@arcanetech/privacy-sdk-stellar 0.6.1 → 1.0.0-rc.0

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/index.js CHANGED
@@ -936,14 +936,39 @@ function uniformApplicationIdHints(applicationId, nAuditSlots) {
936
936
  }
937
937
 
938
938
  // src/transact/proofs/confidential/helpers.ts
939
- import { withdrawObjectFromMerkleWitness } from "@arcanetech/stellar-privacy-pool-zk-sdk";
939
+ import {
940
+ withdrawObjectFromEscrowMerkleWitness,
941
+ withdrawObjectFromMerkleWitness
942
+ } from "@arcanetech/stellar-privacy-pool-zk-sdk";
940
943
  var MIN_CONFIDENTIAL_TRANSFER_STROOPS = 1n;
941
944
  var ZERO_STROOPS = 0n;
945
+ function escrowSpendWitnessFromLimbs(limbs, derivedScalarHex) {
946
+ const nonce = limbs.nonceDecimal?.trim() ?? "";
947
+ if (!nonce) {
948
+ throw new Error("Escrow claimant limbs require nonceDecimal");
949
+ }
950
+ return {
951
+ nonce,
952
+ recipientHi: limbs.recipientHi,
953
+ recipientLo: limbs.recipientLo,
954
+ derivedScalarHex
955
+ };
956
+ }
942
957
  function withdrawWitnessForCoin(parameters) {
943
958
  const { sdk, coin, state } = parameters;
944
959
  const witness = withdrawMerkleWitnessFromTree({ sdk, coin, state });
945
960
  const withdrawApplicationId = coin.application_id ?? parameters.applicationId;
946
- const withdrawObject = withdrawObjectFromMerkleWitness(
961
+ const withdrawObject = parameters.escrow ? withdrawObjectFromEscrowMerkleWitness(
962
+ witness,
963
+ parameters.ownerPubHex,
964
+ withdrawApplicationId,
965
+ parameters.escrow.derivedScalarHex,
966
+ {
967
+ nonce: parameters.escrow.nonce,
968
+ recipientHi: parameters.escrow.recipientHi,
969
+ recipientLo: parameters.escrow.recipientLo
970
+ }
971
+ ) : withdrawObjectFromMerkleWitness(
947
972
  witness,
948
973
  parameters.ownerPubHex,
949
974
  withdrawApplicationId,
@@ -952,21 +977,21 @@ function withdrawWitnessForCoin(parameters) {
952
977
  return { witness, withdrawObject };
953
978
  }
954
979
  function dualWithdrawLegsWithSharedRoot(parameters) {
955
- const legA = withdrawWitnessForCoin({
980
+ const shared = {
956
981
  sdk: parameters.sdk,
957
- coin: parameters.coinA,
958
982
  state: parameters.state,
959
983
  ownerPubHex: parameters.ownerPubHex,
960
984
  privKeyScalar: parameters.privKeyScalar,
961
- applicationId: parameters.applicationId
985
+ applicationId: parameters.applicationId,
986
+ ...parameters.escrow ? { escrow: parameters.escrow } : {}
987
+ };
988
+ const legA = withdrawWitnessForCoin({
989
+ ...shared,
990
+ coin: parameters.coinA
962
991
  });
963
992
  const legB = withdrawWitnessForCoin({
964
- sdk: parameters.sdk,
965
- coin: parameters.coinB,
966
- state: parameters.state,
967
- ownerPubHex: parameters.ownerPubHex,
968
- privKeyScalar: parameters.privKeyScalar,
969
- applicationId: parameters.applicationId
993
+ ...shared,
994
+ coin: parameters.coinB
970
995
  });
971
996
  if (legA.witness.stateRoot !== legB.witness.stateRoot) {
972
997
  throw new Error("Merkle state root mismatch between input coins");
@@ -1237,7 +1262,10 @@ function ed25519PublicKeyHexFromStellarAccount(address) {
1237
1262
  }
1238
1263
 
1239
1264
  // src/transact/encoding/priv-key-scalar-from-recipient-hex.ts
1240
- import { canonicalBabyJubScalarFromInteger } from "@arcanetech/stellar-privacy-pool-zk-sdk";
1265
+ import {
1266
+ canonicalBabyJubScalarFromInteger,
1267
+ reduceDerivedEscrowSpendScalar
1268
+ } from "@arcanetech/stellar-privacy-pool-zk-sdk";
1241
1269
  var SCALAR_HEX_CHAR_LENGTH = 64;
1242
1270
  var DECIMAL_RADIX2 = 10;
1243
1271
  function normalizeRecipientScalarHex(hexInput) {
@@ -1260,6 +1288,25 @@ function privKeyScalarDecimalFromRecipientScalarHex(hexInput) {
1260
1288
  const value = BigInt(`0x${hex}`);
1261
1289
  return canonicalBabyJubScalarFromInteger(value).toString(DECIMAL_RADIX2);
1262
1290
  }
1291
+ function privKeyScalarDecimalFromDerivedEscrowHex(hexInput) {
1292
+ const hex = normalizeRecipientScalarHex(hexInput);
1293
+ const value = BigInt(`0x${hex}`);
1294
+ return reduceDerivedEscrowSpendScalar(value).toString(DECIMAL_RADIX2);
1295
+ }
1296
+ function resolveTransferSpendScalars(input) {
1297
+ const senderHex = input.senderPrivKeyScalarHex;
1298
+ if (!input.escrowSweep) {
1299
+ return {
1300
+ privKeyScalar: privKeyScalarDecimalFromRecipientScalarHex(senderHex),
1301
+ ownerScalarHex: senderHex
1302
+ };
1303
+ }
1304
+ const privKeyScalar = privKeyScalarDecimalFromDerivedEscrowHex(senderHex);
1305
+ return {
1306
+ privKeyScalar,
1307
+ ownerScalarHex: BigInt(privKeyScalar).toString(16).padStart(SCALAR_HEX_CHAR_LENGTH, "0")
1308
+ };
1309
+ }
1263
1310
 
1264
1311
  // src/transact/fees/append-fee-output.ts
1265
1312
  function feeCoinFromSlot(slot) {
@@ -5713,6 +5760,9 @@ function createNullifierSpentChecker(transactEnvironment) {
5713
5760
  };
5714
5761
  }
5715
5762
 
5763
+ // src/client/assess-incoming-note-network.ts
5764
+ import { commitmentHexFromNoteOpening } from "@arcanetech/stellar-privacy-pool-zk-sdk";
5765
+
5716
5766
  // src/client/pool-sync.ts
5717
5767
  function requireTransactEnvironment(transactEnvironment) {
5718
5768
  if (!transactEnvironment) {
@@ -5751,6 +5801,129 @@ async function readPoolLeafEphemeralHexWithEnvironment(transactEnvironment, inpu
5751
5801
  });
5752
5802
  }
5753
5803
 
5804
+ // src/client/assess-incoming-note.ts
5805
+ var COMMITMENT_HEX_LENGTH = 64;
5806
+ function normalizeCommitmentHex(value) {
5807
+ return value.trim().replace(/^0x/iu, "").toLowerCase().padStart(COMMITMENT_HEX_LENGTH, "0");
5808
+ }
5809
+ function commitmentDecimalFromHex(hex) {
5810
+ return BigInt(`0x${normalizeCommitmentHex(hex)}`).toString();
5811
+ }
5812
+ function commitmentFieldsAgree(input) {
5813
+ const recomputedHex = normalizeCommitmentHex(input.recomputedCommitmentHex);
5814
+ if (recomputedHex !== normalizeCommitmentHex(input.deliveredCommitmentHex)) {
5815
+ return false;
5816
+ }
5817
+ try {
5818
+ return BigInt(input.noteCommitmentDecimal.trim()) === BigInt(`0x${recomputedHex}`);
5819
+ } catch {
5820
+ return false;
5821
+ }
5822
+ }
5823
+ async function assessIncomingNote(input) {
5824
+ const assessmentInput = {
5825
+ note: input.note,
5826
+ commitmentHex: input.commitmentHex,
5827
+ privKeyScalarHex: input.privKeyScalarHex
5828
+ };
5829
+ const recomputedHex = await input.ports.recomputeCommitmentHex(assessmentInput);
5830
+ if (!commitmentFieldsAgree({
5831
+ noteCommitmentDecimal: input.note.commitment,
5832
+ deliveredCommitmentHex: input.commitmentHex,
5833
+ recomputedCommitmentHex: recomputedHex
5834
+ })) {
5835
+ return { kind: "dead", reason: "commitment_mismatch" };
5836
+ }
5837
+ const commitmentDecimal = commitmentDecimalFromHex(recomputedHex);
5838
+ const leafPresent = await input.ports.hasCommitmentLeaf(commitmentDecimal);
5839
+ if (!leafPresent) {
5840
+ return { kind: "pending" };
5841
+ }
5842
+ const nullifierHashHex = await input.ports.calculateNullifierHash(
5843
+ input.note.nullifier,
5844
+ privKeyScalarDecimalFromRecipientScalarHex(input.privKeyScalarHex)
5845
+ );
5846
+ const consumed = await input.ports.isNullifierConsumed(nullifierHashHex);
5847
+ if (consumed) {
5848
+ return { kind: "dead", reason: "nullifier_consumed" };
5849
+ }
5850
+ return { kind: "spendable" };
5851
+ }
5852
+
5853
+ // src/client/assess-incoming-note-network.ts
5854
+ function noteApplicationId(note, environment) {
5855
+ const fromNote = note.application_id?.trim();
5856
+ if (fromNote) {
5857
+ return fromNote;
5858
+ }
5859
+ return environment.network.applicationId;
5860
+ }
5861
+ async function recomputeCommitmentHexFromNote(input) {
5862
+ return commitmentHexFromNoteOpening({
5863
+ value: input.note.value,
5864
+ secret: input.note.secret,
5865
+ nullifier: input.note.nullifier,
5866
+ assetHi: input.note.asset_hi,
5867
+ assetLo: input.note.asset_lo,
5868
+ applicationId: input.applicationId,
5869
+ recipientScalarHex: input.privKeyScalarHex
5870
+ });
5871
+ }
5872
+ async function hasCommitmentLeafInPoolState(input) {
5873
+ const cached = await input.state.getPoolMerkleState(input.poolContractId);
5874
+ if ((cached?.commitments ?? []).includes(input.commitmentDecimal)) {
5875
+ return true;
5876
+ }
5877
+ await syncPoolMerkleStateWithEnvironment(input.environment, {
5878
+ poolContractId: input.poolContractId,
5879
+ walletPublicKey: input.walletPublicKey
5880
+ });
5881
+ const synced = await input.state.getPoolMerkleState(input.poolContractId);
5882
+ return (synced?.commitments ?? []).includes(input.commitmentDecimal);
5883
+ }
5884
+ function createAssessIncomingNotePorts(input) {
5885
+ const { environment, state, poolContractId, walletPublicKey } = input;
5886
+ return {
5887
+ recomputeCommitmentHex: ({ note, privKeyScalarHex }) => recomputeCommitmentHexFromNote({
5888
+ note,
5889
+ privKeyScalarHex,
5890
+ applicationId: noteApplicationId(note, environment)
5891
+ }),
5892
+ hasCommitmentLeaf: (commitmentDecimal) => hasCommitmentLeafInPoolState({
5893
+ environment,
5894
+ state,
5895
+ poolContractId,
5896
+ walletPublicKey,
5897
+ commitmentDecimal
5898
+ }),
5899
+ calculateNullifierHash: (nullifier, privKeyScalarDecimal) => getPrivacyPoolService().calculateNullifierHash(nullifier, privKeyScalarDecimal),
5900
+ isNullifierConsumed: async (nullifierHashHex) => {
5901
+ const contractContext = requireContractContext(environment);
5902
+ return readNullifierConsumedOnChain({
5903
+ contractContext,
5904
+ poolContractId,
5905
+ walletPublicKey,
5906
+ nullifierHashHex
5907
+ });
5908
+ }
5909
+ };
5910
+ }
5911
+ async function assessIncomingNoteWithEnvironment(input) {
5912
+ const environment = requireNetworkEnvironment(input.transactEnvironment);
5913
+ const poolContractId = input.poolContractId?.trim() || environment.network.poolContract;
5914
+ return assessIncomingNote({
5915
+ note: input.note,
5916
+ commitmentHex: input.commitmentHex,
5917
+ privKeyScalarHex: input.privKeyScalarHex,
5918
+ ports: createAssessIncomingNotePorts({
5919
+ environment,
5920
+ state: input.state,
5921
+ poolContractId,
5922
+ walletPublicKey: input.walletPublicKey
5923
+ })
5924
+ });
5925
+ }
5926
+
5754
5927
  // src/client/network-facet.ts
5755
5928
  function createPoolNetworkFacet(input) {
5756
5929
  const { transactEnvironment } = input;
@@ -5784,6 +5957,16 @@ function createRegistryNetworkFacet(input) {
5784
5957
  })
5785
5958
  };
5786
5959
  }
5960
+ function createAssessmentNetworkFacet(input) {
5961
+ const { transactEnvironment, state } = input;
5962
+ return {
5963
+ assessIncomingNote: (assessmentInput) => assessIncomingNoteWithEnvironment({
5964
+ transactEnvironment,
5965
+ state,
5966
+ ...assessmentInput
5967
+ })
5968
+ };
5969
+ }
5787
5970
  function createRpcNetworkFacet(input) {
5788
5971
  const { transactEnvironment } = input;
5789
5972
  return {
@@ -5815,6 +5998,7 @@ function createNetworkFacet(input) {
5815
5998
  return {
5816
5999
  ...createPoolNetworkFacet(input),
5817
6000
  ...createRegistryNetworkFacet(input),
6001
+ ...createAssessmentNetworkFacet(input),
5818
6002
  ...createRpcNetworkFacet(input)
5819
6003
  };
5820
6004
  }
@@ -6027,6 +6211,7 @@ function createStellarPrivacyClientInstance(config) {
6027
6211
  registerPrivateAddress: (input) => composed.network.registerPrivateAddress(input),
6028
6212
  resolveTransferRecipient: (input) => composed.network.resolveTransferRecipient(input),
6029
6213
  checkPrivateRecordSpendStatus: (input) => composed.network.checkPrivateRecordSpendStatus(input),
6214
+ assessIncomingNote: (input) => composed.network.assessIncomingNote(input),
6030
6215
  waitForTransactionConfirmation: (input) => composed.network.waitForTransactionConfirmation(input),
6031
6216
  fetchTransactionConfirmationStatus: (txHash) => composed.network.fetchTransactionConfirmationStatus(txHash),
6032
6217
  getTransactionDetails: (txHash) => composed.network.getTransactionDetails(txHash)
@@ -6548,14 +6733,63 @@ async function buildSenderTransferDepositsAndPublicInput(parameters) {
6548
6733
  });
6549
6734
  }
6550
6735
 
6551
- // src/transact/proofs/confidential/dual.ts
6552
- function confidentialEscrowFields(parameters) {
6736
+ // src/transact/proofs/confidential/transfer-spend.ts
6737
+ function confidentialEscrowFields(input) {
6553
6738
  return {
6554
- ...parameters.escrowSend ? { escrowSend: parameters.escrowSend } : {},
6555
- ...parameters.escrowClaimantLimbs ? { escrowClaimantLimbs: parameters.escrowClaimantLimbs } : {}
6739
+ ...input.escrowSend ? { escrowSend: input.escrowSend } : {},
6740
+ ...input.escrowClaimantLimbs ? { escrowClaimantLimbs: input.escrowClaimantLimbs } : {}
6741
+ };
6742
+ }
6743
+ function transferDepositInputFromProof(input, changeStroops, stateRoot) {
6744
+ return {
6745
+ senderPrivKeyScalarHex: input.senderPrivKeyScalarHex,
6746
+ recipientPrivateAddressStpl1: input.recipientPrivateAddressStpl1,
6747
+ transferStroops: input.transferStroops,
6748
+ changeStroops,
6749
+ selfPrivateAddressStpl1ForChange: input.selfPrivateAddressStpl1ForChange,
6750
+ tokenAddress: input.tokenAddress,
6751
+ stateRoot,
6752
+ ...confidentialEscrowFields(input),
6753
+ ...input.feeOutput ? { feeOutput: input.feeOutput } : {}
6556
6754
  };
6557
6755
  }
6756
+ function spendWithdrawForTransfer(parameters) {
6757
+ const limbs = parameters.input.escrowClaimantLimbs;
6758
+ const { privKeyScalar, ownerScalarHex } = resolveTransferSpendScalars({
6759
+ senderPrivKeyScalarHex: parameters.input.senderPrivKeyScalarHex,
6760
+ escrowSweep: Boolean(limbs)
6761
+ });
6762
+ const spent = withdrawWitnessForCoin({
6763
+ sdk: parameters.sdk,
6764
+ coin: parameters.input.coin,
6765
+ state: parameters.input.state,
6766
+ ownerPubHex: parameters.sdk.ecdhEphemeralPublicKeyFromScalarHex(ownerScalarHex),
6767
+ privKeyScalar,
6768
+ applicationId: parameters.applicationId,
6769
+ ...limbs ? {
6770
+ escrow: escrowSpendWitnessFromLimbs(
6771
+ limbs,
6772
+ parameters.input.senderPrivKeyScalarHex
6773
+ )
6774
+ } : {}
6775
+ });
6776
+ if (limbs) {
6777
+ return spent;
6778
+ }
6779
+ return {
6780
+ witness: spent.witness,
6781
+ withdrawObject: stampWithdrawEscrowLimbs(
6782
+ spent.withdrawObject,
6783
+ sweepWithdrawStamp(confidentialEscrowFields(parameters.input))
6784
+ )
6785
+ };
6786
+ }
6787
+
6788
+ // src/transact/proofs/confidential/dual.ts
6558
6789
  function stampDualWithdrawLegs(legs, parameters) {
6790
+ if (parameters.escrowClaimantLimbs) {
6791
+ return legs;
6792
+ }
6559
6793
  const escrowLimbs = sweepWithdrawStamp(confidentialEscrowFields(parameters));
6560
6794
  return {
6561
6795
  legA: {
@@ -6619,12 +6853,12 @@ function dualTransferChangeStroops(parameters) {
6619
6853
  }
6620
6854
  async function buildDualTransferProofContext(parameters, applicationId, sdk) {
6621
6855
  const changeStroops = dualTransferChangeStroops(parameters);
6622
- const privKeyScalar = privKeyScalarDecimalFromRecipientScalarHex(
6623
- parameters.senderPrivKeyScalarHex
6624
- );
6625
- const ownerPubHex = sdk.ecdhEphemeralPublicKeyFromScalarHex(
6626
- parameters.senderPrivKeyScalarHex
6627
- );
6856
+ const limbs = parameters.escrowClaimantLimbs;
6857
+ const { privKeyScalar, ownerScalarHex } = resolveTransferSpendScalars({
6858
+ senderPrivKeyScalarHex: parameters.senderPrivKeyScalarHex,
6859
+ escrowSweep: Boolean(limbs)
6860
+ });
6861
+ const ownerPubHex = sdk.ecdhEphemeralPublicKeyFromScalarHex(ownerScalarHex);
6628
6862
  const { legA, legB } = stampDualWithdrawLegs(
6629
6863
  dualWithdrawLegsWithSharedRoot({
6630
6864
  sdk,
@@ -6633,7 +6867,13 @@ async function buildDualTransferProofContext(parameters, applicationId, sdk) {
6633
6867
  state: parameters.state,
6634
6868
  ownerPubHex,
6635
6869
  privKeyScalar,
6636
- applicationId
6870
+ applicationId,
6871
+ ...limbs ? {
6872
+ escrow: escrowSpendWitnessFromLimbs(
6873
+ limbs,
6874
+ parameters.senderPrivKeyScalarHex
6875
+ )
6876
+ } : {}
6637
6877
  }),
6638
6878
  parameters
6639
6879
  );
@@ -6736,25 +6976,6 @@ async function proveTransaction(parameters) {
6736
6976
  parameters.audit
6737
6977
  );
6738
6978
  }
6739
- function confidentialEscrowFields2(input) {
6740
- return {
6741
- ...input.escrowSend ? { escrowSend: input.escrowSend } : {},
6742
- ...input.escrowClaimantLimbs ? { escrowClaimantLimbs: input.escrowClaimantLimbs } : {}
6743
- };
6744
- }
6745
- function transferDepositInputFromProof(input, changeStroops, stateRoot) {
6746
- return {
6747
- senderPrivKeyScalarHex: input.senderPrivKeyScalarHex,
6748
- recipientPrivateAddressStpl1: input.recipientPrivateAddressStpl1,
6749
- transferStroops: input.transferStroops,
6750
- changeStroops,
6751
- selfPrivateAddressStpl1ForChange: input.selfPrivateAddressStpl1ForChange,
6752
- tokenAddress: input.tokenAddress,
6753
- stateRoot,
6754
- ...confidentialEscrowFields2(input),
6755
- ...input.feeOutput ? { feeOutput: input.feeOutput } : {}
6756
- };
6757
- }
6758
6979
  async function buildTransferProofInputs(parameters) {
6759
6980
  const changeStroops = validateSingleCoinTransferAmounts(
6760
6981
  parameters.input.transferStroops,
@@ -6762,35 +6983,11 @@ async function buildTransferProofInputs(parameters) {
6762
6983
  parameters.input.selfPrivateAddressStpl1ForChange,
6763
6984
  parameters.input.feeOutput?.requiredFee ?? 0n
6764
6985
  );
6765
- const privKeyScalar = privKeyScalarDecimalFromRecipientScalarHex(
6766
- parameters.input.senderPrivKeyScalarHex
6767
- );
6768
- const { witness, withdrawObject } = withdrawWitnessForCoin({
6769
- sdk: parameters.sdk,
6770
- coin: parameters.input.coin,
6771
- state: parameters.input.state,
6772
- ownerPubHex: parameters.sdk.ecdhEphemeralPublicKeyFromScalarHex(
6773
- parameters.input.senderPrivKeyScalarHex
6774
- ),
6775
- privKeyScalar,
6776
- applicationId: parameters.applicationId
6777
- });
6778
- const stampedWithdraw = stampWithdrawEscrowLimbs(
6779
- withdrawObject,
6780
- sweepWithdrawStamp(confidentialEscrowFields2(parameters.input))
6781
- );
6782
- const { recipientSlot, deposits, changeCoin, feeCoin, publicInput } = await buildSenderTransferDepositsAndPublicInput(
6986
+ const { witness, withdrawObject } = spendWithdrawForTransfer(parameters);
6987
+ const depositsBuild = await buildSenderTransferDepositsAndPublicInput(
6783
6988
  transferDepositInputFromProof(parameters.input, changeStroops, witness.stateRoot)
6784
6989
  );
6785
- return {
6786
- witness,
6787
- withdrawObject: stampedWithdraw,
6788
- recipientSlot,
6789
- deposits,
6790
- changeCoin,
6791
- feeCoin,
6792
- publicInput
6793
- };
6990
+ return { witness, withdrawObject, ...depositsBuild };
6794
6991
  }
6795
6992
  async function prepareConfidentialTransferProof(parameters) {
6796
6993
  const poolService = getPrivacyPoolService();