Técnico › ¿Quién envió?

Key image

La huella que deja una salida al gastarse, exactamente una vez

En resumen

La key image (imagen de clave) I = x·Hp(P), donde P es la clave de un solo uso de la salida y x su clave privada. Para una salida dada la key image es siempre la misma, pero no revela de qué salida se trata. La red guarda todas las key images y rechaza cualquier transacción con una repetida.

El problema del doble gasto

En Bitcoin el doble gasto es fácil de detectar: cada entrada apunta directamente a la salida que gasta, y el nodo recuerda esa salida como gastada (el conjunto UTXO). En Monero una entrada apunta a 16 salidas, y no se sabe cuál es la real. Así que «marcar la salida gastada» es imposible. Hace falta una forma de marcar un gasto sin revelar qué se gastó.

La solución

I = x · Hp(P)

Por qué funciona:

  • Determinista. x y P son fijos para una salida, así que I es único. Volver a gastar la salida significa publicar la misma I.
  • No vinculable. Para comprobar que I corresponde a P hace falta x: un observador externo ve dos puntos «aleatorios», Hp(P) e I, y no puede establecer la relación (un problema de Diffie–Hellman).
  • Infalsificable. La firma de anillo vinculable demuestra que I se calculó con el mismo x que una de las claves del anillo.

¿Por qué Hp(P) y no simplemente G? Porque entonces I = x·G = P: la key image sería igual a la clave pública de la salida y el gasto se vería al instante. Hp da un punto cuyo logaritmo nadie conoce, una «segunda base» única para cada salida.

nueva transacciónkey image I = 3f9a… base de datos a17c… 0be2… 3f9a… ← ¡ya está! … ✗ rechazo: doble gasto el nodo no sabe qué salida se gastó, solo que ya vio esta huella

La comprobación del subgrupo: el error de 2017

Ed25519 tiene 8 veces más puntos que el subgrupo de G. Sumar a I un punto de orden pequeño T (con 8·T = 0) da un punto distinto I' = I + T, y bajo ciertas condiciones la firma de anillo seguía verificándose. Una salida: hasta 8 key images distintas, hasta 8 gastos. En 2017 se encontró este error en el código original de CryptoNote; Monero lo corrigió antes de que se explotara, mientras que en Bytecoin sí se explotó.

La solución: el nodo comprueba que l·I = 0, es decir, que I está en el subgrupo correcto.

Key images y monederos de solo lectura

Para saber si tu salida está gastada, el monedero calcula su key image y la busca en la blockchain. Para eso hace falta x = Hs(8aR ‖ i) + b, es decir, la clave de gasto. Por eso un monedero de solo lectura no ve los gastos y muestra un saldo inflado. La solución es exportar las key images desde el monedero completo. Carrot añade una clave dedicada para esto.

Key images en FCMP++

En FCMP++ la key image se mantiene: L = x·Hp(O). Lo que cambia es cómo se demuestra su relación con la salida: en lugar de un anillo, una prueba de pertenencia al árbol de todas las salidas. Una consecuencia importante: todas las key images ya publicadas en transacciones RingCT conservan su significado, y una salida antigua no se puede gastar por segunda vez tras el cambio.