SauceControl.Blake2Fast 0.2.0

Optimized implementations of the BLAKE2b and BLAKE2s hashing algorithms.  Uses SSE2-SSE4.1 Intrinsics support on .NET Core 2.1

Install-Package SauceControl.Blake2Fast -Version 0.2.0
dotnet add package SauceControl.Blake2Fast --version 0.2.0
paket add SauceControl.Blake2Fast --version 0.2.0
The NuGet Team does not provide support for this client. Please contact its maintainers for support.

These RFC 7693-compliant BLAKE2 implementations have been tuned for high speed and low memory usage. The .NET Core 2.1 build supports the new X86 SIMD Intrinsics for even greater speed and Span{T} for even lower memory usage.

Usage

All-at-Once Hashing

The simplest and lightest-weight way to calculate a hash is the all-at-once ComputeHash method.

var hash = Blake2b.ComputeHash(data);

BLAKE2 supports variable digest lengths from 1 to 32 bytes for BLAKE2s or 1 to 64 bytes for BLAKE2b.

var hash = Blake2b.ComputeHash(42, data);

BLAKE2 also natively supports keyed hashing.

var hash = Blake2b.ComputeHash(key, data);

Incremental Hashing

BLAKE2 hashes can be incrementally updated if you do not have the data available all at once.

async Task<byte[]> ComputeHashAsync(Stream data)
{
    var incHash = Blake2b.CreateIncrementalHasher();
    var buffer = new byte[4096];
    int bytesRead;

    while ((bytesRead = await data.ReadAsync(buffer, 0, buffer.Length)) > 0)
    {
        // Use Span<T> for .NET Core 2.1 or ArraySegment<T> for others
        incHash.Update(new ArraySegment<byte>(buffer, 0, bytesRead));
    }

    return incHash.Finish();
}

Allocation-Free Hashing

The output hash digest can be written to an existing buffer to avoid allocating a new array each time. This is especially useful when performing an iterative hash, as might be used in a key derivation function.

byte[] DeriveBytes(string password, byte[] salt)
{
    // Create key from password, then hash the salt using the key
    var pwkey = Blake2b.ComputeHash(System.Text.Encoding.UTF8.GetBytes(password));
    var hbuff = Blake2b.ComputeHash(pwkey, salt);

    // Hash the hash lots of times, re-using the same buffer
    for (int i = 0; i < 1_000_000; i++)
        Blake2b.ComputeAndWriteHash(pwkey, hbuff, hbuff);

    return hbuff;
}

System.Security.Cryptography Interop

For interoperating with code that uses System.Security.Cryptography primitives, Blake2Fast can create a HashAlgorithm wrapper. The wrapper inherits from HMAC in case keyed hashing is required.

HashAlgorithm is less efficient than the above methods, so use it only when necessary for compatibility.

byte[] WriteDataAndCalculateHash(byte[] data)
{
    using (var hashAlg = Blake2b.CreateHashAlgorithm())
    using (var fileStream = new FileStream(@"c:\data\output.bin", FileMode.Create))
    using (var cryptoStream = new CryptoStream(fileStream, hashAlg, CryptoStreamMode.Write))
    {
        cryptoStream.Write(data, 0, data.Length);
        cryptoStream.FlushFinalBlock();
        return hashAlg.Hash;
    }
}

SIMD Intrinsics Warning

The X86 SIMD Intrinsics used in the .NET Core 2.1 build are not officially supported by Microsoft. Although the specific SSE Intrinsics used by Blake2Fast have been well-tested, the JIT support for the X86 Intrinsics in general is experimental in .NET Core 2.1. Please test with your specific hardware and report any issues here or in the CoreCLR repo as appropriate.

If you are uncomfortable using unsupported functionality, you can make a custom build of Blake2Fast by removing the USE_INTRINSICS define constant in the project file. This applies only to .NET Core 2.1; the older build targets use only the scalar code.

These RFC 7693-compliant BLAKE2 implementations have been tuned for high speed and low memory usage. The .NET Core 2.1 build supports the new X86 SIMD Intrinsics for even greater speed and Span{T} for even lower memory usage.

Usage

All-at-Once Hashing

The simplest and lightest-weight way to calculate a hash is the all-at-once ComputeHash method.

var hash = Blake2b.ComputeHash(data);

BLAKE2 supports variable digest lengths from 1 to 32 bytes for BLAKE2s or 1 to 64 bytes for BLAKE2b.

var hash = Blake2b.ComputeHash(42, data);

BLAKE2 also natively supports keyed hashing.

var hash = Blake2b.ComputeHash(key, data);

Incremental Hashing

BLAKE2 hashes can be incrementally updated if you do not have the data available all at once.

async Task<byte[]> ComputeHashAsync(Stream data)
{
    var incHash = Blake2b.CreateIncrementalHasher();
    var buffer = new byte[4096];
    int bytesRead;

    while ((bytesRead = await data.ReadAsync(buffer, 0, buffer.Length)) > 0)
    {
        // Use Span<T> for .NET Core 2.1 or ArraySegment<T> for others
        incHash.Update(new ArraySegment<byte>(buffer, 0, bytesRead));
    }

    return incHash.Finish();
}

Allocation-Free Hashing

The output hash digest can be written to an existing buffer to avoid allocating a new array each time. This is especially useful when performing an iterative hash, as might be used in a key derivation function.

byte[] DeriveBytes(string password, byte[] salt)
{
    // Create key from password, then hash the salt using the key
    var pwkey = Blake2b.ComputeHash(System.Text.Encoding.UTF8.GetBytes(password));
    var hbuff = Blake2b.ComputeHash(pwkey, salt);

    // Hash the hash lots of times, re-using the same buffer
    for (int i = 0; i < 1_000_000; i++)
        Blake2b.ComputeAndWriteHash(pwkey, hbuff, hbuff);

    return hbuff;
}

System.Security.Cryptography Interop

For interoperating with code that uses System.Security.Cryptography primitives, Blake2Fast can create a HashAlgorithm wrapper. The wrapper inherits from HMAC in case keyed hashing is required.

HashAlgorithm is less efficient than the above methods, so use it only when necessary for compatibility.

byte[] WriteDataAndCalculateHash(byte[] data)
{
    using (var hashAlg = Blake2b.CreateHashAlgorithm())
    using (var fileStream = new FileStream(@"c:\data\output.bin", FileMode.Create))
    using (var cryptoStream = new CryptoStream(fileStream, hashAlg, CryptoStreamMode.Write))
    {
        cryptoStream.Write(data, 0, data.Length);
        cryptoStream.FlushFinalBlock();
        return hashAlg.Hash;
    }
}

SIMD Intrinsics Warning

The X86 SIMD Intrinsics used in the .NET Core 2.1 build are not officially supported by Microsoft. Although the specific SSE Intrinsics used by Blake2Fast have been well-tested, the JIT support for the X86 Intrinsics in general is experimental in .NET Core 2.1. Please test with your specific hardware and report any issues here or in the CoreCLR repo as appropriate.

If you are uncomfortable using unsupported functionality, you can make a custom build of Blake2Fast by removing the USE_INTRINSICS define constant in the project file. This applies only to .NET Core 2.1; the older build targets use only the scalar code.

Release Notes

See https://github.com/saucecontrol/Blake2Fast/releases

Version History

Version Downloads Last updated
0.2.0 616 6/18/2018
0.1.0 81 6/15/2018