Vystem 0.2
This commit is contained in:
@@ -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 );
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
108
Blastproof/initfsgen/initfsgen.json
Normal file
108
Blastproof/initfsgen/initfsgen.json
Normal 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"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -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 */ );
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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( ¤t[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, ¤t[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 ],
|
||||
¤t[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( ¤t[0], left, SPX_N );
|
||||
thash( ¤t[1 * SPX_N],
|
||||
¤t[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], ¤t[SPX_N], SPX_N);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
Reference in New Issue
Block a user