@@ -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); | |||
@@ -5,16 +5,14 @@ | |||
#include "fips202.h" | |||
#include <stdint.h> | |||
#include <string.h> | |||
#include <openssl/sha.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 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]; | |||
@@ -4,7 +4,7 @@ | |||
#include <stdint.h> | |||
#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, | |||
@@ -1,15 +1,18 @@ | |||
#include <stdint.h> | |||
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; | |||
} |
@@ -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); | |||
@@ -3,14 +3,14 @@ | |||
#include <stdint.h> | |||
// 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 |
@@ -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 |
@@ -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); | |||
@@ -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); | |||
@@ -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++) { | |||
@@ -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, | |||
@@ -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, | |||
@@ -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]; | |||
} | |||
@@ -4,23 +4,50 @@ | |||
#include <stdint.h> | |||
#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, | |||
@@ -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); | |||
@@ -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); | |||
@@ -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); | |||