dop-wallet-v6 1.3.39 → 1.3.41

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,814 @@
1
+ "use strict";
2
+ /* eslint-disable no-bitwise */
3
+ /* eslint-disable no-plusplus */
4
+ /* eslint-disable max-classes-per-file */
5
+ /* eslint-disable camelcase */
6
+ /* eslint-disable import/no-extraneous-dependencies */
7
+ /* eslint-disable @typescript-eslint/strict-boolean-expressions */
8
+ /**
9
+ * React Native Prover - Complete ZK Proof Solution
10
+ *
11
+ * This module provides a complete proof generation solution for React Native
12
+ * that works exactly like snarkjs in Node.js:
13
+ *
14
+ * Node.js snarkjs flow:
15
+ * 1. groth16.fullProve(inputs, wasmPath, zkeyPath)
16
+ * 2. Internally: Load WASM -> Create WitnessCalculator -> Calculate witness -> Generate proof
17
+ *
18
+ * React Native rapidsnark flow (this module):
19
+ * 1. setReactNativeProver(config) - Initialize with rapidsnark + file system
20
+ * 2. DOP Engine calls groth16.fullProveDop(inputs, wasm, zkey)
21
+ * 3. Internally: Calculate witness using WASM -> Save files -> Call rapidsnark -> Return proof
22
+ *
23
+ * Key components:
24
+ * - CircuitArtifactManager: Downloads and stores circuit files (WASM, zkey) locally
25
+ * - WitnessGenerator: Calculates witness from inputs using WASM (like circom_runtime)
26
+ * - RapidsnarkProver: Generates proof using witness and zkey
27
+ */
28
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
29
+ if (k2 === undefined) k2 = k;
30
+ var desc = Object.getOwnPropertyDescriptor(m, k);
31
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
32
+ desc = { enumerable: true, get: function() { return m[k]; } };
33
+ }
34
+ Object.defineProperty(o, k2, desc);
35
+ }) : (function(o, m, k, k2) {
36
+ if (k2 === undefined) k2 = k;
37
+ o[k2] = m[k];
38
+ }));
39
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
40
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
41
+ }) : function(o, v) {
42
+ o["default"] = v;
43
+ });
44
+ var __importStar = (this && this.__importStar) || function (mod) {
45
+ if (mod && mod.__esModule) return mod;
46
+ var result = {};
47
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
48
+ __setModuleDefault(result, mod);
49
+ return result;
50
+ };
51
+ Object.defineProperty(exports, "__esModule", { value: true });
52
+ exports.hasRNArtifacts = exports.getRNArtifactPath = exports.createRNArtifactStore = exports.createExpoFSInterface = exports.createRNFSInterface = exports.getReactNativeProver = exports.setReactNativeProver = exports.CircuitArtifactManager = exports.calculateWitnessFromWASM = exports.base64ToUint8Array = exports.uint8ArrayToBase64 = void 0;
53
+ const engine_1 = require("../core/engine");
54
+ // ============================================================================
55
+ // Utility Functions
56
+ // ============================================================================
57
+ /**
58
+ * Convert Uint8Array to base64 string (React Native compatible)
59
+ */
60
+ function uint8ArrayToBase64(data) {
61
+ // Use Buffer if available (Node.js/React Native with buffer polyfill)
62
+ if (typeof Buffer !== 'undefined') {
63
+ return Buffer.from(data).toString('base64');
64
+ }
65
+ // Fallback for pure JS environments
66
+ let binary = '';
67
+ const len = data.byteLength;
68
+ for (let i = 0; i < len; i++) {
69
+ binary += String.fromCharCode(data[i]);
70
+ }
71
+ return btoa(binary);
72
+ }
73
+ exports.uint8ArrayToBase64 = uint8ArrayToBase64;
74
+ /**
75
+ * Convert base64 string to Uint8Array (React Native compatible)
76
+ */
77
+ function base64ToUint8Array(base64) {
78
+ // Use Buffer if available
79
+ if (typeof Buffer !== 'undefined') {
80
+ return new Uint8Array(Buffer.from(base64, 'base64'));
81
+ }
82
+ // Fallback for pure JS environments
83
+ const binary = atob(base64);
84
+ const bytes = new Uint8Array(binary.length);
85
+ for (let i = 0; i < binary.length; i++) {
86
+ bytes[i] = binary.charCodeAt(i);
87
+ }
88
+ return bytes;
89
+ }
90
+ exports.base64ToUint8Array = base64ToUint8Array;
91
+ /**
92
+ * Get circuit ID from formatted inputs
93
+ * DOP circuits are named like "3x2" (3 nullifiers, 2 commitments)
94
+ */
95
+ function getCircuitIdFromInputs(inputs) {
96
+ const nullifierCount = inputs.nullifiers?.filter((n) => n !== undefined && n !== null && BigInt(n) !== BigInt(0)).length || 0;
97
+ const commitmentCount = inputs.commitmentsOut?.filter((c) => c !== undefined && c !== null && BigInt(c) !== BigInt(0)).length || 0;
98
+ return `${nullifierCount}x${commitmentCount}`;
99
+ }
100
+ // ============================================================================
101
+ // Witness Calculator (WASM-based, like circom_runtime)
102
+ // ============================================================================
103
+ /**
104
+ * The BN128 prime field used in Groth16
105
+ */
106
+ const BN128_PRIME = BigInt('21888242871839275222246405745257275088548364400416034343698204186575808495617');
107
+ /**
108
+ * FNV-1a hash function for signal names (same as circom_runtime)
109
+ */
110
+ function fnvHash(str) {
111
+ const FNV_OFFSET = BigInt('0xCBF29CE484222325');
112
+ const FNV_PRIME = BigInt('0x100000001B3');
113
+ let hash = FNV_OFFSET;
114
+ for (let i = 0; i < str.length; i++) {
115
+ hash ^= BigInt(str.charCodeAt(i));
116
+ hash = (hash * FNV_PRIME) % (BigInt(1) << BigInt(64));
117
+ }
118
+ return hash;
119
+ }
120
+ /**
121
+ * Convert bigint to 32-bit array (little-endian, like circom_runtime)
122
+ */
123
+ function toArray32(num, size) {
124
+ const result = new Uint32Array(size);
125
+ let temp = num;
126
+ for (let i = 0; i < size; i++) {
127
+ result[i] = Number(temp & BigInt(0xFFFFFFFF));
128
+ temp >>= BigInt(32);
129
+ }
130
+ return result;
131
+ }
132
+ /**
133
+ * Normalize value to prime field (like circom_runtime)
134
+ */
135
+ function normalizeToField(value) {
136
+ let num;
137
+ if (typeof value === 'bigint') {
138
+ num = value;
139
+ }
140
+ else if (typeof value === 'string') {
141
+ // Handle hex strings
142
+ if (value.startsWith('0x')) {
143
+ num = BigInt(value);
144
+ }
145
+ else {
146
+ num = BigInt(value);
147
+ }
148
+ }
149
+ else {
150
+ num = BigInt(value);
151
+ }
152
+ // Normalize to prime field
153
+ num %= BN128_PRIME;
154
+ if (num < BigInt(0)) {
155
+ num += BN128_PRIME;
156
+ }
157
+ return num;
158
+ }
159
+ /**
160
+ * Flatten nested arrays (like circom_runtime)
161
+ */
162
+ function flatArray(arr) {
163
+ const result = [];
164
+ function flatten(item) {
165
+ if (Array.isArray(item)) {
166
+ for (const subItem of item) {
167
+ flatten(subItem);
168
+ }
169
+ }
170
+ else if (typeof item === 'bigint' || typeof item === 'string' || typeof item === 'number') {
171
+ result.push(normalizeToField(item));
172
+ }
173
+ }
174
+ flatten(arr);
175
+ return result;
176
+ }
177
+ /**
178
+ * Create WTNS (witness) binary format
179
+ * This matches the format expected by rapidsnark
180
+ *
181
+ * WTNS format:
182
+ * - 4 bytes: "wtns" magic
183
+ * - 4 bytes: version (2)
184
+ * - 4 bytes: number of sections
185
+ * - Section 1 (header): field info
186
+ * - Section 2 (data): witness values
187
+ */
188
+ function createWTNSBin(witness) {
189
+ const n8 = 32; // 32 bytes per field element (256 bits)
190
+ const witnessSize = witness.length;
191
+ // Calculate total size
192
+ // Header: magic(4) + version(4) + numSections(4) = 12
193
+ // Section 1 header: sectionType(4) + sectionSize(8) = 12
194
+ // Section 1 data: n8(4) + prime(n8) + witnessSize(4) = 4 + 32 + 4 = 40
195
+ // Section 2 header: sectionType(4) + sectionSize(8) = 12
196
+ // Section 2 data: witness values = witnessSize * n8
197
+ const section1Size = 4 + n8 + 4; // n8 size + prime + witness count
198
+ const section2Size = witnessSize * n8;
199
+ const totalSize = 12 + 12 + section1Size + 12 + section2Size;
200
+ const buffer = new ArrayBuffer(totalSize);
201
+ const view = new DataView(buffer);
202
+ const uint8 = new Uint8Array(buffer);
203
+ let offset = 0;
204
+ // Magic "wtns"
205
+ uint8[offset++] = 0x77; // 'w'
206
+ uint8[offset++] = 0x74; // 't'
207
+ uint8[offset++] = 0x6e; // 'n'
208
+ uint8[offset++] = 0x73; // 's'
209
+ // Version (2)
210
+ view.setUint32(offset, 2, true);
211
+ offset += 4;
212
+ // Number of sections (2)
213
+ view.setUint32(offset, 2, true);
214
+ offset += 4;
215
+ // Section 1: Header
216
+ view.setUint32(offset, 1, true); // section type
217
+ offset += 4;
218
+ // Section size as 64-bit
219
+ view.setUint32(offset, section1Size, true);
220
+ offset += 4;
221
+ view.setUint32(offset, 0, true);
222
+ offset += 4;
223
+ // n8 (field element size in bytes)
224
+ view.setUint32(offset, n8, true);
225
+ offset += 4;
226
+ // Prime (BN128 prime, little-endian)
227
+ const primeArray = toArray32(BN128_PRIME, 8);
228
+ for (let i = 0; i < 8; i++) {
229
+ view.setUint32(offset, primeArray[i], true);
230
+ offset += 4;
231
+ }
232
+ // Witness size
233
+ view.setUint32(offset, witnessSize, true);
234
+ offset += 4;
235
+ // Section 2: Data (witness values)
236
+ view.setUint32(offset, 2, true); // section type
237
+ offset += 4;
238
+ // Section size as 64-bit
239
+ view.setUint32(offset, section2Size, true);
240
+ offset += 4;
241
+ view.setUint32(offset, 0, true);
242
+ offset += 4;
243
+ // Write witness values (each as 32-byte little-endian)
244
+ for (const w of witness) {
245
+ const wArray = toArray32(w, 8);
246
+ for (let i = 0; i < 8; i++) {
247
+ view.setUint32(offset, wArray[i], true);
248
+ offset += 4;
249
+ }
250
+ }
251
+ return uint8;
252
+ }
253
+ /**
254
+ * Calculate witness using WASM
255
+ * This is the core function that mimics circom_runtime's WitnessCalculator
256
+ *
257
+ * For React Native, the WASM execution needs special handling.
258
+ * This function provides the interface - the actual WASM execution
259
+ * should be done by a native module or WebAssembly polyfill.
260
+ */
261
+ async function calculateWitnessFromWASM(wasmBuffer, inputs, wasmExecutor) {
262
+ let witness;
263
+ if (wasmExecutor) {
264
+ // Use provided WASM executor
265
+ witness = await wasmExecutor(wasmBuffer, inputs);
266
+ }
267
+ else {
268
+ // Try to use circom_runtime if available
269
+ try {
270
+ const circomRuntime = await Promise.resolve().then(() => __importStar(require('circom_runtime')));
271
+ const witnessCalculator = await circomRuntime.WitnessCalculatorBuilder(wasmBuffer);
272
+ const witnessBin = await witnessCalculator.calculateWTNSBin(inputs);
273
+ // Return directly as it's already in WTNS format
274
+ return {
275
+ witnessBin: new Uint8Array(witnessBin),
276
+ witnessBase64: uint8ArrayToBase64(new Uint8Array(witnessBin)),
277
+ };
278
+ }
279
+ catch {
280
+ throw new Error('WASM execution not available. Please provide a wasmExecutor or ensure circom_runtime is available.');
281
+ }
282
+ }
283
+ // Create WTNS binary from witness array
284
+ const witnessBin = createWTNSBin(witness);
285
+ return {
286
+ witnessBin,
287
+ witnessBase64: uint8ArrayToBase64(witnessBin),
288
+ };
289
+ }
290
+ exports.calculateWitnessFromWASM = calculateWitnessFromWASM;
291
+ // ============================================================================
292
+ // Circuit Artifact Manager
293
+ // ============================================================================
294
+ /**
295
+ * Manages circuit artifacts (WASM, zkey, vkey) on the device
296
+ */
297
+ class CircuitArtifactManager {
298
+ fs;
299
+ artifactDir;
300
+ debug;
301
+ constructor(fs, artifactDir, debug = false) {
302
+ this.fs = fs;
303
+ this.artifactDir = artifactDir || `${fs.documentDirectory}/dop-circuits`;
304
+ this.debug = debug;
305
+ }
306
+ log(message) {
307
+ if (this.debug) {
308
+ console.log(`[CircuitArtifactManager] ${message}`);
309
+ }
310
+ }
311
+ /**
312
+ * Ensure artifact directory exists
313
+ */
314
+ async ensureDir(dir) {
315
+ try {
316
+ if (!(await this.fs.exists(dir))) {
317
+ await this.fs.mkdir(dir);
318
+ this.log(`Created directory: ${dir}`);
319
+ }
320
+ }
321
+ catch {
322
+ // Directory might already exist
323
+ }
324
+ }
325
+ /**
326
+ * Get paths for circuit artifacts
327
+ */
328
+ getArtifactPaths(circuitId) {
329
+ const circuitDir = `${this.artifactDir}/${circuitId}`;
330
+ return {
331
+ wasmPath: `${circuitDir}/circuit.wasm`,
332
+ zkeyPath: `${circuitDir}/circuit.zkey`,
333
+ vkeyPath: `${circuitDir}/vkey.json`,
334
+ circuitId,
335
+ };
336
+ }
337
+ /**
338
+ * Check if circuit artifacts are already stored
339
+ */
340
+ async hasArtifacts(circuitId) {
341
+ const paths = this.getArtifactPaths(circuitId);
342
+ const [hasWasm, hasZkey] = await Promise.all([
343
+ this.fs.exists(paths.wasmPath),
344
+ this.fs.exists(paths.zkeyPath),
345
+ ]);
346
+ return hasWasm && hasZkey;
347
+ }
348
+ /**
349
+ * Store circuit artifacts from buffers
350
+ * Call this after downloading artifacts
351
+ */
352
+ async storeArtifacts(circuitId, wasmBuffer, zkeyBuffer, vkeyJson) {
353
+ const paths = this.getArtifactPaths(circuitId);
354
+ const circuitDir = `${this.artifactDir}/${circuitId}`;
355
+ await this.ensureDir(this.artifactDir);
356
+ await this.ensureDir(circuitDir);
357
+ this.log(`Storing artifacts for circuit ${circuitId}`);
358
+ // Store WASM
359
+ await this.fs.writeFile(paths.wasmPath, uint8ArrayToBase64(wasmBuffer), 'base64');
360
+ this.log(`Stored WASM: ${paths.wasmPath} (${wasmBuffer.byteLength} bytes)`);
361
+ // Store zkey
362
+ await this.fs.writeFile(paths.zkeyPath, uint8ArrayToBase64(zkeyBuffer), 'base64');
363
+ this.log(`Stored zkey: ${paths.zkeyPath} (${zkeyBuffer.byteLength} bytes)`);
364
+ // Store vkey if provided
365
+ if (vkeyJson) {
366
+ await this.fs.writeFile(paths.vkeyPath, JSON.stringify(vkeyJson), 'utf8');
367
+ this.log(`Stored vkey: ${paths.vkeyPath}`);
368
+ }
369
+ return paths;
370
+ }
371
+ /**
372
+ * Store artifacts from the DOP Engine's artifact getter
373
+ * This is called during proof generation when we receive buffers from the engine
374
+ */
375
+ async storeArtifactsFromBuffers(circuitId, wasmOrDat, zkey) {
376
+ const wasmBuffer = wasmOrDat instanceof Uint8Array
377
+ ? wasmOrDat
378
+ : new Uint8Array(wasmOrDat);
379
+ const zkeyBuffer = new Uint8Array(zkey);
380
+ return this.storeArtifacts(circuitId, wasmBuffer, zkeyBuffer);
381
+ }
382
+ /**
383
+ * Load WASM buffer from stored file
384
+ */
385
+ async loadWASM(circuitId) {
386
+ const paths = this.getArtifactPaths(circuitId);
387
+ const base64 = await this.fs.readFile(paths.wasmPath, 'base64');
388
+ return base64ToUint8Array(base64);
389
+ }
390
+ /**
391
+ * Get zkey path for rapidsnark
392
+ */
393
+ getZkeyPath(circuitId) {
394
+ return this.getArtifactPaths(circuitId).zkeyPath;
395
+ }
396
+ /**
397
+ * Clean up artifacts for a circuit
398
+ */
399
+ async removeArtifacts(circuitId) {
400
+ const paths = this.getArtifactPaths(circuitId);
401
+ try {
402
+ await this.fs.unlink(paths.wasmPath);
403
+ }
404
+ catch { /* ignore */ }
405
+ try {
406
+ await this.fs.unlink(paths.zkeyPath);
407
+ }
408
+ catch { /* ignore */ }
409
+ try {
410
+ await this.fs.unlink(paths.vkeyPath);
411
+ }
412
+ catch { /* ignore */ }
413
+ this.log(`Removed artifacts for circuit ${circuitId}`);
414
+ }
415
+ /**
416
+ * Get all stored circuit IDs
417
+ */
418
+ getArtifactDirectory() {
419
+ return this.artifactDir;
420
+ }
421
+ }
422
+ exports.CircuitArtifactManager = CircuitArtifactManager;
423
+ // ============================================================================
424
+ // React Native Prover
425
+ // ============================================================================
426
+ /**
427
+ * React Native Prover Instance
428
+ * Manages the complete proof generation flow
429
+ */
430
+ class ReactNativeProverInstance {
431
+ config;
432
+ artifactManager;
433
+ initialized = false;
434
+ constructor(config) {
435
+ this.config = config;
436
+ this.artifactManager = new CircuitArtifactManager(config.fs, config.artifactDir, config.debug);
437
+ }
438
+ log(message) {
439
+ if (this.config.debug) {
440
+ console.log(`[ReactNativeProver] ${message}`);
441
+ }
442
+ }
443
+ /**
444
+ * Initialize the prover (ensure directories exist)
445
+ */
446
+ async initialize() {
447
+ if (this.initialized)
448
+ return;
449
+ await this.artifactManager.ensureDir(this.config.artifactDir || `${this.config.fs.documentDirectory}/dop-circuits`);
450
+ this.initialized = true;
451
+ this.log('Initialized');
452
+ }
453
+ /**
454
+ * Generate proof using rapidsnark
455
+ * This is the main function that mimics snarkjs.groth16.fullProve
456
+ */
457
+ async generateProof(inputs, wasmBuffer, zkeyBuffer, logger, progressCallback) {
458
+ await this.initialize();
459
+ const circuitId = getCircuitIdFromInputs(inputs);
460
+ this.log(`Generating proof for circuit ${circuitId}`);
461
+ progressCallback?.(5);
462
+ // Step 1: Store artifacts on device (if not already stored)
463
+ logger.debug(`[RN Prover] Step 1: Preparing artifacts for circuit ${circuitId}...`);
464
+ const wasm = wasmBuffer instanceof Uint8Array
465
+ ? wasmBuffer
466
+ : new Uint8Array(wasmBuffer);
467
+ const artifacts = await this.artifactManager.storeArtifactsFromBuffers(circuitId, wasm, zkeyBuffer);
468
+ this.log(`Artifacts stored at: ${artifacts.zkeyPath}`);
469
+ progressCallback?.(20);
470
+ // Step 2: Calculate witness from inputs
471
+ logger.debug('[RN Prover] Step 2: Calculating witness...');
472
+ let witnessResult;
473
+ if (this.config.witnessCalculator) {
474
+ // Use custom witness calculator
475
+ const witnessBin = await this.config.witnessCalculator(wasm, inputs);
476
+ witnessResult = {
477
+ witnessBin,
478
+ witnessBase64: uint8ArrayToBase64(witnessBin),
479
+ };
480
+ }
481
+ else {
482
+ // Use built-in WASM-based calculator
483
+ witnessResult = await calculateWitnessFromWASM(wasm, inputs);
484
+ }
485
+ this.log(`Witness calculated: ${witnessResult.witnessBin.byteLength} bytes`);
486
+ progressCallback?.(50);
487
+ // Step 3: Generate proof with rapidsnark
488
+ logger.debug('[RN Prover] Step 3: Generating proof with rapidsnark...');
489
+ const rapidsnarkResult = await this.config.groth16Prove(artifacts.zkeyPath, witnessResult.witnessBase64);
490
+ this.log('Proof generated successfully');
491
+ progressCallback?.(90);
492
+ // Step 4: Convert to DOP Engine format
493
+ const proof = {
494
+ pi_a: [rapidsnarkResult.proof.a[0], rapidsnarkResult.proof.a[1]],
495
+ pi_b: [
496
+ [rapidsnarkResult.proof.b[0][0], rapidsnarkResult.proof.b[0][1]],
497
+ [rapidsnarkResult.proof.b[1][0], rapidsnarkResult.proof.b[1][1]],
498
+ ],
499
+ pi_c: [rapidsnarkResult.proof.c[0], rapidsnarkResult.proof.c[1]],
500
+ };
501
+ progressCallback?.(100);
502
+ return {
503
+ proof,
504
+ publicSignals: rapidsnarkResult.pub_signals,
505
+ };
506
+ }
507
+ /**
508
+ * Get the artifact manager for manual artifact management
509
+ */
510
+ getArtifactManager() {
511
+ return this.artifactManager;
512
+ }
513
+ }
514
+ // ============================================================================
515
+ // Main Export: setReactNativeProver
516
+ // ============================================================================
517
+ let globalReactNativeProver = null;
518
+ /**
519
+ * Set up React Native prover for DOP Engine
520
+ *
521
+ * This function configures the DOP Engine to use rapidsnark for proof generation
522
+ * on React Native. It works exactly like setSnarkJSGroth16 but uses rapidsnark
523
+ * under the hood.
524
+ *
525
+ * @example
526
+ * ```typescript
527
+ * import { groth16Prove } from 'react-native-rapidsnark';
528
+ * import RNFS from 'react-native-fs';
529
+ * import { setReactNativeProver } from 'new-dop-wallet-v3';
530
+ *
531
+ * // Create file system interface for react-native-fs
532
+ * const fs: RNFileSystem = {
533
+ * writeFile: (path, data, encoding) => RNFS.writeFile(path, data, encoding),
534
+ * readFile: (path, encoding) => RNFS.readFile(path, encoding),
535
+ * exists: RNFS.exists,
536
+ * unlink: RNFS.unlink,
537
+ * mkdir: RNFS.mkdir,
538
+ * documentDirectory: RNFS.DocumentDirectoryPath,
539
+ * cacheDirectory: RNFS.CachesDirectoryPath,
540
+ * };
541
+ *
542
+ * // Initialize React Native prover (call after initDOP)
543
+ * await setReactNativeProver({
544
+ * groth16Prove,
545
+ * fs,
546
+ * debug: true,
547
+ * });
548
+ *
549
+ * // Now all DOP SDK transactions will use rapidsnark automatically!
550
+ * ```
551
+ */
552
+ async function setReactNativeProver(config) {
553
+ const engine = (0, engine_1.getEngine)();
554
+ if (!engine) {
555
+ throw new Error('DOP Engine not initialized. Call initDOP() first.');
556
+ }
557
+ // Create prover instance
558
+ globalReactNativeProver = new ReactNativeProverInstance(config);
559
+ await globalReactNativeProver.initialize();
560
+ console.log('[RN Prover] Setting up React Native prover with rapidsnark');
561
+ // Create groth16 implementation
562
+ const reactNativeGroth16 = {
563
+ fullProve: async (inputs, wasm, zkey, logger) => {
564
+ if (!globalReactNativeProver) {
565
+ throw new Error('React Native prover not initialized');
566
+ }
567
+ if (!wasm) {
568
+ throw new Error('WASM buffer is required for proof generation');
569
+ }
570
+ return globalReactNativeProver.generateProof(inputs, wasm, zkey, logger, undefined);
571
+ },
572
+ /**
573
+ * Verify a proof using rapidsnark's groth16Verify
574
+ * This works like snarkjs.groth16.verify in Node.js
575
+ */
576
+ verify: async (vkey, publicSignals, proof) => {
577
+ // Check if groth16Verify was provided in config
578
+ if (!config.groth16Verify) {
579
+ console.warn('[RN Prover] groth16Verify not provided in config. Cannot verify proof locally.');
580
+ throw new Error('Proof verification requires groth16Verify function. ' +
581
+ 'Pass groth16Verify from react-native-rapidsnark in setReactNativeProver config.');
582
+ }
583
+ try {
584
+ // Convert proof to rapidsnark format
585
+ // rapidsnark expects: proof as JSON string, inputs as JSON string, vkey as JSON string
586
+ const rapidsnarkProof = {
587
+ pi_a: proof.pi_a,
588
+ pi_b: proof.pi_b,
589
+ pi_c: proof.pi_c,
590
+ protocol: 'groth16',
591
+ curve: 'bn128',
592
+ };
593
+ const proofJson = JSON.stringify(rapidsnarkProof);
594
+ const inputsJson = JSON.stringify(publicSignals);
595
+ const vkeyJson = JSON.stringify(vkey);
596
+ const isValid = await config.groth16Verify(proofJson, inputsJson, vkeyJson);
597
+ console.log('[RN Prover] Proof verification result:', isValid);
598
+ return isValid;
599
+ }
600
+ catch (error) {
601
+ console.error('[RN Prover] Proof verification failed:', error);
602
+ throw error;
603
+ }
604
+ },
605
+ };
606
+ // Set on engine
607
+ engine.prover.setSnarkJSGroth16(reactNativeGroth16);
608
+ console.log('[RN Prover] React Native prover configured successfully');
609
+ }
610
+ exports.setReactNativeProver = setReactNativeProver;
611
+ /**
612
+ * Get the global React Native prover instance
613
+ * Useful for accessing the artifact manager directly
614
+ */
615
+ function getReactNativeProver() {
616
+ return globalReactNativeProver;
617
+ }
618
+ exports.getReactNativeProver = getReactNativeProver;
619
+ // ============================================================================
620
+ // Helper: Create file system interfaces
621
+ // ============================================================================
622
+ /**
623
+ * Create RNFileSystem from react-native-fs (RNFS)
624
+ *
625
+ * @example
626
+ * ```typescript
627
+ * import RNFS from 'react-native-fs';
628
+ * const fs = createRNFSInterface(RNFS);
629
+ * ```
630
+ */
631
+ function createRNFSInterface(RNFS) {
632
+ return {
633
+ writeFile: (path, data, encoding) => RNFS.writeFile(path, data, encoding),
634
+ readFile: (path, encoding) => RNFS.readFile(path, encoding),
635
+ exists: RNFS.exists,
636
+ unlink: RNFS.unlink,
637
+ mkdir: (path) => RNFS.mkdir(path, { NSURLIsExcludedFromBackupKey: true }),
638
+ documentDirectory: RNFS.DocumentDirectoryPath,
639
+ cacheDirectory: RNFS.CachesDirectoryPath,
640
+ };
641
+ }
642
+ exports.createRNFSInterface = createRNFSInterface;
643
+ /**
644
+ * Create RNFileSystem from expo-file-system
645
+ *
646
+ * @example
647
+ * ```typescript
648
+ * import * as FileSystem from 'expo-file-system';
649
+ * const fs = createExpoFSInterface(FileSystem);
650
+ * ```
651
+ */
652
+ function createExpoFSInterface(ExpoFS) {
653
+ const docDir = ExpoFS.documentDirectory || '';
654
+ const cacheDir = ExpoFS.cacheDirectory || '';
655
+ return {
656
+ writeFile: async (path, data, encoding) => {
657
+ const options = encoding === 'base64'
658
+ ? { encoding: 'base64' }
659
+ : { encoding: 'utf8' };
660
+ await ExpoFS.writeAsStringAsync(path, data, options);
661
+ },
662
+ readFile: async (path, encoding) => {
663
+ const options = encoding === 'base64'
664
+ ? { encoding: 'base64' }
665
+ : { encoding: 'utf8' };
666
+ return ExpoFS.readAsStringAsync(path, options);
667
+ },
668
+ exists: async (path) => {
669
+ const info = await ExpoFS.getInfoAsync(path);
670
+ return info.exists;
671
+ },
672
+ unlink: (path) => ExpoFS.deleteAsync(path, { idempotent: true }),
673
+ mkdir: (path) => ExpoFS.makeDirectoryAsync(path, { intermediates: true }),
674
+ documentDirectory: docDir,
675
+ cacheDirectory: cacheDir,
676
+ };
677
+ }
678
+ exports.createExpoFSInterface = createExpoFSInterface;
679
+ /**
680
+ * Create an ArtifactStore for React Native that stores files to device storage
681
+ *
682
+ * This allows the SDK's ArtifactDownloader to automatically save artifacts
683
+ * to a location that rapidsnark can access by file path.
684
+ *
685
+ * Use this when initializing the DOP Engine to make artifacts available for rapidsnark.
686
+ *
687
+ * @example
688
+ * ```typescript
689
+ * import RNFS from 'react-native-fs';
690
+ * import { createRNArtifactStore, createRNFSInterface } from 'new-dop-wallet-v3';
691
+ *
692
+ * const fs = createRNFSInterface(RNFS);
693
+ * const artifactStore = createRNArtifactStore(fs);
694
+ *
695
+ * // Pass to ArtifactDownloader when initializing DOP Engine
696
+ * const artifactDownloader = new ArtifactDownloader(artifactStore, false);
697
+ * ```
698
+ */
699
+ function createRNArtifactStore(fs, baseDir) {
700
+ const artifactBaseDir = baseDir || `${fs.documentDirectory}/dop-artifacts`;
701
+ // Ensure base directory exists
702
+ const ensureBaseDir = async () => {
703
+ try {
704
+ if (!(await fs.exists(artifactBaseDir))) {
705
+ await fs.mkdir(artifactBaseDir);
706
+ }
707
+ }
708
+ catch {
709
+ // Directory might already exist
710
+ }
711
+ };
712
+ return {
713
+ /**
714
+ * Get artifact content from device storage
715
+ */
716
+ get: async (path) => {
717
+ const fullPath = `${artifactBaseDir}/${path}`;
718
+ try {
719
+ if (!(await fs.exists(fullPath))) {
720
+ return null;
721
+ }
722
+ // Check if it's a JSON file (vkey)
723
+ if (path.endsWith('.json')) {
724
+ const content = await fs.readFile(fullPath, 'utf8');
725
+ return content;
726
+ }
727
+ // Binary file (zkey, wasm, dat)
728
+ const base64 = await fs.readFile(fullPath, 'base64');
729
+ return Buffer.from(base64, 'base64');
730
+ }
731
+ catch {
732
+ return null;
733
+ }
734
+ },
735
+ /**
736
+ * Store artifact to device storage
737
+ * This is called by SDK's ArtifactDownloader after downloading
738
+ */
739
+ store: async (dir, path, item) => {
740
+ await ensureBaseDir();
741
+ const fullDir = `${artifactBaseDir}/${dir}`;
742
+ const fullPath = `${artifactBaseDir}/${path}`;
743
+ // Ensure directory exists
744
+ try {
745
+ if (!(await fs.exists(fullDir))) {
746
+ await fs.mkdir(fullDir);
747
+ }
748
+ }
749
+ catch {
750
+ // Directory might already exist
751
+ }
752
+ // Store the artifact
753
+ if (typeof item === 'string') {
754
+ // JSON string (vkey)
755
+ await fs.writeFile(fullPath, item, 'utf8');
756
+ }
757
+ else {
758
+ // Binary data (zkey, wasm, dat)
759
+ const base64 = uint8ArrayToBase64(item);
760
+ await fs.writeFile(fullPath, base64, 'base64');
761
+ }
762
+ console.log(`[RN ArtifactStore] Stored artifact: ${path}`);
763
+ },
764
+ /**
765
+ * Check if artifact exists on device
766
+ */
767
+ exists: async (path) => {
768
+ const fullPath = `${artifactBaseDir}/${path}`;
769
+ return fs.exists(fullPath);
770
+ },
771
+ };
772
+ }
773
+ exports.createRNArtifactStore = createRNArtifactStore;
774
+ /**
775
+ * Get the full file path for an artifact stored via RNArtifactStore
776
+ *
777
+ * Use this to get the path for rapidsnark's groth16Prove function
778
+ *
779
+ * @example
780
+ * ```typescript
781
+ * const zkeyPath = getRNArtifactPath(fs, '3x2', 'zkey');
782
+ * const proofResult = await groth16Prove(zkeyPath, witnessBase64);
783
+ * ```
784
+ */
785
+ function getRNArtifactPath(fs, circuitId, artifactType, baseDir) {
786
+ const artifactBaseDir = baseDir || `${fs.documentDirectory}/dop-artifacts`;
787
+ const artifactDir = `artifacts-v2.1/${circuitId}`;
788
+ switch (artifactType) {
789
+ case 'zkey':
790
+ return `${artifactBaseDir}/${artifactDir}/zkey`;
791
+ case 'wasm':
792
+ return `${artifactBaseDir}/${artifactDir}/wasm`;
793
+ case 'vkey':
794
+ return `${artifactBaseDir}/${artifactDir}/vkey.json`;
795
+ case 'dat':
796
+ return `${artifactBaseDir}/${artifactDir}/dat`;
797
+ }
798
+ }
799
+ exports.getRNArtifactPath = getRNArtifactPath;
800
+ /**
801
+ * Check if all artifacts for a circuit are downloaded
802
+ */
803
+ async function hasRNArtifacts(fs, circuitId, baseDir, useNativeArtifacts = false) {
804
+ const zkeyPath = getRNArtifactPath(fs, circuitId, 'zkey', baseDir);
805
+ const wasmOrDatPath = getRNArtifactPath(fs, circuitId, useNativeArtifacts ? 'dat' : 'wasm', baseDir);
806
+ const [hasZkey, hasWasmOrDat] = await Promise.all([
807
+ fs.exists(zkeyPath),
808
+ fs.exists(wasmOrDatPath),
809
+ ]);
810
+ return hasZkey && hasWasmOrDat;
811
+ }
812
+ exports.hasRNArtifacts = hasRNArtifacts;
813
+ // Types and classes are exported where they are defined
814
+ //# sourceMappingURL=react-native-prover.js.map