From 65d658ffc4b87a0f3cd5c379ed2f2a2a771c0986 Mon Sep 17 00:00:00 2001 From: Clinton Ingram Date: Sat, 13 Jun 2020 12:58:47 -0700 Subject: [PATCH] v2.0.0 --- build/Common.props | 1 + license | 2 +- readme.md | 170 ++++++++++++--------- src/Blake2Fast/Blake2b/Blake2bHashState.cs | 18 ++- src/Blake2Fast/Blake2s/Blake2sHashState.cs | 18 ++- src/Blake2Fast/IBlake2Incremental.cs | 17 ++- src/Blake2Fast/_Blake2Main.ttinclude | 18 ++- tests/Blake2.Test/KnownAnswerTest.cs | 18 +-- 8 files changed, 156 insertions(+), 106 deletions(-) diff --git a/build/Common.props b/build/Common.props index e416b45..555aaaf 100644 --- a/build/Common.props +++ b/build/Common.props @@ -48,6 +48,7 @@ + diff --git a/license b/license index e84eaf9..74118fc 100644 --- a/license +++ b/license @@ -1,6 +1,6 @@ The MIT License -Copyright (c) 2018-2019 Clinton Ingram +Copyright (c) 2018-2020 Clinton Ingram Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/readme.md b/readme.md index e3448f3..9ac22e6 100644 --- a/readme.md +++ b/readme.md @@ -3,11 +3,11 @@ Blake2Fast ========== -These [RFC 7693](https://tools.ietf.org/html/rfc7693)-compliant BLAKE2 implementations have been tuned for high speed and low memory usage. The .NET Core 2.1 and 3.0 builds use the new x86 SIMD Intrinsics for even greater speed. `Span` is used throughout for lower memory overhead compared to `byte[]` based APIs. +These [RFC 7693](https://tools.ietf.org/html/rfc7693)-compliant BLAKE2 implementations have been tuned for high speed and low memory usage. The .NET Core builds use the new x86 SIMD Intrinsics for even greater speed. `Span` is used throughout for lower memory overhead compared to `byte[]` based APIs. -On .NET Core 2.1, Blake2Fast uses an SSE4.1 SIMD-accelerated implementation for both BLAKE2b and BLAKE2s. +On .NET Core 2.1+, Blake2Fast includes SSE4.1 SIMD-accelerated implementations of both BLAKE2b and BLAKE2s. -On .NET Core 3.0, a faster AVX2 implementation of BLAKE2b is available (with SSE4.1 fallback for older processors), while BLAKE2s uses the same SSE4.1 implementation. +On .NET Core 3+, a faster AVX2 implementation of BLAKE2b is included in addition to the SSE4.1 implementation. Installation @@ -54,13 +54,32 @@ async Task ComputeHashAsync(Stream data) int bytesRead; while ((bytesRead = await data.ReadAsync(buffer, 0, buffer.Length)) > 0) - hasher.Update(new Span(buffer, 0, bytesRead)); + hasher.Update(buffer.AsSpan(0, bytesRead)); ArrayPool.Shared.Return(buffer); return hasher.Finish(); } ``` +For convenience, the generic `Update()` method accepts any value type that does not contain reference fields, plus arrays and Spans of compatible types. + +```C# +byte[] ComputeCompositeHash() +{ + var hasher = Blake2b.CreateIncrementalHasher(); + + hasher.Update(42); + hasher.Update(Math.Pi); + hasher.Update("I love deadlines. I like the whooshing sound they make as they fly by.".AsSpan()); + + return hasher.Finish(); +} +``` + +Be aware that the value passed to `Update` is added to the hash state in its current memory layout, which may differ based on platform (endianness) or struct layout. Use care when calling `Update` with types other than `byte` if the computed hashes are to be used across application or machine boundaries. + +For example, if you are adding a string to the hash state, you may hash the characters in memory layout as shown above, or you may use [`Encoding.GetBytes`](https://docs.microsoft.com/en-us/dotnet/api/system.text.encoding.getbytes) to ensure the string bytes are handled consistently across platforms. + ### Allocation-Free Hashing The output hash digest can be written to an existing buffer to avoid allocating a new array each time. @@ -107,53 +126,52 @@ byte[] WriteDataAndCalculateHash(byte[] data, string outFile) } ``` -SIMD Intrinsics Warning ------------------------ - -**This warning applies only to .NET Core 2.1**; the older build targets use only the scalar code, and SIMD intrinsics are fully supported on .NET Core 3.0. +.NET Core 2.1 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. If you are uncomfortable using unsupported functionality, you can make a custom build of Blake2Fast by removing the `HWINTRINSICS` define constant for the `netcoreapp2.1` target in the [project file](src/Blake2Fast/Blake2Fast.csproj). +This warning applies only to .NET Core 2.1. The SIMD Intrinsics are fully supported on .NET Core 3+. Benchmarks ---------- -Sample results from the [Blake2.Bench](tests/Blake2.Bench) project. Benchmarks were run on the .NET Core 3.0-preview7 x64 runtime. Configuration below: +Sample results from the [Blake2.Bench](tests/Blake2.Bench) project. Benchmarks were run on the .NET Core 3.1 x64 runtime. Configuration below: ``` ini -BenchmarkDotNet=v0.11.5, OS=Windows 10.0.18362 +BenchmarkDotNet=v0.12.1, OS=Windows 10.0.18363.836 (1909/November2018Update/19H2) Intel Core i7-6700K CPU 4.00GHz (Skylake), 1 CPU, 8 logical and 4 physical cores -.NET Core SDK=3.0.100 - [Host] : .NET Core 3.0.0 (CoreCLR 4.700.19.46205, CoreFX 4.700.19.46214), 64bit RyuJIT - ShortRun : .NET Core 3.0.0 (CoreCLR 4.700.19.46205, CoreFX 4.700.19.46214), 64bit RyuJIT +.NET Core SDK=3.1.301 + [Host] : .NET Core 3.1.5 (CoreCLR 4.700.20.26901, CoreFX 4.700.20.27001), X64 RyuJIT + ShortRun : .NET Core 3.1.5 (CoreCLR 4.700.20.26901, CoreFX 4.700.20.27001), X64 RyuJIT -Job=ShortRun IterationCount=3 LaunchCount=1 WarmupCount=3 +Job=ShortRun IterationCount=3 LaunchCount=1 WarmupCount=3 ``` ### Blake2Fast vs .NET in-box algorithms (MD5 and SHA2) ``` -| Method | Data Length | Mean | Error | StdDev | Gen 0 | Gen 1 | Gen 2 | Allocated | -|----------- |------------:|----------------:|---------------:|---------------:|-------:|------:|------:|----------:| -| BLAKE2-256 | 3 | 115.2 ns | 4.012 ns | 0.2199 ns | 0.0134 | - | - | 56 B | -| BLAKE2-512 | 3 | 158.2 ns | 6.010 ns | 0.3295 ns | 0.0210 | - | - | 88 B | -| MD5 | 3 | 594.4 ns | 125.147 ns | 6.8597 ns | 0.0496 | - | - | 208 B | -| SHA-256 | 3 | 750.7 ns | 12.582 ns | 0.6897 ns | 0.0572 | - | - | 240 B | -| SHA-512 | 3 | 793.2 ns | 145.418 ns | 7.9708 ns | 0.0725 | - | - | 304 B | -| | | | | | | | | | -| BLAKE2-256 | 3268 | 4,365.6 ns | 162.196 ns | 8.8905 ns | 0.0076 | - | - | 56 B | -| BLAKE2-512 | 3268 | 2,816.7 ns | 237.838 ns | 13.0367 ns | 0.0191 | - | - | 88 B | -| MD5 | 3268 | 6,138.1 ns | 551.232 ns | 30.2149 ns | 0.0458 | - | - | 208 B | -| SHA-256 | 3268 | 13,939.6 ns | 18,730.949 ns | 1,026.7065 ns | 0.0458 | - | - | 240 B | -| SHA-512 | 3268 | 7,986.6 ns | 1,738.739 ns | 95.3062 ns | 0.0610 | - | - | 304 B | -| | | | | | | | | | -| BLAKE2-256 | 3145728 | 4,068,222.1 ns | 464,154.358 ns | 25,441.8666 ns | - | - | - | 56 B | -| BLAKE2-512 | 3145728 | 2,603,172.5 ns | 14,066.567 ns | 771.0360 ns | - | - | - | 88 B | -| MD5 | 3145728 | 5,346,016.5 ns | 707,026.849 ns | 38,754.5273 ns | - | - | - | 208 B | -| SHA-256 | 3145728 | 11,527,220.8 ns | 688,897.951 ns | 37,760.8213 ns | - | - | - | 240 B | -| SHA-512 | 3145728 | 6,920,789.6 ns | 963,166.916 ns | 52,794.4287 ns | - | - | - | 304 B | +| Method | Data Length | Mean | Error | StdDev | Gen 0 | Gen 1 | Gen 2 | Allocated | +|----------- |------------:|----------------:|--------------:|-------------:|-------:|------:|------:|----------:| +| BLAKE2-256 | 3 | 106.2 ns | 8.01 ns | 0.44 ns | 0.0134 | - | - | 56 B | +| BLAKE2-512 | 3 | 144.2 ns | 30.51 ns | 1.67 ns | 0.0210 | - | - | 88 B | +| MD5 | 3 | 559.2 ns | 89.97 ns | 4.93 ns | 0.0496 | - | - | 208 B | +| SHA-256 | 3 | 722.7 ns | 61.84 ns | 3.39 ns | 0.0572 | - | - | 240 B | +| SHA-512 | 3 | 749.2 ns | 40.06 ns | 2.20 ns | 0.0725 | - | - | 304 B | +| | | | | | | | | | +| BLAKE2-256 | 3268 | 3,933.6 ns | 148.09 ns | 8.12 ns | 0.0076 | - | - | 56 B | +| BLAKE2-512 | 3268 | 2,429.7 ns | 107.58 ns | 5.90 ns | 0.0191 | - | - | 88 B | +| MD5 | 3268 | 5,866.8 ns | 171.88 ns | 9.42 ns | 0.0458 | - | - | 208 B | +| SHA-256 | 3268 | 12,719.1 ns | 559.17 ns | 30.65 ns | 0.0458 | - | - | 240 B | +| SHA-512 | 3268 | 7,577.3 ns | 555.80 ns | 30.47 ns | 0.0610 | - | - | 304 B | +| | | | | | | | | | +| BLAKE2-256 | 3145728 | 3,667,519.1 ns | 77,804.44 ns | 4,264.72 ns | - | - | - | 56 B | +| BLAKE2-512 | 3145728 | 2,240,879.0 ns | 101,729.66 ns | 5,576.15 ns | - | - | - | 88 B | +| MD5 | 3145728 | 5,108,604.6 ns | 189,941.46 ns | 10,411.33 ns | - | - | - | 208 B | +| SHA-256 | 3145728 | 11,038,065.4 ns | 311,623.07 ns | 17,081.11 ns | - | - | - | 240 B | +| SHA-512 | 3145728 | 6,599,771.6 ns | 251,528.85 ns | 13,787.15 ns | - | - | - | 304 B | ``` Note that the built-in cryptographic hash algorithms in .NET Core forward to platform-native libraries for their implementations. On Windows, this means the implementations are provided by [Windows CNG](https://docs.microsoft.com/en-us/windows/desktop/seccng/cng-portal). Performance may differ on Linux. @@ -163,60 +181,60 @@ On .NET Framework, only scalar (not SIMD) implementations are available for both ### Blake2Fast vs other BLAKE2b implementations available on NuGet ``` -| Method | Data Length | Mean | Error | StdDev | Median | Gen 0 | Gen 1 | Gen 2 | Allocated | -|-------------------- |------------:|----------------:|------------------:|------------------:|----------------:|----------:|----------:|----------:|----------:| -| *Blake2Fast.Blake2b | 3 | 154.6 ns | 11.265 ns | 0.6174 ns | 154.3 ns | 0.0076 | - | - | 32 B | -| Blake2Sharp | 3 | 399.8 ns | 3.924 ns | 0.2151 ns | 399.8 ns | 0.2065 | - | - | 864 B | -| ByteTerrace | 3 | 465.2 ns | 53.384 ns | 2.9262 ns | 464.5 ns | 0.1087 | - | - | 456 B | -| S.D.HashFunction | 3 | 1,925.3 ns | 228.902 ns | 12.5469 ns | 1,930.8 ns | 0.4158 | - | - | 1744 B | -| Konscious | 3 | 1,312.6 ns | 65.560 ns | 3.5936 ns | 1,310.7 ns | 0.2289 | - | - | 960 B | -| Isopoh | 3 | 5,575,764.3 ns | 29,643,293.882 ns | 1,624,848.9645 ns | 6,245,297.4 ns | 1446.2891 | 1435.0586 | 1435.0586 | 38830 B | -| Blake2Core | 3 | 1,466.0 ns | 18.951 ns | 1.0388 ns | 1,466.1 ns | 0.2060 | - | - | 864 B | -| NSec | 3 | 195.9 ns | 37.838 ns | 2.0740 ns | 194.9 ns | 0.0267 | - | - | 112 B | -| | | | | | | | | | | -| *Blake2Fast.Blake2b | 3268 | 2,816.3 ns | 196.974 ns | 10.7968 ns | 2,817.9 ns | 0.0076 | - | - | 32 B | -| Blake2Sharp | 3268 | 4,607.2 ns | 1,289.570 ns | 70.6857 ns | 4,570.6 ns | 0.2060 | - | - | 864 B | -| ByteTerrace | 3268 | 4,283.0 ns | 155.465 ns | 8.5215 ns | 4,286.1 ns | 0.1068 | - | - | 456 B | -| S.D.HashFunction | 3268 | 30,997.7 ns | 365.501 ns | 20.0344 ns | 30,993.8 ns | 2.1973 | - | - | 9344 B | -| Konscious | 3268 | 17,838.6 ns | 5,256.549 ns | 288.1292 ns | 17,810.2 ns | 0.2136 | - | - | 960 B | -| Isopoh | 3268 | 4,900,439.9 ns | 69,196,704.000 ns | 3,792,904.8400 ns | 3,818,492.5 ns | 1665.5273 | 1652.5879 | 1652.5879 | 44453 B | -| Blake2Core | 3268 | 21,460.8 ns | 1,331.275 ns | 72.9717 ns | 21,430.9 ns | 0.1831 | - | - | 864 B | -| NSec | 3268 | 2,926.2 ns | 44.080 ns | 2.4162 ns | 2,927.0 ns | 0.0267 | - | - | 112 B | -| | | | | | | | | | | -| *Blake2Fast.Blake2b | 3145728 | 2,601,242.8 ns | 106,368.445 ns | 5,830.4134 ns | 2,598,229.7 ns | - | - | - | 32 B | -| Blake2Sharp | 3145728 | 4,133,410.5 ns | 558,771.342 ns | 30,628.1427 ns | 4,116,710.5 ns | - | - | - | 864 B | -| ByteTerrace | 3145728 | 3,791,728.8 ns | 15,569.103 ns | 853.3951 ns | 3,791,369.1 ns | - | - | - | 456 B | -| S.D.HashFunction | 3145728 | 28,587,428.1 ns | 1,431,805.370 ns | 78,482.0838 ns | 28,593,243.8 ns | 1781.2500 | - | - | 7472544 B | -| Konscious | 3145728 | 16,070,360.4 ns | 2,271,284.235 ns | 124,496.7530 ns | 16,009,746.9 ns | - | - | - | 960 B | -| Isopoh | 3145728 | 4,222,685.9 ns | 1,711,996.562 ns | 93,840.3084 ns | 4,170,207.8 ns | - | - | - | 984 B | -| Blake2Core | 3145728 | 19,492,347.4 ns | 2,974,640.838 ns | 163,050.1018 ns | 19,413,667.2 ns | - | - | - | 864 B | -| NSec | 3145728 | 2,681,916.7 ns | 217,008.582 ns | 11,894.9727 ns | 2,675,534.4 ns | - | - | - | 112 B | +| Method | Data Length | Mean | Error | StdDev | Gen 0 | Gen 1 | Gen 2 | Allocated | +|-------------------- |------------:|----------------:|-----------------:|----------------:|----------:|----------:|----------:|------------:| +| *Blake2Fast.Blake2b | 3 | 139.5 ns | 2.71 ns | 0.15 ns | 0.0076 | - | - | 32 B | +| Blake2Sharp(1) | 3 | 382.0 ns | 41.26 ns | 2.26 ns | 0.2065 | - | - | 864 B | +| ByteTerrace(2) | 3 | 442.5 ns | 40.06 ns | 2.20 ns | 0.1087 | - | - | 456 B | +| S.D.HashFunction(3) | 3 | 1,818.6 ns | 28.93 ns | 1.59 ns | 0.4158 | - | - | 1744 B | +| Konscious(4) | 3 | 1,234.3 ns | 23.67 ns | 1.30 ns | 0.2289 | - | - | 960 B | +| Isopoh(5) | 3 | 10,403,770.2 ns | 96,909,560.25 ns | 5,311,940.00 ns | 1736.0840 | 1722.4121 | 1722.4121 | 527973075 B | +| Blake2Core(6) | 3 | 1,407.4 ns | 137.05 ns | 7.51 ns | 0.2060 | - | - | 864 B | +| NSec(7) | 3 | 170.2 ns | 17.42 ns | 0.96 ns | 0.0267 | - | - | 112 B | +| | | | | | | | | | +| *Blake2Fast.Blake2b | 3268 | 2,413.4 ns | 48.19 ns | 2.64 ns | 0.0076 | - | - | 32 B | +| Blake2Sharp(1) | 3268 | 4,378.4 ns | 278.87 ns | 15.29 ns | 0.2060 | - | - | 864 B | +| ByteTerrace(2) | 3268 | 4,095.5 ns | 295.62 ns | 16.20 ns | 0.1068 | - | - | 456 B | +| S.D.HashFunction(3) | 3268 | 29,730.2 ns | 2,388.67 ns | 130.93 ns | 2.2278 | - | - | 9344 B | +| Konscious(4) | 3268 | 16,682.2 ns | 997.62 ns | 54.68 ns | 0.2136 | - | - | 960 B | +| Isopoh(5) | 3268 | 1,708,548.1 ns | 3,287,267.60 ns | 180,186.23 ns | 220.7031 | 218.7500 | 218.7500 | 67111641 B | +| Blake2Core(6) | 3268 | 20,619.3 ns | 1,859.13 ns | 101.90 ns | 0.1831 | - | - | 864 B | +| NSec(7) | 3268 | 2,459.1 ns | 252.85 ns | 13.86 ns | 0.0267 | - | - | 112 B | +| | | | | | | | | | +| *Blake2Fast.Blake2b | 3145728 | 2,242,018.9 ns | 156,659.45 ns | 8,587.03 ns | - | - | - | 32 B | +| Blake2Sharp(1) | 3145728 | 3,955,138.2 ns | 113,166.53 ns | 6,203.04 ns | - | - | - | 864 B | +| ByteTerrace(2) | 3145728 | 3,641,689.8 ns | 58,221.45 ns | 3,191.31 ns | - | - | - | 457 B | +| S.D.HashFunction(3) | 3145728 | 27,450,332.3 ns | 1,245,091.70 ns | 68,247.68 ns | 1781.2500 | - | - | 7472544 B | +| Konscious(4) | 3145728 | 15,179,139.1 ns | 668,577.20 ns | 36,646.97 ns | - | - | - | 960 B | +| Isopoh(5) | 3145728 | 4,011,376.3 ns | 477,836.99 ns | 26,191.86 ns | - | - | - | 984 B | +| Blake2Core(6) | 3145728 | 18,704,691.7 ns | 1,247,107.98 ns | 68,358.20 ns | - | - | - | 864 B | +| NSec(7) | 3145728 | 2,247,392.2 ns | 13,390.91 ns | 734.00 ns | - | - | - | 112 B | ``` * (1) `Blake2Sharp` is the reference C# BLAKE2b implementation from the [official BLAKE2 repo](https://github.com/BLAKE2/BLAKE2). This version is not published to NuGet, so the source is included in the benchmark project directly. * (2) `ByteTerrace.Maths.Cryptography.Blake2` version 0.0.6. * (3) `System.Data.HashFunction.Blake2` version 2.0.0. BLAKE2b only. * (4) `Konscious.Security.Cryptography.Blake2` version 1.0.9. BLAKE2b only. -* (5) `Isopoh.Cryptography.Blake2b` version 1.1.2. Yes, it really is that slow on incomplete block lengths. +* (5) `Isopoh.Cryptography.Blake2b` version 1.1.3. Yes, it really is that slow on incomplete block lengths. * (6) `Blake2Core` version 1.0.0. This package contains the reference Blake2Sharp code compiled as a debug (unoptimized) build. BenchmarkDotNet errors in such cases, so the settings were overridden to allow this library to run. -* (7) `NSec.Cryptography` 19.5.0. This implementation of BLAKE2b is not RFC-compliant in that it does not support digest sizes less than 32 bytes or keyed hashing. This library forwards to a referenced native library (libsodium), which contains an AVX2 implementation of BLAKE2b. +* (7) `NSec.Cryptography` 20.2.0. This implementation of BLAKE2b is not RFC-compliant in that it does not support digest sizes less than 32 bytes or keyed hashing. NSec.Cryptography wraps the native `libsodium` library, which contains an AVX2 implementation of BLAKE2b. ### Blake2Fast vs other BLAKE2s implementations available on NuGet ``` -| Method | Data Length | Mean | Error | StdDev | Gen 0 | Gen 1 | Gen 2 | Allocated | -|-------------------- |------------:|---------------:|----------------:|---------------:|-------:|------:|------:|----------:| -| *Blake2Fast.Blake2s | 3 | 113.2 ns | 0.6107 ns | 0.0335 ns | 0.0076 | - | - | 32 B | -| Blake2s-net | 3 | 275.8 ns | 11.9290 ns | 0.6539 ns | 0.1278 | - | - | 536 B | -| ByteTerrace | 3 | 317.5 ns | 60.3902 ns | 3.3102 ns | 0.0763 | - | - | 320 B | -| | | | | | | | | | -| *Blake2Fast.Blake2s | 3268 | 4,387.3 ns | 874.4187 ns | 47.9298 ns | 0.0076 | - | - | 32 B | -| Blake2s-net | 3268 | 6,267.0 ns | 71.3469 ns | 3.9108 ns | 0.1221 | - | - | 536 B | -| ByteTerrace | 3268 | 6,522.3 ns | 46.1384 ns | 2.5290 ns | 0.0763 | - | - | 320 B | -| | | | | | | | | | -| *Blake2Fast.Blake2s | 3145728 | 3,953,215.9 ns | 6,863.9457 ns | 376.2360 ns | - | - | - | 32 B | -| Blake2s-net | 3145728 | 5,873,522.9 ns | 996,716.8203 ns | 54,633.4122 ns | - | - | - | 536 B | -| ByteTerrace | 3145728 | 5,980,544.8 ns | 138,455.1551 ns | 7,589.1942 ns | - | - | - | 320 B | +| Method | Data Length | Mean | Error | StdDev | Gen 0 | Gen 1 | Gen 2 | Allocated | +|-------------------- |------------:|---------------:|--------------:|-------------:|-------:|------:|------:|----------:| +| *Blake2Fast.Blake2s | 3 | 106.5 ns | 2.30 ns | 0.13 ns | 0.0076 | - | - | 32 B | +| Blake2s-net(1) | 3 | 274.4 ns | 39.08 ns | 2.14 ns | 0.1278 | - | - | 536 B | +| ByteTerrace(2) | 3 | 303.6 ns | 5.69 ns | 0.31 ns | 0.0763 | - | - | 320 B | +| | | | | | | | | | +| *Blake2Fast.Blake2s | 3268 | 3,941.2 ns | 388.64 ns | 21.30 ns | 0.0076 | - | - | 32 B | +| Blake2s-net(1) | 3268 | 6,044.0 ns | 251.18 ns | 13.77 ns | 0.1221 | - | - | 536 B | +| ByteTerrace(2) | 3268 | 6,287.7 ns | 715.20 ns | 39.20 ns | 0.0763 | - | - | 320 B | +| | | | | | | | | | +| *Blake2Fast.Blake2s | 3145728 | 3,669,570.7 ns | 308,040.39 ns | 16,884.73 ns | - | - | - | 32 B | +| Blake2s-net(1) | 3145728 | 5,549,277.3 ns | 171,690.31 ns | 9,410.93 ns | - | - | - | 536 B | +| ByteTerrace(2) | 3145728 | 5,754,080.2 ns | 75,019.78 ns | 4,112.09 ns | - | - | - | 320 B | ``` * (1) `blake2s-net` version 0.1.0. This is a conversion of the reference Blake2Sharp code to support BLAKE2s. diff --git a/src/Blake2Fast/Blake2b/Blake2bHashState.cs b/src/Blake2Fast/Blake2b/Blake2bHashState.cs index 5fca27b..70683ff 100644 --- a/src/Blake2Fast/Blake2b/Blake2bHashState.cs +++ b/src/Blake2Fast/Blake2b/Blake2bHashState.cs @@ -114,8 +114,7 @@ internal void Init(int digestLength = HashBytes, ReadOnlySpan key = defaul } } - /// - public void Update(ReadOnlySpan input) + private void update(ReadOnlySpan input) { if (outlen == 0) ThrowHelper.HashNotInitialized(); if (f[0] != 0) ThrowHelper.HashFinalized(); @@ -156,9 +155,18 @@ public void Update(ReadOnlySpan input) where T : struct { ThrowHelper.ThrowIfIsRefOrContainsRefs(); - Update(MemoryMarshal.AsBytes(input)); + update(MemoryMarshal.AsBytes(input)); } + /// + public void Update(Span input) where T : struct => Update((ReadOnlySpan)input); + + /// + public void Update(ArraySegment input) where T : struct => Update((ReadOnlySpan)input); + + /// + public void Update(T[] input) where T : struct => Update((ReadOnlySpan)input); + /// public void Update(T input) where T : struct { @@ -169,9 +177,9 @@ public void Update(T input) where T : struct #if BUILTIN_SPAN Update(MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref input), Unsafe.SizeOf())); #else - Span buff = stackalloc byte[Unsafe.SizeOf()]; + var buff = (Span)stackalloc byte[Unsafe.SizeOf()]; Unsafe.WriteUnaligned(ref buff[0], input); - Update(buff); + update(buff); #endif return; } diff --git a/src/Blake2Fast/Blake2s/Blake2sHashState.cs b/src/Blake2Fast/Blake2s/Blake2sHashState.cs index 859f4fc..6d4eeb6 100644 --- a/src/Blake2Fast/Blake2s/Blake2sHashState.cs +++ b/src/Blake2Fast/Blake2s/Blake2sHashState.cs @@ -109,8 +109,7 @@ internal void Init(int digestLength = HashBytes, ReadOnlySpan key = defaul } } - /// - public void Update(ReadOnlySpan input) + private void update(ReadOnlySpan input) { if (outlen == 0) ThrowHelper.HashNotInitialized(); if (f[0] != 0) ThrowHelper.HashFinalized(); @@ -151,9 +150,18 @@ public void Update(ReadOnlySpan input) where T : struct { ThrowHelper.ThrowIfIsRefOrContainsRefs(); - Update(MemoryMarshal.AsBytes(input)); + update(MemoryMarshal.AsBytes(input)); } + /// + public void Update(Span input) where T : struct => Update((ReadOnlySpan)input); + + /// + public void Update(ArraySegment input) where T : struct => Update((ReadOnlySpan)input); + + /// + public void Update(T[] input) where T : struct => Update((ReadOnlySpan)input); + /// public void Update(T input) where T : struct { @@ -164,9 +172,9 @@ public void Update(T input) where T : struct #if BUILTIN_SPAN Update(MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref input), Unsafe.SizeOf())); #else - Span buff = stackalloc byte[Unsafe.SizeOf()]; + var buff = (Span)stackalloc byte[Unsafe.SizeOf()]; Unsafe.WriteUnaligned(ref buff[0], input); - Update(buff); + update(buff); #endif return; } diff --git a/src/Blake2Fast/IBlake2Incremental.cs b/src/Blake2Fast/IBlake2Incremental.cs index b5f3afc..2514329 100644 --- a/src/Blake2Fast/IBlake2Incremental.cs +++ b/src/Blake2Fast/IBlake2Incremental.cs @@ -26,20 +26,27 @@ interface IBlake2Incremental /// The hash digest length for this instance, in bytes. int DigestLength { get; } - /// Update the hash state with the bytes contained in . + /// Update the hash state with the bytes of all values in . /// The message bytes to add to the hash state. - void Update(ReadOnlySpan input); - - /// /// The type of the data that will be added to the hash state. It must be a value type and must not contain any reference type fields. /// /// The value will be added to the hash state in memory layout order, including any padding bytes. /// Use caution when using this overload with non-primitive structs or when hash values are to be compared across machines with different struct layouts or byte orders. + /// is the only type that is guaranteed to be consistent across platforms. /// /// Thrown when is a reference type or contains any fields of reference types. void Update(ReadOnlySpan input) where T : struct; - /// Update the hash state with the value. + /// + void Update(Span input) where T : struct; + + /// + void Update(ArraySegment input) where T : struct; + + /// + void Update(T[] input) where T : struct; + + /// Update the hash state with the bytes of the value. /// void Update(T input) where T : struct; diff --git a/src/Blake2Fast/_Blake2Main.ttinclude b/src/Blake2Fast/_Blake2Main.ttinclude index a7cb5c2..1151092 100644 --- a/src/Blake2Fast/_Blake2Main.ttinclude +++ b/src/Blake2Fast/_Blake2Main.ttinclude @@ -189,8 +189,7 @@ if (alg.bits == 64) { } } - /// - public void Update(ReadOnlySpan input) + private void update(ReadOnlySpan input) { if (outlen == 0) ThrowHelper.HashNotInitialized(); if (f[0] != 0) ThrowHelper.HashFinalized(); @@ -231,9 +230,18 @@ if (alg.bits == 64) { { ThrowHelper.ThrowIfIsRefOrContainsRefs(); - Update(MemoryMarshal.AsBytes(input)); + update(MemoryMarshal.AsBytes(input)); } + /// + public void Update(Span input) where T : struct => Update((ReadOnlySpan)input); + + /// + public void Update(ArraySegment input) where T : struct => Update((ReadOnlySpan)input); + + /// + public void Update(T[] input) where T : struct => Update((ReadOnlySpan)input); + /// public void Update(T input) where T : struct { @@ -244,9 +252,9 @@ if (alg.bits == 64) { #if BUILTIN_SPAN Update(MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref input), Unsafe.SizeOf())); #else - Span buff = stackalloc byte[Unsafe.SizeOf()]; + var buff = (Span)stackalloc byte[Unsafe.SizeOf()]; Unsafe.WriteUnaligned(ref buff[0], input); - Update(buff); + update(buff); #endif return; } diff --git a/tests/Blake2.Test/KnownAnswerTest.cs b/tests/Blake2.Test/KnownAnswerTest.cs index 25aada3..e5019e2 100644 --- a/tests/Blake2.Test/KnownAnswerTest.cs +++ b/tests/Blake2.Test/KnownAnswerTest.cs @@ -38,21 +38,21 @@ private static byte[] getBytes(string s) private static int getDigit(char c) => c < 'a' ? c - '0' : c - 'a' + 10; - private static KatEntry[] getAllKat() + private static KatEntry[] getKatValues() { - using var stm = typeof(KnownAnswerTest).Assembly.GetManifestResourceStream("Blake2.Test.blake2-kat.json"); + using var stm = typeof(KatEntry).Assembly.GetManifestResourceStream("Blake2.Test.blake2-kat.json"); return ((JsonArray)JsonValue.Load(stm)).Cast().Select(o => new KatEntry(o)).ToArray(); } - public static readonly KatEntry[] All = getAllKat(); + public static readonly KatEntry[] Values = getKatValues(); - public static IEnumerable Blake2b => All.Where(k => k.Alg == "blake2b" && k.Key.Length == 0).Select(k => new object[] { k }); + public static IEnumerable Blake2b => Values.Where(k => k.Alg == "blake2b" && k.Key.Length == 0).Select(k => new object[] { k }); - public static IEnumerable Blake2bKeyed => All.Where(k => k.Alg == "blake2b" && k.Key.Length != 0).Select(k => new object[] { k }); + public static IEnumerable Blake2bKeyed => Values.Where(k => k.Alg == "blake2b" && k.Key.Length != 0).Select(k => new object[] { k }); - public static IEnumerable Blake2s => All.Where(k => k.Alg == "blake2s" && k.Key.Length == 0).Select(k => new object[] { k }); + public static IEnumerable Blake2s => Values.Where(k => k.Alg == "blake2s" && k.Key.Length == 0).Select(k => new object[] { k }); - public static IEnumerable Blake2sKeyed => All.Where(k => k.Alg == "blake2s" && k.Key.Length != 0).Select(k => new object[] { k }); + public static IEnumerable Blake2sKeyed => Values.Where(k => k.Alg == "blake2s" && k.Key.Length != 0).Select(k => new object[] { k }); } public class KnownAnswerTest @@ -139,12 +139,12 @@ public void KatBlake2sKeyed(KatEntry ka) [Fact] public void UpdateThrowsOnRefContainingT() { - Assert.Throws(() => Blake2b.CreateIncrementalHasher().Update(KatEntry.All[0])); + Assert.Throws(() => Blake2b.CreateIncrementalHasher().Update(KatEntry.Values.First())); } [Fact] public void UpdateThrowsOnRefContainingSpanT() { - Assert.Throws(() => Blake2b.CreateIncrementalHasher().Update(new ReadOnlySpan(KatEntry.All))); + Assert.Throws(() => Blake2b.CreateIncrementalHasher().Update(KatEntry.Values)); } }