@veilo/sdk-core 0.1.17 → 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 (218) hide show
  1. package/README.md +1296 -272
  2. package/SHIELD_INTEGRATION.md +143 -0
  3. package/config.d.ts +2 -0
  4. package/config.js +4 -0
  5. package/dist/cjs/client.d.ts +407 -0
  6. package/dist/cjs/client.js +951 -0
  7. package/dist/cjs/compactNote.d.ts +107 -0
  8. package/dist/cjs/compactNote.js +167 -0
  9. package/dist/cjs/config.d.ts +82 -0
  10. package/dist/cjs/config.js +57 -0
  11. package/dist/cjs/events.d.ts +77 -0
  12. package/dist/cjs/events.js +167 -0
  13. package/dist/cjs/idl/privacy_pool.d.ts +5 -0
  14. package/dist/cjs/idl/privacy_pool.js +15218 -0
  15. package/dist/cjs/idl/privacy_pool.json +10313 -0
  16. package/dist/cjs/index.d.ts +16 -0
  17. package/dist/cjs/index.js +67 -0
  18. package/dist/cjs/merkle.d.ts +77 -0
  19. package/dist/cjs/merkle.js +156 -0
  20. package/dist/cjs/poseidon.d.ts +29 -0
  21. package/dist/cjs/poseidon.js +100 -0
  22. package/dist/cjs/program.d.ts +37 -0
  23. package/dist/cjs/program.js +61 -0
  24. package/dist/cjs/proof.d.ts +183 -0
  25. package/dist/cjs/proof.js +292 -0
  26. package/dist/cjs/prover.d.ts +54 -0
  27. package/dist/cjs/prover.js +112 -0
  28. package/dist/cjs/random.d.ts +16 -0
  29. package/dist/cjs/random.js +28 -0
  30. package/dist/cjs/relayer.d.ts +318 -0
  31. package/dist/cjs/relayer.js +257 -0
  32. package/dist/cjs/retry.d.ts +32 -0
  33. package/dist/cjs/retry.js +75 -0
  34. package/dist/cjs/shield/alt.d.ts +87 -0
  35. package/dist/cjs/shield/alt.js +194 -0
  36. package/dist/cjs/shield/computeBudget.d.ts +61 -0
  37. package/dist/cjs/shield/computeBudget.js +64 -0
  38. package/dist/cjs/shield/errors.d.ts +58 -0
  39. package/dist/cjs/shield/errors.js +121 -0
  40. package/dist/cjs/shield/finalize.d.ts +45 -0
  41. package/dist/cjs/shield/finalize.js +119 -0
  42. package/dist/cjs/shield/index.d.ts +35 -0
  43. package/dist/cjs/shield/index.js +68 -0
  44. package/dist/cjs/shield/ix.d.ts +54 -0
  45. package/dist/cjs/shield/ix.js +119 -0
  46. package/dist/cjs/shield/owner.d.ts +36 -0
  47. package/dist/cjs/shield/owner.js +126 -0
  48. package/dist/cjs/shield/ports.d.ts +43 -0
  49. package/dist/cjs/shield/ports.js +153 -0
  50. package/dist/cjs/shield/preflight.d.ts +30 -0
  51. package/dist/cjs/shield/preflight.js +154 -0
  52. package/dist/cjs/shield/shield.d.ts +68 -0
  53. package/dist/cjs/shield/shield.js +499 -0
  54. package/dist/cjs/shield/types.d.ts +202 -0
  55. package/dist/cjs/shield/types.js +2 -0
  56. package/dist/cjs/utxo.d.ts +235 -0
  57. package/dist/cjs/utxo.js +407 -0
  58. package/dist/esm/client.d.ts +407 -0
  59. package/dist/esm/client.js +891 -0
  60. package/dist/esm/compactNote.d.ts +107 -0
  61. package/dist/esm/compactNote.js +156 -0
  62. package/dist/esm/config.d.ts +82 -0
  63. package/dist/esm/config.js +51 -0
  64. package/dist/esm/events.d.ts +77 -0
  65. package/dist/esm/events.js +129 -0
  66. package/dist/esm/idl/privacy_pool.d.ts +5 -0
  67. package/dist/esm/idl/privacy_pool.js +15216 -0
  68. package/dist/esm/idl/privacy_pool.json +10313 -0
  69. package/dist/esm/index.d.ts +16 -0
  70. package/dist/esm/index.js +29 -0
  71. package/dist/esm/merkle.d.ts +77 -0
  72. package/dist/esm/merkle.js +151 -0
  73. package/dist/esm/package.json +1 -0
  74. package/dist/esm/poseidon.d.ts +29 -0
  75. package/dist/esm/poseidon.js +87 -0
  76. package/dist/esm/program.d.ts +37 -0
  77. package/dist/esm/program.js +53 -0
  78. package/dist/esm/proof.d.ts +183 -0
  79. package/dist/esm/proof.js +281 -0
  80. package/dist/esm/prover.d.ts +54 -0
  81. package/dist/esm/prover.js +75 -0
  82. package/dist/esm/random.d.ts +16 -0
  83. package/dist/esm/random.js +21 -0
  84. package/dist/esm/relayer.d.ts +318 -0
  85. package/dist/esm/relayer.js +249 -0
  86. package/dist/esm/retry.d.ts +32 -0
  87. package/dist/esm/retry.js +71 -0
  88. package/dist/esm/shield/alt.d.ts +87 -0
  89. package/dist/esm/shield/alt.js +186 -0
  90. package/dist/esm/shield/computeBudget.d.ts +61 -0
  91. package/dist/esm/shield/computeBudget.js +61 -0
  92. package/dist/esm/shield/errors.d.ts +58 -0
  93. package/dist/esm/shield/errors.js +115 -0
  94. package/dist/esm/shield/finalize.d.ts +45 -0
  95. package/dist/esm/shield/finalize.js +83 -0
  96. package/dist/esm/shield/index.d.ts +35 -0
  97. package/dist/esm/shield/index.js +32 -0
  98. package/dist/esm/shield/ix.d.ts +54 -0
  99. package/dist/esm/shield/ix.js +82 -0
  100. package/dist/esm/shield/owner.d.ts +36 -0
  101. package/dist/esm/shield/owner.js +122 -0
  102. package/dist/esm/shield/ports.d.ts +43 -0
  103. package/dist/esm/shield/ports.js +147 -0
  104. package/dist/esm/shield/preflight.d.ts +30 -0
  105. package/dist/esm/shield/preflight.js +151 -0
  106. package/dist/esm/shield/shield.d.ts +68 -0
  107. package/dist/esm/shield/shield.js +492 -0
  108. package/dist/esm/shield/types.d.ts +202 -0
  109. package/dist/esm/shield/types.js +1 -0
  110. package/dist/esm/utxo.d.ts +235 -0
  111. package/dist/esm/utxo.js +382 -0
  112. package/dist/src/client.d.ts +407 -0
  113. package/dist/src/client.js +951 -0
  114. package/dist/src/compactNote.d.ts +107 -0
  115. package/dist/src/compactNote.js +167 -0
  116. package/dist/src/config.d.ts +82 -0
  117. package/dist/src/config.js +57 -0
  118. package/dist/src/events.d.ts +77 -0
  119. package/dist/src/events.js +167 -0
  120. package/dist/src/idl/privacy_pool.d.ts +5 -0
  121. package/dist/src/idl/privacy_pool.js +15218 -0
  122. package/dist/src/index.d.ts +16 -0
  123. package/dist/src/index.js +67 -0
  124. package/dist/src/merkle.d.ts +77 -0
  125. package/dist/src/merkle.js +156 -0
  126. package/dist/src/poseidon.d.ts +29 -0
  127. package/dist/src/poseidon.js +100 -0
  128. package/dist/src/program.d.ts +37 -0
  129. package/dist/src/program.js +61 -0
  130. package/dist/src/proof.d.ts +183 -0
  131. package/dist/src/proof.js +292 -0
  132. package/dist/src/prover.d.ts +54 -0
  133. package/dist/src/prover.js +112 -0
  134. package/dist/src/random.d.ts +16 -0
  135. package/dist/src/random.js +28 -0
  136. package/dist/src/relayer.d.ts +318 -0
  137. package/dist/src/relayer.js +257 -0
  138. package/dist/src/retry.d.ts +32 -0
  139. package/dist/src/retry.js +75 -0
  140. package/dist/src/shield/alt.d.ts +87 -0
  141. package/dist/src/shield/alt.js +194 -0
  142. package/dist/src/shield/computeBudget.d.ts +61 -0
  143. package/dist/src/shield/computeBudget.js +64 -0
  144. package/dist/src/shield/errors.d.ts +58 -0
  145. package/dist/src/shield/errors.js +121 -0
  146. package/dist/src/shield/finalize.d.ts +45 -0
  147. package/dist/src/shield/finalize.js +119 -0
  148. package/dist/src/shield/index.d.ts +35 -0
  149. package/dist/src/shield/index.js +68 -0
  150. package/dist/src/shield/ix.d.ts +54 -0
  151. package/dist/src/shield/ix.js +119 -0
  152. package/dist/src/shield/owner.d.ts +36 -0
  153. package/dist/src/shield/owner.js +126 -0
  154. package/dist/src/shield/ports.d.ts +43 -0
  155. package/dist/src/shield/ports.js +153 -0
  156. package/dist/src/shield/preflight.d.ts +30 -0
  157. package/dist/src/shield/preflight.js +154 -0
  158. package/dist/src/shield/shield.d.ts +68 -0
  159. package/dist/src/shield/shield.js +499 -0
  160. package/dist/src/shield/types.d.ts +202 -0
  161. package/dist/src/shield/types.js +2 -0
  162. package/dist/src/utxo.d.ts +235 -0
  163. package/dist/src/utxo.js +407 -0
  164. package/dist/tests/compact-note.test.d.ts +1 -0
  165. package/dist/tests/compact-note.test.js +173 -0
  166. package/dist/tests/config.test.d.ts +1 -0
  167. package/dist/tests/config.test.js +102 -0
  168. package/dist/tests/edge-cases.test.d.ts +1 -0
  169. package/dist/tests/edge-cases.test.js +220 -0
  170. package/dist/tests/encryption.test.d.ts +1 -0
  171. package/dist/tests/encryption.test.js +215 -0
  172. package/dist/tests/events.test.d.ts +1 -0
  173. package/dist/tests/events.test.js +78 -0
  174. package/dist/tests/multi-tree.test.d.ts +1 -0
  175. package/dist/tests/multi-tree.test.js +405 -0
  176. package/dist/tests/pda.test.d.ts +1 -0
  177. package/dist/tests/pda.test.js +229 -0
  178. package/dist/tests/poseidon-builder-parity.test.d.ts +1 -0
  179. package/dist/tests/poseidon-builder-parity.test.js +72 -0
  180. package/dist/tests/poseidon.test.d.ts +1 -0
  181. package/dist/tests/poseidon.test.js +142 -0
  182. package/dist/tests/proof.test.d.ts +1 -0
  183. package/dist/tests/proof.test.js +296 -0
  184. package/dist/tests/relayer.test.d.ts +1 -0
  185. package/dist/tests/relayer.test.js +271 -0
  186. package/dist/tests/sdk.integration.test.d.ts +1 -0
  187. package/dist/tests/sdk.integration.test.js +330 -0
  188. package/dist/tests/shield-owner.test.d.ts +1 -0
  189. package/dist/tests/shield-owner.test.js +89 -0
  190. package/dist/tests/shield-preflight.test.d.ts +1 -0
  191. package/dist/tests/shield-preflight.test.js +87 -0
  192. package/dist/tests/shield-realproof.test.d.ts +1 -0
  193. package/dist/tests/shield-realproof.test.js +272 -0
  194. package/dist/tests/shield.test.d.ts +1 -0
  195. package/dist/tests/shield.test.js +403 -0
  196. package/dist/tests/utxo.test.d.ts +1 -0
  197. package/dist/tests/utxo.test.js +140 -0
  198. package/package.json +105 -11
  199. package/poseidon.d.ts +2 -0
  200. package/poseidon.js +4 -0
  201. package/proof.d.ts +2 -0
  202. package/proof.js +4 -0
  203. package/prover.d.ts +2 -0
  204. package/prover.js +4 -0
  205. package/shield.d.ts +2 -0
  206. package/shield.js +4 -0
  207. package/src/client.ts +0 -352
  208. package/src/config.ts +0 -13
  209. package/src/index.ts +0 -6
  210. package/src/merkle.ts +0 -178
  211. package/src/note.ts +0 -193
  212. package/src/poseidon.ts +0 -62
  213. package/src/proof.ts +0 -170
  214. package/test/script.js +0 -0
  215. package/test-tsconfig.json +0 -19
  216. package/tests/note.test.ts +0 -50
  217. package/tests/sdk.integration.test.ts +0 -210
  218. package/tsconfig.json +0 -18
package/src/merkle.ts DELETED
@@ -1,178 +0,0 @@
1
- // sdk-core/src/merkle.ts
2
- import {
3
- BN254_FR_MODULUS,
4
- bytesToBigIntBE,
5
- bigIntToBytesBE,
6
- } from "./note";
7
- import {
8
- getPoseidon,
9
- frToBigInt,
10
- } from "./poseidon";
11
-
12
- export type MerklePath = {
13
- /** Index of the leaf in the tree (0-based) */
14
- leafIndex: number;
15
- /** Sibling hashes from leaf level up to (but not including) the root */
16
- path: Uint8Array[];
17
- /**
18
- * 0 = current node is left child, sibling is right
19
- * 1 = current node is right child, sibling is left
20
- * (matches your Circom `pathIndices` semantics)
21
- */
22
- indices: number[];
23
- };
24
-
25
- export type Bytes32 = Uint8Array;
26
-
27
- // Poseidon-based hash of two 32-byte field elements.
28
- function hashPair(left: Bytes32, right: Bytes32): Bytes32 {
29
- if (left.length !== 32 || right.length !== 32) {
30
- throw new Error("hashPair expects 32-byte inputs");
31
- }
32
-
33
- const poseidon = getPoseidon();
34
-
35
- const lf = bytesToBigIntBE(left) % BN254_FR_MODULUS;
36
- const rf = bytesToBigIntBE(right) % BN254_FR_MODULUS;
37
-
38
- const fe = poseidon([lf, rf]);
39
- const outBig = frToBigInt(fe) % BN254_FR_MODULUS;
40
-
41
- return bigIntToBytesBE(outBig);
42
- }
43
-
44
- /**
45
- * Fixed-depth binary Merkle tree over BN254 Fr:
46
- * - Leaves and internal nodes are 32-byte big-endian Fr elements.
47
- * - Hash is Poseidon(2)(left, right).
48
- * - Unfilled leaves use the Poseidon zero chain:
49
- * zero[0] = 0
50
- * zero[i+1] = Poseidon(zero[i], zero[i])
51
- *
52
- * Depth must match:
53
- * - Circom WithdrawCircuit(depth)
54
- * - Rust MERKLE_TREE_HEIGHT
55
- */
56
- export class MerkleTree {
57
- readonly depth: number;
58
- readonly zeroes: Uint8Array[];
59
- readonly layers: Uint8Array[][];
60
- nextIndex: number;
61
-
62
- constructor(depth = 16) {
63
- this.depth = depth;
64
- this.zeroes = [];
65
- this.layers = [];
66
-
67
- // zero[0] = 0 (Fr), then zero[i+1] = Poseidon(zero[i], zero[i])
68
- let zero = bigIntToBytesBE(0n);
69
- this.zeroes.push(zero);
70
-
71
- for (let level = 1; level <= depth; level++) {
72
- zero = hashPair(zero, zero);
73
- this.zeroes.push(zero);
74
- }
75
-
76
- // Allocate layers:
77
- // level 0: 2^depth leaves
78
- // level 1: 2^(depth-1) parents
79
- // ...
80
- // level depth: 1 root
81
- for (let level = 0; level <= depth; level++) {
82
- const size = 1 << (depth - level);
83
-
84
- if (!Number.isSafeInteger(size) || size <= 0) {
85
- throw new Error(
86
- `Invalid MerkleTree depth=${depth}, level=${level}, size=${size}`,
87
- );
88
- }
89
-
90
- const arr: Uint8Array[] = new Array(size);
91
- for (let i = 0; i < size; i++) {
92
- arr[i] = this.zeroes[level];
93
- }
94
- this.layers.push(arr);
95
- }
96
-
97
- this.nextIndex = 0;
98
- }
99
-
100
- get capacity(): number {
101
- return 1 << this.depth;
102
- }
103
-
104
- get root(): Uint8Array {
105
- return this.layers[this.depth][0];
106
- }
107
-
108
- /**
109
- * Insert a leaf and recompute the path up to the root.
110
- * Returns the leaf index and the new root.
111
- */
112
- insert(leaf: Uint8Array): { index: number; root: Uint8Array } {
113
- if (leaf.length !== 32) {
114
- throw new Error("leaf must be 32 bytes");
115
- }
116
- const index = this.nextIndex;
117
- if (index >= this.capacity) {
118
- throw new Error("Merkle tree is full");
119
- }
120
-
121
- // Set leaf
122
- this.layers[0][index] = leaf;
123
-
124
- // Bubble up
125
- let idx = index;
126
- for (let level = 1; level <= this.depth; level++) {
127
- const parentIndex = Math.floor(idx / 2);
128
- const leftIndex = parentIndex * 2;
129
- const rightIndex = leftIndex + 1;
130
-
131
- const left = this.layers[level - 1][leftIndex];
132
- const right =
133
- rightIndex < this.layers[level - 1].length
134
- ? this.layers[level - 1][rightIndex]
135
- : this.zeroes[level - 1];
136
-
137
- this.layers[level][parentIndex] = hashPair(left, right);
138
- idx = parentIndex;
139
- }
140
-
141
- this.nextIndex++;
142
- return { index, root: this.root };
143
- }
144
-
145
- /**
146
- * Return Merkle proof (path + indices) for a given leaf index.
147
- * This feeds directly into the Circom `MerklePathVerifier(depth)`:
148
- * - `pathElements[i]` = sibling
149
- * - `pathIndices[i]` = 0/1 as defined above
150
- */
151
- getPath(index: number): MerklePath {
152
- if (index < 0 || index >= this.capacity) {
153
- throw new Error("index out of range");
154
- }
155
-
156
- const path: Uint8Array[] = [];
157
- const indices: number[] = [];
158
-
159
- let idx = index;
160
- for (let level = 0; level < this.depth; level++) {
161
- const isRight = idx % 2 === 1;
162
- const siblingIndex = isRight ? idx - 1 : idx + 1;
163
-
164
- const sibling =
165
- siblingIndex < this.layers[level].length
166
- ? this.layers[level][siblingIndex]
167
- : this.zeroes[level];
168
-
169
- path.push(sibling);
170
- // 0 = current is left, 1 = current is right
171
- indices.push(isRight ? 1 : 0);
172
-
173
- idx = Math.floor(idx / 2);
174
- }
175
-
176
- return { leafIndex: index, path, indices };
177
- }
178
- }
package/src/note.ts DELETED
@@ -1,193 +0,0 @@
1
- // sdk-core/src/note.ts
2
- import { PublicKey } from "@solana/web3.js";
3
- import {
4
- createCipheriv,
5
- createDecipheriv,
6
- createHash,
7
- randomBytes,
8
- } from "crypto";
9
- import { frToBigInt, getPoseidon } from "./poseidon";
10
-
11
- export type Note = {
12
- value: bigint; // u64 on-chain, bigint off-chain
13
- owner: PublicKey; // owner public key (later: spend key)
14
- rho: Uint8Array; // 32 bytes random
15
- r: Uint8Array; // 32 bytes random blinding
16
- };
17
-
18
- export type SerializedNote = {
19
- value: bigint;
20
- owner: PublicKey;
21
- rho: Uint8Array;
22
- r: Uint8Array;
23
- commitment: Uint8Array; // 32 bytes, BN254 Fr element
24
- };
25
-
26
- export type EncryptedNotePlaintext = {
27
- secret: Uint8Array; // 32 bytes
28
- nullifier: Uint8Array; // 32 bytes
29
- denomIndex: number; // 1 byte
30
- };
31
-
32
- export function encodeEncryptedNote(note: EncryptedNotePlaintext): Uint8Array {
33
- const buf = new Uint8Array(32 + 32 + 1);
34
- buf.set(note.secret, 0);
35
- buf.set(note.nullifier, 32);
36
- buf[64] = note.denomIndex;
37
- return buf;
38
- }
39
-
40
- // Decode back
41
- export function decodeEncryptedNote(buf: Uint8Array): EncryptedNotePlaintext {
42
- return {
43
- secret: buf.slice(0, 32),
44
- nullifier: buf.slice(32, 64),
45
- denomIndex: buf[64],
46
- };
47
- }
48
-
49
- export function encryptNote(
50
- plaintext: EncryptedNotePlaintext,
51
- sharedKey: Uint8Array // 32 bytes symmetric key (derived from recipient pubkey)
52
- ): Uint8Array {
53
- const iv = randomBytes(12); // ChaCha20/Poly1305 nonce
54
- const cipher = createCipheriv("chacha20-poly1305", sharedKey, iv, {
55
- authTagLength: 16,
56
- });
57
- const encoded = encodeEncryptedNote(plaintext);
58
- const encrypted = Buffer.concat([cipher.update(encoded), cipher.final()]);
59
- const authTag = cipher.getAuthTag();
60
-
61
- // Return iv + ciphertext + tag
62
- return Buffer.concat([iv, encrypted, authTag]);
63
- }
64
-
65
- export function decryptNote(
66
- ciphertext: Uint8Array,
67
- sharedKey: Uint8Array
68
- ): EncryptedNotePlaintext {
69
- const iv = ciphertext.slice(0, 12);
70
- const authTag = ciphertext.slice(ciphertext.length - 16);
71
- const enc = ciphertext.slice(12, ciphertext.length - 16);
72
-
73
- const decipher = createDecipheriv("chacha20-poly1305", sharedKey, iv, {
74
- authTagLength: 16,
75
- });
76
- decipher.setAuthTag(authTag);
77
- const decrypted = Buffer.concat([decipher.update(enc), decipher.final()]);
78
-
79
- return decodeEncryptedNote(decrypted);
80
- }
81
-
82
- function createOwnerHint(pubkey: PublicKey): Uint8Array {
83
- // Simple: hash of recipient encryption pubkey
84
- return createHash("sha256").update(pubkey.toBytes()).digest();
85
- }
86
-
87
- // -----------------------------------------------------------------------------
88
- // BN254 scalar field helpers (shared with merkle/proof)
89
- // -----------------------------------------------------------------------------
90
-
91
- // Standard BN254 scalar field modulus (same Fr as circom / Groth16)
92
- export const BN254_FR_MODULUS = BigInt(
93
- "21888242871839275222246405745257275088548364400416034343698204186575808495617"
94
- );
95
-
96
- export function bytesToBigIntBE(bytes: Uint8Array): bigint {
97
- let x = 0n;
98
- for (const b of bytes) {
99
- x = (x << 8n) | BigInt(b);
100
- }
101
- return x;
102
- }
103
-
104
- export function bigIntToBytesBE(x: bigint): Uint8Array {
105
- const out = new Uint8Array(32);
106
- let v = x;
107
- for (let i = 31; i >= 0; i--) {
108
- out[i] = Number(v & 0xffn);
109
- v >>= 8n;
110
- }
111
- return out;
112
- }
113
-
114
- // -----------------------------------------------------------------------------
115
- // Note construction
116
- // -----------------------------------------------------------------------------
117
-
118
- export function createRandomNote(params: {
119
- value: bigint;
120
- owner: PublicKey;
121
- }): Note {
122
- return {
123
- value: params.value,
124
- owner: params.owner,
125
- rho: new Uint8Array(randomBytes(32)),
126
- r: new Uint8Array(randomBytes(32)),
127
- };
128
- }
129
-
130
- /**
131
- * Optional helper: deterministic encoding of a note into bytes:
132
- * value (8 bytes, LE) || owner (32 bytes) || rho (32) || r (32)
133
- * Kept for compatibility / debugging.
134
- */
135
- export function encodeNoteToBytes(note: Note): Uint8Array {
136
- const valueBuf = Buffer.alloc(8);
137
- valueBuf.writeBigUInt64LE(note.value);
138
-
139
- const ownerBuf = note.owner.toBytes();
140
- if (ownerBuf.length !== 32) {
141
- throw new Error("Owner pubkey must be 32 bytes");
142
- }
143
- if (note.rho.length !== 32 || note.r.length !== 32) {
144
- throw new Error("rho and r must be 32 bytes each");
145
- }
146
-
147
- return Buffer.concat([
148
- valueBuf,
149
- Buffer.from(ownerBuf),
150
- Buffer.from(note.rho),
151
- Buffer.from(note.r),
152
- ]);
153
- }
154
-
155
- /**
156
- * Circom-compatible commitment:
157
- * commitment = Poseidon(value, owner, rho, r)
158
- *
159
- * All arguments are reduced into BN254 Fr before hashing.
160
- * This must match your Circom `NoteCommitment` template.
161
- */
162
- export function commitNote(note: Note): Uint8Array {
163
- const poseidon = getPoseidon();
164
-
165
- const valueField = note.value % BN254_FR_MODULUS;
166
-
167
- const ownerField = bytesToBigIntBE(note.owner.toBytes()) % BN254_FR_MODULUS;
168
-
169
- const rhoField = bytesToBigIntBE(note.rho) % BN254_FR_MODULUS;
170
-
171
- const rField = bytesToBigIntBE(note.r) % BN254_FR_MODULUS;
172
-
173
- const fe = poseidon([valueField, ownerField, rhoField, rField]);
174
- const outBig = frToBigInt(fe) % BN254_FR_MODULUS;
175
-
176
- return bigIntToBytesBE(outBig);
177
- }
178
-
179
- /**
180
- * Convenience: build a random note and its Poseidon commitment.
181
- */
182
- export function createNoteWithCommitment(params: {
183
- value: bigint;
184
- owner: PublicKey;
185
- }): SerializedNote {
186
- const note = createRandomNote(params);
187
- const commitment = commitNote(note);
188
-
189
- return {
190
- ...note,
191
- commitment,
192
- };
193
- }
package/src/poseidon.ts DELETED
@@ -1,62 +0,0 @@
1
- // sdk-core/src/poseidon.ts
2
- import {buildPoseidonReference} from "circomlibjs";
3
-
4
- export type PoseidonFn = ((inputs: bigint[]) => any) & {
5
- F: { toObject: (e: any) => bigint };
6
- };
7
-
8
- let poseidonInstance: PoseidonFn | null = null;
9
-
10
- export async function initPoseidon() {
11
- poseidonInstance = (await buildPoseidonReference()) as PoseidonFn;
12
- }
13
-
14
- export function getPoseidon(): PoseidonFn {
15
- if (!poseidonInstance) {
16
- throw new Error(
17
- "Poseidon not initialized. Call initPoseidon() once before using note/merkle/proof helpers."
18
- );
19
- }
20
- return poseidonInstance;
21
- }
22
-
23
- // Helpers for BN254 field
24
- export const BN254_FR_MODULUS = BigInt(
25
- "21888242871839275222246405745257275088548364400416034343698204186575808495617"
26
- );
27
-
28
- export function bytesToBigIntBE(bytes: Uint8Array): bigint {
29
- let x = 0n;
30
- for (const b of bytes) {
31
- x = (x << 8n) | BigInt(b);
32
- }
33
- return x;
34
- }
35
-
36
- export function bigIntToBytesBE(x: bigint): Uint8Array {
37
- const out = new Uint8Array(32);
38
- let v = x;
39
- for (let i = 31; i >= 0; i--) {
40
- out[i] = Number(v & 0xffn);
41
- v >>= 8n;
42
- }
43
- return out;
44
- }
45
-
46
- /** Convert ffjavascript field element → bigint safely */
47
- export function frToBigInt(fe: any): bigint {
48
- const poseidon = getPoseidon();
49
- const F = (poseidon as any).F;
50
-
51
- if (typeof fe === "bigint") {
52
- return fe;
53
- }
54
-
55
- if (F && typeof F.toObject === "function") {
56
- // This is how ffjavascript exposes the underlying BigInt
57
- return F.toObject(fe) as bigint;
58
- }
59
-
60
- // Fallback: treat as decimal string
61
- return BigInt(fe.toString());
62
- }
package/src/proof.ts DELETED
@@ -1,170 +0,0 @@
1
- // sdk-core/src/proof.ts
2
- import { PublicKey } from "@solana/web3.js";
3
- import {
4
- SerializedNote,
5
- BN254_FR_MODULUS,
6
- bytesToBigIntBE,
7
- bigIntToBytesBE,
8
- } from "./note";
9
- import { MerklePath } from "./merkle";
10
- import {frToBigInt, getPoseidon} from "./poseidon";
11
-
12
- // -----------------------------------------------------------------------------
13
- // Circuit inputs
14
- // -----------------------------------------------------------------------------
15
-
16
- export type WithdrawCircuitInputs = {
17
- root: Uint8Array;
18
- note: SerializedNote;
19
- merklePath: MerklePath;
20
- nullifier: Uint8Array;
21
- denomIndex: number;
22
- recipient: PublicKey;
23
- relayer: PublicKey;
24
- feeBps: number;
25
- };
26
-
27
- // -----------------------------------------------------------------------------
28
- // Nullifier helper – MUST match Circom:
29
- // nullifier = Poseidon(owner, rho)
30
- // -----------------------------------------------------------------------------
31
-
32
- export function deriveNullifier(note: SerializedNote): Uint8Array {
33
- const poseidon = getPoseidon();
34
-
35
- const ownerField =
36
- bytesToBigIntBE(note.owner.toBytes()) % BN254_FR_MODULUS;
37
- const rhoField =
38
- bytesToBigIntBE(note.rho) % BN254_FR_MODULUS;
39
-
40
- const fe = poseidon([ownerField, rhoField]);
41
- const outBig = frToBigInt(fe) % BN254_FR_MODULUS;
42
-
43
- return bigIntToBytesBE(outBig);
44
- }
45
-
46
- // -----------------------------------------------------------------------------
47
- // Groth16 proof types & packing (shared with relayer & dapps)
48
- // -----------------------------------------------------------------------------
49
-
50
- // Shape of a Groth16 proof produced by snarkjs.groth16
51
- export type RawProof = {
52
- pi_a: [string, string, string];
53
- pi_b: [[string, string], [string, string], [string, string]];
54
- pi_c: [string, string, string];
55
- protocol: string;
56
- curve: string;
57
- };
58
-
59
- /**
60
- * This matches the Rust struct:
61
- *
62
- * pub struct WithdrawProof {
63
- * pub proof_a: [u8; 64],
64
- * pub proof_b: [u8; 128],
65
- * pub proof_c: [u8; 64],
66
- * }
67
- *
68
- * In Anchor TS, this is just an object with three number[] fields.
69
- */
70
- export type WithdrawProofStruct = {
71
- proofA: number[]; // 64 bytes
72
- proofB: number[]; // 128 bytes
73
- proofC: number[]; // 64 bytes
74
- };
75
-
76
- // Builder now returns a RawProof (snarkjs output).
77
- export type ProofBuilder = (inputs: WithdrawCircuitInputs) => Promise<RawProof>;
78
-
79
- /**
80
- * Convert bigint -> 32-byte little-endian representation.
81
- * Used to pack proof coords into the 256-byte layout expected on-chain.
82
- */
83
- function bigintTo32BytesLE(x: bigint): Uint8Array {
84
- const out = new Uint8Array(32);
85
- let v = x;
86
- for (let i = 0; i < 32; i++) {
87
- out[i] = Number(v & 0xffn);
88
- v >>= 8n;
89
- }
90
- return out;
91
- }
92
-
93
- /**
94
- * Turn a snarkjs Groth16 proof into 256 bytes:
95
- * A(G1) | B(G2) | C(G1)
96
- * where:
97
- * A = (ax, ay)
98
- * B = (bx0, bx1; by0, by1)
99
- * C = (cx, cy)
100
- *
101
- * Each field element is encoded as 32-byte LE.
102
- * We ignore the extra projective / z components snarkjs keeps.
103
- */
104
- export function packProofToBytes(proof: RawProof): Uint8Array {
105
- const chunks: Uint8Array[] = [];
106
-
107
- // A: [ax, ay, az]
108
- const ax = BigInt(proof.pi_a[0]);
109
- const ay = BigInt(proof.pi_a[1]);
110
- chunks.push(bigintTo32BytesLE(ax), bigintTo32BytesLE(ay));
111
-
112
- // B: [[bx0, bx1], [by0, by1], [bz0, bz1]]
113
- // we only use x, y
114
- const bx = proof.pi_b[0];
115
- const by = proof.pi_b[1];
116
-
117
- const bx0 = BigInt(bx[0]);
118
- const bx1 = BigInt(bx[1]);
119
- const by0 = BigInt(by[0]);
120
- const by1 = BigInt(by[1]);
121
-
122
- chunks.push(
123
- bigintTo32BytesLE(bx0),
124
- bigintTo32BytesLE(bx1),
125
- bigintTo32BytesLE(by0),
126
- bigintTo32BytesLE(by1),
127
- );
128
-
129
- // C: [cx, cy, cz]
130
- const cx = BigInt(proof.pi_c[0]);
131
- const cy = BigInt(proof.pi_c[1]);
132
- chunks.push(bigintTo32BytesLE(cx), bigintTo32BytesLE(cy));
133
-
134
- // Flatten into single Uint8Array (256 bytes)
135
- const out = new Uint8Array(32 * (2 + 4 + 2)); // 256
136
- let offset = 0;
137
- for (const c of chunks) {
138
- out.set(c, offset);
139
- offset += c.length;
140
- }
141
- return out;
142
- }
143
-
144
- /**
145
- * Take a snarkjs proof and produce the JSON shape the Anchor program expects:
146
- *
147
- * pub struct WithdrawProof {
148
- * pub proof_a: [u8; 64],
149
- * pub proof_b: [u8; 128],
150
- * pub proof_c: [u8; 64],
151
- * }
152
- */
153
- export function encodeSnarkjsProofToWithdrawProof(
154
- proof: RawProof,
155
- ): WithdrawProofStruct {
156
- const full = packProofToBytes(proof);
157
- if (full.length !== 256) {
158
- throw new Error(`Expected 256 proof bytes, got ${full.length}`);
159
- }
160
-
161
- const proofA = full.slice(0, 64);
162
- const proofB = full.slice(64, 192);
163
- const proofC = full.slice(192, 256);
164
-
165
- return {
166
- proofA: Array.from(proofA),
167
- proofB: Array.from(proofB),
168
- proofC: Array.from(proofC),
169
- };
170
- }
package/test/script.js DELETED
File without changes
@@ -1,19 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "target": "ES2020",
4
- "module": "commonjs",
5
- "moduleResolution": "node",
6
- "declaration": true,
7
- "outDir": "dist",
8
- "rootDir": ".",
9
- "strict": true,
10
- "esModuleInterop": true,
11
- "skipLibCheck": true,
12
- "forceConsistentCasingInFileNames": true,
13
- "resolveJsonModule": true // 👈 add this
14
- },
15
- "include": [
16
- "src/**/*.ts",
17
- "tests/**/*.test.ts"
18
- ]
19
- }
@@ -1,50 +0,0 @@
1
- // tests/note.test.ts
2
- import "mocha";
3
- import { strict as assert } from "assert";
4
- import { Keypair } from "@solana/web3.js";
5
- import {
6
- createRandomNote,
7
- encodeNoteToBytes,
8
- commitNote,
9
- createNoteWithCommitment,
10
- } from "../src";
11
-
12
- describe("note helpers", () => {
13
- it("creates a random note with correct sizes", () => {
14
- const owner = Keypair.generate().publicKey;
15
- const value = 123n;
16
-
17
- const note = createRandomNote({ value, owner });
18
-
19
- assert.equal(note.value, value);
20
- assert.equal(note.owner.toBase58(), owner.toBase58());
21
- assert.equal(note.rho.length, 32);
22
- assert.equal(note.r.length, 32);
23
- });
24
-
25
- it("encodes and commits deterministically", () => {
26
- const owner = Keypair.generate().publicKey;
27
- const value = 42n;
28
-
29
- const note1 = createRandomNote({ value, owner });
30
- const note2 = { ...note1 };
31
-
32
- const enc1 = encodeNoteToBytes(note1);
33
- const enc2 = encodeNoteToBytes(note2);
34
-
35
- assert.equal(enc1.length, enc2.length);
36
- assert.equal(enc1.length, 8 + 32 + 32 + 32);
37
-
38
- const c1 = commitNote(note1);
39
- const c2 = commitNote(note2);
40
-
41
- assert.equal(c1.length, 32);
42
- assert.equal(Buffer.compare(Buffer.from(c1), Buffer.from(c2)), 0);
43
- });
44
-
45
- it("createNoteWithCommitment returns 32-byte commitment", () => {
46
- const owner = Keypair.generate().publicKey;
47
- const note = createNoteWithCommitment({ value: 10n, owner });
48
- assert.equal(note.commitment.length, 32);
49
- });
50
- });