Movatterモバイル変換


[0]ホーム

URL:


Skip to content
DEV Community
Log in Create account

DEV Community

Ahmed Castro
Ahmed Castro

Posted on • Edited on

     

Interfaces con privacidad en Solidity y zk-WASM

Los usuarios de blockchain necesitan privacidad en sus finanzas, identidad, redes sociales y más. Pero web3 es transparente y público. Entonces, ¿cómo pueden los usuarios proteger su anonimato en un ambiente con estas características?

La clave es crear pruebas de computación en un lugar donde únicamente el usuario tiene acceso, donde los datos del usuario estén seguros. Ese lugar es precisamente el navegador, antes que los datos del usuarios toquen el internet. A esto le llamamos generación de pruebas a nivel de cliente, "client side proving", o "browser proving" en inglés.

diagrama aplicacion zk

Para mantener los parámetros privados, estos nunca deben salir de nuestro navegador

Conozcamos, con un ejemplo práctico y sencillo, cómo crear interfaces que hagan uso de zk-wasm, la tecnología que hace esto posible.

Dependencias

Si aún no lo tienes, instala NPM, yo estaré usando la versión 20.

curl-o-https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash nvm install 20
Enter fullscreen modeExit fullscreen mode

Para este ejemplo usaremos circom, si no lo tienes instalado puedes hacerlo con los comandos a continuación.

curl--proto'=https'--tlsv1.2 https://sh.rustup.rs-sSf | shgit clone https://github.com/iden3/circom.gitcdcircomcargo build--releasecargoinstall--path circomnpminstall-g snarkjs
Enter fullscreen modeExit fullscreen mode

1. Crea un circuito

Haremos un ejemplo muy sencillo: generar una prueba de computación de una multiplicacióna*b=c pero manteniendo privadosa yb. Si te interesa un ejemplo más avanzado con un caso de uso real visitami artículo anterior.

Circom nos permite crear circuitos, que permiten generar pruebas de ejecución ofuscando los parámetros.

Comienza creando el circuito a continuación.

myCircuit.circom

pragmacircom2.0.0;templateMultiplier(){signalinputa;signalinputb;signaloutputc;c<==a*b;}componentmain=Multiplier();
Enter fullscreen modeExit fullscreen mode

Ahora compílalo y genera los artefactos que usaremos más adelante.

circom myCircuit.circom--r1cs--wasm--symsnarkjs powersoftau new bn128 12 pot12_0000.ptau-vsnarkjs powersoftau contribute pot12_0000.ptau pot12_0001.ptau--name="First contribution"-vsnarkjs powersoftau prepare phase2 pot12_0001.ptau pot12_final.ptau-vsnarkjs groth16 setup myCircuit.r1cs pot12_final.ptau myCircuit_0000.zkeysnarkjs zkey contribute myCircuit_0000.zkey myCircuit_0001.zkey--name="1st Contributor Name"-vsnarkjs zkeyexportverificationkey myCircuit_0001.zkey verification_key.json
Enter fullscreen modeExit fullscreen mode

2. Lanza los contratos

El siguiente comando generará un contrato verificador en el archivo deverifier.sol. Lánzalo en un blockchain de preferencia. Este contrato contiene la funciónverifyProof() que recibe por parámetro una prueba de computación hecha con nuestro circuito y devuelvetrue si la prueba es correcta.

Nota: Este contrato es compatible con L1 EVMs, L2 optimistas, pero en términos de L2 ZK, actualmente únicamente es compatible con Scroll.

snarkjs zkeyexportsolidityverifier myCircuit_0001.zkey verifier.sol
Enter fullscreen modeExit fullscreen mode

Ahora lanza el siguiente contrato delógica personalizada pasando como parámetro de constructor el address del contrato verificador que lanzamos anteriormente. En este contrato puedes agregar la lógica en solidity que desees, por ejemplo el conteo de votos de un sistema de votación o la recepción o envío de tokens ERC20 en un sistema DeFi anónimo. En este ejemplo únicamente almacenaremos el resultado de la multiplicación que hicimos en nuestro circuito.

// SPDX-License-Identifier: MITpragmasolidity>=0.7.0<0.9.0;interfaceICircomVerifier{functionverifyProof(uint[2]calldata_pA,uint[2][2]calldata_pB,uint[2]calldata_pC,uint[1]calldata_pubSignals)externalviewreturns(bool);}contractCircomCustomLogic{ICircomVerifiercircomVerifier;uintpublicpublicInput;constructor(addresscircomVeriferAddress){circomVerifier=ICircomVerifier(circomVeriferAddress);}functionsendProof(uint[2]calldata_pA,uint[2][2]calldata_pB,uint[2]calldata_pC,uint[1]calldata_pubSignals)public{// ZK verificationcircomVerifier.verifyProof(_pA,_pB,_pC,_pubSignals);// Your custom logicpublicInput=_pubSignals[0];}}
Enter fullscreen modeExit fullscreen mode

3. Construye un frontend

Ahora crea la siguiente estructura de archivos:

js/  blockchain_stuff.js  snarkjs.min.jsjson_abi/  MyContract.jsonzk_artifacts/  myCircuit_final.zkey  myCircuit.wasm  verification_key.jsonindex.html
Enter fullscreen modeExit fullscreen mode
  • js/snarkjs.min.js: descargaeste archivo que contiene la librería de snark.js
  • json_abi/MyContract.json: el ABI del contratoCircomCustomLogic que recién lanzamos, por ejemplo en Remix, lo puedes hacer dando clic en el botón "ABI" en la pestaña de compilación.
  • zk_artifacts: coloca en esta carpeta los artefactos generados anteriormente. Nota: Cambia el nombre demyCircuit_0002.zkey pormyCircuit_final.zkey
  • index.html yjs/blockchain_stuff.js los detallo a continuación

El archivo HTML a continuación describe la interfaz gráfica donde colocaremos los números a multiplicar. En un ambiente de producción recomendaría usar un frontend framework como react, vue o angular. Este ejemplo es con fines didácticos.

index.html

<!DOCTYPE html><htmllang="en"><head><metacharset="utf-8"></head><body><inputid="connect_button"type="button"value="Connect"onclick="connectWallet()"style="display: none"></input><pid="account_address"style="display: none"></p><pid="web3_message"></p><pid="contract_state"></p><inputtype="input"value=""id="a"></input><inputtype="input"value=""id="b"></input><inputtype="button"value="Send Proof"onclick="_sendProof()"></input><br><scripttype="text/javascript"src="https://cdnjs.cloudflare.com/ajax/libs/web3/1.3.5/web3.min.js"></script><scripttype="text/javascript"src="js/blockchain_stuff.js"></script><scripttype="text/javascript"src="js/snarkjs.min.js"></script></body></html><script>function_sendProof(){a=document.getElementById("a").valueb=document.getElementById("b").valuesendProof(a,b)}</script>
Enter fullscreen modeExit fullscreen mode

Nuestro archivo de javascript contiene tanto la lógica de generación de pruebas zk usando la librería snark.js como la lógica de blockchain usando la librería web3.js. En un ambiente de producción recomendaría usar typescript y no javascript vainilla, este ejemplo es con fines didácticos.

js/blockchain_stuff.js

constNETWORK_ID=534351constMY_CONTRACT_ADDRESS="0xFdAFc996a60bC5fEB307AAF81b1eD0A34a954F06"constMY_CONTRACT_ABI_PATH="./json_abi/MyContract.json"varmy_contractvaraccountsvarweb3functionmetamaskReloadCallback(){window.ethereum.on('accountsChanged',(accounts)=>{document.getElementById("web3_message").textContent="Se cambió el account, refrescando...";window.location.reload()})window.ethereum.on('networkChanged',(accounts)=>{document.getElementById("web3_message").textContent="Se el network, refrescando...";window.location.reload()})}constgetWeb3=async()=>{returnnewPromise((resolve,reject)=>{if(document.readyState=="complete"){if(window.ethereum){constweb3=newWeb3(window.ethereum)window.location.reload()resolve(web3)}else{reject("must install MetaMask")document.getElementById("web3_message").textContent="Error: Porfavor conéctate a Metamask";}}else{window.addEventListener("load",async()=>{if(window.ethereum){constweb3=newWeb3(window.ethereum)resolve(web3)}else{reject("must install MetaMask")document.getElementById("web3_message").textContent="Error: Please install Metamask";}});}});};constgetContract=async(web3,address,abi_path)=>{constresponse=awaitfetch(abi_path);constdata=awaitresponse.json();constnetId=awaitweb3.eth.net.getId();contract=newweb3.eth.Contract(data,address);returncontract}asyncfunctionloadDapp(){metamaskReloadCallback()document.getElementById("web3_message").textContent="Please connect to Metamask"varawaitWeb3=asyncfunction(){web3=awaitgetWeb3()web3.eth.net.getId((err,netId)=>{if(netId==NETWORK_ID){varawaitContract=asyncfunction(){my_contract=awaitgetContract(web3,MY_CONTRACT_ADDRESS,MY_CONTRACT_ABI_PATH)document.getElementById("web3_message").textContent="You are connected to Metamask"onContractInitCallback()web3.eth.getAccounts(function(err,_accounts){accounts=_accountsif(err!=null){console.error("An error occurred:"+err)}elseif(accounts.length>0){onWalletConnectedCallback()document.getElementById("account_address").style.display="block"}else{document.getElementById("connect_button").style.display="block"}});};awaitContract();}else{document.getElementById("web3_message").textContent="Please connect to Scroll Testnet";}});};awaitWeb3();}asyncfunctionconnectWallet(){awaitwindow.ethereum.request({method:"eth_requestAccounts"})accounts=awaitweb3.eth.getAccounts()onWalletConnectedCallback()}loadDapp()constonContractInitCallback=async()=>{varpublicInput=awaitmy_contract.methods.publicInput().call()varcontract_state="Public input:"+publicInputdocument.getElementById("contract_state").textContent=contract_state;}constonWalletConnectedCallback=async()=>{}//// Functions ////constsendProof=async(a,b)=>{document.getElementById("web3_message").textContent="Generating proof...";const{proof,publicSignals}=awaitsnarkjs.groth16.fullProve({a:a,b:b},"../zk_artifacts/myCircuit.wasm","../zk_artifacts/myCircuit_final.zkey");constvkey=awaitfetch("../zk_artifacts/verification_key.json").then(function(res){returnres.json();});constres=awaitsnarkjs.groth16.verify(vkey,publicSignals,proof);pA=proof.pi_apA.pop()pB=proof.pi_bpB.pop()pC=proof.pi_cpC.pop()document.getElementById("web3_message").textContent="Proof generated please confirm transaction.";constresult=awaitmy_contract.methods.sendProof(pA,pB,pC,publicSignals).send({from:accounts[0],gas:0,value:0}).on('transactionHash',function(hash){document.getElementById("web3_message").textContent="Executing...";}).on('receipt',function(receipt){document.getElementById("web3_message").textContent="Success.";}).catch((revertReason)=>{console.log("ERROR! Transaction reverted:"+revertReason.receipt.transactionHash)});}
Enter fullscreen modeExit fullscreen mode

4. Prueba la aplicación

Antes de probar, debes adaptar las variablesNETWORK_ID yMY_CONTRACT_ADDRESS enjs/blockchain_stuff.js.NETWORK_ID es el identificador único de la chain que estés usando, en este ejemplo estoy usando534351 que representa a Scroll Sepolia Testnet, si deseas usar otro te recomiendo buscar el identificador enchainlist. Por otro coloca el address del contratoCircomCustomLogic que recién lanzaste en la variableMY_CONTRACT_ADDRESS.

Ahora estás listo para probar la aplicación en cualquier servidor web. Usualmente yo usolite-server para desarrollar, así lo instalas y levantas un servidor, solo asegúrate de estar en la carpeta del proyecto:

npminstall-g lite-server#para instalarlite-server#para levantar el servidor
Enter fullscreen modeExit fullscreen mode

ejemplo de circuito multiplicador zk
Una vez todo esté listo, tu aplicación debería de verse de esta manera

¿Qué más necesito aprender para desarrollar una zkDapp?

Para desarrollar una aplicación descentralizada y anónima necesitarás una combinación de conocimientos en Circom, Solidity y programación web. Dependiendo de los casos de uso también ocuparás un poco de programación backend en el caso de necesitar un Relayer. Estaré creando guías sobre estos temas así que te invito a que te suscribas.

También te dejo un par de materiales de aprendizaje como siguiente paso:

¡Gracias por leer esta guía!

Sígueme en dev.to y enYoutube para todo lo relacionado al desarrollo en Blockchain en Español.

Top comments(0)

Subscribe
pic
Create template

Templates let you quickly answer FAQs or store snippets for re-use.

Dismiss

Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment'spermalink.

For further actions, you may consider blocking this person and/orreporting abuse

Videos sobre programación en blockchain en español
  • Joined

More fromAhmed Castro

DEV Community

We're a place where coders share, stay up-to-date and grow their careers.

Log in Create account

[8]ページ先頭

©2009-2025 Movatter.jp