@proto-kit/common 0.1.1-develop.1086

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 (96) hide show
  1. package/LICENSE.md +201 -0
  2. package/dist/config/ChildContainerCreatable.d.ts +5 -0
  3. package/dist/config/ChildContainerCreatable.d.ts.map +1 -0
  4. package/dist/config/ChildContainerCreatable.js +1 -0
  5. package/dist/config/ChildContainerProvider.d.ts +5 -0
  6. package/dist/config/ChildContainerProvider.d.ts.map +1 -0
  7. package/dist/config/ChildContainerProvider.js +1 -0
  8. package/dist/config/ConfigurableModule.d.ts +25 -0
  9. package/dist/config/ConfigurableModule.d.ts.map +1 -0
  10. package/dist/config/ConfigurableModule.js +23 -0
  11. package/dist/config/ModuleContainer.d.ts +161 -0
  12. package/dist/config/ModuleContainer.d.ts.map +1 -0
  13. package/dist/config/ModuleContainer.js +278 -0
  14. package/dist/dependencyFactory/DependencyFactory.d.ts +29 -0
  15. package/dist/dependencyFactory/DependencyFactory.d.ts.map +1 -0
  16. package/dist/dependencyFactory/DependencyFactory.js +1 -0
  17. package/dist/dependencyFactory/injectOptional.d.ts +16 -0
  18. package/dist/dependencyFactory/injectOptional.d.ts.map +1 -0
  19. package/dist/dependencyFactory/injectOptional.js +39 -0
  20. package/dist/events/EventEmitter.d.ts +19 -0
  21. package/dist/events/EventEmitter.d.ts.map +1 -0
  22. package/dist/events/EventEmitter.js +34 -0
  23. package/dist/events/EventEmitterProxy.d.ts +17 -0
  24. package/dist/events/EventEmitterProxy.d.ts.map +1 -0
  25. package/dist/events/EventEmitterProxy.js +23 -0
  26. package/dist/events/EventEmittingComponent.d.ts +6 -0
  27. package/dist/events/EventEmittingComponent.d.ts.map +1 -0
  28. package/dist/events/EventEmittingComponent.js +1 -0
  29. package/dist/index.d.ts +20 -0
  30. package/dist/index.d.ts.map +1 -0
  31. package/dist/index.js +19 -0
  32. package/dist/log.d.ts +20 -0
  33. package/dist/log.d.ts.map +1 -0
  34. package/dist/log.js +75 -0
  35. package/dist/test/equalProvable.d.ts +20 -0
  36. package/dist/test/equalProvable.d.ts.map +1 -0
  37. package/dist/test/equalProvable.js +13 -0
  38. package/dist/trees/InMemoryMerkleTreeStorage.d.ts +11 -0
  39. package/dist/trees/InMemoryMerkleTreeStorage.d.ts.map +1 -0
  40. package/dist/trees/InMemoryMerkleTreeStorage.js +12 -0
  41. package/dist/trees/MerkleTreeStore.d.ts +5 -0
  42. package/dist/trees/MerkleTreeStore.d.ts.map +1 -0
  43. package/dist/trees/MerkleTreeStore.js +1 -0
  44. package/dist/trees/MockAsyncMerkleStore.d.ts +9 -0
  45. package/dist/trees/MockAsyncMerkleStore.d.ts.map +1 -0
  46. package/dist/trees/MockAsyncMerkleStore.js +19 -0
  47. package/dist/trees/RollupMerkleTree.d.ts +147 -0
  48. package/dist/trees/RollupMerkleTree.d.ts.map +1 -0
  49. package/dist/trees/RollupMerkleTree.js +217 -0
  50. package/dist/trees/VirtualMerkleTreeStore.d.ts +13 -0
  51. package/dist/trees/VirtualMerkleTreeStore.d.ts.map +1 -0
  52. package/dist/trees/VirtualMerkleTreeStore.js +17 -0
  53. package/dist/types.d.ts +26 -0
  54. package/dist/types.d.ts.map +1 -0
  55. package/dist/types.js +11 -0
  56. package/dist/utils.d.ts +35 -0
  57. package/dist/utils.d.ts.map +1 -0
  58. package/dist/utils.js +73 -0
  59. package/dist/zkProgrammable/ProvableMethodExecutionContext.d.ts +54 -0
  60. package/dist/zkProgrammable/ProvableMethodExecutionContext.d.ts.map +1 -0
  61. package/dist/zkProgrammable/ProvableMethodExecutionContext.js +96 -0
  62. package/dist/zkProgrammable/ZkProgrammable.d.ts +39 -0
  63. package/dist/zkProgrammable/ZkProgrammable.d.ts.map +1 -0
  64. package/dist/zkProgrammable/ZkProgrammable.js +67 -0
  65. package/dist/zkProgrammable/provableMethod.d.ts +19 -0
  66. package/dist/zkProgrammable/provableMethod.d.ts.map +1 -0
  67. package/dist/zkProgrammable/provableMethod.js +73 -0
  68. package/jest.config.cjs +1 -0
  69. package/package.json +34 -0
  70. package/src/config/ChildContainerCreatable.ts +5 -0
  71. package/src/config/ChildContainerProvider.ts +5 -0
  72. package/src/config/ConfigurableModule.ts +57 -0
  73. package/src/config/ModuleContainer.ts +472 -0
  74. package/src/dependencyFactory/DependencyFactory.ts +57 -0
  75. package/src/dependencyFactory/injectOptional.ts +41 -0
  76. package/src/events/EventEmitter.ts +61 -0
  77. package/src/events/EventEmitterProxy.ts +59 -0
  78. package/src/events/EventEmittingComponent.ts +7 -0
  79. package/src/index.ts +19 -0
  80. package/src/log.ts +97 -0
  81. package/src/trees/InMemoryMerkleTreeStorage.ts +17 -0
  82. package/src/trees/MerkleTreeStore.ts +5 -0
  83. package/src/trees/MockAsyncMerkleStore.ts +30 -0
  84. package/src/trees/RollupMerkleTree.ts +356 -0
  85. package/src/trees/VirtualMerkleTreeStore.ts +20 -0
  86. package/src/types.ts +49 -0
  87. package/src/utils.ts +149 -0
  88. package/src/zkProgrammable/ProvableMethodExecutionContext.ts +122 -0
  89. package/src/zkProgrammable/ZkProgrammable.ts +131 -0
  90. package/src/zkProgrammable/provableMethod.ts +123 -0
  91. package/test/config/ContainerEvents.test.ts +67 -0
  92. package/test/config/ModuleContainer.test.ts +172 -0
  93. package/test/trees/MerkleTree.test.ts +106 -0
  94. package/test/tsconfig.json +7 -0
  95. package/test/zkProgrammable/ZkProgrammable.test.ts +304 -0
  96. package/tsconfig.json +8 -0
package/src/index.ts ADDED
@@ -0,0 +1,19 @@
1
+ export * from "./config/ModuleContainer";
2
+ export * from "./config/ConfigurableModule";
3
+ export * from "./config/ChildContainerProvider";
4
+ export * from "./config/ChildContainerCreatable";
5
+ export * from "./types";
6
+ export * from "./zkProgrammable/ZkProgrammable";
7
+ export * from "./zkProgrammable/ProvableMethodExecutionContext";
8
+ export * from "./zkProgrammable/provableMethod";
9
+ export * from "./utils";
10
+ export * from "./dependencyFactory/DependencyFactory";
11
+ export * from "./dependencyFactory/injectOptional";
12
+ export * from "./log";
13
+ export * from "./events/EventEmittingComponent";
14
+ export * from "./events/EventEmitter";
15
+ export * from "./trees/MerkleTreeStore";
16
+ export * from "./trees/InMemoryMerkleTreeStorage";
17
+ export * from "./trees/RollupMerkleTree";
18
+ export * from "./events/EventEmitterProxy";
19
+ export * from "./trees/MockAsyncMerkleStore";
package/src/log.ts ADDED
@@ -0,0 +1,97 @@
1
+ import loglevel, { LogLevelDesc, LogLevelNames } from "loglevel";
2
+ import { Provable } from "o1js";
3
+
4
+ /* eslint-disable @typescript-eslint/no-unsafe-argument */
5
+ function logProvable(
6
+ logFunction: (...args: unknown[]) => void,
7
+ ...args: any[]
8
+ ) {
9
+ Provable.asProver(() => {
10
+ const prettyArguments: string[] = [];
11
+
12
+ args.forEach((argument) => {
13
+ if (argument?.toPretty !== undefined) {
14
+ prettyArguments.push(argument.toPretty());
15
+ } else {
16
+ try {
17
+ prettyArguments.push(JSON.parse(JSON.stringify(argument)));
18
+ } catch {
19
+ prettyArguments.push(argument);
20
+ }
21
+ }
22
+ });
23
+ logFunction(...prettyArguments);
24
+ });
25
+ }
26
+ /* eslint-enable */
27
+
28
+ export const log = {
29
+ provable: {
30
+ info: (...args: unknown[]) => {
31
+ logProvable(loglevel.info, ...args);
32
+ },
33
+
34
+ debug: (...args: unknown[]) => {
35
+ logProvable(loglevel.debug, ...args);
36
+ },
37
+
38
+ error: (...args: unknown[]) => {
39
+ logProvable(loglevel.error, ...args);
40
+ },
41
+
42
+ trace: (...args: unknown[]) => {
43
+ logProvable(log.trace, ...args);
44
+ },
45
+
46
+ warn: (...args: unknown[]) => {
47
+ logProvable(loglevel.warn, ...args);
48
+ },
49
+ },
50
+
51
+ info: (...args: unknown[]) => {
52
+ loglevel.info(...args);
53
+ },
54
+
55
+ debug: (...args: unknown[]) => {
56
+ loglevel.debug(...args);
57
+ },
58
+
59
+ error: (...args: unknown[]) => {
60
+ loglevel.error(...args);
61
+ },
62
+
63
+ trace: (...args: unknown[]) => {
64
+ // Loglevel prints the stack trace by default. To still be able to use trace
65
+ // inside out application, we use the level, but call debug() under the hood
66
+ if (loglevel.getLevel() <= loglevel.levels.TRACE) {
67
+ loglevel.debug(...args);
68
+ }
69
+ },
70
+
71
+ warn: (...args: unknown[]) => {
72
+ loglevel.warn(...args);
73
+ },
74
+
75
+ setLevel: (level: LogLevelDesc) => {
76
+ loglevel.setLevel(level);
77
+ },
78
+
79
+ get levels() {
80
+ return loglevel.levels;
81
+ },
82
+
83
+ getLevel: () => loglevel.getLevel(),
84
+ };
85
+
86
+ const validLogLevels = ["TRACE", "DEBUG", "INFO", "WARN", "ERROR", "SILENT"];
87
+
88
+ export function assertValidTextLogLevel(
89
+ level: string | number
90
+ ): asserts level is LogLevelNames {
91
+ if (
92
+ typeof level === "number" ||
93
+ !validLogLevels.includes(level.toUpperCase())
94
+ ) {
95
+ throw new Error(`${level} is not a valid loglevel`);
96
+ }
97
+ }
@@ -0,0 +1,17 @@
1
+ import { MerkleTreeStore } from "./MerkleTreeStore";
2
+
3
+ export class InMemoryMerkleTreeStorage implements MerkleTreeStore {
4
+ protected nodes: {
5
+ [key: number]: {
6
+ [key: string]: bigint;
7
+ };
8
+ } = {};
9
+
10
+ public getNode(key: bigint, level: number): bigint | undefined {
11
+ return this.nodes[level]?.[key.toString()];
12
+ }
13
+
14
+ public setNode(key: bigint, level: number, value: bigint): void {
15
+ (this.nodes[level] ??= {})[key.toString()] = value;
16
+ }
17
+ }
@@ -0,0 +1,5 @@
1
+ export interface MerkleTreeStore {
2
+ setNode: (key: bigint, level: number, value: bigint) => void;
3
+
4
+ getNode: (key: bigint, level: number) => bigint | undefined;
5
+ }
@@ -0,0 +1,30 @@
1
+ import { noop } from "../utils";
2
+
3
+ import { InMemoryMerkleTreeStorage } from "./InMemoryMerkleTreeStorage";
4
+
5
+ export class MockAsyncMerkleTreeStore {
6
+ public readonly store = new InMemoryMerkleTreeStorage();
7
+
8
+ public commit(): void {
9
+ noop();
10
+ }
11
+
12
+ public openTransaction(): void {
13
+ noop();
14
+ }
15
+
16
+ public async getNodeAsync(
17
+ key: bigint,
18
+ level: number
19
+ ): Promise<bigint | undefined> {
20
+ return this.store.getNode(key, level);
21
+ }
22
+
23
+ public async setNodeAsync(
24
+ key: bigint,
25
+ level: number,
26
+ value: bigint
27
+ ): Promise<void> {
28
+ this.store.setNode(key, level, value);
29
+ }
30
+ }
@@ -0,0 +1,356 @@
1
+ import { Bool, Field, Poseidon, Provable, Struct } from "o1js";
2
+
3
+ import { range } from "../utils";
4
+ import { TypedClass } from "../types";
5
+
6
+ import { MerkleTreeStore } from "./MerkleTreeStore";
7
+ import { InMemoryMerkleTreeStorage } from "./InMemoryMerkleTreeStorage";
8
+
9
+ class StructTemplate extends Struct({
10
+ path: Provable.Array(Field, 0),
11
+ isLeft: Provable.Array(Bool, 0),
12
+ }) {}
13
+
14
+ export interface AbstractMerkleWitness extends StructTemplate {
15
+ height(): number;
16
+
17
+ /**
18
+ * Calculates a root depending on the leaf value.
19
+ * @param leaf Value of the leaf node that belongs to this Witness.
20
+ * @returns The calculated root.
21
+ */
22
+ calculateRoot(hash: Field): Field;
23
+
24
+ /**
25
+ * Calculates the index of the leaf node that belongs to this Witness.
26
+ * @returns Index of the leaf.
27
+ */
28
+ calculateIndex(): Field;
29
+
30
+ checkMembership(root: Field, key: Field, value: Field): Bool;
31
+
32
+ checkMembershipGetRoots(
33
+ root: Field,
34
+ key: Field,
35
+ value: Field
36
+ ): [Bool, Field, Field];
37
+
38
+ toShortenedEntries(): string[];
39
+ }
40
+
41
+ export interface AbstractMerkleTree {
42
+ store: MerkleTreeStore;
43
+ readonly leafCount: bigint;
44
+
45
+ assertIndexRange(index: bigint): void;
46
+
47
+ /**
48
+ * Returns a node which lives at a given index and level.
49
+ * @param level Level of the node.
50
+ * @param index Index of the node.
51
+ * @returns The data of the node.
52
+ */
53
+ getNode(level: number, index: bigint): Field;
54
+
55
+ /**
56
+ * Returns the root of the [Merkle Tree](https://en.wikipedia.org/wiki/Merkle_tree).
57
+ * @returns The root of the Merkle Tree.
58
+ */
59
+ getRoot(): Field;
60
+
61
+ /**
62
+ * Sets the value of a leaf node at a given index to a given value.
63
+ * @param index Position of the leaf node.
64
+ * @param leaf New value.
65
+ */
66
+ setLeaf(index: bigint, leaf: Field): void;
67
+
68
+ /**
69
+ * Returns the witness (also known as
70
+ * [Merkle Proof or Merkle Witness](https://computersciencewiki.org/index.php/Merkle_proof))
71
+ * for the leaf at the given index.
72
+ * @param index Position of the leaf node.
73
+ * @returns The witness that belongs to the leaf.
74
+ */
75
+ getWitness(index: bigint): AbstractMerkleWitness;
76
+
77
+ /**
78
+ * Fills all leaves of the tree.
79
+ * @param leaves Values to fill the leaves with.
80
+ */
81
+ fill(leaves: Field[]): void;
82
+ }
83
+
84
+ export interface AbstractMerkleTreeClass {
85
+ new (store: MerkleTreeStore): AbstractMerkleTree;
86
+
87
+ WITNESS: TypedClass<AbstractMerkleWitness> &
88
+ typeof StructTemplate & { dummy: () => AbstractMerkleWitness };
89
+
90
+ HEIGHT: number;
91
+
92
+ EMPTY_ROOT: bigint;
93
+
94
+ get leafCount(): bigint;
95
+ }
96
+
97
+ /**
98
+ * A [Merkle Tree](https://en.wikipedia.org/wiki/Merkle_tree) is a binary tree in
99
+ * which every leaf is the cryptography hash of a piece of data,
100
+ * and every node is the hash of the concatenation of its two child nodes.
101
+ *
102
+ * A Merkle Tree allows developers to easily and securely verify
103
+ * the integrity of large amounts of data.
104
+ *
105
+ * Take a look at our [documentation](https://docs.minaprotocol.com/en/zkapps)
106
+ * on how to use Merkle Trees in combination with zkApps and
107
+ * zero knowledge programming!
108
+ *
109
+ * Levels are indexed from leaves (level 0) to root (level N - 1).
110
+ *
111
+ * This function takes a height as argument and returns a class
112
+ * that implements a merkletree with that specified height.
113
+ *
114
+ * It also holds the Witness class under tree.WITNESS
115
+ */
116
+ export function createMerkleTree(height: number): AbstractMerkleTreeClass {
117
+ /**
118
+ * The {@link BaseMerkleWitness} class defines a circuit-compatible base class
119
+ * for [Merkle Witness'](https://computersciencewiki.org/index.php/Merkle_proof).
120
+ */
121
+ class RollupMerkleWitness
122
+ extends Struct({
123
+ path: Provable.Array(Field, height - 1),
124
+ isLeft: Provable.Array(Bool, height - 1),
125
+ })
126
+ implements AbstractMerkleWitness
127
+ {
128
+ public static height = height;
129
+
130
+ public height(): number {
131
+ return RollupMerkleWitness.height;
132
+ }
133
+
134
+ /**
135
+ * Calculates a root depending on the leaf value.
136
+ * @param leaf Value of the leaf node that belongs to this Witness.
137
+ * @returns The calculated root.
138
+ */
139
+ public calculateRoot(leaf: Field): Field {
140
+ let hash = leaf;
141
+ const n = this.height();
142
+
143
+ for (let index = 1; index < n; ++index) {
144
+ const isLeft = this.isLeft[index - 1];
145
+ // eslint-disable-next-line @typescript-eslint/no-use-before-define
146
+ const [left, right] = maybeSwap(isLeft, hash, this.path[index - 1]);
147
+ hash = Poseidon.hash([left, right]);
148
+ }
149
+
150
+ return hash;
151
+ }
152
+
153
+ /**
154
+ * Calculates the index of the leaf node that belongs to this Witness.
155
+ * @returns Index of the leaf.
156
+ */
157
+ public calculateIndex(): Field {
158
+ let powerOfTwo = Field(1);
159
+ let index = Field(0);
160
+ const n = this.height();
161
+
162
+ for (let i = 1; i < n; ++i) {
163
+ index = Provable.if(this.isLeft[i - 1], index, index.add(powerOfTwo));
164
+ powerOfTwo = powerOfTwo.mul(2);
165
+ }
166
+
167
+ return index;
168
+ }
169
+
170
+ public checkMembership(root: Field, key: Field, value: Field): Bool {
171
+ const calculatedRoot = this.calculateRoot(value);
172
+ const calculatedKey = this.calculateIndex();
173
+ // We don't have to range-check the key, because if it would be greater
174
+ // than leafCount, it would not match the computedKey
175
+ key.assertEquals(calculatedKey, "Keys of MerkleWitness does not match");
176
+ return root.equals(calculatedRoot);
177
+ }
178
+
179
+ public checkMembershipGetRoots(
180
+ root: Field,
181
+ key: Field,
182
+ value: Field
183
+ ): [Bool, Field, Field] {
184
+ const calculatedRoot = this.calculateRoot(value);
185
+ const calculatedKey = this.calculateIndex();
186
+ key.assertEquals(calculatedKey, "Keys of MerkleWitness does not match");
187
+ return [root.equals(calculatedRoot), root, calculatedRoot];
188
+ }
189
+
190
+ public toShortenedEntries() {
191
+ return range(0, 5)
192
+ .concat(range(this.height() - 4, this.height()))
193
+ .map((index) =>
194
+ [
195
+ this.path[index].toString(),
196
+ this.isLeft[index].toString(),
197
+ ].toString()
198
+ );
199
+ }
200
+
201
+ public static dummy() {
202
+ return new RollupMerkleWitness({
203
+ isLeft: Array<Bool>(height - 1).fill(Bool(false)),
204
+ path: Array<Field>(height - 1).fill(Field(0)),
205
+ });
206
+ }
207
+ }
208
+
209
+ return class AbstractRollupMerkleTree implements AbstractMerkleTree {
210
+ public static HEIGHT = height;
211
+
212
+ public static EMPTY_ROOT = new AbstractRollupMerkleTree(
213
+ new InMemoryMerkleTreeStorage()
214
+ )
215
+ .getRoot()
216
+ .toBigInt();
217
+
218
+ public static get leafCount(): bigint {
219
+ return 2n ** BigInt(AbstractRollupMerkleTree.HEIGHT - 1);
220
+ }
221
+
222
+ public static WITNESS = RollupMerkleWitness;
223
+
224
+ // private in interface
225
+ readonly zeroes: bigint[];
226
+
227
+ readonly store: MerkleTreeStore;
228
+
229
+ public constructor(store: MerkleTreeStore) {
230
+ this.store = store;
231
+ this.zeroes = [0n];
232
+ for (let index = 1; index < AbstractRollupMerkleTree.HEIGHT; index += 1) {
233
+ const previousLevel = Field(this.zeroes[index - 1]);
234
+ this.zeroes.push(
235
+ Poseidon.hash([previousLevel, previousLevel]).toBigInt()
236
+ );
237
+ }
238
+ }
239
+
240
+ public assertIndexRange(index: bigint) {
241
+ if (index > this.leafCount) {
242
+ throw new Error("Index greater than maximum leaf number");
243
+ }
244
+ }
245
+
246
+ /**
247
+ * Returns a node which lives at a given index and level.
248
+ * @param level Level of the node.
249
+ * @param index Index of the node.
250
+ * @returns The data of the node.
251
+ */
252
+ public getNode(level: number, index: bigint): Field {
253
+ this.assertIndexRange(index);
254
+ return Field(this.store.getNode(index, level) ?? this.zeroes[level]);
255
+ }
256
+
257
+ /**
258
+ * Returns the root of the [Merkle Tree](https://en.wikipedia.org/wiki/Merkle_tree).
259
+ * @returns The root of the Merkle Tree.
260
+ */
261
+ public getRoot(): Field {
262
+ return this.getNode(AbstractRollupMerkleTree.HEIGHT - 1, 0n).toConstant();
263
+ }
264
+
265
+ // private in interface
266
+ private setNode(level: number, index: bigint, value: Field) {
267
+ this.store.setNode(index, level, value.toBigInt());
268
+ }
269
+
270
+ /**
271
+ * Sets the value of a leaf node at a given index to a given value.
272
+ * @param index Position of the leaf node.
273
+ * @param leaf New value.
274
+ */
275
+ public setLeaf(index: bigint, leaf: Field) {
276
+ this.assertIndexRange(index);
277
+
278
+ this.setNode(0, index, leaf);
279
+ let currentIndex = index;
280
+ for (let level = 1; level < AbstractRollupMerkleTree.HEIGHT; level += 1) {
281
+ currentIndex /= 2n;
282
+
283
+ const left = this.getNode(level - 1, currentIndex * 2n);
284
+ const right = this.getNode(level - 1, currentIndex * 2n + 1n);
285
+
286
+ this.setNode(level, currentIndex, Poseidon.hash([left, right]));
287
+ }
288
+ }
289
+
290
+ /**
291
+ * Returns the witness (also known as
292
+ * [Merkle Proof or Merkle Witness](https://computersciencewiki.org/index.php/Merkle_proof))
293
+ * for the leaf at the given index.
294
+ * @param index Position of the leaf node.
295
+ * @returns The witness that belongs to the leaf.
296
+ */
297
+ public getWitness(index: bigint): RollupMerkleWitness {
298
+ this.assertIndexRange(index);
299
+
300
+ const path = [];
301
+ const isLefts = [];
302
+ let currentIndex = index;
303
+ for (
304
+ let level = 0;
305
+ level < AbstractRollupMerkleTree.HEIGHT - 1;
306
+ level += 1
307
+ ) {
308
+ const isLeft = currentIndex % 2n === 0n;
309
+ const sibling = this.getNode(
310
+ level,
311
+ isLeft ? currentIndex + 1n : currentIndex - 1n
312
+ );
313
+ isLefts.push(Bool(isLeft));
314
+ path.push(sibling);
315
+ currentIndex /= 2n;
316
+ }
317
+ return new RollupMerkleWitness({
318
+ isLeft: isLefts,
319
+ path,
320
+ });
321
+ }
322
+
323
+ // TODO: should this take an optional offset? should it fail if the array is too long?
324
+ /**
325
+ * Fills all leaves of the tree.
326
+ * @param leaves Values to fill the leaves with.
327
+ */
328
+ public fill(leaves: Field[]) {
329
+ leaves.forEach((value, index) => {
330
+ this.setLeaf(BigInt(index), value);
331
+ });
332
+ }
333
+
334
+ /**
335
+ * Returns the amount of leaf nodes.
336
+ * @returns Amount of leaf nodes.
337
+ */
338
+ public get leafCount(): bigint {
339
+ return AbstractRollupMerkleTree.leafCount;
340
+ }
341
+ };
342
+ }
343
+
344
+ export class RollupMerkleTree extends createMerkleTree(256) {}
345
+ export class RollupMerkleTreeWitness extends RollupMerkleTree.WITNESS {}
346
+
347
+ /**
348
+ * More efficient version of `maybeSwapBad` which
349
+ * reuses an intermediate variable
350
+ */
351
+ function maybeSwap(b: Bool, x: Field, y: Field): [Field, Field] {
352
+ const m = b.toField().mul(x.sub(y)); // b*(x - y)
353
+ const x1 = y.add(m); // y + b*(x - y)
354
+ const y2 = x.sub(m); // x - b*(x - y) = x + b*(y - x)
355
+ return [x1, y2];
356
+ }
@@ -0,0 +1,20 @@
1
+ import { MerkleTreeStore } from "./MerkleTreeStore";
2
+ import { InMemoryMerkleTreeStorage } from "./InMemoryMerkleTreeStorage";
3
+
4
+ /**
5
+ * A MemoryMerkleTreeStore that, if falls back to a parent store if it
6
+ * has no data
7
+ */
8
+ export class VirtualMerkleTreeStore extends InMemoryMerkleTreeStorage {
9
+ public constructor(private readonly parent: MerkleTreeStore) {
10
+ super();
11
+ }
12
+
13
+ public getNode(key: bigint, level: number): bigint | undefined {
14
+ return super.getNode(key, level) ?? this.parent.getNode(key, level);
15
+ }
16
+
17
+ public setNode(key: bigint, level: number, value: bigint): void {
18
+ super.setNode(key, level, value);
19
+ }
20
+ }
package/src/types.ts ADDED
@@ -0,0 +1,49 @@
1
+ // allows to reference interfaces as 'classes' rather than instances
2
+ import { Bool, Field, PublicKey } from "o1js";
3
+
4
+ export type TypedClass<Class> = new (...args: any[]) => Class;
5
+
6
+ export type UnTypedClass = new (...args: any[]) => unknown;
7
+
8
+ /**
9
+ * Using simple `keyof Target` would result into the key
10
+ * being `string | number | symbol`, but we want just a `string`
11
+ */
12
+ export type StringKeyOf<Target extends object> = Extract<keyof Target, string> &
13
+ string;
14
+
15
+ /**
16
+ * Utility type to infer element type from an array type
17
+ */
18
+ export type ArrayElement<ArrayType extends readonly unknown[]> =
19
+ ArrayType extends readonly (infer ElementType)[] ? ElementType : never;
20
+
21
+ /**
22
+ * Transforms X | Y => X & Y
23
+ */
24
+ export type UnionToIntersection<Union> = (
25
+ Union extends any ? (x: Union) => void : never
26
+ ) extends (x: infer Intersection) => void
27
+ ? Intersection
28
+ : never;
29
+
30
+ export type MergeObjects<Input extends Record<string, unknown>> =
31
+ UnionToIntersection<Input[keyof Input]>;
32
+
33
+ export type OmitKeys<Record, Keys> = {
34
+ [Key in keyof Record as Key extends Keys ? never : Key]: Record[Key];
35
+ };
36
+
37
+ // Because Publickey.empty() is not usable in combination with real
38
+ // cryptographic operations because it's group evaluation isn't defined in Fp,
39
+ // we use some other arbitrary point which we treat as "empty" in our circuits
40
+ // other arbitrary point
41
+ export const EMPTY_PUBLICKEY_X = Field(4600);
42
+ export const EMPTY_PUBLICKEY = PublicKey.fromObject({
43
+ x: EMPTY_PUBLICKEY_X,
44
+ isOdd: Bool(true),
45
+ });
46
+
47
+ export type OverwriteObjectType<Base, New> = {
48
+ [Key in keyof Base]: Key extends keyof New ? New[Key] : Base[Key];
49
+ } & New;