# UserWallet — Dérivation de clés et clés multiples par pair **Author:** Équipe 4NK **Date:** 2026-02-02 **Version:** 1.0 ## Objectif Permettre à un pair (identité locale ou appareil distant) d’avoir **plusieurs clés publiques** et de **dériver** de nouvelles paires de clés de façon déterministe à partir d’une clé privée. Vérifier rapidement si une clé publique donnée « appartient » à une clé privée (clé principale ou l’une des clés dérivées). ## Modèle de données ### PairConfig - **`publicKey?: string`** — Clé publique principale (hex 66 caractères). Utilisée pour ECDH, pairing, etc. - **`publicKeys?: string[]`** — Liste optionnelle de clés publiques supplémentaires. Un pair « possède » toute clé dans `{ publicKey } ∪ publicKeys`. Un pair peut donc avoir un nombre important de clés publiques différentes (principale + dérivées ou ajoutées). ## Dérivation déterministe (crypto) Une seule clé privée permet d’obtenir plusieurs paires (clé privée enfant, clé publique enfant) sans stocker plusieurs secrets. La dérivation est **déterministe** : même index ⇒ même paire. ### Algorithme - **Entrée** : clé privée parente (64 hex), index ≥ 0. - **Procédé** : HMAC-SHA256(clé_privée_parente, `"userwallet-derive-v1-"` + index) → 32 octets ; réduction modulo (ordre de la courbe secp256k1 − 1) + 1 pour obtenir un scalaire valide ; clé publique = multiplication du point de base par ce scalaire (format compressé). - **Sortie** : paire (clé privée enfant, clé publique enfant). Courbe : secp256k1 (même que Bitcoin). La clé principale (index « aucun ») est la clé publique dérivée directement de la clé privée de l’identité. ### API (userwallet) | Fonction | Rôle | |----------|------| | `deriveChildKeyPair(parentPrivateKeyHex, index)` | Retourne la paire (privée, publique) pour l’index donné. | | `getDerivedPublicKeys(parentPrivateKeyHex, count)` | Retourne [clé principale, dérivée(0), …, dérivée(count−1)]. Longueur = 1 + count. | | `publicKeyBelongsToIdentity(identityPrivateKeyHex, publicKeyHex, maxDerived?)` | Vrai si la clé publique est la clé principale ou l’une des dérivées d’indice 0..maxDerived−1. Par défaut maxDerived = 0 (seule la clé principale est testée). | **Performance** : la vérification « cette clé appartient-elle à mon identité ? » est en O(1) pour la clé principale (une dérivation + comparaison). Pour les dérivées, au plus `maxDerived` dérivations + comparaisons ; en pratique on borne `maxDerived` pour rester rapide. ## Pairing (pairs et multi-clés) | Fonction | Rôle | |----------|------| | `getPairPublicKeys(pair, identityPrivateKeyHex?, derivedCount?)` | Liste toutes les clés publiques du pair. Pour le pair local + clé privée fournie : clé principale + dérivées 0..derivedCount−1. Pour un pair distant : `publicKey` + `publicKeys`. | | `pairContainsPublicKey(pair, publicKeyHex, identityPrivateKeyHex?, maxDerived?)` | Vrai si le pair possède cette clé (locale : dérivation bornée ; distant : test d’appartenance à `publicKey` / `publicKeys`). | | `addPairPublicKey(pairUuid, publicKeyHex)` | Ajoute une clé à `publicKeys` du pair (sans doublon avec `publicKey`). | ## Fichiers concernés - `userwallet/src/utils/crypto.ts` : `deriveChildKeyPair`, `getDerivedPublicKeys`, `publicKeyBelongsToIdentity` - `userwallet/src/utils/pairing.ts` : `getPairPublicKeys`, `pairContainsPublicKey`, `addPairPublicKey` - `userwallet/src/types/identity.ts` : `PairConfig.publicKeys` ## Usage typique - **Obtenir N clés dérivées** : `getDerivedPublicKeys(identity.privateKey, N)`. - **Vérifier qu’une clé appartient à l’identité** (avec au plus 100 dérivées) : `publicKeyBelongsToIdentity(identity.privateKey, somePubKey, 100)`. - **Vérifier qu’un pair possède une clé** : `pairContainsPublicKey(pair, somePubKey, identity?.privateKey, 100)`.