Changelog
All notable changes to this project are documented in this file.
The format is based on Keep a Changelog 1.1.0,
and the workspace follows Semantic Versioning 2.0.0.
The pre-1.0 line ships breaking changes in minor version bumps
(0.1.x → 0.2.0); patch versions remain backwards-compatible.
Unreleased
Continued T1 / T2 SCA hardening per the Roadmap chapters of
quantica/README.mdandarcana/README.md.Veille-trigger formalisation — record the veille window in
CHANGELOG.mdat every release bump (<window dates>; items reviewed: …; items folded into release: …) so the discipline becomes auditable.Shake out the ported GitHub Actions workflows on the first runs (runner-image deltas: package availability, preinstalled toolchain versions, Pages deployment permissions).
benchbin-name collision betweenquantica_benchandarcana_bench— verify the cargo warning is gone at the next bump and rename one[[bin]]if not.
[0.2.0] - 2026-07-29
The second pre-1.0 cut. Highlights: the shared krypteia-tessera hash
crate (Keccak / SHA-2 now live in exactly one place), a deliberate
three-tier quantica API (facade / hazmat / internal), pre-hash
signatures (HashML-DSA / HashSLH-DSA), the SLH-DSA SHA-2 parameter sets,
conformant external SLH-DSA sign/verify, and the first crates.io
publication of the C-ABI (*_ffi) and WebAssembly (*_wasm) bindings.
Embedded: the memory self-alloc allocator now builds on no-CAS targets
(Cortex-M0, ESP32-C3). The public Rust API remains pre-1.0 and
semver-unlocked.
Changed
Project hosting migrated from Codeberg to GitHub. Codeberg amended its Terms of Service (effective 2026-07-22) to bar projects “that consist predominantly of code written by generative AI tools”. Krypteia is developed in tandem with an AI assistant and documents that fact —
CONTRIBUTING.mdmandates aCo-Authored-By:trailer naming the model and context window on every AI-assisted commit, precisely so the Git history stays an auditable record of which tool produced which line. Rather than obscure that trail or argue the threshold, the project moved: the canonical repository is now https://github.com/cslashm/krypteia, CI runs on GitHub Actions (.github/workflows/, ported from.forgejo/), and the documentation pack is served from GitHub Pages. The doc domain (https://krypteia-rs.dev) is unchanged. The Codeberg repository is archived read-only so the links recorded in the published v0.1 crate metadata keep resolving.quantica API re-tiered before the v0.2 publish (breaking vs
0.1, allowed on the pre-1.0line and reserved by the v0.1 README). The public surface now has three deliberate tiers:Facade (guaranteed): the typed
MlKem/MlDsa/SlhDsaentry points, key/signature wrappers,params,rng,prehash,secret.hazmat(new feature, off by default): the expert building-block tier — byte encodings, samplers, Decompose/hints, the SLH-DSA address/tweakable-hash surface, the raw-slice algorithm facades (ml_kem::kem,ml_dsa::dsa,slh_dsa::slh) and the deterministic*_internalCAVP entries. No stability, misuse-resistance or side-channel promise on this tier — it may change in any release. The KAT suites that drive the deterministic entries (ml_kem_kat,wycheproof,kat_extra) andkrypteia-quantica-ffiopt in explicitly.Internal (
pub(crate)):ntt, the unauthenticatedkpkecomponent, WOTS+/XMSS/FORS/hypertree, the masking/shuffling countermeasures and the SHA-3 shims — no longer reachable, no longer a compatibility surface. This also removes the accidental exposure asymmetry between the ML-KEM and ML-DSA countermeasure modules.
arcana assumes its public arithmetic layer (additive): the SEC1 helpers are lifted to
ecc::{compress_pubkey, decompress_pubkey}(both validate on-curve internally), andecc::field/ecc::curve/rsa::bigintare now documented as a deliberate expert tier with an explicit contract — CT split (scalar_mul_pointandpoint_doublestraight-line/CT;point_add/double_scalar_mulvariable-time, public values only), the no-validation rule on raw point ops, and the variable-time warning onBigInt. Stability on this layer is best-effort pre-1.0.
Added
arcana::ecc::ed448— full Ed448 (RFC 8032 §5.2). Edwards448 “Goldilocks” over GF(2⁴⁴⁸−2²²⁴−1), cofactor 4, SHAKE256-based hashing, 57-byte keys and 114-byte signatures. All three modes — pure Ed448, Ed448ctx (context string) and Ed448ph (prehash) — verified byte-exact against the RFC 8032 §7.4 / §7.5 test vectors. The secret-dependent scalar multiplication is constant-time from the first commit (ct_selectdouble-and-add, mirroring the Ed25519 path). Closes the v0.1 Ed448-stub known limitation.krypteia-tessera— new shared hash crate.no_std+alloc, zero runtime dependencies; the single home for every hash in the workspace. SHA-2 (224/256/384/512/512-224/512-256), SHA-3 (224/256/384/512), SHAKE128/256, cSHAKE128/256, MGF1, SHA-1, RIPEMD-160 and BLAKE2b/2s, behind two minimal traits —Digest(OUTPUT_LEN/BLOCK_LEN) andXof. Every family is KAT-validated; hash compression is deliberately not constant-time (public-data inputs; secret-dependent comparison / zeroization stays insilentops).SLH-DSA SHA-2 parameter sets (FIPS 205 §11.2). Six new parameter sets —
Sha2_128s/f,Sha2_192s/f,Sha2_256s/f— alongside the existing SHAKE sets, behind aTweakableHashabstraction on theParamstrait (ShakeFamily/Sha2Family). The SHA-2 instantiation uses SHA-256 for F/PRF and the compressed 22-byte ADRSᶜ, with SHA-256 at category 1 and SHA-512 at categories 3/5 for H_msg/PRF_msg/T_ℓ/H (FIPS 205 §11.2). Byte-exact against the NIST ACVP keyGen/sigGen/sigVer SHA-2 vectors.Pre-hash signatures — HashML-DSA & HashSLH-DSA. New
sign_prehash/verify_prehashon both schemes (FIPS 204 Alg 4/5, FIPS 205 Alg 23/25) with a sharedPreHashselector covering the full approved set (SHA-224/256/384/512, SHA-512/224, SHA-512/256, SHA3-224/256/384/512, SHAKE128 → 256 bits, SHAKE256 → 512 bits). The OID DER byte strings are verified against NIST.FIPS.204 §5.4 / Algorithm 4 (full 11-byte TLV). Validated byte-exact against the ACVP pre-hash sigGen/sigVer groups, driven through the public typed API.C-ABI and WebAssembly bindings published on crates.io, under the
krypteia-*namespace like every other published crate:krypteia-quantica-ffi,krypteia-arcana-ffi,krypteia-tessera-ffi(staticlib + cdylib + hand-written C headers) andkrypteia-quantica-wasm,krypteia-arcana-wasm,krypteia-tessera-wasm(wasm-bindgen) flip frompublish = falseto published, each exercised by a runtime harness (the Ctest_*.csuites viatools/ffi-tests.sh, and the Node wasm-bindgen tests). Their directories keep the bare names (quantica_ffi/) and each pins[lib] nameto the bare form, so the built artefacts remainlibquantica_ffi.{a,so}and the C headers, link recipes andwasm-packinvocations are unchanged. As pre-1.0crates their ABI/JS surface may still change in a minor release.
Changed
BREAKING — SLH-DSA public
sign/verifynow implement the FIPS 205 external algorithm. They take a context stringctxand apply the domain-separation wrapM′ = 0x00 ‖ len(ctx) ‖ ctx ‖ Mbefore the internal algorithm, so signatures interoperate with conformant external SLH-DSA verifiers; previously they signed the raw message via the internal algorithm (non-conformant). This changes the signature bytes for a given (key, message) — a deliberate conformance break, acceptable pre-1.0(like the 256f fix). Passctx = b""for the no-context case. ML-DSA already exposed the externalctxpath. AddsSlhDsaError::ContextTooLong(raised when|ctx| > 255).BREAKING — the FIPS internal functions are now crate-private. ML-DSA
dsa::{keygen,sign,verify}_internaland SLH-DSAslh::slh_{keygen,sign,verify}_internalarepub(crate), and the redundantMlDsa/SlhDsa*_internalinherent methods are removed: the only public way to sign is the conformant external path. The internal functions bypass domain separation and were a public footgun; a designed low-level / custom-M′wrapper may be re-introduced on real demand (roadmap). ML-KEM internals are unchanged (a KEM has noM′/ctx layer). The ACVP internal-interface vectors moved to in-crate#[cfg(test)]KATs (ml_dsa::acvp_internal,slh_dsa::acvp_internal).arcana hash functions relocated into
krypteia-tessera.arcana::hashis now a thin façade that re-exports the shared types; the per-algorithm module paths (arcana::hash::sha256::Sha256, …) and arcana’s publicHasher/Xoftraits are unchanged, bridged to the crate by two blanket impls (impl<T: tessera::Digest> Hasher for T,impl<T: tessera::Xof> Xof for T). No algorithm or behavioural change: the implementations were moved verbatim and re-validated against the unchanged NIST CAVP hash KATs, NIST ACVP and Google Wycheproof corpora (arcana lib 291/291, CAVP 11/11, ACVP 16/16, Wycheproof 6/6). Removes ~2.3k lines of SHA-2 / SHA-3 duplication on the arcana side.quantica Keccak relocated into
krypteia-tesseratoo.quantica::sha3is now a shim re-exportingtessera::sha3::KeccakState(+ the FIPS 202 rate constants); the ML-KEM / ML-DSA / SLH-DSAsha3wrappers and call sites are unchanged. With this, Keccak exists in exactly one place in the workspace. Both cores are plain, data-oblivious Keccak-f[1600], so no side-channel property changes; an A/B throughput harness (quantica_bench keccak_bench) measured the two at parity. Byte-exact: ML-KEM / ML-DSA KAT, SLH-DSA KAT (incl 256f), and the M0thumbv6mno_std build all green on the shared core.
Removed
Third-party
kat_MLKEM_*.rspvectors (from post-quantum-cryptography/KAT) and their tests. Their ML-KEM key derivation diverges from the authoritative NIST ACVP vectors — our ACVP-validatedkeygen_internalreproduces theirpkwith neither(d, z)nor(z, d)— so they are not a reliable FIPS 203 oracle (likely a pre-final Kyber round-3 derivation, missing the FIPS 203G(d ‖ k)domain byte). ML-KEM conformance remains fully covered by the NIST ACVP suite and Wycheproof. Full rationale is documented inquantica/tests/kat_extra.rs.
Fixed
SLH-DSA-SHAKE-256f produced non-conformant signatures. The
idx_treemask computed1u64 << (H - H'), which overflows for the 256f parameter set (H - H' = 64): in release builds the shift wraps to1 << 0, forcingidx_treeto 0 and yielding signatures that are self-consistent but non-conformant to FIPS 205. Fixed at both the sign and verify sites (quantica/src/slh_dsa/slh.rs); the previously#[ignore]-d 256f siggen/sigver KATs now pass. Only 256f was affected (every other parameter set hasH - H' ≤ 63).memoryself-alloc now builds on no-CAS embedded targets. Theself-allocspin-lock usedAtomicBool::compare_exchange_weak, whichcoredoes not expose on targets without hardware CAS, sokrypteia-memory --features self-allocfailed to compile (E0599) on Cortex-M0 (thumbv6m) and the ESP32-C3-class RV32imc— the M0/ESP32-C3 support advertised since v0.1. Replaced with a per-target interrupt-masking critical section (ARMPRIMASK, RISC-Vmstatus.MIE); CAS-capable targets keep the lock-free spin-lock. Branch-free asm, no public API change.
0.1.0 - 2026-06-12
First public release of the krypteia cryptographic workspace.
Four crates ship on crates.io under the krypteia-* namespace:
krypteia-silentops,
krypteia-memory,
krypteia-quantica, and
krypteia-arcana. Apache-2.0
across the workspace.
The
krypteia-*namespace prefix was adopted because the bare namesmemoryandarcanawere already taken on crates.io by third parties at first publish attempt. Every published crate sets[lib] name = "<short>"so consumersuse silentops::*,use memory::*,use quantica::*,use arcana::*exactly as they would have with the bare names; the only place the namespaced name appears is theCargo.toml[dependencies]line and on crates.io / docs.rs URLs.
Added — quantica (post-quantum cryptography)
ML-KEM (FIPS 203, Key Encapsulation Mechanism) — pure-Rust implementation, all parameter sets (
MlKem512,MlKem768,MlKem1024), typed Zeroize-on-Drop key wrappers.ML-DSA (FIPS 204, Digital Signature Algorithm) — pure-Rust implementation, all parameter sets (
MlDsa44,MlDsa65,MlDsa87), with per-iteration mask refresh in the rejection loop (T1-A), Hermelink 2025/276 audit annex onml_dsa::masked(T1-B).SLH-DSA (FIPS 205, Stateless Hash-Based Signatures) — pure-Rust implementation, SHAKE variants (
Sha2-128f/s,Shake-128f/s,Shake-192f/s,Shake-256f/s), with FORS recompute-and-compare redundancy (T1-C, anti-grafting Castelnovi 2018), full-tree streaming FORS sign (T1-D, anti-template Kannwischer 2018), digest → FORS-indices integrity check (T1-E, anti-fault), and a constant-timefors_pk_from_sig_ct(T1-F).First-order DPA masking + shuffled NTT on both ML-KEM and ML-DSA secret paths (
sca-protectedCargo feature, on by default).Iterative BDS FORS treehash (256 KiB → 448 B per call) and streaming signature output (one allocation,
*_intovariants throughout) to fit the M0 baseline RAM budget.Seven RAM-reduction features for ML-DSA bringing the M0 Sign stack from 179 KB → ~17 KB peak.
no_stdbuild target support; cross-compile recipes inquantica/README.mdforthumbv6m-none-eabi,thumbv7em-none-eabihf,thumbv8m.main-none-eabihf,riscv32imc-unknown-none-elf.
Added — arcana (classical cryptography)
RSA — PKCS#1 v1.5, PSS (with
Sha256/Sha384/Sha512/ SHA-3 family digests), OAEP.ECDSA / ECDH — NIST P-256 / P-384 / P-521, SECG
secp256k1, Brainpool families (P-256 / P-384 / P-512). CT hardening onscalar_mul_point(Montgomery ladder, branchlesspoint_add_ct,black_boxshielding onfield_*masks).EdDSA — Ed25519 (RFC 8032 §5.1).
ECDH — X25519 and X448.
AES — 128 / 192 / 256 with ECB, CBC, CTR, GCM, CCM (RFC 3610), XTS (IEEE 1619) modes.
ChaCha20 and ChaCha20-Poly1305 (RFC 8439), XChaCha20-Poly1305 (24-byte nonce extension).
DES / 3DES (legacy use only — flagged in the per-crate Known limitations).
Hashes: SHA-1, SHA-2 family (224 / 256 / 384 / 512 / 512-truncated), SHA-3 family (224 / 256 / 384 / 512 + SHAKE128/256, cSHAKE128/256), BLAKE2b / BLAKE2s, RIPEMD-160.
MACs: HMAC, CMAC.
Optional RustCrypto trait bridges (
digest,cipher,signature) behind therust-crypto-traitsCargo feature.no_stdbuild target support.
Added — silentops (side-channel countermeasure toolkit)
Constant-time primitives —
ct::ct_eq,ct::ct_select_*,ct::ct_zeroize,ct::ct_copywith five architecture- specific inline-assembly backends gated ontarget_arch+target_feature+ Cargo feature:asm-x86_64— x86_64 inline asm;asm-aarch64— AArch64 withcsel/csinv;asm-thumbv7— ARMv7-M Thumb2 IT blocks (Cortex-M3 / M4 / M33);asm-thumbv6m— ARMv6-M no-IT branchless (Cortex-M0 / M0+);asm-riscv32— RV32I branchless (ESP32-C3 / C6 / H2).
ct_grind— Valgrind memcheck client-request helpers (poison/unpoison) with zero-cost no-op fallback on non-Linux x86_64 / aarch64 targets.verify— dudect-style timing-leakage detector (Welch t-test, std-only) refactored as a reusable library.
Added — memory (TLSF allocator)
Two allocator backends gated by Cargo feature:
os-alloc(default) — forwards to the platformmalloc/free;self-alloc— TLSF allocator over a caller-provided RAM block, single-init, nostd.
global-allocfeature for the FFI consumers (arcana_ffi, futurequantica_ffi) to register as#[global_allocator].
Added — Cross-architecture validation infrastructure (T3-A)
Workspace-internal, exercised on every push:
tools/qemu-user-tests.sh— workspace lib tests on three Linux triplets viacross+ qemu-user:aarch64-unknown- linux-gnu,armv7-unknown-linux-gnueabihf,riscv64gc-unknown-linux-gnu. Pinned tocross 0.2.5+ghcr.io/cross-rs/*:0.2.5Docker images.tools/qemu-system-tests.sh—tests-embeddedsmoke test on four bare-metal targets:riscv32imc-unknown-none-elf(ESP32-C3),riscv32imac-unknown-none-elf(ESP32-C6 / H2),thumbv6m-none-eabi(Cortex-M0, qemumicrobit),thumbv7em-none-eabihf(Cortex-M4F, qemumps2-an386).tools/qemu-vector-tests.sh+tools/vector-runner/— host↔guest semihosting vector-streaming protocol that runs validation corpora through the bare-metalvector_runnerbin without compiling vectors into the binary. Generator and consumer share the wire format viatests_embedded::protocol.Codeberg Forgejo Actions workflow (
.forgejo/workflows/qemu-cross-tests.yml) running all three layers in parallel on every push tomainand every pull request.
Added — Documentation pack and CI
Sphinx documentation pack (
gendoc.sh all) — per-crate README rendered with the per-cratedoc/sca/side-channel annex inlined as a nested TOC under each crate’s chapter VIII subsection 5; cross-crate sidebar entries forsilentopsandmemory; separate Governance sidebar group forCONTRIBUTINGandSECURITY.Continuous publish to krypteia-rs.dev via
.forgejo/workflows/doc.ymlon every push tomain.Workspace governance documents linked from the root README:
CONTRIBUTING.md— contribution policy, including the AI-assistCo-Authored-By:trailer requirement;SECURITY.md— security maintenance process and full responsible-disclosure policy (90-day coordinated disclosure window default, MITRE CNA process for CVE assignment, safe-harbour clause for good-faith research).
Conventions and workspace shape adopted in v0.1
Rust edition 2024 (MSRV
1.85) across the workspace.[workspace.package]factorisation of release metadata (license, repository, homepage, authors, version, edition, rust-version) — inherited via<field>.workspace = true.[workspace.dependencies]factorisation of inter-crate path-deps withversion = "0.1.0"on each socargo publishaccepts them.publish = falseonquantica_ffi,arcana_ffi,quantica_wasm,quantica_bench,arcana_bench,arcana_wasm,tests-embedded,tools/vector-runner— these are workspace-internal previews / placeholders; the C ABI and JS surface stabilise in v0.2.Strict branch policy enforced by
tools/hooks/pre-commit:main,master,pqc-devare read-only, dev work happens ondev/*/doc/*/infra/*/release/*branches.
Known limitations carried into v0.1
These are documented honestly so a v0.1 consumer or external reviewer can size them up before depending on the workspace:
arcana::ecc::eddsa::Ed448— stub. Full implementation deferred to v0.2 against RFC 8032 §5.2.Five
#[ignore]-d KAT tests underquantica/tests/(three ML-KEM RSP + two SLH-DSA SHAKE-256f) — root cause investigation deferred to v0.2 evaluation prep.thumbv8m.main-none-eabihfbare-metal target — wired intests-embedded/memory/mps2-an505.x,tools/qemu-system-tests.sh, and.cargo/config.toml, but currently disabled in the active matrix due to an upstreamrustc 1.96+cortex-m-rt 0.7.5linker issue that emits an empty ELF.silentops’sasm-thumbv7backend coverage is preserved via thethumbv7empath (M4F and M33 share the asm backend).45
unsafe-op-in-unsafe-fnwarnings onarcana_ffiand ~69not_unsafe_ptr_arg_derefclippy errors onquantica_ffi— edition 2024 ripple on the FFI surface. These are workspace-internal in v0.1 (publish = false) and addressed when the C ABI is reworked for v0.2.Codeberg shared-runner CI is not green for v0.1.0 — two distinct image-compat issues block the workflows on the free shared-runner pool: (a) the
cross-basedqemu-usermatrix in.forgejo/workflows/qemu-cross-tests.ymlrequires Docker-in-Docker, which the pool does not expose; (b) thedoc.ymlSphinx build callsrsync, which is not present in the runner image’s apt set. The bare-metalqemu-systemandqemu-vectormatrices use no Docker and need no additional packages, but were not exercised on the pool for v0.1.0 because the YAMLs are bundled in a single workflow with the brokenqemu-usermatrix. Local validation (./tools/qemu-{user,system,vector}-tests.sh,./tools/ctgrind.sh,./gendoc.sh all) covers the same scope the workflows would have. The v0.1.0 long-form Sphinx doc pack was deployed to Codeberg Pages manually from a local./gendoc.sh allrun, not via thedoc.ymlworkflow. Workflow migration to non-Docker tooling (qemu-user-static + binfmt-misc for the cross-arch matrix, apt-getrsyncfor the doc build) lands in v0.2.
Initial public release commit
The b31fdbd “Initial public release of krypteia” commit
(2026-03-13) seeded the public history as an orphan commit,
deliberately disconnected from earlier internal exploration
branches that referenced third-party non-public material
under NDA. All work in this CHANGELOG is reachable from that
orphan root.