Skip to main content

Module sig

Module sig 

Source
Expand description

Digital signature schemes.

A signature scheme lets a signer authenticate messages with their secret key; any holder of the corresponding public key can verify authenticity.

§Choosing an algorithm

PropertyMlDsa (ML-DSA-87)Sphincs (SPHINCS+-SHA2-256f)
AssumptionModule Learning With ErrorsSecurity of SHA-256 (hash only)
Cryptanalytic age~10 years~30 years (hash functions)
Public key2,592 B64 B
Secret key4,896 B128 B
Signature4,595 B49,856 B
Signing speedFastModerate (f = faster variant)
VerificationFastFast
NIST standardFIPS 204FIPS 205 (as SLH-DSA)

§Use MlDsa when:

  • Signature size and signing speed matter — ML-DSA produces compact signatures quickly and is the right default for most applications (TLS certificates, code signing, authentication tokens).
  • You want a NIST-standardised algorithm with broad ecosystem support.
  • You aren’t using using ML-KEM in the application OR you are “ok” with having both your KEM and your SIG break if a cryptoanalytic breakthrough is discovered against module learning with errors.

§Use Sphincs when:

  • You need the most conservative possible security assumption: SPHINCS+ relies only on the security of a hash function (SHA-256), with no algebraic structure to attack. If ML-DSA’s lattice assumption were ever broken, SPHINCS+ would be unaffected.
  • Tiny public and secret keys are important (64 B and 128 B respectively), for example in highly constrained environments or key-pinning scenarios.
  • Large signatures (~49 KB) are acceptable — e.g. long-lived root CA certificates or firmware images where the signature is transmitted once.

§Prehashing with cSHAKE256

Both MlDsa::sign and Sphincs::sign accept the full message as a single &[u8]. For large or streaming messages, or when you want domain separation, prehash the message with crate::prf::cshake256::CShake256 and pass the resulting digest to sign/verify instead:

use pqc::prf::cshake256::CShake256;
use pqc::sig::MlDsa;

let (pk, sk) = MlDsa::keypair()?;

// Build the digest incrementally — no need to buffer the whole message.
let mut h = CShake256::digest(b"myapp v1 document signing");
h.update(header);
h.update(body);
// or: h.update_read(&mut BufReader::new(file))?;  // requires `std` feature
let digest = h.finalize();

let sig = MlDsa::sign(&digest, &sk)?;
// Verifier reconstructs the same digest and calls MlDsa::verify.

The customization string passed to crate::prf::cshake256::CShake256::digest acts as a domain-separation label: two calls with different strings produce completely independent output spaces even with identical message content, so the same key pair can safely serve multiple protocols without cross-context confusion.

§Performance benefit for SPHINCS+

SPHINCS+ signs the raw message by hashing it internally many times across its hypertree — the signing cost scales with message length. Prehashing to a fixed-size 64-byte digest first means SPHINCS+ always operates on 64 bytes regardless of how large the original message is, giving a significant speedup for any message longer than a few hundred bytes.

Structs§

MlDsa
ML-DSA-87 (NIST FIPS 204, security level 5).
PublicKey
New owned buffer
SecretKey
New owned buffer
Signature
New owned buffer
Sphincs
SPHINCS+-SHAKE256-256f-simple (NIST FIPS 205 / SLH-DSA, security level 5, fast variant).

Enums§

Error
Possible errors

Type Aliases§

Result