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