Skip to main content
Version: Next

Rust Setup

This tutorial will show you how to build static library for Android and iOS. Later pages show how to integrate into an existing iOS or Android app.

Make sure you've installed the prerequisites.

Setup the rust project

Mopro works by providing a static library and an interface for your app to build proofs. Before you start this tutorial you should have a zkey and wasm file generated by circom.

To get started we'll make a new rust project that builds this library. Run the following commands in your terminal:

mkdir mopro-example
cd mopro-example
cargo init --lib

This will create a new rust project in the current directory. Now we'll add some dependencies to this project. Edit your Cargo.toml so that it looks like the following:

[package]
name = "mopro-example"
version = "0.1.0"
edition = "2021"

# We're going to build a static library named mopro_bindings
# This library name should not be changed
[lib]
crate-type = ["lib", "cdylib", "staticlib"]
name = "mopro_bindings"

# We're going to build support for circom proofs only
[features]
default = ["mopro-ffi/circom"]

[dependencies]
mopro-ffi = { git = "https://github.com/zkmopro/mopro.git" }
rust-witness = { git = "https://github.com/vimwitch/rust-witness.git" }
uniffi = { version = "0.28", features = ["cli"] }
num-bigint = "0.4.0"

[build-dependencies]
mopro-ffi = { git = "https://github.com/zkmopro/mopro.git" }
rust-witness = { git = "https://github.com/vimwitch/rust-witness.git" }
uniffi = { version = "0.28", features = ["build"] }

Now you should copy your wasm and zkey files somewhere in the project folder. For this tutorial we'll assume you placed them in test-vectors/circom.

info

Download example multiplier2 wasm and zkey here:

Now we need to add 4 rust files. First we'll add build.rs in the main project folder. This file should contain the following:

fn main() {
// We're going to transpile the wasm witness generators to C
// Change this to where you put your zkeys and wasm files
rust_witness::transpile::transpile_wasm("./test-vectors/circom".to_string());
// This is writing the UDL file which defines the functions exposed
// to your app. We have pre-generated this file for you
// This file must be written to ./src
std::fs::write("./src/mopro.udl", mopro_ffi::app_config::UDL).expect("Failed to write UDL");
// Finally initialize uniffi and build the scaffolding into the
// rust binary
uniffi::generate_scaffolding("./src/mopro.udl").unwrap();
}

Second we'll change the file at ./src/lib.rs to look like the following:

use mopro_ffi::{app, WtnsFn};

// Here we're generating the C functions for a circuit named
// multiplier2.
// Your circuit name will be the name of the wasm file all lowercase
// with spaces, dashes and underscores removed
//
// e.g.
// multiplier2 -> multiplier2
// keccak_256_256_main -> keccak256256main
// aadhaar-verifier -> aadhaarverifier
rust_witness::witness!(multiplier2);

// Here we're calling a macro exported by uniffi. This macro will
// write some functions and bind them to the uniffi UDL file. These
// functions will invoke the zkey_witness_map function written below.
app!();

// This function defines a mapping between zkey filename and witness
// generator. When you make a proof the zkey filename will be passed to
// this function in order to retrieve the appropriate witness generator.
// Remember, we built the witness generator for the circuit above using
// rust_witness.
fn zkey_witness_map(name: &str) -> Result<WtnsFn, MoproError> {
match name {
"multiplier2_final.zkey" => Ok(multiplier2_witness),
_ => Err(MoproError::CircomError("Unknown circuit name".to_string())),
}
}

Finally we'll add a new file at src/bin/ios.rs:

fn main() {
// A simple wrapper around a build command provided by mopro.
// In the future this will likely be published in the mopro crate itself.
mopro_ffi::app_config::ios::build();
}

and another at src/bin/android.rs:

fn main() {
// A simple wrapper around a build command provided by mopro.
// In the future this will likely be published in the mopro crate itself.
mopro_ffi::app_config::android::build();
}

Now you're ready to build your static library! You should be able to run either cargo run --bin ios or cargo run --bin android to build the corresponding static library. Move on to iOS setup or Android setup to begin integrating in an app.