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

KeccakHash minor opt #10

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
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
75 changes: 28 additions & 47 deletions src/Meadow.Core/Cryptography/KeccakHash.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ public class KeccakHash
#region Constants
public const int HASH_SIZE = 32;
private const int STATE_SIZE = 200;
private const int ROUND_SIZE = STATE_SIZE - 2 * HASH_SIZE;
private const int ROUND_SIZE_U64 = ROUND_SIZE / 8;
private const int HASH_DATA_AREA = 136;
private const int ROUNDS = 24;
private const int LANE_BITS = 8 * 8;
Expand Down Expand Up @@ -430,70 +432,49 @@ public static byte[] ComputeHashBytes(Span<byte> input, int size = HASH_SIZE)
return output;
}

static readonly ArrayPool<byte> _arrayPool = ArrayPool<byte>.Shared;


// compute a keccak hash (md) of given byte length from "in"
public static void ComputeHash(Span<byte> input, Span<byte> output)
{
if (output.Length <= 0 || output.Length > STATE_SIZE)
{
throw new ArgumentException("Bad keccak use");
}

Span<ulong> state = stackalloc ulong[STATE_SIZE / sizeof(ulong)];
Span<byte> temp = stackalloc byte[TEMP_BUFF_SIZE];

byte[] stateArray = _arrayPool.Rent(STATE_SIZE);
byte[] tempArray = _arrayPool.Rent(TEMP_BUFF_SIZE);

try
var remainingInputLength = input.Length;
int i;
for (; remainingInputLength >= ROUND_SIZE; remainingInputLength -= ROUND_SIZE, input = input.Slice(ROUND_SIZE))
{
Span<ulong> state = MemoryMarshal.Cast<byte, ulong>(stateArray.AsSpan(0, STATE_SIZE));
Span<byte> temp = tempArray.AsSpan(0, TEMP_BUFF_SIZE);

state.Clear();
temp.Clear();

int roundSize = STATE_SIZE == output.Length ? HASH_DATA_AREA : STATE_SIZE - (2 * output.Length);
int roundSizeU64 = roundSize / 8;

var inputLength = input.Length;
int i;
for (; inputLength >= roundSize; inputLength -= roundSize, input = input.Slice(roundSize))
var input64 = MemoryMarshal.Cast<byte, ulong>(input);

for (i = 0; i < ROUND_SIZE_U64; i++)
{
var input64 = MemoryMarshal.Cast<byte, ulong>(input);

for (i = 0; i < roundSizeU64; i++)
{
state[i] ^= input64[i];
}

KeccakF(state, ROUNDS);
state[i] ^= input64[i];
}

// last block and padding
if (inputLength >= TEMP_BUFF_SIZE || inputLength > roundSize || roundSize - inputLength + inputLength + 1 >= TEMP_BUFF_SIZE || roundSize == 0 || roundSize - 1 >= TEMP_BUFF_SIZE || roundSizeU64 * 8 > TEMP_BUFF_SIZE)
{
throw new ArgumentException("Bad keccak use");
}
KeccakF(state);
}

input.Slice(0, inputLength).CopyTo(temp);
temp[inputLength++] = 1;
temp[roundSize - 1] |= 0x80;
// last block and padding
if (input.Length >= TEMP_BUFF_SIZE || input.Length > ROUND_SIZE || ROUND_SIZE + 1 >= TEMP_BUFF_SIZE || ROUND_SIZE == 0 || ROUND_SIZE - 1 >= TEMP_BUFF_SIZE || ROUND_SIZE_U64 * 8 > TEMP_BUFF_SIZE)
{
throw new ArgumentException("Bad keccak use");
}

var tempU64 = MemoryMarshal.Cast<byte, ulong>(temp);
input.Slice(0, remainingInputLength).CopyTo(temp);
temp[remainingInputLength] = 1;
temp[ROUND_SIZE - 1] |= 0x80;

for (i = 0; i < roundSizeU64; i++)
{
state[i] ^= tempU64[i];
}
var tempU64 = MemoryMarshal.Cast<byte, ulong>(temp);

KeccakF(state, ROUNDS);
MemoryMarshal.AsBytes(state).Slice(0, output.Length).CopyTo(output);
}
finally
for (i = 0; i < ROUND_SIZE_U64; i++)
{
_arrayPool.Return(stateArray);
_arrayPool.Return(tempArray);
state[i] ^= tempU64[i];
}

KeccakF(state, ROUNDS);
MemoryMarshal.AsBytes(state.Slice(0, HASH_SIZE / sizeof(ulong))).CopyTo(output);
}

public static void Keccak1600(Span<byte> input, Span<byte> output)
Expand Down