diff --git a/Cargo.toml b/Cargo.toml
index 139fdae..dfad9b2 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,11 +1,31 @@
[package]
-name = "slh-dsa-rs"
+name = "fips205"
version = "0.1.1"
edition = "2021"
license = "MIT OR Apache-2.0"
description = "FIPS 205 (draft): Stateless Hash-Based Digital Signature Standard"
-repository = "https://github.com/integritychain/slh-dsa-rs"
+repository = "https://github.com/integritychain/fips205"
rust-version = "1.73"
[dependencies]
+zeroize = { version = "1.6.0", features = ["zeroize_derive"] }
+rand_core = { version = "0.6.4", default-features = false }
+
+[features]
+default = ["default-rng", "slh_dsa_sha2_128s", "slh_dsa_shake_128s", "slh_dsa_sha2_128f", "slh_dsa_shake_128f",
+ "slh_dsa_sha2_192s", "slh_dsa_shake_192s", "slh_dsa_sha2_192f", "slh_dsa_shake_192f",
+ "slh_dsa_sha2_256s", "slh_dsa_shake_256s", "slh_dsa_sha2_256f", "slh_dsa_shake_256f"]
+default-rng = ["rand_core/getrandom"]
+slh_dsa_sha2_128s = []
+slh_dsa_shake_128s = []
+slh_dsa_sha2_128f = []
+slh_dsa_shake_128f = []
+slh_dsa_sha2_192s = []
+slh_dsa_shake_192s = []
+slh_dsa_sha2_192f = []
+slh_dsa_shake_192f = []
+slh_dsa_sha2_256s = []
+slh_dsa_shake_256s = []
+slh_dsa_sha2_256f = []
+slh_dsa_shake_256f = []
diff --git a/src/algs.rs b/src/algs.rs
new file mode 100644
index 0000000..c1e1089
--- /dev/null
+++ b/src/algs.rs
@@ -0,0 +1,502 @@
+use alloc::vec;
+use alloc::vec::Vec;
+use crate::Params;
+use crate::traits::PK;
+
+/// Algorithm 1: `toInt(X, n)` on page 14.
+/// Convert a byte string to an integer.
+///
+/// Input: n-byte string `X`.
+/// Output: Integer value of `X`.
+pub(crate) fn to_int(x: &[u8], n: usize) -> u64 {
+ assert_eq!(x.len(), n);
+ // 1: total ← 0
+ let mut total = 0_u64;
+ // 2:
+ // 3: for i from 0 to n − 1 do
+ for i in 0..n {
+ // 4: total ← 256 · total + X[i]
+ total = (total << 8) + x[i] as u64;
+ // 5: end for
+ }
+ // 6: return total
+ total
+}
+
+
+/// Algorithm 2: `toByte(x, n)` on page 15.
+/// Convert an integer to a byte string.
+///
+/// Input: Integer `x`, string length `n`.
+/// Output: Byte string of length `n` containing binary representation of `x` in big-endian byte-order.
+pub(crate) fn to_byte(x: u64, n: usize) -> Vec {
+ let mut s = vec![0u8; n];
+
+ // 1: total ← x
+ let mut total = x;
+
+ // 2:
+
+ // 3: for i from 0 to n − 1 do
+ for i in 0..n {
+ //
+ // 4: S[n − 1 − i] ← total mod 256 ▷ Least significant 8 bits of total
+ s[n - 1 - i] = total as u8;
+
+ // 5: total ← total ≫ 8
+ total >>= 8;
+
+ // 6: end for
+ }
+
+ // 7: return S
+ s
+}
+
+
+/// Algorithm 3: `base_2^b(X, b, out_len)` on page 15.
+/// Compute the base 2^b representation of X.
+///
+/// Input: Byte string `X` of length at least ceil(`out_len·b/8`), integer `b`, output length `out_len`.
+/// Output: Array of `out_len` integers in the range `[0, . . . , 2^b − 1]`.
+pub(crate) fn base_2b(x: &[u8], b: u32, out_len: usize) -> Vec {
+ assert!(x.len() >= out_len * b as usize / 8);
+ let mut baseb = vec![0u64; out_len];
+ // 1: in ← 0
+ let mut inn = 0;
+ // 2: bits ← 0
+ let mut bits = 0;
+ // 3: total ← 0
+ let mut total = 0;
+ // 4:
+ // 5: for out from 0 to out_len − 1 do
+ for out in 0..out_len {
+ // 6: while bits < b do
+ while bits < b {
+ // 7: total ← (total ≪ 8) + X[in]
+ total = (total << 8) + x[inn] as u64;
+ // 8: in ← in + 1
+ inn += 1;
+ // 9: bits ← bits + 8
+ bits += 8;
+ // 10: end while
+ }
+ // 11: bits ← bits − b
+ bits -= b;
+ // 12: baseb[out] ← (total ≫ bits) mod 2^b
+ baseb[out] = (total >> bits) & (2u64.pow(b) - 1);
+ // 13: end for
+ }
+ // 14: return baseb
+ baseb
+}
+
+
+/// Algorithm 4: `chain(X, i, s, PK.seed, ADRS)` on page 17.
+/// Chaining function used in WOTS+.
+///
+/// Input: Input string `X`, start index `i`, number of steps `s`, public seed `PK.seed`, address `ADRS`.
+/// Output: Value of `F` iterated `s` times on `X`.
+pub(crate) fn chain(params: &Params, _x: &[u8], i: usize, s: usize, pk: &impl PK, _adrs: u32) -> Option<[u8; 32]> {
+ // 1: if (i + s) ≥ w then
+ if (i + s) >= params.w {
+ // 2: return NULL
+ return None;
+ // 3: end if
+ }
+ // 4:
+ // 5: tmp ← X
+ let mut tmp = [0u8; 32]; // Check digest width
+ // 6:
+ // 7: for j from i to i + s − 1 do
+ for j in i..(i+s) {
+ // 8: ADRS.setHashAddress(j)
+
+ // 9: tmp ← F(PK.seed, ADRS, tmp)
+
+ // 10: end for
+ }
+ // 11: return tmp
+ Some(tmp)
+}
+
+
+/// Algorithm 5: `wots_PKgen(SK.seed, PK.seed, ADRS)` on page 18.
+/// Generate a WOTS+ public key.
+///
+/// Input: Secret seed `SK.seed`, public seed `PK.seed`, address `ADRS`.
+/// Output: WOTS+ public key `pk`.
+const _A5: u32 = 0;
+// 1: skADRS ← ADRS ▷ Copy address to create key generation key address
+// 2: skADRS.setTypeAndClear(WOTS_PRF)
+// 3: skADRS.setKeyPairAddress(ADRS.getKeyPairAddress())
+// 4: for i from 0 to len − 1 do
+// 5: skADRS.setChainAddress(i)
+// 6: sk ← PRF(PK.seed, SK.seed, skADRS) ▷ Compute secret value for chain i
+// 7: ADRS.setChainAddress(i)
+// 8: tmp[i] ← chain(sk, 0, w − 1, PK.seed, ADRS) ▷ Compute public value for chain i
+// 9: end for
+// 10: wotspkADRS ← ADRS ▷ Copy address to create WOTS+ public key address
+// 11: wotspkADRS.setTypeAndClear(WOTS_PK)
+// 12: wotspkADRS.setKeyPairAddress(ADRS.getKeyPairAddress())
+// 13: pk ← Tlen (PK.seed, wotspkADRS,tmp) ▷ Compress public key
+// 14: return pk
+
+
+/// Algorithm 6: `wots_sign(M, SK.seed, PK.seed, ADRS)` on page 19.
+/// Generate a WOTS+ signature on an n-byte message.
+///
+/// Input: Message `M`, secret seed `SK.seed`, public seed `PK.seed`, address `ADRS`.
+/// Output: WOTS+ signature sig.
+const _A6: u32 = 0;
+// 1: csum ← 0
+// 2:
+// 3: msg ← base_2b (M, lgw, len1) ▷ Convert message to base w
+// 4:
+// 5: for i from 0 to len1 − 1 do ▷ Compute checksum
+// 6: csum ← csum + w − 1 − msg[i]
+// 7: end for
+// 8:
+// 9: csum ← csum ≪ ((8 − ((len2·lgw) mod 8)) mod 8) ▷ For lgw = 4 left shift by 4
+// 10: msg ← msg ∥ base_2^b(toByte(csum, ceil(len2·lgw/8)), lgw, len2) ▷ Convert csum to base w
+// 11:
+// 12: skADRS ← ADRS
+// 13: skADRS.setTypeAndClear(WOTS_PRF)
+// 14: skADRS.setKeyPairAddress(ADRS.getKeyPairAddress())
+// 15: for i from 0 to len − 1 do
+// 16: skADRS.setChainAddress(i)
+// 17: sk ← PRF(PK.seed, SK.seed, skADRS) ▷ Compute secret value for chain i
+// 18: ADRS.setChainAddress(i)
+// 19: sig[i] ← chain(sk, 0, msg[i], PK.seed, ADRS) ▷ Compute signature value for chain i
+// 20: end for
+// 21: return sig
+
+
+/// Algorithm 7: `wots_PKFromSig(sig, M, PK.seed, ADRS)` on page 20.
+/// Compute a WOTS+ public key from a message and its signature.
+///
+/// Input: WOTS+ signature `sig`, message `M`, public seed `PK.seed`, address `ADRS`.
+/// Output: WOTS+ public key `pksig` derived from `sig`.
+const _A7: u32 = 0;
+// 1: csum ← 0
+// 2:
+// 3: msg ← base_2b (M, lgw , len1 ) ▷ Convert message to base w
+// 4:
+// 5: for i from 0 to len1 − 1 do ▷ Compute checksum
+// 6: csum ← csum + w − 1 − msg[i]
+// 7: end for
+// 8:
+// 9: csum ← csum ≪ ((8 − ((len2·lgw) mod 8)) mod 8) ▷ For lgw = 4 left shift by 4
+// 10: msg ← msg ∥ base_2^b(toByte(csum, ceil(len2·lgw/8)), lgw, len2) ▷ Convert csum to base w
+// 11: for i from 0 to len − 1 do
+// 12: ADRS.setChainAddress(i)
+// 13: tmp[i] ← chain(sig[i], msg[i], w − 1 − msg[i], PK.seed, ADRS)
+// 14: end for
+// 15: wotspkADRS ← ADRS
+// 16: wotspkADRS.setTypeAndClear(WOTS_PK)
+// 17: wotspkADRS.setKeyPairAddress(ADRS.getKeyPairAddress())
+// 18: pksig ← Tlen (PK.seed, wotspkADRS, tmp)
+// 19: return pksig
+
+
+/// Algorithm 8: `xmss_node(SK.seed, i, z, PK.seed, ADRS)` on page 22.
+/// Compute the root of a Merkle subtree of WOTS+ public keys.
+///
+/// Input: Secret seed `SK.seed`, target node index `i`, target node height `z`, public seed `PK.seed`,
+/// `address ADRS`.
+/// Output: n-byte root `node`.
+const _A8: u32 = 0;
+// 1: if z > h′ or i ≥ 2^{h −z} then
+// 2: return NULL
+// 3: end if
+// 4: if z = 0 then
+// 5: ADRS.setTypeAndClear(WOTS_HASH)
+// 6: ADRS.setKeyPairAddress(i)
+// 7: node ← wots_PKgen(SK.seed, PK.seed, ADRS)
+// 8: else
+// 9: lnode ← xmss_node(SK.seed, 2i, z − 1, PK.seed, ADRS)
+// 10: rnode ← xmss_node(SK.seed, 2i + 1, z − 1, PK.seed, ADRS)
+// 11: ADRS.setTypeAndClear(TREE)
+// 12: ADRS.setTreeHeight(z)
+// 13: ADRS.setTreeIndex(i)
+// 14: node ← H(PK.seed, ADRS, lnode ∥ rnode)
+// 15: end if
+// 16: return node
+
+
+/// Algorithm 9: `xmss_sign(M, SK.seed, idx, PK.seed, ADRS)` on page 23.
+/// Generate an XMSS signature.
+///
+/// Input: n-byte message `M`, secret seed `SK.seed`, index `idx`, public seed `PK.seed`, address `ADRS`.
+/// Output: XMSS signature SIGXMSS = (sig ∥ AUTH).
+const _A9: u32 = 0;
+//
+// 1: for j from 0 to h′-1 do ▷ Build authentication path
+// 2: k ← idx/2 xor 1
+// 3: AUTH[j] ← xmss_node(SK.seed, k, j, PK.seed, ADRS)
+// 4: end for
+// 5:
+// 6: ADRS.setTypeAndClear(WOTS_HASH)
+// 7: ADRS.setKeyPairAddress(idx)
+// 8: sig ← wots_sign(M, SK.seed, PK.seed, ADRS)
+// 9: SIG_XMSS ← sig ∥ AUTH
+// 10: return SIG_XMSS
+
+
+/// Algorithm 10: `xmss_PKFromSig(idx, SIG_XMSS, M, PK.seed, ADRS)`
+/// Compute an XMSS public key from an XMSS signature.
+///
+/// Input: Index `idx`, XMSS signature `SIG_XMSS = (sig ∥ AUTH)`, n-byte message `M`, public seed `PK.seed`,
+/// address `ADRS`.
+/// Output: n-byte root value `node[0]`.
+const _A10: u32 = 0;
+// 1: ADRS.setTypeAndClear(WOTS_HASH) ▷ Compute WOTS+ pk from WOTS+ sig
+// 2: ADRS.setKeyPairAddress(idx)
+// 3: sig ← SIG_XMSS .getWOTSSig() ▷ SIG_XMSS [0 : len · n]
+// 4: AUTH ← SIG_XMSS .getXMSSAUTH() ▷ SIG_XMSS [len · n : (len + h′) · n]
+// 5: node[0] ← wots_PKFromSig(sig, M, PK.seed, ADRS)
+// 6:
+// 7: ADRS.setTypeAndClear(TREE) ▷ Compute root from WOTS+ pk and AUTH
+// 8: ADRS.setTreeIndex(idx)
+// 9: for k from 0 to h′ − 1 do
+// 10: ADRS.setTreeHeight(k + 1)
+// 11: if idx/2^k is even then
+// 12: ADRS.setTreeIndex(ADRS.getTreeIndex()/2)
+// 13: node[1] ← H(PK.seed, ADRS, node[0] ∥ AUTH[k])
+// 14: else
+// 15: ADRS.setTreeIndex((ADRS.getTreeIndex() − 1)/2)
+// 16: node[1] ← H(PK.seed, ADRS, AUTH[k] ∥ node[0])
+// 17: end if
+// 18: node[0] ← node[1]
+// 19: end for
+// 20: return node[0]
+
+
+/// Algorithm 11: `ht_sign(M, SK.seed, PK.seed, idx_tree, idx_leaf)` on page 27.
+/// Generate a hypertree signature.
+///
+/// Input: Message `M`, private seed `SK.seed`, public seed `PK.seed`, tree index `idx_tree`, leaf
+/// index `idx_leaf`.
+/// Output: HT signature SIG_HT.
+const _A11: u32 = 0;
+// 1: ADRS ← toByte(0, 32)
+// 2:
+// 3: ADRS.setTreeAddress(idxtree)
+// 4: SIG_tmp ← xmss_sign(M, SK.seed, idxleaf, PK.seed, ADRS)
+// 5: SIG_HT ← SIG_tmp
+// 6: root ← xmss_PKFromSig(idx_leaf, SIG_tmp, M, PK.seed, ADRS)
+// 7: for j from 1 to d − 1 do
+// 8: idx_leaf ← idx_tree mod 2^{h′} ▷ h′ least significant bits of idx_tree
+// 9: idx_tree ← idx_tree ≫ h′ ▷ Remove least significant h′ bits from idx_tree
+// 10: ADRS.setLayerAddress(j)
+// 11: ADRS.setTreeAddress(idx_tree)
+// 12: SIG_tmp ← xmss_sign(root, SK.seed, idx_leaf, PK.seed, ADRS)
+// 13: SIG_HT ← SIG_HT ∥ SIG_tmp
+// 14: if j < d − 1 then
+// 15: root ← xmss_PKFromSig(idx_leaf, SIG_tmp, root, PK.seed, ADRS)
+// 16: end if
+// 17: end for
+// 18: return SIGHT
+
+
+/// Algorithm 12: `ht_verify(M, SIG_HT, PK.seed, idx_tree, idx_leaf, PK.root)` on page 28.
+/// Verify a hypertree signature.
+///
+/// Input: Message `M`, signature `SIG_HT`, public seed `PK.seed`, tree index `idx_tree`, leaf index `idx_leaf`,
+/// HT public key `PK.root`.
+/// Output: Boolean.
+const _A12: u32 = 0;
+// 1: ADRS ← toByte(0, 32)
+// 2:
+// 3: ADRS.setTreeAddress(idx_tree)
+// 4: SIG_tmp ← SIG_HT.getXMSSSignature(0) ▷ SIG_HT [0 : (h′ + len) · n]
+// 5: node ← xmss_PKFromSig(idx_leaf, SIG_tmp, M, PK.seed, ADRS)
+// 6: for j from 1 to d − 1 do
+// 7: idx_leaf ← idx_tree mod 2^{h′} ▷ h′ least significant bits of idx_tree
+// 8: idx_tree ← idx_tree ≫ h′ ▷ Remove least significant h′ bits from idx_tree
+// 9: ADRS.setLayerAddress(j)
+// 10: ADRS.setTreeAddress(idx_tree)
+// 11: SIG_tmp ← SIG_HT.getXMSSSignature(j) ▷ SIGHT [ j · (h′ + len) · n : ( j + 1)(h′ + len) · n]
+// 12: node ← xmss_PKFromSig(idx_leaf, SIG_tmp, node, PK.seed, ADRS)
+// 13: end for
+// 14: if node = PK.root then
+// 15: return true
+// 16: else
+// 17: return false
+// 18: end if
+
+
+/// Algorithm 13: `fors_SKgen(SK.seed, PK.seed, ADRS, idx)` on page 29.
+/// Generate a FORS private-key value.
+///
+/// Input: Secret seed `SK.seed`, public seed `PK.seed`, address `ADRS`, secret key index `idx`.
+/// Output: n-byte FORS private-key value.
+const _A13: u32 = 0;
+// 1: skADRS ← ADRS ▷ Copy address to create key generation address
+// 2: skADRS.setTypeAndClear(FORS_PRF)
+// 3: skADRS.setKeyPairAddress(ADRS.getKeyPairAddress())
+// 4: skADRS.setTreeIndex(idx)
+// 5: return PRF(PK.seed, SK.seed, skADRS)
+
+
+/// Algorithm 14: `fors_node(SK.seed, i, z, PK.seed, ADRS)` on page 30.
+/// Compute the root of a Merkle subtree of FORS public values.
+///
+/// Input: Secret seed `SK.seed`, target node index `i`, target node height `z`, public seed `PK.seed`,
+/// address `ADRS`.
+/// Output: n-byte root node.
+const _A14: u32 = 0;
+// 1: if z > a or i ≥ k · 2(a−z) then
+// 2: return NULL
+// 3: end if
+// 4: if z = 0 then
+// 5: sk ← fors_SKgen(SK.seed, PK.seed, ADRS, i)
+// 6: ADRS.setTreeHeight(0)
+// 7: ADRS.setTreeIndex(i)
+// 8: node ← F(PK.seed, ADRS, sk)
+// 9: else
+// 10: lnode ← fors_node(SK.seed, 2i, z − 1, PK.seed, ADRS)
+// 11: rnode ← fors_node(SK.seed, 2i + 1, z − 1, PK.seed, ADRS)
+// 12: ADRS.setTreeHeight(z)
+// 13: ADRS.setTreeIndex(i)
+// 14: node ← H(PK.seed, ADRS, lnode ∥ rnode)
+// 15: end if
+// 16: return node
+
+
+/// Algorithm 15: `fors_sign(md, SK.seed, PK.seed, ADRS)`
+/// Generate a FORS signature.
+///
+/// Input: Message digest `md`, secret seed `SK.seed`, address `ADRS`, public seed `PK.seed`.
+/// Output: FORS signature `SIG_FORS`.
+const _A15: u32 = 0;
+// 1: SIG_FORS = NULL ▷ Initialize SIG_FORS as a zero-length byte string
+// 2: indices ← base_2^b(md, a, k)
+// 3: for i from 0 to k − 1 do ▷ Compute signature elements
+// 4: SIG_FORS ← SIG_FORS ∥ fors_SKgen(SK.seed, PK.seed, ADRS, i · 2a + indices[i])
+// 5:
+// 6: for j from 0 to a − 1 do ▷ Compute auth path
+// 7: s ← indices[i]/2^j xor 1
+// 8: AUTH[j] ← fors_node(SK.seed, i · 2^{a−j} + s, j, PK.seed, ADRS)
+// 9: end for
+// 10: SIG_FORS ← SIG_FORS ∥ AUTH
+// 11: end for
+// 12: return SIG_FORS
+
+
+/// Algorithm 16: `fors_pkFromSig(SIG_FORS, md, PK.seed, ADRS)` on page 32.
+/// Compute a FORS public key from a FORS signature.
+///
+/// Input: FORS signature `SIG_FORS`, message digest `md`, public seed `PK.seed`, address `ADRS`.
+/// Output: FORS public key.
+const _A16: u32 = 0;
+// 1: indices ← base_2^b(md, a, k)
+// 2: for i from 0 to k − 1 do
+// 3: sk ← SIG_FORS.getSK(i) ▷ SIG_FORS [i · (a + 1) · n : (i · (a + 1) + 1) · n]
+// 4: ADRS.setTreeHeight(0) ▷ Compute leaf
+// 5: ADRS.setTreeIndex(i · 2^a + indices[i])
+// 6: node[0] ← F(PK.seed, ADRS, sk)
+// 7:
+// 8: auth ← SIGFORS .getAUTH(i) ▷ SIGFORS [(i · (a + 1) + 1) · n : (i + 1) · (a + 1) · n]
+// 9: for j from 0 to a − 1 do ▷ Compute root from leaf and AUTH
+// 10: ADRS.setTreeHeight(j + 1)
+// 11: if indices[i]/2^jj is even then
+// 12: ADRS.setTreeIndex(ADRS.getTreeIndex()/2)
+// 13: node[1] ← H(PK.seed, ADRS, node[0] ∥ auth[j])
+// 14: else
+// 15: ADRS.setTreeIndex((ADRS.getTreeIndex() − 1)/2)
+// 16: node[1] ← H(PK.seed, ADRS, auth[j] ∥ node[0])
+// 17: end if
+// 18: node[0] ← node[1]
+// 19: end for
+// 20: root[i] ← node[0]
+// 21: end for
+// 22: forspkADRS ← ADRS ▷ Compute the FORS public key from the Merkle tree roots
+// 23: forspkADRS.setTypeAndClear(FORS_ROOTS)
+// 24: forspkADRS.setKeyPairAddress(ADRS.getKeyPairAddress())
+// 25: pk ← Tk(PK.seed, forspkADRS, root)
+// 26: return pk;
+
+
+/// Algorithm 17: `slh_keygen()` on page 34.
+/// Generate an SLH-DSA key pair.
+///
+/// Input: (none)
+/// Output: SLH-DSA key pair `(SK, PK)`.
+const _A17: u32 = 0;
+// 1: SK.seed ←$ B^n ▷ Set SK.seed, SK.prf, and PK.seed to random n-byte
+// 2: SK.prf ←$ B^n ▷ strings using an approved random bit generator
+// 3: PK.seed ←$ B^n
+// 4:
+// 5: ADRS ← toByte(0, 32) ▷ Generate the public key for the top-level XMSS tree
+// 6: ADRS.setLayerAddress(d − 1)
+// 7: PK.root ← xmss_node(SK.seed, 0, h′, PK.seed, ADRS)
+// 8:
+// 9: return ( (SK.seed, SK.prf, PK.seed, PK.root), (PK.seed, PK.root) )
+
+
+/// Algorithm 18: `slh_sign(M, SK)` on page 35.
+/// Generate an SLH-DSA signature.
+///
+/// Input: Message `M`, private key `SK = (SK.seed, SK.prf, PK.seed, PK.root)`.
+/// Output: SLH-DSA signature `SIG`.
+const _A18: u32 = 0;
+// 1: ADRS ← toByte(0, 32)
+// 2:
+// 3: opt_rand ← PK.seed ▷ Set opt_rand to either PK.seed
+// 4: if (RANDOMIZE) then ▷ or to a random n-byte string
+// 5: opt_rand ←$ Bn
+// 6: end if
+// 7: R ← PRF_msg(SK.prf, opt_rand, M) ▷ Generate randomizer
+// 8: SIG ← R
+// 9:
+// 10: digest ← H_msg(R, PK.seed, PK.root, M) ▷ Compute message digest
+// 11: md ← digest[0 : ceil(k·a/8)] ▷ first ceil(k·a/8) bytes
+// 12: tmp_idx_tree ← digest[ceil(k·a/8) : ceil(k·a/8) + ceil((h-h/d)/8)] ▷ next ceil((h-h/d)/8) bytes
+// 13: tmp_idx_leaf ← digest[ceil(k·a/8) + ceil((h-h/d)/8) : ceil(k·a/8) + ceil((h-h/d)/8) + ceil(h/8d)] ▷ next ceil(h/8d) bytes
+// 14:
+// 15: idx_tree ← toInt(tmp_idx_tree, ceil((h-h/d)/8)) mod 2^{h−h/d}
+// 16: idx_leaf ← toInt(tmp_idx_leaf, ceil(h/8d) mod 2^{h/d}
+// 17:
+// 18: ADRS.setTreeAddress(idx_tree)
+// 19: ADRS.setTypeAndClear(FORS_TREE)
+// 20: ADRS.setKeyPairAddress(idxleaf)
+// 21: SIG_FORS ← fors_sign(md, SK.seed, PK.seed, ADRS)
+// 22: SIG ← SIG ∥ SIG_FORS
+// 23:
+// 24: PK_FORS ← fors_pkFromSig(SIG_FORS , md, PK.seed, ADRS) ▷ Get FORS key
+// 25:
+// 26: SIG_HT ← ht_sign(PK_FORS , SK.seed, PK.seed, idx_tree, idx_leaf)
+// 27: SIG ← SIG ∥ SIG_HT
+// 28: return SIG
+
+
+/// Algorithm 19: `slh_verify(M, SIG, PK)`
+/// Verify an SLH-DSA signature.
+///
+/// Input: Message `M`, signature `SIG`, public key `PK = (PK.seed, PK.root)`.
+/// Output: Boolean.
+const _A19: u32 = 0;
+// 1: if |SIG| != (1 + k(1 + a) + h + d · len) · n then
+// 2: return false
+// 3: end if
+// 4: ADRS ← toByte(0, 32)
+// 5: R ← SIG.getR() ▷ SIG[0 : n]
+// 6: SIG_FORS ← SIG.getSIG_FORS() ▷ SIG[n : (1 + k(1 + a)) · n]
+// 7: SIG_HT ← SIG.getSIG_HT() ▷ SIG[(1 + k(1 + a)) · n : (1 + k(1 + a) + h + d · len) · n]
+// 8:
+// 9: digest ← Hmsg(R, PK.seed, PK.root, M) ▷ Compute message digest
+// 10: md ← digest[0 : ceil(k·a/8)] ▷ first ceil(k·a/8) bytes
+// 11: tmp_idx_tree ← digest[ceil(k·a/8) : ceil(k·a/8) + ceil((h - h/d)/8)] ▷ next ceil((h - h/d)/8) bytes
+// 12: tmp_idx_leaf ← digest[ceil(k·a/8) + ceil((h - h/d)/8) : ceil(k·a/8) + ceil((h - h/d)/8) + ceil(h/8d)] ▷ next ceil(h/8d) bytes
+// 13:
+// 14: idx_tree ← toInt(tmp_idx_tree, ceil((h - h/d)/8)) mod 2^{h−h/d}
+// 15: idx_leaf ← toInt(tmp_idx_leaf, ceil(h/8d) mod 2^{h/d}
+// 16:
+// 17: ADRS.setTreeAddress(idx_tree) ▷ Compute FORS public key
+// 18: ADRS.setTypeAndClear(FORS_TREE)
+// 19: ADRS.setKeyPairAddress(idx_leaf)
+// 20:
+// 21: PK_FORS ← fors_pkFromSig(SIG_FORS, md, PK.seed, ADRS)
+// 22:
+// 23: return ht_verify(PK_FORS, SIG_HT, PK.seed, idx_tree , idx_leaf, PK.root)
diff --git a/src/lib.rs b/src/lib.rs
index 7d12d9a..75b4dea 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,7 +1,269 @@
-pub fn add(left: usize, right: usize) -> usize {
- left + right
+#![no_std]
+#![deny(clippy::pedantic)]
+#![deny(warnings)]
+#![deny(missing_docs)]
+#![allow(dead_code)]
+
+//! TKTK crate doc
+
+extern crate alloc;
+
+mod algs;
+mod traits;
+
+/// to be deleted
+#[must_use]
+pub fn add(left: usize, right: usize) -> usize { left + right }
+
+struct Params {
+ w: usize
}
+macro_rules! functionality {
+ () => {
+ use zeroize::{Zeroize, ZeroizeOnDrop};
+ use crate::traits::PK;
+ // ----- 'EXTERNAL' DATA TYPES -----
+
+ /// Correctly sized private key specific to the target security parameter set.
+ #[derive(Clone, Zeroize, ZeroizeOnDrop)]
+ pub struct PrivateKey {
+ pub(crate) sk_seed: [u8; N],
+ sk_prf: [u8; N],
+ pk_seed: [u8; N],
+ pk_root: [u8; N],
+ }
+
+ impl PK for PrivateKey {
+ type Seed = [u8; N];
+ fn seed(&self) -> [u8; N] {self.sk_seed}
+ }
+
+ };
+}
+
+/// TKTK
+#[cfg(feature = "slh_dsa_sha2_128s")]
+pub mod slh_dsa_sha2_128s {
+ const N: usize = 16;
+ const H: u32 = 63;
+ const D: u32 = 7;
+ const H_PRIME: u32 = 9;
+ const A: u32 = 12;
+ const K: u32 = 14;
+ const LGW: u32 = 4;
+ const M: u32 = 30;
+ const PK_LEN: usize = 32;
+ const SIG_LEN: usize = 7856;
+ const SK_LEN: usize = 0000;
+
+ functionality!();
+}
+
+
+/// TKTK
+#[cfg(feature = "slh_dsa_shake_128s")]
+pub mod slh_dsa_shake_128s {
+ const N: usize = 16;
+ const H: u32 = 63;
+ const D: u32 = 7;
+ const H_PRIME: u32 = 9;
+ const A: u32 = 12;
+ const K: u32 = 14;
+ const LGW: u32 = 4;
+ const M: u32 = 30;
+ const PK_LEN: usize = 32;
+ const SIG_LEN: usize = 7856;
+ const SK_LEN: usize = 0000;
+
+ functionality!();
+}
+
+/// TKTK
+#[cfg(feature = "slh_dsa_sha2_128f")]
+pub mod slh_dsa_sha2_128f {
+ const N: usize = 16;
+ const H: u32 = 66;
+ const D: u32 = 22;
+ const H_PRIME: u32 = 3;
+ const A: u32 = 6;
+ const K: u32 = 33;
+ const LGW: u32 = 4;
+ const M: u32 = 34;
+ const PK_LEN: usize = 32;
+ const SIG_LEN: usize = 17088;
+ const SK_LEN: usize = 0000;
+
+ functionality!();
+}
+
+/// TKTK
+#[cfg(feature = "slh_dsa_shake_128f")]
+pub mod slh_dsa_shake_128f {
+ const N: usize = 16;
+ const H: u32 = 66;
+ const D: u32 = 22;
+ const H_PRIME: u32 = 3;
+ const A: u32 = 6;
+ const K: u32 = 33;
+ const LGW: u32 = 4;
+ const M: u32 = 34;
+ const PK_LEN: usize = 32;
+ const SIG_LEN: usize = 17088;
+ const SK_LEN: usize = 0000;
+
+ functionality!();
+}
+
+
+/// TKTK
+#[cfg(feature = "slh_dsa_sha2_192s")]
+pub mod slh_dsa_sha2_192s {
+ const N: usize = 24;
+ const H: u32 = 63;
+ const D: u32 = 7;
+ const H_PRIME: u32 = 9;
+ const A: u32 = 14;
+ const K: u32 = 17;
+ const LGW: u32 = 4;
+ const M: u32 = 39;
+ const PK_LEN: usize = 48;
+ const SIG_LEN: usize = 16224;
+ const SK_LEN: usize = 00000;
+
+ functionality!();
+}
+
+
+/// TKTK
+#[cfg(feature = "slh_dsa_shake_192s")]
+pub mod slh_dsa_shake_192s {
+ const N: usize = 24;
+ const H: u32 = 63;
+ const D: u32 = 7;
+ const H_PRIME: u32 = 9;
+ const A: u32 = 14;
+ const K: u32 = 17;
+ const LGW: u32 = 4;
+ const M: u32 = 39;
+ const PK_LEN: usize = 48;
+ const SIG_LEN: usize = 16224;
+ const SK_LEN: usize = 00000;
+
+ functionality!();
+}
+
+/// TKTK
+#[cfg(feature = "slh_dsa_sha2_192f")]
+pub mod slh_dsa_sha2_192f {
+ const N: usize = 24;
+ const H: u32 = 66;
+ const D: u32 = 22;
+ const H_PRIME: u32 = 3;
+ const A: u32 = 8;
+ const K: u32 = 33;
+ const LGW: u32 = 4;
+ const M: u32 = 42;
+ const PK_LEN: usize = 48;
+ const SIG_LEN: usize = 35664;
+ const SK_LEN: usize = 0000;
+
+ functionality!();
+}
+
+/// TKTK
+#[cfg(feature = "slh_dsa_shake_192f")]
+pub mod slh_dsa_shake_192f {
+ const N: usize = 24;
+ const H: u32 = 66;
+ const D: u32 = 22;
+ const H_PRIME: u32 = 3;
+ const A: u32 = 8;
+ const K: u32 = 33;
+ const LGW: u32 = 4;
+ const M: u32 = 42;
+ const PK_LEN: usize = 48;
+ const SIG_LEN: usize = 35664;
+ const SK_LEN: usize = 0000;
+
+ functionality!();
+}
+
+
+/// TKTK
+#[cfg(feature = "slh_dsa_sha2_256s")]
+pub mod slh_dsa_sha2_256s {
+ const N: usize = 32;
+ const H: u32 = 64;
+ const D: u32 = 8;
+ const H_PRIME: u32 = 8;
+ const A: u32 = 14;
+ const K: u32 = 22;
+ const LGW: u32 = 4;
+ const M: u32 = 47;
+ const PK_LEN: usize = 64;
+ const SIG_LEN: usize = 29792;
+ const SK_LEN: usize = 0000;
+
+ functionality!();
+}
+
+
+/// TKTK
+#[cfg(feature = "slh_dsa_shake_256s")]
+pub mod slh_dsa_shake_256s {
+ const N: usize = 32;
+ const H: u32 = 64;
+ const D: u32 = 8;
+ const H_PRIME: u32 = 8;
+ const A: u32 = 14;
+ const K: u32 = 22;
+ const LGW: u32 = 4;
+ const M: u32 = 47;
+ const PK_LEN: usize = 64;
+ const SIG_LEN: usize = 29792;
+ const SK_LEN: usize = 0000;
+
+ functionality!();
+}
+
+/// TKTK
+#[cfg(feature = "slh_dsa_sha2_256f")]
+pub mod slh_dsa_sha2_256f {
+ const N: usize = 32;
+ const H: u32 = 68;
+ const D: u32 = 17;
+ const H_PRIME: u32 = 4;
+ const A: u32 = 9;
+ const K: u32 = 35;
+ const LGW: u32 = 4;
+ const M: u32 = 49;
+ const PK_LEN: usize = 64;
+ const SIG_LEN: usize = 49856;
+ const SK_LEN: usize = 0000;
+
+ functionality!();
+}
+
+/// TKTK
+#[cfg(feature = "slh_dsa_shake_256f")]
+pub mod slh_dsa_shake_256f {
+ const N: usize = 32;
+ const H: u32 = 68;
+ const D: u32 = 17;
+ const H_PRIME: u32 = 4;
+ const A: u32 = 9;
+ const K: u32 = 35;
+ const LGW: u32 = 4;
+ const M: u32 = 49;
+ const PK_LEN: usize = 64;
+ const SIG_LEN: usize = 49856;
+ const SK_LEN: usize = 0000;
+
+ functionality!();
+}
+
+
#[cfg(test)]
mod tests {
use super::*;
diff --git a/src/traits.rs b/src/traits.rs
new file mode 100644
index 0000000..792475b
--- /dev/null
+++ b/src/traits.rs
@@ -0,0 +1,6 @@
+
+
+pub trait PK {
+ type Seed;
+ fn seed(&self) -> Self::Seed;
+}
\ No newline at end of file