Contributing to HashSigs RHDL
HashSigs RHDL is a cryptographic hardware project. Changes must preserve the
profile boundary, one-time-key safety, ready/valid behavior, and the distinction
between evidence tiers. Start with the developer guide
and the API documentation under /api/.
Before you start
- Install Rust 1.96 through the pinned toolchain file.
- Use Bun for every JavaScript or TypeScript command.
- Use mdBook 0.5.4 for the guide. The documentation build rejects another version so navigation and rendered output remain reproducible.
- Install Icarus Verilog and Verilator only for the RTL gates you intend to run.
- Treat Vivado as a separate, resource-intensive evidence stage. Coordinate shared build hosts before starting it.
Do not start by editing generated Verilog. Cryptographic datapaths belong in Rust/RHDL; generated RTL is an artifact bound to the source commit and manifest.
Preserve the profile boundary
The workspace exposes two deliberately incompatible profiles:
LEGACY_KECCAKis byte-compatible with the pinned HashSigsRS revision and uses legacy Keccak-256 padding.HASHSIGS_SHA256_GENERIC_V1is the SHA-256 hardware-performance profile.
Never introduce a runtime fallback, infer a profile from serialized length, or accept one profile’s key or signature as the other. Add the profile identifier to protocol metadata whenever bytes leave the typed Rust boundary.
Security rules
- A WOTS private key signs at most one message. Tests and examples must never normalize private-key reuse.
- The 32-byte WOTS input is already a digest. Application-level prehashing and domain separation remain the caller’s responsibility.
- Secret-dependent branches, addresses, enables, iteration counts, and stalls require explicit review.
- Reset, backpressure, malformed frames, stale tags, and duplicate returns are correctness cases, not optional polish.
- Do not describe this custom construction as XMSS, SLH-DSA, FIPS 205, or a many-time signature system.
Read the security policy before changing a cryptographic or protocol boundary.
Change workflow
- Identify the owning crate and the evidence tier affected by the change.
- Add an independent software-oracle, known-answer, or protocol-invariant test.
- Implement the smallest Rust/RHDL change.
- Run focused unit and integration tests with one build job when memory use is material.
- Run strict formatting, Clippy, and Rustdoc checks.
- If lowering changed, regenerate and simulate the exact generated RTL.
- Regenerate Vivado evidence before changing a resource or timing statement.
- Update the canonical evidence manifest and guide only after the producing evidence page exists.
Useful baseline commands:
cargo fmt --all -- --check
cargo test --workspace --locked -j1
cargo clippy --workspace --all-targets --all-features --locked -j1 -- -D warnings
RUSTDOCFLAGS="-D warnings" cargo doc --workspace --no-deps --locked -j1
bun run docs:test
bun run docs:build:no-api
bun run docs:check
The production signer and verifier contain explicitly ignored, expensive gates. Run one only when its evidence page names it, and do not silently convert an ignored gate into ordinary CI.
Evidence changes
Every measured result must identify its source commit and dirty state, profile, topology, tool and version, target or simulator, constraint, artifact checksum, date, supported claims, and explicit nonclaims. A lower tier cannot inherit a claim from a higher tier or from a different source revision.
Keep negative results. A failed timing or route attempt is useful architecture evidence when its boundary is stated accurately.
Documentation changes
The guide is mdBook source under docs/book/; Rustdoc remains generated from
crate documentation; /evidence/ is generated from docs/evidence/manifest.json.
Do not hand-edit the generated site/ directory.
Documentation must not contain credentials, workstation paths, process IDs, private coordination notes, or links that pretend a missing page succeeded. Add a real page, redirect, or 404 instead.
Pull requests
Keep commits scoped, explain the evidence boundary, list commands actually run, and call out expensive gates not run. Reviewers should be able to distinguish a source claim, an emitted-RTL claim, a Vivado result, and a card measurement from the pull-request description alone.