Skip to main content

3 posts tagged with "noir"

View All Tags

Private Balance Proofs with EAS, Noir, and Mopro

· 6 min read
Sooyoung Hyun
Co-founder, ZKProofport

An application checking a balance requirement may only need one answer: does this user meet the threshold? The exact balance and the wallet associated with it can remain private.

GIWA Dojang provides a useful starting point. Built on the Ethereum Attestation Service (EAS), it defines a Balance Root format that represents a snapshot of balances as a Merkle root.

We used that existing format to build a complete example: express the private conditions in Noir, generate a proof through Mopro’s native Noir adapter, and verify it in a Solidity contract that reads EAS state.

The example uses synthetic balances and a local chain. Proof generation, EAS interactions, and Solidity verification are all real.

Explore the code and reproduction scripts →

From an attestation to a private balance proof​

A Balance Root summarizes a collection of balance entries. Each entry contains a wallet address, an amount, and a salt. A Merkle path connects the entry to the root recorded in an EAS attestation.

Suppose an entry contains a balance of 100, and an application requires at least 80. Our Noir circuit proves that:

  • The balance entry belongs to the specified root.
  • Its amount meets the public threshold.
  • The wallet associated with the entry authorized this request.

The exact amount, original wallet address, Merkle path, and signature are private inputs. The threshold, root, receiving address, and request context are public.

The receiving address can differ from the wallet in the balance entry. The signed request binds that address, the chain, application contract, nonce, deadline, and attestation context. Changing these fields requires a new authorization.

The Solidity application checks the EAS record, verifies the proof, and marks the request as consumed.

How the pieces fit together​

Each component handles a different part of the flow:

ComponentResponsibility
GIWA DojangProvides the existing balance data format we target
EASRecords the root’s issuer, schema, expiration, and revocation state
NoirExpresses private membership, balance comparison, and wallet authorization
MoproConnects the Noir circuit to native proving and generated bindings
Barretenberg and SolidityGenerate the proof and verify it on the EVM

Keeping the existing data format was an important constraint. Dojang uses Ethereum ABI encoding followed by double Keccak hashing for leaves, with sorted hash pairs along the Merkle path.

We implemented the same byte layout in Noir, including address padding. Amounts are represented as 32-byte integers, preserving the full uint256 range without reducing values into a single field element.

Compatibility tests cover OpenZeppelin-generated trees and an original Dojang test vector. The Noir vector test calls the same Merkle functions used by the complete circuit.

Why the EAS check still matters​

A cryptographically valid proof can refer to a root that has expired, been revoked, or was issued by an organization the application does not trust.

The gate therefore reads EAS state when processing each request. It checks the issuer, schema, expiration, revocation, asset, and snapshot policy before verifying the proof. A root revoked after proof generation will still be rejected.

This separates two responsibilities: Noir checks the conditions over the private data, while the application checks whether the referenced attestation is acceptable.

We tested both successful requests and failure cases:

CaseExpected result
Balance 100, threshold 80 or 100Accept
Balance 100, threshold 101Reject
Modified amount, Merkle path, or signatureReject
Existing proof used with a different receiving addressReject
Unauthorized issuer or expired/revoked rootReject
Identical request submitted twiceReject

The test runner also distinguishes circuit rejection from execution errors. Missing files and malformed inputs cannot count as successful negative tests.

Connecting Mopro to Solidity verification​

We used Mopro’s Noir adapter with noir-rs beta.19 and Barretenberg 4.2.0-aztecnr-rc.2. Proofs use the Keccak-based EVM configuration with zero knowledge enabled.

Three integration details were particularly useful:

  • Proof serialization. This noir-rs version includes a four-byte public-input count before the inputs and proof. We used its parser and compared the resulting public inputs with those constructed by the Solidity gate.
  • Verifier deployment. The generated Solidity verifier requires library linking. The scripts generate the verifier from the current verification key and deploy its linked library.
  • Native bindings. We generated Swift bindings and verified the complete proof through Swift on macOS.

The iOS simulator build encountered a transitive backtrace/libc dependency issue. This balance circuit has not been executed on a simulator or physical phone. The repository records that failure alongside the successful native and Swift host paths.

Measuring the complete circuit​

We measured the initial implementation at three Merkle depths. Every run included membership verification, full-width balance comparison, wallet signature verification, and request binding.

Merkle depthBarretenberg finalized size (pre-padding)Median adapter callMedian peak process memory
8311,3564.62 s2.17 GiB
12383,2486.19 s2.26 GiB
16455,1407.90 s2.35 GiB

Circuit sizes were extracted using the benchmark’s pinned toolchain and hash-matched ACIR artifacts. All three circuits have a padded size of 524,288 (2¹⁹).

Measurements used an Apple M4 with 16 GiB RAM, three measured runs per depth, and a preparatory run excluded.

The adapter interval includes witness execution, proving, and internal SRS reading/setup. Initial downloads and initial verification-key preparation are excluded. Memory covers the entire native process. These are host measurements, not mobile benchmarks or isolated proving times.

Successful local redemption transactions used approximately 3.06 million gas, including EAS policy checks, proof verification, and request consumption.

The results document identifies the measured revision and preserves the raw data. Validation of the subsequent refactor is recorded separately; its depth benchmarks have not been rerun.

Try the example​

With the prerequisites listed in the README installed:

git clone https://github.com/zkproofport/dojang-private-balance.git
cd dojang-private-balance
bash scripts/bootstrap.sh
bash scripts/run.sh

The scripts prepare the pinned dependencies, start a local Anvil chain, deploy EAS and the verifier, and run the proof and policy checks.

Connecting this example to real GIWA issuer data still requires a private way for holders to obtain their amount, salt, and Merkle path. The implementation checks a condition about an issuer-asserted snapshot. It does not establish a current balance or conceal information already published elsewhere.

The repository brings together an existing GIWA attestation format, EAS state checks, Noir conditions, Mopro native proving, and Solidity verification in one reproducible example. Developers can use it to explore the same boundaries with their own attestation data and application policies.

At ZKProofport, we have also explored a related flow in a Dojang KYC demo on GIWA Sepolia. This separate prototype uses test attestations to demonstrate KYC eligibility and authorization for another wallet, applying a similar idea to a different credential.

Mopro x Noir: Powering Mobile Zero-Knowledge Proofs

· 12 min read
Vivian Jeng
Developer on the Mopro Team

Introduction​

Noir has been gaining significant traction recently, and for good reason. It's renowned for its elegant circuit frontend design and high-performance backend. With robust SDKs that make building web-based zero-knowledge apps seamless—and the ability to verify proofs on-chain—Noir stands out as a powerful and promising framework for developing modern ZKP applications.

However, while Noir offers strong support for web-based applications, native mobile support is still limited within the ecosystem. Most existing resources for mobile development have been contributed by the zkPassport team, including key projects like

Our work is deeply inspired by the zkPassport team’s contributions, but builds upon them with significant improvements and optimizations.

In this article, we’ll walk through how we integrated Noir into the Mopro project, highlighting the key challenges we faced and the opportunities we uncovered along the way. We'll also introduce Stealthnote Mobile, a fully native mobile application built with Noir, to demonstrate the potential and performance of running zero-knowledge proofs natively on mobile devices.

Build noir-rs​

Like many apps with Mopro, our journey began with building a Rust crate. We started by adopting noir_rs from the zkPassport team. However, we quickly ran into some major challenges: compiling the Barretenberg backend — the proving system used by most Noir projects — could take up to 20 minutes. On top of that, the build process required a very specific developer environment, and lacked caching, meaning the entire binary had to be rebuilt from scratch even after a successful build.

To address these issues, we introduced a solution in

by prebuilding the backend binaries and hosting them on a server. During the build process, these binaries are downloaded automatically, eliminating the need for local compilation. This approach drastically reduces build time—from 20 minutes to just 8 seconds—and removes the need for any special environment setup. In fact, you can see from our GitHub Actions YAML file that no additional dependencies are required.

Suggestions​

Currently, the build process for the backend happens locally, which makes it non-reproducible and difficult to upgrade in CI environments like GitHub Actions. To improve this, we believe the build logic should be moved into CI. However, this process is quite complex and largely duplicated across repositories like the Noir and Aztec packages (See: publish-bb.yml).

Our proposal is that the Noir and Aztec teams consolidate this effort by building libbarretenberg.a within the same CI pipeline and releasing them. Since bb depends on these static libraries, they would naturally be compiled as part of that process. These prebuilt artifacts could then be published alongside the bb binary. This would allow downstream consumers like noir-rs to directly use the published binaries, eliminating the need to maintain custom build scripts or host binaries separately.

note

bb is a CLI tool that generates proofs directly in the user's terminal. Underneath, it relies on libbarretenberg.a—a static library that exposes low-level function APIs for proof generation, e.g.

void acir_prove_ultra_honk(uint8_t const* acir_vec,
bool const* recursive,
uint8_t const* witness_vec,
uint8_t** out)

When properly linked, this library can be used directly within a Rust program, enabling seamless integration of the proving system into native applications.

Go Mobile-Native​

Once we have the Rust crate ready, integrating it into a Mopro project allows us to easily generate bindings for both iOS and Android. Mopro significantly improves the mobile integration experience in the following ways:

  1. No additional Swift or Kotlin bindings required

    Unlike the zkPassport team's approach—where they built separate Swoir and noir_android libraries with custom domain-specific interfaces—Mopro leverages uniffi to automatically generate language bindings. This means developers don’t need to manually maintain Swift 1 or Kotlin wrappers 2; they can directly import and use the generated bindings in their mobile codebases. e.g.

    For swift:

    import moproFFI

    let proofData = try! generateNoirProof(circuitPath: zkemailCircuitPath, srsPath: zkemailSrsPath, inputs: inputs)

    For kotlin:

    import uniffi.mopro.generateNoirProof

    let proofData = generateNoirProof(circuitFile, srsPath, inputs)
  2. Framework-Agnostic Design

    Mopro is not tied to any specific mobile framework. By defining reusable templates for each target framework, developers are free to choose the environment they’re most comfortable with. Currently, Mopro supports native iOS (Xcode + Swift), native Android (Android Studio + Kotlin), as well as cross-platform frameworks like React Native and Flutter—offering maximum flexibility and accessibility for diverse developer needs.

Mopro Support​

We’ve successfully integrated Noir proving into both Mopro-FFI and the Mopro CLI. You can now install the Mopro CLI and follow the steps in the Getting Started guide to create a Noir project. Simply replace the SRS and circuit files with your own, and provide your custom circuit input — that’s it!

We’ve also provided an example zkEmail repository featuring a Noir circuit

along with a NoirHack workshop video.

Feel free to explore the repo, clone it, and follow along to learn how to use Noir with Mopro in a real-world application.

Challenge: Cross-platform support is limited​

Our current implementation draws heavily from the zkPassport team’s work, which currently supports iOS devices and ARM64 Android devices/emulators. However, there are limitations: iOS simulators—essential for efficient development and testing—are not supported, and many Android developers (especially those using Windows with WSL) rely on x86_64 emulators. Even CI environments like GitHub Actions commonly use x86_64 Android emulators.

PlatformsCurrent support targetSupport
iOSaarch64-apple-ios✅
iOSaarch64-apple-ios-sim✅
iOSx86_64-apple-ios❌
Androidx86_64-linux-android✅
Androidi686-linux-android❌
Androidarmv7-linux-androideabi❌
Androidaarch64-linux-androids✅
MacOSstable-aarch64-apple-darwin✅
Linuxx86_64-unknown-linux-gnu✅
Windowsx86_64-pc-windows-msvc❌

Expanding support to these platforms is a significant challenge. The barretenberg backend, written in C++ and built with CMake, is large and complex, making cross-compilation non-trivial. While we’re evaluating the effort required to support additional architectures, we’re also hopeful that the Noir or zkPassport teams may address this gap in the future.

Update (noir-rs v1.0.0-beta.19)

As of noir-rs v1.0.0-beta.19, mopro pulls Barretenberg via the official barretenberg-rs crate from crates.io rather than the publish-bb.yml pipeline in zkmopro/aztec-packages referenced above. The x86_64-apple-ios target was also dropped in that upgrade — barretenberg-rs does not ship prebuilt binaries for the Intel iOS simulator. The rest of the support matrix is unchanged.

Case Study: Stealthnote Mobile App​

During the NoirHack 2025 (April 14th to May 10th), the Mopro team participated by building a mobile-native Noir application. Our project was inspired by Stealthnote, originally created by Saleel. Stealthnote is a web-based app that allows users to sign in with Google OAuth and prove ownership of their organizational email address. It leverages a Noir circuit to generate a zero-knowledge proof from the JWT issued by Google OAuth. You can read more about the original project in Saleel’s blog post.

We aim to enhance performance and user experience by building a fully native mobile app. At the same time, we want to demonstrate that the current Mopro + Noir stack is fully capable of supporting mobile-native development. Therefore, we decided to build a mobile version of Stealthnote.

What We Built​

During the hackathon, we developed

A mobile-native frontend for the original Stealthnote project. To maintain compatibility, we kept the original Noir circuits and backend logic intact, focusing entirely on building the mobile frontend. Even so, creating a mobile frontend involved tackling many challenges across platforms.

We chose Flutter as our cross-platform framework because of its fast build times compared to React Native and its rich ecosystem of packages for mobile functionalities—such as Google authentication, biometric login, camera access, gallery browsing, and file storage. In our view, Flutter is currently the best choice for building high-performance, cross-platform apps.

Our architecture separates responsibilities clearly:

  • Flutter handles:

    1. UI/UX design
    2. Google OAuth authentication
    3. Backend API communication
  • Rust handles:

    1. Parsing the JWT and converting it into the structured inputs required by the Noir circuit
    2. Generating and verifying Noir proofs
    3. Ephemeral key generation using Ed25519 and Poseidon2
    info

    To learn how to integrate Mopro Rust bindings into a Flutter project, please refer to the

This clear separation lets us leverage the strengths of both technologies—Flutter’s frontend speed and flexibility, and Rust’s performance and security for core cryptographic logic.

Benchmark​

While the Mopro team anticipated the outcome, the benchmark results are still notable: a mobile-native prover delivers performance up to 10 times faster than running the same proof in a browser environment.

JWT OperationProveVerify
Browser37.292 s0.286 s
Desktop (Mac M1 Pro)2.02 s0.007 s
Android emulator (Pixel 8)4.786 s3.013 s
iPhone 16 Pro2.626 s1.727 s

Challenge: Insufficient Rust tooling and SDKs.​

One of the main challenges we faced was converting all the TypeScript functions used in StealthNote into their Rust equivalents. For standard cryptographic operations like Ed25519 signatures, this was relatively straightforward — Rust has mature libraries we could rely on.

However, Poseidon2 presented a bigger challenge. Unlike the original Poseidon hash, Poseidon2 is a newer variant used in the Noir circuits. Unfortunately, there was no direct Rust implementation available. The Noir team primarily supports a TypeScript version via bb.js, which is a wrapper around Barretenberg's C++ implementation compiled to WASM. This made it hard to fully understand the logic and port it to Rust.

Eventually, we located the Poseidon2 Noir circuit and its permutation logic in the noir-lang repository. Using that as a reference, we implemented our own version of

aligning it with the Noir circuit to ensure compatibility.

Suggestions​

Since Barretenberg already provides a C++ implementation for most Noir circuit functions, it would actually be more efficient and sustainable for the Noir or Aztec team to maintain a native C++ or Rust SDK for Rust developers — rather than focusing primarily on the JavaScript (bb.js) interface.

As we suggested earlier, an ideal solution would be for the team to publish precompiled static binaries (e.g. libbarretenberg.a) alongside versioned releases. This way, other developers — like us — could easily integrate these binaries into their Rust projects using proper FFI bindings.

This approach would remove the need for every developer to rebuild Barretenberg from source or maintain their own custom builds. For example, our bb.rs project demonstrates this idea, but it still lacks many of the standard library features available in bb.js, such as: poseidon2, blake2, AES encryption/decryption. Providing official support for these as native libraries would greatly improve the developer experience and adoption for building performant, mobile-native or server-side ZK applications.

Conclusion​

We began integrating Noir with Mopro in early April, and the process progressed smoothly — thanks in large part to the foundational work done by the zkPassport team. In contrast to our experience with the Circom prover (which took several months to make mobile-compatible), Noir integration was faster and more straightforward.

However, we also discovered significant gaps in Noir’s current support for mobile-native development. While the prover itself is crucial, a complete SDK ecosystem is equally important. At the moment, teams aiming to build mobile-native apps — like zkPassport — must develop many of the components from scratch, rather than being able to rely on official tooling or prebuilt libraries from the Noir team.

This raises a challenge: what if a project doesn’t have the expertise, time, or resources to build and maintain a mobile-native infrastructure? These barriers can prevent great ideas from becoming usable apps.

There’s still a long road ahead — for both the Mopro team and the Noir ecosystem — to provide a full suite of mobile-native infrastructure that can empower ZK developers, whether they're building the next zkPassport or an entirely new kind of app.

Finally, we want to encourage more developers to explore building mobile-native apps. These platforms offer better performance, deeper device integration, and more seamless user experiences — which are essential if you want your ZK project to truly reach users.

Contribution​

All kinds of contributions are welcome! 🎉

Feel free to check out the current issues on the Mopro GitHub repository, or open a new issue if you notice something missing or have ideas to improve the project.

Here are some current Noir-related issues worth exploring:

Feel free to reach out to the Mopro team on Telegram @zkmopro for questions or support, and follow us on X (formerly Twitter) @zkmopro to stay up to date with our latest progress!

Footnotes​

  1. Noir Swift wrapper: https://github.com/Swoir/Swoir/blob/main/Sources/Swoir/Circuit.swift ↩

  2. Noir Kotlin wrapper: https://github.com/madztheo/noir_android/blob/main/lib/src/main/java/com/noirandroid/lib/Circuit.kt ↩

Integrating Mopro Native Packages Across Mobile Platforms

· 8 min read
Moven Tsai
Developer on the Mopro Team

TL; DR Mopro now ships pre-built native packages for Swift (iOS), Kotlin (Android), Flutter, and React Native.
Just one import and one build. Proving made simple!

Announcing Mopro Native Packages​

We're excited to launch Mopro native packages, enabling developers to effortlessly generate and verify zero-knowledge proofs (ZKPs) directly on mobile devices. These native packages leverage Rust's performance and seamlessly integrate with popular mobile frameworks. Built using the Mopro CLI, they're available for direct import via each platform's package manager.

You can also easily create your own customized native packages by following zkmopro-docs.

FrameworkPackage ManagerDefault PackageszkEmail Packages via Mopro
Swift (iOS)Xcode / SwiftPM / CocoaPodsmopro-swift-packagezkemail-swift-package
Kotlin (Android)JitPackmopro-kotlin-packagezkemail-kotlin-package
Flutterpub.devmopro_flutter_packagezkemail_flutter_package
React Nativenpm / yarnmopro-react-native-packagezkemail-react-native-package

This blog provides a quick guide on integrating these packages into your projects, outlines how we built them (so you can customize your own), addresses challenges we overcame, and highlights future developments. Let's get started!

Import, Build, Prove - That's It​

Mopro's native packages simplify the integration process dramatically. Unlike the traditional approach that requires crafting APIs, generating bindings, and manually building app templates, these pre-built packages allow developers to import them directly via package managers and immediately begin developing application logic.

For ZK projects, converting your Rust-based solutions into mobile-native packages is straightforward with Mopro. Our guide on "How to Build the Package" explains the process clearly.

For instance, our zkEmail native packages were created by first defining ZK proving and verification APIs in Rust, generating bindings with mopro build, and embedding these into native packages. The circuit is the header-only proof from zkemail.nr_header_demo.

Here's how zkEmail performs on Apple M3 chips:

zkEmail OperationiOS, Time (ms)Android, Time (ms)
Proof Generation1,3093,826
Verification9622,857

iOS zkEmail App Example
iOS
Android zkEmail App Example
Android

Flutter App for iOS & Android zkEmail Example

Notice that, with Mopro and the use of Noir-rs, we port zkEmail into native packages while keeping the proof size align with Noir's Barretenberg backend CLI. It transfers the API logic directly to mobile platforms with no extra work or glue code needed!

How it worked before Mopro​

Previously, integrating ZKPs into mobile applications involved more manual work and platform-specific implementations. For example, developers might have used solutions like:

These approaches often required developers to handle bridging code and manage dependencies separately for each platform, unlike the streamlined process Mopro now offers.

With Mopro, developers can leverage pre-built native packages and import them directly via package managers. This, combined with automated binding generation, significantly reduces the need for manual API crafting and platform-specific glue code.

While developers still write their application logic using platform-specific languages, Mopro simplifies the integration of core ZK functionalities, especially when leveraging Rust's extensive cryptography ecosystem.

Under The Hood​

Developing native packages involved tackling several technical challenges to ensure smooth and efficient operation across different platforms.

This section dives into two key challenges we addressed:

  1. Optimizing static library sizes for iOS to manage package distribution and download speeds.
  2. Ensuring compatibility with Android's release mode to prevent runtime errors due to code shrinking.

Optimizing Static Library Sizes for iOS​

Why Static Linking?​

UniFFI exports Swift bindings as a static archive (libmopro_bindings.a). Static linking ensures all Rust symbols are available at link-time, simplifying Xcode integration. However, it bundles all Rust dependencies (Barretenberg Backend, rayon, big-integer math), resulting in larger archive sizes.

Baseline Size​

The full build creates an archive around ≈ 153 MB in size. When uploading files over 100 MB to GitHub, Git LFS takes over by replacing the file with a text pointer in the repository while storing the actual content on a remote server like GitHub.com. This setup can cause issues for package managers that try to fetch the package directly from a GitHub URL for a release publish.

While uploading large files may be acceptable for some package management platforms or remote servers like Cloudflare R2, the large file size slows down:

  • CocoaPods or SwiftPM downloads
  • CI cache recovery
  • Cloning the repository, especially on slower connections

Our Solution: Zip & Unzip Strategy​

To keep development fast and responsive, we compress the entire MoproBindings.xcframework before uploading it to GitHub and publishing it to CocoaPods, reducing its size to about ≈ 41 MB.

We also found that by customizing script_phase in the .podspec (check our implementation in ZKEmailSwift.podspec), we can unzip the bindings during pod install. This gives us the best of both worlds: (1) smaller packages for distribution and (2) full compatibility with Xcode linking. The added CPU cost is minor compared to the time saved on downloads.

Comparison With Android​

On Android, dynamic .so libraries (around 22 MB in total) are used, with symbols loaded lazily at runtime to keep the package size small. In contrast, because iOS's constraint on third-party Rust dynamic libraries in App Store builds, static linking with compression is currently the most viable option, to the best of our knowledge.

Ensuring Android Release Mode Compatibility​

Another challenge we tackled was ensuring compatibility with Android's release mode. By default, Android's release build process applies code shrinking and obfuscation to optimize app size. While beneficial for optimization, this process caused a java.lang.UnsatisfiedLinkError for Mopro apps.

The root cause was that code shrinking interfered with JNA (Java Native Access), a crucial dependency for UniFFI, which we use for Rust-to-Kotlin bindings. The shrinking process was removing or altering parts of JNA that were necessary for the bindings to function correctly, leading to the UnsatisfiedLinkError when the app tried to call the native Rust code.

The Fix: Adjusting Gradle Build Configurations​

Our solution, as detailed in GitHub Issue #416, involves a configuration adjustment in the consuming application's android/build.gradle.kts file (or android/app/build.gradle for older Android projects). Developers using Mopro need to explicitly disable code and resource shrinking for their release builds:

android {
// ...
buildTypes {
getByName("release") {
// Disables code shrinking, obfuscation, and optimization for
// your project's release build type.
minifyEnabled = false
// Disables resource shrinking, which is performed by the
// Android Gradle plugin.
shrinkResources = false
}
}
}

Impact and Future Considerations​

This configuration ensures that JNA and, consequently, the UniFFI bindings remain intact, allowing Mopro-powered Android apps to build and run successfully in release mode. This approach aligns with recommendations found in the official Flutter documentation for handling similar issues. While this increases the final app size slightly, it guarantees the stability and functionality of the native ZK operations. We are also actively exploring ways to refine this in the future to allow for optimized builds without compromising JNA's functionality.

The Road Ahead​

a. Manual Tweaks for Cross-Platform Frameworks​

Cross-platform frameworks like React Native and Flutter require additional glue code to define modules, as they straddle multiple runtimes. Each layer needs its own integration.

For example, in our zkEmail React Native package, we use three separate wrappers.

Similarly, for our zkEmail Flutter package, a comparable set of wrappers is employed:

b. Support for Custom Package Names​

Initially, we encountered naming conflicts when the same XCFramework was used in multiple Xcode projects. Addressing this to allow fully customizable package names is an ongoing effort.

Initial progress was made with updates in issue#387 and a partial fix in PR#404. Further work to complete this feature is being tracked in issue#413.

What's Next: Shaping Mopro's Future Together​

Currently, the Mopro CLI helps you create app templates via the mopro create command, once bindings are generated with mopro build.

Our vision is to enhance this by enabling the automatic generation of fully customized native packages. This would include managing all necessary glue code for cross-platform frameworks, potentially through a new command (maybe like mopro pack) or by extending existing commands. We believe this will significantly streamline the developer workflow. If you're interested in shaping this feature, we invite you to check out the discussion and contribute your ideas in issue #419.

By achieving this, we aim to unlock seamless mobile proving capabilities, simplifying adoption for developers leveraging existing ZK solutions or porting Rust-based ZK projects. Your contributions can help us make mobile ZK development more accessible for everyone!

If you find it interesting, feel free to reach out to the Mopro team on Telegram: @zkmopro, or better yet, dive into the codebase and open a PR! We're excited to see what the community builds with Mopro.

Happy proving!