Tecnico › Chi ha inviato?

Key image

L'impronta che un output lascia quando viene speso, esattamente una volta

In breve

La key image (immagine della chiave) I = x·Hp(P), dove P è la chiave monouso dell'output e x la sua chiave privata. Per un dato output la key image è sempre la stessa, ma non rivela di quale output si tratti. La rete memorizza tutte le key image e rifiuta una transazione con una key image ripetuta.

Il problema della doppia spesa

In Bitcoin le doppie spese sono facili da individuare: ogni input punta dritto all'output che spende, e un nodo ricorda l'output come speso (l'insieme UTXO). In Monero un input punta a 16 output, e quale sia quello reale è sconosciuto. Quindi "contrassegnare l'output speso" è impossibile. Serve un modo per contrassegnare una spesa senza rivelare cosa è stato speso.

La soluzione

I = x · Hp(P)

Perché funziona:

  • Deterministica. x e P sono fissi per un output, quindi I è unica. Spendere di nuovo l'output significa pubblicare la stessa I.
  • Non collegabile. Per verificare che I corrisponda a P serve x: un estraneo vede due punti "casuali" Hp(P) e I e non può stabilire il legame (un problema di Diffie–Hellman).
  • Non falsificabile. La linkable ring signature dimostra che I è stata calcolata con lo stesso x di una delle chiavi del ring.

Perché Hp(P) e non semplicemente G? In quel caso I = x·G = P: la key image sarebbe uguale alla chiave pubblica dell'output e la spesa sarebbe subito visibile. Hp dà un punto di cui nessuno conosce il logaritmo: una "seconda base" unica per ogni output.

nuova transazionekey image I = 3f9a… database del nodo a17c… 0be2… 3f9a… ← c'è già! … ✗ rifiuto: doppia spesa il nodo non sa quale output è stato speso, solo che questa impronta è già stata vista

Il controllo del sottogruppo: il bug del 2017

Ed25519 ha 8 volte più punti del sottogruppo di G. Aggiungendo a I un punto di ordine piccolo T (con 8·T = 0) si ottiene un punto diverso I' = I + T, e in certe condizioni la ring signature risultava comunque valida. Un output: fino a 8 key image diverse, fino a 8 spese. Nel 2017 questo bug è stato trovato nel codice originale di CryptoNote; Monero lo ha corretto prima che venisse sfruttato, mentre Bytecoin è stato colpito.

La correzione: il nodo verifica che l·I = 0, cioè che I stia nel sottogruppo corretto.

Key image e wallet in sola visualizzazione

Per sapere se un tuo output è stato speso, il wallet calcola la sua key image e la cerca sulla blockchain. Per farlo serve x = Hs(8aR ‖ i) + b, cioè la spend key. Per questo un wallet in sola visualizzazione non vede le spese e mostra un saldo gonfiato. Il rimedio è esportare le key image dal wallet completo. Carrot aggiunge una chiave dedicata a questo scopo.

Key image in FCMP++

In FCMP++ la key image resta: L = x·Hp(O). Cambia il modo in cui si dimostra il suo legame con l'output: invece di un ring, una prova di appartenenza all'albero di tutti gli output. Una conseguenza importante: tutte le key image già pubblicate nelle transazioni RingCT mantengono il loro significato, quindi un vecchio output non può essere speso una seconda volta dopo il passaggio.