Table of Contents

File Hashing

Compute cryptographic hashes to verify downloaded files against Civitai metadata.

Supported Algorithms

  • Sha256 - 64 hex characters
  • Sha512 - 128 hex characters
  • Blake3 - 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;
});

Next Steps