pqrascv-core
Post-Quantum Remote Attestation & Supply-Chain Verification (PQ-RASCV)
Hardware-rooted · supply-chain-verified · post-quantum signed — everywhere Rust runs.
pqrascv-core is a no_std + alloc Rust library for issuing and verifying
tamper-evident device attestation quotes. Every quote is signed with
ML-DSA-65 (FIPS 204) and carries a SLSA v1 / in-toto provenance predicate,
binding a device's firmware identity to its build pipeline in a single, compact
CBOR message — on bare-metal Cortex-M4, RISC-V, WASM, or Linux.
Why PQ-RASCV?
Two converging threats are making classical attestation obsolete in 2026:
Supply-chain attacks are accelerating. SolarWinds, XZ Utils, and dozens of lesser-known incidents show that firmware can be compromised at build time. Existing attestation stacks (TPM 2.0, DICE, TDX) prove what is running — but carry no cryptographic proof of how it was built or who signed it off.
Post-quantum migration is overdue. RSA and ECDSA underpin today's attestation chains and are broken by Shor's algorithm. NIST finalised ML-DSA (FIPS 204) and ML-KEM (FIPS 203) in 2024. Devices deployed today may still be in service when cryptographically-relevant quantum computers arrive.
PQ-RASCV addresses both in a single embedded-first library. Every attestation quote is post-quantum signed and supply-chain provenance-linked — no separately bolted-on components.
Features
- Post-quantum by default — ML-DSA-65 signatures; no RSA or ECDSA anywhere
- Supply-chain provenance — SLSA v1 predicates + SBOM hash inside every signed quote
- Three measurement backends — Software SHA3-256, hardware TPM 2.0, DICE CDI derivation
no_std + alloc— one API across Cortex-M4, RISC-V, WASM, and Linux- Allocation-free measurement path —
RoT::measure()never touches the heap - Replay protection — verifier-supplied 32-byte nonce bound inside the signature
- Constant-time PQ ops — RustCrypto crates; key material is
Zeroize-on-drop - Compact wire format — CBOR (RFC 8949), ~3.7 KB total quote including signature
Phase 3.0: Sovereign Bitcoin Node Reference Architecture
PQ-RASCV now ships with a complete reference architecture for Sovereign Bitcoin Nodes, extending its generalized hardware attestation into domain-specific continuous trust verification for Bitcoin infrastructure:
- Bitcoin Node Identity & Workload Integrity — Verifies
bitcoindbinary hashes,bitcoin.confstates, and chainstate integrity directly bound to TPM/hardware measurements. - Node Runtime Continuity — Continuously monitors and attests to active node behavior (mempool status, connected peers, block tip height) detecting runtime drift.
- Distributed Verifier Consensus —
VerifierOrchestratorallows a federation of verifiers to vote on node trust state using deterministic quorum policies (Majority, Unanimous, Threshold). - Transparency Anchoring —
pqrascv-bitcoin-anchorprovides OP_RETURN serialization to commit finalAttestedNodeReporthashes onto the Bitcoin blockchain or transparency logs, eliminating split-brain attestation.
Phase 4.0: Formal Verification & Production Hardening
The core protocols have advanced to Production Readiness, backed by Level B Formal Verification:
- Strict System Invariants — Runtime invariants guarantee monotonic sequence evolution, bounded replay windows, and non-equivocation (
invariants.rs). - Cryptographic Audit Lineage — The
AuditTracesubsystem enforces an append-only, deterministic Merkle log of all policy evaluations and quorum formations. - Bitcoin Finality State Machine —
FinalityCommitmentformally distinguishes between probabilistic confirmation depth and internal deterministic finality thresholds (k_threshold), preventing premature irreversible consensus. - Consistency Checking — Full divergence drift validation via
ConsistencyCheckerensures global state integrity. - Fuzzing & Property Tests — Stabilized
cargo-fuzztargets for panic boundaries andproptestsuites for mathematical trace determinism.
Quick Start
# std (default)
= "1.0.0-rc.1"
# bare-metal — bring your own allocator
= { = "1.0.0-rc.1", = false, = ["alloc"] }
CLI Utility
The fastest way to conduct attestation is using the pqrascv CLI binary:
# 1. Generate post-quantum keypair
# 2. Prover: Generate attestation quote
# 3. Verifier: Validate the quote deterministically
Prover — device side
use ;
let = generate_ml_dsa_keypair.unwrap;
let rot = new;
let firmware_digest = ; // SHA3-256(firmware.bin)
let provenance = new
.add_subject
.with_slsa_level
.build
.unwrap;
let nonce = ; // received from verifier's Challenge
let quote = generate_quote
.unwrap;
let cbor_bytes = quote.to_cbor.unwrap; // send to verifier
Verifier — server side
Uses the companion pqrascv-verifier crate:
use Verifier;
use PolicyConfig;
let verifier = new;
// trusted_vk obtained out-of-band (provisioning DB, PKI, TPM EK cert).
match verifier.verify_cbor
How It Works
PQ-RASCV is a challenge–response protocol. The verifier drives; the prover measures, attests, and signs:
Verifier Prover (device)
│ │
│──── Challenge { nonce: [u8; 32] } ──────► │
│ ├── measure() → PCRs, fw_hash
│ ├── provenance → SLSA v1 predicate
│ └── sign body → ML-DSA-65 sig
│ │
│ ◄──── AttestationQuote (CBOR) ─────────── │
│ │
├── verify ML-DSA-65 signature
├── check nonce match + pub_key_id fingerprint
└── evaluate PolicyConfig → accept / reject
Signed payload fields (QuoteBody):
| Field | Content |
|---|---|
version |
Protocol version (1) |
timestamp |
Unix epoch seconds |
nonce |
32-byte replay-protection token |
measurements.pcrs |
8 × 32-byte PCR-style hash bank |
measurements.firmware_hash |
SHA3-256 of firmware image |
measurements.ai_model_hash |
SHA3-256 of AI model weights (optional) |
provenance |
SLSA v1 predicate — builder ID, subjects, SBOM hash |
pub_key_id |
SHA3-256 fingerprint of signer's ML-DSA-65 verifying key |
signature |
3 309-byte ML-DSA-65 signature over CBOR-encoded body |
Architecture
╔══════════════════════════════════════════════════════╗
║ generate_quote() ← public entry point ║
╚══════╤═══════════════╤══════════════╤════════════════╝
│ │ │
┌────▼─────┐ ┌─────▼──────┐ ┌───▼──────────────────┐
│ RoT │ │ Crypto │ │ Provenance │
│ trait │ │ Backend │ │ SlsaPredicateBuilder │
│ measure()│ │ ML-DSA-65 │ │ InTotoAttestation │
└────┬─────┘ └─────┬──────┘ └───┬──────────────────┘
│ │ │
┌────▼───────────────▼──────────────▼───────────────┐
│ AttestationQuote (CBOR · ML-DSA signed) │
└───────────────────────────────────────────────────┘
| Layer | Module | Heap? |
|---|---|---|
Measurement (RoT trait) |
measurement, backends/ |
No |
Cryptography (CryptoBackend trait) |
crypto |
No |
| Provenance builder | provenance |
Yes — alloc |
| Quote assembly | quote |
Yes — alloc |
| Policy evaluation | config |
No |
Supported Backends
Software RoT (default — no hardware required)
Hashes memory regions with SHA3-256. Ideal for development, WASM, and any platform without a hardware RoT.
let rot = new;
TPM 2.0 — features = ["hardware-tpm"]
Reads the SHA-256 PCR bank (PCRs 0–7) from a hardware or simulated TPM via
tss-esapi (TCG TSS2 ESAPI). Linux only.
= { = "0.1", = ["hardware-tpm"] }
// Set TPM2TOOLS_TCTI=device:/dev/tpm0 or swtpm:path=/tmp/swtpm.sock
let rot = new;
let m = rot.measure.expect;
println!;
# Install system libraries (Ubuntu/Debian)
DICE RoT — features = ["dice"]
TCG DICE Architecture §6 CDI derivation in pure Rust — no OS, no heap, bare-metal ready.
CDI_attestation = SHA3-256( CDI ‖ "DICE-attest" ‖ SHA3-256(firmware) )
= { = "0.1", = ["dice"] }
// Single layer
let rot = new;
// Two-layer chain: bootloader → application
let m0 = new.measure.unwrap;
let cdi1 = m0.pcrs.0; // CDI_0 derived from UDS
let m1 = new.measure.unwrap;
Cryptographic Primitives
| Role | Algorithm | Standard | Sizes |
|---|---|---|---|
| Signatures | ML-DSA-65 | FIPS 204 | seed 32 B · vk 1 952 B · sig 3 309 B |
| Key encapsulation | ML-KEM-768 | FIPS 203 | — |
| Hashing (measurements, fingerprints) | SHA3-256 | FIPS 202 | 32 B digest |
| Wire encoding | CBOR | RFC 8949 | ~3.7 KB total quote |
All PQ operations are constant-time (RustCrypto guarantee).
SigningKeySeed implements Zeroize and is wiped on drop.
Performance
| Target | Flash | Stack peak |
|---|---|---|
Cortex-M4 thumbv7em-none-eabi |
< 64 KB | ~12 KB |
RISC-V riscv32imac-unknown-none-elf |
< 68 KB | ~12 KB |
| Linux x86-64 | — | ~16 KB |
Release profile: lto = true, codegen-units = 1, opt-level = 3.
Measurement latency on Cortex-M4 @ 168 MHz: < 1 ms (Software RoT, 64 KB firmware).
Status & Roadmap
v1.0.0-rc.1 is published. The public API has stabilized, featuring deterministic formal verification and a fully functional CLI.
| Shipped in v1.0.0-rc.1 ✅ | Planned 🗺 |
|---|---|
| ML-DSA-65 sign / verify | Noise_PQX post-quantum transport |
| ML-KEM-768 encapsulation | CBOR COSE signatures (RFC 9052) |
| Software / TPM 2.0 / DICE backends | AMD SEV-SNP & Intel TDX backends |
| SLSA v1 provenance + SBOM hash | heapless allocation-free quote assembly |
| Sovereign Bitcoin Node Architecture | OP-TEE / TrustZone backend |
| Verifier Federation & Consensus | |
| Bitcoin Transparency Anchoring | Stable 1.0 API |
| CLI prover + verifier binary |
Security Considerations
Key storage — SigningKeySeed is 32 bytes and zeroizes on drop. On real hardware,
store it in a hardware-protected keystore (TPM NV, TrustZone, eFuse OTP). Never log
or transmit the seed.
Nonce freshness — reusing a nonce breaks replay protection. Generate a fresh 32-byte nonce per request and verify it matches the returned quote exactly.
Verifying key trust — pqrascv-verifier does not manage a PKI.
The caller supplies a trusted verifying key (provisioning DB, certificate chain, or TPM
EK cert). A compromised key invalidates all quotes signed with it.
DICE CDI confidentiality — the cdi field in DiceRoT is the hardware root secret.
It must never leave the device. Only the one-way cdi_attestation appears in quotes.
Transport layer — ML-DSA-65 protects the signature. If your transport (TLS 1.2, classical ECDH) is not post-quantum, a "harvest now, decrypt later" attacker can record and later decrypt the channel. Pair with a PQ transport (Noise_PQX, planned).
Quote age — set PolicyConfig::max_quote_age_secs to 60–300 s to bound the
validity window of captured quotes.
Contributing
Issues, PRs, and feedback are welcome at github.com/comwanga/pqrascv-core.
Areas where contributions are especially valuable:
- Platform backends — SEV-SNP, TDX, OP-TEE, Apple Secure Enclave
- Transport — Noise_PQX integration, COSE/CBOR signing
- Tooling — CLI binary, provisioning helpers
- Verification —
kaniharnesses for the crypto paths, fuzzing
If you are using pqrascv-core in a project — even experimentally — open a
GitHub Discussion.
Feedback at any stage shapes the road to 1.0.
License
Licensed under either of MIT or Apache 2.0 at your option.
Contributions are dual-licensed under the same terms unless explicitly stated otherwise.