代码之家  ›  专栏  ›  技术社区  ›  Lev Knoblock

Java中重写GIMLIHI散列

  •  1
  • Lev Knoblock  · 技术社区  · 6 年前

    我正试图从C到Java重写GimLIIHHASH。

    我已经对照C代码和测试向量检查了我对gimli排列的重写,这是正确的,所以问题就在我对实际哈希的重写中,尽管我不知道在哪里。

    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);
        }
    }
    

    这直接取自Gimli的C实现, 下面是我已经编写的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实现返回B0634 B2C0B082AEDC5A0FE4EE3ADCFC989EC05DE6F0ADB04B3AAAC27 1F67,Java代码返回4B7F6DA2D5A901DBB580A0864 7E716EA1116328 85 993DA0BA29 D88 CE8926AF025。

    对Java实现与C语言的不同之处的任何帮助都将是非常值得赞赏的。

    1 回复  |  直到 6 年前
        1
  •  1
  •   Lev Knoblock    6 年前

    结果表明,散列不起作用的原因是一个终结性问题: 原始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让我注意到这些功能的行为。