- #include <stdint.h>
- #include <string.h>
-
- #include "xmss_commons.h"
- #include "hash.h"
- #include "wots.h"
- #include "hash_address.h"
- #include "params.h"
-
- /**
- * Helper method for pseudorandom key generation.
- * Expands an n-byte array into a len*n byte array using the `prf` function.
- */
- static void expand_seed(const xmss_params *params,
- unsigned char *outseeds, const unsigned char *inseed)
- {
- uint32_t i;
- unsigned char ctr[32];
-
- for (i = 0; i < params->wots_len; i++) {
- ull_to_bytes(ctr, 32, i);
- prf(params, outseeds + i*params->n, ctr, inseed);
- }
- }
-
- /**
- * 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(const xmss_params *params,
- unsigned char *out, const unsigned char *in,
- unsigned int start, unsigned int steps,
- const unsigned char *pub_seed, uint32_t addr[8])
- {
- uint32_t i;
-
- /* Initialize out with the value at position 'start'. */
- memcpy(out, in, params->n);
-
- /* Iterate 'steps' calls to the hash function. */
- for (i = start; i < (start+steps) && i < params->wots_w; i++) {
- set_hash_addr(addr, i);
- hash_f(params, out, out, pub_seed, 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(const xmss_params *params,
- 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 -= params->wots_log_w;
- output[out] = (total >> bits) & (params->wots_w - 1);
- out++;
- }
- }
-
- /* Computes the WOTS+ checksum over a message (in base_w). */
- static void wots_checksum(const xmss_params *params,
- int *csum_base_w, const int *msg_base_w)
- {
- int csum = 0;
- unsigned char csum_bytes[(params->wots_len2 * params->wots_log_w + 7) / 8];
- unsigned int i;
-
- /* Compute checksum. */
- for (i = 0; i < params->wots_len1; i++) {
- csum += params->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 - ((params->wots_len2 * params->wots_log_w) % 8));
- ull_to_bytes(csum_bytes, sizeof(csum_bytes), csum);
- base_w(params, csum_base_w, params->wots_len2, csum_bytes);
- }
-
- /* Takes a message and derives the matching chain lengths. */
- static void chain_lengths(const xmss_params *params,
- int *lengths, const unsigned char *msg)
- {
- base_w(params, lengths, params->wots_len1, msg);
- wots_checksum(params, lengths + params->wots_len1, lengths);
- }
-
- /**
- * WOTS key generation. Takes a 32 byte seed for the private key, expands it to
- * a full WOTS private key and computes the corresponding public key.
- * It requires the seed pub_seed (used to generate bitmasks and hash keys)
- * and the address of this WOTS key pair.
- *
- * Writes the computed public key to 'pk'.
- */
- void wots_pkgen(const xmss_params *params,
- unsigned char *pk, const unsigned char *seed,
- const unsigned char *pub_seed, uint32_t addr[8])
- {
- uint32_t i;
-
- /* The WOTS+ private key is derived from the seed. */
- expand_seed(params, pk, seed);
-
- for (i = 0; i < params->wots_len; i++) {
- set_chain_addr(addr, i);
- gen_chain(params, pk + i*params->n, pk + i*params->n,
- 0, params->wots_w - 1, pub_seed, addr);
- }
- }
-
- /**
- * Takes a m-byte message and the 32-byte seed for the private key to compute a
- * signature that is placed at 'sig'.
- */
- void wots_sign(const xmss_params *params,
- unsigned char *sig, const unsigned char *msg,
- const unsigned char *seed, const unsigned char *pub_seed,
- uint32_t addr[8])
- {
- int lengths[params->wots_len];
- uint32_t i;
-
- chain_lengths(params, lengths, msg);
-
- /* The WOTS+ private key is derived from the seed. */
- expand_seed(params, sig, seed);
-
- for (i = 0; i < params->wots_len; i++) {
- set_chain_addr(addr, i);
- gen_chain(params, sig + i*params->n, sig + i*params->n,
- 0, lengths[i], pub_seed, addr);
- }
- }
-
- /**
- * Takes a WOTS signature and an m-byte message, computes a WOTS public key.
- *
- * Writes the computed public key to 'pk'.
- */
- void wots_pk_from_sig(const xmss_params *params, unsigned char *pk,
- const unsigned char *sig, const unsigned char *msg,
- const unsigned char *pub_seed, uint32_t addr[8])
- {
- int lengths[params->wots_len];
- uint32_t i;
-
- chain_lengths(params, lengths, msg);
-
- for (i = 0; i < params->wots_len; i++) {
- set_chain_addr(addr, i);
- gen_chain(params, pk + i*params->n, sig + i*params->n,
- lengths[i], params->wots_w - 1 - lengths[i], pub_seed, addr);
- }
- }
|