# Spécification du Système d'Identité et de Processus 4NK **Version:** 1.0 **Date:** 1 octobre 2025 **Auteur:** Analyse complète des composants sdk_client, sdk_common, sdk_relay, sdk_storage, ihm_client, rust-silentPayments ## Table des matières 1. [Vue d'ensemble](#vue-densemble) 2. [Architecture d'identité](#architecture-didentité) 3. [Système de processus](#système-de-processus) 4. [Validation et consensus](#validation-et-consensus) 5. [Communication réseau](#communication-réseau) 6. [Stockage et persistance](#stockage-et-persistance) 7. [Flux de données](#flux-de-données) 8. [Sécurité](#sécurité) --- ## 1. Vue d'ensemble ### 1.1 Philosophie du système 4NK est un système décentralisé de gestion de processus collaboratifs basé sur la blockchain Bitcoin, utilisant les **Silent Payments (BIP352)** pour l'identité et le chiffrement. Le système permet à plusieurs parties de collaborer sur des processus avec des états vérifiables, des rôles définis et des règles de validation cryptographiques. ### 1.2 Principes fondamentaux - **Identité décentralisée** : Basée sur des adresses Silent Payment Bitcoin - **Device-centric** : Chaque appareil possède sa propre clé cryptographique - **Multi-device** : Un utilisateur peut gérer plusieurs appareils via le pairing - **Processus à états** : Évolution contrôlée par des commitments Bitcoin - **Validation distribuée** : Signatures cryptographiques multiples requises - **Communication P2P** : Relais WebSocket pour synchronisation temps réel ### 1.3 Composants principaux | Composant | Rôle | Technologie | |-----------|------|-------------| | `sdk_common` | Types et structures partagés | Rust (WASM-ready) | | `sdk_client` | Bibliothèque cliente WASM | Rust → WebAssembly | | `sdk_relay` | Relais de messages et synchronisation | Rust + WebSocket | | `sdk_storage` | Stockage clé-valeur distribué | Rust + HTTP | | `ihm_client` | Interface utilisateur web | TypeScript + Web Components | | `rust-silentPayments` | Implémentation Silent Payments | Rust (dépendance) | --- ## 2. Architecture d'identité ### 2.1 Hiérarchie d'identité ``` Device ├─ SpClient (Silent Payment Client) │ ├─ Scan Key (privée) │ ├─ Spend Key (privée) │ └─ Silent Payment Address (publique) ├─ SpWallet (outputs UTXO) ├─ Pairing Process (OutPoint) └─ Member (liste d'adresses pairées) ``` ### 2.2 Structure `Device` **Fichier source:** `sdk_common/src/device.rs` ```rust pub struct Device { sp_wallet: SpWallet, // Portefeuille Silent Payments pairing_process_commitment: Option, // ID du processus de pairing paired_member: Member, // Groupe d'adresses pairées } ``` **Opérations principales:** 1. **Création** : `Device::new(sp_client)` - Génère une adresse Silent Payment locale - Initialise un `Member` avec cette adresse seule 2. **Pairing** : `device.pair(commitment_outpoint, member)` - Associe le device à un processus de pairing - Lie plusieurs adresses Silent Payment ensemble 3. **Unpairing** : `device.unpair()` - Réinitialise à l'état local unique ### 2.3 Structure `Member` **Fichier source:** `sdk_common/src/pcd.rs` (lignes 140-223) ```rust pub struct Member { sp_addresses: Vec, // Liste d'adresses Silent Payment } ``` **Caractéristiques:** - Représente un ensemble d'appareils appartenant à une même entité - Utilisé pour les validations multi-signatures - Comparaison indépendante de l'ordre (HashSet interne) - Sérialisation déterministe (tri automatique) **Méthodes clés:** ```rust pub fn new(sp_addresses: Vec) -> Self pub fn get_addresses(&self) -> Vec pub fn key_is_part_of_member(&self, key: &PublicKey) -> bool pub fn get_address_for_key(&self, key: &PublicKey) -> Option ``` ### 2.4 Processus de pairing Le **pairing** est le mécanisme permettant d'associer plusieurs appareils (devices) à une seule identité logique (member). #### Étapes du pairing: 1. **Création du processus de pairing** - Un device crée un nouveau `Process` avec un rôle spécial `"pairing"` - Le `ProcessState` contient un champ public `"pairedAddresses"` avec la liste des adresses 2. **Validation du pairing** - Fichier: `sdk_common/src/process.rs` (lignes 161-200) - Règle: `members` doit être vide (pas de membres préexistants) - Une seule règle de validation pour le champ `"pairedAddresses"` - Signatures requises: - **Création** : Signature de la nouvelle adresse seule - **Ajout** : Signature des adresses déjà pairées - **Retrait** : Signatures de tous les devices (consensus) 3. **État après pairing** ```rust device.pairing_process_commitment = Some(process_id); device.paired_member = Member::new(all_paired_addresses); ``` **Code de validation (extrait):** ```rust fn handle_pairing( &self, pairing_role: RoleDefinition, previous_addresses: Vec, ) -> anyhow::Result<()> { // members must be empty if !pairing_role.members.is_empty() { return Err(anyhow::Error::msg("Invalid pairing role")); } let updated_addresses_json = self.public_data.get_as_json(PAIREDADDRESSES)?; let updated_member = Member::new(updated_addresses_json); let previous_member = Member::new(previous_addresses); let members = if previous_member.get_addresses().is_empty() { vec![&updated_member] // Création } else { vec![&previous_member] // Modification }; // Validation des signatures pairing_rule.is_satisfied(PAIREDADDRESSES, state_id, validation_tokens, members) } ``` ### 2.5 Identité dans le réseau Chaque participant au réseau 4NK est identifié par: 1. **Adresse Silent Payment** : Identité publique cryptographique 2. **Process ID (OutPoint)** : Identifiant du processus de pairing (si multi-device) 3. **Member** : Groupe d'adresses associées **Carte d'identité réseau:** ```rust // Fichier: sdk_common/src/serialization.rs pub struct OutPointMemberMap(pub HashMap); ``` Cette structure permet au réseau de: - Résoudre un `process_id` vers un groupe d'adresses - Vérifier qu'une signature provient d'un membre légitime - Gérer les membres multi-appareils de façon transparente --- ## 3. Système de processus ### 3.1 Modèle de processus Un **Process** est une machine à états distribuée, commitée sur la blockchain Bitcoin. ``` Process └─ states: Vec ├─ State 0 (initial empty) ├─ State 1 (premier commit) ├─ State 2 (update) ├─ ... └─ State n (dernier = toujours empty) ``` **Règle fondamentale:** Le dernier état est toujours vide, représentant le prochain UTXO à dépenser. ### 3.2 Structure `ProcessState` **Fichier source:** `sdk_common/src/process.rs` (lignes 19-35) ```rust pub struct ProcessState { pub commited_in: OutPoint, // UTXO Bitcoin portant cet état pub pcd_commitment: PcdCommitments, // Map field -> hash(value) pub state_id: [u8; 32], // Merkle root (identifiant unique) pub keys: BTreeMap, // Clés de déchiffrement (optionnel) pub validation_tokens: Vec, // Signatures de validation pub public_data: Pcd, // Données publiques (non hashées) pub roles: Roles, // Définition des rôles } ``` #### Éléments clés: 1. **`commited_in`** : UTXO Bitcoin qui "porte" cet état - Permet de lier l'état à la blockchain - Forme l'identifiant du processus (premier `commited_in`) 2. **`pcd_commitment`** : Commitments Merkle des données privées - Map `field_name -> hash(compressed_value)` - Hash taggé: `AnkPcdHash::from_pcd_value(data, field, outpoint)` 3. **`state_id`** : Racine Merkle de tous les commitments + rôles - Identifiant unique de l'état - Utilisé pour les signatures de validation 4. **`validation_tokens`** : Signatures cryptographiques - Prouvent l'approbation des membres - Type: `Proof` (signature Schnorr sur `state_id`) 5. **`public_data`** : Données non chiffrées - Lisibles par tous les participants - Exemple: `"pairedAddresses"` pour le pairing 6. **`roles`** : Définition des rôles et permissions - Map `role_name -> RoleDefinition` - Contrôle qui peut modifier quels champs ### 3.3 Cycle de vie d'un processus ``` ┌─────────────────┐ │ 1. Création │ │ Process::new() │ │ État initial │ │ vide │ └────────┬────────┘ │ v ┌──────────────────────┐ │ 2. Proposition │ │ insert_concurrent │ │ _state() │ │ + validation_tokens │ └────────┬─────────────┘ │ v ┌─────────────────────────┐ │ 3. Validation │ │ ProcessState::is_valid()│ │ Vérif. signatures │ └────────┬────────────────┘ │ v ┌──────────────────────────┐ │ 4. Commit blockchain │ │ Transaction avec │ │ OP_RETURN (state_id) │ └────────┬─────────────────┘ │ v ┌──────────────────────────┐ │ 5. Confirmation │ │ update_states_tip() │ │ Nouvel UTXO │ └────────┬─────────────────┘ │ v (retour étape 2) ``` ### 3.4 États concurrents Le système gère la **concurrence** via des états multiples pour un même `commited_in`: ``` Process { states: [ State(outpoint_0, state_id_A), // Commité State(outpoint_1, state_id_B), // Concurrent 1 State(outpoint_1, state_id_C), // Concurrent 2 State(outpoint_1, [0u8; 32]), // Empty (tip) ] } ``` - Plusieurs propositions peuvent coexister - Une seule sera commitée on-chain - Les autres sont prunées après confirmation **Méthodes de gestion:** ```rust fn get_latest_concurrent_states(&self) -> Vec<&ProcessState> fn remove_all_concurrent_states(&mut self) -> Vec ``` ### 3.5 Types de processus spéciaux #### 3.5.1 Processus de pairing - **Rôle:** `"pairing"` - **Champ public:** `"pairedAddresses"` - **Règle:** Membres vides, validation par adresses existantes #### 3.5.2 Oblitération (Termination) - **État:** `state_id = [0u8; 32]` - **Rôle:** `"apophis"` (défini dans l'état précédent) - **Effet:** Termine définitivement le processus - **Fichier:** `sdk_common/src/process.rs` (lignes 133-159) ```rust fn handle_obliteration(&self, apophis: &RoleDefinition, members_list: &OutPointMemberMap) -> Result<()> { // Vérifie que le rôle "apophis" approuve l'oblitération let empty_field = ""; apophis.is_satisfied( vec![empty_field.to_owned()], [0u8; 32], &self.validation_tokens, members_list, ) } ``` #### 3.5.3 Rôle "Demiurge" - **Contexte:** État initial uniquement - **Pouvoir:** Créer tous les champs initiaux - **Règle auto-générée:** ```rust ValidationRule::new(1.0, all_keys, 1.0) ``` - **Fichier:** `sdk_common/src/process.rs` (lignes 103-130) --- ## 4. Validation et consensus ### 4.1 Architecture de validation La validation dans 4NK repose sur un système de **rôles**, **règles** et **preuves cryptographiques**. ``` Validation Flow: ProcessState └─> roles: Roles └─> RoleDefinition ├─> members: Vec ├─> validation_rules: Vec └─> storages: Vec ``` ### 4.2 Structure `RoleDefinition` **Fichier source:** `sdk_common/src/pcd.rs` (lignes 564-610) ```rust pub struct RoleDefinition { pub members: Vec, // Process IDs des membres pub validation_rules: Vec, // Règles de modification pub storages: Vec, // Storages autorisés } ``` **Caractéristiques:** - **members** : Utilise des `OutPoint` (process IDs) plutôt que des adresses - Permet d'ajouter des devices sans modifier les rôles - Résolu via `OutPointMemberMap` au moment de la validation - **validation_rules** : Définit quels champs peuvent être modifiés - Quorum requis - Signatures minimales par membre - **storages** : Liste des storages où les données peuvent être déposées ### 4.3 Structure `ValidationRule` **Fichier source:** `sdk_common/src/pcd.rs` (lignes 429-562) ```rust pub struct ValidationRule { quorum: f32, // 0.0 à 1.0 (proportion de membres requis) fields: Vec, // Champs concernés par cette règle min_sig_member: f32, // 0.0 à 1.0 (proportion de devices par membre) } ``` **Exemple concret:** ```rust // Règle : 50% des membres, chacun avec au moins 1 device ValidationRule { quorum: 0.5, fields: vec!["contract".to_string(), "amount".to_string()], min_sig_member: 0.5, } ``` **Interprétation:** - 50% des membres du rôle doivent approuver - Chaque membre approuvant doit fournir au moins 50% de ses devices - S'applique aux modifications de `"contract"` et `"amount"` ### 4.4 Processus de validation **Fichier source:** `sdk_common/src/process.rs` (lignes 202-321) #### Étapes de validation: ```rust pub fn is_valid( &self, previous_state: Option<&ProcessState>, members_list: &OutPointMemberMap, ) -> anyhow::Result<()> ``` 1. **Vérification de base** - `validation_tokens` non vide 2. **Cas spéciaux** (prioritaires): - **Oblitération** : `state_id == [0u8; 32]` - **Pairing** : Rôle `"pairing"` présent 3. **Gestion du Demiurge** (état initial uniquement): ```rust if previous_state.is_none() { if let Some(demiurge) = roles.get("demiurge") { // Génère une règle couvrant tous les champs } } ``` 4. **Validation par champ**: Pour chaque champ modifié: - Trouver les rôles applicables - Vérifier qu'au moins un rôle valide le champ - Vérifier les signatures cryptographiques **Algorithme de validation:** ```rust let all_fields_validated: bool = self.pcd_commitment.keys().all(|field| { let applicable_roles = roles.filter(|role| role.has_rule_for(field)); applicable_roles.into_iter().any(|(role_name, role_def)| { role_def.validation_rules.iter().any(|rule| { let members = role_def.members .filter_map(|outpoint| members_list.get(outpoint)) .collect(); rule.is_satisfied(field, state_id, validation_tokens, members).is_ok() }) }) }); ``` ### 4.5 Validation d'une règle **Fichier source:** `sdk_common/src/pcd.rs` (lignes 466-562) ```rust pub fn is_satisfied( &self, field: &str, merkle_root: [u8; 32], proofs: &[Proof], members: &[&Member], ) -> Result<()> ``` #### Algorithme: 1. **Calcul du quorum**: ```rust let required_members = (members.len() as f32 * self.quorum).ceil() as usize; ``` 2. **Filtrage des membres validants**: ```rust let validating_members = members.iter().filter(|member| { let member_proofs = proofs.iter() .filter(|p| member.key_is_part_of_member(&p.get_key())) .collect(); self.satisfy_min_sig_member(member, merkle_root, member_proofs).is_ok() }).count(); ``` 3. **Vérification du quorum**: ```rust validating_members >= required_members ``` ### 4.6 Signatures cryptographiques #### Structure `Proof` ```rust pub struct Proof { signature: SchnorrSignature, public_key: PublicKey, message: [u8; 32], } ``` **Types de messages signés:** ```rust pub enum AnkHash { ValidationYes(AnkValidationYesHash), ValidationNo(AnkValidationNoHash), } ``` - **ValidationYes** : Approbation du `state_id` - **ValidationNo** : Rejet du `state_id` **Création d'une signature:** ```rust let message_hash = state.get_message_hash(true)?; // true = yes let proof = Proof::new(message_hash, spend_key); state.validation_tokens.push(proof); ``` **Vérification:** ```rust fn satisfy_min_sig_member(&self, member: &Member, merkle_root: [u8; 32], proofs: &[&Proof]) -> Result<()> { let required_sigs = (member.addresses().len() as f32 * self.min_sig_member).ceil(); let yes_votes = proofs.iter() .filter(|p| p.verify().is_ok()) .filter(|p| p.get_message() == AnkValidationYesHash::from_merkle_root(merkle_root)) .count(); if yes_votes >= required_sigs { Ok(()) } else { Err("Not enough yes votes") } } ``` ### 4.7 Scénarios de validation #### Scénario 1: Création de processus (2 membres, quorum 100%) ```rust // Membres let alice_bob = Member::new(vec![alice_addr, bob_addr]); let carol = Member::new(vec![carol_addr]); // Rôle let role = RoleDefinition { members: vec![alice_bob_pairing_id, carol_pairing_id], validation_rules: vec![ ValidationRule::new(1.0, vec!["field1"], 0.5) // quorum 100%, 50% devices ], }; // Validation // Alice signe seule (50% de alice_bob) -> ❌ Insuffisant (1/2 membres) // Alice + Carol signent -> ✅ Valide (2/2 membres, quorum atteint) ``` #### Scénario 2: Update avec plusieurs rôles ```rust // Rôle 1: Owner (peut modifier "roles") let owner = RoleDefinition { members: vec![alice_pairing_id], validation_rules: vec![ ValidationRule::new(1.0, vec!["roles"], 1.0) ], }; // Rôle 2: Validator (peut modifier "idCertified", "roles") let validator = RoleDefinition { members: vec![bob_pairing_id], validation_rules: vec![ ValidationRule::new(0.5, vec!["idCertified", "roles"], 1.0) ], }; // Modification de "roles" -> Peut être validé par owner OU validator ``` --- ## 5. Communication réseau ### 5.1 Architecture réseau ``` ┌─────────────┐ WebSocket ┌─────────────┐ │ ihm_client │◄────────────────────────────►│ sdk_relay │ │ (WASM) │ │ (Rust) │ └─────────────┘ └──────┬──────┘ │ ┌───────┴──────┐ │ │ Bitcoin RPC ZMQ Events Blindbit API (rawtx, hashblock) ``` ### 5.2 Protocole WebSocket **Fichier source:** `sdk_common/src/network.rs` #### Types de messages (`AnkFlag`): ```rust pub enum AnkFlag { Handshake, // Synchronisation initiale NewTx, // Nouvelle transaction détectée Cipher, // Données chiffrées Commit, // Demande de commit on-chain Faucet, // Demande de fonds (testnet) Sync, // Synchronisation d'état } ``` #### Structure d'enveloppe: ```rust pub struct Envelope { pub flag: AnkFlag, pub content: String, // JSON sérialisé } ``` ### 5.3 Message types #### 5.3.1 HandshakeMessage **Envoyé par:** sdk_relay → client (à la connexion) ```rust pub struct HandshakeMessage { pub sp_address: String, // Adresse du relay pub peers_list: OutPointMemberMap, // Carte des membres pub processes_list: OutPointProcessMap, // Processus connus pub chain_tip: u32, // Hauteur de bloc } ``` **Objectif:** Synchroniser l'état initial du réseau #### 5.3.2 NewTxMessage **Envoyé par:** sdk_relay → clients (transaction détectée) ```rust pub struct NewTxMessage { pub transaction: String, // Transaction hex pub tweak_data: Option, // Données de tweak Silent Payment pub error: Option, } ``` **Objectif:** Notifier une nouvelle transaction Bitcoin concernant les participants #### 5.3.3 CommitMessage **Envoyé par:** client → sdk_relay (demande de commit) ```rust pub struct CommitMessage { pub process_id: OutPoint, pub pcd_commitment: PcdCommitments, pub roles: Roles, pub public_data: Pcd, pub validation_tokens: Vec, pub error: Option, } ``` **Flux de commit:** 1. **Client** : Envoie `CommitMessage` avec `validation_tokens = []` - Annonce l'intention de commit 2. **Relay** : Diffuse aux autres clients 3. **Autres clients** : Signent et renvoient leurs `validation_tokens` 4. **Client initiateur** : Accumule les signatures, renvoie `CommitMessage` complet 5. **Relay** : Vérifie les signatures, crée la transaction Bitcoin, broadcast ### 5.4 Gestion des connexions **Fichier source:** `sdk_relay/src/main.rs` (lignes 178-242) ```rust async fn handle_connection( raw_stream: TcpStream, addr: SocketAddr, our_sp_address: SilentPaymentAddress, ) { let ws_stream = tokio_tungstenite::accept_async(raw_stream).await?; // Insertion dans la peer map let (tx, rx) = unbounded_channel(); PEERMAP.lock().insert(addr, tx); // Envoi du handshake let init_msg = HandshakeMessage::new( our_sp_address, members_list, processes_list, chain_tip, ); broadcast_message(AnkFlag::Handshake, init_msg, BroadcastType::Sender(addr)); // Gestion des messages let (outgoing, incoming) = ws_stream.split(); incoming.try_for_each(|msg| { process_message(msg.to_text(), addr); future::ok(()) }); } ``` **Types de broadcast:** ```rust pub enum BroadcastType { All, // Tous les peers Sender(SocketAddr), // Peer spécifique Exclude(SocketAddr), // Tous sauf un } ``` ### 5.5 Synchronisation blockchain **Fichier source:** `sdk_relay/src/sync.rs` Le relay écoute les événements Bitcoin via: 1. **ZMQ** : - `rawtx` : Transactions dans le mempool - `hashblock` : Nouveaux blocs minés 2. **Bitcoin RPC** : - Récupération des blocs complets - Vérification des confirmations **Détection de transactions pertinentes:** ```rust pub fn check_tx_for_process_updates(tx: &Transaction) -> Result { let processes = lock_processes()?; for (process_id, process) in processes.iter() { let process_tip = process.get_process_tip()?; // Vérifie si la tx dépense le tip if tx.input.iter().any(|input| input.previous_output == process_tip) { // Extrait le state_id de l'OP_RETURN let op_return = tx.output.iter() .find(|o| o.script_pubkey.is_op_return())?; let state_id = &op_return.script_pubkey.as_bytes()[2..34]; // Met à jour le processus process.commit_state(state_id)?; return Ok(*process_id); } } Err("No matching process") } ``` --- ## 6. Stockage et persistance ### 6.1 Architecture de stockage ``` ┌────────────────────────────────────────────────┐ │ Couche Application │ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │ │ Process │ │ Member │ │ Device │ │ │ │ State │ │ Registry │ │ Wallet │ │ │ └──────────┘ └──────────┘ └──────────┘ │ └────────────────────┬───────────────────────────┘ │ ┌────────────────────▼───────────────────────────┐ │ Couche de Données │ │ ┌─────────────┐ ┌─────────────┐ │ │ │ sdk_storage │ │ Blockchain │ │ │ │ (Key-Value) │ │ Bitcoin │ │ │ └─────────────┘ └─────────────┘ │ └────────────────────────────────────────────────┘ ``` ### 6.2 sdk_storage : Stockage clé-valeur **Fichier source:** `sdk_storage/src/main.rs` #### Architecture: - **Type:** Serveur HTTP REST - **Stockage:** Fichiers dans `~/.4nk/storage/` - **TTL:** Optionnel (expiration automatique) #### API: ```http POST /store { "key": "hex64", # Clé 32 bytes en hex "value": "hex", # Valeur en hex "ttl": 3600 # Optional: secondes } GET /retrieve/:key → { "value": "hex" } ``` #### Utilisation dans 4NK: ```rust // RoleDefinition indique les storages autorisés pub struct RoleDefinition { pub storages: Vec, // URLs des sdk_storage } ``` **Cas d'usage:** 1. **Données chiffrées volumineuses** : Documents, images 2. **Partage de clés** : Clés de déchiffrement AES 3. **Coordination** : États temporaires avant commit ### 6.3 Données sur blockchain **Seules les données commitées on-chain:** ```rust // Transaction Bitcoin TxOut { value: Amount::ZERO, script_pubkey: ScriptBuf::new_op_return(&state_id), // 32 bytes } ``` - **state_id** : Merkle root identifiant l'état - **Pas de données brutes** sur la blockchain - **Récupération** : Via sdk_storage ou pairs ### 6.4 Structure des données (PCD) **Fichier source:** `sdk_common/src/pcd.rs` (lignes 225-333) #### PCD (Private Collaborative Data) ```rust pub struct Pcd(BTreeMap>); ``` **Format de sérialisation:** ``` ┌─────────────────────────┐ │ Version (1 byte): 0x01 │ ├─────────────────────────┤ │ DataType (1 byte): │ │ 0 = FileBlob │ │ 1 = JSON │ ├─────────────────────────┤ │ Compressed data (zstd) │ └─────────────────────────┘ ``` **Exemple d'utilisation:** ```rust // Insertion let mut pcd = Pcd::new(BTreeMap::new()); let value = json!({ "name": "Alice", "age": 30 }); pcd.insert_serializable("profile".to_string(), &value)?; // Récupération let profile: Value = pcd.get_as_json("profile")?; ``` #### PcdCommitments ```rust pub struct PcdCommitments(BTreeMap); ``` **Génération des commitments:** ```rust pub fn new(commited_in: &OutPoint, attributes: &Pcd, roles: &Roles) -> Result { let mut field2hash = BTreeMap::new(); for (field, value) in attributes.iter() { let hash = AnkPcdHash::from_pcd_value(value, field.as_bytes(), commited_in); field2hash.insert(field, hash.to_byte_array()); } // Ajout du hash des rôles let roles_hash = AnkPcdHash::from_pcd_value(roles.to_bytes()?, b"roles", commited_in); field2hash.insert("roles".to_string(), roles_hash); Ok(Self(field2hash)) } ``` **Propriétés:** - **Déterministe** : BTreeMap garantit l'ordre - **Merkle Tree** : Racine utilisée comme `state_id` - **Prouvable** : Chemin Merkle pour prouver un champ ### 6.5 Chiffrement des données **Algorithme:** AES-256-GCM ```rust use sdk_common::crypto::{Aes256Gcm, KeyInit, AeadCore}; // Génération de clé let key = Aes256Gcm::generate_key(&mut rng); // Chiffrement let cipher = Aes256Gcm::new(&key); let nonce = Aes256Gcm::generate_nonce(&mut rng); let ciphertext = cipher.encrypt(&nonce, plaintext.as_ref())?; // Stockage de la clé dans ProcessState.keys state.keys.insert(field_name, key.as_slice().try_into()?); ``` **Distribution des clés:** 1. **Option 1:** Via `sdk_storage` (URL dans `RoleDefinition.storages`) 2. **Option 2:** Chiffrement asymétrique avec clés publiques Silent Payment 3. **Option 3:** Partage hors-bande --- ## 7. Flux de données ### 7.1 Flux de création de processus ``` ┌─────────────┐ │ Client A │ └──────┬──────┘ │ 1. Génère ProcessState initial │ ├─ private_data (chiffré) │ ├─ public_data │ └─ roles ▼ ┌──────────────────────┐ │ Génération state_id │ │ (Merkle root) │ └──────┬───────────────┘ │ 2. Signature avec spend_key │ proof = sign(state_id) ▼ ┌─────────────────────────┐ │ Envoi CommitMessage │ │ → sdk_relay (WebSocket) │ └──────┬──────────────────┘ │ 3. Broadcast aux autres clients ▼ ┌──────────────┐ ┌──────────────┐ │ Client B │ │ Client C │ └──────┬───────┘ └──────┬───────┘ │ 4. Validation │ │ is_valid()? │ │ 5. Signature │ │ proof = sign() │ ▼ ▼ ┌──────────────────────────────────┐ │ Accumulation des signatures │ │ dans CommitMessage │ └──────┬───────────────────────────┘ │ 6. Renvoi à sdk_relay (complet) ▼ ┌────────────────────────────────┐ │ sdk_relay vérifie quorum │ │ ├─ is_valid() │ │ └─ Toutes signatures valides │ └──────┬─────────────────────────┘ │ 7. Création transaction Bitcoin │ ├─ Input: fonds du relay │ ├─ Output 0: UTXO process (546 sats) │ └─ Output 1: OP_RETURN (state_id) ▼ ┌──────────────────────┐ │ Broadcast Bitcoin │ └──────┬───────────────┘ │ 8. Confirmation ▼ ┌──────────────────────────┐ │ ZMQ event (rawtx) │ │ → Tous les clients │ │ → Mise à jour Process │ └──────────────────────────┘ ``` ### 7.2 Flux de mise à jour ``` ┌─────────────┐ │ Client A │ └──────┬──────┘ │ 1. Récupère l'état actuel │ current = process.get_latest_committed_state() ▼ ┌────────────────────────┐ │ Modification de champs │ │ ├─ update_value(key) │ │ └─ Nouveau state_id │ └──────┬─────────────────┘ │ 2. Vérification des permissions │ can_modify = roles.check(member_id, field) ▼ ┌─────────────────────────┐ │ Proposition d'état │ │ insert_concurrent_state │ └──────┬──────────────────┘ │ 3. Collecte des signatures │ (même flux que création) ▼ ┌──────────────────────────┐ │ Commit on-chain │ │ ├─ Dépense ancien UTXO │ │ └─ Crée nouveau UTXO │ └──────┬───────────────────┘ │ 4. Confirmation ▼ ┌──────────────────────────┐ │ Mise à jour réseau │ │ update_states_tip() │ │ Pruning états concurrents│ └──────────────────────────┘ ``` ### 7.3 Flux de pairing multi-device ``` Device 1 (Desktop) Device 2 (Mobile) sdk_relay ────────────────── ───────────────── ───────── │ │ │ │ 1. Création pairing │ │ │ create_pairing_process() │ │ │────────────────────────────────────────────────────►│ │ │ │ │ 2. Broadcast HandshakeMsg │ │ │◄────────────────────────────────────────────────────│ │ │◄───────────────────────│ │ │ │ │ 3. Affichage QR Code │ │ │ (pairing_id + addresses) │ │ │ │ │ │ │ 4. Scan QR Code │ │ │ get_pairing_info() │ │ │ │ │ │ 5. Demande d'ajout │ │ │ pair_device(pairing_id)│ │ │───────────────────────►│ │ │ │ │ 6. Notification nouvelle │ │ │ adresse (CommitMessage) │ │ │◄────────────────────────────────────────────────────│ │ │ │ │ 7. Validation (signature) │ │ │ approve_pairing() │ │ │────────────────────────────────────────────────────►│ │ │ │ │ 8. Commit on-chain │ │ │ (nouveau state pairedAddr.) │ │ │◄────────────────────────────────────────────────────│ │ │◄───────────────────────│ │ │ │ │ 9. Confirmation │ 9. Confirmation │ │ device.pair() │ device.pair() │ │ │ │ ``` ### 7.4 Flux de synchronisation Silent Payments ``` ┌──────────────┐ │ Bitcoin Node │ │ (ZMQ) │ └──────┬───────┘ │ rawtx / hashblock ▼ ┌─────────────────────┐ │ sdk_relay │ │ ┌─────────────────┐ │ │ │ Blindbit Filter │ │ ← Filtres BIP158 compacts │ └────────┬────────┘ │ │ │ │ │ ┌────────▼────────┐ │ │ │ Match Detection │ │ │ └────────┬────────┘ │ └──────────┼──────────┘ │ NewTxMessage (si match) ▼ ┌────────────────────────┐ │ Clients │ │ ┌────────────────────┐ │ │ │ Silent Payment │ │ │ │ Scanner │ │ │ └────────┬───────────┘ │ │ │ │ │ ┌────────▼───────────┐ │ │ │ ECDH + Derivation │ │ │ │ calculate_ecdh() │ │ │ └────────┬───────────┘ │ │ │ │ │ ┌────────▼───────────┐ │ │ │ Output Detection │ │ │ │ OwnedOutput │ │ │ └────────┬───────────┘ │ └──────────┼─────────────┘ │ ▼ ┌──────────────┐ │ Device Wallet│ │ update_outputs│ └──────────────┘ ``` **Détails du scanning:** ```rust // Fichier: sdk_common/src/device.rs (lignes 65-151) pub fn update_outputs_with_transaction( &mut self, tx: &Transaction, blockheight: u32, partial_tweak: PublicKey, ) -> Result> { // 1. Calcul du shared secret let shared_secret = calculate_ecdh_shared_secret( &partial_tweak, &self.sp_wallet.get_sp_client().get_scan_key(), ); // 2. Extraction des clés publiques P2TR let mut pubkeys_to_check: HashMap = HashMap::new(); for (vout, output) in tx.output.iter().enumerate() { if output.script_pubkey.is_p2tr() { let xonly = XOnlyPublicKey::from_slice(&output.script_pubkey.as_bytes()[2..])?; pubkeys_to_check.insert(xonly, vout as u32); } } // 3. Scanning avec sp_receiver let ours = self.sp_wallet.get_sp_client().sp_receiver .scan_transaction(&shared_secret, pubkeys_to_check.keys().cloned().collect())?; // 4. Création des OwnedOutput let mut new_outputs = HashMap::new(); for (label, map) in ours.iter() { for (key, scalar) in map { let vout = pubkeys_to_check.get(&key).unwrap(); let outpoint = OutPoint::new(tx.txid(), *vout); let owned = OwnedOutput { blockheight: Height::from_consensus(blockheight)?, tweak: scalar.to_be_bytes(), amount: tx.output[*vout as usize].value, script: tx.output[*vout as usize].script_pubkey.to_bytes().try_into()?, label: label.clone(), spend_status: OutputSpendStatus::Unspent, }; new_outputs.insert(outpoint, owned); } } // 5. Mise à jour du wallet self.sp_wallet.get_mut_outputs().extend(new_outputs.clone()); // 6. Détection des dépenses for input in tx.input.iter() { if let Some(prevout) = self.sp_wallet.get_mut_outputs().get_mut(&input.previous_output) { prevout.spend_status = OutputSpendStatus::Spent(*tx.txid().as_byte_array()); } } Ok(new_outputs) } ``` --- ## 8. Sécurité ### 8.1 Modèle de menaces #### Menaces couvertes: 1. **Usurpation d'identité** : ✅ Signatures Schnorr obligatoires 2. **Modification non autorisée** : ✅ Validation multi-signatures 3. **Replay attacks** : ✅ state_id unique (Merkle root) 4. **Man-in-the-middle** : ✅ Messages signés cryptographiquement 5. **Observation réseau** : ✅ Données chiffrées (AES-256-GCM) 6. **Perte de clés** : ✅ Multi-device pairing #### Menaces non couvertes: 1. **Compromission du device** : ❌ Clés stockées localement 2. **Collusion des membres** : ⚠️ Dépend du quorum configuré 3. **Attaque 51% Bitcoin** : ❌ Dépendance à la sécurité Bitcoin 4. **DoS sur sdk_relay** : ⚠️ Rate limiting à implémenter ### 8.2 Primitives cryptographiques #### Courbes elliptiques: - **secp256k1** : Courbe Bitcoin standard - **Schnorr signatures** : BIP340 #### Hachage: - **SHA-256** : Hash principal - **Tagged hashes** : BIP340 style ```rust AnkPcdHash::from_pcd_value(data, tag, outpoint) ``` #### Chiffrement symétrique: - **AES-256-GCM** : AEAD (Authenticated Encryption with Associated Data) - **Nonce** : 96 bits aléatoires - **Key derivation** : Potentiellement HKDF (à vérifier) #### Signatures: ```rust pub struct Proof { // Signature Schnorr (64 bytes) signature: [u8; 64], // Clé publique (33 bytes compressed) public_key: PublicKey, // Message (32 bytes) message: [u8; 32], } ``` **Vérification:** ```rust impl Proof { pub fn verify(&self) -> Result<()> { let secp = Secp256k1::verification_only(); let message = Message::from_slice(&self.message)?; secp.verify_schnorr(&self.signature, &message, &self.public_key.x_only_public_key().0)?; Ok(()) } } ``` ### 8.3 Isolation des données #### Niveaux de visibilité: 1. **Privé (PCD)** : - Données chiffrées - Seul le commitment on-chain - Clés distribuées aux membres autorisés 2. **Public (public_data)** : - Lisibles par tous les participants réseau - Exemple: `"pairedAddresses"` 3. **On-chain** : - Uniquement `state_id` (32 bytes) - Aucune donnée sensible #### Gestion des clés: ```rust // Stockage dans ProcessState pub struct ProcessState { pub keys: BTreeMap, // field_name -> AES key } ``` **Distribution:** - **Méthode 1:** Stockage chiffré asymétriquement sur `sdk_storage` - **Méthode 2:** Envoi via `CipherMessage` (WebSocket) - **Méthode 3:** Dérivation à partir d'un secret partagé (ECDH) ### 8.4 Protection contre les attaques #### Rejeu de transactions (Replay): ✅ **Protection:** `state_id` unique (Merkle root inclut `commited_in`) ```rust let hash = AnkPcdHash::from_pcd_value(data, field_name, outpoint); // outpoint change à chaque état -> state_id différent ``` #### Double-spending: ✅ **Protection:** Consensus Bitcoin - Chaque état possède un UTXO unique - Dépense de l'UTXO = commit atomique #### Manipulation des états: ✅ **Protection:** Validation multi-signatures + Merkle proofs ```rust // Impossible de modifier un champ sans: // 1. Recalculer le Merkle root (state_id) // 2. Obtenir les signatures des membres autorisés ``` #### Attaque Sybil (création de fausses identités): ✅ **Protection:** Coût du pairing (frais Bitcoin) - Créer un membre = créer un processus on-chain - Coût: frais de transaction Bitcoin #### Censure par le relay: ⚠️ **Risque résiduel:** - Un relay malveillant peut ne pas diffuser les messages - **Mitigation:** Multi-relays (connexion à plusieurs relays) - **Futur:** Gossip protocol P2P ### 8.5 Audit et traçabilité #### Traçabilité on-chain: ``` Process Timeline (on Bitcoin): Txid 1 (création) → OutPoint 1 → OP_RETURN (state_id_1) Txid 2 (update) → OutPoint 2 → OP_RETURN (state_id_2) Txid 3 (update) → OutPoint 3 → OP_RETURN (state_id_3) ... ``` **Vérification:** 1. Récupérer la chaîne de transactions 2. Vérifier la continuité (input.prev_out = prev_state.commited_in) 3. Vérifier les OP_RETURN (state_id) 4. Recalculer les Merkle roots 5. Vérifier les signatures de chaque état #### Logs off-chain: **sdk_relay** conserve: - Historique des messages WebSocket - États proposés (même non committés) - Signatures reçues **Format de log recommandé:** ```json { "timestamp": "2025-10-01T12:00:00Z", "event": "commit_proposal", "process_id": "abc123:0", "state_id": "def456...", "proposer": "sp1qq...", "validation_tokens": [ { "public_key": "02abc...", "signature": "304402...", "timestamp": "2025-10-01T12:00:05Z" } ], "committed": true, "txid": "xyz789..." } ``` ### 8.6 Bonnes pratiques #### Pour les développeurs: 1. **Quorum élevé pour actions critiques** : ≥ 0.67 (2/3) 2. **min_sig_member = 1.0** : Tous les devices d'un membre doivent signer 3. **Rôle "apophis"** : Toujours définir pour permettre l'oblitération 4. **Chiffrement systématique** : Données sensibles dans PCD (privé) 5. **Validation côté client** : Avant d'envoyer `CommitMessage` #### Pour les utilisateurs: 1. **Multi-device** : Pairer au moins 2 devices (backup) 2. **Sauvegarde des clés** : Export régulier du wallet 3. **Vérification des rôles** : Avant de signer un état 4. **Vérification des champs** : Utiliser `get_fields_to_validate_for_member()` #### Configuration de roles sécurisée: ```rust // Exemple: Gestion de contrat let roles = Roles::new(BTreeMap::from([ // Rôle owner: peut tout modifier ("owner".to_string(), RoleDefinition { members: vec![owner_pairing_id], validation_rules: vec![ ValidationRule::new(1.0, vec!["roles".to_string()], 1.0)?, // 100% consensus ], storages: vec![], }), // Rôle validator: valide les documents ("validator".to_string(), RoleDefinition { members: vec![validator1_id, validator2_id], validation_rules: vec![ ValidationRule::new(0.67, vec!["idCertified".to_string()], 0.5)?, // 2/3 consensus ], storages: vec!["https://storage.4nkweb.com".to_string()], }), // Rôle client: lecture seule + modification de son profil ("client".to_string(), RoleDefinition { members: vec![client_id], validation_rules: vec![ ValidationRule::new(1.0, vec!["clientProfile".to_string()], 1.0)?, ], storages: vec![], }), // Rôle apophis: oblitération (owner uniquement) ("apophis".to_string(), RoleDefinition { members: vec![owner_pairing_id], validation_rules: vec![ ValidationRule::new(1.0, vec!["".to_string()], 1.0)?, ], storages: vec![], }), ])); ``` --- ## Conclusion Le système d'identité et de processus de 4NK repose sur une architecture décentralisée innovante combinant: 1. **Identité cryptographique** : Silent Payments Bitcoin (BIP352) 2. **Multi-device** : Pairing flexible sans compromis de sécurité 3. **Consensus distribué** : Validation multi-signatures avec quorum configurables 4. **Immutabilité** : Commitments Bitcoin pour traçabilité 5. **Confidentialité** : Chiffrement bout-en-bout des données sensibles Cette architecture permet des cas d'usage variés: - Gestion de contrats collaboratifs - Signature électronique multi-parties - Workflows d'approbation décentralisés - Identité numérique souveraine **Points forts:** - Pas de serveur central de confiance - Résistance à la censure - Auditabilité complète - Interopérabilité Bitcoin native **Axes d'amélioration:** - Performance du scanning Silent Payments (optimisation Blindbit) - Résilience réseau (multi-relays, gossip protocol) - Gestion des clés (recovery social, hardware wallets) - UX du pairing (NFC, QR codes dynamiques) --- **Document généré le 1 octobre 2025** **Basé sur l'analyse du code source 4NK (sdk_client, sdk_common, sdk_relay, sdk_storage, ihm_client)**