PhotonBeetleDigest
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));
}
}
}
}