Files
GmSSL/crypto/sphincs/merkle.c
2019-03-13 22:26:55 +08:00

267 lines
6.9 KiB
C

/*
* Copyright (C) 2017 Nagravision S.A.
*/
#include "merkle.h"
#include <stdlib.h>
int merkle_base_address (const struct address *address, struct address *base_address) {
int index = address->index & (MERKLE_hhh - 1);
if (base_address != NULL) {
base_address->layer = address->layer;
base_address->index = address->index - index;
}
return index;
}
int merkle_genpk (const struct hash *key, const struct address *address, struct merkle_pk *pk) {
struct address base_address;
struct hash *buf;
struct wots_sk wsk;
struct lwots_pk wpk;
int j;
merkle_base_address (address, &base_address);
buf = merkle_alloc_buf (MERKLE_h);
if (buf == NULL) return GRAVITY_ERR_ALLOC;
/* Leaves */
for (j = 0; j < MERKLE_hhh; ++j) {
wots_gensk (key, &base_address, &wsk);
lwots_genpk (&wsk, &wpk);
hashcpy (&buf[j], &wpk.k);
++base_address.index;
}
/* Merkle tree */
merkle_compress_all (buf, MERKLE_h, &pk->k);
merkle_free_buf (buf);
return GRAVITY_OK;
}
int merkle_sign (const struct hash *key,
const struct address *address,
struct merkle_sign *sign,
const struct hash *msg,
struct merkle_pk *pk) {
struct address base_address;
struct hash *buf;
struct wots_sk wsk;
struct lwots_pk wpk;
int index;
int j;
index = merkle_base_address (address, &base_address);
buf = merkle_alloc_buf (MERKLE_h);
if (buf == NULL) return GRAVITY_ERR_ALLOC;
/* Leaves */
for (j = 0; j < MERKLE_hhh; ++j) {
wots_gensk (key, &base_address, &wsk);
lwots_genpk (&wsk, &wpk);
hashcpy (&buf[j], &wpk.k);
++base_address.index;
/* WOTS */
if (j == index) wots_sign (&wsk, &sign->wots, msg);
}
/* Merkle tree */
merkle_gen_auth (buf, MERKLE_h, sign->auth, index, pk == NULL ? NULL : &pk->k);
merkle_free_buf (buf);
return GRAVITY_OK;
}
void merkle_extract (struct merkle_pk *pk,
const struct address *address,
const struct merkle_sign *sign,
const struct hash *msg) {
struct lwots_pk wpk;
int index = merkle_base_address (address, NULL);
/* WOTS */
lwots_extract (&wpk, &sign->wots, msg);
/* Auth path */
merkle_compress_auth (&wpk.k, index, sign->auth, MERKLE_h);
hashcpy (&pk->k, &wpk.k);
}
/* Helper functions */
/* Alloc/free a buffer large enough to store leaves and compress them */
struct hash *merkle_alloc_buf (int height) {
int n = 1 << height;
return malloc (2 * n * HASH_SIZE);
}
void merkle_free_buf (struct hash *buf) {
/* TODO: wipe buffer? */
free (buf);
}
/* Compress leaves from level height until root */
void merkle_compress_all (struct hash *buf, int height, struct hash *root) {
int n = 1 << height;
struct hash *src = &buf[n];
struct hash *dst = &buf[0];
struct hash *tmp;
int l;
for (l = 0; l < height; ++l) {
/* Swap buffers */
hashswap (src, dst, tmp);
n >>= 1;
/* Compute all hashes at current layer */
hash_compress_pairs (dst, src, n);
}
hashcpy (root, dst);
}
/* Compute authentication path */
void merkle_gen_auth (struct hash *buf, int height, struct hash *auth, int index, struct hash *root) {
int n = 1 << height;
struct hash *src = &buf[n];
struct hash *dst = &buf[0];
struct hash *tmp;
int l, sibling;
for (l = 0; l < height; ++l) {
/* Copy auth path */
sibling = index ^ 1;
hashcpy (&auth[l], &dst[sibling]);
index >>= 1;
/* Swap buffers */
hashswap (src, dst, tmp);
n >>= 1;
/* Compute all hashes at current layer */
hash_compress_pairs (dst, src, n);
}
/* Public key */
if (root != NULL) hashcpy (root, dst);
}
/* Compress node with its auth path on height_diff levels */
int merkle_compress_auth (struct hash *node, int index, const struct hash *auth, int height_diff) {
struct hash buf[2];
int l;
for (l = 0; l < height_diff; ++l) {
if (index % 2 == 0) {
hashcpy (&buf[0], node);
hashcpy (&buf[1], &auth[l]);
} else {
hashcpy (&buf[0], &auth[l]);
hashcpy (&buf[1], node);
}
hash_2N_to_N (node, buf);
index >>= 1;
}
return index;
}
void merkle_gen_octopus (struct hash *buf,
int height,
struct hash *octopus,
int *octolen,
struct hash *root,
int *indices,
int count) {
int n = 1 << height;
struct hash *src = &buf[n];
struct hash *dst = &buf[0];
struct hash *tmp;
int i, j, l;
int len = 0;
int index, sibling;
for (l = 0; l < height; ++l) {
/* Copy auth octopus */
for (i = 0, j = 0; i < count; ++i, ++j) {
index = indices[i];
sibling = index ^ 1;
/* Check redundancy with sibling */
if (i + 1 < count && indices[i + 1] == sibling)
++i;
else
hashcpy (&octopus[len++], &dst[sibling]);
indices[j] = indices[i] >> 1;
}
/* Update count of non-redundant nodes */
count = j;
/* Swap buffers */
hashswap (src, dst, tmp);
n >>= 1;
/* Compute all hashes at current layer */
hash_compress_pairs (dst, src, n);
}
hashcpy (root, dst);
*octolen = len;
}
int merkle_compress_octopus (struct hash *nodes,
int height,
const struct hash *octopus,
int octolen,
int *indices,
int count) {
struct hash buf[2];
int i, j, l;
int len = 0;
int index;
for (l = 0; l < height; ++l) {
for (i = 0, j = 0; i < count; ++i, ++j) {
/* Select 2 values to merge */
index = indices[i];
if (index % 2 == 0) {
hashcpy (&buf[0], &nodes[i]);
if (i + 1 < count && indices[i + 1] == index + 1) {
++i;
hashcpy (&buf[1], &nodes[i]);
} else {
if (len == octolen) return GRAVITY_ERR_VERIF;
hashcpy (&buf[1], &octopus[len++]);
}
} else {
if (len == octolen) return GRAVITY_ERR_VERIF;
hashcpy (&buf[0], &octopus[len++]);
hashcpy (&buf[1], &nodes[i]);
}
/* Hash values */
hash_2N_to_N (&nodes[j], buf);
indices[j] = indices[i] >> 1;
}
/* Update count of non-redundant nodes */
count = j;
}
/* Check len */
if (len != octolen) return GRAVITY_ERR_VERIF;
return GRAVITY_OK;
}