@interest-protocol/vortex-sdk 0.0.1-alpha.0 → 1.1.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 (121) hide show
  1. package/.eslingignore +1 -0
  2. package/dist/__tests__/entities/keypair.spec.d.ts +2 -0
  3. package/dist/__tests__/entities/keypair.spec.d.ts.map +1 -0
  4. package/dist/__tests__/test-utils.d.ts +25 -0
  5. package/dist/__tests__/test-utils.d.ts.map +1 -0
  6. package/dist/__tests__/types.d.ts +3 -0
  7. package/dist/__tests__/types.d.ts.map +1 -0
  8. package/dist/__tests__/vortex.test.d.ts +2 -0
  9. package/dist/__tests__/vortex.test.d.ts.map +1 -0
  10. package/dist/constants.d.ts +44 -0
  11. package/dist/constants.d.ts.map +1 -0
  12. package/dist/crypto/ff/f1field.d.ts +76 -0
  13. package/dist/crypto/ff/f1field.d.ts.map +1 -0
  14. package/dist/crypto/ff/index.d.ts +6 -0
  15. package/dist/crypto/ff/index.d.ts.map +1 -0
  16. package/dist/crypto/ff/random.d.ts +2 -0
  17. package/dist/crypto/ff/random.d.ts.map +1 -0
  18. package/dist/crypto/ff/scalar.d.ts +45 -0
  19. package/dist/crypto/ff/scalar.d.ts.map +1 -0
  20. package/dist/crypto/ff/utils.d.ts +6 -0
  21. package/dist/crypto/ff/utils.d.ts.map +1 -0
  22. package/dist/crypto/index.d.ts +6 -0
  23. package/dist/crypto/index.d.ts.map +1 -0
  24. package/dist/crypto/poseidon/index.d.ts +2 -0
  25. package/dist/crypto/poseidon/index.d.ts.map +1 -0
  26. package/dist/crypto/poseidon/poseidon-constants-opt.d.ts +7 -0
  27. package/dist/crypto/poseidon/poseidon-constants-opt.d.ts.map +1 -0
  28. package/dist/crypto/poseidon/poseidon-opt.d.ts +16 -0
  29. package/dist/crypto/poseidon/poseidon-opt.d.ts.map +1 -0
  30. package/dist/deposit.d.ts +4 -0
  31. package/dist/deposit.d.ts.map +1 -0
  32. package/dist/entities/index.d.ts +4 -0
  33. package/dist/entities/index.d.ts.map +1 -0
  34. package/dist/entities/keypair.d.ts +29 -0
  35. package/dist/entities/keypair.d.ts.map +1 -0
  36. package/dist/entities/merkle-tree.d.ts +81 -0
  37. package/dist/entities/merkle-tree.d.ts.map +1 -0
  38. package/dist/entities/utxo.d.ts +24 -0
  39. package/dist/entities/utxo.d.ts.map +1 -0
  40. package/dist/index.d.ts +6 -2
  41. package/dist/index.d.ts.map +1 -1
  42. package/dist/index.js +38280 -4459
  43. package/dist/index.js.map +1 -1
  44. package/dist/index.mjs +38244 -4453
  45. package/dist/index.mjs.map +1 -1
  46. package/dist/jest-setup.d.ts +2 -0
  47. package/dist/jest-setup.d.ts.map +1 -0
  48. package/dist/keys/index.d.ts +3 -0
  49. package/dist/keys/index.d.ts.map +1 -0
  50. package/dist/pkg/nodejs/vortex.d.ts +11 -0
  51. package/dist/pkg/nodejs/vortex.d.ts.map +1 -0
  52. package/dist/pkg/web/vortex.d.ts +44 -0
  53. package/dist/pkg/web/vortex.d.ts.map +1 -0
  54. package/dist/utils/decrypt.d.ts +12 -0
  55. package/dist/utils/decrypt.d.ts.map +1 -0
  56. package/dist/utils/env.d.ts +2 -0
  57. package/dist/utils/env.d.ts.map +1 -0
  58. package/dist/utils/events.d.ts +7 -0
  59. package/dist/utils/events.d.ts.map +1 -0
  60. package/dist/utils/ext-data.d.ts +3 -0
  61. package/dist/utils/ext-data.d.ts.map +1 -0
  62. package/dist/utils/index.d.ts +50 -0
  63. package/dist/utils/index.d.ts.map +1 -0
  64. package/dist/utils/prove.d.ts +3 -0
  65. package/dist/utils/prove.d.ts.map +1 -0
  66. package/dist/vortex.d.ts +51 -21
  67. package/dist/vortex.d.ts.map +1 -1
  68. package/dist/vortex.types.d.ts +74 -50
  69. package/dist/vortex.types.d.ts.map +1 -1
  70. package/dist/vortex_bg.wasm +0 -0
  71. package/dist/withdraw.d.ts +4 -0
  72. package/dist/withdraw.d.ts.map +1 -0
  73. package/jest.config.js +31 -0
  74. package/package.json +22 -7
  75. package/src/__tests__/entities/keypair.spec.ts +191 -0
  76. package/src/__tests__/test-utils.ts +76 -0
  77. package/src/__tests__/types.ts +3 -0
  78. package/src/__tests__/vortex.test.ts +25 -0
  79. package/src/constants.ts +104 -0
  80. package/src/crypto/ff/f1field.ts +464 -0
  81. package/src/crypto/ff/index.ts +6 -0
  82. package/src/crypto/ff/random.ts +32 -0
  83. package/src/crypto/ff/readme.md +8 -0
  84. package/src/crypto/ff/scalar.ts +264 -0
  85. package/src/crypto/ff/utils.ts +121 -0
  86. package/src/crypto/index.ts +8 -0
  87. package/src/crypto/poseidon/index.ts +1 -0
  88. package/src/crypto/poseidon/poseidon-constants-opt.ts +24806 -0
  89. package/src/crypto/poseidon/poseidon-opt.ts +184 -0
  90. package/src/deposit.ts +168 -0
  91. package/src/entities/index.ts +3 -0
  92. package/src/entities/keypair.ts +262 -0
  93. package/src/entities/merkle-tree.ts +256 -0
  94. package/src/entities/utxo.ts +52 -0
  95. package/src/index.ts +6 -2
  96. package/src/jest-setup.ts +2 -0
  97. package/src/keys/index.ts +5 -0
  98. package/src/pkg/nodejs/vortex.d.ts +36 -0
  99. package/src/pkg/nodejs/vortex.js +332 -0
  100. package/src/pkg/nodejs/vortex_bg.wasm +0 -0
  101. package/src/pkg/nodejs/vortex_bg.wasm.d.ts +12 -0
  102. package/src/pkg/web/vortex.d.ts +72 -0
  103. package/src/pkg/web/vortex.js +442 -0
  104. package/src/pkg/web/vortex_bg.wasm +0 -0
  105. package/src/pkg/web/vortex_bg.wasm.d.ts +12 -0
  106. package/src/utils/decrypt.ts +46 -0
  107. package/src/utils/env.ts +18 -0
  108. package/src/utils/events.ts +16 -0
  109. package/src/utils/ext-data.ts +43 -0
  110. package/src/utils/index.ts +152 -0
  111. package/src/utils/prove.ts +18 -0
  112. package/src/vortex.ts +235 -111
  113. package/src/vortex.types.ts +74 -54
  114. package/src/withdraw.ts +159 -0
  115. package/tsconfig.json +4 -2
  116. package/dist/admin.d.ts +0 -17
  117. package/dist/admin.d.ts.map +0 -1
  118. package/dist/utils.d.ts +0 -11
  119. package/dist/utils.d.ts.map +0 -1
  120. package/src/admin.ts +0 -124
  121. package/src/utils.ts +0 -66
@@ -0,0 +1,256 @@
1
+ // packages/vortex/src/entities/merkle-tree.ts
2
+
3
+ import {
4
+ ZERO_VALUE,
5
+ EMPTY_SUBTREE_HASHES,
6
+ MERKLE_TREE_HEIGHT,
7
+ } from '../constants';
8
+ import { poseidon2 } from '../crypto';
9
+
10
+ /**
11
+ * Sparse Merkle tree using Tornado Cash Nova's paired insertion strategy.
12
+ * Inserts two leaves at once for better efficiency and privacy.
13
+ */
14
+ export class MerkleTree {
15
+ levels: number;
16
+ capacity: number;
17
+ zeroElement: bigint;
18
+
19
+ private zeros: bigint[];
20
+ private subtrees: bigint[]; // filledSubtrees in Tornado Nova (indices 0..levels-1)
21
+ private _nextIndex: number;
22
+ private leaves: bigint[];
23
+ private _root: bigint;
24
+
25
+ constructor(levels: number) {
26
+ this.levels = levels;
27
+ this.capacity = 2 ** levels;
28
+ this.zeroElement = ZERO_VALUE;
29
+ this.zeros = [];
30
+ this.subtrees = [];
31
+ this._nextIndex = 0;
32
+ this.leaves = [];
33
+
34
+ // Initialize zero hashes (0 to levels, inclusive)
35
+ // We need levels+1 elements: zeros[0] through zeros[levels]
36
+ for (let i = 0; i <= levels; i++) {
37
+ this.zeros[i] = EMPTY_SUBTREE_HASHES[i];
38
+ }
39
+
40
+ // Initialize subtrees[0..levels-1] (matching Nova's filledSubtrees)
41
+ // subtrees[0] is initialized but never used (Nova quirk)
42
+ for (let i = 0; i < levels; i++) {
43
+ this.subtrees[i] = this.zeros[i];
44
+ }
45
+
46
+ // Empty root is zeros[levels]
47
+ this._root = this.zeros[levels];
48
+ }
49
+
50
+ /**
51
+ * Returns the current Merkle root
52
+ */
53
+ root(): bigint {
54
+ return this._root;
55
+ }
56
+
57
+ /**
58
+ * Insert elements in bulk (must be even number for pairing)
59
+ */
60
+ bulkInsert(elements: bigint[]) {
61
+ if (elements.length % 2 !== 0) {
62
+ throw new Error('Must insert even number of elements (pairs)');
63
+ }
64
+
65
+ for (let i = 0; i < elements.length; i += 2) {
66
+ this.insertPair(elements[i], elements[i + 1]);
67
+ }
68
+ }
69
+
70
+ /**
71
+ * Insert a pair of leaves (Nova style)
72
+ * This is the primary insertion method
73
+ */
74
+ insertPair(leaf1: bigint, leaf2: bigint) {
75
+ if (this._nextIndex >= this.capacity) {
76
+ throw new Error('Merkle tree is full. No more leaves can be added');
77
+ }
78
+
79
+ // Store both leaves
80
+ this.leaves.push(leaf1, leaf2);
81
+
82
+ // Start by hashing the pair (level 0)
83
+ let currentIndex = Math.floor(this._nextIndex / 2);
84
+ let currentLevelHash = poseidon2(leaf1, leaf2);
85
+
86
+ // Increment by 2 since we're inserting a pair
87
+ this._nextIndex += 2;
88
+
89
+ // Process levels 1 to levels-1 (matching Nova: for i = 1; i < levels)
90
+ for (let i = 1; i < this.levels; i++) {
91
+ let left: bigint;
92
+ let right: bigint;
93
+
94
+ if (currentIndex % 2 === 0) {
95
+ // Current is left child
96
+ left = currentLevelHash;
97
+ right = this.zeros[i];
98
+ this.subtrees[i] = currentLevelHash; // Cache left subtree
99
+ } else {
100
+ // Current is right child
101
+ left = this.subtrees[i]; // Get cached left subtree
102
+ right = currentLevelHash;
103
+ }
104
+
105
+ currentLevelHash = poseidon2(left, right);
106
+ currentIndex = Math.floor(currentIndex / 2);
107
+ }
108
+
109
+ // Update root
110
+ this._root = currentLevelHash;
111
+ }
112
+
113
+ /**
114
+ * Insert a single leaf (for backward compatibility)
115
+ * Pairs it with a zero leaf
116
+ */
117
+ insert(leaf: bigint) {
118
+ this.insertPair(leaf, this.zeros[0]);
119
+ }
120
+
121
+ /**
122
+ * Generate Merkle path for a leaf at given index
123
+ * Returns sibling hashes and indices for verification
124
+ */
125
+ path(index: number): { pathElements: bigint[]; pathIndices: number[] } {
126
+ if (index < 0 || index >= this._nextIndex) {
127
+ throw new Error(
128
+ `Index out of bounds: ${index} (tree has ${this._nextIndex} leaves)`
129
+ );
130
+ }
131
+
132
+ const pathElements: bigint[] = [];
133
+ const pathIndices: number[] = [];
134
+
135
+ // Level 0: Get sibling leaf
136
+ const isLeftAtLevel0 = index % 2 === 0;
137
+ pathIndices.push(isLeftAtLevel0 ? 0 : 1);
138
+
139
+ const siblingIndex = isLeftAtLevel0 ? index + 1 : index - 1;
140
+ const sibling =
141
+ siblingIndex < this._nextIndex
142
+ ? this.leaves[siblingIndex]
143
+ : this.zeros[0];
144
+ pathElements.push(sibling);
145
+
146
+ // Levels 1 to levels-1 (matching Nova's loop structure)
147
+ let currentIndex = Math.floor(index / 2);
148
+ for (let i = 1; i < this.levels; i++) {
149
+ const isLeft = currentIndex % 2 === 0;
150
+ pathIndices.push(isLeft ? 0 : 1);
151
+
152
+ if (isLeft) {
153
+ // We're left child, sibling is right (zero hash)
154
+ pathElements.push(this.zeros[i]);
155
+ } else {
156
+ // We're right child, sibling is the cached left subtree
157
+ pathElements.push(this.subtrees[i]);
158
+ }
159
+
160
+ currentIndex = Math.floor(currentIndex / 2);
161
+ }
162
+
163
+ return { pathElements, pathIndices };
164
+ }
165
+
166
+ /**
167
+ * Get all leaves in the tree
168
+ */
169
+ elements(): bigint[] {
170
+ return this.leaves;
171
+ }
172
+
173
+ /**
174
+ * Find the index of a specific leaf
175
+ */
176
+ indexOf(element: bigint, comparator: Function | null = null): number {
177
+ if (comparator) {
178
+ return this.leaves.findIndex((leaf) => comparator(element, leaf));
179
+ }
180
+ return this.leaves.findIndex((leaf) => leaf === element);
181
+ }
182
+
183
+ /**
184
+ * Serialize tree state
185
+ */
186
+ serialize() {
187
+ return {
188
+ levels: this.levels,
189
+ zeros: this.zeros,
190
+ subtrees: this.subtrees,
191
+ nextIndex: this._nextIndex,
192
+ leaves: this.leaves,
193
+ root: this._root,
194
+ };
195
+ }
196
+
197
+ /**
198
+ * Verify a Merkle path is valid for a given leaf and root
199
+ */
200
+ verify(
201
+ leaf: bigint,
202
+ pathElements: bigint[],
203
+ pathIndices: number[],
204
+ root: bigint
205
+ ): boolean {
206
+ if (
207
+ pathElements.length !== this.levels ||
208
+ pathIndices.length !== this.levels
209
+ ) {
210
+ return false;
211
+ }
212
+
213
+ let currentHash = leaf;
214
+
215
+ for (let i = 0; i < this.levels; i++) {
216
+ const sibling = pathElements[i];
217
+ const isLeft = pathIndices[i] === 0;
218
+
219
+ if (isLeft) {
220
+ currentHash = poseidon2(currentHash, sibling);
221
+ } else {
222
+ currentHash = poseidon2(sibling, currentHash);
223
+ }
224
+ }
225
+
226
+ return currentHash === root;
227
+ }
228
+
229
+ /**
230
+ * Get the current number of leaves in the tree
231
+ */
232
+ get nextIndex(): number {
233
+ return this._nextIndex;
234
+ }
235
+
236
+ /**
237
+ * Check if the tree is full
238
+ */
239
+ isFull(): boolean {
240
+ return this._nextIndex >= this.capacity;
241
+ }
242
+
243
+ /**
244
+ * Get the maximum capacity of the tree
245
+ */
246
+ getCapacity(): number {
247
+ return this.capacity;
248
+ }
249
+
250
+ /**
251
+ * Get the current fill percentage
252
+ */
253
+ getFillPercentage(): number {
254
+ return (this._nextIndex / this.capacity) * 100;
255
+ }
256
+ }
@@ -0,0 +1,52 @@
1
+ import { VortexKeypair } from './keypair';
2
+ import { poseidon3 } from '../crypto';
3
+
4
+ interface UtxoConstructorArgs {
5
+ amount: bigint;
6
+ blinding?: bigint;
7
+ keypair?: VortexKeypair;
8
+ index?: bigint;
9
+ }
10
+
11
+ export class Utxo {
12
+ amount: bigint;
13
+ blinding: bigint;
14
+ keypair: VortexKeypair;
15
+ index: bigint;
16
+
17
+ constructor({ amount, blinding, keypair, index }: UtxoConstructorArgs) {
18
+ this.amount = amount;
19
+ this.blinding = blinding ?? Utxo.blinding();
20
+ this.keypair = keypair ?? VortexKeypair.generate();
21
+ this.index = index ?? 0n;
22
+ }
23
+
24
+ static blinding() {
25
+ return BigInt(Math.floor(Math.random() * 1_000_000_000));
26
+ }
27
+
28
+ commitment() {
29
+ return poseidon3(
30
+ this.amount,
31
+ BigInt(this.keypair.publicKey),
32
+ this.blinding
33
+ );
34
+ }
35
+
36
+ nullifier() {
37
+ const commitment = this.commitment();
38
+ return poseidon3(
39
+ commitment,
40
+ this.index,
41
+ this.keypair.sign(commitment, this.index)
42
+ );
43
+ }
44
+
45
+ payload() {
46
+ return {
47
+ amount: this.amount,
48
+ blinding: this.blinding,
49
+ index: this.index,
50
+ };
51
+ }
52
+ }
package/src/index.ts CHANGED
@@ -1,4 +1,8 @@
1
- export * from './utils';
1
+ export * from './constants';
2
2
  export * from './vortex';
3
- export * from './admin';
3
+ export * from './entities';
4
4
  export * from './vortex.types';
5
+ export * from './crypto';
6
+ export * from './utils';
7
+ export * from './deposit';
8
+ export * from './withdraw';
@@ -0,0 +1,2 @@
1
+ // jest-setup.ts
2
+ import '@testing-library/jest-dom';