Rust Setup for Android/iOS Bindings
This tutorial provides step-by-step instructions to manually build static libraries with Circom and Halo2 adapters for Android and iOS. It focuses on a hands-on approach for developers who prefer or require manual setup.
Make sure you've installed the prerequisites.
This tutorial will cover:
Setup Circom-Based rust project
You can integrate mopro-ffi
into your own Rust crate, or alternatively, initialize a new project using
cargo init --lib
1. Add dependencies
Include the crate in your Cargo.toml:
[dependencies]
mopro-ffi = { version = "0.2", features = ["circom"] }
uniffi = "0.29"
circom-prover = "0.1"
thiserror = "2.0.12"
[build-dependencies]
mopro-ffi = "0.2"
uniffi = { version = "0.29", features = ["build"] }
2. Setup the lib
Define the name and type for the UniFFI build process configuration.
[lib]
name = "mopro_bindings"
crate-type = ["lib", "cdylib", "staticlib"]
The name of the lib could be fixed in the future. See: #387
3. Add witness generator
Each witness generator must be built within a project. You need to supply the required data for it to generate a circuit-specific execution function.
Here, we used rust-witness as an example.
To learn more about witnesscalc
for Mopro, please check out circom-prover.
Include the rust-witness
in your Cargo.toml
[dependencies]
rust-witness = "0.1"
num-bigint = "0.4"
[build-dependencies]
rust-witness = "0.1"
In build.rs
, add the following code to compile the witness generator wasm sources (.wasm) into a native library and link to it:
fn main() {
rust_witness::transpile::transpile_wasm("../path to directory containing your wasm sources");
// e.g. rust_witness::transpile::transpile_wasm("./test-vectors".to_string());
// The directory should contain the following files:
// - <circuit name>.wasm
}
Here are the example WASM and Zkey files to be downloaded.
4. Use mopro-ffi
macro
The mopro-ffi
macro exports the default Circom prover interfaces. To enable it, activate the mopro-ffi macro in src/lib.rs
.
mopro_ffi::app!();
Bind the corresponding WASM and Zkey files together using mopro-ffi.
use circom_prover::witness::WitnessFn;
// Activate rust-witness function
rust_witness::witness!(multiplier2);
// Set the witness functions to a zkey
mopro_ffi::set_circom_circuits! {
("multiplier2_final.zkey", WitnessFn::RustWitness(multiplier2_witness)),
}
5. Define the binaries
The binaries are used to generate bindings for both iOS and Android platforms.
We'll add a new file at src/bin/ios.rs
:
fn main() {
mopro_ffi::app_config::ios::build();
}
and another at src/bin/android.rs
:
fn main() {
mopro_ffi::app_config::android::build();
}
6. Generate bindings for iOS and Android
Now you're ready to build your static library! You should be able to run either the Mopro CLI or the binaries.
1. Execute the process through Mopro CLI
Create a Config.toml
configuration file like:
target_adapters = [
"circom",
]
target_platforms = [
"android",
"ios",
]
To install the Mopro CLI, please refer to the Getting Started guide.
Execute the building through
mopro build
Then, you can select the target mode and architectures with greater flexibility.
2. Execute the process using the defined binaries.
cargo run --bin ios # Debug mode for iOS
cargo run --bin android # Debug mode for Android
CONFIGURATION=release cargo run --bin ios # Release mode for iOS
CONFIGURATION=release cargo run --bin android # Release mode for Android
to build the corresponding static library. Move on to iOS setup or Android setup to begin integrating in an app.
Running your project in release mode significantly enhances performance compared to debug mode. This is because the Rust compiler applies optimizations that improve runtime speed and reduce binary size, making your application more efficient.
Setup Halo2-Based rust project
Similar to the Setup Circom-based Rust project, you can integrate mopro-ffi
into your own Rust crate, or alternatively, initialize a new project using
cargo init --lib
1. Add dependencies
Include the crate in your Cargo.toml:
[dependencies]
mopro-ffi = { version = "0.2", features = ["halo2"] }
uniffi = "0.29"
thiserror = "2.0.12"
[build-dependencies]
mopro-ffi = "0.2"
uniffi = { version = "0.29", features = ["build"] }
2. Setup the lib
Similar to Setup the lib, define the name and type for the UniFFI build process configuration.
[lib]
name = "mopro_bindings"
crate-type = ["lib", "cdylib", "staticlib"]
The name of the lib could be fixed in the future. See: #387
3. Add Halo2 circuits
Import the Halo2 prover as a Rust crate using:
[dependencies]
plonk-fibonacci = { package = "plonk-fibonacci", git = "https://github.com/sifnoc/plonkish-fibonacci-sample.git" }
See how to define a Halo2 prover crate here: plonkish-fibonacci-sample
Next, copy your SRS and key files into the project folder. For this tutorial, we'll assume you place them in test-vectors/halo2
.
Download example SRS and key files :
4. Use mopro-ffi
macro
Now, add three rust files, just as in the Circom-based Rust project setup 4. Use mopro-ffi
macro.
Update the src/lib.rs
file to look like the following:
mopro_ffi::app!();
mopro_ffi::set_halo2_circuits! {
("plonk_fibonacci_pk.bin", plonk_fibonacci::prove, "plonk_fibonacci_vk.bin", plonk_fibonacci::verify),
}
5. Define the binaries
Similar to Circom-based Rust project setup 5. Define the binaries
6. Generate bindings for iOS and Android
Similar to Circom-based Rust project setup 6. Generate bindings for iOS and Android
However, creating a Config.toml
like
target_adapters = [
"halo2",
]
target_platforms = [
"android",
"ios",
]
Setup any rust project
In addition to supporting Circom and Halo2 circuits, mopro-ffi
allows integration with any Rust crate, enabling developers to define custom functions for iOS and Android. This ensures that Rust developers can leverage their existing expertise while seamlessly building comprehensive packages for mobile development.
1. Add dependencies
Include the crate in your Cargo.toml:
[dependencies]
mopro-ffi = { version = "0.2" }
uniffi = "0.29"
[build-dependencies]
mopro-ffi = "0.2"
uniffi = { version = "0.29", features = ["build"] }
2. Setup the lib
Similar to Setup the lib, define the name and type for the UniFFI build process configuration.
[lib]
name = "mopro_bindings"
crate-type = ["lib", "cdylib", "staticlib"]
3. Define exported functions
Export Rust functions using a procedural macro, as shown below:
mopro_ffi::app!();
#[uniffi::export]
pub fn hello_world() -> String {
"Hello, World!".to_string()
}
For more examples and detailed references, check the UniFFI documentation.
Enable the mopro-ffi
macro to generate UniFFI scaffolding.
4. Define the binaries
Similar to Circom-based Rust project setup 5. Define the binaries
5. Generate bindings for iOS and Android
Similar to Circom-based Rust project setup 6. Generate bindings for iOS and Android
However, creating a Config.toml
like
target_adapters = []
target_platforms = [
"android",
"ios",
]