diff options
author | Robert Relyea <rrelyea@redhat.com> | 2023-02-27 17:19:39 -0800 |
---|---|---|
committer | Robert Relyea <rrelyea@redhat.com> | 2023-02-27 17:19:39 -0800 |
commit | fceb08b2428170ae51938fa93bc2b2c00bd1d5ad (patch) | |
tree | bea248d594fa867f3995d63990d313eb72c5af68 /lib/liboqs/src/sig/sphincs/pqclean_sphincs-sha256-128s-simple_clean/wots.c | |
parent | f4262a3db99a22b38fc8d6d9e8103ad31a697f9f (diff) | |
download | nss-hg-fceb08b2428170ae51938fa93bc2b2c00bd1d5ad.tar.gz |
Add liboqs
Diffstat (limited to 'lib/liboqs/src/sig/sphincs/pqclean_sphincs-sha256-128s-simple_clean/wots.c')
-rw-r--r-- | lib/liboqs/src/sig/sphincs/pqclean_sphincs-sha256-128s-simple_clean/wots.c | 167 |
1 files changed, 167 insertions, 0 deletions
diff --git a/lib/liboqs/src/sig/sphincs/pqclean_sphincs-sha256-128s-simple_clean/wots.c b/lib/liboqs/src/sig/sphincs/pqclean_sphincs-sha256-128s-simple_clean/wots.c new file mode 100644 index 000000000..0f74f47a0 --- /dev/null +++ b/lib/liboqs/src/sig/sphincs/pqclean_sphincs-sha256-128s-simple_clean/wots.c @@ -0,0 +1,167 @@ +#include <stdint.h> +#include <string.h> + +#include "address.h" +#include "hash.h" +#include "hash_state.h" +#include "params.h" +#include "thash.h" +#include "utils.h" +#include "wots.h" + +// TODO clarify address expectations, and make them more uniform. +// TODO i.e. do we expect types to be set already? +// TODO and do we expect modifications or copies? + +/** + * Computes the starting value for a chain, i.e. the secret key. + * Expects the address to be complete up to the chain address. + */ +static void wots_gen_sk(unsigned char *sk, const unsigned char *sk_seed, + uint32_t wots_addr[8], + const hash_state *hash_state_seeded) { + /* Make sure that the hash address is actually zeroed. */ + PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_set_hash_addr(wots_addr, 0); + + /* Generate sk element. */ + PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_prf_addr(sk, sk_seed, wots_addr, hash_state_seeded); +} + +/** + * Computes the chaining function. + * out and in have to be n-byte arrays. + * + * Interprets in as start-th value of the chain. + * addr has to contain the address of the chain. + */ +static void gen_chain(unsigned char *out, const unsigned char *in, + unsigned int start, unsigned int steps, + const unsigned char *pub_seed, uint32_t addr[8], + const hash_state *hash_state_seeded) { + uint32_t i; + + /* Initialize out with the value at position 'start'. */ + memcpy(out, in, PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_N); + + /* Iterate 'steps' calls to the hash function. */ + for (i = start; i < (start + steps) && i < PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_WOTS_W; i++) { + PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_set_hash_addr(addr, i); + PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_thash_1( + out, out, pub_seed, addr, hash_state_seeded); + } +} + +/** + * base_w algorithm as described in draft. + * Interprets an array of bytes as integers in base w. + * This only works when log_w is a divisor of 8. + */ +static void base_w(unsigned int *output, const size_t out_len, + const unsigned char *input) { + size_t in = 0; + size_t out = 0; + unsigned char total = 0; + unsigned int bits = 0; + size_t consumed; + + for (consumed = 0; consumed < out_len; consumed++) { + if (bits == 0) { + total = input[in]; + in++; + bits += 8; + } + bits -= PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_WOTS_LOGW; + output[out] = (unsigned int)((total >> bits) & (PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_WOTS_W - 1)); + out++; + } +} + +/* Computes the WOTS+ checksum over a message (in base_w). */ +static void wots_checksum(unsigned int *csum_base_w, + const unsigned int *msg_base_w) { + unsigned int csum = 0; + unsigned char csum_bytes[(PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_WOTS_LEN2 * PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_WOTS_LOGW + 7) / 8]; + unsigned int i; + + /* Compute checksum. */ + for (i = 0; i < PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_WOTS_LEN1; i++) { + csum += PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_WOTS_W - 1 - msg_base_w[i]; + } + + /* Convert checksum to base_w. */ + /* Make sure expected empty zero bits are the least significant bits. */ + csum = csum << (8 - ((PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_WOTS_LEN2 * PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_WOTS_LOGW) % 8)); + PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_ull_to_bytes( + csum_bytes, sizeof(csum_bytes), csum); + base_w(csum_base_w, PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_WOTS_LEN2, csum_bytes); +} + +/* Takes a message and derives the matching chain lengths. */ +static void chain_lengths(unsigned int *lengths, const unsigned char *msg) { + base_w(lengths, PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_WOTS_LEN1, msg); + wots_checksum(lengths + PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_WOTS_LEN1, lengths); +} + +/** + * WOTS key generation. Takes a 32 byte sk_seed, expands it to WOTS private key + * elements and computes the corresponding public key. + * It requires the seed pub_seed (used to generate bitmasks and hash keys) + * and the address of this WOTS key pair. + * + * Writes the computed public key to 'pk'. + */ +void PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_wots_gen_pk( + unsigned char *pk, const unsigned char *sk_seed, + const unsigned char *pub_seed, uint32_t addr[8], + const hash_state *hash_state_seeded) { + uint32_t i; + + for (i = 0; i < PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_WOTS_LEN; i++) { + PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_set_chain_addr(addr, i); + wots_gen_sk(pk + i * PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_N, sk_seed, addr, hash_state_seeded); + gen_chain(pk + i * PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_N, pk + i * PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_N, + 0, PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_WOTS_W - 1, pub_seed, addr, hash_state_seeded); + } +} + +/** + * Takes a n-byte message and the 32-byte sk_see to compute a signature 'sig'. + */ +void PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_wots_sign( + unsigned char *sig, const unsigned char *msg, + const unsigned char *sk_seed, const unsigned char *pub_seed, + uint32_t addr[8], const hash_state *hash_state_seeded) { + unsigned int lengths[PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_WOTS_LEN]; + uint32_t i; + + chain_lengths(lengths, msg); + + for (i = 0; i < PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_WOTS_LEN; i++) { + PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_set_chain_addr(addr, i); + wots_gen_sk(sig + i * PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_N, sk_seed, addr, hash_state_seeded); + gen_chain(sig + i * PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_N, sig + i * PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_N, 0, lengths[i], pub_seed, addr, hash_state_seeded); + } +} + +/** + * Takes a WOTS signature and an n-byte message, computes a WOTS public key. + * + * Writes the computed public key to 'pk'. + */ +void PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_wots_pk_from_sig( + unsigned char *pk, + const unsigned char *sig, const unsigned char *msg, + const unsigned char *pub_seed, uint32_t addr[8], + const hash_state *hash_state_seeded) { + unsigned int lengths[PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_WOTS_LEN]; + uint32_t i; + + chain_lengths(lengths, msg); + + for (i = 0; i < PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_WOTS_LEN; i++) { + PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_set_chain_addr(addr, i); + gen_chain(pk + i * PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_N, sig + i * PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_N, + lengths[i], PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_WOTS_W - 1 - lengths[i], pub_seed, addr, + hash_state_seeded); + } +} |