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.
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.
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.
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.
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.
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.
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
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.
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.
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
Ahora, creemos SecretCaller.sol
, donde utilizaremos nuestro archivo plonk_vk.sol
para verificar que el usuario que realiza la llamada conozca el secreto.
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.
Una vez que verifiquemos que la prueba es correcta, podemos ejecutar la llamada al contrato con la información que enviamos.
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:
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
.
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.