diff --git a/Makefile b/Makefile index 6c62948..4fa7cfc 100644 --- a/Makefile +++ b/Makefile @@ -14,7 +14,7 @@ hss_lib.a: hss.o hss_alloc.o hss_aux.o hss_common.o \ hss_verify.o hss_verify_inc.o hss_derive.o \ hss_derive.o hss_zeroize.o lm_common.o \ lm_ots_common.o lm_ots_sign.o lm_ots_verify.o lm_verify.o endian.o \ - hash.o sha256.o + hash.o sha256.o fips202.o $(AR) rcs $@ $^ hss_lib_thread.a: hss.o hss_alloc.o hss_aux.o hss_common.o \ @@ -23,98 +23,101 @@ hss_lib_thread.a: hss.o hss_alloc.o hss_aux.o hss_common.o \ hss_verify.o hss_verify_inc.o \ hss_derive.o hss_zeroize.o lm_common.o \ lm_ots_common.o lm_ots_sign.o lm_ots_verify.o lm_verify.o endian.o \ - hash.o sha256.o + hash.o sha256.o fips202.o $(AR) rcs $@ $^ hss_verify.a: hss_verify.o hss_verify_inc.o hss_common.o hss_thread_single.o \ hss_zeroize.o lm_common.o lm_ots_common.o lm_ots_verify.o lm_verify.o \ - endian.o hash.o sha256.o + endian.o hash.o sha256.o fips202.o $(AR) rcs $@ $^ demo: demo.c hss_lib_thread.a $(CC) $(CFLAGS) demo.c hss_lib_thread.a -lcrypto -lpthread -o demo -test_1: test_1.c lm_ots_common.o lm_ots_sign.o lm_ots_verify.o endian.o hash.o sha256.o hss_zeroize.o - $(CC) $(CFLAGS) -o test_1 test_1.c lm_ots_common.o lm_ots_sign.o lm_ots_verify.o endian.o hash.o sha256.o hss_zeroize.o -lcrypto +test_1: test_1.c lm_ots_common.o lm_ots_sign.o lm_ots_verify.o endian.o hash.o sha256.o h fips202.o ss_zeroize.o + $(CC) $(CFLAGS) -o test_1 test_1.c lm_ots_common.o lm_ots_sign.o lm_ots_verify.o endian.o hash.o sha256.o fips202.o hss_zeroize.o -lcrypto -test_hss: test_hss.c test_hss.h test_testvector.c test_stat.c test_keygen.c test_load.c test_sign.c test_sign_inc.c test_verify.c test_verify_inc.c test_keyload.c test_reserve.c test_thread.c test_h25.c hss.h hss_lib_thread.a - $(CC) $(CFLAGS) test_hss.c test_testvector.c test_stat.c test_keygen.c test_sign.c test_sign_inc.c test_load.c test_verify.c test_verify_inc.c test_keyload.c test_reserve.c test_thread.c test_h25.c hss_lib_thread.a -lcrypto -lpthread -o test_hss +test_hss: test_hss.c test_hss.h test_testvector.c test_shake.c test_stat.c test_keygen.c test_load.c test_sign.c test_sign_inc.c test_verify.c test_verify_inc.c test_keyload.c test_reserve.c test_thread.c test_h25.c hss.h hss_lib_thread.a + $(CC) $(CFLAGS) test_hss.c test_testvector.c test_shake.c test_stat.c test_keygen.c test_sign.c test_sign_inc.c test_load.c test_verify.c test_verify_inc.c test_keyload.c test_reserve.c test_thread.c test_h25.c hss_lib_thread.a -lcrypto -lpthread -o test_hss -hss.o: hss.c hss.h common_defs.h hash.h endian.h hss_internal.h hss_aux.h hss_derive.h +hss.o: hss.c hss.h common_defs.h hash.h endian.h hss_internal.h hss_aux.h hss_derive.h config.h $(CC) $(CFLAGS) -c hss.c -o $@ -hss_alloc.o: hss_alloc.c hss.h hss_internal.h lm_common.h +hss_alloc.o: hss_alloc.c hss.h hss_internal.h lm_common.h config.h $(CC) $(CFLAGS) -c hss_alloc.c -o $@ -hss_aux.o: hss_aux.c hss_aux.h hss_internal.h common_defs.h lm_common.h endian.h hash.h +hss_aux.o: hss_aux.c hss_aux.h hss_internal.h common_defs.h lm_common.h endian.h hash.h config.h $(CC) $(CFLAGS) -c hss_aux.c -o $@ -hss_common.o: hss_common.c common_defs.h hss_common.h lm_common.h +hss_common.o: hss_common.c common_defs.h hss_common.h lm_common.h config.h $(CC) $(CFLAGS) -c hss_common.c -o $@ -hss_compute.o: hss_compute.c hss_internal.h hash.h hss_thread.h lm_ots_common.h lm_ots.h endian.h hss_derive.h +hss_compute.o: hss_compute.c hss_internal.h hash.h hss_thread.h lm_ots_common.h lm_ots.h endian.h hss_derive.h config.h $(CC) $(CFLAGS) -c hss_compute.c -o $@ -hss_derive.o: hss_derive.c hss_derive.h hss_internal.h hash.h endian.h +hss_derive.o: hss_derive.c hss_derive.h hss_internal.h hash.h endian.h config.h $(CC) $(CFLAGS) -c hss_derive.c -o $@ -hss_generate.o: hss_generate.c hss.h hss_internal.h hss_aux.h hash.h hss_thread.h hss_reserve.h lm_ots_common.h endian.h +hss_generate.o: hss_generate.c hss.h hss_internal.h hss_aux.h hash.h hss_thread.h hss_reserve.h lm_ots_common.h endian.h config.h $(CC) $(CFLAGS) -c hss_generate.c -o $@ -hss_keygen.o: hss_keygen.c hss.h common_defs.h hss_internal.h hss_aux.h endian.h hash.h hss_thread.h lm_common.h lm_ots_common.h +hss_keygen.o: hss_keygen.c hss.h common_defs.h hss_internal.h hss_aux.h endian.h hash.h hss_thread.h lm_common.h lm_ots_common.h config.h $(CC) $(CFLAGS) -c hss_keygen.c -o $@ -hss_param.o: hss_param.c hss.h hss_internal.h endian.h hss_zeroize.h +hss_param.o: hss_param.c hss.h hss_internal.h endian.h hss_zeroize.h config.h $(CC) $(CFLAGS) -c hss_param.c -o $@ -hss_reserve.o: hss_reserve.c common_defs.h hss_internal.h hss_reserve.h endian.h +hss_reserve.o: hss_reserve.c common_defs.h hss_internal.h hss_reserve.h endian.h config.h $(CC) $(CFLAGS) -c hss_reserve.c -o $@ -hss_sign.o: hss_sign.c common_defs.h hss.h hash.h endian.h hss_internal.h hss_aux.h hss_thread.h hss_reserve.h lm_ots.h lm_ots_common.h hss_derive.h +hss_sign.o: hss_sign.c common_defs.h hss.h hash.h endian.h hss_internal.h hss_aux.h hss_thread.h hss_reserve.h lm_ots.h lm_ots_common.h hss_derive.h config.h $(CC) $(CFLAGS) -c hss_sign.c -o $@ -hss_sign_inc.o: hss_sign_inc.c hss.h common_defs.h hss.h hash.h endian.h hss_internal.h hss_aux.h hss_reserve.h hss_derive.h lm_ots.h lm_ots_common.h hss_sign_inc.h +hss_sign_inc.o: hss_sign_inc.c hss.h common_defs.h hss.h hash.h endian.h hss_internal.h hss_aux.h hss_reserve.h hss_derive.h lm_ots.h lm_ots_common.h hss_sign_inc.h config.h $(CC) $(CFLAGS) -c hss_sign_inc.c -o $@ -hss_thread_single.o: hss_thread_single.c hss_thread.h +hss_thread_single.o: hss_thread_single.c hss_thread.h config.h $(CC) $(CFLAGS) -c hss_thread_single.c -o $@ -hss_thread_pthread.o: hss_thread_pthread.c hss_thread.h +hss_thread_pthread.o: hss_thread_pthread.c hss_thread.h config.h $(CC) $(CFLAGS) -c hss_thread_pthread.c -o $@ -hss_verify.o: hss_verify.c hss_verify.h common_defs.h lm_verify.h lm_common.h lm_ots_verify.h hash.h endian.h hss_thread.h +hss_verify.o: hss_verify.c hss_verify.h common_defs.h lm_verify.h lm_common.h lm_ots_verify.h hash.h endian.h hss_thread.h config.h $(CC) $(CFLAGS) -c hss_verify.c -o $@ -hss_verify_inc.o: hss_verify_inc.c hss_verify_inc.h common_defs.h lm_verify.h lm_common.h lm_ots_verify.h hash.h endian.h hss_thread.h +hss_verify_inc.o: hss_verify_inc.c hss_verify_inc.h common_defs.h lm_verify.h lm_common.h lm_ots_verify.h hash.h endian.h hss_thread.h config.h $(CC) $(CFLAGS) -c hss_verify_inc.c -o $@ -hss_zeroize.o: hss_zeroize.c hss_zeroize.h +hss_zeroize.o: hss_zeroize.c hss_zeroize.h config.h $(CC) $(CFLAGS) -c hss_zeroize.c -o $@ -lm_common.o: lm_common.c lm_common.h hash.h common_defs.h lm_ots_common.h +lm_common.o: lm_common.c lm_common.h hash.h common_defs.h lm_ots_common.h config.h $(CC) $(CFLAGS) -c lm_common.c -o $@ -lm_ots_common.o: lm_ots_common.c common_defs.h hash.h +lm_ots_common.o: lm_ots_common.c common_defs.h hash.h config.h $(CC) $(CFLAGS) -c lm_ots_common.c -o $@ -lm_ots_sign.o: lm_ots_sign.c common_defs.h lm_ots.h lm_ots_common.h hash.h endian.h hss_zeroize.h hss_derive.h +lm_ots_sign.o: lm_ots_sign.c common_defs.h lm_ots.h lm_ots_common.h hash.h endian.h hss_zeroize.h hss_derive.h config.h $(CC) $(CFLAGS) -c lm_ots_sign.c -o $@ -lm_ots_verify.o: lm_ots_verify.c lm_ots_verify.h lm_ots_common.h hash.h endian.h common_defs.h +lm_ots_verify.o: lm_ots_verify.c lm_ots_verify.h lm_ots_common.h hash.h endian.h common_defs.h config.h $(CC) $(CFLAGS) -c lm_ots_verify.c -o $@ -lm_verify.o: lm_verify.c lm_verify.h lm_common.h lm_ots_common.h lm_ots_verify.h hash.h endian.h common_defs.h +lm_verify.o: lm_verify.c lm_verify.h lm_common.h lm_ots_common.h lm_ots_verify.h hash.h endian.h common_defs.h config.h $(CC) $(CFLAGS) -c lm_verify.c -o $@ -endian.o: endian.c endian.h +endian.o: endian.c endian.h config.h $(CC) $(CFLAGS) -c endian.c -o $@ -hash.o: hash.c hash.h sha256.h hss_zeroize.h +hash.o: hash.c hash.h sha256.h fips202.h hss_zeroize.h config.h $(CC) $(CFLAGS) -c hash.c -o $@ -sha256.o: sha256.c sha256.h endian.h +sha256.o: sha256.c sha256.h endian.h config.h $(CC) $(CFLAGS) -c sha256.c -o $@ +fips202.o: fips202.c fips202.h + $(CC) $(CFLAGS) -c fips202.c -o $@ + clean: -rm *.o *.a demo test_hss diff --git a/README b/README index 36b2692..283400a 100644 --- a/README +++ b/README @@ -1,7 +1,6 @@ This code attempts to be a usable implementation of the LMS Hash Based Signature Scheme from RFC 8554. -See read.me for documentation how to use it. +This branch includes the parameter sets from draft-fluhrer-lms-more-parm-sets. -This is the ACVP branch - designed to be (optionally) compatible with the -public ACVP server +See read.me for documentation how to use it. diff --git a/common_defs.h b/common_defs.h index 8373994..831420c 100644 --- a/common_defs.h +++ b/common_defs.h @@ -26,7 +26,7 @@ #define MAX_HSS_LEVELS 8 /* Maximum levels we allow */ /* This is the length of our internal seed values */ -#define SEED_LEN 32 /* Enough to make Grover's infeasible */ +#define MAX_SEED_LEN 32 /* Enough to make Grover's infeasible */ /* Here are some internal types used within the code. They are listed more */ /* for documentation ("this is what this variable is expected to be") rather */ @@ -60,12 +60,41 @@ typedef uint_fast64_t sequence_t; #define LMS_SHA256_N32_H15 0x00000007 #define LMS_SHA256_N32_H20 0x00000008 #define LMS_SHA256_N32_H25 0x00000009 +#define LMS_SHA256_N24_H5 0x0000000a +#define LMS_SHA256_N24_H10 0x0000000b +#define LMS_SHA256_N24_H15 0x0000000c +#define LMS_SHA256_N24_H20 0x0000000d +#define LMS_SHA256_N24_H25 0x0000000e +#define LMS_SHAKE256_N32_H5 0x0000000f +#define LMS_SHAKE256_N32_H10 0x00000010 +#define LMS_SHAKE256_N32_H15 0x00000011 +#define LMS_SHAKE256_N32_H20 0x00000012 +#define LMS_SHAKE256_N32_H25 0x00000013 +#define LMS_SHAKE256_N24_H5 0x00000014 +#define LMS_SHAKE256_N24_H10 0x00000015 +#define LMS_SHAKE256_N24_H15 0x00000016 +#define LMS_SHAKE256_N24_H20 0x00000017 +#define LMS_SHAKE256_N24_H25 0x00000018 + /* LM-OTS registry */ #define LMOTS_SHA256_N32_W1 0x00000001 #define LMOTS_SHA256_N32_W2 0x00000002 #define LMOTS_SHA256_N32_W4 0x00000003 #define LMOTS_SHA256_N32_W8 0x00000004 +#define LMOTS_SHA256_N24_W1 0x00000005 +#define LMOTS_SHA256_N24_W2 0x00000006 +#define LMOTS_SHA256_N24_W4 0x00000007 +#define LMOTS_SHA256_N24_W8 0x00000008 +#define LMOTS_SHAKE256_N32_W1 0x00000009 +#define LMOTS_SHAKE256_N32_W2 0x0000000a +#define LMOTS_SHAKE256_N32_W4 0x0000000b +#define LMOTS_SHAKE256_N32_W8 0x0000000c +#define LMOTS_SHAKE256_N24_W1 0x0000000d +#define LMOTS_SHAKE256_N24_W2 0x0000000e +#define LMOTS_SHAKE256_N24_W4 0x0000000f +#define LMOTS_SHAKE256_N24_W8 0x00000010 + /* * Internal formats of various hashes diff --git a/demo.c b/demo.c index 583fe13..bc09871 100644 --- a/demo.c +++ b/demo.c @@ -61,7 +61,8 @@ const char *default_parm_set = "20/8,10/8"; static const char *seedbits = 0; static const char *i_value = 0; -static bool convert_specified_seed_i_value( void *, size_t ); +static size_t upper_hash_size; +static bool convert_specified_seed_i_value( void *, size_t, size_t ); /* * The HSS routines assume 3 user provided routines; here are the ones @@ -80,7 +81,7 @@ bool do_rand( void *output, size_t len ) { /* The seed was specified on the command line */ /* Return that exact seed and i */ /* This is not something a real application should do */ - return convert_specified_seed_i_value( output, len ); + return convert_specified_seed_i_value( output, len, upper_hash_size ); } struct { unsigned char dev_random_output[32]; @@ -251,13 +252,14 @@ static int fromhex(char c) { * This converts what the user specified into the format that * the library expects */ -static bool convert_specified_seed_i_value( void *buffer, size_t len) { +static bool convert_specified_seed_i_value( void *buffer, size_t len, + size_t upper_hash_size) { int i; const char *in = seedbits; unsigned char *out = buffer; for (i=0; i +static param_set_t pick( int hash_type, ... ) { + va_list ap; + + va_start(ap, hash_type); + int i; + param_set_t val = 0; + for (i=0; i<=hash_type; i++) { + val = va_arg( ap, param_set_t ); + } + va_end(ap); + return val; +} + /* * This parses the parameter set; this is provided so we can try different * sets without recompiling the program each time. This is placed here @@ -775,9 +803,30 @@ static int get_integer(const char **p) { */ static int parse_parm_set( int *levels, param_set_t *lm_array, param_set_t *ots_array, size_t *aux_size, - const char *parm_set) { + const char *parm_set, size_t *upper_hash_size) { int i; size_t aux = DEFAULT_AUX_DATA; + + int hash_type = 0; /* 1 -> 192 bit SHA256, 0 -> 256 bit SHA256 */ + /* 3 -> 192 bit SHAKE256, 2 -> 256 bit SHAKE256 */ + + /* Get the hash function. Now, HSS doesn't require us to use the same */ + /* hash function everywhere, however allowing different hash functions */ + /* at different places makes the parse strings ugly, and there's no */ + /* specific reason to actually use it */ + if (check_string( &parm_set, "SHA192," )) { + hash_type = 1; + } else if (check_string( &parm_set, "SHAKE192," )) { + hash_type = 3; + } else if (check_string( &parm_set, "SHAKE256," )) { + hash_type = 2; + } else { + /* Remove the initial SHA256, string, if present */ + (void)check_string( &parm_set, "SHA256," ); + hash_type = 0; + } + *upper_hash_size = pick( hash_type, 32, 24, 32, 24 ); + for (i=0;; i++) { if (i == 8) { printf( "Error: more than 8 HSS levels specified\n" ); @@ -787,26 +836,65 @@ static int parse_parm_set( int *levels, param_set_t *lm_array, int h = get_integer( &parm_set ); param_set_t lm; switch (h) { - case 5: lm = LMS_SHA256_N32_H5; break; - case 10: lm = LMS_SHA256_N32_H10; break; - case 15: lm = LMS_SHA256_N32_H15; break; - case 20: lm = LMS_SHA256_N32_H20; break; - case 25: lm = LMS_SHA256_N32_H25; break; + case 5: lm = pick( hash_type, LMS_SHA256_N32_H5, + LMS_SHA256_N24_H5, + LMS_SHAKE256_N32_H5, + LMS_SHAKE256_N24_H5 ); + break; + case 10: lm = pick( hash_type, LMS_SHA256_N32_H10, + LMS_SHA256_N24_H10, + LMS_SHAKE256_N32_H10, + LMS_SHAKE256_N24_H10 ); + break; + case 15: lm = pick( hash_type, LMS_SHA256_N32_H15, + LMS_SHA256_N24_H15, + LMS_SHAKE256_N32_H15, + LMS_SHAKE256_N24_H15 ); + break; + case 20: lm = pick( hash_type, LMS_SHA256_N32_H20, + LMS_SHA256_N24_H20, + LMS_SHAKE256_N32_H20, + LMS_SHAKE256_N24_H20 ); + break; + case 25: lm = pick( hash_type, LMS_SHA256_N32_H25, + LMS_SHA256_N24_H25, + LMS_SHAKE256_N32_H25, + LMS_SHAKE256_N24_H25 ); + break; case 0: printf( "Error: expected height of Merkle tree\n" ); return 0; default: printf( "Error: unsupported Merkle tree height %d\n", h ); printf( "Supported heights = 5, 10, 15, 20, 25\n" ); return 0; } /* Now see if we can get the Winternitz parameter */ - param_set_t ots = LMOTS_SHA256_N32_W8; + param_set_t ots = pick( hash_type, LMOTS_SHA256_N32_W8, + LMOTS_SHA256_N24_W8, + LMOTS_SHAKE256_N32_W8, + LMOTS_SHAKE256_N24_W8 ); if (*parm_set == '/') { parm_set++; int w = get_integer( &parm_set ); switch (w) { - case 1: ots = LMOTS_SHA256_N32_W1; break; - case 2: ots = LMOTS_SHA256_N32_W2; break; - case 4: ots = LMOTS_SHA256_N32_W4; break; - case 8: ots = LMOTS_SHA256_N32_W8; break; + case 1: ots = pick( hash_type, LMOTS_SHA256_N32_W1, + LMOTS_SHA256_N24_W1, + LMOTS_SHAKE256_N32_W1, + LMOTS_SHAKE256_N24_W1 ); + break; + case 2: ots = pick( hash_type, LMOTS_SHA256_N32_W2, + LMOTS_SHA256_N24_W2, + LMOTS_SHAKE256_N32_W2, + LMOTS_SHAKE256_N24_W2 ); + break; + case 4: ots = pick( hash_type, LMOTS_SHA256_N32_W4, + LMOTS_SHA256_N24_W4, + LMOTS_SHAKE256_N32_W4, + LMOTS_SHAKE256_N24_W4 ); + break; + case 8: ots = pick( hash_type, LMOTS_SHA256_N32_W8, + LMOTS_SHA256_N24_W8, + LMOTS_SHAKE256_N32_W8, + LMOTS_SHAKE256_N24_W8 ); + break; case 0: printf( "Error: expected Winternitz parameter\n" ); return 0; default: printf( "Error: unsupported Winternitz parameter %d\n", w ); printf( "Supported parmaeters = 1, 2, 4, 8\n" ); @@ -832,29 +920,73 @@ static int parse_parm_set( int *levels, param_set_t *lm_array, return 1; } +static const char *hash_name(int hash_type) { + switch (hash_type) { + case 0: return "SHA-256/192"; + case 1: return "SHA-256"; + case 2: return "SHAKE-256/192"; + case 3: return "SHAKE-256"; + default: return "???"; + } +} + static void list_parameter_set(int levels, const param_set_t *lm_array, const param_set_t *ots_array, size_t aux_size ) { printf( "Parameter set being used: there are %d levels of Merkle trees\n", levels ); int i; for (i=0; i 0) { printf( "Maximum of %lu bytes of aux data\n", (unsigned long)aux_size ); diff --git a/fips202.c b/fips202.c new file mode 100644 index 0000000..ceeb6a5 --- /dev/null +++ b/fips202.c @@ -0,0 +1,762 @@ +/* Based on the public domain implementation in + * crypto_hash/keccakc512/simple/ from http://bench.cr.yp.to/supercop.html + * by Ronny Van Keer + * and the public domain "TweetFips202" implementation + * from https://twitter.com/tweetfips202 + * by Gilles Van Assche, Daniel J. Bernstein, and Peter Schwabe */ + +#include +#include + +#include "fips202.h" + +#define NROUNDS 24 +#define ROL(a, offset) (((a) << (offset)) ^ ((a) >> (64 - (offset)))) + +/************************************************* + * Name: load64 + * + * Description: Load 8 bytes into uint64_t in little-endian order + * + * Arguments: - const uint8_t *x: pointer to input byte array + * + * Returns the loaded 64-bit unsigned integer + **************************************************/ +static uint64_t load64(const uint8_t *x) { + uint64_t r = 0; + for (size_t i = 0; i < 8; ++i) { + r |= (uint64_t)x[i] << 8 * i; + } + + return r; +} + +/************************************************* + * Name: store64 + * + * Description: Store a 64-bit integer to a byte array in little-endian order + * + * Arguments: - uint8_t *x: pointer to the output byte array + * - uint64_t u: input 64-bit unsigned integer + **************************************************/ +static void store64(uint8_t *x, uint64_t u) { + for (size_t i = 0; i < 8; ++i) { + x[i] = (uint8_t) (u >> 8 * i); + } +} + +/* Keccak round constants */ +static const uint64_t KeccakF_RoundConstants[NROUNDS] = { + 0x0000000000000001ULL, 0x0000000000008082ULL, + 0x800000000000808aULL, 0x8000000080008000ULL, + 0x000000000000808bULL, 0x0000000080000001ULL, + 0x8000000080008081ULL, 0x8000000000008009ULL, + 0x000000000000008aULL, 0x0000000000000088ULL, + 0x0000000080008009ULL, 0x000000008000000aULL, + 0x000000008000808bULL, 0x800000000000008bULL, + 0x8000000000008089ULL, 0x8000000000008003ULL, + 0x8000000000008002ULL, 0x8000000000000080ULL, + 0x000000000000800aULL, 0x800000008000000aULL, + 0x8000000080008081ULL, 0x8000000000008080ULL, + 0x0000000080000001ULL, 0x8000000080008008ULL +}; + +/************************************************* + * Name: KeccakF1600_StatePermute + * + * Description: The Keccak F1600 Permutation + * + * Arguments: - uint64_t *state: pointer to input/output Keccak state + **************************************************/ +static void KeccakF1600_StatePermute(uint64_t *state) { + int round; + + uint64_t Aba, Abe, Abi, Abo, Abu; + uint64_t Aga, Age, Agi, Ago, Agu; + uint64_t Aka, Ake, Aki, Ako, Aku; + uint64_t Ama, Ame, Ami, Amo, Amu; + uint64_t Asa, Ase, Asi, Aso, Asu; + uint64_t BCa, BCe, BCi, BCo, BCu; + uint64_t Da, De, Di, Do, Du; + uint64_t Eba, Ebe, Ebi, Ebo, Ebu; + uint64_t Ega, Ege, Egi, Ego, Egu; + uint64_t Eka, Eke, Eki, Eko, Eku; + uint64_t Ema, Eme, Emi, Emo, Emu; + uint64_t Esa, Ese, Esi, Eso, Esu; + + // copyFromState(A, state) + Aba = state[0]; + Abe = state[1]; + Abi = state[2]; + Abo = state[3]; + Abu = state[4]; + Aga = state[5]; + Age = state[6]; + Agi = state[7]; + Ago = state[8]; + Agu = state[9]; + Aka = state[10]; + Ake = state[11]; + Aki = state[12]; + Ako = state[13]; + Aku = state[14]; + Ama = state[15]; + Ame = state[16]; + Ami = state[17]; + Amo = state[18]; + Amu = state[19]; + Asa = state[20]; + Ase = state[21]; + Asi = state[22]; + Aso = state[23]; + Asu = state[24]; + + for (round = 0; round < NROUNDS; round += 2) { + // prepareTheta + BCa = Aba ^ Aga ^ Aka ^ Ama ^ Asa; + BCe = Abe ^ Age ^ Ake ^ Ame ^ Ase; + BCi = Abi ^ Agi ^ Aki ^ Ami ^ Asi; + BCo = Abo ^ Ago ^ Ako ^ Amo ^ Aso; + BCu = Abu ^ Agu ^ Aku ^ Amu ^ Asu; + + // thetaRhoPiChiIotaPrepareTheta(round , A, E) + Da = BCu ^ ROL(BCe, 1); + De = BCa ^ ROL(BCi, 1); + Di = BCe ^ ROL(BCo, 1); + Do = BCi ^ ROL(BCu, 1); + Du = BCo ^ ROL(BCa, 1); + + Aba ^= Da; + BCa = Aba; + Age ^= De; + BCe = ROL(Age, 44); + Aki ^= Di; + BCi = ROL(Aki, 43); + Amo ^= Do; + BCo = ROL(Amo, 21); + Asu ^= Du; + BCu = ROL(Asu, 14); + Eba = BCa ^ ((~BCe) & BCi); + Eba ^= KeccakF_RoundConstants[round]; + Ebe = BCe ^ ((~BCi) & BCo); + Ebi = BCi ^ ((~BCo) & BCu); + Ebo = BCo ^ ((~BCu) & BCa); + Ebu = BCu ^ ((~BCa) & BCe); + + Abo ^= Do; + BCa = ROL(Abo, 28); + Agu ^= Du; + BCe = ROL(Agu, 20); + Aka ^= Da; + BCi = ROL(Aka, 3); + Ame ^= De; + BCo = ROL(Ame, 45); + Asi ^= Di; + BCu = ROL(Asi, 61); + Ega = BCa ^ ((~BCe) & BCi); + Ege = BCe ^ ((~BCi) & BCo); + Egi = BCi ^ ((~BCo) & BCu); + Ego = BCo ^ ((~BCu) & BCa); + Egu = BCu ^ ((~BCa) & BCe); + + Abe ^= De; + BCa = ROL(Abe, 1); + Agi ^= Di; + BCe = ROL(Agi, 6); + Ako ^= Do; + BCi = ROL(Ako, 25); + Amu ^= Du; + BCo = ROL(Amu, 8); + Asa ^= Da; + BCu = ROL(Asa, 18); + Eka = BCa ^ ((~BCe) & BCi); + Eke = BCe ^ ((~BCi) & BCo); + Eki = BCi ^ ((~BCo) & BCu); + Eko = BCo ^ ((~BCu) & BCa); + Eku = BCu ^ ((~BCa) & BCe); + + Abu ^= Du; + BCa = ROL(Abu, 27); + Aga ^= Da; + BCe = ROL(Aga, 36); + Ake ^= De; + BCi = ROL(Ake, 10); + Ami ^= Di; + BCo = ROL(Ami, 15); + Aso ^= Do; + BCu = ROL(Aso, 56); + Ema = BCa ^ ((~BCe) & BCi); + Eme = BCe ^ ((~BCi) & BCo); + Emi = BCi ^ ((~BCo) & BCu); + Emo = BCo ^ ((~BCu) & BCa); + Emu = BCu ^ ((~BCa) & BCe); + + Abi ^= Di; + BCa = ROL(Abi, 62); + Ago ^= Do; + BCe = ROL(Ago, 55); + Aku ^= Du; + BCi = ROL(Aku, 39); + Ama ^= Da; + BCo = ROL(Ama, 41); + Ase ^= De; + BCu = ROL(Ase, 2); + Esa = BCa ^ ((~BCe) & BCi); + Ese = BCe ^ ((~BCi) & BCo); + Esi = BCi ^ ((~BCo) & BCu); + Eso = BCo ^ ((~BCu) & BCa); + Esu = BCu ^ ((~BCa) & BCe); + + // prepareTheta + BCa = Eba ^ Ega ^ Eka ^ Ema ^ Esa; + BCe = Ebe ^ Ege ^ Eke ^ Eme ^ Ese; + BCi = Ebi ^ Egi ^ Eki ^ Emi ^ Esi; + BCo = Ebo ^ Ego ^ Eko ^ Emo ^ Eso; + BCu = Ebu ^ Egu ^ Eku ^ Emu ^ Esu; + + // thetaRhoPiChiIotaPrepareTheta(round+1, E, A) + Da = BCu ^ ROL(BCe, 1); + De = BCa ^ ROL(BCi, 1); + Di = BCe ^ ROL(BCo, 1); + Do = BCi ^ ROL(BCu, 1); + Du = BCo ^ ROL(BCa, 1); + + Eba ^= Da; + BCa = Eba; + Ege ^= De; + BCe = ROL(Ege, 44); + Eki ^= Di; + BCi = ROL(Eki, 43); + Emo ^= Do; + BCo = ROL(Emo, 21); + Esu ^= Du; + BCu = ROL(Esu, 14); + Aba = BCa ^ ((~BCe) & BCi); + Aba ^= KeccakF_RoundConstants[round + 1]; + Abe = BCe ^ ((~BCi) & BCo); + Abi = BCi ^ ((~BCo) & BCu); + Abo = BCo ^ ((~BCu) & BCa); + Abu = BCu ^ ((~BCa) & BCe); + + Ebo ^= Do; + BCa = ROL(Ebo, 28); + Egu ^= Du; + BCe = ROL(Egu, 20); + Eka ^= Da; + BCi = ROL(Eka, 3); + Eme ^= De; + BCo = ROL(Eme, 45); + Esi ^= Di; + BCu = ROL(Esi, 61); + Aga = BCa ^ ((~BCe) & BCi); + Age = BCe ^ ((~BCi) & BCo); + Agi = BCi ^ ((~BCo) & BCu); + Ago = BCo ^ ((~BCu) & BCa); + Agu = BCu ^ ((~BCa) & BCe); + + Ebe ^= De; + BCa = ROL(Ebe, 1); + Egi ^= Di; + BCe = ROL(Egi, 6); + Eko ^= Do; + BCi = ROL(Eko, 25); + Emu ^= Du; + BCo = ROL(Emu, 8); + Esa ^= Da; + BCu = ROL(Esa, 18); + Aka = BCa ^ ((~BCe) & BCi); + Ake = BCe ^ ((~BCi) & BCo); + Aki = BCi ^ ((~BCo) & BCu); + Ako = BCo ^ ((~BCu) & BCa); + Aku = BCu ^ ((~BCa) & BCe); + + Ebu ^= Du; + BCa = ROL(Ebu, 27); + Ega ^= Da; + BCe = ROL(Ega, 36); + Eke ^= De; + BCi = ROL(Eke, 10); + Emi ^= Di; + BCo = ROL(Emi, 15); + Eso ^= Do; + BCu = ROL(Eso, 56); + Ama = BCa ^ ((~BCe) & BCi); + Ame = BCe ^ ((~BCi) & BCo); + Ami = BCi ^ ((~BCo) & BCu); + Amo = BCo ^ ((~BCu) & BCa); + Amu = BCu ^ ((~BCa) & BCe); + + Ebi ^= Di; + BCa = ROL(Ebi, 62); + Ego ^= Do; + BCe = ROL(Ego, 55); + Eku ^= Du; + BCi = ROL(Eku, 39); + Ema ^= Da; + BCo = ROL(Ema, 41); + Ese ^= De; + BCu = ROL(Ese, 2); + Asa = BCa ^ ((~BCe) & BCi); + Ase = BCe ^ ((~BCi) & BCo); + Asi = BCi ^ ((~BCo) & BCu); + Aso = BCo ^ ((~BCu) & BCa); + Asu = BCu ^ ((~BCa) & BCe); + } + + // copyToState(state, A) + state[0] = Aba; + state[1] = Abe; + state[2] = Abi; + state[3] = Abo; + state[4] = Abu; + state[5] = Aga; + state[6] = Age; + state[7] = Agi; + state[8] = Ago; + state[9] = Agu; + state[10] = Aka; + state[11] = Ake; + state[12] = Aki; + state[13] = Ako; + state[14] = Aku; + state[15] = Ama; + state[16] = Ame; + state[17] = Ami; + state[18] = Amo; + state[19] = Amu; + state[20] = Asa; + state[21] = Ase; + state[22] = Asi; + state[23] = Aso; + state[24] = Asu; +} + +/************************************************* + * Name: keccak_absorb + * + * Description: Absorb step of Keccak; + * non-incremental, starts by zeroeing the state. + * + * Arguments: - uint64_t *s: pointer to (uninitialized) output Keccak state + * - uint32_t r: rate in bytes (e.g., 168 for SHAKE128) + * - const uint8_t *m: pointer to input to be absorbed into s + * - size_t mlen: length of input in bytes + * - uint8_t p: domain-separation byte for different + * Keccak-derived functions + **************************************************/ +static void keccak_absorb(uint64_t *s, uint32_t r, const uint8_t *m, + size_t mlen, uint8_t p) { + size_t i; + uint8_t t[200]; + + /* Zero state */ + for (i = 0; i < 25; ++i) { + s[i] = 0; + } + + while (mlen >= r) { + for (i = 0; i < r / 8; ++i) { + s[i] ^= load64(m + 8 * i); + } + + KeccakF1600_StatePermute(s); + mlen -= r; + m += r; + } + + for (i = 0; i < r; ++i) { + t[i] = 0; + } + for (i = 0; i < mlen; ++i) { + t[i] = m[i]; + } + t[i] = p; + t[r - 1] |= 128; + for (i = 0; i < r / 8; ++i) { + s[i] ^= load64(t + 8 * i); + } +} + +/************************************************* + * Name: keccak_squeezeblocks + * + * Description: Squeeze step of Keccak. Squeezes full blocks of r bytes each. + * Modifies the state. Can be called multiple times to keep + * squeezing, i.e., is incremental. + * + * Arguments: - uint8_t *h: pointer to output blocks + * - size_t nblocks: number of blocks to be + * squeezed (written to h) + * - uint64_t *s: pointer to input/output Keccak state + * - uint32_t r: rate in bytes (e.g., 168 for SHAKE128) + **************************************************/ +static void keccak_squeezeblocks(uint8_t *h, size_t nblocks, + uint64_t *s, uint32_t r) { + while (nblocks > 0) { + KeccakF1600_StatePermute(s); + for (size_t i = 0; i < (r >> 3); i++) { + store64(h + 8 * i, s[i]); + } + h += r; + nblocks--; + } +} + +/************************************************* + * Name: keccak_inc_init + * + * Description: Initializes the incremental Keccak state to zero. + * + * Arguments: - uint64_t *s_inc: pointer to input/output incremental state + * First 25 values represent Keccak state. + * 26th value represents either the number of absorbed bytes + * that have not been permuted, or not-yet-squeezed bytes. + **************************************************/ +static void keccak_inc_init(uint64_t *s_inc) { + size_t i; + + for (i = 0; i < 25; ++i) { + s_inc[i] = 0; + } + s_inc[25] = 0; +} + +/************************************************* + * Name: keccak_inc_absorb + * + * Description: Incremental keccak absorb + * Preceded by keccak_inc_init, succeeded by keccak_inc_finalize + * + * Arguments: - uint64_t *s_inc: pointer to input/output incremental state + * First 25 values represent Keccak state. + * 26th value represents either the number of absorbed bytes + * that have not been permuted, or not-yet-squeezed bytes. + * - uint32_t r: rate in bytes (e.g., 168 for SHAKE128) + * - const uint8_t *m: pointer to input to be absorbed into s + * - size_t mlen: length of input in bytes + **************************************************/ +static void keccak_inc_absorb(uint64_t *s_inc, uint32_t r, const uint8_t *m, + size_t mlen) { + size_t i; + + /* 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++) { + /* 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)); + } + mlen -= (size_t)(r - s_inc[25]); + m += r - s_inc[25]; + s_inc[25] = 0; + + KeccakF1600_StatePermute(s_inc); + } + + for (i = 0; i < mlen; i++) { + s_inc[(s_inc[25] + i) >> 3] ^= (uint64_t)m[i] << (8 * ((s_inc[25] + i) & 0x07)); + } + s_inc[25] += mlen; +} + +/************************************************* + * Name: keccak_inc_finalize + * + * Description: Finalizes Keccak absorb phase, prepares for squeezing + * + * Arguments: - uint64_t *s_inc: pointer to input/output incremental state + * First 25 values represent Keccak state. + * 26th value represents either the number of absorbed bytes + * that have not been permuted, or not-yet-squeezed bytes. + * - uint32_t r: rate in bytes (e.g., 168 for SHAKE128) + * - uint8_t p: domain-separation byte for different + * Keccak-derived functions + **************************************************/ +static void keccak_inc_finalize(uint64_t *s_inc, uint32_t r, uint8_t p) { + /* After keccak_inc_absorb, we are guaranteed that s_inc[25] < r, + so we can always use one more byte for p in the current state. */ + s_inc[s_inc[25] >> 3] ^= (uint64_t)p << (8 * (s_inc[25] & 0x07)); + s_inc[(r - 1) >> 3] ^= (uint64_t)128 << (8 * ((r - 1) & 0x07)); + s_inc[25] = 0; +} + +/************************************************* + * Name: keccak_inc_squeeze + * + * Description: Incremental Keccak squeeze; can be called on byte-level + * + * Arguments: - uint8_t *h: pointer to output bytes + * - size_t outlen: number of bytes to be squeezed + * - uint64_t *s_inc: pointer to input/output incremental state + * First 25 values represent Keccak state. + * 26th value represents either the number of absorbed bytes + * that have not been permuted, or not-yet-squeezed bytes. + * - uint32_t r: rate in bytes (e.g., 168 for SHAKE128) + **************************************************/ +static void keccak_inc_squeeze(uint8_t *h, size_t outlen, + uint64_t *s_inc, uint32_t r) { + size_t i; + + /* First consume any bytes we still have sitting around */ + for (i = 0; i < outlen && i < s_inc[25]; i++) { + /* There are s_inc[25] bytes left, so r - s_inc[25] is the first + available byte. We consume from there, i.e., up to r. */ + h[i] = (uint8_t)(s_inc[(r - s_inc[25] + i) >> 3] >> (8 * ((r - s_inc[25] + i) & 0x07))); + } + h += i; + outlen -= i; + s_inc[25] -= i; + + /* Then squeeze the remaining necessary blocks */ + while (outlen > 0) { + KeccakF1600_StatePermute(s_inc); + + for (i = 0; i < outlen && i < r; i++) { + h[i] = (uint8_t)(s_inc[i >> 3] >> (8 * (i & 0x07))); + } + h += i; + outlen -= i; + s_inc[25] = r - i; + } +} + +void shake128_inc_init(uint64_t *s_inc) { + keccak_inc_init(s_inc); +} + +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_finalize(uint64_t *s_inc) { + keccak_inc_finalize(s_inc, 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 shake256_inc_init(uint64_t *s_inc) { + keccak_inc_init(s_inc); +} + +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 shake256_inc_finalize(uint64_t *s_inc) { + keccak_inc_finalize(s_inc, SHAKE256_RATE, 0x1F); +} + +void shake256_inc_squeeze(uint8_t *output, size_t outlen, uint64_t *s_inc) { + keccak_inc_squeeze(output, outlen, s_inc, SHAKE256_RATE); +} + + +/************************************************* + * Name: shake128_absorb + * + * Description: Absorb step of the SHAKE128 XOF. + * non-incremental, starts by zeroeing the state. + * + * Arguments: - uint64_t *s: 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 shake128_absorb(uint64_t *s, const uint8_t *input, size_t inlen) { + keccak_absorb(s, SHAKE128_RATE, input, inlen, 0x1F); +} + +/************************************************* + * Name: shake128_squeezeblocks + * + * Description: Squeeze step of SHAKE128 XOF. Squeezes full blocks of + * SHAKE128_RATE bytes each. Modifies the state. Can be called + * multiple times to keep squeezing, i.e., is incremental. + * + * 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 + **************************************************/ +void shake128_squeezeblocks(uint8_t *output, size_t nblocks, uint64_t *s) { + keccak_squeezeblocks(output, nblocks, s, SHAKE128_RATE); +} + +/************************************************* + * Name: shake256_absorb + * + * Description: Absorb step of the SHAKE256 XOF. + * non-incremental, starts by zeroeing the state. + * + * Arguments: - uint64_t *s: 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); +} + +/************************************************* + * Name: shake256_squeezeblocks + * + * Description: Squeeze step of SHAKE256 XOF. Squeezes full blocks of + * SHAKE256_RATE bytes each. Modifies the state. Can be called + * multiple times to keep squeezing, i.e., is incremental. + * + * 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 + **************************************************/ +void shake256_squeezeblocks(uint8_t *output, size_t nblocks, uint64_t *s) { + keccak_squeezeblocks(output, nblocks, s, SHAKE256_RATE); +} + +/************************************************* + * Name: shake128 + * + * Description: SHAKE128 XOF with non-incremental API + * + * Arguments: - uint8_t *output: pointer to output + * - size_t outlen: requested output length in bytes + * - const uint8_t *input: pointer to input + * - size_t inlen: length of input in bytes + **************************************************/ +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]; + + 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); + for (size_t i = 0; i < outlen; ++i) { + output[i] = t[i]; + } + } +} + +/************************************************* + * Name: shake256 + * + * Description: SHAKE256 XOF with non-incremental API + * + * Arguments: - uint8_t *output: pointer to output + * - size_t outlen: requested output length in bytes + * - const uint8_t *input: pointer to input + * - size_t inlen: length of input in bytes + **************************************************/ +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]; + + 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); + 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]; + } +} diff --git a/fips202.h b/fips202.h new file mode 100644 index 0000000..0aca0a1 --- /dev/null +++ b/fips202.h @@ -0,0 +1,50 @@ +#ifndef FIPS202_H_ +#define FIPS202_H_ + +#include +#include + +#define SHAKE128_RATE 168 +#define SHAKE256_RATE 136 +#define SHA3_256_RATE 136 +#define SHA3_512_RATE 72 + +typedef uint64_t keccak_state[26]; /* index 25 is used to store the */ + /* current offset */ + +void shake128_absorb(uint64_t *s, const uint8_t *input, size_t inlen); + +void shake128_squeezeblocks(uint8_t *output, size_t nblocks, uint64_t *s); + +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); + +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); + +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); + +void shake128(uint8_t *output, size_t outlen, + const uint8_t *input, size_t inlen); + +void shake256(uint8_t *output, size_t outlen, + const uint8_t *input, size_t inlen); + +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); + +void sha3_256(uint8_t *output, const uint8_t *input, size_t inlen); + +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); + +void sha3_512(uint8_t *output, const uint8_t *input, size_t inlen); + +#endif /* FIPS202_H_ */ diff --git a/hash.c b/hash.c index ea5b376..efc9d03 100644 --- a/hash.c +++ b/hash.c @@ -1,6 +1,7 @@ #include #include "hash.h" #include "sha256.h" +#include "fips202.h" #include "hss_zeroize.h" #define ALLOW_VERBOSE 0 /* 1 -> we allow the dumping of intermediate */ @@ -37,20 +38,39 @@ void hss_hash_ctx(void *result, int hash_type, union hash_context *ctx, } #endif + int output_len; switch (hash_type) { case HASH_SHA256: { SHA256_Init(&ctx->sha256); SHA256_Update(&ctx->sha256, message, message_len); SHA256_Final(result, &ctx->sha256); -#if ALLOW_VERBOSE - if (hss_verbose) { - printf( " ->" ); - int i; for (i=0; i<32; i++) printf( " %02x", ((unsigned char *)result)[i] ); printf( "\n" ); - } -#endif + output_len = 32; + break; + } + case HASH_SHA256_24: { + unsigned char temp[SHA256_LEN]; + SHA256_Init(&ctx->sha256); + SHA256_Update(&ctx->sha256, message, message_len); + SHA256_Final(temp, &ctx->sha256); + memcpy(result, temp, 24 ); + hss_zeroize(temp, sizeof temp); + output_len = 24; break; } + case HASH_SHAKE256: case HASH_SHAKE256_24: + shake256_inc_init(ctx->shake256); + shake256_inc_absorb(ctx->shake256, message, message_len); + shake256_inc_finalize(ctx->shake256); + output_len = hss_hash_length(hash_type); + shake256_inc_squeeze(result, output_len, ctx->shake256); + break; } +#if ALLOW_VERBOSE + if (hss_verbose) { + printf( " ->" ); + int i; for (i=0; isha256 ); break; + case HASH_SHAKE256: case HASH_SHAKE256_24: + shake256_inc_init(ctx->shake256); + break; } } @@ -82,38 +105,67 @@ void hss_update_hash_context(int h, union hash_context *ctx, } #endif switch (h) { - case HASH_SHA256: + case HASH_SHA256: case HASH_SHA256_24: SHA256_Update(&ctx->sha256, msg, len_msg); break; + case HASH_SHAKE256: case HASH_SHAKE256_24: + shake256_inc_absorb(ctx->shake256, msg, len_msg); + break; } } void hss_finalize_hash_context(int h, union hash_context *ctx, void *buffer) { + int output_len; switch (h) { case HASH_SHA256: SHA256_Final(buffer, &ctx->sha256); + output_len = 32; + break; + case HASH_SHA256_24: { + unsigned char temp[SHA256_LEN]; + SHA256_Final(temp, &ctx->sha256); + memcpy(buffer, temp, 24); + hss_zeroize(temp, sizeof temp); + output_len = 24; + break; + } + case HASH_SHAKE256: + output_len = 32; + shake256_inc_finalize(ctx->shake256); + shake256_inc_squeeze(buffer, output_len, ctx->shake256); + break; + case HASH_SHAKE256_24: + output_len = 24; + shake256_inc_finalize(ctx->shake256); + shake256_inc_squeeze(buffer, output_len, ctx->shake256); + break; + } #if ALLOW_VERBOSE if (hss_verbose) { printf( " -->" ); - int i; for (i=0; i<32; i++) printf( " %02x", ((unsigned char*)buffer)[i] ); + int i; for (i=0; i #include @@ -15,10 +16,14 @@ */ enum { HASH_SHA256 = 1, /* SHA256 */ + HASH_SHA256_24 = 2, /* SHA256 truncated to 24 bytes */ + HASH_SHAKE256 = 3, /* SHAKE256 */ + HASH_SHAKE256_24 = 4, /* SHAKE256 truncated to 24 bytes */ }; union hash_context { SHA256_CTX sha256; + keccak_state shake256; /* Any other hash contexts would go here */ }; diff --git a/hss.c b/hss.c index 13aeeea..3fcfe07 100644 --- a/hss.c +++ b/hss.c @@ -15,6 +15,7 @@ #include "hss_derive.h" #include "config.h" #include "lm_ots_common.h" +#include "lm_common.h" /* * Allocate and load an ephemeral key @@ -31,7 +32,8 @@ struct hss_working_key *hss_load_private_key( unsigned levels; param_set_t lm[ MAX_HSS_LEVELS ]; param_set_t ots[ MAX_HSS_LEVELS ]; - if (!hss_get_parameter_set( &levels, lm, ots, read_private_key, context)) { + if (!hss_get_parameter_set( &levels, lm, ots, + read_private_key, context, info)) { /* Can't read private key, or private key invalid */ return 0; } @@ -65,12 +67,14 @@ struct hss_working_key *hss_load_private_key( * we don't need to store it in our private key; we can recompute them */ bool hss_generate_root_seed_I_value(unsigned char *seed, unsigned char *I, - const unsigned char *master_seed) { + const unsigned char *master_seed, + param_set_t lm, param_set_t ots) { #if SECRET_METHOD == 2 + size_t seed_len = hss_seed_size(lm); /* In ACVP mode, we use the master seed as the source for both the */ /* root seed, and the root I value */ - memcpy( seed, master_seed, SEED_LEN ); - memcpy( I, master_seed + SEED_LEN, I_LEN ); + memcpy( seed, master_seed, seed_len ); + memcpy( I, master_seed + seed_len, I_LEN ); #else /* * We use a two-level hashing scheme so that we end up using the master @@ -115,6 +119,22 @@ bool hss_generate_root_seed_I_value(unsigned char *seed, unsigned char *I, return true; } +/* + * This returns the size of the seed we use for a Merkle tree level that + * uses the specified parameter set + */ +size_t hss_seed_size(param_set_t lm) { +#if SECRET_METHOD == 2 + unsigned m; /* Length of the seed depends on the hash function that LM uses */ + if (!lm_look_up_parameter_set( lm, 0, &m, 0 )) { + return 0; + } + return m; +#else + return SEED_LEN; /* We always use the same length seed */ +#endif +} + /* * Internal function to generate the child I value (based on the parent's * I value). While this needs to be determanistic (so that we can create the @@ -123,12 +143,14 @@ bool hss_generate_root_seed_I_value(unsigned char *seed, unsigned char *I, * we needn't update this. */ bool hss_generate_child_seed_I_value( unsigned char *seed, unsigned char *I, - const unsigned char *parent_seed, + const unsigned char *parent_seed, size_t parent_seed_len, const unsigned char *parent_I, + size_t child_seed_len, merkle_index_t index, param_set_t lm, param_set_t ots) { struct seed_derive derive; - if (!hss_seed_derive_init( &derive, lm, ots, parent_I, parent_seed )) { + if (!hss_seed_derive_init( &derive, lm, ots, parent_I, parent_seed, + parent_seed_len )) { return false; } @@ -136,14 +158,12 @@ bool hss_generate_child_seed_I_value( unsigned char *seed, unsigned char *I, /* Compute the child seed value */ hss_seed_derive_set_j( &derive, SEED_CHILD_SEED ); - hss_seed_derive( seed, &derive, true ); + hss_seed_derive( seed, child_seed_len, &derive, true ); /* True sets the j value to SEED_CHILD_I */ /* Compute the child I value; with increment_j set to true in the */ /* above call, derive has been set to the SEED_CHILD_I position */ - unsigned char postimage[ SEED_LEN ]; - hss_seed_derive( postimage, &derive, false ); - memcpy( I, postimage, I_LEN ); + hss_seed_derive( I, I_LEN, &derive, false ); hss_seed_derive_done( &derive ); diff --git a/hss.h b/hss.h index 6880ce6..7217c84 100644 --- a/hss.h +++ b/hss.h @@ -299,7 +299,7 @@ bool hss_set_autoreserve( size_t hss_get_private_key_len(unsigned levels, const param_set_t *lm_type, const param_set_t *lm_ots_type); -#define HSS_MAX_PRIVATE_KEY_LEN (8 + 8 + SEED_LEN + 16) +#define HSS_MAX_PRIVATE_KEY_LEN (8 + 16 + MAX_SEED_LEN + 16) /* * This include file has the functions that contains the lengths of the other @@ -331,7 +331,7 @@ size_t hss_get_aux_data_len(size_t max_length, * This is here to solve a chicken-and-egg problem: the hss_working_key * must be initialized to the same parameter set as the private key, * but (other than this function, or somehow remembering it) there's - * no way to retreive the parameter set. + * no way to retrieve the parameter set. * * read_private_key/context will read the private key (if read_private_key is * NULL, context is assumed to point to the private key) @@ -347,12 +347,13 @@ bool hss_get_parameter_set( unsigned *levels, param_set_t lm_ots_type[ MAX_HSS_LEVELS ], bool (*read_private_key)(unsigned char *private_key, size_t len_private_key, void *context), - void *context); + void *context, + struct hss_extra_info *info); enum hss_error_code { hss_error_none = 0, /* I don't know nothing about any error */ - hss_range_normal_failures, /* There errors happen during normal use */ + hss_range_normal_failures, /* These errors happen during normal use */ /* of the signature scheme */ hss_error_bad_signature, /* Invalid signature */ hss_error_private_key_expired, /* This private key has generated all */ @@ -381,9 +382,10 @@ enum hss_error_code { /* properly */ hss_error_ctx_already_used, /* The ctx has already been used */ hss_error_bad_public_key, /* Somehow, we got an invalid public key */ + hss_error_bad_private_key, /* Somehow, we got an invalid private key */ - hss_range_processing_error, /* These errors are cause by an */ - /* error while processing */ + hss_range_processing_error, /* These errors are caused by an */ + /* error detected by an external function */ hss_error_bad_randomness, /* The RNG claimed failure */ hss_error_private_key_write_failed, /* The write of the private key */ /* to NVRAM failed */ diff --git a/hss_alloc.c b/hss_alloc.c index 1980193..9993931 100644 --- a/hss_alloc.c +++ b/hss_alloc.c @@ -8,6 +8,7 @@ #include "hss.h" #include "hss_internal.h" #include "lm_common.h" +#include "lm_ots_common.h" #define MALLOC_OVERHEAD 8 /* Our simplistic model about the overhead */ /* that malloc takes up is that it adds 8 */ @@ -451,6 +452,8 @@ printf( "Allocation = %ld\n", initial_mem_target - mem_target + best_mem ); /* D tree->level = h0; tree->h = level_hash[i]; tree->hash_size = hash_size[i]; + lm_ots_look_up_parameter_set( lm_ots_type[i], &tree->lms_hash, + &tree->lms_hash_size, 0, 0, 0 ); tree->lm_type = lm_type[i]; tree->lm_ots_type = lm_ots_type[i]; /* We'll initialize current_index from the private key */ diff --git a/hss_aux.c b/hss_aux.c index 650e968..7208a1a 100644 --- a/hss_aux.c +++ b/hss_aux.c @@ -237,7 +237,7 @@ static void compute_seed_derive( unsigned char *result, unsigned hash, memset( prefix, 0, DAUX_D ); SET_D( prefix + DAUX_D, D_DAUX ); hss_update_hash_context( hash, ctx, prefix, sizeof prefix ); - hss_update_hash_context( hash, ctx, seed, SEED_LEN ); + hss_update_hash_context( hash, ctx, seed, hss_hash_length(hash) ); hss_finalize_hash_context( hash, ctx, result ); hss_zeroize( &ctx, sizeof ctx ); diff --git a/hss_compute.c b/hss_compute.c index 553dd21..e36f8f8 100644 --- a/hss_compute.c +++ b/hss_compute.c @@ -58,7 +58,7 @@ static enum hss_error_code hss_compute_internal_node( unsigned char *dest, struct seed_derive derive; if (!hss_seed_derive_init( &derive, lm_type, lm_ots_type, - I, seed)) { + I, seed, hss_seed_size(lm_type))) { return hss_error_bad_param_set; } @@ -87,7 +87,7 @@ static enum hss_error_code hss_compute_internal_node( unsigned char *dest, /* Hash it to form the leaf node */ put_bigendian( pub_key + LEAF_R, r, 4); union hash_context ctx; - hss_hash_ctx( current_buf, h, &ctx, pub_key, LEAF_LEN(hash_size) ); + hss_hash_ctx( current_buf, h, &ctx, pub_key, LEAF_LEN(ots_len) ); /* Work up the stack, combining right nodes with the left nodes */ /* that we've already computed */ diff --git a/hss_derive.c b/hss_derive.c index 89a2757..d1ca5fc 100644 --- a/hss_derive.c +++ b/hss_derive.c @@ -46,21 +46,17 @@ /* This creates a seed derivation object */ bool hss_seed_derive_init( struct seed_derive *derive, param_set_t lm, param_set_t ots, - const unsigned char *I, const unsigned char *seed ) { + const unsigned char *I, + const unsigned char *seed, size_t seed_len ) { derive->I = I; derive->master_seed = seed; /* q, j will be set later */ #if SECRET_METHOD == 2 + derive->master_seed_len = seed_len; /* Grab the hash function to use */ if (!lm_look_up_parameter_set(lm, &derive->hash, &derive->m, 0)) { return false; } - - /* Note: currently, this assumes that the hash length is always 256 */ - /* bits; error out if that isn't the case */ - if (derive->m != SEED_LEN) { - return false; - } #endif return true; @@ -79,24 +75,39 @@ void hss_seed_derive_set_j( struct seed_derive *derive, unsigned j ) { /* This derives the current seed value. If increment_j is set, it'll then */ /* reset the object to the next j value */ -void hss_seed_derive( unsigned char *seed, struct seed_derive *derive, +void hss_seed_derive( unsigned char *seed, size_t output_len, struct seed_derive *derive, bool increment_j ) { +#if SECRET_METHOD == 2 + int hash = derive->hash; /* Use the parameter set's hash function */ + unsigned m = derive->m; /* And get it's length */ + unsigned master_seed_len = derive->master_seed_len; +#else + int hash = HASH; /* Use our standard one */ + unsigned master_seed_len = SEED_LEN; +#endif + unsigned char buffer[ PRG_MAX_LEN ]; memcpy( buffer + PRG_I, derive->I, I_LEN ); put_bigendian( buffer + PRG_Q, derive->q, 4 ); put_bigendian( buffer + PRG_J, derive->j, 2 ); buffer[PRG_FF] = 0xff; - memcpy( buffer + PRG_SEED, derive->master_seed, SEED_LEN ); + memcpy( buffer + PRG_SEED, derive->master_seed, master_seed_len ); + + /* Hash the random string, place the result into the same buffer (no */ + /* reason to dirty more than one pan) */ + hss_hash( buffer, hash, buffer, PRG_LEN(master_seed_len) ); #if SECRET_METHOD == 2 - int hash = derive->hash; /* Our the parameter set's hash function */ -#else - int hash = HASH; /* Use our standard one */ + if (output_len > m) { + /* The length wanted is more than the number of bytes the hash gives us */ + /* Pad the rest of the seed with 0's */ + memset( seed + m, 0, output_len - m ); + output_len = m; + } #endif + memcpy( seed, buffer, output_len ); - hss_hash( seed, hash, buffer, PRG_LEN(SEED_LEN) ); - - hss_zeroize( buffer, PRG_LEN(SEED_LEN) ); + hss_zeroize( buffer, PRG_LEN(MAX_SEED_LEN) ); if (increment_j) derive->j += 1; } @@ -128,7 +139,8 @@ static unsigned my_log2(merkle_index_t n); /* This creates a seed derivation object */ bool hss_seed_derive_init( struct seed_derive *derive, param_set_t lm, param_set_t ots, - const unsigned char *I, const unsigned char *seed ) { + const unsigned char *I, + const unsigned char *seed, size_t seed_len ) { derive->I = I; derive->master_seed = seed; @@ -264,9 +276,9 @@ void hss_seed_derive_set_j( struct seed_derive *derive, unsigned j ) { /* it); we just need to copy it to the buffer) */ /* If increment_j is set, it'll then reset the object to the next j value */ /* (which means incrementally computing that path) */ -void hss_seed_derive( unsigned char *seed, struct seed_derive *derive, - bool increment_j ) { - memcpy( seed, derive->j_seed[ derive->j_levels - 1], SEED_LEN ); +void hss_seed_derive( unsigned char *seed, size_t output_len, + struct seed_derive *derive, bool increment_j ) { + memcpy( seed, derive->j_seed[ derive->j_levels - 1], output_len ); if (increment_j) { int i; diff --git a/hss_derive.h b/hss_derive.h index ee47eb6..9b8a15e 100644 --- a/hss_derive.h +++ b/hss_derive.h @@ -1,6 +1,7 @@ #if !defined( HSS_DERIVE_H_ ) #define HSS_DERIVE_H_ +#include #include "common_defs.h" #include "config.h" @@ -18,6 +19,7 @@ struct seed_derive { #if SECRET_METHOD == 2 unsigned hash; /* Hash function to use */ unsigned m; /* Length of hash function */ + unsigned master_seed_len; #endif #if SECRET_METHOD == 1 @@ -33,14 +35,15 @@ struct seed_derive { /* the parent it is; the higher bits indicate the parents' */ /* identities */ - unsigned char q_seed[MAX_Q_HEIGHT][SEED_LEN]; - unsigned char j_seed[MAX_Q_HEIGHT][SEED_LEN]; + unsigned char q_seed[MAX_Q_HEIGHT][MAX_SEED_LEN]; + unsigned char j_seed[MAX_Q_HEIGHT][MAX_SEED_LEN]; #endif }; bool hss_seed_derive_init( struct seed_derive *derive, param_set_t lm, param_set_t ots, - const unsigned char *I, const unsigned char *seed ); + const unsigned char *I, + const unsigned char *seed, size_t seed_len ); /* This sets the internal 'q' value */ /* If we've already have a 'q' value set, it'll try to minimize the number */ @@ -64,8 +67,9 @@ void hss_seed_derive_set_j( struct seed_derive *derive, unsigned j ); /* This generates the current seed. If increment_j is set, this will set */ /* up for the next j value */ -void hss_seed_derive( unsigned char *seed, struct seed_derive *derive, - bool increment_j ); +/* output_len is the length of the seed to generate */ +void hss_seed_derive( unsigned char *seed, size_t output_len, + struct seed_derive *derive, bool increment_j ); /* This needs to be called when we done with a seed_derive */ /* That structure contains keying data, this makes sure those are cleaned */ diff --git a/hss_generate.c b/hss_generate.c index 1f9c500..6f0a1cf 100644 --- a/hss_generate.c +++ b/hss_generate.c @@ -254,15 +254,35 @@ bool hss_generate_working_key( } /* Read the private key */ - unsigned char private_key[ PRIVATE_KEY_LEN ]; + unsigned char private_key[ PRIVATE_KEY_LEN(MAX_SEED_LEN) ]; +#if SECRET_METHOD == 2 + int try; + int seed_len = MIN_SEED_LEN; + for (try=0; try<2; try++) { + if (read_private_key) { + if (!read_private_key( private_key, PRIVATE_KEY_LEN(seed_len), context)) { + info->error_code = hss_error_private_key_read_failed; + goto failed; + } + } else { + memcpy( private_key, context, PRIVATE_KEY_LEN(seed_len) ); + } + int hash_len = get_level0_lm_hash_len( private_key ); + if (hash_len == 0) break; + if (hash_len == seed_len) break; /* We read in the entire thing */ + seed_len = hash_len; + } + if (try == 2) goto failed; +#else if (read_private_key) { - if (!read_private_key( private_key, PRIVATE_KEY_LEN, context)) { + if (!read_private_key( private_key, PRIVATE_KEY_LEN(seed_len), context)) { info->error_code = hss_error_private_key_read_failed; goto failed; } } else { - memcpy( private_key, context, PRIVATE_KEY_LEN ); + memcpy( private_key, context, PRIVATE_KEY_LEN(seed_len) ); } +#endif /* * Make sure that the private key and the allocated working key are @@ -305,7 +325,8 @@ bool hss_generate_working_key( } hss_set_reserve_count(w, current_count); - memcpy( w->private_key, private_key, PRIVATE_KEY_LEN ); + memcpy( w->private_key, private_key, + PRIVATE_KEY_LEN(w->tree[0]->hash_size) ); /* Initialize all the levels of the tree */ @@ -327,7 +348,8 @@ bool hss_generate_working_key( if (i == 0) { /* The root seed, I value is derived from the secret key */ hss_generate_root_seed_I_value( tree->seed, tree->I, - private_key+PRIVATE_KEY_SEED ); + private_key+PRIVATE_KEY_SEED, + tree->lm_type, tree->lm_ots_type ); /* We don't use the I_next value */ } else { /* The seed, I is derived from the parent's values */ @@ -335,23 +357,39 @@ bool hss_generate_working_key( /* Where we are in the Merkle tree */ struct merkle_level *parent = w->tree[i-1]; merkle_index_t index = parent->current_index; + size_t len_parent_seed = hss_seed_size( parent->lm_type ); + size_t len_child_seed = hss_seed_size( tree->lm_type ); - hss_generate_child_seed_I_value( tree->seed, tree->I, - parent->seed, parent->I, + if (!hss_generate_child_seed_I_value( tree->seed, tree->I, + parent->seed, len_parent_seed, + parent->I, len_child_seed, index, parent->lm_type, - parent->lm_ots_type ); + parent->lm_ots_type )) { + info->error_code = hss_error_internal; + goto failed; + } /* The next seed, I is derived from either the parent's I */ /* or the parent's next value */ if (index == tree->max_index) { - hss_generate_child_seed_I_value( tree->seed_next, tree->I_next, - parent->seed_next, parent->I_next, + if (!hss_generate_child_seed_I_value( + tree->seed_next, tree->I_next, + parent->seed_next, len_parent_seed, + parent->I_next, len_child_seed, 0, parent->lm_type, - parent->lm_ots_type); + parent->lm_ots_type)) { + info->error_code = hss_error_internal; + goto failed; + } } else { - hss_generate_child_seed_I_value( tree->seed_next, tree->I_next, - parent->seed, parent->I, + if (!hss_generate_child_seed_I_value( + tree->seed_next, tree->I_next, + parent->seed, len_parent_seed, + parent->I, len_child_seed, index+1, parent->lm_type, - parent->lm_ots_type); + parent->lm_ots_type)) { + info->error_code = hss_error_internal; + goto failed; + } } } } diff --git a/hss_internal.h b/hss_internal.h index 9cd2432..5c2680c 100644 --- a/hss_internal.h +++ b/hss_internal.h @@ -11,13 +11,21 @@ * this subsystem. It should not be used by applications */ -#define PARAM_SET_COMPRESS_LEN 1 /* We assume that we can compress the */ +#define PARAM_SET_COMPRESS_LEN 2 /* We assume that we can compress the */ /* lm_type and the lm_ots type for a */ - /* single level into 1 byte */ + /* single level into 2 bytes */ #define PARM_SET_END 0xff /* We set this marker in the parameter set */ /* when fewer than the maximum levels are used */ +/* This is the length of our internal seed values */ +#if SECRET_METHOD == 2 +#define MIN_SEED_LEN 24 /* Enough to make Grover's infeasible */ +#else +#define MIN_SEED_LEN 32 /* Enough to make Grover's infeasible */ +#define SEED_LEN 32 /* It's always 32 */ +#endif + /* * The internal structure of a private key @@ -29,12 +37,12 @@ #define PRIVATE_KEY_PARAM_SET_LEN (PARAM_SET_COMPRESS_LEN * MAX_HSS_LEVELS) #define PRIVATE_KEY_SEED (PRIVATE_KEY_PARAM_SET + PRIVATE_KEY_PARAM_SET_LEN) #if SECRET_METHOD == 2 -#define PRIVATE_KEY_SEED_LEN (SEED_LEN + I_LEN) +#define PRIVATE_KEY_SEED_LEN(seed_len) (seed_len + I_LEN) #else -#define PRIVATE_KEY_SEED_LEN SEED_LEN +#define PRIVATE_KEY_SEED_LEN(seed_len) SEED_LEN #endif -#define PRIVATE_KEY_LEN (PRIVATE_KEY_SEED + PRIVATE_KEY_SEED_LEN) /* That's */ - /* 48 bytes */ +#define PRIVATE_KEY_LEN(seed_len) (PRIVATE_KEY_SEED + \ + PRIVATE_KEY_SEED_LEN(seed_len)) /* That's 56-72 bytes */ struct merkle_level; struct hss_working_key { @@ -56,7 +64,7 @@ struct hss_working_key { unsigned char *stack; /* The stack memory used by the subtrees */ /* The private key (in its entirety) */ - unsigned char private_key[PRIVATE_KEY_LEN]; + unsigned char private_key[PRIVATE_KEY_LEN(MAX_SEED_LEN)]; /* The pointer to the seed (contained within the private key) */ /* Warning: nonsyntaxic macro; need to be careful how we use this */ #define working_key_seed private_key + PRIVATE_KEY_SEED @@ -88,6 +96,7 @@ struct hss_working_key { struct merkle_level { unsigned level; /* Total number of levels */ unsigned h, hash_size; /* Hash function, width */ + unsigned lms_hash, lms_hash_size; /* Hash function width for the LMS op */ param_set_t lm_type; param_set_t lm_ots_type; /* OTS parameter */ merkle_index_t current_index; /* The number of signatures this tree has */ @@ -131,7 +140,7 @@ struct merkle_level { unsigned char I[I_LEN], I_next[I_LEN]; /* The seed values for the current Merkle tree, and the next one */ - unsigned char seed[SEED_LEN], seed_next[SEED_LEN]; + unsigned char seed[MAX_SEED_LEN], seed_next[MAX_SEED_LEN]; }; /* @@ -172,20 +181,29 @@ bool hss_compress_param_set( unsigned char *compressed, const param_set_t *lm_ots_type, size_t len_compressed ); +/* Internal function to extract the length of the level 0 LM hash from a */ +/* private key */ +int get_level0_lm_hash_len( const unsigned char *private_key ); + /* Internal function to generate the root seed, I value (based on the */ /* private seed). We do this (rather than selecting them at random) so */ /* that we don't need to store them in our private key; we can recompute */ bool hss_generate_root_seed_I_value(unsigned char *seed, unsigned char *I, - const unsigned char *master_seed); + const unsigned char *master_seed, + param_set_t lm, param_set_t ots); /* Internal function to generate the seed, I value for a child Merkle tree */ /* (based on the seed, I value of the parent. We do this (rather than */ /* selecting them at random) so we have consistent values between reboots */ bool hss_generate_child_seed_I_value( unsigned char *seed, unsigned char *I, - const unsigned char *parent_seed, - const unsigned char *parent_I, merkle_index_t index, + const unsigned char *parent_seed, size_t parent_seed_len, + const unsigned char *parent_I, size_t child_seed_len, + merkle_index_t index, param_set_t parent_lm, param_set_t parent_ots ); +/* Internal function to get the size of a seed */ +size_t hss_seed_size(param_set_t lm_param); + /* Combine two internal nodes */ void hss_combine_internal_nodes( unsigned char *dest, const unsigned char *left_node, const unsigned char *right_node, diff --git a/hss_keygen.c b/hss_keygen.c index 7654fb9..f147d55 100644 --- a/hss_keygen.c +++ b/hss_keygen.c @@ -107,7 +107,7 @@ bool hss_generate_private_key( return false; } - unsigned char private_key[ PRIVATE_KEY_LEN ]; + unsigned char private_key[ PRIVATE_KEY_LEN(MAX_SEED_LEN) ]; /* First step: format the private key */ put_bigendian( private_key + PRIVATE_KEY_INDEX, 0, @@ -119,14 +119,15 @@ bool hss_generate_private_key( return false; } if (!(*generate_random)( private_key + PRIVATE_KEY_SEED, - PRIVATE_KEY_SEED_LEN )) { + PRIVATE_KEY_SEED_LEN(size_hash) )) { info->error_code = hss_error_bad_randomness; return false; } /* Now make sure that the private key is written to NVRAM */ if (update_private_key) { - if (!(*update_private_key)( private_key, PRIVATE_KEY_LEN, context)) { + if (!(*update_private_key)( private_key, PRIVATE_KEY_LEN(size_hash), + context)) { /* initial write of private key didn't take */ info->error_code = hss_error_private_key_write_failed; hss_zeroize( private_key, sizeof private_key ); @@ -139,7 +140,7 @@ bool hss_generate_private_key( hss_zeroize( private_key, sizeof private_key ); return false; } - memcpy( context, private_key, PRIVATE_KEY_LEN ); + memcpy( context, private_key, PRIVATE_KEY_LEN(size_hash) ); } /* Figure out what would be the best trade-off for the aux level */ @@ -155,8 +156,9 @@ bool hss_generate_private_key( } unsigned char I[I_LEN]; - unsigned char seed[SEED_LEN]; - if (!hss_generate_root_seed_I_value( seed, I, private_key+PRIVATE_KEY_SEED)) { + unsigned char seed[MAX_SEED_LEN]; + if (!hss_generate_root_seed_I_value( seed, I, private_key+PRIVATE_KEY_SEED, + lm_type[0], lm_ots_type[0])) { info->error_code = hss_error_internal; hss_zeroize( private_key, sizeof private_key ); return false; @@ -271,9 +273,9 @@ bool hss_generate_private_key( info->error_code = got_error; hss_zeroize( private_key, sizeof private_key ); if (update_private_key) { - (void)(*update_private_key)(private_key, PRIVATE_KEY_LEN, context); + (void)(*update_private_key)(private_key, PRIVATE_KEY_LEN(size_hash), context); } else { - hss_zeroize( context, PRIVATE_KEY_LEN ); + hss_zeroize( context, PRIVATE_KEY_LEN(size_hash) ); } free(temp_buffer); return false; @@ -361,5 +363,11 @@ size_t hss_get_private_key_len(unsigned levels, const param_set_t *lm_ots_type) { /* A private key is a 'public object'? Yes, in the sense that we */ /* export it outside this module */ - return PRIVATE_KEY_LEN; +#if SECRET_METHOD == 2 + unsigned hash0_len; + if (!lm_look_up_parameter_set( lm_type[0], 0, &hash0_len, 0 )) { + return 0; + } +#endif + return PRIVATE_KEY_LEN(hash0_len); } diff --git a/hss_param.c b/hss_param.c index 0788370..1a7537e 100644 --- a/hss_param.c +++ b/hss_param.c @@ -3,6 +3,73 @@ #include "hss_internal.h" #include "endian.h" #include "hss_zeroize.h" +#include "lm_common.h" + +static struct map_structure { + param_set_t public; + unsigned char compressed; +} lm_map[] = { + { LMS_SHA256_N32_H5, 0x01 }, + { LMS_SHA256_N32_H10,0x02 }, + { LMS_SHA256_N32_H15,0x03 }, + { LMS_SHA256_N32_H20,0x04 }, + { LMS_SHA256_N32_H25,0x05 }, + { LMS_SHA256_N24_H5, 0x06 }, + { LMS_SHA256_N24_H10,0x07 }, + { LMS_SHA256_N24_H15,0x08 }, + { LMS_SHA256_N24_H20,0x09 }, + { LMS_SHA256_N24_H25,0x0a }, + { LMS_SHAKE256_N32_H5, 0x0b }, + { LMS_SHAKE256_N32_H10,0x0c }, + { LMS_SHAKE256_N32_H15,0x0d }, + { LMS_SHAKE256_N32_H20,0x0e }, + { LMS_SHAKE256_N32_H25,0x0f }, + { LMS_SHAKE256_N24_H5, 0x10 }, + { LMS_SHAKE256_N24_H10,0x11 }, + { LMS_SHAKE256_N24_H15,0x12 }, + { LMS_SHAKE256_N24_H20,0x13 }, + { LMS_SHAKE256_N24_H25,0x14 }, + { 0, 0 }}, + ots_map[] = { + { LMOTS_SHA256_N32_W1, 0x01 }, + { LMOTS_SHA256_N32_W2, 0x02 }, + { LMOTS_SHA256_N32_W4, 0x03 }, + { LMOTS_SHA256_N32_W8, 0x04 }, + { LMOTS_SHA256_N24_W1, 0x05 }, + { LMOTS_SHA256_N24_W2, 0x06 }, + { LMOTS_SHA256_N24_W4, 0x07 }, + { LMOTS_SHA256_N24_W8, 0x08 }, + { LMOTS_SHAKE256_N32_W1, 0x09 }, + { LMOTS_SHAKE256_N32_W2, 0x0a }, + { LMOTS_SHAKE256_N32_W4, 0x0b }, + { LMOTS_SHAKE256_N32_W8, 0x0c }, + { LMOTS_SHAKE256_N24_W1, 0x0d }, + { LMOTS_SHAKE256_N24_W2, 0x0e }, + { LMOTS_SHAKE256_N24_W4, 0x0f }, + { LMOTS_SHAKE256_N24_W8, 0x10 }, + { 0, 0 }}; +static bool map(param_set_t *a, + struct map_structure *map) { + int i; + for (i=0; map[i].public != 0; i++) { + if (map[i].public == *a) { + *a = map[i].compressed; + return true; + } + } + return false; +} +static bool unmap(param_set_t *a, + struct map_structure *map) { + int i; + for (i=0; map[i].public != 0; i++) { + if (map[i].compressed == *a) { + *a = map[i].public; + return true; + } + } + return false; +} /* * Convert a parameter set into the compressed version we use within a private @@ -20,28 +87,14 @@ bool hss_compress_param_set( unsigned char *compressed, if (len_compressed == 0) return false; param_set_t a = *lm_type++; param_set_t b = *lm_ots_type++; - /* All the parameter sets we support are small */ - /* Review this format if we need to support larger ones */ - if (a > 0x0e || b > 0x0e) return false; - /* Make sure the parm sets are supported */ - switch (a) { - case LMS_SHA256_N32_H5: case LMS_SHA256_N32_H10: - case LMS_SHA256_N32_H15: case LMS_SHA256_N32_H20: - case LMS_SHA256_N32_H25: - break; - default: - return false; - } - switch (b) { - case LMOTS_SHA256_N32_W1: case LMOTS_SHA256_N32_W2: - case LMOTS_SHA256_N32_W4: case LMOTS_SHA256_N32_W8: - break; - default: - return false; - } - - *compressed++ = (a<<4) + b; - len_compressed--; + + /* Convert the official mappings to the compressed versions */ + if (!map( &a, lm_map ) || + !map( &b, ots_map )) return false; + + *compressed++ = a; + *compressed++ = b; + len_compressed -= 2; } while (len_compressed) { @@ -73,16 +126,24 @@ bool hss_get_parameter_set( unsigned *levels, param_set_t lm_ots_type[ MAX_HSS_LEVELS ], bool (*read_private_key)(unsigned char *private_key, size_t len_private_key, void *context), - void *context) { - unsigned char private_key[ PRIVATE_KEY_LEN ]; + void *context, + struct hss_extra_info *info) { + unsigned char private_key[ PRIVATE_KEY_LEN(MAX_SEED_LEN) ]; bool success = false; + enum hss_error_code error_code = hss_error_bad_private_key; /* Most of */ + /* the detected errors are 'what's in the private key does not */ + /* correspond to a supported parameter set' */ if (read_private_key) { if (!read_private_key( private_key, PRIVATE_KEY_SEED, context )) { + error_code = hss_error_private_key_read_failed; goto failed; } } else { - if (!context) return false; + if (!context) { + error_code = hss_error_no_private_buffer; + goto failed; + } memcpy( private_key, context, PRIVATE_KEY_SEED ); } @@ -90,27 +151,40 @@ bool hss_get_parameter_set( unsigned *levels, unsigned total_height = 0; unsigned level; for (level=0; level < MAX_HSS_LEVELS; level++) { - unsigned char c = private_key[PRIVATE_KEY_PARAM_SET + level]; - if (c == PARM_SET_END) break; + unsigned char c = private_key[PRIVATE_KEY_PARAM_SET + 2*level]; + unsigned char d = private_key[PRIVATE_KEY_PARAM_SET + 2*level + 1]; + if (c == PARM_SET_END && d == PARM_SET_END) break; /* Decode this level's parameter set */ - param_set_t lm = (c >> 4); - param_set_t ots = (c & 0x0f); + param_set_t lm = c; + param_set_t ots = d; /* Make sure both are supported */ /* While we're here, add up the total Merkle height */ + + /* How we unpack the parameter sets */ + if (!unmap( &lm, lm_map ) || + !unmap( &ots, ots_map )) goto failed; + /* While we're here, add up the total Merkle height */ switch (lm) { - case LMS_SHA256_N32_H5: total_height += 5; break; - case LMS_SHA256_N32_H10: total_height += 10; break; - case LMS_SHA256_N32_H15: total_height += 15; break; - case LMS_SHA256_N32_H20: total_height += 20; break; - case LMS_SHA256_N32_H25: total_height += 25; break; - default: goto failed; - } - switch (ots) { - case LMOTS_SHA256_N32_W1: - case LMOTS_SHA256_N32_W2: - case LMOTS_SHA256_N32_W4: - case LMOTS_SHA256_N32_W8: - break; + case LMS_SHA256_N32_H5: + case LMS_SHA256_N24_H5: + case LMS_SHAKE256_N32_H5: + case LMS_SHAKE256_N24_H5: total_height += 5; break; + case LMS_SHA256_N32_H10: + case LMS_SHA256_N24_H10: + case LMS_SHAKE256_N32_H10: + case LMS_SHAKE256_N24_H10: total_height += 10; break; + case LMS_SHA256_N32_H15: + case LMS_SHA256_N24_H15: + case LMS_SHAKE256_N32_H15: + case LMS_SHAKE256_N24_H15: total_height += 15; break; + case LMS_SHA256_N32_H20: + case LMS_SHA256_N24_H20: + case LMS_SHAKE256_N32_H20: + case LMS_SHAKE256_N24_H20: total_height += 20; break; + case LMS_SHA256_N32_H25: + case LMS_SHA256_N24_H25: + case LMS_SHAKE256_N32_H25: + case LMS_SHAKE256_N24_H25: total_height += 25; break; default: goto failed; } lm_type[level] = lm; @@ -123,7 +197,7 @@ bool hss_get_parameter_set( unsigned *levels, /* Make sure that the rest of the private key has PARM_SET_END */ unsigned i; - for (i = level+1; i max_count) goto failed; /* Private key expired */ + if (current_count > max_count) { + /* Private key expired */ + error_code = hss_error_private_key_expired; + goto failed; + } success = true; /* It worked! */ + error_code = hss_error_none; failed: + if (info) info->error_code = error_code; /* There might be private keying material here */ hss_zeroize( private_key, sizeof private_key ); return success; } + +int get_level0_lm_hash_len( const unsigned char *private_key ) { + /* Look up the compressed parameter set format */ + unsigned char c = private_key[PRIVATE_KEY_PARAM_SET]; + param_set_t lm = c; + if (!unmap( &lm, lm_map )) return 0; + unsigned n; + if (!lm_look_up_parameter_set(lm, 0, &n, 0)) return 0; + return n; +} diff --git a/hss_reserve.c b/hss_reserve.c index 7de0b1a..a1bdca7 100644 --- a/hss_reserve.c +++ b/hss_reserve.c @@ -52,15 +52,17 @@ bool hss_advance_count(struct hss_working_key *w, sequence_t cur_count, *trash_private_key = true; /* We can't trash our copy of the */ /* private key until after we've generated the signature */ /* We can trash the copy in secure storage, though */ + int h0_len = w->tree[0]->hash_size; if (update_private_key) { - unsigned char private_key[PRIVATE_KEY_LEN]; - memset( private_key, PARM_SET_END, PRIVATE_KEY_LEN ); - if (!update_private_key(private_key, PRIVATE_KEY_LEN, context)) { + unsigned char private_key[PRIVATE_KEY_LEN(MAX_SEED_LEN)]; + memset( private_key, PARM_SET_END, PRIVATE_KEY_LEN(MAX_SEED_LEN) ); + if (!update_private_key(private_key, PRIVATE_KEY_LEN(h0_len), + context)) { info->error_code = hss_error_private_key_write_failed; return false; } } else { - memset( context, PARM_SET_END, PRIVATE_KEY_LEN ); + memset( context, PARM_SET_END, PRIVATE_KEY_LEN(h0_len) ); } return true; } @@ -142,7 +144,8 @@ bool hss_reserve_signature( * reason we shouldn't support it */ if (!update_private_key) { - if (0 != memcmp( context, w->private_key, PRIVATE_KEY_LEN)) { + int h0_len = w->tree[0]->hash_size; + if (0 != memcmp( context, w->private_key, PRIVATE_KEY_LEN(h0_len))) { info->error_code = hss_error_key_mismatch; return false; /* Private key mismatch */ } @@ -162,7 +165,7 @@ bool hss_reserve_signature( sequence_t new_reserve_count; /* This is what the new reservation */ /* setting would be (if we accept the reservation) */ - if (current_count > w->max_count - sigs_to_reserve) { + if (current_count + sigs_to_reserve > w->max_count) { /* Not that many sigantures left */ /* We can't promise to be able to generate that many signatures */ info->error_code = hss_error_not_that_many_sigs_left; diff --git a/hss_sign.c b/hss_sign.c index 4ffdfc3..fd5fe03 100644 --- a/hss_sign.c +++ b/hss_sign.c @@ -53,7 +53,9 @@ static enum subtree_build_status subtree_add_next_node( const unsigned char *seed = (next_tree ? tree->seed_next : tree->seed); struct seed_derive derive; if (!hss_seed_derive_init( &derive, tree->lm_type, tree->lm_ots_type, - I, seed )) return subtree_got_error; + I, seed, hss_seed_size(tree->lm_type) )) { + return subtree_got_error; + } hss_seed_derive_set_q(&derive, r); if (!lm_ots_generate_public_key(tree->lm_ots_type, I, r, &derive, pub_key + LEAF_PK, ots_len)) { @@ -64,7 +66,7 @@ static enum subtree_build_status subtree_add_next_node( /* Hash it to form the leaf node */ union hash_context ctx; - hss_hash_ctx( cur_val, tree->h, &ctx, pub_key, LEAF_LEN(hash_size)); + hss_hash_ctx( cur_val, tree->h, &ctx, pub_key, LEAF_LEN(ots_len)); /* Where in the subtree we store the values */ merkle_index_t subtree_index = subtree->current_index + @@ -185,8 +187,10 @@ static int generate_merkle_signature( } else { struct seed_derive derive; if (!hss_seed_derive_init( &derive, - tree->lm_type, tree->lm_ots_type, - tree->I, tree->seed )) return 0; + tree->lm_type, tree->lm_ots_type, tree->I, + tree->seed, hss_seed_size(tree->lm_type) )) { + return 0; + } hss_seed_derive_set_q(&derive, current_index); bool success = lm_ots_generate_signature( tree->lm_ots_type, tree->I, current_index, &derive, @@ -467,7 +471,8 @@ bool hss_generate_signature( /* If we're given a raw private key, make sure it's the one we're */ /* thinking of */ if (!update_private_key) { - if (0 != memcmp( context, w->private_key, PRIVATE_KEY_LEN)) { + int h0_len = w->tree[0]->hash_size; + if (0 != memcmp( context, w->private_key, PRIVATE_KEY_LEN(h0_len))) { info->error_code = hss_error_key_mismatch; return false; /* Private key mismatch */ } @@ -667,22 +672,32 @@ bool hss_generate_signature( } /* Copy in the value of seed, I we'll use for the new tree */ - memcpy( tree->seed, tree->seed_next, SEED_LEN ); + memcpy( tree->seed, tree->seed_next, MAX_SEED_LEN ); memcpy( tree->I, tree->I_next, I_LEN ); /* Compute the new next I, which is derived from either the parent's */ /* I or the parent's I_next value */ merkle_index_t index = parent->current_index; + size_t parent_seed_len = hss_seed_size(parent->lm_type); + size_t child_seed_len = hss_seed_size(tree->lm_type); if (index == parent->max_index) { - hss_generate_child_seed_I_value(tree->seed_next, tree->I_next, - parent->seed_next, parent->I_next, 0, + if (!hss_generate_child_seed_I_value(tree->seed_next, tree->I_next, + parent->seed_next, parent_seed_len, + parent->I_next, child_seed_len, 0, parent->lm_type, - parent->lm_ots_type); + parent->lm_ots_type)) { + info->error_code = hss_error_internal; + goto failed; + } } else { - hss_generate_child_seed_I_value( tree->seed_next, tree->I_next, - parent->seed, parent->I, index+1, + if (!hss_generate_child_seed_I_value(tree->seed_next, tree->I_next, + parent->seed, parent_seed_len, + parent->I, child_seed_len, index+1, parent->lm_type, - parent->lm_ots_type); + parent->lm_ots_type)) { + info->error_code = hss_error_internal; + goto failed; + } } tree->current_index = 0; /* We're starting this from scratch */ @@ -698,7 +713,7 @@ bool hss_generate_signature( /* And we've set things up for the next signature... */ if (trash_private_key) { - memset( w->private_key, PARM_SET_END, PRIVATE_KEY_LEN ); + memset( w->private_key, PARM_SET_END, PRIVATE_KEY_LEN(MAX_SEED_LEN)); } return true; @@ -706,7 +721,7 @@ bool hss_generate_signature( failed: if (trash_private_key) { - memset( w->private_key, PARM_SET_END, PRIVATE_KEY_LEN ); + memset( w->private_key, PARM_SET_END, PRIVATE_KEY_LEN(MAX_SEED_LEN)); } /* On failure, make sure that we don't return anything that might be */ diff --git a/hss_sign_inc.c b/hss_sign_inc.c index 34e94f8..d5856f0 100644 --- a/hss_sign_inc.c +++ b/hss_sign_inc.c @@ -62,14 +62,14 @@ bool hss_sign_init( /* Compute the value of C we'll use */ merkle_index_t q = bottom->current_index; ctx->q = q; - int h = bottom->h; - ctx->h = h; + int h = ctx->h = bottom->lms_hash; struct seed_derive derive; if (!hss_seed_derive_init( &derive, bottom->lm_type, bottom->lm_ots_type, - bottom->I, bottom->seed )) return false; + bottom->I, bottom->seed, + hss_seed_size( bottom->lm_type ) )) return false; hss_seed_derive_set_q(&derive, q); - lm_ots_generate_randomizer( ctx->c, bottom->hash_size, &derive ); + lm_ots_generate_randomizer( ctx->c, bottom->lms_hash_size, &derive ); hss_seed_derive_done(&derive); /* @@ -96,7 +96,7 @@ bool hss_sign_init( unsigned q_bin[4]; put_bigendian( q_bin, q, 4 ); memcpy( prefix + MESG_Q, q_bin, 4 ); /* q */ SET_D( prefix + MESG_D, D_MESG ); - int n = bottom->hash_size; + int n = bottom->lms_hash_size; memcpy( prefix + MESG_C, ctx->c, n ); /* C */ hss_update_hash_context(h, &ctx->hash_ctx, prefix, MESG_PREFIX_LEN(n) ); } @@ -150,7 +150,7 @@ bool hss_sign_finalize( /* hss_generate_child_seed_I_value doesn't allow new values to */ /* overwrite old ones */ unsigned char I_buff[2][I_LEN]; - unsigned char seed_buff[2][SEED_LEN]; + unsigned char seed_buff[2][MAX_SEED_LEN]; /* Q: should we double check the various fixed fields of the signatures */ /* (e.g. the number of signed keys, the parameter sets? */ @@ -158,14 +158,16 @@ bool hss_sign_finalize( signature += 4; int i; + size_t seed_len = hss_seed_size( working_key->tree[0]->lm_type ); for (i=0; i working_key->tree[i]->max_index) { hss_zeroize( seed_buff, sizeof seed_buff ); return 0; } + size_t child_seed_len = hss_seed_size( working_key->tree[i+1]->lm_type ); if (!hss_generate_child_seed_I_value( seed_buff[i&1], I_buff[i&1], - seed, I, q, + seed, seed_len, I, child_seed_len, q, working_key->tree[i]->lm_type, working_key->tree[i]->lm_ots_type )) { hss_zeroize( seed_buff, sizeof seed_buff ); @@ -175,6 +177,7 @@ bool hss_sign_finalize( seed = seed_buff[i&1]; I = I_buff[i&1]; + seed_len = child_seed_len; /* Step to the end of this signed key */ signature += lm_get_signature_len( working_key->tree[i]->lm_type, @@ -189,7 +192,8 @@ bool hss_sign_finalize( /* And then the LM-OTS signature */ /* Copy in the C value into the signature */ - memcpy( signature+4, ctx->c, 32 ); + int n = hss_hash_length(ctx->h); + memcpy( signature+4, ctx->c, n ); /* Generate the final hash */ unsigned char hash[ MAX_HASH ]; @@ -200,7 +204,7 @@ bool hss_sign_finalize( param_set_t ots_type = working_key->tree[i]->lm_ots_type; struct seed_derive derive; bool success = hss_seed_derive_init( &derive, lm_type, ots_type, - I, seed ); + I, seed, seed_len ); if (success) { hss_seed_derive_set_q( &derive, ctx->q ); success = lm_ots_generate_signature( diff --git a/hss_verify_inc.c b/hss_verify_inc.c index d067c31..4622575 100644 --- a/hss_verify_inc.c +++ b/hss_verify_inc.c @@ -116,11 +116,6 @@ bool hss_validate_signature_init( ctx->signature_offset = signature - orig_signature; ctx->signature_len = signature_len; - /* We have the public key in front of us; stash a copy */ - /* Right now, we have a fixed length public key */ - /* If that changes, we'll need to investigate the parmaeter set */ - memcpy( ctx->final_public_key, public_key, 8 + I_LEN + MAX_HASH ); - /* Now, initialize the context */ param_set_t ots_type = get_bigendian( public_key+4, 4 ); @@ -132,6 +127,10 @@ bool hss_validate_signature_init( return false; } ctx->h = h; + + /* We have the public key in front of us; stash a copy */ + memcpy( ctx->final_public_key, public_key, 8 + I_LEN + n ); + hss_init_hash_context( h, &ctx->hash_ctx ); { unsigned char prefix[ MESG_PREFIX_MAXLEN ]; diff --git a/lm_common.c b/lm_common.c index 1ebcfc9..46bfe0f 100644 --- a/lm_common.c +++ b/lm_common.c @@ -17,14 +17,44 @@ bool lm_look_up_parameter_set(param_set_t parameter_set, switch (parameter_set) { case LMS_SHA256_N32_H5: v_h = HASH_SHA256; v_n = 32; v_height = 5; break; + case LMS_SHA256_N24_H5: + v_h = HASH_SHA256_24; v_n = 24; v_height = 5; break; case LMS_SHA256_N32_H10: v_h = HASH_SHA256; v_n = 32; v_height = 10; break; + case LMS_SHA256_N24_H10: + v_h = HASH_SHA256_24; v_n = 24; v_height = 10; break; case LMS_SHA256_N32_H15: v_h = HASH_SHA256; v_n = 32; v_height = 15; break; + case LMS_SHA256_N24_H15: + v_h = HASH_SHA256_24; v_n = 24; v_height = 15; break; case LMS_SHA256_N32_H20: v_h = HASH_SHA256; v_n = 32; v_height = 20; break; + case LMS_SHA256_N24_H20: + v_h = HASH_SHA256_24; v_n = 24; v_height = 20; break; case LMS_SHA256_N32_H25: v_h = HASH_SHA256; v_n = 32; v_height = 25; break; + case LMS_SHA256_N24_H25: + v_h = HASH_SHA256_24; v_n = 24; v_height = 25; break; + case LMS_SHAKE256_N32_H5: + v_h = HASH_SHAKE256; v_n = 32; v_height = 5; break; + case LMS_SHAKE256_N24_H5: + v_h = HASH_SHAKE256_24; v_n = 24; v_height = 5; break; + case LMS_SHAKE256_N32_H10: + v_h = HASH_SHAKE256; v_n = 32; v_height = 10; break; + case LMS_SHAKE256_N24_H10: + v_h = HASH_SHAKE256_24; v_n = 24; v_height = 10; break; + case LMS_SHAKE256_N32_H15: + v_h = HASH_SHAKE256; v_n = 32; v_height = 15; break; + case LMS_SHAKE256_N24_H15: + v_h = HASH_SHAKE256_24; v_n = 24; v_height = 15; break; + case LMS_SHAKE256_N32_H20: + v_h = HASH_SHAKE256; v_n = 32; v_height = 20; break; + case LMS_SHAKE256_N24_H20: + v_h = HASH_SHAKE256_24; v_n = 24; v_height = 20; break; + case LMS_SHAKE256_N32_H25: + v_h = HASH_SHAKE256; v_n = 32; v_height = 25; break; + case LMS_SHAKE256_N24_H25: + v_h = HASH_SHAKE256_24; v_n = 24; v_height = 25; break; default: return false; } diff --git a/lm_ots_common.c b/lm_ots_common.c index 45672e1..95ab357 100644 --- a/lm_ots_common.c +++ b/lm_ots_common.c @@ -5,7 +5,6 @@ #include "lm_ots_common.h" #include "common_defs.h" #include "hash.h" - /* * Convert the external name of a parameter set into the set of values we care * about @@ -16,13 +15,38 @@ bool lm_ots_look_up_parameter_set(param_set_t parameter_set, switch (parameter_set) { case LMOTS_SHA256_N32_W1: v_h = HASH_SHA256; v_n = 32; v_w = 1; v_p = 265; v_ls = 7; break; + case LMOTS_SHA256_N24_W1: + v_h = HASH_SHA256_24; v_n = 24; v_w = 1; v_p = 200; v_ls = 8; break; case LMOTS_SHA256_N32_W2: v_h = HASH_SHA256; v_n = 32; v_w = 2; v_p = 133; v_ls = 6; break; + case LMOTS_SHA256_N24_W2: + v_h = HASH_SHA256_24; v_n = 24; v_w = 2; v_p = 101; v_ls = 6; break; case LMOTS_SHA256_N32_W4: v_h = HASH_SHA256; v_n = 32; v_w = 4; v_p = 67; v_ls = 4; break; + case LMOTS_SHA256_N24_W4: + v_h = HASH_SHA256_24; v_n = 24; v_w = 4; v_p = 51; v_ls = 4; break; case LMOTS_SHA256_N32_W8: v_h = HASH_SHA256; v_n = 32; v_w = 8; v_p = 34; v_ls = 0; break; - default: return false; + case LMOTS_SHA256_N24_W8: + v_h = HASH_SHA256_24; v_n = 24; v_w = 8; v_p = 26; v_ls = 0; break; + case LMOTS_SHAKE256_N32_W1: + v_h = HASH_SHAKE256; v_n = 32; v_w = 1; v_p = 265; v_ls = 7; break; + case LMOTS_SHAKE256_N24_W1: + v_h = HASH_SHAKE256_24; v_n = 24; v_w = 1; v_p = 200; v_ls = 8; break; + case LMOTS_SHAKE256_N32_W2: + v_h = HASH_SHAKE256; v_n = 32; v_w = 2; v_p = 133; v_ls = 6; break; + case LMOTS_SHAKE256_N24_W2: + v_h = HASH_SHAKE256_24; v_n = 24; v_w = 2; v_p = 101; v_ls = 6; break; + case LMOTS_SHAKE256_N32_W4: + v_h = HASH_SHAKE256; v_n = 32; v_w = 4; v_p = 67; v_ls = 4; break; + case LMOTS_SHAKE256_N24_W4: + v_h = HASH_SHAKE256_24; v_n = 24; v_w = 4; v_p = 51; v_ls = 4; break; + case LMOTS_SHAKE256_N32_W8: + v_h = HASH_SHAKE256; v_n = 32; v_w = 8; v_p = 34; v_ls = 0; break; + case LMOTS_SHAKE256_N24_W8: + v_h = HASH_SHAKE256_24; v_n = 24; v_w = 8; v_p = 26; v_ls = 0; break; + default: + return false; } if (h) *h = v_h; diff --git a/lm_ots_sign.c b/lm_ots_sign.c index 52639bd..2f50a77 100644 --- a/lm_ots_sign.c +++ b/lm_ots_sign.c @@ -51,7 +51,7 @@ bool lm_ots_generate_public_key( hss_seed_derive_set_j( seed, 0 ); for (i=0; i extern bool test_testvector(bool fast_flag, bool quiet_flag); +extern bool test_shake(bool fast_flag, bool quiet_flag); extern bool test_keygen(bool fast_flag, bool quiet_flag); extern bool test_load(bool fast_flag, bool quiet_flag); extern bool test_sign(bool fast_flag, bool quiet_flag); diff --git a/test_keygen.c b/test_keygen.c index cd06021..d52f1c0 100644 --- a/test_keygen.c +++ b/test_keygen.c @@ -58,8 +58,8 @@ static bool gen_signature( unsigned char *privkey, bool test_keygen(bool fast_flag, bool quiet_flag) { /* We'll use this parameter set, unless we need to test out a different one */ - param_set_t default_lm_type[2] = { LMS_SHA256_N32_H10, LMS_SHA256_N32_H15 }; - param_set_t default_ots_type[2] = { LMOTS_SHA256_N32_W2, LMOTS_SHA256_N32_W8 }; + param_set_t default_lm_type[2] = { LMS_SHA256_N24_H10, LMS_SHA256_N24_H15 }; + param_set_t default_ots_type[2] = { LMOTS_SHA256_N24_W2, LMOTS_SHA256_N24_W8 }; int default_d = 2; int default_pubkey_size = hss_get_public_key_len( default_d, default_lm_type, default_ots_type ); int default_privkey_size = hss_get_private_key_len( default_d, default_lm_type, default_ots_type ); @@ -159,8 +159,8 @@ bool test_keygen(bool fast_flag, bool quiet_flag) { { param_set_t lm_type[12], ots_type[12]; int i; - for (i=0; i<12; i++) lm_type[i] = LMS_SHA256_N32_H5; - for (i=0; i<12; i++) ots_type[i] = LMOTS_SHA256_N32_W8; + for (i=0; i<12; i++) lm_type[i] = LMS_SHA256_N24_H5; + for (i=0; i<12; i++) ots_type[i] = LMOTS_SHA256_N24_W4; /* Since some of these parm sets are illegal (and so don't */ /* have a size we can look up), we oversize the buffer */ @@ -190,28 +190,44 @@ bool test_keygen(bool fast_flag, bool quiet_flag) { } d = 3; - ots_type[0] = LMOTS_SHA256_N32_W2; /* Make the keygen tests faster */ + ots_type[0] = LMOTS_SHA256_N24_W2; /* Make the keygen tests faster */ /* Try various lm_types (both legal and illegal) */ for (i=0; i<3; i++) { - int lm; - for (lm = 0; lm < 100; lm++) { /* 100??? Well, failure is */ + param_set_t lm; + for (lm = 0; lm < 100; lm++) /* 100??? Well, failure is */ + do { /* quick, so it's not that expensive to test a lot */ bool expect_success; switch (lm) { case LMS_SHA256_N32_H5: case LMS_SHA256_N32_H10: case LMS_SHA256_N32_H15: + case LMS_SHA256_N24_H5: + case LMS_SHA256_N24_H10: + case LMS_SHA256_N24_H15: + case LMS_SHAKE256_N32_H5: + case LMS_SHAKE256_N32_H10: + case LMS_SHAKE256_N32_H15: + case LMS_SHAKE256_N24_H5: + case LMS_SHAKE256_N24_H10: + case LMS_SHAKE256_N24_H15: expect_success = true; break; case LMS_SHA256_N32_H20: - if (i == 0 && fast_flag) continue; /* This parm set */ - /* takes too long for fast mode */ + case LMS_SHA256_N24_H20: + case LMS_SHAKE256_N32_H20: + case LMS_SHAKE256_N24_H20: + if (i == 0 && fast_flag) goto next_iter; /* This parm */ + /* set takes too long for fast mode */ /* (20 seconds on my test machine) */ expect_success = true; break; case LMS_SHA256_N32_H25: - if (i == 0) continue; /* This parm set takes too long */ - /* even for full mode; 10 minutes */ - /* for a test that doesn't tell */ - /* us much */ + case LMS_SHA256_N24_H25: + case LMS_SHAKE256_N32_H25: + case LMS_SHAKE256_N24_H25: + if (i == 0) goto next_iter; /* This parm set takes too */ + /* long even for full mode; 10 */ + /* minutes for a test that doesn't */ + /* tell us much */ expect_success = true; break; default: /* All unsupported LM types */ expect_success = false; break; @@ -223,10 +239,10 @@ bool test_keygen(bool fast_flag, bool quiet_flag) { d, lm_type, ots_type, ignore_priv_key, NULL, pub_key, len_pub_key, NULL, 0, &info); - lm_type[i] = LMS_SHA256_N32_H5; + lm_type[i] = LMS_SHA256_N24_H5; if (expect_success != got_success) { - printf( "Keygen with lm_type[%d] = %d: success = %d\n", - i, lm, got_success ); + printf( "Keygen with lm_type[%d] = %x: success = %d\n", + i, (unsigned)lm, got_success ); return false; } if (!got_success && hss_extra_info_test_error_code(&info) != @@ -234,19 +250,33 @@ bool test_keygen(bool fast_flag, bool quiet_flag) { printf( "Bad parm set got incorrect error\n" ); return false; } - } - } +next_iter: lm ^= 0xe0000000L; /* Cycle through the e000000 parm sets */ + } while (lm & 0x80000000L); + } /* Now, try various lm_ots_types (both legal and illegal) */ for (i=0; i<3; i++) { - int ots; - for (ots = 0; ots < 100; ots++) { + param_set_t ots; + for (ots = 0; ots < 100; ots++) + do { bool expect_success; switch (ots) { case LMOTS_SHA256_N32_W1: case LMOTS_SHA256_N32_W2: case LMOTS_SHA256_N32_W4: case LMOTS_SHA256_N32_W8: + case LMOTS_SHA256_N24_W1: + case LMOTS_SHA256_N24_W2: + case LMOTS_SHA256_N24_W4: + case LMOTS_SHA256_N24_W8: + case LMOTS_SHAKE256_N32_W1: + case LMOTS_SHAKE256_N32_W2: + case LMOTS_SHAKE256_N32_W4: + case LMOTS_SHAKE256_N32_W8: + case LMOTS_SHAKE256_N24_W1: + case LMOTS_SHAKE256_N24_W2: + case LMOTS_SHAKE256_N24_W4: + case LMOTS_SHAKE256_N24_W8: expect_success = true; break; default: /* All unsupported LM types */ expect_success = false; break; @@ -258,9 +288,9 @@ bool test_keygen(bool fast_flag, bool quiet_flag) { d, lm_type, ots_type, ignore_priv_key, NULL, pub_key, len_pub_key, NULL, 0, &info); - ots_type[i] = LMOTS_SHA256_N32_W2; + ots_type[i] = LMOTS_SHA256_N24_W4; if (expect_success != got_success) { - printf( "Keygen with ots_type[%d] = %d: success = %d\n", i, ots, got_success ); + printf( "Keygen with ots_type[%d] = %x: success = %d\n", i, (unsigned)ots, got_success ); return false; } if (!got_success && hss_extra_info_test_error_code(&info) != @@ -268,7 +298,8 @@ bool test_keygen(bool fast_flag, bool quiet_flag) { printf( "Bad parm set got incorrect error\n" ); return false; } - } + ots ^= 0xe0000000L; /* Cycle through the e000000 parm sets */ + } while (ots & 0x80000000L); } } @@ -343,13 +374,35 @@ bool test_keygen(bool fast_flag, bool quiet_flag) { /* Check out the aux data, for various parameter sets and lengths of */ /* aux data */ int i; - for (i=LMS_SHA256_N32_H5; i<=LMS_SHA256_N32_H20; i++) { + static param_set_t parms_to_test[] = { + LMS_SHA256_N32_H5, + LMS_SHA256_N24_H5, + LMS_SHA256_N32_H10, + LMS_SHA256_N24_H10, + LMS_SHA256_N32_H15, + LMS_SHA256_N24_H15, + LMS_SHAKE256_N32_H5, + LMS_SHAKE256_N24_H5, + LMS_SHAKE256_N32_H10, + LMS_SHAKE256_N24_H10, + LMS_SHAKE256_N32_H15, + LMS_SHAKE256_N24_H15, + 0, /* Stop here if not fastflag */ + LMS_SHA256_N32_H20, + LMS_SHA256_N24_H20, + LMS_SHAKE256_N32_H20, + LMS_SHAKE256_N24_H20, + }; + for (i=0; i HSS_MAX_PUBLIC_KEY_LEN || !sig_size || !privkey_size || privkey_size > HSS_MAX_PRIVATE_KEY_LEN) { - printf( "Internal error: bad parm set %d\n", i ); + printf( "Internal error: bad parm set %x\n", (unsigned)lm_type[0] ); return false; } unsigned char pubkey[HSS_MAX_PUBLIC_KEY_LEN], @@ -432,10 +485,11 @@ static bool gen_signature( unsigned char *privkey, unsigned char *sig, size_t sig_len, const unsigned char *pubkey) { /* Step 1: load the working key */ + struct hss_extra_info info = { 0 }; struct hss_working_key *w = hss_load_private_key(NULL, privkey, - 0, aux_data, aux_len, 0 ); + 0, aux_data, aux_len, &info ); if (!w) { - printf( "Error loading working key\n" ); + printf( "Error loading working key ; error_code = %x\n" , info.error_code); return false; } diff --git a/test_keyload.c b/test_keyload.c index df278ec..c0ad811 100644 --- a/test_keyload.c +++ b/test_keyload.c @@ -1,7 +1,7 @@ /* * This test runs a fairly exhaustive test on the key loading functionality * - * It runs 3000 parallel working keys of the same private key; working key i + * It runs 4000 parallel working keys of the same private key; working key i * will be loaded at step i, and then generate signatures from that point; * for example, at step 3, we'll have three working keys; one which was loaded * at index 0 (and has produced 3 signatures so far); one which was loaded @@ -19,7 +19,7 @@ * It also does a pretty decent test on whether our Merkle tree traversal * logic is always traversing properly. * - * It takes 20 minutes to do a full test on my test machine + * It takes 30 minutes to do a full test on my test machine */ #include "hss.h" #include "hash.h" @@ -28,13 +28,14 @@ #include #include -#define PARM_SET LMS_SHA256_N32_H5 -#define PARM_SET_2 LMOTS_SHA256_N32_W2 +/* Use these parm sets because they're the fastest */ +#define PARM_SET LMS_SHA256_N24_H5 +#define PARM_SET_2 LMOTS_SHA256_N24_W2 #define LEVELS 3 -#define MAX_ITER 3000 -#define FAST_ITER 300 /* Number of iterations to run in fast more */ +#define MAX_ITER 4000 +#define FAST_ITER 400 /* Number of iterations to run in fast mode */ static bool generate_random(void *output, size_t length) { unsigned char *p = output; diff --git a/test_load.c b/test_load.c index 0ad1ef3..5c9d93f 100644 --- a/test_load.c +++ b/test_load.c @@ -20,45 +20,45 @@ static bool rand_1( void *output, size_t len) { * This test is here mainly to verify that we generate the correct * working set even if the aux data is corrupted */ -static bool test_aux( param_set_t lm_setting ) { +static bool test_aux( param_set_t lm_setting, param_set_t ots_setting, + unsigned hash_len ) { int levels = 2; param_set_t lm[2]; lm[0] = lm_setting; - lm[1] = LMS_SHA256_N32_H5; - param_set_t ots[2] = { LMOTS_SHA256_N32_W2, LMOTS_SHA256_N32_W2 }; + lm[1] = LMS_SHA256_N24_H5; + param_set_t ots[2]; + ots[0] = ots_setting; + ots[1] = LMOTS_SHA256_N32_W2; unsigned char priv_key[HSS_MAX_PRIVATE_KEY_LEN]; unsigned char len_pub_key = hss_get_public_key_len(levels, lm, ots); - if (!len_pub_key || len_pub_key > HSS_MAX_PUBLIC_KEY_LEN) return false; - unsigned char pub_key[HSS_MAX_PUBLIC_KEY_LEN]; + if (!len_pub_key) return false; + unsigned char pub_key[len_pub_key]; size_t len_sig = hss_get_signature_len(levels, lm, ots); if (!len_sig) return false; - unsigned char *sig = malloc(len_sig); - if (!sig) return false; + unsigned char sig[len_sig]; int i; - unsigned char aux_data[50000]; /* 50000 is the largest auxdata we try */ for (i=0; i<2; i++) { unsigned aux_size = (i ? 50000 : 500); + unsigned char aux_data[aux_size]; if (!hss_generate_private_key( rand_1, levels, lm, ots, NULL, priv_key, pub_key, sizeof pub_key, aux_data, aux_size, 0)) { printf( "Error generating private key\n" ); - free(sig); return false; } /* Corrupt the aux data; we corrupt location 36 because that's on */ /* the aux path of the initial signature; hence if the corruption */ /* is not detected, the first signature would be wrong */ - aux_data[36] ^= 0x01; + aux_data[hash_len+4] ^= 0x01; /* Now, load the working key */ struct hss_working_key *w = hss_load_private_key( - NULL, priv_key, 0, aux_data, aux_size, 0 ); + NULL, priv_key, 0, aux_data, aux_size, 0); if (!w) { printf( "Error loading private key\n" ); - free(sig); return false; } @@ -66,32 +66,29 @@ static bool test_aux( param_set_t lm_setting ) { static unsigned char test_message[1] = "a"; if (!hss_generate_signature(w, NULL, priv_key, test_message, sizeof test_message, - sig, len_sig, 0)) { + sig, sizeof sig, 0)) { hss_free_working_key(w); printf( "Error generating signature\n" ); - free(sig); return false; } /* Verify the signature */ bool v = hss_validate_signature(pub_key, test_message, sizeof test_message, - sig, len_sig, 0); + sig, sizeof sig, 0); hss_free_working_key(w); if (!v) { printf( "Error validating signature from altered aux\n" ); - free(sig); return false; } } - free(sig); return true; } -#define NUM_PARM_SETS 4 +#define NUM_PARM_SETS 11 -static bool load_key( int *index, unsigned char priv_key[][HSS_MAX_PRIVATE_KEY_LEN], +static bool load_key( int *index, unsigned char priv_key[][48], struct hss_working_key **w, int levels, ...) { int i; int n = *index; @@ -108,8 +105,8 @@ static bool load_key( int *index, unsigned char priv_key[][HSS_MAX_PRIVATE_KEY_L va_list arg; va_start(arg, levels); for (i=0; i +#include +#include "hash.h" +#include "test_hss.h" + +/* + * Run the test vector on the various internal SHAKE APIs + */ +static bool do_hash_test( const unsigned char *input, unsigned len_input, + const unsigned char *expected_output, + int hash_type, unsigned len_output ) { + unsigned char output[32+1]; + + int fence; + for (fence=3; fence<=4; fence++) { + output[len_output] = fence; /* To detect it if the hash function */ + /* generated a longer output than it is supposed to */ + + /* Check the simple hash implementation */ + memset( output, 0, len_output ); + hss_hash(output, hash_type, input, len_input ); + /* Check if the output is what we expect */ + if (0 != memcmp( output, expected_output, len_output )) return false; + /* Check if the hash function generated more output than */ + /* we expect */ + if (output[len_output] != fence) return false; + + /* Check the context implementation */ + union hash_context ctx; + memset( output, 0, len_output ); + hss_hash_ctx(output, hash_type, &ctx, input, len_input ); + if (0 != memcmp( output, expected_output, len_output )) return false; + if (output[len_output] != fence) return false; + + /* Check the incremental version, stepping through the possible */ + /* increments */ + int incr; + for (incr = 1; incr <= len_input; incr++) { + + hss_init_hash_context( hash_type, &ctx ); + int offset; + for (offset=0; offset < len_input; offset += incr ) { + int this_block = incr; + if (offset + this_block > len_input) { + this_block = len_input - offset; + } + hss_update_hash_context( hash_type, &ctx, + &input[offset], this_block ); + } + memset( output, 0, len_output ); + hss_finalize_hash_context( hash_type, &ctx, output ); + if (0 != memcmp( output, expected_output, len_output )) { + return false; + } + if (output[len_output] != fence) return false; + } + } + return true; +} + +/* + * Run the test vector on both SHAKE hash functions (the 256 bit and the 192 + * bit versions) that we provide + */ +static bool do_test( const unsigned char *input, unsigned len_input, + const unsigned char *expected_output ) { + if (!do_hash_test( input, len_input, expected_output, HASH_SHAKE256, 32 )) + return false; + if (!do_hash_test( input, len_input, expected_output, HASH_SHAKE256_24, 24 )) + return false; + return true; +} + +/* + * These test vectors were extracted from SHAKE256ShortMsg.rsp + * If the inputs appear to be rather arbitrary, well, complain to NIST + */ +bool test_shake(bool fast_flag, bool quiet_flag) { + { + const unsigned char input[] = { + 0x4a, 0x71, 0x96, 0x4b + }; + const unsigned char expected_output[] = { + 0x7b,0x7e,0x12,0xd2,0xa5,0x20,0xe2,0x32, + 0xfd,0xe6,0xc4,0x1d,0xbb,0xb2,0xb8,0xb7, + 0x4c,0x29,0x12,0xfb,0x3f,0x15,0x40,0x4f, + 0x73,0x04,0xfe,0x46,0x69,0x14,0x30,0xc9 + }; + + if (!do_test(input, sizeof input, expected_output)) return false; + } + + /* 47 byte input; the input size we see when doing a OTS computation */ + /* with a 192 bit hash */ + { + const unsigned char input[] = { + 0x43,0xfa,0x7c,0x73,0xc6,0x19,0x6e,0xf2, + 0x8d,0x3a,0xe7,0x34,0xfd,0x80,0x8c,0x1d, + 0x01,0x7e,0xb9,0x64,0xfd,0x54,0x18,0xdf, + 0x04,0x1b,0x73,0x01,0x4a,0x84,0xc6,0xa1, + 0xdc,0xbb,0x99,0xfc,0x8e,0x92,0x8c,0xfe, + 0x35,0xdb,0x34,0xbd,0x17,0x15,0x25 + }; + const unsigned char expected_output[] = { + 0x96,0x20,0xf7,0xda,0x5b,0x74,0x10,0xfe, + 0x8d,0xb4,0xe7,0x77,0x96,0xf5,0x57,0x0d, + 0x5a,0xde,0xf8,0xa3,0x44,0x17,0xbc,0x70, + 0xe6,0x0c,0xe6,0x8c,0x57,0x1e,0x8e,0x1e + }; + + if (!do_test(input, sizeof input, expected_output)) return false; + } + + /* 55 byte input; the input size we see when doing a OTS computation */ + /* with a 256 bit hash */ + { + const unsigned char input[] = { + 0x89,0xdb,0x45,0x54,0xee,0xc0,0x9a,0x89, + 0xf9,0xe4,0x9f,0x64,0xe5,0xe4,0x8e,0x0d, + 0xcd,0xc3,0x6e,0x3a,0x1d,0x8c,0x2c,0xf6, + 0x47,0x38,0xed,0xa2,0xb7,0xd1,0xa3,0x39, + 0x08,0xd8,0xde,0xd8,0x78,0xe5,0xe6,0x7d, + 0x99,0x8d,0x06,0x0e,0x4a,0x88,0x2a,0x9e, + 0xe6,0x13,0xad,0xed,0xbb,0x94,0x6c + }; + const unsigned char expected_output[] = { + 0xfd,0xd0,0xd8,0xe3,0x1a,0xb4,0x50,0x23, + 0x17,0xa9,0x02,0x93,0xa3,0x88,0x8e,0xdc, + 0xe2,0x8a,0xe9,0xa5,0x87,0x4b,0x71,0x67, + 0x38,0xa9,0x3b,0x25,0xdb,0x6d,0xe6,0x6d + }; + + if (!do_test(input, sizeof input, expected_output)) return false; + } + + /* 195 byte input; this is larger than the internal Keccak rate, and */ + /* hence the implemetation will need to perform multiple permutations */ + { + const unsigned char input[] = { + 0xc4,0x36,0xd1,0x9f,0x05,0x55,0x0b,0x69, + 0x79,0xbd,0xc6,0x9b,0xfd,0x27,0xea,0x4c, + 0xd8,0x0c,0x1a,0x60,0xf0,0x0a,0x8b,0x09, + 0x3e,0x89,0x17,0x8c,0x7f,0x9e,0x8d,0x49, + 0x2c,0x30,0x4c,0xf6,0xad,0x59,0x10,0x2b, + 0xca,0x0e,0x0b,0x23,0x62,0x03,0x38,0xc1, + 0x5f,0xc9,0xec,0xd1,0xe9,0x39,0xae,0x91, + 0xda,0x16,0x48,0x6f,0x72,0xee,0x1e,0x15, + 0x4d,0x41,0xbf,0xa3,0x91,0xe6,0xba,0x3b, + 0x6c,0xa9,0xb3,0xc3,0xbe,0x39,0xb5,0xe6, + 0x12,0x42,0xca,0x5c,0xd3,0xd6,0xc9,0x6c, + 0xbd,0x11,0x70,0xaf,0x91,0xfd,0xb2,0x16, + 0x0d,0xb3,0x52,0x2e,0x1b,0xc3,0xb1,0xa3, + 0x49,0xd6,0xe5,0x04,0x79,0x92,0x0a,0xc5, + 0xd9,0xbe,0xdd,0x8a,0x16,0xa7,0x87,0xa3, + 0xcd,0xc2,0xb6,0xd2,0x43,0x92,0xf2,0x55, + 0x55,0xcc,0x2f,0x20,0xb2,0xba,0x9e,0x6b, + 0x47,0xdd,0xc9,0x6c,0xfb,0xd6,0xdf,0x66, + 0x9d,0x87,0x4c,0xe2,0x1a,0x75,0x8d,0x3c, + 0xf4,0x70,0x43,0x62,0xef,0x77,0x86,0xd9, + 0x0e,0xd6,0x7b,0x01,0xbd,0x91,0x29,0x99, + 0x50,0x05,0x88,0x85,0xac,0xcd,0xdb,0xcf, + 0x44,0xe3,0x40,0xed,0x48,0x07,0x86,0x42, + 0x18,0x65,0x3e,0xe7,0xff,0x72,0x15,0xaa, + 0x1e,0x17,0x61 + }; + const unsigned char expected_output[] = { + 0x20,0x6b,0xe7,0x26,0xfc,0x68,0x13,0x67, + 0x38,0x7f,0xf0,0xa1,0x53,0x03,0x53,0x30, + 0x58,0x07,0x0f,0x96,0x55,0x43,0x8a,0xd8, + 0x14,0x2c,0xf3,0x9a,0x05,0x23,0xb2,0xce, + }; + + if (!do_test(input, sizeof input, expected_output)) return false; + } + + return true; +} diff --git a/test_sign.c b/test_sign.c index 56e22bf..b10b2e5 100644 --- a/test_sign.c +++ b/test_sign.c @@ -33,11 +33,34 @@ static unsigned long get_int(const unsigned char *p) { static int lookup_h(unsigned long val) { switch (val) { - case LMS_SHA256_N32_H5: return 5; - case LMS_SHA256_N32_H10: return 10; - case LMS_SHA256_N32_H15: return 15; - case LMS_SHA256_N32_H20: return 20; - case LMS_SHA256_N32_H25: return 25; + case LMS_SHA256_N32_H5: + case LMS_SHA256_N24_H5: return 5; + case LMS_SHA256_N32_H10: + case LMS_SHA256_N24_H10: return 10; + case LMS_SHA256_N32_H15: + case LMS_SHA256_N24_H15: return 15; + case LMS_SHA256_N32_H20: + case LMS_SHA256_N24_H20: return 20; + case LMS_SHA256_N32_H25: + case LMS_SHA256_N24_H25: return 25; + default: return 0; + } +} + +static int lookup_n(unsigned long val) { + switch (val) { + case LMS_SHA256_N32_H5: + case LMS_SHA256_N32_H10: + case LMS_SHA256_N32_H15: + case LMS_SHA256_N32_H20: + case LMS_SHA256_N32_H25: + return 32; + case LMS_SHA256_N24_H5: + case LMS_SHA256_N24_H10: + case LMS_SHA256_N24_H15: + case LMS_SHA256_N24_H20: + case LMS_SHA256_N24_H25: + return 24; default: return 0; } } @@ -47,27 +70,52 @@ static bool test_parm( int d, long num_sig, ... ); bool test_sign(bool fast_flag, bool quiet_flag) { /* Test out various parameter sets */ - if (!test_parm( 1, 32, LMS_SHA256_N32_H5, LMOTS_SHA256_N32_W1 )) return false; - if (!test_parm( 1, 32, LMS_SHA256_N32_H5, LMOTS_SHA256_N32_W2 )) return false; - if (!test_parm( 1, 32, LMS_SHA256_N32_H5, LMOTS_SHA256_N32_W4 )) return false; - if (!test_parm( 1, 32, LMS_SHA256_N32_H5, LMOTS_SHA256_N32_W8 )) return false; - if (!test_parm( 1, 1024, LMS_SHA256_N32_H10, LMOTS_SHA256_N32_W2 )) return false; - if (!test_parm( 2, 1024, LMS_SHA256_N32_H5, LMOTS_SHA256_N32_W4, - LMS_SHA256_N32_H5, LMOTS_SHA256_N32_W2 )) return false; - if (!test_parm( 1, 32768, LMS_SHA256_N32_H15, LMOTS_SHA256_N32_W2 )) return false; - if (!test_parm( 2, 32768, LMS_SHA256_N32_H10, LMOTS_SHA256_N32_W4, - LMS_SHA256_N32_H5, LMOTS_SHA256_N32_W2 )) return false; - if (!test_parm( 2, 32768, LMS_SHA256_N32_H5, LMOTS_SHA256_N32_W4, - LMS_SHA256_N32_H10, LMOTS_SHA256_N32_W2 )) return false; - if (!test_parm( 3, 32768, LMS_SHA256_N32_H5, LMOTS_SHA256_N32_W4, - LMS_SHA256_N32_H5, LMOTS_SHA256_N32_W4, - LMS_SHA256_N32_H5, LMOTS_SHA256_N32_W2 )) return false; + typedef unsigned long ul; + if (!test_parm( 1, 32, (ul)LMS_SHA256_N32_H5, (ul)LMOTS_SHA256_N32_W1 )) return false; + if (!test_parm( 1, 32, (ul)LMS_SHA256_N24_H5, (ul)LMOTS_SHA256_N24_W1 )) return false; + if (!test_parm( 1, 32, (ul)LMS_SHA256_N32_H5, (ul)LMOTS_SHA256_N32_W2 )) return false; + if (!test_parm( 1, 32, (ul)LMS_SHA256_N24_H5, (ul)LMOTS_SHA256_N24_W2 )) return false; + if (!test_parm( 1, 32, (ul)LMS_SHA256_N32_H5, (ul)LMOTS_SHA256_N32_W4 )) return false; + if (!test_parm( 1, 32, (ul)LMS_SHA256_N24_H5, (ul)LMOTS_SHA256_N24_W4 )) return false; + if (!test_parm( 1, 32, (ul)LMS_SHA256_N32_H5, (ul)LMOTS_SHA256_N32_W8 )) return false; + if (!test_parm( 1, 32, (ul)LMS_SHA256_N24_H5, (ul)LMOTS_SHA256_N24_W8 )) return false; + if (!test_parm( 1, 1024, (ul)LMS_SHA256_N32_H10, (ul)LMOTS_SHA256_N32_W2 )) return false; + if (!test_parm( 1, 1024, (ul)LMS_SHA256_N24_H10, (ul)LMOTS_SHA256_N24_W2 )) return false; + if (!test_parm( 1, 1024, (ul)LMS_SHA256_N32_H10, (ul)LMOTS_SHA256_N24_W2 )) return false; + if (!test_parm( 1, 1024, (ul)LMS_SHA256_N24_H10, (ul)LMOTS_SHA256_N32_W2 )) return false; + if (!test_parm( 2, 1024, (ul)LMS_SHA256_N32_H5, (ul)LMOTS_SHA256_N32_W4, + (ul)LMS_SHA256_N32_H5, (ul)LMOTS_SHA256_N32_W2 )) return false; + if (!test_parm( 2, 1024, (ul)LMS_SHA256_N24_H5, (ul)LMOTS_SHA256_N24_W4, + (ul)LMS_SHA256_N24_H5, (ul)LMOTS_SHA256_N24_W2 )) return false; + if (!test_parm( 2, 1024, (ul)LMS_SHA256_N32_H5, (ul)LMOTS_SHA256_N32_W4, + (ul)LMS_SHA256_N24_H5, (ul)LMOTS_SHA256_N24_W2 )) return false; + if (!test_parm( 2, 1024, (ul)LMS_SHA256_N24_H5, (ul)LMOTS_SHA256_N24_W4, + (ul)LMS_SHA256_N32_H5, (ul)LMOTS_SHA256_N32_W2 )) return false; + if (!test_parm( 1, 32768, (ul)LMS_SHA256_N32_H15, (ul)LMOTS_SHA256_N32_W2 )) return false; + if (!test_parm( 1, 32768, (ul)LMS_SHA256_N24_H15, (ul)LMOTS_SHA256_N24_W2 )) return false; + if (!fast_flag) { + if (!test_parm( 2, 32768, (ul)LMS_SHA256_N32_H10, (ul)LMOTS_SHA256_N32_W4, + (ul)LMS_SHA256_N32_H5, (ul)LMOTS_SHA256_N32_W2 )) return false; + if (!test_parm( 2, 32768, (ul)LMS_SHA256_N24_H10, (ul)LMOTS_SHA256_N24_W4, + (ul)LMS_SHA256_N24_H5, (ul)LMOTS_SHA256_N24_W2 )) return false; + if (!test_parm( 2, 32768, (ul)LMS_SHA256_N32_H5, (ul)LMOTS_SHA256_N32_W4, + (ul)LMS_SHA256_N32_H10, (ul)LMOTS_SHA256_N32_W2 )) return false; + if (!test_parm( 2, 32768, (ul)LMS_SHA256_N24_H5, (ul)LMOTS_SHA256_N24_W4, + (ul)LMS_SHA256_N24_H10, (ul)LMOTS_SHA256_N24_W2 )) return false; + if (!test_parm( 3, 32768, (ul)LMS_SHA256_N32_H5, (ul)LMOTS_SHA256_N32_W4, + (ul)LMS_SHA256_N32_H5, (ul)LMOTS_SHA256_N32_W4, + (ul)LMS_SHA256_N32_H5, (ul)LMOTS_SHA256_N32_W2 )) return false; + if (!test_parm( 3, 32768, (ul)LMS_SHA256_N24_H5, (ul)LMOTS_SHA256_N24_W4, + (ul)LMS_SHA256_N24_H5, (ul)LMOTS_SHA256_N24_W4, + (ul)LMS_SHA256_N24_H5, (ul)LMOTS_SHA256_N24_W2 )) return false; + } return true; } static bool test_parm( int d, long num_sig, ... ) { - if (d < 1 || d > 8) return false; /* A different test suite checks that out */ + if (d < 1 || d > 8) return false; /* A different test suite checks */ + /* out illegal numbers of levels */ /* Gather up the parameter set */ param_set_t lm_type[8]; @@ -77,8 +125,8 @@ static bool test_parm( int d, long num_sig, ... ) { va_start(arg, num_sig); int i; for (i=0; i HSS_MAX_PUBLIC_KEY_LEN || - !sig_size || - !privkey_size || privkey_size > HSS_MAX_PRIVATE_KEY_LEN) { + if (!pubkey_size || !sig_size || !privkey_size) { printf( "Internal error: bad parm set\n" ); return false; } - unsigned char pubkey[HSS_MAX_PUBLIC_KEY_LEN]; - unsigned char *sig = malloc(sig_size); - if (!sig) return false; - unsigned char privkey[HSS_MAX_PRIVATE_KEY_LEN]; + unsigned char pubkey[pubkey_size]; + unsigned char sig[sig_size]; + unsigned char privkey[privkey_size]; if (!hss_generate_private_key( rand_1, d, lm_type, ots_type, NULL, privkey, pubkey, pubkey_size, NULL, 0, 0)) { printf( "Pubkey gen failure\n" ); - free(sig); return false; } @@ -109,7 +153,6 @@ static bool test_parm( int d, long num_sig, ... ) { 0, NULL, 0, 0 ); if (!w) { printf( "Error loading working key\n" ); - free(sig); return false; } @@ -126,13 +169,11 @@ static bool test_parm( int d, long num_sig, ... ) { if (success) { printf( "Error: signature succeeded with too small of a buffer\n" ); hss_free_working_key(w); - free(sig); return false; } if (hss_extra_info_test_error_code(&info) != hss_error_buffer_overflow) { printf( "Error: too small buffer gives wrong error\n" ); hss_free_working_key(w); - free(sig); return false; } @@ -143,13 +184,12 @@ static bool test_parm( int d, long num_sig, ... ) { if (success || !all_zeros(sig, sig_size)) { printf( "Error: signature succeeded when key update failed\n" ); hss_free_working_key(w); - free(sig); return false; } if (hss_extra_info_test_error_code(&info) != hss_error_private_key_write_failed) { - printf( "Error: update failure gives wrong error\n" ); + printf( "Error: update failure gives wrong error got %d expected %d\n", + hss_extra_info_test_error_code(&info), hss_error_private_key_write_failed ); hss_free_working_key(w); - free(sig); return false; } } @@ -177,7 +217,6 @@ static bool test_parm( int d, long num_sig, ... ) { if (hss_extra_info_test_error_code(&info) != hss_error_private_key_expired) { printf( "Error: private key expiry failure gives wrong error\n" ); hss_free_working_key(w); - free(sig); return false; } } @@ -223,13 +262,18 @@ static bool test_parm( int d, long num_sig, ... ) { case LMOTS_SHA256_N32_W2: offset += 32 + 32*133; break; case LMOTS_SHA256_N32_W4: offset += 32 + 32*67; break; case LMOTS_SHA256_N32_W8: offset += 32 + 32*34; break; + case LMOTS_SHA256_N24_W1: offset += 24 + 24*200; break; + case LMOTS_SHA256_N24_W2: offset += 24 + 24*101; break; + case LMOTS_SHA256_N24_W4: offset += 24 + 24*51; break; + case LMOTS_SHA256_N24_W8: offset += 24 + 24*26; break; default: goto failed; } /* Get the LM type */ get_next(val); if (val != lm_type[level]) goto failed; /* Skip the appropriate number of hashes */ int h = lookup_h(val); if (!h) goto failed; - offset += 32*h; + int n = lookup_n(val); if (!n) goto failed; + offset += n*h; /* Make sure that the q we got was in range */ if (q >= 1UL << h) goto failed; @@ -239,8 +283,9 @@ static bool test_parm( int d, long num_sig, ... ) { /* We're now into the public key; validate its parm set */ get_next(val); if (val != lm_type[level+1]) goto failed; h = lookup_h(val); if (!h) goto failed; seq_no <<= h; + n = lookup_n(val); if (!n) goto failed; get_next(val); if (val != ots_type[level+1]) goto failed; - offset += 16 + 32; + offset += 16 + n; } /* If the signature used the wrong sequence number, fail */ @@ -251,12 +296,14 @@ static bool test_parm( int d, long num_sig, ... ) { } hss_free_working_key(w); - free(sig); return retval; failed: printf( "Signature did not match expected\n" ); + printf( "Parameter set under test:\n" ); + for (i=0; i HSS_MAX_PRIVATE_KEY_LEN) { printf( " Len private key failed\n" ); @@ -324,30 +323,126 @@ bool test_sign_inc(bool fast_flag, bool quiet_flag) { param_set_t lm_ots_array[1] = { LMOTS_SHA256_N32_W8 }; if (!run_test( d, lm_array, lm_ots_array, 32, true )) return false; } + { + int d = 1; + param_set_t lm_array[1] = { LMS_SHA256_N24_H5 }; + param_set_t lm_ots_array[1] = { LMOTS_SHA256_N24_W8 }; + if (!run_test( d, lm_array, lm_ots_array, 32, true )) return false; + } + { + int d = 1; + param_set_t lm_array[1] = { LMS_SHA256_N24_H5 }; + param_set_t lm_ots_array[1] = { LMOTS_SHA256_N32_W8 }; + if (!run_test( d, lm_array, lm_ots_array, 32, true )) return false; + } + { + int d = 1; + param_set_t lm_array[1] = { LMS_SHA256_N32_H5 }; + param_set_t lm_ots_array[1] = { LMOTS_SHA256_N24_W8 }; + if (!run_test( d, lm_array, lm_ots_array, 32, true )) return false; + } + { + int d = 1; + param_set_t lm_array[1] = { LMS_SHAKE256_N24_H5 }; + param_set_t lm_ots_array[1] = { LMOTS_SHAKE256_N24_W8 }; + if (!run_test( d, lm_array, lm_ots_array, 32, true )) return false; + } + { + int d = 1; + param_set_t lm_array[1] = { LMS_SHAKE256_N32_H5 }; + param_set_t lm_ots_array[1] = { LMOTS_SHAKE256_N32_W8 }; + if (!run_test( d, lm_array, lm_ots_array, 32, true )) return false; + } { int d = 1; param_set_t lm_array[1] = { LMS_SHA256_N32_H10 }; param_set_t lm_ots_array[1] = { LMOTS_SHA256_N32_W4 }; if (!run_test( d, lm_array, lm_ots_array, 1024, true )) return false; } + { + int d = 1; + param_set_t lm_array[1] = { LMS_SHA256_N24_H10 }; + param_set_t lm_ots_array[1] = { LMOTS_SHA256_N24_W4 }; + if (!run_test( d, lm_array, lm_ots_array, 1024, true )) return false; + } + { + int d = 1; + param_set_t lm_array[1] = { LMS_SHAKE256_N32_H10 }; + param_set_t lm_ots_array[1] = { LMOTS_SHAKE256_N32_W4 }; + if (!run_test( d, lm_array, lm_ots_array, 1024, true )) return false; + } + { + int d = 1; + param_set_t lm_array[1] = { LMS_SHAKE256_N24_H10 }; + param_set_t lm_ots_array[1] = { LMOTS_SHAKE256_N24_W4 }; + if (!run_test( d, lm_array, lm_ots_array, 1024, true )) return false; + } { int d = 2; param_set_t lm_array[2] = { LMS_SHA256_N32_H5, LMS_SHA256_N32_H5 }; param_set_t lm_ots_array[2] = { LMOTS_SHA256_N32_W4, LMOTS_SHA256_N32_W2 }; if (!run_test( d, lm_array, lm_ots_array, 1024, true )) return false; } + { + int d = 2; + param_set_t lm_array[2] = { LMS_SHA256_N24_H5, LMS_SHA256_N24_H5 }; + param_set_t lm_ots_array[2] = { LMOTS_SHA256_N24_W4, LMOTS_SHA256_N24_W2 }; + if (!run_test( d, lm_array, lm_ots_array, 1024, true )) return false; + } + { + int d = 2; + param_set_t lm_array[2] = { LMS_SHA256_N32_H5, LMS_SHA256_N24_H5 }; + param_set_t lm_ots_array[2] = { LMOTS_SHA256_N24_W4, LMOTS_SHA256_N24_W2 }; + if (!run_test( d, lm_array, lm_ots_array, 1024, true )) return false; + } + { + int d = 2; + param_set_t lm_array[2] = { LMS_SHA256_N24_H5, LMS_SHA256_N32_H5 }; + param_set_t lm_ots_array[2] = { LMOTS_SHA256_N24_W4, LMOTS_SHA256_N24_W2 }; + if (!run_test( d, lm_array, lm_ots_array, 1024, true )) return false; + } + { + int d = 2; + param_set_t lm_array[2] = { LMS_SHA256_N24_H5, LMS_SHA256_N24_H5 }; + param_set_t lm_ots_array[2] = { LMOTS_SHA256_N32_W4, LMOTS_SHA256_N24_W2 }; + if (!run_test( d, lm_array, lm_ots_array, 1024, true )) return false; + } + { + int d = 2; + param_set_t lm_array[2] = { LMS_SHAKE256_N24_H5, LMS_SHAKE256_N24_H5 }; + param_set_t lm_ots_array[2] = { LMOTS_SHAKE256_N24_W4, LMOTS_SHAKE256_N24_W2 }; + if (!run_test( d, lm_array, lm_ots_array, 1024, true )) return false; + } + { + int d = 2; + param_set_t lm_array[2] = { LMS_SHAKE256_N32_H5, LMS_SHAKE256_N32_H5 }; + param_set_t lm_ots_array[2] = { LMOTS_SHAKE256_N32_W4, LMOTS_SHAKE256_N32_W2 }; + if (!run_test( d, lm_array, lm_ots_array, 1024, true )) return false; + } + { + int d = 2; + param_set_t lm_array[2] = { LMS_SHA256_N24_H5, LMS_SHA256_N24_H5 }; + param_set_t lm_ots_array[2] = { LMOTS_SHA256_N24_W4, LMOTS_SHA256_N32_W2 }; + if (!run_test( d, lm_array, lm_ots_array, 1024, true )) return false; + } { int d = 2; param_set_t lm_array[2] = { LMS_SHA256_N32_H10, LMS_SHA256_N32_H5 }; param_set_t lm_ots_array[2] = { LMOTS_SHA256_N32_W8, LMOTS_SHA256_N32_W2 }; if (!run_test( d, lm_array, lm_ots_array, 100, false )) return false; } + { + int d = 2; + param_set_t lm_array[2] = { LMS_SHA256_N24_H10, LMS_SHA256_N24_H5 }; + param_set_t lm_ots_array[2] = { LMOTS_SHA256_N24_W8, LMOTS_SHA256_N24_W2 }; + if (!run_test( d, lm_array, lm_ots_array, 100, false )) return false; + } { int d = 3; param_set_t lm_array[3] = { - LMS_SHA256_N32_H10, LMS_SHA256_N32_H5, LMS_SHA256_N32_H5 }; + LMS_SHA256_N24_H10, LMS_SHA256_N24_H5, LMS_SHA256_N24_H5 }; param_set_t lm_ots_array[3] = { - LMOTS_SHA256_N32_W8, LMOTS_SHA256_N32_W4, LMOTS_SHA256_N32_W2 }; + LMOTS_SHA256_N24_W8, LMOTS_SHA256_N24_W4, LMOTS_SHA256_N24_W2 }; if (!run_test( d, lm_array, lm_ots_array, 2000, false )) return false; } @@ -364,9 +459,9 @@ bool test_sign_inc(bool fast_flag, bool quiet_flag) { { int d = 3; param_set_t lm_array[3] = { - LMS_SHA256_N32_H10, LMS_SHA256_N32_H5, LMS_SHA256_N32_H5 }; + LMS_SHA256_N24_H10, LMS_SHA256_N24_H5, LMS_SHA256_N24_H5 }; param_set_t lm_ots_array[3] = { - LMOTS_SHA256_N32_W8, LMOTS_SHA256_N32_W8, LMOTS_SHA256_N32_W8 }; + LMOTS_SHA256_N24_W8, LMOTS_SHA256_N24_W8, LMOTS_SHA256_N24_W8 }; int num_iter; if (fast_flag) num_iter = 100; else num_iter = 10000; if (!run_test_2( d, lm_array, lm_ots_array, num_iter )) return false; diff --git a/test_testvector.c b/test_testvector.c index 05c46cd..9afa4d3 100644 --- a/test_testvector.c +++ b/test_testvector.c @@ -913,8 +913,459 @@ bool test_testvector_2(void) { return verified; } +bool test_testvector_3(void) { + /* This is test case 3 */ + /* This is the SHA256/192 test from draft-fluhrer-lms-more-parm_sets */ + static const unsigned char public_key[] = { + 0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x0a, + 0x00,0x00,0x00,0x08, + 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27, + 0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f, + 0x2c,0x57,0x14,0x50,0xae,0xd9,0x9c,0xfb, + 0x4f,0x4a,0xc2,0x85,0xda,0x14,0x88,0x27, + 0x96,0x61,0x83,0x14,0x50,0x8b,0x12,0xd2, + }; + static const unsigned char message[] = { + 0x54,0x65,0x73,0x74,0x20,0x6d,0x65,0x73, + 0x73,0x61,0x67,0x65,0x20,0x66,0x6f,0x72, + 0x20,0x53,0x48,0x41,0x32,0x35,0x36,0x2d, + 0x31,0x39,0x32,0x0a, + }; + static const unsigned char signature[] = { + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05, + 0x00,0x00,0x00,0x08, + 0x0b,0x50,0x40,0xa1,0x8c,0x1b,0x5c,0xab, + 0xcb,0xc8,0x5b,0x04,0x74,0x02,0xec,0x62, + 0x94,0xa3,0x0d,0xd8,0xda,0x8f,0xc3,0xda, + 0xe1,0x3b,0x9f,0x08,0x75,0xf0,0x93,0x61, + 0xdc,0x77,0xfc,0xc4,0x48,0x1e,0xa4,0x63, + 0xc0,0x73,0x71,0x62,0x49,0x71,0x91,0x93, + 0x61,0x4b,0x83,0x5b,0x46,0x94,0xc0,0x59, + 0xf1,0x2d,0x3a,0xed,0xd3,0x4f,0x3d,0xb9, + 0x3f,0x35,0x80,0xfb,0x88,0x74,0x3b,0x8b, + 0x3d,0x06,0x48,0xc0,0x53,0x7b,0x7a,0x50, + 0xe4,0x33,0xd7,0xea,0x9d,0x66,0x72,0xff, + 0xfc,0x5f,0x42,0x77,0x0f,0xea,0xb4,0xf9, + 0x8e,0xb3,0xf3,0xb2,0x3f,0xd2,0x06,0x1e, + 0x4d,0x0b,0x38,0xf8,0x32,0x86,0x0a,0xe7, + 0x66,0x73,0xad,0x1a,0x1a,0x52,0xa9,0x00, + 0x5d,0xcf,0x1b,0xfb,0x56,0xfe,0x16,0xff, + 0x72,0x36,0x27,0x61,0x2f,0x9a,0x48,0xf7, + 0x90,0xf3,0xc4,0x7a,0x67,0xf8,0x70,0xb8, + 0x1e,0x91,0x9d,0x99,0x91,0x9c,0x8d,0xb4, + 0x81,0x68,0x83,0x8c,0xec,0xe0,0xab,0xfb, + 0x68,0x3d,0xa4,0x8b,0x92,0x09,0x86,0x8b, + 0xe8,0xec,0x10,0xc6,0x3d,0x8b,0xf8,0x0d, + 0x36,0x49,0x8d,0xfc,0x20,0x5d,0xc4,0x5d, + 0x0d,0xd8,0x70,0x57,0x2d,0x6d,0x8f,0x1d, + 0x90,0x17,0x7c,0xf5,0x13,0x7b,0x8b,0xbf, + 0x7b,0xcb,0x67,0xa4,0x6f,0x86,0xf2,0x6c, + 0xfa,0x5a,0x44,0xcb,0xca,0xa4,0xe1,0x8d, + 0xa0,0x99,0xa9,0x8b,0x0b,0x3f,0x96,0xd5, + 0xac,0x8a,0xc3,0x75,0xd8,0xda,0x2a,0x7c, + 0x24,0x80,0x04,0xba,0x11,0xd7,0xac,0x77, + 0x5b,0x92,0x18,0x35,0x9c,0xdd,0xab,0x4c, + 0xf8,0xcc,0xc6,0xd5,0x4c,0xb7,0xe1,0xb3, + 0x5a,0x36,0xdd,0xc9,0x26,0x5c,0x08,0x70, + 0x63,0xd2,0xfc,0x67,0x42,0xa7,0x17,0x78, + 0x76,0x47,0x6a,0x32,0x4b,0x03,0x29,0x5b, + 0xfe,0xd9,0x9f,0x2e,0xaf,0x1f,0x38,0x97, + 0x05,0x83,0xc1,0xb2,0xb6,0x16,0xaa,0xd0, + 0xf3,0x1c,0xd7,0xa4,0xb1,0xbb,0x0a,0x51, + 0xe4,0x77,0xe9,0x4a,0x01,0xbb,0xb4,0xd6, + 0xf8,0x86,0x6e,0x25,0x28,0xa1,0x59,0xdf, + 0x3d,0x6c,0xe2,0x44,0xd2,0xb6,0x51,0x8d, + 0x1f,0x02,0x12,0x28,0x5a,0x3c,0x2d,0x4a, + 0x92,0x70,0x54,0xa1,0xe1,0x62,0x0b,0x5b, + 0x02,0xaa,0xb0,0xc8,0xc1,0x0e,0xd4,0x8a, + 0xe5,0x18,0xea,0x73,0xcb,0xa8,0x1f,0xcf, + 0xff,0x88,0xbf,0xf4,0x61,0xda,0xc5,0x1e, + 0x7a,0xb4,0xca,0x75,0xf4,0x7a,0x62,0x59, + 0xd2,0x48,0x20,0xb9,0x99,0x57,0x92,0xd1, + 0x39,0xf6,0x1a,0xe2,0xa8,0x18,0x6a,0xe4, + 0xe3,0xc9,0xbf,0xe0,0xaf,0x2c,0xc7,0x17, + 0xf4,0x24,0xf4,0x1a,0xa6,0x7f,0x03,0xfa, + 0xed,0xb0,0x66,0x51,0x15,0xf2,0x06,0x7a, + 0x46,0x84,0x3a,0x4c,0xbb,0xd2,0x97,0xd5, + 0xe8,0x3b,0xc1,0xaa,0xfc,0x18,0xd1,0xd0, + 0x3b,0x3d,0x89,0x4e,0x85,0x95,0xa6,0x52, + 0x60,0x73,0xf0,0x2a,0xb0,0xf0,0x8b,0x99, + 0xfd,0x9e,0xb2,0x08,0xb5,0x9f,0xf6,0x31, + 0x7e,0x55,0x45,0xe6,0xf9,0xad,0x5f,0x9c, + 0x18,0x3a,0xbd,0x04,0x3d,0x5a,0xcd,0x6e, + 0xb2,0xdd,0x4d,0xa3,0xf0,0x2d,0xbc,0x31, + 0x67,0xb4,0x68,0x72,0x0a,0x4b,0x8b,0x92, + 0xdd,0xfe,0x79,0x60,0x99,0x8b,0xb7,0xa0, + 0xec,0xf2,0xa2,0x6a,0x37,0x59,0x82,0x99, + 0x41,0x3f,0x7b,0x2a,0xec,0xd3,0x9a,0x30, + 0xce,0xc5,0x27,0xb4,0xd9,0x71,0x0c,0x44, + 0x73,0x63,0x90,0x22,0x45,0x1f,0x50,0xd0, + 0x1c,0x04,0x57,0x12,0x5d,0xa0,0xfa,0x44, + 0x29,0xc0,0x7d,0xad,0x85,0x9c,0x84,0x6c, + 0xbb,0xd9,0x3a,0xb5,0xb9,0x1b,0x01,0xbc, + 0x77,0x0b,0x08,0x9c,0xfe,0xde,0x6f,0x65, + 0x1e,0x86,0xdd,0x7c,0x15,0x98,0x9c,0x8b, + 0x53,0x21,0xde,0xa9,0xca,0x60,0x8c,0x71, + 0xfd,0x86,0x23,0x23,0x07,0x2b,0x82,0x7c, + 0xee,0x7a,0x7e,0x28,0xe4,0xe2,0xb9,0x99, + 0x64,0x72,0x33,0xc3,0x45,0x69,0x44,0xbb, + 0x7a,0xef,0x91,0x87,0xc9,0x6b,0x3f,0x5b, + 0x79,0xfb,0x98,0xbc,0x76,0xc3,0x57,0x4d, + 0xd0,0x6f,0x0e,0x95,0x68,0x5e,0x5b,0x3a, + 0xef,0x3a,0x54,0xc4,0x15,0x5f,0xe3,0xad, + 0x81,0x77,0x49,0x62,0x9c,0x30,0xad,0xbe, + 0x89,0x7c,0x4f,0x44,0x54,0xc8,0x6c,0x49, + 0x00,0x00,0x00,0x0a, + 0xe9,0xca,0x10,0xea,0xa8,0x11,0xb2,0x2a, + 0xe0,0x7f,0xb1,0x95,0xe3,0x59,0x0a,0x33, + 0x4e,0xa6,0x42,0x09,0x94,0x2f,0xba,0xe3, + 0x38,0xd1,0x9f,0x15,0x21,0x82,0xc8,0x07, + 0xd3,0xc4,0x0b,0x18,0x9d,0x3f,0xcb,0xea, + 0x94,0x2f,0x44,0x68,0x24,0x39,0xb1,0x91, + 0x33,0x2d,0x33,0xae,0x0b,0x76,0x1a,0x2a, + 0x8f,0x98,0x4b,0x56,0xb2,0xac,0x2f,0xd4, + 0xab,0x08,0x22,0x3a,0x69,0xed,0x1f,0x77, + 0x19,0xc7,0xaa,0x7e,0x9e,0xee,0x96,0x50, + 0x4b,0x0e,0x60,0xc6,0xbb,0x5c,0x94,0x2d, + 0x69,0x5f,0x04,0x93,0xeb,0x25,0xf8,0x0a, + 0x58,0x71,0xcf,0xfd,0x13,0x1d,0x0e,0x04, + 0xff,0xe5,0x06,0x5b,0xc7,0x87,0x5e,0x82, + 0xd3,0x4b,0x40,0xb6,0x9d,0xd9,0xf3,0xc1, + }; + + bool verified = hss_validate_signature( + public_key, + message, sizeof message, + signature, sizeof signature, 0); + + return verified; +} + +bool test_testvector_4(void) { + /* This is test case 4 */ + /* This is the SHAKE256/192 test from draft-fluhrer-lms-more-parm_sets */ + static const unsigned char public_key[] = { + 0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x14, + 0x00,0x00,0x00,0x10, + 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57, + 0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f, + 0xdb,0x54,0xa4,0x50,0x99,0x01,0x05,0x1c, + 0x01,0xe2,0x6d,0x99,0x90,0xe5,0x50,0x34, + 0x79,0x86,0xda,0x87,0x92,0x4f,0xf0,0xb1, + }; + static const unsigned char message[] = { + 0x54,0x65,0x73,0x74,0x20,0x6d,0x65,0x73, + 0x73,0x61,0x67,0x65,0x20,0x66,0x6f,0x72, + 0x20,0x53,0x48,0x41,0x4b,0x45,0x32,0x35, + 0x36,0x2d,0x31,0x39,0x32,0x0a, + }; + static const unsigned char signature[] = { + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06, + 0x00,0x00,0x00,0x10, + 0x84,0x21,0x9d,0xa9,0xce,0x9f,0xff,0xb1, + 0x6e,0xdb,0x94,0x52,0x7c,0x6d,0x10,0x56, + 0x55,0x87,0xdb,0x28,0x06,0x2d,0xea,0xc4, + 0x20,0x8e,0x62,0xfc,0x4f,0xbe,0x9d,0x85, + 0xde,0xb3,0xc6,0xbd,0x2c,0x01,0x64,0x0a, + 0xcc,0xb3,0x87,0xd8,0xa6,0x09,0x3d,0x68, + 0x51,0x12,0x34,0xa6,0xa1,0xa5,0x01,0x08, + 0x09,0x1c,0x03,0x4c,0xb1,0x77,0x7e,0x02, + 0xb5,0xdf,0x46,0x61,0x49,0xa6,0x69,0x69, + 0xa4,0x98,0xe4,0x20,0x0c,0x0a,0x0c,0x1b, + 0xf5,0xd1,0x00,0xcd,0xb9,0x7d,0x2d,0xd4, + 0x0e,0xfd,0x3c,0xad,0xa2,0x78,0xac,0xc5, + 0xa5,0x70,0x07,0x1a,0x04,0x39,0x56,0x11, + 0x2c,0x6d,0xee,0xbd,0x1e,0xb3,0xa7,0xb5, + 0x6f,0x5f,0x67,0x91,0x51,0x5a,0x7b,0x5f, + 0xfd,0xdb,0x0e,0xc2,0xd9,0x09,0x4b,0xfb, + 0xc8,0x89,0xea,0x15,0xc3,0xc7,0xb9,0xbe, + 0xa9,0x53,0xef,0xb7,0x5e,0xd6,0x48,0xf5, + 0x35,0xb9,0xac,0xab,0x66,0xa2,0xe9,0x63, + 0x1e,0x42,0x6e,0x4e,0x99,0xb7,0x33,0xca, + 0xa6,0xc5,0x59,0x63,0x92,0x9b,0x77,0xfe, + 0xc5,0x4a,0x7e,0x70,0x3d,0x81,0x62,0xe7, + 0x36,0x87,0x5c,0xb6,0xa4,0x55,0xd4,0xa9, + 0x01,0x5c,0x7a,0x6d,0x8f,0xd5,0xfe,0x75, + 0xe4,0x02,0xb4,0x70,0x36,0xdc,0x37,0x70, + 0xf4,0xa1,0xdd,0x0a,0x55,0x9c,0xb4,0x78, + 0xc7,0xfb,0x17,0x26,0x00,0x53,0x21,0xbe, + 0x9d,0x1a,0xc2,0xde,0x94,0xd7,0x31,0xee, + 0x4c,0xa7,0x9c,0xff,0x45,0x4c,0x81,0x1f, + 0x46,0xd1,0x19,0x80,0x90,0x9f,0x04,0x7b, + 0x20,0x05,0xe8,0x4b,0x6e,0x15,0x37,0x84, + 0x46,0xb1,0xca,0x69,0x1e,0xfe,0x49,0x1e, + 0xa9,0x8a,0xcc,0x9d,0x3c,0x0f,0x78,0x5c, + 0xab,0xa5,0xe2,0xeb,0x3c,0x30,0x68,0x11, + 0xc2,0x40,0xba,0x22,0x80,0x29,0x23,0x82, + 0x7d,0x58,0x26,0x39,0x30,0x4a,0x1e,0x97, + 0x83,0xba,0x5b,0xc9,0xd6,0x9d,0x99,0x9a, + 0x7d,0xb8,0xf7,0x49,0x77,0x0c,0x3c,0x04, + 0xa1,0x52,0x85,0x6d,0xc7,0x26,0xd8,0x06, + 0x79,0x21,0x46,0x5b,0x61,0xb3,0xf8,0x47, + 0xb1,0x3b,0x26,0x35,0xa4,0x53,0x79,0xe5, + 0xad,0xc6,0xff,0x58,0xa9,0x9b,0x00,0xe6, + 0x0a,0xc7,0x67,0xf7,0xf3,0x01,0x75,0xf9, + 0xf7,0xa1,0x40,0x25,0x7e,0x21,0x8b,0xe3, + 0x07,0x95,0x4b,0x12,0x50,0xc9,0xb4,0x19, + 0x02,0xc4,0xfa,0x7c,0x90,0xd8,0xa5,0x92, + 0x94,0x5c,0x66,0xe8,0x6a,0x76,0xde,0xfc, + 0xb8,0x45,0x00,0xb5,0x55,0x98,0xa1,0x99, + 0x0f,0xaa,0xa1,0x00,0x77,0xc7,0x4c,0x94, + 0x89,0x57,0x31,0x58,0x5c,0x8f,0x90,0x0d, + 0xe1,0xa1,0xc6,0x75,0xbd,0x8b,0x0c,0x18, + 0x0e,0xbe,0x2b,0x5e,0xb3,0xef,0x80,0x19, + 0xec,0xe3,0xe1,0xea,0x72,0x23,0xeb,0x79, + 0x06,0xa2,0x04,0x2b,0x62,0x62,0xb4,0xaa, + 0x25,0xc4,0xb8,0xa0,0x5f,0x20,0x5c,0x8b, + 0xef,0xee,0xf1,0x1c,0xef,0xf1,0x28,0x25, + 0x08,0xd7,0x1b,0xc2,0xa8,0xcf,0xa0,0xa9, + 0x9f,0x73,0xf3,0xe3,0xa7,0x4b,0xb4,0xb3, + 0xc0,0xd8,0xca,0x2a,0xbd,0x0e,0x1c,0x2c, + 0x17,0xda,0xfe,0x18,0xb4,0xee,0x22,0x98, + 0xe8,0x7b,0xcf,0xb1,0x30,0x5b,0x3c,0x06, + 0x9e,0x6d,0x38,0x55,0x69,0xa4,0x06,0x7e, + 0xd5,0x47,0x48,0x6d,0xd1,0xa5,0x0d,0x6f, + 0x4a,0x58,0xaa,0xb9,0x6e,0x2f,0xa8,0x83, + 0xa9,0xa3,0x9e,0x1b,0xd4,0x55,0x41,0xee, + 0xe9,0x4e,0xfc,0x32,0xfa,0xa9,0xa9,0x4b, + 0xe6,0x6d,0xc8,0x53,0x8b,0x2d,0xab,0x05, + 0xae,0xe5,0xef,0xa6,0xb3,0xb2,0xef,0xb3, + 0xfd,0x02,0x0f,0xe7,0x89,0x47,0x7a,0x93, + 0xaf,0xff,0x9a,0x3e,0x63,0x6d,0xbb,0xa8, + 0x64,0xa5,0xbf,0xfa,0x3e,0x28,0xd1,0x3d, + 0x49,0xbb,0x59,0x7d,0x94,0x86,0x5b,0xde, + 0x88,0xc4,0x62,0x7f,0x20,0x6a,0xb2,0xb4, + 0x65,0x08,0x4d,0x6b,0x78,0x06,0x66,0xe9, + 0x52,0xf8,0x71,0x0e,0xfd,0x74,0x8b,0xd0, + 0xf1,0xae,0x8f,0x10,0x35,0x08,0x7f,0x50, + 0x28,0xf1,0x4a,0xff,0xcc,0x5f,0xff,0xe3, + 0x32,0x12,0x1a,0xe4,0xf8,0x7a,0xc5,0xf1, + 0xea,0xc9,0x06,0x26,0x08,0xc7,0xd8,0x77, + 0x08,0xf1,0x72,0x3f,0x38,0xb2,0x32,0x37, + 0xa4,0xed,0xf4,0xb4,0x9a,0x5c,0xd3,0xd7, + 0x00,0x00,0x00,0x14, + 0xdd,0x4b,0xdc,0x8f,0x92,0x8f,0xb5,0x26, + 0xf6,0xfb,0x7c,0xdb,0x94,0x4a,0x7e,0xba, + 0xa7,0xfb,0x05,0xd9,0x95,0xb5,0x72,0x1a, + 0x27,0x09,0x6a,0x50,0x07,0xd8,0x2f,0x79, + 0xd0,0x63,0xac,0xd4,0x34,0xa0,0x4e,0x97, + 0xf6,0x15,0x52,0xf7,0xf8,0x1a,0x93,0x17, + 0xb4,0xec,0x7c,0x87,0xa5,0xed,0x10,0xc8, + 0x81,0x92,0x8f,0xc6,0xeb,0xce,0x6d,0xfc, + 0xe9,0xda,0xae,0x9c,0xc9,0xdb,0xa6,0x90, + 0x7c,0xa9,0xa9,0xdd,0x5f,0x9f,0x57,0x37, + 0x04,0xd5,0xe6,0xcf,0x22,0xa4,0x3b,0x04, + 0xe6,0x4c,0x1f,0xfc,0x7e,0x1c,0x44,0x2e, + 0xcb,0x49,0x5b,0xa2,0x65,0xf4,0x65,0xc5, + 0x62,0x91,0xa9,0x02,0xe6,0x2a,0x46,0x1f, + 0x6d,0xfd,0xa2,0x32,0x45,0x7f,0xad,0x14, + }; + + bool verified = hss_validate_signature( + public_key, + message, sizeof message, + signature, sizeof signature, 0); + + return verified; +} + +bool test_testvector_5(void) { + /* This is test case 5 */ + /* This is the SHAKE256/256 test from draft-fluhrer-lms-more-parm_sets */ + static const unsigned char public_key[] = { + 0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x0f, + 0x00,0x00,0x00,0x0c, + 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87, + 0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f, + 0x9b,0xb7,0xfa,0xee,0x41,0x1c,0xae,0x80, + 0x6c,0x16,0xa4,0x66,0xc3,0x19,0x1a,0x8b, + 0x65,0xd0,0xac,0x31,0x93,0x2b,0xbf,0x0c, + 0x2d,0x07,0xc7,0xa4,0xa3,0x63,0x79,0xfe, + }; + static const unsigned char message[] = { + 0x54,0x65,0x73,0x74,0x20,0x6d,0x65,0x73, + 0x61,0x67,0x65,0x20,0x66,0x6f,0x72,0x20, + 0x53,0x48,0x41,0x4b,0x45,0x32,0x35,0x36, + 0x2d,0x32,0x35,0x36,0x0a, + }; + static const unsigned char signature[] = { + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07, + 0x00,0x00,0x00,0x0c, + 0xb8,0x27,0x09,0xf0,0xf0,0x0e,0x83,0x75, + 0x91,0x90,0x99,0x62,0x33,0xd1,0xee,0x4f, + 0x4e,0xc5,0x05,0x34,0x47,0x3c,0x02,0xff, + 0xa1,0x45,0xe8,0xca,0x28,0x74,0xe3,0x2b, + 0x16,0xb2,0x28,0x11,0x8c,0x62,0xb9,0x6c, + 0x9c,0x77,0x67,0x8b,0x33,0x18,0x37,0x30, + 0xde,0xba,0xad,0xe8,0xfe,0x60,0x7f,0x05, + 0xc6,0x69,0x7b,0xc9,0x71,0x51,0x9a,0x34, + 0x1d,0x69,0xc0,0x01,0x29,0x68,0x0b,0x67, + 0xe7,0x5b,0x3b,0xd7,0xd8,0xaa,0x5c,0x8b, + 0x71,0xf0,0x26,0x69,0xd1,0x77,0xa2,0xa0, + 0xee,0xa8,0x96,0xdc,0xd1,0x66,0x0f,0x16, + 0x86,0x4b,0x30,0x2f,0xf3,0x21,0xf9,0xc4, + 0xb8,0x35,0x44,0x08,0xd0,0x67,0x60,0x50, + 0x4f,0x76,0x8e,0xbd,0x4e,0x54,0x5a,0x9b, + 0x0a,0xc0,0x58,0xc5,0x75,0x07,0x8e,0x6c, + 0x14,0x03,0x16,0x0f,0xb4,0x54,0x50,0xd6, + 0x1a,0x9c,0x8c,0x81,0xf6,0xbd,0x69,0xbd, + 0xfa,0x26,0xa1,0x6e,0x12,0xa2,0x65,0xba, + 0xf7,0x9e,0x9e,0x23,0x3e,0xb7,0x1a,0xf6, + 0x34,0xec,0xc6,0x6d,0xc8,0x8e,0x10,0xc6, + 0xe0,0x14,0x29,0x42,0xd4,0x84,0x3f,0x70, + 0xa0,0x24,0x27,0x27,0xbc,0x5a,0x2a,0xab, + 0xf7,0xb0,0xec,0x12,0xa9,0x90,0x90,0xd8, + 0xca,0xee,0xf2,0x13,0x03,0xf8,0xac,0x58, + 0xb9,0xf2,0x00,0x37,0x1d,0xc9,0xe4,0x1a, + 0xb9,0x56,0xe1,0xa3,0xef,0xed,0x9d,0x4b, + 0xbb,0x38,0x97,0x5b,0x46,0xc2,0x8d,0x5f, + 0x5b,0x3e,0xd1,0x9d,0x84,0x7b,0xd0,0xa7, + 0x37,0x17,0x72,0x63,0xcb,0xc1,0xa2,0x26, + 0x2d,0x40,0xe8,0x08,0x15,0xee,0x14,0x9b, + 0x6c,0xce,0x27,0x14,0x38,0x4c,0x9b,0x7f, + 0xce,0xb3,0xbb,0xcb,0xd2,0x52,0x28,0xdd, + 0xa8,0x30,0x65,0x36,0x37,0x6f,0x87,0x93, + 0xec,0xad,0xd6,0x02,0x02,0x65,0xda,0xb9, + 0x07,0x5f,0x64,0xc7,0x73,0xef,0x97,0xd0, + 0x73,0x52,0x91,0x99,0x95,0xb7,0x44,0x04, + 0xcc,0x69,0xa6,0xf3,0xb4,0x69,0x44,0x5c, + 0x92,0x86,0xa6,0xb2,0xc9,0xf6,0xdc,0x83, + 0x9b,0xe7,0x66,0x18,0xf0,0x53,0xde,0x76, + 0x3d,0xa3,0x57,0x1e,0xf7,0x0f,0x80,0x5c, + 0x9c,0xc5,0x4b,0x8e,0x50,0x1a,0x98,0xb9, + 0x8c,0x70,0x78,0x5e,0xeb,0x61,0x73,0x7e, + 0xce,0xd7,0x8b,0x0e,0x38,0x0d,0xed,0x4f, + 0x76,0x9a,0x9d,0x42,0x27,0x86,0xde,0xf5, + 0x97,0x00,0xee,0xf3,0x27,0x80,0x17,0xba, + 0xbb,0xe5,0xf9,0x06,0x3b,0x46,0x8a,0xe0, + 0xdd,0x61,0xd9,0x4f,0x9f,0x99,0xd5,0xcc, + 0x36,0xfb,0xec,0x41,0x78,0xd2,0xbd,0xa3, + 0xad,0x31,0xe1,0x64,0x4a,0x2b,0xcc,0xe2, + 0x08,0xd7,0x2d,0x50,0xa7,0x63,0x78,0x51, + 0xaa,0x90,0x8b,0x94,0xdc,0x43,0x76,0x12, + 0x0d,0x5b,0xea,0xb0,0xfb,0x80,0x5e,0x19, + 0x45,0xc4,0x18,0x34,0xdd,0x60,0x85,0xe6, + 0xdb,0x1a,0x3a,0xa7,0x8f,0xcb,0x59,0xf6, + 0x2b,0xde,0x68,0x23,0x6a,0x10,0x61,0x8c, + 0xff,0x12,0x3a,0xbe,0x64,0xda,0xe8,0xda, + 0xbb,0x2e,0x84,0xca,0x70,0x53,0x09,0xc2, + 0xab,0x98,0x6d,0x4f,0x83,0x26,0xba,0x06, + 0x42,0x27,0x2c,0xb3,0x90,0x4e,0xb9,0x6f, + 0x6f,0x5e,0x3b,0xb8,0x81,0x39,0x97,0x88, + 0x1b,0x6a,0x33,0xca,0xc0,0x71,0x4e,0x4b, + 0x5e,0x7a,0x88,0x2a,0xd8,0x7e,0x14,0x19, + 0x31,0xf9,0x7d,0x61,0x2b,0x84,0xe9,0x03, + 0xe7,0x73,0x13,0x9a,0xe3,0x77,0xf5,0xba, + 0x19,0xac,0x86,0x19,0x8d,0x48,0x5f,0xca, + 0x97,0x74,0x25,0x68,0xf6,0xff,0x75,0x81, + 0x20,0xa8,0x9b,0xf1,0x90,0x59,0xb8,0xa6, + 0xbf,0xe2,0xd8,0x6b,0x12,0x77,0x81,0x64, + 0x43,0x6a,0xb2,0x65,0x9b,0xa8,0x66,0x76, + 0x7f,0xcc,0x43,0x55,0x84,0x12,0x5f,0xb7, + 0x92,0x42,0x01,0xee,0x67,0xb5,0x35,0xda, + 0xf7,0x2c,0x5c,0xb3,0x1f,0x5a,0x0b,0x1d, + 0x92,0x63,0x24,0xc2,0x6e,0x67,0xd4,0xc3, + 0x83,0x6e,0x30,0x1a,0xa0,0x9b,0xae,0x8f, + 0xb3,0xf9,0x1f,0x16,0x22,0xb1,0x81,0x8c, + 0xcf,0x44,0x0f,0x52,0xca,0x9b,0x5b,0x9b, + 0x99,0xab,0xa8,0xa6,0x75,0x4a,0xae,0x2b, + 0x96,0x7c,0x49,0x54,0xfa,0x85,0x29,0x8a, + 0xd9,0xb1,0xe7,0x4f,0x27,0xa4,0x61,0x27, + 0xc3,0x61,0x31,0xc8,0x99,0x1f,0x0c,0xc2, + 0xba,0x57,0xa1,0x5d,0x35,0xc9,0x1c,0xf8, + 0xbc,0x48,0xe8,0xe2,0x0d,0x62,0x5a,0xf4, + 0xe8,0x5d,0x8f,0x94,0x02,0xec,0x44,0xaf, + 0xbd,0x47,0x92,0xb9,0x24,0xb8,0x39,0x33, + 0x2a,0x64,0x78,0x8a,0x77,0x01,0xa3,0x00, + 0x94,0xb9,0xec,0x4b,0x9f,0x4b,0x64,0x8f, + 0x16,0x8b,0xf4,0x57,0xfb,0xb3,0xc9,0x59, + 0x4f,0xa8,0x79,0x20,0xb6,0x45,0xe4,0x2a, + 0xa2,0xfe,0xcc,0x9e,0x21,0xe0,0x00,0xca, + 0x7d,0x3f,0xf9,0x14,0xe1,0x5c,0x40,0xa8, + 0xbc,0x53,0x31,0x29,0xa7,0xfd,0x39,0x52, + 0x93,0x76,0x43,0x0f,0x35,0x5a,0xaf,0x96, + 0xa0,0xa1,0x3d,0x13,0xf2,0x41,0x91,0x41, + 0xb3,0xcc,0x25,0x84,0x3e,0x8c,0x90,0xd0, + 0xe5,0x51,0xa3,0x55,0xdd,0x90,0xad,0x77, + 0x0e,0xa7,0x25,0x52,0x14,0xce,0x11,0x23, + 0x86,0x05,0xde,0x2f,0x00,0x0d,0x20,0x01, + 0x04,0xd0,0xc3,0xa3,0xe3,0x5a,0xe6,0x4e, + 0xa1,0x0a,0x3e,0xff,0x37,0xac,0x7e,0x95, + 0x49,0x21,0x7c,0xdf,0x52,0xf3,0x07,0x17, + 0x2e,0x2f,0x6c,0x7a,0x2a,0x45,0x43,0xe1, + 0x43,0x14,0x03,0x65,0x25,0xb1,0xad,0x53, + 0xee,0xad,0xdf,0x0e,0x24,0xb1,0xf3,0x69, + 0x14,0xed,0x22,0x48,0x3f,0x28,0x89,0xf6, + 0x1e,0x62,0xb6,0xfb,0x78,0xf5,0x64,0x5b, + 0xdb,0xb0,0x2c,0x9e,0x5b,0xf9,0x7d,0xb7, + 0xa0,0x00,0x4e,0x87,0xc2,0xa5,0x53,0x99, + 0xb6,0x19,0x58,0x78,0x6c,0x97,0xbd,0x52, + 0xfa,0x19,0x9c,0x27,0xf6,0xbb,0x4d,0x68, + 0xc4,0x90,0x79,0x33,0x56,0x27,0x55,0xbf, + 0xec,0x5d,0x4f,0xb5,0x2f,0x06,0xc2,0x89, + 0xd6,0xe8,0x52,0xcf,0x6b,0xc7,0x73,0xff, + 0xd4,0xc0,0x7e,0xe2,0xd6,0xcc,0x55,0xf5, + 0x7e,0xdc,0xfb,0xc8,0xe8,0x69,0x2a,0x49, + 0xad,0x47,0xa1,0x21,0xfe,0x3c,0x1b,0x16, + 0xca,0xb1,0xcc,0x28,0x5f,0xaf,0x67,0x93, + 0xff,0xad,0x7a,0x8c,0x34,0x1a,0x49,0xc5, + 0xd2,0xdc,0xe7,0x06,0x9e,0x46,0x4c,0xb9, + 0x0a,0x00,0xb2,0x90,0x36,0x48,0xb2,0x3c, + 0x81,0xa6,0x8e,0x21,0xd7,0x48,0xa7,0xe7, + 0xb1,0xdf,0x8a,0x59,0x3f,0x38,0x94,0xb2, + 0x47,0x7e,0x83,0x16,0x94,0x7c,0xa7,0x25, + 0xd1,0x41,0x13,0x52,0x02,0xa9,0x44,0x2e, + 0x1d,0xb3,0x3b,0xbd,0x39,0x0d,0x2c,0x04, + 0x40,0x1c,0x39,0xb2,0x53,0xb7,0x8c,0xe2, + 0x97,0xb0,0xe1,0x47,0x55,0xe4,0x6e,0xc0, + 0x8a,0x14,0x6d,0x27,0x9c,0x67,0xaf,0x70, + 0xde,0x25,0x68,0x90,0x80,0x4d,0x83,0xd6, + 0xec,0x5c,0xa3,0x28,0x6f,0x1f,0xca,0x9c, + 0x72,0xab,0xf6,0xef,0x86,0x8e,0x7f,0x6e, + 0xb0,0xfd,0xdd,0xa1,0xb0,0x40,0xec,0xec, + 0x9b,0xbc,0x69,0xe2,0xfd,0x86,0x18,0xe9, + 0xdb,0x3b,0xdb,0x0a,0xf1,0x3d,0xda,0x06, + 0xc6,0x61,0x7e,0x95,0xaf,0xa5,0x22,0xd6, + 0xa2,0x55,0x2d,0xe1,0x53,0x24,0xd9,0x91, + 0x19,0xf5,0x5e,0x9a,0xf1,0x1a,0xe3,0xd5, + 0x61,0x4b,0x56,0x4c,0x64,0x2d,0xbf,0xec, + 0x6c,0x64,0x41,0x98,0xce,0x80,0xd2,0x43, + 0x3a,0xc8,0xee,0x73,0x8f,0x9d,0x82,0x5e, + 0x00,0x00,0x00,0x0f, + 0x71,0xd5,0x85,0xa3,0x5c,0x3a,0x90,0x83, + 0x79,0xf4,0x07,0x2d,0x07,0x03,0x11,0xdb, + 0x5d,0x65,0xb2,0x42,0xb7,0x14,0xbc,0x5a, + 0x75,0x6b,0xa5,0xe2,0x28,0xab,0xfa,0x0d, + 0x13,0x29,0x97,0x8a,0x05,0xd5,0xe8,0x15, + 0xcf,0x4d,0x74,0xc1,0xe5,0x47,0xec,0x4a, + 0xa3,0xca,0x95,0x6a,0xe9,0x27,0xdf,0x8b, + 0x29,0xfb,0x9f,0xab,0x39,0x17,0xa7,0xa4, + 0xae,0x61,0xba,0x57,0xe5,0x34,0x2e,0x9d, + 0xb1,0x2c,0xaf,0x6f,0x6d,0xbc,0x52,0x53, + 0xde,0x52,0x68,0xd4,0xb0,0xc4,0xce,0x4e, + 0xbe,0x68,0x52,0xf0,0x12,0xb1,0x62,0xfc, + 0x1c,0x12,0xb9,0xff,0xc3,0xbc,0xb1,0xd3, + 0xac,0x85,0x89,0x77,0x76,0x55,0xe2,0x2c, + 0xd9,0xb9,0x9f,0xf1,0xe4,0x34,0x6f,0xd0, + 0xef,0xea,0xa1,0xda,0x04,0x46,0x92,0xe7, + 0xad,0x6b,0xfc,0x33,0x7d,0xb6,0x98,0x49, + 0xe5,0x44,0x11,0xdf,0x89,0x20,0xc2,0x28, + 0xa2,0xb7,0x76,0x2c,0x11,0xe4,0xb1,0xc4, + 0x9e,0xfb,0x74,0x48,0x6d,0x39,0x31,0xea, + }; + + bool verified = hss_validate_signature( + public_key, + message, sizeof message, + signature, sizeof signature, 0); + + return verified; +} bool test_testvector(bool fast_flag, bool quiet_flag) { return test_testvector_1() && - test_testvector_2(); + test_testvector_2() && + test_testvector_3() && + test_testvector_4() && + test_testvector_5(); } diff --git a/test_verify.c b/test_verify.c index 789f948..9eeee61 100644 --- a/test_verify.c +++ b/test_verify.c @@ -8,8 +8,11 @@ #include "test_hss.h" static param_set_t h_array[] = { + LMS_SHA256_N24_H5, LMS_SHA256_N32_H5, - LMS_SHA256_N32_H10 + LMS_SHAKE256_N24_H5, + LMS_SHAKE256_N32_H5, + LMS_SHA256_N24_H10, /* We don't test out the higher heights, because that'd take too */ /* long, and wouldn't tell us that much for this test */ }; @@ -17,19 +20,44 @@ static param_set_t h_array[] = { static param_set_t w_array[] = { LMOTS_SHA256_N32_W1, + LMOTS_SHA256_N24_W1, LMOTS_SHA256_N32_W2, + LMOTS_SHA256_N24_W2, LMOTS_SHA256_N32_W4, - LMOTS_SHA256_N32_W8 + LMOTS_SHA256_N24_W4, + LMOTS_SHA256_N32_W8, + LMOTS_SHA256_N24_W8, + LMOTS_SHAKE256_N32_W1, + LMOTS_SHAKE256_N24_W1, + LMOTS_SHAKE256_N32_W2, + LMOTS_SHAKE256_N24_W2, + LMOTS_SHAKE256_N32_W4, + LMOTS_SHAKE256_N24_W4, + LMOTS_SHAKE256_N32_W8, + LMOTS_SHAKE256_N24_W8, }; #define MAX_W_INDEX (sizeof w_array / sizeof *w_array ) /* This is (roughly) the number of hash compression operatios needed to */ -/* compute various OTS verifications. Really off by a factor of two; */ -/* however that factor of two is consistent */ -int cost_per_sig[4] = { +/* compute various OTS verifications. This ignores a number of factors */ +/* (SHA-256 vs SHAKE computations), however it should be within a couple */ +/* orders of magnitude */ +int cost_per_sig[MAX_W_INDEX] = { (1<<1) * 265, + (1<<1) * 201, (1<<2) * 133, - (1<<4) * 133, + (1<<2) * 101, + (1<<4) * 67, + (1<<4) * 51, (1<<8) * 34, + (1<<8) * 26, + (1<<1) * 265, + (1<<1) * 201, + (1<<2) * 133, + (1<<2) * 101, + (1<<4) * 67, + (1<<4) * 51, + (1<<8) * 34, + (1<<8) * 26, }; static bool do_verify( unsigned char *private_key, unsigned char *public_key, @@ -66,11 +94,21 @@ bool test_verify(bool fast_flag, bool quiet_flag) { for (w_index=0; w_index < MAX_W_INDEX; w_index++) { param_set_t h = h_array[h_index]; param_set_t w = w_array[w_index]; + /* Flag is set if we're testing out a W=8 parameter set */ + int w8 = (w == LMOTS_SHA256_N32_W8 || w == LMOTS_SHA256_N24_W8 || + w == LMOTS_SHAKE256_N32_W8 || + w == LMOTS_SHAKE256_N24_W8); + /* Flag is set if we're testing out a W=4 parameter set */ + int w4 = (w == LMOTS_SHA256_N32_W4 || w == LMOTS_SHA256_N24_W4 || + w == LMOTS_SHAKE256_N32_W4 || + w == LMOTS_SHAKE256_N24_W4); + /* Note: this particular combination takes longer than the */ /* rest combined; it wouldn't tell us much more, so skip it */ - if (h == LMS_SHA256_N32_H10 && w == LMOTS_SHA256_N32_W8) continue; + if (h == LMS_SHA256_N24_H10 && w8) continue; /* In fast mode, we both testing out W=8 only for d=1 */ - if (fast_flag && d > 1 && w == LMOTS_SHA256_N32_W8) continue; + if (fast_flag && d > 1 && w8) continue; + if (fast_flag && d > 2 && w4) continue; work_array[w_count].d = max_d = d; work_array[w_count].h = h; diff --git a/test_verify_inc.c b/test_verify_inc.c index c52867e..0d108a9 100644 --- a/test_verify_inc.c +++ b/test_verify_inc.c @@ -55,184 +55,212 @@ static bool do_validate( void *public_key, return success; } -#define MAX_D 4 -bool test_verify_inc(bool fast_flag, bool quiet_flag) { +static bool do_test(bool fast_flag, int max_d, + param_set_t *lm_array, param_set_t *lm_ots_array) { int d; - param_set_t lm_array[MAX_D] = { LMS_SHA256_N32_H10, LMS_SHA256_N32_H5, - LMS_SHA256_N32_H5, LMS_SHA256_N32_H5 }; - param_set_t lm_ots_array[MAX_D] = { - LMOTS_SHA256_N32_W4, LMOTS_SHA256_N32_W4, - LMOTS_SHA256_N32_W4, LMOTS_SHA256_N32_W4 }; - - for (d=1; d<=MAX_D; d++) { - size_t len_private_key = hss_get_private_key_len(d, lm_array, lm_ots_array ); - if (len_private_key == 0 || len_private_key > HSS_MAX_PRIVATE_KEY_LEN) { - printf( " Len private key failed\n" ); - return false; - } - unsigned char private_key[HSS_MAX_PRIVATE_KEY_LEN]; - - unsigned len_public_key = hss_get_public_key_len(d, lm_array, lm_ots_array ); - if (len_public_key == 0) { - printf( " Len public key failed\n" ); - return false; - } - - size_t len_signature = hss_get_signature_len(d, lm_array, lm_ots_array ); - if (len_signature == 0) { - printf( " Len signature failed\n" ); - return false; - } - - unsigned char public_key[HSS_MAX_PUBLIC_KEY_LEN]; - - unsigned char aux_data[1000]; + for (d=1; d<=max_d; d++) { + size_t len_private_key = hss_get_private_key_len(d, lm_array, lm_ots_array ); + if (len_private_key == 0 || len_private_key > HSS_MAX_PRIVATE_KEY_LEN) { + printf( " Len private key failed\n" ); + return false; + } + unsigned char private_key[HSS_MAX_PRIVATE_KEY_LEN]; - /* Generate the public key */ - if (!hss_generate_private_key( - generate_random, - d, lm_array, lm_ots_array, - NULL, private_key, - public_key, len_public_key, - aux_data, sizeof aux_data, 0 )) { - printf( " Gen private key failed\n" ); - return false; - } - - /* Load the private key into memory */ - struct hss_working_key *w = hss_load_private_key( - NULL, private_key, - 0, /* Minimal memory */ - aux_data, sizeof aux_data, 0 ); - if (!w) { - printf( " *** failed loading private key\n" ); - return false; - } - - unsigned char *signature = malloc(len_signature); - if (!signature) { - printf( " *** malloc failure\n" ); - return false; - } - - /* - * Try correct validations, at various step levels - */ - int step; - for (step = 1; step < 70; step++) { - /* Generate a valid signature */ - static unsigned char test_message[] = - "The powers not delegated to the United States by the Constitution, " - "nor prohibited by it to the States, are reserved to the States " - "respectively, or to the people"; - - if (!hss_generate_signature( w, NULL, private_key, - test_message, sizeof test_message, - signature, len_signature, 0 )) { - printf( " *** failed signing test message\n" ); - hss_free_working_key(w); - free(signature); + unsigned len_public_key = hss_get_public_key_len(d, lm_array, lm_ots_array ); + if (len_public_key == 0 || len_public_key > HSS_MAX_PUBLIC_KEY_LEN) { + printf( " Len public key failed\n" ); return false; } - - if (!do_validate( public_key, - test_message, sizeof test_message, - signature, len_signature, step, 0 )) { - printf( " *** failed valid signature\n" ); - hss_free_working_key(w); - free(signature); + + size_t len_signature = hss_get_signature_len(d, lm_array, lm_ots_array ); + if (len_signature == 0) { + printf( " Len signature failed\n" ); return false; } - } - - /* Try validating the wrong message (and reuse the signature we */ - /* generated above) */ - unsigned char wrong_message[] = "Wrong message"; - enum hss_error_code error; - if (do_validate( public_key, - wrong_message, sizeof wrong_message, - signature, len_signature, 7, &error )) { - printf( " *** incorrect message validated\n" ); - hss_free_working_key(w); - free(signature); - return false; - } - if (error != hss_error_bad_signature) { - printf( " *** incorrect error code\n" ); - hss_free_working_key(w); - free(signature); - return false; - } - - /* Corrupt the signature; check if we detect that */ - int i; - unsigned char test_message[] = "The powers ..."; - - if (!hss_generate_signature( w, NULL, private_key, - test_message, sizeof test_message, - signature, len_signature, 0 )) { - printf( " *** failed signing test message\n" ); - hss_free_working_key(w); - free(signature); - return false; - } - int count = 0; - for (i=0; i