<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <id>https://zkmopro.org/blog</id>
    <title>Mopro Blog</title>
    <updated>2025-05-08T00:00:00.000Z</updated>
    <generator>https://github.com/jpmonette/feed</generator>
    <link rel="alternate" href="https://zkmopro.org/blog"/>
    <subtitle>Mopro Blog</subtitle>
    <icon>https://zkmopro.org/img/logo_sm.svg</icon>
    <entry>
        <title type="html"><![CDATA[Integrating Mopro Native Packages Across Mobile Platforms]]></title>
        <id>https://zkmopro.org/blog/mopro-native-packages</id>
        <link href="https://zkmopro.org/blog/mopro-native-packages"/>
        <updated>2025-05-08T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[TL; DR Mopro now ships pre-built native packages for Swift (iOS), Kotlin (Android), Flutter, and React Native.]]></summary>
        <content type="html"><![CDATA[<blockquote>
<p><strong>TL; DR</strong> Mopro now ships pre-built native packages for Swift (iOS), Kotlin (Android), Flutter, and React Native.<br>
<!-- -->Just one import and one build. Proving made simple!</p>
</blockquote>
<h2 class="anchor anchorWithStickyNavbar_wa2S" id="announcing-mopro-native-packages">Announcing Mopro Native Packages<a href="https://zkmopro.org/blog/mopro-native-packages#announcing-mopro-native-packages" class="hash-link" aria-label="Direct link to Announcing Mopro Native Packages" title="Direct link to Announcing Mopro Native Packages">​</a></h2>
<p>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.</p>
<p>You can also easily create your own customized native packages by following <a href="https://zkmopro.org/docs/getting-started" target="_blank" rel="noopener noreferrer">zkmopro-docs</a>.</p>
<table><thead><tr><th>Framework</th><th>Package Manager</th><th>Default Packages</th><th>zkEmail Packages via Mopro</th></tr></thead><tbody><tr><td><strong>Swift (iOS)</strong></td><td>Xcode / SwiftPM / CocoaPods</td><td><a href="https://github.com/zkmopro/mopro-swift-package" target="_blank" rel="noopener noreferrer">mopro-swift-package</a></td><td><a href="https://github.com/zkmopro/zkemail-swift-package" target="_blank" rel="noopener noreferrer">zkemail-swift-package</a></td></tr><tr><td><strong>Kotlin (Android)</strong></td><td>JitPack</td><td><a href="https://github.com/zkmopro/mopro-kotlin-package" target="_blank" rel="noopener noreferrer">mopro-kotlin-package</a></td><td><a href="https://github.com/zkmopro/zkemail-kotlin-package" target="_blank" rel="noopener noreferrer">zkemail-kotlin-package</a></td></tr><tr><td><strong>Flutter</strong></td><td>pub.dev</td><td><a href="https://github.com/zkmopro/mopro_flutter_package" target="_blank" rel="noopener noreferrer">mopro_flutter_package</a></td><td><a href="https://github.com/zkmopro/zkemail_flutter_package" target="_blank" rel="noopener noreferrer">zkemail_flutter_package</a></td></tr><tr><td><strong>React Native</strong></td><td>npm / yarn</td><td><a href="https://github.com/zkmopro/mopro-react-native-package" target="_blank" rel="noopener noreferrer">mopro-react-native-package</a></td><td><a href="https://github.com/zkmopro/zkemail-react-native-package" target="_blank" rel="noopener noreferrer">zkemail-react-native-package</a></td></tr></tbody></table>
<p>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!</p>
<h2 class="anchor anchorWithStickyNavbar_wa2S" id="import-build-prove---thats-it">Import, Build, Prove - That's It<a href="https://zkmopro.org/blog/mopro-native-packages#import-build-prove---thats-it" class="hash-link" aria-label="Direct link to Import, Build, Prove - That's It" title="Direct link to Import, Build, Prove - That's It">​</a></h2>
<p>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.</p>
<p>For ZK projects, converting your Rust-based solutions into mobile-native packages is straightforward with Mopro. Our guide on <a href="https://github.com/zkmopro/mopro-swift-package?tab=readme-ov-file#how-to-build-the-package" target="_blank" rel="noopener noreferrer">"How to Build the Package"</a> explains the process clearly.</p>
<p>For instance, our zkEmail native packages were created by first <a href="https://github.com/zkmopro/mopro-zkemail-nr/blob/main/src/lib.rs" target="_blank" rel="noopener noreferrer">defining ZK proving and verification APIs in Rust</a>, generating bindings with <code>mopro build</code>, and embedding these into native packages. The circuit is the header-only proof from <a href="https://github.com/Mach-34/zkemail.nr_header_demo" target="_blank" rel="noopener noreferrer">zkemail.nr_header_demo</a>.</p>
<p>Here's how zkEmail performs on Apple M3 chips:</p>
<table><thead><tr><th>zkEmail Operation</th><th>iOS, Time (ms)</th><th>Android, Time (ms)</th></tr></thead><tbody><tr><td>Proof Generation</td><td>1,309</td><td>3,826</td></tr><tr><td>Verification</td><td>962</td><td>2,857</td></tr></tbody></table>
<p align="center"></p><table><tbody><tr><td align="center"><a href="https://zkmopro.org/img/zkemail-flutter-app-ios.png" target="_blank" rel="noopener noreferrer"><img src="https://zkmopro.org/img/zkemail-flutter-app-ios.png" alt="iOS zkEmail App Example" width="300"></a><br><sub><b>iOS</b></sub></td><td align="center"><a href="https://zkmopro.org/img/zkemail-flutter-app-android.png" target="_blank" rel="noopener noreferrer"><img src="https://zkmopro.org/img/zkemail-flutter-app-android.png" alt="Android zkEmail App Example" width="300"></a><br><sub><b>Android</b></sub></td></tr></tbody></table><p></p><p align="center"><em>Flutter App for iOS &amp; Android zkEmail Example</em></p><p></p>
<p>Notice that, with Mopro and the use of <a href="https://github.com/zkmopro/noir-rs" target="_blank" rel="noopener noreferrer">Noir-rs</a>, 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!</p>
<h3 class="anchor anchorWithStickyNavbar_wa2S" id="how-it-worked-before-mopro">How it worked before Mopro<a href="https://zkmopro.org/blog/mopro-native-packages#how-it-worked-before-mopro" class="hash-link" aria-label="Direct link to How it worked before Mopro" title="Direct link to How it worked before Mopro">​</a></h3>
<p>Previously, integrating ZKPs into mobile applications involved more manual work and platform-specific implementations. For example, developers might have used solutions like:</p>
<ul>
<li><strong>Swoir:</strong> <a href="https://github.com/Swoir/Swoir/tree/main" target="_blank" rel="noopener noreferrer">https://github.com/Swoir/Swoir/tree/main</a></li>
<li><strong>noir-android:</strong> <a href="https://github.com/madztheo/noir_android/tree/main" target="_blank" rel="noopener noreferrer">https://github.com/madztheo/noir_android/tree/main</a></li>
</ul>
<p>These approaches often required developers to handle bridging code and manage dependencies separately for each platform, unlike the streamlined process Mopro now offers.</p>
<p>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.</p>
<p>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.</p>
<h2 class="anchor anchorWithStickyNavbar_wa2S" id="under-the-hood">Under The Hood<a href="https://zkmopro.org/blog/mopro-native-packages#under-the-hood" class="hash-link" aria-label="Direct link to Under The Hood" title="Direct link to Under The Hood">​</a></h2>
<p>Developing native packages involved tackling several technical challenges to ensure smooth and efficient operation across different platforms.</p>
<p>This section dives into two key challenges we addressed:</p>
<ol>
<li>Optimizing static library sizes for iOS to manage package distribution and download speeds.</li>
<li>Ensuring compatibility with Android's release mode to prevent runtime errors due to code shrinking.</li>
</ol>
<h3 class="anchor anchorWithStickyNavbar_wa2S" id="optimizing-static-library-sizes-for-ios">Optimizing Static Library Sizes for iOS<a href="https://zkmopro.org/blog/mopro-native-packages#optimizing-static-library-sizes-for-ios" class="hash-link" aria-label="Direct link to Optimizing Static Library Sizes for iOS" title="Direct link to Optimizing Static Library Sizes for iOS">​</a></h3>
<h4 class="anchor anchorWithStickyNavbar_wa2S" id="why-static-linking">Why Static Linking?<a href="https://zkmopro.org/blog/mopro-native-packages#why-static-linking" class="hash-link" aria-label="Direct link to Why Static Linking?" title="Direct link to Why Static Linking?">​</a></h4>
<p>UniFFI exports Swift bindings as a static archive (<code>libmopro_bindings.a</code>). 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.</p>
<h4 class="anchor anchorWithStickyNavbar_wa2S" id="baseline-size">Baseline Size<a href="https://zkmopro.org/blog/mopro-native-packages#baseline-size" class="hash-link" aria-label="Direct link to Baseline Size" title="Direct link to Baseline Size">​</a></h4>
<p>The full build creates an archive around <strong>≈ 153 MB</strong> 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.</p>
<p>While uploading large files may be acceptable for some package management platforms or remote servers like Cloudflare R2, the large file size slows down:</p>
<ul>
<li>CocoaPods or SwiftPM downloads</li>
<li>CI cache recovery</li>
<li>Cloning the repository, especially on slower connections</li>
</ul>
<h4 class="anchor anchorWithStickyNavbar_wa2S" id="our-solution-zip--unzip-strategy">Our Solution: Zip &amp; Unzip Strategy<a href="https://zkmopro.org/blog/mopro-native-packages#our-solution-zip--unzip-strategy" class="hash-link" aria-label="Direct link to Our Solution: Zip &amp; Unzip Strategy" title="Direct link to Our Solution: Zip &amp; Unzip Strategy">​</a></h4>
<p>To keep development fast and responsive, we compress the entire <code>MoproBindings.xcframework</code> before uploading it to GitHub and publishing it to CocoaPods, reducing its size to about <strong>≈ 41 MB</strong>.</p>
<p>We also found that by customizing <code>script_phase</code> in the <code>.podspec</code> (check our implementation in <a href="https://github.com/zkmopro/zkemail-swift-package/blob/b5c3a94f8580b0332ced2c8409a1017530a56e38/ZKEmailSwift.podspec#L93-L103" target="_blank" rel="noopener noreferrer"><code>ZKEmailSwift.podspec</code></a>), 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.</p>
<h4 class="anchor anchorWithStickyNavbar_wa2S" id="comparison-with-android">Comparison With Android<a href="https://zkmopro.org/blog/mopro-native-packages#comparison-with-android" class="hash-link" aria-label="Direct link to Comparison With Android" title="Direct link to Comparison With Android">​</a></h4>
<p>On Android, dynamic <code>.so</code> 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.</p>
<h3 class="anchor anchorWithStickyNavbar_wa2S" id="ensuring-android-release-mode-compatibility">Ensuring Android Release Mode Compatibility<a href="https://zkmopro.org/blog/mopro-native-packages#ensuring-android-release-mode-compatibility" class="hash-link" aria-label="Direct link to Ensuring Android Release Mode Compatibility" title="Direct link to Ensuring Android Release Mode Compatibility">​</a></h3>
<p>Another challenge we tackled was ensuring compatibility with Android's release mode. By default, Android's release build process applies <a href="https://developer.android.com/build/shrink-code" target="_blank" rel="noopener noreferrer">code shrinking and obfuscation</a> to optimize app size. While beneficial for optimization, this process caused a <code>java.lang.UnsatisfiedLinkError</code> for Mopro apps.</p>
<p>The root cause was that code shrinking interfered with <a href="https://mozilla.github.io/uniffi-rs/latest/kotlin/gradle.html#jna-dependency" target="_blank" rel="noopener noreferrer">JNA (Java Native Access)</a>, 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 <code>UnsatisfiedLinkError</code> when the app tried to call the native Rust code.</p>
<h4 class="anchor anchorWithStickyNavbar_wa2S" id="the-fix-adjusting-gradle-build-configurations">The Fix: Adjusting Gradle Build Configurations<a href="https://zkmopro.org/blog/mopro-native-packages#the-fix-adjusting-gradle-build-configurations" class="hash-link" aria-label="Direct link to The Fix: Adjusting Gradle Build Configurations" title="Direct link to The Fix: Adjusting Gradle Build Configurations">​</a></h4>
<p>Our solution, as detailed in <a href="https://github.com/zkmopro/mopro/issues/416" target="_blank" rel="noopener noreferrer">GitHub Issue #416</a>, involves a configuration adjustment in the consuming application's <code>android/build.gradle.kts</code> file (or <code>android/app/build.gradle</code> for older Android projects). Developers using Mopro need to explicitly disable code and resource shrinking for their release builds:</p>
<div class="language-kotlin codeBlockContainer_ZiiY theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QMo3"><pre tabindex="0" class="prism-code language-kotlin codeBlock_jfw7 thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_jUhv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">android </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// ...</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    buildTypes </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token function" style="color:rgb(130, 170, 255)">getByName</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string-literal singleline string" style="color:rgb(195, 232, 141)">"release"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">            </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// Disables code shrinking, obfuscation, and optimization for</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">            </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// your project's release build type.</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">            minifyEnabled </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token boolean" style="color:rgb(255, 88, 116)">false</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">            </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// Disables resource shrinking, which is performed by the</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">            </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// Android Gradle plugin.</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">            shrinkResources </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token boolean" style="color:rgb(255, 88, 116)">false</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></span></code></pre><div class="buttonGroup_TGb3"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_DrnI" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_ABK0"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_A0fP"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<h4 class="anchor anchorWithStickyNavbar_wa2S" id="impact-and-future-considerations">Impact and Future Considerations<a href="https://zkmopro.org/blog/mopro-native-packages#impact-and-future-considerations" class="hash-link" aria-label="Direct link to Impact and Future Considerations" title="Direct link to Impact and Future Considerations">​</a></h4>
<p>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 <a href="https://docs.flutter.dev/deployment/android#shrink-your-code-with-r8" target="_blank" rel="noopener noreferrer">similar issues</a>. 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.</p>
<h2 class="anchor anchorWithStickyNavbar_wa2S" id="the-road-ahead">The Road Ahead<a href="https://zkmopro.org/blog/mopro-native-packages#the-road-ahead" class="hash-link" aria-label="Direct link to The Road Ahead" title="Direct link to The Road Ahead">​</a></h2>
<h3 class="anchor anchorWithStickyNavbar_wa2S" id="a-manual-tweaks-for-cross-platform-frameworks">a. Manual Tweaks for Cross-Platform Frameworks<a href="https://zkmopro.org/blog/mopro-native-packages#a-manual-tweaks-for-cross-platform-frameworks" class="hash-link" aria-label="Direct link to a. Manual Tweaks for Cross-Platform Frameworks" title="Direct link to a. Manual Tweaks for Cross-Platform Frameworks">​</a></h3>
<p>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.</p>
<p>For example, in our <a href="https://github.com/zkmopro/zkemail-react-native-package" target="_blank" rel="noopener noreferrer">zkEmail React Native package</a>, we use three separate wrappers.</p>
<ul>
<li>[TypeScript] <a href="https://github.com/zkmopro/zkemail-react-native-package/blob/main/src/MoproReactNativePackageModule.ts" target="_blank" rel="noopener noreferrer"><code>MoproReactNativePackageModule.ts</code></a>: declares the public API and lets the React Native code-gen load the native module.</li>
<li>[Swift] <a href="https://github.com/zkmopro/zkemail-react-native-package/blob/main/ios/MoproReactNativePackageModule.swift" target="_blank" rel="noopener noreferrer"><code>MoproReactNativePackageModule.swift</code></a>: loads bindings into Objective-C–discoverable classes.</li>
<li>[Kotlin] <a href="https://github.com/zkmopro/zkemail-react-native-package/blob/main/android/src/main/java/expo/modules/moproreactnativepackage/MoproReactNativePackageModule.kt" target="_blank" rel="noopener noreferrer"><code>MoproReactNativePackageModule.kt</code></a>: loads bindings and bridges via JNI.</li>
</ul>
<p>Similarly, for our <a href="https://github.com/zkmopro/zkemail_flutter_package" target="_blank" rel="noopener noreferrer">zkEmail Flutter package</a>, a comparable set of wrappers is employed:</p>
<ul>
<li>[Dart] <a href="https://github.com/zkmopro/zkemail_flutter_package/blob/main/lib/zkemail_flutter_package.dart" target="_blank" rel="noopener noreferrer"><code>zkemail_flutter_package.dart</code></a>: defines the public Dart API for the Flutter plugin, invoking methods on the native side via platform channels.</li>
<li>[Swift] <a href="https://github.com/zkmopro/zkemail_flutter_package/blob/main/ios/Classes/ZkemailFlutterPackagePlugin.swift" target="_blank" rel="noopener noreferrer"><code>ZkemailFlutterPackagePlugin.swift</code></a>: calls the underlying Rust-generated Swift bindings.</li>
<li>[Kotlin] <a href="https://github.com/zkmopro/zkemail_flutter_package/blob/main/android/src/main/kotlin/com/zkmopro/zkemail_flutter_package/ZkemailFlutterPackagePlugin.kt" target="_blank" rel="noopener noreferrer"><code>ZkemailFlutterPackagePlugin.kt</code></a>: bridges Dart calls to the Rust-generated Kotlin bindings.</li>
</ul>
<h3 class="anchor anchorWithStickyNavbar_wa2S" id="b-support-for-custom-package-names">b. Support for Custom Package Names<a href="https://zkmopro.org/blog/mopro-native-packages#b-support-for-custom-package-names" class="hash-link" aria-label="Direct link to b. Support for Custom Package Names" title="Direct link to b. Support for Custom Package Names">​</a></h3>
<p>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.</p>
<p>Initial progress was made with updates in <a href="https://github.com/zkmopro/mopro/issues/387" target="_blank" rel="noopener noreferrer">issue#387</a> and a partial fix in <a href="https://github.com/zkmopro/mopro/pull/404" target="_blank" rel="noopener noreferrer">PR#404</a>. Further work to complete this feature is being tracked in <a href="https://github.com/zkmopro/mopro/issues/413" target="_blank" rel="noopener noreferrer">issue#413</a>.</p>
<h2 class="anchor anchorWithStickyNavbar_wa2S" id="whats-next-shaping-mopros-future-together">What's Next: Shaping Mopro's Future Together<a href="https://zkmopro.org/blog/mopro-native-packages#whats-next-shaping-mopros-future-together" class="hash-link" aria-label="Direct link to What's Next: Shaping Mopro's Future Together" title="Direct link to What's Next: Shaping Mopro's Future Together">​</a></h2>
<p>Currently, the Mopro CLI helps you create app templates via the <code>mopro create</code> command, once bindings are generated with <code>mopro build</code>.</p>
<p>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 <code>mopro pack</code>) 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 <a href="https://github.com/zkmopro/mopro/issues/419" target="_blank" rel="noopener noreferrer">issue #419</a>.</p>
<p>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!</p>
<p>If you find it interesting, feel free to reach out to the Mopro team on Telegram: <a href="https://t.me/zkmopro" target="_blank" rel="noopener noreferrer">@zkmopro</a>, or better yet, dive into the codebase and open a PR! We're excited to see what the community builds with Mopro.</p>
<p>Happy proving!</p>]]></content>
        <author>
            <name>Moven Tsai</name>
            <uri>https://github.com/moven0831</uri>
        </author>
        <category label="multi-platform" term="multi-platform"/>
        <category label="native-package" term="native-package"/>
        <category label="zkEmail" term="zkEmail"/>
        <category label="noir" term="noir"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[2025 ETHTaipei Workshop]]></title>
        <id>https://zkmopro.org/blog/2025-ethtaipei-workshop</id>
        <link href="https://zkmopro.org/blog/2025-ethtaipei-workshop"/>
        <updated>2025-03-27T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Overview]]></summary>
        <content type="html"><![CDATA[<h2 class="anchor anchorWithStickyNavbar_wa2S" id="overview">Overview<a href="https://zkmopro.org/blog/2025-ethtaipei-workshop#overview" class="hash-link" aria-label="Direct link to Overview" title="Direct link to Overview">​</a></h2>
<p>This tutorial guides developers through getting started with Mopro and building a native mobile app from scratch. It covers</p>
<ul>
<li>
<p>Setting up an example <a href="https://github.com/zkmopro/circuit-registry/blob/main/multiplier2/multiplier2.circom" target="_blank" rel="noopener noreferrer">multiplier2</a> Circom circuit</p>
<ul>
<li>Starting from <a href="https://zkmopro.org/blog/2025-ethtaipei-workshop#0-prerequisites">0. Prerequisites</a></li>
</ul>
</li>
<li>
<p>Modifying it to use a different circuit, such as <a href="https://github.com/zkmopro/circuit-registry/blob/main/keccak256/keccak256_256_test.circom" target="_blank" rel="noopener noreferrer">keccak256</a></p>
<ul>
<li>Starting from <a href="https://zkmopro.org/blog/2025-ethtaipei-workshop#6-update-circuits">6. Prerequisites</a></li>
</ul>
</li>
<li>
<p>Additionally, we'll integrate the <a href="https://github.com/worldcoin/semaphore-rs" target="_blank" rel="noopener noreferrer">semaphore-rs</a> Rust crate to generate native bindings and run the implementation on both iOS and Android.</p>
</li>
</ul>
<div class="theme-admonition theme-admonition-info admonition_iIk3 alert alert--info"><div class="admonitionHeading_Z8US"><span class="admonitionIcon_SBrw"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>info</div><div class="admonitionContent_S87P"><p>This is a workshop tutorial from <a href="https://ethtaipei.org/" target="_blank" rel="noopener noreferrer">ETHTaipei</a> 2025 in April. If you'd like to follow along and build a native mobile app, please check out this commit: <a href="https://github.com/zkmopro/mopro/tree/085fa41e2e2d0c76036cffceed3661ecd15c5fe7" target="_blank" rel="noopener noreferrer">085fa41</a>.</p></div></div>
<ul>
<li>
<p>We also offer comprehensive iOS and Android tutorials to guide you through the entire process, ensuring you don’t miss anything!</p>
<ul>
<li><strong>iOS</strong></li>
</ul>
<p align="center"><iframe width="560" height="315" src="https://www.youtube.com/embed/qPtKTJU1Xfo?si=1a2sh7t24u17lS4r" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin"></iframe></p>
<ul>
<li><strong>Android</strong></li>
</ul>
<p align="center"><iframe width="560" height="315" src="https://www.youtube.com/embed/P2Cwqrir_4o?si=ta30AFEf1yBA6MAP" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin"></iframe></p>
</li>
</ul>
<h2 class="anchor anchorWithStickyNavbar_wa2S" id="0-prerequisites">0. Prerequisites<a href="https://zkmopro.org/blog/2025-ethtaipei-workshop#0-prerequisites" class="hash-link" aria-label="Direct link to 0. Prerequisites" title="Direct link to 0. Prerequisites">​</a></h2>
<ul>
<li>XCode or Android Studio<!-- -->
<ul>
<li>If you're using Android Studio, ensure that you follow the <a href="https://zkmopro.org/docs/prerequisites/#android-configuration" target="_blank" rel="noopener noreferrer">Android configuration</a> steps and set the <code>ANDROID_HOME</code> environment variable.</li>
</ul>
</li>
<li>Rust and CMake</li>
</ul>
<div class="theme-admonition theme-admonition-info admonition_iIk3 alert alert--info"><div class="admonitionHeading_Z8US"><span class="admonitionIcon_SBrw"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>info</div><div class="admonitionContent_S87P"><p>Documentation: <a href="https://zkmopro.org/docs/prerequisites" target="_blank" rel="noopener noreferrer">https://zkmopro.org/docs/prerequisites</a></p></div></div>
<h2 class="anchor anchorWithStickyNavbar_wa2S" id="1-download-mopro-cli-tool">1. Download Mopro CLI tool<a href="https://zkmopro.org/blog/2025-ethtaipei-workshop#1-download-mopro-cli-tool" class="hash-link" aria-label="Direct link to 1. Download Mopro CLI tool" title="Direct link to 1. Download Mopro CLI tool">​</a></h2>
<p>We offer a convenient command-line tool called <code>mopro</code> to streamline the development process. It functions similarly to tools like <code>npx create-react-app</code> or Foundry, enabling developers to get started quickly and efficiently.</p>
<div class="language-sh codeBlockContainer_ZiiY theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QMo3"><pre tabindex="0" class="prism-code language-sh codeBlock_jfw7 thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_jUhv"><span class="token-line" style="color:#bfc7d5"><span class="token function" style="color:rgb(130, 170, 255)">git</span><span class="token plain"> clone https://github.com/zkmopro/mopro</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token builtin class-name" style="color:rgb(255, 203, 107)">cd</span><span class="token plain"> mopro/cli</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token function" style="color:rgb(130, 170, 255)">cargo</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">install</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(191, 199, 213)">--path</span><span class="token plain"> </span><span class="token builtin class-name" style="color:rgb(255, 203, 107)">.</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token builtin class-name" style="color:rgb(255, 203, 107)">cd</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">..</span><span class="token plain">/</span><span class="token punctuation" style="color:rgb(199, 146, 234)">..</span><br></span></code></pre><div class="buttonGroup_TGb3"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_DrnI" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_ABK0"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_A0fP"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<h2 class="anchor anchorWithStickyNavbar_wa2S" id="2-initialize-a-project-with-mopro-cli">2. Initialize a project with Mopro CLI<a href="https://zkmopro.org/blog/2025-ethtaipei-workshop#2-initialize-a-project-with-mopro-cli" class="hash-link" aria-label="Direct link to 2. Initialize a project with Mopro CLI" title="Direct link to 2. Initialize a project with Mopro CLI">​</a></h2>
<p>The <code>mopro init</code> command helps you create a Rust project designed to generate bindings for both iOS and Android.
This step is similar to running <code>npx create-react-app</code>, so select the directory where you want to create your new app.</p>
<div class="language-sh codeBlockContainer_ZiiY theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QMo3"><pre tabindex="0" class="prism-code language-sh codeBlock_jfw7 thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_jUhv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">mopro init</span><br></span></code></pre><div class="buttonGroup_TGb3"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_DrnI" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_ABK0"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_A0fP"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Start by selecting a name for your project (default: <code>mopro-example-app</code>).</p>
<p>Next, choose the proving system that best fits your needs—Mopro currently supports both <code>circom</code> and <code>halo2</code>. For this example, we’ll be using <code>circom</code>.</p>
<p><img decoding="async" loading="lazy" alt="mopro init" src="https://zkmopro.org/assets/images/mopro-init-15ce2cb3c72622fd11b8638d945b3388.jpg" class="img_KKSl"></p>
<p>Next, navigate to your project directory by running:</p>
<div class="language-sh codeBlockContainer_ZiiY theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QMo3"><pre tabindex="0" class="prism-code language-sh codeBlock_jfw7 thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_jUhv"><span class="token-line" style="color:#bfc7d5"><span class="token builtin class-name" style="color:rgb(255, 203, 107)">cd</span><span class="token plain"> mopro-example-app</span><br></span></code></pre><div class="buttonGroup_TGb3"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_DrnI" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_ABK0"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_A0fP"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<h2 class="anchor anchorWithStickyNavbar_wa2S" id="3-build-rust-bindings-with-mopro-cli">3. Build Rust bindings with mopro CLI<a href="https://zkmopro.org/blog/2025-ethtaipei-workshop#3-build-rust-bindings-with-mopro-cli" class="hash-link" aria-label="Direct link to 3. Build Rust bindings with mopro CLI" title="Direct link to 3. Build Rust bindings with mopro CLI">​</a></h2>
<p><code>mopro build</code> command can help developers build binaries for mobile targets (e.g. iOS and Android devices).</p>
<div class="language-sh codeBlockContainer_ZiiY theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QMo3"><pre tabindex="0" class="prism-code language-sh codeBlock_jfw7 thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_jUhv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">mopro build</span><br></span></code></pre><div class="buttonGroup_TGb3"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_DrnI" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_ABK0"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_A0fP"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<ul>
<li>
<p>Choose <code>debug</code> for faster builds during development or <code>release</code> for optimized performance in production.</p>
</li>
<li>
<p>Select the platforms you want to build for: <code>ios</code>, <code>android</code>, <code>web</code>.</p>
</li>
<li>
<p>Select the architecture for each platform:</p>
<ul>
<li><strong>iOS</strong>:</li>
</ul>
</li>
</ul>
<table><thead><tr><th>Architecture</th><th>Description</th><th>Suggested</th></tr></thead><tbody><tr><td><code>aarch64-apple-ios</code></td><td>For physical iOS devices</td><td>✅</td></tr><tr><td><code>aarch64-apple-ios-sim</code></td><td>For M-series Mac simulators</td><td>✅</td></tr><tr><td><code>x86_64-apple-ios</code></td><td>For Intel-based Mac simulators</td><td>-</td></tr></tbody></table>
<ul>
<li><strong>Android</strong>:</li>
</ul>
<table><thead><tr><th>Architecture</th><th>Description</th><th>Suggested</th></tr></thead><tbody><tr><td><code>x86_64-linux-android</code></td><td>For 64-bit Intel architecture (x86_64)</td><td>✅</td></tr><tr><td><code>i686-linux-android</code></td><td>For 32-bit Intel architecture (x86)</td><td>-</td></tr><tr><td><code>armv7-linux-androideabi</code></td><td>For 32-bit ARM architecture (ARMv7-A)</td><td>-</td></tr><tr><td><code>aarch64-linux-android</code></td><td>For 64-bit ARM architecture (ARMv8-A)</td><td>✅</td></tr></tbody></table>
<p><img decoding="async" loading="lazy" alt="mopro build" src="https://zkmopro.org/assets/images/mopro-build-f1378661def0f1ee18e5d52ee6d65408.jpg" class="img_KKSl"></p>
<div class="theme-admonition theme-admonition-warning admonition_iIk3 alert alert--warning"><div class="admonitionHeading_Z8US"><span class="admonitionIcon_SBrw"><svg viewBox="0 0 16 16"><path fill-rule="evenodd" d="M8.893 1.5c-.183-.31-.52-.5-.887-.5s-.703.19-.886.5L.138 13.499a.98.98 0 0 0 0 1.001c.193.31.53.501.886.501h13.964c.367 0 .704-.19.877-.5a1.03 1.03 0 0 0 .01-1.002L8.893 1.5zm.133 11.497H6.987v-2.003h2.039v2.003zm0-3.004H6.987V5.987h2.039v4.006z"></path></svg></span>warning</div><div class="admonitionContent_S87P"><p>The build process may take a few minutes to complete.</p></div></div>
<p>Next, you will see the following instructions displayed:</p>
<p><img decoding="async" loading="lazy" alt="mopro-build-finish" src="https://zkmopro.org/assets/images/mopro-build-finish-d1bdf80e44ae5a12658564248cbf430a.jpg" class="img_KKSl"></p>
<h2 class="anchor anchorWithStickyNavbar_wa2S" id="4-create-templates-for-mobile-development">4. Create templates for mobile development<a href="https://zkmopro.org/blog/2025-ethtaipei-workshop#4-create-templates-for-mobile-development" class="hash-link" aria-label="Direct link to 4. Create templates for mobile development" title="Direct link to 4. Create templates for mobile development">​</a></h2>
<p><code>mopro create</code> command generates templates for various platforms and integrates bindings into the specified directories.</p>
<div class="language-sh codeBlockContainer_ZiiY theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QMo3"><pre tabindex="0" class="prism-code language-sh codeBlock_jfw7 thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_jUhv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">mopro create</span><br></span></code></pre><div class="buttonGroup_TGb3"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_DrnI" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_ABK0"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_A0fP"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Currently supported platforms:</p>
<ul>
<li>iOS (Xcode project)</li>
<li>Android (Android Studio project)</li>
<li>React Native</li>
<li>Flutter</li>
<li>Web</li>
</ul>
<p>After running the <code>mopro create</code> command, a new folder will be created in the current directory, such as:</p>
<ul>
<li><code>ios</code></li>
<li><code>android</code></li>
<li><code>react-native</code></li>
<li><code>flutter</code></li>
<li><code>web</code> (currently does not support Circom prover)</li>
</ul>
<p>You will then see the following instructions to open the project:</p>
<p><img decoding="async" loading="lazy" alt="mopro-create" src="https://zkmopro.org/assets/images/mopro-create-37df526950ca837bf96f459c00053828.jpg" class="img_KKSl"></p>
<p>If you want to create multiple templates, simply run <code>mopro create</code> again and select a different framework each time.</p>
<p><img decoding="async" loading="lazy" alt="mopro-create-android" src="https://zkmopro.org/assets/images/mopro-create-android-4a7cee681deeaa66291b0dbf93f23796.jpg" class="img_KKSl"></p>
<h2 class="anchor anchorWithStickyNavbar_wa2S" id="5-run-the-app-on-a-devicesimulator">5. Run the app on a device/simulator<a href="https://zkmopro.org/blog/2025-ethtaipei-workshop#5-run-the-app-on-a-devicesimulator" class="hash-link" aria-label="Direct link to 5. Run the app on a device/simulator" title="Direct link to 5. Run the app on a device/simulator">​</a></h2>
<h3 class="anchor anchorWithStickyNavbar_wa2S" id="ios">iOS<a href="https://zkmopro.org/blog/2025-ethtaipei-workshop#ios" class="hash-link" aria-label="Direct link to iOS" title="Direct link to iOS">​</a></h3>
<p>Open the Xcode project by running the following command:</p>
<div class="language-sh codeBlockContainer_ZiiY theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QMo3"><pre tabindex="0" class="prism-code language-sh codeBlock_jfw7 thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_jUhv"><span class="token-line" style="color:#bfc7d5"><span class="token function" style="color:rgb(130, 170, 255)">open</span><span class="token plain"> ios/MoproApp.xcodeproj</span><br></span></code></pre><div class="buttonGroup_TGb3"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_DrnI" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_ABK0"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_A0fP"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Select the target device and run the project by pressing <code>cmd</code> + <code>R</code>.</p>
<p>Alternatively, you can watch this video to see how to run the app.</p>
<p align="center"><iframe width="560" height="315" src="https://www.youtube.com/embed/6TydXwYMQCU?si=9s3B8OVa_eRLzchU&amp;start=100" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin"></iframe></p>
<h3 class="anchor anchorWithStickyNavbar_wa2S" id="android">Android<a href="https://zkmopro.org/blog/2025-ethtaipei-workshop#android" class="hash-link" aria-label="Direct link to Android" title="Direct link to Android">​</a></h3>
<p>Open the Android Studio project by running the following command:</p>
<div class="language-sh codeBlockContainer_ZiiY theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QMo3"><pre tabindex="0" class="prism-code language-sh codeBlock_jfw7 thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_jUhv"><span class="token-line" style="color:#bfc7d5"><span class="token function" style="color:rgb(130, 170, 255)">open</span><span class="token plain"> android </span><span class="token parameter variable" style="color:rgb(191, 199, 213)">-a</span><span class="token plain"> Android</span><span class="token punctuation" style="color:rgb(199, 146, 234)">\</span><span class="token plain"> Studio</span><br></span></code></pre><div class="buttonGroup_TGb3"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_DrnI" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_ABK0"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_A0fP"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Run the project by pressing <code>^</code> + <code>R</code> or <code>ctrl</code> + <code>R</code>.</p>
<p>Alternatively, you can watch this video to see how to run the app.</p>
<p align="center"><iframe width="560" height="315" src="https://www.youtube.com/embed/r6WolEEHuMw?si=Lrvkxt03fnqwaYlK&amp;start=196" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin"></iframe></p>
<h2 class="anchor anchorWithStickyNavbar_wa2S" id="6-update-circuits">6. Update circuits<a href="https://zkmopro.org/blog/2025-ethtaipei-workshop#6-update-circuits" class="hash-link" aria-label="Direct link to 6. Update circuits" title="Direct link to 6. Update circuits">​</a></h2>
<p>This section explains how to update circuits with alternative witness generators and corresponding zkey files. We use the <a href="https://github.com/zkmopro/circuit-registry/blob/main/keccak256/keccak256_256_test.circom" target="_blank" rel="noopener noreferrer">Keccak256 circuit</a> as a reference example here.</p>
<ol>
<li>
<p>Add wasm and zkey file in the <code>test-vectors/circom</code> folder</p>
<ul>
<li>wasm: <a href="https://ci-keys.zkmopro.org/keccak256_256_test.wasm" target="_blank" rel="noopener noreferrer">https://ci-keys.zkmopro.org/keccak256_256_test.wasm</a></li>
<li>zkey: <a href="https://ci-keys.zkmopro.org/keccak256_256_test_final.zkey" target="_blank" rel="noopener noreferrer">https://ci-keys.zkmopro.org/keccak256_256_test_final.zkey</a></li>
</ul>
</li>
<li>
<p>In <code>src/lib.rs</code> file, update the circuit's witness generator function definition.</p>
<div class="language-diff codeBlockContainer_ZiiY theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QMo3"><pre tabindex="0" class="prism-code language-diff codeBlock_jfw7 thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_jUhv"><span class="token-line" style="color:#bfc7d5"><span class="token deleted-sign deleted prefix deleted" style="color:rgb(255, 85, 114)">-</span><span class="token deleted-sign deleted line" style="color:rgb(255, 85, 114)">  rust_witness::witness!(multiplier2);</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token deleted-sign deleted line" style="color:rgb(255, 85, 114)"></span><span class="token inserted-sign inserted prefix inserted" style="color:rgb(195, 232, 141)">+</span><span class="token inserted-sign inserted line" style="color:rgb(195, 232, 141)">  rust_witness::witness!(keccak256256test);</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token inserted-sign inserted line" style="color:rgb(195, 232, 141)"></span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">mopro_ffi::set_circom_circuits! {</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token deleted-sign deleted prefix deleted" style="color:rgb(255, 85, 114)">-</span><span class="token deleted-sign deleted line" style="color:rgb(255, 85, 114)">    ("multiplier2_final.zkey", WitnessFn::RustWitness(multiplier2_witness))</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token deleted-sign deleted line" style="color:rgb(255, 85, 114)"></span><span class="token inserted-sign inserted prefix inserted" style="color:rgb(195, 232, 141)">+</span><span class="token inserted-sign inserted line" style="color:rgb(195, 232, 141)">    ("keccak256_256_test_final.zkey", WitnessFn::RustWitness(keccak256256test_witness))</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token inserted-sign inserted line" style="color:rgb(195, 232, 141)"></span><span class="token plain">}</span><br></span></code></pre><div class="buttonGroup_TGb3"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_DrnI" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_ABK0"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_A0fP"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<div class="theme-admonition theme-admonition-warning admonition_iIk3 alert alert--warning"><div class="admonitionHeading_Z8US"><span class="admonitionIcon_SBrw"><svg viewBox="0 0 16 16"><path fill-rule="evenodd" d="M8.893 1.5c-.183-.31-.52-.5-.887-.5s-.703.19-.886.5L.138 13.499a.98.98 0 0 0 0 1.001c.193.31.53.501.886.501h13.964c.367 0 .704-.19.877-.5a1.03 1.03 0 0 0 .01-1.002L8.893 1.5zm.133 11.497H6.987v-2.003h2.039v2.003zm0-3.004H6.987V5.987h2.039v4.006z"></path></svg></span>warning</div><div class="admonitionContent_S87P"><p>The name should match the lowercase version of the WASM file, with all special characters removed.<br>
e.g.<br>
<code>multiplier2</code> -&gt; <code>multiplier2</code><br>
<code>keccak_256_256_main</code> -&gt; <code>keccak256256main</code><br>
<code>aadhaar-verifier</code> -&gt; <code>aadhaarverifier</code></p></div></div>
</li>
<li>
<p>Similar to <a href="https://zkmopro.org/blog/2025-ethtaipei-workshop#3-build-rust-bindings-with-mopro-cli">Step 3</a>, regenerate the bindings to reflect the updated circuit.</p>
<div class="language-sh codeBlockContainer_ZiiY theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QMo3"><pre tabindex="0" class="prism-code language-sh codeBlock_jfw7 thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_jUhv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">mopro build</span><br></span></code></pre><div class="buttonGroup_TGb3"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_DrnI" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_ABK0"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_A0fP"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
</li>
<li>
<p>Manually update the bindings in the app by replacing the existing ones.</p>
<ul>
<li>
<p><strong>iOS:</strong></p>
<ul>
<li>Replace <code>ios/MoproiOSBindings</code> with <code>MoproiOSBindings</code>.</li>
</ul>
</li>
<li>
<p><strong>Android:</strong></p>
<ul>
<li>
<p>Replace <code>android/app/src/main/jniLibs</code> with <code>MoproAndroidBindings/jniLibs</code></p>
</li>
<li>
<p>Replace <code>android/app/src/main/java/uniffi</code> with <code>MoproAndroidBindings/uniffi</code></p>
</li>
</ul>
</li>
</ul>
<div class="theme-admonition theme-admonition-info admonition_iIk3 alert alert--info"><div class="admonitionHeading_Z8US"><span class="admonitionIcon_SBrw"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>info</div><div class="admonitionContent_S87P"><p>We aim to provide the <code>mopro update</code> CLI tool to assist with updating bindings.
Contributions to this effort are welcome.<a href="https://github.com/zkmopro/mopro/issues/269" target="_blank" rel="noopener noreferrer">https://github.com/zkmopro/mopro/issues/269</a></p></div></div>
</li>
<li>
<p>Copy zkeys to assets</p>
<ul>
<li>
<p><strong>iOS:</strong><br>
Open Xcode, drag in the zkeys you plan to use for proving, then navigate to the project’s <strong>Build Phases</strong>. Under <strong>Copy Bundle Resources</strong>, add each zkey to ensure it's included in the app bundle.</p>
<p>Alternatively, you can watch this video to see how to copy zkey in XCode.</p>
<p align="center"><iframe width="560" height="315" src="https://www.youtube.com/embed/6TydXwYMQCU?si=QvOxlfbOOyX3GpcM&amp;start=53" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin"></iframe></p>
</li>
<li>
<p><strong>Android</strong><br>
Paste the zkey in the assets folder: <code>android/app/src/main/assets</code>.</p>
<p>Alternatively, you can watch this video to see how to copy zkey in XCode.</p>
<p align="center"><iframe width="560" height="315" src="https://www.youtube.com/embed/r6WolEEHuMw?si=aOs7SPz4ajtE1hMP&amp;start=141" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin"></iframe></p>
</li>
</ul>
</li>
<li>
<p>Update circuit input and zkey path</p>
</li>
</ol>
<ul>
<li>
<p>Update <code>zkeyPath</code> to <code>keccak256_256_test_final</code></p>
<ul>
<li><strong>iOS:</strong><br></li>
</ul>
<div class="language-diff codeBlockContainer_ZiiY theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QMo3"><pre tabindex="0" class="prism-code language-diff codeBlock_jfw7 thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_jUhv"><span class="token-line" style="color:#bfc7d5"><span class="token deleted-sign deleted prefix deleted" style="color:rgb(255, 85, 114)">-</span><span class="token deleted-sign deleted line" style="color:rgb(255, 85, 114)"> private let zkeyPath = Bundle.main.path(forResource: "multiplier2_final", ofType: "zkey")!</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token deleted-sign deleted line" style="color:rgb(255, 85, 114)"></span><span class="token inserted-sign inserted prefix inserted" style="color:rgb(195, 232, 141)">+</span><span class="token inserted-sign inserted line" style="color:rgb(195, 232, 141)"> private let zkeyPath = Bundle.main.path(forResource: "keccak256_256_test_final", ofType: "zkey")!</span><br></span></code></pre><div class="buttonGroup_TGb3"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_DrnI" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_ABK0"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_A0fP"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<ul>
<li><strong>Android:</strong><br></li>
</ul>
<div class="language-diff codeBlockContainer_ZiiY theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QMo3"><pre tabindex="0" class="prism-code language-diff codeBlock_jfw7 thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_jUhv"><span class="token-line" style="color:#bfc7d5"><span class="token deleted-sign deleted prefix deleted" style="color:rgb(255, 85, 114)">-</span><span class="token deleted-sign deleted line" style="color:rgb(255, 85, 114)"> val zkeyPath = getFilePathFromAssets("multiplier2_final.zkey")</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token deleted-sign deleted line" style="color:rgb(255, 85, 114)"></span><span class="token inserted-sign inserted prefix inserted" style="color:rgb(195, 232, 141)">+</span><span class="token inserted-sign inserted line" style="color:rgb(195, 232, 141)"> val zkeyPath = getFilePathFromAssets("keccak256_256_test_final.zkey")</span><br></span></code></pre><div class="buttonGroup_TGb3"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_DrnI" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_ABK0"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_A0fP"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
</li>
<li>
<p>Update circuit inputs: <a href="https://ci-keys.zkmopro.org/keccak256.json" target="_blank" rel="noopener noreferrer">https://ci-keys.zkmopro.org/keccak256.json</a></p>
<ul>
<li><strong>iOS:</strong><br></li>
</ul>
<div class="language-diff codeBlockContainer_ZiiY theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QMo3"><pre tabindex="0" class="prism-code language-diff codeBlock_jfw7 thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_jUhv"><span class="token-line" style="color:#bfc7d5"><span class="token deleted-sign deleted prefix deleted" style="color:rgb(255, 85, 114)">-</span><span class="token deleted-sign deleted line" style="color:rgb(255, 85, 114)"> let input_str: String = "{\"b\":[\"5\"],\"a\":[\"3\"]}"</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token deleted-sign deleted line" style="color:rgb(255, 85, 114)"></span><span class="token inserted-sign inserted prefix inserted" style="color:rgb(195, 232, 141)">+</span><span class="token inserted-sign inserted line" style="color:rgb(195, 232, 141)"> let input_str: String = "{\"in\":[\"0\",\"0\",\"1\",\"0\",\"1\",\"1\",\"1\",\"0\",\"1\",\"0\",\"1\",\"0\",\"0\",\"1\",\"1\",\"0\",\"1\",\"1\",\"0\",\"0\",\"1\",\"1\",\"1\",\"0\",\"0\",\"0\",\"1\",\"0\",\"1\",\"1\",\"1\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\"]}"</span><br></span></code></pre><div class="buttonGroup_TGb3"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_DrnI" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_ABK0"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_A0fP"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<ul>
<li><strong>Android:</strong><br></li>
</ul>
<div class="language-diff codeBlockContainer_ZiiY theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QMo3"><pre tabindex="0" class="prism-code language-diff codeBlock_jfw7 thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_jUhv"><span class="token-line" style="color:#bfc7d5"><span class="token deleted-sign deleted prefix deleted" style="color:rgb(255, 85, 114)">-</span><span class="token deleted-sign deleted line" style="color:rgb(255, 85, 114)"> val input_str: String = "{\"b\":[\"5\"],\"a\":[\"3\"]}"</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token deleted-sign deleted line" style="color:rgb(255, 85, 114)"></span><span class="token inserted-sign inserted prefix inserted" style="color:rgb(195, 232, 141)">+</span><span class="token inserted-sign inserted line" style="color:rgb(195, 232, 141)"> val input_str: String = "{\"in\":[\"0\",\"0\",\"1\",\"0\",\"1\",\"1\",\"1\",\"0\",\"1\",\"0\",\"1\",\"0\",\"0\",\"1\",\"1\",\"0\",\"1\",\"1\",\"0\",\"0\",\"1\",\"1\",\"1\",\"0\",\"0\",\"0\",\"1\",\"0\",\"1\",\"1\",\"1\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\"]}"</span><br></span></code></pre><div class="buttonGroup_TGb3"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_DrnI" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_ABK0"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_A0fP"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
</li>
</ul>
<ol start="7">
<li>Then Run the app again like in <a href="https://zkmopro.org/blog/2025-ethtaipei-workshop#5-run-the-app-on-a-devicesimulator">step 5</a>.</li>
</ol>
<h2 class="anchor anchorWithStickyNavbar_wa2S" id="7-update-rust-exported-functions">7. Update Rust exported functions<a href="https://zkmopro.org/blog/2025-ethtaipei-workshop#7-update-rust-exported-functions" class="hash-link" aria-label="Direct link to 7. Update Rust exported functions" title="Direct link to 7. Update Rust exported functions">​</a></h2>
<p>Currently, only <code>generateCircomProof</code> and <code>verifyCircomProof</code> are available with the bindings, but the bindings can be extended to support nearly all Rust functions.</p>
<p>Here is an example demonstrating how to use the Semaphore crate.</p>
<ol>
<li>
<p>Update <code>Cargo.toml</code></p>
<p>Import semaphore crate from: <a href="https://github.com/worldcoin/semaphore-rs" target="_blank" rel="noopener noreferrer">https://github.com/worldcoin/semaphore-rs</a></p>
<div class="theme-admonition theme-admonition-info admonition_iIk3 alert alert--info"><div class="admonitionHeading_Z8US"><span class="admonitionIcon_SBrw"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>info</div><div class="admonitionContent_S87P"><p>We are using this specific commit <a href="https://github.com/worldcoin/semaphore-rs/tree/340d4ada82da830b07041cf2185aa6fd1c4e2967" target="_blank" rel="noopener noreferrer">340d4ad</a> for <code>semaphore-rs</code>.</p></div></div>
<div class="language-toml codeBlockContainer_ZiiY theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockTitle_ignD">Cargo.toml</div><div class="codeBlockContent_QMo3"><pre tabindex="0" class="prism-code language-toml codeBlock_jfw7 thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_jUhv"><span class="token-line" style="color:#bfc7d5"><span class="token key property">semaphore-rs</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> </span><span class="token key property">git</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"https://github.com/worldcoin/semaphore-rs"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token key property">features</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token string" style="color:rgb(195, 232, 141)">"depth_16"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token key property">rev</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"340d4ad"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></span></code></pre><div class="buttonGroup_TGb3"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_DrnI" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_ABK0"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_A0fP"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
</li>
<li>
<p>Define a function to generate semaphore proof</p>
<p><a href="https://github.com/chengggkk/Zuma/blob/master/src/lib.rs" target="_blank" rel="noopener noreferrer">Here</a> is an example to define semaphore <code>prove</code> and <code>verify</code> in <code>src/lib.rs</code></p>
<p>Alternatively, we can create a demo function called <code>semaphore()</code> to run the code from the <a href="https://github.com/worldcoin/semaphore-rs?tab=readme-ov-file#example" target="_blank" rel="noopener noreferrer">README</a>.</p>
<div class="language-rust codeBlockContainer_ZiiY theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockTitle_ignD">src/lib.rs</div><div class="codeBlockContent_QMo3"><pre tabindex="0" class="prism-code language-rust codeBlock_jfw7 thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_jUhv"><span class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">use</span><span class="token plain"> </span><span class="token namespace" style="color:rgb(178, 204, 214)">semaphore_rs</span><span class="token namespace punctuation" style="color:rgb(199, 146, 234)">::</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain">get_supported_depths</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> hash_to_field</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">Field</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token namespace" style="color:rgb(178, 204, 214)">identity</span><span class="token namespace punctuation" style="color:rgb(199, 146, 234)">::</span><span class="token class-name" style="color:rgb(255, 203, 107)">Identity</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">            </span><span class="token namespace" style="color:rgb(178, 204, 214)">poseidon_tree</span><span class="token namespace punctuation" style="color:rgb(199, 146, 234)">::</span><span class="token class-name" style="color:rgb(255, 203, 107)">LazyPoseidonTree</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token namespace" style="color:rgb(178, 204, 214)">protocol</span><span class="token namespace punctuation" style="color:rgb(199, 146, 234)">::</span><span class="token operator" style="color:rgb(137, 221, 255)">*</span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">pub</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">fn</span><span class="token plain"> </span><span class="token function-definition function" style="color:rgb(130, 170, 255)">semaphore</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// generate identity</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">let</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">mut</span><span class="token plain"> secret </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">*</span><span class="token string" style="color:rgb(195, 232, 141)">b"secret"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">let</span><span class="token plain"> id </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">Identity</span><span class="token punctuation" style="color:rgb(199, 146, 234)">::</span><span class="token function" style="color:rgb(130, 170, 255)">from_secret</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token operator" style="color:rgb(137, 221, 255)">&amp;</span><span class="token keyword" style="font-style:italic">mut</span><span class="token plain"> secret</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">None</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// Get the first available tree depth. This is controlled by the crate features.</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">let</span><span class="token plain"> depth </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">get_supported_depths</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token number" style="color:rgb(247, 140, 108)">0</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// generate merkle tree</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">let</span><span class="token plain"> leaf </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">Field</span><span class="token punctuation" style="color:rgb(199, 146, 234)">::</span><span class="token function" style="color:rgb(130, 170, 255)">from</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token number" style="color:rgb(247, 140, 108)">0</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">let</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">mut</span><span class="token plain"> tree </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">LazyPoseidonTree</span><span class="token punctuation" style="color:rgb(199, 146, 234)">::</span><span class="token function" style="color:rgb(130, 170, 255)">new</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">depth</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> leaf</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">derived</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    tree </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> tree</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">update</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token number" style="color:rgb(247, 140, 108)">0</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">&amp;</span><span class="token plain">id</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">commitment</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">let</span><span class="token plain"> merkle_proof </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> tree</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">proof</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token number" style="color:rgb(247, 140, 108)">0</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">let</span><span class="token plain"> root </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> tree</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">root</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// change signal and external_nullifier here</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">let</span><span class="token plain"> signal_hash </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">hash_to_field</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">b"xxx"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">let</span><span class="token plain"> external_nullifier_hash </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">hash_to_field</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">b"appId"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">let</span><span class="token plain"> nullifier_hash </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">generate_nullifier_hash</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token operator" style="color:rgb(137, 221, 255)">&amp;</span><span class="token plain">id</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> external_nullifier_hash</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">let</span><span class="token plain"> proof </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">generate_proof</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token operator" style="color:rgb(137, 221, 255)">&amp;</span><span class="token plain">id</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">&amp;</span><span class="token plain">merkle_proof</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> external_nullifier_hash</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> signal_hash</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">unwrap</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">let</span><span class="token plain"> success </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">verify_proof</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">root</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> nullifier_hash</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> signal_hash</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> external_nullifier_hash</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">&amp;</span><span class="token plain">proof</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> depth</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">unwrap</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token macro property">assert!</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">success</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></span></code></pre><div class="buttonGroup_TGb3"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_DrnI" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_ABK0"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_A0fP"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<div class="theme-admonition theme-admonition-warning admonition_iIk3 alert alert--warning"><div class="admonitionHeading_Z8US"><span class="admonitionIcon_SBrw"><svg viewBox="0 0 16 16"><path fill-rule="evenodd" d="M8.893 1.5c-.183-.31-.52-.5-.887-.5s-.703.19-.886.5L.138 13.499a.98.98 0 0 0 0 1.001c.193.31.53.501.886.501h13.964c.367 0 .704-.19.877-.5a1.03 1.03 0 0 0 .01-1.002L8.893 1.5zm.133 11.497H6.987v-2.003h2.039v2.003zm0-3.004H6.987V5.987h2.039v4.006z"></path></svg></span>warning</div><div class="admonitionContent_S87P"><p>You can also try returning a value; otherwise, nothing will happen after execution.
e.g.</p><div class="language-rust codeBlockContainer_ZiiY theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QMo3"><pre tabindex="0" class="prism-code language-rust codeBlock_jfw7 thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_jUhv"><span class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">pub</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">fn</span><span class="token plain"> </span><span class="token function-definition function" style="color:rgb(130, 170, 255)">semaphore</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">-&gt;</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">bool</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// ...</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> success</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></span></code></pre><div class="buttonGroup_TGb3"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_DrnI" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_ABK0"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_A0fP"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div></div></div>
</li>
<li>
<p>Export the function through UniFFI procedural macros</p>
<p>You can simply use the UniFFI proc-macros (e.g. <code>#[uniffi::export]</code>) to define the function interfaces.</p>
<div class="theme-admonition theme-admonition-info admonition_iIk3 alert alert--info"><div class="admonitionHeading_Z8US"><span class="admonitionIcon_SBrw"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>info</div><div class="admonitionContent_S87P"><p>For more details, refer to the <a href="https://mozilla.github.io/uniffi-rs/latest/proc_macro/index.html" target="_blank" rel="noopener noreferrer">UniFFI documentation</a>.</p></div></div>
<div class="language-diff codeBlockContainer_ZiiY theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QMo3"><pre tabindex="0" class="prism-code language-diff codeBlock_jfw7 thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_jUhv"><span class="token-line" style="color:#bfc7d5"><span class="token inserted-sign inserted prefix inserted" style="color:rgb(195, 232, 141)">+</span><span class="token inserted-sign inserted line" style="color:rgb(195, 232, 141)"> #[uniffi::export]</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token inserted-sign inserted line" style="color:rgb(195, 232, 141)"></span><span class="token plain">pub fn semaphore() {</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">   // generate identity</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">   let mut secret = *b"secret";</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">   ...</span><br></span></code></pre><div class="buttonGroup_TGb3"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_DrnI" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_ABK0"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_A0fP"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
</li>
<li>
<p>Run <code>mopro build</code> again and manually update the bindings for iOS and Android as explained in <a href="https://zkmopro.org/blog/2025-ethtaipei-workshop#6-update-circuits">Step 6</a>.</p>
</li>
<li>
<p>You can now call the <code>semaphore()</code> function you just defined on both iOS and Android. 🎉</p>
</li>
</ol>
<h2 class="anchor anchorWithStickyNavbar_wa2S" id="8-conclusion">8. Conclusion<a href="https://zkmopro.org/blog/2025-ethtaipei-workshop#8-conclusion" class="hash-link" aria-label="Direct link to 8. Conclusion" title="Direct link to 8. Conclusion">​</a></h2>
<ul>
<li>
<p>By following the tutorial, you will learn to create a native mobile ZK app with:</p>
<ul>
<li>A simple circuit</li>
<li>Custom circuits</li>
<li>Custom functions and structs</li>
</ul>
</li>
<li>
<p>Just like with the Semaphore case, this approach can be extended to any Rust crate, as long as you define the input and output types according to the <a href="https://mozilla.github.io/uniffi-rs/latest/proc_macro/index.html" target="_blank" rel="noopener noreferrer">UniFFI documentation</a>.</p>
</li>
<li>
<p>Alternative platforms, such as wasm for web, and frameworks like React Native and Flutter are also supported. Please check out:</p>
<ul>
<li><a href="https://github.com/zkmopro/react-native-app" target="_blank" rel="noopener noreferrer">https://github.com/zkmopro/react-native-app</a></li>
<li><a href="https://github.com/zkmopro/flutter-app" target="_blank" rel="noopener noreferrer">https://github.com/zkmopro/flutter-app</a></li>
</ul>
<p>Or simply run <code>mopro build</code> for these frameworks.</p>
</li>
<li>
<p>There are still many challenges to address, and contributions are highly encouraged. Feel free to explore the issues list.</p>
<ul>
<li><a href="https://github.com/zkmopro/mopro/issues" target="_blank" rel="noopener noreferrer">https://github.com/zkmopro/mopro/issues</a></li>
<li><a href="https://github.com/zkmopro/gpu-acceleration/issues" target="_blank" rel="noopener noreferrer">https://github.com/zkmopro/gpu-acceleration/issues</a></li>
</ul>
</li>
<li>
<p>We encourage developers to build mobile apps, as it helps us enhance the developer experience and gain a deeper understanding of the challenges involved.</p>
</li>
</ul>]]></content>
        <author>
            <name>Vivian Jeng</name>
            <uri>https://github.com/vivianjeng</uri>
        </author>
        <category label="workshop" term="workshop"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Comparison of Circom Provers]]></title>
        <id>https://zkmopro.org/blog/circom-comparison</id>
        <link href="https://zkmopro.org/blog/circom-comparison"/>
        <updated>2025-01-07T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Introduction]]></summary>
        <content type="html"><![CDATA[<h2 class="anchor anchorWithStickyNavbar_wa2S" id="introduction">Introduction<a href="https://zkmopro.org/blog/circom-comparison#introduction" class="hash-link" aria-label="Direct link to Introduction" title="Direct link to Introduction">​</a></h2>
<p>Throughout 2024, we compared various Groth16 provers for Circom. Our goal was to demonstrate that native provers (written in C++ or Rust) outperform <code>snarkjs</code> in terms of speed. Along the way, we uncovered some fascinating insights, which we’re excited to share with you in this post.</p>
<p>To understand a Groth16 prover, let’s break it down into two main components: <strong>witness generation</strong> and <strong>proof generation</strong>.</p>
<p><strong>Witness Generation:</strong> This step involves processing inputs along with witness calculation functions to produce the necessary witness values for a circuit. It's a purely computational step and does not involve any zero-knowledge properties.</p>
<p><strong>Proof Generation:</strong> Once the witness is generated, this step takes the witness and the zkey (generated by <code>snarkjs</code>) to compute the polynomial commitments and produce a succinct zero-knowledge proof.</p>
<p>Ideally, developers should have the flexibility to switch between different witness generation and proof generation implementations. This would allow them to leverage the fastest options available, optimizing performance and enhancing their development experience.</p>
<p>However, each of these tools presents unique challenges. In the following sections, we will delve into these challenges in detail and provide a comparison table for clarity.</p>
<h2 class="anchor anchorWithStickyNavbar_wa2S" id="witness-generation">Witness Generation<a href="https://zkmopro.org/blog/circom-comparison#witness-generation" class="hash-link" aria-label="Direct link to Witness Generation" title="Direct link to Witness Generation">​</a></h2>
<h3 class="anchor anchorWithStickyNavbar_wa2S" id="snarkjs"><code>snarkjs</code><a href="https://zkmopro.org/blog/circom-comparison#snarkjs" class="hash-link" aria-label="Direct link to snarkjs" title="Direct link to snarkjs">​</a></h3>
<ul>
<li><a href="https://github.com/iden3/snarkjs" target="_blank" rel="noopener noreferrer">https://github.com/iden3/snarkjs</a></li>
</ul>
<p><code>snarkjs</code> is one of the most widely used tools for generating Groth16 proofs and witnesses. Written in JavaScript, it runs seamlessly across various environments, including browsers on both desktops and mobile devices. However, it faces performance challenges with large circuits. For instance, an RSA circuit can take around 15 seconds to process, while a more complex circuit like zk-email may require up to a minute to generate a proof. This highlights the need for optimized solutions, such as leveraging mobile-native capabilities and even mobile GPUs, to significantly enhance performance.</p>
<h3 class="anchor anchorWithStickyNavbar_wa2S" id="witnesscalc"><code>witnesscalc</code><a href="https://zkmopro.org/blog/circom-comparison#witnesscalc" class="hash-link" aria-label="Direct link to witnesscalc" title="Direct link to witnesscalc">​</a></h3>
<ul>
<li><a href="https://github.com/0xPolygonID/witnesscalc" target="_blank" rel="noopener noreferrer">https://github.com/0xPolygonID/witnesscalc</a></li>
</ul>
<p><code>witnesscalc</code> is a lightweight, C++-based tool designed for efficient witness generation for circuits compiled with Circom. It offers a faster alternative to JavaScript-based tools like <code>snarkjs</code>. With cross-platform support and compatibility with other ZKP tools, Witnesscalc is ideal for handling performance-sensitive applications and large circuits.</p>
<p>While Witnesscalc performs exceptionally well with circuits such as RSA, Anon Aadhaar, Open Passport, and zkEmail, integrating it into Mopro presents challenges due to its C++ implementation, whereas Mopro is built on Rust. We are actively working to bridge this gap to leverage its performance benefits within the mobile proving ecosystem.</p>
<h3 class="anchor anchorWithStickyNavbar_wa2S" id="wasmer"><code>wasmer</code><a href="https://zkmopro.org/blog/circom-comparison#wasmer" class="hash-link" aria-label="Direct link to wasmer" title="Direct link to wasmer">​</a></h3>
<ul>
<li><a href="https://github.com/arkworks-rs/circom-compat" target="_blank" rel="noopener noreferrer">https://github.com/arkworks-rs/circom-compat</a></li>
</ul>
<p>One option available in Rust is <code>circom-compat</code>, maintained by the Arkworks team. This library uses the <code>.wasm</code> file generated by Circom and relies on the Rust crate <a href="https://github.com/wasmerio/wasmer" target="_blank" rel="noopener noreferrer"><code>wasmer</code></a> to execute the witness generation. However, wasmer doesn’t run natively on devices—it creates a WebAssembly execution environment for the <code>.wasm</code> file. As a result, the performance of wasmer is comparable to the WebAssembly performance of <code>snarkjs</code> running in a browser.</p>
<p>Initially, we encountered memory issues with wasmer during implementation (<a href="https://github.com/zkmopro/mopro/issues/1" target="_blank" rel="noopener noreferrer">issue #1</a>). Later, we discovered that the Apple App Store does not support any wasmer functions or frameworks, making it impossible to publish apps using this solution on the App Store or TestFlight (<a href="https://github.com/zkmopro/mopro/issues/107" target="_blank" rel="noopener noreferrer">issue #107</a>). As a result, we decided to abandon this approach for Mopro.</p>
<h3 class="anchor anchorWithStickyNavbar_wa2S" id="circom-witness-rs"><code>circom-witness-rs</code><a href="https://zkmopro.org/blog/circom-comparison#circom-witness-rs" class="hash-link" aria-label="Direct link to circom-witness-rs" title="Direct link to circom-witness-rs">​</a></h3>
<ul>
<li><a href="https://github.com/philsippl/circom-witness-rs" target="_blank" rel="noopener noreferrer">https://github.com/philsippl/circom-witness-rs</a></li>
</ul>
<p>Another Rust-based option is <code>circom-witness-rs</code>, developed by the Worldcoin team. Unlike solutions that rely on WebAssembly (wasm) output from the Circom compiler, this tool directly utilizes <code>.cpp</code> and <code>.dat</code> files generated by Circom. It employs the <a href="https://github.com/dtolnay/cxx" target="_blank" rel="noopener noreferrer"><code>cxx</code></a> crate to execute functions within the <code>.cpp</code> files, enhanced with optimizations such as dead code elimination. This approach has demonstrated excellent performance, particularly with Semaphore circuits. However, we discovered that it encounters compatibility issues with certain circuits, such as RSA, limiting its applicability for broader use cases.</p>
<h3 class="anchor anchorWithStickyNavbar_wa2S" id="circom-witnesscalc"><code>circom-witnesscalc</code><a href="https://zkmopro.org/blog/circom-comparison#circom-witnesscalc" class="hash-link" aria-label="Direct link to circom-witnesscalc" title="Direct link to circom-witnesscalc">​</a></h3>
<ul>
<li><a href="https://github.com/iden3/circom-witnesscalc" target="_blank" rel="noopener noreferrer">https://github.com/iden3/circom-witnesscalc</a></li>
</ul>
<p>The team at iden3 took over this project and began maintaining it under the name <code>circom-witnesscalc</code>. While it heavily draws inspiration from <code>circom-witness-rs</code>, it inherits the same limitation—it does not support RSA circuits. For more details, refer to the "Unimplemented Features" section in the <a href="https://github.com/iden3/circom-witnesscalc?tab=readme-ov-file#unimplemented-features" target="_blank" rel="noopener noreferrer">README</a>.</p>
<h3 class="anchor anchorWithStickyNavbar_wa2S" id="rust-witness"><code>rust-witness</code><a href="https://zkmopro.org/blog/circom-comparison#rust-witness" class="hash-link" aria-label="Direct link to rust-witness" title="Direct link to rust-witness">​</a></h3>
<ul>
<li><a href="https://github.com/chancehudson/rust-witness" target="_blank" rel="noopener noreferrer">https://github.com/chancehudson/rust-witness</a></li>
</ul>
<p>Currently, Mopro utilizes a tool called <code>rust-witness</code>, developed by a member of the Mopro team. This tool leverages <a href="https://github.com/turbolent/w2c2" target="_blank" rel="noopener noreferrer"><code>w2c2</code></a> to translate WebAssembly (<code>.wasm</code>) files into portable C code. By transpiling <code>.wasm</code> files from Circom into C binaries, rust-witness has demonstrated compatibility across all circuits and platforms tested so far, including desktop, iOS, and Android. Additionally, its performance has shown to be slightly better than that of wasmer.</p>
<h2 class="anchor anchorWithStickyNavbar_wa2S" id="proof-generation">Proof Generation<a href="https://zkmopro.org/blog/circom-comparison#proof-generation" class="hash-link" aria-label="Direct link to Proof Generation" title="Direct link to Proof Generation">​</a></h2>
<h3 class="anchor anchorWithStickyNavbar_wa2S" id="snarkjs-1"><code>snarkjs</code><a href="https://zkmopro.org/blog/circom-comparison#snarkjs-1" class="hash-link" aria-label="Direct link to snarkjs-1" title="Direct link to snarkjs-1">​</a></h3>
<ul>
<li><a href="https://github.com/iden3/snarkjs" target="_blank" rel="noopener noreferrer">https://github.com/iden3/snarkjs</a></li>
</ul>
<p>As mentioned earlier, <code>snarkjs</code> is the most commonly used tool for generating Groth16 proofs. However, its performance still has room for improvement.</p>
<h3 class="anchor anchorWithStickyNavbar_wa2S" id="rapidsnark"><code>rapidsnark</code><a href="https://zkmopro.org/blog/circom-comparison#rapidsnark" class="hash-link" aria-label="Direct link to rapidsnark" title="Direct link to rapidsnark">​</a></h3>
<ul>
<li><a href="https://github.com/iden3/rapidsnark" target="_blank" rel="noopener noreferrer">https://github.com/iden3/rapidsnark</a></li>
</ul>
<p>Rapidsnark, developed by the iden3 team, is an alternative to <code>snarkjs</code> designed to deliver faster Groth16 proof generation. Similar to <code>witnesscalc</code>, it is written in C++. While it shows promising performance, we are still working on integrating it into Mopro.</p>
<h3 class="anchor anchorWithStickyNavbar_wa2S" id="ark-works"><code>ark-works</code><a href="https://zkmopro.org/blog/circom-comparison#ark-works" class="hash-link" aria-label="Direct link to ark-works" title="Direct link to ark-works">​</a></h3>
<ul>
<li><a href="https://github.com/arkworks-rs/circom-compat" target="_blank" rel="noopener noreferrer">https://github.com/arkworks-rs/circom-compat</a></li>
</ul>
<p>The primary Rust-based option is <code>circom-compat</code>, maintained by the Arkworks team. Arkworks is a Rust ecosystem designed for programmable cryptography, deliberately avoiding dependencies on native libraries like <code>gmp</code>. In our experiments, Arkworks has proven to work seamlessly with all circuits and platforms. If you have Rust installed, you can easily execute Groth16 proving using Arkworks without any issues. As a result, Mopro has adopted this approach to generate proofs for cross-platform applications.</p>
<h2 class="anchor anchorWithStickyNavbar_wa2S" id="comparison-table">Comparison Table<a href="https://zkmopro.org/blog/circom-comparison#comparison-table" class="hash-link" aria-label="Direct link to Comparison Table" title="Direct link to Comparison Table">​</a></h2>
<p>Here, we present a table comparing different witness generators and proof generators to provide a clearer understanding of their features and performance.</p>
<p>In this comparison, we use <code>circom-witnesscalc</code> as a representative for both <code>circom-witness-rs</code> and <code>circom-witnesscalc</code>, as they share fundamentally similar implementations and characteristics.</p>
<table><tbody><tr><th>Witness Generator</th><th><a href="https://github.com/iden3/snarkjs" target="_blank" rel="noopener noreferrer"><code>snarkjs</code></a></th><th><a href="https://github.com/0xPolygonID/witnesscalc" target="_blank" rel="noopener noreferrer"><code>witnesscalc</code></a></th><th><a href="https://github.com/arkworks-rs/circom-compat" target="_blank" rel="noopener noreferrer"><code>wasmer</code></a></th><th><a href="https://github.com/iden3/circom-witnesscalc" target="_blank" rel="noopener noreferrer"><code>circom-witnesscalc</code></a></th><th><a href="https://github.com/chancehudson/rust-witness" target="_blank" rel="noopener noreferrer"><code>rust-witness</code></a></th></tr><tr><td><a href="https://zkmopro.org/docs/performance">Performance</a></td><td>slow</td><td>the fastest 🚀</td><td>slow</td><td>sometimes fastest 🚀</td><td>slightly faster than snarkjs</td></tr><tr><td>Supported Circuits</td><td>all</td><td>all</td><td>all</td><td>RSA not supported</td><td>all</td></tr><tr><td>Language</td><td>JavaScript</td><td>C++</td><td>Rust</td><td>Rust</td><td>Rust</td></tr><tr><td>Browser</td><td>✅</td><td>❌</td><td>❌</td><td>❌</td><td>❌</td></tr><tr><td>Desktop</td><td>✅</td><td>✅</td><td>✅</td><td>✅</td><td>✅</td></tr><tr><td>iOS</td><td>✅</td><td>✅</td><td>❌</td><td>✅</td><td>✅</td></tr><tr><td>Android</td><td>✅</td><td>✅</td><td>✅</td><td>✅</td><td>✅</td></tr><tr><td>Mopro Support</td><td>❌</td><td>⚠️ WIP <sup><a href="https://zkmopro.org/blog/circom-comparison#user-content-fn-1-ca0b0e" id="user-content-fnref-1-ca0b0e" data-footnote-ref="true" aria-describedby="footnote-label">1</a></sup></td><td>❌ Abandoned</td><td>⚠️ Possible <sup><a href="https://zkmopro.org/blog/circom-comparison#user-content-fn-2-ca0b0e" id="user-content-fnref-2-ca0b0e" data-footnote-ref="true" aria-describedby="footnote-label">2</a></sup></td><td>✅</td></tr></tbody></table>
<table><tbody><tr><th>Proof Generator</th><th><a href="https://github.com/iden3/snarkjs" target="_blank" rel="noopener noreferrer"><code>snarkjs</code></a></th><th><a href="https://github.com/iden3/rapidsnark" target="_blank" rel="noopener noreferrer"><code>rapidsnark</code></a></th><th><a href="https://github.com/arkworks-rs/circom-compat" target="_blank" rel="noopener noreferrer"><code>arkworks</code></a></th></tr><tr><td><a href="https://zkmopro.org/docs/performance">Performance</a></td><td>slow</td><td>the fastest 🚀</td><td>fast</td></tr><tr><td>Supported Circuits</td><td>all</td><td>all</td><td>all</td></tr><tr><td>Language</td><td>JavaScript</td><td>C++</td><td>Rust</td></tr><tr><td>Browser</td><td>✅</td><td>❌</td><td>✅<sup><a href="https://zkmopro.org/blog/circom-comparison#user-content-fn-3-ca0b0e" id="user-content-fnref-3-ca0b0e" data-footnote-ref="true" aria-describedby="footnote-label">3</a></sup></td></tr><tr><td>Desktop</td><td>✅</td><td>✅</td><td>✅</td></tr><tr><td>iOS</td><td>✅</td><td>✅</td><td>✅</td></tr><tr><td>Android</td><td>✅</td><td>✅</td><td>✅</td></tr><tr><td>Mopro Support</td><td>❌</td><td>⚠️ WIP <sup><a href="https://zkmopro.org/blog/circom-comparison#user-content-fn-4-ca0b0e" id="user-content-fnref-4-ca0b0e" data-footnote-ref="true" aria-describedby="footnote-label">4</a></sup></td><td>✅</td></tr></tbody></table>
<h2 class="anchor anchorWithStickyNavbar_wa2S" id="conclusion">Conclusion<a href="https://zkmopro.org/blog/circom-comparison#conclusion" class="hash-link" aria-label="Direct link to Conclusion" title="Direct link to Conclusion">​</a></h2>
<p>In conclusion, we found that the <code>witnesscalc</code> and <code>rapidsnark</code> stack offers the best performance, but integrating it into Rust presents significant challenges. These tools rely heavily on C++ and native dependencies like <code>gmp</code>, <code>cmake</code>, and <code>nasm</code>. Our goal is to integrate these tools into Rust to make them more accessible for application development. Similar to how <code>snarkjs</code> seamlessly integrates into JavaScript projects like Semaphore and ZuPass, having a Rust-compatible stack would simplify building cross-platform applications. Providing only an executable limits flexibility and usability for developers. In 2025, we are prioritizing efforts to enable seamless integration of these tools into Rust or to provide templates for customized circuits.</p>
<p>We recognize the difficulty in choosing the right tools and are committed to supporting developers in this journey. If you need assistance, feel free to reach out to the Mopro team on Telegram: <a href="https://t.me/zkmopro" target="_blank" rel="noopener noreferrer">@zkmopro</a>.</p>
<!-- -->
<section data-footnotes="true" class="footnotes"><h2 class="anchor anchorWithStickyNavbar_wa2S sr-only" id="footnote-label">Footnotes<a href="https://zkmopro.org/blog/circom-comparison#footnote-label" class="hash-link" aria-label="Direct link to Footnotes" title="Direct link to Footnotes">​</a></h2>
<ol>
<li id="user-content-fn-1-ca0b0e">
<p>We are actively working on integrating <code>witnesscalc</code> into Mopro. Please refer to <a href="https://github.com/zkmopro/mopro/issues/284" target="_blank" rel="noopener noreferrer">issue #284</a> <a href="https://zkmopro.org/blog/circom-comparison#user-content-fnref-1-ca0b0e" data-footnote-backref="" aria-label="Back to reference 1" class="data-footnote-backref">↩</a></p>
</li>
<li id="user-content-fn-2-ca0b0e">
<p>Please refer to <a href="https://github.com/zkmopro/mopro/pull/255" target="_blank" rel="noopener noreferrer">PR #255</a> to see how to use <code>circom-witnesscalc</code> with Mopro. <a href="https://zkmopro.org/blog/circom-comparison#user-content-fnref-2-ca0b0e" data-footnote-backref="" aria-label="Back to reference 2" class="data-footnote-backref">↩</a></p>
</li>
<li id="user-content-fn-3-ca0b0e">
<p><a href="https://github.com/waku-org" target="_blank" rel="noopener noreferrer">waku-org</a> has investigated this approach; however, it does not outperform snarkjs in terms of performance. Please refer to <a href="https://github.com/zkmopro/mopro/issues/202#issuecomment-2236923108" target="_blank" rel="noopener noreferrer">this comment</a> for more details. <a href="https://zkmopro.org/blog/circom-comparison#user-content-fnref-3-ca0b0e" data-footnote-backref="" aria-label="Back to reference 3" class="data-footnote-backref">↩</a></p>
</li>
<li id="user-content-fn-4-ca0b0e">
<p>We are actively working on integrating <code>rapidsnark</code> into Mopro. Please refer to <a href="https://github.com/zkmopro/mopro/issues/285" target="_blank" rel="noopener noreferrer">issue #285</a> <a href="https://zkmopro.org/blog/circom-comparison#user-content-fnref-4-ca0b0e" data-footnote-backref="" aria-label="Back to reference 4" class="data-footnote-backref">↩</a></p>
</li>
</ol>
</section>]]></content>
        <author>
            <name>Vivian Jeng</name>
            <uri>https://github.com/vivianjeng</uri>
        </author>
        <category label="circom" term="circom"/>
        <category label="comparison" term="comparison"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Reflecting on 2024 - The Mopro Retrospective]]></title>
        <id>https://zkmopro.org/blog/2024-mopro-retrospective</id>
        <link href="https://zkmopro.org/blog/2024-mopro-retrospective"/>
        <updated>2025-01-06T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[It has been a remarkable year for the Mopro project. We’ve successfully transitioned from a proof of concept to a ready-to-use solution, attracting significant interest from various projects.]]></summary>
        <content type="html"><![CDATA[<p>It has been a remarkable year for the Mopro project. We’ve successfully transitioned from a proof of concept to a ready-to-use solution, attracting significant interest from various projects.</p>
<p>Here are the milestones we’ve achieved this year, along with key reflections on our journey.</p>
<h3 class="anchor anchorWithStickyNavbar_wa2S" id="optimizing-developer-workflow">Optimizing Developer Workflow<a href="https://zkmopro.org/blog/2024-mopro-retrospective#optimizing-developer-workflow" class="hash-link" aria-label="Direct link to Optimizing Developer Workflow" title="Direct link to Optimizing Developer Workflow">​</a></h3>
<p>We streamlined the development process through significant codebase refactoring. By merging <code>mopro-core</code> and <code>mopro-ffi</code> into a single <code>mopro-ffi</code> folder and consolidating the iOS, Android, and web apps into a <code>test-e2e</code> folder, we reduced folder depth, making it easier for contributors to locate functions.</p>
<p>Additionally, we removed the circuits compilation and trusted setup processes, along with unused toolchain targets. These optimizations have drastically improved our CI workflow, reducing the peak runtime from around 1 hour to just 10 minutes (10 times faster)!</p>
<p>We also enhanced the Mopro CLI, significantly reducing the time required for setup and usage. As mentioned earlier, users no longer need to install unnecessary toolchains or download unused circuits from the Mopro repository.</p>
<p>Looking ahead to 2025, we plan to make the CLI even more accessible by providing precompiled binaries for download, eliminating the need for git clone during installation.</p>
<p>Users can now quickly clone the repository and build an iOS or Android project in just three commands—<code>mopro init</code>, <code>mopro build</code>, and <code>mopro create</code>—all within 3 minutes! For detailed instructions, check out the <a href="https://zkmopro.org/docs/getting-started">Getting Started</a> section.</p>
<h3 class="anchor anchorWithStickyNavbar_wa2S" id="enabling-multi-platform-support">Enabling Multi-Platform Support<a href="https://zkmopro.org/blog/2024-mopro-retrospective#enabling-multi-platform-support" class="hash-link" aria-label="Direct link to Enabling Multi-Platform Support" title="Direct link to Enabling Multi-Platform Support">​</a></h3>
<p>In addition to Swift for iOS and Kotlin for Android, we’ve now created templates for cross-platform frameworks like React Native and Flutter. The CLI has been updated to support these platforms, and the documentation has been refreshed to reflect these enhancements.</p>
<p>Please refer to the following resources:</p>
<ul>
<li><a href="https://zkmopro.org/docs/setup/react-native-setup">React Native Setup</a></li>
<li><a href="https://github.com/zkmopro/react-native-app" target="_blank" rel="noopener noreferrer">React Native App</a></li>
<li><a href="https://zkmopro.org/docs/setup/flutter-setup">Flutter Setup</a></li>
<li><a href="https://github.com/zkmopro/flutter-app" target="_blank" rel="noopener noreferrer">Flutter App</a></li>
</ul>
<p>Additionally, Mopro now supports WASM for web browsers. We provide wasm-bindgen for the Halo2 prover, enabling developers to use the Mopro CLI to generate website templates with bindings. This significantly reduces the time spent navigating the outdated Halo2 tutorial available at <a href="https://zcash.github.io/halo2/user/wasm-port.html" target="_blank" rel="noopener noreferrer">Using halo2 in WASM</a> (It was authored in 2022).</p>
<p>Please refer to the following resources to learn how to use Mopro for building WASM applications for web browsers:</p>
<ul>
<li><a href="https://zkmopro.org/docs/setup/web-wasm-setup">WASM Setup</a></li>
</ul>
<h3 class="anchor anchorWithStickyNavbar_wa2S" id="expanding-compatibility-with-general-rust-functions">Expanding Compatibility with General Rust Functions<a href="https://zkmopro.org/blog/2024-mopro-retrospective#expanding-compatibility-with-general-rust-functions" class="hash-link" aria-label="Direct link to Expanding Compatibility with General Rust Functions" title="Direct link to Expanding Compatibility with General Rust Functions">​</a></h3>
<p>We realized that generating and verifying proofs alone isn’t sufficient for application developers. To address this, we made the Mopro template compatible with any Rust crate or function, allowing developer to extend the FFI interface directly through Rust code.</p>
<p>For instance, if a developer needs a Poseidon hash function but neither Swift nor Kotlin provides a Poseidon hash library, they can integrate a Rust Poseidon crate. First, they define the function API in Rust, such as:</p>
<div class="language-rust codeBlockContainer_ZiiY theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QMo3"><pre tabindex="0" class="prism-code language-rust codeBlock_jfw7 thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_jUhv"><span class="token-line" style="color:#bfc7d5"><span class="token attribute attr-name" style="color:rgb(255, 203, 107)">#[uniffi::export]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">pub</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">fn</span><span class="token plain"> </span><span class="token function-definition function" style="color:rgb(130, 170, 255)">poseidon</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">input</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">Vec</span><span class="token operator" style="color:rgb(137, 221, 255)">&lt;</span><span class="token keyword" style="font-style:italic">u8</span><span class="token operator" style="color:rgb(137, 221, 255)">&gt;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">-&gt;</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">Vec</span><span class="token operator" style="color:rgb(137, 221, 255)">&lt;</span><span class="token keyword" style="font-style:italic">u8</span><span class="token operator" style="color:rgb(137, 221, 255)">&gt;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// Poseidon hash implementation</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></span></code></pre><div class="buttonGroup_TGb3"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_DrnI" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_ABK0"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_A0fP"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>By annotating your function with <code>#[uniffi::export]</code>, UniFFI automatically declares the appropriate FFI type and generates the necessary bindings for Swift, Kotlin.</p>
<p>Once processed, the generated foreign language bindings expose your custom functions seamlessly. You can then call the Poseidon function in your Swift or Kotlin code as if it were a native API, enabling straightforward cross-language integration.</p>
<p>For more details on how UniFFI processes your Rust code to generate these bindings, please refer to the <a href="https://mozilla.github.io/uniffi-rs/latest/proc_macro/index.html" target="_blank" rel="noopener noreferrer">Uniffi - Procedural Macros</a>.</p>
<p>By running <code>mopro build</code> again, the developer can generate Swift and/or Kotlin bindings for the Poseidon hash function. They can then easily call the function in Swift or Kotlin like this:</p>
<div class="language-swift codeBlockContainer_ZiiY theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QMo3"><pre tabindex="0" class="prism-code language-swift codeBlock_jfw7 thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_jUhv"><span class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">let</span><span class="token plain"> hash </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">poseidon</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">input</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> input</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><br></span></code></pre><div class="buttonGroup_TGb3"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_DrnI" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_ABK0"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_A0fP"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>or in kotlin</p>
<div class="language-kotlin codeBlockContainer_ZiiY theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QMo3"><pre tabindex="0" class="prism-code language-kotlin codeBlock_jfw7 thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_jUhv"><span class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">val</span><span class="token plain"> hash </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">poseidon</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">input</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><br></span></code></pre><div class="buttonGroup_TGb3"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_DrnI" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_ABK0"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_A0fP"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Additionally, this approach is compatible with WASM for browsers. You can define a function in Rust as follows:</p>
<div class="language-rust codeBlockContainer_ZiiY theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QMo3"><pre tabindex="0" class="prism-code language-rust codeBlock_jfw7 thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_jUhv"><span class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">use</span><span class="token plain"> </span><span class="token namespace" style="color:rgb(178, 204, 214)">serde_wasm_bindgen</span><span class="token namespace punctuation" style="color:rgb(199, 146, 234)">::</span><span class="token plain">to_value</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">use</span><span class="token plain"> </span><span class="token namespace" style="color:rgb(178, 204, 214)">wasm_bindgen</span><span class="token namespace punctuation" style="color:rgb(199, 146, 234)">::</span><span class="token namespace" style="color:rgb(178, 204, 214)">prelude</span><span class="token namespace punctuation" style="color:rgb(199, 146, 234)">::</span><span class="token operator" style="color:rgb(137, 221, 255)">*</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token attribute attr-name" style="color:rgb(255, 203, 107)">#[wasm_bindgen]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">pub</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">fn</span><span class="token plain"> </span><span class="token function-definition function" style="color:rgb(130, 170, 255)">poseidon</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">input</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">JsValue</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">-&gt;</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">Result</span><span class="token operator" style="color:rgb(137, 221, 255)">&lt;</span><span class="token class-name" style="color:rgb(255, 203, 107)">JsValue</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">JsValue</span><span class="token operator" style="color:rgb(137, 221, 255)">&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// Poseidon function implementation</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token function" style="color:rgb(130, 170, 255)">to_value</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">...</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></span></code></pre><div class="buttonGroup_TGb3"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_DrnI" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_ABK0"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_A0fP"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Then, by running <code>mopro build</code> again with the web target, you can generate the necessary bindings for the web. Once built, you can call the <code>poseidon</code> function directly in JavaScript, making it seamlessly accessible in browser-based applications.</p>
<h3 class="anchor anchorWithStickyNavbar_wa2S" id="the-rise-of-new-zk-mobile-apps">The Rise of New ZK Mobile Apps<a href="https://zkmopro.org/blog/2024-mopro-retrospective#the-rise-of-new-zk-mobile-apps" class="hash-link" aria-label="Direct link to The Rise of New ZK Mobile Apps" title="Direct link to The Rise of New ZK Mobile Apps">​</a></h3>
<p>This year, we’ve seen a growing number of ZK mobile apps being developed. Some notable examples include:</p>
<ol>
<li><a href="https://github.com/worldcoin/idkit-swift" target="_blank" rel="noopener noreferrer">World ID</a></li>
<li><a href="https://github.com/anon-aadhaar/anon-aadhaar-react-native" target="_blank" rel="noopener noreferrer">Anon Aadhaar</a></li>
<li><a href="https://github.com/zk-passport/openpassport" target="_blank" rel="noopener noreferrer">Open Passport</a></li>
<li><a href="https://github.com/mynawallet" target="_blank" rel="noopener noreferrer">Myna Wallet</a></li>
<li><a href="https://github.com/rarimo/FreedomTool" target="_blank" rel="noopener noreferrer">FreedomTool</a></li>
</ol>
<p>These apps benefit significantly from mobile-native proving compared to using tools like snarkjs. For instance, Anon Aadhaar achieves up to <em>8x</em> faster performance with <a href="https://github.com/iden3/rapidsnark" target="_blank" rel="noopener noreferrer">rapidsnark</a> compared to <a href="https://github.com/iden3/snarkjs" target="_blank" rel="noopener noreferrer">snarkjs</a>.</p>
<p>For more details on the benchmarks, please refer to the <a href="https://zkmopro.org/docs/performance">benchmark section</a>.</p>
<p>While we’ve provided the Mopro stack with <code>rust-witness</code> and <code>ark-works</code>, most applications are leveraging the <code>witnesscalc</code> and <code>rapidsnark</code> stack for faster proving, particularly with RSA circuits.</p>
<p>Given the adoption trends and benchmark results, we've recognized the need to prioritize improving <code>rapidsnark</code> integration and further enhancing the developer experience. This will be a key focus in Q1 of 2025.</p>
<p>We’re excited to see even more ZK mobile-native apps emerge in the near future, delivering <strong>improved performance</strong> and <strong>enhanced user experiences</strong>.</p>
<h3 class="anchor anchorWithStickyNavbar_wa2S" id="final-thoughts-and-looking-ahead">Final Thoughts and Looking Ahead<a href="https://zkmopro.org/blog/2024-mopro-retrospective#final-thoughts-and-looking-ahead" class="hash-link" aria-label="Direct link to Final Thoughts and Looking Ahead" title="Direct link to Final Thoughts and Looking Ahead">​</a></h3>
<p>The Mopro tool has become more robust, now supporting multiple platforms. However, our vision extends further—we aim to develop a mobile-native ecosystem as comprehensive and developer-friendly as the JavaScript/TypeScript ecosystem, empowering developers to seamlessly build innovative apps.</p>
<p>As we look to the future, we encourage developers to explore the opportunities in building ZK mobile applications. By leveraging mobile-native proving, you can create apps that are not only faster but also more accessible to users worldwide. Let’s work together to shape the next wave of ZK technology and bring its benefits to mobile platforms!</p>]]></content>
        <author>
            <name>Vivian Jeng</name>
            <uri>https://github.com/vivianjeng</uri>
        </author>
        <category label="retrospective" term="retrospective"/>
    </entry>
</feed>