diff options
Diffstat (limited to 'lib/liboqs/src/sig/sphincs/pqclean_sphincs-shake256-192f-simple_clean')
20 files changed, 1691 insertions, 0 deletions
diff --git a/lib/liboqs/src/sig/sphincs/pqclean_sphincs-shake256-192f-simple_clean/Makefile b/lib/liboqs/src/sig/sphincs/pqclean_sphincs-shake256-192f-simple_clean/Makefile new file mode 100644 index 000000000..fe090f3ff --- /dev/null +++ b/lib/liboqs/src/sig/sphincs/pqclean_sphincs-shake256-192f-simple_clean/Makefile @@ -0,0 +1,49 @@ +#! gmake +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +####################################################################### +# (1) Include initial platform-independent assignments (MANDATORY). # +####################################################################### + +include manifest.mn + +####################################################################### +# (2) Include "global" configuration information. (OPTIONAL) # +####################################################################### + +USE_GCOV = +include $(CORE_DEPTH)/coreconf/config.mk + +####################################################################### +# (3) Include "component" configuration information. (OPTIONAL) # +####################################################################### + + + +####################################################################### +# (4) Include "local" platform-dependent assignments (OPTIONAL). # +####################################################################### + +include config.mk + +####################################################################### +# (5) Execute "global" rules. (OPTIONAL) # +####################################################################### + +include $(CORE_DEPTH)/coreconf/rules.mk + +####################################################################### +# (6) Execute "component" rules. (OPTIONAL) # +####################################################################### + + + +####################################################################### +# (7) Execute "local" rules. (OPTIONAL). # +####################################################################### + +WARNING_CFLAGS = $(NULL) + diff --git a/lib/liboqs/src/sig/sphincs/pqclean_sphincs-shake256-192f-simple_clean/address.c b/lib/liboqs/src/sig/sphincs/pqclean_sphincs-shake256-192f-simple_clean/address.c new file mode 100644 index 000000000..cce899fe7 --- /dev/null +++ b/lib/liboqs/src/sig/sphincs/pqclean_sphincs-shake256-192f-simple_clean/address.c @@ -0,0 +1,78 @@ +#include <stdint.h> + +#include "address.h" +#include "params.h" +#include "utils.h" + +void PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_addr_to_bytes( + unsigned char *bytes, const uint32_t addr[8]) { + int i; + + for (i = 0; i < 8; i++) { + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_ull_to_bytes( + bytes + i * 4, 4, addr[i]); + } +} + +void PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_set_layer_addr( + uint32_t addr[8], uint32_t layer) { + addr[0] = layer; +} + +void PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_set_tree_addr( + uint32_t addr[8], uint64_t tree) { + addr[1] = 0; + addr[2] = (uint32_t) (tree >> 32); + addr[3] = (uint32_t) tree; +} + +void PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_set_type( + uint32_t addr[8], uint32_t type) { + addr[4] = type; +} + +void PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_copy_subtree_addr( + uint32_t out[8], const uint32_t in[8]) { + out[0] = in[0]; + out[1] = in[1]; + out[2] = in[2]; + out[3] = in[3]; +} + +/* These functions are used for OTS addresses. */ + +void PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_set_keypair_addr( + uint32_t addr[8], uint32_t keypair) { + addr[5] = keypair; +} + +void PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_copy_keypair_addr( + uint32_t out[8], const uint32_t in[8]) { + out[0] = in[0]; + out[1] = in[1]; + out[2] = in[2]; + out[3] = in[3]; + out[5] = in[5]; +} + +void PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_set_chain_addr( + uint32_t addr[8], uint32_t chain) { + addr[6] = chain; +} + +void PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_set_hash_addr( + uint32_t addr[8], uint32_t hash) { + addr[7] = hash; +} + +/* These functions are used for all hash tree addresses (including FORS). */ + +void PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_set_tree_height( + uint32_t addr[8], uint32_t tree_height) { + addr[6] = tree_height; +} + +void PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_set_tree_index( + uint32_t addr[8], uint32_t tree_index) { + addr[7] = tree_index; +} diff --git a/lib/liboqs/src/sig/sphincs/pqclean_sphincs-shake256-192f-simple_clean/address.h b/lib/liboqs/src/sig/sphincs/pqclean_sphincs-shake256-192f-simple_clean/address.h new file mode 100644 index 000000000..f57ffb75f --- /dev/null +++ b/lib/liboqs/src/sig/sphincs/pqclean_sphincs-shake256-192f-simple_clean/address.h @@ -0,0 +1,50 @@ +#ifndef PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_ADDRESS_H +#define PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_ADDRESS_H + +#include <stdint.h> + +#define PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_ADDR_TYPE_WOTS 0 +#define PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_ADDR_TYPE_WOTSPK 1 +#define PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_ADDR_TYPE_HASHTREE 2 +#define PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_ADDR_TYPE_FORSTREE 3 +#define PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_ADDR_TYPE_FORSPK 4 + +void PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_addr_to_bytes( + unsigned char *bytes, const uint32_t addr[8]); + +void PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_set_layer_addr( + uint32_t addr[8], uint32_t layer); + +void PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_set_tree_addr( + uint32_t addr[8], uint64_t tree); + +void PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_set_type( + uint32_t addr[8], uint32_t type); + +/* Copies the layer and tree part of one address into the other */ +void PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_copy_subtree_addr( + uint32_t out[8], const uint32_t in[8]); + +/* These functions are used for WOTS and FORS addresses. */ + +void PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_set_keypair_addr( + uint32_t addr[8], uint32_t keypair); + +void PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_set_chain_addr( + uint32_t addr[8], uint32_t chain); + +void PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_set_hash_addr( + uint32_t addr[8], uint32_t hash); + +void PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_copy_keypair_addr( + uint32_t out[8], const uint32_t in[8]); + +/* These functions are used for all hash tree addresses (including FORS). */ + +void PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_set_tree_height( + uint32_t addr[8], uint32_t tree_height); + +void PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_set_tree_index( + uint32_t addr[8], uint32_t tree_index); + +#endif diff --git a/lib/liboqs/src/sig/sphincs/pqclean_sphincs-shake256-192f-simple_clean/api.h b/lib/liboqs/src/sig/sphincs/pqclean_sphincs-shake256-192f-simple_clean/api.h new file mode 100644 index 000000000..48e622dba --- /dev/null +++ b/lib/liboqs/src/sig/sphincs/pqclean_sphincs-shake256-192f-simple_clean/api.h @@ -0,0 +1,81 @@ +#ifndef PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_API_H +#define PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_API_H + +#include <stddef.h> +#include <stdint.h> + + + +#define PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_CRYPTO_ALGNAME "SPHINCS+" + +#define PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_CRYPTO_SECRETKEYBYTES 96 +#define PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_CRYPTO_PUBLICKEYBYTES 48 +#define PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_CRYPTO_BYTES 35664 +#define PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_CRYPTO_SEEDBYTES 72 + + +/* + * Returns the length of a secret key, in bytes + */ +size_t PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_crypto_sign_secretkeybytes(void); + +/* + * Returns the length of a public key, in bytes + */ +size_t PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_crypto_sign_publickeybytes(void); + +/* + * Returns the length of a signature, in bytes + */ +size_t PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_crypto_sign_bytes(void); + +/* + * Returns the length of the seed required to generate a key pair, in bytes + */ +size_t PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_crypto_sign_seedbytes(void); + +/* + * Generates a SPHINCS+ key pair given a seed. + * Format sk: [SK_SEED || SK_PRF || PUB_SEED || root] + * Format pk: [root || PUB_SEED] + */ +int PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_crypto_sign_seed_keypair( + uint8_t *pk, uint8_t *sk, const uint8_t *seed); + +/* + * Generates a SPHINCS+ key pair. + * Format sk: [SK_SEED || SK_PRF || PUB_SEED || root] + * Format pk: [root || PUB_SEED] + */ +int PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_crypto_sign_keypair( + uint8_t *pk, uint8_t *sk); + +/** + * Returns an array containing a detached signature. + */ +int PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_crypto_sign_signature( + uint8_t *sig, size_t *siglen, + const uint8_t *m, size_t mlen, const uint8_t *sk); + +/** + * Verifies a detached signature and message under a given public key. + */ +int PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_crypto_sign_verify( + const uint8_t *sig, size_t siglen, + const uint8_t *m, size_t mlen, const uint8_t *pk); + +/** + * Returns an array containing the signature followed by the message. + */ +int PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_crypto_sign( + uint8_t *sm, size_t *smlen, + const uint8_t *m, size_t mlen, const uint8_t *sk); + +/** + * Verifies a given signature-message pair under a given public key. + */ +int PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_crypto_sign_open( + uint8_t *m, size_t *mlen, + const uint8_t *sm, size_t smlen, const uint8_t *pk); + +#endif diff --git a/lib/liboqs/src/sig/sphincs/pqclean_sphincs-shake256-192f-simple_clean/config.mk b/lib/liboqs/src/sig/sphincs/pqclean_sphincs-shake256-192f-simple_clean/config.mk new file mode 100644 index 000000000..b28c9ce64 --- /dev/null +++ b/lib/liboqs/src/sig/sphincs/pqclean_sphincs-shake256-192f-simple_clean/config.mk @@ -0,0 +1,17 @@ +# DO NOT EDIT: generated from config.mk.subdirs.template +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +# add fixes for platform integration issues here. +# +# liboqs programs expect the public include files to be in oqs/xxxx, +# So we put liboqs in it's own module, oqs, and point to the dist files +INCLUDES += -I$(CORE_DEPTH)/lib/liboqs/src/common/pqclean_shims -I$(CORE_DEPTH)/lib/liboqs/src/common/sha3/xkcp_low/KeccakP-1600/plain-64bits +DEFINES += + +ifeq ($(OS_ARCH), Darwin) +DEFINES += -DOQS_HAVE_ALIGNED_ALLOC -DOQS_HAVE_MEMALIGN -DOQS_HAVE_POSIX_MEMALIGN +endif + diff --git a/lib/liboqs/src/sig/sphincs/pqclean_sphincs-shake256-192f-simple_clean/fors.c b/lib/liboqs/src/sig/sphincs/pqclean_sphincs-shake256-192f-simple_clean/fors.c new file mode 100644 index 000000000..bc6f7f50c --- /dev/null +++ b/lib/liboqs/src/sig/sphincs/pqclean_sphincs-shake256-192f-simple_clean/fors.c @@ -0,0 +1,161 @@ +#include <stdint.h> +#include <stdlib.h> +#include <string.h> + +#include "address.h" +#include "fors.h" +#include "hash.h" +#include "hash_state.h" +#include "thash.h" +#include "utils.h" + +static void fors_gen_sk(unsigned char *sk, const unsigned char *sk_seed, + uint32_t fors_leaf_addr[8], const hash_state *hash_state_seeded) { + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_prf_addr( + sk, sk_seed, fors_leaf_addr, hash_state_seeded); +} + +static void fors_sk_to_leaf(unsigned char *leaf, const unsigned char *sk, + const unsigned char *pub_seed, + uint32_t fors_leaf_addr[8], + const hash_state *hash_state_seeded) { + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_thash_1( + leaf, sk, pub_seed, fors_leaf_addr, hash_state_seeded); +} + +static void fors_gen_leaf(unsigned char *leaf, const unsigned char *sk_seed, + const unsigned char *pub_seed, + uint32_t addr_idx, const uint32_t fors_tree_addr[8], + const hash_state *hash_state_seeded) { + uint32_t fors_leaf_addr[8] = {0}; + + /* Only copy the parts that must be kept in fors_leaf_addr. */ + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_copy_keypair_addr( + fors_leaf_addr, fors_tree_addr); + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_set_type( + fors_leaf_addr, PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_ADDR_TYPE_FORSTREE); + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_set_tree_index( + fors_leaf_addr, addr_idx); + + fors_gen_sk(leaf, sk_seed, fors_leaf_addr, hash_state_seeded); + fors_sk_to_leaf(leaf, leaf, pub_seed, fors_leaf_addr, hash_state_seeded); +} + +/** + * Interprets m as PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_FORS_HEIGHT-bit unsigned integers. + * Assumes m contains at least PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_FORS_HEIGHT * PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_FORS_TREES bits. + * Assumes indices has space for PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_FORS_TREES integers. + */ +static void message_to_indices(uint32_t *indices, const unsigned char *m) { + unsigned int i, j; + unsigned int offset = 0; + + for (i = 0; i < PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_FORS_TREES; i++) { + indices[i] = 0; + for (j = 0; j < PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_FORS_HEIGHT; j++) { + indices[i] ^= (((uint32_t)m[offset >> 3] >> (offset & 0x7)) & 0x1) << j; + offset++; + } + } +} + +/** + * Signs a message m, deriving the secret key from sk_seed and the FTS address. + * Assumes m contains at least PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_FORS_HEIGHT * PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_FORS_TREES bits. + */ +void PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_fors_sign( + unsigned char *sig, unsigned char *pk, + const unsigned char *m, + const unsigned char *sk_seed, const unsigned char *pub_seed, + const uint32_t fors_addr[8], const hash_state *hash_state_seeded) { + uint32_t indices[PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_FORS_TREES]; + unsigned char roots[PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_FORS_TREES * PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_N]; + uint32_t fors_tree_addr[8] = {0}; + uint32_t fors_pk_addr[8] = {0}; + uint32_t idx_offset; + unsigned int i; + + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_copy_keypair_addr( + fors_tree_addr, fors_addr); + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_copy_keypair_addr( + fors_pk_addr, fors_addr); + + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_set_type( + fors_tree_addr, PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_ADDR_TYPE_FORSTREE); + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_set_type( + fors_pk_addr, PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_ADDR_TYPE_FORSPK); + + message_to_indices(indices, m); + + for (i = 0; i < PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_FORS_TREES; i++) { + idx_offset = i * (1 << PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_FORS_HEIGHT); + + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_set_tree_height( + fors_tree_addr, 0); + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_set_tree_index( + fors_tree_addr, indices[i] + idx_offset); + + /* Include the secret key part that produces the selected leaf node. */ + fors_gen_sk(sig, sk_seed, fors_tree_addr, hash_state_seeded); + sig += PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_N; + + /* Compute the authentication path for this leaf node. */ + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_treehash_FORS_HEIGHT( + roots + i * PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_N, sig, sk_seed, pub_seed, + indices[i], idx_offset, fors_gen_leaf, fors_tree_addr, + hash_state_seeded); + sig += PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_N * PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_FORS_HEIGHT; + } + + /* Hash horizontally across all tree roots to derive the public key. */ + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_thash_FORS_TREES( + pk, roots, pub_seed, fors_pk_addr, hash_state_seeded); +} + +/** + * Derives the FORS public key from a signature. + * This can be used for verification by comparing to a known public key, or to + * subsequently verify a signature on the derived public key. The latter is the + * typical use-case when used as an FTS below an OTS in a hypertree. + * Assumes m contains at least PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_FORS_HEIGHT * PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_FORS_TREES bits. + */ +void PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_fors_pk_from_sig( + unsigned char *pk, + const unsigned char *sig, const unsigned char *m, + const unsigned char *pub_seed, const uint32_t fors_addr[8], + const hash_state *hash_state_seeded) { + uint32_t indices[PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_FORS_TREES]; + unsigned char roots[PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_FORS_TREES * PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_N]; + unsigned char leaf[PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_N]; + uint32_t fors_tree_addr[8] = {0}; + uint32_t fors_pk_addr[8] = {0}; + uint32_t idx_offset; + unsigned int i; + + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_copy_keypair_addr(fors_tree_addr, fors_addr); + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_copy_keypair_addr(fors_pk_addr, fors_addr); + + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_set_type(fors_tree_addr, PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_ADDR_TYPE_FORSTREE); + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_set_type(fors_pk_addr, PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_ADDR_TYPE_FORSPK); + + message_to_indices(indices, m); + + for (i = 0; i < PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_FORS_TREES; i++) { + idx_offset = i * (1 << PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_FORS_HEIGHT); + + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_set_tree_height(fors_tree_addr, 0); + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_set_tree_index(fors_tree_addr, indices[i] + idx_offset); + + /* Derive the leaf from the included secret key part. */ + fors_sk_to_leaf(leaf, sig, pub_seed, fors_tree_addr, hash_state_seeded); + sig += PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_N; + + /* Derive the corresponding root node of this tree. */ + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_compute_root(roots + i * PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_N, leaf, indices[i], idx_offset, sig, + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_FORS_HEIGHT, pub_seed, fors_tree_addr, hash_state_seeded); + sig += PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_N * PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_FORS_HEIGHT; + } + + /* Hash horizontally across all tree roots to derive the public key. */ + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_thash_FORS_TREES(pk, roots, pub_seed, fors_pk_addr, hash_state_seeded); +} diff --git a/lib/liboqs/src/sig/sphincs/pqclean_sphincs-shake256-192f-simple_clean/fors.h b/lib/liboqs/src/sig/sphincs/pqclean_sphincs-shake256-192f-simple_clean/fors.h new file mode 100644 index 000000000..a2648beab --- /dev/null +++ b/lib/liboqs/src/sig/sphincs/pqclean_sphincs-shake256-192f-simple_clean/fors.h @@ -0,0 +1,32 @@ +#ifndef PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_FORS_H +#define PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_FORS_H + +#include <stdint.h> + +#include "hash_state.h" +#include "params.h" + +/** + * Signs a message m, deriving the secret key from sk_seed and the FTS address. + * Assumes m contains at least PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_FORS_HEIGHT * PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_FORS_TREES bits. + */ +void PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_fors_sign( + unsigned char *sig, unsigned char *pk, + const unsigned char *m, + const unsigned char *sk_seed, const unsigned char *pub_seed, + const uint32_t fors_addr[8], const hash_state *hash_state_seeded); + +/** + * Derives the FORS public key from a signature. + * This can be used for verification by comparing to a known public key, or to + * subsequently verify a signature on the derived public key. The latter is the + * typical use-case when used as an FTS below an OTS in a hypertree. + * Assumes m contains at least PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_FORS_HEIGHT * PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_FORS_TREES bits. + */ +void PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_fors_pk_from_sig( + unsigned char *pk, + const unsigned char *sig, const unsigned char *m, + const unsigned char *pub_seed, const uint32_t fors_addr[8], + const hash_state *hash_state_seeded); + +#endif diff --git a/lib/liboqs/src/sig/sphincs/pqclean_sphincs-shake256-192f-simple_clean/hash.h b/lib/liboqs/src/sig/sphincs/pqclean_sphincs-shake256-192f-simple_clean/hash.h new file mode 100644 index 000000000..bbd5ebdb3 --- /dev/null +++ b/lib/liboqs/src/sig/sphincs/pqclean_sphincs-shake256-192f-simple_clean/hash.h @@ -0,0 +1,31 @@ +#ifndef PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_HASH_H +#define PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_HASH_H + +#include "hash_state.h" + +#include <stddef.h> +#include <stdint.h> + +void PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_initialize_hash_function( + hash_state *hash_state_seeded, + const unsigned char *pub_seed, const unsigned char *sk_seed); + +void PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_destroy_hash_function(hash_state *hash_state_seeded); + +void PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_prf_addr( + unsigned char *out, const unsigned char *key, const uint32_t addr[8], + const hash_state *hash_state_seeded); + +void PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_gen_message_random( + unsigned char *R, + const unsigned char *sk_prf, const unsigned char *optrand, + const unsigned char *m, size_t mlen, + const hash_state *hash_state_seeded); + +void PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_hash_message( + unsigned char *digest, uint64_t *tree, uint32_t *leaf_idx, + const unsigned char *R, const unsigned char *pk, + const unsigned char *m, size_t mlen, + const hash_state *hash_state_seeded); + +#endif diff --git a/lib/liboqs/src/sig/sphincs/pqclean_sphincs-shake256-192f-simple_clean/hash_shake256.c b/lib/liboqs/src/sig/sphincs/pqclean_sphincs-shake256-192f-simple_clean/hash_shake256.c new file mode 100644 index 000000000..81d055a56 --- /dev/null +++ b/lib/liboqs/src/sig/sphincs/pqclean_sphincs-shake256-192f-simple_clean/hash_shake256.c @@ -0,0 +1,106 @@ +#include <stdint.h> +#include <string.h> + +#include "address.h" +#include "hash.h" +#include "params.h" +#include "utils.h" + +#include "fips202.h" + +/* For SHAKE256, there is no immediate reason to initialize at the start, + so this function is an empty operation. */ +void PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_initialize_hash_function( + hash_state *hash_state_seeded, // NOLINT(readability-non-const-parameter) + const unsigned char *pub_seed, const unsigned char *sk_seed) { + (void)hash_state_seeded; /* Suppress an 'unused parameter' warning. */ + (void)pub_seed; /* Suppress an 'unused parameter' warning. */ + (void)sk_seed; /* Suppress an 'unused parameter' warning. */ +} + +/* This is not necessary for SHAKE256, so we don't do anything */ +void PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_destroy_hash_function( + hash_state *hash_state_seeded) { // NOLINT(readability-non-const-parameter) + (void)hash_state_seeded; +} + +/* + * Computes PRF(key, addr), given a secret key of PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_N bytes and an address + */ +void PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_prf_addr( + unsigned char *out, const unsigned char *key, const uint32_t addr[8], + const hash_state *hash_state_seeded) { + unsigned char buf[PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_N + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_ADDR_BYTES]; + + memcpy(buf, key, PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_N); + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_addr_to_bytes(buf + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_N, addr); + + shake256(out, PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_N, buf, PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_N + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_ADDR_BYTES); + + (void)hash_state_seeded; /* Prevent unused parameter warning. */ +} + +/** + * Computes the message-dependent randomness R, using a secret seed and an + * optional randomization value as well as the message. + */ +void PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_gen_message_random( + unsigned char *R, + const unsigned char *sk_prf, const unsigned char *optrand, + const unsigned char *m, size_t mlen, + const hash_state *hash_state_seeded) { + shake256incctx state; + + shake256_inc_init(&state); + shake256_inc_absorb(&state, sk_prf, PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_N); + shake256_inc_absorb(&state, optrand, PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_N); + shake256_inc_absorb(&state, m, mlen); + shake256_inc_finalize(&state); + shake256_inc_squeeze(R, PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_N, &state); + shake256_inc_ctx_release(&state); + + (void)hash_state_seeded; /* Prevent unused parameter warning. */ +} + +/** + * Computes the message hash using R, the public key, and the message. + * Outputs the message digest and the index of the leaf. The index is split in + * the tree index and the leaf index, for convenient copying to an address. + */ +void PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_hash_message( + unsigned char *digest, uint64_t *tree, uint32_t *leaf_idx, + const unsigned char *R, const unsigned char *pk, + const unsigned char *m, size_t mlen, + const hash_state *hash_state_seeded) { +#define PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_TREE_BITS (PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_TREE_HEIGHT * (PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_D - 1)) +#define PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_TREE_BYTES ((PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_TREE_BITS + 7) / 8) +#define PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_LEAF_BITS PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_TREE_HEIGHT +#define PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_LEAF_BYTES ((PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_LEAF_BITS + 7) / 8) +#define PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_DGST_BYTES (PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_FORS_MSG_BYTES + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_TREE_BYTES + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_LEAF_BYTES) + + unsigned char buf[PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_DGST_BYTES]; + unsigned char *bufp = buf; + shake256incctx state; + + shake256_inc_init(&state); + shake256_inc_absorb(&state, R, PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_N); + shake256_inc_absorb(&state, pk, PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_PK_BYTES); + shake256_inc_absorb(&state, m, mlen); + shake256_inc_finalize(&state); + shake256_inc_squeeze(buf, PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_DGST_BYTES, &state); + shake256_inc_ctx_release(&state); + + memcpy(digest, bufp, PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_FORS_MSG_BYTES); + bufp += PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_FORS_MSG_BYTES; + + *tree = PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_bytes_to_ull( + bufp, PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_TREE_BYTES); + *tree &= (~(uint64_t)0) >> (64 - PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_TREE_BITS); + bufp += PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_TREE_BYTES; + + *leaf_idx = (uint32_t)PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_bytes_to_ull( + bufp, PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_LEAF_BYTES); + *leaf_idx &= (~(uint32_t)0) >> (32 - PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_LEAF_BITS); + + (void)hash_state_seeded; /* Prevent unused parameter warning. */ +} diff --git a/lib/liboqs/src/sig/sphincs/pqclean_sphincs-shake256-192f-simple_clean/hash_state.h b/lib/liboqs/src/sig/sphincs/pqclean_sphincs-shake256-192f-simple_clean/hash_state.h new file mode 100644 index 000000000..7d92ef872 --- /dev/null +++ b/lib/liboqs/src/sig/sphincs/pqclean_sphincs-shake256-192f-simple_clean/hash_state.h @@ -0,0 +1,30 @@ +#ifndef SPX_HASH_STATE_H +#define SPX_HASH_STATE_H + +/** + * Defines the type of the hash function state. + * + * Don't be fooled into thinking this instance of SPHINCS+ isn't stateless! + * + * From Section 7.2.2 from the SPHINCS+ round-2 specification: + * + * Each of the instances of the tweakable hash function take PK.seed as its + * first input, which is constant for a given key pair – and, thus, across + * a single signature. This leads to a lot of redundant computation. To remedy + * this, we pad PK.seed to the length of a full 64-byte SHA-256 input block. + * Because of the Merkle-Damgård construction that underlies SHA-256, this + * allows for reuse of the intermediate SHA-256 state after the initial call to + * the compression function which improves performance. + * + * We pass this hash state around in functions, because otherwise we need to + * have a global variable. + * + * SHAKE256 does not need this state. Because this implementation is generated + * from a shared code base, we still need to specify some hash_state as it is + * still passed around. We chose to use an `int` as a placeholder for this + * purpose. + */ + +#define hash_state int + +#endif diff --git a/lib/liboqs/src/sig/sphincs/pqclean_sphincs-shake256-192f-simple_clean/manifest.mn b/lib/liboqs/src/sig/sphincs/pqclean_sphincs-shake256-192f-simple_clean/manifest.mn new file mode 100644 index 000000000..ec5a6c111 --- /dev/null +++ b/lib/liboqs/src/sig/sphincs/pqclean_sphincs-shake256-192f-simple_clean/manifest.mn @@ -0,0 +1,29 @@ +# DO NOT EDIT: generated from manifest.mn.subdirs.template +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +CORE_DEPTH = ../../../../../.. + +MODULE = oqs + +LIBRARY_NAME = oqs_src_sig_sphincs_pqclean_sphincs-shake256-192f-simple_clean +SHARED_LIBRARY = $(NULL) + +CSRCS = \ + address.c \ + fors.c \ + hash_shake256.c \ + sign.c \ + thash_shake256_simple.c \ + utils.c \ + wots.c \ + $(NULL) + +# only add module debugging in opt builds if DEBUG_PKCS11 is set +ifdef DEBUG_PKCS11 + DEFINES += -DDEBUG_MODULE +endif + +# This part of the code, including all sub-dirs, can be optimized for size +export ALLOW_OPT_CODE_SIZE = 1 diff --git a/lib/liboqs/src/sig/sphincs/pqclean_sphincs-shake256-192f-simple_clean/params.h b/lib/liboqs/src/sig/sphincs/pqclean_sphincs-shake256-192f-simple_clean/params.h new file mode 100644 index 000000000..292f83c4d --- /dev/null +++ b/lib/liboqs/src/sig/sphincs/pqclean_sphincs-shake256-192f-simple_clean/params.h @@ -0,0 +1,53 @@ +#ifndef PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_PARAMS_H +#define PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_PARAMS_H + +/* Hash output length in bytes. */ +#define PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_N 24 +/* Height of the hypertree. */ +#define PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_FULL_HEIGHT 66 +/* Number of subtree layer. */ +#define PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_D 22 +/* FORS tree dimensions. */ +#define PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_FORS_HEIGHT 8 +#define PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_FORS_TREES 33 +/* Winternitz parameter, */ +#define PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_WOTS_W 16 + +/* The hash function is defined by linking a different hash.c file, as opposed + to setting a #define constant. */ + +/* For clarity */ +#define PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_ADDR_BYTES 32 + +/* WOTS parameters. */ +#define PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_WOTS_LOGW 4 + +#define PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_WOTS_LEN1 (8 * PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_N / PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_WOTS_LOGW) + +/* PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_WOTS_LEN2 is floor(log(len_1 * (w - 1)) / log(w)) + 1; we precompute */ +#define PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_WOTS_LEN2 3 + +#define PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_WOTS_LEN (PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_WOTS_LEN1 + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_WOTS_LEN2) +#define PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_WOTS_BYTES (PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_WOTS_LEN * PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_N) +#define PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_WOTS_PK_BYTES PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_WOTS_BYTES + +/* Subtree size. */ +#define PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_TREE_HEIGHT (PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_FULL_HEIGHT / PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_D) + +/* FORS parameters. */ +#define PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_FORS_MSG_BYTES ((PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_FORS_HEIGHT * PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_FORS_TREES + 7) / 8) +#define PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_FORS_BYTES ((PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_FORS_HEIGHT + 1) * PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_FORS_TREES * PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_N) +#define PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_FORS_PK_BYTES PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_N + +/* Resulting SPX sizes. */ +#define PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_BYTES (PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_N + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_FORS_BYTES + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_D * PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_WOTS_BYTES +\ + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_FULL_HEIGHT * PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_N) +#define PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_PK_BYTES (2 * PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_N) +#define PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_SK_BYTES (2 * PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_N + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_PK_BYTES) + +/* Optionally, signing can be made non-deterministic using optrand. + This can help counter side-channel attacks that would benefit from + getting a large number of traces when the signer uses the same nodes. */ +#define PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_OPTRAND_BYTES 32 + +#endif diff --git a/lib/liboqs/src/sig/sphincs/pqclean_sphincs-shake256-192f-simple_clean/pqclean_sphincs-shake256-192f-simple_clean.gyp b/lib/liboqs/src/sig/sphincs/pqclean_sphincs-shake256-192f-simple_clean/pqclean_sphincs-shake256-192f-simple_clean.gyp new file mode 100644 index 000000000..058d520e7 --- /dev/null +++ b/lib/liboqs/src/sig/sphincs/pqclean_sphincs-shake256-192f-simple_clean/pqclean_sphincs-shake256-192f-simple_clean.gyp @@ -0,0 +1,45 @@ +# DO NOT EDIT: generated from subdir.gyp.template +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +{ + 'includes': [ + '../../../../../../coreconf/config.gypi' + ], + 'targets': [ + { + 'target_name': 'oqs_src_sig_sphincs_pqclean_sphincs-shake256-192f-simple_clean', + 'type': 'static_library', + 'sources': [ + 'address.c', + 'fors.c', + 'hash_shake256.c', + 'sign.c', + 'thash_shake256_simple.c', + 'utils.c', + 'wots.c', + ], + 'dependencies': [ + '<(DEPTH)/exports.gyp:nss_exports' + ] + } + ], + 'target_defaults': { + 'defines': [ + ], + 'include_dirs': [ + '<(DEPTH)/lib/liboqs/src/common/pqclean_shims', + '<(DEPTH)/lib/liboqs/src/common/sha3/xkcp_low/KeccakP-1600/plain-64bits', + ], + [ 'OS=="mac"', { + 'defines': [ + 'OQS_HAVE_POSIX_MEMALIGN', + 'OQS_HAVE_ALIGNED_ALLOC', + 'OQS_HAVE_MEMALIGN' + ] + }] + }, + 'variables': { + 'module': 'oqs' + } +} diff --git a/lib/liboqs/src/sig/sphincs/pqclean_sphincs-shake256-192f-simple_clean/sign.c b/lib/liboqs/src/sig/sphincs/pqclean_sphincs-shake256-192f-simple_clean/sign.c new file mode 100644 index 000000000..7efb32f90 --- /dev/null +++ b/lib/liboqs/src/sig/sphincs/pqclean_sphincs-shake256-192f-simple_clean/sign.c @@ -0,0 +1,356 @@ +#include <stddef.h> +#include <stdint.h> +#include <string.h> + +#include "address.h" +#include "api.h" +#include "fors.h" +#include "hash.h" +#include "hash_state.h" +#include "params.h" +#include "randombytes.h" +#include "thash.h" +#include "utils.h" +#include "wots.h" + +/** + * Computes the leaf at a given address. First generates the WOTS key pair, + * then computes leaf by hashing horizontally. + */ +static void wots_gen_leaf(unsigned char *leaf, const unsigned char *sk_seed, + const unsigned char *pub_seed, + uint32_t addr_idx, const uint32_t tree_addr[8], + const hash_state *hash_state_seeded) { + unsigned char pk[PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_WOTS_BYTES]; + uint32_t wots_addr[8] = {0}; + uint32_t wots_pk_addr[8] = {0}; + + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_set_type( + wots_addr, PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_ADDR_TYPE_WOTS); + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_set_type( + wots_pk_addr, PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_ADDR_TYPE_WOTSPK); + + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_copy_subtree_addr( + wots_addr, tree_addr); + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_set_keypair_addr( + wots_addr, addr_idx); + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_wots_gen_pk( + pk, sk_seed, pub_seed, wots_addr, hash_state_seeded); + + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_copy_keypair_addr( + wots_pk_addr, wots_addr); + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_thash_WOTS_LEN( + leaf, pk, pub_seed, wots_pk_addr, hash_state_seeded); +} + +/* + * Returns the length of a secret key, in bytes + */ +size_t PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_crypto_sign_secretkeybytes(void) { + return PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_CRYPTO_SECRETKEYBYTES; +} + +/* + * Returns the length of a public key, in bytes + */ +size_t PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_crypto_sign_publickeybytes(void) { + return PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_CRYPTO_PUBLICKEYBYTES; +} + +/* + * Returns the length of a signature, in bytes + */ +size_t PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_crypto_sign_bytes(void) { + return PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_CRYPTO_BYTES; +} + +/* + * Returns the length of the seed required to generate a key pair, in bytes + */ +size_t PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_crypto_sign_seedbytes(void) { + return PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_CRYPTO_SEEDBYTES; +} + +/* + * Generates an SPX key pair given a seed of length + * Format sk: [SK_SEED || SK_PRF || PUB_SEED || root] + * Format pk: [PUB_SEED || root] + */ +int PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_crypto_sign_seed_keypair( + uint8_t *pk, uint8_t *sk, const uint8_t *seed) { + /* We do not need the auth path in key generation, but it simplifies the + code to have just one treehash routine that computes both root and path + in one function. */ + unsigned char auth_path[PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_TREE_HEIGHT * PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_N]; + uint32_t top_tree_addr[8] = {0}; + hash_state hash_state_seeded; + + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_set_layer_addr( + top_tree_addr, PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_D - 1); + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_set_type( + top_tree_addr, PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_ADDR_TYPE_HASHTREE); + + /* Initialize SK_SEED, SK_PRF and PUB_SEED from seed. */ + memcpy(sk, seed, PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_CRYPTO_SEEDBYTES); + + memcpy(pk, sk + 2 * PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_N, PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_N); + + /* This hook allows the hash function instantiation to do whatever + preparation or computation it needs, based on the public seed. */ + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_initialize_hash_function(&hash_state_seeded, pk, sk); + + /* Compute root node of the top-most subtree. */ + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_treehash_TREE_HEIGHT( + sk + 3 * PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_N, auth_path, sk, sk + 2 * PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_N, 0, 0, + wots_gen_leaf, top_tree_addr, &hash_state_seeded); + + memcpy(pk + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_N, sk + 3 * PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_N, PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_N); + + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_destroy_hash_function(&hash_state_seeded); + return 0; +} + +/* + * Generates an SPX key pair. + * Format sk: [SK_SEED || SK_PRF || PUB_SEED || root] + * Format pk: [PUB_SEED || root] + */ +int PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_crypto_sign_keypair( + uint8_t *pk, uint8_t *sk) { + unsigned char seed[PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_CRYPTO_SEEDBYTES]; + randombytes(seed, PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_CRYPTO_SEEDBYTES); + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_crypto_sign_seed_keypair( + pk, sk, seed); + + return 0; +} + +/** + * Returns an array containing a detached signature. + */ +int PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_crypto_sign_signature( + uint8_t *sig, size_t *siglen, + const uint8_t *m, size_t mlen, const uint8_t *sk) { + const unsigned char *sk_seed = sk; + const unsigned char *sk_prf = sk + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_N; + const unsigned char *pk = sk + 2 * PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_N; + const unsigned char *pub_seed = pk; + + unsigned char optrand[PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_N]; + unsigned char mhash[PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_FORS_MSG_BYTES]; + unsigned char root[PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_N]; + uint32_t i; + uint64_t tree; + uint32_t idx_leaf; + uint32_t wots_addr[8] = {0}; + uint32_t tree_addr[8] = {0}; + + hash_state hash_state_seeded; + + /* This hook allows the hash function instantiation to do whatever + preparation or computation it needs, based on the public seed. */ + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_initialize_hash_function( + &hash_state_seeded, + pub_seed, sk_seed); + + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_set_type( + wots_addr, PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_ADDR_TYPE_WOTS); + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_set_type( + tree_addr, PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_ADDR_TYPE_HASHTREE); + + /* Optionally, signing can be made non-deterministic using optrand. + This can help counter side-channel attacks that would benefit from + getting a large number of traces when the signer uses the same nodes. */ + randombytes(optrand, PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_N); + /* Compute the digest randomization value. */ + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_gen_message_random( + sig, sk_prf, optrand, m, mlen, &hash_state_seeded); + + /* Derive the message digest and leaf index from R, PK and M. */ + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_hash_message( + mhash, &tree, &idx_leaf, sig, pk, m, mlen, &hash_state_seeded); + sig += PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_N; + + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_set_tree_addr(wots_addr, tree); + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + /* Sign the message hash using FORS. */ + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_fors_sign( + sig, root, mhash, sk_seed, pub_seed, wots_addr, &hash_state_seeded); + sig += PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_FORS_BYTES; + + for (i = 0; i < PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_D; i++) { + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_set_layer_addr(tree_addr, i); + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_set_tree_addr(tree_addr, tree); + + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_copy_subtree_addr( + wots_addr, tree_addr); + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + /* Compute a WOTS signature. */ + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_wots_sign( + sig, root, sk_seed, pub_seed, wots_addr, &hash_state_seeded); + sig += PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_WOTS_BYTES; + + /* Compute the authentication path for the used WOTS leaf. */ + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_treehash_TREE_HEIGHT( + root, sig, sk_seed, pub_seed, idx_leaf, 0, + wots_gen_leaf, tree_addr, &hash_state_seeded); + sig += PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_TREE_HEIGHT * PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_N; + + /* Update the indices for the next layer. */ + idx_leaf = (tree & ((1 << PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_TREE_HEIGHT) - 1)); + tree = tree >> PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_TREE_HEIGHT; + } + + *siglen = PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_BYTES; + + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_destroy_hash_function(&hash_state_seeded); + return 0; +} + +/** + * Verifies a detached signature and message under a given public key. + */ +int PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_crypto_sign_verify( + const uint8_t *sig, size_t siglen, + const uint8_t *m, size_t mlen, const uint8_t *pk) { + const unsigned char *pub_seed = pk; + const unsigned char *pub_root = pk + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_N; + unsigned char mhash[PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_FORS_MSG_BYTES]; + unsigned char wots_pk[PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_WOTS_BYTES]; + unsigned char root[PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_N]; + unsigned char leaf[PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_N]; + unsigned int i; + uint64_t tree; + uint32_t idx_leaf; + uint32_t wots_addr[8] = {0}; + uint32_t tree_addr[8] = {0}; + uint32_t wots_pk_addr[8] = {0}; + + hash_state hash_state_seeded; + + if (siglen != PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_BYTES) { + return -1; + } + + /* This hook allows the hash function instantiation to do whatever + preparation or computation it needs, based on the public seed. */ + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_initialize_hash_function( + &hash_state_seeded, + pub_seed, NULL); + + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_set_type( + wots_addr, PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_ADDR_TYPE_WOTS); + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_set_type( + tree_addr, PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_ADDR_TYPE_HASHTREE); + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_set_type( + wots_pk_addr, PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_ADDR_TYPE_WOTSPK); + + /* Derive the message digest and leaf index from R || PK || M. */ + /* The additional PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_N is a result of the hash domain separator. */ + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_hash_message( + mhash, &tree, &idx_leaf, sig, pk, m, mlen, &hash_state_seeded); + sig += PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_N; + + /* Layer correctly defaults to 0, so no need to set_layer_addr */ + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_set_tree_addr(wots_addr, tree); + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_fors_pk_from_sig( + root, sig, mhash, pub_seed, wots_addr, &hash_state_seeded); + sig += PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_FORS_BYTES; + + /* For each subtree.. */ + for (i = 0; i < PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_D; i++) { + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_set_layer_addr(tree_addr, i); + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_set_tree_addr(tree_addr, tree); + + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_copy_subtree_addr( + wots_addr, tree_addr); + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_copy_keypair_addr( + wots_pk_addr, wots_addr); + + /* The WOTS public key is only correct if the signature was correct. */ + /* Initially, root is the FORS pk, but on subsequent iterations it is + the root of the subtree below the currently processed subtree. */ + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_wots_pk_from_sig( + wots_pk, sig, root, pub_seed, wots_addr, &hash_state_seeded); + sig += PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_WOTS_BYTES; + + /* Compute the leaf node using the WOTS public key. */ + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_thash_WOTS_LEN( + leaf, wots_pk, pub_seed, wots_pk_addr, &hash_state_seeded); + + /* Compute the root node of this subtree. */ + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_compute_root( + root, leaf, idx_leaf, 0, sig, PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_TREE_HEIGHT, + pub_seed, tree_addr, &hash_state_seeded); + sig += PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_TREE_HEIGHT * PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_N; + + /* Update the indices for the next layer. */ + idx_leaf = (tree & ((1 << PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_TREE_HEIGHT) - 1)); + tree = tree >> PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_TREE_HEIGHT; + } + + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_destroy_hash_function(&hash_state_seeded); + /* Check if the root node equals the root node in the public key. */ + if (memcmp(root, pub_root, PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_N) != 0) { + return -1; + } + + return 0; +} + + +/** + * Returns an array containing the signature followed by the message. + */ +int PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_crypto_sign( + uint8_t *sm, size_t *smlen, + const uint8_t *m, size_t mlen, const uint8_t *sk) { + size_t siglen; + + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_crypto_sign_signature( + sm, &siglen, m, mlen, sk); + + memmove(sm + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_BYTES, m, mlen); + *smlen = siglen + mlen; + + return 0; +} + +/** + * Verifies a given signature-message pair under a given public key. + */ +int PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_crypto_sign_open( + uint8_t *m, size_t *mlen, + const uint8_t *sm, size_t smlen, const uint8_t *pk) { + /* The API caller does not necessarily know what size a signature should be + but SPHINCS+ signatures are always exactly PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_BYTES. */ + if (smlen < PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_BYTES) { + memset(m, 0, smlen); + *mlen = 0; + return -1; + } + + *mlen = smlen - PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_BYTES; + + if (PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_crypto_sign_verify( + sm, PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_BYTES, sm + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_BYTES, *mlen, pk)) { + memset(m, 0, smlen); + *mlen = 0; + return -1; + } + + /* If verification was successful, move the message to the right place. */ + memmove(m, sm + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_BYTES, *mlen); + + return 0; +} diff --git a/lib/liboqs/src/sig/sphincs/pqclean_sphincs-shake256-192f-simple_clean/thash.h b/lib/liboqs/src/sig/sphincs/pqclean_sphincs-shake256-192f-simple_clean/thash.h new file mode 100644 index 000000000..b090f26a6 --- /dev/null +++ b/lib/liboqs/src/sig/sphincs/pqclean_sphincs-shake256-192f-simple_clean/thash.h @@ -0,0 +1,28 @@ +#ifndef PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_THASH_H +#define PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_THASH_H + +#include "hash_state.h" + +#include <stdint.h> + +void PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_thash_1( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8], + const hash_state *hash_state_seeded); + +void PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_thash_2( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8], + const hash_state *hash_state_seeded); + +void PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_thash_WOTS_LEN( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8], + const hash_state *hash_state_seeded); + +void PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_thash_FORS_TREES( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8], + const hash_state *hash_state_seeded); + +#endif diff --git a/lib/liboqs/src/sig/sphincs/pqclean_sphincs-shake256-192f-simple_clean/thash_shake256_simple.c b/lib/liboqs/src/sig/sphincs/pqclean_sphincs-shake256-192f-simple_clean/thash_shake256_simple.c new file mode 100644 index 000000000..8ed51d81e --- /dev/null +++ b/lib/liboqs/src/sig/sphincs/pqclean_sphincs-shake256-192f-simple_clean/thash_shake256_simple.c @@ -0,0 +1,74 @@ +#include <stdint.h> +#include <string.h> + +#include "address.h" +#include "hash_state.h" +#include "params.h" +#include "thash.h" + +#include "fips202.h" + +/** + * Takes an array of inblocks concatenated arrays of PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_N bytes. + */ +static void PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_thash( + unsigned char *out, unsigned char *buf, + const unsigned char *in, unsigned int inblocks, + const unsigned char *pub_seed, uint32_t addr[8]) { + + memcpy(buf, pub_seed, PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_N); + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_addr_to_bytes(buf + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_N, addr); + memcpy(buf + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_N + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_ADDR_BYTES, in, inblocks * PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_N); + + shake256(out, PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_N, buf, PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_N + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_ADDR_BYTES + inblocks * PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_N); +} + +/* The wrappers below ensure that we use fixed-size buffers on the stack */ + +void PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_thash_1( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8], + const hash_state *hash_state_seeded) { + + unsigned char buf[PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_N + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_ADDR_BYTES + 1 * PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_N]; + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_thash( + out, buf, in, 1, pub_seed, addr); + + (void)hash_state_seeded; /* Avoid unused parameter warning. */ +} + +void PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_thash_2( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8], + const hash_state *hash_state_seeded) { + + unsigned char buf[PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_N + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_ADDR_BYTES + 2 * PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_N]; + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_thash( + out, buf, in, 2, pub_seed, addr); + + (void)hash_state_seeded; /* Avoid unused parameter warning. */ +} + +void PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_thash_WOTS_LEN( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8], + const hash_state *hash_state_seeded) { + + unsigned char buf[PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_N + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_ADDR_BYTES + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_WOTS_LEN * PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_N]; + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_thash( + out, buf, in, PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_WOTS_LEN, pub_seed, addr); + + (void)hash_state_seeded; /* Avoid unused parameter warning. */ +} + +void PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_thash_FORS_TREES( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8], + const hash_state *hash_state_seeded) { + + unsigned char buf[PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_N + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_ADDR_BYTES + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_FORS_TREES * PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_N]; + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_thash( + out, buf, in, PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_FORS_TREES, pub_seed, addr); + + (void)hash_state_seeded; /* Avoid unused parameter warning. */ +} diff --git a/lib/liboqs/src/sig/sphincs/pqclean_sphincs-shake256-192f-simple_clean/utils.c b/lib/liboqs/src/sig/sphincs/pqclean_sphincs-shake256-192f-simple_clean/utils.c new file mode 100644 index 000000000..82ae4b3ff --- /dev/null +++ b/lib/liboqs/src/sig/sphincs/pqclean_sphincs-shake256-192f-simple_clean/utils.c @@ -0,0 +1,199 @@ +#include <stddef.h> +#include <string.h> + +#include "address.h" +#include "hash.h" +#include "hash_state.h" +#include "params.h" +#include "thash.h" +#include "utils.h" + +/** + * Converts the value of 'in' to 'outlen' bytes in big-endian byte order. + */ +void PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_ull_to_bytes( + unsigned char *out, size_t outlen, unsigned long long in) { + + /* Iterate over out in decreasing order, for big-endianness. */ + for (size_t i = outlen; i > 0; i--) { + out[i - 1] = in & 0xff; + in = in >> 8; + } +} + +/** + * Converts the inlen bytes in 'in' from big-endian byte order to an integer. + */ +unsigned long long PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_bytes_to_ull( + const unsigned char *in, size_t inlen) { + unsigned long long retval = 0; + + for (size_t i = 0; i < inlen; i++) { + retval |= ((unsigned long long)in[i]) << (8 * (inlen - 1 - i)); + } + return retval; +} + +/** + * Computes a root node given a leaf and an auth path. + * Expects address to be complete other than the tree_height and tree_index. + */ +void PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_compute_root( + unsigned char *root, const unsigned char *leaf, + uint32_t leaf_idx, uint32_t idx_offset, + const unsigned char *auth_path, uint32_t tree_height, + const unsigned char *pub_seed, uint32_t addr[8], + const hash_state *hash_state_seeded) { + uint32_t i; + unsigned char buffer[2 * PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_N]; + + /* If leaf_idx is odd (last bit = 1), current path element is a right child + and auth_path has to go left. Otherwise it is the other way around. */ + if (leaf_idx & 1) { + memcpy(buffer + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_N, leaf, PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_N); + memcpy(buffer, auth_path, PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_N); + } else { + memcpy(buffer, leaf, PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_N); + memcpy(buffer + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_N, auth_path, PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_N); + } + auth_path += PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_N; + + for (i = 0; i < tree_height - 1; i++) { + leaf_idx >>= 1; + idx_offset >>= 1; + /* Set the address of the node we're creating. */ + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_set_tree_height(addr, i + 1); + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_set_tree_index( + addr, leaf_idx + idx_offset); + + /* Pick the right or left neighbor, depending on parity of the node. */ + if (leaf_idx & 1) { + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_thash_2( + buffer + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_N, buffer, pub_seed, addr, hash_state_seeded); + memcpy(buffer, auth_path, PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_N); + } else { + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_thash_2( + buffer, buffer, pub_seed, addr, hash_state_seeded); + memcpy(buffer + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_N, auth_path, PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_N); + } + auth_path += PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_N; + } + + /* The last iteration is exceptional; we do not copy an auth_path node. */ + leaf_idx >>= 1; + idx_offset >>= 1; + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_set_tree_height(addr, tree_height); + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_set_tree_index( + addr, leaf_idx + idx_offset); + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_thash_2( + root, buffer, pub_seed, addr, hash_state_seeded); +} + +/** + * For a given leaf index, computes the authentication path and the resulting + * root node using Merkle's TreeHash algorithm. + * Expects the layer and tree parts of the tree_addr to be set, as well as the + * tree type (i.e. PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_ADDR_TYPE_HASHTREE or PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_ADDR_TYPE_FORSTREE). + * Applies the offset idx_offset to indices before building addresses, so that + * it is possible to continue counting indices across trees. + */ +static void PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_treehash( + unsigned char *root, unsigned char *auth_path, + unsigned char *stack, unsigned int *heights, + const unsigned char *sk_seed, const unsigned char *pub_seed, + uint32_t leaf_idx, uint32_t idx_offset, uint32_t tree_height, + void (*gen_leaf)( + unsigned char * /* leaf */, + const unsigned char * /* sk_seed */, + const unsigned char * /* pub_seed */, + uint32_t /* addr_idx */, const uint32_t[8] /* tree_addr */, + const hash_state * /* hash_state_seeded */), + uint32_t tree_addr[8], + const hash_state *hash_state_seeded) { + + unsigned int offset = 0; + uint32_t idx; + uint32_t tree_idx; + + for (idx = 0; idx < (uint32_t)(1 << tree_height); idx++) { + /* Add the next leaf node to the stack. */ + gen_leaf(stack + offset * PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_N, + sk_seed, pub_seed, idx + idx_offset, tree_addr, + hash_state_seeded); + offset++; + heights[offset - 1] = 0; + + /* If this is a node we need for the auth path.. */ + if ((leaf_idx ^ 0x1) == idx) { + memcpy(auth_path, stack + (offset - 1)*PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_N, PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_N); + } + + /* While the top-most nodes are of equal height.. */ + while (offset >= 2 && heights[offset - 1] == heights[offset - 2]) { + /* Compute index of the new node, in the next layer. */ + tree_idx = (idx >> (heights[offset - 1] + 1)); + + /* Set the address of the node we're creating. */ + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_set_tree_height( + tree_addr, heights[offset - 1] + 1); + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_set_tree_index( + tree_addr, tree_idx + (idx_offset >> (heights[offset - 1] + 1))); + /* Hash the top-most nodes from the stack together. */ + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_thash_2( + stack + (offset - 2)*PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_N, stack + (offset - 2)*PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_N, + pub_seed, tree_addr, hash_state_seeded); + offset--; + /* Note that the top-most node is now one layer higher. */ + heights[offset - 1]++; + + /* If this is a node we need for the auth path.. */ + if (((leaf_idx >> heights[offset - 1]) ^ 0x1) == tree_idx) { + memcpy(auth_path + heights[offset - 1]*PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_N, + stack + (offset - 1)*PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_N, PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_N); + } + } + } + memcpy(root, stack, PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_N); +} + +/* The wrappers below ensure that we use fixed-size buffers on the stack */ + +void PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_treehash_FORS_HEIGHT( + unsigned char *root, unsigned char *auth_path, + const unsigned char *sk_seed, const unsigned char *pub_seed, + uint32_t leaf_idx, uint32_t idx_offset, + void (*gen_leaf)( + unsigned char * /* leaf */, + const unsigned char * /* sk_seed */, + const unsigned char * /* pub_seed */, + uint32_t /* addr_idx */, const uint32_t[8] /* tree_addr */, + const hash_state * /* hash_state_seeded */), + uint32_t tree_addr[8], const hash_state *hash_state_seeded) { + + unsigned char stack[(PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_FORS_HEIGHT + 1)*PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_N]; + unsigned int heights[PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_FORS_HEIGHT + 1]; + + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_treehash( + root, auth_path, stack, heights, sk_seed, pub_seed, + leaf_idx, idx_offset, PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_FORS_HEIGHT, gen_leaf, tree_addr, hash_state_seeded); +} + +void PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_treehash_TREE_HEIGHT( + unsigned char *root, unsigned char *auth_path, + const unsigned char *sk_seed, const unsigned char *pub_seed, + uint32_t leaf_idx, uint32_t idx_offset, + void (*gen_leaf)( + unsigned char * /* leaf */, + const unsigned char * /* sk_seed */, + const unsigned char * /* pub_seed */, + uint32_t /* addr_idx */, const uint32_t[8] /* tree_addr */, + const hash_state * /* hash_state_seeded */), + uint32_t tree_addr[8], const hash_state *hash_state_seeded) { + + unsigned char stack[(PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_TREE_HEIGHT + 1)*PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_N]; + unsigned int heights[PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_TREE_HEIGHT + 1]; + + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_treehash( + root, auth_path, stack, heights, sk_seed, pub_seed, + leaf_idx, idx_offset, PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_TREE_HEIGHT, gen_leaf, tree_addr, hash_state_seeded); +} diff --git a/lib/liboqs/src/sig/sphincs/pqclean_sphincs-shake256-192f-simple_clean/utils.h b/lib/liboqs/src/sig/sphincs/pqclean_sphincs-shake256-192f-simple_clean/utils.h new file mode 100644 index 000000000..66b280a35 --- /dev/null +++ b/lib/liboqs/src/sig/sphincs/pqclean_sphincs-shake256-192f-simple_clean/utils.h @@ -0,0 +1,64 @@ +#ifndef PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_UTILS_H +#define PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_UTILS_H + +#include "hash_state.h" +#include "params.h" +#include <stddef.h> +#include <stdint.h> + +/** + * Converts the value of 'in' to 'outlen' bytes in big-endian byte order. + */ +void PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_ull_to_bytes( + unsigned char *out, size_t outlen, unsigned long long in); + +/** + * Converts the inlen bytes in 'in' from big-endian byte order to an integer. + */ +unsigned long long PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_bytes_to_ull( + const unsigned char *in, size_t inlen); + +/** + * Computes a root node given a leaf and an auth path. + * Expects address to be complete other than the tree_height and tree_index. + */ +void PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_compute_root( + unsigned char *root, const unsigned char *leaf, + uint32_t leaf_idx, uint32_t idx_offset, + const unsigned char *auth_path, uint32_t tree_height, + const unsigned char *pub_seed, uint32_t addr[8], + const hash_state *hash_state_seeded); + +/** + * For a given leaf index, computes the authentication path and the resulting + * root node using Merkle's TreeHash algorithm. + * Expects the layer and tree parts of the tree_addr to be set, as well as the + * tree type (i.e. PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_ADDR_TYPE_HASHTREE or PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_ADDR_TYPE_FORSTREE). + * Applies the offset idx_offset to indices before building addresses, so that + * it is possible to continue counting indices across trees. + */ +void PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_treehash_FORS_HEIGHT( + unsigned char *root, unsigned char *auth_path, + const unsigned char *sk_seed, const unsigned char *pub_seed, + uint32_t leaf_idx, uint32_t idx_offset, + void (*gen_leaf)( + unsigned char * /* leaf */, + const unsigned char * /* sk_seed */, + const unsigned char * /* pub_seed */, + uint32_t /* addr_idx */, const uint32_t[8] /* tree_addr */, + const hash_state * /* hash_state_seeded */), + uint32_t tree_addr[8], const hash_state *hash_state_seeded); + +void PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_treehash_TREE_HEIGHT( + unsigned char *root, unsigned char *auth_path, + const unsigned char *sk_seed, const unsigned char *pub_seed, + uint32_t leaf_idx, uint32_t idx_offset, + void (*gen_leaf)( + unsigned char * /* leaf */, + const unsigned char * /* sk_seed */, + const unsigned char * /* pub_seed */, + uint32_t /* addr_idx */, const uint32_t[8] /* tree_addr */, + const hash_state * /* hash_state_seeded */), + uint32_t tree_addr[8], const hash_state *hash_state_seeded); + +#endif diff --git a/lib/liboqs/src/sig/sphincs/pqclean_sphincs-shake256-192f-simple_clean/wots.c b/lib/liboqs/src/sig/sphincs/pqclean_sphincs-shake256-192f-simple_clean/wots.c new file mode 100644 index 000000000..40a615ea1 --- /dev/null +++ b/lib/liboqs/src/sig/sphincs/pqclean_sphincs-shake256-192f-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_SPHINCSSHAKE256192FSIMPLE_CLEAN_set_hash_addr(wots_addr, 0); + + /* Generate sk element. */ + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_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_SPHINCSSHAKE256192FSIMPLE_CLEAN_N); + + /* Iterate 'steps' calls to the hash function. */ + for (i = start; i < (start + steps) && i < PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_WOTS_W; i++) { + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_set_hash_addr(addr, i); + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_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_SPHINCSSHAKE256192FSIMPLE_CLEAN_WOTS_LOGW; + output[out] = (unsigned int)((total >> bits) & (PQCLEAN_SPHINCSSHAKE256192FSIMPLE_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_SPHINCSSHAKE256192FSIMPLE_CLEAN_WOTS_LEN2 * PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_WOTS_LOGW + 7) / 8]; + unsigned int i; + + /* Compute checksum. */ + for (i = 0; i < PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_WOTS_LEN1; i++) { + csum += PQCLEAN_SPHINCSSHAKE256192FSIMPLE_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_SPHINCSSHAKE256192FSIMPLE_CLEAN_WOTS_LEN2 * PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_WOTS_LOGW) % 8)); + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_ull_to_bytes( + csum_bytes, sizeof(csum_bytes), csum); + base_w(csum_base_w, PQCLEAN_SPHINCSSHAKE256192FSIMPLE_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_SPHINCSSHAKE256192FSIMPLE_CLEAN_WOTS_LEN1, msg); + wots_checksum(lengths + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_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_SPHINCSSHAKE256192FSIMPLE_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_SPHINCSSHAKE256192FSIMPLE_CLEAN_WOTS_LEN; i++) { + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_set_chain_addr(addr, i); + wots_gen_sk(pk + i * PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_N, sk_seed, addr, hash_state_seeded); + gen_chain(pk + i * PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_N, pk + i * PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_N, + 0, PQCLEAN_SPHINCSSHAKE256192FSIMPLE_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_SPHINCSSHAKE256192FSIMPLE_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_SPHINCSSHAKE256192FSIMPLE_CLEAN_WOTS_LEN]; + uint32_t i; + + chain_lengths(lengths, msg); + + for (i = 0; i < PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_WOTS_LEN; i++) { + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_set_chain_addr(addr, i); + wots_gen_sk(sig + i * PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_N, sk_seed, addr, hash_state_seeded); + gen_chain(sig + i * PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_N, sig + i * PQCLEAN_SPHINCSSHAKE256192FSIMPLE_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_SPHINCSSHAKE256192FSIMPLE_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_SPHINCSSHAKE256192FSIMPLE_CLEAN_WOTS_LEN]; + uint32_t i; + + chain_lengths(lengths, msg); + + for (i = 0; i < PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_WOTS_LEN; i++) { + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_set_chain_addr(addr, i); + gen_chain(pk + i * PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_N, sig + i * PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_N, + lengths[i], PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_WOTS_W - 1 - lengths[i], pub_seed, addr, + hash_state_seeded); + } +} diff --git a/lib/liboqs/src/sig/sphincs/pqclean_sphincs-shake256-192f-simple_clean/wots.h b/lib/liboqs/src/sig/sphincs/pqclean_sphincs-shake256-192f-simple_clean/wots.h new file mode 100644 index 000000000..5627cc935 --- /dev/null +++ b/lib/liboqs/src/sig/sphincs/pqclean_sphincs-shake256-192f-simple_clean/wots.h @@ -0,0 +1,41 @@ +#ifndef PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_WOTS_H +#define PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_WOTS_H + +#include "hash_state.h" +#include "params.h" +#include <stdint.h> + +/** + * WOTS key generation. Takes a 32 byte seed for the private key, expands it to + * a full WOTS private key 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_SPHINCSSHAKE256192FSIMPLE_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); + +/** + * Takes a n-byte message and the 32-byte seed for the private key to compute a + * signature that is placed at 'sig'. + */ +void PQCLEAN_SPHINCSSHAKE256192FSIMPLE_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); + +/** + * Takes a WOTS signature and an n-byte message, computes a WOTS public key. + * + * Writes the computed public key to 'pk'. + */ +void PQCLEAN_SPHINCSSHAKE256192FSIMPLE_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); + +#endif |