Vystem 0.2

This commit is contained in:
2026-05-27 19:34:54 +02:00
parent a43c08b893
commit d238606b75
372 changed files with 51320 additions and 83217 deletions

View File

@@ -1,104 +0,0 @@
#include <stdint.h>
#include <string.h>
#include "address.h"
#include "params.h"
#include "utils.h"
/*
* Specify which level of Merkle tree (the "layer") we're working on
*/
void set_layer_addr(uint32_t addr[8], uint32_t layer)
{
((unsigned char *)addr)[SPX_OFFSET_LAYER] = (unsigned char)layer;
}
/*
* Specify which Merkle tree within the level (the "tree address") we're working on
*/
void set_tree_addr(uint32_t addr[8], uint64_t tree)
{
#if (SPX_TREE_HEIGHT * (SPX_D - 1)) > 64
#error Subtree addressing is currently limited to at most 2^64 trees
#endif
ull_to_bytes(&((unsigned char *)addr)[SPX_OFFSET_TREE], 8, tree );
}
/*
* Specify the reason we'll use this address structure for, that is, what
* hash will we compute with it. This is used so that unrelated types of
* hashes don't accidentally get the same address structure. The type will be
* one of the SPX_ADDR_TYPE constants
*/
void set_type(uint32_t addr[8], uint32_t type)
{
((unsigned char *)addr)[SPX_OFFSET_TYPE] = (unsigned char)type;
}
/*
* Copy the layer and tree fields of the address structure. This is used
* when we're doing multiple types of hashes within the same Merkle tree
*/
void copy_subtree_addr(uint32_t out[8], const uint32_t in[8])
{
memcpy( out, in, SPX_OFFSET_TREE+8 );
}
/* These functions are used for OTS addresses. */
/*
* Specify which Merkle leaf we're working on; that is, which OTS keypair
* we're talking about.
*/
void set_keypair_addr(uint32_t addr[8], uint32_t keypair)
{
u32_to_bytes(&((unsigned char *)addr)[SPX_OFFSET_KP_ADDR], keypair);
}
/*
* Copy the layer, tree and keypair fields of the address structure. This is
* used when we're doing multiple things within the same OTS keypair
*/
void copy_keypair_addr(uint32_t out[8], const uint32_t in[8])
{
memcpy( out, in, SPX_OFFSET_TREE+8 );
memcpy( (unsigned char *)out + SPX_OFFSET_KP_ADDR, (unsigned char *)in + SPX_OFFSET_KP_ADDR, 4);
}
/*
* Specify which Merkle chain within the OTS we're working with
* (the chain address)
*/
void set_chain_addr(uint32_t addr[8], uint32_t chain)
{
((unsigned char *)addr)[SPX_OFFSET_CHAIN_ADDR] = (unsigned char)chain;
}
/*
* Specify where in the Merkle chain we are
* (the hash address)
*/
void set_hash_addr(uint32_t addr[8], uint32_t hash)
{
((unsigned char *)addr)[SPX_OFFSET_HASH_ADDR] = (unsigned char)hash;
}
/* These functions are used for all hash tree addresses (including FORS). */
/*
* Specify the height of the node in the Merkle/FORS tree we are in
* (the tree height)
*/
void set_tree_height(uint32_t addr[8], uint32_t tree_height)
{
((unsigned char *)addr)[SPX_OFFSET_TREE_HGT] = (unsigned char)tree_height;
}
/*
* Specify the distance from the left edge of the node in the Merkle/FORS tree
* (the tree index)
*/
void set_tree_index(uint32_t addr[8], uint32_t tree_index)
{
u32_to_bytes(&((unsigned char *)addr)[SPX_OFFSET_TREE_INDEX], tree_index );
}

View File

@@ -1,161 +0,0 @@
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include "fors.h"
#include "utils.h"
#include "utilsx1.h"
#include "hash.h"
#include "thash.h"
#include "address.h"
static void fors_gen_sk(unsigned char *sk, const spx_ctx *ctx,
uint32_t fors_leaf_addr[8])
{
prf_addr(sk, ctx, fors_leaf_addr);
}
static void fors_sk_to_leaf(unsigned char *leaf, const unsigned char *sk,
const spx_ctx *ctx,
uint32_t fors_leaf_addr[8])
{
thash(leaf, sk, 1, ctx, fors_leaf_addr);
}
struct fors_gen_leaf_info {
uint32_t leaf_addrx[8];
};
static void fors_gen_leafx1(unsigned char *leaf,
const spx_ctx *ctx,
uint32_t addr_idx, void *info)
{
struct fors_gen_leaf_info *fors_info = info;
uint32_t *fors_leaf_addr = fors_info->leaf_addrx;
/* Only set the parts that the caller doesn't set */
set_tree_index(fors_leaf_addr, addr_idx);
set_type(fors_leaf_addr, SPX_ADDR_TYPE_FORSPRF);
fors_gen_sk(leaf, ctx, fors_leaf_addr);
set_type(fors_leaf_addr, SPX_ADDR_TYPE_FORSTREE);
fors_sk_to_leaf(leaf, leaf,
ctx, fors_leaf_addr);
}
/**
* Interprets m as SPX_FORS_HEIGHT-bit unsigned integers.
* Assumes m contains at least SPX_FORS_HEIGHT * SPX_FORS_TREES bits.
* Assumes indices has space for SPX_FORS_TREES integers.
*/
static void message_to_indices(uint32_t *indices, const unsigned char *m)
{
unsigned int i, j;
unsigned int offset = 0;
for (i = 0; i < SPX_FORS_TREES; i++) {
indices[i] = 0;
for (j = 0; j < SPX_FORS_HEIGHT; j++) {
indices[i] ^= ((m[offset >> 3] >> (offset & 0x7)) & 1u) << j;
offset++;
}
}
}
/**
* Signs a message m, deriving the secret key from sk_seed and the FTS address.
* Assumes m contains at least SPX_FORS_HEIGHT * SPX_FORS_TREES bits.
*/
void fors_sign(unsigned char *sig, unsigned char *pk,
const unsigned char *m,
const spx_ctx *ctx,
const uint32_t fors_addr[8])
{
uint32_t indices[SPX_FORS_TREES];
unsigned char roots[SPX_FORS_TREES * SPX_N];
uint32_t fors_tree_addr[8] = {0};
struct fors_gen_leaf_info fors_info = {0};
uint32_t *fors_leaf_addr = fors_info.leaf_addrx;
uint32_t fors_pk_addr[8] = {0};
uint32_t idx_offset;
unsigned int i;
copy_keypair_addr(fors_tree_addr, fors_addr);
copy_keypair_addr(fors_leaf_addr, fors_addr);
copy_keypair_addr(fors_pk_addr, fors_addr);
set_type(fors_pk_addr, SPX_ADDR_TYPE_FORSPK);
message_to_indices(indices, m);
for (i = 0; i < SPX_FORS_TREES; i++) {
idx_offset = i * (1 << SPX_FORS_HEIGHT);
set_tree_height(fors_tree_addr, 0);
set_tree_index(fors_tree_addr, indices[i] + idx_offset);
set_type(fors_tree_addr, SPX_ADDR_TYPE_FORSPRF);
/* Include the secret key part that produces the selected leaf node. */
fors_gen_sk(sig, ctx, fors_tree_addr);
set_type(fors_tree_addr, SPX_ADDR_TYPE_FORSTREE);
sig += SPX_N;
/* Compute the authentication path for this leaf node. */
treehashx1(roots + i*SPX_N, sig, ctx,
indices[i], idx_offset, SPX_FORS_HEIGHT, fors_gen_leafx1,
fors_tree_addr, &fors_info);
sig += SPX_N * SPX_FORS_HEIGHT;
}
/* Hash horizontally across all tree roots to derive the public key. */
thash(pk, roots, SPX_FORS_TREES, ctx, fors_pk_addr);
}
/**
* Derives the FORS public key from a signature.
* This can be used for verification by comparing to a known public key, or to
* subsequently verify a signature on the derived public key. The latter is the
* typical use-case when used as an FTS below an OTS in a hypertree.
* Assumes m contains at least SPX_FORS_HEIGHT * SPX_FORS_TREES bits.
*/
void fors_pk_from_sig(unsigned char *pk,
const unsigned char *sig, const unsigned char *m,
const spx_ctx* ctx,
const uint32_t fors_addr[8])
{
uint32_t indices[SPX_FORS_TREES];
unsigned char roots[SPX_FORS_TREES * SPX_N];
unsigned char leaf[SPX_N];
uint32_t fors_tree_addr[8] = {0};
uint32_t fors_pk_addr[8] = {0};
uint32_t idx_offset;
unsigned int i;
copy_keypair_addr(fors_tree_addr, fors_addr);
copy_keypair_addr(fors_pk_addr, fors_addr);
set_type(fors_tree_addr, SPX_ADDR_TYPE_FORSTREE);
set_type(fors_pk_addr, SPX_ADDR_TYPE_FORSPK);
message_to_indices(indices, m);
for (i = 0; i < SPX_FORS_TREES; i++) {
idx_offset = i * (1 << SPX_FORS_HEIGHT);
set_tree_height(fors_tree_addr, 0);
set_tree_index(fors_tree_addr, indices[i] + idx_offset);
/* Derive the leaf from the included secret key part. */
fors_sk_to_leaf(leaf, sig, ctx, fors_tree_addr);
sig += SPX_N;
/* Derive the corresponding root node of this tree. */
compute_root(roots + i*SPX_N, leaf, indices[i], idx_offset,
sig, SPX_FORS_HEIGHT, ctx, fors_tree_addr);
sig += SPX_N * SPX_FORS_HEIGHT;
}
/* Hash horizontally across all tree roots to derive the public key. */
thash(pk, roots, SPX_FORS_TREES, ctx, fors_pk_addr);
}

View File

@@ -1,197 +0,0 @@
#include <stdint.h>
#include <string.h>
#include "address.h"
#include "utils.h"
#include "params.h"
#include "hash.h"
#include "sha2.h"
#if SPX_N >= 24
#define SPX_SHAX_OUTPUT_BYTES SPX_SHA512_OUTPUT_BYTES
#define SPX_SHAX_BLOCK_BYTES SPX_SHA512_BLOCK_BYTES
#define shaX_inc_init sha512_inc_init
#define shaX_inc_blocks sha512_inc_blocks
#define shaX_inc_finalize sha512_inc_finalize
#define shaX sha512
#define mgf1_X mgf1_512
#else
#define SPX_SHAX_OUTPUT_BYTES SPX_SHA256_OUTPUT_BYTES
#define SPX_SHAX_BLOCK_BYTES SPX_SHA256_BLOCK_BYTES
#define shaX_inc_init sha256_inc_init
#define shaX_inc_blocks sha256_inc_blocks
#define shaX_inc_finalize sha256_inc_finalize
#define shaX sha256
#define mgf1_X mgf1_256
#endif
/* For SHA, there is no immediate reason to initialize at the start,
so this function is an empty operation. */
void initialize_hash_function(spx_ctx *ctx)
{
seed_state(ctx);
}
/*
* Computes PRF(pk_seed, sk_seed, addr).
*/
void prf_addr(unsigned char *out, const spx_ctx *ctx,
const uint32_t addr[8])
{
uint8_t sha2_state[40];
unsigned char buf[SPX_SHA256_ADDR_BYTES + SPX_N];
unsigned char outbuf[SPX_SHA256_OUTPUT_BYTES];
/* Retrieve precomputed state containing pub_seed */
memcpy(sha2_state, ctx->state_seeded, 40 * sizeof(uint8_t));
/* Remainder: ADDR^c ‖ SK.seed */
memcpy(buf, addr, SPX_SHA256_ADDR_BYTES);
memcpy(buf + SPX_SHA256_ADDR_BYTES, ctx->sk_seed, SPX_N);
sha256_inc_finalize(outbuf, sha2_state, buf, SPX_SHA256_ADDR_BYTES + SPX_N);
memcpy(out, outbuf, SPX_N);
}
/**
* Computes the message-dependent randomness R, using a secret seed as a key
* for HMAC, and an optional randomization value prefixed to the message.
* This requires m to have at least SPX_SHAX_BLOCK_BYTES + SPX_N space
* available in front of the pointer, i.e. before the message to use for the
* prefix. This is necessary to prevent having to move the message around (and
* allocate memory for it).
*/
void gen_message_random(unsigned char *R, const unsigned char *sk_prf,
const unsigned char *optrand,
const unsigned char *m, unsigned long long mlen,
const spx_ctx *ctx)
{
(void)ctx;
unsigned char buf[SPX_SHAX_BLOCK_BYTES + SPX_SHAX_OUTPUT_BYTES];
uint8_t state[8 + SPX_SHAX_OUTPUT_BYTES];
int i;
#if SPX_N > SPX_SHAX_BLOCK_BYTES
#error "Currently only supports SPX_N of at most SPX_SHAX_BLOCK_BYTES"
#endif
/* This implements HMAC-SHA */
for (i = 0; i < SPX_N; i++) {
buf[i] = 0x36 ^ sk_prf[i];
}
memset(buf + SPX_N, 0x36, SPX_SHAX_BLOCK_BYTES - SPX_N);
shaX_inc_init(state);
shaX_inc_blocks(state, buf, 1);
memcpy(buf, optrand, SPX_N);
/* If optrand + message cannot fill up an entire block */
if (SPX_N + mlen < SPX_SHAX_BLOCK_BYTES) {
memcpy(buf + SPX_N, m, mlen);
shaX_inc_finalize(buf + SPX_SHAX_BLOCK_BYTES, state,
buf, mlen + SPX_N);
}
/* Otherwise first fill a block, so that finalize only uses the message */
else {
memcpy(buf + SPX_N, m, SPX_SHAX_BLOCK_BYTES - SPX_N);
shaX_inc_blocks(state, buf, 1);
m += SPX_SHAX_BLOCK_BYTES - SPX_N;
mlen -= SPX_SHAX_BLOCK_BYTES - SPX_N;
shaX_inc_finalize(buf + SPX_SHAX_BLOCK_BYTES, state, m, mlen);
}
for (i = 0; i < SPX_N; i++) {
buf[i] = 0x5c ^ sk_prf[i];
}
memset(buf + SPX_N, 0x5c, SPX_SHAX_BLOCK_BYTES - SPX_N);
shaX(buf, buf, SPX_SHAX_BLOCK_BYTES + SPX_SHAX_OUTPUT_BYTES);
memcpy(R, buf, SPX_N);
}
/**
* Computes the message hash using R, the public key, and the message.
* Outputs the message digest and the index of the leaf. The index is split in
* the tree index and the leaf index, for convenient copying to an address.
*/
void hash_message(unsigned char *digest, uint64_t *tree, uint32_t *leaf_idx,
const unsigned char *R, const unsigned char *pk,
const unsigned char *m, unsigned long long mlen,
const spx_ctx *ctx)
{
(void)ctx;
#define SPX_TREE_BITS (SPX_TREE_HEIGHT * (SPX_D - 1))
#define SPX_TREE_BYTES ((SPX_TREE_BITS + 7) / 8)
#define SPX_LEAF_BITS SPX_TREE_HEIGHT
#define SPX_LEAF_BYTES ((SPX_LEAF_BITS + 7) / 8)
#define SPX_DGST_BYTES (SPX_FORS_MSG_BYTES + SPX_TREE_BYTES + SPX_LEAF_BYTES)
unsigned char seed[2*SPX_N + SPX_SHAX_OUTPUT_BYTES];
/* Round to nearest multiple of SPX_SHAX_BLOCK_BYTES */
#if (SPX_SHAX_BLOCK_BYTES & (SPX_SHAX_BLOCK_BYTES-1)) != 0
#error "Assumes that SPX_SHAX_BLOCK_BYTES is a power of 2"
#endif
#define SPX_INBLOCKS (((SPX_N + SPX_PK_BYTES + SPX_SHAX_BLOCK_BYTES - 1) & \
-SPX_SHAX_BLOCK_BYTES) / SPX_SHAX_BLOCK_BYTES)
unsigned char inbuf[SPX_INBLOCKS * SPX_SHAX_BLOCK_BYTES];
unsigned char buf[SPX_DGST_BYTES];
unsigned char *bufp = buf;
uint8_t state[8 + SPX_SHAX_OUTPUT_BYTES];
shaX_inc_init(state);
// seed: SHA-X(R ‖ PK.seed ‖ PK.root ‖ M)
memcpy(inbuf, R, SPX_N);
memcpy(inbuf + SPX_N, pk, SPX_PK_BYTES);
/* If R + pk + message cannot fill up an entire block */
if (SPX_N + SPX_PK_BYTES + mlen < SPX_INBLOCKS * SPX_SHAX_BLOCK_BYTES) {
memcpy(inbuf + SPX_N + SPX_PK_BYTES, m, mlen);
shaX_inc_finalize(seed + 2*SPX_N, state, inbuf, SPX_N + SPX_PK_BYTES + mlen);
}
/* Otherwise first fill a block, so that finalize only uses the message */
else {
memcpy(inbuf + SPX_N + SPX_PK_BYTES, m,
SPX_INBLOCKS * SPX_SHAX_BLOCK_BYTES - SPX_N - SPX_PK_BYTES);
shaX_inc_blocks(state, inbuf, SPX_INBLOCKS);
m += SPX_INBLOCKS * SPX_SHAX_BLOCK_BYTES - SPX_N - SPX_PK_BYTES;
mlen -= SPX_INBLOCKS * SPX_SHAX_BLOCK_BYTES - SPX_N - SPX_PK_BYTES;
shaX_inc_finalize(seed + 2*SPX_N, state, m, mlen);
}
// H_msg: MGF1-SHA-X(R ‖ PK.seed ‖ seed)
memcpy(seed, R, SPX_N);
memcpy(seed + SPX_N, pk, SPX_N);
/* By doing this in two steps, we prevent hashing the message twice;
otherwise each iteration in MGF1 would hash the message again. */
mgf1_X(bufp, SPX_DGST_BYTES, seed, 2*SPX_N + SPX_SHAX_OUTPUT_BYTES);
memcpy(digest, bufp, SPX_FORS_MSG_BYTES);
bufp += SPX_FORS_MSG_BYTES;
#if SPX_TREE_BITS > 64
#error For given height and depth, 64 bits cannot represent all subtrees
#endif
if (SPX_D == 1) {
*tree = 0;
} else {
*tree = bytes_to_ull(bufp, SPX_TREE_BYTES);
*tree &= (~(uint64_t)0) >> (64 - SPX_TREE_BITS);
}
bufp += SPX_TREE_BYTES;
*leaf_idx = (uint32_t)bytes_to_ull(bufp, SPX_LEAF_BYTES);
*leaf_idx &= (~(uint32_t)0) >> (32 - SPX_LEAF_BITS);
}

View File

@@ -12,14 +12,15 @@ extern "C" {
#include <vector>
#include <cstring>
#include <algorithm>
#include "common/versions.h"
using namespace std;
namespace fs=filesystem;
#pragma pack(push,1)
struct initfs_header {
uint8_t sign[8]={'I','n','i','t','F','i','S','y'};
uint16_t bootloader_version=0x0001;
uint16_t initfs_version=0x0001;
uint32_t os_version=0x00000001;
uint16_t bootloader_version=VY_COMMON_VERSIONS_BOOTLOADER;
uint16_t initfs_version=VY_COMMON_VERSIONS_INITFS;
uint32_t os_version=VY_COMMON_VERSIONS_OS;
uint8_t installation_id[48]={0};
uint64_t initfs_size=0;
uint64_t table_size=0;
@@ -48,9 +49,9 @@ struct file_entry {
#pragma pack(push,1)
struct signsyst_header {
uint8_t sign[8]={'S','i','g','n','S','y','s','t'};
uint16_t bootloader_version=0x0001;
uint16_t initfs_version=0x0001;
uint32_t os_version=0x00000001;
uint16_t bootloader_version=VY_COMMON_VERSIONS_BOOTLOADER;
uint16_t initfs_version=VY_COMMON_VERSIONS_INITFS;
uint32_t os_version=VY_COMMON_VERSIONS_OS;
uint8_t installation_id[48]={0};
uint64_t signature_size=0;
uint64_t signature_count=0;
@@ -138,7 +139,7 @@ int main(int argc,char **argv) {
uint64_t value=(header.initfs_size+header.table_size+header.files_area_size+header.entries_width+header.entries_count+header.files_area_offset)%UINT64_MAX;
header.check1=(value*0x9E3779B185EBCA87)^header.entropy_check1;
sha3(header.installation_id,sizeof(header.installation_id),header.installation_id_hash_hash,sizeof(header.installation_id_hash_hash));
ofstream initfs_footprint("initfs-footprint.bin",ios::binary);
ofstream initfs_footprint("initfsfp.bin",ios::binary);
if (!initfs_footprint) {
cout<<"[InitFSGen] Error: Can't open initfs-footprint.bin."<<endl;
return -1;
@@ -220,7 +221,7 @@ int main(int argc,char **argv) {
initfs_bin.write(reinterpret_cast<char*>(entries_table.data()),entries_table.size());
initfs_bin.write(reinterpret_cast<char*>(files_area.data()),files_area.size());
initfs_bin.close();
ofstream signsyst_hash("signsyst-hash.bin",ios::binary);
ofstream signsyst_hash("sshash.bin",ios::binary);
if (!signsyst_hash) {
cout<<"[InitFSGen] Error: Can't open signsyst-hash.bin."<<endl;
return -1;

View File

@@ -0,0 +1,108 @@
{
"version":"0.1",
"root_folder":"%filefolder%",
"run_context":"sub",
"name":"Initfsgen build",
"actions":[
{
"action":"compile_one_cpp",
"args":{
"source_variables":false,
"source":"initfsgen.cpp",
"compiler_variables":true,
"compiler":"$CPP_COMPILER$",
"pre_arguments_variables":true,
"pre_arguments":[
"-I%rootcallerfolder%",
"-c"
],
"post_arguments_variables":true,
"post_arguments":[
],
"output_file_variables":true,
"output_file":"initfsgen.o",
"success_status":[
0
],
"ignore_success_status":true,
"cache_authorized":true,
"headers_command_variables":true,
"headers_command":"gcc -I%rootcallerfolder% -MMD -MF %dfile% -E %sourcefile% -o /dev/null"
}
},
{
"action":"run_command_wait",
"args":{
"command_variables":true,
"command":[
"$CPP_COMPILER$",
"initfsgen.o",
"-o",
"initfsgen",
"-L.",
"-lcommoncrypto",
"-lcrypto",
"-I%rootcallerfolder%"
],
"show_output":"on_failure",
"success_status":[
0
],
"ignore_success_status":false
}
},
{
"action":"run_command_wait_dir",
"args":{
"command_variables":true,
"command":[
"%rootcallerfolder%/$EDK2_BLASTPROOF_DIR$/initfsgen/initfsgen",
"%rootcallerfolder%/$INITFS_DIR$"
],
"show_output":"on_failure",
"success_status":[
0
],
"ignore_success_status":false,
"working_dir_variables":true,
"working_dir":"%rootcallerfolder%"
}
},
{
"action":"move_file",
"args":{
"source_file_variables":true,
"source_file":"%rootcallerfolder%/initfs.bin",
"destination_folder_variables":true,
"destination_folder":"%rootcallerfolder%/$EDK2_BLASTPROOF_DIR$/initfsgen"
}
},
{
"action":"move_file",
"args":{
"source_file_variables":true,
"source_file":"%rootcallerfolder%/signsyst.bin",
"destination_folder_variables":true,
"destination_folder":"%rootcallerfolder%/$EDK2_BLASTPROOF_DIR$/initfsgen"
}
},
{
"action":"move_file",
"args":{
"source_file_variables":true,
"source_file":"%rootcallerfolder%/initfsfp.bin",
"destination_folder_variables":true,
"destination_folder":"%rootcallerfolder%/$EDK2_BLASTPROOF_DIR$/initfsgen"
}
},
{
"action":"move_file",
"args":{
"source_file_variables":true,
"source_file":"%rootcallerfolder%/sshash.bin",
"destination_folder_variables":true,
"destination_folder":"%rootcallerfolder%/$EDK2_BLASTPROOF_DIR$/initfsgen"
}
}
]
}

View File

@@ -1,61 +0,0 @@
#include <stdint.h>
#include <string.h>
#include "utils.h"
#include "utilsx1.h"
#include "wots.h"
#include "wotsx1.h"
#include "merkle.h"
#include "address.h"
#include "params.h"
/*
* This generates a Merkle signature (WOTS signature followed by the Merkle
* authentication path). This is in this file because most of the complexity
* is involved with the WOTS signature; the Merkle authentication path logic
* is mostly hidden in treehashx4
*/
void merkle_sign(uint8_t *sig, unsigned char *root,
const spx_ctx *ctx,
uint32_t wots_addr[8], uint32_t tree_addr[8],
uint32_t idx_leaf)
{
unsigned char *auth_path = sig + SPX_WOTS_BYTES;
struct leaf_info_x1 info = { 0 };
unsigned steps[ SPX_WOTS_LEN ];
info.wots_sig = sig;
chain_lengths(steps, root);
info.wots_steps = steps;
set_type(&tree_addr[0], SPX_ADDR_TYPE_HASHTREE);
set_type(&info.pk_addr[0], SPX_ADDR_TYPE_WOTSPK);
copy_subtree_addr(&info.leaf_addr[0], wots_addr);
copy_subtree_addr(&info.pk_addr[0], wots_addr);
info.wots_sign_leaf = idx_leaf;
treehashx1(root, auth_path, ctx,
idx_leaf, 0,
SPX_TREE_HEIGHT,
wots_gen_leafx1,
tree_addr, &info);
}
/* Compute root node of the top-most subtree. */
void merkle_gen_root(unsigned char *root, const spx_ctx *ctx)
{
/* We do not need the auth path in key generation, but it simplifies the
code to have just one treehash routine that computes both root and path
in one function. */
unsigned char auth_path[SPX_TREE_HEIGHT * SPX_N + SPX_WOTS_BYTES];
uint32_t top_tree_addr[8] = {0};
uint32_t wots_addr[8] = {0};
set_layer_addr(top_tree_addr, SPX_D - 1);
set_layer_addr(wots_addr, SPX_D - 1);
merkle_sign(auth_path, root, ctx,
wots_addr, top_tree_addr,
(uint32_t)~0 /* ~0 means "don't bother generating an auth path */ );
}

View File

@@ -1,43 +0,0 @@
/*
This code was taken from the SPHINCS reference implementation and is public domain.
*/
#include <fcntl.h>
#include <unistd.h>
#include "randombytes.h"
static int fd = -1;
void randombytes(unsigned char *x, unsigned long long xlen)
{
unsigned long long i;
if (fd == -1) {
for (;;) {
fd = open("/dev/urandom", O_RDONLY);
if (fd != -1) {
break;
}
sleep(1);
}
}
while (xlen > 0) {
if (xlen < 1048576) {
i = xlen;
}
else {
i = 1048576;
}
i = (unsigned long long)read(fd, x, i);
if (i < 1) {
sleep(1);
continue;
}
x += i;
xlen -= i;
}
}

View File

@@ -1,700 +0,0 @@
/* Based on the public domain implementation in
* crypto_hash/sha512/ref/ from http://bench.cr.yp.to/supercop.html
* by D. J. Bernstein */
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include "utils.h"
#include "sha2.h"
static uint32_t load_bigendian_32(const uint8_t *x) {
return (uint32_t)(x[3]) | (((uint32_t)(x[2])) << 8) |
(((uint32_t)(x[1])) << 16) | (((uint32_t)(x[0])) << 24);
}
static uint64_t load_bigendian_64(const uint8_t *x) {
return (uint64_t)(x[7]) | (((uint64_t)(x[6])) << 8) |
(((uint64_t)(x[5])) << 16) | (((uint64_t)(x[4])) << 24) |
(((uint64_t)(x[3])) << 32) | (((uint64_t)(x[2])) << 40) |
(((uint64_t)(x[1])) << 48) | (((uint64_t)(x[0])) << 56);
}
static void store_bigendian_32(uint8_t *x, uint64_t u) {
x[3] = (uint8_t) u;
u >>= 8;
x[2] = (uint8_t) u;
u >>= 8;
x[1] = (uint8_t) u;
u >>= 8;
x[0] = (uint8_t) u;
}
static void store_bigendian_64(uint8_t *x, uint64_t u) {
x[7] = (uint8_t) u;
u >>= 8;
x[6] = (uint8_t) u;
u >>= 8;
x[5] = (uint8_t) u;
u >>= 8;
x[4] = (uint8_t) u;
u >>= 8;
x[3] = (uint8_t) u;
u >>= 8;
x[2] = (uint8_t) u;
u >>= 8;
x[1] = (uint8_t) u;
u >>= 8;
x[0] = (uint8_t) u;
}
#define SHR(x, c) ((x) >> (c))
#define ROTR_32(x, c) (((x) >> (c)) | ((x) << (32 - (c))))
#define ROTR_64(x,c) (((x) >> (c)) | ((x) << (64 - (c))))
#define Ch(x, y, z) (((x) & (y)) ^ (~(x) & (z)))
#define Maj(x, y, z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)))
#define Sigma0_32(x) (ROTR_32(x, 2) ^ ROTR_32(x,13) ^ ROTR_32(x,22))
#define Sigma1_32(x) (ROTR_32(x, 6) ^ ROTR_32(x,11) ^ ROTR_32(x,25))
#define sigma0_32(x) (ROTR_32(x, 7) ^ ROTR_32(x,18) ^ SHR(x, 3))
#define sigma1_32(x) (ROTR_32(x,17) ^ ROTR_32(x,19) ^ SHR(x,10))
#define Sigma0_64(x) (ROTR_64(x,28) ^ ROTR_64(x,34) ^ ROTR_64(x,39))
#define Sigma1_64(x) (ROTR_64(x,14) ^ ROTR_64(x,18) ^ ROTR_64(x,41))
#define sigma0_64(x) (ROTR_64(x, 1) ^ ROTR_64(x, 8) ^ SHR(x,7))
#define sigma1_64(x) (ROTR_64(x,19) ^ ROTR_64(x,61) ^ SHR(x,6))
#define M_32(w0, w14, w9, w1) w0 = sigma1_32(w14) + (w9) + sigma0_32(w1) + (w0);
#define M_64(w0, w14, w9, w1) w0 = sigma1_64(w14) + (w9) + sigma0_64(w1) + (w0);
#define EXPAND_32 \
M_32(w0, w14, w9, w1) \
M_32(w1, w15, w10, w2) \
M_32(w2, w0, w11, w3) \
M_32(w3, w1, w12, w4) \
M_32(w4, w2, w13, w5) \
M_32(w5, w3, w14, w6) \
M_32(w6, w4, w15, w7) \
M_32(w7, w5, w0, w8) \
M_32(w8, w6, w1, w9) \
M_32(w9, w7, w2, w10) \
M_32(w10, w8, w3, w11) \
M_32(w11, w9, w4, w12) \
M_32(w12, w10, w5, w13) \
M_32(w13, w11, w6, w14) \
M_32(w14, w12, w7, w15) \
M_32(w15, w13, w8, w0)
#define EXPAND_64 \
M_64(w0 ,w14,w9 ,w1 ) \
M_64(w1 ,w15,w10,w2 ) \
M_64(w2 ,w0 ,w11,w3 ) \
M_64(w3 ,w1 ,w12,w4 ) \
M_64(w4 ,w2 ,w13,w5 ) \
M_64(w5 ,w3 ,w14,w6 ) \
M_64(w6 ,w4 ,w15,w7 ) \
M_64(w7 ,w5 ,w0 ,w8 ) \
M_64(w8 ,w6 ,w1 ,w9 ) \
M_64(w9 ,w7 ,w2 ,w10) \
M_64(w10,w8 ,w3 ,w11) \
M_64(w11,w9 ,w4 ,w12) \
M_64(w12,w10,w5 ,w13) \
M_64(w13,w11,w6 ,w14) \
M_64(w14,w12,w7 ,w15) \
M_64(w15,w13,w8 ,w0 )
#define F_32(w, k) \
T1 = h + Sigma1_32(e) + Ch(e, f, g) + (k) + (w); \
T2 = Sigma0_32(a) + Maj(a, b, c); \
h = g; \
g = f; \
f = e; \
e = d + T1; \
d = c; \
c = b; \
b = a; \
a = T1 + T2;
#define F_64(w,k) \
T1 = h + Sigma1_64(e) + Ch(e,f,g) + k + w; \
T2 = Sigma0_64(a) + Maj(a,b,c); \
h = g; \
g = f; \
f = e; \
e = d + T1; \
d = c; \
c = b; \
b = a; \
a = T1 + T2;
static size_t crypto_hashblocks_sha256(uint8_t *statebytes,
const uint8_t *in, size_t inlen) {
uint32_t state[8];
uint32_t a;
uint32_t b;
uint32_t c;
uint32_t d;
uint32_t e;
uint32_t f;
uint32_t g;
uint32_t h;
uint32_t T1;
uint32_t T2;
a = load_bigendian_32(statebytes + 0);
state[0] = a;
b = load_bigendian_32(statebytes + 4);
state[1] = b;
c = load_bigendian_32(statebytes + 8);
state[2] = c;
d = load_bigendian_32(statebytes + 12);
state[3] = d;
e = load_bigendian_32(statebytes + 16);
state[4] = e;
f = load_bigendian_32(statebytes + 20);
state[5] = f;
g = load_bigendian_32(statebytes + 24);
state[6] = g;
h = load_bigendian_32(statebytes + 28);
state[7] = h;
while (inlen >= 64) {
uint32_t w0 = load_bigendian_32(in + 0);
uint32_t w1 = load_bigendian_32(in + 4);
uint32_t w2 = load_bigendian_32(in + 8);
uint32_t w3 = load_bigendian_32(in + 12);
uint32_t w4 = load_bigendian_32(in + 16);
uint32_t w5 = load_bigendian_32(in + 20);
uint32_t w6 = load_bigendian_32(in + 24);
uint32_t w7 = load_bigendian_32(in + 28);
uint32_t w8 = load_bigendian_32(in + 32);
uint32_t w9 = load_bigendian_32(in + 36);
uint32_t w10 = load_bigendian_32(in + 40);
uint32_t w11 = load_bigendian_32(in + 44);
uint32_t w12 = load_bigendian_32(in + 48);
uint32_t w13 = load_bigendian_32(in + 52);
uint32_t w14 = load_bigendian_32(in + 56);
uint32_t w15 = load_bigendian_32(in + 60);
F_32(w0, 0x428a2f98)
F_32(w1, 0x71374491)
F_32(w2, 0xb5c0fbcf)
F_32(w3, 0xe9b5dba5)
F_32(w4, 0x3956c25b)
F_32(w5, 0x59f111f1)
F_32(w6, 0x923f82a4)
F_32(w7, 0xab1c5ed5)
F_32(w8, 0xd807aa98)
F_32(w9, 0x12835b01)
F_32(w10, 0x243185be)
F_32(w11, 0x550c7dc3)
F_32(w12, 0x72be5d74)
F_32(w13, 0x80deb1fe)
F_32(w14, 0x9bdc06a7)
F_32(w15, 0xc19bf174)
EXPAND_32
F_32(w0, 0xe49b69c1)
F_32(w1, 0xefbe4786)
F_32(w2, 0x0fc19dc6)
F_32(w3, 0x240ca1cc)
F_32(w4, 0x2de92c6f)
F_32(w5, 0x4a7484aa)
F_32(w6, 0x5cb0a9dc)
F_32(w7, 0x76f988da)
F_32(w8, 0x983e5152)
F_32(w9, 0xa831c66d)
F_32(w10, 0xb00327c8)
F_32(w11, 0xbf597fc7)
F_32(w12, 0xc6e00bf3)
F_32(w13, 0xd5a79147)
F_32(w14, 0x06ca6351)
F_32(w15, 0x14292967)
EXPAND_32
F_32(w0, 0x27b70a85)
F_32(w1, 0x2e1b2138)
F_32(w2, 0x4d2c6dfc)
F_32(w3, 0x53380d13)
F_32(w4, 0x650a7354)
F_32(w5, 0x766a0abb)
F_32(w6, 0x81c2c92e)
F_32(w7, 0x92722c85)
F_32(w8, 0xa2bfe8a1)
F_32(w9, 0xa81a664b)
F_32(w10, 0xc24b8b70)
F_32(w11, 0xc76c51a3)
F_32(w12, 0xd192e819)
F_32(w13, 0xd6990624)
F_32(w14, 0xf40e3585)
F_32(w15, 0x106aa070)
EXPAND_32
F_32(w0, 0x19a4c116)
F_32(w1, 0x1e376c08)
F_32(w2, 0x2748774c)
F_32(w3, 0x34b0bcb5)
F_32(w4, 0x391c0cb3)
F_32(w5, 0x4ed8aa4a)
F_32(w6, 0x5b9cca4f)
F_32(w7, 0x682e6ff3)
F_32(w8, 0x748f82ee)
F_32(w9, 0x78a5636f)
F_32(w10, 0x84c87814)
F_32(w11, 0x8cc70208)
F_32(w12, 0x90befffa)
F_32(w13, 0xa4506ceb)
F_32(w14, 0xbef9a3f7)
F_32(w15, 0xc67178f2)
a += state[0];
b += state[1];
c += state[2];
d += state[3];
e += state[4];
f += state[5];
g += state[6];
h += state[7];
state[0] = a;
state[1] = b;
state[2] = c;
state[3] = d;
state[4] = e;
state[5] = f;
state[6] = g;
state[7] = h;
in += 64;
inlen -= 64;
}
store_bigendian_32(statebytes + 0, state[0]);
store_bigendian_32(statebytes + 4, state[1]);
store_bigendian_32(statebytes + 8, state[2]);
store_bigendian_32(statebytes + 12, state[3]);
store_bigendian_32(statebytes + 16, state[4]);
store_bigendian_32(statebytes + 20, state[5]);
store_bigendian_32(statebytes + 24, state[6]);
store_bigendian_32(statebytes + 28, state[7]);
return inlen;
}
static int crypto_hashblocks_sha512(unsigned char *statebytes,const unsigned char *in,unsigned long long inlen)
{
uint64_t state[8];
uint64_t a;
uint64_t b;
uint64_t c;
uint64_t d;
uint64_t e;
uint64_t f;
uint64_t g;
uint64_t h;
uint64_t T1;
uint64_t T2;
a = load_bigendian_64(statebytes + 0); state[0] = a;
b = load_bigendian_64(statebytes + 8); state[1] = b;
c = load_bigendian_64(statebytes + 16); state[2] = c;
d = load_bigendian_64(statebytes + 24); state[3] = d;
e = load_bigendian_64(statebytes + 32); state[4] = e;
f = load_bigendian_64(statebytes + 40); state[5] = f;
g = load_bigendian_64(statebytes + 48); state[6] = g;
h = load_bigendian_64(statebytes + 56); state[7] = h;
while (inlen >= 128) {
uint64_t w0 = load_bigendian_64(in + 0);
uint64_t w1 = load_bigendian_64(in + 8);
uint64_t w2 = load_bigendian_64(in + 16);
uint64_t w3 = load_bigendian_64(in + 24);
uint64_t w4 = load_bigendian_64(in + 32);
uint64_t w5 = load_bigendian_64(in + 40);
uint64_t w6 = load_bigendian_64(in + 48);
uint64_t w7 = load_bigendian_64(in + 56);
uint64_t w8 = load_bigendian_64(in + 64);
uint64_t w9 = load_bigendian_64(in + 72);
uint64_t w10 = load_bigendian_64(in + 80);
uint64_t w11 = load_bigendian_64(in + 88);
uint64_t w12 = load_bigendian_64(in + 96);
uint64_t w13 = load_bigendian_64(in + 104);
uint64_t w14 = load_bigendian_64(in + 112);
uint64_t w15 = load_bigendian_64(in + 120);
F_64(w0 ,0x428a2f98d728ae22ULL)
F_64(w1 ,0x7137449123ef65cdULL)
F_64(w2 ,0xb5c0fbcfec4d3b2fULL)
F_64(w3 ,0xe9b5dba58189dbbcULL)
F_64(w4 ,0x3956c25bf348b538ULL)
F_64(w5 ,0x59f111f1b605d019ULL)
F_64(w6 ,0x923f82a4af194f9bULL)
F_64(w7 ,0xab1c5ed5da6d8118ULL)
F_64(w8 ,0xd807aa98a3030242ULL)
F_64(w9 ,0x12835b0145706fbeULL)
F_64(w10,0x243185be4ee4b28cULL)
F_64(w11,0x550c7dc3d5ffb4e2ULL)
F_64(w12,0x72be5d74f27b896fULL)
F_64(w13,0x80deb1fe3b1696b1ULL)
F_64(w14,0x9bdc06a725c71235ULL)
F_64(w15,0xc19bf174cf692694ULL)
EXPAND_64
F_64(w0 ,0xe49b69c19ef14ad2ULL)
F_64(w1 ,0xefbe4786384f25e3ULL)
F_64(w2 ,0x0fc19dc68b8cd5b5ULL)
F_64(w3 ,0x240ca1cc77ac9c65ULL)
F_64(w4 ,0x2de92c6f592b0275ULL)
F_64(w5 ,0x4a7484aa6ea6e483ULL)
F_64(w6 ,0x5cb0a9dcbd41fbd4ULL)
F_64(w7 ,0x76f988da831153b5ULL)
F_64(w8 ,0x983e5152ee66dfabULL)
F_64(w9 ,0xa831c66d2db43210ULL)
F_64(w10,0xb00327c898fb213fULL)
F_64(w11,0xbf597fc7beef0ee4ULL)
F_64(w12,0xc6e00bf33da88fc2ULL)
F_64(w13,0xd5a79147930aa725ULL)
F_64(w14,0x06ca6351e003826fULL)
F_64(w15,0x142929670a0e6e70ULL)
EXPAND_64
F_64(w0 ,0x27b70a8546d22ffcULL)
F_64(w1 ,0x2e1b21385c26c926ULL)
F_64(w2 ,0x4d2c6dfc5ac42aedULL)
F_64(w3 ,0x53380d139d95b3dfULL)
F_64(w4 ,0x650a73548baf63deULL)
F_64(w5 ,0x766a0abb3c77b2a8ULL)
F_64(w6 ,0x81c2c92e47edaee6ULL)
F_64(w7 ,0x92722c851482353bULL)
F_64(w8 ,0xa2bfe8a14cf10364ULL)
F_64(w9 ,0xa81a664bbc423001ULL)
F_64(w10,0xc24b8b70d0f89791ULL)
F_64(w11,0xc76c51a30654be30ULL)
F_64(w12,0xd192e819d6ef5218ULL)
F_64(w13,0xd69906245565a910ULL)
F_64(w14,0xf40e35855771202aULL)
F_64(w15,0x106aa07032bbd1b8ULL)
EXPAND_64
F_64(w0 ,0x19a4c116b8d2d0c8ULL)
F_64(w1 ,0x1e376c085141ab53ULL)
F_64(w2 ,0x2748774cdf8eeb99ULL)
F_64(w3 ,0x34b0bcb5e19b48a8ULL)
F_64(w4 ,0x391c0cb3c5c95a63ULL)
F_64(w5 ,0x4ed8aa4ae3418acbULL)
F_64(w6 ,0x5b9cca4f7763e373ULL)
F_64(w7 ,0x682e6ff3d6b2b8a3ULL)
F_64(w8 ,0x748f82ee5defb2fcULL)
F_64(w9 ,0x78a5636f43172f60ULL)
F_64(w10,0x84c87814a1f0ab72ULL)
F_64(w11,0x8cc702081a6439ecULL)
F_64(w12,0x90befffa23631e28ULL)
F_64(w13,0xa4506cebde82bde9ULL)
F_64(w14,0xbef9a3f7b2c67915ULL)
F_64(w15,0xc67178f2e372532bULL)
EXPAND_64
F_64(w0 ,0xca273eceea26619cULL)
F_64(w1 ,0xd186b8c721c0c207ULL)
F_64(w2 ,0xeada7dd6cde0eb1eULL)
F_64(w3 ,0xf57d4f7fee6ed178ULL)
F_64(w4 ,0x06f067aa72176fbaULL)
F_64(w5 ,0x0a637dc5a2c898a6ULL)
F_64(w6 ,0x113f9804bef90daeULL)
F_64(w7 ,0x1b710b35131c471bULL)
F_64(w8 ,0x28db77f523047d84ULL)
F_64(w9 ,0x32caab7b40c72493ULL)
F_64(w10,0x3c9ebe0a15c9bebcULL)
F_64(w11,0x431d67c49c100d4cULL)
F_64(w12,0x4cc5d4becb3e42b6ULL)
F_64(w13,0x597f299cfc657e2aULL)
F_64(w14,0x5fcb6fab3ad6faecULL)
F_64(w15,0x6c44198c4a475817ULL)
a += state[0];
b += state[1];
c += state[2];
d += state[3];
e += state[4];
f += state[5];
g += state[6];
h += state[7];
state[0] = a;
state[1] = b;
state[2] = c;
state[3] = d;
state[4] = e;
state[5] = f;
state[6] = g;
state[7] = h;
in += 128;
inlen -= 128;
}
store_bigendian_64(statebytes + 0,state[0]);
store_bigendian_64(statebytes + 8,state[1]);
store_bigendian_64(statebytes + 16,state[2]);
store_bigendian_64(statebytes + 24,state[3]);
store_bigendian_64(statebytes + 32,state[4]);
store_bigendian_64(statebytes + 40,state[5]);
store_bigendian_64(statebytes + 48,state[6]);
store_bigendian_64(statebytes + 56,state[7]);
return inlen;
}
static const uint8_t iv_256[32] = {
0x6a, 0x09, 0xe6, 0x67, 0xbb, 0x67, 0xae, 0x85,
0x3c, 0x6e, 0xf3, 0x72, 0xa5, 0x4f, 0xf5, 0x3a,
0x51, 0x0e, 0x52, 0x7f, 0x9b, 0x05, 0x68, 0x8c,
0x1f, 0x83, 0xd9, 0xab, 0x5b, 0xe0, 0xcd, 0x19
};
static const uint8_t iv_512[64] = {
0x6a, 0x09, 0xe6, 0x67, 0xf3, 0xbc, 0xc9, 0x08, 0xbb, 0x67, 0xae,
0x85, 0x84, 0xca, 0xa7, 0x3b, 0x3c, 0x6e, 0xf3, 0x72, 0xfe, 0x94,
0xf8, 0x2b, 0xa5, 0x4f, 0xf5, 0x3a, 0x5f, 0x1d, 0x36, 0xf1, 0x51,
0x0e, 0x52, 0x7f, 0xad, 0xe6, 0x82, 0xd1, 0x9b, 0x05, 0x68, 0x8c,
0x2b, 0x3e, 0x6c, 0x1f, 0x1f, 0x83, 0xd9, 0xab, 0xfb, 0x41, 0xbd,
0x6b, 0x5b, 0xe0, 0xcd, 0x19, 0x13, 0x7e, 0x21, 0x79
};
void sha256_inc_init(uint8_t *state) {
for (size_t i = 0; i < 32; ++i) {
state[i] = iv_256[i];
}
for (size_t i = 32; i < 40; ++i) {
state[i] = 0;
}
}
void sha512_inc_init(uint8_t *state) {
for (size_t i = 0; i < 64; ++i) {
state[i] = iv_512[i];
}
for (size_t i = 64; i < 72; ++i) {
state[i] = 0;
}
}
void sha256_inc_blocks(uint8_t *state, const uint8_t *in, size_t inblocks) {
uint64_t bytes = load_bigendian_64(state + 32);
crypto_hashblocks_sha256(state, in, 64 * inblocks);
bytes += 64 * inblocks;
store_bigendian_64(state + 32, bytes);
}
void sha512_inc_blocks(uint8_t *state, const uint8_t *in, size_t inblocks) {
uint64_t bytes = load_bigendian_64(state + 64);
crypto_hashblocks_sha512(state, in, 128 * inblocks);
bytes += 128 * inblocks;
store_bigendian_64(state + 64, bytes);
}
void sha256_inc_finalize(uint8_t *out, uint8_t *state, const uint8_t *in, size_t inlen) {
uint8_t padded[128];
uint64_t bytes = load_bigendian_64(state + 32) + inlen;
crypto_hashblocks_sha256(state, in, inlen);
in += inlen;
inlen &= 63;
in -= inlen;
for (size_t i = 0; i < inlen; ++i) {
padded[i] = in[i];
}
padded[inlen] = 0x80;
if (inlen < 56) {
for (size_t i = inlen + 1; i < 56; ++i) {
padded[i] = 0;
}
padded[56] = (uint8_t) (bytes >> 53);
padded[57] = (uint8_t) (bytes >> 45);
padded[58] = (uint8_t) (bytes >> 37);
padded[59] = (uint8_t) (bytes >> 29);
padded[60] = (uint8_t) (bytes >> 21);
padded[61] = (uint8_t) (bytes >> 13);
padded[62] = (uint8_t) (bytes >> 5);
padded[63] = (uint8_t) (bytes << 3);
crypto_hashblocks_sha256(state, padded, 64);
} else {
for (size_t i = inlen + 1; i < 120; ++i) {
padded[i] = 0;
}
padded[120] = (uint8_t) (bytes >> 53);
padded[121] = (uint8_t) (bytes >> 45);
padded[122] = (uint8_t) (bytes >> 37);
padded[123] = (uint8_t) (bytes >> 29);
padded[124] = (uint8_t) (bytes >> 21);
padded[125] = (uint8_t) (bytes >> 13);
padded[126] = (uint8_t) (bytes >> 5);
padded[127] = (uint8_t) (bytes << 3);
crypto_hashblocks_sha256(state, padded, 128);
}
for (size_t i = 0; i < 32; ++i) {
out[i] = state[i];
}
}
void sha512_inc_finalize(uint8_t *out, uint8_t *state, const uint8_t *in, size_t inlen) {
uint8_t padded[256];
uint64_t bytes = load_bigendian_64(state + 64) + inlen;
crypto_hashblocks_sha512(state, in, inlen);
in += inlen;
inlen &= 127;
in -= inlen;
for (size_t i = 0; i < inlen; ++i) {
padded[i] = in[i];
}
padded[inlen] = 0x80;
if (inlen < 112) {
for (size_t i = inlen + 1; i < 119; ++i) {
padded[i] = 0;
}
padded[119] = (uint8_t) (bytes >> 61);
padded[120] = (uint8_t) (bytes >> 53);
padded[121] = (uint8_t) (bytes >> 45);
padded[122] = (uint8_t) (bytes >> 37);
padded[123] = (uint8_t) (bytes >> 29);
padded[124] = (uint8_t) (bytes >> 21);
padded[125] = (uint8_t) (bytes >> 13);
padded[126] = (uint8_t) (bytes >> 5);
padded[127] = (uint8_t) (bytes << 3);
crypto_hashblocks_sha512(state, padded, 128);
} else {
for (size_t i = inlen + 1; i < 247; ++i) {
padded[i] = 0;
}
padded[247] = (uint8_t) (bytes >> 61);
padded[248] = (uint8_t) (bytes >> 53);
padded[249] = (uint8_t) (bytes >> 45);
padded[250] = (uint8_t) (bytes >> 37);
padded[251] = (uint8_t) (bytes >> 29);
padded[252] = (uint8_t) (bytes >> 21);
padded[253] = (uint8_t) (bytes >> 13);
padded[254] = (uint8_t) (bytes >> 5);
padded[255] = (uint8_t) (bytes << 3);
crypto_hashblocks_sha512(state, padded, 256);
}
for (size_t i = 0; i < 64; ++i) {
out[i] = state[i];
}
}
void sha256(uint8_t *out, const uint8_t *in, size_t inlen) {
uint8_t state[40];
sha256_inc_init(state);
sha256_inc_finalize(out, state, in, inlen);
}
void sha512(uint8_t *out, const uint8_t *in, size_t inlen) {
uint8_t state[72];
sha512_inc_init(state);
sha512_inc_finalize(out, state, in, inlen);
}
/**
* mgf1 function based on the SHA-256 hash function
* Note that inlen should be sufficiently small that it still allows for
* an array to be allocated on the stack. Typically 'in' is merely a seed.
* Outputs outlen number of bytes
*/
void mgf1_256(unsigned char *out, unsigned long outlen,
const unsigned char *in, unsigned long inlen)
{
SPX_VLA(uint8_t, inbuf, inlen+4);
unsigned char outbuf[SPX_SHA256_OUTPUT_BYTES];
unsigned long i;
memcpy(inbuf, in, inlen);
/* While we can fit in at least another full block of SHA256 output.. */
for (i = 0; (i+1)*SPX_SHA256_OUTPUT_BYTES <= outlen; i++) {
u32_to_bytes(inbuf + inlen, i);
sha256(out, inbuf, inlen + 4);
out += SPX_SHA256_OUTPUT_BYTES;
}
/* Until we cannot anymore, and we fill the remainder. */
if (outlen > i*SPX_SHA256_OUTPUT_BYTES) {
u32_to_bytes(inbuf + inlen, i);
sha256(outbuf, inbuf, inlen + 4);
memcpy(out, outbuf, outlen - i*SPX_SHA256_OUTPUT_BYTES);
}
}
/*
* mgf1 function based on the SHA-512 hash function
*/
void mgf1_512(unsigned char *out, unsigned long outlen,
const unsigned char *in, unsigned long inlen)
{
SPX_VLA(uint8_t, inbuf, inlen+4);
unsigned char outbuf[SPX_SHA512_OUTPUT_BYTES];
unsigned long i;
memcpy(inbuf, in, inlen);
/* While we can fit in at least another full block of SHA512 output.. */
for (i = 0; (i+1)*SPX_SHA512_OUTPUT_BYTES <= outlen; i++) {
u32_to_bytes(inbuf + inlen, i);
sha512(out, inbuf, inlen + 4);
out += SPX_SHA512_OUTPUT_BYTES;
}
/* Until we cannot anymore, and we fill the remainder. */
if (outlen > i*SPX_SHA512_OUTPUT_BYTES) {
u32_to_bytes(inbuf + inlen, i);
sha512(outbuf, inbuf, inlen + 4);
memcpy(out, outbuf, outlen - i*SPX_SHA512_OUTPUT_BYTES);
}
}
/**
* Absorb the constant pub_seed using one round of the compression function
* This initializes state_seeded and state_seeded_512, which can then be
* reused in thash
**/
void seed_state(spx_ctx *ctx) {
uint8_t block[SPX_SHA512_BLOCK_BYTES];
size_t i;
for (i = 0; i < SPX_N; ++i) {
block[i] = ctx->pub_seed[i];
}
for (i = SPX_N; i < SPX_SHA512_BLOCK_BYTES; ++i) {
block[i] = 0;
}
/* block has been properly initialized for both SHA-256 and SHA-512 */
sha256_inc_init(ctx->state_seeded);
sha256_inc_blocks(ctx->state_seeded, block, 1);
#if SPX_SHA512
sha512_inc_init(ctx->state_seeded_512);
sha512_inc_blocks(ctx->state_seeded_512, block, 1);
#endif
}

View File

@@ -1,190 +0,0 @@
// sha3.c
// 19-Nov-11 Markku-Juhani O. Saarinen <mjos@iki.fi>
// Revised 07-Aug-15 to match with official release of FIPS PUB 202 "SHA3"
// Revised 03-Sep-15 for portability + OpenSSL - style API
#include "sha3.h"
// update the state with given number of rounds
void sha3_keccakf(uint64_t st[25])
{
// constants
const uint64_t keccakf_rndc[24] = {
0x0000000000000001, 0x0000000000008082, 0x800000000000808a,
0x8000000080008000, 0x000000000000808b, 0x0000000080000001,
0x8000000080008081, 0x8000000000008009, 0x000000000000008a,
0x0000000000000088, 0x0000000080008009, 0x000000008000000a,
0x000000008000808b, 0x800000000000008b, 0x8000000000008089,
0x8000000000008003, 0x8000000000008002, 0x8000000000000080,
0x000000000000800a, 0x800000008000000a, 0x8000000080008081,
0x8000000000008080, 0x0000000080000001, 0x8000000080008008
};
const int keccakf_rotc[24] = {
1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 2, 14,
27, 41, 56, 8, 25, 43, 62, 18, 39, 61, 20, 44
};
const int keccakf_piln[24] = {
10, 7, 11, 17, 18, 3, 5, 16, 8, 21, 24, 4,
15, 23, 19, 13, 12, 2, 20, 14, 22, 9, 6, 1
};
// variables
int i, j, r;
uint64_t t, bc[5];
#if __BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__
uint8_t *v;
// endianess conversion. this is redundant on little-endian targets
for (i = 0; i < 25; i++) {
v = (uint8_t *) &st[i];
st[i] = ((uint64_t) v[0]) | (((uint64_t) v[1]) << 8) |
(((uint64_t) v[2]) << 16) | (((uint64_t) v[3]) << 24) |
(((uint64_t) v[4]) << 32) | (((uint64_t) v[5]) << 40) |
(((uint64_t) v[6]) << 48) | (((uint64_t) v[7]) << 56);
}
#endif
// actual iteration
for (r = 0; r < KECCAKF_ROUNDS; r++) {
// Theta
for (i = 0; i < 5; i++)
bc[i] = st[i] ^ st[i + 5] ^ st[i + 10] ^ st[i + 15] ^ st[i + 20];
for (i = 0; i < 5; i++) {
t = bc[(i + 4) % 5] ^ ROTL64(bc[(i + 1) % 5], 1);
for (j = 0; j < 25; j += 5)
st[j + i] ^= t;
}
// Rho Pi
t = st[1];
for (i = 0; i < 24; i++) {
j = keccakf_piln[i];
bc[0] = st[j];
st[j] = ROTL64(t, keccakf_rotc[i]);
t = bc[0];
}
// Chi
for (j = 0; j < 25; j += 5) {
for (i = 0; i < 5; i++)
bc[i] = st[j + i];
for (i = 0; i < 5; i++)
st[j + i] ^= (~bc[(i + 1) % 5]) & bc[(i + 2) % 5];
}
// Iota
st[0] ^= keccakf_rndc[r];
}
#if __BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__
// endianess conversion. this is redundant on little-endian targets
for (i = 0; i < 25; i++) {
v = (uint8_t *) &st[i];
t = st[i];
v[0] = t & 0xFF;
v[1] = (t >> 8) & 0xFF;
v[2] = (t >> 16) & 0xFF;
v[3] = (t >> 24) & 0xFF;
v[4] = (t >> 32) & 0xFF;
v[5] = (t >> 40) & 0xFF;
v[6] = (t >> 48) & 0xFF;
v[7] = (t >> 56) & 0xFF;
}
#endif
}
// Initialize the context for SHA3
int sha3_init(sha3_ctx_t *c, int mdlen)
{
int i;
for (i = 0; i < 25; i++)
c->st.q[i] = 0;
c->mdlen = mdlen;
c->rsiz = 200 - 2 * mdlen;
c->pt = 0;
return 1;
}
// update state with more data
int sha3_update(sha3_ctx_t *c, const void *data, size_t len)
{
size_t i;
int j;
j = c->pt;
for (i = 0; i < len; i++) {
c->st.b[j++] ^= ((const uint8_t *) data)[i];
if (j >= c->rsiz) {
sha3_keccakf(c->st.q);
j = 0;
}
}
c->pt = j;
return 1;
}
// finalize and output a hash
int sha3_final(void *md, sha3_ctx_t *c)
{
int i;
c->st.b[c->pt] ^= 0x06;
c->st.b[c->rsiz - 1] ^= 0x80;
sha3_keccakf(c->st.q);
for (i = 0; i < c->mdlen; i++) {
((uint8_t *) md)[i] = c->st.b[i];
}
return 1;
}
// compute a SHA-3 hash (md) of given byte length from "in"
void *sha3(const void *in, size_t inlen, void *md, int mdlen)
{
sha3_ctx_t sha3;
sha3_init(&sha3, mdlen);
sha3_update(&sha3, in, inlen);
sha3_final(md, &sha3);
return md;
}
// SHAKE128 and SHAKE256 extensible-output functionality
void shake_xof(sha3_ctx_t *c)
{
c->st.b[c->pt] ^= 0x1F;
c->st.b[c->rsiz - 1] ^= 0x80;
sha3_keccakf(c->st.q);
c->pt = 0;
}
void shake_out(sha3_ctx_t *c, void *out, size_t len)
{
size_t i;
int j;
j = c->pt;
for (i = 0; i < len; i++) {
if (j >= c->rsiz) {
sha3_keccakf(c->st.q);
j = 0;
}
((uint8_t *) out)[i] = c->st.b[j++];
}
c->pt = j;
}

View File

@@ -1,287 +0,0 @@
#include <stddef.h>
#include <string.h>
#include <stdint.h>
#include "api.h"
#include "params.h"
#include "wots.h"
#include "fors.h"
#include "hash.h"
#include "thash.h"
#include "address.h"
#include "randombytes.h"
#include "utils.h"
#include "merkle.h"
/*
* Returns the length of a secret key, in bytes
*/
unsigned long long crypto_sign_secretkeybytes(void)
{
return CRYPTO_SECRETKEYBYTES;
}
/*
* Returns the length of a public key, in bytes
*/
unsigned long long crypto_sign_publickeybytes(void)
{
return CRYPTO_PUBLICKEYBYTES;
}
/*
* Returns the length of a signature, in bytes
*/
unsigned long long crypto_sign_bytes(void)
{
return CRYPTO_BYTES;
}
/*
* Returns the length of the seed required to generate a key pair, in bytes
*/
unsigned long long crypto_sign_seedbytes(void)
{
return CRYPTO_SEEDBYTES;
}
/*
* Generates an SPX key pair given a seed of length
* Format sk: [SK_SEED || SK_PRF || PUB_SEED || root]
* Format pk: [PUB_SEED || root]
*/
int crypto_sign_seed_keypair(unsigned char *pk, unsigned char *sk,
const unsigned char *seed)
{
spx_ctx ctx;
/* Initialize SK_SEED, SK_PRF and PUB_SEED from seed. */
memcpy(sk, seed, CRYPTO_SEEDBYTES);
memcpy(pk, sk + 2*SPX_N, SPX_N);
memcpy(ctx.pub_seed, pk, SPX_N);
memcpy(ctx.sk_seed, sk, SPX_N);
/* This hook allows the hash function instantiation to do whatever
preparation or computation it needs, based on the public seed. */
initialize_hash_function(&ctx);
/* Compute root node of the top-most subtree. */
merkle_gen_root(sk + 3*SPX_N, &ctx);
memcpy(pk + SPX_N, sk + 3*SPX_N, SPX_N);
return 0;
}
/*
* Generates an SPX key pair.
* Format sk: [SK_SEED || SK_PRF || PUB_SEED || root]
* Format pk: [PUB_SEED || root]
*/
int crypto_sign_keypair(unsigned char *pk, unsigned char *sk)
{
unsigned char seed[CRYPTO_SEEDBYTES];
randombytes(seed, CRYPTO_SEEDBYTES);
crypto_sign_seed_keypair(pk, sk, seed);
return 0;
}
/**
* Returns an array containing a detached signature.
*/
int crypto_sign_signature(uint8_t *sig, size_t *siglen,
const uint8_t *m, size_t mlen, const uint8_t *sk)
{
spx_ctx ctx;
const unsigned char *sk_prf = sk + SPX_N;
const unsigned char *pk = sk + 2*SPX_N;
unsigned char optrand[SPX_N];
unsigned char mhash[SPX_FORS_MSG_BYTES];
unsigned char root[SPX_N];
uint32_t i;
uint64_t tree;
uint32_t idx_leaf;
uint32_t wots_addr[8] = {0};
uint32_t tree_addr[8] = {0};
memcpy(ctx.sk_seed, sk, SPX_N);
memcpy(ctx.pub_seed, pk, SPX_N);
/* This hook allows the hash function instantiation to do whatever
preparation or computation it needs, based on the public seed. */
initialize_hash_function(&ctx);
set_type(wots_addr, SPX_ADDR_TYPE_WOTS);
set_type(tree_addr, SPX_ADDR_TYPE_HASHTREE);
/* Optionally, signing can be made non-deterministic using optrand.
This can help counter side-channel attacks that would benefit from
getting a large number of traces when the signer uses the same nodes. */
randombytes(optrand, SPX_N);
/* Compute the digest randomization value. */
gen_message_random(sig, sk_prf, optrand, m, mlen, &ctx);
/* Derive the message digest and leaf index from R, PK and M. */
hash_message(mhash, &tree, &idx_leaf, sig, pk, m, mlen, &ctx);
sig += SPX_N;
set_tree_addr(wots_addr, tree);
set_keypair_addr(wots_addr, idx_leaf);
/* Sign the message hash using FORS. */
fors_sign(sig, root, mhash, &ctx, wots_addr);
sig += SPX_FORS_BYTES;
for (i = 0; i < SPX_D; i++) {
set_layer_addr(tree_addr, i);
set_tree_addr(tree_addr, tree);
copy_subtree_addr(wots_addr, tree_addr);
set_keypair_addr(wots_addr, idx_leaf);
merkle_sign(sig, root, &ctx, wots_addr, tree_addr, idx_leaf);
sig += SPX_WOTS_BYTES + SPX_TREE_HEIGHT * SPX_N;
/* Update the indices for the next layer. */
idx_leaf = (tree & ((1 << SPX_TREE_HEIGHT)-1));
tree = tree >> SPX_TREE_HEIGHT;
}
*siglen = SPX_BYTES;
return 0;
}
/**
* Verifies a detached signature and message under a given public key.
*/
int crypto_sign_verify(const uint8_t *sig, size_t siglen,
const uint8_t *m, size_t mlen, const uint8_t *pk)
{
spx_ctx ctx;
const unsigned char *pub_root = pk + SPX_N;
unsigned char mhash[SPX_FORS_MSG_BYTES];
unsigned char wots_pk[SPX_WOTS_BYTES];
unsigned char root[SPX_N];
unsigned char leaf[SPX_N];
unsigned int i;
uint64_t tree;
uint32_t idx_leaf;
uint32_t wots_addr[8] = {0};
uint32_t tree_addr[8] = {0};
uint32_t wots_pk_addr[8] = {0};
if (siglen != SPX_BYTES) {
return -1;
}
memcpy(ctx.pub_seed, pk, SPX_N);
/* This hook allows the hash function instantiation to do whatever
preparation or computation it needs, based on the public seed. */
initialize_hash_function(&ctx);
set_type(wots_addr, SPX_ADDR_TYPE_WOTS);
set_type(tree_addr, SPX_ADDR_TYPE_HASHTREE);
set_type(wots_pk_addr, SPX_ADDR_TYPE_WOTSPK);
/* Derive the message digest and leaf index from R || PK || M. */
/* The additional SPX_N is a result of the hash domain separator. */
hash_message(mhash, &tree, &idx_leaf, sig, pk, m, mlen, &ctx);
sig += SPX_N;
/* Layer correctly defaults to 0, so no need to set_layer_addr */
set_tree_addr(wots_addr, tree);
set_keypair_addr(wots_addr, idx_leaf);
fors_pk_from_sig(root, sig, mhash, &ctx, wots_addr);
sig += SPX_FORS_BYTES;
/* For each subtree.. */
for (i = 0; i < SPX_D; i++) {
set_layer_addr(tree_addr, i);
set_tree_addr(tree_addr, tree);
copy_subtree_addr(wots_addr, tree_addr);
set_keypair_addr(wots_addr, idx_leaf);
copy_keypair_addr(wots_pk_addr, wots_addr);
/* The WOTS public key is only correct if the signature was correct. */
/* Initially, root is the FORS pk, but on subsequent iterations it is
the root of the subtree below the currently processed subtree. */
wots_pk_from_sig(wots_pk, sig, root, &ctx, wots_addr);
sig += SPX_WOTS_BYTES;
/* Compute the leaf node using the WOTS public key. */
thash(leaf, wots_pk, SPX_WOTS_LEN, &ctx, wots_pk_addr);
/* Compute the root node of this subtree. */
compute_root(root, leaf, idx_leaf, 0, sig, SPX_TREE_HEIGHT,
&ctx, tree_addr);
sig += SPX_TREE_HEIGHT * SPX_N;
/* Update the indices for the next layer. */
idx_leaf = (tree & ((1 << SPX_TREE_HEIGHT)-1));
tree = tree >> SPX_TREE_HEIGHT;
}
/* Check if the root node equals the root node in the public key. */
if (memcmp(root, pub_root, SPX_N)) {
return -1;
}
return 0;
}
/**
* Returns an array containing the signature followed by the message.
*/
int crypto_sign(unsigned char *sm, unsigned long long *smlen,
const unsigned char *m, unsigned long long mlen,
const unsigned char *sk)
{
size_t siglen;
crypto_sign_signature(sm, &siglen, m, (size_t)mlen, sk);
memmove(sm + SPX_BYTES, m, mlen);
*smlen = siglen + mlen;
return 0;
}
/**
* Verifies a given signature-message pair under a given public key.
*/
int crypto_sign_open(unsigned char *m, unsigned long long *mlen,
const unsigned char *sm, unsigned long long smlen,
const unsigned char *pk)
{
/* The API caller does not necessarily know what size a signature should be
but SPHINCS+ signatures are always exactly SPX_BYTES. */
if (smlen < SPX_BYTES) {
memset(m, 0, smlen);
*mlen = 0;
return -1;
}
*mlen = smlen - SPX_BYTES;
if (crypto_sign_verify(sm, SPX_BYTES, sm + SPX_BYTES, (size_t)*mlen, pk)) {
memset(m, 0, smlen);
*mlen = 0;
return -1;
}
/* If verification was successful, move the message to the right place. */
memmove(m, sm + SPX_BYTES, *mlen);
return 0;
}

View File

@@ -1,74 +0,0 @@
#include <stdint.h>
#include <string.h>
#include "thash.h"
#include "address.h"
#include "params.h"
#include "utils.h"
#include "sha2.h"
#if SPX_SHA512
static void thash_512(unsigned char *out, const unsigned char *in, unsigned int inblocks,
const spx_ctx *ctx, uint32_t addr[8]);
#endif
/**
* Takes an array of inblocks concatenated arrays of SPX_N bytes.
*/
void thash(unsigned char *out, const unsigned char *in, unsigned int inblocks,
const spx_ctx *ctx, uint32_t addr[8])
{
#if SPX_SHA512
if (inblocks > 1) {
thash_512(out, in, inblocks, ctx, addr);
return;
}
#endif
unsigned char outbuf[SPX_SHA256_OUTPUT_BYTES];
SPX_VLA(uint8_t, bitmask, inblocks * SPX_N);
SPX_VLA(uint8_t, buf, SPX_N + SPX_SHA256_OUTPUT_BYTES + inblocks*SPX_N);
uint8_t sha2_state[40];
unsigned int i;
memcpy(buf, ctx->pub_seed, SPX_N);
memcpy(buf + SPX_N, addr, SPX_SHA256_ADDR_BYTES);
mgf1_256(bitmask, inblocks * SPX_N, buf, SPX_N + SPX_SHA256_ADDR_BYTES);
/* Retrieve precomputed state containing pub_seed */
memcpy(sha2_state, ctx->state_seeded, 40 * sizeof(uint8_t));
for (i = 0; i < inblocks * SPX_N; i++) {
buf[SPX_N + SPX_SHA256_ADDR_BYTES + i] = in[i] ^ bitmask[i];
}
sha256_inc_finalize(outbuf, sha2_state, buf + SPX_N,
SPX_SHA256_ADDR_BYTES + inblocks*SPX_N);
memcpy(out, outbuf, SPX_N);
}
#if SPX_SHA512
static void thash_512(unsigned char *out, const unsigned char *in, unsigned int inblocks,
const spx_ctx *ctx, uint32_t addr[8])
{
unsigned char outbuf[SPX_SHA512_OUTPUT_BYTES];
SPX_VLA(uint8_t, bitmask, inblocks * SPX_N);
SPX_VLA(uint8_t, buf, SPX_N + SPX_SHA256_ADDR_BYTES + inblocks*SPX_N);
uint8_t sha2_state[72];
unsigned int i;
memcpy(buf, ctx->pub_seed, SPX_N);
memcpy(buf + SPX_N, addr, SPX_SHA256_ADDR_BYTES);
mgf1_512(bitmask, inblocks * SPX_N, buf, SPX_N + SPX_SHA256_ADDR_BYTES);
/* Retrieve precomputed state containing pub_seed */
memcpy(sha2_state, ctx->state_seeded_512, 72 * sizeof(uint8_t));
for (i = 0; i < inblocks * SPX_N; i++) {
buf[SPX_N + SPX_SHA256_ADDR_BYTES + i] = in[i] ^ bitmask[i];
}
sha512_inc_finalize(outbuf, sha2_state, buf + SPX_N,
SPX_SHA256_ADDR_BYTES + inblocks*SPX_N);
memcpy(out, outbuf, SPX_N);
}
#endif

View File

@@ -1,59 +0,0 @@
#include <stdint.h>
#include <string.h>
#include "thash.h"
#include "address.h"
#include "params.h"
#include "utils.h"
#include "sha2.h"
#if SPX_SHA512
static void thash_512(unsigned char *out, const unsigned char *in, unsigned int inblocks,
const spx_ctx *ctx, uint32_t addr[8]);
#endif
/**
* Takes an array of inblocks concatenated arrays of SPX_N bytes.
*/
void thash(unsigned char *out, const unsigned char *in, unsigned int inblocks,
const spx_ctx *ctx, uint32_t addr[8])
{
#if SPX_SHA512
if (inblocks > 1) {
thash_512(out, in, inblocks, ctx, addr);
return;
}
#endif
unsigned char outbuf[SPX_SHA256_OUTPUT_BYTES];
uint8_t sha2_state[40];
SPX_VLA(uint8_t, buf, SPX_SHA256_ADDR_BYTES + inblocks*SPX_N);
/* Retrieve precomputed state containing pub_seed */
memcpy(sha2_state, ctx->state_seeded, 40 * sizeof(uint8_t));
memcpy(buf, addr, SPX_SHA256_ADDR_BYTES);
memcpy(buf + SPX_SHA256_ADDR_BYTES, in, inblocks * SPX_N);
sha256_inc_finalize(outbuf, sha2_state, buf, SPX_SHA256_ADDR_BYTES + inblocks*SPX_N);
memcpy(out, outbuf, SPX_N);
}
#if SPX_SHA512
static void thash_512(unsigned char *out, const unsigned char *in, unsigned int inblocks,
const spx_ctx *ctx, uint32_t addr[8])
{
unsigned char outbuf[SPX_SHA512_OUTPUT_BYTES];
uint8_t sha2_state[72];
SPX_VLA(uint8_t, buf, SPX_SHA256_ADDR_BYTES + inblocks*SPX_N);
/* Retrieve precomputed state containing pub_seed */
memcpy(sha2_state, ctx->state_seeded_512, 72 * sizeof(uint8_t));
memcpy(buf, addr, SPX_SHA256_ADDR_BYTES);
memcpy(buf + SPX_SHA256_ADDR_BYTES, in, inblocks * SPX_N);
sha512_inc_finalize(outbuf, sha2_state, buf, SPX_SHA256_ADDR_BYTES + inblocks*SPX_N);
memcpy(out, outbuf, SPX_N);
}
#endif

View File

@@ -1,154 +0,0 @@
#include <string.h>
#include "utils.h"
#include "params.h"
#include "hash.h"
#include "thash.h"
#include "address.h"
/**
* Converts the value of 'in' to 'outlen' bytes in big-endian byte order.
*/
void ull_to_bytes(unsigned char *out, unsigned int outlen,
unsigned long long in)
{
int i;
/* Iterate over out in decreasing order, for big-endianness. */
for (i = (signed int)outlen - 1; i >= 0; i--) {
out[i] = in & 0xff;
in = in >> 8;
}
}
void u32_to_bytes(unsigned char *out, uint32_t in)
{
out[0] = (unsigned char)(in >> 24);
out[1] = (unsigned char)(in >> 16);
out[2] = (unsigned char)(in >> 8);
out[3] = (unsigned char)in;
}
/**
* Converts the inlen bytes in 'in' from big-endian byte order to an integer.
*/
unsigned long long bytes_to_ull(const unsigned char *in, unsigned int inlen)
{
unsigned long long retval = 0;
unsigned int i;
for (i = 0; i < inlen; i++) {
retval |= ((unsigned long long)in[i]) << (8*(inlen - 1 - i));
}
return retval;
}
/**
* Computes a root node given a leaf and an auth path.
* Expects address to be complete other than the tree_height and tree_index.
*/
void compute_root(unsigned char *root, const unsigned char *leaf,
uint32_t leaf_idx, uint32_t idx_offset,
const unsigned char *auth_path, uint32_t tree_height,
const spx_ctx *ctx, uint32_t addr[8])
{
uint32_t i;
unsigned char buffer[2 * SPX_N];
/* If leaf_idx is odd (last bit = 1), current path element is a right child
and auth_path has to go left. Otherwise it is the other way around. */
if (leaf_idx & 1) {
memcpy(buffer + SPX_N, leaf, SPX_N);
memcpy(buffer, auth_path, SPX_N);
}
else {
memcpy(buffer, leaf, SPX_N);
memcpy(buffer + SPX_N, auth_path, SPX_N);
}
auth_path += SPX_N;
for (i = 0; i < tree_height - 1; i++) {
leaf_idx >>= 1;
idx_offset >>= 1;
/* Set the address of the node we're creating. */
set_tree_height(addr, i + 1);
set_tree_index(addr, leaf_idx + idx_offset);
/* Pick the right or left neighbor, depending on parity of the node. */
if (leaf_idx & 1) {
thash(buffer + SPX_N, buffer, 2, ctx, addr);
memcpy(buffer, auth_path, SPX_N);
}
else {
thash(buffer, buffer, 2, ctx, addr);
memcpy(buffer + SPX_N, auth_path, SPX_N);
}
auth_path += SPX_N;
}
/* The last iteration is exceptional; we do not copy an auth_path node. */
leaf_idx >>= 1;
idx_offset >>= 1;
set_tree_height(addr, tree_height);
set_tree_index(addr, leaf_idx + idx_offset);
thash(root, buffer, 2, ctx, addr);
}
/**
* For a given leaf index, computes the authentication path and the resulting
* root node using Merkle's TreeHash algorithm.
* Expects the layer and tree parts of the tree_addr to be set, as well as the
* tree type (i.e. SPX_ADDR_TYPE_HASHTREE or SPX_ADDR_TYPE_FORSTREE).
* Applies the offset idx_offset to indices before building addresses, so that
* it is possible to continue counting indices across trees.
*/
void treehash(unsigned char *root, unsigned char *auth_path, const spx_ctx* ctx,
uint32_t leaf_idx, uint32_t idx_offset, uint32_t tree_height,
void (*gen_leaf)(
unsigned char* /* leaf */,
const spx_ctx* /* ctx */,
uint32_t /* addr_idx */, const uint32_t[8] /* tree_addr */),
uint32_t tree_addr[8])
{
SPX_VLA(uint8_t, stack, (tree_height+1)*SPX_N);
SPX_VLA(unsigned int, heights, tree_height+1);
unsigned int offset = 0;
uint32_t idx;
uint32_t tree_idx;
for (idx = 0; idx < (uint32_t)(1 << tree_height); idx++) {
/* Add the next leaf node to the stack. */
gen_leaf(stack + offset*SPX_N, ctx, idx + idx_offset, tree_addr);
offset++;
heights[offset - 1] = 0;
/* If this is a node we need for the auth path.. */
if ((leaf_idx ^ 0x1) == idx) {
memcpy(auth_path, stack + (offset - 1)*SPX_N, SPX_N);
}
/* While the top-most nodes are of equal height.. */
while (offset >= 2 && heights[offset - 1] == heights[offset - 2]) {
/* Compute index of the new node, in the next layer. */
tree_idx = (idx >> (heights[offset - 1] + 1));
/* Set the address of the node we're creating. */
set_tree_height(tree_addr, heights[offset - 1] + 1);
set_tree_index(tree_addr,
tree_idx + (idx_offset >> (heights[offset-1] + 1)));
/* Hash the top-most nodes from the stack together. */
thash(stack + (offset - 2)*SPX_N,
stack + (offset - 2)*SPX_N, 2, ctx, tree_addr);
offset--;
/* Note that the top-most node is now one layer higher. */
heights[offset - 1]++;
/* If this is a node we need for the auth path.. */
if (((leaf_idx >> heights[offset - 1]) ^ 0x1) == tree_idx) {
memcpy(auth_path + heights[offset - 1]*SPX_N,
stack + (offset - 1)*SPX_N, SPX_N);
}
}
}
memcpy(root, stack, SPX_N);
}

View File

@@ -1,100 +0,0 @@
#include <string.h>
#include "utils.h"
#include "utilsx1.h"
#include "params.h"
#include "thash.h"
#include "address.h"
/*
* Generate the entire Merkle tree, computing the authentication path for
* leaf_idx, and the resulting root node using Merkle's TreeHash algorithm.
* Expects the layer and tree parts of the tree_addr to be set, as well as the
* tree type (i.e. SPX_ADDR_TYPE_HASHTREE or SPX_ADDR_TYPE_FORSTREE)
*
* This expects tree_addr to be initialized to the addr structures for the
* Merkle tree nodes
*
* Applies the offset idx_offset to indices before building addresses, so that
* it is possible to continue counting indices across trees.
*
* This works by using the standard Merkle tree building algorithm,
*/
void treehashx1(unsigned char *root, unsigned char *auth_path,
const spx_ctx* ctx,
uint32_t leaf_idx, uint32_t idx_offset,
uint32_t tree_height,
void (*gen_leaf)(
unsigned char* /* Where to write the leaves */,
const spx_ctx* /* ctx */,
uint32_t idx, void *info),
uint32_t tree_addr[8],
void *info)
{
/* This is where we keep the intermediate nodes */
SPX_VLA(uint8_t, stack, tree_height*SPX_N);
uint32_t idx;
uint32_t max_idx = (uint32_t)((1 << tree_height) - 1);
for (idx = 0;; idx++) {
unsigned char current[2*SPX_N]; /* Current logical node is at */
/* index[SPX_N]. We do this to minimize the number of copies */
/* needed during a thash */
gen_leaf( &current[SPX_N], ctx, idx + idx_offset,
info );
/* Now combine the freshly generated right node with previously */
/* generated left ones */
uint32_t internal_idx_offset = idx_offset;
uint32_t internal_idx = idx;
uint32_t internal_leaf = leaf_idx;
uint32_t h; /* The height we are in the Merkle tree */
for (h=0;; h++, internal_idx >>= 1, internal_leaf >>= 1) {
/* Check if we hit the top of the tree */
if (h == tree_height) {
/* We hit the root; return it */
memcpy( root, &current[SPX_N], SPX_N );
return;
}
/*
* Check if the node we have is a part of the
* authentication path; if it is, write it out
*/
if ((internal_idx ^ internal_leaf) == 0x01) {
memcpy( &auth_path[ h * SPX_N ],
&current[SPX_N],
SPX_N );
}
/*
* Check if we're at a left child; if so, stop going up the stack
* Exception: if we've reached the end of the tree, keep on going
* (so we combine the last 4 nodes into the one root node in two
* more iterations)
*/
if ((internal_idx & 1) == 0 && idx < max_idx) {
break;
}
/* Ok, we're at a right node */
/* Now combine the left and right logical nodes together */
/* Set the address of the node we're creating. */
internal_idx_offset >>= 1;
set_tree_height(tree_addr, h + 1);
set_tree_index(tree_addr, internal_idx/2 + internal_idx_offset );
unsigned char *left = &stack[h * SPX_N];
memcpy( &current[0], left, SPX_N );
thash( &current[1 * SPX_N],
&current[0 * SPX_N],
2, ctx, tree_addr);
}
/* We've hit a left child; save the current for when we get the */
/* corresponding right right */
memcpy( &stack[h * SPX_N], &current[SPX_N], SPX_N);
}
}

View File

@@ -1,112 +0,0 @@
#include <stdint.h>
#include <string.h>
#include "utils.h"
#include "utilsx1.h"
#include "hash.h"
#include "thash.h"
#include "wots.h"
#include "wotsx1.h"
#include "address.h"
#include "params.h"
// TODO clarify address expectations, and make them more uniform.
// TODO i.e. do we expect types to be set already?
// TODO and do we expect modifications or copies?
/**
* Computes the chaining function.
* out and in have to be n-byte arrays.
*
* Interprets in as start-th value of the chain.
* addr has to contain the address of the chain.
*/
static void gen_chain(unsigned char *out, const unsigned char *in,
unsigned int start, unsigned int steps,
const spx_ctx *ctx, uint32_t addr[8])
{
uint32_t i;
/* Initialize out with the value at position 'start'. */
memcpy(out, in, SPX_N);
/* Iterate 'steps' calls to the hash function. */
for (i = start; i < (start+steps) && i < SPX_WOTS_W; i++) {
set_hash_addr(addr, i);
thash(out, out, 1, ctx, addr);
}
}
/**
* base_w algorithm as described in draft.
* Interprets an array of bytes as integers in base w.
* This only works when log_w is a divisor of 8.
*/
static void base_w(unsigned int *output, const int out_len,
const unsigned char *input)
{
int in = 0;
int out = 0;
unsigned char total;
int bits = 0;
int consumed;
for (consumed = 0; consumed < out_len; consumed++) {
if (bits == 0) {
total = input[in];
in++;
bits += 8;
}
bits -= SPX_WOTS_LOGW;
output[out] = (total >> bits) & (SPX_WOTS_W - 1);
out++;
}
}
/* Computes the WOTS+ checksum over a message (in base_w). */
static void wots_checksum(unsigned int *csum_base_w,
const unsigned int *msg_base_w)
{
unsigned int csum = 0;
unsigned char csum_bytes[(SPX_WOTS_LEN2 * SPX_WOTS_LOGW + 7) / 8];
unsigned int i;
/* Compute checksum. */
for (i = 0; i < SPX_WOTS_LEN1; i++) {
csum += SPX_WOTS_W - 1 - msg_base_w[i];
}
/* Convert checksum to base_w. */
/* Make sure expected empty zero bits are the least significant bits. */
csum = csum << ((8 - ((SPX_WOTS_LEN2 * SPX_WOTS_LOGW) % 8)) % 8);
ull_to_bytes(csum_bytes, sizeof(csum_bytes), csum);
base_w(csum_base_w, SPX_WOTS_LEN2, csum_bytes);
}
/* Takes a message and derives the matching chain lengths. */
void chain_lengths(unsigned int *lengths, const unsigned char *msg)
{
base_w(lengths, SPX_WOTS_LEN1, msg);
wots_checksum(lengths + SPX_WOTS_LEN1, lengths);
}
/**
* Takes a WOTS signature and an n-byte message, computes a WOTS public key.
*
* Writes the computed public key to 'pk'.
*/
void wots_pk_from_sig(unsigned char *pk,
const unsigned char *sig, const unsigned char *msg,
const spx_ctx *ctx, uint32_t addr[8])
{
unsigned int lengths[SPX_WOTS_LEN];
uint32_t i;
chain_lengths(lengths, msg);
for (i = 0; i < SPX_WOTS_LEN; i++) {
set_chain_addr(addr, i);
gen_chain(pk + i*SPX_N, sig + i*SPX_N,
lengths[i], SPX_WOTS_W - 1 - lengths[i], ctx, addr);
}
}

View File

@@ -1,73 +0,0 @@
#include <stdint.h>
#include <string.h>
#include "utils.h"
#include "hash.h"
#include "thash.h"
#include "wots.h"
#include "wotsx1.h"
#include "address.h"
#include "params.h"
/*
* This generates a WOTS public key
* It also generates the WOTS signature if leaf_info indicates
* that we're signing with this WOTS key
*/
void wots_gen_leafx1(unsigned char *dest,
const spx_ctx *ctx,
uint32_t leaf_idx, void *v_info) {
struct leaf_info_x1 *info = v_info;
uint32_t *leaf_addr = info->leaf_addr;
uint32_t *pk_addr = info->pk_addr;
unsigned int i, k;
unsigned char pk_buffer[ SPX_WOTS_BYTES ];
unsigned char *buffer;
uint32_t wots_k_mask;
if (leaf_idx == info->wots_sign_leaf) {
/* We're traversing the leaf that's signing; generate the WOTS */
/* signature */
wots_k_mask = 0;
} else {
/* Nope, we're just generating pk's; turn off the signature logic */
wots_k_mask = (uint32_t)~0;
}
set_keypair_addr( leaf_addr, leaf_idx );
set_keypair_addr( pk_addr, leaf_idx );
for (i = 0, buffer = pk_buffer; i < SPX_WOTS_LEN; i++, buffer += SPX_N) {
uint32_t wots_k = info->wots_steps[i] | wots_k_mask; /* Set wots_k to */
/* the step if we're generating a signature, ~0 if we're not */
/* Start with the secret seed */
set_chain_addr(leaf_addr, i);
set_hash_addr(leaf_addr, 0);
set_type(leaf_addr, SPX_ADDR_TYPE_WOTSPRF);
prf_addr(buffer, ctx, leaf_addr);
set_type(leaf_addr, SPX_ADDR_TYPE_WOTS);
/* Iterate down the WOTS chain */
for (k=0;; k++) {
/* Check if this is the value that needs to be saved as a */
/* part of the WOTS signature */
if (k == wots_k) {
memcpy( info->wots_sig + i * SPX_N, buffer, SPX_N );
}
/* Check if we hit the top of the chain */
if (k == SPX_WOTS_W - 1) break;
/* Iterate one step on the chain */
set_hash_addr(leaf_addr, k);
thash(buffer, buffer, 1, ctx, leaf_addr);
}
}
/* Do the final thash to generate the public keys */
thash(dest, pk_buffer, SPX_WOTS_LEN, ctx, pk_addr);
}