**Motivations:** - website-skeleton needs a real service contract with valid UUIDs and validators - Service wallet required for production use with configurable public key - Iframe styling needs improvement to remove scrollbars and match UserWallet theme **Root causes:** - DEFAULT_VALIDATEURS used placeholder public key that cannot verify signatures - No service wallet generation script for production deployment - Iframe had fixed height causing scrollbars and visual mismatch with dark theme **Correctifs:** - Created real service contract in src/serviceContract.ts with dedicated UUIDs (skeleton-service-uuid-4nkweb-2026) - Added service wallet generation script (generate-service-wallet.mjs) with .env and .env.private files - Improved iframe container styling: increased height (800px), dark background (#1a1a1a), better shadows, hidden scrollbars - Added .env.private to .gitignore for security **Evolutions:** - Service contract automatically loaded on startup and sent to UserWallet iframe - Public key configurable via VITE_SKELETON_SERVICE_PUBLIC_KEY environment variable - Added npm script 'generate-wallet' for easy wallet generation - Enhanced iframe visual integration with UserWallet dark theme **Pages affectées:** - website-skeleton/src/serviceContract.ts (new) - website-skeleton/src/config.ts - website-skeleton/src/main.ts - website-skeleton/generate-service-wallet.mjs (new) - website-skeleton/index.html - website-skeleton/package.json - website-skeleton/.gitignore - website-skeleton/.env (new) - website-skeleton/.env.private (new)
6.4 KiB
6.4 KiB
Pairing : Encodage de la clé publique dans les mots BIP32
Author: Équipe 4NK
Date: 2026-01-28
Version: 1.0
Problème identifié
Question initiale
Si les mots BIP32 encodent l'UUID du pair, cela implique que :
- Le pair a déjà été créé et publié sur un relais
- Il faut récupérer le pair depuis le relais pour obtenir sa clé publique
- Mais lors du pairing initial, le pair n'existe pas encore sur le relais
Problème technique
Il n'existe pas de mécanisme pour récupérer un pair par UUID sur un relais. Les relais permettent uniquement de :
- Récupérer des messages par hash :
GET /messages/:hash - Récupérer des messages par fenêtre temporelle :
GET /messages?start=&end=
Il n'y a pas d'endpoint GET /pairs/:uuid ou équivalent.
Conséquence
Si les mots encodent l'UUID du pair :
- Le pair doit être publié sur un relais avant le pairing
- Il faut un mécanisme pour le récupérer par UUID (qui n'existe pas)
- Le pairing initial devient impossible sans publication préalable
Solution implémentée
Principe
Les mots BIP32 encodent maintenant directement la clé publique de l'identité (66 hex = 33 bytes) au lieu de l'UUID du pair.
Avantages
- ✅ Pas besoin de récupérer quoi que ce soit depuis un relais
- ✅ La clé publique est disponible immédiatement (elle fait partie de l'identité)
- ✅ Les mots peuvent être échangés directement entre les deux devices
- ✅ La clé publique est stockée dans
PairConfig.publicKeyet utilisée pour ECDH - ✅ Le pairing initial fonctionne sans publication préalable
Format
- Clé publique : 66 caractères hex (33 bytes)
- Encodage : 17 mots BIP32
- 16 mots pour les 32 premiers bytes (2 bytes par mot)
- 1 mot pour le dernier byte (33ème byte, padding avec 0)
Modifications techniques
Nouvelles fonctions (userwallet/src/utils/bip32.ts)
/**
* Convert public key (hex, 66 chars) to BIP32 word list.
* Public key is 33 bytes. Each word encodes 2 bytes (16 bits), so we need 17 words.
* Last word encodes only 1 byte (the 33rd byte), so we pad with 0.
*/
export function publicKeyToBip32Words(publicKey: string): string[]
/**
* Convert BIP32 word list back to public key (hex, 66 chars).
* Expects 17 words: 16 words for 32 bytes + 1 word for the last byte.
*/
export function bip32WordsToPublicKey(words: string[]): string | null
Modifications du pairing (userwallet/src/utils/pairing.ts)
createLocalPair()
Avant :
- Génère un UUID
- Encode l'UUID en mots BIP32 (8 mots)
Maintenant :
- Génère un UUID pour le pair
- Encode la clé publique de l'identité en mots BIP32 (17 mots)
- Stocke la clé publique dans
PairConfig.publicKey
addRemotePairFromWords()
Avant :
- Décode les mots pour obtenir l'UUID du pair
- Clé publique optionnelle (fournie séparément)
Maintenant :
- Décode les mots pour obtenir directement la clé publique
- Génère un UUID pour le pair localement
- Stocke automatiquement la clé publique dans
PairConfig.publicKey
ensureLocalPairForSetup()
Avant :
- Retourne les mots de l'UUID du pair local
Maintenant :
- Nécessite la clé publique de l'identité en paramètre
- Retourne les mots de la clé publique
parseAndValidatePairingWords()
Avant :
- Valide 8 mots
- Vérifie qu'ils décodent un UUID valide
Maintenant :
- Valide 17 mots
- Vérifie qu'ils décodent une clé publique valide (préfixe 02/03/04)
Modifications de l'interface utilisateur
Messages d'erreur
- Avant : "Mots invalides. 8 mots requis."
- Maintenant : "Mots invalides. 17 mots requis."
Composants affectés
PairingDisplayScreen.tsx: Saisie des mots du 1er appareilPairingSetupBlock.tsx: Saisie des mots du 2ème appareilPairManagementScreen.tsx: Affichage des mots de la clé publique
ECDH et pairing
La clé publique extraite des mots est :
- Stockée automatiquement dans
PairConfig.publicKey - Utilisée pour ECDH lors du pairing (
publishPairingMessage) - Récupérée depuis les signatures si nécessaire (fallback)
Flux de pairing
Device 1 (premier appareil)
- Génère un UUID pour le pair local
- Encode la clé publique de son identité en 17 mots BIP32
- Affiche les mots pour le device 2
- Reçoit les mots du device 2
- Décode les mots pour obtenir la clé publique du device 2
- Crée le pair distant avec cette clé publique
- Utilise la clé publique pour ECDH lors du pairing
Device 2 (second appareil)
- Génère un UUID pour le pair local
- Encode la clé publique de son identité en 17 mots BIP32
- Affiche les mots pour le device 1
- Reçoit les mots du device 1
- Décode les mots pour obtenir la clé publique du device 1
- Crée le pair distant avec cette clé publique
- Utilise la clé publique pour ECDH lors du pairing
Comparaison avant/après
Avant (UUID)
Mots → UUID du pair → Besoin de récupérer le pair depuis un relais
→ Problème : pas d'endpoint pour récupérer par UUID
→ Problème : le pair n'existe pas encore sur le relais
Maintenant (Clé publique)
Mots → Clé publique directement → Stockée dans PairConfig.publicKey
→ Utilisée pour ECDH
→ Pas besoin de relais
Impact
Positif
- ✅ Pairing initial fonctionne sans publication préalable
- ✅ Pas de dépendance à un relais pour le pairing
- ✅ Clé publique disponible immédiatement
- ✅ ECDH fonctionne dès le pairing
Changements nécessaires
- ⚠️ Les mots passent de 8 à 17 mots
- ⚠️ Les anciens pairs avec mots UUID ne sont plus compatibles
- ⚠️ Migration nécessaire si des pairs existent déjà
Migration
Si des pairs existent déjà avec l'ancien format (UUID) :
- Les pairs locaux peuvent être régénérés avec la nouvelle méthode
- Les pairs distants doivent être re-pairés avec les nouveaux mots (17 mots)
- L'ancien format (8 mots) n'est plus supporté
Références
userwallet/src/utils/bip32.ts: Fonctions d'encodage/décodageuserwallet/src/utils/pairing.ts: Logique de pairinguserwallet/src/services/pairingConfirm.ts: Confirmation de pairing avec ECDHuserwallet/src/components/PairingDisplayScreen.tsx: Interface de pairinguserwallet/src/components/PairingSetupBlock.tsx: Configuration de pairing