Skip to content

Commit e49f3b9

Browse files
committed
enable allocation-free incremental hashing
1 parent d50f5fa commit e49f3b9

22 files changed

+248
-110
lines changed

src/Blake2Fast/Blake2Fast.csproj

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,17 +31,17 @@
3131
<Service Include="{508349b6-6b84-4df5-91f0-309beebad82d}" />
3232
<None Update="Blake2b\Blake2b.tt" LastGenOutput="Blake2b.cs" Generator="TextTemplatingFileGenerator" />
3333
<None Update="Blake2s\Blake2s.tt" LastGenOutput="Blake2s.cs" Generator="TextTemplatingFileGenerator" />
34-
<None Update="Blake2b\Blake2bContext.tt" LastGenOutput="Blake2bContext.cs" Generator="TextTemplatingFileGenerator" />
35-
<None Update="Blake2s\Blake2sContext.tt" LastGenOutput="Blake2sContext.cs" Generator="TextTemplatingFileGenerator" />
34+
<None Update="Blake2b\Blake2bHashState.tt" LastGenOutput="Blake2bHashState.cs" Generator="TextTemplatingFileGenerator" />
35+
<None Update="Blake2s\Blake2sHashState.tt" LastGenOutput="Blake2sHashState.cs" Generator="TextTemplatingFileGenerator" />
3636
<None Update="Blake2b\Blake2bScalar.tt" LastGenOutput="Blake2bScalar.cs" Generator="TextTemplatingFileGenerator" />
3737
<None Update="Blake2s\Blake2sScalar.tt" LastGenOutput="Blake2sScalar.cs" Generator="TextTemplatingFileGenerator" />
3838
<None Update="Blake2b\Blake2bSse4.tt" LastGenOutput="Blake2bSse4.cs" Generator="TextTemplatingFileGenerator" />
3939
<None Update="Blake2s\Blake2sSse4.tt" LastGenOutput="Blake2sSse4.cs" Generator="TextTemplatingFileGenerator" />
4040
<None Update="Blake2b\Blake2bAvx2.tt" LastGenOutput="Blake2bAvx2.cs" Generator="TextTemplatingFileGenerator" />
4141
<Compile Update="Blake2b\Blake2b.cs" DependentUpon="Blake2b.tt" DesignTime="True" AutoGen="True" />
4242
<Compile Update="Blake2s\Blake2s.cs" DependentUpon="Blake2s.tt" DesignTime="True" AutoGen="True" />
43-
<Compile Update="Blake2b\Blake2bContext.cs" DependentUpon="Blake2bContext.tt" DesignTime="True" AutoGen="True" />
44-
<Compile Update="Blake2s\Blake2sContext.cs" DependentUpon="Blake2sContext.tt" DesignTime="True" AutoGen="True" />
43+
<Compile Update="Blake2b\Blake2bHashState.cs" DependentUpon="Blake2bHashState.tt" DesignTime="True" AutoGen="True" />
44+
<Compile Update="Blake2s\Blake2sHashState.cs" DependentUpon="Blake2sHashState.tt" DesignTime="True" AutoGen="True" />
4545
<Compile Update="Blake2b\Blake2bScalar.cs" DependentUpon="Blake2bScalar.tt" DesignTime="True" AutoGen="True" />
4646
<Compile Update="Blake2s\Blake2sScalar.cs" DependentUpon="Blake2sScalar.tt" DesignTime="True" AutoGen="True" />
4747
<Compile Update="Blake2b\Blake2bSse4.cs" DependentUpon="Blake2bSse4.tt" DesignTime="True" AutoGen="True" />

src/Blake2Fast/Blake2Hmac.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,8 @@ private IBlake2Incremental createIncrementalInstance()
6363
#endif
6464

6565
return alg == Algorithm.Blake2b ?
66-
Blake2b.CreateIncrementalHasher(HashSizeValue / 8, key) :
67-
Blake2s.CreateIncrementalHasher(HashSizeValue / 8, key);
66+
(IBlake2Incremental)Blake2b.CreateIncrementalHasher(HashSizeValue / 8, key) :
67+
(IBlake2Incremental)Blake2s.CreateIncrementalHasher(HashSizeValue / 8, key);
6868
}
6969
}
7070
}

src/Blake2Fast/Blake2b/Blake2b.cs

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
using System.Security.Cryptography;
1313
#endif
1414

15+
using Blake2Fast.Implementation;
16+
1517
namespace Blake2Fast
1618
{
1719
/// <summary>Static helper methods for BLAKE2b hashing.</summary>
@@ -23,7 +25,7 @@ namespace Blake2Fast
2325
static class Blake2b
2426
{
2527
/// <summary>The default hash digest length in bytes. For BLAKE2b, this value is 64.</summary>
26-
public const int DefaultDigestLength = Blake2bContext.HashBytes;
28+
public const int DefaultDigestLength = Blake2bHashState.HashBytes;
2729

2830
/// <inheritdoc cref="ComputeHash(int, ReadOnlySpan{byte}, ReadOnlySpan{byte})" />
2931
public static byte[] ComputeHash(ReadOnlySpan<byte> input) => ComputeHash(DefaultDigestLength, default, input);
@@ -42,10 +44,10 @@ static class Blake2b
4244
/// <returns>The computed hash digest from the message bytes in <paramref name="input" />.</returns>
4345
public static byte[] ComputeHash(int digestLength, ReadOnlySpan<byte> key, ReadOnlySpan<byte> input)
4446
{
45-
var ctx = default(Blake2bContext);
46-
ctx.Init(digestLength, key);
47-
ctx.Update(input);
48-
return ctx.Finish();
47+
var hs = default(Blake2bHashState);
48+
hs.Init(digestLength, key);
49+
hs.Update(input);
50+
return hs.Finish();
4951
}
5052

5153
/// <inheritdoc cref="ComputeAndWriteHash(ReadOnlySpan{byte}, ReadOnlySpan{byte}, Span{byte})" />
@@ -69,31 +71,31 @@ public static void ComputeAndWriteHash(int digestLength, ReadOnlySpan<byte> key,
6971
if (output.Length < digestLength)
7072
throw new ArgumentException($"Output buffer must have a capacity of at least {digestLength} bytes.", nameof(output));
7173

72-
var ctx = default(Blake2bContext);
73-
ctx.Init(digestLength, key);
74-
ctx.Update(input);
75-
ctx.TryFinish(output, out int _);
74+
var hs = default(Blake2bHashState);
75+
hs.Init(digestLength, key);
76+
hs.Update(input);
77+
hs.Finish(output);
7678
}
7779

7880
/// <inheritdoc cref="CreateIncrementalHasher(int, ReadOnlySpan{byte})" />
79-
public static IBlake2Incremental CreateIncrementalHasher() => CreateIncrementalHasher(DefaultDigestLength, default);
81+
public static Blake2bHashState CreateIncrementalHasher() => CreateIncrementalHasher(DefaultDigestLength, default);
8082

8183
/// <inheritdoc cref="CreateIncrementalHasher(int, ReadOnlySpan{byte})" />
82-
public static IBlake2Incremental CreateIncrementalHasher(int digestLength) => CreateIncrementalHasher(digestLength, default);
84+
public static Blake2bHashState CreateIncrementalHasher(int digestLength) => CreateIncrementalHasher(digestLength, default);
8385

8486
/// <inheritdoc cref="CreateIncrementalHasher(int, ReadOnlySpan{byte})" />
85-
public static IBlake2Incremental CreateIncrementalHasher(ReadOnlySpan<byte> key) => CreateIncrementalHasher(DefaultDigestLength, key);
87+
public static Blake2bHashState CreateIncrementalHasher(ReadOnlySpan<byte> key) => CreateIncrementalHasher(DefaultDigestLength, key);
8688

8789
/// <summary>Create and initialize an incremental BLAKE2b hash computation.</summary>
8890
/// <remarks>If you will receive the input in segments rather than all at once, this is the most efficient way to calculate the hash.</remarks>
8991
/// <param name="digestLength">The hash digest length in bytes. Valid values are 1 to 64.</param>
9092
/// <param name="key">0 to 64 bytes of input for initializing a keyed hash.</param>
91-
/// <returns>An <see cref="IBlake2Incremental" /> interface for updating and finalizing the hash.</returns>
92-
public static IBlake2Incremental CreateIncrementalHasher(int digestLength, ReadOnlySpan<byte> key)
93+
/// <returns>An <see cref="Blake2bHashState" /> instance for updating and finalizing the hash.</returns>
94+
public static Blake2bHashState CreateIncrementalHasher(int digestLength, ReadOnlySpan<byte> key)
9395
{
94-
var ctx = default(Blake2bContext);
95-
ctx.Init(digestLength, key);
96-
return ctx;
96+
var hs = default(Blake2bHashState);
97+
hs.Init(digestLength, key);
98+
return hs;
9799
}
98100

99101
#if BLAKE2_CRYPTOGRAPHY

src/Blake2Fast/Blake2b/Blake2bAvx2.cs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,14 @@
1111
using System.Runtime.InteropServices;
1212
using System.Runtime.CompilerServices;
1313

14-
namespace Blake2Fast
14+
namespace Blake2Fast.Implementation
1515
{
16-
unsafe internal partial struct Blake2bContext
16+
#if BLAKE2_PUBLIC
17+
public
18+
#else
19+
internal
20+
#endif
21+
unsafe partial struct Blake2bHashState
1722
{
1823
// SIMD algorithm described in https://eprint.iacr.org/2012/275.pdf
1924
[MethodImpl(MethodImplOptions.AggressiveOptimization)]

src/Blake2Fast/Blake2b/Blake2bAvx2.tt

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,14 @@ using System.Runtime.Intrinsics.X86;
1313
using System.Runtime.InteropServices;
1414
using System.Runtime.CompilerServices;
1515

16-
namespace Blake2Fast
16+
namespace Blake2Fast.Implementation
1717
{
18-
unsafe internal partial struct Blake2bContext
18+
#if BLAKE2_PUBLIC
19+
public
20+
#else
21+
internal
22+
#endif
23+
unsafe partial struct Blake2bHashState
1924
{
2025
// SIMD algorithm described in https://eprint.iacr.org/2012/275.pdf
2126
[MethodImpl(MethodImplOptions.AggressiveOptimization)]

src/Blake2Fast/Blake2b/Blake2bContext.cs renamed to src/Blake2Fast/Blake2b/Blake2bHashState.cs

Lines changed: 33 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,23 @@
1313
using System.Runtime.Intrinsics.X86;
1414
#endif
1515

16-
namespace Blake2Fast
16+
namespace Blake2Fast.Implementation
1717
{
18-
unsafe internal partial struct Blake2bContext : IBlake2Incremental
18+
/// <summary>Defines the state associated with an incremental BLAKE2b hashing operation.</summary>
19+
/// <remarks>Instances of this struct must be created by <see cref="Blake2b.CreateIncrementalHasher()" />. An instance created directly will be unusable.</remarks>
20+
#if BLAKE2_PUBLIC
21+
public
22+
#else
23+
internal
24+
#endif
25+
unsafe partial struct Blake2bHashState : IBlake2Incremental
1926
{
20-
public const int WordSize = sizeof(ulong);
21-
public const int BlockWords = 16;
22-
public const int BlockBytes = BlockWords * WordSize;
23-
public const int HashWords = 8;
24-
public const int HashBytes = HashWords * WordSize;
25-
public const int MaxKeyBytes = HashBytes;
27+
internal const int WordSize = sizeof(ulong);
28+
internal const int BlockWords = 16;
29+
internal const int BlockBytes = BlockWords * WordSize;
30+
internal const int HashWords = 8;
31+
internal const int HashBytes = HashWords * WordSize;
32+
internal const int MaxKeyBytes = HashBytes;
2633

2734
private fixed byte b[BlockBytes];
2835
private fixed ulong h[HashWords];
@@ -49,14 +56,15 @@ unsafe internal partial struct Blake2bContext : IBlake2Incremental
4956
};
5057
#endif
5158

59+
/// <inheritdoc />
5260
public int DigestLength => (int)outlen;
5361

5462
private void compress(ref byte input, uint offs, uint cb)
5563
{
5664
uint inc = Math.Min(cb, BlockBytes);
5765

5866
fixed (byte* pinput = &input)
59-
fixed (Blake2bContext* s = &this)
67+
fixed (Blake2bHashState* s = &this)
6068
{
6169
ulong* sh = s->h;
6270
byte* pin = pinput + offs;
@@ -86,7 +94,7 @@ private void compress(ref byte input, uint offs, uint cb)
8694
}
8795
}
8896

89-
public void Init(int digestLength = HashBytes, ReadOnlySpan<byte> key = default)
97+
internal void Init(int digestLength = HashBytes, ReadOnlySpan<byte> key = default)
9098
{
9199
uint keylen = (uint)key.Length;
92100

@@ -106,8 +114,10 @@ public void Init(int digestLength = HashBytes, ReadOnlySpan<byte> key = default)
106114
}
107115
}
108116

117+
/// <inheritdoc />
109118
public void Update(ReadOnlySpan<byte> input)
110119
{
120+
if (outlen == 0) ThrowHelper.HashNotInitialized();
111121
if (f[0] != 0) ThrowHelper.HashFinalized();
112122

113123
uint consumed = 0;
@@ -141,13 +151,15 @@ public void Update(ReadOnlySpan<byte> input)
141151
}
142152
}
143153

154+
/// <inheritdoc />
144155
public void Update<T>(ReadOnlySpan<T> input) where T : struct
145156
{
146157
ThrowHelper.ThrowIfIsRefOrContainsRefs<T>();
147158

148159
Update(MemoryMarshal.AsBytes(input));
149160
}
150161

162+
/// <inheritdoc />
151163
public void Update<T>(T input) where T : struct
152164
{
153165
ThrowHelper.ThrowIfIsRefOrContainsRefs<T>();
@@ -172,6 +184,7 @@ public void Update<T>(T input) where T : struct
172184

173185
private void finish(Span<byte> hash)
174186
{
187+
if (outlen == 0) ThrowHelper.HashNotInitialized();
175188
if (f[0] != 0) ThrowHelper.HashFinalized();
176189

177190
if (c < BlockBytes)
@@ -183,6 +196,7 @@ private void finish(Span<byte> hash)
183196
Unsafe.CopyBlockUnaligned(ref hash[0], ref Unsafe.As<ulong, byte>(ref h[0]), outlen);
184197
}
185198

199+
/// <inheritdoc />
186200
public byte[] Finish()
187201
{
188202
byte[] hash = new byte[outlen];
@@ -191,6 +205,15 @@ public byte[] Finish()
191205
return hash;
192206
}
193207

208+
/// <inheritdoc />
209+
public void Finish(Span<byte> output)
210+
{
211+
if ((uint)output.Length < outlen) ThrowHelper.OutputTooSmall(DigestLength);
212+
213+
finish(output);
214+
}
215+
216+
/// <inheritdoc />
194217
public bool TryFinish(Span<byte> output, out int bytesWritten)
195218
{
196219
if ((uint)output.Length < outlen)
File renamed without changes.

src/Blake2Fast/Blake2b/Blake2bScalar.cs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,14 @@
55
// </auto-generated>
66
//------------------------------------------------------------------------------
77

8-
namespace Blake2Fast
8+
namespace Blake2Fast.Implementation
99
{
10-
unsafe internal partial struct Blake2bContext
10+
#if BLAKE2_PUBLIC
11+
public
12+
#else
13+
internal
14+
#endif
15+
unsafe partial struct Blake2bHashState
1116
{
1217
private static void mixScalar(ulong* sh, ulong* m)
1318
{

src/Blake2Fast/Blake2b/Blake2bSse4.cs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,14 @@
1111
using System.Runtime.InteropServices;
1212
using System.Runtime.CompilerServices;
1313

14-
namespace Blake2Fast
14+
namespace Blake2Fast.Implementation
1515
{
16-
unsafe internal partial struct Blake2bContext
16+
#if BLAKE2_PUBLIC
17+
public
18+
#else
19+
internal
20+
#endif
21+
unsafe partial struct Blake2bHashState
1722
{
1823
// SIMD algorithm described in https://eprint.iacr.org/2012/275.pdf
1924
#if !HWINTRINSICS_EXP

src/Blake2Fast/Blake2b/Blake2bSse4.tt

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,14 @@ using System.Runtime.Intrinsics.X86;
1313
using System.Runtime.InteropServices;
1414
using System.Runtime.CompilerServices;
1515

16-
namespace Blake2Fast
16+
namespace Blake2Fast.Implementation
1717
{
18-
unsafe internal partial struct Blake2bContext
18+
#if BLAKE2_PUBLIC
19+
public
20+
#else
21+
internal
22+
#endif
23+
unsafe partial struct Blake2bHashState
1924
{
2025
// SIMD algorithm described in https://eprint.iacr.org/2012/275.pdf
2126
#if !HWINTRINSICS_EXP

0 commit comments

Comments
 (0)