Skip to Content
SDK ReferenceTypeScript APIzk
SDK reference (auto)

zk

Classes

IncrementalMerkleTree

Constructors

Constructor
new IncrementalMerkleTree(depth): IncrementalMerkleTree;
Parameters
ParameterType
depthnumber
Returns

IncrementalMerkleTree

Properties

PropertyModifierType
depthreadonlynumber

Accessors

root
Get Signature
get root(): bigint;
Returns

bigint

nextIndex
Get Signature
get nextIndex(): number;
Returns

number

leaves
Get Signature
get leaves(): readonly bigint[];
Returns

readonly bigint[]

Methods

insert()
insert(leaf): Promise<number>;

Insert a new leaf. O(depth) hashes. Returns the inserted leaf’s index. Throws if the tree is full (leaves.length === 2^depth).

Parameters
ParameterType
leafbigint
Returns

Promise<number>

fromLeaves()
static fromLeaves(leaves, depth): Promise<IncrementalMerkleTree>;

Build a fully-populated tree from an ordered leaf list. Useful for hydrating from chain state on startup.

Parameters
ParameterType
leavesreadonly bigint[]
depthnumber
Returns

Promise<IncrementalMerkleTree>

proof()
proof(leafIndex): Promise<{ root: bigint; pathElements: bigint[]; pathIndices: number[]; }>;

Inclusion proof for a leaf at the given index. Walks the tree level by level: at each level, the sibling is the hash of the sibling subtree’s leaves (computed on demand) when those leaves exist, otherwise the precomputed ZEROS[i]. Cost: O(N) hashes per call in the worst case (sibling subtree is fully populated). Memory stays at O(N) — the O(2^depth) a fully-padded tree would require is the alternative.

TODO(perf): cache the layer arrays to drop per-proof cost to O(log N). Acceptable at projected near-term scale (~hundreds of commitments); revisit before mainnet.

Returns the same MerkleProof shape every spend circuit consumes ({ root, pathElements, pathIndices }). Throws when leafIndex is outside the inserted range.

Parameters
ParameterType
leafIndexnumber
Returns

Promise<{ root: bigint; pathElements: bigint[]; pathIndices: number[]; }>

Interfaces

ClaimEntry

One claim distribution within an authorize proof — “send X of the buy token to recipient Y, releasable at time Z, secured by this per-claim secret.”

Properties

PropertyTypeDescription
secretbigint-
recipientstringEthereum address (0x-prefixed).
tokenstringToken address — circuit enforces equality with the order’s buyToken per used claim.
amountbigint-
releaseTimebigint-

AuthorizeProofInput

Inputs to generateAuthorizeProof.

Properties

PropertyTypeDescription
noteCommitmentNoteEscrow note being spent (v2: includes BabyJub pubkey binding).
leafIndexnumberIndex of note’s commitment in the on-chain Merkle tree.
allLeaves?bigint[]All commitment leaves in the pool. Required when merkleProof is omitted.
merkleProof?MerkleProofPre-computed Merkle proof for the note’s commitment. When provided, the expensive O(2^COMMIT_TREE_DEPTH) tree rebuild is skipped — recommended for any pool past a few thousand leaves. Apps should maintain an incremental tree and supply this.
sellAmountbigintHow much of note.token to sell. Must be ≤ note.amount.
buyTokenstringCounterparty’s sell token.
buyAmountbigintMinimum amount of buyToken we require — the price limit.
maxFeebigintRelayer fee cap in basis points (100 = 1%).
expirybigintOrder expiry as unix seconds; settle checks block.timestamp ≤ expiry.
noncebigintReplay-protection nonce — one per attempt.
relayerstringAddress of the relayer this proof is bound to.
eddsaPrivateKeyUint8ArrayBaby Jubjub private key (from deriveEdDSAKey). The local copy is wiped after signing.
claimsClaimEntry[]Distribution of the proceeds. claims.length ≤ tier.cap.
newSalt?bigintSalt for the residual (change) commitment. The page that pre-computed expectedChangeCommitment for the note file MUST pass the same salt here, otherwise the on-chain new commitment will differ from the stored one and the change UTXO will be effectively unspendable. Omit when sellAmount === note.amount (fully spent — no change). When change > 0 and this is omitted, the prover generates a random fallback but does not surface it back — callers should not rely on that path.

AuthorizeProofResult

Output of generateAuthorizeProof. Public signals are returned as bigints in circuit-declared order so they plug into the Solidity verifier without further conversion. The named fields duplicate signals from publicSignals for ergonomic use when building the settleAuth calldata.

Properties

PropertyTypeDescription
proofGroth16Proof-
publicSignalsreadonly bigint[]-
pubKeyBindbigintFirst public signal of authorize.circom — the BabyJub pubkey bound to this proof. Off-chain relayer compliance checks read this without re-deriving from publicSignals.
commitmentRootbigint-
nullifierbigint-
nonceNullifierbigint-
newCommitmentbigint-
claimsRootbigint-
totalLockedbigint-
orderHashbigint-

CancelProofInput

Properties

PropertyTypeDescription
noteCommitmentNoteThe user’s escrow commitment note (v2 — includes BabyJub pubkey).
leafIndexnumberIndex of this commitment’s leaf in the on-chain Merkle tree.
allLeaves?bigint[]All commitment leaves in the pool. Required when merkleProof is omitted.
merkleProof?MerkleProofPre-computed Merkle proof — recommended once the pool grows past a few thousand leaves; skipping the O(2^depth) rebuild is the difference between sub-second and multi-second cancel cost.
noncebigintNonce of the order being cancelled.
eddsaPrivateKeyUint8ArrayEdDSA private key bound into note’s commitment. Caller-owned; the prover wipes its own working copy after signing.
submitterstringAddress of the wallet that will submit the cancel tx — always msg.sender of cancelPrivate. The contract binds this into the proof (pubSignals[4] = uint160(msg.sender)) and the EdDSA signature commits to it via cancelMsg = Poseidon(oldNonceNullifier, submitter), so a proof generated for one submitter address can’t be replayed by another wallet. Despite cancel’s “anyone can submit” framing in earlier versions, the contract has no relayer registry check on this path — cancelPrivate is permissionless and the user typically signs and broadcasts the cancel tx themselves from their own wallet. Pass the user’s address here.

CancelProofResult

Properties

PropertyTypeDescription
proofGroth16Proof-
publicSignalsreadonly bigint[]-
commitmentRootbigint-
oldNullifierbigint-
oldNonceNullifierbigint-
newCommitmentbigint-
freshSaltbigintFresh salt for the rotated commitment — the caller must persist this so the new note can be spent later (same balance, new salt).

ClaimProofInput

Inputs to generateClaimProof. The secret and leafIndex identify which slot in the settlement’s claims tree this proof is releasing; the rest is exact-match material the circuit re-hashes to verify the leaf.

Properties

PropertyTypeDescription
secretbigintPer-claim secret from the original ClaimEntry.
recipientbigintRecipient address as a uint256.
tokenbigintToken address as a uint256.
amountbigint-
releaseTimebigintUnix-seconds release time the original order set.
leafIndexnumberIndex of this claim within the settlement’s claims tree.
allClaimLeavesbigint[]All 2^tier.claimsTreeDepth leaves of the claims tree (padded with 0n). Used to re-derive claimsRoot and the inclusion proof. Ignored when merkleProof is supplied.
merkleProof?MerkleProofOptional fast path: when supplied, allClaimLeaves is ignored and the circuit takes this proof’s pathElements / pathIndices / root directly.

ClaimProofResult

Output of generateClaimProof. Convenience fields duplicate signals from publicSignals so callers building claim calldata don’t have to re-derive them.

Properties

PropertyType
proofGroth16Proof
publicSignalsreadonly bigint[]
claimsRootbigint
nullifierbigint

DeepRecoverRecipient

One recipient line for deep recovery, in leaf order. The operator supplies these (they created the payout); amounts are token-raw.

Properties

PropertyType
recipientstring
amountbigint

DeepRecoverArgs

Properties

PropertyTypeDescription
seedbigintPer-payout seed — re-derived from the wallet via claimSeedFromKey.
recipientsDeepRecoverRecipient[]Recipients in their original leaf order (index matters: it feeds both the tree position and the secret derivation).
tokenstring-
tierCapnumberClaims-tree capacity the settle used (16
targetClaimsRootstringThe on-chain-registered root to match against (0x bytes32).
startSecnumberInclusive unix-second search window for the one unknown field, releaseTime (= claimFrom).
endSecnumber-
stepSec?numberSearch granularity in seconds (default 1).
maxCandidates?numberSafety cap on candidates so a fat-fingered window can’t spin forever. Default 200k (~2 days at 1s). Exceeding it throws.
onProgress?(scanned, total) => voidProgress callback (scanned, total) for a UI bar.
signal?AbortSignalAbort signal so the UI can cancel a long scan.

DeepRecoverClaim

Properties

PropertyType
recipientstring
tokenstring
amountbigint
releaseTimebigint
secretbigint

DeepRecoverResult

Properties

PropertyTypeDescription
releaseTimebigint-
claimsDeepRecoverClaim[]Reconstructed claims (with derived secrets) for the matched root — feed these to the package rebuilder.

CircuitAssets

Wasm + zkey assets for a single circuit. snarkjs accepts URLs, ArrayBuffers, or Uint8Arrays for both — pass whatever the host has already loaded.

Properties

PropertyType
wasmstring | ArrayBuffer | Uint8Array<ArrayBufferLike>
zkeystring | ArrayBuffer | Uint8Array<ArrayBufferLike>

DepositProofResult

Properties

PropertyTypeDescription
commitmentbigintPoseidon commitment derived from the note. Returned alongside the proof so callers don’t have to recompute it before sending the deposit transaction.
proofGroth16Proof-
publicSignalsreadonly bigint[]Public signals from the prover, in circuit-declared order. The deposit circuit emits one signal — the commitment — but we return the full array so callers can plug the result straight into the SDK’s ProveResult / ProverWorkerResponse shape without re-deriving it.

PayoutRecipient

Recipient line for a multi-recipient payout. The token is shared across the whole payout — see SplitPayoutOpts.token.

Properties

PropertyTypeDescription
recipientstringEthereum address (0x-prefixed).
amountbigintAmount of opts.token to send to this recipient.
releaseTimebigintEarliest unix-second the recipient can claim.
secret?bigintOptional pre-computed per-claim secret. When omitted, splitPayout draws one from SplitPayoutOpts.generateSecret (defaulting to randomFieldElement).

SplitPayoutOpts

Properties

PropertyTypeDescription
tokenstringToken address that goes into every ClaimEntry.token. The protocol enforces claim.token === buyToken per used claim, so callers should pass the same value as their AuthorizeProofInput.buyToken.
tier?CircuitTierTier to chunk against. Defaults to pickActiveTier(recipients.length) so the smallest active circuit covers the run; pass an explicit tier when the caller needs to pin to a specific verifier (e.g. tests, or a Pay UI that wants to multi-batch on a smaller tier even when a larger one is active).
generateSecret?() => bigintOverride the per-claim secret generator. Useful for tests that need deterministic output. Defaults to randomFieldElement.

PayoutBatch

One settle-sized batch of claims. The caller plugs claims into AuthorizeProofInput.claims and totalAmount into both sellAmount and buyAmount (self-pay USDC → USDC pattern). Each batch needs its own AuthorizeProofInput and signature.

Properties

PropertyTypeDescription
totalAmountbigintSum of amount across claims.
claimsClaimEntry[]Up to tier.cap fully-formed entries, ready to pass straight to generateAuthorizeProof.
tierCircuitTierTier this batch was sized for. The caller forwards it to generateAuthorizeProof so the circuit’s claimsTreeDepth matches the chunking. Every batch from one splitPayout call carries the same tier.

WithdrawProofInput

Properties

PropertyTypeDescription
noteCommitmentNoteThe note being spent.
merkleProofMerkleProofLive merkle proof for note’s commitment in the pool tree.
withdrawAmountbigintRaw token amount to withdraw. Must satisfy 0 < amount <= note.amount.
recipientstringRecipient EOA — receives the withdrawn tokens.
relayer?stringRelayer address paid out of the withdraw amount. Pass 0x000…000 for self-pay (no relayer).
eddsaPrivateKeyUint8ArrayEdDSA private key bound into note’s commitment via pubKeyAx/Ay. Required since the EdDSA gate was added to the withdraw circuit — copying the note file alone is not sufficient to spend; the original wallet’s signing capability must be present to sign Poseidon(nullifierHash, recipient). Caller-owned; the prover wipes its own working copy after signing.

WithdrawProofResult

Properties

PropertyTypeDescription
proofGroth16Proof-
publicSignalsreadonly bigint[]-
newCommitmentbigint0n for full-amount withdraws; otherwise the freshly-computed commitment of the change UTXO. Callers must persist the matching changeNote before broadcasting.
changeNoteCommitmentNote | nullChange-UTXO preimage. null for full-amount withdraws (no residue to persist).
rootbigint-
nullifierHashbigint-
tokenHashbigint-

CommitmentNote

A commitment note — the secret material backing one escrow entry.

The full v2 commitment binds the BabyJub signing pubkey ([issue #128]):

commitment = Poseidon( TAG_COMMITMENT_V2, ownerSecret, token, amount, salt, pubKeyAx, pubKeyAy )

Losing either ownerSecret or the EdDSA private key behind pubKeyAx/pubKeyAy makes the funds unspendable. Wallets must back both up together.

Properties

PropertyTypeDescription
ownerSecretbigint-
tokenbigintToken address as uint256. Use BigInt(addr) to convert.
amountbigint-
saltbigint-
pubKeyAxbigintBabyJub signing pubkey x-coordinate.
pubKeyAybigintBabyJub signing pubkey y-coordinate.

MerkleProof

Merkle inclusion proof for a commitment in the on-chain pool.

Properties

PropertyType
rootbigint
pathElementsbigint[]
pathIndicesnumber[]

PoseidonModule()

Opaque Poseidon module handle. Hot loops (e.g. building a depth-20 Merkle tree → 1M+ hashes) should fetch this once via getPoseidonModule() and call poseidonHashWith(p, inputs) synchronously inside the loop, rather than awaiting poseidonHash per hash and paying 1M microtasks.

PoseidonModule(inputs): unknown;

Opaque Poseidon module handle. Hot loops (e.g. building a depth-20 Merkle tree → 1M+ hashes) should fetch this once via getPoseidonModule() and call poseidonHashWith(p, inputs) synchronously inside the loop, rather than awaiting poseidonHash per hash and paying 1M microtasks.

Parameters

ParameterType
inputsbigint[]

Returns

unknown

Properties

PropertyType
F{ toObject: bigint; }
F.toObjectbigint

CircuitTier

Tier descriptor for an authorize.circom variant. The same Pay/Pro flow can run against any tier — the only differences are the compiled wasm/zkey assets, the on-chain verifier address, and how many claims fit per settlement. The 15 Groth16 public signals are shared across tiers (claimsRoot already aggregates the variable- length claims set inside the circuit).

All three protocol tiers (16 / 64 / 128) are live; the proof helpers (generateAuthorizeProof, generateClaimProof, splitPayout) take a CircuitTier parameter and default to TIER_16 only for legacy callers. MAX_CLAIMS_PER_SIDE stays as a deprecated re-export for the same reason.

Properties

PropertyModifierTypeDescription
capreadonly16 | 64 | 128Max claims per side (= 2^claimsTreeDepth). Doubles as the on-chain verifier registry key on PrivateSettlement.
claimsTreeDepthreadonly4 | 6 | 7Depth of the per-settlement claims Merkle tree (log2 of cap).

EdDSAKeyPair

Properties

PropertyTypeDescription
privateKeyUint8Array32-byte Baby Jubjub private key (the keccak of the ECDSA sig).
publicKeyreadonly [bigint, bigint]Public point on Baby Jubjub: [Ax, Ay].

EdDSASignature

Properties

PropertyType
Sbigint
R8xbigint
R8ybigint

BuiltTree

A built Poseidon Merkle tree. layers[0] is the leaf layer (padded to 2^depth); layers[depth] is the root layer (one element). Suitable input for getMerkleProof.

Properties

PropertyType
rootbigint
layersbigint[][]

MerklePathProof

Inclusion proof for a single leaf in a BuiltTree.

Properties

PropertyType
pathElementsbigint[]
pathIndicesnumber[]

MockProverOpts

Properties

PropertyTypeDescription
latencyMs?numberLatency for each prove call (ms). Defaults to 50 — enough to make spinners visible in tests without slowing them down.
publicSignalsCount?numberNumber of public signals to return per proof. Tests that inspect the count can override; default is one (the most common circuit shape).

SnarkjsRawProof

Raw Groth16 proof shape returned by snarkjs.

Properties

PropertyType
pi_a[string, string, string]
pi_b[[string, string], [string, string], [string, string]]
pi_c[string, string, string]

ProveTiming

Properties

PropertyTypeDescription
circuitZkCircuit-
durationMsnumberRaw float — sub-ms precision retained so the same hook can time fast ops (hashing, witness-only) later without lossy rounding here.
okboolean-

Prover

Generates Groth16 proofs.

Implementations:

  • createWebWorkerProver (browser) — runs snarkjs in a Web Worker so 30-second proofs don’t freeze the UI.
  • createMockProver (dev/test) — returns deterministic dummy proofs so UI flows can be exercised without circuit assets.
  • createWebViewProver (mobile, planned) — bridges to a React Native WebView running the same snarkjs build.

The interface is deliberately minimal: callers don’t care which platform is producing the proof, only that they get one back.

Methods

ready()
ready(): Promise<void>;

Resolve once the prover is ready to accept jobs (circuits loaded, worker spawned, etc.). Idempotent: subsequent calls return the same promise.

Returns

Promise<void>

prove()
prove(req, opts?): Promise<ProveResult>;

Generate one proof. Concurrent calls are serialized by every built-in implementation — proving is CPU-heavy and parallel jobs would just thrash.

Parameters
ParameterType
reqProveRequest
opts?ProveOpts
Returns

Promise<ProveResult>

dispose()
dispose(): void;

Release any worker / WebView / circuit memory. The prover is unusable after this. Calling twice is a no-op.

Returns

void


Groth16Proof

Groth16 proof in the shape every Solidity verifier expects: two G1 elements (a, c) and one G2 element (b). Tuples — not arrays — so positional access is type-checked at call sites.

Properties

PropertyType
areadonly [bigint, bigint]
breadonly [readonly [bigint, bigint], readonly [bigint, bigint]]
creadonly [bigint, bigint]

ProveResult

Output of one proof job. publicSignals carries the public inputs in circuit-declared order so callers can splice them into the verifier call. meta is an optional side-channel for private outputs the worker computed but the circuit doesn’t expose as a public signal — e.g. cancel’s freshSalt, which the rotated note needs persisted client-side but the on-chain call doesn’t take. Field-element values; same BigInt structuredClone path as the proof itself. Workers that don’t need the channel just omit it.

Properties

PropertyType
proofGroth16Proof
publicSignalsreadonly bigint[]
meta?Readonly<Record<string, bigint>>

ProveOpts

Optional knobs for a single prove call. Every implementation must honor signal for cancellation; onProgress is best-effort.

Properties

PropertyTypeDescription
signal?AbortSignalCancel the proof job. The returned promise rejects with a DOMException(“AbortError”) when fired.
onProgress?(msg) => voidCalled with short status strings (“loading wasm”, “running groth16…”). Surfaces are free to ignore.

ProveRequest

A request to generate one proof. The input shape is per-circuit and validated by the implementation; this layer only carries it.

Properties

PropertyTypeDescription
circuitIdCircuitId-
inputRecord<string, unknown>Field-by-field circuit input. BigInts are accepted directly for prime-field values; strings/numbers are coerced by the implementation. Concrete shapes are exposed by per-circuit helpers in higher-level modules (e.g. zk/deposit).
tier?CircuitTierOptional circuit-tier hint for per-tier provers (e.g. authorize 16 / 64 / 128). CircuitTier is a plain data object so it survives postMessage’s structured clone unchanged. Workers fall back to TIER_16 when omitted, preserving the historical single-tier behavior.

WebWorkerProverOpts

Properties

PropertyTypeDescription
createWorker() => WorkerFactory for the worker. Lazy so we don’t spawn until the first prove (or ready()) call.
label?stringOptional logger label used in fallback warnings and errors.
fallbackProve?(req, opts?) => Promise<ProveResult>Main-thread fallback when the Worker constructor throws (most often: SSR, COOP/COEP misconfiguration, very old browsers). Without one, the prover surfaces the worker error to the caller.

LazyWorkerProverOpts

Properties

PropertyTypeDescription
circuitZkCircuitCircuit name — used for the timing wrapper’s label and as the WebWorkerProverOpts.label for fallback warnings.
createWorker() => WorkerSpawn the per-circuit worker. Lazily invoked on first ready() / prove() so apps that never use the prover don’t pay the ~24 MB asset fetch.

ProverWorkerHandlers

What a circuit-specific worker file plugs into setupProverWorker.

Methods

prove()
prove(req): Promise<{ proof: Groth16Proof; publicSignals: readonly bigint[]; meta?: Readonly<Record<string, bigint>>; }>;

Run the proof for one job. May throw — the runtime turns that into a { type: "error" } message back to the main thread. meta is an optional side-channel for private outputs the circuit doesn’t expose as a public signal (e.g. cancel’s freshSalt). See ProveResult.meta.

Parameters
ParameterType
reqProverWorkerRequest
Returns

Promise<{ proof: Groth16Proof; publicSignals: readonly bigint[]; meta?: Readonly<Record<string, bigint>>; }>

preload()?
optional preload(): Promise<void>;

Optional asset / Poseidon warmup, run once before the worker signals “ready”. Errors here are reported as a worker-scope error AND posted as a sentinel error message so the main thread surfaces a clear failure instead of waiting forever for a ready that never comes.

Returns

Promise<void>

Type Aliases

AuthorizeProofMetaKey

type AuthorizeProofMetaKey = typeof AUTHORIZE_PROOF_META_KEYS[number];

AuthorizeProofMeta

type AuthorizeProofMeta = Record<AuthorizeProofMetaKey, bigint>;

TierAssetPaths

type TierAssetPaths = CircuitAssets;

Asset URL pair for one circuit tier. Re-exports CircuitAssets under a tier-flavoured name for callsites that surface tiers explicitly; consumers can pass either type interchangeably.


ZkCircuit

type ZkCircuit = "authorize" | "cancel" | "claim" | "deposit" | "withdraw";

ProveReporter

type ProveReporter = (timing) => void;

Parameters

ParameterType
timingProveTiming

Returns

void


CircuitId

type CircuitId = | "deposit" | "authorize" | "claim" | string & { };

Identifier for a Groth16 circuit shipped with the protocol. Open string-literal union — the well-known names get IDE autocomplete, but any string is accepted so consumers shipping private circuits don’t have to fork the SDK. (Type aliases can’t be declaration-merged; widening via (string & {}) is the workaround.)


ProverWorkerRequest

type ProverWorkerRequest = { type: "prove"; jobId: number; circuitId: string; input: Record<string, unknown>; tier?: CircuitTier; };

Wire-format messages exchanged with a prover Web Worker.

The worker side is not part of this SDK — each Phase 2b+ circuit module ships its own worker that responds to these messages. The split keeps circuit-specific snarkjs code (large wasm, per-circuit input shapes) out of any bundle that doesn’t use it.

BigInts cross the boundary as native BigInt values. The HTML structuredClone algorithm has supported BigInt across all browsers and Node ≥ 17 for years, so the older string-encoding workaround is unnecessary and just slowed proofs down.

Properties

PropertyTypeDescription
type"prove"-
jobIdnumber-
circuitIdstring-
inputRecord<string, unknown>-
tier?CircuitTierOptional circuit tier hint. CircuitTier is a plain data object (no methods), so it survives postMessage’s structured clone unchanged. Worker handlers default to TIER_16 when omitted, preserving the single-tier behavior pre-multi-tier callers expect.

ProverWorkerResponse

type ProverWorkerResponse = | { type: "ready"; } | { type: "progress"; jobId: number; message: string; } | { type: "result"; jobId: number; proof: Groth16Proof; publicSignals: readonly bigint[]; meta?: Readonly<Record<string, bigint>>; } | { type: "error"; jobId: number; message: string; };

Union Members

Type Literal
{ type: "ready"; }

Type Literal
{ type: "progress"; jobId: number; message: string; }

Type Literal
{ type: "result"; jobId: number; proof: Groth16Proof; publicSignals: readonly bigint[]; meta?: Readonly<Record<string, bigint>>; }
type
type: "result";
jobId
jobId: number;
proof
proof: Groth16Proof;
publicSignals
publicSignals: readonly bigint[];
meta?
optional meta?: Readonly<Record<string, bigint>>;

See ProveResult.meta.


Type Literal
{ type: "error"; jobId: number; message: string; }

Variables

AUTHORIZE_PROOF_META_KEYS

const AUTHORIZE_PROOF_META_KEYS: readonly ["pubKeyBind", "commitmentRoot", "nullifier", "nonceNullifier", "newCommitment", "claimsRoot", "totalLocked", "orderHash"];

Extracted scalars an authorize-circuit Web Worker should pass back via ProveResult.meta. They duplicate fields the worker already has on AuthorizeProofResult so the main thread can pack SettleAuthSide without re-deriving by public-signal index.


CANCEL_PUBLIC_SIGNALS

const CANCEL_PUBLIC_SIGNALS: readonly ["commitmentRoot", "oldNullifier", "oldNonceNullifier", "newCommitment", "submitter"];

Cancel circuit’s public-input order, in the same order the .circom declares them. Mirrored by the contract verifier’s scalar arguments. Change one, change both — the constant lives here so consumers can’t drift from it.


CANCEL_META_FRESH_SALT

const CANCEL_META_FRESH_SALT: "freshSalt";

Meta-channel key under which cancel.worker returns the private freshSalt to assembleCancelProofResult.


CLAIMS_TREE_SIZE

const CLAIMS_TREE_SIZE: number;

Tier-16 claims-tree size, kept as the historical export.

Deprecated

Derive size from the picked tier (1 << tier.claimsTreeDepth) so it follows the source settlement’s circuit; this constant is hard-pinned to TIER_16 and will silently return the wrong value on a tier-64 / tier-128 settlement once those ship.


FIELD_MODULUS

const FIELD_MODULUS: 21888242871839275222246405745257275088548364400416034343698204186575808495617n = 21888242871839275222246405745257275088548364400416034343698204186575808495617n;

BN254 scalar field modulus — every Poseidon output and every random field element must live below this.


COMMIT_TREE_DEPTH

const COMMIT_TREE_DEPTH: 20 = 20;

Depth of the on-chain commitment Merkle tree (2^20 ≈ 1M leaves).


TIER_16

const TIER_16: CircuitTier;

Tier 16 — depth 4 → 16 leaves, ~23K authorize constraints, ptau pot15. The default + smallest tier; what every Pay run uses for ≤ 16 recipients.


TIER_64

const TIER_64: CircuitTier;

Tier 64 — depth 6 → 64 leaves, ~56K authorize constraints, ptau pot16. Picked by pickActiveTier for runs of 17–64 recipients. Registered on PrivateSettlement via setAuthorizeVerifier(64, addr) + setClaimVerifier(64, addr).


TIER_128

const TIER_128: CircuitTier;

Tier 128 — depth 7 → 128 leaves, ~101K authorize constraints, ptau pot17. Picked by pickActiveTier for runs of 65–128 recipients. Heaviest prove time (~6–12 s on a mid-tier laptop; mobile-borderline) — Pay’s wizard surfaces the trade-off in the Privacy plan.


TIERS

const TIERS: readonly CircuitTier[];

Public registry of every tier the SDK knows about, ordered by capacity. Use pickTier to select one — direct indexing is fine when the tier is fixed (e.g. tests).


ACTIVE_TIERS

const ACTIVE_TIERS: readonly CircuitTier[];

Tiers that have a live verifier today. Production code should validate against this list before submitting; everything outside it will revert on-chain with TierNotConfigured(tier).

Ordering invariant: must stay sorted by cap ascending. pickActiveTier relies on the order — the first match wins (smallest tier that covers n), and the multi-batch fallback uses the last entry as the largest available cap. New tiers must be inserted in sorted position; the assertion below enforces it at module load to keep silent ordering bugs from changing tier selection.


MAX_CLAIMS_PER_SIDE

const MAX_CLAIMS_PER_SIDE: 16 | 64 | 128 = TIER_16.cap;

Maximum number of claim leaves per side in a single settlement.

Deprecated

Use CircuitTier.cap from a tier picked via pickTier instead. Hardcoding the tier-16 cap in callers blocks the multi-tier rollout. The constant stays as a transitional re-export of TIER_16.cap so legacy paths keep compiling.


CLAIMS_TREE_DEPTH

const CLAIMS_TREE_DEPTH: 4 | 6 | 7 = TIER_16.claimsTreeDepth;

Depth of the per-settlement claims Merkle tree (2^4 = 16 leaves).

Deprecated

Use CircuitTier.claimsTreeDepth via pickTier. Re-exported as the tier-16 depth during the multi-tier migration.


DEFAULT_DERIVE_MESSAGE

const DEFAULT_DERIVE_MESSAGE: "Sign to generate your zkScatter trading key.\n\nThis key is used to sign orders privately.\nIt does not grant access to your funds." = "Sign to generate your zkScatter trading key.\n\nThis key is used to sign orders privately.\nIt does not grant access to your funds.";

Default fixed message used by deriveEdDSAKey when callers don’t pass their own. Keeping this stable across SDK versions matters: changing it would invalidate every existing user’s EdDSA key.


TAG_ESCROW_NULL

const TAG_ESCROW_NULL: 0n = 0n;

Shared Poseidon domain-separation tags.

Mirrors the canonical definitions in circuits/tags.circom. Every Poseidon-based commitment, nullifier, or bound hash prepends one of these tags as its first input so the preimage spaces are disjoint.

CONSENSUS-CRITICAL: any change to these values must land in lock-step with:

  • circuits/tags.circom
  • zk-relayer/src/core/tags.ts
  • frontend/app/lib/zk/tags.ts (legacy duplicate, to be removed) Disagreement here causes proofs to verify against a different preimage space than the contract expects — silent data loss.

TAG_NONCE_NULL

const TAG_NONCE_NULL: 1n = 1n;

TAG_CLAIM_NULL

const TAG_CLAIM_NULL: 2n = 2n;

TAG_COMMITMENT_V2

const TAG_COMMITMENT_V2: 3n = 3n;

PRELOAD_ERROR_JOB_ID

const PRELOAD_ERROR_JOB_ID: -1 = -1;

Sentinel jobId used by preload-failure error messages. The main client uses this to surface init failures even when no job is in flight; a real prove jobId is always > 0.

Functions

hashAuthorizeOrder()

function hashAuthorizeOrder(order): Promise<bigint>;

Compute the order hash that the circuit and contract both sign over. Field order is consensus-critical:

Poseidon(sellToken, buyToken, sellAmount, buyAmount, maxFee, expiry, nonce, claimsRoot, relayer)

Including claimsRoot prevents claim-bag swapping; including relayer enables the trustless fee split.

Parameters

ParameterType
order{ sellToken: bigint; buyToken: bigint; sellAmount: bigint; buyAmount: bigint; maxFee: bigint; expiry: bigint; nonce: bigint; claimsRoot: bigint; relayer: bigint; }
order.sellTokenbigint
order.buyTokenbigint
order.sellAmountbigint
order.buyAmountbigint
order.maxFeebigint
order.expirybigint
order.noncebigint
order.claimsRootbigint
order.relayerbigint

Returns

Promise<bigint>


generateAuthorizeProof()

function generateAuthorizeProof( input, assets, tier?): Promise<AuthorizeProofResult>;

Generate a Groth16 authorize proof for a private limit order.

Pure function — no globals, no caching. Workers / app code own asset loading and re-use. The circuit is ~22.5K constraints; one proof is ~1–2 s on desktop and ~5–9 s on phone-class hardware.

The function pre-computes the intermediate values (commitmentRoot, nullifiers, claimsRoot, orderHash) so the caller can build the settleAuth calldata without re-deriving them from publicSignals.

Parameters

ParameterTypeDefault value
inputAuthorizeProofInputundefined
assetsCircuitAssetsundefined
tierCircuitTierTIER_16

Returns

Promise<AuthorizeProofResult>


authorizeMetaFrom()

function authorizeMetaFrom(result): AuthorizeProofMeta;

Pluck the worker-meta subset out of an AuthorizeProofResult. Used inside the worker to populate ProveResult.meta.

Parameters

ParameterType
resultAuthorizeProofResult

Returns

AuthorizeProofMeta


assembleAuthorizeProofResult()

function assembleAuthorizeProofResult(proveResult): AuthorizeProofResult;

Reassemble an AuthorizeProofResult from a ProveResult whose worker populated meta via authorizeMetaFrom. Validates every required field so callers don’t paper over a worker that forgot to surface a scalar — the alternative is a chain of ! non-null asserts at the call site.

Parameters

ParameterType
proveResultProveResult

Returns

AuthorizeProofResult


assembleCancelProofResult()

function assembleCancelProofResult(envelope): CancelProofResult;

Reconstruct a rich CancelProofResult from the slim { proof, publicSignals, meta? } envelope a Web Worker passes back. The cancel circuit’s private freshSalt is not in publicSignals — it isn’t needed by the on-chain cancelPrivate call (the contract doesn’t take it), but vault rotation persistence (writing the rotated note with the new salt) needs it. The worker carries it back through the meta channel; if a worker omits it, this returns freshSalt: 0n and rotation persistence stays gated off in the caller.

Parameters

ParameterType
envelope{ proof: Groth16Proof; publicSignals: readonly bigint[]; meta?: Readonly<Record<string, bigint>>; }
envelope.proofGroth16Proof
envelope.publicSignalsreadonly bigint[]
envelope.meta?Readonly<Record<string, bigint>>

Returns

CancelProofResult


generateCancelProof()

function generateCancelProof(input, assets): Promise<CancelProofResult>;

Parameters

ParameterType
inputCancelProofInput
assetsCircuitAssets

Returns

Promise<CancelProofResult>


singleClaimTree()

function singleClaimTree( entry, leafIndex, tier?): Promise<{ claimLeaf: bigint; allClaimLeaves: bigint[]; }>;

Build an N-leaf claims tree with a single entry at leafIndex, rest zero-padded. tier defaults to TIER_16 — the only live authorize tier today — but a settlement produced by a higher tier must pass that tier so the claims tree size matches. The shape every single-claim flow needs; centralised so the inline poseidonHash + Array(N).fill(0n) pattern lives in one place.

Note: recipient and token are passed as BigInt — call sites with 0x-prefixed hex strings should BigInt(addr) before passing, since the circuit hashes them as field elements.

Parameters

ParameterTypeDefault value
entry{ secret: bigint; recipient: bigint; token: bigint; amount: bigint; releaseTime: bigint; }undefined
entry.secretbigintundefined
entry.recipientbigintundefined
entry.tokenbigintundefined
entry.amountbigintundefined
entry.releaseTimebigintundefined
leafIndexnumberundefined
tierCircuitTierTIER_16

Returns

Promise<{ claimLeaf: bigint; allClaimLeaves: bigint[]; }>


buildClaimsTree()

function buildClaimsTree(claims, tier?): Promise<{ root: bigint; layers: bigint[][]; leaves: bigint[]; }>;

N-leaf variant of singleClaimTree for an entire batch — hashes every claim into its leaf, zero-pads up to CLAIMS_TREE_SIZE, and builds the Poseidon tree. Returns the layers so callers can pull a per-leaf inclusion proof via getMerkleProof(layers, i) without rebuilding. The hash recipe matches the authorize circuit exactly — keep in lock-step with generateAuthorizeProof’s internal claim-leaf construction.

Parameters

ParameterTypeDefault value
claimsreadonly { secret: bigint; recipient: string | bigint; token: string | bigint; amount: bigint; releaseTime: bigint; }[]undefined
tierCircuitTierTIER_16

Returns

Promise<{ root: bigint; layers: bigint[][]; leaves: bigint[]; }>


generateClaimProof()

function generateClaimProof( input, assets, tier?): Promise<ClaimProofResult>;

Generate a Groth16 claim proof for one slot of a settlement.

Pre-checks:

  • leafIndex in range (slow path) or non-negative (fast path)
  • claim data hashes to the leaf at leafIndex (slow path) — catches “wrong claim file” / “wrong settlement” mistakes loudly instead of after a 2 s proof
  • allClaimLeaves.length === 2^tier.claimsTreeDepth

Parameters

ParameterTypeDefault value
inputClaimProofInputundefined
assetsCircuitAssetsundefined
tierCircuitTierTIER_16

Returns

Promise<ClaimProofResult>


deepRecoverReleaseTime()

function deepRecoverReleaseTime(args): Promise<DeepRecoverResult | null>;

Recover the one fuzzy field — releaseTime — of a payout whose claim links were lost, by reconstructing the claims tree for each candidate timestamp and matching it against the on-chain root.

Everything else is known: the seed is re-derivable from the wallet, and the operator supplies recipients + amounts + order. releaseTime is run-wide (one value for the whole payout), so it’s a single scalar to scan, with the on-chain claimsRoot as an exact-match oracle. Returns the matched releaseTime + reconstructed claims, or null if no candidate in the window reproduces the target root.

Parameters

ParameterType
argsDeepRecoverArgs

Returns

Promise<DeepRecoverResult | null>


generateDepositProof()

function generateDepositProof(note, assets): Promise<DepositProofResult>;

Generate a Groth16 deposit proof for a CommitmentNote.

Pure function — no globals, no caching. Callers (typically a Web Worker) decide where the wasm/zkey come from and whether to cache them across calls.

The commitment is derived from the note’s preimage internally, so a caller can’t accidentally pair a note with a mismatched commitment and then debug an opaque on-chain InvalidProof revert. The function also re-checks the prover’s first public signal against the derived commitment as a defence-in-depth assertion.

Parameters

ParameterType
noteCommitmentNote
assetsCircuitAssets

Returns

Promise<DepositProofResult>


withDeterministicSecrets()

function withDeterministicSecrets( recipients, seed, token): Promise<PayoutRecipient[]>;

Fill each recipient’s secret deterministically from a per-payout seed (see deriveClaimSecret), returning a new array ready for splitPayout. Use this instead of the default random generator whenever the caller wants the resulting claimsRoot to be reproducible across retries / recovery — the secret for recipient i is deriveClaimSecret(seed, recipient, token, amount, releaseTime, i), indexed by the recipient’s position in the full payout (preserved by splitPayout’s in-order chunking). token must match SplitPayoutOpts.token. A recipient that already carries a secret is left untouched.

Parameters

ParameterType
recipientsPayoutRecipient[]
seedbigint
tokenstring

Returns

Promise<PayoutRecipient[]>


splitPayout()

function splitPayout(recipients, opts): PayoutBatch[];

Chunk a recipient list into batches that fit the picked circuit tier’s cap. Order is preserved — recipient i always lands in batch floor(i / tier.cap) — and per-claim secrets are drawn for any recipient that didn’t supply one.

Tier defaults to pickActiveTier(recipients.length) so a caller that doesn’t care about tiers gets the smallest live circuit that covers the run; with only TIER_16 active today, that matches the historical behavior. When a future tier ships and is added to ACTIVE_TIERS, the same call automatically routes a 17-recipient run through one tier-64 batch instead of two tier-16 batches.

This is a pure helper. The caller still selects which note(s) to spend per batch, manages the residual change UTXO, and drives N proofs / N signatures. splitPayout only exists so apps don’t re-implement chunking + secret-generation on top of generateAuthorizeProof.

Parameters

ParameterType
recipientsPayoutRecipient[]
optsSplitPayoutOpts

Returns

PayoutBatch[]


authorizeAssetPaths()

function authorizeAssetPaths(tier, baseDir): { wasm: string; zkey: string; };

Resolve the per-tier authorize-circuit asset URLs for a given static-asset base directory.

  • TIER_16 → <baseDir>/authorize.wasm + <baseDir>/authorize_final.zkey (legacy filename, present in every existing deploy).
  • Higher tiers → <baseDir>/authorize_<cap>.wasm + <baseDir>/authorize_<cap>_final.zkey (e.g. authorize_64.wasm).

Today only the TIER_16 artifacts exist in circuits/build/; the higher-tier paths will 404 until the corresponding ceremony ships the matching .wasm / .zkey files. Production paths can’t reach those URLs accidentally — pickActiveTier only returns tiers in ACTIVE_TIERS, which the deploy controls. The intentional side effect: the moment a TIER_64 / TIER_128 ceremony drops the files alongside the tier-16 ones and updates ACTIVE_TIERS, every caller picks up the new artifacts with no code change.

Pass baseDir like "/zk" (Pay’s public/zk static folder) or the per-app deploy path. No trailing slash.

Parameters

ParameterType
tierCircuitTier
baseDirstring

Returns

{ wasm: string; zkey: string; }
wasm
wasm: string;
zkey
zkey: string;

claimAssetPaths()

function claimAssetPaths(tier, baseDir): { wasm: string; zkey: string; };

Same idea as authorizeAssetPaths but for the claim circuit. Claim circuits are tier-specific because the claims tree depth matches the source settlement’s tier — a tier-64 settlement hands out claim packages whose proofs need a depth-6 claim circuit.

Parameters

ParameterType
tierCircuitTier
baseDirstring

Returns

{ wasm: string; zkey: string; }
wasm
wasm: string;
zkey
zkey: string;

generateWithdrawProof()

function generateWithdrawProof(input, assets): Promise<WithdrawProofResult>;

Generate a Groth16 withdraw proof. Mirrors generateDepositProof’s shape — pure function, no caching. The commitment / nullifier / tokenHash / change-UTXO commitment are derived locally and cross-checked against the prover’s public signals so a malformed prove can’t slip through with a mismatched root or recipient.

Defense-in-depth: the on-chain pool re-verifies all of these via the verifier contract; the local checks just surface circuit-vs- app drift earlier and with clearer error messages.

Parameters

ParameterType
inputWithdrawProofInput
assetsCircuitAssets

Returns

Promise<WithdrawProofResult>


getPoseidonModule()

function getPoseidonModule(): Promise<PoseidonModule>;

Get (and lazily build) the cached Poseidon module. The in-flight Promise is memoized so concurrent callers share one initialization.

Returns

Promise<PoseidonModule>


warmupPoseidon()

function warmupPoseidon(): Promise<void>;

Eagerly build the Poseidon round-constant table so the first proof job doesn’t pay the build cost on the user’s hot path. Worker preload hooks should call this on startup.

Returns

Promise<void>


poseidonHash()

function poseidonHash(inputs): Promise<bigint>;

Generic Poseidon hash — convenient for one-off calls. Awaits the cached module each call, so use poseidonHashWith inside hot loops instead.

Parameters

ParameterType
inputsbigint[]

Returns

Promise<bigint>


poseidonHashWith()

function poseidonHashWith(poseidon, inputs): bigint;

Synchronous Poseidon hash given an already-built module. Use inside hot loops where awaiting per call would dominate the cost.

Parameters

ParameterType
poseidonPoseidonModule
inputsbigint[]

Returns

bigint


randomFieldElement()

function randomFieldElement(): bigint;

Generate a cryptographically random field element strictly less than the BN254 scalar modulus. Uses crypto.getRandomValues (globalThis.crypto works in browser, Node 19+, Deno, Bun).

Sampling: top byte is masked with 0x3f so the candidate is at most 254 bits (since FIELD_MODULUS < 2^254). The do-while rejects the ~24% of candidates that still land in [FIELD_MODULUS, 2^254), leaving a uniform distribution over [0, FIELD_MODULUS) with no modulo bias. We pay slightly more rejections than the legacy 0x1f mask did, but get a full ~254 bits of entropy rather than ~253.

Returns

bigint


claimSecretPreimage()

function claimSecretPreimage( seed, recipient, token, amount, releaseTime, index): bigint[];

Poseidon preimage for a deterministic claim secret — the single source of truth shared by deriveClaimSecret (one-off) and the batched withDeterministicSecrets (Poseidon module fetched once), so the two can never drift. A drift would make a recovery run regenerate the wrong secrets.

Parameters

ParameterType
seedbigint
recipientstring
tokenstring
amountbigint
releaseTimebigint
indexnumber

Returns

bigint[]


deriveClaimSecret()

function deriveClaimSecret( seed, recipient, token, amount, releaseTime, index): Promise<bigint>;

Parameters

ParameterType
seedbigint
recipientstring
tokenstring
amountbigint
releaseTimebigint
indexnumber

Returns

Promise<bigint>


generateNote()

function generateNote( token, amount, pubKey): CommitmentNote;

Build a fresh CommitmentNote bound to the caller’s BabyJub signing pubkey.

Parameters

ParameterType
tokenstring
amountbigint
pubKeyreadonly [bigint, bigint]

Returns

CommitmentNote


computeCommitment()

function computeCommitment(note): Promise<bigint>;

v2 commitment: Poseidon(TAG_COMMITMENT_V2, ownerSecret, token, amount, salt, pubKeyAx, pubKeyAy)

Parameters

ParameterType
noteCommitmentNote

Returns

Promise<bigint>


computeNullifier()

function computeNullifier(note): Promise<bigint>;

Escrow nullifier (withdraw + settle): Poseidon(0, ownerSecret, salt).

Parameters

ParameterType
noteCommitmentNote

Returns

Promise<bigint>


computeNonceNullifier()

function computeNonceNullifier(ownerSecret, nonce): Promise<bigint>;

Nonce nullifier (settle replay protection): Poseidon(1, ownerSecret, nonce).

Parameters

ParameterType
ownerSecretbigint
noncebigint

Returns

Promise<bigint>


computeClaimNullifier()

function computeClaimNullifier( secret, leafIndex, claimsRoot): Promise<bigint>;

Claim nullifier: Poseidon(2, secret, leafIndex, claimsRoot).

claimsRoot is bound into the preimage so the same (secret, leafIndex) in two different settled claims groups yields two DISTINCT nullifiers — the on-chain claimNullifiers set is global, and a maker derives every recipient’s claim secret, so without this binding a maker could settle a throwaway group with a colliding leaf and permanently brick the honest recipient’s claim. Must stay byte-identical to claim_template.circom’s nullifier derivation.

Parameters

ParameterType
secretbigint
leafIndexbigint
claimsRootbigint

Returns

Promise<bigint>


computeTokenHash()

function computeTokenHash(token): Promise<bigint>;

Token hash for circuit public inputs: Poseidon(token).

Parameters

ParameterType
tokenstring

Returns

Promise<bigint>


toBytes32Hex()

function toBytes32Hex(value): string;

Format a bigint as a 0x-prefixed bytes32 hex string.

Parameters

ParameterType
valuebigint

Returns

string


pickTier()

function pickTier(recipientCount): CircuitTier;

Pick the smallest tier that fits recipientCount. Returns the matching CircuitTier or throws when no tier covers the request — capping the upper bound is intentional, the on-chain cap mirrors it.

Callers should pad the actual claims array up to tier.cap with dummy entries (see padClaims) to keep per-tier batches visually identical and protect the per-tier anonymity set.

This is the theoretical picker — it considers every tier the protocol defines, including ones whose verifier is not yet deployed. Production callers want pickActiveTier, which filters to ACTIVE_TIERS and falls back to the largest active tier with multi-batch when no active tier covers the request.

Parameters

ParameterType
recipientCountnumber

Returns

CircuitTier


pickActiveTier()

function pickActiveTier(recipientCount): CircuitTier;

Pick the smallest active tier that fits recipientCount — i.e. one whose verifier is wired on-chain today (see ACTIVE_TIERS). When no active tier covers the request, the largest active tier is returned so the caller can chunk the recipients into multiple batches of that tier; this is the multi-batch fallback the Pay app uses while tier 64 / 128 are not yet live.

Throws when ACTIVE_TIERS is empty (a misconfigured deployment).

Use this in production paths that actually generate proofs and submit on-chain; reserve pickTier for design-level reasoning that should ignore deployment status.

Parameters

ParameterType
recipientCountnumber

Returns

CircuitTier


padClaims()

function padClaims<T>( claims, tier, dummy): T[];

Pad a claims array up to tier.cap by appending the same dummy value in every empty slot. The returned array is a new outer array (the input is not mutated), but each padded slot shares one reference to dummy — pass a frozen / immutable sentinel when T is an object type, or callers will see ghost mutations across slots. Throws when the input already exceeds the tier capacity (the caller picked the wrong tier for this list).

Padding is mandatory for anonymity: every tier-N settlement looks like every other tier-N settlement at the on-chain layer because the claims tree always carries N leaves. Tight-packing leaks the recipient count via the calldata size and proof timing.

Type Parameters

Type Parameter
T

Parameters

ParameterType
claimsreadonly T[]
tierCircuitTier
dummyT

Returns

T[]


claimSeedFromKey()

function claimSeedFromKey(privateKey): bigint;

Domain-separated derivation of a per-payout claim-secret seed from the wallet’s deterministic EdDSA private key bytes (keccak256 of the fixed-message ECDSA signature). Because the key is re-derivable from the wallet alone, so is the seed — there is no random seed to lose, and a recovery run can regenerate every claim secret just by re-signing. The domain tag keeps this value independent of the EdDSA key’s own uses. Reduced into the BN254 scalar field for use as a Poseidon input.

Note: the seed is per-wallet (not per-payout); per-claim uniqueness comes from the leaf fields in deriveClaimSecret. Two byte-identical payouts (same recipients, amounts, releaseTime, order) would collide, but that surfaces as a ClaimsGroupAlreadyExists revert on the second settle — self-detecting, never silent loss.

Parameters

ParameterType
privateKeyUint8Array

Returns

bigint


warmupEddsa()

function warmupEddsa(): Promise<void>;

Eagerly initialise the EdDSA + BabyJub tables. Worker preload hooks should call this on startup so the first signing job doesn’t pay the build cost on the user’s hot path.

Returns

Promise<void>


deriveEdDSAKey()

function deriveEdDSAKey(signerOrSignature, opts?): Promise<{ keyPair: EdDSAKeyPair; signature: string; }>;

Derive the EdDSA keypair from a wallet signature.

Pass either an ethers.Signer (we’ll prompt for signMessage) or a hex-encoded signature you already have. Returning the signature lets callers cache it for later flows that need the same material (e.g. AES-GCM key-wrapping for vault backup).

When a string signature is passed, opts.message has no effect (the signature was produced against whatever message the caller used). Passing both is treated as a programmer error — throws rather than silently ignoring the override.

Parameters

ParameterType
signerOrSignaturestring | Signer
optsDeriveOpts

Returns

Promise<{ keyPair: EdDSAKeyPair; signature: string; }>


signEdDSA()

function signEdDSA(privateKey, message): Promise<EdDSASignature>;

Sign a message (a field element — usually a Poseidon order hash) with EdDSA.

Parameters

ParameterType
privateKeyUint8Array
messagebigint

Returns

Promise<EdDSASignature>


serializeKeyPair()

function serializeKeyPair(kp): string;

Serialize an EdDSA keypair to a JSON string for storage. The private key is hex-encoded; pubkey field elements are decimal strings (BigInt-safe).

Parameters

ParameterType
kpEdDSAKeyPair

Returns

string


deserializeKeyPair()

function deserializeKeyPair(json): EdDSAKeyPair;

Inverse of serializeKeyPair. Throws a single "deserializeKeyPair: malformed JSON" for any structural issue — invalid JSON, wrong shape, non-string fields, BigInt parse failure — so callers don’t have to discriminate between the underlying parse / coercion errors.

Parameters

ParameterType
jsonstring

Returns

EdDSAKeyPair


buildMerkleTree()

function buildMerkleTree(leaves, depth): Promise<BuiltTree>;

Build a Poseidon Merkle tree of the given depth from leaves. The leaf array is padded with the leaf-level zero (0n) up to 2^depth; internal zero values are derived by hashing the level below.

Awaits the Poseidon module once at the top, then hashes synchronously inside the loop. Awaiting per hash would cost a microtask per node — at COMMIT_TREE_DEPTH = 20 (~1 M hashes) that becomes the dominant cost.

Apps that maintain an incremental tree should pre-compute MerkleProofs and pass them through AuthorizeProofInput .merkleProof instead of asking the prover to rebuild from scratch each call.

Parameters

ParameterType
leavesbigint[]
depthnumber

Returns

Promise<BuiltTree>


getMerkleProof()

function getMerkleProof(layers, leafIndex): MerklePathProof;

Walk a BuiltTree from leaf to root, collecting siblings. The returned pathIndices[i] is 1 when the original leaf is on the right side of its sibling at level i, 0 otherwise — matching the convention every Circom Merkle template uses.

Parameters

ParameterType
layersbigint[][]
leafIndexnumber

Returns

MerklePathProof


createMockProver()

function createMockProver(opts?): Prover;

A Prover that returns deterministic dummy proofs after a small delay. Useful for:

  • exercising UI flows without shipping circuit assets
  • integration tests that don’t want to set up snarkjs
  • storybooks / visual regression

The returned proof is structurally valid (BigInts in the right shape) but cryptographically nonsense. Verifiers will reject it.

Parameters

ParameterType
optsMockProverOpts

Returns

Prover


formatGroth16Proof()

function formatGroth16Proof(raw): Groth16Proof;

Convert snarkjs’s raw proof shape to the SDK’s Groth16Proof tuple (which mirrors what every Solidity verifier expects).

The G2 element’s limb order is reversed (pi_b[i][1] first, then pi_b[i][0]) — that’s the pairing-curve convention every circomlibjs-generated verifier was scaffolded against. Centralizing the swap here means each per-circuit prover (deposit / authorize / claim) doesn’t get a chance to reverse the limbs differently and break verification in a way that’s painful to debug.

Parameters

ParameterType
rawSnarkjsRawProof

Returns

Groth16Proof


setProveReporter()

function setProveReporter(fn): void;

Parameters

ParameterType
fnProveReporter

Returns

void


timeProve()

function timeProve<T>(circuit, run): Promise<T>;

Type Parameters

Type Parameter
T

Parameters

ParameterType
circuitZkCircuit
run() => Promise<T>

Returns

Promise<T>


wrapProverWithTimer()

function wrapProverWithTimer(circuit, inner): Prover;

Wrap a Prover so each prove() call is bracketed by timeProve(circuit, ...). Telemetry runs on the main thread — workers can’t dispatch the zk-perf:prove window event, and the postMessage round-trip is in the noise on a 1–9 s proof.

Parameters

ParameterType
circuitZkCircuit
innerProver

Returns

Prover


wipeBytes()

function wipeBytes(buf): void;

Best-effort overwrite of secret material in a Uint8Array.

Useful for keypair / signature buffers that we want to keep out of GC scan paths once we’re done with them. Does not protect against:

  • copies the runtime made for V8 small-string interning
  • JIT optimization passes that re-materialize the buffer
  • same-process attackers with arbitrary read

It’s worth the call (cheap, makes core dumps less interesting) but should not be treated as a strong erasure primitive.

Parameters

ParameterType
bufUint8Array

Returns

void


createWebWorkerProver()

function createWebWorkerProver(opts): Prover;

Build a Prover backed by a Web Worker.

Concurrency: jobs are processed strictly in order. Calling prove() while another job is in flight enqueues the new request — no parallel execution (proving is CPU-bound; parallel jobs would just contend) and no thundering-herd wake-up.

Cancellation: an aborted signal rejects immediately whether the job is queued or running. A running job’s worker is terminated (cheapest way to stop snarkjs mid-flight) and a fresh one spawns on the next call.

Worker errors: a runtime error from the worker tears down the instance — the worker is often in a bad state after an error and reusing it produces unpredictable failures. The next call spawns a fresh worker (or hits fallbackProve).

Parameters

ParameterType
optsWebWorkerProverOpts

Returns

Prover


createLazyWorkerProver()

function createLazyWorkerProver(opts): Prover;

Lazy-singleton authorize/claim/deposit/etc prover, wrapped with the standard timing reporter. Apps used to hand-roll this five-line pattern per circuit (apps/pro/app/lib/{authorize,cancel,claim, deposit}Prover.ts); this single helper supersedes them. The worker URL stays at the call site because Webpack/Turbopack resolves import.meta.url only when seen as a literal there.

Parameters

ParameterType
optsLazyWorkerProverOpts

Returns

Prover


setupProverWorker()

function setupProverWorker(handlers): { postProgress: void; };

Wire a Web Worker script to the SDK’s prover protocol.

Usage from a circuit-specific worker file (consumer-owned):

// apps/<name>/workers/deposit.worker.ts import { setupProverWorker, warmupPoseidon, generateDepositProof, } from "@zkscatter/sdk/zk"; setupProverWorker({ preload: () => warmupPoseidon(), prove: async (req) => { const { proof, publicSignals } = await generateDepositProof( req.input as never, { wasm: "/zk/deposit.wasm", zkey: "/zk/deposit.zkey" }, ); return { proof, publicSignals }; }, });

The runtime handles message decoding, request validation, and error wrapping. Per-job progress messages can be sent with the returned postProgress helper.

Parameters

ParameterType
handlersProverWorkerHandlers

Returns

postProgress()
postProgress(jobId, message): void;

Send a progress message to the main thread for a job in flight. No-op outside a Web Worker context.

Parameters
ParameterType
jobIdnumber
messagestring
Returns

void


prefetchAssets()

function prefetchAssets(urls): Promise<void>;

Best-effort prefetch — never throws so callers can void prefetchAssets(...) from a fire-and-forget context.

Parameters

ParameterType
urlsreadonly string[]

Returns

Promise<void>


withCachedAssets()

function withCachedAssets<T>(paths, run): Promise<T>;

Resolve wasm + zkey to Blob URLs (or fall back to canonical), hand them to run, and revoke when run settles. resolveAsset always fulfils (errors fall back to the canonical URL with a no-op revoke), so a plain Promise.all is equivalent to and clearer than Promise.allSettled here.

Type Parameters

Type Parameter
T

Parameters

ParameterType
paths{ wasm: string; zkey: string; }
paths.wasmstring
paths.zkeystring
run(urls) => Promise<T>

Returns

Promise<T>


warmProverAssets()

function warmProverAssets(paths): Promise<void>;

Worker preload one-liner: resolves snarkjs + warms Poseidon + prefetches the circuit’s wasm/zkey in parallel. Replaces the four near-identical preload bodies that lived in *-worker.ts.

Parameters

ParameterType
paths{ wasm: string; zkey: string; }
paths.wasmstring
paths.zkeystring

Returns

Promise<void>

Last updated on