anchorage_layer_simple/docs/PAIRING_PUBLIC_KEY_ENCODING.md
ncantu 497bcf0819 Add real service contract for website-skeleton and improve iframe styling
**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)
2026-01-28 17:28:50 +01:00

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 :

  1. Le pair doit être publié sur un relais avant le pairing
  2. Il faut un mécanisme pour le récupérer par UUID (qui n'existe pas)
  3. 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.publicKey et 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 appareil
  • PairingSetupBlock.tsx : Saisie des mots du 2ème appareil
  • PairManagementScreen.tsx : Affichage des mots de la clé publique

ECDH et pairing

La clé publique extraite des mots est :

  1. Stockée automatiquement dans PairConfig.publicKey
  2. Utilisée pour ECDH lors du pairing (publishPairingMessage)
  3. Récupérée depuis les signatures si nécessaire (fallback)

Flux de pairing

Device 1 (premier appareil)

  1. Génère un UUID pour le pair local
  2. Encode la clé publique de son identité en 17 mots BIP32
  3. Affiche les mots pour le device 2
  4. Reçoit les mots du device 2
  5. Décode les mots pour obtenir la clé publique du device 2
  6. Crée le pair distant avec cette clé publique
  7. Utilise la clé publique pour ECDH lors du pairing

Device 2 (second appareil)

  1. Génère un UUID pour le pair local
  2. Encode la clé publique de son identité en 17 mots BIP32
  3. Affiche les mots pour le device 1
  4. Reçoit les mots du device 1
  5. Décode les mots pour obtenir la clé publique du device 1
  6. Crée le pair distant avec cette clé publique
  7. 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) :

  1. Les pairs locaux peuvent être régénérés avec la nouvelle méthode
  2. Les pairs distants doivent être re-pairés avec les nouveaux mots (17 mots)
  3. L'ancien format (8 mots) n'est plus supporté

Références

  • userwallet/src/utils/bip32.ts : Fonctions d'encodage/décodage
  • userwallet/src/utils/pairing.ts : Logique de pairing
  • userwallet/src/services/pairingConfirm.ts : Confirmation de pairing avec ECDH
  • userwallet/src/components/PairingDisplayScreen.tsx : Interface de pairing
  • userwallet/src/components/PairingSetupBlock.tsx : Configuration de pairing