v0.2.5-pre.003

This commit is contained in:
2026-08-19 10:52:21 +02:00
parent bcda6db11f
commit c6794af05b
20 changed files with 2721 additions and 37 deletions

View File

@@ -1,5 +1,5 @@
<!-- file: docs/000-README.md -->
<!-- version: 34 -->
<!-- version: 35 -->
# Documentation KSP
@@ -9,7 +9,7 @@ Le préfixe `000-` est volontaire : la documentation est destinée à devenir vo
## Rôle de `docs/`
Le répertoire contient la documentation durable du projet : règles détaillées, idées à explorer, architecture, références, décisions, guides, plans et validations.
Le répertoire contient la documentation durable du projet : règles détaillées, idées à explorer, architecture, spécifications de formats, références, décisions, guides, plans et validations.
Les documents temporaires d'une livraison ne sont pas stockés sous `docs/`. Ils sont enregistrés sous `deltas/` afin de conserver un seul historique de livraison pour l'ensemble du dépôt.
@@ -31,6 +31,9 @@ docs/
│ ├── 008-DATA_MATERIALIZATION_AND_STORE.md
│ ├── 009-ACQUISITION_WORKERS_AND_JOBS.md
│ └── 010-APPS_SERVICES_SCENARIOS_AND_CONTROL.md
├── formats/
│ ├── 000-README.md
│ └── KSPWALLET_V1.md
├── plans/
│ ├── 000-README.md
│ ├── 001-V0_0_3_PLAN.md
@@ -72,6 +75,10 @@ D'autres sous-répertoires seront ajoutés uniquement lorsque leur rôle aura é
Le plan historique de la phase fondatrice clôturée est conservé dans [`plans/001-V0_0_3_PLAN.md`](plans/001-V0_0_3_PLAN.md). La séquence active des premières releases fonctionnelles est définie dans [`plans/002-FUNCTIONAL_RELEASE_SEQUENCE.md`](plans/002-FUNCTIONAL_RELEASE_SEQUENCE.md). Le plan détaillé de la release stable `0.1.1` est conservé comme historique clôturé dans [`plans/003-V0_1_1_CORE_FOUNDATION_PLAN.md`](plans/003-V0_1_1_CORE_FOUNDATION_PLAN.md). Le plan détaillé de la release stable `0.1.2` est conservé comme historique clôturé dans [`plans/004-V0_1_2_LOGGING_FOUNDATION_PLAN.md`](plans/004-V0_1_2_LOGGING_FOUNDATION_PLAN.md). Le plan détaillé de la release stable `0.1.3 — Configuration foundation` est conservé comme historique clôturé dans [`plans/005-V0_1_3_CONFIG_FOUNDATION_PLAN.md`](plans/005-V0_1_3_CONFIG_FOUNDATION_PLAN.md). Le plan détaillé de la release stable `0.1.4 — ksp-app-config-desk` est conservé comme historique clôturé dans [`plans/006-V0_1_4_CONFIG_DESKTOP_PLAN.md`](plans/006-V0_1_4_CONFIG_DESKTOP_PLAN.md), avec sa matrice finale [`validation/001-V0_1_4_CONFIG_DESKTOP.md`](validation/001-V0_1_4_CONFIG_DESKTOP.md). Son prompt d'ouverture historique reste [`../prompts/004-V0_1_4_START_PROMPT.md`](../prompts/004-V0_1_4_START_PROMPT.md). La release stable `0.2.0` clôt l'audit de bot3 et le découpage de la série. Son plan directeur est conservé comme historique clôturé dans [`plans/007-V0_2_0_SERIES_PLANNING.md`](plans/007-V0_2_0_SERIES_PLANNING.md), avec sa matrice finale [`validation/002-V0_2_0_SERIES_PLANNING.md`](validation/002-V0_2_0_SERIES_PLANNING.md). La release stable `0.2.1 — HTTP Solana foundation` a été ouverte par [`../prompts/006-V0_2_1_START_PROMPT.md`](../prompts/006-V0_2_1_START_PROMPT.md). Son gate de sizing et sa matrice exhaustive sont conservés dans [`plans/008-V0_2_1_ONCHAIN_HTTP_PLAN.md`](plans/008-V0_2_1_ONCHAIN_HTTP_PLAN.md), avec la validation finale [`validation/003-V0_2_1_ONCHAIN_HTTP.md`](validation/003-V0_2_1_ONCHAIN_HTTP.md), README/USAGE Transport et le smoke Devnet opt-in de composition Config -> Transport. Le prompt [`../prompts/007-V0_2_2_START_PROMPT.md`](../prompts/007-V0_2_2_START_PROMPT.md) a ouvert la release stable `0.2.2 — HTTP Accounts + Tokens + Cluster`. Son plan clôturé [`plans/009-V0_2_2_HTTP_ACCOUNTS_TOKENS_CLUSTER_PLAN.md`](plans/009-V0_2_2_HTTP_ACCOUNTS_TOKENS_CLUSTER_PLAN.md) conserve l'audit et l'implémentation des 22 wrappers typés, tandis que [`validation/004-V0_2_2_HTTP_ACCOUNTS_TOKENS_CLUSTER.md`](validation/004-V0_2_2_HTTP_ACCOUNTS_TOKENS_CLUSTER.md) enregistre les validations déterministes, les graphes Cargo et les deux smokes Devnet passés avant publication. Le prompt [`../prompts/008-V0_2_3_START_PROMPT.md`](../prompts/008-V0_2_3_START_PROMPT.md) a ouvert la release stable `0.2.3 — HTTP Transactions`. Son plan clôturé [`plans/010-V0_2_3_HTTP_TRANSACTIONS_PLAN.md`](plans/010-V0_2_3_HTTP_TRANSACTIONS_PLAN.md) conserve l'audit et l'implémentation des 11 wrappers ; le réaudit [`validation/005-V0_2_3_KSP_TRANSPORT_007_RETRO_AUDIT.md`](validation/005-V0_2_3_KSP_TRANSPORT_007_RETRO_AUDIT.md) confirme la complétude des 37 wrappers HTTP typés et [`validation/006-V0_2_3_HTTP_TRANSACTIONS.md`](validation/006-V0_2_3_HTTP_TRANSACTIONS.md) enregistre les validations finales, graphes Cargo et deux smokes Devnet passés avant publication. Le prompt [`../prompts/009-V0_2_4_START_PROMPT.md`](../prompts/009-V0_2_4_START_PROMPT.md) a ouvert la release stable `0.2.4 — HTTP Blocks + Economics + compliance HTTP finale`. Son plan clôturé [`plans/011-V0_2_4_HTTP_BLOCKS_ECONOMICS_PLAN.md`](plans/011-V0_2_4_HTTP_BLOCKS_ECONOMICS_PLAN.md) conserve limplémentation des 15 wrappers et la compliance `52/52 + 14/14`; la matrice finale [`validation/007-V0_2_4_HTTP_FINAL_COMPLIANCE.md`](validation/007-V0_2_4_HTTP_FINAL_COMPLIANCE.md) enregistre le réaudit SIMD/inventaire, les canaries globales et les preuves opérateur avant publication. Le prompt [`../prompts/010-V0_2_5_START_PROMPT.md`](../prompts/010-V0_2_5_START_PROMPT.md), finalisé par `0.2.4-pre.009-fix.001`, ouvre `0.2.5 — Wallet foundation` sur la base stable `v0.2.4`. Son gate `0.2.5-pre.001` est conservé dans [`plans/012-V0_2_5_WALLET_FOUNDATION_PLAN.md`](plans/012-V0_2_5_WALLET_FOUNDATION_PLAN.md) : il réaudite bot2/bot3 et les crates actuelles, formalise le threat model offline, retient les capacités VIEW/OWNER indépendantes et le niveau B read-only, cadre le format interopérable `.kspwallet` V1 et redimensionne la release avant implémentation cryptographique.
## Spécifications de formats
Les formats durables, interopérables et destinés à être réimplémentables hors de KSP sont indexés depuis [`formats/000-README.md`](formats/000-README.md). Le premier format natif publié dans cette famille est [`.kspwallet` V1](formats/KSPWALLET_V1.md), dont `0.2.5-pre.003` fige l'enveloppe JSON stricte, les key slots, les limites structurelles, le transcript OWNER et les AAD indépendamment de l'implémentation Rust.
`IDEAS.md` conserve les pistes et questions qui ne sont pas encore des engagements du roadmap ni des décisions architecturales.
## Prompts

View File

@@ -0,0 +1,12 @@
<!-- file: docs/formats/000-README.md -->
<!-- version: 1 -->
# Formats KSP
Ce répertoire contient les spécifications de formats durables appartenant à KSP et destinées à être implémentables indépendamment du code source Rust.
Une spécification de format décrit le wire exact, les encodages, les limites, les règles de parsing/rejet, les données authentifiées et les procédures d'interopérabilité nécessaires. Elle ne dépend pas d'un type Rust interne comme condition de compréhension.
## Formats actifs
- [`KSPWALLET_V1.md`](KSPWALLET_V1.md) — spécification du format natif autonome `.kspwallet` V1. `0.2.5-pre.003` fige son enveloppe JSON stricte, ses limites structurelles, ses key slots, son transcript OWNER et ses AAD ; les paramètres de création KDF/crypto effectifs et les vecteurs cryptographiques complets sont consolidés par les prereleases Wallet suivantes.

View File

@@ -0,0 +1,617 @@
<!-- file: docs/formats/KSPWALLET_V1.md -->
<!-- version: 1 -->
# `.kspwallet` V1 — spécification du format natif Wallet KSP
## 1. Statut et objectif
Ce document est l'autorité normative du **wire `.kspwallet` `format_version = 1`**.
`0.2.5-pre.003` fige :
```text
enveloppe JSON UTF-8 stricte
encodage Base64url sans padding
key slots OWNER / VIEW
limites structurelles V1
transcript binaire OWNER
AAD de wrapping OWNER / VIEW
AAD des compartiments owner-control / metadata / secret
règles unknown-field / unknown-version
```
Les prereleases suivantes complètent les paramètres de création Argon2id benchmarkés, les opérations cryptographiques, les payloads plaintext exacts et les vecteurs cryptographiques complets. Toute évolution qui modifie un élément déjà déclaré **figé** par cette spécification exige une évolution explicitement tracée avant la release stable ; après publication de V1, une incompatibilité de wire exige un nouveau `format_version`.
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
V1 est **autonome**. Ouvrir un wallet ne requiert aucun :
```text
salt externe
pepper KSP
OTP
secret compilé dans KSP
service distant
réseau
keychain OS
fichier secret annexe
ancre de confiance externe
```
Tous les salts, nonces, paramètres KDF, wrapped keys, ciphertexts et éléments nécessaires à l'interprétation cryptographique sont dans le fichier.
Sans password OWNER, un détenteur du fichier ne doit pas obtenir la keypair Solana, signer, exporter le secret ni produire une modification OWNER-authentifiée des metadata. VIEW donne uniquement accès à Pubkey/alias/notes et à la rotation de **son propre password VIEW**.
Les ACL et permissions du système de fichiers sont hors du contrat cryptographique de `.kspwallet`. Remplacer entièrement un fichier par un autre wallet valide ne révèle pas l'ancien secret et revient à substituer une autre identité Wallet.
## 3. Encodage général
Le document est :
```text
JSON
UTF-8
objet top-level unique
maximum 1 048 576 octets
trailing whitespace JSON autorisé
trailing data non-whitespace interdit
```
L'ordre des propriétés JSON n'est **pas sémantique**. Une implémentation peut réordonner ou réindenter le JSON sans changer le transcript cryptographique tant que l'état sémantique parsé est identique.
Tous les champs binaires utilisent **Base64url RFC 4648 alphabet URL-safe, sans padding** :
```text
alphabet : A-Z a-z 0-9 - _
padding = interdit
trailing bits non canoniques = interdits
```
Le parsing normatif effectue conceptuellement :
```text
decode Base64url sans padding
-> re-encode Base64url sans padding
-> la chaîne obtenue doit être exactement égale à l'entrée
```
## 4. Magic et version
Valeurs V1 :
```text
magic = "KSPWALLET"
format_version = 1
```
Un `magic` différent est invalide.
Un `format_version` différent doit être signalé comme **version non supportée**, et non interprété avec la grammaire V1.
`format_version` ne change pas lors d'une rotation de password, d'une modification d'alias/note ou d'une réécriture atomique.
## 5. Enveloppe JSON exacte
La forme V1 est :
```json
{
"magic": "KSPWALLET",
"format_version": 1,
"owner_auth_public_key": "<32 octets Base64url>",
"view_descriptor": {
"enabled": true,
"slot_id": "<16 octets Base64url ou null>"
},
"key_slots": [
{
"slot_id": "<16 octets Base64url>",
"role": "owner",
"kdf": {
"algorithm": "argon2id",
"version": 19,
"memory_kib": 65536,
"iterations": 3,
"parallelism": 1,
"salt": "<16..64 octets Base64url>"
},
"wrap": {
"algorithm": "xchacha20-poly1305",
"nonce": "<24 octets Base64url>",
"ciphertext": "<Base64url>"
}
},
{
"slot_id": "<16 octets Base64url>",
"role": "view",
"kdf": {
"algorithm": "argon2id",
"version": 19,
"memory_kib": 32768,
"iterations": 4,
"parallelism": 1,
"salt": "<16..64 octets Base64url>"
},
"wrap": {
"algorithm": "xchacha20-poly1305",
"nonce": "<24 octets Base64url>",
"ciphertext": "<Base64url>"
}
}
],
"owner_control": {
"control_version": 1,
"algorithm": "xchacha20-poly1305",
"nonce": "<24 octets Base64url>",
"ciphertext": "<Base64url>"
},
"metadata": {
"metadata_version": 1,
"algorithm": "xchacha20-poly1305",
"nonce": "<24 octets Base64url>",
"ciphertext": "<Base64url>"
},
"secret": {
"secret_version": 1,
"algorithm": "xchacha20-poly1305",
"nonce": "<24 octets Base64url>",
"ciphertext": "<Base64url>"
},
"state_signature": {
"algorithm": "ed25519",
"signature": "<64 octets Base64url>"
}
}
```
Les valeurs Argon2 chiffrées dans cet exemple sont **des valeurs de fixture structurelle**, pas les defaults de création V1. Les defaults ne deviennent normatifs qu'après benchmark de `pre.004`.
## 6. `owner_auth_public_key`
`owner_auth_public_key` contient exactement **32 octets** : la clé publique Ed25519 de l'autorité d'administration du format Wallet.
Elle est distincte de la keypair Solana. La Pubkey Solana reste dans le compartiment metadata chiffré et ne doit pas apparaître dans l'enveloppe verrouillée.
La clé privée correspondant à `owner_auth_public_key` appartient au matériau OWNER protégé ; elle n'est jamais un champ public du fichier.
## 7. Descripteur VIEW
`view_descriptor` est OWNER-authentifié.
Règles :
```text
enabled = true => slot_id contient exactement 16 octets et un unique slot role="view" possède le même slot_id
enabled = false => slot_id est null et aucun slot role="view" n'existe
```
Le `slot_id` VIEW est stable pendant une rotation self-service du password VIEW.
VIEW peut modifier uniquement les paramètres de protection de **son slot VIEW courant** dans les limites V1 et rewrapper la même capability metadata. VIEW ne peut pas modifier le descripteur signé, désactiver/recréer VIEW ou transformer son slot en OWNER.
## 8. Key slots
V1 accepte :
```text
exactement 1 slot role="owner"
0 ou 1 slot role="view"
maximum total = 2
slot_id unique entre les slots
```
L'ordre des entrées dans le tableau JSON `key_slots` n'est pas sémantique. Pour le transcript, OWNER est traité séparément et VIEW est représenté par son descripteur stable.
### 8.1 KDF
Identifiant V1 :
```text
algorithm = "argon2id"
version = 19
```
Bornes structurelles de parsing :
```text
memory_kib : 1 .. 1 048 576
iterations : 1 .. 64
parallelism : 1 .. 64
salt : 16 .. 64 octets
```
Ces plafonds sont des bornes de format/rejet hostile ; ils ne définissent pas les paramètres de **création par défaut**. Ceux-ci sont benchmarkés séparément.
Le password KDF futur est la séquence exacte des octets UTF-8 fournis, sans normalisation Unicode implicite, avec une longueur maximale de 1024 octets et un password vide refusé à la création.
### 8.2 Wrapping
Identifiant V1 :
```text
algorithm = "xchacha20-poly1305"
nonce = 24 octets
ciphertext >= 16 octets
ciphertext <= 4096 octets
```
Le ciphertext contient le tag Poly1305 de 16 octets produit par l'AEAD.
Le contenu plaintext exact des wrapped capabilities est figé avec la couche crypto/payload suivante ; la grammaire envelope/key-slot et son AAD sont déjà figés ici.
## 9. Compartiments chiffrés
Trois compartiments indépendants existent :
```text
owner_control
metadata
secret
```
Leurs versions initiales sont indépendantes :
```text
control_version = 1
metadata_version = 1
secret_version = 1
```
Les trois utilisent :
```text
algorithm = "xchacha20-poly1305"
nonce = 24 octets
```
Bornes ciphertext V1 :
```text
owner_control : 16 .. 4096 octets
metadata : 16 .. 65 552 octets
secret : 16 .. 4096 octets
```
La metadata plaintext V1 reste bornée à 65 536 octets. Les payloads plaintext exacts sont consolidés dans la tranche dédiée, mais les champs wire ci-dessus ne changent pas.
Le compartiment metadata contient à terme au minimum :
```text
Pubkey Solana Base58 canonique
alias optionnel <= 256 octets UTF-8
maximum 64 notes
texte note <= 8192 octets UTF-8
id de note = 16 octets aléatoires
```
Le compartiment secret contient la keypair Solana exacte nécessaire à la signature OWNER.
## 10. Signature d'état OWNER
V1 :
```text
algorithm = "ed25519"
signature = 64 octets
```
La signature porte sur le **transcript sémantique OWNER-controlled**, jamais sur les octets JSON bruts.
`state_signature.signature` elle-même est exclue du transcript. L'identifiant `algorithm = "ed25519"` est inclus.
Les paramètres/salt/nonce/ciphertext du slot VIEW self-service sont exclus de la signature OWNER ; le descripteur stable VIEW est inclus.
## 11. Codec binaire transcript/AAD
### 11.1 Préfixe de domaine
Chaque transcript/AAD commence par :
```text
ASCII(domain_separator) || 0x00
```
### 11.2 Champ TLV
Chaque champ suivant utilise exactement :
```text
tag : u16 big-endian
length : u64 big-endian
value : `length` octets
```
Un entier `u32` est encodé dans `value` comme **4 octets big-endian**.
Un booléen est encodé comme un octet :
```text
false = 0x00
true = 0x01
```
Les champs binaires sont les **octets décodés** du Base64url, jamais le texte Base64url.
### 11.3 Tags V1
| Tag hex | Champ |
|--------:|----------------------------------------------------|
| `0001` | magic |
| `0002` | format_version |
| `0003` | owner_auth_public_key |
| `0010` | view enabled |
| `0011` | rôle VIEW littéral `view` |
| `0012` | view slot_id ; longueur zéro lorsque VIEW disabled |
| `0100` | slot_id |
| `0101` | slot role |
| `0102` | KDF algorithm |
| `0103` | KDF version |
| `0104` | KDF memory_kib |
| `0105` | KDF iterations |
| `0106` | KDF parallelism |
| `0107` | KDF salt |
| `0108` | wrap algorithm |
| `0109` | wrap nonce |
| `010A` | wrap ciphertext |
| `0200` | compartment kind |
| `0201` | compartment payload version |
| `0202` | compartment algorithm |
| `0203` | compartment nonce |
| `0204` | compartment ciphertext |
| `0500` | state-signature algorithm |
Les tags ne remplacent pas l'ordre normatif ; **l'ordre ci-dessous est obligatoire**.
## 12. Transcript OWNER state signature
Domain separator :
```text
KSPWALLET-V1-STATE
```
Ordre exact :
```text
0001 magic = ASCII "KSPWALLET"
0002 format_version = u32 BE 1
0003 owner_auth_public_key = 32 octets
0010 view enabled = 00/01
0011 ASCII "view"
0012 view slot_id = 16 octets si enabled, longueur 0 sinon
OWNER slot uniquement :
0100 owner slot_id
0101 ASCII "owner"
0102 ASCII "argon2id"
0103 Argon2 version u32 BE
0104 memory_kib u32 BE
0105 iterations u32 BE
0106 parallelism u32 BE
0107 owner salt
0108 ASCII "xchacha20-poly1305"
0109 owner wrap nonce
010A owner wrap ciphertext
owner_control :
0200 ASCII "owner-control"
0201 control_version u32 BE
0202 ASCII "xchacha20-poly1305"
0203 nonce
0204 ciphertext
metadata :
0200 ASCII "metadata"
0201 metadata_version u32 BE
0202 ASCII "xchacha20-poly1305"
0203 nonce
0204 ciphertext
secret :
0200 ASCII "secret"
0201 secret_version u32 BE
0202 ASCII "xchacha20-poly1305"
0203 nonce
0204 ciphertext
0500 ASCII "ed25519"
```
Sont explicitement **exclus** du transcript OWNER :
```text
VIEW KDF parameters
VIEW salt
VIEW wrap nonce
VIEW wrap ciphertext
state_signature.signature
```
Cette exclusion autorise VIEW à changer son propre password en rewrappant sa capability sans posséder l'autorité OWNER. Elle ne lui permet pas de modifier metadata/secret/OWNER state, qui restent signés.
## 13. AAD des key slots
### 13.1 OWNER
Domain separator :
```text
KSPWALLET-V1-AAD-OWNER-SLOT
```
Ordre exact :
```text
0001 magic
0002 format_version
0003 owner_auth_public_key
0100 slot_id
0101 "owner"
0102 "argon2id"
0103 KDF version
0104 memory_kib
0105 iterations
0106 parallelism
0107 salt
0108 "xchacha20-poly1305"
```
Le nonce est passé séparément à l'AEAD et n'est pas répété dans l'AAD. Le ciphertext/tag est le résultat AEAD et n'appartient pas à son propre AAD.
### 13.2 VIEW
Domain separator :
```text
KSPWALLET-V1-AAD-VIEW-SLOT
```
La suite TLV est identique à OWNER sauf :
```text
0101 = ASCII "view"
0100 = slot_id VIEW signé par view_descriptor
```
Les paramètres KDF/salt sont volontairement dans l'AAD calculé pour **l'état courant** du slot VIEW. VIEW peut les remplacer lors d'une rotation de son password, puis produire un nouveau wrapping valide de la même capability metadata.
## 14. AAD des compartiments
Les trois AAD commencent par les champs communs :
```text
0001 magic
0002 format_version
0003 owner_auth_public_key
```
Puis :
```text
0200 compartment kind
0201 compartment payload version
0202 "xchacha20-poly1305"
```
Domain separators :
```text
owner_control : KSPWALLET-V1-AAD-OWNER-CONTROL
metadata : KSPWALLET-V1-AAD-METADATA
secret : KSPWALLET-V1-AAD-SECRET
```
Valeurs de `compartment kind` :
```text
owner-control
metadata
secret
```
Le nonce est fourni séparément à l'AEAD et le ciphertext/tag est le résultat de l'opération ; ni l'un ni l'autre n'est dupliqué dans cet AAD.
## 15. Parsing et rejet stricts
V1 rejette :
```text
magic inconnu
champ top-level inconnu
champ nested inconnu
champ requis absent
champ dupliqué JSON
role slot autre que owner/view
algorithme autre que les identifiants V1
Argon2 version autre que 19
KDF hors bornes structurelles
Base64url invalide, paddé ou non canonique
owner_auth_public_key != 32 octets
slot_id != 16 octets
XChaCha nonce != 24 octets
state signature != 64 octets
OWNER slot absent ou dupliqué
VIEW slot dupliqué
slot_id OWNER == slot_id VIEW
VIEW descriptor incohérent avec VIEW slot
payload version autre que 1
ciphertext sous 16 octets ou au-dessus de sa borne V1
document > 1 MiB
trailing data non-whitespace
```
La vérification de taille du document précède le parsing JSON et toute opération KDF coûteuse.
## 16. JSON produit par KSP
Le serializer KSP V1 émet actuellement :
```text
JSON pretty-print
ordre stable des champs du modèle KSP
OWNER slot avant VIEW slot
newline final
```
Cet ordre et ce pretty-print sont un **profil de sortie KSP**, pas une canonicalisation cryptographique. Une implémentation externe conforme peut produire un autre ordre/espacement JSON si le parsing V1 aboutit au même état sémantique.
## 17. Checksum
Aucun checksum supplémentaire V1.
La détection cryptographique repose sur :
```text
AEAD des wrapped keys/compartiments
state_signature OWNER pour l'état OWNER-controlled
AAD domain-separated
```
Un checksum non authentifié n'ajouterait pas de garantie de sécurité utile.
## 18. Fixture structurelle `pre.003`
Le dépôt contient :
```text
crates/ksp-wallet-lib/tests/fixtures/kspwallet_v1_wire_only.json
```
Cette fixture est **wire-only et test-only** :
```text
ses ciphertexts sont des octets artificiels
sa signature est artificielle
elle ne constitue pas un wallet cryptographiquement valide
elle ne fixe pas les defaults Argon2 de production
elle ne contient aucune clé réelle
```
Elle fige néanmoins :
```text
JSON V1
Base64url
longueurs
slots/descripteur
transcript OWNER exact
AAD exacts
round-trip du codec
```
Les vecteurs cryptographiques publics complets avec passwords et secret test-only connus sont ajoutés après implémentation KDF/AEAD/wrapping/signature.
## 19. Invariants encore à compléter sans modifier le wire figé
Les tranches suivantes doivent compléter :
```text
pre.004 : defaults Argon2 benchmarkés + implémentation KDF/AEAD/wrapping + vecteurs crypto
pre.005 : payloads owner-control/metadata/secret + create/open VIEW/OWNER + state signature effective
pre.006+ : persistence/administration/signature/import-export selon le plan Wallet
```
Toute découverte imposant de modifier la grammaire, les tags, l'ordre transcript ou les domain separators définis dans ce document doit être traitée explicitement avant la publication stable, jamais masquée par une tolérance du parseur.

View File

@@ -1,5 +1,5 @@
<!-- file: docs/plans/000-README.md -->
<!-- version: 41 -->
<!-- version: 42 -->
# Plans KSP
@@ -20,7 +20,7 @@ Un plan décrit le périmètre, les décisions déjà acquises, les questions ou
- [`009-V0_2_2_HTTP_ACCOUNTS_TOKENS_CLUSTER_PLAN.md`](009-V0_2_2_HTTP_ACCOUNTS_TOKENS_CLUSTER_PLAN.md) — plan clôturé de la release stable `0.2.2`, établi par `pre.001`, corrigé après réaudit Agave v4.2.1 puis exécuté jusqu'à `pre.007-fix.002`; il couvre les 22 wrappers Accounts/Tokens/Cluster, le smoke Transport opt-in et la préparation de `0.2.3`.
- [`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 actif de `0.2.5 — Wallet foundation`, ouvert par `pre.001`; il fixe le threat model offline, le design VIEW/OWNER par key slots, le niveau B read-only, le format `.kspwallet` V1, les primitives candidates et le sizing révisé jusquà `pre.010`.
- [`012-V0_2_5_WALLET_FOUNDATION_PLAN.md`](012-V0_2_5_WALLET_FOUNDATION_PLAN.md) — plan actif de `0.2.5 — Wallet foundation`, ouvert par `pre.001`; `pre.002` matérialise la crate et `pre.003` fige le wire JSON V1, ses key slots, limites, transcript/AAD et la première spécification interopérable `docs/formats/KSPWALLET_V1.md`, avant la cryptographie effective de `pre.004+`.
Le `pre.001` de chaque release fonctionnelle peut introduire son propre plan détaillé lorsque la release s'ouvre.

View File

@@ -1,5 +1,5 @@
<!-- file: docs/plans/002-FUNCTIONAL_RELEASE_SEQUENCE.md -->
<!-- version: 47 -->
<!-- version: 48 -->
# Séquence des releases fonctionnelles KSP
@@ -410,6 +410,8 @@ La release doit fournir `docs/formats/KSPWALLET_V1.md` comme spécification sép
`0.2.5-pre.002` matérialise la crate sans ouvrir encore le codec ou la cryptographie du fichier : `WalletView`/`WalletOwner`, `WalletCapability`, projections `LockedWalletInfo`/`WalletInfo`/`WalletNote`, wrappers `ViewPassword`/`OwnerPassword`, codes derreur Wallet et target de logging explicite `ksp-wallet-lib`. La crate dépend seulement de Core, Logging et `zeroize`; elle consomme la Pubkey exclusivement via `ksp_core_lib::Pubkey` et ne dépend directement ni de `solana-pubkey`, ni de Config, Transport, ExecutionPolicy, Store ou Tauri. Les primitives Solana keypair/signature ne seront ajoutées que lorsquelles seront réellement consommées.
`0.2.5-pre.003` ouvre le format sans effectuer encore de cryptographie : `KspWalletEnvelopeV1` parse/serialize le JSON strict borné à 1 MiB, impose Base64url sans padding canonique, exactement un slot OWNER et un slot VIEW optionnel lié par `view_descriptor`, puis produit les octets déterministes du transcript OWNER et des AAD par TLV domain-separated. `docs/formats/KSPWALLET_V1.md` devient l'autorité indépendante du code pour ce wire figé. Les paramètres Argon2 de création, KDF/AEAD effectifs, payloads et vérification Ed25519 restent `pre.004+`.
## `0.2.6` — Wallet Desk
Mission : valider Config composite + `.kspwallet` + transport HTTP dans une application Tauri mince.

View File

@@ -1,5 +1,5 @@
<!-- file: docs/plans/012-V0_2_5_WALLET_FOUNDATION_PLAN.md -->
<!-- version: 5 -->
<!-- version: 6 -->
# Plan `0.2.5` — Wallet foundation
@@ -308,7 +308,7 @@ exactement 1 slot OWNER
0 ou 1 slot VIEW
```
Le slot OWNER et l'état de contrôle sont OWNER-signed. Pour VIEW, l'état OWNER-signed contient un **descripteur stable** (`enabled`, rôle et identifiant de slot ou équivalent wire à figer en `pre.003`). Lorsque VIEW est activé, le fichier doit contenir exactement un slot VIEW correspondant à ce descripteur. Ses paramètres Argon2id autorisés, son salt et son nonce/ciphertext de wrapping restent rotatables sans OWNER, mais les algorithmes V1, son rôle, son identité et son activation ne le sont pas. Le wrapping VIEW utilise un AAD qui lie au minimum format/version, autorité wallet, rôle VIEW et identifiant signé du slot.
Le slot OWNER et l'état de contrôle sont OWNER-signed. Pour VIEW, l'état OWNER-signed contient un **descripteur stable** (`enabled` et `slot_id`), figé par le wire V1 de `pre.003`. Lorsque VIEW est activé, le fichier doit contenir exactement un slot VIEW correspondant à ce descripteur. Ses paramètres Argon2id autorisés, son salt et son nonce/ciphertext de wrapping restent rotatables sans OWNER, mais les algorithmes V1, son rôle, son identité et son activation ne le sont pas. Le wrapping VIEW utilise un AAD qui lie au minimum format/version, autorité wallet, rôle VIEW et identifiant signé du slot.
Le wire utilise néanmoins un tableau générique `key_slots` afin qu'un futur `format_version` puisse introduire d'autres rôles sans remodeler toute l'enveloppe.
@@ -461,7 +461,7 @@ Le fichier JSON n'est **jamais** signé comme octets JSON bruts et aucune canoni
### 9.2 Enveloppe conceptuelle
Structure de travail à figer par le codec `pre.003` :
Structure V1 figée par le codec `pre.003` (les longueurs/encodages exacts sont normatifs dans `docs/formats/KSPWALLET_V1.md`) :
```json
{
@@ -474,6 +474,7 @@ Structure de travail à figer par le codec `pre.003` :
},
"key_slots": [
{
"slot_id": "<base64url 16 octets>",
"role": "owner|view",
"kdf": {
"algorithm": "argon2id",
@@ -491,16 +492,19 @@ Structure de travail à figer par le codec `pre.003` :
}
],
"owner_control": {
"control_version": 1,
"algorithm": "xchacha20-poly1305",
"nonce": "<base64url>",
"ciphertext": "<base64url>"
},
"metadata": {
"metadata_version": 1,
"algorithm": "xchacha20-poly1305",
"nonce": "<base64url>",
"ciphertext": "<base64url>"
},
"secret": {
"secret_version": 1,
"algorithm": "xchacha20-poly1305",
"nonce": "<base64url>",
"ciphertext": "<base64url>"
@@ -544,7 +548,7 @@ content keys
password-derived keys
```
La clé publique d'administration révèle un fingerprint aléatoire du **format wallet**, pas l'identité blockchain Solana. Elle constitue la racine de vérification **embarquée** de l'état sous la même autorité OWNER ; sa présence ne crée aucune dépendance à un facteur externe. Le placement et l'encodage exacts de `view_descriptor` restent à figer en `pre.003` ; son invariant est qu'il est OWNER-signed alors que seuls les champs de protection du slot VIEW correspondant sont self-rotatables.
La clé publique d'administration révèle un fingerprint aléatoire du **format wallet**, pas l'identité blockchain Solana. Elle constitue la racine de vérification **embarquée** de l'état sous la même autorité OWNER ; sa présence ne crée aucune dépendance à un facteur externe. `pre.003` fige `view_descriptor` avec `enabled` + `slot_id`: `slot_id` vaut exactement 16 octets Base64url lorsque VIEW est activé et `null` lorsqu'il est désactivé ; le descripteur est OWNER-signed alors que seuls les champs de protection du slot VIEW correspondant sont self-rotatables.
### 9.4 Pubkey et secret payload
@@ -577,7 +581,7 @@ id = 16 octets aléatoires, Base64url sans padding
data = texte UTF-8 protégé
```
L'ID facilite update/delete sans rendre le texte lui-même identifiant. Les bornes restent vérifiables pendant `pre.003`; toute modification avant freeze wire doit être tracée.
L'ID facilite update/delete sans rendre le texte lui-même identifiant. `pre.003` fige ces bornes structurelles V1 ; les payloads plaintext exacts restent implémentés dans les tranches suivantes sans modifier ces plafonds.
### 9.6 Password text contract
@@ -659,7 +663,7 @@ identifiants algo/version pertinents
paramètres publics nécessaires à lier le ciphertext à son contexte
```
Le layout exact du transcript et de chaque AAD devient normatif dans `docs/formats/KSPWALLET_V1.md` et dans les vecteurs déterministes.
`pre.003` fige le layout exact dans `docs/formats/KSPWALLET_V1.md` : domain separator ASCII terminé par `0x00`, puis champs TLV `tag u16 BE || length u64 BE || value`; les `u32` sont encodés sur 4 octets big-endian. Le transcript OWNER inclut le slot OWNER complet et le descripteur VIEW stable mais exclut KDF/salt/wrap VIEW self-service. Les AAD OWNER/VIEW et owner-control/metadata/secret utilisent des domain separators distincts. Les vecteurs déterministes de la tranche verrouillent les octets produits.
## 11. Secret en mémoire
@@ -1193,4 +1197,4 @@ Une future `format_version >= 2` pourra réétudier des facteurs/ancrages extern
## 26. Suite immédiate
`0.2.5-pre.003` est la suite immédiate : codec JSON strict, limites, DTOs denveloppe/key slots, transcript/AAD et première spécification `docs/formats/KSPWALLET_V1.md`. La cryptographie effective KDF/AEAD reste à `pre.004+`.
`0.2.5-pre.003` fige désormais le codec JSON strict, les limites structurelles, `slot_id` 16 octets, le descripteur VIEW, les DTOs denveloppe/key slots, les TLV transcript/AAD et la première spécification `docs/formats/KSPWALLET_V1.md`. La fixture `kspwallet_v1_wire_only.json` est volontairement structurelle et non cryptographiquement valide. La suite immédiate devient `pre.004` : benchmark des defaults Argon2 puis KDF/AEAD/wrapping/CSPRNG effectifs et premiers vecteurs cryptographiques publics.

View File

@@ -1,5 +1,5 @@
<!-- file: docs/rules/FILE_CONTRACTS.md -->
<!-- version: 16 -->
<!-- version: 17 -->
# Contrats des fichiers
@@ -25,18 +25,20 @@ Les règles `FILE-*` définissent la responsabilité et le mode de modification
## Répertoire `docs/`
| Fichier/famille | Responsabilité | Règle de modification |
|-----------------------------------|----------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------|
| `docs/000-README.md` | Indexer et expliquer la documentation tout en restant en tête des listings et arbres de fichiers. | Modifier lorsque l'organisation durable de `docs/` change ; `000-README.md` reste prioritaire lorsqu'un ordre numérique existe. |
| `docs/rules/*.md` | Définir les règles normatives par portée. | Modifier uniquement pour une décision normative ; incrémenter la version du fichier à chaque enregistrement modifiant son contenu. |
| `docs/rules/PROMPT_STRUCTURE.md` | Définir la structure, le cycle de vie et le dimensionnement des prompts/sessions KSP. | Modifier lorsque le contrat des prompts ou les règles de découpage de sessions/prereleases changent. |
| `docs/architecture/000-README.md` | Indexer les documents décrivant l'architecture KSP décidée ou en cours de cadrage explicite. | Modifier lorsque la structure documentaire d'architecture change. |
| `docs/architecture/*.md` | Décrire les objectifs, frontières, responsabilités et architecture courante ou explicitement proposée. | Ne pas utiliser comme journal de livraison ; distinguer clairement les décisions validées des hypothèses encore ouvertes. |
| `docs/plans/000-README.md` | Indexer les plans de versions/phases. | Modifier lorsque l'organisation des plans change. |
| `docs/plans/*.md` | Organiser une version ou phase complexe et, pour `pre.001`, détailler la prévision souple de ses prereleases. | Faire évoluer le plan lorsque la planification change ; prévoir des tranches intermédiaires bornées et redécouper toute tranche estimée trop lourde. |
| `docs/IDEAS.md` | Conserver les idées, pistes, questions et alternatives à explorer qui ne sont pas encore des engagements du roadmap. | Ajouter une idée dès qu'elle mérite d'être conservée ; mettre à jour son statut lorsqu'elle est explorée, retenue, rejetée ou transférée. |
| futurs documents de référence | Définir vocabulaire, identifiants et références canoniques. | Mettre à jour quand la référence canonique évolue. |
| futures validations | Conserver des résultats réellement exécutés. | Ne jamais enregistrer une validation supposée comme réussie. |
| Fichier/famille | Responsabilité | Règle de modification |
|-----------------------------------|-------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `docs/000-README.md` | Indexer et expliquer la documentation tout en restant en tête des listings et arbres de fichiers. | Modifier lorsque l'organisation durable de `docs/` change ; `000-README.md` reste prioritaire lorsqu'un ordre numérique existe. |
| `docs/formats/000-README.md` | Indexer les spécifications de formats durables KSP destinées à l'interopérabilité externe. | Modifier lorsqu'un format durable entre/sort de cette famille ou que son statut change ; conserver `000-README.md` comme point d'entrée. |
| `docs/formats/*.md` | Spécifier un wire KSP durable indépendamment de son implémentation, avec encodages, limites, parsing, auth et vecteurs. | Modifier avec traçabilité lorsqu'un contrat de format évolue ; après publication stable d'une version de format, toute incompatibilité de wire ouvre une nouvelle version de format plutôt qu'une tolérance silencieuse. |
| `docs/rules/*.md` | Définir les règles normatives par portée. | Modifier uniquement pour une décision normative ; incrémenter la version du fichier à chaque enregistrement modifiant son contenu. |
| `docs/rules/PROMPT_STRUCTURE.md` | Définir la structure, le cycle de vie et le dimensionnement des prompts/sessions KSP. | Modifier lorsque le contrat des prompts ou les règles de découpage de sessions/prereleases changent. |
| `docs/architecture/000-README.md` | Indexer les documents décrivant l'architecture KSP décidée ou en cours de cadrage explicite. | Modifier lorsque la structure documentaire d'architecture change. |
| `docs/architecture/*.md` | Décrire les objectifs, frontières, responsabilités et architecture courante ou explicitement proposée. | Ne pas utiliser comme journal de livraison ; distinguer clairement les décisions validées des hypothèses encore ouvertes. |
| `docs/plans/000-README.md` | Indexer les plans de versions/phases. | Modifier lorsque l'organisation des plans change. |
| `docs/plans/*.md` | Organiser une version ou phase complexe et, pour `pre.001`, détailler la prévision souple de ses prereleases. | Faire évoluer le plan lorsque la planification change ; prévoir des tranches intermédiaires bornées et redécouper toute tranche estimée trop lourde. |
| `docs/IDEAS.md` | Conserver les idées, pistes, questions et alternatives à explorer qui ne sont pas encore des engagements du roadmap. | Ajouter une idée dès qu'elle mérite d'être conservée ; mettre à jour son statut lorsqu'elle est explorée, retenue, rejetée ou transférée. |
| futurs documents de référence | Définir vocabulaire, identifiants et références canoniques. | Mettre à jour quand la référence canonique évolue. |
| futures validations | Conserver des résultats réellement exécutés. | Ne jamais enregistrer une validation supposée comme réussie. |
## Répertoire `config/`