From fdd3de58d044c7f89f2fbb0a1b9ec5be3917f307 Mon Sep 17 00:00:00 2001 From: sifnoc Date: Mon, 6 Jan 2025 08:32:06 +0000 Subject: [PATCH 1/7] docs: added 'mopro-wasm' page in v0.1.0 and iOS configuration in prerequisites page --- docs/docs/prerequisites.md | 6 +++ docs/static/img/xcode-setting.png | Bin 0 -> 126738 bytes .../version-0.1.0/mopro-wasm.md | 43 ++++++++++++++++++ .../version-0.1.0-sidebars.json | 7 ++- 4 files changed, 55 insertions(+), 1 deletion(-) create mode 100644 docs/static/img/xcode-setting.png create mode 100644 docs/versioned_docs/version-0.1.0/mopro-wasm.md diff --git a/docs/docs/prerequisites.md b/docs/docs/prerequisites.md index 31ed65cc..0fc6f47f 100644 --- a/docs/docs/prerequisites.md +++ b/docs/docs/prerequisites.md @@ -22,6 +22,12 @@ Depending on what platforms and adapters you use, there are several prerequisite - Halo2 - Pre-generated SRS (Structured Reference String) file, typically used as the universal setup for your circuits +## iOS configuration + +Ensure that the command-line tools path is correctly set in Xcode. You can check this by navigating to Xcode > Settings > Locations. + +![xcode - settings - location](/img/xcode-setting.png) + ## Android configuration Some additional configuration is required for Android. diff --git a/docs/static/img/xcode-setting.png b/docs/static/img/xcode-setting.png new file mode 100644 index 0000000000000000000000000000000000000000..eabbf4f852d5ac5d9d73b11839693cca2408543a GIT binary patch literal 126738 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 I(1UUOALLPS{r~^~ literal 0 HcmV?d00001 diff --git a/docs/versioned_docs/version-0.1.0/mopro-wasm.md b/docs/versioned_docs/version-0.1.0/mopro-wasm.md new file mode 100644 index 00000000..8510b213 --- /dev/null +++ b/docs/versioned_docs/version-0.1.0/mopro-wasm.md @@ -0,0 +1,43 @@ +# mopro-wasm + +The mopro-wasm module enables the compilation of WASM code using `wasm-pack` for supported proving systems. + +**Note:** Currently, only the WASM module for Halo2 can be generated in mopro-wasm. Support for additional proving systems may be added in the future. + +This module supports multithreading in WASM through the use of `wasm-bindgen-rayon`. + +## Development + +### Prerequisites + +1. Install Rust and wasm-pack: + + Ensure you have Rust installed, and install wasm-pack for building and testing WASM modules: + + ```bash + curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh + ``` + +2. Install chrome and chromedriver(for testing): + + Both chrome and chromedriver must be installed, and their versions must match. + + Please refer to [Get started with ChromeDriver](https://developer.chrome.com/docs/chromedriver/get-started) + +### Building + +To compile the WASM module for all supported backends-"plonk," "hyperplonk," and "gemini", run the following command: + +```bash +wasm-pack build --target web -- --all-features +``` + +This commands output files into the **pkg** directory, includes the generated WASM file, JavaScript bindings, and metadata required for integration with web applications. + +### Testing + +Run the fibonacci circuit tests for all the backends in the browser in headless mode. + +```bash +wasm-pack test --chrome --headless -- --all-features +``` \ No newline at end of file diff --git a/docs/versioned_sidebars/version-0.1.0-sidebars.json b/docs/versioned_sidebars/version-0.1.0-sidebars.json index 4b285709..7b14df92 100644 --- a/docs/versioned_sidebars/version-0.1.0-sidebars.json +++ b/docs/versioned_sidebars/version-0.1.0-sidebars.json @@ -41,6 +41,11 @@ "label": "Mopro FFI", "id": "mopro-ffi" }, + { + "type": "doc", + "label": "Mopro WASM", + "id": "mopro-wasm" + }, { "type": "doc", "label": "Performance and Benchmarks", @@ -57,4 +62,4 @@ "id": "FAQ" } ] -} +} \ No newline at end of file From fd78b72cd12614407f128f1e5992c63625ead69b Mon Sep 17 00:00:00 2001 From: sifnoc Date: Thu, 9 Jan 2025 13:33:26 +0000 Subject: [PATCH 2/7] docs: Updated adding new circuit for mopro-wasm --- docs/docs/prerequisites.md | 1 + docs/docs/setup/web-wasm-setup.md | 72 ++++++++++++++++++++++++++++++- 2 files changed, 72 insertions(+), 1 deletion(-) diff --git a/docs/docs/prerequisites.md b/docs/docs/prerequisites.md index 0fc6f47f..f8abf21f 100644 --- a/docs/docs/prerequisites.md +++ b/docs/docs/prerequisites.md @@ -14,6 +14,7 @@ Depending on what platforms and adapters you use, there are several prerequisite - Android - [Android Studio](https://developer.android.com/studio) - Also see [configuration](#android-configuration) below + - [JDK(Java Development Kit)](https://www.oracle.com/java/technologies/downloads) - Web(WASM) - [wasm-pack](https://rustwasm.github.io/wasm-pack/installer/) - [Download Chrome/ChromeDriver](https://googlechromelabs.github.io/chrome-for-testing/) diff --git a/docs/docs/setup/web-wasm-setup.md b/docs/docs/setup/web-wasm-setup.md index ff00a1b4..7575c833 100644 --- a/docs/docs/setup/web-wasm-setup.md +++ b/docs/docs/setup/web-wasm-setup.md @@ -4,7 +4,7 @@ This tutorial will show you how to build static library with Halo2 adapter for w Before proceeding, ensure that **Rust**, **Wasm-Pack** and **Chrome** are installed. Refer to the [Prerequisites](/docs/prerequisites). -### Proving from Web Browser +## Proving from Web Browser This web test page requires three Wasm circuits: `halo2-plonk-fibonacci`, `halo2-hyperplonk-fibonacci`, and `halo2-gemini-fibonacci`. @@ -28,3 +28,73 @@ For more details on building and integrating these circuits, refer to [`mopro-wa Open a web browser and visit the test page at the default url: `http://localhost:3000`. Check the results displayed in the browser console or user interface. + + +## Integrating a New Circuit Implementation + +This section assumes the existence of a user-defined circuit implementation based on the [PSE Halo2](https://github.com/privacy-scaling-explorations/halo2). + +Note that there are multiple Halo2 implementations (e.g., Zcash, PSE, Axiom). Mopro primarily supports the [PSE Halo2](https://github.com/privacy-scaling-explorations/halo2), which is a Plonk backend and works well with [wasm-bindgen-rayon](https://github.com/RReverser/wasm-bindgen-rayon). Refer to the [README](https://github.com/zkmopro/mopro/tree/main/mopro-wasm#introduction-to-wasm-compilation-with-halo2) of mopro-wasm for information about compatibility between Halo2 and Wasm. + +Follow these steps to update and build the user-defined circuit implementation for Wasm: + +1. **Update `Cargo.toml` in 'mopro-wasm'** + + The customized circuit crate should be added as a dependency manually, as illustrated below: + + ```toml + [dependencies] + ... + gemini-fibonacci = { package = "gemini-fibonacci", git = "https://github.com/sifnoc/plonkish-fibonacci-sample.git", optional = true } + my-halo2-circuit = { ... } + ``` + +2. **Create Wrapper Functions for Generate/Verify proof method**: + + To compile Wasm code with the circuit, wrapper functions for generating and verifying proof methods in the user-defined circuit implementation must be created in `mopro-wasm/src/lib.rs`, using the example structure provided below: + + ```rust + use my_halo2_circuit; + + #[wasm_bindgen] + pub fn generate_proof(input: JsValue) -> Result { + // function implementations with `my-halo2-circuit` + let proof = my_halo2_circuit::generate_proof(parsed_input); + to_value(...) + } + + #[wasm_bindgen] + pub fn verify_proof(proof: JsValue, public_inputs: JsValue) -> Result { + // function implementations with `my-halo2-circuit` + let result = my_halo2_circuit::verify_proof(parsed_proof, parsed_public_input); + to_value(...) + } + ``` + +3. **Build the Wasm Package** + + The following command builds the wasm package in "mopro-wasm": + + ```shell + mopro-wasm $ wasm-pack build --target web --out-name my-halo2-circuit + ``` + + The generated wasm files will be located in the "pkg" folder. Refer to the [**wasm-pack**](https://rustwasm.github.io/wasm-pack/book/) documentation for more details. + + +4. **Integrate the Wasm Code**: + + The wasm code can be imported and used in a web application, as illustrated below: + + ```javascript + const mopro_wasm = await import('./pkg/my-halo2-circuit.js'); + await mopro_wasm.default(); + await mopro_wasm.initThreadPool(navigator.hardwareConcurrency); + + async function generateProof (input) { + const proof = await mopro_wasm.generate_proof(input); + console.log(proof); + } + ``` + + Initializing with `initThreadPool` is necessary to enable multi-threading n WebAssembly within the browser. \ No newline at end of file From 37f5b74c8fc0197e9fd53c68c9a7d7723ee44ad3 Mon Sep 17 00:00:00 2001 From: sifnoc Date: Mon, 13 Jan 2025 13:16:32 +0000 Subject: [PATCH 3/7] docs: Updated setup pages with using mopro cli instead of based on 'Rust setup' page --- docs/docs/getting-started.md | 10 +- docs/docs/prerequisites.md | 2 +- docs/docs/setup/android-setup.md | 4 +- docs/docs/setup/flutter-setup.md | 2 +- docs/docs/setup/ios-setup.md | 4 +- docs/docs/setup/react-native-setup.md | 64 ++++++++---- docs/docs/setup/rust-setup.md | 137 +++++++++++++++++++++++-- docs/docs/setup/web-wasm-setup.md | 141 ++++++++++++++------------ docs/sidebars.ts | 4 +- 9 files changed, 261 insertions(+), 107 deletions(-) diff --git a/docs/docs/getting-started.md b/docs/docs/getting-started.md index ad72bb3e..ee4797f4 100644 --- a/docs/docs/getting-started.md +++ b/docs/docs/getting-started.md @@ -1,6 +1,6 @@ # Getting started -This tutorial guides you through building a static library with the Circom/Halo2 adapter for Android and iOS and creating example templates for mobile development. +This tutorial guides you through building a static library with the Circom/Halo2 adapter for Android, iOS and Web and creating example templates for mobile development. ## 0. Prerequisites @@ -28,7 +28,7 @@ mopro init ## 3. Build bindings Navigate to your project directory. (e.g. `cd mopro-example-app`)
-Build bindings for specific targets (iOS, Android). +Build bindings for specific targets (iOS, Android, Web). ```sh mopro build @@ -58,7 +58,9 @@ For iOS: open ios/MoproApp.xcodeproj ``` -For Android +For Android: ```sh open android -a Android\ Studio -``` \ No newline at end of file +``` + +For Web: diff --git a/docs/docs/prerequisites.md b/docs/docs/prerequisites.md index f8abf21f..3d890c88 100644 --- a/docs/docs/prerequisites.md +++ b/docs/docs/prerequisites.md @@ -13,8 +13,8 @@ Depending on what platforms and adapters you use, there are several prerequisite - [Xcode](https://developer.apple.com/xcode/) - Android - [Android Studio](https://developer.android.com/studio) - - Also see [configuration](#android-configuration) below - [JDK(Java Development Kit)](https://www.oracle.com/java/technologies/downloads) + - Also see [configuration](#android-configuration) below - Web(WASM) - [wasm-pack](https://rustwasm.github.io/wasm-pack/installer/) - [Download Chrome/ChromeDriver](https://googlechromelabs.github.io/chrome-for-testing/) diff --git a/docs/docs/setup/android-setup.md b/docs/docs/setup/android-setup.md index 5737f3fc..5cbe74a5 100644 --- a/docs/docs/setup/android-setup.md +++ b/docs/docs/setup/android-setup.md @@ -1,6 +1,8 @@ # Android Setup -After you've completed the [Rust setup](docs/setup/rust-setup.md) you should be able to run `cargo run --bin android`. This will create a new folder called `MoproAndroidBindings`. It should look like the structure +Before starting, ensure you have completed ["Getting Started - 3. Mopro build"](/docs/getting-started.md#3-build-bindings) and selected the android platform during the build process. This step uses the mopro cli to generate the required bindings for your android project. + +After successfully completing the build, a folder named **MoproAndroidBindings** will appear in your project directory. The structure of this folder should look like this: ```sh MoproAndroidBindings diff --git a/docs/docs/setup/flutter-setup.md b/docs/docs/setup/flutter-setup.md index f403e625..124a8d7d 100644 --- a/docs/docs/setup/flutter-setup.md +++ b/docs/docs/setup/flutter-setup.md @@ -1,6 +1,6 @@ # Flutter Setup -After completing the [Rust setup](rust-setup.md) and setting up either [iOS setup](ios-setup.md) or [Android setup](android-setup.md), you're ready to create a cross-platform project using [Flutter](https://flutter.dev/).
+Using ["Getting Started - 3. Mopro build"](/docs/getting-started.md#3-build-bindings) guide, you can generate the "MoproAndroidBindings" and "MoproIOSBindings" for the ios and android platforms in your project folder, you're ready to create a cross-platform project using [Flutter](https://flutter.dev/).
Flutter is a framework for building natively compiled, multi-platform applications from a single codebase. ## 1. Prerequisites diff --git a/docs/docs/setup/ios-setup.md b/docs/docs/setup/ios-setup.md index 0872aa77..e85d944a 100644 --- a/docs/docs/setup/ios-setup.md +++ b/docs/docs/setup/ios-setup.md @@ -1,7 +1,9 @@ # iOS Setup -Once you've completed the [Rust setup](docs/setup/rust-setup.md) you should be able to run `cargo run --bin ios`. This will create a new folder called `MoproiOSBindings`. Inside this folder there should be a file named `mopro.swift` and a folder named `MoproBindings.xcframework`. +Before starting, ensure you have completed ["Getting Started - 3. Mopro build"](/docs/getting-started.md#3-build-bindings) with selecting **iOS** platform. This step enables you to use the mopro cli to generate the required bindings for your iOS project. + +Once the iOS bindings have been built successfully, you will find a folder named **MoproiOSBindings** in your project directory. Inside **MoproiOSBindings** folder there should be a file named `mopro.swift` and a folder named `MoproBindings.xcframework`. ## Demo video of this tutorial diff --git a/docs/docs/setup/react-native-setup.md b/docs/docs/setup/react-native-setup.md index ff9f25c5..122bb715 100644 --- a/docs/docs/setup/react-native-setup.md +++ b/docs/docs/setup/react-native-setup.md @@ -1,6 +1,7 @@ # React Native Setup -After completing the [Rust setup](rust-setup.md) and setting up either [iOS setup](ios-setup.md) or [Android setup](android-setup.md), you're ready to create a cross-platform project using [React Native](https://reactnative.dev/).
+Using ["Getting Started - 3. Mopro build"](/docs/getting-started.md#3-build-bindings) guide, you can generate the "MoproAndroidBindings" and "MoproIOSBindings" for the ios and android platforms in your project folder. These bindings allow you to create a cross-platform project using [React Native](https://reactnative.dev/).
+ React Native is a _JavaScript_ framework that enables developers to build native apps for multiple platforms with a single codebase. In this tutorial, you will learn how to create a native Mopro module on both Android and iOS simulators.
@@ -10,9 +11,30 @@ In this tutorial, you will learn how to create a native Mopro module on both And Second Image -You have 2 options to get started with a mopro React Native project: +You have 3 options to get started with a mopro React Native project: + +## Option 1: Use Mopro Cli + +The easiest way to set up your project is by using the mopro cli **create** command.
This command helps you quickly add templates, similar to the next option, but with fewer manual steps. + +```sh +mopro-example-app $ mopro create +``` + +Assuming you’ve successfully built the **ios** and **android** bindings: `MoproAndroidBindings` and `MoproIOSBindings` in your project folder, the mopro cli stored some parameters into the `Config.toml` file and reads them during the create command. It will also allow you to select the **react-native** template, as shown below: + +``` +? Create template › + ios + android + web - Require binding + flutter +❯ react-native +``` + +## Option 2: Clone the Repository and Import the Bindings -### Option 1: Clone the Repository and Import the Bindings +This option is a more manual compared to [Option 1](docs/react-native-setup#option-1-use-mopro-cli). You can clone a pre-configured repository and manually import the generated bindings into your React Native project. 1. Clone the [zkmopro/react-native-app](https://github.com/zkmopro/react-native-app) repository @@ -40,11 +62,11 @@ You have 2 options to get started with a mopro React Native project: 4. Update mopro bindings in [Android](#4-2-include-mopro-bindings-in-the-native-android-module) and [iOS](#51-use-a-framework) native module -### Option 2: Follow the Tutorial and Build a React Native Module +## Option 3: Follow the Tutorial and Build a React Native Module If you prefer a more hands-on approach and wish to understand how everything works, you can follow the tutorial to build a React Native module from scratch. -## 1. Initializing a New React Native Project or Using an Existing One +### 1. Initializing a New React Native Project or Using an Existing One - Getting started with React Native: [Official documentation](https://reactnative.dev/docs/environment-setup) @@ -65,7 +87,7 @@ If you prefer a more hands-on approach and wish to understand how everything wor ``` for Android emulators. -## 2. Creating a Native Module +### 2. Creating a Native Module - Creating a native module by the command @@ -80,7 +102,7 @@ If you prefer a more hands-on approach and wish to understand how everything wor [Wrap third-party native libraries](https://docs.expo.dev/modules/third-party-library/) ::: -## 3. Define an API +### 3. Define an API - Define the types for the native module. Add the following types in the file: @@ -122,9 +144,9 @@ If you prefer a more hands-on approach and wish to understand how everything wor } ``` -## 4. Implement the module on Android +### 4. Implement the module on Android -### 4-1. Add dependency for [jna](https://github.com/java-native-access/jna) in the file `build.gradle`. +#### 4-1. Add dependency for [jna](https://github.com/java-native-access/jna) in the file `build.gradle`. ```kotlin title="/modules/mopro/android/build.gradle" dependencies { @@ -132,7 +154,7 @@ dependencies { } ``` -### 4-2. Include Mopro bindings in the native Android module +#### 4-2. Include Mopro bindings in the native Android module - Get the `MoproAndroidBindings` from `cargo run --bin android`. :::info @@ -165,7 +187,7 @@ dependencies { └── libuniffi_mopro.so ``` -### 4-3. Create convertible types for Javascript library with kotlin. +#### 4-3. Create convertible types for Javascript library with kotlin. It is a better way to represent a JavaScript object with the native type safety. @@ -230,7 +252,7 @@ class Result : Record { Ref: [Records](https://docs.expo.dev/modules/module-api/#records) ::: -### 4-4. Create native module implementation in `MoproModule.kt` +#### 4-4. Create native module implementation in `MoproModule.kt` ```kotlin title="/modules/mopro/android/src/main/java/expo/modules/mopro/MoproModule.kt" package expo.modules.mopro @@ -284,9 +306,9 @@ class MoproModule : Module() { } ``` -## 5. Implement the module on iOS +### 5. Implement the module on iOS -### 5.1 Use a framework +#### 5.1 Use a framework - Get the `MoproiOSBindings` from `cargo run --bin ios`. :::info @@ -302,7 +324,7 @@ class MoproModule : Module() { ... ``` -### 5.2 Create convertible types for Javascript library with swift. +#### 5.2 Create convertible types for Javascript library with swift. - Create a new file called `MoproType.swift` in the following folder: `modules/mopro/ios` @@ -346,7 +368,7 @@ class MoproModule : Module() { } ``` -### 5-3. Create native module implementation in `MoproModule.swift` +#### 5-3. Create native module implementation in `MoproModule.swift` ```swift title="/modules/mopro/ios/MoproModule.swift" import ExpoModulesCore @@ -416,9 +438,9 @@ public class MoproModule: Module { } ``` -## 6. Run the app +### 6. Run the app -### 6.1 Install expo-asset +#### 6.1 Install expo-asset Install `expo-asset` to use assets. @@ -426,7 +448,7 @@ Install `expo-asset` to use assets. npx expo install expo-asset ``` -### 6.2 Check the expo command +#### 6.2 Check the expo command The `android` and `ios` script should be as follows: @@ -443,7 +465,7 @@ The `android` and `ios` script should be as follows: } ``` -### 6.3 Create an example view +#### 6.3 Create an example view This view enables users to generate `multiplier2` proofs and the public signals. @@ -573,7 +595,7 @@ const styles = StyleSheet.create({ }); ``` -### 6.4 Run in simulators +#### 6.4 Run in simulators - **Android** diff --git a/docs/docs/setup/rust-setup.md b/docs/docs/setup/rust-setup.md index 5c84bfad..326d8ea0 100644 --- a/docs/docs/setup/rust-setup.md +++ b/docs/docs/setup/rust-setup.md @@ -1,24 +1,24 @@ -# Rust Setup +# Manual Setup for Android/iOS Bindings -This tutorial will show you how to build static library with Circom adapter for Android and iOS. Later pages show how to integrate into an existing iOS or Android app. +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](/docs/prerequisites). -## Demo video of this tutorial +## Setup Circom-Based rust project + +**Demo video of this tutorial**

-## 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: ```sh -mkdir mopro-example -cd mopro-example +mkdir mopro-example-app +cd mopro-example-app cargo init --lib ``` @@ -26,7 +26,7 @@ This will create a new rust project in the current directory. Now we'll add some ```toml [package] -name = "mopro-example" +name = "mopro-example-app" version = "0.1.0" edition = "2021" @@ -66,7 +66,7 @@ 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: +Now we need to add four rust files. First we'll add a `build.rs` in the main project folder. This file should contain the following: ```rust use std::path::Path; @@ -168,3 +168,122 @@ CONFIGURATION=release cargo run --bin android # Release mode 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](#setup-circom-based-rust-project), start by running the following commands in your terminal: + +```sh +mkdir mopro-example-app +cd mopro-example-app +cargo init --lib +``` + +This will create a new Rust project in the current directory. Next, add the required dependencies to the project. Edit your `Cargo.toml` to match the following: + +```toml +[package] +name = "mopro-example-app" +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" + +# Adapters for different proof systems +[features] +default = ["mopro-ffi/halo2"] + +[dependencies] +mopro-ffi = { git = "https://github.com/zkmopro/mopro.git", branch = "main" } +rust-witness = "0.1.1" +uniffi = { version = "0.28", features = ["cli"] } +num-bigint = "0.4.0" +plonk-fibonacci = { package = "plonk-fibonacci", git = "https://github.com/sifnoc/plonkish-fibonacci-sample.git" } + +[build-dependencies] +mopro-ffi = { git = "https://github.com/zkmopro/mopro.git", branch = "main" } +rust-witness = "0.1.1" +uniffi = { version = "0.28", features = ["build"] } +``` + +Next, copy your SRS and key files into the project folder. For this tutorial, we'll assume you place them in `test-vectors/halo2`. + +:::info +Download example SRS and key files : + +- [plonk_fibonacci_srs.bin](https://github.com/zkmopro/mopro/blob/dfb9b286c63f6b418fe27465796c818996558bf7/test-vectors/halo2/plonk_fibonacci_srs.bin) +- [plonk_fibonacci_pk.bin](https://github.com/zkmopro/mopro/blob/dfb9b286c63f6b418fe27465796c818996558bf7/test-vectors/halo2/plonk_fibonacci_pk.bin) +- [plonk_fibonacci_vk.bin](https://github.com/zkmopro/mopro/blob/dfb9b286c63f6b418fe27465796c818996558bf7/test-vectors/halo2/plonk_fibonacci_vk.bin) + +::: + + +Now, add four rust files, just as in the Circom-based Rust project setup. + +First, add a `build.rs` in the main project folder. This file should contain the following: + +```rust +fn main() { + // This is writing the UDL file which defines the functions exposed + // to your app. We have pre-generated this file for you. + // Feel free to modify it to suit your needs. + let udl_path = Path::new("src/mopro.udl"); + if !udl_path.exists() { + std::fs::write(udl_path, mopro_ffi::app_config::UDL).expect("Failed to write UDL"); + } + // Finally initialize uniffi and build the scaffolding into the + // rust binary + uniffi::generate_scaffolding(udl_path.to_str().unwrap()).unwrap(); +} +``` + +Next, update the `./src/lib.rs` file to look like the following: + +```rust +// Here we're calling a macro exported by uniffi. This macro will +// write some functions and bind them to the uniffi UDL file. +mopro_ffi::app!(); + +mopro_ffi::set_halo2_circuits! { + ("plonk_fibonacci_pk.bin", plonk_fibonacci::prove, "plonk_fibonacci_vk.bin", plonk_fibonacci::verify), +} +``` + +Similar to the Circom-based Rust setup, add `ios.rs` and `android.rs` for binary execution. + +Create the file `src/bin/ios.rs` as shown below: + +```rust +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(); +} +``` + +Create another file `src/bin/android.rs` as shown below: + +```rust +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 + + +```sh +cargo run --bin ios +``` + +or + +```sh +cargo run --bin android +``` diff --git a/docs/docs/setup/web-wasm-setup.md b/docs/docs/setup/web-wasm-setup.md index 7575c833..15fbfa35 100644 --- a/docs/docs/setup/web-wasm-setup.md +++ b/docs/docs/setup/web-wasm-setup.md @@ -1,100 +1,107 @@ # Web(Wasm) setup -This tutorial will show you how to build static library with Halo2 adapter for web browser. +This tutorial will show you how to build static library for web browser. Before proceeding, ensure that **Rust**, **Wasm-Pack** and **Chrome** are installed. Refer to the [Prerequisites](/docs/prerequisites). -## Proving from Web Browser +## Support Halo2 Circuit Implementation -This web test page requires three Wasm circuits: `halo2-plonk-fibonacci`, `halo2-hyperplonk-fibonacci`, and `halo2-gemini-fibonacci`. +This section assumes the existence of a user-defined circuit implementation based on the [PSE Halo2](https://github.com/privacy-scaling-explorations/halo2). -For more details on building and integrating these circuits, refer to [`mopro-wasm/README.md`](https://github.com/zkmopro/mopro/blob/main/mopro-wasm/README.md). +Note that there are multiple Halo2 implementations (e.g., Zcash, PSE, Axiom). Mopro primarily supports the [PSE Halo2](https://github.com/privacy-scaling-explorations/halo2), which is a Plonk backend and works well with [wasm-bindgen-rayon](https://github.com/RReverser/wasm-bindgen-rayon). Refer to the [README](https://github.com/zkmopro/mopro/tree/main/mopro-wasm#introduction-to-wasm-compilation-with-halo2) of mopro-wasm for information about compatibility between Halo2 and Wasm. -1. **Generate the Wasm package**: - Use `wasm-pack` to build the `mopro` Wasm package with all features enabled. Run the following command from the `mopro-wasm` directory: +## Update "mopro-wasm-lib" - ```bash - mopro-wasm $ wasm-pack build --target web --out-dir ../test-e2e/MoproWasmBindings -- --all-features - ``` +Once followed ["3. Mopro build"](/docs/getting-started.md#3-build-bindings) for Web(Wasm) in ["Getting Started"](/docs/getting-started.md) page, there is "mopro-wasm-lib" would be generated when it selected with `web` template. -2. Run the Test Server: - Navigate to the 'test-e2e/web' directory, install dependencies, and start the server with following commands: +The "mopro-wasm-lib" is the place that compile wasm code eventually. So, it should be updated users Halo2 circuit instead of the example circuit implementations: fibonacci circuit with different backends: "plonk", "hyperplonk" and "gemini". - ```bash - test-e2e/web $ yarn && yarn start - ``` +### 1. Modify 'Cargo.toml' in the "mopro-wasm-lib" -3. **Verify the Results**: - Open a web browser and visit the test page at the default url: `http://localhost:3000`. - - Check the results displayed in the browser console or user interface. +The user-defined circuit implmentation crate should be added as a dependency manually, as illustrated below: +```rust +[package] +name = "mopro-wasm-lib" +version = "0.1.0" +edition = "2021" -## Integrating a New Circuit Implementation +[lib] +crate-type = ["rlib", "cdylib"] -This section assumes the existence of a user-defined circuit implementation based on the [PSE Halo2](https://github.com/privacy-scaling-explorations/halo2). +[dependencies] +// mopro-wasm = { git = "https://github.com/zkmopro/mopro",features = [ +// "gemini", +// "hyperplonk", +// "plonk", +// ]} +my-halo2-circuit = { git = "http://github.com/users/my-halo2-circuit.git" } -Note that there are multiple Halo2 implementations (e.g., Zcash, PSE, Axiom). Mopro primarily supports the [PSE Halo2](https://github.com/privacy-scaling-explorations/halo2), which is a Plonk backend and works well with [wasm-bindgen-rayon](https://github.com/RReverser/wasm-bindgen-rayon). Refer to the [README](https://github.com/zkmopro/mopro/tree/main/mopro-wasm#introduction-to-wasm-compilation-with-halo2) of mopro-wasm for information about compatibility between Halo2 and Wasm. +[target.wasm32-unknown-unknown.dependencies] +console_error_panic_hook = "0.1.7" +getrandom = { version = "0.2.15", features = ["js"] } +serde-wasm-bindgen = "0.6.5" +wasm-bindgen = { version = "0.2.95", features = ["serde-serialize"] } +wasm-bindgen-console-logger = "0.1.1" +wasm-bindgen-futures = "0.4.47" +wasm-bindgen-rayon = { version = "1.2.2", features = ["no-bundler"] } +wasm-bindgen-test = "0.3.42" + +``` + +The `mopro-wasm` crate no longer required for compiling users-defined circuit implementation: **"my-halo2-circuit"** in that case. -Follow these steps to update and build the user-defined circuit implementation for Wasm: +```shell +mopro-wasm-lib $ rustup run nightly-2024-07-18 wasm-pack build --target web --out-dir MoproWasmBindings +``` -1. **Update `Cargo.toml` in 'mopro-wasm'** - The customized circuit crate should be added as a dependency manually, as illustrated below: +### 2. Create Wrapper Functions for Generate/Verify proof method - ```toml - [dependencies] - ... - gemini-fibonacci = { package = "gemini-fibonacci", git = "https://github.com/sifnoc/plonkish-fibonacci-sample.git", optional = true } - my-halo2-circuit = { ... } - ``` +To compile Wasm code with the circuit, wrapper functions for generating and verifying proof methods in the user-defined circuit implementation must be created in `mopro-wasm-lib/src/lib.rs`, using the example structure provided below: -2. **Create Wrapper Functions for Generate/Verify proof method**: +```rust +use my_halo2_circuit; - To compile Wasm code with the circuit, wrapper functions for generating and verifying proof methods in the user-defined circuit implementation must be created in `mopro-wasm/src/lib.rs`, using the example structure provided below: +#[wasm_bindgen] +pub fn generate_proof(input: JsValue) -> Result { + // function implementations with `my-halo2-circuit` + let proof = my_halo2_circuit::generate_proof(parsed_input); + to_value(...) +} - ```rust - use my_halo2_circuit; +#[wasm_bindgen] +pub fn verify_proof(proof: JsValue, public_inputs: JsValue) -> Result { + // function implementations with `my-halo2-circuit` + let result = my_halo2_circuit::verify_proof(parsed_proof, parsed_public_input); + to_value(...) +} +``` - #[wasm_bindgen] - pub fn generate_proof(input: JsValue) -> Result { - // function implementations with `my-halo2-circuit` - let proof = my_halo2_circuit::generate_proof(parsed_input); - to_value(...) - } +### 3. Build the Wasm Package - #[wasm_bindgen] - pub fn verify_proof(proof: JsValue, public_inputs: JsValue) -> Result { - // function implementations with `my-halo2-circuit` - let result = my_halo2_circuit::verify_proof(parsed_proof, parsed_public_input); - to_value(...) - } - ``` +The following command builds the wasm package in "mopro-wasm-lib": -3. **Build the Wasm Package** +```shell +mopro-wasm-lib $ wasm-pack build --target web --out-name my-halo2-circuit +``` - The following command builds the wasm package in "mopro-wasm": +The generated wasm files will be located in the "pkg" folder. Refer to the [**wasm-pack**](https://rustwasm.github.io/wasm-pack/book/) documentation for more details. - ```shell - mopro-wasm $ wasm-pack build --target web --out-name my-halo2-circuit - ``` - The generated wasm files will be located in the "pkg" folder. Refer to the [**wasm-pack**](https://rustwasm.github.io/wasm-pack/book/) documentation for more details. +### 4. **Integrate the Wasm Code**: +The wasm code can be imported and used in a web application, as illustrated below: -4. **Integrate the Wasm Code**: - - The wasm code can be imported and used in a web application, as illustrated below: +```javascript +const mopro_wasm = await import('./pkg/my-halo2-circuit.js'); +await mopro_wasm.default(); +await mopro_wasm.initThreadPool(navigator.hardwareConcurrency); - ```javascript - const mopro_wasm = await import('./pkg/my-halo2-circuit.js'); - await mopro_wasm.default(); - await mopro_wasm.initThreadPool(navigator.hardwareConcurrency); +async function generateProof (input) { + const proof = await mopro_wasm.generate_proof(input); + console.log(proof); +} +``` - async function generateProof (input) { - const proof = await mopro_wasm.generate_proof(input); - console.log(proof); - } - ``` - - Initializing with `initThreadPool` is necessary to enable multi-threading n WebAssembly within the browser. \ No newline at end of file +Initializing with `initThreadPool` is necessary to enable multi-threading n WebAssembly within the browser. diff --git a/docs/sidebars.ts b/docs/sidebars.ts index ee2a9627..1a9e153d 100644 --- a/docs/sidebars.ts +++ b/docs/sidebars.ts @@ -21,12 +21,12 @@ const sidebars: SidebarsConfig = { type: 'category', label: 'Setup', items: [ - 'setup/rust-setup', 'setup/ios-setup', 'setup/android-setup', 'setup/web-wasm-setup', 'setup/react-native-setup', - 'setup/flutter-setup' + 'setup/flutter-setup', + 'setup/rust-setup' ] }, { From fcd35729542411acc3891aca4c879727b492b5b6 Mon Sep 17 00:00:00 2001 From: sifnoc Date: Mon, 13 Jan 2025 16:08:24 +0000 Subject: [PATCH 4/7] fix: Using mopro cli for updating circuit for web wasm bindings --- docs/docs/setup/web-wasm-setup.md | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/docs/docs/setup/web-wasm-setup.md b/docs/docs/setup/web-wasm-setup.md index 15fbfa35..a4c9ab2e 100644 --- a/docs/docs/setup/web-wasm-setup.md +++ b/docs/docs/setup/web-wasm-setup.md @@ -51,11 +51,6 @@ wasm-bindgen-test = "0.3.42" The `mopro-wasm` crate no longer required for compiling users-defined circuit implementation: **"my-halo2-circuit"** in that case. -```shell -mopro-wasm-lib $ rustup run nightly-2024-07-18 wasm-pack build --target web --out-dir MoproWasmBindings -``` - - ### 2. Create Wrapper Functions for Generate/Verify proof method To compile Wasm code with the circuit, wrapper functions for generating and verifying proof methods in the user-defined circuit implementation must be created in `mopro-wasm-lib/src/lib.rs`, using the example structure provided below: @@ -78,17 +73,16 @@ pub fn verify_proof(proof: JsValue, public_inputs: JsValue) -> Result Date: Tue, 14 Jan 2025 05:46:43 +0000 Subject: [PATCH 5/7] fix: updated follows review feedback --- docs/docs/setup/flutter-setup.md | 2 +- docs/docs/setup/react-native-setup.md | 6 +++--- docs/docs/setup/rust-setup.md | 2 -- docs/docs/setup/web-wasm-setup.md | 2 +- 4 files changed, 5 insertions(+), 7 deletions(-) diff --git a/docs/docs/setup/flutter-setup.md b/docs/docs/setup/flutter-setup.md index 124a8d7d..3f1485bb 100644 --- a/docs/docs/setup/flutter-setup.md +++ b/docs/docs/setup/flutter-setup.md @@ -1,6 +1,6 @@ # Flutter Setup -Using ["Getting Started - 3. Mopro build"](/docs/getting-started.md#3-build-bindings) guide, you can generate the "MoproAndroidBindings" and "MoproIOSBindings" for the ios and android platforms in your project folder, you're ready to create a cross-platform project using [Flutter](https://flutter.dev/).
+Using ["Getting Started - 3. Mopro build"](/docs/getting-started.md#3-build-bindings) guide, you can generate the "MoproAndroidBindings" and "MoproIOSBindings" for the iOS and android platforms in your project folder, you're ready to create a cross-platform project using [Flutter](https://flutter.dev/).
Flutter is a framework for building natively compiled, multi-platform applications from a single codebase. ## 1. Prerequisites diff --git a/docs/docs/setup/react-native-setup.md b/docs/docs/setup/react-native-setup.md index 122bb715..a198436a 100644 --- a/docs/docs/setup/react-native-setup.md +++ b/docs/docs/setup/react-native-setup.md @@ -1,6 +1,6 @@ # React Native Setup -Using ["Getting Started - 3. Mopro build"](/docs/getting-started.md#3-build-bindings) guide, you can generate the "MoproAndroidBindings" and "MoproIOSBindings" for the ios and android platforms in your project folder. These bindings allow you to create a cross-platform project using [React Native](https://reactnative.dev/).
+Using ["Getting Started - 3. Mopro build"](/docs/getting-started.md#3-build-bindings) guide, you can generate the "MoproAndroidBindings" and "MoproIOSBindings" for the iOS and android platforms in your project folder. These bindings allow you to create a cross-platform project using [React Native](https://reactnative.dev/).
React Native is a _JavaScript_ framework that enables developers to build native apps for multiple platforms with a single codebase. @@ -21,7 +21,7 @@ The easiest way to set up your project is by using the mopro cli **create** comm mopro-example-app $ mopro create ``` -Assuming you’ve successfully built the **ios** and **android** bindings: `MoproAndroidBindings` and `MoproIOSBindings` in your project folder, the mopro cli stored some parameters into the `Config.toml` file and reads them during the create command. It will also allow you to select the **react-native** template, as shown below: +Assuming you’ve successfully built the **iOS** and **android** bindings: `MoproAndroidBindings` and `MoproIOSBindings` in your project folder, the mopro cli stored some parameters into the `Config.toml` file and reads them during the create command. It will also allow you to select the **react-native** template, as shown below: ``` ? Create template › @@ -34,7 +34,7 @@ Assuming you’ve successfully built the **ios** and **android** bindings: `Mopr ## Option 2: Clone the Repository and Import the Bindings -This option is a more manual compared to [Option 1](docs/react-native-setup#option-1-use-mopro-cli). You can clone a pre-configured repository and manually import the generated bindings into your React Native project. +This option is a more manual compared to [Option 1](#option-1-use-mopro-cli). You can clone a pre-configured repository and manually import the generated bindings into your React Native project. 1. Clone the [zkmopro/react-native-app](https://github.com/zkmopro/react-native-app) repository diff --git a/docs/docs/setup/rust-setup.md b/docs/docs/setup/rust-setup.md index 326d8ea0..5e3253b1 100644 --- a/docs/docs/setup/rust-setup.md +++ b/docs/docs/setup/rust-setup.md @@ -199,14 +199,12 @@ default = ["mopro-ffi/halo2"] [dependencies] mopro-ffi = { git = "https://github.com/zkmopro/mopro.git", branch = "main" } -rust-witness = "0.1.1" uniffi = { version = "0.28", features = ["cli"] } num-bigint = "0.4.0" plonk-fibonacci = { package = "plonk-fibonacci", git = "https://github.com/sifnoc/plonkish-fibonacci-sample.git" } [build-dependencies] mopro-ffi = { git = "https://github.com/zkmopro/mopro.git", branch = "main" } -rust-witness = "0.1.1" uniffi = { version = "0.28", features = ["build"] } ``` diff --git a/docs/docs/setup/web-wasm-setup.md b/docs/docs/setup/web-wasm-setup.md index a4c9ab2e..b8e62ab8 100644 --- a/docs/docs/setup/web-wasm-setup.md +++ b/docs/docs/setup/web-wasm-setup.md @@ -88,7 +88,7 @@ mopro-example-app $ mopro build The wasm code can be imported and used in a web application, as illustrated below: ```javascript -const mopro_wasm = await import('./pkg/my-halo2-circuit.js'); +const mopro_wasm = await import('./MoproWasmBindings/mopro_wasm_lib.js'); await mopro_wasm.default(); await mopro_wasm.initThreadPool(navigator.hardwareConcurrency); From 270f9df01bf2e39c6340800b27e8860458ae67c1 Mon Sep 17 00:00:00 2001 From: sifnoc Date: Tue, 14 Jan 2025 05:47:16 +0000 Subject: [PATCH 6/7] docs: updated v0.1.0 version docs with next(latest updates) --- .../version-0.1.0/adapters/halo2.md | 2 +- .../version-0.1.0/getting-started.md | 10 +- docs/versioned_docs/version-0.1.0/intro.md | 1 + .../version-0.1.0/prerequisites.md | 7 + .../version-0.1.0/setup/android-setup.md | 4 +- .../version-0.1.0/setup/flutter-setup.md | 2 +- .../version-0.1.0/setup/ios-setup.md | 4 +- .../version-0.1.0/setup/react-native-setup.md | 64 +++++--- .../version-0.1.0/setup/rust-setup.md | 147 ++++++++++++++++-- .../version-0.1.0/setup/web-wasm-setup.md | 109 ++++++++++--- 10 files changed, 290 insertions(+), 60 deletions(-) diff --git a/docs/versioned_docs/version-0.1.0/adapters/halo2.md b/docs/versioned_docs/version-0.1.0/adapters/halo2.md index 96f358a5..a35418e6 100644 --- a/docs/versioned_docs/version-0.1.0/adapters/halo2.md +++ b/docs/versioned_docs/version-0.1.0/adapters/halo2.md @@ -87,7 +87,7 @@ fn get_halo2_proving_circuit(circuit: &str) -> Result fn get_halo2_verifying_circuit(circuit: &str) -> Result { match circuit { - "fibonacci_vk.bin" => Ok(plonk_fibonacci::verify), + "plonk_fibonacci_vk.bin" => Ok(plonk_fibonacci::verify), _ => Err(MoproError::CircuitNotFound), } } diff --git a/docs/versioned_docs/version-0.1.0/getting-started.md b/docs/versioned_docs/version-0.1.0/getting-started.md index ad72bb3e..ee4797f4 100644 --- a/docs/versioned_docs/version-0.1.0/getting-started.md +++ b/docs/versioned_docs/version-0.1.0/getting-started.md @@ -1,6 +1,6 @@ # Getting started -This tutorial guides you through building a static library with the Circom/Halo2 adapter for Android and iOS and creating example templates for mobile development. +This tutorial guides you through building a static library with the Circom/Halo2 adapter for Android, iOS and Web and creating example templates for mobile development. ## 0. Prerequisites @@ -28,7 +28,7 @@ mopro init ## 3. Build bindings Navigate to your project directory. (e.g. `cd mopro-example-app`)
-Build bindings for specific targets (iOS, Android). +Build bindings for specific targets (iOS, Android, Web). ```sh mopro build @@ -58,7 +58,9 @@ For iOS: open ios/MoproApp.xcodeproj ``` -For Android +For Android: ```sh open android -a Android\ Studio -``` \ No newline at end of file +``` + +For Web: diff --git a/docs/versioned_docs/version-0.1.0/intro.md b/docs/versioned_docs/version-0.1.0/intro.md index a22d2242..1b4d5a0b 100644 --- a/docs/versioned_docs/version-0.1.0/intro.md +++ b/docs/versioned_docs/version-0.1.0/intro.md @@ -21,6 +21,7 @@ Mopro consists of a set of libraries and utilities. The following subprojects ar Primary libraries and utilities of interest: - `mopro-ffi` - main package, exposes macros for configuring and building projects. +- `mopro-wasm` - enables the compilation of Halo2 circuits into wasm modules. - `test-e2e` - example implementation of mopro in Android and iOS apps, used for testing. Secondary subprojects: diff --git a/docs/versioned_docs/version-0.1.0/prerequisites.md b/docs/versioned_docs/version-0.1.0/prerequisites.md index 31ed65cc..3d890c88 100644 --- a/docs/versioned_docs/version-0.1.0/prerequisites.md +++ b/docs/versioned_docs/version-0.1.0/prerequisites.md @@ -13,6 +13,7 @@ Depending on what platforms and adapters you use, there are several prerequisite - [Xcode](https://developer.apple.com/xcode/) - Android - [Android Studio](https://developer.android.com/studio) + - [JDK(Java Development Kit)](https://www.oracle.com/java/technologies/downloads) - Also see [configuration](#android-configuration) below - Web(WASM) - [wasm-pack](https://rustwasm.github.io/wasm-pack/installer/) @@ -22,6 +23,12 @@ Depending on what platforms and adapters you use, there are several prerequisite - Halo2 - Pre-generated SRS (Structured Reference String) file, typically used as the universal setup for your circuits +## iOS configuration + +Ensure that the command-line tools path is correctly set in Xcode. You can check this by navigating to Xcode > Settings > Locations. + +![xcode - settings - location](/img/xcode-setting.png) + ## Android configuration Some additional configuration is required for Android. diff --git a/docs/versioned_docs/version-0.1.0/setup/android-setup.md b/docs/versioned_docs/version-0.1.0/setup/android-setup.md index 5737f3fc..5cbe74a5 100644 --- a/docs/versioned_docs/version-0.1.0/setup/android-setup.md +++ b/docs/versioned_docs/version-0.1.0/setup/android-setup.md @@ -1,6 +1,8 @@ # Android Setup -After you've completed the [Rust setup](docs/setup/rust-setup.md) you should be able to run `cargo run --bin android`. This will create a new folder called `MoproAndroidBindings`. It should look like the structure +Before starting, ensure you have completed ["Getting Started - 3. Mopro build"](/docs/getting-started.md#3-build-bindings) and selected the android platform during the build process. This step uses the mopro cli to generate the required bindings for your android project. + +After successfully completing the build, a folder named **MoproAndroidBindings** will appear in your project directory. The structure of this folder should look like this: ```sh MoproAndroidBindings diff --git a/docs/versioned_docs/version-0.1.0/setup/flutter-setup.md b/docs/versioned_docs/version-0.1.0/setup/flutter-setup.md index f403e625..3f1485bb 100644 --- a/docs/versioned_docs/version-0.1.0/setup/flutter-setup.md +++ b/docs/versioned_docs/version-0.1.0/setup/flutter-setup.md @@ -1,6 +1,6 @@ # Flutter Setup -After completing the [Rust setup](rust-setup.md) and setting up either [iOS setup](ios-setup.md) or [Android setup](android-setup.md), you're ready to create a cross-platform project using [Flutter](https://flutter.dev/).
+Using ["Getting Started - 3. Mopro build"](/docs/getting-started.md#3-build-bindings) guide, you can generate the "MoproAndroidBindings" and "MoproIOSBindings" for the iOS and android platforms in your project folder, you're ready to create a cross-platform project using [Flutter](https://flutter.dev/).
Flutter is a framework for building natively compiled, multi-platform applications from a single codebase. ## 1. Prerequisites diff --git a/docs/versioned_docs/version-0.1.0/setup/ios-setup.md b/docs/versioned_docs/version-0.1.0/setup/ios-setup.md index 0872aa77..e85d944a 100644 --- a/docs/versioned_docs/version-0.1.0/setup/ios-setup.md +++ b/docs/versioned_docs/version-0.1.0/setup/ios-setup.md @@ -1,7 +1,9 @@ # iOS Setup -Once you've completed the [Rust setup](docs/setup/rust-setup.md) you should be able to run `cargo run --bin ios`. This will create a new folder called `MoproiOSBindings`. Inside this folder there should be a file named `mopro.swift` and a folder named `MoproBindings.xcframework`. +Before starting, ensure you have completed ["Getting Started - 3. Mopro build"](/docs/getting-started.md#3-build-bindings) with selecting **iOS** platform. This step enables you to use the mopro cli to generate the required bindings for your iOS project. + +Once the iOS bindings have been built successfully, you will find a folder named **MoproiOSBindings** in your project directory. Inside **MoproiOSBindings** folder there should be a file named `mopro.swift` and a folder named `MoproBindings.xcframework`. ## Demo video of this tutorial diff --git a/docs/versioned_docs/version-0.1.0/setup/react-native-setup.md b/docs/versioned_docs/version-0.1.0/setup/react-native-setup.md index ff9f25c5..a198436a 100644 --- a/docs/versioned_docs/version-0.1.0/setup/react-native-setup.md +++ b/docs/versioned_docs/version-0.1.0/setup/react-native-setup.md @@ -1,6 +1,7 @@ # React Native Setup -After completing the [Rust setup](rust-setup.md) and setting up either [iOS setup](ios-setup.md) or [Android setup](android-setup.md), you're ready to create a cross-platform project using [React Native](https://reactnative.dev/).
+Using ["Getting Started - 3. Mopro build"](/docs/getting-started.md#3-build-bindings) guide, you can generate the "MoproAndroidBindings" and "MoproIOSBindings" for the iOS and android platforms in your project folder. These bindings allow you to create a cross-platform project using [React Native](https://reactnative.dev/).
+ React Native is a _JavaScript_ framework that enables developers to build native apps for multiple platforms with a single codebase. In this tutorial, you will learn how to create a native Mopro module on both Android and iOS simulators.
@@ -10,9 +11,30 @@ In this tutorial, you will learn how to create a native Mopro module on both And Second Image -You have 2 options to get started with a mopro React Native project: +You have 3 options to get started with a mopro React Native project: + +## Option 1: Use Mopro Cli + +The easiest way to set up your project is by using the mopro cli **create** command.
This command helps you quickly add templates, similar to the next option, but with fewer manual steps. + +```sh +mopro-example-app $ mopro create +``` + +Assuming you’ve successfully built the **iOS** and **android** bindings: `MoproAndroidBindings` and `MoproIOSBindings` in your project folder, the mopro cli stored some parameters into the `Config.toml` file and reads them during the create command. It will also allow you to select the **react-native** template, as shown below: + +``` +? Create template › + ios + android + web - Require binding + flutter +❯ react-native +``` + +## Option 2: Clone the Repository and Import the Bindings -### Option 1: Clone the Repository and Import the Bindings +This option is a more manual compared to [Option 1](#option-1-use-mopro-cli). You can clone a pre-configured repository and manually import the generated bindings into your React Native project. 1. Clone the [zkmopro/react-native-app](https://github.com/zkmopro/react-native-app) repository @@ -40,11 +62,11 @@ You have 2 options to get started with a mopro React Native project: 4. Update mopro bindings in [Android](#4-2-include-mopro-bindings-in-the-native-android-module) and [iOS](#51-use-a-framework) native module -### Option 2: Follow the Tutorial and Build a React Native Module +## Option 3: Follow the Tutorial and Build a React Native Module If you prefer a more hands-on approach and wish to understand how everything works, you can follow the tutorial to build a React Native module from scratch. -## 1. Initializing a New React Native Project or Using an Existing One +### 1. Initializing a New React Native Project or Using an Existing One - Getting started with React Native: [Official documentation](https://reactnative.dev/docs/environment-setup) @@ -65,7 +87,7 @@ If you prefer a more hands-on approach and wish to understand how everything wor ``` for Android emulators. -## 2. Creating a Native Module +### 2. Creating a Native Module - Creating a native module by the command @@ -80,7 +102,7 @@ If you prefer a more hands-on approach and wish to understand how everything wor [Wrap third-party native libraries](https://docs.expo.dev/modules/third-party-library/) ::: -## 3. Define an API +### 3. Define an API - Define the types for the native module. Add the following types in the file: @@ -122,9 +144,9 @@ If you prefer a more hands-on approach and wish to understand how everything wor } ``` -## 4. Implement the module on Android +### 4. Implement the module on Android -### 4-1. Add dependency for [jna](https://github.com/java-native-access/jna) in the file `build.gradle`. +#### 4-1. Add dependency for [jna](https://github.com/java-native-access/jna) in the file `build.gradle`. ```kotlin title="/modules/mopro/android/build.gradle" dependencies { @@ -132,7 +154,7 @@ dependencies { } ``` -### 4-2. Include Mopro bindings in the native Android module +#### 4-2. Include Mopro bindings in the native Android module - Get the `MoproAndroidBindings` from `cargo run --bin android`. :::info @@ -165,7 +187,7 @@ dependencies { └── libuniffi_mopro.so ``` -### 4-3. Create convertible types for Javascript library with kotlin. +#### 4-3. Create convertible types for Javascript library with kotlin. It is a better way to represent a JavaScript object with the native type safety. @@ -230,7 +252,7 @@ class Result : Record { Ref: [Records](https://docs.expo.dev/modules/module-api/#records) ::: -### 4-4. Create native module implementation in `MoproModule.kt` +#### 4-4. Create native module implementation in `MoproModule.kt` ```kotlin title="/modules/mopro/android/src/main/java/expo/modules/mopro/MoproModule.kt" package expo.modules.mopro @@ -284,9 +306,9 @@ class MoproModule : Module() { } ``` -## 5. Implement the module on iOS +### 5. Implement the module on iOS -### 5.1 Use a framework +#### 5.1 Use a framework - Get the `MoproiOSBindings` from `cargo run --bin ios`. :::info @@ -302,7 +324,7 @@ class MoproModule : Module() { ... ``` -### 5.2 Create convertible types for Javascript library with swift. +#### 5.2 Create convertible types for Javascript library with swift. - Create a new file called `MoproType.swift` in the following folder: `modules/mopro/ios` @@ -346,7 +368,7 @@ class MoproModule : Module() { } ``` -### 5-3. Create native module implementation in `MoproModule.swift` +#### 5-3. Create native module implementation in `MoproModule.swift` ```swift title="/modules/mopro/ios/MoproModule.swift" import ExpoModulesCore @@ -416,9 +438,9 @@ public class MoproModule: Module { } ``` -## 6. Run the app +### 6. Run the app -### 6.1 Install expo-asset +#### 6.1 Install expo-asset Install `expo-asset` to use assets. @@ -426,7 +448,7 @@ Install `expo-asset` to use assets. npx expo install expo-asset ``` -### 6.2 Check the expo command +#### 6.2 Check the expo command The `android` and `ios` script should be as follows: @@ -443,7 +465,7 @@ The `android` and `ios` script should be as follows: } ``` -### 6.3 Create an example view +#### 6.3 Create an example view This view enables users to generate `multiplier2` proofs and the public signals. @@ -573,7 +595,7 @@ const styles = StyleSheet.create({ }); ``` -### 6.4 Run in simulators +#### 6.4 Run in simulators - **Android** diff --git a/docs/versioned_docs/version-0.1.0/setup/rust-setup.md b/docs/versioned_docs/version-0.1.0/setup/rust-setup.md index 25b5505c..5e3253b1 100644 --- a/docs/versioned_docs/version-0.1.0/setup/rust-setup.md +++ b/docs/versioned_docs/version-0.1.0/setup/rust-setup.md @@ -1,24 +1,24 @@ -# Rust Setup +# Manual Setup for Android/iOS Bindings -This tutorial will show you how to build static library with Circom adapter for Android and iOS. Later pages show how to integrate into an existing iOS or Android app. +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](/docs/prerequisites). -## Demo video of this tutorial +## Setup Circom-Based rust project + +**Demo video of this tutorial**

-## 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: ```sh -mkdir mopro-example -cd mopro-example +mkdir mopro-example-app +cd mopro-example-app cargo init --lib ``` @@ -26,7 +26,7 @@ This will create a new rust project in the current directory. Now we'll add some ```toml [package] -name = "mopro-example" +name = "mopro-example-app" version = "0.1.0" edition = "2021" @@ -61,14 +61,15 @@ Now you should copy your wasm and zkey files somewhere in the project folder. Fo :::info Download example multiplier2 wasm and zkey here: -- [multiplier2.wasm](https://github.com/zkmopro/mopro/raw/ae88356e680ac4d785183267d6147167fabe071c/test-vectors/circom/multiplier2.wasm) -- [multiplier2_final.zkey](https://github.com/zkmopro/mopro/raw/ae88356e680ac4d785183267d6147167fabe071c/test-vectors/circom/multiplier2_final.zkey) +- [multiplier2.wasm](https://github.com/zkmopro/mopro/raw/ae88356e680ac4d785183267d6147167fabe071c/test-vectors/circom/multiplier2.wasm) +- [multiplier2_final.zkey](https://github.com/zkmopro/mopro/raw/ae88356e680ac4d785183267d6147167fabe071c/test-vectors/circom/multiplier2_final.zkey) ::: -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: +Now we need to add four rust files. First we'll add a `build.rs` in the main project folder. This file should contain the following: ```rust +use std::path::Path; fn main() { // We're going to transpile the wasm witness generators to C // Change this to where you put your zkeys and wasm files @@ -76,10 +77,13 @@ fn main() { // 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"); + let udl_path = Path::new("src/mopro.udl"); + if !udl_path.exists() { + std::fs::write(udl_path, 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(); + uniffi::generate_scaffolding(udl_path.to_str().unwrap()).unwrap(); } ``` @@ -164,3 +168,120 @@ CONFIGURATION=release cargo run --bin android # Release mode 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](#setup-circom-based-rust-project), start by running the following commands in your terminal: + +```sh +mkdir mopro-example-app +cd mopro-example-app +cargo init --lib +``` + +This will create a new Rust project in the current directory. Next, add the required dependencies to the project. Edit your `Cargo.toml` to match the following: + +```toml +[package] +name = "mopro-example-app" +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" + +# Adapters for different proof systems +[features] +default = ["mopro-ffi/halo2"] + +[dependencies] +mopro-ffi = { git = "https://github.com/zkmopro/mopro.git", branch = "main" } +uniffi = { version = "0.28", features = ["cli"] } +num-bigint = "0.4.0" +plonk-fibonacci = { package = "plonk-fibonacci", git = "https://github.com/sifnoc/plonkish-fibonacci-sample.git" } + +[build-dependencies] +mopro-ffi = { git = "https://github.com/zkmopro/mopro.git", branch = "main" } +uniffi = { version = "0.28", features = ["build"] } +``` + +Next, copy your SRS and key files into the project folder. For this tutorial, we'll assume you place them in `test-vectors/halo2`. + +:::info +Download example SRS and key files : + +- [plonk_fibonacci_srs.bin](https://github.com/zkmopro/mopro/blob/dfb9b286c63f6b418fe27465796c818996558bf7/test-vectors/halo2/plonk_fibonacci_srs.bin) +- [plonk_fibonacci_pk.bin](https://github.com/zkmopro/mopro/blob/dfb9b286c63f6b418fe27465796c818996558bf7/test-vectors/halo2/plonk_fibonacci_pk.bin) +- [plonk_fibonacci_vk.bin](https://github.com/zkmopro/mopro/blob/dfb9b286c63f6b418fe27465796c818996558bf7/test-vectors/halo2/plonk_fibonacci_vk.bin) + +::: + + +Now, add four rust files, just as in the Circom-based Rust project setup. + +First, add a `build.rs` in the main project folder. This file should contain the following: + +```rust +fn main() { + // This is writing the UDL file which defines the functions exposed + // to your app. We have pre-generated this file for you. + // Feel free to modify it to suit your needs. + let udl_path = Path::new("src/mopro.udl"); + if !udl_path.exists() { + std::fs::write(udl_path, mopro_ffi::app_config::UDL).expect("Failed to write UDL"); + } + // Finally initialize uniffi and build the scaffolding into the + // rust binary + uniffi::generate_scaffolding(udl_path.to_str().unwrap()).unwrap(); +} +``` + +Next, update the `./src/lib.rs` file to look like the following: + +```rust +// Here we're calling a macro exported by uniffi. This macro will +// write some functions and bind them to the uniffi UDL file. +mopro_ffi::app!(); + +mopro_ffi::set_halo2_circuits! { + ("plonk_fibonacci_pk.bin", plonk_fibonacci::prove, "plonk_fibonacci_vk.bin", plonk_fibonacci::verify), +} +``` + +Similar to the Circom-based Rust setup, add `ios.rs` and `android.rs` for binary execution. + +Create the file `src/bin/ios.rs` as shown below: + +```rust +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(); +} +``` + +Create another file `src/bin/android.rs` as shown below: + +```rust +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 + + +```sh +cargo run --bin ios +``` + +or + +```sh +cargo run --bin android +``` diff --git a/docs/versioned_docs/version-0.1.0/setup/web-wasm-setup.md b/docs/versioned_docs/version-0.1.0/setup/web-wasm-setup.md index ff00a1b4..b8e62ab8 100644 --- a/docs/versioned_docs/version-0.1.0/setup/web-wasm-setup.md +++ b/docs/versioned_docs/version-0.1.0/setup/web-wasm-setup.md @@ -1,30 +1,103 @@ # Web(Wasm) setup -This tutorial will show you how to build static library with Halo2 adapter for web browser. +This tutorial will show you how to build static library for web browser. Before proceeding, ensure that **Rust**, **Wasm-Pack** and **Chrome** are installed. Refer to the [Prerequisites](/docs/prerequisites). -### Proving from Web Browser +## Support Halo2 Circuit Implementation -This web test page requires three Wasm circuits: `halo2-plonk-fibonacci`, `halo2-hyperplonk-fibonacci`, and `halo2-gemini-fibonacci`. +This section assumes the existence of a user-defined circuit implementation based on the [PSE Halo2](https://github.com/privacy-scaling-explorations/halo2). -For more details on building and integrating these circuits, refer to [`mopro-wasm/README.md`](https://github.com/zkmopro/mopro/blob/main/mopro-wasm/README.md). +Note that there are multiple Halo2 implementations (e.g., Zcash, PSE, Axiom). Mopro primarily supports the [PSE Halo2](https://github.com/privacy-scaling-explorations/halo2), which is a Plonk backend and works well with [wasm-bindgen-rayon](https://github.com/RReverser/wasm-bindgen-rayon). Refer to the [README](https://github.com/zkmopro/mopro/tree/main/mopro-wasm#introduction-to-wasm-compilation-with-halo2) of mopro-wasm for information about compatibility between Halo2 and Wasm. -1. **Generate the Wasm package**: - Use `wasm-pack` to build the `mopro` Wasm package with all features enabled. Run the following command from the `mopro-wasm` directory: +## Update "mopro-wasm-lib" - ```bash - mopro-wasm $ wasm-pack build --target web --out-dir ../test-e2e/MoproWasmBindings -- --all-features - ``` +Once followed ["3. Mopro build"](/docs/getting-started.md#3-build-bindings) for Web(Wasm) in ["Getting Started"](/docs/getting-started.md) page, there is "mopro-wasm-lib" would be generated when it selected with `web` template. -2. Run the Test Server: - Navigate to the 'test-e2e/web' directory, install dependencies, and start the server with following commands: +The "mopro-wasm-lib" is the place that compile wasm code eventually. So, it should be updated users Halo2 circuit instead of the example circuit implementations: fibonacci circuit with different backends: "plonk", "hyperplonk" and "gemini". - ```bash - test-e2e/web $ yarn && yarn start - ``` +### 1. Modify 'Cargo.toml' in the "mopro-wasm-lib" -3. **Verify the Results**: - Open a web browser and visit the test page at the default url: `http://localhost:3000`. - - Check the results displayed in the browser console or user interface. +The user-defined circuit implmentation crate should be added as a dependency manually, as illustrated below: + +```rust +[package] +name = "mopro-wasm-lib" +version = "0.1.0" +edition = "2021" + +[lib] +crate-type = ["rlib", "cdylib"] + +[dependencies] +// mopro-wasm = { git = "https://github.com/zkmopro/mopro",features = [ +// "gemini", +// "hyperplonk", +// "plonk", +// ]} +my-halo2-circuit = { git = "http://github.com/users/my-halo2-circuit.git" } + +[target.wasm32-unknown-unknown.dependencies] +console_error_panic_hook = "0.1.7" +getrandom = { version = "0.2.15", features = ["js"] } +serde-wasm-bindgen = "0.6.5" +wasm-bindgen = { version = "0.2.95", features = ["serde-serialize"] } +wasm-bindgen-console-logger = "0.1.1" +wasm-bindgen-futures = "0.4.47" +wasm-bindgen-rayon = { version = "1.2.2", features = ["no-bundler"] } +wasm-bindgen-test = "0.3.42" + +``` + +The `mopro-wasm` crate no longer required for compiling users-defined circuit implementation: **"my-halo2-circuit"** in that case. + +### 2. Create Wrapper Functions for Generate/Verify proof method + +To compile Wasm code with the circuit, wrapper functions for generating and verifying proof methods in the user-defined circuit implementation must be created in `mopro-wasm-lib/src/lib.rs`, using the example structure provided below: + +```rust +use my_halo2_circuit; + +#[wasm_bindgen] +pub fn generate_proof(input: JsValue) -> Result { + // function implementations with `my-halo2-circuit` + let proof = my_halo2_circuit::generate_proof(parsed_input); + to_value(...) +} + +#[wasm_bindgen] +pub fn verify_proof(proof: JsValue, public_inputs: JsValue) -> Result { + // function implementations with `my-halo2-circuit` + let result = my_halo2_circuit::verify_proof(parsed_proof, parsed_public_input); + to_value(...) +} +``` + +### 3. Build again for web + +To ensure a clean build, remove the existing `MoproWasmBindings` directory in the `mopro-example-app`, which was previously generated with `mopro-wasm-lib`. +Then, execute the `mopro build` command again, selecting the "web" platform in `mopro-example-app`: + +```shell +mopro-example-app $ rm -rf MoproWasmBindings +mopro-example-app $ mopro build +``` + +### 4. **Integrate the Wasm Code**: + +The wasm code can be imported and used in a web application, as illustrated below: + +```javascript +const mopro_wasm = await import('./MoproWasmBindings/mopro_wasm_lib.js'); +await mopro_wasm.default(); +await mopro_wasm.initThreadPool(navigator.hardwareConcurrency); + +async function generateProof (input) { + const proof = await mopro_wasm.generate_proof(input); + console.log(proof); +} +``` + +Initializing with `initThreadPool` is necessary to enable multi-threading n WebAssembly within the browser. + +Note that the web template generated using the `mopro create` command is currently built only for example circuit implementations: `plonk-fibonacci`, `hyperplonk-fibonacci` and `gemini-fibonacci`. User should modify `index.js` and `index.html` manually if want to use the web template with users' circuit implementation, such as `my-halo2-circuit` in this tutorial. \ No newline at end of file From 93f0f4ab3ec4ca946f13df84749906fd3ae0d2e6 Mon Sep 17 00:00:00 2001 From: sifnoc Date: Tue, 14 Jan 2025 05:51:54 +0000 Subject: [PATCH 7/7] fix: sync sidebar updated with latest doc --- docs/versioned_sidebars/version-0.1.0-sidebars.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/versioned_sidebars/version-0.1.0-sidebars.json b/docs/versioned_sidebars/version-0.1.0-sidebars.json index 7b14df92..47552077 100644 --- a/docs/versioned_sidebars/version-0.1.0-sidebars.json +++ b/docs/versioned_sidebars/version-0.1.0-sidebars.json @@ -19,12 +19,12 @@ "type": "category", "label": "Setup", "items": [ - "setup/rust-setup", "setup/ios-setup", "setup/android-setup", "setup/web-wasm-setup", "setup/react-native-setup", - "setup/flutter-setup" + "setup/flutter-setup", + "setup/rust-setup" ] }, {