Implementar ZKPs en Ethereum: Tutorial Práctico
En este artículo detallado exploraremos cómo integrar Pruebas de Conocimiento Cero (ZKPs) en la blockchain de Ethereum, desde la teoría básica hasta un ejemplo completo con circom y snarkjs, incluyendo la interacción en Solidity y despliegue en testnets.
Índice
- 1. ¿Por qué ZKPs en Ethereum
- 2. Tipos de ZKPs: SNARK vs STARK
- 3. Entorno de desarrollo y herramientas
- 4. Creación de circuitos con circom
- 5. Configuración de la fase de confianza
- 6. Generación de pruebas y test de off-chain
- 7. Smart contract verificador en Solidity
- 8. Despliegue y verificación on-chain
- 9. Buenas prácticas y optimización
- 10. Referencias
1. ¿Por qué ZKPs en Ethereum
Las Zero-Knowledge Proofs (ZKPs) permiten demostrar la validez de una afirmación sin revelar información adicional. En Ethereum, representan una solución potente para:
- Privacidad: ocultar datos sensibles (identidad, balances).
- Escalabilidad: rollups zk-rollup que procesan transacciones off-chain y envían una prueba compacta on-chain.
- Interoperabilidad: verificar datos de otras cadenas sin confianza externa.
2. Tipos de ZKPs: SNARK vs STARK
Existen varias familias de ZKPs las más populares en Ethereum son:
- zk-SNARK: pruebas pequeñas, verificación rápida, requieren fase de confianza (trusted setup).
- zk-STARK: sin fase de confianza, mayor transparencia, pero pruebas más grandes y más lentas de verificar.
En este tutorial nos centraremos en zk-SNARK usando circom y snarkjs.
3. Entorno de desarrollo y herramientas
Antes de comenzar, asegúrate de contar con lo siguiente:
| Herramienta | Versión Recomendada | Instalación |
|---|---|---|
| Node.js npm | >= 14 | https://nodejs.org |
| circom | 2.x | npm install -g circom |
| snarkjs | 0.5.x | npm install -g snarkjs |
| Hardhat | >=2.0 | npm install –save-dev hardhat |
| Solidity | ^0.8.0 | Incluido en Hardhat |
4. Creación de circuitos con circom
Un circuito define la relación matemática entre entradas y salidas. Vamos a desarrollar un ejemplo de prueba de preimagen de hash con MiMC.
4.1. Archivo mixtHash.circom
component main { public [out] private [in] }
template MiMCCircuit() {
signal input in
signal output out
// iteraciones de MiMC
var rounds = 91
var c = 0
signal x = in
for (var i = 0 i < rounds i ) {
x <== (x c) 3
c
}
out <== x
}
instantiate main = MiMCCircuit()
Este circuito toma un in privado y genera un out público.
4.2. Compilar el circuito
circom mimc.circom --r1cs --wasm --sym -o build
Obtendrás:
build/mimc.r1cs: definición del circuito.build/mimc.wasm: para generar el testigo.build/mimc.sym: símbolos útiles para debugging.
5. Configuración de la fase de confianza
La construcción Groth16 requiere un Trusted Setup. Usaremos snarkjs:
- Inicialización de Phase 1 (Powers of Tau):
snarkjs powersoftau new bn128 12 pot12_0000.ptau snarkjs powersoftau contribute pot12_0000.ptau pot12_0001.ptau --name=First contribution # repetir varias contribuciones para mayor seguridad... snarkjs powersoftau prepare phase2 pot12_0001.ptau pot12_final.ptau
- Generación de claves específicas del circuito:
snarkjs groth16 setup build/mimc.r1cs pot12_final.ptau mimc_0000.zkey snarkjs zkey contribute mimc_0000.zkey mimc_final.zkey --name=Key Contributor snarkjs zkey export verificationkey mimc_final.zkey verification_key.json
6. Generación de pruebas y test off-chain
Con las claves listas, se puede generar el testigo y la prueba:
- Calcular el testigo usando el WASM:
node build/mimc_js/generate_witness.js build/mimc_js/mimc.wasm input.json witness.wtns
Donde input.json contiene:
{
in: 123456
}
- Generar la prueba y los parámetros públicos:
snarkjs groth16 prove mimc_final.zkey witness.wtns proof.json public.json
snarkjs groth16 verify verification_key.json public.json proof.json
Si todo es correcto, la prueba es válida y lista para llevarse a la blockchain.
7. Smart contract verificador en Solidity
snarkjs puede generar un contrato de verificación:
snarkjs zkey export solidityverifier mimc_final.zkey Verifier.sol
Ejemplo de uso en Solidity:
pragma solidity ^0.8.0
import ./Verifier.sol
contract MiMCSnark {
Verifier public verifier
constructor(address _verifier) {
verifier = Verifier(_verifier)
}
function verifyProof(
uint[2] memory a,
uint[2][2] memory b,
uint[2] memory c,
uint[1] memory input
) external view returns (bool) {
return verifier.verifyProof(a, b, c, input)
}
}
8. Despliegue y verificación on-chain
Usando Hardhat, configura el script de despliegue:
// scripts/deploy.js
async function main() {
const Verifier = await ethers.getContractFactory(Verifier)
const verifier = await Verifier.deploy()
await verifier.deployed()
const MiMCSnark = await ethers.getContractFactory(MiMCSnark)
const mimc = await MiMCSnark.deploy(verifier.address)
await mimc.deployed()
console.log(Verifier:, verifier.address)
console.log(MiMCSnark:, mimc.address)
}
main()
Ejecuta:
npx hardhat run scripts/deploy.js --network goerli
Luego, desde un script o frontend puedes llamar a verifyProof pasando los datos de proof.json y public.json.
9. Buenas prácticas y optimización
- Minimizar inputs públicos: más valores públicos aumentan el gas.
- Batch proofs: agrupar varias pruebas en una sola transacción.
- Verificación off-chain: usar relayers o oráculos para disminuir costos.
- Auditorías: revisar circuitos y contratos, especialmente la fase de confianza.
10. Referencias
- Documentación oficial de circom
- snarkjs – Guía completa
- Hardhat – Ethereum Development Environment
- Solidity – Documentación oficial
- EIP-197: zk-SNARK precompile
Con este tutorial práctico tienes todas las piezas para implementar ZKPs en Ethereum: desde crear y compilar circuitos, generar la confianza, construir y desplegar contratos de verificación, hasta las recomendaciones de optimización. ¡Adelante y construye la próxima generación de dApps privadas y escalables!
Deja una respuesta