IntegrityChain: FIPS 205 Stateless Hash-Based Digital Signature Standard
FIPS 205 Stateless Hash-Based Digital Signature Standard written in pure Rust for server, desktop, browser and embedded applications. The source repository includes examples demonstrating benchmarking, code provenance, constant-time statistical measurements, a fuzzing harness, WASM execution, a C FFI shared library and Python bindings.
This crate implements the released FIPS 205 standard in pure Rust with minimal and mainstream dependencies, and without
any unsafe code. All twelve security parameter sets are fully functional and tested. Key generation and signing are
constant-time: every branch, loop bound and memory index depends only on public data, and each signature makes the
same number of hash calls for its parameter set, whatever the key, message or randomness. The crate does not require
the standard library (it is #![no_std]), makes no heap allocations (no alloc needed), and exposes the RNG, so it
suits the full range of applications from server down to bare metal. The API is stabilized, and the code is heavily
biased towards safety and correctness.
See https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.205.pdf for a full description of the target functionality.
The functionality is extremely simple to use, as demonstrated by the following example.
# use Error;
#
#
The Rust Documentation lives under each Module corresponding to the desired security parameter.
Notes
- This crate is fully functional and corresponds to the final released FIPS 205 (August 13, 2024).
- Constant-time: key generation and signing never branch, loop or index memory on secret data
(
SK.seed,SK.prf,opt_rand, and the FORS and WOTS+ secret values derived from them). Control flow and memory access follow only public data: the parameter set, the message and context lengths, thehedgedflag, and the message digest, tree indices and WOTS+ digits that the signature reveals. For each parameter set, key generation and signing always make the same number of calls to each hash function; only hashing the message and context takes longer as they grow. Checked by source review, by counting hash calls in all twelve parameter sets, and by thedudectmeasurements. The claim is at the source level: the compiler and CPU are trusted not to add secret-dependent timing, and the caller's RNG is outside it. Verify uses only public data and makes no constant-time claim. - FIPS 205 places specific requirements on randomness (section 3.1), hence the exposed
RNG. RNG integration usesrand_core0.6: custom generators implementCryptoRngCore(CryptoRng+RngCore), which this crate re-exports along withRngError. Key generation and signing calltry_fill_bytes, so handle its error, or usekeygen_from_seedand sign withhedged = false. - The default features enable
default-rngplus all twelve parameter sets. That OS RNG path is for hosted environments; it will not compile on bare-metal targets that lack agetrandombackend (for examplethumbv7em-none-eabi). Embedded builds usedefault-features = false, the parameter-set feature they need, and*_with_rng, orkeygen_from_seedandhedged = false:fips205 = { version = "0.5", default-features = false, features = ["slh-dsa-sha2-128s"] }. try_hash_signandhash_verify(HashSLH-DSA) take a precomputed digest and a DER-encoded OID (pre_hashlists the NIST CSOR encodings). The library does not hash the message. For apre_hashOID the digest must have that function's output length (32 bytes for SHAKE128, 64 for SHAKE256), so passing the message by mistake is an error. Any other OID must be DER-encoded and takes a digest of up to 1024 bytes.- Test vectors: the NIST ACVP keyGen, sigGen and sigVer vectors (including HashSLH-DSA) and the
SLotH known-answer files, regenerated and checked by hash,
run in the test suite, and the Python bindings apply the ACVP files for the four 128-bit sets
through the C ABI. The vector files stay in the repository; the published crate has only the
keyGen file, which the bindings' tests can use through
FIPS205_NIST_VECTORS. - A C shared library (
libfips205, published asfips205-ffi) for the four 128-bit sets, including HashSLH-DSA, with Python bindings, and a WASM browser demo, are described inffi/README.mdandwasm/README.md. - Requires Rust 1.85 or higher (Debian stable, trixie). The minimum supported Rust version may change in the future, but only with a minor version bump (once the major version is above 0).
- All on-by-default features of this library are covered by
SemVer.
License
Contents are licensed under either the Apache License, Version 2.0 or MIT license at your option.
Contribution
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.