Переписывание Gimli_hash на Java - PullRequest
0 голосов
/ 11 января 2019

Я пытаюсь переписать 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, будет принята с благодарностью.

1 Ответ

0 голосов
/ 11 января 2019

Оказывается, причина, по которой хеш не работал, была в порядке байтов: Исходные stateToBytes и stateToInt не работали, потому что они были в BE вместо LE: Оригинал:

private static byte[] stateToBytes(int[] state) {
        byte[][] temp = new byte[state.length][];

        for (int i = 0; i < temp.length; i++) {
            temp[i] = intToBytes(state[i]);
        }

        return merge(temp);
    }

    private static int[] stateToInt(byte[] state) {
        int[] out = new int[state.length / 4];
        for (int i = 0; i < (state.length / 4); i++) {
            out[i] = byteArrayToInt(Arrays.copyOfRange(state, (i * 4), ((i + 1) * 4)));
        }

        return out;
    }

Обновлен:

private static byte[] stateToBytes(int[] state) {
        byte[][] temp = new byte[state.length][];

        for (int i = 0; i < temp.length; i++) {
            temp[i] = reverse(intToBytes(state[i]));
        }

        return merge(temp);
    }

    private static int[] stateToInt(byte[] state) {
        int[] out = new int[state.length / 4];
        for (int i = 0; i < (state.length / 4); i++) {
            out[i] = byteArrayToInt(reverse(Arrays.copyOfRange(state, (i * 4), ((i + 1) * 4))));
        }

        return out;
    }

Спасибо @paddy за то, что обратили мое внимание на поведение этих функций.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...