First commit, Vystem v0.1
This commit is contained in:
104
Blastproof/initfsgen/address.c
Normal file
104
Blastproof/initfsgen/address.c
Normal file
@@ -0,0 +1,104 @@
|
||||
#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 );
|
||||
}
|
||||
51
Blastproof/initfsgen/address.h
Normal file
51
Blastproof/initfsgen/address.h
Normal file
@@ -0,0 +1,51 @@
|
||||
#ifndef SPX_ADDRESS_H
|
||||
#define SPX_ADDRESS_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include "params.h"
|
||||
|
||||
/* The hash types that are passed to set_type */
|
||||
#define SPX_ADDR_TYPE_WOTS 0
|
||||
#define SPX_ADDR_TYPE_WOTSPK 1
|
||||
#define SPX_ADDR_TYPE_HASHTREE 2
|
||||
#define SPX_ADDR_TYPE_FORSTREE 3
|
||||
#define SPX_ADDR_TYPE_FORSPK 4
|
||||
#define SPX_ADDR_TYPE_WOTSPRF 5
|
||||
#define SPX_ADDR_TYPE_FORSPRF 6
|
||||
|
||||
#define set_layer_addr SPX_NAMESPACE(set_layer_addr)
|
||||
void set_layer_addr(uint32_t addr[8], uint32_t layer);
|
||||
|
||||
#define set_tree_addr SPX_NAMESPACE(set_tree_addr)
|
||||
void set_tree_addr(uint32_t addr[8], uint64_t tree);
|
||||
|
||||
#define set_type SPX_NAMESPACE(set_type)
|
||||
void set_type(uint32_t addr[8], uint32_t type);
|
||||
|
||||
/* Copies the layer and tree part of one address into the other */
|
||||
#define copy_subtree_addr SPX_NAMESPACE(copy_subtree_addr)
|
||||
void copy_subtree_addr(uint32_t out[8], const uint32_t in[8]);
|
||||
|
||||
/* These functions are used for WOTS and FORS addresses. */
|
||||
|
||||
#define set_keypair_addr SPX_NAMESPACE(set_keypair_addr)
|
||||
void set_keypair_addr(uint32_t addr[8], uint32_t keypair);
|
||||
|
||||
#define set_chain_addr SPX_NAMESPACE(set_chain_addr)
|
||||
void set_chain_addr(uint32_t addr[8], uint32_t chain);
|
||||
|
||||
#define set_hash_addr SPX_NAMESPACE(set_hash_addr)
|
||||
void set_hash_addr(uint32_t addr[8], uint32_t hash);
|
||||
|
||||
#define copy_keypair_addr SPX_NAMESPACE(copy_keypair_addr)
|
||||
void copy_keypair_addr(uint32_t out[8], const uint32_t in[8]);
|
||||
|
||||
/* These functions are used for all hash tree addresses (including FORS). */
|
||||
|
||||
#define set_tree_height SPX_NAMESPACE(set_tree_height)
|
||||
void set_tree_height(uint32_t addr[8], uint32_t tree_height);
|
||||
|
||||
#define set_tree_index SPX_NAMESPACE(set_tree_index)
|
||||
void set_tree_index(uint32_t addr[8], uint32_t tree_index);
|
||||
|
||||
#endif
|
||||
77
Blastproof/initfsgen/api.h
Normal file
77
Blastproof/initfsgen/api.h
Normal file
@@ -0,0 +1,77 @@
|
||||
#ifndef SPX_API_H
|
||||
#define SPX_API_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "params.h"
|
||||
|
||||
#define CRYPTO_ALGNAME "SPHINCS+"
|
||||
|
||||
#define CRYPTO_SECRETKEYBYTES SPX_SK_BYTES
|
||||
#define CRYPTO_PUBLICKEYBYTES SPX_PK_BYTES
|
||||
#define CRYPTO_BYTES SPX_BYTES
|
||||
#define CRYPTO_SEEDBYTES 3*SPX_N
|
||||
|
||||
/*
|
||||
* Returns the length of a secret key, in bytes
|
||||
*/
|
||||
unsigned long long crypto_sign_secretkeybytes(void);
|
||||
|
||||
/*
|
||||
* Returns the length of a public key, in bytes
|
||||
*/
|
||||
unsigned long long crypto_sign_publickeybytes(void);
|
||||
|
||||
/*
|
||||
* Returns the length of a signature, in bytes
|
||||
*/
|
||||
unsigned long long crypto_sign_bytes(void);
|
||||
|
||||
/*
|
||||
* Returns the length of the seed required to generate a key pair, in bytes
|
||||
*/
|
||||
unsigned long long crypto_sign_seedbytes(void);
|
||||
|
||||
/*
|
||||
* Generates a SPHINCS+ key pair given a seed.
|
||||
* Format sk: [SK_SEED || SK_PRF || PUB_SEED || root]
|
||||
* Format pk: [root || PUB_SEED]
|
||||
*/
|
||||
int crypto_sign_seed_keypair(unsigned char *pk, unsigned char *sk,
|
||||
const unsigned char *seed);
|
||||
|
||||
/*
|
||||
* Generates a SPHINCS+ key pair.
|
||||
* Format sk: [SK_SEED || SK_PRF || PUB_SEED || root]
|
||||
* Format pk: [root || PUB_SEED]
|
||||
*/
|
||||
int crypto_sign_keypair(unsigned char *pk, unsigned char *sk);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
#endif
|
||||
4
Blastproof/initfsgen/build.sh
Executable file
4
Blastproof/initfsgen/build.sh
Executable file
@@ -0,0 +1,4 @@
|
||||
# SPDX-License-Identifier: MPL-2.0
|
||||
gcc -c address.c fors.c hash_sha2.c merkle.c randombytes.c sign.c utils.c utilsx1.c wots.c wotsx1.c thash_sha2_robust.c sha2.c sha3.c -Ofast -march=native
|
||||
g++ initfsgen.cpp address.o fors.o hash_sha2.o merkle.o randombytes.o sign.o utils.o utilsx1.o wots.o wotsx1.o thash_sha2_robust.o sha2.o sha3.o -o initfsgen -lcrypto -Ofast -march=native
|
||||
rm *.o
|
||||
28
Blastproof/initfsgen/context.h
Normal file
28
Blastproof/initfsgen/context.h
Normal file
@@ -0,0 +1,28 @@
|
||||
#ifndef SPX_CONTEXT_H
|
||||
#define SPX_CONTEXT_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "params.h"
|
||||
|
||||
typedef struct {
|
||||
uint8_t pub_seed[SPX_N];
|
||||
uint8_t sk_seed[SPX_N];
|
||||
|
||||
#ifdef SPX_SHA2
|
||||
// sha256 state that absorbed pub_seed
|
||||
uint8_t state_seeded[40];
|
||||
|
||||
# if SPX_SHA512
|
||||
// sha512 state that absorbed pub_seed
|
||||
uint8_t state_seeded_512[72];
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef SPX_HARAKA
|
||||
uint64_t tweaked512_rc64[10][8];
|
||||
uint32_t tweaked256_rc32[10][8];
|
||||
#endif
|
||||
} spx_ctx;
|
||||
|
||||
#endif
|
||||
161
Blastproof/initfsgen/fors.c
Normal file
161
Blastproof/initfsgen/fors.c
Normal file
@@ -0,0 +1,161 @@
|
||||
#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);
|
||||
}
|
||||
32
Blastproof/initfsgen/fors.h
Normal file
32
Blastproof/initfsgen/fors.h
Normal file
@@ -0,0 +1,32 @@
|
||||
#ifndef SPX_FORS_H
|
||||
#define SPX_FORS_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "params.h"
|
||||
#include "context.h"
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
#define fors_sign SPX_NAMESPACE(fors_sign)
|
||||
void fors_sign(unsigned char *sig, unsigned char *pk,
|
||||
const unsigned char *m,
|
||||
const spx_ctx* ctx,
|
||||
const uint32_t fors_addr[8]);
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
#define fors_pk_from_sig SPX_NAMESPACE(fors_pk_from_sig)
|
||||
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]);
|
||||
|
||||
#endif
|
||||
27
Blastproof/initfsgen/hash.h
Normal file
27
Blastproof/initfsgen/hash.h
Normal file
@@ -0,0 +1,27 @@
|
||||
#ifndef SPX_HASH_H
|
||||
#define SPX_HASH_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include "context.h"
|
||||
#include "params.h"
|
||||
|
||||
#define initialize_hash_function SPX_NAMESPACE(initialize_hash_function)
|
||||
void initialize_hash_function(spx_ctx *ctx);
|
||||
|
||||
#define prf_addr SPX_NAMESPACE(prf_addr)
|
||||
void prf_addr(unsigned char *out, const spx_ctx *ctx,
|
||||
const uint32_t addr[8]);
|
||||
|
||||
#define gen_message_random SPX_NAMESPACE(gen_message_random)
|
||||
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);
|
||||
|
||||
#define hash_message SPX_NAMESPACE(hash_message)
|
||||
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);
|
||||
|
||||
#endif
|
||||
197
Blastproof/initfsgen/hash_sha2.c
Normal file
197
Blastproof/initfsgen/hash_sha2.c
Normal file
@@ -0,0 +1,197 @@
|
||||
#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);
|
||||
}
|
||||
|
||||
|
||||
241
Blastproof/initfsgen/initfsgen.cpp
Normal file
241
Blastproof/initfsgen/initfsgen.cpp
Normal file
@@ -0,0 +1,241 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
extern "C" {
|
||||
#include "api.h"
|
||||
#include "sha3.h"
|
||||
}
|
||||
#undef str
|
||||
#include <cstdint>
|
||||
#include <iostream>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <cstring>
|
||||
#include <algorithm>
|
||||
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;
|
||||
uint8_t installation_id[48]={0};
|
||||
uint64_t initfs_size=0;
|
||||
uint64_t table_size=0;
|
||||
uint64_t files_area_size=0;
|
||||
uint64_t entries_width=256;
|
||||
uint64_t entries_count=0;
|
||||
uint64_t files_area_offset=0;
|
||||
uint64_t entropy_check1=0;
|
||||
uint64_t check1=0;
|
||||
uint8_t entry_table_hash[64]={0};
|
||||
uint8_t files_area_hash[64]={0};
|
||||
uint8_t installation_id_hash_hash[64]={0};
|
||||
uint8_t padding[128]={0};
|
||||
uint8_t header_hash[64]={0};
|
||||
};
|
||||
#pragma pack(pop)
|
||||
#pragma pack(push,1)
|
||||
struct file_entry {
|
||||
uint64_t file_offset=0;
|
||||
uint64_t file_size=0;
|
||||
uint8_t pk[64]={0};
|
||||
uint8_t hash[64]={0};
|
||||
char file_name[112]={0};
|
||||
};
|
||||
#pragma pack(pop)
|
||||
#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;
|
||||
uint8_t installation_id[48]={0};
|
||||
uint64_t signature_size=0;
|
||||
uint64_t signature_count=0;
|
||||
uint64_t signsyst_size=0;
|
||||
uint64_t signature_block_size=0;
|
||||
uint8_t signature_block_hash[64];
|
||||
uint8_t padding[288]={0};
|
||||
uint8_t header_hash[64]={0};
|
||||
};
|
||||
#pragma pack(pop)
|
||||
void secure_erase(void *address,size_t size) {
|
||||
explicit_bzero(address,size);
|
||||
}
|
||||
vector<unsigned char> generate_padding(size_t x,unsigned char p) {
|
||||
vector<unsigned char> result(x,0);
|
||||
size_t f0=0;
|
||||
size_t f1=1;
|
||||
while (f0<x) {
|
||||
result[f0]=p;
|
||||
size_t next=f0+f1;
|
||||
f0=f1;
|
||||
f1=next;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
int main(int argc,char **argv) {
|
||||
if (argc!=2) {
|
||||
cout<<"[InitFSGen] Error: invalid number of argument."<<endl;
|
||||
return -1;
|
||||
}
|
||||
string folder_path=string(argv[1]);
|
||||
if (!fs::exists(folder_path)) {
|
||||
cout<<"[InitFSGen] Error: provided path doesn't exists."<<endl;
|
||||
return -1;
|
||||
}
|
||||
if (!fs::is_directory(folder_path)) {
|
||||
cout<<"[InitFSGen] Error: provided path isn't a directory"<<endl;
|
||||
return -1;
|
||||
}
|
||||
vector<string> initfs_files_name;
|
||||
vector<size_t> initfs_files_size;
|
||||
size_t total_size=0;
|
||||
for (auto &entry:fs::directory_iterator(folder_path)) {
|
||||
if (!entry.is_regular_file()) {
|
||||
cout<<"[InitFSGen] Error: InitFS only support files. Following entry isn't a regular file : "<<entry.path()<<endl;
|
||||
return -1;
|
||||
}
|
||||
initfs_files_name.push_back(string(fs::absolute(entry.path())));
|
||||
initfs_files_size.push_back(entry.file_size());
|
||||
total_size+=entry.file_size();
|
||||
}
|
||||
vector<unsigned char> entropy_id;
|
||||
entropy_id.resize(48);
|
||||
ifstream random("/dev/urandom",ios::binary);
|
||||
if (!random) {
|
||||
cout<<"[InitFSGen] Error: Can't open secure entropy source."<<endl;
|
||||
return -1;
|
||||
}
|
||||
random.read(reinterpret_cast<char*>(entropy_id.data()),entropy_id.size());
|
||||
if (random.gcount()!=entropy_id.size()) {
|
||||
cout<<"[InitFSGen] Error: Can't read enougth entropy for installation id."<<endl;
|
||||
return -1;
|
||||
}
|
||||
vector<unsigned char> entropy;
|
||||
entropy.resize(8);
|
||||
random.read(reinterpret_cast<char*>(entropy.data()),entropy.size());
|
||||
if (random.gcount()!=entropy.size()) {
|
||||
cout<<"[InitFSGen] Error: Can't read enougth entropy."<<endl;
|
||||
return -1;
|
||||
}
|
||||
initfs_header header{};
|
||||
signsyst_header sign_header={};
|
||||
memcpy(header.installation_id,entropy_id.data(),entropy_id.size());
|
||||
memcpy(sign_header.installation_id,entropy_id.data(),entropy_id.size());
|
||||
sign_header.signature_size=CRYPTO_BYTES;
|
||||
sign_header.signature_count=initfs_files_name.size();
|
||||
sign_header.signature_block_size=sign_header.signature_count*sign_header.signature_size;
|
||||
sign_header.signsyst_size=512+sign_header.signature_block_size;
|
||||
memcpy(&header.entropy_check1,entropy.data(),entropy.size());
|
||||
header.entries_count=initfs_files_name.size();
|
||||
header.table_size=header.entries_count*header.entries_width;
|
||||
header.files_area_size=total_size;
|
||||
header.initfs_size=512+header.table_size+header.files_area_size;
|
||||
header.files_area_offset=512+header.table_size;
|
||||
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);
|
||||
if (!initfs_footprint) {
|
||||
cout<<"[InitFSGen] Error: Can't open initfs-footprint.bin."<<endl;
|
||||
return -1;
|
||||
}
|
||||
initfs_footprint.write(reinterpret_cast<char*>(header.installation_id_hash_hash),sizeof(header.installation_id_hash_hash));
|
||||
sha3(header.installation_id_hash_hash,sizeof(header.installation_id_hash_hash),header.installation_id_hash_hash,sizeof(header.installation_id_hash_hash));
|
||||
vector<unsigned char> files_area;
|
||||
vector<file_entry> files_entries_table;
|
||||
vector<unsigned char> sig_list;
|
||||
sig_list.resize(CRYPTO_BYTES*header.entries_count);
|
||||
size_t cursor=0;
|
||||
files_area.resize(header.files_area_size);
|
||||
uint8_t sk[CRYPTO_SECRETKEYBYTES]={0};
|
||||
for (size_t i=0;i<initfs_files_name.size();++i) {
|
||||
ifstream file(initfs_files_name[i],ios::binary);
|
||||
if (!file) {
|
||||
cout<<"[InitFSGen] Error: Can't read file: "<<initfs_files_name[i]<<endl;
|
||||
return -1;
|
||||
}
|
||||
file.read(reinterpret_cast<char*>(files_area.data()+cursor),initfs_files_size[i]);
|
||||
if (file.gcount()!=initfs_files_size[i]) {
|
||||
cout<<"[InitFSGen] Error: Couldn't read full file: "<<initfs_files_name[i]<<endl;
|
||||
return -1;
|
||||
}
|
||||
file_entry entry;
|
||||
string filename=string(fs::path(initfs_files_name[i]).filename());
|
||||
copy(filename.data(),filename.data()+min(filename.size(),static_cast<size_t>(112)),entry.file_name);
|
||||
entry.file_size=initfs_files_size[i];
|
||||
entry.file_offset=cursor;
|
||||
sha3(files_area.data()+cursor,initfs_files_size[i],entry.hash,64);
|
||||
if (crypto_sign_keypair(entry.pk,sk)) {
|
||||
cout<<"[InitFSGen] Error: can't generate keypair for file: "<<initfs_files_name[i]<<endl;
|
||||
secure_erase(sk,sizeof(sk));
|
||||
return -1;
|
||||
}
|
||||
size_t siglen=0;
|
||||
if (crypto_sign_signature(sig_list.data()+i*CRYPTO_BYTES,&siglen,files_area.data()+cursor,initfs_files_size[i],sk)) {
|
||||
cout<<"[InitFSGen] Error: can't generate signature for file: "<<initfs_files_name[i]<<endl;
|
||||
secure_erase(sk,sizeof(sk));
|
||||
return -1;
|
||||
}
|
||||
secure_erase(sk,sizeof(sk));
|
||||
if (siglen!=CRYPTO_BYTES) {
|
||||
cout<<"[InitFSGen] Error: Signature isn't the expected size for file: "<<initfs_files_name[i]<<endl;
|
||||
return -1;
|
||||
}
|
||||
files_entries_table.push_back(entry);
|
||||
cursor+=initfs_files_size[i];
|
||||
}
|
||||
vector<unsigned char> entries_table;
|
||||
entries_table.resize(header.table_size);
|
||||
for (size_t i=0;i<files_entries_table.size();++i) {
|
||||
memcpy(entries_table.data()+i*header.entries_width,&files_entries_table[i],sizeof(file_entry));
|
||||
}
|
||||
sha3(entries_table.data(),entries_table.size(),header.entry_table_hash,sizeof(header.entry_table_hash));
|
||||
for (size_t i=0;i<48;++i) {
|
||||
header.entry_table_hash[i+16]^=header.installation_id[i];
|
||||
}
|
||||
sha3(files_area.data(),files_area.size(),header.files_area_hash,sizeof(header.files_area_hash));
|
||||
for (size_t i=0;i<48;++i) {
|
||||
header.files_area_hash[i+16]^=header.installation_id[i];
|
||||
}
|
||||
sha3(sig_list.data(),sig_list.size(),sign_header.signature_block_hash,sizeof(sign_header.signature_block_hash));
|
||||
for (size_t i=0;i<48;++i) {
|
||||
sign_header.signature_block_hash[i+16]^=sign_header.installation_id[i];
|
||||
}
|
||||
auto padding=generate_padding(sizeof(header.padding),header.installation_id[0]);
|
||||
memcpy(header.padding,padding.data(),padding.size());
|
||||
auto padding_sign=generate_padding(sizeof(sign_header.padding),sign_header.installation_id[sizeof(sign_header.installation_id)-1]);
|
||||
memcpy(sign_header.padding,padding_sign.data(),padding_sign.size());
|
||||
sha3(&header,sizeof(header)-sizeof(header.header_hash),header.header_hash,sizeof(header.header_hash));
|
||||
sha3(&sign_header,sizeof(sign_header)-sizeof(sign_header.header_hash),sign_header.header_hash,sizeof(sign_header.header_hash));
|
||||
ofstream initfs_bin("initfs.bin",ios::binary);
|
||||
if (!initfs_bin) {
|
||||
cout<<"[InitFSGen] Error: Can't open initfs.bin."<<endl;
|
||||
return -1;
|
||||
}
|
||||
initfs_bin.write(reinterpret_cast<char*>(&header),sizeof(header));
|
||||
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);
|
||||
if (!signsyst_hash) {
|
||||
cout<<"[InitFSGen] Error: Can't open signsyst-hash.bin."<<endl;
|
||||
return -1;
|
||||
}
|
||||
vector<unsigned char> signsysthash(64,0);
|
||||
sha3(&sign_header,sizeof(sign_header),signsysthash.data(),signsysthash.size());
|
||||
signsyst_hash.write(reinterpret_cast<char*>(signsysthash.data()),signsysthash.size());
|
||||
signsyst_hash.close();
|
||||
ofstream signsyst_bin("signsyst.bin",ios::binary);
|
||||
if (!signsyst_bin) {
|
||||
cout<<"[InitFSGen] Error: Can't open signsyst.bin."<<endl;
|
||||
return -1;
|
||||
}
|
||||
signsyst_bin.write(reinterpret_cast<char*>(&sign_header),sizeof(sign_header));
|
||||
signsyst_bin.write(reinterpret_cast<char*>(sig_list.data()),sig_list.size());
|
||||
signsyst_bin.close();
|
||||
return 0;
|
||||
}
|
||||
61
Blastproof/initfsgen/merkle.c
Normal file
61
Blastproof/initfsgen/merkle.c
Normal file
@@ -0,0 +1,61 @@
|
||||
#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 */ );
|
||||
}
|
||||
18
Blastproof/initfsgen/merkle.h
Normal file
18
Blastproof/initfsgen/merkle.h
Normal file
@@ -0,0 +1,18 @@
|
||||
#if !defined( MERKLE_H_ )
|
||||
#define MERKLE_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/* Generate a Merkle signature (WOTS signature followed by the Merkle */
|
||||
/* authentication path) */
|
||||
#define merkle_sign SPX_NAMESPACE(merkle_sign)
|
||||
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);
|
||||
|
||||
/* Compute the root node of the top-most subtree. */
|
||||
#define merkle_gen_root SPX_NAMESPACE(merkle_gen_root)
|
||||
void merkle_gen_root(unsigned char *root, const spx_ctx* ctx);
|
||||
|
||||
#endif /* MERKLE_H_ */
|
||||
3
Blastproof/initfsgen/params.h
Normal file
3
Blastproof/initfsgen/params.h
Normal file
@@ -0,0 +1,3 @@
|
||||
#define str(s) #s
|
||||
#define xstr(s) str(s)
|
||||
#include "params/params-sphincs-sha2-256f.h"
|
||||
85
Blastproof/initfsgen/params/params-sphincs-sha2-256f.h
Normal file
85
Blastproof/initfsgen/params/params-sphincs-sha2-256f.h
Normal file
@@ -0,0 +1,85 @@
|
||||
#ifndef SPX_PARAMS_H
|
||||
#define SPX_PARAMS_H
|
||||
|
||||
#define SPX_NAMESPACE(s) SPX_##s
|
||||
|
||||
/* Hash output length in bytes. */
|
||||
#define SPX_N 32
|
||||
/* Height of the hypertree. */
|
||||
#define SPX_FULL_HEIGHT 68
|
||||
/* Number of subtree layer. */
|
||||
#define SPX_D 17
|
||||
/* FORS tree dimensions. */
|
||||
#define SPX_FORS_HEIGHT 9
|
||||
#define SPX_FORS_TREES 35
|
||||
/* Winternitz parameter, */
|
||||
#define SPX_WOTS_W 16
|
||||
|
||||
/* The hash function is defined by linking a different hash.c file, as opposed
|
||||
to setting a #define constant. */
|
||||
|
||||
/* This is a SHA2-based parameter set, hence whether we use SHA-256
|
||||
* exclusively or we use both SHA-256 and SHA-512 is controlled by
|
||||
* the following #define */
|
||||
#define SPX_SHA512 1 /* Use SHA-512 for H and T_l, l >= 2 */
|
||||
|
||||
/* For clarity */
|
||||
#define SPX_ADDR_BYTES 32
|
||||
|
||||
/* WOTS parameters. */
|
||||
#if SPX_WOTS_W == 256
|
||||
#define SPX_WOTS_LOGW 8
|
||||
#elif SPX_WOTS_W == 16
|
||||
#define SPX_WOTS_LOGW 4
|
||||
#else
|
||||
#error SPX_WOTS_W assumed 16 or 256
|
||||
#endif
|
||||
|
||||
#define SPX_WOTS_LEN1 (8 * SPX_N / SPX_WOTS_LOGW)
|
||||
|
||||
/* SPX_WOTS_LEN2 is floor(log(len_1 * (w - 1)) / log(w)) + 1; we precompute */
|
||||
#if SPX_WOTS_W == 256
|
||||
#if SPX_N <= 1
|
||||
#define SPX_WOTS_LEN2 1
|
||||
#elif SPX_N <= 256
|
||||
#define SPX_WOTS_LEN2 2
|
||||
#else
|
||||
#error Did not precompute SPX_WOTS_LEN2 for n outside {2, .., 256}
|
||||
#endif
|
||||
#elif SPX_WOTS_W == 16
|
||||
#if SPX_N <= 8
|
||||
#define SPX_WOTS_LEN2 2
|
||||
#elif SPX_N <= 136
|
||||
#define SPX_WOTS_LEN2 3
|
||||
#elif SPX_N <= 256
|
||||
#define SPX_WOTS_LEN2 4
|
||||
#else
|
||||
#error Did not precompute SPX_WOTS_LEN2 for n outside {2, .., 256}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define SPX_WOTS_LEN (SPX_WOTS_LEN1 + SPX_WOTS_LEN2)
|
||||
#define SPX_WOTS_BYTES (SPX_WOTS_LEN * SPX_N)
|
||||
#define SPX_WOTS_PK_BYTES SPX_WOTS_BYTES
|
||||
|
||||
/* Subtree size. */
|
||||
#define SPX_TREE_HEIGHT (SPX_FULL_HEIGHT / SPX_D)
|
||||
|
||||
#if SPX_TREE_HEIGHT * SPX_D != SPX_FULL_HEIGHT
|
||||
#error SPX_D should always divide SPX_FULL_HEIGHT
|
||||
#endif
|
||||
|
||||
/* FORS parameters. */
|
||||
#define SPX_FORS_MSG_BYTES ((SPX_FORS_HEIGHT * SPX_FORS_TREES + 7) / 8)
|
||||
#define SPX_FORS_BYTES ((SPX_FORS_HEIGHT + 1) * SPX_FORS_TREES * SPX_N)
|
||||
#define SPX_FORS_PK_BYTES SPX_N
|
||||
|
||||
/* Resulting SPX sizes. */
|
||||
#define SPX_BYTES (SPX_N + SPX_FORS_BYTES + SPX_D * SPX_WOTS_BYTES +\
|
||||
SPX_FULL_HEIGHT * SPX_N)
|
||||
#define SPX_PK_BYTES (2 * SPX_N)
|
||||
#define SPX_SK_BYTES (2 * SPX_N + SPX_PK_BYTES)
|
||||
|
||||
#include "../sha2_offsets.h"
|
||||
|
||||
#endif
|
||||
43
Blastproof/initfsgen/randombytes.c
Normal file
43
Blastproof/initfsgen/randombytes.c
Normal file
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
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;
|
||||
}
|
||||
}
|
||||
6
Blastproof/initfsgen/randombytes.h
Normal file
6
Blastproof/initfsgen/randombytes.h
Normal file
@@ -0,0 +1,6 @@
|
||||
#ifndef SPX_RANDOMBYTES_H
|
||||
#define SPX_RANDOMBYTES_H
|
||||
|
||||
extern void randombytes(unsigned char * x,unsigned long long xlen);
|
||||
|
||||
#endif
|
||||
700
Blastproof/initfsgen/sha2.c
Normal file
700
Blastproof/initfsgen/sha2.c
Normal file
@@ -0,0 +1,700 @@
|
||||
/* 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
|
||||
}
|
||||
43
Blastproof/initfsgen/sha2.h
Normal file
43
Blastproof/initfsgen/sha2.h
Normal file
@@ -0,0 +1,43 @@
|
||||
#ifndef SPX_SHA2_H
|
||||
#define SPX_SHA2_H
|
||||
|
||||
#include "params.h"
|
||||
|
||||
#define SPX_SHA256_BLOCK_BYTES 64
|
||||
#define SPX_SHA256_OUTPUT_BYTES 32 /* This does not necessarily equal SPX_N */
|
||||
|
||||
#define SPX_SHA512_BLOCK_BYTES 128
|
||||
#define SPX_SHA512_OUTPUT_BYTES 64
|
||||
|
||||
#if SPX_SHA256_OUTPUT_BYTES < SPX_N
|
||||
#error Linking against SHA-256 with N larger than 32 bytes is not supported
|
||||
#endif
|
||||
|
||||
#define SPX_SHA256_ADDR_BYTES 22
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
void sha256_inc_init(uint8_t *state);
|
||||
void sha256_inc_blocks(uint8_t *state, const uint8_t *in, size_t inblocks);
|
||||
void sha256_inc_finalize(uint8_t *out, uint8_t *state, const uint8_t *in, size_t inlen);
|
||||
void sha256(uint8_t *out, const uint8_t *in, size_t inlen);
|
||||
|
||||
void sha512_inc_init(uint8_t *state);
|
||||
void sha512_inc_blocks(uint8_t *state, const uint8_t *in, size_t inblocks);
|
||||
void sha512_inc_finalize(uint8_t *out, uint8_t *state, const uint8_t *in, size_t inlen);
|
||||
void sha512(uint8_t *out, const uint8_t *in, size_t inlen);
|
||||
|
||||
#define mgf1_256 SPX_NAMESPACE(mgf1_256)
|
||||
void mgf1_256(unsigned char *out, unsigned long outlen,
|
||||
const unsigned char *in, unsigned long inlen);
|
||||
|
||||
#define mgf1_512 SPX_NAMESPACE(mgf1_512)
|
||||
void mgf1_512(unsigned char *out, unsigned long outlen,
|
||||
const unsigned char *in, unsigned long inlen);
|
||||
|
||||
#define seed_state SPX_NAMESPACE(seed_state)
|
||||
void seed_state(spx_ctx *ctx);
|
||||
|
||||
|
||||
#endif
|
||||
20
Blastproof/initfsgen/sha2_offsets.h
Normal file
20
Blastproof/initfsgen/sha2_offsets.h
Normal file
@@ -0,0 +1,20 @@
|
||||
#ifndef SHA2_OFFSETS_H_
|
||||
#define SHA2_OFFSETS_H_
|
||||
|
||||
/*
|
||||
* Offsets of various fields in the address structure when we use SHA2 as
|
||||
* the Sphincs+ hash function
|
||||
*/
|
||||
|
||||
#define SPX_OFFSET_LAYER 0 /* The byte used to specify the Merkle tree layer */
|
||||
#define SPX_OFFSET_TREE 1 /* The start of the 8 byte field used to specify the tree */
|
||||
#define SPX_OFFSET_TYPE 9 /* The byte used to specify the hash type (reason) */
|
||||
#define SPX_OFFSET_KP_ADDR 10 /* The start of the 4 byte field used to specify the key pair address */
|
||||
#define SPX_OFFSET_CHAIN_ADDR 17 /* The byte used to specify the chain address (which Winternitz chain) */
|
||||
#define SPX_OFFSET_HASH_ADDR 21 /* The byte used to specify the hash address (where in the Winternitz chain) */
|
||||
#define SPX_OFFSET_TREE_HGT 17 /* The byte used to specify the height of this node in the FORS or Merkle tree */
|
||||
#define SPX_OFFSET_TREE_INDEX 18 /* The start of the 4 byte field used to specify the node in the FORS or Merkle tree */
|
||||
|
||||
#define SPX_SHA2 1
|
||||
|
||||
#endif /* SHA2_OFFSETS_H_ */
|
||||
190
Blastproof/initfsgen/sha3.c
Normal file
190
Blastproof/initfsgen/sha3.c
Normal file
@@ -0,0 +1,190 @@
|
||||
// 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;
|
||||
}
|
||||
46
Blastproof/initfsgen/sha3.h
Normal file
46
Blastproof/initfsgen/sha3.h
Normal file
@@ -0,0 +1,46 @@
|
||||
// sha3.h
|
||||
// 19-Nov-11 Markku-Juhani O. Saarinen <mjos@iki.fi>
|
||||
|
||||
#ifndef SHA3_H
|
||||
#define SHA3_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifndef KECCAKF_ROUNDS
|
||||
#define KECCAKF_ROUNDS 24
|
||||
#endif
|
||||
|
||||
#ifndef ROTL64
|
||||
#define ROTL64(x, y) (((x) << (y)) | ((x) >> (64 - (y))))
|
||||
#endif
|
||||
|
||||
// state context
|
||||
typedef struct {
|
||||
union { // state:
|
||||
uint8_t b[200]; // 8-bit bytes
|
||||
uint64_t q[25]; // 64-bit words
|
||||
} st;
|
||||
int pt, rsiz, mdlen; // these don't overflow
|
||||
} sha3_ctx_t;
|
||||
|
||||
// Compression function.
|
||||
void sha3_keccakf(uint64_t st[25]);
|
||||
|
||||
// OpenSSL - like interfece
|
||||
int sha3_init(sha3_ctx_t *c, int mdlen); // mdlen = hash output in bytes
|
||||
int sha3_update(sha3_ctx_t *c, const void *data, size_t len);
|
||||
int sha3_final(void *md, sha3_ctx_t *c); // digest goes to md
|
||||
|
||||
// compute a sha3 hash (md) of given byte length from "in"
|
||||
void *sha3(const void *in, size_t inlen, void *md, int mdlen);
|
||||
|
||||
// SHAKE128 and SHAKE256 extensible-output functions
|
||||
#define shake128_init(c) sha3_init(c, 16)
|
||||
#define shake256_init(c) sha3_init(c, 32)
|
||||
#define shake_update sha3_update
|
||||
|
||||
void shake_xof(sha3_ctx_t *c);
|
||||
void shake_out(sha3_ctx_t *c, void *out, size_t len);
|
||||
|
||||
#endif
|
||||
287
Blastproof/initfsgen/sign.c
Normal file
287
Blastproof/initfsgen/sign.c
Normal file
@@ -0,0 +1,287 @@
|
||||
#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;
|
||||
}
|
||||
13
Blastproof/initfsgen/thash.h
Normal file
13
Blastproof/initfsgen/thash.h
Normal file
@@ -0,0 +1,13 @@
|
||||
#ifndef SPX_THASH_H
|
||||
#define SPX_THASH_H
|
||||
|
||||
#include "context.h"
|
||||
#include "params.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define thash SPX_NAMESPACE(thash)
|
||||
void thash(unsigned char *out, const unsigned char *in, unsigned int inblocks,
|
||||
const spx_ctx *ctx, uint32_t addr[8]);
|
||||
|
||||
#endif
|
||||
74
Blastproof/initfsgen/thash_sha2_robust.c
Normal file
74
Blastproof/initfsgen/thash_sha2_robust.c
Normal file
@@ -0,0 +1,74 @@
|
||||
#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
|
||||
59
Blastproof/initfsgen/thash_sha2_simple.c
Normal file
59
Blastproof/initfsgen/thash_sha2_simple.c
Normal file
@@ -0,0 +1,59 @@
|
||||
#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
|
||||
154
Blastproof/initfsgen/utils.c
Normal file
154
Blastproof/initfsgen/utils.c
Normal file
@@ -0,0 +1,154 @@
|
||||
#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);
|
||||
}
|
||||
64
Blastproof/initfsgen/utils.h
Normal file
64
Blastproof/initfsgen/utils.h
Normal file
@@ -0,0 +1,64 @@
|
||||
#ifndef SPX_UTILS_H
|
||||
#define SPX_UTILS_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include "params.h"
|
||||
#include "context.h"
|
||||
|
||||
|
||||
/* To support MSVC use alloca() instead of VLAs. See #20. */
|
||||
#ifdef _MSC_VER
|
||||
/* MSVC defines _alloca in malloc.h */
|
||||
# include <malloc.h>
|
||||
/* Note: _malloca(), which is recommended over deprecated _alloca,
|
||||
requires that you call _freea(). So we stick with _alloca */
|
||||
# define SPX_VLA(__t,__x,__s) __t *__x = (__t*)_alloca((__s)*sizeof(__t))
|
||||
#else
|
||||
# define SPX_VLA(__t,__x,__s) __t __x[__s]
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Converts the value of 'in' to 'outlen' bytes in big-endian byte order.
|
||||
*/
|
||||
#define ull_to_bytes SPX_NAMESPACE(ull_to_bytes)
|
||||
void ull_to_bytes(unsigned char *out, unsigned int outlen,
|
||||
unsigned long long in);
|
||||
#define u32_to_bytes SPX_NAMESPACE(u32_to_bytes)
|
||||
void u32_to_bytes(unsigned char *out, uint32_t in);
|
||||
|
||||
/**
|
||||
* Converts the inlen bytes in 'in' from big-endian byte order to an integer.
|
||||
*/
|
||||
#define bytes_to_ull SPX_NAMESPACE(bytes_to_ull)
|
||||
unsigned long long bytes_to_ull(const unsigned char *in, unsigned int inlen);
|
||||
|
||||
/**
|
||||
* Computes a root node given a leaf and an auth path.
|
||||
* Expects address to be complete other than the tree_height and tree_index.
|
||||
*/
|
||||
#define compute_root SPX_NAMESPACE(compute_root)
|
||||
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]);
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
#define treehash SPX_NAMESPACE(treehash)
|
||||
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 /* ctx */,
|
||||
uint32_t /* addr_idx */, const uint32_t[8] /* tree_addr */),
|
||||
uint32_t tree_addr[8]);
|
||||
|
||||
|
||||
#endif
|
||||
100
Blastproof/initfsgen/utilsx1.c
Normal file
100
Blastproof/initfsgen/utilsx1.c
Normal file
@@ -0,0 +1,100 @@
|
||||
#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);
|
||||
}
|
||||
}
|
||||
26
Blastproof/initfsgen/utilsx1.h
Normal file
26
Blastproof/initfsgen/utilsx1.h
Normal file
@@ -0,0 +1,26 @@
|
||||
#ifndef SPX_UTILSX4_H
|
||||
#define SPX_UTILSX4_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include "params.h"
|
||||
#include "context.h"
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
#define treehashx1 SPX_NAMESPACE(treehashx1)
|
||||
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 leaf */,
|
||||
const spx_ctx* /* ctx */,
|
||||
uint32_t addr_idx, void *info),
|
||||
uint32_t tree_addrx4[8], void *info);
|
||||
|
||||
#endif
|
||||
112
Blastproof/initfsgen/wots.c
Normal file
112
Blastproof/initfsgen/wots.c
Normal file
@@ -0,0 +1,112 @@
|
||||
#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);
|
||||
}
|
||||
}
|
||||
25
Blastproof/initfsgen/wots.h
Normal file
25
Blastproof/initfsgen/wots.h
Normal file
@@ -0,0 +1,25 @@
|
||||
#ifndef SPX_WOTS_H
|
||||
#define SPX_WOTS_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "params.h"
|
||||
#include "context.h"
|
||||
|
||||
/**
|
||||
* Takes a WOTS signature and an n-byte message, computes a WOTS public key.
|
||||
*
|
||||
* Writes the computed public key to 'pk'.
|
||||
*/
|
||||
#define wots_pk_from_sig SPX_NAMESPACE(wots_pk_from_sig)
|
||||
void wots_pk_from_sig(unsigned char *pk,
|
||||
const unsigned char *sig, const unsigned char *msg,
|
||||
const spx_ctx *ctx, uint32_t addr[8]);
|
||||
|
||||
/*
|
||||
* Compute the chain lengths needed for a given message hash
|
||||
*/
|
||||
#define chain_lengths SPX_NAMESPACE(chain_lengths)
|
||||
void chain_lengths(unsigned int *lengths, const unsigned char *msg);
|
||||
|
||||
#endif
|
||||
73
Blastproof/initfsgen/wotsx1.c
Normal file
73
Blastproof/initfsgen/wotsx1.c
Normal file
@@ -0,0 +1,73 @@
|
||||
#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);
|
||||
}
|
||||
36
Blastproof/initfsgen/wotsx1.h
Normal file
36
Blastproof/initfsgen/wotsx1.h
Normal file
@@ -0,0 +1,36 @@
|
||||
#if !defined( WOTSX1_H_ )
|
||||
#define WOTSX1_H_
|
||||
|
||||
#include <string.h>
|
||||
|
||||
/*
|
||||
* This is here to provide an interface to the internal wots_gen_leafx1
|
||||
* routine. While this routine is not referenced in the package outside of
|
||||
* wots.c, it is called from the stand-alone benchmark code to characterize
|
||||
* the performance
|
||||
*/
|
||||
struct leaf_info_x1 {
|
||||
unsigned char *wots_sig;
|
||||
uint32_t wots_sign_leaf; /* The index of the WOTS we're using to sign */
|
||||
uint32_t *wots_steps;
|
||||
uint32_t leaf_addr[8];
|
||||
uint32_t pk_addr[8];
|
||||
};
|
||||
|
||||
/* Macro to set the leaf_info to something 'benign', that is, it would */
|
||||
/* run with the same time as it does during the real signing process */
|
||||
/* Used only by the benchmark code */
|
||||
#define INITIALIZE_LEAF_INFO_X1(info, addr, step_buffer) { \
|
||||
info.wots_sig = 0; \
|
||||
info.wots_sign_leaf = ~0u; \
|
||||
info.wots_steps = step_buffer; \
|
||||
memcpy( &info.leaf_addr[0], addr, 32 ); \
|
||||
memcpy( &info.pk_addr[0], addr, 32 ); \
|
||||
}
|
||||
|
||||
#define wots_gen_leafx1 SPX_NAMESPACE(wots_gen_leafx1)
|
||||
void wots_gen_leafx1(unsigned char *dest,
|
||||
const spx_ctx *ctx,
|
||||
uint32_t leaf_idx, void *v_info);
|
||||
|
||||
#endif /* WOTSX1_H_ */
|
||||
Reference in New Issue
Block a user