org.bouncycastle.crypto.digests.PhotonBeetleDigest Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of bcprov-jdk15to18 Show documentation
Show all versions of bcprov-jdk15to18 Show documentation
The Bouncy Castle Crypto package is a Java implementation of cryptographic algorithms. This jar contains JCE provider and lightweight API for the Bouncy Castle Cryptography APIs for JDK 1.5 to JDK 1.8.
package org.bouncycastle.crypto.digests;
import java.io.ByteArrayOutputStream;
import org.bouncycastle.crypto.DataLengthException;
import org.bouncycastle.crypto.Digest;
import org.bouncycastle.crypto.OutputLengthException;
import org.bouncycastle.util.Arrays;
import org.bouncycastle.util.Bytes;
/**
* Photon-Beetle, https://www.isical.ac.in/~lightweight/beetle/
* https://csrc.nist.gov/CSRC/media/Projects/lightweight-cryptography/documents/finalist-round/updated-spec-doc/photon-beetle-spec-final.pdf
*
* Photon-Beetle with reference to C Reference Impl from: https://github.com/PHOTON-Beetle/Software
*
*/
public class PhotonBeetleDigest
implements Digest
{
private byte[] state;
private byte[][] state_2d;
private ByteArrayOutputStream buffer = new ByteArrayOutputStream();
private final 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 = {//[D][12]
{1, 3, 7, 14, 13, 11, 6, 12, 9, 2, 5, 10},
{0, 2, 6, 15, 12, 10, 7, 13, 8, 3, 4, 11},
{2, 0, 4, 13, 14, 8, 5, 15, 10, 1, 6, 9},
{6, 4, 0, 9, 10, 12, 1, 11, 14, 5, 2, 13},
{14, 12, 8, 1, 2, 4, 9, 3, 6, 13, 10, 5},
{15, 13, 9, 0, 3, 5, 8, 2, 7, 12, 11, 4},
{13, 15, 11, 2, 1, 7, 10, 0, 5, 14, 9, 6},
{9, 11, 15, 6, 5, 3, 14, 4, 1, 10, 13, 2}
};
private byte[][] MixColMatrix = { //[D][D]
{2, 4, 2, 11, 2, 8, 5, 6},
{12, 9, 8, 13, 7, 7, 5, 2},
{4, 4, 13, 13, 9, 4, 13, 9},
{1, 6, 5, 1, 12, 13, 15, 14},
{15, 12, 9, 13, 14, 5, 14, 13},
{9, 14, 5, 15, 4, 12, 9, 6},
{12, 2, 2, 10, 3, 1, 1, 14},
{15, 1, 13, 10, 5, 10, 2, 3}
};
private byte[] sbox = {12, 5, 6, 11, 9, 0, 10, 13, 3, 14, 15, 8, 4, 7, 1, 2};
public PhotonBeetleDigest()
{
state = new byte[STATE_INBYTES];
state_2d = new byte[D][D];
}
@Override
public String getAlgorithmName()
{
return "Photon-Beetle Hash";
}
@Override
public int getDigestSize()
{
return TAG_INBYTES;
}
@Override
public void update(byte input)
{
buffer.write(input);
}
@Override
public void update(byte[] input, int inOff, int len)
{
if ((inOff + len) > input.length)
{
throw new DataLengthException("input buffer too short");
}
buffer.write(input, inOff, len);
}
@Override
public int doFinal(byte[] output, int outOff)
{
if (32 + outOff > output.length)
{
throw new OutputLengthException("output buffer is too short");
}
byte[] input = buffer.toByteArray();
int inlen = input.length;
if (inlen == 0)
{
state[STATE_INBYTES - 1] ^= 1 << LAST_THREE_BITS_OFFSET;
}
else if (inlen <= INITIAL_RATE_INBYTES)
{
System.arraycopy(input, 0, state, 0, inlen);
if (inlen < INITIAL_RATE_INBYTES)
{
state[inlen] ^= 0x01; // ozs
}
state[STATE_INBYTES - 1] ^= (inlen < INITIAL_RATE_INBYTES ? (byte)1 : (byte)2) << LAST_THREE_BITS_OFFSET;
}
else
{
System.arraycopy(input, 0, state, 0, INITIAL_RATE_INBYTES);
inlen -= INITIAL_RATE_INBYTES;
int Dlen_inblocks = (inlen + RATE_INBYTES - 1) / RATE_INBYTES;
int i, LastDBlocklen;
for (i = 0; i < Dlen_inblocks - 1; i++)
{
PHOTON_Permutation();
Bytes.xorTo(RATE_INBYTES, input, INITIAL_RATE_INBYTES + i * RATE_INBYTES, state, 0);
}
PHOTON_Permutation();
LastDBlocklen = inlen - i * RATE_INBYTES;
Bytes.xorTo(LastDBlocklen, input, INITIAL_RATE_INBYTES + i * RATE_INBYTES, state, 0);
if (LastDBlocklen < RATE_INBYTES)
{
state[LastDBlocklen] ^= 0x01; // ozs
}
state[STATE_INBYTES - 1] ^= (inlen % RATE_INBYTES == 0 ? (byte)1 : (byte)2) << LAST_THREE_BITS_OFFSET;
}
PHOTON_Permutation();
System.arraycopy(state, 0, output, outOff, SQUEEZE_RATE_INBYTES);
PHOTON_Permutation();
System.arraycopy(state, 0, output, outOff + SQUEEZE_RATE_INBYTES, TAG_INBYTES - SQUEEZE_RATE_INBYTES);
return TAG_INBYTES;
}
@Override
public void reset()
{
buffer.reset();
Arrays.fill(state, (byte)0);
}
void PHOTON_Permutation()
{
int i, j, k, l;
for (i = 0; i < DSquare; i++)
{
state_2d[i >>> Dq][i & Dr] = (byte)(((state[i >> 1] & 0xFF) >>> (4 * (i & 1))) & 0xf);
}
for (int round = 0; round < ROUND; round++)
{
//AddKey
for (i = 0; i < D; i++)
{
state_2d[i][0] ^= RC[i][round];
}
//SubCell
for (i = 0; i < D; i++)
{
for (j = 0; j < D; j++)
{
state_2d[i][j] = sbox[state_2d[i][j]];
}
}
//ShiftRow
for (i = 1; i < D; i++)
{
System.arraycopy(state_2d[i], 0, state, 0, D);
System.arraycopy(state, i, state_2d[i], 0, D - i);
System.arraycopy(state, 0, state_2d[i], D - i, i);
}
//MixColumn
for (j = 0; j < D; j++)
{
for (i = 0; i < D; i++)
{
byte sum = 0;
for (k = 0; k < D; k++)
{
int x = MixColMatrix[i][k], ret = 0, b = state_2d[k][j];
for (l = 0; l < S; l++)
{
if (((b >>> l) & 1) != 0)
{
ret ^= x;
}
if (((x >>> S_1) & 1) != 0)
{
x <<= 1;
x ^= 0x3;
}
else
{
x <<= 1;
}
}
sum ^= ret & 15;
}
state[i] = sum;
}
for (i = 0; i < D; i++)
{
state_2d[i][j] = state[i];
}
}
}
for (i = 0; i < DSquare; i += 2)
{
state[i >>> 1] = (byte)(((state_2d[i >>> Dq][i & Dr] & 0xf)) | ((state_2d[i >>> Dq][(i + 1) & Dr] & 0xf) << 4));
}
}
}