Skip to content

LatticeArc

crates.io docs.rs CI NIST PQC FIPS 203–206 codecov License

Post-quantum cryptography for Rust. You describe what you're protecting; LatticeArc picks the algorithm, security level, and compliance mode. Hybrid (PQ + classical) by default. One crate.

What you'd normally wire up yourself What can go wrong
Pick from 4 NIST standards, 11 parameter sets Wrong security level, wrong algorithm type
Combine ML-KEM + X25519 + HKDF + AES-GCM Broken key combiner, missing domain separation
Zeroize secrets, constant-time comparisons Leaks via Debug, timing side-channels
FIPS 140-3, CNSA 2.0 mode restrictions Non-compliant algorithm silently selected
use latticearc::{encrypt, decrypt, CryptoConfig, UseCase, EncryptKey, DecryptKey};
use latticearc::generate_hybrid_keypair_with_level;
use latticearc::primitives::kem::ml_kem::MlKemSecurityLevel;

// HealthcareRecords resolves to ML-KEM-1024 (NIST Level 5), so the keypair
// must be generated at the matching level — generate_hybrid_keypair() defaults
// to ML-KEM-768 and would be rejected by validate_key_matches_scheme.
let (pk, sk) = generate_hybrid_keypair_with_level(MlKemSecurityLevel::MlKem1024)?;
let encrypted = encrypt(b"patient records",
    EncryptKey::Hybrid(&pk),
    CryptoConfig::new().use_case(UseCase::HealthcareRecords))?;
let decrypted = decrypt(&encrypted, DecryptKey::Hybrid(&sk), CryptoConfig::new())?;
// ML-KEM-1024 + X25519 + HKDF-SHA256 + AES-256-GCM — selected automatically

Quick Start

Library

[dependencies]
latticearc = "0.9"

Hybrid encryption — PQ + classical, both must fail for an attacker to succeed:

use latticearc::{encrypt, decrypt, CryptoConfig, EncryptKey, DecryptKey};

let (pk, sk) = latticearc::generate_hybrid_keypair()?;
let encrypted = encrypt(b"secret data", EncryptKey::Hybrid(&pk), CryptoConfig::new())?;
let decrypted = decrypt(&encrypted, DecryptKey::Hybrid(&sk), CryptoConfig::new())?;

Digital signatures — ML-DSA-65 + Ed25519 hybrid:

use latticearc::{
    generate_signing_keypair, sign_with_key, verify_with_anchor, CryptoConfig,
};

let config = CryptoConfig::new();
let kp = generate_signing_keypair(config.clone())?;
let signed = sign_with_key(
    b"document",
    kp.expose_secret_key(),
    kp.public_key(),
    config.clone(),
)?;

// Production verify pins the trust anchor. Bare `verify(&signed, config)`
// also exists but trusts the public key the envelope itself carries —
// appropriate only when the embedded key IS the trust root. See
// `docs/SECURITY_GUIDE.md` for the embedded-key threat model.
assert!(verify_with_anchor(&signed, kp.public_key(), kp.scheme(), CryptoConfig::new())?);

CLI

latticearc-cli exposes the same library for ops and CI workflows — no Rust required:

cargo install --git https://github.com/LatticeArc/latticearc latticearc-cli
# or, from a local checkout:  cargo install --path latticearc-cli
# Sign a legal document (ML-DSA-87 + Ed25519 hybrid, selected by use case)
latticearc-cli keygen --use-case legal-documents --output ./keys
latticearc-cli sign   --input contract.pdf \
  --key keys/hybrid-ml-dsa-87-ed25519.sec.json \
  --public-key keys/hybrid-ml-dsa-87-ed25519.pub.json
latticearc-cli verify --input contract.pdf \
  --signature contract.pdf.sig.json \
  --key keys/hybrid-ml-dsa-87-ed25519.pub.json

# Encrypt healthcare records (AES-256-GCM)
latticearc-cli keygen  --algorithm aes256 --output ./keys
latticearc-cli encrypt --use-case healthcare-records \
  --input patient.json --output patient.enc.json \
  --key keys/aes256.key.json

22 use cases · 12 algorithms · hybrid + PQ-only modes. Full reference: latticearc-cli/README.md.


When to Use

Use LatticeArc when you want:

  • Hybrid PQ + classical encrypt/decrypt without wiring ML-KEM + X25519 + HKDF + AES-GCM yourself
  • Use-case-driven algorithm selection (22 workloads, 3 compliance modes)
  • A CLI that ops teams can use without writing Rust
  • Opt-in FIPS routing with no code changes

Reach for something else when you need:

  • A single low-level primitive — use aws-lc-rs, fips204, fips205, or fn-dsa directly
  • End-to-end CMVP-certified module — no CMVP backend exists for PQ signatures yet
  • Cross-language bindings — liboqs covers C, Python, Go, Java
  • no_std / embedded — wolfCrypt leads for embedded PQ
  • A TLS stack — use rustls, OpenSSL 3.5, or wolfSSL

Detailed comparison: Ecosystem Map


How It Works

Plaintext, key type, and config flow through a policy engine that selects the algorithm pipeline at runtime:

flowchart LR
    subgraph "You provide"
        DATA["Plaintext"]
        KEY["Key type"]
        CFG["CryptoConfig"]
    end

    subgraph "LatticeArc decides"
        ENGINE["Policy\nEngine"]
    end

    subgraph "Hybrid mode"
        H_KEM["ML-KEM\nencapsulate"]
        H_ECDH["X25519\nkey exchange"]
        H_HKDF["HKDF\ncombine"]
        H_AES["AES-256-GCM\nencrypt"]
        H_KEM --> H_HKDF
        H_ECDH --> H_HKDF
        H_HKDF --> H_AES
    end

    subgraph "PQ-only mode"
        P_KEM["ML-KEM\nencapsulate"]
        P_HKDF["HKDF\nderive"]
        P_AES["AES-256-GCM\nencrypt"]
        P_KEM --> P_HKDF
        P_HKDF --> P_AES
    end

    DATA --> ENGINE
    KEY --> ENGINE
    CFG --> ENGINE
    ENGINE -->|"CryptoMode::Hybrid"| H_KEM
    ENGINE -->|"CryptoMode::PqOnly"| P_KEM

    style ENGINE fill:#8b5cf6,stroke:#6d28d9,color:#fff
    style H_AES fill:#10b981,stroke:#059669,color:#fff
    style P_AES fill:#3b82f6,stroke:#1d4ed8,color:#fff
Loading

Algorithms & Backends

Algorithm conformance ≠ module validation. --features fips switches aws-lc-rs to its CMVP-validated build for the algorithms it covers. PQ signatures always use non-validated crates. LatticeArc itself is not a CMVP-certified module.

Category Algorithms Backend
PQ Key Encapsulation ML-KEM-512/768/1024 (FIPS 203) aws-lc-rs — FIPS 140-3 validated with --features fips
PQ Signatures ML-DSA-44/65/87 (FIPS 204) fips204 — NIST-conformant, not CMVP-validated
PQ Hash Signatures SLH-DSA (FIPS 205) fips205 — NIST-conformant, not CMVP-validated
PQ Lattice Signatures FN-DSA-512/1024 (draft FIPS 206) fn-dsa — NIST-conformant, not CMVP-validated
Classical Signatures Ed25519 ed25519-dalek — audited
Classical Key Exchange X25519 aws-lc-rs — FIPS 140-3 validated with --features fips
Symmetric Encryption AES-256-GCM aws-lc-rs — FIPS 140-3 validated with --features fips
Symmetric Encryption ChaCha20-Poly1305 chacha20poly1305 — non-FIPS
Hash SHA-2 (256/384/512) RustCrypto sha2 — widely reviewed, NOT CMVP-validated. --features fips does NOT swap SHA-2 to aws-lc-rs.
Hash SHA-3, BLAKE2 sha3 / blake2 crates — non-FIPS
KDF HKDF-SHA256 aws-lc-rs — FIPS 140-3 validated with --features fips

Details: Algorithm Selection Guide · NIST Compliance

Architecture

The unified API sits over a small set of composite operations, which sit over the NIST primitives, which sit over their backends:

block-beta
    columns 3

    block:API["Unified API"]:3
        columns 3
        encrypt["encrypt()"] decrypt["decrypt()"] sign["sign_with_key()"]
    end

    block:CONFIG["Configuration"]:3
        columns 3
        cc["CryptoConfig"] mode["CryptoMode"] level["SecurityLevel"]
    end

    block:HYBRID["Hybrid & PQ-Only Encryption"]:2
        columns 2
        henc["hybrid\nML-KEM + X25519\n+ HKDF + AES-GCM"]
        pqenc["pq_only\nML-KEM\n+ HKDF + AES-GCM"]
    end

    block:SIG["Signatures"]:1
        columns 1
        hsig["ML-DSA + Ed25519\nSLH-DSA · FN-DSA"]
    end

    block:PRIM["Primitives"]:3
        columns 5
        kem["ML-KEM\nFIPS 203"] dsa["ML-DSA\nFIPS 204"] slh["SLH-DSA\nFIPS 205"] fn["FN-DSA\ndraft FIPS 206"] sym["AES-GCM\nX25519 · Ed25519"]
    end

    block:BACK["Backends"]:3
        columns 3
        awslc["aws-lc-rs\n(FIPS opt-in)"] fips204["fips204 · fips205"] fndsa["fn-dsa · ed25519-dalek"]
    end

    style API fill:#3b82f6,stroke:#1d4ed8,color:#fff
    style CONFIG fill:#e2e8f0,stroke:#64748b
    style HYBRID fill:#10b981,stroke:#059669,color:#fff
    style SIG fill:#f59e0b,stroke:#d97706,color:#fff
    style PRIM fill:#e2e8f0,stroke:#94a3b8
    style BACK fill:#374151,stroke:#1f2937,color:#fff
Loading

Verification

Multi-layered — each tier catches what the tier below cannot.

Proof-level

Tool What it proves Scope
SAW (via aws-lc-rs) Machine-checked correctness of C primitives AES-GCM, HMAC, HKDF, SHA-2, ECDSA, ECDH — see aws-lc-verification for the up-to-date proof inventory
Kani Bounded model checking of Rust code 29 proofs; 18 PR-blocking, full suite scheduled nightly

Property-based, differential, attacker-chosen

Tool What it catches
Proptest Roundtrip, non-malleability, single-bit rejection invariants (40+ properties × 256+ cases)
Cross-impl differential ML-KEM (fips203 vs aws-lc-rs, 600 round-trips/run), ML-DSA (fips204 vs pqcrypto-mldsa), SLH-DSA (fips205 vs pqcrypto-sphincsplus) — 21 tests
Wycheproof 555 attacker-chosen vectors through our AES-GCM, ChaCha20-Poly1305, HMAC, HKDF wrappers

Constant-time (3-way gate, weekly)

Tool Methodology
Criterion Qualitative wall-clock divergence between input classes
DudeCT Welch's t-test; per-bench gates — |max t| < 10 for HMAC verify (PRIMARY CT gate), |max t| < 50 for hybrid ct_eq (regression sentry — ctgrind is authoritative on this pure-Rust path). See .github/workflows/dudect.yml for rationale.
ctgrind (Valgrind memcheck) Marks secret bytes as uninit; fails on any branch or index depending on them

DoS, fuzz, sanitizers

  • Allocation budgets — per-API-call ceiling on every crypto op, regression-gated via stats_alloc
  • 31 libfuzzer targets — AEAD, KEM, signatures, KDF, serialization, DoS; weekly matrix; OSS-Fuzz scaffold in fuzz/oss-fuzz/
  • cargo-mutants --in-diff — 80% score floor, PR-blocking on changed crypto files
  • Sanitizers — ASan / TSan / LSan run weekly (Rust-side coverage); C-side uninitialized-read coverage for aws-lc lives in the upstream library's own CI, matching aws-lc-rs / ring / rustls / RustCrypto practice
  • #![forbid(unsafe_code)] enforced at workspace level

Full proof inventory: Formal Verification


Security

Designed under the assumption that any single algorithm may be broken — hybrid mode ensures an attacker must defeat both components. Key material is zeroized on drop, tag comparisons run in constant time, secret types have manual Debug impls that redact contents.

Limitations

  • Not a CMVP-certified cryptographic module. No CMVP backend exists for PQ signatures. Use --features fips for the subset that routes through aws-lc-rs.
  • Not independently audited. Security researchers welcome to review.
  • Pre-1.0. API may change between minor versions; see CHANGELOG.md. CLI environment variables documented in latticearc-cli/README.md.

Reporting & upstream


Build

Requires Rust 1.93+ and a C/C++ compiler. FIPS builds also need CMake and Go.

cargo build                       # default
brew install cmake go             # macOS, FIPS prerequisites
# sudo apt install cmake golang-go build-essential  # Ubuntu
cargo build --features fips       # FIPS-validated backend
Error Fix
CMake not found Install CMake (FIPS only)
Go not found Install Go 1.18+ (FIPS only)
cc not found (Linux) sudo apt install build-essential
Long initial build First build compiles AWS-LC from source (~2-3 min)

Cargo features

Feature Default Effect
fips off Routes AES-GCM, ML-KEM, X25519, HKDF through CMVP-validated aws-lc-rs. Required for ComplianceMode::Fips140_3 / Cnsa2_0. SHA-2 stays on RustCrypto sha2. Transitively enables fips-self-test.
fips-self-test off Power-up KAT self-tests for FIPS-boundary algorithms (ML-KEM, AES-GCM, ML-DSA, SLH-DSA).
tracing-init off Exposes init_tracing[_with_file] helpers. Libraries must NOT enable this — subscriber init belongs in the binary. Enabled by latticearc-cli.
secret-mlock off mlock(2) / VirtualLock for heap-backed SecretVec buffers — prevents swap and core-dump exposure.
kat-test-vectors off Test-only. Exposes AeadCipher::new_allow_weak_key to reproduce NIST AES-GCM Test Cases 1 & 2 (all-zero key).
perf off Benchmarking/metrics module (latticearc::perf) — bench scaffolding with no production consumer; enable only for perf tooling.

Migration

LatticeArc is pre-1.0; each minor version may ship breaking changes. See CHANGELOG.md for the authoritative per-release breaking-change list with rationale.


Documentation

Document Description
Algorithm Selection Guide Use-case tables, security-level mapping, compliance modes
Unified API Guide Zero-trust sessions, all 22 use cases, PQ-only mode
Key Format Specification LatticeArc Portable Key (LPK) schema, JSON + CBOR
Ecosystem Map Comparison with OpenSSL, aws-lc-rs, liboqs, RustCrypto, age, Sequoia
NIST Compliance Per-algorithm FIPS conformance status
Formal Verification Complete Kani proof inventory
Design & Architecture Crate structure, module boundaries, design decisions
Design Patterns Config, crypto safety, and testing patterns
CLI Reference Full latticearc-cli command reference

License & Contributing

Apache 2.0 — see LICENSE. Contributions welcome; see CONTRIBUTING.md.

About

Hybrid Post-Quantum Cryptography Library for Rust - Secure transition to Quantum-Safe Encryption.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages