diff --git a/crypto/src/crypto/IDigest.cs b/crypto/src/crypto/IDigest.cs
index 36caf3728e..c705723531 100644
--- a/crypto/src/crypto/IDigest.cs
+++ b/crypto/src/crypto/IDigest.cs
@@ -9,41 +9,41 @@ public interface IDigest
string AlgorithmName { get; }
/// Return the size, in bytes, of the digest produced by this message digest.
- /// the size, in bytes, of the digest produced by this message digest.
+ /// The size, in bytes, of the digest produced by this message digest.
int GetDigestSize();
/// Return the size, in bytes, of the internal buffer used by this digest.
- /// the size, in bytes, of the internal buffer used by this digest.
+ /// The size, in bytes, of the internal buffer used by this digest.
int GetByteLength();
/// Update the message digest with a single byte.
- /// the input byte to be entered.
+ /// The input byte to be entered.
void Update(byte input);
/// Update the message digest with a block of bytes.
- /// the byte array containing the data.
- /// the offset into the byte array where the data starts.
- /// the length of the data.
+ /// The byte array containing the data.
+ /// The offset into the byte array where the data starts.
+ /// The length of the data.
void BlockUpdate(byte[] input, int inOff, int inLen);
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
/// Update the message digest with a span of bytes.
- /// the span containing the data.
+ /// The span containing the data.
void BlockUpdate(ReadOnlySpan input);
#endif
/// Close the digest, producing the final digest value.
/// This call leaves the digest reset.
- /// the byte array the digest is to be copied into.
- /// the offset into the byte array the digest is to start at.
- /// the number of bytes written
+ /// The byte array the digest is to be copied into.
+ /// The offset into the byte array the digest is to start at.
+ /// The number of bytes written.
int DoFinal(byte[] output, int outOff);
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
/// Close the digest, producing the final digest value.
/// This call leaves the digest reset.
- /// the span the digest is to be copied into.
- /// the number of bytes written
+ /// The span the digest is to be copied into.
+ /// The number of bytes written.
int DoFinal(Span output);
#endif
diff --git a/crypto/src/crypto/digests/Blake2bDigest.cs b/crypto/src/crypto/digests/Blake2bDigest.cs
index b880bc5683..8d9c95be82 100644
--- a/crypto/src/crypto/digests/Blake2bDigest.cs
+++ b/crypto/src/crypto/digests/Blake2bDigest.cs
@@ -30,18 +30,22 @@ This implementation does not support the Tree Hashing Mode.
---------------+--------+-----------+------+------------+
*/
- /**
- * Implementation of the cryptographic hash function Blake2b.
- *
- * Blake2b offers a built-in keying mechanism to be used directly
- * for authentication ("Prefix-MAC") rather than a HMAC construction.
- *
- * Blake2b offers a built-in support for a salt for randomized hashing
- * and a personal string for defining a unique hash function for each application.
- *
- * BLAKE2b is optimized for 64-bit platforms and produces digests of any size
- * between 1 and 64 bytes.
- */
+ ///
+ /// Implementation of the cryptographic hash function Blake2b.
+ /// BLAKE2b is optimized for 64-bit platforms and produces digests of any size
+ /// between 1 and 64 bytes.
+ ///
+ ///
+ ///
+ ///
+ /// Blake2b offers a built-in keying mechanism to be used directly
+ /// for authentication ("Prefix-MAC") rather than a HMAC construction.
+ ///
+ ///
+ /// Blake2b offers a built-in support for a salt for randomized hashing
+ /// and a personal string for defining a unique hash function for each application.
+ ///
+ ///
public sealed class Blake2bDigest
: IDigest
{
@@ -87,7 +91,7 @@ public sealed class Blake2bDigest
// Tree hashing parameters:
// Because this class does not implement the Tree Hashing Mode,
// these parameters can be treated as constants (see init() function)
- /*
+ /*
* private int fanout = 1; // 0-255 private int depth = 1; // 1 - 255
* private int leafLength= 0; private long nodeOffset = 0L; private int
* nodeDepth = 0; private int innerHashLength = 0;
@@ -112,11 +116,18 @@ public sealed class Blake2bDigest
// For Tree Hashing Mode, not used here:
// private long f1 = 0L; // finalization flag, for last node: ~0L
+ ///
+ /// Initializes a new instance of .
+ ///
public Blake2bDigest()
: this(512)
{
}
+ ///
+ /// Constructs a new instance of from another ./>.
+ ///
+ /// The original instance of that is copied.
public Blake2bDigest(Blake2bDigest digest)
{
this.bufferPos = digest.bufferPos;
@@ -132,11 +143,11 @@ public Blake2bDigest(Blake2bDigest digest)
this.f0 = digest.f0;
}
- /**
- * Basic sized constructor - size in bits.
- *
- * @param digestSize size of the digest in bits
- */
+ ///
+ /// Initializes a new instance of with a given digest size.
+ ///
+ /// Digest size in bits.
+ ///
public Blake2bDigest(int digestSize)
{
if (digestSize < 8 || digestSize > 512 || digestSize % 8 != 0)
@@ -148,15 +159,18 @@ public Blake2bDigest(int digestSize)
Init();
}
- /**
- * Blake2b for authentication ("Prefix-MAC mode").
- * After calling the doFinal() method, the key will
- * remain to be used for further computations of
- * this instance.
- * The key can be overwritten using the clearKey() method.
- *
- * @param key A key up to 64 bytes or null
- */
+ ///
+ ///
+ /// Initializes a new instance of with a key.
+ ///
+ ///
+ /// Blake2b for authentication ("Prefix-MAC mode").
+ /// After calling the method, the key will
+ /// remain to be used for further computations of this instance.
+ /// The key can be cleared using the method.
+ ///
+ /// A key up to 64 bytes or null.
+ ///
public Blake2bDigest(byte[] key)
{
buffer = new byte[BLOCK_LENGTH_BYTES];
@@ -176,18 +190,21 @@ public Blake2bDigest(byte[] key)
Init();
}
- /**
- * Blake2b with key, required digest length (in bytes), salt and personalization.
- * After calling the doFinal() method, the key, the salt and the personal string
- * will remain and might be used for further computations with this instance.
- * The key can be overwritten using the clearKey() method, the salt (pepper)
- * can be overwritten using the clearSalt() method.
- *
- * @param key A key up to 64 bytes or null
- * @param digestLength from 1 up to 64 bytes
- * @param salt 16 bytes or null
- * @param personalization 16 bytes or null
- */
+ ///
+ ///
+ /// Initializes a new instance of with a key, required digest length (in bytes), salt and personalization.
+ ///
+ ///
+ /// After calling the method, the key, the salt and the personalization
+ /// will remain and might be used for further computations with this instance.
+ /// The key can be overwritten using the method, the salt (pepper)
+ /// can be overwritten using the method.
+ ///
+ /// A key up to 64 bytes or null.
+ /// Digest length from 1 to 64 bytes.
+ /// A 16 bytes or nullable salt.
+ /// A 16 bytes or null personalization.
+ ///
public Blake2bDigest(byte[] key, int digestLength, byte[] salt, byte[] personalization)
{
if (digestLength < 1 || digestLength > 64)
@@ -274,11 +291,7 @@ private void InitializeInternalState()
internalState[15] = blake2b_IV[7];// ^ f1 with f1 = 0
}
- /**
- * update the message digest with a single byte.
- *
- * @param b the input byte to be entered.
- */
+ ///
public void Update(byte b)
{
// process the buffer if full else add to buffer:
@@ -306,13 +319,7 @@ public void Update(byte b)
}
}
- /**
- * update the message digest with a block of bytes.
- *
- * @param message the byte array containing the data.
- * @param offset the offset into the byte array where the data starts.
- * @param len the length of the data.
- */
+ ///
public void BlockUpdate(byte[] message, int offset, int len)
{
if (message == null || len == 0)
@@ -369,6 +376,7 @@ public void BlockUpdate(byte[] message, int offset, int len)
}
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ ///
public void BlockUpdate(ReadOnlySpan input)
{
if (input.IsEmpty)
@@ -421,14 +429,14 @@ public void BlockUpdate(ReadOnlySpan input)
}
#endif
- /**
- * close the digest, producing the final digest value. The doFinal
- * call leaves the digest reset.
- * Key, salt and personal string remain.
- *
- * @param out the array the digest is to be copied into.
- * @param outOffset the offset into the out array the digest is to start at.
- */
+ /// Close the digest, producing the final digest value.
+ ///
+ /// The call leaves the digest reset.
+ /// Key, salt and personal string remain.
+ ///
+ /// The byte array the digest is to be copied into.
+ /// The offset into the byte array the digest is to start at.
+ /// The number of bytes written.
public int DoFinal(byte[] output, int outOffset)
{
Check.OutputLength(output, outOffset, digestLength, "output buffer too short");
@@ -464,6 +472,13 @@ public int DoFinal(byte[] output, int outOffset)
}
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ /// Close the digest, producing the final digest value.
+ ///
+ /// The call leaves the digest reset.
+ /// Key, salt and personal string remain.
+ ///
+ /// The span the digest is to be copied into.
+ /// The number of bytes written.
public int DoFinal(Span output)
{
Check.OutputLength(output, digestLength, "output buffer too short");
@@ -495,11 +510,10 @@ public int DoFinal(Span output)
}
#endif
- /**
- * Reset the digest back to it's initial state.
- * The key, the salt and the personal string will
- * remain for further computations.
- */
+ ///
+ /// Reset the digest back to it's initial state.
+ /// The key, the salt and the personalization will remain for further computations.
+ ///
public void Reset()
{
bufferPos = 0;
@@ -519,6 +533,13 @@ public void Reset()
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
private void Compress(ReadOnlySpan message)
{
+#if NETCOREAPP3_0_OR_GREATER
+ if (Blake2b_X86.IsSupported)
+ {
+ Blake2b_X86.Compress(f0 == ulong.MaxValue, chainValue, message, t0, t1, blake2b_IV);
+ return;
+ }
+#endif
InitializeInternalState();
Span m = stackalloc ulong[16];
@@ -594,38 +615,28 @@ private static ulong Rotr64(ulong x, int rot)
return x >> rot | x << -rot;
}
- /**
- * return the algorithm name
- *
- * @return the algorithm name
- */
+ ///
public string AlgorithmName => "BLAKE2b";
- /**
- * return the size, in bytes, of the digest produced by this message digest.
- *
- * @return the size, in bytes, of the digest produced by this message digest.
- */
+ ///
public int GetDigestSize()
{
return digestLength;
}
- /**
- * Return the size in bytes of the internal buffer the digest applies it's compression
- * function to.
- *
- * @return byte length of the digests internal buffer.
- */
+ ///
+ /// Return the size in bytes of the internal buffer the digest applies it's compression
+ /// function to.
+ ///
+ /// The byte length of the digests internal buffer.
public int GetByteLength()
{
return BLOCK_LENGTH_BYTES;
}
- /**
- * Overwrite the key
- * if it is no longer used (zeroization)
- */
+ ///
+ /// Clears the key.
+ ///
public void ClearKey()
{
if (key != null)
@@ -635,10 +646,9 @@ public void ClearKey()
}
}
- /**
- * Overwrite the salt (pepper) if it
- * is secret and no longer used (zeroization)
- */
+ ///
+ /// Clears the salt (pepper).
+ ///
public void ClearSalt()
{
if (salt != null)
diff --git a/crypto/src/crypto/digests/Blake2b_X86.cs b/crypto/src/crypto/digests/Blake2b_X86.cs
new file mode 100644
index 0000000000..f121d3c1a1
--- /dev/null
+++ b/crypto/src/crypto/digests/Blake2b_X86.cs
@@ -0,0 +1,419 @@
+#if NETCOREAPP3_0_OR_GREATER
+using System;
+using System.Diagnostics;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Runtime.Intrinsics;
+using System.Runtime.Intrinsics.X86;
+
+namespace Org.BouncyCastle.Crypto.Digests
+{
+ // License from the original code created by Clinton Ingram (saucecontrol) for Blake2Fast
+ // at https://github.com/saucecontrol/Blake2Fast. The code has been copied and modified.
+
+ // The MIT License
+
+ // Copyright(c) 2018-2021 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
+ // in the Software without restriction, including without limitation the rights
+ // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ // copies of the Software, and to permit persons to whom the Software is
+ // furnished to do so, subject to the following conditions:
+
+ // The above copyright notice and this permission notice shall be included in
+ // all copies or substantial portions of the Software.
+
+ // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ // THE SOFTWARE.
+
+ internal static class Blake2b_X86
+ {
+ public static bool IsSupported => Avx2.IsSupported && BitConverter.IsLittleEndian;
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void Compress(bool isFinal, Span hashBuffer, ReadOnlySpan message, ulong totalSegmentsLow, ulong totalSegmentsHigh, ReadOnlySpan blakeIV)
+ {
+ if (!IsSupported)
+ throw new PlatformNotSupportedException(nameof(Blake2b_X86));
+
+ Debug.Assert(message.Length >= Unsafe.SizeOf() * 8);
+ Debug.Assert(hashBuffer.Length >= 8);
+
+ var hashBytes = MemoryMarshal.AsBytes(hashBuffer);
+ var ivBytes = MemoryMarshal.AsBytes(blakeIV);
+
+ var r_14 = isFinal ? ulong.MaxValue : 0;
+ var t_0 = Vector256.Create(totalSegmentsLow, totalSegmentsHigh, r_14, 0);
+
+ Vector256 row1 = LoadVector256(hashBytes);
+ Vector256 row2 = LoadVector256(hashBytes[Vector256.Count..]);
+ Vector256 row3 = LoadVector256(ivBytes);
+ Vector256 row4 = LoadVector256(ivBytes[Vector256.Count..]);
+ row4 = Avx2.Xor(row4, t_0);
+
+ Vector256 orig_1 = row1;
+ Vector256 orig_2 = row2;
+
+ Perform12Rounds(message, ref row1, ref row2, ref row3, ref row4);
+
+ row1 = Avx2.Xor(row1, row3);
+ row2 = Avx2.Xor(row2, row4);
+ row1 = Avx2.Xor(row1, orig_1);
+ row2 = Avx2.Xor(row2, orig_2);
+
+ Store(row1, hashBytes);
+ Store(row2, hashBytes[Vector256.Count..]);
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static void Perform12Rounds(ReadOnlySpan m, ref Vector256 row1, ref Vector256 row2, ref Vector256 row3, ref Vector256 row4)
+ {
+ Debug.Assert(m.Length >= 128);
+
+ #region Rounds
+ //ROUND 1
+ var m0 = BroadcastVector128ToVector256(m);
+ var m1 = BroadcastVector128ToVector256(m[Unsafe.SizeOf>()..]);
+ var m2 = BroadcastVector128ToVector256(m[(Unsafe.SizeOf>() * 2)..]);
+ var m3 = BroadcastVector128ToVector256(m[(Unsafe.SizeOf>() * 3)..]);
+
+ var t0 = Avx2.UnpackLow(m0, m1);
+ var t1 = Avx2.UnpackLow(m2, m3);
+ var b1 = Avx2.Blend(t0.AsUInt32(), t1.AsUInt32(), 0b_1111_0000).AsUInt64();
+
+ t0 = Avx2.UnpackHigh(m0, m1);
+ t1 = Avx2.UnpackHigh(m2, m3);
+ var b2 = Avx2.Blend(t0.AsUInt32(), t1.AsUInt32(), 0b_1111_0000).AsUInt64();
+
+ var m4 = BroadcastVector128ToVector256(m[(Unsafe.SizeOf>() * 4)..]);
+ var m5 = BroadcastVector128ToVector256(m[(Unsafe.SizeOf>() * 5)..]);
+ var m6 = BroadcastVector128ToVector256(m[(Unsafe.SizeOf>() * 6)..]);
+ var m7 = BroadcastVector128ToVector256(m[(Unsafe.SizeOf>() * 7)..]);
+
+ t0 = Avx2.UnpackLow(m7, m4);
+ t1 = Avx2.UnpackLow(m5, m6);
+ var b3 = Avx2.Blend(t0.AsUInt32(), t1.AsUInt32(), 0b_1111_0000).AsUInt64();
+
+ t0 = Avx2.UnpackHigh(m7, m4);
+ t1 = Avx2.UnpackHigh(m5, m6);
+ var b4 = Avx2.Blend(t0.AsUInt32(), t1.AsUInt32(), 0b_1111_0000).AsUInt64();
+
+ Round(ref row1, ref row2, ref row3, ref row4, b1, b2, b3, b4);
+
+ //ROUND 2
+ t0 = Avx2.UnpackLow(m7, m2);
+ t1 = Avx2.UnpackHigh(m4, m6);
+ b1 = Avx2.Blend(t0.AsUInt32(), t1.AsUInt32(), 0b_1111_0000).AsUInt64();
+
+ t0 = Avx2.UnpackLow(m5, m4);
+ t1 = Avx2.AlignRight(m3, m7, 8);
+ b2 = Avx2.Blend(t0.AsUInt32(), t1.AsUInt32(), 0b_1111_0000).AsUInt64();
+
+ t0 = Avx2.UnpackHigh(m2, m0);
+ t1 = Avx2.Blend(m0.AsUInt32(), m5.AsUInt32(), 0b_1100_1100).AsUInt64();
+ b3 = Avx2.Blend(t0.AsUInt32(), t1.AsUInt32(), 0b_1111_0000).AsUInt64();
+
+ t0 = Avx2.AlignRight(m6, m1, 8);
+ t1 = Avx2.Blend(m1.AsUInt32(), m3.AsUInt32(), 0b_1100_1100).AsUInt64();
+ b4 = Avx2.Blend(t0.AsUInt32(), t1.AsUInt32(), 0b_1111_0000).AsUInt64();
+
+ Round(ref row1, ref row2, ref row3, ref row4, b1, b2, b3, b4);
+
+ //ROUND 3
+ t0 = Avx2.AlignRight(m6, m5, 8);
+ t1 = Avx2.UnpackHigh(m2, m7);
+ b1 = Avx2.Blend(t0.AsUInt32(), t1.AsUInt32(), 0b_1111_0000).AsUInt64();
+
+ t0 = Avx2.UnpackLow(m4, m0);
+ t1 = Avx2.Blend(m1.AsUInt32(), m6.AsUInt32(), 0b_1100_1100).AsUInt64();
+ b2 = Avx2.Blend(t0.AsUInt32(), t1.AsUInt32(), 0b_1111_0000).AsUInt64();
+
+ t0 = Avx2.AlignRight(m5, m4, 8);
+ t1 = Avx2.UnpackHigh(m1, m3);
+ b3 = Avx2.Blend(t0.AsUInt32(), t1.AsUInt32(), 0b_1111_0000).AsUInt64();
+
+ t0 = Avx2.UnpackLow(m2, m7);
+ t1 = Avx2.Blend(m3.AsUInt32(), m0.AsUInt32(), 0b_1100_1100).AsUInt64();
+ b4 = Avx2.Blend(t0.AsUInt32(), t1.AsUInt32(), 0b_1111_0000).AsUInt64();
+
+ Round(ref row1, ref row2, ref row3, ref row4, b1, b2, b3, b4);
+
+ //ROUND 4
+ t0 = Avx2.UnpackHigh(m3, m1);
+ t1 = Avx2.UnpackHigh(m6, m5);
+ b1 = Avx2.Blend(t0.AsUInt32(), t1.AsUInt32(), 0b_1111_0000).AsUInt64();
+
+ t0 = Avx2.UnpackHigh(m4, m0);
+ t1 = Avx2.UnpackLow(m6, m7);
+ b2 = Avx2.Blend(t0.AsUInt32(), t1.AsUInt32(), 0b_1111_0000).AsUInt64();
+
+ t0 = Avx2.AlignRight(m1, m7, 8);
+ t1 = Avx2.Shuffle(m2.AsUInt32(), 0b_01_00_11_10).AsUInt64();
+ b3 = Avx2.Blend(t0.AsUInt32(), t1.AsUInt32(), 0b_1111_0000).AsUInt64();
+
+ t0 = Avx2.UnpackLow(m4, m3);
+ t1 = Avx2.UnpackLow(m5, m0);
+ b4 = Avx2.Blend(t0.AsUInt32(), t1.AsUInt32(), 0b_1111_0000).AsUInt64();
+
+ Round(ref row1, ref row2, ref row3, ref row4, b1, b2, b3, b4);
+
+ //ROUND 5
+ t0 = Avx2.UnpackHigh(m4, m2);
+ t1 = Avx2.UnpackLow(m1, m5);
+ b1 = Avx2.Blend(t0.AsUInt32(), t1.AsUInt32(), 0b_1111_0000).AsUInt64();
+
+ t0 = Avx2.Blend(m0.AsUInt32(), m3.AsUInt32(), 0b_1100_1100).AsUInt64();
+ t1 = Avx2.Blend(m2.AsUInt32(), m7.AsUInt32(), 0b_1100_1100).AsUInt64();
+ b2 = Avx2.Blend(t0.AsUInt32(), t1.AsUInt32(), 0b_1111_0000).AsUInt64();
+
+ t0 = Avx2.AlignRight(m7, m1, 8);
+ t1 = Avx2.AlignRight(m3, m5, 8);
+ b3 = Avx2.Blend(t0.AsUInt32(), t1.AsUInt32(), 0b_1111_0000).AsUInt64();
+
+ t0 = Avx2.UnpackHigh(m6, m0);
+ t1 = Avx2.UnpackLow(m6, m4);
+ b4 = Avx2.Blend(t0.AsUInt32(), t1.AsUInt32(), 0b_1111_0000).AsUInt64();
+
+ Round(ref row1, ref row2, ref row3, ref row4, b1, b2, b3, b4);
+
+ //ROUND 6
+ t0 = Avx2.UnpackLow(m1, m3);
+ t1 = Avx2.UnpackLow(m0, m4);
+ b1 = Avx2.Blend(t0.AsUInt32(), t1.AsUInt32(), 0b_1111_0000).AsUInt64();
+
+ t0 = Avx2.UnpackLow(m6, m5);
+ t1 = Avx2.UnpackHigh(m5, m1);
+ b2 = Avx2.Blend(t0.AsUInt32(), t1.AsUInt32(), 0b_1111_0000).AsUInt64();
+
+ t0 = Avx2.AlignRight(m2, m0, 8);
+ t1 = Avx2.UnpackHigh(m3, m7);
+ b3 = Avx2.Blend(t0.AsUInt32(), t1.AsUInt32(), 0b_1111_0000).AsUInt64();
+
+ t0 = Avx2.UnpackHigh(m4, m6);
+ t1 = Avx2.AlignRight(m7, m2, 8);
+ b4 = Avx2.Blend(t0.AsUInt32(), t1.AsUInt32(), 0b_1111_0000).AsUInt64();
+
+ Round(ref row1, ref row2, ref row3, ref row4, b1, b2, b3, b4);
+
+ //ROUND 7
+ t0 = Avx2.Blend(m6.AsUInt32(), m0.AsUInt32(), 0b_1100_1100).AsUInt64();
+ t1 = Avx2.UnpackLow(m7, m2);
+ b1 = Avx2.Blend(t0.AsUInt32(), t1.AsUInt32(), 0b_1111_0000).AsUInt64();
+
+ t0 = Avx2.UnpackHigh(m2, m7);
+ t1 = Avx2.AlignRight(m5, m6, 8);
+ b2 = Avx2.Blend(t0.AsUInt32(), t1.AsUInt32(), 0b_1111_0000).AsUInt64();
+
+ t0 = Avx2.UnpackLow(m4, m0);
+ t1 = Avx2.Blend(m3.AsUInt32(), m4.AsUInt32(), 0b_1100_1100).AsUInt64();
+ b3 = Avx2.Blend(t0.AsUInt32(), t1.AsUInt32(), 0b_1111_0000).AsUInt64();
+
+ t0 = Avx2.UnpackHigh(m5, m3);
+ t1 = Avx2.Shuffle(m1.AsUInt32(), 0b_01_00_11_10).AsUInt64();
+ b4 = Avx2.Blend(t0.AsUInt32(), t1.AsUInt32(), 0b_1111_0000).AsUInt64();
+
+ Round(ref row1, ref row2, ref row3, ref row4, b1, b2, b3, b4);
+
+ //ROUND 8
+ t0 = Avx2.UnpackHigh(m6, m3);
+ t1 = Avx2.Blend(m6.AsUInt32(), m1.AsUInt32(), 0b_1100_1100).AsUInt64();
+ b1 = Avx2.Blend(t0.AsUInt32(), t1.AsUInt32(), 0b_1111_0000).AsUInt64();
+
+ t0 = Avx2.AlignRight(m7, m5, 8);
+ t1 = Avx2.UnpackHigh(m0, m4);
+ b2 = Avx2.Blend(t0.AsUInt32(), t1.AsUInt32(), 0b_1111_0000).AsUInt64();
+
+ t0 = Avx2.Blend(m1.AsUInt32(), m2.AsUInt32(), 0b_1100_1100).AsUInt64();
+ t1 = Avx2.AlignRight(m4, m7, 8);
+ b3 = Avx2.Blend(t0.AsUInt32(), t1.AsUInt32(), 0b_1111_0000).AsUInt64();
+
+ t0 = Avx2.UnpackLow(m5, m0);
+ t1 = Avx2.UnpackLow(m2, m3);
+ b4 = Avx2.Blend(t0.AsUInt32(), t1.AsUInt32(), 0b_1111_0000).AsUInt64();
+
+ Round(ref row1, ref row2, ref row3, ref row4, b1, b2, b3, b4);
+
+ //ROUND 9
+ t0 = Avx2.UnpackLow(m3, m7);
+ t1 = Avx2.AlignRight(m0, m5, 8);
+ b1 = Avx2.Blend(t0.AsUInt32(), t1.AsUInt32(), 0b_1111_0000).AsUInt64();
+
+ t0 = Avx2.UnpackHigh(m7, m4);
+ t1 = Avx2.AlignRight(m4, m1, 8);
+ b2 = Avx2.Blend(t0.AsUInt32(), t1.AsUInt32(), 0b_1111_0000).AsUInt64();
+
+ t0 = Avx2.UnpackLow(m5, m6);
+ t1 = Avx2.UnpackHigh(m6, m0);
+ b3 = Avx2.Blend(t0.AsUInt32(), t1.AsUInt32(), 0b_1111_0000).AsUInt64();
+
+ t0 = Avx2.AlignRight(m1, m2, 8);
+ t1 = Avx2.AlignRight(m2, m3, 8);
+ b4 = Avx2.Blend(t0.AsUInt32(), t1.AsUInt32(), 0b_1111_0000).AsUInt64();
+
+ Round(ref row1, ref row2, ref row3, ref row4, b1, b2, b3, b4);
+
+ //ROUND 10
+ t0 = Avx2.UnpackLow(m5, m4);
+ t1 = Avx2.UnpackHigh(m3, m0);
+ b1 = Avx2.Blend(t0.AsUInt32(), t1.AsUInt32(), 0b_1111_0000).AsUInt64();
+
+ t0 = Avx2.UnpackLow(m1, m2);
+ t1 = Avx2.Blend(m3.AsUInt32(), m2.AsUInt32(), 0b_1100_1100).AsUInt64();
+ b2 = Avx2.Blend(t0.AsUInt32(), t1.AsUInt32(), 0b_1111_0000).AsUInt64();
+
+ t0 = Avx2.UnpackHigh(m6, m7);
+ t1 = Avx2.UnpackHigh(m4, m1);
+ b3 = Avx2.Blend(t0.AsUInt32(), t1.AsUInt32(), 0b_1111_0000).AsUInt64();
+
+ t0 = Avx2.Blend(m0.AsUInt32(), m5.AsUInt32(), 0b_1100_1100).AsUInt64();
+ t1 = Avx2.UnpackLow(m7, m6);
+ b4 = Avx2.Blend(t0.AsUInt32(), t1.AsUInt32(), 0b_1111_0000).AsUInt64();
+
+ Round(ref row1, ref row2, ref row3, ref row4, b1, b2, b3, b4);
+
+ //ROUND 11
+ t0 = Avx2.UnpackLow(m0, m1);
+ t1 = Avx2.UnpackLow(m2, m3);
+ b1 = Avx2.Blend(t0.AsUInt32(), t1.AsUInt32(), 0b_1111_0000).AsUInt64();
+
+ t0 = Avx2.UnpackHigh(m0, m1);
+ t1 = Avx2.UnpackHigh(m2, m3);
+ b2 = Avx2.Blend(t0.AsUInt32(), t1.AsUInt32(), 0b_1111_0000).AsUInt64();
+
+ t0 = Avx2.UnpackLow(m7, m4);
+ t1 = Avx2.UnpackLow(m5, m6);
+ b3 = Avx2.Blend(t0.AsUInt32(), t1.AsUInt32(), 0b_1111_0000).AsUInt64();
+
+ t0 = Avx2.UnpackHigh(m7, m4);
+ t1 = Avx2.UnpackHigh(m5, m6);
+ b4 = Avx2.Blend(t0.AsUInt32(), t1.AsUInt32(), 0b_1111_0000).AsUInt64();
+
+ Round(ref row1, ref row2, ref row3, ref row4, b1, b2, b3, b4);
+
+ //ROUND 12
+ t0 = Avx2.UnpackLow(m7, m2);
+ t1 = Avx2.UnpackHigh(m4, m6);
+ b1 = Avx2.Blend(t0.AsUInt32(), t1.AsUInt32(), 0b_1111_0000).AsUInt64();
+
+ t0 = Avx2.UnpackLow(m5, m4);
+ t1 = Avx2.AlignRight(m3, m7, 8);
+ b2 = Avx2.Blend(t0.AsUInt32(), t1.AsUInt32(), 0b_1111_0000).AsUInt64();
+
+ t0 = Avx2.UnpackHigh(m2, m0);
+ t1 = Avx2.Blend(m0.AsUInt32(), m5.AsUInt32(), 0b_1100_1100).AsUInt64();
+ b3 = Avx2.Blend(t0.AsUInt32(), t1.AsUInt32(), 0b_1111_0000).AsUInt64();
+
+ t0 = Avx2.AlignRight(m6, m1, 8);
+ t1 = Avx2.Blend(m1.AsUInt32(), m3.AsUInt32(), 0b_1100_1100).AsUInt64();
+ b4 = Avx2.Blend(t0.AsUInt32(), t1.AsUInt32(), 0b_1111_0000).AsUInt64();
+
+ Round(ref row1, ref row2, ref row3, ref row4, b1, b2, b3, b4);
+ #endregion
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static void Round(ref Vector256 row1, ref Vector256 row2, ref Vector256 row3, ref Vector256 row4, Vector256 b1, Vector256 b2, Vector256 b3, Vector256 b4)
+ {
+ Vector256 r24 = Vector256.Create((byte)3, 4, 5, 6, 7, 0, 1, 2, 11, 12, 13, 14, 15, 8, 9, 10, 3, 4, 5, 6, 7, 0, 1, 2, 11, 12, 13, 14, 15, 8, 9, 10);
+ Vector256 r16 = Vector256.Create((byte)2, 3, 4, 5, 6, 7, 0, 1, 10, 11, 12, 13, 14, 15, 8, 9, 2, 3, 4, 5, 6, 7, 0, 1, 10, 11, 12, 13, 14, 15, 8, 9);
+
+ G1(r24, ref row1, ref row2, ref row3, ref row4, b1);
+ G2(r16, ref row1, ref row2, ref row3, ref row4, b2);
+
+ Diagonalize(ref row1, ref row3, ref row4);
+
+ G1(r24, ref row1, ref row2, ref row3, ref row4, b3);
+ G2(r16, ref row1, ref row2, ref row3, ref row4, b4);
+
+ Undiagonalize(ref row1, ref row3, ref row4);
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static void Diagonalize(ref Vector256 row1, ref Vector256 row3, ref Vector256 row4)
+ {
+ // +-------------------+ +-------------------+
+ // | 0 | 1 | 2 | 3 | | 3 | 0 | 1 | 2 |
+ // +-------------------+ +-------------------+
+ // | 8 | 9 | 10 | 11 | ---> | 9 | 10 | 11 | 8 |
+ // +-------------------+ +-------------------+
+ // | 12 | 13 | 14 | 15 | | 14 | 15 | 12 | 13 |
+ // +-------------------+ +-------------------+
+
+ row1 = Avx2.Permute4x64(row1, 0b_10_01_00_11);
+ row3 = Avx2.Permute4x64(row3, 0b_00_11_10_01);
+ row4 = Avx2.Permute4x64(row4, 0b_01_00_11_10);
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static void G1(Vector256 r24, ref Vector256 row1, ref Vector256 row2, ref Vector256 row3, ref Vector256 row4, Vector256 b0)
+ {
+ row1 = Avx2.Add(Avx2.Add(row1, b0), row2);
+ row4 = Avx2.Xor(row4, row1);
+ row4 = Avx2.Shuffle(row4.AsUInt32(), 0b_10_11_00_01).AsUInt64();
+
+ row3 = Avx2.Add(row3, row4);
+ row2 = Avx2.Xor(row2, row3);
+ row2 = Avx2.Shuffle(row2.AsByte(), r24).AsUInt64();
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static void G2(Vector256 r16, ref Vector256 row1, ref Vector256 row2, ref Vector256 row3, ref Vector256 row4, Vector256 b0)
+ {
+ row1 = Avx2.Add(Avx2.Add(row1, b0), row2);
+ row4 = Avx2.Xor(row4, row1);
+ row4 = Avx2.Shuffle(row4.AsByte(), r16).AsUInt64();
+
+ row3 = Avx2.Add(row3, row4);
+ row2 = Avx2.Xor(row2, row3);
+ row2 = Avx2.Xor(Avx2.ShiftRightLogical(row2, 63), Avx2.Add(row2, row2));
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static void Undiagonalize(ref Vector256 row1, ref Vector256 row3, ref Vector256 row4)
+ {
+ // +-------------------+ +-------------------+
+ // | 3 | 0 | 1 | 2 | | 0 | 1 | 2 | 3 |
+ // +-------------------+ +-------------------+
+ // | 9 | 10 | 11 | 8 | ---> | 8 | 9 | 10 | 11 |
+ // +-------------------+ +-------------------+
+ // | 14 | 15 | 12 | 13 | | 12 | 13 | 14 | 15 |
+ // +-------------------+ +-------------------+
+
+ row1 = Avx2.Permute4x64(row1, 0b_00_11_10_01);
+ row3 = Avx2.Permute4x64(row3, 0b_10_01_00_11);
+ row4 = Avx2.Permute4x64(row4, 0b_01_00_11_10);
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static Vector256 BroadcastVector128ToVector256(ReadOnlySpan source) where T : struct
+ {
+ Debug.Assert(source.Length >= Unsafe.SizeOf>());
+
+ var vector = MemoryMarshal.Read>(source);
+ Vector256 result = vector.ToVector256Unsafe();
+ return result.WithUpper(vector);
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static Vector256 LoadVector256(ReadOnlySpan source) where T : struct
+ {
+ Debug.Assert(source.Length >= Unsafe.SizeOf>());
+ return MemoryMarshal.Read>(source);
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static void Store(Vector256 vector, Span destination) where T : struct
+ {
+ Debug.Assert(destination.Length >= Unsafe.SizeOf>());
+ MemoryMarshal.Write(destination, ref vector);
+ }
+ }
+}
+#endif
diff --git a/crypto/src/crypto/digests/Blake2sDigest.cs b/crypto/src/crypto/digests/Blake2sDigest.cs
index 591095fbf2..91d73bf620 100644
--- a/crypto/src/crypto/digests/Blake2sDigest.cs
+++ b/crypto/src/crypto/digests/Blake2sDigest.cs
@@ -31,18 +31,22 @@ This implementation does not support the Tree Hashing Mode.
---------------+--------+-----------+------+------------+
*/
- /**
- * Implementation of the cryptographic hash function BLAKE2s.
- *
- * BLAKE2s offers a built-in keying mechanism to be used directly
- * for authentication ("Prefix-MAC") rather than a HMAC construction.
- *
- * BLAKE2s offers a built-in support for a salt for randomized hashing
- * and a personal string for defining a unique hash function for each application.
- *
- * BLAKE2s is optimized for 32-bit platforms and produces digests of any size
- * between 1 and 32 bytes.
- */
+ ///
+ /// Implementation of the cryptographic hash function BLAKE2s.
+ /// BLAKE2s is optimized for 32-bit platforms and produces digests of any size
+ /// between 1 and 32 bytes.
+ ///
+ ///
+ ///
+ ///
+ /// BLAKE2s offers a built-in keying mechanism to be used directly
+ /// for authentication ("Prefix-MAC") rather than a HMAC construction.
+ ///
+ ///
+ /// BLAKE2s is optimized for 32-bit platforms and produces digests of any size
+ /// between 1 and 32 bytes.
+ ///
+ ///
public sealed class Blake2sDigest
: IDigest
{
@@ -130,14 +134,18 @@ public sealed class Blake2sDigest
// For Tree Hashing Mode, not used here:
// private long f1 = 0L; // finalization flag, for last node: ~0L
- /**
- * BLAKE2s-256 for hashing.
- */
+ ///
+ /// Initializes a new instance of .
+ ///
public Blake2sDigest()
: this(256)
{
}
+ ///
+ /// Constructs a new instance of from another ./>.
+ ///
+ /// The original instance of that is copied.
public Blake2sDigest(Blake2sDigest digest)
{
this.bufferPos = digest.bufferPos;
@@ -160,11 +168,11 @@ public Blake2sDigest(Blake2sDigest digest)
this.innerHashLength = digest.innerHashLength;
}
- /**
- * BLAKE2s for hashing.
- *
- * @param digestBits the desired digest length in bits. Must be a multiple of 8 and less than 256.
- */
+ ///
+ /// Initializes a new instance of with a given digest size.
+ ///
+ /// Digest size in bits.
+ ///
public Blake2sDigest(int digestBits)
{
if (digestBits < 8 || digestBits > 256 || digestBits % 8 != 0)
@@ -175,33 +183,38 @@ public Blake2sDigest(int digestBits)
Init(null, null, null);
}
- /**
- * BLAKE2s for authentication ("Prefix-MAC mode").
- *
- * After calling the doFinal() method, the key will remain to be used for
- * further computations of this instance. The key can be overwritten using
- * the clearKey() method.
- *
- * @param key a key up to 32 bytes or null
- */
+ ///
+ ///
+ /// Initializes a new instance of with a key.
+ ///
+ ///
+ /// Blake2s for authentication ("Prefix-MAC mode").
+ /// After calling the method, the key will
+ /// remain to be used for further computations of this instance.
+ /// The key can be cleared using the method.
+ ///
+ /// A key up to 32 bytes or null.
+ ///
public Blake2sDigest(byte[] key)
{
Init(null, null, key);
}
- /**
- * BLAKE2s with key, required digest length, salt and personalization.
- *
- * After calling the doFinal() method, the key, the salt and the personal
- * string will remain and might be used for further computations with this
- * instance. The key can be overwritten using the clearKey() method, the
- * salt (pepper) can be overwritten using the clearSalt() method.
- *
- * @param key a key up to 32 bytes or null
- * @param digestBytes from 1 up to 32 bytes
- * @param salt 8 bytes or null
- * @param personalization 8 bytes or null
- */
+ ///
+ ///
+ /// Initializes a new instance of with a key, required digest length (in bytes), salt and personalization.
+ ///
+ ///
+ /// After calling the method, the key, the salt and the personalization
+ /// will remain and might be used for further computations with this instance.
+ /// The key can be overwritten using the method, the salt (pepper)
+ /// can be overwritten using the method.
+ ///
+ /// A key up to 32 bytes or null.
+ /// Digest length from 1 to 32 bytes.
+ /// A 8 bytes or nullable salt.
+ /// A 8 bytes or null personalization.
+ ///
public Blake2sDigest(byte[] key, int digestBytes, byte[] salt, byte[] personalization)
{
if (digestBytes < 1 || digestBytes > 32)
@@ -306,11 +319,7 @@ private void InitializeInternalState()
internalState[15] = blake2s_IV[7];// ^ f1 with f1 = 0
}
- /**
- * Update the message digest with a single byte.
- *
- * @param b the input byte to be entered.
- */
+ ///
public void Update(byte b)
{
// process the buffer if full else add to buffer:
@@ -338,13 +347,7 @@ public void Update(byte b)
}
}
- /**
- * Update the message digest with a block of bytes.
- *
- * @param message the byte array containing the data.
- * @param offset the offset into the byte array where the data starts.
- * @param len the length of the data.
- */
+ ///
public void BlockUpdate(byte[] message, int offset, int len)
{
if (message == null || len == 0)
@@ -404,6 +407,7 @@ public void BlockUpdate(byte[] message, int offset, int len)
}
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ ///
public void BlockUpdate(ReadOnlySpan input)
{
if (input.IsEmpty)
@@ -458,13 +462,14 @@ public void BlockUpdate(ReadOnlySpan input)
}
#endif
- /**
- * Close the digest, producing the final digest value. The doFinal() call
- * leaves the digest reset. Key, salt and personal string remain.
- *
- * @param out the array the digest is to be copied into.
- * @param outOffset the offset into the out array the digest is to start at.
- */
+ /// Close the digest, producing the final digest value.
+ ///
+ /// The call leaves the digest reset.
+ /// Key, salt and personal string remain.
+ ///
+ /// The byte array the digest is to be copied into.
+ /// The offset into the byte array the digest is to start at.
+ /// The number of bytes written.
public int DoFinal(byte[] output, int outOffset)
{
Check.OutputLength(output, outOffset, digestLength, "output buffer too short");
@@ -502,6 +507,13 @@ public int DoFinal(byte[] output, int outOffset)
}
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ /// Close the digest, producing the final digest value.
+ ///
+ /// The call leaves the digest reset.
+ /// Key, salt and personal string remain.
+ ///
+ /// The span the digest is to be copied into.
+ /// The number of bytes written.
public int DoFinal(Span output)
{
Check.OutputLength(output, digestLength, "output buffer too short");
@@ -535,10 +547,10 @@ public int DoFinal(Span output)
}
#endif
- /**
- * Reset the digest back to its initial state. The key, the salt and the
- * personal string will remain for further computations.
- */
+ ///
+ /// Reset the digest back to it's initial state.
+ /// The key, the salt and the personalization will remain for further computations.
+ ///
public void Reset()
{
bufferPos = 0;
@@ -559,6 +571,13 @@ public void Reset()
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
private void Compress(ReadOnlySpan message)
{
+#if NETCOREAPP3_0_OR_GREATER
+ if (Blake2s_X86.IsSupported)
+ {
+ Blake2s_X86.Compress(f0 == uint.MaxValue, chainValue, message, t0, t1, blake2s_IV);
+ return;
+ }
+#endif
InitializeInternalState();
Span m = stackalloc uint[16];
@@ -629,37 +648,28 @@ private void G(uint m1, uint m2, int posA, int posB, int posC, int posD)
internalState[posB] = Integers.RotateRight(internalState[posB] ^ internalState[posC], 7);
}
- /**
- * Return the algorithm name.
- *
- * @return the algorithm name
- */
+ ///
public string AlgorithmName => "BLAKE2s";
- /**
- * Return the size in bytes of the digest produced by this message digest.
- *
- * @return the size in bytes of the digest produced by this message digest.
- */
+ ///
public int GetDigestSize()
{
return digestLength;
}
- /**
- * Return the size in bytes of the internal buffer the digest applies its
- * compression function to.
- *
- * @return byte length of the digest's internal buffer.
- */
+ ///
+ /// Return the size in bytes of the internal buffer the digest applies it's compression
+ /// function to.
+ ///
+ /// The byte length of the digests internal buffer.
public int GetByteLength()
{
return BLOCK_LENGTH_BYTES;
}
- /**
- * Overwrite the key if it is no longer used (zeroization).
- */
+ ///
+ /// Clears the key.
+ ///
public void ClearKey()
{
if (key != null)
@@ -669,10 +679,9 @@ public void ClearKey()
}
}
- /**
- * Overwrite the salt (pepper) if it is secret and no longer used
- * (zeroization).
- */
+ ///
+ /// Clears the salt (pepper).
+ ///
public void ClearSalt()
{
if (salt != null)
diff --git a/crypto/src/crypto/digests/Blake2s_X86.cs b/crypto/src/crypto/digests/Blake2s_X86.cs
new file mode 100644
index 0000000000..06a24aabba
--- /dev/null
+++ b/crypto/src/crypto/digests/Blake2s_X86.cs
@@ -0,0 +1,384 @@
+#if NETCOREAPP3_0_OR_GREATER
+using System;
+using System.Diagnostics;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Runtime.Intrinsics;
+using System.Runtime.Intrinsics.X86;
+
+namespace Org.BouncyCastle.Crypto.Digests
+{
+ // License from the original code created by Clinton Ingram (saucecontrol) for Blake2Fast
+ // at https://github.com/saucecontrol/Blake2Fast. The code has been copied and modified.
+
+ // The MIT License
+
+ // Copyright(c) 2018-2021 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
+ // in the Software without restriction, including without limitation the rights
+ // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ // copies of the Software, and to permit persons to whom the Software is
+ // furnished to do so, subject to the following conditions:
+
+ // The above copyright notice and this permission notice shall be included in
+ // all copies or substantial portions of the Software.
+
+ // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ // THE SOFTWARE.
+
+ internal static class Blake2s_X86
+ {
+ public static bool IsSupported => Avx2.IsSupported && BitConverter.IsLittleEndian;
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void Compress(bool isFinal, Span hashBuffer, ReadOnlySpan message, uint totalSegmentsLow, uint totalSegmentsHigh, ReadOnlySpan blakeIV)
+ {
+ if (!IsSupported)
+ throw new PlatformNotSupportedException(nameof(Blake2s_X86));
+
+ Debug.Assert(message.Length >= Unsafe.SizeOf() * 8);
+ Debug.Assert(hashBuffer.Length >= 8);
+
+ var hashBytes = MemoryMarshal.AsBytes(hashBuffer);
+ var ivBytes = MemoryMarshal.AsBytes(blakeIV);
+
+ var r_14 = isFinal ? uint.MaxValue : 0;
+ var t_0 = Vector128.Create(totalSegmentsLow, totalSegmentsHigh, r_14, 0);
+
+ Vector128 row1 = LoadVector128(hashBytes);
+ Vector128 row2 = LoadVector128(hashBytes[Vector128.Count..]);
+ Vector128 row3 = LoadVector128(ivBytes);
+ Vector128 row4 = LoadVector128(ivBytes[Vector128.Count..]);
+ row4 = Sse2.Xor(row4, t_0);
+
+ Vector128 orig_1 = row1;
+ Vector128 orig_2 = row2;
+
+ Perform10Rounds(message, ref row1, ref row2, ref row3, ref row4);
+
+ row1 = Sse2.Xor(row1, row3);
+ row2 = Sse2.Xor(row2, row4);
+ row1 = Sse2.Xor(row1, orig_1);
+ row2 = Sse2.Xor(row2, orig_2);
+
+ Store(row1, hashBytes);
+ Store(row2, hashBytes[Vector128.Count..]);
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static void Perform10Rounds(ReadOnlySpan m, ref Vector128 row1, ref Vector128 row2, ref Vector128 row3, ref Vector128 row4)
+ {
+ Debug.Assert(m.Length >= Unsafe.SizeOf() * 16);
+
+ #region Rounds
+ var m0 = LoadVector128(m);
+ var m1 = LoadVector128(m[Vector128.Count..]);
+ var m2 = LoadVector128(m[(Vector128.Count * 2)..]);
+ var m3 = LoadVector128(m[(Vector128.Count * 3)..]);
+
+ //ROUND 1
+ var b1 = Sse.Shuffle(m0.AsSingle(), m1.AsSingle(), 0b_10_00_10_00).AsUInt32();
+
+ var b2 = Sse.Shuffle(m0.AsSingle(), m1.AsSingle(), 0b_11_01_11_01).AsUInt32();
+
+ var t0 = Sse2.Shuffle(m2, 0b_11_10_00_01);
+ var t1 = Sse2.Shuffle(m3, 0b_00_01_11_10);
+ var b3 = Sse41.Blend(t0.AsUInt16(), t1.AsUInt16(), 0b_11_00_00_11).AsUInt32();
+
+ t0 = Sse41.Blend(t0.AsUInt16(), t1.AsUInt16(), 0b_00_11_11_00).AsUInt32();
+ var b4 = Sse2.Shuffle(t0, 0b_10_11_00_01);
+
+ Round(ref row1, ref row2, ref row3, ref row4, b1, b2, b3, b4);
+
+ //ROUND 2
+ t0 = Sse41.Blend(m1.AsUInt16(), m2.AsUInt16(), 0b_00_00_11_00).AsUInt32();
+ t1 = Sse2.ShiftLeftLogical128BitLane(m3, 4);
+ var t2 = Sse41.Blend(t0.AsUInt16(), t1.AsUInt16(), 0b_11_11_00_00).AsUInt32();
+ b1 = Sse2.Shuffle(t2, 0b_10_01_00_11);
+
+ t0 = Sse2.Shuffle(m2, 0b_00_00_10_00);
+ t1 = Sse41.Blend(m1.AsUInt16(), m3.AsUInt16(), 0b_11_00_00_00).AsUInt32();
+ t2 = Sse41.Blend(t0.AsUInt16(), t1.AsUInt16(), 0b_11_11_00_00).AsUInt32();
+ b2 = Sse2.Shuffle(t2, 0b_10_11_00_01);
+
+ t0 = Sse2.ShiftLeftLogical128BitLane(m1, 4);
+ t1 = Sse41.Blend(m2.AsUInt16(), t0.AsUInt16(), 0b_00_11_00_00).AsUInt32();
+ t2 = Sse41.Blend(m0.AsUInt16(), t1.AsUInt16(), 0b_11_11_00_00).AsUInt32();
+ b3 = Sse2.Shuffle(t2, 0b_11_00_01_10);
+
+ t0 = Sse2.UnpackHigh(m0, m1);
+ t1 = Sse2.ShiftLeftLogical128BitLane(m3, 4);
+ t2 = Sse41.Blend(t0.AsUInt16(), t1.AsUInt16(), 0b_00_00_11_00).AsUInt32();
+ b4 = Sse2.Shuffle(t2, 0b_11_00_01_10);
+
+ Round(ref row1, ref row2, ref row3, ref row4, b1, b2, b3, b4);
+
+ //ROUND 3
+ t0 = Sse2.UnpackHigh(m2, m3);
+ t1 = Sse41.Blend(m3.AsUInt16(), m1.AsUInt16(), 0b_00_00_11_00).AsUInt32();
+ t2 = Sse41.Blend(t0.AsUInt16(), t1.AsUInt16(), 0b_00_00_11_11).AsUInt32();
+ b1 = Sse2.Shuffle(t2, 0b_11_01_00_10);
+
+ t0 = Sse2.UnpackLow(m2, m0);
+ t1 = Sse41.Blend(t0.AsUInt16(), m0.AsUInt16(), 0b_11_11_00_00).AsUInt32();
+ t2 = Sse2.ShiftLeftLogical128BitLane(m3, 8);
+ b2 = Sse41.Blend(t1.AsUInt16(), t2.AsUInt16(), 0b_11_00_00_00).AsUInt32();
+
+ t0 = Sse41.Blend(m0.AsUInt16(), m2.AsUInt16(), 0b_00_11_11_00).AsUInt32();
+ t1 = Sse2.ShiftRightLogical128BitLane(m1, 12);
+ t2 = Sse41.Blend(t0.AsUInt16(), t1.AsUInt16(), 0b_00_00_00_11).AsUInt32();
+ b3 = Sse2.Shuffle(t2, 0b_00_11_10_01);
+
+ t0 = Sse2.ShiftLeftLogical128BitLane(m3, 4);
+ t1 = Sse41.Blend(m0.AsUInt16(), m1.AsUInt16(), 0b_00_11_00_11).AsUInt32();
+ t2 = Sse41.Blend(t1.AsUInt16(), t0.AsUInt16(), 0b_11_00_00_00).AsUInt32();
+ b4 = Sse2.Shuffle(t2, 0b_01_10_11_00);
+
+ Round(ref row1, ref row2, ref row3, ref row4, b1, b2, b3, b4);
+
+ //ROUND 4
+ t0 = Sse2.UnpackHigh(m0, m1);
+ t1 = Sse2.UnpackHigh(t0, m2);
+ t2 = Sse41.Blend(t1.AsUInt16(), m3.AsUInt16(), 0b_00_00_11_00).AsUInt32();
+ b1 = Sse2.Shuffle(t2, 0b_11_01_00_10);
+
+ t0 = Sse2.ShiftLeftLogical128BitLane(m2, 8);
+ t1 = Sse41.Blend(m3.AsUInt16(), m0.AsUInt16(), 0b_00_00_11_00).AsUInt32();
+ t2 = Sse41.Blend(t1.AsUInt16(), t0.AsUInt16(), 0b_11_00_00_00).AsUInt32();
+ b2 = Sse2.Shuffle(t2, 0b_10_00_01_11);
+
+ t0 = Sse41.Blend(m0.AsUInt16(), m1.AsUInt16(), 0b_00_00_11_11).AsUInt32();
+ t1 = Sse41.Blend(t0.AsUInt16(), m3.AsUInt16(), 0b_11_00_00_00).AsUInt32();
+ b3 = Sse2.Shuffle(t1, 0b_00_01_10_11);
+
+ t0 = Ssse3.AlignRight(m0, m1, 4);
+ b4 = Sse41.Blend(t0.AsUInt16(), m2.AsUInt16(), 0b_00_11_00_11).AsUInt32();
+
+ Round(ref row1, ref row2, ref row3, ref row4, b1, b2, b3, b4);
+
+ //ROUND 5
+ t0 = Sse2.UnpackLow(m1.AsUInt64(), m2.AsUInt64()).AsUInt32();
+ t1 = Sse2.UnpackHigh(m0.AsUInt64(), m2.AsUInt64()).AsUInt32();
+ t2 = Sse41.Blend(t0.AsUInt16(), t1.AsUInt16(), 0b_00_11_00_11).AsUInt32();
+ b1 = Sse2.Shuffle(t2, 0b_10_00_01_11);
+
+ t0 = Sse2.UnpackHigh(m1.AsUInt64(), m3.AsUInt64()).AsUInt32();
+ t1 = Sse2.UnpackLow(m0.AsUInt64(), m1.AsUInt64()).AsUInt32();
+ b2 = Sse41.Blend(t0.AsUInt16(), t1.AsUInt16(), 0b_00_11_00_11).AsUInt32();
+
+ t0 = Sse2.UnpackHigh(m3.AsUInt64(), m1.AsUInt64()).AsUInt32();
+ t1 = Sse2.UnpackHigh(m2.AsUInt64(), m0.AsUInt64()).AsUInt32();
+ t2 = Sse41.Blend(t1.AsUInt16(), t0.AsUInt16(), 0b_00_11_00_11).AsUInt32();
+ b3 = Sse2.Shuffle(t2, 0b_10_01_00_11);
+
+ t0 = Sse41.Blend(m0.AsUInt16(), m2.AsUInt16(), 0b_00_00_00_11).AsUInt32();
+ t1 = Sse2.ShiftLeftLogical128BitLane(t0, 8);
+ t2 = Sse41.Blend(t1.AsUInt16(), m3.AsUInt16(), 0b_00_00_11_11).AsUInt32();
+ b4 = Sse2.Shuffle(t2, 0b_10_00_11_01);
+
+ Round(ref row1, ref row2, ref row3, ref row4, b1, b2, b3, b4);
+
+ //ROUND 6
+ t0 = Sse2.UnpackHigh(m0, m1);
+ t1 = Sse2.UnpackLow(m0, m2);
+ b1 = Sse2.UnpackLow(t0.AsUInt64(), t1.AsUInt64()).AsUInt32();
+
+ t0 = Sse2.ShiftRightLogical128BitLane(m2, 4);
+ t1 = Sse41.Blend(m0.AsUInt16(), m3.AsUInt16(), 0b_00_00_00_11).AsUInt32();
+ b2 = Sse41.Blend(t1.AsUInt16(), t0.AsUInt16(), 0b_00_11_11_00).AsUInt32();
+
+ t0 = Sse41.Blend(m1.AsUInt16(), m0.AsUInt16(), 0b_00_00_11_00).AsUInt32();
+ t1 = Sse2.ShiftRightLogical128BitLane(m3, 4);
+ t2 = Sse41.Blend(t0.AsUInt16(), t1.AsUInt16(), 0b_00_11_00_00).AsUInt32();
+ b3 = Sse2.Shuffle(t2, 0b_10_11_00_01);
+
+ t0 = Sse2.UnpackLow(m2.AsUInt64(), m1.AsUInt64()).AsUInt32();
+ t1 = Sse2.Shuffle(m3, 0b_10_00_01_00);
+ t2 = Sse2.ShiftRightLogical128BitLane(t0, 4);
+ b4 = Sse41.Blend(t1.AsUInt16(), t2.AsUInt16(), 0b_00_11_00_11).AsUInt32();
+
+ Round(ref row1, ref row2, ref row3, ref row4, b1, b2, b3, b4);
+
+ //ROUND 7
+ t0 = Sse2.ShiftLeftLogical128BitLane(m1, 12);
+ t1 = Sse41.Blend(m0.AsUInt16(), m3.AsUInt16(), 0b_00_11_00_11).AsUInt32();
+ b1 = Sse41.Blend(t1.AsUInt16(), t0.AsUInt16(), 0b_11_00_00_00).AsUInt32();
+
+ t0 = Sse41.Blend(m3.AsUInt16(), m2.AsUInt16(), 0b_00_11_00_00).AsUInt32();
+ t1 = Sse2.ShiftRightLogical128BitLane(m1, 4);
+ t2 = Sse41.Blend(t0.AsUInt16(), t1.AsUInt16(), 0b_00_00_00_11).AsUInt32();
+ b2 = Sse2.Shuffle(t2, 0b_10_01_11_00);
+
+ t0 = Sse2.UnpackLow(m0.AsUInt64(), m2.AsUInt64()).AsUInt32();
+ t1 = Sse2.ShiftRightLogical128BitLane(m1, 4);
+ t2 = Sse41.Blend(t0.AsUInt16(), t1.AsUInt16(), 0b_00_00_11_00).AsUInt32();
+ b3 = Sse2.Shuffle(t2, 0b_11_01_00_10);
+
+ t0 = Sse2.UnpackHigh(m1, m2);
+ t1 = Sse2.UnpackHigh(m0.AsUInt64(), t0.AsUInt64()).AsUInt32();
+ b4 = Sse2.Shuffle(t1, 0b_00_01_10_11);
+
+ Round(ref row1, ref row2, ref row3, ref row4, b1, b2, b3, b4);
+
+ //ROUND 8
+ t0 = Sse2.UnpackHigh(m0, m1);
+ t1 = Sse41.Blend(t0.AsUInt16(), m3.AsUInt16(), 0b_00_00_11_11).AsUInt32();
+ b1 = Sse2.Shuffle(t1, 0b_10_00_11_01);
+
+ t0 = Sse41.Blend(m2.AsUInt16(), m3.AsUInt16(), 0b_00_11_00_00).AsUInt32();
+ t1 = Sse2.ShiftRightLogical128BitLane(m0, 4);
+ t2 = Sse41.Blend(t0.AsUInt16(), t1.AsUInt16(), 0b_00_00_00_11).AsUInt32();
+ b2 = Sse2.Shuffle(t2, 0b_01_00_10_11);
+
+ t0 = Sse2.UnpackHigh(m0.AsUInt64(), m3.AsUInt64()).AsUInt32();
+ t1 = Sse2.UnpackLow(m1.AsUInt64(), m2.AsUInt64()).AsUInt32();
+ t2 = Sse41.Blend(t0.AsUInt16(), t1.AsUInt16(), 0b_00_11_11_00).AsUInt32();
+ b3 = Sse2.Shuffle(t2, 0b_10_11_01_00);
+
+ t0 = Sse2.UnpackLow(m0, m1);
+ t1 = Sse2.UnpackHigh(m1, m2);
+ t2 = Sse2.UnpackLow(t0.AsUInt64(), t1.AsUInt64()).AsUInt32();
+ b4 = Sse2.Shuffle(t2, 0b_10_01_00_11);
+
+ Round(ref row1, ref row2, ref row3, ref row4, b1, b2, b3, b4);
+
+ //ROUND 9
+ t0 = Sse2.UnpackHigh(m1, m3);
+ t1 = Sse2.UnpackLow(t0.AsUInt64(), m0.AsUInt64()).AsUInt32();
+ t2 = Sse41.Blend(t1.AsUInt16(), m2.AsUInt16(), 0b_11_00_00_00).AsUInt32();
+ b1 = Sse2.ShuffleHigh(t2.AsUInt16(), 0b_01_00_11_10).AsUInt32();
+
+ t0 = Sse2.UnpackHigh(m0, m3);
+ t1 = Sse41.Blend(m2.AsUInt16(), t0.AsUInt16(), 0b_11_11_00_00).AsUInt32();
+ b2 = Sse2.Shuffle(t1, 0b_00_10_01_11);
+
+ t0 = Sse2.UnpackLow(m0.AsUInt64(), m3.AsUInt64()).AsUInt32();
+ t1 = Sse2.ShiftRightLogical128BitLane(m2, 8);
+ t2 = Sse41.Blend(t0.AsUInt16(), t1.AsUInt16(), 0b_00_00_00_11).AsUInt32();
+ b3 = Sse2.Shuffle(t2, 0b_01_11_10_00);
+
+ t0 = Sse41.Blend(m1.AsUInt16(), m0.AsUInt16(), 0b_00_11_00_00).AsUInt32();
+ b4 = Sse2.Shuffle(t0, 0b_00_11_10_01);
+
+ Round(ref row1, ref row2, ref row3, ref row4, b1, b2, b3, b4);
+
+ //ROUND 10
+ t0 = Sse41.Blend(m0.AsUInt16(), m2.AsUInt16(), 0b_00_00_00_11).AsUInt32();
+ t1 = Sse41.Blend(m1.AsUInt16(), m2.AsUInt16(), 0b_00_11_00_00).AsUInt32();
+ t2 = Sse41.Blend(t1.AsUInt16(), t0.AsUInt16(), 0b_00_00_11_11).AsUInt32();
+ b1 = Sse2.Shuffle(t2, 0b_01_11_00_10);
+
+ t0 = Sse2.ShiftLeftLogical128BitLane(m0, 4);
+ t1 = Sse41.Blend(m1.AsUInt16(), t0.AsUInt16(), 0b_11_00_00_00).AsUInt32();
+ b2 = Sse2.Shuffle(t1, 0b_01_10_00_11);
+
+ t0 = Sse2.UnpackHigh(m0, m3);
+ t1 = Sse2.UnpackLow(m2, m3);
+ t2 = Sse2.UnpackHigh(t0.AsUInt64(), t1.AsUInt64()).AsUInt32();
+ b3 = Sse2.Shuffle(t2, 0b_00_10_01_11);
+
+ t0 = Sse41.Blend(m3.AsUInt16(), m2.AsUInt16(), 0b_11_00_00_00).AsUInt32();
+ t1 = Sse2.UnpackLow(m0, m3);
+ t2 = Sse41.Blend(t0.AsUInt16(), t1.AsUInt16(), 0b_00_00_11_11).AsUInt32();
+ b4 = Sse2.Shuffle(t2, 0b_01_10_11_00);
+
+ Round(ref row1, ref row2, ref row3, ref row4, b1, b2, b3, b4);
+ #endregion
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static void Round(ref Vector128 row1, ref Vector128 row2, ref Vector128 row3, ref Vector128 row4, Vector128 b1, Vector128 b2, Vector128 b3, Vector128 b4)
+ {
+ Vector128 r8 = Vector128.Create((byte)1, 2, 3, 0, 5, 6, 7, 4, 9, 10, 11, 8, 13, 14, 15, 12);
+ Vector128 r16 = Vector128.Create((byte)2, 3, 0, 1, 6, 7, 4, 5, 10, 11, 8, 9, 14, 15, 12, 13);
+
+ G1(r16, ref row1, ref row2, ref row3, ref row4, b1);
+ G2(r8, ref row1, ref row2, ref row3, ref row4, b2);
+
+ Diagonalize(ref row1, ref row3, ref row4);
+
+ G1(r16, ref row1, ref row2, ref row3, ref row4, b3);
+ G2(r8, ref row1, ref row2, ref row3, ref row4, b4);
+
+ Undiagonalize(ref row1, ref row3, ref row4);
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static void Diagonalize(ref Vector128 row1, ref Vector128 row3, ref Vector128 row4)
+ {
+ // +-------------------+ +-------------------+
+ // | 0 | 1 | 2 | 3 | | 3 | 0 | 1 | 2 |
+ // +-------------------+ +-------------------+
+ // | 8 | 9 | 10 | 11 | ---> | 9 | 10 | 11 | 8 |
+ // +-------------------+ +-------------------+
+ // | 12 | 13 | 14 | 15 | | 14 | 15 | 12 | 13 |
+ // +-------------------+ +-------------------+
+
+ row1 = Sse2.Shuffle(row1, 0b_10_01_00_11);
+ row3 = Sse2.Shuffle(row3, 0b_00_11_10_01);
+ row4 = Sse2.Shuffle(row4, 0b_01_00_11_10);
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static void G1(Vector128 r16, ref Vector128 row1, ref Vector128 row2, ref Vector128 row3, ref Vector128 row4, Vector128 b0)
+ {
+ row1 = Sse2.Add(Sse2.Add(row1, b0), row2);
+ row4 = Sse2.Xor(row4, row1);
+ row4 = Ssse3.Shuffle(row4.AsByte(), r16).AsUInt32();
+
+ row3 = Sse2.Add(row3, row4);
+ row2 = Sse2.Xor(row2, row3);
+ row2 = Sse2.Xor(Sse2.ShiftRightLogical(row2, 12), Sse2.ShiftLeftLogical(row2, 32 - 12));
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static void G2(Vector128 r8, ref Vector128 row1, ref Vector128 row2, ref Vector128 row3, ref Vector128 row4, Vector128 b0)
+ {
+ row1 = Sse2.Add(Sse2.Add(row1, b0), row2);
+ row4 = Sse2.Xor(row4, row1);
+ row4 = Ssse3.Shuffle(row4.AsByte(), r8).AsUInt32();
+
+ row3 = Sse2.Add(row3, row4);
+ row2 = Sse2.Xor(row2, row3);
+ row2 = Sse2.Xor(Sse2.ShiftRightLogical(row2, 7), Sse2.ShiftLeftLogical(row2, 32 - 7));
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static void Undiagonalize(ref Vector128 row1, ref Vector128 row3, ref Vector128 row4)
+ {
+ // +-------------------+ +-------------------+
+ // | 3 | 0 | 1 | 2 | | 0 | 1 | 2 | 3 |
+ // +-------------------+ +-------------------+
+ // | 9 | 10 | 11 | 8 | ---> | 8 | 9 | 10 | 11 |
+ // +-------------------+ +-------------------+
+ // | 14 | 15 | 12 | 13 | | 12 | 13 | 14 | 15 |
+ // +-------------------+ +-------------------+
+
+ row1 = Sse2.Shuffle(row1, 0b_00_11_10_01);
+ row3 = Sse2.Shuffle(row3, 0b_10_01_00_11);
+ row4 = Sse2.Shuffle(row4, 0b_01_00_11_10);
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static Vector128 LoadVector128(ReadOnlySpan source) where T : struct
+ {
+ Debug.Assert(source.Length >= Unsafe.SizeOf>());
+ return MemoryMarshal.Read>(source);
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static void Store(Vector128 vector, Span destination) where T : struct
+ {
+ Debug.Assert(destination.Length >= Unsafe.SizeOf>());
+ MemoryMarshal.Write(destination, ref vector);
+ }
+ }
+}
+#endif
diff --git a/crypto/src/crypto/digests/Blake2xsDigest.cs b/crypto/src/crypto/digests/Blake2xsDigest.cs
index 05323d14a0..c80bde78a9 100644
--- a/crypto/src/crypto/digests/Blake2xsDigest.cs
+++ b/crypto/src/crypto/digests/Blake2xsDigest.cs
@@ -12,19 +12,23 @@ The BLAKE2 cryptographic hash function was designed by Jean-
Reference Implementation and Description can be found at: https://blake2.net/blake2x.pdf
*/
- /**
- * Implementation of the eXtendable Output Function (XOF) BLAKE2xs.
- *
- * BLAKE2xs offers a built-in keying mechanism to be used directly
- * for authentication ("Prefix-MAC") rather than a HMAC construction.
- *
- * BLAKE2xs offers a built-in support for a salt for randomized hashing
- * and a personal string for defining a unique hash function for each application.
- *
- * BLAKE2xs is optimized for 32-bit platforms and produces digests of any size
- * between 1 and 2^16-2 bytes. The length can also be unknown and then the maximum
- * length will be 2^32 blocks of 32 bytes.
- */
+ ///
+ /// Implementation of the eXtendable Output Function (XOF) BLAKE2xs.
+ /// BLAKE2xs is optimized for 32-bit platforms and produces digests of any size
+ /// between 1 and 2^16-2 bytes. The length can also be unknown and then the maximum
+ /// length will be 2^32 blocks of 32 bytes.
+ ///
+ ///
+ ///
+ ///
+ /// BLAKE2xs offers a built-in keying mechanism to be used directly
+ /// for authentication ("Prefix-MAC") rather than a HMAC construction.
+ ///
+ ///
+ /// BLAKE2xs offers a built-in support for a salt for randomized hashing
+ /// and a personal string for defining a unique hash function for each application.
+ ///
+ ///
public sealed class Blake2xsDigest
: IXof
{
@@ -78,43 +82,48 @@ public sealed class Blake2xsDigest
*/
private long nodeOffset;
- /**
- * BLAKE2xs for hashing with unknown digest length
- */
+ ///
+ /// Initializes a new instance of for hashing an unknown digest length.
+ ///
public Blake2xsDigest()
: this(UnknownDigestLength)
{
}
- /**
- * BLAKE2xs for hashing
- *
- * @param digestBytes The desired digest length in bytes. Must be above 1 and less than 2^16-1
- */
+ ///
+ /// Initializes a new instance of with a given digest size.
+ ///
+ /// The desired digest length in bytes. Must be above 1 and less than 2^16-1.
public Blake2xsDigest(int digestBytes)
: this(digestBytes, null, null, null)
{
}
- /**
- * BLAKE2xs with key
- *
- * @param digestBytes The desired digest length in bytes. Must be above 1 and less than 2^16-1
- * @param key A key up to 32 bytes or null
- */
+ ///
+ ///
+ /// Initializes a new instance of with a key and given digest length.
+ ///
+ /// After calling the method, the key will
+ /// remain to be used for further computations of this instance.
+ ///
+ /// The desired digest length in bytes. Must be above 1 and less than 2^16-1.
+ /// A key up to 32 bytes or null.
public Blake2xsDigest(int digestBytes, byte[] key)
: this(digestBytes, key, null, null)
{
}
- /**
- * BLAKE2xs with key, salt and personalization
- *
- * @param digestBytes The desired digest length in bytes. Must be above 1 and less than 2^16-1
- * @param key A key up to 32 bytes or null
- * @param salt 8 bytes or null
- * @param personalization 8 bytes or null
- */
+
+ ///
+ ///
+ /// Initializes a new instance of with a key, required digest length (in bytes), salt and personalization.
+ ///
+ ///
+ /// The desired digest length in bytes. Must be above 1 and less than 2^16-1.
+ /// A key up to 32 bytes or null.
+ /// A 8 bytes or null salt.
+ /// A 8 bytes or null personalization.
+ ///
public Blake2xsDigest(int digestBytes, byte[] key, byte[] salt, byte[] personalization)
{
if (digestBytes < 1 || digestBytes > UnknownDigestLength)
@@ -125,6 +134,10 @@ public Blake2xsDigest(int digestBytes, byte[] key, byte[] salt, byte[] personali
hash = new Blake2sDigest(DigestLength, key, salt, personalization, nodeOffset);
}
+ ///
+ /// Constructs a new instance of from another ./>.
+ ///
+ /// The original instance of that is copied.
public Blake2xsDigest(Blake2xsDigest digest)
{
digestLength = digest.digestLength;
@@ -137,72 +150,53 @@ public Blake2xsDigest(Blake2xsDigest digest)
nodeOffset = digest.nodeOffset;
}
- /**
- * Return the algorithm name.
- *
- * @return the algorithm name
- */
+ ///
public string AlgorithmName => "BLAKE2xs";
- /**
- * Return the size in bytes of the digest produced by this message digest.
- *
- * @return the size in bytes of the digest produced by this message digest.
- */
+ ///
public int GetDigestSize() => digestLength;
- /**
- * Return the size in bytes of the internal buffer the digest applies its
- * compression function to.
- *
- * @return byte length of the digest's internal buffer.
- */
+ ///
+ /// Return the size in bytes of the internal buffer the digest applies it's compression
+ /// function to.
+ ///
+ /// The byte length of the digests internal buffer.
public int GetByteLength() => hash.GetByteLength();
- /**
- * Return the maximum size in bytes the digest can produce when the length
- * is unknown
- *
- * @return byte length of the largest digest with unknown length
- */
+ ///
+ /// Return the maximum size in bytes the digest can produce when the length
+ /// is unknown
+ ///
+ /// The byte length of the largest digest with unknown length
public long GetUnknownMaxLength()
{
return MaxNumberBlocks * DigestLength;
}
- /**
- * Update the message digest with a single byte.
- *
- * @param in the input byte to be entered.
- */
+ ///
public void Update(byte b)
{
hash.Update(b);
}
- /**
- * Update the message digest with a block of bytes.
- *
- * @param in the byte array containing the data.
- * @param inOff the offset into the byte array where the data starts.
- * @param len the length of the data.
- */
+ ///
public void BlockUpdate(byte[] input, int inOff, int inLen)
{
hash.BlockUpdate(input, inOff, inLen);
}
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ ///
public void BlockUpdate(ReadOnlySpan input)
{
hash.BlockUpdate(input);
}
#endif
- /**
- * Reset the digest back to its initial state. The key, the salt and the
- * personal string will remain for further computations.
- */
+ ///
+ /// Reset the digest back to it's initial state.
+ /// The key, the salt and the personalization will remain for further computations.
+ ///
public void Reset()
{
hash.Reset();
@@ -214,26 +208,28 @@ public void Reset()
nodeOffset = ComputeNodeOffset();
}
- /**
- * Close the digest, producing the final digest value. The doFinal() call
- * leaves the digest reset. Key, salt and personal string remain.
- *
- * @param out the array the digest is to be copied into.
- * @param outOffset the offset into the out array the digest is to start at.
- */
+ /// Close the digest, producing the final digest value.
+ ///
+ /// The call leaves the digest reset.
+ /// Key, salt and personal string remain.
+ ///
+ /// The byte array the digest is to be copied into.
+ /// The offset into the byte array the digest is to start at.
+ /// The number of bytes written.
public int DoFinal(byte[] output, int outOff)
{
return OutputFinal(output, outOff, digestLength);
}
- /**
- * Close the digest, producing the final digest value. The doFinal() call
- * leaves the digest reset. Key, salt, personal string remain.
- *
- * @param out output array to write the output bytes to.
- * @param outOff offset to start writing the bytes at.
- * @param outLen the number of output bytes requested.
- */
+ /// Close the digest, producing the final digest value.
+ ///
+ /// The call leaves the digest reset.
+ /// Key, salt and personal string remain.
+ ///
+ /// The output array to write the output bytes to.
+ /// The offset to start writing the bytes at.
+ /// The number of output bytes requested.
+ /// The number of bytes written.
public int OutputFinal(byte[] output, int outOff, int outLen)
{
int ret = Output(output, outOff, outLen);
@@ -243,15 +239,14 @@ public int OutputFinal(byte[] output, int outOff, int outLen)
return ret;
}
- /**
- * Start outputting the results of the final calculation for this digest. Unlike doFinal, this method
- * will continue producing output until the Xof is explicitly reset, or signals otherwise.
- *
- * @param out output array to write the output bytes to.
- * @param outOff offset to start writing the bytes at.
- * @param outLen the number of output bytes requested.
- * @return the number of bytes written
- */
+ ///
+ /// Start outputting the results of the final calculation for this digest. Unlike , this method
+ /// will continue producing output until the Xof is explicitly reset, or signals otherwise.
+ ///
+ /// The output array to write the output bytes to.
+ /// The offset to start writing the bytes at.
+ /// The number of output bytes requested.
+ /// The number of bytes written.
public int Output(byte[] output, int outOff, int outLen)
{
Check.OutputLength(output, outOff, outLen, "output buffer too short");
@@ -298,6 +293,13 @@ public int Output(byte[] output, int outOff, int outLen)
}
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ /// Close the digest, producing the final digest value.
+ ///
+ /// The call leaves the digest reset.
+ /// Key, salt and personal string remain.
+ ///
+ /// The output span to write the output bytes to.
+ /// The number of bytes written.
public int DoFinal(Span output)
{
Check.OutputLength(output, digestLength, "output buffer too short");
@@ -305,6 +307,13 @@ public int DoFinal(Span output)
return OutputFinal(output[..digestLength]);
}
+ /// Close the digest, producing the final digest value.
+ ///
+ /// The call leaves the digest reset.
+ /// Key, salt and personal string remain.
+ ///
+ /// The output span to write the output bytes to.
+ /// The number of bytes written.
public int OutputFinal(Span output)
{
int ret = Output(output);
@@ -314,6 +323,12 @@ public int OutputFinal(Span output)
return ret;
}
+ ///
+ /// Start outputting the results of the final calculation for this digest. Unlike , this method
+ /// will continue producing output until the Xof is explicitly reset, or signals otherwise.
+ ///
+ /// The output span to write the output bytes to.
+ /// The number of bytes written.
public int Output(Span output)
{
int outLen = output.Length;