From 27ddcd0e8c92ec7a496cecdbd369ba7c3c6a590e Mon Sep 17 00:00:00 2001 From: Thom Wiggers Date: Mon, 29 Aug 2022 13:25:46 +0200 Subject: [PATCH 1/8] Refactor SHA2 api * Use abstract types for SHA2 state This allows to more easily replace SHA2 implementations * Define 'free'-style functions for hash state This allows potential heap-based SHA2 implementations to instantiate sha2 in SPHINCS+ --- ref/context.h | 7 +- ref/hash.h | 19 ++ ref/hash_haraka.c | 5 + ref/hash_sha2.c | 125 ++++++++- ref/hash_shake.c | 7 +- ref/sha2.c | 550 ++++++++++++++++++---------------------- ref/sha2.h | 100 ++++++-- ref/sign.c | 9 + ref/thash_sha2_robust.c | 12 +- ref/thash_sha2_simple.c | 13 +- 10 files changed, 492 insertions(+), 355 deletions(-) diff --git a/ref/context.h b/ref/context.h index aded5643..8471900e 100644 --- a/ref/context.h +++ b/ref/context.h @@ -4,6 +4,9 @@ #include #include "params.h" +#ifdef SPX_SHA2 +#include "sha2.h" +#endif typedef struct { uint8_t pub_seed[SPX_N]; @@ -11,11 +14,11 @@ typedef struct { #ifdef SPX_SHA2 // sha256 state that absorbed pub_seed - uint8_t state_seeded[40]; + sha256ctx state_seeded; # if SPX_SHA512 // sha512 state that absorbed pub_seed - uint8_t state_seeded_512[72]; + sha512ctx state_seeded_512[72]; # endif #endif diff --git a/ref/hash.h b/ref/hash.h index b141f099..00ea7ecc 100644 --- a/ref/hash.h +++ b/ref/hash.h @@ -8,6 +8,9 @@ #define initialize_hash_function SPX_NAMESPACE(initialize_hash_function) void initialize_hash_function(spx_ctx *ctx); +#define free_hash_function SPX_NAMESPACE(free_hash_function) +void free_hash_function(spx_ctx *ctx); + #define prf_addr SPX_NAMESPACE(prf_addr) void prf_addr(unsigned char *out, const spx_ctx *ctx, const uint32_t addr[8]); @@ -24,4 +27,20 @@ void hash_message(unsigned char *digest, uint64_t *tree, uint32_t *leaf_idx, const unsigned char *m, unsigned long long mlen, const spx_ctx *ctx); + +#ifdef SPX_SHA2 +# define SPX_SHA256_ADDR_BYTES 22 + +# define mgf1_256 SPX_NAMESPACE(mgf1_256) + void mgf1_256(unsigned char *out, unsigned long outlen, + const unsigned char *in, unsigned long inlen); + +# define mgf1_512 SPX_NAMESPACE(mgf1_512) + void mgf1_512(unsigned char *out, unsigned long outlen, + const unsigned char *in, unsigned long inlen); + +# define seed_state SPX_NAMESPACE(seed_state) + void seed_state(spx_ctx *ctx); +#endif + #endif diff --git a/ref/hash_haraka.c b/ref/hash_haraka.c index 8ae2de0b..d65d83fb 100644 --- a/ref/hash_haraka.c +++ b/ref/hash_haraka.c @@ -13,6 +13,11 @@ void initialize_hash_function(spx_ctx* ctx) tweak_constants(ctx); } +// we don't support heap-based haraka right now +void free_hash_function(spx_ctx *ctx) { + (void)ctx; // suppress unused variable warnings +} + /* * Computes PRF(key, addr), given a secret key of SPX_N bytes and an address */ diff --git a/ref/hash_sha2.c b/ref/hash_sha2.c index 730bcc9c..30b3ef6b 100644 --- a/ref/hash_sha2.c +++ b/ref/hash_sha2.c @@ -7,6 +7,11 @@ #include "hash.h" #include "sha2.h" +#if SPX_SHA256_OUTPUT_BYTES < SPX_N + #error Linking against SHA-256 with N larger than 32 bytes is not supported +#endif + + #if SPX_N >= 24 #define SPX_SHAX_OUTPUT_BYTES SPX_SHA512_OUTPUT_BYTES #define SPX_SHAX_BLOCK_BYTES SPX_SHA512_BLOCK_BYTES @@ -15,6 +20,7 @@ #define shaX_inc_finalize sha512_inc_finalize #define shaX sha512 #define mgf1_X mgf1_512 +#define shaXstate sha512ctx #else #define SPX_SHAX_OUTPUT_BYTES SPX_SHA256_OUTPUT_BYTES #define SPX_SHAX_BLOCK_BYTES SPX_SHA256_BLOCK_BYTES @@ -23,8 +29,34 @@ #define shaX_inc_finalize sha256_inc_finalize #define shaX sha256 #define mgf1_X mgf1_256 +#define shaXstate sha256ctx #endif +/** + * Absorb the constant pub_seed using one round of the compression function + * This initializes state_seeded and state_seeded_512, which can then be + * reused in thash + **/ +void seed_state(spx_ctx *ctx) { + uint8_t block[SPX_SHA512_BLOCK_BYTES]; + size_t i; + + for (i = 0; i < SPX_N; ++i) { + block[i] = ctx->pub_seed[i]; + } + for (i = SPX_N; i < SPX_SHA512_BLOCK_BYTES; ++i) { + block[i] = 0; + } + /* block has been properly initialized for both SHA-256 and SHA-512 */ + + sha256_inc_init(&ctx->state_seeded); + sha256_inc_blocks(&ctx->state_seeded, block, 1); +#if SPX_SHA512 + sha512_inc_init(&ctx->state_seeded_512); + sha512_inc_blocks(&ctx->state_seeded_512, block, 1); +#endif +} + /* For SHA, there is no immediate reason to initialize at the start, so this function is an empty operation. */ @@ -33,24 +65,89 @@ void initialize_hash_function(spx_ctx *ctx) seed_state(ctx); } +/* Free the incremental hashing context for heap-based SHA2 APIs */ +void free_hash_function(spx_ctx *ctx) +{ + sha256_inc_ctx_release(&ctx->state_seeded); +#if SPX_SHA512 + sha512_inc_ctx_release(&ctx->state_seeded_512); +#endif +} + + +/** + * mgf1 function based on the SHA-256 hash function + * Note that inlen should be sufficiently small that it still allows for + * an array to be allocated on the stack. Typically 'in' is merely a seed. + * Outputs outlen number of bytes + */ +void mgf1_256(unsigned char *out, unsigned long outlen, + const unsigned char *in, unsigned long inlen) +{ + SPX_VLA(uint8_t, inbuf, inlen+4); + unsigned char outbuf[SPX_SHA256_OUTPUT_BYTES]; + uint32_t i; + + memcpy(inbuf, in, inlen); + + /* While we can fit in at least another full block of SHA256 output.. */ + for (i = 0; (i+1)*SPX_SHA256_OUTPUT_BYTES <= outlen; i++) { + u32_to_bytes(inbuf + inlen, i); + sha256(out, inbuf, inlen + 4); + out += SPX_SHA256_OUTPUT_BYTES; + } + /* Until we cannot anymore, and we fill the remainder. */ + if (outlen > i*SPX_SHA256_OUTPUT_BYTES) { + u32_to_bytes(inbuf + inlen, i); + sha256(outbuf, inbuf, inlen + 4); + memcpy(out, outbuf, outlen - i*SPX_SHA256_OUTPUT_BYTES); + } +} + +/* + * mgf1 function based on the SHA-512 hash function + */ +void mgf1_512(unsigned char *out, unsigned long outlen, + const unsigned char *in, unsigned long inlen) +{ + SPX_VLA(uint8_t, inbuf, inlen+4); + unsigned char outbuf[SPX_SHA512_OUTPUT_BYTES]; + uint32_t i; + + memcpy(inbuf, in, inlen); + + /* While we can fit in at least another full block of SHA512 output.. */ + for (i = 0; (i+1)*SPX_SHA512_OUTPUT_BYTES <= outlen; i++) { + u32_to_bytes(inbuf + inlen, i); + sha512(out, inbuf, inlen + 4); + out += SPX_SHA512_OUTPUT_BYTES; + } + /* Until we cannot anymore, and we fill the remainder. */ + if (outlen > i*SPX_SHA512_OUTPUT_BYTES) { + u32_to_bytes(inbuf + inlen, i); + sha512(outbuf, inbuf, inlen + 4); + memcpy(out, outbuf, outlen - i*SPX_SHA512_OUTPUT_BYTES); + } +} + /* * Computes PRF(pk_seed, sk_seed, addr). */ void prf_addr(unsigned char *out, const spx_ctx *ctx, const uint32_t addr[8]) { - uint8_t sha2_state[40]; + sha256ctx sha2_state; unsigned char buf[SPX_SHA256_ADDR_BYTES + SPX_N]; unsigned char outbuf[SPX_SHA256_OUTPUT_BYTES]; /* Retrieve precomputed state containing pub_seed */ - memcpy(sha2_state, ctx->state_seeded, 40 * sizeof(uint8_t)); + sha256_inc_ctx_clone(&sha2_state, &ctx->state_seeded); /* Remainder: ADDR^c ‖ SK.seed */ memcpy(buf, addr, SPX_SHA256_ADDR_BYTES); memcpy(buf + SPX_SHA256_ADDR_BYTES, ctx->sk_seed, SPX_N); - sha256_inc_finalize(outbuf, sha2_state, buf, SPX_SHA256_ADDR_BYTES + SPX_N); + sha256_inc_finalize(outbuf, &sha2_state, buf, SPX_SHA256_ADDR_BYTES + SPX_N); memcpy(out, outbuf, SPX_N); } @@ -71,7 +168,7 @@ void gen_message_random(unsigned char *R, const unsigned char *sk_prf, (void)ctx; unsigned char buf[SPX_SHAX_BLOCK_BYTES + SPX_SHAX_OUTPUT_BYTES]; - uint8_t state[8 + SPX_SHAX_OUTPUT_BYTES]; + shaXstate state; int i; #if SPX_N > SPX_SHAX_BLOCK_BYTES @@ -84,25 +181,25 @@ void gen_message_random(unsigned char *R, const unsigned char *sk_prf, } memset(buf + SPX_N, 0x36, SPX_SHAX_BLOCK_BYTES - SPX_N); - shaX_inc_init(state); - shaX_inc_blocks(state, buf, 1); + shaX_inc_init(&state); + shaX_inc_blocks(&state, buf, 1); memcpy(buf, optrand, SPX_N); /* If optrand + message cannot fill up an entire block */ if (SPX_N + mlen < SPX_SHAX_BLOCK_BYTES) { memcpy(buf + SPX_N, m, mlen); - shaX_inc_finalize(buf + SPX_SHAX_BLOCK_BYTES, state, + shaX_inc_finalize(buf + SPX_SHAX_BLOCK_BYTES, &state, buf, mlen + SPX_N); } /* Otherwise first fill a block, so that finalize only uses the message */ else { memcpy(buf + SPX_N, m, SPX_SHAX_BLOCK_BYTES - SPX_N); - shaX_inc_blocks(state, buf, 1); + shaX_inc_blocks(&state, buf, 1); m += SPX_SHAX_BLOCK_BYTES - SPX_N; mlen -= SPX_SHAX_BLOCK_BYTES - SPX_N; - shaX_inc_finalize(buf + SPX_SHAX_BLOCK_BYTES, state, m, mlen); + shaX_inc_finalize(buf + SPX_SHAX_BLOCK_BYTES, &state, m, mlen); } for (i = 0; i < SPX_N; i++) { @@ -143,9 +240,9 @@ void hash_message(unsigned char *digest, uint64_t *tree, uint32_t *leaf_idx, unsigned char buf[SPX_DGST_BYTES]; unsigned char *bufp = buf; - uint8_t state[8 + SPX_SHAX_OUTPUT_BYTES]; + shaXstate state; - shaX_inc_init(state); + shaX_inc_init(&state); // seed: SHA-X(R ‖ PK.seed ‖ PK.root ‖ M) memcpy(inbuf, R, SPX_N); @@ -154,17 +251,17 @@ void hash_message(unsigned char *digest, uint64_t *tree, uint32_t *leaf_idx, /* If R + pk + message cannot fill up an entire block */ if (SPX_N + SPX_PK_BYTES + mlen < SPX_INBLOCKS * SPX_SHAX_BLOCK_BYTES) { memcpy(inbuf + SPX_N + SPX_PK_BYTES, m, mlen); - shaX_inc_finalize(seed + 2*SPX_N, state, inbuf, SPX_N + SPX_PK_BYTES + mlen); + shaX_inc_finalize(seed + 2*SPX_N, &state, inbuf, SPX_N + SPX_PK_BYTES + mlen); } /* Otherwise first fill a block, so that finalize only uses the message */ else { memcpy(inbuf + SPX_N + SPX_PK_BYTES, m, SPX_INBLOCKS * SPX_SHAX_BLOCK_BYTES - SPX_N - SPX_PK_BYTES); - shaX_inc_blocks(state, inbuf, SPX_INBLOCKS); + shaX_inc_blocks(&state, inbuf, SPX_INBLOCKS); m += SPX_INBLOCKS * SPX_SHAX_BLOCK_BYTES - SPX_N - SPX_PK_BYTES; mlen -= SPX_INBLOCKS * SPX_SHAX_BLOCK_BYTES - SPX_N - SPX_PK_BYTES; - shaX_inc_finalize(seed + 2*SPX_N, state, m, mlen); + shaX_inc_finalize(seed + 2*SPX_N, &state, m, mlen); } // H_msg: MGF1-SHA-X(R ‖ PK.seed ‖ seed) diff --git a/ref/hash_shake.c b/ref/hash_shake.c index afb18d52..4f4a160a 100644 --- a/ref/hash_shake.c +++ b/ref/hash_shake.c @@ -9,11 +9,16 @@ /* For SHAKE256, there is no immediate reason to initialize at the start, so this function is an empty operation. */ -void initialize_hash_function(spx_ctx* ctx) +void initialize_hash_function(spx_ctx *ctx) { (void)ctx; /* Suppress an 'unused parameter' warning. */ } +// in case the hash function api is heap-based. +void free_hash_function(spx_ctx *ctx) { + (void)ctx; +} + /* * Computes PRF(pk_seed, sk_seed, addr) */ diff --git a/ref/sha2.c b/ref/sha2.c index ef730470..999d36c0 100644 --- a/ref/sha2.c +++ b/ref/sha2.c @@ -6,7 +6,6 @@ #include #include -#include "utils.h" #include "sha2.h" static uint32_t load_bigendian_32(const uint8_t *x) { @@ -51,7 +50,7 @@ static void store_bigendian_64(uint8_t *x, uint64_t u) { #define SHR(x, c) ((x) >> (c)) #define ROTR_32(x, c) (((x) >> (c)) | ((x) << (32 - (c)))) -#define ROTR_64(x,c) (((x) >> (c)) | ((x) << (64 - (c)))) +#define ROTR_64(x, c) (((x) >> (c)) | ((x) << (64 - (c)))) #define Ch(x, y, z) (((x) & (y)) ^ (~(x) & (z))) #define Maj(x, y, z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z))) @@ -61,10 +60,10 @@ static void store_bigendian_64(uint8_t *x, uint64_t u) { #define sigma0_32(x) (ROTR_32(x, 7) ^ ROTR_32(x,18) ^ SHR(x, 3)) #define sigma1_32(x) (ROTR_32(x,17) ^ ROTR_32(x,19) ^ SHR(x,10)) -#define Sigma0_64(x) (ROTR_64(x,28) ^ ROTR_64(x,34) ^ ROTR_64(x,39)) -#define Sigma1_64(x) (ROTR_64(x,14) ^ ROTR_64(x,18) ^ ROTR_64(x,41)) -#define sigma0_64(x) (ROTR_64(x, 1) ^ ROTR_64(x, 8) ^ SHR(x,7)) -#define sigma1_64(x) (ROTR_64(x,19) ^ ROTR_64(x,61) ^ SHR(x,6)) +#define Sigma0_64(x) (ROTR_64(x, 28) ^ ROTR_64(x, 34) ^ ROTR_64(x, 39)) +#define Sigma1_64(x) (ROTR_64(x, 14) ^ ROTR_64(x, 18) ^ ROTR_64(x, 41)) +#define sigma0_64(x) (ROTR_64(x, 1) ^ ROTR_64(x, 8) ^ SHR(x, 7)) +#define sigma1_64(x) (ROTR_64(x, 19) ^ ROTR_64(x, 61) ^ SHR(x, 6)) #define M_32(w0, w14, w9, w1) w0 = sigma1_32(w14) + (w9) + sigma0_32(w1) + (w0); #define M_64(w0, w14, w9, w1) w0 = sigma1_64(w14) + (w9) + sigma0_64(w1) + (w0); @@ -87,23 +86,23 @@ static void store_bigendian_64(uint8_t *x, uint64_t u) { M_32(w14, w12, w7, w15) \ M_32(w15, w13, w8, w0) -#define EXPAND_64 \ - M_64(w0 ,w14,w9 ,w1 ) \ - M_64(w1 ,w15,w10,w2 ) \ - M_64(w2 ,w0 ,w11,w3 ) \ - M_64(w3 ,w1 ,w12,w4 ) \ - M_64(w4 ,w2 ,w13,w5 ) \ - M_64(w5 ,w3 ,w14,w6 ) \ - M_64(w6 ,w4 ,w15,w7 ) \ - M_64(w7 ,w5 ,w0 ,w8 ) \ - M_64(w8 ,w6 ,w1 ,w9 ) \ - M_64(w9 ,w7 ,w2 ,w10) \ - M_64(w10,w8 ,w3 ,w11) \ - M_64(w11,w9 ,w4 ,w12) \ - M_64(w12,w10,w5 ,w13) \ - M_64(w13,w11,w6 ,w14) \ - M_64(w14,w12,w7 ,w15) \ - M_64(w15,w13,w8 ,w0 ) +#define EXPAND_64 \ + M_64(w0, w14, w9, w1) \ + M_64(w1, w15, w10, w2) \ + M_64(w2, w0, w11, w3) \ + M_64(w3, w1, w12, w4) \ + M_64(w4, w2, w13, w5) \ + M_64(w5, w3, w14, w6) \ + M_64(w6, w4, w15, w7) \ + M_64(w7, w5, w0, w8) \ + M_64(w8, w6, w1, w9) \ + M_64(w9, w7, w2, w10) \ + M_64(w10, w8, w3, w11) \ + M_64(w11, w9, w4, w12) \ + M_64(w12, w10, w5, w13) \ + M_64(w13, w11, w6, w14) \ + M_64(w14, w12, w7, w15) \ + M_64(w15, w13, w8, w0) #define F_32(w, k) \ T1 = h + Sigma1_32(e) + Ch(e, f, g) + (k) + (w); \ @@ -117,16 +116,16 @@ static void store_bigendian_64(uint8_t *x, uint64_t u) { b = a; \ a = T1 + T2; -#define F_64(w,k) \ - T1 = h + Sigma1_64(e) + Ch(e,f,g) + k + w; \ - T2 = Sigma0_64(a) + Maj(a,b,c); \ - h = g; \ - g = f; \ - f = e; \ - e = d + T1; \ - d = c; \ - c = b; \ - b = a; \ +#define F_64(w, k) \ + T1 = h + Sigma1_64(e) + Ch(e, f, g) + (k) + (w); \ + T2 = Sigma0_64(a) + Maj(a, b, c); \ + h = g; \ + g = f; \ + f = e; \ + e = d + T1; \ + d = c; \ + c = b; \ + b = a; \ a = T1 + T2; static size_t crypto_hashblocks_sha256(uint8_t *statebytes, @@ -286,174 +285,181 @@ static size_t crypto_hashblocks_sha256(uint8_t *statebytes, return inlen; } -static int crypto_hashblocks_sha512(unsigned char *statebytes,const unsigned char *in,unsigned long long inlen) -{ - uint64_t state[8]; - uint64_t a; - uint64_t b; - uint64_t c; - uint64_t d; - uint64_t e; - uint64_t f; - uint64_t g; - uint64_t h; - uint64_t T1; - uint64_t T2; - - a = load_bigendian_64(statebytes + 0); state[0] = a; - b = load_bigendian_64(statebytes + 8); state[1] = b; - c = load_bigendian_64(statebytes + 16); state[2] = c; - d = load_bigendian_64(statebytes + 24); state[3] = d; - e = load_bigendian_64(statebytes + 32); state[4] = e; - f = load_bigendian_64(statebytes + 40); state[5] = f; - g = load_bigendian_64(statebytes + 48); state[6] = g; - h = load_bigendian_64(statebytes + 56); state[7] = h; - - while (inlen >= 128) { - uint64_t w0 = load_bigendian_64(in + 0); - uint64_t w1 = load_bigendian_64(in + 8); - uint64_t w2 = load_bigendian_64(in + 16); - uint64_t w3 = load_bigendian_64(in + 24); - uint64_t w4 = load_bigendian_64(in + 32); - uint64_t w5 = load_bigendian_64(in + 40); - uint64_t w6 = load_bigendian_64(in + 48); - uint64_t w7 = load_bigendian_64(in + 56); - uint64_t w8 = load_bigendian_64(in + 64); - uint64_t w9 = load_bigendian_64(in + 72); - uint64_t w10 = load_bigendian_64(in + 80); - uint64_t w11 = load_bigendian_64(in + 88); - uint64_t w12 = load_bigendian_64(in + 96); - uint64_t w13 = load_bigendian_64(in + 104); - uint64_t w14 = load_bigendian_64(in + 112); - uint64_t w15 = load_bigendian_64(in + 120); - - F_64(w0 ,0x428a2f98d728ae22ULL) - F_64(w1 ,0x7137449123ef65cdULL) - F_64(w2 ,0xb5c0fbcfec4d3b2fULL) - F_64(w3 ,0xe9b5dba58189dbbcULL) - F_64(w4 ,0x3956c25bf348b538ULL) - F_64(w5 ,0x59f111f1b605d019ULL) - F_64(w6 ,0x923f82a4af194f9bULL) - F_64(w7 ,0xab1c5ed5da6d8118ULL) - F_64(w8 ,0xd807aa98a3030242ULL) - F_64(w9 ,0x12835b0145706fbeULL) - F_64(w10,0x243185be4ee4b28cULL) - F_64(w11,0x550c7dc3d5ffb4e2ULL) - F_64(w12,0x72be5d74f27b896fULL) - F_64(w13,0x80deb1fe3b1696b1ULL) - F_64(w14,0x9bdc06a725c71235ULL) - F_64(w15,0xc19bf174cf692694ULL) - - EXPAND_64 - - F_64(w0 ,0xe49b69c19ef14ad2ULL) - F_64(w1 ,0xefbe4786384f25e3ULL) - F_64(w2 ,0x0fc19dc68b8cd5b5ULL) - F_64(w3 ,0x240ca1cc77ac9c65ULL) - F_64(w4 ,0x2de92c6f592b0275ULL) - F_64(w5 ,0x4a7484aa6ea6e483ULL) - F_64(w6 ,0x5cb0a9dcbd41fbd4ULL) - F_64(w7 ,0x76f988da831153b5ULL) - F_64(w8 ,0x983e5152ee66dfabULL) - F_64(w9 ,0xa831c66d2db43210ULL) - F_64(w10,0xb00327c898fb213fULL) - F_64(w11,0xbf597fc7beef0ee4ULL) - F_64(w12,0xc6e00bf33da88fc2ULL) - F_64(w13,0xd5a79147930aa725ULL) - F_64(w14,0x06ca6351e003826fULL) - F_64(w15,0x142929670a0e6e70ULL) - - EXPAND_64 - - F_64(w0 ,0x27b70a8546d22ffcULL) - F_64(w1 ,0x2e1b21385c26c926ULL) - F_64(w2 ,0x4d2c6dfc5ac42aedULL) - F_64(w3 ,0x53380d139d95b3dfULL) - F_64(w4 ,0x650a73548baf63deULL) - F_64(w5 ,0x766a0abb3c77b2a8ULL) - F_64(w6 ,0x81c2c92e47edaee6ULL) - F_64(w7 ,0x92722c851482353bULL) - F_64(w8 ,0xa2bfe8a14cf10364ULL) - F_64(w9 ,0xa81a664bbc423001ULL) - F_64(w10,0xc24b8b70d0f89791ULL) - F_64(w11,0xc76c51a30654be30ULL) - F_64(w12,0xd192e819d6ef5218ULL) - F_64(w13,0xd69906245565a910ULL) - F_64(w14,0xf40e35855771202aULL) - F_64(w15,0x106aa07032bbd1b8ULL) - - EXPAND_64 - - F_64(w0 ,0x19a4c116b8d2d0c8ULL) - F_64(w1 ,0x1e376c085141ab53ULL) - F_64(w2 ,0x2748774cdf8eeb99ULL) - F_64(w3 ,0x34b0bcb5e19b48a8ULL) - F_64(w4 ,0x391c0cb3c5c95a63ULL) - F_64(w5 ,0x4ed8aa4ae3418acbULL) - F_64(w6 ,0x5b9cca4f7763e373ULL) - F_64(w7 ,0x682e6ff3d6b2b8a3ULL) - F_64(w8 ,0x748f82ee5defb2fcULL) - F_64(w9 ,0x78a5636f43172f60ULL) - F_64(w10,0x84c87814a1f0ab72ULL) - F_64(w11,0x8cc702081a6439ecULL) - F_64(w12,0x90befffa23631e28ULL) - F_64(w13,0xa4506cebde82bde9ULL) - F_64(w14,0xbef9a3f7b2c67915ULL) - F_64(w15,0xc67178f2e372532bULL) - - EXPAND_64 - - F_64(w0 ,0xca273eceea26619cULL) - F_64(w1 ,0xd186b8c721c0c207ULL) - F_64(w2 ,0xeada7dd6cde0eb1eULL) - F_64(w3 ,0xf57d4f7fee6ed178ULL) - F_64(w4 ,0x06f067aa72176fbaULL) - F_64(w5 ,0x0a637dc5a2c898a6ULL) - F_64(w6 ,0x113f9804bef90daeULL) - F_64(w7 ,0x1b710b35131c471bULL) - F_64(w8 ,0x28db77f523047d84ULL) - F_64(w9 ,0x32caab7b40c72493ULL) - F_64(w10,0x3c9ebe0a15c9bebcULL) - F_64(w11,0x431d67c49c100d4cULL) - F_64(w12,0x4cc5d4becb3e42b6ULL) - F_64(w13,0x597f299cfc657e2aULL) - F_64(w14,0x5fcb6fab3ad6faecULL) - F_64(w15,0x6c44198c4a475817ULL) - - a += state[0]; - b += state[1]; - c += state[2]; - d += state[3]; - e += state[4]; - f += state[5]; - g += state[6]; - h += state[7]; - +static size_t crypto_hashblocks_sha512(uint8_t *statebytes, + const uint8_t *in, size_t inlen) { + uint64_t state[8]; + uint64_t a; + uint64_t b; + uint64_t c; + uint64_t d; + uint64_t e; + uint64_t f; + uint64_t g; + uint64_t h; + uint64_t T1; + uint64_t T2; + + a = load_bigendian_64(statebytes + 0); state[0] = a; + b = load_bigendian_64(statebytes + 8); state[1] = b; + c = load_bigendian_64(statebytes + 16); state[2] = c; + d = load_bigendian_64(statebytes + 24); state[3] = d; + e = load_bigendian_64(statebytes + 32); state[4] = e; + f = load_bigendian_64(statebytes + 40); state[5] = f; + g = load_bigendian_64(statebytes + 48); state[6] = g; + h = load_bigendian_64(statebytes + 56); state[7] = h; - in += 128; - inlen -= 128; - } + while (inlen >= 128) { + uint64_t w0 = load_bigendian_64(in + 0); + uint64_t w1 = load_bigendian_64(in + 8); + uint64_t w2 = load_bigendian_64(in + 16); + uint64_t w3 = load_bigendian_64(in + 24); + uint64_t w4 = load_bigendian_64(in + 32); + uint64_t w5 = load_bigendian_64(in + 40); + uint64_t w6 = load_bigendian_64(in + 48); + uint64_t w7 = load_bigendian_64(in + 56); + uint64_t w8 = load_bigendian_64(in + 64); + uint64_t w9 = load_bigendian_64(in + 72); + uint64_t w10 = load_bigendian_64(in + 80); + uint64_t w11 = load_bigendian_64(in + 88); + uint64_t w12 = load_bigendian_64(in + 96); + uint64_t w13 = load_bigendian_64(in + 104); + uint64_t w14 = load_bigendian_64(in + 112); + uint64_t w15 = load_bigendian_64(in + 120); + + F_64(w0, 0x428a2f98d728ae22ULL) + F_64(w1, 0x7137449123ef65cdULL) + F_64(w2, 0xb5c0fbcfec4d3b2fULL) + F_64(w3, 0xe9b5dba58189dbbcULL) + F_64(w4, 0x3956c25bf348b538ULL) + F_64(w5, 0x59f111f1b605d019ULL) + F_64(w6, 0x923f82a4af194f9bULL) + F_64(w7, 0xab1c5ed5da6d8118ULL) + F_64(w8, 0xd807aa98a3030242ULL) + F_64(w9, 0x12835b0145706fbeULL) + F_64(w10, 0x243185be4ee4b28cULL) + F_64(w11, 0x550c7dc3d5ffb4e2ULL) + F_64(w12, 0x72be5d74f27b896fULL) + F_64(w13, 0x80deb1fe3b1696b1ULL) + F_64(w14, 0x9bdc06a725c71235ULL) + F_64(w15, 0xc19bf174cf692694ULL) + + EXPAND_64 + + F_64(w0, 0xe49b69c19ef14ad2ULL) + F_64(w1, 0xefbe4786384f25e3ULL) + F_64(w2, 0x0fc19dc68b8cd5b5ULL) + F_64(w3, 0x240ca1cc77ac9c65ULL) + F_64(w4, 0x2de92c6f592b0275ULL) + F_64(w5, 0x4a7484aa6ea6e483ULL) + F_64(w6, 0x5cb0a9dcbd41fbd4ULL) + F_64(w7, 0x76f988da831153b5ULL) + F_64(w8, 0x983e5152ee66dfabULL) + F_64(w9, 0xa831c66d2db43210ULL) + F_64(w10, 0xb00327c898fb213fULL) + F_64(w11, 0xbf597fc7beef0ee4ULL) + F_64(w12, 0xc6e00bf33da88fc2ULL) + F_64(w13, 0xd5a79147930aa725ULL) + F_64(w14, 0x06ca6351e003826fULL) + F_64(w15, 0x142929670a0e6e70ULL) + + EXPAND_64 + + F_64(w0, 0x27b70a8546d22ffcULL) + F_64(w1, 0x2e1b21385c26c926ULL) + F_64(w2, 0x4d2c6dfc5ac42aedULL) + F_64(w3, 0x53380d139d95b3dfULL) + F_64(w4, 0x650a73548baf63deULL) + F_64(w5, 0x766a0abb3c77b2a8ULL) + F_64(w6, 0x81c2c92e47edaee6ULL) + F_64(w7, 0x92722c851482353bULL) + F_64(w8, 0xa2bfe8a14cf10364ULL) + F_64(w9, 0xa81a664bbc423001ULL) + F_64(w10, 0xc24b8b70d0f89791ULL) + F_64(w11, 0xc76c51a30654be30ULL) + F_64(w12, 0xd192e819d6ef5218ULL) + F_64(w13, 0xd69906245565a910ULL) + F_64(w14, 0xf40e35855771202aULL) + F_64(w15, 0x106aa07032bbd1b8ULL) + + EXPAND_64 + + F_64(w0, 0x19a4c116b8d2d0c8ULL) + F_64(w1, 0x1e376c085141ab53ULL) + F_64(w2, 0x2748774cdf8eeb99ULL) + F_64(w3, 0x34b0bcb5e19b48a8ULL) + F_64(w4, 0x391c0cb3c5c95a63ULL) + F_64(w5, 0x4ed8aa4ae3418acbULL) + F_64(w6, 0x5b9cca4f7763e373ULL) + F_64(w7, 0x682e6ff3d6b2b8a3ULL) + F_64(w8, 0x748f82ee5defb2fcULL) + F_64(w9, 0x78a5636f43172f60ULL) + F_64(w10, 0x84c87814a1f0ab72ULL) + F_64(w11, 0x8cc702081a6439ecULL) + F_64(w12, 0x90befffa23631e28ULL) + F_64(w13, 0xa4506cebde82bde9ULL) + F_64(w14, 0xbef9a3f7b2c67915ULL) + F_64(w15, 0xc67178f2e372532bULL) + + EXPAND_64 + + F_64(w0, 0xca273eceea26619cULL) + F_64(w1, 0xd186b8c721c0c207ULL) + F_64(w2, 0xeada7dd6cde0eb1eULL) + F_64(w3, 0xf57d4f7fee6ed178ULL) + F_64(w4, 0x06f067aa72176fbaULL) + F_64(w5, 0x0a637dc5a2c898a6ULL) + F_64(w6, 0x113f9804bef90daeULL) + F_64(w7, 0x1b710b35131c471bULL) + F_64(w8, 0x28db77f523047d84ULL) + F_64(w9, 0x32caab7b40c72493ULL) + F_64(w10, 0x3c9ebe0a15c9bebcULL) + F_64(w11, 0x431d67c49c100d4cULL) + F_64(w12, 0x4cc5d4becb3e42b6ULL) + F_64(w13, 0x597f299cfc657e2aULL) + F_64(w14, 0x5fcb6fab3ad6faecULL) + F_64(w15, 0x6c44198c4a475817ULL) - store_bigendian_64(statebytes + 0,state[0]); - store_bigendian_64(statebytes + 8,state[1]); - store_bigendian_64(statebytes + 16,state[2]); - store_bigendian_64(statebytes + 24,state[3]); - store_bigendian_64(statebytes + 32,state[4]); - store_bigendian_64(statebytes + 40,state[5]); - store_bigendian_64(statebytes + 48,state[6]); - store_bigendian_64(statebytes + 56,state[7]); + a += state[0]; + b += state[1]; + c += state[2]; + d += state[3]; + e += state[4]; + f += state[5]; + g += state[6]; + h += state[7]; - return inlen; -} + state[0] = a; + state[1] = b; + state[2] = c; + state[3] = d; + state[4] = e; + state[5] = f; + state[6] = g; + state[7] = h; + + in += 128; + inlen -= 128; + } + store_bigendian_64(statebytes + 0, state[0]); + store_bigendian_64(statebytes + 8, state[1]); + store_bigendian_64(statebytes + 16, state[2]); + store_bigendian_64(statebytes + 24, state[3]); + store_bigendian_64(statebytes + 32, state[4]); + store_bigendian_64(statebytes + 40, state[5]); + store_bigendian_64(statebytes + 48, state[6]); + store_bigendian_64(statebytes + 56, state[7]); + + return inlen; +} static const uint8_t iv_256[32] = { 0x6a, 0x09, 0xe6, 0x67, 0xbb, 0x67, 0xae, 0x85, @@ -471,47 +477,65 @@ static const uint8_t iv_512[64] = { 0x6b, 0x5b, 0xe0, 0xcd, 0x19, 0x13, 0x7e, 0x21, 0x79 }; -void sha256_inc_init(uint8_t *state) { +void sha256_inc_init(sha256ctx *state) { for (size_t i = 0; i < 32; ++i) { - state[i] = iv_256[i]; + state->ctx[i] = iv_256[i]; } for (size_t i = 32; i < 40; ++i) { - state[i] = 0; + state->ctx[i] = 0; } } -void sha512_inc_init(uint8_t *state) { +void sha512_inc_init(sha512ctx *state) { for (size_t i = 0; i < 64; ++i) { - state[i] = iv_512[i]; + state->ctx[i] = iv_512[i]; } for (size_t i = 64; i < 72; ++i) { - state[i] = 0; + state->ctx[i] = 0; } } -void sha256_inc_blocks(uint8_t *state, const uint8_t *in, size_t inblocks) { - uint64_t bytes = load_bigendian_64(state + 32); +void sha256_inc_ctx_clone(sha256ctx *stateout, const sha256ctx *statein) { + memcpy(stateout->ctx, statein->ctx, SPX_SHA256CTX_BYTES); +} - crypto_hashblocks_sha256(state, in, 64 * inblocks); +void sha512_inc_ctx_clone(sha512ctx *stateout, const sha512ctx *statein) { + memcpy(stateout->ctx, statein->ctx, SPX_SHA512CTX_BYTES); +} + +/* Destroy the hash state. */ +void sha256_inc_ctx_release(sha256ctx *state) { + (void)state; // avoid unused variable warnings +} + +/* Destroy the hash state. */ +void sha512_inc_ctx_release(sha512ctx *state) { + (void)state; // avoid unused variable warnings +} + +void sha256_inc_blocks(sha256ctx *state, const uint8_t *in, size_t inblocks) { + uint64_t bytes = load_bigendian_64(state->ctx + 32); + + crypto_hashblocks_sha256(state->ctx, in, 64 * inblocks); bytes += 64 * inblocks; - store_bigendian_64(state + 32, bytes); + store_bigendian_64(state->ctx + 32, bytes); } -void sha512_inc_blocks(uint8_t *state, const uint8_t *in, size_t inblocks) { - uint64_t bytes = load_bigendian_64(state + 64); +void sha512_inc_blocks(sha512ctx *state, const uint8_t *in, size_t inblocks) { + uint64_t bytes = load_bigendian_64(state->ctx + 64); - crypto_hashblocks_sha512(state, in, 128 * inblocks); + crypto_hashblocks_sha512(state->ctx, in, 128 * inblocks); bytes += 128 * inblocks; - store_bigendian_64(state + 64, bytes); + store_bigendian_64(state->ctx + 64, bytes); } -void sha256_inc_finalize(uint8_t *out, uint8_t *state, const uint8_t *in, size_t inlen) { +void sha256_inc_finalize(uint8_t *out, sha256ctx *state, const uint8_t *in, size_t inlen) { uint8_t padded[128]; - uint64_t bytes = load_bigendian_64(state + 32) + inlen; + uint64_t bytes = load_bigendian_64(state->ctx + 32) + inlen; - crypto_hashblocks_sha256(state, in, inlen); + crypto_hashblocks_sha256(state->ctx, in, inlen); in += inlen; inlen &= 63; in -= inlen; @@ -533,7 +557,7 @@ void sha256_inc_finalize(uint8_t *out, uint8_t *state, const uint8_t *in, size_t padded[61] = (uint8_t) (bytes >> 13); padded[62] = (uint8_t) (bytes >> 5); padded[63] = (uint8_t) (bytes << 3); - crypto_hashblocks_sha256(state, padded, 64); + crypto_hashblocks_sha256(state->ctx, padded, 64); } else { for (size_t i = inlen + 1; i < 120; ++i) { padded[i] = 0; @@ -546,20 +570,20 @@ void sha256_inc_finalize(uint8_t *out, uint8_t *state, const uint8_t *in, size_t padded[125] = (uint8_t) (bytes >> 13); padded[126] = (uint8_t) (bytes >> 5); padded[127] = (uint8_t) (bytes << 3); - crypto_hashblocks_sha256(state, padded, 128); + crypto_hashblocks_sha256(state->ctx, padded, 128); } for (size_t i = 0; i < 32; ++i) { - out[i] = state[i]; + out[i] = state->ctx[i]; } - + sha256_inc_ctx_release(state); } -void sha512_inc_finalize(uint8_t *out, uint8_t *state, const uint8_t *in, size_t inlen) { +void sha512_inc_finalize(uint8_t *out, sha512ctx *state, const uint8_t *in, size_t inlen) { uint8_t padded[256]; - uint64_t bytes = load_bigendian_64(state + 64) + inlen; + uint64_t bytes = load_bigendian_64(state->ctx + 64) + inlen; - crypto_hashblocks_sha512(state, in, inlen); + crypto_hashblocks_sha512(state->ctx, in, inlen); in += inlen; inlen &= 127; in -= inlen; @@ -582,7 +606,7 @@ void sha512_inc_finalize(uint8_t *out, uint8_t *state, const uint8_t *in, size_t padded[125] = (uint8_t) (bytes >> 13); padded[126] = (uint8_t) (bytes >> 5); padded[127] = (uint8_t) (bytes << 3); - crypto_hashblocks_sha512(state, padded, 128); + crypto_hashblocks_sha512(state->ctx, padded, 128); } else { for (size_t i = inlen + 1; i < 247; ++i) { padded[i] = 0; @@ -596,105 +620,25 @@ void sha512_inc_finalize(uint8_t *out, uint8_t *state, const uint8_t *in, size_t padded[253] = (uint8_t) (bytes >> 13); padded[254] = (uint8_t) (bytes >> 5); padded[255] = (uint8_t) (bytes << 3); - crypto_hashblocks_sha512(state, padded, 256); + crypto_hashblocks_sha512(state->ctx, padded, 256); } for (size_t i = 0; i < 64; ++i) { - out[i] = state[i]; + out[i] = state->ctx[i]; } + sha512_inc_ctx_release(state); } void sha256(uint8_t *out, const uint8_t *in, size_t inlen) { - uint8_t state[40]; + sha256ctx state; - sha256_inc_init(state); - sha256_inc_finalize(out, state, in, inlen); + sha256_inc_init(&state); + sha256_inc_finalize(out, &state, in, inlen); } void sha512(uint8_t *out, const uint8_t *in, size_t inlen) { - uint8_t state[72]; - - sha512_inc_init(state); - sha512_inc_finalize(out, state, in, inlen); -} + sha512ctx state; -/** - * mgf1 function based on the SHA-256 hash function - * Note that inlen should be sufficiently small that it still allows for - * an array to be allocated on the stack. Typically 'in' is merely a seed. - * Outputs outlen number of bytes - */ -void mgf1_256(unsigned char *out, unsigned long outlen, - const unsigned char *in, unsigned long inlen) -{ - SPX_VLA(uint8_t, inbuf, inlen+4); - unsigned char outbuf[SPX_SHA256_OUTPUT_BYTES]; - unsigned long i; - - memcpy(inbuf, in, inlen); - - /* While we can fit in at least another full block of SHA256 output.. */ - for (i = 0; (i+1)*SPX_SHA256_OUTPUT_BYTES <= outlen; i++) { - u32_to_bytes(inbuf + inlen, i); - sha256(out, inbuf, inlen + 4); - out += SPX_SHA256_OUTPUT_BYTES; - } - /* Until we cannot anymore, and we fill the remainder. */ - if (outlen > i*SPX_SHA256_OUTPUT_BYTES) { - u32_to_bytes(inbuf + inlen, i); - sha256(outbuf, inbuf, inlen + 4); - memcpy(out, outbuf, outlen - i*SPX_SHA256_OUTPUT_BYTES); - } -} - -/* - * mgf1 function based on the SHA-512 hash function - */ -void mgf1_512(unsigned char *out, unsigned long outlen, - const unsigned char *in, unsigned long inlen) -{ - SPX_VLA(uint8_t, inbuf, inlen+4); - unsigned char outbuf[SPX_SHA512_OUTPUT_BYTES]; - unsigned long i; - - memcpy(inbuf, in, inlen); - - /* While we can fit in at least another full block of SHA512 output.. */ - for (i = 0; (i+1)*SPX_SHA512_OUTPUT_BYTES <= outlen; i++) { - u32_to_bytes(inbuf + inlen, i); - sha512(out, inbuf, inlen + 4); - out += SPX_SHA512_OUTPUT_BYTES; - } - /* Until we cannot anymore, and we fill the remainder. */ - if (outlen > i*SPX_SHA512_OUTPUT_BYTES) { - u32_to_bytes(inbuf + inlen, i); - sha512(outbuf, inbuf, inlen + 4); - memcpy(out, outbuf, outlen - i*SPX_SHA512_OUTPUT_BYTES); - } -} - - -/** - * Absorb the constant pub_seed using one round of the compression function - * This initializes state_seeded and state_seeded_512, which can then be - * reused in thash - **/ -void seed_state(spx_ctx *ctx) { - uint8_t block[SPX_SHA512_BLOCK_BYTES]; - size_t i; - - for (i = 0; i < SPX_N; ++i) { - block[i] = ctx->pub_seed[i]; - } - for (i = SPX_N; i < SPX_SHA512_BLOCK_BYTES; ++i) { - block[i] = 0; - } - /* block has been properly initialized for both SHA-256 and SHA-512 */ - - sha256_inc_init(ctx->state_seeded); - sha256_inc_blocks(ctx->state_seeded, block, 1); -#if SPX_SHA512 - sha512_inc_init(ctx->state_seeded_512); - sha512_inc_blocks(ctx->state_seeded_512, block, 1); -#endif + sha512_inc_init(&state); + sha512_inc_finalize(out, &state, in, inlen); } diff --git a/ref/sha2.h b/ref/sha2.h index 732ab4bf..0c5d37a3 100644 --- a/ref/sha2.h +++ b/ref/sha2.h @@ -1,43 +1,97 @@ #ifndef SPX_SHA2_H #define SPX_SHA2_H -#include "params.h" +#include +#include #define SPX_SHA256_BLOCK_BYTES 64 -#define SPX_SHA256_OUTPUT_BYTES 32 /* This does not necessarily equal SPX_N */ +#define SPX_SHA256_OUTPUT_BYTES 32 #define SPX_SHA512_BLOCK_BYTES 128 #define SPX_SHA512_OUTPUT_BYTES 64 -#if SPX_SHA256_OUTPUT_BYTES < SPX_N - #error Linking against SHA-256 with N larger than 32 bytes is not supported -#endif +/* The incremental API allows hashing of individual input blocks; these blocks + must be exactly 64 bytes each. + Use the 'finalize' functions for any remaining bytes (possibly over 64). */ -#define SPX_SHA256_ADDR_BYTES 22 +#define SPX_SHA256CTX_BYTES 40 +/* Structure for the incremental API */ +typedef struct { + uint8_t ctx[SPX_SHA256CTX_BYTES]; +} sha256ctx; -#include -#include +#define SPX_SHA512CTX_BYTES 72 +/* Structure for the incremental API */ +typedef struct { + uint8_t ctx[SPX_SHA512CTX_BYTES]; +} sha512ctx; + +/* ====== SHA256 API ==== */ + +/** + * Initialize the incremental hashing API + */ +void sha256_inc_init(sha256ctx *state); + +/** + * Copy the hashing state + */ +void sha256_inc_ctx_clone(sha256ctx *stateout, const sha256ctx *statein); -void sha256_inc_init(uint8_t *state); -void sha256_inc_blocks(uint8_t *state, const uint8_t *in, size_t inblocks); -void sha256_inc_finalize(uint8_t *out, uint8_t *state, const uint8_t *in, size_t inlen); +/** + * Absorb blocks + */ +void sha256_inc_blocks(sha256ctx *state, const uint8_t *in, size_t inblocks); + +/** + * Finalize and obtain the digest + * + * If applicable, this function will free the memory associated with the sha256ctx. + */ +void sha256_inc_finalize(uint8_t *out, sha256ctx *state, const uint8_t *in, size_t inlen); + +/** + * Destroy the state. Make sure to use this, as this API may not always be stack-based. + */ +void sha256_inc_ctx_release(sha256ctx *state); + +/** + * All-in-one sha256 function + */ void sha256(uint8_t *out, const uint8_t *in, size_t inlen); -void sha512_inc_init(uint8_t *state); -void sha512_inc_blocks(uint8_t *state, const uint8_t *in, size_t inblocks); -void sha512_inc_finalize(uint8_t *out, uint8_t *state, const uint8_t *in, size_t inlen); -void sha512(uint8_t *out, const uint8_t *in, size_t inlen); +/* ====== SHA512 API ==== */ -#define mgf1_256 SPX_NAMESPACE(mgf1_256) -void mgf1_256(unsigned char *out, unsigned long outlen, - const unsigned char *in, unsigned long inlen); +/** + * Initialize the incremental hashing API + */ +void sha512_inc_init(sha512ctx *state); -#define mgf1_512 SPX_NAMESPACE(mgf1_512) -void mgf1_512(unsigned char *out, unsigned long outlen, - const unsigned char *in, unsigned long inlen); +/** + * Copy the hashing state + */ +void sha512_inc_ctx_clone(sha512ctx *stateout, const sha512ctx *statein); -#define seed_state SPX_NAMESPACE(seed_state) -void seed_state(spx_ctx *ctx); +/** + * Absorb blocks + */ +void sha512_inc_blocks(sha512ctx *state, const uint8_t *in, size_t inblocks); +/** + * Finalize and obtain the digest + * + * If applicable, this function will free the memory associated with the sha512ctx. + */ +void sha512_inc_finalize(uint8_t *out, sha512ctx *state, const uint8_t *in, size_t inlen); + +/** + * Destroy the state. Make sure to use this if not calling finalize, as this API may not always be stack-based. + */ +void sha512_inc_ctx_release(sha512ctx *state); + +/** + * All-in-one sha512 function + */ +void sha512(uint8_t *out, const uint8_t *in, size_t inlen); #endif diff --git a/ref/sign.c b/ref/sign.c index a8e0c3c3..0177b0f9 100644 --- a/ref/sign.c +++ b/ref/sign.c @@ -3,6 +3,7 @@ #include #include "api.h" +#include "context.h" #include "params.h" #include "wots.h" #include "fors.h" @@ -70,6 +71,9 @@ int crypto_sign_seed_keypair(unsigned char *pk, unsigned char *sk, /* Compute root node of the top-most subtree. */ merkle_gen_root(sk + 3*SPX_N, &ctx); + // cleanup + free_hash_function(&ctx); + memcpy(pk + SPX_N, sk + 3*SPX_N, SPX_N); return 0; @@ -152,6 +156,8 @@ int crypto_sign_signature(uint8_t *sig, size_t *siglen, tree = tree >> SPX_TREE_HEIGHT; } + free_hash_function(&ctx); + *siglen = SPX_BYTES; return 0; @@ -231,6 +237,9 @@ int crypto_sign_verify(const uint8_t *sig, size_t siglen, tree = tree >> SPX_TREE_HEIGHT; } + // cleanup + free_hash_function(&ctx); + /* Check if the root node equals the root node in the public key. */ if (memcmp(root, pub_root, SPX_N)) { return -1; diff --git a/ref/thash_sha2_robust.c b/ref/thash_sha2_robust.c index 67ca3dae..551b88c0 100644 --- a/ref/thash_sha2_robust.c +++ b/ref/thash_sha2_robust.c @@ -27,7 +27,7 @@ void thash(unsigned char *out, const unsigned char *in, unsigned int inblocks, unsigned char outbuf[SPX_SHA256_OUTPUT_BYTES]; SPX_VLA(uint8_t, bitmask, inblocks * SPX_N); SPX_VLA(uint8_t, buf, SPX_N + SPX_SHA256_OUTPUT_BYTES + inblocks*SPX_N); - uint8_t sha2_state[40]; + sha256ctx sha2_state; unsigned int i; memcpy(buf, ctx->pub_seed, SPX_N); @@ -35,13 +35,13 @@ void thash(unsigned char *out, const unsigned char *in, unsigned int inblocks, mgf1_256(bitmask, inblocks * SPX_N, buf, SPX_N + SPX_SHA256_ADDR_BYTES); /* Retrieve precomputed state containing pub_seed */ - memcpy(sha2_state, ctx->state_seeded, 40 * sizeof(uint8_t)); + sha256_inc_ctx_clone(&sha2_state, ctx->state_seeded); for (i = 0; i < inblocks * SPX_N; i++) { buf[SPX_N + SPX_SHA256_ADDR_BYTES + i] = in[i] ^ bitmask[i]; } - sha256_inc_finalize(outbuf, sha2_state, buf + SPX_N, + sha256_inc_finalize(outbuf, &sha2_state, buf + SPX_N, SPX_SHA256_ADDR_BYTES + inblocks*SPX_N); memcpy(out, outbuf, SPX_N); } @@ -53,7 +53,7 @@ static void thash_512(unsigned char *out, const unsigned char *in, unsigned int unsigned char outbuf[SPX_SHA512_OUTPUT_BYTES]; SPX_VLA(uint8_t, bitmask, inblocks * SPX_N); SPX_VLA(uint8_t, buf, SPX_N + SPX_SHA256_ADDR_BYTES + inblocks*SPX_N); - uint8_t sha2_state[72]; + sha512ctx sha2_state; unsigned int i; memcpy(buf, ctx->pub_seed, SPX_N); @@ -61,13 +61,13 @@ static void thash_512(unsigned char *out, const unsigned char *in, unsigned int mgf1_512(bitmask, inblocks * SPX_N, buf, SPX_N + SPX_SHA256_ADDR_BYTES); /* Retrieve precomputed state containing pub_seed */ - memcpy(sha2_state, ctx->state_seeded_512, 72 * sizeof(uint8_t)); + sha512_inc_ctx_clone(&sha2_state, &ctx->state_seeded_512); for (i = 0; i < inblocks * SPX_N; i++) { buf[SPX_N + SPX_SHA256_ADDR_BYTES + i] = in[i] ^ bitmask[i]; } - sha512_inc_finalize(outbuf, sha2_state, buf + SPX_N, + sha512_inc_finalize(outbuf, &sha2_state, buf + SPX_N, SPX_SHA256_ADDR_BYTES + inblocks*SPX_N); memcpy(out, outbuf, SPX_N); } diff --git a/ref/thash_sha2_simple.c b/ref/thash_sha2_simple.c index da588964..cb5c3ee1 100644 --- a/ref/thash_sha2_simple.c +++ b/ref/thash_sha2_simple.c @@ -6,6 +6,7 @@ #include "params.h" #include "utils.h" #include "sha2.h" +#include "hash.h" #if SPX_SHA512 static void thash_512(unsigned char *out, const unsigned char *in, unsigned int inblocks, @@ -26,16 +27,16 @@ void thash(unsigned char *out, const unsigned char *in, unsigned int inblocks, #endif unsigned char outbuf[SPX_SHA256_OUTPUT_BYTES]; - uint8_t sha2_state[40]; + sha256ctx sha2_state; SPX_VLA(uint8_t, buf, SPX_SHA256_ADDR_BYTES + inblocks*SPX_N); /* Retrieve precomputed state containing pub_seed */ - memcpy(sha2_state, ctx->state_seeded, 40 * sizeof(uint8_t)); + sha256_inc_ctx_clone(&sha2_state, &ctx->state_seeded); memcpy(buf, addr, SPX_SHA256_ADDR_BYTES); memcpy(buf + SPX_SHA256_ADDR_BYTES, in, inblocks * SPX_N); - sha256_inc_finalize(outbuf, sha2_state, buf, SPX_SHA256_ADDR_BYTES + inblocks*SPX_N); + sha256_inc_finalize(outbuf, &sha2_state, buf, SPX_SHA256_ADDR_BYTES + inblocks*SPX_N); memcpy(out, outbuf, SPX_N); } @@ -44,16 +45,16 @@ static void thash_512(unsigned char *out, const unsigned char *in, unsigned int const spx_ctx *ctx, uint32_t addr[8]) { unsigned char outbuf[SPX_SHA512_OUTPUT_BYTES]; - uint8_t sha2_state[72]; + sha512ctx sha2_state; SPX_VLA(uint8_t, buf, SPX_SHA256_ADDR_BYTES + inblocks*SPX_N); /* Retrieve precomputed state containing pub_seed */ - memcpy(sha2_state, ctx->state_seeded_512, 72 * sizeof(uint8_t)); + sha512_inc_ctx_clone(&sha2_state, &ctx->state_seeded_512); memcpy(buf, addr, SPX_SHA256_ADDR_BYTES); memcpy(buf + SPX_SHA256_ADDR_BYTES, in, inblocks * SPX_N); - sha512_inc_finalize(outbuf, sha2_state, buf, SPX_SHA256_ADDR_BYTES + inblocks*SPX_N); + sha512_inc_finalize(outbuf, &sha2_state, buf, SPX_SHA256_ADDR_BYTES + inblocks*SPX_N); memcpy(out, outbuf, SPX_N); } #endif From 42cab3c151c988eb9b21e2ffd8be733bc1068e6d Mon Sep 17 00:00:00 2001 From: Thom Wiggers Date: Mon, 29 Aug 2022 13:38:32 +0200 Subject: [PATCH 2/8] Refactor FIPS202 API * Uses opaque incremental hashing context Allows easier replacement of hashing primitives by different backing implementations. * Adds context release functions Allows heap-backed FIPS202 implementations. fips202.[ch] from PQClean --- ref/fips202.c | 195 ++++++++++++++++++----------------------------- ref/fips202.h | 112 ++++++++++++++++++++------- ref/hash_shake.c | 30 ++++---- 3 files changed, 175 insertions(+), 162 deletions(-) diff --git a/ref/fips202.c b/ref/fips202.c index ceeb6a5c..020a9b13 100644 --- a/ref/fips202.c +++ b/ref/fips202.c @@ -7,6 +7,7 @@ #include #include +#include #include "fips202.h" @@ -441,7 +442,7 @@ static void keccak_inc_absorb(uint64_t *s_inc, uint32_t r, const uint8_t *m, /* Recall that s_inc[25] is the non-absorbed bytes xored into the state */ while (mlen + s_inc[25] >= r) { - for (i = 0; i < r - s_inc[25]; i++) { + for (i = 0; i < r - (uint32_t)s_inc[25]; i++) { /* Take the i'th byte from message xor with the s_inc[25] + i'th byte of the state; little-endian */ s_inc[(s_inc[25] + i) >> 3] ^= (uint64_t)m[i] << (8 * ((s_inc[25] + i) & 0x07)); @@ -520,36 +521,52 @@ static void keccak_inc_squeeze(uint8_t *h, size_t outlen, } } -void shake128_inc_init(uint64_t *s_inc) { - keccak_inc_init(s_inc); +void shake128_inc_init(shake128incctx *state) { + keccak_inc_init(state->ctx); } -void shake128_inc_absorb(uint64_t *s_inc, const uint8_t *input, size_t inlen) { - keccak_inc_absorb(s_inc, SHAKE128_RATE, input, inlen); +void shake128_inc_absorb(shake128incctx *state, const uint8_t *input, size_t inlen) { + keccak_inc_absorb(state->ctx, SHAKE128_RATE, input, inlen); } -void shake128_inc_finalize(uint64_t *s_inc) { - keccak_inc_finalize(s_inc, SHAKE128_RATE, 0x1F); +void shake128_inc_finalize(shake128incctx *state) { + keccak_inc_finalize(state->ctx, SHAKE128_RATE, 0x1F); } -void shake128_inc_squeeze(uint8_t *output, size_t outlen, uint64_t *s_inc) { - keccak_inc_squeeze(output, outlen, s_inc, SHAKE128_RATE); +void shake128_inc_squeeze(uint8_t *output, size_t outlen, shake128incctx *state) { + keccak_inc_squeeze(output, outlen, state->ctx, SHAKE128_RATE); } -void shake256_inc_init(uint64_t *s_inc) { - keccak_inc_init(s_inc); +void shake128_inc_ctx_clone(shake128incctx *dest, const shake128incctx *src) { + memcpy(dest->ctx, src->ctx, SPX_SHAKEINCCTX_BYTES); } -void shake256_inc_absorb(uint64_t *s_inc, const uint8_t *input, size_t inlen) { - keccak_inc_absorb(s_inc, SHAKE256_RATE, input, inlen); +void shake128_inc_ctx_release(shake128incctx *state) { + (void)state; // avoid unused variable warnings } -void shake256_inc_finalize(uint64_t *s_inc) { - keccak_inc_finalize(s_inc, SHAKE256_RATE, 0x1F); +void shake256_inc_init(shake256incctx *state) { + keccak_inc_init(state->ctx); } -void shake256_inc_squeeze(uint8_t *output, size_t outlen, uint64_t *s_inc) { - keccak_inc_squeeze(output, outlen, s_inc, SHAKE256_RATE); +void shake256_inc_absorb(shake256incctx *state, const uint8_t *input, size_t inlen) { + keccak_inc_absorb(state->ctx, SHAKE256_RATE, input, inlen); +} + +void shake256_inc_finalize(shake256incctx *state) { + keccak_inc_finalize(state->ctx, SHAKE256_RATE, 0x1F); +} + +void shake256_inc_squeeze(uint8_t *output, size_t outlen, shake256incctx *state) { + keccak_inc_squeeze(output, outlen, state->ctx, SHAKE256_RATE); +} + +void shake256_inc_ctx_clone(shake256incctx *dest, const shake256incctx *src) { + memcpy(dest->ctx, src->ctx, SPX_SHAKEINCCTX_BYTES); +} + +void shake256_inc_ctx_release(shake256incctx *state) { + (void)state; // avoid unused variable warnings } @@ -564,8 +581,8 @@ void shake256_inc_squeeze(uint8_t *output, size_t outlen, uint64_t *s_inc) { * into s * - size_t inlen: length of input in bytes **************************************************/ -void shake128_absorb(uint64_t *s, const uint8_t *input, size_t inlen) { - keccak_absorb(s, SHAKE128_RATE, input, inlen, 0x1F); +void shake128_absorb(shake128ctx *state, const uint8_t *input, size_t inlen) { + keccak_absorb(state->ctx, SHAKE128_RATE, input, inlen, 0x1F); } /************************************************* @@ -578,10 +595,19 @@ void shake128_absorb(uint64_t *s, const uint8_t *input, size_t inlen) { * Arguments: - uint8_t *output: pointer to output blocks * - size_t nblocks: number of blocks to be squeezed * (written to output) - * - uint64_t *s: pointer to input/output Keccak state + * - shake128ctx *state: pointer to input/output Keccak state **************************************************/ -void shake128_squeezeblocks(uint8_t *output, size_t nblocks, uint64_t *s) { - keccak_squeezeblocks(output, nblocks, s, SHAKE128_RATE); +void shake128_squeezeblocks(uint8_t *output, size_t nblocks, shake128ctx *state) { + keccak_squeezeblocks(output, nblocks, state->ctx, SHAKE128_RATE); +} + +void shake128_ctx_clone(shake128ctx *dest, const shake128ctx *src) { + memcpy(dest->ctx, src->ctx, SPX_SHAKECTX_BYTES); +} + +/** Release the allocated state. Call only once. */ +void shake128_ctx_release(shake128ctx *state) { + (void)state; // avoid unused variable warnings } /************************************************* @@ -590,13 +616,13 @@ void shake128_squeezeblocks(uint8_t *output, size_t nblocks, uint64_t *s) { * Description: Absorb step of the SHAKE256 XOF. * non-incremental, starts by zeroeing the state. * - * Arguments: - uint64_t *s: pointer to (uninitialized) output Keccak state + * Arguments: - shake256ctx *state: pointer to (uninitialized) output Keccak state * - const uint8_t *input: pointer to input to be absorbed * into s * - size_t inlen: length of input in bytes **************************************************/ -void shake256_absorb(uint64_t *s, const uint8_t *input, size_t inlen) { - keccak_absorb(s, SHAKE256_RATE, input, inlen, 0x1F); +void shake256_absorb(shake256ctx *state, const uint8_t *input, size_t inlen) { + keccak_absorb(state->ctx, SHAKE256_RATE, input, inlen, 0x1F); } /************************************************* @@ -609,10 +635,19 @@ void shake256_absorb(uint64_t *s, const uint8_t *input, size_t inlen) { * Arguments: - uint8_t *output: pointer to output blocks * - size_t nblocks: number of blocks to be squeezed * (written to output) - * - uint64_t *s: pointer to input/output Keccak state + * - shake256ctx *state: pointer to input/output Keccak state **************************************************/ -void shake256_squeezeblocks(uint8_t *output, size_t nblocks, uint64_t *s) { - keccak_squeezeblocks(output, nblocks, s, SHAKE256_RATE); +void shake256_squeezeblocks(uint8_t *output, size_t nblocks, shake256ctx *state) { + keccak_squeezeblocks(output, nblocks, state->ctx, SHAKE256_RATE); +} + +void shake256_ctx_clone(shake256ctx *dest, const shake256ctx *src) { + memcpy(dest->ctx, src->ctx, SPX_SHAKECTX_BYTES); +} + +/** Release the allocated state. Call only once. */ +void shake256_ctx_release(shake256ctx *state) { + (void)state; // avoid unused variable warnings } /************************************************* @@ -629,20 +664,21 @@ void shake128(uint8_t *output, size_t outlen, const uint8_t *input, size_t inlen) { size_t nblocks = outlen / SHAKE128_RATE; uint8_t t[SHAKE128_RATE]; - uint64_t s[25]; + shake128ctx s; - shake128_absorb(s, input, inlen); - shake128_squeezeblocks(output, nblocks, s); + shake128_absorb(&s, input, inlen); + shake128_squeezeblocks(output, nblocks, &s); output += nblocks * SHAKE128_RATE; outlen -= nblocks * SHAKE128_RATE; if (outlen) { - shake128_squeezeblocks(t, 1, s); + shake128_squeezeblocks(t, 1, &s); for (size_t i = 0; i < outlen; ++i) { output[i] = t[i]; } } + shake128_ctx_release(&s); } /************************************************* @@ -659,104 +695,19 @@ void shake256(uint8_t *output, size_t outlen, const uint8_t *input, size_t inlen) { size_t nblocks = outlen / SHAKE256_RATE; uint8_t t[SHAKE256_RATE]; - uint64_t s[25]; + shake256ctx s; - shake256_absorb(s, input, inlen); - shake256_squeezeblocks(output, nblocks, s); + shake256_absorb(&s, input, inlen); + shake256_squeezeblocks(output, nblocks, &s); output += nblocks * SHAKE256_RATE; outlen -= nblocks * SHAKE256_RATE; if (outlen) { - shake256_squeezeblocks(t, 1, s); + shake256_squeezeblocks(t, 1, &s); for (size_t i = 0; i < outlen; ++i) { output[i] = t[i]; } } -} - -void sha3_256_inc_init(uint64_t *s_inc) { - keccak_inc_init(s_inc); -} - -void sha3_256_inc_absorb(uint64_t *s_inc, const uint8_t *input, size_t inlen) { - keccak_inc_absorb(s_inc, SHA3_256_RATE, input, inlen); -} - -void sha3_256_inc_finalize(uint8_t *output, uint64_t *s_inc) { - uint8_t t[SHA3_256_RATE]; - keccak_inc_finalize(s_inc, SHA3_256_RATE, 0x06); - - keccak_squeezeblocks(t, 1, s_inc, SHA3_256_RATE); - - for (size_t i = 0; i < 32; i++) { - output[i] = t[i]; - } -} - -/************************************************* - * Name: sha3_256 - * - * Description: SHA3-256 with non-incremental API - * - * Arguments: - uint8_t *output: pointer to output - * - const uint8_t *input: pointer to input - * - size_t inlen: length of input in bytes - **************************************************/ -void sha3_256(uint8_t *output, const uint8_t *input, size_t inlen) { - uint64_t s[25]; - uint8_t t[SHA3_256_RATE]; - - /* Absorb input */ - keccak_absorb(s, SHA3_256_RATE, input, inlen, 0x06); - - /* Squeeze output */ - keccak_squeezeblocks(t, 1, s, SHA3_256_RATE); - - for (size_t i = 0; i < 32; i++) { - output[i] = t[i]; - } -} - -void sha3_512_inc_init(uint64_t *s_inc) { - keccak_inc_init(s_inc); -} - -void sha3_512_inc_absorb(uint64_t *s_inc, const uint8_t *input, size_t inlen) { - keccak_inc_absorb(s_inc, SHA3_512_RATE, input, inlen); -} - -void sha3_512_inc_finalize(uint8_t *output, uint64_t *s_inc) { - uint8_t t[SHA3_512_RATE]; - keccak_inc_finalize(s_inc, SHA3_512_RATE, 0x06); - - keccak_squeezeblocks(t, 1, s_inc, SHA3_512_RATE); - - for (size_t i = 0; i < 32; i++) { - output[i] = t[i]; - } -} - -/************************************************* - * Name: sha3_512 - * - * Description: SHA3-512 with non-incremental API - * - * Arguments: - uint8_t *output: pointer to output - * - const uint8_t *input: pointer to input - * - size_t inlen: length of input in bytes - **************************************************/ -void sha3_512(uint8_t *output, const uint8_t *input, size_t inlen) { - uint64_t s[25]; - uint8_t t[SHA3_512_RATE]; - - /* Absorb input */ - keccak_absorb(s, SHA3_512_RATE, input, inlen, 0x06); - - /* Squeeze output */ - keccak_squeezeblocks(t, 1, s, SHA3_512_RATE); - - for (size_t i = 0; i < 64; i++) { - output[i] = t[i]; - } + shake256_ctx_release(&s); } diff --git a/ref/fips202.h b/ref/fips202.h index e11cb7f3..1180e4e4 100644 --- a/ref/fips202.h +++ b/ref/fips202.h @@ -6,42 +6,102 @@ #define SHAKE128_RATE 168 #define SHAKE256_RATE 136 -#define SHA3_256_RATE 136 -#define SHA3_512_RATE 72 -void shake128_absorb(uint64_t *s, const uint8_t *input, size_t inlen); +#define SPX_SHAKEINCCTX_BYTES (sizeof(uint64_t)*26) +#define SPX_SHAKECTX_BYTES (sizeof(uint64_t)*25) -void shake128_squeezeblocks(uint8_t *output, size_t nblocks, uint64_t *s); +// Context for incremental API +typedef struct { + uint64_t ctx[SPX_SHAKEINCCTX_BYTES]; +} shake128incctx; -void shake128_inc_init(uint64_t *s_inc); -void shake128_inc_absorb(uint64_t *s_inc, const uint8_t *input, size_t inlen); -void shake128_inc_finalize(uint64_t *s_inc); -void shake128_inc_squeeze(uint8_t *output, size_t outlen, uint64_t *s_inc); +// Context for non-incremental API +typedef struct { + uint64_t ctx[SPX_SHAKECTX_BYTES]; +} shake128ctx; -void shake256_absorb(uint64_t *s, const uint8_t *input, size_t inlen); -void shake256_squeezeblocks(uint8_t *output, size_t nblocks, uint64_t *s); +// Context for incremental API +typedef struct { + uint64_t ctx[SPX_SHAKEINCCTX_BYTES]; +} shake256incctx; -void shake256_inc_init(uint64_t *s_inc); -void shake256_inc_absorb(uint64_t *s_inc, const uint8_t *input, size_t inlen); -void shake256_inc_finalize(uint64_t *s_inc); -void shake256_inc_squeeze(uint8_t *output, size_t outlen, uint64_t *s_inc); +// Context for non-incremental API +typedef struct { + uint64_t ctx[SPX_SHAKECTX_BYTES]; +} shake256ctx; -void shake128(uint8_t *output, size_t outlen, - const uint8_t *input, size_t inlen); +/* Initialize the state and absorb the provided input. + * + * This function does not support being called multiple times + * with the same state. + */ +void shake128_absorb(shake128ctx *state, const uint8_t *input, size_t inlen); +/* Squeeze output out of the sponge. + * + * Supports being called multiple times + */ +void shake128_squeezeblocks(uint8_t *output, size_t nblocks, shake128ctx *state); +/* Free the state */ +void shake128_ctx_release(shake128ctx *state); +/* Copy the state. */ +void shake128_ctx_clone(shake128ctx *dest, const shake128ctx *src); -void shake256(uint8_t *output, size_t outlen, - const uint8_t *input, size_t inlen); +/* Initialize incremental hashing API */ +void shake128_inc_init(shake128incctx *state); +/* Absorb more information into the XOF. + * + * Can be called multiple times. + */ +void shake128_inc_absorb(shake128incctx *state, const uint8_t *input, size_t inlen); +/* Finalize the XOF for squeezing */ +void shake128_inc_finalize(shake128incctx *state); +/* Squeeze output out of the sponge. + * + * Supports being called multiple times + */ +void shake128_inc_squeeze(uint8_t *output, size_t outlen, shake128incctx *state); +/* Copy the context of the SHAKE128 XOF */ +void shake128_inc_ctx_clone(shake128incctx* dest, const shake128incctx *src); +/* Free the context of the SHAKE128 XOF */ +void shake128_inc_ctx_release(shake128incctx *state); -void sha3_256_inc_init(uint64_t *s_inc); -void sha3_256_inc_absorb(uint64_t *s_inc, const uint8_t *input, size_t inlen); -void sha3_256_inc_finalize(uint8_t *output, uint64_t *s_inc); +/* Initialize the state and absorb the provided input. + * + * This function does not support being called multiple times + * with the same state. + */ +void shake256_absorb(shake256ctx *state, const uint8_t *input, size_t inlen); +/* Squeeze output out of the sponge. + * + * Supports being called multiple times + */ +void shake256_squeezeblocks(uint8_t *output, size_t nblocks, shake256ctx *state); +/* Free the context held by this XOF */ +void shake256_ctx_release(shake256ctx *state); +/* Copy the context held by this XOF */ +void shake256_ctx_clone(shake256ctx *dest, const shake256ctx *src); -void sha3_256(uint8_t *output, const uint8_t *input, size_t inlen); +/* Initialize incremental hashing API */ +void shake256_inc_init(shake256incctx *state); +void shake256_inc_absorb(shake256incctx *state, const uint8_t *input, size_t inlen); +/* Prepares for squeeze phase */ +void shake256_inc_finalize(shake256incctx *state); +/* Squeeze output out of the sponge. + * + * Supports being called multiple times + */ +void shake256_inc_squeeze(uint8_t *output, size_t outlen, shake256incctx *state); +/* Copy the state */ +void shake256_inc_ctx_clone(shake256incctx* dest, const shake256incctx *src); +/* Free the state */ +void shake256_inc_ctx_release(shake256incctx *state); -void sha3_512_inc_init(uint64_t *s_inc); -void sha3_512_inc_absorb(uint64_t *s_inc, const uint8_t *input, size_t inlen); -void sha3_512_inc_finalize(uint8_t *output, uint64_t *s_inc); +/* One-stop SHAKE128 call */ +void shake128(uint8_t *output, size_t outlen, + const uint8_t *input, size_t inlen); -void sha3_512(uint8_t *output, const uint8_t *input, size_t inlen); +/* One-stop SHAKE256 call */ +void shake256(uint8_t *output, size_t outlen, + const uint8_t *input, size_t inlen); #endif diff --git a/ref/hash_shake.c b/ref/hash_shake.c index 4f4a160a..6d88904c 100644 --- a/ref/hash_shake.c +++ b/ref/hash_shake.c @@ -44,14 +44,15 @@ void gen_message_random(unsigned char *R, const unsigned char *sk_prf, const spx_ctx *ctx) { (void)ctx; - uint64_t s_inc[26]; + shake256incctx s_inc; - shake256_inc_init(s_inc); - shake256_inc_absorb(s_inc, sk_prf, SPX_N); - shake256_inc_absorb(s_inc, optrand, SPX_N); - shake256_inc_absorb(s_inc, m, mlen); - shake256_inc_finalize(s_inc); - shake256_inc_squeeze(R, SPX_N, s_inc); + shake256_inc_init(&s_inc); + shake256_inc_absorb(&s_inc, sk_prf, SPX_N); + shake256_inc_absorb(&s_inc, optrand, SPX_N); + shake256_inc_absorb(&s_inc, m, mlen); + shake256_inc_finalize(&s_inc); + shake256_inc_squeeze(R, SPX_N, &s_inc); + shake256_inc_ctx_release(&s_inc); } /** @@ -73,14 +74,15 @@ void hash_message(unsigned char *digest, uint64_t *tree, uint32_t *leaf_idx, unsigned char buf[SPX_DGST_BYTES]; unsigned char *bufp = buf; - uint64_t s_inc[26]; + shake256incctx s_inc; - shake256_inc_init(s_inc); - shake256_inc_absorb(s_inc, R, SPX_N); - shake256_inc_absorb(s_inc, pk, SPX_PK_BYTES); - shake256_inc_absorb(s_inc, m, mlen); - shake256_inc_finalize(s_inc); - shake256_inc_squeeze(buf, SPX_DGST_BYTES, s_inc); + shake256_inc_init(&s_inc); + shake256_inc_absorb(&s_inc, R, SPX_N); + shake256_inc_absorb(&s_inc, pk, SPX_PK_BYTES); + shake256_inc_absorb(&s_inc, m, mlen); + shake256_inc_finalize(&s_inc); + shake256_inc_squeeze(buf, SPX_DGST_BYTES, &s_inc); + shake256_inc_ctx_release(&s_inc); memcpy(digest, bufp, SPX_FORS_MSG_BYTES); bufp += SPX_FORS_MSG_BYTES; From 636e2b5f6809d63182f451c1dfc972238e9995b6 Mon Sep 17 00:00:00 2001 From: Thom Wiggers Date: Mon, 29 Aug 2022 15:10:33 +0200 Subject: [PATCH 3/8] Refactor out context initialization from hash_{hash}.c --- ref/Makefile | 8 ++++---- ref/context.h | 9 ++++++++- ref/context_haraka.c | 12 ++++++++++++ ref/context_sha2.c | 42 ++++++++++++++++++++++++++++++++++++++++ ref/context_shake.c | 13 +++++++++++++ ref/hash.h | 9 --------- ref/hash_haraka.c | 10 ---------- ref/hash_sha2.c | 43 ----------------------------------------- ref/hash_shake.c | 12 ------------ ref/thash_sha2_robust.c | 4 +++- 10 files changed, 82 insertions(+), 80 deletions(-) create mode 100644 ref/context_haraka.c create mode 100644 ref/context_sha2.c create mode 100644 ref/context_shake.c diff --git a/ref/Makefile b/ref/Makefile index a3aabad2..d5770acc 100644 --- a/ref/Makefile +++ b/ref/Makefile @@ -5,18 +5,18 @@ CC=/usr/bin/gcc CFLAGS=-Wall -Wextra -Wpedantic -O3 -std=c99 -Wconversion -Wmissing-prototypes -DPARAMS=$(PARAMS) $(EXTRA_CFLAGS) SOURCES = address.c randombytes.c merkle.c wots.c wotsx1.c utils.c utilsx1.c fors.c sign.c -HEADERS = params.h address.h randombytes.h merkle.h wots.h wotsx1.h utils.h utilsx1.h fors.h api.h hash.h thash.h +HEADERS = params.h address.h randombytes.h merkle.h wots.h wotsx1.h utils.h utilsx1.h fors.h api.h hash.h thash.h context.h ifneq (,$(findstring shake,$(PARAMS))) - SOURCES += fips202.c hash_shake.c thash_shake_$(THASH).c + SOURCES += fips202.c hash_shake.c thash_shake_$(THASH).c context_shake.c HEADERS += fips202.h endif ifneq (,$(findstring haraka,$(PARAMS))) - SOURCES += haraka.c hash_haraka.c thash_haraka_$(THASH).c + SOURCES += haraka.c hash_haraka.c thash_haraka_$(THASH).c context_haraka.c HEADERS += haraka.h endif ifneq (,$(findstring sha2,$(PARAMS))) - SOURCES += sha2.c hash_sha2.c thash_sha2_$(THASH).c + SOURCES += sha2.c hash_sha2.c thash_sha2_$(THASH).c context_sha2.c HEADERS += sha2.h endif diff --git a/ref/context.h b/ref/context.h index 8471900e..5454c69f 100644 --- a/ref/context.h +++ b/ref/context.h @@ -2,6 +2,7 @@ #define SPX_CONTEXT_H #include +#include #include "params.h" #ifdef SPX_SHA2 @@ -18,7 +19,7 @@ typedef struct { # if SPX_SHA512 // sha512 state that absorbed pub_seed - sha512ctx state_seeded_512[72]; + sha512ctx state_seeded_512; # endif #endif @@ -28,4 +29,10 @@ typedef struct { #endif } spx_ctx; +#define initialize_hash_function SPX_NAMESPACE(initialize_hash_function) +void initialize_hash_function(spx_ctx *ctx); + +#define free_hash_function SPX_NAMESPACE(free_hash_function) +void free_hash_function(spx_ctx *ctx); + #endif diff --git a/ref/context_haraka.c b/ref/context_haraka.c new file mode 100644 index 00000000..ca6a7daa --- /dev/null +++ b/ref/context_haraka.c @@ -0,0 +1,12 @@ +#include "context.h" +#include "haraka.h" + +void initialize_hash_function(spx_ctx* ctx) +{ + tweak_constants(ctx); +} + +// we don't support heap-based haraka right now +void free_hash_function(spx_ctx *ctx) { + (void)ctx; // suppress unused variable warnings +} diff --git a/ref/context_sha2.c b/ref/context_sha2.c new file mode 100644 index 00000000..0ee5bebd --- /dev/null +++ b/ref/context_sha2.c @@ -0,0 +1,42 @@ +#include "context.h" + +/** + * Absorb the constant pub_seed using one round of the compression function + * This initializes state_seeded and state_seeded_512, which can then be + * reused in thash + **/ +static void seed_state(spx_ctx *ctx) { + uint8_t block[SPX_SHA512_BLOCK_BYTES]; + size_t i; + + for (i = 0; i < SPX_N; ++i) { + block[i] = ctx->pub_seed[i]; + } + for (i = SPX_N; i < SPX_SHA512_BLOCK_BYTES; ++i) { + block[i] = 0; + } + /* block has been properly initialized for both SHA-256 and SHA-512 */ + + sha256_inc_init(&ctx->state_seeded); + sha256_inc_blocks(&ctx->state_seeded, block, 1); +#if SPX_SHA512 + sha512_inc_init(&ctx->state_seeded_512); + sha512_inc_blocks(&ctx->state_seeded_512, block, 1); +#endif +} + + +/* We initialize the state for the hash functions */ +void initialize_hash_function(spx_ctx *ctx) +{ + seed_state(ctx); +} + +/* Free the incremental hashing context for heap-based SHA2 APIs */ +void free_hash_function(spx_ctx *ctx) +{ + sha256_inc_ctx_release(&ctx->state_seeded); +#if SPX_SHA512 + sha512_inc_ctx_release(&ctx->state_seeded_512); +#endif +} diff --git a/ref/context_shake.c b/ref/context_shake.c new file mode 100644 index 00000000..d1ddd7f5 --- /dev/null +++ b/ref/context_shake.c @@ -0,0 +1,13 @@ +#include "context.h" + +/* For SHAKE256, there is no immediate reason to initialize at the start, + so this function is an empty operation. */ +void initialize_hash_function(spx_ctx *ctx) +{ + (void)ctx; /* Suppress an 'unused parameter' warning. */ +} + +// in case the hash function api is heap-based. +void free_hash_function(spx_ctx *ctx) { + (void)ctx; +} diff --git a/ref/hash.h b/ref/hash.h index 00ea7ecc..e5371331 100644 --- a/ref/hash.h +++ b/ref/hash.h @@ -5,12 +5,6 @@ #include "context.h" #include "params.h" -#define initialize_hash_function SPX_NAMESPACE(initialize_hash_function) -void initialize_hash_function(spx_ctx *ctx); - -#define free_hash_function SPX_NAMESPACE(free_hash_function) -void free_hash_function(spx_ctx *ctx); - #define prf_addr SPX_NAMESPACE(prf_addr) void prf_addr(unsigned char *out, const spx_ctx *ctx, const uint32_t addr[8]); @@ -38,9 +32,6 @@ void hash_message(unsigned char *digest, uint64_t *tree, uint32_t *leaf_idx, # define mgf1_512 SPX_NAMESPACE(mgf1_512) void mgf1_512(unsigned char *out, unsigned long outlen, const unsigned char *in, unsigned long inlen); - -# define seed_state SPX_NAMESPACE(seed_state) - void seed_state(spx_ctx *ctx); #endif #endif diff --git a/ref/hash_haraka.c b/ref/hash_haraka.c index d65d83fb..7e766a30 100644 --- a/ref/hash_haraka.c +++ b/ref/hash_haraka.c @@ -8,16 +8,6 @@ #include "haraka.h" #include "hash.h" -void initialize_hash_function(spx_ctx* ctx) -{ - tweak_constants(ctx); -} - -// we don't support heap-based haraka right now -void free_hash_function(spx_ctx *ctx) { - (void)ctx; // suppress unused variable warnings -} - /* * Computes PRF(key, addr), given a secret key of SPX_N bytes and an address */ diff --git a/ref/hash_sha2.c b/ref/hash_sha2.c index 30b3ef6b..dab31fcf 100644 --- a/ref/hash_sha2.c +++ b/ref/hash_sha2.c @@ -32,49 +32,6 @@ #define shaXstate sha256ctx #endif -/** - * Absorb the constant pub_seed using one round of the compression function - * This initializes state_seeded and state_seeded_512, which can then be - * reused in thash - **/ -void seed_state(spx_ctx *ctx) { - uint8_t block[SPX_SHA512_BLOCK_BYTES]; - size_t i; - - for (i = 0; i < SPX_N; ++i) { - block[i] = ctx->pub_seed[i]; - } - for (i = SPX_N; i < SPX_SHA512_BLOCK_BYTES; ++i) { - block[i] = 0; - } - /* block has been properly initialized for both SHA-256 and SHA-512 */ - - sha256_inc_init(&ctx->state_seeded); - sha256_inc_blocks(&ctx->state_seeded, block, 1); -#if SPX_SHA512 - sha512_inc_init(&ctx->state_seeded_512); - sha512_inc_blocks(&ctx->state_seeded_512, block, 1); -#endif -} - - -/* For SHA, there is no immediate reason to initialize at the start, - so this function is an empty operation. */ -void initialize_hash_function(spx_ctx *ctx) -{ - seed_state(ctx); -} - -/* Free the incremental hashing context for heap-based SHA2 APIs */ -void free_hash_function(spx_ctx *ctx) -{ - sha256_inc_ctx_release(&ctx->state_seeded); -#if SPX_SHA512 - sha512_inc_ctx_release(&ctx->state_seeded_512); -#endif -} - - /** * mgf1 function based on the SHA-256 hash function * Note that inlen should be sufficiently small that it still allows for diff --git a/ref/hash_shake.c b/ref/hash_shake.c index 6d88904c..6f548db3 100644 --- a/ref/hash_shake.c +++ b/ref/hash_shake.c @@ -7,18 +7,6 @@ #include "hash.h" #include "fips202.h" -/* For SHAKE256, there is no immediate reason to initialize at the start, - so this function is an empty operation. */ -void initialize_hash_function(spx_ctx *ctx) -{ - (void)ctx; /* Suppress an 'unused parameter' warning. */ -} - -// in case the hash function api is heap-based. -void free_hash_function(spx_ctx *ctx) { - (void)ctx; -} - /* * Computes PRF(pk_seed, sk_seed, addr) */ diff --git a/ref/thash_sha2_robust.c b/ref/thash_sha2_robust.c index 551b88c0..6991647d 100644 --- a/ref/thash_sha2_robust.c +++ b/ref/thash_sha2_robust.c @@ -1,6 +1,8 @@ #include #include +#include "context.h" +#include "hash.h" #include "thash.h" #include "address.h" #include "params.h" @@ -35,7 +37,7 @@ void thash(unsigned char *out, const unsigned char *in, unsigned int inblocks, mgf1_256(bitmask, inblocks * SPX_N, buf, SPX_N + SPX_SHA256_ADDR_BYTES); /* Retrieve precomputed state containing pub_seed */ - sha256_inc_ctx_clone(&sha2_state, ctx->state_seeded); + sha256_inc_ctx_clone(&sha2_state, &ctx->state_seeded); for (i = 0; i < inblocks * SPX_N; i++) { buf[SPX_N + SPX_SHA256_ADDR_BYTES + i] = in[i] ^ bitmask[i]; From 357af50505452b29ad869442b396b548844352de Mon Sep 17 00:00:00 2001 From: Thom Wiggers Date: Thu, 24 Nov 2022 16:13:25 +0100 Subject: [PATCH 4/8] Change hashing API in sha2-avx2 implementation --- sha2-avx2/Makefile | 4 +- sha2-avx2/context.h | 16 +++++- sha2-avx2/context_sha2.c | 77 +++++++++++++++++++++++++++++ sha2-avx2/hash_sha2x8.c | 3 +- sha2-avx2/sha256avx.c | 88 ++++++++++++++++++++++++++++----- sha2-avx2/sha256avx.h | 76 +++------------------------- sha2-avx2/sha256x8.c | 24 ++------- sha2-avx2/sha256x8.h | 4 +- sha2-avx2/sha512x4.c | 74 +++++++++++++-------------- sha2-avx2/sha512x4.h | 6 +-- sha2-avx2/thash_sha2_robustx8.c | 9 ++-- sha2-avx2/thash_sha2_simplex8.c | 9 ++-- 12 files changed, 230 insertions(+), 160 deletions(-) create mode 100644 sha2-avx2/context_sha2.c diff --git a/sha2-avx2/Makefile b/sha2-avx2/Makefile index f708543c..48fa8d6f 100644 --- a/sha2-avx2/Makefile +++ b/sha2-avx2/Makefile @@ -5,8 +5,8 @@ CC = /usr/bin/gcc CFLAGS = -Wall -Wextra -Wpedantic -Wmissing-prototypes -O3 -std=c99 -march=native -flto -fomit-frame-pointer -DPARAMS=$(PARAMS) $(EXTRA_CFLAGS) -SOURCES = hash_sha2.c hash_sha2x8.c thash_sha2_$(THASH).c thash_sha2_$(THASH)x8.c sha2.c sha256x8.c sha512x4.c sha256avx.c address.c randombytes.c merkle.c wots.c utils.c utilsx8.c fors.c sign.c -HEADERS = params.h hash.h hashx8.h thash.h thashx8.h sha2.h sha256x8.h sha512x4.h sha256avx.h address.h randombytes.h merkle.h wots.h utils.h utilsx8.h fors.h api.h +SOURCES = hash_sha2.c hash_sha2x8.c thash_sha2_$(THASH).c thash_sha2_$(THASH)x8.c sha2.c sha256x8.c sha512x4.c sha256avx.c address.c randombytes.c merkle.c wots.c utils.c utilsx8.c fors.c sign.c context_sha2.c +HEADERS = params.h hash.h hashx8.h thash.h thashx8.h sha2.h sha256x8.h sha512x4.h sha256avx.h address.h randombytes.h merkle.h wots.h utils.h utilsx8.h fors.h api.h context.h DET_SOURCES = $(SOURCES:randombytes.%=rng.%) DET_HEADERS = $(HEADERS:randombytes.%=rng.%) diff --git a/sha2-avx2/context.h b/sha2-avx2/context.h index 05ffbe85..d3e126b1 100644 --- a/sha2-avx2/context.h +++ b/sha2-avx2/context.h @@ -4,15 +4,27 @@ #include #include "params.h" +#include "sha2.h" +#include "sha256avx.h" +#include "sha512x4.h" typedef struct { uint8_t pub_seed[SPX_N]; uint8_t sk_seed[SPX_N]; - uint8_t state_seeded[40]; + sha256ctx state_seeded; + sha256x8ctx statex8_seeded; #if SPX_SHA512 - uint8_t state_seeded_512[72]; + sha512ctx state_seeded_512; + sha512x4ctx statex4_seeded_512; #endif } spx_ctx; + +#define initialize_hash_function SPX_NAMESPACE(initialize_hash_function) +void initialize_hash_function(spx_ctx *ctx); + +#define free_hash_function SPX_NAMESPACE(free_hash_function) +void free_hash_function(spx_ctx *ctx); + #endif diff --git a/sha2-avx2/context_sha2.c b/sha2-avx2/context_sha2.c new file mode 100644 index 00000000..d65bd749 --- /dev/null +++ b/sha2-avx2/context_sha2.c @@ -0,0 +1,77 @@ +#include + +#include "context.h" + +static uint32_t load_bigendian_32(const uint8_t *x) { + return (uint32_t)(x[3]) | (((uint32_t)(x[2])) << 8) | + (((uint32_t)(x[1])) << 16) | (((uint32_t)(x[0])) << 24); +} + +/** + * Absorb the constant pub_seed using one round of the compression function + * This initializes state_seeded and state_seeded_512, which can then be + * reused in thash + **/ +static void seed_state(spx_ctx *ctx) { + uint8_t block[SPX_SHA512_BLOCK_BYTES]; + size_t i; + + for (i = 0; i < SPX_N; ++i) { + block[i] = ctx->pub_seed[i]; + } + for (i = SPX_N; i < SPX_SHA512_BLOCK_BYTES; ++i) { + block[i] = 0; + } + /* block has been properly initialized for both SHA-256 and SHA-512 */ + + sha256_inc_init(&ctx->state_seeded); + sha256_inc_blocks(&ctx->state_seeded, block, 1); + + // this still assumes internal representation of the SHA256x1 API. + // should be replaced by proper initialization. + for (size_t i = 0; i < 8; i++) { + uint32_t t = load_bigendian_32(((uint8_t*)&ctx->state_seeded.ctx) + 4*i); + ctx->statex8_seeded.s[i] = _mm256_set_epi32(t, t, t, t, t, t, t, t); + } + + ctx->statex8_seeded.datalen = 0; + ctx->statex8_seeded.msglen = 512; + +#if SPX_SHA512 + sha512_inc_init(&ctx->state_seeded_512); + sha512_inc_blocks(&ctx->state_seeded_512, block, 1); + + // this still assumes internal representation of the SHA512x1 API. + // should be replaced by proper initialization. + uint8_t *seed = (uint8_t*)&ctx->state_seeded_512.ctx; + for (i = 0; i < 8; i++) { + uint64_t t = (uint64_t)(seed[7]) | (((uint64_t)(seed[6])) << 8) | + (((uint64_t)(seed[5])) << 16) | (((uint64_t)(seed[4])) << 24) | + (((uint64_t)(seed[3])) << 32) | (((uint64_t)(seed[2])) << 40) | + (((uint64_t)(seed[1])) << 48) | (((uint64_t)(seed[0])) << 56); + ctx->statex4_seeded_512.s[i] = _mm256_set_epi64x(t, t, t, t); + seed += 8; + } + + ctx->statex4_seeded_512.datalen = 0; + ctx->statex4_seeded_512.msglen = 1024; + + +#endif +} + + +/* For SHA, we initialize the hash function at the start */ +void initialize_hash_function(spx_ctx *ctx) +{ + seed_state(ctx); +} + +/* Free the incremental hashing context for heap-based SHA2 APIs */ +void free_hash_function(spx_ctx *ctx) +{ + sha256_inc_ctx_release(&ctx->state_seeded); +#if SPX_SHA512 + sha512_inc_ctx_release(&ctx->state_seeded_512); +#endif +} diff --git a/sha2-avx2/hash_sha2x8.c b/sha2-avx2/hash_sha2x8.c index 3f59b9ab..f0f4f887 100644 --- a/sha2-avx2/hash_sha2x8.c +++ b/sha2-avx2/hash_sha2x8.c @@ -4,6 +4,7 @@ #include "address.h" #include "utils.h" #include "params.h" +#include "hash.h" #include "hashx8.h" #include "sha2.h" #include "sha256x8.h" @@ -49,7 +50,7 @@ void prf_addrx8(unsigned char *out0, outbufx8 + 7*SPX_SHA256_OUTPUT_BYTES, /* seed */ - ctx->state_seeded, 512, + &ctx->statex8_seeded, /* in */ bufx8 + 0*(SPX_SHA256_ADDR_BYTES + SPX_N), diff --git a/sha2-avx2/sha256avx.c b/sha2-avx2/sha256avx.c index 7fc10916..3913b8d9 100644 --- a/sha2-avx2/sha256avx.c +++ b/sha2-avx2/sha256avx.c @@ -4,8 +4,68 @@ #include "sha256avx.h" +static const unsigned int RC[] = { + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, + 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, + 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, + 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, + 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, + 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, + 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, + 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, + 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 +}; + +#define u32 uint32_t +#define u256 __m256i + +#define XOR _mm256_xor_si256 +#define OR _mm256_or_si256 +#define AND _mm256_and_si256 +#define ADD32 _mm256_add_epi32 +#define NOT(x) _mm256_xor_si256(x, _mm256_set_epi32(-1, -1, -1, -1, -1, -1, -1, -1)) + +#define LOAD(src) _mm256_loadu_si256((__m256i *)(src)) +#define STORE(dest,src) _mm256_storeu_si256((__m256i *)(dest),src) + +#define BYTESWAP(x) _mm256_shuffle_epi8(x, _mm256_set_epi8(0xc,0xd,0xe,0xf,0x8,0x9,0xa,0xb,0x4,0x5,0x6,0x7,0x0,0x1,0x2,0x3,0xc,0xd,0xe,0xf,0x8,0x9,0xa,0xb,0x4,0x5,0x6,0x7,0x0,0x1,0x2,0x3)) + +#define SHIFTR32(x, y) _mm256_srli_epi32(x, y) +#define SHIFTL32(x, y) _mm256_slli_epi32(x, y) + +#define ROTR32(x, y) OR(SHIFTR32(x, y), SHIFTL32(x, 32 - y)) +#define ROTL32(x, y) OR(SHIFTL32(x, y), SHIFTR32(x, 32 - y)) + +#define XOR3(a, b, c) XOR(XOR(a, b), c) + +#define ADD3_32(a, b, c) ADD32(ADD32(a, b), c) +#define ADD4_32(a, b, c, d) ADD32(ADD32(ADD32(a, b), c), d) +#define ADD5_32(a, b, c, d, e) ADD32(ADD32(ADD32(ADD32(a, b), c), d), e) + +#define MAJ_AVX(a, b, c) XOR3(AND(a, b), AND(a, c), AND(b, c)) +#define CH_AVX(a, b, c) XOR(AND(a, b), AND(NOT(a), c)) + +#define SIGMA1_AVX(x) XOR3(ROTR32(x, 6), ROTR32(x, 11), ROTR32(x, 25)) +#define SIGMA0_AVX(x) XOR3(ROTR32(x, 2), ROTR32(x, 13), ROTR32(x, 22)) + +#define WSIGMA1_AVX(x) XOR3(ROTR32(x, 17), ROTR32(x, 19), SHIFTR32(x, 10)) +#define WSIGMA0_AVX(x) XOR3(ROTR32(x, 7), ROTR32(x, 18), SHIFTR32(x, 3)) + +#define SHA256ROUND_AVX(a, b, c, d, e, f, g, h, rc, w) \ + T0 = ADD5_32(h, SIGMA1_AVX(e), CH_AVX(e, f, g), _mm256_set1_epi32(RC[rc]), w); \ + d = ADD32(d, T0); \ + T1 = ADD32(SIGMA0_AVX(a), MAJ_AVX(a, b, c)); \ + h = ADD32(T0, T1); + // Transpose 8 vectors containing 32-bit values -void transpose(u256 s[8]) { +static void transpose(u256 s[8]) { u256 tmp0[8]; u256 tmp1[8]; tmp0[0] = _mm256_unpacklo_epi32(s[0], s[1]); @@ -31,10 +91,14 @@ void transpose(u256 s[8]) { s[4] = _mm256_permute2x128_si256(tmp1[0], tmp1[4], 0x31); s[5] = _mm256_permute2x128_si256(tmp1[1], tmp1[5], 0x31); s[6] = _mm256_permute2x128_si256(tmp1[2], tmp1[6], 0x31); - s[7] = _mm256_permute2x128_si256(tmp1[3], tmp1[7], 0x31); + s[7] = _mm256_permute2x128_si256(tmp1[3], tmp1[7], 0x31); +} + +void sha256_ctx_clone8x(sha256x8ctx *out, const sha256x8ctx *in) { + memcpy(out, in, sizeof(sha256x8ctx)); } -void sha256_init8x(sha256ctx *ctx) { +void sha256_init8x(sha256x8ctx *ctx) { ctx->s[0] = _mm256_set_epi32(0x6a09e667,0x6a09e667,0x6a09e667,0x6a09e667,0x6a09e667,0x6a09e667,0x6a09e667,0x6a09e667); ctx->s[1] = _mm256_set_epi32(0xbb67ae85,0xbb67ae85,0xbb67ae85,0xbb67ae85,0xbb67ae85,0xbb67ae85,0xbb67ae85,0xbb67ae85); ctx->s[2] = _mm256_set_epi32(0x3c6ef372,0x3c6ef372,0x3c6ef372,0x3c6ef372,0x3c6ef372,0x3c6ef372,0x3c6ef372,0x3c6ef372); @@ -43,12 +107,12 @@ void sha256_init8x(sha256ctx *ctx) { ctx->s[5] = _mm256_set_epi32(0x9b05688c,0x9b05688c,0x9b05688c,0x9b05688c,0x9b05688c,0x9b05688c,0x9b05688c,0x9b05688c); ctx->s[6] = _mm256_set_epi32(0x1f83d9ab,0x1f83d9ab,0x1f83d9ab,0x1f83d9ab,0x1f83d9ab,0x1f83d9ab,0x1f83d9ab,0x1f83d9ab); ctx->s[7] = _mm256_set_epi32(0x5be0cd19,0x5be0cd19,0x5be0cd19,0x5be0cd19,0x5be0cd19,0x5be0cd19,0x5be0cd19,0x5be0cd19); - + ctx->datalen = 0; ctx->msglen = 0; } -void sha256_final8x(sha256ctx *ctx, +void sha256_final8x(sha256x8ctx *ctx, unsigned char *out0, unsigned char *out1, unsigned char *out2, @@ -56,7 +120,7 @@ void sha256_final8x(sha256ctx *ctx, unsigned char *out4, unsigned char *out5, unsigned char *out6, - unsigned char *out7) + unsigned char *out7) { unsigned int i, curlen; @@ -127,7 +191,7 @@ void sha256_final8x(sha256ctx *ctx, STORE(out7, BYTESWAP(ctx->s[7])); } -void sha256_transform8x(sha256ctx *ctx, +void sha256_transform8x(sha256x8ctx *ctx, const unsigned char* data0, const unsigned char* data1, const unsigned char* data2, @@ -169,7 +233,7 @@ void sha256_transform8x(sha256ctx *ctx, s[6] = ctx->s[6]; s[7] = ctx->s[7]; - SHA256ROUND_AVX(s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7], 0, w[0]); + SHA256ROUND_AVX(s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7], 0, w[0]); SHA256ROUND_AVX(s[7], s[0], s[1], s[2], s[3], s[4], s[5], s[6], 1, w[1]); SHA256ROUND_AVX(s[6], s[7], s[0], s[1], s[2], s[3], s[4], s[5], 2, w[2]); SHA256ROUND_AVX(s[5], s[6], s[7], s[0], s[1], s[2], s[3], s[4], 3, w[3]); @@ -184,7 +248,7 @@ void sha256_transform8x(sha256ctx *ctx, SHA256ROUND_AVX(s[4], s[5], s[6], s[7], s[0], s[1], s[2], s[3], 12, w[12]); SHA256ROUND_AVX(s[3], s[4], s[5], s[6], s[7], s[0], s[1], s[2], 13, w[13]); SHA256ROUND_AVX(s[2], s[3], s[4], s[5], s[6], s[7], s[0], s[1], 14, w[14]); - SHA256ROUND_AVX(s[1], s[2], s[3], s[4], s[5], s[6], s[7], s[0], 15, w[15]); + SHA256ROUND_AVX(s[1], s[2], s[3], s[4], s[5], s[6], s[7], s[0], 15, w[15]); w[16] = ADD4_32(WSIGMA1_AVX(w[14]), w[0], w[9], WSIGMA0_AVX(w[1])); SHA256ROUND_AVX(s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7], 16, w[16]); w[17] = ADD4_32(WSIGMA1_AVX(w[15]), w[1], w[10], WSIGMA0_AVX(w[2])); @@ -216,7 +280,7 @@ void sha256_transform8x(sha256ctx *ctx, w[30] = ADD4_32(WSIGMA1_AVX(w[28]), w[14], w[23], WSIGMA0_AVX(w[15])); SHA256ROUND_AVX(s[2], s[3], s[4], s[5], s[6], s[7], s[0], s[1], 30, w[30]); w[31] = ADD4_32(WSIGMA1_AVX(w[29]), w[15], w[24], WSIGMA0_AVX(w[16])); - SHA256ROUND_AVX(s[1], s[2], s[3], s[4], s[5], s[6], s[7], s[0], 31, w[31]); + SHA256ROUND_AVX(s[1], s[2], s[3], s[4], s[5], s[6], s[7], s[0], 31, w[31]); w[32] = ADD4_32(WSIGMA1_AVX(w[30]), w[16], w[25], WSIGMA0_AVX(w[17])); SHA256ROUND_AVX(s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7], 32, w[32]); w[33] = ADD4_32(WSIGMA1_AVX(w[31]), w[17], w[26], WSIGMA0_AVX(w[18])); @@ -268,9 +332,9 @@ void sha256_transform8x(sha256ctx *ctx, w[56] = ADD4_32(WSIGMA1_AVX(w[54]), w[40], w[49], WSIGMA0_AVX(w[41])); SHA256ROUND_AVX(s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7], 56, w[56]); w[57] = ADD4_32(WSIGMA1_AVX(w[55]), w[41], w[50], WSIGMA0_AVX(w[42])); - SHA256ROUND_AVX(s[7], s[0], s[1], s[2], s[3], s[4], s[5], s[6], 57, w[57]); + SHA256ROUND_AVX(s[7], s[0], s[1], s[2], s[3], s[4], s[5], s[6], 57, w[57]); w[58] = ADD4_32(WSIGMA1_AVX(w[56]), w[42], w[51], WSIGMA0_AVX(w[43])); - SHA256ROUND_AVX(s[6], s[7], s[0], s[1], s[2], s[3], s[4], s[5], 58, w[58]); + SHA256ROUND_AVX(s[6], s[7], s[0], s[1], s[2], s[3], s[4], s[5], 58, w[58]); w[59] = ADD4_32(WSIGMA1_AVX(w[57]), w[43], w[52], WSIGMA0_AVX(w[44])); SHA256ROUND_AVX(s[5], s[6], s[7], s[0], s[1], s[2], s[3], s[4], 59, w[59]); w[60] = ADD4_32(WSIGMA1_AVX(w[58]), w[44], w[53], WSIGMA0_AVX(w[45])); diff --git a/sha2-avx2/sha256avx.h b/sha2-avx2/sha256avx.h index e887063c..95848b94 100644 --- a/sha2-avx2/sha256avx.h +++ b/sha2-avx2/sha256avx.h @@ -1,79 +1,19 @@ #ifndef SHA256AVX_H #define SHA256AVX_H -#include "immintrin.h" -#include - -static const unsigned int RC[] = { - 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, - 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, - 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, - 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, - 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, - 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, - 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, - 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, - 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, - 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, - 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, - 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, - 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, - 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, - 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, - 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 -}; - -#define u32 uint32_t -#define u256 __m256i - -#define XOR _mm256_xor_si256 -#define OR _mm256_or_si256 -#define AND _mm256_and_si256 -#define ADD32 _mm256_add_epi32 -#define NOT(x) _mm256_xor_si256(x, _mm256_set_epi32(-1, -1, -1, -1, -1, -1, -1, -1)) - -#define LOAD(src) _mm256_loadu_si256((__m256i *)(src)) -#define STORE(dest,src) _mm256_storeu_si256((__m256i *)(dest),src) - -#define BYTESWAP(x) _mm256_shuffle_epi8(x, _mm256_set_epi8(0xc,0xd,0xe,0xf,0x8,0x9,0xa,0xb,0x4,0x5,0x6,0x7,0x0,0x1,0x2,0x3,0xc,0xd,0xe,0xf,0x8,0x9,0xa,0xb,0x4,0x5,0x6,0x7,0x0,0x1,0x2,0x3)) - -#define SHIFTR32(x, y) _mm256_srli_epi32(x, y) -#define SHIFTL32(x, y) _mm256_slli_epi32(x, y) - -#define ROTR32(x, y) OR(SHIFTR32(x, y), SHIFTL32(x, 32 - y)) -#define ROTL32(x, y) OR(SHIFTL32(x, y), SHIFTR32(x, 32 - y)) -#define XOR3(a, b, c) XOR(XOR(a, b), c) - -#define ADD3_32(a, b, c) ADD32(ADD32(a, b), c) -#define ADD4_32(a, b, c, d) ADD32(ADD32(ADD32(a, b), c), d) -#define ADD5_32(a, b, c, d, e) ADD32(ADD32(ADD32(ADD32(a, b), c), d), e) - -#define MAJ_AVX(a, b, c) XOR3(AND(a, b), AND(a, c), AND(b, c)) -#define CH_AVX(a, b, c) XOR(AND(a, b), AND(NOT(a), c)) - -#define SIGMA1_AVX(x) XOR3(ROTR32(x, 6), ROTR32(x, 11), ROTR32(x, 25)) -#define SIGMA0_AVX(x) XOR3(ROTR32(x, 2), ROTR32(x, 13), ROTR32(x, 22)) - -#define WSIGMA1_AVX(x) XOR3(ROTR32(x, 17), ROTR32(x, 19), SHIFTR32(x, 10)) -#define WSIGMA0_AVX(x) XOR3(ROTR32(x, 7), ROTR32(x, 18), SHIFTR32(x, 3)) - -#define SHA256ROUND_AVX(a, b, c, d, e, f, g, h, rc, w) \ - T0 = ADD5_32(h, SIGMA1_AVX(e), CH_AVX(e, f, g), _mm256_set1_epi32(RC[rc]), w); \ - d = ADD32(d, T0); \ - T1 = ADD32(SIGMA0_AVX(a), MAJ_AVX(a, b, c)); \ - h = ADD32(T0, T1); +#include +#include typedef struct SHA256state { - u256 s[8]; + __m256i s[8]; unsigned char msgblocks[8*64]; int datalen; unsigned long long msglen; -} sha256ctx; - +} sha256x8ctx; -void transpose(u256 s[8]); -void sha256_init8x(sha256ctx *ctx); -void sha256_final8x(sha256ctx *ctx, +void sha256_ctx_clone8x(sha256x8ctx *out, const sha256x8ctx *in); +void sha256_init8x(sha256x8ctx *ctx); +void sha256_final8x(sha256x8ctx *ctx, unsigned char *out0, unsigned char *out1, unsigned char *out2, @@ -83,7 +23,7 @@ void sha256_final8x(sha256ctx *ctx, unsigned char *out6, unsigned char *out7); -void sha256_transform8x(sha256ctx *ctx, +void sha256_transform8x(sha256x8ctx *ctx, const unsigned char *data0, const unsigned char *data1, const unsigned char *data2, diff --git a/sha2-avx2/sha256x8.c b/sha2-avx2/sha256x8.c index 460ba6a0..951789d7 100644 --- a/sha2-avx2/sha256x8.c +++ b/sha2-avx2/sha256x8.c @@ -4,14 +4,9 @@ #include "sha256avx.h" #include "utils.h" -static uint32_t load_bigendian_32(const uint8_t *x) { - return (uint32_t)(x[3]) | (((uint32_t)(x[2])) << 8) | - (((uint32_t)(x[1])) << 16) | (((uint32_t)(x[0])) << 24); -} - // Performs sha256x8 on an initialized (and perhaps seeded) state. static void _sha256x8( - sha256ctx *ctx, + sha256x8ctx *ctx, unsigned char *out0, unsigned char *out1, unsigned char *out2, @@ -67,8 +62,7 @@ void sha256x8_seeded( unsigned char *out5, unsigned char *out6, unsigned char *out7, - const unsigned char *seed, - unsigned long long seedlen, + const sha256x8ctx *seed, const unsigned char *in0, const unsigned char *in1, const unsigned char *in2, @@ -77,17 +71,9 @@ void sha256x8_seeded( const unsigned char *in5, const unsigned char *in6, const unsigned char *in7, unsigned long long inlen) { - uint32_t t; - - sha256ctx ctx; - - for (size_t i = 0; i < 8; i++) { - t = load_bigendian_32(seed + 4*i); - ctx.s[i] = _mm256_set_epi32(t, t, t, t, t, t, t, t); - } - ctx.datalen = 0; - ctx.msglen = seedlen; + sha256x8ctx ctx; + sha256_ctx_clone8x(&ctx, seed); _sha256x8(&ctx, out0, out1, out2, out3, out4, out5, out6, out7, in0, in1, in2, in3, in4, in5, in6, in7, inlen); @@ -111,7 +97,7 @@ void sha256x8(unsigned char *out0, const unsigned char *in6, const unsigned char *in7, unsigned long long inlen) { - sha256ctx ctx; + sha256x8ctx ctx; sha256_init8x(&ctx); _sha256x8(&ctx, out0, out1, out2, out3, out4, out5, out6, out7, diff --git a/sha2-avx2/sha256x8.h b/sha2-avx2/sha256x8.h index 0060de5d..333e7331 100644 --- a/sha2-avx2/sha256x8.h +++ b/sha2-avx2/sha256x8.h @@ -2,6 +2,7 @@ #define SPX_SHA256X8_H #include "params.h" +#include "sha256avx.h" #define SPX_SHA256_BLOCK_BYTES 64 #define SPX_SHA256_OUTPUT_BYTES 32 /* This does not necessarily equal SPX_N */ @@ -20,8 +21,7 @@ void sha256x8_seeded( unsigned char *out5, unsigned char *out6, unsigned char *out7, - const unsigned char *seed, - unsigned long long seedlen, + const sha256x8ctx *seed, const unsigned char *in0, const unsigned char *in1, const unsigned char *in2, diff --git a/sha2-avx2/sha512x4.c b/sha2-avx2/sha512x4.c index 0306ec71..e6524811 100644 --- a/sha2-avx2/sha512x4.c +++ b/sha2-avx2/sha512x4.c @@ -11,7 +11,7 @@ typedef uint64_t u64; typedef __m256i u256; static void sha512_transform4x( - sha512ctx4x *ctx, + sha512x4ctx *ctx, const unsigned char *d0, const unsigned char *d1, const unsigned char *d2, @@ -51,7 +51,7 @@ static void transpose(u256 s[4]) { } -static void sha512_init4x(sha512ctx4x *ctx) { +static void sha512_init4x(sha512x4ctx *ctx) { #define SET4(x) _mm256_set_epi64x(x, x, x, x) ctx->s[0] = SET4(0x6a09e667f3bcc908ULL); ctx->s[1] = SET4(0xbb67ae8584caa73bULL); @@ -62,7 +62,7 @@ static void sha512_init4x(sha512ctx4x *ctx) { ctx->s[6] = SET4(0x1f83d9abfb41bd6bULL); ctx->s[7] = SET4(0x5be0cd19137e2179ULL); #undef SET4 - + ctx->datalen = 0; ctx->msglen = 0; } @@ -113,50 +113,50 @@ static u256 GAMMA1_AVX(u256 x) { h = ADD64(T0, T1); static const unsigned long long RC[80] = { - 0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, + 0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, 0xb5c0fbcfec4d3b2fULL, 0xe9b5dba58189dbbcULL, - 0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL, + 0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL, 0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL, - 0xd807aa98a3030242ULL, 0x12835b0145706fbeULL, + 0xd807aa98a3030242ULL, 0x12835b0145706fbeULL, 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL, - 0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, + 0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, 0x9bdc06a725c71235ULL, 0xc19bf174cf692694ULL, - 0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL, + 0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL, 0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL, - 0x2de92c6f592b0275ULL, 0x4a7484aa6ea6e483ULL, + 0x2de92c6f592b0275ULL, 0x4a7484aa6ea6e483ULL, 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL, - 0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL, + 0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL, 0xb00327c898fb213fULL, 0xbf597fc7beef0ee4ULL, - 0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL, + 0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL, 0x06ca6351e003826fULL, 0x142929670a0e6e70ULL, - 0x27b70a8546d22ffcULL, 0x2e1b21385c26c926ULL, + 0x27b70a8546d22ffcULL, 0x2e1b21385c26c926ULL, 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL, - 0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, + 0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, 0x81c2c92e47edaee6ULL, 0x92722c851482353bULL, 0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL, 0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL, - 0xd192e819d6ef5218ULL, 0xd69906245565a910ULL, + 0xd192e819d6ef5218ULL, 0xd69906245565a910ULL, 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL, - 0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, + 0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, 0x2748774cdf8eeb99ULL, 0x34b0bcb5e19b48a8ULL, - 0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL, + 0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL, 0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL, - 0x748f82ee5defb2fcULL, 0x78a5636f43172f60ULL, + 0x748f82ee5defb2fcULL, 0x78a5636f43172f60ULL, 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL, - 0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, + 0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, 0xbef9a3f7b2c67915ULL, 0xc67178f2e372532bULL, - 0xca273eceea26619cULL, 0xd186b8c721c0c207ULL, + 0xca273eceea26619cULL, 0xd186b8c721c0c207ULL, 0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL, - 0x06f067aa72176fbaULL, 0x0a637dc5a2c898a6ULL, + 0x06f067aa72176fbaULL, 0x0a637dc5a2c898a6ULL, 0x113f9804bef90daeULL, 0x1b710b35131c471bULL, - 0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, + 0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, 0x3c9ebe0a15c9bebcULL, 0x431d67c49c100d4cULL, - 0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL, + 0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL, 0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL, }; static void sha512_transform4x( - sha512ctx4x *ctx, + sha512x4ctx *ctx, const unsigned char *d0, const unsigned char *d1, const unsigned char *d2, @@ -269,7 +269,7 @@ static void sha512_transform4x( } static void _sha512x4( - sha512ctx4x* ctx, + sha512x4ctx* ctx, unsigned char *out0, unsigned char *out1, unsigned char *out2, @@ -404,9 +404,9 @@ void mgf1x4_512(unsigned char *outx4, unsigned long outlen, u32_to_bytes(inbufx4 + inlen + j*(inlen + 4), i); } - sha512ctx4x ctx; + sha512x4ctx ctx; sha512_init4x(&ctx); - + _sha512x4( &ctx, outbuf + 0*64, @@ -433,26 +433,14 @@ void sha512x4_seeded( unsigned char *out1, unsigned char *out2, unsigned char *out3, - const unsigned char *seed, - unsigned long long seedlen, + const sha512x4ctx *seed, const unsigned char *in0, const unsigned char *in1, const unsigned char *in2, const unsigned char *in3, unsigned long long inlen) { - sha512ctx4x ctx; - unsigned long i; - - for (i = 0; i < 8; i++) { - uint64_t t = (uint64_t)(seed[7]) | (((uint64_t)(seed[6])) << 8) | - (((uint64_t)(seed[5])) << 16) | (((uint64_t)(seed[4])) << 24) | - (((uint64_t)(seed[3])) << 32) | (((uint64_t)(seed[2])) << 40) | - (((uint64_t)(seed[1])) << 48) | (((uint64_t)(seed[0])) << 56); - ctx.s[i] = _mm256_set_epi64x(t, t, t, t); - seed += 8; - } - - ctx.msglen = seedlen; + sha512x4ctx ctx; + sha512_ctx_clone4x(&ctx, seed); _sha512x4( &ctx, out0, out1, out2, out3, @@ -460,3 +448,7 @@ void sha512x4_seeded( inlen ); } + +void sha512_ctx_clone4x(sha512x4ctx *out, const sha512x4ctx *in) { + memcpy(out, in, sizeof(sha512x4ctx)); +} diff --git a/sha2-avx2/sha512x4.h b/sha2-avx2/sha512x4.h index 013459f4..91abe44d 100644 --- a/sha2-avx2/sha512x4.h +++ b/sha2-avx2/sha512x4.h @@ -10,7 +10,7 @@ typedef struct SHA512state4x { unsigned char msgblocks[4*128]; int datalen; unsigned long long msglen; -} sha512ctx4x; +} sha512x4ctx; #define sha512x4_seeded SPX_NAMESPACE(sha512x4_seeded) @@ -19,14 +19,14 @@ void sha512x4_seeded( unsigned char *out1, unsigned char *out2, unsigned char *out3, - const unsigned char *seed, - unsigned long long seedlen, + const sha512x4ctx *seed, const unsigned char *in0, const unsigned char *in1, const unsigned char *in2, const unsigned char *in3, unsigned long long inlen); +void sha512_ctx_clone4x(sha512x4ctx *out, const sha512x4ctx *in); /** * Note that inlen should be sufficiently small that it still allows for diff --git a/sha2-avx2/thash_sha2_robustx8.c b/sha2-avx2/thash_sha2_robustx8.c index e15671a7..fea9179d 100644 --- a/sha2-avx2/thash_sha2_robustx8.c +++ b/sha2-avx2/thash_sha2_robustx8.c @@ -4,6 +4,7 @@ #include "address.h" #include "utils.h" #include "params.h" +#include "hash.h" #include "thashx8.h" #include "sha2.h" #include "sha256x8.h" @@ -128,7 +129,7 @@ void thashx8(unsigned char *out0, outbufx8 + 7*SPX_SHA256_OUTPUT_BYTES, /* seed */ - ctx->state_seeded, 512, + &ctx->statex8_seeded, /* in */ bufx8 + SPX_N + 0*(SPX_N + SPX_SHA256_ADDR_BYTES + inblocks*SPX_N), @@ -240,8 +241,7 @@ static void thashx8_512( outbuf + 1*SPX_SHA512_OUTPUT_BYTES, outbuf + 2*SPX_SHA512_OUTPUT_BYTES, outbuf + 3*SPX_SHA512_OUTPUT_BYTES, - ctx->state_seeded_512, /* seed */ - 1024, /* seed length */ + &ctx->statex4_seeded_512, /* seed */ bufx8 + SPX_N + 0*(SPX_N + SPX_SHA256_ADDR_BYTES + inblocks*SPX_N), bufx8 + SPX_N + 1*(SPX_N + SPX_SHA256_ADDR_BYTES + inblocks*SPX_N), bufx8 + SPX_N + 2*(SPX_N + SPX_SHA256_ADDR_BYTES + inblocks*SPX_N), @@ -259,8 +259,7 @@ static void thashx8_512( outbuf + 1*SPX_SHA512_OUTPUT_BYTES, outbuf + 2*SPX_SHA512_OUTPUT_BYTES, outbuf + 3*SPX_SHA512_OUTPUT_BYTES, - ctx->state_seeded_512, /* seed */ - 1024, /* seed length */ + &ctx->statex4_seeded_512, /* seed */ bufx8 + SPX_N + 4*(SPX_N + SPX_SHA256_ADDR_BYTES + inblocks*SPX_N), bufx8 + SPX_N + 5*(SPX_N + SPX_SHA256_ADDR_BYTES + inblocks*SPX_N), bufx8 + SPX_N + 6*(SPX_N + SPX_SHA256_ADDR_BYTES + inblocks*SPX_N), diff --git a/sha2-avx2/thash_sha2_simplex8.c b/sha2-avx2/thash_sha2_simplex8.c index 2b40d028..6acee885 100644 --- a/sha2-avx2/thash_sha2_simplex8.c +++ b/sha2-avx2/thash_sha2_simplex8.c @@ -4,6 +4,7 @@ #include "address.h" #include "utils.h" #include "params.h" +#include "hash.h" #include "thashx8.h" #include "sha2.h" #include "sha256x8.h" @@ -103,7 +104,7 @@ void thashx8(unsigned char *out0, outbufx8 + 7*SPX_SHA256_OUTPUT_BYTES, /* seed */ - ctx->state_seeded, 512, + &ctx->statex8_seeded, /* in */ bufx8 + 0*(SPX_SHA256_ADDR_BYTES + inblocks*SPX_N), @@ -184,8 +185,7 @@ static void thashx8_512( outbuf + 1*SPX_SHA512_OUTPUT_BYTES, outbuf + 2*SPX_SHA512_OUTPUT_BYTES, outbuf + 3*SPX_SHA512_OUTPUT_BYTES, - ctx->state_seeded_512, /* seed */ - 1024, /* seed length */ + &ctx->statex4_seeded_512, /* seed */ bufx8 + 0*(SPX_SHA256_ADDR_BYTES + inblocks*SPX_N), /* in */ bufx8 + 1*(SPX_SHA256_ADDR_BYTES + inblocks*SPX_N), bufx8 + 2*(SPX_SHA256_ADDR_BYTES + inblocks*SPX_N), @@ -203,8 +203,7 @@ static void thashx8_512( outbuf + 1*SPX_SHA512_OUTPUT_BYTES, outbuf + 2*SPX_SHA512_OUTPUT_BYTES, outbuf + 3*SPX_SHA512_OUTPUT_BYTES, - ctx->state_seeded_512, /* seed */ - 1024, /* seed length */ + &ctx->statex4_seeded_512, /* seed */ bufx8 + 4*(SPX_SHA256_ADDR_BYTES + inblocks*SPX_N), /* in */ bufx8 + 5*(SPX_SHA256_ADDR_BYTES + inblocks*SPX_N), bufx8 + 6*(SPX_SHA256_ADDR_BYTES + inblocks*SPX_N), From bafee157f3ed1f59d26480cb57673e52cd149321 Mon Sep 17 00:00:00 2001 From: Thom Wiggers Date: Mon, 29 Aug 2022 15:44:17 +0200 Subject: [PATCH 5/8] Fix Haraka and Shake context usage --- haraka-aesni/Makefile | 4 ++-- haraka-aesni/context.h | 6 ++++++ haraka-aesni/context_haraka.c | 1 + shake-avx2/Makefile | 4 ++-- shake-avx2/context.h | 6 ++++++ shake-avx2/context_shake.c | 1 + 6 files changed, 18 insertions(+), 4 deletions(-) create mode 120000 haraka-aesni/context_haraka.c create mode 120000 shake-avx2/context_shake.c diff --git a/haraka-aesni/Makefile b/haraka-aesni/Makefile index a5c5816d..e77f92b7 100644 --- a/haraka-aesni/Makefile +++ b/haraka-aesni/Makefile @@ -5,8 +5,8 @@ CC = /usr/bin/gcc CFLAGS = -Wall -Wextra -Wpedantic -Wmissing-prototypes -O3 -std=c99 -march=native -fomit-frame-pointer -flto -DPARAMS=$(PARAMS) $(EXTRA_CFLAGS) -SOURCES = hash_haraka.c hash_harakax4.c thash_haraka_$(THASH).c thash_haraka_$(THASH)x4.c address.c randombytes.c merkle.c wots.c utils.c utilsx4.c fors.c sign.c haraka.c -HEADERS = params.h hash.h hashx4.h thash.h thashx4.h address.h randombytes.h merkle.c wots.h utils.h utilsx4.h fors.h api.h haraka.h harakax4.h +SOURCES = hash_haraka.c hash_harakax4.c thash_haraka_$(THASH).c thash_haraka_$(THASH)x4.c address.c randombytes.c merkle.c wots.c utils.c utilsx4.c fors.c sign.c haraka.c context_haraka.c +HEADERS = params.h hash.h hashx4.h thash.h thashx4.h address.h randombytes.h merkle.c wots.h utils.h utilsx4.h fors.h api.h haraka.h harakax4.h context.h DET_SOURCES = $(SOURCES:randombytes.%=rng.%) DET_HEADERS = $(HEADERS:randombytes.%=rng.%) diff --git a/haraka-aesni/context.h b/haraka-aesni/context.h index f88445a2..434b6d71 100644 --- a/haraka-aesni/context.h +++ b/haraka-aesni/context.h @@ -13,4 +13,10 @@ typedef struct { __m128i rc[40]; } spx_ctx; +#define initialize_hash_function SPX_NAMESPACE(initialize_hash_function) +void initialize_hash_function(spx_ctx *ctx); + +#define free_hash_function SPX_NAMESPACE(free_hash_function) +void free_hash_function(spx_ctx *ctx); + #endif diff --git a/haraka-aesni/context_haraka.c b/haraka-aesni/context_haraka.c new file mode 120000 index 00000000..856b7d97 --- /dev/null +++ b/haraka-aesni/context_haraka.c @@ -0,0 +1 @@ +../ref/context_haraka.c \ No newline at end of file diff --git a/shake-avx2/Makefile b/shake-avx2/Makefile index fa8421cc..ad83d23a 100644 --- a/shake-avx2/Makefile +++ b/shake-avx2/Makefile @@ -4,8 +4,8 @@ THASH = robust CC = /usr/bin/gcc CFLAGS = -Wall -Wextra -Wpedantic -Wmissing-prototypes -O3 -std=c99 -march=native -fomit-frame-pointer -flto -DPARAMS=$(PARAMS) $(EXTRA_CFLAGS) -SOURCES = hash_shake.c hash_shakex4.c thash_shake_$(THASH).c thash_shake_$(THASH)x4.c address.c randombytes.c merkle.c wots.c utils.c utilsx4.c fors.c sign.c fips202.c fips202x4.c keccak4x/KeccakP-1600-times4-SIMD256.o -HEADERS = params.h hash.h hashx4.h thash.h thashx4.h address.h randombytes.h merkle.h wots.h utils.h utilsx4.h fors.h api.h fips202.h fips202x4.h +SOURCES = hash_shake.c hash_shakex4.c thash_shake_$(THASH).c thash_shake_$(THASH)x4.c address.c randombytes.c merkle.c wots.c utils.c utilsx4.c fors.c sign.c fips202.c fips202x4.c context_shake.c keccak4x/KeccakP-1600-times4-SIMD256.o +HEADERS = params.h hash.h hashx4.h thash.h thashx4.h address.h randombytes.h merkle.h wots.h utils.h utilsx4.h fors.h api.h fips202.h fips202x4.h context.h DET_SOURCES = $(SOURCES:randombytes.%=rng.%) DET_HEADERS = $(HEADERS:randombytes.%=rng.%) diff --git a/shake-avx2/context.h b/shake-avx2/context.h index 993c9ce4..6e0a33f3 100644 --- a/shake-avx2/context.h +++ b/shake-avx2/context.h @@ -10,4 +10,10 @@ typedef struct { uint8_t sk_seed[SPX_N]; } spx_ctx; +#define initialize_hash_function SPX_NAMESPACE(initialize_hash_function) +void initialize_hash_function(spx_ctx *ctx); + +#define free_hash_function SPX_NAMESPACE(free_hash_function) +void free_hash_function(spx_ctx *ctx); + #endif diff --git a/shake-avx2/context_shake.c b/shake-avx2/context_shake.c new file mode 120000 index 00000000..c67a9018 --- /dev/null +++ b/shake-avx2/context_shake.c @@ -0,0 +1 @@ +../ref/context_shake.c \ No newline at end of file From c5054bdbd238a14bc856b471acc79b5605e7770c Mon Sep 17 00:00:00 2001 From: Thom Wiggers Date: Mon, 16 Jan 2023 14:14:35 +0100 Subject: [PATCH 6/8] Better align context.h clang-tidy suggested that this layout was more efficient. --- sha2-avx2/context.h | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/sha2-avx2/context.h b/sha2-avx2/context.h index d3e126b1..9ea94a47 100644 --- a/sha2-avx2/context.h +++ b/sha2-avx2/context.h @@ -9,15 +9,18 @@ #include "sha512x4.h" typedef struct { - uint8_t pub_seed[SPX_N]; - uint8_t sk_seed[SPX_N]; + sha256x8ctx statex8_seeded; +#if SPX_SHA512 + sha512x4ctx statex4_seeded_512; +#endif sha256ctx state_seeded; - sha256x8ctx statex8_seeded; #if SPX_SHA512 sha512ctx state_seeded_512; - sha512x4ctx statex4_seeded_512; #endif + + uint8_t pub_seed[SPX_N]; + uint8_t sk_seed[SPX_N]; } spx_ctx; From 039595305deb5722c1fdb1bda2597f79f7c1f4dd Mon Sep 17 00:00:00 2001 From: Thom Wiggers Date: Mon, 16 Jan 2023 14:30:02 +0100 Subject: [PATCH 7/8] Don't rely on SHA2x1 internals --- sha2-avx2/context_sha2.c | 34 ++++++++-------------------------- sha2-avx2/sha256avx.h | 12 ++++++++++-- sha2-avx2/sha512x4.c | 12 ++---------- sha2-avx2/sha512x4.h | 18 ++++++++++++++++-- 4 files changed, 36 insertions(+), 40 deletions(-) diff --git a/sha2-avx2/context_sha2.c b/sha2-avx2/context_sha2.c index d65bd749..e4b84ab8 100644 --- a/sha2-avx2/context_sha2.c +++ b/sha2-avx2/context_sha2.c @@ -2,11 +2,6 @@ #include "context.h" -static uint32_t load_bigendian_32(const uint8_t *x) { - return (uint32_t)(x[3]) | (((uint32_t)(x[2])) << 8) | - (((uint32_t)(x[1])) << 16) | (((uint32_t)(x[0])) << 24); -} - /** * Absorb the constant pub_seed using one round of the compression function * This initializes state_seeded and state_seeded_512, which can then be @@ -27,13 +22,11 @@ static void seed_state(spx_ctx *ctx) { sha256_inc_init(&ctx->state_seeded); sha256_inc_blocks(&ctx->state_seeded, block, 1); - // this still assumes internal representation of the SHA256x1 API. - // should be replaced by proper initialization. - for (size_t i = 0; i < 8; i++) { - uint32_t t = load_bigendian_32(((uint8_t*)&ctx->state_seeded.ctx) + 4*i); - ctx->statex8_seeded.s[i] = _mm256_set_epi32(t, t, t, t, t, t, t, t); - } - + // initialize x8 + sha256_init8x(&ctx->statex8_seeded); + sha256_transform8x(&ctx->statex8_seeded, + block, block, block, block, + block, block, block, block); ctx->statex8_seeded.datalen = 0; ctx->statex8_seeded.msglen = 512; @@ -41,22 +34,11 @@ static void seed_state(spx_ctx *ctx) { sha512_inc_init(&ctx->state_seeded_512); sha512_inc_blocks(&ctx->state_seeded_512, block, 1); - // this still assumes internal representation of the SHA512x1 API. - // should be replaced by proper initialization. - uint8_t *seed = (uint8_t*)&ctx->state_seeded_512.ctx; - for (i = 0; i < 8; i++) { - uint64_t t = (uint64_t)(seed[7]) | (((uint64_t)(seed[6])) << 8) | - (((uint64_t)(seed[5])) << 16) | (((uint64_t)(seed[4])) << 24) | - (((uint64_t)(seed[3])) << 32) | (((uint64_t)(seed[2])) << 40) | - (((uint64_t)(seed[1])) << 48) | (((uint64_t)(seed[0])) << 56); - ctx->statex4_seeded_512.s[i] = _mm256_set_epi64x(t, t, t, t); - seed += 8; - } - + // initialize x4 + sha512_initx4(&ctx->statex4_seeded_512); + sha512_transform(&ctx->statex4_seeded_512, block, block, block, block); ctx->statex4_seeded_512.datalen = 0; ctx->statex4_seeded_512.msglen = 1024; - - #endif } diff --git a/sha2-avx2/sha256avx.h b/sha2-avx2/sha256avx.h index 95848b94..198c135e 100644 --- a/sha2-avx2/sha256avx.h +++ b/sha2-avx2/sha256avx.h @@ -1,18 +1,25 @@ #ifndef SHA256AVX_H #define SHA256AVX_H -#include #include +#include + +#include "params.h" typedef struct SHA256state { __m256i s[8]; unsigned char msgblocks[8*64]; - int datalen; + unsigned int datalen; unsigned long long msglen; } sha256x8ctx; +#define sha256_ctx_clone8x SPX_NAMESPACE(sha256_ctx_clone8x) void sha256_ctx_clone8x(sha256x8ctx *out, const sha256x8ctx *in); + +#define sha256_init8x SPX_NAMESPACE(sha256_init8x) void sha256_init8x(sha256x8ctx *ctx); + +#define sha256_final8x SPX_NAMESPACE(sha256_final8x) void sha256_final8x(sha256x8ctx *ctx, unsigned char *out0, unsigned char *out1, @@ -23,6 +30,7 @@ void sha256_final8x(sha256x8ctx *ctx, unsigned char *out6, unsigned char *out7); +#define sha256_transform8x SPX_NAMESPACE(sha256_transform8x) void sha256_transform8x(sha256x8ctx *ctx, const unsigned char *data0, const unsigned char *data1, diff --git a/sha2-avx2/sha512x4.c b/sha2-avx2/sha512x4.c index e6524811..364126a3 100644 --- a/sha2-avx2/sha512x4.c +++ b/sha2-avx2/sha512x4.c @@ -10,14 +10,6 @@ typedef uint64_t u64; typedef __m256i u256; -static void sha512_transform4x( - sha512x4ctx *ctx, - const unsigned char *d0, - const unsigned char *d1, - const unsigned char *d2, - const unsigned char *d3 -); - #define BYTESWAP(x) _mm256_shuffle_epi8(x, _mm256_set_epi8(0x8,0x9,0xa,0xb,0xc,0xd,0xe,0xf,0x0,0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0x9,0xa,0xb,0xc,0xd,0xe,0xf,0x0,0x1,0x2,0x3,0x4,0x5,0x6,0x7)) #define STORE(dest,src) _mm256_storeu_si256((__m256i *)(dest),src) @@ -51,7 +43,7 @@ static void transpose(u256 s[4]) { } -static void sha512_init4x(sha512x4ctx *ctx) { +void sha512_init4x(sha512x4ctx *ctx) { #define SET4(x) _mm256_set_epi64x(x, x, x, x) ctx->s[0] = SET4(0x6a09e667f3bcc908ULL); ctx->s[1] = SET4(0xbb67ae8584caa73bULL); @@ -155,7 +147,7 @@ static const unsigned long long RC[80] = { 0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL, }; -static void sha512_transform4x( +void sha512_transform4x( sha512x4ctx *ctx, const unsigned char *d0, const unsigned char *d1, diff --git a/sha2-avx2/sha512x4.h b/sha2-avx2/sha512x4.h index 91abe44d..937ea059 100644 --- a/sha2-avx2/sha512x4.h +++ b/sha2-avx2/sha512x4.h @@ -1,17 +1,30 @@ #ifndef SHA512AVX_H #define SHA512AVX_H + +#include #include -#include "immintrin.h" + #include "params.h" typedef struct SHA512state4x { __m256i s[8]; unsigned char msgblocks[4*128]; - int datalen; + unsigned int datalen; unsigned long long msglen; } sha512x4ctx; +#define sha512_init4x SPX_NAMESPACE(sha512_init4x) +void sha512_init4x(sha512x4ctx *ctx); + +#define sha512_transform4x SPX_NAMESPACE(sha512_transform4x) +void sha512_transform4x( + sha512x4ctx *ctx, + const unsigned char *d0, + const unsigned char *d1, + const unsigned char *d2, + const unsigned char *d3); + #define sha512x4_seeded SPX_NAMESPACE(sha512x4_seeded) void sha512x4_seeded( @@ -26,6 +39,7 @@ void sha512x4_seeded( const unsigned char *in3, unsigned long long inlen); +#define sha512_ctx_clone4x SPX_NAMESPACE(sha512_ctx_clone4x) void sha512_ctx_clone4x(sha512x4ctx *out, const sha512x4ctx *in); /** From 98b58c17b4222bd277c39ff1a31778be782e70b9 Mon Sep 17 00:00:00 2001 From: Thom Wiggers Date: Mon, 16 Jan 2023 14:30:20 +0100 Subject: [PATCH 8/8] Fix missing context in shake-a64 --- shake-a64/Makefile | 4 ++-- shake-a64/context.h | 6 ++++++ shake-a64/context_shake.c | 1 + 3 files changed, 9 insertions(+), 2 deletions(-) create mode 120000 shake-a64/context_shake.c diff --git a/shake-a64/Makefile b/shake-a64/Makefile index b6412d00..e43d32b2 100644 --- a/shake-a64/Makefile +++ b/shake-a64/Makefile @@ -3,8 +3,8 @@ THASH = robust CFLAGS = -Wall -Wextra -Wpedantic -Wmissing-prototypes -O3 -std=c99 -fomit-frame-pointer -flto -DPARAMS=$(PARAMS) $(EXTRA_CFLAGS) -SOURCES = hash_shake.c hash_shakex2.c thash_shake_$(THASH)x2.c address.c randombytes.c merkle.c wots.c utils.c utilsx2.c fors.c sign.c fips202.c fips202x2.c f1600x2.c f1600x2.s -HEADERS = params.h hash.h hashx2.h thashx2.h address.h randombytes.h merkle.h wots.h utils.h utilsx2.h fors.h api.h fips202.h fips202x2.h f1600x2.h thash.h +SOURCES = context_shake.c hash_shake.c hash_shakex2.c thash_shake_$(THASH)x2.c address.c randombytes.c merkle.c wots.c utils.c utilsx2.c fors.c sign.c fips202.c fips202x2.c f1600x2.c f1600x2.s +HEADERS = context.h params.h hash.h hashx2.h thashx2.h address.h randombytes.h merkle.h wots.h utils.h utilsx2.h fors.h api.h fips202.h fips202x2.h f1600x2.h thash.h DET_SOURCES = $(SOURCES:randombytes.%=rng.%) DET_HEADERS = $(HEADERS:randombytes.%=rng.%) diff --git a/shake-a64/context.h b/shake-a64/context.h index 993c9ce4..6e0a33f3 100644 --- a/shake-a64/context.h +++ b/shake-a64/context.h @@ -10,4 +10,10 @@ typedef struct { uint8_t sk_seed[SPX_N]; } spx_ctx; +#define initialize_hash_function SPX_NAMESPACE(initialize_hash_function) +void initialize_hash_function(spx_ctx *ctx); + +#define free_hash_function SPX_NAMESPACE(free_hash_function) +void free_hash_function(spx_ctx *ctx); + #endif diff --git a/shake-a64/context_shake.c b/shake-a64/context_shake.c new file mode 120000 index 00000000..c67a9018 --- /dev/null +++ b/shake-a64/context_shake.c @@ -0,0 +1 @@ +../ref/context_shake.c \ No newline at end of file