Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Blake2b intrinsics POC #398

Draft
wants to merge 18 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 12 additions & 12 deletions crypto/src/crypto/IDigest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,41 +9,41 @@ public interface IDigest
string AlgorithmName { get; }

/// <summary>Return the size, in bytes, of the digest produced by this message digest.</summary>
/// <returns>the size, in bytes, of the digest produced by this message digest.</returns>
/// <returns>The size, in bytes, of the digest produced by this message digest.</returns>
int GetDigestSize();

/// <summary>Return the size, in bytes, of the internal buffer used by this digest.</summary>
/// <returns>the size, in bytes, of the internal buffer used by this digest.</returns>
/// <returns>The size, in bytes, of the internal buffer used by this digest.</returns>
int GetByteLength();

/// <summary>Update the message digest with a single byte.</summary>
/// <param name="input">the input byte to be entered.</param>
/// <param name="input">The input byte to be entered.</param>
void Update(byte input);

/// <summary>Update the message digest with a block of bytes.</summary>
/// <param name="input">the byte array containing the data.</param>
/// <param name="inOff">the offset into the byte array where the data starts.</param>
/// <param name="inLen">the length of the data.</param>
/// <param name="input">The byte array containing the data.</param>
/// <param name="inOff">The offset into the byte array where the data starts.</param>
/// <param name="inLen">The length of the data.</param>
void BlockUpdate(byte[] input, int inOff, int inLen);

#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
/// <summary>Update the message digest with a span of bytes.</summary>
/// <param name="input">the span containing the data.</param>
/// <param name="input">The span containing the data.</param>
void BlockUpdate(ReadOnlySpan<byte> input);
#endif

/// <summary>Close the digest, producing the final digest value.</summary>
/// <remarks>This call leaves the digest reset.</remarks>
/// <param name="output">the byte array the digest is to be copied into.</param>
/// <param name="outOff">the offset into the byte array the digest is to start at.</param>
/// <returns>the number of bytes written</returns>
/// <param name="output">The byte array the digest is to be copied into.</param>
/// <param name="outOff">The offset into the byte array the digest is to start at.</param>
/// <returns>The number of bytes written.</returns>
int DoFinal(byte[] output, int outOff);

#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
/// <summary>Close the digest, producing the final digest value.</summary>
/// <remarks>This call leaves the digest reset.</remarks>
/// <param name="output">the span the digest is to be copied into.</param>
/// <returns>the number of bytes written</returns>
/// <param name="output">The span the digest is to be copied into.</param>
/// <returns>The number of bytes written.</returns>
int DoFinal(Span<byte> output);
#endif

Expand Down
186 changes: 98 additions & 88 deletions crypto/src/crypto/digests/Blake2bDigest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,18 +30,22 @@ This implementation does not support the Tree Hashing Mode.
---------------+--------+-----------+------+------------+
*/

/**
* Implementation of the cryptographic hash function Blake2b.
* <p/>
* Blake2b offers a built-in keying mechanism to be used directly
* for authentication ("Prefix-MAC") rather than a HMAC construction.
* <p/>
* 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.
* <p/>
* BLAKE2b is optimized for 64-bit platforms and produces digests of any size
* between 1 and 64 bytes.
*/
/// <summary>
/// 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.
/// </summary>
///
/// <remarks>
/// <para>
/// Blake2b offers a built-in keying mechanism to be used directly
/// for authentication ("Prefix-MAC") rather than a HMAC construction.
/// </para>
/// <para>
/// 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.
/// </para>
/// </remarks>
public sealed class Blake2bDigest
: IDigest
{
Expand Down Expand Up @@ -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;
Expand All @@ -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

/// <summary>
/// Initializes a new instance of <see cref="Blake2bDigest"/>.
/// </summary>
public Blake2bDigest()
: this(512)
{
}

/// <summary>
/// Constructs a new instance of <see cref="Blake2bDigest"/> from another <see cref="Blake2bDigest"/>./>.
/// </summary>
/// <param name="digest">The original instance of <see cref="Blake2bDigest"/> that is copied.</param>
public Blake2bDigest(Blake2bDigest digest)
{
this.bufferPos = digest.bufferPos;
Expand All @@ -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
*/
/// <summary>
/// Initializes a new instance of <see cref="Blake2bDigest"/> with a given digest size.
/// </summary>
/// <param name="digestSize">Digest size in bits.</param>
/// <exception cref="ArgumentException"></exception>
public Blake2bDigest(int digestSize)
{
if (digestSize < 8 || digestSize > 512 || digestSize % 8 != 0)
Expand All @@ -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
*/
/// <summary>
/// <para>
/// Initializes a new instance of <see cref="Blake2bDigest"/> with a key.
/// </para>
///
/// Blake2b for authentication ("Prefix-MAC mode").
/// After calling the <see cref="DoFinal(byte[], int)"/> method, the key will
/// remain to be used for further computations of this instance.
/// The key can be cleared using the <see cref="ClearKey"/> method.
/// </summary>
/// <param name="key">A key up to 64 bytes or null.</param>
/// <exception cref="ArgumentException"></exception>
public Blake2bDigest(byte[] key)
{
buffer = new byte[BLOCK_LENGTH_BYTES];
Expand All @@ -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
*/
/// <summary>
/// <para>
/// Initializes a new instance of <see cref="Blake2bDigest"/> with a key, required digest length (in bytes), salt and personalization.
/// </para>
///
/// After calling the <see cref="DoFinal(byte[], int)"/> 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 <see cref="ClearKey"/> method, the salt (pepper)
/// can be overwritten using the <see cref="ClearSalt"/> method.
/// </summary>
/// <param name="key">A key up to 64 bytes or null.</param>
/// <param name="digestLength">Digest length from 1 to 64 bytes.</param>
/// <param name="salt">A 16 bytes or nullable salt.</param>
/// <param name="personalization">A 16 bytes or null personalization.</param>
/// <exception cref="ArgumentException"></exception>
public Blake2bDigest(byte[] key, int digestLength, byte[] salt, byte[] personalization)
{
if (digestLength < 1 || digestLength > 64)
Expand Down Expand Up @@ -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.
*/
/// <inheritdoc />
public void Update(byte b)
{
// process the buffer if full else add to buffer:
Expand Down Expand Up @@ -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.
*/
/// <inheritdoc />
public void BlockUpdate(byte[] message, int offset, int len)
{
if (message == null || len == 0)
Expand Down Expand Up @@ -369,6 +376,7 @@ public void BlockUpdate(byte[] message, int offset, int len)
}

#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
/// <inheritdoc />
public void BlockUpdate(ReadOnlySpan<byte> input)
{
if (input.IsEmpty)
Expand Down Expand Up @@ -421,14 +429,14 @@ public void BlockUpdate(ReadOnlySpan<byte> 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.
*/
/// <summary>Close the digest, producing the final digest value.</summary>
/// <remarks>
/// The <see cref="DoFinal(byte[], int)"/> call leaves the digest reset.
/// Key, salt and personal string remain.
/// </remarks>
/// <param name="output">The byte array the digest is to be copied into.</param>
/// <param name="outOffset">The offset into the byte array the digest is to start at.</param>
/// <returns>The number of bytes written.</returns>
public int DoFinal(byte[] output, int outOffset)
{
Check.OutputLength(output, outOffset, digestLength, "output buffer too short");
Expand Down Expand Up @@ -464,6 +472,13 @@ public int DoFinal(byte[] output, int outOffset)
}

#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
/// <summary>Close the digest, producing the final digest value.</summary>
/// <remarks>
/// The <see cref="DoFinal(Span{byte})"/> call leaves the digest reset.
/// Key, salt and personal string remain.
/// </remarks>
/// <param name="output">The span the digest is to be copied into.</param>
/// <returns>The number of bytes written.</returns>
public int DoFinal(Span<byte> output)
{
Check.OutputLength(output, digestLength, "output buffer too short");
Expand Down Expand Up @@ -495,11 +510,10 @@ public int DoFinal(Span<byte> output)
}
#endif

/**
* Reset the digest back to it's initial state.
* The key, the salt and the personal string will
* remain for further computations.
*/
/// <summary>
/// Reset the digest back to it's initial state.
/// The key, the salt and the personalization will remain for further computations.
/// </summary>
public void Reset()
{
bufferPos = 0;
Expand All @@ -519,6 +533,13 @@ public void Reset()
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
private void Compress(ReadOnlySpan<byte> 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<ulong> m = stackalloc ulong[16];
Expand Down Expand Up @@ -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
*/
/// <inheritdoc />
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.
*/
/// <inheritdoc />
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.
*/
/// <summary>
/// Return the size in bytes of the internal buffer the digest applies it's compression
/// function to.
/// </summary>
/// <returns>The byte length of the digests internal buffer.</returns>
public int GetByteLength()
{
return BLOCK_LENGTH_BYTES;
}

/**
* Overwrite the key
* if it is no longer used (zeroization)
*/
/// <summary>
/// Clears the key.
/// </summary>
public void ClearKey()
{
if (key != null)
Expand All @@ -635,10 +646,9 @@ public void ClearKey()
}
}

/**
* Overwrite the salt (pepper) if it
* is secret and no longer used (zeroization)
*/
/// <summary>
/// Clears the salt (pepper).
/// </summary>
public void ClearSalt()
{
if (salt != null)
Expand Down
Loading