mirror of
https://github.com/selfxyz/self.git
synced 2026-04-27 03:01:15 -04:00
removing mopro dirs
This commit is contained in:
14
app/ark-zkey/.gitignore
vendored
14
app/ark-zkey/.gitignore
vendored
@@ -1,14 +0,0 @@
|
||||
# Generated by Cargo
|
||||
# will have compiled files and executables
|
||||
debug/
|
||||
target/
|
||||
|
||||
# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
|
||||
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
|
||||
Cargo.lock
|
||||
|
||||
# These are backup files generated by rustfmt
|
||||
**/*.rs.bk
|
||||
|
||||
# MSVC Windows builds of rustc generate these, which store debugging information
|
||||
*.pdb
|
||||
@@ -1,32 +0,0 @@
|
||||
[package]
|
||||
name = "ark-zkey"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[[bin]]
|
||||
name = "arkzkey-util"
|
||||
path = "src/bin/arkzkey_util.rs"
|
||||
|
||||
# XXX: Shouldn't be necessary, but this way we stay consistent with wasmer version and fix
|
||||
# error[E0432]: unresolved import `wasmer` error
|
||||
# (likely due to other packages)
|
||||
[patch.crates-io]
|
||||
# NOTE: Forked wasmer to work around memory limits
|
||||
# See https://github.com/wasmerio/wasmer/commit/09c7070
|
||||
wasmer = { git = "https://github.com/oskarth/wasmer.git", rev = "09c7070" }
|
||||
|
||||
[dependencies]
|
||||
color-eyre = "0.6"
|
||||
memmap2 = "0.9"
|
||||
flame = "0.2"
|
||||
flamer = "0.5"
|
||||
|
||||
ark-serialize = { version = "=0.4.1", features = ["derive"] }
|
||||
ark-bn254 = { version = "=0.4.0" }
|
||||
ark-groth16 = { version = "=0.4.0" }
|
||||
ark-circom = { git = "https://github.com/arkworks-rs/circom-compat.git" }
|
||||
ark-relations = { version = "=0.4.0" }
|
||||
ark-ff = { version = "=0.4.1" }
|
||||
ark-ec = { version = "=0.4.1" }
|
||||
@@ -1,52 +0,0 @@
|
||||
# ark-zkey
|
||||
|
||||
Library to read `zkey` faster by serializing to `arkworks` friendly format.
|
||||
|
||||
See https://github.com/oskarth/mopro/issues/25 for context.
|
||||
|
||||
## How to use
|
||||
|
||||
Run the following to convert a `zkey` to an `arkzkey`. This should be done as a pre-processing step.
|
||||
|
||||
`cargo run --bin arkzkey-util --release -- ../mopro-core/examples/circom/keccak256/target/keccak256_256_test_final.zkey`
|
||||
|
||||
This will generate and place an `arkzkey` file in the same directory as the original zkey.
|
||||
|
||||
You can also install it locally:
|
||||
|
||||
`cargo install --bin arkzkey-util --path . --release`
|
||||
|
||||
## Tests
|
||||
|
||||
```
|
||||
cargo test multiplier2 --release -- --nocapture
|
||||
cargo test keccak256 --release -- --nocapture
|
||||
cargo test rsa --release -- --nocapture
|
||||
```
|
||||
|
||||
## Benchmark (Keccak)
|
||||
|
||||
`cargo test keccak256 --release -- --nocapture`
|
||||
|
||||
```
|
||||
[build] Processing zkey data...
|
||||
test tests::test_keccak256_serialization_deserialization has been running for over 60 seconds
|
||||
[build]Time to process zkey data: 158.753181958s
|
||||
[build] Serializing proving key and constraint matrices
|
||||
[build] Time to serialize proving key and constraint matrices: 42ns
|
||||
[build] Writing arkzkey to: ../mopro-core/examples/circom/keccak256/target/keccak256_256_test_final.arkzkey
|
||||
[build] Time to write arkzkey: 16.204274125s
|
||||
Reading arkzkey from: ../mopro-core/examples/circom/keccak256/target/keccak256_256_test_final.arkzkey
|
||||
Time to open arkzkey file: 51.75µs
|
||||
Time to mmap arkzkey: 17.25µs
|
||||
Time to deserialize proving key: 18.323550083s
|
||||
Time to deserialize matrices: 46.935792ms
|
||||
Time to read arkzkey: 18.3730695s
|
||||
test tests::test_keccak256_serialization_deserialization ... ok
|
||||
```
|
||||
|
||||
Vs naive:
|
||||
|
||||
`[build] Time to process zkey data: 158.753181958s`
|
||||
|
||||
**Result: 18s vs 158s**
|
||||
@@ -1,36 +0,0 @@
|
||||
use std::env;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
extern crate ark_zkey;
|
||||
use ark_zkey::{convert_zkey, read_proving_key_and_matrices_from_zkey};
|
||||
|
||||
fn main() -> color_eyre::eyre::Result<()> {
|
||||
color_eyre::install()?;
|
||||
|
||||
let args: Vec<String> = env::args().collect();
|
||||
if args.len() != 2 {
|
||||
eprintln!("Usage: zkey_to_arkzkey <path_to_zkey_file>");
|
||||
std::process::exit(1);
|
||||
}
|
||||
|
||||
let zkey_path = &args[1];
|
||||
let (proving_key, constraint_matrices) = read_proving_key_and_matrices_from_zkey(zkey_path)?;
|
||||
|
||||
let arkzkey_path = get_arkzkey_path(zkey_path);
|
||||
let arkzkey_path_str = arkzkey_path
|
||||
.to_str()
|
||||
.ok_or_else(|| color_eyre::eyre::eyre!("Failed to convert arkzkey path to string"))?;
|
||||
|
||||
convert_zkey(proving_key, constraint_matrices, &arkzkey_path_str)?;
|
||||
|
||||
println!("Converted zkey file saved to: {}", arkzkey_path.display());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_arkzkey_path(zkey_path: &str) -> PathBuf {
|
||||
let path = Path::new(zkey_path);
|
||||
let mut arkzkey_path = path.to_path_buf();
|
||||
arkzkey_path.set_extension("arkzkey");
|
||||
arkzkey_path
|
||||
}
|
||||
@@ -1,247 +0,0 @@
|
||||
use ark_bn254::{Bn254, Fr};
|
||||
use ark_circom::read_zkey;
|
||||
//use ark_ec::pairing::Pairing;
|
||||
use ark_ff::Field;
|
||||
use ark_groth16::ProvingKey;
|
||||
//use ark_groth16::VerifyingKey;
|
||||
use ark_relations::r1cs::ConstraintMatrices;
|
||||
use ark_serialize::{CanonicalDeserialize, CanonicalSerialize};
|
||||
use color_eyre::eyre::{Result, WrapErr};
|
||||
use memmap2::Mmap;
|
||||
use std::fs::File;
|
||||
//use std::io::Cursor;
|
||||
//use std::io::{Read,self};
|
||||
use std::io::BufReader;
|
||||
use std::path::PathBuf;
|
||||
use std::time::Instant;
|
||||
|
||||
#[derive(CanonicalSerialize, CanonicalDeserialize, Clone, Debug, PartialEq)]
|
||||
pub struct SerializableProvingKey(pub ProvingKey<Bn254>);
|
||||
|
||||
#[derive(CanonicalSerialize, CanonicalDeserialize, Clone, Debug, PartialEq)]
|
||||
pub struct SerializableMatrix<F: Field> {
|
||||
pub data: Vec<Vec<(F, usize)>>,
|
||||
}
|
||||
|
||||
#[derive(CanonicalSerialize, CanonicalDeserialize, Clone, Debug, PartialEq)]
|
||||
pub struct SerializableConstraintMatrices<F: Field> {
|
||||
pub num_instance_variables: usize,
|
||||
pub num_witness_variables: usize,
|
||||
pub num_constraints: usize,
|
||||
pub a_num_non_zero: usize,
|
||||
pub b_num_non_zero: usize,
|
||||
pub c_num_non_zero: usize,
|
||||
pub a: SerializableMatrix<F>,
|
||||
pub b: SerializableMatrix<F>,
|
||||
pub c: SerializableMatrix<F>,
|
||||
}
|
||||
|
||||
impl<F: Field> From<Vec<Vec<(F, usize)>>> for SerializableMatrix<F> {
|
||||
fn from(matrix: Vec<Vec<(F, usize)>>) -> Self {
|
||||
SerializableMatrix { data: matrix }
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: Field> From<SerializableMatrix<F>> for Vec<Vec<(F, usize)>> {
|
||||
fn from(serializable_matrix: SerializableMatrix<F>) -> Self {
|
||||
serializable_matrix.data
|
||||
}
|
||||
}
|
||||
|
||||
pub fn serialize_proving_key(pk: &SerializableProvingKey) -> Vec<u8> {
|
||||
let mut serialized_data = Vec::new();
|
||||
pk.serialize_compressed(&mut serialized_data)
|
||||
.expect("Serialization failed");
|
||||
serialized_data
|
||||
}
|
||||
|
||||
pub fn deserialize_proving_key(data: Vec<u8>) -> SerializableProvingKey {
|
||||
SerializableProvingKey::deserialize_compressed_unchecked(&mut &data[..])
|
||||
.expect("Deserialization failed")
|
||||
}
|
||||
|
||||
pub fn read_arkzkey(
|
||||
arkzkey_path: &str,
|
||||
) -> Result<(SerializableProvingKey, SerializableConstraintMatrices<Fr>)> {
|
||||
let now = std::time::Instant::now();
|
||||
let arkzkey_file_path = PathBuf::from(arkzkey_path);
|
||||
let arkzkey_file = File::open(arkzkey_file_path).wrap_err("Failed to open arkzkey file")?;
|
||||
println!("Time to open arkzkey file: {:?}", now.elapsed());
|
||||
|
||||
//let mut buf_reader = BufReader::new(arkzkey_file);
|
||||
|
||||
// Using mmap
|
||||
let now = std::time::Instant::now();
|
||||
let mmap = unsafe { Mmap::map(&arkzkey_file)? };
|
||||
let mut cursor = std::io::Cursor::new(mmap);
|
||||
println!("Time to mmap arkzkey: {:?}", now.elapsed());
|
||||
|
||||
// Was &mut buf_reader
|
||||
let now = std::time::Instant::now();
|
||||
let proving_key = SerializableProvingKey::deserialize_compressed_unchecked(&mut cursor)
|
||||
.wrap_err("Failed to deserialize proving key")?;
|
||||
println!("Time to deserialize proving key: {:?}", now.elapsed());
|
||||
|
||||
let now = std::time::Instant::now();
|
||||
let constraint_matrices =
|
||||
SerializableConstraintMatrices::deserialize_compressed_unchecked(&mut cursor)
|
||||
.wrap_err("Failed to deserialize constraint matrices")?;
|
||||
println!("Time to deserialize matrices: {:?}", now.elapsed());
|
||||
|
||||
Ok((proving_key, constraint_matrices))
|
||||
}
|
||||
|
||||
// TODO: Return ProvingKey<Bn254>, ConstraintMatrices<Fr>?
|
||||
pub fn read_arkzkey_from_bytes(
|
||||
arkzkey_bytes: &[u8],
|
||||
) -> Result<(ProvingKey<Bn254>, ConstraintMatrices<Fr>)> {
|
||||
let mut cursor = std::io::Cursor::new(arkzkey_bytes);
|
||||
|
||||
let now = std::time::Instant::now();
|
||||
let serialized_proving_key =
|
||||
SerializableProvingKey::deserialize_compressed_unchecked(&mut cursor)
|
||||
.wrap_err("Failed to deserialize proving key")?;
|
||||
println!("Time to deserialize proving key: {:?}", now.elapsed());
|
||||
|
||||
let now = std::time::Instant::now();
|
||||
let serialized_constraint_matrices =
|
||||
SerializableConstraintMatrices::deserialize_compressed_unchecked(&mut cursor)
|
||||
.wrap_err("Failed to deserialize constraint matrices")?;
|
||||
println!("Time to deserialize matrices: {:?}", now.elapsed());
|
||||
|
||||
// Get on right form for API
|
||||
let proving_key: ProvingKey<Bn254> = serialized_proving_key.0;
|
||||
let constraint_matrices: ConstraintMatrices<Fr> = ConstraintMatrices {
|
||||
num_instance_variables: serialized_constraint_matrices.num_instance_variables,
|
||||
num_witness_variables: serialized_constraint_matrices.num_witness_variables,
|
||||
num_constraints: serialized_constraint_matrices.num_constraints,
|
||||
a_num_non_zero: serialized_constraint_matrices.a_num_non_zero,
|
||||
b_num_non_zero: serialized_constraint_matrices.b_num_non_zero,
|
||||
c_num_non_zero: serialized_constraint_matrices.c_num_non_zero,
|
||||
a: serialized_constraint_matrices.a.data,
|
||||
b: serialized_constraint_matrices.b.data,
|
||||
c: serialized_constraint_matrices.c.data,
|
||||
};
|
||||
|
||||
Ok((proving_key, constraint_matrices))
|
||||
}
|
||||
|
||||
pub fn read_proving_key_and_matrices_from_zkey(
|
||||
zkey_path: &str,
|
||||
) -> Result<(SerializableProvingKey, SerializableConstraintMatrices<Fr>)> {
|
||||
println!("Reading zkey from: {}", zkey_path);
|
||||
let now = Instant::now();
|
||||
let zkey_file_path = PathBuf::from(zkey_path);
|
||||
let zkey_file = File::open(zkey_file_path).wrap_err("Failed to open zkey file")?;
|
||||
|
||||
let mut buf_reader = BufReader::new(zkey_file);
|
||||
|
||||
let (proving_key, matrices) =
|
||||
read_zkey(&mut buf_reader).wrap_err("Failed to read zkey file")?;
|
||||
println!("Time to read zkey: {:?}", now.elapsed());
|
||||
|
||||
println!("Serializing proving key and constraint matrices");
|
||||
let now = Instant::now();
|
||||
let serializable_proving_key = SerializableProvingKey(proving_key);
|
||||
let serializable_constrain_matrices = SerializableConstraintMatrices {
|
||||
num_instance_variables: matrices.num_instance_variables,
|
||||
num_witness_variables: matrices.num_witness_variables,
|
||||
num_constraints: matrices.num_constraints,
|
||||
a_num_non_zero: matrices.a_num_non_zero,
|
||||
b_num_non_zero: matrices.b_num_non_zero,
|
||||
c_num_non_zero: matrices.c_num_non_zero,
|
||||
a: SerializableMatrix { data: matrices.a },
|
||||
b: SerializableMatrix { data: matrices.b },
|
||||
c: SerializableMatrix { data: matrices.c },
|
||||
};
|
||||
println!(
|
||||
"Time to serialize proving key and constraint matrices: {:?}",
|
||||
now.elapsed()
|
||||
);
|
||||
|
||||
Ok((serializable_proving_key, serializable_constrain_matrices))
|
||||
}
|
||||
|
||||
pub fn convert_zkey(
|
||||
proving_key: SerializableProvingKey,
|
||||
constraint_matrices: SerializableConstraintMatrices<Fr>,
|
||||
arkzkey_path: &str,
|
||||
) -> Result<()> {
|
||||
let arkzkey_file_path = PathBuf::from(arkzkey_path);
|
||||
|
||||
let serialized_path = PathBuf::from(arkzkey_file_path);
|
||||
|
||||
let mut file =
|
||||
File::create(&serialized_path).wrap_err("Failed to create serialized proving key file")?;
|
||||
|
||||
proving_key
|
||||
.serialize_compressed(&mut file)
|
||||
.wrap_err("Failed to serialize proving key")?;
|
||||
|
||||
constraint_matrices
|
||||
.serialize_compressed(&mut file)
|
||||
.wrap_err("Failed to serialize constraint matrices")?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use std::time::Instant;
|
||||
|
||||
fn test_circuit_serialization_deserialization(zkey_path: &str) -> Result<()> {
|
||||
let arkzkey_path = zkey_path.replace(".zkey", ".arkzkey");
|
||||
|
||||
let (original_proving_key, original_constraint_matrices) =
|
||||
read_proving_key_and_matrices_from_zkey(zkey_path)?;
|
||||
|
||||
println!("[build] Writing arkzkey to: {}", arkzkey_path);
|
||||
let now = Instant::now();
|
||||
convert_zkey(
|
||||
original_proving_key.clone(),
|
||||
original_constraint_matrices.clone(),
|
||||
&arkzkey_path,
|
||||
)?;
|
||||
println!("[build] Time to write arkzkey: {:?}", now.elapsed());
|
||||
|
||||
println!("Reading arkzkey from: {}", arkzkey_path);
|
||||
let now = Instant::now();
|
||||
let (deserialized_proving_key, deserialized_constraint_matrices) =
|
||||
read_arkzkey(&arkzkey_path)?;
|
||||
println!("Time to read arkzkey: {:?}", now.elapsed());
|
||||
|
||||
assert_eq!(
|
||||
original_proving_key, deserialized_proving_key,
|
||||
"Original and deserialized proving keys do not match"
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
original_constraint_matrices, deserialized_constraint_matrices,
|
||||
"Original and deserialized constraint matrices do not match"
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_multiplier2_serialization_deserialization() -> Result<()> {
|
||||
test_circuit_serialization_deserialization(
|
||||
"../mopro-core/examples/circom/multiplier2/target/multiplier2_final.zkey",
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_keccak256_serialization_deserialization() -> Result<()> {
|
||||
test_circuit_serialization_deserialization(
|
||||
"../mopro-core/examples/circom/keccak256/target/keccak256_256_test_final.zkey",
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rsa_serialization_deserialization() -> Result<()> {
|
||||
test_circuit_serialization_deserialization(
|
||||
"../mopro-core/examples/circom/rsa/target/main_final.zkey",
|
||||
)
|
||||
}
|
||||
}
|
||||
14
app/mopro-core/.gitignore
vendored
14
app/mopro-core/.gitignore
vendored
@@ -1,14 +0,0 @@
|
||||
# Generated by Cargo
|
||||
# will have compiled files and executables
|
||||
debug/
|
||||
target/
|
||||
|
||||
# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
|
||||
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
|
||||
Cargo.lock
|
||||
|
||||
# These are backup files generated by rustfmt
|
||||
**/*.rs.bk
|
||||
|
||||
# MSVC Windows builds of rustc generate these, which store debugging information
|
||||
*.pdb
|
||||
@@ -1,51 +0,0 @@
|
||||
[package]
|
||||
name = "mopro-core"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[patch.crates-io]
|
||||
# NOTE: Forked wasmer to work around memory limits
|
||||
# See https://github.com/wasmerio/wasmer/commit/09c7070
|
||||
wasmer = { git = "https://github.com/oskarth/wasmer.git", rev = "09c7070" }
|
||||
|
||||
[features]
|
||||
default = []
|
||||
dylib = ["wasmer/dylib"]
|
||||
|
||||
[dependencies]
|
||||
ark-circom = { git = "https://github.com/arkworks-rs/circom-compat.git" }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
ark-serialize = { version = "=0.4.1", features = ["derive"] }
|
||||
num-bigint = { version = "=0.4.3", default-features = false, features = [
|
||||
"rand",
|
||||
] }
|
||||
instant = "0.1"
|
||||
wasmer = { git = "https://github.com/oskarth/wasmer.git", rev = "09c7070" }
|
||||
once_cell = "1.8"
|
||||
|
||||
# ZKP generation
|
||||
ark-ec = { version = "=0.4.1", default-features = false, features = [
|
||||
"parallel",
|
||||
] }
|
||||
ark-crypto-primitives = { version = "=0.4.0" }
|
||||
ark-std = { version = "=0.4.0", default-features = false, features = [
|
||||
"parallel",
|
||||
] }
|
||||
ark-bn254 = { version = "=0.4.0" }
|
||||
ark-groth16 = { version = "=0.4.0", default-features = false, features = [
|
||||
"parallel",
|
||||
] }
|
||||
ark-relations = { version = "0.4", default-features = false }
|
||||
ark-zkey = { path = "../ark-zkey" }
|
||||
|
||||
# Error handling
|
||||
thiserror = "=1.0.39"
|
||||
color-eyre = "=0.6.2"
|
||||
criterion = "=0.3.6"
|
||||
|
||||
[build-dependencies]
|
||||
color-eyre = "0.6"
|
||||
enumset = "1.0.8"
|
||||
wasmer = { git = "https://github.com/oskarth/wasmer.git", rev = "09c7070" }
|
||||
@@ -1,47 +0,0 @@
|
||||
# mopro-core
|
||||
|
||||
Core mobile Rust library. For FFI, see `mopro-ffi` which is a thin wrapper for exposing UniFFI bindings around this library.
|
||||
|
||||
## Overview
|
||||
|
||||
TBD.
|
||||
|
||||
## Examples
|
||||
|
||||
Run `cargo run --example circom`. Also see `examples/circom/README.md` for more information.
|
||||
|
||||
## Build dylib
|
||||
|
||||
Experimental support.
|
||||
|
||||
Turns `.wasm` file into a dynamic library (`.dylib`).
|
||||
|
||||
Run:
|
||||
|
||||
`cargo build --features dylib`
|
||||
|
||||
After that you'll see location of the dylib file:
|
||||
|
||||
```
|
||||
warning: Building dylib for aarch64-apple-darwin
|
||||
warning: Dylib location: /Users/user/repos/github.com/oskarth/mopro/mopro-core/target/debug/aarch64-apple-darwin/keccak256.dylib
|
||||
```
|
||||
|
||||
Right now this is hardcoded for `rsa`.
|
||||
|
||||
Note that:
|
||||
- It has to be built for the right architecture
|
||||
- Have to run `install_name_tool` to adjust install name
|
||||
- Run `codesign` to sign dylib for use on iOS
|
||||
|
||||
### Script
|
||||
|
||||
Add third argument: `dylib`:
|
||||
|
||||
`./scripts/update_bindings.sh device release dylib`
|
||||
|
||||
Note that `APPLE_SIGNING_IDENTITY` must be set.
|
||||
|
||||
## To use ark-zkey
|
||||
|
||||
Experimental support for significantly faster zkey loading. See `../ark-zkey` README for how to build arkzkey.
|
||||
@@ -1,95 +0,0 @@
|
||||
use color_eyre::eyre::Result;
|
||||
use std::env;
|
||||
use std::path::PathBuf;
|
||||
|
||||
fn prepare_env(zkey_path: String, wasm_path: String, arkzkey_path: String) -> Result<()> {
|
||||
let project_dir = env::var("CARGO_MANIFEST_DIR")?;
|
||||
let zkey_file = PathBuf::from(&project_dir).join(zkey_path);
|
||||
let wasm_file = PathBuf::from(&project_dir).join(wasm_path);
|
||||
let arkzkey_file = PathBuf::from(&project_dir).join(arkzkey_path);
|
||||
|
||||
// TODO: Right now emitting as warnings for visibility, figure out better way to do this?
|
||||
println!("cargo:warning=zkey_file: {}", zkey_file.display());
|
||||
println!("cargo:warning=wasm_file: {}", wasm_file.display());
|
||||
println!("cargo:warning=arkzkey_file: {}", arkzkey_file.display());
|
||||
|
||||
// Set BUILD_RS_ZKEY_FILE and BUILD_RS_WASM_FILE env var
|
||||
println!("cargo:rustc-env=BUILD_RS_ZKEY_FILE={}", zkey_file.display());
|
||||
println!("cargo:rustc-env=BUILD_RS_WASM_FILE={}", wasm_file.display());
|
||||
println!(
|
||||
"cargo:rustc-env=BUILD_RS_ARKZKEY_FILE={}",
|
||||
arkzkey_file.display()
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(feature = "dylib")]
|
||||
fn build_dylib(wasm_path: String, dylib_name: String) -> Result<()> {
|
||||
use std::path::Path;
|
||||
use std::{fs, str::FromStr};
|
||||
|
||||
use color_eyre::eyre::eyre;
|
||||
use enumset::enum_set;
|
||||
use enumset::EnumSet;
|
||||
|
||||
use wasmer::Cranelift;
|
||||
use wasmer::Dylib;
|
||||
use wasmer::Target;
|
||||
use wasmer::{Module, Store, Triple};
|
||||
|
||||
let out_dir = env::var("OUT_DIR")?;
|
||||
let project_dir = env::var("CARGO_MANIFEST_DIR")?;
|
||||
let build_mode = env::var("PROFILE")?;
|
||||
let target_arch = env::var("TARGET")?;
|
||||
|
||||
let out_dir = Path::new(&out_dir).to_path_buf();
|
||||
let wasm_file = Path::new(&wasm_path).to_path_buf();
|
||||
let dylib_file = out_dir.join(&dylib_name);
|
||||
let final_dir = PathBuf::from(&project_dir)
|
||||
.join("target")
|
||||
.join(&target_arch)
|
||||
.join(build_mode);
|
||||
|
||||
// if dylib_file.exists() {
|
||||
// return Ok(());
|
||||
// }
|
||||
|
||||
// Create a WASM engine for the target that can compile
|
||||
let triple = Triple::from_str(&target_arch).map_err(|e| eyre!(e))?;
|
||||
let cpu_features = enum_set!();
|
||||
let target = Target::new(triple, cpu_features);
|
||||
let engine = Dylib::new(Cranelift::default()).target(target).engine();
|
||||
println!("cargo:warning=Building dylib for {}", target_arch);
|
||||
|
||||
// Compile the WASM module
|
||||
let store = Store::new(&engine);
|
||||
let module = Module::from_file(&store, &wasm_file).unwrap();
|
||||
module.serialize_to_file(&dylib_file).unwrap();
|
||||
assert!(dylib_file.exists());
|
||||
|
||||
// Copy dylib to a more predictable path
|
||||
fs::create_dir_all(&final_dir)?;
|
||||
let final_path = final_dir.join(dylib_name);
|
||||
fs::copy(&dylib_file, &final_path)?;
|
||||
println!("cargo:warning=Dylib location: {}", final_path.display());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn main() -> Result<()> {
|
||||
// TODO: build_circuit function to builds all related artifacts, instead of doing this externally
|
||||
let dir = "../../circuits";
|
||||
let circuit = "proof_of_passport";
|
||||
|
||||
let zkey_path = format!("{}/build/{}_final.zkey", dir, circuit);
|
||||
let wasm_path = format!("{}/build/{}_js/{}.wasm", dir, circuit, circuit);
|
||||
// TODO: Need to modify script for this
|
||||
let arkzkey_path = format!("{}/build/{}_final.arkzkey", dir, circuit);
|
||||
|
||||
println!("cargo:warning=arkzkey_path: {}", arkzkey_path);
|
||||
|
||||
prepare_env(zkey_path, wasm_path, arkzkey_path)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
pub mod middleware;
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum MoproError {
|
||||
#[error("CircomError: {0}")]
|
||||
CircomError(String),
|
||||
}
|
||||
@@ -1,860 +0,0 @@
|
||||
use self::{
|
||||
serialization::{SerializableInputs, SerializableProof, SerializableProvingKey},
|
||||
utils::{assert_paths_exists, bytes_to_bits},
|
||||
};
|
||||
use crate::MoproError;
|
||||
|
||||
use std::collections::HashMap;
|
||||
//use std::io::Cursor;
|
||||
use std::sync::Mutex;
|
||||
use std::time::Instant;
|
||||
|
||||
use ark_bn254::{Bn254, Fr};
|
||||
use ark_circom::{
|
||||
CircomBuilder,
|
||||
CircomCircuit,
|
||||
CircomConfig,
|
||||
CircomReduction,
|
||||
WitnessCalculator, //read_zkey,
|
||||
};
|
||||
use ark_crypto_primitives::snark::SNARK;
|
||||
use ark_groth16::{prepare_verifying_key, Groth16, ProvingKey};
|
||||
use ark_std::UniformRand;
|
||||
|
||||
use ark_relations::r1cs::ConstraintMatrices;
|
||||
use ark_std::rand::thread_rng;
|
||||
use color_eyre::Result;
|
||||
use core::include_bytes;
|
||||
use num_bigint::BigInt;
|
||||
use once_cell::sync::{Lazy, OnceCell};
|
||||
|
||||
use wasmer::{Module, Store};
|
||||
|
||||
use ark_zkey::read_arkzkey_from_bytes; //SerializableConstraintMatrices
|
||||
|
||||
#[cfg(feature = "dylib")]
|
||||
use {
|
||||
std::{env, path::Path},
|
||||
wasmer::Dylib,
|
||||
};
|
||||
|
||||
pub mod serialization;
|
||||
pub mod utils;
|
||||
|
||||
type GrothBn = Groth16<Bn254>;
|
||||
|
||||
type CircuitInputs = HashMap<String, Vec<BigInt>>;
|
||||
|
||||
// TODO: Split up this namespace a bit, right now quite a lot of things going on
|
||||
|
||||
pub struct CircomState {
|
||||
builder: Option<CircomBuilder<Bn254>>,
|
||||
circuit: Option<CircomCircuit<Bn254>>,
|
||||
params: Option<ProvingKey<Bn254>>,
|
||||
}
|
||||
|
||||
impl Default for CircomState {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: A lot of the contents of this file is inspired by github.com/worldcoin/semaphore-rs
|
||||
|
||||
// TODO: Replace printlns with logging
|
||||
|
||||
//const ZKEY_BYTES: &[u8] = include_bytes!(env!("BUILD_RS_ZKEY_FILE"));
|
||||
|
||||
const ARKZKEY_BYTES: &[u8] = include_bytes!(env!("BUILD_RS_ARKZKEY_FILE"));
|
||||
|
||||
// static ZKEY: Lazy<(ProvingKey<Bn254>, ConstraintMatrices<Fr>)> = Lazy::new(|| {
|
||||
// let mut reader = Cursor::new(ZKEY_BYTES);
|
||||
// read_zkey(&mut reader).expect("Failed to read zkey")
|
||||
// });
|
||||
|
||||
static ARKZKEY: Lazy<(ProvingKey<Bn254>, ConstraintMatrices<Fr>)> = Lazy::new(|| {
|
||||
//let mut reader = Cursor::new(ARKZKEY_BYTES);
|
||||
// TODO: Use reader? More flexible; unclear if perf diff
|
||||
read_arkzkey_from_bytes(ARKZKEY_BYTES).expect("Failed to read arkzkey")
|
||||
});
|
||||
|
||||
const WASM: &[u8] = include_bytes!(env!("BUILD_RS_WASM_FILE"));
|
||||
|
||||
/// `WITNESS_CALCULATOR` is a lazily initialized, thread-safe singleton of type `WitnessCalculator`.
|
||||
/// `OnceCell` ensures that the initialization occurs exactly once, and `Mutex` allows safe shared
|
||||
/// access from multiple threads.
|
||||
static WITNESS_CALCULATOR: OnceCell<Mutex<WitnessCalculator>> = OnceCell::new();
|
||||
|
||||
/// Initializes the `WITNESS_CALCULATOR` singleton with a `WitnessCalculator` instance created from
|
||||
/// a specified dylib file (WASM circuit). Also initialize `ZKEY`.
|
||||
#[cfg(feature = "dylib")]
|
||||
pub fn initialize(dylib_path: &Path) {
|
||||
println!("Initializing dylib: {:?}", dylib_path);
|
||||
|
||||
WITNESS_CALCULATOR
|
||||
.set(from_dylib(dylib_path))
|
||||
.expect("Failed to set WITNESS_CALCULATOR");
|
||||
|
||||
// Initialize ARKZKEY
|
||||
// TODO: Speed this up even more
|
||||
let now = std::time::Instant::now();
|
||||
Lazy::force(&ARKZKEY);
|
||||
println!("Initializing arkzkey took: {:.2?}", now.elapsed());
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "dylib"))]
|
||||
pub fn initialize() {
|
||||
println!("Initializing library with arkzkey");
|
||||
|
||||
// Initialize ARKZKEY
|
||||
// TODO: Speed this up even more!
|
||||
let now = std::time::Instant::now();
|
||||
Lazy::force(&ARKZKEY);
|
||||
println!("Initializing arkzkey took: {:.2?}", now.elapsed());
|
||||
}
|
||||
|
||||
/// Creates a `WitnessCalculator` instance from a dylib file.
|
||||
#[cfg(feature = "dylib")]
|
||||
fn from_dylib(path: &Path) -> Mutex<WitnessCalculator> {
|
||||
let store = Store::new(&Dylib::headless().engine());
|
||||
let module = unsafe {
|
||||
Module::deserialize_from_file(&store, path).expect("Failed to load dylib module")
|
||||
};
|
||||
let result =
|
||||
WitnessCalculator::from_module(module).expect("Failed to create WitnessCalculator");
|
||||
|
||||
Mutex::new(result)
|
||||
}
|
||||
|
||||
// #[must_use]
|
||||
// pub fn zkey() -> &'static (ProvingKey<Bn254>, ConstraintMatrices<Fr>) {
|
||||
// &ZKEY
|
||||
// }
|
||||
|
||||
// Experimental
|
||||
#[must_use]
|
||||
pub fn arkzkey() -> &'static (ProvingKey<Bn254>, ConstraintMatrices<Fr>) {
|
||||
&ARKZKEY
|
||||
}
|
||||
|
||||
/// Provides access to the `WITNESS_CALCULATOR` singleton, initializing it if necessary.
|
||||
/// It expects the path to the dylib file to be set in the `CIRCUIT_WASM_DYLIB` environment variable.
|
||||
#[cfg(feature = "dylib")]
|
||||
#[must_use]
|
||||
pub fn witness_calculator() -> &'static Mutex<WitnessCalculator> {
|
||||
let var_name = "CIRCUIT_WASM_DYLIB";
|
||||
|
||||
WITNESS_CALCULATOR.get_or_init(|| {
|
||||
let path = env::var(var_name).unwrap_or_else(|_| {
|
||||
panic!(
|
||||
"Mopro circuit WASM Dylib not initialized. \
|
||||
Please set {} environment variable to the path of the dylib file",
|
||||
var_name
|
||||
)
|
||||
});
|
||||
from_dylib(Path::new(&path))
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "dylib"))]
|
||||
#[must_use]
|
||||
pub fn witness_calculator() -> &'static Mutex<WitnessCalculator> {
|
||||
WITNESS_CALCULATOR.get_or_init(|| {
|
||||
let store = Store::default();
|
||||
let module = Module::from_binary(&store, WASM).expect("WASM should be valid");
|
||||
let result =
|
||||
WitnessCalculator::from_module(module).expect("Failed to create WitnessCalculator");
|
||||
Mutex::new(result)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn generate_proof2(
|
||||
inputs: CircuitInputs,
|
||||
) -> Result<(SerializableProof, SerializableInputs), MoproError> {
|
||||
let mut rng = thread_rng();
|
||||
let rng = &mut rng;
|
||||
|
||||
let r = ark_bn254::Fr::rand(rng);
|
||||
let s = ark_bn254::Fr::rand(rng);
|
||||
|
||||
println!("Generating proof 2");
|
||||
|
||||
let now = std::time::Instant::now();
|
||||
let full_assignment = witness_calculator()
|
||||
.lock()
|
||||
.expect("Failed to lock witness calculator")
|
||||
.calculate_witness_element::<Bn254, _>(inputs, false)
|
||||
.map_err(|e| MoproError::CircomError(e.to_string()))?;
|
||||
|
||||
println!("Witness generation took: {:.2?}", now.elapsed());
|
||||
|
||||
let now = std::time::Instant::now();
|
||||
//let zkey = zkey();
|
||||
let zkey = arkzkey();
|
||||
println!("Loading arkzkey took: {:.2?}", now.elapsed());
|
||||
|
||||
let public_inputs = full_assignment.as_slice()[1..zkey.1.num_instance_variables].to_vec();
|
||||
|
||||
let now = std::time::Instant::now();
|
||||
let ark_proof = Groth16::<_, CircomReduction>::create_proof_with_reduction_and_matrices(
|
||||
&zkey.0,
|
||||
r,
|
||||
s,
|
||||
&zkey.1,
|
||||
zkey.1.num_instance_variables,
|
||||
zkey.1.num_constraints,
|
||||
full_assignment.as_slice(),
|
||||
);
|
||||
|
||||
let proof = ark_proof.map_err(|e| MoproError::CircomError(e.to_string()))?;
|
||||
|
||||
println!("proof generation took: {:.2?}", now.elapsed());
|
||||
|
||||
// TODO: Add SerializableInputs(inputs)))
|
||||
Ok((SerializableProof(proof), SerializableInputs(public_inputs)))
|
||||
}
|
||||
|
||||
pub fn verify_proof2(
|
||||
serialized_proof: SerializableProof,
|
||||
serialized_inputs: SerializableInputs,
|
||||
) -> Result<bool, MoproError> {
|
||||
let start = Instant::now();
|
||||
let zkey = arkzkey();
|
||||
let pvk = prepare_verifying_key(&zkey.0.vk);
|
||||
|
||||
let proof_verified =
|
||||
GrothBn::verify_with_processed_vk(&pvk, &serialized_inputs.0, &serialized_proof.0)
|
||||
.map_err(|e| MoproError::CircomError(e.to_string()))?;
|
||||
|
||||
let verification_duration = start.elapsed();
|
||||
println!("Verification time 2: {:?}", verification_duration);
|
||||
Ok(proof_verified)
|
||||
}
|
||||
|
||||
impl CircomState {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
builder: None,
|
||||
circuit: None,
|
||||
params: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn setup(
|
||||
&mut self,
|
||||
wasm_path: &str,
|
||||
r1cs_path: &str,
|
||||
) -> Result<SerializableProvingKey, MoproError> {
|
||||
assert_paths_exists(wasm_path, r1cs_path)?;
|
||||
println!("Setup");
|
||||
let start = Instant::now();
|
||||
|
||||
// Load the WASM and R1CS for witness and proof generation
|
||||
let cfg = self.load_config(wasm_path, r1cs_path)?;
|
||||
|
||||
// Create an empty instance for setup
|
||||
self.builder = Some(CircomBuilder::new(cfg));
|
||||
|
||||
// Run a trusted setup using the rng in the state
|
||||
let params = self.run_trusted_setup()?;
|
||||
|
||||
self.params = Some(params.clone());
|
||||
|
||||
let setup_duration = start.elapsed();
|
||||
println!("Setup time: {:?}", setup_duration);
|
||||
|
||||
Ok(SerializableProvingKey(params))
|
||||
}
|
||||
|
||||
// NOTE: Consider generate_proof<T: Into<BigInt>> API
|
||||
// XXX: BigInt might present problems for UniFFI
|
||||
pub fn generate_proof(
|
||||
&mut self,
|
||||
inputs: CircuitInputs,
|
||||
) -> Result<(SerializableProof, SerializableInputs), MoproError> {
|
||||
let start = Instant::now();
|
||||
println!("Generating proof");
|
||||
|
||||
let mut rng = thread_rng();
|
||||
|
||||
let builder = self.builder.as_mut().ok_or(MoproError::CircomError(
|
||||
"Builder has not been set up".to_string(),
|
||||
))?;
|
||||
|
||||
// Insert our inputs as key value pairs
|
||||
for (key, values) in &inputs {
|
||||
for value in values {
|
||||
builder.push_input(&key, value.clone());
|
||||
}
|
||||
}
|
||||
|
||||
// Clone the builder, then build the circuit
|
||||
let circom = builder
|
||||
.clone()
|
||||
.build()
|
||||
.map_err(|e| MoproError::CircomError(e.to_string()))?;
|
||||
|
||||
// Update the circuit in self
|
||||
self.circuit = Some(circom.clone());
|
||||
|
||||
let params = self.params.as_ref().ok_or(MoproError::CircomError(
|
||||
"Parameters have not been set up".to_string(),
|
||||
))?;
|
||||
|
||||
let inputs = circom.get_public_inputs().ok_or(MoproError::CircomError(
|
||||
"Failed to get public inputs".to_string(),
|
||||
))?;
|
||||
|
||||
let proof = GrothBn::prove(params, circom.clone(), &mut rng)
|
||||
.map_err(|e| MoproError::CircomError(e.to_string()))?;
|
||||
|
||||
let proof_duration = start.elapsed();
|
||||
println!("Proof generation time: {:?}", proof_duration);
|
||||
|
||||
Ok((SerializableProof(proof), SerializableInputs(inputs)))
|
||||
}
|
||||
|
||||
pub fn verify_proof(
|
||||
&self,
|
||||
serialized_proof: SerializableProof,
|
||||
serialized_inputs: SerializableInputs,
|
||||
) -> Result<bool, MoproError> {
|
||||
let start = Instant::now();
|
||||
|
||||
println!("Verifying proof");
|
||||
|
||||
let params = self.params.as_ref().ok_or(MoproError::CircomError(
|
||||
"Parameters have not been set up".to_string(),
|
||||
))?;
|
||||
|
||||
let pvk =
|
||||
GrothBn::process_vk(¶ms.vk).map_err(|e| MoproError::CircomError(e.to_string()))?;
|
||||
|
||||
let proof_verified =
|
||||
GrothBn::verify_with_processed_vk(&pvk, &serialized_inputs.0, &serialized_proof.0)
|
||||
.map_err(|e| MoproError::CircomError(e.to_string()))?;
|
||||
|
||||
let verification_duration = start.elapsed();
|
||||
println!("Verification time: {:?}", verification_duration);
|
||||
Ok(proof_verified)
|
||||
}
|
||||
|
||||
fn load_config(
|
||||
&self,
|
||||
wasm_path: &str,
|
||||
r1cs_path: &str,
|
||||
) -> Result<CircomConfig<Bn254>, MoproError> {
|
||||
CircomConfig::<Bn254>::new(wasm_path, r1cs_path)
|
||||
.map_err(|e| MoproError::CircomError(e.to_string()))
|
||||
}
|
||||
|
||||
fn run_trusted_setup(&mut self) -> Result<ProvingKey<Bn254>, MoproError> {
|
||||
let circom_setup = self
|
||||
.builder
|
||||
.as_mut()
|
||||
.ok_or(MoproError::CircomError(
|
||||
"Builder has not been set up".to_string(),
|
||||
))?
|
||||
.setup();
|
||||
|
||||
let mut rng = thread_rng();
|
||||
|
||||
GrothBn::generate_random_parameters_with_reduction(circom_setup, &mut rng)
|
||||
.map_err(|e| MoproError::CircomError(e.to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
// Helper function for Keccak256 example
|
||||
pub fn bytes_to_circuit_inputs(bytes: &[u8]) -> CircuitInputs {
|
||||
let bits = bytes_to_bits(bytes);
|
||||
let big_int_bits = bits
|
||||
.into_iter()
|
||||
.map(|bit| BigInt::from(bit as u8))
|
||||
.collect();
|
||||
let mut inputs = HashMap::new();
|
||||
inputs.insert("in".to_string(), big_int_bits);
|
||||
inputs
|
||||
}
|
||||
|
||||
pub fn strings_to_circuit_inputs(strings: &[&str]) -> Vec<BigInt> {
|
||||
strings
|
||||
.iter()
|
||||
.map(|&value| BigInt::parse_bytes(value.as_bytes(), 10).unwrap())
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn bytes_to_circuit_outputs(bytes: &[u8]) -> SerializableInputs {
|
||||
let bits = bytes_to_bits(bytes);
|
||||
let field_bits = bits.into_iter().map(|bit| Fr::from(bit as u8)).collect();
|
||||
SerializableInputs(field_bits)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_setup_prove_verify_simple() {
|
||||
let wasm_path = "./examples/circom/multiplier2/target/multiplier2_js/multiplier2.wasm";
|
||||
let r1cs_path = "./examples/circom/multiplier2/target/multiplier2.r1cs";
|
||||
|
||||
// Instantiate CircomState
|
||||
let mut circom_state = CircomState::new();
|
||||
|
||||
// Setup
|
||||
let setup_res = circom_state.setup(wasm_path, r1cs_path);
|
||||
assert!(setup_res.is_ok());
|
||||
|
||||
let _serialized_pk = setup_res.unwrap();
|
||||
|
||||
// Deserialize the proving key and inputs if necessary
|
||||
|
||||
// Prepare inputs
|
||||
let mut inputs = HashMap::new();
|
||||
let a = 3;
|
||||
let b = 5;
|
||||
let c = a * b;
|
||||
inputs.insert("a".to_string(), vec![BigInt::from(a)]);
|
||||
inputs.insert("b".to_string(), vec![BigInt::from(b)]);
|
||||
// output = [public output c, public input a]
|
||||
let expected_output = vec![Fr::from(c), Fr::from(a)];
|
||||
let serialized_outputs = SerializableInputs(expected_output);
|
||||
|
||||
// Proof generation
|
||||
let generate_proof_res = circom_state.generate_proof(inputs);
|
||||
|
||||
// Check and print the error if there is one
|
||||
if let Err(e) = &generate_proof_res {
|
||||
println!("Error: {:?}", e);
|
||||
}
|
||||
|
||||
assert!(generate_proof_res.is_ok());
|
||||
|
||||
let (serialized_proof, serialized_inputs) = generate_proof_res.unwrap();
|
||||
|
||||
// Check output
|
||||
assert_eq!(serialized_inputs, serialized_outputs);
|
||||
|
||||
// Proof verification
|
||||
let verify_res = circom_state.verify_proof(serialized_proof, serialized_inputs);
|
||||
assert!(verify_res.is_ok());
|
||||
assert!(verify_res.unwrap()); // Verifying that the proof was indeed verified
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_setup_prove_verify_keccak() {
|
||||
let wasm_path =
|
||||
"./examples/circom/keccak256/target/keccak256_256_test_js/keccak256_256_test.wasm";
|
||||
let r1cs_path = "./examples/circom/keccak256/target/keccak256_256_test.r1cs";
|
||||
|
||||
// Instantiate CircomState
|
||||
let mut circom_state = CircomState::new();
|
||||
|
||||
// Setup
|
||||
let setup_res = circom_state.setup(wasm_path, r1cs_path);
|
||||
assert!(setup_res.is_ok());
|
||||
|
||||
let _serialized_pk = setup_res.unwrap();
|
||||
|
||||
// Deserialize the proving key and inputs if necessary
|
||||
|
||||
// Prepare inputs
|
||||
let input_vec = vec![
|
||||
116, 101, 115, 116, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0,
|
||||
];
|
||||
|
||||
// Expected output
|
||||
let expected_output_vec = vec![
|
||||
37, 17, 98, 135, 161, 178, 88, 97, 125, 150, 143, 65, 228, 211, 170, 133, 153, 9, 88,
|
||||
212, 4, 212, 175, 238, 249, 210, 214, 116, 170, 85, 45, 21,
|
||||
];
|
||||
|
||||
let inputs = bytes_to_circuit_inputs(&input_vec);
|
||||
let serialized_outputs = bytes_to_circuit_outputs(&expected_output_vec);
|
||||
|
||||
// Proof generation
|
||||
let generate_proof_res = circom_state.generate_proof(inputs);
|
||||
|
||||
// Check and print the error if there is one
|
||||
if let Err(e) = &generate_proof_res {
|
||||
println!("Error: {:?}", e);
|
||||
}
|
||||
|
||||
assert!(generate_proof_res.is_ok());
|
||||
|
||||
let (serialized_proof, serialized_inputs) = generate_proof_res.unwrap();
|
||||
|
||||
// Check output
|
||||
assert_eq!(serialized_inputs, serialized_outputs);
|
||||
|
||||
// Proof verification
|
||||
let verify_res = circom_state.verify_proof(serialized_proof, serialized_inputs);
|
||||
assert!(verify_res.is_ok());
|
||||
|
||||
assert!(verify_res.unwrap()); // Verifying that the proof was indeed verified
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_setup_error() {
|
||||
// Arrange: Create a new CircomState instance
|
||||
let mut circom_state = CircomState::new();
|
||||
|
||||
let wasm_path = "badpath/multiplier2.wasm";
|
||||
let r1cs_path = "badpath/multiplier2.r1cs";
|
||||
|
||||
// Act: Call the setup method
|
||||
let result = circom_state.setup(wasm_path, r1cs_path);
|
||||
|
||||
// Assert: Check that the method returns an error
|
||||
assert!(result.is_err());
|
||||
}
|
||||
|
||||
#[cfg(feature = "dylib")]
|
||||
#[test]
|
||||
fn test_dylib_init_and_generate_witness() {
|
||||
// Assumes that the dylib file has been built and is in the following location
|
||||
let dylib_path = "target/debug/aarch64-apple-darwin/keccak256.dylib";
|
||||
|
||||
// Initialize libray
|
||||
initialize(Path::new(&dylib_path));
|
||||
|
||||
let input_vec = vec![
|
||||
116, 101, 115, 116, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0,
|
||||
];
|
||||
|
||||
let inputs = bytes_to_circuit_inputs(&input_vec);
|
||||
let now = std::time::Instant::now();
|
||||
let full_assignment = witness_calculator()
|
||||
.lock()
|
||||
.expect("Failed to lock witness calculator")
|
||||
.calculate_witness_element::<Bn254, _>(inputs, false)
|
||||
.map_err(|e| MoproError::CircomError(e.to_string()));
|
||||
|
||||
println!("Witness generation took: {:.2?}", now.elapsed());
|
||||
|
||||
assert!(full_assignment.is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_generate_proof2() {
|
||||
// XXX: This can be done better
|
||||
#[cfg(feature = "dylib")]
|
||||
{
|
||||
// Assumes that the dylib file has been built and is in the following location
|
||||
let dylib_path = "target/debug/aarch64-apple-darwin/keccak256.dylib";
|
||||
|
||||
// Initialize libray
|
||||
initialize(Path::new(&dylib_path));
|
||||
}
|
||||
|
||||
let input_vec = vec![
|
||||
116, 101, 115, 116, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0,
|
||||
];
|
||||
let expected_output_vec = vec![
|
||||
37, 17, 98, 135, 161, 178, 88, 97, 125, 150, 143, 65, 228, 211, 170, 133, 153, 9, 88,
|
||||
212, 4, 212, 175, 238, 249, 210, 214, 116, 170, 85, 45, 21,
|
||||
];
|
||||
let inputs = bytes_to_circuit_inputs(&input_vec);
|
||||
let serialized_outputs = bytes_to_circuit_outputs(&expected_output_vec);
|
||||
|
||||
let generate_proof_res = generate_proof2(inputs);
|
||||
let (serialized_proof, serialized_inputs) = generate_proof_res.unwrap();
|
||||
assert_eq!(serialized_inputs, serialized_outputs);
|
||||
|
||||
// Proof verification
|
||||
let verify_res = verify_proof2(serialized_proof, serialized_inputs);
|
||||
assert!(verify_res.is_ok());
|
||||
assert!(verify_res.unwrap()); // Verifying that the proof was indeed verified
|
||||
}
|
||||
|
||||
#[ignore = "ignore for ci"]
|
||||
#[test]
|
||||
fn test_setup_prove_rsa() {
|
||||
let wasm_path = "./examples/circom/rsa/target/main_js/main.wasm";
|
||||
let r1cs_path = "./examples/circom/rsa/target/main.r1cs";
|
||||
|
||||
// Instantiate CircomState
|
||||
let mut circom_state = CircomState::new();
|
||||
|
||||
// Setup
|
||||
let setup_res = circom_state.setup(wasm_path, r1cs_path);
|
||||
assert!(setup_res.is_ok());
|
||||
|
||||
let _serialized_pk = setup_res.unwrap();
|
||||
|
||||
// Deserialize the proving key and inputs if necessary
|
||||
|
||||
// Prepare inputs
|
||||
let signature = [
|
||||
"3582320600048169363",
|
||||
"7163546589759624213",
|
||||
"18262551396327275695",
|
||||
"4479772254206047016",
|
||||
"1970274621151677644",
|
||||
"6547632513799968987",
|
||||
"921117808165172908",
|
||||
"7155116889028933260",
|
||||
"16769940396381196125",
|
||||
"17141182191056257954",
|
||||
"4376997046052607007",
|
||||
"17471823348423771450",
|
||||
"16282311012391954891",
|
||||
"70286524413490741",
|
||||
"1588836847166444745",
|
||||
"15693430141227594668",
|
||||
"13832254169115286697",
|
||||
"15936550641925323613",
|
||||
"323842208142565220",
|
||||
"6558662646882345749",
|
||||
"15268061661646212265",
|
||||
"14962976685717212593",
|
||||
"15773505053543368901",
|
||||
"9586594741348111792",
|
||||
"1455720481014374292",
|
||||
"13945813312010515080",
|
||||
"6352059456732816887",
|
||||
"17556873002865047035",
|
||||
"2412591065060484384",
|
||||
"11512123092407778330",
|
||||
"8499281165724578877",
|
||||
"12768005853882726493",
|
||||
];
|
||||
let modulus = [
|
||||
"13792647154200341559",
|
||||
"12773492180790982043",
|
||||
"13046321649363433702",
|
||||
"10174370803876824128",
|
||||
"7282572246071034406",
|
||||
"1524365412687682781",
|
||||
"4900829043004737418",
|
||||
"6195884386932410966",
|
||||
"13554217876979843574",
|
||||
"17902692039595931737",
|
||||
"12433028734895890975",
|
||||
"15971442058448435996",
|
||||
"4591894758077129763",
|
||||
"11258250015882429548",
|
||||
"16399550288873254981",
|
||||
"8246389845141771315",
|
||||
"14040203746442788850",
|
||||
"7283856864330834987",
|
||||
"12297563098718697441",
|
||||
"13560928146585163504",
|
||||
"7380926829734048483",
|
||||
"14591299561622291080",
|
||||
"8439722381984777599",
|
||||
"17375431987296514829",
|
||||
"16727607878674407272",
|
||||
"3233954801381564296",
|
||||
"17255435698225160983",
|
||||
"15093748890170255670",
|
||||
"15810389980847260072",
|
||||
"11120056430439037392",
|
||||
"5866130971823719482",
|
||||
"13327552690270163501",
|
||||
];
|
||||
let base_message = [
|
||||
"18114495772705111902",
|
||||
"2254271930739856077",
|
||||
"2068851770",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
];
|
||||
|
||||
let mut inputs: HashMap<String, Vec<BigInt>> = HashMap::new();
|
||||
inputs.insert(
|
||||
"signature".to_string(),
|
||||
strings_to_circuit_inputs(&signature),
|
||||
);
|
||||
inputs.insert("modulus".to_string(), strings_to_circuit_inputs(&modulus));
|
||||
inputs.insert(
|
||||
"base_message".to_string(),
|
||||
strings_to_circuit_inputs(&base_message),
|
||||
);
|
||||
|
||||
// Proof generation
|
||||
let generate_proof_res = circom_state.generate_proof(inputs);
|
||||
|
||||
// Check and print the error if there is one
|
||||
if let Err(e) = &generate_proof_res {
|
||||
println!("Error: {:?}", e);
|
||||
}
|
||||
|
||||
assert!(generate_proof_res.is_ok());
|
||||
|
||||
let (serialized_proof, serialized_inputs) = generate_proof_res.unwrap();
|
||||
|
||||
// Proof verification
|
||||
let verify_res = circom_state.verify_proof(serialized_proof, serialized_inputs);
|
||||
assert!(verify_res.is_ok());
|
||||
|
||||
assert!(verify_res.unwrap()); // Verifying that the proof was indeed verified
|
||||
}
|
||||
|
||||
#[ignore = "ignore for ci"]
|
||||
#[test]
|
||||
fn test_setup_prove_rsa2() {
|
||||
// Prepare inputs
|
||||
let signature = [
|
||||
"3582320600048169363",
|
||||
"7163546589759624213",
|
||||
"18262551396327275695",
|
||||
"4479772254206047016",
|
||||
"1970274621151677644",
|
||||
"6547632513799968987",
|
||||
"921117808165172908",
|
||||
"7155116889028933260",
|
||||
"16769940396381196125",
|
||||
"17141182191056257954",
|
||||
"4376997046052607007",
|
||||
"17471823348423771450",
|
||||
"16282311012391954891",
|
||||
"70286524413490741",
|
||||
"1588836847166444745",
|
||||
"15693430141227594668",
|
||||
"13832254169115286697",
|
||||
"15936550641925323613",
|
||||
"323842208142565220",
|
||||
"6558662646882345749",
|
||||
"15268061661646212265",
|
||||
"14962976685717212593",
|
||||
"15773505053543368901",
|
||||
"9586594741348111792",
|
||||
"1455720481014374292",
|
||||
"13945813312010515080",
|
||||
"6352059456732816887",
|
||||
"17556873002865047035",
|
||||
"2412591065060484384",
|
||||
"11512123092407778330",
|
||||
"8499281165724578877",
|
||||
"12768005853882726493",
|
||||
];
|
||||
let modulus = [
|
||||
"13792647154200341559",
|
||||
"12773492180790982043",
|
||||
"13046321649363433702",
|
||||
"10174370803876824128",
|
||||
"7282572246071034406",
|
||||
"1524365412687682781",
|
||||
"4900829043004737418",
|
||||
"6195884386932410966",
|
||||
"13554217876979843574",
|
||||
"17902692039595931737",
|
||||
"12433028734895890975",
|
||||
"15971442058448435996",
|
||||
"4591894758077129763",
|
||||
"11258250015882429548",
|
||||
"16399550288873254981",
|
||||
"8246389845141771315",
|
||||
"14040203746442788850",
|
||||
"7283856864330834987",
|
||||
"12297563098718697441",
|
||||
"13560928146585163504",
|
||||
"7380926829734048483",
|
||||
"14591299561622291080",
|
||||
"8439722381984777599",
|
||||
"17375431987296514829",
|
||||
"16727607878674407272",
|
||||
"3233954801381564296",
|
||||
"17255435698225160983",
|
||||
"15093748890170255670",
|
||||
"15810389980847260072",
|
||||
"11120056430439037392",
|
||||
"5866130971823719482",
|
||||
"13327552690270163501",
|
||||
];
|
||||
let base_message = [
|
||||
"18114495772705111902",
|
||||
"2254271930739856077",
|
||||
"2068851770",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
];
|
||||
|
||||
let mut inputs: HashMap<String, Vec<BigInt>> = HashMap::new();
|
||||
inputs.insert(
|
||||
"signature".to_string(),
|
||||
strings_to_circuit_inputs(&signature),
|
||||
);
|
||||
inputs.insert("modulus".to_string(), strings_to_circuit_inputs(&modulus));
|
||||
inputs.insert(
|
||||
"base_message".to_string(),
|
||||
strings_to_circuit_inputs(&base_message),
|
||||
);
|
||||
|
||||
// Proof generation
|
||||
let generate_proof_res = generate_proof2(inputs);
|
||||
|
||||
// Check and print the error if there is one
|
||||
if let Err(e) = &generate_proof_res {
|
||||
println!("Error: {:?}", e);
|
||||
}
|
||||
|
||||
assert!(generate_proof_res.is_ok());
|
||||
|
||||
let (serialized_proof, serialized_inputs) = generate_proof_res.unwrap();
|
||||
|
||||
// Proof verification
|
||||
let verify_res = verify_proof2(serialized_proof, serialized_inputs);
|
||||
assert!(verify_res.is_ok());
|
||||
|
||||
assert!(verify_res.unwrap()); // Verifying that the proof was indeed verified
|
||||
}
|
||||
}
|
||||
@@ -1,106 +0,0 @@
|
||||
use ark_bn254::Bn254;
|
||||
use ark_ec::pairing::Pairing;
|
||||
use ark_groth16::{Proof, ProvingKey};
|
||||
use ark_serialize::{CanonicalDeserialize, CanonicalSerialize};
|
||||
use color_eyre::Result;
|
||||
|
||||
#[derive(CanonicalSerialize, CanonicalDeserialize, Clone, Debug)]
|
||||
pub struct SerializableProvingKey(pub ProvingKey<Bn254>);
|
||||
|
||||
#[derive(CanonicalSerialize, CanonicalDeserialize, Clone, Debug)]
|
||||
pub struct SerializableProof(pub Proof<Bn254>);
|
||||
|
||||
#[derive(CanonicalSerialize, CanonicalDeserialize, Clone, Debug, PartialEq)]
|
||||
pub struct SerializableInputs(pub Vec<<Bn254 as Pairing>::ScalarField>);
|
||||
|
||||
pub fn serialize_proof(proof: &SerializableProof) -> Vec<u8> {
|
||||
let mut serialized_data = Vec::new();
|
||||
proof
|
||||
.serialize_uncompressed(&mut serialized_data)
|
||||
.expect("Serialization failed");
|
||||
serialized_data
|
||||
}
|
||||
|
||||
pub fn deserialize_proof(data: Vec<u8>) -> SerializableProof {
|
||||
SerializableProof::deserialize_uncompressed(&mut &data[..]).expect("Deserialization failed")
|
||||
}
|
||||
|
||||
pub fn serialize_proving_key(pk: &SerializableProvingKey) -> Vec<u8> {
|
||||
let mut serialized_data = Vec::new();
|
||||
pk.serialize_uncompressed(&mut serialized_data)
|
||||
.expect("Serialization failed");
|
||||
serialized_data
|
||||
}
|
||||
|
||||
pub fn deserialize_proving_key(data: Vec<u8>) -> SerializableProvingKey {
|
||||
SerializableProvingKey::deserialize_uncompressed(&mut &data[..])
|
||||
.expect("Deserialization failed")
|
||||
}
|
||||
|
||||
pub fn serialize_inputs(inputs: &SerializableInputs) -> Vec<u8> {
|
||||
let mut serialized_data = Vec::new();
|
||||
inputs
|
||||
.serialize_uncompressed(&mut serialized_data)
|
||||
.expect("Serialization failed");
|
||||
serialized_data
|
||||
}
|
||||
|
||||
pub fn deserialize_inputs(data: Vec<u8>) -> SerializableInputs {
|
||||
SerializableInputs::deserialize_uncompressed(&mut &data[..]).expect("Deserialization failed")
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::middleware::circom::serialization::SerializableProvingKey;
|
||||
use crate::middleware::circom::utils::assert_paths_exists;
|
||||
use crate::MoproError;
|
||||
use ark_bn254::Bn254;
|
||||
use ark_circom::{CircomBuilder, CircomConfig};
|
||||
use ark_groth16::Groth16;
|
||||
use ark_std::rand::thread_rng;
|
||||
use color_eyre::Result;
|
||||
|
||||
type GrothBn = Groth16<Bn254>;
|
||||
|
||||
fn generate_serializable_proving_key(
|
||||
wasm_path: &str,
|
||||
r1cs_path: &str,
|
||||
) -> Result<SerializableProvingKey, MoproError> {
|
||||
assert_paths_exists(wasm_path, r1cs_path)?;
|
||||
|
||||
let cfg = CircomConfig::<Bn254>::new(wasm_path, r1cs_path)
|
||||
.map_err(|e| MoproError::CircomError(e.to_string()))?;
|
||||
|
||||
let builder = CircomBuilder::new(cfg);
|
||||
let circom = builder.setup();
|
||||
|
||||
let mut rng = thread_rng();
|
||||
let raw_params = GrothBn::generate_random_parameters_with_reduction(circom, &mut rng)
|
||||
.map_err(|e| MoproError::CircomError(e.to_string()))?;
|
||||
|
||||
Ok(SerializableProvingKey(raw_params))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_serialization_deserialization() {
|
||||
let wasm_path = "./examples/circom/multiplier2/target/multiplier2_js/multiplier2.wasm";
|
||||
let r1cs_path = "./examples/circom/multiplier2/target/multiplier2.r1cs";
|
||||
|
||||
// Generate a serializable proving key for testing
|
||||
let serializable_pk = generate_serializable_proving_key(wasm_path, r1cs_path)
|
||||
.expect("Failed to generate serializable proving key");
|
||||
|
||||
// Serialize
|
||||
let serialized_data = serialize_proving_key(&serializable_pk);
|
||||
|
||||
// Deserialize
|
||||
let deserialized_pk = deserialize_proving_key(serialized_data);
|
||||
|
||||
// Assert that the original and deserialized ProvingKeys are the same
|
||||
assert_eq!(
|
||||
serializable_pk.0, deserialized_pk.0,
|
||||
"Original and deserialized proving keys do not match"
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
use crate::MoproError;
|
||||
|
||||
use std::path::Path;
|
||||
|
||||
pub fn assert_paths_exists(wasm_path: &str, r1cs_path: &str) -> Result<(), MoproError> {
|
||||
// Check that the files exist - ark-circom should probably do this instead and not panic
|
||||
if !Path::new(wasm_path).exists() {
|
||||
return Err(MoproError::CircomError(format!(
|
||||
"Path does not exist: {}",
|
||||
wasm_path
|
||||
)));
|
||||
}
|
||||
|
||||
if !Path::new(r1cs_path).exists() {
|
||||
return Err(MoproError::CircomError(format!(
|
||||
"Path does not exist: {}",
|
||||
r1cs_path
|
||||
)));
|
||||
};
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn bytes_to_bits(bytes: &[u8]) -> Vec<bool> {
|
||||
let mut bits = Vec::new();
|
||||
for &byte in bytes {
|
||||
for j in 0..8 {
|
||||
let bit = (byte >> j) & 1;
|
||||
bits.push(bit == 1);
|
||||
}
|
||||
}
|
||||
bits
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
pub mod circom;
|
||||
18
app/mopro-ffi/.gitignore
vendored
18
app/mopro-ffi/.gitignore
vendored
@@ -1,18 +0,0 @@
|
||||
# Generated by Cargo
|
||||
# will have compiled files and executables
|
||||
debug/
|
||||
target/
|
||||
|
||||
# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
|
||||
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
|
||||
Cargo.lock
|
||||
|
||||
# These are backup files generated by rustfmt
|
||||
**/*.rs.bk
|
||||
|
||||
# MSVC Windows builds of rustc generate these, which store debugging information
|
||||
*.pdb
|
||||
|
||||
# kotlin generated file
|
||||
jniLibs/
|
||||
src/uniffi/mopro/
|
||||
@@ -1,47 +0,0 @@
|
||||
[package]
|
||||
name = "mopro-ffi"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[lib]
|
||||
crate-type = ["lib", "cdylib", "staticlib"]
|
||||
name = "mopro_ffi"
|
||||
|
||||
[[bin]]
|
||||
name = "uniffi-bindgen"
|
||||
path = "uniffi-bindgen.rs"
|
||||
|
||||
[features]
|
||||
default = []
|
||||
|
||||
# If we enable dylib here it should be enabled in mopro-core as well
|
||||
dylib = ["mopro-core/dylib"]
|
||||
|
||||
[patch.crates-io]
|
||||
# NOTE: Forked wasmer to work around memory limits
|
||||
# See https://github.com/wasmerio/wasmer/commit/09c7070
|
||||
wasmer = { git = "https://github.com/oskarth/wasmer.git", rev = "09c7070" }
|
||||
|
||||
[dependencies]
|
||||
mopro-core = { path = "../mopro-core" }
|
||||
uniffi = { version = "0.25", features = ["cli"] }
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
bincode = "1"
|
||||
ark-serialize = { version = "=0.4.1", features = ["derive"] }
|
||||
num-bigint = { version = "=0.4.3", default-features = false, features = [
|
||||
"rand",
|
||||
] }
|
||||
|
||||
# Error handling
|
||||
thiserror = "=1.0.39"
|
||||
color-eyre = "=0.6.2"
|
||||
criterion = "=0.3.6"
|
||||
|
||||
[build-dependencies]
|
||||
uniffi = { version = "0.25", features = ["build"] }
|
||||
|
||||
[dev-dependencies]
|
||||
uniffi = { version = "0.25", features = ["bindgen-tests"] }
|
||||
ark-bn254 = { version = "=0.4.0" }
|
||||
@@ -1,16 +0,0 @@
|
||||
TARGETS = x86_64-apple-ios aarch64-apple-ios aarch64-apple-ios-sim
|
||||
BUILD_TYPES = debug release
|
||||
|
||||
all: $(BUILD_TYPES)
|
||||
|
||||
debug: $(TARGETS)
|
||||
for target in $(TARGETS); do \
|
||||
cargo build --target $$target; \
|
||||
done
|
||||
|
||||
release:
|
||||
for target in $(TARGETS); do \
|
||||
cargo build --release --target $$target; \
|
||||
done
|
||||
|
||||
.PHONY: all $(BUILD_TYPES) $(TARGETS)
|
||||
@@ -1,48 +0,0 @@
|
||||
# mopro-ffi
|
||||
|
||||
Thin wrapper around `mopro-core`, exposes UniFFI bindings to be used by `rust-ios`, etc.
|
||||
|
||||
## Overview
|
||||
|
||||
TBD.
|
||||
|
||||
## Development
|
||||
|
||||
### Prerequisites
|
||||
|
||||
1. Ensure you have Rust installed
|
||||
2. Add platform targets `rustup target add x86_64-apple-ios aarch64-apple-ios aarch64-apple-ios-sim`
|
||||
3. Install `uniffi-bindgen` locally with `cargo install --bin uniffi-bindgen --path .`
|
||||
4. In order to locally run the bindings tests, you will need
|
||||
* Kotlin:
|
||||
* `kotlinc`, the [Kotlin command-line compiler](https://kotlinlang.org/docs/command-line.html).
|
||||
* `ktlint`, the [Kotlin linter used to format the generated bindings](https://ktlint.github.io/).
|
||||
* The [Java Native Access](https://github.com/java-native-access/jna#download) JAR downloaded and its path
|
||||
added to your `$CLASSPATH` environment variable.
|
||||
* Swift:
|
||||
* `swift` and `swiftc`, the [Swift command-line tools](https://swift.org/download/).
|
||||
* The Swift `Foundation` package.
|
||||
|
||||
### Platforms supported
|
||||
|
||||
Currently iOS is the main target, but Android will soon follow. PRs welcome.
|
||||
|
||||
### Building
|
||||
|
||||
Run `make` to build debug and release static libraries for supported platforms.
|
||||
|
||||
### Generate UniFFI bindings
|
||||
|
||||
The following command generates Swift bindings:
|
||||
|
||||
`uniffi-bindgen generate src/mopro.udl --language swift --out-dir target/SwiftBindings`
|
||||
|
||||
## Test bindings
|
||||
|
||||
To test bindings:
|
||||
|
||||
`cargo test --test test_generated_bindings`
|
||||
|
||||
To test bindings in release mode without warning:
|
||||
|
||||
`cargo test --test test_generated_bindings --release 2>/dev/null`
|
||||
@@ -1,3 +0,0 @@
|
||||
fn main() {
|
||||
uniffi::generate_scaffolding("src/mopro.udl").expect("Building the UDL file failed");
|
||||
}
|
||||
@@ -1,295 +0,0 @@
|
||||
use mopro_core::middleware::circom;
|
||||
use mopro_core::MoproError;
|
||||
|
||||
use num_bigint::BigInt;
|
||||
use std::collections::HashMap;
|
||||
use std::path::Path;
|
||||
use std::str::FromStr;
|
||||
use std::sync::RwLock;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum FFIError {
|
||||
MoproError(mopro_core::MoproError),
|
||||
SerializationError(String),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct GenerateProofResult {
|
||||
pub proof: Vec<u8>,
|
||||
pub inputs: Vec<u8>,
|
||||
}
|
||||
|
||||
// NOTE: Make UniFFI and Rust happy, can maybe do some renaming here
|
||||
#[allow(non_snake_case)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct SetupResult {
|
||||
pub provingKey: Vec<u8>,
|
||||
}
|
||||
|
||||
// pub inputs: Vec<u8>,
|
||||
|
||||
impl From<mopro_core::MoproError> for FFIError {
|
||||
fn from(error: mopro_core::MoproError) -> Self {
|
||||
FFIError::MoproError(error)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct MoproCircom {
|
||||
state: RwLock<circom::CircomState>,
|
||||
}
|
||||
|
||||
impl Default for MoproCircom {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "dylib"))]
|
||||
pub fn initialize_mopro() -> Result<(), MoproError> {
|
||||
// TODO: Error handle / panic?
|
||||
circom::initialize();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(feature = "dylib")]
|
||||
pub fn initialize_mopro() -> Result<(), MoproError> {
|
||||
println!("need to use dylib to init!");
|
||||
panic!("need to use dylib to init!");
|
||||
}
|
||||
|
||||
#[cfg(feature = "dylib")]
|
||||
pub fn initialize_mopro_dylib(dylib_path: String) -> Result<(), MoproError> {
|
||||
// TODO: Error handle / panic?
|
||||
let dylib_path = Path::new(dylib_path.as_str());
|
||||
circom::initialize(dylib_path);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "dylib"))]
|
||||
pub fn initialize_mopro_dylib(dylib_path: String) -> Result<(), MoproError> {
|
||||
println!("dylib feature not enabled!");
|
||||
panic!("dylib feature not enabled!");
|
||||
}
|
||||
|
||||
pub fn generate_proof2(
|
||||
inputs: HashMap<String, Vec<String>>,
|
||||
) -> Result<GenerateProofResult, MoproError> {
|
||||
// Convert inputs to BigInt
|
||||
let bigint_inputs = inputs
|
||||
.into_iter()
|
||||
.map(|(k, v)| {
|
||||
(
|
||||
k,
|
||||
v.into_iter()
|
||||
.map(|i| BigInt::from_str(&i).unwrap())
|
||||
.collect(),
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
|
||||
let (proof, inputs) = circom::generate_proof2(bigint_inputs)?;
|
||||
|
||||
let serialized_proof = circom::serialization::serialize_proof(&proof);
|
||||
let serialized_inputs = circom::serialization::serialize_inputs(&inputs);
|
||||
Ok(GenerateProofResult {
|
||||
proof: serialized_proof,
|
||||
inputs: serialized_inputs,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn verify_proof2(proof: Vec<u8>, public_input: Vec<u8>) -> Result<bool, MoproError> {
|
||||
let deserialized_proof = circom::serialization::deserialize_proof(proof);
|
||||
let deserialized_public_input = circom::serialization::deserialize_inputs(public_input);
|
||||
let is_valid = circom::verify_proof2(deserialized_proof, deserialized_public_input)?;
|
||||
Ok(is_valid)
|
||||
}
|
||||
|
||||
// TODO: Use FFIError::SerializationError instead
|
||||
impl MoproCircom {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
state: RwLock::new(circom::CircomState::new()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn setup(&self, wasm_path: String, r1cs_path: String) -> Result<SetupResult, MoproError> {
|
||||
let mut state_guard = self.state.write().unwrap();
|
||||
let pk = state_guard.setup(wasm_path.as_str(), r1cs_path.as_str())?;
|
||||
Ok(SetupResult {
|
||||
provingKey: circom::serialization::serialize_proving_key(&pk),
|
||||
})
|
||||
}
|
||||
|
||||
// inputs: circom::serialization::serialize_inputs(&inputs),
|
||||
|
||||
pub fn generate_proof(
|
||||
&self,
|
||||
inputs: HashMap<String, Vec<String>>,
|
||||
) -> Result<GenerateProofResult, MoproError> {
|
||||
let mut state_guard = self.state.write().unwrap();
|
||||
|
||||
// Convert inputs to BigInt
|
||||
let bigint_inputs = inputs
|
||||
.into_iter()
|
||||
.map(|(k, v)| {
|
||||
(
|
||||
k,
|
||||
v.into_iter()
|
||||
.map(|i| BigInt::from_str(&i).unwrap())
|
||||
.collect(),
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
|
||||
let (proof, inputs) = state_guard.generate_proof(bigint_inputs)?;
|
||||
|
||||
Ok(GenerateProofResult {
|
||||
proof: circom::serialization::serialize_proof(&proof),
|
||||
inputs: circom::serialization::serialize_inputs(&inputs),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn verify_proof(&self, proof: Vec<u8>, public_input: Vec<u8>) -> Result<bool, MoproError> {
|
||||
let state_guard = self.state.read().unwrap();
|
||||
let deserialized_proof = circom::serialization::deserialize_proof(proof);
|
||||
let deserialized_public_input = circom::serialization::deserialize_inputs(public_input);
|
||||
let is_valid = state_guard.verify_proof(deserialized_proof, deserialized_public_input)?;
|
||||
Ok(is_valid)
|
||||
}
|
||||
}
|
||||
|
||||
fn add(a: u32, b: u32) -> u32 {
|
||||
a + b
|
||||
}
|
||||
|
||||
fn hello() -> String {
|
||||
"Hello World from Rust".to_string()
|
||||
}
|
||||
|
||||
// TODO: Remove me
|
||||
// UniFFI expects String type
|
||||
// See https://mozilla.github.io/uniffi-rs/udl/builtin_types.html
|
||||
// fn run_example(wasm_path: String, r1cs_path: String) -> Result<(), MoproError> {
|
||||
// circom::run_example(wasm_path.as_str(), r1cs_path.as_str())
|
||||
// }
|
||||
|
||||
uniffi::include_scaffolding!("mopro");
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use ark_bn254::Fr;
|
||||
use num_bigint::BigUint;
|
||||
|
||||
fn bytes_to_circuit_inputs(input_vec: &Vec<u8>) -> HashMap<String, Vec<String>> {
|
||||
let bits = circom::utils::bytes_to_bits(&input_vec);
|
||||
let converted_vec: Vec<String> = bits
|
||||
.into_iter()
|
||||
.map(|bit| (bit as i32).to_string())
|
||||
.collect();
|
||||
let mut inputs = HashMap::new();
|
||||
inputs.insert("in".to_string(), converted_vec);
|
||||
inputs
|
||||
}
|
||||
|
||||
fn bytes_to_circuit_outputs(bytes: &[u8]) -> Vec<u8> {
|
||||
let bits = circom::utils::bytes_to_bits(bytes);
|
||||
let field_bits = bits.into_iter().map(|bit| Fr::from(bit as u8)).collect();
|
||||
let circom_outputs = circom::serialization::SerializableInputs(field_bits);
|
||||
circom::serialization::serialize_inputs(&circom_outputs)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn add_works() {
|
||||
let result = add(2, 2);
|
||||
assert_eq!(result, 4);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_end_to_end() -> Result<(), MoproError> {
|
||||
// Paths to your wasm and r1cs files
|
||||
let wasm_path =
|
||||
"./../mopro-core/examples/circom/multiplier2/target/multiplier2_js/multiplier2.wasm";
|
||||
let r1cs_path = "./../mopro-core/examples/circom/multiplier2/target/multiplier2.r1cs";
|
||||
|
||||
// Create a new MoproCircom instance
|
||||
let mopro_circom = MoproCircom::new();
|
||||
|
||||
// Step 1: Setup
|
||||
let setup_result = mopro_circom.setup(wasm_path.to_string(), r1cs_path.to_string())?;
|
||||
assert!(setup_result.provingKey.len() > 0);
|
||||
|
||||
let mut inputs = HashMap::new();
|
||||
let a = BigUint::from_str(
|
||||
"21888242871839275222246405745257275088548364400416034343698204186575808495616",
|
||||
)
|
||||
.unwrap();
|
||||
let b = BigUint::from(1u8);
|
||||
let c = a.clone() * b.clone();
|
||||
inputs.insert("a".to_string(), vec![a.to_string()]);
|
||||
inputs.insert("b".to_string(), vec![b.to_string()]);
|
||||
// output = [public output c, public input a]
|
||||
let expected_output = vec![Fr::from(c), Fr::from(a)];
|
||||
let circom_outputs = circom::serialization::SerializableInputs(expected_output);
|
||||
let serialized_outputs = circom::serialization::serialize_inputs(&circom_outputs);
|
||||
|
||||
// Step 2: Generate Proof
|
||||
let generate_proof_result = mopro_circom.generate_proof(inputs)?;
|
||||
let serialized_proof = generate_proof_result.proof;
|
||||
let serialized_inputs = generate_proof_result.inputs;
|
||||
|
||||
assert!(serialized_proof.len() > 0);
|
||||
assert_eq!(serialized_inputs, serialized_outputs);
|
||||
|
||||
// Step 3: Verify Proof
|
||||
let is_valid = mopro_circom.verify_proof(serialized_proof, serialized_inputs)?;
|
||||
assert!(is_valid);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_end_to_end_keccak() -> Result<(), MoproError> {
|
||||
// Paths to your wasm and r1cs files
|
||||
let wasm_path =
|
||||
"./../mopro-core/examples/circom/keccak256/target/keccak256_256_test_js/keccak256_256_test.wasm";
|
||||
let r1cs_path = "./../mopro-core/examples/circom/keccak256/target/keccak256_256_test.r1cs";
|
||||
|
||||
// Create a new MoproCircom instance
|
||||
let mopro_circom = MoproCircom::new();
|
||||
|
||||
// Step 1: Setup
|
||||
let setup_result = mopro_circom.setup(wasm_path.to_string(), r1cs_path.to_string())?;
|
||||
assert!(setup_result.provingKey.len() > 0);
|
||||
|
||||
// Prepare inputs
|
||||
let input_vec = vec![
|
||||
116, 101, 115, 116, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0,
|
||||
];
|
||||
|
||||
// Expected output
|
||||
let expected_output_vec = vec![
|
||||
37, 17, 98, 135, 161, 178, 88, 97, 125, 150, 143, 65, 228, 211, 170, 133, 153, 9, 88,
|
||||
212, 4, 212, 175, 238, 249, 210, 214, 116, 170, 85, 45, 21,
|
||||
];
|
||||
|
||||
let inputs = bytes_to_circuit_inputs(&input_vec);
|
||||
let serialized_outputs = bytes_to_circuit_outputs(&expected_output_vec);
|
||||
|
||||
// Step 2: Generate Proof
|
||||
let generate_proof_result = mopro_circom.generate_proof(inputs)?;
|
||||
let serialized_proof = generate_proof_result.proof;
|
||||
let serialized_inputs = generate_proof_result.inputs;
|
||||
|
||||
assert!(serialized_proof.len() > 0);
|
||||
assert_eq!(serialized_inputs, serialized_outputs);
|
||||
|
||||
// Step 3: Verify Proof
|
||||
|
||||
let is_valid = mopro_circom.verify_proof(serialized_proof, serialized_inputs)?;
|
||||
assert!(is_valid);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
namespace mopro {
|
||||
u32 add(u32 a, u32 b);
|
||||
string hello();
|
||||
|
||||
[Throws=MoproError]
|
||||
void initialize_mopro();
|
||||
|
||||
[Throws=MoproError]
|
||||
void initialize_mopro_dylib(string dylib_path);
|
||||
|
||||
[Throws=MoproError]
|
||||
GenerateProofResult generate_proof2(record<string, sequence<string>> circuit_inputs);
|
||||
|
||||
[Throws=MoproError]
|
||||
boolean verify_proof2(bytes proof, bytes public_input);
|
||||
};
|
||||
|
||||
dictionary SetupResult {
|
||||
bytes provingKey;
|
||||
};
|
||||
|
||||
dictionary GenerateProofResult {
|
||||
bytes proof;
|
||||
bytes inputs;
|
||||
};
|
||||
|
||||
[Error]
|
||||
enum MoproError {
|
||||
"CircomError",
|
||||
};
|
||||
|
||||
interface MoproCircom {
|
||||
constructor();
|
||||
|
||||
[Throws=MoproError]
|
||||
SetupResult setup(string wasm_path, string r1cs_path);
|
||||
|
||||
[Throws=MoproError]
|
||||
GenerateProofResult generate_proof(record<string, sequence<string>> circuit_inputs);
|
||||
|
||||
[Throws=MoproError]
|
||||
boolean verify_proof(bytes proof, bytes public_input);
|
||||
};
|
||||
@@ -1,21 +0,0 @@
|
||||
import uniffi.mopro.*
|
||||
|
||||
var wasmPath = "../mopro-core/examples/circom/multiplier2/target/multiplier2_js/multiplier2.wasm"
|
||||
var r1csPath = "../mopro-core/examples/circom/multiplier2/target/multiplier2.r1cs"
|
||||
|
||||
try {
|
||||
var moproCircom = MoproCircom()
|
||||
var setupResult = moproCircom.setup(wasmPath, r1csPath)
|
||||
assert(setupResult.provingKey.size > 0) { "Proving key should not be empty" }
|
||||
|
||||
val inputs = mutableMapOf<String, List<String>>()
|
||||
inputs["a"] = listOf("3")
|
||||
inputs["b"] = listOf("5")
|
||||
|
||||
var generateProofResult = moproCircom.generateProof(inputs)
|
||||
assert(generateProofResult.proof.size > 0) { "Proof is empty" }
|
||||
var isValid = moproCircom.verifyProof(generateProofResult.proof, generateProofResult.inputs)
|
||||
assert(isValid) { "Proof is invalid" }
|
||||
} catch (e: Exception) {
|
||||
println(e)
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
import mopro
|
||||
import Foundation
|
||||
|
||||
let moproCircom = MoproCircom()
|
||||
|
||||
let wasmPath = "./../../../../mopro-core/examples/circom/multiplier2/target/multiplier2_js/multiplier2.wasm"
|
||||
let r1csPath = "./../../../../mopro-core/examples/circom/multiplier2/target/multiplier2.r1cs"
|
||||
|
||||
func serializeOutputs(_ stringArray: [String]) -> [UInt8] {
|
||||
var bytesArray: [UInt8] = []
|
||||
let length = stringArray.count
|
||||
var littleEndianLength = length.littleEndian
|
||||
let targetLength = 32
|
||||
withUnsafeBytes(of: &littleEndianLength) {
|
||||
bytesArray.append(contentsOf: $0)
|
||||
}
|
||||
for value in stringArray {
|
||||
// TODO: should handle 254-bit input
|
||||
var littleEndian = Int32(value)!.littleEndian
|
||||
var byteLength = 0
|
||||
withUnsafeBytes(of: &littleEndian) {
|
||||
bytesArray.append(contentsOf: $0)
|
||||
byteLength = byteLength + $0.count
|
||||
}
|
||||
if byteLength < targetLength {
|
||||
let paddingCount = targetLength - byteLength
|
||||
let paddingArray = [UInt8](repeating: 0, count: paddingCount)
|
||||
bytesArray.append(contentsOf: paddingArray)
|
||||
}
|
||||
}
|
||||
return bytesArray
|
||||
}
|
||||
|
||||
do {
|
||||
// Setup
|
||||
let setupResult = try moproCircom.setup(wasmPath: wasmPath, r1csPath: r1csPath)
|
||||
assert(!setupResult.provingKey.isEmpty, "Proving key should not be empty")
|
||||
|
||||
// Prepare inputs
|
||||
var inputs = [String: [String]]()
|
||||
let a = 3
|
||||
let b = 5
|
||||
let c = a*b
|
||||
inputs["a"] = [String(a)]
|
||||
inputs["b"] = [String(b)]
|
||||
|
||||
// Expected outputs
|
||||
let outputs: [String] = [String(c), String(a)]
|
||||
let expectedOutput: [UInt8] = serializeOutputs(outputs)
|
||||
|
||||
// Generate Proof
|
||||
let generateProofResult = try moproCircom.generateProof(circuitInputs: inputs)
|
||||
assert(!generateProofResult.proof.isEmpty, "Proof should not be empty")
|
||||
|
||||
// Verify Proof
|
||||
assert(Data(expectedOutput) == generateProofResult.inputs, "Circuit outputs mismatch the expected outputs")
|
||||
|
||||
let isValid = try moproCircom.verifyProof(proof: generateProofResult.proof, publicInput: generateProofResult.inputs)
|
||||
assert(isValid, "Proof verification should succeed")
|
||||
|
||||
} catch let error as MoproError {
|
||||
print("MoproError: \(error)")
|
||||
} catch {
|
||||
print("Unexpected error: \(error)")
|
||||
}
|
||||
@@ -1,279 +0,0 @@
|
||||
import uniffi.mopro.*
|
||||
|
||||
var wasmPath =
|
||||
"../mopro-core/examples/circom/keccak256/target/keccak256_256_test_js/keccak256_256_test.wasm"
|
||||
var r1csPath = "../mopro-core/examples/circom/keccak256/target/keccak256_256_test.r1cs"
|
||||
|
||||
try {
|
||||
var moproCircom = MoproCircom()
|
||||
var setupResult = moproCircom.setup(wasmPath, r1csPath)
|
||||
assert(setupResult.provingKey.size > 0) { "Proving key should not be empty" }
|
||||
|
||||
val inputs = mutableMapOf<String, List<String>>()
|
||||
inputs["in"] =
|
||||
listOf(
|
||||
"0",
|
||||
"0",
|
||||
"1",
|
||||
"0",
|
||||
"1",
|
||||
"1",
|
||||
"1",
|
||||
"0",
|
||||
"1",
|
||||
"0",
|
||||
"1",
|
||||
"0",
|
||||
"0",
|
||||
"1",
|
||||
"1",
|
||||
"0",
|
||||
"1",
|
||||
"1",
|
||||
"0",
|
||||
"0",
|
||||
"1",
|
||||
"1",
|
||||
"1",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"1",
|
||||
"0",
|
||||
"1",
|
||||
"1",
|
||||
"1",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0"
|
||||
)
|
||||
|
||||
var generateProofResult = moproCircom.generateProof(inputs)
|
||||
assert(generateProofResult.proof.size > 0) { "Proof is empty" }
|
||||
var isValid = moproCircom.verifyProof(generateProofResult.proof, generateProofResult.inputs)
|
||||
assert(isValid) { "Proof is invalid" }
|
||||
} catch (e: Exception) {
|
||||
println(e)
|
||||
}
|
||||
@@ -1,82 +0,0 @@
|
||||
import mopro
|
||||
import Foundation
|
||||
|
||||
let moproCircom = MoproCircom()
|
||||
|
||||
let wasmPath = "./../../../../mopro-core/examples/circom/keccak256/target/keccak256_256_test_js/keccak256_256_test.wasm"
|
||||
let r1csPath = "./../../../../mopro-core/examples/circom/keccak256/target/keccak256_256_test.r1cs"
|
||||
|
||||
// Helper function to convert bytes to bits
|
||||
func bytesToBits(bytes: [UInt8]) -> [String] {
|
||||
var bits = [String]()
|
||||
for byte in bytes {
|
||||
for j in 0..<8 {
|
||||
let bit = (byte >> j) & 1
|
||||
bits.append(String(bit))
|
||||
}
|
||||
}
|
||||
return bits
|
||||
}
|
||||
|
||||
func serializeOutputs(_ stringArray: [String]) -> [UInt8] {
|
||||
var bytesArray: [UInt8] = []
|
||||
let length = stringArray.count
|
||||
var littleEndianLength = length.littleEndian
|
||||
let targetLength = 32
|
||||
withUnsafeBytes(of: &littleEndianLength) {
|
||||
bytesArray.append(contentsOf: $0)
|
||||
}
|
||||
for value in stringArray {
|
||||
// TODO: should handle 254-bit input
|
||||
var littleEndian = Int32(value)!.littleEndian
|
||||
var byteLength = 0
|
||||
withUnsafeBytes(of: &littleEndian) {
|
||||
bytesArray.append(contentsOf: $0)
|
||||
byteLength = byteLength + $0.count
|
||||
}
|
||||
if byteLength < targetLength {
|
||||
let paddingCount = targetLength - byteLength
|
||||
let paddingArray = [UInt8](repeating: 0, count: paddingCount)
|
||||
bytesArray.append(contentsOf: paddingArray)
|
||||
}
|
||||
}
|
||||
return bytesArray
|
||||
}
|
||||
|
||||
do {
|
||||
// Setup
|
||||
let setupResult = try moproCircom.setup(wasmPath: wasmPath, r1csPath: r1csPath)
|
||||
assert(!setupResult.provingKey.isEmpty, "Proving key should not be empty")
|
||||
|
||||
// Prepare inputs
|
||||
let inputVec: [UInt8] = [
|
||||
116, 101, 115, 116, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0,
|
||||
]
|
||||
let bits = bytesToBits(bytes: inputVec)
|
||||
var inputs = [String: [String]]()
|
||||
inputs["in"] = bits
|
||||
|
||||
// Expected outputs
|
||||
let outputVec: [UInt8] = [
|
||||
37, 17, 98, 135, 161, 178, 88, 97, 125, 150, 143, 65, 228, 211, 170, 133, 153, 9, 88,
|
||||
212, 4, 212, 175, 238, 249, 210, 214, 116, 170, 85, 45, 21,
|
||||
]
|
||||
let outputBits: [String] = bytesToBits(bytes: outputVec)
|
||||
let expectedOutput: [UInt8] = serializeOutputs(outputBits)
|
||||
|
||||
// Generate Proof
|
||||
let generateProofResult = try moproCircom.generateProof(circuitInputs: inputs)
|
||||
assert(!generateProofResult.proof.isEmpty, "Proof should not be empty")
|
||||
|
||||
// Verify Proof
|
||||
assert(Data(expectedOutput) == generateProofResult.inputs, "Circuit outputs mismatch the expected outputs")
|
||||
|
||||
let isValid = try moproCircom.verifyProof(proof: generateProofResult.proof, publicInput: generateProofResult.inputs)
|
||||
assert(isValid, "Proof verification should succeed")
|
||||
|
||||
} catch let error as MoproError {
|
||||
print("MoproError: \(error)")
|
||||
} catch {
|
||||
print("Unexpected error: \(error)")
|
||||
}
|
||||
@@ -1,273 +0,0 @@
|
||||
import uniffi.mopro.*
|
||||
|
||||
try {
|
||||
initializeMopro()
|
||||
|
||||
val inputs = mutableMapOf<String, List<String>>()
|
||||
inputs["in"] =
|
||||
listOf(
|
||||
"0",
|
||||
"0",
|
||||
"1",
|
||||
"0",
|
||||
"1",
|
||||
"1",
|
||||
"1",
|
||||
"0",
|
||||
"1",
|
||||
"0",
|
||||
"1",
|
||||
"0",
|
||||
"0",
|
||||
"1",
|
||||
"1",
|
||||
"0",
|
||||
"1",
|
||||
"1",
|
||||
"0",
|
||||
"0",
|
||||
"1",
|
||||
"1",
|
||||
"1",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"1",
|
||||
"0",
|
||||
"1",
|
||||
"1",
|
||||
"1",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0"
|
||||
)
|
||||
|
||||
var generateProofResult = generateProof2(inputs)
|
||||
assert(generateProofResult.proof.size > 0) { "Proof is empty" }
|
||||
var isValid = verifyProof2(generateProofResult.proof, generateProofResult.inputs)
|
||||
assert(isValid) { "Proof is invalid" }
|
||||
} catch (e: Exception) {
|
||||
println(e)
|
||||
}
|
||||
@@ -1,86 +0,0 @@
|
||||
import Foundation
|
||||
import mopro
|
||||
|
||||
//let moproCircom = MoproCircom()
|
||||
|
||||
// Using zkey and generate_proof2
|
||||
|
||||
// let wasmPath = "./../../../../mopro-core/examples/circom/keccak256/target/keccak256_256_test_js/keccak256_256_test.wasm"
|
||||
// let r1csPath = "./../../../../mopro-core/examples/circom/keccak256/target/keccak256_256_test.r1cs"
|
||||
|
||||
// Helper function to convert bytes to bits
|
||||
func bytesToBits(bytes: [UInt8]) -> [String] {
|
||||
var bits = [String]()
|
||||
for byte in bytes {
|
||||
for j in 0..<8 {
|
||||
let bit = (byte >> j) & 1
|
||||
bits.append(String(bit))
|
||||
}
|
||||
}
|
||||
return bits
|
||||
}
|
||||
|
||||
func serializeOutputs(_ stringArray: [String]) -> [UInt8] {
|
||||
var bytesArray: [UInt8] = []
|
||||
let length = stringArray.count
|
||||
var littleEndianLength = length.littleEndian
|
||||
let targetLength = 32
|
||||
withUnsafeBytes(of: &littleEndianLength) {
|
||||
bytesArray.append(contentsOf: $0)
|
||||
}
|
||||
for value in stringArray {
|
||||
// TODO: should handle 254-bit input
|
||||
var littleEndian = Int32(value)!.littleEndian
|
||||
var byteLength = 0
|
||||
withUnsafeBytes(of: &littleEndian) {
|
||||
bytesArray.append(contentsOf: $0)
|
||||
byteLength = byteLength + $0.count
|
||||
}
|
||||
if byteLength < targetLength {
|
||||
let paddingCount = targetLength - byteLength
|
||||
let paddingArray = [UInt8](repeating: 0, count: paddingCount)
|
||||
bytesArray.append(contentsOf: paddingArray)
|
||||
}
|
||||
}
|
||||
return bytesArray
|
||||
}
|
||||
|
||||
do {
|
||||
// // Setup
|
||||
// let setupResult = try moproCircom.setup(wasmPath: wasmPath, r1csPath: r1csPath)
|
||||
// assert(!setupResult.provingKey.isEmpty, "Proving key should not be empty")
|
||||
|
||||
// Prepare inputs
|
||||
let inputVec: [UInt8] = [
|
||||
116, 101, 115, 116, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0,
|
||||
]
|
||||
let bits = bytesToBits(bytes: inputVec)
|
||||
var inputs = [String: [String]]()
|
||||
inputs["in"] = bits
|
||||
|
||||
// Expected outputs
|
||||
let outputVec: [UInt8] = [
|
||||
37, 17, 98, 135, 161, 178, 88, 97, 125, 150, 143, 65, 228, 211, 170, 133, 153, 9, 88,
|
||||
212, 4, 212, 175, 238, 249, 210, 214, 116, 170, 85, 45, 21,
|
||||
]
|
||||
let outputBits: [String] = bytesToBits(bytes: outputVec)
|
||||
let expectedOutput: [UInt8] = serializeOutputs(outputBits)
|
||||
|
||||
// // Generate Proof
|
||||
let generateProofResult = try generateProof2(circuitInputs: inputs)
|
||||
// let generateProofResult = try moproCircom.generateProof(circuitInputs: inputs)
|
||||
assert(!generateProofResult.proof.isEmpty, "Proof should not be empty")
|
||||
|
||||
// // Verify Proof
|
||||
assert(Data(expectedOutput) == generateProofResult.inputs, "Circuit outputs mismatch the expected outputs")
|
||||
|
||||
let isValid = try verifyProof2(
|
||||
proof: generateProofResult.proof, publicInput: generateProofResult.inputs)
|
||||
assert(isValid, "Proof verification should succeed")
|
||||
|
||||
} catch let error as MoproError {
|
||||
print("MoproError: \(error)")
|
||||
} catch {
|
||||
print("Unexpected error: \(error)")
|
||||
}
|
||||
@@ -1,115 +0,0 @@
|
||||
import uniffi.mopro.*;
|
||||
|
||||
var wasmPath = "../mopro-core/examples/circom/rsa/target/main_js/main.wasm"
|
||||
var r1csPath = "../mopro-core/examples/circom/rsa/target/main.r1cs"
|
||||
|
||||
try {
|
||||
var moproCircom = MoproCircom()
|
||||
var setupResult = moproCircom.setup(wasmPath, r1csPath)
|
||||
assert(setupResult.provingKey.size > 0) { "Proving key should not be empty"}
|
||||
|
||||
val inputs = mutableMapOf<String, List<String>>()
|
||||
inputs["signature"] = listOf("3582320600048169363",
|
||||
"7163546589759624213",
|
||||
"18262551396327275695",
|
||||
"4479772254206047016",
|
||||
"1970274621151677644",
|
||||
"6547632513799968987",
|
||||
"921117808165172908",
|
||||
"7155116889028933260",
|
||||
"16769940396381196125",
|
||||
"17141182191056257954",
|
||||
"4376997046052607007",
|
||||
"17471823348423771450",
|
||||
"16282311012391954891",
|
||||
"70286524413490741",
|
||||
"1588836847166444745",
|
||||
"15693430141227594668",
|
||||
"13832254169115286697",
|
||||
"15936550641925323613",
|
||||
"323842208142565220",
|
||||
"6558662646882345749",
|
||||
"15268061661646212265",
|
||||
"14962976685717212593",
|
||||
"15773505053543368901",
|
||||
"9586594741348111792",
|
||||
"1455720481014374292",
|
||||
"13945813312010515080",
|
||||
"6352059456732816887",
|
||||
"17556873002865047035",
|
||||
"2412591065060484384",
|
||||
"11512123092407778330",
|
||||
"8499281165724578877",
|
||||
"12768005853882726493")
|
||||
inputs["modulus"] = listOf("13792647154200341559",
|
||||
"12773492180790982043",
|
||||
"13046321649363433702",
|
||||
"10174370803876824128",
|
||||
"7282572246071034406",
|
||||
"1524365412687682781",
|
||||
"4900829043004737418",
|
||||
"6195884386932410966",
|
||||
"13554217876979843574",
|
||||
"17902692039595931737",
|
||||
"12433028734895890975",
|
||||
"15971442058448435996",
|
||||
"4591894758077129763",
|
||||
"11258250015882429548",
|
||||
"16399550288873254981",
|
||||
"8246389845141771315",
|
||||
"14040203746442788850",
|
||||
"7283856864330834987",
|
||||
"12297563098718697441",
|
||||
"13560928146585163504",
|
||||
"7380926829734048483",
|
||||
"14591299561622291080",
|
||||
"8439722381984777599",
|
||||
"17375431987296514829",
|
||||
"16727607878674407272",
|
||||
"3233954801381564296",
|
||||
"17255435698225160983",
|
||||
"15093748890170255670",
|
||||
"15810389980847260072",
|
||||
"11120056430439037392",
|
||||
"5866130971823719482",
|
||||
"13327552690270163501",)
|
||||
inputs["base_message"] = listOf("18114495772705111902",
|
||||
"2254271930739856077",
|
||||
"2068851770",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",)
|
||||
|
||||
var generateProofResult = moproCircom.generateProof(inputs)
|
||||
assert(generateProofResult.proof.size > 0) { "Proof is empty"}
|
||||
var isValid = moproCircom.verifyProof(generateProofResult.proof, generateProofResult.inputs)
|
||||
assert(isValid) { "Proof is invalid"}
|
||||
} catch (e: Exception) {
|
||||
println(e);
|
||||
}
|
||||
@@ -1,174 +0,0 @@
|
||||
import mopro
|
||||
import Foundation
|
||||
|
||||
let moproCircom = MoproCircom()
|
||||
|
||||
let wasmPath = "./../../../../mopro-core/examples/circom/rsa/target/main_js/main.wasm"
|
||||
let r1csPath = "./../../../../mopro-core/examples/circom/rsa/target/main.r1cs"
|
||||
|
||||
// Helper function to convert bytes to bits
|
||||
func bytesToBits(bytes: [UInt8]) -> [String] {
|
||||
var bits = [String]()
|
||||
for byte in bytes {
|
||||
for j in 0..<8 {
|
||||
let bit = (byte >> j) & 1
|
||||
bits.append(String(bit))
|
||||
}
|
||||
}
|
||||
return bits
|
||||
}
|
||||
|
||||
func serializeOutputs(_ stringArray: [String]) -> [UInt8] {
|
||||
var bytesArray: [UInt8] = []
|
||||
let length = stringArray.count
|
||||
var littleEndianLength = length.littleEndian
|
||||
let targetLength = 32
|
||||
withUnsafeBytes(of: &littleEndianLength) {
|
||||
bytesArray.append(contentsOf: $0)
|
||||
}
|
||||
for value in stringArray {
|
||||
// TODO: should handle 254-bit input
|
||||
var littleEndian = Int32(value)!.littleEndian
|
||||
var byteLength = 0
|
||||
withUnsafeBytes(of: &littleEndian) {
|
||||
bytesArray.append(contentsOf: $0)
|
||||
byteLength = byteLength + $0.count
|
||||
}
|
||||
if byteLength < targetLength {
|
||||
let paddingCount = targetLength - byteLength
|
||||
let paddingArray = [UInt8](repeating: 0, count: paddingCount)
|
||||
bytesArray.append(contentsOf: paddingArray)
|
||||
}
|
||||
}
|
||||
return bytesArray
|
||||
}
|
||||
|
||||
do {
|
||||
// Setup
|
||||
let setupResult = try moproCircom.setup(wasmPath: wasmPath, r1csPath: r1csPath)
|
||||
assert(!setupResult.provingKey.isEmpty, "Proving key should not be empty")
|
||||
|
||||
// Prepare inputs
|
||||
let signature: [String] = [
|
||||
"3582320600048169363",
|
||||
"7163546589759624213",
|
||||
"18262551396327275695",
|
||||
"4479772254206047016",
|
||||
"1970274621151677644",
|
||||
"6547632513799968987",
|
||||
"921117808165172908",
|
||||
"7155116889028933260",
|
||||
"16769940396381196125",
|
||||
"17141182191056257954",
|
||||
"4376997046052607007",
|
||||
"17471823348423771450",
|
||||
"16282311012391954891",
|
||||
"70286524413490741",
|
||||
"1588836847166444745",
|
||||
"15693430141227594668",
|
||||
"13832254169115286697",
|
||||
"15936550641925323613",
|
||||
"323842208142565220",
|
||||
"6558662646882345749",
|
||||
"15268061661646212265",
|
||||
"14962976685717212593",
|
||||
"15773505053543368901",
|
||||
"9586594741348111792",
|
||||
"1455720481014374292",
|
||||
"13945813312010515080",
|
||||
"6352059456732816887",
|
||||
"17556873002865047035",
|
||||
"2412591065060484384",
|
||||
"11512123092407778330",
|
||||
"8499281165724578877",
|
||||
"12768005853882726493",
|
||||
]
|
||||
|
||||
let modulus: [String] = [
|
||||
"13792647154200341559",
|
||||
"12773492180790982043",
|
||||
"13046321649363433702",
|
||||
"10174370803876824128",
|
||||
"7282572246071034406",
|
||||
"1524365412687682781",
|
||||
"4900829043004737418",
|
||||
"6195884386932410966",
|
||||
"13554217876979843574",
|
||||
"17902692039595931737",
|
||||
"12433028734895890975",
|
||||
"15971442058448435996",
|
||||
"4591894758077129763",
|
||||
"11258250015882429548",
|
||||
"16399550288873254981",
|
||||
"8246389845141771315",
|
||||
"14040203746442788850",
|
||||
"7283856864330834987",
|
||||
"12297563098718697441",
|
||||
"13560928146585163504",
|
||||
"7380926829734048483",
|
||||
"14591299561622291080",
|
||||
"8439722381984777599",
|
||||
"17375431987296514829",
|
||||
"16727607878674407272",
|
||||
"3233954801381564296",
|
||||
"17255435698225160983",
|
||||
"15093748890170255670",
|
||||
"15810389980847260072",
|
||||
"11120056430439037392",
|
||||
"5866130971823719482",
|
||||
"13327552690270163501",
|
||||
]
|
||||
let base_message: [String] = [
|
||||
"18114495772705111902",
|
||||
"2254271930739856077",
|
||||
"2068851770",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
]
|
||||
|
||||
var inputs = [String: [String]]()
|
||||
inputs["signature"] = signature;
|
||||
inputs["modulus"] = modulus;
|
||||
inputs["base_message"] = base_message;
|
||||
|
||||
|
||||
// Generate Proof
|
||||
let generateProofResult = try moproCircom.generateProof(circuitInputs: inputs)
|
||||
assert(!generateProofResult.proof.isEmpty, "Proof should not be empty")
|
||||
|
||||
// Verifying the Proof
|
||||
let isValid = try moproCircom.verifyProof(proof: generateProofResult.proof, publicInput: generateProofResult.inputs)
|
||||
assert(isValid, "Proof verification should succeed")
|
||||
|
||||
} catch let error as MoproError {
|
||||
print("MoproError: \(error)")
|
||||
} catch {
|
||||
print("Unexpected error: \(error)")
|
||||
}
|
||||
@@ -1,167 +0,0 @@
|
||||
import mopro
|
||||
import Foundation
|
||||
|
||||
// Helper function to convert bytes to bits
|
||||
func bytesToBits(bytes: [UInt8]) -> [String] {
|
||||
var bits = [String]()
|
||||
for byte in bytes {
|
||||
for j in 0..<8 {
|
||||
let bit = (byte >> j) & 1
|
||||
bits.append(String(bit))
|
||||
}
|
||||
}
|
||||
return bits
|
||||
}
|
||||
|
||||
func serializeOutputs(_ stringArray: [String]) -> [UInt8] {
|
||||
var bytesArray: [UInt8] = []
|
||||
let length = stringArray.count
|
||||
var littleEndianLength = length.littleEndian
|
||||
let targetLength = 32
|
||||
withUnsafeBytes(of: &littleEndianLength) {
|
||||
bytesArray.append(contentsOf: $0)
|
||||
}
|
||||
for value in stringArray {
|
||||
// TODO: should handle 254-bit input
|
||||
var littleEndian = Int32(value)!.littleEndian
|
||||
var byteLength = 0
|
||||
withUnsafeBytes(of: &littleEndian) {
|
||||
bytesArray.append(contentsOf: $0)
|
||||
byteLength = byteLength + $0.count
|
||||
}
|
||||
if byteLength < targetLength {
|
||||
let paddingCount = targetLength - byteLength
|
||||
let paddingArray = [UInt8](repeating: 0, count: paddingCount)
|
||||
bytesArray.append(contentsOf: paddingArray)
|
||||
}
|
||||
}
|
||||
return bytesArray
|
||||
}
|
||||
|
||||
do {
|
||||
// Initialize
|
||||
try initializeMopro()
|
||||
|
||||
// Prepare inputs
|
||||
let signature: [String] = [
|
||||
"3582320600048169363",
|
||||
"7163546589759624213",
|
||||
"18262551396327275695",
|
||||
"4479772254206047016",
|
||||
"1970274621151677644",
|
||||
"6547632513799968987",
|
||||
"921117808165172908",
|
||||
"7155116889028933260",
|
||||
"16769940396381196125",
|
||||
"17141182191056257954",
|
||||
"4376997046052607007",
|
||||
"17471823348423771450",
|
||||
"16282311012391954891",
|
||||
"70286524413490741",
|
||||
"1588836847166444745",
|
||||
"15693430141227594668",
|
||||
"13832254169115286697",
|
||||
"15936550641925323613",
|
||||
"323842208142565220",
|
||||
"6558662646882345749",
|
||||
"15268061661646212265",
|
||||
"14962976685717212593",
|
||||
"15773505053543368901",
|
||||
"9586594741348111792",
|
||||
"1455720481014374292",
|
||||
"13945813312010515080",
|
||||
"6352059456732816887",
|
||||
"17556873002865047035",
|
||||
"2412591065060484384",
|
||||
"11512123092407778330",
|
||||
"8499281165724578877",
|
||||
"12768005853882726493",
|
||||
]
|
||||
|
||||
let modulus: [String] = [
|
||||
"13792647154200341559",
|
||||
"12773492180790982043",
|
||||
"13046321649363433702",
|
||||
"10174370803876824128",
|
||||
"7282572246071034406",
|
||||
"1524365412687682781",
|
||||
"4900829043004737418",
|
||||
"6195884386932410966",
|
||||
"13554217876979843574",
|
||||
"17902692039595931737",
|
||||
"12433028734895890975",
|
||||
"15971442058448435996",
|
||||
"4591894758077129763",
|
||||
"11258250015882429548",
|
||||
"16399550288873254981",
|
||||
"8246389845141771315",
|
||||
"14040203746442788850",
|
||||
"7283856864330834987",
|
||||
"12297563098718697441",
|
||||
"13560928146585163504",
|
||||
"7380926829734048483",
|
||||
"14591299561622291080",
|
||||
"8439722381984777599",
|
||||
"17375431987296514829",
|
||||
"16727607878674407272",
|
||||
"3233954801381564296",
|
||||
"17255435698225160983",
|
||||
"15093748890170255670",
|
||||
"15810389980847260072",
|
||||
"11120056430439037392",
|
||||
"5866130971823719482",
|
||||
"13327552690270163501",
|
||||
]
|
||||
let base_message: [String] = [
|
||||
"18114495772705111902",
|
||||
"2254271930739856077",
|
||||
"2068851770",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
]
|
||||
|
||||
var inputs = [String: [String]]()
|
||||
inputs["signature"] = signature;
|
||||
inputs["modulus"] = modulus;
|
||||
inputs["base_message"] = base_message;
|
||||
|
||||
// Generate Proof
|
||||
let generateProofResult = try generateProof2(circuitInputs: inputs)
|
||||
assert(!generateProofResult.proof.isEmpty, "Proof should not be empty")
|
||||
|
||||
// Verifying the Proof
|
||||
let isValid = try verifyProof2(proof: generateProofResult.proof, publicInput: generateProofResult.inputs)
|
||||
assert(isValid, "Proof verification should succeed")
|
||||
|
||||
} catch let error as MoproError {
|
||||
print("MoproError: \(error)")
|
||||
} catch {
|
||||
print("Unexpected error: \(error)")
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
uniffi::build_foreign_language_testcases!(
|
||||
"tests/bindings/test_mopro.swift",
|
||||
"tests/bindings/test_mopro.kts",
|
||||
// "tests/bindings/test_mopro.rb",
|
||||
// "tests/bindings/test_mopro.py",
|
||||
"tests/bindings/test_mopro_keccak.swift",
|
||||
// "tests/bindings/test_mopro_keccak.kts", // FIXME: java.lang.OutOfMemoryError: Java heap space
|
||||
"tests/bindings/test_mopro_keccak2.swift",
|
||||
"tests/bindings/test_mopro_keccak2.kts",
|
||||
"tests/bindings/test_mopro_rsa.swift",
|
||||
// "tests/bindings/test_mopro_rsa.kts", // FIXME: java.lang.OutOfMemoryError: Java heap space
|
||||
// "tests/bindings/test_mopro_rsa2.swift",
|
||||
);
|
||||
@@ -1,3 +0,0 @@
|
||||
fn main() {
|
||||
uniffi::uniffi_bindgen_main()
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
[bindings.swift]
|
||||
module_name = "mopro"
|
||||
Reference in New Issue
Block a user