SDK Structure
The SDK is split into two packages: a core library (packages/core) that contains all cryptographic logic, and a mobile package (packages/mobile) that adds platform-specific adapters for React Native.
Cross-Platform Strategy
Three subsystems require platform-specific implementations: proof generation, discrete-log solving, and persistent storage. Each is abstracted behind an interface, with platform-appropriate implementations registered at startup.
Proof Generation
| Platform | Implementation | Notes |
|---|---|---|
| iOS | MoPro (native Rust via Expo modules) | Fastest, uses compiled Noir circuits |
| iOS/Android | WebViewMT (multi-threaded WASM in a hidden WebView) | Fallback, requires COOP/COEP headers for SharedArrayBuffer |
| Browser/Node | NoirJS + bb.js (WASM) | Default, no native dependencies |
The adapter interface (NativeProverAdapter) exposes prove(), init(), isReady(), and destroy(). If a native adapter is registered, the SDK uses it; otherwise it falls back to WASM.
Discrete-Log Solver
| Platform | Implementation | Notes |
|---|---|---|
| iOS | Native Rust via Expo modules | Uses precomputed tame DP tables |
| Browser | WASM, multi-threaded if SharedArrayBuffer available | Falls back to cooperative single-threaded mode |
| Node | WASM (node-specific build) | Direct import |
The adapter interface (NativeSolverAdapter) exposes init(), solve(), and dispose().
Key Storage
| Platform | Implementation |
|---|---|
| iOS | MMKV (encrypted persistent storage via react-native-mmkv) |
| Browser | localStorage or IndexedDB |
| Node | Filesystem |
| Fallback | In-memory Map |
The StorageAdapter interface exposes get(), set(), delete(), and clear(). The SDK auto-detects the environment and picks the appropriate backend.
Initialization
On mobile, setupMobileEB() detects available native modules and registers the best adapters. On web and Node, the SDK uses WASM implementations directly with no setup needed beyond creating an EBClient instance.