krypteia-quantica 0.1.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
//! SLH-DSA parameter sets (FIPS 205, Section 11).
//!
//! This module defines the [`Params`] trait and the six SHAKE-based parameter set structs.
//! All SHAKE-based parameter sets use Winternitz parameter `w = 16` (`lg_w = 4`).
//!
//! Each parameter set is identified by its security level (128, 192, or 256 bits) and
//! a size/speed trade-off suffix: "s" (small signatures) or "f" (fast signing/verification).

/// 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.
///
/// See FIPS 205, Table 2 for the complete list of parameter values.
pub trait Params: Clone + Default {
    /// 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 SHAKE-based 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 SHAKE-based 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-128s ======
/// 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 {
    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";
}

// ====== SHAKE-128f ======
/// 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 {
    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";
}

// ====== SHAKE-192s ======
/// SLH-DSA-SHAKE-192s parameter set (NIST security level 3, small signatures).
///
/// Provides 192-bit security with compact signatures but slower operations
/// compared to [`Shake192f`].
#[derive(Clone, Default)]
pub struct Shake192s;

impl Params for Shake192s {
    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";
}

// ====== SHAKE-192f ======
/// SLH-DSA-SHAKE-192f parameter set (NIST security level 3, fast operations).
///
/// Provides 192-bit security with faster signing and verification but larger
/// signatures compared to [`Shake192s`].
#[derive(Clone, Default)]
pub struct Shake192f;

impl Params for Shake192f {
    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";
}

// ====== SHAKE-256s ======
/// SLH-DSA-SHAKE-256s parameter set (NIST security level 5, small signatures).
///
/// Provides 256-bit security with compact signatures but slower operations
/// compared to [`Shake256f`].
#[derive(Clone, Default)]
pub struct Shake256s;

impl Params for Shake256s {
    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";
}

// ====== SHAKE-256f ======
/// SLH-DSA-SHAKE-256f parameter set (NIST security level 5, fast operations).
///
/// Provides 256-bit security with faster signing and verification but larger
/// signatures compared to [`Shake256s`].
#[derive(Clone, Default)]
pub struct Shake256f;

impl Params for Shake256f {
    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";
}