<PackageReference Include="BouncyCastle.Cryptography" Version="2.5.0" />

PhotonBeetleDigest

public sealed class PhotonBeetleDigest : IDigest
using Org.BouncyCastle.Utilities; using System; namespace Org.BouncyCastle.Crypto.Digests { public sealed class PhotonBeetleDigest : IDigest { private const int INITIAL_RATE_INBYTES = 16; private const int RATE_INBYTES = 4; private const int SQUEEZE_RATE_INBYTES = 16; private const int STATE_INBYTES = 32; private const int TAG_INBYTES = 32; private const int LAST_THREE_BITS_OFFSET = 5; private const int ROUND = 12; private const int D = 8; private const int Dq = 3; private const int Dr = 7; private const int DSquare = 64; private const int S = 4; private const int S_1 = 3; private static readonly byte[] RC = new byte[96] { 1, 0, 2, 6, 14, 15, 13, 9, 3, 2, 0, 4, 12, 13, 15, 11, 7, 6, 4, 0, 8, 9, 11, 15, 14, 15, 13, 9, 1, 0, 2, 6, 13, 12, 14, 10, 2, 3, 1, 5, 11, 10, 8, 12, 4, 5, 7, 3, 6, 7, 5, 1, 9, 8, 10, 14, 12, 13, 15, 11, 3, 2, 0, 4, 9, 8, 10, 14, 6, 7, 5, 1, 2, 3, 1, 5, 13, 12, 14, 10, 5, 4, 6, 2, 10, 11, 9, 13, 10, 11, 9, 13, 5, 4, 6, 2 }; private static readonly byte[][] MixColMatrix = new byte[8][] { new byte[8] { 2, 4, 2, 11, 2, 8, 5, 6 }, new byte[8] { 12, 9, 8, 13, 7, 7, 5, 2 }, new byte[8] { 4, 4, 13, 13, 9, 4, 13, 9 }, new byte[8] { 1, 6, 5, 1, 12, 13, 15, 14 }, new byte[8] { 15, 12, 9, 13, 14, 5, 14, 13 }, new byte[8] { 9, 14, 5, 15, 4, 12, 9, 6 }, new byte[8] { 12, 2, 2, 10, 3, 1, 1, 14 }, new byte[8] { 15, 1, 13, 10, 5, 10, 2, 3 } }; private static readonly byte[] sbox = new byte[16] { 12, 5, 6, 11, 9, 0, 10, 13, 3, 14, 15, 8, 4, 7, 1, 2 }; private readonly byte[] state; private readonly byte[][] state_2d; private readonly byte[] m_buf = new byte[16]; private int m_bufPos; private int m_phase; public string AlgorithmName => "Photon-Beetle Hash"; public PhotonBeetleDigest() { state = new byte[32]; state_2d = new byte[8][]; for (int i = 0; i < 8; i++) { state_2d[i] = new byte[8]; } } public int GetDigestSize() { return 32; } public int GetByteLength() { throw new NotImplementedException(); } public void Update(byte input) { m_buf[m_bufPos] = input; if (++m_bufPos == 16) { ProcessBuffer(m_buf); m_bufPos = 0; } } public void BlockUpdate(byte[] input, int inOff, int inLen) { Check.DataLength(input, inOff, inLen, "input buffer too short"); BlockUpdate(input.AsSpan(inOff, inLen)); } public void BlockUpdate(ReadOnlySpan<byte> input) { int num = 16 - m_bufPos; if (input.Length < num) { input.CopyTo(m_buf.AsSpan(m_bufPos)); m_bufPos += input.Length; } else { if (m_bufPos > 0) { input.Slice(0, num).CopyTo(m_buf.AsSpan(m_bufPos)); ProcessBuffer(m_buf); int num2 = num; input = input.Slice(num2, input.Length - num2); } while (input.Length >= 16) { ProcessBuffer(input); input = input.Slice(16, input.Length - 16); } input.CopyTo(m_buf); m_bufPos = input.Length; } } public int DoFinal(byte[] output, int outOff) { return DoFinal(output.AsSpan(outOff)); } public int DoFinal(Span<byte> output) { Check.OutputLength(output, 32, "output buffer too short"); FinishAbsorbing(); PHOTON_Permutation(); Span<byte> span = state.AsSpan(0, 16); span.CopyTo(output); PHOTON_Permutation(); span = state.AsSpan(0, 16); span.CopyTo(output.Slice(16, output.Length - 16)); Reset(); return 32; } public void Reset() { Arrays.Fill(state, 0); Arrays.Fill(m_buf, 0); m_bufPos = 0; m_phase = 0; } private void FinishAbsorbing() { if (m_phase == 0) { if (m_bufPos != 0) { Array.Copy(m_buf, 0, state, 0, m_bufPos); state[m_bufPos] ^= 1; } state[31] ^= 32; } else if (m_phase == 1 && m_bufPos == 0) { state[31] ^= 64; } else { int i = 0; for (int num = m_bufPos - 4; i <= num; i += 4) { PHOTON_Permutation(); Bytes.XorTo(4, m_buf, i, state, 0); } int num2 = m_bufPos - i; if (num2 != 0) { PHOTON_Permutation(); Bytes.XorTo(num2, m_buf, i, state, 0); state[num2] ^= 1; state[31] ^= 64; } else state[31] ^= 32; } } private void ProcessBuffer(ReadOnlySpan<byte> buf) { if (m_phase == 0) { buf.Slice(0, 16).CopyTo(state); m_phase = 1; } else { PHOTON_Permutation(); Bytes.XorTo(4, buf, state); PHOTON_Permutation(); Bytes.XorTo(4, buf.Slice(4, buf.Length - 4), state); PHOTON_Permutation(); Bytes.XorTo(4, buf.Slice(8, buf.Length - 8), state); PHOTON_Permutation(); Bytes.XorTo(4, buf.Slice(12, buf.Length - 12), state); m_phase = 2; } } private void PHOTON_Permutation() { for (int i = 0; i < 64; i++) { state_2d[i >> 3][i & 7] = (byte)(((state[i >> 1] & 255) >> 4 * (i & 1)) & 15); } for (int j = 0; j < 12; j++) { int num = j * 8; for (int i = 0; i < 8; i++) { state_2d[i][0] ^= RC[num++]; } for (int i = 0; i < 8; i++) { for (int k = 0; k < 8; k++) { state_2d[i][k] = sbox[state_2d[i][k]]; } } for (int i = 1; i < 8; i++) { Array.Copy(state_2d[i], 0, state, 0, 8); Array.Copy(state, i, state_2d[i], 0, 8 - i); Array.Copy(state, 0, state_2d[i], 8 - i, i); } for (int k = 0; k < 8; k++) { for (int i = 0; i < 8; i++) { int num3 = 0; for (int l = 0; l < 8; l++) { int num4 = MixColMatrix[i][l]; int num5 = state_2d[l][k]; num3 ^= num4 * (num5 & 1); num3 ^= num4 * (num5 & 2); num3 ^= num4 * (num5 & 4); num3 ^= num4 * (num5 & 8); } int num6 = num3 >> 4; num3 = ((num3 & 15) ^ num6 ^ (num6 << 1)); int num7 = num3 >> 4; num3 = ((num3 & 15) ^ num7 ^ (num7 << 1)); state[i] = (byte)num3; } for (int i = 0; i < 8; i++) { state_2d[i][k] = state[i]; } } } for (int i = 0; i < 64; i += 2) { state[i >> 1] = (byte)((state_2d[i >> 3][i & 7] & 15) | ((state_2d[i >> 3][(i + 1) & 7] & 15) << 4)); } } } }