manbytesgnu_site

Source files for manbytesgnu.org
git clone git://holbrook.no/manbytesgnu_site.git
Log | Files | Refs

commit d103667080444dc3ca78ca16bdb833ee282a91a5
parent 4484e885e5912669a688ff2492582e2793ceb690
Author: nolash <dev@holbrook.no>
Date:   Sun, 18 Apr 2021 20:38:05 +0200

Add code files

Diffstat:
A.gitignore | 3+++
Mcontent/20210418_keccak.rst | 161++++++++++++++++++++++++++++++++++++++-----------------------------------------
Acontent/code/keccak-benchmarks/XKCP/bench.c | 51+++++++++++++++++++++++++++++++++++++++++++++++++++
Acontent/code/keccak-benchmarks/XKCP/main.c | 9+++++++++
Acontent/code/keccak-benchmarks/XKCP/small.c | 8++++++++
Acontent/code/keccak-benchmarks/keccak-tiny/bench.c | 48++++++++++++++++++++++++++++++++++++++++++++++++
Acontent/code/keccak-benchmarks/keccak-tiny/keccak-tiny.c | 163+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Acontent/code/keccak-benchmarks/keccak-tiny/keccak-tiny.h | 23+++++++++++++++++++++++
Acontent/code/keccak-benchmarks/libkeccak/bench.c | 62++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Acontent/code/keccak-benchmarks/tiny_sha3/bench.c | 46++++++++++++++++++++++++++++++++++++++++++++++
Acontent/code/keccak-benchmarks/tiny_sha3/sha3.c | 191+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
11 files changed, 682 insertions(+), 83 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -0,0 +1,3 @@ +*.o +*.pyc +__pycache__ diff --git a/content/20210418_keccak.rst b/content/20210418_keccak.rst @@ -2,11 +2,14 @@ In search of a slim KECCAK dependency ##################################### :date: 2021-04-18 15:01 -:modified: 2021-04-18 15:29 +:modified: 2021-04-18 19:48 :category: Code :author: Louis Holbrook :tags: crypto,hash,keccak,python,c - +:slug: keccak-benchmarks +:summary: Compare performance and sizes of alternative KECCAK SHA3 implementations +:lang: en +:status: draft Implementations =============== @@ -17,63 +20,15 @@ XKCP - Location: https://github.com/xkcp/xkcp - Git hash: c438ee7b2736726f629da11b7012cffcf6b84fef -XKCP:: - - #include <string.h> - #include <stdio.h> - #include <stdlib.h> - #include <time.h> - - #include <XKCP/KeccakHash.h> - #include <XKCP/KangarooTwelve.h> - #include <XKCP/SP800-185.h> - - #ifndef ROUNDS - #define ROUNDS 100000 - #endif - - void main() { - int rounds; - long delta_sec; - long delta_nsec; - struct timespec start; - struct timespec end; - - Keccak_HashInstance instance; - - int i; - char data[3] = {'f', 'o', 'o'}; - - unsigned char buf[256]; - memset(buf, 0, 256); - - for (i = 0; i < 10000; i++) { - Keccak_HashInitialize(&instance, 1088, 512, 256, 0x01); - Keccak_HashUpdate(&instance, data, 24); - Keccak_HashFinal(&instance, buf); - } - - clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &start); - for (i = 0; i < ROUNDS; i++) { - Keccak_HashInitialize(&instance, 1088, 512, 256, 0x01); - Keccak_HashUpdate(&instance, data, 24); - Keccak_HashFinal(&instance, buf); - } - clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &end); - - delta_sec = end.tv_sec - start.tv_sec; - delta_nsec = end.tv_nsec - start.tv_nsec; - if (delta_nsec < 0) { - delta_sec++; - delta_nsec += 1000000000L; - } - printf("%u.%09u\n", delta_sec, delta_nsec); - - for (i = 0; i < 32; i++) { - printf("%02x", buf[i]); - } - printf("\n"); - } + +.. include:: code/keccak-benchmarks/XKCP/small.c + :code: c + :number-lines: 0 + +.. include:: code/keccak-benchmarks/XKCP/bench.c + :code: c + :number-lines: 0 + keccak_tiny ----------- @@ -90,15 +45,15 @@ tiny_sha3 - Location: https://github.com/mjosaarinen/tiny_sha3 - Git hash: dcbb3192047c2a721f5f851db591871d428036a9 -Had to change "padding" value. +Had to change "padding" value in ``sha3.c`` -sha3.c:142:: +.. code-block:: c + :linenos: table + :linenostart: 142 - < c->st.b[c->pt] ^= 0x01; - --- - > c->st.b[c->pt] ^= 0x06; + c->st.b[c->pt] ^= 0x01; -bench.c:: +.. code-block:: c sha3(data, 3, buf, 32); @@ -108,7 +63,7 @@ libkeccak - Location: https://github.com/maandree/libkeccak - Git hash: 718b1a6ea1c44bcf15e55d3c265310e1cd9211fa -bench.c:: +.. code-block:: bench.c libkeccak_state_initialise(&state, &spec); libkeccak_fast_update(&state, msg, 3); @@ -121,24 +76,64 @@ Results - Input: "foo" - Rounds: 100000 -:XKCP generic64: - - Time: 0.041101298 - - Executable size: 37768 - - Archive size: 358558 +.. + :XKCP generic64: + - Time: 0.041101298 + - Executable size: 37768 + - Archive size: 358558 +.. + :keccak-tiny: + - Time: 0.046095483 + - Executable size: 49400 + - Object size: 35544 +.. + :tiny_sha3 [1]_: + - Time: 0.080156921 + - Executable size: 16577 + - Object size: 6712 +.. + :libkeccak: + - Time: 0.200222898 + - Executable size: 50152 + - Archive size: 78680 + +============== ============== =============== +Implementation Execution time Executable size +============== ============== =============== +XKCP 0.041101298 37768 +keccak-tiny 0.046095483 49400 +tiny_sha3 [1]_ 0.080156921 16577 +libkeccak 0.200222898 50152 +============== ============== =============== -:keccak-tiny: - - Time: 0.046095483 - - Executable size: 49400 - - Object size: 35544 + .. [1] Author claims it is not suited for production -:tiny_sha3 [1]_: - - Time: 0.080156921 - - Executable size: 16577 - - Object size: 6712 -:libkeccak: - - Time: 0.200222898 - - Executable size: 50152 - - Archive size: 78680 +Python +====== + +XKCP has a pure-python implementation, but it's hopelessly slow. + +Added to ``CompactFIPS202.py``: + +.. code-block:: python + + if __name__ == '__main__': + for i in range(10): + a = Keccak(1088, 512, b'foo', 0x01, 32) + + for j in range(1,4): + a = 10**j + start_time = time.clock_gettime_ns(time.CLOCK_PROCESS_CPUTIME_ID) + for i in range(a): + b = Keccak(1088, 512, b'foo', 0x01, 32) + end_time = time.clock_gettime_ns(time.CLOCK_PROCESS_CPUTIME_ID) + print(a, (end_time - start_time) / (10**9)) + +:: + + $ python CompactFIPS202.py + 10 0.007536721 + 100 0.066636149 + 1000 0.64519725 - .. [1] Author claims it is not suited for production diff --git a/content/code/keccak-benchmarks/XKCP/bench.c b/content/code/keccak-benchmarks/XKCP/bench.c @@ -0,0 +1,51 @@ +#include <string.h> +#include <stdio.h> +#include <stdlib.h> +#include <time.h> + +#include <XKCP/KeccakHash.h> + +#ifndef ROUNDS +#define ROUNDS 100000 +#endif + +extern int wrap_keccak(const char *data, char *zout); + +void main() { + int rounds; + long delta_sec; + long delta_nsec; + struct timespec start; + struct timespec end; + + Keccak_HashInstance instance; + + int i; + char data[3] = {'f', 'o', 'o'}; + + unsigned char buf[256]; + memset(buf, 0, 256); + + for (i = 0; i < 10000; i++) { + wrap_keccak(data, buf); + } + + clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &start); + for (i = 0; i < ROUNDS; i++) { + wrap_keccak(data, buf); + } + clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &end); + + delta_sec = end.tv_sec - start.tv_sec; + delta_nsec = end.tv_nsec - start.tv_nsec; + if (delta_nsec < 0) { + delta_sec++; + delta_nsec += 1000000000L; + } + printf("%u.%09u\n", delta_sec, delta_nsec); + + for (i = 0; i < 32; i++) { + printf("%02x", buf[i]); + } + printf("\n"); +} diff --git a/content/code/keccak-benchmarks/XKCP/main.c b/content/code/keccak-benchmarks/XKCP/main.c @@ -0,0 +1,9 @@ +#include <XKCP/KeccakHash.h> + +extern int wrap_keccak(const char *data, size_t bitlen, char *zout); + +int main(int argc, char **argv) { + unsigned char buf[256]; + wrap_keccak(*(argv+1), strlen(*(argv+1)), buf); + return 0; +} diff --git a/content/code/keccak-benchmarks/XKCP/small.c b/content/code/keccak-benchmarks/XKCP/small.c @@ -0,0 +1,8 @@ +#include <XKCP/KeccakHash.h> + +int wrap_keccak(const char *data, size_t bitlen, char *zout) { + Keccak_HashInstance instance; + Keccak_HashInitialize(&instance, 1088, 512, 256, 0x01); + Keccak_HashUpdate(&instance, data, (int)bitlen); + Keccak_HashFinal(&instance, zout); +} diff --git a/content/code/keccak-benchmarks/keccak-tiny/bench.c b/content/code/keccak-benchmarks/keccak-tiny/bench.c @@ -0,0 +1,48 @@ +#include <string.h> +#include <stdio.h> +#include <stdlib.h> +#include <time.h> +#include "keccak-tiny.h" + +#ifndef ROUNDS +#define ROUNDS 100000 +#endif + +void main() { + int rounds; + long delta_sec; + long delta_nsec; + struct timespec start; + struct timespec end; + + int i; + //unsigned char *buf; + char data[3] = {'f', 'o', 'o'}; + + //buf = malloc(256); + unsigned char buf[256]; + memset(buf, 0, 256); + + for (i = 0; i < 10000; i++) { + hash(buf, 32, data, 3, 200-64, 0x01); + } + + clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &start); + for (i = 0; i < ROUNDS; i++) { + hash(buf, 32, data, 3, 200-64, 0x01); + } + clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &end); + + delta_sec = end.tv_sec - start.tv_sec; + delta_nsec = end.tv_nsec - start.tv_nsec; + if (delta_nsec < 0) { + delta_sec++; + delta_nsec += 1000000000L; + } + printf("%u.%09u\n", delta_sec, delta_nsec); + + for (i = 0; i < 32; i++) { + printf("%02x", buf[i]); + } + printf("\n"); +} diff --git a/content/code/keccak-benchmarks/keccak-tiny/keccak-tiny.c b/content/code/keccak-benchmarks/keccak-tiny/keccak-tiny.c @@ -0,0 +1,163 @@ +/** libkeccak-tiny + * + * A single-file implementation of SHA-3 and SHAKE. + * + * Implementor: David Leon Gil + * License: CC0, attribution kindly requested. Blame taken too, + * but not liability. + */ +#include "keccak-tiny.h" + +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +/******** The Keccak-f[1600] permutation ********/ + +/*** Constants. ***/ +static const uint8_t rho[24] = \ + { 1, 3, 6, 10, 15, 21, + 28, 36, 45, 55, 2, 14, + 27, 41, 56, 8, 25, 43, + 62, 18, 39, 61, 20, 44}; +static const uint8_t pi[24] = \ + {10, 7, 11, 17, 18, 3, + 5, 16, 8, 21, 24, 4, + 15, 23, 19, 13, 12, 2, + 20, 14, 22, 9, 6, 1}; +static const uint64_t RC[24] = \ + {1ULL, 0x8082ULL, 0x800000000000808aULL, 0x8000000080008000ULL, + 0x808bULL, 0x80000001ULL, 0x8000000080008081ULL, 0x8000000000008009ULL, + 0x8aULL, 0x88ULL, 0x80008009ULL, 0x8000000aULL, + 0x8000808bULL, 0x800000000000008bULL, 0x8000000000008089ULL, 0x8000000000008003ULL, + 0x8000000000008002ULL, 0x8000000000000080ULL, 0x800aULL, 0x800000008000000aULL, + 0x8000000080008081ULL, 0x8000000000008080ULL, 0x80000001ULL, 0x8000000080008008ULL}; + +/*** Helper macros to unroll the permutation. ***/ +#define rol(x, s) (((x) << s) | ((x) >> (64 - s))) +#define REPEAT6(e) e e e e e e +#define REPEAT24(e) REPEAT6(e e e e) +#define REPEAT5(e) e e e e e +#define FOR5(v, s, e) \ + v = 0; \ + REPEAT5(e; v += s;) + +/*** Keccak-f[1600] ***/ +static inline void keccakf(void* state) { + uint64_t* a = (uint64_t*)state; + uint64_t b[5] = {0}; + uint64_t t = 0; + uint8_t x, y; + + for (int i = 0; i < 24; i++) { + // Theta + FOR5(x, 1, + b[x] = 0; + FOR5(y, 5, + b[x] ^= a[x + y]; )) + FOR5(x, 1, + FOR5(y, 5, + a[y + x] ^= b[(x + 4) % 5] ^ rol(b[(x + 1) % 5], 1); )) + // Rho and pi + t = a[1]; + x = 0; + REPEAT24(b[0] = a[pi[x]]; + a[pi[x]] = rol(t, rho[x]); + t = b[0]; + x++; ) + // Chi + FOR5(y, + 5, + FOR5(x, 1, + b[x] = a[y + x];) + FOR5(x, 1, + a[y + x] = b[x] ^ ((~b[(x + 1) % 5]) & b[(x + 2) % 5]); )) + // Iota + a[0] ^= RC[i]; + } +} + +/******** The FIPS202-defined functions. ********/ + +/*** Some helper macros. ***/ + +#define _(S) do { S } while (0) +#define FOR(i, ST, L, S) \ + _(for (size_t i = 0; i < L; i += ST) { S; }) +#define mkapply_ds(NAME, S) \ + static inline void NAME(uint8_t* dst, \ + const uint8_t* src, \ + size_t len) { \ + FOR(i, 1, len, S); \ + } +#define mkapply_sd(NAME, S) \ + static inline void NAME(const uint8_t* src, \ + uint8_t* dst, \ + size_t len) { \ + FOR(i, 1, len, S); \ + } + +mkapply_ds(xorin, dst[i] ^= src[i]) // xorin +mkapply_sd(setout, dst[i] = src[i]) // setout + +#define P keccakf +#define Plen 200 + +// Fold P*F over the full blocks of an input. +#define foldP(I, L, F) \ + while (L >= rate) { \ + F(a, I, rate); \ + P(a); \ + I += rate; \ + L -= rate; \ + } + +/** The sponge-based hash construction. **/ +int hash(uint8_t* out, size_t outlen, + const uint8_t* in, size_t inlen, + size_t rate, uint8_t delim) { + if ((out == NULL) || ((in == NULL) && inlen != 0) || (rate >= Plen)) { + return -1; + } + uint8_t a[Plen] = {0}; + // Absorb input. + foldP(in, inlen, xorin); + // Xor in the DS and pad frame. + a[inlen] ^= delim; + a[rate - 1] ^= 0x80; + // Xor in the last block. + xorin(a, in, inlen); + // Apply P + P(a); + // Squeeze output. + foldP(out, outlen, setout); + setout(a, out, outlen); + memset_s(a, 200, 0, 200); + return 0; +} + +/*** Helper macros to define SHA3 and SHAKE instances. ***/ +#define defshake(bits) \ + int shake##bits(uint8_t* out, size_t outlen, \ + const uint8_t* in, size_t inlen) { \ + return hash(out, outlen, in, inlen, 200 - (bits / 4), 0x1f); \ + } +#define defsha3(bits) \ + int sha3_##bits(uint8_t* out, size_t outlen, \ + const uint8_t* in, size_t inlen) { \ + if (outlen > (bits/8)) { \ + return -1; \ + } \ + return hash(out, outlen, in, inlen, 200 - (bits / 4), 0x06); \ + } + +/*** FIPS202 SHAKE VOFs ***/ +defshake(128) +defshake(256) + +/*** FIPS202 SHA3 FOFs ***/ +defsha3(224) +defsha3(256) +defsha3(384) +defsha3(512) diff --git a/content/code/keccak-benchmarks/keccak-tiny/keccak-tiny.h b/content/code/keccak-benchmarks/keccak-tiny/keccak-tiny.h @@ -0,0 +1,23 @@ +#ifndef KECCAK_FIPS202_H +#define KECCAK_FIPS202_H +#define __STDC_WANT_LIB_EXT1__ 1 +#include <stdint.h> +#include <stdlib.h> + +#define decshake(bits) \ + int shake##bits(uint8_t*, size_t, const uint8_t*, size_t); + +#define decsha3(bits) \ + int sha3_##bits(uint8_t*, size_t, const uint8_t*, size_t); + +decshake(128) +decshake(256) +decsha3(224) +decsha3(256) +decsha3(384) +decsha3(512) + +int hash(uint8_t* out, size_t outlen, + const uint8_t* in, size_t inlen, + size_t rate, uint8_t delim); +#endif diff --git a/content/code/keccak-benchmarks/libkeccak/bench.c b/content/code/keccak-benchmarks/libkeccak/bench.c @@ -0,0 +1,62 @@ +#include <stdio.h> +#include <time.h> +#include "libkeccak.h" + +#define BITRATE 1088 +#define CAPACITY 512 +#define OUTPUT 256 + +#ifndef ROUNDS +#define ROUNDS 100000 +#endif + +void main() { + struct timespec start; + struct timespec end; + + struct libkeccak_spec spec; + struct libkeccak_state state; + + unsigned char buf[32]; + char msg[3] = {'f', 'o', 'o'}; + int i; + int r; + + long delta_sec; + long delta_nsec; + + spec.bitrate = BITRATE; + spec.capacity = CAPACITY; + spec.output = OUTPUT; + + libkeccak_state_initialise(&state, &spec); + + for (i = 0; i < 100; i++) { + libkeccak_state_initialise(&state, &spec); + libkeccak_fast_update(&state, msg, 3); + libkeccak_fast_digest(&state, NULL, 0, 0, NULL, buf); + } + + clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &start); + for (i = 0; i < ROUNDS; i++) { + libkeccak_state_initialise(&state, &spec); + libkeccak_fast_update(&state, msg, 3); + libkeccak_fast_digest(&state, NULL, 0, 0, NULL, buf); + } + clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &end); + + delta_sec = end.tv_sec - start.tv_sec; + delta_nsec = end.tv_nsec - start.tv_nsec; + if (delta_nsec < 0) { + delta_sec++; + delta_nsec += 1000000000L; + } + printf("%u.%09u\n", delta_sec, delta_nsec); + + for (i = 0; i < 32; i++) { + printf("%02x", buf[i]); + } + + printf("\n"); + +} diff --git a/content/code/keccak-benchmarks/tiny_sha3/bench.c b/content/code/keccak-benchmarks/tiny_sha3/bench.c @@ -0,0 +1,46 @@ +#include <stdio.h> +#include "sha3.h" +#include <stdlib.h> +#include <string.h> +#include <time.h> + +#ifndef ROUNDS +#define ROUNDS 100000 +#endif + +void main() { + int rounds; + long delta_sec; + long delta_nsec; + struct timespec start; + struct timespec end; + + int i; + char data[3] = {'f', 'o', 'o'}; + + unsigned char buf[256]; + memset(buf, 0, 256); + + for (i = 0; i < 100000; i++) { + sha3(data, 3, buf, 32); + } + + clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &start); + for (i = 0; i < ROUNDS; i++) { + sha3(data, 3, buf, 32); + } + clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &end); + + delta_sec = end.tv_sec - start.tv_sec; + delta_nsec = end.tv_nsec - start.tv_nsec; + if (delta_nsec < 0) { + delta_sec++; + delta_nsec += 1000000000L; + } + printf("%u.%09u\n", delta_sec, delta_nsec); + + for (i = 0; i < 32; i++) { + printf("%02x", buf[i]); + } + printf("\n"); +} diff --git a/content/code/keccak-benchmarks/tiny_sha3/sha3.c b/content/code/keccak-benchmarks/tiny_sha3/sha3.c @@ -0,0 +1,191 @@ +// sha3.c +// 19-Nov-11 Markku-Juhani O. Saarinen <mjos@iki.fi> + +// Revised 07-Aug-15 to match with official release of FIPS PUB 202 "SHA3" +// Revised 03-Sep-15 for portability + OpenSSL - style API + +#include "sha3.h" + +// update the state with given number of rounds + +void sha3_keccakf(uint64_t st[25]) +{ + // constants + const uint64_t keccakf_rndc[24] = { + 0x0000000000000001, 0x0000000000008082, 0x800000000000808a, + 0x8000000080008000, 0x000000000000808b, 0x0000000080000001, + 0x8000000080008081, 0x8000000000008009, 0x000000000000008a, + 0x0000000000000088, 0x0000000080008009, 0x000000008000000a, + 0x000000008000808b, 0x800000000000008b, 0x8000000000008089, + 0x8000000000008003, 0x8000000000008002, 0x8000000000000080, + 0x000000000000800a, 0x800000008000000a, 0x8000000080008081, + 0x8000000000008080, 0x0000000080000001, 0x8000000080008008 + }; + const int keccakf_rotc[24] = { + 1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 2, 14, + 27, 41, 56, 8, 25, 43, 62, 18, 39, 61, 20, 44 + }; + const int keccakf_piln[24] = { + 10, 7, 11, 17, 18, 3, 5, 16, 8, 21, 24, 4, + 15, 23, 19, 13, 12, 2, 20, 14, 22, 9, 6, 1 + }; + + // variables + int i, j, r; + uint64_t t, bc[5]; + +#if __BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__ + uint8_t *v; + + // endianess conversion. this is redundant on little-endian targets + for (i = 0; i < 25; i++) { + v = (uint8_t *) &st[i]; + st[i] = ((uint64_t) v[0]) | (((uint64_t) v[1]) << 8) | + (((uint64_t) v[2]) << 16) | (((uint64_t) v[3]) << 24) | + (((uint64_t) v[4]) << 32) | (((uint64_t) v[5]) << 40) | + (((uint64_t) v[6]) << 48) | (((uint64_t) v[7]) << 56); + } +#endif + + // actual iteration + for (r = 0; r < KECCAKF_ROUNDS; r++) { + + // Theta + for (i = 0; i < 5; i++) + bc[i] = st[i] ^ st[i + 5] ^ st[i + 10] ^ st[i + 15] ^ st[i + 20]; + + for (i = 0; i < 5; i++) { + t = bc[(i + 4) % 5] ^ ROTL64(bc[(i + 1) % 5], 1); + for (j = 0; j < 25; j += 5) + st[j + i] ^= t; + } + + // Rho Pi + t = st[1]; + for (i = 0; i < 24; i++) { + j = keccakf_piln[i]; + bc[0] = st[j]; + st[j] = ROTL64(t, keccakf_rotc[i]); + t = bc[0]; + } + + // Chi + for (j = 0; j < 25; j += 5) { + for (i = 0; i < 5; i++) + bc[i] = st[j + i]; + for (i = 0; i < 5; i++) + st[j + i] ^= (~bc[(i + 1) % 5]) & bc[(i + 2) % 5]; + } + + // Iota + st[0] ^= keccakf_rndc[r]; + } + +#if __BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__ + // endianess conversion. this is redundant on little-endian targets + for (i = 0; i < 25; i++) { + v = (uint8_t *) &st[i]; + t = st[i]; + v[0] = t & 0xFF; + v[1] = (t >> 8) & 0xFF; + v[2] = (t >> 16) & 0xFF; + v[3] = (t >> 24) & 0xFF; + v[4] = (t >> 32) & 0xFF; + v[5] = (t >> 40) & 0xFF; + v[6] = (t >> 48) & 0xFF; + v[7] = (t >> 56) & 0xFF; + } +#endif +} + +// Initialize the context for SHA3 + +int sha3_init(sha3_ctx_t *c, int mdlen) +{ + int i; + + for (i = 0; i < 25; i++) + c->st.q[i] = 0; + c->mdlen = mdlen; + c->rsiz = 200 - 2 * mdlen; + c->pt = 0; + + return 1; +} + +// update state with more data + +int sha3_update(sha3_ctx_t *c, const void *data, size_t len) +{ + size_t i; + int j; + + j = c->pt; + for (i = 0; i < len; i++) { + c->st.b[j++] ^= ((const uint8_t *) data)[i]; + if (j >= c->rsiz) { + sha3_keccakf(c->st.q); + j = 0; + } + } + c->pt = j; + + return 1; +} + +// finalize and output a hash + +int sha3_final(void *md, sha3_ctx_t *c) +{ + int i; + + c->st.b[c->pt] ^= 0x01; + c->st.b[c->rsiz - 1] ^= 0x80; + sha3_keccakf(c->st.q); + + for (i = 0; i < c->mdlen; i++) { + ((uint8_t *) md)[i] = c->st.b[i]; + } + + return 1; +} + +// compute a SHA-3 hash (md) of given byte length from "in" + +void *sha3(const void *in, size_t inlen, void *md, int mdlen) +{ + sha3_ctx_t sha3; + + sha3_init(&sha3, mdlen); + sha3_update(&sha3, in, inlen); + sha3_final(md, &sha3); + + return md; +} + +// SHAKE128 and SHAKE256 extensible-output functionality + +void shake_xof(sha3_ctx_t *c) +{ + c->st.b[c->pt] ^= 0x1F; + c->st.b[c->rsiz - 1] ^= 0x80; + sha3_keccakf(c->st.q); + c->pt = 0; +} + +void shake_out(sha3_ctx_t *c, void *out, size_t len) +{ + size_t i; + int j; + + j = c->pt; + for (i = 0; i < len; i++) { + if (j >= c->rsiz) { + sha3_keccakf(c->st.q); + j = 0; + } + ((uint8_t *) out)[i] = c->st.b[j++]; + } + c->pt = j; +} +