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

<crate>/doc/sca/countermeasures/<algo>.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/

<crate>/doc/

Each crate owns its papers/, analysis/, sca/, specs/. The workspace-level doc/ is for shared Sphinx config + cross-crate infra runbooks.

<crate>/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 todaytarget per Tier item.

Tier item naming

T<n>-<id> (e.g. T1-A, T2-D, T4-A)

The leading T<n> 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 <crate>/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

<crate>/doc/sca/biblio.bib, mirrored by PDF in <crate>/doc/papers/

Key convention: <author><year>_<topic> (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 <crate>_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 <crate>/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 <crate>/doc/papers/<key>.pdf   (key = author<year>_topic)
   3. Add bib entry to <crate>/doc/sca/biblio.bib
   4. Add a Tier item (T<n>-<id>) to the relevant
      <crate>/doc/sca/countermeasures/<algo>.rst
        │
        ▼
   5. Implement the countermeasure in <crate>/src/…
   6. Bump the asm-branch-count expectation in
      <crate>/doc/sca/countermeasures/<algo>.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 <crate>/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 (workspace), quantica/README.md, arcana/README.md

The README chapter contract

doc/TOC.md

The threat model & countermeasure plan for a crate

<crate>/doc/sca/index.rst → individual chapters

The bibliography for either crate

<crate>/doc/sca/biblio.bib (source-of-truth) + biblio.rst (rendered)

The PDFs of cited papers

<crate>/doc/papers/<key>.pdf (<key> 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

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 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 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 <crate>/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.