diff --git a/.claude/blackboard.md b/.claude/blackboard.md index 7095dd60..884a4b23 100644 --- a/.claude/blackboard.md +++ b/.claude/blackboard.md @@ -1,3 +1,16 @@ +## 2026-09-25 (2) — encryption: Argon2 KDF + envelope behind a default-on `kdf` feature + +- `crates/encryption`: `argon2` is optional; `kdf = ["dep:argon2"]`, `default = ["kdf"]`, + `wasm-bindings` implies `kdf`. `kdf`, `envelope` and the root `seal/open/KdfParams/EnvelopeError` + re-exports are gated. +- Why: the only in-tree consumer (OGAR `ogar-encryption`) owns its KDF + envelope on argon2 0.6 + (the AdaWorldAPI/password-hashes fork) and needs only aead/hash/sign/channel here. With + `default-features = false` argon2 0.5 is no longer compiled into it. +- Verified: `cargo test -p encryption` green with default, `--no-default-features` + (12 + 28, argon2 absent from `cargo tree`), and `--features wasm-bindings`; clippy + `-D warnings` clean with no default features; wasm32 check green. +- Loose end: OGAR moves its wasm bindings onto its own argon2-0.6 envelope (separate PR). + ## 2026-09-25 — U64x8::transpose8: the one physical routing step argon2 needs `U64x8::transpose8([U64x8; 8]) -> [U64x8; 8]`, `out[i]` lane `j` == `rows[j]` lane `i`, on all six realizations. AVX-512: 8 unpack + 16 `vshufi64x2` (24). AVX2: four 4×4 blocks, `unpack` + `vperm2i128`. NEON / wasm: 32 `vtrn1q`/`vtrn2q` or `i64x2.shuffle` on 2×2 blocks. Scalar / nightly: the index map. diff --git a/crates/encryption/Cargo.toml b/crates/encryption/Cargo.toml index b3c6b1e0..8415c04e 100644 --- a/crates/encryption/Cargo.toml +++ b/crates/encryption/Cargo.toml @@ -14,7 +14,11 @@ crate-type = ["rlib", "cdylib"] [dependencies] # RustCrypto suite — all pure Rust, all compile to wasm32-unknown-unknown. -argon2 = { version = "0.5", default-features = false, features = ["alloc"] } +# Behind the default `kdf` feature: the only in-tree consumer +# (ogar-encryption) carries its own Argon2 KDF + envelope on argon2 0.6 and +# builds this crate with `default-features = false`, so argon2 0.5 is not +# compiled into it at all. +argon2 = { version = "0.5", default-features = false, features = ["alloc"], optional = true } chacha20poly1305 = { version = "0.10", default-features = false, features = ["alloc"] } ed25519-dalek = { version = "2", default-features = false, features = ["alloc", "zeroize"] } sha2 = { version = "0.10", default-features = false } @@ -36,5 +40,7 @@ wasm-bindgen = { version = "0.2", optional = true } getrandom = { version = "0.2", features = ["js"] } [features] -default = [] -wasm-bindings = ["dep:wasm-bindgen"] +default = ["kdf"] +# The Argon2id KDF and the seal/open envelope built on it. +kdf = ["dep:argon2"] +wasm-bindings = ["dep:wasm-bindgen", "kdf"] diff --git a/crates/encryption/src/lib.rs b/crates/encryption/src/lib.rs index 6bdd64bc..74c8fc7d 100644 --- a/crates/encryption/src/lib.rs +++ b/crates/encryption/src/lib.rs @@ -67,15 +67,18 @@ pub mod aead; pub mod channel; +#[cfg(feature = "kdf")] pub mod envelope; pub mod hash; pub mod hkdf_sha384; +#[cfg(feature = "kdf")] pub mod kdf; pub mod sign; #[cfg(feature = "wasm-bindings")] pub mod wasm; +#[cfg(feature = "kdf")] pub use envelope::{open, seal, EnvelopeError, KdfParams}; /// Fill `buf` from the platform CSPRNG (`getrandom`; on wasm32 this is