# Security Maintenance Process — krypteia This document describes **how the krypteia workspace is maintained for security**. It is the orientation page for any developer working on the project (whether on the post-quantum side `quantica` or the classical side `arcana`) and it is the canonical reference for the **common directives**, the **shared skills**, and the **lifecycle** that keep the workspace coherent and evaluation-ready across multiple parallel sessions. ## 1. Mission and target The krypteia workspace is being prepared for a **lab-class third-party evaluation / certification** of its cryptographic implementations. Both crates target the same evaluation: | Crate | Scope | |------------|------------------------------------------| | `quantica` | Post-quantum: ML-KEM, ML-DSA, SLH-DSA | | `arcana` | Classical: RSA, ECDSA/ECDH, EdDSA, X25519/X448, AES, MACs, hashes | The intended evaluation profile assumes a **moderate-effort attacker** in a 25-35 person-day window. Both crates must therefore share the same threat-model assumptions, the same verification methodology, the same documentation skeleton, and the same paper-trail discipline. ## 2. Three pillars — veille, doc, code The maintenance process rests on three interlocking activities: ``` ┌───────────────────────┐ │ VEILLE │ │ literature review, │ │ new attacks, new CMs │ └─────┬─────────────┬───┘ │ │ feeds │ │ triggers ▼ ▼ ┌──────────────────┐ ┌───────────────────────┐ │ DOC │ │ CODE │ │ threat model, │◄┤ implementation + │ │ countermeasures, │ │ countermeasure + │ │ bibliography │►│ verification │ └──────────────────┘ └───────────────────────┘ ``` * **Veille** → identifies new attacks and refines the threat model. * **Doc** → records the threat model, the countermeasures, and the reasoning. Updated **before** code, so it is also a roadmap. * **Code** → implements the documented countermeasures, verified by ctgrind and dudect; the asm-level branch counting is the day-to-day CT regression indicator. Dropping any one of the three produces brittle code: code without veille is one paper away from being broken; code without doc is unauditable; doc without code is empty. ## 3. The shared skill — `crypto-research` A single skill drives all three pillars: `~/.claude/skills/crypto-research/`. It applies to both crates and both sessions (one per crate). Its three workflows codify the project-wide discipline: | Workflow | Reference file | When to use | |------------|---------------------------------------------|----------------------------------------------| | Veille | `references/veille.md` | "What's new on X?" / "is Y still safe?" | | Implementation | `references/impl-from-paper.md` | "Implement X from spec / paper" | | Audit | `references/sca-audit.md` | "Is this constant-time?" / "audit this" | All three workflows share `references/sources.md` — the **canonical catalog** of where to fetch primary material: * **IACR ePrint** (`https://eprint.iacr.org/`) — first stop for any crypto topic. * **TCHES** (`https://tches.iacr.org/`) — premier venue for SCA, fault, hardware. CHES papers ≥ 2018 live here. * **Systems-security venues** — USENIX, S&P, CCS, NDSS for microarchitectural attacks. * **NIST FIPS / IETF RFCs / public test corpora** — the normative layer. The skill enforces **primary-source citation** (ePrint ID, venue+year, spec section) — no Wikipedia, no blog posts as primary evidence. ## 4. Common directives These rules apply identically on both sides of the workspace: ### 4.1 Code | Directive | Where it lives | Notes | |---|---|---| | **Pure Rust, zero external crates** | `Cargo.toml` (each crate); only workspace-local `silentops` is allowed | `core` + `alloc` (and optionally `std`); no external dep is acceptable. | | **Constant-time on the data path** | `arcana/src/ecc/curve.rs`, `quantica/src/ml_dsa/masked.rs`, … | No secret-dependent branches, no secret-indexed memory, no variable-latency ops on secrets. Validated by ctgrind + dudect. | | **`silentops` for CT primitives** | `silentops/src/ct/` | Single audit surface for `ct_select`, `ct_eq`, `ct_zeroize`, `ct_copy`. Architecture-specific asm backends select at compile time. Both crates depend on it. | | **`silentops::verify` for dudect** | `silentops/src/verify/` | Statistical timing test (Reparaz-Balasch-Verbauwhede 2017). | | **`silentops::ct_grind` for ctgrind** | `silentops/src/ct_grind/` | Valgrind memcheck client requests (`poison`/`unpoison`). | | **Tier-based hardening plan** | `/doc/sca/countermeasures/.rst` | T1 = active vuln → critical; T2 = standard hardening; T3 = verification tooling; T4 = deferred (beyond current evaluation scope); T5 = documentation pass. | | **Bare-metal target validation** | `tools/stack-sizes.sh` | All quantica primitives compile clean for `thumbv6m`, `thumbv7em`, `thumbv8m.main`, `riscv32imc-unknown-none-elf`. arcana planned to follow once the caller-buffer refactor lands. | | **Three Cargo profiles** | workspace `Cargo.toml` | `release` (opt-level=2, CT-safe), `release-embedded` (opt-z + abort, asm CT backends), `release-bench` (opt-level=3, **not CT-safe**). | | **`core::hint::black_box` shielding** | wherever a CT mask is derived from a secret | Without it, LLVM (rustc 1.84+) recovers branches over `(x & mask) \| (y & !mask)`. The asm CT backends in `silentops` are the stronger fix. | ### 4.2 Documentation | Directive | Where it lives | Notes | |---|---|---| | **README structure contract** | doc/TOC.md | 17 mandatory H2 chapters in fixed order, plus per-chapter sub-section contract. Both `quantica/README.md` and `arcana/README.md` must follow it. | | **Per-crate ownership of `doc/`** | `/doc/` | Each crate owns its papers/, analysis/, sca/, specs/. The workspace-level `doc/` is for shared Sphinx config + cross-crate infra runbooks. | | **`/doc/sca/` annex skeleton** | identical structure on both sides | `index.rst` + `threat_model.rst` + `primitives.rst` + `countermeasures/*.rst` + `verification.rst` + `biblio.{bib,rst}`. Each chapter has a "Code path summary" table mapping `today` ↔ `target` per Tier item. | | **Tier item naming** | `T-` (e.g. `T1-A`, `T2-D`, `T4-A`) | The leading `T` matches the item's tier (T1 = active vulnerability, T2 = hardening, T3 = verification tooling, T4 = deferred). Identifiers are stable; renaming breaks cross-references in source-code rustdoc, in `/doc/sca/countermeasures/*.rst` and in this file. | | **Apache-2.0 license** | every README footer + per-crate `Cargo.toml` | Single line `Apache-2.0.` per the TOC contract. | | **Bibliographic discipline** | `/doc/sca/biblio.bib`, mirrored by PDF in `/doc/papers/` | Key convention: `_` (e.g. `adomnicai2021_fixslicing_aes`). The PDF file-stem matches the bib key, so the bib search ↔ the paper search are the same. | | **HTML doc pack via `gendoc.sh`** | gendoc.sh | Three modes: `all`, `quantica`, `arcana`. Renders Sphinx + rustdoc into `htmldoc/`. Each mode is **self-contained** (a quantica reader does not need arcana, and vice versa). | ### 4.3 Veille | Directive | Notes | |---|---| | **Continuous veille is mandatory** | A new SCA paper that touches a primitive we ship is an audit trigger, not a deferred item. | | **Primary-source citations only** | ePrint ID / venue+year / spec section. No Wikipedia, no blog posts as primary evidence. | | **Veille discipline for test corpora** | A Wycheproof / CAVP / ACVP refresh that adds vectors for a primitive we implement is a regression-test trigger — import vectors, rerun suite, note corpus version in the changelog. Missing a corpus update is the same class of risk as missing an attack paper. | ### 4.4 Verification | Method | Coverage | Owner | |---|---|---| | **ctgrind** (Valgrind memcheck) | Control-flow + memory-access CT (host CI). | Driver in `quantica_bench/src/bin/ctgrind.rs`; shared infrastructure in `silentops::ct_grind`; runbook in doc/infra/ctgrind.md. arcana harness mirrored as `arcana_bench` (T3-A, planned). | | **dudect** (statistical timing) | Microarchitectural timing on target hardware. | Shared `silentops::verify` module; per-crate harnesses under `_bench/examples/`. | | **release-asm branch counting** | Day-to-day CT regression indicator. | Manual `cargo rustc --release ... --emit=asm` + grep for `j(e\|ne\|z\|nz\|l\|le\|g\|ge\|a\|b)` in functions of interest. Documented expected counts in each `/doc/sca/countermeasures/*.rst`. | | **Wycheproof + CAVP + ACVP** | Functional + edge-case + negative testing. | Per-crate `tests/` directories; cumulative count tracked in each README's "Test validation" chapter. | | **Bare-metal cross-build** | Catch `no_std` / heap-creep regressions early. | `tools/stack-sizes.sh` wraps it on the quantica side. | ## 5. Per-crate ownership The workspace is **two parallel sessions** that share the rules above but maintain their own state. The split is deliberate so that unrelated work can advance in parallel without merge conflicts. ``` krypteia/ ├── doc/ ← workspace shared (this is what `gendoc.sh` builds) │ ├── TOC.md ← README structure contract (canonical) │ ├── conf.py / Makefile ← Sphinx config │ ├── index_*.rst ← TOC roots (mode-specific) │ ├── infra/ ← cross-cutting runbooks (ctgrind, gitea, …) │ ├── _gen/ ← gendoc-staged READMEs (gitignored) │ ├── quantica/ ← gendoc-staged crate doc (gitignored) │ └── arcana/ ← gendoc-staged crate doc (gitignored) │ ├── quantica/ ← post-quantum side (own session) │ ├── README.md ← follows doc/TOC.md │ ├── doc/ ← crate-owned source-of-truth │ │ ├── papers/ ← cited PDFs (file-stem = bib key) │ │ ├── analysis/ ← memory / timing notes │ │ ├── specs/ ← FIPS 203/204/205 │ │ └── sca/ ← threat model + countermeasures + biblio │ ├── src/ │ ├── tests/ │ └── examples/ │ ├── arcana/ ← classical side (own session) │ ├── README.md ← follows doc/TOC.md │ ├── doc/ ← crate-owned source-of-truth (mirrors quantica) │ │ ├── papers/ │ │ ├── analysis/ │ │ └── sca/ ← same skeleton as quantica/doc/sca/ │ ├── src/ │ ├── tests/ │ └── examples/ │ ├── silentops/ ← shared CT primitives + dudect + ctgrind ├── quantica_ffi/ ← C FFI for quantica ├── arcana_ffi/ ← C FFI for arcana ├── quantica_bench/ ← memcheck + ctgrind drivers (quantica) ├── tools/ ← stack-sizes.sh, ctgrind.sh, … └── gendoc.sh ← unified HTML doc-pack generator ``` **What's per-crate:** code, tests, examples, the README, the `doc/` sub-tree. **What's workspace-shared:** the rules in this document, the Sphinx config, the `gendoc.sh` generator, the `silentops` crate, the `tools/` scripts, the `doc/TOC.md` README contract, and the `doc/infra/` cross-cutting runbooks. A change to a per-crate concern stays in that crate's session. A change to a shared concern goes through this workspace-level `doc/` or `tools/` directory. ## 6. Lifecycle of a security item The flow from "we found a paper / a CVE / an evaluator comment" to "the countermeasure is shipped and verified" is: ``` 1. Veille run (skill: crypto-research) │ ▼ 2. Add paper to /doc/papers/.pdf (key = author_topic) 3. Add bib entry to /doc/sca/biblio.bib 4. Add a Tier item (T-) to the relevant /doc/sca/countermeasures/.rst │ ▼ 5. Implement the countermeasure in /src/… 6. Bump the asm-branch-count expectation in /doc/sca/countermeasures/.rst 7. Add ctgrind + dudect harness entries │ ▼ 8. Update Code path summary table from `today` to `target` for the just-shipped item 9. Append a row to /doc/sca/index.rst change log 10. Commit, ./gendoc.sh validates the pack ``` Steps 1-4 are **doc-only** and serve as a roadmap entry; the item sits as `planned` until the code lands. Steps 5-7 are the implementation. Steps 8-10 close the loop. ## 7. Where to find what | You want to know… | Look at… | |---|---| | The big picture of either crate | [README.md](../_gen/root_overview.md) (workspace), `quantica/README.md`, `arcana/README.md` | | The README chapter contract | doc/TOC.md | | The threat model & countermeasure plan for a crate | `/doc/sca/index.rst` → individual chapters | | The bibliography for either crate | `/doc/sca/biblio.bib` (source-of-truth) + `biblio.rst` (rendered) | | The PDFs of cited papers | `/doc/papers/.pdf` (`` matches bib) | | The shared CT primitives | silentops/src/ct/ | | How to run ctgrind | doc/infra/ctgrind.md | | How to build the HTML pack | gendoc.sh (`./gendoc.sh [all|quantica|arcana]`) | | The cross-cutting tooling | tools/ | | The veille / impl / audit workflow itself | `~/.claude/skills/crypto-research/` | ## 8. Vulnerability reporting The krypteia v0.1 line ships publicly on [codeberg.org/cslashm/krypteia](https://codeberg.org/cslashm/krypteia) and crates.io (`silentops`, `memory`, `quantica`, `arcana`). The disclosure process below applies to every published crate. ### 8.1 Reporting channel Send a **private** report to **`cedric.mesnil@pm.me`** before opening any public Codeberg issue or PR. Reports may be encrypted to the maintainer's GPG key (fingerprint published in the maintainer's Codeberg profile when available); plain email is also accepted. A report should include: * a clear description of the issue, * the affected crate(s) and version range (or git commit if reporting against `main`), * a proof-of-concept (PoC) or reproducer if available, * an assessment of impact (information disclosure, timing oracle, fault injection vector, …), * whether the reporter wishes to be credited in the fix and under which name. Maintainer is **`cedric.mesnil@pm.me`** for v0.1. The roster will expand in v0.2 once additional reviewers join. ### 8.2 Initial response * **Acknowledgment** within **5 working days** of receipt. * **Triage verdict** (in-scope / out-of-scope, severity estimate) within **15 working days**. A heads-up that the report is being looked at will land within the first window even if the verdict requires more time. ### 8.3 Coordinated disclosure window The default embargo window is **90 calendar days** from acknowledgment to public disclosure, mirroring the industry norm (Google Project Zero, CERT/CC). Within that window: * the maintainer prepares a fix on a private dev branch; * a CVE is requested via the [MITRE CNA process](https://cveform.mitre.org/) if the finding meets CVE criteria; * the reporter is kept informed of the fix timeline; * the patch lands in a tagged release (`v0.X.Y` patch bump or `v0.X+1.0` minor bump depending on impact) AT the end of the embargo, NOT before. The window can be **shortened** by mutual agreement (e.g. for a trivially-exploitable issue where a partial fix is already public) and **extended** if the fix has significant cross-crate impact and needs additional validation time. The maintainer will not unilaterally extend past 120 days. ### 8.4 Public advisory When the patched release ships, the maintainer publishes a Codeberg security advisory describing the issue, the affected versions, the CVE (if assigned), the fix commit, and credit to the reporter (unless anonymity is requested). ### 8.5 Out of scope * Findings against unmaintained branches (only `main` and the latest tagged release receive fixes — older releases are end-of-life). * Findings that require an attacker model strictly beyond the per-crate threat model documented in `/doc/sca/threat_model.rst` (e.g., a physical attacker with EM-probe access on an algorithm whose SCA chapter explicitly defers DPA hardening to T4 in v0.1) — these are filed as **roadmap items** in the relevant tier, not as vulnerabilities. The maintainer will redirect such reports to the appropriate roadmap row. * Reports against `*_ffi`, `*_wasm`, `*_bench`, `tests-embedded`, `tools/vector-runner`, and the placeholder crates `arcana_bench` / `arcana_wasm`. These ship as `publish = false` workspace-internal previews in v0.1; the v0.2 release that publishes them will extend this policy. ### 8.6 Safe harbour Good-faith vulnerability research conducted under this policy will not trigger any legal action by the maintainer. The maintainer agrees not to pursue civil claims, criminal referrals, or DMCA takedowns against reporters who comply with the disclosure window above. ## 9. License Apache-2.0.