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-ext-debug-jdk18on Show documentation
Show all versions of bcprov-ext-debug-jdk18on 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 Java 1.8 and later with debug enabled.
The newest version!
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));
}
}
}