diff --git a/Cargo.toml b/Cargo.toml index c2fd353..9045354 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,7 +6,7 @@ resolver = "3" members = ["crates/ksp-app-config-desk", "crates/ksp-config-lib", "crates/ksp-core-lib", "crates/ksp-logging-lib", "crates/ksp-onchain-transport-lib"] [workspace.package] -version = "0.2.4" +version = "0.2.5-pre.1" edition = "2024" license = "MIT" repository = "https://git.sasedev.com/Sasedev/khadhroony-solana-project" diff --git a/ROADMAP.md b/ROADMAP.md index f006a58..7f7c14f 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -1,5 +1,5 @@ - + # Roadmap KSP @@ -49,7 +49,7 @@ Le roadmap décrit les objectifs à atteindre et les grandes étapes prévues. U - [X] `0.2.2` — HTTP Accounts + Tokens + Cluster : 22 wrappers typés (5 Accounts + 5 Tokens + 12 Cluster), canaries de complétude 52+14, smoke Devnet Transport pur et smoke historique Config -> Transport validés, documentation durable et prompt `0.2.3` publiés stables. - [X] `0.2.3` — HTTP Transactions stable : 11/11 wrappers typés publiés, classification `8 Read / 2 WriteSubmission / 1 Simulation`, no-resend ambigu prouvé pour les write submissions, `KSP-TRANSPORT-007` réaudité conforme sur les 37 wrappers HTTP courants, graphes Cargo et deux smokes Devnet validés ; `0.2.4` reprend les 15 Blocks/Economics restants. - [X] `0.2.4` — HTTP Blocks + Economics stable : 15/15 wrappers `V0_2_4` publiés, surface typed complète à 52/52 méthodes courantes, 14/14 historiques conservées, réaudit SIMD/inventaire final et `KSP-TRANSPORT-007` global validés ; deux smokes Devnet passés avant publication. -- [ ] `0.2.5` — Introduire `ksp-wallet-lib` et le format interopérable `.kspwallet` avec threat model offline, capacités indépendantes VIEW/OWNER, metadata protégées, signature, rotations de key slots et import/export extensible ; exclure `WalletPolicy`. +- [/] `0.2.5` — Wallet foundation ouverte par `pre.001` : threat model offline et héritage bot2/bot3 réaudités, `.kspwallet` V1 entièrement autonome sans facteur externe, design content-keys/key-slots VIEW/OWNER indépendant, read-only VIEW niveau B via autorité Ed25519 de format distincte couvrant tout état mutable, keypair V1 immuable, spec multi-langages séparée + vecteurs publics exigés, paramètres KDF à benchmarker avant freeze, persistence/signature/rotations/import-export répartis jusqu’à `pre.010` ; `WalletPolicy` reste exclu. - [ ] `0.2.6` — Introduire `ksp-app-wallet-desk` utilisant Config composite + Wallet + transport HTTP, notamment pour afficher l'identité et le solde d'un wallet. - [ ] `0.2.7` — Étendre `ksp-onchain-transport-lib` au WebSocket Solana standard complet ; permettre plusieurs sessions sur une même URL sans imposer encore un pool automatique complexe. - [ ] `0.2.8` — Ajouter Helius LaserStream WebSocket comme extension du moteur WebSocket standard, sans duplication de client. diff --git a/deltas/0.2.5/pre.001.md b/deltas/0.2.5/pre.001.md new file mode 100644 index 0000000..eb5c297 --- /dev/null +++ b/deltas/0.2.5/pre.001.md @@ -0,0 +1,239 @@ + + + +# Delta `0.2.5-pre.001` — audit Wallet, threat model, format V1 et sizing + +## Base requise + +Release stable attendue : + +```text +v0.2.4 +``` + +La base fournie confirme `workspace.package.version = 0.2.4` avant ouverture. + +## Type de livraison + +```text +ksp-general-0.2.5-pre.001.zip +``` + +L'archive d'échange est un **delta** applicable depuis la racine de `v0.2.4` et contient uniquement les fichiers ajoutés/modifiés par cette livraison, conformément à `VER-ARCHIVE-004`. + +## Objet + +Ouvrir `0.2.5 — Wallet foundation` sans commencer par une implémentation cryptographique. Ce delta : + +- réaudite les Wallet historiques bot2/bot3 ; +- classe les idées à réutiliser/refondre/abandonner/reporter ; +- formalise le threat model offline du `.kspwallet` ; +- arrête l'architecture indépendante VIEW/OWNER par content keys + key slots ; +- retient le niveau B pour le read-only VIEW via une autorité Ed25519 de format distincte de la keypair Solana et couvrant tout état mutable/de sécurité ; +- confirme que `.kspwallet` V1 est entièrement autonome et ne requiert aucun facteur/ancrage externe ; +- rend la keypair Solana V1 immuable après création/import ; +- exige une spec séparée `docs/formats/KSPWALLET_V1.md` suffisante pour une implémentation indépendante dans un autre langage ; +- choisit l'enveloppe JSON V1 stricte et un transcript binaire sémantique plutôt qu'une signature des octets JSON ; +- réaudite les crates Solana/crypto/persistence actuelles ; +- fixe les candidats V1 sans les ajouter prématurément ; +- distingue rotation de password et révocation cryptographique forte de VIEW ; +- fixe le minimum import/export à Solana CLI JSON + keypair Base58 générique ; +- redimensionne la release de 8 à 10 prereleases avant publication. + +## Décisions principales + +### Héritage + +Réutiliser conceptuellement : strict 64-byte Solana keypair, signature sans getter secret, redaction/zeroize, `spawn_blocking`, CSPRNG OS, parsing borné, AEAD/AAD, no-clobber/atomic persistence, Solana CLI JSON, Base58 et inspection sûre. + +Refondre : password model, format, alias, unlocked representation, persistence API, logging et adapters. + +Abandonner : `.kswallet`, `KSWALLET`, alias/pubkey en clair, alias=filename, single password, chiffrement direct du keypair, JSON legacy/migration, `WalletPolicy`, direct `tracing`. + +Reporter : mnemonic UI, proprietary wallets sans wire normatif prouvé, hardware/remote/recovery. + +### Threat model + +Le fichier volé est attaquable offline sans rate-limit. Les salts sont publics. Aucun pepper KSP n'existe. `.kspwallet` V1 est explicitement auto-contenu : aucun salt externe, pepper, OTP, service distant, keychain ou ancre externe n'est requis. Les altérations partielles et toute mutation sous l'autorité OWNER originale sont authentifiées ; la substitution/rollback total d'un fichier valide reste indétectable par le seul fichier auto-contenu et cette limite est documentée sans introduire de dépendance externe en V1. + +### Key hierarchy + +```text +VIEW password -> Argon2id VIEW -> KEK VIEW -> wrap K_metadata +OWNER password -> Argon2id OWNER -> KEK OWNER -> wrap K_owner_root + +K_owner_root -> owner-control -> K_metadata + K_secret + admin signing secret +K_metadata -> metadata -> Pubkey + alias + notes +K_secret -> secret -> Solana keypair +``` + +OWNER ne dépend jamais de VIEW. + +### VIEW read-only + +Le niveau B est retenu : une clé Ed25519 d'administration du format, distincte de la keypair Solana, signe un transcript déterministe de tout l'état mutable/de sécurité. VIEW peut lire les metadata mais ne peut pas produire sous l'autorité OWNER originale une mutation acceptée de metadata, key slots/passwords, compartments ou keypair. Les modifications physiques d'octets restent possibles pour un attaquant filesystem, mais elles sont rejetées si elles ne portent pas une signature OWNER valide. + +Cette garantie ne couvre pas le remplacement complet du fichier **et** de sa propre clé publique de contrôle par un autre wallet auto-cohérent, ni le rollback intégral vers une ancienne copie valide. V1 n'utilise aucune ancre externe pour masquer cette limite. + +### Rotation / révocation + +`rotate_view_password` peut rewrap la même `K_metadata` et invalide l'ancien password pour le fichier courant. Une vraie révocation VIEW génère une nouvelle `K_metadata`, rechiffre metadata/control et recrée/supprime le slot VIEW. + +`rotate_owner_password` rewrap `K_owner_root` et ne modifie pas la keypair Solana. La keypair Solana V1 est immuable après création/import ; une autre keypair correspond à un autre wallet, pas à une mutation du wallet existant. + +### Format V1 + +```text +JSON UTF-8 strict +magic = KSPWALLET +format_version = 1 +Base64url sans padding pour binary wire +key_slots génériques, V1 = OWNER obligatoire + VIEW optionnel +owner_control / metadata / secret séparés +owner_auth_public_key visible, identité Solana cachée +state_signature Ed25519 couvrant tout état mutable/de sécurité +unknown fields/version = reject +pas de checksum séparé +aucune dépendance externe requise pour ouvrir/vérifier V1 +``` + +La signature porte sur un transcript binaire déterministe et domain-separated, pas sur une canonicalisation JSON. + +### Crypto candidate + +```text +KDF Argon2id v19 +AEAD XChaCha20-Poly1305 +CSPRNG getrandom / OS +memory zeroize +admin auth Ed25519 standard, dépendance directe à confirmer par cargo tree +``` + +Les paramètres Argon2 de création ne sont **pas** figés ici. Ils seront benchmarkés avant freeze et sérialisés par slot ; le parseur aura des caps anti-DoS avant KDF. + +### Import/export minimum + +```text +solana-cli-json +solana-keypair-base58 +``` + +Pas de nom/adapteur Phantom/Solflare/Backpack/Trust sans wire actuel suffisamment normatif. + +## Prévision révisée + +```text +pre.001 audit + threat model + design + sizing +pre.002 crate/API foundation + errors/logging/canaries +pre.003 strict JSON wire + key slots + transcript/AAD + contrat docs/formats + spec initiale +pre.004 KDF benchmark + AEAD/wrapping + vectors crypto in-memory +pre.005 compartments + create/open VIEW/OWNER + state signature +pre.006 persistence atomic/no-clobber + async + filesystem hardening +pre.007 signing + metadata admin + rotations + VIEW strong revoke/recreate +pre.008 extensible import/export + CLI JSON + Base58 + inspect +pre.009 security/interoperability/compliance audit + adversarial tests + cargo trees +pre.010 spec/README/USAGE/graphes/prompt Wallet Desk + candidate close +rel.001 publication stricte +``` + +Le plan détaillé est `docs/plans/012-V0_2_5_WALLET_FOUNDATION_PLAN.md`. + +## Correction de l'artefact d'échange avant validation + +Une première archive préparatoire avait été produite à tort comme copie complète du dépôt. Elle est **invalidée explicitement et ne doit pas être appliquée** : elle ne respectait pas `VER-ARCHIVE-001`/`VER-ARCHIVE-004`. Comme cette livraison n'a pas été validée ni indiquée comme commitée par l'opérateur, le présent artefact est la livraison `pre.001` correcte, reconstruite comme delta depuis `v0.2.4`; il ne s'agit pas d'un `fix` fonctionnel appliqué après commit. + +La même revue a durci deux points de conception avant implémentation : autonomie absolue du format V1 et authentification OWNER de tout état mutable, avec la limite irréductible du remplacement total clairement séparée. + +## Fichiers ajoutés + +```text +docs/plans/012-V0_2_5_WALLET_FOUNDATION_PLAN.md +deltas/0.2.5/pre.001.md +``` + +## Fichiers modifiés + +```text +Cargo.toml +ROADMAP.md +docs/000-README.md +docs/plans/000-README.md +docs/plans/002-FUNCTIONAL_RELEASE_SEQUENCE.md +``` + +## Fichiers volontairement inchangés + +```text +CHANGELOG.md +crates/** +config/** +docs/validation/** +deltas/0.2.4/** +``` + +Aucune crate Wallet ni dépendance crypto n'est ajoutée par le gate. Le changelog reste synchronisé en fin de session conformément à `VER-SESSION-005`. + +## Audit de dépendances actuel + +Constats externes au 2026-08-18, sans modification Cargo dans ce delta : + +```text +solana-pubkey 4.3.0 +solana-keypair 3.1.2 +solana-signer 3.0.1 +argon2 0.5.3 +scrypt 0.12.0 +pbkdf2 0.13.0 +chacha20poly1305 0.11.0 +aes-gcm-siv 0.12.0 +getrandom 0.4.3 +zeroize 1.9.0 +ed25519-dalek 3.0.0 +base64 0.23.1 +tempfile 3.27.0 +``` + +Les versions directes Solana/crypto seront réauditées au moment exact où chaque dépendance est introduite. `solana-signature 3.5.2` est la publication courante auditée ; son ajout direct reste conditionné à la surface publique réellement retenue et au cargo tree de ce moment. + +## Validations exécutées + +- inspection/réaduit de l'archive stable KSP `v0.2.4` fournie ; +- relecture de l'index `RULES.md`, de l'ensemble des fichiers `docs/rules/*.md`, des documents architecture/plans/validation Wallet demandés et des conventions de delta/archive ; +- confirmation des frontières Wallet déjà documentées et de `VER-ARCHIVE-004` ; +- inspection globale de l'archive historique bot3 et lecture détaillée de `ks-wallet`, de ses tests, guides, plan/validation Wallet, format natif et héritage bot2 Wallet ; +- inspection de l'ancien `TemporaryWalletStore` bot2 ; +- réaudit des primitives/crates publiées actuelles nécessaires au plan ; +- confirmation que le gate ne nécessite aucune nouvelle dépendance dans `pre.001` ; +- vérification documentaire que le nouveau plan ne réintroduit ni Config, Transport, Store, Tauri ni WalletPolicy dans Wallet ; +- contrôle que V1 ne requiert aucun facteur externe et que la spec multi-langages séparée est un critère de clôture ; +- contrôle du contenu de l'archive d'échange selon `VER-ARCHIVE-004` : sept chemins seulement, tous ajoutés/modifiés par `pre.001`. + +## Validations non exécutées + +Le sandbox courant ne fournit pas le binaire `cargo`; les validations Cargo doivent être rejouées par l'opérateur avant commit : + +```bash +cargo fmt --all +cargo check --workspace +cargo clippy --workspace --all-targets +``` + +`cargo test -p ksp-wallet-lib` n'est pas applicable à `pre.001` puisque la crate n'existe volontairement pas encore. + +Aucun `cargo tree` ne peut être pertinent à ce stade puisque les dépendances ne changent pas. Il devient obligatoire dès leur introduction et à la compliance finale. + +L'archive stable fournie ne contient pas `.git`; le commit attendu après application et validations suit : + +```text +v0.2.5-pre.001 +``` + +## Questions bloquantes + +Aucune pour `pre.002`. + +Les paramètres Argon2 de production sont volontairement **non décidés** avant benchmark ; ce n'est pas une question d'architecture bloquante. + +## Suite + +`0.2.5-pre.002` : créer `crates/ksp-wallet-lib` avec foundation API/capabilities, erreurs, logging KSP et canaries de frontières, sans encore implémenter le chiffrement `.kspwallet`. diff --git a/docs/000-README.md b/docs/000-README.md index c64b2c0..7b5a59c 100644 --- a/docs/000-README.md +++ b/docs/000-README.md @@ -1,5 +1,5 @@ - + # Documentation KSP @@ -43,7 +43,8 @@ docs/ │ ├── 008-V0_2_1_ONCHAIN_HTTP_PLAN.md │ ├── 009-V0_2_2_HTTP_ACCOUNTS_TOKENS_CLUSTER_PLAN.md │ ├── 010-V0_2_3_HTTP_TRANSACTIONS_PLAN.md -│ └── 011-V0_2_4_HTTP_BLOCKS_ECONOMICS_PLAN.md +│ ├── 011-V0_2_4_HTTP_BLOCKS_ECONOMICS_PLAN.md +│ └── 012-V0_2_5_WALLET_FOUNDATION_PLAN.md ├── validation/ │ ├── 000-README.md │ ├── 001-V0_1_4_CONFIG_DESKTOP.md @@ -69,7 +70,7 @@ D'autres sous-répertoires seront ajoutés uniquement lorsque leur rôle aura é ## Documents de planification -Le plan historique de la phase fondatrice clôturée est conservé dans [`plans/001-V0_0_3_PLAN.md`](plans/001-V0_0_3_PLAN.md). La séquence active des premières releases fonctionnelles est définie dans [`plans/002-FUNCTIONAL_RELEASE_SEQUENCE.md`](plans/002-FUNCTIONAL_RELEASE_SEQUENCE.md). Le plan détaillé de la release stable `0.1.1` est conservé comme historique clôturé dans [`plans/003-V0_1_1_CORE_FOUNDATION_PLAN.md`](plans/003-V0_1_1_CORE_FOUNDATION_PLAN.md). Le plan détaillé de la release stable `0.1.2` est conservé comme historique clôturé dans [`plans/004-V0_1_2_LOGGING_FOUNDATION_PLAN.md`](plans/004-V0_1_2_LOGGING_FOUNDATION_PLAN.md). Le plan détaillé de la release stable `0.1.3 — Configuration foundation` est conservé comme historique clôturé dans [`plans/005-V0_1_3_CONFIG_FOUNDATION_PLAN.md`](plans/005-V0_1_3_CONFIG_FOUNDATION_PLAN.md). Le plan détaillé de la release stable `0.1.4 — ksp-app-config-desk` est conservé comme historique clôturé dans [`plans/006-V0_1_4_CONFIG_DESKTOP_PLAN.md`](plans/006-V0_1_4_CONFIG_DESKTOP_PLAN.md), avec sa matrice finale [`validation/001-V0_1_4_CONFIG_DESKTOP.md`](validation/001-V0_1_4_CONFIG_DESKTOP.md). Son prompt d'ouverture historique reste [`../prompts/004-V0_1_4_START_PROMPT.md`](../prompts/004-V0_1_4_START_PROMPT.md). La release stable `0.2.0` clôt l'audit de bot3 et le découpage de la série. Son plan directeur est conservé comme historique clôturé dans [`plans/007-V0_2_0_SERIES_PLANNING.md`](plans/007-V0_2_0_SERIES_PLANNING.md), avec sa matrice finale [`validation/002-V0_2_0_SERIES_PLANNING.md`](validation/002-V0_2_0_SERIES_PLANNING.md). La release stable `0.2.1 — HTTP Solana foundation` a été ouverte par [`../prompts/006-V0_2_1_START_PROMPT.md`](../prompts/006-V0_2_1_START_PROMPT.md). Son gate de sizing et sa matrice exhaustive sont conservés dans [`plans/008-V0_2_1_ONCHAIN_HTTP_PLAN.md`](plans/008-V0_2_1_ONCHAIN_HTTP_PLAN.md), avec la validation finale [`validation/003-V0_2_1_ONCHAIN_HTTP.md`](validation/003-V0_2_1_ONCHAIN_HTTP.md), README/USAGE Transport et le smoke Devnet opt-in de composition Config -> Transport. Le prompt [`../prompts/007-V0_2_2_START_PROMPT.md`](../prompts/007-V0_2_2_START_PROMPT.md) a ouvert la release stable `0.2.2 — HTTP Accounts + Tokens + Cluster`. Son plan clôturé [`plans/009-V0_2_2_HTTP_ACCOUNTS_TOKENS_CLUSTER_PLAN.md`](plans/009-V0_2_2_HTTP_ACCOUNTS_TOKENS_CLUSTER_PLAN.md) conserve l'audit et l'implémentation des 22 wrappers typés, tandis que [`validation/004-V0_2_2_HTTP_ACCOUNTS_TOKENS_CLUSTER.md`](validation/004-V0_2_2_HTTP_ACCOUNTS_TOKENS_CLUSTER.md) enregistre les validations déterministes, les graphes Cargo et les deux smokes Devnet passés avant publication. Le prompt [`../prompts/008-V0_2_3_START_PROMPT.md`](../prompts/008-V0_2_3_START_PROMPT.md) a ouvert la release stable `0.2.3 — HTTP Transactions`. Son plan clôturé [`plans/010-V0_2_3_HTTP_TRANSACTIONS_PLAN.md`](plans/010-V0_2_3_HTTP_TRANSACTIONS_PLAN.md) conserve l'audit et l'implémentation des 11 wrappers ; le réaudit [`validation/005-V0_2_3_KSP_TRANSPORT_007_RETRO_AUDIT.md`](validation/005-V0_2_3_KSP_TRANSPORT_007_RETRO_AUDIT.md) confirme la complétude des 37 wrappers HTTP typés et [`validation/006-V0_2_3_HTTP_TRANSACTIONS.md`](validation/006-V0_2_3_HTTP_TRANSACTIONS.md) enregistre les validations finales, graphes Cargo et deux smokes Devnet passés avant publication. Le prompt [`../prompts/009-V0_2_4_START_PROMPT.md`](../prompts/009-V0_2_4_START_PROMPT.md) a ouvert la release stable `0.2.4 — HTTP Blocks + Economics + compliance HTTP finale`. Son plan clôturé [`plans/011-V0_2_4_HTTP_BLOCKS_ECONOMICS_PLAN.md`](plans/011-V0_2_4_HTTP_BLOCKS_ECONOMICS_PLAN.md) conserve l’implémentation des 15 wrappers et la compliance `52/52 + 14/14`; la matrice finale [`validation/007-V0_2_4_HTTP_FINAL_COMPLIANCE.md`](validation/007-V0_2_4_HTTP_FINAL_COMPLIANCE.md) enregistre le réaudit SIMD/inventaire, les canaries globales et les preuves opérateur avant publication. Le prompt [`../prompts/010-V0_2_5_START_PROMPT.md`](../prompts/010-V0_2_5_START_PROMPT.md), finalisé par `0.2.4-pre.009-fix.001`, ouvre `0.2.5 — Wallet foundation` sur la base stable `v0.2.4`. +Le plan historique de la phase fondatrice clôturée est conservé dans [`plans/001-V0_0_3_PLAN.md`](plans/001-V0_0_3_PLAN.md). La séquence active des premières releases fonctionnelles est définie dans [`plans/002-FUNCTIONAL_RELEASE_SEQUENCE.md`](plans/002-FUNCTIONAL_RELEASE_SEQUENCE.md). Le plan détaillé de la release stable `0.1.1` est conservé comme historique clôturé dans [`plans/003-V0_1_1_CORE_FOUNDATION_PLAN.md`](plans/003-V0_1_1_CORE_FOUNDATION_PLAN.md). Le plan détaillé de la release stable `0.1.2` est conservé comme historique clôturé dans [`plans/004-V0_1_2_LOGGING_FOUNDATION_PLAN.md`](plans/004-V0_1_2_LOGGING_FOUNDATION_PLAN.md). Le plan détaillé de la release stable `0.1.3 — Configuration foundation` est conservé comme historique clôturé dans [`plans/005-V0_1_3_CONFIG_FOUNDATION_PLAN.md`](plans/005-V0_1_3_CONFIG_FOUNDATION_PLAN.md). Le plan détaillé de la release stable `0.1.4 — ksp-app-config-desk` est conservé comme historique clôturé dans [`plans/006-V0_1_4_CONFIG_DESKTOP_PLAN.md`](plans/006-V0_1_4_CONFIG_DESKTOP_PLAN.md), avec sa matrice finale [`validation/001-V0_1_4_CONFIG_DESKTOP.md`](validation/001-V0_1_4_CONFIG_DESKTOP.md). Son prompt d'ouverture historique reste [`../prompts/004-V0_1_4_START_PROMPT.md`](../prompts/004-V0_1_4_START_PROMPT.md). La release stable `0.2.0` clôt l'audit de bot3 et le découpage de la série. Son plan directeur est conservé comme historique clôturé dans [`plans/007-V0_2_0_SERIES_PLANNING.md`](plans/007-V0_2_0_SERIES_PLANNING.md), avec sa matrice finale [`validation/002-V0_2_0_SERIES_PLANNING.md`](validation/002-V0_2_0_SERIES_PLANNING.md). La release stable `0.2.1 — HTTP Solana foundation` a été ouverte par [`../prompts/006-V0_2_1_START_PROMPT.md`](../prompts/006-V0_2_1_START_PROMPT.md). Son gate de sizing et sa matrice exhaustive sont conservés dans [`plans/008-V0_2_1_ONCHAIN_HTTP_PLAN.md`](plans/008-V0_2_1_ONCHAIN_HTTP_PLAN.md), avec la validation finale [`validation/003-V0_2_1_ONCHAIN_HTTP.md`](validation/003-V0_2_1_ONCHAIN_HTTP.md), README/USAGE Transport et le smoke Devnet opt-in de composition Config -> Transport. Le prompt [`../prompts/007-V0_2_2_START_PROMPT.md`](../prompts/007-V0_2_2_START_PROMPT.md) a ouvert la release stable `0.2.2 — HTTP Accounts + Tokens + Cluster`. Son plan clôturé [`plans/009-V0_2_2_HTTP_ACCOUNTS_TOKENS_CLUSTER_PLAN.md`](plans/009-V0_2_2_HTTP_ACCOUNTS_TOKENS_CLUSTER_PLAN.md) conserve l'audit et l'implémentation des 22 wrappers typés, tandis que [`validation/004-V0_2_2_HTTP_ACCOUNTS_TOKENS_CLUSTER.md`](validation/004-V0_2_2_HTTP_ACCOUNTS_TOKENS_CLUSTER.md) enregistre les validations déterministes, les graphes Cargo et les deux smokes Devnet passés avant publication. Le prompt [`../prompts/008-V0_2_3_START_PROMPT.md`](../prompts/008-V0_2_3_START_PROMPT.md) a ouvert la release stable `0.2.3 — HTTP Transactions`. Son plan clôturé [`plans/010-V0_2_3_HTTP_TRANSACTIONS_PLAN.md`](plans/010-V0_2_3_HTTP_TRANSACTIONS_PLAN.md) conserve l'audit et l'implémentation des 11 wrappers ; le réaudit [`validation/005-V0_2_3_KSP_TRANSPORT_007_RETRO_AUDIT.md`](validation/005-V0_2_3_KSP_TRANSPORT_007_RETRO_AUDIT.md) confirme la complétude des 37 wrappers HTTP typés et [`validation/006-V0_2_3_HTTP_TRANSACTIONS.md`](validation/006-V0_2_3_HTTP_TRANSACTIONS.md) enregistre les validations finales, graphes Cargo et deux smokes Devnet passés avant publication. Le prompt [`../prompts/009-V0_2_4_START_PROMPT.md`](../prompts/009-V0_2_4_START_PROMPT.md) a ouvert la release stable `0.2.4 — HTTP Blocks + Economics + compliance HTTP finale`. Son plan clôturé [`plans/011-V0_2_4_HTTP_BLOCKS_ECONOMICS_PLAN.md`](plans/011-V0_2_4_HTTP_BLOCKS_ECONOMICS_PLAN.md) conserve l’implémentation des 15 wrappers et la compliance `52/52 + 14/14`; la matrice finale [`validation/007-V0_2_4_HTTP_FINAL_COMPLIANCE.md`](validation/007-V0_2_4_HTTP_FINAL_COMPLIANCE.md) enregistre le réaudit SIMD/inventaire, les canaries globales et les preuves opérateur avant publication. Le prompt [`../prompts/010-V0_2_5_START_PROMPT.md`](../prompts/010-V0_2_5_START_PROMPT.md), finalisé par `0.2.4-pre.009-fix.001`, ouvre `0.2.5 — Wallet foundation` sur la base stable `v0.2.4`. Son gate `0.2.5-pre.001` est conservé dans [`plans/012-V0_2_5_WALLET_FOUNDATION_PLAN.md`](plans/012-V0_2_5_WALLET_FOUNDATION_PLAN.md) : il réaudite bot2/bot3 et les crates actuelles, formalise le threat model offline, retient les capacités VIEW/OWNER indépendantes et le niveau B read-only, cadre le format interopérable `.kspwallet` V1 et redimensionne la release avant implémentation cryptographique. `IDEAS.md` conserve les pistes et questions qui ne sont pas encore des engagements du roadmap ni des décisions architecturales. diff --git a/docs/plans/000-README.md b/docs/plans/000-README.md index ce3ee17..260bf7e 100644 --- a/docs/plans/000-README.md +++ b/docs/plans/000-README.md @@ -1,5 +1,5 @@ - + # Plans KSP @@ -20,6 +20,7 @@ Un plan décrit le périmètre, les décisions déjà acquises, les questions ou - [`009-V0_2_2_HTTP_ACCOUNTS_TOKENS_CLUSTER_PLAN.md`](009-V0_2_2_HTTP_ACCOUNTS_TOKENS_CLUSTER_PLAN.md) — plan clôturé de la release stable `0.2.2`, établi par `pre.001`, corrigé après réaudit Agave v4.2.1 puis exécuté jusqu'à `pre.007-fix.002`; il couvre les 22 wrappers Accounts/Tokens/Cluster, le smoke Transport opt-in et la préparation de `0.2.3`. - [`010-V0_2_3_HTTP_TRANSACTIONS_PLAN.md`](010-V0_2_3_HTTP_TRANSACTIONS_PLAN.md) — plan historique clôturé de la release stable `0.2.3 — HTTP Transactions`, ouvert par `pre.001`, exécuté jusqu'à `pre.009` puis publié par `rel.001`; il couvre les 11 méthodes, la classification `8 Read / 2 WriteSubmission / 1 Simulation`, `KSP-TRANSPORT-007`, le no-resend et la préparation de `0.2.4`. - [`011-V0_2_4_HTTP_BLOCKS_ECONOMICS_PLAN.md`](011-V0_2_4_HTTP_BLOCKS_ECONOMICS_PLAN.md) — plan historique clôturé de la release stable `0.2.4`, ouvert par `pre.001`, exécuté jusqu’à `pre.009`, complété par le fix documentaire Wallet `pre.009-fix.001` puis publié par `rel.001`; il couvre les 10 Blocks + 5 Economics et la compliance finale `52/52 + 14/14` sous `KSP-TRANSPORT-007`. +- [`012-V0_2_5_WALLET_FOUNDATION_PLAN.md`](012-V0_2_5_WALLET_FOUNDATION_PLAN.md) — plan actif de `0.2.5 — Wallet foundation`, ouvert par `pre.001`; il fixe le threat model offline, le design VIEW/OWNER par key slots, le niveau B read-only, le format `.kspwallet` V1, les primitives candidates et le sizing révisé jusqu’à `pre.010`. Le `pre.001` de chaque release fonctionnelle peut introduire son propre plan détaillé lorsque la release s'ouvre. diff --git a/docs/plans/002-FUNCTIONAL_RELEASE_SEQUENCE.md b/docs/plans/002-FUNCTIONAL_RELEASE_SEQUENCE.md index dc69a69..2bbc900 100644 --- a/docs/plans/002-FUNCTIONAL_RELEASE_SEQUENCE.md +++ b/docs/plans/002-FUNCTIONAL_RELEASE_SEQUENCE.md @@ -1,5 +1,5 @@ - + # Séquence des releases fonctionnelles KSP @@ -398,11 +398,15 @@ Chaque `pre.001` réaudite la documentation officielle actuelle. Les méthodes D ## `0.2.5` — Wallet foundation -Mission : créer `ksp-wallet-lib` et le format `.kspwallet`. +Mission : créer `ksp-wallet-lib` et le format natif interopérable `.kspwallet`, indépendants de Config/Transport/Tauri/ExecutionPolicy. -Inclure un format `.kspwallet` documenté et interopérable, un threat model d’attaque offline, des capacités indépendantes `VIEW`/`OWNER`, Pubkey/alias/notes protégés lorsque verrouillé, key slots/rotations sans changement de keypair, signature sans exposition publique du secret brut et import/export extensible. +`0.2.5-pre.001` ouvre la release par un gate documentaire : l'ancien JSON temporaire et `.kswallet` ne sont pas migrés, mais leurs invariants utiles (keypair strict, signature sans getter secret, zeroization, `spawn_blocking`, no-clobber/atomic persistence, adapters CLI JSON/Base58) servent de canaris conceptuels. Le nouveau format cache Pubkey/alias/notes lorsqu'il est verrouillé et sépare VIEW/OWNER par content keys et key slots indépendants. -`pre.001` doit auditer les choix KDF/AEAD/key wrapping/secret memory actuels avant de figer V1. Exclure : temporary wallet JSON historique et `WalletPolicy`. +Le design retient un read-only VIEW de niveau B : une clé Ed25519 d'administration du format, distincte de la keypair Solana, authentifie un transcript déterministe de tout l'état mutable/de sécurité. Sans OWNER, un détenteur VIEW ne peut donc pas fabriquer sous l'autorité OWNER originale une modification de metadata, key slot/password, compartment secret ou keypair qui soit acceptée. La cryptographie détecte/rejette les mutations ; elle ne prétend pas empêcher un attaquant filesystem d'écrire physiquement des octets ni distinguer une substitution intégrale par un autre wallet auto-cohérent. + +Le format V1 est cadré comme JSON UTF-8 strict avec binary Base64url sans padding, `format_version`, paramètres Argon2id sérialisés, key slots génériques, owner-control/metadata/secret séparés et XChaCha20-Poly1305. **V1 est entièrement autonome** : aucun salt externe, pepper, OTP, secret KSP, service distant ou ancre externe n'est requis. Les paramètres Argon2 de création ne sont gelés qu'après benchmark. OWNER reste indépendant de VIEW, peut rekey les metadata pour une révocation VIEW forte sans changer la keypair Solana, et la keypair V1 reste immuable après création/import. + +La release doit fournir `docs/formats/KSPWALLET_V1.md` comme spécification séparée et indépendante de Rust, accompagnée de vecteurs publics auto-contenus permettant une réimplémentation dans un autre langage. La prévision est étendue jusqu'à `pre.010` afin de séparer codec, crypto, capabilities, persistence, administration, import/export, security audit et documentation interopérable. Le plan actif est `docs/plans/012-V0_2_5_WALLET_FOUNDATION_PLAN.md`. ## `0.2.6` — Wallet Desk diff --git a/docs/plans/012-V0_2_5_WALLET_FOUNDATION_PLAN.md b/docs/plans/012-V0_2_5_WALLET_FOUNDATION_PLAN.md new file mode 100644 index 0000000..95047df --- /dev/null +++ b/docs/plans/012-V0_2_5_WALLET_FOUNDATION_PLAN.md @@ -0,0 +1,1153 @@ + + + +# Plan `0.2.5` — Wallet foundation + +## 1. Objet et gate `pre.001` + +La release `0.2.5` ouvre, sur la base stable `v0.2.4`, le premier cœur Wallet autonome KSP : + +```text +crates/ksp-wallet-lib +format natif .kspwallet +``` + +`0.2.5-pre.001` est volontairement documentaire. Il ne crée pas encore la crate et n'ajoute aucune dépendance cryptographique : il réaudite l'héritage bot2/bot3, fixe le threat model, choisit le design VIEW/OWNER, cadre le format wire, réaudite les primitives actuelles et redimensionne la release avant toute implémentation sensible. + +Le gate est **positif avec découpage élargi** : la release reste cohérente comme unité fonctionnelle, mais la prévision initiale en huit prereleases compresse trop fortement le format, les key slots, l'authentification cryptographique des metadata, la persistence et les validations adversariales. La prévision passe donc à dix prereleases avant `rel.001`. + +## 2. Frontières non négociables + +Direction autorisée : + +```text +ksp-wallet-lib + -> ksp-core-lib + -> ksp-logging-lib + -> primitives crypto/key/signature low-level explicitement retenues +``` + +Interdictions : + +```text +ksp-wallet-lib -X-> ksp-config-lib +ksp-wallet-lib -X-> ksp-onchain-transport-lib +ksp-wallet-lib -X-> ksp-execution-policy-api +ksp-wallet-lib -X-> Store +ksp-wallet-lib -X-> Tauri +ksp-wallet-lib -X-> tracing direct +ksp-wallet-lib -X-> accès environnement direct +``` + +Le Wallet possède le stockage local, le déverrouillage, la projection autorisée, la signature et l'administration du wallet. Il ne possède aucune règle d'autorisation de dépense, de programme, de réseau, de simulation ou de plafond. + +## 3. Décisions antérieures conservées + +`pre.001` confirme sans les rouvrir : + +1. le suffixe natif est `.kspwallet` ; +2. aucune crate `ksp-wallet-api` séparée n'est créée dans l'architecture actuelle ; +3. `WalletPolicy` n'appartient pas au Wallet ; +4. le JSON temporaire bot2/bot3 n'est pas migré ; +5. `.kswallet` reste historique et ne devient pas un alias du nouveau format ; +6. les secrets Wallet ne transitent jamais par Config ; +7. Transport n'est pas requis par le cœur Wallet ; +8. l'import/export reste extensible mais limité aux formats prouvés utiles ; +9. les scénarios futurs pourront utiliser de vrais `.kspwallet` dédiés Devnet/tests ; +10. Wallet Desk reste `0.2.6` ; +11. `.kspwallet` est publiquement spécifiable et récupérable sans KSP ; +12. aucun pepper/global secret KSP n'est requis ; +13. Pubkey, alias et notes restent cachés wallet verrouillé ; +14. l'alias est interne et indépendant du filename ; +15. les notes sont des metadata protégées administrées par OWNER ; +16. `format_version` versionne le format, pas les éditions ; +17. les paramètres crypto nécessaires à la lecture sont sérialisés ; +18. VIEW et OWNER sont deux capacités indépendantes ; +19. OWNER ne dépend jamais de VIEW ; +20. VIEW compromis ne donne ni le secret Solana ni OWNER ; +21. rotation des passwords ne change pas la keypair ; +22. OWNER peut supprimer/recréer VIEW sans l'ancien password VIEW. + +Clarifications confirmées pendant la revue du gate : + +23. **`.kspwallet` V1 est entièrement autonome** : le fichier et le password correspondant sont les seuls éléments requis pour parser, vérifier l'intégrité sous son autorité OWNER embarquée, déverrouiller et récupérer les capacités prévues. V1 n'utilise et ne requiert aucun salt externe, pepper KSP, OTP, secret serveur, keychain, état machine, réseau ou ancre de confiance externe ; +24. la spécification finale est un document séparé `docs/formats/KSPWALLET_V1.md`, indépendant de l'implémentation Rust et suffisamment précis pour réimplémenter le format dans un autre langage sans lire `ksp-wallet-lib` ; +25. toute mutation persistante acceptée sous l'autorité d'un wallet V1 est **OWNER-authorized** : key slots, paramètres KDF, compartments, metadata et état de protection sont couverts par l'authentification OWNER ; VIEW reste incapable de forger un nouvel état valide sous cette même autorité ; +26. la keypair Solana est **immuable dans un wallet V1 après création/import**. V1 ne fournit pas d'opération de remplacement de keypair ; une autre keypair crée un autre wallet. + +## 4. Réaudit de l'héritage bot2/bot3 + +### 4.1 bot2 — `TemporaryWalletStore` + +L'archive historique contient un store de laboratoire basé sur le keypair JSON Solana 64 octets. Les propriétés utiles sont : validation stricte du keypair, no-clobber, permissions Unix `0700/0600`, effacement des buffers sérialisés et frontière `Signer` sans exposition publique des octets privés. + +Le format lui-même est **abandonné** pour KSP natif : il n'offre aucun chiffrement password et le prompt `0.2.5` exclut explicitement sa migration. + +### 4.2 bot3 — `ks-wallet` + +Le dernier `ks-wallet` historique fournit : + +```text +.kswallet / magic KSWALLET +format binaire V1 +Argon2id v19 +XChaCha20-Poly1305 +salt 16 octets +nonce 24 octets +un password unique +alias + Pubkey en clair dans le header +ciphertext exact d'un keypair Solana 64 octets +atomic create / replace +import/export Solana CLI JSON + Base58 +UnlockedWallet / signature +WalletPolicy historique +migration du JSON legacy +``` + +Ses defaults Argon2 historiques (`65536 KiB`, 3 passes, 4 lanes) sont seulement un fait d'archive ; ils ne deviennent **pas** les defaults KSP. + +### 4.3 Matrice de reprise + +| Élément historique | Décision `0.2.5` | Motif | +|----------------------------------------------------------|-----------------------------------------|---------------------------------------------------------| +| création `Keypair::new()` / key material standard Solana | réutiliser conceptuellement | primitive standard maintenue | +| validation stricte 64 octets + cohérence secret/pubkey | réutiliser conceptuellement | bon invariant d'import et de secret payload | +| frontière de signature sans getter secret | réutiliser conceptuellement | invariant de sécurité public | +| password owned, redacted, non-Clone | refondre | séparer `ViewPassword` / `OwnerPassword` | +| zeroization des buffers possédés | réutiliser conceptuellement | utile avec limites documentées | +| `spawn_blocking` pour Argon2 | réutiliser conceptuellement | KDF CPU/memory-bound hors executor async | +| CSPRNG OS | réutiliser conceptuellement | pas de RNG KSP maison | +| parsing borné + identifiants algo/version | réutiliser conceptuellement | indispensable au format hostile | +| AEAD + données associées | réutiliser conceptuellement | authentification locale du wire | +| temp-file + `sync_all` + publication atomique | refondre | préserver l'idée, durcir la portabilité | +| concurrent no-clobber : un seul créateur gagne | réutiliser conceptuellement | invariant de création | +| import Solana CLI JSON | réutiliser/refondre | format immédiatement utile | +| Base58 keypair complet | réutiliser/refondre | format générique Solana utile, sans l'étiqueter Phantom | +| `inspect_transfer_file` sans persister | réutiliser/refondre | projection sûre d'un import | +| `.kswallet` / magic `KSWALLET` | abandonner | nouveau contrat `.kspwallet` | +| alias dans filename/header | abandonner | alias interne indépendant du fichier | +| Pubkey/alias visibles verrouillé | abandonner | contradictoire avec les invariants KSP | +| password unique | abandonner | contradictoire avec VIEW/OWNER | +| chiffrement direct du keypair avec password | abandonner | rotations/capabilities exigent envelope keys | +| `WalletPolicy` | abandonner | responsabilité Execution Policy | +| JSON temporaire + migration legacy | abandonner | explicitement hors périmètre | +| logging `tracing` direct | abandonner | façade `ksp-logging-lib` obligatoire | +| mnemonics/hardware/remote/recovery | reporter | hors périmètre `0.2.5` | +| adapters propriétaires Backpack/Phantom/Solflare/Trust | reporter tant que wire exact non prouvé | ne pas coder par supposition | + +## 5. Threat model `.kspwallet` + +### 5.1 Attaquant avec copie du fichier + +Un détenteur d'une copie du fichier peut lancer des essais de passwords **hors ligne**, sans rate-limit serveur. La sécurité d'un password faible ne peut donc pas être promise. Le KDF memory-hard augmente le coût unitaire de chaque tentative ; il ne transforme pas une faible entropie humaine en secret fort. + +Les salts sont publics et indépendants. Leur rôle est d'empêcher la mutualisation efficace de précalculs entre wallets/slots ; ils ne sont ni un secret ni un pepper. + +### 5.2 Spécification et paramètres entièrement connus + +Le threat model suppose que l'attaquant connaît : + +```text +format exact +algorithmes +paramètres KDF +salts +nonces +ciphertexts +code source KSP +``` + +Le format ouvert n'est pas une faiblesse : la confidentialité repose sur les secrets d'accès et les primitives standard. + +### 5.3 VIEW compromis + +Avec seulement le password VIEW, l'attaquant peut légitimement lire : + +```text +Pubkey +alias +notes +``` + +Il ne doit pouvoir dériver ni : + +```text +OWNER KEK +owner root key +Solana secret/keypair +format-admin signing secret +``` + +L'API KSP VIEW ne conserve pas la metadata content key après déchiffrement ; elle expose une projection read-only et ne possède aucune méthode de signature ou d'administration. + +### 5.4 OWNER compromis + +OWNER donne volontairement la capacité complète : metadata, signature, administration et export secret explicitement demandé. Une rotation ultérieure du **password** OWNER retire l'ancien password du fichier courant, mais ne peut pas révoquer rétroactivement une `owner_root_key` qu'un OWNER malveillant aurait déjà exfiltrée. + +Une future opération de rekey cryptographique complet pourrait changer l'owner root et les content keys, mais elle n'est pas confondue avec `rotate_owner_password`. + +### 5.5 Modification partielle du fichier + +Les ciphertexts sont authentifiés par AEAD et l'état global accepté est couvert par l'authentification OWNER définie plus bas. Toute modification partielle d'un champ couvert doit provoquer un rejet déterministe sans exposer une cause crypto trop fine. + +### 5.6 Remplacement total / rollback + +Un attaquant capable de remplacer le fichier entier peut substituer : + +```text +owner auth public key +key slots +ciphertexts +state signature +``` + +par ceux d'un autre wallet valide. Un format autonome ne peut pas détecter cette substitution à partir d'une information de confiance stockée uniquement dans le fichier substitué. + +La même limite vaut pour un rollback complet vers une ancienne copie valide. Cette limite n'autorise **aucune dépendance externe en V1** : le format V1 reste volontairement auto-contenu et interdit comme prérequis tout salt externe, pepper, OTP, secret KSP, service distant, keychain ou ancre de confiance extérieure. Une éventuelle version de format future pourrait étudier un facteur/ancrage externe, mais ce mécanisme n'appartient ni au format V1 ni à `0.2.5`. + +### 5.7 Matrice des garanties + +| Garantie | Cryptographie fichier | Types/capabilities KSP | Filesystem | Ancre externe éventuelle, hors V1 | +|-------------------------------------------------------------------|----------------------:|-----------------------:|----------------------:|----------------------------------------------------------:| +| confidentialité metadata verrouillées | oui | oui | complément | non | +| confidentialité secret Solana face à VIEW | oui | oui | complément | non | +| indépendance VIEW/OWNER | oui | oui | non | non | +| VIEW ne signe pas | séparation de clés | oui | non | non | +| VIEW ne modifie pas via API | indirect | oui | non | non | +| metadata modifiées par VIEW détectées sous la même autorité OWNER | oui, state signature | oui | non | non | +| détection corruption/tampering partiel | oui | parsing strict | complément | non | +| no-clobber / atomic replace | non | API | oui | non | +| protection autres users OS | non | non | best-effort | non | +| détection remplacement total valide | non | non | permissions seulement | théoriquement oui, mais **interdite comme dépendance V1** | +| détection rollback total valide | non | non | non | théoriquement oui, mais **interdite comme dépendance V1** | + +## 6. Niveau B — VIEW read-only renforcé cryptographiquement + +`pre.001` retient **B**. + +Le wallet possède une **clé d'administration Ed25519 propre au format**, distincte de la keypair Solana. Sa clé publique de vérification est dans l'enveloppe minimale ; sa clé privée est accessible seulement par OWNER. + +Chaque état persistant valide porte une `state_signature` OWNER calculée sur un transcript déterministe de **tout l'état mutable et de sécurité du fichier**, à l'exception de la signature elle-même : magic/version, autorité publique, key slots et leurs paramètres KDF/wrapping, versions de compartments, algorithmes, nonces et ciphertexts. Toute opération qui change le fichier doit donc être réalisée depuis une capacité OWNER capable de récupérer la clé privée d'administration et de produire une nouvelle signature valide. + +Conséquence : un détenteur VIEW qui aurait conservé la metadata content key peut techniquement produire un nouveau ciphertext metadata, mais il ne peut pas produire, sous la même autorité OWNER, une nouvelle `state_signature` acceptée. Il ne peut pas davantage modifier un key slot, changer un password, remplacer le compartment secret ou substituer la keypair tout en conservant un état accepté sous l'autorité OWNER originale. + +La cryptographie ne peut pas empêcher un attaquant disposant d'un accès écriture filesystem de modifier physiquement les octets ; elle garantit que ces octets modifiés sont **rejetés** faute d'authentification OWNER valide. Les permissions filesystem complètent cette propriété en empêchant l'écriture lorsque l'OS peut effectivement l'interdire. + +Limite incompressible : une substitution du **fichier entier** par un autre wallet auto-cohérent, incluant une nouvelle autorité publique OWNER et une nouvelle signature valide, est indétectable par le seul fichier substitué. Cela reste vrai en particulier si l'attaquant connaît le password VIEW et crée le faux wallet avec ce même password. Détecter cette substitution ou un rollback intégral exigerait de comparer à un état de confiance conservé ailleurs ; V1 n'en dépend pas et ne prétend donc pas fournir cette garantie. + +La keypair Solana **n'est pas** réutilisée comme clé d'administration du format. + +### 6.1 Garantie d'intégrité V1 sous l'autorité OWNER originale + +Sans password OWNER ni clé privée d'administration exfiltrée, un attaquant — y compris s'il connaît le format complet et le password VIEW — ne peut pas produire un état accepté sous l'autorité OWNER originale qui : + +```text +modifie Pubkey / alias / notes +modifie un paramètre KDF, salt, nonce ou wrapped key +remplace / supprime / ajoute un key slot +change le password VIEW ou OWNER +remplace le compartment secret +swap la keypair Solana +change les versions/algorithmes couverts +``` + +Le parseur applique d'abord les bornes structurelles/anti-DoS, puis vérifie la `state_signature` avant tout déverrouillage coûteux ou projection autorisée. Une mutation non signée est un fichier invalide, pas un nouvel état Wallet. + +Cette garantie est volontairement formulée « sous l'autorité OWNER originale » afin de ne pas confondre **forgery/tampering** avec la substitution totale d'un fichier auto-signé par une autre autorité. + +## 7. Architecture de clés V1 + +### 7.1 Matériaux aléatoires + +À la création : + +```text +K_owner_root 32 octets aléatoires +K_metadata 32 octets aléatoires +K_secret 32 octets aléatoires +admin_signing_key clé Ed25519 distincte +``` + +### 7.2 Key slots + +```text +password VIEW + -> Argon2id(params_view, salt_view) + -> KEK_view + -> slot VIEW + -> wrap K_metadata seulement + +password OWNER + -> Argon2id(params_owner, salt_owner) + -> KEK_owner + -> slot OWNER + -> wrap K_owner_root seulement +``` + +Les salts et paramètres sont indépendants par slot. V1 autorise : + +```text +exactement 1 slot OWNER +0 ou 1 slot VIEW +``` + +Le wire utilise néanmoins un tableau générique `key_slots` afin qu'un futur `format_version` puisse introduire d'autres rôles sans remodeler toute l'enveloppe. + +### 7.3 Compartiment OWNER control + +Chiffré avec `K_owner_root`, il contient au minimum : + +```text +control_version +K_metadata +K_secret +admin_signing_secret +``` + +OWNER peut donc accéder à metadata/secret et gérer VIEW sans dépendre du slot VIEW. + +### 7.4 Compartiment metadata + +Chiffré avec `K_metadata` : + +```text +metadata_version +Solana Pubkey +alias optionnel +notes +``` + +VIEW et OWNER peuvent le déchiffrer. + +### 7.5 Compartiment secret + +Chiffré avec `K_secret` : + +```text +secret_version +Solana keypair material +``` + +Seul OWNER reçoit `K_secret` via le control compartment. + +### 7.6 Rotation et révocation + +Il faut distinguer : + +**rotation de password VIEW** : nouveau salt/KDF/KEK et nouveau wrapping du même `K_metadata`. L'ancien password ne déverrouille plus le fichier courant, mais cette opération ne révoque pas une `K_metadata` déjà exfiltrée par un VIEW malveillant. + +**révocation/recréation forte de VIEW** : OWNER génère une nouvelle `K_metadata`, rechiffre les metadata, met à jour le control compartment puis crée ou retire le slot VIEW. Une ancienne `K_metadata` ne lit alors plus les **futurs** états metadata. Les anciennes copies du wallet restent naturellement lisibles par qui en possédait déjà les secrets. + +**rotation du password OWNER** : nouveau salt/KDF/KEK et nouveau wrapping de `K_owner_root`, sans changement de keypair Solana ni dépendance à VIEW. + +**keypair Solana** : immuable dans V1 après création/import. Aucun `replace_keypair` n'est exposé. Toute tentative de modifier `secret` ou la Pubkey metadata sans une réécriture OWNER valide échoue sur la `state_signature`; même avec OWNER, l'import d'une autre keypair crée un nouveau `.kspwallet` au lieu de muter l'identité cryptographique existante. + +## 8. Primitives et dépendances réauditées le 2026-08-18 + +Aucune dépendance ci-dessous n'est ajoutée dans `pre.001`. Ce sont les candidates pour les tranches qui les consommeront réellement. + +### 8.1 Solana low-level + +| Besoin | Crate publiée auditée | Décision candidate | +|------------------|--------------------------|--------------------------------------------------------| +| Pubkey | `solana-pubkey 4.3.0` | déjà workspace, conserver | +| keypair concret | `solana-keypair 3.1.2` | retenir, features minimales | +| interface signer | `solana-signer 3.0.1` | retenir si contrat public/impl l'exige | +| signature | `solana-signature 3.5.2` | dépendance directe seulement si le type public l'exige | + +`solana-keypair` fournit le keypair Ed25519, la conversion stricte depuis 64 octets, la signature, le format JSON de 64 entiers et une représentation Base58 complète. Aucun client RPC Solana n'est nécessaire. + +La génération SDK récente définit `Pubkey` comme alias du type `Address`, mais l'écosystème a déjà connu des incompatibilités lorsque plusieurs générations de `solana-address` coexistent. `pre.002` doit donc prouver par compilation/cargo-tree que le `Pubkey` possédé par `ksp-core-lib` et le `Address/Pubkey` exposé par `solana-keypair` sont de la même génération avant de figer les signatures publiques Wallet. Aucun second type d'adresse KSP n'est introduit pour contourner un mismatch. + +Un `cargo tree` est obligatoire lors de l'introduction réelle afin de contrôler les versions `ed25519-dalek`, `solana-signature`, `rand/getrandom` et éviter des duplications évitables. + +Audit source notable : `solana-keypair 3.1.2` contient un bloc `unsafe` interne dans sa conversion Base58 vers `String`. Cela ne modifie pas la règle `#![forbid(unsafe_code)]` du code KSP, mais doit rester visible dans l'audit des transitifs ; `pre.008` réévaluera le chemin Base58 réellement appelé et les alternatives avant de figer l'adapter. + +### 8.2 KDF + +| Primitive | Version publiée auditée | Décision V1 | +|-----------|------------------------:|--------------------------------------------| +| Argon2 | `0.5.3` | **retenu : Argon2id v19** | +| scrypt | `0.12.0` | alternative maintenue, non ajoutée | +| PBKDF2 | `0.13.0` | compatibilité/legacy seulement, non ajouté | + +Les paramètres Argon2 de création seront benchmarkés sur les machines cibles. Ils ne sont pas copiés de bot3, d'un RFC ou d'un default de crate. Le fichier sérialise tous les paramètres nécessaires afin qu'un ancien wallet conserve son profil historique. + +Le parseur impose des **bornes maximales** avant de lancer le KDF, afin qu'un fichier hostile ne puisse demander arbitrairement mémoire/CPU. Les valeurs exactes de création et de rejet sont gelées en `pre.004` après benchmark. + +### 8.3 AEAD + +| Primitive | Version publiée auditée | Décision V1 | +|--------------------|--------------------------:|------------------| +| XChaCha20-Poly1305 | `chacha20poly1305 0.11.0` | **retenu** | +| AES-256-GCM-SIV | `aes-gcm-siv 0.12.0` | non retenu en V1 | + +XChaCha20-Poly1305 fournit une clé 256 bits et un nonce étendu 192 bits. Un nonce neuf est généré pour chaque wrapping/chiffrement. La crate RustCrypto documente un audit NCC Group sans constat significatif. + +AES-GCM-SIV apporte une meilleure tolérance à la réutilisation accidentelle de nonce que GCM classique, mais la crate RustCrypto courante indique ne pas avoir elle-même fait l'objet d'un audit de sécurité. V1 n'a pas besoin de deux AEAD : la seconde primitive est donc écartée sans créer de dépendance concurrente. + +### 8.4 CSPRNG + +`getrandom 0.4.3` est retenu comme candidate low-level pour les octets aléatoires propres au format. Les API de génération de keypair Solana restent libres d'utiliser leur CSPRNG interne maintenu. + +### 8.5 Secret memory + +`zeroize 1.9.0` est retenu. `secrecy` n'est pas ajouté tant qu'un besoin ergonomique concret n'est pas démontré ; des types KSP simples peuvent imposer eux-mêmes redaction/non-Clone et utiliser `Zeroize`/`Zeroizing`. + +Pour la clé admin Ed25519 distincte, `ed25519-dalek 3.0.0` est une candidate standard, mais son ajout direct est **conditionné au cargo-tree** de la tranche qui implémente l'authentification afin d'éviter une génération concurrente inutile avec celle déjà tirée par `solana-keypair`. + +### 8.6 État des audits de sécurité publics + +Le gate ne généralise pas une absence d'audit à partir du silence d'une page de crate. Il enregistre seulement les assertions primaires explicitement retrouvées : + +```text +chacha20poly1305 audit NCC Group documenté, sans constat significatif +aes-gcm-siv crate documentant explicitement qu'aucun audit de cette crate n'a été réalisé +ed25519-dalek documentation courante mettant en avant zeroization/constant-time/forbid unsafe du crate direct +argon2/scrypt/... maintenance et versions réauditées ; statut d'audit à réexaminer avant ajout si aucune source primaire explicite n'est jointe +``` + +L'absence d'une ligne « audited » dans ce document ne signifie donc pas « sûr par absence de preuve » ; chaque dépendance sensible reste soumise à un réaudit au moment de son introduction. + +### 8.7 Encodage et persistence + +Candidates : + +```text +base64 0.23.1 pour Base64url sans padding des champs binaires JSON +tempfile 3.27.0 pour temp files privés same-directory + persist/persist_noclobber +``` + +Elles ne sont ajoutées que lorsqu'elles sont réellement consommées. + +## 9. Format natif `.kspwallet` V1 + +### 9.1 Choix wire + +V1 retient une **enveloppe JSON UTF-8 stricte**. Objectifs : + +```text +interopérabilité multi-langages immédiate +inspection structurelle simple sans secret +aucune dépendance endianness pour la grammaire JSON +champs crypto explicites et auto-descriptifs +fixtures/vecteurs lisibles +``` + +Les champs binaires sont encodés en **Base64url sans padding**. + +Le fichier JSON n'est **jamais** signé comme octets JSON bruts et aucune canonicalisation JSON externe n'est requise. + +### 9.2 Enveloppe conceptuelle + +Structure de travail à figer par le codec `pre.003` : + +```json +{ + "magic": "KSPWALLET", + "format_version": 1, + "owner_auth_public_key": "", + "key_slots": [ + { + "role": "owner|view", + "kdf": { + "algorithm": "argon2id", + "version": 19, + "memory_kib": 0, + "iterations": 0, + "parallelism": 0, + "salt": "" + }, + "wrap": { + "algorithm": "xchacha20-poly1305", + "nonce": "", + "ciphertext": "" + } + } + ], + "owner_control": { + "algorithm": "xchacha20-poly1305", + "nonce": "", + "ciphertext": "" + }, + "metadata": { + "algorithm": "xchacha20-poly1305", + "nonce": "", + "ciphertext": "" + }, + "secret": { + "algorithm": "xchacha20-poly1305", + "nonce": "", + "ciphertext": "" + }, + "state_signature": { + "algorithm": "ed25519", + "signature": "" + } +} +``` + +Les `0` ci-dessus signifient « valeur déterminée par le benchmark futur », pas des paramètres valides. + +### 9.3 Informations visibles wallet verrouillé + +Autorisé : + +```text +magic +format_version +identifiants crypto +paramètres KDF +salts +nonces +wrapped keys/key slots +ciphertexts +owner_auth_public_key +state_signature +présence ou absence d'un slot VIEW +``` + +Interdit en clair : + +```text +Solana Pubkey +alias +notes +Solana secret/keypair +admin signing secret +content keys +password-derived keys +``` + +La clé publique d'administration révèle un fingerprint aléatoire du **format wallet**, pas l'identité blockchain Solana. Elle constitue la racine de vérification **embarquée** de l'état sous la même autorité OWNER ; sa présence ne crée aucune dépendance à un facteur externe. + +### 9.4 Pubkey et secret payload + +Dans le compartiment metadata, la Pubkey est représentée par sa chaîne Base58 Solana canonique. Le parseur doit pouvoir vérifier `parse -> re-encode == input`. + +Dans le compartiment secret, V1 conserve le keypair Solana exact 64 octets. L'ouverture OWNER vérifie systématiquement : + +```text +keypair 64 octets valide +Pubkey dérivée du secret == Pubkey metadata +``` + +### 9.5 Alias et notes + +Décisions de bornes initiales à implémenter/tester : + +```text +alias optionnel <= 256 octets UTF-8 +notes <= 64 entrées +texte d'une note <= 8 KiB UTF-8 +metadata plaintext total <= 64 KiB +fichier .kspwallet total <= 1 MiB +password encodé UTF-8 <= 1024 octets +``` + +Une note V1 possède : + +```text +id = 16 octets aléatoires, Base64url sans padding +data = texte UTF-8 protégé +``` + +L'ID facilite update/delete sans rendre le texte lui-même identifiant. Les bornes restent vérifiables pendant `pre.003`; toute modification avant freeze wire doit être tracée. + +### 9.6 Password text contract + +V1 définit le KDF input comme les **octets UTF-8 exacts** du password fourni. Aucune normalisation Unicode implicite n'est appliquée. La documentation d'interop doit rendre ce point explicite. + +La création refuse un password vide. L'API peut construire des wrappers depuis des octets ou un texte UTF-8, mais ne doit pas conserver un `String` en clair au-delà de la dérivation nécessaire. + +### 9.7 Strictness / unknown fields + +V1 : + +```text +magic inconnu rejet +format_version inconnu rejet explicite +champ top-level inconnu rejet +champ crypto/slot inconnu rejet +role slot inconnu rejet +slot OWNER dupliqué/absent rejet +slot VIEW dupliqué rejet +valeur enum/algo inconnue rejet +base64 non canonique rejet +trailing data non whitespace rejet +fichier hors bornes rejet avant crypto coûteuse +``` + +L'extensibilité se fait par un nouveau `format_version`, pas par une tolérance silencieuse qui changerait le sens de données authentifiées. + +### 9.8 Versionnement protégé + +`format_version` reste la version de l'enveloppe/wire/crypto/transcript. Il n'est pas incrémenté pour une rotation ou une édition metadata. + +`pre.001` **ne retient pas un unique `payload_version` global**. Les trois compartiments évoluent indépendamment et portent plutôt : + +```text +control_version +metadata_version +secret_version +``` + +Une évolution locale d'un payload protégé pourra ainsi être migrée explicitement sans prétendre que l'enveloppe entière change nécessairement de grammaire. + +Aucune migration automatique mutante n'est exécutée lors d'un simple `open`. Toute migration future est explicite, OWNER-authorized, testable et atomique. + +### 9.9 Checksum + +Pas de checksum séparé V1 : AEAD protège chaque ciphertext et la `state_signature` protège l'état sémantique global accepté sous l'autorité OWNER. Un checksum supplémentaire ne fournit pas de garantie de sécurité utile. + +## 10. Authentification, transcript et AAD + +### 10.1 Pas de signature des octets JSON + +La signature d'état porte sur un **transcript binaire déterministe** construit après parsing strict, avec : + +```text +domain separation KSPWALLET-V1-STATE +ordre de champs fixé par la spec +longueurs explicites +entiers en big-endian +octets binaires décodés, pas leurs représentations Base64 texte +rôle/algorithme/version inclus +chaque KDF param/salt/nonce/ciphertext inclus +state_signature elle-même exclue +``` + +Une réindentation ou un ordre JSON différent qui se parse vers le même état sémantique n'exige donc pas une canonicalisation JSON pour vérifier la signature. + +### 10.2 AEAD AAD + +Chaque opération de wrapping/chiffrement utilise un AAD domain-separated incluant au minimum : + +```text +magic/format_version +owner_auth_public_key +kind de compartiment ou rôle de slot +identifiants algo/version pertinents +paramètres publics nécessaires à lier le ciphertext à son contexte +``` + +Le layout exact du transcript et de chaque AAD devient normatif dans `docs/formats/KSPWALLET_V1.md` et dans les vecteurs déterministes. + +## 11. Secret en mémoire + +Contrat : + +```text +ViewPassword / OwnerPassword non Copy, non Clone par défaut, Debug redacted +WalletView aucune key de secret et aucune metadata key retenue +WalletOwner secret/root/admin keys privés, sans getter raw public +secret/key buffers temporaires Zeroizing/Zeroize lorsque possédés +message signé jamais loggé +password détruit dès que la KDF n'en a plus besoin +``` + +`WalletOwner::sign()` permet la signature sans export du secret brut. + +Une exportation secrète n'existe que comme opération OWNER explicitement nommée via un adapter de transfert. Elle ne crée pas de méthode de commodité `secret() -> Vec`. + +### Limites de zeroization + +KSP peut garantir que ses buffers possédés explicitement zeroizables exécutent leur effacement de drop et éviter les clones volontaires. KSP ne promet pas d'effacer : + +```text +registres CPU +copies internes de bibliothèques tierces +copies transitoires produites par l'allocateur/runtime +swap/core dumps +copies déjà exfiltrées par un processus compromis +``` + +Le threat model ne transforme donc pas `zeroize` en garantie de mémoire secrète absolue. + +## 12. API publique à concevoir en `pre.002` + +Responsabilités proposées, noms encore ajustables : + +```text +LockedWalletInfo +WalletInfo +WalletNote +WalletView +WalletOwner +ViewPassword +OwnerPassword +WalletCreateOptions +WalletCapability +``` + +Surface conceptuelle : + +```rust +inspect(path) -> LockedWalletInfo +create(path, owner_password, optional_view_password, options) -> WalletOwner +open_view(path, view_password) -> WalletView +open_owner(path, owner_password) -> WalletOwner +``` + +`WalletView` : + +```text +pubkey() +alias() +notes() +info() +``` + +Aucune méthode de mutation/signature/export secret/key-slot. + +`WalletOwner` : + +```text +pubkey()/alias()/notes()/info() +sign(message) +update_alias(...) +add_note(...) +update_note(...) +delete_note(...) +rotate_view_password(...) +disable_view() +recreate_view(...) +rotate_owner_password(...) +export_with(...) +``` + +Les mutations persistées sont async et atomiques. `sign()` est locale/CPU et reste naturellement sync. + +## 13. Async / sync + +Séparation retenue : + +```text +filesystem public API async-first +KDF Argon2 spawn_blocking +codec/AEAD local sync interne, enveloppé par flux async +signature locale sync +atomic persistence blocking OS work isolé hors executor async si nécessaire +``` + +La crate peut donc être utilisée depuis Tauri plus tard sans dépendre de Tauri et sans bloquer naïvement un executor Tokio avec Argon2. + +## 14. Persistence + +### 14.1 Baseline portable + +Pour créer/remplacer un `.kspwallet` : + +1. sérialiser complètement le nouvel état en mémoire bornée ; +2. créer un temp file privé **dans le même répertoire** que la destination ; +3. écrire tout le contenu ; +4. `flush`/`sync_all` le temp file ; +5. publier avec une primitive no-clobber pour `create` ou replace pour administration ; +6. synchroniser le répertoire parent lorsque la plateforme le permet ; +7. ne jamais considérer un fichier partiellement écrit comme nouveau wallet valide. + +`tempfile::NamedTempFile`/`persist_noclobber`/`persist` est la candidate de `pre.006`, complétée par les fsync nécessaires. Sa sémantique exacte doit être testée par plateforme avant de revendiquer la durabilité crash-safe. + +### 14.2 No-clobber + +`create` ne fait jamais d'overwrite implicite. En concurrence, un seul créateur peut publier la destination ; les autres reçoivent `destination_exists`. + +### 14.3 Unix + +Durcissement visé : + +```text +wallet file créé par KSP 0600 +répertoire dédié créé par KSP 0700 +``` + +KSP ne change pas arbitrairement les permissions d'un parent fourni par l'appelant. + +Les sources secrètes d'import doivent être des fichiers réguliers et les symlinks sont refusés par défaut pour réduire les ambiguïtés/TOCTOU usuelles. La stratégie exacte est testée dans la tranche persistence/import. + +### 14.4 Autres plateformes + +Aucune promesse POSIX `0600/0700` sur Windows. La documentation distingue garanties portables, ACL/permissions système et durcissement Unix. + +Un crash peut laisser un temp artifact complet à nettoyer ; l'invariant prioritaire est de ne pas transformer l'ancien wallet valide en fichier partiellement remplacé. + +## 15. Erreurs et non-oracle + +Le domaine KSP commun reste `ksp-core-lib::ErrorCode/Error/Result`. + +Catégories de travail : + +```text +wallet.format_invalid +wallet.format_version_unsupported +wallet.crypto_parameters_invalid +wallet.authentication_failed +wallet.view_unlock_failed +wallet.owner_unlock_failed +wallet.capability_insufficient +wallet.io_failed +wallet.destination_exists +wallet.atomic_persistence_failed +wallet.transfer_format_unsupported +wallet.key_material_invalid +wallet.signature_failed +``` + +Les erreurs de structure publiques peuvent être précises. Une fois une tentative de déverrouillage cryptographique engagée, mauvais password, tag AEAD invalide et key unwrap invalide ne doivent pas devenir un oracle détaillé inutile : la cause externe est regroupée par rôle/opération. + +Jamais dans message/context/source reformaté volontairement : + +```text +password +secret/keypair bytes +seed phrase +KDF input +plaintext secret +ciphertext complet +notes/alias par défaut +``` + +## 16. Logging + +Cible KSP future proposée : + +```text +ksp.wallet +``` + +Via `ksp-logging-lib` uniquement. + +Événements sûrs : + +```text +operation=create/open_view/open_owner/rotate/sign/import/export +capability=view|owner +format_version +transfer format code +success/failure category +duration +``` + +Pas de full path/filename par défaut dans les logs Wallet ; le caller peut corréler l'opération à son propre contexte applicatif. Ne jamais logger password, secret, payload signé, contenu complet, ciphertext complet, alias ou notes, même en trace. + +## 17. Import/export extensible + +### 17.1 Architecture + +Le cœur ne doit pas utiliser un enum central fermé qui oblige à modifier toutes les branches à chaque nouveau format. + +`pre.008` doit introduire un contrat d'adapter/descriptor ouvert avec un code stable et des implémentations built-in enregistrables. L'import et l'export sont séparables pour qu'un format read-only n'implémente pas artificiellement l'autre sens. + +Toute API d'export qui remet temporairement du key material à un adapter est explicitement OWNER-only, nommée dangereusement et limite la durée de vie de la copie via zeroization. Aucun getter secret général n'est introduit. + +### 17.2 Formats engagés pour `0.2.5` + +Minimum retenu : + +```text +solana-cli-json tableau strict de 64 u8 +solana-keypair-base58 Base58 du keypair complet 64 octets +``` + +Le second nom reste générique : `pre.001` ne l'appelle pas « Phantom » ou « Solflare » sans spécification wire normative prouvant une équivalence contractuelle. + +Ces deux formats suffisent à démontrer import, export, inspection et extensibilité sans dépendance propriétaire. + +### 17.3 Formats audités mais reportés + +```text +Phantom +Solflare +Backpack +Trust Wallet +mnemonic/seed phrase +hardware/remote signer +``` + +Ils peuvent être ajoutés ultérieurement uniquement après réaudit du wire réel et du threat model correspondant. + +## 18. Interopérabilité externe + +La release doit créer/finaliser une **spécification séparée de l'implémentation Rust** : + +```text +docs/formats/000-README.md +docs/formats/KSPWALLET_V1.md +``` + +Comme `docs/formats/` n'existe pas encore dans `v0.2.4`, son premier ajout doit respecter `FILE_CONTRACTS.md` : le contrat documentaire de cette nouvelle famille et l'index `docs/000-README.md` sont mis à jour dans la même tranche qui introduit la première spec (`pre.003` au plus tard). + +`KSPWALLET_V1.md` est l'autorité normative du wire V1. Il ne doit pas renvoyer à un type Rust ou au code source comme condition nécessaire pour comprendre le format. Une implémentation indépendante en Python, Go, C/C++, Java, Rust ou autre doit pouvoir créer, vérifier, ouvrir VIEW/OWNER et effectuer les rotations définies à partir de cette seule spécification et des vecteurs publics. + +La spec normative contiendra : + +```text +JSON schema grammaticale exacte +encodages Base64url/Base58/UTF-8 +KDF et paramètres sérialisés +key wrapping et compartiments +AAD exacts +transcript state signature exact +big-endian/length prefixes du transcript +règles strictes de parsing +bornes +VIEW open +OWNER open +rotations/revocation VIEW +rotation OWNER +migration/versioning +limites anti-substitution/rollback +``` + +### 18.1 Vecteurs publics déterministes + +Les fixtures publieront volontairement : + +```text +Solana secret/keypair TEST-ONLY connu +admin key TEST-ONLY connue +password VIEW connu +password OWNER connu +salts/nonces/content keys déterministes +metadata attendues +KDF outputs attendus +wrapped keys attendues +ciphertexts attendus +state transcript attendu +state signature attendue +fichier .kspwallet final attendu +projection VIEW/OWNER attendue +signature Solana d'un message test attendu +``` + +Les vecteurs sont explicitement **insecure / tests only** et ne servent jamais de wallet de production. Ils sont auto-contenus : aucun secret, salt, pepper, OTP, fichier annexe ou état KSP non publié n'est requis pour reproduire les résultats. + +L'injection de random déterministe reste privée aux tests/codec fixtures ; l'API production ne permet pas au caller de remplacer silencieusement le CSPRNG. + +## 19. Tests de sécurité et contrat + +### 19.1 Format + +- round-trip natif ; +- magic/version ; +- unknown fields/version rejetés ; +- troncation, trailing bytes, types, Base64, tailles rejetés ; +- tampering partiel détecté ; +- aucun secret/Pubkey/alias/note en clair ; +- paramètres KDF/crypto complets ; +- transcript/vecteurs externes reproductibles. + +### 19.2 VIEW/OWNER + +- VIEW lit seulement metadata autorisées ; +- aucune signature/mutation/admin/export via type VIEW ; +- OWNER fonctionne sans VIEW ; +- OWNER signe et administre ; +- mauvais rôle/password échoue sans fuite ; +- salts/KDF material indépendants ; +- VIEW ne dérive pas OWNER/secret ; +- modification metadata par détenteur VIEW sans admin signing key rejetée ; +- modification d'un key slot/KDF/wrapped key par détenteur VIEW rejetée ; +- tentative de changer password VIEW/OWNER sans OWNER rejetée ; +- substitution du ciphertext secret/keypair sans OWNER rejetée ; +- `state_signature` invalide/manquante rejetée avant projection ; +- substitution totale explicitement non promise. + +### 19.3 Rotation/revocation + +- rotation VIEW conserve keypair/Pubkey ; +- old password VIEW n'ouvre plus le slot courant ; +- rotation OWNER conserve keypair/Pubkey ; +- old password OWNER n'ouvre plus le slot courant ; +- disable/recreate VIEW ne nécessite pas ancien password VIEW ; +- recreate VIEW forte change `K_metadata` ; +- anciennes copies restent hors de la promesse de révocation ; +- paramètres KDF historiques restent lisibles après changement des defaults. + +### 19.4 Secret/diagnostics + +- `Debug`/projection/error/log sans secret ; +- wrappers secrets non `Copy` et non `Clone` par défaut ; +- VIEW ne matérialise jamais le keypair ; +- signature sans getter secret ; +- zeroization testée seulement là où observable honnêtement. + +### 19.5 Persistence + +- create ; +- destination existante ; +- concurrence no-clobber ; +- replace atomique ; +- fault injection avant publication préserve l'ancien wallet ; +- permissions Unix ; +- symlink/source handling ; +- éventuels temp remnants documentés sans corruption du wallet publié. + +### 19.6 Architecture + +- canary crate-root ; +- Wallet -X-> Config/Transport/ExecutionPolicy/Store/Tauri ; +- Wallet -X-> `tracing` direct ; +- aucun env direct ; +- aucun `unsafe` KSP ; +- cargo-tree sans duplication crypto injustifiée. + +## 20. Sizing + +| Domaine | Taille | Risque principal | +|-------------------------------|-------:|----------------------------------------------| +| crate/API foundation | M | capability surface durable | +| threat model | M | faux niveau de garantie | +| format wire | L | strict parsing/versioning | +| interop/test vectors | L | transcript exact multi-langages | +| KDF/AEAD/key wrapping | L | paramètres + nonce/AAD | +| VIEW/OWNER key slots | XL | indépendance et rotations | +| auth crypto metadata niveau B | L/XL | clé admin + transcript + substitution limits | +| persistence | L | no-clobber + crash semantics multi-OS | +| signing | M | aucun secret getter | +| password/key-slot rotation | L | rotation vs vraie révocation | +| alias/notes | M | bornes + persistence | +| import/export | M/L | extension sans secret API générale | +| security/adversarial tests | XL | tamper/fault/diagnostics | +| spec/README/USAGE | L | contrat externe autonome | + +Conclusion : **pas de rescoping fonctionnel**, mais split supplémentaire avant crypto lourde. + +## 21. Prévision souple révisée + +```text +pre.001 audit bot2/bot3 + deps actuelles + threat model + VIEW/OWNER + format/API + sizing +pre.002 crate foundation + capability/password/info types + erreurs + logging contract + canaries architecture +pre.003 codec JSON strict + limites + key-slot/envelope DTOs + transcript/AAD codec + contrat docs/formats + spec V1 initiale +pre.004 benchmark KDF + Argon2id/XChaCha wrapping + content keys + deterministic crypto vectors in-memory +pre.005 owner-control + metadata/secret compartments + create/open VIEW/OWNER + state signature niveau B +pre.006 persistence async/atomic/no-clobber + Unix hardening + fault/concurrency tests +pre.007 signature Solana + alias/notes + rotations passwords + disable/recreate VIEW avec rekey metadata +pre.008 import/export adapters + Solana CLI JSON + generic keypair Base58 + inspect +pre.009 audit security/interoperability/compliance + adversarial vectors/tests + cargo trees +pre.010 spec finale + README/USAGE + graphes/docs + candidate de clôture + prompt 0.2.6 +rel.001 publication strictement publicationnelle +``` + +Une `fix` ou tranche supplémentaire est préférable à la suppression d'une garantie sécurité si un des gates révèle une incompatibilité. + +## 22. Dépendances candidates par tranche + +Aucune ajoutée en `pre.001`. + +Liste de travail, à réauditer juste avant insertion sous `[workspace.dependencies]` : + +```text +argon2 ^0.5 +base64 ^0.23 +chacha20poly1305 ^0.11 +ed25519-dalek ^3.0 # seulement si cargo-tree justifie le direct +getrandom ^0.4 +solana-keypair ^3.1 +solana-signer ^3.0 # si réellement nécessaire directement +solana-signature ^3.5 # seulement si le type public l'exige +tempfile ^3.27 +zeroize ^1.9 +``` + +Déjà présents et réutilisables : + +```text +serde +serde_json +tokio +solana-pubkey +ksp-core-lib +ksp-logging-lib +``` + +Non retenus nativement en V1 : + +```text +scrypt +pbkdf2 +aes-gcm-siv +secrecy +bs58 +Solana RPC clients +Config/Store/Tauri +``` + +Le fait que `bs58` ne soit pas requis sera révalidé lorsque les adapters sont codés : `solana-keypair` fournit déjà la conversion Base58 du keypair complet. + +## 23. Sources externes réauditées + +Sources primaires consultées le 2026-08-18 : + +```text +https://docs.rs/solana-keypair/3.1.2/ +https://docs.rs/solana-signer/3.0.1/ +https://docs.rs/solana-pubkey/4.3.0/ +https://docs.rs/solana-signature/latest/ +https://docs.rs/argon2/0.5.3/ +https://docs.rs/scrypt/0.12.0/ +https://docs.rs/pbkdf2/0.13.0/ +https://docs.rs/chacha20poly1305/0.11.0/ +https://docs.rs/aes-gcm-siv/0.12.0/ +https://docs.rs/getrandom/0.4.3/ +https://docs.rs/zeroize/1.9.0/ +https://docs.rs/ed25519-dalek/3.0.0/ +https://docs.rs/base64/0.23.1/ +https://docs.rs/tempfile/3.27.0/ +``` + +Les versions sont des constats d'audit du gate, pas des dépendances ajoutées par ce delta. Chaque tranche réaudite sa candidate au moment où elle devient réellement consommée. + +## 24. Critères de sortie `0.2.5` + +La release n'est clôturable que si : + +```text +.kspwallet V1 est entièrement autonome : fichier + password suffisent, sans facteur/ancre externe +KSPWALLET_V1.md permet une implémentation indépendante sans consulter le code Rust +.kspwallet V1 est spécifié hors code et couvert par vecteurs publics auto-contenus +VIEW/OWNER sont indépendants cryptographiquement et dans l'API +Pubkey/alias/notes restent cachés verrouillé +VIEW ne peut pas signer/admin/exporter via l'API +niveau B rejette toute mutation de l'état couvert sous la même autorité OWNER sans signature OWNER valide +VIEW connu ne permet ni changement de password/key slot ni swap de keypair sous l'autorité OWNER originale +limite substitution/rollback complet est documentée sans surpromesse +keypair V1 est immuable après création/import +rotation password ne change pas keypair +OWNER gère VIEW sans ancien password VIEW +révocation forte VIEW rekey les metadata futures +sign() n'exige pas d'extraction publique du secret +persistence no-clobber/atomique respecte le contrat documenté +interop Solana CLI JSON + Base58 est prouvée +aucun Config/Transport/Policy/Store/Tauri/env/tracing direct ne fuit dans Wallet +cargo tree et diagnostics secrets sont audités +README/USAGE/spec/vecteurs sont cohérents +``` + +## 25. Hors périmètre confirmé + +```text +ksp-app-wallet-desk +balance/réseau +HTTP/WebSocket/gRPC +WalletPolicy / execution policy +construction/simulation/envoi transaction +Store +seed phrase UI +hardware wallet/Ledger +remote signer +browser/mobile/cloud custody +trading +recovery slot réel +hardware/automation slots réels +anti-rollback externe +salt/pepper externe requis par le format V1 +OTP / second facteur externe requis par le format V1 +ancre de confiance externe requise par le format V1 +``` + +Une future `format_version >= 2` pourra réétudier des facteurs/ancrages externes, mais cette piste n'est ni conçue ni implémentée dans `0.2.5`. + +## 26. Suite immédiate + +`0.2.5-pre.002` crée seulement la foundation de `ksp-wallet-lib` : boundaries Cargo, types de capability/password/info, erreurs, façade logging et canaries architecturales. Le codec et la cryptographie du fichier restent à `pre.003+`.