/** * sha3 * https://pablotron.org/sha3 * * Copyright (c) 2023, 2024 Paul Duncan * SPDX-License-Identifier: MIT-0 * * Embeddable, dependency-free, MIT-0-licensed C11 implementation of the * following SHA-3 hash functions, XOFs, and HMACs: * * - SHA3-224, SHA3-256, SHA3-384, and SHA3-512 * - SHAKE128 and SHAKE256 * - HMAC-SHA3-224, HMAC-SHA3-256, HMAC-SHA3-384, and HMAC-SHA3-512 * - cSHAKE128, cSHAKE128-XOF, cSHAKE256, and cSHAKE256-XOF * - KMAC128, KMAC128-XOF, KMAC256, and KMAC256-XOF * - TupleHash128, TupleHash128-XOF, TupleHash256, and TupleHash256-XOF * - ParallelHash128, ParallelHash128-XOF, ParallelHash256, and ParallelHash256-XOF * - TurboSHAKE128 and TurboSHAKE256 * - KangarooTwelve */ #include // true, false #include // uint64_t #include // memcpy() #include "sha3.h" /** @cond INTERNAL */ // 64-bit rotate left #define ROL(v, n) (((v) << (n)) | ((v) >> (64-(n)))) // minimum of two values #define MIN(a, b) (((a) < (b)) ? (a) : (b)) // number of rounds for permute() #define SHA3_NUM_ROUNDS 24 #if !defined(__AVX512F__) || defined(SHA3_TEST) // If AVX512 is supported and we are not building the test suite, // then do not compile the scalar step functions below. // // (because they aren't used by the AVX512 implementation). // theta step of keccak permutation (scalar implementation) static inline void theta(uint64_t a[static 25]) { const uint64_t c[5] = { a[0] ^ a[5] ^ a[10] ^ a[15] ^ a[20], a[1] ^ a[6] ^ a[11] ^ a[16] ^ a[21], a[2] ^ a[7] ^ a[12] ^ a[17] ^ a[22], a[3] ^ a[8] ^ a[13] ^ a[18] ^ a[23], a[4] ^ a[9] ^ a[14] ^ a[19] ^ a[24], }; const uint64_t d[5] = { c[4] ^ ROL(c[1], 1), c[0] ^ ROL(c[2], 1), c[1] ^ ROL(c[3], 1), c[2] ^ ROL(c[4], 1), c[3] ^ ROL(c[0], 1), }; a[ 0] ^= d[0]; a[ 1] ^= d[1]; a[ 2] ^= d[2]; a[ 3] ^= d[3]; a[ 4] ^= d[4]; a[ 5] ^= d[0]; a[ 6] ^= d[1]; a[ 7] ^= d[2]; a[ 8] ^= d[3]; a[ 9] ^= d[4]; a[10] ^= d[0]; a[11] ^= d[1]; a[12] ^= d[2]; a[13] ^= d[3]; a[14] ^= d[4]; a[15] ^= d[0]; a[16] ^= d[1]; a[17] ^= d[2]; a[18] ^= d[3]; a[19] ^= d[4]; a[20] ^= d[0]; a[21] ^= d[1]; a[22] ^= d[2]; a[23] ^= d[3]; a[24] ^= d[4]; } // rho step of keccak permutation (scalar implementation) static inline void rho(uint64_t a[static 25]) { a[1] = ROL(a[1], 1); // 1 % 64 = 1 a[2] = ROL(a[2], 62); // 190 % 64 = 62 a[3] = ROL(a[3], 28); // 28 % 64 = 28 a[4] = ROL(a[4], 27); // 91 % 64 = 27 a[5] = ROL(a[5], 36); // 36 % 64 = 36 a[6] = ROL(a[6], 44); // 300 % 64 = 44 a[7] = ROL(a[7], 6); // 6 % 64 = 6 a[8] = ROL(a[8], 55); // 55 % 64 = 55 a[9] = ROL(a[9], 20); // 276 % 64 = 20 a[10] = ROL(a[10], 3); // 3 % 64 = 3 a[11] = ROL(a[11], 10); // 10 % 64 = 10 a[12] = ROL(a[12], 43); // 171 % 64 = 43 a[13] = ROL(a[13], 25); // 153 % 64 = 25 a[14] = ROL(a[14], 39); // 231 % 64 = 39 a[15] = ROL(a[15], 41); // 105 % 64 = 41 a[16] = ROL(a[16], 45); // 45 % 64 = 45 a[17] = ROL(a[17], 15); // 15 % 64 = 15 a[18] = ROL(a[18], 21); // 21 % 64 = 21 a[19] = ROL(a[19], 8); // 136 % 64 = 8 a[20] = ROL(a[20], 18); // 210 % 64 = 18 a[21] = ROL(a[21], 2); // 66 % 64 = 2 a[22] = ROL(a[22], 61); // 253 % 64 = 61 a[23] = ROL(a[23], 56); // 120 % 64 = 56 a[24] = ROL(a[24], 14); // 78 % 64 = 14 } // pi step of keccak permutation (scalar implementation) static inline void pi(uint64_t dst[static 25], const uint64_t src[static 25]) { dst[0] = src[0]; dst[1] = src[6]; dst[2] = src[12]; dst[3] = src[18]; dst[4] = src[24]; dst[5] = src[3]; dst[6] = src[9]; dst[7] = src[10]; dst[8] = src[16]; dst[9] = src[22]; dst[10] = src[1]; dst[11] = src[7]; dst[12] = src[13]; dst[13] = src[19]; dst[14] = src[20]; dst[15] = src[4]; dst[16] = src[5]; dst[17] = src[11]; dst[18] = src[17]; dst[19] = src[23]; dst[20] = src[2]; dst[21] = src[8]; dst[22] = src[14]; dst[23] = src[15]; dst[24] = src[21]; } // chi step of keccak permutation (scalar implementation) static inline void chi(uint64_t dst[static 25], const uint64_t src[static 25]) { dst[0] = src[0] ^ (~src[1] & src[2]); dst[1] = src[1] ^ (~src[2] & src[3]); dst[2] = src[2] ^ (~src[3] & src[4]); dst[3] = src[3] ^ (~src[4] & src[0]); dst[4] = src[4] ^ (~src[0] & src[1]); dst[5] = src[5] ^ (~src[6] & src[7]); dst[6] = src[6] ^ (~src[7] & src[8]); dst[7] = src[7] ^ (~src[8] & src[9]); dst[8] = src[8] ^ (~src[9] & src[5]); dst[9] = src[9] ^ (~src[5] & src[6]); dst[10] = src[10] ^ (~src[11] & src[12]); dst[11] = src[11] ^ (~src[12] & src[13]); dst[12] = src[12] ^ (~src[13] & src[14]); dst[13] = src[13] ^ (~src[14] & src[10]); dst[14] = src[14] ^ (~src[10] & src[11]); dst[15] = src[15] ^ (~src[16] & src[17]); dst[16] = src[16] ^ (~src[17] & src[18]); dst[17] = src[17] ^ (~src[18] & src[19]); dst[18] = src[18] ^ (~src[19] & src[15]); dst[19] = src[19] ^ (~src[15] & src[16]); dst[20] = src[20] ^ (~src[21] & src[22]); dst[21] = src[21] ^ (~src[22] & src[23]); dst[22] = src[22] ^ (~src[23] & src[24]); dst[23] = src[23] ^ (~src[24] & src[20]); dst[24] = src[24] ^ (~src[20] & src[21]); } // iota step of keccak permutation (scalar implementation) static inline void iota(uint64_t a[static 25], const int i) { // round constants (ambiguous in spec) static const uint64_t RCS[] = { 0x0000000000000001ULL, 0x0000000000008082ULL, 0x800000000000808aULL, 0x8000000080008000ULL, 0x000000000000808bULL, 0x0000000080000001ULL, 0x8000000080008081ULL, 0x8000000000008009ULL, 0x000000000000008aULL, 0x0000000000000088ULL, 0x0000000080008009ULL, 0x000000008000000aULL, 0x000000008000808bULL, 0x800000000000008bULL, 0x8000000000008089ULL, 0x8000000000008003ULL, 0x8000000000008002ULL, 0x8000000000000080ULL, 0x000000000000800aULL, 0x800000008000000aULL, 0x8000000080008081ULL, 0x8000000000008080ULL, 0x0000000080000001ULL, 0x8000000080008008ULL, }; a[0] ^= RCS[i]; } #endif /* !defined(__AVX512F__) || defined(SHA3_TEST) */ #ifndef __AVX512F__ // keccak permutation (scalar implementation) // // note: clang is better about inlining this than gcc with a // configurable number of rounds. the configurable number of rounds is // only used by turboshake, so it might be worth creating a specialized // `permute12()` to handle turboshake. static inline void permute(uint64_t a[static 25], const size_t num_rounds) { uint64_t tmp[25] = { 0 }; for (int i = 0; i < (int) num_rounds; i++) { theta(a); rho(a); pi(tmp, a); chi(a, tmp); iota(a, 24 - num_rounds + i); } } #endif /* __AVX512F__ */ #ifdef __AVX512F__ #include // keccak permutation (avx512 implementation). // // copied from `permute_avx512_fast()` in `tests/permute/permute.c`. all // steps are inlined as blocks. ~3x faster than scalar implementation, // but could be sped up more. // // how it operates (roughly): // // 1. load rows from state `s` into avx512 registers r0-r4, like so: // // r0 <- | s[ 0] | s[ 1] | s[ 2] | s[ 3] | s[ 4] | n/a | n/a | n/a | // r1 <- | s[ 5] | s[ 6] | s[ 7] | s[ 8] | s[ 9] | n/a | n/a | n/a | // r2 <- | s[10] | s[11] | s[12] | s[13] | s[14] | n/a | n/a | n/a | // r3 <- | s[15] | s[16] | s[17] | s[18] | s[19] | n/a | n/a | n/a | // r4 <- | s[20] | s[21] | s[22] | s[23] | s[24] | n/a | n/a | n/a | // // 2. load the first 8 round constants for iota into an avx512 `ra` // (round constants) register. // // 3. for each round: // a. Perform theta, rho, pi, and chi steps. pi, in particular, has // a large number of permutation registers (so it may spill). // b. Perform iota with the first round constant in `rc`, then permute // `rc`. If we have exhausted all 8 round constants and we are not // at the final round, then load the next 8 round constants. // // 4. copy the rows from registers r0-r4 back to the state `s`. // // as noted above, this is not the most efficient avx512 implementation; // the row registers have three empty slots and there are a lot of loads // that could be removed with a little more work. static inline void permute(uint64_t s[static 25], const size_t num_rounds) { // unaligned load mask and permutation indices uint8_t mask = 0x1f, m0b = 0x01; const __mmask8 m = _load_mask8(&mask), m0 = _load_mask8(&m0b); // round constants (used in iota) static const uint64_t RCS[] = { 0x0000000000000001ULL, 0x0000000000008082ULL, 0x800000000000808aULL, 0x8000000080008000ULL, 0x000000000000808bULL, 0x0000000080000001ULL, 0x8000000080008081ULL, 0x8000000000008009ULL, 0x000000000000008aULL, 0x0000000000000088ULL, 0x0000000080008009ULL, 0x000000008000000aULL, 0x000000008000808bULL, 0x800000000000008bULL, 0x8000000000008089ULL, 0x8000000000008003ULL, 0x8000000000008002ULL, 0x8000000000000080ULL, 0x000000000000800aULL, 0x800000008000000aULL, 0x8000000080008081ULL, 0x8000000000008080ULL, 0x0000000080000001ULL, 0x8000000080008008ULL, }; // load round constant // note: this will bomb if num_rounds < 8 or num_rounds > 24. __m512i rc = _mm512_loadu_epi64((void*) (RCS + 24 - num_rounds)); // load rc permutation static const uint64_t rc_ps[8] = { 1, 2, 3, 4, 5, 6, 7, 0 }; const __m512i rc_p = _mm512_loadu_epi64((void*) rc_ps); // load rows __m512i r0 = _mm512_maskz_loadu_epi64(m, (void*) (s)), r1 = _mm512_maskz_loadu_epi64(m, (void*) (s + 5)), r2 = _mm512_maskz_loadu_epi64(m, (void*) (s + 10)), r3 = _mm512_maskz_loadu_epi64(m, (void*) (s + 15)), r4 = _mm512_maskz_loadu_epi64(m, (void*) (s + 20)); for (int i = 0; i < (int) num_rounds; i++) { // theta { const __m512i i0 = _mm512_setr_epi64(4, 0, 1, 2, 3, 5, 6, 7), i1 = _mm512_setr_epi64(1, 2, 3, 4, 0, 5, 6, 7); // c = xor(r0, r1, r2, r3, r4) const __m512i r01 = _mm512_xor_epi64(r0, r1), r23 = _mm512_xor_epi64(r2, r3), r03 = _mm512_xor_epi64(r01, r23), c = _mm512_xor_epi64(r03, r4); // d = xor(permute(i0, c), permute(i1, rol(c, 1))) const __m512i d0 = _mm512_permutexvar_epi64(i0, c), d1 = _mm512_permutexvar_epi64(i1, _mm512_rol_epi64(c, 1)), d = _mm512_xor_epi64(d0, d1); // row = xor(row, d) r0 = _mm512_xor_epi64(r0, d); r1 = _mm512_xor_epi64(r1, d); r2 = _mm512_xor_epi64(r2, d); r3 = _mm512_xor_epi64(r3, d); r4 = _mm512_xor_epi64(r4, d); } // rho { // unaligned load mask and rotate values static const uint64_t vs0[8] = { 0, 1, 62, 28, 27, 0, 0, 0 }, vs1[8] = { 36, 44, 6, 55, 20, 0, 0, 0 }, vs2[8] = { 3, 10, 43, 25, 39, 0, 0, 0 }, vs3[8] = { 41, 45, 15, 21, 8, 0, 0, 0 }, vs4[8] = { 18, 2, 61, 56, 14, 0, 0, 0 }; // load rotate values const __m512i v0 = _mm512_loadu_epi64((void*) vs0), v1 = _mm512_loadu_epi64((void*) vs1), v2 = _mm512_loadu_epi64((void*) vs2), v3 = _mm512_loadu_epi64((void*) vs3), v4 = _mm512_loadu_epi64((void*) vs4); // rotate r0 = _mm512_rolv_epi64(r0, v0); r1 = _mm512_rolv_epi64(r1, v1); r2 = _mm512_rolv_epi64(r2, v2); r3 = _mm512_rolv_epi64(r3, v3); r4 = _mm512_rolv_epi64(r4, v4); } // pi { // mask bytes uint8_t m01b = 0x03, m23b = 0x0c, m4b = 0x10; // load masks const __mmask8 m01 = _load_mask8(&m01b), m23 = _load_mask8(&m23b), m4 = _load_mask8(&m4b); // permutation indices // // (note: these are masked so only the relevant indices for // _mm512_maskz_permutex2var_epi64() in each array are filled in) static const uint64_t t0_pis_01[8] = { 0, 8 + 1, 0, 0, 0, 0, 0, 0 }, t0_pis_23[8] = { 0, 0, 2, 8 + 3, 0, 0, 0, 0 }, t0_pis_4[8] = { 0, 0, 0, 0, 4, 0, 0, 0 }, t1_pis_01[8] = { 3, 8 + 4, 0, 0, 0, 0, 0, 0 }, t1_pis_23[8] = { 0, 0, 0, 8 + 1, 0, 0, 0, 0 }, t1_pis_4[8] = { 0, 0, 0, 0, 2, 0, 0, 0 }, t2_pis_01[8] = { 1, 8 + 2, 0, 0, 0, 0, 0, 0 }, t2_pis_23[8] = { 0, 0, 3, 8 + 4, 0, 0, 0, 0 }, t2_pis_4[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }, t3_pis_01[8] = { 4, 8 + 0, 0, 0, 0, 0, 0, 0 }, t3_pis_23[8] = { 0, 0, 1, 8 + 2, 0, 0, 0, 0 }, t3_pis_4[8] = { 0, 0, 0, 0, 3, 0, 0, 0 }, t4_pis_01[8] = { 2, 8 + 3, 0, 0, 0, 0, 0, 0 }, t4_pis_23[8] = { 0, 0, 4, 8 + 0, 0, 0, 0, 0 }, t4_pis_4[8] = { 0, 0, 0, 0, 1, 0, 0, 0 }; // load permutation indices const __m512i t0_p01 = _mm512_maskz_loadu_epi64(m01, (void*) t0_pis_01), t0_p23 = _mm512_maskz_loadu_epi64(m23, (void*) t0_pis_23), t0_p4 = _mm512_maskz_loadu_epi64(m4, (void*) t0_pis_4), t1_p01 = _mm512_maskz_loadu_epi64(m01, (void*) t1_pis_01), t1_p23 = _mm512_maskz_loadu_epi64(m23, (void*) t1_pis_23), t1_p4 = _mm512_maskz_loadu_epi64(m4, (void*) t1_pis_4), t2_p01 = _mm512_maskz_loadu_epi64(m01, (void*) t2_pis_01), t2_p23 = _mm512_maskz_loadu_epi64(m23, (void*) t2_pis_23), t2_p4 = _mm512_maskz_loadu_epi64(m4, (void*) t2_pis_4), t3_p01 = _mm512_maskz_loadu_epi64(m01, (void*) t3_pis_01), t3_p23 = _mm512_maskz_loadu_epi64(m23, (void*) t3_pis_23), t3_p4 = _mm512_maskz_loadu_epi64(m4, (void*) t3_pis_4), t4_p01 = _mm512_maskz_loadu_epi64(m01, (void*) t4_pis_01), t4_p23 = _mm512_maskz_loadu_epi64(m23, (void*) t4_pis_23), t4_p4 = _mm512_maskz_loadu_epi64(m4, (void*) t4_pis_4); // permute rows const __m512i t0e0 = _mm512_maskz_permutex2var_epi64(m01, r0, t0_p01, r1), t0e2 = _mm512_maskz_permutex2var_epi64(m23, r2, t0_p23, r3), t0e4 = _mm512_maskz_permutex2var_epi64(m4, r4, t0_p4, r0), t0 = _mm512_or_epi64(_mm512_or_epi64(t0e0, t0e2), t0e4), t1e0 = _mm512_maskz_permutex2var_epi64(m01, r0, t1_p01, r1), t1e2 = _mm512_maskz_permutex2var_epi64(m23, r2, t1_p23, r3), t1e4 = _mm512_maskz_permutex2var_epi64(m4, r4, t1_p4, r0), t1 = _mm512_or_epi64(_mm512_or_epi64(t1e0, t1e2), t1e4), t2e0 = _mm512_maskz_permutex2var_epi64(m01, r0, t2_p01, r1), t2e2 = _mm512_maskz_permutex2var_epi64(m23, r2, t2_p23, r3), t2e4 = _mm512_maskz_permutex2var_epi64(m4, r4, t2_p4, r0), t2 = _mm512_or_epi64(_mm512_or_epi64(t2e0, t2e2), t2e4), t3e0 = _mm512_maskz_permutex2var_epi64(m01, r0, t3_p01, r1), t3e2 = _mm512_maskz_permutex2var_epi64(m23, r2, t3_p23, r3), t3e4 = _mm512_maskz_permutex2var_epi64(m4, r4, t3_p4, r0), t3 = _mm512_or_epi64(_mm512_or_epi64(t3e0, t3e2), t3e4), t4e0 = _mm512_maskz_permutex2var_epi64(m01, r0, t4_p01, r1), t4e2 = _mm512_maskz_permutex2var_epi64(m23, r2, t4_p23, r3), t4e4 = _mm512_maskz_permutex2var_epi64(m4, r4, t4_p4, r0), t4 = _mm512_or_epi64(_mm512_or_epi64(t4e0, t4e2), t4e4); // store rows r0 = t0; r1 = t1; r2 = t2; r3 = t3; r4 = t4; } // chi { // permutation indices static const uint64_t pis0[8] = { 1, 2, 3, 4, 0, 0, 0, 0 }, pis1[8] = { 2, 3, 4, 0, 1, 0, 0, 0 }; // load permutation indices const __m512i p0 = _mm512_maskz_loadu_epi64(m, (void*) pis0), p1 = _mm512_maskz_loadu_epi64(m, (void*) pis1); // permute rows const __m512i t0_e0 = _mm512_maskz_permutexvar_epi64(m, p0, r0), t0_e1 = _mm512_maskz_permutexvar_epi64(m, p1, r0), t0 = _mm512_xor_epi64(r0, _mm512_andnot_epi64(t0_e0, t0_e1)), t1_e0 = _mm512_maskz_permutexvar_epi64(m, p0, r1), t1_e1 = _mm512_maskz_permutexvar_epi64(m, p1, r1), t1 = _mm512_xor_epi64(r1, _mm512_andnot_epi64(t1_e0, t1_e1)), t2_e0 = _mm512_maskz_permutexvar_epi64(m, p0, r2), t2_e1 = _mm512_maskz_permutexvar_epi64(m, p1, r2), t2 = _mm512_xor_epi64(r2, _mm512_andnot_epi64(t2_e0, t2_e1)), t3_e0 = _mm512_maskz_permutexvar_epi64(m, p0, r3), t3_e1 = _mm512_maskz_permutexvar_epi64(m, p1, r3), t3 = _mm512_xor_epi64(r3, _mm512_andnot_epi64(t3_e0, t3_e1)), t4_e0 = _mm512_maskz_permutexvar_epi64(m, p0, r4), t4_e1 = _mm512_maskz_permutexvar_epi64(m, p1, r4), t4 = _mm512_xor_epi64(r4, _mm512_andnot_epi64(t4_e0, t4_e1)); // store rows r0 = t0; r1 = t1; r2 = t2; r3 = t3; r4 = t4; } // iota { // xor round constant, shuffle rc register r0 = _mm512_mask_xor_epi64(r0, m0, r0, rc); rc = _mm512_permutexvar_epi64(rc_p, rc); if (((24 - num_rounds + i + 1) % 8) == 0 && i != 23) { // load next set of round constants // note: this will bomb if num_rounds < 8 or num_rounds > 24. rc = _mm512_loadu_epi64((void*) (RCS + 24 - num_rounds + (i + 1))); } } } // store rows _mm512_mask_storeu_epi64((void*) (s), m, r0), _mm512_mask_storeu_epi64((void*) (s + 5), m, r1), _mm512_mask_storeu_epi64((void*) (s + 10), m, r2), _mm512_mask_storeu_epi64((void*) (s + 15), m, r3), _mm512_mask_storeu_epi64((void*) (s + 20), m, r4); } #endif /* __AVX512F__ */ // one-shot keccak. // NOTE: only used by `hash_once()`. static inline size_t keccak(sha3_state_t * const a, const uint8_t *m, size_t m_len, const size_t rate) { while (m_len >= rate) { // absorb u64-sized chunks for (size_t i = 0; i < rate / sizeof(uint64_t); i++) { a->u64[i] ^= ((uint64_t*) m)[i]; } // permute permute(a->u64, SHA3_NUM_ROUNDS); m += rate; m_len -= rate; } // absorb u64-sized chunks for (size_t i = 0; i < m_len / sizeof(uint64_t); i++) { a->u64[i] ^= ((uint64_t*) m)[i]; } // absorb final bytes for (size_t i = m_len & ~(sizeof(uint64_t) - 1); i < m_len; i++) { a->u8[i] ^= m[i]; } // return final chunk size return m_len; } // one-shot sha3 hash. static inline void hash_once(const uint8_t *m, size_t m_len, uint8_t * const dst, const size_t dst_len) { // in the sha3 hash functions, the capacity is always 2 times the // destination length, and the rate is the total state size minus the // capacity const size_t rate = 200 - 2 * dst_len; sha3_state_t a = { .u64 = { 0 } }; const size_t len = keccak(&a, m, m_len, rate); // append suffix and padding // (note: suffix and padding are ambiguous in spec) a.u8[len] ^= 0x06; a.u8[rate-1] ^= 0x80; // permute permute(a.u64, SHA3_NUM_ROUNDS); // copy to destination memcpy(dst, a.u8, dst_len); } // Initialize iterative sha3 hash context. static inline void hash_init(sha3_t * const hash) { memset(hash, 0, sizeof(sha3_t)); } // Absorb input data into iterative SHA-3 hash context. static inline bool hash_absorb(sha3_t * const hash, const size_t rate, const uint8_t *src, size_t len) { if (hash->finalized) { // hash already finalized, return false return false; } // absorb bytes (FIXME: absorb larger chunks) for (size_t i = 0; i < len; i++) { hash->a.u8[hash->num_bytes++] ^= src[i]; if (hash->num_bytes == rate) { // permute permute(hash->a.u64, SHA3_NUM_ROUNDS); hash->num_bytes = 0; } } // return success return true; } // Finalize iterative SHA-3 hash context. static inline void hash_final(sha3_t * const hash, const size_t rate, uint8_t * dst, const size_t dst_len) { if (!hash->finalized) { // mark context as final hash->finalized = true; // append suffix and padding // (note: suffix and padding are ambiguous in spec) hash->a.u8[hash->num_bytes] ^= 0x06; hash->a.u8[rate - 1] ^= 0x80; // permute permute(hash->a.u64, SHA3_NUM_ROUNDS); } // copy to destination memcpy(dst, hash->a.u8, dst_len); } // define hash one-shot and iterative context functions #define DEF_HASH(BITS) \ /* one-shot hash */ \ void sha3_ ## BITS(const uint8_t *m, size_t m_len, uint8_t dst[static SHA3_ ## BITS ## _LEN]) { \ hash_once(m, m_len, dst, SHA3_ ## BITS ## _LEN); \ } \ \ /* Initialize iterative hash context. */ \ void sha3_ ## BITS ## _init(sha3_t * const hash) { \ hash_init(hash); \ } \ \ /* Absorb data into SHA3 iterative hash context. */ \ _Bool sha3_ ## BITS ## _absorb(sha3_t * const hash, const uint8_t *src, const size_t len) { \ return hash_absorb(hash, SHA3_ ## BITS ## _RATE, src, len); \ } \ \ /* Finalize SHA3 iterative hash context. */ \ void sha3_ ## BITS ## _final(sha3_t * const hash, uint8_t dst[static SHA3_ ## BITS ## _LEN]) { \ hash_final(hash, SHA3_ ## BITS ## _RATE, dst, SHA3_ ## BITS ## _LEN); \ } // sha3-224 #define SHA3_224_LEN 28 // sha3-224 output length, in bytes #define SHA3_224_RATE 200 - 2 * SHA3_224_LEN // sha3-224 input rate DEF_HASH(224) // sha3_224_{init,absorb,final}() // sha3-256 #define SHA3_256_LEN 32 // sha3-256 output length, in bytes #define SHA3_256_RATE 200 - 2 * SHA3_256_LEN // sha3-256 input rate, in bytes DEF_HASH(256) // sha3_256_{init,absorb,final}() // sha3-384 #define SHA3_384_LEN 48 // sha3-384 output length, in bytes #define SHA3_384_RATE 200 - 2 * SHA3_384_LEN // sha3-384 input rate, in bytes DEF_HASH(384) // sha3_384_{init,absorb,final}() // sha3-512 #define SHA3_512_LEN 64 // sha3-512 output length, in bytes #define SHA3_512_RATE 200 - 2 * SHA3_512_LEN // sha3-512 input rate, in bytes DEF_HASH(512) // sha3_512_{init,absorb,final}() // initialize xof context static inline void xof_init(sha3_xof_t * const xof) { memset(xof, 0, sizeof(sha3_xof_t)); } // absorb message into xof context without checking to see if the // context has already been squeezed. // // called by `xof_absorb()` and `xof_once()`. static inline void xof_absorb_raw(sha3_xof_t * const xof, const size_t rate, const size_t num_rounds, const uint8_t *m, size_t m_len) { // load byte count from context size_t num_bytes = xof->num_bytes; // absorb aligned chunks if ((num_bytes & 7) == 0 && (((uintptr_t) m) & 7) == 0) { // absorb 32 byte chunks (4 x uint64) while (num_bytes + 32 <= rate && m_len > 32) { // xor chunk into state // (FIXME: does not vectorize for some reason, even when unrolled) for (size_t i = 0; i < 4; i++) { xof->a.u64[num_bytes/8 + i] ^= ((uint64_t*) m)[i]; } // update counters num_bytes += 32; m += 32; m_len -= 32; if (num_bytes == rate) { // permute state permute(xof->a.u64, num_rounds); num_bytes = 0; } } // absorb 8 byte chunks (1 x uint64) while (num_bytes + 8 <= rate && m_len > 8) { // xor chunk into state xof->a.u64[num_bytes/8] ^= *((uint64_t*) m); // update counters num_bytes += 8; m += 8; m_len -= 8; if (num_bytes == rate) { // permute state permute(xof->a.u64, num_rounds); num_bytes = 0; } } } // absorb remaining bytes for (size_t i = 0; i < m_len; i++) { // xor byte into state xof->a.u8[num_bytes++] ^= m[i]; if (num_bytes == rate) { // permute state permute(xof->a.u64, num_rounds); num_bytes = 0; } } // save byte count to context xof->num_bytes = num_bytes; } // check state, absorb bytes static inline _Bool xof_absorb(sha3_xof_t * const xof, const size_t rate, const size_t num_rounds, const uint8_t * const m, size_t m_len) { // check state if (xof->squeezing) { // xof has already been squeezed, return error return false; } // absorb xof_absorb_raw(xof, rate, num_rounds, m, m_len); // return success return true; } // finalize absorb static inline void xof_absorb_done(sha3_xof_t * const xof, const size_t rate, const size_t num_rounds, const uint8_t pad) { // append suffix (s6.2) and padding // (note: suffix and padding are ambiguous in spec) xof->a.u8[xof->num_bytes] ^= pad; xof->a.u8[rate - 1] ^= 0x80; // permute permute(xof->a.u64, num_rounds); // switch to squeeze mode xof->num_bytes = 0; xof->squeezing = true; } // squeeze data without checking state (used by xof_once()) static inline void xof_squeeze_raw(sha3_xof_t * const xof, const size_t rate, const size_t num_rounds, uint8_t *dst, size_t dst_len) { if (!xof->num_bytes) { // num_bytes is zero, so we are reading from the start of the // internal state buffer. while `dst_len` is greater than rate, // copy `rate` sized chunks directly from the internal state buffer // to the destination, then permute the internal state. squeeze // rate-sized chunks to destination while (dst_len >= rate) { memcpy(dst, xof->a.u8, rate); // copy rate-sized chunk permute(xof->a.u64, num_rounds); // permute state // update destination pointer and length dst += rate; dst_len -= rate; } if (dst_len > 0) { // the remaining destination length is less than `rate`, so copy a // `dst_len`-sized chunk from the internal state to the // destination buffer, then update the read byte count. // squeeze dst_len-sized block to destination memcpy(dst, xof->a.u8, dst_len); // copy dst_len-sized chunk xof->num_bytes = dst_len; // update read byte count } } else { // fall back to squeezing one byte at a time // squeeze bytes to destination for (size_t i = 0; i < dst_len; i++) { dst[i] = xof->a.u8[xof->num_bytes++]; // squeeze byte to destination if (xof->num_bytes == rate) { permute(xof->a.u64, num_rounds); // permute state xof->num_bytes = 0; // clear read bytes count } } } } // squeeze data from xof static inline void xof_squeeze(sha3_xof_t * const xof, const size_t rate, const size_t num_rounds, const uint8_t pad, uint8_t * const dst, const size_t dst_len) { // check state if (!xof->squeezing) { // finalize absorb xof_absorb_done(xof, rate, num_rounds, pad); } xof_squeeze_raw(xof, rate, num_rounds, dst, dst_len); } // one-shot xof absorb and squeeze static inline void xof_once(const size_t rate, const size_t num_rounds, const uint8_t pad, const uint8_t * const src, const size_t src_len, uint8_t * const dst, const size_t dst_len) { // init sha3_xof_t xof; xof_init(&xof); // absorb xof_absorb_raw(&xof, rate, num_rounds, src, src_len); xof_absorb_done(&xof, rate, num_rounds, pad); // squeeze xof_squeeze_raw(&xof, rate, num_rounds, dst, dst_len); } // define shake iterative context and one-shot functions #define DEF_SHAKE(BITS) \ /* init shake context */ \ void shake ## BITS ## _init(sha3_xof_t * const xof) { \ xof_init(xof); \ } \ \ /* absorb bytes into shake context */ \ _Bool shake ## BITS ## _absorb(sha3_xof_t * const xof, const uint8_t * const m, const size_t len) { \ return xof_absorb(xof, SHAKE ## BITS ## _RATE, SHA3_NUM_ROUNDS, m, len); \ } \ \ /* squeeze bytes from shake context */ \ void shake ## BITS ## _squeeze(sha3_xof_t * const xof, uint8_t * const dst, const size_t dst_len) { \ xof_squeeze(xof, SHAKE ## BITS ## _RATE, SHA3_NUM_ROUNDS, SHAKE ## BITS ## _PAD, dst, dst_len); \ } \ \ /* one-shot shake absorb and squeeze */ \ void shake ## BITS(const uint8_t * const src, const size_t src_len, uint8_t * const dst, const size_t dst_len) { \ xof_once(SHAKE ## BITS ## _RATE, SHA3_NUM_ROUNDS, SHAKE ## BITS ## _PAD, src, src_len, dst, dst_len); \ } // shake128 #define SHAKE128_RATE (200 - 2 * 16) // shake128 input rate, in bytes #define SHAKE128_PAD 0x1f // shake128 padding DEF_SHAKE(128) // shake128_{init,absorb,squeeze}() // shake256 #define SHAKE256_RATE (200 - 2 * 32) // shake256 input rate, in bytes #define SHAKE256_PAD 0x1f // shake256 padding DEF_SHAKE(256) // shake256_{init,absorb,squeeze}() // define hmac-sha3 iterative context and one-shot functions #define DEF_HMAC(BITS) \ /* init hmac-sha3 context */ \ void hmac_sha3_ ## BITS ## _init(hmac_sha3_t *hmac, const uint8_t *k, const size_t k_len) { \ /* clear finalized flag */ \ hmac->finalized = false; \ \ /* init key buffer */ \ uint8_t k_buf[SHA3_ ## BITS ## _RATE] = { 0 }; \ if (k_len <= sizeof(k_buf)) { \ memcpy(k_buf, k, k_len); \ } else { \ sha3_ ## BITS(k, k_len, k_buf); \ } \ \ /* apply opad */ \ for (size_t i = 0; i < SHA3_ ## BITS ## _RATE; i++) { \ k_buf[i] ^= 0x5c; \ } \ \ /* init outer hash, absorb outer key */ \ sha3_ ## BITS ## _init(&(hmac->outer)); \ sha3_ ## BITS ## _absorb(&(hmac->outer), k_buf, sizeof(k_buf)); \ \ /* remove opad, apply ipad */ \ for (size_t i = 0; i < SHA3_ ## BITS ## _RATE; i++) { \ k_buf[i] ^= (0x5c ^ 0x36); \ } \ \ /* init outer hash, absorb inner key */ \ sha3_ ## BITS ## _init(&(hmac->inner)); \ sha3_ ## BITS ## _absorb(&(hmac->inner), k_buf, sizeof(k_buf)); \ } \ \ /* absorb data into hmac-sha3 context */ \ _Bool hmac_sha3_ ## BITS ## _absorb(hmac_sha3_t *hmac, const uint8_t *src, const size_t len) { \ return sha3_ ## BITS ## _absorb(&(hmac->inner), src, len); \ } \ \ /* finalize hmac-sha3 context */ \ void hmac_sha3_ ## BITS ## _final(hmac_sha3_t *hmac, uint8_t dst[static SHA3_ ## BITS ## _LEN]) { \ /* finalize inner hash into buffer */ \ uint8_t buf[SHA3_ ## BITS ## _LEN] = { 0 }; \ sha3_ ## BITS ## _final(&(hmac->inner), buf); \ \ /* absorb into outer hash */ \ sha3_ ## BITS ## _absorb(&(hmac->outer), buf, sizeof(buf)); \ \ /* finalize outer hash into destination */ \ sha3_ ## BITS ## _final(&(hmac->outer), dst); \ } \ \ /* one-shot hmac-sha3 */ \ void hmac_sha3_ ## BITS(const uint8_t * const k, const size_t k_len, const uint8_t * const m, const size_t m_len, uint8_t dst[static SHA3_## BITS ##_LEN]) { \ /* init */ \ hmac_sha3_t hmac; \ hmac_sha3_## BITS ##_init(&hmac, k, k_len); \ \ /* absorb */ \ hmac_sha3_## BITS ##_absorb(&hmac, m, m_len); \ \ /* finalize */ \ hmac_sha3_## BITS ##_final(&hmac, dst); \ } // define hmacs DEF_HMAC(224) // hmac-sha3-224 DEF_HMAC(256) // hmac-sha3-224 DEF_HMAC(384) // hmac-sha3-224 DEF_HMAC(512) // hmac-sha3-224 // NIST SP 800-105 utility function. static inline size_t left_encode(uint8_t buf[static 9], const uint64_t n) { if (n > 0x00ffffffffffffffULL) { buf[0] = 8; buf[1] = (n >> 56) & 0xff; buf[2] = (n >> 40) & 0xff; buf[3] = (n >> 32) & 0xff; buf[4] = (n >> 24) & 0xff; buf[5] = (n >> 16) & 0xff; buf[6] = (n >> 8) & 0xff; buf[7] = n & 0xff; return 9; } else if (n > 0x0000ffffffffffffULL) { buf[0] = 7; buf[1] = (n >> 56) & 0xff; buf[2] = (n >> 40) & 0xff; buf[3] = (n >> 32) & 0xff; buf[4] = (n >> 24) & 0xff; buf[5] = (n >> 16) & 0xff; buf[6] = (n >> 8) & 0xff; buf[7] = n & 0xff; return 8; } else if (n > 0x000000ffffffffffULL) { buf[0] = 6; buf[1] = (n >> 40) & 0xff; buf[2] = (n >> 32) & 0xff; buf[3] = (n >> 24) & 0xff; buf[4] = (n >> 16) & 0xff; buf[5] = (n >> 8) & 0xff; buf[6] = n & 0xff; return 7; } else if (n > 0x00000000ffffffffULL) { buf[0] = 5; buf[1] = (n >> 32) & 0xff; buf[2] = (n >> 24) & 0xff; buf[3] = (n >> 16) & 0xff; buf[4] = (n >> 8) & 0xff; buf[5] = n & 0xff; return 6; } else if (n > 0x0000000000ffffffULL) { buf[0] = 4; buf[1] = (n >> 24) & 0xff; buf[2] = (n >> 16) & 0xff; buf[3] = (n >> 8) & 0xff; buf[4] = n & 0xff; return 5; } else if (n > 0x000000000000ffffULL) { buf[0] = 3; buf[1] = (n >> 16) & 0xff; buf[2] = (n >> 8) & 0xff; buf[3] = n & 0xff; return 4; } else if (n > 0x00000000000000ffULL) { buf[0] = 2; buf[1] = (n >> 8) & 0xff; buf[2] = n & 0xff; return 3; } else { buf[0] = 1; buf[1] = n & 0xff; return 2; } } // NIST SP 800-105 utility function. static inline size_t right_encode(uint8_t buf[static 9], const uint64_t n) { if (n > 0x00ffffffffffffffULL) { buf[0] = (n >> 56) & 0xff; buf[1] = (n >> 40) & 0xff; buf[2] = (n >> 32) & 0xff; buf[3] = (n >> 24) & 0xff; buf[4] = (n >> 16) & 0xff; buf[5] = (n >> 8) & 0xff; buf[6] = n & 0xff; buf[7] = 8; return 9; } else if (n > 0x0000ffffffffffffULL) { buf[0] = (n >> 56) & 0xff; buf[1] = (n >> 40) & 0xff; buf[2] = (n >> 32) & 0xff; buf[3] = (n >> 24) & 0xff; buf[4] = (n >> 16) & 0xff; buf[5] = (n >> 8) & 0xff; buf[6] = n & 0xff; buf[7] = 7; return 8; } else if (n > 0x000000ffffffffffULL) { buf[0] = (n >> 40) & 0xff; buf[1] = (n >> 32) & 0xff; buf[2] = (n >> 24) & 0xff; buf[3] = (n >> 16) & 0xff; buf[4] = (n >> 8) & 0xff; buf[5] = n & 0xff; buf[6] = 6; return 7; } else if (n > 0x00000000ffffffffULL) { buf[0] = (n >> 32) & 0xff; buf[1] = (n >> 24) & 0xff; buf[2] = (n >> 16) & 0xff; buf[3] = (n >> 8) & 0xff; buf[4] = n & 0xff; buf[5] = 5; return 6; } else if (n > 0x0000000000ffffffULL) { buf[0] = (n >> 24) & 0xff; buf[1] = (n >> 16) & 0xff; buf[2] = (n >> 8) & 0xff; buf[3] = n & 0xff; buf[4] = 4; return 5; } else if (n > 0x000000000000ffffULL) { buf[0] = (n >> 16) & 0xff; buf[1] = (n >> 8) & 0xff; buf[2] = n & 0xff; buf[3] = 3; return 4; } else if (n > 0x00000000000000ffULL) { buf[0] = (n >> 8) & 0xff; buf[1] = n & 0xff; buf[2] = 2; return 3; } else { buf[0] = n & 0xff; buf[1] = 1; return 2; } } // kangarootwelve length encoding. // (similar to right_encode(), but slightly different) static inline size_t k12_length_encode(uint8_t buf[static 9], const uint64_t n) { if (n > 0x00ffffffffffffffULL) { buf[0] = (n >> 56) & 0xff; buf[1] = (n >> 40) & 0xff; buf[2] = (n >> 32) & 0xff; buf[3] = (n >> 24) & 0xff; buf[4] = (n >> 16) & 0xff; buf[5] = (n >> 8) & 0xff; buf[6] = n & 0xff; buf[7] = 8; return 9; } else if (n > 0x0000ffffffffffffULL) { buf[0] = (n >> 56) & 0xff; buf[1] = (n >> 40) & 0xff; buf[2] = (n >> 32) & 0xff; buf[3] = (n >> 24) & 0xff; buf[4] = (n >> 16) & 0xff; buf[5] = (n >> 8) & 0xff; buf[6] = n & 0xff; buf[7] = 7; return 8; } else if (n > 0x000000ffffffffffULL) { buf[0] = (n >> 40) & 0xff; buf[1] = (n >> 32) & 0xff; buf[2] = (n >> 24) & 0xff; buf[3] = (n >> 16) & 0xff; buf[4] = (n >> 8) & 0xff; buf[5] = n & 0xff; buf[6] = 6; return 7; } else if (n > 0x00000000ffffffffULL) { buf[0] = (n >> 32) & 0xff; buf[1] = (n >> 24) & 0xff; buf[2] = (n >> 16) & 0xff; buf[3] = (n >> 8) & 0xff; buf[4] = n & 0xff; buf[5] = 5; return 6; } else if (n > 0x0000000000ffffffULL) { buf[0] = (n >> 24) & 0xff; buf[1] = (n >> 16) & 0xff; buf[2] = (n >> 8) & 0xff; buf[3] = n & 0xff; buf[4] = 4; return 5; } else if (n > 0x000000000000ffffULL) { buf[0] = (n >> 16) & 0xff; buf[1] = (n >> 8) & 0xff; buf[2] = n & 0xff; buf[3] = 3; return 4; } else if (n > 0x00000000000000ffULL) { buf[0] = (n >> 8) & 0xff; buf[1] = n & 0xff; buf[2] = 2; return 3; } else if (n > 0) { buf[0] = n & 0xff; buf[1] = 1; return 2; } else { buf[0] = 0; return 1; } } // Write prefix for encode_string() to the given buffer. Accepts the // length of the string, in bytes. // // Returns the length of the prefix, in bytes. static inline size_t encode_string_prefix(uint8_t buf[static 9], const size_t num_bytes) { return left_encode(buf, (uint64_t) num_bytes << 3); } typedef struct { uint8_t prefix[9]; // bytepad prefix size_t prefix_len; // length of bytepad prefix, in bytes size_t pad_len; // number of padding bytes after prefix and data } bytepad_t; // write bytepad() prefix to buffer, then return structure containing // the length of the prefix, in bytes, and the total number of static inline bytepad_t bytepad(const size_t data_len, const size_t width) { bytepad_t r = { { 0 }, 0, 0 }; const size_t prefix_len = left_encode(r.prefix, width); const size_t total_len = prefix_len + data_len; const size_t padded_len = (total_len / width + ((total_len % width) ? 1 : 0)) * width; r.prefix_len = prefix_len; r.pad_len = padded_len - total_len; return r; } #define CSHAKE128_XOF_RATE (200 - 2 * 16) #define CSHAKE128_XOF_PAD 0x04 _Bool cshake128_xof_absorb(sha3_xof_t * const xof, const uint8_t * const msg, const size_t len) { return xof_absorb(xof, CSHAKE128_XOF_RATE, SHA3_NUM_ROUNDS, msg, len); } void cshake128_xof_squeeze(sha3_xof_t * const xof, uint8_t * const dst, const size_t len) { xof_squeeze(xof, CSHAKE128_XOF_RATE, SHA3_NUM_ROUNDS, CSHAKE128_XOF_PAD, dst, len); } void cshake128_xof_init(sha3_xof_t * const xof, const cshake_params_t params) { static const uint8_t PAD[CSHAKE128_XOF_RATE] = { 0 }; if (!params.name_len && !params.custom_len) { // cshake w/o nist prefix and domain is shake shake128_init(xof); // FIXME: padding will be wrong on subsequent cshake128_xof_absorb() // calls return; } // build nist function name prefix uint8_t name_buf[9] = { 0 }; const size_t name_len = encode_string_prefix(name_buf, params.name_len); // build custom string prefix uint8_t custom_buf[9] = { 0 }; const size_t custom_len = encode_string_prefix(custom_buf, params.custom_len); const size_t raw_len = name_len + params.name_len + custom_len + params.custom_len; // build bytepad prefix const bytepad_t bp = bytepad(raw_len, CSHAKE128_XOF_RATE); // init xof xof_init(xof); // absorb bytepad prefix (void) cshake128_xof_absorb(xof, bp.prefix, bp.prefix_len); // absorb name string (void) cshake128_xof_absorb(xof, name_buf, name_len); if (params.name_len > 0) { (void) cshake128_xof_absorb(xof, params.name, params.name_len); } // absorb custom string (void) cshake128_xof_absorb(xof, custom_buf, custom_len); if (params.custom_len > 0) { (void) cshake128_xof_absorb(xof, params.custom, params.custom_len); } // absorb padding for (size_t ofs = 0; ofs < bp.pad_len; ofs += sizeof(PAD)) { const size_t len = MIN(bp.pad_len - ofs, sizeof(PAD)); (void) cshake128_xof_absorb(xof, PAD, len); } } void cshake128( const cshake_params_t params, const uint8_t * const msg, const size_t msg_len, uint8_t * const dst, const size_t dst_len ) { if (!params.name_len && !params.custom_len) { // cshake w/o nist prefix and domain is shake shake128(msg, msg_len, dst, dst_len); return; } // init sha3_xof_t xof; cshake128_xof_init(&xof, params); // absorb (void) cshake128_xof_absorb(&xof, msg, msg_len); // squeeze cshake128_xof_squeeze(&xof, dst, dst_len); } #define CSHAKE256_XOF_RATE (200 - 2 * 32) #define CSHAKE256_XOF_PAD 0x04 _Bool cshake256_xof_absorb(sha3_xof_t * const xof, const uint8_t * const msg, const size_t len) { return xof_absorb(xof, CSHAKE256_XOF_RATE, SHA3_NUM_ROUNDS, msg, len); } void cshake256_xof_squeeze(sha3_xof_t * const xof, uint8_t * const dst, const size_t len) { xof_squeeze(xof, CSHAKE256_XOF_RATE, SHA3_NUM_ROUNDS, CSHAKE256_XOF_PAD, dst, len); } void cshake256_xof_init(sha3_xof_t * const xof, const cshake_params_t params) { static const uint8_t PAD[CSHAKE256_XOF_RATE] = { 0 }; if (!params.name_len && !params.custom_len) { // cshake w/o nist prefix and domain is shake shake256_init(xof); // FIXME: padding will be wrong on subsequent cshake256_xof_absorb() // calls return; } // build nist function name prefix uint8_t name_buf[9] = { 0 }; const size_t name_len = encode_string_prefix(name_buf, params.name_len); // build custom string prefix uint8_t custom_buf[9] = { 0 }; const size_t custom_len = encode_string_prefix(custom_buf, params.custom_len); const size_t raw_len = name_len + params.name_len + custom_len + params.custom_len; // build bytepad prefix const bytepad_t bp = bytepad(raw_len, CSHAKE256_XOF_RATE); // init xof xof_init(xof); // absorb bytepad prefix (void) cshake256_xof_absorb(xof, bp.prefix, bp.prefix_len); // absorb name string (void) cshake256_xof_absorb(xof, name_buf, name_len); if (params.name_len > 0) { (void) cshake256_xof_absorb(xof, params.name, params.name_len); } // absorb custom string (void) cshake256_xof_absorb(xof, custom_buf, custom_len); if (params.custom_len > 0) { (void) cshake256_xof_absorb(xof, params.custom, params.custom_len); } // absorb padding for (size_t ofs = 0; ofs < bp.pad_len; ofs += sizeof(PAD)) { const size_t len = MIN(bp.pad_len - ofs, sizeof(PAD)); (void) cshake256_xof_absorb(xof, PAD, len); } } void cshake256( const cshake_params_t params, const uint8_t * const msg, const size_t msg_len, uint8_t * const dst, const size_t dst_len ) { if (!params.name_len && !params.custom_len) { // cshake w/o nist prefix and domain is shake shake256(msg, msg_len, dst, dst_len); return; } // init sha3_xof_t xof; cshake256_xof_init(&xof, params); // absorb (void) cshake256_xof_absorb(&xof, msg, msg_len); // squeeze cshake256_xof_squeeze(&xof, dst, dst_len); } void kmac128( const kmac_params_t params, const uint8_t * const msg, const size_t msg_len, uint8_t * const dst, const size_t dst_len ) { static const uint8_t PAD[CSHAKE128_XOF_RATE] = { 0 }; static const uint8_t NAME[4] = { 'K', 'M', 'A', 'C' }; // build cshake128 params const cshake_params_t cshake_params = { .name = NAME, .name_len = sizeof(NAME), .custom = params.custom, .custom_len = params.custom_len, }; // build key prefix uint8_t key_buf[9] = { 0 }; const size_t key_buf_len = encode_string_prefix(key_buf, params.key_len); // build bytepad prefix const bytepad_t bp = bytepad(key_buf_len + params.key_len, CSHAKE128_XOF_RATE); // init xof sha3_xof_t xof; cshake128_xof_init(&xof, cshake_params); // absorb bytepad prefix (void) cshake128_xof_absorb(&xof, bp.prefix, bp.prefix_len); // absorb key (void) cshake128_xof_absorb(&xof, key_buf, key_buf_len); if (params.key_len > 0) { (void) cshake128_xof_absorb(&xof, params.key, params.key_len); } // absorb padding for (size_t ofs = 0; ofs < bp.pad_len; ofs += sizeof(PAD)) { const size_t len = MIN(bp.pad_len - ofs, sizeof(PAD)); (void) cshake128_xof_absorb(&xof, PAD, len); } // absorb message (void) cshake128_xof_absorb(&xof, msg, msg_len); // build output length suffix uint8_t suffix_buf[9] = { 0 }; const size_t suffix_buf_len = right_encode(suffix_buf, dst_len << 3); // absorb output length suffix (void) cshake128_xof_absorb(&xof, suffix_buf, suffix_buf_len); // squeeze cshake128_xof_squeeze(&xof, dst, dst_len); } void kmac256( const kmac_params_t params, const uint8_t * const msg, const size_t msg_len, uint8_t * const dst, const size_t dst_len ) { static const uint8_t PAD[CSHAKE256_XOF_RATE] = { 0 }; static const uint8_t NAME[4] = { 'K', 'M', 'A', 'C' }; // build cshake256 params const cshake_params_t cshake_params = { .name = NAME, .name_len = sizeof(NAME), .custom = params.custom, .custom_len = params.custom_len, }; // build key prefix uint8_t key_buf[9] = { 0 }; const size_t key_buf_len = encode_string_prefix(key_buf, params.key_len); // build bytepad prefix const bytepad_t bp = bytepad(key_buf_len + params.key_len, CSHAKE256_XOF_RATE); // init xof sha3_xof_t xof; cshake256_xof_init(&xof, cshake_params); // absorb bytepad prefix (void) cshake256_xof_absorb(&xof, bp.prefix, bp.prefix_len); // absorb key (void) cshake256_xof_absorb(&xof, key_buf, key_buf_len); if (params.key_len > 0) { (void) cshake256_xof_absorb(&xof, params.key, params.key_len); } // absorb padding for (size_t ofs = 0; ofs < bp.pad_len; ofs += sizeof(PAD)) { const size_t len = MIN(bp.pad_len - ofs, sizeof(PAD)); (void) cshake256_xof_absorb(&xof, PAD, len); } // absorb message (void) cshake256_xof_absorb(&xof, msg, msg_len); // build output length suffix uint8_t suffix_buf[9] = { 0 }; const size_t suffix_buf_len = right_encode(suffix_buf, dst_len << 3); // absorb output length suffix (void) cshake256_xof_absorb(&xof, suffix_buf, suffix_buf_len); // squeeze cshake256_xof_squeeze(&xof, dst, dst_len); } _Bool kmac128_xof_absorb(sha3_xof_t * const xof, const uint8_t * const msg, const size_t len) { return cshake128_xof_absorb(xof, msg, len); } void kmac128_xof_squeeze(sha3_xof_t * const xof, uint8_t * const dst, const size_t len) { if (!xof->squeezing) { // append XOF length suffix const uint8_t SUFFIX[] = { 0, 1 }; (void) cshake128_xof_absorb(xof, SUFFIX, sizeof(SUFFIX)); } cshake128_xof_squeeze(xof, dst, len); } void kmac128_xof_init(sha3_xof_t * const xof, const kmac_params_t params) { static const uint8_t PAD[CSHAKE128_XOF_RATE] = { 0 }; static const uint8_t NAME[4] = { 'K', 'M', 'A', 'C' }; // build cshake128 params const cshake_params_t cshake_params = { .name = NAME, .name_len = sizeof(NAME), .custom = params.custom, .custom_len = params.custom_len, }; // build key prefix uint8_t key_buf[9] = { 0 }; const size_t key_buf_len = encode_string_prefix(key_buf, params.key_len); // build bytepad prefix const bytepad_t bp = bytepad(key_buf_len + params.key_len, CSHAKE128_XOF_RATE); // init xof cshake128_xof_init(xof, cshake_params); // absorb bytepad prefix (void) cshake128_xof_absorb(xof, bp.prefix, bp.prefix_len); // absorb key (void) cshake128_xof_absorb(xof, key_buf, key_buf_len); if (params.key_len > 0) { (void) cshake128_xof_absorb(xof, params.key, params.key_len); } // absorb padding for (size_t ofs = 0; ofs < bp.pad_len; ofs += sizeof(PAD)) { const size_t len = MIN(bp.pad_len - ofs, sizeof(PAD)); (void) cshake128_xof_absorb(xof, PAD, len); } } void kmac128_xof_once(const kmac_params_t params, const uint8_t * const src, const size_t src_len, uint8_t * const dst, const size_t dst_len) { sha3_xof_t xof; kmac128_xof_init(&xof, params); kmac128_xof_absorb(&xof, src, src_len); kmac128_xof_squeeze(&xof, dst, dst_len); } _Bool kmac256_xof_absorb(sha3_xof_t * const xof, const uint8_t * const msg, const size_t len) { return cshake256_xof_absorb(xof, msg, len); } void kmac256_xof_squeeze(sha3_xof_t * const xof, uint8_t * const dst, const size_t len) { if (!xof->squeezing) { // append XOF length suffix const uint8_t SUFFIX[] = { 0, 1 }; (void) cshake256_xof_absorb(xof, SUFFIX, sizeof(SUFFIX)); } cshake256_xof_squeeze(xof, dst, len); } void kmac256_xof_init(sha3_xof_t * const xof, const kmac_params_t params) { static const uint8_t PAD[CSHAKE256_XOF_RATE] = { 0 }; static const uint8_t NAME[4] = { 'K', 'M', 'A', 'C' }; // build cshake256 params const cshake_params_t cshake_params = { .name = NAME, .name_len = sizeof(NAME), .custom = params.custom, .custom_len = params.custom_len, }; // build key prefix uint8_t key_buf[9] = { 0 }; const size_t key_buf_len = encode_string_prefix(key_buf, params.key_len); // build bytepad prefix const bytepad_t bp = bytepad(key_buf_len + params.key_len, CSHAKE256_XOF_RATE); // init xof cshake256_xof_init(xof, cshake_params); // absorb bytepad prefix (void) cshake256_xof_absorb(xof, bp.prefix, bp.prefix_len); // absorb key (void) cshake256_xof_absorb(xof, key_buf, key_buf_len); if (params.key_len > 0) { (void) cshake256_xof_absorb(xof, params.key, params.key_len); } // absorb padding for (size_t ofs = 0; ofs < bp.pad_len; ofs += sizeof(PAD)) { const size_t len = MIN(bp.pad_len - ofs, sizeof(PAD)); (void) cshake256_xof_absorb(xof, PAD, len); } } void kmac256_xof_once(const kmac_params_t params, const uint8_t * const src, const size_t src_len, uint8_t * const dst, const size_t dst_len) { sha3_xof_t xof; kmac256_xof_init(&xof, params); kmac256_xof_absorb(&xof, src, src_len); kmac256_xof_squeeze(&xof, dst, dst_len); } static inline void tuplehash128_init(sha3_xof_t * const xof, const tuplehash_params_t params, const size_t dst_len) { static const uint8_t NAME[] = { 'T', 'u', 'p', 'l', 'e', 'H', 'a', 's', 'h' }; // build cshake128 params const cshake_params_t cshake_params = { .name = NAME, .name_len = sizeof(NAME), .custom = params.custom, .custom_len = params.custom_len, }; // init xof cshake128_xof_init(xof, cshake_params); // absorb tuples // FIXME: length counter in 800-185 is wrong here for (size_t i = 0; i < params.num_strs; i++) { // absorb length uint8_t buf[9] = { 0 }; const size_t buf_len = encode_string_prefix(buf, params.strs[i].len); (void) cshake128_xof_absorb(xof, buf, buf_len); // absorb content if (params.strs[i].len > 0) { (void) cshake128_xof_absorb(xof, params.strs[i].ptr, params.strs[i].len); } } // build output length suffix uint8_t suffix_buf[9] = { 0 }; const size_t suffix_buf_len = right_encode(suffix_buf, dst_len << 3); // absorb output length suffix (void) cshake128_xof_absorb(xof, suffix_buf, suffix_buf_len); } void tuplehash128(const tuplehash_params_t params, uint8_t * const dst, const size_t dst_len) { // init sha3_xof_t xof; tuplehash128_init(&xof, params, dst_len); // squeeze cshake128_xof_squeeze(&xof, dst, dst_len); } void tuplehash128_xof_init(sha3_xof_t * const xof, const tuplehash_params_t params) { tuplehash128_init(xof, params, 0); } void tuplehash128_xof_squeeze(sha3_xof_t * const xof, uint8_t * const dst, const size_t dst_len) { cshake128_xof_squeeze(xof, dst, dst_len); } void tuplehash128_xof_once(const tuplehash_params_t params, uint8_t * const dst, const size_t dst_len) { // init xof sha3_xof_t xof; tuplehash128_xof_init(&xof, params); // squeeze cshake128_xof_squeeze(&xof, dst, dst_len); } static inline void tuplehash256_init(sha3_xof_t * const xof, const tuplehash_params_t params, const size_t dst_len) { static const uint8_t NAME[] = { 'T', 'u', 'p', 'l', 'e', 'H', 'a', 's', 'h' }; // build cshake256 params const cshake_params_t cshake_params = { .name = NAME, .name_len = sizeof(NAME), .custom = params.custom, .custom_len = params.custom_len, }; // init xof cshake256_xof_init(xof, cshake_params); // absorb tuples // FIXME: length counter in 800-185 is wrong here for (size_t i = 0; i < params.num_strs; i++) { // absorb length uint8_t buf[9] = { 0 }; const size_t buf_len = encode_string_prefix(buf, params.strs[i].len); (void) cshake256_xof_absorb(xof, buf, buf_len); // absorb content if (params.strs[i].len > 0) { (void) cshake256_xof_absorb(xof, params.strs[i].ptr, params.strs[i].len); } } // build output length suffix uint8_t suffix_buf[9] = { 0 }; const size_t suffix_buf_len = right_encode(suffix_buf, dst_len << 3); // absorb output length suffix (void) cshake256_xof_absorb(xof, suffix_buf, suffix_buf_len); } void tuplehash256(const tuplehash_params_t params, uint8_t * const dst, const size_t dst_len) { // init sha3_xof_t xof; tuplehash256_init(&xof, params, dst_len); // squeeze cshake256_xof_squeeze(&xof, dst, dst_len); } void tuplehash256_xof_init(sha3_xof_t * const xof, const tuplehash_params_t params) { tuplehash256_init(xof, params, 0); } void tuplehash256_xof_squeeze(sha3_xof_t * const xof, uint8_t * const dst, const size_t dst_len) { cshake256_xof_squeeze(xof, dst, dst_len); } void tuplehash256_xof_once(const tuplehash_params_t params, uint8_t * const dst, const size_t dst_len) { // init xof sha3_xof_t xof; tuplehash256_xof_init(&xof, params); // squeeze cshake256_xof_squeeze(&xof, dst, dst_len); } static void parallelhash128_emit_block(parallelhash_t * const hash) { // squeeze curr xof, absorb into root xof uint8_t buf[32]; shake128_squeeze(&(hash->curr_xof), buf, sizeof(buf)); (void) cshake128_xof_absorb(&(hash->root_xof), buf, sizeof(buf)); // increment block count hash->num_blocks++; } static inline void parallelhash128_reset_curr_xof(parallelhash_t *hash) { // init curr xof shake128_init(&(hash->curr_xof)); hash->ofs = 0; } static inline void parallelhash128_init(parallelhash_t *hash, const parallelhash_params_t params) { static const uint8_t NAME[] = { 'P', 'a', 'r', 'a', 'l', 'l', 'e', 'l', 'H', 'a', 's', 'h' }; // build root xof cshake128 params const cshake_params_t root_cshake_params = { .name = NAME, .name_len = sizeof(NAME), .custom = params.custom, .custom_len = params.custom_len, }; // init root xof cshake128_xof_init(&(hash->root_xof), root_cshake_params); // build block size uint8_t buf[9] = { 0 }; const size_t buf_len = left_encode(buf, params.block_len); // absorb block length into root xof (void) cshake128_xof_absorb(&(hash->root_xof), buf, buf_len); // set parameters hash->block_len = params.block_len; hash->num_blocks = 0; hash->squeezing = false; // init curr xof parallelhash128_reset_curr_xof(hash); } static inline void parallelhash128_absorb(parallelhash_t * const hash, const uint8_t *msg, size_t msg_len) { while (msg_len > 0) { const size_t len = MIN(msg_len, hash->block_len - hash->ofs); (void) shake128_absorb(&(hash->curr_xof), msg, len); msg += len; msg_len -= len; hash->ofs += len; if (hash->ofs == hash->block_len) { // emit block, reset curr xof parallelhash128_emit_block(hash); parallelhash128_reset_curr_xof(hash); } } } static inline void parallelhash128_squeeze(parallelhash_t * const hash, uint8_t * const dst, const size_t dst_len) { if (!hash->squeezing) { // mark as squeezing hash->squeezing = true; if (hash->ofs > 0) { // squeeze curr xof, absorb into root xof parallelhash128_emit_block(hash); } { // build num blocks suffix uint8_t buf[9] = { 0 }; const size_t len = right_encode(buf, hash->num_blocks); // absorb num blocks suffix into root xof (void) cshake128_xof_absorb(&(hash->root_xof), buf, len); } { // build output size suffix uint8_t buf[9] = { 0 }; const size_t len = right_encode(buf, dst_len << 3); // absorb output size suffix into root xof (void) cshake128_xof_absorb(&(hash->root_xof), buf, len); } } if (dst_len > 0) { cshake128_xof_squeeze(&(hash->root_xof), dst, dst_len); } } void parallelhash128(const parallelhash_params_t params, const uint8_t * const src, const size_t src_len, uint8_t * const dst, const size_t dst_len) { // init parallelhash_t hash; parallelhash128_init(&hash, params); // absorb parallelhash128_absorb(&hash, src, src_len); // squeeze parallelhash128_squeeze(&hash, dst, dst_len); } void parallelhash128_xof_init(parallelhash_t *hash, const parallelhash_params_t params) { parallelhash128_init(hash, params); } void parallelhash128_xof_absorb(parallelhash_t *hash, const uint8_t *msg, const size_t msg_len) { parallelhash128_absorb(hash, msg, msg_len); } void parallelhash128_xof_squeeze(parallelhash_t *hash, uint8_t *dst, const size_t dst_len) { if (!hash->squeezing) { // emit zero length parallelhash128_squeeze(hash, dst, 0); } parallelhash128_squeeze(hash, dst, dst_len); } void parallelhash128_xof_once(const parallelhash_params_t params, const uint8_t * const src, const size_t src_len, uint8_t * const dst, const size_t dst_len) { // init parallelhash_t hash; parallelhash128_xof_init(&hash, params); // absorb parallelhash128_xof_absorb(&hash, src, src_len); // squeeze parallelhash128_xof_squeeze(&hash, dst, dst_len); } static void parallelhash256_emit_block(parallelhash_t * const hash) { // squeeze curr xof, absorb into root xof uint8_t buf[64]; shake256_squeeze(&(hash->curr_xof), buf, sizeof(buf)); (void) cshake256_xof_absorb(&(hash->root_xof), buf, sizeof(buf)); // increment block count hash->num_blocks++; } static inline void parallelhash256_reset_curr_xof(parallelhash_t *hash) { // init curr xof shake256_init(&(hash->curr_xof)); hash->ofs = 0; } static inline void parallelhash256_init(parallelhash_t *hash, const parallelhash_params_t params) { static const uint8_t NAME[] = { 'P', 'a', 'r', 'a', 'l', 'l', 'e', 'l', 'H', 'a', 's', 'h' }; // build root xof cshake256 params const cshake_params_t root_cshake_params = { .name = NAME, .name_len = sizeof(NAME), .custom = params.custom, .custom_len = params.custom_len, }; // init root xof cshake256_xof_init(&(hash->root_xof), root_cshake_params); // build block size uint8_t buf[9] = { 0 }; const size_t buf_len = left_encode(buf, params.block_len); // absorb block length into root xof (void) cshake256_xof_absorb(&(hash->root_xof), buf, buf_len); // set parameters hash->block_len = params.block_len; hash->num_blocks = 0; hash->squeezing = false; // init curr xof parallelhash256_reset_curr_xof(hash); } static inline void parallelhash256_absorb(parallelhash_t * const hash, const uint8_t *msg, size_t msg_len) { while (msg_len > 0) { const size_t len = MIN(msg_len, hash->block_len - hash->ofs); (void) shake256_absorb(&(hash->curr_xof), msg, len); msg += len; msg_len -= len; hash->ofs += len; if (hash->ofs == hash->block_len) { // emit block, reset curr xof parallelhash256_emit_block(hash); parallelhash256_reset_curr_xof(hash); } } } static inline void parallelhash256_squeeze(parallelhash_t * const hash, uint8_t * const dst, const size_t dst_len) { if (!hash->squeezing) { // mark as squeezing hash->squeezing = true; if (hash->ofs > 0) { // squeeze curr xof, absorb into root xof parallelhash256_emit_block(hash); } { // build num blocks suffix uint8_t buf[9] = { 0 }; const size_t len = right_encode(buf, hash->num_blocks); // absorb num blocks suffix into root xof (void) cshake256_xof_absorb(&(hash->root_xof), buf, len); } { // build output size suffix uint8_t buf[9] = { 0 }; const size_t len = right_encode(buf, dst_len << 3); // absorb output size suffix into root xof (void) cshake256_xof_absorb(&(hash->root_xof), buf, len); } } if (dst_len > 0) { cshake256_xof_squeeze(&(hash->root_xof), dst, dst_len); } } void parallelhash256(const parallelhash_params_t params, const uint8_t * const src, const size_t src_len, uint8_t * const dst, const size_t dst_len) { // init parallelhash_t hash; parallelhash256_init(&hash, params); // absorb parallelhash256_absorb(&hash, src, src_len); // squeeze parallelhash256_squeeze(&hash, dst, dst_len); } void parallelhash256_xof_init(parallelhash_t *hash, const parallelhash_params_t params) { parallelhash256_init(hash, params); } void parallelhash256_xof_absorb(parallelhash_t *hash, const uint8_t *msg, const size_t msg_len) { parallelhash256_absorb(hash, msg, msg_len); } void parallelhash256_xof_squeeze(parallelhash_t *hash, uint8_t *dst, const size_t dst_len) { if (!hash->squeezing) { // emit zero length parallelhash256_squeeze(hash, dst, 0); } parallelhash256_squeeze(hash, dst, dst_len); } void parallelhash256_xof_once(const parallelhash_params_t params, const uint8_t * const src, const size_t src_len, uint8_t * const dst, const size_t dst_len) { // init parallelhash_t hash; parallelhash256_xof_init(&hash, params); // absorb parallelhash256_xof_absorb(&hash, src, src_len); // squeeze parallelhash256_xof_squeeze(&hash, dst, dst_len); } // number of rounds #define TURBOSHAKE_NUM_ROUNDS 12 // default turboshake pad byte (can be customized for domain separation) #define TURBOSHAKE_PAD 0x1f // init turboshake context with given pad byte. returns false if the // pad byte is out of range. static inline _Bool turboshake_init(turboshake_t * const ts, const uint8_t pad) { // check for valid pad if (!pad || pad > 0x1f) { // invalid pad return false; } // init xof xof_init(&(ts->xof)); ts->pad = pad; // return success return true; } // init turboeshake128 context with custom pad byte. returns false if the // pad byte is out of range. _Bool turboshake128_init_custom(turboshake_t * const ts, const uint8_t pad) { return turboshake_init(ts, pad); } // init turboeshake128 context. void turboshake128_init(turboshake_t * const ts) { (void) turboshake_init(ts, TURBOSHAKE_PAD); } // absorb bytes into turboshake128 context. _Bool turboshake128_absorb(turboshake_t * const ts, const uint8_t * const m, const size_t len) { return xof_absorb(&(ts->xof), SHAKE128_RATE, TURBOSHAKE_NUM_ROUNDS, m, len); } void turboshake128_squeeze(turboshake_t * const ts, uint8_t * const dst, const size_t dst_len) { xof_squeeze(&(ts->xof), SHAKE128_RATE, TURBOSHAKE_NUM_ROUNDS, ts->pad, dst, dst_len); } void turboshake128(const uint8_t * const src, const size_t src_len, uint8_t * const dst, const size_t dst_len) { xof_once(SHAKE128_RATE, TURBOSHAKE_NUM_ROUNDS, TURBOSHAKE_PAD, src, src_len, dst, dst_len); } void turboshake128_custom(const uint8_t pad, const uint8_t * const src, const size_t src_len, uint8_t * const dst, const size_t dst_len) { xof_once(SHAKE128_RATE, TURBOSHAKE_NUM_ROUNDS, pad, src, src_len, dst, dst_len); } _Bool turboshake256_init_custom(turboshake_t * const ts, const uint8_t pad) { return turboshake_init(ts, pad); } void turboshake256_init(turboshake_t * const ts) { (void) turboshake_init(ts, TURBOSHAKE_PAD); } _Bool turboshake256_absorb(turboshake_t * const ts, const uint8_t * const m, const size_t len) { return xof_absorb(&(ts->xof), SHAKE256_RATE, TURBOSHAKE_NUM_ROUNDS, m, len); } void turboshake256_squeeze(turboshake_t * const ts, uint8_t * const dst, const size_t dst_len) { xof_squeeze(&(ts->xof), SHAKE256_RATE, TURBOSHAKE_NUM_ROUNDS, ts->pad, dst, dst_len); } void turboshake256(const uint8_t * const src, const size_t src_len, uint8_t * const dst, const size_t dst_len) { xof_once(SHAKE256_RATE, TURBOSHAKE_NUM_ROUNDS, TURBOSHAKE_PAD, src, src_len, dst, dst_len); } void turboshake256_custom(const uint8_t pad, const uint8_t * const src, const size_t src_len, uint8_t * const dst, const size_t dst_len) { xof_once(SHAKE256_RATE, TURBOSHAKE_NUM_ROUNDS, pad, src, src_len, dst, dst_len); } // kangarootwelve block size, in bytes #define K12_BLOCK_LEN 8192 // pad byte for single kangarootwelve chunk (<= 8192 bytes) #define K12_PAD_SINGLE 0x07 // pad byte for root kangarootwelve turboshake instance (> 8192 bytes) #define K12_PAD_ROOT 0x06 // pad byte for child kangarootwelve turboshake instances (> 8192 bytes) #define K12_PAD_CHILD 0x0B // private kangarootwelve big context typedef struct { turboshake_t *root, // root turboshake context curr; // current child turboshake context size_t num_bytes, // num bytes in current block num_blocks; // total number of blocks } k12_big_t; // init kangarootwelve big context static void k12_big_init(k12_big_t * const big, turboshake_t * const root) { // init root context turboshake128_init_custom(root, K12_PAD_ROOT); big->root = root; big->num_bytes = 0; big->num_blocks = 0; } // absorb data in child context static void k12_big_child_absorb(k12_big_t * const big, const uint8_t *src, size_t src_len) { while (src_len > 0) { const size_t len = MIN(K12_BLOCK_LEN - big->num_bytes, src_len); // absorb into child context turboshake128_absorb(&(big->curr), src, len); src += len; src_len -= len; big->num_bytes += len; if (big->num_bytes == K12_BLOCK_LEN) { // hash child uint8_t buf[32] = { 0 }; turboshake128_squeeze(&(big->curr), buf, sizeof(buf)); // absorb hash into root turboshake128_absorb(big->root, buf, sizeof(buf)); // reset child turboshake128_init_custom(&(big->curr), K12_PAD_CHILD); // clear byte count, increment block count big->num_bytes = 0; big->num_blocks++; } } } // absorb data in root context // (passes excess data to child context) static void k12_big_root_absorb(k12_big_t * const big, const uint8_t *src, size_t src_len) { while (src_len > 0) { const size_t len = MIN(K12_BLOCK_LEN - big->num_bytes, src_len); // absorb into root context turboshake128_absorb(big->root, src, len); src += len; src_len -= len; big->num_bytes += len; if (big->num_bytes == K12_BLOCK_LEN) { // absorb trailer for first block uint8_t buf[8] = { 3, 0, 0, 0, 0, 0, 0, 0 }; turboshake128_absorb(big->root, buf, sizeof(buf)); // init child turboshake128_init_custom(&(big->curr), K12_PAD_CHILD); // clear byte count, increment block count big->num_bytes = 0; big->num_blocks++; // absorb rest of source in child k12_big_child_absorb(big, src, src_len); return; } } } // absorb data static void k12_big_absorb(k12_big_t * const big, const uint8_t *src, size_t src_len) { if (big->num_blocks) { // absorb successive blocks in child context k12_big_child_absorb(big, src, src_len); } else { // absorb first block in root context k12_big_root_absorb(big, src, src_len); } } // finalize "big" kangarootwelve context static void k12_big_absorb_done(k12_big_t * const big) { if (big->num_bytes > 0) { // hash child, absorb into root uint8_t buf[32] = { 0 }; turboshake128_squeeze(&(big->curr), buf, sizeof(buf)); turboshake128_absorb(big->root, buf, sizeof(buf)); } // absorb block count uint8_t buf[9] = { 0 }; const size_t buf_len = k12_length_encode(buf, big->num_blocks); turboshake128_absorb(big->root, buf, buf_len); // absorb tail static const uint8_t tail[2] = { 0xff, 0xff }; turboshake128_absorb(big->root, tail, sizeof(tail)); } // squeeze into destination void k12_squeeze(k12_t *k12, uint8_t *dst, const size_t dst_len) { turboshake128_squeeze(&(k12->ts), dst, dst_len); } void k12_init(k12_t *k12, const uint8_t *src, const size_t src_len, const uint8_t *custom, const size_t custom_len) { uint8_t cl_buf[9] = { 0 }; const size_t cl_buf_len = k12_length_encode(cl_buf, custom_len); // get total size, in bytes const size_t total_len = src_len + custom_len + cl_buf_len; if (total_len <= K12_BLOCK_LEN) { // total size is less than a single block, so create a single // turboshake128 instance, absorb the source data and the custom // string. // init turboshake context with single node padding turboshake128_init_custom(&(k12->ts), K12_PAD_SINGLE); // absorb source, custom string, and custom string length turboshake128_absorb(&(k12->ts), src, src_len); turboshake128_absorb(&(k12->ts), custom, custom_len); turboshake128_absorb(&(k12->ts), cl_buf, cl_buf_len); } else { // total size greater than a single block, so create an internal // "big" kangarootwelve context, absorb the source data and the custom // string into the context. // // (the internal kangarootwelve context takes care of multiplexing // the block data between the root and child contexts) // init turboshake context with root node padding turboshake128_init_custom(&(k12->ts), K12_PAD_ROOT); // init big context k12_big_t big; k12_big_init(&big, &(k12->ts)); // absorb source, custom string, and custom string length k12_big_absorb(&big, src, src_len); k12_big_absorb(&big, custom, custom_len); k12_big_absorb(&big, cl_buf, cl_buf_len); k12_big_absorb_done(&big); } } // one-shot k12 with custom string void k12_custom_once(const uint8_t *src, const size_t src_len, const uint8_t *custom, const size_t custom_len, uint8_t *dst, const size_t dst_len) { k12_t k12; k12_init(&k12, src, src_len, custom, custom_len); k12_squeeze(&k12, dst, dst_len); } // one-shot kangarootwelve w/o custom string void k12_once(const uint8_t *src, const size_t src_len, uint8_t *dst, const size_t dst_len) { k12_custom_once(src, src_len, NULL, 0, dst, dst_len); } #ifdef SHA3_TEST #include // printf() #include // malloc() (used in test_kangarootwelve()) static void dump_hex(FILE *f, const uint8_t * const a, const size_t len) { fprintf(f, " "); for (size_t i = 0; i < len; i++) { fprintf(f, "%02x ", a[i]); if ((i + 1) % 16 == 0) { fprintf(f, "\n "); } } fprintf(f, "\n"); } static void dump_state(FILE *f, const uint64_t a[static 25]) { dump_hex(f, (const uint8_t *) a, 25 * 8); } static void test_theta(void) { // src: https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/SHA3-256_Msg30.pdf uint64_t a[25] = { [0] = 0x00000001997b5853ULL, [16] = 0x8000000000000000ULL }; const uint8_t exp[] = { 0x52, 0x58, 0x7B, 0x99, 0x01, 0x00, 0x00, 0x00, 0x53, 0x58, 0x7B, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA6, 0xB0, 0xF6, 0x32, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x53, 0x58, 0x7B, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA6, 0xB0, 0xF6, 0x32, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x53, 0x58, 0x7B, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA6, 0xB0, 0xF6, 0x32, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x53, 0x58, 0x7B, 0x99, 0x01, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA6, 0xB0, 0xF6, 0x32, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x53, 0x58, 0x7B, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA6, 0xB0, 0xF6, 0x32, 0x03, 0x00, 0x00, 0x00, }; theta(a); if (memcmp(exp, a, sizeof(exp))) { fprintf(stderr, "test_theta() failed, got:\n"); dump_state(stderr, a); fprintf(stderr, "exp:\n"); dump_state(stderr, (uint64_t*) exp); } } static void test_rho(void) { uint8_t a[] = { 0x52, 0x58, 0x7B, 0x99, 0x01, 0x00, 0x00, 0x00, 0x53, 0x58, 0x7B, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA6, 0xB0, 0xF6, 0x32, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x53, 0x58, 0x7B, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA6, 0xB0, 0xF6, 0x32, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x53, 0x58, 0x7B, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA6, 0xB0, 0xF6, 0x32, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x53, 0x58, 0x7B, 0x99, 0x01, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA6, 0xB0, 0xF6, 0x32, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x53, 0x58, 0x7B, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA6, 0xB0, 0xF6, 0x32, 0x03, 0x00, 0x00, 0x00, }; const uint8_t exp[] = { 0x52, 0x58, 0x7B, 0x99, 0x01, 0x00, 0x00, 0x00, 0xA6, 0xB0, 0xF6, 0x32, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x85, 0xB5, 0x97, 0x19, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x97, 0x19, 0x00, 0x00, 0x00, 0x30, 0x85, 0xB5, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x0A, 0x6B, 0x2F, 0x33, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4C, 0x61, 0xED, 0x65, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0x01, 0x00, 0x00, 0x00, 0x53, 0x58, 0x7B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x2F, 0x33, 0x00, 0x00, 0x00, 0x70, 0x0A, 0x6B, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA6, 0xB0, 0xF6, 0x32, 0x03, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4C, 0x61, 0xED, 0x65, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x29, 0xAC, 0xBD, 0xCC, 0x00, 0x00, }; rho((uint64_t*) a); if (memcmp(exp, a, sizeof(exp))) { fprintf(stderr, "test_rho() failed, got:\n"); dump_state(stderr, (uint64_t*) a); fprintf(stderr, "exp:\n"); dump_state(stderr, (uint64_t*) exp); } } static void test_pi(void) { const uint8_t src[] = { 0x52, 0x58, 0x7B, 0x99, 0x01, 0x00, 0x00, 0x00, 0xA6, 0xB0, 0xF6, 0x32, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x85, 0xB5, 0x97, 0x19, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x97, 0x19, 0x00, 0x00, 0x00, 0x30, 0x85, 0xB5, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x0A, 0x6B, 0x2F, 0x33, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4C, 0x61, 0xED, 0x65, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0x01, 0x00, 0x00, 0x00, 0x53, 0x58, 0x7B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x2F, 0x33, 0x00, 0x00, 0x00, 0x70, 0x0A, 0x6B, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA6, 0xB0, 0xF6, 0x32, 0x03, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4C, 0x61, 0xED, 0x65, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x29, 0xAC, 0xBD, 0xCC, 0x00, 0x00, }; uint8_t got[25*8] = { 0 }; const uint8_t exp[] = { 0x52, 0x58, 0x7B, 0x99, 0x01, 0x00, 0x00, 0x00, 0x97, 0x19, 0x00, 0x00, 0x00, 0x30, 0x85, 0xB5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x29, 0xAC, 0xBD, 0xCC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x0A, 0x6B, 0x2F, 0x33, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2F, 0x33, 0x00, 0x00, 0x00, 0x70, 0x0A, 0x6B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xA6, 0xB0, 0xF6, 0x32, 0x03, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA6, 0xB0, 0xF6, 0x32, 0x03, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x85, 0xB5, 0x97, 0x19, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x4C, 0x61, 0xED, 0x65, 0x06, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0x01, 0x00, 0x00, 0x00, 0x53, 0x58, 0x7B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x4C, 0x61, 0xED, 0x65, 0x06, 0x00, 0x00, 0x00, }; pi((uint64_t*) got, (uint64_t*) src); if (memcmp(exp, got, sizeof(exp))) { fprintf(stderr, "test_pi() failed, got:\n"); dump_state(stderr, (uint64_t*) got); fprintf(stderr, "exp:\n"); dump_state(stderr, (uint64_t*) exp); } } static void test_chi(void) { const uint8_t src[] = { 0x52, 0x58, 0x7B, 0x99, 0x01, 0x00, 0x00, 0x00, 0x97, 0x19, 0x00, 0x00, 0x00, 0x30, 0x85, 0xB5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x29, 0xAC, 0xBD, 0xCC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x0A, 0x6B, 0x2F, 0x33, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2F, 0x33, 0x00, 0x00, 0x00, 0x70, 0x0A, 0x6B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xA6, 0xB0, 0xF6, 0x32, 0x03, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA6, 0xB0, 0xF6, 0x32, 0x03, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x85, 0xB5, 0x97, 0x19, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x4C, 0x61, 0xED, 0x65, 0x06, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0x01, 0x00, 0x00, 0x00, 0x53, 0x58, 0x7B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x4C, 0x61, 0xED, 0x65, 0x06, 0x00, 0x00, 0x00, }; uint8_t got[25*8] = { 0 }; const uint8_t exp[] = { 0x52, 0x58, 0x7B, 0x99, 0x01, 0x04, 0x00, 0x00, 0x97, 0x19, 0x00, 0x00, 0x00, 0x30, 0x85, 0xB5, 0x00, 0x80, 0x29, 0xAC, 0xBD, 0xC8, 0x00, 0x00, 0x52, 0x58, 0x52, 0x11, 0x00, 0x00, 0x00, 0x00, 0x85, 0x81, 0x29, 0xAC, 0xBD, 0xFC, 0x85, 0xB5, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x27, 0x33, 0x60, 0x0A, 0x6B, 0x5F, 0x39, 0x6B, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x2F, 0x33, 0x00, 0x00, 0x00, 0x70, 0x0A, 0x6B, 0x00, 0x00, 0x60, 0x0A, 0x6B, 0x2F, 0x33, 0x10, 0xA6, 0xB0, 0xF6, 0x32, 0x03, 0x00, 0x00, 0x00, 0x20, 0xA6, 0xB0, 0xF6, 0x32, 0x03, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA6, 0x16, 0x42, 0xC4, 0x31, 0x03, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4C, 0x61, 0xDD, 0xE0, 0xB3, 0x97, 0x19, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x4C, 0x61, 0xED, 0x65, 0x06, 0x00, 0x00, 0x00, 0x40, 0x00, 0x30, 0x85, 0xB5, 0x97, 0x19, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x99, 0x01, 0x00, 0x00, 0x00, 0x53, 0x58, 0x5B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD5, 0x60, 0xED, 0x65, 0x06, 0x53, 0x58, 0x7B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x20, 0x4C, 0x61, 0xED, 0x65, 0x06, 0x00, 0x00, 0x00, }; chi((uint64_t*) got, (uint64_t*) src); if (memcmp(exp, got, sizeof(exp))) { fprintf(stderr, "test_chi() failed, got:\n"); dump_state(stderr, (uint64_t*) got); fprintf(stderr, "exp:\n"); dump_state(stderr, (uint64_t*) exp); } } static void test_iota(void) { uint8_t a[] = { 0x52, 0x58, 0x7B, 0x99, 0x01, 0x04, 0x00, 0x00, 0x97, 0x19, 0x00, 0x00, 0x00, 0x30, 0x85, 0xB5, 0x00, 0x80, 0x29, 0xAC, 0xBD, 0xC8, 0x00, 0x00, 0x52, 0x58, 0x52, 0x11, 0x00, 0x00, 0x00, 0x00, 0x85, 0x81, 0x29, 0xAC, 0xBD, 0xFC, 0x85, 0xB5, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x27, 0x33, 0x60, 0x0A, 0x6B, 0x5F, 0x39, 0x6B, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x2F, 0x33, 0x00, 0x00, 0x00, 0x70, 0x0A, 0x6B, 0x00, 0x00, 0x60, 0x0A, 0x6B, 0x2F, 0x33, 0x10, 0xA6, 0xB0, 0xF6, 0x32, 0x03, 0x00, 0x00, 0x00, 0x20, 0xA6, 0xB0, 0xF6, 0x32, 0x03, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA6, 0x16, 0x42, 0xC4, 0x31, 0x03, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4C, 0x61, 0xDD, 0xE0, 0xB3, 0x97, 0x19, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x4C, 0x61, 0xED, 0x65, 0x06, 0x00, 0x00, 0x00, 0x40, 0x00, 0x30, 0x85, 0xB5, 0x97, 0x19, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x99, 0x01, 0x00, 0x00, 0x00, 0x53, 0x58, 0x5B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD5, 0x60, 0xED, 0x65, 0x06, 0x53, 0x58, 0x7B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x20, 0x4C, 0x61, 0xED, 0x65, 0x06, 0x00, 0x00, 0x00, }; const uint8_t exp[] = { 0x53, 0x58, 0x7B, 0x99, 0x01, 0x04, 0x00, 0x00, 0x97, 0x19, 0x00, 0x00, 0x00, 0x30, 0x85, 0xB5, 0x00, 0x80, 0x29, 0xAC, 0xBD, 0xC8, 0x00, 0x00, 0x52, 0x58, 0x52, 0x11, 0x00, 0x00, 0x00, 0x00, 0x85, 0x81, 0x29, 0xAC, 0xBD, 0xFC, 0x85, 0xB5, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x27, 0x33, 0x60, 0x0A, 0x6B, 0x5F, 0x39, 0x6B, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x2F, 0x33, 0x00, 0x00, 0x00, 0x70, 0x0A, 0x6B, 0x00, 0x00, 0x60, 0x0A, 0x6B, 0x2F, 0x33, 0x10, 0xA6, 0xB0, 0xF6, 0x32, 0x03, 0x00, 0x00, 0x00, 0x20, 0xA6, 0xB0, 0xF6, 0x32, 0x03, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA6, 0x16, 0x42, 0xC4, 0x31, 0x03, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4C, 0x61, 0xDD, 0xE0, 0xB3, 0x97, 0x19, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x4C, 0x61, 0xED, 0x65, 0x06, 0x00, 0x00, 0x00, 0x40, 0x00, 0x30, 0x85, 0xB5, 0x97, 0x19, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x99, 0x01, 0x00, 0x00, 0x00, 0x53, 0x58, 0x5B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD5, 0x60, 0xED, 0x65, 0x06, 0x53, 0x58, 0x7B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x20, 0x4C, 0x61, 0xED, 0x65, 0x06, 0x00, 0x00, 0x00, }; iota((uint64_t*) a, 0); if (memcmp(exp, a, sizeof(exp))) { fprintf(stderr, "test_iota() failed, got:\n"); dump_state(stderr, (uint64_t*) a); fprintf(stderr, "exp:\n"); dump_state(stderr, (uint64_t*) exp); } } static void test_permute(void) { uint64_t a[25] = { [0] = 0x00000001997b5853ULL, [16] = 0x8000000000000000ULL }; const uint64_t exp[] = { 0xE95A9E40EF2F24C8ULL, 0x24C64DAE57C8F1D1ULL, 0x8CAA629F80192BB9ULL, 0xD0B178A0541C4107ULL, }; permute(a, SHA3_NUM_ROUNDS); if (memcmp(exp, a, sizeof(exp))) { fprintf(stderr, "test_permute() failed, got:\n"); dump_hex(stderr, (uint8_t*) a, 32); fprintf(stderr, "exp:\n"); dump_hex(stderr, (uint8_t*) exp, 32); } } static void test_sha3_224(void) { static const struct { const char *name; // test name const uint8_t msg[256]; // test message const size_t len; // test message length const uint8_t exp[28]; // expected hash } tests[] = {{ .name = "empty", .msg = "", .len = 0, .exp = { 0x6b, 0x4e, 0x03, 0x42, 0x36, 0x67, 0xdb, 0xb7, 0x3b, 0x6e, 0x15, 0x45, 0x4f, 0x0e, 0xb1, 0xab, 0xd4, 0x59, 0x7f, 0x9a, 0x1b, 0x07, 0x8e, 0x3f, 0x5b, 0x5a, 0x6b, 0xc7, }, }, { .name = "asdf", .msg = "asdf", .len = 4, .exp = { 0x47, 0xcc, 0xa2, 0x03, 0xee, 0xfc, 0xa3, 0x49, 0xde, 0xaa, 0x41, 0x8d, 0xa7, 0xfe, 0x05, 0x38, 0x9e, 0xf6, 0x49, 0x98, 0x5c, 0x87, 0xa9, 0xb6, 0x55, 0xad, 0x12, 0x8c, }, }, { .name = "a-134", .msg = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", .len = 134, .exp = { 0x5d, 0x1d, 0xb4, 0xe4, 0x7c, 0x0c, 0x4a, 0x42, 0x45, 0xb9, 0x0d, 0x18, 0x55, 0xb0, 0x7c, 0xb1, 0x6f, 0xb9, 0x40, 0xc5, 0x00, 0x76, 0xc1, 0xfd, 0x2a, 0xc2, 0x17, 0xfe, }, }, { .name = "a-135", .msg = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", .len = 135, .exp = { 0xf9, 0xf2, 0x8c, 0x21, 0xa2, 0xb0, 0x88, 0x4b, 0xbd, 0x35, 0x94, 0xca, 0xe8, 0x2b, 0xf8, 0x11, 0xc0, 0xc1, 0xed, 0xe4, 0x27, 0xe0, 0x83, 0xd5, 0x57, 0x6e, 0x90, 0x9d, }, }, { .name = "a-136", .msg = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", .len = 136, .exp = { 0x96, 0x13, 0x6a, 0x6a, 0x09, 0x44, 0x33, 0xb4, 0xaa, 0x85, 0x5f, 0x16, 0x38, 0x29, 0xa2, 0xce, 0x6b, 0xca, 0x7d, 0x56, 0xcf, 0xd2, 0x16, 0x3b, 0x47, 0xf1, 0xf1, 0xc4, }, }, { .name = "ff-256", .msg = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, }, .len = 256, .exp = { 0xb6, 0x53, 0x4d, 0x8b, 0xee, 0xdf, 0xb5, 0xed, 0x3f, 0x95, 0x3b, 0x09, 0xd1, 0x2f, 0xc3, 0x8f, 0x3d, 0x8b, 0x0b, 0xea, 0x9d, 0x80, 0xbd, 0x1e, 0x25, 0xc9, 0xfc, 0x35, }, }, { .name = "a-210", .msg = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", .len = 210, .exp = { 0x03, 0x05, 0x4a, 0xb0, 0xa3, 0x37, 0x99, 0xbe, 0x2b, 0x17, 0xc8, 0x2b, 0x3a, 0x13, 0x90, 0x05, 0x2e, 0x49, 0xdf, 0x31, 0x6d, 0x85, 0x15, 0x2d, 0x74, 0x66, 0xab, 0x57, }, }}; for (size_t i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) { uint8_t got[28] = { 0 }; sha3_224(tests[i].msg, tests[i].len, got); if (memcmp(got, tests[i].exp, sizeof(got))) { fprintf(stderr, "test_sha3_224(\"%s\") failed, got:\n", tests[i].name); dump_hex(stderr, got, 28); fprintf(stderr, "exp:\n"); dump_hex(stderr, tests[i].exp, 28); } } } static void test_sha3_256(void) { static const struct { const char *name; // test name const uint8_t msg[256]; // test message const size_t len; // test message length const uint8_t exp[32]; // expected hash } tests[] = {{ .name = "empty", .msg = "", .len = 0, .exp = { 0xa7, 0xff, 0xc6, 0xf8, 0xbf, 0x1e, 0xd7, 0x66, 0x51, 0xc1, 0x47, 0x56, 0xa0, 0x61, 0xd6, 0x62, 0xf5, 0x80, 0xff, 0x4d, 0xe4, 0x3b, 0x49, 0xfa, 0x82, 0xd8, 0x0a, 0x4b, 0x80, 0xf8, 0x43, 0x4a, }, }, { .name = "asdf", .msg = "asdf", .len = 4, .exp = { 0xdd, 0x27, 0x81, 0xf4, 0xc5, 0x1b, 0xcc, 0xdb, 0xe2, 0x3e, 0x4d, 0x39, 0x8b, 0x8a, 0x82, 0x26, 0x1f, 0x58, 0x5c, 0x27, 0x8d, 0xbb, 0x4b, 0x84, 0x98, 0x9f, 0xea, 0x70, 0xe7, 0x67, 0x23, 0xa9, }, }, { .name = "a-134", .msg = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", .len = 134, .exp = { 0x58, 0xb9, 0x70, 0xc3, 0x7a, 0xc2, 0xd6, 0x5b, 0x59, 0x9b, 0x69, 0x18, 0x68, 0xa6, 0x14, 0x01, 0xa5, 0x01, 0xc4, 0x0f, 0x23, 0x5d, 0x55, 0xf0, 0x59, 0xd3, 0x9a, 0x94, 0x2f, 0x41, 0xdc, 0xee, }, }, { .name = "a-135", .msg = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", .len = 135, .exp = { 0x80, 0x94, 0xbb, 0x53, 0xc4, 0x4c, 0xfb, 0x1e, 0x67, 0xb7, 0xc3, 0x04, 0x47, 0xf9, 0xa1, 0xc3, 0x36, 0x96, 0xd2, 0x46, 0x3e, 0xcc, 0x1d, 0x9c, 0x92, 0x53, 0x89, 0x13, 0x39, 0x28, 0x43, 0xc9, }, }, { .name = "a-136", .msg = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", .len = 136, .exp = { 0x3f, 0xc5, 0x55, 0x9f, 0x14, 0xdb, 0x8e, 0x45, 0x3a, 0x0a, 0x30, 0x91, 0xed, 0xbd, 0x2b, 0xc2, 0x5e, 0x11, 0x52, 0x8d, 0x81, 0xc6, 0x6f, 0xa5, 0x70, 0xa4, 0xef, 0xdc, 0xc2, 0x69, 0x5e, 0xe1, }, }, { .name = "ff-256", .msg = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, }, .len = 256, .exp = { 0xea, 0xa5, 0x7c, 0x69, 0x9a, 0x7a, 0x61, 0x4f, 0x9d, 0x96, 0x1e, 0x42, 0xd8, 0xb1, 0x2a, 0x93, 0x54, 0x6e, 0x8e, 0x80, 0xd3, 0x1f, 0x5c, 0xfc, 0xc4, 0x3f, 0x95, 0x39, 0xed, 0x06, 0x30, 0x7a, }, }, { .name = "a-210", .msg = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", .len = 210, .exp = { 0xb4, 0x12, 0xbd, 0x70, 0xce, 0x67, 0xeb, 0x59, 0x0b, 0xb2, 0x25, 0x09, 0xef, 0x4e, 0x68, 0x7e, 0x02, 0xb4, 0x8e, 0x07, 0xd2, 0xbb, 0xd7, 0xbb, 0x9a, 0xfb, 0x58, 0x70, 0xfd, 0x14, 0xc1, 0x13, }, }}; for (size_t i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) { uint8_t got[32] = { 0 }; sha3_256(tests[i].msg, tests[i].len, got); if (memcmp(got, tests[i].exp, sizeof(got))) { fprintf(stderr, "test_sha3_256(\"%s\") failed, got:\n", tests[i].name); dump_hex(stderr, got, 32); fprintf(stderr, "exp:\n"); dump_hex(stderr, tests[i].exp, 32); } } } static void test_sha3_384(void) { static const struct { const char *name; // test name const uint8_t msg[256]; // test message const size_t len; // test message length const uint8_t exp[48]; // expected hash } tests[] = {{ .name = "empty", .msg = "", .len = 0, .exp = { 0x0c, 0x63, 0xa7, 0x5b, 0x84, 0x5e, 0x4f, 0x7d, 0x01, 0x10, 0x7d, 0x85, 0x2e, 0x4c, 0x24, 0x85, 0xc5, 0x1a, 0x50, 0xaa, 0xaa, 0x94, 0xfc, 0x61, 0x99, 0x5e, 0x71, 0xbb, 0xee, 0x98, 0x3a, 0x2a, 0xc3, 0x71, 0x38, 0x31, 0x26, 0x4a, 0xdb, 0x47, 0xfb, 0x6b, 0xd1, 0xe0, 0x58, 0xd5, 0xf0, 0x04, }, }, { .name = "asdf", .msg = "asdf", .len = 4, .exp = { 0xcc, 0x8c, 0x24, 0x61, 0xa8, 0xac, 0xb5, 0x8c, 0x9e, 0x7b, 0x78, 0x95, 0x8e, 0xa3, 0x6d, 0x5f, 0xd3, 0x20, 0x38, 0xf9, 0x58, 0xcd, 0xbb, 0x59, 0xf2, 0x6b, 0x0f, 0xfd, 0x1c, 0x36, 0x57, 0x61, 0x83, 0xe1, 0xc2, 0xca, 0x33, 0x57, 0xca, 0x1e, 0x33, 0x3a, 0x11, 0xaf, 0xac, 0x8a, 0xed, 0xe6, }, }, { .name = "a-134", .msg = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", .len = 134, .exp = { 0xac, 0x8b, 0xca, 0x5d, 0x14, 0xed, 0xb5, 0xfc, 0x82, 0xe2, 0x2e, 0x45, 0x33, 0x34, 0xcb, 0x39, 0xef, 0x43, 0x14, 0xa5, 0x9a, 0xd7, 0xba, 0x6f, 0xb1, 0x0f, 0x0b, 0x11, 0xbe, 0x7b, 0x4a, 0xf3, 0xfd, 0xe3, 0xe9, 0x54, 0x07, 0x81, 0xc2, 0x39, 0xfa, 0x4c, 0x1f, 0x60, 0x44, 0xf3, 0x1d, 0xa9, }, }, { .name = "a-135", .msg = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", .len = 135, .exp = { 0xa2, 0xd5, 0x19, 0x07, 0xc0, 0x61, 0x1e, 0x25, 0xc0, 0x58, 0xf0, 0x67, 0x50, 0x42, 0xe8, 0xf5, 0x3c, 0xc4, 0x73, 0xdc, 0x34, 0x7c, 0x5e, 0xa8, 0xa8, 0x13, 0xd8, 0x86, 0xb3, 0xaa, 0x8f, 0x8d, 0xca, 0xb6, 0x1a, 0x23, 0x62, 0x37, 0xd9, 0x4d, 0xe4, 0x04, 0xcd, 0x66, 0x60, 0x62, 0x43, 0xf9, }, }, { .name = "a-136", .msg = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", .len = 136, .exp = { 0xcb, 0xbc, 0xb4, 0x66, 0x41, 0x7a, 0x2f, 0x6d, 0x46, 0x64, 0x79, 0xbb, 0x6d, 0xc6, 0x59, 0x43, 0x4d, 0x95, 0x89, 0xde, 0x3a, 0x53, 0xac, 0xc9, 0xb4, 0x27, 0x58, 0x04, 0x82, 0xe3, 0x05, 0x94, 0x88, 0x88, 0xc8, 0xfa, 0x6d, 0x06, 0x9c, 0x5e, 0x6a, 0x89, 0x9a, 0xa3, 0x4a, 0x9a, 0xf1, 0x5a, }, }, { .name = "ff-256", .msg = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, }, .len = 256, .exp = { 0x91, 0xb2, 0xc0, 0xab, 0x2c, 0xe3, 0x31, 0xcd, 0x59, 0xab, 0x98, 0x3b, 0x87, 0xaf, 0xc9, 0xe5, 0x45, 0x66, 0x33, 0xb1, 0x30, 0x49, 0xac, 0x84, 0x36, 0x04, 0xc9, 0xb6, 0xc3, 0xab, 0x09, 0xc3, 0x5c, 0xf8, 0x8c, 0xcb, 0xf7, 0x61, 0xc5, 0x64, 0x7c, 0x92, 0x2b, 0xcc, 0x9b, 0x37, 0x5a, 0x6b, }, }, { .name = "a-210", .msg = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", .len = 210, .exp = { 0x23, 0x2f, 0xba, 0x5c, 0x81, 0x59, 0x36, 0xc7, 0x7b, 0x37, 0x3a, 0x5e, 0x5d, 0xa0, 0xd2, 0xca, 0x3b, 0x15, 0xcd, 0x28, 0x58, 0x92, 0x66, 0x14, 0x5a, 0x92, 0xd6, 0x50, 0xfa, 0x58, 0xef, 0x4f, 0xdf, 0xa3, 0x4e, 0x9e, 0x2f, 0x0e, 0xa8, 0x7a, 0x67, 0x32, 0x8f, 0x68, 0x9a, 0x6b, 0x8f, 0x04, }, }}; for (size_t i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) { uint8_t got[48] = { 0 }; sha3_384(tests[i].msg, tests[i].len, got); if (memcmp(got, tests[i].exp, sizeof(got))) { fprintf(stderr, "test_sha3_384(\"%s\") failed, got:\n", tests[i].name); dump_hex(stderr, got, 48); fprintf(stderr, "exp:\n"); dump_hex(stderr, tests[i].exp, 48); } } } static void test_sha3_512(void) { static const struct { const char *name; // test name const uint8_t msg[256]; // test message const size_t len; // test message length const uint8_t exp[64]; // expected hash } tests[] = {{ .name = "empty", .msg = "", .len = 0, .exp = { 0xa6, 0x9f, 0x73, 0xcc, 0xa2, 0x3a, 0x9a, 0xc5, 0xc8, 0xb5, 0x67, 0xdc, 0x18, 0x5a, 0x75, 0x6e, 0x97, 0xc9, 0x82, 0x16, 0x4f, 0xe2, 0x58, 0x59, 0xe0, 0xd1, 0xdc, 0xc1, 0x47, 0x5c, 0x80, 0xa6, 0x15, 0xb2, 0x12, 0x3a, 0xf1, 0xf5, 0xf9, 0x4c, 0x11, 0xe3, 0xe9, 0x40, 0x2c, 0x3a, 0xc5, 0x58, 0xf5, 0x00, 0x19, 0x9d, 0x95, 0xb6, 0xd3, 0xe3, 0x01, 0x75, 0x85, 0x86, 0x28, 0x1d, 0xcd, 0x26, }, }, { .name = "asdf", .msg = "asdf", .len = 4, .exp = { 0x8d, 0x88, 0xcf, 0x5b, 0x20, 0xf5, 0x3a, 0xcd, 0x7a, 0xe1, 0x47, 0x9b, 0x5b, 0x36, 0xdc, 0x20, 0x21, 0x75, 0x3b, 0x04, 0x99, 0x02, 0xc7, 0x72, 0x47, 0xbb, 0x27, 0xb1, 0x31, 0xb3, 0x00, 0xbd, 0x3c, 0xa8, 0xbe, 0xef, 0x28, 0x75, 0x6d, 0xce, 0x27, 0xb8, 0x99, 0x08, 0x67, 0xc4, 0x57, 0x7a, 0x25, 0x35, 0xe7, 0xe3, 0xb7, 0x51, 0x41, 0x39, 0x9c, 0xa1, 0xa9, 0x4c, 0xc8, 0x4b, 0x0e, 0xb9, }, }, { .name = "a-134", .msg = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", .len = 134, .exp = { 0x4e, 0x72, 0xa4, 0xf6, 0x55, 0x99, 0xa2, 0x47, 0x2a, 0x66, 0xf8, 0xa8, 0xd6, 0xcf, 0xb3, 0x84, 0xb7, 0xd3, 0x4f, 0x52, 0xec, 0xaa, 0x00, 0xe9, 0xf0, 0x66, 0x82, 0x0b, 0x0e, 0xdc, 0x1f, 0xcc, 0x9c, 0xf3, 0x12, 0x0b, 0x81, 0x46, 0x89, 0xbc, 0x62, 0xb7, 0x72, 0x0f, 0x4e, 0x4c, 0x99, 0x3d, 0xa0, 0x84, 0x08, 0x27, 0xf6, 0x95, 0x03, 0x8a, 0x82, 0x18, 0x69, 0xe8, 0xa6, 0x27, 0x60, 0xe8, }, }, { .name = "a-135", .msg = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", .len = 135, .exp = { 0x4b, 0xe1, 0xe7, 0x02, 0x76, 0xf9, 0x12, 0x2f, 0x47, 0x0a, 0x54, 0xc2, 0x72, 0x40, 0xc7, 0xd0, 0x70, 0x9d, 0xab, 0x74, 0x69, 0x95, 0x8b, 0x48, 0xa9, 0x50, 0xd6, 0x9d, 0xa6, 0xdd, 0x07, 0xca, 0x13, 0x58, 0x26, 0xd9, 0xd2, 0x3e, 0x97, 0x5c, 0xb9, 0x28, 0x3e, 0x7d, 0x23, 0x6e, 0xf9, 0x8a, 0x80, 0x45, 0x1d, 0xca, 0x8e, 0x31, 0x1f, 0x52, 0x09, 0x63, 0x08, 0xb2, 0xc8, 0xd7, 0x0c, 0xc7, }, }, { .name = "a-136", .msg = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", .len = 136, .exp = { 0xe5, 0x03, 0x92, 0xc9, 0x1e, 0xd9, 0x57, 0x68, 0xc8, 0xdc, 0xf5, 0x2a, 0x12, 0xe5, 0xdb, 0x1e, 0xcd, 0x03, 0x47, 0xfb, 0x99, 0x5f, 0x7f, 0xf4, 0xea, 0x06, 0x99, 0x46, 0x49, 0xbb, 0xd1, 0xa0, 0xde, 0x7a, 0xe3, 0x6a, 0x62, 0xaa, 0xdc, 0x00, 0xa7, 0x04, 0xd7, 0x30, 0xb5, 0x2b, 0xda, 0x19, 0x1b, 0x72, 0x95, 0x1e, 0x2a, 0xfc, 0x9b, 0x6f, 0xb6, 0x82, 0x47, 0x87, 0xb2, 0x08, 0x62, 0x57, }, }, { .name = "ff-256", .msg = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, }, .len = 256, .exp = { 0x02, 0x3a, 0x91, 0x27, 0xcf, 0x29, 0x6d, 0x01, 0x12, 0x0e, 0x3d, 0xaa, 0x92, 0x76, 0x15, 0x23, 0x8e, 0x97, 0xdd, 0xb6, 0x33, 0x26, 0xe2, 0x89, 0xb3, 0x31, 0xe2, 0x25, 0xbe, 0x41, 0xea, 0xd5, 0x90, 0xf1, 0xdd, 0x5c, 0x80, 0x1d, 0x91, 0x03, 0xfe, 0x65, 0x7d, 0x23, 0x63, 0xbd, 0xb2, 0x66, 0xe7, 0x90, 0xb1, 0x89, 0x0b, 0x3d, 0xd5, 0x79, 0xdc, 0xa7, 0xf9, 0x1f, 0x5f, 0x4d, 0x98, 0x49, }, }, { .name = "a-210", .msg = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", .len = 210, .exp = { 0x47, 0xfa, 0xd7, 0x8d, 0x72, 0x35, 0xe5, 0xcd, 0xb9, 0xd7, 0x23, 0x6c, 0xfc, 0xf2, 0x79, 0xdb, 0x0f, 0x8a, 0xcd, 0x5b, 0xf1, 0x7b, 0xdc, 0x74, 0x18, 0xe4, 0x29, 0xb7, 0x1a, 0x0a, 0x21, 0xb7, 0xed, 0xe8, 0x54, 0x64, 0xcf, 0x69, 0x44, 0x63, 0xff, 0x0e, 0x56, 0xf2, 0x8f, 0x04, 0xbf, 0x85, 0xc0, 0x85, 0xe1, 0x17, 0x6a, 0x47, 0xd7, 0x3b, 0xf2, 0x8b, 0xdb, 0xa0, 0x4f, 0x4a, 0xe7, 0x61, }, }}; for (size_t i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) { uint8_t got[64] = { 0 }; sha3_512(tests[i].msg, tests[i].len, got); if (memcmp(got, tests[i].exp, sizeof(got))) { fprintf(stderr, "test_sha3_512(\"%s\") failed, got:\n", tests[i].name); dump_hex(stderr, got, 64); fprintf(stderr, "exp:\n"); dump_hex(stderr, tests[i].exp, 64); } } } static void test_sha3_224_ctx(void) { static const struct { const char *name; // test name const uint8_t msg[256]; // test message const size_t len; // test message length const uint8_t exp[28]; // expected hash } tests[] = {{ .name = "empty", .msg = "", .len = 0, .exp = { 0x6b, 0x4e, 0x03, 0x42, 0x36, 0x67, 0xdb, 0xb7, 0x3b, 0x6e, 0x15, 0x45, 0x4f, 0x0e, 0xb1, 0xab, 0xd4, 0x59, 0x7f, 0x9a, 0x1b, 0x07, 0x8e, 0x3f, 0x5b, 0x5a, 0x6b, 0xc7, }, }, { .name = "asdf", .msg = "asdf", .len = 4, .exp = { 0x47, 0xcc, 0xa2, 0x03, 0xee, 0xfc, 0xa3, 0x49, 0xde, 0xaa, 0x41, 0x8d, 0xa7, 0xfe, 0x05, 0x38, 0x9e, 0xf6, 0x49, 0x98, 0x5c, 0x87, 0xa9, 0xb6, 0x55, 0xad, 0x12, 0x8c, }, }, { .name = "a-134", .msg = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", .len = 134, .exp = { 0x5d, 0x1d, 0xb4, 0xe4, 0x7c, 0x0c, 0x4a, 0x42, 0x45, 0xb9, 0x0d, 0x18, 0x55, 0xb0, 0x7c, 0xb1, 0x6f, 0xb9, 0x40, 0xc5, 0x00, 0x76, 0xc1, 0xfd, 0x2a, 0xc2, 0x17, 0xfe, }, }, { .name = "a-135", .msg = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", .len = 135, .exp = { 0xf9, 0xf2, 0x8c, 0x21, 0xa2, 0xb0, 0x88, 0x4b, 0xbd, 0x35, 0x94, 0xca, 0xe8, 0x2b, 0xf8, 0x11, 0xc0, 0xc1, 0xed, 0xe4, 0x27, 0xe0, 0x83, 0xd5, 0x57, 0x6e, 0x90, 0x9d, }, }, { .name = "a-136", .msg = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", .len = 136, .exp = { 0x96, 0x13, 0x6a, 0x6a, 0x09, 0x44, 0x33, 0xb4, 0xaa, 0x85, 0x5f, 0x16, 0x38, 0x29, 0xa2, 0xce, 0x6b, 0xca, 0x7d, 0x56, 0xcf, 0xd2, 0x16, 0x3b, 0x47, 0xf1, 0xf1, 0xc4, }, }, { .name = "ff-256", .msg = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, }, .len = 256, .exp = { 0xb6, 0x53, 0x4d, 0x8b, 0xee, 0xdf, 0xb5, 0xed, 0x3f, 0x95, 0x3b, 0x09, 0xd1, 0x2f, 0xc3, 0x8f, 0x3d, 0x8b, 0x0b, 0xea, 0x9d, 0x80, 0xbd, 0x1e, 0x25, 0xc9, 0xfc, 0x35, }, }, { .name = "a-210", .msg = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", .len = 210, .exp = { 0x03, 0x05, 0x4a, 0xb0, 0xa3, 0x37, 0x99, 0xbe, 0x2b, 0x17, 0xc8, 0x2b, 0x3a, 0x13, 0x90, 0x05, 0x2e, 0x49, 0xdf, 0x31, 0x6d, 0x85, 0x15, 0x2d, 0x74, 0x66, 0xab, 0x57, }, }}; // run all tests for (size_t i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) { // try all possible absorb sizes from 1 to len for (size_t j = 1; j < tests[i].len; j++) { // init sha3_t hash; sha3_224_init(&hash); // absorb for (size_t k = 0; k < tests[i].len; k += j) { const size_t absorb_len = MIN(tests[i].len - k, j); sha3_224_absorb(&hash, tests[i].msg + k, absorb_len); } // finalize uint8_t got[28] = { 0 }; sha3_224_final(&hash, got); // check if (memcmp(got, tests[i].exp, sizeof(got))) { fprintf(stderr, "test_sha3_224_ctx(\"%s\") failed, got:\n", tests[i].name); dump_hex(stderr, got, 28); fprintf(stderr, "exp:\n"); dump_hex(stderr, tests[i].exp, 28); } } } } static void test_sha3_256_ctx(void) { static const struct { const char *name; // test name const uint8_t msg[256]; // test message const size_t len; // test message length const uint8_t exp[32]; // expected hash } tests[] = {{ .name = "empty", .msg = "", .len = 0, .exp = { 0xa7, 0xff, 0xc6, 0xf8, 0xbf, 0x1e, 0xd7, 0x66, 0x51, 0xc1, 0x47, 0x56, 0xa0, 0x61, 0xd6, 0x62, 0xf5, 0x80, 0xff, 0x4d, 0xe4, 0x3b, 0x49, 0xfa, 0x82, 0xd8, 0x0a, 0x4b, 0x80, 0xf8, 0x43, 0x4a, }, }, { .name = "asdf", .msg = "asdf", .len = 4, .exp = { 0xdd, 0x27, 0x81, 0xf4, 0xc5, 0x1b, 0xcc, 0xdb, 0xe2, 0x3e, 0x4d, 0x39, 0x8b, 0x8a, 0x82, 0x26, 0x1f, 0x58, 0x5c, 0x27, 0x8d, 0xbb, 0x4b, 0x84, 0x98, 0x9f, 0xea, 0x70, 0xe7, 0x67, 0x23, 0xa9, }, }, { .name = "a-134", .msg = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", .len = 134, .exp = { 0x58, 0xb9, 0x70, 0xc3, 0x7a, 0xc2, 0xd6, 0x5b, 0x59, 0x9b, 0x69, 0x18, 0x68, 0xa6, 0x14, 0x01, 0xa5, 0x01, 0xc4, 0x0f, 0x23, 0x5d, 0x55, 0xf0, 0x59, 0xd3, 0x9a, 0x94, 0x2f, 0x41, 0xdc, 0xee, }, }, { .name = "a-135", .msg = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", .len = 135, .exp = { 0x80, 0x94, 0xbb, 0x53, 0xc4, 0x4c, 0xfb, 0x1e, 0x67, 0xb7, 0xc3, 0x04, 0x47, 0xf9, 0xa1, 0xc3, 0x36, 0x96, 0xd2, 0x46, 0x3e, 0xcc, 0x1d, 0x9c, 0x92, 0x53, 0x89, 0x13, 0x39, 0x28, 0x43, 0xc9, }, }, { .name = "a-136", .msg = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", .len = 136, .exp = { 0x3f, 0xc5, 0x55, 0x9f, 0x14, 0xdb, 0x8e, 0x45, 0x3a, 0x0a, 0x30, 0x91, 0xed, 0xbd, 0x2b, 0xc2, 0x5e, 0x11, 0x52, 0x8d, 0x81, 0xc6, 0x6f, 0xa5, 0x70, 0xa4, 0xef, 0xdc, 0xc2, 0x69, 0x5e, 0xe1, }, }, { .name = "ff-256", .msg = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, }, .len = 256, .exp = { 0xea, 0xa5, 0x7c, 0x69, 0x9a, 0x7a, 0x61, 0x4f, 0x9d, 0x96, 0x1e, 0x42, 0xd8, 0xb1, 0x2a, 0x93, 0x54, 0x6e, 0x8e, 0x80, 0xd3, 0x1f, 0x5c, 0xfc, 0xc4, 0x3f, 0x95, 0x39, 0xed, 0x06, 0x30, 0x7a, }, }, { .name = "a-210", .msg = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", .len = 210, .exp = { 0xb4, 0x12, 0xbd, 0x70, 0xce, 0x67, 0xeb, 0x59, 0x0b, 0xb2, 0x25, 0x09, 0xef, 0x4e, 0x68, 0x7e, 0x02, 0xb4, 0x8e, 0x07, 0xd2, 0xbb, 0xd7, 0xbb, 0x9a, 0xfb, 0x58, 0x70, 0xfd, 0x14, 0xc1, 0x13, }, }}; // run all tests for (size_t i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) { // try all possible absorb sizes from 1 to len for (size_t j = 1; j < tests[i].len; j++) { // init context sha3_t hash; sha3_256_init(&hash); // absorb for (size_t k = 0; k < tests[i].len; k += j) { const size_t absorb_len = MIN(tests[i].len - k, j); sha3_256_absorb(&hash, tests[i].msg + k, absorb_len); } // finalize uint8_t got[32] = { 0 }; sha3_256_final(&hash, got); // check if (memcmp(got, tests[i].exp, sizeof(got))) { fprintf(stderr, "test_sha3_256_ctx(\"%s\") failed, got:\n", tests[i].name); dump_hex(stderr, got, 32); fprintf(stderr, "exp:\n"); dump_hex(stderr, tests[i].exp, 32); } } } } static void test_sha3_384_ctx(void) { static const struct { const char *name; // test name const uint8_t msg[256]; // test message const size_t len; // test message length const uint8_t exp[48]; // expected hash } tests[] = {{ .name = "empty", .msg = "", .len = 0, .exp = { 0x0c, 0x63, 0xa7, 0x5b, 0x84, 0x5e, 0x4f, 0x7d, 0x01, 0x10, 0x7d, 0x85, 0x2e, 0x4c, 0x24, 0x85, 0xc5, 0x1a, 0x50, 0xaa, 0xaa, 0x94, 0xfc, 0x61, 0x99, 0x5e, 0x71, 0xbb, 0xee, 0x98, 0x3a, 0x2a, 0xc3, 0x71, 0x38, 0x31, 0x26, 0x4a, 0xdb, 0x47, 0xfb, 0x6b, 0xd1, 0xe0, 0x58, 0xd5, 0xf0, 0x04, }, }, { .name = "asdf", .msg = "asdf", .len = 4, .exp = { 0xcc, 0x8c, 0x24, 0x61, 0xa8, 0xac, 0xb5, 0x8c, 0x9e, 0x7b, 0x78, 0x95, 0x8e, 0xa3, 0x6d, 0x5f, 0xd3, 0x20, 0x38, 0xf9, 0x58, 0xcd, 0xbb, 0x59, 0xf2, 0x6b, 0x0f, 0xfd, 0x1c, 0x36, 0x57, 0x61, 0x83, 0xe1, 0xc2, 0xca, 0x33, 0x57, 0xca, 0x1e, 0x33, 0x3a, 0x11, 0xaf, 0xac, 0x8a, 0xed, 0xe6, }, }, { .name = "a-134", .msg = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", .len = 134, .exp = { 0xac, 0x8b, 0xca, 0x5d, 0x14, 0xed, 0xb5, 0xfc, 0x82, 0xe2, 0x2e, 0x45, 0x33, 0x34, 0xcb, 0x39, 0xef, 0x43, 0x14, 0xa5, 0x9a, 0xd7, 0xba, 0x6f, 0xb1, 0x0f, 0x0b, 0x11, 0xbe, 0x7b, 0x4a, 0xf3, 0xfd, 0xe3, 0xe9, 0x54, 0x07, 0x81, 0xc2, 0x39, 0xfa, 0x4c, 0x1f, 0x60, 0x44, 0xf3, 0x1d, 0xa9, }, }, { .name = "a-135", .msg = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", .len = 135, .exp = { 0xa2, 0xd5, 0x19, 0x07, 0xc0, 0x61, 0x1e, 0x25, 0xc0, 0x58, 0xf0, 0x67, 0x50, 0x42, 0xe8, 0xf5, 0x3c, 0xc4, 0x73, 0xdc, 0x34, 0x7c, 0x5e, 0xa8, 0xa8, 0x13, 0xd8, 0x86, 0xb3, 0xaa, 0x8f, 0x8d, 0xca, 0xb6, 0x1a, 0x23, 0x62, 0x37, 0xd9, 0x4d, 0xe4, 0x04, 0xcd, 0x66, 0x60, 0x62, 0x43, 0xf9, }, }, { .name = "a-136", .msg = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", .len = 136, .exp = { 0xcb, 0xbc, 0xb4, 0x66, 0x41, 0x7a, 0x2f, 0x6d, 0x46, 0x64, 0x79, 0xbb, 0x6d, 0xc6, 0x59, 0x43, 0x4d, 0x95, 0x89, 0xde, 0x3a, 0x53, 0xac, 0xc9, 0xb4, 0x27, 0x58, 0x04, 0x82, 0xe3, 0x05, 0x94, 0x88, 0x88, 0xc8, 0xfa, 0x6d, 0x06, 0x9c, 0x5e, 0x6a, 0x89, 0x9a, 0xa3, 0x4a, 0x9a, 0xf1, 0x5a, }, }, { .name = "ff-256", .msg = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, }, .len = 256, .exp = { 0x91, 0xb2, 0xc0, 0xab, 0x2c, 0xe3, 0x31, 0xcd, 0x59, 0xab, 0x98, 0x3b, 0x87, 0xaf, 0xc9, 0xe5, 0x45, 0x66, 0x33, 0xb1, 0x30, 0x49, 0xac, 0x84, 0x36, 0x04, 0xc9, 0xb6, 0xc3, 0xab, 0x09, 0xc3, 0x5c, 0xf8, 0x8c, 0xcb, 0xf7, 0x61, 0xc5, 0x64, 0x7c, 0x92, 0x2b, 0xcc, 0x9b, 0x37, 0x5a, 0x6b, }, }, { .name = "a-210", .msg = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", .len = 210, .exp = { 0x23, 0x2f, 0xba, 0x5c, 0x81, 0x59, 0x36, 0xc7, 0x7b, 0x37, 0x3a, 0x5e, 0x5d, 0xa0, 0xd2, 0xca, 0x3b, 0x15, 0xcd, 0x28, 0x58, 0x92, 0x66, 0x14, 0x5a, 0x92, 0xd6, 0x50, 0xfa, 0x58, 0xef, 0x4f, 0xdf, 0xa3, 0x4e, 0x9e, 0x2f, 0x0e, 0xa8, 0x7a, 0x67, 0x32, 0x8f, 0x68, 0x9a, 0x6b, 0x8f, 0x04, }, }}; // run all tests for (size_t i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) { // try all possible absorb sizes from 1 to len for (size_t j = 1; j < tests[i].len; j++) { // init sha3_t hash; sha3_384_init(&hash); // absorb for (size_t k = 0; k < tests[i].len; k += j) { const size_t absorb_len = MIN(tests[i].len - k, j); sha3_384_absorb(&hash, tests[i].msg + k, absorb_len); } // finalize uint8_t got[48] = { 0 }; sha3_384_final(&hash, got); // check if (memcmp(got, tests[i].exp, sizeof(got))) { fprintf(stderr, "test_sha3_384_ctx(\"%s\") failed, got:\n", tests[i].name); dump_hex(stderr, got, 48); fprintf(stderr, "exp:\n"); dump_hex(stderr, tests[i].exp, 48); } } } } static void test_sha3_512_ctx(void) { static const struct { const char *name; // test name const uint8_t msg[256]; // test message const size_t len; // test message length const uint8_t exp[64]; // expected hash } tests[] = {{ .name = "empty", .msg = "", .len = 0, .exp = { 0xa6, 0x9f, 0x73, 0xcc, 0xa2, 0x3a, 0x9a, 0xc5, 0xc8, 0xb5, 0x67, 0xdc, 0x18, 0x5a, 0x75, 0x6e, 0x97, 0xc9, 0x82, 0x16, 0x4f, 0xe2, 0x58, 0x59, 0xe0, 0xd1, 0xdc, 0xc1, 0x47, 0x5c, 0x80, 0xa6, 0x15, 0xb2, 0x12, 0x3a, 0xf1, 0xf5, 0xf9, 0x4c, 0x11, 0xe3, 0xe9, 0x40, 0x2c, 0x3a, 0xc5, 0x58, 0xf5, 0x00, 0x19, 0x9d, 0x95, 0xb6, 0xd3, 0xe3, 0x01, 0x75, 0x85, 0x86, 0x28, 0x1d, 0xcd, 0x26, }, }, { .name = "asdf", .msg = "asdf", .len = 4, .exp = { 0x8d, 0x88, 0xcf, 0x5b, 0x20, 0xf5, 0x3a, 0xcd, 0x7a, 0xe1, 0x47, 0x9b, 0x5b, 0x36, 0xdc, 0x20, 0x21, 0x75, 0x3b, 0x04, 0x99, 0x02, 0xc7, 0x72, 0x47, 0xbb, 0x27, 0xb1, 0x31, 0xb3, 0x00, 0xbd, 0x3c, 0xa8, 0xbe, 0xef, 0x28, 0x75, 0x6d, 0xce, 0x27, 0xb8, 0x99, 0x08, 0x67, 0xc4, 0x57, 0x7a, 0x25, 0x35, 0xe7, 0xe3, 0xb7, 0x51, 0x41, 0x39, 0x9c, 0xa1, 0xa9, 0x4c, 0xc8, 0x4b, 0x0e, 0xb9, }, }, { .name = "a-134", .msg = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", .len = 134, .exp = { 0x4e, 0x72, 0xa4, 0xf6, 0x55, 0x99, 0xa2, 0x47, 0x2a, 0x66, 0xf8, 0xa8, 0xd6, 0xcf, 0xb3, 0x84, 0xb7, 0xd3, 0x4f, 0x52, 0xec, 0xaa, 0x00, 0xe9, 0xf0, 0x66, 0x82, 0x0b, 0x0e, 0xdc, 0x1f, 0xcc, 0x9c, 0xf3, 0x12, 0x0b, 0x81, 0x46, 0x89, 0xbc, 0x62, 0xb7, 0x72, 0x0f, 0x4e, 0x4c, 0x99, 0x3d, 0xa0, 0x84, 0x08, 0x27, 0xf6, 0x95, 0x03, 0x8a, 0x82, 0x18, 0x69, 0xe8, 0xa6, 0x27, 0x60, 0xe8, }, }, { .name = "a-135", .msg = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", .len = 135, .exp = { 0x4b, 0xe1, 0xe7, 0x02, 0x76, 0xf9, 0x12, 0x2f, 0x47, 0x0a, 0x54, 0xc2, 0x72, 0x40, 0xc7, 0xd0, 0x70, 0x9d, 0xab, 0x74, 0x69, 0x95, 0x8b, 0x48, 0xa9, 0x50, 0xd6, 0x9d, 0xa6, 0xdd, 0x07, 0xca, 0x13, 0x58, 0x26, 0xd9, 0xd2, 0x3e, 0x97, 0x5c, 0xb9, 0x28, 0x3e, 0x7d, 0x23, 0x6e, 0xf9, 0x8a, 0x80, 0x45, 0x1d, 0xca, 0x8e, 0x31, 0x1f, 0x52, 0x09, 0x63, 0x08, 0xb2, 0xc8, 0xd7, 0x0c, 0xc7, }, }, { .name = "a-136", .msg = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", .len = 136, .exp = { 0xe5, 0x03, 0x92, 0xc9, 0x1e, 0xd9, 0x57, 0x68, 0xc8, 0xdc, 0xf5, 0x2a, 0x12, 0xe5, 0xdb, 0x1e, 0xcd, 0x03, 0x47, 0xfb, 0x99, 0x5f, 0x7f, 0xf4, 0xea, 0x06, 0x99, 0x46, 0x49, 0xbb, 0xd1, 0xa0, 0xde, 0x7a, 0xe3, 0x6a, 0x62, 0xaa, 0xdc, 0x00, 0xa7, 0x04, 0xd7, 0x30, 0xb5, 0x2b, 0xda, 0x19, 0x1b, 0x72, 0x95, 0x1e, 0x2a, 0xfc, 0x9b, 0x6f, 0xb6, 0x82, 0x47, 0x87, 0xb2, 0x08, 0x62, 0x57, }, }, { .name = "ff-256", .msg = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, }, .len = 256, .exp = { 0x02, 0x3a, 0x91, 0x27, 0xcf, 0x29, 0x6d, 0x01, 0x12, 0x0e, 0x3d, 0xaa, 0x92, 0x76, 0x15, 0x23, 0x8e, 0x97, 0xdd, 0xb6, 0x33, 0x26, 0xe2, 0x89, 0xb3, 0x31, 0xe2, 0x25, 0xbe, 0x41, 0xea, 0xd5, 0x90, 0xf1, 0xdd, 0x5c, 0x80, 0x1d, 0x91, 0x03, 0xfe, 0x65, 0x7d, 0x23, 0x63, 0xbd, 0xb2, 0x66, 0xe7, 0x90, 0xb1, 0x89, 0x0b, 0x3d, 0xd5, 0x79, 0xdc, 0xa7, 0xf9, 0x1f, 0x5f, 0x4d, 0x98, 0x49, }, }, { .name = "a-210", .msg = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", .len = 210, .exp = { 0x47, 0xfa, 0xd7, 0x8d, 0x72, 0x35, 0xe5, 0xcd, 0xb9, 0xd7, 0x23, 0x6c, 0xfc, 0xf2, 0x79, 0xdb, 0x0f, 0x8a, 0xcd, 0x5b, 0xf1, 0x7b, 0xdc, 0x74, 0x18, 0xe4, 0x29, 0xb7, 0x1a, 0x0a, 0x21, 0xb7, 0xed, 0xe8, 0x54, 0x64, 0xcf, 0x69, 0x44, 0x63, 0xff, 0x0e, 0x56, 0xf2, 0x8f, 0x04, 0xbf, 0x85, 0xc0, 0x85, 0xe1, 0x17, 0x6a, 0x47, 0xd7, 0x3b, 0xf2, 0x8b, 0xdb, 0xa0, 0x4f, 0x4a, 0xe7, 0x61, }, }}; for (size_t i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) { // try all possible absorb sizes from 1 to len for (size_t j = 1; j < tests[i].len; j++) { // init sha3_t hash; sha3_512_init(&hash); // absorb for (size_t k = 0; k < tests[i].len; k += j) { const size_t absorb_len = MIN(tests[i].len - k, j); sha3_512_absorb(&hash, tests[i].msg + k, absorb_len); } // finalize uint8_t got[64] = { 0 }; sha3_512_final(&hash, got); // check if (memcmp(got, tests[i].exp, sizeof(got))) { fprintf(stderr, "test_sha3_512_ctx(\"%s\") failed, got:\n", tests[i].name); dump_hex(stderr, got, 64); fprintf(stderr, "exp:\n"); dump_hex(stderr, tests[i].exp, 64); } } } } static void test_shake128_ctx(void) { static const struct { const char *name; // test name const uint8_t msg[256]; // test message const size_t len; // test message length const uint8_t exp[16]; // expected hash } tests[] = {{ .name = "empty", .msg = "", .len = 0, .exp = { 0x7f, 0x9c, 0x2b, 0xa4, 0xe8, 0x8f, 0x82, 0x7d, 0x61, 0x60, 0x45, 0x50, 0x76, 0x05, 0x85, 0x3e, }, }, { .name = "asdf", .msg = "asdf", .len = 4, .exp = { 0xef, 0x02, 0x2c, 0xc5, 0x3c, 0x74, 0xb3, 0x28, 0x43, 0xf9, 0xc1, 0xf1, 0x14, 0x13, 0xd5, 0x9c, }, }, { .name = "a-134", .msg = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", .len = 134, .exp = { 0xc8, 0x73, 0x5e, 0x5f, 0x6f, 0x15, 0xaf, 0xe5, 0x1a, 0x8c, 0x3b, 0x07, 0xc4, 0xc6, 0x8d, 0x86, }, }, { .name = "a-135", .msg = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", .len = 135, .exp = { 0xa5, 0xe2, 0xb2, 0x27, 0x8d, 0x1b, 0x75, 0x86, 0x6c, 0x78, 0x77, 0xa0, 0xff, 0xa2, 0x47, 0x37, }, }, { .name = "a-136", .msg = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", .len = 136, .exp = { 0x0d, 0x01, 0x58, 0xd4, 0x46, 0x78, 0x3a, 0x9b, 0x18, 0xa6, 0x90, 0x8c, 0x08, 0xbb, 0x5d, 0xe6, }, }, { .name = "ff-256", .msg = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, }, .len = 256, .exp = { 0xf3, 0x06, 0x93, 0x04, 0x16, 0x5c, 0x0e, 0xad, 0x13, 0x25, 0xb5, 0x26, 0x76, 0x05, 0x95, 0xed, }, }, { .name = "a-210", .msg = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", .len = 210, .exp = { 0xb1, 0xb4, 0xf3, 0xad, 0x3a, 0x1f, 0x67, 0x60, 0xe3, 0x08, 0x67, 0xdd, 0x71, 0xb3, 0x49, 0xfa, }, }}; for (size_t i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) { for (size_t len = 1; len < tests[i].len; len++) { // init xof sha3_xof_t xof; shake128_init(&xof); // absorb for (size_t ofs = 0; ofs < tests[i].len; ofs += len) { const size_t absorb_len = MIN(tests[i].len - ofs, len); if (!shake128_absorb(&xof, tests[i].msg + ofs, absorb_len)) { fprintf(stderr, "%s(\"%s\", %zu) failed: shake128_absorb()\n", __func__, tests[i].name, len); return; } } // squeeze uint8_t got[16] = { 0 }; shake128_squeeze(&xof, got, sizeof(got)); // check if (memcmp(got, tests[i].exp, sizeof(got))) { fprintf(stderr, "%s(\"%s\", %zu) failed, got:\n", __func__, tests[i].name, len); dump_hex(stderr, got, 16); fprintf(stderr, "exp:\n"); dump_hex(stderr, tests[i].exp, 16); } } } } static void test_shake128(void) { static const struct { const char *name; // test name const uint8_t msg[256]; // test message const size_t len; // test message length const uint8_t exp[16]; // expected hash } tests[] = {{ .name = "empty", .msg = "", .len = 0, .exp = { 0x7f, 0x9c, 0x2b, 0xa4, 0xe8, 0x8f, 0x82, 0x7d, 0x61, 0x60, 0x45, 0x50, 0x76, 0x05, 0x85, 0x3e, }, }, { .name = "asdf", .msg = "asdf", .len = 4, .exp = { 0xef, 0x02, 0x2c, 0xc5, 0x3c, 0x74, 0xb3, 0x28, 0x43, 0xf9, 0xc1, 0xf1, 0x14, 0x13, 0xd5, 0x9c, }, }, { .name = "a-134", .msg = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", .len = 134, .exp = { 0xc8, 0x73, 0x5e, 0x5f, 0x6f, 0x15, 0xaf, 0xe5, 0x1a, 0x8c, 0x3b, 0x07, 0xc4, 0xc6, 0x8d, 0x86, }, }, { .name = "a-135", .msg = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", .len = 135, .exp = { 0xa5, 0xe2, 0xb2, 0x27, 0x8d, 0x1b, 0x75, 0x86, 0x6c, 0x78, 0x77, 0xa0, 0xff, 0xa2, 0x47, 0x37, }, }, { .name = "a-136", .msg = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", .len = 136, .exp = { 0x0d, 0x01, 0x58, 0xd4, 0x46, 0x78, 0x3a, 0x9b, 0x18, 0xa6, 0x90, 0x8c, 0x08, 0xbb, 0x5d, 0xe6, }, }, { .name = "ff-256", .msg = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, }, .len = 256, .exp = { 0xf3, 0x06, 0x93, 0x04, 0x16, 0x5c, 0x0e, 0xad, 0x13, 0x25, 0xb5, 0x26, 0x76, 0x05, 0x95, 0xed, }, }, { .name = "a-210", .msg = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", .len = 210, .exp = { 0xb1, 0xb4, 0xf3, 0xad, 0x3a, 0x1f, 0x67, 0x60, 0xe3, 0x08, 0x67, 0xdd, 0x71, 0xb3, 0x49, 0xfa, }, }}; for (size_t i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) { for (size_t len = 1; len < tests[i].len; len++) { // run uint8_t got[16]; shake128(tests[i].msg, tests[i].len, got, sizeof(got)); // check if (memcmp(got, tests[i].exp, sizeof(got))) { fprintf(stderr, "%s(\"%s\", %zu) failed, got:\n", __func__, tests[i].name, len); dump_hex(stderr, got, 16); fprintf(stderr, "exp:\n"); dump_hex(stderr, tests[i].exp, 16); } } } } static void test_shake256_ctx(void) { static const struct { const char *name; // test name const uint8_t msg[256]; // test message const size_t len; // test message length const uint8_t exp[32]; // expected hash } tests[] = {{ .name = "empty", .msg = "", .len = 0, .exp = { 0x46, 0xb9, 0xdd, 0x2b, 0x0b, 0xa8, 0x8d, 0x13, 0x23, 0x3b, 0x3f, 0xeb, 0x74, 0x3e, 0xeb, 0x24, 0x3f, 0xcd, 0x52, 0xea, 0x62, 0xb8, 0x1b, 0x82, 0xb5, 0x0c, 0x27, 0x64, 0x6e, 0xd5, 0x76, 0x2f, }, }, { .name = "asdf", .msg = "asdf", .len = 4, .exp = { 0xf0, 0x0c, 0x15, 0x64, 0x33, 0x96, 0x61, 0x6a, 0x89, 0xa0, 0xcb, 0x79, 0x03, 0x9f, 0x74, 0x05, 0x75, 0xde, 0xfe, 0x9d, 0xbe, 0x30, 0x7c, 0xcc, 0xda, 0xf8, 0xae, 0x21, 0x0e, 0x1c, 0x9c, 0xc6, }, }, { .name = "a-134", .msg = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", .len = 134, .exp = { 0xf1, 0xe0, 0x3f, 0x37, 0x8e, 0xb7, 0x79, 0x04, 0xba, 0x15, 0xbb, 0x64, 0x2a, 0x84, 0xb9, 0x0d, 0xe5, 0x2e, 0x29, 0x3e, 0xaf, 0xc2, 0x7c, 0xef, 0x05, 0x88, 0x3b, 0x16, 0x56, 0xae, 0xc3, 0x41, }, }, { .name = "a-135", .msg = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", .len = 135, .exp = { 0x55, 0xb9, 0x91, 0xec, 0xe1, 0xe5, 0x67, 0xb6, 0xe7, 0xc2, 0xc7, 0x14, 0x44, 0x4d, 0xd2, 0x01, 0xcd, 0x51, 0xf4, 0xf3, 0x83, 0x2d, 0x08, 0xe1, 0xd2, 0x6b, 0xeb, 0xc6, 0x3e, 0x07, 0xa3, 0xd7, }, }, { .name = "a-136", .msg = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", .len = 136, .exp = { 0x8f, 0xcc, 0x5a, 0x08, 0xf0, 0xa1, 0xf6, 0x82, 0x7c, 0x9c, 0xf6, 0x4e, 0xe8, 0xd1, 0x6e, 0x04, 0x43, 0x10, 0x63, 0x59, 0xca, 0x6c, 0x8e, 0xfd, 0x23, 0x07, 0x59, 0x25, 0x6f, 0x44, 0x99, 0x6a, }, }, { .name = "ff-256", .msg = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, }, .len = 256, .exp = { 0x3f, 0x25, 0xdf, 0x0e, 0x37, 0x17, 0x14, 0xdf, 0xb0, 0xcc, 0x3d, 0x96, 0x17, 0xe1, 0xa0, 0x71, 0x75, 0xa0, 0xf0, 0x84, 0xc7, 0x00, 0x29, 0x23, 0x5c, 0x72, 0x7c, 0x5a, 0x68, 0x5e, 0xf0, 0x14, }, }, { .name = "a-210", .msg = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", .len = 210, .exp = { 0xc9, 0xe2, 0xd9, 0x58, 0xf2, 0xdd, 0x3d, 0x97, 0x53, 0x8a, 0x1b, 0xac, 0x1b, 0x4e, 0xb3, 0x2e, 0x28, 0x23, 0x6b, 0x5d, 0xfc, 0xe0, 0x29, 0xfc, 0xc8, 0x73, 0xc0, 0xf2, 0x70, 0xe1, 0x3e, 0x9f, }, }}; for (size_t i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) { for (size_t len = 1; len < tests[i].len; len++) { // init xof sha3_xof_t xof; shake256_init(&xof); // absorb for (size_t ofs = 0; ofs < tests[i].len; ofs += len) { const size_t absorb_len = MIN(tests[i].len - ofs, len); if (!shake256_absorb(&xof, tests[i].msg + ofs, absorb_len)) { fprintf(stderr, "%s(\"%s\", %zu) failed: shake256_xof_absorb()\n", __func__, tests[i].name, len); return; } } // squeeze uint8_t got[32] = { 0 }; shake256_squeeze(&xof, got, sizeof(got)); // check if (memcmp(got, tests[i].exp, sizeof(got))) { fprintf(stderr, "%s(\"%s\", %zu) failed, got:\n", __func__, tests[i].name, len); dump_hex(stderr, got, 16); fprintf(stderr, "exp:\n"); dump_hex(stderr, tests[i].exp, 16); } } } } static void test_shake256(void) { static const struct { const char *name; // test name const uint8_t msg[256]; // test message const size_t len; // test message length const uint8_t exp[32]; // expected hash } tests[] = {{ .name = "empty", .msg = "", .len = 0, .exp = { 0x46, 0xb9, 0xdd, 0x2b, 0x0b, 0xa8, 0x8d, 0x13, 0x23, 0x3b, 0x3f, 0xeb, 0x74, 0x3e, 0xeb, 0x24, 0x3f, 0xcd, 0x52, 0xea, 0x62, 0xb8, 0x1b, 0x82, 0xb5, 0x0c, 0x27, 0x64, 0x6e, 0xd5, 0x76, 0x2f, }, }, { .name = "asdf", .msg = "asdf", .len = 4, .exp = { 0xf0, 0x0c, 0x15, 0x64, 0x33, 0x96, 0x61, 0x6a, 0x89, 0xa0, 0xcb, 0x79, 0x03, 0x9f, 0x74, 0x05, 0x75, 0xde, 0xfe, 0x9d, 0xbe, 0x30, 0x7c, 0xcc, 0xda, 0xf8, 0xae, 0x21, 0x0e, 0x1c, 0x9c, 0xc6, }, }, { .name = "a-134", .msg = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", .len = 134, .exp = { 0xf1, 0xe0, 0x3f, 0x37, 0x8e, 0xb7, 0x79, 0x04, 0xba, 0x15, 0xbb, 0x64, 0x2a, 0x84, 0xb9, 0x0d, 0xe5, 0x2e, 0x29, 0x3e, 0xaf, 0xc2, 0x7c, 0xef, 0x05, 0x88, 0x3b, 0x16, 0x56, 0xae, 0xc3, 0x41, }, }, { .name = "a-135", .msg = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", .len = 135, .exp = { 0x55, 0xb9, 0x91, 0xec, 0xe1, 0xe5, 0x67, 0xb6, 0xe7, 0xc2, 0xc7, 0x14, 0x44, 0x4d, 0xd2, 0x01, 0xcd, 0x51, 0xf4, 0xf3, 0x83, 0x2d, 0x08, 0xe1, 0xd2, 0x6b, 0xeb, 0xc6, 0x3e, 0x07, 0xa3, 0xd7, }, }, { .name = "a-136", .msg = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", .len = 136, .exp = { 0x8f, 0xcc, 0x5a, 0x08, 0xf0, 0xa1, 0xf6, 0x82, 0x7c, 0x9c, 0xf6, 0x4e, 0xe8, 0xd1, 0x6e, 0x04, 0x43, 0x10, 0x63, 0x59, 0xca, 0x6c, 0x8e, 0xfd, 0x23, 0x07, 0x59, 0x25, 0x6f, 0x44, 0x99, 0x6a, }, }, { .name = "ff-256", .msg = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, }, .len = 256, .exp = { 0x3f, 0x25, 0xdf, 0x0e, 0x37, 0x17, 0x14, 0xdf, 0xb0, 0xcc, 0x3d, 0x96, 0x17, 0xe1, 0xa0, 0x71, 0x75, 0xa0, 0xf0, 0x84, 0xc7, 0x00, 0x29, 0x23, 0x5c, 0x72, 0x7c, 0x5a, 0x68, 0x5e, 0xf0, 0x14, }, }, { .name = "a-210", .msg = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", .len = 210, .exp = { 0xc9, 0xe2, 0xd9, 0x58, 0xf2, 0xdd, 0x3d, 0x97, 0x53, 0x8a, 0x1b, 0xac, 0x1b, 0x4e, 0xb3, 0x2e, 0x28, 0x23, 0x6b, 0x5d, 0xfc, 0xe0, 0x29, 0xfc, 0xc8, 0x73, 0xc0, 0xf2, 0x70, 0xe1, 0x3e, 0x9f, }, }}; for (size_t i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) { for (size_t len = 1; len < tests[i].len; len++) { // run shake256 uint8_t got[32]; shake256(tests[i].msg, tests[i].len, got, sizeof(got)); // check if (memcmp(got, tests[i].exp, sizeof(got))) { fprintf(stderr, "%s(\"%s\", %zu) failed, got:\n", __func__, tests[i].name, len); dump_hex(stderr, got, 16); fprintf(stderr, "exp:\n"); dump_hex(stderr, tests[i].exp, 16); } } } } static void test_left_encode(void) { static const struct { const char *name; uint64_t val; uint8_t exp[9]; size_t exp_len; } tests[] = {{ .name = "zero", .val = 0, .exp = { 0x01, 0x00 }, .exp_len = 2, }, { .name = "120", .val = 120, .exp = { 0x01, 0x78 }, .exp_len = 2, }, { .name = "256", .val = 256, .exp = { 0x02, 0x01, 0x00 }, .exp_len = 3, }, { .name = "65535", .val = 65535, .exp = { 0x02, 0xff, 0xff }, .exp_len = 3, }, { .name = "65536", .val = 65536, .exp = { 0x03, 0x01, 0x00, 0x00 }, .exp_len = 4, }, { .name = "0xff00ff", .val = 0xff00ff, .exp = { 0x03, 0xff, 0x00, 0xff }, .exp_len = 4, }, { .name = "0x01000000", .val = 0x01000000, .exp = { 0x04, 0x01, 0x00, 0x00, 0x00 }, .exp_len = 5, }, { .name = "0xffffffff", .val = 0xffffffff, .exp = { 0x04, 0xff, 0xff, 0xff, 0xff }, .exp_len = 5, }, { .name = "0x0100000000", .val = 0x0100000000, .exp = { 0x05, 0x01, 0x00, 0x00, 0x00, 0x00 }, .exp_len = 6, }}; for (size_t i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) { uint8_t got[9]; const size_t got_len = left_encode(got, tests[i].val); // check length and data if (got_len != tests[i].exp_len) { fprintf(stderr, "test_left_encode(\"%s\") length check failed: got %zu, exp %zu:\n", tests[i].name, got_len, tests[i].exp_len); } else if (memcmp(got, tests[i].exp, got_len)) { fprintf(stderr, "test_left_encode(\"%s\") failed, got:\n", tests[i].name); dump_hex(stderr, got, got_len); fprintf(stderr, "exp:\n"); dump_hex(stderr, tests[i].exp, got_len); } } } static void test_right_encode(void) { static const struct { const char *name; uint64_t val; uint8_t exp[9]; size_t exp_len; } tests[] = {{ .name = "zero", .val = 0, .exp = { 0x00, 0x01 }, .exp_len = 2, }, { .name = "120", .val = 120, .exp = { 0x78, 0x01 }, .exp_len = 2, }, { .name = "256", .val = 256, .exp = { 0x01, 0x00, 0x02 }, .exp_len = 3, }, { .name = "65535", .val = 65535, .exp = { 0xff, 0xff, 0x02 }, .exp_len = 3, }, { .name = "65536", .val = 65536, .exp = { 0x01, 0x00, 0x00, 0x03 }, .exp_len = 4, }, { .name = "0xff00ff", .val = 0xff00ff, .exp = { 0xff, 0x00, 0xff, 0x03 }, .exp_len = 4, }, { .name = "0x01000000", .val = 0x01000000, .exp = { 0x01, 0x00, 0x00, 0x00, 0x04 }, .exp_len = 5, }, { .name = "0xffffffff", .val = 0xffffffff, .exp = { 0xff, 0xff, 0xff, 0xff, 0x04 }, .exp_len = 5, }, { .name = "0x0100000000", .val = 0x0100000000, .exp = { 0x01, 0x00, 0x00, 0x00, 0x00, 0x05 }, .exp_len = 6, }}; for (size_t i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) { uint8_t got[9]; const size_t got_len = right_encode(got, tests[i].val); // check length and data if (got_len != tests[i].exp_len) { fprintf(stderr, "test_right_encode(\"%s\") length check failed: got %zu, exp %zu:\n", tests[i].name, got_len, tests[i].exp_len); } else if (memcmp(got, tests[i].exp, got_len)) { fprintf(stderr, "test_right_encode(\"%s\") failed, got:\n", tests[i].name); dump_hex(stderr, got, got_len); fprintf(stderr, "exp:\n"); dump_hex(stderr, tests[i].exp, got_len); } } } static void test_encode_string_prefix(void) { static const struct { const char *name; uint8_t val[256]; size_t val_len; uint8_t exp[9]; size_t exp_len; } tests[] = {{ .name = "empty", .val = "", .val_len = 0, .exp = { 0x01, 0x00 }, .exp_len = 2, }, { .name = "4", .val = "asdf", .val_len = 4, .exp = { 0x01, 0x20 }, .exp_len = 2, }, { .name = "31", .val = "asdfasdfasdfasdfasdfasdfasdfasd", .val_len = 31, .exp = { 0x01, 0xf8 }, .exp_len = 2, }, { .name = "32", .val = "asdfasdfasdfasdfasdfasdfasdfasdf", .val_len = 32, .exp = { 0x02, 0x01, 0x00 }, .exp_len = 3, }, { .name = "33", .val = "asdfasdfasdfasdfasdfasdfasdfasdfa", .val_len = 33, .exp = { 0x02, 0x01, 0x08 }, .exp_len = 3, }}; for (size_t i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) { uint8_t got[9]; const size_t got_len = encode_string_prefix(got, tests[i].val_len); // check length and data if (got_len != tests[i].exp_len) { fprintf(stderr, "test_encode_string_prefix(\"%s\") length check failed: got %zu, exp %zu:\n", tests[i].name, got_len, tests[i].exp_len); } else if (memcmp(got, tests[i].exp, got_len)) { fprintf(stderr, "test_encode_string_prefix(\"%s\") failed, got:\n", tests[i].name); dump_hex(stderr, got, got_len); fprintf(stderr, "exp:\n"); dump_hex(stderr, tests[i].exp, got_len); } } } static void test_bytepad(void) { static const struct { const char *name; size_t data_len, width; uint8_t exp_prefix[9]; size_t exp_prefix_len, exp_pad_len; } tests[] = {{ .name = "0-10", .data_len = 0, .width = 10, .exp_prefix = { 0x01, 0x0a }, .exp_prefix_len = 2, .exp_pad_len = 8, }, { .name = "8-10", .data_len = 8, .width = 10, .exp_prefix = { 0x01, 0x0a }, .exp_prefix_len = 2, .exp_pad_len = 0, }, { .name = "9-10", .data_len = 9, .width = 10, .exp_prefix = { 0x01, 0x0a }, .exp_prefix_len = 2, .exp_pad_len = 9, }, { .name = "10-10", .data_len = 10, .width = 10, .exp_prefix = { 0x01, 0x0a }, .exp_prefix_len = 2, .exp_pad_len = 8, }, { .name = "11-10", .data_len = 11, .width = 10, .exp_prefix = { 0x01, 0x0a }, .exp_prefix_len = 2, .exp_pad_len = 7, }}; for (size_t i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) { const bytepad_t got = bytepad(tests[i].data_len, tests[i].width); // check prefix length and data if (got.prefix_len != tests[i].exp_prefix_len || got.pad_len != tests[i].exp_pad_len) { fprintf(stderr, "test_bytepad(\"%s\") length check failed:\n got: { %zu, %zu }\n exp: { %zu, %zu }\n", tests[i].name, got.prefix_len, got.pad_len, tests[i].exp_prefix_len, tests[i].exp_pad_len); } else if (memcmp(got.prefix, tests[i].exp_prefix, got.prefix_len)) { fprintf(stderr, "test_bytepad(\"%s\") failed, got:\n", tests[i].name); dump_hex(stderr, got.prefix, got.prefix_len); fprintf(stderr, "exp:\n"); dump_hex(stderr, tests[i].exp_prefix, got.prefix_len); } } } static void test_cshake128(void) { static const struct { const char *test_name; // test name const uint8_t name[256]; // nist function name const size_t name_len; // nist function name length const uint8_t custom[256]; // custom name const size_t custom_len; // custom name length const uint8_t msg[256]; // test message const size_t len; // test message length const uint8_t exp[32]; // expected hash } tests[] = {{ // src: https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/cSHAKE_samples.pdf .test_name = "cSHAKE Sample #1", .custom = "Email Signature", .custom_len = 15, .msg = { 0, 1, 2, 3 }, .len = 4, .exp = { 0xC1, 0xC3, 0x69, 0x25, 0xB6, 0x40, 0x9A, 0x04, 0xF1, 0xB5, 0x04, 0xFC, 0xBC, 0xA9, 0xD8, 0x2B, 0x40, 0x17, 0x27, 0x7C, 0xB5, 0xED, 0x2B, 0x20, 0x65, 0xFC, 0x1D, 0x38, 0x14, 0xD5, 0xAA, 0xF5, }, }, { // src: https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/cSHAKE_samples.pdf .test_name = "cSHAKE Sample #2", .custom = "Email Signature", .custom_len = 15, .msg = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, }, .len = 200, .exp = { 0xC5, 0x22, 0x1D, 0x50, 0xE4, 0xF8, 0x22, 0xD9, 0x6A, 0x2E, 0x88, 0x81, 0xA9, 0x61, 0x42, 0x0F, 0x29, 0x4B, 0x7B, 0x24, 0xFE, 0x3D, 0x20, 0x94, 0xBA, 0xED, 0x2C, 0x65, 0x24, 0xCC, 0x16, 0x6B, }, }}; for (size_t i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) { const cshake_params_t params = { .name = tests[i].name, .name_len = tests[i].name_len, .custom = tests[i].custom, .custom_len = tests[i].custom_len, }; // run uint8_t got[32]; cshake128(params, tests[i].msg, tests[i].len, got, sizeof(got)); // check if (memcmp(got, tests[i].exp, sizeof(got))) { fprintf(stderr, "test_cshake128(\"%s\") failed, got:\n", tests[i].test_name); dump_hex(stderr, got, 32); fprintf(stderr, "exp:\n"); dump_hex(stderr, tests[i].exp, 32); } } } static void test_cshake256(void) { static const struct { const char *test_name; // test name const uint8_t name[256]; // nist function name const size_t name_len; // nist function name length const uint8_t custom[256]; // custom name const size_t custom_len; // custom name length const uint8_t msg[256]; // test message const size_t len; // test message length const uint8_t exp[64]; // expected hash } tests[] = {{ // src: https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/cSHAKE_samples.pdf .test_name = "cSHAKE Sample #3", .custom = "Email Signature", .custom_len = 15, .msg = { 0, 1, 2, 3 }, .len = 4, .exp = { 0xD0, 0x08, 0x82, 0x8E, 0x2B, 0x80, 0xAC, 0x9D, 0x22, 0x18, 0xFF, 0xEE, 0x1D, 0x07, 0x0C, 0x48, 0xB8, 0xE4, 0xC8, 0x7B, 0xFF, 0x32, 0xC9, 0x69, 0x9D, 0x5B, 0x68, 0x96, 0xEE, 0xE0, 0xED, 0xD1, 0x64, 0x02, 0x0E, 0x2B, 0xE0, 0x56, 0x08, 0x58, 0xD9, 0xC0, 0x0C, 0x03, 0x7E, 0x34, 0xA9, 0x69, 0x37, 0xC5, 0x61, 0xA7, 0x4C, 0x41, 0x2B, 0xB4, 0xC7, 0x46, 0x46, 0x95, 0x27, 0x28, 0x1C, 0x8C, }, }, { // src: https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/cSHAKE_samples.pdf .test_name = "cSHAKE Sample #4", .custom = "Email Signature", .custom_len = 15, .msg = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, }, .len = 200, .exp = { 0x07, 0xDC, 0x27, 0xB1, 0x1E, 0x51, 0xFB, 0xAC, 0x75, 0xBC, 0x7B, 0x3C, 0x1D, 0x98, 0x3E, 0x8B, 0x4B, 0x85, 0xFB, 0x1D, 0xEF, 0xAF, 0x21, 0x89, 0x12, 0xAC, 0x86, 0x43, 0x02, 0x73, 0x09, 0x17, 0x27, 0xF4, 0x2B, 0x17, 0xED, 0x1D, 0xF6, 0x3E, 0x8E, 0xC1, 0x18, 0xF0, 0x4B, 0x23, 0x63, 0x3C, 0x1D, 0xFB, 0x15, 0x74, 0xC8, 0xFB, 0x55, 0xCB, 0x45, 0xDA, 0x8E, 0x25, 0xAF, 0xB0, 0x92, 0xBB, }, }}; for (size_t i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) { const cshake_params_t params = { .name = tests[i].name, .name_len = tests[i].name_len, .custom = tests[i].custom, .custom_len = tests[i].custom_len, }; // run uint8_t got[32]; cshake256(params, tests[i].msg, tests[i].len, got, sizeof(got)); // check if (memcmp(got, tests[i].exp, sizeof(got))) { fprintf(stderr, "test_cshake256(\"%s\") failed, got:\n", tests[i].test_name); dump_hex(stderr, got, 32); fprintf(stderr, "exp:\n"); dump_hex(stderr, tests[i].exp, 32); } } } static void test_kmac128(void) { static const struct { const char *name; // test name const uint8_t key[256]; // key const size_t key_len; // key length const uint8_t custom[256]; // custom name const size_t custom_len; // custom name length const uint8_t msg[256]; // test message const size_t len; // test message length const size_t dst_len; // output length const uint8_t exp[32]; // expected hash } tests[] = {{ // https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/KMAC_samples.pdf .name = "KMAC128 Sample #1", .key = { 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, }, .key_len = 32, .custom = "", .custom_len = 0, .msg = { 0, 1, 2, 3 }, .len = 4, .exp = { 0xE5, 0x78, 0x0B, 0x0D, 0x3E, 0xA6, 0xF7, 0xD3, 0xA4, 0x29, 0xC5, 0x70, 0x6A, 0xA4, 0x3A, 0x00, 0xFA, 0xDB, 0xD7, 0xD4, 0x96, 0x28, 0x83, 0x9E, 0x31, 0x87, 0x24, 0x3F, 0x45, 0x6E, 0xE1, 0x4E, }, }, { .name = "KMAC128 Sample #2", .key = { 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, }, .key_len = 32, .custom = "My Tagged Application", .custom_len = 21, .msg = { 0, 1, 2, 3 }, .len = 4, .exp = { 0x3B, 0x1F, 0xBA, 0x96, 0x3C, 0xD8, 0xB0, 0xB5, 0x9E, 0x8C, 0x1A, 0x6D, 0x71, 0x88, 0x8B, 0x71, 0x43, 0x65, 0x1A, 0xF8, 0xBA, 0x0A, 0x70, 0x70, 0xC0, 0x97, 0x9E, 0x28, 0x11, 0x32, 0x4A, 0xA5, }, }, { .name = "KMAC128 Sample #3", .key = { 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, }, .key_len = 32, .custom = "My Tagged Application", .custom_len = 21, .msg = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, }, .len = 200, .exp = { 0x1F, 0x5B, 0x4E, 0x6C, 0xCA, 0x02, 0x20, 0x9E, 0x0D, 0xCB, 0x5C, 0xA6, 0x35, 0xB8, 0x9A, 0x15, 0xE2, 0x71, 0xEC, 0xC7, 0x60, 0x07, 0x1D, 0xFD, 0x80, 0x5F, 0xAA, 0x38, 0xF9, 0x72, 0x92, 0x30, }, }}; for (size_t i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) { const kmac_params_t params = { .key = tests[i].key, .key_len = tests[i].key_len, .custom = tests[i].custom, .custom_len = tests[i].custom_len, }; // run uint8_t got[32]; kmac128(params, tests[i].msg, tests[i].len, got, sizeof(got)); // check if (memcmp(got, tests[i].exp, sizeof(got))) { fprintf(stderr, "test_kmac128(\"%s\") failed, got:\n", tests[i].name); dump_hex(stderr, got, 32); fprintf(stderr, "exp:\n"); dump_hex(stderr, tests[i].exp, 32); } } } static void test_kmac256(void) { static const struct { const char *name; // test name const uint8_t key[256]; // key const size_t key_len; // key length const uint8_t custom[256]; // custom name const size_t custom_len; // custom name length const uint8_t msg[256]; // test message const size_t len; // test message length const uint8_t exp[64]; // expected hash } tests[] = {{ // https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/KMAC_samples.pdf .name = "KMAC256 Sample #4", .key = { 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, }, .key_len = 32, .custom = "My Tagged Application", .custom_len = 21, .msg = { 0, 1, 2, 3 }, .len = 4, .exp = { 0x20, 0xC5, 0x70, 0xC3, 0x13, 0x46, 0xF7, 0x03, 0xC9, 0xAC, 0x36, 0xC6, 0x1C, 0x03, 0xCB, 0x64, 0xC3, 0x97, 0x0D, 0x0C, 0xFC, 0x78, 0x7E, 0x9B, 0x79, 0x59, 0x9D, 0x27, 0x3A, 0x68, 0xD2, 0xF7, 0xF6, 0x9D, 0x4C, 0xC3, 0xDE, 0x9D, 0x10, 0x4A, 0x35, 0x16, 0x89, 0xF2, 0x7C, 0xF6, 0xF5, 0x95, 0x1F, 0x01, 0x03, 0xF3, 0x3F, 0x4F, 0x24, 0x87, 0x10, 0x24, 0xD9, 0xC2, 0x77, 0x73, 0xA8, 0xDD, }, }, { .name = "KMAC256 Sample #5", .key = { 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, }, .key_len = 32, .custom = "", .custom_len = 0, .msg = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, }, .len = 200, .exp = { 0x75, 0x35, 0x8C, 0xF3, 0x9E, 0x41, 0x49, 0x4E, 0x94, 0x97, 0x07, 0x92, 0x7C, 0xEE, 0x0A, 0xF2, 0x0A, 0x3F, 0xF5, 0x53, 0x90, 0x4C, 0x86, 0xB0, 0x8F, 0x21, 0xCC, 0x41, 0x4B, 0xCF, 0xD6, 0x91, 0x58, 0x9D, 0x27, 0xCF, 0x5E, 0x15, 0x36, 0x9C, 0xBB, 0xFF, 0x8B, 0x9A, 0x4C, 0x2E, 0xB1, 0x78, 0x00, 0x85, 0x5D, 0x02, 0x35, 0xFF, 0x63, 0x5D, 0xA8, 0x25, 0x33, 0xEC, 0x6B, 0x75, 0x9B, 0x69, }, }, { .name = "KMAC256 Sample #6", .key = { 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, }, .key_len = 32, .custom = "My Tagged Application", .custom_len = 21, .msg = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, }, .len = 200, .exp = { 0xB5, 0x86, 0x18, 0xF7, 0x1F, 0x92, 0xE1, 0xD5, 0x6C, 0x1B, 0x8C, 0x55, 0xDD, 0xD7, 0xCD, 0x18, 0x8B, 0x97, 0xB4, 0xCA, 0x4D, 0x99, 0x83, 0x1E, 0xB2, 0x69, 0x9A, 0x83, 0x7D, 0xA2, 0xE4, 0xD9, 0x70, 0xFB, 0xAC, 0xFD, 0xE5, 0x00, 0x33, 0xAE, 0xA5, 0x85, 0xF1, 0xA2, 0x70, 0x85, 0x10, 0xC3, 0x2D, 0x07, 0x88, 0x08, 0x01, 0xBD, 0x18, 0x28, 0x98, 0xFE, 0x47, 0x68, 0x76, 0xFC, 0x89, 0x65, }, }}; for (size_t i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) { const kmac_params_t params = { .key = tests[i].key, .key_len = tests[i].key_len, .custom = tests[i].custom, .custom_len = tests[i].custom_len, }; // run uint8_t got[64]; kmac256(params, tests[i].msg, tests[i].len, got, sizeof(got)); // check if (memcmp(got, tests[i].exp, sizeof(got))) { fprintf(stderr, "test_kmac256(\"%s\") failed, got:\n", tests[i].name); dump_hex(stderr, got, 32); fprintf(stderr, "exp:\n"); dump_hex(stderr, tests[i].exp, 32); } } } static void test_kmac128_xof(void) { static const struct { const char *name; // test name const uint8_t key[256]; // key const size_t key_len; // key length const uint8_t custom[256]; // custom name const size_t custom_len; // custom name length const uint8_t msg[256]; // test message const size_t len; // test message length const size_t dst_len; // output length const uint8_t exp[32]; // expected hash } tests[] = {{ // https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/KMACXOF_samples.pdf .name = "KMACXOF128 Sample #1", .key = { 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, }, .key_len = 32, .custom = "", .custom_len = 0, .msg = { 0, 1, 2, 3 }, .len = 4, .exp = { 0xCD, 0x83, 0x74, 0x0B, 0xBD, 0x92, 0xCC, 0xC8, 0xCF, 0x03, 0x2B, 0x14, 0x81, 0xA0, 0xF4, 0x46, 0x0E, 0x7C, 0xA9, 0xDD, 0x12, 0xB0, 0x8A, 0x0C, 0x40, 0x31, 0x17, 0x8B, 0xAC, 0xD6, 0xEC, 0x35, }, }, { .name = "KMACXOF128 Sample #2", .key = { 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, }, .key_len = 32, .custom = "My Tagged Application", .custom_len = 21, .msg = { 0, 1, 2, 3 }, .len = 4, .exp = { 0x31, 0xA4, 0x45, 0x27, 0xB4, 0xED, 0x9F, 0x5C, 0x61, 0x01, 0xD1, 0x1D, 0xE6, 0xD2, 0x6F, 0x06, 0x20, 0xAA, 0x5C, 0x34, 0x1D, 0xEF, 0x41, 0x29, 0x96, 0x57, 0xFE, 0x9D, 0xF1, 0xA3, 0xB1, 0x6C, }, }, { .name = "KMACXOF128 Sample #3", .key = { 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, }, .key_len = 32, .custom = "My Tagged Application", .custom_len = 21, .msg = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, }, .len = 200, .exp = { 0x47, 0x02, 0x6C, 0x7C, 0xD7, 0x93, 0x08, 0x4A, 0xA0, 0x28, 0x3C, 0x25, 0x3E, 0xF6, 0x58, 0x49, 0x0C, 0x0D, 0xB6, 0x14, 0x38, 0xB8, 0x32, 0x6F, 0xE9, 0xBD, 0xDF, 0x28, 0x1B, 0x83, 0xAE, 0x0F, }, }}; for (size_t i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) { const kmac_params_t params = { .key = tests[i].key, .key_len = tests[i].key_len, .custom = tests[i].custom, .custom_len = tests[i].custom_len, }; // run uint8_t got[32]; kmac128_xof_once(params, tests[i].msg, tests[i].len, got, sizeof(got)); // check if (memcmp(got, tests[i].exp, sizeof(got))) { fprintf(stderr, "test_kmac128_xof(\"%s\") failed, got:\n", tests[i].name); dump_hex(stderr, got, 32); fprintf(stderr, "exp:\n"); dump_hex(stderr, tests[i].exp, 32); } } } static void test_kmac256_xof(void) { static const struct { const char *name; // test name const uint8_t key[256]; // key const size_t key_len; // key length const uint8_t custom[256]; // custom name const size_t custom_len; // custom name length const uint8_t msg[256]; // test message const size_t len; // test message length const size_t dst_len; // output length const uint8_t exp[64]; // expected hash } tests[] = {{ // https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/KMACXOF_samples.pdf .name = "KMACXOF Sample #4", .key = { 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, }, .key_len = 32, .custom = "My Tagged Application", .custom_len = 21, .msg = { 0, 1, 2, 3 }, .len = 4, .exp = { 0x17, 0x55, 0x13, 0x3F, 0x15, 0x34, 0x75, 0x2A, 0xAD, 0x07, 0x48, 0xF2, 0xC7, 0x06, 0xFB, 0x5C, 0x78, 0x45, 0x12, 0xCA, 0xB8, 0x35, 0xCD, 0x15, 0x67, 0x6B, 0x16, 0xC0, 0xC6, 0x64, 0x7F, 0xA9, 0x6F, 0xAA, 0x7A, 0xF6, 0x34, 0xA0, 0xBF, 0x8F, 0xF6, 0xDF, 0x39, 0x37, 0x4F, 0xA0, 0x0F, 0xAD, 0x9A, 0x39, 0xE3, 0x22, 0xA7, 0xC9, 0x20, 0x65, 0xA6, 0x4E, 0xB1, 0xFB, 0x08, 0x01, 0xEB, 0x2B, }, }, { .name = "KMACXOF Sample #5", .key = { 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, }, .key_len = 32, .custom = "", .custom_len = 0, .msg = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, }, .len = 200, .exp = { 0xFF, 0x7B, 0x17, 0x1F, 0x1E, 0x8A, 0x2B, 0x24, 0x68, 0x3E, 0xED, 0x37, 0x83, 0x0E, 0xE7, 0x97, 0x53, 0x8B, 0xA8, 0xDC, 0x56, 0x3F, 0x6D, 0xA1, 0xE6, 0x67, 0x39, 0x1A, 0x75, 0xED, 0xC0, 0x2C, 0xA6, 0x33, 0x07, 0x9F, 0x81, 0xCE, 0x12, 0xA2, 0x5F, 0x45, 0x61, 0x5E, 0xC8, 0x99, 0x72, 0x03, 0x1D, 0x18, 0x33, 0x73, 0x31, 0xD2, 0x4C, 0xEB, 0x8F, 0x8C, 0xA8, 0xE6, 0xA1, 0x9F, 0xD9, 0x8B, }, }, { .name = "KMACXOF Sample #6", .key = { 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, }, .key_len = 32, .custom = "My Tagged Application", .custom_len = 21, .msg = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, }, .len = 200, .exp = { 0xD5, 0xBE, 0x73, 0x1C, 0x95, 0x4E, 0xD7, 0x73, 0x28, 0x46, 0xBB, 0x59, 0xDB, 0xE3, 0xA8, 0xE3, 0x0F, 0x83, 0xE7, 0x7A, 0x4B, 0xFF, 0x44, 0x59, 0xF2, 0xF1, 0xC2, 0xB4, 0xEC, 0xEB, 0xB8, 0xCE, 0x67, 0xBA, 0x01, 0xC6, 0x2E, 0x8A, 0xB8, 0x57, 0x8D, 0x2D, 0x49, 0x9B, 0xD1, 0xBB, 0x27, 0x67, 0x68, 0x78, 0x11, 0x90, 0x02, 0x0A, 0x30, 0x6A, 0x97, 0xDE, 0x28, 0x1D, 0xCC, 0x30, 0x30, 0x5D, }, }}; for (size_t i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) { const kmac_params_t params = { .key = tests[i].key, .key_len = tests[i].key_len, .custom = tests[i].custom, .custom_len = tests[i].custom_len, }; // run uint8_t got[64]; kmac256_xof_once(params, tests[i].msg, tests[i].len, got, sizeof(got)); // check if (memcmp(got, tests[i].exp, sizeof(got))) { fprintf(stderr, "test_kmac256_xof(\"%s\") failed, got:\n", tests[i].name); dump_hex(stderr, got, 32); fprintf(stderr, "exp:\n"); dump_hex(stderr, tests[i].exp, 32); } } } static void test_tuplehash128(void) { static const struct { const char *name; // test name const uint8_t data[256]; // string data const size_t pairs[10]; // string ofs/len pairs const size_t num_strs; // number of strings const uint8_t custom[256]; // custom name const size_t custom_len; // custom name length const uint8_t exp[32]; // expected hash } tests[] = {{ // https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/TupleHash_samples.pdf .name = "TupleHash Sample #1", .data = { 0x00, 0x01, 0x02, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15 }, .pairs = { 0, 3, 3, 6, }, .num_strs = 2, .custom = "", .custom_len = 0, .exp = { 0xC5, 0xD8, 0x78, 0x6C, 0x1A, 0xFB, 0x9B, 0x82, 0x11, 0x1A, 0xB3, 0x4B, 0x65, 0xB2, 0xC0, 0x04, 0x8F, 0xA6, 0x4E, 0x6D, 0x48, 0xE2, 0x63, 0x26, 0x4C, 0xE1, 0x70, 0x7D, 0x3F, 0xFC, 0x8E, 0xD1, }, }, { .name = "TupleHash Sample #2", .data = { 0x00, 0x01, 0x02, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15 }, .pairs = { 0, 3, 3, 6, }, .num_strs = 2, .custom = "My Tuple App", .custom_len = 12, .exp = { 0x75, 0xCD, 0xB2, 0x0F, 0xF4, 0xDB, 0x11, 0x54, 0xE8, 0x41, 0xD7, 0x58, 0xE2, 0x41, 0x60, 0xC5, 0x4B, 0xAE, 0x86, 0xEB, 0x8C, 0x13, 0xE7, 0xF5, 0xF4, 0x0E, 0xB3, 0x55, 0x88, 0xE9, 0x6D, 0xFB, }, }, { .name = "TupleHash Sample #3", .data = { 0x00, 0x01, 0x02, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, }, .pairs = { 0, 3, 3, 6, 9, 9, }, .num_strs = 3, .custom = "My Tuple App", .custom_len = 12, .exp = { 0xE6, 0x0F, 0x20, 0x2C, 0x89, 0xA2, 0x63, 0x1E, 0xDA, 0x8D, 0x4C, 0x58, 0x8C, 0xA5, 0xFD, 0x07, 0xF3, 0x9E, 0x51, 0x51, 0x99, 0x8D, 0xEC, 0xCF, 0x97, 0x3A, 0xDB, 0x38, 0x04, 0xBB, 0x6E, 0x84, }, }}; for (size_t i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) { // build strings tuplehash_str_t strs[10] = { 0 }; for (size_t j = 0; j < tests[i].num_strs; j++) { strs[j].ptr = tests[i].data + tests[i].pairs[2 * j]; strs[j].len = tests[i].pairs[2 * j + 1]; } // build params const tuplehash_params_t params = { .strs = strs, .num_strs = tests[i].num_strs, .custom = tests[i].custom, .custom_len = tests[i].custom_len, }; // run uint8_t got[32]; tuplehash128(params, got, sizeof(got)); // check if (memcmp(got, tests[i].exp, sizeof(got))) { fprintf(stderr, "test_tuplehash128(\"%s\") failed, got:\n", tests[i].name); dump_hex(stderr, got, 32); fprintf(stderr, "exp:\n"); dump_hex(stderr, tests[i].exp, 32); } } } static void test_tuplehash128_xof(void) { static const struct { const char *name; // test name const uint8_t data[256]; // string data const size_t pairs[10]; // string ofs/len pairs const size_t num_strs; // number of strings const uint8_t custom[256]; // custom name const size_t custom_len; // custom name length const uint8_t exp[32]; // expected hash } tests[] = {{ // src: https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/TupleHashXOF_samples.pdf .name = "TupleHashXOF Sample #1", .data = { 0x00, 0x01, 0x02, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15 }, .pairs = { 0, 3, 3, 6, }, .num_strs = 2, .custom = "", .custom_len = 0, .exp = { 0x2F, 0x10, 0x3C, 0xD7, 0xC3, 0x23, 0x20, 0x35, 0x34, 0x95, 0xC6, 0x8D, 0xE1, 0xA8, 0x12, 0x92, 0x45, 0xC6, 0x32, 0x5F, 0x6F, 0x2A, 0x3D, 0x60, 0x8D, 0x92, 0x17, 0x9C, 0x96, 0xE6, 0x84, 0x88, }, }, { .name = "TupleHashXOF Sample #2", .data = { 0x00, 0x01, 0x02, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15 }, .pairs = { 0, 3, 3, 6, }, .num_strs = 2, .custom = "My Tuple App", .custom_len = 12, .exp = { 0x3F, 0xC8, 0xAD, 0x69, 0x45, 0x31, 0x28, 0x29, 0x28, 0x59, 0xA1, 0x8B, 0x6C, 0x67, 0xD7, 0xAD, 0x85, 0xF0, 0x1B, 0x32, 0x81, 0x5E, 0x22, 0xCE, 0x83, 0x9C, 0x49, 0xEC, 0x37, 0x4E, 0x9B, 0x9A, }, }, { .name = "TupleHashXOF Sample #3", .data = { 0x00, 0x01, 0x02, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, }, .pairs = { 0, 3, 3, 6, 9, 9, }, .num_strs = 3, .custom = "My Tuple App", .custom_len = 12, .exp = { 0x90, 0x0F, 0xE1, 0x6C, 0xAD, 0x09, 0x8D, 0x28, 0xE7, 0x4D, 0x63, 0x2E, 0xD8, 0x52, 0xF9, 0x9D, 0xAA, 0xB7, 0xF7, 0xDF, 0x4D, 0x99, 0xE7, 0x75, 0x65, 0x78, 0x85, 0xB4, 0xBF, 0x76, 0xD6, 0xF8, }, }}; for (size_t i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) { // build strings tuplehash_str_t strs[10] = { 0 }; for (size_t j = 0; j < tests[i].num_strs; j++) { strs[j].ptr = tests[i].data + tests[i].pairs[2 * j]; strs[j].len = tests[i].pairs[2 * j + 1]; } // build params const tuplehash_params_t params = { .strs = strs, .num_strs = tests[i].num_strs, .custom = tests[i].custom, .custom_len = tests[i].custom_len, }; // run uint8_t got[32]; tuplehash128_xof_once(params, got, sizeof(got)); // check if (memcmp(got, tests[i].exp, sizeof(got))) { fprintf(stderr, "test_tuplehash128_xof(\"%s\") failed, got:\n", tests[i].name); dump_hex(stderr, got, 32); fprintf(stderr, "exp:\n"); dump_hex(stderr, tests[i].exp, 32); } } } static void test_tuplehash256(void) { static const struct { const char *name; // test name const uint8_t data[256]; // string data const size_t pairs[10]; // string ofs/len pairs const size_t num_strs; // number of strings const uint8_t custom[256]; // custom name const size_t custom_len; // custom name length const uint8_t exp[64]; // expected hash } tests[] = {{ // https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/TupleHash_samples.pdf .name = "TupleHash Sample #4", .data = { 0x00, 0x01, 0x02, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15 }, .pairs = { 0, 3, 3, 6, }, .num_strs = 2, .custom = "", .custom_len = 0, .exp = { 0xCF, 0xB7, 0x05, 0x8C, 0xAC, 0xA5, 0xE6, 0x68, 0xF8, 0x1A, 0x12, 0xA2, 0x0A, 0x21, 0x95, 0xCE, 0x97, 0xA9, 0x25, 0xF1, 0xDB, 0xA3, 0xE7, 0x44, 0x9A, 0x56, 0xF8, 0x22, 0x01, 0xEC, 0x60, 0x73, 0x11, 0xAC, 0x26, 0x96, 0xB1, 0xAB, 0x5E, 0xA2, 0x35, 0x2D, 0xF1, 0x42, 0x3B, 0xDE, 0x7B, 0xD4, 0xBB, 0x78, 0xC9, 0xAE, 0xD1, 0xA8, 0x53, 0xC7, 0x86, 0x72, 0xF9, 0xEB, 0x23, 0xBB, 0xE1, 0x94, }, }, { .name = "TupleHash Sample #5", .data = { 0x00, 0x01, 0x02, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15 }, .pairs = { 0, 3, 3, 6, }, .num_strs = 2, .custom = "My Tuple App", .custom_len = 12, .exp = { 0x14, 0x7C, 0x21, 0x91, 0xD5, 0xED, 0x7E, 0xFD, 0x98, 0xDB, 0xD9, 0x6D, 0x7A, 0xB5, 0xA1, 0x16, 0x92, 0x57, 0x6F, 0x5F, 0xE2, 0xA5, 0x06, 0x5F, 0x3E, 0x33, 0xDE, 0x6B, 0xBA, 0x9F, 0x3A, 0xA1, 0xC4, 0xE9, 0xA0, 0x68, 0xA2, 0x89, 0xC6, 0x1C, 0x95, 0xAA, 0xB3, 0x0A, 0xEE, 0x1E, 0x41, 0x0B, 0x0B, 0x60, 0x7D, 0xE3, 0x62, 0x0E, 0x24, 0xA4, 0xE3, 0xBF, 0x98, 0x52, 0xA1, 0xD4, 0x36, 0x7E, }, }, { .name = "TupleHash Sample #6", .data = { 0x00, 0x01, 0x02, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, }, .pairs = { 0, 3, 3, 6, 9, 9, }, .num_strs = 3, .custom = "My Tuple App", .custom_len = 12, .exp = { 0x45, 0x00, 0x0B, 0xE6, 0x3F, 0x9B, 0x6B, 0xFD, 0x89, 0xF5, 0x47, 0x17, 0x67, 0x0F, 0x69, 0xA9, 0xBC, 0x76, 0x35, 0x91, 0xA4, 0xF0, 0x5C, 0x50, 0xD6, 0x88, 0x91, 0xA7, 0x44, 0xBC, 0xC6, 0xE7, 0xD6, 0xD5, 0xB5, 0xE8, 0x2C, 0x01, 0x8D, 0xA9, 0x99, 0xED, 0x35, 0xB0, 0xBB, 0x49, 0xC9, 0x67, 0x8E, 0x52, 0x6A, 0xBD, 0x8E, 0x85, 0xC1, 0x3E, 0xD2, 0x54, 0x02, 0x1D, 0xB9, 0xE7, 0x90, 0xCE, }, }}; for (size_t i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) { // build strings tuplehash_str_t strs[10] = { 0 }; for (size_t j = 0; j < tests[i].num_strs; j++) { strs[j].ptr = tests[i].data + tests[i].pairs[2 * j]; strs[j].len = tests[i].pairs[2 * j + 1]; } // build params const tuplehash_params_t params = { .strs = strs, .num_strs = tests[i].num_strs, .custom = tests[i].custom, .custom_len = tests[i].custom_len, }; // run uint8_t got[64]; tuplehash256(params, got, sizeof(got)); // check if (memcmp(got, tests[i].exp, sizeof(got))) { fprintf(stderr, "test_tuplehash256(\"%s\") failed, got:\n", tests[i].name); dump_hex(stderr, got, 32); fprintf(stderr, "exp:\n"); dump_hex(stderr, tests[i].exp, 32); } } } static void test_tuplehash256_xof(void) { static const struct { const char *name; // test name const uint8_t data[256]; // string data const size_t pairs[10]; // string ofs/len pairs const size_t num_strs; // number of strings const uint8_t custom[256]; // custom name const size_t custom_len; // custom name length const uint8_t exp[64]; // expected hash } tests[] = {{ // src: https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/TupleHashXOF_samples.pdf .name = "TupleHashXOF Sample #4", .data = { 0x00, 0x01, 0x02, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15 }, .pairs = { 0, 3, 3, 6, }, .num_strs = 2, .custom = "", .custom_len = 0, .exp = { 0x03, 0xDE, 0xD4, 0x61, 0x0E, 0xD6, 0x45, 0x0A, 0x1E, 0x3F, 0x8B, 0xC4, 0x49, 0x51, 0xD1, 0x4F, 0xBC, 0x38, 0x4A, 0xB0, 0xEF, 0xE5, 0x7B, 0x00, 0x0D, 0xF6, 0xB6, 0xDF, 0x5A, 0xAE, 0x7C, 0xD5, 0x68, 0xE7, 0x73, 0x77, 0xDA, 0xF1, 0x3F, 0x37, 0xEC, 0x75, 0xCF, 0x5F, 0xC5, 0x98, 0xB6, 0x84, 0x1D, 0x51, 0xDD, 0x20, 0x7C, 0x99, 0x1C, 0xD4, 0x5D, 0x21, 0x0B, 0xA6, 0x0A, 0xC5, 0x2E, 0xB9, }, }, { .name = "TupleHashXOF Sample #5", .data = { 0x00, 0x01, 0x02, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15 }, .pairs = { 0, 3, 3, 6, }, .num_strs = 2, .custom = "My Tuple App", .custom_len = 12, .exp = { 0x64, 0x83, 0xCB, 0x3C, 0x99, 0x52, 0xEB, 0x20, 0xE8, 0x30, 0xAF, 0x47, 0x85, 0x85, 0x1F, 0xC5, 0x97, 0xEE, 0x3B, 0xF9, 0x3B, 0xB7, 0x60, 0x2C, 0x0E, 0xF6, 0xA6, 0x5D, 0x74, 0x1A, 0xEC, 0xA7, 0xE6, 0x3C, 0x3B, 0x12, 0x89, 0x81, 0xAA, 0x05, 0xC6, 0xD2, 0x74, 0x38, 0xC7, 0x9D, 0x27, 0x54, 0xBB, 0x1B, 0x71, 0x91, 0xF1, 0x25, 0xD6, 0x62, 0x0F, 0xCA, 0x12, 0xCE, 0x65, 0x8B, 0x24, 0x42, }, }, { .name = "TupleHashXOF Sample #6", .data = { 0x00, 0x01, 0x02, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, }, .pairs = { 0, 3, 3, 6, 9, 9, }, .num_strs = 3, .custom = "My Tuple App", .custom_len = 12, .exp = { 0x0C, 0x59, 0xB1, 0x14, 0x64, 0xF2, 0x33, 0x6C, 0x34, 0x66, 0x3E, 0xD5, 0x1B, 0x2B, 0x95, 0x0B, 0xEC, 0x74, 0x36, 0x10, 0x85, 0x6F, 0x36, 0xC2, 0x8D, 0x1D, 0x08, 0x8D, 0x8A, 0x24, 0x46, 0x28, 0x4D, 0xD0, 0x98, 0x30, 0xA6, 0xA1, 0x78, 0xDC, 0x75, 0x23, 0x76, 0x19, 0x9F, 0xAE, 0x93, 0x5D, 0x86, 0xCF, 0xDE, 0xE5, 0x91, 0x3D, 0x49, 0x22, 0xDF, 0xD3, 0x69, 0xB6, 0x6A, 0x53, 0xC8, 0x97, }, }}; for (size_t i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) { // build strings tuplehash_str_t strs[10] = { 0 }; for (size_t j = 0; j < tests[i].num_strs; j++) { strs[j].ptr = tests[i].data + tests[i].pairs[2 * j]; strs[j].len = tests[i].pairs[2 * j + 1]; } // build params const tuplehash_params_t params = { .strs = strs, .num_strs = tests[i].num_strs, .custom = tests[i].custom, .custom_len = tests[i].custom_len, }; // run uint8_t got[64]; tuplehash256_xof_once(params, got, sizeof(got)); // check if (memcmp(got, tests[i].exp, sizeof(got))) { fprintf(stderr, "test_tuplehash256_xof(\"%s\") failed, got:\n", tests[i].name); dump_hex(stderr, got, 32); fprintf(stderr, "exp:\n"); dump_hex(stderr, tests[i].exp, 32); } } } static void test_parallelhash128(void) { static const struct { const char *name; // test name const uint8_t custom[256]; // custom name const size_t custom_len; // custom name length const size_t block_len; // block size, in bytes const uint8_t msg[256]; // input data const size_t len; // message length, in bytes const uint8_t exp[32]; // expected hash } tests[] = {{ // src: https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/ParallelHash_samples.pdf .name = "ParallelHash Sample #1", .custom = "", .custom_len = 0, .block_len = 8, .msg = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, }, .len = 24, .exp = { 0xBA, 0x8D, 0xC1, 0xD1, 0xD9, 0x79, 0x33, 0x1D, 0x3F, 0x81, 0x36, 0x03, 0xC6, 0x7F, 0x72, 0x60, 0x9A, 0xB5, 0xE4, 0x4B, 0x94, 0xA0, 0xB8, 0xF9, 0xAF, 0x46, 0x51, 0x44, 0x54, 0xA2, 0xB4, 0xF5, }, }, { .name = "ParallelHash Sample #2", .custom = "Parallel Data", .custom_len = 13, .block_len = 8, .msg = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, }, .len = 24, .exp = { 0xFC, 0x48, 0x4D, 0xCB, 0x3F, 0x84, 0xDC, 0xEE, 0xDC, 0x35, 0x34, 0x38, 0x15, 0x1B, 0xEE, 0x58, 0x15, 0x7D, 0x6E, 0xFE, 0xD0, 0x44, 0x5A, 0x81, 0xF1, 0x65, 0xE4, 0x95, 0x79, 0x5B, 0x72, 0x06, }, }, { .name = "ParallelHash Sample #3", .custom = "Parallel Data", .custom_len = 13, .block_len = 12, .msg = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, }, .len = 72, .exp = { 0xF7, 0xFD, 0x53, 0x12, 0x89, 0x6C, 0x66, 0x85, 0xC8, 0x28, 0xAF, 0x7E, 0x2A, 0xDB, 0x97, 0xE3, 0x93, 0xE7, 0xF8, 0xD5, 0x4E, 0x3C, 0x2E, 0xA4, 0xB9, 0x5E, 0x5A, 0xCA, 0x37, 0x96, 0xE8, 0xFC, }, }}; for (size_t i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) { // build params const parallelhash_params_t params = { .block_len = tests[i].block_len, .custom = tests[i].custom, .custom_len = tests[i].custom_len, }; // run uint8_t got[32]; parallelhash128(params, tests[i].msg, tests[i].len, got, sizeof(got)); // check if (memcmp(got, tests[i].exp, sizeof(got))) { fprintf(stderr, "test_parallelhash128(\"%s\") failed, got:\n", tests[i].name); dump_hex(stderr, got, 32); fprintf(stderr, "exp:\n"); dump_hex(stderr, tests[i].exp, 32); } } } static void test_parallelhash128_xof(void) { static const struct { const char *name; // test name const uint8_t custom[256]; // custom name const size_t custom_len; // custom name length const size_t block_len; // block size, in bytes const uint8_t msg[256]; // input data const size_t len; // message length, in bytes const uint8_t exp[32]; // expected hash } tests[] = {{ // src: https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/ParallelHashXOF_samples.pdf .name = "ParallelHashXOF Sample #1", .custom = "", .custom_len = 0, .block_len = 8, .msg = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, }, .len = 24, .exp = { 0xFE, 0x47, 0xD6, 0x61, 0xE4, 0x9F, 0xFE, 0x5B, 0x7D, 0x99, 0x99, 0x22, 0xC0, 0x62, 0x35, 0x67, 0x50, 0xCA, 0xF5, 0x52, 0x98, 0x5B, 0x8E, 0x8C, 0xE6, 0x66, 0x7F, 0x27, 0x27, 0xC3, 0xC8, 0xD3, }, }, { .name = "ParallelHashXOF Sample #2", .custom = "Parallel Data", .custom_len = 13, .block_len = 8, .msg = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, }, .len = 24, .exp = { 0xEA, 0x2A, 0x79, 0x31, 0x40, 0x82, 0x0F, 0x7A, 0x12, 0x8B, 0x8E, 0xB7, 0x0A, 0x94, 0x39, 0xF9, 0x32, 0x57, 0xC6, 0xE6, 0xE7, 0x9B, 0x4A, 0x54, 0x0D, 0x29, 0x1D, 0x6D, 0xAE, 0x70, 0x98, 0xD7, }, }, { .name = "ParallelHashXOF Sample #3", .custom = "Parallel Data", .custom_len = 13, .block_len = 12, .msg = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, }, .len = 72, .exp = { 0x01, 0x27, 0xAD, 0x97, 0x72, 0xAB, 0x90, 0x46, 0x91, 0x98, 0x7F, 0xCC, 0x4A, 0x24, 0x88, 0x8F, 0x34, 0x1F, 0xA0, 0xDB, 0x21, 0x45, 0xE8, 0x72, 0xD4, 0xEF, 0xD2, 0x55, 0x37, 0x66, 0x02, 0xF0, }, }}; for (size_t i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) { // build params const parallelhash_params_t params = { .block_len = tests[i].block_len, .custom = tests[i].custom, .custom_len = tests[i].custom_len, }; // run uint8_t got[32]; parallelhash128_xof_once(params, tests[i].msg, tests[i].len, got, sizeof(got)); // check if (memcmp(got, tests[i].exp, sizeof(got))) { fprintf(stderr, "test_parallelhash128_xof(\"%s\") failed, got:\n", tests[i].name); dump_hex(stderr, got, 32); fprintf(stderr, "exp:\n"); dump_hex(stderr, tests[i].exp, 32); } } } static void test_parallelhash256(void) { static const struct { const char *name; // test name const uint8_t custom[256]; // custom name const size_t custom_len; // custom name length const size_t block_len; // block size, in bytes const uint8_t msg[256]; // input data const size_t len; // message length, in bytes const uint8_t exp[64]; // expected hash } tests[] = {{ // src: https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/ParallelHash_samples.pdf .name = "ParallelHash Sample #4", .custom = "", .custom_len = 0, .block_len = 8, .msg = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, }, .len = 24, .exp = { 0xBC, 0x1E, 0xF1, 0x24, 0xDA, 0x34, 0x49, 0x5E, 0x94, 0x8E, 0xAD, 0x20, 0x7D, 0xD9, 0x84, 0x22, 0x35, 0xDA, 0x43, 0x2D, 0x2B, 0xBC, 0x54, 0xB4, 0xC1, 0x10, 0xE6, 0x4C, 0x45, 0x11, 0x05, 0x53, 0x1B, 0x7F, 0x2A, 0x3E, 0x0C, 0xE0, 0x55, 0xC0, 0x28, 0x05, 0xE7, 0xC2, 0xDE, 0x1F, 0xB7, 0x46, 0xAF, 0x97, 0xA1, 0xDD, 0x01, 0xF4, 0x3B, 0x82, 0x4E, 0x31, 0xB8, 0x76, 0x12, 0x41, 0x04, 0x29, }, }, { .name = "ParallelHash Sample #5", .custom = "Parallel Data", .custom_len = 13, .block_len = 8, .msg = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, }, .len = 24, .exp = { 0xCD, 0xF1, 0x52, 0x89, 0xB5, 0x4F, 0x62, 0x12, 0xB4, 0xBC, 0x27, 0x05, 0x28, 0xB4, 0x95, 0x26, 0x00, 0x6D, 0xD9, 0xB5, 0x4E, 0x2B, 0x6A, 0xDD, 0x1E, 0xF6, 0x90, 0x0D, 0xDA, 0x39, 0x63, 0xBB, 0x33, 0xA7, 0x24, 0x91, 0xF2, 0x36, 0x96, 0x9C, 0xA8, 0xAF, 0xAE, 0xA2, 0x9C, 0x68, 0x2D, 0x47, 0xA3, 0x93, 0xC0, 0x65, 0xB3, 0x8E, 0x29, 0xFA, 0xE6, 0x51, 0xA2, 0x09, 0x1C, 0x83, 0x31, 0x10, }, }, { .name = "ParallelHash Sample #6", .custom = "Parallel Data", .custom_len = 13, .block_len = 12, .msg = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, }, .len = 72, .exp = { 0x69, 0xD0, 0xFC, 0xB7, 0x64, 0xEA, 0x05, 0x5D, 0xD0, 0x93, 0x34, 0xBC, 0x60, 0x21, 0xCB, 0x7E, 0x4B, 0x61, 0x34, 0x8D, 0xFF, 0x37, 0x5D, 0xA2, 0x62, 0x67, 0x1C, 0xDE, 0xC3, 0xEF, 0xFA, 0x8D, 0x1B, 0x45, 0x68, 0xA6, 0xCC, 0xE1, 0x6B, 0x1C, 0xAD, 0x94, 0x6D, 0xDD, 0xE2, 0x7F, 0x6C, 0xE2, 0xB8, 0xDE, 0xE4, 0xCD, 0x1B, 0x24, 0x85, 0x1E, 0xBF, 0x00, 0xEB, 0x90, 0xD4, 0x38, 0x13, 0xE9, }, }}; for (size_t i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) { // build params const parallelhash_params_t params = { .block_len = tests[i].block_len, .custom = tests[i].custom, .custom_len = tests[i].custom_len, }; // run uint8_t got[64]; parallelhash256(params, tests[i].msg, tests[i].len, got, sizeof(got)); // check if (memcmp(got, tests[i].exp, sizeof(got))) { fprintf(stderr, "test_parallelhash256(\"%s\") failed, got:\n", tests[i].name); dump_hex(stderr, got, sizeof(got)); fprintf(stderr, "exp:\n"); dump_hex(stderr, tests[i].exp, sizeof(got)); } } } static void test_parallelhash256_xof(void) { static const struct { const char *name; // test name const uint8_t custom[256]; // custom name const size_t custom_len; // custom name length const size_t block_len; // block size, in bytes const uint8_t msg[256]; // input data const size_t len; // message length, in bytes const uint8_t exp[64]; // expected hash } tests[] = {{ // src: https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/ParallelHashXOF_samples.pdf .name = "ParallelHashXOF Sample #4", .custom = "", .custom_len = 0, .block_len = 8, .msg = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, }, .len = 24, .exp = { 0xC1, 0x0A, 0x05, 0x27, 0x22, 0x61, 0x46, 0x84, 0x14, 0x4D, 0x28, 0x47, 0x48, 0x50, 0xB4, 0x10, 0x75, 0x7E, 0x3C, 0xBA, 0x87, 0x65, 0x1B, 0xA1, 0x67, 0xA5, 0xCB, 0xDD, 0xFF, 0x7F, 0x46, 0x66, 0x75, 0xFB, 0xF8, 0x4B, 0xCA, 0xE7, 0x37, 0x8A, 0xC4, 0x44, 0xBE, 0x68, 0x1D, 0x72, 0x94, 0x99, 0xAF, 0xCA, 0x66, 0x7F, 0xB8, 0x79, 0x34, 0x8B, 0xFD, 0xDA, 0x42, 0x78, 0x63, 0xC8, 0x2F, 0x1C, }, }, { .name = "ParallelHashXOF Sample #5", .custom = "Parallel Data", .custom_len = 13, .block_len = 8, .msg = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, }, .len = 24, .exp = { 0x53, 0x8E, 0x10, 0x5F, 0x1A, 0x22, 0xF4, 0x4E, 0xD2, 0xF5, 0xCC, 0x16, 0x74, 0xFB, 0xD4, 0x0B, 0xE8, 0x03, 0xD9, 0xC9, 0x9B, 0xF5, 0xF8, 0xD9, 0x0A, 0x2C, 0x81, 0x93, 0xF3, 0xFE, 0x6E, 0xA7, 0x68, 0xE5, 0xC1, 0xA2, 0x09, 0x87, 0xE2, 0xC9, 0xC6, 0x5F, 0xEB, 0xED, 0x03, 0x88, 0x7A, 0x51, 0xD3, 0x56, 0x24, 0xED, 0x12, 0x37, 0x75, 0x94, 0xB5, 0x58, 0x55, 0x41, 0xDC, 0x37, 0x7E, 0xFC, }, }, { .name = "ParallelHashXOF Sample #6", .custom = "Parallel Data", .custom_len = 13, .block_len = 12, .msg = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, }, .len = 72, .exp = { 0x6B, 0x3E, 0x79, 0x0B, 0x33, 0x0C, 0x88, 0x9A, 0x20, 0x4C, 0x2F, 0xBC, 0x72, 0x8D, 0x80, 0x9F, 0x19, 0x36, 0x73, 0x28, 0xD8, 0x52, 0xF4, 0x00, 0x2D, 0xC8, 0x29, 0xF7, 0x3A, 0xFD, 0x6B, 0xCE, 0xFB, 0x7F, 0xE5, 0xB6, 0x07, 0xB1, 0x3A, 0x80, 0x1C, 0x0B, 0xE5, 0xC1, 0x17, 0x0B, 0xDB, 0x79, 0x4E, 0x33, 0x94, 0x58, 0xFD, 0xB0, 0xE6, 0x2A, 0x6A, 0xF3, 0xD4, 0x25, 0x58, 0x97, 0x02, 0x49, }, }}; for (size_t i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) { // build params const parallelhash_params_t params = { .block_len = tests[i].block_len, .custom = tests[i].custom, .custom_len = tests[i].custom_len, }; // run uint8_t got[64]; parallelhash256_xof_once(params, tests[i].msg, tests[i].len, got, sizeof(got)); // check if (memcmp(got, tests[i].exp, sizeof(got))) { fprintf(stderr, "test_parallelhash256_xof(\"%s\") failed, got:\n", tests[i].name); dump_hex(stderr, got, sizeof(got)); fprintf(stderr, "exp:\n"); dump_hex(stderr, tests[i].exp, sizeof(got)); } } } static void test_hmac_sha3_224(void) { static const struct { const char *name; // test name const uint8_t key[256]; // key const size_t key_len; // key length, in bytes const uint8_t msg[256]; // input data const size_t msg_len; // message length, in bytes const uint8_t exp[28]; // expected hash } tests[] = {{ // src: https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/HMAC_SHA3-224.pdf .name = "HMAC-SHA3-224 Sample #1", .key = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, }, .key_len = 28, .msg = "Sample message for keylen 0) { // alloc src src = malloc(tests[i].len); // copy src data from pattern for (size_t ofs = 0; ofs < tests[i].len; ofs += sizeof(PATTERN)) { const size_t len = MIN(tests[i].len - ofs, sizeof(PATTERN)); memcpy(src + ofs, PATTERN, len); } } // populate custom string uint8_t *custom = NULL; if (tests[i].custom_len > 0) { // alloc custom custom = malloc(tests[i].custom_len); // copy custom data from pattern for (size_t ofs = 0; ofs < tests[i].custom_len; ofs += sizeof(PATTERN)) { const size_t len = MIN(tests[i].custom_len - ofs, sizeof(PATTERN)); memcpy(custom + ofs, PATTERN, len); } } // run uint8_t got[32] = { 0 }; k12_custom_once(src, tests[i].len, custom, tests[i].custom_len, got, sizeof(got)); // check if (memcmp(got, tests[i].exp, sizeof(got))) { fprintf(stderr, "test_k12(\"%s\") failed, got:\n", tests[i].name); dump_hex(stderr, got, sizeof(got)); fprintf(stderr, "exp:\n"); dump_hex(stderr, tests[i].exp, sizeof(got)); } // free test data if (!tests[i].is_data && tests[i].len) { free(src); } free(custom); } } int main(void) { test_theta(); test_rho(); test_pi(); test_chi(); test_iota(); test_permute(); test_sha3_224(); test_sha3_256(); test_sha3_384(); test_sha3_512(); test_sha3_224_ctx(); test_sha3_256_ctx(); test_sha3_384_ctx(); test_sha3_512_ctx(); test_shake128_ctx(); test_shake128(); test_shake256_ctx(); test_shake256(); test_left_encode(); test_right_encode(); test_encode_string_prefix(); test_bytepad(); test_cshake128(); test_cshake256(); test_kmac128(); test_kmac256(); test_kmac128_xof(); test_kmac256_xof(); test_tuplehash128(); test_tuplehash256(); test_tuplehash128_xof(); test_tuplehash256_xof(); test_parallelhash128(); test_parallelhash128_xof(); test_parallelhash256(); test_parallelhash256_xof(); test_hmac_sha3_224(); test_hmac_sha3_256(); test_hmac_sha3_384(); test_hmac_sha3_512(); test_hmac_sha3_224_ctx(); test_hmac_sha3_256_ctx(); test_hmac_sha3_384_ctx(); test_hmac_sha3_512_ctx(); test_turboshake128(); test_turboshake256(); test_k12_length_encode(); test_k12(); printf("ok\n"); } #endif /* SHA3_TEST */ /** @endcond INTERNAL */