@permissionless-technologies/upp-sdk 0.3.5 → 0.4.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.
Files changed (140) hide show
  1. package/dist/{asp-ZA3RGN7G.js → asp-72WUGTQE.js} +3 -3
  2. package/dist/asp-72WUGTQE.js.map +1 -0
  3. package/dist/{asp-TXSAFFD3.cjs → asp-CUE3NMBN.cjs} +14 -14
  4. package/dist/asp-CUE3NMBN.cjs.map +1 -0
  5. package/dist/{chunk-KXPZUBPI.cjs → chunk-23B5XSS4.cjs} +12 -12
  6. package/dist/{chunk-KXPZUBPI.cjs.map → chunk-23B5XSS4.cjs.map} +1 -1
  7. package/dist/{chunk-SQKBT2SH.cjs → chunk-2G22R7AJ.cjs} +18 -7
  8. package/dist/chunk-2G22R7AJ.cjs.map +1 -0
  9. package/dist/chunk-5QSSX3KR.js +64 -0
  10. package/dist/chunk-5QSSX3KR.js.map +1 -0
  11. package/dist/{chunk-P37MRZ73.js → chunk-6IEYWJVS.js} +8 -8
  12. package/dist/chunk-6IEYWJVS.js.map +1 -0
  13. package/dist/{chunk-5V5HSN6Y.js → chunk-6TFDBBAQ.js} +3 -3
  14. package/dist/{chunk-5V5HSN6Y.js.map → chunk-6TFDBBAQ.js.map} +1 -1
  15. package/dist/{chunk-ZKZV6OI3.cjs → chunk-7BNJV2ZS.cjs} +21 -21
  16. package/dist/{chunk-ZKZV6OI3.cjs.map → chunk-7BNJV2ZS.cjs.map} +1 -1
  17. package/dist/{chunk-XBNYAAMU.js → chunk-7T4CUE6E.js} +3 -3
  18. package/dist/{chunk-XBNYAAMU.js.map → chunk-7T4CUE6E.js.map} +1 -1
  19. package/dist/{chunk-OD2SDC4L.js → chunk-CEJN5ZE5.js} +3 -3
  20. package/dist/{chunk-OD2SDC4L.js.map → chunk-CEJN5ZE5.js.map} +1 -1
  21. package/dist/{chunk-2JQISXBD.js → chunk-DTEAFJG7.js} +8 -8
  22. package/dist/{chunk-2JQISXBD.js.map → chunk-DTEAFJG7.js.map} +1 -1
  23. package/dist/chunk-EHGH6TAW.js +100 -0
  24. package/dist/chunk-EHGH6TAW.js.map +1 -0
  25. package/dist/{chunk-ZU6J7KMY.js → chunk-GPF72JFR.js} +3 -3
  26. package/dist/{chunk-ZU6J7KMY.js.map → chunk-GPF72JFR.js.map} +1 -1
  27. package/dist/chunk-HEHXSV47.cjs +77 -0
  28. package/dist/chunk-HEHXSV47.cjs.map +1 -0
  29. package/dist/chunk-I5EKGD4P.cjs +113 -0
  30. package/dist/chunk-I5EKGD4P.cjs.map +1 -0
  31. package/dist/{chunk-EUP7MBAH.cjs → chunk-IIUKM5VE.cjs} +7 -7
  32. package/dist/{chunk-EUP7MBAH.cjs.map → chunk-IIUKM5VE.cjs.map} +1 -1
  33. package/dist/{chunk-PJLRCR2T.js → chunk-OBBSIPEK.js} +30 -35
  34. package/dist/chunk-OBBSIPEK.js.map +1 -0
  35. package/dist/{chunk-QSL4XPNU.cjs → chunk-Q2E432UK.cjs} +41 -46
  36. package/dist/chunk-Q2E432UK.cjs.map +1 -0
  37. package/dist/{chunk-QKI4QWLT.js → chunk-RNUG3EFC.js} +6 -6
  38. package/dist/{chunk-QKI4QWLT.js.map → chunk-RNUG3EFC.js.map} +1 -1
  39. package/dist/{chunk-3YZSIYJC.cjs → chunk-SWTNJPK5.cjs} +11 -11
  40. package/dist/{chunk-3YZSIYJC.cjs.map → chunk-SWTNJPK5.cjs.map} +1 -1
  41. package/dist/{chunk-BH24DZ5S.cjs → chunk-U3YFYMWF.cjs} +5 -5
  42. package/dist/{chunk-BH24DZ5S.cjs.map → chunk-U3YFYMWF.cjs.map} +1 -1
  43. package/dist/{chunk-3HQ7A6ZM.cjs → chunk-UFEDJJSH.cjs} +5 -5
  44. package/dist/{chunk-3HQ7A6ZM.cjs.map → chunk-UFEDJJSH.cjs.map} +1 -1
  45. package/dist/{chunk-W77GRBO4.js → chunk-UQIM2KT3.js} +3 -3
  46. package/dist/{chunk-W77GRBO4.js.map → chunk-UQIM2KT3.js.map} +1 -1
  47. package/dist/{chunk-SJDPDHSD.cjs → chunk-UTAJSERA.cjs} +4 -4
  48. package/dist/{chunk-SJDPDHSD.cjs.map → chunk-UTAJSERA.cjs.map} +1 -1
  49. package/dist/{chunk-KLGLXF6H.cjs → chunk-UYE2JASE.cjs} +2 -2
  50. package/dist/{chunk-KLGLXF6H.cjs.map → chunk-UYE2JASE.cjs.map} +1 -1
  51. package/dist/{chunk-S4B7GYLN.js → chunk-W3HLIKC2.js} +18 -8
  52. package/dist/chunk-W3HLIKC2.js.map +1 -0
  53. package/dist/{chunk-NDM5EJEV.cjs → chunk-XVIICZKW.cjs} +7 -7
  54. package/dist/chunk-XVIICZKW.cjs.map +1 -0
  55. package/dist/{chunk-OFA2DP7S.js → chunk-ZTVXII74.js} +2 -2
  56. package/dist/{chunk-OFA2DP7S.js.map → chunk-ZTVXII74.js.map} +1 -1
  57. package/dist/core/index.cjs +82 -82
  58. package/dist/core/index.d.cts +2 -2
  59. package/dist/core/index.d.ts +2 -2
  60. package/dist/core/index.js +10 -10
  61. package/dist/{index-B45-okum.d.cts → index-BgPdYxFS.d.cts} +18 -18
  62. package/dist/{index-o-Ds3YAq.d.cts → index-CL4vb3ej.d.cts} +1 -1
  63. package/dist/{index-BIcvNMPt.d.ts → index-CtcXgof_.d.ts} +18 -18
  64. package/dist/{index-DwAJBoU7.d.ts → index-D6nvfm59.d.ts} +1 -1
  65. package/dist/index.cjs +175 -176
  66. package/dist/index.cjs.map +1 -1
  67. package/dist/index.d.cts +3 -3
  68. package/dist/index.d.ts +3 -3
  69. package/dist/index.js +29 -30
  70. package/dist/index.js.map +1 -1
  71. package/dist/indexer/index.cjs +6 -6
  72. package/dist/indexer/index.d.cts +5 -5
  73. package/dist/indexer/index.d.ts +5 -5
  74. package/dist/indexer/index.js +1 -1
  75. package/dist/keys/index.cjs +18 -18
  76. package/dist/keys/index.js +4 -4
  77. package/dist/merkle-DZHEOPH3.cjs +30 -0
  78. package/dist/{merkle-HGDC6OB4.cjs.map → merkle-DZHEOPH3.cjs.map} +1 -1
  79. package/dist/merkle-IF2RMWCF.js +5 -0
  80. package/dist/{merkle-7KS2EHRF.js.map → merkle-IF2RMWCF.js.map} +1 -1
  81. package/dist/poseidon-ACM7E2OH.js +7 -0
  82. package/dist/{poseidon-UHTJLWQM.js.map → poseidon-ACM7E2OH.js.map} +1 -1
  83. package/dist/poseidon-PUSGUIVZ.cjs +61 -0
  84. package/dist/{poseidon-WHJSZSNP.cjs.map → poseidon-PUSGUIVZ.cjs.map} +1 -1
  85. package/dist/proof-JME3IZTX.js +4 -0
  86. package/dist/{proof-C4YBP6RY.js.map → proof-JME3IZTX.js.map} +1 -1
  87. package/dist/proof-XR6XE5PJ.cjs +49 -0
  88. package/dist/{proof-5OECB3RQ.cjs.map → proof-XR6XE5PJ.cjs.map} +1 -1
  89. package/dist/react/index.cjs +52 -55
  90. package/dist/react/index.cjs.map +1 -1
  91. package/dist/react/index.d.cts +2 -2
  92. package/dist/react/index.d.ts +2 -2
  93. package/dist/react/index.js +25 -28
  94. package/dist/react/index.js.map +1 -1
  95. package/dist/{transfer-BzyernBd.d.cts → transfer-D111ihqN.d.cts} +108 -56
  96. package/dist/{transfer-sqS6mJko.d.ts → transfer-DvIXqHCr.d.ts} +108 -56
  97. package/dist/transfer-MQMGSXTH.js +8 -0
  98. package/dist/{transfer-P4D57KJ5.js.map → transfer-MQMGSXTH.js.map} +1 -1
  99. package/dist/transfer-PB6D5VCW.cjs +37 -0
  100. package/dist/{transfer-XCVVZ7FF.cjs.map → transfer-PB6D5VCW.cjs.map} +1 -1
  101. package/dist/utils/index.cjs +60 -61
  102. package/dist/utils/index.d.cts +37 -14
  103. package/dist/utils/index.d.ts +37 -14
  104. package/dist/utils/index.js +6 -7
  105. package/package.json +4 -2
  106. package/src/contracts/interfaces/IUniversalPrivatePool.sol +10 -8
  107. package/src/contracts/interfaces/IVerifiers.sol +16 -52
  108. package/src/deployments/11155111.json +15 -12
  109. package/dist/asp-TXSAFFD3.cjs.map +0 -1
  110. package/dist/asp-ZA3RGN7G.js.map +0 -1
  111. package/dist/babyjubjub-2MGQVCKB.js +0 -5
  112. package/dist/babyjubjub-2MGQVCKB.js.map +0 -1
  113. package/dist/babyjubjub-MWZLJOVZ.cjs +0 -66
  114. package/dist/babyjubjub-MWZLJOVZ.cjs.map +0 -1
  115. package/dist/chunk-JWNXBALH.cjs +0 -57
  116. package/dist/chunk-JWNXBALH.cjs.map +0 -1
  117. package/dist/chunk-NDM5EJEV.cjs.map +0 -1
  118. package/dist/chunk-P37MRZ73.js.map +0 -1
  119. package/dist/chunk-PJLRCR2T.js.map +0 -1
  120. package/dist/chunk-PTDVGWHU.cjs +0 -10
  121. package/dist/chunk-PTDVGWHU.cjs.map +0 -1
  122. package/dist/chunk-QSL4XPNU.cjs.map +0 -1
  123. package/dist/chunk-S4B7GYLN.js.map +0 -1
  124. package/dist/chunk-SQKBT2SH.cjs.map +0 -1
  125. package/dist/chunk-TSF6HEVS.cjs +0 -201
  126. package/dist/chunk-TSF6HEVS.cjs.map +0 -1
  127. package/dist/chunk-UAVWYXDN.js +0 -8
  128. package/dist/chunk-UAVWYXDN.js.map +0 -1
  129. package/dist/chunk-V23OSL25.js +0 -48
  130. package/dist/chunk-V23OSL25.js.map +0 -1
  131. package/dist/chunk-YOWDERVC.js +0 -186
  132. package/dist/chunk-YOWDERVC.js.map +0 -1
  133. package/dist/merkle-7KS2EHRF.js +0 -5
  134. package/dist/merkle-HGDC6OB4.cjs +0 -30
  135. package/dist/poseidon-UHTJLWQM.js +0 -7
  136. package/dist/poseidon-WHJSZSNP.cjs +0 -45
  137. package/dist/proof-5OECB3RQ.cjs +0 -45
  138. package/dist/proof-C4YBP6RY.js +0 -4
  139. package/dist/transfer-P4D57KJ5.js +0 -8
  140. package/dist/transfer-XCVVZ7FF.cjs +0 -37
@@ -0,0 +1,64 @@
1
+ import { __esm } from './chunk-Z6ZWNWWR.js';
2
+ import { poseidon6, poseidon5, poseidon4, poseidon3, poseidon2, poseidon1 } from 'poseidon-bls12381';
3
+
4
+ async function poseidon(inputs) {
5
+ return poseidonSync(inputs);
6
+ }
7
+ function poseidonSync(inputs) {
8
+ const fn = POSEIDON_FNS[inputs.length];
9
+ if (!fn) {
10
+ throw new Error(
11
+ `Poseidon: unsupported arity ${inputs.length}. Supported: 1-6.`
12
+ );
13
+ }
14
+ return fn(inputs);
15
+ }
16
+ async function poseidonHash(inputs) {
17
+ const hash = poseidonSync(inputs);
18
+ return `0x${hash.toString(16).padStart(64, "0")}`;
19
+ }
20
+ async function poseidonScalar(inputs) {
21
+ const hash = poseidonSync(inputs);
22
+ return hash % BABYJUBJUB_SUBORDER;
23
+ }
24
+ function addressToField(address) {
25
+ return BigInt(address);
26
+ }
27
+ function fieldToAddress(field) {
28
+ const masked = field & (1n << 160n) - 1n;
29
+ return `0x${masked.toString(16).padStart(40, "0")}`;
30
+ }
31
+ function isValidFieldElement(value) {
32
+ return value >= 0n && value < FIELD_PRIME;
33
+ }
34
+ function toFieldElement(value) {
35
+ return (value % FIELD_PRIME + FIELD_PRIME) % FIELD_PRIME;
36
+ }
37
+ function computeOwnerHash(secret) {
38
+ return poseidonSync([secret]);
39
+ }
40
+ function computeNoteCommitment(amount, ownerHash, blinding, origin, token) {
41
+ return poseidonSync([amount, ownerHash, blinding, origin, token]);
42
+ }
43
+ function computeNullifier(oneTimeSecret, leafIndex, commitment) {
44
+ return poseidonSync([oneTimeSecret, leafIndex, commitment]);
45
+ }
46
+ var FIELD_PRIME, BABYJUBJUB_SUBORDER, POSEIDON_FNS;
47
+ var init_poseidon = __esm({
48
+ "src/utils/poseidon.ts"() {
49
+ FIELD_PRIME = 0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001n;
50
+ BABYJUBJUB_SUBORDER = 2736030358979909402780800718157159386076813972158567259200215660948447373041n;
51
+ POSEIDON_FNS = {
52
+ 1: poseidon1,
53
+ 2: poseidon2,
54
+ 3: poseidon3,
55
+ 4: poseidon4,
56
+ 5: poseidon5,
57
+ 6: poseidon6
58
+ };
59
+ }
60
+ });
61
+
62
+ export { BABYJUBJUB_SUBORDER, FIELD_PRIME, addressToField, computeNoteCommitment, computeNullifier, computeOwnerHash, fieldToAddress, init_poseidon, isValidFieldElement, poseidon, poseidonHash, poseidonScalar, poseidonSync, toFieldElement };
63
+ //# sourceMappingURL=chunk-5QSSX3KR.js.map
64
+ //# sourceMappingURL=chunk-5QSSX3KR.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/utils/poseidon.ts"],"names":[],"mappings":";;;AAoEA,eAAsB,SAAS,MAAA,EAAmC;AAChE,EAAA,OAAO,aAAa,MAAM,CAAA;AAC5B;AAKO,SAAS,aAAa,MAAA,EAA0B;AACrD,EAAA,MAAM,EAAA,GAAK,YAAA,CAAa,MAAA,CAAO,MAAM,CAAA;AACrC,EAAA,IAAI,CAAC,EAAA,EAAI;AACP,IAAA,MAAM,IAAI,KAAA;AAAA,MACR,CAAA,4BAAA,EAA+B,OAAO,MAAM,CAAA,iBAAA;AAAA,KAC9C;AAAA,EACF;AACA,EAAA,OAAO,GAAG,MAAM,CAAA;AAClB;AAKA,eAAsB,aAAa,MAAA,EAA0C;AAC3E,EAAA,MAAM,IAAA,GAAO,aAAa,MAAM,CAAA;AAChC,EAAA,OAAO,CAAA,EAAA,EAAK,KAAK,QAAA,CAAS,EAAE,EAAE,QAAA,CAAS,EAAA,EAAI,GAAG,CAAC,CAAA,CAAA;AACjD;AAQA,eAAsB,eAAe,MAAA,EAAmC;AACtE,EAAA,MAAM,IAAA,GAAO,aAAa,MAAM,CAAA;AAChC,EAAA,OAAO,IAAA,GAAO,mBAAA;AAChB;AAKO,SAAS,eAAe,OAAA,EAAgC;AAC7D,EAAA,OAAO,OAAO,OAAO,CAAA;AACvB;AAKO,SAAS,eAAe,KAAA,EAA8B;AAE3D,EAAA,MAAM,MAAA,GAAS,KAAA,GAAA,CAAU,EAAA,IAAM,IAAA,IAAQ,EAAA;AACvC,EAAA,OAAO,CAAA,EAAA,EAAK,OAAO,QAAA,CAAS,EAAE,EAAE,QAAA,CAAS,EAAA,EAAI,GAAG,CAAC,CAAA,CAAA;AACnD;AAKO,SAAS,oBAAoB,KAAA,EAAwB;AAC1D,EAAA,OAAO,KAAA,IAAS,MAAM,KAAA,GAAQ,WAAA;AAChC;AAKO,SAAS,eAAe,KAAA,EAAuB;AACpD,EAAA,OAAA,CAAS,KAAA,GAAQ,cAAe,WAAA,IAAe,WAAA;AACjD;AASO,SAAS,iBAAiB,MAAA,EAAwB;AACvD,EAAA,OAAO,YAAA,CAAa,CAAC,MAAM,CAAC,CAAA;AAC9B;AASO,SAAS,qBAAA,CACd,MAAA,EACA,SAAA,EACA,QAAA,EACA,QACA,KAAA,EACQ;AACR,EAAA,OAAO,aAAa,CAAC,MAAA,EAAQ,WAAW,QAAA,EAAU,MAAA,EAAQ,KAAK,CAAC,CAAA;AAClE;AAOO,SAAS,gBAAA,CACd,aAAA,EACA,SAAA,EACA,UAAA,EACQ;AACR,EAAA,OAAO,YAAA,CAAa,CAAC,aAAA,EAAe,SAAA,EAAW,UAAU,CAAC,CAAA;AAC5D;AA7KA,IA4Ba,aAOA,mBAAA,CAAA,CAGP;AAtCN,IAAA,aAAA,GAAA,KAAA,CAAA;AAAA,EAAA,uBAAA,GAAA;AA4BO,IAAM,WAAA,GAAc,mEAAA;AAOpB,IAAM,mBAAA,GAAsB,6EAAA;AAGnC,IAAM,YAAA,GAA6D;AAAA,MACjE,CAAA,EAAG,SAAA;AAAA,MACH,CAAA,EAAG,SAAA;AAAA,MACH,CAAA,EAAG,SAAA;AAAA,MACH,CAAA,EAAG,SAAA;AAAA,MACH,CAAA,EAAG,SAAA;AAAA,MACH,CAAA,EAAG;AAAA,KACL;AAAA,EAAA;AAAA,CAAA","file":"chunk-5QSSX3KR.js","sourcesContent":["/**\n * Poseidon Hash Utilities (BLS12-381)\n *\n * Poseidon hash over the BLS12-381 scalar field (128-bit security).\n * Uses the poseidon-bls12381 package for hash computation.\n *\n * This replaces the previous circomlibjs BN254 Poseidon implementation.\n * The BLS12-381 field provides 128-bit security (vs ~100-bit for BN254),\n * meeting the NIST 128-bit minimum standard.\n */\n\nimport {\n poseidon1,\n poseidon2,\n poseidon3,\n poseidon4,\n poseidon5,\n poseidon6,\n} from 'poseidon-bls12381'\n\n/**\n * BLS12-381 scalar field prime (Fr)\n *\n * r = 0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001\n * = 52435875175126190479447740508185965837690552500527637822603658699938581184513\n *\n * This is ~255 bits, providing 128-bit security.\n */\nexport const FIELD_PRIME = 0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001n\n\n/**\n * @deprecated BabyJubJub is no longer used in BLS12-381 circuits.\n * Hash-based ownership (ownerHash = Poseidon(secret)) replaces curve operations.\n * Kept temporarily for backward compatibility with off-chain stealth address code.\n */\nexport const BABYJUBJUB_SUBORDER = 2736030358979909402780800718157159386076813972158567259200215660948447373041n\n\n// Arity-indexed Poseidon functions for BLS12-381\nconst POSEIDON_FNS: Record<number, (inputs: bigint[]) => bigint> = {\n 1: poseidon1,\n 2: poseidon2,\n 3: poseidon3,\n 4: poseidon4,\n 5: poseidon5,\n 6: poseidon6,\n}\n\n/**\n * Compute Poseidon hash over BLS12-381 scalar field\n *\n * Synchronous — no initialization needed (unlike circomlibjs).\n * The async signature is preserved for backward compatibility.\n *\n * @param inputs - Array of field elements to hash (1-6 elements)\n * @returns Hash as bigint in BLS12-381 scalar field\n *\n * @example\n * ```ts\n * // Note commitment (5 inputs)\n * const commitment = await poseidon([amount, ownerHash, blinding, origin, token])\n *\n * // Nullifier (3 inputs)\n * const nullifier = await poseidon([oneTimeSecret, leafIndex, commitment])\n *\n * // Owner hash (1 input)\n * const ownerHash = await poseidon([oneTimeSecret])\n * ```\n */\nexport async function poseidon(inputs: bigint[]): Promise<bigint> {\n return poseidonSync(inputs)\n}\n\n/**\n * Synchronous Poseidon hash (preferred for new code)\n */\nexport function poseidonSync(inputs: bigint[]): bigint {\n const fn = POSEIDON_FNS[inputs.length]\n if (!fn) {\n throw new Error(\n `Poseidon: unsupported arity ${inputs.length}. Supported: 1-6.`\n )\n }\n return fn(inputs)\n}\n\n/**\n * Compute Poseidon hash and return as hex string\n */\nexport async function poseidonHash(inputs: bigint[]): Promise<`0x${string}`> {\n const hash = poseidonSync(inputs)\n return `0x${hash.toString(16).padStart(64, '0')}`\n}\n\n/**\n * @deprecated BabyJubJub scalars are no longer used. Use poseidon() directly.\n *\n * Compute Poseidon hash modulo BabyJubJub suborder.\n * Kept for backward compatibility with off-chain stealth address code.\n */\nexport async function poseidonScalar(inputs: bigint[]): Promise<bigint> {\n const hash = poseidonSync(inputs)\n return hash % BABYJUBJUB_SUBORDER\n}\n\n/**\n * Convert an address to a field element\n */\nexport function addressToField(address: `0x${string}`): bigint {\n return BigInt(address)\n}\n\n/**\n * Convert a field element to an address (20 bytes)\n */\nexport function fieldToAddress(field: bigint): `0x${string}` {\n // Mask to 160 bits (20 bytes) for address\n const masked = field & ((1n << 160n) - 1n)\n return `0x${masked.toString(16).padStart(40, '0')}`\n}\n\n/**\n * Check if a value is within the BLS12-381 scalar field\n */\nexport function isValidFieldElement(value: bigint): boolean {\n return value >= 0n && value < FIELD_PRIME\n}\n\n/**\n * Reduce a value modulo BLS12-381 field prime\n */\nexport function toFieldElement(value: bigint): bigint {\n return ((value % FIELD_PRIME) + FIELD_PRIME) % FIELD_PRIME\n}\n\n/**\n * Compute owner hash from spending secret\n *\n * ownerHash = Poseidon(secret)\n *\n * This replaces BabyJubJub DerivePublicKey for circuit ownership proofs.\n */\nexport function computeOwnerHash(secret: bigint): bigint {\n return poseidonSync([secret])\n}\n\n/**\n * Compute note commitment (BLS12-381)\n *\n * commitment = Poseidon(amount, ownerHash, blinding, origin, token)\n *\n * 5-input format (replaces old 6-input format with pubkeyX/pubkeyY).\n */\nexport function computeNoteCommitment(\n amount: bigint,\n ownerHash: bigint,\n blinding: bigint,\n origin: bigint,\n token: bigint\n): bigint {\n return poseidonSync([amount, ownerHash, blinding, origin, token])\n}\n\n/**\n * Compute nullifier for a note\n *\n * nullifier = Poseidon(oneTimeSecret, leafIndex, commitment)\n */\nexport function computeNullifier(\n oneTimeSecret: bigint,\n leafIndex: bigint,\n commitment: bigint\n): bigint {\n return poseidonSync([oneTimeSecret, leafIndex, commitment])\n}\n"]}
@@ -1,8 +1,8 @@
1
1
  import { __require } from './chunk-Z6ZWNWWR.js';
2
- import { PoseidonBN254, DEFAULT_TREE_DEPTH, generateSingleMemberProof, verifyMembershipProof, computeMerkleRoot, generateMembershipProof } from '@permissionless-technologies/upc-sdk';
2
+ import { PoseidonBLS12381, DEFAULT_TREE_DEPTH, generateSingleMemberProof, verifyMembershipProof, computeMerkleRoot, generateMembershipProof } from '@permissionless-technologies/upc-sdk';
3
3
 
4
4
  var ASP_TREE_DEPTH = DEFAULT_TREE_DEPTH;
5
- var bn254 = new PoseidonBN254();
5
+ var bls12381 = new PoseidonBLS12381();
6
6
  async function computeSingleOriginASPRoot(origin) {
7
7
  return origin;
8
8
  }
@@ -19,7 +19,7 @@ async function verifyASPProof(origin, proof) {
19
19
  return verifyMembershipProof(
20
20
  origin,
21
21
  { root: proof.aspRoot, pathElements: proof.aspPathElements, pathIndices: proof.aspPathIndices },
22
- bn254
22
+ bls12381
23
23
  );
24
24
  }
25
25
  var DEMO_ASP_ID = 1n;
@@ -29,16 +29,16 @@ async function createDemoASPRoot(origin) {
29
29
  }
30
30
  function buildASPTree(origins) {
31
31
  const { buildMerkleTree } = __require("@permissionless-technologies/upc-sdk");
32
- return buildMerkleTree(origins, ASP_TREE_DEPTH, bn254);
32
+ return buildMerkleTree(origins, ASP_TREE_DEPTH, bls12381);
33
33
  }
34
34
  async function computeMultiOriginASPRoot(origins) {
35
- return computeMerkleRoot(origins, ASP_TREE_DEPTH, bn254);
35
+ return computeMerkleRoot(origins, ASP_TREE_DEPTH, bls12381);
36
36
  }
37
37
  async function generateMultiOriginASPProof(aspId, origin, allOrigins) {
38
38
  if (allOrigins.length <= 1) {
39
39
  return generateSingleOriginASPProof(aspId, origin);
40
40
  }
41
- const proof = await generateMembershipProof(origin, allOrigins, ASP_TREE_DEPTH, bn254);
41
+ const proof = await generateMembershipProof(origin, allOrigins, ASP_TREE_DEPTH, bls12381);
42
42
  return {
43
43
  aspId,
44
44
  aspRoot: proof.root,
@@ -54,5 +54,5 @@ async function generateASPProof(aspId, origin, approvedOrigins) {
54
54
  }
55
55
 
56
56
  export { ASP_TREE_DEPTH, DEMO_ASP_ID, DEMO_ASP_NAME, buildASPTree, computeMultiOriginASPRoot, computeSingleOriginASPRoot, createDemoASPRoot, generateASPProof, generateMultiOriginASPProof, generateSingleOriginASPProof, verifyASPProof };
57
- //# sourceMappingURL=chunk-P37MRZ73.js.map
58
- //# sourceMappingURL=chunk-P37MRZ73.js.map
57
+ //# sourceMappingURL=chunk-6IEYWJVS.js.map
58
+ //# sourceMappingURL=chunk-6IEYWJVS.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/core/asp.ts"],"names":[],"mappings":";;;AAuBO,IAAM,cAAA,GAAiB;AAG9B,IAAM,QAAA,GAAW,IAAI,gBAAA,EAAiB;AAmBtC,eAAsB,2BAA2B,MAAA,EAAiC;AAChF,EAAA,OAAO,MAAA;AACT;AAKA,eAAsB,4BAAA,CACpB,OACA,MAAA,EACmB;AACnB,EAAA,MAAM,KAAA,GAAQ,yBAAA,CAA0B,MAAA,EAAQ,cAAc,CAAA;AAC9D,EAAA,OAAO;AAAA,IACL,KAAA;AAAA,IACA,SAAS,KAAA,CAAM,IAAA;AAAA,IACf,iBAAiB,KAAA,CAAM,YAAA;AAAA,IACvB,gBAAgB,KAAA,CAAM;AAAA,GACxB;AACF;AAKA,eAAsB,cAAA,CAAe,QAAgB,KAAA,EAAmC;AACtF,EAAA,OAAO,qBAAA;AAAA,IACL,MAAA;AAAA,IACA,EAAE,MAAM,KAAA,CAAM,OAAA,EAAS,cAAc,KAAA,CAAM,eAAA,EAAiB,WAAA,EAAa,KAAA,CAAM,cAAA,EAAe;AAAA,IAC9F;AAAA,GACF;AACF;AAKO,IAAM,WAAA,GAAc;AACpB,IAAM,aAAA,GAAgB;AAK7B,eAAsB,kBAAkB,MAAA,EAAiC;AACvE,EAAA,OAAO,2BAA2B,MAAM,CAAA;AAC1C;AAKO,SAAS,aAAa,OAAA,EAAmB;AAC9C,EAAA,MAAM,EAAE,eAAA,EAAgB,GAAI,SAAA,CAAQ,sCAAsC,CAAA;AAC1E,EAAA,OAAO,eAAA,CAAgB,OAAA,EAAS,cAAA,EAAgB,QAAQ,CAAA;AAC1D;AAKA,eAAsB,0BAA0B,OAAA,EAAoC;AAClF,EAAA,OAAO,iBAAA,CAAkB,OAAA,EAAS,cAAA,EAAgB,QAAQ,CAAA;AAC5D;AAKA,eAAsB,2BAAA,CACpB,KAAA,EACA,MAAA,EACA,UAAA,EACmB;AACnB,EAAA,IAAI,UAAA,CAAW,UAAU,CAAA,EAAG;AAC1B,IAAA,OAAO,4BAAA,CAA6B,OAAO,MAAM,CAAA;AAAA,EACnD;AAEA,EAAA,MAAM,QAAQ,MAAM,uBAAA,CAAwB,MAAA,EAAQ,UAAA,EAAY,gBAAgB,QAAQ,CAAA;AAExF,EAAA,OAAO;AAAA,IACL,KAAA;AAAA,IACA,SAAS,KAAA,CAAM,IAAA;AAAA,IACf,iBAAiB,KAAA,CAAM,YAAA;AAAA,IACvB,gBAAgB,KAAA,CAAM;AAAA,GACxB;AACF;AAKA,eAAsB,gBAAA,CACpB,KAAA,EACA,MAAA,EACA,eAAA,EACmB;AACnB,EAAA,IAAI,eAAA,IAAmB,eAAA,CAAgB,MAAA,GAAS,CAAA,EAAG;AACjD,IAAA,OAAO,2BAAA,CAA4B,KAAA,EAAO,MAAA,EAAQ,eAAe,CAAA;AAAA,EACnE;AACA,EAAA,OAAO,4BAAA,CAA6B,OAAO,MAAM,CAAA;AACnD","file":"chunk-6IEYWJVS.js","sourcesContent":["/**\n * ASP (Association Set Provider) Utilities\n *\n * Thin wrapper around @permissionless-technologies/upc-sdk.\n * Provides pool-specific types (ASPProof with aspId) while delegating\n * Merkle tree operations to the compliance SDK.\n *\n * In UPP, every transfer must prove the origin is in an approved ASP's allowlist.\n *\n * Uses BLS12-381 Poseidon (128-bit security) for Merkle tree operations,\n * matching the circuit hash function.\n */\n\nimport {\n generateMembershipProof,\n generateSingleMemberProof,\n computeMerkleRoot,\n verifyMembershipProof,\n DEFAULT_TREE_DEPTH,\n PoseidonBLS12381,\n} from '@permissionless-technologies/upc-sdk'\n\n// Re-export tree depth from UPC\nexport const ASP_TREE_DEPTH = DEFAULT_TREE_DEPTH\n\n// Use BLS12-381 Poseidon (128-bit security) — matches circuit hash function\nconst bls12381 = new PoseidonBLS12381()\n\n/**\n * ASP Merkle proof structure (pool-specific: includes aspId)\n */\nexport interface ASPProof {\n /** ASP ID */\n aspId: bigint\n /** ASP's published root */\n aspRoot: bigint\n /** Path elements (siblings) - 20 levels */\n aspPathElements: bigint[]\n /** Path indices - 20 levels */\n aspPathIndices: number[]\n}\n\n/**\n * Compute the ASP root for a single-leaf tree\n */\nexport async function computeSingleOriginASPRoot(origin: bigint): Promise<bigint> {\n return origin // LeanIMT single-leaf optimization: root = leaf\n}\n\n/**\n * Generate ASP proof for a single-origin tree\n */\nexport async function generateSingleOriginASPProof(\n aspId: bigint,\n origin: bigint\n): Promise<ASPProof> {\n const proof = generateSingleMemberProof(origin, ASP_TREE_DEPTH)\n return {\n aspId,\n aspRoot: proof.root,\n aspPathElements: proof.pathElements,\n aspPathIndices: proof.pathIndices,\n }\n}\n\n/**\n * Verify an ASP proof locally (for debugging)\n */\nexport async function verifyASPProof(origin: bigint, proof: ASPProof): Promise<boolean> {\n return verifyMembershipProof(\n origin,\n { root: proof.aspRoot, pathElements: proof.aspPathElements, pathIndices: proof.aspPathIndices },\n bls12381\n )\n}\n\n/**\n * Demo ASP configuration\n */\nexport const DEMO_ASP_ID = 1n\nexport const DEMO_ASP_NAME = 'Demo ASP (Single-Origin)'\n\n/**\n * Create a \"universal approval\" ASP root\n */\nexport async function createDemoASPRoot(origin: bigint): Promise<bigint> {\n return computeSingleOriginASPRoot(origin)\n}\n\n/**\n * Build an ASP Merkle tree from multiple origin addresses\n */\nexport function buildASPTree(origins: bigint[]) {\n const { buildMerkleTree } = require('@permissionless-technologies/upc-sdk') as typeof import('@permissionless-technologies/upc-sdk')\n return buildMerkleTree(origins, ASP_TREE_DEPTH, bls12381)\n}\n\n/**\n * Compute the Merkle root for a set of approved origins\n */\nexport async function computeMultiOriginASPRoot(origins: bigint[]): Promise<bigint> {\n return computeMerkleRoot(origins, ASP_TREE_DEPTH, bls12381)\n}\n\n/**\n * Generate an ASP membership proof for one origin within a multi-origin tree\n */\nexport async function generateMultiOriginASPProof(\n aspId: bigint,\n origin: bigint,\n allOrigins: bigint[]\n): Promise<ASPProof> {\n if (allOrigins.length <= 1) {\n return generateSingleOriginASPProof(aspId, origin)\n }\n\n const proof = await generateMembershipProof(origin, allOrigins, ASP_TREE_DEPTH, bls12381)\n\n return {\n aspId,\n aspRoot: proof.root,\n aspPathElements: proof.pathElements,\n aspPathIndices: proof.pathIndices,\n }\n}\n\n/**\n * Generate an ASP proof, automatically choosing single-origin or multi-origin\n */\nexport async function generateASPProof(\n aspId: bigint,\n origin: bigint,\n approvedOrigins?: bigint[]\n): Promise<ASPProof> {\n if (approvedOrigins && approvedOrigins.length > 0) {\n return generateMultiOriginASPProof(aspId, origin, approvedOrigins)\n }\n return generateSingleOriginASPProof(aspId, origin)\n}\n"]}
@@ -1,4 +1,4 @@
1
- import { init_crypto, bytesToHex } from './chunk-W77GRBO4.js';
1
+ import { init_crypto, bytesToHex } from './chunk-UQIM2KT3.js';
2
2
  import { keccak256 } from 'viem';
3
3
 
4
4
  // src/utils/keccak-m31.ts
@@ -77,5 +77,5 @@ function hexToUint8Array(hex) {
77
77
  }
78
78
 
79
79
  export { DIGEST_SIZE, M31_P, SECRET_LIMBS, computeStarkCommitment, computeStarkNullifier, computeStarkOwnerHash, keccakHashTwo, keccakM31, splitToM31Limbs };
80
- //# sourceMappingURL=chunk-5V5HSN6Y.js.map
81
- //# sourceMappingURL=chunk-5V5HSN6Y.js.map
80
+ //# sourceMappingURL=chunk-6TFDBBAQ.js.map
81
+ //# sourceMappingURL=chunk-6TFDBBAQ.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/utils/keccak-m31.ts"],"names":[],"mappings":"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","file":"chunk-5V5HSN6Y.js","sourcesContent":["/**\n * Keccak-256 hashing over M31 field elements.\n *\n * This module implements the same hashing algorithm as the Rust Stwo prover\n * (stwo-prover/src/hash.rs), producing identical outputs for identical inputs.\n *\n * Algorithm:\n * 1. Each M31 element is encoded as 4 little-endian bytes\n * 2. All encoded bytes are concatenated and fed to Keccak-256\n * 3. The 32-byte output is split into 4 chunks of 8 bytes\n * 4. Each chunk is read as a little-endian uint64 and reduced mod M31_P\n *\n * M31 field: p = 2^31 - 1 = 2,147,483,647\n */\n\nimport { keccak256 } from 'viem'\nimport { bytesToHex } from './crypto.js'\n\n/** The M31 prime: 2^31 - 1 */\nexport const M31_P = 2147483647n\n\n/** Number of M31 elements in a digest */\nexport const DIGEST_SIZE = 4\n\n/** Number of M31 limbs for owner secrets (248 bits of entropy) */\nexport const SECRET_LIMBS = 8\n\n/** M31 digest type: tuple of 4 M31 values */\nexport type M31Digest = readonly [bigint, bigint, bigint, bigint]\n\n/** M31 secret type: tuple of 8 M31 values */\nexport type M31Secret = readonly [bigint, bigint, bigint, bigint, bigint, bigint, bigint, bigint]\n\n/**\n * Hash arbitrary M31 elements using Keccak-256.\n *\n * Matches Rust: `hash_m31(inputs: &[M31]) -> [M31; 4]`\n *\n * Each M31 is encoded as 4 little-endian bytes. The keccak output\n * is split into 4 × 8-byte LE chunks, each reduced mod M31_P.\n */\nexport function keccakM31(inputs: readonly bigint[]): M31Digest {\n // Encode each M31 as 4 little-endian bytes\n const bytes = new Uint8Array(inputs.length * 4)\n for (let i = 0; i < inputs.length; i++) {\n const val = Number(inputs[i]! & 0xFFFFFFFFn)\n const offset = i * 4\n bytes[offset] = val & 0xFF\n bytes[offset + 1] = (val >> 8) & 0xFF\n bytes[offset + 2] = (val >> 16) & 0xFF\n bytes[offset + 3] = (val >> 24) & 0xFF\n }\n\n // Keccak-256\n const hashHex = keccak256(bytesToHex(bytes))\n\n // Parse 32-byte output into 4 × uint64 LE, reduce mod M31_P\n return bytesToM31Digest(hashHex)\n}\n\n/**\n * Hash two M31 elements (Merkle tree node hash).\n *\n * Matches Rust: `hash_two(left: M31, right: M31) -> [M31; 4]`\n */\nexport function keccakHashTwo(left: bigint, right: bigint): M31Digest {\n return keccakM31([left, right])\n}\n\n/**\n * Compute owner hash from an 8-limb secret.\n *\n * Matches Rust: `compute_owner_hash(owner_secret: &[M31; 8]) -> [M31; 4]`\n */\nexport function computeStarkOwnerHash(ownerSecret: M31Secret): M31Digest {\n return keccakM31(ownerSecret)\n}\n\n/**\n * Compute a STARK note commitment.\n *\n * Matches Rust: `compute_commitment(amount, owner_hash, blinding, origin, token)`\n *\n * Input order: [amount, ownerHash[0], ownerHash[1], ownerHash[2], ownerHash[3], blinding, origin, token]\n */\nexport function computeStarkCommitment(\n amount: bigint,\n ownerHash: M31Digest,\n blinding: bigint,\n origin: bigint,\n token: bigint,\n): M31Digest {\n return keccakM31([\n amount,\n ownerHash[0],\n ownerHash[1],\n ownerHash[2],\n ownerHash[3],\n blinding,\n origin,\n token,\n ])\n}\n\n/**\n * Compute a STARK nullifier.\n *\n * Matches Rust: `compute_nullifier(owner_secret, leaf_index, commitment)`\n *\n * Input order: [ownerSecret[0..8], leafIndex, commitment[0..4]]\n */\nexport function computeStarkNullifier(\n ownerSecret: M31Secret,\n leafIndex: bigint,\n commitment: M31Digest,\n): M31Digest {\n return keccakM31([\n ...ownerSecret,\n leafIndex,\n ...commitment,\n ])\n}\n\n/**\n * Split a 32-byte keccak hash into 8 M31 limbs.\n *\n * Used for deriving STARK spending/viewing secrets from a seed.\n * Each limb is 4 bytes of the hash, read as LE uint32, reduced mod M31_P.\n */\nexport function splitToM31Limbs(hashHex: `0x${string}`): M31Secret {\n const bytes = hexToUint8Array(hashHex)\n const limbs: bigint[] = []\n for (let i = 0; i < SECRET_LIMBS; i++) {\n const offset = i * 4\n const val = (bytes[offset]!)\n | ((bytes[offset + 1]!) << 8)\n | ((bytes[offset + 2]!) << 16)\n | ((bytes[offset + 3]!) << 24)\n limbs.push(BigInt(val >>> 0) % M31_P)\n }\n return limbs as unknown as M31Secret\n}\n\n/**\n * Convert a hex hash output to an M31 digest (4 elements).\n *\n * Splits 32 bytes into 4 × 8-byte LE chunks, reduces each mod M31_P.\n */\nfunction bytesToM31Digest(hashHex: `0x${string}`): M31Digest {\n const bytes = hexToUint8Array(hashHex)\n const digest: bigint[] = []\n\n for (let i = 0; i < DIGEST_SIZE; i++) {\n const offset = i * 8\n // Read 8 bytes as little-endian uint64\n let val = 0n\n for (let j = 0; j < 8; j++) {\n val |= BigInt(bytes[offset + j]!) << BigInt(j * 8)\n }\n digest.push(val % M31_P)\n }\n\n return digest as unknown as M31Digest\n}\n\n/**\n * Convert hex string to Uint8Array\n */\nfunction hexToUint8Array(hex: `0x${string}`): Uint8Array {\n const str = hex.slice(2)\n const bytes = new Uint8Array(str.length / 2)\n for (let i = 0; i < bytes.length; i++) {\n bytes[i] = parseInt(str.slice(i * 2, i * 2 + 2), 16)\n }\n return bytes\n}\n"]}
1
+ {"version":3,"sources":["../src/utils/keccak-m31.ts"],"names":[],"mappings":"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","file":"chunk-6TFDBBAQ.js","sourcesContent":["/**\n * Keccak-256 hashing over M31 field elements.\n *\n * This module implements the same hashing algorithm as the Rust Stwo prover\n * (stwo-prover/src/hash.rs), producing identical outputs for identical inputs.\n *\n * Algorithm:\n * 1. Each M31 element is encoded as 4 little-endian bytes\n * 2. All encoded bytes are concatenated and fed to Keccak-256\n * 3. The 32-byte output is split into 4 chunks of 8 bytes\n * 4. Each chunk is read as a little-endian uint64 and reduced mod M31_P\n *\n * M31 field: p = 2^31 - 1 = 2,147,483,647\n */\n\nimport { keccak256 } from 'viem'\nimport { bytesToHex } from './crypto.js'\n\n/** The M31 prime: 2^31 - 1 */\nexport const M31_P = 2147483647n\n\n/** Number of M31 elements in a digest */\nexport const DIGEST_SIZE = 4\n\n/** Number of M31 limbs for owner secrets (248 bits of entropy) */\nexport const SECRET_LIMBS = 8\n\n/** M31 digest type: tuple of 4 M31 values */\nexport type M31Digest = readonly [bigint, bigint, bigint, bigint]\n\n/** M31 secret type: tuple of 8 M31 values */\nexport type M31Secret = readonly [bigint, bigint, bigint, bigint, bigint, bigint, bigint, bigint]\n\n/**\n * Hash arbitrary M31 elements using Keccak-256.\n *\n * Matches Rust: `hash_m31(inputs: &[M31]) -> [M31; 4]`\n *\n * Each M31 is encoded as 4 little-endian bytes. The keccak output\n * is split into 4 × 8-byte LE chunks, each reduced mod M31_P.\n */\nexport function keccakM31(inputs: readonly bigint[]): M31Digest {\n // Encode each M31 as 4 little-endian bytes\n const bytes = new Uint8Array(inputs.length * 4)\n for (let i = 0; i < inputs.length; i++) {\n const val = Number(inputs[i]! & 0xFFFFFFFFn)\n const offset = i * 4\n bytes[offset] = val & 0xFF\n bytes[offset + 1] = (val >> 8) & 0xFF\n bytes[offset + 2] = (val >> 16) & 0xFF\n bytes[offset + 3] = (val >> 24) & 0xFF\n }\n\n // Keccak-256\n const hashHex = keccak256(bytesToHex(bytes))\n\n // Parse 32-byte output into 4 × uint64 LE, reduce mod M31_P\n return bytesToM31Digest(hashHex)\n}\n\n/**\n * Hash two M31 elements (Merkle tree node hash).\n *\n * Matches Rust: `hash_two(left: M31, right: M31) -> [M31; 4]`\n */\nexport function keccakHashTwo(left: bigint, right: bigint): M31Digest {\n return keccakM31([left, right])\n}\n\n/**\n * Compute owner hash from an 8-limb secret.\n *\n * Matches Rust: `compute_owner_hash(owner_secret: &[M31; 8]) -> [M31; 4]`\n */\nexport function computeStarkOwnerHash(ownerSecret: M31Secret): M31Digest {\n return keccakM31(ownerSecret)\n}\n\n/**\n * Compute a STARK note commitment.\n *\n * Matches Rust: `compute_commitment(amount, owner_hash, blinding, origin, token)`\n *\n * Input order: [amount, ownerHash[0], ownerHash[1], ownerHash[2], ownerHash[3], blinding, origin, token]\n */\nexport function computeStarkCommitment(\n amount: bigint,\n ownerHash: M31Digest,\n blinding: bigint,\n origin: bigint,\n token: bigint,\n): M31Digest {\n return keccakM31([\n amount,\n ownerHash[0],\n ownerHash[1],\n ownerHash[2],\n ownerHash[3],\n blinding,\n origin,\n token,\n ])\n}\n\n/**\n * Compute a STARK nullifier.\n *\n * Matches Rust: `compute_nullifier(owner_secret, leaf_index, commitment)`\n *\n * Input order: [ownerSecret[0..8], leafIndex, commitment[0..4]]\n */\nexport function computeStarkNullifier(\n ownerSecret: M31Secret,\n leafIndex: bigint,\n commitment: M31Digest,\n): M31Digest {\n return keccakM31([\n ...ownerSecret,\n leafIndex,\n ...commitment,\n ])\n}\n\n/**\n * Split a 32-byte keccak hash into 8 M31 limbs.\n *\n * Used for deriving STARK spending/viewing secrets from a seed.\n * Each limb is 4 bytes of the hash, read as LE uint32, reduced mod M31_P.\n */\nexport function splitToM31Limbs(hashHex: `0x${string}`): M31Secret {\n const bytes = hexToUint8Array(hashHex)\n const limbs: bigint[] = []\n for (let i = 0; i < SECRET_LIMBS; i++) {\n const offset = i * 4\n const val = (bytes[offset]!)\n | ((bytes[offset + 1]!) << 8)\n | ((bytes[offset + 2]!) << 16)\n | ((bytes[offset + 3]!) << 24)\n limbs.push(BigInt(val >>> 0) % M31_P)\n }\n return limbs as unknown as M31Secret\n}\n\n/**\n * Convert a hex hash output to an M31 digest (4 elements).\n *\n * Splits 32 bytes into 4 × 8-byte LE chunks, reduces each mod M31_P.\n */\nfunction bytesToM31Digest(hashHex: `0x${string}`): M31Digest {\n const bytes = hexToUint8Array(hashHex)\n const digest: bigint[] = []\n\n for (let i = 0; i < DIGEST_SIZE; i++) {\n const offset = i * 8\n // Read 8 bytes as little-endian uint64\n let val = 0n\n for (let j = 0; j < 8; j++) {\n val |= BigInt(bytes[offset + j]!) << BigInt(j * 8)\n }\n digest.push(val % M31_P)\n }\n\n return digest as unknown as M31Digest\n}\n\n/**\n * Convert hex string to Uint8Array\n */\nfunction hexToUint8Array(hex: `0x${string}`): Uint8Array {\n const str = hex.slice(2)\n const bytes = new Uint8Array(str.length / 2)\n for (let i = 0; i < bytes.length; i++) {\n bytes[i] = parseInt(str.slice(i * 2, i * 2 + 2), 16)\n }\n return bytes\n}\n"]}
@@ -1,8 +1,8 @@
1
1
  'use strict';
2
2
 
3
- var chunkBH24DZ5S_cjs = require('./chunk-BH24DZ5S.cjs');
4
- var chunk3HQ7A6ZM_cjs = require('./chunk-3HQ7A6ZM.cjs');
5
- var chunkJWNXBALH_cjs = require('./chunk-JWNXBALH.cjs');
3
+ var chunkU3YFYMWF_cjs = require('./chunk-U3YFYMWF.cjs');
4
+ var chunkUFEDJJSH_cjs = require('./chunk-UFEDJJSH.cjs');
5
+ var chunkHEHXSV47_cjs = require('./chunk-HEHXSV47.cjs');
6
6
  var viem = require('viem');
7
7
 
8
8
  // src/keys/types.ts
@@ -12,22 +12,22 @@ var DEFAULT_KEY_DERIVATION_CONFIG = {
12
12
  };
13
13
 
14
14
  // src/keys/derive.ts
15
- chunkJWNXBALH_cjs.init_poseidon();
16
- chunk3HQ7A6ZM_cjs.init_crypto();
15
+ chunkHEHXSV47_cjs.init_poseidon();
16
+ chunkUFEDJJSH_cjs.init_crypto();
17
17
  async function deriveKeysFromSignature(signature, config = DEFAULT_KEY_DERIVATION_CONFIG) {
18
- const { poseidon } = await import('./poseidon-WHJSZSNP.cjs');
18
+ const { poseidon } = await import('./poseidon-PUSGUIVZ.cjs');
19
19
  const seed = viem.keccak256(signature);
20
20
  const spendingSecretHash = viem.keccak256(
21
21
  viem.toHex(new TextEncoder().encode(`${seed}:spending:v${config.version}`))
22
22
  );
23
- const spendingSecretRaw = chunk3HQ7A6ZM_cjs.bytesToBigint(chunk3HQ7A6ZM_cjs.hexToBytes(spendingSecretHash));
24
- const spendingSecret = spendingSecretRaw % chunkJWNXBALH_cjs.FIELD_PRIME;
23
+ const spendingSecretRaw = chunkUFEDJJSH_cjs.bytesToBigint(chunkUFEDJJSH_cjs.hexToBytes(spendingSecretHash));
24
+ const spendingSecret = spendingSecretRaw % chunkHEHXSV47_cjs.FIELD_PRIME;
25
25
  const ownerHash = await poseidon([spendingSecret]);
26
26
  const viewingSecretHash = viem.keccak256(
27
27
  viem.toHex(new TextEncoder().encode(`${seed}:viewing:v${config.version}`))
28
28
  );
29
- const viewingSecretRaw = chunk3HQ7A6ZM_cjs.bytesToBigint(chunk3HQ7A6ZM_cjs.hexToBytes(viewingSecretHash));
30
- const viewingSecret = viewingSecretRaw % chunkJWNXBALH_cjs.FIELD_PRIME;
29
+ const viewingSecretRaw = chunkUFEDJJSH_cjs.bytesToBigint(chunkUFEDJJSH_cjs.hexToBytes(viewingSecretHash));
30
+ const viewingSecret = viewingSecretRaw % chunkHEHXSV47_cjs.FIELD_PRIME;
31
31
  const viewingHash = await poseidon([viewingSecret]);
32
32
  return {
33
33
  spendingSecret,
@@ -48,13 +48,13 @@ function deriveStarkKeysFromSignature(signature, config = DEFAULT_KEY_DERIVATION
48
48
  const starkSpendingHash = viem.keccak256(
49
49
  viem.toHex(new TextEncoder().encode(`${seed}:stark:spending:v${config.version}`))
50
50
  );
51
- const starkSecret = chunkBH24DZ5S_cjs.splitToM31Limbs(starkSpendingHash);
52
- const starkOwnerHash = chunkBH24DZ5S_cjs.computeStarkOwnerHash(starkSecret);
51
+ const starkSecret = chunkU3YFYMWF_cjs.splitToM31Limbs(starkSpendingHash);
52
+ const starkOwnerHash = chunkU3YFYMWF_cjs.computeStarkOwnerHash(starkSecret);
53
53
  const starkViewingHash = viem.keccak256(
54
54
  viem.toHex(new TextEncoder().encode(`${seed}:stark:viewing:v${config.version}`))
55
55
  );
56
- const starkViewingSecret = chunkBH24DZ5S_cjs.splitToM31Limbs(starkViewingHash);
57
- const starkViewingHashDigest = chunkBH24DZ5S_cjs.computeStarkOwnerHash(starkViewingSecret);
56
+ const starkViewingSecret = chunkU3YFYMWF_cjs.splitToM31Limbs(starkViewingHash);
57
+ const starkViewingHashDigest = chunkU3YFYMWF_cjs.computeStarkOwnerHash(starkViewingSecret);
58
58
  return {
59
59
  starkSecret,
60
60
  starkOwnerHash,
@@ -68,12 +68,12 @@ async function deriveDualKeysFromSignature(signature, config = DEFAULT_KEY_DERIV
68
68
  return { snark, stark };
69
69
  }
70
70
  async function deriveNullifierKey(spendingSecret) {
71
- const { poseidon } = await import('./poseidon-WHJSZSNP.cjs');
71
+ const { poseidon } = await import('./poseidon-PUSGUIVZ.cjs');
72
72
  return await poseidon([spendingSecret, 0n]);
73
73
  }
74
- chunk3HQ7A6ZM_cjs.init_crypto();
74
+ chunkUFEDJJSH_cjs.init_crypto();
75
75
  async function derivePerNoteKey(viewingSecret, nonce) {
76
- const { poseidon } = await import('./poseidon-WHJSZSNP.cjs');
76
+ const { poseidon } = await import('./poseidon-PUSGUIVZ.cjs');
77
77
  const perNoteKey = await poseidon([viewingSecret, nonce]);
78
78
  return viem.toHex(perNoteKey, { size: 32 });
79
79
  }
@@ -132,7 +132,7 @@ function getViewingKeyFromExport(exportData, leafIndex) {
132
132
  return key ? key.decryptionKey : null;
133
133
  }
134
134
  function deriveStarkPerNoteKey(starkViewingSecret, nonce) {
135
- const digest = chunkBH24DZ5S_cjs.keccakM31([...starkViewingSecret, nonce]);
135
+ const digest = chunkU3YFYMWF_cjs.keccakM31([...starkViewingSecret, nonce]);
136
136
  const bytes = new Uint8Array(16);
137
137
  for (let i = 0; i < 4; i++) {
138
138
  const val = Number(digest[i]);
@@ -141,7 +141,7 @@ function deriveStarkPerNoteKey(starkViewingSecret, nonce) {
141
141
  bytes[i * 4 + 2] = val >> 16 & 255;
142
142
  bytes[i * 4 + 3] = val >> 24 & 255;
143
143
  }
144
- return viem.keccak256(chunk3HQ7A6ZM_cjs.bytesToHex(bytes));
144
+ return viem.keccak256(chunkUFEDJJSH_cjs.bytesToHex(bytes));
145
145
  }
146
146
  function deriveStarkPerNoteKeyFromKeys(keys, nonce) {
147
147
  return deriveStarkPerNoteKey(keys.starkViewingSecret, nonce);
@@ -161,5 +161,5 @@ exports.getKeyDerivationMessage = getKeyDerivationMessage;
161
161
  exports.getViewingKeyFromExport = getViewingKeyFromExport;
162
162
  exports.validateAuditKeyExport = validateAuditKeyExport;
163
163
  exports.verifyKeysMatchSignature = verifyKeysMatchSignature;
164
- //# sourceMappingURL=chunk-ZKZV6OI3.cjs.map
165
- //# sourceMappingURL=chunk-ZKZV6OI3.cjs.map
164
+ //# sourceMappingURL=chunk-7BNJV2ZS.cjs.map
165
+ //# sourceMappingURL=chunk-7BNJV2ZS.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/keys/types.ts","../src/keys/derive.ts","../src/keys/viewing.ts"],"names":["init_poseidon","init_crypto","keccak256","toHex","bytesToBigint","hexToBytes","FIELD_PRIME","splitToM31Limbs","computeStarkOwnerHash","keccakM31","bytesToHex"],"mappings":"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","file":"chunk-ZKZV6OI3.cjs","sourcesContent":["/**\n * Key Type Definitions for UPP SDK\n *\n * Post-quantum key structure (hash-based, no elliptic curves):\n *\n * Wallet Signature → Seed\n * ├── Spending Secret → Owner Hash = Poseidon(spendingSecret)\n * └── Viewing Secret (for note encryption, derived from seed)\n *\n * Ownership is proven via hash preimage: \"I know secret such that Poseidon(secret) == ownerHash\"\n * This replaces the previous BabyJubJub ECDLP-based ownership proof.\n */\n\nimport type { Hex, Address } from 'viem'\n\n/**\n * Master keys derived from wallet signature\n *\n * Post-quantum: uses hash-based ownership instead of BabyJubJub curve.\n * ownerHash = Poseidon(spendingSecret) replaces spendingPubKey (curve point).\n */\nexport interface MasterKeys {\n /** Spending secret - for note ownership proofs (hash preimage) */\n spendingSecret: bigint\n /** Owner hash = Poseidon(spendingSecret) - publicly committed in notes */\n ownerHash: bigint\n /** Viewing secret - for note encryption/decryption (symmetric key derivation) */\n viewingSecret: bigint\n /** Viewing hash = Poseidon(viewingSecret) - for search tags and indexing */\n viewingHash: bigint\n}\n\n/**\n * Per-transaction viewing key (for decryption)\n *\n * Can be shared with auditors to reveal specific transactions\n * without compromising the master viewing secret.\n *\n * Post-quantum: uses hash-based key derivation instead of ECDH.\n */\nexport interface TransactionViewingKey {\n /** The Merkle leaf index (for locating the on-chain event) */\n leafIndex: number\n /** The per-note nonce (used in key derivation) */\n nonce: bigint\n /** The per-note decryption key (derived from viewingSecret + nonce) */\n decryptionKey: Hex\n}\n\n/**\n * Exported viewing keys for audit\n *\n * Contains the minimum information needed for an auditor\n * to decrypt specific transactions.\n */\nexport interface AuditKeyExport {\n /** Version for forward compatibility (v4 = post-quantum hash-based) */\n version: 4\n /** Ethereum address that signed to derive keys (for identification) */\n signerAddress: Address\n /** The viewing hash (for verification) */\n viewingHash: bigint\n /** Per-transaction viewing keys */\n viewingKeys: TransactionViewingKey[]\n /** Instructions for auditor */\n instructions: string\n}\n\n/**\n * Stealth address components (simplified for hash-based system)\n * Published once, used by senders to encrypt notes\n */\nexport interface StealthAddressComponents {\n /** Owner hash = Poseidon(spendingSecret) */\n ownerHash: bigint\n /** Viewing hash = Poseidon(viewingSecret) - for encryption */\n viewingHash: bigint\n /** Optional chain ID (for multi-chain support) */\n chainId?: number\n}\n\n/**\n * Configuration for key derivation\n */\nexport interface KeyDerivationConfig {\n /** The message to sign for key derivation */\n message: string\n /** Version number for the key derivation scheme */\n version: 1\n}\n\n/**\n * Default key derivation configuration\n */\nexport const DEFAULT_KEY_DERIVATION_CONFIG: KeyDerivationConfig = {\n message: 'UPP Stealth Key Derivation v1',\n version: 1,\n}\n\n/**\n * Result of deriving one-time keys for a transaction (hash-based)\n */\nexport interface OneTimeKeys {\n /** One-time secret (for the owner to spend the note) */\n oneTimeSecret: bigint\n /** One-time owner hash = Poseidon(oneTimeSecret) - in the commitment */\n ownerHash: bigint\n}\n\n/**\n * Serialized key format for storage\n */\nexport interface SerializedKeys {\n version: 1\n /** Hex-encoded encrypted key data */\n encryptedData: Hex\n /** Salt for key derivation (if password protected) */\n salt?: Hex\n /** Nonce for encryption */\n nonce: Hex\n}\n\n// =========================================================================\n// STARK Key Types (M31/Keccak-based, post-quantum)\n// =========================================================================\n\nimport type { M31Digest, M31Secret } from '../utils/keccak-m31.js'\n\n/** Which proving system to use */\nexport type ProvingSystem = 'snark' | 'stark'\n\n/**\n * STARK master keys derived from wallet signature.\n *\n * Uses M31 field and keccak-256 hashing — no elliptic curves.\n * ownerHash = keccak_m31(starkSecret) — 4 M31 elements.\n */\nexport interface StarkMasterKeys {\n /** 8 M31 limbs (248 bits of entropy) — for ownership proofs */\n starkSecret: M31Secret\n /** keccak_m31(starkSecret) — publicly committed in STARK notes */\n starkOwnerHash: M31Digest\n /** 8 M31 limbs — for note encryption/decryption */\n starkViewingSecret: M31Secret\n /** keccak_m31(starkViewingSecret) — for search tags and indexing */\n starkViewingHash: M31Digest\n}\n\n/**\n * Dual master keys: both SNARK (BN254/Poseidon) and STARK (M31/Keccak).\n *\n * Derived from the same wallet signature via domain-separated keccak256.\n * Breaking BJJ (quantum) does NOT compromise STARK keys (keccak preimage resistance).\n */\nexport interface DualMasterKeys {\n snark: MasterKeys\n stark: StarkMasterKeys\n}\n","/**\n * Key Derivation from Wallet Signature (Post-Quantum / Hash-Based)\n *\n * Derives keys from an Ethereum wallet signature using only hash functions.\n * No elliptic curve operations — quantum-resistant by design.\n *\n * Security Model:\n * - Keys are derived deterministically from the signature\n * - No seed phrase management required\n * - Same signature always produces same keys\n * - Ownership proven via hash preimage (Poseidon), not discrete log\n */\n\nimport { keccak256, toHex, type Hex } from 'viem'\nimport { FIELD_PRIME } from '../utils/poseidon.js'\nimport { hexToBytes, bytesToBigint } from '../utils/crypto.js'\nimport { splitToM31Limbs, computeStarkOwnerHash } from '../utils/keccak-m31.js'\nimport type { MasterKeys, StarkMasterKeys, DualMasterKeys, KeyDerivationConfig } from './types.js'\nimport { DEFAULT_KEY_DERIVATION_CONFIG } from './types.js'\n\n/**\n * Derive master keys from a wallet signature (hash-based, post-quantum)\n *\n * This replaces the previous BabyJubJub-based derivation.\n * Instead of curve points, we use Poseidon hashes for ownership proofs.\n *\n * @param signature - The wallet signature (from personal_sign or EIP-712)\n * @param config - Optional key derivation configuration\n * @returns Master keys for stealth operations\n *\n * @example\n * ```ts\n * const signature = await walletClient.signMessage({\n * message: 'UPP Stealth Key Derivation v1'\n * })\n * const keys = await deriveKeysFromSignature(signature)\n * // keys.ownerHash is Poseidon(spendingSecret) — used in note commitments\n * ```\n */\nexport async function deriveKeysFromSignature(\n signature: Hex,\n config: KeyDerivationConfig = DEFAULT_KEY_DERIVATION_CONFIG\n): Promise<MasterKeys> {\n const { poseidon } = await import('../utils/poseidon.js')\n\n // Create a seed from the signature using keccak256\n const seed = keccak256(signature)\n\n // Derive spending secret from seed\n const spendingSecretHash = keccak256(\n toHex(new TextEncoder().encode(`${seed}:spending:v${config.version}`))\n )\n const spendingSecretRaw = bytesToBigint(hexToBytes(spendingSecretHash))\n const spendingSecret = spendingSecretRaw % FIELD_PRIME\n\n // Derive owner hash: Poseidon(spendingSecret)\n // This replaces BabyJubJub public key derivation\n const ownerHash = await poseidon([spendingSecret])\n\n // Derive viewing secret from seed\n const viewingSecretHash = keccak256(\n toHex(new TextEncoder().encode(`${seed}:viewing:v${config.version}`))\n )\n const viewingSecretRaw = bytesToBigint(hexToBytes(viewingSecretHash))\n const viewingSecret = viewingSecretRaw % FIELD_PRIME\n\n // Derive viewing hash: Poseidon(viewingSecret)\n const viewingHash = await poseidon([viewingSecret])\n\n return {\n spendingSecret,\n ownerHash,\n viewingSecret,\n viewingHash,\n }\n}\n\n/**\n * Get the message to sign for key derivation\n */\nexport function getKeyDerivationMessage(\n config: KeyDerivationConfig = DEFAULT_KEY_DERIVATION_CONFIG\n): string {\n return config.message\n}\n\n/**\n * Verify that keys match a given signature\n */\nexport async function verifyKeysMatchSignature(\n keys: MasterKeys,\n signature: Hex,\n config: KeyDerivationConfig = DEFAULT_KEY_DERIVATION_CONFIG\n): Promise<boolean> {\n const derivedKeys = await deriveKeysFromSignature(signature, config)\n\n return (\n keys.spendingSecret === derivedKeys.spendingSecret &&\n keys.ownerHash === derivedKeys.ownerHash &&\n keys.viewingSecret === derivedKeys.viewingSecret &&\n keys.viewingHash === derivedKeys.viewingHash\n )\n}\n\n/**\n * Derive STARK master keys from a wallet signature (M31/Keccak, post-quantum)\n *\n * Uses domain-separated keccak256 to derive M31 secrets, then keccak_m31\n * for owner/viewing hashes. No elliptic curve operations.\n *\n * @param signature - The wallet signature (same one used for SNARK keys)\n * @param config - Optional key derivation configuration\n * @returns STARK master keys for stealth operations\n */\nexport function deriveStarkKeysFromSignature(\n signature: Hex,\n config: KeyDerivationConfig = DEFAULT_KEY_DERIVATION_CONFIG\n): StarkMasterKeys {\n const seed = keccak256(signature)\n\n // Derive STARK spending secret: 8 M31 limbs from a single keccak256\n const starkSpendingHash = keccak256(\n toHex(new TextEncoder().encode(`${seed}:stark:spending:v${config.version}`))\n )\n const starkSecret = splitToM31Limbs(starkSpendingHash)\n const starkOwnerHash = computeStarkOwnerHash(starkSecret)\n\n // Derive STARK viewing secret: 8 M31 limbs from a separate keccak256\n const starkViewingHash = keccak256(\n toHex(new TextEncoder().encode(`${seed}:stark:viewing:v${config.version}`))\n )\n const starkViewingSecret = splitToM31Limbs(starkViewingHash)\n const starkViewingHashDigest = computeStarkOwnerHash(starkViewingSecret)\n\n return {\n starkSecret,\n starkOwnerHash,\n starkViewingSecret,\n starkViewingHash: starkViewingHashDigest,\n }\n}\n\n/**\n * Derive both SNARK and STARK keys from a single wallet signature.\n *\n * Same seed, domain-separated derivation. Breaking BJJ (quantum) does NOT\n * compromise STARK keys — keccak preimage resistance provides 2^128 quantum security.\n */\nexport async function deriveDualKeysFromSignature(\n signature: Hex,\n config: KeyDerivationConfig = DEFAULT_KEY_DERIVATION_CONFIG\n): Promise<DualMasterKeys> {\n const snark = await deriveKeysFromSignature(signature, config)\n const stark = deriveStarkKeysFromSignature(signature, config)\n return { snark, stark }\n}\n\n/**\n * Derive a nullifier key from the spending secret\n *\n * nullifier = Poseidon(nullifierKey, leafIndex, commitment)\n */\nexport async function deriveNullifierKey(spendingSecret: bigint): Promise<bigint> {\n const { poseidon } = await import('../utils/poseidon.js')\n return await poseidon([spendingSecret, 0n]) // 0n = nullifier domain\n}\n","/**\n * Per-Transaction Viewing Key Derivation (Post-Quantum, Hash-Based)\n *\n * Implements hierarchical viewing keys using Poseidon hash instead of ECDH.\n *\n * Key Properties:\n * - Per-note decryption key: Poseidon(viewingSecret, nonce)\n * - AES key: keccak256(perNoteKey) for symmetric encryption\n *\n * Derivation:\n * perNoteKey = Poseidon(viewingSecret, nonce)\n * aesKey = keccak256(perNoteKey)\n *\n * SECURITY (v4):\n * Audit exports contain per-note decryption keys derived from viewingSecret + nonce.\n * This prevents master key recovery: knowing Poseidon(viewingSecret, nonce) doesn't\n * reveal viewingSecret due to the one-wayness of Poseidon.\n */\n\nimport type { Address, Hex } from 'viem'\nimport { keccak256, toHex } from 'viem'\nimport type {\n MasterKeys,\n StarkMasterKeys,\n TransactionViewingKey,\n AuditKeyExport,\n} from './types.js'\nimport { keccakM31, type M31Secret } from '../utils/keccak-m31.js'\nimport { bytesToHex } from '../utils/crypto.js'\n\n/**\n * Derive a per-note decryption key from master viewing secret and nonce\n *\n * @param viewingSecret - Master viewing secret\n * @param nonce - Unique per-note nonce\n * @returns Per-note decryption key as hex\n */\nexport async function derivePerNoteKey(\n viewingSecret: bigint,\n nonce: bigint\n): Promise<Hex> {\n const { poseidon } = await import('../utils/poseidon.js')\n const perNoteKey = await poseidon([viewingSecret, nonce])\n return toHex(perNoteKey, { size: 32 })\n}\n\n/**\n * Derive per-note key from MasterKeys convenience wrapper\n */\nexport async function derivePerNoteKeyFromKeys(\n keys: MasterKeys,\n nonce: bigint\n): Promise<Hex> {\n return derivePerNoteKey(keys.viewingSecret, nonce)\n}\n\n/**\n * Note reference for audit export\n */\nexport interface NoteReference {\n /** The Merkle leaf index (for locating the on-chain event) */\n leafIndex: number\n /** The nonce used in per-note key derivation */\n nonce: bigint\n}\n\n/**\n * Export viewing keys for specific notes\n *\n * Creates an export package that can be shared with an auditor.\n * The auditor can use these keys to decrypt the specified notes,\n * but cannot derive keys for other notes.\n *\n * @param keys - Master keys\n * @param signerAddress - The Ethereum address that signed to derive keys\n * @param notes - Array of note references (leafIndex + nonce) to export\n * @returns Audit key export package\n */\nexport async function exportViewingKeysForAudit(\n keys: MasterKeys,\n signerAddress: Address,\n notes: NoteReference[]\n): Promise<AuditKeyExport> {\n const viewingKeys: TransactionViewingKey[] = []\n\n for (const note of notes) {\n // Derive the per-note decryption key\n const decryptionKey = await derivePerNoteKey(keys.viewingSecret, note.nonce)\n\n viewingKeys.push({\n leafIndex: note.leafIndex,\n nonce: note.nonce,\n decryptionKey,\n })\n }\n\n return {\n version: 4,\n signerAddress,\n viewingHash: keys.viewingHash,\n viewingKeys,\n instructions: `\nThis export contains per-note decryption keys for ${viewingKeys.length} UPP note(s).\n\nTo decrypt a note:\n1. Find the viewingKey entry for the desired leafIndex\n2. Retrieve the encrypted note from the blockchain (Shielded event at that leaf index)\n3. Derive AES key: key = keccak256(decryptionKey)\n4. Decrypt the note ciphertext with AES-GCM\n\nThese per-note keys ONLY allow decryption of the specified notes.\nThey do NOT reveal:\n- The master viewing secret (protected by Poseidon one-wayness)\n- Keys for any other notes\n- The spending secret (cannot spend funds)\n `.trim(),\n }\n}\n\n/**\n * Validate an audit key export\n */\nexport function validateAuditKeyExport(\n exportData: AuditKeyExport\n): { valid: boolean; error?: string } {\n if (exportData.version !== 4) {\n return { valid: false, error: `Unsupported version: ${exportData.version}. Expected version 4.` }\n }\n\n if (!exportData.signerAddress || !exportData.signerAddress.startsWith('0x')) {\n return { valid: false, error: 'Invalid signer address' }\n }\n\n if (exportData.viewingHash === undefined || exportData.viewingHash === null) {\n return { valid: false, error: 'Missing viewing hash' }\n }\n\n if (!Array.isArray(exportData.viewingKeys) || exportData.viewingKeys.length === 0) {\n return { valid: false, error: 'No viewing keys in export' }\n }\n\n return { valid: true }\n}\n\n/**\n * Look up a decryption key from an audit export by leaf index\n *\n * Returns the per-note decryption key for direct use in AES-GCM decryption.\n * Derive AES key: keccak256(decryptionKey)\n */\nexport function getViewingKeyFromExport(\n exportData: AuditKeyExport,\n leafIndex: number\n): Hex | null {\n const key = exportData.viewingKeys.find(k => k.leafIndex === leafIndex)\n return key ? key.decryptionKey : null\n}\n\n// =========================================================================\n// STARK Per-Note Viewing Key Derivation (Keccak-based, no elliptic curves)\n// =========================================================================\n\n/**\n * Derive a STARK per-note decryption key from viewing secret and nonce.\n *\n * Uses keccak_m31 instead of Poseidon — purely symmetric, post-quantum safe.\n * The nonce is encoded as a single M31 element appended to the viewing secret.\n *\n * perNoteDigest = keccak_m31(viewingSecret[0..8], nonce)\n * aesKey = keccak256(perNoteDigest_packed_as_16_LE_bytes)\n *\n * @param starkViewingSecret - 8 M31 limbs (the master STARK viewing secret)\n * @param nonce - Per-note nonce (M31 range)\n * @returns 32-byte AES key as hex\n */\nexport function deriveStarkPerNoteKey(\n starkViewingSecret: M31Secret,\n nonce: bigint\n): Hex {\n // keccak_m31(viewingSecret[0..8], nonce) → 4 M31 elements\n const digest = keccakM31([...starkViewingSecret, nonce])\n\n // Pack digest as 16 bytes LE for AES key derivation\n const bytes = new Uint8Array(16)\n for (let i = 0; i < 4; i++) {\n const val = Number(digest[i]!)\n bytes[i * 4] = val & 0xff\n bytes[i * 4 + 1] = (val >> 8) & 0xff\n bytes[i * 4 + 2] = (val >> 16) & 0xff\n bytes[i * 4 + 3] = (val >> 24) & 0xff\n }\n\n // Derive 32-byte AES key via keccak256\n return keccak256(bytesToHex(bytes))\n}\n\n/**\n * Derive STARK per-note key from StarkMasterKeys convenience wrapper\n */\nexport function deriveStarkPerNoteKeyFromKeys(\n keys: StarkMasterKeys,\n nonce: bigint\n): Hex {\n return deriveStarkPerNoteKey(keys.starkViewingSecret, nonce)\n}\n"]}
1
+ {"version":3,"sources":["../src/keys/types.ts","../src/keys/derive.ts","../src/keys/viewing.ts"],"names":["init_poseidon","init_crypto","keccak256","toHex","bytesToBigint","hexToBytes","FIELD_PRIME","splitToM31Limbs","computeStarkOwnerHash","keccakM31","bytesToHex"],"mappings":"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","file":"chunk-7BNJV2ZS.cjs","sourcesContent":["/**\n * Key Type Definitions for UPP SDK\n *\n * Post-quantum key structure (hash-based, no elliptic curves):\n *\n * Wallet Signature → Seed\n * ├── Spending Secret → Owner Hash = Poseidon(spendingSecret)\n * └── Viewing Secret (for note encryption, derived from seed)\n *\n * Ownership is proven via hash preimage: \"I know secret such that Poseidon(secret) == ownerHash\"\n * This replaces the previous BabyJubJub ECDLP-based ownership proof.\n */\n\nimport type { Hex, Address } from 'viem'\n\n/**\n * Master keys derived from wallet signature\n *\n * Post-quantum: uses hash-based ownership instead of BabyJubJub curve.\n * ownerHash = Poseidon(spendingSecret) replaces spendingPubKey (curve point).\n */\nexport interface MasterKeys {\n /** Spending secret - for note ownership proofs (hash preimage) */\n spendingSecret: bigint\n /** Owner hash = Poseidon(spendingSecret) - publicly committed in notes */\n ownerHash: bigint\n /** Viewing secret - for note encryption/decryption (symmetric key derivation) */\n viewingSecret: bigint\n /** Viewing hash = Poseidon(viewingSecret) - for search tags and indexing */\n viewingHash: bigint\n}\n\n/**\n * Per-transaction viewing key (for decryption)\n *\n * Can be shared with auditors to reveal specific transactions\n * without compromising the master viewing secret.\n *\n * Post-quantum: uses hash-based key derivation instead of ECDH.\n */\nexport interface TransactionViewingKey {\n /** The Merkle leaf index (for locating the on-chain event) */\n leafIndex: number\n /** The per-note nonce (used in key derivation) */\n nonce: bigint\n /** The per-note decryption key (derived from viewingSecret + nonce) */\n decryptionKey: Hex\n}\n\n/**\n * Exported viewing keys for audit\n *\n * Contains the minimum information needed for an auditor\n * to decrypt specific transactions.\n */\nexport interface AuditKeyExport {\n /** Version for forward compatibility (v4 = post-quantum hash-based) */\n version: 4\n /** Ethereum address that signed to derive keys (for identification) */\n signerAddress: Address\n /** The viewing hash (for verification) */\n viewingHash: bigint\n /** Per-transaction viewing keys */\n viewingKeys: TransactionViewingKey[]\n /** Instructions for auditor */\n instructions: string\n}\n\n/**\n * Stealth address components (simplified for hash-based system)\n * Published once, used by senders to encrypt notes\n */\nexport interface StealthAddressComponents {\n /** Owner hash = Poseidon(spendingSecret) */\n ownerHash: bigint\n /** Viewing hash = Poseidon(viewingSecret) - for encryption */\n viewingHash: bigint\n /** Optional chain ID (for multi-chain support) */\n chainId?: number\n}\n\n/**\n * Configuration for key derivation\n */\nexport interface KeyDerivationConfig {\n /** The message to sign for key derivation */\n message: string\n /** Version number for the key derivation scheme */\n version: 1\n}\n\n/**\n * Default key derivation configuration\n */\nexport const DEFAULT_KEY_DERIVATION_CONFIG: KeyDerivationConfig = {\n message: 'UPP Stealth Key Derivation v1',\n version: 1,\n}\n\n/**\n * Result of deriving one-time keys for a transaction (hash-based)\n */\nexport interface OneTimeKeys {\n /** One-time secret (for the owner to spend the note) */\n oneTimeSecret: bigint\n /** One-time owner hash = Poseidon(oneTimeSecret) - in the commitment */\n ownerHash: bigint\n}\n\n/**\n * Serialized key format for storage\n */\nexport interface SerializedKeys {\n version: 1\n /** Hex-encoded encrypted key data */\n encryptedData: Hex\n /** Salt for key derivation (if password protected) */\n salt?: Hex\n /** Nonce for encryption */\n nonce: Hex\n}\n\n// =========================================================================\n// STARK Key Types (M31/Keccak-based, post-quantum)\n// =========================================================================\n\nimport type { M31Digest, M31Secret } from '../utils/keccak-m31.js'\n\n/** Which proving system to use */\nexport type ProvingSystem = 'snark' | 'stark'\n\n/**\n * STARK master keys derived from wallet signature.\n *\n * Uses M31 field and keccak-256 hashing — no elliptic curves.\n * ownerHash = keccak_m31(starkSecret) — 4 M31 elements.\n */\nexport interface StarkMasterKeys {\n /** 8 M31 limbs (248 bits of entropy) — for ownership proofs */\n starkSecret: M31Secret\n /** keccak_m31(starkSecret) — publicly committed in STARK notes */\n starkOwnerHash: M31Digest\n /** 8 M31 limbs — for note encryption/decryption */\n starkViewingSecret: M31Secret\n /** keccak_m31(starkViewingSecret) — for search tags and indexing */\n starkViewingHash: M31Digest\n}\n\n/**\n * Dual master keys: both SNARK (BN254/Poseidon) and STARK (M31/Keccak).\n *\n * Derived from the same wallet signature via domain-separated keccak256.\n * Breaking BJJ (quantum) does NOT compromise STARK keys (keccak preimage resistance).\n */\nexport interface DualMasterKeys {\n snark: MasterKeys\n stark: StarkMasterKeys\n}\n","/**\n * Key Derivation from Wallet Signature (Post-Quantum / Hash-Based)\n *\n * Derives keys from an Ethereum wallet signature using only hash functions.\n * No elliptic curve operations — quantum-resistant by design.\n *\n * Security Model:\n * - Keys are derived deterministically from the signature\n * - No seed phrase management required\n * - Same signature always produces same keys\n * - Ownership proven via hash preimage (Poseidon), not discrete log\n */\n\nimport { keccak256, toHex, type Hex } from 'viem'\nimport { FIELD_PRIME } from '../utils/poseidon.js'\nimport { hexToBytes, bytesToBigint } from '../utils/crypto.js'\nimport { splitToM31Limbs, computeStarkOwnerHash } from '../utils/keccak-m31.js'\nimport type { MasterKeys, StarkMasterKeys, DualMasterKeys, KeyDerivationConfig } from './types.js'\nimport { DEFAULT_KEY_DERIVATION_CONFIG } from './types.js'\n\n/**\n * Derive master keys from a wallet signature (hash-based, post-quantum)\n *\n * This replaces the previous BabyJubJub-based derivation.\n * Instead of curve points, we use Poseidon hashes for ownership proofs.\n *\n * @param signature - The wallet signature (from personal_sign or EIP-712)\n * @param config - Optional key derivation configuration\n * @returns Master keys for stealth operations\n *\n * @example\n * ```ts\n * const signature = await walletClient.signMessage({\n * message: 'UPP Stealth Key Derivation v1'\n * })\n * const keys = await deriveKeysFromSignature(signature)\n * // keys.ownerHash is Poseidon(spendingSecret) — used in note commitments\n * ```\n */\nexport async function deriveKeysFromSignature(\n signature: Hex,\n config: KeyDerivationConfig = DEFAULT_KEY_DERIVATION_CONFIG\n): Promise<MasterKeys> {\n const { poseidon } = await import('../utils/poseidon.js')\n\n // Create a seed from the signature using keccak256\n const seed = keccak256(signature)\n\n // Derive spending secret from seed\n const spendingSecretHash = keccak256(\n toHex(new TextEncoder().encode(`${seed}:spending:v${config.version}`))\n )\n const spendingSecretRaw = bytesToBigint(hexToBytes(spendingSecretHash))\n const spendingSecret = spendingSecretRaw % FIELD_PRIME\n\n // Derive owner hash: Poseidon(spendingSecret)\n // This replaces BabyJubJub public key derivation\n const ownerHash = await poseidon([spendingSecret])\n\n // Derive viewing secret from seed\n const viewingSecretHash = keccak256(\n toHex(new TextEncoder().encode(`${seed}:viewing:v${config.version}`))\n )\n const viewingSecretRaw = bytesToBigint(hexToBytes(viewingSecretHash))\n const viewingSecret = viewingSecretRaw % FIELD_PRIME\n\n // Derive viewing hash: Poseidon(viewingSecret)\n const viewingHash = await poseidon([viewingSecret])\n\n return {\n spendingSecret,\n ownerHash,\n viewingSecret,\n viewingHash,\n }\n}\n\n/**\n * Get the message to sign for key derivation\n */\nexport function getKeyDerivationMessage(\n config: KeyDerivationConfig = DEFAULT_KEY_DERIVATION_CONFIG\n): string {\n return config.message\n}\n\n/**\n * Verify that keys match a given signature\n */\nexport async function verifyKeysMatchSignature(\n keys: MasterKeys,\n signature: Hex,\n config: KeyDerivationConfig = DEFAULT_KEY_DERIVATION_CONFIG\n): Promise<boolean> {\n const derivedKeys = await deriveKeysFromSignature(signature, config)\n\n return (\n keys.spendingSecret === derivedKeys.spendingSecret &&\n keys.ownerHash === derivedKeys.ownerHash &&\n keys.viewingSecret === derivedKeys.viewingSecret &&\n keys.viewingHash === derivedKeys.viewingHash\n )\n}\n\n/**\n * Derive STARK master keys from a wallet signature (M31/Keccak, post-quantum)\n *\n * Uses domain-separated keccak256 to derive M31 secrets, then keccak_m31\n * for owner/viewing hashes. No elliptic curve operations.\n *\n * @param signature - The wallet signature (same one used for SNARK keys)\n * @param config - Optional key derivation configuration\n * @returns STARK master keys for stealth operations\n */\nexport function deriveStarkKeysFromSignature(\n signature: Hex,\n config: KeyDerivationConfig = DEFAULT_KEY_DERIVATION_CONFIG\n): StarkMasterKeys {\n const seed = keccak256(signature)\n\n // Derive STARK spending secret: 8 M31 limbs from a single keccak256\n const starkSpendingHash = keccak256(\n toHex(new TextEncoder().encode(`${seed}:stark:spending:v${config.version}`))\n )\n const starkSecret = splitToM31Limbs(starkSpendingHash)\n const starkOwnerHash = computeStarkOwnerHash(starkSecret)\n\n // Derive STARK viewing secret: 8 M31 limbs from a separate keccak256\n const starkViewingHash = keccak256(\n toHex(new TextEncoder().encode(`${seed}:stark:viewing:v${config.version}`))\n )\n const starkViewingSecret = splitToM31Limbs(starkViewingHash)\n const starkViewingHashDigest = computeStarkOwnerHash(starkViewingSecret)\n\n return {\n starkSecret,\n starkOwnerHash,\n starkViewingSecret,\n starkViewingHash: starkViewingHashDigest,\n }\n}\n\n/**\n * Derive both SNARK and STARK keys from a single wallet signature.\n *\n * Same seed, domain-separated derivation. Breaking BJJ (quantum) does NOT\n * compromise STARK keys — keccak preimage resistance provides 2^128 quantum security.\n */\nexport async function deriveDualKeysFromSignature(\n signature: Hex,\n config: KeyDerivationConfig = DEFAULT_KEY_DERIVATION_CONFIG\n): Promise<DualMasterKeys> {\n const snark = await deriveKeysFromSignature(signature, config)\n const stark = deriveStarkKeysFromSignature(signature, config)\n return { snark, stark }\n}\n\n/**\n * Derive a nullifier key from the spending secret\n *\n * nullifier = Poseidon(nullifierKey, leafIndex, commitment)\n */\nexport async function deriveNullifierKey(spendingSecret: bigint): Promise<bigint> {\n const { poseidon } = await import('../utils/poseidon.js')\n return await poseidon([spendingSecret, 0n]) // 0n = nullifier domain\n}\n","/**\n * Per-Transaction Viewing Key Derivation (Post-Quantum, Hash-Based)\n *\n * Implements hierarchical viewing keys using Poseidon hash instead of ECDH.\n *\n * Key Properties:\n * - Per-note decryption key: Poseidon(viewingSecret, nonce)\n * - AES key: keccak256(perNoteKey) for symmetric encryption\n *\n * Derivation:\n * perNoteKey = Poseidon(viewingSecret, nonce)\n * aesKey = keccak256(perNoteKey)\n *\n * SECURITY (v4):\n * Audit exports contain per-note decryption keys derived from viewingSecret + nonce.\n * This prevents master key recovery: knowing Poseidon(viewingSecret, nonce) doesn't\n * reveal viewingSecret due to the one-wayness of Poseidon.\n */\n\nimport type { Address, Hex } from 'viem'\nimport { keccak256, toHex } from 'viem'\nimport type {\n MasterKeys,\n StarkMasterKeys,\n TransactionViewingKey,\n AuditKeyExport,\n} from './types.js'\nimport { keccakM31, type M31Secret } from '../utils/keccak-m31.js'\nimport { bytesToHex } from '../utils/crypto.js'\n\n/**\n * Derive a per-note decryption key from master viewing secret and nonce\n *\n * @param viewingSecret - Master viewing secret\n * @param nonce - Unique per-note nonce\n * @returns Per-note decryption key as hex\n */\nexport async function derivePerNoteKey(\n viewingSecret: bigint,\n nonce: bigint\n): Promise<Hex> {\n const { poseidon } = await import('../utils/poseidon.js')\n const perNoteKey = await poseidon([viewingSecret, nonce])\n return toHex(perNoteKey, { size: 32 })\n}\n\n/**\n * Derive per-note key from MasterKeys convenience wrapper\n */\nexport async function derivePerNoteKeyFromKeys(\n keys: MasterKeys,\n nonce: bigint\n): Promise<Hex> {\n return derivePerNoteKey(keys.viewingSecret, nonce)\n}\n\n/**\n * Note reference for audit export\n */\nexport interface NoteReference {\n /** The Merkle leaf index (for locating the on-chain event) */\n leafIndex: number\n /** The nonce used in per-note key derivation */\n nonce: bigint\n}\n\n/**\n * Export viewing keys for specific notes\n *\n * Creates an export package that can be shared with an auditor.\n * The auditor can use these keys to decrypt the specified notes,\n * but cannot derive keys for other notes.\n *\n * @param keys - Master keys\n * @param signerAddress - The Ethereum address that signed to derive keys\n * @param notes - Array of note references (leafIndex + nonce) to export\n * @returns Audit key export package\n */\nexport async function exportViewingKeysForAudit(\n keys: MasterKeys,\n signerAddress: Address,\n notes: NoteReference[]\n): Promise<AuditKeyExport> {\n const viewingKeys: TransactionViewingKey[] = []\n\n for (const note of notes) {\n // Derive the per-note decryption key\n const decryptionKey = await derivePerNoteKey(keys.viewingSecret, note.nonce)\n\n viewingKeys.push({\n leafIndex: note.leafIndex,\n nonce: note.nonce,\n decryptionKey,\n })\n }\n\n return {\n version: 4,\n signerAddress,\n viewingHash: keys.viewingHash,\n viewingKeys,\n instructions: `\nThis export contains per-note decryption keys for ${viewingKeys.length} UPP note(s).\n\nTo decrypt a note:\n1. Find the viewingKey entry for the desired leafIndex\n2. Retrieve the encrypted note from the blockchain (Shielded event at that leaf index)\n3. Derive AES key: key = keccak256(decryptionKey)\n4. Decrypt the note ciphertext with AES-GCM\n\nThese per-note keys ONLY allow decryption of the specified notes.\nThey do NOT reveal:\n- The master viewing secret (protected by Poseidon one-wayness)\n- Keys for any other notes\n- The spending secret (cannot spend funds)\n `.trim(),\n }\n}\n\n/**\n * Validate an audit key export\n */\nexport function validateAuditKeyExport(\n exportData: AuditKeyExport\n): { valid: boolean; error?: string } {\n if (exportData.version !== 4) {\n return { valid: false, error: `Unsupported version: ${exportData.version}. Expected version 4.` }\n }\n\n if (!exportData.signerAddress || !exportData.signerAddress.startsWith('0x')) {\n return { valid: false, error: 'Invalid signer address' }\n }\n\n if (exportData.viewingHash === undefined || exportData.viewingHash === null) {\n return { valid: false, error: 'Missing viewing hash' }\n }\n\n if (!Array.isArray(exportData.viewingKeys) || exportData.viewingKeys.length === 0) {\n return { valid: false, error: 'No viewing keys in export' }\n }\n\n return { valid: true }\n}\n\n/**\n * Look up a decryption key from an audit export by leaf index\n *\n * Returns the per-note decryption key for direct use in AES-GCM decryption.\n * Derive AES key: keccak256(decryptionKey)\n */\nexport function getViewingKeyFromExport(\n exportData: AuditKeyExport,\n leafIndex: number\n): Hex | null {\n const key = exportData.viewingKeys.find(k => k.leafIndex === leafIndex)\n return key ? key.decryptionKey : null\n}\n\n// =========================================================================\n// STARK Per-Note Viewing Key Derivation (Keccak-based, no elliptic curves)\n// =========================================================================\n\n/**\n * Derive a STARK per-note decryption key from viewing secret and nonce.\n *\n * Uses keccak_m31 instead of Poseidon — purely symmetric, post-quantum safe.\n * The nonce is encoded as a single M31 element appended to the viewing secret.\n *\n * perNoteDigest = keccak_m31(viewingSecret[0..8], nonce)\n * aesKey = keccak256(perNoteDigest_packed_as_16_LE_bytes)\n *\n * @param starkViewingSecret - 8 M31 limbs (the master STARK viewing secret)\n * @param nonce - Per-note nonce (M31 range)\n * @returns 32-byte AES key as hex\n */\nexport function deriveStarkPerNoteKey(\n starkViewingSecret: M31Secret,\n nonce: bigint\n): Hex {\n // keccak_m31(viewingSecret[0..8], nonce) → 4 M31 elements\n const digest = keccakM31([...starkViewingSecret, nonce])\n\n // Pack digest as 16 bytes LE for AES key derivation\n const bytes = new Uint8Array(16)\n for (let i = 0; i < 4; i++) {\n const val = Number(digest[i]!)\n bytes[i * 4] = val & 0xff\n bytes[i * 4 + 1] = (val >> 8) & 0xff\n bytes[i * 4 + 2] = (val >> 16) & 0xff\n bytes[i * 4 + 3] = (val >> 24) & 0xff\n }\n\n // Derive 32-byte AES key via keccak256\n return keccak256(bytesToHex(bytes))\n}\n\n/**\n * Derive STARK per-note key from StarkMasterKeys convenience wrapper\n */\nexport function deriveStarkPerNoteKeyFromKeys(\n keys: StarkMasterKeys,\n nonce: bigint\n): Hex {\n return deriveStarkPerNoteKey(keys.starkViewingSecret, nonce)\n}\n"]}
@@ -1,4 +1,4 @@
1
- import { M31_P, SECRET_LIMBS } from './chunk-5V5HSN6Y.js';
1
+ import { M31_P, SECRET_LIMBS } from './chunk-6TFDBBAQ.js';
2
2
  import { keccak256, encodePacked, pad, numberToHex } from 'viem';
3
3
 
4
4
  var STARK_AMOUNT_SCALE = 10n ** 15n;
@@ -136,5 +136,5 @@ function buildStarkTransferWitness(params) {
136
136
  }
137
137
 
138
138
  export { STARK_AMOUNT_SCALE, STARK_ASP_TREE_DEPTH, STARK_STATE_TREE_DEPTH, addressToM31, buildStarkTransferWitness, buildStarkWithdrawWitness, computeTransferPublicInputsSeed, computeWithdrawPublicInputsSeed, isStarkAligned, packM31Digest, scaleAmountForStark, splitSecretToM31Limbs, truncateToM31 };
139
- //# sourceMappingURL=chunk-XBNYAAMU.js.map
140
- //# sourceMappingURL=chunk-XBNYAAMU.js.map
139
+ //# sourceMappingURL=chunk-7T4CUE6E.js.map
140
+ //# sourceMappingURL=chunk-7T4CUE6E.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/utils/stark.ts"],"names":[],"mappings":";;;AAmBO,IAAM,qBAAqB,GAAA,IAAO;AAGlC,IAAM,sBAAA,GAAyB;AAG/B,IAAM,oBAAA,GAAuB;AAO7B,SAAS,eAAe,MAAA,EAAyB;AACtD,EAAA,IAAI,MAAA,IAAU,IAAI,OAAO,KAAA;AACzB,EAAA,MAAM,SAAS,MAAA,GAAS,kBAAA;AACxB,EAAA,OAAO,MAAA,GAAS,kBAAA,KAAuB,MAAA,IAAU,MAAA,GAAS,KAAA;AAC5D;AASO,SAAS,oBAAoB,SAAA,EAA2B;AAC7D,EAAA,MAAM,SAAS,SAAA,GAAY,kBAAA;AAC3B,EAAA,IAAI,MAAA,GAAS,uBAAuB,SAAA,EAAW;AAC7C,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA,OAAA,EAAU,SAAS,CAAA,6BAAA,EAAgC,kBAAkB,CAAA,CAAA,CAAG,CAAA;AAAA,EAC1F;AACA,EAAA,IAAI,UAAU,KAAA,EAAO;AACnB,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA,cAAA,EAAiB,MAAM,CAAA,kBAAA,EAAqB,KAAK,CAAA,CAAA,CAAG,CAAA;AAAA,EACtE;AACA,EAAA,OAAO,OAAO,MAAM,CAAA;AACtB;AAGO,SAAS,cAAc,KAAA,EAAuB;AACnD,EAAA,OAAO,MAAA,CAAO,QAAQ,KAAK,CAAA;AAC7B;AAOO,SAAS,aAAa,IAAA,EAAuB;AAClD,EAAA,OAAO,MAAA,CAAO,MAAA,CAAO,IAAI,CAAA,GAAI,KAAK,CAAA;AACpC;AAUO,SAAS,sBAAsB,MAAA,EAA0B;AAC9D,EAAA,MAAM,QAAkB,EAAC;AACzB,EAAA,IAAI,SAAA,GAAY,MAAA;AAChB,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,YAAA,EAAc,CAAA,EAAA,EAAK;AACrC,IAAA,KAAA,CAAM,IAAA,CAAK,MAAA,CAAO,SAAA,GAAY,KAAK,CAAC,CAAA;AACpC,IAAA,SAAA,GAAY,SAAA,GAAY,KAAA;AAAA,EAC1B;AACA,EAAA,OAAO,KAAA;AACT;AAMO,SAAS,cAAc,MAAA,EAAkD;AAC9E,EAAA,OAAO,MAAA,CAAO,OAAO,CAAC,CAAC,IAClB,MAAA,CAAO,MAAA,CAAO,CAAC,CAAC,CAAA,IAAK,MACrB,MAAA,CAAO,MAAA,CAAO,CAAC,CAAC,CAAA,IAAK,MACrB,MAAA,CAAO,MAAA,CAAO,CAAC,CAAC,CAAA,IAAK,GAAA;AAC5B;AAUO,SAAS,gCAAgC,MAAA,EASxC;AACN,EAAA,OAAO,SAAA;AAAA,IACL,YAAA;AAAA,MACE,CAAC,WAAW,SAAA,EAAW,SAAA,EAAW,WAAW,SAAA,EAAW,SAAA,EAAW,WAAW,MAAM,CAAA;AAAA,MACpF;AAAA,QACE,MAAA,CAAO,SAAA;AAAA,QACP,MAAA,CAAO,SAAA;AAAA,QACP,MAAA,CAAO,OAAA;AAAA,QACP,MAAA,CAAO,KAAA;AAAA,QACP,MAAA,CAAO,KAAA;AAAA,QACP,MAAA,CAAO,MAAA;AAAA,QACP,MAAA,CAAO,SAAA;AAAA,QACP,MAAA,CAAO;AAAA;AACT;AACF,GACF;AACF;AAMO,SAAS,gCAAgC,MAAA,EAOxC;AACN,EAAA,OAAO,SAAA;AAAA,IACL,YAAA;AAAA,MACE,CAAC,SAAA,EAAW,SAAA,EAAW,SAAA,EAAW,SAAA,EAAW,WAAW,SAAS,CAAA;AAAA,MACjE;AAAA,QACE,MAAA,CAAO,SAAA;AAAA,QACP,MAAA,CAAO,SAAA;AAAA,QACP,MAAA,CAAO,OAAA;AAAA,QACP,MAAA,CAAO,KAAA;AAAA,QACP,MAAA,CAAO,iBAAA;AAAA,QACP,MAAA,CAAO;AAAA;AACT;AACF,GACF;AACF;AA8EA,SAAS,aAAa,KAAA,EAA6B;AACjD,EAAA,IAAI,OAAO,UAAU,QAAA,EAAU;AAC7B,IAAA,OAAO,IAAI,WAAA,CAAY,KAAK,GAAG,EAAE,IAAA,EAAM,IAAI,CAAA;AAAA,EAC7C;AACA,EAAA,OAAO,KAAA;AACT;AAEA,SAAS,eAAe,IAAA,EAAuB;AAC7C,EAAA,OAAO,KAAK,WAAA,EAAY;AAC1B;AAKO,SAAS,0BAA0B,MAAA,EAqBjB;AACvB,EAAA,OAAO;AAAA,IACL,cAAc,MAAA,CAAO,WAAA;AAAA,IACrB,cAAc,MAAA,CAAO,WAAA;AAAA,IACrB,gBAAgB,MAAA,CAAO,aAAA;AAAA,IACvB,cAAc,MAAA,CAAO,WAAA;AAAA,IACrB,OAAO,MAAA,CAAO,KAAA;AAAA,IACd,YAAY,MAAA,CAAO,SAAA;AAAA,IACnB,qBAAqB,IAAI,KAAA,CAAM,sBAAsB,CAAA,CAAE,KAAK,CAAC,CAAA;AAAA,IAC7D,oBAAoB,IAAI,KAAA,CAAM,sBAAsB,CAAA,CAAE,KAAK,CAAC,CAAA;AAAA,IAC5D,mBAAmB,IAAI,KAAA,CAAM,oBAAoB,CAAA,CAAE,KAAK,CAAC,CAAA;AAAA,IACzD,kBAAkB,IAAI,KAAA,CAAM,oBAAoB,CAAA,CAAE,KAAK,CAAC,CAAA;AAAA,IACxD,iBAAiB,MAAA,CAAO,cAAA;AAAA,IACxB,eAAe,MAAA,CAAO,YAAA;AAAA,IACtB,iBAAiB,MAAA,CAAO,cAAA;AAAA,IACxB,WAAW,MAAA,CAAO,SAAA;AAAA,IAClB,aAAa,MAAA,CAAO,UAAA;AAAA,IACpB,eAAe,MAAA,CAAO,YAAA;AAAA,IACtB,cAAA,EAAgB,YAAA,CAAa,MAAA,CAAO,eAAe,CAAA;AAAA,IACnD,YAAA,EAAc,YAAA,CAAa,MAAA,CAAO,aAAa,CAAA;AAAA,IAC/C,UAAA,EAAY,YAAA,CAAa,MAAA,CAAO,WAAW,CAAA;AAAA,IAC3C,iBAAA,EAAmB,cAAA,CAAe,MAAA,CAAO,YAAY,CAAA;AAAA,IACrD,UAAA,EAAY,YAAA,CAAa,MAAA,CAAO,SAAS,CAAA;AAAA,IACzC,qBAAA,EAAuB,cAAA,CAAe,MAAA,CAAO,gBAAgB,CAAA;AAAA,IAC7D,kBAAkB,MAAA,CAAO;AAAA,GAC3B;AACF;AAKO,SAAS,0BAA0B,MAAA,EAuBjB;AACvB,EAAA,OAAO;AAAA,IACL,cAAc,MAAA,CAAO,WAAA;AAAA,IACrB,cAAc,MAAA,CAAO,WAAA;AAAA,IACrB,gBAAgB,MAAA,CAAO,aAAA;AAAA,IACvB,cAAc,MAAA,CAAO,WAAA;AAAA,IACrB,OAAO,MAAA,CAAO,KAAA;AAAA,IACd,YAAY,MAAA,CAAO,SAAA;AAAA,IACnB,qBAAqB,IAAI,KAAA,CAAM,sBAAsB,CAAA,CAAE,KAAK,CAAC,CAAA;AAAA,IAC7D,oBAAoB,IAAI,KAAA,CAAM,sBAAsB,CAAA,CAAE,KAAK,CAAC,CAAA;AAAA,IAC5D,mBAAmB,IAAI,KAAA,CAAM,oBAAoB,CAAA,CAAE,KAAK,CAAC,CAAA;AAAA,IACzD,kBAAkB,IAAI,KAAA,CAAM,oBAAoB,CAAA,CAAE,KAAK,CAAC,CAAA;AAAA,IACxD,gBAAgB,MAAA,CAAO,aAAA;AAAA,IACvB,oBAAoB,MAAA,CAAO,gBAAA;AAAA,IAC3B,kBAAkB,MAAA,CAAO,eAAA;AAAA,IACzB,gBAAgB,MAAA,CAAO,aAAA;AAAA,IACvB,gBAAgB,MAAA,CAAO,aAAA;AAAA,IACvB,oBAAoB,MAAA,CAAO,gBAAA;AAAA,IAC3B,kBAAkB,MAAA,CAAO,eAAA;AAAA,IACzB,gBAAgB,MAAA,CAAO,aAAA;AAAA,IACvB,aAAa,MAAA,CAAO,UAAA;AAAA,IACpB,eAAe,MAAA,CAAO,YAAA;AAAA,IACtB,cAAA,EAAgB,YAAA,CAAa,MAAA,CAAO,eAAe,CAAA;AAAA,IACnD,YAAA,EAAc,YAAA,CAAa,MAAA,CAAO,aAAa,CAAA;AAAA,IAC/C,iBAAA,EAAmB,cAAA,CAAe,MAAA,CAAO,YAAY,CAAA;AAAA,IACrD,yBAAyB,MAAA,CAAO,oBAAA;AAAA,IAChC,yBAAyB,MAAA,CAAO;AAAA,GAClC;AACF","file":"chunk-XBNYAAMU.js","sourcesContent":["/**\n * STARK Utilities — Amount scaling, witness building, Fiat-Shamir\n *\n * These functions must produce identical outputs to the Rust Stwo prover\n * (stwo-prover/src/) and the Solidity verifier.\n *\n * M31 field: p = 2^31 - 1 = 2,147,483,647\n * Amount precision: 0.001 tokens (1e15 wei scale factor)\n */\n\nimport type { Address, Hex } from 'viem'\nimport { keccak256, encodePacked, pad, numberToHex } from 'viem'\nimport { M31_P, SECRET_LIMBS } from './keccak-m31.js'\n\n// ============================================================================\n// Constants\n// ============================================================================\n\n/** Matches Solidity STARK_AMOUNT_SCALE = 1e15 */\nexport const STARK_AMOUNT_SCALE = 10n ** 15n\n\n/** State tree depth (Merkle tree for commitments) */\nexport const STARK_STATE_TREE_DEPTH = 32\n\n/** ASP tree depth */\nexport const STARK_ASP_TREE_DEPTH = 20\n\n// ============================================================================\n// Amount Scaling\n// ============================================================================\n\n/** Check if a wei amount is STARK-scale aligned and fits in M31. */\nexport function isStarkAligned(amount: bigint): boolean {\n if (amount <= 0n) return false\n const scaled = amount / STARK_AMOUNT_SCALE\n return scaled * STARK_AMOUNT_SCALE === amount && scaled < M31_P\n}\n\n/**\n * Scale a wei amount down for the STARK circuit.\n * Precision: 0.001 tokens (1e15 wei). Max: ~2.1M tokens.\n *\n * @returns The scaled amount as a number (fits in M31)\n * @throws If not aligned to STARK_AMOUNT_SCALE or exceeds M31\n */\nexport function scaleAmountForStark(weiAmount: bigint): number {\n const scaled = weiAmount / STARK_AMOUNT_SCALE\n if (scaled * STARK_AMOUNT_SCALE !== weiAmount) {\n throw new Error(`Amount ${weiAmount} not aligned to STARK scale (${STARK_AMOUNT_SCALE})`)\n }\n if (scaled >= M31_P) {\n throw new Error(`Scaled amount ${scaled} exceeds M31 max (${M31_P})`)\n }\n return Number(scaled)\n}\n\n/** Truncate a bigint to fit in M31 (modular reduction). */\nexport function truncateToM31(value: bigint): number {\n return Number(value % M31_P)\n}\n\n// ============================================================================\n// Field Conversions\n// ============================================================================\n\n/** Convert an Ethereum address to an M31 field element (truncated). */\nexport function addressToM31(addr: Address): number {\n return Number(BigInt(addr) % M31_P)\n}\n\n/**\n * Split a 254-bit spending secret into 8 M31 limbs (248 bits of entropy).\n *\n * Each limb holds 31 bits (reduced mod M31_P). The secret is split\n * little-endian: limb[0] = lowest 31 bits, limb[7] = highest bits.\n *\n * This matches the Rust prover's expectation of `[M31; 8]` for owner_secret.\n */\nexport function splitSecretToM31Limbs(secret: bigint): number[] {\n const limbs: number[] = []\n let remaining = secret\n for (let i = 0; i < SECRET_LIMBS; i++) {\n limbs.push(Number(remaining % M31_P))\n remaining = remaining / M31_P\n }\n return limbs\n}\n\n/**\n * Pack an M31 digest (4 M31 elements) into a uint128 for Solidity.\n * Each element occupies 32 bits (little-endian packing).\n */\nexport function packM31Digest(digest: [number, number, number, number]): bigint {\n return BigInt(digest[0])\n | (BigInt(digest[1]) << 32n)\n | (BigInt(digest[2]) << 64n)\n | (BigInt(digest[3]) << 96n)\n}\n\n// ============================================================================\n// Fiat-Shamir Public Input Seeds\n// ============================================================================\n\n/**\n * Compute the Fiat-Shamir public inputs seed for a STARK withdrawal.\n * Must produce the same hash as Solidity and Rust.\n */\nexport function computeWithdrawPublicInputsSeed(params: {\n nullifier: Hex\n stateRoot: bigint\n aspRoot: bigint\n aspId: bigint\n token: Address\n amount: bigint\n recipient: Address\n isRagequit: boolean\n}): Hex {\n return keccak256(\n encodePacked(\n ['bytes32', 'uint256', 'uint256', 'uint256', 'address', 'uint256', 'address', 'bool'],\n [\n params.nullifier,\n params.stateRoot,\n params.aspRoot,\n params.aspId,\n params.token,\n params.amount,\n params.recipient,\n params.isRagequit,\n ],\n ),\n )\n}\n\n/**\n * Compute the Fiat-Shamir public inputs seed for a STARK transfer.\n * Must produce the same hash as Solidity and Rust.\n */\nexport function computeTransferPublicInputsSeed(params: {\n nullifier: Hex\n stateRoot: bigint\n aspRoot: bigint\n token: Address\n outputCommitment1: Hex\n outputCommitment2: Hex\n}): Hex {\n return keccak256(\n encodePacked(\n ['bytes32', 'uint256', 'uint256', 'address', 'bytes32', 'bytes32'],\n [\n params.nullifier,\n params.stateRoot,\n params.aspRoot,\n params.token,\n params.outputCommitment1,\n params.outputCommitment2,\n ],\n ),\n )\n}\n\n// ============================================================================\n// Witness Types\n// ============================================================================\n\n/**\n * Witness inputs for the STARK withdrawal prover.\n * All numeric values are u32 (must fit in M31 field, i.e. < 2^31 - 1).\n * Hex string fields are for Fiat-Shamir seed binding.\n */\nexport interface StarkWithdrawWitness {\n owner_secret: number[]\n input_amount: number\n input_blinding: number\n input_origin: number\n token: number\n leaf_index: number\n state_path_elements: number[]\n state_path_indices: number[]\n asp_path_elements: number[]\n asp_path_indices: number[]\n withdraw_amount: number\n change_amount: number\n change_blinding: number\n recipient: number\n is_ragequit: number\n // Ethereum-native hex values for Fiat-Shamir seed binding\n nullifier_hex: string\n state_root_hex: string\n asp_root_hex: string\n asp_id_hex: string\n token_address_hex: string\n amount_hex: string\n recipient_address_hex: string\n is_ragequit_bool: boolean\n}\n\n/**\n * Witness inputs for the STARK transfer prover (1-in-2-out).\n * All numeric values are u32 (must fit in M31 field).\n */\nexport interface StarkTransferWitness {\n owner_secret: number[]\n input_amount: number\n input_blinding: number\n input_origin: number\n token: number\n leaf_index: number\n state_path_elements: number[]\n state_path_indices: number[]\n asp_path_elements: number[]\n asp_path_indices: number[]\n // Output 1\n output1_amount: number\n output1_owner_hash: [number, number, number, number]\n output1_blinding: number\n output1_origin: number\n // Output 2\n output2_amount: number\n output2_owner_hash: [number, number, number, number]\n output2_blinding: number\n output2_origin: number\n // Ragequit flag\n is_ragequit: number\n // Ethereum-native hex values for Fiat-Shamir seed binding\n nullifier_hex: string\n state_root_hex: string\n asp_root_hex: string\n token_address_hex: string\n output_commitment_1_hex: string\n output_commitment_2_hex: string\n}\n\n// ============================================================================\n// Witness Builders\n// ============================================================================\n\nfunction toBytes32Hex(value: bigint | Hex): string {\n if (typeof value === 'bigint') {\n return pad(numberToHex(value), { size: 32 })\n }\n return value as string\n}\n\nfunction toAddress20Hex(addr: Address): string {\n return addr.toLowerCase()\n}\n\n/**\n * Build a complete STARK withdrawal witness from note data.\n */\nexport function buildStarkWithdrawWitness(params: {\n ownerSecret: number[]\n inputAmount: number\n inputBlinding: number\n inputOrigin: number\n token: number\n leafIndex: number\n withdrawAmount: number\n changeAmount: number\n changeBlinding: number\n recipient: number\n isRagequit: number\n // Full Ethereum values for seed binding\n nullifierHex: Hex\n stateRootBigInt: bigint\n aspRootBigInt: bigint\n aspIdBigInt: bigint\n tokenAddress: Address\n amountWei: bigint\n recipientAddress: Address\n isRagequitBool: boolean\n}): StarkWithdrawWitness {\n return {\n owner_secret: params.ownerSecret,\n input_amount: params.inputAmount,\n input_blinding: params.inputBlinding,\n input_origin: params.inputOrigin,\n token: params.token,\n leaf_index: params.leafIndex,\n state_path_elements: new Array(STARK_STATE_TREE_DEPTH).fill(0),\n state_path_indices: new Array(STARK_STATE_TREE_DEPTH).fill(0),\n asp_path_elements: new Array(STARK_ASP_TREE_DEPTH).fill(0),\n asp_path_indices: new Array(STARK_ASP_TREE_DEPTH).fill(0),\n withdraw_amount: params.withdrawAmount,\n change_amount: params.changeAmount,\n change_blinding: params.changeBlinding,\n recipient: params.recipient,\n is_ragequit: params.isRagequit,\n nullifier_hex: params.nullifierHex,\n state_root_hex: toBytes32Hex(params.stateRootBigInt),\n asp_root_hex: toBytes32Hex(params.aspRootBigInt),\n asp_id_hex: toBytes32Hex(params.aspIdBigInt),\n token_address_hex: toAddress20Hex(params.tokenAddress),\n amount_hex: toBytes32Hex(params.amountWei),\n recipient_address_hex: toAddress20Hex(params.recipientAddress),\n is_ragequit_bool: params.isRagequitBool,\n }\n}\n\n/**\n * Build a complete STARK transfer witness (1-in-2-out).\n */\nexport function buildStarkTransferWitness(params: {\n ownerSecret: number[]\n inputAmount: number\n inputBlinding: number\n inputOrigin: number\n token: number\n leafIndex: number\n output1Amount: number\n output1OwnerHash: [number, number, number, number]\n output1Blinding: number\n output1Origin: number\n output2Amount: number\n output2OwnerHash: [number, number, number, number]\n output2Blinding: number\n output2Origin: number\n isRagequit: number\n // Full Ethereum values for seed binding\n nullifierHex: Hex\n stateRootBigInt: bigint\n aspRootBigInt: bigint\n tokenAddress: Address\n outputCommitment1Hex: Hex\n outputCommitment2Hex: Hex\n}): StarkTransferWitness {\n return {\n owner_secret: params.ownerSecret,\n input_amount: params.inputAmount,\n input_blinding: params.inputBlinding,\n input_origin: params.inputOrigin,\n token: params.token,\n leaf_index: params.leafIndex,\n state_path_elements: new Array(STARK_STATE_TREE_DEPTH).fill(0),\n state_path_indices: new Array(STARK_STATE_TREE_DEPTH).fill(0),\n asp_path_elements: new Array(STARK_ASP_TREE_DEPTH).fill(0),\n asp_path_indices: new Array(STARK_ASP_TREE_DEPTH).fill(0),\n output1_amount: params.output1Amount,\n output1_owner_hash: params.output1OwnerHash,\n output1_blinding: params.output1Blinding,\n output1_origin: params.output1Origin,\n output2_amount: params.output2Amount,\n output2_owner_hash: params.output2OwnerHash,\n output2_blinding: params.output2Blinding,\n output2_origin: params.output2Origin,\n is_ragequit: params.isRagequit,\n nullifier_hex: params.nullifierHex,\n state_root_hex: toBytes32Hex(params.stateRootBigInt),\n asp_root_hex: toBytes32Hex(params.aspRootBigInt),\n token_address_hex: toAddress20Hex(params.tokenAddress),\n output_commitment_1_hex: params.outputCommitment1Hex,\n output_commitment_2_hex: params.outputCommitment2Hex,\n }\n}\n"]}
1
+ {"version":3,"sources":["../src/utils/stark.ts"],"names":[],"mappings":"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","file":"chunk-7T4CUE6E.js","sourcesContent":["/**\n * STARK Utilities — Amount scaling, witness building, Fiat-Shamir\n *\n * These functions must produce identical outputs to the Rust Stwo prover\n * (stwo-prover/src/) and the Solidity verifier.\n *\n * M31 field: p = 2^31 - 1 = 2,147,483,647\n * Amount precision: 0.001 tokens (1e15 wei scale factor)\n */\n\nimport type { Address, Hex } from 'viem'\nimport { keccak256, encodePacked, pad, numberToHex } from 'viem'\nimport { M31_P, SECRET_LIMBS } from './keccak-m31.js'\n\n// ============================================================================\n// Constants\n// ============================================================================\n\n/** Matches Solidity STARK_AMOUNT_SCALE = 1e15 */\nexport const STARK_AMOUNT_SCALE = 10n ** 15n\n\n/** State tree depth (Merkle tree for commitments) */\nexport const STARK_STATE_TREE_DEPTH = 32\n\n/** ASP tree depth */\nexport const STARK_ASP_TREE_DEPTH = 20\n\n// ============================================================================\n// Amount Scaling\n// ============================================================================\n\n/** Check if a wei amount is STARK-scale aligned and fits in M31. */\nexport function isStarkAligned(amount: bigint): boolean {\n if (amount <= 0n) return false\n const scaled = amount / STARK_AMOUNT_SCALE\n return scaled * STARK_AMOUNT_SCALE === amount && scaled < M31_P\n}\n\n/**\n * Scale a wei amount down for the STARK circuit.\n * Precision: 0.001 tokens (1e15 wei). Max: ~2.1M tokens.\n *\n * @returns The scaled amount as a number (fits in M31)\n * @throws If not aligned to STARK_AMOUNT_SCALE or exceeds M31\n */\nexport function scaleAmountForStark(weiAmount: bigint): number {\n const scaled = weiAmount / STARK_AMOUNT_SCALE\n if (scaled * STARK_AMOUNT_SCALE !== weiAmount) {\n throw new Error(`Amount ${weiAmount} not aligned to STARK scale (${STARK_AMOUNT_SCALE})`)\n }\n if (scaled >= M31_P) {\n throw new Error(`Scaled amount ${scaled} exceeds M31 max (${M31_P})`)\n }\n return Number(scaled)\n}\n\n/** Truncate a bigint to fit in M31 (modular reduction). */\nexport function truncateToM31(value: bigint): number {\n return Number(value % M31_P)\n}\n\n// ============================================================================\n// Field Conversions\n// ============================================================================\n\n/** Convert an Ethereum address to an M31 field element (truncated). */\nexport function addressToM31(addr: Address): number {\n return Number(BigInt(addr) % M31_P)\n}\n\n/**\n * Split a 254-bit spending secret into 8 M31 limbs (248 bits of entropy).\n *\n * Each limb holds 31 bits (reduced mod M31_P). The secret is split\n * little-endian: limb[0] = lowest 31 bits, limb[7] = highest bits.\n *\n * This matches the Rust prover's expectation of `[M31; 8]` for owner_secret.\n */\nexport function splitSecretToM31Limbs(secret: bigint): number[] {\n const limbs: number[] = []\n let remaining = secret\n for (let i = 0; i < SECRET_LIMBS; i++) {\n limbs.push(Number(remaining % M31_P))\n remaining = remaining / M31_P\n }\n return limbs\n}\n\n/**\n * Pack an M31 digest (4 M31 elements) into a uint128 for Solidity.\n * Each element occupies 32 bits (little-endian packing).\n */\nexport function packM31Digest(digest: [number, number, number, number]): bigint {\n return BigInt(digest[0])\n | (BigInt(digest[1]) << 32n)\n | (BigInt(digest[2]) << 64n)\n | (BigInt(digest[3]) << 96n)\n}\n\n// ============================================================================\n// Fiat-Shamir Public Input Seeds\n// ============================================================================\n\n/**\n * Compute the Fiat-Shamir public inputs seed for a STARK withdrawal.\n * Must produce the same hash as Solidity and Rust.\n */\nexport function computeWithdrawPublicInputsSeed(params: {\n nullifier: Hex\n stateRoot: bigint\n aspRoot: bigint\n aspId: bigint\n token: Address\n amount: bigint\n recipient: Address\n isRagequit: boolean\n}): Hex {\n return keccak256(\n encodePacked(\n ['bytes32', 'uint256', 'uint256', 'uint256', 'address', 'uint256', 'address', 'bool'],\n [\n params.nullifier,\n params.stateRoot,\n params.aspRoot,\n params.aspId,\n params.token,\n params.amount,\n params.recipient,\n params.isRagequit,\n ],\n ),\n )\n}\n\n/**\n * Compute the Fiat-Shamir public inputs seed for a STARK transfer.\n * Must produce the same hash as Solidity and Rust.\n */\nexport function computeTransferPublicInputsSeed(params: {\n nullifier: Hex\n stateRoot: bigint\n aspRoot: bigint\n token: Address\n outputCommitment1: Hex\n outputCommitment2: Hex\n}): Hex {\n return keccak256(\n encodePacked(\n ['bytes32', 'uint256', 'uint256', 'address', 'bytes32', 'bytes32'],\n [\n params.nullifier,\n params.stateRoot,\n params.aspRoot,\n params.token,\n params.outputCommitment1,\n params.outputCommitment2,\n ],\n ),\n )\n}\n\n// ============================================================================\n// Witness Types\n// ============================================================================\n\n/**\n * Witness inputs for the STARK withdrawal prover.\n * All numeric values are u32 (must fit in M31 field, i.e. < 2^31 - 1).\n * Hex string fields are for Fiat-Shamir seed binding.\n */\nexport interface StarkWithdrawWitness {\n owner_secret: number[]\n input_amount: number\n input_blinding: number\n input_origin: number\n token: number\n leaf_index: number\n state_path_elements: number[]\n state_path_indices: number[]\n asp_path_elements: number[]\n asp_path_indices: number[]\n withdraw_amount: number\n change_amount: number\n change_blinding: number\n recipient: number\n is_ragequit: number\n // Ethereum-native hex values for Fiat-Shamir seed binding\n nullifier_hex: string\n state_root_hex: string\n asp_root_hex: string\n asp_id_hex: string\n token_address_hex: string\n amount_hex: string\n recipient_address_hex: string\n is_ragequit_bool: boolean\n}\n\n/**\n * Witness inputs for the STARK transfer prover (1-in-2-out).\n * All numeric values are u32 (must fit in M31 field).\n */\nexport interface StarkTransferWitness {\n owner_secret: number[]\n input_amount: number\n input_blinding: number\n input_origin: number\n token: number\n leaf_index: number\n state_path_elements: number[]\n state_path_indices: number[]\n asp_path_elements: number[]\n asp_path_indices: number[]\n // Output 1\n output1_amount: number\n output1_owner_hash: [number, number, number, number]\n output1_blinding: number\n output1_origin: number\n // Output 2\n output2_amount: number\n output2_owner_hash: [number, number, number, number]\n output2_blinding: number\n output2_origin: number\n // Ragequit flag\n is_ragequit: number\n // Ethereum-native hex values for Fiat-Shamir seed binding\n nullifier_hex: string\n state_root_hex: string\n asp_root_hex: string\n token_address_hex: string\n output_commitment_1_hex: string\n output_commitment_2_hex: string\n}\n\n// ============================================================================\n// Witness Builders\n// ============================================================================\n\nfunction toBytes32Hex(value: bigint | Hex): string {\n if (typeof value === 'bigint') {\n return pad(numberToHex(value), { size: 32 })\n }\n return value as string\n}\n\nfunction toAddress20Hex(addr: Address): string {\n return addr.toLowerCase()\n}\n\n/**\n * Build a complete STARK withdrawal witness from note data.\n */\nexport function buildStarkWithdrawWitness(params: {\n ownerSecret: number[]\n inputAmount: number\n inputBlinding: number\n inputOrigin: number\n token: number\n leafIndex: number\n withdrawAmount: number\n changeAmount: number\n changeBlinding: number\n recipient: number\n isRagequit: number\n // Full Ethereum values for seed binding\n nullifierHex: Hex\n stateRootBigInt: bigint\n aspRootBigInt: bigint\n aspIdBigInt: bigint\n tokenAddress: Address\n amountWei: bigint\n recipientAddress: Address\n isRagequitBool: boolean\n}): StarkWithdrawWitness {\n return {\n owner_secret: params.ownerSecret,\n input_amount: params.inputAmount,\n input_blinding: params.inputBlinding,\n input_origin: params.inputOrigin,\n token: params.token,\n leaf_index: params.leafIndex,\n state_path_elements: new Array(STARK_STATE_TREE_DEPTH).fill(0),\n state_path_indices: new Array(STARK_STATE_TREE_DEPTH).fill(0),\n asp_path_elements: new Array(STARK_ASP_TREE_DEPTH).fill(0),\n asp_path_indices: new Array(STARK_ASP_TREE_DEPTH).fill(0),\n withdraw_amount: params.withdrawAmount,\n change_amount: params.changeAmount,\n change_blinding: params.changeBlinding,\n recipient: params.recipient,\n is_ragequit: params.isRagequit,\n nullifier_hex: params.nullifierHex,\n state_root_hex: toBytes32Hex(params.stateRootBigInt),\n asp_root_hex: toBytes32Hex(params.aspRootBigInt),\n asp_id_hex: toBytes32Hex(params.aspIdBigInt),\n token_address_hex: toAddress20Hex(params.tokenAddress),\n amount_hex: toBytes32Hex(params.amountWei),\n recipient_address_hex: toAddress20Hex(params.recipientAddress),\n is_ragequit_bool: params.isRagequitBool,\n }\n}\n\n/**\n * Build a complete STARK transfer witness (1-in-2-out).\n */\nexport function buildStarkTransferWitness(params: {\n ownerSecret: number[]\n inputAmount: number\n inputBlinding: number\n inputOrigin: number\n token: number\n leafIndex: number\n output1Amount: number\n output1OwnerHash: [number, number, number, number]\n output1Blinding: number\n output1Origin: number\n output2Amount: number\n output2OwnerHash: [number, number, number, number]\n output2Blinding: number\n output2Origin: number\n isRagequit: number\n // Full Ethereum values for seed binding\n nullifierHex: Hex\n stateRootBigInt: bigint\n aspRootBigInt: bigint\n tokenAddress: Address\n outputCommitment1Hex: Hex\n outputCommitment2Hex: Hex\n}): StarkTransferWitness {\n return {\n owner_secret: params.ownerSecret,\n input_amount: params.inputAmount,\n input_blinding: params.inputBlinding,\n input_origin: params.inputOrigin,\n token: params.token,\n leaf_index: params.leafIndex,\n state_path_elements: new Array(STARK_STATE_TREE_DEPTH).fill(0),\n state_path_indices: new Array(STARK_STATE_TREE_DEPTH).fill(0),\n asp_path_elements: new Array(STARK_ASP_TREE_DEPTH).fill(0),\n asp_path_indices: new Array(STARK_ASP_TREE_DEPTH).fill(0),\n output1_amount: params.output1Amount,\n output1_owner_hash: params.output1OwnerHash,\n output1_blinding: params.output1Blinding,\n output1_origin: params.output1Origin,\n output2_amount: params.output2Amount,\n output2_owner_hash: params.output2OwnerHash,\n output2_blinding: params.output2Blinding,\n output2_origin: params.output2Origin,\n is_ragequit: params.isRagequit,\n nullifier_hex: params.nullifierHex,\n state_root_hex: toBytes32Hex(params.stateRootBigInt),\n asp_root_hex: toBytes32Hex(params.aspRootBigInt),\n token_address_hex: toAddress20Hex(params.tokenAddress),\n output_commitment_1_hex: params.outputCommitment1Hex,\n output_commitment_2_hex: params.outputCommitment2Hex,\n }\n}\n"]}
@@ -1,4 +1,4 @@
1
- import { init_stealth } from './chunk-QKI4QWLT.js';
1
+ import { init_stealth } from './chunk-RNUG3EFC.js';
2
2
 
3
3
  // src/core/client.ts
4
4
  function createUPPClient(_config) {
@@ -39,5 +39,5 @@ function generateRandomBlinding() {
39
39
  init_stealth();
40
40
 
41
41
  export { NOTE_VERSION, createNote, createUPPClient, decryptNote, encryptNote };
42
- //# sourceMappingURL=chunk-OD2SDC4L.js.map
43
- //# sourceMappingURL=chunk-OD2SDC4L.js.map
42
+ //# sourceMappingURL=chunk-CEJN5ZE5.js.map
43
+ //# sourceMappingURL=chunk-CEJN5ZE5.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/core/client.ts","../src/core/types.ts","../src/core/note.ts","../src/core/index.ts"],"names":[],"mappings":";;;AAoFO,SAAS,gBAAgB,OAAA,EAAqC;AAEnE,EAAA,MAAM,IAAI,MAAM,iBAAiB,CAAA;AACnC;;;AC9EO,IAAM,YAAA,GAAe;;;ACiCrB,SAAS,WAAW,MAAA,EAAgC;AACzD,EAAA,MAAM,EAAE,MAAA,EAAQ,KAAA,EAAO,QAAQ,MAAA,EAAQ,IAAA,EAAM,UAAS,GAAI,MAAA;AAG1D,EAAA,MAAM,YAAA,GAAe,YAAY,sBAAA,EAAuB;AAExD,EAAA,OAAO;AAAA,IACL,OAAA,EAAS,YAAA;AAAA,IACT,MAAA;AAAA,IACA,QAAA,EAAU,YAAA;AAAA,IACV,MAAA;AAAA,IACA,MAAA;AAAA,IACA,KAAA;AAAA,IACA,IAAA;AAAA,IACA,WAAW,IAAA,CAAK,KAAA,CAAM,IAAA,CAAK,GAAA,KAAQ,GAAI;AAAA,GACzC;AACF;AASO,SAAS,WAAA,CAAY,OAAa,aAAA,EAA0C;AAEjF,EAAA,MAAM,IAAI,MAAM,iBAAiB,CAAA;AACnC;AASO,SAAS,WAAA,CAAY,YAA2B,aAAA,EAAwC;AAE7F,EAAA,MAAM,IAAI,MAAM,iBAAiB,CAAA;AACnC;AAyBA,SAAS,sBAAA,GAAiC;AAExC,EAAA,MAAM,KAAA,GAAQ,IAAI,UAAA,CAAW,EAAE,CAAA;AAC/B,EAAA,MAAA,CAAO,gBAAgB,KAAK,CAAA;AAC5B,EAAA,OAAO,OAAO,IAAA,GAAO,KAAA,CAAM,KAAK,KAAK,CAAA,CAAE,IAAI,CAAA,CAAA,KAAK,CAAA,CAAE,SAAS,EAAE,CAAA,CAAE,SAAS,CAAA,EAAG,GAAG,CAAC,CAAA,CAAE,IAAA,CAAK,EAAE,CAAC,CAAA;AAC3F;;;ACtGA,YAAA,EAAA","file":"chunk-OD2SDC4L.js","sourcesContent":["/**\n * Main UPP Client\n *\n * Provides high-level API for interacting with the Universal Private Pool.\n */\n\nimport type { Address, PublicClient, WalletClient } from 'viem'\nimport type {\n ShieldParams,\n TransferParams,\n MergeParams,\n WithdrawParams,\n Note,\n} from './types.js'\n\n/**\n * UPP Client configuration\n */\nexport interface UPPClientConfig {\n /** Viem public client for reading chain state */\n publicClient: PublicClient\n /** Viem wallet client for sending transactions */\n walletClient: WalletClient\n /** Universal Private Pool contract address */\n poolAddress: Address\n /** ASP Registry Hub contract address */\n aspHubAddress: Address\n /** Chain ID (optional, derived from clients if not provided) */\n chainId?: number\n}\n\n/**\n * UPP Client interface\n */\nexport interface UPPClient {\n /** Shield tokens into the private pool */\n shield(params: ShieldParams): Promise<{ commitment: `0x${string}`; note: Note }>\n\n /** Transfer tokens privately */\n transfer(params: TransferParams): Promise<{ nullifier: `0x${string}`; changeNote?: Note }>\n\n /** Merge multiple notes into one */\n merge(params: MergeParams): Promise<{ commitment: `0x${string}`; note: Note }>\n\n /** Withdraw tokens from the private pool */\n withdraw(params: WithdrawParams): Promise<{ txHash: `0x${string}` }>\n\n /** Scan for notes belonging to a viewing key */\n scanNotes(viewingKey: `0x${string}`): Promise<Note[]>\n\n /** Get the current state root */\n getStateRoot(): Promise<bigint>\n\n /** Check if a nullifier has been spent */\n isNullifierSpent(nullifier: `0x${string}`): Promise<boolean>\n}\n\n/**\n * Create a UPP client instance\n *\n * @example\n * ```ts\n * import { createUPPClient } from '@upp/sdk'\n * import { createPublicClient, createWalletClient, http } from 'viem'\n * import { sepolia } from 'viem/chains'\n *\n * const publicClient = createPublicClient({\n * chain: sepolia,\n * transport: http(),\n * })\n *\n * const walletClient = createWalletClient({\n * chain: sepolia,\n * transport: http(),\n * })\n *\n * const client = createUPPClient({\n * publicClient,\n * walletClient,\n * poolAddress: '0x...',\n * aspHubAddress: '0x...',\n * })\n * ```\n */\nexport function createUPPClient(_config: UPPClientConfig): UPPClient {\n // TODO: Implement client\n throw new Error('Not implemented')\n}\n","/**\n * Core type definitions for UPP SDK\n */\n\nimport type { Address, Hex } from 'viem'\n\n/**\n * Note version - increment when note structure changes\n */\nexport const NOTE_VERSION = 5\n\n/**\n * A private note in the Universal Private Pool\n */\nexport interface Note {\n /** Note format version */\n version: number\n /** Token amount (in wei) */\n amount: bigint\n /** Random blinding factor */\n blinding: bigint\n /** Current origin - who is responsible for these funds (updated on merge) */\n origin: Address\n /** Sender - who sent this specific note (for payment attribution) */\n sender: Address\n /** ERC20 token address */\n token: Address\n /** Optional memo/message */\n memo?: string\n /** Timestamp when note was created */\n timestamp?: number\n}\n\n/**\n * Encrypted note data stored on-chain (post-quantum, hash-based)\n */\nexport interface EncryptedNote {\n /** AES-GCM encrypted note data */\n ciphertext: Hex\n /** AES-GCM nonce */\n nonce: Hex\n}\n\n/**\n * Stealth meta-address (hash-based, post-quantum)\n * Published once, used by senders to encrypt notes to the recipient\n */\nexport interface StealthMetaAddress {\n /** Owner hash = Poseidon(spendingSecret) */\n ownerHash: bigint\n /** Viewing hash = Poseidon(viewingSecret) */\n viewingHash: bigint\n}\n\n/**\n * One-time address for a specific transaction (simplified for hash-based system)\n */\nexport interface StealthAddress {\n /** Owner hash for this note */\n ownerHash: bigint\n /** Search tag for efficient scanning */\n searchTag?: bigint\n}\n\n/**\n * On-chain merge record for audit trail\n */\nexport interface MergeRecord {\n /** Output commitment (the merged note) */\n outputCommitment: Hex\n /** First input nullifier */\n nullifier1: Hex\n /** Second input nullifier */\n nullifier2: Hex\n /** Who performed the merge (new origin) */\n merger: Address\n /** Token that was merged */\n token: Address\n /** Block timestamp */\n timestamp: number\n}\n\n/**\n * ASP (Association Set Provider) root\n */\nexport interface ASPRoot {\n /** Merkle root of approved addresses */\n root: bigint\n /** IPFS hash for off-chain data */\n ipfsHash: Hex\n /** When this root was published */\n timestamp: number\n /** Number of addresses in the set */\n leafCount: number\n}\n\n/**\n * Shield operation parameters\n */\nexport interface ShieldParams {\n /** ERC20 token to shield */\n token: Address\n /** Amount to shield (in wei) */\n amount: bigint\n /** Optional: recipient owner hash (defaults to self) */\n recipientOwnerHash?: bigint\n /** Optional: memo to include in note */\n memo?: string\n}\n\n/**\n * Transfer operation parameters\n */\nexport interface TransferParams {\n /** Note to spend */\n note: Note\n /** Recipient stealth address */\n recipient: StealthAddress\n /** Amount to send (remainder goes back to sender as change) */\n amount: bigint\n /** Optional: memo to include */\n memo?: string\n}\n\n/**\n * Merge operation parameters\n */\nexport interface MergeParams {\n /** Notes to merge (must be same token) */\n notes: [Note, Note]\n /** Optional: memo for the merged note */\n memo?: string\n}\n\n/**\n * Withdraw operation parameters\n */\nexport interface WithdrawParams {\n /** Note to withdraw */\n note: Note\n /** Amount to withdraw */\n amount: bigint\n /** Recipient address for the tokens */\n recipient: Address\n /** ASP ID to use for compliance check */\n aspId?: number\n /** Use ragequit (origin withdrawing own funds) */\n ragequit?: boolean\n}\n\n/**\n * Proof for ZK operations\n */\nexport interface Proof {\n /** Proof points */\n proof: {\n pi_a: [string, string]\n pi_b: [[string, string], [string, string]]\n pi_c: [string, string]\n }\n /** Public signals */\n publicSignals: string[]\n}\n\n/**\n * Note commitment (hash)\n */\nexport type Commitment = Hex\n\n/**\n * Nullifier (spent note identifier)\n */\nexport type Nullifier = Hex\n\n// =========================================================================\n// STARK Note Types (M31/Keccak-based, post-quantum)\n// =========================================================================\n\nimport type { M31Digest } from '../utils/keccak-m31.js'\n\n// STARK_AMOUNT_SCALE moved to utils/stark.ts\nexport { STARK_AMOUNT_SCALE } from '../utils/stark.js'\n\n/**\n * A private STARK note in the Universal Private Pool.\n *\n * All field values are M31 elements (< 2^31 - 1).\n * Commitment = keccak_m31(amount, ownerHash[0..4], blinding, origin, token).\n */\nexport interface StarkNote {\n /** Amount in STARK units (actual wei = amount * STARK_AMOUNT_SCALE) */\n amount: bigint\n /** Owner hash = keccak_m31(starkSecret) — 4 M31 elements */\n ownerHash: M31Digest\n /** Random blinding factor (M31) */\n blinding: bigint\n /** Origin address encoded as M31 (lower 31 bits of address) */\n origin: bigint\n /** Token address encoded as M31 (lower 31 bits of address) */\n token: bigint\n /** The leaf index in the STARK Keccak Merkle tree (set after shielding) */\n leafIndex?: number\n /** The commitment digest (set after computation) */\n commitment?: M31Digest\n /** Optional memo */\n memo?: string\n /** Timestamp when note was created */\n timestamp?: number\n}\n\n/**\n * STARK stealth meta-address (M31/Keccak-based)\n * Published once, used by senders to encrypt notes to the recipient\n */\nexport interface StarkStealthMetaAddress {\n /** Owner hash = keccak_m31(starkSecret) — 4 M31 elements */\n ownerHash: M31Digest\n /** Viewing hash = keccak_m31(starkViewingSecret) — 4 M31 elements */\n viewingHash: M31Digest\n}\n\n/**\n * STARK proof for ZK operations (serialized Circle STARK proof)\n */\nexport interface StarkProof {\n /** Raw serialized Stwo Circle STARK proof bytes */\n proofBytes: Hex\n /** Public inputs seed (keccak256 of public parameters) */\n publicInputsSeed: Hex\n}\n","/**\n * Note management utilities\n *\n * Create, encrypt, and decrypt private notes.\n */\n\nimport type { Address, Hex } from 'viem'\nimport type { Note, EncryptedNote } from './types.js'\nimport { NOTE_VERSION } from './types.js'\n\n/**\n * Parameters for creating a new note\n */\nexport interface CreateNoteParams {\n /** Token amount */\n amount: bigint\n /** ERC20 token address */\n token: Address\n /** Origin address (who is responsible) */\n origin: Address\n /** Sender address */\n sender: Address\n /** Optional memo */\n memo?: string\n /** Optional blinding factor (generated if not provided) */\n blinding?: bigint\n}\n\n/**\n * Create a new private note\n *\n * @example\n * ```ts\n * const note = createNote({\n * amount: 1000n * 10n ** 18n,\n * token: '0x...',\n * origin: '0xMyAddress...',\n * sender: '0xMyAddress...',\n * memo: 'Payment for services',\n * })\n * ```\n */\nexport function createNote(params: CreateNoteParams): Note {\n const { amount, token, origin, sender, memo, blinding } = params\n\n // Generate random blinding factor if not provided\n const noteBlinding = blinding ?? generateRandomBlinding()\n\n return {\n version: NOTE_VERSION,\n amount,\n blinding: noteBlinding,\n origin,\n sender,\n token,\n memo,\n timestamp: Math.floor(Date.now() / 1000),\n }\n}\n\n/**\n * Encrypt a note for a recipient\n *\n * @param note - The note to encrypt\n * @param sharedSecret - ECDH shared secret with recipient\n * @returns Encrypted note data\n */\nexport function encryptNote(_note: Note, _sharedSecret: Uint8Array): EncryptedNote {\n // TODO: Implement AES-GCM encryption\n throw new Error('Not implemented')\n}\n\n/**\n * Decrypt a received note\n *\n * @param encrypted - The encrypted note data\n * @param sharedSecret - ECDH shared secret\n * @returns Decrypted note or null if decryption fails\n */\nexport function decryptNote(_encrypted: EncryptedNote, _sharedSecret: Uint8Array): Note | null {\n // TODO: Implement AES-GCM decryption\n throw new Error('Not implemented')\n}\n\n/**\n * Compute the commitment hash for a note\n *\n * commitment = Poseidon(amount, blinding, origin, token)\n */\nexport function computeCommitment(_note: Note): Hex {\n // TODO: Implement Poseidon hash\n throw new Error('Not implemented')\n}\n\n/**\n * Compute the nullifier for spending a note\n *\n * nullifier = Poseidon(blinding, leafIndex)\n */\nexport function computeNullifier(_note: Note, _leafIndex: bigint): Hex {\n // TODO: Implement nullifier computation\n throw new Error('Not implemented')\n}\n\n/**\n * Generate a random blinding factor\n */\nfunction generateRandomBlinding(): bigint {\n // TODO: Use crypto.getRandomValues for secure randomness\n const bytes = new Uint8Array(31) // 31 bytes to stay in field\n crypto.getRandomValues(bytes)\n return BigInt('0x' + Array.from(bytes).map(b => b.toString(16).padStart(2, '0')).join(''))\n}\n","/**\n * Core UPP SDK functionality\n */\n\nexport { createUPPClient } from './client.js'\nexport type { UPPClient, UPPClientConfig } from './client.js'\n\nexport { createNote, encryptNote, decryptNote } from './note.js'\n\n// Stealth address utilities (post-quantum, hash-based)\nexport {\n STEALTH_ADDRESS_PREFIX,\n ADDRESS_VERSION,\n encodeStealthAddress,\n decodeStealthAddress,\n isValidStealthAddress,\n generateStealthAddress,\n createOneTimeKeys,\n verifyOwnership,\n computeNoteEncryptionKey,\n // STARK stealth addresses (0zs prefix)\n STARK_STEALTH_ADDRESS_PREFIX,\n STARK_ADDRESS_VERSION,\n encodeStarkStealthAddress,\n decodeStarkStealthAddress,\n isValidStarkStealthAddress,\n generateStarkStealthAddress,\n detectAddressType,\n} from './stealth.js'\n\n// Proof generation (UPP circuits)\nexport {\n generateUPPProof,\n formatProofForContract,\n getUPPCircuitArtifacts,\n STATE_TREE_DEPTH,\n ASP_TREE_DEPTH,\n} from './proof.js'\nexport type {\n UPPCircuitType,\n UPPTransferCircuitInputs,\n UPPWithdrawCircuitInputs,\n UPPCircuitInputs,\n CircuitArtifacts,\n ProofResult,\n} from './proof.js'\n\n// Legacy stealth proof exports (deprecated)\nexport {\n generateProof,\n verifyProof,\n generateStealthProof,\n getStealthCircuitArtifacts,\n} from './proof.js'\nexport type {\n CircuitType,\n StealthCircuitType,\n StealthCircuitInputs,\n Stealth1x2CircuitInputs,\n Stealth2x2CircuitInputs,\n} from './proof.js'\n\nexport * from './types.js'\n\n// Swap order book module\nexport {\n computeGiveAmount,\n computeTakeAmount,\n computeRate,\n formatRate,\n computeCancelKeyHash,\n generateCancelSecret,\n filterOrdersByASP,\n filterOrdersByTokenPair,\n isFillerASPAccepted,\n isOrderActive,\n computeTotalBuyAmount,\n computeFillPercentage,\n storeCancelSecret,\n getCancelSecret,\n removeCancelSecret,\n getOwnOrderIds,\n RATE_PRECISION,\n SWAP_EVENTS_ABI,\n SWAP_ORDER_PLACED_EVENT,\n SWAP_ORDER_FILLED_EVENT,\n SWAP_ORDER_CLAIMED_EVENT,\n SWAP_ORDER_CANCELLED_EVENT,\n} from './swap.js'\nexport type {\n SwapOrder,\n SwapOrderParams,\n SwapFillParams,\n SwapOrderEvent,\n SwapFillEvent,\n} from './swap.js'\n\n// Account adapter (pluggable key source + persistence)\nexport { DirectAccountAdapter, StorableAccountAdapter } from './account.js'\nexport type { IAccountAdapter } from './account.js'\n\n// ASP provider (pluggable compliance)\nexport type { IASPProvider, ASPMembershipProof } from './asp-provider.js'\n\n// Note store (single source of truth for note state)\nexport { NoteStore } from './note-store.js'\nexport type { INoteStore, ShieldedNote, NoteStatus, ProofSystem } from './note-store.js'\n\n// ASP (Association Set Provider) module\nexport {\n computeSingleOriginASPRoot,\n generateSingleOriginASPProof,\n verifyASPProof,\n DEMO_ASP_ID,\n DEMO_ASP_NAME,\n createDemoASPRoot,\n // Multi-origin ASP tree\n buildASPTree,\n computeMultiOriginASPRoot,\n generateMultiOriginASPProof,\n generateASPProof,\n} from './asp.js'\nexport type { ASPProof } from './asp.js'\n\n// Transfer module\nexport {\n syncMerkleTree,\n getMerkleProofsForNotes,\n computeNullifier,\n buildUPPTransferCircuitInputs,\n buildTransfer,\n formatOutputForContract,\n} from './transfer.js'\nexport type {\n TransferStage,\n SpendableNote,\n MerkleProofWithNote,\n TransferContext,\n TransferBuildResult,\n NoteWithAmount,\n} from './transfer.js'\n"]}
1
+ {"version":3,"sources":["../src/core/client.ts","../src/core/types.ts","../src/core/note.ts","../src/core/index.ts"],"names":[],"mappings":";;;AAoFO,SAAS,gBAAgB,OAAA,EAAqC;AAEnE,EAAA,MAAM,IAAI,MAAM,iBAAiB,CAAA;AACnC;;;AC9EO,IAAM,YAAA,GAAe;;;ACiCrB,SAAS,WAAW,MAAA,EAAgC;AACzD,EAAA,MAAM,EAAE,MAAA,EAAQ,KAAA,EAAO,QAAQ,MAAA,EAAQ,IAAA,EAAM,UAAS,GAAI,MAAA;AAG1D,EAAA,MAAM,YAAA,GAAe,YAAY,sBAAA,EAAuB;AAExD,EAAA,OAAO;AAAA,IACL,OAAA,EAAS,YAAA;AAAA,IACT,MAAA;AAAA,IACA,QAAA,EAAU,YAAA;AAAA,IACV,MAAA;AAAA,IACA,MAAA;AAAA,IACA,KAAA;AAAA,IACA,IAAA;AAAA,IACA,WAAW,IAAA,CAAK,KAAA,CAAM,IAAA,CAAK,GAAA,KAAQ,GAAI;AAAA,GACzC;AACF;AASO,SAAS,WAAA,CAAY,OAAa,aAAA,EAA0C;AAEjF,EAAA,MAAM,IAAI,MAAM,iBAAiB,CAAA;AACnC;AASO,SAAS,WAAA,CAAY,YAA2B,aAAA,EAAwC;AAE7F,EAAA,MAAM,IAAI,MAAM,iBAAiB,CAAA;AACnC;AAyBA,SAAS,sBAAA,GAAiC;AAExC,EAAA,MAAM,KAAA,GAAQ,IAAI,UAAA,CAAW,EAAE,CAAA;AAC/B,EAAA,MAAA,CAAO,gBAAgB,KAAK,CAAA;AAC5B,EAAA,OAAO,OAAO,IAAA,GAAO,KAAA,CAAM,KAAK,KAAK,CAAA,CAAE,IAAI,CAAA,CAAA,KAAK,CAAA,CAAE,SAAS,EAAE,CAAA,CAAE,SAAS,CAAA,EAAG,GAAG,CAAC,CAAA,CAAE,IAAA,CAAK,EAAE,CAAC,CAAA;AAC3F;;;ACtGA,YAAA,EAAA","file":"chunk-CEJN5ZE5.js","sourcesContent":["/**\n * Main UPP Client\n *\n * Provides high-level API for interacting with the Universal Private Pool.\n */\n\nimport type { Address, PublicClient, WalletClient } from 'viem'\nimport type {\n ShieldParams,\n TransferParams,\n MergeParams,\n WithdrawParams,\n Note,\n} from './types.js'\n\n/**\n * UPP Client configuration\n */\nexport interface UPPClientConfig {\n /** Viem public client for reading chain state */\n publicClient: PublicClient\n /** Viem wallet client for sending transactions */\n walletClient: WalletClient\n /** Universal Private Pool contract address */\n poolAddress: Address\n /** ASP Registry Hub contract address */\n aspHubAddress: Address\n /** Chain ID (optional, derived from clients if not provided) */\n chainId?: number\n}\n\n/**\n * UPP Client interface\n */\nexport interface UPPClient {\n /** Shield tokens into the private pool */\n shield(params: ShieldParams): Promise<{ commitment: `0x${string}`; note: Note }>\n\n /** Transfer tokens privately */\n transfer(params: TransferParams): Promise<{ nullifier: `0x${string}`; changeNote?: Note }>\n\n /** Merge multiple notes into one */\n merge(params: MergeParams): Promise<{ commitment: `0x${string}`; note: Note }>\n\n /** Withdraw tokens from the private pool */\n withdraw(params: WithdrawParams): Promise<{ txHash: `0x${string}` }>\n\n /** Scan for notes belonging to a viewing key */\n scanNotes(viewingKey: `0x${string}`): Promise<Note[]>\n\n /** Get the current state root */\n getStateRoot(): Promise<bigint>\n\n /** Check if a nullifier has been spent */\n isNullifierSpent(nullifier: `0x${string}`): Promise<boolean>\n}\n\n/**\n * Create a UPP client instance\n *\n * @example\n * ```ts\n * import { createUPPClient } from '@upp/sdk'\n * import { createPublicClient, createWalletClient, http } from 'viem'\n * import { sepolia } from 'viem/chains'\n *\n * const publicClient = createPublicClient({\n * chain: sepolia,\n * transport: http(),\n * })\n *\n * const walletClient = createWalletClient({\n * chain: sepolia,\n * transport: http(),\n * })\n *\n * const client = createUPPClient({\n * publicClient,\n * walletClient,\n * poolAddress: '0x...',\n * aspHubAddress: '0x...',\n * })\n * ```\n */\nexport function createUPPClient(_config: UPPClientConfig): UPPClient {\n // TODO: Implement client\n throw new Error('Not implemented')\n}\n","/**\n * Core type definitions for UPP SDK\n */\n\nimport type { Address, Hex } from 'viem'\n\n/**\n * Note version - increment when note structure changes\n */\nexport const NOTE_VERSION = 5\n\n/**\n * A private note in the Universal Private Pool\n */\nexport interface Note {\n /** Note format version */\n version: number\n /** Token amount (in wei) */\n amount: bigint\n /** Random blinding factor */\n blinding: bigint\n /** Current origin - who is responsible for these funds (updated on merge) */\n origin: Address\n /** Sender - who sent this specific note (for payment attribution) */\n sender: Address\n /** ERC20 token address */\n token: Address\n /** Optional memo/message */\n memo?: string\n /** Timestamp when note was created */\n timestamp?: number\n}\n\n/**\n * Encrypted note data stored on-chain (post-quantum, hash-based)\n */\nexport interface EncryptedNote {\n /** AES-GCM encrypted note data */\n ciphertext: Hex\n /** AES-GCM nonce */\n nonce: Hex\n}\n\n/**\n * Stealth meta-address (hash-based, post-quantum)\n * Published once, used by senders to encrypt notes to the recipient\n */\nexport interface StealthMetaAddress {\n /** Owner hash = Poseidon(spendingSecret) */\n ownerHash: bigint\n /** Viewing hash = Poseidon(viewingSecret) */\n viewingHash: bigint\n}\n\n/**\n * One-time address for a specific transaction (simplified for hash-based system)\n */\nexport interface StealthAddress {\n /** Owner hash for this note */\n ownerHash: bigint\n /** Search tag for efficient scanning */\n searchTag?: bigint\n}\n\n/**\n * On-chain merge record for audit trail\n */\nexport interface MergeRecord {\n /** Output commitment (the merged note) */\n outputCommitment: Hex\n /** First input nullifier */\n nullifier1: Hex\n /** Second input nullifier */\n nullifier2: Hex\n /** Who performed the merge (new origin) */\n merger: Address\n /** Token that was merged */\n token: Address\n /** Block timestamp */\n timestamp: number\n}\n\n/**\n * ASP (Association Set Provider) root\n */\nexport interface ASPRoot {\n /** Merkle root of approved addresses */\n root: bigint\n /** IPFS hash for off-chain data */\n ipfsHash: Hex\n /** When this root was published */\n timestamp: number\n /** Number of addresses in the set */\n leafCount: number\n}\n\n/**\n * Shield operation parameters\n */\nexport interface ShieldParams {\n /** ERC20 token to shield */\n token: Address\n /** Amount to shield (in wei) */\n amount: bigint\n /** Optional: recipient owner hash (defaults to self) */\n recipientOwnerHash?: bigint\n /** Optional: memo to include in note */\n memo?: string\n}\n\n/**\n * Transfer operation parameters\n */\nexport interface TransferParams {\n /** Note to spend */\n note: Note\n /** Recipient stealth address */\n recipient: StealthAddress\n /** Amount to send (remainder goes back to sender as change) */\n amount: bigint\n /** Optional: memo to include */\n memo?: string\n}\n\n/**\n * Merge operation parameters\n */\nexport interface MergeParams {\n /** Notes to merge (must be same token) */\n notes: [Note, Note]\n /** Optional: memo for the merged note */\n memo?: string\n}\n\n/**\n * Withdraw operation parameters\n */\nexport interface WithdrawParams {\n /** Note to withdraw */\n note: Note\n /** Amount to withdraw */\n amount: bigint\n /** Recipient address for the tokens */\n recipient: Address\n /** ASP ID to use for compliance check */\n aspId?: number\n /** Use ragequit (origin withdrawing own funds) */\n ragequit?: boolean\n}\n\n/**\n * Proof for ZK operations\n */\nexport interface Proof {\n /** Proof points */\n proof: {\n pi_a: [string, string]\n pi_b: [[string, string], [string, string]]\n pi_c: [string, string]\n }\n /** Public signals */\n publicSignals: string[]\n}\n\n/**\n * Note commitment (hash)\n */\nexport type Commitment = Hex\n\n/**\n * Nullifier (spent note identifier)\n */\nexport type Nullifier = Hex\n\n// =========================================================================\n// STARK Note Types (M31/Keccak-based, post-quantum)\n// =========================================================================\n\nimport type { M31Digest } from '../utils/keccak-m31.js'\n\n// STARK_AMOUNT_SCALE moved to utils/stark.ts\nexport { STARK_AMOUNT_SCALE } from '../utils/stark.js'\n\n/**\n * A private STARK note in the Universal Private Pool.\n *\n * All field values are M31 elements (< 2^31 - 1).\n * Commitment = keccak_m31(amount, ownerHash[0..4], blinding, origin, token).\n */\nexport interface StarkNote {\n /** Amount in STARK units (actual wei = amount * STARK_AMOUNT_SCALE) */\n amount: bigint\n /** Owner hash = keccak_m31(starkSecret) — 4 M31 elements */\n ownerHash: M31Digest\n /** Random blinding factor (M31) */\n blinding: bigint\n /** Origin address encoded as M31 (lower 31 bits of address) */\n origin: bigint\n /** Token address encoded as M31 (lower 31 bits of address) */\n token: bigint\n /** The leaf index in the STARK Keccak Merkle tree (set after shielding) */\n leafIndex?: number\n /** The commitment digest (set after computation) */\n commitment?: M31Digest\n /** Optional memo */\n memo?: string\n /** Timestamp when note was created */\n timestamp?: number\n}\n\n/**\n * STARK stealth meta-address (M31/Keccak-based)\n * Published once, used by senders to encrypt notes to the recipient\n */\nexport interface StarkStealthMetaAddress {\n /** Owner hash = keccak_m31(starkSecret) — 4 M31 elements */\n ownerHash: M31Digest\n /** Viewing hash = keccak_m31(starkViewingSecret) — 4 M31 elements */\n viewingHash: M31Digest\n}\n\n/**\n * STARK proof for ZK operations (serialized Circle STARK proof)\n */\nexport interface StarkProof {\n /** Raw serialized Stwo Circle STARK proof bytes */\n proofBytes: Hex\n /** Public inputs seed (keccak256 of public parameters) */\n publicInputsSeed: Hex\n}\n","/**\n * Note management utilities\n *\n * Create, encrypt, and decrypt private notes.\n */\n\nimport type { Address, Hex } from 'viem'\nimport type { Note, EncryptedNote } from './types.js'\nimport { NOTE_VERSION } from './types.js'\n\n/**\n * Parameters for creating a new note\n */\nexport interface CreateNoteParams {\n /** Token amount */\n amount: bigint\n /** ERC20 token address */\n token: Address\n /** Origin address (who is responsible) */\n origin: Address\n /** Sender address */\n sender: Address\n /** Optional memo */\n memo?: string\n /** Optional blinding factor (generated if not provided) */\n blinding?: bigint\n}\n\n/**\n * Create a new private note\n *\n * @example\n * ```ts\n * const note = createNote({\n * amount: 1000n * 10n ** 18n,\n * token: '0x...',\n * origin: '0xMyAddress...',\n * sender: '0xMyAddress...',\n * memo: 'Payment for services',\n * })\n * ```\n */\nexport function createNote(params: CreateNoteParams): Note {\n const { amount, token, origin, sender, memo, blinding } = params\n\n // Generate random blinding factor if not provided\n const noteBlinding = blinding ?? generateRandomBlinding()\n\n return {\n version: NOTE_VERSION,\n amount,\n blinding: noteBlinding,\n origin,\n sender,\n token,\n memo,\n timestamp: Math.floor(Date.now() / 1000),\n }\n}\n\n/**\n * Encrypt a note for a recipient\n *\n * @param note - The note to encrypt\n * @param sharedSecret - ECDH shared secret with recipient\n * @returns Encrypted note data\n */\nexport function encryptNote(_note: Note, _sharedSecret: Uint8Array): EncryptedNote {\n // TODO: Implement AES-GCM encryption\n throw new Error('Not implemented')\n}\n\n/**\n * Decrypt a received note\n *\n * @param encrypted - The encrypted note data\n * @param sharedSecret - ECDH shared secret\n * @returns Decrypted note or null if decryption fails\n */\nexport function decryptNote(_encrypted: EncryptedNote, _sharedSecret: Uint8Array): Note | null {\n // TODO: Implement AES-GCM decryption\n throw new Error('Not implemented')\n}\n\n/**\n * Compute the commitment hash for a note\n *\n * commitment = Poseidon(amount, blinding, origin, token)\n */\nexport function computeCommitment(_note: Note): Hex {\n // TODO: Implement Poseidon hash\n throw new Error('Not implemented')\n}\n\n/**\n * Compute the nullifier for spending a note\n *\n * nullifier = Poseidon(blinding, leafIndex)\n */\nexport function computeNullifier(_note: Note, _leafIndex: bigint): Hex {\n // TODO: Implement nullifier computation\n throw new Error('Not implemented')\n}\n\n/**\n * Generate a random blinding factor\n */\nfunction generateRandomBlinding(): bigint {\n // TODO: Use crypto.getRandomValues for secure randomness\n const bytes = new Uint8Array(31) // 31 bytes to stay in field\n crypto.getRandomValues(bytes)\n return BigInt('0x' + Array.from(bytes).map(b => b.toString(16).padStart(2, '0')).join(''))\n}\n","/**\n * Core UPP SDK functionality\n */\n\nexport { createUPPClient } from './client.js'\nexport type { UPPClient, UPPClientConfig } from './client.js'\n\nexport { createNote, encryptNote, decryptNote } from './note.js'\n\n// Stealth address utilities (post-quantum, hash-based)\nexport {\n STEALTH_ADDRESS_PREFIX,\n ADDRESS_VERSION,\n encodeStealthAddress,\n decodeStealthAddress,\n isValidStealthAddress,\n generateStealthAddress,\n createOneTimeKeys,\n verifyOwnership,\n computeNoteEncryptionKey,\n // STARK stealth addresses (0zs prefix)\n STARK_STEALTH_ADDRESS_PREFIX,\n STARK_ADDRESS_VERSION,\n encodeStarkStealthAddress,\n decodeStarkStealthAddress,\n isValidStarkStealthAddress,\n generateStarkStealthAddress,\n detectAddressType,\n} from './stealth.js'\n\n// Proof generation (UPP circuits)\nexport {\n generateUPPProof,\n formatProofForContract,\n getUPPCircuitArtifacts,\n STATE_TREE_DEPTH,\n ASP_TREE_DEPTH,\n} from './proof.js'\nexport type {\n UPPCircuitType,\n UPPTransferCircuitInputs,\n UPPWithdrawCircuitInputs,\n UPPCircuitInputs,\n CircuitArtifacts,\n ProofResult,\n} from './proof.js'\n\n// Legacy stealth proof exports (deprecated)\nexport {\n generateProof,\n verifyProof,\n generateStealthProof,\n getStealthCircuitArtifacts,\n} from './proof.js'\nexport type {\n CircuitType,\n StealthCircuitType,\n StealthCircuitInputs,\n Stealth1x2CircuitInputs,\n Stealth2x2CircuitInputs,\n} from './proof.js'\n\nexport * from './types.js'\n\n// Swap order book module\nexport {\n computeGiveAmount,\n computeTakeAmount,\n computeRate,\n formatRate,\n computeCancelKeyHash,\n generateCancelSecret,\n filterOrdersByASP,\n filterOrdersByTokenPair,\n isFillerASPAccepted,\n isOrderActive,\n computeTotalBuyAmount,\n computeFillPercentage,\n storeCancelSecret,\n getCancelSecret,\n removeCancelSecret,\n getOwnOrderIds,\n RATE_PRECISION,\n SWAP_EVENTS_ABI,\n SWAP_ORDER_PLACED_EVENT,\n SWAP_ORDER_FILLED_EVENT,\n SWAP_ORDER_CLAIMED_EVENT,\n SWAP_ORDER_CANCELLED_EVENT,\n} from './swap.js'\nexport type {\n SwapOrder,\n SwapOrderParams,\n SwapFillParams,\n SwapOrderEvent,\n SwapFillEvent,\n} from './swap.js'\n\n// Account adapter (pluggable key source + persistence)\nexport { DirectAccountAdapter, StorableAccountAdapter } from './account.js'\nexport type { IAccountAdapter } from './account.js'\n\n// ASP provider (pluggable compliance)\nexport type { IASPProvider, ASPMembershipProof } from './asp-provider.js'\n\n// Note store (single source of truth for note state)\nexport { NoteStore } from './note-store.js'\nexport type { INoteStore, ShieldedNote, NoteStatus, ProofSystem } from './note-store.js'\n\n// ASP (Association Set Provider) module\nexport {\n computeSingleOriginASPRoot,\n generateSingleOriginASPProof,\n verifyASPProof,\n DEMO_ASP_ID,\n DEMO_ASP_NAME,\n createDemoASPRoot,\n // Multi-origin ASP tree\n buildASPTree,\n computeMultiOriginASPRoot,\n generateMultiOriginASPProof,\n generateASPProof,\n} from './asp.js'\nexport type { ASPProof } from './asp.js'\n\n// Transfer module\nexport {\n syncMerkleTree,\n getMerkleProofsForNotes,\n computeNullifier,\n buildUPPTransferCircuitInputs,\n buildTransfer,\n formatOutputForContract,\n} from './transfer.js'\nexport type {\n TransferStage,\n SpendableNote,\n MerkleProofWithNote,\n TransferContext,\n TransferBuildResult,\n NoteWithAmount,\n} from './transfer.js'\n"]}