v0.2.6-pre.015
This commit is contained in:
@@ -1,12 +1,12 @@
|
||||
# file: Cargo.toml
|
||||
# version: 187
|
||||
# version: 188
|
||||
|
||||
[workspace]
|
||||
resolver = "3"
|
||||
members = ["crates/ksp-app-config-desk", "crates/ksp-app-wallet-desk", "crates/ksp-config-lib", "crates/ksp-core-lib", "crates/ksp-logging-lib", "crates/ksp-onchain-transport-lib", "crates/ksp-wallet-lib"]
|
||||
|
||||
[workspace.package]
|
||||
version = "0.2.6-pre.14.fix.1"
|
||||
version = "0.2.6-pre.15"
|
||||
edition = "2024"
|
||||
license = "MIT"
|
||||
repository = "https://git.sasedev.com/Sasedev/khadhroony-solana-project"
|
||||
|
||||
19
ROADMAP.md
19
ROADMAP.md
@@ -1,5 +1,5 @@
|
||||
<!-- file: ROADMAP.md -->
|
||||
<!-- version: 76 -->
|
||||
<!-- version: 77 -->
|
||||
|
||||
# Roadmap KSP
|
||||
|
||||
@@ -50,15 +50,14 @@ Le roadmap décrit les objectifs à atteindre et les grandes étapes prévues. U
|
||||
- [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.
|
||||
- [X] `0.2.5` — Wallet foundation stable : `.kspwallet` V1, VIEW/OWNER indépendants, Argon2id/XChaCha20-Poly1305, autorité Ed25519 OWNER, persistence no-clobber, signature, administration/rotations/révocation VIEW forte, import/export Solana CLI JSON + Base58, canaris adversariaux, interop externe et documentation durable publiés. La clôture `pre.010-fix.001`–`fix.003` ajoute `ed25519-dalek 3.0.0` direct, normalise le Rust workspace et installe l’audit structurel Python complémentaire à rustfmt/Clippy. `Pubkey` reste via `ksp-core-lib`, la keypair reste encapsulée dans Wallet et Config/Transport/ExecutionPolicy/Store/Tauri restent hors Wallet.
|
||||
- [/] `0.2.6` — `ksp-app-wallet-desk` : surface fonctionnelle Wallet Desk acquise ; `pre.014` harmonise le gabarit/splash/Tauri multi-app puis `pre.015` clôture documentation et build final. Plan détaillé : `docs/plans/013-V0_2_6_WALLET_DESK_PLAN.md`.
|
||||
- [ ] `0.2.7` — Durcir la persistence `.kspwallet` dans `ksp-wallet-lib` avec un conteneur binaire versionné rétrocompatible ; conserver les semantics cryptographiques V1 et rejouer Wallet Desk comme consommateur sans changement fonctionnel attendu.
|
||||
- [ ] `0.2.8` — É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.9` — Ajouter Helius LaserStream WebSocket comme extension du moteur WebSocket standard, sans duplication de client.
|
||||
- [ ] `0.2.10` — Ajouter une première fondation Yellowstone gRPC standard/provider-neutral ; dimensionner la surface exacte à `pre.001` selon la documentation normative actuelle.
|
||||
- [ ] `0.2.11` — Introduire `ksp-offchain-transport-lib` avec un premier lecteur de prix, au minimum SOL/USD et SOL/EUR.
|
||||
- [ ] `0.2.12` — Introduire une petite application desk de visualisation/validation des prix offchain, puis intégrer cette capacité dans `ksp-app-wallet-desk` sans dupliquer la logique de récupération/normalisation possédée par le composant spécialisé.
|
||||
- [ ] `0.2.13` — Introduire la première surface de `ksp-interface-lib`, comprenant une API wire publique utilisable par les implémentations officielles et externes.
|
||||
- [ ] `0.2.14` — Introduire `ksp-program-api` comme premier contrat Program extensible, sans imposer encore `ksp-program-lib` complet.
|
||||
- [/] `0.2.6` — `ksp-app-wallet-desk` + évolution `.kspwallet` V2 : surface Desk acquise ; `pre.014` polish, `pre.015` wire binaire V2, `pre.016` APIs génériques/versionnées + V2, `pre.017` migration/canaris, `pre.018` candidate finale. Plan détaillé : `docs/plans/013-V0_2_6_WALLET_DESK_PLAN.md`.
|
||||
- [ ] `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.
|
||||
- [ ] `0.2.9` — Ajouter une première fondation Yellowstone gRPC standard/provider-neutral ; dimensionner la surface exacte à `pre.001` selon la documentation normative actuelle.
|
||||
- [ ] `0.2.10` — Introduire `ksp-offchain-transport-lib` avec un premier lecteur de prix, au minimum SOL/USD et SOL/EUR.
|
||||
- [ ] `0.2.11` — Introduire une petite application desk de visualisation/validation des prix offchain, puis intégrer cette capacité dans `ksp-app-wallet-desk` sans dupliquer la logique de récupération/normalisation possédée par le composant spécialisé.
|
||||
- [ ] `0.2.12` — Introduire la première surface de `ksp-interface-lib`, comprenant une API wire publique utilisable par les implémentations officielles et externes.
|
||||
- [ ] `0.2.13` — Introduire `ksp-program-api` comme premier contrat Program extensible, sans imposer encore `ksp-program-lib` complet.
|
||||
|
||||
### Règles Transport pour toute la série
|
||||
|
||||
|
||||
@@ -914,23 +914,23 @@ impl AppState {
|
||||
std::result::Result::Err(_) => return std::result::Result::Err(session_lock_error()),
|
||||
};
|
||||
let previous = std::mem::replace(&mut *session, crate::WalletSession::no_selection());
|
||||
match previous {
|
||||
return match previous {
|
||||
crate::WalletSession::ViewOperation { wallet_id: reserved_wallet_id, path: reserved_path, pubkey: reserved_pubkey }
|
||||
if reserved_wallet_id == wallet_id && reserved_path == path && reserved_pubkey == pubkey =>
|
||||
{
|
||||
*session = crate::WalletSession::View { wallet_id: wallet_id.clone(), path, wallet: view };
|
||||
ksp_logging_lib::info!(target: crate::TRACING_TARGET, domain = crate::TRACING_DOMAIN_WALLET_SESSION, wallet_id = wallet_id.as_str(), operation, "Wallet VIEW privileged operation completed");
|
||||
return std::result::Result::Ok(dto);
|
||||
std::result::Result::Ok(dto)
|
||||
},
|
||||
other => {
|
||||
*session = other;
|
||||
drop(view);
|
||||
return std::result::Result::Err(ksp_core_lib::Error::new(
|
||||
std::result::Result::Err(ksp_core_lib::Error::new(
|
||||
crate::ERROR_CODE_WALLET_SESSION_INVALID,
|
||||
"Wallet VIEW operation completion no longer owns the selected session",
|
||||
));
|
||||
))
|
||||
},
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
fn restore_view_after_operation_failure(&self, context: ViewOperationContext) {
|
||||
@@ -1039,7 +1039,7 @@ impl AppState {
|
||||
std::result::Result::Err(_) => return std::result::Result::Err(session_lock_error()),
|
||||
};
|
||||
let previous = std::mem::replace(&mut *session, crate::WalletSession::no_selection());
|
||||
match previous {
|
||||
return match previous {
|
||||
crate::WalletSession::OwnerOperation {
|
||||
wallet_id: reserved_wallet_id,
|
||||
path: reserved_path,
|
||||
@@ -1048,17 +1048,17 @@ impl AppState {
|
||||
} if reserved_wallet_id == wallet_id && reserved_path == path && reserved_pubkey == pubkey && reserved_view_enabled == view_enabled => {
|
||||
*session = crate::WalletSession::Owner { wallet_id: wallet_id.clone(), path, view_enabled: result_view_enabled, wallet: owner };
|
||||
ksp_logging_lib::info!(target: crate::TRACING_TARGET, domain = crate::TRACING_DOMAIN_WALLET_SESSION, wallet_id = wallet_id.as_str(), operation, "Wallet OWNER privileged operation completed");
|
||||
return std::result::Result::Ok(dto);
|
||||
std::result::Result::Ok(dto)
|
||||
},
|
||||
other => {
|
||||
*session = other;
|
||||
drop(owner);
|
||||
return std::result::Result::Err(ksp_core_lib::Error::new(
|
||||
std::result::Result::Err(ksp_core_lib::Error::new(
|
||||
crate::ERROR_CODE_WALLET_SESSION_INVALID,
|
||||
"Wallet OWNER operation completion no longer owns the selected session",
|
||||
));
|
||||
))
|
||||
},
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
fn restore_owner_after_operation_failure(&self, context: OwnerOperationContext) {
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
<!-- file: crates/ksp-wallet-lib/README.md -->
|
||||
<!-- version: 2 -->
|
||||
<!-- version: 3 -->
|
||||
|
||||
# `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, 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.
|
||||
`ksp-wallet-lib` est la bibliothèque KSP propriétaire du Wallet Solana natif. Elle possède le format autonome `.kspwallet` V1 et, depuis `0.2.6-pre.015`, le wire 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.
|
||||
|
||||
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.
|
||||
|
||||
@@ -14,6 +14,7 @@ La crate est volontairement indépendante de Config, du réseau et de Tauri. Un
|
||||
La crate possède :
|
||||
|
||||
- le format natif `.kspwallet` V1 et son parser JSON strict ;
|
||||
- le wire binaire `.kspwallet` V2, son codec borné/canonique et ses domains/transcripts distincts ;
|
||||
- les key slots OWNER/VIEW indépendants ;
|
||||
- Argon2id pour les KDF de passwords ;
|
||||
- XChaCha20-Poly1305 pour le wrapping et les compartiments ;
|
||||
@@ -192,3 +193,7 @@ Elles couvrent le wire, Argon2id/XChaCha20-Poly1305, l'ouverture VIEW/OWNER, la
|
||||
- [`../../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.015` ajoute uniquement le codec structurel V2 et sa spécification. Les APIs de persistence runtime restent V1 jusqu’à `pre.016`, qui ajoute `create_wallet_file(...)` default V2, les variantes `_v1`/`_v2` et le dispatch générique de lecture. Le default est une décision explicite et ne suit pas automatiquement une future V3.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!-- file: crates/ksp-wallet-lib/USAGE.md -->
|
||||
<!-- version: 2 -->
|
||||
<!-- version: 3 -->
|
||||
|
||||
# Utilisation de `ksp-wallet-lib`
|
||||
|
||||
@@ -277,3 +277,14 @@ ksp-onchain-transport-lib
|
||||
```
|
||||
|
||||
Cette composition est le rôle de `0.2.6 — ksp-app-wallet-desk`, pas de `ksp-wallet-lib`.
|
||||
|
||||
## Wire V2 (`0.2.6-pre.015`)
|
||||
|
||||
Le codec structurel V2 peut être utilisé pour analyser une fixture/document V2 déjà produit :
|
||||
|
||||
```rust
|
||||
let envelope = ksp_wallet_lib::KspWalletEnvelopeV2::parse_binary(bytes)?;
|
||||
let canonical = envelope.to_binary_bytes()?;
|
||||
```
|
||||
|
||||
La persistence applicative ne doit pas encore appeler ce codec directement pour créer un wallet : `pre.016` introduit les APIs génériques/versionnées et le default V2.
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
// file: crates/ksp-wallet-lib/src/constants.rs
|
||||
// version: 7
|
||||
// version: 8
|
||||
|
||||
//! Wallet-owned constants.
|
||||
|
||||
/// Native Wallet format version implemented by the V1 codec.
|
||||
pub const KSPWALLET_FORMAT_VERSION_V1: u32 = 1;
|
||||
/// Native Wallet format version implemented by the V2 binary codec.
|
||||
pub const KSPWALLET_FORMAT_VERSION_V2: u32 = 2;
|
||||
/// Exact magic string required by every native `.kspwallet` document.
|
||||
pub const KSPWALLET_MAGIC: &str = "KSPWALLET";
|
||||
/// Maximum accepted `.kspwallet` document size before JSON parsing.
|
||||
@@ -85,6 +87,50 @@ pub const KSPWALLET_V1_STATE_TRANSCRIPT_DOMAIN: &[u8] = b"KSPWALLET-V1-STATE";
|
||||
pub const KSPWALLET_V1_VIEW_SLOT_AAD_DOMAIN: &[u8] = b"KSPWALLET-V1-AAD-VIEW-SLOT";
|
||||
/// Byte length of an XChaCha20-Poly1305 nonce.
|
||||
pub const KSPWALLET_V1_XCHACHA_NONCE_BYTES: usize = 24;
|
||||
/// Byte length of the Poly1305 authentication tag appended to each V2 ciphertext.
|
||||
pub const KSPWALLET_V2_AEAD_TAG_BYTES: usize = KSPWALLET_V1_AEAD_TAG_BYTES;
|
||||
/// Argon2 version serialized by V2 key slots.
|
||||
pub const KSPWALLET_V2_ARGON2_VERSION: u32 = KSPWALLET_V1_ARGON2_VERSION;
|
||||
/// Byte length of an Ed25519 public key used as V2 Wallet format authority.
|
||||
pub const KSPWALLET_V2_ED25519_PUBLIC_KEY_BYTES: usize = KSPWALLET_V1_ED25519_PUBLIC_KEY_BYTES;
|
||||
/// Byte length of an Ed25519 detached V2 state signature.
|
||||
pub const KSPWALLET_V2_ED25519_SIGNATURE_BYTES: usize = KSPWALLET_V1_ED25519_SIGNATURE_BYTES;
|
||||
/// Initial protected payload version used independently by V2 control, metadata and secret compartments.
|
||||
pub const KSPWALLET_V2_INITIAL_PAYLOAD_VERSION: u32 = KSPWALLET_V1_INITIAL_PAYLOAD_VERSION;
|
||||
/// Structural V2 ceiling for serialized Argon2 iteration cost.
|
||||
pub const KSPWALLET_V2_MAX_ARGON2_ITERATIONS: u32 = KSPWALLET_V1_MAX_ARGON2_ITERATIONS;
|
||||
/// Structural V2 ceiling for serialized Argon2 memory cost.
|
||||
pub const KSPWALLET_V2_MAX_ARGON2_MEMORY_KIB: u32 = KSPWALLET_V1_MAX_ARGON2_MEMORY_KIB;
|
||||
/// Structural V2 ceiling for serialized Argon2 parallelism.
|
||||
pub const KSPWALLET_V2_MAX_ARGON2_PARALLELISM: u32 = KSPWALLET_V1_MAX_ARGON2_PARALLELISM;
|
||||
/// Maximum Argon2 salt size accepted by V2.
|
||||
pub const KSPWALLET_V2_MAX_KDF_SALT_BYTES: usize = KSPWALLET_V1_MAX_KDF_SALT_BYTES;
|
||||
/// Maximum wrapped-key ciphertext size accepted by V2.
|
||||
pub const KSPWALLET_V2_MAX_KEY_WRAP_CIPHERTEXT_BYTES: usize = KSPWALLET_V1_MAX_KEY_WRAP_CIPHERTEXT_BYTES;
|
||||
/// Maximum protected metadata ciphertext size accepted by V2.
|
||||
pub const KSPWALLET_V2_MAX_METADATA_CIPHERTEXT_BYTES: usize = KSPWALLET_V1_MAX_METADATA_CIPHERTEXT_BYTES;
|
||||
/// Maximum OWNER-control ciphertext size accepted by V2.
|
||||
pub const KSPWALLET_V2_MAX_OWNER_CONTROL_CIPHERTEXT_BYTES: usize = KSPWALLET_V1_MAX_OWNER_CONTROL_CIPHERTEXT_BYTES;
|
||||
/// Maximum OWNER-only secret ciphertext size accepted by V2.
|
||||
pub const KSPWALLET_V2_MAX_SECRET_CIPHERTEXT_BYTES: usize = KSPWALLET_V1_MAX_SECRET_CIPHERTEXT_BYTES;
|
||||
/// Domain separator for V2 metadata-compartment AEAD AAD.
|
||||
pub const KSPWALLET_V2_METADATA_AAD_DOMAIN: &[u8] = b"KSPWALLET-V2-AAD-METADATA";
|
||||
/// Minimum Argon2 salt size accepted by V2.
|
||||
pub const KSPWALLET_V2_MIN_KDF_SALT_BYTES: usize = KSPWALLET_V1_MIN_KDF_SALT_BYTES;
|
||||
/// Domain separator for V2 OWNER-control compartment AEAD AAD.
|
||||
pub const KSPWALLET_V2_OWNER_CONTROL_AAD_DOMAIN: &[u8] = b"KSPWALLET-V2-AAD-OWNER-CONTROL";
|
||||
/// Domain separator for V2 OWNER key-slot wrapping AAD.
|
||||
pub const KSPWALLET_V2_OWNER_SLOT_AAD_DOMAIN: &[u8] = b"KSPWALLET-V2-AAD-OWNER-SLOT";
|
||||
/// Domain separator for V2 OWNER-only secret compartment AEAD AAD.
|
||||
pub const KSPWALLET_V2_SECRET_AAD_DOMAIN: &[u8] = b"KSPWALLET-V2-AAD-SECRET";
|
||||
/// Byte length of every V2 key-slot identifier.
|
||||
pub const KSPWALLET_V2_SLOT_ID_BYTES: usize = KSPWALLET_V1_SLOT_ID_BYTES;
|
||||
/// Domain separator for the V2 OWNER state-signature transcript.
|
||||
pub const KSPWALLET_V2_STATE_TRANSCRIPT_DOMAIN: &[u8] = b"KSPWALLET-V2-STATE";
|
||||
/// Domain separator for V2 VIEW key-slot wrapping AAD.
|
||||
pub const KSPWALLET_V2_VIEW_SLOT_AAD_DOMAIN: &[u8] = b"KSPWALLET-V2-AAD-VIEW-SLOT";
|
||||
/// Byte length of an XChaCha20-Poly1305 nonce in V2.
|
||||
pub const KSPWALLET_V2_XCHACHA_NONCE_BYTES: usize = KSPWALLET_V1_XCHACHA_NONCE_BYTES;
|
||||
|
||||
/// Owning tracing target for events emitted by the Wallet crate.
|
||||
pub(crate) const TRACING_TARGET: &str = "ksp-wallet-lib";
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: crates/ksp-wallet-lib/src/lib.rs
|
||||
// version: 11
|
||||
// version: 12
|
||||
|
||||
#![warn(missing_docs)]
|
||||
#![deny(unreachable_pub)]
|
||||
@@ -15,7 +15,8 @@
|
||||
//! adds Solana message signing, protected metadata administration, password rotation and strong VIEW disable/recreate with capability-bound atomic
|
||||
//! replacement. `0.2.5-pre.008` adds bounded Solana CLI JSON and canonical full-keypair Base58 import/export adapters with safe inspection and no-clobber
|
||||
//! native import/export publication. `0.2.5-pre.009` adds adversarial security/compliance canaries and records the final dependency/interop audit before
|
||||
//! documentation closure. Public keys are consumed exclusively through the [`ksp_core_lib::Pubkey`] re-export owned by KSP Core, and behavioral
|
||||
//! documentation closure. `0.2.6-pre.015` defines the strict binary `.kspwallet` V2 wire and its bounded canonical codec without yet changing the public
|
||||
//! persistence default or Wallet Desk dispatch. Public keys are consumed exclusively through the [`ksp_core_lib::Pubkey`] re-export owned by KSP Core, and behavioral
|
||||
//! observability uses only
|
||||
//! `ksp-logging-lib` with the explicit crate target defined in `src/constants.rs`.
|
||||
|
||||
@@ -29,10 +30,12 @@ mod password;
|
||||
mod payload;
|
||||
mod persistence;
|
||||
mod transcript;
|
||||
mod transcript_v2;
|
||||
mod transfer;
|
||||
mod view;
|
||||
mod wallet;
|
||||
mod wire;
|
||||
mod wire_v2;
|
||||
|
||||
#[cfg(test)]
|
||||
#[path = "../unit_tests/security.rs"]
|
||||
@@ -42,6 +45,8 @@ mod security_tests;
|
||||
pub use self::capability::WalletCapability;
|
||||
/// Native `.kspwallet` V1 format version.
|
||||
pub use self::constants::KSPWALLET_FORMAT_VERSION_V1;
|
||||
/// Native `.kspwallet` V2 binary format version.
|
||||
pub use self::constants::KSPWALLET_FORMAT_VERSION_V2;
|
||||
/// Exact magic string required by every native `.kspwallet` document.
|
||||
pub use self::constants::KSPWALLET_MAGIC;
|
||||
/// Maximum accepted `.kspwallet` document size before parsing.
|
||||
@@ -122,6 +127,50 @@ pub use self::constants::KSPWALLET_V1_STATE_TRANSCRIPT_DOMAIN;
|
||||
pub use self::constants::KSPWALLET_V1_VIEW_SLOT_AAD_DOMAIN;
|
||||
/// Byte length of an XChaCha20-Poly1305 nonce.
|
||||
pub use self::constants::KSPWALLET_V1_XCHACHA_NONCE_BYTES;
|
||||
/// Byte length of the AEAD authentication tag appended to V2 ciphertexts.
|
||||
pub use self::constants::KSPWALLET_V2_AEAD_TAG_BYTES;
|
||||
/// Argon2 version serialized by `.kspwallet` V2 key slots.
|
||||
pub use self::constants::KSPWALLET_V2_ARGON2_VERSION;
|
||||
/// Byte length of the V2 Ed25519 format-authority public key.
|
||||
pub use self::constants::KSPWALLET_V2_ED25519_PUBLIC_KEY_BYTES;
|
||||
/// Byte length of the V2 Ed25519 detached state signature.
|
||||
pub use self::constants::KSPWALLET_V2_ED25519_SIGNATURE_BYTES;
|
||||
/// Initial per-compartment protected payload version for V2.
|
||||
pub use self::constants::KSPWALLET_V2_INITIAL_PAYLOAD_VERSION;
|
||||
/// Maximum structural Argon2 iteration count accepted by the V2 parser.
|
||||
pub use self::constants::KSPWALLET_V2_MAX_ARGON2_ITERATIONS;
|
||||
/// Maximum structural Argon2 memory cost accepted by the V2 parser.
|
||||
pub use self::constants::KSPWALLET_V2_MAX_ARGON2_MEMORY_KIB;
|
||||
/// Maximum structural Argon2 parallelism accepted by the V2 parser.
|
||||
pub use self::constants::KSPWALLET_V2_MAX_ARGON2_PARALLELISM;
|
||||
/// Maximum Argon2 salt size accepted by V2.
|
||||
pub use self::constants::KSPWALLET_V2_MAX_KDF_SALT_BYTES;
|
||||
/// Maximum wrapped-key ciphertext size accepted by V2.
|
||||
pub use self::constants::KSPWALLET_V2_MAX_KEY_WRAP_CIPHERTEXT_BYTES;
|
||||
/// Maximum protected metadata ciphertext size accepted by V2.
|
||||
pub use self::constants::KSPWALLET_V2_MAX_METADATA_CIPHERTEXT_BYTES;
|
||||
/// Maximum OWNER-control ciphertext size accepted by V2.
|
||||
pub use self::constants::KSPWALLET_V2_MAX_OWNER_CONTROL_CIPHERTEXT_BYTES;
|
||||
/// Maximum OWNER-only secret ciphertext size accepted by V2.
|
||||
pub use self::constants::KSPWALLET_V2_MAX_SECRET_CIPHERTEXT_BYTES;
|
||||
/// Domain separator for V2 metadata-compartment AEAD AAD.
|
||||
pub use self::constants::KSPWALLET_V2_METADATA_AAD_DOMAIN;
|
||||
/// Minimum Argon2 salt size accepted by V2.
|
||||
pub use self::constants::KSPWALLET_V2_MIN_KDF_SALT_BYTES;
|
||||
/// Domain separator for V2 OWNER-control compartment AEAD AAD.
|
||||
pub use self::constants::KSPWALLET_V2_OWNER_CONTROL_AAD_DOMAIN;
|
||||
/// Domain separator for V2 OWNER key-slot wrapping AAD.
|
||||
pub use self::constants::KSPWALLET_V2_OWNER_SLOT_AAD_DOMAIN;
|
||||
/// Domain separator for V2 OWNER-only secret compartment AEAD AAD.
|
||||
pub use self::constants::KSPWALLET_V2_SECRET_AAD_DOMAIN;
|
||||
/// Byte length of every V2 key-slot identifier.
|
||||
pub use self::constants::KSPWALLET_V2_SLOT_ID_BYTES;
|
||||
/// Domain separator for the V2 OWNER state-signature transcript.
|
||||
pub use self::constants::KSPWALLET_V2_STATE_TRANSCRIPT_DOMAIN;
|
||||
/// Domain separator for V2 VIEW key-slot wrapping AAD.
|
||||
pub use self::constants::KSPWALLET_V2_VIEW_SLOT_AAD_DOMAIN;
|
||||
/// Byte length of an XChaCha20-Poly1305 nonce in V2.
|
||||
pub use self::constants::KSPWALLET_V2_XCHACHA_NONCE_BYTES;
|
||||
/// Error code used when an atomic Wallet persistence operation cannot publish a valid replacement.
|
||||
pub use self::error::ERROR_CODE_ATOMIC_PERSISTENCE_FAILED;
|
||||
/// Error code used when an authenticated Wallet structure cannot be verified.
|
||||
@@ -224,6 +273,30 @@ pub use self::wire::WalletStateSignatureAlgorithmV1;
|
||||
pub use self::wire::WalletStateSignatureV1;
|
||||
/// OWNER-signed stable descriptor of the optional VIEW slot.
|
||||
pub use self::wire::WalletViewDescriptorV1;
|
||||
/// Strict semantic representation of one parsed native `.kspwallet` V2 binary envelope.
|
||||
pub use self::wire_v2::KspWalletEnvelopeV2;
|
||||
/// Authenticated-encryption algorithm fixed by native Wallet V2.
|
||||
pub use self::wire_v2::WalletAeadAlgorithmV2;
|
||||
/// Protected compartment kind fixed by native Wallet V2.
|
||||
pub use self::wire_v2::WalletCompartmentKindV2;
|
||||
/// One validated encrypted V2 compartment.
|
||||
pub use self::wire_v2::WalletEncryptedCompartmentV2;
|
||||
/// Password KDF fixed by native Wallet V2.
|
||||
pub use self::wire_v2::WalletKdfAlgorithmV2;
|
||||
/// Parsed Argon2id parameters from one V2 key slot.
|
||||
pub use self::wire_v2::WalletKdfParametersV2;
|
||||
/// Role of one native V2 key slot.
|
||||
pub use self::wire_v2::WalletKeySlotRoleV2;
|
||||
/// One validated OWNER or VIEW V2 key slot.
|
||||
pub use self::wire_v2::WalletKeySlotV2;
|
||||
/// Parsed AEAD wrapped-key payload from one V2 key slot.
|
||||
pub use self::wire_v2::WalletKeyWrapV2;
|
||||
/// State-signature algorithm fixed by native Wallet V2.
|
||||
pub use self::wire_v2::WalletStateSignatureAlgorithmV2;
|
||||
/// Detached OWNER state signature embedded in a V2 envelope.
|
||||
pub use self::wire_v2::WalletStateSignatureV2;
|
||||
/// OWNER-signed stable descriptor of the optional VIEW slot in V2.
|
||||
pub use self::wire_v2::WalletViewDescriptorV2;
|
||||
|
||||
/// Wallet-owned tracing target used by the KSP logging facade.
|
||||
pub(crate) use self::constants::TRACING_TARGET;
|
||||
@@ -277,6 +350,12 @@ pub(crate) use self::transcript::compartment_aad;
|
||||
pub(crate) use self::transcript::slot_aad;
|
||||
/// Internal deterministic OWNER-state transcript codec shared by Wallet crypto layers.
|
||||
pub(crate) use self::transcript::state_transcript;
|
||||
/// Internal deterministic V2 compartment-AAD codec shared by Wallet crypto layers.
|
||||
pub(crate) use self::transcript_v2::compartment_aad_v2;
|
||||
/// Internal deterministic V2 key-slot-AAD codec shared by Wallet crypto layers.
|
||||
pub(crate) use self::transcript_v2::slot_aad_v2;
|
||||
/// Internal deterministic V2 OWNER-state transcript codec shared by Wallet crypto layers.
|
||||
pub(crate) use self::transcript_v2::state_transcript_v2;
|
||||
/// Internal no-clobber transfer-file writer used only by OWNER export.
|
||||
pub(crate) use self::transfer::write_wallet_transfer_file_v1;
|
||||
/// Crate-internal `OwnerStateV1` state shared across the owning crate.
|
||||
|
||||
141
crates/ksp-wallet-lib/src/transcript_v2.rs
Normal file
141
crates/ksp-wallet-lib/src/transcript_v2.rs
Normal file
@@ -0,0 +1,141 @@
|
||||
// file: crates/ksp-wallet-lib/src/transcript_v2.rs
|
||||
// version: 1
|
||||
|
||||
//! Deterministic `.kspwallet` V2 state-transcript and AEAD-AAD encoding.
|
||||
|
||||
const TAG_COMPARTMENT_ALGORITHM: u16 = 0x0202;
|
||||
const TAG_COMPARTMENT_CIPHERTEXT: u16 = 0x0204;
|
||||
const TAG_COMPARTMENT_KIND: u16 = 0x0200;
|
||||
const TAG_COMPARTMENT_NONCE: u16 = 0x0203;
|
||||
const TAG_COMPARTMENT_VERSION: u16 = 0x0201;
|
||||
const TAG_FORMAT_VERSION: u16 = 0x0002;
|
||||
const TAG_KDF_ALGORITHM: u16 = 0x0102;
|
||||
const TAG_KDF_ITERATIONS: u16 = 0x0105;
|
||||
const TAG_KDF_MEMORY_KIB: u16 = 0x0104;
|
||||
const TAG_KDF_PARALLELISM: u16 = 0x0106;
|
||||
const TAG_KDF_SALT: u16 = 0x0107;
|
||||
const TAG_KDF_VERSION: u16 = 0x0103;
|
||||
const TAG_MAGIC: u16 = 0x0001;
|
||||
const TAG_OWNER_AUTH_PUBLIC_KEY: u16 = 0x0003;
|
||||
const TAG_SLOT_ID: u16 = 0x0100;
|
||||
const TAG_SLOT_ROLE: u16 = 0x0101;
|
||||
const TAG_STATE_SIGNATURE_ALGORITHM: u16 = 0x0500;
|
||||
const TAG_VIEW_ENABLED: u16 = 0x0010;
|
||||
const TAG_VIEW_ROLE: u16 = 0x0011;
|
||||
const TAG_VIEW_SLOT_ID: u16 = 0x0012;
|
||||
const TAG_WRAP_ALGORITHM: u16 = 0x0108;
|
||||
const TAG_WRAP_CIPHERTEXT: u16 = 0x010A;
|
||||
const TAG_WRAP_NONCE: u16 = 0x0109;
|
||||
|
||||
/// Builds the normative OWNER state-signature transcript for one validated V2 envelope.
|
||||
pub(crate) fn state_transcript_v2(envelope: &crate::KspWalletEnvelopeV2) -> std::vec::Vec<u8> {
|
||||
let mut output = start(crate::KSPWALLET_V2_STATE_TRANSCRIPT_DOMAIN);
|
||||
push_common(&mut output, envelope);
|
||||
push_bool(&mut output, TAG_VIEW_ENABLED, envelope.view_descriptor().enabled());
|
||||
push_u8(&mut output, TAG_VIEW_ROLE, crate::WalletKeySlotRoleV2::View.wire_id());
|
||||
match envelope.view_descriptor().slot_id() {
|
||||
std::option::Option::Some(slot_id) => push_bytes(&mut output, TAG_VIEW_SLOT_ID, slot_id),
|
||||
std::option::Option::None => push_bytes(&mut output, TAG_VIEW_SLOT_ID, &[]),
|
||||
}
|
||||
push_slot(&mut output, envelope.owner_slot(), true);
|
||||
push_compartment(&mut output, envelope.owner_control(), true);
|
||||
push_compartment(&mut output, envelope.metadata(), true);
|
||||
push_compartment(&mut output, envelope.secret(), true);
|
||||
push_u8(&mut output, TAG_STATE_SIGNATURE_ALGORITHM, envelope.state_signature().algorithm().wire_id());
|
||||
return output;
|
||||
}
|
||||
|
||||
/// Builds the normative wrapping AAD for one validated V2 OWNER or VIEW key slot.
|
||||
pub(crate) fn slot_aad_v2(envelope: &crate::KspWalletEnvelopeV2, slot: &crate::WalletKeySlotV2) -> std::vec::Vec<u8> {
|
||||
let domain = match slot.role() {
|
||||
crate::WalletKeySlotRoleV2::Owner => crate::KSPWALLET_V2_OWNER_SLOT_AAD_DOMAIN,
|
||||
crate::WalletKeySlotRoleV2::View => crate::KSPWALLET_V2_VIEW_SLOT_AAD_DOMAIN,
|
||||
};
|
||||
let mut output = start(domain);
|
||||
push_common(&mut output, envelope);
|
||||
push_slot(&mut output, slot, false);
|
||||
return output;
|
||||
}
|
||||
|
||||
/// Builds the normative AEAD AAD for one validated V2 encrypted compartment.
|
||||
pub(crate) fn compartment_aad_v2(envelope: &crate::KspWalletEnvelopeV2, compartment: &crate::WalletEncryptedCompartmentV2) -> std::vec::Vec<u8> {
|
||||
let domain = match compartment.kind() {
|
||||
crate::WalletCompartmentKindV2::OwnerControl => crate::KSPWALLET_V2_OWNER_CONTROL_AAD_DOMAIN,
|
||||
crate::WalletCompartmentKindV2::Metadata => crate::KSPWALLET_V2_METADATA_AAD_DOMAIN,
|
||||
crate::WalletCompartmentKindV2::Secret => crate::KSPWALLET_V2_SECRET_AAD_DOMAIN,
|
||||
};
|
||||
let mut output = start(domain);
|
||||
push_common(&mut output, envelope);
|
||||
push_compartment(&mut output, compartment, false);
|
||||
return output;
|
||||
}
|
||||
|
||||
fn start(domain: &[u8]) -> std::vec::Vec<u8> {
|
||||
let mut output = std::vec::Vec::with_capacity(512);
|
||||
output.extend_from_slice(domain);
|
||||
output.push(0);
|
||||
return output;
|
||||
}
|
||||
|
||||
fn push_bool(output: &mut std::vec::Vec<u8>, tag: u16, value: bool) {
|
||||
let byte = if value { 1_u8 } else { 0_u8 };
|
||||
push_bytes(output, tag, &[byte]);
|
||||
return;
|
||||
}
|
||||
|
||||
fn push_bytes(output: &mut std::vec::Vec<u8>, tag: u16, value: &[u8]) {
|
||||
output.extend_from_slice(tag.to_be_bytes().as_slice());
|
||||
let length = value.len() as u64;
|
||||
output.extend_from_slice(length.to_be_bytes().as_slice());
|
||||
output.extend_from_slice(value);
|
||||
return;
|
||||
}
|
||||
|
||||
fn push_common(output: &mut std::vec::Vec<u8>, envelope: &crate::KspWalletEnvelopeV2) {
|
||||
push_bytes(output, TAG_MAGIC, crate::KSPWALLET_MAGIC.as_bytes());
|
||||
push_u32(output, TAG_FORMAT_VERSION, envelope.format_version());
|
||||
push_bytes(output, TAG_OWNER_AUTH_PUBLIC_KEY, envelope.owner_auth_public_key());
|
||||
return;
|
||||
}
|
||||
|
||||
fn push_compartment(output: &mut std::vec::Vec<u8>, compartment: &crate::WalletEncryptedCompartmentV2, include_ciphertext: bool) {
|
||||
push_u8(output, TAG_COMPARTMENT_KIND, compartment.kind().wire_id());
|
||||
push_u32(output, TAG_COMPARTMENT_VERSION, compartment.payload_version());
|
||||
push_u8(output, TAG_COMPARTMENT_ALGORITHM, compartment.algorithm().wire_id());
|
||||
if include_ciphertext {
|
||||
push_bytes(output, TAG_COMPARTMENT_NONCE, compartment.nonce());
|
||||
push_bytes(output, TAG_COMPARTMENT_CIPHERTEXT, compartment.ciphertext());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
fn push_slot(output: &mut std::vec::Vec<u8>, slot: &crate::WalletKeySlotV2, include_wrap_payload: bool) {
|
||||
push_bytes(output, TAG_SLOT_ID, slot.slot_id());
|
||||
push_u8(output, TAG_SLOT_ROLE, slot.role().wire_id());
|
||||
push_u8(output, TAG_KDF_ALGORITHM, slot.kdf().algorithm().wire_id());
|
||||
push_u32(output, TAG_KDF_VERSION, slot.kdf().version());
|
||||
push_u32(output, TAG_KDF_MEMORY_KIB, slot.kdf().memory_kib());
|
||||
push_u32(output, TAG_KDF_ITERATIONS, slot.kdf().iterations());
|
||||
push_u32(output, TAG_KDF_PARALLELISM, slot.kdf().parallelism());
|
||||
push_bytes(output, TAG_KDF_SALT, slot.kdf().salt());
|
||||
push_u8(output, TAG_WRAP_ALGORITHM, slot.wrap().algorithm().wire_id());
|
||||
if include_wrap_payload {
|
||||
push_bytes(output, TAG_WRAP_NONCE, slot.wrap().nonce());
|
||||
push_bytes(output, TAG_WRAP_CIPHERTEXT, slot.wrap().ciphertext());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
fn push_u32(output: &mut std::vec::Vec<u8>, tag: u16, value: u32) {
|
||||
push_bytes(output, tag, value.to_be_bytes().as_slice());
|
||||
return;
|
||||
}
|
||||
|
||||
fn push_u8(output: &mut std::vec::Vec<u8>, tag: u16, value: u8) {
|
||||
push_bytes(output, tag, &[value]);
|
||||
return;
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[path = "../unit_tests/transcript_v2.rs"]
|
||||
mod tests;
|
||||
1037
crates/ksp-wallet-lib/src/wire_v2.rs
Normal file
1037
crates/ksp-wallet-lib/src/wire_v2.rs
Normal file
File diff suppressed because it is too large
Load Diff
BIN
crates/ksp-wallet-lib/tests/fixtures/kspwallet_v2_wire_only.bin
vendored
Normal file
BIN
crates/ksp-wallet-lib/tests/fixtures/kspwallet_v2_wire_only.bin
vendored
Normal file
Binary file not shown.
@@ -1,5 +1,5 @@
|
||||
// file: crates/ksp-wallet-lib/tests/public_api.rs
|
||||
// version: 9
|
||||
// version: 10
|
||||
|
||||
//! Public API canaries for the Wallet foundation.
|
||||
|
||||
@@ -81,6 +81,25 @@ fn strict_v1_envelope_and_transcript_are_available_from_crate_root() -> ksp_core
|
||||
return std::result::Result::Ok(());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn public_pre_015_v2_binary_wire_codec_is_available_from_crate_root() -> ksp_core_lib::Result<()> {
|
||||
let source = include_bytes!("fixtures/kspwallet_v2_wire_only.bin");
|
||||
let envelope = match ksp_wallet_lib::KspWalletEnvelopeV2::parse_binary(source) {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||
};
|
||||
assert_eq!(envelope.format_version(), ksp_wallet_lib::KSPWALLET_FORMAT_VERSION_V2);
|
||||
assert_eq!(envelope.owner_slot().role(), ksp_wallet_lib::WalletKeySlotRoleV2::Owner);
|
||||
assert!(envelope.view_descriptor().enabled());
|
||||
assert_eq!(envelope.metadata().kind(), ksp_wallet_lib::WalletCompartmentKindV2::Metadata);
|
||||
let encoded = match envelope.to_binary_bytes() {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||
};
|
||||
assert_eq!(encoded.as_slice(), source);
|
||||
return std::result::Result::Ok(());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn public_pre_005_create_open_and_calibrated_defaults_are_available_from_crate_root() {
|
||||
let _ = ksp_wallet_lib::create_wallet_v1;
|
||||
|
||||
55
crates/ksp-wallet-lib/unit_tests/transcript_v2.rs
Normal file
55
crates/ksp-wallet-lib/unit_tests/transcript_v2.rs
Normal file
@@ -0,0 +1,55 @@
|
||||
// file: crates/ksp-wallet-lib/unit_tests/transcript_v2.rs
|
||||
// version: 1
|
||||
|
||||
const FIXTURE: &[u8] = include_bytes!("../tests/fixtures/kspwallet_v2_wire_only.bin");
|
||||
|
||||
#[test]
|
||||
fn v2_state_transcript_is_domain_separated_and_deterministic() -> ksp_core_lib::Result<()> {
|
||||
let envelope = match crate::KspWalletEnvelopeV2::parse_binary(FIXTURE) {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||
};
|
||||
let first = envelope.state_transcript();
|
||||
let second = envelope.state_transcript();
|
||||
assert_eq!(first, second);
|
||||
assert!(first.starts_with(crate::KSPWALLET_V2_STATE_TRANSCRIPT_DOMAIN));
|
||||
assert!(!first.starts_with(crate::KSPWALLET_V1_STATE_TRANSCRIPT_DOMAIN));
|
||||
return std::result::Result::Ok(());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn v2_owner_and_view_slot_aad_are_role_domain_separated() -> ksp_core_lib::Result<()> {
|
||||
let envelope = match crate::KspWalletEnvelopeV2::parse_binary(FIXTURE) {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||
};
|
||||
let owner = envelope.owner_slot_aad();
|
||||
let view = match envelope.view_slot_aad() {
|
||||
std::option::Option::Some(value) => value,
|
||||
std::option::Option::None => {
|
||||
return std::result::Result::Err(ksp_core_lib::Error::new(crate::ERROR_CODE_FORMAT_INVALID, "fixture VIEW slot is missing"));
|
||||
},
|
||||
};
|
||||
assert!(owner.starts_with(crate::KSPWALLET_V2_OWNER_SLOT_AAD_DOMAIN));
|
||||
assert!(view.starts_with(crate::KSPWALLET_V2_VIEW_SLOT_AAD_DOMAIN));
|
||||
assert_ne!(owner, view);
|
||||
return std::result::Result::Ok(());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn v2_compartment_aad_is_domain_separated_by_kind() -> ksp_core_lib::Result<()> {
|
||||
let envelope = match crate::KspWalletEnvelopeV2::parse_binary(FIXTURE) {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||
};
|
||||
let owner_control = envelope.compartment_aad(crate::WalletCompartmentKindV2::OwnerControl);
|
||||
let metadata = envelope.compartment_aad(crate::WalletCompartmentKindV2::Metadata);
|
||||
let secret = envelope.compartment_aad(crate::WalletCompartmentKindV2::Secret);
|
||||
assert!(owner_control.starts_with(crate::KSPWALLET_V2_OWNER_CONTROL_AAD_DOMAIN));
|
||||
assert!(metadata.starts_with(crate::KSPWALLET_V2_METADATA_AAD_DOMAIN));
|
||||
assert!(secret.starts_with(crate::KSPWALLET_V2_SECRET_AAD_DOMAIN));
|
||||
assert_ne!(owner_control, metadata);
|
||||
assert_ne!(metadata, secret);
|
||||
assert_ne!(owner_control, secret);
|
||||
return std::result::Result::Ok(());
|
||||
}
|
||||
136
crates/ksp-wallet-lib/unit_tests/wire_v2.rs
Normal file
136
crates/ksp-wallet-lib/unit_tests/wire_v2.rs
Normal file
@@ -0,0 +1,136 @@
|
||||
// file: crates/ksp-wallet-lib/unit_tests/wire_v2.rs
|
||||
// version: 1
|
||||
|
||||
const FIXTURE: &[u8] = include_bytes!("../tests/fixtures/kspwallet_v2_wire_only.bin");
|
||||
const V1_JSON_FIXTURE: &[u8] = include_bytes!("../tests/fixtures/kspwallet_v1_wire_only.json");
|
||||
|
||||
#[test]
|
||||
fn strict_v2_fixture_parses_and_round_trips_byte_exact() -> ksp_core_lib::Result<()> {
|
||||
let parsed = match crate::KspWalletEnvelopeV2::parse_binary(FIXTURE) {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||
};
|
||||
assert_eq!(parsed.format_version(), crate::KSPWALLET_FORMAT_VERSION_V2);
|
||||
assert!(parsed.view_descriptor().enabled());
|
||||
assert_eq!(parsed.owner_slot().role(), crate::WalletKeySlotRoleV2::Owner);
|
||||
assert_eq!(parsed.view_slot().map(crate::WalletKeySlotV2::role), std::option::Option::Some(crate::WalletKeySlotRoleV2::View));
|
||||
assert_eq!(parsed.owner_control().kind(), crate::WalletCompartmentKindV2::OwnerControl);
|
||||
assert_eq!(parsed.metadata().kind(), crate::WalletCompartmentKindV2::Metadata);
|
||||
assert_eq!(parsed.secret().kind(), crate::WalletCompartmentKindV2::Secret);
|
||||
let encoded = match parsed.to_binary_bytes() {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||
};
|
||||
assert_eq!(encoded.as_slice(), FIXTURE);
|
||||
return std::result::Result::Ok(());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn v2_wire_fixture_is_materially_smaller_than_equivalent_v1_json_fixture() {
|
||||
assert!(FIXTURE.len() < V1_JSON_FIXTURE.len());
|
||||
assert_eq!(FIXTURE.len(), 628);
|
||||
assert_eq!(V1_JSON_FIXTURE.len(), 2037);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unknown_v2_format_version_is_rejected_before_body_parsing() {
|
||||
let mut source = FIXTURE.to_vec();
|
||||
source[9..11].copy_from_slice(3_u16.to_be_bytes().as_slice());
|
||||
let result = crate::KspWalletEnvelopeV2::parse_binary(source.as_slice());
|
||||
assert!(result.is_err());
|
||||
let error = match result {
|
||||
std::result::Result::Err(error) => error,
|
||||
std::result::Result::Ok(_) => return,
|
||||
};
|
||||
assert_eq!(error.code(), crate::ERROR_CODE_FORMAT_VERSION_UNSUPPORTED);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn declared_length_mismatch_and_trailing_bytes_are_rejected() {
|
||||
let mut mismatched = FIXTURE.to_vec();
|
||||
mismatched[11..15].copy_from_slice(627_u32.to_be_bytes().as_slice());
|
||||
let mismatch_result = crate::KspWalletEnvelopeV2::parse_binary(mismatched.as_slice());
|
||||
assert!(mismatch_result.is_err());
|
||||
let mut trailing = FIXTURE.to_vec();
|
||||
trailing.push(0);
|
||||
trailing[11..15].copy_from_slice(629_u32.to_be_bytes().as_slice());
|
||||
let trailing_result = crate::KspWalletEnvelopeV2::parse_binary(trailing.as_slice());
|
||||
assert!(trailing_result.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unknown_header_flags_are_rejected() {
|
||||
let mut source = FIXTURE.to_vec();
|
||||
source[15..17].copy_from_slice(2_u16.to_be_bytes().as_slice());
|
||||
let result = crate::KspWalletEnvelopeV2::parse_binary(source.as_slice());
|
||||
assert!(result.is_err());
|
||||
let error = match result {
|
||||
std::result::Result::Err(error) => error,
|
||||
std::result::Result::Ok(_) => return,
|
||||
};
|
||||
assert_eq!(error.code(), crate::ERROR_CODE_FORMAT_INVALID);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn enabled_view_descriptor_must_match_the_v2_view_slot() {
|
||||
let mut source = FIXTURE.to_vec();
|
||||
source[49] ^= 0x01;
|
||||
let result = crate::KspWalletEnvelopeV2::parse_binary(source.as_slice());
|
||||
assert!(result.is_err());
|
||||
let error = match result {
|
||||
std::result::Result::Err(error) => error,
|
||||
std::result::Result::Ok(_) => return,
|
||||
};
|
||||
assert_eq!(error.code(), crate::ERROR_CODE_FORMAT_INVALID);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn v2_key_slots_require_canonical_owner_then_view_order() {
|
||||
let mut source = FIXTURE.to_vec();
|
||||
source[65] = 2;
|
||||
let result = crate::KspWalletEnvelopeV2::parse_binary(source.as_slice());
|
||||
assert!(result.is_err());
|
||||
let error = match result {
|
||||
std::result::Result::Err(error) => error,
|
||||
std::result::Result::Ok(_) => return,
|
||||
};
|
||||
assert_eq!(error.code(), crate::ERROR_CODE_FORMAT_INVALID);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn v2_pathological_kdf_parameters_are_rejected_before_crypto() {
|
||||
let mut source = FIXTURE.to_vec();
|
||||
source[87..91].copy_from_slice(0_u32.to_be_bytes().as_slice());
|
||||
let result = crate::KspWalletEnvelopeV2::parse_binary(source.as_slice());
|
||||
assert!(result.is_err());
|
||||
let error = match result {
|
||||
std::result::Result::Err(error) => error,
|
||||
std::result::Result::Ok(_) => return,
|
||||
};
|
||||
assert_eq!(error.code(), crate::ERROR_CODE_CRYPTO_PARAMETERS_INVALID);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn v2_oversized_document_is_rejected_before_body_allocation() {
|
||||
let oversized = std::vec![0_u8; crate::KSPWALLET_MAX_FILE_BYTES + 1];
|
||||
let result = crate::KspWalletEnvelopeV2::parse_binary(oversized.as_slice());
|
||||
assert!(result.is_err());
|
||||
let error = match result {
|
||||
std::result::Result::Err(error) => error,
|
||||
std::result::Result::Ok(_) => return,
|
||||
};
|
||||
assert_eq!(error.code(), crate::ERROR_CODE_FORMAT_INVALID);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn v2_envelope_debug_does_not_render_ciphertext_contents() -> ksp_core_lib::Result<()> {
|
||||
let parsed = match crate::KspWalletEnvelopeV2::parse_binary(FIXTURE) {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||
};
|
||||
let rendered = format!("{parsed:?}");
|
||||
assert!(rendered.contains("ciphertext_bytes"));
|
||||
assert!(!rendered.contains("128, 129, 130, 131"));
|
||||
assert!(!rendered.contains("224, 225, 226, 227"));
|
||||
return std::result::Result::Ok(());
|
||||
}
|
||||
435
deltas/0.2.6/pre.015.md
Normal file
435
deltas/0.2.6/pre.015.md
Normal file
@@ -0,0 +1,435 @@
|
||||
<!-- file: deltas/0.2.6/pre.015.md -->
|
||||
<!-- version: 1 -->
|
||||
|
||||
# Delta `0.2.6-pre.015` — wire binaire `.kspwallet` V2 et codec canonique
|
||||
|
||||
## Base requise
|
||||
|
||||
```text
|
||||
0.2.6-pre.014-fix.001 appliquée
|
||||
workspace.package.version = 0.2.6-pre.14.fix.1
|
||||
```
|
||||
|
||||
Le checkpoint opérateur de la base est intégralement vert :
|
||||
|
||||
```text
|
||||
cargo fmt --all OK
|
||||
python3 scripts/audit_rust_workspace_rules.py clean
|
||||
cargo check --workspace OK
|
||||
cargo clippy --workspace --all-targets OK
|
||||
cargo test -p ksp-app-config-desk OK
|
||||
cargo test -p ksp-app-wallet-desk OK
|
||||
cargo test --workspace OK
|
||||
Wallet Desk release_compliance 4/4 OK
|
||||
smokes live toujours opt-in/ignored
|
||||
Tauri Config Desk crate-local OK visuel
|
||||
Tauri Wallet Desk crate-local OK visuel + import/balance Devnet manuel
|
||||
```
|
||||
|
||||
Le correctif `pre.014-fix.001` est donc accepté comme base de `pre.015`.
|
||||
|
||||
## Type de livraison
|
||||
|
||||
Cette tranche est fournie sous forme de **delta uniquement**, à appliquer sur la base précédente :
|
||||
|
||||
```text
|
||||
ksp-general-0.2.6-pre.015-delta.zip
|
||||
```
|
||||
|
||||
Le signal technique devient :
|
||||
|
||||
```text
|
||||
workspace.package.version = 0.2.6-pre.15
|
||||
commit = v0.2.6-pre.015
|
||||
```
|
||||
|
||||
Aucun tag prerelease.
|
||||
|
||||
Les `package.json` et `tauri.conf.json` des applications ne changent pas : `pre.015` ne modifie ni frontend, ni Tauri, ni contrat de build des Desks.
|
||||
|
||||
## Objectif de la tranche
|
||||
|
||||
`pre.015` fige le **format `.kspwallet` V2 binaire** et son codec structurel strict dans `ksp-wallet-lib`.
|
||||
|
||||
Cette tranche réalise :
|
||||
|
||||
```text
|
||||
spécification normative V2
|
||||
framing binaire KSP propriétaire
|
||||
codec parse/serialize byte-exact
|
||||
identifiants numériques stables
|
||||
bornes structurelles avant crypto
|
||||
transcripts/AAD V2 séparés de V1
|
||||
fixture binaire canonique wire-only
|
||||
tests déterministes du codec et des invariants
|
||||
API publique du codec V2 depuis la racine de crate
|
||||
documentation de la politique default != latest
|
||||
réalignement du plan 0.2.6 et des releases 0.2.7+
|
||||
```
|
||||
|
||||
Cette tranche **ne réalise pas encore** :
|
||||
|
||||
```text
|
||||
create_wallet_file_v2
|
||||
open_wallet_*_file_v2
|
||||
façades génériques multi-version
|
||||
basculement de Wallet Desk vers les façades génériques
|
||||
migration V1 -> V2
|
||||
réécriture automatique de wallets V1
|
||||
second facteur / V3
|
||||
build Tauri de production
|
||||
```
|
||||
|
||||
Ces responsabilités restent réparties entre `pre.016`, `pre.017` et `pre.018`.
|
||||
|
||||
## Décision V1 / V2
|
||||
|
||||
V1 reste un format stable historique :
|
||||
|
||||
```text
|
||||
format_version = 1
|
||||
JSON UTF-8 strict
|
||||
bytes -> Base64URL sans padding
|
||||
APIs _v1 conservées
|
||||
lecture durable obligatoire
|
||||
```
|
||||
|
||||
V2 est un nouveau format explicite :
|
||||
|
||||
```text
|
||||
format_version = 2
|
||||
wire binaire KSP
|
||||
aucune Base64
|
||||
aucune compression
|
||||
entiers multi-octets big-endian
|
||||
ordre et cardinalité canoniques
|
||||
aucun trailing byte
|
||||
```
|
||||
|
||||
Le caractère binaire n'est pas présenté comme une mesure cryptographique. Les propriétés de confidentialité/authenticité restent possédées par Argon2id, XChaCha20-Poly1305, Ed25519 et les règles VIEW/OWNER.
|
||||
|
||||
## Wire V2
|
||||
|
||||
Le document commence par :
|
||||
|
||||
```text
|
||||
magic 9 bytes = KSPWALLET
|
||||
format_version u16 BE = 2
|
||||
document_length u32 BE = taille totale exacte
|
||||
flags u16 BE
|
||||
owner_auth_public_key 32 bytes
|
||||
view_slot_id 16 bytes si VIEW_ENABLED
|
||||
```
|
||||
|
||||
Flags :
|
||||
|
||||
```text
|
||||
bit 0 = VIEW_ENABLED
|
||||
autres bits = réservés et obligatoirement zéro
|
||||
```
|
||||
|
||||
Le body est strictement :
|
||||
|
||||
```text
|
||||
OWNER key slot
|
||||
VIEW key slot si VIEW_ENABLED
|
||||
OWNER-CONTROL compartment
|
||||
METADATA compartment
|
||||
SECRET compartment
|
||||
state signature
|
||||
EOF immédiat
|
||||
```
|
||||
|
||||
Les slots et compartiments transportent leurs IDs numériques de rôle/kind/algorithme, leurs longueurs explicites et leurs bytes directement.
|
||||
|
||||
Bornes et détails complets :
|
||||
|
||||
```text
|
||||
docs/formats/KSPWALLET_V2.md
|
||||
```
|
||||
|
||||
## Codec strict
|
||||
|
||||
Nouveau module :
|
||||
|
||||
```text
|
||||
crates/ksp-wallet-lib/src/wire_v2.rs
|
||||
```
|
||||
|
||||
Surface publique principale :
|
||||
|
||||
```rust
|
||||
KspWalletEnvelopeV2::parse_binary(...)
|
||||
KspWalletEnvelopeV2::to_binary_bytes(...)
|
||||
```
|
||||
|
||||
Le parser rejette avant toute opération cryptographique :
|
||||
|
||||
```text
|
||||
> 1 MiB
|
||||
magic/version incorrects
|
||||
document_length incohérent
|
||||
flags réservés
|
||||
troncature / longueur hors input
|
||||
role/kind/algorithme inconnu
|
||||
ordre OWNER/VIEW ou compartiments non canonique
|
||||
VIEW descriptor incohérent
|
||||
Argon2 structurellement invalide
|
||||
salt/ciphertext hors bornes
|
||||
payload_version non supporté
|
||||
trailing bytes
|
||||
```
|
||||
|
||||
Le codec n'authentifie ni ne déchiffre encore un wallet V2 ; cette composition avec les primitives Wallet existantes est réservée à `pre.016`.
|
||||
|
||||
## Transcripts et AAD V2
|
||||
|
||||
Nouveau module :
|
||||
|
||||
```text
|
||||
crates/ksp-wallet-lib/src/transcript_v2.rs
|
||||
```
|
||||
|
||||
V2 possède des domain separators distincts :
|
||||
|
||||
```text
|
||||
KSPWALLET-V2-STATE
|
||||
KSPWALLET-V2-AAD-OWNER-SLOT
|
||||
KSPWALLET-V2-AAD-VIEW-SLOT
|
||||
KSPWALLET-V2-AAD-OWNER-CONTROL
|
||||
KSPWALLET-V2-AAD-METADATA
|
||||
KSPWALLET-V2-AAD-SECRET
|
||||
```
|
||||
|
||||
La discipline TLV déterministe de V1 est conservée mais les rôles, algorithmes et kinds V2 sont transcriptés sous leurs IDs numériques. Les domains V1/V2 restent séparés pour éviter toute interchangeabilité cryptographique entre versions.
|
||||
|
||||
Le VIEW wrap mutable reste hors du state transcript, comme en V1 ; le descriptor signé lie son identité stable et permet la self-rotation VIEW sans OWNER.
|
||||
|
||||
## Fixture canonique
|
||||
|
||||
Nouvelle fixture structurelle :
|
||||
|
||||
```text
|
||||
crates/ksp-wallet-lib/tests/fixtures/kspwallet_v2_wire_only.bin
|
||||
```
|
||||
|
||||
Mesure :
|
||||
|
||||
```text
|
||||
V1 JSON wire-only = 2037 octets
|
||||
V2 binary wire-only = 628 octets
|
||||
réduction = 1409 octets, environ 69,2 %
|
||||
```
|
||||
|
||||
Hash du fixture V2 :
|
||||
|
||||
```text
|
||||
sha256 = cbacb37326c76e6dde8d614601cd765a8c0fd9744f891d640b8a3cd71cf60a93
|
||||
```
|
||||
|
||||
Cette fixture valide framing/canonicalité ; elle n'est pas revendiquée comme un wallet V2 cryptographiquement authentifié tant que création/open V2 n'est pas matérialisé en `pre.016`.
|
||||
|
||||
## Politique API durable : default distinct de latest
|
||||
|
||||
La documentation fige dès `pre.015` la politique qui sera matérialisée en code dans `pre.016`.
|
||||
|
||||
Deux notions doivent rester distinctes :
|
||||
|
||||
```text
|
||||
DEFAULT_WALLET_FORMAT
|
||||
LATEST_SUPPORTED_WALLET_FORMAT
|
||||
```
|
||||
|
||||
Après intégration runtime V2 :
|
||||
|
||||
```text
|
||||
DEFAULT_WALLET_FORMAT = V2
|
||||
LATEST_SUPPORTED_WALLET_FORMAT = V2
|
||||
```
|
||||
|
||||
Si V3 existe plus tard :
|
||||
|
||||
```text
|
||||
DEFAULT_WALLET_FORMAT = V2 # peut rester V2
|
||||
LATEST_SUPPORTED_WALLET_FORMAT = V3
|
||||
```
|
||||
|
||||
Une nouvelle version supportée ne change jamais automatiquement le default.
|
||||
|
||||
### Création
|
||||
|
||||
API générique :
|
||||
|
||||
```text
|
||||
create_wallet_file(...) -> DEFAULT_WALLET_FORMAT, donc V2
|
||||
```
|
||||
|
||||
APIs forcées :
|
||||
|
||||
```text
|
||||
create_wallet_file_v1(...)
|
||||
create_wallet_file_v2(...)
|
||||
create_wallet_file_v3(...) si V3 existe un jour
|
||||
```
|
||||
|
||||
Les fonctions `_vN` restent une possibilité explicite pour les applications qui veulent imposer un wire précis.
|
||||
|
||||
### Lecture / inspection
|
||||
|
||||
API générique :
|
||||
|
||||
```text
|
||||
open_wallet_*_file(...)
|
||||
inspect_locked_wallet_file(...)
|
||||
```
|
||||
|
||||
doit détecter et dispatcher les versions supportées.
|
||||
|
||||
API versionnée :
|
||||
|
||||
```text
|
||||
open_wallet_*_file_v1(...)
|
||||
open_wallet_*_file_v2(...)
|
||||
inspect_locked_wallet_file_v1(...)
|
||||
inspect_locked_wallet_file_v2(...)
|
||||
```
|
||||
|
||||
doit exiger exactement la version indiquée.
|
||||
|
||||
La même règle est appliquée aux autres opérations pour lesquelles la version native du fichier est pertinente.
|
||||
|
||||
## Future V3 / second facteur
|
||||
|
||||
V2 est volontairement **sans second facteur**.
|
||||
|
||||
Si un futur V3 introduit password + 2FA :
|
||||
|
||||
```text
|
||||
ksp-wallet-lib possède la politique d'autorisation
|
||||
ksp-wallet-lib décide si un second facteur est requis
|
||||
ksp-wallet-lib possède challenge et validation cryptographique
|
||||
WalletOwner est impossible tant que les facteurs exigés ne sont pas satisfaits
|
||||
Wallet Desk ne décide jamais qu'une preuve 2FA est valide
|
||||
```
|
||||
|
||||
Wallet Desk ou un autre client peut néanmoins évoluer pour l'UX interactive : OTP, push/attente, enrollment, recovery, hardware/WebAuthn ou consentement externe.
|
||||
|
||||
`ksp-wallet-lib` doit conserver sa frontière autonome vis-à-vis de Config/Transport/Tauri. Si un fournisseur réseau est nécessaire, une abstraction/provider KSP séparée peut obtenir la preuve tandis que Wallet reste propriétaire de la règle d'autorisation.
|
||||
|
||||
## Nouveau découpage de `0.2.6`
|
||||
|
||||
La documentation/candidate anciennement prévue en `pre.015` est repoussée afin de ne pas mélanger wire, runtime/migration et packaging :
|
||||
|
||||
```text
|
||||
pre.015 wire binaire V2 + codec canonique
|
||||
pre.016 APIs génériques/versionnées + création/open V2 + Wallet Desk sur API générique
|
||||
pre.017 migration explicite V1 -> V2 + persistence/canaris + régression Wallet Desk
|
||||
pre.018 documentation finale + candidate + stratégie release/bundle/CWD + build Tauri final
|
||||
rel.001 publication stable v0.2.6
|
||||
```
|
||||
|
||||
Le build Tauri reste interdit avant `pre.018` et devra être l'absolue dernière opération de validation de la candidate.
|
||||
|
||||
## Réalignement de la série
|
||||
|
||||
`pre.014` avait temporairement intercalé le chantier binaire en `0.2.7`. Cette décision est superseded puisque V2 est désormais traité dans `0.2.6`.
|
||||
|
||||
La suite redevient :
|
||||
|
||||
```text
|
||||
0.2.7 WebSocket Solana standard
|
||||
0.2.8 Helius LaserStream WebSocket
|
||||
0.2.9 Yellowstone gRPC standard/provider-neutral
|
||||
0.2.10 off-chain price transport
|
||||
0.2.11 price visualization desk + intégration Wallet Desk
|
||||
0.2.12 interface/wire foundation
|
||||
0.2.13 program-api foundation
|
||||
```
|
||||
|
||||
Le prompt `prompts/012-V0_2_7_START_PROMPT.md` est réaligné sur WebSocket Solana standard.
|
||||
|
||||
## Fichiers ajoutés
|
||||
|
||||
```text
|
||||
crates/ksp-wallet-lib/src/transcript_v2.rs
|
||||
crates/ksp-wallet-lib/src/wire_v2.rs
|
||||
crates/ksp-wallet-lib/tests/fixtures/kspwallet_v2_wire_only.bin
|
||||
crates/ksp-wallet-lib/unit_tests/transcript_v2.rs
|
||||
crates/ksp-wallet-lib/unit_tests/wire_v2.rs
|
||||
docs/formats/KSPWALLET_V2.md
|
||||
deltas/0.2.6/pre.015.md
|
||||
```
|
||||
|
||||
## Fichiers modifiés
|
||||
|
||||
```text
|
||||
Cargo.toml
|
||||
ROADMAP.md
|
||||
crates/ksp-wallet-lib/README.md
|
||||
crates/ksp-wallet-lib/USAGE.md
|
||||
crates/ksp-wallet-lib/src/constants.rs
|
||||
crates/ksp-wallet-lib/src/lib.rs
|
||||
crates/ksp-wallet-lib/tests/public_api.rs
|
||||
docs/000-README.md
|
||||
docs/IDEAS.md
|
||||
docs/architecture/004-COMPONENT_INVENTORY.md
|
||||
docs/formats/000-README.md
|
||||
docs/formats/KSPWALLET_V1.md
|
||||
docs/plans/000-README.md
|
||||
docs/plans/002-FUNCTIONAL_RELEASE_SEQUENCE.md
|
||||
docs/plans/013-V0_2_6_WALLET_DESK_PLAN.md
|
||||
docs/validation/009-V0_2_6_WALLET_DESK_COMPLIANCE.md
|
||||
prompts/000-README.md
|
||||
prompts/011-V0_2_6_START_PROMPT.md
|
||||
prompts/012-V0_2_7_START_PROMPT.md
|
||||
```
|
||||
|
||||
## Fichiers volontairement non modifiés
|
||||
|
||||
```text
|
||||
CHANGELOG.md
|
||||
crates/ksp-app-config-desk/*
|
||||
crates/ksp-app-wallet-desk/*
|
||||
```
|
||||
|
||||
Le CHANGELOG reste réservé à la clôture. Les Desks ne changent pas tant que la façade générique/runtime V2 n'est pas prête en `pre.016`.
|
||||
|
||||
## Contrôles assistant
|
||||
|
||||
L'environnement de génération ne fournit pas `cargo`, `rustc` ou `rustfmt`. Les contrôles exécutables disponibles sont donc structurels :
|
||||
|
||||
```text
|
||||
python3 scripts/audit_rust_workspace_rules.py requis avant livraison
|
||||
fixture V2 header/length/layout vérification indépendante
|
||||
fixture V2 sha256 vérification indépendante
|
||||
comparaison V1/V2 2037 / 628 octets
|
||||
delta vérifié contre pre.014-fix.001
|
||||
```
|
||||
|
||||
Compilation, Clippy et tests restent autoritatifs côté opérateur.
|
||||
|
||||
## Validation opérateur requise
|
||||
|
||||
Après application du delta :
|
||||
|
||||
```bash
|
||||
cargo fmt --all
|
||||
python3 scripts/audit_rust_workspace_rules.py
|
||||
cargo check --workspace
|
||||
cargo clippy --workspace --all-targets
|
||||
cargo test -p ksp-wallet-lib
|
||||
cargo test -p ksp-app-wallet-desk
|
||||
cargo test --workspace
|
||||
```
|
||||
|
||||
Points attendus :
|
||||
|
||||
```text
|
||||
V1 reste intégralement vert
|
||||
nouveaux tests wire_v2/transcript_v2 verts
|
||||
public API V2 codec visible depuis crate root
|
||||
aucune régression Wallet Desk
|
||||
smokes réseau restent ignored sauf opt-in explicite
|
||||
```
|
||||
|
||||
**Ne pas exécuter `cargo tauri build` en `pre.015`.** Le build final reste réservé à `pre.018` et doit demeurer l'ultime opération de validation de `0.2.6`.
|
||||
File diff suppressed because one or more lines are too long
@@ -1,5 +1,5 @@
|
||||
<!-- file: docs/IDEAS.md -->
|
||||
<!-- version: 20 -->
|
||||
<!-- version: 21 -->
|
||||
|
||||
# Idées à explorer
|
||||
|
||||
@@ -202,13 +202,13 @@ Formats/cibles à inventorier et prioriser selon usage réel :
|
||||
|
||||
Chaque format doit être étudié côté sécurité, round-trip, secret/public, dépendances et compatibilité avant engagement.
|
||||
|
||||
### Conteneur binaire `.kspwallet` et formats logiques futurs
|
||||
### `.kspwallet` V2 binaire et formats futurs
|
||||
|
||||
**Status :** Retenu pour audit en `0.2.7` / facteurs futurs à explorer
|
||||
**Status :** V2 retenu et matérialisé en `0.2.6-pre.015` / facteurs futurs à explorer
|
||||
|
||||
Le JSON V1 actuel est un format d’interop lisible. Base64 seul n’apporte aucune sécurité et resterait un texte trivialement décodable avec environ un tiers de surcharge. `0.2.7` doit donc étudier un **conteneur de persistence binaire versionné** séparé du `format_version` logique/cryptographique : magic/framing explicite, lecture rétrocompatible du JSON V1 historique, écriture binaire par défaut après validation, migration explicite et test vectors. Le choix du codec/framing exact est audité avant engagement ; il ne doit pas casser les transcripts/AAD, VIEW/OWNER, keypair ou import/export.
|
||||
Le JSON V1 actuel reste le format historique stable et lisible. Base64 seul n’apporte aucune sécurité et resterait un texte trivialement décodable avec environ un tiers de surcharge. La décision initialement envisagée pour `0.2.7` a été ramenée dans `0.2.6` : `pre.015` définit un **wire binaire V2 KSP** avec magic/framing explicite, entiers big-endian, identifiants numériques stables, longueurs bornées et lecture/écriture canonique stricte. V1 reste supporté sans réinterprétation ; la façade de lecture multi-version, la création V2 et la politique `DEFAULT_WALLET_FORMAT = V2` arrivent en `pre.016`, puis la migration explicite V1 -> V2 en `pre.017`. Le V2 ne modifie pas à lui seul les garanties cryptographiques de VIEW/OWNER, keypair ou import/export.
|
||||
|
||||
Un futur `format_version >= 2` pourra introduire d’autres modèles d’autorisation, notamment password + facteur supplémentaire. `ksp-wallet-lib` restera propriétaire du format, des challenges et de la vérification, mais toute interaction réelle (OTP, enrollment/recovery, hardware/WebAuthn, validation distante) exigera une évolution de Wallet Desk ou du client concerné. Un seed TOTP stocké uniquement dans le même fichier que le wallet ne doit pas être présenté automatiquement comme un second facteur indépendant contre un attaquant possédant ce fichier.
|
||||
V2 est désormais réservé au wire binaire KSP sans second facteur. Un futur V3 pourra introduire d’autres modèles d’autorisation, notamment password + facteur supplémentaire. `ksp-wallet-lib` restera propriétaire du format, des challenges et de la vérification, mais toute interaction réelle (OTP, enrollment/recovery, hardware/WebAuthn, validation distante) exigera une évolution de Wallet Desk ou du client concerné. Un seed TOTP stocké uniquement dans le même fichier que le wallet ne doit pas être présenté automatiquement comme un second facteur indépendant contre un attaquant possédant ce fichier.
|
||||
|
||||
## Pipelines
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!-- file: docs/architecture/004-COMPONENT_INVENTORY.md -->
|
||||
<!-- version: 16 -->
|
||||
<!-- version: 17 -->
|
||||
|
||||
# Inventaire initial des composants KSP
|
||||
|
||||
@@ -26,14 +26,14 @@ Ce document maintient l'inventaire synthétique des composants retenus ou presse
|
||||
| On-chain HTTP | `ksp-onchain-transport-lib` | lib | Stable | `0.2.1`–`0.2.4` | HTTP standard complet : 52/52 current + 14/14 historical |
|
||||
| Wallet | `ksp-wallet-lib` | lib | Stable | `0.2.5` | `.kspwallet`, VIEW/OWNER, secrets, signature, import/export |
|
||||
| Wallet Desk | `ksp-app-wallet-desk` | app | Retenu | `0.2.6` | Wallet + Config composite + HTTP/balance |
|
||||
| Wallet persistence | `ksp-wallet-lib` | lib | Retenu | `0.2.7` | conteneur binaire rétrocompatible autour du payload V1 |
|
||||
| Standard WS | `ksp-onchain-transport-lib` | lib | Retenu | `0.2.8` | WebSocket Solana complet, sessions/subscriptions |
|
||||
| Helius WS | `ksp-onchain-transport-lib` | lib | Retenu | `0.2.9` | LaserStream WebSocket comme extension du moteur standard |
|
||||
| Yellowstone | `ksp-onchain-transport-lib` | lib | Pressenti | `0.2.10` | client gRPC standard/provider-neutral |
|
||||
| Off-chain price | `ksp-offchain-transport-lib` | lib | Retenu | `0.2.11` | première abstraction/provider de prix SOL/USD, SOL/EUR |
|
||||
| Price Desk | nom à fixer | app | Retenu | `0.2.12` | visualisation/validation des prix + intégration Wallet Desk |
|
||||
| Wire | `ksp-interface-lib` | lib | Retenu | `0.2.13` | façade wire officielle + API publique wire |
|
||||
| Program API | `ksp-program-api` | API | Retenu | `0.2.14` | contrats extensibles Program |
|
||||
| Wallet V2 | `ksp-wallet-lib` | lib | En cours | `0.2.6` | wire binaire V2 + API default/versionnée + migration |
|
||||
| Standard WS | `ksp-onchain-transport-lib` | lib | Retenu | `0.2.7` | WebSocket Solana complet, sessions/subscriptions |
|
||||
| Helius WS | `ksp-onchain-transport-lib` | lib | Retenu | `0.2.8` | LaserStream WebSocket comme extension du moteur standard |
|
||||
| Yellowstone | `ksp-onchain-transport-lib` | lib | Pressenti | `0.2.9` | client gRPC standard/provider-neutral |
|
||||
| Off-chain price | `ksp-offchain-transport-lib` | lib | Retenu | `0.2.10` | première abstraction/provider de prix SOL/USD, SOL/EUR |
|
||||
| Price Desk | nom à fixer | app | Retenu | `0.2.11` | visualisation/validation des prix + intégration Wallet Desk |
|
||||
| Wire | `ksp-interface-lib` | lib | Retenu | `0.2.12` | façade wire officielle + API publique wire |
|
||||
| Program API | `ksp-program-api` | API | Retenu | `0.2.13` | contrats extensibles Program |
|
||||
| Program impl. | `ksp-program-lib` | lib | Retenu | vertical slices ultérieurs | implementations Program officielles |
|
||||
| Program extension | `ksp-program-<name>-lib` | lib externe | À la demande | dès besoin | implementation externe de `ksp-program-api` |
|
||||
| Store API | `ksp-store-api` | API | Retenu | `0.3.1` | contrats persistence backend-agnostic, RAW d'abord |
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!-- file: docs/formats/000-README.md -->
|
||||
<!-- version: 5 -->
|
||||
<!-- version: 6 -->
|
||||
|
||||
# Formats KSP
|
||||
|
||||
@@ -10,3 +10,4 @@ Une spécification de format décrit le wire exact, les encodages, les limites,
|
||||
## Formats actifs
|
||||
|
||||
- [`KSPWALLET_V1.md`](KSPWALLET_V1.md) — spécification du format natif autonome `.kspwallet` V1. `0.2.5-pre.003` fige l'enveloppe/wire et les transcripts/AAD, `pre.004` ajoute Argon2id/XChaCha20-Poly1305/CSPRNG OS, `pre.005` fixe les payloads plaintext, le profil de création KSP calibré, l'autorité Ed25519 OWNER et le vecteur complet, `pre.006`–`pre.008` matérialisent persistence/administration/transfert, `pre.009` ferme l'audit adversarial/interoperabilité/compliance et `pre.010` synchronise la documentation finale sans modifier le wire V1.
|
||||
- [`KSPWALLET_V2.md`](KSPWALLET_V2.md) — wire binaire natif V2 introduit par `0.2.6-pre.015` : framing canonique KSP, IDs numériques, longueurs big-endian, aucun Base64/compression, domains/transcripts V2 distincts et politique `default != latest`.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!-- file: docs/formats/KSPWALLET_V1.md -->
|
||||
<!-- version: 11 -->
|
||||
<!-- version: 12 -->
|
||||
|
||||
# `.kspwallet` V1 — spécification du format natif Wallet KSP
|
||||
|
||||
@@ -22,6 +22,8 @@ règles unknown-field / unknown-version
|
||||
|
||||
`0.2.5-pre.004` ajoute les primitives KDF/AEAD normatives et un premier vecteur cryptographique public. `0.2.5-pre.005` fixe les payloads plaintext V1, l'autorité Ed25519 OWNER, les procédures de création et d'ouverture VIEW/OWNER, le profil de création KSP issu du benchmark opérateur et un vecteur `.kspwallet` complet généré indépendamment du code Rust. `0.2.5-pre.006` matérialise la persistence filesystem bornée et la création no-clobber. `0.2.5-pre.007` matérialise la signature Solana OWNER, l'administration des metadata, les rotations OWNER/VIEW, la révocation forte VIEW et leur remplacement filesystem capability-bound. `0.2.5-pre.008` matérialise les adapters Solana CLI JSON et Base58 complet, leur inspection sûre, l'import no-clobber vers un nouveau `.kspwallet` et l'export secret OWNER explicite. `pre.009` ferme l'audit adversarial/interoperability/compliance et `pre.010` synchronise la documentation de clôture sans modifier le wire ni les primitives. Après publication stable de V1, toute évolution qui modifie un élément déclaré **figé** par cette spécification doit être explicitement tracée ; une incompatibilité de wire exige un nouveau `format_version`.
|
||||
|
||||
Depuis `0.2.6-pre.015`, V1 reste explicitement supporté comme format historique stable tandis que V2 définit le nouveau wire binaire. Les APIs versionnées V1 sont conservées et une lecture générique future doit auto-détecter V1/V2 sans migration implicite.
|
||||
|
||||
Le but final est qu'une implémentation indépendante en Rust, Python, Go, C/C++, Java ou autre puisse créer, parser, vérifier et ouvrir un `.kspwallet` sans lire le code source de `ksp-wallet-lib`.
|
||||
|
||||
## 2. Modèle de confiance V1
|
||||
|
||||
441
docs/formats/KSPWALLET_V2.md
Normal file
441
docs/formats/KSPWALLET_V2.md
Normal file
@@ -0,0 +1,441 @@
|
||||
<!-- file: docs/formats/KSPWALLET_V2.md -->
|
||||
<!-- version: 1 -->
|
||||
|
||||
# `.kspwallet` V2 — spécification du wire binaire natif KSP
|
||||
|
||||
## 1. Statut et objectif
|
||||
|
||||
Ce document est l'autorité normative du **wire `.kspwallet` `format_version = 2`** introduit par `0.2.6-pre.015`.
|
||||
|
||||
V2 remplace l'enveloppe JSON/Base64url de V1 par un framing binaire KSP canonique. L'objectif est :
|
||||
|
||||
```text
|
||||
réduire fortement la taille persistée
|
||||
supprimer l'encodage Base64 des champs déjà binaires
|
||||
éviter qu'un .kspwallet nouvellement créé soit un document JSON lisible comme tel
|
||||
conserver un format documenté et implémentable hors Rust
|
||||
préserver les frontières cryptographiques Wallet
|
||||
```
|
||||
|
||||
Le caractère binaire **n'ajoute aucune propriété cryptographique**. La confidentialité et l'authenticité continuent de dépendre d'Argon2id, XChaCha20-Poly1305 et Ed25519, jamais de l'absence de JSON.
|
||||
|
||||
`0.2.6-pre.015` fige la grammaire binaire, les identifiants numériques, les bornes structurelles et les transcripts/AAD V2. La création/ouverture/persistence V2, l'auto-détection V1/V2 et le basculement de l'API générique vers V2 sont matérialisés dans les tranches suivantes de `0.2.6`.
|
||||
|
||||
V1 reste un format stable supporté. V2 ne réinterprète jamais un document V1 avec sa propre grammaire.
|
||||
|
||||
## 2. Politique de version et API
|
||||
|
||||
Les notions suivantes sont distinctes :
|
||||
|
||||
```text
|
||||
DEFAULT_WALLET_FORMAT
|
||||
LATEST_SUPPORTED_WALLET_FORMAT
|
||||
```
|
||||
|
||||
À partir de l'intégration V2 :
|
||||
|
||||
```text
|
||||
DEFAULT_WALLET_FORMAT = V2
|
||||
LATEST_SUPPORTED_WALLET_FORMAT = V2
|
||||
```
|
||||
|
||||
Si un futur V3 apparaît, par exemple pour un modèle d'autorisation avec second facteur, `LATEST_SUPPORTED_WALLET_FORMAT` pourra devenir V3 tandis que `DEFAULT_WALLET_FORMAT` pourra **rester V2**. Le default ne suit jamais automatiquement la dernière version.
|
||||
|
||||
La politique d'API retenue est :
|
||||
|
||||
```text
|
||||
create_wallet_file(...) -> format default explicitement choisi, V2
|
||||
create_wallet_file_v1(...) -> force V1
|
||||
create_wallet_file_v2(...) -> force V2
|
||||
create_wallet_file_v3(...) -> force V3 si V3 existe un jour
|
||||
|
||||
open_wallet_*_file(...) -> détecte puis dispatch les versions supportées
|
||||
open_wallet_*_file_v1(...) -> exige V1
|
||||
open_wallet_*_file_v2(...) -> exige V2
|
||||
open_wallet_*_file_v3(...) -> exige V3 si V3 existe un jour
|
||||
```
|
||||
|
||||
Le même principe s'applique aux opérations dont la version de fichier est pertinente, notamment inspection et import natif.
|
||||
|
||||
## 3. Encodage général
|
||||
|
||||
Un document V2 est :
|
||||
|
||||
```text
|
||||
binaire
|
||||
maximum 1 048 576 octets
|
||||
entiers multi-octets = unsigned big-endian
|
||||
ordre des champs = normatif
|
||||
aucun padding implicite
|
||||
aucune Base64
|
||||
aucune compression
|
||||
aucun trailing byte
|
||||
```
|
||||
|
||||
Les longueurs sont exprimées en **octets**.
|
||||
|
||||
Une implémentation conforme doit vérifier les bornes **avant** toute allocation dépendant d'une longueur reçue. Le document entier est déjà borné par `1 048 576` octets avant parsing.
|
||||
|
||||
## 4. Header V2
|
||||
|
||||
Le début de fichier est strictement :
|
||||
|
||||
| Ordre | Champ | Taille | Valeur / règle |
|
||||
|------:|---------------------------|-----------------:|------------------------------------------------|
|
||||
| 1 | `magic` | 9 | ASCII exact `KSPWALLET` |
|
||||
| 2 | `format_version` | 2 | `0x0002` |
|
||||
| 3 | `document_length` | 4 | longueur totale exacte du fichier |
|
||||
| 4 | `flags` | 2 | bit 0 = VIEW activé ; tous les autres bits = 0 |
|
||||
| 5 | `owner_auth_public_key` | 32 | clé publique Ed25519 OWNER |
|
||||
| 6 | `view_descriptor.slot_id` | 16 conditionnels | présent uniquement si `flags & 0x0001 != 0` |
|
||||
|
||||
Offsets fixes avant le descripteur conditionnel :
|
||||
|
||||
```text
|
||||
0x0000..0x0008 magic
|
||||
0x0009..0x000A format_version
|
||||
0x000B..0x000E document_length
|
||||
0x000F..0x0010 flags
|
||||
0x0011..0x0030 owner_auth_public_key
|
||||
```
|
||||
|
||||
Pour un wallet VIEW-enabled, `view_descriptor.slot_id` occupe ensuite `0x0031..0x0040`.
|
||||
|
||||
### 4.1 Flags
|
||||
|
||||
```text
|
||||
0x0001 VIEW_ENABLED
|
||||
0xFFFE réservé, doit être zéro
|
||||
```
|
||||
|
||||
Tout bit réservé non nul rend le document invalide. V2 n'emploie pas les bits réservés comme mécanisme d'extension silencieuse ; une modification incompatible exige un nouveau format.
|
||||
|
||||
## 5. Ordre canonique du body
|
||||
|
||||
Après le header :
|
||||
|
||||
```text
|
||||
OWNER key slot obligatoire
|
||||
VIEW key slot présent seulement si VIEW_ENABLED
|
||||
OWNER-CONTROL encrypted compartment obligatoire
|
||||
METADATA encrypted compartment obligatoire
|
||||
SECRET encrypted compartment obligatoire
|
||||
state signature obligatoire
|
||||
EOF immédiat
|
||||
```
|
||||
|
||||
Aucun compteur de slots ou de compartiments n'est nécessaire : leur cardinalité et leur ordre sont déterminés par V2.
|
||||
|
||||
## 6. Key slot V2
|
||||
|
||||
Chaque key slot est encodé ainsi :
|
||||
|
||||
| Champ | Taille | Valeur / règle |
|
||||
|--------------------------|---------:|-----------------------------------------|
|
||||
| `role` | 1 | `0x01` OWNER, `0x02` VIEW |
|
||||
| `slot_id` | 16 | identifiant binaire exact |
|
||||
| `kdf_algorithm` | 1 | `0x01` Argon2id |
|
||||
| `kdf_version` | 4 | `19` |
|
||||
| `memory_kib` | 4 | `1..1 048 576`, et `>= parallelism * 8` |
|
||||
| `iterations` | 4 | `1..64` |
|
||||
| `parallelism` | 4 | `1..64` |
|
||||
| `salt_length` | 1 | `16..64` |
|
||||
| `salt` | variable | exactement `salt_length` octets |
|
||||
| `wrap_algorithm` | 1 | `0x01` XChaCha20-Poly1305 |
|
||||
| `wrap_nonce` | 24 | nonce exact |
|
||||
| `wrap_ciphertext_length` | 2 | `16..4096` |
|
||||
| `wrap_ciphertext` | variable | exactement la longueur déclarée |
|
||||
|
||||
Ordre obligatoire :
|
||||
|
||||
```text
|
||||
premier slot = OWNER
|
||||
second slot = VIEW seulement si VIEW_ENABLED
|
||||
```
|
||||
|
||||
Si VIEW est activé :
|
||||
|
||||
```text
|
||||
header.view_descriptor.slot_id == VIEW key slot.slot_id
|
||||
```
|
||||
|
||||
Toute divergence est invalide avant KDF/déchiffrement.
|
||||
|
||||
## 7. Compartiments V2
|
||||
|
||||
Chaque compartiment est encodé :
|
||||
|
||||
| Champ | Taille | Valeur / règle |
|
||||
|---------------------|---------:|------------------------------------------------------|
|
||||
| `kind` | 1 | `0x01` OWNER-CONTROL, `0x02` METADATA, `0x03` SECRET |
|
||||
| `payload_version` | 4 | `1` pour le profil initial V2 |
|
||||
| `algorithm` | 1 | `0x01` XChaCha20-Poly1305 |
|
||||
| `nonce` | 24 | nonce exact |
|
||||
| `ciphertext_length` | 4 | longueur exacte |
|
||||
| `ciphertext` | variable | ciphertext + tag Poly1305 |
|
||||
|
||||
Bornes initiales :
|
||||
|
||||
```text
|
||||
OWNER-CONTROL : 16..4096 octets
|
||||
METADATA : 16..65552 octets
|
||||
SECRET : 16..4096 octets
|
||||
```
|
||||
|
||||
L'ordre exact est OWNER-CONTROL, METADATA, SECRET. Le `kind` encodé doit correspondre à la position attendue ; il n'autorise pas un réordonnancement.
|
||||
|
||||
Les payloads plaintext V2 conservent le modèle fonctionnel établi en V1 pour cette évolution : owner-control, metadata et secret Solana restent des compartiments distincts. Une future modification incompatible de leur sémantique exige une version de format explicite.
|
||||
|
||||
## 8. Signature d'état
|
||||
|
||||
La fin du document est :
|
||||
|
||||
| Champ | Taille | Valeur / règle |
|
||||
|-----------------------------|-------:|---------------------------|
|
||||
| `state_signature.algorithm` | 1 | `0x01` Ed25519 |
|
||||
| `state_signature.signature` | 64 | signature detached exacte |
|
||||
|
||||
Aucun octet ne peut suivre ces 65 octets.
|
||||
|
||||
## 9. Identifiants numériques figés
|
||||
|
||||
### 9.1 Rôles
|
||||
|
||||
```text
|
||||
0x01 OWNER
|
||||
0x02 VIEW
|
||||
```
|
||||
|
||||
### 9.2 Algorithmes
|
||||
|
||||
```text
|
||||
KDF
|
||||
0x01 Argon2id
|
||||
|
||||
AEAD
|
||||
0x01 XChaCha20-Poly1305
|
||||
|
||||
state signature
|
||||
0x01 Ed25519
|
||||
```
|
||||
|
||||
### 9.3 Compartiments
|
||||
|
||||
```text
|
||||
0x01 OWNER-CONTROL
|
||||
0x02 METADATA
|
||||
0x03 SECRET
|
||||
```
|
||||
|
||||
`0x00` est invalide dans ces espaces. Les autres valeurs sont réservées et rejetées par V2 tant qu'elles ne sont pas explicitement normalisées par une évolution compatible documentée ; aucune valeur inconnue n'est devinée.
|
||||
|
||||
## 10. Canonicalité et rejet
|
||||
|
||||
Le parser V2 doit rejeter avant crypto :
|
||||
|
||||
```text
|
||||
fichier > 1 MiB
|
||||
magic incorrect
|
||||
format_version != 2
|
||||
document_length différent de la taille reçue
|
||||
flag réservé non nul
|
||||
champ tronqué
|
||||
longueur qui dépasse le reste du document
|
||||
role/algorithm/kind inconnu
|
||||
ordre OWNER/VIEW invalide
|
||||
VIEW descriptor et VIEW slot incohérents
|
||||
Argon2 hors bornes
|
||||
salt hors bornes
|
||||
ciphertext hors bornes
|
||||
payload_version non supporté
|
||||
trailing bytes
|
||||
```
|
||||
|
||||
Il n'existe qu'un encodage canonique d'un même état sémantique V2 : mêmes champs, même ordre, mêmes largeurs, même endianness et aucune donnée ignorée.
|
||||
|
||||
## 11. Transcripts et AAD V2
|
||||
|
||||
V2 possède ses propres domaines ; V1 et V2 ne partagent jamais un domain separator :
|
||||
|
||||
```text
|
||||
KSPWALLET-V2-STATE
|
||||
KSPWALLET-V2-AAD-OWNER-SLOT
|
||||
KSPWALLET-V2-AAD-VIEW-SLOT
|
||||
KSPWALLET-V2-AAD-OWNER-CONTROL
|
||||
KSPWALLET-V2-AAD-METADATA
|
||||
KSPWALLET-V2-AAD-SECRET
|
||||
```
|
||||
|
||||
Le transcript/AAD V2 conserve la discipline TLV déterministe de V1 :
|
||||
|
||||
```text
|
||||
domain || 0x00
|
||||
puis pour chaque champ :
|
||||
tag:u16 big-endian
|
||||
length:u64 big-endian
|
||||
value:length bytes
|
||||
```
|
||||
|
||||
Les tags restent alignés avec les familles V1 :
|
||||
|
||||
```text
|
||||
0x0001 magic
|
||||
0x0002 format_version
|
||||
0x0003 owner_auth_public_key
|
||||
0x0010 view_enabled
|
||||
0x0011 view_role
|
||||
0x0012 view_slot_id
|
||||
0x0100 slot_id
|
||||
0x0101 slot_role
|
||||
0x0102 kdf_algorithm
|
||||
0x0103 kdf_version
|
||||
0x0104 kdf_memory_kib
|
||||
0x0105 kdf_iterations
|
||||
0x0106 kdf_parallelism
|
||||
0x0107 kdf_salt
|
||||
0x0108 wrap_algorithm
|
||||
0x0109 wrap_nonce
|
||||
0x010A wrap_ciphertext
|
||||
0x0200 compartment_kind
|
||||
0x0201 compartment_version
|
||||
0x0202 compartment_algorithm
|
||||
0x0203 compartment_nonce
|
||||
0x0204 compartment_ciphertext
|
||||
0x0500 state_signature_algorithm
|
||||
```
|
||||
|
||||
Différence normative V2 : les rôles/algorithmes/kinds sont transcriptés sous leur **ID numérique d'un octet**, et `format_version = 2` est transcripté en `u32` big-endian. Les domaines distincts empêchent qu'un transcript V1 et un transcript V2 soient interchangeables.
|
||||
|
||||
### 11.1 State transcript
|
||||
|
||||
Le state transcript contient :
|
||||
|
||||
```text
|
||||
common
|
||||
view descriptor
|
||||
OWNER slot avec wrap nonce+ciphertext
|
||||
OWNER-CONTROL avec nonce+ciphertext
|
||||
METADATA avec nonce+ciphertext
|
||||
SECRET avec nonce+ciphertext
|
||||
state signature algorithm
|
||||
```
|
||||
|
||||
Le VIEW wrap mutable n'est pas ajouté au state transcript, selon le modèle d'autorisation VIEW déjà retenu : son identité stable reste liée par le descriptor signé tandis que son credential peut être self-rotaté sans OWNER.
|
||||
|
||||
### 11.2 Slot AAD
|
||||
|
||||
Le slot AAD contient :
|
||||
|
||||
```text
|
||||
common
|
||||
slot_id
|
||||
role
|
||||
KDF algorithm/version/parameters/salt
|
||||
wrap algorithm
|
||||
```
|
||||
|
||||
Le wrap nonce/ciphertext n'est pas inclus dans son propre AAD.
|
||||
|
||||
### 11.3 Compartment AAD
|
||||
|
||||
Le compartment AAD contient :
|
||||
|
||||
```text
|
||||
common
|
||||
kind
|
||||
payload_version
|
||||
algorithm
|
||||
```
|
||||
|
||||
Le nonce/ciphertext n'est pas inclus dans son propre AAD.
|
||||
|
||||
## 12. V1 et V2
|
||||
|
||||
V1 et V2 sont deux formats explicites :
|
||||
|
||||
| Propriété | V1 | V2 |
|
||||
|--------------------------|------------------------------------|---------------|
|
||||
| enveloppe | JSON UTF-8 | binaire KSP |
|
||||
| champs binaires | Base64url no-pad | bytes directs |
|
||||
| version | `1` | `2` |
|
||||
| canonicalité | sémantique JSON + Base64 canonique | byte-exact |
|
||||
| taille fixture wire-only | 2037 octets | 628 octets |
|
||||
| Argon2id | oui | oui |
|
||||
| XChaCha20-Poly1305 | oui | oui |
|
||||
| Ed25519 OWNER state | oui | oui |
|
||||
| VIEW/OWNER | oui | oui |
|
||||
|
||||
La réduction mesurée sur le fixture structurel de référence est :
|
||||
|
||||
```text
|
||||
2037 -> 628 octets
|
||||
-1409 octets
|
||||
~69,2 %
|
||||
```
|
||||
|
||||
Cette mesure n'est pas une promesse de ratio constant : la taille dépend notamment des metadata chiffrées.
|
||||
|
||||
## 13. Fixture structurelle
|
||||
|
||||
Fixture canonique de `pre.015` :
|
||||
|
||||
```text
|
||||
crates/ksp-wallet-lib/tests/fixtures/kspwallet_v2_wire_only.bin
|
||||
size = 628
|
||||
sha256 = cbacb37326c76e6dde8d614601cd765a8c0fd9744f891d640b8a3cd71cf60a93
|
||||
```
|
||||
|
||||
Préfixe hexadécimal :
|
||||
|
||||
```text
|
||||
4b535057414c4c4554 0002 00000274 0001
|
||||
000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
|
||||
202122232425262728292a2b2c2d2e2f
|
||||
```
|
||||
|
||||
Lecture :
|
||||
|
||||
```text
|
||||
4b535057414c4c4554 = "KSPWALLET"
|
||||
0002 = format_version V2
|
||||
00000274 = 628 octets
|
||||
0001 = VIEW_ENABLED
|
||||
```
|
||||
|
||||
La fixture `wire_only` vérifie framing/canonicalité ; elle n'est pas présentée comme une signature cryptographique V2 valide tant que la création/open V2 n'est pas intégrée par la tranche suivante.
|
||||
|
||||
## 14. Compatibilité et migration
|
||||
|
||||
V2 n'autorise aucune migration implicite à l'ouverture.
|
||||
|
||||
Politique prévue :
|
||||
|
||||
```text
|
||||
lecture générique V1/V2 oui
|
||||
création générique V2
|
||||
création V1 forcée oui
|
||||
création V2 forcée oui
|
||||
réécriture V1 -> V2 cachée non
|
||||
migration V1 -> V2 opération explicite
|
||||
```
|
||||
|
||||
Une migration doit authentifier le wallet source avec la capability requise, produire un nouveau document V2 valide et respecter la persistence no-clobber/atomique. Une simple transcodification non authentifiée des bytes V1 n'est pas suffisante puisque V2 possède ses propres domains/transcripts.
|
||||
|
||||
## 15. Future V3 / second facteur
|
||||
|
||||
V2 ne réalise aucun second facteur.
|
||||
|
||||
Si un futur V3 ajoute une autorisation dépendant d'un facteur externe :
|
||||
|
||||
```text
|
||||
ksp-wallet-lib possède la règle qui exige le facteur
|
||||
ksp-wallet-lib possède le challenge et la validation cryptographique
|
||||
aucun WalletOwner ne peut être obtenu si le facteur requis n'est pas satisfait
|
||||
Wallet Desk ne décide jamais que le second facteur est valide
|
||||
```
|
||||
|
||||
Une UI comme Wallet Desk peut néanmoins devoir évoluer pour orchestrer l'expérience : attente de confirmation, saisie OTP, enrollment, recovery, hardware/WebAuthn ou consentement externe.
|
||||
|
||||
Le réseau ou le fournisseur externe ne doit pas forcer `ksp-wallet-lib` à dépendre directement de Config/Transport/Tauri. Une abstraction/provider KSP séparée peut fournir la preuve à Wallet tandis que Wallet reste propriétaire de la politique d'autorisation.
|
||||
|
||||
L'arrivée d'un V3 ne change pas automatiquement le default : V2 peut rester `DEFAULT_WALLET_FORMAT` aussi longtemps que KSP le décide explicitement.
|
||||
@@ -1,5 +1,5 @@
|
||||
<!-- file: docs/plans/000-README.md -->
|
||||
<!-- version: 49 -->
|
||||
<!-- version: 50 -->
|
||||
|
||||
# Plans KSP
|
||||
|
||||
@@ -21,7 +21,7 @@ Un plan décrit le périmètre, les décisions déjà acquises, les questions ou
|
||||
- [`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 historique clôturé de la release stable `0.2.5 — Wallet foundation`, ouvert par `pre.001`, livré jusqu’à `pre.010`, renforcé par `pre.010-fix.001`–`fix.003` pour Dalek 3 et la normalisation Rust/audit structurel, puis publié par `rel.001`; il couvre `.kspwallet` V1, VIEW/OWNER, crypto, persistence, administration, transfer et compliance.
|
||||
- [`013-V0_2_6_WALLET_DESK_PLAN.md`](013-V0_2_6_WALLET_DESK_PLAN.md) — plan actif de `0.2.6 — Wallet Desk`, ouvert par `pre.001`; `pre.002` matérialise le shell Tauri et `pre.003` la composition `std.wallet`/composite ainsi que la préparation des répertoires. Le plan fixe aussi secrets `KSP_SECRET_WALLET_PASS_*`, inventory DataTables/path safety, lifecycle VIEW/OWNER, screen/command/DTO maps, balance HTTP, administration retenue et forecast souple détaillé jusqu’à `pre.015`, avec `pre.014` réservé au polish Bootstrap/splashscreen puis `pre.015` à la documentation finale, au prompt `0.2.7` et au build Tauri final.
|
||||
- [`013-V0_2_6_WALLET_DESK_PLAN.md`](013-V0_2_6_WALLET_DESK_PLAN.md) — plan actif de `0.2.6 — Wallet Desk`, ouvert par `pre.001`; `pre.002` matérialise le shell Tauri et `pre.003` la composition `std.wallet`/composite ainsi que la préparation des répertoires. Le plan fixe aussi secrets `KSP_SECRET_WALLET_PASS_*`, inventory DataTables/path safety, lifecycle VIEW/OWNER, screen/command/DTO maps, balance HTTP, administration retenue et forecast étendu jusqu’à `pre.018` : `pre.014` polish Bootstrap/splashscreen, `pre.015` wire binaire `.kspwallet` V2, `pre.016` APIs génériques/versionnées + V2, `pre.017` migration/canaris, puis `pre.018` documentation candidate et build Tauri final.
|
||||
|
||||
Le `pre.001` de chaque release fonctionnelle peut introduire son propre plan détaillé lorsque la release s'ouvre.
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!-- file: docs/plans/002-FUNCTIONAL_RELEASE_SEQUENCE.md -->
|
||||
<!-- version: 75 -->
|
||||
<!-- version: 76 -->
|
||||
|
||||
# Séquence des releases fonctionnelles KSP
|
||||
|
||||
@@ -361,14 +361,13 @@ Par défaut :
|
||||
0.2.4 HTTP Blocks + Economics + compliance complète
|
||||
0.2.5 wallet foundation (.kspwallet)
|
||||
0.2.6 Wallet Desk
|
||||
0.2.7 .kspwallet binary persistence container
|
||||
0.2.8 standard Solana WebSocket
|
||||
0.2.9 Helius LaserStream WebSocket
|
||||
0.2.10 Yellowstone gRPC standard foundation
|
||||
0.2.11 off-chain price transport
|
||||
0.2.12 price visualization desk + intégration prix dans Wallet Desk
|
||||
0.2.13 interface/wire foundation
|
||||
0.2.14 program-api foundation
|
||||
0.2.7 standard Solana WebSocket
|
||||
0.2.8 Helius LaserStream WebSocket
|
||||
0.2.9 Yellowstone gRPC standard foundation
|
||||
0.2.10 off-chain price transport
|
||||
0.2.11 price visualization desk + intégration prix dans Wallet Desk
|
||||
0.2.12 interface/wire foundation
|
||||
0.2.13 program-api foundation
|
||||
```
|
||||
|
||||
`0.2.1-pre.001` a appliqué le gate de sizing et refusé le scope HTTP monolithique initial : l'inventaire du 2026-08-17 contient 52 méthodes courantes et 14 méthodes Deprecated historiques. Ce premier delta avait réparti la couverture typée sur `0.2.1`–`0.2.6`. `0.2.1-pre.001-fix.001` recalibre ensuite les 48 méthodes restantes sur trois releases complémentaires `0.2.2`–`0.2.4`, soit trois sessions nominales au maximum si chaque release utilise sa session complète. Si une release se clôt plus vite que prévu, la même session peut enchaîner la suivante après clôture complète de la précédente et nouveau gate de sizing positif. Un Wallet Desk utile doit pouvoir lire le solde du wallet : `getBalance` fait donc partie des quatre canaris de la foundation `0.2.1`, avant Wallet. Les transports live arrivent ensuite ; Interface/Program restent préparés avant les couches de données décodées.
|
||||
@@ -443,29 +442,26 @@ pre.011 disable/recreate VIEW fort
|
||||
pre.012 export OWNER fichier CLI JSON/Base58
|
||||
pre.013 intégration, compliance, sécurité et smoke
|
||||
pre.014 polish du gabarit Bootstrap et du splashscreen
|
||||
pre.015 documentation finale, validations, prompt 0.2.7 et cargo tauri build en dernière opération
|
||||
pre.015 .kspwallet V2 wire binaire + codec canonique
|
||||
pre.016 APIs génériques/versionnées + création/ouverture V2
|
||||
pre.017 migration V1 -> V2 + persistence/canaris + régression Wallet Desk
|
||||
pre.018 documentation finale, validations, prompt 0.2.7 et cargo tauri build en dernière opération
|
||||
rel.001 publication stable 0.2.6
|
||||
```
|
||||
|
||||
La tranche `pre.014` est réservée aux défauts visuels/templating observés en usage réel, notamment les scrollbars occasionnelles du splashscreen ; son contenu précis sera borné à partir du retour opérateur avant implémentation. `ROADMAP.md` reste synthétique et `CHANGELOG.md` n'est synchronisé qu'à la phase documentaire finale.
|
||||
|
||||
## `0.2.7` — `.kspwallet` binary persistence container
|
||||
|
||||
Mission : faire évoluer uniquement la couche de persistence de `ksp-wallet-lib` afin qu’un `.kspwallet` nouvellement écrit ne soit plus un document JSON directement lisible dans un éditeur texte ordinaire, sans prétendre ajouter de sécurité cryptographique par simple obfuscation.
|
||||
|
||||
Le gate `pre.001` doit comparer framing binaire custom, codecs binaires stables et éventuelle compression, puis fixer un conteneur explicitement versionné. Base64 seul est exclu comme solution : il reste textuel, trivialement réversible et augmente la taille. Le conteneur et le `format_version` logique/cryptographique sont séparés afin de conserver V1 pour les semantics VIEW/OWNER actuelles et de réserver les futurs formats logiques à de vraies évolutions d’autorisation. La lecture rétrocompatible des JSON V1 historiques et les migrations/test vectors sont obligatoires. Wallet Desk ne doit pas être modifié fonctionnellement ; ses tests/smokes sont rejoués comme preuve consommateur.
|
||||
|
||||
## `0.2.8` — WebSocket Solana standard
|
||||
## `0.2.7` — WebSocket Solana standard
|
||||
|
||||
Mission : couvrir la surface WebSocket standard officielle ciblée.
|
||||
|
||||
Une URL peut avoir plusieurs sessions physiques ; une session peut avoir plusieurs subscriptions. Un pool automatique de sessions est reporté jusqu'à besoin concret.
|
||||
|
||||
## `0.2.9` — Helius LaserStream WebSocket
|
||||
## `0.2.8` — Helius LaserStream WebSocket
|
||||
|
||||
Mission : étendre le moteur WebSocket standard avec les opérations/filtres/capabilities Helius ciblés sans copier le client.
|
||||
|
||||
## `0.2.10` — Yellowstone gRPC standard
|
||||
## `0.2.9` — Yellowstone gRPC standard
|
||||
|
||||
Mission : introduire un backend Yellowstone standard/provider-neutral.
|
||||
|
||||
@@ -473,21 +469,21 @@ Le `pre.001` est un gate de sizing : inventorier toute la surface normative cibl
|
||||
|
||||
Les profiles/adapters Helius/Triton/ERPC/Chainstack/Shyft sont reportés après les priorités fondatrices.
|
||||
|
||||
## `0.2.11` / `0.2.12` — Off-chain price + app
|
||||
## `0.2.10` / `0.2.11` — Off-chain price + app
|
||||
|
||||
`0.2.11` introduit `ksp-offchain-transport-lib` avec au minimum SOL/USD et SOL/EUR via une abstraction indépendante du premier provider.
|
||||
`0.2.10` introduit `ksp-offchain-transport-lib` avec au minimum SOL/USD et SOL/EUR via une abstraction indépendante du premier provider.
|
||||
|
||||
`0.2.12` ajoute une petite application desk de visualisation/validation. Après stabilisation de cette application spécialisée, la même release doit intégrer la capacité de prix offchain dans `ksp-app-wallet-desk` sans dupliquer la récupération/normalisation appartenant au composant spécialisé.
|
||||
`0.2.11` ajoute une petite application desk de visualisation/validation. Après stabilisation de cette application spécialisée, la même release doit intégrer la capacité de prix offchain dans `ksp-app-wallet-desk` sans dupliquer la récupération/normalisation appartenant au composant spécialisé.
|
||||
|
||||
Metadata HTTP/IPFS/Arweave viendra au premier besoin Metadata réel.
|
||||
|
||||
## `0.2.13` — Interface foundation
|
||||
## `0.2.12` — Interface foundation
|
||||
|
||||
`ksp-interface-lib` devient la façade wire officielle et expose une API publique wire utilisable par les implementations officielles et externes.
|
||||
|
||||
Aucune `ksp-interface-api` séparée n'est retenue pour l'instant.
|
||||
|
||||
## `0.2.14` — Program API foundation
|
||||
## `0.2.13` — Program API foundation
|
||||
|
||||
Introduire `ksp-program-api`, sans suffixe `-lib`, comme contrat d'extension Program.
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!-- file: docs/plans/013-V0_2_6_WALLET_DESK_PLAN.md -->
|
||||
<!-- version: 32 -->
|
||||
<!-- version: 33 -->
|
||||
|
||||
# Plan `0.2.6` — Wallet Desk
|
||||
|
||||
@@ -772,7 +772,7 @@ outil de logging contrôlé
|
||||
## 12. Command map
|
||||
|
||||
| Command | Entrée frontend | Sortie sûre | Délégation |
|
||||
|----------------------------------------------|--------------------|-------------------------------------|---------------------------------|
|
||||
|----------------------------------------------|--------------------|-------------------------------------|-------------------------------------|
|
||||
| `get_runtime_status` | — | `WalletRuntimeStatusDto` | Config/app state |
|
||||
| `list_wallets` | — | `Vec<WalletInventoryEntryDto>` | app filesystem + Wallet inspect |
|
||||
| `refresh_wallets` | — | inventory DTO | app filesystem + Wallet inspect |
|
||||
@@ -1677,7 +1677,7 @@ workspace checkpoint complet
|
||||
|
||||
Le smoke live est volontairement `ignored` dans `cargo test --workspace`. Il doit être déclenché explicitement avec un `KSP_WALLETS_DIRECTORY` dédié ; le test charge ce paramètre uniquement via `ConfigEnvironment`, crée un `.kspwallet` réel dans le répertoire effectif du profil composite, ouvre VIEW, exécute `getBalance` via le Transport composite puis supprime le wallet canari. Ainsi le smoke cross-crates vit dans la surface d'orchestration Wallet Desk et non dans Config ou Transport.
|
||||
|
||||
Cette tranche doit produire la preuve que les surfaces ajoutées fonctionnent ensemble avant le polish visuel `pre.014` et la documentation finale `pre.015`.
|
||||
Cette tranche doit produire la preuve que les surfaces ajoutées fonctionnent ensemble avant le polish visuel `pre.014` et les tranches V2 binaires intercalées avant la candidate finale.
|
||||
|
||||
### `pre.014` — polish gabarit Bootstrap et splashscreen
|
||||
|
||||
@@ -1693,25 +1693,65 @@ réutilisation du gabarit commun sans déplacer de logique métier
|
||||
|
||||
Cette tranche n'est pas un prétexte pour refondre l'UX métier. Les détails précis des défauts et critères d'acceptation seront fournis par l'opérateur lorsqu'elle sera ouverte.
|
||||
|
||||
### `pre.015` — documentation finale, candidate build et prompt suivant
|
||||
### `pre.015` — `.kspwallet` V2 : wire binaire + codec canonique
|
||||
|
||||
Cette tranche intercalée remplace l'ancien départ immédiat en documentation finale. Elle fixe le wire binaire V2 et son codec structurel dans `ksp-wallet-lib` sans modifier encore Wallet Desk ni les APIs de persistence V1 utilisées en production.
|
||||
|
||||
```text
|
||||
KSPWALLET magic binaire
|
||||
format_version = 2
|
||||
longueur totale explicite
|
||||
flags réservés stricts
|
||||
OWNER puis VIEW optionnel
|
||||
Argon2id / XChaCha20-Poly1305 / Ed25519 par IDs numériques
|
||||
compartiments OWNER-CONTROL / METADATA / SECRET
|
||||
entiers big-endian
|
||||
aucune Base64
|
||||
aucune compression
|
||||
aucun trailing byte
|
||||
domains/transcripts/AAD V2 distincts de V1
|
||||
fixture wire-only canonique + comparaison de taille
|
||||
```
|
||||
|
||||
La politique API est figée dès cette tranche : `DEFAULT_WALLET_FORMAT` et `LATEST_SUPPORTED_WALLET_FORMAT` sont deux notions distinctes. À l'intégration V2, le default devient V2. Une future V3 n'entraîne jamais automatiquement le déplacement du default.
|
||||
|
||||
### `pre.016` — APIs génériques/versionnées + création/ouverture V2
|
||||
|
||||
Matérialiser :
|
||||
|
||||
```text
|
||||
create_wallet_file(...) -> V2 par default explicite
|
||||
create_wallet_file_v1(...) conservé
|
||||
create_wallet_file_v2(...) ajouté
|
||||
open/inspect génériques -> détection V1/V2
|
||||
open/inspect _v1/_v2 -> format forcé strict
|
||||
create/open in-memory V2 + crypto/transcripts V2
|
||||
Wallet Desk migre vers les APIs génériques, jamais vers un numéro de format
|
||||
```
|
||||
|
||||
Une future API `_v3` pourra être ajoutée sans transformer automatiquement le default en V3.
|
||||
|
||||
### `pre.017` — migration V1 -> V2 + persistence/canaris
|
||||
|
||||
Ajouter la migration explicite et authentifiée V1 vers V2, les paths de remplacement/no-clobber nécessaires, les canaris adversariaux/interop et la régression complète Wallet Desk. Aucune migration silencieuse lors d'une simple ouverture.
|
||||
|
||||
### `pre.018` — documentation finale, candidate build et prompt suivant
|
||||
|
||||
Dernière tranche prévue avant `rel.001` :
|
||||
|
||||
```text
|
||||
crates/ksp-app-wallet-desk/README.md
|
||||
crates/ksp-app-wallet-desk/USAGE.md
|
||||
docs/architecture / inventory / dependency graph synchronisés si impactés
|
||||
README/USAGE Wallet Desk
|
||||
docs/validation 0.2.6 finalisée
|
||||
ROADMAP / functional sequence / CHANGELOG synchronisés
|
||||
stratégie CWD/resources release packagée fermée
|
||||
dépendances et versions finales réauditées
|
||||
commandes smoke documentées
|
||||
prompt de démarrage 0.2.7 préparé
|
||||
validation Rust workspace finale
|
||||
parcours fonctionnel cargo tauri dev final
|
||||
prompt de démarrage 0.2.7 WebSocket finalisé
|
||||
cargo tauri build en toute dernière opération
|
||||
```
|
||||
|
||||
Si le build final ou la documentation révèle une correction technique, utiliser `pre.015-fix.NNN` ou insérer une tranche supplémentaire. `pre.015` n'est pas une obligation de clôture artificielle.
|
||||
Si une correction technique apparaît, utiliser `pre.018-fix.NNN` ou insérer une tranche supplémentaire.
|
||||
|
||||
### `rel.001` — publication stable
|
||||
|
||||
@@ -1871,7 +1911,7 @@ KSP_WALLETS_DIRECTORY=var/wallet-desk-pre014 \
|
||||
bash -lc 'cd crates/ksp-app-wallet-desk && cargo tauri dev'
|
||||
```
|
||||
|
||||
Le build Tauri de production reste reporté à `pre.015` et doit demeurer l’absolue dernière opération.
|
||||
À ce stade de `pre.014`, le build Tauri de production était encore reporté à `pre.015`. Cette décision historique est **superseded par l’extension décidée en `pre.015`** : le build final est désormais réservé à `pre.018` et doit demeurer l’absolue dernière opération.
|
||||
|
||||
|
||||
### Correctif `0.2.6-pre.014-fix.001` — layout desktop et canari durable
|
||||
@@ -1887,6 +1927,6 @@ splash : feed #debug-info pleine largeur dans les deux Desks
|
||||
pre.013 gate : le canari ne fige plus une shell_phase destinée à évoluer à chaque tranche
|
||||
```
|
||||
|
||||
Le recalage du CWD n'existe actuellement qu'en `debug_assertions` dans les deux `main.rs`. La candidate `pre.015` doit donc vérifier explicitement la stratégie de résolution production/bundle pour `config`, `.env`, `logs` et `wallets` avant le build final ; le comportement release ne doit pas être supposé identique au parcours `cargo tauri dev`.
|
||||
Le recalage du CWD n'existe actuellement qu'en `debug_assertions` dans les deux `main.rs`. La candidate finale `pre.018` doit donc vérifier explicitement la stratégie de résolution production/bundle pour `config`, `.env`, `logs` et `wallets` avant le build final ; le comportement release ne doit pas être supposé identique au parcours `cargo tauri dev`.
|
||||
|
||||
Ce fix touche le frontend/build contract et porte donc le signal technique `workspace.package.version = 0.2.6-pre.14.fix.1`. `ROADMAP.md`, `CHANGELOG.md` et `docs/plans/002-FUNCTIONAL_RELEASE_SEQUENCE.md` restent inchangés.
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
<!-- file: docs/validation/009-V0_2_6_WALLET_DESK_COMPLIANCE.md -->
|
||||
<!-- version: 3 -->
|
||||
<!-- version: 4 -->
|
||||
|
||||
# Validation `0.2.6` — Wallet Desk integration / compliance / security
|
||||
|
||||
## 1. Objet
|
||||
|
||||
Cette matrice est ouverte par `0.2.6-pre.013` comme preuve durable de composition et de conformité de `ksp-app-wallet-desk`. Elle sera complétée en `pre.015` avec les résultats finaux, le polish visuel de `pre.014`, la documentation de clôture et le dernier build Tauri.
|
||||
Cette matrice est ouverte par `0.2.6-pre.013` comme preuve durable de composition et de conformité de `ksp-app-wallet-desk`. Le calendrier a été étendu après `pre.014` : `pre.015` introduit le wire V2, `pre.016` les APIs génériques/versionnées, `pre.017` migration/régression, puis `pre.018` porte la clôture documentaire et le dernier build Tauri.
|
||||
|
||||
Elle ne remplace ni le plan [`../plans/013-V0_2_6_WALLET_DESK_PLAN.md`](../plans/013-V0_2_6_WALLET_DESK_PLAN.md), ni la matrice Wallet V1 [`008-V0_2_5_WALLET_SECURITY_COMPLIANCE.md`](008-V0_2_5_WALLET_SECURITY_COMPLIANCE.md), ni les deltas `0.2.6`.
|
||||
|
||||
@@ -52,7 +52,7 @@ Le checkpoint opérateur `pre.012` du 21 août 2026 est vert : `cargo fmt`, audi
|
||||
## 3. Matrice de frontières
|
||||
|
||||
| Frontière | Contrat `0.2.6` | Preuve durable |
|
||||
|---|---|---|
|
||||
|------------------------------|--------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------|
|
||||
| Frontend -> Config | aucun accès direct env/.env | `release_compliance::backend_keeps_config_wallet_transport_and_logging_ownership_boundaries` + ownership Config |
|
||||
| Frontend -> Wallet secret | passwords uniquement request-only ; jamais de keypair en IPC | `desktop_security` + `release_compliance::response_dtos_keep_secret_key_material_out_of_ipc` |
|
||||
| Frontend -> filesystem | aucun path arbitraire ; picker natif Rust | tests import/export + capability audit |
|
||||
@@ -238,4 +238,9 @@ cargo test --workspace : BLOCKED par un faux positif du canari Logging global
|
||||
|
||||
Le blocage workspace est limité à `ksp-logging-lib/tests/ownership.rs::workspace_crates_do_not_bypass_ksp_logging_facade` : le scanner voit le littéral `tracing::` dans `release_compliance.rs`, alors que ce littéral est la chaîne recherchée par le canari et non un usage de `tracing`. `pre.013-fix.002` supprime ce littéral statique en construisant le motif à l'exécution, sans modifier le scanner global ni relâcher la politique Logging.
|
||||
|
||||
La matrice reste ouverte jusqu'à `pre.015`, où seront ajoutés le résultat du polish `pre.014`, le parcours fonctionnel final, les docs README/USAGE et le build Tauri exécuté en toute dernière opération.
|
||||
La matrice reste ouverte jusqu'à `pre.018`, après les tranches V2 `pre.015`–`pre.017`; `pre.018` ajoute le parcours fonctionnel final, README/USAGE et le build Tauri exécuté en toute dernière opération.
|
||||
|
||||
|
||||
## 11. Intercalation V2 à partir de `pre.015`
|
||||
|
||||
`pre.015` ne modifie pas encore Wallet Desk : il ajoute dans `ksp-wallet-lib` un codec binaire V2 strict et une fixture canonique. Les gates Desk `pre.013`/`pre.014` restent donc applicables sans changement. `pre.016` devra faire migrer le Desk vers les APIs génériques afin qu’il ne connaisse plus `_v1`/`_v2`.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!-- file: prompts/000-README.md -->
|
||||
<!-- version: 18 -->
|
||||
<!-- version: 19 -->
|
||||
|
||||
# Prompts KSP
|
||||
|
||||
@@ -32,5 +32,4 @@ Le prompt générique `0.1.x` a été affiné pendant `0.0.3` puis remplacé par
|
||||
- [`009-V0_2_4_START_PROMPT.md`](009-V0_2_4_START_PROMPT.md) — prompt préparé par `0.2.3-pre.009`, destiné à ouvrir `0.2.4 — HTTP Blocks + Economics + compliance HTTP finale` après publication stable de `0.2.3`; il cible les 15 wrappers restants et impose `KSP-TRANSPORT-007` ainsi qu'un nouvel audit/sizing à `pre.001`.
|
||||
- [`010-V0_2_5_START_PROMPT.md`](010-V0_2_5_START_PROMPT.md) — prompt préparé par `0.2.4-pre.009` puis finalisé en version 2 par `pre.009-fix.001`, destiné à ouvrir `0.2.5 — Wallet foundation` sur la base stable `v0.2.4`; il impose audit/threat-model/sizing avant choix cryptographiques et cadre `.kspwallet` interopérable, capacités indépendantes VIEW/OWNER, metadata protégées, key slots/rotations, signature, persistence atomique et import/export extensible sans `WalletPolicy`.
|
||||
- [`011-V0_2_6_START_PROMPT.md`](011-V0_2_6_START_PROMPT.md) — prompt préparé par `0.2.5-pre.010` puis renforcé pendant `pre.010-fix.001`–`fix.003`, destiné à ouvrir `0.2.6 — Wallet Desk` après le tag stable `v0.2.5`; il impose une première tranche audit/sizing, rappelle les règles Rust/audit structurel, cadre Config composite + Wallet + HTTP `getBalance`, lifecycle VIEW/OWNER, sécurité password/export, validation frontend/Tauri et conserve le TODO `0.2.12` d’intégration des prix offchain dans Wallet Desk après validation de la Price Desk spécialisée.
|
||||
|
||||
- [`012-V0_2_7_START_PROMPT.md`](012-V0_2_7_START_PROMPT.md) — prompt préparé pendant `0.2.6-pre.014`, destiné à ouvrir `0.2.7 — conteneur binaire .kspwallet` après publication stable de `0.2.6`; il sépare version de conteneur et `format_version` logique V1, exclut Base64 comme pseudo-sécurité, impose compatibilité JSON V1/migration/interop et utilise Wallet Desk comme canari consommateur sans modification fonctionnelle attendue.
|
||||
- [`012-V0_2_7_START_PROMPT.md`](012-V0_2_7_START_PROMPT.md) — prompt réaligné par `0.2.6-pre.015` pour ouvrir `0.2.7 — WebSocket Solana standard`; le chantier `.kspwallet` V2 ayant été ramené dans `0.2.6`, il rétablit la séquence Transport et impose audit officiel/sizing avant implémentation.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!-- file: prompts/011-V0_2_6_START_PROMPT.md -->
|
||||
<!-- version: 5 -->
|
||||
<!-- version: 6 -->
|
||||
|
||||
# Prompt de démarrage `0.2.6` — Wallet Desk
|
||||
|
||||
@@ -190,7 +190,7 @@ pre.006 wallet details + balance HTTP + refresh/diagnostics
|
||||
pre.007 metadata administration + rotations VIEW/OWNER
|
||||
pre.008 strong VIEW disable/recreate + export OWNER + security UX
|
||||
pre.009 integration tests + Devnet smoke + compliance/security review
|
||||
pre.010 README/USAGE/build final + prompt 0.2.7 si nécessaire
|
||||
pre.010 README/USAGE/build final + prompt suivant si nécessaire
|
||||
rel.001 publication stable
|
||||
```
|
||||
|
||||
@@ -652,7 +652,7 @@ Le gate n'est considéré franchi que si ces livrables sont écrits/consignés d
|
||||
## 24. Hors périmètre
|
||||
|
||||
```text
|
||||
modification du format logique/cryptographique .kspwallet V1 sans défaut démontré (le conteneur de persistence est traité séparément en 0.2.7)
|
||||
modification destructive du wire V1 stable ; V2 binaire est ajouté explicitement en `pre.015+` sans réécrire V1
|
||||
WalletPolicy / execution policy
|
||||
construction/simulation/envoi de transaction
|
||||
WebSocket/gRPC
|
||||
@@ -666,11 +666,11 @@ trading
|
||||
|
||||
Le Wallet Desk valide et administre Wallet ; il ne devient pas l'application globale KSP.
|
||||
|
||||
### TODO futur `0.2.12` — prix offchain dans Wallet Desk
|
||||
### TODO futur `0.2.11` — prix offchain dans Wallet Desk
|
||||
|
||||
La visualisation de prix offchain n'appartient pas au scope de `0.2.6`. Une application spécialisée de visualisation de prix offchain doit d'abord être réalisée et valider durablement ses sources, contrats, rafraîchissement, cache et UX.
|
||||
|
||||
Pour `0.2.12`, prévoir explicitement un chantier d'intégration de cette capacité dans `ksp-app-wallet-desk` afin qu'un wallet puisse afficher les informations de prix offchain pertinentes sans dupliquer la logique de récupération/normalisation possédée par le composant spécialisé. Le futur travail devra réauditer la frontière entre application, bibliothèque/service partagé et Transport avant implémentation ; le TODO n'autorise pas l'ajout anticipé de logique de prix dans Wallet Desk pendant `0.2.6`.
|
||||
Pour `0.2.11`, prévoir explicitement un chantier d'intégration de cette capacité dans `ksp-app-wallet-desk` afin qu'un wallet puisse afficher les informations de prix offchain pertinentes sans dupliquer la logique de récupération/normalisation possédée par le composant spécialisé. Le futur travail devra réauditer la frontière entre application, bibliothèque/service partagé et Transport avant implémentation ; le TODO n'autorise pas l'ajout anticipé de logique de prix dans Wallet Desk pendant `0.2.6`.
|
||||
|
||||
## 25. Résultat attendu de `0.2.6`
|
||||
|
||||
@@ -718,4 +718,9 @@ canari pre.013 : ne plus figer la phase shell historique
|
||||
version technique : 0.2.6-pre.14.fix.1
|
||||
```
|
||||
|
||||
Le workflow Tauri reste crate-local. En debug, les deux binaires recalent ensuite leur current working directory sur la racine du workspace via `CARGO_MANIFEST_DIR/../..`; la stratégie release/bundle reste un point explicite à fermer en `pre.015`.
|
||||
Le workflow Tauri reste crate-local. En debug, les deux binaires recalent ensuite leur current working directory sur la racine du workspace via `CARGO_MANIFEST_DIR/../..`; la stratégie release/bundle reste un point explicite à fermer dans la candidate finale `pre.018`.
|
||||
|
||||
|
||||
## Addendum `pre.015` — V2 binaire intercalé
|
||||
|
||||
Après validation du polish `pre.014-fix.001`, la release est volontairement étendue : `pre.015` wire/codec V2, `pre.016` APIs génériques/versionnées et V2 runtime, `pre.017` migration/régression, `pre.018` candidate finale. Le prompt `0.2.7` redevient WebSocket Solana standard.
|
||||
|
||||
@@ -1,268 +1,82 @@
|
||||
<!-- file: prompts/012-V0_2_7_START_PROMPT.md -->
|
||||
<!-- version: 1 -->
|
||||
<!-- version: 2 -->
|
||||
|
||||
# Prompt de démarrage `0.2.7` — conteneur binaire `.kspwallet`
|
||||
# Prompt de démarrage `0.2.7` — WebSocket Solana standard
|
||||
|
||||
## 1. Contexte de reprise
|
||||
|
||||
La base attendue est la release stable :
|
||||
Base attendue : tag stable `v0.2.6`.
|
||||
|
||||
```text
|
||||
v0.2.6
|
||||
```
|
||||
|
||||
`0.2.5` a stabilisé `ksp-wallet-lib` et le format logique/cryptographique `.kspwallet` V1 : capacités VIEW/OWNER indépendantes, Argon2id, XChaCha20-Poly1305, autorité OWNER Ed25519, persistence atomique/no-clobber, rotations, révocation VIEW forte, signature et transferts Solana CLI JSON/Base58.
|
||||
|
||||
`0.2.6` a validé cette surface au travers de `ksp-app-wallet-desk` sans déplacer la propriété du format ou des secrets hors de Wallet.
|
||||
`0.2.6` a validé Wallet Desk puis intégré le wire binaire `.kspwallet` V2, les APIs Wallet génériques/versionnées, la compatibilité V1/V2 et les migrations explicites. `0.2.7` revient donc à la séquence Transport prévue avant l'intercalation temporaire du chantier binaire.
|
||||
|
||||
La release à ouvrir est :
|
||||
|
||||
```text
|
||||
0.2.7 — conteneur binaire de persistence .kspwallet
|
||||
0.2.7 — WebSocket Solana standard
|
||||
```
|
||||
|
||||
La première tranche est `0.2.7-pre.001` et commence obligatoirement par **audit + threat-model + options de framing/codec + compatibilité/migration + sizing**, avant toute modification du wire de persistence.
|
||||
`0.2.7-pre.001` commence obligatoirement par audit officiel actuel + inventory exhaustif des subscriptions/unsubscriptions/notifications + threat-model/reconnexion + sizing avant implémentation lourde.
|
||||
|
||||
## 2. Motivation
|
||||
## 2. Mission
|
||||
|
||||
Le document `.kspwallet` V1 actuellement persisté est un JSON strict. Ses valeurs sensibles restent cryptographiquement protégées, mais le fichier peut être ouvert et lu comme texte par un éditeur ordinaire.
|
||||
Étendre `ksp-onchain-transport-lib` à la surface WebSocket Solana standard retenue, sans déplacer Config dans Transport et sans introduire encore Helius LaserStream.
|
||||
|
||||
L'objectif de `0.2.7` est de rendre la **persistence physique** binaire et explicitement framed, sans prétendre que cette transformation ajoute une protection cryptographique supplémentaire.
|
||||
|
||||
### Non-solution explicite : Base64 seul
|
||||
|
||||
Base64 seul n'est pas une solution acceptable :
|
||||
|
||||
- il reste textuel/ASCII ;
|
||||
- il est trivialement réversible ;
|
||||
- il ne fournit aucune confidentialité ni intégrité supplémentaire ;
|
||||
- il augmente typiquement la taille d'environ un tiers.
|
||||
|
||||
Le changement recherché est un vrai **conteneur binaire de persistence**, pas une obfuscation textuelle.
|
||||
|
||||
## 3. Séparation normative : conteneur vs format logique
|
||||
|
||||
Ne pas consommer artificiellement `format_version = 2` uniquement parce que la persistence devient binaire.
|
||||
|
||||
Distinguer explicitement :
|
||||
Contrat de sessions :
|
||||
|
||||
```text
|
||||
container/framing version
|
||||
!=
|
||||
wallet logical/cryptographic format_version
|
||||
une même URL peut porter plusieurs sessions physiques
|
||||
une session peut porter plusieurs subscriptions
|
||||
pas de pool/scheduler automatique complexe sans besoin démontré
|
||||
reconnexion bornée et états de subscription explicites
|
||||
notifications typées sans fuite d'URL/secrets dans Debug/logs
|
||||
```
|
||||
|
||||
Le payload logique V1 doit pouvoir conserver ses invariants actuels :
|
||||
## 3. Frontières
|
||||
|
||||
Conserver :
|
||||
|
||||
```text
|
||||
VIEW / OWNER
|
||||
KDF / salts / slots
|
||||
AEAD / nonces / AAD
|
||||
OWNER signature/transcript
|
||||
metadata/secret compartments
|
||||
Solana keypair identity
|
||||
rotation / strong VIEW administration
|
||||
Transport -X-> Config
|
||||
Transport -X-> Wallet
|
||||
Transport -X-> Store
|
||||
Transport -X-> tracing direct
|
||||
Config -> Transport autorisé
|
||||
ksp-logging-lib seul propriétaire des émissions applicatives
|
||||
```
|
||||
|
||||
Un futur `format_version >= 2` reste disponible pour de vraies évolutions d'autorisation/crypto, notamment second facteur.
|
||||
## 4. Audit pre.001
|
||||
|
||||
## 4. Audit obligatoire `pre.001`
|
||||
Auditer au minimum :
|
||||
|
||||
Comparer au minimum :
|
||||
- documentation Solana/Agave actuelle ;
|
||||
- méthodes subscribe/unsubscribe courantes, deprecated/unstable et notifications associées ;
|
||||
- formes de paramètres/options et réponses ;
|
||||
- reconnexion, resubscribe, backpressure, cancellation et shutdown ;
|
||||
- plusieurs sessions pour une même URL ;
|
||||
- limites provider utiles sans les figer comme règles Solana universelles ;
|
||||
- dépendances WebSocket Rust actuelles et leur graphe ;
|
||||
- sizing « une release = une session ».
|
||||
|
||||
1. framing binaire custom KSP avec grammar explicite ;
|
||||
2. codecs binaires Serde adaptés et stables ;
|
||||
3. formats self-describing éventuels ;
|
||||
4. éventuelle compression du payload si elle apporte une vraie valeur ;
|
||||
5. impact interop externe Rust/Python/Go/C ;
|
||||
6. complexité de parsing borné et rejet des inputs adversariaux ;
|
||||
7. dépendances nouvelles et leur maturité/maintenance ;
|
||||
8. capacité à préserver les test vectors cryptographiques V1 ;
|
||||
9. migration et détection sûre du JSON V1 legacy ;
|
||||
10. règles d'unknown container version / taille / trailing bytes / canonicalité.
|
||||
|
||||
Ne choisir aucun codec uniquement parce qu'il est pratique dans Rust : le format doit rester spécifiable indépendamment de l'implémentation.
|
||||
|
||||
## 5. Compatibilité obligatoire
|
||||
|
||||
`ksp-wallet-lib` doit rester capable de lire les `.kspwallet` JSON V1 déjà créés.
|
||||
|
||||
Le candidat doit définir explicitement :
|
||||
## 5. Hors périmètre
|
||||
|
||||
```text
|
||||
legacy JSON V1 read
|
||||
new binary container read
|
||||
new binary container write default
|
||||
migration explicite legacy -> binary
|
||||
no-clobber / atomic replace
|
||||
rollback/interruption behavior
|
||||
Helius LaserStream WebSocket -> 0.2.8
|
||||
Yellowstone gRPC
|
||||
Store/materialization
|
||||
Wallet/2FA
|
||||
pool automatique sophistiqué de sessions WebSocket
|
||||
frontend réseau direct
|
||||
```
|
||||
|
||||
Une simple ouverture d'un legacy wallet ne doit pas le réécrire silencieusement sans contrat explicite.
|
||||
|
||||
## 6. Sécurité
|
||||
|
||||
Le conteneur binaire n'est **pas** présenté comme une nouvelle couche de chiffrement.
|
||||
|
||||
Le threat model V1 reste notamment :
|
||||
|
||||
- attaquant possédant le fichier ;
|
||||
- connaissance complète de la spec ;
|
||||
- essais offline illimités sur les passwords ;
|
||||
- connaissance éventuelle d'un seul credential VIEW ou OWNER ;
|
||||
- capacité à modifier/remplacer/rollback le fichier.
|
||||
|
||||
Les gains de `0.2.7` sont :
|
||||
|
||||
```text
|
||||
framing déterministe
|
||||
non-textual persistence
|
||||
parsing/versioning physique explicite
|
||||
meilleure séparation container/payload
|
||||
préparation des futures migrations
|
||||
```
|
||||
|
||||
Pas :
|
||||
|
||||
```text
|
||||
obscurity = security
|
||||
Base64 = encryption
|
||||
binaire = protection contre attaque offline
|
||||
```
|
||||
|
||||
## 7. Frontière `ksp-wallet-lib`
|
||||
|
||||
Le changement doit rester possédé par `ksp-wallet-lib`.
|
||||
|
||||
`ksp-app-wallet-desk` ne doit pas connaître :
|
||||
|
||||
- le codec du conteneur ;
|
||||
- sa magic/version physique ;
|
||||
- son layout ;
|
||||
- ses offsets ;
|
||||
- la distinction legacy/new lors des opérations ordinaires.
|
||||
|
||||
Les APIs de haut niveau Wallet doivent absorber cette évolution autant que possible.
|
||||
|
||||
## 8. Wallet Desk comme canari consommateur
|
||||
|
||||
Aucune modification fonctionnelle de `ksp-app-wallet-desk` n'est attendue uniquement pour ce changement de persistence.
|
||||
|
||||
Après modification de Wallet, rejouer au minimum :
|
||||
|
||||
```bash
|
||||
cargo test -p ksp-wallet-lib
|
||||
cargo test -p ksp-app-wallet-desk
|
||||
cargo test --workspace
|
||||
```
|
||||
|
||||
Puis un parcours fonctionnel Wallet Desk doit prouver au minimum :
|
||||
|
||||
```text
|
||||
inventory
|
||||
create
|
||||
locked inspect
|
||||
VIEW unlock
|
||||
OWNER unlock
|
||||
metadata
|
||||
rotation
|
||||
strong VIEW disable/recreate
|
||||
export/import
|
||||
balance HTTP
|
||||
```
|
||||
|
||||
Si le Desk doit être modifié pour comprendre le conteneur physique, considérer cela comme un signal d'abstraction insuffisante et réauditer la frontière Wallet avant d'accepter le changement.
|
||||
|
||||
## 9. Interop et test vectors
|
||||
|
||||
Mettre à jour la spec `.kspwallet` avec une grammar byte-level du conteneur :
|
||||
|
||||
- magic ;
|
||||
- version du conteneur ;
|
||||
- longueur(s) ;
|
||||
- codec/payload kind ;
|
||||
- endianess ;
|
||||
- bornes ;
|
||||
- trailing bytes ;
|
||||
- canonicalité ;
|
||||
- unknown-version policy.
|
||||
|
||||
Conserver les test vectors cryptographiques V1 lorsque les transcripts/AAD ne changent pas, et ajouter des fixtures déterministes container + payload.
|
||||
|
||||
Prévoir au moins un parseur externe de canari afin d'éviter un format binaire « Rust-only » accidentel.
|
||||
|
||||
## 10. Futur `format_version >= 2` / second facteur
|
||||
|
||||
Ce chantier **ne réalise pas** password + OTP/2FA.
|
||||
|
||||
Pour une future version logique :
|
||||
|
||||
- `ksp-wallet-lib` possède le format, les facteurs, challenges et vérifications ;
|
||||
- un client interactif tel que Wallet Desk devra évoluer lorsqu'un OTP, enrollment/recovery, hardware/WebAuthn ou consentement externe doit être saisi/présenté ;
|
||||
- un seed TOTP enfermé uniquement dans le même fichier ne doit pas être assimilé automatiquement à un second facteur indépendant contre un attaquant qui possède ce fichier.
|
||||
|
||||
Le conteneur `0.2.7` doit simplement laisser cette évolution possible sans la pré-concevoir excessivement.
|
||||
|
||||
## 11. Dépendances
|
||||
|
||||
Toute nouvelle dépendance externe commune est déclarée dans `[workspace.dependencies]` puis consommée avec `.workspace = true`.
|
||||
|
||||
Avant ajout :
|
||||
|
||||
- vérifier la version actuelle ;
|
||||
- auditer maintenance/licence/graphe ;
|
||||
- éviter les générations obsolètes inutiles ;
|
||||
- vérifier qu'une petite grammar custom n'est pas plus durable qu'un codec lourd, ou inversement.
|
||||
|
||||
## 12. Discipline Rust / tests
|
||||
|
||||
Conserver toutes les règles KSP actuelles : Rust 2024, async-first, pas de `unsafe`, `unwrap`, `expect`, `panic` runtime, audits structurels, dépendance Logging via `ksp-logging-lib`, Config hors Wallet.
|
||||
|
||||
Validation générale :
|
||||
## 6. Validation
|
||||
|
||||
```bash
|
||||
cargo fmt --all
|
||||
python3 scripts/audit_rust_workspace_rules.py
|
||||
cargo check --workspace
|
||||
cargo clippy --workspace --all-targets
|
||||
cargo test -p ksp-wallet-lib
|
||||
cargo test -p ksp-app-wallet-desk
|
||||
cargo test -p ksp-onchain-transport-lib
|
||||
cargo test --workspace
|
||||
```
|
||||
|
||||
## 13. Forecast souple à recalibrer en `pre.001`
|
||||
|
||||
Point de départ recommandé :
|
||||
|
||||
```text
|
||||
pre.001 audit framing/codec/threat-model/interop/sizing
|
||||
pre.002 spec container + parser bounded + fixtures
|
||||
pre.003 writer binary + persistence integration
|
||||
pre.004 legacy JSON read + migration explicite
|
||||
pre.005 adversarial/interop/test vectors
|
||||
pre.006 Wallet Desk regression + live functional smoke
|
||||
pre.007 compliance/docs/prompt suivant
|
||||
rel.001
|
||||
```
|
||||
|
||||
Ce découpage est indicatif ; le gate `pre.001` doit le recalibrer selon le choix de format réel.
|
||||
|
||||
## 14. Résultat attendu
|
||||
|
||||
À la clôture stable :
|
||||
|
||||
```text
|
||||
les nouveaux .kspwallet sont persistés dans un conteneur binaire spécifié
|
||||
les anciens JSON V1 restent lisibles
|
||||
aucune sécurité fictive n'est attribuée au binaire/Base64
|
||||
les semantics cryptographiques V1 restent intactes sauf défaut démontré
|
||||
les migrations sont explicites et testées
|
||||
Wallet Desk fonctionne sans connaissance du format physique
|
||||
interop externe et parsing adversarial sont prouvés
|
||||
```
|
||||
|
||||
## 15. Instruction d'ouverture
|
||||
|
||||
Commencer par relire la spec `.kspwallet` V1, les modules `wire`, `transcript`, `persistence`, `wallet`, `owner`, `transfer` et tous les test vectors actuels.
|
||||
|
||||
Ensuite produire l'audit `0.2.7-pre.001` avant de coder le nouveau conteneur.
|
||||
Prévoir des fixtures déterministes et un smoke réseau opt-in seulement lorsqu'une composition réelle le justifie.
|
||||
|
||||
Reference in New Issue
Block a user