Technique › Qui a envoyé ?

Key image

L’empreinte qu’une sortie laisse en étant dépensée — une seule et unique fois

En bref

La key image (image de clé) I = x·Hp(P), où P est la clé à usage unique de la sortie et x sa clé privée. Pour une sortie donnée, la key image est toujours la même, mais elle ne révèle pas de quelle sortie il s’agit. Le réseau conserve toutes les key images et rejette une transaction dont la key image est répétée.

Le problème de la double dépense

Dans Bitcoin, les doubles dépenses sont faciles à détecter : chaque entrée désigne directement la sortie qu’elle dépense, et un nœud mémorise la sortie comme dépensée (l’ensemble UTXO). Dans Monero, une entrée désigne 16 sorties, et on ignore laquelle est la vraie. « Marquer la sortie dépensée » est donc impossible. Il faut un moyen de marquer une dépense sans révéler ce qui a été dépensé.

La solution

I = x · Hp(P)

Pourquoi cela fonctionne :

  • Déterministe. x et P sont fixes pour une sortie, donc I est unique. Dépenser à nouveau la sortie oblige à publier le même I.
  • Non reliable. Pour vérifier que I correspond à P, il faut x : un observateur voit deux points « aléatoires » Hp(P) et I et ne peut pas établir le lien (un problème de Diffie–Hellman).
  • Infalsifiable. La signature en anneau liable prouve que I a été calculé avec le même x que l’une des clés de l’anneau.

Pourquoi Hp(P) et pas simplement G ? On aurait alors I = x·G = P — la key image serait égale à la clé publique de la sortie et la dépense serait immédiatement visible. Hp donne un point dont personne ne connaît le logarithme — une « seconde base » propre à chaque sortie.

nouvelle transactionkey image I = 3f9a… base du nœud a17c… 0be2… 3f9a… ← déjà présente ! … ✗ rejet : double dépense le nœud ignore quelle sortie a été dépensée — il sait seulement que cette empreinte a déjà été vue

La vérification du sous-groupe : le bug de 2017

Ed25519 compte 8 fois plus de points que le sous-groupe de G. Ajouter à I un point d’ordre faible T (avec 8·T = 0) donne un point différent I' = I + T, et sous certaines conditions la signature en anneau restait valide. Une sortie — jusqu’à 8 key images différentes — jusqu’à 8 dépenses. En 2017, ce bug a été découvert dans le code original de CryptoNote ; Monero l’a corrigé avant toute exploitation, tandis que Bytecoin a été exploité.

Le correctif : le nœud vérifie que l·I = 0, c’est-à-dire que I appartient au bon sous-groupe.

Key images et portefeuilles en lecture seule

Pour savoir si votre sortie est dépensée, le portefeuille calcule sa key image et la cherche sur la blockchain. Cela nécessite x = Hs(8aR ‖ i) + b — c’est-à-dire la clé de dépense. Un portefeuille en lecture seule ne voit donc pas les dépenses et affiche un solde gonflé. La solution de contournement consiste à exporter les key images depuis le portefeuille complet. Carrot ajoute une clé dédiée à cet usage.

Les key images dans FCMP++

Dans FCMP++, la key image demeure : L = x·Hp(O). Ce qui change, c’est la façon de prouver son lien avec la sortie — au lieu d’un anneau, une preuve d’appartenance à l’arbre de toutes les sorties. Conséquence importante : toutes les key images déjà publiées dans des transactions RingCT conservent leur sens — une ancienne sortie ne peut pas être dépensée une seconde fois après la transition.