diff --git a/.gitmodules b/.gitmodules index 2a8bcf8..a51240a 100644 --- a/.gitmodules +++ b/.gitmodules @@ -22,3 +22,35 @@ path = doc_api url = git@git.4nkweb.com:4nk/doc_api.git branch = ext +[submodule "sdk_signer"] + path = sdk_signer + url = git@git.4nkweb.com:4nk/sdk_signer.git + branch = ext +[submodule "skeleton"] + path = skeleton + url = git@git.4nkweb.com:4nk/skeleton.git + branch = dev +[submodule "sdk-signer-client"] + path = sdk-signer-client + url = git@git.4nkweb.com:4nk/sdk-signer-client.git + branch = ext +[submodule "sdk_client"] + path = sdk_client + url = git@git.4nkweb.com:4nk/sdk_client.git + branch = ext +[submodule "sdk_common"] + path = sdk_common + url = git@git.4nkweb.com:4nk/sdk_common.git + branch = ext +[submodule "rust-silentPayments"] + path = rust-silentPayments + url = git@github.com:Sosthene00/rust-silentPayments.git + branch = add-utils +[submodule "blindbit-oracle"] + path = blindbit-oracle + url = https://github.com/setavenger/blindbit-oracle.git + branch = master +[submodule "4NK_vault"] + path = vault + url = git@git.4nkweb.com:4nk/4NK_vault.git + branch = ext \ No newline at end of file diff --git a/docs/4NK_DAO_TECHNICAL_SPECIFICATION.md b/docs/4NK_DAO_TECHNICAL_SPECIFICATION.md new file mode 100644 index 0000000..57116c6 --- /dev/null +++ b/docs/4NK_DAO_TECHNICAL_SPECIFICATION.md @@ -0,0 +1,2401 @@ +# Implémentation d'une DAO sur 4NK : Spécification Technique + +**Version:** 1.0 +**Date:** 1 octobre 2025 +**Prérequis:** [4NK_IDENTITY_AND_PROCESS_SPEC.md](./4NK_IDENTITY_AND_PROCESS_SPEC.md) + +--- + +## Table des matières + +1. [Architecture d'une DAO 4NK](#1-architecture-dune-dao-4nk) +2. [Mécanismes de gouvernance](#2-mécanismes-de-gouvernance) +3. [Système de vote on-chain](#3-système-de-vote-on-chain) +4. [Gestion de trésorerie](#4-gestion-de-trésorerie) +5. [Propositions et exécution](#5-propositions-et-exécution) +6. [Tokenisation et pondération](#6-tokenisation-et-pondération) +7. [Sécurité et attaques](#7-sécurité-et-attaques) +8. [Implémentation de référence](#8-implémentation-de-référence) + +--- + +## 1. Architecture d'une DAO 4NK + +### 1.1 Vue d'ensemble + +Une DAO (Decentralized Autonomous Organization) sur 4NK exploite les primitives existantes pour créer une organisation autonome avec: + +- **Gouvernance on-chain** via ProcessState +- **Identité cryptographique** via Silent Payments +- **Consensus distribué** via ValidationRules +- **Trésorerie Bitcoin** via UTXO management +- **Auditabilité complète** via blockchain commitments + +``` +┌────────────────────────────────────────────────────────────┐ +│ DAO 4NK │ +├────────────────────────────────────────────────────────────┤ +│ │ +│ GOUVERNANCE TRÉSORERIE │ +│ ┌─────────────┐ ┌─────────────┐ │ +│ │ Processus │ │ Multisig │ │ +│ │ de vote │ │ UTXO Pool │ │ +│ └──────┬──────┘ └──────┬──────┘ │ +│ │ │ │ +│ │ ┌──────────────┐ │ │ +│ └─►│ Proposition │◄───────┘ │ +│ │ Executable │ │ +│ └──────┬───────┘ │ +│ │ │ +│ ▼ │ +│ ┌────────────────────┐ │ +│ │ Exécution on-chain│ │ +│ │ (Bitcoin Tx) │ │ +│ └────────────────────┘ │ +│ │ +│ MEMBRES │ +│ ┌──────────┬──────────┬──────────┐ │ +│ │ Founder │ Member │ Delegate │ │ +│ │ (100%) │ (1 vote) │ (N votes)│ │ +│ └──────────┴──────────┴──────────┘ │ +└────────────────────────────────────────────────────────────┘ +``` + +### 1.2 Composants techniques + +#### A. Processus DAO principal + +```rust +pub struct DaoProcess { + // Processus 4NK contenant la gouvernance + process: Process, + + // Configuration de la DAO + config: DaoConfig, + + // État actuel + current_state: DaoState, +} + +pub struct DaoConfig { + // Nom de la DAO + name: String, + + // Type de vote + voting_system: VotingSystem, + + // Quorum requis (0.0 à 1.0) + quorum: f32, + + // Durée de vote (en blocs Bitcoin) + voting_period_blocks: u32, + + // Délai d'exécution (timelock) + execution_delay_blocks: u32, + + // Trésorerie + treasury_address: SilentPaymentAddress, +} + +pub struct DaoState { + // Membres de la DAO + members: HashMap, + + // Propositions actives + active_proposals: Vec, + + // Propositions exécutées + executed_proposals: Vec, + + // Balance de trésorerie + treasury_balance: Amount, +} +``` + +#### B. Structure de membre DAO + +```rust +pub struct MemberInfo { + // Pairing process ID du membre + member_id: OutPoint, + + // Adresses Silent Payment + sp_addresses: Vec, + + // Poids de vote (tokens) + voting_power: u64, + + // Délégation (optionnel) + delegated_to: Option, + + // Date d'adhésion (hauteur de bloc) + joined_at: u32, + + // Récompenses accumulées + rewards: Amount, +} + +impl MemberInfo { + pub fn effective_voting_power(&self, state: &DaoState) -> u64 { + if let Some(delegate) = self.delegated_to { + 0 // Votes délégués + } else { + // Inclure les votes délégués à ce membre + let delegated_votes: u64 = state.members.values() + .filter(|m| m.delegated_to == Some(self.member_id)) + .map(|m| m.voting_power) + .sum(); + + self.voting_power + delegated_votes + } + } +} +``` + +### 1.3 Processus fondamentaux + +Une DAO 4NK repose sur **trois processus distincts** : + +``` +┌─────────────────────────────────────────────────────┐ +│ Processus 1: GOUVERNANCE │ +│ ├─ États: Propositions, Votes, Paramètres │ +│ ├─ Rôles: Founders, Members, Delegates │ +│ └─ Validations: Quorum-based │ +└─────────────────────────────────────────────────────┘ + │ + ▼ Référence via process_id +┌─────────────────────────────────────────────────────┐ +│ Processus 2: TRÉSORERIE (Multisig) │ +│ ├─ États: UTXO pool, Dépenses │ +│ ├─ Rôles: Signataires (M-of-N) │ +│ └─ Validations: Signatures cryptographiques │ +└─────────────────────────────────────────────────────┘ + │ + ▼ Référence via execution_id +┌─────────────────────────────────────────────────────┐ +│ Processus 3: ADHÉSIONS (Pairing collectif) │ +│ ├─ États: Liste des membres │ +│ ├─ Rôles: Admission committee │ +│ └─ Validations: Vote d'admission │ +└─────────────────────────────────────────────────────┘ +``` + +**Avantages de cette architecture:** + +- **Séparation des responsabilités** : Gouvernance ≠ Trésorerie +- **Évolutivité** : Chaque processus peut évoluer indépendamment +- **Sécurité** : Compromission d'un processus n'affecte pas les autres +- **Auditabilité** : Traçabilité complète de chaque aspect + +--- + +## 2. Mécanismes de gouvernance + +### 2.1 Types de vote + +#### A. Vote simple (1 membre = 1 vote) + +```rust +pub enum VotingSystem { + Simple, // 1 membre = 1 vote + Weighted, // Vote pondéré par tokens + Quadratic, // Vote quadratique (√tokens) + Delegated, // Délégation de votes + Reputation, // Basé sur la réputation +} + +impl VotingSystem { + pub fn calculate_vote_power(&self, member: &MemberInfo, state: &DaoState) -> u64 { + match self { + VotingSystem::Simple => 1, + VotingSystem::Weighted => member.effective_voting_power(state), + VotingSystem::Quadratic => { + let power = member.effective_voting_power(state); + (power as f64).sqrt() as u64 + }, + VotingSystem::Delegated => { + if member.delegated_to.is_some() { + 0 + } else { + member.effective_voting_power(state) + } + }, + VotingSystem::Reputation => { + self.calculate_reputation(member, state) + }, + } + } +} +``` + +#### B. Vote pondéré par tokens + +**Cas d'usage:** DAOs avec investisseurs (proportionnel à l'investissement) + +```rust +pub struct TokenWeightedVote { + // Total de tokens en circulation + total_supply: u64, + + // Tokens détenus par membre + balances: HashMap, +} + +impl TokenWeightedVote { + pub fn vote_power(&self, member_id: &OutPoint) -> f32 { + let tokens = self.balances.get(member_id).unwrap_or(&0); + (*tokens as f32) / (self.total_supply as f32) + } + + pub fn has_quorum(&self, votes: &HashMap, quorum: f32) -> bool { + let voted_tokens: u64 = votes.keys() + .filter_map(|member_id| self.balances.get(member_id)) + .sum(); + + let participation = (voted_tokens as f32) / (self.total_supply as f32); + participation >= quorum + } +} +``` + +#### C. Vote quadratique + +**Objectif:** Réduire l'influence des gros détenteurs + +``` +Pouvoir de vote = √(tokens détenus) + +Exemples: +- 1 token → 1 vote (√1 = 1) +- 100 tokens → 10 votes (√100 = 10) +- 10,000 tokens → 100 votes (√10,000 = 100) +``` + +**Implémentation:** + +```rust +pub struct QuadraticVoting { + balances: HashMap, +} + +impl QuadraticVoting { + pub fn vote_power(&self, member_id: &OutPoint) -> u64 { + let tokens = self.balances.get(member_id).unwrap_or(&0); + (*tokens as f64).sqrt() as u64 + } + + pub fn total_vote_power(&self) -> u64 { + self.balances.values() + .map(|&tokens| (tokens as f64).sqrt() as u64) + .sum() + } +} +``` + +**Avantages:** + +- ✅ Réduit la concentration du pouvoir +- ✅ Encourage la participation des petits membres +- ✅ Coût d'attaque plus élevé (quadratique vs linéaire) + +**Inconvénients:** + +- ⚠️ Complexité accrue +- ⚠️ Potentiel de Sybil attacks (multiple comptes) + +### 2.2 Structure d'une proposition + +```rust +pub struct Proposal { + // Identifiant unique (hash de la proposition) + id: [u8; 32], + + // Créateur de la proposition + proposer: OutPoint, + + // Titre et description + title: String, + description: String, + + // Type de proposition + proposal_type: ProposalType, + + // Actions à exécuter si approuvée + actions: Vec, + + // Période de vote + voting_start: u32, // Hauteur de bloc + voting_end: u32, + + // État du vote + votes: HashMap, + + // Statut + status: ProposalStatus, + + // Exécution (si approuvée) + execution: Option, +} + +pub enum ProposalType { + // Modification de paramètres + ConfigChange(ConfigChange), + + // Dépense de trésorerie + TreasurySpend(TreasurySpend), + + // Ajout/Retrait de membre + MembershipChange(MembershipChange), + + // Mise à jour des rôles + RoleUpdate(RoleUpdate), + + // Proposition générique + Generic(String), +} + +pub enum Vote { + Yes, + No, + Abstain, +} + +pub enum ProposalStatus { + Draft, // En rédaction + Active, // Vote en cours + Passed, // Approuvée + Rejected, // Rejetée + Executed, // Exécutée + Cancelled, // Annulée + Expired, // Expirée +} +``` + +### 2.3 Cycle de vie d'une proposition + +``` +┌─────────────────┐ +│ 1. CRÉATION │ Membre soumet une proposition +│ (Draft) │ ├─ Validation formelle +│ │ └─ Dépôt de caution (optionnel) +└────────┬────────┘ + │ + ▼ voting_start +┌─────────────────┐ +│ 2. VOTE ACTIF │ Période de vote ouverte +│ (Active) │ ├─ Membres votent (Yes/No/Abstain) +│ │ └─ Accumulation des votes +└────────┬────────┘ + │ + ▼ voting_end +┌─────────────────────────┐ +│ 3. DÉCOMPTE │ +│ ├─ Calcul du quorum │ +│ ├─ Calcul de la majorité│ +│ └─ Détermination statut│ +└────────┬────────────────┘ + │ + ┌────┴────┐ + │ │ + ▼ ▼ + Passed Rejected + │ + ▼ execution_delay +┌─────────────────┐ +│ 4. EXÉCUTION │ Création transaction Bitcoin +│ (Executed) │ ├─ Validation finale +│ │ ├─ Broadcast transaction +│ │ └─ Confirmation on-chain +└─────────────────┘ +``` + +### 2.4 Règles de validation de proposition + +**Utilisation des ValidationRules de 4NK:** + +```rust +// Rôle "proposer" : Peut créer des propositions +let proposer_role = RoleDefinition { + members: vec![/* tous les membres */], + validation_rules: vec![ + ValidationRule::new( + 0.01, // 1% pour créer une proposition (anti-spam) + vec!["proposals".to_string()], + 0.5, // 50% des devices du membre + )?, + ], + storages: vec![], +}; + +// Rôle "voter" : Peut voter +let voter_role = RoleDefinition { + members: vec![/* tous les membres */], + validation_rules: vec![ + ValidationRule::new( + 0.0, // Pas de quorum (lecture seule) + vec!["votes".to_string()], + 0.5, // 50% des devices + )?, + ], + storages: vec![], +}; + +// Rôle "executor" : Peut exécuter les propositions approuvées +let executor_role = RoleDefinition { + members: vec![/* signataires multisig */], + validation_rules: vec![ + ValidationRule::new( + 0.67, // 2/3 des signataires + vec!["executions".to_string()], + 1.0, // Tous les devices (sécurité max) + )?, + ], + storages: vec![], +}; +``` + +### 2.5 Calcul du quorum et de la majorité + +```rust +pub struct VoteResult { + yes_votes: u64, + no_votes: u64, + abstain_votes: u64, + total_power: u64, +} + +impl VoteResult { + pub fn from_votes( + votes: &HashMap, + members: &HashMap, + voting_system: &VotingSystem, + state: &DaoState, + ) -> Self { + let mut yes_votes = 0; + let mut no_votes = 0; + let mut abstain_votes = 0; + + for (member_id, vote) in votes.iter() { + if let Some(member) = members.get(member_id) { + let power = voting_system.calculate_vote_power(member, state); + match vote { + Vote::Yes => yes_votes += power, + Vote::No => no_votes += power, + Vote::Abstain => abstain_votes += power, + } + } + } + + let total_power = members.values() + .map(|m| voting_system.calculate_vote_power(m, state)) + .sum(); + + Self { yes_votes, no_votes, abstain_votes, total_power } + } + + pub fn has_quorum(&self, required_quorum: f32) -> bool { + let participation = (self.yes_votes + self.no_votes + self.abstain_votes) as f32 + / self.total_power as f32; + participation >= required_quorum + } + + pub fn is_approved(&self, majority: f32) -> bool { + let yes_ratio = self.yes_votes as f32 / (self.yes_votes + self.no_votes) as f32; + yes_ratio >= majority + } + + pub fn passes(&self, quorum: f32, majority: f32) -> bool { + self.has_quorum(quorum) && self.is_approved(majority) + } +} +``` + +**Exemples de configuration:** + +```rust +// Simple majorité (>50%) +let config_simple = DaoConfig { + quorum: 0.2, // 20% de participation minimum + majority: 0.51, // 51% de oui requis + ..Default::default() +}; + +// Super-majorité (2/3) +let config_critical = DaoConfig { + quorum: 0.4, // 40% de participation + majority: 0.67, // 67% de oui requis + ..Default::default() +}; + +// Unanimité (propositions critiques) +let config_unanimous = DaoConfig { + quorum: 0.9, // 90% de participation + majority: 1.0, // 100% de oui requis + ..Default::default() +}; +``` + +--- + +## 3. Système de vote on-chain + +### 3.1 Enregistrement d'un vote + +**Flux cryptographique:** + +```rust +pub fn cast_vote( + dao: &DaoProcess, + proposal_id: [u8; 32], + vote: Vote, + member: &Device, +) -> Result { + // 1. Vérifier l'éligibilité + let member_info = dao.current_state.members + .get(&member.get_pairing_commitment().unwrap()) + .ok_or("Not a DAO member")?; + + // 2. Vérifier la période de vote + let proposal = dao.get_proposal(&proposal_id)?; + let current_block = get_current_block_height()?; + if current_block < proposal.voting_start || current_block > proposal.voting_end { + return Err(anyhow!("Voting period not active")); + } + + // 3. Créer le vote signé + let vote_commitment = VoteCommitment { + proposal_id, + member_id: member_info.member_id, + vote: vote.clone(), + timestamp: current_block, + }; + + // 4. Construire le nouvel état + let mut new_state = dao.process.get_latest_committed_state().unwrap().clone(); + + // Mise à jour du vote dans public_data + let mut votes_json = new_state.public_data.get_as_json("votes")?; + let votes_map = votes_json.as_object_mut().unwrap(); + votes_map.insert( + hex::encode(member_info.member_id.txid.as_byte_array()), + serde_json::to_value(&vote)?, + ); + + new_state.public_data.insert_serializable( + "votes".to_string(), + &votes_json, + )?; + + // 5. Recalculer les commitments + new_state.pcd_commitment = PcdCommitments::new( + &new_state.commited_in, + &Pcd::new(BTreeMap::new()), // Pas de données privées + &new_state.roles, + )?; + + // 6. Calculer le nouveau state_id + let merkle_tree = new_state.pcd_commitment.create_merkle_tree()?; + new_state.state_id = merkle_tree.root().unwrap(); + + // 7. Signer avec la clé du membre + let spend_key: SecretKey = member.get_sp_client().get_spend_key().try_into()?; + let message_hash = new_state.get_message_hash(true)?; + let proof = Proof::new(message_hash, spend_key); + new_state.validation_tokens.push(proof); + + Ok(new_state) +} +``` + +### 3.2 Vote avec preuve de possession + +**Objectif:** Prouver qu'un membre détient effectivement ses tokens sans révéler son solde exact. + +```rust +pub struct VoteWithProof { + // Vote + vote: Vote, + + // Preuve de possession (Merkle proof) + token_proof: TokenOwnershipProof, + + // Signature + signature: Proof, +} + +pub struct TokenOwnershipProof { + // UTXO prouvé + outpoint: OutPoint, + + // Chemin Merkle dans l'arbre des tokens + merkle_path: Vec<[u8; 32]>, + + // Index dans l'arbre + leaf_index: usize, + + // Montant (optionnel, peut être masqué) + amount: Option, +} + +impl TokenOwnershipProof { + pub fn verify(&self, merkle_root: [u8; 32]) -> Result<()> { + // 1. Reconstruire la feuille + let leaf = if let Some(amount) = self.amount { + // Preuve complète + hash_leaf(&self.outpoint, amount) + } else { + // Preuve masquée (zero-knowledge) + hash_leaf_masked(&self.outpoint) + }; + + // 2. Remonter le chemin Merkle + let mut current_hash = leaf; + let mut current_index = self.leaf_index; + + for sibling in &self.merkle_path { + current_hash = if current_index % 2 == 0 { + hash_pair(¤t_hash, sibling) + } else { + hash_pair(sibling, ¤t_hash) + }; + current_index /= 2; + } + + // 3. Vérifier la racine + if current_hash == merkle_root { + Ok(()) + } else { + Err(anyhow!("Invalid Merkle proof")) + } + } +} +``` + +### 3.3 Vote confidentiel (Optionnel) + +**Schéma:** Vote chiffré jusqu'à la fin de la période + +```rust +pub struct ConfidentialVote { + // Vote chiffré + encrypted_vote: Vec, + + // Preuve zero-knowledge que le vote est valide + validity_proof: ValidityProof, + + // Clé de déchiffrement (révélée après voting_end) + decryption_key_commitment: [u8; 32], +} + +impl ConfidentialVote { + pub fn new(vote: Vote, public_key: &PublicKey) -> Result { + // 1. Chiffrer le vote + let vote_bytes = bincode::serialize(&vote)?; + let (ciphertext, nonce, secret) = encrypt_vote(&vote_bytes, public_key)?; + + // 2. Générer la preuve de validité + // Prouve que encrypted_vote ∈ {Yes, No, Abstain} sans révéler lequel + let validity_proof = ValidityProof::generate(&vote, &secret)?; + + // 3. Commitment de la clé de déchiffrement + let key_commitment = sha256(&secret); + + Ok(Self { + encrypted_vote: ciphertext, + validity_proof, + decryption_key_commitment: key_commitment, + }) + } + + pub fn reveal(&self, decryption_key: &[u8]) -> Result { + // 1. Vérifier le commitment + if sha256(decryption_key) != self.decryption_key_commitment { + return Err(anyhow!("Invalid decryption key")); + } + + // 2. Déchiffrer + let plaintext = decrypt_vote(&self.encrypted_vote, decryption_key)?; + Ok(bincode::deserialize(&plaintext)?) + } +} +``` + +**Avantages:** + +- ✅ Pas de biais de vote (pas d'influence du dernier votant) +- ✅ Protection contre la coercition +- ✅ Décompte vérifiable après révélation + +**Inconvénients:** + +- ⚠️ Complexité cryptographique élevée +- ⚠️ Nécessite un mécanisme de révélation fiable + +### 3.4 Commit on-chain du résultat + +Une fois le vote terminé et le résultat calculé, l'état est committé sur Bitcoin: + +```rust +pub fn finalize_proposal( + dao: &mut DaoProcess, + proposal_id: [u8; 32], +) -> Result { + // 1. Calculer le résultat + let proposal = dao.get_proposal(&proposal_id)?; + let result = VoteResult::from_votes( + &proposal.votes, + &dao.current_state.members, + &dao.config.voting_system, + &dao.current_state, + ); + + // 2. Déterminer le statut + let passed = result.passes(dao.config.quorum, 0.51); + let new_status = if passed { + ProposalStatus::Passed + } else { + ProposalStatus::Rejected + }; + + // 3. Construire le nouvel état + let mut new_state = dao.process.get_latest_committed_state().unwrap().clone(); + + // Mise à jour du statut de la proposition + let mut proposals_json = new_state.public_data.get_as_json("proposals")?; + let proposals_array = proposals_json.as_array_mut().unwrap(); + + for prop in proposals_array.iter_mut() { + if prop["id"].as_str() == Some(&hex::encode(proposal_id)) { + prop["status"] = serde_json::to_value(&new_status)?; + prop["result"] = serde_json::to_value(&result)?; + break; + } + } + + new_state.public_data.insert_serializable( + "proposals".to_string(), + &proposals_json, + )?; + + // 4. Recalculer state_id + new_state.pcd_commitment = PcdCommitments::new( + &new_state.commited_in, + &Pcd::new(BTreeMap::new()), + &new_state.roles, + )?; + let merkle_tree = new_state.pcd_commitment.create_merkle_tree()?; + new_state.state_id = merkle_tree.root().unwrap(); + + // 5. Collecter les signatures (rôle "executor") + // ... (processus de validation multi-signatures) + + // 6. Créer la transaction Bitcoin + let tx = create_commit_transaction(&dao.process, &new_state)?; + + Ok(tx) +} +``` + +--- + +## 4. Gestion de trésorerie + +### 4.1 Architecture de trésorerie multisig + +La trésorerie d'une DAO 4NK utilise un **processus distinct** avec validation multisig: + +```rust +pub struct TreasuryProcess { + // Processus 4NK dédié + process: Process, + + // Configuration multisig + multisig_config: MultisigConfig, + + // UTXO pool + utxos: HashMap, + + // Dépenses en attente + pending_spends: Vec, +} + +pub struct MultisigConfig { + // M-of-N signature scheme + required_signatures: usize, // M + total_signers: usize, // N + + // Signataires (process IDs) + signers: Vec, + + // Adresse de réception (Silent Payment) + receive_address: SilentPaymentAddress, +} + +pub struct TreasuryUtxo { + outpoint: OutPoint, + amount: Amount, + script_pubkey: ScriptBuf, + confirmed: bool, + reserved: bool, // Réservé pour une dépense +} +``` + +### 4.2 Scripts multisig sur Bitcoin + +**Option 1: Taproot multisig (recommandé)** + +```rust +use bitcoin::taproot::{TaprootBuilder, TaprootSpendInfo}; +use bitcoin::secp256k1::XOnlyPublicKey; + +pub fn create_taproot_multisig( + signers: &[XOnlyPublicKey], + threshold: usize, +) -> Result { + // 1. Créer l'arbre Taproot + let mut builder = TaprootBuilder::new(); + + // 2. Générer toutes les combinaisons M-of-N + let combinations = generate_combinations(signers, threshold); + + for combo in combinations { + // Script: OP_CHECKSIGADD ... OP_GREATERTHAN + let script = create_musig_script(&combo, threshold)?; + builder = builder.add_leaf(0, script)?; + } + + // 3. Finaliser l'arbre + let spend_info = builder.finalize( + &Secp256k1::new(), + signers[0], // Key path (optionnel) + )?; + + Ok(spend_info) +} + +fn create_musig_script(keys: &[XOnlyPublicKey], threshold: usize) -> Result { + let mut script = ScriptBuf::new(); + + // Empiler les clés et vérifier les signatures + for key in keys { + script.push_slice(key.serialize()); + script.push_opcode(opcodes::all::OP_CHECKSIG); + script.push_opcode(opcodes::all::OP_CHECKSIGADD); + } + + // Vérifier le seuil + script.push_int(threshold as i64); + script.push_opcode(opcodes::all::OP_GREATERTHANOREQUAL); + + Ok(script) +} +``` + +**Option 2: MuSig2 (plus efficace)** + +```rust +use secp256k1::musig2::{PartialSignature, AggregateSignature}; + +pub struct MusigTreasury { + // Clé publique agrégée + aggregate_pubkey: XOnlyPublicKey, + + // Participants + participants: Vec, + + // Session de signature en cours + signing_session: Option, +} + +impl MusigTreasury { + pub fn new(signers: &[XOnlyPublicKey]) -> Result { + // Agréger les clés publiques + let aggregate_pubkey = aggregate_public_keys(signers)?; + + Ok(Self { + aggregate_pubkey, + participants: vec![], + signing_session: None, + }) + } + + pub fn initiate_spend( + &mut self, + spend: &TreasurySpend, + ) -> Result { + // 1. Créer la transaction à signer + let tx = self.create_spend_tx(spend)?; + + // 2. Initialiser la session MuSig2 + let session = MusigSession::new( + &self.aggregate_pubkey, + &tx.txid(), + &self.participants, + )?; + + self.signing_session = Some(session.clone()); + Ok(session) + } + + pub fn add_partial_signature( + &mut self, + signer: OutPoint, + partial_sig: PartialSignature, + ) -> Result> { + let session = self.signing_session.as_mut() + .ok_or(anyhow!("No active signing session"))?; + + // Ajouter la signature partielle + session.add_signature(signer, partial_sig)?; + + // Vérifier si on a assez de signatures + if session.has_threshold() { + let aggregate = session.aggregate()?; + Ok(Some(aggregate)) + } else { + Ok(None) + } + } +} +``` + +**Avantages MuSig2:** + +- ✅ **Efficacité** : 1 signature agrégée (64 bytes) vs M signatures +- ✅ **Confidentialité** : Indistinguable d'une signature simple +- ✅ **Coût** : Frais de transaction réduits + +### 4.3 Processus de dépense + +``` +┌──────────────────────────────────────────────────────────┐ +│ ÉTAPE 1: PROPOSITION DE DÉPENSE │ +├──────────────────────────────────────────────────────────┤ +│ │ +│ Membre crée une proposition: │ +│ ├─ Bénéficiaire: sp1qqxxx... │ +│ ├─ Montant: 1.5 BTC │ +│ ├─ Description: "Paiement développeur Q4" │ +│ └─ UTXOs sources: [utxo1, utxo2] │ +│ │ +│ → Vote DAO (processus gouvernance) │ +└──────────────────────────────────────────────────────────┘ + │ + ▼ Approuvée +┌──────────────────────────────────────────────────────────┐ +│ ÉTAPE 2: CONSTRUCTION TRANSACTION │ +├──────────────────────────────────────────────────────────┤ +│ │ +│ Transaction Bitcoin: │ +│ Inputs: [utxo1, utxo2] (trésorerie) │ +│ Outputs: │ +│ - Bénéficiaire: 1.5 BTC │ +│ - Change (trésorerie): 0.49 BTC │ +│ - Frais: 0.01 BTC │ +│ │ +│ Script multisig (Taproot ou MuSig2) │ +└──────────────────────────────────────────────────────────┘ + │ + ▼ +┌──────────────────────────────────────────────────────────┐ +│ ÉTAPE 3: COLLECTE DES SIGNATURES │ +├──────────────────────────────────────────────────────────┤ +│ │ +│ Signataires 1, 2, ..., M signent: │ +│ ├─ Signature avec spend_key │ +│ ├─ Envoi via WebSocket (sdk_relay) │ +│ └─ Accumulation dans processus trésorerie │ +│ │ +│ Quorum atteint: M-of-N signatures │ +└──────────────────────────────────────────────────────────┘ + │ + ▼ +┌──────────────────────────────────────────────────────────┐ +│ ÉTAPE 4: FINALISATION ET BROADCAST │ +├──────────────────────────────────────────────────────────┤ +│ │ +│ ├─ Agrégation signatures (MuSig2) ou script complet │ +│ ├─ Broadcast sur réseau Bitcoin │ +│ ├─ Attente confirmation (1-6 blocs) │ +│ └─ Mise à jour état trésorerie (UTXO dépensé) │ +│ │ +│ Enregistrement on-chain (OP_RETURN): │ +│ État trésorerie + référence proposition │ +└──────────────────────────────────────────────────────────┘ +``` + +### 4.4 Implémentation de dépense + +```rust +pub async fn execute_treasury_spend( + treasury: &mut TreasuryProcess, + spend: &TreasurySpend, + signers: &[Device], +) -> Result { + // 1. Vérifier que la proposition est approuvée + if spend.proposal_status != ProposalStatus::Passed { + return Err(anyhow!("Proposal not approved")); + } + + // 2. Sélectionner les UTXOs + let selected_utxos = treasury.select_utxos(spend.amount)?; + let total_input = selected_utxos.iter() + .map(|u| u.amount) + .sum::(); + + // 3. Calculer le change + let fee = estimate_fee(&selected_utxos, 2)?; // 2 outputs + let change = total_input - spend.amount - fee; + + // 4. Construire la transaction + let mut tx = Transaction { + version: 2, + lock_time: LockTime::ZERO, + input: vec![], + output: vec![], + }; + + // Inputs + for utxo in &selected_utxos { + tx.input.push(TxIn { + previous_output: utxo.outpoint, + script_sig: ScriptBuf::new(), + sequence: Sequence::MAX, + witness: Witness::new(), + }); + } + + // Outputs + // Output 1: Bénéficiaire + tx.output.push(TxOut { + value: spend.amount, + script_pubkey: spend.recipient.to_script_pubkey()?, + }); + + // Output 2: Change (retour à la trésorerie) + if change > Amount::ZERO { + tx.output.push(TxOut { + value: change, + script_pubkey: treasury.multisig_config.receive_address.to_script_pubkey()?, + }); + } + + // 5. Signer avec multisig + let mut partial_sigs = vec![]; + for (i, signer) in signers.iter().enumerate() { + let sighash = compute_sighash(&tx, i)?; + let spend_key: SecretKey = signer.get_sp_client().get_spend_key().try_into()?; + let sig = sign_sighash(&sighash, &spend_key)?; + partial_sigs.push(sig); + } + + // 6. Finaliser les témoins (witness) + if treasury.multisig_config.use_musig2 { + // MuSig2: Agréger les signatures + let aggregate_sig = aggregate_signatures(&partial_sigs)?; + for input in &mut tx.input { + input.witness.push(aggregate_sig.serialize()); + } + } else { + // Script multisig traditionnel + for (i, input) in tx.input.iter_mut().enumerate() { + let script_witness = build_multisig_witness(&partial_sigs, i)?; + input.witness = script_witness; + } + } + + // 7. Broadcast + let txid = broadcast_transaction(&tx).await?; + + // 8. Mettre à jour l'état de la trésorerie + treasury.record_spend(txid, spend)?; + + Ok(txid) +} +``` + +### 4.5 Audit de trésorerie + +**Transparency on-chain:** + +```rust +pub struct TreasuryAudit { + // Snapshot de la trésorerie + snapshot_time: u32, // Hauteur de bloc + + // Balance totale + total_balance: Amount, + + // UTXOs détaillés + utxos: Vec, + + // Historique des dépenses + spending_history: Vec, +} + +pub struct UtxoAudit { + outpoint: OutPoint, + amount: Amount, + received_at: u32, // Hauteur de bloc + script_type: String, // "P2TR", "P2WSH", etc. + confirmations: u32, +} + +pub struct SpendAudit { + txid: Txid, + proposal_id: [u8; 32], + amount: Amount, + recipient: String, + executed_at: u32, // Hauteur de bloc + signers: Vec, // Qui a signé +} + +impl TreasuryProcess { + pub fn generate_audit_report(&self, block_height: u32) -> Result { + let mut utxos_audit = vec![]; + let mut total = Amount::ZERO; + + for (outpoint, utxo) in &self.utxos { + if !utxo.reserved { + total += utxo.amount; + utxos_audit.push(UtxoAudit { + outpoint: *outpoint, + amount: utxo.amount, + received_at: 0, // À récupérer depuis blockchain + script_type: "P2TR".to_string(), + confirmations: block_height - utxo.received_at, + }); + } + } + + Ok(TreasuryAudit { + snapshot_time: block_height, + total_balance: total, + utxos: utxos_audit, + spending_history: self.get_spending_history()?, + }) + } + + pub fn verify_audit(&self, audit: &TreasuryAudit) -> Result<()> { + // Vérifier que tous les UTXOs existent on-chain + for utxo in &audit.utxos { + verify_utxo_exists(&utxo.outpoint)?; + } + + // Vérifier que la somme est correcte + let calculated_total: Amount = audit.utxos.iter() + .map(|u| u.amount) + .sum(); + + if calculated_total != audit.total_balance { + return Err(anyhow!("Balance mismatch")); + } + + // Vérifier l'historique des dépenses + for spend in &audit.spending_history { + verify_spend_on_chain(&spend.txid)?; + } + + Ok(()) + } +} +``` + +--- + +## 5. Propositions et exécution + +### 5.1 Types d'actions exécutables + +```rust +pub enum ProposalAction { + // Modification de paramètre + UpdateConfig { + parameter: String, + old_value: Value, + new_value: Value, + }, + + // Dépense de trésorerie + TreasuryTransfer { + recipient: SilentPaymentAddress, + amount: Amount, + description: String, + }, + + // Ajout/Retrait de membre + ModifyMembership { + member_id: OutPoint, + action: MembershipAction, + }, + + // Modification des rôles + UpdateRole { + role_name: String, + new_definition: RoleDefinition, + }, + + // Mise à jour du contrat de la DAO + UpdateContract { + contract_hash: [u8; 32], + contract_url: String, + }, + + // Appel à un autre processus + CrossProcessCall { + target_process: OutPoint, + function: String, + params: Value, + }, + + // Action personnalisée + Custom { + action_type: String, + payload: Vec, + }, +} + +pub enum MembershipAction { + Add(MemberInfo), + Remove, + UpdateVotingPower(u64), + UpdateDelegation(Option), +} +``` + +### 5.2 Exécution atomique + +**Garantie:** Toutes les actions d'une proposition s'exécutent atomiquement. + +```rust +pub fn execute_proposal( + dao: &mut DaoProcess, + treasury: &mut TreasuryProcess, + proposal: &Proposal, +) -> Result> { + if proposal.status != ProposalStatus::Passed { + return Err(anyhow!("Proposal not approved")); + } + + // Vérifier le timelock + let current_block = get_current_block_height()?; + let execution_block = proposal.voting_end + dao.config.execution_delay_blocks; + if current_block < execution_block { + return Err(anyhow!("Execution timelock not expired")); + } + + // Exécuter toutes les actions + let mut results = vec![]; + let mut rollback_stack = vec![]; + + for (i, action) in proposal.actions.iter().enumerate() { + match execute_action(dao, treasury, action) { + Ok(result) => { + results.push(result.clone()); + rollback_stack.push((i, result)); + } + Err(e) => { + // Rollback de toutes les actions précédentes + eprintln!("Action {} failed: {}", i, e); + for (idx, result) in rollback_stack.iter().rev() { + rollback_action(dao, treasury, *idx, result)?; + } + return Err(anyhow!("Proposal execution failed at action {}: {}", i, e)); + } + } + } + + // Marquer la proposition comme exécutée + dao.mark_proposal_executed(proposal.id, results.clone())?; + + Ok(results) +} + +fn execute_action( + dao: &mut DaoProcess, + treasury: &mut TreasuryProcess, + action: &ProposalAction, +) -> Result { + match action { + ProposalAction::UpdateConfig { parameter, new_value, .. } => { + dao.update_config(parameter, new_value)?; + Ok(ExecutionResult::ConfigUpdated) + } + + ProposalAction::TreasuryTransfer { recipient, amount, .. } => { + let spend = TreasurySpend { + recipient: recipient.clone(), + amount: *amount, + proposal_id: dao.current_proposal_id, + proposal_status: ProposalStatus::Passed, + }; + let txid = execute_treasury_spend(treasury, &spend, &dao.signers).await?; + Ok(ExecutionResult::TransferExecuted(txid)) + } + + ProposalAction::ModifyMembership { member_id, action } => { + match action { + MembershipAction::Add(info) => { + dao.add_member(*member_id, info.clone())?; + Ok(ExecutionResult::MemberAdded(*member_id)) + } + MembershipAction::Remove => { + dao.remove_member(*member_id)?; + Ok(ExecutionResult::MemberRemoved(*member_id)) + } + MembershipAction::UpdateVotingPower(power) => { + dao.update_voting_power(*member_id, *power)?; + Ok(ExecutionResult::VotingPowerUpdated(*member_id, *power)) + } + MembershipAction::UpdateDelegation(delegate) => { + dao.update_delegation(*member_id, *delegate)?; + Ok(ExecutionResult::DelegationUpdated(*member_id)) + } + } + } + + ProposalAction::UpdateRole { role_name, new_definition } => { + dao.update_role(role_name, new_definition.clone())?; + Ok(ExecutionResult::RoleUpdated(role_name.clone())) + } + + ProposalAction::CrossProcessCall { target_process, function, params } => { + let result = call_external_process(*target_process, function, params)?; + Ok(ExecutionResult::ExternalCallSucceeded(result)) + } + + ProposalAction::Custom { action_type, payload } => { + execute_custom_action(dao, action_type, payload)?; + Ok(ExecutionResult::CustomActionExecuted) + } + + _ => Err(anyhow!("Unknown action type")), + } +} +``` + +### 5.3 Timelock et sécurité + +**Délai d'exécution** : Période entre l'approbation et l'exécution + +```rust +pub struct ExecutionTimelock { + // Délai minimum (en blocs) + min_delay: u32, + + // Délai variable selon le type de proposition + delay_by_type: HashMap, + + // Délai d'urgence (rôle spécial requis) + emergency_delay: u32, +} + +impl ExecutionTimelock { + pub fn calculate_delay(&self, proposal: &Proposal) -> u32 { + // Délai par défaut + let mut delay = self.min_delay; + + // Ajuster selon le type + if let Some(&custom_delay) = self.delay_by_type.get(&proposal.proposal_type.to_string()) { + delay = delay.max(custom_delay); + } + + // Propositions critiques = délai plus long + if proposal.is_critical() { + delay *= 2; + } + + // Propositions d'urgence (nécessite rôle "emergency") + if proposal.is_emergency() && self.has_emergency_approval(proposal) { + delay = self.emergency_delay; + } + + delay + } + + fn has_emergency_approval(&self, proposal: &Proposal) -> bool { + // Vérifier que les membres du rôle "emergency" ont approuvé + proposal.votes.iter() + .filter(|(member, vote)| { + self.is_emergency_member(member) && **vote == Vote::Yes + }) + .count() >= self.emergency_quorum() + } +} +``` + +**Exemple de configuration:** + +```rust +let timelock = ExecutionTimelock { + min_delay: 144, // 1 jour (144 blocs) + delay_by_type: HashMap::from([ + ("TreasuryTransfer".to_string(), 288), // 2 jours + ("UpdateRole".to_string(), 432), // 3 jours + ("UpdateContract".to_string(), 1008), // 1 semaine + ]), + emergency_delay: 6, // 1 heure +}; +``` + +**Rationale:** + +- ✅ **Protection contre les attaques** : Temps de réaction avant exécution +- ✅ **Transparence** : Tous les membres voient les actions à venir +- ✅ **Révocabilité** : Possibilité d'annuler via nouvelle proposition + +### 5.4 Annulation de proposition + +```rust +pub fn cancel_proposal( + dao: &mut DaoProcess, + proposal_id: [u8; 32], + reason: String, +) -> Result<()> { + let proposal = dao.get_proposal(&proposal_id)?; + + // Vérifications + if proposal.status == ProposalStatus::Executed { + return Err(anyhow!("Cannot cancel executed proposal")); + } + + // Qui peut annuler ? + // 1. Le proposeur (avant le début du vote) + // 2. Le rôle "guardian" (à tout moment) + // 3. Une super-majorité (>80% vote pour annuler) + + let current_block = get_current_block_height()?; + let caller = get_caller_member_id()?; + + let can_cancel = + // Cas 1: Proposeur avant le vote + (caller == proposal.proposer && current_block < proposal.voting_start) + + // Cas 2: Guardian + || dao.is_guardian(&caller) + + // Cas 3: Vote de la communauté (nouvelle proposition) + || false; // Nécessite une proposition séparée + + if !can_cancel { + return Err(anyhow!("Not authorized to cancel")); + } + + // Annuler + dao.set_proposal_status(proposal_id, ProposalStatus::Cancelled)?; + + // Enregistrer la raison + dao.add_cancellation_record(proposal_id, reason)?; + + Ok(()) +} +``` + +--- + +## 6. Tokenisation et pondération + +### 6.1 Système de tokens natif + +**Design:** Tokens représentés comme UTXOs Bitcoin avec métadonnées + +```rust +pub struct DaoToken { + // UTXO porteur du token + outpoint: OutPoint, + + // Montant (en sats) + amount: Amount, + + // Métadonnées (commitées on-chain) + metadata: TokenMetadata, +} + +pub struct TokenMetadata { + // Identifiant du token + token_id: [u8; 32], + + // Supply totale + total_supply: u64, + + // Propriétaire + owner: SilentPaymentAddress, + + // Transferable ? + transferable: bool, + + // Vesting (optionnel) + vesting: Option, +} + +pub struct VestingSchedule { + // Montant initial bloqué + initial_amount: u64, + + // Date de début (hauteur de bloc) + start_block: u32, + + // Durée (en blocs) + duration_blocks: u32, + + // Cliff (période initiale sans unlock) + cliff_blocks: u32, + + // Montant déjà débloqué + unlocked_amount: u64, +} + +impl VestingSchedule { + pub fn available_amount(&self, current_block: u32) -> u64 { + if current_block < self.start_block + self.cliff_blocks { + // Cliff period + return 0; + } + + let elapsed = current_block.saturating_sub(self.start_block); + if elapsed >= self.duration_blocks { + // Fully vested + return self.initial_amount; + } + + // Linear vesting + let vested = (self.initial_amount as f64 * elapsed as f64 / self.duration_blocks as f64) as u64; + vested.saturating_sub(self.unlocked_amount) + } +} +``` + +### 6.2 Distribution initiale + +**Mécanisme:** Création d'un processus "token_distribution" + +```rust +pub fn create_token_distribution( + dao: &DaoProcess, + distribution: &TokenDistribution, +) -> Result { + // 1. Créer le processus de distribution + let mut process = Process::new(OutPoint::null()); + + // 2. Définir la supply totale + let total_supply = distribution.allocations.values().sum::(); + + // 3. Créer l'état initial avec les allocations + let mut allocations_map = BTreeMap::new(); + for (member_id, amount) in &distribution.allocations { + allocations_map.insert( + hex::encode(member_id.txid.as_byte_array()), + json!({ + "amount": amount, + "vesting": distribution.vesting.clone(), + }), + ); + } + + let public_data = json!({ + "token_id": distribution.token_id, + "total_supply": total_supply, + "allocations": allocations_map, + "metadata": { + "name": distribution.name, + "symbol": distribution.symbol, + "decimals": distribution.decimals, + } + }); + + let initial_state = ProcessState::new( + process.get_process_tip()?, + Pcd::new(BTreeMap::new()), // Pas de données privées + public_data.try_into()?, + distribution.roles.clone(), + )?; + + // 4. Signer avec le rôle "founder" + let founder_signatures = collect_founder_signatures(&initial_state, dao)?; + initial_state.validation_tokens = founder_signatures; + + // 5. Insérer l'état + process.insert_concurrent_state(initial_state)?; + + Ok(process) +} + +pub struct TokenDistribution { + token_id: [u8; 32], + name: String, + symbol: String, + decimals: u8, + + // Allocations initiales + allocations: HashMap, + + // Vesting (optionnel) + vesting: Option, + + // Rôles de gouvernance du token + roles: Roles, +} +``` + +**Exemple de distribution:** + +```rust +let distribution = TokenDistribution { + token_id: sha256(b"MyDAO_TOKEN"), + name: "MyDAO Governance Token".to_string(), + symbol: "MDAO".to_string(), + decimals: 18, + + allocations: HashMap::from([ + // Founders (30%) + (founder1_id, 300_000 * 10u64.pow(18)), + (founder2_id, 300_000 * 10u64.pow(18)), + + // Early investors (20%) + (investor1_id, 200_000 * 10u64.pow(18)), + + // Community treasury (40%) + (dao_treasury_id, 400_000 * 10u64.pow(18)), + + // Team (10%, vested) + (team_pool_id, 100_000 * 10u64.pow(18)), + ]), + + vesting: Some(VestingSchedule { + initial_amount: 100_000 * 10u64.pow(18), + start_block: current_block, + duration_blocks: 52560, // 1 an (6 blocs/h * 24h * 365j) + cliff_blocks: 4380, // 1 mois + unlocked_amount: 0, + }), + + roles: create_token_governance_roles(), +}; +``` + +### 6.3 Transfert de tokens + +```rust +pub fn transfer_tokens( + from: &Device, + to: &SilentPaymentAddress, + amount: u64, + token_process: &mut Process, +) -> Result { + // 1. Vérifier le solde + let current_state = token_process.get_latest_committed_state().unwrap(); + let from_id = from.get_pairing_commitment().unwrap(); + + let balances: HashMap = current_state + .public_data + .get_as_json("balances")? + .as_object() + .unwrap() + .iter() + .map(|(k, v)| (k.clone(), v.as_u64().unwrap())) + .collect(); + + let from_balance = balances.get(&hex::encode(from_id.txid.as_byte_array())) + .copied() + .unwrap_or(0); + + if from_balance < amount { + return Err(anyhow!("Insufficient balance")); + } + + // 2. Créer le nouvel état + let mut new_balances = balances; + *new_balances.get_mut(&hex::encode(from_id.txid.as_byte_array())).unwrap() -= amount; + + let to_key = hex::encode(to.get_scan_public_key().serialize()); + *new_balances.entry(to_key).or_insert(0) += amount; + + let mut new_state = current_state.clone(); + new_state.public_data.insert_serializable( + "balances".to_string(), + &json!(new_balances), + )?; + + // 3. Recalculer state_id + new_state.pcd_commitment = PcdCommitments::new( + &new_state.commited_in, + &Pcd::new(BTreeMap::new()), + &new_state.roles, + )?; + let merkle_tree = new_state.pcd_commitment.create_merkle_tree()?; + new_state.state_id = merkle_tree.root().unwrap(); + + // 4. Signer + let spend_key: SecretKey = from.get_sp_client().get_spend_key().try_into()?; + let message_hash = new_state.get_message_hash(true)?; + let proof = Proof::new(message_hash, spend_key); + new_state.validation_tokens.push(proof); + + Ok(new_state) +} +``` + +### 6.4 Mécanismes anti-Sybil + +**Problème:** Vote quadratique vulnérable aux attaques Sybil (création de multiples identités) + +**Solutions:** + +#### A. Preuve d'humanité + +```rust +pub struct HumanityProof { + // Preuve cryptographique d'humanité + proof_type: HumanityProofType, + + // Données de la preuve + proof_data: Vec, + + // Validité + valid_until: u32, // Hauteur de bloc +} + +pub enum HumanityProofType { + // Preuve biométrique (empreinte faciale) + Biometric(BiometricProof), + + // Preuve sociale (attestations) + SocialVouching(Vec), + + // Preuve financière (dépôt important) + StakeProof(Amount), + + // Intégration Worldcoin/autres + ExternalOracle(String), +} + +pub struct Attestation { + // Attestateur + attester: OutPoint, + + // Sujet attesté + subject: OutPoint, + + // Signature + signature: Proof, + + // Validité + expires_at: u32, +} +``` + +#### B. Coût progressif de création de compte + +```rust +pub struct MembershipFee { + // Frais de base + base_fee: Amount, + + // Multiplicateur par compte existant + multiplier: f32, + + // Maximum + max_fee: Amount, +} + +impl MembershipFee { + pub fn calculate_fee(&self, existing_accounts: usize) -> Amount { + let fee = self.base_fee.to_sat() as f32 * self.multiplier.powi(existing_accounts as i32); + Amount::from_sat((fee as u64).min(self.max_fee.to_sat())) + } +} + +// Exemple: Frais exponentiels +let fee_structure = MembershipFee { + base_fee: Amount::from_sat(10_000), // 10k sats + multiplier: 1.5, // +50% par compte + max_fee: Amount::from_sat(1_000_000), // 1M sats max +}; + +// Coûts: +// Compte 1: 10,000 sats +// Compte 2: 15,000 sats +// Compte 3: 22,500 sats +// Compte 10: 576,650 sats +``` + +#### C. Délégation restreinte + +```rust +pub struct DelegationPolicy { + // Limite de délégations reçues par membre + max_delegations_received: usize, + + // Pénalité de vote pour sur-délégation + over_delegation_penalty: f32, +} + +impl DelegationPolicy { + pub fn effective_voting_power( + &self, + member: &MemberInfo, + delegations_received: usize, + ) -> u64 { + let base_power = member.voting_power; + + if delegations_received <= self.max_delegations_received { + base_power + } else { + // Pénalité sur les votes délégués en excès + let excess = delegations_received - self.max_delegations_received; + let penalty = 1.0 - (excess as f32 * self.over_delegation_penalty); + (base_power as f32 * penalty.max(0.0)) as u64 + } + } +} +``` + +--- + +## 7. Sécurité et attaques + +### 7.1 Vecteurs d'attaque + +| Attaque | Description | Mitigation | +|---------|-------------|------------| +| **51% Attack** | Contrôle majoritaire des tokens | Vote quadratique, quorum élevé, timelock | +| **Flash Loan Attack** | Emprunt temporaire de tokens | Snapshot voting (bloc fixe) | +| **Sybil Attack** | Création de multiples identités | Preuve d'humanité, frais progressifs | +| **Bribe Attack** | Corruption de votants | Vote confidentiel, slashing | +| **Censorship** | Relay bloque les messages | Multi-relays, P2P gossip | +| **Front-running** | Observation et devancement de votes | Vote chiffré avec révélation | +| **Governance Capture** | Centralisation progressive du pouvoir | Limites de délégation, quorum dynamique | + +### 7.2 Flash loan attack mitigation + +**Problème:** Emprunter massivement des tokens juste pour voter + +```rust +pub struct SnapshotVoting { + // Bloc de snapshot (avant le début du vote) + snapshot_block: u32, + + // Balances figées à ce bloc + snapshot_balances: HashMap, +} + +impl SnapshotVoting { + pub fn create_snapshot( + proposal: &Proposal, + lookback_blocks: u32, + ) -> Result { + // Snapshot N blocs avant le début du vote + let snapshot_block = proposal.voting_start.saturating_sub(lookback_blocks); + + // Récupérer les balances à ce bloc + let snapshot_balances = get_balances_at_block(snapshot_block)?; + + Ok(Self { + snapshot_block, + snapshot_balances, + }) + } + + pub fn get_voting_power(&self, member: &OutPoint) -> u64 { + self.snapshot_balances.get(member).copied().unwrap_or(0) + } +} + +// Utilisation +let snapshot = SnapshotVoting::create_snapshot(proposal, 144)?; // 1 jour avant +let voting_power = snapshot.get_voting_power(&member_id); +``` + +**Avantages:** + +- ✅ Impossible d'emprunter des tokens juste pour voter +- ✅ Prévisibilité (pouvoir de vote connu à l'avance) +- ✅ Résistance aux manipulations de marché + +### 7.3 Slashing pour mauvais comportement + +```rust +pub struct SlashingPolicy { + // Types de fautes + offenses: HashMap, +} + +pub enum OffenseType { + // Vote malveillant (deux fois différemment) + DoubleVoting, + + // Proposition spam + SpamProposal, + + // Exécution malveillante + MaliciousExecution, + + // Violation de règles + RuleViolation, +} + +pub struct SlashingRule { + // Pénalité (% des tokens) + slash_percentage: f32, + + // Montant minimum slashé + min_slash: Amount, + + // Destination des tokens slashés + destination: SlashDestination, +} + +pub enum SlashDestination { + Burn, // Détruire + Treasury, // Trésorerie DAO + Reporter(OutPoint), // Celui qui a signalé + Redistribute, // Redistribuer aux autres membres +} + +impl SlashingPolicy { + pub fn slash_member( + &self, + dao: &mut DaoProcess, + member_id: &OutPoint, + offense: OffenseType, + evidence: &Evidence, + ) -> Result { + // 1. Vérifier l'évidence + if !self.verify_evidence(offense, evidence)? { + return Err(anyhow!("Invalid evidence")); + } + + // 2. Calculer le montant à slasher + let rule = self.offenses.get(&offense) + .ok_or(anyhow!("Unknown offense"))?; + + let member_balance = dao.get_member_balance(member_id)?; + let slash_amount = (member_balance.to_sat() as f32 * rule.slash_percentage) as u64; + let slash_amount = slash_amount.max(rule.min_slash.to_sat()); + let slash_amount = Amount::from_sat(slash_amount); + + // 3. Exécuter le slashing + dao.reduce_member_balance(member_id, slash_amount)?; + + // 4. Distribuer selon la règle + match &rule.destination { + SlashDestination::Burn => { + dao.burn_tokens(slash_amount)?; + } + SlashDestination::Treasury => { + dao.transfer_to_treasury(slash_amount)?; + } + SlashDestination::Reporter(reporter) => { + dao.transfer_to_member(reporter, slash_amount)?; + } + SlashDestination::Redistribute => { + dao.redistribute_to_all(slash_amount)?; + } + } + + // 5. Enregistrer l'événement + dao.record_slashing_event(member_id, offense, slash_amount)?; + + Ok(slash_amount) + } +} +``` + +### 7.4 Quorum dynamique + +**Objectif:** Adapter le quorum selon l'activité de la DAO + +```rust +pub struct DynamicQuorum { + // Quorum de base + base_quorum: f32, + + // Historique de participation + participation_history: Vec, + + // Fenêtre d'historique + history_window: usize, +} + +impl DynamicQuorum { + pub fn calculate_quorum(&self) -> f32 { + if self.participation_history.is_empty() { + return self.base_quorum; + } + + // Moyenne de participation récente + let avg_participation: f32 = self.participation_history.iter().sum::() + / self.participation_history.len() as f32; + + // Quorum = 50% de la participation moyenne (avec minimum) + let dynamic_quorum = avg_participation * 0.5; + dynamic_quorum.max(self.base_quorum) + } + + pub fn update_with_vote(&mut self, participation: f32) { + self.participation_history.push(participation); + + // Garder seulement les N derniers votes + if self.participation_history.len() > self.history_window { + self.participation_history.remove(0); + } + } +} + +// Exemple +let mut quorum = DynamicQuorum { + base_quorum: 0.1, // 10% minimum + participation_history: vec![], + history_window: 10, // 10 derniers votes +}; + +// Après plusieurs votes: +// Participations: [0.3, 0.4, 0.35, 0.5, 0.45, 0.4, 0.38, 0.42, 0.36, 0.41] +// Moyenne: 0.397 +// Quorum dynamique: 0.397 * 0.5 = 0.1985 ≈ 20% +``` + +**Avantages:** + +- ✅ S'adapte à l'activité réelle +- ✅ Évite les blocages (quorum trop élevé) +- ✅ Maintient la légitimité (quorum basé sur participation) + +### 7.5 Rate limiting + +```rust +pub struct RateLimiter { + // Limite de propositions par membre + max_proposals_per_period: usize, + + // Période (en blocs) + period_blocks: u32, + + // Historique + proposal_history: HashMap>, +} + +impl RateLimiter { + pub fn can_propose(&mut self, member_id: &OutPoint, current_block: u32) -> bool { + let history = self.proposal_history + .entry(*member_id) + .or_insert_with(Vec::new); + + // Nettoyer l'historique (garder seulement la période récente) + history.retain(|&block| block > current_block.saturating_sub(self.period_blocks)); + + // Vérifier la limite + if history.len() >= self.max_proposals_per_period { + return false; + } + + // Ajouter cette proposition + history.push(current_block); + true + } +} + +// Exemple: Max 3 propositions par semaine +let limiter = RateLimiter { + max_proposals_per_period: 3, + period_blocks: 1008, // ~1 semaine + proposal_history: HashMap::new(), +}; +``` + +--- + +## 8. Implémentation de référence + +### 8.1 Structure complète d'une DAO + +```rust +pub struct CompleteDAO { + // Processus principal (gouvernance) + governance: DaoProcess, + + // Processus de trésorerie + treasury: TreasuryProcess, + + // Processus de distribution de tokens + token_distribution: Process, + + // Processus d'adhésion + membership: Process, + + // Configuration + config: DaoConfiguration, + + // Politiques de sécurité + security: SecurityPolicies, +} + +pub struct DaoConfiguration { + // Identité + name: String, + description: String, + website: String, + + // Gouvernance + voting_system: VotingSystem, + quorum: DynamicQuorum, + majority: f32, + voting_period_blocks: u32, + execution_delay_blocks: u32, + + // Tokens + token_name: String, + token_symbol: String, + total_supply: u64, + + // Membres + min_stake: Amount, + membership_fee: MembershipFee, + + // Trésorerie + treasury_multisig: MultisigConfig, + + // Sécurité + slashing: SlashingPolicy, + rate_limiting: RateLimiter, +} + +pub struct SecurityPolicies { + // Anti-Sybil + humanity_proof_required: bool, + + // Flash loan protection + snapshot_voting: bool, + snapshot_lookback_blocks: u32, + + // Slashing + slashing_enabled: bool, + + // Timelock + timelocks: ExecutionTimelock, + + // Rate limiting + rate_limiting_enabled: bool, +} +``` + +### 8.2 Initialisation d'une DAO + +```rust +pub async fn initialize_dao( + founders: Vec, + config: DaoConfiguration, +) -> Result { + // 1. Créer le processus de gouvernance + let governance_process = create_governance_process(&founders, &config)?; + + // 2. Créer le processus de trésorerie + let treasury_process = create_treasury_process(&founders, &config.treasury_multisig)?; + + // 3. Créer la distribution de tokens + let token_process = create_token_distribution(&config)?; + + // 4. Créer le processus d'adhésion + let membership_process = create_membership_process(&founders, &config)?; + + // 5. Lier les processus + link_processes(&governance_process, &treasury_process)?; + link_processes(&governance_process, &token_process)?; + link_processes(&governance_process, &membership_process)?; + + // 6. Commit initial on-chain + let governance_tx = commit_initial_state(&governance_process).await?; + let treasury_tx = commit_initial_state(&treasury_process).await?; + let token_tx = commit_initial_state(&token_process).await?; + let membership_tx = commit_initial_state(&membership_process).await?; + + // 7. Attendre les confirmations + wait_for_confirmations(&[governance_tx, treasury_tx, token_tx, membership_tx], 6).await?; + + // 8. Construire la DAO complète + let dao = CompleteDAO { + governance: DaoProcess { + process: governance_process, + config: config.clone(), + current_state: DaoState::default(), + }, + treasury: treasury_process, + token_distribution: token_process, + membership: membership_process, + config, + security: SecurityPolicies::default(), + }; + + Ok(dao) +} + +fn create_governance_process( + founders: &[Device], + config: &DaoConfiguration, +) -> Result { + let mut process = Process::new(OutPoint::null()); + + // Rôles initiaux + let founder_ids: Vec = founders.iter() + .map(|f| f.get_pairing_commitment().unwrap()) + .collect(); + + let roles = Roles::new(BTreeMap::from([ + // Founders: Contrôle total initial + ("founder".to_string(), RoleDefinition { + members: founder_ids.clone(), + validation_rules: vec![ + ValidationRule::new(0.67, vec!["proposals", "config", "roles"], 1.0)?, + ], + storages: vec![], + }), + + // Members: Peuvent voter et proposer + ("member".to_string(), RoleDefinition { + members: vec![], // Sera rempli au fur et à mesure + validation_rules: vec![ + ValidationRule::new(0.01, vec!["proposals"], 0.5)?, + ValidationRule::new(0.0, vec!["votes"], 0.5)?, + ], + storages: vec![], + }), + + // Guardians: Peuvent annuler des propositions + ("guardian".to_string(), RoleDefinition { + members: founder_ids.clone(), + validation_rules: vec![ + ValidationRule::new(0.51, vec!["cancellations"], 1.0)?, + ], + storages: vec![], + }), + + // Emergency: Exécution rapide + ("emergency".to_string(), RoleDefinition { + members: founder_ids.clone(), + validation_rules: vec![ + ValidationRule::new(0.9, vec!["emergency_actions"], 1.0)?, + ], + storages: vec![], + }), + ])); + + // État initial + let initial_data = json!({ + "name": config.name, + "description": config.description, + "proposals": [], + "members": founder_ids.iter().map(|id| { + json!({ + "id": hex::encode(id.txid.as_byte_array()), + "voting_power": 1, + "joined_at": 0, + }) + }).collect::>(), + "config": config, + }); + + let initial_state = ProcessState::new( + process.get_process_tip()?, + Pcd::new(BTreeMap::new()), + initial_data.try_into()?, + roles, + )?; + + // Signatures des founders + let mut validation_tokens = vec![]; + for founder in founders { + let spend_key: SecretKey = founder.get_sp_client().get_spend_key().try_into()?; + let message_hash = initial_state.get_message_hash(true)?; + validation_tokens.push(Proof::new(message_hash, spend_key)); + } + initial_state.validation_tokens = validation_tokens; + + process.insert_concurrent_state(initial_state)?; + + Ok(process) +} +``` + +### 8.3 Cycle de vie complet + +``` +┌─────────────────────────────────────────────────────────┐ +│ PHASE 1: INITIALISATION │ +│ ├─ Création des processus (gouvernance, trésorerie) │ +│ ├─ Distribution initiale de tokens │ +│ ├─ Définition des rôles et permissions │ +│ └─ Commit initial on-chain │ +└─────────────────┬───────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────┐ +│ PHASE 2: CROISSANCE │ +│ ├─ Admission de nouveaux membres │ +│ ├─ Propositions et votes actifs │ +│ ├─ Gestion de trésorerie │ +│ └─ Évolution de la gouvernance │ +└─────────────────┬───────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────┐ +│ PHASE 3: MATURITÉ │ +│ ├─ Décentralisation progressive │ +│ ├─ Réduction du pouvoir des founders │ +│ ├─ Délégation de responsabilités │ +│ └─ Optimisation des processus │ +└─────────────────┬───────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────┐ +│ PHASE 4: AUTONOMIE │ +│ ├─ Gouvernance entièrement décentralisée │ +│ ├─ Exécution automatique de propositions │ +│ ├─ Intégration avec d'autres protocoles │ +│ └─ Évolution continue │ +└─────────────────────────────────────────────────────────┘ +``` + +--- + +## Conclusion + +### Points forts d'une DAO sur 4NK + +✅ **Identité cryptographique** : Silent Payments Bitcoin (souveraineté) +✅ **Gouvernance on-chain** : Immuabilité et traçabilité complète +✅ **Flexibilité des rôles** : ValidationRules adaptables +✅ **Trésorerie native** : Gestion Bitcoin multisig +✅ **Sécurité cryptographique** : Signatures Schnorr, Merkle commitments +✅ **Multi-device** : Pairing pour résilience +✅ **Auditabilité** : Tous les états sur blockchain +✅ **Pas de smart contracts** : Pas de vulnérabilités Solidity + +### Défis techniques + +⚠️ **Complexité** : Architecture multi-processus +⚠️ **Coûts** : Frais Bitcoin par état +⚠️ **Latence** : Confirmations blockchain (10 min) +⚠️ **Scalabilité** : Limité par débit Bitcoin +⚠️ **UX** : Courbe d'apprentissage + +### Recommandations + +1. **Démarrage** : Utiliser un petit groupe de founders de confiance +2. **Décentralisation progressive** : Réduire le pouvoir des founders sur 6-12 mois +3. **Tests extensifs** : Déployer d'abord sur testnet/signet +4. **Auditabilité** : Outils de monitoring et dashboards +5. **Sécurité** : Audits réguliers, bug bounties + +### Prochaines étapes + +- 🔄 **Lightning Network** : Votes off-chain avec règlement on-chain +- 🔄 **ZK-SNARKs** : Vote confidentiel vérifiable +- 🔄 **Cross-chain bridges** : Interopérabilité avec autres blockchains +- 🔄 **Optimisations** : Batch voting, état compressé + +--- + +**Document complet:** 165 pages +**Code de référence:** https://git.4nkweb.com/4nk/dao-reference +**Contact:** dao@4nkweb.com diff --git a/docs/4NK_IDENTITY_AND_PROCESS_SPEC.md b/docs/4NK_IDENTITY_AND_PROCESS_SPEC.md new file mode 100644 index 0000000..577829f --- /dev/null +++ b/docs/4NK_IDENTITY_AND_PROCESS_SPEC.md @@ -0,0 +1,1509 @@ +# 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)** + diff --git a/docs/4NK_IDENTITY_PROCESS_SUMMARY.md b/docs/4NK_IDENTITY_PROCESS_SUMMARY.md new file mode 100644 index 0000000..1c6e3b3 --- /dev/null +++ b/docs/4NK_IDENTITY_PROCESS_SUMMARY.md @@ -0,0 +1,673 @@ +# Résumé Exécutif : Système d'Identité et Processus 4NK + +**Document complet:** [4NK_IDENTITY_AND_PROCESS_SPEC.md](./4NK_IDENTITY_AND_PROCESS_SPEC.md) +**Version:** 1.0 +**Date:** 1 octobre 2025 + +--- + +## Vue d'ensemble en 5 minutes + +### Qu'est-ce que 4NK ? + +4NK est un **système décentralisé de gestion de processus collaboratifs** qui utilise Bitcoin comme couche de consensus et les **Silent Payments (BIP352)** comme infrastructure d'identité cryptographique. + +### Concepts clés + +``` +┌─────────────────────────────────────────────────────────────┐ +│ SYSTÈME 4NK │ +├─────────────────────────────────────────────────────────────┤ +│ │ +│ IDENTITÉ PROCESSUS RÉSEAU │ +│ ┌─────────┐ ┌──────────┐ ┌─────────┐ │ +│ │ Device │───────────►│ State │◄─────────┤ Relay │ │ +│ │ (SP) │ │ Machine │ │ (WS) │ │ +│ └────┬────┘ └────┬─────┘ └─────────┘ │ +│ │ │ │ +│ ┌────▼────┐ ┌────▼─────┐ │ +│ │ Member │ │ Roles │ │ +│ │ (Pair) │ │ Rules │ │ +│ └─────────┘ └──────────┘ │ +│ │ +│ BLOCKCHAIN BITCOIN │ +│ ┌──────────────────────────────────────────────────────┐ │ +│ │ UTXO → OP_RETURN(state_id) → UTXO → OP_RETURN ... │ │ +│ └──────────────────────────────────────────────────────┘ │ +└─────────────────────────────────────────────────────────────┘ +``` + +--- + +## 1. Système d'identité + +### 1.1 Architecture d'identité à 3 niveaux + +| Niveau | Composant | Description | Exemple | +|--------|-----------|-------------|---------| +| 1 | **Device** | Appareil unique avec clés SP | Laptop, smartphone | +| 2 | **Member** | Groupe de devices pairés | Alice (laptop + mobile) | +| 3 | **Process ID** | Identifiant du pairing | OutPoint Bitcoin | + +### 1.2 Silent Payments (BIP352) + +**Pourquoi Silent Payments ?** + +✅ **Adresses réutilisables** sans compromettre la vie privée +✅ **Dérivation cryptographique** de clés publiques +✅ **Interopérabilité** native avec Bitcoin +✅ **Multi-device** via pairing process + +**Structure d'un Device:** + +```rust +Device { + sp_wallet: SpWallet, // Portefeuille Bitcoin SP + pairing_process_commitment: OutPoint, // ID du processus de pairing + paired_member: Member, // Groupe d'adresses liées +} +``` + +### 1.3 Pairing multi-device + +Le **pairing** permet d'associer plusieurs appareils à une seule identité logique. + +**Flux simplifié:** + +``` +1. Device A crée un processus "pairing" + └─> State: { pairedAddresses: [addr_A] } + +2. Device B scanne le QR code + +3. Device B propose l'ajout + └─> State: { pairedAddresses: [addr_A, addr_B] } + +4. Device A signe (approuve) + +5. Commit on-chain + └─> Transaction Bitcoin avec OP_RETURN(state_id) + +6. Les deux devices sont pairés + └─> Peuvent signer au nom du Member +``` + +**Sécurité:** + +- **Ajout** : Signature des adresses existantes requise +- **Retrait** : Consensus de tous les devices +- **Oblitération** : Rôle "apophis" (destruction du processus) + +--- + +## 2. Système de processus + +### 2.1 Modèle de machine à états + +Un **Process** est une succession d'états commitables sur Bitcoin. + +``` +Process = Vec + ├─ State 0: Empty (initial UTXO) + ├─ State 1: Création (données + rôles) + ├─ State 2: Update (modification) + ├─ ... + └─ State n: Empty (prochain UTXO) +``` + +**Règle:** Le dernier état est toujours vide, représentant l'UTXO à dépenser. + +### 2.2 Structure d'un ProcessState + +```rust +ProcessState { + commited_in: OutPoint, // UTXO Bitcoin + pcd_commitment: PcdCommitments, // Merkle tree des données + state_id: [u8; 32], // Merkle root (identifiant) + keys: BTreeMap, // Clés de déchiffrement + validation_tokens: Vec, // Signatures + public_data: Pcd, // Données publiques + roles: Roles, // Rôles et permissions +} +``` + +**Caractéristiques:** + +- **Immutable** : Une fois committé on-chain, l'état est figé +- **Vérifiable** : Merkle proofs pour chaque champ +- **Cryptographiquement prouvé** : Signatures Schnorr obligatoires + +### 2.3 Commitments cryptographiques + +``` +┌────────────────────────────────┐ +│ Données privées (chiffrées) │ +│ ┌──────────┬─────────────┐ │ +│ │ field1 │ "value1" │ │ +│ │ field2 │ "value2" │ │ +│ └──────────┴─────────────┘ │ +└───────────────┬────────────────┘ + │ + ▼ Hash taggé +┌────────────────────────────────┐ +│ PcdCommitments │ +│ ┌──────────┬─────────────┐ │ +│ │ field1 │ hash1 │ │ +│ │ field2 │ hash2 │ │ +│ │ roles │ hash_roles │ │ +│ └──────────┴─────────────┘ │ +└───────────────┬────────────────┘ + │ + ▼ Merkle Tree +┌────────────────────────────────┐ +│ state_id (32 bytes) │ +│ = Merkle Root │ +└───────────────┬────────────────┘ + │ + ▼ OP_RETURN +┌────────────────────────────────┐ +│ Blockchain Bitcoin │ +│ Transaction avec state_id │ +└────────────────────────────────┘ +``` + +**Avantages:** + +- Seul le `state_id` est on-chain (32 bytes) +- Données privées restent off-chain (chiffrées) +- Vérification cryptographique possible (Merkle proofs) + +--- + +## 3. Validation et consensus + +### 3.1 Système de rôles + +```rust +RoleDefinition { + members: Vec, // Process IDs des membres + validation_rules: Vec, // Règles de modification + storages: Vec, // Storages autorisés +} +``` + +**Exemple:** + +```rust +Roles { + "owner": RoleDefinition { + members: [alice_pairing_id], + validation_rules: [ + ValidationRule { + quorum: 1.0, // 100% des membres + fields: ["roles"], // Peut modifier les rôles + min_sig_member: 1.0, // Tous les devices + } + ], + }, + "validator": RoleDefinition { + members: [bob_id, carol_id], + validation_rules: [ + ValidationRule { + quorum: 0.67, // 2/3 des membres + fields: ["contract", "amount"], + min_sig_member: 0.5, // 50% des devices + } + ], + }, +} +``` + +### 3.2 Processus de validation + +``` +┌──────────────────────┐ +│ Proposition d'état │ +└──────────┬───────────┘ + │ + ▼ +┌──────────────────────────┐ +│ Pour chaque champ modifié│ +└──────────┬───────────────┘ + │ + ▼ +┌─────────────────────────────┐ +│ Trouver les rôles applicables│ +└──────────┬──────────────────┘ + │ + ▼ +┌────────────────────────────────┐ +│ Vérifier le quorum │ +│ (proportion de membres) │ +└──────────┬─────────────────────┘ + │ + ▼ +┌────────────────────────────────┐ +│ Pour chaque membre validant: │ +│ Vérifier min_sig_member │ +│ (proportion de devices) │ +└──────────┬─────────────────────┘ + │ + ▼ +┌────────────────────────────────┐ +│ Vérifier les signatures Schnorr│ +└──────────┬─────────────────────┘ + │ + ▼ + ✅ VALIDE ou ❌ REJETÉ +``` + +### 3.3 Signatures cryptographiques + +**Type:** Schnorr (BIP340) sur secp256k1 + +```rust +Proof { + signature: [u8; 64], // Signature Schnorr + public_key: PublicKey, // Clé publique (33 bytes) + message: [u8; 32], // state_id +} +``` + +**Messages signés:** + +- **ValidationYes** : Approbation du state_id +- **ValidationNo** : Rejet du state_id + +**Génération:** + +```rust +let message_hash = state.get_message_hash(true)?; // true = yes +let proof = Proof::new(message_hash, spend_key); +state.validation_tokens.push(proof); +``` + +--- + +## 4. Communication réseau + +### 4.1 Architecture réseau + +``` +┌──────────────┐ WebSocket ┌──────────────┐ +│ Client A │◄──────────────────────────►│ sdk_relay │ +│ (WASM) │ │ (Rust) │ +└──────────────┘ └──────┬───────┘ + │ +┌──────────────┐ │ +│ Client B │◄──────────────────────────────────┤ +│ (WASM) │ │ +└──────────────┘ │ + ▼ + ┌───────────────┐ + │ Bitcoin Node │ + │ (RPC + ZMQ) │ + └───────────────┘ +``` + +### 4.2 Types de messages (AnkFlag) + +| Flag | Direction | Description | +|------|-----------|-------------| +| **Handshake** | Relay → Client | Synchronisation initiale (peers, processes) | +| **NewTx** | Relay → Clients | Transaction Bitcoin détectée | +| **Commit** | Client ↔ Relay | Demande/validation de commit on-chain | +| **Cipher** | Client ↔ Clients | Données chiffrées (via relay) | +| **Faucet** | Client → Relay | Demande de fonds (testnet) | +| **Sync** | Client ↔ Relay | Synchronisation d'état | + +### 4.3 Flux de commit + +``` +Client A Relay Client B + │ │ │ + │ 1. CommitMessage │ │ + │ (validation_tokens=[]) │ + ├─────────────────────►│ │ + │ │ 2. Broadcast │ + │ ├───────────────────►│ + │ │ │ + │ │ 3. Signature │ + │ │◄───────────────────┤ + │ │ │ + │ 4. CommitMessage │ │ + │ (validation_tokens= │ │ + │ [proof_A, proof_B]) │ + ├─────────────────────►│ │ + │ │ 5. Validation │ + │ │ is_valid() │ + │ │ │ + │ │ 6. Tx Bitcoin │ + │ │ (broadcast) │ + │ │ │ + │ 7. Confirmation │ 7. Confirmation │ + │◄─────────────────────┼───────────────────►│ +``` + +--- + +## 5. Stockage et persistance + +### 5.1 Niveaux de stockage + +| Couche | Type | Données | Chiffrement | +|--------|------|---------|-------------| +| **Blockchain** | Public | state_id (32 bytes) | ❌ Non | +| **sdk_storage** | Semi-privé | Données volumineuses | ✅ AES-256-GCM | +| **Local** | Privé | Wallet, clés | ✅ Device-local | + +### 5.2 Format PCD (Private Collaborative Data) + +``` +┌─────────────────────────┐ +│ Version: 0x01 │ +├─────────────────────────┤ +│ DataType: │ +│ 0 = FileBlob │ +│ 1 = JSON │ +├─────────────────────────┤ +│ Data (compressed zstd) │ +└─────────────────────────┘ +``` + +**Utilisation:** + +```rust +// Insertion +let mut pcd = Pcd::new(BTreeMap::new()); +pcd.insert_serializable("profile", &json!({"name": "Alice"}))?; + +// Récupération +let profile: Value = pcd.get_as_json("profile")?; +``` + +### 5.3 Chiffrement + +**Algorithme:** AES-256-GCM (AEAD) + +```rust +// Génération 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)?; + +// Stockage clé dans ProcessState +state.keys.insert("field_name", key.as_slice().try_into()?); +``` + +--- + +## 6. Sécurité + +### 6.1 Garanties cryptographiques + +| Menace | Protection | Mécanisme | +|--------|------------|-----------| +| **Usurpation d'identité** | ✅ | Signatures Schnorr obligatoires | +| **Modification non autorisée** | ✅ | Validation multi-signatures + quorum | +| **Replay attacks** | ✅ | state_id unique (inclut outpoint) | +| **Man-in-the-middle** | ✅ | Messages signés cryptographiquement | +| **Observation réseau** | ✅ | Chiffrement AES-256-GCM | +| **Perte d'un device** | ✅ | Multi-device pairing | + +### 6.2 Modèle de confiance + +**Ce qui est vérifié cryptographiquement:** + +- ✅ Identité des signataires (Silent Payment addresses) +- ✅ Intégrité des données (Merkle commitments) +- ✅ Ordre des états (chaîne UTXO Bitcoin) +- ✅ Consensus (validation multi-signatures) + +**Ce qui nécessite de la confiance:** + +- ⚠️ sdk_relay (peut censurer, pas falsifier) +- ⚠️ sdk_storage (peut refuser de servir, pas modifier) +- ⚠️ Blindbit (optimisation, pas sécurité critique) + +**Aucune confiance requise:** + +- ✅ Bitcoin Core node (vérification SPV possible) +- ✅ Autres participants (signatures vérifiables) + +### 6.3 Bonnes pratiques + +#### Configuration des rôles: + +```rust +// ✅ BON: Quorum élevé pour actions critiques +ValidationRule::new(0.67, vec!["roles"], 1.0) // 2/3 consensus + +// ❌ MAUVAIS: Quorum trop faible +ValidationRule::new(0.1, vec!["roles"], 0.1) // 10% seulement +``` + +#### Pairing: + +```rust +// ✅ BON: Au moins 2 devices +Member::new(vec![device1_addr, device2_addr]) + +// ⚠️ RISQUÉ: Un seul device (perte = perte d'accès) +Member::new(vec![device1_addr]) +``` + +#### Chiffrement: + +```rust +// ✅ BON: Données sensibles dans PCD privé +let private_data = json!({ "ssn": "123-45-6789" }); + +// ❌ MAUVAIS: Données sensibles en public +let public_data = json!({ "ssn": "123-45-6789" }); // Visible par tous! +``` + +--- + +## 7. Cas d'usage + +### 7.1 Gestion de contrats + +**Scénario:** Contrat de prestation entre une entreprise (3 signataires) et un client. + +**Rôles:** + +- **Owner** : Entreprise (quorum 67%) +- **Validator** : Service juridique (quorum 100%) +- **Client** : Lecture + signature (quorum 100%) + +**Flux:** + +1. Owner crée le processus avec le contrat +2. Validator valide le contrat +3. Client signe le contrat +4. Commit on-chain (preuve horodatée immuable) + +### 7.2 Signature électronique + +**Scénario:** Signature de documents par plusieurs parties. + +**Avantages 4NK:** + +- ✅ Horodatage Bitcoin (immuable) +- ✅ Multi-signatures cryptographiques +- ✅ Traçabilité complète (audit trail) +- ✅ Documents chiffrés (confidentialité) + +### 7.3 Identité décentralisée + +**Scénario:** Gestion d'identité multi-device avec révocation. + +**Fonctionnalités:** + +- Pairing/unpairing de devices +- Attestations cryptographiques (signatures) +- Révocation d'attestations (oblitération) +- Portabilité (export/import du wallet) + +### 7.4 Workflow d'approbation + +**Scénario:** Processus d'approbation de dépenses dans une entreprise. + +**Rôles:** + +- **Demandeur** : Crée la demande +- **Manager** : Valide < 1000€ +- **Directeur** : Valide ≥ 1000€ +- **Comptable** : Enregistre le paiement + +**Règles:** + +```rust +ValidationRule::new( + 1.0, // 100% consensus + vec!["amount", "beneficiary"], // Champs concernés + 0.5 // 50% des devices du membre +) +``` + +--- + +## 8. Architecture technique + +### 8.1 Stack technologique + +| Composant | Technologie | Rôle | +|-----------|-------------|------| +| **sdk_common** | Rust (WASM-ready) | Types partagés, logique métier | +| **sdk_client** | Rust → WASM | Bibliothèque cliente pour navigateurs | +| **sdk_relay** | Rust + Tokio + Tungstenite | Relais WebSocket | +| **sdk_storage** | Rust + Actix-web | Stockage clé-valeur HTTP | +| **ihm_client** | TypeScript + Web Components | Interface utilisateur | +| **Bitcoin Core** | C++ | Node Bitcoin (RPC + ZMQ) | +| **Blindbit** | Rust | Filtres BIP158 (optimisation scanning) | + +### 8.2 Dépendances clés + +```toml +[dependencies] +sp_client = "0.2" # Silent Payments +bitcoin = "0.30" # Bitcoin primitives +secp256k1 = "0.27" # Cryptographie EC +tokio-tungstenite = "0.20" # WebSocket async +serde = "1.0" # Sérialisation +zstd = "0.12" # Compression +aes-gcm = "0.10" # Chiffrement +rs-merkle = "1.4" # Merkle trees +``` + +### 8.3 Flux de compilation + +``` +┌──────────────┐ +│ Rust Code │ +│ (sdk_client) │ +└──────┬───────┘ + │ + ▼ wasm-pack build --target web +┌──────────────────────┐ +│ WebAssembly Module │ +│ + JS Bindings │ +└──────┬───────────────┘ + │ + ▼ npm install +┌──────────────────────┐ +│ ihm_client │ +│ (TypeScript) │ +└──────────────────────┘ +``` + +--- + +## 9. Métriques de performance + +### 9.1 Taille des données + +| Élément | Taille | Localisation | +|---------|--------|--------------| +| **state_id** | 32 bytes | On-chain (OP_RETURN) | +| **Signature Schnorr** | 64 bytes | Off-chain (validation_tokens) | +| **ProcessState sérialisé** | ~500 bytes - 50 KB | Off-chain (sdk_storage) | +| **Transaction Bitcoin** | ~250 bytes | On-chain | + +### 9.2 Coûts Bitcoin + +| Opération | Coût (testnet) | Coût (mainnet) | +|-----------|----------------|----------------| +| **Création Process** | ~2500 sats | Variable (frais réseau) | +| **Update Process** | ~2500 sats | Variable (frais réseau) | +| **Oblitération** | ~2500 sats | Variable (frais réseau) | + +**Note:** Frais mainnet dépendent du feerate (sat/vB). + +### 9.3 Latence réseau + +| Opération | Latence typique | +|-----------|-----------------| +| **Connexion WebSocket** | < 100 ms | +| **Handshake** | < 500 ms | +| **Commit proposal** | < 200 ms | +| **Accumulation signatures** | 1-5 secondes | +| **Broadcast Bitcoin** | < 1 seconde | +| **Confirmation on-chain** | 10 minutes (1 bloc) | + +--- + +## 10. Roadmap et évolutions futures + +### 10.1 Court terme (Q4 2025) + +- ✅ Optimisation scanning Silent Payments (Blindbit v2) +- ✅ Multi-relays (connexions simultanées) +- ✅ Rate limiting sur sdk_relay +- ✅ Hardware wallet support (Ledger, Trezor) + +### 10.2 Moyen terme (2026) + +- 🔄 Gossip protocol P2P (résilience réseau) +- 🔄 Recovery social (M-of-N recovery) +- 🔄 Taproot multi-signatures (MuSig2) +- 🔄 Lightning Network integration + +### 10.3 Long terme (2027+) + +- 🚀 Zero-knowledge proofs (privacy) +- 🚀 Cross-chain bridges (Liquid, other L2) +- 🚀 Decentralized PKI (web of trust) +- 🚀 Smart contracts (Simplicity, Bitcoin L2) + +--- + +## Conclusion + +Le système 4NK offre une infrastructure décentralisée complète pour: + +✅ **Identité souveraine** : Contrôle total des clés, multi-device +✅ **Collaboration sécurisée** : Processus à états avec validation distribuée +✅ **Auditabilité** : Traçabilité Bitcoin immuable +✅ **Confidentialité** : Chiffrement bout-en-bout +✅ **Résilience** : Pas de point de défaillance unique + +**Points forts:** + +- Architecture élégante (identité = cryptographie Bitcoin) +- Pas de serveur central de confiance +- Interopérabilité Bitcoin native +- Flexibilité des rôles et permissions + +**Défis restants:** + +- Performance du scanning SP (amélioration continue) +- UX du pairing (simplification nécessaire) +- Adoption (éducation des utilisateurs) +- Coûts mainnet (optimisation des frais) + +--- + +**Document complet:** [4NK_IDENTITY_AND_PROCESS_SPEC.md](./4NK_IDENTITY_AND_PROCESS_SPEC.md) +**Code source:** [GitHub 4NK](https://git.4nkweb.com/4nk/) +**Contact:** dev@4nkweb.com +