Una prueba de conocimiento cero (ZKP) es un protocolo criptográfico en el que un probador convence a un verificador de que una afirmación es verdadera sin revelar nada más allá de esa verdad. Esta guía explica el modelo mental probador-verificador, la diferencia entre pruebas interactivas y no interactivas, y las propiedades de solidez y conocimiento cero que debes considerar antes de lanzar una funcionalidad ZK. Luego recorre un bucle de verificación fuera de cadena ejecutable y un procedimiento para medir el costo de verificación en cadena contra un endpoint RPC que controles, de modo que puedas separar el comportamiento documentado del protocolo de los números que realmente observas.
Qué garantiza realmente una prueba ZK
Una prueba de conocimiento cero es un protocolo entre dos partes: un probador, que conoce un testigo secreto, y un verificador, que comprueba una afirmación sobre ese testigo. La prueba convence al verificador de que la afirmación es verdadera sin transmitir información más allá de la veracidad de la afirmación. El ejemplo canónico es demostrar que conoces el logaritmo discreto de un valor público sin imprimir el exponente, o demostrar que una transacción cuadra sin revelar los montos.
Tres propiedades importan al evaluar cualquier esquema ZK. La completitud significa que un probador honesto con un testigo válido siempre puede convencer al verificador. La solidez significa que un probador deshonesto no puede convencer al verificador de una afirmación falsa excepto con probabilidad insignificante. El conocimiento cero significa que el verificador no aprende nada más allá de la verdad de la afirmación, lo que normalmente se formaliza mostrando que un simulador puede producir transcripciones indistinguibles de las reales.
Este artículo cubre los conceptos, un flujo de verificación ejecutable y un método de medición. No afirma costos de gas específicos, tiempos de generación de pruebas ni soporte de red para ningún sistema de prueba en particular; esos dependen del circuito, del backend de prueba y de la cadena, y debes medirlos tú mismo usando el procedimiento a continuación.
- Probador: posee el testigo privado y produce la prueba.
- Verificador: comprueba la prueba contra las entradas públicas.
- Testigo: los datos secretos sobre los que trata la prueba.
- Entradas públicas: la afirmación que el verificador puede ver.
Supuestos y requisitos previos
Los ejemplos de código asumen Node.js 18 o posterior y un shell con curl. Para la sección de medición en cadena necesitas un endpoint RPC para la red donde está desplegado tu contrato verificador. Usa un marcador de posición como RPC_URL y proporciona tu propio endpoint; si estás eligiendo un proveedor, la guía de endpoints RPC y la guía de endpoints RPC multicadena explican qué comparar, mientras que el servicio de API RPC describe el acceso gestionado.
También debes saber qué sistema de prueba usa tu proyecto. Los zk-SNARKs normalmente dependen de una configuración de confianza y producen pruebas pequeñas, mientras que los zk-STARKs evitan la configuración de confianza y tienden a producir pruebas más grandes. La interfaz de verificación difiere, así que trata los fragmentos aquí como un arnés que adaptas a tu biblioteca en lugar de un reemplazo directo para cada esquema.
Pruebas interactivas versus no interactivas
En una prueba interactiva, el probador y el verificador intercambian varios mensajes. Un ejemplo clásico es la cueva de Alí Babá: el probador emerge repetidamente de un túnel aleatorio elegido por el verificador, y tras suficientes rondas el verificador queda convencido de que el probador conoce el camino secreto. Cada ronda añade solidez pero requiere que el verificador esté en línea y proporcione aleatoriedad fresca.
La mayoría de las aplicaciones blockchain necesitan pruebas no interactivas, porque un contrato verificador no puede mantener una conversación de múltiples rondas con un probador fuera de línea. La heurística de Fiat-Shamir convierte una prueba interactiva en un solo mensaje derivando los desafíos del verificador a partir de un hash de la transcripción. Por eso las pruebas ZK no interactivas a veces se llaman NIZKs, y es la forma que normalmente verificarás en cadena.
La consecuencia práctica es que tu seguridad ahora depende de que la función hash se comporte como un oráculo aleatorio. Si la derivación del desafío es predecible o la transcripción es ambigua, un probador malicioso podría falsificar pruebas. Audita cuidadosamente la separación de dominio de la transcripción Fiat-Shamir cuando implementes un circuito personalizado.
El modelo mental probador-verificador en código
El siguiente ejemplo de Node.js ilustra la forma de un bucle de verificación sin pretender ser un sistema de prueba de producción. Modela un probador que se compromete con un secreto, un verificador que comprueba un compromiso público y una comprobación de manipulación que debería fallar. Reemplaza el hash de juguete por la llamada verify de tu biblioteca cuando integres un esquema real.
Ejecútalo con node zk-harness.mjs. El resultado esperado es que la prueba honesta se verifique y la prueba manipulada sea rechazada. Si ambas pasan, tu lógica de verificación no está vinculando realmente la entrada pública a la prueba.
import { createHash } from 'node:crypto';
function commit(secret, publicInput) {
return createHash('sha256')
.update(`${publicInput}:${secret}`)
.digest('hex');
}
function verify(commitment, publicInput, revealedSecret) {
return commit(revealedSecret, publicInput) === commitment;
}
const publicInput = 'balance>=0';
const secret = 'witness-42';
const commitment = commit(secret, publicInput);
console.log('honest proof verifies:', verify(commitment, publicInput, secret));
console.log('tampered proof verifies:', verify(commitment, publicInput, 'witness-43'));
console.log('wrong public input verifies:', verify(commitment, 'balance>=100', secret));Medición del costo de verificación en cadena
El costo de verificación es el número que decide si una funcionalidad ZK es viable en una cadena determinada. No confíes en la cifra de gas de una publicación de blog; mídela contra tu propio contrato verificador y tu propio endpoint RPC. El procedimiento es: despliega el verificador, prepara una prueba válida y sus entradas públicas, llama a la función verify del verificador mediante eth_call para confirmar que devuelve true, luego envía una transacción real y lee el gas usado del recibo.
El paso eth_call es gratuito y detecta pruebas malformadas antes de que gastes gas. El paso de transacción te da el gas real consumido. Registra el número de bloque, la versión del sistema de prueba y el hash del bytecode del verificador junto con el número para que la medición sea reproducible.
Usa una tabla como la siguiente para registrar tus ejecuciones. Las celdas están intencionalmente en blanco porque los valores dependen de tu circuito y cadena; complétalas con tus propios recibos.
- | Ejecución | Sistema de prueba | Entradas públicas | Resultado de eth_call | Gas usado | Bloque |
- | --- | --- | --- | --- | --- | --- |
- | 1 | (tu sistema) | (tus entradas) | (true/false) | (del recibo) | (número de bloque) |
- | 2 | (tu sistema) | (tus entradas) | (true/false) | (del recibo) | (número de bloque) |
Comprobación RPC ejecutable para un contrato verificador
El fragmento de shell a continuación llama a un contrato verificador mediante JSON-RPC. Usa eth_call con una carga útil de calldata previamente codificada. Reemplaza RPC_URL, VERIFIER_ADDRESS y CALLDATA con tus propios valores. El resultado esperado es una respuesta JSON cuyo campo result es el booleano codificado en ABI o la salida de verificación.
Si el nodo devuelve un error, verifica que el contrato esté desplegado en esa dirección en esa cadena y que el selector de calldata coincida con la firma de la función del verificador. Un resultado 0x sin revert normalmente significa que la llamada tuvo éxito pero devolvió datos vacíos, lo que a menudo indica un desajuste de selector.
curl -s -X POST "$RPC_URL" \
-H 'Content-Type: application/json' \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "eth_call",
"params": [
{ "to": "VERIFIER_ADDRESS", "data": "CALLDATA" },
"latest"
]
}'Verificación del resultado y lectura del recibo
Después de enviar la transacción de verificación, obtén el recibo con eth_getTransactionReceipt y lee gasUsed y status. Un status de 0x1 significa que la transacción tuvo éxito; 0x0 significa que se revirtió y el gas se consumió igualmente. Compara el valor de gasUsed con tu resultado de eth_call: la llamada no consume gas, por lo que el recibo es el número autoritativo.
Para una medición reproducible, ejecuta la misma prueba al menos tres veces y registra cada recibo. La varianza puede provenir de cambios de estado, slots de almacenamiento fríos versus calientes y el calendario de gas del bloque específico. Si necesitas latencia estable para un verificador de alto volumen, un nodo dedicado elimina los efectos de vecino ruidoso que los endpoints compartidos pueden introducir.
Si estás comparando proveedores para esta carga de trabajo, mantén la metodología fija y cambia solo el endpoint. La página de precios de RPC explica las dimensiones del plan, y el directorio de redes lista las cadenas soportadas para que puedas confirmar tu cadena objetivo antes de hacer el benchmark.
Solución de problemas comunes de integración ZK
La mayoría de los errores de integración ZK caen en unos pocos grupos. La prueba se verifica fuera de cadena pero se revierte en cadena normalmente significa que las entradas públicas están codificadas de manera diferente, por ejemplo, elementos de campo serializados en un orden de bytes distinto. La prueba siempre se verifica significa que el verificador no está vinculando las entradas públicas, o que el desafío Fiat-Shamir omite parte de la transcripción. La prueba nunca se verifica a menudo apunta a una clave de verificación desajustada o a un circuito compilado con parámetros diferentes a los del verificador desplegado.
Para fallos a nivel de RPC, distingue errores de transporte de reversiones de contrato. Un error estilo -32000 con datos de reversión significa que el nodo llegó a la EVM y el contrato rechazó la llamada; un tiempo de espera o reinicio de conexión significa que el endpoint no respondió. La lógica de reintento debe tratarlos de manera diferente, porque reintentar una reversión determinista desperdicia tiempo y gas.
- Verifica el orden de bytes y el módulo del campo al codificar entradas públicas.
- Confirma que el hash de la clave de verificación coincide con el verificador desplegado.
- Registra los datos completos de reversión, no solo el mensaje de error.
- Separa los reintentos de transporte de los fallos a nivel de contrato.
Limitaciones y compensaciones
Las pruebas ZK no son gratuitas. La generación de pruebas es computacionalmente costosa y el costo crece con el tamaño del circuito. La verificación es más barata pero aún consume gas, y el costo exacto depende de las operaciones de emparejamiento o comprobaciones de hash que requiera tu esquema. Las configuraciones de confianza introducen una ceremonia cuya compromiso puede romper la solidez, por lo que algunos equipos eligen configuraciones transparentes a pesar de pruebas más grandes.
También hay un límite de privacidad que respetar. Una prueba ZK oculta el testigo, pero las entradas públicas, el momento de la transacción y los metadatos en cadena aún pueden filtrar información. Si tu modelo de amenaza incluye correlación temporal o vinculabilidad de entradas, una prueba por sí sola no es suficiente; también debes diseñar el protocolo circundante.
Por último, la madurez de las herramientas varía. Algunos sistemas de prueba tienen verificadores auditados estables, mientras que otros evolucionan rápidamente. Fija las versiones de las bibliotecas y vuelve a ejecutar tu procedimiento de medición después de cada actualización, porque un cambio en el verificador puede alterar tanto el costo de gas como los supuestos de seguridad.
Próximos pasos para una integración ZK
Comienza escribiendo la afirmación que quieres probar, el testigo y las entradas públicas. Luego elige un sistema de prueba que coincida con tu modelo de confianza y la cadena objetivo de tu verificador. Construye primero el arnés fuera de cadena, confirma que las pruebas honestas pasan y las manipuladas fallan, y solo entonces despliega el verificador.
Una vez que el verificador esté activo, ejecuta el procedimiento de medición contra un endpoint estable y registra los resultados en una tabla que puedas compartir con tu equipo. Si necesitas ayuda para seleccionar un endpoint para las cadenas que apuntas, la guía de endpoints RPC y el servicio de API RPC son los puntos de partida adecuados. Para verificación de alto volumen, evalúa un nodo dedicado y revisa los precios de RPC antes de comprometerte con un plan.