v0.5.2-pre.004
This commit is contained in:
@@ -1,11 +1,11 @@
|
||||
<!-- file: ks-wallet/USAGE.md -->
|
||||
<!-- version: 9 -->
|
||||
<!-- version: 10 -->
|
||||
|
||||
# Utilisation de ks-wallet
|
||||
|
||||
## Statut
|
||||
|
||||
En `0.5.2-pre.003`, le manager valide désormais la structure complète du conteneur binaire `.kswallet` v1 avant de retourner un handle. Le password, le chiffrement/déchiffrement réel et la création persistante publique arrivent en `pre.004`.
|
||||
En `0.5.2-pre.004`, le manager gère le premier cycle de vie natif complet : création `.kswallet`, ouverture authentifiée, ouverture d'un fichier explicitement sélectionné et changement de mot de passe. La migration legacy et l'import/export restent pour `pre.005`.
|
||||
|
||||
## Valider un alias
|
||||
|
||||
@@ -166,7 +166,7 @@ let wallets = match manager.scan().await {
|
||||
};
|
||||
```
|
||||
|
||||
`scan()` est non récursif et ne traite que les `<alias>.kswallet`. En `pre.003`, chaque candidat doit décoder entièrement selon le format v1 : magic/version, flags, IDs crypto, paramètres KDF, pubkey déclarée, alias, sel, nonce et ciphertext de taille exacte. Le nom du fichier et l'alias encodé doivent correspondre.
|
||||
`scan()` est non récursif et ne traite que les `<alias>.kswallet`. Chaque candidat doit décoder entièrement selon le format v1 : magic/version, flags, IDs crypto, paramètres KDF, pubkey déclarée, alias, sel, nonce et ciphertext de taille exacte. Le nom du fichier et l'alias encodé doivent correspondre.
|
||||
|
||||
Le lookup par alias reste limité à la racine configurée :
|
||||
|
||||
@@ -194,14 +194,125 @@ println!("pubkey={}", handle.public_key());
|
||||
println!("format={}", handle.format_version());
|
||||
```
|
||||
|
||||
`WalletFileHandle` conserve le chemin en interne mais ne fournit aucun getter public vers ce chemin et son `Debug` ne l'affiche pas. Sa pubkey est une identité **déclarée** avant unlock : elle ne deviendra authentifiée qu'après validation AEAD et comparaison avec la keypair déchiffrée en `pre.004`. `inspect_file()` ne modifie pas la configuration et n'ajoute pas le fichier sélectionné au résultat de `scan()`.
|
||||
`WalletFileHandle` conserve le chemin en interne mais ne fournit aucun getter public vers ce chemin et son `Debug` ne l'affiche pas. Sa pubkey reste une identité **déclarée** tant que le fichier n'a pas été ouvert : `unlock()`/`unlock_file()` authentifient l'AEAD puis vérifient que la pubkey de la keypair déchiffrée correspond exactement au header avant de retourner `UnlockedWallet`. `inspect_file()` ne modifie pas la configuration et n'ajoute pas le fichier sélectionné au résultat de `scan()`.
|
||||
|
||||
|
||||
## Cycle de vie natif protégé par mot de passe
|
||||
|
||||
`WalletPassword` prend possession du mot de passe pour **une seule opération**. Il n'est ni clonable ni sérialisable et son `Debug` est toujours redacted. L'appelant construit donc une nouvelle valeur pour chaque création, ouverture ou changement de mot de passe.
|
||||
|
||||
### Créer un wallet persistant natif
|
||||
|
||||
```rust
|
||||
let alias = match ks_wallet::WalletAlias::parse("operator") {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => {
|
||||
return std::result::Result::Err(error);
|
||||
},
|
||||
};
|
||||
let password = match ks_wallet::WalletPassword::new(password_string) {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => {
|
||||
return std::result::Result::Err(error);
|
||||
},
|
||||
};
|
||||
let wallet = match manager.create(alias.clone(), password).await {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => {
|
||||
return std::result::Result::Err(error);
|
||||
},
|
||||
};
|
||||
println!("pubkey={}", wallet.public_key());
|
||||
```
|
||||
|
||||
`create()` génère une keypair Solana, la protège avec Argon2id + XChaCha20-Poly1305, publie `<alias>.kswallet` sans écraser une destination existante et retourne une capacité `UnlockedWallet`. Aucun getter public ne fournit les bytes privés.
|
||||
|
||||
### Ouvrir par alias
|
||||
|
||||
```rust
|
||||
let password = match ks_wallet::WalletPassword::new(password_string) {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => {
|
||||
return std::result::Result::Err(error);
|
||||
},
|
||||
};
|
||||
let wallet = match manager.unlock(&alias, password).await {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => {
|
||||
return std::result::Result::Err(error);
|
||||
},
|
||||
};
|
||||
let signature = match wallet.sign_message(b"authenticated operation") {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => {
|
||||
return std::result::Result::Err(error);
|
||||
},
|
||||
};
|
||||
println!("signature={signature}");
|
||||
wallet.lock();
|
||||
```
|
||||
|
||||
Un mauvais mot de passe ou une altération des données authentifiées échoue avant la création de la capacité de signature. `lock()` consomme explicitement `UnlockedWallet`; laisser la valeur sortir de portée a le même effet de durée de vie.
|
||||
|
||||
### Ouvrir un fichier choisi hors du store
|
||||
|
||||
```rust
|
||||
let handle = match manager.inspect_file(selected_path).await {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => {
|
||||
return std::result::Result::Err(error);
|
||||
},
|
||||
};
|
||||
let password = match ks_wallet::WalletPassword::new(password_string) {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => {
|
||||
return std::result::Result::Err(error);
|
||||
},
|
||||
};
|
||||
let wallet = match manager.unlock_file(&handle, password).await {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => {
|
||||
return std::result::Result::Err(error);
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
Le handle est revalidé contre le fichier avant l'ouverture authentifiée. Le fichier externe reste extérieur au scan/configuration du manager.
|
||||
|
||||
### Changer le mot de passe
|
||||
|
||||
```rust
|
||||
let current_password = match ks_wallet::WalletPassword::new(current_password_string) {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => {
|
||||
return std::result::Result::Err(error);
|
||||
},
|
||||
};
|
||||
let new_password = match ks_wallet::WalletPassword::new(new_password_string) {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => {
|
||||
return std::result::Result::Err(error);
|
||||
},
|
||||
};
|
||||
let handle = match manager
|
||||
.change_password(&alias, current_password, new_password)
|
||||
.await
|
||||
{
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => {
|
||||
return std::result::Result::Err(error);
|
||||
},
|
||||
};
|
||||
println!("pubkey={}", handle.public_key());
|
||||
```
|
||||
|
||||
`change_password()` n'altère pas la keypair : il authentifie l'ancien conteneur, rechiffre exactement le même matériau avec un nouveau sel/nonce et remplace atomiquement le `.kswallet`. La pubkey reste identique. Cette opération ne peut pas révoquer rétroactivement une `UnlockedWallet` déjà remise à un consommateur ; cette capacité doit être `lock()`/dropée par son propriétaire.
|
||||
|
||||
## Format binaire v1
|
||||
|
||||
Le layout exact, les bornes et la politique de publication cible sont documentés dans [`../docs/NATIVE_FORMAT.md`](../docs/NATIVE_FORMAT.md). `pre.003` implémente la lecture et le décodage stricts nécessaires au scan ; l'encodage de création et la publication atomique sont introduits en `pre.004`. Le payload secret v1 est strictement borné à une keypair Solana de 64 octets et produit un ciphertext/tag de 80 octets.
|
||||
Le layout exact, les bornes et la politique de publication sont documentés dans [`../docs/NATIVE_FORMAT.md`](../docs/NATIVE_FORMAT.md). `pre.004` implémente désormais l'encodage, la lecture, la protection et la publication. Le payload secret v1 est strictement borné à une keypair Solana de 64 octets et produit un ciphertext/tag de 80 octets.
|
||||
|
||||
Le format encode Argon2id v19 avec un profil d'écriture par défaut de 64 MiB / 3 passes / 4 lanes et XChaCha20-Poly1305 avec nonce 24 octets. Ces paramètres sont seulement encodés/validés en `pre.003`; leur exécution cryptographique commence en `pre.004`.
|
||||
Le format exécute Argon2id v19 avec un profil d'écriture par défaut de 64 MiB / 3 passes / 4 lanes et XChaCha20-Poly1305 avec nonce 24 octets. Les paramètres lus depuis un fichier restent bornés avant toute exécution du KDF.
|
||||
|
||||
## Cible persistante `0.5.2`
|
||||
|
||||
@@ -211,7 +322,7 @@ Le nouveau stockage natif doit utiliser :
|
||||
<alias>.kswallet
|
||||
```
|
||||
|
||||
Le fichier `.kswallet` sera un conteneur binaire versionné protégé par le mot de passe propre au wallet.
|
||||
Le fichier `.kswallet` est un conteneur binaire versionné protégé par le mot de passe propre au wallet.
|
||||
|
||||
L'API cible doit permettre conceptuellement :
|
||||
|
||||
@@ -229,7 +340,7 @@ Le store découvrira les wallets persistants en scannant son répertoire résolu
|
||||
|
||||
Le changement de mot de passe rechiffre la même keypair. Il n'existe pas de rotation normale du secret Ed25519 conservant la même pubkey : une nouvelle clé secrète signifie une nouvelle identité Solana.
|
||||
|
||||
Le modèle runtime exact du wallet ouvert sera décidé dans les prereleases d'implémentation. Les noms `WalletManager`, `WalletFileHandle`, `WalletIdentity` et `WalletPersistence` font désormais partie de l'API de base.
|
||||
Le modèle runtime ouvert est `UnlockedWallet`, capacité non clonable possédant le signer authentifié. `WalletManager`, `WalletFileHandle`, `WalletIdentity`, `WalletPersistence`, `WalletPassword` et `UnlockedWallet` font désormais partie de l'API de base.
|
||||
|
||||
## Import/export cible
|
||||
|
||||
@@ -262,4 +373,4 @@ L'export vers Solana CLI utilise son tableau JSON de 64 octets. Pour Phantom, So
|
||||
- rejet des keypairs corrompus ;
|
||||
- vérification des permissions Unix privées.
|
||||
|
||||
`pre.003` ajoute le décodage/validation v1 stricts, les bornes KDF/fichier et les tests de corruption/réouverture. `pre.004` ajoute l'encodage de création, la publication atomique, le password/changement de password et le chiffrement effectif ; les tranches suivantes couvrent la migration, l'import/export et les canaris de non-divulgation.
|
||||
`pre.003` ajoute le décodage/validation v1 stricts et les bornes KDF/fichier. `pre.004` ajoute l'encodage, la publication atomique, le password, la dérivation/chiffrement effectifs, l'ouverture authentifiée, le changement de password et les tests de non-divulgation associés. Les tranches suivantes couvrent migration et import/export puis l'intégration des consommateurs.
|
||||
|
||||
Reference in New Issue
Block a user