paritytech / paritytech/verifiablejs
Enable React Native (iOS/Android) support — evaluate native `verifiable` crate via UniFFI Turbo Modules
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 1
- Forks
- 1
- Avg merge
- 1h 59m
- Merged PRs (30d)
- 4
Description
Goal
Make verifiablejs usable from React Native to build real iOS/Android apps. This issue captures the full investigation, the blockers, every approach considered, and a recommended plan so it can be picked up directly.
TL;DR: You cannot drop the current WASM package into React Native today. The most durable path is not to ship WASM to the device at all — compile the verifiable crate to a native library and bridge it to JS as a Turbo Module, ideally via UniFFI, which can also regenerate the web/Node builds from the same source. Start with a time-boxed spike to de-risk the mobile toolchain.
Why the current package doesn't work in React Native
The package ships two wasm-pack targets; both hard-depend on things Hermes (RN's default engine) doesn't provide:
- No
WebAssemblyruntime in Hermes.pkg-bundler/verifiablejs.js→import * as wasm from "./verifiablejs_bg.wasm"(needs bundler WASM-ESM + aWebAssemblyglobal).pkg-nodejs/verifiablejs.js→require('fs').readFileSync(...)+new WebAssembly.Module(...)(needs Nodefs/path+WebAssembly).- Hermes historically has no
global.WebAssembly(facebook/hermes#429). Native WASM is only just landing in Hermes v1 / React Native 0.84 — bleeding edge, and wasm-bindgen-glue compatibility is unproven.
- Metro doesn't resolve
.wasmimports or Node built-ins out of the box. getrandomneedscrypto.getRandomValues(Cargo.tomlusesgetrandom = { features = ["js"] }); RN has no globalcrypto(would needreact-native-get-random-values).TextEncoder/TextDecoderglobals need polyfilling on older RN.- ~7.3 MB
.wasm— cold-start / bundle cost on-device.
Approaches considered
⭐ A. Native verifiable crate via UniFFI Turbo Module — recommended
Don't ship WASM. Compile the Rust crate natively for mobile and bridge via uniffi-bindgen-react-native (renaming to uniffi-bindgen-javascript).
Why it's actually simpler than the WASM route:
getrandomgets simpler — native targets use the OS RNG directly; drop thejsfeature and the polyfill.- No Metro
.wasmhandling, noWebAssemblyglobal, no 7.3 MB blob at cold start. - Native speed for the heavy ring-VRF proving, on all RN versions (no waiting for RN 0.84).
verifiableis pure-Rust arkworks crypto, no system deps → clean cross-compile.
Bonus: from one UniFFI annotation set, uniffi-bindgen-react-native emits iOS/Android (Turbo Modules), web (still WASM, generated via wasm-bindgen), and Node/Bun (N-API). So this is a plausible single-toolchain future covering web + mobile, not a web-vs-mobile fork.
Cost / risk:
- Re-express the API (
one_shot,validate,validate_with_commitment,sign,verify_signature, key mgmt — seepackages/verifiablejs/src/lib.rs) in UniFFI annotations. API is mostlyUint8Arrayin/out → maps cleanly to UniFFIbytes/records. - New Rust→mobile build & CI:
cargo-ndk(Android),.xcframework(iOS). uniffi-bindgen-react-nativeis relatively young for the JS/RN target.
B. Polygen (AOT wasm2c → C → JSI) — callstackincubator/polygen
Reuses the existing .wasm, AOT-compiled so it runs on iOS (no JIT). Near-native speed.
- ⚠️ Runs the module, not the wasm-bindgen JS glue — still must wire
crypto.getRandomValues/TextEncoder. "Under active development, use at your own risk." RN 0.75+, new arch only. - Good as a fast de-risking spike if we want to prove the existing binary can run at all, but weaker as the long-term answer than A.
C. react-native-webassembly (wasm3 interpreter via JSI) — cawfree/react-native-webassembly
Runs universal .wasm but interpreted → slow. Ring-VRF proving is heavy; likely too slow. Low-priority fallback.
D. Native Hermes WASM (RN 0.84 / Hermes v1)
Cleanest reuse of the existing package eventually, but bleeding-edge; still needs Metro .wasm handling + polyfills, and wasm-bindgen glue on Hermes v1 is unverified. Revisit once 0.84 is stable.
Background: what is UniFFI, and how does it relate to wasm-pack?
UniFFI is Mozilla's multi-language bindings generator for Rust (built for Firefox to share Rust across Swift/Kotlin/Python). You annotate a thin Rust wrapper; it generates idiomatic bindings + C-ABI glue per target.
UniFFI vs wasm-pack:
wasm-pack (today) |
UniFFI + rn/js bindgen | |
|---|---|---|
| Targets | Web + Node (WASM only) | Web (WASM) + Node + iOS + Android native |
| Setup | one command, mature | more setup, mobile build/CI, newer JS/RN tooling |
| JS API control | full wasm-bindgen power |
constrained to UniFFI's cross-language type system |
- Keep
wasm-packwhile web/Node is the whole story — simpler, mature, full control of the JS API shape. Right tool today. - Reach for UniFFI once mobile is a real target — one annotation set → web + node + iOS + Android, and the web output is still WASM, so we lose ~nothing on web while gaining native mobile.
Proposed plan (for a fresh agent)
Phase 0 — Decision spike (time-boxed):
- Confirm
verifiablecross-compiles toaarch64-apple-iosandaarch64-linux-androidcleanly (pure Rust, expected yes). Note any feature-flag/no_std/getrandomadjustments needed. - Stand up a minimal
uniffi-bindgen-react-nativeproof-of-concept wrapping one function (one_shot) end-to-end into a bare RN app on a simulator; measure APK/IPA size delta and proving latency. - (Optional, parallel) Quick Polygen spike to see if the existing
.wasmruns at all — useful data point, not the deliverable.
Phase 1 — Full binding crate (if spike is green):
- Author the UniFFI wrapper covering the full API surface in
packages/verifiablejs/src/lib.rs. - Wire mobile builds:
cargo-ndk(Android),.xcframework(iOS); integrate into CI. - Publish an RN-consumable package (Turbo Module + TS types).
- Evaluate whether to migrate the web/Node builds onto the same UniFFI source of truth or keep
wasm-packin parallel.
Phase 2 — Docs:
- Add a "React Native / mobile" section to the README Platform Support with setup + status.
Open questions
- Do we commit to UniFFI as the single toolchain (web+node+mobile), or keep
wasm-packfor web and add UniFFI only for mobile? - Minimum RN version / new-architecture requirement we're willing to require.
- Any API-shape constraints from UniFFI's type system that would change the current JS ergonomics (current API is byte-array-centric, so likely minimal).
References
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with packages/verifiablejs/src/lib.rs and the one_shot API, then verify native cross-compilation for aarch64-apple-ios and aarch64-linux-android. Build a minimal uniffi-bindgen-react-native proof of concept in a bare React Native app and measure proving latency and package size. Done means the spike has documented toolchain blockers and a decision on whether to proceed with the full binding plan.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- android, ios, react-native, rust
- Domain
- build-system, mobile-dev
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100