**Motivations:** - Implement BIP39 mnemonic import for identity creation - Add password-based key protection for enhanced security - Improve pairing workflow with QR code and URL display - Migrate hash cache from LocalStorage to IndexedDB for better scalability - Update signet-dashboard and mempool components **Root causes:** - N/A (feature implementations) **Correctifs:** - N/A (no bug fixes in this commit) **Evolutions:** - BIP39 mnemonic import: Support for 12/24 word English mnemonics with BIP32 derivation path m/44'/0'/0'/0/0 - Key protection: Password-based encryption of private keys at rest with unlock/lock functionality - Pairing workflow: QR code and URL display for device pairing, form-based word exchange between devices - IndexedDB migration: Hash cache moved from LocalStorage to IndexedDB to avoid size limitations - Global action bar: URL parameter support for navigation - Pairing connection: Enhanced pairing status management **Pages affectées:** - userwallet/src/utils/identity.ts - userwallet/src/utils/keyProtection.ts - userwallet/src/utils/sessionUnlockedKey.ts - userwallet/src/utils/indexedDbStorage.ts - userwallet/src/utils/cache.ts - userwallet/src/utils/pairing.ts - userwallet/src/components/UnlockScreen.tsx - userwallet/src/components/PairingDisplayScreen.tsx - userwallet/src/components/PairingSetupBlock.tsx - userwallet/src/components/GlobalActionBar.tsx - userwallet/src/components/HomeScreen.tsx - userwallet/src/components/ImportIdentityScreen.tsx - userwallet/src/components/DataExportImportScreen.tsx - userwallet/src/hooks/useIdentity.ts - userwallet/src/hooks/usePairingConnected.ts - userwallet/src/services/syncService.ts - userwallet/src/services/pairingConfirm.ts - userwallet/src/App.tsx - userwallet/package.json - userwallet/docs/specs.md - userwallet/docs/storage.md - userwallet/docs/synthese.md - signet-dashboard/public/*.html - signet-dashboard/public/app.js - signet-dashboard/public/styles.css - mempool (submodule updates) - hash_list.txt, hash_list_cache.txt, utxo_list.txt, utxo_list_cache.txt, fees_list.txt - features/*.md (documentation files)
64 KiB
Synthèse
- Modèle : Messages publiés sans signatures ni clés ; signatures et clés publiées séparément ; tout adressé par hash canonique ; récupération par GET uniquement (pull).
- Objets : Service, Contrat, Champ, Action, ActionLogin, Membre, Pair, MessageBase, Hash, Signature, Validateurs, MsgChiffre, MsgSignature, MsgCle.
- Graphe : Service → Contrat → Champ → Action(login) → Membre → Pair ; contraintes « au moins 1 parent ».
- Pairing : UUID pair ↔ mots BIP32 ; pairing obligatoire pour login.
- Écrans : accueil, création/import identité, relais, pairing, sync, services, chemin login, challenge, signatures mFA, publication, résultat.
- Machine à états : S_INIT → S_HOME, S_SYNC_GLOBAL, S_PAIR_, S_LOGIN_, etc., avec erreurs récupérables / fatales.
Lister les étapes et ecran d'un login basé sur ce principe :
- Génération de cles secp256k1 pour signer et vérifier les signatures
- login sans serveur central par verification de conformité contrat / signature
- pairing obligatoire pour se connecter (mFA)
Contrat d'identié avec types name: au moins
Service: Contrat Type names chiffrés dont service
Contrat : Message à valider types name chiffrés dont contrat
Champ : Message à valider types name chiffrés dont champ
- contrats parents uuid, au mois 1
ActionLogin: Action Types names chiffrés dont login
Action: Message à valider types name chiffrés dont action
- Auteurs de l'action
- contrats parents uuid, au moins 1
Objets créés lors de la création :
Lors de la création d'un Pair :
- Création automatique d'un Pair (MessageBase avec types_names_chiffres incluant "pair")
- Le Pair doit être associé à au moins un Membre (membres_parents_uuid, au moins 1)
Lors de la création d'un Membre :
- Création automatique d'un Membre (MessageAValider avec types_names_chiffres incluant "membre")
- Le Membre doit être associé à au moins une Action (actions_parents_uuid, au moins 1)
Lors de la création d'un contrat de login d'un Service :
- Création automatique d'un Contrat (MessageAValider avec types_names_chiffres incluant "contrat")
- Création automatique d'une ActionLogin (Action avec types_names_chiffres incluant "login")
- Création automatique d'un Membre (MessageAValider avec types_names_chiffres incluant "membre")
- L'ActionLogin est associée au Contrat (contrats_parents_uuid incluant l'UUID du Contrat)
- Le Membre est associé à l'ActionLogin (actions_parents_uuid incluant l'UUID de l'ActionLogin)
- Le nom du contrat de login est passé en paramètre initial à l'iframe ou au site, par défaut "default"
Membre : Message à valider types name chiffrés dont membre Actions parents uuid, au moins 1
Pair : MessageBase Types names chiffrés dont pair Membres parents uuid, au moins 1
Message Base: Hash du JSON sans le hash, sans la signature uuid Version Types names chiffrés dont pair Clés de chiffrement avec tous les paramètres et l'algo Datajson dont les attributs :
- Obligatoires : services uuid, types uuid
- optionnels :label, description longue, description courte, photo, image, bannière, URL, paragraphes (couples de textes + images), tarif Timestpamp Liste de relais (IP) Hash du JSON signé du pair avec dans la signature le hash, la clé publique et la signature Version logicielle
Hash :
- Hash du JSON (sans le hash, sans les signatures, sans clés de chiffrement)
- Algo
Signature :
- hash
- clé publique
- signature cryptographique
- Nonce et autre matériel éventuel
Message à valider :
- MessageBase +
- Validateurs du message
Validateurs: Listes des membres du role, au moins 1
- Pour chacun des membres : la liste des signatures obligatoires des autres membres et/ou de lui même
Message individuel de déchiffrement :
- hash du message
- clé de chiffrement du message chiffré: + clé de chiffrement chiffrée avec tous le paramètres et algo
- df : + diffie-hellman à scanner contenant une clé de déchiffrement de la clé de déchiffrement dans le secret partagé
Message de signature :
- Signature
Les messages sont postés sans les signatures et sans les clés de chiffrement, les signatures et les cles sont postées spécifiquement après. Les messages sont tous envoyés chiffrés de type:
- hash
- Message chiffré
- datajson public
LEs signatures et les clés de chiffrement ne sont pas récupérées au get elles sont récupérées spécifiquement apres et ajoutés aux messages stockés
Tous les envois passent par des relais qui stockent et relaient entre relais (sauvegarde des hash pour ne pas relayer ceux déjà reçus) Périodiquement et par services les client font des cet pour récupérer les informations
Chacun publie pour tous sans destinataire indiqué mais chiffré. Mais un diffie hellman est possible avec tous les pairs concernés pour d'échanger par la suite des clés de déchiffrement entre clé publiques, ce matériel exploitable que par les parties concernées est envoyé lors des échanges de clés
Pour ajouter un uuid d'un pair à un un membre celui ci est converti via bip32 en une liste de mots puis reconstitué (device 2 affiche les mots, device les saisis), ainsi l'uuid est une clé qui ne sert que d'identifiant
Pour se logguer il faut founir des signatures des pairs attendues dans l'action de type login de ce membre ayant dans ses services parents uuid l'uuid du service sur lequel il veut se connecter
Pour savoir si il y a un message à récupérer et déchiffrer il faut récupérer et scanner tous (depuis la date anniversaire de création des clés)les messages de clés depuis (proposer un bloom filtrer et/ou des arbres de merkle pur gérer l'historique des hash et ne pas tout rescanner) aucun message n'est reçu ils sont tous récupérés (get) en fonction des deffie hellman
Introduction Ce qui suit décrit, de manière opérationnelle, les étapes et les écrans d’un login fondé sur des clés secp256k1, une validation “sans serveur central” (conformité des contrats et signatures), et un pairing obligatoire jouant le rôle de second facteur. La description suppose un réseau de relais stockant et relayant des objets immuables adressés par hash, avec séparation stricte entre messages, signatures et clés de chiffrement, récupérées par appels dédiés.
Principes structurants à respecter à chaque étape Séparation des flux et des objets
- Un message “métier” est publié sans signatures et sans clés de chiffrement.
- Les signatures sont publiées ensuite, séparément, via des objets “Message de signature”.
- Les clés (ou matériels) de déchiffrement sont publiées ensuite, séparément, via des objets “Message individuel de déchiffrement”.
- Les requêtes de récupération ne renvoient pas automatiquement signatures et clés ; elles sont récupérées explicitement et rattachées localement au message stocké.
Adressage et immutabilité
- Tout objet est adressé par hash (hash du JSON canonique “sans hash, sans signatures, sans clés de chiffrement” selon la règle donnée).
- Un relais conserve l’historique des hash reçus pour ne pas relayer deux fois.
Confidentialité “publish to all”
- Tout est publié sans destinataire explicite.
- Le contenu utile est chiffré ; seuls les pairs capables d’obtenir (ou de dériver) la clé de déchiffrement peuvent lire.
- Les échanges de matériels de déchiffrement peuvent s’appuyer sur Diffie-Hellman (ECDH secp256k1) entre clés publiques concernées ; le “matériel DH” est publiable car inexploitable par les tiers.
Conformité “contrat / signature”
- La “vérité” d’un login provient de la vérification locale d’un graphe de contrats (service → contrat → champ → action → membre → pair) et de la satisfaction des validateurs (signatures requises, rôles, multi-signatures).
Pairing obligatoire (mFA)
- Sans association préalable d’au moins un “pair” (device/instance), aucune session n’est autorisée.
- L’ajout de l’UUID d’un pair à un membre se fait par conversion BIP32 en mots affichés/saisis pour limiter les erreurs et éviter l’échange brut d’identifiants.
Objets et contraintes à refléter dans l’UX (rappel synthétique) Les écrans doivent permettre de construire, vérifier et exploiter ces objets et liens (UUID “parents” au moins 1 partout où requis).
Service
- Contrat
- Types names chiffrés dont “service”
Contrat
- Message à valider
- Types names chiffrés dont “contrat”
Champ
- Message à valider
- Types names chiffrés dont “champ”
- Contrats parents UUID, au moins 1
ActionLogin
- Action
- Types names chiffrés dont “login”
Action
- Message à valider
- Types names chiffrés dont “action”
- Validateurs de l’action
- Contrats parents UUID, au moins 1
Membre
- Message à valider
- Types names chiffrés dont “membre”
- Actions parents UUID, au moins 1
Pair
- MessageBase
- Types names chiffrés dont “pair”
- Membres parents UUID, au moins 1
MessageBase
-
Hash du JSON sans le hash, sans la signature
-
UUID
-
Version
-
Types names chiffrés dont “pair” (et plus généralement le type de l’objet)
-
Clés de chiffrement avec paramètres et algo
-
Datajson
- obligatoires : services UUID, types UUID
- optionnels : label, descriptions, médias, URL, paragraphes, tarif
-
Timestamp
-
Liste de relais (IP)
-
Hash du JSON signé du pair, avec dans la signature : hash + clé publique + signature
-
Version logicielle
Hash
- Hash du JSON (sans hash, sans signatures, sans clés de chiffrement)
- Algo
Signature
- Hash
- Clé publique
- Signature cryptographique
- Nonce et matériel éventuel
Message à valider
- MessageBase
- Validateurs du message
Validateurs
- Liste des membres du rôle, au moins 1
- Pour chacun : liste des signatures obligatoires (lui-même et/ou autres membres)
Message individuel de déchiffrement
- Hash du message
- Clé de chiffrement du message chiffré, incluant une clé de chiffrement chiffrée avec paramètres et algo
- Matériel DH à scanner contenant une clé de déchiffrement (dans le secret partagé)
Message de signature
- Signature
Écrans et parcours, de bout en bout Écran d’accueil Objectif
- Démarrer une session locale, présenter l’état du wallet d’identité (clés, pairs, cache), proposer connexion ou onboarding.
Éléments affichés
- Statut “identité locale présente / absente”
- Empreinte courte de la clé publique principale (secp256k1), si existante
- Statut “pairing requis : non satisfait / satisfait”
- Statut réseau relais : atteignables, latence, dernier sync, file d’objets en attente
- Boutons : Créer identité, Importer identité, Se connecter, Gérer pairs, Paramètres relais, Synchroniser maintenant
Écran de création d’identité locale Objectif
- Générer la paire de clés secp256k1 (signature) et initialiser les paramètres de chiffrement.
Actions
- Génération clé privée secp256k1
- Dérivation clé publique secp256k1
- Éventuelle dérivation de sous-clés (BIP32) si vous utilisez un arbre pour identités/pairs/services
Champs et options
- Nom local de l’identité (purement local)
- Option de protection locale (PIN, biométrie, mot de passe) pour chiffrer la clé privée au repos
- Paramètres crypto par défaut (algorithmes symétriques, KDF, formats) pour “Clés de chiffrement avec tous les paramètres”
Sorties
- Identité locale créée
- Date “anniversaire de création des clés” enregistrée (sert de point de départ de scan)
- Cache local initialisé (index des hash vus, index services/types, index ECDH)
Écran d’import d’identité Objectif
- Restaurer la clé privée (ou seed BIP32) et les métadonnées locales nécessaires.
Actions
- Import seed / clé privée
- Recalcul clé publique
- Réindex local minimal
Contrôles
- Vérifier cohérence clé publique dérivée
- Vérifier format/versions
Écran de gestion des relais Objectif
- Déclarer la liste de relais, tester, prioriser, et configurer la stratégie de synchronisation.
Champs
- Liste de relais (IP ou endpoints)
- Stratégie : périodicité, par services, par fenêtres temporelles
- Paramètres anti-resscan : Bloom filter, Merkle trees (optionnel), taille de cache de hash
Actions
- Test connectivité
- Mise à jour de la liste et sauvegarde locale
Écran de pairing (obligatoire avant login) Objectif
- Associer au moins un pair à un membre, via procédure robuste “mots BIP32”, pour fournir le second facteur.
Pré-requis conceptuel
- Un pair est un objet rattaché à un ou plusieurs membres (Membres parents UUID ≥ 1).
- L’association se matérialise par la publication d’objets (selon votre modèle) où l’UUID du pair est présent dans le graphe du membre, et validé par les signatures attendues.
Sous-écran “ajouter un pair” Deux modes pratiques
-
Mode “ce device devient un pair”
- Générer/attribuer un UUID pair local
- Afficher la séquence de mots BIP32 dérivée de cet UUID
-
Mode “associer un pair existant”
- Saisir les mots BIP32 affichés par l’autre device
- Reconstituer l’UUID pair
- Préparer la publication des messages nécessaires pour lier ce pair au membre
Contrôles
- Vérification de saisie (checksum/wordlist)
- Vérification que le pair n’est pas déjà associé
- Vérification que le membre cible est connu (ou possibilité de le découvrir via sync)
Sorties
- UUID pair reconnu et enregistré localement
- Publication (ou préparation) des messages “pair” / “membre” nécessaires à l’association
- Mise en file des signatures et clés de chiffrement à publier séparément
Écran de synchronisation initiale (découverte) Objectif
- Récupérer et indexer l’ensemble des messages utiles pour construire le graphe et détecter ce qui est déchiffrable.
Contraintes imposées par votre modèle “publish to all”
- Aucun message n’est “reçu” : tout est “récupéré (get)” puis filtré localement.
- Pour détecter un message déchiffrable, il faut scanner les messages de clés depuis la date anniversaire de création des clés (ou depuis le dernier checkpoint).
Éléments affichés
- Fenêtre temporelle de scan (début = date anniversaire / dernier checkpoint, fin = maintenant)
- Compteurs : messages récupérés, hash nouveaux, hash déjà vus, signatures en attente de fetch, clés en attente de fetch
- Indicateur Bloom/Merkle : actif/inactif, taux de faux positifs (si Bloom), profondeur/segments (si Merkle)
- Liste des services découverts (via datajson.services UUID) et types UUID
Actions
- Synchroniser maintenant
- Affiner par service
- Construire/mettre à jour l’index Merkle ou Bloom côté client
- Exporter un checkpoint local (hash racine Merkle, ou bitset Bloom) si utile
Étapes techniques de sync côté client
- GET messages chiffrés “hash + message chiffré + datajson public” depuis relais, filtrés par période et/ou service
- Déduplication par hash (cache local + cache relais)
- Pour chaque message potentiel : tenter d’identifier la nécessité d’une clé (via type UUID, service UUID, et index ECDH)
- Fetch dédié des “Message individuel de déchiffrement” pertinents (par hash) et construction du matériel ECDH
- Déchiffrement, parsing JSON, calcul hash canonique, vérification cohérence “Hash du JSON sans hash…”
- Fetch dédié des “Message de signature” (par hash) et attachement local
- Vérification des signatures secp256k1 conformément aux validateurs du message
Écran de sélection du service Objectif
- Choisir le service (service UUID) sur lequel l’utilisateur veut s’authentifier.
Affichage
-
Liste des services disponibles (découverts localement)
-
Pour chaque service : statut de confiance
- “Contrat complet et valide”
- “Contrat incomplet (éléments manquants)”
- “Contrat invalide (hash/signature/validateurs non satisfaits)”
-
Option de rafraîchissement sync “par service”
Action
- Choisir un service → déclenche construction du chemin de validation login
Écran “construction du chemin login” Objectif
- Construire et afficher la chaîne d’objets nécessaires, puis calculer la liste exacte des signatures attendues.
Chaîne minimale attendue
- Service (service UUID)
- Contrat(s) rattachés
- Champs (au moins 1 champ avec contrats parents UUID)
- ActionLogin → Action de type login
- Membre (ayant actions parents UUID incluant l’action login)
- Pair(s) (ayant membres parents UUID incluant ce membre)
Travail du client
- Résoudre les liens par UUID parents, vérifier “au moins 1” partout où requis
- Vérifier les “types names chiffrés” : existence, déchiffrement si nécessaire, cohérence avec type UUID
- Pour chaque objet : recalcul hash canonique et comparer au hash déclaré
- Construire l’ensemble “validateurs” applicables à l’action login et au message de login
- Produire la matrice “signatures obligatoires” : qui doit signer quoi, et sous quelles clés publiques
Affichage conseillé
- Graphe ou liste hiérarchique (service → … → pair), avec statut vert/rouge par nœud
- Détail des signatures requises : membre(s) valideur(s), nombre minimal, dépendances “autres membres et/ou lui-même”
Écran “vérification du pairing requis” Objectif
- S’assurer que les pairs exigés par l’action login sont présents et activables localement.
Vérifications
- Les UUID de pairs attendus sont connus localement (ou récupérables)
- Chaque pair attendu peut produire une signature (donc la clé privée correspondante est accessible localement ou via device associé)
- Le mapping pair ↔ membre ↔ action login est valide et signé selon validateurs
Cas usuels
- Pair local unique : ce device signe
- Multi-pair : exiger au moins N signatures de pairs distincts (mFA renforcé)
- Pair distant : déclencher un flux “signer sur l’autre device” via procédure de partage (QR, mots, lien) sans serveur central, uniquement par publication de signatures
Écran “challenge / message à valider” Objectif
- Générer le “Message à valider” de la session de login, puis organiser sa signature et sa vérification.
Contenu minimal à préparer
- MessageBase complet (uuid, version, timestamp, types UUID, services UUID, relais, version logicielle, datajson public minimal)
- Hash canonique calculé selon règle
- Nonce de session et/ou matériel anti-rejeu dans “Signature” (nonce et autre matériel éventuel)
- Références explicites au service UUID cible
- Références explicites à l’action login UUID et au membre UUID (selon votre modèle), pour lier la preuve à l’intention
Affichage
- Résumé des attributs publics (service UUID, type UUID, timestamp, relais)
- Statut “détecté comme conforme au contrat : oui/non”
- Bouton “Signer” (désactivé si pairing non satisfait)
Écran “signature(s) mFA” Objectif
- Collecter les signatures requises, potentiellement depuis plusieurs pairs/devices.
Flux de signature
-
Pour le pair local
- Signer hash canonique secp256k1
- Produire objet “Message de signature” : hash + clé publique + signature + nonce/matériel
-
Pour les pairs distants
- Afficher un “paquet de demande de signature” (hash, contexte, paramètres)
- Sur l’autre device : vérifier contexte, signer, publier la signature
- Sur ce device : récupérer la signature via fetch dédié et l’attacher localement
Affichage
-
Liste des signatures attendues avec état
- “manquante”
- “reçue”
- “valide”
- “invalide” (mauvais hash, mauvaise clé publique, signature invalide)
-
Règles de validateurs satisfaites / non satisfaites, en temps réel
Écran “publication du login” Objectif
- Publier la preuve de login dans le réseau de relais, conformément à la règle “message d’abord, signatures ensuite, clés ensuite”.
Étapes d’émission côté client
-
Publier le message chiffré (objet contenant : hash + message chiffré + datajson public)
- Sans signatures
- Sans clés de chiffrement
-
Publier ensuite, séparément, les “Message de signature” nécessaires
-
Publier ensuite, séparément, les “Message individuel de déchiffrement” nécessaires (si d’autres parties doivent déchiffrer, par exemple le service ou un ensemble de validateurs)
-
Relais : propagation inter-relais, déduplication par hash
Affichage
- Liste des relais cibles, état de publication par relais
- Hash final de la preuve
- Statut “propagation suffisante” (par exemple M relais sur N ont confirmé stockage)
Écran “vérification côté service sans serveur central” Objectif
- Décrire ce que fait le “service” (ou l’application de service) pour accepter la session, en ne reposant que sur contrats + signatures.
Mécanique de vérification (côté service)
- Récupérer le message publié (par hash ou par scan périodique “par service”)
- Récupérer explicitement signatures associées
- Récupérer explicitement matériels de déchiffrement si nécessaire
- Déchiffrer, recalculer hash canonique, comparer
- Vérifier signatures secp256k1, clés publiques, nonces
- Rejouer la construction du graphe (service → … → action login → membre → pairs) depuis les UUID et messages disponibles
- Vérifier validateurs : liste des membres du rôle, signatures obligatoires, seuils
- Vérifier anti-rejeu : timestamp, nonce, fenêtre temporelle, unicité du hash/nonce
- Si OK : émettre un “jeton local” (non central) ou ouvrir une session locale ; sinon refuser
Écran “résultat de connexion” Objectif
- Donner un état explicite, traçable, et diagnostiquable.
États possibles
- Connecté : preuve acceptée
- Refusé : contrat incomplet
- Refusé : signatures insuffisantes
- Refusé : signature invalide
- Refusé : anti-rejeu déclenché (nonce déjà vu / timestamp hors fenêtre)
- Refusé : pairing requis non satisfait
- Refusé : impossibilité de récupérer signatures/clés après délai
Affichage recommandé
- Hash de la preuve
- Service UUID
- Liste des validateurs satisfaits / non satisfaits
- Journal succinct : quels objets manquaient (hash), quelles signatures manquaient (clé publique), quels matériels DH manquaient
Écran “récupération et déchiffrement en continu” Objectif
- Assurer le fonctionnement périodique “par services” : scan, fetch des clés, fetch des signatures, mise à jour du graphe et des droits.
Fonctions
- Planification périodique : pour chaque service connu, GET des nouveaux messages depuis dernier checkpoint
- Dédup hash
- Tentative de correspondance via index ECDH pour identifier les messages potentiellement déchiffrables
- Fetch des messages de clés (déchiffrement), puis fetch des signatures, puis validation
Optimisations à exposer (au moins comme options avancées)
-
Bloom filter
- Objectif : éviter de rescanner tout l’historique des hash
- Données : bitset local, éventuellement partagé entre devices
- Limite : faux positifs possibles → nécessite vérification finale par hash
-
Arbres de Merkle
- Objectif : prouver rapidement la présence/absence d’un hash dans un ensemble et synchroniser des segments
- Données : racines par période/service, preuve d’inclusion
- Limite : complexité de maintenance côté relais et côté client
Détails critiques de validation à intégrer (pour éviter des ambiguïtés en production) Canonisation JSON
- Définir une canonisation stricte : ordre des clés, encodage, normalisation des nombres/chaînes, gestion des tableaux.
- Sans cela, “Hash du JSON” devient instable entre implémentations.
Gestion des versions
- “Version” et “Version logicielle” doivent être prises en compte dans la validation (compatibilité ascendante, migrations).
- Le client doit afficher clairement la version d’un contrat et refuser ou isoler les versions non supportées.
Anti-rejeu
- Timestamp seul est insuffisant ; exiger un nonce unique par tentative, et un cache de nonces vus (par service) sur une fenêtre glissante.
- Le service doit rejeter un hash/nonce déjà accepté.
Clés publiques et identité
- La clé publique incluse dans la signature doit être reliée, par le graphe et les validateurs, au pair attendu.
- Interdire l’acceptation d’une signature “valide cryptographiquement” mais non autorisée “contractuellement”.
Séparation signatures / clés
- Prévoir un état “message reçu mais indéchiffrable (clé manquante)” et “message déchiffré mais non validé (signature manquante)”.
- L’UX doit rendre ces états visibles, sinon les utilisateurs concluent à des pertes de données.
Conclusion Un login conforme à ce modèle n’est pas un simple écran “identifiant/mot de passe”, mais un enchaînement de construction et de vérification d’un graphe contractuel, suivi d’une collecte de signatures multi-pairs, puis d’une publication en trois temps (message, signatures, clés), le tout synchronisé via des relais. La robustesse globale vient de la cohérence entre canonisation des hash, règles de validateurs, anti-rejeu, et de la capacité du client à scanner efficacement l’historique (Bloom/Merkle) sans jamais supposer qu’un message “arrive” par push.
Si une suite est souhaitée, la prochaine étape naturelle consiste à produire une spécification d’écrans sous forme de maquettes textuelles (composants, états, erreurs, journaux), puis une machine à états formelle du protocole de login (états, transitions, timeouts, reprise sur erreur), strictement alignée sur les objets et contraintes listés ci-dessus.
Écrans à produire pour login sans serveur central (secp256k1 + contrats + pairing mFA)
Principes UX et contraintes non négociables
Les règles suivantes doivent être visibles dans la conception des écrans (au minimum en “états avancés”, logs, diagnostics) :
- Tous les messages sont récupérés par GET (aucun push).
- Les messages “métier” sont publiés sans signatures et sans clés de chiffrement.
- Les signatures sont publiées après, séparément.
- Les clés/matériels de déchiffrement sont publiés après, séparément.
- Un GET de message ne renvoie pas signatures et clés : elles sont fetch spécifiquement ensuite.
- Tous les objets sont adressés par hash du JSON canonique (sans hash, sans signatures, sans clés de chiffrement).
- Le login est une preuve validée localement par graphe (service → contrat → champ → action/login → membre → pair) + validateurs.
- Le pairing est obligatoire pour autoriser une connexion : au moins un pair associé et attendu par l’action de login.
- Publication “pour tous” : aucun destinataire explicite. Le message est chiffré et n’est lisible que par les parties capables d’obtenir les clés.
Glossaire des objets manipulés dans l’UI
- Service : objet décrivant un service et son contrat associé.
- Contrat : objet “contrat d’identité”.
- Champ : objet rattaché à au moins un contrat parent.
- Action : objet rattaché à au moins un contrat parent, contient des validateurs.
- ActionLogin : action de type “login”.
- Membre : objet rattaché à au moins une action parent.
- Pair : objet rattaché à au moins un membre parent (device/instance).
- MessageBase : trame commune incluant uuid/version/types/services/timestamp/relais/hash/signature/pubkey.
- Message à valider : MessageBase + validateurs.
- Hash : hash du JSON canonique (sans hash, sans signatures, sans clés de chiffrement) + algo.
- Signature : hash + clé publique + signature + nonce/matériel.
- Message de signature : objet portant une Signature.
- Message individuel de déchiffrement : objet portant matériel de déchiffrement + ECDH.
Écran “accueil”
Objectif
Point d’entrée de l’application : état de l’identité locale, état du pairing, accès au login et à la synchronisation.
Pré-requis
Aucun.
Composants UI
- Statut identité locale : présente / absente
- Empreinte de la clé publique principale (format court)
- Statut pairing : requis / satisfait / incomplet
- Statut réseau relais : OK / dégradé / indisponible
- Dernière synchronisation : date/heure
- Boutons :
- Créer une identité locale
- Importer une identité
- Se connecter
- Gérer les pairs
- Réglages relais
- Synchroniser maintenant
États / erreurs
- Identité absente → bouton “Se connecter” désactivé
- Pairing non satisfait → “Se connecter” possible mais renverra vers pairing obligatoire
- Relais indisponibles → mode offline (lecture cache uniquement)
Écran “création d’identité locale”
Objectif
Générer les clés secp256k1 et initialiser les paramètres crypto locaux.
Pré-requis
Aucun.
Composants UI
- Nom local de l’identité (optionnel)
- Protection locale :
- PIN / mot de passe / biométrie (selon plateforme)
- Paramètres crypto avancés (optionnel) :
- Algos de chiffrement symétrique
- KDF
- Format canonique JSON
- Hash (algo)
Actions utilisateur
- Générer l’identité
Traitements locaux
- Génération clé privée secp256k1
- Calcul clé publique secp256k1
- Enregistrement “date anniversaire de création des clés”
- Création du cache local :
- index hash vus
- index services/types
- index ECDH (si applicable)
États / erreurs
- Erreur entropie / RNG indisponible
- Protection locale non conforme (PIN trop court, etc.)
Écran “import d’identité”
Objectif
Restaurer une identité existante (clé privée ou seed/hiérarchie).
Pré-requis
Disposer d’un secret d’import.
Composants UI
- Mode import :
- Seed / phrase / clé privée
- Fichier chiffré (optionnel)
- Champ d’entrée + validation checksum
- Protection locale au repos (comme création)
Traitements locaux
- Recalcul clé publique
- Vérification cohérence
- Initialisation cache
États / erreurs
- Seed invalide
- Clé privée hors format
- Incompatibilité de version
Écran “réglages relais”
Objectif
Configurer la liste de relais et les stratégies de synchronisation.
Composants UI
- Liste des relais (IP / endpoint)
- Priorité / ordre (drag & drop)
- Options :
- Sync périodique par service
- Fenêtre de scan par défaut
- Déduplication locale (taille cache hash)
- Accélérateurs : Bloom filter / Merkle (avancé)
- Boutons :
- Tester relais
- Ajouter / supprimer relais
- Sauvegarder
États / erreurs
- Relais non joignable
- Timeout réseau
- Configuration invalide (liste vide)
Écran “synchronisation globale”
Objectif
Récupérer des messages publiés sur relais, sans destinataire, et mettre à jour le cache local.
Pré-requis
Identité locale présente.
Composants UI
- Fenêtre de scan :
- Début : anniversaire clés / dernier checkpoint
- Fin : maintenant
- Sélecteurs :
- Tous services
- Service spécifique (si déjà connu)
- Compteurs :
- messages récupérés
- hash nouveaux
- hash déjà vus
- messages déchiffrables détectés
- signatures à récupérer
- clés à récupérer
- Boutons :
- Synchroniser maintenant
- Pause / reprendre
- Forcer “fetch signatures”
- Forcer “fetch clés”
- Diagnostiquer un hash
Traitements locaux
- GET messages chiffrés : (hash + message chiffré + datajson public)
- Déduplication par hash
- Indexation par service UUID / type UUID
- Tentatives d’identification :
- ce message est-il potentiellement déchiffrable ?
- Fetch dédié des messages “clés” pertinents
- Déchiffrement, parsing JSON, recalcul hash canonique
- Fetch dédié des “messages de signature”
- Vérification signatures secp256k1
- Mise à jour du graphe (service/contrat/action/membre/pair)
États / erreurs
- Message présent mais clé manquante → “indéchiffrable”
- Message déchiffré mais signatures manquantes → “non validé”
- Hash incohérent (JSON canonique différent) → “objet corrompu / non conforme”
- Signatures invalides → “preuve invalide”
Écran “gestion des services”
Objectif
Lister les services connus localement et leur état de validité contractuelle.
Pré-requis
Au moins une synchronisation effectuée.
Composants UI
- Liste des services (service UUID)
- Pour chaque service :
- label (si disponible et déchiffré)
- statut contrat :
- complet et valide
- incomplet (objets manquants)
- invalide (signatures/validateurs)
- dernier sync service
- Actions :
- Ouvrir
- Resync par service
- Voir graphe
États / erreurs
- Service détecté mais contrat non résolu → “incomplet”
- Types names chiffrés non déchiffrables → “affichage minimal”
Écran “détail service / graphe contractuel”
Objectif
Afficher la chaîne complète : service → contrat → champ → action → membre → pair(s), avec états.
Composants UI
- Vue hiérarchique ou graphe
- Nœuds avec :
- UUID
- type UUID
- statut (valide/incomplet/invalide)
- hash
- Liste “objets manquants” (hash attendus)
- Bouton “diagnostic”
Traitements locaux
- Résolution des parents UUID
- Validation “au moins 1 parent” sur objets concernés
- Vérification hash canonique
- Vérification signatures et validateurs
États / erreurs
- Cycle détecté dans les UUID parents (si possible) → bloquer
- Parent absent → incomplet
Écran “gestion des pairs”
Objectif
Lister les pairs connus et gérer l’association à des membres.
Composants UI
- Liste des pairs (UUID pair)
- Pour chaque pair :
- membres parents UUID
- statut : associé / en attente / invalide
- capacité signature : OK / indisponible
- Actions :
- Ajouter un pair
- Associer à un membre
- Retirer (local uniquement, selon politique)
- Diagnostiquer
Écran “ajout de pair (mFA)”
Objectif
Réaliser le pairing obligatoire via conversion BIP32 en mots.
Pré-requis
Identité locale présente.
Mode A : “ce device devient un pair”
Composants UI
- Générer UUID pair
- Afficher liste de mots BIP32 dérivée de l’UUID
- Bouton “continuer” (confirmation)
Traitements locaux
- Conversion UUID → chemin BIP32 → mots
- Enregistrement local du pair
Mode B : “associer un pair existant”
Composants UI
- Saisie des mots BIP32 affichés par l’autre device
- Bouton “reconstituer UUID”
Traitements locaux
- Mots → reconstitution UUID
- Vérification checksum
- Enregistrement pair
Publication
- Préparation des messages nécessaires pour lier pair ↔ membre :
- message métier (sans signature, sans clés)
- puis message(s) de signature
- puis message(s) de déchiffrement si requis
États / erreurs
- Mots invalides / ordre incorrect
- Pair déjà présent
- Membre cible absent du cache (sync requise)
Écran “sélection membre”
Objectif
Choisir le membre concerné par le login (quand plusieurs membres existent).
Pré-requis
Graphe local résolu au moins partiellement.
Composants UI
- Liste des membres
- label (si déchiffré)
- actions parents (dont login)
- pairs associés
- Action : sélectionner
États / erreurs
- Aucun membre avec action login → impossible de se connecter
Écran “sélection service pour connexion”
Objectif
Choisir le service cible du login.
Pré-requis
Services connus.
Composants UI
- Liste des services + statuts
- Bouton “continuer”
États / erreurs
- Service invalide → alerte + détails
Écran “construction du chemin login”
Objectif
Résoudre et afficher le chemin de validation du login, et calculer les signatures attendues.
Composants UI
- Résumé du chemin :
- service UUID
- contrat(s) UUID
- action login UUID
- membre UUID
- pairs attendus UUID
- Tableau “signatures requises” :
- validateurs
- règles (qui doit signer)
- statut (manquante/reçue/valide/invalide)
- Boutons :
- Synchroniser (si incomplet)
- Démarrer login
Traitements locaux
- Résolution parents
- Validation validateurs de l’action login
- Détermination du set minimal de signatures pour satisfaire la règle
États / erreurs
- Contrat incomplet
- Validateurs impossibles à satisfaire (ex : pair manquant)
Écran “message de login à valider”
Objectif
Construire le Message à valider de login.
Composants UI
- Résumé public :
- service UUID
- type UUID
- timestamp
- relais cibles
- Paramètres anti-rejeu :
- nonce généré (affichage possible en mode avancé)
- Bouton “signer”
Traitements locaux
- Construction MessageBase
- Insertion datajson public minimal (services UUID, types UUID)
- Calcul hash canonique
- Préparation du message chiffré
- Préparation publication “message d’abord”
États / erreurs
- Format JSON non canonique détecté
- Relais indisponibles
Écran “collecte des signatures (mFA)”
Objectif
Obtenir toutes les signatures obligatoires attendues pour l’action login.
Composants UI
- Liste des signatures requises :
- clé publique attendue
- pair/membre associé
- état
- Boutons :
- Signer avec ce device
- Demander signature sur autre pair
- Rafraîchir (fetch signatures)
- Voir détail signature
Flux “signature locale”
- Calcul signature secp256k1
- Création Message de signature
Flux “signature distante”
- Afficher un paquet de demande (hash + contexte)
- Autre device signe et publie
- Ce device fetch la signature et rattache
États / erreurs
- Signature invalide
- Nonce déjà utilisé (anti-rejeu)
- Délai d’attente dépassé
Écran “publication du login”
Objectif
Publier la preuve en respectant la séparation : message chiffré → signatures → clés de déchiffrement.
Composants UI
- Liste des relais + état :
- envoyé / confirmé / échec
- Hash final de la preuve
- Boutons :
- Publier
- Republier sur relais manquants
- Afficher diagnostics
Traitements réseau (ordre strict)
- POST message chiffré (sans signatures, sans clés)
- POST message(s) de signature
- POST message(s) individuels de déchiffrement (si requis)
États / erreurs
- Message publié mais signatures non publiées → preuve incomplète
- Signatures publiées mais clés manquantes → preuve inutilisable par tiers
Écran “résultat de connexion”
Objectif
Afficher un verdict explicite et traçable.
États possibles
- Connexion acceptée
- Connexion refusée : contrat incomplet
- Connexion refusée : signatures insuffisantes
- Connexion refusée : signatures invalides
- Connexion refusée : pairing non satisfait
- Connexion refusée : anti-rejeu (nonce déjà vu / timestamp hors fenêtre)
- Connexion refusée : objets manquants
Composants UI
- Statut final
- Hash de la preuve
- Service UUID
- Détails :
- signatures requises vs obtenues
- objets manquants
- logs (mode avancé)
- Actions :
- Recommencer
- Resync
- Diagnostic
Écran “diagnostic avancé (hash / objet)”
Objectif
Aider à comprendre un échec (objet manquant, clé absente, signature invalide).
Composants UI
- Entrée hash (ou sélection depuis liste)
- Détails objet :
- type UUID
- service UUID
- timestamp
- statut déchiffrement : OK/non
- statut signature : OK/non
- Boutons :
- Fetch signatures
- Fetch clés
- Vérifier canonisation JSON
- Vérifier validateurs
Erreurs typiques affichées
- Hash recalculé ≠ hash déclaré
- Signature secp256k1 invalide
- Clé publique non autorisée par validateurs
- Matériel DH absent / non exploitable
- Parents UUID absents
Écran “synchronisation continue par service”
Objectif
Maintenir le cache à jour périodiquement, par service.
Composants UI
- Liste services + toggle sync automatique
- Fréquence (min/heure/jour)
- Fenêtre de scan
- Accélérateurs :
- Bloom filter : taille, faux positifs estimés
- Merkle : segments/périodes
- Bouton “lancer maintenant”
Traitements locaux
- GET messages depuis dernier checkpoint
- Dédup hash
- Fetch signatures et clés si nécessaire
- Validation graphe et droits
États / erreurs
- Volume trop important → recommander Bloom/Merkle
- Relais instables → backoff
Écran “paramètres crypto (avancé)”
Objectif
Afficher et régler les politiques crypto et compatibilité.
Composants UI
- Algorithme hash (ex : sha256)
- Canonisation JSON (mode strict)
- Paramètres ECDH (secp256k1)
- Paramètres KDF/symétrique (si exposés)
- Politique anti-rejeu :
- TTL nonce
- fenêtre timestamp
États / erreurs
- Incompatibilité avec services existants
- Paramètres non supportés par version logicielle
Machine à états du login sans serveur central (secp256k1 + contrats + pairing mFA)
Objectif
Décrire une machine à états déterministe et implémentable pour :
- créer/importer une identité,
- synchroniser des messages via relais (pull-only),
- résoudre le graphe contractuel,
- imposer le pairing (mFA),
- construire un message de login à valider,
- collecter et vérifier les signatures attendues,
- publier la preuve (message → signatures → clés),
- obtenir un verdict local côté client et côté service (sans autorité centrale).
Définitions globales
Notation
- État :
S_* - Événement :
E_* - Garde (condition) :
G_* - Action (effet) :
A_* - Erreur :
X_*
Règles d’adressage et de contenu
- Tout objet est adressé par
Hash(JSON_canonique(objet)) JSON_canonique(objet)= JSON sans :hashsignaturesclefs_de_chiffrement
- Les signatures et les clés sont récupérées séparément après
GET message. - Tout est publié pour tous (sans destinataire explicite), chiffré.
Objets de preuve
MsgChiffre:{ hash, message_chiffre, datajson_public }MsgSignature:{ signature: {hash, pubkey, sig, nonce, materiel} }MsgCle:{ hash_message, cle_chiffrement, df_ecdh_scannable }
Fenêtres de synchronisation
T0 = date_anniversaire_creation_clesT_last = dernier_checkpoint_local- Scan par défaut :
[T_last ou T0 ; maintenant]
Cache local minimal
cache_hash_vusindex_par_service_uuidindex_par_type_uuidindex_par_hash -> (msg, signatures?, cles?, statut_dechiffrement, statut_validation)index_pairs_locauxindex_membres_connusindex_ecdh(si ECDH structuré par pubkeys)
Variables de session (runtime)
service_cible_uuidmembre_cible_uuidaction_login_uuidpairs_attendus[]signatures_requises[]nonce_loginhash_loginmsg_login_chiffrerelays[]timer_deadlines(réseau, collecte signatures, fetch clés)
États et transitions
S_INIT (démarrage application)
Entrée
- Charger cache local
- Charger identité locale si présente
- Charger configuration relais
Événements sortants
E_IDENTITY_ABSENT→S_IDENTITY_REQUIREDE_IDENTITY_PRESENT→S_HOME
S_IDENTITY_REQUIRED (identité manquante)
UI associée
- écran accueil avec options “Créer” / “Importer”
Transitions
E_CREATE_IDENTITY→S_IDENTITY_CREATEE_IMPORT_IDENTITY→S_IDENTITY_IMPORT
S_IDENTITY_CREATE (création identité locale)
Actions
A_GEN_SECP256K1_KEYPAIRA_SET_T0_ANNIVERSAIREA_INIT_CACHE
Sorties
E_IDENTITY_CREATED→S_HOME
Erreurs
X_RNG_UNAVAILABLE→S_ERROR_FATAL
S_IDENTITY_IMPORT (import identité)
Actions
A_PARSE_SEED_OR_PRIVKEYA_DERIVE_PUBKEYA_SET_OR_CONFIRM_T0A_INIT_CACHE
Sorties
E_IDENTITY_IMPORTED→S_HOME
Erreurs
X_IMPORT_INVALID→S_ERROR_RECOVERABLE
S_HOME (accueil)
Événements
E_OPEN_RELAY_SETTINGS→S_RELAY_SETTINGSE_SYNC_NOW→S_SYNC_GLOBALE_MANAGE_PAIRS→S_PAIR_MANAGEMENTE_LOGIN_START→S_LOGIN_SELECT_SERVICE
Gardes
G_IDENTITY_PRESENTsinon retourS_IDENTITY_REQUIRED
S_RELAY_SETTINGS (configuration relais)
Actions
A_SAVE_RELAYS_CONFIGA_TEST_RELAYS(optionnel)
Sorties
E_RELAYS_SAVED→S_HOMEE_CANCEL→S_HOME
Erreurs
X_RELAYS_INVALID→S_ERROR_RECOVERABLE
S_SYNC_GLOBAL (synchronisation globale)
Objectif
Récupérer MsgChiffre, dédupliquer par hash, puis fetch clés et signatures sur demande.
Entrée
- Déterminer fenêtre
[T_scan_start; T_scan_end] - Initialiser compteurs
Actions boucle (pull)
A_GET_MSGS_CHIFFRES(relays, window)→ liste{hash, message_chiffre, datajson_public}A_DEDUP_HASH(cache_hash_vus)A_INDEX_PUBLIC_METADATA(service_uuid, type_uuid, timestamp)A_DETECT_POTENTIEL_DECHIFFRABLE(index_ecdh, datajson_public)(heuristique)A_FETCH_KEYS_BY_HASH(hash)(si candidat)A_TRY_DECRYPT(hash)(si clé présente)A_RECALC_CANONICAL_HASHA_FETCH_SIGNATURES_BY_HASH(hash)(si déchiffré)A_VERIFY_SIGNATURESA_UPDATE_GRAPH_CACHE
Sorties
E_SYNC_DONE→S_HOMEE_SYNC_DONE_WITH_DISCOVERY→S_SERVICE_LIST
Erreurs récupérables
X_RELAY_TIMEOUT→ resterS_SYNC_GLOBALavec backoffX_DECRYPT_KEY_MISSING→ marquer état local “indéchiffrable”X_SIG_MISSING→ marquer “non validé”X_HASH_MISMATCH→ marquer “corrompu / non conforme”
S_SERVICE_LIST (liste services)
Entrée
- Charger services connus depuis
index_par_service_uuid
Transitions
E_SELECT_SERVICE(service_uuid)→S_LOGIN_SELECT_MEMBER(ou direct si membre unique)E_RESYNC_SERVICE(service_uuid)→S_SYNC_SERVICEE_BACK→S_HOME
S_SYNC_SERVICE (sync ciblée service)
Actions
A_GET_MSGS_CHIFFRES(filter=service_uuid)- mêmes actions de déchiffrement/validation que
S_SYNC_GLOBAL
Sorties
E_SYNC_SERVICE_DONE→S_SERVICE_LISTE_BACK→S_SERVICE_LIST
S_PAIR_MANAGEMENT (gestion pairs)
Transitions
E_PAIR_ADD→S_PAIR_ADDE_PAIR_ASSOCIATE_TO_MEMBER→S_PAIR_ASSOCIATEE_BACK→S_HOME
S_PAIR_ADD (ajout d’un pair)
Modes
- local : “ce device devient un pair”
- distant : “associer un pair existant”
Actions
A_GEN_PAIR_UUID(mode local)A_UUID_TO_BIP32_WORDS(affichage)A_WORDS_TO_UUID(saisie)A_STORE_PAIR_LOCAL
Sorties
E_PAIR_READY→S_PAIR_ASSOCIATE
Erreurs
X_WORDS_INVALID→S_ERROR_RECOVERABLE
S_PAIR_ASSOCIATE (associer pair ↔ membre)
Gardes
G_MEMBRE_EXISTS_LOCALLYsinonS_SYNC_GLOBAL
Actions (préparation publication)
A_BUILD_PAIR_MEMBERSHIP_MESSAGE(message métier sans signatures/clefs)A_ENCRYPT_MESSAGEA_CALC_HASHA_QUEUE_PUBLISH_MESSAGEA_QUEUE_PUBLISH_SIGNATURES_REQUIREDA_QUEUE_PUBLISH_KEYS_IF_REQUIRED
Sorties
E_ASSOCIATION_QUEUED→S_PUBLISH_QUEUE
S_PUBLISH_QUEUE (file de publication)
Objectif
Publier dans l’ordre strict : message → signatures → clés.
Actions
A_POST_MSG_CHIFFREA_POST_MSG_SIGNATURESA_POST_MSG_KEYS
Sorties
E_PUBLISH_OK→S_HOMEE_PUBLISH_PARTIAL→S_ERROR_RECOVERABLE
Erreurs
X_RELAY_DOWN→S_ERROR_RECOVERABLE
S_LOGIN_SELECT_SERVICE (début login : choix service)
Gardes
G_PAIRING_SATISFIEDsinonS_LOGIN_PAIRING_REQUIRED
Transitions
E_SELECT_SERVICE(service_uuid)→S_LOGIN_SELECT_MEMBERE_BACK→S_HOME
S_LOGIN_PAIRING_REQUIRED (pairing obligatoire)
Transitions
E_GO_PAIRING→S_PAIR_MANAGEMENTE_BACK→S_HOME
S_LOGIN_SELECT_MEMBER (choix membre)
Gardes
G_MEMBRE_WITH_ACTION_LOGIN_EXISTSsinonS_ERROR_RECOVERABLE
Transitions
E_SELECT_MEMBER(membre_uuid)→S_LOGIN_BUILD_PATHE_BACK→S_SERVICE_LIST
S_LOGIN_BUILD_PATH (résolution graphe et validateurs)
Actions
A_RESOLVE_GRAPH(service_uuid, membre_uuid)- service → contrat → champ → action(login) → membre → pairs
A_VALIDATE_PARENTS_UUID_CONSTRAINTSA_VALIDATE_TYPES_NAMES_IF_AVAILABLEA_LOAD_ACTION_VALIDATORSA_COMPUTE_REQUIRED_SIGNATURES_SET
Sorties
E_PATH_OK→S_LOGIN_CHECK_PAIRSE_PATH_INCOMPLETE→S_ERROR_RECOVERABLEE_PATH_INVALID→S_ERROR_RECOVERABLE
Erreurs
X_PARENT_MISSINGX_VALIDATORS_UNSATISFIABLEX_HASH_MISMATCH
S_LOGIN_CHECK_PAIRS (vérifier pairs attendus)
Gardes
G_ALL_REQUIRED_PAIRS_AVAILABLEsinonS_LOGIN_NEED_MORE_PAIRS
Sorties
E_PAIRS_OK→S_LOGIN_BUILD_CHALLENGE
S_LOGIN_NEED_MORE_PAIRS (pairs manquants)
Transitions
E_ADD_PAIR→S_PAIR_MANAGEMENTE_RESYNC→S_SYNC_SERVICEE_BACK→S_SERVICE_LIST
S_LOGIN_BUILD_CHALLENGE (construction message à valider)
Actions
A_GENERATE_NONCEA_BUILD_MESSAGEBASE_LOGIN- services_uuid = service_cible_uuid
- types_uuid = type_login_uuid
- timestamp = now
- relays = relays[]
- version logicielle
A_ENCRYPT_LOGIN_MESSAGEA_CANONICALIZE_JSONA_CALC_HASH_LOGIN
Sorties
E_CHALLENGE_READY→S_LOGIN_COLLECT_SIGNATURES
Erreurs
X_CANONICALIZATION_FAILX_ENCRYPT_FAIL
S_LOGIN_COLLECT_SIGNATURES (collecte signatures mFA)
Objectif
Obtenir toutes les signatures imposées par validateurs.
Sous-états internes (recommandé)
S_LOGIN_SIG_LOCALS_LOGIN_SIG_REMOTE_WAITS_LOGIN_SIG_FETCH
Actions
A_SIGN_LOCAL(hash_login, privkey_pair_local)→ MsgSignatureA_REQUEST_REMOTE_SIGNATURE(hash_login, context)(UI/QR/mots selon design)A_FETCH_SIGNATURES_BY_HASH(hash_login)A_VERIFY_SIGNATURES_SECP256K1A_CHECK_VALIDATORS_SATISFIED
Sorties
E_SIGNATURES_COMPLETE→S_LOGIN_PUBLISH_PROOFE_SIGNATURES_INCOMPLETE→ resterS_LOGIN_COLLECT_SIGNATURES
Erreurs
X_SIGNATURE_INVALIDX_SIGNATURE_TIMEOUTX_NONCE_REUSED(si cache nonce)X_PUBKEY_NOT_AUTHORIZED
S_LOGIN_PUBLISH_PROOF (publication preuve login)
Ordre strict
- publier message chiffré sans signatures ni clés
- publier message(s) de signature
- publier message(s) de déchiffrement si nécessaire
Actions
A_POST_MSG_CHIFFRE(hash_login, msg_login_chiffre)A_POST_SIGNATURES(hash_login, signatures[])A_POST_KEYS_IF_REQUIRED(hash_login, key_materials[])
Sorties
E_PUBLISH_LOGIN_OK→S_LOGIN_VERIFY_LOCALE_PUBLISH_LOGIN_PARTIAL→S_ERROR_RECOVERABLE
Erreurs
X_RELAY_POST_FAIL
S_LOGIN_VERIFY_LOCAL (vérification locale finale)
Objectif
Le client démontre que la preuve est auto-cohérente et satisfaisante avant affichage.
Actions
A_RELOAD_PUBLISHED_OBJECTS_IF_NEEDEDA_VERIFY_CANONICAL_HASH(hash_login)A_VERIFY_SIGNATURESA_VERIFY_GRAPH_CONFORMITYA_VERIFY_ANTI_REPLAY(nonce, timestamp_window)
Sorties
E_LOCAL_VERDICT_ACCEPT→S_LOGIN_SUCCESSE_LOCAL_VERDICT_REJECT→S_LOGIN_FAILURE
S_LOGIN_SUCCESS (connexion OK)
Sorties
E_DONE→S_HOME
S_LOGIN_FAILURE (connexion KO)
Actions
- Afficher diagnostics : signatures manquantes, objets manquants, anti-rejeu, etc.
Sorties
E_RETRY→S_LOGIN_BUILD_PATH(ouS_LOGIN_COLLECT_SIGNATURESselon cause)E_RESYNC→S_SYNC_SERVICEE_BACK→S_HOME
États d’erreur
S_ERROR_RECOVERABLE (erreur récupérable)
Objectif
Afficher une erreur explicite et proposer des actions de reprise.
Sorties possibles
E_RETRY→ état précédentE_SYNC_NOW→S_SYNC_GLOBALE_OPEN_DIAGNOSTIC→S_DIAGNOSTICE_BACK→S_HOME
S_ERROR_FATAL (erreur bloquante)
Objectif
Cas impossible à corriger sans intervention externe (ex : RNG indisponible).
Sorties
E_EXIT→ fin
S_DIAGNOSTIC (diagnostic hash / objet)
Actions
A_FETCH_MSG_BY_HASHA_FETCH_SIGNATURES_BY_HASHA_FETCH_KEYS_BY_HASHA_TRY_DECRYPTA_VERIFY_HASHA_VERIFY_SIGNATURESA_VERIFY_VALIDATORS
Sorties
E_BACK→S_HOME(ou état appelant)
Anti-rejeu et cohérence temporelle (contrainte transversale)
Règles
- Un login doit inclure un
nonce_loginunique. - Le service (ou le validateur final) doit maintenir un cache
nonce_vuspar fenêtre temporelle. - Le client doit également maintenir un cache local pour éviter de republier un nonce déjà utilisé.
Erreurs
X_NONCE_REUSED: nonce déjà vu → rejet.X_TIMESTAMP_OUT_OF_WINDOW: timestamp trop ancien/futur → rejet.
Optimisation de scan (optionnel)
Bloom filter
- État utilisateur : activé/désactivé
- Effet : éviter de re-fetch massivement des hash déjà vus
- Limite : faux positifs → toujours confirmer par vérification hash
Merkle trees
- État utilisateur : activé/désactivé
- Effet : synchroniser par segments et preuves d’inclusion
- Limite : complexité de maintenance côté relais
Résumé des sorties réseau par phase
Synchronisation
- GET
MsgChiffre(par fenêtre temporelle, éventuellement par service) - GET
MsgClepar hash (ciblé) - GET
MsgSignaturepar hash (ciblé)
Publication preuve (ordre strict)
- POST
MsgChiffre(sans signatures ni clés) - POST
MsgSignature - POST
MsgCle(si requis)
Table des causes d’échec et état de reprise conseillé
- Contrat incomplet →
S_SYNC_SERVICEpuisS_LOGIN_BUILD_PATH - Parent UUID manquant →
S_SYNC_GLOBALpuisS_LOGIN_BUILD_PATH - Message indéchiffrable (clé manquante) →
S_SYNC_GLOBAL+ fetch clés → retry - Signature manquante →
S_LOGIN_COLLECT_SIGNATURES+ fetch signatures → retry - Signature invalide → rester
S_LOGIN_COLLECT_SIGNATURES(recollect) - Pubkey non autorisée →
S_LOGIN_BUILD_PATH(recalcul validateurs) - Nonce rejoué →
S_LOGIN_BUILD_CHALLENGE(nouveau nonce) - Relais down →
S_RELAY_SETTINGSouS_PUBLISH_QUEUEavec retry/backoff
Catalogue des objets du projet (contrats, identité, pairing, login, relais)
Portée
Ce document recense l’ensemble des objets manipulés par le protocole :
- structure des contrats et des entités (service, contrat, champ, action, membre, pair),
- structure commune de message (MessageBase, hash, signature),
- objets de validation (validateurs, message à valider),
- objets cryptographiques séparés (message de signature, message individuel de déchiffrement),
- enveloppes réseau (messages chiffrés publiés sur relais),
- contraintes de publication et de récupération.
La règle principale est la séparation stricte :
- publication du message sans signatures ni clés,
- publication des signatures ensuite,
- publication des clés/matériels de déchiffrement ensuite.
Conventions et invariants
Types (types uuid et types names chiffrés)
Chaque objet porte un types_uuid et un types_names_chiffres incluant au minimum le type de l’objet.
Le type name est chiffré et peut inclure des sous-types (ex : "login" pour ActionLogin).
Hash canonique
Le hash est calculé sur le JSON canonique de l’objet :
- sans le champ
hash, - sans la liste
signatures, - sans les champs
cles_de_chiffrement(ou équivalents), - sans tout bloc de signature ou matériel crypto posté séparément.
Le hash doit spécifier explicitement l’algorithme.
Signature secp256k1
Les signatures servent à prouver :
- l’intégrité (le hash),
- l’autorité (clé publique autorisée par validateurs),
- l’anti-rejeu (nonce / matériel additionnel éventuel).
Publication “pour tous”
Tous les messages sont publiés :
- sans destinataire explicite,
- sous forme chiffrée,
- récupérés par GET périodiques via relais.
Récupération séparée
Un GET de message ne doit pas renvoyer automatiquement :
- signatures,
- clés/matériels de déchiffrement. Ils sont récupérés par requêtes dédiées ensuite.
Structure commune : MessageBase
Rôle
Base obligatoire d’un message de l’écosystème. Supporte l’adressage (hash), l’indexation (uuid, version, type, service), et la synchronisation (timestamp, relais).
Champs obligatoires
uuid: identifiant unique de l’objetversion: version du schéma de cet objettypes:types_uuid: identifiant de typetypes_names_chiffres: au minimum le type (ex : "pair", "membre", "contrat")
cles_de_chiffrement: paramètres + algorithmes (présents dans le message complet, mais exclus du hash canonique)datajson:- obligatoires :
services_uuid[]: au moins 1types_uuid[]: au moins 1
- optionnels :
labeldescription_longuedescription_courtephotoimagebanniereurlparagraphes[]: couples texte + imagetarif
- obligatoires :
timestamp: horodatageliste_relais[]: liste de relais (IP / endpoints)version_logicielle: version du client ayant produit le message
Champs dérivés / attachés après coup
hash: hash canonique (stockable dans le message complet, mais calculé sans certains champs)signatures[]: non inclus dans le message publié initialement (posté séparément)
Objet : Hash
Rôle
Décrit le hash canonique d’un objet.
Champs
algo: nom de l’algorithme (ex : sha256)hash_value: valeur du hash (encodage à spécifier)
Calcul
Le hash porte sur le JSON canonique :
- sans
hash, - sans signatures,
- sans clés de chiffrement.
Objet : Signature
Rôle
Preuve cryptographique associée à un hash.
Champs
hash: hash signé (référence)cle_publique: clé publique secp256k1signature: signature cryptographique secp256k1nonce: anti-rejeumateriel: champs optionnels (ex : contexte, challenge, metadata anti-rejeu)
Contraintes
- La clé publique doit être autorisée selon les validateurs du message et/ou de l’action.
- Le nonce doit être unique dans la fenêtre de validité considérée.
Objet : Message à valider
Rôle
Enveloppe logique d’un message nécessitant validation contractuelle.
Composition
MessageBasevalidateurs
Finalité
Permet de déterminer :
- quelles signatures sont requises,
- qui a autorité pour signer,
- quelles dépendances de signatures sont nécessaires.
Objet : Validateurs
Rôle
Définir les exigences de signatures, sous forme de règles par rôle/membre.
Champs
membres_du_role[]: au moins 1
Pour chaque membre de rôle :
signatures_obligatoires[]:- signatures exigées des autres membres et/ou de lui-même
- cardinalité minimale (si modèle seuil)
- dépendances éventuelles
Contraintes
- La liste des membres du rôle doit être non vide.
- Les signatures doivent pouvoir être résolues vers des clés publiques présentes dans le graphe (membre/pair).
Objet : Message de signature
Rôle
Publication séparée d’une ou plusieurs signatures associées à un message.
Champs obligatoires
signature: structure Signature complète
Indexation recommandée
hash_cible: hash du message ciblé (si non redondant avec signature.hash)
Cycle de vie
- message publié sans signatures
- message(s) de signature publiés ensuite et attachés localement au message ciblé
Objet : Message individuel de déchiffrement
Rôle
Publication séparée des éléments permettant de récupérer une clé de déchiffrement (ou une clé enveloppe).
Champs obligatoires
hash_message: hash du message chiffré concernécle_de_chiffrement_message:- clé de chiffrement du message chiffré
- clé de chiffrement chiffrée (enveloppe)
- paramètres et algorithmes complets
df_ecdh_scannable:- matériel Diffie-Hellman à scanner
- contient une clé (ou information) permettant de déchiffrer la clé enveloppe via secret partagé
Contraintes
- Le matériel DH est inutilisable sans possession d’une clé privée correspondante.
- Ce message doit pouvoir être filtré/identifié côté client lors d’un scan global.
Objet : Enveloppe réseau “message chiffré publié”
Rôle
Format minimal publié sur les relais pour la diffusion “pour tous”.
Champs
hash: hash canonique du message (référence)message_chiffre: payload chiffré (opaque)datajson_public:- métadonnées non sensibles utiles au filtrage
- doit inclure au minimum :
services_uuid[]types_uuid[]
- peut inclure :
timestampversion- autres marqueurs de routage/filtrage
Contraintes
- Ne doit pas inclure signatures.
- Ne doit pas inclure clés de chiffrement.
Objets “contrats / identité”
Objet : Service
Rôle
Décrit un service, son identité contractuelle, et sert de racine à une authentification.
Champs spécifiques
contrat_uuid: référence vers un Contrattypes_names_chiffresinclut "service"
Contraintes
- Doit exister dans
datajson.services_uuid[]des objets liés au service. - Doit être résoluble via sync par service.
Objet : Contrat
Rôle
Contrat d’identité principal pour un service.
Champs spécifiques
message_a_valider: base + validateurs applicablestypes_names_chiffresinclut "contrat"
Contraintes
- Le contrat doit être déchiffrable et validable pour autoriser des actions.
Objet : Champ
Rôle
Unité contractuelle rattachée à un ou plusieurs contrats.
Champs spécifiques
message_a_validertypes_names_chiffresinclut "champ"contrats_parents_uuid[]: au moins 1
Contraintes
- Au moins un parent contrat.
- Permet d’étendre la structure du contrat et des exigences.
Objet : Action
Rôle
Action exécutable dans le contexte du contrat. Contient ses propres validateurs.
Champs spécifiques
message_a_validertypes_names_chiffresinclut "action"validateurs_actioncontrats_parents_uuid[]: au moins 1
Contraintes
- Au moins un parent contrat.
- Les validateurs doivent être satisfaisables.
Objet : ActionLogin
Rôle
Spécialisation de Action, de type “login”.
Champs spécifiques
action: référence Actiontypes_names_chiffresinclut "login"
Contraintes
- Doit être identifiable comme action de login dans le graphe.
- Les signatures requises pour login sont tirées des validateurs de l’action.
Objet : Membre
Rôle
Identité d’un membre (acteur) autorisé à exécuter des actions, dont login.
Champs spécifiques
message_a_validertypes_names_chiffresinclut "membre"actions_parents_uuid[]: au moins 1
Contraintes
- Doit référencer au moins une action.
- Doit pouvoir être lié à un ou plusieurs pairs (devices).
Objet : Pair
Rôle
Représente un device/instance participant aux signatures (mFA).
Champs spécifiques
MessageBasetypes_names_chiffresinclut "pair"membres_parents_uuid[]: au moins 1
Contraintes
- Pairing obligatoire : au moins un pair attendu doit être disponible pour login.
- L’UUID du pair sert d’identifiant uniquement (clé d’identification), pas de secret.
Conversion UUID pair ↔ mots (BIP32)
Rôle
Procédure robuste d’association pair ↔ membre sans échanger l’UUID brut.
Procédé
- UUID du pair converti via dérivation BIP32 en une liste de mots.
- Device A affiche les mots.
- Device B saisit les mots.
- Reconstitution de l’UUID du pair.
Contraintes
- La liste de mots doit inclure un checksum ou mécanisme de détection d’erreur.
- Les mots n’exposent pas de secret exploitable : l’UUID n’est qu’un identifiant.
Objet : Relais (entité réseau)
Rôle
Stocker et relayer des objets adressés par hash. Assurer une diffusion inter-relais.
Responsabilités minimales
- Stocker :
- enveloppes
MsgChiffre - messages
MsgSignature - messages
MsgCle
- enveloppes
- Relayer entre relais
- Déduplication :
- sauvegarder les hash reçus pour ne pas relayer deux fois
Contraintes
- Un relais ne doit pas “fusionner” message + signatures + clés lors d’un GET.
- Le client doit pouvoir GET par période et idéalement filtrer par service.
Catalogue des flux (rappel)
Publication d’un objet (ordre strict)
- Publication
MsgChiffre
- contient hash + message chiffré + datajson public
- sans signatures
- sans clés
- Publication
MsgSignature
- une ou plusieurs signatures (selon validateurs)
- attachées au hash
- Publication
MsgCle
- clés / matériels DH nécessaires au déchiffrement
- attachés au hash
Récupération côté client
- GET
MsgChiffre(pull périodique, par fenêtre) - Déduplication par hash
- GET
MsgCle(si candidat déchiffrable) - Déchiffrement, parsing, recalcul hash canonique
- GET
MsgSignature - Vérification secp256k1 + validateurs
- Mise à jour graphe local
Conditions de login (rappel)
Pour se logguer, il faut :
- cibler un
service_uuid, - trouver l’ActionLogin du membre,
- satisfaire les validateurs de l’action login,
- fournir les signatures attendues des pairs requis,
- publier preuve (message → signatures → clés),
- permettre au service de vérifier la conformité contrat/signature sans serveur central.