225 lines
9.8 KiB
Markdown
225 lines
9.8 KiB
Markdown
<!-- file: crates/ksp-wallet-lib/README.md -->
|
||
<!-- version: 6 -->
|
||
|
||
# `ksp-wallet-lib`
|
||
|
||
Statut : **stable ; surface V1/V2 et façade multi-version validées**.
|
||
|
||
`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. Les APIs non versionnées créent/importent en V2 par default explicite et lisent V1/V2 par détection bornée. La migration V1 -> V2 est 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, les APIs génériques `inspect_locked_wallet` / `inspect_locked_wallet_file` auto-détectent V1/V2 et exposent uniquement les mêmes champs sûrs. Les variantes `_v1` / `_v2` restent disponibles lorsqu’un caller veut imposer exactement le format attendu :
|
||
|
||
```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 la fondation Wallet ;
|
||
- [`../../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) — prompt historique de reprise vers Wallet Desk.
|
||
|
||
## Wire/runtime V2 et façade multi-version
|
||
|
||
Le wire structurel V2, son codec et ses transcripts/AAD sont figés ; le runtime V2 complet et la façade multi-version exposent :
|
||
|
||
```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. La migration authentifiée V1 -> V2 est une 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.
|
||
|