crisgarner.eth

Posted on Aug 02, 2023Read on Mirror.xyz

Noir 101 para Solidity Devs

En este tutorial, crearemos un sencillo "Contrato Público Secreto" utilizando Noir y Foundry. El contrato será desplegado con una función de ejecución que solo puede ser ejecutada con un "calldata" secreto, lo que significa que solo si conoces la función secreta y lo demuestras, podrás ejecutar la funcionalidad del contrato.

Puedes ver el código completo utilizado en este tutorial en el siguiente repositorio.

Primeros Pasos

Noir es un Lenguaje Específico de Dominio para sistemas de prueba de conocimiento-cero (SNARK). Sus elecciones de diseño están fuertemente influenciadas por Rust y se centran en una sintaxis simple y familiar. Aunque Noir puede ser utilizado para diferentes propósitos, este tutorial se enfoca en el desarrollo de Solidity. Utilizaremos Noir para crear los circuitos y Foundry para probar los contratos de Solidity.

Instalando Noir

A medida que Noir evoluciona constantemente, la forma recomendada de instalarlo es mediante el uso de noirup, que instala nargo, una herramienta de línea de comandos para interactuar con programas de Noir (compilar, demostrar, verificar, crear contratos, etc.). En OSX o Linux, ejecuta el siguiente comando en la terminal:

$ curl -L https://raw.githubusercontent.com/noir-lang/noirup/main/install | bash

Puedes comprobar que la instalación fue exitosa ejecutando nargo --version. Otras opciones de instalación están disponibles en la documentación oficial.

Instalando Foundry

Al igual que Noir, la forma recomendada de instalar Foundry es utilizando foundryup. Ejecuta el siguiente comando para instalarlo:

curl -L https://foundry.paradigm.xyz | bash

Dado que está fuera del alcance de este tutorial, puedes obtener más información sobre Foundry en el sitio oficial de documentación.

Instalando Noir Language Support (Opcional)

Si utilizas VS Code, te sugiero instalar la extensión "Noir Language Support". Esta extensión agrega resaltado de sintaxis, errores y advertencias de compilación, así como fragmentos de código útiles para trabajar con Noir.

https://marketplace.visualstudio.com/items?itemName=noir-lang.vscode-noir

Creando un Proyecto

Con Nargo y Foundry instalados, podemos crear un proyecto. Aunque podríamos usar los comandos forge init projectName y nargo new projectName, tendríamos que hacer algunos ajustes y limpieza de archivos. Por lo tanto, te sugiero que utilices el repositorio de Noir Starter with Foundry.

https://github.com/noir-lang/noir-starter/tree/main/with-foundry

Puedes hacer un "fork" del repositorio o utilizarlo como inspiración para ordenar los archivos desde cero. Solo ten en cuenta que necesitarás editar el archivo foundry.toml y agregar ffi y fs_permissions para que las pruebas de Foundry puedan acceder a las pruebas generadas por noir.

[profile.default]
src = "src"
out = "out"
libs = ["lib"]
fs_permissions = [{ access = "read-write", path = "./"},{ access = "read-write", path = "/tmp/"}]
ffi = true

# See more config options https://github.com/foundry-rs/foundry/tree/master/config

Creando los Circuitos

Estamos listos para crear nuestro circuito. Dirígete a la carpeta circuits/src y crea un nuevo archivo Noir llamado main.nr. Este es un circuito bastante simple que solo verifica que los valores enviados desde el contrato sean los que definimos en secreto. Utilizamos la función hash de Pedersen para crear un hash único basado en los parámetros y luego los comparamos con el hash de nuestros parámetros secretos para ver si coinciden.

main.nr

Luego, podemos construir los archivos de salida ejecutando:

$ nargo check 

Esto generará dos archivos: Prover.toml, que contiene los valores de entrada, y Verifier.toml, que tiene los valores públicos. Rellenamos los valores en "Prover.toml" si ya sabemos qué función queremos llamar y probamos la ejecución válida creando una prueba mediante el siguiente comando:

$ nargo prove nameOfProof 

Esto generará una nueva carpeta llamada proofs que contendrá un archivo de prueba con el nombre que especifiques. Dependiendo de tu computadora y código, este comando puede tardar unos segundos en ejecutarse. Luego, podemos verificar la correcta ejecución de nuestro programa mediante el siguiente comando:

$ nargo verify nameOfProof 

Si no hay errores, no se mostrará ningún mensaje. Finalmente, podemos generar el contrato del verificador mediante el siguiente comando:

$ nargo codegen-verifier 

Esto creará la carpeta contract y el contrato plonk_vk.sol, que luego podemos utilizar para verificar nuestros contratos.

Creando los Contratos

Vuelve a la carpeta del proyecto y crea dos archivos Solidity en la carpeta contract. MyToken.sol será un sencillo token ERC20 con una función pública mint que cualquiera puede llamar. Agrega la biblioteca solmate ejecutando:

$ forge install transmissions11/solmate 

MyToken.Sol

Ahora, creemos SecretCaller.sol, donde utilizaremos nuestro archivo plonk_vk.sol para verificar que el usuario que realiza la llamada conozca el secreto.

SecretCaller.Sol

Importamos el contrato del verificador y lo asignamos al constructor. Luego, podemos llamar la función verify en la función secretCall. Debemos pasar la prueba como bytes y generar los publicInputs como un array de "bytes32" para pasarlo al verificador.

SecretCaller.sol

Una vez que verifiquemos que la prueba es correcta, podemos ejecutar la llamada al contrato con la información que enviamos.

Probando los Contratos

Ahora que tenemos los contratos que queremos probar, llenemos el archivo Prover.toml con los valores correctos (puedes usar "console.log" en los archivos de prueba para ver los valores), generemos una prueba y probemos todo usando Foundry. Comienza creando el archivo SecretCaller.t.sol en el directorio de test y analicemos lo que está sucediendo:

SecretCaller.t.sol

Importamos los contratos que vamos a probar, los desplegamos y usamos una función auxiliar para obtener la prueba que generamos en los pasos anteriores. Luego, vamos a crear dos funciones de prueba que enviarán datos correctos e incorrectos para ver si podemos ejecutar la función secretCall.

SecretCall.t.sol

Luego, podemos ejecutar el comando $ forge test en la consola y las dos pruebas deberían pasar.


¡Eso es todo! Recuerda que este código es solo para fines de prueba y si alguien realiza una llamada de contrato, los datos serán públicos en el blockchain, lo que significa que cualquiera puede replicar la llamada.

Este tutorial se construyó utilizando Noir versión 0.7.1. Como se espera con un lenguaje en evolución, es probable que haya cambios en el futuro. Te sugiero que sigas la cuenta oficial de Twitter de Noir y te unas al servidor oficial de Discord en caso de que tengas alguna duda. Siéntete libre de enviarme un mensaje directo en Twitter con preguntas o comentarios a @crisgarner.