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

PhotonBeetleDigest

public sealed class PhotonBeetleDigest : IDigest
using Org.BouncyCastle.Utilities; using System; using System.IO; namespace Org.BouncyCastle.Crypto.Digests { public sealed class PhotonBeetleDigest : IDigest { private byte[] state; private byte[][] state_2d; private MemoryStream buffer = new MemoryStream(); private const int INITIAL_RATE_INBYTES = 16; private int RATE_INBYTES = 4; private int SQUEEZE_RATE_INBYTES = 16; private int STATE_INBYTES = 32; private int TAG_INBYTES = 32; private int LAST_THREE_BITS_OFFSET = 5; private int ROUND = 12; private int D = 8; private int Dq = 3; private int Dr = 7; private int DSquare = 64; private int S = 4; private int S_1 = 3; private byte[][] RC = new byte[8][] { new byte[12] { 1, 3, 7, 14, 13, 11, 6, 12, 9, 2, 5, 10 }, new byte[12] { 0, 2, 6, 15, 12, 10, 7, 13, 8, 3, 4, 11 }, new byte[12] { 2, 0, 4, 13, 14, 8, 5, 15, 10, 1, 6, 9 }, new byte[12] { 6, 4, 0, 9, 10, 12, 1, 11, 14, 5, 2, 13 }, new byte[12] { 14, 12, 8, 1, 2, 4, 9, 3, 6, 13, 10, 5 }, new byte[12] { 15, 13, 9, 0, 3, 5, 8, 2, 7, 12, 11, 4 }, new byte[12] { 13, 15, 11, 2, 1, 7, 10, 0, 5, 14, 9, 6 }, new byte[12] { 9, 11, 15, 6, 5, 3, 14, 4, 1, 10, 13, 2 } }; private 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 byte[] sbox = new byte[16] { 12, 5, 6, 11, 9, 0, 10, 13, 3, 14, 15, 8, 4, 7, 1, 2 }; public string AlgorithmName => "Photon-Beetle Hash"; public PhotonBeetleDigest() { state = new byte[STATE_INBYTES]; state_2d = new byte[D][]; for (int i = 0; i < D; i++) { state_2d[i] = new byte[D]; } } public int GetDigestSize() { return TAG_INBYTES; } public int GetByteLength() { throw new NotImplementedException(); } public void Update(byte input) { buffer.WriteByte(input); } public void BlockUpdate(byte[] input, int inOff, int inLen) { Check.DataLength(input, inOff, inLen, "input buffer too short"); buffer.Write(input, inOff, inLen); } public int DoFinal(byte[] output, int outOff) { Check.OutputLength(output, outOff, 32, "output buffer too short"); byte[] array = buffer.GetBuffer(); int num = (int)buffer.Length; if (num == 0) state[STATE_INBYTES - 1] ^= (byte)(1 << LAST_THREE_BITS_OFFSET); else if (num <= 16) { Array.Copy(array, 0, state, 0, num); if (num < 16) state[num] ^= 1; state[STATE_INBYTES - 1] ^= (byte)(((num < 16) ? 1 : 2) << LAST_THREE_BITS_OFFSET); } else { Array.Copy(array, 0, state, 0, 16); num -= 16; int num2 = (num + RATE_INBYTES - 1) / RATE_INBYTES; int i; for (i = 0; i < num2 - 1; i++) { PHOTON_Permutation(); Bytes.XorTo(RATE_INBYTES, array, 16 + i * RATE_INBYTES, state, 0); } PHOTON_Permutation(); int num3 = num - i * RATE_INBYTES; Bytes.XorTo(num3, array, 16 + i * RATE_INBYTES, state, 0); if (num3 < RATE_INBYTES) state[num3] ^= 1; state[STATE_INBYTES - 1] ^= (byte)(((num % RATE_INBYTES == 0) ? 1 : 2) << LAST_THREE_BITS_OFFSET); } PHOTON_Permutation(); Array.Copy(state, 0, output, outOff, SQUEEZE_RATE_INBYTES); PHOTON_Permutation(); Array.Copy(state, 0, output, outOff + SQUEEZE_RATE_INBYTES, TAG_INBYTES - SQUEEZE_RATE_INBYTES); return TAG_INBYTES; } public void Reset() { buffer.SetLength(0); Arrays.Fill(state, 0); } private void PHOTON_Permutation() { for (int i = 0; i < DSquare; i++) { state_2d[i >> Dq][i & Dr] = (byte)(((state[i >> 1] & 255) >> 4 * (i & 1)) & 15); } for (int j = 0; j < ROUND; j++) { for (int i = 0; i < D; i++) { state_2d[i][0] ^= RC[i][j]; } for (int i = 0; i < D; i++) { for (int k = 0; k < D; k++) { state_2d[i][k] = sbox[state_2d[i][k]]; } } for (int i = 1; i < D; i++) { Array.Copy(state_2d[i], 0, state, 0, D); Array.Copy(state, i, state_2d[i], 0, D - i); Array.Copy(state, 0, state_2d[i], D - i, i); } for (int k = 0; k < D; k++) { for (int i = 0; i < D; i++) { byte b = 0; for (int l = 0; l < D; l++) { int num = MixColMatrix[i][l]; int num2 = 0; int num3 = state_2d[l][k]; for (int m = 0; m < S; m++) { if (((num3 >> m) & 1) != 0) num2 ^= num; if (((num >> S_1) & 1) != 0) { num <<= 1; num ^= 3; } else num <<= 1; } b = (byte)(b ^ (byte)(num2 & 15)); } state[i] = b; } for (int i = 0; i < D; i++) { state_2d[i][k] = state[i]; } } } for (int i = 0; i < DSquare; i += 2) { state[i >> 1] = (byte)((state_2d[i >> Dq][i & Dr] & 15) | ((state_2d[i >> Dq][(i + 1) & Dr] & 15) << 4)); } } } }