diff --git a/fips202.h b/fips202.h index d76083c..2f30878 100644 --- a/fips202.h +++ b/fips202.h @@ -4,9 +4,15 @@ #define SHAKE128_RATE 168 #define SHAKE256_RATE 136 +/* Evaluates SHAKE-128 on `inlen' bytes in `in', according to FIPS-202. + * Writes the first `outlen` bytes of output to `out`. + */ void shake128(unsigned char *out, unsigned long long outlen, const unsigned char *in, unsigned long long inlen); +/* Evaluates SHAKE-256 on `inlen' bytes in `in', according to FIPS-202. + * Writes the first `outlen` bytes of output to `out`. + */ void shake256(unsigned char *out, unsigned long long outlen, const unsigned char *in, unsigned long long inlen); diff --git a/hash.c b/hash.c index 54bacdc..5a1ea8e 100644 --- a/hash.c +++ b/hash.c @@ -5,16 +5,14 @@ #include "fips202.h" #include -#include #include -unsigned char* addr_to_byte(unsigned char *bytes, const uint32_t addr[8]) +void addr_to_bytes(unsigned char *bytes, const uint32_t addr[8]) { int i; for (i = 0; i < 8; i++) { - to_byte(bytes + i*4, addr[i], 4); + ull_to_bytes(bytes + i*4, addr[i], 4); } - return bytes; } static int core_hash(const xmss_params *params, @@ -25,9 +23,11 @@ static int core_hash(const xmss_params *params, unsigned long long i = 0; unsigned char buf[inlen + n + keylen]; - /* Input is of the form (toByte(X, 32) || KEY || M). */ + /* We arrange the input into the hash function to be of the form: + * toByte(X, 32) || KEY || M + */ - to_byte(buf, type, n); + ull_to_bytes(buf, type, n); for (i=0; i < keylen; i++) { buf[i+n] = key[i]; @@ -80,18 +80,23 @@ int hash_h(const xmss_params *params, unsigned char buf[2*params->n]; unsigned char key[params->n]; unsigned char bitmask[2*params->n]; - unsigned char byte_addr[32]; + unsigned char addr_as_bytes[32]; unsigned int i; + /* Generate the n-byte key. */ set_key_and_mask(addr, 0); - addr_to_byte(byte_addr, addr); - prf(params, key, byte_addr, pub_seed, params->n); + addr_to_bytes(addr_as_bytes, addr); + prf(params, key, addr_as_bytes, pub_seed, params->n); + + /* Generate the 2n-byte mask. */ set_key_and_mask(addr, 1); - addr_to_byte(byte_addr, addr); - prf(params, bitmask, byte_addr, pub_seed, params->n); + addr_to_bytes(addr_as_bytes, addr); + prf(params, bitmask, addr_as_bytes, pub_seed, params->n); + set_key_and_mask(addr, 2); - addr_to_byte(byte_addr, addr); - prf(params, bitmask+params->n, byte_addr, pub_seed, params->n); + addr_to_bytes(addr_as_bytes, addr); + prf(params, bitmask + params->n, addr_as_bytes, pub_seed, params->n); + for (i = 0; i < 2*params->n; i++) { buf[i] = in[i] ^ bitmask[i]; } @@ -105,16 +110,16 @@ int hash_f(const xmss_params *params, unsigned char buf[params->n]; unsigned char key[params->n]; unsigned char bitmask[params->n]; - unsigned char byte_addr[32]; + unsigned char addr_as_bytes[32]; unsigned int i; set_key_and_mask(addr, 0); - addr_to_byte(byte_addr, addr); - prf(params, key, byte_addr, pub_seed, params->n); + addr_to_bytes(addr_as_bytes, addr); + prf(params, key, addr_as_bytes, pub_seed, params->n); set_key_and_mask(addr, 1); - addr_to_byte(byte_addr, addr); - prf(params, bitmask, byte_addr, pub_seed, params->n); + addr_to_bytes(addr_as_bytes, addr); + prf(params, bitmask, addr_as_bytes, pub_seed, params->n); for (i = 0; i < params->n; i++) { buf[i] = in[i] ^ bitmask[i]; diff --git a/hash.h b/hash.h index 64b244c..4a23769 100644 --- a/hash.h +++ b/hash.h @@ -4,7 +4,7 @@ #include #include "params.h" -unsigned char* addr_to_byte(unsigned char *bytes, const uint32_t addr[8]); +void addr_to_bytes(unsigned char *bytes, const uint32_t addr[8]); int prf(const xmss_params *params, unsigned char *out, const unsigned char *in, diff --git a/hash_address.c b/hash_address.c index b74043e..271c41f 100644 --- a/hash_address.c +++ b/hash_address.c @@ -1,15 +1,18 @@ #include -void set_layer_addr(uint32_t addr[8], uint32_t layer) { +void set_layer_addr(uint32_t addr[8], uint32_t layer) +{ addr[0] = layer; } -void set_tree_addr(uint32_t addr[8], uint64_t tree) { +void set_tree_addr(uint32_t addr[8], uint64_t tree) +{ addr[1] = (uint32_t) (tree >> 32); addr[2] = (uint32_t) tree; } -void set_type(uint32_t addr[8], uint32_t type) { +void set_type(uint32_t addr[8], uint32_t type) +{ int i; addr[3] = type; @@ -18,36 +21,43 @@ void set_type(uint32_t addr[8], uint32_t type) { } } -void set_key_and_mask(uint32_t addr[8], uint32_t key_and_mask) { +void set_key_and_mask(uint32_t addr[8], uint32_t key_and_mask) +{ addr[7] = key_and_mask; } /* These functions are used for OTS addresses. */ -void set_ots_addr(uint32_t addr[8], uint32_t ots) { +void set_ots_addr(uint32_t addr[8], uint32_t ots) +{ addr[4] = ots; } -void set_chain_addr(uint32_t addr[8], uint32_t chain) { +void set_chain_addr(uint32_t addr[8], uint32_t chain) +{ addr[5] = chain; } -void set_hash_addr(uint32_t addr[8], uint32_t hash) { +void set_hash_addr(uint32_t addr[8], uint32_t hash) +{ addr[6] = hash; } -/* This function is used for L-trees. */ +/* This function is used for L-tree addresses. */ -void set_ltree_addr(uint32_t addr[8], uint32_t ltree) { +void set_ltree_addr(uint32_t addr[8], uint32_t ltree) +{ addr[4] = ltree; } /* These functions are used for hash tree addresses. */ -void set_tree_height(uint32_t addr[8], uint32_t treeHeight) { +void set_tree_height(uint32_t addr[8], uint32_t treeHeight) +{ addr[5] = treeHeight; } -void set_tree_index(uint32_t addr[8], uint32_t treeIndex) { +void set_tree_index(uint32_t addr[8], uint32_t treeIndex) +{ addr[6] = treeIndex; } diff --git a/hash_address.h b/hash_address.h index 776b070..c9097c4 100644 --- a/hash_address.h +++ b/hash_address.h @@ -19,7 +19,7 @@ void set_chain_addr(uint32_t addr[8], uint32_t chain); void set_hash_addr(uint32_t addr[8], uint32_t hash); -/* This function is used for L-trees. */ +/* This function is used for L-tree addresses. */ void set_ltree_addr(uint32_t addr[8], uint32_t ltree); diff --git a/params.h b/params.h index bafa79e..002e957 100644 --- a/params.h +++ b/params.h @@ -3,14 +3,14 @@ #include -// These are merely internal identifiers for the supported hash functions +/* These are merely internal identifiers for the supported hash functions. */ #define XMSS_SHA2 0 #define XMSS_SHAKE 1 -// This is a consequence of the OID definitions in the draft, used for parsing +/* This is a result of the OID definitions in the draft; needed for parsing. */ #define XMSS_OID_LEN 4 -// This structure will be populated when calling xmss[mt]_parse_oid +/* This structure will be populated when calling xmss[mt]_parse_oid. */ typedef struct { unsigned int func; unsigned int n; @@ -30,10 +30,30 @@ typedef struct { unsigned int bds_k; } xmss_params; +/** + * Accepts strings such as "XMSS-SHA2_10_256" + * and outputs OIDs such as 0x01000001. + * Returns 1 when the parameter set is not found, 0 otherwise + */ int xmss_str_to_oid(uint32_t *oid, const char* s); + +/** + * Accepts takes strings such as "XMSSMT-SHA2_20/2_256" + * and outputs OIDs such as 0x01000001. + * Returns 1 when the parameter set is not found, 0 otherwise + */ int xmssmt_str_to_oid(uint32_t *oid, const char* s); +/** + * Accepts OIDs such as 0x01000001, and configures params accordingly. + * Returns 1 when the OID is not found, 0 otherwise. + */ int xmss_parse_oid(xmss_params *params, const uint32_t oid); + +/** + * Accepts OIDs such as 0x01000001, and configures params accordingly. + * Returns 1 when the OID is not found, 0 otherwise. + */ int xmssmt_parse_oid(xmss_params *params, const uint32_t oid); #endif diff --git a/randombytes.h b/randombytes.h index 65cf221..8e096a9 100644 --- a/randombytes.h +++ b/randombytes.h @@ -1,6 +1,9 @@ #ifndef XMSS_RANDOMBYTES_H #define XMSS_RANDOMBYTES_H -extern void randombytes(unsigned char * x,unsigned long long xlen); +/** + * Tries to read xlen bytes from a source of randomness, and writes them to x. + */ +void randombytes(unsigned char *x, unsigned long long xlen); #endif diff --git a/test/xmss_sign.c b/test/xmss_sign.c index f9e10bf..e2e75eb 100644 --- a/test/xmss_sign.c +++ b/test/xmss_sign.c @@ -24,13 +24,13 @@ int main(int argc, char **argv) { return -1; } - // Read the OID from the public key, as we need its length to seek past it + /* Read the OID from the public key, as we need its length to seek past it */ fread(&oid_pk, 1, XMSS_OID_LEN, keypair); xmss_parse_oid(¶ms, oid_pk); - // fseek past the public key + /* fseek past the public key */ fseek(keypair, params.publickey_bytes, SEEK_CUR); - // This is the OID we're actually going to use. Likely the same, but still. + /* This is the OID we're actually going to use. Likely the same, but still. */ fread(&oid_sk, 1, XMSS_OID_LEN, keypair); xmss_parse_oid(¶ms, oid_sk); diff --git a/test/xmssmt_sign.c b/test/xmssmt_sign.c index a136430..790663f 100644 --- a/test/xmssmt_sign.c +++ b/test/xmssmt_sign.c @@ -24,13 +24,13 @@ int main(int argc, char **argv) { return -1; } - // Read the OID from the public key, as we need its length to seek past it + /* Read the OID from the public key, as we need its length to seek past it. */ fread(&oid_pk, 1, XMSS_OID_LEN, keypair); xmssmt_parse_oid(¶ms, oid_pk); - // fseek past the public key + /* fseek past the public key. */ fseek(keypair, params.publickey_bytes, SEEK_CUR); - // This is the OID we're actually going to use. Likely the same, but still. + /* This is the OID we're actually going to use. Likely the same, but still.. */ fread(&oid_sk, 1, XMSS_OID_LEN, keypair); xmssmt_parse_oid(¶ms, oid_sk); diff --git a/wots.c b/wots.c index 47d2571..54ca088 100644 --- a/wots.c +++ b/wots.c @@ -6,9 +6,8 @@ #include "params.h" /** - * Helper method for pseudorandom key generation - * Expands an n-byte array into a len*n byte array - * this is done using PRF + * Helper method for pseudorandom key generation. + * Expands an n-byte array into a len*n byte array using the `prf` function. */ static void expand_seed(const xmss_params *params, unsigned char *outseeds, const unsigned char *inseed) @@ -17,17 +16,17 @@ static void expand_seed(const xmss_params *params, unsigned char ctr[32]; for (i = 0; i < params->wots_len; i++) { - to_byte(ctr, i, 32); + ull_to_bytes(ctr, i, 32); prf(params, outseeds + i*params->n, ctr, inseed, params->n); } } /** * Computes the chaining function. - * out and in have to be n-byte arrays + * out and in have to be n-byte arrays. * - * interpretes in as start-th value of the chain - * addr has to contain the address of the chain + * Interprets in as start-th value of the chain. + * addr has to contain the address of the chain. */ static void gen_chain(const xmss_params *params, unsigned char *out, const unsigned char *in, @@ -48,6 +47,7 @@ static void gen_chain(const xmss_params *params, /** * base_w algorithm as described in draft. + * Interprets an array of bytes as integers in base w. */ static void base_w(const xmss_params *params, int *output, const int out_len, const unsigned char *input) @@ -104,7 +104,7 @@ void wots_sign(const xmss_params *params, csum = csum << (8 - ((params->wots_len2 * params->wots_log_w) % 8)); - to_byte(csum_bytes, csum, ((params->wots_len2 * params->wots_log_w) + 7) / 8); + ull_to_bytes(csum_bytes, csum, ((params->wots_len2 * params->wots_log_w) + 7) / 8); base_w(params, csum_basew, params->wots_len2, csum_bytes); for (i = 0; i < params->wots_len2; i++) { @@ -138,7 +138,7 @@ void wots_pk_from_sig(const xmss_params *params, unsigned char *pk, csum = csum << (8 - ((params->wots_len2 * params->wots_log_w) % 8)); - to_byte(csum_bytes, csum, ((params->wots_len2 * params->wots_log_w) + 7) / 8); + ull_to_bytes(csum_bytes, csum, ((params->wots_len2 * params->wots_log_w) + 7) / 8); base_w(params, csum_basew, params->wots_len2, csum_bytes); for (i = 0; i < params->wots_len2; i++) { diff --git a/wots.h b/wots.h index d1b4266..61f0b8b 100644 --- a/wots.h +++ b/wots.h @@ -5,17 +5,20 @@ #include "params.h" /** - * WOTS key generation. Takes a 32byte seed for the secret key, expands it to a full WOTS secret key and computes the corresponding public key. - * For this it takes the seed pub_seed which is used to generate bitmasks and hash keys and the address of this WOTS key pair addr + * WOTS key generation. Takes a 32 byte seed for the secret key, expands it to + * a full WOTS secret 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. * - * Places the computed public key at address pk. + * Writes the computed public key to 'pk'. */ void wots_pkgen(const xmss_params *params, unsigned char *pk, const unsigned char *sk, const unsigned char *pub_seed, uint32_t addr[8]); /** - * Takes a m-byte message and the 32-byte seed for the secret key to compute a signature that is placed at "sig". + * Takes a m-byte message and the 32-byte seed for the secret key to compute a + * signature that is placed at 'sig'. */ void wots_sign(const xmss_params *params, unsigned char *sig, const unsigned char *msg, @@ -23,7 +26,9 @@ void wots_sign(const xmss_params *params, uint32_t addr[8]); /** - * Takes a WOTS signature, a m-byte message and computes a WOTS public key that it places at pk. + * Takes a WOTS signature and an m-byte message, computes a WOTS public key. + * + * Writes the computed public key to 'pk'. */ void wots_pk_from_sig(const xmss_params *params, unsigned char *pk, const unsigned char *sig, const unsigned char *msg, diff --git a/xmss.h b/xmss.h index 09c1ef8..c7b4b69 100644 --- a/xmss.h +++ b/xmss.h @@ -5,13 +5,13 @@ /** * Generates a XMSS key pair for a given parameter set. - * Format sk: [oid || (32bit) idx || SK_SEED || SK_PRF || PUB_SEED || root] - * Format pk: [oid || root || PUB_SEED] + * Format sk: [OID || (32bit) idx || SK_SEED || SK_PRF || PUB_SEED || root] + * Format pk: [OID || root || PUB_SEED] */ int xmss_keypair(unsigned char *pk, unsigned char *sk, const uint32_t oid); /** - * Signs a message. + * Signs a message using an XMSS secret key. * Returns * 1. an array containing the signature followed by the message AND * 2. an updated secret key! @@ -21,9 +21,11 @@ int xmss_sign(unsigned char *sk, const unsigned char *m, unsigned long long mlen); /** - * Verifies a given message signature pair under a given public key. + * Verifies a given message signature pair using a given public key. * - * Note: msg and msglen are pure outputs which carry the message in case verification succeeds. The (input) message is assumed to be within sig_msg which has the form (sig||msg). + * Note: m and mlen are pure outputs which carry the message in case + * verification succeeds. The (input) message is assumed to be contained in sm + * which has the form [signature || message]. */ int xmss_sign_open(unsigned char *m, unsigned long long *mlen, const unsigned char *sm, unsigned long long smlen, @@ -31,13 +33,13 @@ int xmss_sign_open(unsigned char *m, unsigned long long *mlen, /* * Generates a XMSSMT key pair for a given parameter set. - * Format sk: [oid || (ceil(h/8) bit) idx || SK_SEED || SK_PRF || PUB_SEED || root] - * Format pk: [oid || root || PUB_SEED] + * Format sk: [OID || (ceil(h/8) bit) idx || SK_SEED || SK_PRF || PUB_SEED || root] + * Format pk: [OID || root || PUB_SEED] */ int xmssmt_keypair(unsigned char *pk, unsigned char *sk, const uint32_t oid); /** - * Signs a message. + * Signs a message using an XMSSMT secret key. * Returns * 1. an array containing the signature followed by the message AND * 2. an updated secret key! @@ -47,7 +49,11 @@ int xmssmt_sign(unsigned char *sk, const unsigned char *m, unsigned long long mlen); /** - * Verifies a given message signature pair under a given public key. + * Verifies a given message signature pair using a given public key. + * + * Note: m and mlen are pure outputs which carry the message in case + * verification succeeds. The (input) message is assumed to be contained in sm + * which has the form [signature || message]. */ int xmssmt_sign_open(unsigned char *m, unsigned long long *mlen, const unsigned char *sm, unsigned long long smlen, diff --git a/xmss_commons.c b/xmss_commons.c index 5febacb..c19bdd4 100644 --- a/xmss_commons.c +++ b/xmss_commons.c @@ -8,18 +8,23 @@ #include "wots.h" #include "xmss_commons.h" -void to_byte(unsigned char *out, unsigned long long in, uint32_t bytes) +/** + * Converts the value of 'in' to 'len' bytes in big-endian byte order. + */ +void ull_to_bytes(unsigned char *out, unsigned long long in, uint32_t len) { int i; - for (i = bytes-1; i >= 0; i--) { + for (i = len - 1; i >= 0; i--) { out[i] = in & 0xff; in = in >> 8; } } /** - * Computes the leaf at a given address. First generates the WOTS key pair, then computes leaf using l_tree. As this happens position independent, we only require that addr encodes the right ltree-address. + * Computes the leaf at a given address. First generates the WOTS key pair, + * then computes leaf using l_tree. As this happens position independent, we + * only require that addr encodes the right ltree-address. */ void gen_leaf_wots(const xmss_params *params, unsigned char *leaf, const unsigned char *sk_seed, const unsigned char *pub_seed, @@ -35,44 +40,50 @@ void gen_leaf_wots(const xmss_params *params, unsigned char *leaf, } /** - * Used for pseudorandom keygeneration, - * generates the seed for the WOTS keypair at address addr + * Used for pseudo-random key generation. + * Generates the seed for the WOTS key pair at address 'addr'. * - * takes params->n byte sk_seed and returns params->n byte seed using 32 byte address addr. + * Takes n-byte sk_seed and returns n-byte seed using 32 byte address 'addr'. */ void get_seed(const xmss_params *params, unsigned char *seed, const unsigned char *sk_seed, uint32_t addr[8]) { unsigned char bytes[32]; - // Make sure that chain addr, hash addr, and key bit are 0! + /* Make sure that chain addr, hash addr, and key bit are zeroed. */ set_chain_addr(addr, 0); set_hash_addr(addr, 0); set_key_and_mask(addr, 0); - // Generate pseudorandom value - addr_to_byte(bytes, addr); + + /* Generate seed. */ + addr_to_bytes(bytes, addr); prf(params, seed, bytes, sk_seed, params->n); } /** - * Computes a leaf from a WOTS public key using an L-tree. + * Computes a leaf node from a WOTS public key using an L-tree. + * Note that this destroys the used WOTS public key. */ -void l_tree(const xmss_params *params, unsigned char *leaf, unsigned char *wots_pk, +void l_tree(const xmss_params *params, + unsigned char *leaf, unsigned char *wots_pk, const unsigned char *pub_seed, uint32_t addr[8]) { unsigned int l = params->wots_len; - uint32_t i = 0; + unsigned int parent_nodes; + uint32_t i; uint32_t height = 0; - uint32_t bound; set_tree_height(addr, height); while (l > 1) { - bound = l >> 1; - for (i = 0; i < bound; i++) { + parent_nodes = l >> 1; + for (i = 0; i < parent_nodes; i++) { set_tree_index(addr, i); - hash_h(params, wots_pk + i*params->n, wots_pk + i*2*params->n, pub_seed, addr); + /* Hashes the nodes at (i*2)*params->n and (i*2)*params->n + 1 */ + hash_h(params, wots_pk + i*params->n, wots_pk + (i*2)*params->n, pub_seed, addr); } + /* If the row contained an odd number of nodes, the last node was not hashed. + Instead, we pull it up to the next layer. */ if (l & 1) { memcpy(wots_pk + (l >> 1)*params->n, wots_pk + (l - 1)*params->n, params->n); l = (l >> 1) + 1; @@ -87,7 +98,7 @@ void l_tree(const xmss_params *params, unsigned char *leaf, unsigned char *wots_ } /** - * Computes a root node given a leaf and an authapth + * Computes a root node given a leaf and an auth path */ static void validate_authpath(const xmss_params *params, unsigned char *root, const unsigned char *leaf, unsigned long leafidx, @@ -97,8 +108,8 @@ static void validate_authpath(const xmss_params *params, unsigned char *root, uint32_t i, j; unsigned char buffer[2*params->n]; - // If leafidx is odd (last bit = 1), current path element is a right child and authpath has to go to the left. - // Otherwise, it is the other way around + /* If leafidx is odd (last bit = 1), current path element is a right child + and authpath has to go left. Otherwise it is the other way around. */ if (leafidx & 1) { for (j = 0; j < params->n; j++) { buffer[params->n + j] = leaf[j]; @@ -117,6 +128,7 @@ static void validate_authpath(const xmss_params *params, unsigned char *root, set_tree_height(addr, i); leafidx >>= 1; set_tree_index(addr, leafidx); + /* Pick the right or left neighbor, depending on parity of the node. */ if (leafidx & 1) { hash_h(params, buffer + params->n, buffer, pub_seed, addr); for (j = 0; j < params->n; j++) { @@ -139,6 +151,7 @@ static void validate_authpath(const xmss_params *params, unsigned char *root, /** * Verifies a given message signature pair under a given public key. + * Note that this assumes a pk without an OID, i.e. [root || PUB_SEED] */ int xmss_core_sign_open(const xmss_params *params, unsigned char *m, unsigned long long *mlen, @@ -156,7 +169,6 @@ int xmss_core_sign_open(const xmss_params *params, unsigned char pub_seed[params->n]; memcpy(pub_seed, pk + params->n, params->n); - // Init addresses uint32_t ots_addr[8] = {0}; uint32_t ltree_addr[8] = {0}; uint32_t node_addr[8] = {0}; @@ -167,34 +179,34 @@ int xmss_core_sign_open(const xmss_params *params, *mlen = smlen - params->bytes; - // Extract index + /* Convert the index bytes from the signature to an integer. */ for (i = 0; i < params->index_len; i++) { idx |= ((unsigned long long)sm[i]) << (8*(params->index_len - 1 - i)); } - // Generate hash key (R || root || idx) + /* Prepare the hash key, of the form [R || root || idx]. */ memcpy(hash_key, sm + params->index_len, params->n); memcpy(hash_key + params->n, pk, params->n); - to_byte(hash_key + 2*params->n, idx, params->n); + ull_to_bytes(hash_key + 2*params->n, idx, params->n); - // hash message + /* Compute the message hash. */ h_msg(params, msg_h, sm + params->bytes, *mlen, hash_key, 3*params->n); sm += params->index_len + params->n; - // Prepare Address + /* The WOTS public key is only correct if the signature was correct. */ set_ots_addr(ots_addr, idx); - // Check WOTS signature wots_pk_from_sig(params, wots_pk, sm, msg_h, pub_seed, ots_addr); sm += params->wots_keysize; - // Compute Ltree + /* Compute the leaf node using the WOTS public key. */ set_ltree_addr(ltree_addr, idx); l_tree(params, pkhash, wots_pk, pub_seed, ltree_addr); - // Compute root + /* Compute the root node. */ validate_authpath(params, root, pkhash, idx, sm, pub_seed, node_addr); sm += params->tree_height*params->n; + /* Check if the root node equals the root node in the public key. */ for (i = 0; i < params->n; i++) { if (root[i] != pk[i]) { for (i = 0; i < *mlen; i++) { @@ -205,6 +217,7 @@ int xmss_core_sign_open(const xmss_params *params, } } + /* If verification was successful, copy the message from the signature. */ for (i = 0; i < *mlen; i++) { m[i] = sm[i]; } @@ -214,6 +227,7 @@ int xmss_core_sign_open(const xmss_params *params, /** * Verifies a given message signature pair under a given public key. + * Note that this assumes a pk without an OID, i.e. [root || PUB_SEED] */ int xmssmt_core_sign_open(const xmss_params *params, unsigned char *m, unsigned long long *mlen, @@ -230,7 +244,6 @@ int xmssmt_core_sign_open(const xmss_params *params, unsigned char hash_key[3*params->n]; const unsigned char *pub_seed = pk + params->n; - // Init addresses uint32_t ots_addr[8] = {0}; uint32_t ltree_addr[8] = {0}; uint32_t node_addr[8] = {0}; @@ -241,22 +254,22 @@ int xmssmt_core_sign_open(const xmss_params *params, *mlen = smlen - params->bytes; - // Extract index + /* Convert the index bytes from the signature to an integer. */ for (i = 0; i < params->index_len; i++) { idx |= ((unsigned long long)sm[i]) << (8*(params->index_len - 1 - i)); } - // Generate hash key (R || root || idx) + /* Prepare the hash key, of the form [R || root || idx]. */ memcpy(hash_key, sm + params->index_len, params->n); memcpy(hash_key + params->n, pk, params->n); - to_byte(hash_key + 2*params->n, idx, params->n); + ull_to_bytes(hash_key + 2*params->n, idx, params->n); - // hash message + /* Compute the message hash. */ h_msg(params, msg_h, sm + params->bytes, *mlen, hash_key, 3*params->n); sm += params->index_len + params->n; + /* For each subtree.. */ for (i = 0; i < params->d; i++) { - // Prepare Address idx_leaf = (idx & ((1 << params->tree_height)-1)); idx = idx >> params->tree_height; @@ -268,21 +281,23 @@ int xmssmt_core_sign_open(const xmss_params *params, set_tree_addr(ots_addr, idx); set_tree_addr(node_addr, idx); + /* The WOTS public key is only correct if the signature was correct. */ set_ots_addr(ots_addr, idx_leaf); - - // Check WOTS signature + /* Initially, root = msg_h, but on subsequent iterations it is the root + of the subtree below the currently processed subtree. */ wots_pk_from_sig(params, wots_pk, sm, root, pub_seed, ots_addr); sm += params->wots_keysize; - // Compute Ltree + /* Compute the leaf node using the WOTS public key. */ set_ltree_addr(ltree_addr, idx_leaf); l_tree(params, pkhash, wots_pk, pub_seed, ltree_addr); - // Compute root + /* Compute the root node of this subtree. */ validate_authpath(params, root, pkhash, idx_leaf, sm, pub_seed, node_addr); sm += params->tree_height*params->n; } + /* Check if the final root node equals the root node in the public key. */ for (i = 0; i < params->n; i++) { if (root[i] != pk[i]) { for (i = 0; i < *mlen; i++) { @@ -293,6 +308,7 @@ int xmssmt_core_sign_open(const xmss_params *params, } } + /* If verification was successful, copy the message from the signature. */ for (i = 0; i < *mlen; i++) { m[i] = sm[i]; } diff --git a/xmss_commons.h b/xmss_commons.h index 3757d2e..c2fbcf1 100644 --- a/xmss_commons.h +++ b/xmss_commons.h @@ -4,23 +4,50 @@ #include #include "params.h" -void to_byte(unsigned char *output, unsigned long long in, uint32_t bytes); +/** + * Converts the value of 'in' to 'len' bytes in big-endian byte order. + */ +void ull_to_bytes(unsigned char *output, unsigned long long in, uint32_t bytes); +/** + * Computes the leaf at a given address. First generates the WOTS key pair, + * then computes leaf using l_tree. As this happens position independent, we + * only require that addr encodes the right ltree-address. + */ void gen_leaf_wots(const xmss_params *params, unsigned char *leaf, const unsigned char *sk_seed, const unsigned char *pub_seed, uint32_t ltree_addr[8], uint32_t ots_addr[8]); +/** + * Used for pseudo-random key generation. + * Generates the seed for the WOTS key pair at address 'addr'. + * + * Takes n-byte sk_seed and returns n-byte seed using 32 byte address 'addr'. + */ void get_seed(const xmss_params *params, unsigned char *seed, const unsigned char *sk_seed, uint32_t addr[8]); -void l_tree(const xmss_params *params, unsigned char *leaf, unsigned char *wots_pk, +/** + * Computes a leaf node from a WOTS public key using an L-tree. + * Note that the WOTS public key is destroyed. + */ +void l_tree(const xmss_params *params, + unsigned char *leaf, unsigned char *wots_pk, const unsigned char *pub_seed, uint32_t addr[8]); +/** + * Verifies a given message signature pair under a given public key. + * Note that this assumes a pk without an OID, i.e. [root || PUB_SEED] + */ int xmss_core_sign_open(const xmss_params *params, unsigned char *m, unsigned long long *mlen, const unsigned char *sm, unsigned long long smlen, const unsigned char *pk); +/** + * Verifies a given message signature pair under a given public key. + * Note that this assumes a pk without an OID, i.e. [root || PUB_SEED] + */ int xmssmt_core_sign_open(const xmss_params *params, unsigned char *m, unsigned long long *mlen, const unsigned char *sm, unsigned long long smlen, diff --git a/xmss_core.c b/xmss_core.c index 31472ba..c806133 100644 --- a/xmss_core.c +++ b/xmss_core.c @@ -11,14 +11,14 @@ #include "xmss_core.h" /** - * Merkle's TreeHash algorithm. The address only needs to initialize the first 78 bits of addr. Everything else will be set by treehash. + * Merkle's TreeHash algorithm. The address only needs to initialize the first + * 78 bits of addr. Everything else will be set by treehash. * Currently only used for key generation. - * */ static void treehash(const xmss_params *params, unsigned char *node, uint32_t index, const unsigned char *sk_seed, const unsigned char *pub_seed, const uint32_t addr[8]) { uint32_t idx = index; - // use three different addresses because at this point we use all three formats in parallel + // Use three different addresses because at this point we use all three formats in parallel uint32_t ots_addr[8]; uint32_t ltree_addr[8]; uint32_t node_addr[8]; @@ -58,9 +58,12 @@ static void treehash(const xmss_params *params, unsigned char *node, uint32_t in } /** - * Computes the authpath and the root. This method is using a lot of space as we build the whole tree and then select the authpath nodes. - * For more efficient algorithms see e.g. the chapter on hash-based signatures in Bernstein, Buchmann, Dahmen. "Post-quantum Cryptography", Springer 2009. - * It returns the authpath in "authpath" with the node on level 0 at index 0. + * Computes the authpath and the root. This method is using a lot of space as we + * build the whole tree and then select the authpath nodes. For more efficient + * algorithms see e.g. the chapter on hash-based signatures in Bernstein, + * Buchmann, Dahmen. "Post-quantum Cryptography", Springer 2009. + * + * Returns the authpath in "authpath" with the node on level 0 at index 0. */ static void compute_authpath_wots(const xmss_params *params, unsigned char *root, unsigned char *authpath, unsigned long leaf_idx, const unsigned char *sk_seed, unsigned char *pub_seed, uint32_t addr[8]) { @@ -155,7 +158,7 @@ int xmss_core_sign(const xmss_params *params, unsigned char *sk, unsigned char * // index as 32 bytes string unsigned char idx_bytes_32[32]; - to_byte(idx_bytes_32, idx, 32); + ull_to_bytes(idx_bytes_32, idx, 32); memcpy(sk_seed, sk+4, params->n); memcpy(sk_prf, sk+4+params->n, params->n); @@ -166,8 +169,9 @@ int xmss_core_sign(const xmss_params *params, unsigned char *sk, unsigned char * sk[1] = ((idx + 1) >> 16) & 255; sk[2] = ((idx + 1) >> 8) & 255; sk[3] = (idx + 1) & 255; - // -- Secret key for this non-forward-secure version is now updated. - // -- A productive implementation should use a file handle instead and write the updated secret key at this point! + // Secret key for this non-forward-secure version is now updated. + // A production implementation should consider using a file handle instead, + // and write the updated secret key at this point! // Init working params unsigned char R[params->n]; @@ -186,7 +190,7 @@ int xmss_core_sign(const xmss_params *params, unsigned char *sk, unsigned char * // Generate hash key (R || root || idx) memcpy(hash_key, R, params->n); memcpy(hash_key+params->n, sk+4+3*params->n, params->n); - to_byte(hash_key+2*params->n, idx, params->n); + ull_to_bytes(hash_key+2*params->n, idx, params->n); // Then use it for message digest h_msg(params, msg_h, m, mlen, hash_key, 3*params->n); @@ -302,9 +306,9 @@ int xmssmt_core_sign(const xmss_params *params, unsigned char *sk, unsigned char for (i = 0; i < params->index_len; i++) { sk[i] = ((idx + 1) >> 8*(params->index_len - 1 - i)) & 255; } - // -- Secret key for this non-forward-secure version is now updated. - // -- A productive implementation should use a file handle instead and write the updated secret key at this point! - + // Secret key for this non-forward-secure version is now updated. + // A production implementation should consider using a file handle instead, + // and write the updated secret key at this point! // --------------------------------- // Message Hashing @@ -312,12 +316,12 @@ int xmssmt_core_sign(const xmss_params *params, unsigned char *sk, unsigned char // Message Hash: // First compute pseudorandom value - to_byte(idx_bytes_32, idx, 32); + ull_to_bytes(idx_bytes_32, idx, 32); prf(params, R, idx_bytes_32, sk_prf, params->n); // Generate hash key (R || root || idx) memcpy(hash_key, R, params->n); memcpy(hash_key+params->n, sk+params->index_len+3*params->n, params->n); - to_byte(hash_key+2*params->n, idx, params->n); + ull_to_bytes(hash_key+2*params->n, idx, params->n); // Then use it for message digest h_msg(params, msg_h, m, mlen, hash_key, 3*params->n); diff --git a/xmss_core.h b/xmss_core.h index 83c8297..3308cae 100644 --- a/xmss_core.h +++ b/xmss_core.h @@ -14,13 +14,14 @@ int xmss_core_keypair(const xmss_params *params, unsigned char *pk, unsigned cha * Returns * 1. an array containing the signature followed by the message AND * 2. an updated secret key! - * */ int xmss_core_sign(const xmss_params *params, unsigned char *sk, unsigned char *sig_msg, unsigned long long *sig_msg_len, const unsigned char *msg, unsigned long long msglen); /** * Verifies a given message signature pair under a given public key. * - * Note: msg and msglen are pure outputs which carry the message in case verification succeeds. The (input) message is assumed to be within sig_msg which has the form (sig||msg). + * Note: msg and msglen are pure outputs which carry the message in case + * verification succeeds. The (input) message is assumed to be within sig_msg + * which has the form (sig||msg). */ int xmss_core_sign_open(const xmss_params *params, unsigned char *msg, unsigned long long *msglen, const unsigned char *sig_msg, unsigned long long sig_msg_len, const unsigned char *pk); diff --git a/xmss_core_fast.c b/xmss_core_fast.c index 3d0c634..2262685 100644 --- a/xmss_core_fast.c +++ b/xmss_core_fast.c @@ -396,7 +396,7 @@ int xmss_core_sign(const xmss_params *params, // index as 32 bytes string unsigned char idx_bytes_32[32]; - to_byte(idx_bytes_32, idx, 32); + ull_to_bytes(idx_bytes_32, idx, 32); unsigned char hash_key[3*params->n]; @@ -405,8 +405,9 @@ int xmss_core_sign(const xmss_params *params, sk[1] = ((idx + 1) >> 16) & 255; sk[2] = ((idx + 1) >> 8) & 255; sk[3] = (idx + 1) & 255; - // -- Secret key for this non-forward-secure version is now updated. - // -- A productive implementation should use a file handle instead and write the updated secret key at this point! + // Secret key for this non-forward-secure version is now updated. + // A production implementation should consider using a file handle instead, + // and write the updated secret key at this point! // Init working params unsigned char R[params->n]; @@ -424,7 +425,7 @@ int xmss_core_sign(const xmss_params *params, // Generate hash key (R || root || idx) memcpy(hash_key, R, params->n); memcpy(hash_key+params->n, sk+4+3*params->n, params->n); - to_byte(hash_key+2*params->n, idx, params->n); + ull_to_bytes(hash_key+2*params->n, idx, params->n); // Then use it for message digest h_msg(params, msg_h, m, mlen, hash_key, 3*params->n); @@ -566,9 +567,9 @@ int xmssmt_core_sign(const xmss_params *params, for (i = 0; i < params->index_len; i++) { sk[i] = ((idx + 1) >> 8*(params->index_len - 1 - i)) & 255; } - // -- Secret key for this non-forward-secure version is now updated. - // -- A productive implementation should use a file handle instead and write the updated secret key at this point! - + // Secret key for this non-forward-secure version is now updated. + // A production implementation should consider using a file handle instead, + // and write the updated secret key at this point! // --------------------------------- // Message Hashing @@ -576,12 +577,12 @@ int xmssmt_core_sign(const xmss_params *params, // Message Hash: // First compute pseudorandom value - to_byte(idx_bytes_32, idx, 32); + ull_to_bytes(idx_bytes_32, idx, 32); prf(params, R, idx_bytes_32, sk_prf, params->n); // Generate hash key (R || root || idx) memcpy(hash_key, R, params->n); memcpy(hash_key+params->n, sk+params->index_len+3*params->n, params->n); - to_byte(hash_key+2*params->n, idx, params->n); + ull_to_bytes(hash_key+2*params->n, idx, params->n); // Then use it for message digest h_msg(params, msg_h, m, mlen, hash_key, 3*params->n);