aethel_core/lib.rs
1//! # aethel-core — Post-Quantum Ephemeral Identifier Engine
2//!
3//! `aethel-core` implements the **Polymorphic Lattice Projection (PLP)** standard
4//! for decoupled post-quantum ephemeral identity. It replaces static W3C DIDs
5//! with non-deterministic, ephemeral identity projections that leave **zero
6//! static public keys**, full stop — this crate has no blockchain, ledger, or
7//! on-chain component of any kind; the property holds regardless of where a
8//! caller chooses to publish anything.
9//!
10//! ## Core Components
11//!
12//! - **[`plp`]** — Polymorphic Lattice Projection engine: ring arithmetic, ZK sigma
13//! protocol, and rejection sampling over Module-LWE (M-LWE).
14//! - **[`htss`]** — 5D Hypercube Threshold Secret Sharing: Shamir 3-of-5 over F_q,
15//! dimension-disjoint routing across Q_5 (32 nodes, 80 edges).
16//! - **`saap`** (crate-private; its prove and verify pathway is retired, D-13) — Selective Attribute Attestation Protocol: BDLOP vector commitment
17//! scheme with ZK selective disclosure and norm-bound verification.
18//! - **[`sampling`]** — Enclave constant-time rejection sampling: 16-iteration padded
19//! loop, CMOV selection, volatile zeroization, and CBD η=2 sampler.
20//! - `puf` (research, non-default `puf` feature) — SRAM PUF + BCH(1023,512,55) fuzzy
21//! extractor: GF(2^10) arithmetic, Berlekamp-Massey, Chien Search, and pure Rust WASM
22//! implementation. Not part of the default build or the `aethel:core` WIT world.
23//! - **[`ct_verify`]** — Valgrind/ctgrind constant-time verification harness.
24//!
25//! ## Security Properties
26//!
27//! - **Unlinkability**: `Adv_Adversary_Link(b_τ1, b_τ2) ≤ Negl(λ)` under M-LWE hardness.
28//! - **Post-Quantum Soundness**: Reduces to Decision M-LWE_{k,k+1,η,q} over R_q.
29//! - **Zero Static Keys**: No public key is ever written to persistent storage or ledger.
30//! - **Constant-Time**: All secret-dependent operations execute in fixed time (I_max=16).
31//!
32//! ## Parameters (AETHEL-SAAP-LEVEL1)
33//!
34//! - Ring: `R_q = Z_q[X]/(X^256 + 1)`, `q = 8_380_417`
35//! - Module rank: `k = 4`
36//! - Noise: CBD η=2, rejection bound γ₁=131072, β=78
37//!
38//! ## Feature Flags
39//!
40//! - `std` (default): Standard library support, heap allocation.
41//! - `component`: Builds the WebAssembly Component Model adapter (`src/component.rs`)
42//! implementing the `aethel:core` WIT world. This is the only WebAssembly surface; a
43//! `wasm-bindgen` cdylib used to sit alongside it and was retired (see the note at the
44//! bottom of this file).
45//! - `enclave`: Enables constant-time enclave execution paths and volatile zeroization.
46//! - `puf` (research, non-default): Compiles the `puf` module. SRAM PUF is out of scope
47//! for the `aethel:core` WIT world and has no WASM export of its own; this feature
48//! exists for research use only, not for production identity derivation.
49//!
50//! ## Unsafe Code
51//!
52//! The default build (no `puf`, no `enclave`) contains exactly 5 `unsafe` blocks, all in
53//! [`sampling`], each carrying a `// SAFETY:` comment explaining the invariant it relies on
54//! (volatile zeroization writes and constant-time byte-slice reinterpretation of same-sized,
55//! non-aliasing structs). Enabling `puf` or `enclave` additionally compiles 2 more `unsafe`
56//! blocks in `puf::ffi`, an FFI wrapper around a C enclave shim that is not shipped by
57//! default.
58//!
59//! ---
60//!
61//! ## The 0x307 crate family
62//!
63//! `aethel-core` is one of six open-source crates from [0x307](https://0x307.com/crates), held to one
64//! audit and stability standard.
65//!
66//! | Crate | Tier | What it does |
67//! |---|---|---|
68//! | [pqc-sig](https://crates.io/crates/pqc-sig) | Production | ML-DSA, SLH-DSA and FN-DSA signatures (FIPS 204/205/206) |
69//! | [pqc-kem](https://crates.io/crates/pqc-kem) | Production | ML-KEM (FIPS 203), the X25519 + ML-KEM-768 hybrid, X-Wing, and sealed boxes |
70//! | [aethel-core](https://crates.io/crates/aethel-core) (this crate) | Production | Post-quantum anonymous identity: a separate identifier per context, context-bound ML-DSA signing |
71//! | [aethel-sdk](https://crates.io/crates/aethel-sdk) | Preview | The SDK over aethel-core, and the place to start |
72//! | [aethel-vault](https://crates.io/crates/aethel-vault) | Preview | Agent-held wallet: policy-gated x402 / EIP-3009 signing with ML-DSA-65 spend records |
73//! | [pqc-privacy](https://crates.io/crates/pqc-privacy) | Lab | Research bundle, kept off every identity and payment path |
74//!
75//! **Production** crates are thin, standards-bound libraries meant to be depended on today. **Preview** crates work and are published, with APIs still settling. **Lab** crates are research, never on an identity or payment path.
76//!
77//! **Runnable examples:** [0x307/examples](https://github.com/0x307/examples), one program per
78//! crate, pinned to the published versions.
79//!
80//! **Audit status:** None of these crates has been independently audited, and none holds a CMVP / FIPS 140-3 validation. "FIPS 203/204/205/206" means the algorithms follow those standards, not that the code is certified. Known issues for this crate are in
81//! [SECURITY.md](https://github.com/0x307/aethel-core/blob/main/SECURITY.md). Versioning and yanks:
82//! [STABILITY.md](https://github.com/0x307/aethel-core/blob/main/STABILITY.md).
83//!
84
85#![cfg_attr(not(feature = "std"), no_std)]
86// unsafe_code is required for volatile memory operations in sampling.rs and puf.rs
87#![warn(missing_docs)]
88#![warn(clippy::all)]
89
90// ── Allocator setup ───────────────────────────────────────────────────────────
91
92extern crate alloc;
93
94#[cfg(feature = "std")]
95extern crate std;
96
97
98// ── Module declarations ──────────────────────────────────────────────────────
99
100/// Polymorphic Lattice Projection (PLP) engine.
101pub mod plp;
102
103/// Threshold secret sharing (Shamir 3-of-5) plus a local hypercube routing simulation.
104pub mod htss;
105
106/// Selective Attribute Attestation Protocol (SAAP) verification engine.
107// Superseded by [`credential`], and no longer part of the public surface: its
108// signatures take a raw u64 disclosure mask, which the WIT world is explicit
109// about never putting on the wire (P3-10 / 0X3-78). Retained crate-internally
110// so its characterisation tests keep pinning the old verifier's defects as
111// running code.
112pub(crate) mod saap;
113
114/// Identity key generation, purpose-separated (context-bound) signing, and
115/// the native `Identity` → PLP projection/proof bridge (A-1).
116pub mod signing;
117
118pub mod credential;
119
120/// Enclave constant-time rejection sampling and CBD η=2 sampler.
121pub mod sampling;
122
123/// `aethel-plp-1` — versioned wire envelope for PLP projections and proofs
124/// (A-4), plus the byte-only [`wire::verify_projection`] entry point.
125pub mod wire;
126
127/// SRAM PUF + BCH(1023,512,55) fuzzy extractor (research, non-default; see the `puf` feature).
128#[cfg(feature = "puf")]
129pub mod puf;
130
131/// Valgrind/ctgrind constant-time verification harness.
132pub mod ct_verify;
133
134/// Rust-side mirror of the `aethel:core` WIT world's `identity-error` variant.
135pub mod identity_error;
136
137/// WebAssembly Component Model adapter implementing the `aethel:core` WIT world.
138#[cfg(feature = "component")]
139pub mod component;
140
141// ── Re-exports of public API types ───────────────────────────────────────────
142
143pub use htss::{HypercubeNetwork, NodeAddress, SecretSharer, ZkProofSegment};
144pub use identity_error::IdentityError;
145pub use plp::{EphemeralProjection, MasterIdentity, Prover, Verifier, ZkIdentityProof};
146pub use saap::{SaapProof, SaapValidationError};
147
148// `sampling::{PlpProof, RejectionError, VectorK}` is intentionally NOT
149// re-exported at the root as of 0.6.0 (BREAKING — A-4). Those are the
150// enclave sampler's internal types; mixing them into the public verify
151// surface was exactly the "host copies structs / pulls sampling internals"
152// gap A-4 closes. They remain reachable at `aethel_core::sampling::*` for
153// code that genuinely needs the enclave path.
154
155// A-1 / X-2: the native identity surface. `signing::Identity` is the type an
156// agent actually holds (an ML-DSA-65 keypair + PLP seed derived together from
157// one entropy input); `verify` and `verify_with_purpose` are its free-function
158// verification counterparts, needing only public material. See
159// `docs/PURPOSES.md` for the purpose-context registry and
160// `signing::Identity::sign_with_purpose` for how it is used.
161pub use signing::{verify, verify_with_purpose, Identity};
162
163// A-4: the bytes-only verify entry point the gap analysis names —
164// `verify_projection(projection_bytes, proof_bytes, context) -> Result<bool, _>`
165// — decoding `aethel-plp-1` wire envelopes so a caller never touches
166// `sampling` internals or a hand-copied struct layout.
167pub use wire::verify_projection;
168
169// ── Crate-level constants ─────────────────────────────────────────────────────
170
171/// Ring degree N for the cyclotomic polynomial X^N + 1.
172pub const RING_N: usize = 256;
173
174/// Prime modulus q = 8_380_417 ≈ 2^23, q ≡ 1 (mod 512).
175pub const MODULUS_Q: i64 = 8_380_417;
176
177/// Module rank k (AETHEL-SAAP-LEVEL1).
178pub const MODULE_K: usize = 4;
179
180/// Centered Binomial Distribution parameter η = 2.
181pub const PARAM_ETA: i64 = 2;
182
183/// Masking vector bound γ₁ = 2^17 = 131_072.
184pub const PARAM_GAMMA1: i64 = 131_072;
185
186/// Rejection sampling bound β = 78.
187pub const PARAM_BETA: i64 = 78;
188
189/// Rejection threshold γ₁ - β = 130_994.
190pub const REJECTION_BOUND: i64 = PARAM_GAMMA1 - PARAM_BETA;
191
192/// Fixed iteration ceiling for constant-time enclave loop.
193pub const FIXED_ITERATION_CEILING: usize = 16;
194
195/// Magic header bytes for the Ephemeral Identity Attestation Bundle (EIAB).
196pub const EIAB_MAGIC: &[u8; 4] = b"ATH1";
197
198// ── Build provenance ──────────────────────────────────────────────────────────
199//
200// Excluded from the component build, and deliberately.
201//
202// `COMPONENT_SHA256` is the digest of the component this source builds.
203// Compiling it into that same component would make the artifact contain its own
204// digest: a fixed point that does not exist, because recording a new hash
205// changes the bytes, which changes the hash. These constants exist for native
206// consumers — an SDK that embeds the component and wants to check that the
207// crate it links and the artifact it vendors describe one build — so gating
208// them out costs nothing and keeps the component reproducible.
209
210/// The commit this build's component was produced from.
211///
212/// **This names the commit whose tree was built, which is an ancestor of the
213/// commit that records it.** A file cannot contain the hash of the commit
214/// containing it, so the release step writes the revision the recorded
215/// [`COMPONENT_SHA256`] was measured from, one commit behind itself.
216///
217/// It is provenance for a reader, not an equality check, and comparing it to a
218/// revision pinned downstream will not work: a consumer that pins merge commits
219/// is pinning commits that did not exist when this was written. To verify that a
220/// vendored artifact matches this crate, compare [`COMPONENT_SHA256`], which
221/// describes the bytes instead of a label.
222#[cfg(not(feature = "component"))]
223pub const GIT_REVISION: &str = env!("AETHEL_CORE_GIT_REVISION");
224
225/// SHA-256 of the canonical `aethel_core.component.wasm` this crate builds.
226///
227/// Canonical means the platform CI builds on. The hash is platform-specific:
228/// rustc embeds platform paths and links a different std, so the same source
229/// built on Windows or macOS produces different bytes, and a hash is only
230/// meaningful alongside the toolchain that produced it.
231///
232/// This is the value to assert on. An SDK that vendors the component can compare
233/// its own recorded hash against this one and fail when they disagree, which
234/// catches a linked dependency and an embedded artifact that have drifted apart
235/// while both still claim the same version.
236#[cfg(not(feature = "component"))]
237pub const COMPONENT_SHA256: &str = env!("AETHEL_CORE_COMPONENT_SHA256");
238
239// ── Error type ────────────────────────────────────────────────────────────────
240
241/// Top-level error type for aethel-core operations.
242#[derive(Debug, Clone, PartialEq, Eq)]
243pub enum AethelError {
244 /// Serialization or deserialization failed.
245 SerializationError,
246 /// Proof verification failed.
247 VerificationFailed,
248 /// Rejection sampling exhausted all iterations.
249 RejectionSamplingFailed,
250 /// PUF reconstruction failed (too many bit errors).
251 PufReconstructionFailed,
252 /// Invalid input length.
253 InvalidInputLength,
254 /// SAAP validation error.
255 SaapError(SaapValidationError),
256}
257
258impl From<SaapValidationError> for AethelError {
259 fn from(e: SaapValidationError) -> Self {
260 AethelError::SaapError(e)
261 }
262}
263
264// ── One WebAssembly artifact ──────────────────────────────────────────────────
265//
266// The wasm-bindgen export surface that used to live here is gone (P3-13 /
267// 0X3-81). It was a second WebAssembly surface alongside the Component Model
268// component: untyped (`Vec<u8>`/`bool`/`u64`), signalling failure with sentinel
269// values instead of `result<T, identity-error>`, and taking a raw u64
270// disclosure mask the WIT world is explicit about never putting on the wire.
271//
272// Two surfaces contradicts the charter's "one shared .wasm; adding a language
273// never adds crypto", and the untyped one is where both P3-10 soundness
274// findings sat unnoticed precisely because nothing connected it to the declared
275// world. An SDK author picking it up got sentinels rather than typed results.
276//
277// The component in `src/component.rs`, built with `--features component`, is
278// the L1 boundary. See README's "The WASM Component (L1 boundary)".