package im.actor.runtime.crypto.primitives.streebog;
// Disabling Bounds checks for speeding up calculations
/*-[
#define J2OBJC_DISABLE_ALL_CHECKS 1
]-*/
public class StreebogDigest {
private final int hashLength;
private Int512 h = new Int512();
private Int512 m = new Int512();
private Int512 e = new Int512();
private int pt;
private long n;
public StreebogDigest(int hashLength) {
this.hashLength = hashLength;
reset();
}
public void reset() {
// IV:: 01010.. for 256-bit hash, 0000... for 512-bit hash
// memset(&sbx->h, hlen == 32 ? 0x01 : 0x00, 64);
// memset(&sbx->e, 0x00, 64);
for (int i = 0; i < 64; i++) {
if (hashLength == 32) {
h.setByte(i, (byte) 0x01);
} else {
h.setByte(i, (byte) 0x00);
}
e.setByte(i, (byte) 0x00);
}
// sbx->pt = 63;
// sbx->n = 0;
pt = 63;
n = 0;
}
public void update(byte[] in, int offset, int length) {
// j = sbx->pt;
int j = pt;
for (int i = 0; i < length; i++) {
m.setByte(j--, (byte) (in[offset + i] & 0xFF));
// compress
// if (j < 0) {
if (j < 0) {
// streebog_g(&sbx->h, &sbx->m, sbx->n);
StreebogMath.streebog_g(h, m, n);
// sbx->n += 0x200;
n += 0x200;
// epsilon summation
// c = 0;
int c = 0;
// for (j = 63; j >= 0; j--) {
for (j = 63; j >= 0; j--) {
// c += sbx->e.b[j] + sbx->m.b[j];
c += (e.getByte(j) & 0xFF) + (m.getByte(j) & 0xFF);
// sbx->e.b[j] = c & 0xFF;
e.setByte(j, (byte) (c & 0xFF));
// c >>= 8;
c >>= 8;
}
// j = 63;
j = 63;
}
}
// sbx->pt = j;
pt = j;
}
public void doFinal(byte[] out, int offset) {
// pad the message and run final g
// i = sbx->pt;
int i = pt;
// sbx->m.b[i--] = 0x01;
m.setByte(i--, (byte) 0x01);
while (i >= 0) {
// sbx->m.b[i--] = 0x00;
m.setByte(i--, (byte) 0x00);
}
// streebog_g(&sbx->h, &sbx->m, sbx->n);
StreebogMath.streebog_g(h, m, n);
// epsilon summation
int c = 0;
for (i = 63; i >= 0; i--) {
// c += sbx->e.b[i] + sbx->m.b[i];
c += (e.getByte(i) & 0xFF) + (m.getByte(i) & 0xFF);
// sbx->e.b[i] = c & 0xFF;
e.setByte(i, (byte) (c & 0xFF));
// c >>= 8;
c = c >> 8;
}
// finalization n
// memset(&sbx->m, 0x00, 64);
for (int j = 0; j < 64; j++) {
m.setByte(j, (byte) 0x00);
}
// sbx->n += (63 - sbx->pt) << 3; // total bits
n += (63 - pt) << 3;
for (i = 63; n > 0; i--) {
// sbx->m.b[i] = sbx->n & 0xFF;
m.setByte(i, (byte) (n & 0xFF));
// sbx->n >>= 8;
n = n >> 8;
}
// streebog_g(&sbx->h, &sbx->m, 0);
// streebog_g(&sbx->h, &sbx->e, 0);
StreebogMath.streebog_g(h, m, 0);
StreebogMath.streebog_g(h, e, 0);
// copy the result
// memcpy(hash, &sbx->h, sbx->hlen);
for (int j = 0; j < hashLength; j++) {
out[offset + j] = h.getByte(j);
}
// clear out sensitive stuff
reset();
}
}