krypteia-quantica 0.2.0

Pure-Rust post-quantum cryptography: FIPS 203 ML-KEM, FIPS 204 ML-DSA, and FIPS 205 SLH-DSA. First-order arithmetic masking, shuffled NTT, FORS recompute-and-compare redundancy, constant-time rejection sampling. Targets embedded (no_std), STM32 M0/M4/M33, ESP32-C3 RISC-V. Zero runtime dependencies.
Documentation
// SPDX-License-Identifier: Apache-2.0
// Copyright 2026 Cédric Mesnil <cslashm@pm.me>

//! SLH-DSA parameter sets (FIPS 205, Section 11).
//!
//! This module defines the [`Params`] trait and the twelve FIPS 205
//! parameter set structs — six SHAKE (§11.1) and six SHA-2 (§11.2). All
//! parameter sets use Winternitz parameter `w = 16` (`lg_w = 4`).
//!
//! Each parameter set is identified by its hash family (SHAKE / SHA2),
//! security level (128, 192, or 256 bits) and a size/speed trade-off
//! suffix: "s" (small signatures) or "f" (fast signing/verification).

use super::hash::{ShakeFamily, TweakableHash};
use super::hash_sha2::Sha2Family;

/// Trait defining all compile-time parameters for an SLH-DSA instance.
///
/// Implementors of this trait represent a specific FIPS 205 parameter set (e.g.,
/// SLH-DSA-SHAKE-128f). The constants fully determine key sizes, signature sizes,
/// tree structures, and hash output lengths; the `Hash` associated
/// type selects the tweakable-hash instantiation (SHAKE or SHA-2).
///
/// See FIPS 205, Table 2 for the complete list of parameter values.
pub trait Params: Clone + Default {
    /// Tweakable-hash family for this parameter set: `ShakeFamily`
    /// (FIPS 205 §11.1) or `Sha2Family` (§11.2).
    type Hash: TweakableHash;

    /// Security parameter `n`: hash output length in bytes.
    ///
    /// This is the fundamental security parameter. All hash outputs, secret values,
    /// and tree nodes are `n` bytes long.
    const N: usize;
    /// Total hypertree height: `h = d * h'`.
    ///
    /// Determines the total number of FORS key pairs the scheme can use: `2^h`.
    const H: usize;
    /// Number of layers `d` in the hypertree.
    ///
    /// The hypertree consists of `d` stacked XMSS trees, each of height `h'`.
    const D: usize;
    /// Height `h'` of each individual XMSS tree within the hypertree.
    ///
    /// Each XMSS tree authenticates `2^h'` keys in the layer below it.
    const H_PRIME: usize;
    /// Height `a` of each FORS tree (each tree has `2^a` leaves).
    const A: usize;
    /// Number `k` of FORS trees used per signature.
    const K: usize;
    /// Winternitz parameter `lg(w)`, always 4 for the FIPS 205 parameter sets.
    const LG_W: usize = 4;
    /// Winternitz parameter `w = 2^lg_w = 16`.
    ///
    /// Controls the time/size trade-off in WOTS+ chains: each chain has `w - 1` steps.
    const W: usize = 16;
    /// Message digest length `m` in bytes, output by `H_msg`.
    ///
    /// The digest is split into FORS indices, a tree index, and a leaf index.
    const M: usize;

    // Derived WOTS+ constants
    /// WOTS+ parameter `len1 = ceil(8*n / lg_w) = 2*n` (since `lg_w = 4`).
    ///
    /// Number of base-`w` digits needed to represent an `n`-byte message.
    const LEN1: usize = 2 * Self::N;
    /// WOTS+ parameter `len2 = 3` for all FIPS 205 parameter sets.
    ///
    /// Number of base-`w` digits in the checksum.
    const LEN2: usize = 3;
    /// WOTS+ parameter `len = len1 + len2`: total number of hash chains.
    const LEN: usize = Self::LEN1 + Self::LEN2;

    // Key and signature sizes
    /// Public key size in bytes: `2*n` (PK.seed || PK.root).
    const PK_LEN: usize = 2 * Self::N;
    /// Secret key size in bytes: `4*n` (SK.seed || SK.prf || PK.seed || PK.root).
    const SK_LEN: usize = 4 * Self::N;

    /// Human-readable name of this parameter set (e.g., `"SLH-DSA-SHAKE-128f"`).
    const NAME: &'static str;
}

/// Compute the total SLH-DSA signature length in bytes for parameter set `P`.
///
/// The signature layout is `R || SIG_FORS || SIG_HT`, with total size:
/// `n + k*(1+a)*n + (h + d*len)*n`.
///
/// This is a runtime function rather than a `const` due to Rust const-generics limitations.
pub fn sig_len<P: Params>() -> usize {
    // R || SIG_FORS || SIG_HT
    // n + k*(1+a)*n + (h + d*len)*n
    P::N + P::K * (1 + P::A) * P::N + (P::H + P::D * P::LEN) * P::N
}

// ============================================================
// SHAKE parameter sets (FIPS 205 §11.1)
// ============================================================

/// SLH-DSA-SHAKE-128s parameter set (NIST security level 1, small signatures).
///
/// Provides 128-bit security with relatively compact signatures (~7856 bytes) but
/// slower signing and verification compared to [`Shake128f`].
#[derive(Clone, Default)]
pub struct Shake128s;

impl Params for Shake128s {
    type Hash = ShakeFamily;
    const N: usize = 16;
    const H: usize = 63;
    const D: usize = 7;
    const H_PRIME: usize = 9;
    const A: usize = 12;
    const K: usize = 14;
    const M: usize = 30;
    const NAME: &'static str = "SLH-DSA-SHAKE-128s";
}

/// SLH-DSA-SHAKE-128f parameter set (NIST security level 1, fast operations).
///
/// Provides 128-bit security with faster signing and verification but larger
/// signatures (~17088 bytes) compared to [`Shake128s`].
#[derive(Clone, Default)]
pub struct Shake128f;

impl Params for Shake128f {
    type Hash = ShakeFamily;
    const N: usize = 16;
    const H: usize = 66;
    const D: usize = 22;
    const H_PRIME: usize = 3;
    const A: usize = 6;
    const K: usize = 33;
    const M: usize = 34;
    const NAME: &'static str = "SLH-DSA-SHAKE-128f";
}

/// SLH-DSA-SHAKE-192s parameter set (NIST security level 3, small signatures).
#[derive(Clone, Default)]
pub struct Shake192s;

impl Params for Shake192s {
    type Hash = ShakeFamily;
    const N: usize = 24;
    const H: usize = 63;
    const D: usize = 7;
    const H_PRIME: usize = 9;
    const A: usize = 14;
    const K: usize = 17;
    const M: usize = 39;
    const NAME: &'static str = "SLH-DSA-SHAKE-192s";
}

/// SLH-DSA-SHAKE-192f parameter set (NIST security level 3, fast operations).
#[derive(Clone, Default)]
pub struct Shake192f;

impl Params for Shake192f {
    type Hash = ShakeFamily;
    const N: usize = 24;
    const H: usize = 66;
    const D: usize = 22;
    const H_PRIME: usize = 3;
    const A: usize = 8;
    const K: usize = 33;
    const M: usize = 42;
    const NAME: &'static str = "SLH-DSA-SHAKE-192f";
}

/// SLH-DSA-SHAKE-256s parameter set (NIST security level 5, small signatures).
#[derive(Clone, Default)]
pub struct Shake256s;

impl Params for Shake256s {
    type Hash = ShakeFamily;
    const N: usize = 32;
    const H: usize = 64;
    const D: usize = 8;
    const H_PRIME: usize = 8;
    const A: usize = 14;
    const K: usize = 22;
    const M: usize = 47;
    const NAME: &'static str = "SLH-DSA-SHAKE-256s";
}

/// SLH-DSA-SHAKE-256f parameter set (NIST security level 5, fast operations).
#[derive(Clone, Default)]
pub struct Shake256f;

impl Params for Shake256f {
    type Hash = ShakeFamily;
    const N: usize = 32;
    const H: usize = 68;
    const D: usize = 17;
    const H_PRIME: usize = 4;
    const A: usize = 9;
    const K: usize = 35;
    const M: usize = 49;
    const NAME: &'static str = "SLH-DSA-SHAKE-256f";
}

// ============================================================
// SHA-2 parameter sets (FIPS 205 §11.2)
//
// Structural constants (n, h, d, h', a, k, m) are identical to the
// same-category SHAKE sets (FIPS 205 Table 2); only the hash family and
// the name differ.
// ============================================================

/// SLH-DSA-SHA2-128s parameter set (NIST security level 1, small signatures).
#[derive(Clone, Default)]
pub struct Sha2_128s;

impl Params for Sha2_128s {
    type Hash = Sha2Family;
    const N: usize = 16;
    const H: usize = 63;
    const D: usize = 7;
    const H_PRIME: usize = 9;
    const A: usize = 12;
    const K: usize = 14;
    const M: usize = 30;
    const NAME: &'static str = "SLH-DSA-SHA2-128s";
}

/// SLH-DSA-SHA2-128f parameter set (NIST security level 1, fast operations).
#[derive(Clone, Default)]
pub struct Sha2_128f;

impl Params for Sha2_128f {
    type Hash = Sha2Family;
    const N: usize = 16;
    const H: usize = 66;
    const D: usize = 22;
    const H_PRIME: usize = 3;
    const A: usize = 6;
    const K: usize = 33;
    const M: usize = 34;
    const NAME: &'static str = "SLH-DSA-SHA2-128f";
}

/// SLH-DSA-SHA2-192s parameter set (NIST security level 3, small signatures).
#[derive(Clone, Default)]
pub struct Sha2_192s;

impl Params for Sha2_192s {
    type Hash = Sha2Family;
    const N: usize = 24;
    const H: usize = 63;
    const D: usize = 7;
    const H_PRIME: usize = 9;
    const A: usize = 14;
    const K: usize = 17;
    const M: usize = 39;
    const NAME: &'static str = "SLH-DSA-SHA2-192s";
}

/// SLH-DSA-SHA2-192f parameter set (NIST security level 3, fast operations).
#[derive(Clone, Default)]
pub struct Sha2_192f;

impl Params for Sha2_192f {
    type Hash = Sha2Family;
    const N: usize = 24;
    const H: usize = 66;
    const D: usize = 22;
    const H_PRIME: usize = 3;
    const A: usize = 8;
    const K: usize = 33;
    const M: usize = 42;
    const NAME: &'static str = "SLH-DSA-SHA2-192f";
}

/// SLH-DSA-SHA2-256s parameter set (NIST security level 5, small signatures).
#[derive(Clone, Default)]
pub struct Sha2_256s;

impl Params for Sha2_256s {
    type Hash = Sha2Family;
    const N: usize = 32;
    const H: usize = 64;
    const D: usize = 8;
    const H_PRIME: usize = 8;
    const A: usize = 14;
    const K: usize = 22;
    const M: usize = 47;
    const NAME: &'static str = "SLH-DSA-SHA2-256s";
}

/// SLH-DSA-SHA2-256f parameter set (NIST security level 5, fast operations).
#[derive(Clone, Default)]
pub struct Sha2_256f;

impl Params for Sha2_256f {
    type Hash = Sha2Family;
    const N: usize = 32;
    const H: usize = 68;
    const D: usize = 17;
    const H_PRIME: usize = 4;
    const A: usize = 9;
    const K: usize = 35;
    const M: usize = 49;
    const NAME: &'static str = "SLH-DSA-SHA2-256f";
}