/** Terminate the hash to get the digest @param md The hash state @param out [out] The destination of the hash (64 bytes) @return CRYPT_OK if successful */ int whirlpool_done(hash_state * md, unsigned char *out) { int i; LTC_ARGCHK(md != NULL); LTC_ARGCHK(out != NULL); if (md->whirlpool.curlen >= sizeof(md->whirlpool.buf)) { return CRYPT_INVALID_ARG; } /* increase the length of the message */ md->whirlpool.length += md->whirlpool.curlen * 8; /* append the '1' bit */ md->whirlpool.buf[md->whirlpool.curlen++] = (unsigned char)0x80; /* if the length is currently above 32 bytes we append zeros * then compress. Then we can fall back to padding zeros and length * encoding like normal. */ if (md->whirlpool.curlen > 32) { while (md->whirlpool.curlen < 64) { md->whirlpool.buf[md->whirlpool.curlen++] = (unsigned char)0; } whirlpool_compress(md, md->whirlpool.buf); md->whirlpool.curlen = 0; } /* pad upto 56 bytes of zeroes (should be 32 but we only support 64-bit lengths) */ while (md->whirlpool.curlen < 56) { md->whirlpool.buf[md->whirlpool.curlen++] = (unsigned char)0; } /* store length */ STORE64H(md->whirlpool.length, md->whirlpool.buf+56); whirlpool_compress(md, md->whirlpool.buf); /* copy output */ for (i = 0; i < 8; i++) { STORE64H(md->whirlpool.state[i], out+(8*i)); } #ifdef LTC_CLEAN_STACK zeromem(md, sizeof(*md)); #endif return CRYPT_OK; }
int main(void) { // Self-check if (!self_check()) { printf("Self-check failed\n"); return EXIT_FAILURE; } printf("Self-check passed\n"); // Benchmark speed uint8_t state[STATE_LEN] = {0}; uint8_t block[BLOCK_LEN] = {0}; const long ITERS = 1000000; clock_t start_time = clock(); for (long i = 0; i < ITERS; i++) whirlpool_compress(state, block); printf("Speed: %.1f MB/s\n", (double)ITERS * (sizeof(block) / sizeof(block[0])) / (clock() - start_time) * CLOCKS_PER_SEC / 1000000); return EXIT_SUCCESS; }