v0.2.5-pre.003
This commit is contained in:
439
deltas/0.2.5/pre.003.md
Normal file
439
deltas/0.2.5/pre.003.md
Normal file
@@ -0,0 +1,439 @@
|
||||
<!-- file: deltas/0.2.5/pre.003.md -->
|
||||
<!-- version: 1 -->
|
||||
|
||||
# Delta `0.2.5-pre.003` — wire `.kspwallet` V1 strict + transcript/AAD + spécification interop
|
||||
|
||||
## Base requise
|
||||
|
||||
```text
|
||||
livraison : 0.2.5-pre.002-fix.002
|
||||
workspace.package.version = "0.2.5-pre.2.fix.2"
|
||||
```
|
||||
|
||||
La base effective est l'archive Gitea opérateur `0.2.5-pre.002`, complétée successivement par `pre.002-fix.001` et `pre.002-fix.002`. Les validations opérateur de cette base sont toutes passées : `cargo fmt --all`, `cargo check --workspace`, `cargo clippy --workspace --all-targets` et `cargo test -p ksp-wallet-lib`.
|
||||
|
||||
## Objectif
|
||||
|
||||
Figer la **grammaire externe et les octets d'authentification contextuelle V1** avant toute implémentation KDF/AEAD réelle.
|
||||
|
||||
Cette tranche introduit :
|
||||
|
||||
```text
|
||||
KspWalletEnvelopeV1
|
||||
JSON UTF-8 strict
|
||||
Base64url canonique sans padding
|
||||
limite fichier 1 MiB
|
||||
key slots OWNER + VIEW optionnel
|
||||
slot_id 16 octets
|
||||
view_descriptor signé conceptuellement par OWNER
|
||||
paramètres Argon2id structuraux sérialisés
|
||||
compartiments owner_control / metadata / secret versionnés
|
||||
state_signature Ed25519 wire
|
||||
transcript OWNER déterministe TLV
|
||||
AAD OWNER slot / VIEW slot
|
||||
AAD owner-control / metadata / secret
|
||||
fixture wire-only déterministe
|
||||
spécification docs/formats/KSPWALLET_V1.md
|
||||
```
|
||||
|
||||
Aucune dérivation de clé, aucun chiffrement/déchiffrement, aucune vérification Ed25519, aucune keypair Solana et aucune persistence ne sont exécutés dans `pre.003`.
|
||||
|
||||
## Version Cargo
|
||||
|
||||
Conformément à `VER-ID-009` :
|
||||
|
||||
```text
|
||||
0.2.5-pre.2.fix.2 -> 0.2.5-pre.3
|
||||
```
|
||||
|
||||
## Dépendances
|
||||
|
||||
`serde` et `serde_json` étaient déjà centralisés au workspace et sont maintenant consommés par Wallet pour le codec strict. La feature `derive` appartient au manifest membre, conformément à `DEP-CARGO-003`.
|
||||
|
||||
Nouvelle dépendance commune :
|
||||
|
||||
```toml
|
||||
base64 = { version = "^0.23" }
|
||||
```
|
||||
|
||||
Le manifest Wallet consomme :
|
||||
|
||||
```toml
|
||||
base64.workspace = true
|
||||
serde = { workspace = true, features = ["derive"] }
|
||||
serde_json.workspace = true
|
||||
```
|
||||
|
||||
La génération actuelle réauditée lors de la tranche est `base64 0.23.1`. Le moteur `URL_SAFE_NO_PAD` impose l'alphabet URL-safe sans padding et rejette les trailing bits non canoniques ; Wallet effectue en plus `decode -> re-encode == input`.
|
||||
|
||||
Aucune dépendance Argon2, AEAD, CSPRNG, Ed25519 ou Solana supplémentaire n'est encore ajoutée.
|
||||
|
||||
## Wire V1 figé
|
||||
|
||||
### Enveloppe
|
||||
|
||||
Champs top-level exacts :
|
||||
|
||||
```text
|
||||
magic
|
||||
format_version
|
||||
owner_auth_public_key
|
||||
view_descriptor
|
||||
key_slots
|
||||
owner_control
|
||||
metadata
|
||||
secret
|
||||
state_signature
|
||||
```
|
||||
|
||||
Tous les DTO serde V1 utilisent `deny_unknown_fields`.
|
||||
|
||||
Le parser effectue d'abord un probe `magic + format_version` afin qu'une version future soit rejetée explicitement comme `format_version_unsupported` avant d'essayer d'imposer la forme V1.
|
||||
|
||||
### Binary encoding
|
||||
|
||||
Tous les champs binaires V1 sont Base64url sans padding. Longueurs fixes principales :
|
||||
|
||||
```text
|
||||
owner_auth_public_key 32 octets
|
||||
slot_id 16 octets
|
||||
XChaCha nonce 24 octets
|
||||
Ed25519 state signature 64 octets
|
||||
KDF salt 16..64 octets
|
||||
```
|
||||
|
||||
### Key slots
|
||||
|
||||
V1 accepte exactement :
|
||||
|
||||
```text
|
||||
1 OWNER
|
||||
0 ou 1 VIEW
|
||||
maximum 2 slots
|
||||
slot_id uniques
|
||||
```
|
||||
|
||||
`view_descriptor` est figé comme :
|
||||
|
||||
```text
|
||||
enabled=true + slot_id 16 octets correspondant au slot VIEW
|
||||
enabled=false + slot_id=null + aucun slot VIEW
|
||||
```
|
||||
|
||||
L'ordre JSON du tableau `key_slots` n'est pas sémantique. Le serializer KSP émet OWNER puis VIEW.
|
||||
|
||||
### KDF structural bounds
|
||||
|
||||
Sans exécuter Argon2, le parser rejette avant crypto coûteuse :
|
||||
|
||||
```text
|
||||
algorithm = argon2id
|
||||
version = 19
|
||||
memory_kib = 1..1_048_576
|
||||
iterations = 1..64
|
||||
parallelism = 1..64
|
||||
salt = 16..64 octets
|
||||
```
|
||||
|
||||
Ces plafonds sont des limites de format/rejet hostile. Ils ne fixent **pas** les defaults de création, benchmarkés en `pre.004`.
|
||||
|
||||
### Compartiments
|
||||
|
||||
Versions indépendantes initiales :
|
||||
|
||||
```text
|
||||
control_version = 1
|
||||
metadata_version = 1
|
||||
secret_version = 1
|
||||
```
|
||||
|
||||
Tous utilisent le wire `xchacha20-poly1305` avec nonce 24 octets. Limites ciphertext :
|
||||
|
||||
```text
|
||||
owner_control <= 4096 octets
|
||||
metadata <= 65552 octets
|
||||
secret <= 4096 octets
|
||||
```
|
||||
|
||||
## Transcript OWNER
|
||||
|
||||
La signature ne porte jamais sur les octets JSON bruts.
|
||||
|
||||
Codec binaire figé :
|
||||
|
||||
```text
|
||||
ASCII(domain) || 0x00
|
||||
puis pour chaque champ :
|
||||
tag u16 big-endian
|
||||
length u64 big-endian
|
||||
value length octets
|
||||
|
||||
u32 => 4 octets big-endian dans value
|
||||
bool => 00 ou 01
|
||||
```
|
||||
|
||||
Domain :
|
||||
|
||||
```text
|
||||
KSPWALLET-V1-STATE
|
||||
```
|
||||
|
||||
Le transcript inclut :
|
||||
|
||||
```text
|
||||
magic/version
|
||||
autorité publique OWNER
|
||||
descripteur VIEW stable
|
||||
slot OWNER complet
|
||||
owner_control complet
|
||||
metadata complète
|
||||
secret complet
|
||||
algorithme state signature
|
||||
```
|
||||
|
||||
Il exclut volontairement :
|
||||
|
||||
```text
|
||||
KDF/salt VIEW
|
||||
wrap nonce/ciphertext VIEW
|
||||
state_signature.signature
|
||||
```
|
||||
|
||||
Cela matérialise le contrat décidé : VIEW peut rewrapper son accès metadata pour changer son propre password sans posséder l'autorité OWNER, mais ne peut pas modifier l'état OWNER-controlled.
|
||||
|
||||
## AAD
|
||||
|
||||
Domains distincts :
|
||||
|
||||
```text
|
||||
KSPWALLET-V1-AAD-OWNER-SLOT
|
||||
KSPWALLET-V1-AAD-VIEW-SLOT
|
||||
KSPWALLET-V1-AAD-OWNER-CONTROL
|
||||
KSPWALLET-V1-AAD-METADATA
|
||||
KSPWALLET-V1-AAD-SECRET
|
||||
```
|
||||
|
||||
Les AAD utilisent le même TLV déterministe et lient au minimum magic/version, `owner_auth_public_key`, rôle/kind et paramètres publics pertinents.
|
||||
|
||||
Le nonce est fourni séparément à l'AEAD et n'est pas dupliqué dans l'AAD ; le ciphertext/tag est le résultat de l'opération et n'appartient pas à son propre AAD.
|
||||
|
||||
## Fixture structurelle
|
||||
|
||||
Ajout :
|
||||
|
||||
```text
|
||||
crates/ksp-wallet-lib/tests/fixtures/kspwallet_v1_wire_only.json
|
||||
```
|
||||
|
||||
Cette fixture :
|
||||
|
||||
```text
|
||||
est strictement test-only
|
||||
n'utilise aucune clé réelle
|
||||
contient des ciphertexts artificiels
|
||||
contient une signature artificielle
|
||||
n'est pas un wallet cryptographiquement valide
|
||||
ne fixe pas les defaults Argon2 de production
|
||||
```
|
||||
|
||||
Elle fixe en revanche les octets attendus du transcript et des cinq AAD.
|
||||
|
||||
## API publique
|
||||
|
||||
La façade réexporte les contrats V1 sans exposer les modules internes :
|
||||
|
||||
```text
|
||||
KspWalletEnvelopeV1
|
||||
WalletKeySlotV1
|
||||
WalletKeySlotRoleV1
|
||||
WalletKdfParametersV1
|
||||
WalletKeyWrapV1
|
||||
WalletViewDescriptorV1
|
||||
WalletEncryptedCompartmentV1
|
||||
WalletCompartmentKindV1
|
||||
WalletStateSignatureV1
|
||||
identifiants d'algorithmes V1
|
||||
constantes de limites/domain separation
|
||||
```
|
||||
|
||||
`KspWalletEnvelopeV1` fournit :
|
||||
|
||||
```text
|
||||
parse_json(...)
|
||||
to_json_bytes()
|
||||
getters wire read-only
|
||||
state_transcript()
|
||||
owner_slot_aad()
|
||||
view_slot_aad()
|
||||
compartment_aad(...)
|
||||
```
|
||||
|
||||
Aucun constructeur public ne permet de fabriquer arbitrairement un envelope non validé.
|
||||
|
||||
Les `Debug` des enveloppes/slots/compartiments n'affichent pas les ciphertexts, salts ou nonces complets ; ils n'exposent que les algorithmes, versions et tailles nécessaires au diagnostic.
|
||||
|
||||
## Documentation de format
|
||||
|
||||
Nouveau contrat durable :
|
||||
|
||||
```text
|
||||
docs/formats/
|
||||
```
|
||||
|
||||
`docs/rules/FILE_CONTRACTS.md` est mis à jour dans la même tranche, avant que cette famille devienne une convention répétée.
|
||||
|
||||
Ajouts :
|
||||
|
||||
```text
|
||||
docs/formats/000-README.md
|
||||
docs/formats/KSPWALLET_V1.md
|
||||
```
|
||||
|
||||
`KSPWALLET_V1.md` est indépendant du code Rust et décrit déjà de manière normative : grammaire, encodages, limites, strictness, key slots, tags TLV, ordre transcript et AAD. Les opérations KDF/AEAD/payloads et vecteurs crypto complets seront ajoutés dans les tranches qui les implémentent.
|
||||
|
||||
## Frontières confirmées
|
||||
|
||||
Toujours interdit :
|
||||
|
||||
```text
|
||||
Wallet -> Config
|
||||
Wallet -> Transport
|
||||
Wallet -> ExecutionPolicy
|
||||
Wallet -> Store
|
||||
Wallet -> Tauri
|
||||
Wallet -> tracing direct
|
||||
Wallet -> solana-pubkey direct
|
||||
Wallet -> environnement processus
|
||||
```
|
||||
|
||||
`Pubkey` reste possédée/réexportée par `ksp-core-lib`; `pre.003` n'introduit aucun type Pubkey Solana direct.
|
||||
|
||||
Le target comportemental reste `TRACING_TARGET = "ksp-wallet-lib"` dans `src/constants.rs` et le parsing wire émet uniquement un `trace` non secret via `ksp-logging-lib` après validation réussie.
|
||||
|
||||
## Tests ajoutés/étendus
|
||||
|
||||
### Unitaires wire
|
||||
|
||||
```text
|
||||
fixture V1 parse + semantic round-trip
|
||||
unknown format version
|
||||
unknown top-level field
|
||||
Base64url paddé/non canonique
|
||||
mismatch view_descriptor / VIEW slot
|
||||
KDF zéro/pathologique
|
||||
fichier > 1 MiB
|
||||
Debug sans ciphertext complet
|
||||
```
|
||||
|
||||
### Unitaires transcript/AAD
|
||||
|
||||
```text
|
||||
state transcript exact
|
||||
OWNER slot AAD exact
|
||||
VIEW slot AAD exact
|
||||
owner-control AAD exact
|
||||
metadata AAD exact
|
||||
secret AAD exact
|
||||
domain separation
|
||||
```
|
||||
|
||||
### Intégration
|
||||
|
||||
Le canari public API vérifie que l'enveloppe, les rôles et codecs transcript/AAD sont réellement consommables depuis le crate-root.
|
||||
|
||||
Le canari de dépendances est étendu à `base64`, `serde` et `serde_json` tout en conservant le firewall existant.
|
||||
|
||||
## Fichiers ajoutés
|
||||
|
||||
```text
|
||||
crates/ksp-wallet-lib/src/transcript.rs
|
||||
crates/ksp-wallet-lib/src/wire.rs
|
||||
crates/ksp-wallet-lib/tests/fixtures/kspwallet_v1_wire_only.json
|
||||
crates/ksp-wallet-lib/unit_tests/transcript.rs
|
||||
crates/ksp-wallet-lib/unit_tests/wire.rs
|
||||
docs/formats/000-README.md
|
||||
docs/formats/KSPWALLET_V1.md
|
||||
deltas/0.2.5/pre.003.md
|
||||
```
|
||||
|
||||
## Fichiers modifiés
|
||||
|
||||
```text
|
||||
Cargo.toml
|
||||
ROADMAP.md
|
||||
crates/ksp-wallet-lib/Cargo.toml
|
||||
crates/ksp-wallet-lib/src/constants.rs
|
||||
crates/ksp-wallet-lib/src/lib.rs
|
||||
crates/ksp-wallet-lib/tests/dependency_boundary.rs
|
||||
crates/ksp-wallet-lib/tests/public_api.rs
|
||||
docs/000-README.md
|
||||
docs/plans/000-README.md
|
||||
docs/plans/002-FUNCTIONAL_RELEASE_SEQUENCE.md
|
||||
docs/plans/012-V0_2_5_WALLET_FOUNDATION_PLAN.md
|
||||
docs/rules/FILE_CONTRACTS.md
|
||||
```
|
||||
|
||||
## Fichiers supprimés
|
||||
|
||||
Aucun.
|
||||
|
||||
## Validations exécutées dans l'environnement de préparation
|
||||
|
||||
Cargo/Rust n'est pas installé dans l'environnement de préparation. Les contrôles statiques suivants ont été exécutés :
|
||||
|
||||
```text
|
||||
diff exact contre la base pre.002 + fix.001 + fix.002
|
||||
scan production : aucun unwrap/expect/panic/?
|
||||
scan boundaries : aucun solana_pubkey:: / tracing:: / std::env:: / Config / Transport / Tauri
|
||||
scan RUST-API-004 : helpers pub(crate) transcript réexportés au crate-root
|
||||
scan manifests : dépendances centralisées workspace
|
||||
contrôle manuel des headers/version de fichiers
|
||||
contrôle des longueurs/fixture et vecteurs transcript/AAD via implémentation indépendante Python du TLV
|
||||
```
|
||||
|
||||
## Validations opérateur requises
|
||||
|
||||
```bash
|
||||
cargo fmt --all
|
||||
cargo check --workspace
|
||||
cargo clippy --workspace --all-targets
|
||||
cargo test -p ksp-wallet-lib
|
||||
```
|
||||
|
||||
Si cette tranche constitue le checkpoint Rust de clôture intermédiaire retenu, exécuter également :
|
||||
|
||||
```bash
|
||||
cargo test --workspace
|
||||
```
|
||||
|
||||
## Décisions
|
||||
|
||||
- geler le wire JSON V1 maintenant, avant la crypto réelle ;
|
||||
- ne pas signer/canonicaliser les octets JSON ;
|
||||
- utiliser un transcript sémantique TLV déterministe ;
|
||||
- rendre l'ordre `key_slots` JSON non sémantique ;
|
||||
- fixer `slot_id` à 16 octets ;
|
||||
- permettre VIEW self-service uniquement via exclusion contrôlée de son wrapping du transcript OWNER ;
|
||||
- sérialiser les versions de payload indépendamment ;
|
||||
- rejeter les paramètres KDF structurellement pathologiques avant toute KDF ;
|
||||
- ne pas ajouter Argon2/AEAD/Ed25519 avant consommation effective ;
|
||||
- créer `docs/formats/` avec son contrat dans `FILE_CONTRACTS.md` dans la même tranche.
|
||||
|
||||
## Questions ouvertes reportées à `pre.004`
|
||||
|
||||
```text
|
||||
defaults Argon2id mesurés sur machines cibles
|
||||
API exacte de spawn_blocking pour KDF
|
||||
crate CSPRNG exacte lors de l'implémentation
|
||||
crate XChaCha20-Poly1305 exacte/feature set final
|
||||
layout plaintext exact des wrapped capabilities
|
||||
premiers vecteurs crypto publics valides
|
||||
```
|
||||
|
||||
Ces questions ne doivent pas modifier silencieusement le wire/transcript/AAD figés par `pre.003`.
|
||||
|
||||
## Commit attendu
|
||||
|
||||
```text
|
||||
v0.2.5-pre.003
|
||||
```
|
||||
Reference in New Issue
Block a user