# Théorie : comprendre les fondations de Jiyu
> Ce document explique la théorie derrière chaque solution technique choisie dans
> [implementation.md](./implementation.md) : les acronymes, les concepts, et le
> pourquoi des choses. Il suit le même découpage en briques. C'est un document
> d'apprentissage, pas une référence normative.
---
## Brique 1 : la cryptographie de base
### Les trois familles d'outils crypto
Toute la crypto du protocole se range dans trois familles, et il faut les distinguer
parce qu'elles ne protègent pas contre la même chose :
- **Signer** : prouver qui a écrit quoi. Ne cache rien, authentifie.
- **Chiffrer** : cacher le contenu. Ne prouve pas qui écrit (c'est l'AEAD qui combine
les deux, voir plus bas).
- **Dériver** : fabriquer plusieurs clés à partir d'un secret, de façon déterministe
et à sens unique.
### Ed25519 : les signatures
Une **signature numérique** fonctionne avec une paire de clés : la clé privée signe,
la clé publique vérifie. Quiconque a ta clé publique peut vérifier que c'est bien toi
qui as signé, personne ne peut signer à ta place sans la privée.
**Ed25519** est un algorithme de signature sur **courbes elliptiques**. L'idée des
courbes elliptiques, sans les maths : ce sont des objets mathématiques où il est
facile de calculer dans un sens (clé privée → clé publique) et pratiquement
impossible dans l'autre. L'avantage sur l'ancien standard RSA : des clés de 32
octets et des signatures de 64 octets au lieu de plusieurs centaines, et des calculs
plus rapides. Sur nos transports lents, ces 64 octets par post comptent.
### X25519, KEM, et l'accord de clés
Problème fondamental : comment deux personnes qui ne se sont jamais parlé
établissent-elles un secret commun, alors que tout le monde écoute le canal ?
- **X25519** est un **Diffie-Hellman** sur courbe elliptique : chacun envoie sa clé
publique, chacun combine sa privée avec la publique de l'autre, et les deux
aboutissent au même secret sans jamais l'avoir transmis. C'est magique et c'est
prouvé depuis 1976.
- Un **KEM** (Key Encapsulation Mechanism) est la version moderne et généralisée :
tu prends la clé publique de l'autre, tu "encapsules" un secret dedans, tu envoies
la capsule ; seul le détenteur de la clé privée peut l'ouvrir.
### Post-quantique, ML-KEM et X-Wing
Un ordinateur quantique suffisamment grand casserait X25519 et Ed25519 (l'algorithme
de Shor résout le problème mathématique sous-jacent). Il n'existe pas encore, mais :
- **La menace "harvest now, decrypt later"** : un adversaire enregistre ton trafic
chiffré aujourd'hui et le déchiffrera dans dix ans. C'est pour ça que l'accord de
clés doit être post-quantique dès maintenant : le secret établi aujourd'hui protège
des messages qui doivent rester secrets longtemps.
- Les **signatures** ne craignent rien aujourd'hui : forger une signature exige
l'ordinateur quantique au moment de la forge, pas après coup. D'où Ed25519 conservé.
- **ML-KEM** (Module-Lattice KEM, ex-Kyber, standardisé par le NIST sous FIPS 203)
est un KEM fondé sur les **réseaux euclidiens** (lattices), un problème
mathématique que les ordinateurs quantiques ne savent pas résoudre.
- **X-Wing** est un **hybride** : X25519 + ML-KEM-768 combinés. Pour casser le
secret, il faut casser LES DEUX. On se protège ainsi contre les deux risques :
l'ordinateur quantique (qui casserait X25519 seul) et une faille découverte dans
les maths jeunes de ML-KEM (qui casserait ML-KEM seul).
### AEAD et ChaCha20-Poly1305
**AEAD** = Authenticated Encryption with Associated Data. C'est le chiffrement
moderne : il cache le contenu ET garantit qu'il n'a pas été modifié en route (un
chiffrement sans authentification est vulnérable à des attaques par modification).
**ChaCha20** fait le chiffrement, **Poly1305** l'authentification. On le choisit
plutôt qu'AES parce qu'AES n'est rapide que grâce à des instructions matérielles
dédiées, absentes en WebAssembly ; ChaCha20 est rapide et sûr en pur logiciel.
### KDF, HKDF, et la dérivation
Une **KDF** (Key Derivation Function) fabrique des clés à partir d'un secret. C'est
une fonction à sens unique : de la clé dérivée, impossible de remonter au secret.
**HKDF** (RFC 5869) est la KDF standard, bâtie sur HMAC-SHA256. On lui donne un
secret + une étiquette de contexte ("tag-epoque-42", "pseudonyme-place-X") et elle
sort une clé propre à ce contexte. C'est elle qui fabrique :
- les **tags d'époque** (pseudonymes tournants des places),
- les **pseudonymes par place** (dérivés de l'identité maîtresse + ID de place :
stable dans la place, incorrélable entre places),
- les clés de message à partir du secret de groupe.
### Le ratchet symétrique et la forward secrecy
La **forward secrecy** (confidentialité persistante) : si on te vole tes clés
aujourd'hui, le trafic d'hier doit rester indéchiffrable. Le mécanisme : le
**ratchet** (cliquet). La clé avance en sens unique, `clé_suivante = HKDF(clé_actuelle)`,
et on efface les anciennes au fur et à mesure. Comme HKDF est à sens unique,
posséder la clé du jour ne permet pas de recalculer celle d'hier. Le mot "cliquet"
dit tout : ça tourne dans un sens, jamais dans l'autre.
Chez Jiyu, ce cliquet opère au niveau des **générations** de clés de groupe (une
génération par changement de membres ou rafraîchissement, brique 3), pas message
par message : puisque nos axiomes remettent l'historique intégral aux nouveaux
membres, les secrets passés sont conservés par conception, et c'est l'exclusion
(nouvelle génération que l'exclu n'a pas) qui matérialise la protection. À
l'intérieur d'une génération, chaque message a sa clé propre, dérivée par
compteur.
### BLAKE3 et les hashs
Un **hash** est une empreinte : n'importe quelle donnée → 32 octets, déterministe,
impossible à inverser, impossible (en pratique) de trouver deux données avec la même
empreinte. Usages chez nous : identifier un contenu (l'ID d'un post EST son hash) et
chaîner des blocs (chaque bloc contient le hash du précédent : modifier l'histoire
casse toute la chaîne). **BLAKE3** est un hash moderne, beaucoup plus rapide que
SHA-256 en logiciel, ce qui compte sur mobile en WASM.
---
## Brique 2 : le log répliqué
### Append-only, DAG, et pourquoi pas une base de données
Notre structure de données fondamentale est un **log append-only** : on ajoute des
événements (post, réaction, édition), on ne modifie jamais rien. La "suppression"
est un nouvel événement (tombstone) qui dit "considérez ceci comme effacé". Pourquoi :
dans un système distribué sans serveur, la modification en place crée des conflits
insolubles ; l'ajout pur fusionne trivialement (l'union de deux ensembles d'événements
est toujours bien définie).
**DAG** = Directed Acyclic Graph, graphe orienté sans cycle. Chaque entrée référence
ses parents (les dernières entrées connues au moment d'écrire). Quand deux personnes
écrivent en parallèle sans se voir (partition réseau), le graphe fourche ; quand
elles se resynchronisent, les deux branches coexistent dans le DAG et sont fusionnées
par le tri. Git fonctionne exactement comme ça.
### Les horloges de Lamport
Problème : sans serveur central, pas d'horloge de référence, et les horloges des
téléphones mentent. Comment ordonner les messages ? **L'horloge de Lamport** (1978)
est un compteur logique : chaque auteur incrémente son compteur à chaque message, et
le règle au max de ce qu'il a vu + 1. Résultat : un ordre partiel causal (si j'ai vu
ton message avant d'écrire le mien, le mien a un numéro plus grand). Pour départager
les égalités (deux messages avec le même numéro écrits en parallèle), on compare les
clés publiques des auteurs : arbitraire mais déterministe, tout le monde calcule le
même ordre. C'est un **CRDT** au sens large : une structure dont la fusion est
commutative, associative et idempotente, donc tous les pairs convergent vers le même
état quel que soit l'ordre de réception.
### La synchronisation : vecteurs de frontière et RBSR
Deux pairs se retrouvent : comment savoir quoi s'échanger sans tout renvoyer ?
- **Vecteur de frontière** (le mécanisme de Scuttlebutt) : comme chaque auteur
numérote ses messages, "tout ce que je possède" se résume en une liste
`{auteur → dernier numéro vu}`. On échange les listes, on compare, chacun sait
exactement ce qui manque à l'autre. Un aller-retour, quelques octets par auteur.
- **RBSR** (Range-Based Set Reconciliation) : pour les cas où le vecteur ne marche
pas (logs troués par la rétention partielle). Les deux pairs voient leurs logs
comme des ensembles triés et échangent des **empreintes par plage** (le hash
agrégé de "tout ce que j'ai entre janvier et mars"). Empreintes égales : plage
identique, on passe. Différentes : on coupe la plage en deux et on recommence.
Convergence logarithmique, comme une recherche dichotomique sur les différences.
---
## Brique 3 : les clés de groupe
### Le problème du chiffrement de groupe
Chiffrer pour une personne, c'est facile (son KEM). Chiffrer pour un groupe de 10 000
personnes dont la composition change, c'est le problème dur : à chaque exclusion il
faut une nouvelle clé de groupe distribuée à tous SAUF l'exclu. Naïvement : chiffrer
la nouvelle clé vers chacun des 9 999 restants, un par un. Intenable.
### TreeKEM : l'arbre qui rend ça logarithmique
**TreeKEM** organise les membres en arbre binaire : chaque membre est une feuille,
chaque nœud interne porte une clé connue de tout son sous-arbre. La clé racine est la
clé de groupe. Quand un membre change ou part, seul le **chemin de sa feuille à la
racine** doit être re-clé : log₂(N) nœuds, soit ~14 opérations pour 10 000 membres au
lieu de 10 000. C'est LE mécanisme qui rend les grands groupes chiffrés possibles.
### MLS, et pourquoi on ne l'utilise pas
**MLS** (Messaging Layer Security, RFC 9420) est le standard IETF qui industrialise
TreeKEM. Mais il a une exigence cachée : tous les membres doivent traiter les
changements de groupe **dans le même ordre total, immédiatement** ; deux opérations
concurrentes non ordonnées produisent deux arbres incompatibles. MLS délègue cet
ordonnancement à un serveur. Notre réseau, fait de partitions et de
store-and-forward, ne peut pas fournir ça, et la recherche a montré (papier FREEK,
CRYPTO 2023) que rafistoler MLS pour tolérer les fourches est un vrai sujet
scientifique, pas un patch.
### La CGKA à ordre causal, notre voie
La bonne famille d'outils pour nous s'appelle la **CGKA à ordre causal** (lignée
DCGKA, Weidner/Kleppmann) : les opérations de groupe s'appliquent **dès leur
réception, dans l'ordre causal** (celui que notre DAG fournit déjà), et les
opérations concurrentes fusionnent nativement au lieu de casser l'arbre. Deux
conséquences directes : plus besoin d'attendre un quorum pour qu'une exclusion
coupe l'accès de l'exclu (l'exclusion est transparente pour les autres membres),
et les partitions ne sont plus un cas d'erreur mais le régime normal.
Notre moteur v1 est **BeeKEM** (projet Keyhive d'Ink & Switch, le labo derrière
Automerge) : un TreeKEM qui a appris la concurrence : divergence arbitraire entre
répliques, coût logarithmique conservé, les conflits d'updates concurrents laissent
des "clés multiples" sur les nœuds de l'arbre, résorbées à l'update suivant. C'est
une crypto de recherche (papier récent, pas encore d'audit) : choix assumé pour
l'échelle, avec un repli désigné, `p2panda-encryption` (implémentation du DCGKA,
papier peer-reviewé, trajectoire d'audit), derrière la même interface.
Le **registre** (brique 4) reste dans la boucle mais change de rôle : il n'ordonne
plus les clés, il les **autorise** : chaque opération de clés doit pointer
l'opération de gouvernance qui la justifie (l'exclusion, le join...). Si la
gouvernance invalide après coup une opération déjà appliquée, on répare par
**compensation** (ré-ajouter l'exclu à tort, avec les secrets qu'il a manqués),
jamais par retour arrière.
---
## Brique 4 : le registre de gouvernance
### La chaîne de hashs
Chaque opération de gouvernance (transfert de tokens, exclusion...) est un **bloc
signé** contenant le hash du bloc précédent. Conséquence : impossible de réécrire
l'histoire sans que tout le monde le voie (changer un vieux bloc change son hash,
donc casse tous les suivants). C'est la structure de Git et de toutes les blockchains,
et elle ne vaut que ce que vaut la règle qui dit quel bloc est accepté.
### Quorum pondéré et finalité
Notre règle : un bloc devient **final** quand des détenteurs représentant plus de
50 % des tokens en circulation l'ont **contre-signé**. Le paquet bloc + signatures
s'appelle un **certificat de quorum** : n'importe qui peut vérifier, hors ligne, que
le quorum a bien été atteint (les signatures sont là, les poids se calculent). Pas
de mineurs, pas de course : les validateurs SONT les détenteurs, et la finalité
s'accumule de façon asynchrone (les contre-signatures arrivent quand les gens se
connectent). Contresigner n'est pas approuver : c'est attester la validité, et les
clients le font automatiquement pour tout bloc valide qu'ils voient : la finalité
avance à la vitesse de propagation.
### Fourches, double-spend, et pourquoi ce n'est pas une cryptomonnaie
Un **double-spend** : Eve signe deux blocs contradictoires (envoyer les mêmes tokens
à Alice dans un bloc, à Bob dans l'autre) et les diffuse dans deux partitions. À la
fusion, les deux blocs signés par la même clé avec le même parent constituent une
**fourche** : preuve mécanique de triche, résolue par la règle "premier finalisé
gagne". Ce qui nous évite toute la machinerie des cryptomonnaies : nos tokens n'ont
aucune valeur hors de leur place (pas de motivation économique au vol), les
validateurs sont connus (pas de problème Sybil, pas de proof-of-work), et chaque
place a sa chaîne (pas de consensus mondial). Il reste ~500-1000 lignes de règles de
validation déterministes, la partie qu'on spécifie formellement et qu'on audite.
### La dormance
Piège du quorum pondéré : si un détenteur de 40 % disparaît (téléphone perdu, plus
de backup), plus aucun quorum de 50 % n'est possible, la gouvernance gèle à vie.
Solution : un détenteur muet depuis 90 jours sort du **dénominateur** du calcul (ses
tokens ne comptent plus dans le "total en circulation" tant qu'il ne se manifeste
pas). Il ne perd rien : sa première signature le réintègre. Précédent : l'"inactivity
leak" d'Ethereum répond au même problème.
---
## Brique 5 : le réseau
### Bundles vs streams, et le DTN
Deux visions du réseau : le **stream** (un tuyau continu entre deux machines en
ligne, TCP, WebSocket) et le **bundle** (un paquet autonome qui se débrouille,
stocké, transporté, retransmis). Le monde des streams suppose la connexion ; notre
monde (BLE en rafales, ultrason lent, courier qui prend le métro avec les données)
est celui du **DTN** (Delay-Tolerant Networking), né chez la NASA pour
l'interplanétaire : les deux extrémités ne sont jamais en ligne en même temps, le
réseau EST le stockage intermédiaire. D'où notre abstraction : tout est bundle, et
les transports à connexion (Internet) font passer des bundles dans leurs streams
(trivial), jamais l'inverse (impossible proprement).
### Le pub/sub par tags
**Pub/sub** (publish/subscribe) : plutôt que d'adresser des machines, on s'abonne à
des sujets. Notre sujet est le **tag d'époque** d'une place : opaque pour les
non-membres, recalculable par les membres. Chaque node annonce à ses voisins "je
porte / je cherche ces tags", et les bundles suivent ces gradients d'abonnement.
C'est du routage par centres d'intérêt, pas par adresses : personne n'a besoin de
savoir où est qui.
### NAT traversal : STUN, TURN, hole punching
Sur Internet, ton téléphone n'a pas d'adresse publique : il est derrière un **NAT**
(le routeur qui partage une IP entre tous les appareils). Deux téléphones derrière
deux NAT ne peuvent pas se joindre directement sans aide :
- **STUN** : un serveur qui te dit "vu de l'extérieur, tu es telle IP:port". Léger,
il n'achemine rien.
- **Hole punching** : les deux pairs, connaissant leurs adresses vues de l'extérieur,
s'envoient des paquets simultanément ; les NAT, croyant à des réponses, laissent
passer. Marche dans la majorité des cas.
- **TURN** : quand rien ne marche, un serveur relaie le trafic (coûteux, dernier
recours).
**WebRTC** empaquette tout ça pour le navigateur (c'est sa raison d'être), et
**libp2p** le fait pour le natif (AutoNAT, DCUtR). C'est toute la valeur qu'on tire
de libp2p : ce plombing pénible et éprouvé.
### DHT
Une **DHT** (Distributed Hash Table) est un annuaire sans serveur : chaque clé
(chez nous : un tag d'époque) est stockée par les quelques nœuds dont l'ID est le
plus "proche" de la clé (proximité mathématique, XOR pour Kademlia). Pour publier ou
chercher, on navigue de proche en proche vers la bonne zone, en log(N) sauts. C'est
le rendez-vous de phase 2 : "qui est joignable pour le tag T ?" sans serveur central.
---
## Brique 6 : le stockage et les clés locales
### IndexedDB et OPFS
Les deux stockages du navigateur : **IndexedDB** est une base clé-valeur
transactionnelle (bien pour l'état, les métadonnées), **OPFS** (Origin Private File
System) est un vrai système de fichiers privé, avec accès synchrone rapide depuis un
worker (bien pour les tranches du log, gros et séquentiel).
### Passkeys, WebAuthn et l'extension PRF
**WebAuthn** est le standard d'authentification par clé matérielle : la clé privée
vit dans le **Secure Enclave** (iPhone) ou équivalent (une puce dédiée dont les clés
ne sortent jamais, déverrouillée par biométrie). Une **passkey** en est l'usage grand
public. L'extension **PRF** (Pseudo-Random Function) ajoute la pièce qui nous sert :
la passkey peut dériver un secret symétrique stable. Résultat : "Face ID → secret →
déchiffrement de la graine locale". La graine chiffrée dort dans IndexedDB, la clé
qui l'ouvre dort dans le matériel, gardée par ton visage.
---
## Brique 7 : la sérialisation
### Le problème de la canonicité
Une signature porte sur des octets exacts. Si deux implémentations sérialisent le
même objet avec un octet de différence (ordre des champs, espaces, encodage d'un
entier), la signature de l'une est invalide chez l'autre. Deux écoles : forcer un
encodage canonique (fragile, Scuttlebutt s'y est brûlé), ou notre règle : **les
octets signés sont opaques et voyagent verbatim**, on ne re-sérialise jamais ce qui
est signé. Le problème disparaît à la racine.
### CBOR et CDDL
**CBOR** (RFC 8949) est un format binaire auto-décrit : comme JSON mais compact et
binaire ; les données portent leur structure, un décodeur peut sauter les champs
qu'il ne connaît pas (c'est ce qui permet aux vieux octets de rester lisibles pour
toujours, et aux nouveaux champs d'apparaître sans casser les vieux clients).
**CDDL** (RFC 8610) est son langage de schéma : on décrit chaque format dans un
fichier lisible et vérifiable mécaniquement, qui devient une pièce de la spec.
---
## Brique 8 : le runtime
### Le pattern sans-I/O
Une machine à états pure : le moteur ne touche ni au réseau, ni au disque, ni à
l'horloge. On lui donne "voici ce qui est arrivé, voici l'heure", il répond "voici
quoi émettre, voici quoi écrire". Tout ce qui est réel (sockets, fichiers, timers)
vit dans des **drivers** par plateforme. Deux conséquences majeures : le même moteur
tourne partout à l'octet près, et on peut **simuler un réseau entier dans un test**
(50 pairs, partitions, fusions, en accéléré, reproductible). C'est le pattern des
implémentations sérieuses de protocoles en Rust (Quinn pour QUIC, str0m pour WebRTC).
### WASM, workers et SharedArrayBuffer
**WebAssembly** exécute notre Rust dans le navigateur, mais dans un modèle
mono-thread par défaut. Les **Web Workers** sont les threads du web : isolés,
communiquant par messages. Le **SharedArrayBuffer** serait la mémoire réellement
partagée entre eux ; on s'en passe parce qu'il exige des en-têtes serveur spéciaux
qui limiteraient qui peut héberger un miroir de la PWA (axiome de résistance à la
censure), et que nos flux (petits messages) ne le justifient pas.
---
## Brique 9 : le modem ultrasonore
### Moduler : transformer des octets en son
Un modem (modulateur-démodulateur) traduit des bits en signal physique et retour.
**FSK** (Frequency-Shift Keying) : chaque symbole est représenté par une fréquence
(un sifflet aigu = 1, un plus grave = 0, généralisé à une grille de fréquences pour
plusieurs bits par symbole). Le schéma ggwave émet 6 tonalités simultanées dans la
bande 18-20 kHz (inaudible aux adultes), chacune codant 4 bits. Robuste et simple :
c'est notre mode par défaut.
### FFT : lire les fréquences
La **FFT** (Fast Fourier Transform) décompose un signal en ses fréquences : on lui
donne 20 ms de micro, elle répond "il y a de l'énergie à 18 200 Hz et 19 400 Hz".
Le décodage FSK est alors une détection de pics : quelles fréquences de la grille
sont allumées → quels bits.
### Reed-Solomon : survivre aux erreurs
Le canal acoustique est sale (échos, bruits, absorption). **Reed-Solomon** est un
code correcteur : on ajoute de la redondance calculée aux données, et le décodeur
peut reconstruire les symboles perdus ou corrompus (jusqu'à un certain taux). C'est
le code des CD, des QR codes et de l'espace lointain : à chaque fois le même
problème, un canal qu'on ne peut pas nettoyer, donc des données qui se réparent.
### FDD : le full-duplex par fréquences
**FDD** (Frequency-Division Duplexing) : les deux pairs parlent en même temps, sur
des sous-bandes disjointes (A émet en 18-19 kHz, écoute en 19,5-20,5 ; B l'inverse).
Le défi : ton propre haut-parleur crie dans ton micro bien plus fort que le signal
distant (problème "near-far"), d'où filtres raides et bandes de garde. Le mode
cohérent ajoute l'**égalisation adaptative** : un filtre qui apprend en continu les
déformations du canal (échos de la pièce) et les annule, ce qui permet des
modulations plus denses et le 1-4 kbit/s.
---
## Le nommage : triangle de Zooko et petnames
### Le triangle de Zooko
Un système de noms voudrait trois propriétés : **global** (le nom désigne la même
chose pour tout le monde), **sécurisé** (personne ne peut s'approprier le nom d'un
autre), **mémorisable** (un humain peut le retenir). La conjecture de Zooko (2001) :
on ne peut en avoir que deux à la fois. Une clé publique est globale et sécurisée
mais imprononçable ; "alex" est mémorisable mais ni global ni sécurisé ; un annuaire
central donne les trois... au prix d'une autorité centrale, interdite chez nous.
Les systèmes qui prétendent tricher dans une seule couche de nom (pseudo unique +
discriminateur + règles d'unicité) accumulent des rustines : c'est le chemin qu'on
a d'abord pris, puis abandonné.
### La solution : superposer les couches (modèle petname, Stiegler 2005)
Au lieu d'un nom qui fait tout, quatre objets qui font chacun deux sommets du
triangle :
- **La clé** (`pseudo_pk`) : globale + sécurisée. La seule identité du protocole.
- **La représentation de clé** : un indice calculé depuis la clé (chiffres d'un
hash, identicon). Globale + sécurisée aussi (n'importe qui peut la recalculer,
personne ne peut la forger), et *à moitié* mémorisable : elle rend la clé
comparable d'un coup d'œil.
- **Le nom allégué** (alleged name) : ce que quelqu'un *affirme* : "appelez-moi
alex". Mémorisable, mais ni global ni sécurisé : c'est une suggestion venue du
réseau, affichée comme telle. Notre entrée `profile` est exactement ça, et le
protocole ne lui donne aucune sémantique : c'est du contenu ordinaire.
- **Le petname** : le nom que TOI tu assignes à une clé dans TA table locale
("Maman", "Alex du club"). Mémorisable + sécurisé, non global : il n'existe que
chez toi. Un chat s'appelle Garfield parce que *tu* l'appelles Garfield ;
d'autres chats s'appellent Garfield ailleurs, mais un seul dans ta maison. La
sécurité vient de la localité : un imposteur peut alléguer n'importe quoi, il ne
peut pas écrire dans ta table.
C'est le principe du carnet d'adresses érigé en mécanisme de sécurité, et c'est ce
que fait Signal en production (noms de profil non uniques + renommage local +
alertes d'homonymie). L'usurpation se combat dans la couche de perception : le
protocole garantit les clés, jamais les noms.
## Brique 10 : backup et multi-device
### Argon2, scrypt : les KDF "mémoire-dures"
Dériver une clé d'une passphrase avec un hash rapide est une erreur : un attaquant
essaie des milliards de passphrases par seconde sur GPU. Les KDF **mémoire-dures**
(Argon2, scrypt, ce dernier étant celui du format age) rendent chaque essai
volontairement coûteux en mémoire ET en temps : le brute-force devient hors de prix.
C'est la différence entre "ta passphrase doit être imprononçable" et "une bonne
passphrase suffit".
### Le format age
**age** est un format standard de chiffrement de fichiers, conçu pour remplacer GPG
en plus simple. Ce qu'on lui prend : le chiffrement **par flux en tranches** (un
backup de 2 Go se chiffre et se déchiffre sans tenir en mémoire, et une corruption
locale ne détruit pas tout), le mode passphrase avec scrypt intégré, et
l'interopérabilité (n'importe quel outil age ouvre le fichier, si on a la
passphrase).
### BIP-39 : la graine en mots
**BIP-39** transforme des octets aléatoires en une phrase de mots choisis dans une
liste de 2048 (chaque mot code 11 bits) : `velours cactus horizon...`. Inventé pour
les wallets Bitcoin, adopté partout parce que des mots se notent sur papier sans
erreur de recopie (la liste est conçue pour que les mots soient non ambigus). C'est
la forme papier de notre graine d'identité.
### Certificats d'appareils
Une **chaîne de confiance** en miniature : l'identité maîtresse signe la clé de
chaque appareil ("cet appareil est à moi"), et les places ne voient que des
appareils certifiés. Révoquer un appareil volé = publier un bloc de révocation ; les
places éjectent sa feuille MLS à la rotation suivante (avancée à maintenant),
l'identité elle-même n'est pas compromise. C'est le modèle de Signal et de tous les
systèmes multi-device sérieux : l'identité est une racine qui délègue, jamais une
clé qui se promène.