This guide will show you how to embed your own function into mopro-ffi
, successfully generate either Swift or Kotlin bindings, and create a corresponding static library (e.g. xcframework if your target is iOS).
Before getting started, ensure you have:
- Created your own function logic in Rust.
- Forked the
mopro
repository.
To generate Rust scaffolding, import your crates inside the lib.rs
file in mopro-ffi
. We recommend creating a replicate function in lib.rs
that calls your functions from the imported crates. Then, create the same function inside the macro to get the relevant functions into scope and call FFI.
For example:
// mopro-ffi/src/lib.rs
use your_crates;
pub fn your_function(a: u32, b: u32) -> Result<bool, MoproError> {
// Function logic
your_crates::some_function()
}
#[macro_export]
macro_rules! app {
() => {
// Remember to import the struct here if you are using a custom one
use mopro_ffi::{BenchmarkResult, GenerateProofResult, MoproError, ProofCalldata, G1, G2};
use std::collections::HashMap;
fn your_function(a: u32, b: u32) -> Result<bool, MoproError> {
mopro_ffi::your_function(a, b)
}
uniffi::include_scaffolding!("mopro");
};
}
If you are using a feature flag, handle the situation when the flag is not activated.
For example:
// mopro-ffi/src/lib.rs
use your_crates;
#[cfg(feature = "your-feature")]
pub fn your_function(a: u32, b: u32) -> Result<bool, MoproError> {
// Function logic
your_crates::some_function()
}
#[cfg(not(feature = "your-feature"))]
pub fn your_function(_: u32, _: u32) -> Result<bool, MoproError> {
Err(MoproError::YourCustomError("something went wrong".to_string()))
}
Modify mopro-ffi/src/mopro.udl
to define your functions and variable types. Follow the uniffi documentation for more details.
For example:
// mopro-ffi/src/mopro.udl
namespace mopro {
// ... other definitions
[Throws=MoproError]
boolean your_function(u32 a, u32 b);
};
dictionary YourStruct {
u32 a;
u32 b;
};
First, ensure the library name in mopro-ffi/Cargo.toml
is "mopro_bindings". This guarantees the configuration is correctly set up for binding generation.
# mopro-ffi/Cargo.toml
[lib]
name = "mopro_bindings" # Make sure the lib name is correct
Next, run the mopro-ffi/build_bindings.sh
script to generate bindings for your custom functions. Remember to re-run it every time you modify the UDL file and push the resulting output to your repo.
Congratulations! Your custom functions have been successfully added to mopro
. Now, let's integrate mopro
into your app project. If you don't have an app project yet, we recommend forking one from mopro-app.
First, follow the steps in Mopro/Rust-setup to create a valid setup.
Next, include your forked mopro
dependencies and uniffi in your Rust directory.
[package]
name = "your_app"
version = "0.1.0"
edition = "2021"
[lib]
crate-type = ["lib", "cdylib", "staticlib"]
name = "mopro_bindings" # This library name should not be changed
[[bin]]
name = "ios"
[features]
default = ["mopro-ffi/circom"]
[dependencies]
# ... other dependencies
mopro-ffi = { git = "https://github.com/zkmopro/mopro.git", branch = "feat/integrate-gpu-acceleration", features = ["gpu-acceleration"] }
uniffi = { version = "0.28", features = ["cli"] }
[build-dependencies]
# ... other dependencies
mopro-ffi = { git = "https://github.com/zkmopro/mopro.git", branch = "feat/integrate-gpu-acceleration", features = ["gpu-acceleration"] }
uniffi = { version = "0.28", features = ["build"] }
Finally, run the following command in the terminal to build the static library.
# CONFIGURATION is either debug or release
CONFIGURATION=release cargo run --bin ios
CONFIGURATION=debug cargo run --bin ios
Now, you can open your-app/ios/your-app.xcodeproj
to check that your custom functions have been successfully bound to your app.