@sip-protocol/sdk 0.6.6 → 0.6.8

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.
package/dist/browser.js CHANGED
@@ -21291,6 +21291,8 @@ var BrowserNoirProvider = class _BrowserNoirProvider {
21291
21291
  validityBackend = null;
21292
21292
  fulfillmentNoir = null;
21293
21293
  fulfillmentBackend = null;
21294
+ // Mutex for WASM operations (prevents BorrowMutError from concurrent access)
21295
+ wasmMutex = Promise.resolve();
21294
21296
  // Worker instance (optional)
21295
21297
  worker = null;
21296
21298
  workerPending = /* @__PURE__ */ new Map();
@@ -21590,57 +21592,59 @@ var BrowserNoirProvider = class _BrowserNoirProvider {
21590
21592
  if (!this.fundingNoir || !this.fundingBackend) {
21591
21593
  throw new ProofGenerationError("funding", "Funding circuit not initialized");
21592
21594
  }
21593
- try {
21594
- onProgress?.({
21595
- stage: "witness",
21596
- percent: 10,
21597
- message: "Preparing witness inputs..."
21598
- });
21599
- const blindingField = this.bytesToField(params.blindingFactor);
21600
- const witnessInputs = {
21601
- minimum_required: `0x${params.minimumRequired.toString(16)}`,
21602
- asset_id: `0x${this.assetIdToField(params.assetId)}`,
21603
- balance: `0x${params.balance.toString(16)}`,
21604
- blinding: blindingField
21605
- };
21606
- onProgress?.({
21607
- stage: "witness",
21608
- percent: 30,
21609
- message: "Generating witness..."
21610
- });
21611
- const { witness, returnValue } = await this.fundingNoir.execute(witnessInputs);
21612
- onProgress?.({
21613
- stage: "proving",
21614
- percent: 50,
21615
- message: "Generating proof (this may take a moment)..."
21616
- });
21617
- const proofData = await this.fundingBackend.generateProof(witness);
21618
- onProgress?.({
21619
- stage: "complete",
21620
- percent: 100,
21621
- message: "Proof generated successfully"
21622
- });
21623
- const commitmentHashBytes = returnValue;
21624
- const commitmentHashHex = bytesToHex11(new Uint8Array(commitmentHashBytes));
21625
- const publicInputs = [
21626
- `0x${params.minimumRequired.toString(16).padStart(64, "0")}`,
21627
- `0x${this.assetIdToField(params.assetId)}`,
21628
- `0x${commitmentHashHex}`
21629
- ];
21630
- const proof = {
21631
- type: "funding",
21632
- proof: `0x${bytesToHex11(proofData.proof)}`,
21633
- publicInputs
21634
- };
21635
- return { proof, publicInputs };
21636
- } catch (error) {
21637
- const message = error instanceof Error ? error.message : String(error);
21638
- throw new ProofGenerationError(
21639
- "funding",
21640
- `Failed to generate funding proof: ${message}`,
21641
- error instanceof Error ? error : void 0
21642
- );
21643
- }
21595
+ return this.acquireWasmLock(async () => {
21596
+ try {
21597
+ onProgress?.({
21598
+ stage: "witness",
21599
+ percent: 10,
21600
+ message: "Preparing witness inputs..."
21601
+ });
21602
+ const blindingField = this.bytesToField(params.blindingFactor);
21603
+ const witnessInputs = {
21604
+ minimum_required: `0x${params.minimumRequired.toString(16)}`,
21605
+ asset_id: `0x${this.assetIdToField(params.assetId)}`,
21606
+ balance: `0x${params.balance.toString(16)}`,
21607
+ blinding: blindingField
21608
+ };
21609
+ onProgress?.({
21610
+ stage: "witness",
21611
+ percent: 30,
21612
+ message: "Generating witness..."
21613
+ });
21614
+ const { witness, returnValue } = await this.fundingNoir.execute(witnessInputs);
21615
+ onProgress?.({
21616
+ stage: "proving",
21617
+ percent: 50,
21618
+ message: "Generating proof (this may take a moment)..."
21619
+ });
21620
+ const proofData = await this.fundingBackend.generateProof(witness);
21621
+ onProgress?.({
21622
+ stage: "complete",
21623
+ percent: 100,
21624
+ message: "Proof generated successfully"
21625
+ });
21626
+ const commitmentHashBytes = returnValue;
21627
+ const commitmentHashHex = bytesToHex11(new Uint8Array(commitmentHashBytes));
21628
+ const publicInputs = [
21629
+ `0x${params.minimumRequired.toString(16).padStart(64, "0")}`,
21630
+ `0x${this.assetIdToField(params.assetId)}`,
21631
+ `0x${commitmentHashHex}`
21632
+ ];
21633
+ const proof = {
21634
+ type: "funding",
21635
+ proof: `0x${bytesToHex11(proofData.proof)}`,
21636
+ publicInputs
21637
+ };
21638
+ return { proof, publicInputs };
21639
+ } catch (error) {
21640
+ const message = error instanceof Error ? error.message : String(error);
21641
+ throw new ProofGenerationError(
21642
+ "funding",
21643
+ `Failed to generate funding proof: ${message}`,
21644
+ error instanceof Error ? error : void 0
21645
+ );
21646
+ }
21647
+ });
21644
21648
  }
21645
21649
  /**
21646
21650
  * Generate a Validity Proof
@@ -21652,89 +21656,91 @@ var BrowserNoirProvider = class _BrowserNoirProvider {
21652
21656
  if (!this.validityNoir || !this.validityBackend) {
21653
21657
  throw new ProofGenerationError("validity", "Validity circuit not initialized");
21654
21658
  }
21655
- try {
21656
- onProgress?.({
21657
- stage: "witness",
21658
- percent: 10,
21659
- message: "Preparing validity witness..."
21660
- });
21661
- const intentHashField = this.hexToField(params.intentHash);
21662
- const senderAddressField = this.hexToField(params.senderAddress);
21663
- const senderBlindingField = this.bytesToField(params.senderBlinding);
21664
- const senderSecretField = this.bytesToField(params.senderSecret);
21665
- const nonceField = this.bytesToField(params.nonce);
21666
- const { commitmentX, commitmentY } = await this.computeSenderCommitment(
21667
- senderAddressField,
21668
- senderBlindingField
21669
- );
21670
- const nullifier = await this.computeNullifier(senderSecretField, intentHashField, nonceField);
21671
- const signature = Array.from(params.authorizationSignature);
21672
- const messageHash = this.fieldToBytes32(intentHashField);
21673
- let pubKeyX;
21674
- let pubKeyY;
21675
- if (params.senderPublicKey) {
21676
- pubKeyX = Array.from(params.senderPublicKey.x);
21677
- pubKeyY = Array.from(params.senderPublicKey.y);
21678
- } else {
21679
- const coords = this.getPublicKeyCoordinates(params.senderSecret);
21680
- pubKeyX = coords.x;
21681
- pubKeyY = coords.y;
21682
- }
21683
- const witnessInputs = {
21684
- intent_hash: intentHashField,
21685
- sender_commitment_x: commitmentX,
21686
- sender_commitment_y: commitmentY,
21687
- nullifier,
21688
- timestamp: params.timestamp.toString(),
21689
- expiry: params.expiry.toString(),
21690
- sender_address: senderAddressField,
21691
- sender_blinding: senderBlindingField,
21692
- sender_secret: senderSecretField,
21693
- pub_key_x: pubKeyX,
21694
- pub_key_y: pubKeyY,
21695
- signature,
21696
- message_hash: messageHash,
21697
- nonce: nonceField
21698
- };
21699
- onProgress?.({
21700
- stage: "witness",
21701
- percent: 30,
21702
- message: "Generating witness..."
21703
- });
21704
- const { witness } = await this.validityNoir.execute(witnessInputs);
21705
- onProgress?.({
21706
- stage: "proving",
21707
- percent: 50,
21708
- message: "Generating validity proof..."
21709
- });
21710
- const proofData = await this.validityBackend.generateProof(witness);
21711
- onProgress?.({
21712
- stage: "complete",
21713
- percent: 100,
21714
- message: "Validity proof generated"
21715
- });
21716
- const publicInputs = [
21717
- `0x${intentHashField}`,
21718
- `0x${commitmentX}`,
21719
- `0x${commitmentY}`,
21720
- `0x${nullifier}`,
21721
- `0x${params.timestamp.toString(16).padStart(16, "0")}`,
21722
- `0x${params.expiry.toString(16).padStart(16, "0")}`
21723
- ];
21724
- const proof = {
21725
- type: "validity",
21726
- proof: `0x${bytesToHex11(proofData.proof)}`,
21727
- publicInputs
21728
- };
21729
- return { proof, publicInputs };
21730
- } catch (error) {
21731
- const message = error instanceof Error ? error.message : String(error);
21732
- throw new ProofGenerationError(
21733
- "validity",
21734
- `Failed to generate validity proof: ${message}`,
21735
- error instanceof Error ? error : void 0
21736
- );
21737
- }
21659
+ return this.acquireWasmLock(async () => {
21660
+ try {
21661
+ onProgress?.({
21662
+ stage: "witness",
21663
+ percent: 10,
21664
+ message: "Preparing validity witness..."
21665
+ });
21666
+ const intentHashField = this.hexToField(params.intentHash);
21667
+ const senderAddressField = this.hexToField(params.senderAddress);
21668
+ const senderBlindingField = this.bytesToField(params.senderBlinding);
21669
+ const senderSecretField = this.bytesToField(params.senderSecret);
21670
+ const nonceField = this.bytesToField(params.nonce);
21671
+ const { commitmentX, commitmentY } = await this.computeSenderCommitment(
21672
+ senderAddressField,
21673
+ senderBlindingField
21674
+ );
21675
+ const nullifier = await this.computeNullifier(senderSecretField, intentHashField, nonceField);
21676
+ const signature = Array.from(params.authorizationSignature);
21677
+ const messageHash = this.fieldToBytes32(intentHashField);
21678
+ let pubKeyX;
21679
+ let pubKeyY;
21680
+ if (params.senderPublicKey) {
21681
+ pubKeyX = Array.from(params.senderPublicKey.x);
21682
+ pubKeyY = Array.from(params.senderPublicKey.y);
21683
+ } else {
21684
+ const coords = this.getPublicKeyCoordinates(params.senderSecret);
21685
+ pubKeyX = coords.x;
21686
+ pubKeyY = coords.y;
21687
+ }
21688
+ const witnessInputs = {
21689
+ intent_hash: intentHashField,
21690
+ sender_commitment_x: commitmentX,
21691
+ sender_commitment_y: commitmentY,
21692
+ nullifier,
21693
+ timestamp: params.timestamp.toString(),
21694
+ expiry: params.expiry.toString(),
21695
+ sender_address: senderAddressField,
21696
+ sender_blinding: senderBlindingField,
21697
+ sender_secret: senderSecretField,
21698
+ pub_key_x: pubKeyX,
21699
+ pub_key_y: pubKeyY,
21700
+ signature,
21701
+ message_hash: messageHash,
21702
+ nonce: nonceField
21703
+ };
21704
+ onProgress?.({
21705
+ stage: "witness",
21706
+ percent: 30,
21707
+ message: "Generating witness..."
21708
+ });
21709
+ const { witness } = await this.validityNoir.execute(witnessInputs);
21710
+ onProgress?.({
21711
+ stage: "proving",
21712
+ percent: 50,
21713
+ message: "Generating validity proof..."
21714
+ });
21715
+ const proofData = await this.validityBackend.generateProof(witness);
21716
+ onProgress?.({
21717
+ stage: "complete",
21718
+ percent: 100,
21719
+ message: "Validity proof generated"
21720
+ });
21721
+ const publicInputs = [
21722
+ `0x${intentHashField}`,
21723
+ `0x${commitmentX}`,
21724
+ `0x${commitmentY}`,
21725
+ `0x${nullifier}`,
21726
+ `0x${params.timestamp.toString(16).padStart(16, "0")}`,
21727
+ `0x${params.expiry.toString(16).padStart(16, "0")}`
21728
+ ];
21729
+ const proof = {
21730
+ type: "validity",
21731
+ proof: `0x${bytesToHex11(proofData.proof)}`,
21732
+ publicInputs
21733
+ };
21734
+ return { proof, publicInputs };
21735
+ } catch (error) {
21736
+ const message = error instanceof Error ? error.message : String(error);
21737
+ throw new ProofGenerationError(
21738
+ "validity",
21739
+ `Failed to generate validity proof: ${message}`,
21740
+ error instanceof Error ? error : void 0
21741
+ );
21742
+ }
21743
+ });
21738
21744
  }
21739
21745
  /**
21740
21746
  * Generate a Fulfillment Proof
@@ -21746,95 +21752,97 @@ var BrowserNoirProvider = class _BrowserNoirProvider {
21746
21752
  if (!this.fulfillmentNoir || !this.fulfillmentBackend) {
21747
21753
  throw new ProofGenerationError("fulfillment", "Fulfillment circuit not initialized");
21748
21754
  }
21749
- try {
21750
- onProgress?.({
21751
- stage: "witness",
21752
- percent: 10,
21753
- message: "Preparing fulfillment witness..."
21754
- });
21755
- const intentHashField = this.hexToField(params.intentHash);
21756
- const recipientStealthField = this.hexToField(params.recipientStealth);
21757
- const { commitmentX, commitmentY } = await this.computeOutputCommitment(
21758
- params.outputAmount,
21759
- params.outputBlinding
21760
- );
21761
- const solverSecretField = this.bytesToField(params.solverSecret);
21762
- const solverId = await this.computeSolverId(solverSecretField);
21763
- const outputBlindingField = this.bytesToField(params.outputBlinding);
21764
- const attestation = params.oracleAttestation;
21765
- const attestationRecipientField = this.hexToField(attestation.recipient);
21766
- const attestationTxHashField = this.hexToField(attestation.txHash);
21767
- const oracleSignature = Array.from(attestation.signature);
21768
- const oracleMessageHash = await this.computeOracleMessageHash(
21769
- attestation.recipient,
21770
- attestation.amount,
21771
- attestation.txHash,
21772
- attestation.blockNumber
21773
- );
21774
- const oraclePubKeyX = this.config.oraclePublicKey?.x ?? new Array(32).fill(0);
21775
- const oraclePubKeyY = this.config.oraclePublicKey?.y ?? new Array(32).fill(0);
21776
- const witnessInputs = {
21777
- intent_hash: intentHashField,
21778
- output_commitment_x: commitmentX,
21779
- output_commitment_y: commitmentY,
21780
- recipient_stealth: recipientStealthField,
21781
- min_output_amount: params.minOutputAmount.toString(),
21782
- solver_id: solverId,
21783
- fulfillment_time: params.fulfillmentTime.toString(),
21784
- expiry: params.expiry.toString(),
21785
- output_amount: params.outputAmount.toString(),
21786
- output_blinding: outputBlindingField,
21787
- solver_secret: solverSecretField,
21788
- attestation_recipient: attestationRecipientField,
21789
- attestation_amount: attestation.amount.toString(),
21790
- attestation_tx_hash: attestationTxHashField,
21791
- attestation_block: attestation.blockNumber.toString(),
21792
- oracle_signature: oracleSignature,
21793
- oracle_message_hash: oracleMessageHash,
21794
- oracle_pub_key_x: oraclePubKeyX,
21795
- oracle_pub_key_y: oraclePubKeyY
21796
- };
21797
- onProgress?.({
21798
- stage: "witness",
21799
- percent: 30,
21800
- message: "Generating witness..."
21801
- });
21802
- const { witness } = await this.fulfillmentNoir.execute(witnessInputs);
21803
- onProgress?.({
21804
- stage: "proving",
21805
- percent: 50,
21806
- message: "Generating fulfillment proof..."
21807
- });
21808
- const proofData = await this.fulfillmentBackend.generateProof(witness);
21809
- onProgress?.({
21810
- stage: "complete",
21811
- percent: 100,
21812
- message: "Fulfillment proof generated"
21813
- });
21814
- const publicInputs = [
21815
- `0x${intentHashField}`,
21816
- `0x${commitmentX}`,
21817
- `0x${commitmentY}`,
21818
- `0x${recipientStealthField}`,
21819
- `0x${params.minOutputAmount.toString(16).padStart(16, "0")}`,
21820
- `0x${solverId}`,
21821
- `0x${params.fulfillmentTime.toString(16).padStart(16, "0")}`,
21822
- `0x${params.expiry.toString(16).padStart(16, "0")}`
21823
- ];
21824
- const proof = {
21825
- type: "fulfillment",
21826
- proof: `0x${bytesToHex11(proofData.proof)}`,
21827
- publicInputs
21828
- };
21829
- return { proof, publicInputs };
21830
- } catch (error) {
21831
- const message = error instanceof Error ? error.message : String(error);
21832
- throw new ProofGenerationError(
21833
- "fulfillment",
21834
- `Failed to generate fulfillment proof: ${message}`,
21835
- error instanceof Error ? error : void 0
21836
- );
21837
- }
21755
+ return this.acquireWasmLock(async () => {
21756
+ try {
21757
+ onProgress?.({
21758
+ stage: "witness",
21759
+ percent: 10,
21760
+ message: "Preparing fulfillment witness..."
21761
+ });
21762
+ const intentHashField = this.hexToField(params.intentHash);
21763
+ const recipientStealthField = this.hexToField(params.recipientStealth);
21764
+ const { commitmentX, commitmentY } = await this.computeOutputCommitment(
21765
+ params.outputAmount,
21766
+ params.outputBlinding
21767
+ );
21768
+ const solverSecretField = this.bytesToField(params.solverSecret);
21769
+ const solverId = await this.computeSolverId(solverSecretField);
21770
+ const outputBlindingField = this.bytesToField(params.outputBlinding);
21771
+ const attestation = params.oracleAttestation;
21772
+ const attestationRecipientField = this.hexToField(attestation.recipient);
21773
+ const attestationTxHashField = this.hexToField(attestation.txHash);
21774
+ const oracleSignature = Array.from(attestation.signature);
21775
+ const oracleMessageHash = await this.computeOracleMessageHash(
21776
+ attestation.recipient,
21777
+ attestation.amount,
21778
+ attestation.txHash,
21779
+ attestation.blockNumber
21780
+ );
21781
+ const oraclePubKeyX = this.config.oraclePublicKey?.x ?? new Array(32).fill(0);
21782
+ const oraclePubKeyY = this.config.oraclePublicKey?.y ?? new Array(32).fill(0);
21783
+ const witnessInputs = {
21784
+ intent_hash: intentHashField,
21785
+ output_commitment_x: commitmentX,
21786
+ output_commitment_y: commitmentY,
21787
+ recipient_stealth: recipientStealthField,
21788
+ min_output_amount: params.minOutputAmount.toString(),
21789
+ solver_id: solverId,
21790
+ fulfillment_time: params.fulfillmentTime.toString(),
21791
+ expiry: params.expiry.toString(),
21792
+ output_amount: params.outputAmount.toString(),
21793
+ output_blinding: outputBlindingField,
21794
+ solver_secret: solverSecretField,
21795
+ attestation_recipient: attestationRecipientField,
21796
+ attestation_amount: attestation.amount.toString(),
21797
+ attestation_tx_hash: attestationTxHashField,
21798
+ attestation_block: attestation.blockNumber.toString(),
21799
+ oracle_signature: oracleSignature,
21800
+ oracle_message_hash: oracleMessageHash,
21801
+ oracle_pub_key_x: oraclePubKeyX,
21802
+ oracle_pub_key_y: oraclePubKeyY
21803
+ };
21804
+ onProgress?.({
21805
+ stage: "witness",
21806
+ percent: 30,
21807
+ message: "Generating witness..."
21808
+ });
21809
+ const { witness } = await this.fulfillmentNoir.execute(witnessInputs);
21810
+ onProgress?.({
21811
+ stage: "proving",
21812
+ percent: 50,
21813
+ message: "Generating fulfillment proof..."
21814
+ });
21815
+ const proofData = await this.fulfillmentBackend.generateProof(witness);
21816
+ onProgress?.({
21817
+ stage: "complete",
21818
+ percent: 100,
21819
+ message: "Fulfillment proof generated"
21820
+ });
21821
+ const publicInputs = [
21822
+ `0x${intentHashField}`,
21823
+ `0x${commitmentX}`,
21824
+ `0x${commitmentY}`,
21825
+ `0x${recipientStealthField}`,
21826
+ `0x${params.minOutputAmount.toString(16).padStart(16, "0")}`,
21827
+ `0x${solverId}`,
21828
+ `0x${params.fulfillmentTime.toString(16).padStart(16, "0")}`,
21829
+ `0x${params.expiry.toString(16).padStart(16, "0")}`
21830
+ ];
21831
+ const proof = {
21832
+ type: "fulfillment",
21833
+ proof: `0x${bytesToHex11(proofData.proof)}`,
21834
+ publicInputs
21835
+ };
21836
+ return { proof, publicInputs };
21837
+ } catch (error) {
21838
+ const message = error instanceof Error ? error.message : String(error);
21839
+ throw new ProofGenerationError(
21840
+ "fulfillment",
21841
+ `Failed to generate fulfillment proof: ${message}`,
21842
+ error instanceof Error ? error : void 0
21843
+ );
21844
+ }
21845
+ });
21838
21846
  }
21839
21847
  /**
21840
21848
  * Verify a proof
@@ -21861,22 +21869,25 @@ var BrowserNoirProvider = class _BrowserNoirProvider {
21861
21869
  "SIP_4004" /* PROOF_PROVIDER_NOT_READY */
21862
21870
  );
21863
21871
  }
21864
- try {
21865
- const proofHex = proof.proof.startsWith("0x") ? proof.proof.slice(2) : proof.proof;
21866
- const proofBytes = hexToBytes9(proofHex);
21867
- const isValid = await backend.verifyProof({
21868
- proof: proofBytes,
21869
- publicInputs: proof.publicInputs.map(
21870
- (input) => input.startsWith("0x") ? input.slice(2) : input
21871
- )
21872
- });
21873
- return isValid;
21874
- } catch (error) {
21875
- if (this.config.verbose) {
21876
- console.error("[BrowserNoirProvider] Verification error:", error);
21872
+ const backendToUse = backend;
21873
+ return this.acquireWasmLock(async () => {
21874
+ try {
21875
+ const proofHex = proof.proof.startsWith("0x") ? proof.proof.slice(2) : proof.proof;
21876
+ const proofBytes = hexToBytes9(proofHex);
21877
+ const isValid = await backendToUse.verifyProof({
21878
+ proof: proofBytes,
21879
+ publicInputs: proof.publicInputs.map(
21880
+ (input) => input.startsWith("0x") ? input.slice(2) : input
21881
+ )
21882
+ });
21883
+ return isValid;
21884
+ } catch (error) {
21885
+ if (this.config.verbose) {
21886
+ console.error("[BrowserNoirProvider] Verification error:", error);
21887
+ }
21888
+ return false;
21877
21889
  }
21878
- return false;
21879
- }
21890
+ });
21880
21891
  }
21881
21892
  /**
21882
21893
  * Destroy the provider and free resources
@@ -21904,6 +21915,25 @@ var BrowserNoirProvider = class _BrowserNoirProvider {
21904
21915
  this._isReady = false;
21905
21916
  }
21906
21917
  // ─── Private Utility Methods ────────────────────────────────────────────────
21918
+ /**
21919
+ * Acquire WASM mutex lock for exclusive access
21920
+ *
21921
+ * The ACVM WASM module uses Rust RefCell internally which panics on
21922
+ * concurrent mutable borrows. This mutex ensures serial execution.
21923
+ */
21924
+ async acquireWasmLock(operation) {
21925
+ const previousLock = this.wasmMutex;
21926
+ let releaseLock;
21927
+ this.wasmMutex = new Promise((resolve) => {
21928
+ releaseLock = resolve;
21929
+ });
21930
+ try {
21931
+ await previousLock;
21932
+ return await operation();
21933
+ } finally {
21934
+ releaseLock();
21935
+ }
21936
+ }
21907
21937
  ensureReady() {
21908
21938
  if (!this._isReady) {
21909
21939
  throw new ProofError(