Files
khadhroony-solana-project/deltas/0.2.5/pre.004.md
2026-08-19 11:29:05 +02:00

333 lines
11 KiB
Markdown

<!-- file: deltas/0.2.5/pre.004.md -->
<!-- version: 1 -->
# Delta `0.2.5-pre.004` — Argon2id + XChaCha20-Poly1305 + CSPRNG + vecteur crypto
## Base requise
```text
livraison : 0.2.5-pre.003-fix.001
workspace.package.version = "0.2.5-pre.3.fix.1"
```
La base effective est `pre.003` complétée par `pre.003-fix.001` et par les deux réorganisations opérateur conservées dans `constants.rs` et `lib.rs` : bloc unique de `pub const` avant `pub(crate) const`, puis groupe unique de `pub use` avant le groupe `pub(crate) use`.
Les validations opérateur fournies pour cette base sont propres :
```text
cargo fmt --all -> terminé
cargo check --workspace -> terminé sans warning
cargo clippy --workspace --all-targets -> terminé sans warning
cargo test -p ksp-wallet-lib -> 18 unit tests OK
2 dependency-boundary tests OK
5 public API tests OK
2 doc-tests compile_fail OK
0 échec
cargo tree -p ksp-wallet-lib -d -> aucune duplication dans le sous-arbre Wallet
```
Le workspace possède par ailleurs plusieurs générations transitives de `base64` (`0.21.7`, `0.22.1`, `0.23.1`), mais le sous-arbre `ksp-wallet-lib` validé en `pre.003-fix.001` ne contient aucune duplication. Les audits inverses doivent donc qualifier la version (`base64@0.23.1`) lorsque nécessaire.
## Objectif
Matérialiser la première couche cryptographique **in-memory** du format V1 sans encore créer/ouvrir un wallet complet :
```text
Argon2id v19 password KDF
KEK 32 octets
XChaCha20-Poly1305
content keys 32 octets
wrapping / unwrapping authentifié
CSPRNG OS via getrandom
zeroization des clés/buffers secrets possédés
premier vecteur public KDF + wrapping
benchmark opérateur des candidats Argon2 de création
```
Restent explicitement hors tranche :
```text
payload owner-control réel
payload metadata réel
payload secret réel
state signature Ed25519 effective
create/open VIEW/OWNER
filesystem/persistence
signature Solana
rotations de passwords
import/export
```
## Version Cargo
Conformément à `VER-ID-009` :
```text
0.2.5-pre.3.fix.1 -> 0.2.5-pre.4
```
Le compteur documentaire du `Cargo.toml` racine passe de `146` à `148` : `pre.003-fix.001` avait modifié ce fichier sans consommer le numéro `147`; cette livraison restaure l'historique `GEN-FILE-004` avant sa propre modification. Le même principe est appliqué à `wire.rs` (`1 -> 3`, avec `2` consommé conceptuellement par `pre.003-fix.001`) et à `lib.rs` (`2 -> 4`, avec `3` correspondant à la réorganisation opérateur post-`pre.003`).
## Dépendances
Nouvelles dépendances communes sous `[workspace.dependencies]` :
```toml
argon2 = { version = "^0.5", default-features = false }
chacha20poly1305 = { version = "^0.11", default-features = false }
getrandom = { version = "^0.4", default-features = false }
```
Le manifest Wallet active uniquement les features consommées :
```toml
argon2 = { workspace = true, features = ["zeroize"] }
chacha20poly1305 = { workspace = true, features = ["alloc", "zeroize"] }
getrandom.workspace = true
```
Audit actuel de la tranche :
```text
argon2 génération stable 0.5.x, publiée 0.5.3 ; 0.6 reste release-candidate
chacha20poly1305 génération stable 0.11.x, publiée 0.11.0
getrandom génération stable 0.4.x, publiée 0.4.3
zeroize déjà présent au workspace
```
`argon2` n'active ni API PHC/password-hash, ni rand, ni alloc par commodité ; Wallet utilise directement `hash_password_into`. `chacha20poly1305` active `alloc` parce que l'API AEAD utilisée retourne les ciphertexts/plaintexts dans des `Vec<u8>`, et `zeroize` afin de durcir les états internes de la primitive. Le CSPRNG est possédé explicitement par Wallet via `getrandom` plutôt que par une feature de génération aléatoire de l'AEAD.
Aucun client RPC, aucune crate Solana supplémentaire, Config, Transport, Store, Tauri ou `tracing` direct n'est ajouté.
## Argon2id V1
La dérivation utilise exactement :
```text
algorithm Argon2id
version 19 / 0x13
password octets UTF-8 exacts fournis par le caller
salt octets sérialisés dans le key slot
m_cost memory_kib sérialisé
t_cost iterations sérialisé
p_cost parallelism sérialisé
output 32 octets
pepper aucun
secret ext. aucun
```
Les bornes V1 déjà figées sont réappliquées avant le KDF. La tranche ajoute explicitement l'invariant Argon2 :
```text
memory_kib >= 8 * parallelism
```
Un password vide ou supérieur à `1024` octets est rejeté par la primitive interne.
Le KDF reste sync/in-memory à ce niveau bas. `pre.005+` doit l'appeler depuis les futurs flux async create/open via la frontière blocking prévue par le plan ; aucune API async fictive n'est ajoutée ici.
## Default Argon2 non figé
Cette livraison **ne choisit pas arbitrairement** le profil de création. Le test opérateur ignoré par défaut compare :
```text
64 MiB / 3 passes / 1 lane
128 MiB / 3 passes / 1 lane
256 MiB / 3 passes / 1 lane
```
Commande dédiée après les validations normales :
```bash
cargo test -p ksp-wallet-lib benchmark_argon2_creation_candidates -- --ignored --nocapture --test-threads=1
```
Le résultat doit être conservé dans le retour opérateur. `pre.005` ne figera le default de création qu'après examen de ces mesures. Les wallets existants resteront indépendants de ce default grâce aux paramètres sérialisés dans chaque slot.
## XChaCha20-Poly1305
La primitive V1 utilise :
```text
key 32 octets
nonce 24 octets
AAD bytes TLV domain-separated figés en pre.003
ciphertext = encrypted bytes || tag Poly1305 16 octets
```
Le nonce est toujours fourni séparément à l'AEAD. La tranche ne construit aucune canonicalisation JSON crypto : les AAD restent ceux du codec sémantique TLV de `pre.003`.
Toute erreur de tag/déchiffrement est ramenée au code générique :
```text
wallet/authentication_failed
```
Le code ne produit donc pas d'oracle public distinguant key, nonce, AAD ou ciphertext incorrect.
## CSPRNG et secrets en mémoire
`getrandom::fill` fournit directement les octets provenant de la source cryptographique de l'OS. Une défaillance devient :
```text
wallet/randomness_failed
```
Aucun secret, seed ou état RNG KSP n'est introduit.
Le type interne de clé 32 octets :
```text
n'est ni Copy ni Clone
Debug => SecretKeyV1(<redacted>)
zeroize ses octets au Drop
```
L'unwrap zeroize également son buffer plaintext intermédiaire après transfert dans le type secret possédé.
Les primitives restent volontairement privées en `pre.004`. Un `allow(dead_code)` **local au seul module `crypto.rs` et documenté** existe parce que cette tranche matérialise ces primitives une prerelease avant leurs callers production `create/open` de `pre.005`; il ne modifie aucun lint workspace et doit disparaître lorsque ces callers sont branchés.
## Vecteur cryptographique public
Nouveau fixture :
```text
crates/ksp-wallet-lib/tests/fixtures/kspwallet_v1_crypto_vectors.json
```
Il contient exclusivement des valeurs publiques **TEST ONLY** et fixe de manière reproductible :
```text
password UTF-8
salt
m/t/p Argon2id
KEK dérivée attendue
content key 32 octets
nonce XChaCha 24 octets
AAD
wrapped key attendu
```
Les paramètres du vecteur (`32 KiB / 2 passes / 1 lane`) sont volontairement faibles pour conserver un test déterministe rapide. Ils ne constituent jamais le default de production ni une recommandation de sécurité.
Le vecteur a été recalculé indépendamment du code Rust avec une implémentation Argon2id et une construction XChaCha20-Poly1305 `HChaCha20 + ChaCha20-Poly1305 IETF`; l'implémentation indépendante a d'abord été vérifiée contre le vecteur HChaCha20 publié par la spécification XChaCha.
Les tests vérifient :
```text
KEK attendue
ciphertext/tag attendu
unwrap exact de la content key
tampering -> authentication_failed
Debug secret redacted
CSPRNG key/nonce callable
```
## Wire et spécification
`wire.rs` rejette maintenant avant crypto un tuple Argon2 dont la mémoire ne satisfait pas les huit blocs de 1 KiB par lane.
`docs/formats/KSPWALLET_V1.md` documente désormais indépendamment du code Rust :
```text
Argon2id v19 exact
password UTF-8 sans normalisation implicite
output KEK 32 octets
absence de pepper/secret externe
XChaCha20-Poly1305 key/nonce/tag
CSPRNG OS
content keys 32 octets
wrapping OWNER / VIEW
emplacement du vecteur crypto public
statut explicitement non fixé du default Argon2 de création
```
Le format V1 reste autonome : tous les salts, paramètres et nonces nécessaires sont dans le `.kspwallet`; aucun facteur externe n'est introduit.
## Canaries de dépendances
`dependency_boundary.rs` vérifie les trois nouvelles dépendances Wallet et leurs features, tout en conservant les interdictions :
```text
Wallet -X-> Config
Wallet -X-> Transport
Wallet -X-> ExecutionPolicy
Wallet -X-> Store
Wallet -X-> Tauri
Wallet -X-> tracing direct
Wallet -X-> solana-pubkey direct
```
`Pubkey` reste possédée/réexportée par `ksp-core-lib`; cette tranche n'ajoute aucune dépendance Solana Wallet.
## Validation attendue
Après application :
```bash
cargo fmt --all
cargo check --workspace
cargo clippy --workspace --all-targets
cargo test -p ksp-wallet-lib
cargo test --workspace
```
Audit de dépendances/features de la tranche :
```bash
cargo tree -p ksp-wallet-lib
cargo tree -p ksp-wallet-lib -d
cargo tree -e features -p ksp-wallet-lib
cargo tree -i argon2@0.5.3
cargo tree -i chacha20poly1305@0.11.0
cargo tree -i getrandom@0.4.3
cargo tree -i base64@0.23.1
cargo tree -i zeroize@1.9.0
```
L'audit doit confirmer au minimum :
```text
pas de duplication dans le sous-arbre Wallet sans justification
pas de default features Argon2/ChaCha réactivées accidentellement
pas de Config/Transport/Tauri/RPC Solana transitif propre à Wallet
base64 0.23.1 reste la génération consommée directement par Wallet
```
Puis exécuter séparément le benchmark opérateur :
```bash
cargo test -p ksp-wallet-lib benchmark_argon2_creation_candidates -- --ignored --nocapture --test-threads=1
```
## Fichiers ajoutés
```text
crates/ksp-wallet-lib/src/crypto.rs
crates/ksp-wallet-lib/unit_tests/crypto.rs
crates/ksp-wallet-lib/tests/fixtures/kspwallet_v1_crypto_vectors.json
deltas/0.2.5/pre.004.md
```
## Fichiers modifiés
```text
Cargo.toml
ROADMAP.md
crates/ksp-wallet-lib/Cargo.toml
crates/ksp-wallet-lib/src/error.rs
crates/ksp-wallet-lib/src/lib.rs
crates/ksp-wallet-lib/src/wire.rs
crates/ksp-wallet-lib/tests/dependency_boundary.rs
crates/ksp-wallet-lib/tests/public_api.rs
crates/ksp-wallet-lib/unit_tests/wire.rs
docs/formats/000-README.md
docs/formats/KSPWALLET_V1.md
docs/plans/002-FUNCTIONAL_RELEASE_SEQUENCE.md
docs/plans/012-V0_2_5_WALLET_FOUNDATION_PLAN.md
```
## Suite
`0.2.5-pre.005` consommera ces primitives pour les compartiments `owner_control` / metadata / secret, `create/open VIEW/OWNER` et l'authentification d'état OWNER niveau B. Le default Argon2 de création sera figé uniquement après réception du benchmark opérateur de cette tranche.