#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include "hash.h"
#include "hash_address.h"
#include "params.h"
#include "wots.h"
#include "utils.h"
#include "xmss_commons.h"
static void l_tree(const xmss_params *params,
unsigned char *leaf, unsigned char *wots_pk,
const unsigned char *pub_seed, uint32_t addr[8],
unsigned char *thash_buf)
{
unsigned int l = params->wots_len;
unsigned int parent_nodes;
uint32_t i;
uint32_t height = 0;
set_tree_height(addr, height);
while (l > 1) {
parent_nodes = l >> 1;
for (i = 0; i < parent_nodes; i++) {
set_tree_index(addr, i);
thash_h(params, wots_pk + i*params->n,
wots_pk + (i*2)*params->n, pub_seed, addr, thash_buf);
}
if (l & 1) {
memcpy(wots_pk + (l >> 1)*params->n,
wots_pk + (l - 1)*params->n, params->n);
l = (l >> 1) + 1;
}
else {
l = l >> 1;
}
height++;
set_tree_height(addr, height);
}
memcpy(leaf, wots_pk, params->n);
}
static void compute_root(const xmss_params *params, unsigned char *root,
const unsigned char *leaf, unsigned long leafidx,
const unsigned char *auth_path,
const unsigned char *pub_seed, uint32_t addr[8],
unsigned char *buffer,
unsigned char *thash_buf)
{
uint32_t i;
if (leafidx & 1) {
memcpy(buffer + params->n, leaf, params->n);
memcpy(buffer, auth_path, params->n);
}
else {
memcpy(buffer, leaf, params->n);
memcpy(buffer + params->n, auth_path, params->n);
}
auth_path += params->n;
for (i = 0; i < params->tree_height - 1; i++) {
set_tree_height(addr, i);
leafidx >>= 1;
set_tree_index(addr, leafidx);
if (leafidx & 1) {
thash_h(params, buffer + params->n, buffer, pub_seed, addr, thash_buf);
memcpy(buffer, auth_path, params->n);
}
else {
thash_h(params, buffer, buffer, pub_seed, addr, thash_buf);
memcpy(buffer + params->n, auth_path, params->n);
}
auth_path += params->n;
}
set_tree_height(addr, params->tree_height - 1);
leafidx >>= 1;
set_tree_index(addr, leafidx);
thash_h(params, root, buffer, pub_seed, addr, thash_buf);
}
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])
{
unsigned char *pk = OQS_MEM_malloc(params->wots_sig_bytes + 2 * params->padding_len + 6 * params->n + 32);
if (pk == NULL) {
return;
}
unsigned char *thash_buf = pk + params->wots_sig_bytes;
wots_pkgen(params, pk, sk_seed, pub_seed, ots_addr);
l_tree(params, leaf, pk, pub_seed, ltree_addr, thash_buf);
OQS_MEM_insecure_free(pk);
}
int xmss_core_sign_open(const xmss_params *params,
const unsigned char *m, unsigned long long mlen,
const unsigned char *sm, unsigned long long smlen,
const unsigned char *pk)
{
return xmssmt_core_sign_open(params, m, mlen, sm, smlen, pk);
}
int xmssmt_core_sign_open(const xmss_params *params,
const unsigned char *m, unsigned long long mlen,
const unsigned char *sm, unsigned long long smlen,
const unsigned char *pk)
{
const unsigned char *pub_root = pk;
const unsigned char *pub_seed = pk + params->n;
unsigned char *tmp = OQS_MEM_malloc(params->wots_sig_bytes + params->n + params->n +
+ 2 *params->n + 2 * params->padding_len + 6 * params->n + 32);
if (tmp == NULL) {
return -1;
}
unsigned char *wots_pk = tmp;
unsigned char *leaf = tmp + params->wots_sig_bytes;
unsigned char *root = leaf + params->n;
unsigned char *compute_root_buf = root + params->n;
unsigned char *thash_buf = compute_root_buf + 2*params->n;
unsigned long long prefix_length = params->padding_len + 3*params->n;
unsigned long long m_with_prefix_len = mlen + prefix_length;
unsigned char *m_with_prefix = NULL;
unsigned char *mhash = root;
unsigned long long idx = 0;
unsigned int i, ret;
uint32_t idx_leaf;
uint32_t ots_addr[8] = {0};
uint32_t ltree_addr[8] = {0};
uint32_t node_addr[8] = {0};
set_type(ots_addr, XMSS_ADDR_TYPE_OTS);
set_type(ltree_addr, XMSS_ADDR_TYPE_LTREE);
set_type(node_addr, XMSS_ADDR_TYPE_HASHTREE);
(void) smlen;
if ((m_with_prefix_len == 0) || (m_with_prefix = OQS_MEM_malloc(m_with_prefix_len)) == NULL){
ret = -1;
goto fail;
}
idx = bytes_to_ull(sm, params->index_bytes);
memcpy(m_with_prefix, sm + params->sig_bytes - prefix_length, (size_t)prefix_length);
memcpy(m_with_prefix + prefix_length, m, (size_t)mlen);
hash_message(params, mhash, sm + params->index_bytes, pk, idx,
m_with_prefix,
mlen);
sm += params->index_bytes + params->n;
for (i = 0; i < params->d; i++) {
idx_leaf = (idx & ((1 << params->tree_height)-1));
idx = idx >> params->tree_height;
set_layer_addr(ots_addr, i);
set_layer_addr(ltree_addr, i);
set_layer_addr(node_addr, i);
set_tree_addr(ltree_addr, idx);
set_tree_addr(ots_addr, idx);
set_tree_addr(node_addr, idx);
set_ots_addr(ots_addr, idx_leaf);
wots_pk_from_sig(params, wots_pk, sm, root, pub_seed, ots_addr);
sm += params->wots_sig_bytes;
set_ltree_addr(ltree_addr, idx_leaf);
l_tree(params, leaf, wots_pk, pub_seed, ltree_addr, thash_buf);
compute_root(params, root, leaf, idx_leaf, sm, pub_seed, node_addr, compute_root_buf, thash_buf);
sm += params->tree_height*params->n;
}
if (memcmp(root, pub_root, params->n)) {
ret = -1;
goto fail;
}
ret = 0;
fail:
OQS_MEM_insecure_free(tmp);
OQS_MEM_insecure_free(m_with_prefix);
return ret;
}