@heliuslabs/zolana-web-prover 0.2.0-alpha → 0.3.1-alpha

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 (38) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/README.md +29 -11
  3. package/dist/abortable.d.ts +2 -0
  4. package/dist/abortable.js +30 -0
  5. package/dist/errors.js +38 -0
  6. package/dist/index.d.ts +2 -1
  7. package/dist/index.js +5 -909
  8. package/dist/key-digests.js +49 -0
  9. package/dist/key-store.d.ts +67 -0
  10. package/dist/key-store.js +318 -0
  11. package/dist/measurement.js +0 -0
  12. package/dist/proof-requests.js +68 -0
  13. package/dist/prover-fetch.d.ts +18 -0
  14. package/dist/prover-fetch.js +74 -0
  15. package/dist/prover.worker.js +147 -0
  16. package/dist/proving-threads.js +10 -0
  17. package/dist/runtime/accelerator/LICENSE-APACHE +201 -0
  18. package/dist/runtime/accelerator/LICENSE-MIT +19 -0
  19. package/dist/runtime/accelerator/gnark_kernel.d.ts +88 -0
  20. package/dist/runtime/accelerator/gnark_kernel.js +455 -0
  21. package/dist/runtime/accelerator/gnark_kernel_bg.wasm +0 -0
  22. package/dist/runtime/accelerator/snippets/wasm-bindgen-rayon-38edf6e439f6d70d/src/workerHelpers.js +107 -0
  23. package/dist/runtime/runtime-manifest.json +49 -0
  24. package/dist/{dist/bridge → runtime}/zolana-prover.wasm +0 -0
  25. package/dist/scripts/assets.mjs +70 -0
  26. package/dist/scripts/install-keys.mjs +46 -0
  27. package/dist/shapes.d.ts +15 -9
  28. package/dist/shapes.js +86 -0
  29. package/dist/wasm-prover.d.ts +16 -17
  30. package/dist/wasm-prover.js +383 -0
  31. package/package.json +8 -7
  32. package/dist/assets/prover.worker-sn1Mixyo.js +0 -637
  33. package/dist/dist/bridge/manifest.json +0 -23
  34. package/dist/dist/bridge/transfer-2x2.json +0 -1
  35. package/dist/runtime.lock.json +0 -14
  36. package/dist/scripts/setup-assets.mjs +0 -216
  37. package/dist/wasm/prover/provingkeys/proving-keys.lock +0 -531
  38. /package/dist/{dist/bridge → vendor}/wasm_exec.js +0 -0
package/CHANGELOG.md CHANGED
@@ -1,5 +1,31 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.3.1-alpha — 2026-10-20
4
+
5
+ - Published with npm provenance. No code changes.
6
+
7
+ ## 0.3.0-alpha — 2026-10-20
8
+
9
+ The runtime ships in the package: an app installs it with npm, its bundler emits the worker, the Go bridge and the accelerator, and threaded proving works in a Chrome extension page.
10
+
11
+ Breaking
12
+
13
+ - `WasmProverOptions.wasmUrl` is gone; the worker loads the Go bridge and the accelerator from beside itself, where Vite and webpack 5 emit them.
14
+ - `zolana-prover-assets` is now `zolana-prover-keys --output <directory> --keys <names>`, which installs proving keys for self-hosting and nothing else.
15
+
16
+ Changed
17
+
18
+ - Runtime 0.3.2, the 0.3.1 accelerator with Rayon's thread helpers for bundlers: its threads start from files the bundler emits rather than from `blob:` URLs, which an extension page refuses, so 0.2.0-alpha proves there only with `threads: 0`.
19
+ - A thread pool that has not started after 30 s fails initialization with `wasm_init_failed` instead of waiting forever.
20
+ - A key downloads in ranged parts of 8 MB kept in the cache as they arrive, so an interrupted download resumes where it stopped.
21
+ - A kept decoded key is checked by its size instead of hashed on every load, about 0.02–0.05 s less per load after a page reload.
22
+
23
+ Added
24
+
25
+ - `neededKeys(maxInputs, outputs, maxMergeInputs)` names the keys spends and merges up to those limits prove with, for `prefetch`.
26
+ - `prover.provingKeys()` lists every key with the bytes the browser keeps of it and whether its decoded form is kept; `ProvingKeyStatus` is exported.
27
+ - `prover.clearKeys()` removes the kept keys, their decoded forms and interrupted downloads.
28
+
3
29
  ## 0.2.0-alpha — 2026-10-20
4
30
 
5
31
  The first release. `ZolanaWebProver` proves `@heliuslabs/zolana` 0.4.0-alpha transfer and merge requests in a browser worker with the threaded accelerator of runtime 0.3.1, verifies each proof before it returns it, and answers the SDK's `/prove` requests in the page through `createFetch()`. A warm proof takes 0.31 s for two notes to two outputs and 0.97 s for eight, in Chrome at four threads on an Apple M5 Pro.
package/README.md CHANGED
@@ -2,23 +2,32 @@
2
2
 
3
3
  Local Groth16 proving and gnark verification in a browser worker. The core package has no protocol SDK or Solana dependencies. Transaction building, submission and benchmark orchestration live in the repository's browser example, not this package.
4
4
 
5
- ## Install and serve assets
5
+ ## Install
6
6
 
7
7
  ```sh
8
8
  npm install @heliuslabs/zolana-web-prover
9
- npx --no-install zolana-prover-assets --output public --keys none
10
9
  ```
11
10
 
12
- The package contains the worker, the rebuilt Go Wasm bridge and its matching runtime shim. Proving keys and the threaded accelerator stay outside the core package. Keys load on first use from the pinned key set on the Zolana key CDN, which serves them with CORS, and are checked against the size and SHA-256 bundled in the package, so an app installs none. The asset command installs the bundled, sanitized Go bridge and sample request plus the pinned accelerator into your app's public directory; without `--keys none` it also installs the 2-input/2-output key for self-hosting. It checks the bundled bridge's manifest and verifies the release manifest's SHA-256 and size, then each downloaded file and key against the packaged lockfiles. It never installs the older Go bridge, shim or sample request from that release. It needs Node.js and network access, but no Go or Rust. Installation itself does not run downloads. For a local mirror, set `ZOLANA_RUNTIME_BASE_URL` and `ZOLANA_KEYS_BASE_URL` to `file:///.../` directories containing the release assets and keys respectively; the same digest checks apply.
11
+ The package contains the worker, the sanitized Go Wasm bridge with its runtime shim, and the threaded accelerator. Import it, and the app's bundler emits them as files beside the worker; the packed-consumer CI builds an app with Vite and with webpack 5 and proves from both. A bundler that does not emit `new URL(…, import.meta.url)` assets and nested module workers (esbuild and Rollup without plugins) cannot load the runtime. Keys load on first use from the pinned key set on the Zolana key CDN, which serves them with CORS, and are checked against the size and SHA-256 bundled in the package, so an app installs none.
13
12
 
14
- Serve `public/prover`, `public/keys` if you self-host keys, and, for the demo, `public/fixtures` without flattening the accelerator's `snippets` directory. Serve `.wasm` as `application/wasm`, `.js` as JavaScript, and the document with:
13
+ Serve the document with:
15
14
 
16
15
  ```text
17
16
  Cross-Origin-Opener-Policy: same-origin
18
17
  Cross-Origin-Embedder-Policy: require-corp
19
18
  ```
20
19
 
21
- Use HTTPS (localhost is suitable for development) and a bundler that preserves the emitted module worker asset URL; the packed-consumer CI tests Vite's production build. The accelerator must remain beside `zolana-prover.wasm` at `accelerator/gnark_kernel.js`. These headers are required for threaded proving. Set `threads: 0` for Go-only proving without cross-origin isolation. Apply compatible CORS/CORP policies if you host assets on another origin. Every key is checked against the size and SHA-256 bundled in the package from the pinned proving-keys lockfile, so the key host does not need to be trusted for integrity.
20
+ Use HTTPS (localhost is suitable for development). These headers are required for threaded proving; set `threads: 0` for Go-only proving without cross-origin isolation. Every key is checked against the size and SHA-256 bundled in the package from the pinned proving-keys lockfile, so the key host does not need to be trusted for integrity.
21
+
22
+ In a Chrome extension, prove from an extension page; an extension's service worker cannot start workers. Give the manifest the same isolation and allow WebAssembly:
23
+
24
+ ```json
25
+ "cross_origin_embedder_policy": { "value": "require-corp" },
26
+ "cross_origin_opener_policy": { "value": "same-origin" },
27
+ "content_security_policy": { "extension_pages": "script-src 'self' 'wasm-unsafe-eval'; object-src 'self'" }
28
+ ```
29
+
30
+ The packed-consumer CI proves from such a page with Go and with threads.
22
31
 
23
32
  ## Prove locally
24
33
 
@@ -26,7 +35,6 @@ Use HTTPS (localhost is suitable for development) and a bundler that preserves t
26
35
  import { ZolanaWebProver, WasmProverError } from "@heliuslabs/zolana-web-prover";
27
36
 
28
37
  const prover = new ZolanaWebProver({
29
- wasmUrl: new URL("/prover/zolana-prover.wasm", location.href).href,
30
38
  proverUrl: "https://local-prover.invalid",
31
39
  });
32
40
 
@@ -44,15 +52,17 @@ try {
44
52
 
45
53
  ## Self-host proving keys
46
54
 
47
- To serve keys yourself, for offline use, a mirror or your own CDN, install the shapes your application's requests need and pass their location as `keyBaseUrl` (for example `keyBaseUrl: "/keys"`). Without `--keys`, the asset command installs only the demo's 2x2 key; real transfer shapes may differ (for example, 1x2):
55
+ To serve keys yourself, for offline use, a mirror or your own CDN, install the shapes your application's requests need and pass their location as `keyBaseUrl` (for example `keyBaseUrl: "/keys"`):
48
56
 
49
57
  ```sh
50
- npx --no-install zolana-prover-assets --output public --keys transfer_confidential_1_2.key,transfer_confidential_2_2.key
58
+ npx --no-install zolana-prover-keys --output public/keys --keys transfer_confidential_1_2.key,transfer_confidential_2_2.key
51
59
  ```
52
60
 
53
- `--keys` replaces the default selection. Names must be confidential-transfer or merge keys present in the pinned proving-keys lockfile; arbitrary names, paths and unsupported circuits are rejected before installation. Bytes still undergo size and SHA-256 checks. Use `keyForProveRequest` or `observeProofRequests` to identify needed shapes without logging witness bodies. A missing key fails rather than substituting a different circuit. Previously downloaded files are not deleted when selecting a new list.
61
+ Names must be confidential-transfer or merge keys present in the pinned proving-keys lockfile; arbitrary names, paths and unsupported circuits are rejected before installation. Bytes still undergo size and SHA-256 checks. Use `keyForProveRequest` or `observeProofRequests` to identify needed shapes without logging witness bodies. A missing key fails rather than substituting a different circuit. Previously downloaded files are not deleted when selecting a new list. The command needs Node.js and network access; for a local mirror of the key set, set `ZOLANA_KEYS_BASE_URL` to a `file:///.../` directory, and the same checks apply.
62
+
63
+ Keys are 9–362 MB each for confidential transfers (16 MB for 2x2, 94 MB for 12x8) and 56–380 MB for merge; deserialized circuits and proving work need additional memory. Only one deserialized key is retained, and changing shapes reloads it. The first load of a shape decompresses the key's curve points on the accelerator's thread pool (1.4 s for 2x2 and 4.9 s for 8x2 in Chrome at four threads on an Apple M5 Pro; slower with `threads: 0`, where Go decompresses them) and stores the decoded raw form in the browser Cache API in place of the downloaded file; later loads, including after a reload, read the raw form in 0.15 s (2x2) and 0.5 s (8x2), plus about 0.15 s to read it from the cache; it is checked by size, not hashed again, since a damaged entry fails its load and is rebuilt from the pinned key. The raw form is about 1.6× the file's size, and storage is subject to the browser's quota. Keys live in the Cache API store `zolana-proving-keys-<key set>`, and stores left by other key sets are deleted on first use. Pass `persistStorage: true` to ask the browser not to evict them under storage pressure (`navigator.storage.persist()`; Firefox asks the user). Install only the shapes you use, and budget separately for download/storage size and runtime memory.
54
64
 
55
- Keys are 9–362 MB each for confidential transfers (16 MB for 2x2, 94 MB for 12x8) and 56–380 MB for merge; deserialized circuits and proving work need additional memory. Only one deserialized key is retained, and changing shapes reloads it. The first load of a shape decompresses the key's curve points on the accelerator's thread pool (1.4 s for 2x2 and 4.9 s for 8x2 in Chrome at four threads on an Apple M5 Pro; slower with `threads: 0`, where Go decompresses them) and stores the decoded raw form in the browser Cache API in place of the downloaded file; later loads, including after a reload, read the raw form in 0.15 s (2x2) and 0.5 s (8x2), plus about 0.2 s to read and check it. The raw form is about 1.6× the file's size, and storage is subject to the browser's quota. Keys live in the Cache API store `zolana-proving-keys-<key set>`, and stores left by other key sets are deleted on first use. Pass `persistStorage: true` to ask the browser not to evict them under storage pressure (`navigator.storage.persist()`; Firefox asks the user). Install only the shapes you use, and budget separately for download/storage size and runtime memory.
65
+ A key downloads in ranged parts of 8 MB, each kept in the cache as it arrives, so a download that a closed tab, a lost connection or an abort interrupted resumes where it stopped; a host that ignores ranges sends the whole key instead. The key is checked against the lockfile once it is whole, and a download that resumed from a damaged part starts over once.
56
66
 
57
67
  ## Prefetch keys
58
68
 
@@ -67,6 +77,14 @@ await prover.prefetch({
67
77
 
68
78
  `stage` is `download` while bytes arrive and `decode` once the worker starts loading the key. Pass `onKeyProgress` to the constructor to receive the same events for every load, including the ones a proof triggers. Without the Cache API only the last prefetched shape stays loaded.
69
79
 
80
+ `neededKeys(maxInputs, outputs, maxMergeInputs)` names the shapes that spends of up to `maxInputs` notes with `outputs` outputs, and merges of up to `maxMergeInputs` notes, prove with, smallest first, for `prefetch`; a transfer has two outputs, the payment and the change. `provingKeys()` lists every key the prover can load with its size, the bytes the browser keeps of it and whether its decoded form is kept, without starting the worker. `clearKeys()` removes the kept keys, their decoded forms and interrupted downloads after any work in progress. These follow the mobile SDK's `ProvingKeys.needed`, `status` and `clear`:
81
+
82
+ ```ts
83
+ const shapes = neededKeys(8, [2], 24); // spends of up to 8 notes, merges of up to 24
84
+ await prover.prefetch({ shapes });
85
+ const kept = (await prover.provingKeys()).reduce((sum, key) => sum + key.downloaded, 0);
86
+ ```
87
+
70
88
  ## Lifecycle and failures
71
89
 
72
90
  - First use initializes the worker automatically. Requests are serialized; only one deserialized key is resident at a time.
@@ -75,4 +93,4 @@ await prover.prefetch({
75
93
  - `terminate()` rejects outstanding work, clears the factory and disables automatic restart. Create a new prover, or explicitly call `start(factory)` to reuse the object. A supplied single `Worker` cannot be recreated automatically.
76
94
  - `WasmProverError.code` and its fixed message identify failures without serializing backend messages, witness values, causes or stacks from the backend. Core code does not log errors. The fetch adapter returns a JSON 500 with the safe `code` and `message`; cancellation rejects instead. Caller-provided abort reasons and callback errors remain caller-controlled and should not contain secrets.
77
95
 
78
- The accelerator comes from the `runtime-v0.3.1` release; the Go bridge is rebuilt from source and bundled, so that release's older bridge, shim and sample request are ignored. The TypeScript worker/API boundary additionally redacts backend errors as defense in depth.
96
+ The accelerator comes from the `runtime-v0.3.2` release, built with Rayon's thread helpers for bundlers; the Go bridge is built from source. The TypeScript worker/API boundary additionally redacts backend errors as defense in depth.
@@ -1,2 +1,4 @@
1
1
  /** Race work against cancellation even when an I/O implementation ignores signals. */
2
2
  export declare function abortable<T>(work: Promise<T>, signal?: AbortSignal): Promise<T>;
3
+ /** Rethrows a cancellation, so a caller that swallows other errors still stops. */
4
+ export declare function rethrowAbort(error: unknown, signal?: AbortSignal): void;
@@ -0,0 +1,30 @@
1
+ /** Race work against cancellation even when an I/O implementation ignores signals. */
2
+ export function abortable(work, signal) {
3
+ if (signal === undefined)
4
+ return work;
5
+ return new Promise((resolve, reject) => {
6
+ const abort = () => reject(signal.reason);
7
+ const cleanup = () => signal.removeEventListener("abort", abort);
8
+ // Always observe work, including when the signal was already aborted.
9
+ work.then((value) => {
10
+ cleanup();
11
+ if (signal.aborted)
12
+ reject(signal.reason);
13
+ else
14
+ resolve(value);
15
+ }, (error) => {
16
+ cleanup();
17
+ reject(signal.aborted ? signal.reason : error);
18
+ });
19
+ if (signal.aborted)
20
+ abort();
21
+ else
22
+ signal.addEventListener("abort", abort, { once: true });
23
+ });
24
+ }
25
+ /** Rethrows a cancellation, so a caller that swallows other errors still stops. */
26
+ export function rethrowAbort(error, signal) {
27
+ signal?.throwIfAborted();
28
+ if (error instanceof Error && error.name === "AbortError")
29
+ throw error;
30
+ }
package/dist/errors.js ADDED
@@ -0,0 +1,38 @@
1
+ const messages = {
2
+ wasm_prover_error: "Prover operation failed",
3
+ wasm_init_failed: "Prover initialization failed; check runtime assets, threads and isolation headers",
4
+ wasm_worker_failed: "Prover worker failed",
5
+ wasm_worker_not_started: "Prover worker is not started",
6
+ wasm_worker_terminated: "Prover worker terminated",
7
+ wasm_invalid_response: "Invalid prover response",
8
+ wasm_invalid_request: "Unsupported circuit or malformed request",
9
+ wasm_key_manifest_error: "The proving key is not in the pinned key set",
10
+ wasm_key_download_failed: "Proving-key download failed",
11
+ wasm_key_digest_mismatch: "Proving key does not match the lockfile; stage the pinned assets",
12
+ wasm_key_load_failed: "Proving-key loading failed",
13
+ wasm_prove_failed: "Proof generation failed",
14
+ wasm_verify_failed: "Native gnark verification rejected the proof",
15
+ };
16
+ export class WasmProverError extends Error {
17
+ code;
18
+ constructor(code = "wasm_prover_error") {
19
+ const safeCode = Object.hasOwn(messages, code) ? code : "wasm_prover_error";
20
+ super(messages[safeCode]);
21
+ this.name = "WasmProverError";
22
+ this.code = safeCode;
23
+ }
24
+ }
25
+ export function operationError(kind) {
26
+ switch (kind) {
27
+ case "init":
28
+ return new WasmProverError("wasm_init_failed");
29
+ case "loadKey":
30
+ return new WasmProverError("wasm_key_load_failed");
31
+ case "prove":
32
+ return new WasmProverError("wasm_prove_failed");
33
+ case "verify":
34
+ return new WasmProverError("wasm_verify_failed");
35
+ default:
36
+ return new WasmProverError("wasm_worker_failed");
37
+ }
38
+ }
package/dist/index.d.ts CHANGED
@@ -1,7 +1,8 @@
1
- export { TRANSFER_SHAPES, MERGE_KEY_BYTES, MERGE_KEY_FILE, MERGE_SHAPE, MERGE_SHAPES, keyForProveRequest, canonicalShape, formatBytes, shapeByLabel, type Shape, type ShapeKey, } from "./shapes.js";
1
+ export { TRANSFER_SHAPES, MERGE_KEY_BYTES, MERGE_KEY_FILE, MERGE_SHAPE, MERGE_SHAPES, keyForProveRequest, canonicalShape, formatBytes, neededKeys, shapeByLabel, type Shape, type ShapeKey, } from "./shapes.js";
2
2
  export { KEY_BASE_URL } from "./key-digests.js";
3
3
  export type { KeyProgress, Measurement } from "./measurement.js";
4
4
  export type { WasmProverErrorCode } from "./errors.js";
5
5
  export { WasmProver, WasmProver as ZolanaWebProver, WasmProverError, type WasmProverOptions, type WorkerRequest, type WorkerResponse, } from "./wasm-prover.js";
6
+ export type { ProvingKeyStatus } from "./key-store.js";
6
7
  export { automaticProvingThreads } from "./proving-threads.js";
7
8
  export { observeProofRequests } from "./proof-requests.js";