/** * 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 */ /** @cond INTERNAL */ #include // true, false #include // uint64_t #include // memcpy() #include "sha3.h" // available backends // // each backend implements a permute_n_() function, which is // wrapped in a #if/#endif pair below. // // there are currently 5 backends, but only 2 of them -- scalar and // avx512 -- are auto-detected. the remaining three are experimental // neon backends and are currently slower than the scalar backend. // // To add a new backend: // // 1. Add a "#define BACKEND_FOO UNIQUE_ID" line to this section. // Example: "#define BACKEND_FOO 99". // 2. (optional) if the backend can be automatically detected, add a // #elif branch to the auto-detect section below. // 3. Add a section which begins with "#if BACKEND == BACKEND_FOO" and // ends with "#endif /* BACKEND == BACKEND_FOO */" and contains a // `permute_n_foo()` function and any helper functions. // 4. Add a branch to the "map permute_n()" block which maps // `permute_n()` to `permute_n_foo()`. // 5. Add a branch to the "sha3_backend()" which returns the name of // your backend. // 6. Add `test_permute_12_foo()` and `test_permute_24_foo()` test // functions in the TEST_SHA3 block. Use the test functions for the // other backends as a template. // 7. Add calls to the test functions from the previous step to `main()`. // // At this point you should be able to run the test suite and build the // top-level shared library, the top-level example application, and the // applications in the `examples/` directory with your new backend. // // For example, to run the test suite against the backend with a unique // ID of 99, you would do this: // // # run test suite against backend 99 // make test BACKEND=99 // #define BACKEND_AUTO 0 // auto-detect (default) #define BACKEND_SCALAR 1 // scalar backend #define BACKEND_AVX512 2 // AVX-512 backend #define BACKEND_NEON 3 // Neon backend. Slower than scalar. #define BACKEND_DIET_NEON 4 // Neon backend, fewer registers. Slower than scalar. #define BACKEND_HYBRID 5 // Hybrid scalar/neon backend. Slower than scalar. #define BACKEND_AVX2 6 // AVX2 backend // if BACKEND is defined and set to 0 (the default), then unset it // and auto-detect the appropriate backend below #if defined(BACKEND) && BACKEND == BACKEND_AUTO #undef BACKEND #endif /* defined(BACKEND) && BACKEND == 0 */ // auto-detect backend #ifndef BACKEND #if defined(__AVX512F__) #define BACKEND BACKEND_AVX512 #elif 0 && defined(__AVX2__) #define BACKEND BACKEND_AVX2 #elif 0 && defined(__ARM_NEON) #define BACKEND BACKEND_NEON #else // no optimized backend detected, fall back to scalar #define BACKEND BACKEND_SCALAR #endif #endif /* !BACKEND */ // 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 // align memory to N bytes #define ALIGN(N) __attribute__((aligned(N))) // Iota round constants. 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, }; #if (BACKEND == BACKEND_SCALAR) || defined(TEST_SHA3) // The scalar Keccak step functions in this block are only built if one // of the following conditions is true: // // * we are using the scalar backend, or // * we are building the test suite. // // The scalar Keccak step functions in this block are not built for // AVX-512 and Neon backends, because those backends do not use them. /** * @brief Theta step of scalar Keccak permutation. * @param[in,out] a Keccak state (array of 25 64-bit integers). * * @note Only built when using the scalar backend or when building the * test suite. */ 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]; } /** * @brief Rho step of scalar Keccak permutation. * @param[in,out] a Keccak state (array of 25 64-bit integers). * * @note Only built when using the scalar backend or when building the * test suite. */ 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 } /** * @brief Pi step of scalar Keccak permutation. * @param[in,out] a Keccak state (array of 25 64-bit integers). * * @note Only built when using the scalar backend or when building the * test suite. */ 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]; } /** * @brief Chi step of scalar Keccak permutation. * @param[in,out] a Keccak state (array of 25 64-bit integers). * * @note Only built when using the scalar backend or when building the * test suite. */ 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]); } /** * @brief Iota step of scalar Keccak permutation. * @param[in,out] a Keccak state (array of 25 64-bit integers). * * @note Only built when using the scalar backend or when building the * test suite. */ static inline void iota(uint64_t a[static 25], const int i) { a[0] ^= RCS[i]; } /** * @brief Scalar Keccak permutation. * * Apply `num_rounds` of Keccak permutation. * * @param[in,out] a Keccak state (array of 25 64-bit integers). * @param[in] num_rounds Number of rounds (12 or 24). * * @note Only built when using the scalar backend or when building the * test suite. */ static inline void permute_n_scalar(uint64_t a[static 25], const size_t num_rounds) { uint64_t tmp[25] = { 0 }; for (size_t i = (SHA3_NUM_ROUNDS - num_rounds); __builtin_expect(i < SHA3_NUM_ROUNDS, 1); i++) { theta(a); rho(a); pi(tmp, a); chi(a, tmp); iota(a, i); } } #endif /* (BACKEND == BACKEND_SCALAR) || defined(TEST_SHA3) */ #if BACKEND == BACKEND_AVX512 #include /** * @brief AVX-512 Keccak permutation. * * @param[in,out] s Keccak state (array of 25 64-bit integers). * @param[in] num_rounds Number of rounds (12 or 24). * * How it works: * * 1. The Keccak state is loaded from `s` (an array of 25 64-bit * unsigned integers) into the first 5 64-bit lanes of 5 AVX-512 * registers r0-r4, like this: * * ----------------------------------------------------------------- * | | 64-bit Lane | * |-----|---------------------------------------------------------| * | Reg | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | * |-----|-------|-------|-------|-------|-------|-----|-----|-----| * | 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. The Keccak permutation is applied `num_rounds` times, where * `num_rounds` is either 12 for TurboSHAKE and KangarooTwelve or 24 * otherwise. * * 3. The permuted Keccak state is copied from the first 5 64-bit lanes * of AVX-512 registers r0-r4 back to `s`. */ static inline void permute_n_avx512(uint64_t s[static 25], const size_t num_rounds) { // load rows (r0-r4) __m512i r0 = _mm512_maskz_loadu_epi64(0x1f, s + 0), // row 0 r1 = _mm512_maskz_loadu_epi64(0x1f, s + 5), // row 1 r2 = _mm512_maskz_loadu_epi64(0x1f, s + 10), // row 2 r3 = _mm512_maskz_loadu_epi64(0x1f, s + 15), // row 3 r4 = _mm512_maskz_loadu_epi64(0x1f, s + 20); // row 4 // loop over rounds for (size_t i = (SHA3_NUM_ROUNDS - num_rounds); __builtin_expect(i < SHA3_NUM_ROUNDS, 1); i++) { // theta { // permute ids static const __m512i I0 = { 4, 0, 1, 2, 3 }, I1 = { 1, 2, 3, 4, 0 }; // c = xor(r0, r1, r2, r3, r4) const __m512i r01 = _mm512_maskz_xor_epi64(0x1f, r0, r1), r23 = _mm512_maskz_xor_epi64(0x1f, r2, r3), c = _mm512_maskz_ternarylogic_epi64(0x1f, r01, r23, r4, 0x96); // 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 { // rotate values // // note: switching from maskz_load_epi64()s to static const // __m512i incurs a 500 cycle penalty; leaving them for now static const uint64_t V0_VALS[5] ALIGN(64) = { 0, 1, 62, 28, 27 }, V1_VALS[5] ALIGN(64) = { 36, 44, 6, 55, 20 }, V2_VALS[5] ALIGN(64) = { 3, 10, 43, 25, 39 }, V3_VALS[5] ALIGN(64) = { 41, 45, 15, 21, 8 }, V4_VALS[5] ALIGN(64) = { 18, 2, 61, 56, 14 }; // rotate rows r0 = _mm512_rolv_epi64(r0, _mm512_maskz_load_epi64(0x1f, V0_VALS)); r1 = _mm512_rolv_epi64(r1, _mm512_maskz_load_epi64(0x1f, V1_VALS)); r2 = _mm512_rolv_epi64(r2, _mm512_maskz_load_epi64(0x1f, V2_VALS)); r3 = _mm512_rolv_epi64(r3, _mm512_maskz_load_epi64(0x1f, V3_VALS)); r4 = _mm512_rolv_epi64(r4, _mm512_maskz_load_epi64(0x1f, V4_VALS)); } // pi // // The cells are permuted across all rows of the state array. each // output row is the combination of three permutations: // // - e0: row 0 and row 1 // - e2: row 2 and row 3 // - e4: row 4 and row 0 // // the IDs for each permutation are merged into a single array // (T*_IDS) to reduce register pressure, and the permute operations // are masked so that each permutation only uses the relevant IDs. // // afterwards, the permutations are combined to form a temporary // row: // // t0 = t0e0 | t0e2 | t0e4 // // once the permutations for all rows are complete, the temporary // rows are saved to the actual row registers: // // r0 = t0 // { // permute ids static const __m512i T0_IDS = { 0, 8 + 1, 2, 8 + 3, 4 }, T1_IDS = { 3, 8 + 4, 0, 8 + 1, 2 }, T2_IDS = { 1, 8 + 2, 3, 8 + 4, 0 }, T3_IDS = { 4, 8 + 0, 1, 8 + 2, 3 }, T4_IDS = { 2, 8 + 3, 4, 8 + 0, 1 }; __m512i t0, t1, t2, t3, t4; { // permute r0 const __m512i t0e0 = _mm512_maskz_permutex2var_epi64(0x03, r0, T0_IDS, r1), t0e2 = _mm512_maskz_permutex2var_epi64(0x0c, r2, T0_IDS, r3), t0e4 = _mm512_maskz_permutex2var_epi64(0x10, r4, T0_IDS, r0); // permute r1 const __m512i t1e0 = _mm512_maskz_permutex2var_epi64(0x03, r0, T1_IDS, r1), t1e2 = _mm512_maskz_permutex2var_epi64(0x0c, r2, T1_IDS, r3), t1e4 = _mm512_maskz_permutex2var_epi64(0x10, r4, T1_IDS, r0); // permute r2 const __m512i t2e0 = _mm512_maskz_permutex2var_epi64(0x03, r0, T2_IDS, r1), t2e2 = _mm512_maskz_permutex2var_epi64(0x0c, r2, T2_IDS, r3), t2e4 = _mm512_maskz_permutex2var_epi64(0x10, r4, T2_IDS, r0); // permute r3 const __m512i t3e0 = _mm512_maskz_permutex2var_epi64(0x03, r0, T3_IDS, r1), t3e2 = _mm512_maskz_permutex2var_epi64(0x0c, r2, T3_IDS, r3), t3e4 = _mm512_maskz_permutex2var_epi64(0x10, r4, T3_IDS, r0); // permute r4 const __m512i t4e0 = _mm512_maskz_permutex2var_epi64(0x03, r0, T4_IDS, r1), t4e2 = _mm512_maskz_permutex2var_epi64(0x0c, r2, T4_IDS, r3), t4e4 = _mm512_maskz_permutex2var_epi64(0x10, r4, T4_IDS, r0); // combine permutes: tN = e0 | e2 | e4 t0 = _mm512_maskz_ternarylogic_epi64(0x1f, t0e0, t0e2, t0e4, 0xfe); t1 = _mm512_maskz_ternarylogic_epi64(0x1f, t1e0, t1e2, t1e4, 0xfe); t2 = _mm512_maskz_ternarylogic_epi64(0x1f, t2e0, t2e2, t2e4, 0xfe); t3 = _mm512_maskz_ternarylogic_epi64(0x1f, t3e0, t3e2, t3e4, 0xfe); t4 = _mm512_maskz_ternarylogic_epi64(0x1f, t4e0, t4e2, t4e4, 0xfe); } // store rows r0 = t0; r1 = t1; r2 = t2; r3 = t3; r4 = t4; } // chi { // permute ids static const __m512i P0 = { 1, 2, 3, 4, 0 }, P1 = { 2, 3, 4, 0, 1 }; { // r0 ^= ~e0 & e1 const __m512i t0_e0 = _mm512_maskz_permutexvar_epi64(0x1f, P0, r0), t0_e1 = _mm512_maskz_permutexvar_epi64(0x1f, P1, r0); r0 = _mm512_maskz_ternarylogic_epi64(0x1f, r0, t0_e0, t0_e1, 0xd2); } { // r1 ^= ~e0 & e1 const __m512i t1_e0 = _mm512_maskz_permutexvar_epi64(0x1f, P0, r1), t1_e1 = _mm512_maskz_permutexvar_epi64(0x1f, P1, r1); r1 = _mm512_maskz_ternarylogic_epi64(0x1f, r1, t1_e0, t1_e1, 0xd2); } { // r2 ^= ~e0 & e1 const __m512i t2_e0 = _mm512_maskz_permutexvar_epi64(0x1f, P0, r2), t2_e1 = _mm512_maskz_permutexvar_epi64(0x1f, P1, r2); r2 = _mm512_maskz_ternarylogic_epi64(0x1f, r2, t2_e0, t2_e1, 0xd2); } { // r3 ^= ~e0 & e1 const __m512i t3_e0 = _mm512_maskz_permutexvar_epi64(0x1f, P0, r3), t3_e1 = _mm512_maskz_permutexvar_epi64(0x1f, P1, r3); r3 = _mm512_maskz_ternarylogic_epi64(0x1f, r3, t3_e0, t3_e1, 0xd2); } { // r4 ^= ~e0 & e1 const __m512i t4_e0 = _mm512_maskz_permutexvar_epi64(0x1f, P0, r4), t4_e1 = _mm512_maskz_permutexvar_epi64(0x1f, P1, r4); r4 = _mm512_maskz_ternarylogic_epi64(0x1f, r4, t4_e0, t4_e1, 0xd2); } } // iota { // xor round constant to first cell r0 = _mm512_mask_xor_epi64(r0, 1, r0, _mm512_maskz_loadu_epi64(1, RCS + i)); } } // store rows _mm512_mask_storeu_epi64(s + 5 * 0, 0x1f, r0); _mm512_mask_storeu_epi64(s + 5 * 1, 0x1f, r1); _mm512_mask_storeu_epi64(s + 5 * 2, 0x1f, r2); _mm512_mask_storeu_epi64(s + 5 * 3, 0x1f, r3); _mm512_mask_storeu_epi64(s + 5 * 4, 0x1f, r4); } #endif /* BACKEND == BACKEND_AVX512 */ #if BACKEND == BACKEND_AVX2 #include // lane masks static const __m256i LM0 = { ~0, 0, 0, 0 }, // only lane 0 LM1 = { 0, ~0, 0, 0 }, // only lane 1 LM2 = { 0, 0, ~0, 0 }, // only lane 2 LM3 = { 0, 0, 0, ~0 }; // only lane 3 // rotate left immediate #define AVX2_ROLI(v, n) (_mm256_slli_epi64((v), (n)) | _mm256_srli_epi64((v), (64-(n)))) // rotate left by vector #define AVX2_ROLV(v, n) (_mm256_sllv_epi64((v), (n)) | _mm256_srlv_epi64((v), (64-(n)))) // theta permute IDs #define THETA_I0_LO 0x90 // 0, 0, 1, 2 -> 0b10010000 -> 0x90 #define THETA_I0_HI 0x03 // 3, 0, 0, 0 -> 0b00000011 -> 0x03 #define THETA_I1_LO 0x39 // 1, 2, 3, 0 -> 0b00111001 -> 0x39 #define THETA_I1_HI 0x00 // 0, 0, 0, 0 -> 0b00000000 -> 0x00 // pi permute IDs #define PI_T1_LO 0x43 // 0b01000011 -> 0x43 #define PI_T1_HI 0x02 #define PI_T2_LO 0x39 // 0b00111001 -> 0x39 #define PI_T3_LO 0x90 // 0b10010000 -> 0x90 #define PI_T3_HI 0x03 #define PI_T4_LO 0x0e // 0b00001110 -> 0x0e // chi blend mask #define CHI_MASK 0xc0 // 0b11000000 // chi permute IDs #define CHI_A_IDS 0x39 // 1, 2, 3, 0 -> 0b00111001 -> 0x39 #define CHI_B_IDS 0x0e // 2, 3, 0, 0 -> 0b00001110 -> 0x0e // chi step #define CHI(LO, HI) do { \ const __m256i a_lo = _mm256_blend_epi32(_mm256_permute4x64_epi64(LO, CHI_A_IDS), _mm256_permute4x64_epi64(HI, CHI_A_IDS), CHI_MASK), \ a_hi = LO, \ b_lo = (_mm256_permute4x64_epi64(LO, CHI_B_IDS) & ~LM2) | (_mm256_permute4x64_epi64(HI, CHI_B_IDS) & ~LM0), \ b_hi = _mm256_shuffle_epi32(LO, 0x0e); \ \ LO ^= _mm256_andnot_si256(a_lo, b_lo); HI ^= _mm256_andnot_si256(a_hi, b_hi); \ } while (0) /** * @brief AVX2 Keccak permutation. * * @param[in,out] s Keccak state (array of 25 64-bit integers). * @param[in] num_rounds Number of rounds (12 or 24). * * How it works: * * 1. The Keccak state for cells in columns 0-3 is loaded from `s` (an * array of 25 64-bit unsigned integers) into four 64-bit lanes of 5 * 256-bit registers r0_lo-r4_lo. * * 2. The Keccak state for cells in column 4 is loaded from `s` into * the first 64-bit lanes of 5 256-bit registers r0_hi-r4_hi. * * When steps #1 and #2 are done, the registers look like this: * * ------------------------------------------------ * | | 64-bit Lanes of 256-bit Registers | * |----------|-----------------------------------| * | Register | Lane 0 | Lane 1 | Lane 2 | Lane 3 | * |----------|--------|--------|--------|--------| * | r0_lo | s[ 0] | s[ 1] | s[ 2] | s[ 3] | * | r1_lo | s[ 5] | s[ 6] | s[ 7] | s[ 8] | * | r2_lo | s[10] | s[11] | s[12] | s[13] | * | r3_lo | s[15] | s[16] | s[17] | s[18] | * | r4_lo | s[20] | s[21] | s[22] | s[23] | * | r0_hi | s[ 4] | n/a | n/a | n/a | * | r1_hi | s[ 9] | n/a | n/a | n/a | * | r2_hi | s[14] | n/a | n/a | n/a | * | r3_hi | s[19] | n/a | n/a | n/a | * | r4_hi | s[24] | n/a | n/a | n/a | * ------------------------------------------------ * * 3. The Keccak permutation is applied `num_rounds` times, where * `num_rounds` is either 12 for TurboSHAKE and KangarooTwelve or 24 * otherwise. * * 4. The permuted Keccak state is copied back to `s`. */ static inline void permute_n_avx2(uint64_t s[static 25], const size_t num_rounds) { // load state array into avx2 registers __m256i r0_lo = _mm256_loadu_si256((__m256i*) (s + 0)), /* row 0, cols 0-3 */ r1_lo = _mm256_loadu_si256((__m256i*) (s + 5)), /* row 1, cols 0-3 */ r2_lo = _mm256_loadu_si256((__m256i*) (s + 10)), /* row 2, cols 0-3 */ r3_lo = _mm256_loadu_si256((__m256i*) (s + 15)), /* row 3, cols 0-3 */ r4_lo = _mm256_loadu_si256((__m256i*) (s + 20)), /* row 4, cols 0-3 */ r0_hi = { s[ 4] }, /* row 0, col 4 */ r1_hi = { s[ 9] }, /* row 1, col 4 */ r2_hi = { s[14] }, /* row 2, col 4 */ r3_hi = { s[19] }, /* row 3, col 4 */ r4_hi = { s[24] }; /* row 4, col 4 */ // loop over rounds for (size_t i = (SHA3_NUM_ROUNDS - num_rounds); __builtin_expect(i < SHA3_NUM_ROUNDS, 1); i++) { // theta { // c = xor(r0, r1, r2, r3, r4) const __m256i c_lo = r0_lo ^ r1_lo ^ r2_lo ^ r3_lo ^ r4_lo, c_hi = r0_hi ^ r1_hi ^ r2_hi ^ r3_hi ^ r4_hi; // i0 = { 4, 0, 1, 2, 3 }, i1 = { 1, 2, 3, 4, 0 } // d = xor(permute(i0, c), permute(i1, rol(c, 1))) const __m256i d0_lo = (_mm256_permute4x64_epi64(c_lo, THETA_I0_LO) & ~LM0) | (c_hi & LM0), d0_hi = _mm256_permute4x64_epi64(c_lo, THETA_I0_HI), d1_lo = _mm256_blend_epi32(_mm256_permute4x64_epi64(c_lo, THETA_I1_LO), _mm256_permute4x64_epi64(c_hi, THETA_I1_HI), 0xc0), d_lo = d0_lo ^ AVX2_ROLI(d1_lo, 1), d_hi = d0_hi ^ AVX2_ROLI(c_lo, 1); // row = xor(row, d) r0_lo ^= d_lo; r1_lo ^= d_lo; r2_lo ^= d_lo; r3_lo ^= d_lo; r4_lo ^= d_lo; r0_hi ^= d_hi; r1_hi ^= d_hi; r2_hi ^= d_hi; r3_hi ^= d_hi; r4_hi ^= d_hi; } // rho { // rotate values static const __m256i V0_LO = { 0, 1, 62, 28 }, V1_LO = { 36, 44, 6, 55 }, V2_LO = { 3, 10, 43, 25 }, V3_LO = { 41, 45, 15, 21 }, V4_LO = { 18, 2, 61, 56 }; // rotate rows r0_lo = AVX2_ROLV(r0_lo, V0_LO); r0_hi = AVX2_ROLI(r0_hi, 27); r1_lo = AVX2_ROLV(r1_lo, V1_LO); r1_hi = AVX2_ROLI(r1_hi, 20); r2_lo = AVX2_ROLV(r2_lo, V2_LO); r2_hi = AVX2_ROLI(r2_hi, 39); r3_lo = AVX2_ROLV(r3_lo, V3_LO); r3_hi = AVX2_ROLI(r3_hi, 8); r4_lo = AVX2_ROLV(r4_lo, V4_LO); r4_hi = AVX2_ROLI(r4_hi, 14); } // pi { const __m256i t0_lo = _mm256_blend_epi32(( (r0_lo & LM0) | (r1_lo & LM1) | (r2_lo & LM2) ), r3_lo, 0xc0), t0_hi = r4_hi, t1_lo = _mm256_blend_epi32(( (_mm256_permute4x64_epi64(r0_lo, PI_T1_LO) & LM0) | (_mm256_permute4x64_epi64(r1_hi, PI_T1_LO) & LM1) | (_mm256_permute4x64_epi64(r2_lo, PI_T1_LO) & LM2) ), _mm256_permute4x64_epi64(r3_lo, PI_T1_LO), 0xc0), t1_hi = _mm256_permute4x64_epi64(r4_lo, PI_T1_HI), t2_lo = _mm256_blend_epi32(( (_mm256_permute4x64_epi64(r0_lo, PI_T2_LO) & LM0) | (_mm256_permute4x64_epi64(r1_lo, PI_T2_LO) & LM1) | (_mm256_permute4x64_epi64(r2_lo, PI_T2_LO) & LM2) ), _mm256_permute4x64_epi64(r3_hi, PI_T2_LO), 0xc0), t2_hi = r4_lo, t3_lo = (_mm256_permute4x64_epi64(r0_hi, PI_T3_LO) & LM0) | (_mm256_permute4x64_epi64(r1_lo, PI_T3_LO) & LM1) | (_mm256_permute4x64_epi64(r2_lo, PI_T3_LO) & LM2) | (_mm256_permute4x64_epi64(r3_lo, PI_T3_LO) & LM3), t3_hi = _mm256_permute4x64_epi64(r4_lo, PI_T3_HI), t4_lo = (_mm256_permute4x64_epi64(r0_lo, PI_T4_LO) & LM0) | (_mm256_permute4x64_epi64(r1_lo, PI_T4_LO) & LM1) | (_mm256_permute4x64_epi64(r2_hi, PI_T4_LO) & LM2) | (_mm256_permute4x64_epi64(r3_lo, PI_T4_LO) & LM3), t4_hi = _mm256_shuffle_epi32(r4_lo, 0x0e); r0_lo = t0_lo; r0_hi = t0_hi & LM0; r1_lo = t1_lo; r1_hi = t1_hi & LM0; r2_lo = t2_lo; r2_hi = t2_hi & LM0; r3_lo = t3_lo; r3_hi = t3_hi & LM0; r4_lo = t4_lo; r4_hi = t4_hi & LM0; } // chi { CHI(r0_lo, r0_hi); // r0 CHI(r1_lo, r1_hi); // r1 CHI(r2_lo, r2_hi); // r2 CHI(r3_lo, r3_hi); // r3 CHI(r4_lo, r4_hi); // r4 } // iota const __m256i rc = { RCS[i], 0, 0, 0 }; r0_lo ^= rc; } // store rows to state union { long long int *i64; uint64_t *u64; } p = { .u64 = s }; _mm256_storeu_si256((__m256i*) (p.i64 + 0), r0_lo); /* row 0, cols 0-3 */ _mm256_storeu_si256((__m256i*) (p.i64 + 5), r1_lo); /* row 1, cols 0-3 */ _mm256_storeu_si256((__m256i*) (p.i64 + 10), r2_lo); /* row 2, cols 0-3 */ _mm256_storeu_si256((__m256i*) (p.i64 + 15), r3_lo); /* row 3, cols 0-3 */ _mm256_storeu_si256((__m256i*) (p.i64 + 20), r4_lo); /* row 4, cols 0-3 */ _mm256_maskstore_epi64(p.i64 + 4, LM0, r0_hi); /* row 0, col 4 */ _mm256_maskstore_epi64(p.i64 + 9, LM0, r1_hi); /* row 1, col 4 */ _mm256_maskstore_epi64(p.i64 + 14, LM0, r2_hi); /* row 2, col 4 */ _mm256_maskstore_epi64(p.i64 + 19, LM0, r3_hi); /* row 3, col 4 */ _mm256_maskstore_epi64(p.i64 + 24, LM0, r4_hi); /* row 4, col 4 */ } #endif /* BACKEND == BACKEND_AVX2 */ #if BACKEND == BACKEND_NEON #include // rotate elements in uint64x2_t left by N bits #define VROLQ(A, N) vsriq_n_u64(vshlq_n_u64((A), (N)), (A), 64-(N)) // keccak row, represented as 3 128-bit vector registers // // columns are stored in the low 5 64-bit lanes. this wastes one // 64-bit lane per row at the expense of making many of the instructions // simpler. typedef struct { uint64x2_t p0, // columns 0 and 1 p1, // columns 2 and 3 p2; // column 4. high lane is unused } row_t; /** * @brief Set row contents. * * Apply `num_rounds` of Keccak permutation. * * @param[in] p0 Value of columns 0 and 1. * @param[in] p1 Value of columns 2 and 3. * @param[in] p2 Value of columns 4 in low lane. High lane is unused. */ static inline row_t row_set(const uint64x2_t a, const uint64x2_t b, const uint64x2_t c) { return (row_t) { a, b, c }; } // get Nth pair of u64s from row #define ROW_GET(A, N) ((A).p ## N) /** * @brief Load row from memory. * @param[in] p Pointer to 40 bytes of memory. * @return row_t */ static inline row_t row_load(const uint64_t p[static 5]) { return row_set(vld1q_u64(p + 0), vld1q_u64(p + 2), vdupq_n_u64(p[4])); } /** * @brief Store row to memory. * @param[in] p Pointer to 40 bytes of memory. * @param[in] a Row to store. */ static inline void row_store(uint64_t p[static 5], const row_t a) { const uint64x2x2_t vals = { .val = { ROW_GET(a, 0), ROW_GET(a, 1) } }; vst1q_u64_x2(p + 0, vals); vst1_u64(p + 4, vdup_laneq_u64(ROW_GET(a, 2), 0)); } // rotate row lanes left // // --------------------------- --------------------------- // | 64-bit Lanes (Before) | | 64-bit Lanes (After) | // |-------------------------| |-------------------------| // | 0 | 1 | 2 | 3 | 4 | 5 | --> | 0 | 1 | 2 | 3 | 4 | 5 | // |---|---|---|---|---|-----| |---|---|---|---|---|-----| // | A | B | C | D | E | n/a | | E | A | B | C | D | n/a | // --------------------------- --------------------------- // static inline row_t row_rll(const row_t a) { return row_set( vzip1q_u64(ROW_GET(a, 2), ROW_GET(a, 0)), // { a4, a0 } vextq_u64(ROW_GET(a, 0), ROW_GET(a, 1), 1), // { a1, a2 } vdupq_laneq_u64(ROW_GET(a, 1), 1) // { a3, n/a } ); } // rotate row lanes right // // --------------------------- --------------------------- // | 64-bit Lanes (Before) | | 64-bit Lanes (After) | // |-------------------------| |-------------------------| // | 0 | 1 | 2 | 3 | 4 | 5 | --> | 0 | 1 | 2 | 3 | 4 | 5 | // |---|---|---|---|---|-----| |---|---|---|---|---|-----| // | A | B | C | D | E | n/a | | B | C | D | E | A | n/a | // --------------------------- --------------------------- // static inline row_t row_rlr(const row_t a) { return row_set( vextq_u64(ROW_GET(a, 0), ROW_GET(a, 1), 1), // { a1, a2 } vextq_u64(ROW_GET(a, 1), ROW_GET(a, 2), 1), // { a3, a4 } ROW_GET(a, 0) // { a0, n/a } ); } // c = a ^ b static inline row_t row_eor(const row_t A, const row_t B) { return row_set( ROW_GET(A, 0) ^ ROW_GET(B, 0), ROW_GET(A, 1) ^ ROW_GET(B, 1), ROW_GET(A, 2) ^ ROW_GET(B, 2) ); } // f = a ^ b ^ c ^ d ^ e // FIXME want: veor3_u64(a, b, c); static inline row_t row_eor5(const row_t a, const row_t b, const row_t c, const row_t d, const row_t e) { return row_set( ROW_GET(a, 0) ^ ROW_GET(b, 0) ^ ROW_GET(c, 0) ^ ROW_GET(d, 0) ^ ROW_GET(e, 0), ROW_GET(a, 1) ^ ROW_GET(b, 1) ^ ROW_GET(c, 1) ^ ROW_GET(d, 1) ^ ROW_GET(e, 1), ROW_GET(a, 2) ^ ROW_GET(b, 2) ^ ROW_GET(c, 2) ^ ROW_GET(d, 2) ^ ROW_GET(e, 2) ); } // rotate bits in each lane left one bit // FIXME: want vrax1q_u64() (not supported on n2l or pi5) static inline row_t row_rol1_u64(const row_t a) { return row_set( VROLQ(ROW_GET(a, 0), 1), VROLQ(ROW_GET(a, 1), 1), VROLQ(ROW_GET(a, 2), 1) ); } // encoded rho rotate values // // original values: // // static const int64x2_t // r0_a = { 0, 1 }, r0_b = { 62, 28 }, r02_c = { 27, 39 }, // r1_a = { 36, 44 }, r1_b = { 6, 55 }, r13_c = { 20, 8 }, // r2_a = { 3, 10 }, r2_b = { 43, 25 }, // r3_a = { 41, 45 }, r3_b = { 15, 21 }, // r4_a = { 18, 2 }, r4_b = { 61, 56 }, r4_c = { 14, 0 }; // // low element of r[0-4]_{a,b} packed into low lane of r_ab, like so: // // >> v = [0, 36, 3, 41, 18, 62, 6, 43, 15, 61].each_with_index.reduce(0) { |r, (c, i)| r+(64**i)* // c } // => 1103290028930644224 // >> (v >> 6*9) & 0x3f // => 61 // >> 6*9 // => 54 // >> v // => 1103290028930644224 // >> '0x%016x' % v // => "0x0f4fac6f92a43900" // // high element of r[0-4]_{a,b} packed into high lane of r_ab, like so: // // >> v = [1, 44, 10, 45, 2, 28, 55, 25, 21, 56].each_with_index.reduce(0) { |r, (c, i)| r+(64**i) // *c } // => 1014831051886078721 // >> '0x%016x' % v // => "0x0e15677702b4ab01" // // low elements of r[0-4]_c packed into low lane of r_c, like so: // // >> v = [27, 20, 39, 8, 14].each_with_index.reduce(0) { |r, (c, i)| r+(64**i)*c } // => 237139227 // >> '0x%016x' % v // => "0x000000000e22751b" // // (there are no high elements of r[0-4]_c, all zero) // // to extract elements, right shift by 6*Y (where Y is the row // number), then mask to lower 6 bits (0x3f). for example, to // extract r4_b: // // >> (v >> 6*9) & 0x3f // => 61 static const int64x2_t r_ab = { 0x0f4fac6f92a43900LL, 0x0e15677702b4ab01LL }, r_c = { 0x000000000e22751bLL, 0 }; // apply rho rotation to row static inline row_t row_rho(const row_t a, const size_t id) { const int64x2_t v0_hi = (r_ab >> (6 * id)) & 0x3f, v0_lo = ((r_ab >> (6 * id)) & 0x3f) - 64, v1_hi = (r_ab >> (30 + (6 * id))) & 0x3f, v1_lo = ((r_ab >> (30 + (6 * id))) & 0x3f) - 64, v2_hi = (r_c >> (6 * id)) & 0x3f, v2_lo = ((r_c >> (6 * id)) & 0x3f) - 64; return row_set( vorrq_u64(vshlq_u64(ROW_GET(a, 0), v0_hi), vshlq_u64(ROW_GET(a, 0), v0_lo)), vorrq_u64(vshlq_u64(ROW_GET(a, 1), v1_hi), vshlq_u64(ROW_GET(a, 1), v1_lo)), vorrq_u64(vshlq_u64(ROW_GET(a, 2), v2_hi), vshlq_u64(ROW_GET(a, 2), v2_lo)) ); } // c = (~a & b) // note: was using ~(a | ~b) = (~a & b) (demorgan's laws), but changed // to BIC b, a instead (b & ~a) static inline row_t row_andn(const row_t a, const row_t b) { return row_set( vbicq_u64(ROW_GET(b, 0), ROW_GET(a, 0)), vbicq_u64(ROW_GET(b, 1), ROW_GET(a, 1)), vbicq_u64(ROW_GET(b, 2), ROW_GET(a, 2)) ); } // apply chi permutation to entire row // note: ~(a | ~b) = (~a & b) (demorgan's laws) static inline row_t row_chi(const row_t a) { return row_eor(a, row_andn(row_rlr(a), row_set( ROW_GET(a, 1), // { a2, a3 } vtrn1q_u64(ROW_GET(a, 2), ROW_GET(a, 0)), // { a4, a0 } vdupq_laneq_u64(ROW_GET(a, 0), 1) // { a1, n/a } ))); } // return new vector with low lane of first argument and high lane of // second argument static inline uint64x2_t pi_lo_hi(const uint64x2_t a, const uint64x2_t b) { // was using vqtbl2q_u8() with tables, but this is faster const uint64x2_t c = vextq_u64(b, a, 1); return vextq_u64(c, c, 1); } /** * @brief Neon Keccak permutation. * * @param[in,out] s Keccak state (array of 25 64-bit integers). * @param[in] num_rounds Number of rounds (12 or 24). * * @note Experimental Neon backend. Slower than scalar backend and not * enabled by default. */ static inline void permute_n_neon(uint64_t a[static 25], const size_t num_rounds) { // Map of Keccak state to 64-bit lanes of 128-bit registers // --------------------------------------------------------- // | | Column / Register and 64-Bit Lane | // |-------------------------------------------------------| // | Row | 3 | 4 | 0 | 1 | 2 | // |-----|---------|---------|---------|---------|---------| // | 2 | r2.p1.1 | r2.p2.0 | r2.p0.0 | r2.p0.1 | r2.p1.0 | // | 1 | r1.p1.1 | r1.p2.0 | r1.p0.0 | r1.p0.1 | r1.p1.0 | // | 0 | r0.p1.1 | r0.p2.0 | r0.p0.0 | r0.p0.1 | r1.p1.0 | // | 4 | r4.p1.1 | r4.p2.0 | r4.p0.0 | r4.p0.1 | r1.p1.0 | // | 3 | r3.p1.1 | r3.p2.0 | r3.p0.0 | r3.p0.1 | r1.p1.0 | // --------------------------------------------------------- // load rows row_t r0 = row_load(a + 0), r1 = row_load(a + 5), r2 = row_load(a + 10), r3 = row_load(a + 15), r4 = row_load(a + 20); // round loop (two rounds per iteration) for (size_t i = 24 - num_rounds; i < SHA3_NUM_ROUNDS; i++) { /* theta */ { /* c = r0 ^ r1 ^ r2 ^ r3 ^ r4, d = rll(c) ^ (rlr(c) << 1) */ const row_t c = row_eor5(r0, r1, r2, r3, r4), d = row_eor(row_rll(c), row_rol1_u64(row_rlr(c))); r0 = row_eor(r0, d); /* r0 ^= d */ r1 = row_eor(r1, d); /* r1 ^= d */ r2 = row_eor(r2, d); /* r2 ^= d */ r3 = row_eor(r3, d); /* r3 ^= d */ r4 = row_eor(r4, d); /* r4 ^= d */ } /* rho */ { r0 = row_rho(r0, 0); r1 = row_rho(r1, 1); r2 = row_rho(r2, 2); r3 = row_rho(r3, 3); r4 = row_rho(r4, 4); } /* pi */ { const row_t t0 = row_set( pi_lo_hi(ROW_GET(r0, 0), ROW_GET(r1, 0)), pi_lo_hi(ROW_GET(r2, 1), ROW_GET(r3, 1)), ROW_GET(r4, 2) ); const row_t t1 = row_set( vextq_u64(ROW_GET(r0, 1), ROW_GET(r1, 2), 1), pi_lo_hi(ROW_GET(r2, 0), ROW_GET(r3, 0)), ROW_GET(r4, 1) ); const row_t t2 = row_set( vextq_u64(ROW_GET(r0, 0), ROW_GET(r1, 1), 1), vextq_u64(ROW_GET(r2, 1), ROW_GET(r3, 2), 1), ROW_GET(r4, 0) ); const row_t t3 = row_set( vtrn1q_u64(ROW_GET(r0, 2), ROW_GET(r1, 0)), vextq_u64(ROW_GET(r2, 0), ROW_GET(r3, 1), 1), vdupq_laneq_u64(ROW_GET(r4, 1), 1) ); const row_t t4 = row_set( pi_lo_hi(ROW_GET(r0, 1), ROW_GET(r1, 1)), vtrn1q_u64(ROW_GET(r2, 2), ROW_GET(r3, 0)), vdupq_laneq_u64(ROW_GET(r4, 0), 1) ); /* store rows */ r0 = t0; r1 = t1; r2 = t2; r3 = t3; r4 = t4; } /* chi */ r0 = row_chi(r0); r1 = row_chi(r1); r2 = row_chi(r2); r3 = row_chi(r3); r4 = row_chi(r4); /* iota */ r0.p0 ^= (uint64x2_t) { RCS[i], 0 }; } // store rows row_store(a + 0, r0); row_store(a + 5, r1); row_store(a + 10, r2); row_store(a + 15, r3); row_store(a + 20, r4); } #endif /* BACKEND == BACKEND_NEON */ #if BACKEND == BACKEND_DIET_NEON #include // rotate element in uint64x1_t left by N bits #define VROL(A, N) vsri_n_u64(vshl_n_u64((A), (N)), (A), 64-(N)) // rotate elements in uint64x2_t left by N bits // note: vrax1q_u64() not supported on pizza #define VROLQ(A, N) vsriq_n_u64(vshlq_n_u64((A), (N)), (A), 64-(N)) // keccak row, represented as 3 128-bit vector registers // // columns are stored in the low 5 64-bit lanes. this wastes one // 64-bit lane per row at the expense of making many of the instructions // simpler. typedef struct { uint64x2_t p0, p1; // first 4 columns uint64x1_t p2; // last column } row_t; // set contents of row static inline row_t row_set(const uint64x2_t a, const uint64x2_t b, const uint64x1_t c) { return (row_t) { a, b, c }; } // get Nth pair of u64s from row // (N = [0, 1], returns uint64x2_t, N == 2, returns uint64x1_t) #define row_get(A, N) ((A).p ## N) #define row_last(A) ((A).p2) // rotate row lanes left // // --------------------------- --------------------------- // | 64-bit Lanes (Before) | | 64-bit Lanes (After) | // |-------------------------| |-------------------------| // | 0 | 1 | 2 | 3 | 4 | 5 | --> | 0 | 1 | 2 | 3 | 4 | 5 | // |---|---|---|---|---|-----| |---|---|---|---|---|-----| // | A | B | C | D | E | n/a | | E | A | B | C | D | n/a | // --------------------------- --------------------------- // static inline row_t row_rll(const row_t a) { return row_set( vcombine_u64(row_last(a), vdup_laneq_u64(row_get(a, 0), 0)), // { a4, a0 } vextq_u64(row_get(a, 0), row_get(a, 1), 1), // { a1, a2 } vdup_laneq_u64(row_get(a, 1), 1) // { a3, n/a } ); } // rotate row lanes right // // --------------------------- --------------------------- // | 64-bit Lanes (Before) | | 64-bit Lanes (After) | // |-------------------------| |-------------------------| // | 0 | 1 | 2 | 3 | 4 | 5 | --> | 0 | 1 | 2 | 3 | 4 | 5 | // |---|---|---|---|---|-----| |---|---|---|---|---|-----| // | A | B | C | D | E | n/a | | B | C | D | E | A | n/a | // --------------------------- --------------------------- // static inline row_t row_rlr(const row_t a) { return row_set( vextq_u64(row_get(a, 0), row_get(a, 1), 1), // { a1, a2 } vcombine_u64(vdup_laneq_u64(row_get(a, 1), 1), row_last(a)), // { a3, a4 } vdup_laneq_u64(row_get(a, 0), 0) // { a0, n/a } ); } // c = a ^ b static inline row_t row_eor(const row_t a, const row_t b) { return row_set( row_get(a, 0) ^ row_get(b, 0), row_get(a, 1) ^ row_get(b, 1), row_last(a) ^ row_last(b) ); } // f = a ^ b ^ c ^ d ^ e // FIXME want: veor3_u64(a, b, c); static inline row_t row_eor5(const row_t a, const row_t b, const row_t c, const row_t d, const row_t e) { return row_set( row_get(a, 0) ^ row_get(b, 0) ^ row_get(c, 0) ^ row_get(d, 0) ^ row_get(e, 0), row_get(a, 1) ^ row_get(b, 1) ^ row_get(c, 1) ^ row_get(d, 1) ^ row_get(e, 1), row_last(a) ^ row_last(b) ^ row_last(c) ^ row_last(d) ^ row_last(e) ); } // rotate bits in each lane left one bit static inline row_t row_rol1_u64(const row_t a) { return row_set( VROLQ(row_get(a, 0), 1), VROLQ(row_get(a, 1), 1), VROL(row_last(a), 1) ); } static const int64x2_t r_ab = { 0x0f4fac6f92a43900LL, 0x0e15677702b4ab01LL }; static const int64x1_t r_c = { 0x000000000e22751bLL }; // apply rho rotation to row static inline row_t row_rho(const row_t a, const size_t id) { const int64x2_t v0_hi = (r_ab >> (6 * id)) & 0x3f, v0_lo = ((r_ab >> (6 * id)) & 0x3f) - 64, v1_hi = (r_ab >> (30 + (6 * id))) & 0x3f, v1_lo = ((r_ab >> (30 + (6 * id))) & 0x3f) - 64; const int64x1_t v2_hi = (r_c >> (6 * id)) & 0x3f, v2_lo = ((r_c >> (6 * id)) & 0x3f) - 64; return row_set( vorrq_u64(vshlq_u64(row_get(a, 0), v0_hi), vshlq_u64(row_get(a, 0), v0_lo)), vorrq_u64(vshlq_u64(row_get(a, 1), v1_hi), vshlq_u64(row_get(a, 1), v1_lo)), vorr_u64(vshl_u64(row_last(a), v2_hi), vshl_u64(row_last(a), v2_lo)) ); } // c = (~a & b) // note: was using ~(a | ~b) = (~a & b) (demorgan's laws), but changed // to BIC b, a instead (b & ~a) static inline row_t row_andn(const row_t a, const row_t b) { return row_set( vbicq_u64(row_get(b, 0), row_get(a, 0)), vbicq_u64(row_get(b, 1), row_get(a, 1)), vbic_u64(row_last(b), row_last(a)) ); } // apply chi permutation to entire row // note: ~(a | ~b) = (~a & b) (demorgan's laws) static inline row_t row_chi(const row_t a) { return row_eor(a, row_andn(row_rlr(a), row_set( row_get(a, 1), // { a2, a3 } vcombine_u64(row_last(a), vdup_laneq_u64(row_get(a, 0), 0)), // { a4, a0 } vdup_laneq_u64(row_get(a, 0), 1) // { a1 } ))); } // return new vector with low lane of first argument and high lane of // second argument static inline uint64x2_t pi_lo_hi(const uint64x2_t a, const uint64x2_t b) { // was using vqtbl2q_u8() with tables, but this is faster const uint64x2_t c = vextq_u64(b, a, 1); return vextq_u64(c, c, 1); } /** * @brief Neon Keccak permutation. * * @param[in,out] s Keccak state (array of 25 64-bit integers). * @param[in] num_rounds Number of rounds (12 or 24). * * @note Experimental Neon backend which uses one fewer 64-bit register * than the "neon" backend. Slower than scalar backend and not enabled * by default. */ static inline void permute_n_diet_neon(uint64_t a[static 25], const size_t num_rounds) { // load rows row_t r0, r1, r2, r3, r4; { // 3 loads of 8 and 1 load of 1 cell (3*8 + 1 = 25) const uint64x2x4_t m0 = vld1q_u64_x4(a + 0), // r0 cols 0-4, r1 cols 0-2 m1 = vld1q_u64_x4(a + 8), // r1 cols 3-4, r2 cols 0-4, r3 col 1 m2 = vld1q_u64_x4(a + 16); // r3 cols 1-4, r4 cols 0-3 const uint64x1_t m3 = vld1_u64(a + 24); // r4 col 4 // permute loaded data into rows r0 = row_set(m0.val[0], m0.val[1], vdup_laneq_u64(m0.val[2], 0)); r1 = row_set(vextq_u64(m0.val[2], m0.val[3], 1), vextq_u64(m0.val[3], m1.val[0], 1), vdup_laneq_u64(m1.val[0], 1)); r2 = row_set(m1.val[1], m1.val[2], vdup_laneq_u64(m1.val[3], 0)); r3 = row_set(vextq_u64(m1.val[3], m2.val[0], 1), vextq_u64(m2.val[0], m2.val[1], 1), vdup_laneq_u64(m2.val[1], 1)); r4 = row_set(m2.val[2], m2.val[3], m3); } // loop for num rounds for (size_t i = 24 - num_rounds; i < 24; i++) { // theta { // c = r0 ^ r1 ^ r2 ^ r3 ^ r4, d = rll(c) ^ (rlr(c) << 1) const row_t c = row_eor5(r0, r1, r2, r3, r4), d = row_eor(row_rll(c), row_rol1_u64(row_rlr(c))); r0 = row_eor(r0, d); // r0 ^= d r1 = row_eor(r1, d); // r1 ^= d r2 = row_eor(r2, d); // r2 ^= d r3 = row_eor(r3, d); // r3 ^= d r4 = row_eor(r4, d); // r4 ^= d } // rho r0 = row_rho(r0, 0); r1 = row_rho(r1, 1); r2 = row_rho(r2, 2); r3 = row_rho(r3, 3); r4 = row_rho(r4, 4); // pi { const row_t t0 = row_set( pi_lo_hi(row_get(r0, 0), row_get(r1, 0)), pi_lo_hi(row_get(r2, 1), row_get(r3, 1)), row_last(r4) ); const row_t t1 = row_set( vcombine_u64(vdup_laneq_u64(row_get(r0, 1), 1), row_last(r1)), pi_lo_hi(row_get(r2, 0), row_get(r3, 0)), vdup_laneq_u64(row_get(r4, 1), 0) ); const row_t t2 = row_set( vextq_u64(row_get(r0, 0), row_get(r1, 1), 1), vcombine_u64(vdup_laneq_u64(row_get(r2, 1), 1), row_last(r3)), vdup_laneq_u64(row_get(r4, 0), 0) ); const row_t t3 = row_set( vcombine_u64(row_last(r0), vdup_laneq_u64(row_get(r1, 0), 0)), vextq_u64(row_get(r2, 0), row_get(r3, 1), 1), vdup_laneq_u64(row_get(r4, 1), 1) ); const row_t t4 = row_set( pi_lo_hi(row_get(r0, 1), row_get(r1, 1)), vcombine_u64(row_last(r2), vdup_laneq_u64(row_get(r3, 0), 0)), vdup_laneq_u64(row_get(r4, 0), 1) ); // store rows r0 = t0; r1 = t1; r2 = t2; r3 = t3; r4 = t4; } // chi r0 = row_chi(r0); r1 = row_chi(r1); r2 = row_chi(r2); r3 = row_chi(r3); r4 = row_chi(r4); // iota const uint64x2_t rc = { RCS[i], 0 }; r0.p0 ^= rc; } // store rows { // store columns 0-4 of r0 and columns 0-2 of r1 const uint64x2x4_t m0 = { .val = { row_get(r0, 0), row_get(r0, 1), vcombine_u64(row_last(r0), vdup_laneq_u64(row_get(r1, 0), 0)), vextq_u64(row_get(r1, 0), row_get(r1, 1), 1) }, }; vst1q_u64_x4(a + 0, m0); } { // store columns 3-4 of r1, columns 0-4 of r2, and column 0 of r3 const uint64x2x4_t m1 = { .val = { vcombine_u64(vdup_laneq_u64(row_get(r1, 1), 1), row_last(r1)), row_get(r2, 0), row_get(r2, 1), vcombine_u64(row_last(r2), vdup_laneq_u64(row_get(r3, 0), 0)), }, }; vst1q_u64_x4(a + 8, m1); } { // store columns 1-4 of r3 and columns 03 of r4 const uint64x2x4_t m2 = { .val = { vextq_u64(row_get(r3, 0), row_get(r3, 1), 1), vcombine_u64(vdup_laneq_u64(row_get(r3, 1), 1), row_last(r3)), row_get(r4, 0), row_get(r4, 1), }, }; vst1q_u64_x4(a + 16, m2); } // store column 4 of r4 vst1_u64(a + 24, row_last(r4)); } #endif /* BACKEND == BACKEND_DIET_NEON */ #if (BACKEND == BACKEND_HYBRID) #include /** * @brief Hybrid scalar/neon Keccak permutation. * * Apply `num_rounds` of Keccak permutation. * * @param[in,out] a Keccak state (array of 25 64-bit integers). * @param[in] num_rounds Number of rounds (12 or 24). * * @note Slower than scalar backend and not enabled by default. */ static inline void permute_n_hybrid(uint64_t a[static 25], const size_t num_rounds) { uint64_t tmp[25] = { 0 }; for (size_t i = SHA3_NUM_ROUNDS - num_rounds; i < SHA3_NUM_ROUNDS; i++) { // theta 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), }; const uint64x2_t d0 = { d[0], d[1] }, d1 = { d[2], d[3] }; const uint64x1_t d2 = { d[4] }; uint64x2_t r0a = { a[ 0], a[ 1] }, r0b = { a[ 2], a[ 3] }, r1a = { a[ 5], a[ 6] }, r1b = { a[ 7], a[ 8] }, r2a = { a[10], a[11] }, r2b = { a[12], a[13] }, r3a = { a[15], a[16] }, r3b = { a[17], a[18] }, r4a = { a[20], a[21] }, r4b = { a[22], a[23] }; uint64x1_t r0c = { a[ 4] }, r1c = { a[ 9] }, r2c = { a[14] }, r3c = { a[19] }, r4c = { a[24] }; r0a ^= d0; r0b ^= d1; r0c ^= d2; r1a ^= d0; r1b ^= d1; r1c ^= d2; r2a ^= d0; r2b ^= d1; r2c ^= d2; r3a ^= d0; r3b ^= d1; r3c ^= d2; r4a ^= d0; r4b ^= d1; r4c ^= d2; // rho { static const uint64x2_t r0a_ids = { 0, 1 }, r0b_ids = { 62, 28 }, r1a_ids = { 36, 44 }, r1b_ids = { 6, 55 }, r2a_ids = { 3, 10 }, r2b_ids = { 43, 25 }, r3a_ids = { 41, 45 }, r3b_ids = { 15, 21 }, r4a_ids = { 18, 2 }, r4b_ids = { 61, 56 }; static const uint64x1_t r0c_ids = { 27 }, r1c_ids = { 20 }, r2c_ids = { 39 }, r3c_ids = { 8 }, r4c_ids = { 14 }; r0a = (r0a << r0a_ids) | (r0a >> (64 - r0a_ids)); r0b = (r0b << r0b_ids) | (r0b >> (64 - r0b_ids)); r0c = (r0c << r0c_ids) | (r0c >> (64 - r0c_ids)); r1a = (r1a << r1a_ids) | (r1a >> (64 - r1a_ids)); r1b = (r1b << r1b_ids) | (r1b >> (64 - r1b_ids)); r1c = (r1c << r1c_ids) | (r1c >> (64 - r1c_ids)); r2a = (r2a << r2a_ids) | (r2a >> (64 - r2a_ids)); r2b = (r2b << r2b_ids) | (r2b >> (64 - r2b_ids)); r2c = (r2c << r2c_ids) | (r2c >> (64 - r2c_ids)); r3a = (r3a << r3a_ids) | (r3a >> (64 - r3a_ids)); r3b = (r3b << r3b_ids) | (r3b >> (64 - r3b_ids)); r3c = (r3c << r3c_ids) | (r3c >> (64 - r3c_ids)); r4a = (r4a << r4a_ids) | (r4a >> (64 - r4a_ids)); r4b = (r4b << r4b_ids) | (r4b >> (64 - r4b_ids)); r4c = (r4c << r4c_ids) | (r4c >> (64 - r4c_ids)); vst1q_u64(a + 0, r0a); vst1q_u64(a + 2, r0b); vst1_u64(a + 4, r0c); vst1q_u64(a + 5, r1a); vst1q_u64(a + 7, r1b); vst1_u64(a + 9, r1c); vst1q_u64(a + 10, r2a); vst1q_u64(a + 12, r2b); vst1_u64(a + 14, r2c); vst1q_u64(a + 15, r3a); vst1q_u64(a + 17, r3b); vst1_u64(a + 19, r3c); vst1q_u64(a + 20, r4a); vst1q_u64(a + 22, r4b); vst1_u64(a + 24, r4c); } // pi { tmp[ 0] = a[ 0]; tmp[ 1] = a[ 6]; tmp[ 2] = a[12]; tmp[ 3] = a[18]; tmp[ 4] = a[24]; tmp[ 5] = a[ 3]; tmp[ 6] = a[ 9]; tmp[ 7] = a[10]; tmp[ 8] = a[16]; tmp[ 9] = a[22]; tmp[10] = a[ 1]; tmp[11] = a[ 7]; tmp[12] = a[13]; tmp[13] = a[19]; tmp[14] = a[20]; tmp[15] = a[ 4]; tmp[16] = a[ 5]; tmp[17] = a[11]; tmp[18] = a[17]; tmp[19] = a[23]; tmp[20] = a[ 2]; tmp[21] = a[ 8]; tmp[22] = a[14]; tmp[23] = a[15]; tmp[24] = a[21]; } // chi { a[ 0] = tmp[ 0] ^ (~tmp[ 1] & tmp[ 2]); a[ 1] = tmp[ 1] ^ (~tmp[ 2] & tmp[ 3]); a[ 2] = tmp[ 2] ^ (~tmp[ 3] & tmp[ 4]); a[ 3] = tmp[ 3] ^ (~tmp[ 4] & tmp[ 0]); a[ 4] = tmp[ 4] ^ (~tmp[ 0] & tmp[ 1]); a[ 5] = tmp[ 5] ^ (~tmp[ 6] & tmp[ 7]); a[ 6] = tmp[ 6] ^ (~tmp[ 7] & tmp[ 8]); a[ 7] = tmp[ 7] ^ (~tmp[ 8] & tmp[ 9]); a[ 8] = tmp[ 8] ^ (~tmp[ 9] & tmp[ 5]); a[ 9] = tmp[ 9] ^ (~tmp[ 5] & tmp[ 6]); a[10] = tmp[10] ^ (~tmp[11] & tmp[12]); a[11] = tmp[11] ^ (~tmp[12] & tmp[13]); a[12] = tmp[12] ^ (~tmp[13] & tmp[14]); a[13] = tmp[13] ^ (~tmp[14] & tmp[10]); a[14] = tmp[14] ^ (~tmp[10] & tmp[11]); a[15] = tmp[15] ^ (~tmp[16] & tmp[17]); a[16] = tmp[16] ^ (~tmp[17] & tmp[18]); a[17] = tmp[17] ^ (~tmp[18] & tmp[19]); a[18] = tmp[18] ^ (~tmp[19] & tmp[15]); a[19] = tmp[19] ^ (~tmp[15] & tmp[16]); a[20] = tmp[20] ^ (~tmp[21] & tmp[22]); a[21] = tmp[21] ^ (~tmp[22] & tmp[23]); a[22] = tmp[22] ^ (~tmp[23] & tmp[24]); a[23] = tmp[23] ^ (~tmp[24] & tmp[20]); a[24] = tmp[24] ^ (~tmp[20] & tmp[21]); } a[0] ^= RCS[i]; } } #endif /* (BACKEND == BACKEND_HYBRID) */ // map permute_n() to active backend #if BACKEND == BACKEND_AVX512 #define permute_n permute_n_avx512 // use avx512 backend #elif BACKEND == BACKEND_AVX2 #define permute_n permute_n_avx2 // use AVX2 backend #elif BACKEND == BACKEND_NEON #define permute_n permute_n_neon // use neon backend #elif BACKEND == BACKEND_DIET_NEON #define permute_n permute_n_diet_neon // use diet-neon backend #elif BACKEND == BACKEND_HYBRID #define permute_n permute_n_hybrid // use hybrid backend #elif BACKEND == BACKEND_SCALAR #define permute_n permute_n_scalar // use scalar backend #else #error "unknown sha3 backend" #endif /* BACKEND */ /** * @brief 24 round Keccak permutation. * @param[in,out] a Keccak state (array of 25 64-bit integers). */ static inline void permute_24(uint64_t s[static 25]) { permute_n(s, 24); } /** * @brief 12 round Keccak permutation. * @param[in,out] a Keccak state (array of 25 64-bit integers). * @note Only used by TurboSHAKE and KangarooTwelve. */ static inline void permute_12(uint64_t s[static 25]) { permute_n(s, 12); } /** * @brief Absorb message into state and return updated byte count. * * Used by `hash_once()`, `hash_absorb()`, `xof_absorb_raw()`. * * @param[in,out] a Keccak state (array of 25 64-bit integers). * @param[in] num_bytes Number of absorbed bytes since last permute. * @param[in] rate Rate of has function. * @param[in] m Pointer to input message chunk. * @param[in] m_len Length of input message chunk, in bytes. */ static inline size_t absorb(sha3_state_t * const a, size_t num_bytes, const size_t rate, const uint8_t *m, size_t m_len) { // absorb aligned chunks if ((num_bytes & 7) == 0 && (((uintptr_t) m) & 7) == 0) { // absorb 32 byte chunks (4 x uint64) while (m_len >= 32 && num_bytes <= rate - 32) { // xor chunk into state // (FIXME: does not vectorize for some reason, even when unrolled) for (size_t i = 0; i < 4; i++) { 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_24(a->u64); num_bytes = 0; } } // absorb 8 byte chunks (1 x uint64) while (m_len >= 8 && num_bytes <= rate - 8) { // xor chunk into state 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_24(a->u64); num_bytes = 0; } } } // absorb remaining bytes for (size_t i = 0; i < m_len; i++) { // xor byte into state a->u8[num_bytes++] ^= m[i]; if (num_bytes == rate) { // permute state permute_24(a->u64); num_bytes = 0; } } // return byte count return num_bytes; } /** * @brief Absorb message into XOF12 state and return updated byte count. * * Used by `xof12_absorb_raw()`. * * @param[in,out] a Keccak state (array of 25 64-bit integers). * @param[in] num_bytes Number of absorbed bytes since last permute. * @param[in] rate Rate of hash function. * @param[in] m Pointer to input message chunk. * @param[in] m_len Length of input message chunk, in bytes. */ static inline size_t absorb_12(sha3_state_t * const a, size_t num_bytes, const size_t rate, const uint8_t *m, size_t m_len) { // absorb aligned chunks if ((num_bytes & 7) == 0 && (((uintptr_t) m) & 7) == 0) { // absorb 32 byte chunks (4 x uint64) while (m_len >= 32 && num_bytes <= rate - 32) { // xor chunk into state // (FIXME: does not vectorize for some reason, even when unrolled) for (size_t i = 0; i < 4; i++) { 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_12(a->u64); num_bytes = 0; } } // absorb 8 byte chunks (1 x uint64) while (m_len >= 8 && num_bytes <= rate - 8) { // xor chunk into state 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_12(a->u64); num_bytes = 0; } } } // absorb remaining bytes for (size_t i = 0; i < m_len; i++) { // xor byte into state a->u8[num_bytes++] ^= m[i]; if (num_bytes == rate) { // permute state permute_12(a->u64); num_bytes = 0; } } // return byte count return num_bytes; } // Get the rate of a FIPS 202 hash function or extendable-output // function (XOF). // // The "rate" is the number of bytes that can be absorbed or squeezed // before the internal state is permuted. It is calculated by the total // state size (200 bytes) minus the capacity (FIPS 202, Section 5.2). // // The capacity and rate is determined as follows: // // * Hash functions: The capacity is 2 times the length of the output // digest. For example, the length of a SHA3-256 digest is 32 bytes // (256 bits), so the capacity is 64 bytes and the rate is 136 bytes // (200-64 = 136). // * XOFs: The capacity is 2 times the named strength. For example, the // named strength of SHAKE128 is 16 bytes (128 bits), so the capacity // is 32 bytes and the rate is 168 bytes (200-32 = 168). // // The table below shows the output size, rate, and capacity for each // FIPS 202 function. All values are in bytes. // // --------------------------------------- // | Function | Output | Rate | Capacity | // |----------|--------|------|----------| // | SHA3-224 | 28 | 144 | 56 | // | SHA3-256 | 32 | 136 | 64 | // | SHA3-384 | 48 | 104 | 96 | // | SHA3-512 | 64 | 72 | 128 | // | SHAKE128 | n/a | 168 | 32 | // | SHAKE256 | n/a | 136 | 64 | // --------------------------------------- // #define RATE(len) (200 - 2 * (len)) /** * @brief One-shot function which hashes the input message and writes * the digest to the destination buffer. * * Used by `sha3_224()`, `sha3_256()`, `sha3_384()` and `sha3_512()`. * * @param[in] m Pointer to input message. * @param[in] m_len Length of input message, in bytes. * @param[out] dst Pointer to destination buffer. * @param[in] dst_len Length of destination buffer, in bytes. Used to * determine the rate of the hash function. */ static inline void hash_once(const uint8_t *m, size_t m_len, uint8_t * const dst, const size_t dst_len) { // init state sha3_state_t a = { .u64 = { 0 } }; // absorb message, get new internal length const size_t len = absorb(&a, 0, RATE(dst_len), m, m_len); // append suffix and padding // (note: suffix and padding are ambiguous in spec) a.u8[len] ^= 0x06; a.u8[RATE(dst_len)-1] ^= 0x80; // final permutation permute_24(a.u64); // copy to destination memcpy(dst, a.u8, dst_len); } /** * @brief Initialize iterative hash context. * * Used by `sha3_224_init()`, `sha3_256_init()`, `sha3_384_init()` and * `sha3_512_init()`. * * @param[in,out] hash Hash context. */ static inline void hash_init(sha3_t * const hash) { memset(hash, 0, sizeof(sha3_t)); } /** * @brief Absorb data into iterative hash context. * * Used by `sha3_224_absorb()`, `sha3_256_absorb()`, `sha3_384_absorb()` * and `sha3_512_absorb()`. * * @param[in,out] hash Hash context. * @param[in] rate Hash function rate. * @param[in] src Pointer to buffer containing chunk of input message. * @param[in] src_len Length of input message chunk, in bytes. * * @return True if data was absorbed, and false if the hash context has * already been finalized. */ 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, return success hash->num_bytes = absorb(&(hash->a), hash->num_bytes, rate, src, len); return true; } /** * @brief Finalize iterative hash context. * * Used by `sha3_224_final()`, `sha3_256_final()`, `sha3_384_final()` * and `sha3_512_final()`. * * @param[in,out] hash Hash context. * @param[in] rate Hash function rate. * @param[in] dst Pointer to destination buffer. * @param[in] dst_len Length of destination buffer, in bytes. * * @note May be called more than once without affecting the final digest value. */ 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_24(hash->a.u64); } // copy to destination memcpy(dst, hash->a.u8, dst_len); } // define hash one-shot and iterative context functions #define DEF_HASH(BITS, OUT_LEN) \ /* one-shot hash */ \ void sha3_ ## BITS(const uint8_t *m, size_t m_len, uint8_t dst[static OUT_LEN]) { \ hash_once(m, m_len, dst, OUT_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, RATE(OUT_LEN), src, len); \ } \ \ /* Finalize SHA3 iterative hash context. */ \ void sha3_ ## BITS ## _final(sha3_t * const hash, uint8_t dst[static OUT_LEN]) { \ hash_final(hash, RATE(OUT_LEN), dst, OUT_LEN); \ } // declare hash functions DEF_HASH(224, 28) // sha3-224 DEF_HASH(256, 32) // sha3-256 DEF_HASH(384, 48) // sha3-384 DEF_HASH(512, 64) // sha3-512 /** * @brief Initialize XOF context. * * @param[in,out] xof XOF context. */ static inline void xof_init(sha3_xof_t * const xof) { memset(xof, 0, sizeof(sha3_xof_t)); } /** * @brief Absorb data into XOF context without checking to see if the * context has already been squeezed. * * Called by `xof_absorb()` and `xof_once()`. * * @param[in,out] xof XOF context. * @param[in] rate Rate of XOF function. * @param[in] m Pointer to buffer containing chunk of input message. * @param[in] m_len Length of input message chunk, in bytes. */ static inline void xof_absorb_raw(sha3_xof_t * const xof, const size_t rate, const uint8_t *m, size_t m_len) { xof->num_bytes = absorb(&(xof->a), xof->num_bytes, rate, m, m_len); } /** * @brief Absorb data into XOF context. * * @param[in,out] xof XOF context. * @param[in] rate Rate of XOF function. * @param[in] m Pointer to buffer containing chunk of input message. * @param[in] m_len Length of input message chunk, in bytes. * * @return `true` if the input message chunk was absorbed, or `false` if * this XOF context has already been squeezed. */ static inline _Bool xof_absorb(sha3_xof_t * const xof, const size_t rate, const uint8_t * const m, size_t m_len) { // check context state if (xof->squeezing) { // xof has already been squeezed, return error return false; } // absorb, return success xof_absorb_raw(xof, rate, m, m_len); return true; } /** * @brief Finalize absorb for this XOF context and switch context mode * from absorbing to squeezing. * * @param[in,out] xof XOF context. * @param[in] rate Rate of XOF function. * @param[in] pad Padding byte of XOF function. */ static inline void xof_absorb_done(sha3_xof_t * const xof, const size_t rate, 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_24(xof->a.u64); // switch to squeeze mode xof->num_bytes = 0; xof->squeezing = true; } /** * @brief Squeeze data from XOF context without checking mode. * * @param[in,out] xof XOF context. * @param[in] rate Rate of XOF function. * @param[out] dst Pointer to destination buffer. * @param[out] dst_len Length of destination buffer, in bytes. */ static inline void xof_squeeze_raw(sha3_xof_t * const xof, const size_t rate, 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_24(xof->a.u64); // 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_24(xof->a.u64); // permute state xof->num_bytes = 0; // clear read bytes count } } } } /** * @brief Finalize absorb (if necessary) and then squeeze data from this * XOF context. * * @param[in,out] xof XOF context. * @param[in] rate Rate of XOF function. * @param[in] pad Padding byte of XOF function. * @param[out] dst Pointer to destination buffer. * @param[in] dst_len Length of destination buffer, in bytes. */ static inline void xof_squeeze(sha3_xof_t * const xof, const size_t rate, 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, pad); } xof_squeeze_raw(xof, rate, dst, dst_len); } /** * @brief One-shot XOF absorb and squeeze. * * @param[in] rate Rate of XOF function. * @param[in] pad Padding byte of XOF function. * @param[in] src Pointer to buffer containing input message. * @param[in] src_len Length of input message, in bytes. * @param[out] dst Pointer to destination buffer. * @param[out] dst_len Length of destination buffer, in bytes. */ static inline void xof_once(const size_t rate, 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, src, src_len); xof_absorb_done(&xof, rate, pad); // squeeze xof_squeeze_raw(&xof, rate, dst, dst_len); } /** * @brief Initialize XOF12 context. * * @param[in,out] xof XOF12 context. */ static inline void xof12_init(sha3_xof12_t * const xof) { memset(xof, 0, sizeof(sha3_xof12_t)); } /** * @brief Absorb data into XOF12 context without checking to see if the * context has already been squeezed. * * Called by `xof12_absorb()` and `xof12_once()`. * * @param[in,out] xof XOF12 context. * @param[in] rate Rate of XOF12 function. * @param[in] m Pointer to buffer containing chunk of input message. * @param[in] m_len Length of input message chunk, in bytes. */ static inline void xof12_absorb_raw(sha3_xof12_t * const xof, const size_t rate, const uint8_t *m, size_t m_len) { xof->num_bytes = absorb_12(&(xof->a), xof->num_bytes, rate, m, m_len); } /** * @brief Absorb data into XOF12 context. * * @param[in,out] xof XOF12 context. * @param[in] rate Rate of XOF12 function. * @param[in] m Pointer to buffer containing chunk of input message. * @param[in] m_len Length of input message chunk, in bytes. * * @return `true` if the input message chunk was absorbed, or `false` if * this XOF context has already been squeezed. */ static inline _Bool xof12_absorb(sha3_xof12_t * const xof, const size_t rate, const uint8_t * const m, size_t m_len) { // check context state if (xof->squeezing) { // xof has already been squeezed, return error return false; } // absorb, return success xof12_absorb_raw(xof, rate, m, m_len); return true; } /** * @brief Finalize absorb for this XOF12 context and switch context mode * from absorbing to squeezing. * * @param[in,out] xof XOF12 context. * @param[in] rate Rate of XOF12 function. * @param[in] pad Padding byte of XOF12 function. */ static inline void xof12_absorb_done(sha3_xof12_t * const xof, const size_t rate, 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_12(xof->a.u64); // switch to squeeze mode xof->num_bytes = 0; xof->squeezing = true; } /** * @brief Squeeze data from XOF12 context without checking mode. * * @param[in,out] xof XOF12 context. * @param[in] rate Rate of XOF12 function. * @param[out] dst Pointer to destination buffer. * @param[out] dst_len Length of destination buffer, in bytes. */ static inline void xof12_squeeze_raw(sha3_xof12_t * const xof, const size_t rate, 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_12(xof->a.u64); // 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_12(xof->a.u64); // permute state xof->num_bytes = 0; // clear read bytes count } } } } /** * @brief Finalize absorb (if necessary) and then squeeze data from this * XOF12 context. * * @param[in,out] xof XOF12 context. * @param[in] rate Rate of XOF12 function. * @param[in] pad Padding byte of XOF12 function. * @param[out] dst Pointer to destination buffer. * @param[in] dst_len Length of destination buffer, in bytes. */ static inline void xof12_squeeze(sha3_xof12_t * const xof, const size_t rate, const uint8_t pad, uint8_t * const dst, const size_t dst_len) { // check state if (!xof->squeezing) { // finalize absorb xof12_absorb_done(xof, rate, pad); } xof12_squeeze_raw(xof, rate, dst, dst_len); } /** * @brief One-shot XOF12 absorb and squeeze. * * @param[in] rate Rate of XOF12 function. * @param[in] pad Padding byte of XOF12 function. * @param[in] src Pointer to buffer containing input message. * @param[in] src_len Length of input message, in bytes. * @param[out] dst Pointer to destination buffer. * @param[out] dst_len Length of destination buffer, in bytes. */ static inline void xof12_once(const size_t rate, 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_xof12_t xof; xof12_init(&xof); // absorb xof12_absorb_raw(&xof, rate, src, src_len); xof12_absorb_done(&xof, rate, pad); // squeeze xof12_squeeze_raw(&xof, rate, 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, 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, SHAKE_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, SHAKE_PAD, src, src_len, dst, dst_len); \ } // shake padding byte and rates #define SHAKE_PAD 0x1f #define SHAKE128_RATE RATE(16) // shake128 input rate, in bytes #define SHAKE256_RATE RATE(32) // shake256 input rate, in bytes // declare shake functions DEF_SHAKE(128) // shake128_{init,absorb,squeeze}() DEF_SHAKE(256) // shake256_{init,absorb,squeeze}() // define hmac-sha3 iterative context and one-shot functions #define DEF_HMAC(BITS, OUT_LEN) \ /* 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[RATE(OUT_LEN)] = { 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 < RATE(OUT_LEN); 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 < RATE(OUT_LEN); 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 OUT_LEN]) { \ /* finalize inner hash into buffer */ \ uint8_t buf[OUT_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 OUT_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); \ } // declare hmac-sha3 functions DEF_HMAC(224, 28) // hmac-sha3-224 DEF_HMAC(256, 32) // hmac-sha3-224 DEF_HMAC(384, 48) // hmac-sha3-224 DEF_HMAC(512, 64) // 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; } // cshake padding byte #define CSHAKE_PAD 0x04 // define cshake one-shot and iterative context functions #define DEF_CSHAKE(BITS) \ /* absorb data into cshake context */ \ _Bool cshake ## BITS ## _xof_absorb(sha3_xof_t * const xof, const uint8_t * const msg, const size_t len) { \ return xof_absorb(xof, SHAKE ## BITS ## _RATE, msg, len); \ } \ \ /* squeeze data from cshake context */ \ void cshake ## BITS ## _xof_squeeze(sha3_xof_t * const xof, uint8_t * const dst, const size_t len) { \ xof_squeeze(xof, SHAKE ## BITS ## _RATE, CSHAKE_PAD, dst, len); \ } \ \ /* initialize cshake context */ \ void cshake ## BITS ## _xof_init(sha3_xof_t * const xof, const cshake_params_t params) { \ static const uint8_t PAD[SHAKE ## BITS ## _RATE] = { 0 }; \ \ if (!params.name_len && !params.custom_len) { \ /* cshake w/o nist prefix and domain is shake */ \ shake ## BITS ## _init(xof); \ \ /* FIXME: padding will be wrong on subsequent 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, SHAKE ## BITS ## _RATE); \ \ /* init xof */ \ xof_init(xof); \ \ /* absorb bytepad prefix */ \ (void) cshake ## BITS ## _xof_absorb(xof, bp.prefix, bp.prefix_len); \ \ /* absorb name string */ \ (void) cshake ## BITS ## _xof_absorb(xof, name_buf, name_len); \ if (params.name_len > 0) { \ (void) cshake ## BITS ## _xof_absorb(xof, params.name, params.name_len); \ } \ \ /* absorb custom string */ \ (void) cshake ## BITS ## _xof_absorb(xof, custom_buf, custom_len); \ if (params.custom_len > 0) { \ (void) cshake ## BITS ## _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) cshake ## BITS ## _xof_absorb(xof, PAD, len); \ } \ } \ \ /* one-shot cshake */ \ void cshake ## BITS ( \ 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 */ \ shake ## BITS (msg, msg_len, dst, dst_len); \ return; \ } \ \ /* init */ \ sha3_xof_t xof; \ cshake ## BITS ## _xof_init(&xof, params); \ \ /* absorb */ \ (void) cshake ## BITS ## _xof_absorb(&xof, msg, msg_len); \ \ /* squeeze */ \ cshake ## BITS ## _xof_squeeze(&xof, dst, dst_len); \ } // declare cshake functions DEF_CSHAKE(128) // cshake128 DEF_CSHAKE(256) // cshake256 // define kmac one-shot and xof functions #define DEF_KMAC(BITS) \ /* one-shot kmac (non-xof) */ \ void kmac ## BITS ( \ 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[SHAKE ## BITS ## _RATE] = { 0 }; \ static const uint8_t NAME[4] = { 'K', 'M', 'A', 'C' }; \ \ /* build 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, SHAKE ## BITS ## _RATE); \ \ /* init xof */ \ sha3_xof_t xof; \ cshake ## BITS ## _xof_init(&xof, cshake_params); \ \ /* absorb bytepad prefix */ \ (void) cshake ## BITS ## _xof_absorb(&xof, bp.prefix, bp.prefix_len); \ \ /* absorb key */ \ (void) cshake ## BITS ## _xof_absorb(&xof, key_buf, key_buf_len); \ if (params.key_len > 0) { \ (void) cshake ## BITS ## _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) cshake ## BITS ## _xof_absorb(&xof, PAD, len); \ } \ \ /* absorb message */ \ (void) cshake ## BITS ## _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) cshake ## BITS ## _xof_absorb(&xof, suffix_buf, suffix_buf_len); \ \ /* squeeze */ \ cshake ## BITS ## _xof_squeeze(&xof, dst, dst_len); \ } \ \ /* absorb data into kmac-xof context */ \ _Bool kmac ## BITS ## _xof_absorb(sha3_xof_t * const xof, const uint8_t * const msg, const size_t len) { \ return cshake ## BITS ## _xof_absorb(xof, msg, len); \ } \ \ /* squeeze data from kmac-xof context */ \ void kmac ## BITS ## _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) cshake ## BITS ## _xof_absorb(xof, SUFFIX, sizeof(SUFFIX)); \ } \ cshake ## BITS ## _xof_squeeze(xof, dst, len); \ } \ \ /* init kmac-xof context */ \ void kmac ## BITS ## _xof_init(sha3_xof_t * const xof, const kmac_params_t params) { \ static const uint8_t PAD[SHAKE ## BITS ## _RATE] = { 0 }; \ static const uint8_t NAME[4] = { 'K', 'M', 'A', 'C' }; \ \ /* build cshake 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, SHAKE ## BITS ## _RATE); \ \ /* init xof */ \ cshake ## BITS ## _xof_init(xof, cshake_params); \ \ /* absorb bytepad prefix */ \ (void) cshake ## BITS ## _xof_absorb(xof, bp.prefix, bp.prefix_len); \ \ /* absorb key */ \ (void) cshake ## BITS ## _xof_absorb(xof, key_buf, key_buf_len); \ if (params.key_len > 0) { \ (void) cshake ## BITS ## _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) cshake ## BITS ## _xof_absorb(xof, PAD, len); \ } \ } \ \ /* one-shot kmac-xof */ \ void kmac ## BITS ## _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; \ kmac ## BITS ## _xof_init(&xof, params); \ kmac ## BITS ## _xof_absorb(&xof, src, src_len); \ kmac ## BITS ## _xof_squeeze(&xof, dst, dst_len); \ } // declare kmac functions DEF_KMAC(128) // kmac128 DEF_KMAC(256) // kmac256 // define tuplehash and tuplehash-xof functions #define DEF_TUPLEHASH(BITS) \ /* init tuplehash context */ \ static inline void tuplehash ## BITS ## _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 cshake ## BITS ## params */ \ const cshake_params_t cshake_params = { \ .name = NAME, \ .name_len = sizeof(NAME), \ .custom = params.custom, \ .custom_len = params.custom_len, \ }; \ \ /* init xof */ \ cshake ## BITS ## _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) cshake ## BITS ## _xof_absorb(xof, buf, buf_len); \ \ /* absorb content */ \ if (params.strs[i].len > 0) { \ (void) cshake ## BITS ## _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) cshake ## BITS ## _xof_absorb(xof, suffix_buf, suffix_buf_len); \ } \ \ /* one-shot tuplehash with fixed-length output (non-xof) */ \ void tuplehash ## BITS (const tuplehash_params_t params, uint8_t * const dst, const size_t dst_len) { \ /* init */ \ sha3_xof_t xof; \ tuplehash ## BITS ## _init(&xof, params, dst_len); \ \ /* squeeze */ \ cshake ## BITS ## _xof_squeeze(&xof, dst, dst_len); \ } \ \ /* init tuplehash context */ \ void tuplehash ## BITS ## _xof_init(sha3_xof_t * const xof, const tuplehash_params_t params) { \ tuplehash ## BITS ## _init(xof, params, 0); \ } \ \ /* squeeze data from tuplehash */ \ void tuplehash ## BITS ## _xof_squeeze(sha3_xof_t * const xof, uint8_t * const dst, const size_t dst_len) { \ cshake ## BITS ## _xof_squeeze(xof, dst, dst_len); \ } \ \ /* one-shot tuplehash-xof */ \ void tuplehash ## BITS ## _xof_once(const tuplehash_params_t params, uint8_t * const dst, const size_t dst_len) { \ /* init xof */ \ sha3_xof_t xof; \ tuplehash ## BITS ## _xof_init(&xof, params); \ \ /* squeeze */ \ cshake ## BITS ## _xof_squeeze(&xof, dst, dst_len); \ } // declare tuplehash functions DEF_TUPLEHASH(128) // tuplehash128, tuplehash128-xof DEF_TUPLEHASH(256) // tuplehash256, tuplehash256-xof // define parallelhash and parallelhash-xof functions #define DEF_PARALLELHASH(BITS) \ /* emit block for current xof into root xof */ \ static inline void parallelhash ## BITS ## _emit_block(parallelhash_t * const hash) { \ /* squeeze curr xof, absorb into root xof */ \ uint8_t buf[BITS / 4]; /* ph128: 32, ph256: 64 */ \ shake ## BITS ## _squeeze(&(hash->curr_xof), buf, sizeof(buf)); \ (void) cshake ## BITS ## _xof_absorb(&(hash->root_xof), buf, sizeof(buf)); \ \ /* increment block count */ \ hash->num_blocks++; \ } \ \ /* reset context for current internal xof */ \ static inline void parallelhash ## BITS ## _reset_curr_xof(parallelhash_t *hash) { \ /* init curr xof */ \ shake ## BITS ## _init(&(hash->curr_xof)); \ hash->ofs = 0; \ } \ \ /* init parallelhash context */ \ static inline void parallelhash ## BITS ## _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 cshake 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 */ \ cshake ## BITS ## _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) cshake ## BITS ## _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 */ \ parallelhash ## BITS ## _reset_curr_xof(hash); \ } \ \ /* absorb data into parallelhash context */ \ static inline void parallelhash ## BITS ## _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) shake ## BITS ## _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 */ \ parallelhash ## BITS ## _emit_block(hash); \ parallelhash ## BITS ## _reset_curr_xof(hash); \ } \ } \ } \ \ /* squeeze data from parallelhash context */ \ static inline void parallelhash ## BITS ## _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 */ \ parallelhash ## BITS ## _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) cshake ## BITS ## _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) cshake ## BITS ## _xof_absorb(&(hash->root_xof), buf, len); \ } \ } \ \ if (dst_len > 0) { \ cshake ## BITS ## _xof_squeeze(&(hash->root_xof), dst, dst_len); \ } \ } \ \ /* one-shot fixed-length parallelhash (non-xof) */ \ void parallelhash ## BITS (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; \ parallelhash ## BITS ## _init(&hash, params); \ \ /* absorb */ \ parallelhash ## BITS ## _absorb(&hash, src, src_len); \ \ /* squeeze */ \ parallelhash ## BITS ## _squeeze(&hash, dst, dst_len); \ } \ \ /* init parallelhash-xof context */ \ void parallelhash ## BITS ## _xof_init(parallelhash_t *hash, const parallelhash_params_t params) { \ parallelhash ## BITS ## _init(hash, params); \ } \ \ /* absorb data into parallelhash-xof context */ \ void parallelhash ## BITS ## _xof_absorb(parallelhash_t *hash, const uint8_t *msg, const size_t msg_len) { \ parallelhash ## BITS ## _absorb(hash, msg, msg_len); \ } \ \ /* squeeze data from parallelhash-xof context */ \ void parallelhash ## BITS ## _xof_squeeze(parallelhash_t *hash, uint8_t *dst, const size_t dst_len) { \ if (!hash->squeezing) { \ /* emit zero length */ \ parallelhash ## BITS ## _squeeze(hash, dst, 0); \ } \ \ parallelhash ## BITS ## _squeeze(hash, dst, dst_len); \ } \ \ /* one-shot parallelhash-xof */ \ void parallelhash ## BITS ## _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; \ parallelhash ## BITS ## _xof_init(&hash, params); \ \ /* absorb */ \ parallelhash ## BITS ## _xof_absorb(&hash, src, src_len); \ \ /* squeeze */ \ parallelhash ## BITS ## _xof_squeeze(&hash, dst, dst_len); \ } // declare parallelhash functions DEF_PARALLELHASH(128) // parallelhash128, parallehash128-xof DEF_PARALLELHASH(256) // parallelhash256, parallehash256-xof // 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 xof12_init(&(ts->xof)); ts->pad = pad; // return success return true; } // define turboshake functions #define DEF_TURBOSHAKE(BITS) \ /* init turboshake context with custom pad byte. returns false if the */ \ /* pad byte is out of range. */ \ _Bool turboshake ## BITS ## _init_custom(turboshake_t * const ts, const uint8_t pad) { \ return turboshake_init(ts, pad); \ } \ \ /* init turboshake context */ \ void turboshake ## BITS ## _init(turboshake_t * const ts) { \ (void) turboshake_init(ts, TURBOSHAKE_PAD); \ } \ \ /* absorb bytes into turboshake context. */ \ _Bool turboshake ## BITS ## _absorb(turboshake_t * const ts, const uint8_t * const m, const size_t len) { \ return xof12_absorb(&(ts->xof), SHAKE ## BITS ## _RATE, m, len); \ } \ \ /* squeeze bytes from turboshake context */ \ void turboshake ## BITS ## _squeeze(turboshake_t * const ts, uint8_t * const dst, const size_t dst_len) { \ xof12_squeeze(&(ts->xof), SHAKE ## BITS ## _RATE, ts->pad, dst, dst_len); \ } \ \ /* one-shot turboshake with default pad byte */ \ void turboshake ## BITS (const uint8_t * const src, const size_t src_len, uint8_t * const dst, const size_t dst_len) { \ xof12_once(SHAKE ## BITS ## _RATE, TURBOSHAKE_PAD, src, src_len, dst, dst_len); \ } \ \ /* one-shot turboshake with custom pad byte */ \ void turboshake ## BITS ## _custom(const uint8_t pad, const uint8_t * const src, const size_t src_len, uint8_t * const dst, const size_t dst_len) { \ xof12_once(SHAKE ## BITS ## _RATE, pad, src, src_len, dst, dst_len); \ } // declare turboshake functions DEF_TURBOSHAKE(128) // turboshake128 DEF_TURBOSHAKE(256) // turboshake128 // 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); } // Return backend name. const char *sha3_backend(void) { #if BACKEND == BACKEND_AVX512 return "avx512"; #elif BACKEND == BACKEND_AVX2 return "avx2"; #elif BACKEND == BACKEND_NEON return "neon"; #elif BACKEND == BACKEND_DIET_NEON return "diet-neon"; #elif BACKEND == BACKEND_HYBRID return "hybrid"; #elif BACKEND == BACKEND_SCALAR return "scalar"; #endif /* BACKEND */ } #ifdef TEST_SHA3 #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 fail_test(const char * const func, const char * const name, const uint8_t * const got, const size_t got_len, const uint8_t * const exp, const size_t exp_len) { fprintf(stderr, "%s(\"%s\") failed, got:\n", func, name); dump_hex(stderr, got, got_len); fprintf(stderr, "exp:\n"); dump_hex(stderr, exp, exp_len); } 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, "%s() failed, got:\n", __func__); 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, "%s() failed, got:\n", __func__); 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, "%s() failed, got:\n", __func__); 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, "%s() failed, got:\n", __func__); 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, "%s() failed, got:\n", __func__); dump_state(stderr, (uint64_t*) a); fprintf(stderr, "exp:\n"); dump_state(stderr, (uint64_t*) exp); } } static const struct { uint64_t a[25]; // input state const uint64_t exp[25]; // expected value const size_t exp_len; // length of exp, in bytes } PERMUTE_24_TESTS[] = {{ .a = { [0] = 0x00000001997b5853ULL, [16] = 0x8000000000000000ULL }, .exp = { 0xE95A9E40EF2F24C8ULL, 0x24C64DAE57C8F1D1ULL, 0x8CAA629F80192BB9ULL, 0xD0B178A0541C4107ULL }, .exp_len = 32, }}; static void test_permute_24_scalar(void) { for (size_t i = 0; i < sizeof(PERMUTE_24_TESTS) / sizeof(PERMUTE_24_TESTS[0]); i++) { const size_t exp_len = PERMUTE_24_TESTS[i].exp_len; uint64_t got[25] = { 0 }; memcpy(got, PERMUTE_24_TESTS[i].a, sizeof(got)); permute_n_scalar(got, 24); // call permute_n() directly if (memcmp(got, PERMUTE_24_TESTS[i].exp, exp_len)) { fail_test(__func__, "", (uint8_t*) got, exp_len, (uint8_t*) PERMUTE_24_TESTS[i].exp, exp_len); } } } static void test_permute_24_avx512(void) { #if BACKEND == BACKEND_AVX512 for (size_t i = 0; i < sizeof(PERMUTE_24_TESTS) / sizeof(PERMUTE_24_TESTS[0]); i++) { const size_t exp_len = PERMUTE_24_TESTS[i].exp_len; uint64_t got[25] = { 0 }; memcpy(got, PERMUTE_24_TESTS[i].a, sizeof(got)); permute_n_avx512(got, 24); // call permute_n() directly if (memcmp(got, PERMUTE_24_TESTS[i].exp, exp_len)) { fail_test(__func__, "", (uint8_t*) got, exp_len, (uint8_t*) PERMUTE_24_TESTS[i].exp, exp_len); } } #endif /* BACKEND == BACKEND_AVX512 */ } static void test_permute_24_neon(void) { #if BACKEND == BACKEND_NEON for (size_t i = 0; i < sizeof(PERMUTE_24_TESTS) / sizeof(PERMUTE_24_TESTS[0]); i++) { const size_t exp_len = PERMUTE_24_TESTS[i].exp_len; uint64_t got[25] = { 0 }; memcpy(got, PERMUTE_24_TESTS[i].a, sizeof(got)); permute_n_neon(got, 24); // call permute_n() directly if (memcmp(got, PERMUTE_24_TESTS[i].exp, exp_len)) { fail_test(__func__, "", (uint8_t*) got, exp_len, (uint8_t*) PERMUTE_24_TESTS[i].exp, exp_len); } } #endif /* BACKEND == BACKEND_NEON */ } static void test_permute_24_diet_neon(void) { #if BACKEND == BACKEND_DIET_NEON for (size_t i = 0; i < sizeof(PERMUTE_24_TESTS) / sizeof(PERMUTE_24_TESTS[0]); i++) { const size_t exp_len = PERMUTE_24_TESTS[i].exp_len; uint64_t got[25] = { 0 }; memcpy(got, PERMUTE_24_TESTS[i].a, sizeof(got)); permute_n_diet_neon(got, 24); // call permute_n() directly if (memcmp(got, PERMUTE_24_TESTS[i].exp, exp_len)) { fail_test(__func__, "", (uint8_t*) got, exp_len, (uint8_t*) PERMUTE_24_TESTS[i].exp, exp_len); } } #endif /* BACKEND == BACKEND_DIET_NEON */ } static void test_permute_24_hybrid(void) { #if BACKEND == BACKEND_HYBRID for (size_t i = 0; i < sizeof(PERMUTE_24_TESTS) / sizeof(PERMUTE_24_TESTS[0]); i++) { const size_t exp_len = PERMUTE_24_TESTS[i].exp_len; uint64_t got[25] = { 0 }; memcpy(got, PERMUTE_24_TESTS[i].a, sizeof(got)); permute_n_hybrid(got, 24); // call permute_n() directly if (memcmp(got, PERMUTE_24_TESTS[i].exp, exp_len)) { fail_test(__func__, "", (uint8_t*) got, exp_len, (uint8_t*) PERMUTE_24_TESTS[i].exp, exp_len); } } #endif /* BACKEND == BACKEND_HYBRID */ } static const struct { uint64_t a[25]; // input state const uint64_t exp[25]; // expected value const size_t exp_len; // length of exp, in bytes } PERMUTE_12_TESTS[] = {{ .a = { [0] = 0x00000001997b5853ULL, [16] = 0x8000000000000000ULL }, .exp = { 0X8B346BAFF5DA94C6ULL, 0XD7D37EC35E3B2EECULL, 0XBBF724EABFD84018ULL, 0X5E3C1AFA4EA7B3A1ULL }, .exp_len = 32, }}; static void test_permute_12_scalar(void) { for (size_t i = 0; i < sizeof(PERMUTE_12_TESTS) / sizeof(PERMUTE_12_TESTS[0]); i++) { const size_t exp_len = PERMUTE_12_TESTS[i].exp_len; uint64_t got[25] = { 0 }; memcpy(got, PERMUTE_12_TESTS[i].a, sizeof(got)); permute_n_scalar(got, 12); // call permute_n() directly if (memcmp(got, PERMUTE_12_TESTS[i].exp, exp_len)) { fail_test(__func__, "", (uint8_t*) got, exp_len, (uint8_t*) PERMUTE_12_TESTS[i].exp, exp_len); } } } static void test_permute_12_avx512(void) { #if BACKEND == BACKEND_AVX512 for (size_t i = 0; i < sizeof(PERMUTE_12_TESTS) / sizeof(PERMUTE_12_TESTS[0]); i++) { const size_t exp_len = PERMUTE_12_TESTS[i].exp_len; uint64_t got[25] = { 0 }; memcpy(got, PERMUTE_12_TESTS[i].a, sizeof(got)); permute_n_avx512(got, 12); // call permute_n() directly if (memcmp(got, PERMUTE_12_TESTS[i].exp, exp_len)) { fail_test(__func__, "", (uint8_t*) got, exp_len, (uint8_t*) PERMUTE_12_TESTS[i].exp, exp_len); } } #endif /* BACKEND == BACKEND_AVX512 */ } static void test_permute_12_neon(void) { #if BACKEND == BACKEND_NEON for (size_t i = 0; i < sizeof(PERMUTE_12_TESTS) / sizeof(PERMUTE_12_TESTS[0]); i++) { const size_t exp_len = PERMUTE_12_TESTS[i].exp_len; uint64_t got[25] = { 0 }; memcpy(got, PERMUTE_12_TESTS[i].a, sizeof(got)); permute_n_neon(got, 12); // call permute_n() directly if (memcmp(got, PERMUTE_12_TESTS[i].exp, exp_len)) { fail_test(__func__, "", (uint8_t*) got, exp_len, (uint8_t*) PERMUTE_12_TESTS[i].exp, exp_len); } } #endif /* BACKEND == BACKEND_NEON */ } static void test_permute_12_diet_neon(void) { #if BACKEND == BACKEND_DIET_NEON for (size_t i = 0; i < sizeof(PERMUTE_12_TESTS) / sizeof(PERMUTE_12_TESTS[0]); i++) { const size_t exp_len = PERMUTE_12_TESTS[i].exp_len; uint64_t got[25] = { 0 }; memcpy(got, PERMUTE_12_TESTS[i].a, sizeof(got)); permute_n_diet_neon(got, 12); // call permute_n() directly if (memcmp(got, PERMUTE_12_TESTS[i].exp, exp_len)) { fail_test(__func__, "", (uint8_t*) got, exp_len, (uint8_t*) PERMUTE_12_TESTS[i].exp, exp_len); } } #endif /* BACKEND == BACKEND_DIET_NEON */ } static void test_permute_12_hybrid(void) { #if BACKEND == BACKEND_HYBRID for (size_t i = 0; i < sizeof(PERMUTE_12_TESTS) / sizeof(PERMUTE_12_TESTS[0]); i++) { const size_t exp_len = PERMUTE_12_TESTS[i].exp_len; uint64_t got[25] = { 0 }; memcpy(got, PERMUTE_12_TESTS[i].a, sizeof(got)); permute_n_hybrid(got, 12); // call permute_n() directly if (memcmp(got, PERMUTE_12_TESTS[i].exp, exp_len)) { fail_test(__func__, "", (uint8_t*) got, exp_len, (uint8_t*) PERMUTE_12_TESTS[i].exp, exp_len); } } #endif /* BACKEND == BACKEND_HYBRID */ } 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))) { fail_test(__func__, tests[i].name, got, 28, 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))) { fail_test(__func__, tests[i].name, got, 32, 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))) { fail_test(__func__, tests[i].name, got, 48, 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))) { fail_test(__func__, tests[i].name, got, 64, 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))) { fail_test(__func__, tests[i].name, got, 28, 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))) { fail_test(__func__, tests[i].name, got, 32, 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))) { fail_test(__func__, tests[i].name, got, 48, 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))) { fail_test(__func__, tests[i].name, got, 64, 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))) { // build test name char name[64]; snprintf(name, sizeof(name), "%s (%zu)", tests[i].name, len); // fail test fail_test(__func__, name, got, 16, 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))) { // build test name char name[64]; snprintf(name, sizeof(name), "%s (%zu)", tests[i].name, len); // fail test fail_test(__func__, name, got, 16, 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))) { // build test name char name[64]; snprintf(name, sizeof(name), "%s (%zu)", tests[i].name, len); // fail test fail_test(__func__, name, got, 16, 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))) { // build test name char name[64]; snprintf(name, sizeof(name), "%s (%zu)", tests[i].name, len); // fail test fail_test(__func__, name, got, 16, 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, "%s(\"%s\") length check failed: got %zu, exp %zu:\n", __func__, tests[i].name, got_len, tests[i].exp_len); } else if (memcmp(got, tests[i].exp, got_len)) { fail_test(__func__, tests[i].name, got, got_len, 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, "%s(\"%s\") length check failed: got %zu, exp %zu:\n", __func__, tests[i].name, got_len, tests[i].exp_len); } else if (memcmp(got, tests[i].exp, got_len)) { fail_test(__func__, tests[i].name, got, got_len, 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, "%s(\"%s\") length check failed: got %zu, exp %zu:\n", __func__, tests[i].name, got_len, tests[i].exp_len); } else if (memcmp(got, tests[i].exp, got_len)) { fail_test(__func__, tests[i].name, got, got_len, 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, "%s(\"%s\") length check failed:\n got: { %zu, %zu }\n exp: { %zu, %zu }\n", __func__, 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)) { fail_test(__func__, tests[i].name, got.prefix, got.prefix_len, 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))) { fail_test(__func__, tests[i].test_name, got, 32, 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))) { fail_test(__func__, tests[i].test_name, got, 32, 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))) { fail_test(__func__, tests[i].name, got, 32, 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))) { fail_test(__func__, tests[i].name, got, 32, 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))) { fail_test(__func__, tests[i].name, got, 32, 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))) { fail_test(__func__, tests[i].name, got, 32, 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))) { fail_test(__func__, tests[i].name, got, 32, 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))) { fail_test(__func__, tests[i].name, got, 32, 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))) { fail_test(__func__, tests[i].name, got, 32, 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))) { fail_test(__func__, tests[i].name, got, 32, 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))) { fail_test(__func__, tests[i].name, got, 32, 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))) { fail_test(__func__, tests[i].name, got, 32, 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))) { fail_test(__func__, tests[i].name, got, sizeof(got), 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))) { fail_test(__func__, tests[i].name, got, sizeof(got), 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))) { fail_test(__func__, tests[i].name, got, sizeof(got), 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_24_scalar(); test_permute_24_avx512(); test_permute_24_neon(); test_permute_24_diet_neon(); test_permute_24_hybrid(); test_permute_12_scalar(); test_permute_12_avx512(); test_permute_12_neon(); test_permute_12_diet_neon(); test_permute_12_hybrid(); 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 (%s)\n", sha3_backend()); } #endif /* TEST_SHA3 */ /** @endcond INTERNAL */