Previous code allocated an array on the stack of mlen bytes, but it should be possible to also sign heap-space messages. By relying on the fact that sm and m fit the message + signature, we move the message so that 4*n bytes of prefix can be added.master
@@ -1,12 +1,13 @@ | |||
#include <stdint.h> | |||
#include <string.h> | |||
#include <openssl/sha.h> | |||
#include "hash_address.h" | |||
#include "xmss_commons.h" | |||
#include "params.h" | |||
#include "hash.h" | |||
#include "fips202.h" | |||
#include <stdint.h> | |||
#include <openssl/sha.h> | |||
void addr_to_bytes(unsigned char *bytes, const uint32_t addr[8]) | |||
{ | |||
int i; | |||
@@ -20,22 +21,13 @@ static int core_hash(const xmss_params *params, | |||
const unsigned char *key, unsigned int keylen, | |||
const unsigned char *in, unsigned long long inlen, int n) | |||
{ | |||
unsigned long long i = 0; | |||
unsigned char buf[inlen + n + keylen]; | |||
/* We arrange the input into the hash function to be of the form: | |||
* toByte(X, 32) || KEY || M | |||
*/ | |||
* toByte(X, 32) || KEY || M */ | |||
ull_to_bytes(buf, n, type); | |||
for (i=0; i < keylen; i++) { | |||
buf[i+n] = key[i]; | |||
} | |||
for (i=0; i < inlen; i++) { | |||
buf[keylen + n + i] = in[i]; | |||
} | |||
memcpy(buf + n, key, keylen); | |||
memcpy(buf + keylen + n, in, inlen); | |||
if (n == 32 && params->func == XMSS_SHA2) { | |||
SHA256(buf, inlen + keylen + n, out); | |||
@@ -70,6 +62,44 @@ int h_msg(const xmss_params *params, | |||
return core_hash(params, out, 2, key, keylen, in, inlen, params->n); | |||
} | |||
/* | |||
* Computes the message hash using R, the public root, the index of the leaf | |||
* node, and the message. Notably, it requires m_with_prefix to have 4*n bytes | |||
* of space before the message, to use for the prefix. This is necessary to | |||
* prevent having to move the message around (and thus allocate memory for it). | |||
*/ | |||
int hash_message(const xmss_params *params, unsigned char *out, | |||
const unsigned char *R, const unsigned char *root, | |||
unsigned long long idx, | |||
unsigned char *m_with_prefix, unsigned long long mlen) | |||
{ | |||
/* We're creating a hash using input of the form: | |||
toByte(X, 32) || R || root || index || M */ | |||
ull_to_bytes(m_with_prefix, params->n, 2); | |||
memcpy(m_with_prefix + params->n, R, params->n); | |||
memcpy(m_with_prefix + 2 * params->n, root, params->n); | |||
ull_to_bytes(m_with_prefix + 3 * params->n, params->n, idx); | |||
/* Since the message can be bigger than the stack, this cannot use the | |||
* core_hash function. */ | |||
if (params->n == 32 && params->func == XMSS_SHA2) { | |||
SHA256(m_with_prefix, mlen + 4*params->n, out); | |||
} | |||
else if (params->n == 32 && params->func == XMSS_SHAKE) { | |||
shake128(out, 32, m_with_prefix, mlen + 4*params->n); | |||
} | |||
else if (params->n == 64 && params->func == XMSS_SHA2) { | |||
SHA512(m_with_prefix, mlen + 4*params->n, out); | |||
} | |||
else if (params->n == 64 && params->func == XMSS_SHAKE) { | |||
shake256(out, 64, m_with_prefix, mlen + 4*params->n); | |||
} | |||
else { | |||
return 1; | |||
} | |||
return 0; | |||
} | |||
/** | |||
* We assume the left half is in in[0]...in[n-1] | |||
*/ | |||
@@ -23,4 +23,9 @@ int hash_f(const xmss_params *params, | |||
unsigned char *out, const unsigned char *in, | |||
const unsigned char *pub_seed, uint32_t addr[8]); | |||
int hash_message(const xmss_params *params, unsigned char *out, | |||
const unsigned char *R, const unsigned char *root, | |||
unsigned long long idx, | |||
unsigned char *m_with_prefix, unsigned long long mlen); | |||
#endif |
@@ -1,9 +1,11 @@ | |||
#include <stdio.h> | |||
#include <stdint.h> | |||
#include <string.h> | |||
#include <stdlib.h> | |||
#include "../xmss.h" | |||
#include "../params.h" | |||
#include "../randombytes.h" | |||
#define MLEN 32 | |||
#define SIGNATURES 16 | |||
@@ -33,12 +35,14 @@ int main() | |||
unsigned char pk[XMSS_OID_LEN + params.pk_bytes]; | |||
unsigned char sk[XMSS_OID_LEN + params.sk_bytes]; | |||
unsigned char m[MLEN]; | |||
unsigned char sm[params.sig_bytes + MLEN]; | |||
unsigned char mout[params.sig_bytes + MLEN]; | |||
unsigned char *m = malloc(MLEN); | |||
unsigned char *sm = malloc(params.sig_bytes + MLEN); | |||
unsigned char *mout = malloc(params.sig_bytes + MLEN); | |||
unsigned long long smlen; | |||
unsigned long long mlen; | |||
randombytes(m, MLEN); | |||
XMSS_KEYPAIR(pk, sk, oid); | |||
printf("Testing %d %s signatures.. \n", SIGNATURES, XMSS_VARIANT); | |||
@@ -106,5 +110,9 @@ int main() | |||
} | |||
} | |||
free(m); | |||
free(sm); | |||
free(mout); | |||
return 0; | |||
} |
@@ -1,4 +1,5 @@ | |||
#include <stdio.h> | |||
#include <stdlib.h> | |||
#include "../params.h" | |||
#include "../xmss.h" | |||
@@ -49,8 +50,8 @@ int main(int argc, char **argv) { | |||
XMSS_PARSE_OID(¶ms, oid); | |||
unsigned char pk[XMSS_OID_LEN + params.pk_bytes]; | |||
unsigned char sm[smlen]; | |||
unsigned char m[smlen]; | |||
unsigned char *sm = malloc(smlen); | |||
unsigned char *m = malloc(smlen); | |||
unsigned long long mlen; | |||
fseek(keypair_file, 0, SEEK_SET); | |||
@@ -70,5 +71,8 @@ int main(int argc, char **argv) { | |||
fclose(keypair_file); | |||
fclose(sm_file); | |||
free(m); | |||
free(sm); | |||
return ret; | |||
} |
@@ -1,4 +1,5 @@ | |||
#include <stdio.h> | |||
#include <stdlib.h> | |||
#include "../params.h" | |||
#include "../xmss.h" | |||
@@ -56,8 +57,8 @@ int main(int argc, char **argv) { | |||
XMSS_PARSE_OID(¶ms, oid_sk); | |||
unsigned char sk[XMSS_OID_LEN + params.sk_bytes]; | |||
unsigned char m[mlen]; | |||
unsigned char sm[params.sig_bytes + mlen]; | |||
unsigned char *m = malloc(mlen); | |||
unsigned char *sm = malloc(params.sig_bytes + mlen); | |||
unsigned long long smlen; | |||
/* fseek back to start of sk. */ | |||
@@ -74,4 +75,9 @@ int main(int argc, char **argv) { | |||
fclose(keypair_file); | |||
fclose(m_file); | |||
free(m); | |||
free(sm); | |||
return 0; | |||
} |
@@ -115,25 +115,6 @@ void l_tree(const xmss_params *params, | |||
memcpy(leaf, wots_pk, params->n); | |||
} | |||
/** | |||
* Computes the randomized message hash. | |||
*/ | |||
void hash_message(const xmss_params *params, unsigned char *mhash, | |||
const unsigned char *R, const unsigned char *root, | |||
unsigned long long idx, | |||
const unsigned char *m, unsigned long long mlen) | |||
{ | |||
unsigned char hash_key[3*params->n]; | |||
/* Compute hash key. */ | |||
memcpy(hash_key, R, params->n); | |||
memcpy(hash_key + params->n, root, params->n); | |||
ull_to_bytes(hash_key + 2*params->n, params->n, idx); | |||
/* Hash the message using the randomized hash key. */ | |||
h_msg(params, mhash, m, mlen, hash_key, 3*params->n); | |||
} | |||
/** | |||
* Computes a root node given a leaf and an auth path | |||
*/ | |||
@@ -228,9 +209,13 @@ int xmssmt_core_sign_open(const xmss_params *params, | |||
/* Convert the index bytes from the signature to an integer. */ | |||
idx = bytes_to_ull(sm, params->index_bytes); | |||
/* Put the message all the way at the end of the m buffer, so that we can | |||
* prepend the required other inputs for the hash function. */ | |||
memcpy(m + params->sig_bytes, sm + params->sig_bytes, *mlen); | |||
/* Compute the message hash. */ | |||
hash_message(params, mhash, sm + params->index_bytes, pk, idx, | |||
sm + params->sig_bytes, *mlen); | |||
m + params->sig_bytes - 4*params->n, *mlen); | |||
sm += params->index_bytes + params->n; | |||
/* For each subtree.. */ | |||
@@ -41,14 +41,6 @@ void l_tree(const xmss_params *params, | |||
unsigned char *leaf, unsigned char *wots_pk, | |||
const unsigned char *pub_seed, uint32_t addr[8]); | |||
/** | |||
* Computes the randomized message hash. | |||
*/ | |||
void hash_message(const xmss_params *params, unsigned char *mhash, | |||
const unsigned char *R, const unsigned char *root, | |||
unsigned long long idx, | |||
const unsigned char *m, unsigned long long mlen); | |||
/** | |||
* 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] | |||
@@ -189,10 +189,14 @@ int xmssmt_core_sign(const xmss_params *params, | |||
uint32_t ots_addr[8] = {0}; | |||
set_type(ots_addr, XMSS_ADDR_TYPE_OTS); | |||
/* Already put the message in the right place, to make it easier to prepend | |||
* things when computing the hash over the message. */ | |||
memcpy(sm + params->sig_bytes, m, mlen); | |||
*smlen = params->sig_bytes + mlen; | |||
/* Read and use the current index from the secret key. */ | |||
idx = (unsigned long)bytes_to_ull(sk, params->index_bytes); | |||
memcpy(sm, sk, params->index_bytes); | |||
sm += params->index_bytes; | |||
/************************************************************************* | |||
* THIS IS WHERE PRODUCTION IMPLEMENTATIONS WOULD UPDATE THE SECRET KEY. * | |||
@@ -202,11 +206,12 @@ int xmssmt_core_sign(const xmss_params *params, | |||
/* Compute the digest randomization value. */ | |||
ull_to_bytes(idx_bytes_32, 32, idx); | |||
prf(params, sm, idx_bytes_32, sk_prf, params->n); | |||
prf(params, sm + params->index_bytes, idx_bytes_32, sk_prf, params->n); | |||
/* Compute the message hash. */ | |||
hash_message(params, mhash, sm, pub_root, idx, m, mlen); | |||
sm += params->n; | |||
hash_message(params, mhash, sm + params->index_bytes, pub_root, idx, | |||
sm + params->sig_bytes - 4*params->n, mlen); | |||
sm += params->index_bytes + params->n; | |||
set_type(ots_addr, XMSS_ADDR_TYPE_OTS); | |||
@@ -232,8 +237,5 @@ int xmssmt_core_sign(const xmss_params *params, | |||
sm += params->tree_height*params->n; | |||
} | |||
memcpy(sm, m, mlen); | |||
*smlen = params->sig_bytes + mlen; | |||
return 0; | |||
} |
@@ -393,6 +393,8 @@ int xmss_core_sign(const xmss_params *params, | |||
unsigned char *sm, unsigned long long *smlen, | |||
const unsigned char *m, unsigned long long mlen) | |||
{ | |||
const unsigned char *pub_root = sk + params->index_bytes + 3*params->n; | |||
uint16_t i = 0; | |||
// Extract SK | |||
@@ -408,8 +410,6 @@ int xmss_core_sign(const xmss_params *params, | |||
unsigned char idx_bytes_32[32]; | |||
ull_to_bytes(idx_bytes_32, 32, idx); | |||
unsigned char hash_key[3*params->n]; | |||
// Update SK | |||
sk[0] = ((idx + 1) >> 24) & 255; | |||
sk[1] = ((idx + 1) >> 16) & 255; | |||
@@ -432,12 +432,14 @@ int xmss_core_sign(const xmss_params *params, | |||
// Message Hash: | |||
// First compute pseudorandom value | |||
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+4+3*params->n, params->n); | |||
ull_to_bytes(hash_key+2*params->n, params->n, idx); | |||
// Then use it for message digest | |||
h_msg(params, msg_h, m, mlen, hash_key, 3*params->n); | |||
/* Already put the message in the right place, to make it easier to prepend | |||
* things when computing the hash over the message. */ | |||
memcpy(sm + params->sig_bytes, m, mlen); | |||
/* Compute the message hash. */ | |||
hash_message(params, msg_h, R, pub_root, idx, | |||
sm + params->sig_bytes - 4*params->n, mlen); | |||
// Start collecting signature | |||
*smlen = 0; | |||
@@ -554,6 +556,8 @@ int xmssmt_core_sign(const xmss_params *params, | |||
unsigned char *sm, unsigned long long *smlen, | |||
const unsigned char *m, unsigned long long mlen) | |||
{ | |||
const unsigned char *pub_root = sk + params->index_bytes + 3*params->n; | |||
uint64_t idx_tree; | |||
uint32_t idx_leaf; | |||
uint64_t i, j; | |||
@@ -566,7 +570,6 @@ int xmssmt_core_sign(const xmss_params *params, | |||
// Init working params | |||
unsigned char R[params->n]; | |||
unsigned char msg_h[params->n]; | |||
unsigned char hash_key[3*params->n]; | |||
unsigned char ots_seed[params->n]; | |||
uint32_t addr[8] = {0, 0, 0, 0, 0, 0, 0, 0}; | |||
uint32_t ots_addr[8] = {0, 0, 0, 0, 0, 0, 0, 0}; | |||
@@ -599,13 +602,14 @@ int xmssmt_core_sign(const xmss_params *params, | |||
// First compute pseudorandom value | |||
ull_to_bytes(idx_bytes_32, 32, idx); | |||
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_bytes+3*params->n, params->n); | |||
ull_to_bytes(hash_key+2*params->n, params->n, idx); | |||
// Then use it for message digest | |||
h_msg(params, msg_h, m, mlen, hash_key, 3*params->n); | |||
/* Already put the message in the right place, to make it easier to prepend | |||
* things when computing the hash over the message. */ | |||
memcpy(sm + params->sig_bytes, m, mlen); | |||
/* Compute the message hash. */ | |||
hash_message(params, msg_h, R, pub_root, idx, | |||
sm + params->sig_bytes - 4*params->n, mlen); | |||
// Start collecting signature | |||
*smlen = 0; | |||