gestumblinde

Gestumblinde - reference implementation of SLH-DSA
git clone git://www.tkruger.se/gestumblinde.git
Log | Files | Refs | README

xmss.c (3207B)


      1 #include "xmss.h"
      2 
      3 /*
      4  * Compute the root of a Merkle subtree of WOTS+ public keys.
      5  *
      6  * Returns length of written output.
      7  */
      8 int xmss_node(uint8_t *out, const uint8_t sk_seed[ENN], const uint64_t i,
      9               const uint64_t z, const uint8_t pk_seed[ENN],
     10               uint32_t adrs[ADRS_LEN]) {
     11   if (z > HP || i >= (1 << (HP - z)))
     12     return 0;
     13 
     14   if (z == 0) {
     15     adrs[ADRS_TYPE_IDX] = WOTS_HASH;
     16     adrs[ADRS_KEYPAIR_IDX] = htobe32((uint32_t)i);
     17     bzero(&adrs[ADRS_CHAIN_ADDRESS_IDX], 2 * sizeof(*adrs));
     18 
     19     wotsp_pkgen(out, sk_seed, pk_seed, adrs);
     20   } else {
     21     uint8_t buffer[2 * ENN];
     22     uint8_t *left = buffer;
     23     uint8_t *right = buffer + ENN;
     24 
     25 #ifndef NDEBUG
     26     int r = xmss_node(left, sk_seed, 2 * i, z - 1, pk_seed, adrs);
     27     assert(r == ENN);
     28     r = xmss_node(right, sk_seed, 2 * i + 1, z - 1, pk_seed, adrs);
     29     assert(r == ENN);
     30 #else
     31     xmss_node(left, sk_seed, 2 * i, z - 1, pk_seed, adrs);
     32     xmss_node(right, sk_seed, 2 * i + 1, z - 1, pk_seed, adrs);
     33 #endif
     34 
     35     adrs[ADRS_TYPE_IDX] = TREE;
     36     adrs[ADRS_KEYPAIR_IDX] = 0; // padding zero for TREE type
     37     adrs[ADRS_TREE_HEIGHT_IDX] = htobe32((uint32_t)z);
     38     adrs[ADRS_TREE_INDEX_IDX] = htobe32((uint32_t)i);
     39 
     40     hash_h(out, pk_seed, adrs, buffer);
     41   }
     42 
     43   return ENN;
     44 }
     45 
     46 /*
     47  * Generate an XMSS signature
     48  */
     49 int xmss_sign(uint8_t *out, const uint8_t m[ENN], const uint8_t sk_seed[ENN],
     50               const uint64_t idx, const uint8_t pk_seed[ENN],
     51               uint32_t adrs[ADRS_LEN]) {
     52   assert(idx <= (1 << HP));
     53   size_t j;
     54 
     55   uint8_t *auth = out + (WOTSP_LEN * ENN);
     56   uint64_t k;
     57   for (j = 0; j < HP; j++) {
     58     k = (idx >> j) ^ 0x01;
     59     xmss_node(auth, sk_seed, k, j, pk_seed, adrs);
     60     auth += ENN;
     61   }
     62 
     63   adrs[ADRS_TYPE_IDX] = WOTS_HASH;
     64   adrs[ADRS_KEYPAIR_IDX] = htobe32((uint32_t)idx);
     65   bzero(&adrs[ADRS_CHAIN_ADDRESS_IDX], 2 * sizeof(*adrs));
     66 
     67   wotsp_sign(out, m, sk_seed, pk_seed, adrs);
     68 
     69   return 0;
     70 }
     71 
     72 /*
     73  * Compute an XMSS public key from an XMSS signature
     74  */
     75 int xmss_pk_from_sig(uint8_t *out, const uint64_t idx, const uint8_t *sig,
     76                      const uint8_t m[ENN], const uint8_t pk_seed[ENN],
     77                      uint32_t adrs[ADRS_LEN]) {
     78   adrs[ADRS_TYPE_IDX] = WOTS_HASH;
     79   adrs[ADRS_KEYPAIR_IDX] = htobe32((uint32_t)idx);
     80   bzero(&adrs[ADRS_CHAIN_ADDRESS_IDX], 2 * sizeof(*adrs));
     81 
     82   const uint8_t *auth = sig + (WOTSP_LEN * ENN);
     83   uint8_t node_data[3 * ENN];
     84 
     85   wotsp_pk_from_sig(node_data + ENN, sig, m, ENN, pk_seed, adrs);
     86 
     87   adrs[ADRS_TYPE_IDX] = TREE;
     88   adrs[ADRS_KEYPAIR_IDX] = 0; // padding zero for TREE type
     89   adrs[ADRS_TREE_INDEX_IDX] = htobe32((uint32_t)idx);
     90 
     91   size_t k;
     92   for (k = 0; k < HP; k++) {
     93     adrs[ADRS_TREE_HEIGHT_IDX] = htobe32((uint32_t)k + 1);
     94     uint32_t ti = betoh32(adrs[ADRS_TREE_INDEX_IDX]);
     95     if ((idx >> k) % 2 == 0) {
     96       adrs[ADRS_TREE_INDEX_IDX] = htobe32(ti >> 1);
     97       memcpy(node_data + 2 * ENN, auth + k * ENN, ENN);
     98       hash_h(node_data + ENN, pk_seed, adrs, node_data + ENN);
     99     } else {
    100       adrs[ADRS_TREE_INDEX_IDX] = htobe32((ti - 1) >> 1);
    101       memcpy(node_data, auth + k * ENN, ENN);
    102       hash_h(node_data + ENN, pk_seed, adrs, node_data);
    103     }
    104   }
    105 
    106   memcpy(out, node_data + ENN, ENN);
    107 
    108   return 0;
    109 }