blob: f2113b5c87d9b6ab23cbcf3a457750dc1aa24a1f [file] [log] [blame] [edit]
// Copyright 2024 The BoringSSL Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <openssl/base.h>
#include <string.h>
#include "../../internal.h"
#include "./address.h"
#include "./merkle.h"
#include "./params.h"
#include "./thash.h"
#include "./wots.h"
// Implements Algorithm 9: xmss_node function (page 23)
void slhdsa_treehash(const slh_dsa_config *config, uint8_t *out_pk,
const uint8_t *sk_seed, uint32_t i, uint32_t z,
const uint8_t *pk_seed, uint8_t addr[32]) {
BSSL_CHECK(z <= config->tree_height);
BSSL_CHECK(i < (uint32_t)(1u << (config->tree_height - z)));
if (z == 0) {
slhdsa_set_type(config, addr, SLHDSA_ADDR_TYPE_WOTS);
slhdsa_set_keypair_addr(config, addr, i);
slhdsa_wots_pk_gen(config, out_pk, sk_seed, pk_seed, addr);
} else {
// Stores left node and right node.
uint8_t nodes[2 * SLHDSA_MAX_N];
slhdsa_treehash(config, nodes, sk_seed, 2 * i, z - 1, pk_seed, addr);
slhdsa_treehash(config, nodes + config->n, sk_seed, 2 * i + 1, z - 1,
pk_seed, addr);
slhdsa_set_type(config, addr, SLHDSA_ADDR_TYPE_HASHTREE);
slhdsa_set_tree_height(config, addr, z);
slhdsa_set_tree_index(config, addr, i);
slhdsa_thash_h(config, out_pk, nodes, pk_seed, addr);
}
}
// Implements Algorithm 10: xmss_sign function (page 24)
void slhdsa_xmss_sign(const slh_dsa_config *config, uint8_t *sig,
const uint8_t *msg, unsigned int idx,
const uint8_t *sk_seed, const uint8_t *pk_seed,
uint8_t addr[32]) {
// Build authentication path
const size_t wots_bytes = slhdsa_wots_bytes(config);
const size_t n = config->n;
for (size_t j = 0; j < config->tree_height; ++j) {
unsigned int k = (idx >> j) ^ 1;
slhdsa_treehash(config, sig + wots_bytes + j * n, sk_seed, k, j, pk_seed,
addr);
}
// Compute WOTS+ signature
slhdsa_set_type(config, addr, SLHDSA_ADDR_TYPE_WOTS);
slhdsa_set_keypair_addr(config, addr, idx);
slhdsa_wots_sign(config, sig, msg, sk_seed, pk_seed, addr);
}
// Implements Algorithm 11: xmss_pkFromSig function (page 25)
void slhdsa_xmss_pk_from_sig(const slh_dsa_config *config, uint8_t *root,
const uint8_t *xmss_sig, unsigned int idx,
const uint8_t *msg, const uint8_t *pk_seed,
uint8_t addr[32]) {
// Stores node[0] and node[1] from Algorithm 11
slhdsa_set_type(config, addr, SLHDSA_ADDR_TYPE_WOTS);
slhdsa_set_keypair_addr(config, addr, idx);
uint8_t node[2 * SLHDSA_MAX_N];
const size_t n = config->n;
slhdsa_wots_pk_from_sig(config, node, xmss_sig, msg, pk_seed, addr);
slhdsa_set_type(config, addr, SLHDSA_ADDR_TYPE_HASHTREE);
slhdsa_set_tree_index(config, addr, idx);
uint8_t tmp[2 * SLHDSA_MAX_N];
const uint8_t *const auth = xmss_sig + slhdsa_wots_bytes(config);
for (uint32_t k = 0; k < config->tree_height; ++k) {
slhdsa_set_tree_height(config, addr, k + 1);
if (((idx >> k) & 1) == 0) {
slhdsa_set_tree_index(config, addr,
slhdsa_get_tree_index(config, addr) >> 1);
OPENSSL_memcpy(tmp, node, n);
OPENSSL_memcpy(tmp + n, auth + k * n, n);
slhdsa_thash_h(config, node + n, tmp, pk_seed, addr);
} else {
slhdsa_set_tree_index(config, addr,
(slhdsa_get_tree_index(config, addr) - 1) >> 1);
OPENSSL_memcpy(tmp, auth + k * n, n);
OPENSSL_memcpy(tmp + n, node, n);
slhdsa_thash_h(config, node + n, tmp, pk_seed, addr);
}
OPENSSL_memcpy(node, node + n, n);
}
OPENSSL_memcpy(root, node, n);
}
// Implements Algorithm 12: ht_sign function (page 27)
void slhdsa_ht_sign(const slh_dsa_config *config, uint8_t *sig,
const uint8_t *message, uint64_t idx_tree,
uint32_t idx_leaf, const uint8_t *sk_seed,
const uint8_t *pk_seed) {
uint8_t addr[32] = {0};
slhdsa_set_tree_addr(config, addr, idx_tree);
// Layer 0
slhdsa_xmss_sign(config, sig, message, idx_leaf, sk_seed, pk_seed, addr);
uint8_t root[SLHDSA_MAX_N];
slhdsa_xmss_pk_from_sig(config, root, sig, idx_leaf, message, pk_seed, addr);
sig += slhdsa_xmss_bytes(config);
// All other layers
BSSL_CHECK(config->tree_height <= SLHDSA_MAX_TREE_HEIGHT);
const uint32_t leaf_mask = (1u << config->tree_height) - 1;
for (uint32_t j = 1; j < config->d; ++j) {
idx_leaf = idx_tree & leaf_mask;
idx_tree = idx_tree >> config->tree_height;
slhdsa_set_layer_addr(config, addr, j);
slhdsa_set_tree_addr(config, addr, idx_tree);
slhdsa_xmss_sign(config, sig, root, idx_leaf, sk_seed, pk_seed, addr);
if (j < (config->d - 1)) {
slhdsa_xmss_pk_from_sig(config, root, sig, idx_leaf, root, pk_seed, addr);
}
sig += slhdsa_xmss_bytes(config);
}
}
// Implements Algorithm 13: ht_verify function (page 28)
int slhdsa_ht_verify(const slh_dsa_config *config, const uint8_t *sig,
const uint8_t *message, uint64_t idx_tree,
uint32_t idx_leaf, const uint8_t *pk_root,
const uint8_t *pk_seed) {
uint8_t addr[32] = {0};
slhdsa_set_tree_addr(config, addr, idx_tree);
uint8_t node[SLHDSA_MAX_N];
slhdsa_xmss_pk_from_sig(config, node, sig, idx_leaf, message, pk_seed, addr);
BSSL_CHECK(config->tree_height <= SLHDSA_MAX_TREE_HEIGHT);
const uint32_t leaf_mask = (1u << config->tree_height) - 1;
for (uint32_t j = 1; j < config->d; ++j) {
idx_leaf = idx_tree & leaf_mask;
idx_tree = idx_tree >> config->tree_height;
slhdsa_set_layer_addr(config, addr, j);
slhdsa_set_tree_addr(config, addr, idx_tree);
slhdsa_xmss_pk_from_sig(config, node, sig + j * slhdsa_xmss_bytes(config),
idx_leaf, node, pk_seed, addr);
}
return memcmp(node, pk_root, config->n) == 0;
}