in xmss_fast.c [551:658]
int xmss_sign(unsigned char *sk, bds_state *state, unsigned char *sig_msg, unsigned long long *sig_msg_len, const unsigned char *msg, unsigned long long msglen, const xmss_params *params)
{
unsigned int h = params->h;
unsigned int n = params->n;
unsigned int k = params->k;
uint16_t i = 0;
// Extract SK
unsigned long idx = ((unsigned long)sk[0] << 24) | ((unsigned long)sk[1] << 16) | ((unsigned long)sk[2] << 8) | sk[3];
unsigned char sk_seed[n];
memcpy(sk_seed, sk+4, n);
unsigned char sk_prf[n];
memcpy(sk_prf, sk+4+n, n);
unsigned char pub_seed[n];
memcpy(pub_seed, sk+4+2*n, n);
// index as 32 bytes string
unsigned char idx_bytes_32[32];
to_byte(idx_bytes_32, idx, 32);
unsigned char hash_key[3*n];
// Update SK
sk[0] = ((idx + 1) >> 24) & 255;
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!
// Init working params
unsigned char R[n];
unsigned char msg_h[n];
unsigned char ots_seed[n];
uint32_t ots_addr[8] = {0, 0, 0, 0, 0, 0, 0, 0};
// ---------------------------------
// Message Hashing
// ---------------------------------
// Message Hash:
// First compute pseudorandom value
prf(R, idx_bytes_32, sk_prf, n);
// Generate hash key (R || root || idx)
memcpy(hash_key, R, n);
memcpy(hash_key+n, sk+4+3*n, n);
to_byte(hash_key+2*n, idx, n);
// Then use it for message digest
h_msg(msg_h, msg, msglen, hash_key, 3*n, n);
// Start collecting signature
*sig_msg_len = 0;
// Copy index to signature
sig_msg[0] = (idx >> 24) & 255;
sig_msg[1] = (idx >> 16) & 255;
sig_msg[2] = (idx >> 8) & 255;
sig_msg[3] = idx & 255;
sig_msg += 4;
*sig_msg_len += 4;
// Copy R to signature
for (i = 0; i < n; i++)
sig_msg[i] = R[i];
sig_msg += n;
*sig_msg_len += n;
// ----------------------------------
// Now we start to "really sign"
// ----------------------------------
// Prepare Address
setType(ots_addr, 0);
setOTSADRS(ots_addr, idx);
// Compute seed for OTS key pair
get_seed(ots_seed, sk_seed, n, ots_addr);
// Compute WOTS signature
wots_sign(sig_msg, msg_h, ots_seed, &(params->wots_par), pub_seed, ots_addr);
sig_msg += params->wots_par.keysize;
*sig_msg_len += params->wots_par.keysize;
// the auth path was already computed during the previous round
memcpy(sig_msg, state->auth, h*n);
if (idx < (1U << h) - 1) {
bds_round(state, idx, sk_seed, params, pub_seed, ots_addr);
bds_treehash_update(state, (h - k) >> 1, sk_seed, params, pub_seed, ots_addr);
}
/* TODO: save key/bds state here! */
sig_msg += params->h*n;
*sig_msg_len += params->h*n;
//Whipe secret elements?
//zerobytes(tsk, CRYPTO_SECRETKEYBYTES);
memcpy(sig_msg, msg, msglen);
*sig_msg_len += msglen;
return 0;
}