Skip to content

Commit

Permalink
Test rust client for gnark prover
Browse files Browse the repository at this point in the history
  • Loading branch information
sergeytimoshin committed Feb 23, 2024
1 parent e984843 commit a970a0a
Show file tree
Hide file tree
Showing 11 changed files with 227 additions and 14 deletions.
49 changes: 47 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@ include "bitify.circom";
template MerkleTreeProof(levels, numberOfUTXOs) {
signal input root[numberOfUTXOs];
signal input leaf[numberOfUTXOs];
signal input inPathElements[numberOfUTXOs][levels];
signal input inPathIndices[numberOfUTXOs];
signal input in_path_elements[numberOfUTXOs][levels];
signal input in_path_indices[numberOfUTXOs];

component inTree[numberOfUTXOs];
for (var i = 0; i < numberOfUTXOs; i++) {
inTree[i] = MerkleProof(levels);
inTree[i].leaf <== leaf[i];
inTree[i].pathIndices <== inPathIndices[i];
inTree[i].pathElements <== inPathElements[i];
inTree[i].pathIndices <== in_path_indices[i];
inTree[i].pathElements <== in_path_elements[i];
inTree[i].root === root[i];
}
}
Expand Down
8 changes: 8 additions & 0 deletions circuit-lib/circuitlib-rs/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,11 @@ log = "0.4"
env_logger = "0.10.2"
# 1.3.0 required by package `aes-gcm-siv v0.10.3`
zeroize = "=1.3.0"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0.60"
num-traits = "0.2.18"

[dev-dependencies]
tokio = { version = "1.36.0", features = ["rt", "macros"] }
reqwest = { version = "0.11.24", features = ["json", "rustls-tls"] }
duct = "0.13.7"
1 change: 1 addition & 0 deletions circuit-lib/circuitlib-rs/scripts/prover.sh
9 changes: 9 additions & 0 deletions circuit-lib/circuitlib-rs/src/helpers.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
use env_logger::Builder;
use log::LevelFilter;

pub fn change_endianness(bytes: &[u8]) -> Vec<u8> {
let mut vec = Vec::new();
for b in bytes.chunks(32) {
Expand All @@ -13,3 +16,9 @@ pub fn convert_endianness_128(bytes: &[u8]) -> Vec<u8> {
.flat_map(|b| b.iter().copied().rev().collect::<Vec<u8>>())
.collect::<Vec<u8>>()
}

pub fn init_logger() {
let _ = Builder::new()
.filter_module("circuitlib_rs", LevelFilter::Info)
.try_init();
}
1 change: 1 addition & 0 deletions circuit-lib/circuitlib-rs/src/merkle_proof_inputs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ pub fn public_inputs(merkle_proof_inputs: &[MerkleTreeProofInput]) -> Vec<[u8; 3
}

pub struct ProofInputs<'a>(pub &'a [MerkleTreeProofInput]);

impl<'a> TryInto<HashMap<String, Inputs>> for ProofInputs<'a> {
type Error = std::io::Error;

Expand Down
5 changes: 5 additions & 0 deletions circuit-lib/circuitlib-rs/tests/gnark/constants.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
pub const SERVER_ADDRESS: &str = "http://localhost:3001";
pub const HEALTH_CHECK: &str = "/health";
pub const PROVE: &str = "/prove";

const CONTENT_TYPE: &str = "text/plain; charset=utf-8";
114 changes: 114 additions & 0 deletions circuit-lib/circuitlib-rs/tests/gnark/helpers.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
use std::{
process::{Child, Command},
thread,
time::Duration,
};

use circuitlib_rs::{init_merkle_tree::merkle_tree_inputs, merkle_proof_inputs::MerkleTreeInfo};
use num_bigint::BigInt;
use num_traits::ToPrimitive;
use serde::Serialize;
use serde_json::json;

use crate::constants::{HEALTH_CHECK, SERVER_ADDRESS};

#[allow(non_snake_case)]
#[derive(Serialize)]
pub struct JsonStruct {
root: Vec<String>,
leaf: Vec<String>,
inPathIndices: Vec<u32>,
inPathElements: Vec<Vec<String>>,
}

impl JsonStruct {
fn new(number_of_utxos: usize) -> Self {
let merkle_inputs = merkle_tree_inputs(MerkleTreeInfo::H26);
let roots = create_vec_of_string(number_of_utxos, &merkle_inputs.root);
let leafs = create_vec_of_string(number_of_utxos, &merkle_inputs.leaf);
let in_path_indices = create_vec_of_u32(number_of_utxos, &merkle_inputs.in_path_indices);
let in_path_elements =
create_vec_of_vec_of_string(number_of_utxos, &merkle_inputs.in_path_elements);
Self {
root: roots,
leaf: leafs,
inPathIndices: in_path_indices,
inPathElements: in_path_elements,
}
}
}
pub fn prepare_inputs(number_of_utxos: usize) -> String {
let json_struct = JsonStruct::new(number_of_utxos);
create_json_from_struct(&json_struct)
}

pub fn spawn_gnark_server() -> Child {
let server_process = Command::new("sh")
.arg("-c")
.arg("scripts/prover.sh")
.spawn()
.expect("Failed to start server process");

// Wait for the server to launch before proceeding.
thread::sleep(Duration::from_secs(5));

server_process
}

pub fn kill_gnark_server(gnark: &mut Child) {
println!("kill gnark!");
Command::new("sh")
.arg("-c")
.arg("killall light-prover")
.spawn()
.unwrap();
gnark.kill().unwrap();
println!("gnark killed!");
}

pub async fn health_check() {
const MAX_RETRIES: usize = 20;
const TIMEOUT: usize = 5;

let client = reqwest::Client::new();

for _ in 0..MAX_RETRIES {
match client
.get(&format!("{}{}", SERVER_ADDRESS, HEALTH_CHECK))
.send()
.await
{
Ok(_) => break,
Err(_) => {
tokio::time::sleep(Duration::from_secs(TIMEOUT as u64)).await;
}
}
}
}

pub fn create_vec_of_string(number_of_utxos: usize, element: &BigInt) -> Vec<String> {
vec![format!("0x{}", element.to_str_radix(16)); number_of_utxos]
}

pub fn create_vec_of_u32(number_of_utxos: usize, element: &BigInt) -> Vec<u32> {
vec![element.to_u32().unwrap(); number_of_utxos]
}

pub fn create_vec_of_vec_of_string(
number_of_utxos: usize,
elements: &[BigInt],
) -> Vec<Vec<String>> {
let vec: Vec<String> = elements
.iter()
.map(|e| format!("0x{}", e.to_str_radix(16)))
.collect();
vec![vec; number_of_utxos]
}

pub fn create_json_from_struct(json_struct: &JsonStruct) -> String {
let json = json!(json_struct);
match serde_json::to_string_pretty(&json) {
Ok(json) => json,
Err(_) => panic!("Merkle tree data invalid"),
}
}
11 changes: 11 additions & 0 deletions circuit-lib/circuitlib-rs/tests/gnark/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
mod constants;
mod helpers;
mod prove;

use std::{
process::{Child, Command},
thread,
time::Duration,
};

use circuitlib_rs::helpers::init_logger;
26 changes: 26 additions & 0 deletions circuit-lib/circuitlib-rs/tests/gnark/prove.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
use circuitlib_rs::helpers::init_logger;
use reqwest::header::CONTENT_TYPE;

use crate::{
constants::{PROVE, SERVER_ADDRESS},
helpers::{health_check, kill_gnark_server, prepare_inputs, spawn_gnark_server},
};

#[tokio::test]
async fn prove_inclusion() {
let number_of_utxos = 1;
init_logger();
let mut gnark = spawn_gnark_server();
health_check().await;
let inputs = prepare_inputs(number_of_utxos);
let client = reqwest::Client::new();
let response_result = client
.post(&format!("{}{}", SERVER_ADDRESS, PROVE))
.header("Content-Type", CONTENT_TYPE)
.body(inputs)
.send()
.await
.expect("Failed to execute request.");
assert!(response_result.status().is_success());
kill_gnark_server(&mut gnark);
}
9 changes: 1 addition & 8 deletions circuit-lib/circuitlib-rs/tests/merkle/main.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
use circuitlib_rs::{
groth16_solana_verifier::{groth16_solana_verify, merkle_inclusion_proof},
helpers::init_logger,
init_merkle_tree::merkle_tree_inputs,
merkle_proof_inputs::{MerkleTreeInfo, MerkleTreeProofInput},
verifying_keys::vk,
};
use env_logger::Builder;
use log::LevelFilter;

macro_rules! test_and_prove {
($fn_name:ident, $mt_height:expr, $nr_inputs:expr) => {
Expand Down Expand Up @@ -33,9 +32,3 @@ test_and_prove!(test_and_prove_26_2, MerkleTreeInfo::H26, 2);
test_and_prove!(test_and_prove_26_3, MerkleTreeInfo::H26, 3);
test_and_prove!(test_and_prove_26_4, MerkleTreeInfo::H26, 4);
test_and_prove!(test_and_prove_26_8, MerkleTreeInfo::H26, 8);

fn init_logger() {
let _ = Builder::new()
.filter_module("circuitlib_rs", LevelFilter::Info)
.try_init();
}

0 comments on commit a970a0a

Please sign in to comment.