Las pruebas de conocimiento cero permiten transacciones privadas y seguras. Con zkSNARK y zkSTARK, un probador puede demostrar la posesión de cierta información a un verificador sin revelar los datos reales.
Esto tiene un enorme potencial para el anonimato y la confidencialidad. Pero los zkSTARK y zkSNARK son complejos. Risc0 los hace más accesibles. Veamos su implementación muy básica:
Este tutorial cubrirá:
Instalación de Risc0
Escribiendo su primer programa a prueba de conocimiento cero usando Rust
Requisitos previos:
Copiar y pegar atajos
Instalaciones requeridas:
Algunos conocimientos básicos de codificación en Rust.
Editor de código (VSCODE si es posible)
Al final, tendrás experiencia práctica con pruebas de conocimiento cero en Risc0. No se requieren conocimientos avanzados de matemáticas o criptografía.
Nos centraremos en los conceptos básicos de codificación para comenzar a crear soluciones del mundo real. Esta introducción práctica tiene como objetivo hacer que cualquier desarrollador pueda entender la poderosa tecnología de privacidad.
(Para MacOS) Para instalar Rust y Cargo, puede ejecutar el siguiente comando en la terminal:
curl [https://sh.rustup.rs](https://sh.rustup.rs/) -sSf | sh
Para instalar Risc0, ejecute el siguiente comando después de la instalación de Rust y reinicie la terminal:
cargo install cargo-risczero
brew install openssl
brew install pkgconf
risc0
con: cargo risczero install
Eso es todo lo que necesitamos. Entonces, vayamos al editor de código.
Ahora que hemos terminado con la instalación, puedes leer y seguir estos pasos de abra kadabra 🪄:
Abra el editor de código y diríjase a la ubicación donde desea crear su proyecto en la terminal del editor.
Cree una nueva instancia del proyecto usando el siguiente comando en la terminal: cargo risczero new multiply
.
Deberías ver una carpeta creada llamada multiplicar. CD en él. cd multiply
La estructura de carpetas es muy simple.
Tenemos una carpeta de host y una carpeta de métodos.
La carpeta host contiene el programa host al que llamamos programa invitado. También tiene la capacidad de verificar si lo desea.
La carpeta de métodos contiene el programa invitado que contiene la parte de la aplicación zkvm que se prueba. Recibe los parámetros de entrada del host y luego, según la lógica, genera resultados, los envía al diario y los envía al host como recibo.
El resto de los archivos se explicarán sobre la marcha según sea necesario.
Comencemos con el programa de invitados.
Cambiemos el nombre de los archivos main.rs —> multiply.rs
.
Cree una carpeta llamada bin
en la carpeta src
y mueva mutiply.rs
a ella. Su estructura de carpetas debería verse así:
Abra Cargo.toml
y cambie la actualización a name = "method_name” —> name = "multiply”
.
Agregue el siguiente código en Cargo.toml
.
[[bin]] name = "multiply" path = "src/bin/multiply.rs"
Entonces tu Cargo.toml
final se verá así:
Ahora, abre multiply.rs
. Aquí editaremos la función principal. Esta es la función que se ejecutará en zkvm.
En el siguiente código, tomamos la entrada del programa anfitrión. Luego nos aseguramos de que la entrada no sea un factor trivial, es decir, 1. Luego calculamos el producto y finalmente lo enviamos nuevamente al host del programa.
// We will get the values for these variables from host program let a:u64 = env::read(); let b:u64 = env::read(); // To avoid trivial factors like multiplication by 1 if a == 1 || b == 1 { panic!("Trivial factors !!") // The panic! macro in Rust is used to intentionally crash a program when an unrecoverable error occurs } // Caculate the product of the two numbers let product = a.checked_mul(b).expect("Integer Overflow"); // Commit back the output to the host to save it as receipt env::commit(&product);
Después de los cambios anteriores, sus multiply.rs
deberían verse así.
Hay un cambio final más en la carpeta Cargo.toml
de methods
.
Abra y actualice el valor de name = "multiply-methods”
.
Su Cargo.toml
final se verá como se muestra a continuación.
Nuestro trabajo aquí está hecho.
Ahora, vayamos al programa anfitrión.
Su carpeta de host debe verse así ahora.
Queremos dividir main.rs
en dos archivos que son prover.rs
y verify.rs
.
Cree una nueva carpeta en src
y asígnele el nombre bin
.
Eliminar main.rs
Cree archivos y asígneles el nombre verify.rs
y prove.rs
.
Su estructura de carpetas debería verse así ahora.
Abra prove.rs
y comencemos a codificar:
Agregue el siguiente código. Estas son las importaciones que necesitaremos.
use multiply_methods::MULTIPLY_ELF; // It is a binary file of multiply_method use risc0_zkvm::{ default_prover, serde::{from_slice, to_vec}, ExecutorEnv, };
Hagamos cambios en la función principal.
fn main() { // Declaring our secret input params let a: u64 = 17; let b: u64 = 23; // First, we construct an executor environment let env = ExecutorEnv::builder() .add_input(&to_vec(&a).unwrap()) // Passing the input params to environment so it can be used by gues proggram .add_input(&to_vec(&b).unwrap()) .build() .unwrap(); // Obtain the default prover. let prover = default_prover(); // Produce a receipt by proving the specified ELF binary. let receipt = prover.prove_elf(env, MULTIPLY_ELF).unwrap(); // Extract journal of receipt (ie output c, where c = a * b) let c: u64 = from_slice(&receipt.journal).unwrap(); // Print an assertion println!("Hello, world! I know the factors of {}, and I can prove it!", c); // Let's serialize the receipt so we can save it to an file for verifier program to verify. let serialized = bincode::serialize(&receipt).unwrap(); // Writing the serialized contect to receipt.bin file let _saved_file = match std::fs::write("./receipt.bin", serialized){ Ok(()) => println!("Receipt saved and serialized as receipt.bin"), Err(_) => println!("Something went wrong !!"), }; }
Tus prove.rs
finales deberían verse así.
Abramos y agreguemos código a nuestro verify.rs
.
Aquí, importaremos la identificación de la imagen del programa invitado y algunas importaciones básicas.
use multiply_methods::MULTIPLY_ID; use risc0_zkvm::Receipt;
Hagamos cambios en la función principal.
fn main(){ // Let's impor the receipt that was generated by prove let receipt_path ="./receipt.bin".to_string(); let receipt_file = std::fs::read(receipt_path).unwrap(); // As we has serialized the receipt we need to desrialize it let receipt = bincode::deserialize::<Receipt>(&receipt_file).unwrap(); // Let's verify if the receipt that was generated was not created tampered with let _verification = match receipt.verify(MULTIPLY_ID){ Ok(()) => println!("Proof is Valid"), Err(_) => println!("Something went wrong !!"), }; }
Tus verify.rs
finales deberían verse así.
Prometo que estos son los cambios finales. Ahora casi hemos terminado.
Abra Cargo.toml
en la carpeta host
y realice los cambios siguientes en dependencias.
multiply-methods = { path = "../methods" }
Su Cargo.toml se verá así.
Finalmente es hora de ver si nuestro código funciona.
Encienda su consola en el directorio raíz del proyecto y ejecute el siguiente comando en console cargo run --release --bin prove
Este comando generará la prueba y el recibo para el verificador.
Cuando se ejecute por primera vez, llevará mucho tiempo. Así que no te preocupes, tómate un café hasta que se complete.
Una vez hecho esto, si quieres, podrás verificar el recibo que has generado. Para eso, ejecute este comando cargo run --release --bin verify
Cuando se ejecute por primera vez, llevará mucho tiempo. Así que no te preocupes, tómate un café hasta que se complete.