## Objective & Motivation ### Goal Migrate the management of language bindings (Python, Swift, JS) from [EZKL](https://ezkl.xyz/) to [Mopro](https://zkmopro.org/). ### Why - **Reduced Maintenance:** Lower EZKL’s maintenance overhead. - **Standardization:** Achieve consistent bindings across all platforms. - **Future-proofing:** Simplify expansion to support additional languages (e.g., Kotlin). ### Outcome [Mopro](https://zkmopro.org/) manages all language bindings, enabling [EZKL](https://ezkl.xyz/) to concentrate on its core functionality. ### References - [EZKL GitHub Repository](https://github.com/zkonduit/ezkl) - [Mopro GitHub Repository](https://github.com/zkmopro/mopro) ### Existing Contributions from Mopro Mopro has already made significant contributions to EZKL. For instance, the **EZKL MSM Metal optimization** builds upon work from [Mopro GPU Acceleration](https://github.com/zkmopro/gpu-acceleration). --- ## Current EZKL Bindings [EZKL](https://ezkl.xyz/) is a CLI that not only provides functionality as a standalone binary but also as a multi-platform tool, allowing developers to access to the Verifiable Machine Learning from different platforms. ### Binding Management In addition to the Rust CLI, EZKL manages its bindings via [this module](https://github.com/zkonduit/ezkl/blob/main/src/bindings/mod.rs), which includes: - **Python bindings** (feature-gated as `python-bindings`) - **WASM bindings** (target-gated by `all(target_arch = "wasm32", target_os = "unknown")`) - **Universal bindings** using `uniffi-rs` (currently for Swift, feature-gated as `ios-bindings`) These bindings generate three separate libraries: - **EZKL Python Library** ([piwheels package](https://www.piwheels.org/project/ezkl/)) - **EZKL JavaScript Engine** ([@ezkljs/engine](https://www.npmjs.com/package/@ezkljs/engine) for browser/nodejs) - **EZKL Swift Package** ([ezkl-swift-package](https://github.com/zkonduit/ezkl-swift-package)) Currently, each binding follows its own workflow for building, testing, and publishing, despite sharing substantial underlying logic. Unifying these processes is a key objective. ### iOS Binding Implementation - **Current Approach:** EZKL employs `uniffi-rs` directly rather than delegating to Mopro. - **Testing Workaround:** Due to testing limitations, EZKL had to **fork** `uniffi-rs` ([Forked Uniffi](https://github.com/ElusAegis/uniffi-rs/tree/feat/testing-feature-build-fix)) to accommodate special compilation flags. - **Status:** This workaround remains unresolved in the main `uniffi-rs` repository ([Open Issue](https://github.com/mozilla/uniffi-rs/issues/2269)). ### WASM Binding Implementation - Utilizes `wasm_bindgen` along with additional helper repositories integrated with `wasm_bindgen`. ### Python Binding Implementation - Uses `pyo3` for Rust-Python interoperability along with additional helper repositories. ### Key Differences Between Bindings - **Python bindings:** Accept file paths as input. - **Swift & JavaScript bindings:** Operate directly on file bytes as input. While these differences require some adjustments, the core functionality remains similar, making consolidation feasible. ### Current Challenges - **Complex Maintenance:** Managing separate workflows increases overall complexity. - **Fragmented Processes:** Different workflows for building, testing, and publishing bindings lead to inefficiencies. - **Objective:** Offload binding management to Mopro to simplify EZKL’s repository and streamline maintenance. ## Mopro Integration Plan The first phase of integrating [Mopro](https://zkmopro.org/) aims to abstract away iOS binding management in [EZKL](https://ezkl.xyz/), later extending support to Kotlin and Android, and finally abstracting away Wasm and Python bindings. We begin with iOS because: - The iOS bindings are newly introduced and not widely adopted, making it simpler to migrate. - Significant changes will not disrupt a large user base. - The iOS implementation is well-understood by Artem, as he developed it internally ([PR #846](https://github.com/zkonduit/ezkl/pull/846)). --- ### Current iOS Binding Implementation #### Source Code Integration - **Core Approach:** Uses `uniffi-rs` procedural macros. - **Location:** The exportable functions reside in the **universal** module, annotated with `uniffi::export` and guarded by the `ios-bindings` feature flag ([source link](https://github.com/zkonduit/ezkl/blob/73c813a81d5bc490a1d287addb1a1e2f25d41e60/src/bindings/universal.rs#L65)). - **Setup Scaffolding:** `uniffi::setup_scaffolding!()` is called in `lib.rs`, also behind the `ios-bindings` gate ([source link](https://github.com/zkonduit/ezkl/blob/73c813a81d5bc490a1d287addb1a1e2f25d41e60/src/lib.rs#L169)). #### Changes to the Source Code Ideally, we want to keep the simplicity of `uniffi-rs` while shifting to Mopro-specific macros. For example: ```rust // Current #[uniffi::export] fn example_function(...) { ... } uniffi::setup_scaffolding!(); ``` could become: ```rust // Hypothetical Mopro usage #[mopro::export] fn example_function(...) { ... } mopro::setup!(); ``` Under the hood, Mopro would then determine the appropriate bindings engine. Developers need only import `mopro` and configure `Cargo.toml` to specify the correct library type. --- ### Custom iOS Binding Build Process - **Custom Binary:** EZKL uses a dedicated binary (`ios_gen_bindings.rs`) to generate iOS bindings. - **Multiple References:** The build script references `"EzklCore.swift"`, `"EzklCore.xcframework"`, and `"EzklCoreBindings"` in several places ([example link](https://github.com/zkonduit/ezkl/blob/73c813a81d5bc490a1d287addb1a1e2f25d41e60/src/bin/ios_gen_bindings.rs#L42)). - **Size Constraints:** The `x86_64-apple-ios` target was omitted to keep the final library under 100MB. - **Feature Gating:** The bindings are built with the hardcoded `ios-bindings` feature activated ([Cargo.toml reference](https://github.com/zkonduit/ezkl/blob/73c813a81d5bc490a1d287addb1a1e2f25d41e60/Cargo.toml#L211)). - **Static Library Type:** Specified as `staticlib` in `Cargo.toml`. #### Changes to the Bindings Generation The Mopro CLI can streamline iOS binding generation, removing the need for a separate binary. Below are desired features from Mopro, along with their proposed priority levels: | Feature | Priority | Description | |------------------------------------|---------------|---------------------------------------------------------------------------------------------------------------------| | **Replace Custom Binary Management** | Must | Mopro’s CLI should automate iOS binding generation, removing the need for `ios_gen_bindings.rs`. | | **Library Naming Configuration** | Must / Could | Let users specify the output library name or auto-detect from `Cargo.toml`. | | **Configuration Validation** | Nice to Have | Check for correct crate types and features in `Cargo.toml` and guide users on misconfigurations. | | **Target Selection** | Must | Allow users to specify and build for different target architectures without changing the source (e.g., wasm, swift, kotlin). | | **Feature Selection** | Must | Dynamically pass Mopro features (e.g., `mopro/ios-bindings`) to the Rust code. | | **Swift Intel Mac Option** | Could | Offer an easy toggle to include/exclude `x86_64-apple-ios` for improved file size control. | --- ### Testing iOS Bindings #### Rust-Driven Tests - **Test Framework:** Utilizes `uniffi/bindgen-tests`, gated under the `ios-bindings-test` feature. - **Test Locations:** Found in the [`tests/ios` directory](https://github.com/zkonduit/ezkl/tree/main/tests/ios) and in `ios_integration_tests.rs`. - **Custom `build.rs` for Feature Passing:** - A custom `build.rs` script is required to pass additional features to `uniffi-rs` when building the test bindings. - The script includes: ```rust if cfg!(feature = "ios-bindings-test") { println!("cargo::rustc-env=UNIFFI_CARGO_BUILD_EXTRA_ARGS=--features=ios-bindings --no-default-features"); } ``` - This is necessary because `uniffi-rs` does not natively support configuring features dynamically during test builds. - **Forked `uniffi-rs` Dependency:** - EZKL relies on a fork of `uniffi-rs` to enable feature-configurable tests. - The forked version allows injecting compilation flags that are needed to correctly build and run the tests. - Related discussion: [GitHub issue](https://github.com/mozilla/uniffi-rs/issues/2269). - **Workflow:** Defined in the GitHub Actions file [`rust.yml`](https://github.com/zkonduit/ezkl/blob/73c813a81d5bc490a1d287addb1a1e2f25d41e60/.github/workflows/rust.yml#L812). - ##### Suggested Improvements - **Mopro Build Script:** Internally manage the issue that requried the build script to enable relevant features automatically. - **Reusable GitHub Action:** Offer a standardized approach to running tests for iOS bindings. - **Unified Testing Abstraction:** Standardize test declarations (like in `ios_integration_tests.rs`) across multiple targets. --- ### CI/CD Pipeline for iOS Bindings #### Rust Driven Test Execution - The testing workflow runs in [`rust.yml`](https://github.com/zkonduit/ezkl/blob/73c813a81d5bc490a1d287addb1a1e2f25d41e60/.github/workflows/rust.yml#L812). #### Integration Testing via Sample App - **Process:** A Swift package example ([`ezkl-swift-package/Example`](https://github.com/zkonduit/ezkl-swift-package/tree/main/Example)) is executed on CI. - **Execution:** The app is run as part of the CI job in [`rust.yml`](https://github.com/zkonduit/ezkl/blob/73c813a81d5bc490a1d287addb1a1e2f25d41e60/.github/workflows/rust.yml#L832). - **Potential Mopro Contribution:** Mopro could generalize this approach, simplifying how example apps are run for integration tests. #### Swift Package Management - **Continuous Deployment (CD):** Handled by [`swift-pm.yml`](https://github.com/zkonduit/ezkl/blob/main/.github/workflows/swift-pm.yml), triggered on each release. - **Process Steps:** 1. Clone the Swift package repository. 2. Generate new bindings, replacing existing assets. 3. Run tests within the Swift example project. 4. Commit updates and tag a new release. ##### Potential Mopro Contributions - **Automated Updates:** Provide a mechanism to automatically update dependent repositories after new bindings are generated. - **Standardized Package Management:** Ensure cross-platform consistency in packaging and versioning. - **Enhanced Security:** Improve GitHub token handling so that binding updates can be pushed securely to external repositories. --- ### Future Steps: Expanding Mopro Beyond iOS Once Mopro takes charge of iOS binding management, we can gradually incorporate additional binding processes for Python and WASM. A **unified Mopro CLI** could generate bindings across all targets by inspecting function annotations (e.g., `mopro::export` and `mopro::setup!`). #### Unified CLI Approach ```bash cargo install mopro mopro wasm --package-name Ezkl ``` #### Next Steps 1. **Kotlin Support:** Introduce Kotlin/Android bindings, which should be straightforward once the iOS integration is stable. 2. **Python & WASM Consolidation:** Migrate Python and WASM binding engines to Mopro for further maintenance relief. 3. **Long-Term Maintenance:** With Mopro managing all bindings, EZKL can focus on its core cryptographic and ML functionalities without juggling multiple binding systems. ## Conclusion This proposal has outlined how integrating Mopro into EZKL can streamline multi-platform binding management. By starting with iOS and then extending support to Kotlin, Python, and WASM, we can establish a **unified binding system** that offers: - **Reduced Maintenance Complexity:** Consolidate disparate binding engines and workflows, thereby simplifying EZKL’s codebase. - **Standardized CLI Usage:** Enable a consistent `mopro` command to generate bindings across all supported platforms. - **Automated CI/CD Workflows:** Seamlessly manage package releases with minimal manual intervention. Following this roadmap will allow EZKL to offload binding management to Mopro, freeing resources to focus on its core cryptographic and machine learning functionalities. <!-- --- ## Mopro Integration Plan The first step in integrating [Mopro](https://zkmopro.org/) is to abstract iOS management in [EZKL](https://ezkl.xyz/) and provide additional access to Kotlin and Android deployments. This is the easiest step because: - The iOS bindings were recently added and are not widely used yet, making it easier to migrate. - We can make significant changes without disrupting existing users. - The integration is well understood as the implementation was done internally ([PR #846](https://github.com/zkonduit/ezkl/pull/846)). ### Current iOS Binding Implementation #### Source Code integration - Uses `uniffi-rs` procedural macros. - Contained within the **universal** module, where functions to be exported are annotated with `uniffi::export` and gated under the `ios-bindings` flag ([source](https://github.com/zkonduit/ezkl/blob/73c813a81d5bc490a1d287addb1a1e2f25d41e60/src/bindings/universal.rs#L65)). - `uniffi::setup_scaffolding!()` is invoked in `lib.rs`, also feature-gated under `ios-bindings` ([source](https://github.com/zkonduit/ezkl/blob/73c813a81d5bc490a1d287addb1a1e2f25d41e60/src/lib.rs#L169)). #### Changes to the source code: - Ideally, we would maintain the simplicity of using uniffi, and just replace what we currently do with uniffi-rs with the could be replaced with `mopro::export` and `mopro::setup!()`. under the hood mopro could then decide on the best bindings endine, by waiting for Mopro specific features, such as mopro/ios-bindings and configure the dependencies based on this. So the only thing that you need to import is the `mopro` library and make sure to specify the correct library type in Cargo toml. The rest will be managed under the hood. #### Custom iOS Binding Build Process - EZKL has a custom binary that builds the iOS bindings ([ios_gen_bindings.rs](https://github.com/zkonduit/ezkl/blob/main/src/bin/ios_gen_bindings.rs)). - The binding generation references `"EzklCore.swift"`, `"EzklCore.xcframework"`, and `"EzklCoreBindings"` in multiple locations ([L42](https://github.com/zkonduit/ezkl/blob/73c813a81d5bc490a1d287addb1a1e2f25d41e60/src/bin/ios_gen_bindings.rs#L42), [L74](https://github.com/zkonduit/ezkl/blob/73c813a81d5bc490a1d287addb1a1e2f25d41e60/src/bin/ios_gen_bindings.rs#L74), [L103](https://github.com/zkonduit/ezkl/blob/73c813a81d5bc490a1d287addb1a1e2f25d41e60/src/bin/ios_gen_bindings.rs#L103)). - `"x86_64-apple-ios"` target was removed to keep the binding library size under 100MB, making it manageable on GitHub. - `ios-bindings` enables a set of features during the binding build process ([L161](https://github.com/zkonduit/ezkl/blob/73c813a81d5bc490a1d287addb1a1e2f25d41e60/src/bin/ios_gen_bindings.rs#L161)). - When building the binary, additional features are manually specified in `Cargo.toml` ([L211](https://github.com/zkonduit/ezkl/blob/73c813a81d5bc490a1d287addb1a1e2f25d41e60/Cargo.toml#L211)). - `staticlib` is added as a crate type in `Cargo.toml`. #### Changes to the bindings generation: Mopro CLI can simplify and standardize iOS binding generation by handling key aspects of the process: - **Replace Custom Binary Management**: Instead of maintaining a separate binary for generating bindings, Mopro should allow calling its CLI to handle this task automatically. *(Need)* - **Library Naming Configuration**: Users should be able to specify the desired output library name instead of relying on the default `MoproFFI`. Mopro could also offer an option to extract the library name from `Cargo.toml`. *(Must, Could)* - **Configuration Validation**: Mopro should check that required configurations (e.g., correct library type in `Cargo.toml`) are set up properly and provide guidance if misconfigurations are detected. *(Nice to Have)* - **Target Selection**: Users should be able to specify which targets to generate bindings for and possibly define which features should be activated for each. Possibly this can be simplified and the Mopro cli can automatically pass *(Must)* - **Feature Selection**: When generating bindings, the rust code would need to know for which tagetn it is generating the bindings, this can be done using the CLI passing the mopro features, such as `mopro/ios-bindings` feature. *(Must)* - **Intel Mac Target Option**: Mopro should allow users to configure whether to include `x86_64-apple-ios` support, given the size trade-offs. *(Could)* ### Testing iOS Bindings #### Rust Driven Tests - **Framework**: Uses `uniffi/bindgen-tests`, gated under `ios-bindings-test`. - **Test Location**: Tested native functions Defined in the [`tests/ios`](https://github.com/zkonduit/ezkl/tree/main/tests/ios) folder. - **Framework**: Uses `ios_integration_tests.rs` ([source](https://github.com/zkonduit/ezkl/blob/main/tests/ios_integration_tests.rs)). - **Challenges**: Autogeneration of tests is difficult due to required setup (e.g., reading test files). - **Dependency on Forked Uniffi**: To allow feature configuration for testing ([Issue](https://github.com/mozilla/uniffi-rs/issues/2269)). - **Workflow**: Defined in [`rust.yml`](https://github.com/zkonduit/ezkl/blob/73c813a81d5bc490a1d287addb1a1e2f25d41e60/.github/workflows/rust.yml#L812). #### Changes to Rust Driven Tests - **Suggested Mopro Improvement**: Provide a build script that enables relevant test features dynamically. - **Potential Mopro Improvement**: Provide GitHub Action or reusable template. - **Potential Mopro Abstraction**: Standardize test specification for different targets as in `ios_integration_tests.rs`and provide a common way to call the tests ### CI/CD Pipeline for iOS Bindings #### Local Test Execution - **Workflow**: Defined in [`rust.yml`](https://github.com/zkonduit/ezkl/blob/73c813a81d5bc490a1d287addb1a1e2f25d41e60/.github/workflows/rust.yml#L812). #### Integration Testing via Sample App - **Process**: Runs a Swift package example stored in [`ezkl-swift-package/Example`](https://github.com/zkonduit/ezkl-swift-package/tree/main/Example). - **Execution**: Runs the app on CI as per [`rust.yml`](https://github.com/zkonduit/ezkl/blob/73c813a81d5bc490a1d287addb1a1e2f25d41e60/.github/workflows/rust.yml#L832). - **Potential Mopro Contribution**: Abstract the sample app execution into a standardized test framework. #### Swift Package Management - **CD Workflow**: Runs via [`swift-pm.yml`](https://github.com/zkonduit/ezkl/blob/main/.github/workflows/swift-pm.yml) on every release. - **Process**: - Clones the Swift package repo. - Builds new bindings and replaces old assets. - Runs tests within the Swift example project. - Pushes updates and tags a new release. #### Swift Package Management Mopro Contribution - Automate repetitive update processes of the package as github pushes from the main repo. - Provide standardization for package management across different platforms. - Improve GitHub token handling to enhance security as currently we need a token to push from rust CI repository to the siwft package. ### Future Steps: Expanding Mopro Beyond iOS Once Mopro successfully handles the iOS binding management, providing an initial layer of simplification, it can further absorb the other binding generation processes for Python and WASM. The goal would be to introduce a **unified CLI** that generates bindings from annotated functions across all targets. #### Challenges and Considerations: - **Python-specific Export Rules**: Unlike Swift and WASM, Python requires a different set of exported functions. Some mechanism must allow defining which functions should be included for each platform. - **Uniform Command-line Interface**: Ideally, we would want to annotate functions with `mopro::export` and `mopro::setup!` and then generate bindings with a single command, e.g.,: ```sh cargo install mopro mopro wasm --package-name Ezkl ``` This should produce WASM bindings with minimal adjustments between platforms. - **CI/CD Automation**: Mopro should also provide a **deployment workflow** that can be imported into CI/CD pipelines to automate multi-platform package releases. #### Next Steps: - **Kotlin Support**: Since Kotlin bindings should be straightforward to integrate, this would be the next logical step. - **Python and WASM Merging**: Unify the Python and WASM binding engines under Mopro to simplify the maintenance of EZKL. - **Long-term Maintenance Reduction**: This abstraction would allow EZKL to rely on a single tool for generating and deploying bindings across all platforms, ensuring consistency and reducing maintenance overhead. --- -->