@aztec/merkle-tree 0.1.0-alpha10

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 (94) hide show
  1. package/.eslintrc.cjs +1 -0
  2. package/.tsbuildinfo +1 -0
  3. package/README.md +41 -0
  4. package/dest/hasher.d.ts +11 -0
  5. package/dest/hasher.d.ts.map +1 -0
  6. package/dest/hasher.js +2 -0
  7. package/dest/index.d.ts +14 -0
  8. package/dest/index.d.ts.map +1 -0
  9. package/dest/index.js +14 -0
  10. package/dest/interfaces/append_only_tree.d.ts +13 -0
  11. package/dest/interfaces/append_only_tree.d.ts.map +1 -0
  12. package/dest/interfaces/append_only_tree.js +2 -0
  13. package/dest/interfaces/indexed_tree.d.ts +63 -0
  14. package/dest/interfaces/indexed_tree.d.ts.map +1 -0
  15. package/dest/interfaces/indexed_tree.js +2 -0
  16. package/dest/interfaces/merkle_tree.d.ts +47 -0
  17. package/dest/interfaces/merkle_tree.d.ts.map +1 -0
  18. package/dest/interfaces/merkle_tree.js +2 -0
  19. package/dest/interfaces/update_only_tree.d.ts +15 -0
  20. package/dest/interfaces/update_only_tree.d.ts.map +1 -0
  21. package/dest/interfaces/update_only_tree.js +2 -0
  22. package/dest/load_tree.d.ts +13 -0
  23. package/dest/load_tree.d.ts.map +1 -0
  24. package/dest/load_tree.js +17 -0
  25. package/dest/new_tree.d.ts +15 -0
  26. package/dest/new_tree.d.ts.map +1 -0
  27. package/dest/new_tree.js +16 -0
  28. package/dest/pedersen.d.ts +42 -0
  29. package/dest/pedersen.d.ts.map +1 -0
  30. package/dest/pedersen.js +49 -0
  31. package/dest/sibling_path/sibling_path.d.ts +92 -0
  32. package/dest/sibling_path/sibling_path.d.ts.map +1 -0
  33. package/dest/sibling_path/sibling_path.js +120 -0
  34. package/dest/sparse_tree/sparse_tree.d.ts +15 -0
  35. package/dest/sparse_tree/sparse_tree.d.ts.map +1 -0
  36. package/dest/sparse_tree/sparse_tree.js +31 -0
  37. package/dest/sparse_tree/sparse_tree.test.d.ts +2 -0
  38. package/dest/sparse_tree/sparse_tree.test.d.ts.map +1 -0
  39. package/dest/sparse_tree/sparse_tree.test.js +132 -0
  40. package/dest/standard_indexed_tree/standard_indexed_tree.d.ts +230 -0
  41. package/dest/standard_indexed_tree/standard_indexed_tree.d.ts.map +1 -0
  42. package/dest/standard_indexed_tree/standard_indexed_tree.js +497 -0
  43. package/dest/standard_indexed_tree/standard_indexed_tree.test.d.ts +2 -0
  44. package/dest/standard_indexed_tree/standard_indexed_tree.test.d.ts.map +1 -0
  45. package/dest/standard_indexed_tree/standard_indexed_tree.test.js +316 -0
  46. package/dest/standard_tree/standard_tree.d.ts +25 -0
  47. package/dest/standard_tree/standard_tree.d.ts.map +1 -0
  48. package/dest/standard_tree/standard_tree.js +50 -0
  49. package/dest/standard_tree/standard_tree.test.d.ts +2 -0
  50. package/dest/standard_tree/standard_tree.test.d.ts.map +1 -0
  51. package/dest/standard_tree/standard_tree.test.js +58 -0
  52. package/dest/test/standard_based_test_suite.d.ts +6 -0
  53. package/dest/test/standard_based_test_suite.d.ts.map +1 -0
  54. package/dest/test/standard_based_test_suite.js +86 -0
  55. package/dest/test/test_suite.d.ts +6 -0
  56. package/dest/test/test_suite.d.ts.map +1 -0
  57. package/dest/test/test_suite.js +118 -0
  58. package/dest/test/utils/append_leaves.d.ts +5 -0
  59. package/dest/test/utils/append_leaves.d.ts.map +1 -0
  60. package/dest/test/utils/append_leaves.js +14 -0
  61. package/dest/test/utils/create_mem_down.d.ts +3 -0
  62. package/dest/test/utils/create_mem_down.d.ts.map +1 -0
  63. package/dest/test/utils/create_mem_down.js +3 -0
  64. package/dest/test/utils/pedersen_with_counter.d.ts +24 -0
  65. package/dest/test/utils/pedersen_with_counter.d.ts.map +1 -0
  66. package/dest/test/utils/pedersen_with_counter.js +31 -0
  67. package/dest/tree_base.d.ts +118 -0
  68. package/dest/tree_base.d.ts.map +1 -0
  69. package/dest/tree_base.js +214 -0
  70. package/package.json +14 -0
  71. package/package.local.json +3 -0
  72. package/src/hasher.ts +9 -0
  73. package/src/index.ts +13 -0
  74. package/src/interfaces/append_only_tree.ts +12 -0
  75. package/src/interfaces/indexed_tree.ts +78 -0
  76. package/src/interfaces/merkle_tree.ts +52 -0
  77. package/src/interfaces/update_only_tree.ts +15 -0
  78. package/src/load_tree.ts +24 -0
  79. package/src/new_tree.ts +26 -0
  80. package/src/pedersen.ts +58 -0
  81. package/src/sibling_path/sibling_path.ts +139 -0
  82. package/src/sparse_tree/sparse_tree.test.ts +177 -0
  83. package/src/sparse_tree/sparse_tree.ts +32 -0
  84. package/src/standard_indexed_tree/standard_indexed_tree.test.ts +450 -0
  85. package/src/standard_indexed_tree/standard_indexed_tree.ts +591 -0
  86. package/src/standard_tree/standard_tree.test.ts +74 -0
  87. package/src/standard_tree/standard_tree.ts +54 -0
  88. package/src/test/standard_based_test_suite.ts +139 -0
  89. package/src/test/test_suite.ts +162 -0
  90. package/src/test/utils/append_leaves.ts +15 -0
  91. package/src/test/utils/create_mem_down.ts +3 -0
  92. package/src/test/utils/pedersen_with_counter.ts +30 -0
  93. package/src/tree_base.ts +242 -0
  94. package/tsconfig.json +17 -0
@@ -0,0 +1,42 @@
1
+ /// <reference types="node" resolution-mode="require"/>
2
+ import { IWasmModule } from '@aztec/foundation/wasm';
3
+ import { Hasher } from './hasher.js';
4
+ /**
5
+ * A helper class encapsulating Pedersen hash functionality.
6
+ */
7
+ export declare class Pedersen implements Hasher {
8
+ private wasm;
9
+ constructor(wasm: IWasmModule);
10
+ /**
11
+ * Compresses two 32-byte hashes.
12
+ * @param lhs - The first hash.
13
+ * @param rhs - The second hash.
14
+ * @returns The new 32-byte hash.
15
+ */
16
+ compress(lhs: Uint8Array, rhs: Uint8Array): Buffer;
17
+ /**
18
+ * Compresses an array of buffers.
19
+ * @param inputs - The array of buffers to compress.
20
+ * @returns The resulting 32-byte hash.
21
+ */
22
+ compressInputs(inputs: Buffer[]): Buffer;
23
+ /**
24
+ * Get a 32-byte pedersen hash from a buffer.
25
+ * @param data - The data buffer.
26
+ * @returns The resulting hash buffer.
27
+ */
28
+ hashToField(data: Uint8Array): Buffer;
29
+ /**
30
+ * Given a buffer containing 32 byte pedersen leaves, return a new buffer containing the leaves and all pairs of
31
+ * nodes that define a merkle tree.
32
+ *
33
+ * E.g.
34
+ * Input: [1][2][3][4]
35
+ * Output: [1][2][3][4][compress(1,2)][compress(3,4)][compress(5,6)].
36
+ *
37
+ * @param leaves - The 32 byte pedersen leaves.
38
+ * @returns A tree represented by an array.
39
+ */
40
+ hashToTree(leaves: Buffer[]): Promise<Buffer[]>;
41
+ }
42
+ //# sourceMappingURL=pedersen.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pedersen.d.ts","sourceRoot":"","sources":["../src/pedersen.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAOrD,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC;;GAEG;AACH,qBAAa,QAAS,YAAW,MAAM;IACzB,OAAO,CAAC,IAAI;gBAAJ,IAAI,EAAE,WAAW;IAErC;;;;;OAKG;IACI,QAAQ,CAAC,GAAG,EAAE,UAAU,EAAE,GAAG,EAAE,UAAU,GAAG,MAAM;IAIzD;;;;OAIG;IACI,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM;IAI/C;;;;OAIG;IACI,WAAW,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM;IAI5C;;;;;;;;;;OAUG;IACI,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;CAGvD"}
@@ -0,0 +1,49 @@
1
+ import { pedersenCompress, pedersenGetHash, pedersenGetHashTree, pedersenHashInputs, } from '@aztec/circuits.js/barretenberg';
2
+ /**
3
+ * A helper class encapsulating Pedersen hash functionality.
4
+ */
5
+ export class Pedersen {
6
+ constructor(wasm) {
7
+ this.wasm = wasm;
8
+ }
9
+ /**
10
+ * Compresses two 32-byte hashes.
11
+ * @param lhs - The first hash.
12
+ * @param rhs - The second hash.
13
+ * @returns The new 32-byte hash.
14
+ */
15
+ compress(lhs, rhs) {
16
+ return pedersenCompress(this.wasm, lhs, rhs);
17
+ }
18
+ /**
19
+ * Compresses an array of buffers.
20
+ * @param inputs - The array of buffers to compress.
21
+ * @returns The resulting 32-byte hash.
22
+ */
23
+ compressInputs(inputs) {
24
+ return pedersenHashInputs(this.wasm, inputs);
25
+ }
26
+ /**
27
+ * Get a 32-byte pedersen hash from a buffer.
28
+ * @param data - The data buffer.
29
+ * @returns The resulting hash buffer.
30
+ */
31
+ hashToField(data) {
32
+ return pedersenGetHash(this.wasm, Buffer.from(data));
33
+ }
34
+ /**
35
+ * Given a buffer containing 32 byte pedersen leaves, return a new buffer containing the leaves and all pairs of
36
+ * nodes that define a merkle tree.
37
+ *
38
+ * E.g.
39
+ * Input: [1][2][3][4]
40
+ * Output: [1][2][3][4][compress(1,2)][compress(3,4)][compress(5,6)].
41
+ *
42
+ * @param leaves - The 32 byte pedersen leaves.
43
+ * @returns A tree represented by an array.
44
+ */
45
+ hashToTree(leaves) {
46
+ return Promise.resolve(pedersenGetHashTree(this.wasm, leaves));
47
+ }
48
+ }
49
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGVkZXJzZW4uanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvcGVkZXJzZW4udHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQ0EsT0FBTyxFQUNMLGdCQUFnQixFQUNoQixlQUFlLEVBQ2YsbUJBQW1CLEVBQ25CLGtCQUFrQixHQUNuQixNQUFNLGlDQUFpQyxDQUFDO0FBR3pDOztHQUVHO0FBQ0gsTUFBTSxPQUFPLFFBQVE7SUFDbkIsWUFBb0IsSUFBaUI7UUFBakIsU0FBSSxHQUFKLElBQUksQ0FBYTtJQUFHLENBQUM7SUFFekM7Ozs7O09BS0c7SUFDSSxRQUFRLENBQUMsR0FBZSxFQUFFLEdBQWU7UUFDOUMsT0FBTyxnQkFBZ0IsQ0FBQyxJQUFJLENBQUMsSUFBSSxFQUFFLEdBQUcsRUFBRSxHQUFHLENBQUMsQ0FBQztJQUMvQyxDQUFDO0lBRUQ7Ozs7T0FJRztJQUNJLGNBQWMsQ0FBQyxNQUFnQjtRQUNwQyxPQUFPLGtCQUFrQixDQUFDLElBQUksQ0FBQyxJQUFJLEVBQUUsTUFBTSxDQUFDLENBQUM7SUFDL0MsQ0FBQztJQUVEOzs7O09BSUc7SUFDSSxXQUFXLENBQUMsSUFBZ0I7UUFDakMsT0FBTyxlQUFlLENBQUMsSUFBSSxDQUFDLElBQUksRUFBRSxNQUFNLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUM7SUFDdkQsQ0FBQztJQUVEOzs7Ozs7Ozs7O09BVUc7SUFDSSxVQUFVLENBQUMsTUFBZ0I7UUFDaEMsT0FBTyxPQUFPLENBQUMsT0FBTyxDQUFDLG1CQUFtQixDQUFDLElBQUksQ0FBQyxJQUFJLEVBQUUsTUFBTSxDQUFDLENBQUMsQ0FBQztJQUNqRSxDQUFDO0NBQ0YifQ==
@@ -0,0 +1,92 @@
1
+ /// <reference types="node" resolution-mode="require"/>
2
+ import { Pedersen } from '../pedersen.js';
3
+ import { Fr } from '@aztec/foundation/fields';
4
+ /**
5
+ * Contains functionality to compute and serialize/deserialize a sibling path.
6
+ * E.g. Sibling path for a leaf at index 3 in a tree of depth 3 consists of:
7
+ * d0: [ root ]
8
+ * d1: [ ] [*]
9
+ * d2: [*] [ ] [ ] [ ]
10
+ * d3: [ ] [ ] [*] [ ] [ ] [ ] [ ] [ ].
11
+ *
12
+ * And the elements would be ordered as: [ leaf_at_index_2, node_at_level_2_index_0, node_at_level_1_index_1 ].
13
+ */
14
+ export declare class SiblingPath<N extends number> {
15
+ /**
16
+ * Size of the sibling path (number of fields it contains).
17
+ */
18
+ pathSize: N;
19
+ private data;
20
+ /**
21
+ * Returns sibling path hashed up from the a element.
22
+ * @param size - The number of elements in a given path.
23
+ * @param zeroElement - Value of the zero element.
24
+ * @param pedersen - Implementation of a hasher interface using the Pedersen hash.
25
+ * @returns A sibling path hashed up from a zero element.
26
+ */
27
+ static ZERO<N extends number>(size: N, zeroElement: Buffer, pedersen: Pedersen): SiblingPath<N>;
28
+ /**
29
+ * Constructor.
30
+ * @param pathSize - The size of the sibling path.
31
+ * @param path - The sibling path data.
32
+ */
33
+ constructor(
34
+ /**
35
+ * Size of the sibling path (number of fields it contains).
36
+ */
37
+ pathSize: N,
38
+ /**
39
+ * The sibling path data.
40
+ */
41
+ path: Buffer[]);
42
+ /**
43
+ * Serializes this SiblingPath object to a buffer.
44
+ * @returns The buffer representation of this object.
45
+ */
46
+ toBuffer(): Buffer;
47
+ /**
48
+ * Returns the path buffer underlying the sibling path.
49
+ * @returns The Buffer array representation of this object.
50
+ */
51
+ toBufferArray(): Buffer[];
52
+ /**
53
+ * Convert the Sibling Path object into an array of field elements.
54
+ * @returns The field array representation of this object.
55
+ */
56
+ toFieldArray(): Fr[];
57
+ /**
58
+ * Deserializes a SiblingPath from a buffer.
59
+ * @param buf - A buffer containing the buffer representation of SiblingPath.
60
+ * @param offset - An offset to start deserializing from.
61
+ * @returns A SiblingPath object.
62
+ */
63
+ static fromBuffer<N extends number>(buf: Buffer, offset?: number): SiblingPath<N>;
64
+ /**
65
+ * Deserializes a SiblingPath object from a slice of a part of a buffer and returns the amount of bytes advanced.
66
+ * @param buf - A buffer representation of the sibling path.
67
+ * @param offset - An offset to start deserializing from.
68
+ * @returns The deserialized sibling path and the number of bytes advanced.
69
+ */
70
+ static deserialize<N extends number>(buf: Buffer, offset?: number): {
71
+ elem: SiblingPath<N>;
72
+ adv: number;
73
+ };
74
+ /**
75
+ * Serializes this SiblingPath object to a hex string representation.
76
+ * @returns A hex string representation of the sibling path.
77
+ */
78
+ toString(): string;
79
+ /**
80
+ * Deserializes a SiblingPath object from a hex string representation.
81
+ * @param repr - A hex string representation of the sibling path.
82
+ * @returns A SiblingPath object.
83
+ */
84
+ static fromString<N extends number>(repr: string): SiblingPath<N>;
85
+ /**
86
+ * Generate a subtree path from the current sibling path.
87
+ * @param subtreeHeight - The size of the subtree that we are getting the path for.
88
+ * @returns A new sibling path that is the for the requested subtree.
89
+ */
90
+ getSubtreeSiblingPath<SubtreeHeight extends number, SubtreeSiblingPathHeight extends number>(subtreeHeight: SubtreeHeight): SiblingPath<SubtreeSiblingPathHeight>;
91
+ }
92
+ //# sourceMappingURL=sibling_path.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sibling_path.d.ts","sourceRoot":"","sources":["../../src/sibling_path/sibling_path.ts"],"names":[],"mappings":";AAMA,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,EAAE,EAAE,MAAM,0BAA0B,CAAC;AAE9C;;;;;;;;;GASG;AACH,qBAAa,WAAW,CAAC,CAAC,SAAS,MAAM;IA0BrC;;OAEG;IACI,QAAQ,EAAE,CAAC;IA5BpB,OAAO,CAAC,IAAI,CAAmB;IAE/B;;;;;;OAMG;WACW,IAAI,CAAC,CAAC,SAAS,MAAM,EAAE,IAAI,EAAE,CAAC,EAAE,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,GAAG,WAAW,CAAC,CAAC,CAAC;IAUtG;;;;OAIG;;IAED;;OAEG;IACI,QAAQ,EAAE,CAAC;IAClB;;OAEG;IACH,IAAI,EAAE,MAAM,EAAE;IAKhB;;;OAGG;IACI,QAAQ,IAAI,MAAM;IAIzB;;;OAGG;IACI,aAAa,IAAI,MAAM,EAAE;IAIhC;;;OAGG;IACI,YAAY,IAAI,EAAE,EAAE;IAI3B;;;;;OAKG;IACH,MAAM,CAAC,UAAU,CAAC,CAAC,SAAS,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,SAAI,GAAG,WAAW,CAAC,CAAC,CAAC;IAK5E;;;;;OAKG;IACH,MAAM,CAAC,WAAW,CAAC,CAAC,SAAS,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,SAAI;;;;IAU5D;;;OAGG;IACI,QAAQ,IAAI,MAAM;IAIzB;;;;OAIG;WACW,UAAU,CAAC,CAAC,SAAS,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,WAAW,CAAC,CAAC,CAAC;IAIxE;;;;OAIG;IACI,qBAAqB,CAAC,aAAa,SAAS,MAAM,EAAE,wBAAwB,SAAS,MAAM,EAChG,aAAa,EAAE,aAAa,GAC3B,WAAW,CAAC,wBAAwB,CAAC;CAMzC"}
@@ -0,0 +1,120 @@
1
+ import { assertLength, deserializeArrayFromVector, serializeBufferArrayToVector, } from '@aztec/foundation/serialize';
2
+ import { Fr } from '@aztec/foundation/fields';
3
+ /**
4
+ * Contains functionality to compute and serialize/deserialize a sibling path.
5
+ * E.g. Sibling path for a leaf at index 3 in a tree of depth 3 consists of:
6
+ * d0: [ root ]
7
+ * d1: [ ] [*]
8
+ * d2: [*] [ ] [ ] [ ]
9
+ * d3: [ ] [ ] [*] [ ] [ ] [ ] [ ] [ ].
10
+ *
11
+ * And the elements would be ordered as: [ leaf_at_index_2, node_at_level_2_index_0, node_at_level_1_index_1 ].
12
+ */
13
+ export class SiblingPath {
14
+ /**
15
+ * Returns sibling path hashed up from the a element.
16
+ * @param size - The number of elements in a given path.
17
+ * @param zeroElement - Value of the zero element.
18
+ * @param pedersen - Implementation of a hasher interface using the Pedersen hash.
19
+ * @returns A sibling path hashed up from a zero element.
20
+ */
21
+ static ZERO(size, zeroElement, pedersen) {
22
+ const bufs = [];
23
+ let current = zeroElement;
24
+ for (let i = 0; i < size; ++i) {
25
+ bufs.push(current);
26
+ current = pedersen.compress(current, current);
27
+ }
28
+ return new SiblingPath(size, bufs);
29
+ }
30
+ /**
31
+ * Constructor.
32
+ * @param pathSize - The size of the sibling path.
33
+ * @param path - The sibling path data.
34
+ */
35
+ constructor(
36
+ /**
37
+ * Size of the sibling path (number of fields it contains).
38
+ */
39
+ pathSize,
40
+ /**
41
+ * The sibling path data.
42
+ */
43
+ path) {
44
+ this.pathSize = pathSize;
45
+ this.data = assertLength(path, pathSize);
46
+ }
47
+ /**
48
+ * Serializes this SiblingPath object to a buffer.
49
+ * @returns The buffer representation of this object.
50
+ */
51
+ toBuffer() {
52
+ return serializeBufferArrayToVector(this.data);
53
+ }
54
+ /**
55
+ * Returns the path buffer underlying the sibling path.
56
+ * @returns The Buffer array representation of this object.
57
+ */
58
+ toBufferArray() {
59
+ return this.data;
60
+ }
61
+ /**
62
+ * Convert the Sibling Path object into an array of field elements.
63
+ * @returns The field array representation of this object.
64
+ */
65
+ toFieldArray() {
66
+ return this.data.map(buf => Fr.fromBuffer(buf));
67
+ }
68
+ /**
69
+ * Deserializes a SiblingPath from a buffer.
70
+ * @param buf - A buffer containing the buffer representation of SiblingPath.
71
+ * @param offset - An offset to start deserializing from.
72
+ * @returns A SiblingPath object.
73
+ */
74
+ static fromBuffer(buf, offset = 0) {
75
+ const { elem } = SiblingPath.deserialize(buf, offset);
76
+ return elem;
77
+ }
78
+ /**
79
+ * Deserializes a SiblingPath object from a slice of a part of a buffer and returns the amount of bytes advanced.
80
+ * @param buf - A buffer representation of the sibling path.
81
+ * @param offset - An offset to start deserializing from.
82
+ * @returns The deserialized sibling path and the number of bytes advanced.
83
+ */
84
+ static deserialize(buf, offset = 0) {
85
+ const deserializePath = (buf, offset) => ({
86
+ elem: buf.slice(offset, offset + 32),
87
+ adv: 32,
88
+ });
89
+ const { elem, adv } = deserializeArrayFromVector(deserializePath, buf, offset);
90
+ const size = elem.length;
91
+ return { elem: new SiblingPath(size, elem), adv };
92
+ }
93
+ /**
94
+ * Serializes this SiblingPath object to a hex string representation.
95
+ * @returns A hex string representation of the sibling path.
96
+ */
97
+ toString() {
98
+ return this.toBuffer().toString('hex');
99
+ }
100
+ /**
101
+ * Deserializes a SiblingPath object from a hex string representation.
102
+ * @param repr - A hex string representation of the sibling path.
103
+ * @returns A SiblingPath object.
104
+ */
105
+ static fromString(repr) {
106
+ return SiblingPath.fromBuffer(Buffer.from(repr, 'hex'));
107
+ }
108
+ /**
109
+ * Generate a subtree path from the current sibling path.
110
+ * @param subtreeHeight - The size of the subtree that we are getting the path for.
111
+ * @returns A new sibling path that is the for the requested subtree.
112
+ */
113
+ getSubtreeSiblingPath(subtreeHeight) {
114
+ // Drop the size of the subtree from the path, and return the rest.
115
+ const subtreeData = this.data.slice(subtreeHeight);
116
+ const subtreePathSize = (this.pathSize - subtreeHeight);
117
+ return new SiblingPath(subtreePathSize, subtreeData);
118
+ }
119
+ }
120
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2libGluZ19wYXRoLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3NpYmxpbmdfcGF0aC9zaWJsaW5nX3BhdGgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUVMLFlBQVksRUFDWiwwQkFBMEIsRUFDMUIsNEJBQTRCLEdBQzdCLE1BQU0sNkJBQTZCLENBQUM7QUFFckMsT0FBTyxFQUFFLEVBQUUsRUFBRSxNQUFNLDBCQUEwQixDQUFDO0FBRTlDOzs7Ozs7Ozs7R0FTRztBQUNILE1BQU0sT0FBTyxXQUFXO0lBR3RCOzs7Ozs7T0FNRztJQUNJLE1BQU0sQ0FBQyxJQUFJLENBQW1CLElBQU8sRUFBRSxXQUFtQixFQUFFLFFBQWtCO1FBQ25GLE1BQU0sSUFBSSxHQUFhLEVBQUUsQ0FBQztRQUMxQixJQUFJLE9BQU8sR0FBRyxXQUFXLENBQUM7UUFDMUIsS0FBSyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLElBQUksRUFBRSxFQUFFLENBQUMsRUFBRTtZQUM3QixJQUFJLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxDQUFDO1lBQ25CLE9BQU8sR0FBRyxRQUFRLENBQUMsUUFBUSxDQUFDLE9BQU8sRUFBRSxPQUFPLENBQUMsQ0FBQztTQUMvQztRQUNELE9BQU8sSUFBSSxXQUFXLENBQUMsSUFBSSxFQUFFLElBQUksQ0FBQyxDQUFDO0lBQ3JDLENBQUM7SUFFRDs7OztPQUlHO0lBQ0g7SUFDRTs7T0FFRztJQUNJLFFBQVc7SUFDbEI7O09BRUc7SUFDSCxJQUFjO1FBSlAsYUFBUSxHQUFSLFFBQVEsQ0FBRztRQU1sQixJQUFJLENBQUMsSUFBSSxHQUFHLFlBQVksQ0FBQyxJQUFJLEVBQUUsUUFBUSxDQUFDLENBQUM7SUFDM0MsQ0FBQztJQUVEOzs7T0FHRztJQUNJLFFBQVE7UUFDYixPQUFPLDRCQUE0QixDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQztJQUNqRCxDQUFDO0lBRUQ7OztPQUdHO0lBQ0ksYUFBYTtRQUNsQixPQUFPLElBQUksQ0FBQyxJQUFJLENBQUM7SUFDbkIsQ0FBQztJQUVEOzs7T0FHRztJQUNJLFlBQVk7UUFDakIsT0FBTyxJQUFJLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxVQUFVLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQztJQUNsRCxDQUFDO0lBRUQ7Ozs7O09BS0c7SUFDSCxNQUFNLENBQUMsVUFBVSxDQUFtQixHQUFXLEVBQUUsTUFBTSxHQUFHLENBQUM7UUFDekQsTUFBTSxFQUFFLElBQUksRUFBRSxHQUFHLFdBQVcsQ0FBQyxXQUFXLENBQUksR0FBRyxFQUFFLE1BQU0sQ0FBQyxDQUFDO1FBQ3pELE9BQU8sSUFBSSxDQUFDO0lBQ2QsQ0FBQztJQUVEOzs7OztPQUtHO0lBQ0gsTUFBTSxDQUFDLFdBQVcsQ0FBbUIsR0FBVyxFQUFFLE1BQU0sR0FBRyxDQUFDO1FBQzFELE1BQU0sZUFBZSxHQUFHLENBQUMsR0FBVyxFQUFFLE1BQWMsRUFBRSxFQUFFLENBQUMsQ0FBQztZQUN4RCxJQUFJLEVBQUUsR0FBRyxDQUFDLEtBQUssQ0FBQyxNQUFNLEVBQUUsTUFBTSxHQUFHLEVBQUUsQ0FBQztZQUNwQyxHQUFHLEVBQUUsRUFBRTtTQUNSLENBQUMsQ0FBQztRQUNILE1BQU0sRUFBRSxJQUFJLEVBQUUsR0FBRyxFQUFFLEdBQUcsMEJBQTBCLENBQUMsZUFBZSxFQUFFLEdBQUcsRUFBRSxNQUFNLENBQUMsQ0FBQztRQUMvRSxNQUFNLElBQUksR0FBRyxJQUFJLENBQUMsTUFBTSxDQUFDO1FBQ3pCLE9BQU8sRUFBRSxJQUFJLEVBQUUsSUFBSSxXQUFXLENBQUksSUFBUyxFQUFFLElBQUksQ0FBQyxFQUFFLEdBQUcsRUFBRSxDQUFDO0lBQzVELENBQUM7SUFFRDs7O09BR0c7SUFDSSxRQUFRO1FBQ2IsT0FBTyxJQUFJLENBQUMsUUFBUSxFQUFFLENBQUMsUUFBUSxDQUFDLEtBQUssQ0FBQyxDQUFDO0lBQ3pDLENBQUM7SUFFRDs7OztPQUlHO0lBQ0ksTUFBTSxDQUFDLFVBQVUsQ0FBbUIsSUFBWTtRQUNyRCxPQUFPLFdBQVcsQ0FBQyxVQUFVLENBQUksTUFBTSxDQUFDLElBQUksQ0FBQyxJQUFJLEVBQUUsS0FBSyxDQUFDLENBQUMsQ0FBQztJQUM3RCxDQUFDO0lBRUQ7Ozs7T0FJRztJQUNJLHFCQUFxQixDQUMxQixhQUE0QjtRQUU1QixtRUFBbUU7UUFDbkUsTUFBTSxXQUFXLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsYUFBYSxDQUFDLENBQUM7UUFDbkQsTUFBTSxlQUFlLEdBQUcsQ0FBQyxJQUFJLENBQUMsUUFBUSxHQUFHLGFBQWEsQ0FBNkIsQ0FBQztRQUNwRixPQUFPLElBQUksV0FBVyxDQUFDLGVBQWUsRUFBRSxXQUFXLENBQUMsQ0FBQztJQUN2RCxDQUFDO0NBQ0YifQ==
@@ -0,0 +1,15 @@
1
+ /// <reference types="node" resolution-mode="require"/>
2
+ import { UpdateOnlyTree } from '../interfaces/update_only_tree.js';
3
+ import { TreeBase } from '../tree_base.js';
4
+ /**
5
+ * A Merkle tree implementation that uses a LevelDB database to store the tree.
6
+ */
7
+ export declare class SparseTree extends TreeBase implements UpdateOnlyTree {
8
+ /**
9
+ * Updates a leaf in the tree.
10
+ * @param leaf - New contents of the leaf.
11
+ * @param index - Index of the leaf to be updated.
12
+ */
13
+ updateLeaf(leaf: Buffer, index: bigint): Promise<void>;
14
+ }
15
+ //# sourceMappingURL=sparse_tree.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sparse_tree.d.ts","sourceRoot":"","sources":["../../src/sparse_tree/sparse_tree.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,mCAAmC,CAAC;AACnE,OAAO,EAAgB,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAEzD;;GAEG;AACH,qBAAa,UAAW,SAAQ,QAAS,YAAW,cAAc;IAChE;;;;OAIG;IACU,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAmBpE"}
@@ -0,0 +1,31 @@
1
+ import { INITIAL_LEAF, TreeBase } from '../tree_base.js';
2
+ /**
3
+ * A Merkle tree implementation that uses a LevelDB database to store the tree.
4
+ */
5
+ export class SparseTree extends TreeBase {
6
+ /**
7
+ * Updates a leaf in the tree.
8
+ * @param leaf - New contents of the leaf.
9
+ * @param index - Index of the leaf to be updated.
10
+ */
11
+ async updateLeaf(leaf, index) {
12
+ if (index > this.maxIndex) {
13
+ throw Error(`Index out of bounds. Index ${index}, max index: ${this.maxIndex}.`);
14
+ }
15
+ const insertingZeroElement = leaf.equals(INITIAL_LEAF);
16
+ const originallyZeroElement = (await this.getLeafValue(index, true))?.equals(INITIAL_LEAF);
17
+ if (insertingZeroElement && originallyZeroElement) {
18
+ return;
19
+ }
20
+ await this.addLeafToCacheAndHashToRoot(leaf, index);
21
+ if (insertingZeroElement) {
22
+ // Deleting element (originally non-zero and new value is zero)
23
+ this.cachedSize = (this.cachedSize ?? this.size) - 1n;
24
+ }
25
+ else if (originallyZeroElement) {
26
+ // Inserting new element (originally zero and new value is non-zero)
27
+ this.cachedSize = (this.cachedSize ?? this.size) + 1n;
28
+ }
29
+ }
30
+ }
31
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3BhcnNlX3RyZWUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvc3BhcnNlX3RyZWUvc3BhcnNlX3RyZWUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQ0EsT0FBTyxFQUFFLFlBQVksRUFBRSxRQUFRLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUV6RDs7R0FFRztBQUNILE1BQU0sT0FBTyxVQUFXLFNBQVEsUUFBUTtJQUN0Qzs7OztPQUlHO0lBQ0ksS0FBSyxDQUFDLFVBQVUsQ0FBQyxJQUFZLEVBQUUsS0FBYTtRQUNqRCxJQUFJLEtBQUssR0FBRyxJQUFJLENBQUMsUUFBUSxFQUFFO1lBQ3pCLE1BQU0sS0FBSyxDQUFDLDhCQUE4QixLQUFLLGdCQUFnQixJQUFJLENBQUMsUUFBUSxHQUFHLENBQUMsQ0FBQztTQUNsRjtRQUVELE1BQU0sb0JBQW9CLEdBQUcsSUFBSSxDQUFDLE1BQU0sQ0FBQyxZQUFZLENBQUMsQ0FBQztRQUN2RCxNQUFNLHFCQUFxQixHQUFHLENBQUMsTUFBTSxJQUFJLENBQUMsWUFBWSxDQUFDLEtBQUssRUFBRSxJQUFJLENBQUMsQ0FBQyxFQUFFLE1BQU0sQ0FBQyxZQUFZLENBQUMsQ0FBQztRQUMzRixJQUFJLG9CQUFvQixJQUFJLHFCQUFxQixFQUFFO1lBQ2pELE9BQU87U0FDUjtRQUNELE1BQU0sSUFBSSxDQUFDLDJCQUEyQixDQUFDLElBQUksRUFBRSxLQUFLLENBQUMsQ0FBQztRQUNwRCxJQUFJLG9CQUFvQixFQUFFO1lBQ3hCLCtEQUErRDtZQUMvRCxJQUFJLENBQUMsVUFBVSxHQUFHLENBQUMsSUFBSSxDQUFDLFVBQVUsSUFBSSxJQUFJLENBQUMsSUFBSSxDQUFDLEdBQUcsRUFBRSxDQUFDO1NBQ3ZEO2FBQU0sSUFBSSxxQkFBcUIsRUFBRTtZQUNoQyxvRUFBb0U7WUFDcEUsSUFBSSxDQUFDLFVBQVUsR0FBRyxDQUFDLElBQUksQ0FBQyxVQUFVLElBQUksSUFBSSxDQUFDLElBQUksQ0FBQyxHQUFHLEVBQUUsQ0FBQztTQUN2RDtJQUNILENBQUM7Q0FDRiJ9
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=sparse_tree.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sparse_tree.test.d.ts","sourceRoot":"","sources":["../../src/sparse_tree/sparse_tree.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,132 @@
1
+ import { default as levelup } from 'levelup';
2
+ import { treeTestSuite } from '../test/test_suite.js';
3
+ import { SparseTree } from './sparse_tree.js';
4
+ import { standardBasedTreeTestSuite } from '../test/standard_based_test_suite.js';
5
+ import { createMemDown } from '../test/utils/create_mem_down.js';
6
+ import { Pedersen } from '../pedersen.js';
7
+ import { randomBytes } from 'crypto';
8
+ import { INITIAL_LEAF, SiblingPath } from '../index.js';
9
+ import { newTree } from '../new_tree.js';
10
+ import { loadTree } from '../load_tree.js';
11
+ import { createLogger } from '@aztec/foundation/log';
12
+ import { CircuitsWasm } from '@aztec/circuits.js';
13
+ const log = createLogger('aztec:sparse_tree_test');
14
+ const createDb = async (levelUp, hasher, name, depth) => {
15
+ return await newTree(SparseTree, levelUp, hasher, name, depth);
16
+ };
17
+ const createFromName = async (levelUp, hasher, name) => {
18
+ return await loadTree(SparseTree, levelUp, hasher, name);
19
+ };
20
+ const TEST_TREE_DEPTH = 3;
21
+ treeTestSuite('SparseTree', createDb, createFromName);
22
+ standardBasedTreeTestSuite('SparseTree', createDb);
23
+ describe('SparseTreeSpecific', () => {
24
+ let wasm;
25
+ let pedersen;
26
+ beforeEach(async () => {
27
+ wasm = await CircuitsWasm.get();
28
+ pedersen = new Pedersen(wasm);
29
+ });
30
+ it('throws when index is bigger than (2^DEPTH - 1) ', async () => {
31
+ const db = levelup(createMemDown());
32
+ const depth = 32;
33
+ const tree = await createDb(db, pedersen, 'test', depth);
34
+ const index = 2n ** BigInt(depth);
35
+ await expect(tree.updateLeaf(Buffer.alloc(32), index)).rejects.toThrow();
36
+ });
37
+ it('updating non-empty leaf does not change tree size', async () => {
38
+ const depth = 32;
39
+ const maxIndex = 2 ** depth - 1;
40
+ const db = levelup(createMemDown());
41
+ const tree = await createDb(db, pedersen, 'test', depth);
42
+ const randomIndex = BigInt(Math.floor(Math.random() * maxIndex));
43
+ expect(tree.getNumLeaves(false)).toEqual(0n);
44
+ // Insert a leaf
45
+ await tree.updateLeaf(randomBytes(32), randomIndex);
46
+ expect(tree.getNumLeaves(true)).toEqual(1n);
47
+ // Update a leaf
48
+ await tree.updateLeaf(randomBytes(32), randomIndex);
49
+ expect(tree.getNumLeaves(true)).toEqual(1n);
50
+ });
51
+ it('deleting leaf decrements tree size', async () => {
52
+ const depth = 254;
53
+ const maxIndex = 2 ** depth - 1;
54
+ const db = levelup(createMemDown());
55
+ const tree = await createDb(db, pedersen, 'test', depth);
56
+ const randomIndex = BigInt(Math.floor(Math.random() * maxIndex));
57
+ expect(tree.getNumLeaves(false)).toEqual(0n);
58
+ // Insert a leaf
59
+ await tree.updateLeaf(randomBytes(32), randomIndex);
60
+ expect(tree.getNumLeaves(true)).toEqual(1n);
61
+ // Delete a leaf
62
+ await tree.updateLeaf(INITIAL_LEAF, randomIndex);
63
+ expect(tree.getNumLeaves(true)).toEqual(0n);
64
+ });
65
+ it('should have correct root and sibling path after in a "non-append-only" way', async () => {
66
+ const db = levelup(createMemDown());
67
+ const tree = await createDb(db, pedersen, 'test', 3);
68
+ const level2ZeroHash = pedersen.compress(INITIAL_LEAF, INITIAL_LEAF);
69
+ const level1ZeroHash = pedersen.compress(level2ZeroHash, level2ZeroHash);
70
+ expect(tree.getNumLeaves(false)).toEqual(0n);
71
+ expect(tree.getRoot(false)).toEqual(pedersen.compress(level1ZeroHash, level1ZeroHash));
72
+ // Insert leaf at index 3
73
+ let level1LeftHash;
74
+ const leafAtIndex3 = randomBytes(32);
75
+ {
76
+ await tree.updateLeaf(leafAtIndex3, 3n);
77
+ expect(tree.getNumLeaves(true)).toEqual(1n);
78
+ const level2Hash = pedersen.compress(INITIAL_LEAF, leafAtIndex3);
79
+ level1LeftHash = pedersen.compress(level2ZeroHash, level2Hash);
80
+ const root = pedersen.compress(level1LeftHash, level1ZeroHash);
81
+ expect(tree.getRoot(true)).toEqual(root);
82
+ expect(await tree.getSiblingPath(3n, true)).toEqual(new SiblingPath(TEST_TREE_DEPTH, [INITIAL_LEAF, level2ZeroHash, level1ZeroHash]));
83
+ }
84
+ // Insert leaf at index 6
85
+ let level1RightHash;
86
+ {
87
+ const leafAtIndex6 = randomBytes(32);
88
+ await tree.updateLeaf(leafAtIndex6, 6n);
89
+ expect(tree.getNumLeaves(true)).toEqual(2n);
90
+ const level2Hash = pedersen.compress(leafAtIndex6, INITIAL_LEAF);
91
+ level1RightHash = pedersen.compress(level2ZeroHash, level2Hash);
92
+ const root = pedersen.compress(level1LeftHash, level1RightHash);
93
+ expect(tree.getRoot(true)).toEqual(root);
94
+ expect(await tree.getSiblingPath(6n, true)).toEqual(new SiblingPath(TEST_TREE_DEPTH, [INITIAL_LEAF, level2ZeroHash, level1LeftHash]));
95
+ }
96
+ // Insert leaf at index 2
97
+ const leafAtIndex2 = randomBytes(32);
98
+ {
99
+ await tree.updateLeaf(leafAtIndex2, 2n);
100
+ expect(tree.getNumLeaves(true)).toEqual(3n);
101
+ const level2Hash = pedersen.compress(leafAtIndex2, leafAtIndex3);
102
+ level1LeftHash = pedersen.compress(level2ZeroHash, level2Hash);
103
+ const root = pedersen.compress(level1LeftHash, level1RightHash);
104
+ expect(tree.getRoot(true)).toEqual(root);
105
+ expect(await tree.getSiblingPath(2n, true)).toEqual(new SiblingPath(TEST_TREE_DEPTH, [leafAtIndex3, level2ZeroHash, level1RightHash]));
106
+ }
107
+ // Updating leaf at index 3
108
+ {
109
+ const updatedLeafAtIndex3 = randomBytes(32);
110
+ await tree.updateLeaf(updatedLeafAtIndex3, 3n);
111
+ expect(tree.getNumLeaves(true)).toEqual(3n);
112
+ const level2Hash = pedersen.compress(leafAtIndex2, updatedLeafAtIndex3);
113
+ level1LeftHash = pedersen.compress(level2ZeroHash, level2Hash);
114
+ const root = pedersen.compress(level1LeftHash, level1RightHash);
115
+ expect(tree.getRoot(true)).toEqual(root);
116
+ expect(await tree.getSiblingPath(3n, true)).toEqual(new SiblingPath(TEST_TREE_DEPTH, [leafAtIndex2, level2ZeroHash, level1RightHash]));
117
+ }
118
+ });
119
+ it.skip('measures time of inserting 1000 leaves at random positions for depth 254', async () => {
120
+ const depth = 254;
121
+ const maxIndex = 2 ** depth - 1;
122
+ const db = levelup(createMemDown());
123
+ const tree = await createDb(db, pedersen, 'test', depth);
124
+ const leaves = Array.from({ length: 1000 }).map(() => randomBytes(32));
125
+ const indices = Array.from({ length: 1000 }).map(() => BigInt(Math.floor(Math.random() * maxIndex)));
126
+ const start = Date.now();
127
+ await Promise.all(leaves.map((leaf, i) => tree.updateLeaf(leaf, indices[i])));
128
+ const end = Date.now();
129
+ log(`Inserting 1000 leaves at random positions for depth 254 took ${end - start}ms`);
130
+ }, 300000);
131
+ });
132
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3BhcnNlX3RyZWUudGVzdC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9zcGFyc2VfdHJlZS9zcGFyc2VfdHJlZS50ZXN0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxPQUFPLElBQUksT0FBTyxFQUFFLE1BQU0sU0FBUyxDQUFDO0FBRTdDLE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSx1QkFBdUIsQ0FBQztBQUN0RCxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sa0JBQWtCLENBQUM7QUFDOUMsT0FBTyxFQUFFLDBCQUEwQixFQUFFLE1BQU0sc0NBQXNDLENBQUM7QUFDbEYsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLGtDQUFrQyxDQUFDO0FBQ2pFLE9BQU8sRUFBRSxRQUFRLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUMxQyxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0sUUFBUSxDQUFDO0FBQ3JDLE9BQU8sRUFBRSxZQUFZLEVBQUUsV0FBVyxFQUFFLE1BQU0sYUFBYSxDQUFDO0FBRXhELE9BQU8sRUFBRSxPQUFPLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUN6QyxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDM0MsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLHVCQUF1QixDQUFDO0FBRXJELE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUVsRCxNQUFNLEdBQUcsR0FBRyxZQUFZLENBQUMsd0JBQXdCLENBQUMsQ0FBQztBQUVuRCxNQUFNLFFBQVEsR0FBRyxLQUFLLEVBQ3BCLE9BQXdCLEVBQ3hCLE1BQWMsRUFDZCxJQUFZLEVBQ1osS0FBYSxFQUNZLEVBQUU7SUFDM0IsT0FBTyxNQUFNLE9BQU8sQ0FBQyxVQUFVLEVBQUUsT0FBTyxFQUFFLE1BQU0sRUFBRSxJQUFJLEVBQUUsS0FBSyxDQUFDLENBQUM7QUFDakUsQ0FBQyxDQUFDO0FBRUYsTUFBTSxjQUFjLEdBQUcsS0FBSyxFQUFFLE9BQXdCLEVBQUUsTUFBYyxFQUFFLElBQVksRUFBMkIsRUFBRTtJQUMvRyxPQUFPLE1BQU0sUUFBUSxDQUFDLFVBQVUsRUFBRSxPQUFPLEVBQUUsTUFBTSxFQUFFLElBQUksQ0FBQyxDQUFDO0FBQzNELENBQUMsQ0FBQztBQUVGLE1BQU0sZUFBZSxHQUFHLENBQUMsQ0FBQztBQUUxQixhQUFhLENBQUMsWUFBWSxFQUFFLFFBQVEsRUFBRSxjQUFjLENBQUMsQ0FBQztBQUN0RCwwQkFBMEIsQ0FBQyxZQUFZLEVBQUUsUUFBUSxDQUFDLENBQUM7QUFFbkQsUUFBUSxDQUFDLG9CQUFvQixFQUFFLEdBQUcsRUFBRTtJQUNsQyxJQUFJLElBQWlCLENBQUM7SUFDdEIsSUFBSSxRQUFrQixDQUFDO0lBRXZCLFVBQVUsQ0FBQyxLQUFLLElBQUksRUFBRTtRQUNwQixJQUFJLEdBQUcsTUFBTSxZQUFZLENBQUMsR0FBRyxFQUFFLENBQUM7UUFDaEMsUUFBUSxHQUFHLElBQUksUUFBUSxDQUFDLElBQUksQ0FBQyxDQUFDO0lBQ2hDLENBQUMsQ0FBQyxDQUFDO0lBRUgsRUFBRSxDQUFDLGlEQUFpRCxFQUFFLEtBQUssSUFBSSxFQUFFO1FBQy9ELE1BQU0sRUFBRSxHQUFHLE9BQU8sQ0FBQyxhQUFhLEVBQUUsQ0FBQyxDQUFDO1FBQ3BDLE1BQU0sS0FBSyxHQUFHLEVBQUUsQ0FBQztRQUNqQixNQUFNLElBQUksR0FBRyxNQUFNLFFBQVEsQ0FBQyxFQUFFLEVBQUUsUUFBUSxFQUFFLE1BQU0sRUFBRSxLQUFLLENBQUMsQ0FBQztRQUV6RCxNQUFNLEtBQUssR0FBRyxFQUFFLElBQUksTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBQ2xDLE1BQU0sTUFBTSxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUMsRUFBRSxLQUFLLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxPQUFPLEVBQUUsQ0FBQztJQUMzRSxDQUFDLENBQUMsQ0FBQztJQUVILEVBQUUsQ0FBQyxtREFBbUQsRUFBRSxLQUFLLElBQUksRUFBRTtRQUNqRSxNQUFNLEtBQUssR0FBRyxFQUFFLENBQUM7UUFDakIsTUFBTSxRQUFRLEdBQUcsQ0FBQyxJQUFJLEtBQUssR0FBRyxDQUFDLENBQUM7UUFFaEMsTUFBTSxFQUFFLEdBQUcsT0FBTyxDQUFDLGFBQWEsRUFBRSxDQUFDLENBQUM7UUFDcEMsTUFBTSxJQUFJLEdBQUcsTUFBTSxRQUFRLENBQUMsRUFBRSxFQUFFLFFBQVEsRUFBRSxNQUFNLEVBQUUsS0FBSyxDQUFDLENBQUM7UUFFekQsTUFBTSxXQUFXLEdBQUcsTUFBTSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLE1BQU0sRUFBRSxHQUFHLFFBQVEsQ0FBQyxDQUFDLENBQUM7UUFDakUsTUFBTSxDQUFDLElBQUksQ0FBQyxZQUFZLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxPQUFPLENBQUMsRUFBRSxDQUFDLENBQUM7UUFFN0MsZ0JBQWdCO1FBQ2hCLE1BQU0sSUFBSSxDQUFDLFVBQVUsQ0FBQyxXQUFXLENBQUMsRUFBRSxDQUFDLEVBQUUsV0FBVyxDQUFDLENBQUM7UUFDcEQsTUFBTSxDQUFDLElBQUksQ0FBQyxZQUFZLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxPQUFPLENBQUMsRUFBRSxDQUFDLENBQUM7UUFFNUMsZ0JBQWdCO1FBQ2hCLE1BQU0sSUFBSSxDQUFDLFVBQVUsQ0FBQyxXQUFXLENBQUMsRUFBRSxDQUFDLEVBQUUsV0FBVyxDQUFDLENBQUM7UUFDcEQsTUFBTSxDQUFDLElBQUksQ0FBQyxZQUFZLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxPQUFPLENBQUMsRUFBRSxDQUFDLENBQUM7SUFDOUMsQ0FBQyxDQUFDLENBQUM7SUFFSCxFQUFFLENBQUMsb0NBQW9DLEVBQUUsS0FBSyxJQUFJLEVBQUU7UUFDbEQsTUFBTSxLQUFLLEdBQUcsR0FBRyxDQUFDO1FBQ2xCLE1BQU0sUUFBUSxHQUFHLENBQUMsSUFBSSxLQUFLLEdBQUcsQ0FBQyxDQUFDO1FBRWhDLE1BQU0sRUFBRSxHQUFHLE9BQU8sQ0FBQyxhQUFhLEVBQUUsQ0FBQyxDQUFDO1FBQ3BDLE1BQU0sSUFBSSxHQUFHLE1BQU0sUUFBUSxDQUFDLEVBQUUsRUFBRSxRQUFRLEVBQUUsTUFBTSxFQUFFLEtBQUssQ0FBQyxDQUFDO1FBRXpELE1BQU0sV0FBVyxHQUFHLE1BQU0sQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxNQUFNLEVBQUUsR0FBRyxRQUFRLENBQUMsQ0FBQyxDQUFDO1FBQ2pFLE1BQU0sQ0FBQyxJQUFJLENBQUMsWUFBWSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQyxDQUFDO1FBRTdDLGdCQUFnQjtRQUNoQixNQUFNLElBQUksQ0FBQyxVQUFVLENBQUMsV0FBVyxDQUFDLEVBQUUsQ0FBQyxFQUFFLFdBQVcsQ0FBQyxDQUFDO1FBQ3BELE1BQU0sQ0FBQyxJQUFJLENBQUMsWUFBWSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQyxDQUFDO1FBRTVDLGdCQUFnQjtRQUNoQixNQUFNLElBQUksQ0FBQyxVQUFVLENBQUMsWUFBWSxFQUFFLFdBQVcsQ0FBQyxDQUFDO1FBQ2pELE1BQU0sQ0FBQyxJQUFJLENBQUMsWUFBWSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQyxDQUFDO0lBQzlDLENBQUMsQ0FBQyxDQUFDO0lBRUgsRUFBRSxDQUFDLDRFQUE0RSxFQUFFLEtBQUssSUFBSSxFQUFFO1FBQzFGLE1BQU0sRUFBRSxHQUFHLE9BQU8sQ0FBQyxhQUFhLEVBQUUsQ0FBQyxDQUFDO1FBQ3BDLE1BQU0sSUFBSSxHQUFHLE1BQU0sUUFBUSxDQUFDLEVBQUUsRUFBRSxRQUFRLEVBQUUsTUFBTSxFQUFFLENBQUMsQ0FBQyxDQUFDO1FBRXJELE1BQU0sY0FBYyxHQUFHLFFBQVEsQ0FBQyxRQUFRLENBQUMsWUFBWSxFQUFFLFlBQVksQ0FBQyxDQUFDO1FBQ3JFLE1BQU0sY0FBYyxHQUFHLFFBQVEsQ0FBQyxRQUFRLENBQUMsY0FBYyxFQUFFLGNBQWMsQ0FBQyxDQUFDO1FBRXpFLE1BQU0sQ0FBQyxJQUFJLENBQUMsWUFBWSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQyxDQUFDO1FBQzdDLE1BQU0sQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxRQUFRLENBQUMsY0FBYyxFQUFFLGNBQWMsQ0FBQyxDQUFDLENBQUM7UUFFdkYseUJBQXlCO1FBQ3pCLElBQUksY0FBc0IsQ0FBQztRQUMzQixNQUFNLFlBQVksR0FBRyxXQUFXLENBQUMsRUFBRSxDQUFDLENBQUM7UUFDckM7WUFDRSxNQUFNLElBQUksQ0FBQyxVQUFVLENBQUMsWUFBWSxFQUFFLEVBQUUsQ0FBQyxDQUFDO1lBQ3hDLE1BQU0sQ0FBQyxJQUFJLENBQUMsWUFBWSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQyxDQUFDO1lBQzVDLE1BQU0sVUFBVSxHQUFHLFFBQVEsQ0FBQyxRQUFRLENBQUMsWUFBWSxFQUFFLFlBQVksQ0FBQyxDQUFDO1lBQ2pFLGNBQWMsR0FBRyxRQUFRLENBQUMsUUFBUSxDQUFDLGNBQWMsRUFBRSxVQUFVLENBQUMsQ0FBQztZQUMvRCxNQUFNLElBQUksR0FBRyxRQUFRLENBQUMsUUFBUSxDQUFDLGNBQWMsRUFBRSxjQUFjLENBQUMsQ0FBQztZQUMvRCxNQUFNLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQztZQUN6QyxNQUFNLENBQUMsTUFBTSxJQUFJLENBQUMsY0FBYyxDQUFDLEVBQUUsRUFBRSxJQUFJLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FDakQsSUFBSSxXQUFXLENBQUMsZUFBZSxFQUFFLENBQUMsWUFBWSxFQUFFLGNBQWMsRUFBRSxjQUFjLENBQUMsQ0FBQyxDQUNqRixDQUFDO1NBQ0g7UUFFRCx5QkFBeUI7UUFDekIsSUFBSSxlQUF1QixDQUFDO1FBQzVCO1lBQ0UsTUFBTSxZQUFZLEdBQUcsV0FBVyxDQUFDLEVBQUUsQ0FBQyxDQUFDO1lBQ3JDLE1BQU0sSUFBSSxDQUFDLFVBQVUsQ0FBQyxZQUFZLEVBQUUsRUFBRSxDQUFDLENBQUM7WUFDeEMsTUFBTSxDQUFDLElBQUksQ0FBQyxZQUFZLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxPQUFPLENBQUMsRUFBRSxDQUFDLENBQUM7WUFDNUMsTUFBTSxVQUFVLEdBQUcsUUFBUSxDQUFDLFFBQVEsQ0FBQyxZQUFZLEVBQUUsWUFBWSxDQUFDLENBQUM7WUFDakUsZUFBZSxHQUFHLFFBQVEsQ0FBQyxRQUFRLENBQUMsY0FBYyxFQUFFLFVBQVUsQ0FBQyxDQUFDO1lBQ2hFLE1BQU0sSUFBSSxHQUFHLFFBQVEsQ0FBQyxRQUFRLENBQUMsY0FBYyxFQUFFLGVBQWUsQ0FBQyxDQUFDO1lBQ2hFLE1BQU0sQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDO1lBQ3pDLE1BQU0sQ0FBQyxNQUFNLElBQUksQ0FBQyxjQUFjLENBQUMsRUFBRSxFQUFFLElBQUksQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUNqRCxJQUFJLFdBQVcsQ0FBQyxlQUFlLEVBQUUsQ0FBQyxZQUFZLEVBQUUsY0FBYyxFQUFFLGNBQWMsQ0FBQyxDQUFDLENBQ2pGLENBQUM7U0FDSDtRQUVELHlCQUF5QjtRQUN6QixNQUFNLFlBQVksR0FBRyxXQUFXLENBQUMsRUFBRSxDQUFDLENBQUM7UUFDckM7WUFDRSxNQUFNLElBQUksQ0FBQyxVQUFVLENBQUMsWUFBWSxFQUFFLEVBQUUsQ0FBQyxDQUFDO1lBQ3hDLE1BQU0sQ0FBQyxJQUFJLENBQUMsWUFBWSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQyxDQUFDO1lBQzVDLE1BQU0sVUFBVSxHQUFHLFFBQVEsQ0FBQyxRQUFRLENBQUMsWUFBWSxFQUFFLFlBQVksQ0FBQyxDQUFDO1lBQ2pFLGNBQWMsR0FBRyxRQUFRLENBQUMsUUFBUSxDQUFDLGNBQWMsRUFBRSxVQUFVLENBQUMsQ0FBQztZQUMvRCxNQUFNLElBQUksR0FBRyxRQUFRLENBQUMsUUFBUSxDQUFDLGNBQWMsRUFBRSxlQUFlLENBQUMsQ0FBQztZQUNoRSxNQUFNLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQztZQUN6QyxNQUFNLENBQUMsTUFBTSxJQUFJLENBQUMsY0FBYyxDQUFDLEVBQUUsRUFBRSxJQUFJLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FDakQsSUFBSSxXQUFXLENBQUMsZUFBZSxFQUFFLENBQUMsWUFBWSxFQUFFLGNBQWMsRUFBRSxlQUFlLENBQUMsQ0FBQyxDQUNsRixDQUFDO1NBQ0g7UUFFRCwyQkFBMkI7UUFDM0I7WUFDRSxNQUFNLG1CQUFtQixHQUFHLFdBQVcsQ0FBQyxFQUFFLENBQUMsQ0FBQztZQUM1QyxNQUFNLElBQUksQ0FBQyxVQUFVLENBQUMsbUJBQW1CLEVBQUUsRUFBRSxDQUFDLENBQUM7WUFDL0MsTUFBTSxDQUFDLElBQUksQ0FBQyxZQUFZLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxPQUFPLENBQUMsRUFBRSxDQUFDLENBQUM7WUFDNUMsTUFBTSxVQUFVLEdBQUcsUUFBUSxDQUFDLFFBQVEsQ0FBQyxZQUFZLEVBQUUsbUJBQW1CLENBQUMsQ0FBQztZQUN4RSxjQUFjLEdBQUcsUUFBUSxDQUFDLFFBQVEsQ0FBQyxjQUFjLEVBQUUsVUFBVSxDQUFDLENBQUM7WUFDL0QsTUFBTSxJQUFJLEdBQUcsUUFBUSxDQUFDLFFBQVEsQ0FBQyxjQUFjLEVBQUUsZUFBZSxDQUFDLENBQUM7WUFDaEUsTUFBTSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLENBQUM7WUFDekMsTUFBTSxDQUFDLE1BQU0sSUFBSSxDQUFDLGNBQWMsQ0FBQyxFQUFFLEVBQUUsSUFBSSxDQUFDLENBQUMsQ0FBQyxPQUFPLENBQ2pELElBQUksV0FBVyxDQUFDLGVBQWUsRUFBRSxDQUFDLFlBQVksRUFBRSxjQUFjLEVBQUUsZUFBZSxDQUFDLENBQUMsQ0FDbEYsQ0FBQztTQUNIO0lBQ0gsQ0FBQyxDQUFDLENBQUM7SUFFSCxFQUFFLENBQUMsSUFBSSxDQUFDLDBFQUEwRSxFQUFFLEtBQUssSUFBSSxFQUFFO1FBQzdGLE1BQU0sS0FBSyxHQUFHLEdBQUcsQ0FBQztRQUNsQixNQUFNLFFBQVEsR0FBRyxDQUFDLElBQUksS0FBSyxHQUFHLENBQUMsQ0FBQztRQUVoQyxNQUFNLEVBQUUsR0FBRyxPQUFPLENBQUMsYUFBYSxFQUFFLENBQUMsQ0FBQztRQUNwQyxNQUFNLElBQUksR0FBRyxNQUFNLFFBQVEsQ0FBQyxFQUFFLEVBQUUsUUFBUSxFQUFFLE1BQU0sRUFBRSxLQUFLLENBQUMsQ0FBQztRQUV6RCxNQUFNLE1BQU0sR0FBRyxLQUFLLENBQUMsSUFBSSxDQUFDLEVBQUUsTUFBTSxFQUFFLElBQUksRUFBRSxDQUFDLENBQUMsR0FBRyxDQUFDLEdBQUcsRUFBRSxDQUFDLFdBQVcsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDO1FBQ3ZFLE1BQU0sT0FBTyxHQUFHLEtBQUssQ0FBQyxJQUFJLENBQUMsRUFBRSxNQUFNLEVBQUUsSUFBSSxFQUFFLENBQUMsQ0FBQyxHQUFHLENBQUMsR0FBRyxFQUFFLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLE1BQU0sRUFBRSxHQUFHLFFBQVEsQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUVyRyxNQUFNLEtBQUssR0FBRyxJQUFJLENBQUMsR0FBRyxFQUFFLENBQUM7UUFDekIsTUFBTSxPQUFPLENBQUMsR0FBRyxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQyxJQUFJLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLElBQUksRUFBRSxPQUFPLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDOUUsTUFBTSxHQUFHLEdBQUcsSUFBSSxDQUFDLEdBQUcsRUFBRSxDQUFDO1FBQ3ZCLEdBQUcsQ0FBQyxnRUFBZ0UsR0FBRyxHQUFHLEtBQUssSUFBSSxDQUFDLENBQUM7SUFDdkYsQ0FBQyxFQUFFLE1BQU8sQ0FBQyxDQUFDO0FBQ2QsQ0FBQyxDQUFDLENBQUMifQ==