File Hashing
Compute cryptographic hashes to verify downloaded files against Civitai metadata.
Supported Algorithms
Sha256- 64 hex charactersSha512- 128 hex charactersBlake3- 64 hex characters (fast, modern)Crc32- 8 hex characters (integrity check)
Hash File
// Compute SHA256 hash of a file
var hashResult = await hashingService.ComputeHashAsync(
@"C:\Models\model.safetensors",
HashAlgorithm.Sha256);
if (hashResult is Result<HashedFile>.Success hashingSuccess)
{
Console.WriteLine($"File: {hashingSuccess.Data.FilePath}");
Console.WriteLine($"Hash: {hashingSuccess.Data.Hash}");
Console.WriteLine($"Algorithm: {hashingSuccess.Data.Algorithm}");
Console.WriteLine($"Size: {hashingSuccess.Data.FileSize:N0} bytes");
Console.WriteLine($"Time: {hashingSuccess.Data.ComputationTime.TotalMilliseconds:F2}ms");
}
else if (hashResult is Result<HashedFile>.Failure hashingFailure)
{
Console.WriteLine($"Error: {hashingFailure.Error.Message}");
}
Hash Stream
// Compute hash from a stream
await using var stream = File.OpenRead(@"C:\Models\model.safetensors");
var streamHashResult = await hashingService.ComputeHashAsync(stream, HashAlgorithm.Blake3);
if (streamHashResult is Result<HashedFile>.Success streamHashSuccess)
{
Console.WriteLine($"BLAKE3 Hash: {streamHashSuccess.Data.Hash}");
}
Verify Downloads
// Verify a downloaded model against Civitai's hash
var modelResult = await apiClient.Models.GetByIdAsync(123456);
if (modelResult is Result<Model>.Success modelSuccess)
{
var version = modelSuccess.Data.ModelVersions?.FirstOrDefault();
var file = version?.Files?.FirstOrDefault(f => f.Primary == true);
if (file?.Hashes?.Sha256 is { } civitaiHash)
{
var verificationResult = await hashingService.ComputeHashAsync(
@"C:\Models\downloaded_model.safetensors",
HashAlgorithm.Sha256);
if (verificationResult is Result<HashedFile>.Success verificationSuccess)
{
var isValid = string.Equals(
verificationSuccess.Data.Hash,
civitaiHash,
StringComparison.OrdinalIgnoreCase);
Console.WriteLine(isValid
? "File integrity verified!"
: $"Hash mismatch! Expected: {civitaiHash}, Got: {verificationSuccess.Data.Hash}");
}
}
}
Multiple Hashes
// Compute multiple hash types for comparison
var filePath = @"C:\Models\model.safetensors";
var sha256Task = hashingService.ComputeHashAsync(filePath, HashAlgorithm.Sha256);
var blake3Task = hashingService.ComputeHashAsync(filePath, HashAlgorithm.Blake3);
var crc32Task = hashingService.ComputeHashAsync(filePath, HashAlgorithm.Crc32);
await Task.WhenAll(sha256Task, blake3Task, crc32Task);
Console.WriteLine("Hash comparison:");
if (sha256Task.Result is Result<HashedFile>.Success sha256Success)
Console.WriteLine($" SHA256: {sha256Success.Data.Hash}");
if (blake3Task.Result is Result<HashedFile>.Success blake3Success)
Console.WriteLine($" BLAKE3: {blake3Success.Data.Hash}");
if (crc32Task.Result is Result<HashedFile>.Success crc32Success)
Console.WriteLine($" CRC32: {crc32Success.Data.Hash}");
Async with Cancellation
// Hash a file with cancellation support
var largeFilePath = @"C:\Models\large_model.safetensors";
using var cts = new CancellationTokenSource(TimeSpan.FromMinutes(5));
var cancellationResult = await hashingService.ComputeHashAsync(
largeFilePath,
HashAlgorithm.Blake3,
cts.Token);
Error Handling
Error Codes: FileNotFound, StreamNotReadable, HashComputationFailed
// Handle hashing errors with switch expression
var errorSwitchResult = await hashingService.ComputeHashAsync(filePath, HashAlgorithm.Sha256);
switch (errorSwitchResult)
{
case Result<HashedFile>.Success success:
Console.WriteLine($"Hash: {success.Data.Hash}");
break;
case Result<HashedFile>.Failure { Error.Code: ErrorCode.FileNotFound }:
Console.WriteLine("File not found");
break;
case Result<HashedFile>.Failure failure:
Console.WriteLine($"Error: {failure.Error.Message}");
break;
}
Integration with Downloads
// Integrate hashing with download configuration
builder.Services.AddCivitaiDownloads(options =>
{
options.Models.VerifyHash = true;
options.Models.HashAlgorithm = HashAlgorithm.Sha256;
});