# `ksp-wallet-lib` Statut : **stable depuis KSP `0.2.5`**. `ksp-wallet-lib` est la bibliothèque KSP propriétaire du Wallet Solana natif. Elle possède le format autonome `.kspwallet` V1 et le format binaire V2 canonique, les capacités indépendantes VIEW/OWNER, la protection du secret Solana, la signature, l'administration des metadata, les rotations de credentials, la persistence native et les adapters d'import/export explicitement supportés. Depuis `0.2.6-pre.016`, les APIs non versionnées créent/importent en V2 par default explicite et lisent V1/V2 par détection bornée. `0.2.6-pre.017` ajoute la migration V1 -> V2 explicite et OWNER-authentifiée, sans migration à l'ouverture. La crate est volontairement indépendante de Config, du réseau et de Tauri. Un consumer fournit les chemins, passwords et metadata ; Wallet ouvre, protège, signe et persiste sans décider d'une policy de dépense ni contacter un RPC. ## Responsabilités La crate possède : - le format natif `.kspwallet` V1 et son parser JSON strict ; - le wire binaire `.kspwallet` V2, son codec borné/canonique, sa création/ouverture/persistence et ses domains/transcripts distincts ; - la façade générique V1/V2 et les variantes `_v1`/`_v2` permettant soit le default, soit un wire forcé ; - les key slots OWNER/VIEW indépendants ; - Argon2id pour les KDF de passwords ; - XChaCha20-Poly1305 pour le wrapping et les compartiments ; - une autorité Ed25519 d'administration distincte de la keypair Solana ; - les compartiments `owner_control`, `metadata` et `secret` ; - la création et l'ouverture in-memory ; - la création et l'ouverture fichier async-first ; - la projection verrouillée minimale ; - la signature Solana via OWNER sans getter secret ; - l'alias et les notes protégés ; - les rotations OWNER/VIEW ; - la révocation forte VIEW par OWNER ; - la persistence create/import no-clobber ; - le remplacement administratif capability-bound avec détection de handle stale ; - l'inspection/import/export Solana CLI JSON et Base58 de keypair complète ; - les diagnostics et erreurs Wallet sans exposition de secrets. La crate ne possède pas : ```text Config Transport HTTP/WebSocket/gRPC balance/réseau WalletPolicy / execution policy construction ou envoi de transaction Store Tauri/UI hardware wallet / remote signer anti-rollback externe ``` ## Frontières de dépendances La direction de production est : ```text ksp-wallet-lib -> ksp-core-lib -> ksp-logging-lib -> argon2 / chacha20poly1305 / getrandom -> ed25519-dalek / solana-keypair -> serde / serde_json -> tempfile / tokio -> zeroize ``` Les dépendances suivantes sont interdites : ```text ksp-wallet-lib -X-> ksp-config-lib ksp-wallet-lib -X-> ksp-onchain-transport-lib ksp-wallet-lib -X-> execution policy ksp-wallet-lib -X-> Store ksp-wallet-lib -X-> Tauri ksp-wallet-lib -X-> tracing direct ksp-wallet-lib -X-> std::env ksp-wallet-lib -X-> solana-pubkey direct ksp-wallet-lib -X-> solana-signer direct ksp-wallet-lib -X-> solana-signature direct ``` La Pubkey publique est toujours `ksp_core_lib::Pubkey`. `solana-keypair` reste un détail secret/signing interne à Wallet et n'est pas réexportée. ## Modèle de capacités ### Verrouillé Sans password, `inspect_locked_wallet_v1` et `inspect_locked_wallet_file_v1` exposent uniquement : ```text format_version view_enabled ``` La Pubkey, l'alias et les notes restent chiffrés. ### VIEW `WalletView` expose : ```text Pubkey alias notes rotation de son propre password VIEW ``` VIEW ne possède aucune API de signature, d'export secret, de mutation metadata, de rotation OWNER ou de désactivation/recréation VIEW. ### OWNER `WalletOwner` expose toutes les metadata autorisées et ajoute : ```text signature Solana export du secret via adapters explicites alias/notes administration rotation OWNER rotation VIEW sans ancien password VIEW disable VIEW avec rekey metadata fort recreate VIEW avec nouveau slot et nouveau K_metadata ``` OWNER ne dépend jamais du password VIEW. ## Format `.kspwallet` V1 Le format est publiquement spécifié dans [`../../docs/formats/KSPWALLET_V1.md`](../../docs/formats/KSPWALLET_V1.md). Il est autonome : un fichier valide et le password de la capacité concernée suffisent à l'ouverture ; aucun pepper KSP, keychain, OTP, service distant, réseau ou secret externe n'est requis. Les principales primitives sont : ```text KDF Argon2id v19 profil création 65 536 KiB / 3 iterations / 1 lane AEAD XChaCha20-Poly1305 CSPRNG OS via getrandom state signature Ed25519 wire binary Base64url sans padding format JSON UTF-8 strict ``` Les paramètres KDF sont sérialisés dans chaque slot afin que de futurs defaults puissent évoluer sans rendre les wallets existants illisibles. ## Persistence Toute création/import reçoit un chemin explicite du caller et applique le no-clobber. Wallet ne découvre ni ne crée un répertoire configuré par lui-même. Les mutations OWNER/VIEW persistées utilisent un remplacement capability-bound : le fichier courant doit encore correspondre à l'enveloppe authentifiée attendue par le handle. Un handle stale ou une mauvaise cible retourne `wallet.state_conflict`. Cette protection ne constitue pas un CAS filesystem linéarisable et ne fournit pas d'anti-rollback externe. Les garanties d'atomicité/crash-durability dépendent également de l'OS et du filesystem. ## Import/export Les formats built-in V1 sont : ```text WalletTransferFormat::SolanaCliJson WalletTransferFormat::SolanaKeypairBase58 ``` L'inspection d'un transfert retourne seulement sa Pubkey et son format. L'import crée toujours un nouveau `.kspwallet` no-clobber autour de la keypair validée. L'export secret appartient uniquement à `WalletOwner`. `WalletTransferFormat` est `#[non_exhaustive]` afin de permettre des formats built-in supplémentaires sans prétendre fournir un plugin public arbitraire de codec secret. ## Sécurité et limites Le threat model V1 considère notamment un attaquant possédant une copie complète du fichier et capable d'essais de password offline sans limite serveur. Argon2id augmente le coût de chaque essai ; il ne compense pas un password faible. Limites explicitement assumées : - remplacement total par un autre wallet valide non détectable depuis le nouveau fichier seul ; - rollback vers une ancienne copie valide non détectable sans état/ancre externe ; - absence de second facteur, keychain, hardware wallet ou remote signer en V1 ; - `zeroize` réduit les copies possédées mais ne prouve pas l'effacement physique de toute copie potentielle ; - les permissions filesystem sont une hygiène externe, pas une garantie cryptographique. La matrice durable [`../../docs/validation/008-V0_2_5_WALLET_SECURITY_COMPLIANCE.md`](../../docs/validation/008-V0_2_5_WALLET_SECURITY_COMPLIANCE.md) enregistre les canaris adversariaux, l'interop indépendante et l'audit Cargo. ## Tests et vecteurs Les fixtures publiques test-only sont sous `tests/fixtures/` : ```text kspwallet_v1_wire_only.json kspwallet_v1_crypto_vectors.json kspwallet_v1_full_vector.json kspwallet_v1_full_vector_meta.json ``` Elles couvrent le wire, Argon2id/XChaCha20-Poly1305, l'ouverture VIEW/OWNER, la signature d'état et l'interop transfer. Les tests adversariaux couvrent tampering, wrong passwords, frontières VIEW/OWNER, persistence, concurrence et diagnostics secrets. ## Documentation - [`USAGE.md`](USAGE.md) — exemples des principales surfaces publiques ; - [`../../docs/formats/KSPWALLET_V1.md`](../../docs/formats/KSPWALLET_V1.md) — spécification normative indépendante de Rust ; - [`../../docs/plans/012-V0_2_5_WALLET_FOUNDATION_PLAN.md`](../../docs/plans/012-V0_2_5_WALLET_FOUNDATION_PLAN.md) — plan historique et threat model de `0.2.5` ; - [`../../docs/validation/008-V0_2_5_WALLET_SECURITY_COMPLIANCE.md`](../../docs/validation/008-V0_2_5_WALLET_SECURITY_COMPLIANCE.md) — matrice de sécurité/interoperabilité/compliance ; - [`../../prompts/011-V0_2_6_START_PROMPT.md`](../../prompts/011-V0_2_6_START_PROMPT.md) — reprise vers Wallet Desk après publication stable de `0.2.5`. ## V2 en `0.2.6-pre.015` / `pre.016` / `pre.017` `pre.015` a figé le wire structurel V2, son codec et ses transcripts/AAD. `pre.016` matérialise le runtime V2 complet et la façade multi-version : ```text DEFAULT_WALLET_FORMAT = V2 LATEST_SUPPORTED_WALLET_FORMAT = V2 create_wallet_file(...) -> V2 create_wallet_file_v1(...) -> V1 forcé create_wallet_file_v2(...) -> V2 forcé open/inspect génériques -> détection V1/V2 open/inspect _v1/_v2 -> format forcé strict ``` `WalletOwner` et `WalletView` conservent le format natif qu'ils ont ouvert : metadata, rotations OWNER/VIEW, disable/recreate VIEW, self-rotation VIEW, signature et export ne transcodent jamais implicitement le fichier. Le default est une décision explicite et ne suit pas automatiquement une future V3. `pre.017` matérialise la migration authentifiée V1 -> V2 comme opération séparée ; aucune lecture ou mutation ordinaire ne migre implicitement. ### Migration explicite V1 -> V2 ```text migrate_wallet_v1_to_v2(...) migration mémoire migrate_wallet_file_v1_to_v2(...) copie V2 no-clobber, V1 source conservée migrate_wallet_file_v1_to_v2_in_place(...) remplacement V1 atomique et stale-protected ``` La migration exige OWNER. Elle conserve l'identité Solana et les metadata protégées exactes, y compris les identifiants stables de notes, mais reconstruit un nouvel envelope V2 avec ses propres matériaux cryptographiques. Si VIEW est activé, un mot de passe VIEW cible doit être fourni ; il peut être identique à l'ancien ou remplacé sous l'autorité OWNER. Une source VIEW désactivée reste désactivée.