mirror of
https://github.com/logos-blockchain/logos-blockchain-rust-rapidsnark.git
synced 2026-06-07 11:49:32 +00:00
Merge pull request #1 from zkmopro/refactor
feat: wrap up `groth16_prover_zkey_file`, build for macOS, iOS device…
This commit is contained in:
commit
1d32c928c8
2
.cargo/config.toml
Normal file
2
.cargo/config.toml
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
[env]
|
||||||
|
RUST_RAPIDSNARK_LINK_TEST_WITNESS="1"
|
||||||
67
.github/workflows/build-and-test.yml
vendored
67
.github/workflows/build-and-test.yml
vendored
@ -29,7 +29,46 @@ jobs:
|
|||||||
|
|
||||||
- name: Check formatting
|
- name: Check formatting
|
||||||
run: cargo fmt --all -- --check
|
run: cargo fmt --all -- --check
|
||||||
test:
|
build-ios:
|
||||||
|
runs-on: macos-latest
|
||||||
|
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
target:
|
||||||
|
- aarch64-apple-ios
|
||||||
|
- aarch64-apple-ios-sim
|
||||||
|
- x86_64-apple-ios
|
||||||
|
steps:
|
||||||
|
- name: Checkout Repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
- name: Install Rust
|
||||||
|
uses: dtolnay/rust-toolchain@stable
|
||||||
|
with:
|
||||||
|
toolchain: "1.81.0"
|
||||||
|
targets: ${{ matrix.target }}
|
||||||
|
- name: Build
|
||||||
|
run: cargo build --target ${{ matrix.target }}
|
||||||
|
build-android:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
target:
|
||||||
|
- x86_64-linux-android
|
||||||
|
- aarch64-linux-android
|
||||||
|
steps:
|
||||||
|
- name: Checkout Repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
- name: Install Rust
|
||||||
|
uses: dtolnay/rust-toolchain@stable
|
||||||
|
with:
|
||||||
|
toolchain: "1.81.0"
|
||||||
|
targets: ${{ matrix.target }}
|
||||||
|
- name: Install Android NDK
|
||||||
|
run: cargo install cargo-ndk
|
||||||
|
- name: Build
|
||||||
|
run: cargo ndk -t ${{ matrix.target }} build
|
||||||
|
test-linux:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name
|
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name
|
||||||
steps:
|
steps:
|
||||||
@ -37,7 +76,31 @@ jobs:
|
|||||||
- name: Install Rust toolchain
|
- name: Install Rust toolchain
|
||||||
uses: actions-rs/toolchain@v1
|
uses: actions-rs/toolchain@v1
|
||||||
with:
|
with:
|
||||||
toolchain: stable
|
toolchain: "1.81.0"
|
||||||
|
override: true
|
||||||
|
- name: Run tests
|
||||||
|
run: cargo test
|
||||||
|
test-macOS:
|
||||||
|
runs-on: macos-latest
|
||||||
|
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: Install Rust toolchain
|
||||||
|
uses: actions-rs/toolchain@v1
|
||||||
|
with:
|
||||||
|
toolchain: "1.81.0"
|
||||||
|
override: true
|
||||||
|
- name: Run tests
|
||||||
|
run: cargo test
|
||||||
|
test-macOS-x86_64:
|
||||||
|
runs-on: macos-13
|
||||||
|
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: Install Rust toolchain
|
||||||
|
uses: actions-rs/toolchain@v1
|
||||||
|
with:
|
||||||
|
toolchain: "1.81.0"
|
||||||
override: true
|
override: true
|
||||||
- name: Run tests
|
- name: Run tests
|
||||||
run: cargo test
|
run: cargo test
|
||||||
|
|||||||
2250
Cargo.lock
generated
2250
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@ -7,12 +7,11 @@ edition = "2021"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1.0.95"
|
anyhow = "1.0.95"
|
||||||
ark-bn254 = "0.4.0"
|
|
||||||
ark-circom = { git = "https://github.com/zkmopro/circom-compat.git", version = "0.1.0", branch = "wasm-delete" }
|
|
||||||
num-bigint = "0.4.6"
|
num-bigint = "0.4.6"
|
||||||
rust-witness = "0.1.2"
|
rust-witness = "0.1.2"
|
||||||
serde = { version = "1.0.217", features = ["derive"] }
|
serde = { version = "1.0.217", features = ["derive"] }
|
||||||
serde_json = "1.0.135"
|
serde_json = "1.0.135"
|
||||||
|
num-traits = "0.2.19"
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
cc = "1.0"
|
cc = "1.0"
|
||||||
|
|||||||
33
build.rs
33
build.rs
@ -1,8 +1,12 @@
|
|||||||
|
use std::env;
|
||||||
|
use std::fs;
|
||||||
|
use std::path::Path;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
// #[cfg(test)]
|
if std::env::var("RUST_RAPIDSNARK_LINK_TEST_WITNESS").is_ok() {
|
||||||
rust_witness::transpile::transpile_wasm("./test-vectors".to_string());
|
rust_witness::transpile::transpile_wasm("./test-vectors".to_string());
|
||||||
|
}
|
||||||
|
|
||||||
let target = std::env::var("TARGET").unwrap();
|
let target = std::env::var("TARGET").unwrap();
|
||||||
let arch = target.split('-').next().unwrap();
|
let arch = target.split('-').next().unwrap();
|
||||||
@ -39,4 +43,29 @@ fn main() {
|
|||||||
println!("cargo:rustc-link-lib=static=fr");
|
println!("cargo:rustc-link-lib=static=fr");
|
||||||
println!("cargo:rustc-link-lib=static=fq");
|
println!("cargo:rustc-link-lib=static=fq");
|
||||||
println!("cargo:rustc-link-lib=static=gmp");
|
println!("cargo:rustc-link-lib=static=gmp");
|
||||||
|
|
||||||
|
// refer to https://github.com/bbqsrc/cargo-ndk to see how to link the libc++_shared.so file in Android
|
||||||
|
if env::var("CARGO_CFG_TARGET_OS").unwrap() == "android" {
|
||||||
|
android();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn android() {
|
||||||
|
println!("cargo:rustc-link-lib=c++_shared");
|
||||||
|
|
||||||
|
if let Ok(output_path) = env::var("CARGO_NDK_OUTPUT_PATH") {
|
||||||
|
let sysroot_libs_path = PathBuf::from(env::var_os("CARGO_NDK_SYSROOT_LIBS_PATH").unwrap());
|
||||||
|
let lib_path = sysroot_libs_path.join("libc++_shared.so");
|
||||||
|
assert!(
|
||||||
|
lib_path.exists(),
|
||||||
|
"Error: Source file {:?} does not exist",
|
||||||
|
lib_path
|
||||||
|
);
|
||||||
|
let dest_dir = Path::new(&output_path).join(env::var("CARGO_NDK_ANDROID_TARGET").unwrap());
|
||||||
|
println!("cargo:rerun-if-changed={}", dest_dir.display());
|
||||||
|
if !dest_dir.exists() {
|
||||||
|
fs::create_dir_all(&dest_dir).unwrap();
|
||||||
|
}
|
||||||
|
fs::copy(lib_path, Path::new(&dest_dir).join("libc++_shared.so")).unwrap();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
rapidsnark/aarch64-apple-darwin/librapidsnark-fr-fq.a
Normal file
BIN
rapidsnark/aarch64-apple-darwin/librapidsnark-fr-fq.a
Normal file
Binary file not shown.
Binary file not shown.
BIN
rapidsnark/aarch64-apple-darwin/librapidsnark.dylib
Executable file
BIN
rapidsnark/aarch64-apple-darwin/librapidsnark.dylib
Executable file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
rapidsnark/aarch64-apple-ios-sim/librapidsnark-fr-fq.a
Normal file
BIN
rapidsnark/aarch64-apple-ios-sim/librapidsnark-fr-fq.a
Normal file
Binary file not shown.
Binary file not shown.
BIN
rapidsnark/aarch64-apple-ios-sim/librapidsnark.dylib
Executable file
BIN
rapidsnark/aarch64-apple-ios-sim/librapidsnark.dylib
Executable file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
rapidsnark/aarch64-apple-ios/librapidsnark-fr-fq.a
Normal file
BIN
rapidsnark/aarch64-apple-ios/librapidsnark-fr-fq.a
Normal file
Binary file not shown.
Binary file not shown.
BIN
rapidsnark/aarch64-apple-ios/librapidsnark.dylib
Executable file
BIN
rapidsnark/aarch64-apple-ios/librapidsnark.dylib
Executable file
Binary file not shown.
BIN
rapidsnark/aarch64-linux-android/libfq.a
Normal file
BIN
rapidsnark/aarch64-linux-android/libfq.a
Normal file
Binary file not shown.
BIN
rapidsnark/aarch64-linux-android/libfr.a
Normal file
BIN
rapidsnark/aarch64-linux-android/libfr.a
Normal file
Binary file not shown.
BIN
rapidsnark/aarch64-linux-android/libgmp.a
Normal file
BIN
rapidsnark/aarch64-linux-android/libgmp.a
Normal file
Binary file not shown.
BIN
rapidsnark/aarch64-linux-android/librapidsnark-fr-fq.a
Normal file
BIN
rapidsnark/aarch64-linux-android/librapidsnark-fr-fq.a
Normal file
Binary file not shown.
BIN
rapidsnark/aarch64-linux-android/librapidsnark.a
Normal file
BIN
rapidsnark/aarch64-linux-android/librapidsnark.a
Normal file
Binary file not shown.
BIN
rapidsnark/aarch64-linux-android/librapidsnark.so
Executable file
BIN
rapidsnark/aarch64-linux-android/librapidsnark.so
Executable file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
rapidsnark/aarch64/librapidsnark-fr-fq.a
Normal file
BIN
rapidsnark/aarch64/librapidsnark-fr-fq.a
Normal file
Binary file not shown.
Binary file not shown.
BIN
rapidsnark/aarch64/librapidsnark.so
Normal file
BIN
rapidsnark/aarch64/librapidsnark.so
Normal file
Binary file not shown.
BIN
rapidsnark/x86_64-apple-darwin/libfq.a
Normal file
BIN
rapidsnark/x86_64-apple-darwin/libfq.a
Normal file
Binary file not shown.
BIN
rapidsnark/x86_64-apple-darwin/libfr.a
Normal file
BIN
rapidsnark/x86_64-apple-darwin/libfr.a
Normal file
Binary file not shown.
BIN
rapidsnark/x86_64-apple-darwin/libgmp.a
Normal file
BIN
rapidsnark/x86_64-apple-darwin/libgmp.a
Normal file
Binary file not shown.
BIN
rapidsnark/x86_64-apple-darwin/librapidsnark-fr-fq.a
Normal file
BIN
rapidsnark/x86_64-apple-darwin/librapidsnark-fr-fq.a
Normal file
Binary file not shown.
BIN
rapidsnark/x86_64-apple-darwin/librapidsnark.a
Normal file
BIN
rapidsnark/x86_64-apple-darwin/librapidsnark.a
Normal file
Binary file not shown.
BIN
rapidsnark/x86_64-apple-darwin/librapidsnark.dylib
Executable file
BIN
rapidsnark/x86_64-apple-darwin/librapidsnark.dylib
Executable file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
rapidsnark/x86_64-apple-ios/librapidsnark-fr-fq.a
Normal file
BIN
rapidsnark/x86_64-apple-ios/librapidsnark-fr-fq.a
Normal file
Binary file not shown.
Binary file not shown.
BIN
rapidsnark/x86_64-apple-ios/librapidsnark.dylib
Executable file
BIN
rapidsnark/x86_64-apple-ios/librapidsnark.dylib
Executable file
Binary file not shown.
BIN
rapidsnark/x86_64-linux-android/libfq.a
Normal file
BIN
rapidsnark/x86_64-linux-android/libfq.a
Normal file
Binary file not shown.
BIN
rapidsnark/x86_64-linux-android/libfr.a
Normal file
BIN
rapidsnark/x86_64-linux-android/libfr.a
Normal file
Binary file not shown.
BIN
rapidsnark/x86_64-linux-android/libgmp.a
Normal file
BIN
rapidsnark/x86_64-linux-android/libgmp.a
Normal file
Binary file not shown.
BIN
rapidsnark/x86_64-linux-android/librapidsnark-fr-fq.a
Normal file
BIN
rapidsnark/x86_64-linux-android/librapidsnark-fr-fq.a
Normal file
Binary file not shown.
BIN
rapidsnark/x86_64-linux-android/librapidsnark.a
Normal file
BIN
rapidsnark/x86_64-linux-android/librapidsnark.a
Normal file
Binary file not shown.
BIN
rapidsnark/x86_64-linux-android/librapidsnark.so
Normal file
BIN
rapidsnark/x86_64-linux-android/librapidsnark.so
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
348
src/lib.rs
348
src/lib.rs
@ -14,177 +14,185 @@
|
|||||||
//!
|
//!
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::ffi::CString;
|
|
||||||
use std::fs::File;
|
|
||||||
use std::os::raw::c_char;
|
|
||||||
use std::os::raw::c_uint;
|
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
use anyhow::Context;
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use ark_bn254::Bn254;
|
|
||||||
use ark_circom::read_proving_key;
|
|
||||||
use ark_circom::ZkeyHeaderReader;
|
|
||||||
use num_bigint::BigInt;
|
use num_bigint::BigInt;
|
||||||
use serde::Deserialize;
|
|
||||||
use serde::Serialize;
|
|
||||||
|
|
||||||
/// A function that converts named inputs to a full witness. This should be generated using e.g.
|
/// A function that converts named inputs to a full witness. This should be generated using e.g.
|
||||||
/// [rust-witness](https://crates.io/crates/rust-witness).
|
/// [rust-witness](https://crates.io/crates/rust-witness).
|
||||||
pub type WtnsFn = fn(HashMap<String, Vec<BigInt>>) -> Vec<BigInt>;
|
pub type WtnsFn = fn(HashMap<String, Vec<BigInt>>) -> Vec<BigInt>;
|
||||||
|
|
||||||
// match what rapidsnark expects
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
|
||||||
#[allow(non_snake_case)]
|
|
||||||
struct VerificationKey {
|
|
||||||
protocol: String,
|
|
||||||
curve: String,
|
|
||||||
nPublic: u32,
|
|
||||||
vk_alpha_1: [String; 3],
|
|
||||||
vk_beta_2: [[String; 2]; 3],
|
|
||||||
vk_gamma_2: [[String; 2]; 3],
|
|
||||||
vk_delta_2: [[String; 2]; 3],
|
|
||||||
IC: Vec<[String; 3]>,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A structure representing a proof and public signals.
|
/// A structure representing a proof and public signals.
|
||||||
#[repr(C)]
|
#[derive(Debug)]
|
||||||
pub struct ProofResult {
|
pub struct ProofResult {
|
||||||
proof: *mut c_char,
|
pub proof: String,
|
||||||
public_signals: *mut c_char,
|
pub public_signals: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
fn groth16_api_prove(
|
pub fn groth16_prover_zkey_file(
|
||||||
zkeyFilename: *const c_char,
|
zkey_file_path: *const std::os::raw::c_char,
|
||||||
wtnsData: *mut u8,
|
wtns_buffer: *const std::os::raw::c_void,
|
||||||
wtnsDataLen: c_uint,
|
wtns_size: std::ffi::c_ulong,
|
||||||
) -> *mut ProofResult;
|
proof_buffer: *mut std::os::raw::c_char,
|
||||||
fn groth16_api_verify(proof: *mut ProofResult, key_json: *const c_char) -> bool;
|
proof_size: *mut std::ffi::c_ulong,
|
||||||
fn free_proof_result(result: *mut ProofResult);
|
public_buffer: *mut std::os::raw::c_char,
|
||||||
|
public_size: *mut std::ffi::c_ulong,
|
||||||
|
error_msg: *mut std::os::raw::c_char,
|
||||||
|
error_msg_maxsize: std::ffi::c_ulong,
|
||||||
|
) -> i32;
|
||||||
|
|
||||||
|
pub fn groth16_verify(
|
||||||
|
proof: *const std::os::raw::c_char,
|
||||||
|
inputs: *const std::os::raw::c_char,
|
||||||
|
verification_key: *const std::os::raw::c_char,
|
||||||
|
error_msg: *mut std::os::raw::c_char,
|
||||||
|
error_msg_maxsize: std::ffi::c_ulong,
|
||||||
|
) -> i32;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Verify a proof using a zkey. The proof is expected to be encoded as json.
|
use num_traits::ops::bytes::ToBytes;
|
||||||
pub fn verify_proof(zkey_path: &str, proof: String) -> Result<bool> {
|
use std::io::{self};
|
||||||
let mut header_reader = ZkeyHeaderReader::new(zkey_path);
|
|
||||||
header_reader.read();
|
/// Parse bigints to `wtns` format.<br/>
|
||||||
let file = File::open(zkey_path)?;
|
/// Reference: [witnesscalc/src/witnesscalc.cpp](https://github.com/0xPolygonID/witnesscalc/blob/4a789880727aa0df50f1c4ef78ec295f5a30a15e/src/witnesscalc.cpp)
|
||||||
let mut reader = std::io::BufReader::new(file);
|
pub fn parse_bigints_to_witness(bigints: Vec<BigInt>) -> io::Result<Vec<u8>> {
|
||||||
let proving_key = read_proving_key::<_, Bn254>(&mut reader)?;
|
let mut buffer = Vec::new();
|
||||||
// convert out proving key to json so we can
|
let version: u32 = 2;
|
||||||
// use it with rapidsnark
|
let n_sections: u32 = 2;
|
||||||
let vk = proving_key.vk;
|
let n8: u32 = 32;
|
||||||
// let v = proving_key.vk.alpha_g1.to_string();
|
let q = BigInt::from_str(
|
||||||
let vkey = VerificationKey {
|
"21888242871839275222246405745257275088548364400416034343698204186575808495617",
|
||||||
protocol: "groth16".to_string(),
|
)
|
||||||
curve: "bn128".to_string(),
|
.unwrap();
|
||||||
nPublic: 0, // this is unused in the rapidsnark verifier
|
let n_witness_values: u32 = bigints.len() as u32;
|
||||||
vk_alpha_1: [
|
|
||||||
vk.alpha_g1.x.to_string(),
|
// Write the format bytes (4 bytes)
|
||||||
vk.alpha_g1.y.to_string(),
|
let wtns_format = "wtns".as_bytes();
|
||||||
"1".to_string(),
|
buffer.extend_from_slice(wtns_format);
|
||||||
],
|
|
||||||
vk_beta_2: [
|
// Write version (4 bytes)
|
||||||
[vk.beta_g2.x.c0.to_string(), vk.beta_g2.x.c1.to_string()],
|
buffer.extend_from_slice(&version.to_le_bytes());
|
||||||
[vk.beta_g2.y.c0.to_string(), vk.beta_g2.y.c1.to_string()],
|
|
||||||
["1".to_string(), "0".to_string()],
|
// Write number of sections (4 bytes)
|
||||||
],
|
buffer.extend_from_slice(&n_sections.to_le_bytes());
|
||||||
vk_gamma_2: [
|
|
||||||
[vk.gamma_g2.x.c0.to_string(), vk.gamma_g2.x.c1.to_string()],
|
// Iterate through sections to write the data
|
||||||
[vk.gamma_g2.y.c0.to_string(), vk.gamma_g2.y.c1.to_string()],
|
// Section 1 (Field parameters)
|
||||||
["1".to_string(), "0".to_string()],
|
let section_id_1: u32 = 1;
|
||||||
],
|
let section_length_1: u64 = 8 + n8 as u64;
|
||||||
vk_delta_2: [
|
buffer.extend_from_slice(§ion_id_1.to_le_bytes());
|
||||||
[vk.delta_g2.x.c0.to_string(), vk.delta_g2.x.c1.to_string()],
|
buffer.extend_from_slice(§ion_length_1.to_le_bytes());
|
||||||
[vk.delta_g2.y.c0.to_string(), vk.delta_g2.y.c1.to_string()],
|
|
||||||
["1".to_string(), "0".to_string()],
|
// Write n8 (4 bytes), q (32 bytes), and n_witness_values (4 bytes)
|
||||||
],
|
buffer.extend_from_slice(&n8.to_le_bytes());
|
||||||
IC: vk
|
buffer.extend_from_slice(&q.to_signed_bytes_le());
|
||||||
.gamma_abc_g1
|
buffer.extend_from_slice(&n_witness_values.to_le_bytes());
|
||||||
.iter()
|
|
||||||
.map(|p| [p.x.to_string(), p.y.to_string(), "1".to_string()])
|
// Section 2 (Witness data)
|
||||||
.collect(),
|
let section_id_2: u32 = 2;
|
||||||
};
|
let section_length_2: u64 = bigints.len() as u64 * n8 as u64; // Witness data size
|
||||||
let vkey_json = serde_json::to_string(&vkey)?;
|
buffer.extend_from_slice(§ion_id_2.to_le_bytes());
|
||||||
let vkey_json_cstr = CString::new(vkey_json)?;
|
buffer.extend_from_slice(§ion_length_2.to_le_bytes());
|
||||||
let v: serde_json::Value = serde_json::from_str(&proof)?;
|
|
||||||
let proof = v["proof"].to_string();
|
// Write the witness data (each BigInt to n8 bytes)
|
||||||
let signals = v["signals"].to_string();
|
for bigint in bigints {
|
||||||
|
let mut bytes = bigint.to_le_bytes();
|
||||||
|
bytes.resize(n8 as usize, 0); // Ensure each BigInt is padded to n8 bytes
|
||||||
|
buffer.extend_from_slice(&bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the buffer containing the complete witness data
|
||||||
|
Ok(buffer)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Wrapper for `groth16_prover_zkey_file`
|
||||||
|
pub fn groth16_prover_zkey_file_wrapper(
|
||||||
|
zkey_path: &str,
|
||||||
|
wtns_buffer: Vec<u8>,
|
||||||
|
) -> Result<ProofResult> {
|
||||||
|
let wtns_size = wtns_buffer.len() as u64;
|
||||||
|
|
||||||
|
let mut proof_buffer = vec![0u8; 4 * 1024 * 1024]; // Adjust size as needed
|
||||||
|
let mut proof_size: u64 = 4 * 1024 * 1024;
|
||||||
|
let proof_ptr = proof_buffer.as_mut_ptr() as *mut std::ffi::c_char;
|
||||||
|
|
||||||
|
let mut public_buffer = vec![0u8; 4 * 1024 * 1024]; // Adjust size as needed
|
||||||
|
let mut public_size: u64 = 4 * 1024 * 1024;
|
||||||
|
let public_ptr = public_buffer.as_mut_ptr() as *mut std::ffi::c_char;
|
||||||
|
|
||||||
|
let mut error_msg = vec![0u8; 256]; // Error message buffer
|
||||||
|
let error_msg_ptr = error_msg.as_mut_ptr() as *mut std::ffi::c_char;
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let result = groth16_api_verify(
|
let result = groth16_prover_zkey_file(
|
||||||
&mut ProofResult {
|
zkey_path.as_ptr() as *const std::ffi::c_char,
|
||||||
proof: CString::new(proof).unwrap().into_raw(),
|
wtns_buffer.as_ptr() as *const std::os::raw::c_void, // Witness buffer
|
||||||
public_signals: CString::new(signals).unwrap().into_raw(),
|
wtns_size,
|
||||||
},
|
proof_ptr,
|
||||||
vkey_json_cstr.as_ptr(),
|
&mut proof_size,
|
||||||
|
public_ptr,
|
||||||
|
&mut public_size,
|
||||||
|
error_msg_ptr,
|
||||||
|
error_msg.len() as u64,
|
||||||
);
|
);
|
||||||
Ok(result)
|
if result != 0 {
|
||||||
|
let error_string = std::ffi::CStr::from_ptr(error_msg_ptr)
|
||||||
|
.to_string_lossy()
|
||||||
|
.into_owned();
|
||||||
|
return Err(anyhow::anyhow!("Proof generation failed: {}", error_string));
|
||||||
|
}
|
||||||
|
// Convert both strings
|
||||||
|
let proof = std::ffi::CStr::from_ptr(proof_ptr)
|
||||||
|
.to_string_lossy()
|
||||||
|
.into_owned();
|
||||||
|
let public_signals = std::ffi::CStr::from_ptr(public_ptr)
|
||||||
|
.to_string_lossy()
|
||||||
|
.into_owned();
|
||||||
|
Ok(ProofResult {
|
||||||
|
proof,
|
||||||
|
public_signals,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generate a groth16 proof using a specific zkey. Inputs are expected to be base 10 encoded
|
/// Wrapper for `groth16_verify`
|
||||||
/// strings. Returns a json encoded proof and public signals.
|
pub fn groth16_verify_wrapper(proof: &str, inputs: &str, verification_key: &str) -> Result<bool> {
|
||||||
pub fn generate_proof(
|
let proof_cstr = std::ffi::CString::new(proof).unwrap();
|
||||||
zkey_path: &str,
|
let inputs_cstr = std::ffi::CString::new(inputs).unwrap();
|
||||||
inputs: std::collections::HashMap<String, Vec<String>>,
|
let verification_key_cstr = std::ffi::CString::new(verification_key).unwrap();
|
||||||
witness_fn: WtnsFn,
|
|
||||||
) -> Result<String> {
|
|
||||||
// Form the inputs
|
|
||||||
let bigint_inputs = inputs
|
|
||||||
.into_iter()
|
|
||||||
.map(|(k, v)| {
|
|
||||||
(
|
|
||||||
k,
|
|
||||||
v.into_iter()
|
|
||||||
.map(|i| BigInt::from_str(&i).unwrap())
|
|
||||||
.collect(),
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
let mut wtns = witness_fn(bigint_inputs)
|
|
||||||
.into_iter()
|
|
||||||
.map(|w| w.to_biguint().unwrap())
|
|
||||||
.flat_map(|v| {
|
|
||||||
let mut bytes = v.to_bytes_le();
|
|
||||||
bytes.resize(32, 0);
|
|
||||||
bytes
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
// Convert Rust strings to C strings
|
|
||||||
let zkey_cstr = CString::new(zkey_path).context("Failed to create CString for zkey path")?;
|
|
||||||
|
|
||||||
|
let mut error_msg = vec![0u8; 256]; // Error message buffer
|
||||||
|
let error_msg_ptr = error_msg.as_mut_ptr() as *mut std::ffi::c_char;
|
||||||
unsafe {
|
unsafe {
|
||||||
let proof_ptr =
|
let result = groth16_verify(
|
||||||
groth16_api_prove(zkey_cstr.as_ptr(), wtns.as_mut_ptr(), wtns.len() as c_uint);
|
proof_cstr.as_ptr() as *const std::ffi::c_char,
|
||||||
|
inputs_cstr.as_ptr() as *const std::ffi::c_char,
|
||||||
if proof_ptr.is_null() {
|
verification_key_cstr.as_ptr() as *const std::ffi::c_char,
|
||||||
return Err(anyhow::anyhow!("Proof generation failed"));
|
error_msg_ptr,
|
||||||
|
error_msg.len() as u64,
|
||||||
|
);
|
||||||
|
if result == 2 {
|
||||||
|
let error_string = std::ffi::CStr::from_ptr(error_msg_ptr)
|
||||||
|
.to_string_lossy()
|
||||||
|
.into_owned();
|
||||||
|
return Err(anyhow::anyhow!(
|
||||||
|
"Proof verification failed: {}",
|
||||||
|
error_string
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
Ok(result == 0)
|
||||||
// Convert both strings
|
|
||||||
let result = &*proof_ptr;
|
|
||||||
let proof = std::ffi::CStr::from_ptr(result.proof)
|
|
||||||
.to_string_lossy()
|
|
||||||
.into_owned();
|
|
||||||
let public_signals = std::ffi::CStr::from_ptr(result.public_signals)
|
|
||||||
.to_string_lossy()
|
|
||||||
.into_owned();
|
|
||||||
free_proof_result(proof_ptr);
|
|
||||||
Ok(format!(
|
|
||||||
"{{ \"proof\": {proof},\"signals\": {public_signals}}}"
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use anyhow::bail;
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use num_bigint::BigInt;
|
use num_bigint::BigInt;
|
||||||
use std::collections::HashMap;
|
use std::{collections::HashMap, str::FromStr};
|
||||||
use std::str::FromStr;
|
|
||||||
|
use crate::{parse_bigints_to_witness, WtnsFn};
|
||||||
|
|
||||||
rust_witness::witness!(multiplier2);
|
rust_witness::witness!(multiplier2);
|
||||||
rust_witness::witness!(keccak256256test);
|
rust_witness::witness!(keccak256256test);
|
||||||
@ -211,6 +219,28 @@ mod tests {
|
|||||||
inputs
|
inputs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn compute_witness(
|
||||||
|
inputs: HashMap<String, Vec<String>>,
|
||||||
|
witness_fn: WtnsFn,
|
||||||
|
) -> Result<Vec<u8>> {
|
||||||
|
// Form the inputs
|
||||||
|
let bigint_inputs = inputs
|
||||||
|
.into_iter()
|
||||||
|
.map(|(k, v)| {
|
||||||
|
(
|
||||||
|
k,
|
||||||
|
v.into_iter()
|
||||||
|
.map(|i| BigInt::from_str(&i).unwrap())
|
||||||
|
.collect(),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let wtns: Vec<BigInt> = witness_fn(bigint_inputs);
|
||||||
|
let witnesscalc_wtns = parse_bigints_to_witness(wtns)?;
|
||||||
|
Ok(witnesscalc_wtns)
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_prove_rapidsnark() -> Result<()> {
|
fn test_prove_rapidsnark() -> Result<()> {
|
||||||
// Create a new MoproCircom instance
|
// Create a new MoproCircom instance
|
||||||
@ -222,15 +252,22 @@ mod tests {
|
|||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let b = BigInt::from(1u8);
|
let b = BigInt::from(1u8);
|
||||||
// let c = a.clone() * b.clone();
|
|
||||||
inputs.insert("a".to_string(), vec![a.to_string()]);
|
inputs.insert("a".to_string(), vec![a.to_string()]);
|
||||||
inputs.insert("b".to_string(), vec![b.to_string()]);
|
inputs.insert("b".to_string(), vec![b.to_string()]);
|
||||||
|
|
||||||
let proof_json = super::generate_proof(&zkey_path, inputs, multiplier2_witness)?;
|
// Generate Witness Buffer
|
||||||
let valid = super::verify_proof(&zkey_path, proof_json)?;
|
let wtns_buffer = compute_witness(inputs, multiplier2_witness)?;
|
||||||
if !valid {
|
|
||||||
bail!("Proof is invalid");
|
// Generate Proof
|
||||||
}
|
let proof_result = super::groth16_prover_zkey_file_wrapper(&zkey_path, wtns_buffer)?;
|
||||||
|
|
||||||
|
let vkey = std::fs::read_to_string("./test-vectors/multiplier2.vkey.json")?;
|
||||||
|
let valid = super::groth16_verify_wrapper(
|
||||||
|
&proof_result.proof,
|
||||||
|
&proof_result.public_signals,
|
||||||
|
&vkey,
|
||||||
|
)?;
|
||||||
|
assert!(valid);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -246,12 +283,21 @@ mod tests {
|
|||||||
|
|
||||||
let inputs = bytes_to_circuit_inputs(&input_vec);
|
let inputs = bytes_to_circuit_inputs(&input_vec);
|
||||||
|
|
||||||
|
// Generate Witness Buffer
|
||||||
|
let wtns_buffer = compute_witness(inputs, keccak256256test_witness)?;
|
||||||
|
let wtns_data = std::fs::read("./test-vectors/keccak256_256_test.wtns")?;
|
||||||
|
assert_eq!(wtns_buffer, wtns_data);
|
||||||
|
|
||||||
// Generate Proof
|
// Generate Proof
|
||||||
let proof_json = super::generate_proof(&zkey_path, inputs, keccak256256test_witness)?;
|
let proof_result = super::groth16_prover_zkey_file_wrapper(&zkey_path, wtns_buffer)?;
|
||||||
let valid = super::verify_proof(&zkey_path, proof_json)?;
|
|
||||||
if !valid {
|
let vkey = std::fs::read_to_string("./test-vectors/keccak256_256_test.vkey.json")?;
|
||||||
bail!("Proof is invalid");
|
let valid = super::groth16_verify_wrapper(
|
||||||
}
|
&proof_result.proof,
|
||||||
|
&proof_result.public_signals,
|
||||||
|
&vkey,
|
||||||
|
)?;
|
||||||
|
assert!(valid);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
1369
test-vectors/keccak256_256_test.vkey.json
Normal file
1369
test-vectors/keccak256_256_test.vkey.json
Normal file
File diff suppressed because it is too large
Load Diff
BIN
test-vectors/keccak256_256_test.wtns
Normal file
BIN
test-vectors/keccak256_256_test.wtns
Normal file
Binary file not shown.
99
test-vectors/multiplier2.vkey.json
Normal file
99
test-vectors/multiplier2.vkey.json
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
{
|
||||||
|
"protocol": "groth16",
|
||||||
|
"curve": "bn128",
|
||||||
|
"nPublic": 2,
|
||||||
|
"vk_alpha_1": [
|
||||||
|
"20491192805390485299153009773594534940189261866228447918068658471970481763042",
|
||||||
|
"9383485363053290200918347156157836566562967994039712273449902621266178545958",
|
||||||
|
"1"
|
||||||
|
],
|
||||||
|
"vk_beta_2": [
|
||||||
|
[
|
||||||
|
"6375614351688725206403948262868962793625744043794305715222011528459656738731",
|
||||||
|
"4252822878758300859123897981450591353533073413197771768651442665752259397132"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"10505242626370262277552901082094356697409835680220590971873171140371331206856",
|
||||||
|
"21847035105528745403288232691147584728191162732299865338377159692350059136679"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"1",
|
||||||
|
"0"
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"vk_gamma_2": [
|
||||||
|
[
|
||||||
|
"10857046999023057135944570762232829481370756359578518086990519993285655852781",
|
||||||
|
"11559732032986387107991004021392285783925812861821192530917403151452391805634"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"8495653923123431417604973247489272438418190587263600148770280649306958101930",
|
||||||
|
"4082367875863433681332203403145435568316851327593401208105741076214120093531"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"1",
|
||||||
|
"0"
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"vk_delta_2": [
|
||||||
|
[
|
||||||
|
"21433406528933179909930745994334927660178418579094216084923767796468271186424",
|
||||||
|
"13751094566666250787453117075390489314032734336035585479837046065555811806277"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"16699850258000131247573555544305336535932817397817319735498422046083998163923",
|
||||||
|
"12877331500166317036475448636193806012569545897268783945479551162026182231936"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"1",
|
||||||
|
"0"
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"vk_alphabeta_12": [
|
||||||
|
[
|
||||||
|
[
|
||||||
|
"2029413683389138792403550203267699914886160938906632433982220835551125967885",
|
||||||
|
"21072700047562757817161031222997517981543347628379360635925549008442030252106"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"5940354580057074848093997050200682056184807770593307860589430076672439820312",
|
||||||
|
"12156638873931618554171829126792193045421052652279363021382169897324752428276"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"7898200236362823042373859371574133993780991612861777490112507062703164551277",
|
||||||
|
"7074218545237549455313236346927434013100842096812539264420499035217050630853"
|
||||||
|
]
|
||||||
|
],
|
||||||
|
[
|
||||||
|
[
|
||||||
|
"7077479683546002997211712695946002074877511277312570035766170199895071832130",
|
||||||
|
"10093483419865920389913245021038182291233451549023025229112148274109565435465"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"4595479056700221319381530156280926371456704509942304414423590385166031118820",
|
||||||
|
"19831328484489333784475432780421641293929726139240675179672856274388269393268"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"11934129596455521040620786944827826205713621633706285934057045369193958244500",
|
||||||
|
"8037395052364110730298837004334506829870972346962140206007064471173334027475"
|
||||||
|
]
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"IC": [
|
||||||
|
[
|
||||||
|
"6819801395408938350212900248749732364821477541620635511814266536599629892365",
|
||||||
|
"9092252330033992554755034971584864587974280972948086568597554018278609861372",
|
||||||
|
"1"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"17882351432929302592725330552407222299541667716607588771282887857165175611387",
|
||||||
|
"18907419617206324833977586007131055763810739835484972981819026406579664278293",
|
||||||
|
"1"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"15838138634521468894153380932528531886891906022296751863057552941301429532008",
|
||||||
|
"10499496224041775125547926627482656159317436804293654376137218419558038465083",
|
||||||
|
"1"
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user