¡Bienvenido! ¿Eres nuevo en Zcash?
La red de Zcash es joven, ¡pero evoluciona rápidamente! ¡Regístrate y nos pondremos en contacto con más información sobre cómo puedes comenzar con Zcash!

Idioma

Cómo Funcionan Las Transacciones Entre Direcciones Blindadas

Ariel Gabizon | Nov 29, 2016

En 'Anatomía de una transacción Zcash' dimos una visión general de las transacciones Zcash. El propósito de este post es proporcionar una explicación simplificada de cómo funcionan las transacciones que preservan la privacidad en Zcash, y dónde entran en juego exactamente las pruebas de Conocimiento-Cero. Siguiendo la terminología de ese post, nos estamos centrando aquí exclusivamente en las transacciones entre direcciones blindadas (comúnmente llamadas z-addrs).

Para concentrarnos en comprender el aspecto de preservación de la privacidad, dejemos a un lado todo lo que tiene que ver con llegar al consenso usando una Prueba de trabajo y el blockchain, y centrémonos en un nodo particular que ha obtenido la lista correcta de las salidas de transacciones no gastadas.

Recordemos primero cómo se ve esta lista en el blockchain de bitcoin. Cada salida de transacción no gastada (UTXO) se puede considerar como una "nota" no gastada que es descrita por la dirección/clave pública de su propietario y la cantidad de BTC que contiene. Para simplificar la presentación, supongamos que cada nota de esas contiene exactamente 1 BTC, y que hay como máximo una nota por dirección. Así, en un momento dado, la base de datos de un nodo consiste en una lista de notas no gastadas, donde cada nota se puede describir simplemente por la dirección del propietario. Por ejemplo, la base de datos puede tener este aspecto:

\(\mathsf{Note}_1=\) \((\mathsf{PK}_1)\), \(\mathsf{Note}_2=\) \((\mathsf{PK}_2)\), \(\mathsf{Note}_3=\) \((\mathsf{PK}_3)\)

Supongamos que \(\mathsf{PK}_1\) es la dirección de Alice y que ella desea enviar su nota de 1 BTC a la dirección de Bob \(\mathsf{PK}_4.\) Ella envía un mensaje que dice esencialmente "Mueve 1 BTC de \(\mathsf{PK}_1\) a \(\mathsf{PK}_4\)" a todos los nodos. Ella firma este mensaje con la clave secreta \(\mathsf{sk}_1\) correspondiente a \(\mathsf{PK}_1,\) y esto convence al nodo de que ella tiene el derecho de mover el dinero de \(\mathsf{PK}_1.\) Después de que el nodo comprueba la firma y comprueba que existe realmente una nota de 1 BTC con dirección \(\mathsf{PK}_1,\) ese nodo actualizará su base de datos en consecuencia:

\(\mathsf{Note}_4=\) \((\mathsf{PK}_4)\), \(\mathsf{Note}_2=\) \((\mathsf{PK}_2)\), \(\mathsf{Note}_3=\) \((\mathsf{PK}_3)\)

Ahora supongamos que cada nota también contiene un 'número de serie' al azar (también conocido como identificador único) \(r.\) Pronto veremos que esto es útil para obtener privacidad. Por lo tanto, la base de datos se verá más o menos así:

\(\mathsf{Note}_1=\) \((\) \(\mathsf{PK}_1\) \(,\) \(r_1)\), \(\mathsf{Note}_2=\) \((\) \(\mathsf{PK}_2\) \(,\) \(r_2)\), \(\mathsf{Note}_3=\) \((\) \(\mathsf{PK}_3\) \(,\) \(r_3)\)

Un primer paso natural hacia la privacidad sería hacer que el nodo almacene sólo "datos cifrados", o simplemente hashes, de las notas, en lugar de las notas mismas.

\(\mathsf{H}_1=\) \(\mathbf{HASH}(\mathsf{Note}_1)\), \(\mathsf{H}_2=\) \(\mathbf{HASH}(\mathsf{Note}_2)\), \(\mathsf{H}_3=\) \(\mathbf{HASH}(\mathsf{Note}_3)\)

Como segundo paso para preservar la privacidad, el nodo continuará almacenando el hash de una nota incluso después de haber sido gastada. Por lo tanto, ya no es una base de datos de notas no gastadas, sino más bien una base de datos de todas las notas que alguna vez han existido.

La cuestión principal ahora es cómo distinguir, sin destruir la privacidad, entre notas que han sido gastadas y notas que no. Aquí es donde entra el nullifier set, o lista anuladora. Esta es una lista de hashes de todos los números de serie de notas que han sido gastadas. Cada nodo almacena la lista anuladora, además de la lista de notas hasheadas. Por ejemplo, después que la \(\mathsf{Note}_2\) ha sido gastada, la base de datos del nodo podría verse así:

Notas hasheadas Lista anuladora
\(\mathsf{H}_1=\) \(\mathbf{HASH}(\mathsf{Note}_1)\) \(\mathsf{nf}_1=\) \(\mathbf{HASH}(\mathsf{r}_2)\)
\(\mathsf{H}_2=\) \(\mathbf{HASH}(\mathsf{Note}_2)\)  
\(\mathsf{H}_3=\) \(\mathbf{HASH}(\mathsf{Note}_3)\)  

Cómo se hace una transacción

Ahora supongamos que Alice posee la \(\mathsf{Note}_1\) y desea enviarla a Bob, cuya clave pública es \(\mathsf{PK}_4.\) Asumiremos, para simplificar, que Alice y Bob tienen un canal privado entre ellos aunque esto no es realmente necesario en Zcash. Básicamente, Alice invalidará su nota publicando su anulador, y al mismo tiempo creará una nueva nota que es controlada por Bob.

Más precisamente, ella hace lo siguiente:

  1. Ella elige aleatoriamente un nuevo número de serie \(r_4\) y determina la nueva nota \(\mathsf{Note}_4=\) \((\) \(\mathsf{PK}_4\) \(,\) \(r_4).\)
  2. Ella envía la \(\mathsf{Note}_4\) a Bob en privado.
  3. Ella envía el anulador de la \(\mathsf{Note}_1,\) \(\mathsf{nf}_2=\) \(\mathbf{HASH}(\mathsf{r}_1)\) a todos los nodos.
  4. Ella envía el hash de la nueva nota \(\mathsf{H}_4=\) \(\mathbf{HASH}(\mathsf{Note}_4)\) a todos los nodos.

Ahora, cuando un nodo recibe \(\mathsf{nf}_2\) y \(\mathsf{H}_4,\) verificará si la nota correspondiente a \(\mathsf{nf}_2\) ya ha sido gastada, simplemente comprobando si \(\mathsf{nf}_2\) ya existe en la lista anuladora. Si no existe aún, el nodo añade \(\mathsf{nf}_2\) a la lista anuladora y agrega \(\mathsf{H}_4\) a la lista de notas hasheadas; de esta manera, valida la transacción entre Alice y Bob.

Notas hasheadas Lista anuladora
\(\mathsf{H}_1=\) \(\mathbf{HASH}(\mathsf{Note}_1)\) \(\mathsf{nf}_1=\) \(\mathbf{HASH}(\mathsf{r}_2)\)
\(\mathsf{H}_2=\) \(\mathbf{HASH}(\mathsf{Note}_2)\) \(\mathsf{nf}_2=\) \(\mathbf{HASH}(\mathsf{r}_1)\)
\(\mathsf{H}_3=\) \(\mathbf{HASH}(\mathsf{Note}_3)\)  
\(\mathsf{H}_4=\) \(\mathbf{HASH}(\mathsf{Note}_4)\)  

... pero espera un segundo, comprobamos que la \(\mathsf{Note}_1\) no fue gastada antes... pero no comprobamos si pertenece a Alice. De hecho, no comprobamos que fuera una nota 'real' siquiera, real en el sentido de que su hash estuviera en la tabla de notas hasheadas del nodo. La forma sencilla de arreglar esto sería que Alice simplemente publicara la \(\mathsf{Note}_1,\) en lugar de su hash; pero por supuesto, esto socavaría la privacidad que estamos tratando de lograr.

Es aquí que las pruebas de Conocimiento--Cero vienen al rescate:

Además de los pasos anteriores, Alice publicará un proof-string \(\pi\) convenciendo a los nodos de que quienquiera que publicó esta transacción conoce los valores \(\mathsf{PK}_1,\) \(\mathsf{sk}_1,\) y \(r_1\) de manera que

  1. El hash de la nota \(\mathsf{Note}_1=\) (\(\mathsf{PK}_1,\) \(r_1)\) existe en la lista de notas hasheadas;
  2. \(\mathsf{sk}_1\) es la clave privada correspondiente a \(\mathsf{PK}_1\) (y por lo tanto, quienquiera que la conozca es el legítimo propietario de la \(\mathsf{Note}_1)\);
  3. El hash de \(r_1\) es \(\mathsf{nf}_2\), (y por lo tanto, si \(\mathsf{nf}_2\) ─que ahora sabemos que es el anulador de la \(\mathsf{Note}_1\) ─ no está actualmente en la lista anuladora, la \(\mathsf{Note}_1\) todavía no ha sido gastada).

Las propiedades de las pruebas de Conocimiento-Cero asegurarán que la \(\pi\) no revele ninguna información sobre \(\mathsf{PK}_1,\) \(\mathsf{sk}_1,\) o \(r_1\).

Los principales puntos del artículo en los que hemos 'hecho trampa' u omitido detalles

Queremos enfatizar que esta ha sido una descripción muy simplificada, y recomendamos consultar las especificaciones del protocolo para ver todos los detalles.

Estas son algunas de las cosas principales que fueron pasadas por alto:

  1. Las notas hasheadas necesitan ser almacenadas no como una simple lista, sino en un árbol de Merkle. Esto juega un papel importante para hacer que las pruebas de Conocimiento-Cero sean eficientes. Además, necesitamos almacenar un compromiso de ocultamiento y vinculación computacional de la nota, y no solamente su hash.
  2. El anulador necesita ser definido de una manera ligeramente más compleja para asegurar la privacidad futura del receptor en relación con el remitente.
  3. No hemos entrado en detalles sobre cómo eliminar la necesidad de un canal privado entre remitente y destinatario.