gestumblinde

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

slh.py (3331B)


      1 """
      2 From Section 9.
      3 Top level functions of SLH-DSA.
      4 """
      5 
      6 from secrets import token_bytes
      7 from address import Address, AddressType
      8 from slh_dsa import SLHDSA
      9 from utils import cdiv, toByte, toInt
     10 from xmss import xmss_node
     11 from fors import fors_sign, fors_pk_from_sig
     12 from ht import ht_sign, ht_verify
     13 
     14 def slh_keygen(ctx: SLHDSA):
     15     """Generate an SLH-DSA key pair"""
     16     sk_seed = token_bytes(ctx.n)
     17     sk_prf = token_bytes(ctx.n)
     18     pk_seed = token_bytes(ctx.n)
     19 
     20     adrs = Address(toByte(0, 32)) # adrs <- toByte(0,32)
     21     adrs.set_layer_address(ctx.d - 1)
     22     pk_root = xmss_node(sk_seed, 0, ctx.hp, pk_seed, adrs, ctx)
     23 
     24     return ((sk_seed, sk_prf, pk_seed, pk_root), (pk_seed, pk_root))
     25 
     26 def slh_sign(M: bytes, sk: tuple[bytes, bytes, bytes, bytes], ctx: SLHDSA, randomize = False) -> bytes:
     27     """Generate an SLH-DSA signature"""
     28     assert len(sk) == 4
     29     sk_seed, sk_prf, pk_seed, pk_root = sk
     30 
     31     adrs = Address(toByte(0, 32)) # adrs <- toByte(0,32)
     32 
     33     opt_rand = pk_seed
     34     if randomize:
     35         opt_rand = token_bytes(ctx.n)
     36     r = ctx.prf_msg(sk_prf, opt_rand, M)
     37     sig = r
     38 
     39     digest = ctx.h_msg(r, pk_seed, pk_root, M)
     40     md = digest[0 : cdiv(ctx.k*ctx.a, 8)]
     41     tmp_idx_tree = digest[cdiv(ctx.k*ctx.a,8) : cdiv(ctx.k*ctx.a,8)+cdiv(ctx.h-ctx.h//ctx.d,8)]
     42     tmp_idx_leaf = digest[cdiv(ctx.k*ctx.a,8)+cdiv(ctx.h-ctx.h//ctx.d,8) : cdiv(ctx.k*ctx.a,8)+cdiv(ctx.h-ctx.h//ctx.d,8)+cdiv(ctx.h,8*ctx.d)]
     43     idx_tree = toInt(tmp_idx_tree, cdiv(ctx.h-ctx.h//ctx.d,8)) % 2**(ctx.h-ctx.h//ctx.d)
     44     idx_leaf = toInt(tmp_idx_leaf, cdiv(ctx.h,8*ctx.d)) % 2**(ctx.h//ctx.d)
     45 
     46     adrs.set_tree_address(idx_tree)
     47     adrs.set_type_and_clear(AddressType.FORS_TREE)
     48     adrs.set_key_pair_address(toByte(idx_leaf, 4))
     49     sig_fors = fors_sign(md, sk_seed, pk_seed, adrs, ctx)
     50     sig += sig_fors
     51 
     52     pk_fors = fors_pk_from_sig(sig_fors, md, pk_seed, adrs, ctx)
     53 
     54     sig_ht = ht_sign(pk_fors, sk_seed, pk_seed, idx_tree, idx_leaf, ctx)
     55     sig += sig_ht
     56 
     57     return sig
     58 
     59 def slh_verify(M: bytes, sig: bytes, pk: tuple[bytes, bytes], ctx: SLHDSA) -> bool:
     60     """Verify an SLH-DSA signature"""
     61 
     62     if len(sig) != (1 + ctx.k * (1 + ctx.a) + ctx.h + ctx.d * ctx.wotsp_len) * ctx.n:
     63         return False
     64 
     65     pk_seed, pk_root = pk
     66 
     67     adrs = Address(toByte(0, 32)) # adrs <- toByte(0,32)
     68     r = sig[0:ctx.n] # r <- sig.getR()
     69     sig_fors = sig[ctx.n : (1+ctx.k*(1+ctx.a))*ctx.n] # sig <- sig.getSIG_FORS()
     70     sig_ht = sig[(1+ctx.k*(1+ctx.a))*ctx.n : (1+ctx.k*(1+ctx.a)+ctx.h+ctx.d*ctx.wotsp_len)*ctx.n] # sig <- sig.getSIG_HT()
     71     
     72     digest = ctx.h_msg(r, pk_seed, pk_root, M)
     73     md = digest[0 : cdiv(ctx.k*ctx.a, 8)]
     74     tmp_idx_tree = digest[cdiv(ctx.k*ctx.a,8) : cdiv(ctx.k*ctx.a,8)+cdiv(ctx.h-ctx.h//ctx.d,8)]
     75     tmp_idx_leaf = digest[cdiv(ctx.k*ctx.a,8)+cdiv(ctx.h-ctx.h//ctx.d,8) : cdiv(ctx.k*ctx.a,8)+cdiv(ctx.h-ctx.h//ctx.d,8)+cdiv(ctx.h,8*ctx.d)]
     76     idx_tree = toInt(tmp_idx_tree, cdiv(ctx.h-ctx.h//ctx.d,8)) % 2**(ctx.h-ctx.h//ctx.d)
     77     idx_leaf = toInt(tmp_idx_leaf, cdiv(ctx.h,8*ctx.d)) % 2**(ctx.h//ctx.d)
     78 
     79     adrs.set_tree_address(idx_tree)
     80     adrs.set_type_and_clear(AddressType.FORS_TREE)
     81     adrs.set_key_pair_address(toByte(idx_leaf, 4))
     82 
     83     pk_fors = fors_pk_from_sig(sig_fors, md, pk_seed, adrs, ctx)
     84 
     85     return ht_verify(pk_fors, sig_ht, pk_seed, idx_tree, idx_leaf, pk_root, ctx)
     86