aethel-core 0.7.5

Post-quantum anonymous identity for Rust and WASM. A no_std alternative to static W3C DIDs: per-context identifiers, no reusable public key, context-bound ML-DSA signing. Selective disclosure ships and is being hardened; see SECURITY.md.
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
# aethel-core — Post-Quantum Ephemeral Identity Engine

> **Tier:** Production · **MSRV:** 1.85 · **License:** Apache-2.0 · Not independently audited, see [the crate family](#the-0x307-crate-family)

[![WASM](https://img.shields.io/badge/target-wasm32--unknown--unknown-green)](https://webassembly.org/)
[![License: Apache-2.0](https://img.shields.io/badge/License-Apache--2.0-blue.svg)](#license)

## PLP in one paragraph

An agent holds one [`signing::Identity`](src/signing.rs) (sealed at rest, never persisted
in the clear). To present to a verifier: derive a one-time PLP projection for the
verifier's context, prove ownership of it, sign the verifier's attach challenge under a
purpose-separated context (`docs/PURPOSES.md`), and hand over bytes —
[`wire::encode_projection`](src/wire.rs)/[`encode_proof`](src/wire.rs) output. The verifier
holds no secret at all: it calls [`wire::verify_projection`](src/wire.rs) and
`verify_with_purpose` on nothing but those bytes. See
[`examples/present_to_verifier.rs`](examples/present_to_verifier.rs) for the whole flow in
under 40 lines, and run it with `cargo run --example present_to_verifier`.

`aethel-core` is a `no_std`-compatible Rust library
implementing three post-quantum identity primitives, compiled natively or to
`wasm32-unknown-unknown`:

- **Polymorphic Lattice Projection (PLP)** — context-bound ephemeral identity projection and
  ZK ownership proof over Module-LWE (M-LWE).
- **Selective Attribute Attestation Protocol (SAAP)** — BDLOP vector commitment with
  selective disclosure and norm-bound verification. The commitment does not currently
  provide the hiding property the design calls for; see
  [`SECURITY.md`](./SECURITY.md#known-limitations) before relying on undisclosed
  attributes staying undisclosed.
- **Threshold secret sharing (Shamir 3-of-5) for identity backup** — a ritual the agent's
  principal or an operator runs over a sealed identity's key material, routed (as a local
  model, not a running network) over a Q_5 hypercube graph (32 nodes, 80 edges). This is
  **not** a hosted service — 8gentz does not run the 32-node cube; see
  [`docs/HTSS-TOPOLOGY.md`](docs/HTSS-TOPOLOGY.md#who-runs-htss-a-3).

## What runs today vs. what is designed

**Runs today** (covered by `cargo test`: 27 `--lib` unit tests + 18 `tests/plp_tests.rs`
integration tests + 1 doctest, all passing on default features):

- `plp` — key derivation (`MasterIdentity::from_seed`), context projection
  (`project_at_context`), ZK proof generation and verification (`Prover`, `Verifier`)
- `credential` — BDLOP credential issuance and blinding (`Credential::issue`,
  `BlindedCredential::new`) and the linked selective-disclosure proof (`credential::prove`,
  exported as `saap-verify-presentation`). **The commitment does not hide**: see `SECURITY.md`
  and `docs/DEVIATIONS.md` D-01
- `saap` — crate-internal primitives the credential module builds on. The single-response
  `saap_prove`/`verify_saap_proof` pathway was retired from the WIT world in 0.1.5 (D-13)
- `htss` — 3-of-5 threshold secret splitting and reconstruction, hypercube routing
- `sampling` — constant-time rejection sampling, CBD η=2 sampler, norm checking
- `ct_verify` — a Valgrind/ctgrind constant-time verification harness (doctest-covered)
- `identity_error` — the Rust-side mirror of the WIT world's `identity-error` variant, plus
  checked wrappers (`*_checked` functions) that return it instead of panicking
- `component` — the WebAssembly Component Model adapter implementing the `aethel:core` WIT
  world; the single WASM artifact every language binding embeds

**Designed, not yet implemented / out of scope for this crate:**

- **SRAM PUF fuzzy extraction** (`puf` module, non-default `puf` feature) — a BCH(1023,512,55)
  fuzzy extractor for deriving key material from noisy hardware SRAM. This is research code:
  its BCH encoder is a simplified placeholder (see the comments in `src/puf.rs`), it is not
  part of the default build, and it does not appear in the `aethel:core` WIT world. Enabling
  `--features puf` compiles it; the default build does not, and no exported operation reaches
  it.
- **`enclave` feature** — gates a set of `extern "C"` FFI declarations (`src/puf.rs`'s `ffi`
  module) into a C enclave shim (`c/bch_decoder.c`, `c/ct_norm.c`, `c/ct_sampling.c`) that this
  repo does not build a real target for; `c/ct_sampling.c` calls C functions declared nowhere
  in this repo. Nothing in the working code path (`plp`, `saap`, `htss`, `sampling`, `puf`
  without `enclave`) calls into it.
- **`aethel-runtime`** and the substrate repos (`pqvm`, `waven`, `wamr`, `awre`, `qies`,
  `obfuscation`) — separate repositories this crate does not depend on, build, or test.
  Nothing in this repo implies they ship alongside it.

## Cryptographic Parameters

| Parameter | Value |
|-----------|-------|
| Ring | `R_q = Z_q[X]/(X^256 + 1)` |
| Modulus `q` | `8,380,417` |
| Module rank `k` | 4 (`plp::MODULE_K`) |
| Noise `η` | 2 (Centered Binomial Distribution) |
| Masking bound `γ₁` | 131,072 (2^17) |
| Challenge weight | 39 non-zero coefficients in `{±1}` (`plp::CHALLENGE_WEIGHT`) |
| Rejection bound `β` | 78, which is `39 × 2` and is checked against the challenge weight at compile time |
| Rejection ceiling | 48 for an identity proof, 192 for a credential presentation |
| PLP matrix domain separator | `"AETHEL_PLP_CTX_V3"` |
| PLP challenge domain separator | `"AETHEL_PLP_CHALLENGE_V4"` |
| SAAP challenge domain separator | `"AETHEL_SAAP_CHALLENGE_V3"` |

## Modules

| Module | Description | Status |
|--------|-------------|--------|
| `plp` | Polymorphic Lattice Projection — context-bound ephemeral identity projection over M-LWE | Default |
| `signing` | Identity key generation, purpose-separated signing (`sign_with_purpose`/`verify_with_purpose`), and the native `Identity` → PLP projection/proof bridge | Default |
| `wire` | `aethel-plp-1` versioned wire envelope + `verify_projection(bytes, bytes, bytes) -> Result<bool, _>` | Default |
| `saap` | Selective Attribute Attestation Protocol — BDLOP commitment + ZK selective disclosure | Default |
| `credential` | Issuer-authenticated credential issuance/presentation, superseding `saap`'s public surface | Default |
| `htss` | Threshold secret sharing (Shamir 3-of-5) for identity backup, modeled over a Q_5 routing graph — a principal/operator ritual, not a hosted service | Default |
| `sampling` | Constant-time rejection sampling — 16-iteration fixed loop, CMOV, zeroization | Default |
| `ct_verify` | Constant-time verification harness | Default |
| `identity_error` | Mirror of the WIT `identity-error` variant, plus checked wrappers | Default |
| `puf` | SRAM PUF fuzzy extractor — BCH(1023,512,55) over GF(2^10), research code | Non-default (`puf` feature) |

### Which type do I hold? (X-2)

| Role | Type | Notes |
|---|---|---|
| **Agent** | one [`signing::Identity`](src/signing.rs) | Sealed at rest (`export_sealed`/`import_sealed`). Holds an ML-DSA-65 keypair and a PLP master seed together. |
| **Verifier** | nothing — bytes only | Calls `verify`/`verify_with_purpose`/`wire::verify_projection`. No secret of any kind. |
| **Internal derivation** | [`plp::MasterIdentity`](src/plp.rs) | Derived from an `Identity`'s seed on demand; prefer `Identity` in application code. |
| **aethel-vault** (separate crate) | a settlement signer key, and — `fhe-state` mode only — a TFHE key pair | Neither leaves the agent; consumes this crate for identity, purpose bytes, and `verify_projection`. |

See [`docs/PURPOSES.md`](docs/PURPOSES.md) for the full purpose-bytes registry
(`signing::purpose`) and the domain-separation rule it enforces, and
[`docs/WIRE-FORMAT.md`](docs/WIRE-FORMAT.md) for the `aethel-plp-1` wire codec.

## Feature Flags

| Feature | Default | Description |
|---------|---------|-------------|
| `std` | ✅ Yes | Standard library support, heap allocation. |
| `component` | ❌ No | Builds the WebAssembly Component Model adapter implementing the `aethel:core` WIT world. The one WASM artifact; see [The WASM Component](#the-wasm-component-l1-boundary). |
| `enclave` | ❌ No | Compiles the C enclave FFI shim (see [What runs today vs. what is designed](#what-runs-today-vs-what-is-designed)). Not buildable against a real enclave target in this repo. |
| `puf` | ❌ No | Compiles the `puf` module (SRAM PUF fuzzy extraction). Research only, and not reachable through the `aethel:core` WIT world. |

## WASM Exports

```wit
package aethel:core@0.1.0;

world aethel-core {
  export identity;       // plp-*, master-identity, credential, saap-verify-presentation
  export secret-sharing; // htss-split, htss-reconstruct
}
```

See [`wit/aethel-core.wit`](wit/aethel-core.wit) for the full WIT interface definition. It is
checked in and authoritative: bindings are generated from it, so the declared world and the
compiled artifact cannot drift apart the way they did before P3-10.

## The WASM Component (L1 boundary)

`aethel-core` builds as a **WebAssembly Component Model component** implementing the
`aethel:core` world declared in [`wit/aethel-core.wit`](wit/aethel-core.wit). This is the
artifact every language binding embeds — one shared component, never per-language crypto.

```bash
cargo build --release --target wasm32-unknown-unknown   --no-default-features --features component
wasm-tools component new   target/wasm32-unknown-unknown/release/aethel_core.wasm   -o aethel_core.component.wasm
```

Verify what you built exposes the declared world:

```bash
wasm-tools validate aethel_core.component.wasm
python3 scripts/check-component-exports.py wit/aethel-core.wit aethel_core.component.wasm
```

The checker derives the expected surface from `wit/aethel-core.wit` and compares it with what
the component actually declares: the export set for equality, and every interface's types and
signatures. `scripts/component-negative-control.py` builds a component with one export removed
and requires the checker to reject it, which CI runs as its own job.

And that it actually runs — loading it in `wasmtime` and checking every operation
against the native implementation:

```bash
cargo test --features component-tests --test component_execution
```

Those are different claims. Validating proves the artifact is well-formed; only the
execution proof shows the component and the native API compute the same answers, which is
what "one artifact embedded by every language" has to mean.

### Reproducing the published artifact

Two builds of the same source commit produce byte-identical output. The expected hash is
checked into [`component.sha256`](component.sha256) and enforced in CI, so you do not have to
take our word for what the binary contains:

```bash
sha256sum aethel_core.component.wasm
cat component.sha256
```

**The canonical build platform is CI**, and the hash in `component.sha256` is the one produced
there: `ubuntu-latest`, Rust 1.97.0, wasm-tools 1.258.0, as pinned in
`.github/workflows/component.yml`. Reproduce it on that platform and you get the same bytes;
CI proves this on every push by building twice from a clean target directory and comparing.

Building on a different OS will produce a **different hash** — this is not a
platform-independent guarantee, and we would rather say so than let you discover it. A
Windows build of this exact commit differs from the Linux one, because Rust embeds
platform-specific paths and links a different `std`. If your hash does not match and you are
not on the canonical platform, that is expected; if it does not match and you *are*, the
artifact was not built from this source.

### Component status per operation

| Operation | Status |
|---|---|
| `plp-project-at-context` | Implemented |
| `plp-prove-identity` | Implemented |
| `plp-verify` | Implemented |
| `plp-verify-bytes` | Implemented (A-4 — verify from `aethel-plp-1` wire bytes, binding the verifier's own context) |
| `encode-projection` | Implemented (A-4 — typed record to `aethel-plp-1` bytes) |
| `encode-proof` | Implemented (A-4) |
| `saap-verify-presentation` | Implemented |
| `issuer-public-parameters` | Implemented |
| `verify-signature` | Implemented |
| `sign-with-purpose` (on `master-identity`) | Implemented (sign under a registered purpose, as `Identity::sign_with_purpose`) |
| `verify-signature-with-purpose` | Implemented (as `signing::verify_with_purpose`) |
| `htss-split` | Implemented (fixed internal nonce, see `src/component.rs`) |
| `htss-reconstruct` | Implemented |

Selective disclosure runs through the `credential` resource (`issue` / `present`) and
`saap-verify-presentation`, anchored on the PLP projection `b_τ = A_τ·s + e_τ`, whose noise is
what makes it publishable. Issuing and verifying take opposite halves of the issuer's key
pair: `issue` takes the issuer seed, `saap-verify-presentation` takes the
`issuer-public-parameters` derived from it, so a verifier holds no secret and issuer and
verifier can be separate parties. What those parameters do and do not vouch for is stated on
the type in the WIT, and at length in [`docs/ISSUER-AUTHENTICATION.md`](docs/ISSUER-AUTHENTICATION.md). An earlier `attestation` interface exported a narrower
`saap-prove` / `saap-verify` pair whose verify half could only ever deny — it needed a public
key `t = A_τ·sk` that its signature could not carry and that, having no error term, was an
exact linear image of the secret. That interface was removed in 0.1.5 rather than kept as a
surface that could never succeed.

This is the only WebAssembly artifact. The `wasm-bindgen` core module that used to sit
alongside it was retired in 0.1.5: two surfaces contradicted the one-artifact rule, and the
untyped one signalled failure with sentinel values instead of `result<T, identity-error>`.

## Target matrix (X-3)

| Role | Target | Artifact | Status |
|---|---|---|---|
| sagp-host / native verifier | native rlib, `x86_64`/`aarch64` | `aethel-core` crate, `wire::verify_projection` | Supported, tested (`cargo test`) |
| Agent SDK | `wasm32-unknown-unknown` component | `aethel_core.component.wasm` (`--features component`) | Supported, tested (`cargo test --features component-tests`) |
| Inner worker | `wasm32-wasip2` | — | Not built today. The `wasm32-wasip2` Rust target exists and this crate's default-feature code builds under it, but no CI job or shipped artifact targets it; treat as "to decide" per the gap-remediation plan, not as a supported target. |

Add `aethel-vault` to the ["Shared WASM Modules"](#shared-wasm-modules) table below: it
consumes this crate for identity, purpose bytes, and `verify_projection`, and is a
*research* module in the same sense the others there are — see that crate's own README for
its target matrix and production/research status.

## Building

### Prerequisites
- Rust 1.85+ (`rustup target add wasm32-unknown-unknown` for WASM builds)

### Native Build + Tests

```bash
cargo build
cargo test
```

### WASM Build

The WebAssembly build is the component; see
[The WASM Component (L1 boundary)](#the-wasm-component-l1-boundary) for the full recipe.

```bash
cargo build --release --target wasm32-unknown-unknown --no-default-features --features component
```

### With the `puf` Feature

```bash
cargo build --features puf
cargo test --features puf
```

## Integration Example (Rust)

The full "load an identity, present to a verifier, verify from bytes" flow lives in
[`examples/present_to_verifier.rs`](examples/present_to_verifier.rs) (run with
`cargo run --example present_to_verifier`) — see [PLP in one paragraph](#plp-in-one-paragraph)
above. The lower-level struct API it is built on:

```rust
use aethel_core::plp::{MasterIdentity, Prover, Verifier};

// Derive a master identity from a 32-byte seed (caller-supplied entropy)
let seed = [0x11u8; 32];
let identity = MasterIdentity::from_seed(&seed);

// Project at context τ (context-bound).
// `randomness` MUST be at least 32 bytes of fresh, secret entropy, sampled anew
// per projection. It does two jobs: it seeds the error term that makes the
// projection an M-LWE sample rather than an exact linear image of the secret,
// and it salts the context matrix A so two projections at one τ are independent
// samples. Reusing τ is safe; reusing `randomness` is what is not.
let tau = b"session_context_2026";
let randomness = [0x22u8; 32]; // demo value; sample fresh in real use
let projection = identity.project_at_context(tau, &randomness);

// Prove ownership. The proof is computed against the projection, so it is
// bound to that projection's A.
let proof = Prover::prove_identity(&identity, &projection, &seed)
    .expect("honest parameters");

// Verify (by any party with the projection and proof)
assert!(Verifier::verify(&projection, &proof));
```

Most application code should prefer [`signing::Identity`](src/signing.rs)'s
`project_at_context`/`prove` over calling `plp::MasterIdentity` directly — see
["Which type do I hold?"](#which-type-do-i-hold-x-2).

## Security Properties

- **Post-quantum secure**: Based on Module Learning With Errors (M-LWE), conjectured secure against quantum adversaries
- **Ephemeral identifiers**: Each context `τ` produces a mathematically independent projection — no linkability across contexts
- **Constant-time**: All secret-dependent operations use fixed-iteration loops and CMOV selection
- **No traditional crypto**: Zero AES, RSA, ECDSA, or classical elliptic curve operations
- **PLP is an identity, not an address. Spend rails stay `eip155`.** A PLP projection is
  never encoded as, hashed into, or substituted for a Base address; USDC settlement is a
  separate dialect this crate has no notion of. See
  [`docs/PLP-ALGORITHM.md` §9](docs/PLP-ALGORITHM.md#9-plp-vs-didpkheip155--two-dialects-not-two-competitors-a-2).
- **A key signs under one purpose only.** `signing::Identity::sign_with_purpose`/`verify_with_purpose`
  use FIPS 204's native context mechanism, so a signature made for one purpose (attach
  challenge, receipt, HITL approval, ...) provably does not verify under another. See
  [`docs/PURPOSES.md`](docs/PURPOSES.md).
- **Offline generation**: Identity generation (`plp` key derivation, context projection, proof generation — the `--lib` unit tests plus `tests/plp_tests.rs`) never requires network access, and this is proven by denying the capability at the boundary rather than by trusting application code to report it honestly. CI's `offline-generation` job (`.github/workflows/ci.yml`) runs that generation test suite inside a network namespace with no interface, and in the same isolated step runs a negative-control test (`tests/network_isolation_negative_control.rs`) that deliberately makes a real network call — that control is *expected to fail* there, and its failure is what proves the isolation is real. If you don't trust this claim, don't take it on faith: read `offline-generation` in the Actions tab, or reproduce it locally (Linux/WSL2) with `unshare --net --map-root-user -- cargo test --offline --lib --test plp_tests`.

## Unsafe Code

The default build (`std`, no `puf`, no `enclave`) contains exactly 5 `unsafe` blocks, all in
[`src/sampling.rs`](src/sampling.rs) (lines ~98, ~167, ~173, ~179, ~408 at time of writing),
each carrying a `// SAFETY:` comment above it explaining the invariant it relies on:

- Two `enclave_explicit_zeroize` / `PolyRq::zeroize` blocks use `core::ptr::write_volatile` in
  a loop over a pointer derived from a live `&mut` reference, sized to `size_of::<T>()`,
  followed by a `compiler_fence` — this is what makes secret zeroization survive dead-store
  elimination.
- Three blocks in `enclave_plp_prove_fixed_time` reinterpret same-sized, non-aliasing local
  `PlpProof` values as byte slices (`core::slice::from_raw_parts[_mut]`) to run a
  constant-time conditional copy (`ct_cond_copy`) without branching on secret data.

Enabling `puf` or `enclave` additionally compiles 2 more `unsafe` blocks, in `src/puf.rs`'s
`ffi` module — a wrapper around the C enclave shim described in
[What runs today vs. what is designed](#what-runs-today-vs-what-is-designed).

## Shared WASM Modules

aethel-core is one of several independently-versioned repositories intended to run alongside
each other as WASM modules loaded by a wasmer.io host. These are separate repos with their own
build and test suites — this README makes no claims about their state:

| Module | Purpose | Relationship to aethel-core | Production / research |
|--------|---------|---|---|
| `pqc-kem` | ML-KEM (FIPS 203) key encapsulation | Sibling module, not a dependency | Research |
| `pqc-sig` | ML-DSA (FIPS 204) signatures | **Direct dependency** — `signing::Identity` is built on `pqc_sig::MlDsa65Keypair` | Research |
| `privacy` | ε-Differential Privacy noise injection | Sibling module, not a dependency | Research |
| `obfuscation` | WASM binary hardening | Sibling module, not a dependency | Research |
| `aethel-vault` (repo `aethel-runtime`) | Agent-held wallet: settlement signing, spend policy, receipts | **Consumes this crate** — identity, `signing::purpose` constants, `wire::verify_projection` | Research; see that crate's own README for its target matrix and custody rules |

## Continuous Integration

[`.github/workflows/ci.yml`](.github/workflows/ci.yml) runs on every push and pull request, on
a fresh GitHub-hosted runner.

Three jobs:

- **Build & test** — `cargo build --all-targets` / `cargo test` with default features.
- **Offline generation (network-isolated)** — re-runs the identity-generation test suite inside
  a real network namespace with no interface configured, proving generation works with zero
  network access rather than just asserting it in-process. A negative control in the same job
  confirms the isolation itself is real: a test that tries to make a network call is expected
  to fail under isolation, and the job fails loudly if it doesn't.
- **WASM test (Node)** — runs the test suite under `wasm32-unknown-unknown` via `wasm-pack test
  --node`. This is what actually exercises the zeroization test in WASM linear memory rather
  than only on native — memory that isn't returned to an OS on drop the way native heap memory
  is. The job also greps for that test by name, because a run that silently skipped it would
  otherwise still be green.

## Further Documentation

[`docs/`](./docs/) has deeper algorithm write-ups: [`PLP-ALGORITHM.md`](./docs/PLP-ALGORITHM.md)
(§9 covers PLP vs `did:pkh:eip155`), [`SAAP-SPEC.md`](./docs/SAAP-SPEC.md),
[`HTSS-TOPOLOGY.md`](./docs/HTSS-TOPOLOGY.md) ("Who runs HTSS" section),
[`SRAM-PUF.md`](./docs/SRAM-PUF.md), [`OVERVIEW.md`](./docs/OVERVIEW.md),
[`PURPOSES.md`](./docs/PURPOSES.md) (the purpose-bytes registry, A-1/X-2), and
[`WIRE-FORMAT.md`](./docs/WIRE-FORMAT.md) (the normative `aethel-plp-1` wire codec, A-4).
Each of the pre-existing files was reviewed against this README (P3-05, 2026-08-26) and
carries inline markers wherever it describes a credential-issuance layer, hardware target,
or parameter level that isn't actually shipped — read the editorial note at the top of each
file first.

## Contributing

See [`CONTRIBUTING.md`](./CONTRIBUTING.md).

## Maintainer and Support

Ed Johnson is the named maintainer. This is a best-effort, single-maintainer project — see
[`STABILITY.md`](./STABILITY.md) for the release cadence and support posture, and
[`SECURITY.md`](./SECURITY.md) to report a vulnerability.

## License

Apache-2.0.

## References

- [NIST FIPS 203: ML-KEM](https://csrc.nist.gov/pubs/fips/203/final)
- [NIST FIPS 204: ML-DSA](https://csrc.nist.gov/pubs/fips/204/final)

---

## The 0x307 crate family

`aethel-core` is one of six open-source crates from [0x307](https://0x307.com/crates), held to one
audit and stability standard.

| Crate | Tier | What it does |
|---|---|---|
| [pqc-sig](https://crates.io/crates/pqc-sig) | Production | ML-DSA, SLH-DSA and FN-DSA signatures (FIPS 204/205/206) |
| [pqc-kem](https://crates.io/crates/pqc-kem) | Production | ML-KEM (FIPS 203), the X25519 + ML-KEM-768 hybrid, X-Wing, and sealed boxes |
| [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 |
| [aethel-sdk](https://crates.io/crates/aethel-sdk) | Preview | The SDK over aethel-core, and the place to start |
| [aethel-vault](https://crates.io/crates/aethel-vault) | Preview | Agent-held wallet: policy-gated x402 / EIP-3009 signing with ML-DSA-65 spend records |
| [pqc-privacy](https://crates.io/crates/pqc-privacy) | Lab | Research bundle, kept off every identity and payment path |

**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.

**Runnable examples:** [0x307/examples](https://github.com/0x307/examples), one program per
crate, pinned to the published versions.

**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
[SECURITY.md](https://github.com/0x307/aethel-core/blob/main/SECURITY.md). Versioning and yanks:
[STABILITY.md](https://github.com/0x307/aethel-core/blob/main/STABILITY.md).