#include <stdint.h>
#include <string.h>
#include "utils.h"
#include "hash.h"
#include "wots.h"
#include "hash_address.h"
#include "params.h"
static void expand_seed(const xmss_params *params,
unsigned char *outseeds, const unsigned char *inseed,
const unsigned char *pub_seed, uint32_t addr[8],
unsigned char *buf)
{
unsigned int i;
unsigned char *prf_buf = buf + params->n + 32;
set_hash_addr(addr, 0);
set_key_and_mask(addr, 0);
memcpy(buf, pub_seed, params->n);
for (i = 0; i < params->wots_len; i++) {
set_chain_addr(addr, i);
addr_to_bytes(buf + params->n, addr);
prf_keygen(params, outseeds + i*params->n, buf, inseed, prf_buf);
}
}
static void gen_chain(const xmss_params *params,
unsigned char *out, const unsigned char *in,
unsigned int start, unsigned int steps,
const unsigned char *pub_seed, uint32_t addr[8],
unsigned char *thash_buf)
{
unsigned int i;
memcpy(out, in, params->n);
for (i = start; i < (start+steps) && i < params->wots_w; i++) {
set_hash_addr(addr, i);
thash_f(params, out, out, pub_seed, addr, thash_buf);
}
}
static void base_w(const xmss_params *params,
unsigned int *output, const unsigned int out_len, const unsigned char *input)
{
unsigned int in = 0;
unsigned int out = 0;
unsigned char total;
unsigned int bits = 0;
unsigned int consumed;
for (consumed = 0; consumed < out_len; consumed++) {
if (bits == 0) {
total = input[in];
in++;
bits += 8;
}
bits -= params->wots_log_w;
output[out] = (total >> bits) & (params->wots_w - 1);
out++;
}
}
static void wots_checksum(const xmss_params *params,
unsigned int *csum_base_w, const unsigned int *msg_base_w)
{
int csum = 0;
unsigned int csum_bytes_length = (params->wots_len2 * params->wots_log_w + 7) / 8;
unsigned char *csum_bytes = OQS_MEM_malloc(csum_bytes_length);
if (csum_bytes == NULL) {
return;
}
unsigned int i;
for (i = 0; i < params->wots_len1; i++) {
csum += params->wots_w - 1 - msg_base_w[i];
}
csum = csum << (8 - ((params->wots_len2 * params->wots_log_w) % 8));
ull_to_bytes(csum_bytes, csum_bytes_length, csum);
base_w(params, csum_base_w, params->wots_len2, csum_bytes);
OQS_MEM_insecure_free(csum_bytes);
}
static void chain_lengths(const xmss_params *params,
unsigned int *lengths, const unsigned char *msg)
{
base_w(params, lengths, params->wots_len1, msg);
wots_checksum(params, lengths + params->wots_len1, lengths);
}
void wots_pkgen(const xmss_params *params,
unsigned char *pk, const unsigned char *seed,
const unsigned char *pub_seed, uint32_t addr[8])
{
unsigned int i;
const size_t buf_size = 2 * params->padding_len + 4 * params->n + 64;
unsigned char *buf = OQS_MEM_malloc(buf_size);
if (buf == NULL) {
return;
}
expand_seed(params, pk, seed, pub_seed, addr, buf);
for (i = 0; i < params->wots_len; i++) {
set_chain_addr(addr, i);
gen_chain(params, pk + i*params->n, pk + i*params->n,
0, params->wots_w - 1, pub_seed, addr, buf);
}
OQS_MEM_secure_free(buf, buf_size);
}
void wots_sign(const xmss_params *params,
unsigned char *sig, const unsigned char *msg,
const unsigned char *seed, const unsigned char *pub_seed,
uint32_t addr[8])
{
const size_t buf_size = 2 * params->padding_len + 4 * params->n + 64;
unsigned int *lengths = OQS_MEM_calloc(params->wots_len, sizeof(unsigned int));
unsigned char *buf = OQS_MEM_malloc(buf_size);
unsigned int i;
if (lengths == NULL || buf == NULL) {
return;
}
chain_lengths(params, lengths, msg);
expand_seed(params, sig, seed, pub_seed, addr, buf);
for (i = 0; i < params->wots_len; i++) {
set_chain_addr(addr, i);
gen_chain(params, sig + i*params->n, sig + i*params->n,
0, lengths[i], pub_seed, addr, buf);
}
OQS_MEM_insecure_free(lengths);
OQS_MEM_secure_free(buf, buf_size);
}
void wots_pk_from_sig(const xmss_params *params, unsigned char *pk,
const unsigned char *sig, const unsigned char *msg,
const unsigned char *pub_seed, uint32_t addr[8])
{
unsigned int *lengths = OQS_MEM_calloc(params->wots_len, sizeof(unsigned int ));
const size_t thash_buf_len = 2 * params->padding_len + 4 * params->n + 32;
unsigned char *thash_buf = OQS_MEM_malloc(thash_buf_len);
unsigned int i;
if (lengths == NULL || thash_buf == NULL) {
return;
}
chain_lengths(params, lengths, msg);
for (i = 0; i < params->wots_len; i++) {
set_chain_addr(addr, i);
gen_chain(params, pk + i*params->n, sig + i*params->n,
lengths[i], params->wots_w - 1 - lengths[i], pub_seed, addr, thash_buf);
}
OQS_MEM_insecure_free(lengths);
OQS_MEM_insecure_free(thash_buf);
}