Perform various reformatting / renaming

This commit is contained in:
Joost Rijneveld 2017-10-23 14:10:39 +02:00
джерело 998137622a
коміт 305bd614bb
Не вдалося знайти GPG ключ що відповідає даному підпису
Ідентифікатор GPG ключа: A4FE39CF49CBC553
17 змінених файлів з 234 додано та 130 видалено

@ -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);

41
hash.c

@ -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];

2
hash.h

@ -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(&params, 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(&params, 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(&params, 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(&params, oid_sk);

18
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++) {

15
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,

24
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,

@ -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);