Я пытаюсь переписать Gimli_hash с C на Java.
Я проверил переписывание перестановки Gimli как для кода c, так и для тестовых векторов, и это правильно, поэтому проблема заключается где-то в моем переписывании фактического хэша, хотя я не могу понять, где.
void Gimli_hash(const uint8_t *input,
uint64_t inputByteLen,
uint8_t *output,
uint64_t outputByteLen)
{
uint32_t state[12];
uint8_t* state_8 = (uint8_t*)state;
uint64_t blockSize = 0;
uint64_t i;
// === Initialize the state ===
memset(state, 0, sizeof(state));
// === Absorb all the input blocks ===
while(inputByteLen > 0) {
blockSize = MIN(inputByteLen, rateInBytes);
for(i=0; i<blockSize; i++)
state_8[i] ^= input[i];
input += blockSize;
inputByteLen -= blockSize;
if (blockSize == rateInBytes) {
gimli(state);
blockSize = 0;
}
}
// === Do the padding and switch to the squeezing phase ===
state_8[blockSize] ^= 0x1F;
// Add the second bit of padding
state_8[rateInBytes-1] ^= 0x80;
// Switch to the squeezing phase
gimli(state);
// === Squeeze out all the output blocks ===
while(outputByteLen > 0) {
blockSize = MIN(outputByteLen, rateInBytes);
memcpy(output, state, blockSize);
output += blockSize;
outputByteLen -= blockSize;
if (outputByteLen > 0)
gimli(state);
}
}
Это взято непосредственно из C-реализации Gimli,
и вот код Java, который мне удалось собрать:
public static byte[] hash(byte[] input, int outputLen) {
int inputlen = input.length;
int[] state = new int[12];
byte[] state_8 = stateToBytes(state);
int blocksize = 0;
int i;
int pointer = 0;
/* Absorbing input */
while (inputlen > 0) {
blocksize = Math.min(inputlen, rateInBytes);
for (i = 0; Integer.compareUnsigned(i, blocksize) < 0; i++) {
state_8[i] ^= input[i + pointer];
}
state = stateToInt(state_8);
pointer += blocksize;
inputlen -= blocksize;
if (blocksize == rateInBytes) {
gimli(state);
state_8 = stateToBytes(state);
blocksize = 0;
}
}
state_8[blocksize] ^= 0x1f;
state_8[rateInBytes - 1] ^= 0x80;
state = stateToInt(state_8);
gimli(state);
state_8 = stateToBytes(state);
byte[] output = new byte[outputLen];
int outputPointer = 0;
while (outputLen > 0) {
blocksize = Math.min(outputLen, rateInBytes);
System.arraycopy(state_8, 0, output, outputPointer, blocksize);
outputPointer += blocksize;
outputLen -= blocksize;
if (outputLen > 0) {
gimli(state);
state_8 = stateToBytes(state);
}
}
return output;
}
StateToInt и stateToBytes просто конвертируют между байтовым форматом состояния и форматом int (потому что перестановка работает в формате int, но хэш в байтовом формате). При хешировании пустой строки (0 байт) реализация C возвращает b0634b2c0b082aedc5c0a2fe4ee3adcfc989ec05de6f00addb04b3aaac271f67, а код Java возвращает 4b7f6da2d5a901dbdb580a08647d3 50 088088088029032291
Любая помощь в выяснении того, где реализация Java отличается от C, будет принята с благодарностью.