pqrascv-core
Post-Quantum Remote Attestation & Supply-Chain Verification
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 provenance predicate binding a device's firmware identity to its build pipeline — on bare-metal Cortex-M4, RISC-V, WASM, or Linux.
Why PQ-RASCV?
Traditional attestation proves what is running but not how it was built or who signed it off. Classical signatures (RSA, ECDSA) are also broken by Shor's algorithm. PQ-RASCV fixes both:
- Post-quantum by default — ML-DSA-65 signatures, no RSA or ECDSA in the protocol
- Supply-chain provenance — SLSA v1 predicate + SBOM hash inside every signed quote
- One API everywhere — Cortex-M4, RISC-V, WASM, Linux, all using the same code
no_std + alloc— works on bare-metal without an OS
Add to your project
# std (default)
= "1.0.0-rc.8"
# bare-metal / no_std
= { = "1.0.0-rc.8", = false, = ["alloc"] }
CLI — fastest way to try it
# Generate a keypair
# Generate an attestation quote (prover side)
# Verify the quote (verifier side) — use the nonce printed by attest
Library usage
Prover (device side)
use ;
let = generate_ml_dsa_keypair.unwrap;
// SoftwareRoT is for testing only. Use TpmRoT or DiceRoT in production.
let rot = new;
let provenance = new
.add_subject
.with_slsa_level
.build
.unwrap;
let nonce = ; // received from the verifier
let quote = generate_quote.unwrap;
let cbor_bytes = quote.to_cbor.unwrap; // send to verifier
Verifier (server side)
use Verifier;
use PolicyConfig;
let verifier = new;
match verifier.verify_cbor
Python
# Build the extension
&&
=
= # 1952 bytes
= # 3309 bytes
assert
C / Embedded
unsigned char sk, vk, sig;
size_t sk_len = sizeof, vk_len = sizeof, sig_len = sizeof;
;
;
;
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 + pub_key_id fingerprint
└── evaluate PolicyConfig → accept / reject
Each quote carries: protocol version, timestamp, nonce, 8 × SHA3-256 PCRs, firmware hash, SLSA v1 predicate, and a 3 309-byte ML-DSA-65 signature. Wire size: ~3.7 KB CBOR.
Feature flags
| Feature | Default | What it enables |
|---|---|---|
std |
yes | std::error::Error on the error type |
alloc |
yes | Quote and provenance assembly |
hardware-tpm |
no | TPM 2.0 PCR reads via tss-esapi (Linux) |
dice |
no | DICE CDI derivation — pure Rust, no OS required |
software-rot-unsafe |
no | Software SHA3-256 RoT — testing only |
Measurement backends
| Backend | Feature | Status |
|---|---|---|
SoftwareRoT |
software-rot-unsafe |
Testing / demo only — rejected by PolicyEngineV2::production() |
TpmRoT |
hardware-tpm |
Production — requires tpm2-tss system library (Linux) |
DiceRoT |
dice |
Production — pure Rust, suitable for MCU boot chains |
TdxRoT |
intel-tdx |
Experimental — Linux kernel ≥ 5.19, /dev/tdx_guest |
SevSnpRoT |
amd-sev-snp |
Experimental — Linux kernel ≥ 5.19, /dev/sev-guest |
Security considerations
- Keep the seed secret. Store it in a TPM NV slot, eFuse, or TrustZone keystore — not in flash.
- Use a fresh nonce every request. Reusing a nonce breaks replay protection.
- Set
max_quote_age_secsto 60–300 s to bound the validity window of captured quotes. SoftwareRoTis test-only.PolicyEngineV2::production()rejects it; the CLI requires--software-rot-acknowledged.- Post-quantum transport. ML-DSA-65 protects the signature. Pair with a PQ transport (Noise_PQX / COSE Sign1) to close the channel against "harvest now, decrypt later".
See SECURITY.md for the vulnerability reporting policy.
Status — v1.0.0-rc.8
API is stabilizing. The ml-dsa crate is pinned to =0.1.0-rc.8 (FIPS-final algorithm, pre-stable Rust crate). The stable 1.0 release will follow the first stable ml-dsa ≥ 0.1.0.
| Ready | Experimental |
|---|---|
| ML-DSA-65 sign / verify | Intel TDX backend |
| Software / TPM 2.0 / DICE backends | AMD SEV-SNP backend |
| SLSA v1 provenance + SBOM hash | Sigstore verify_all (1-hop Fulcio + SET-based Rekor) |
| CBOR-native PKI (Root CA → Device) | OP-TEE, Apple Secure Enclave backends |
CRL revocation, CA rollover (TrustStore) |
|
PolicyEngineV2 composable rule engine |
|
| Bitcoin OP_RETURN anchoring + Merkle / SPV proofs | |
| COSE Sign1 (RFC 9052) + Noise_PQX transport | |
CLI (pqrascv attest / pqrascv verify) |
|
| Python bindings (PyO3 0.24) | |
C FFI + include/pqrascv.h |
|
| Kani formal verification (4 harnesses) | |
| Fuzz targets (7) |
Contributing
&&
See CONTRIBUTING.md for coding standards and the review process. Issues and PRs are welcome at github.com/comwanga/pqrascv-core.
License
MIT OR Apache-2.0 at your option.