|
| 1 | +#include "build_merkle.h" |
| 2 | +#include "sphincs_hash.h" |
| 3 | +#include "adr.h" |
| 4 | +#include "private_key_gen.h" |
| 5 | +#include "zeroize.h" |
| 6 | + |
| 7 | +/* |
| 8 | + * This is the object that incrementally builds a Merkle tree, and produces |
| 9 | + * the authentication path to the specified node (target_node) and the |
| 10 | + * root value |
| 11 | + * This does it incrementally, because we want to be able to spread the work |
| 12 | + * over a number of signature generation requests |
| 13 | + * This is split out of the full step procedure because the public key |
| 14 | + * generation process also uses this (and also to limit the size of the |
| 15 | + * step function, which is already too huge) |
| 16 | + * |
| 17 | + * The point of this object is to place the results into auth_path and root |
| 18 | + * If auth_path is non-NULL, then the authentication path for target_node |
| 19 | + * is placed there |
| 20 | + * If root is non-NULL, then the root node value is placed there |
| 21 | + */ |
| 22 | + |
| 23 | +bool init_build_merkle( struct build_merkle_state *state, |
| 24 | + const void *sk_seed, const void *pk_seed, |
| 25 | + hash_t hash, int tree_height, |
| 26 | + unsigned layer, uint_fast64_t tree, |
| 27 | + int target_node, unsigned char *auth_path, |
| 28 | + unsigned char *root) { |
| 29 | + state->sk_seed = sk_seed; |
| 30 | + state->pk_seed = pk_seed; |
| 31 | + SHA256_set_first_block(&state->pk_seed_pre, pk_seed, hash_len(hash)); |
| 32 | + state->hash = hash; |
| 33 | + state->n = hash_len(hash); |
| 34 | + switch (hash_len( hash )) { |
| 35 | + case 16: state->wots_digits = 32 + 3; break; |
| 36 | + case 24: state->wots_digits = 48 + 3; break; |
| 37 | + case 32: state->wots_digits = 64 + 3; break; |
| 38 | + default: return false; |
| 39 | + } |
| 40 | + state->tree_height = tree_height; |
| 41 | + state->target_node = target_node; |
| 42 | + set_layer_address( state->adr, layer ); |
| 43 | + set_tree_address( state->adr, tree ); |
| 44 | + /* The rest of adr will be initialized later */ |
| 45 | + state->auth_path = auth_path; |
| 46 | + state->root = root; |
| 47 | + state->current_node = 0; |
| 48 | + |
| 49 | + return true; |
| 50 | +} |
| 51 | + |
| 52 | +/* |
| 53 | + * This performs the next step in producing the authentication path and/or |
| 54 | + * the root |
| 55 | + * This returns TRUE if we're done |
| 56 | + * If ret_hc is non-NULL, we place the number of hash compression operations |
| 57 | + * we've done there |
| 58 | + */ |
| 59 | +bool step_build_merkle(struct build_merkle_state *state, |
| 60 | + int *ret_hc) { |
| 61 | + |
| 62 | + int hc_done_so_far = 0; /* Count of the number of hash */ |
| 63 | + /* computations we've done */ |
| 64 | + |
| 65 | +#if SPEED_SETTING |
| 66 | +#define MERKLE_CHAINS_PER_ITER 1 /* generating 1 OTS public key takes */ |
| 67 | + /* about as long as the LMS step with W=2 */ |
| 68 | +#else |
| 69 | +#define MERKLE_CHAINS_PER_ITER 2 /* generating 2 OTS public keys takes */ |
| 70 | + /* about as long as the LMS step with W=4 */ |
| 71 | +#endif |
| 72 | + int m; |
| 73 | + struct private_key_generator gen; |
| 74 | + bool all_done_flag = false; |
| 75 | + |
| 76 | + for (m=0; m<MERKLE_CHAINS_PER_ITER; m++) { |
| 77 | + int current_node = state->current_node; |
| 78 | + if (current_node >= (1 << state->tree_height)) { |
| 79 | + /* We're done */ |
| 80 | + all_done_flag = true; |
| 81 | + break; |
| 82 | + } |
| 83 | + |
| 84 | + /* Fire up the engine that'll produce private WOTS keys */ |
| 85 | + init_private_key_gen( &gen, state->sk_seed, state->n, state->adr, |
| 86 | + ADR_CONST_FOR_TREE ); |
| 87 | + hc_done_so_far += 1; /* This does about 1 hash compression operation */ |
| 88 | + |
| 89 | + /* Build a WOTS public key */ |
| 90 | + int i; |
| 91 | + set_type( state->adr, WOTS_HASH_ADDRESS ); |
| 92 | + set_key_pair_address( state->adr, current_node ); |
| 93 | + int n = state->n; |
| 94 | + |
| 95 | + uint32_t wots_buffer[MAX_HASH_LEN/4 * MAX_WOTS_DIGITS]; /* We store */ |
| 96 | + /* the tops of the WOTS+ chains here */ |
| 97 | + for (i = 0; i < 51; i++) { |
| 98 | + set_chain_address( state->adr, i ); |
| 99 | + |
| 100 | + /* Create the private WOTS+ key */ |
| 101 | + set_hash_address( state->adr, 0 ); |
| 102 | + void *digit = &wots_buffer[ (n/4)*i ]; |
| 103 | + do_private_key_gen( digit, n, &gen, &state->adr[LEN_ADR-16] ); |
| 104 | + |
| 105 | + /* Now, advance it to the top of the WOTS+ chain */ |
| 106 | + int j; |
| 107 | + for (j=0; j<15; j++) { |
| 108 | + set_hash_address( state->adr, j ); |
| 109 | + do_F(digit, state->hash, &state->pk_seed_pre, state->adr, |
| 110 | + digit); |
| 111 | + } |
| 112 | + } |
| 113 | + /* The number of hash compression operations we've done in the */ |
| 114 | + /* above loop */ |
| 115 | + hc_done_so_far += 51 * (1 + 15); |
| 116 | + |
| 117 | + /* We've computing all the public WOTS digits */ |
| 118 | + /* Now, compress the hashes into a single value */ |
| 119 | + set_type( state->adr, WOTS_KEY_COMPRESSION ); |
| 120 | + set_key_pair_address( state->adr, current_node ); |
| 121 | + unsigned char buffer[ MAX_HASH_LEN ]; |
| 122 | + |
| 123 | + do_thash( buffer, state->hash, &state->pk_seed_pre, state->adr, |
| 124 | + wots_buffer, n * state->wots_digits );\ |
| 125 | + /* The approximate number of hashes in the above t-hash */ |
| 126 | + hc_done_so_far += (n * state->wots_digits) / 16 + 1 + |
| 127 | + (n * state->wots_digits) / 32; |
| 128 | + |
| 129 | + /* We've put the full WOTS public key */ |
| 130 | + /* Now, walk up the Merkle tree to combine it with previous computed */ |
| 131 | + /* WOTS public keys */ |
| 132 | + int h; |
| 133 | + for (h = 0;; h++) { |
| 134 | + if (state->auth_path) { |
| 135 | + /* If this node is on the authentication path (that is, */ |
| 136 | + /* adjacent to the path from the root to the target node), */ |
| 137 | + /* write it out */ |
| 138 | + if ((state->target_node^current_node) >> h == 1) { |
| 139 | + memcpy( state->auth_path + h*n, buffer, n ); |
| 140 | + } |
| 141 | + } |
| 142 | + /* Check which child we are to the node immediately above us */ |
| 143 | + if (current_node & (1<<h)) { |
| 144 | + /* We're the right child at this node */ |
| 145 | + /* Combine it with the corresponding left child */ |
| 146 | + set_type(state->adr, HASH_TREE_ADDRESS); |
| 147 | + set_tree_height(state->adr, h+1 ); |
| 148 | + set_tree_index(state->adr, current_node >> (h+1)); |
| 149 | + do_H(buffer, state->hash, &state->pk_seed_pre, state->adr, |
| 150 | + state->stack + h*n, buffer ); |
| 151 | + hc_done_so_far += 2; /* a do_H does 2 hash compressios */ |
| 152 | + } else { |
| 153 | + if (h == state->tree_height) { |
| 154 | + /* Actually, there is no node above us; we're at the top */ |
| 155 | + /* of the tree (aka the root) */ |
| 156 | + if (state->root) memcpy( state->root, buffer, n ); |
| 157 | + all_done_flag = true; /* We built the entire tree */ |
| 158 | + } else { |
| 159 | + /* We're the left child at this node */ |
| 160 | + /* Store it for when we have computed the right child */ |
| 161 | + memcpy( state->stack + h*n, buffer, n ); |
| 162 | + } |
| 163 | + break; |
| 164 | + } |
| 165 | + } |
| 166 | + |
| 167 | + /* On the next iteration, start working on the next WOTS leaf */ |
| 168 | + state->current_node += 1; |
| 169 | + } |
| 170 | + |
| 171 | + zeroize( &gen, sizeof gen ); /* There's private data here */ |
| 172 | + |
| 173 | + if (ret_hc) *ret_hc = hc_done_so_far; |
| 174 | + return all_done_flag; |
| 175 | +} |
0 commit comments