@baerae/zkap-zkp-react-native 0.1.3 → 0.1.5

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.
Files changed (36) hide show
  1. package/README.md +24 -3
  2. package/ZkapReactNative.podspec +42 -0
  3. package/android/CMakeLists.txt +81 -0
  4. package/android/build.gradle +111 -14
  5. package/android/cpp-adapter.cpp +43 -0
  6. package/android/libs/arm64-v8a/libzkap_uniffi_bindings.so +0 -0
  7. package/android/libs/x86_64/libzkap_uniffi_bindings.so +0 -0
  8. package/android/proguard-rules.pro +2 -0
  9. package/android/src/main/AndroidManifest.xml +5 -0
  10. package/android/src/main/java/com/baerae/zkapreactnative/ZkapReactNativeModule.kt +51 -0
  11. package/android/src/main/java/com/baerae/zkapreactnative/ZkapReactNativePackage.kt +34 -0
  12. package/cpp/baerae-zkap-react-native.cpp +17 -0
  13. package/cpp/baerae-zkap-react-native.h +15 -0
  14. package/cpp/generated/zkap_uniffi_bindings.cpp +2154 -0
  15. package/cpp/generated/zkap_uniffi_bindings.hpp +66 -0
  16. package/ios/ZkapReactNative.h +16 -0
  17. package/ios/ZkapReactNative.mm +412 -0
  18. package/ios/ZkapZkp.xcframework/Info.plist +5 -5
  19. package/ios/ZkapZkp.xcframework/ios-arm64/libzkap_uniffi_bindings.a +0 -0
  20. package/ios/ZkapZkp.xcframework/ios-arm64_x86_64-simulator/libzkap_uniffi_bindings.a +0 -0
  21. package/package.json +37 -16
  22. package/src/NativeZkapReactNative.ts +11 -0
  23. package/src/generated/zkap_uniffi_bindings-ffi.ts +150 -0
  24. package/src/generated/zkap_uniffi_bindings.ts +1015 -0
  25. package/src/index.ts +250 -47
  26. package/ubrn.config.yaml +13 -0
  27. package/android/libs/armeabi-v7a/libzkap_uniffi_bindings.so +0 -0
  28. package/android/src/main/java/expo/modules/zkap/ZkapSdkModule.kt +0 -153
  29. package/android/src/main/java/uniffi/zkap_uniffi_bindings/zkap_uniffi_bindings.kt +0 -1566
  30. package/expo-module.config.json +0 -9
  31. package/ios/ZkapSdkModule.podspec +0 -35
  32. package/ios/ZkapSdkModule.swift +0 -147
  33. package/ios/uniffi/zkap_uniffi_bindings.swift +0 -1174
  34. package/ios/uniffi/zkap_uniffi_bindingsFFI.h +0 -567
  35. package/ios/uniffi/zkap_uniffi_bindingsFFI.modulemap +0 -7
  36. package/src/artifact-manager.ts +0 -231
@@ -1,231 +0,0 @@
1
- /**
2
- * artifact-manager — MVP implementation
3
- *
4
- * Included: download, cache path management, SHA256 verification,
5
- * atomic rename, max 3 retries, progress callback
6
- * Excluded: HTTP Range resume, background download, advanced cache cleanup
7
- */
8
-
9
- import * as FileSystem from 'expo-file-system';
10
- import * as Crypto from 'expo-crypto';
11
-
12
- // ──────────────────────────────────────────────────────────────────
13
- // Types
14
- // ──────────────────────────────────────────────────────────────────
15
-
16
- export interface ArtifactManifest {
17
- version: string;
18
- circuit: string;
19
- artifacts: {
20
- proving_key: {
21
- url: string;
22
- sha256: string;
23
- size_bytes: number;
24
- compressed_size_bytes?: number;
25
- };
26
- };
27
- min_sdk_version: string;
28
- max_sdk_version: string;
29
- }
30
-
31
- export interface InitProveArtifactsOptions {
32
- /** URL of the manifest.json that describes the proving key location */
33
- manifestUrl: string;
34
- /**
35
- * Local directory for caching the proving key.
36
- * Defaults to `<FileSystem.cacheDirectory>/zkap/`
37
- */
38
- cacheDir?: string;
39
- /**
40
- * Called periodically during download.
41
- * `downloaded` and `total` are in bytes.
42
- */
43
- onProgress?: (downloaded: number, total: number) => void;
44
- }
45
-
46
- // ──────────────────────────────────────────────────────────────────
47
- // Constants
48
- // ──────────────────────────────────────────────────────────────────
49
-
50
- const MAX_RETRIES = 3;
51
- const RETRY_BASE_DELAY_MS = 1000;
52
-
53
- // ──────────────────────────────────────────────────────────────────
54
- // Public API
55
- // ──────────────────────────────────────────────────────────────────
56
-
57
- /**
58
- * Download (if not cached) and verify the Groth16 proving key.
59
- *
60
- * Returns the local file path to the cached proving key,
61
- * which should be passed to `prove()` as `request.pk_path`.
62
- *
63
- * @throws if download fails after 3 retries, or SHA256 verification fails
64
- */
65
- export async function initProveArtifacts(
66
- options: InitProveArtifactsOptions
67
- ): Promise<string> {
68
- const cacheDir =
69
- (options.cacheDir ?? `${FileSystem.cacheDirectory}zkap/`)
70
- .replace(/^file:\/\//, '');
71
-
72
- // Ensure cache directory exists
73
- await ensureDir(cacheDir);
74
-
75
- // 1. Download manifest
76
- const manifest = await fetchManifest(options.manifestUrl);
77
-
78
- // 2. Determine cache file path (version-namespaced to avoid stale cache)
79
- const pkInfo = manifest.artifacts.proving_key;
80
- const fileName = `zkap-${manifest.version}-pk.bin`;
81
- const pkCachePath = `${cacheDir}${fileName}`;
82
- const pkTmpPath = `${pkCachePath}.tmp`;
83
-
84
- // 3. Check if already cached and valid
85
- const fileInfo = await FileSystem.getInfoAsync(pkCachePath);
86
- if (fileInfo.exists) {
87
- const valid = await verifySha256(pkCachePath, pkInfo.sha256);
88
- if (valid) {
89
- return pkCachePath;
90
- }
91
- // Cache is corrupted — delete and re-download
92
- await FileSystem.deleteAsync(pkCachePath, { idempotent: true });
93
- }
94
-
95
- // 4. Download with retries
96
- await downloadWithRetry({
97
- url: pkInfo.url,
98
- tmpPath: pkTmpPath,
99
- totalBytes: pkInfo.size_bytes,
100
- onProgress: options.onProgress,
101
- maxRetries: MAX_RETRIES,
102
- });
103
-
104
- // 5. Verify SHA256
105
- const valid = await verifySha256(pkTmpPath, pkInfo.sha256);
106
- if (!valid) {
107
- await FileSystem.deleteAsync(pkTmpPath, { idempotent: true });
108
- throw new Error(
109
- '[zkap/artifact-manager] SHA256 verification failed. ' +
110
- 'The downloaded file may be corrupted. Please try again.'
111
- );
112
- }
113
-
114
- // 6. Atomic rename: tmp → final cache path
115
- await FileSystem.moveAsync({ from: pkTmpPath, to: pkCachePath });
116
-
117
- return pkCachePath;
118
- }
119
-
120
- // ──────────────────────────────────────────────────────────────────
121
- // Internal helpers
122
- // ──────────────────────────────────────────────────────────────────
123
-
124
- async function ensureDir(dir: string): Promise<void> {
125
- const info = await FileSystem.getInfoAsync(dir);
126
- if (!info.exists) {
127
- await FileSystem.makeDirectoryAsync(dir, { intermediates: true });
128
- }
129
- }
130
-
131
- async function fetchManifest(url: string): Promise<ArtifactManifest> {
132
- const response = await fetch(url);
133
- if (!response.ok) {
134
- throw new Error(
135
- `[zkap/artifact-manager] Failed to fetch manifest: HTTP ${response.status}`
136
- );
137
- }
138
- return response.json() as Promise<ArtifactManifest>;
139
- }
140
-
141
- interface DownloadOptions {
142
- url: string;
143
- tmpPath: string;
144
- totalBytes: number;
145
- onProgress?: (downloaded: number, total: number) => void;
146
- maxRetries: number;
147
- }
148
-
149
- async function downloadWithRetry(opts: DownloadOptions): Promise<void> {
150
- let lastError: Error | null = null;
151
-
152
- for (let attempt = 1; attempt <= opts.maxRetries; attempt++) {
153
- try {
154
- // Clean up any partial download from a previous attempt
155
- await FileSystem.deleteAsync(opts.tmpPath, { idempotent: true });
156
-
157
- const downloadResumable = FileSystem.createDownloadResumable(
158
- opts.url,
159
- opts.tmpPath,
160
- {},
161
- (progress) => {
162
- if (opts.onProgress) {
163
- opts.onProgress(
164
- progress.totalBytesWritten,
165
- progress.totalBytesExpectedToWrite > 0
166
- ? progress.totalBytesExpectedToWrite
167
- : opts.totalBytes
168
- );
169
- }
170
- }
171
- );
172
-
173
- const result = await downloadResumable.downloadAsync();
174
- if (!result || result.status !== 200) {
175
- throw new Error(
176
- `[zkap/artifact-manager] Download failed with status ${result?.status ?? 'unknown'}`
177
- );
178
- }
179
-
180
- return; // Success
181
- } catch (err) {
182
- lastError = err instanceof Error ? err : new Error(String(err));
183
- if (attempt < opts.maxRetries) {
184
- const delay = RETRY_BASE_DELAY_MS * Math.pow(2, attempt - 1);
185
- await sleep(delay);
186
- }
187
- }
188
- }
189
-
190
- throw new Error(
191
- `[zkap/artifact-manager] Download failed after ${opts.maxRetries} attempts. ` +
192
- `Last error: ${lastError?.message ?? 'unknown'}`
193
- );
194
- }
195
-
196
- async function verifySha256(filePath: string, expectedHex: string): Promise<boolean> {
197
- try {
198
- // Read file as base64, convert to raw binary Uint8Array, then SHA256 the binary.
199
- // NOTE: digestStringAsync hashes the string's UTF-8 bytes, not the file's binary
200
- // content. We must use Crypto.digest(algorithm, Uint8Array) for correct results.
201
- const base64 = await FileSystem.readAsStringAsync(filePath, {
202
- encoding: FileSystem.EncodingType.Base64,
203
- });
204
-
205
- // base64 → raw binary bytes
206
- const binaryStr = atob(base64);
207
- const bytes = new Uint8Array(binaryStr.length);
208
- for (let i = 0; i < binaryStr.length; i++) {
209
- bytes[i] = binaryStr.charCodeAt(i);
210
- }
211
-
212
- // Hash the raw binary
213
- const digestBuffer = await Crypto.digest(
214
- Crypto.CryptoDigestAlgorithm.SHA256,
215
- bytes
216
- );
217
-
218
- // ArrayBuffer → hex string
219
- const digestHex = Array.from(new Uint8Array(digestBuffer))
220
- .map((b) => b.toString(16).padStart(2, '0'))
221
- .join('');
222
-
223
- return digestHex.toLowerCase() === expectedHex.toLowerCase();
224
- } catch {
225
- return false;
226
- }
227
- }
228
-
229
- function sleep(ms: number): Promise<void> {
230
- return new Promise((resolve) => setTimeout(resolve, ms));
231
- }