@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.
- package/.eslintrc.cjs +1 -0
- package/.tsbuildinfo +1 -0
- package/README.md +41 -0
- package/dest/hasher.d.ts +11 -0
- package/dest/hasher.d.ts.map +1 -0
- package/dest/hasher.js +2 -0
- package/dest/index.d.ts +14 -0
- package/dest/index.d.ts.map +1 -0
- package/dest/index.js +14 -0
- package/dest/interfaces/append_only_tree.d.ts +13 -0
- package/dest/interfaces/append_only_tree.d.ts.map +1 -0
- package/dest/interfaces/append_only_tree.js +2 -0
- package/dest/interfaces/indexed_tree.d.ts +63 -0
- package/dest/interfaces/indexed_tree.d.ts.map +1 -0
- package/dest/interfaces/indexed_tree.js +2 -0
- package/dest/interfaces/merkle_tree.d.ts +47 -0
- package/dest/interfaces/merkle_tree.d.ts.map +1 -0
- package/dest/interfaces/merkle_tree.js +2 -0
- package/dest/interfaces/update_only_tree.d.ts +15 -0
- package/dest/interfaces/update_only_tree.d.ts.map +1 -0
- package/dest/interfaces/update_only_tree.js +2 -0
- package/dest/load_tree.d.ts +13 -0
- package/dest/load_tree.d.ts.map +1 -0
- package/dest/load_tree.js +17 -0
- package/dest/new_tree.d.ts +15 -0
- package/dest/new_tree.d.ts.map +1 -0
- package/dest/new_tree.js +16 -0
- package/dest/pedersen.d.ts +42 -0
- package/dest/pedersen.d.ts.map +1 -0
- package/dest/pedersen.js +49 -0
- package/dest/sibling_path/sibling_path.d.ts +92 -0
- package/dest/sibling_path/sibling_path.d.ts.map +1 -0
- package/dest/sibling_path/sibling_path.js +120 -0
- package/dest/sparse_tree/sparse_tree.d.ts +15 -0
- package/dest/sparse_tree/sparse_tree.d.ts.map +1 -0
- package/dest/sparse_tree/sparse_tree.js +31 -0
- package/dest/sparse_tree/sparse_tree.test.d.ts +2 -0
- package/dest/sparse_tree/sparse_tree.test.d.ts.map +1 -0
- package/dest/sparse_tree/sparse_tree.test.js +132 -0
- package/dest/standard_indexed_tree/standard_indexed_tree.d.ts +230 -0
- package/dest/standard_indexed_tree/standard_indexed_tree.d.ts.map +1 -0
- package/dest/standard_indexed_tree/standard_indexed_tree.js +497 -0
- package/dest/standard_indexed_tree/standard_indexed_tree.test.d.ts +2 -0
- package/dest/standard_indexed_tree/standard_indexed_tree.test.d.ts.map +1 -0
- package/dest/standard_indexed_tree/standard_indexed_tree.test.js +316 -0
- package/dest/standard_tree/standard_tree.d.ts +25 -0
- package/dest/standard_tree/standard_tree.d.ts.map +1 -0
- package/dest/standard_tree/standard_tree.js +50 -0
- package/dest/standard_tree/standard_tree.test.d.ts +2 -0
- package/dest/standard_tree/standard_tree.test.d.ts.map +1 -0
- package/dest/standard_tree/standard_tree.test.js +58 -0
- package/dest/test/standard_based_test_suite.d.ts +6 -0
- package/dest/test/standard_based_test_suite.d.ts.map +1 -0
- package/dest/test/standard_based_test_suite.js +86 -0
- package/dest/test/test_suite.d.ts +6 -0
- package/dest/test/test_suite.d.ts.map +1 -0
- package/dest/test/test_suite.js +118 -0
- package/dest/test/utils/append_leaves.d.ts +5 -0
- package/dest/test/utils/append_leaves.d.ts.map +1 -0
- package/dest/test/utils/append_leaves.js +14 -0
- package/dest/test/utils/create_mem_down.d.ts +3 -0
- package/dest/test/utils/create_mem_down.d.ts.map +1 -0
- package/dest/test/utils/create_mem_down.js +3 -0
- package/dest/test/utils/pedersen_with_counter.d.ts +24 -0
- package/dest/test/utils/pedersen_with_counter.d.ts.map +1 -0
- package/dest/test/utils/pedersen_with_counter.js +31 -0
- package/dest/tree_base.d.ts +118 -0
- package/dest/tree_base.d.ts.map +1 -0
- package/dest/tree_base.js +214 -0
- package/package.json +14 -0
- package/package.local.json +3 -0
- package/src/hasher.ts +9 -0
- package/src/index.ts +13 -0
- package/src/interfaces/append_only_tree.ts +12 -0
- package/src/interfaces/indexed_tree.ts +78 -0
- package/src/interfaces/merkle_tree.ts +52 -0
- package/src/interfaces/update_only_tree.ts +15 -0
- package/src/load_tree.ts +24 -0
- package/src/new_tree.ts +26 -0
- package/src/pedersen.ts +58 -0
- package/src/sibling_path/sibling_path.ts +139 -0
- package/src/sparse_tree/sparse_tree.test.ts +177 -0
- package/src/sparse_tree/sparse_tree.ts +32 -0
- package/src/standard_indexed_tree/standard_indexed_tree.test.ts +450 -0
- package/src/standard_indexed_tree/standard_indexed_tree.ts +591 -0
- package/src/standard_tree/standard_tree.test.ts +74 -0
- package/src/standard_tree/standard_tree.ts +54 -0
- package/src/test/standard_based_test_suite.ts +139 -0
- package/src/test/test_suite.ts +162 -0
- package/src/test/utils/append_leaves.ts +15 -0
- package/src/test/utils/create_mem_down.ts +3 -0
- package/src/test/utils/pedersen_with_counter.ts +30 -0
- package/src/tree_base.ts +242 -0
- package/tsconfig.json +17 -0
|
@@ -0,0 +1,497 @@
|
|
|
1
|
+
import { toBigIntBE, toBufferBE } from '@aztec/foundation/bigint-buffer';
|
|
2
|
+
import { createLogger } from '@aztec/foundation/log';
|
|
3
|
+
import { TreeBase } from '../tree_base.js';
|
|
4
|
+
import { SiblingPath } from '../index.js';
|
|
5
|
+
const log = createLogger('aztec:standard-indexed-tree');
|
|
6
|
+
const indexToKeyLeaf = (name, index) => {
|
|
7
|
+
return `${name}:leaf:${index}`;
|
|
8
|
+
};
|
|
9
|
+
const zeroLeaf = {
|
|
10
|
+
value: 0n,
|
|
11
|
+
nextValue: 0n,
|
|
12
|
+
nextIndex: 0n,
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* Pre-compute empty witness.
|
|
16
|
+
* @param treeHeight - Height of tree for sibling path.
|
|
17
|
+
* @returns An empty witness.
|
|
18
|
+
*/
|
|
19
|
+
function getEmptyLowLeafWitness(treeHeight) {
|
|
20
|
+
return {
|
|
21
|
+
leafData: zeroLeaf,
|
|
22
|
+
index: 0n,
|
|
23
|
+
siblingPath: new SiblingPath(treeHeight, Array(treeHeight).fill(toBufferBE(0n, 32))),
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
27
|
+
const encodeTreeValue = (leafData) => {
|
|
28
|
+
const valueAsBuffer = toBufferBE(leafData.value, 32);
|
|
29
|
+
const indexAsBuffer = toBufferBE(leafData.nextIndex, 32);
|
|
30
|
+
const nextValueAsBuffer = toBufferBE(leafData.nextValue, 32);
|
|
31
|
+
return Buffer.concat([valueAsBuffer, indexAsBuffer, nextValueAsBuffer]);
|
|
32
|
+
};
|
|
33
|
+
const hashEncodedTreeValue = (leaf, hasher) => {
|
|
34
|
+
return hasher.compressInputs([leaf.value, leaf.nextIndex, leaf.nextValue].map(val => toBufferBE(val, 32)));
|
|
35
|
+
};
|
|
36
|
+
const decodeTreeValue = (buf) => {
|
|
37
|
+
const value = toBigIntBE(buf.subarray(0, 32));
|
|
38
|
+
const nextIndex = toBigIntBE(buf.subarray(32, 64));
|
|
39
|
+
const nextValue = toBigIntBE(buf.subarray(64, 96));
|
|
40
|
+
return {
|
|
41
|
+
value,
|
|
42
|
+
nextIndex,
|
|
43
|
+
nextValue,
|
|
44
|
+
};
|
|
45
|
+
};
|
|
46
|
+
const initialLeaf = {
|
|
47
|
+
value: 0n,
|
|
48
|
+
nextIndex: 0n,
|
|
49
|
+
nextValue: 0n,
|
|
50
|
+
};
|
|
51
|
+
/**
|
|
52
|
+
* Indexed merkle tree.
|
|
53
|
+
*/
|
|
54
|
+
export class StandardIndexedTree extends TreeBase {
|
|
55
|
+
constructor() {
|
|
56
|
+
super(...arguments);
|
|
57
|
+
this.leaves = [];
|
|
58
|
+
this.cachedLeaves = {};
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Appends the given leaves to the tree.
|
|
62
|
+
* @param leaves - The leaves to append.
|
|
63
|
+
* @returns Empty promise.
|
|
64
|
+
*/
|
|
65
|
+
async appendLeaves(leaves) {
|
|
66
|
+
for (const leaf of leaves) {
|
|
67
|
+
await this.appendLeaf(leaf);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Commits the changes to the database.
|
|
72
|
+
* @returns Empty promise.
|
|
73
|
+
*/
|
|
74
|
+
async commit() {
|
|
75
|
+
await super.commit();
|
|
76
|
+
await this.commitLeaves();
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Rolls back the not-yet-committed changes.
|
|
80
|
+
* @returns Empty promise.
|
|
81
|
+
*/
|
|
82
|
+
async rollback() {
|
|
83
|
+
await super.rollback();
|
|
84
|
+
this.clearCachedLeaves();
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Gets the value of the leaf at the given index.
|
|
88
|
+
* @param index - Index of the leaf of which to obtain the value.
|
|
89
|
+
* @param includeUncommitted - Indicates whether to include uncommitted leaves in the computation.
|
|
90
|
+
* @returns The value of the leaf at the given index or undefined if the leaf is empty.
|
|
91
|
+
*/
|
|
92
|
+
getLeafValue(index, includeUncommitted) {
|
|
93
|
+
const leaf = this.getLatestLeafDataCopy(Number(index), includeUncommitted);
|
|
94
|
+
if (!leaf)
|
|
95
|
+
return Promise.resolve(undefined);
|
|
96
|
+
return Promise.resolve(toBufferBE(leaf.value, 32));
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Finds the index of the largest leaf whose value is less than or equal to the provided value.
|
|
100
|
+
* @param newValue - The new value to be inserted into the tree.
|
|
101
|
+
* @param includeUncommitted - If true, the uncommitted changes are included in the search.
|
|
102
|
+
* @returns The found leaf index and a flag indicating if the corresponding leaf's value is equal to `newValue`.
|
|
103
|
+
*/
|
|
104
|
+
findIndexOfPreviousValue(newValue, includeUncommitted) {
|
|
105
|
+
const numLeaves = this.getNumLeaves(includeUncommitted);
|
|
106
|
+
const diff = [];
|
|
107
|
+
for (let i = 0; i < numLeaves; i++) {
|
|
108
|
+
const storedLeaf = this.getLatestLeafDataCopy(i, includeUncommitted);
|
|
109
|
+
// The stored leaf can be undefined if it addresses an empty leaf
|
|
110
|
+
// If the leaf is empty we do the same as if the leaf was larger
|
|
111
|
+
if (storedLeaf === undefined) {
|
|
112
|
+
diff.push(newValue);
|
|
113
|
+
}
|
|
114
|
+
else if (storedLeaf.value > newValue) {
|
|
115
|
+
diff.push(newValue);
|
|
116
|
+
}
|
|
117
|
+
else if (storedLeaf.value === newValue) {
|
|
118
|
+
return { index: i, alreadyPresent: true };
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
diff.push(newValue - storedLeaf.value);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
const minIndex = this.findMinIndex(diff);
|
|
125
|
+
return { index: minIndex, alreadyPresent: false };
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Gets the latest LeafData copy.
|
|
129
|
+
* @param index - Index of the leaf of which to obtain the LeafData copy.
|
|
130
|
+
* @param includeUncommitted - If true, the uncommitted changes are included in the search.
|
|
131
|
+
* @returns A copy of the leaf data at the given index or undefined if the leaf was not found.
|
|
132
|
+
*/
|
|
133
|
+
getLatestLeafDataCopy(index, includeUncommitted) {
|
|
134
|
+
const leaf = !includeUncommitted ? this.leaves[index] : this.cachedLeaves[index] ?? this.leaves[index];
|
|
135
|
+
return leaf
|
|
136
|
+
? {
|
|
137
|
+
value: leaf.value,
|
|
138
|
+
nextIndex: leaf.nextIndex,
|
|
139
|
+
nextValue: leaf.nextValue,
|
|
140
|
+
}
|
|
141
|
+
: undefined;
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Appends the given leaf to the tree.
|
|
145
|
+
* @param leaf - The leaf to append.
|
|
146
|
+
* @returns Empty promise.
|
|
147
|
+
*/
|
|
148
|
+
async appendLeaf(leaf) {
|
|
149
|
+
const newValue = toBigIntBE(leaf);
|
|
150
|
+
// Special case when appending zero
|
|
151
|
+
if (newValue === 0n) {
|
|
152
|
+
const newSize = (this.cachedSize ?? this.size) + 1n;
|
|
153
|
+
if (newSize - 1n > this.maxIndex) {
|
|
154
|
+
throw Error(`Can't append beyond max index. Max index: ${this.maxIndex}`);
|
|
155
|
+
}
|
|
156
|
+
this.cachedSize = newSize;
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
const indexOfPrevious = this.findIndexOfPreviousValue(newValue, true);
|
|
160
|
+
const previousLeafCopy = this.getLatestLeafDataCopy(indexOfPrevious.index, true);
|
|
161
|
+
if (previousLeafCopy === undefined) {
|
|
162
|
+
throw new Error(`Previous leaf not found!`);
|
|
163
|
+
}
|
|
164
|
+
const newLeaf = {
|
|
165
|
+
value: newValue,
|
|
166
|
+
nextIndex: previousLeafCopy.nextIndex,
|
|
167
|
+
nextValue: previousLeafCopy.nextValue,
|
|
168
|
+
};
|
|
169
|
+
if (indexOfPrevious.alreadyPresent) {
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
// insert a new leaf at the highest index and update the values of our previous leaf copy
|
|
173
|
+
const currentSize = this.getNumLeaves(true);
|
|
174
|
+
previousLeafCopy.nextIndex = BigInt(currentSize);
|
|
175
|
+
previousLeafCopy.nextValue = newLeaf.value;
|
|
176
|
+
this.cachedLeaves[Number(currentSize)] = newLeaf;
|
|
177
|
+
this.cachedLeaves[Number(indexOfPrevious.index)] = previousLeafCopy;
|
|
178
|
+
await this._updateLeaf(hashEncodedTreeValue(previousLeafCopy, this.hasher), BigInt(indexOfPrevious.index));
|
|
179
|
+
await this._updateLeaf(hashEncodedTreeValue(newLeaf, this.hasher), this.getNumLeaves(true));
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Finds the index of the minimum value in an array.
|
|
183
|
+
* @param values - The collection of values to be searched.
|
|
184
|
+
* @returns The index of the minimum value in the array.
|
|
185
|
+
*/
|
|
186
|
+
findMinIndex(values) {
|
|
187
|
+
if (!values.length) {
|
|
188
|
+
return 0;
|
|
189
|
+
}
|
|
190
|
+
let minIndex = 0;
|
|
191
|
+
for (let i = 1; i < values.length; i++) {
|
|
192
|
+
if (values[minIndex] > values[i]) {
|
|
193
|
+
minIndex = i;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
return minIndex;
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Initializes the tree.
|
|
200
|
+
* @param prefilledSize - A number of leaves that are prefilled with values.
|
|
201
|
+
* @returns Empty promise.
|
|
202
|
+
*/
|
|
203
|
+
async init(prefilledSize) {
|
|
204
|
+
this.leaves.push(initialLeaf);
|
|
205
|
+
await this._updateLeaf(hashEncodedTreeValue(initialLeaf, this.hasher), 0n);
|
|
206
|
+
for (let i = 1; i < prefilledSize; i++) {
|
|
207
|
+
await this.appendLeaf(Buffer.from([i]));
|
|
208
|
+
}
|
|
209
|
+
await this.commit();
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Loads Merkle tree data from a database and assigns them to this object.
|
|
213
|
+
*/
|
|
214
|
+
async initFromDb() {
|
|
215
|
+
const startingIndex = 0n;
|
|
216
|
+
const values = [];
|
|
217
|
+
const promise = new Promise((resolve, reject) => {
|
|
218
|
+
this.db
|
|
219
|
+
.createReadStream({
|
|
220
|
+
gte: indexToKeyLeaf(this.getName(), startingIndex),
|
|
221
|
+
lte: indexToKeyLeaf(this.getName(), 2n ** BigInt(this.getDepth())),
|
|
222
|
+
})
|
|
223
|
+
.on('data', function (data) {
|
|
224
|
+
const index = Number(data.key);
|
|
225
|
+
values[index] = decodeTreeValue(data.value);
|
|
226
|
+
})
|
|
227
|
+
.on('close', function () { })
|
|
228
|
+
.on('end', function () {
|
|
229
|
+
resolve();
|
|
230
|
+
})
|
|
231
|
+
.on('error', function () {
|
|
232
|
+
log('stream error');
|
|
233
|
+
reject();
|
|
234
|
+
});
|
|
235
|
+
});
|
|
236
|
+
await promise;
|
|
237
|
+
this.leaves = values;
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* Commits all the leaves to the database and removes them from a cache.
|
|
241
|
+
*/
|
|
242
|
+
async commitLeaves() {
|
|
243
|
+
const batch = this.db.batch();
|
|
244
|
+
const keys = Object.getOwnPropertyNames(this.cachedLeaves);
|
|
245
|
+
for (const key of keys) {
|
|
246
|
+
const index = Number(key);
|
|
247
|
+
batch.put(key, this.cachedLeaves[index]);
|
|
248
|
+
this.leaves[index] = this.cachedLeaves[index];
|
|
249
|
+
}
|
|
250
|
+
await batch.write();
|
|
251
|
+
this.clearCachedLeaves();
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* Clears the cache.
|
|
255
|
+
*/
|
|
256
|
+
clearCachedLeaves() {
|
|
257
|
+
this.cachedLeaves = {};
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* Updates a leaf in the tree.
|
|
261
|
+
* @param leaf - New contents of the leaf.
|
|
262
|
+
* @param index - Index of the leaf to be updated.
|
|
263
|
+
*/
|
|
264
|
+
// TODO: rename back to updateLeaf once the old updateLeaf is removed
|
|
265
|
+
async _updateLeaf(leaf, index) {
|
|
266
|
+
if (index > this.maxIndex) {
|
|
267
|
+
throw Error(`Index out of bounds. Index ${index}, max index: ${this.maxIndex}.`);
|
|
268
|
+
}
|
|
269
|
+
await this.addLeafToCacheAndHashToRoot(leaf, index);
|
|
270
|
+
const numLeaves = this.getNumLeaves(true);
|
|
271
|
+
if (index >= numLeaves) {
|
|
272
|
+
this.cachedSize = index + 1n;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* Exposes the underlying tree's update leaf method.
|
|
277
|
+
* @param leaf - The hash to set at the leaf.
|
|
278
|
+
* @param index - The index of the element.
|
|
279
|
+
*/
|
|
280
|
+
// TODO: remove once the batch insertion functionality is moved here from circuit_block_builder.ts
|
|
281
|
+
async updateLeaf(leaf, index) {
|
|
282
|
+
let encodedLeaf;
|
|
283
|
+
if (leaf.value == 0n) {
|
|
284
|
+
encodedLeaf = toBufferBE(0n, 32);
|
|
285
|
+
}
|
|
286
|
+
else {
|
|
287
|
+
encodedLeaf = hashEncodedTreeValue(leaf, this.hasher);
|
|
288
|
+
}
|
|
289
|
+
this.cachedLeaves[Number(index)] = leaf;
|
|
290
|
+
await this._updateLeaf(encodedLeaf, index);
|
|
291
|
+
}
|
|
292
|
+
/* eslint-disable jsdoc/require-description-complete-sentence */
|
|
293
|
+
/* The following doc block messes up with complete-sentence, so we just disable it */
|
|
294
|
+
/**
|
|
295
|
+
*
|
|
296
|
+
* Each base rollup needs to provide non membership / inclusion proofs for each of the nullifier.
|
|
297
|
+
* This method will return membership proofs and perform partial node updates that will
|
|
298
|
+
* allow the circuit to incrementally update the tree and perform a batch insertion.
|
|
299
|
+
*
|
|
300
|
+
* This offers massive circuit performance savings over doing incremental insertions.
|
|
301
|
+
*
|
|
302
|
+
* A description of the algorithm can be found here: https://colab.research.google.com/drive/1A0gizduSi4FIiIJZ8OylwIpO9-OTqV-R
|
|
303
|
+
*
|
|
304
|
+
* WARNING: This function has side effects, it will insert values into the tree.
|
|
305
|
+
*
|
|
306
|
+
* Assumptions:
|
|
307
|
+
* 1. There are 8 nullifiers provided and they are either unique or empty. (denoted as 0)
|
|
308
|
+
* 2. If kc 0 has 1 nullifier, and kc 1 has 3 nullifiers the layout will assume to be the sparse
|
|
309
|
+
* nullifier layout: [kc0-0, 0, 0, 0, kc1-0, kc1-1, kc1-2, 0]
|
|
310
|
+
*
|
|
311
|
+
* Algorithm overview
|
|
312
|
+
*
|
|
313
|
+
* In general, if we want to batch insert items, we first to update their low nullifier to point to them,
|
|
314
|
+
* then batch insert all of the values as at once in the final step.
|
|
315
|
+
* To update a low nullifier, we provide an insertion proof that the low nullifier currently exists to the
|
|
316
|
+
* circuit, then update the low nullifier.
|
|
317
|
+
* Updating this low nullifier will in turn change the root of the tree. Therefore future low nullifier insertion proofs
|
|
318
|
+
* must be given against this new root.
|
|
319
|
+
* As a result, each low nullifier membership proof will be provided against an intermediate tree state, each with differing
|
|
320
|
+
* roots.
|
|
321
|
+
*
|
|
322
|
+
* This become tricky when two items that are being batch inserted need to update the same low nullifier, or need to use
|
|
323
|
+
* a value that is part of the same batch insertion as their low nullifier. In this case a zero low nullifier path is given
|
|
324
|
+
* to the circuit, and it must determine from the set of batch inserted values if the insertion is valid.
|
|
325
|
+
*
|
|
326
|
+
* The following example will illustrate attempting to insert 2,3,20,19 into a tree already containing 0,5,10,15
|
|
327
|
+
*
|
|
328
|
+
* The example will explore two cases. In each case the values low nullifier will exist within the batch insertion,
|
|
329
|
+
* One where the low nullifier comes before the item in the set (2,3), and one where it comes after (20,19).
|
|
330
|
+
*
|
|
331
|
+
* The original tree: Pending insertion subtree
|
|
332
|
+
*
|
|
333
|
+
* index 0 2 3 4 - - - -
|
|
334
|
+
* ------------------------------------- ----------------------------
|
|
335
|
+
* val 0 5 10 15 - - - -
|
|
336
|
+
* nextIdx 1 2 3 0 - - - -
|
|
337
|
+
* nextVal 5 10 15 0 - - - -
|
|
338
|
+
*
|
|
339
|
+
*
|
|
340
|
+
* Inserting 2: (happy path)
|
|
341
|
+
* 1. Find the low nullifier (0) - provide inclusion proof
|
|
342
|
+
* 2. Update its pointers
|
|
343
|
+
* 3. Insert 2 into the pending subtree
|
|
344
|
+
*
|
|
345
|
+
* index 0 2 3 4 5 - - -
|
|
346
|
+
* ------------------------------------- ----------------------------
|
|
347
|
+
* val 0 5 10 15 2 - - -
|
|
348
|
+
* nextIdx 5 2 3 0 2 - - -
|
|
349
|
+
* nextVal 2 10 15 0 5 - - -
|
|
350
|
+
*
|
|
351
|
+
* Inserting 3: The low nullifier exists within the insertion current subtree
|
|
352
|
+
* 1. When looking for the low nullifier for 3, we will receive 0 again as we have not inserted 2 into the main tree
|
|
353
|
+
* This is problematic, as we cannot use either 0 or 2 as our inclusion proof.
|
|
354
|
+
* Why cant we?
|
|
355
|
+
* - Index 0 has a val 0 and nextVal of 2. This is NOT enough to prove non inclusion of 2.
|
|
356
|
+
* - Our existing tree is in a state where we cannot prove non inclusion of 3.
|
|
357
|
+
* We do not provide a non inclusion proof to out circuit, but prompt it to look within the insertion subtree.
|
|
358
|
+
* 2. Update pending insertion subtree
|
|
359
|
+
* 3. Insert 3 into pending subtree
|
|
360
|
+
*
|
|
361
|
+
* (no inclusion proof provided)
|
|
362
|
+
* index 0 2 3 4 5 6 - -
|
|
363
|
+
* ------------------------------------- ----------------------------
|
|
364
|
+
* val 0 5 10 15 2 3 - -
|
|
365
|
+
* nextIdx 5 2 3 0 6 2 - -
|
|
366
|
+
* nextVal 2 10 15 0 3 5 - -
|
|
367
|
+
*
|
|
368
|
+
* Inserting 20: (happy path)
|
|
369
|
+
* 1. Find the low nullifier (15) - provide inculsion proof
|
|
370
|
+
* 2. Update its pointers
|
|
371
|
+
* 3. Insert 20 into the pending subtree
|
|
372
|
+
*
|
|
373
|
+
* index 0 2 3 4 5 6 7 -
|
|
374
|
+
* ------------------------------------- ----------------------------
|
|
375
|
+
* val 0 5 10 15 2 3 20 -
|
|
376
|
+
* nextIdx 5 2 3 7 6 2 0 -
|
|
377
|
+
* nextVal 2 10 15 20 3 5 0 -
|
|
378
|
+
*
|
|
379
|
+
* Inserting 19:
|
|
380
|
+
* 1. In this case we can find a low nullifier, but we are updating a low nullifier that has already been updated
|
|
381
|
+
* We can provide an inclusion proof of this intermediate tree state.
|
|
382
|
+
* 2. Update its pointers
|
|
383
|
+
* 3. Insert 19 into the pending subtree
|
|
384
|
+
*
|
|
385
|
+
* index 0 2 3 4 5 6 7 8
|
|
386
|
+
* ------------------------------------- ----------------------------
|
|
387
|
+
* val 0 5 10 15 2 3 20 19
|
|
388
|
+
* nextIdx 5 2 3 8 6 2 0 7
|
|
389
|
+
* nextVal 2 10 15 19 3 5 0 20
|
|
390
|
+
*
|
|
391
|
+
* Perform subtree insertion
|
|
392
|
+
*
|
|
393
|
+
* index 0 2 3 4 5 6 7 8
|
|
394
|
+
* ---------------------------------------------------------------------
|
|
395
|
+
* val 0 5 10 15 2 3 20 19
|
|
396
|
+
* nextIdx 5 2 3 8 6 2 0 7
|
|
397
|
+
* nextVal 2 10 15 19 3 5 0 20
|
|
398
|
+
*
|
|
399
|
+
* TODO: this implementation will change once the zero value is changed from h(0,0,0). Changes incoming over the next sprint
|
|
400
|
+
* @param leaves - Values to insert into the tree.
|
|
401
|
+
* @param treeHeight - Height of the tree.
|
|
402
|
+
* @param subtreeHeight - Height of the subtree.
|
|
403
|
+
* @returns The data for the leaves to be updated when inserting the new ones.
|
|
404
|
+
*/
|
|
405
|
+
async batchInsert(leaves, treeHeight, subtreeHeight) {
|
|
406
|
+
// Keep track of touched low leaves
|
|
407
|
+
const touched = new Map();
|
|
408
|
+
const emptyLowLeafWitness = getEmptyLowLeafWitness(treeHeight);
|
|
409
|
+
// Accumulators
|
|
410
|
+
const lowLeavesWitnesses = [];
|
|
411
|
+
const pendingInsertionSubtree = [];
|
|
412
|
+
// Start info
|
|
413
|
+
const startInsertionIndex = this.getNumLeaves(true);
|
|
414
|
+
// Get insertion path for each leaf
|
|
415
|
+
for (let i = 0; i < leaves.length; i++) {
|
|
416
|
+
const newValue = toBigIntBE(leaves[i]);
|
|
417
|
+
// Keep space and just insert zero values
|
|
418
|
+
if (newValue === 0n) {
|
|
419
|
+
pendingInsertionSubtree.push(zeroLeaf);
|
|
420
|
+
lowLeavesWitnesses.push(emptyLowLeafWitness);
|
|
421
|
+
continue;
|
|
422
|
+
}
|
|
423
|
+
const indexOfPrevious = this.findIndexOfPreviousValue(newValue, true);
|
|
424
|
+
// If a touched node has a value that is less greater than the current value
|
|
425
|
+
const prevNodes = touched.get(indexOfPrevious.index);
|
|
426
|
+
if (prevNodes && prevNodes.some(v => v < newValue)) {
|
|
427
|
+
// check the pending low nullifiers for a low nullifier that works
|
|
428
|
+
// This is the case where the next value is less than the pending
|
|
429
|
+
for (let j = 0; j < pendingInsertionSubtree.length; j++) {
|
|
430
|
+
if (pendingInsertionSubtree[j].value === 0n)
|
|
431
|
+
continue;
|
|
432
|
+
if (pendingInsertionSubtree[j].value < newValue &&
|
|
433
|
+
(pendingInsertionSubtree[j].nextValue > newValue || pendingInsertionSubtree[j].nextValue === 0n)) {
|
|
434
|
+
// add the new value to the pending low nullifiers
|
|
435
|
+
const currentLowLeaf = {
|
|
436
|
+
value: newValue,
|
|
437
|
+
nextValue: pendingInsertionSubtree[j].nextValue,
|
|
438
|
+
nextIndex: pendingInsertionSubtree[j].nextIndex,
|
|
439
|
+
};
|
|
440
|
+
pendingInsertionSubtree.push(currentLowLeaf);
|
|
441
|
+
// Update the pending low leaf to point at the new value
|
|
442
|
+
pendingInsertionSubtree[j].nextValue = newValue;
|
|
443
|
+
pendingInsertionSubtree[j].nextIndex = startInsertionIndex + BigInt(i);
|
|
444
|
+
break;
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
// Any node updated in this space will need to calculate its low nullifier from a previously inserted value
|
|
448
|
+
lowLeavesWitnesses.push(emptyLowLeafWitness);
|
|
449
|
+
}
|
|
450
|
+
else {
|
|
451
|
+
// Update the touched mapping
|
|
452
|
+
if (prevNodes) {
|
|
453
|
+
prevNodes.push(newValue);
|
|
454
|
+
touched.set(indexOfPrevious.index, prevNodes);
|
|
455
|
+
}
|
|
456
|
+
else {
|
|
457
|
+
touched.set(indexOfPrevious.index, [newValue]);
|
|
458
|
+
}
|
|
459
|
+
// get the low leaf
|
|
460
|
+
const lowLeaf = this.getLatestLeafDataCopy(indexOfPrevious.index, true);
|
|
461
|
+
if (lowLeaf === undefined) {
|
|
462
|
+
return [undefined, await this.getSubtreeSiblingPath(subtreeHeight, true)];
|
|
463
|
+
}
|
|
464
|
+
const siblingPath = await this.getSiblingPath(BigInt(indexOfPrevious.index), true);
|
|
465
|
+
const witness = {
|
|
466
|
+
leafData: { ...lowLeaf },
|
|
467
|
+
index: BigInt(indexOfPrevious.index),
|
|
468
|
+
siblingPath,
|
|
469
|
+
};
|
|
470
|
+
// Update the running paths
|
|
471
|
+
lowLeavesWitnesses.push(witness);
|
|
472
|
+
const currentLowLeaf = {
|
|
473
|
+
value: newValue,
|
|
474
|
+
nextValue: lowLeaf.nextValue,
|
|
475
|
+
nextIndex: lowLeaf.nextIndex,
|
|
476
|
+
};
|
|
477
|
+
pendingInsertionSubtree.push(currentLowLeaf);
|
|
478
|
+
lowLeaf.nextValue = newValue;
|
|
479
|
+
lowLeaf.nextIndex = startInsertionIndex + BigInt(i);
|
|
480
|
+
await this.updateLeaf(lowLeaf, BigInt(indexOfPrevious.index));
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
const newSubtreeSiblingPath = await this.getSubtreeSiblingPath(subtreeHeight, true);
|
|
484
|
+
// Perform batch insertion of new pending values
|
|
485
|
+
for (let i = 0; i < pendingInsertionSubtree.length; i++) {
|
|
486
|
+
await this.updateLeaf(pendingInsertionSubtree[i], startInsertionIndex + BigInt(i));
|
|
487
|
+
}
|
|
488
|
+
return [lowLeavesWitnesses, newSubtreeSiblingPath];
|
|
489
|
+
}
|
|
490
|
+
async getSubtreeSiblingPath(subtreeHeight, includeUncommitted) {
|
|
491
|
+
const nextAvailableLeafIndex = this.getNumLeaves(includeUncommitted);
|
|
492
|
+
const fullSiblingPath = await this.getSiblingPath(nextAvailableLeafIndex, includeUncommitted);
|
|
493
|
+
// Drop the first subtreeHeight items since we only care about the path to the subtree root
|
|
494
|
+
return fullSiblingPath.getSubtreeSiblingPath(subtreeHeight);
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3RhbmRhcmRfaW5kZXhlZF90cmVlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3N0YW5kYXJkX2luZGV4ZWRfdHJlZS9zdGFuZGFyZF9pbmRleGVkX3RyZWUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFVBQVUsRUFBRSxVQUFVLEVBQUUsTUFBTSxpQ0FBaUMsQ0FBQztBQUN6RSxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sdUJBQXVCLENBQUM7QUFHckQsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBQzNDLE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSxhQUFhLENBQUM7QUFFMUMsTUFBTSxHQUFHLEdBQUcsWUFBWSxDQUFDLDZCQUE2QixDQUFDLENBQUM7QUFFeEQsTUFBTSxjQUFjLEdBQUcsQ0FBQyxJQUFZLEVBQUUsS0FBYSxFQUFFLEVBQUU7SUFDckQsT0FBTyxHQUFHLElBQUksU0FBUyxLQUFLLEVBQUUsQ0FBQztBQUNqQyxDQUFDLENBQUM7QUFFRixNQUFNLFFBQVEsR0FBYTtJQUN6QixLQUFLLEVBQUUsRUFBRTtJQUNULFNBQVMsRUFBRSxFQUFFO0lBQ2IsU0FBUyxFQUFFLEVBQUU7Q0FDZCxDQUFDO0FBb0JGOzs7O0dBSUc7QUFDSCxTQUFTLHNCQUFzQixDQUFtQixVQUFhO0lBQzdELE9BQU87UUFDTCxRQUFRLEVBQUUsUUFBUTtRQUNsQixLQUFLLEVBQUUsRUFBRTtRQUNULFdBQVcsRUFBRSxJQUFJLFdBQVcsQ0FBQyxVQUFVLEVBQUUsS0FBSyxDQUFDLFVBQVUsQ0FBQyxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsRUFBRSxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUM7S0FDckYsQ0FBQztBQUNKLENBQUM7QUFFRCw2REFBNkQ7QUFDN0QsTUFBTSxlQUFlLEdBQUcsQ0FBQyxRQUFrQixFQUFFLEVBQUU7SUFDN0MsTUFBTSxhQUFhLEdBQUcsVUFBVSxDQUFDLFFBQVEsQ0FBQyxLQUFLLEVBQUUsRUFBRSxDQUFDLENBQUM7SUFDckQsTUFBTSxhQUFhLEdBQUcsVUFBVSxDQUFDLFFBQVEsQ0FBQyxTQUFTLEVBQUUsRUFBRSxDQUFDLENBQUM7SUFDekQsTUFBTSxpQkFBaUIsR0FBRyxVQUFVLENBQUMsUUFBUSxDQUFDLFNBQVMsRUFBRSxFQUFFLENBQUMsQ0FBQztJQUM3RCxPQUFPLE1BQU0sQ0FBQyxNQUFNLENBQUMsQ0FBQyxhQUFhLEVBQUUsYUFBYSxFQUFFLGlCQUFpQixDQUFDLENBQUMsQ0FBQztBQUMxRSxDQUFDLENBQUM7QUFFRixNQUFNLG9CQUFvQixHQUFHLENBQUMsSUFBYyxFQUFFLE1BQWMsRUFBRSxFQUFFO0lBQzlELE9BQU8sTUFBTSxDQUFDLGNBQWMsQ0FBQyxDQUFDLElBQUksQ0FBQyxLQUFLLEVBQUUsSUFBSSxDQUFDLFNBQVMsRUFBRSxJQUFJLENBQUMsU0FBUyxDQUFDLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsVUFBVSxDQUFDLEdBQUcsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUM7QUFDN0csQ0FBQyxDQUFDO0FBRUYsTUFBTSxlQUFlLEdBQUcsQ0FBQyxHQUFXLEVBQUUsRUFBRTtJQUN0QyxNQUFNLEtBQUssR0FBRyxVQUFVLENBQUMsR0FBRyxDQUFDLFFBQVEsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQztJQUM5QyxNQUFNLFNBQVMsR0FBRyxVQUFVLENBQUMsR0FBRyxDQUFDLFFBQVEsQ0FBQyxFQUFFLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQztJQUNuRCxNQUFNLFNBQVMsR0FBRyxVQUFVLENBQUMsR0FBRyxDQUFDLFFBQVEsQ0FBQyxFQUFFLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQztJQUNuRCxPQUFPO1FBQ0wsS0FBSztRQUNMLFNBQVM7UUFDVCxTQUFTO0tBQ0UsQ0FBQztBQUNoQixDQUFDLENBQUM7QUFFRixNQUFNLFdBQVcsR0FBYTtJQUM1QixLQUFLLEVBQUUsRUFBRTtJQUNULFNBQVMsRUFBRSxFQUFFO0lBQ2IsU0FBUyxFQUFFLEVBQUU7Q0FDZCxDQUFDO0FBRUY7O0dBRUc7QUFDSCxNQUFNLE9BQU8sbUJBQW9CLFNBQVEsUUFBUTtJQUFqRDs7UUFDVSxXQUFNLEdBQWUsRUFBRSxDQUFDO1FBQ3hCLGlCQUFZLEdBQWdDLEVBQUUsQ0FBQztJQTBmekQsQ0FBQztJQXhmQzs7OztPQUlHO0lBQ0ksS0FBSyxDQUFDLFlBQVksQ0FBQyxNQUFnQjtRQUN4QyxLQUFLLE1BQU0sSUFBSSxJQUFJLE1BQU0sRUFBRTtZQUN6QixNQUFNLElBQUksQ0FBQyxVQUFVLENBQUMsSUFBSSxDQUFDLENBQUM7U0FDN0I7SUFDSCxDQUFDO0lBRUQ7OztPQUdHO0lBQ0ksS0FBSyxDQUFDLE1BQU07UUFDakIsTUFBTSxLQUFLLENBQUMsTUFBTSxFQUFFLENBQUM7UUFDckIsTUFBTSxJQUFJLENBQUMsWUFBWSxFQUFFLENBQUM7SUFDNUIsQ0FBQztJQUVEOzs7T0FHRztJQUNJLEtBQUssQ0FBQyxRQUFRO1FBQ25CLE1BQU0sS0FBSyxDQUFDLFFBQVEsRUFBRSxDQUFDO1FBQ3ZCLElBQUksQ0FBQyxpQkFBaUIsRUFBRSxDQUFDO0lBQzNCLENBQUM7SUFFRDs7Ozs7T0FLRztJQUNJLFlBQVksQ0FBQyxLQUFhLEVBQUUsa0JBQTJCO1FBQzVELE1BQU0sSUFBSSxHQUFHLElBQUksQ0FBQyxxQkFBcUIsQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLEVBQUUsa0JBQWtCLENBQUMsQ0FBQztRQUMzRSxJQUFJLENBQUMsSUFBSTtZQUFFLE9BQU8sT0FBTyxDQUFDLE9BQU8sQ0FBQyxTQUFTLENBQUMsQ0FBQztRQUM3QyxPQUFPLE9BQU8sQ0FBQyxPQUFPLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBQyxLQUFLLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQztJQUNyRCxDQUFDO0lBRUQ7Ozs7O09BS0c7SUFDSCx3QkFBd0IsQ0FDdEIsUUFBZ0IsRUFDaEIsa0JBQTJCO1FBVzNCLE1BQU0sU0FBUyxHQUFHLElBQUksQ0FBQyxZQUFZLENBQUMsa0JBQWtCLENBQUMsQ0FBQztRQUN4RCxNQUFNLElBQUksR0FBYSxFQUFFLENBQUM7UUFFMUIsS0FBSyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLFNBQVMsRUFBRSxDQUFDLEVBQUUsRUFBRTtZQUNsQyxNQUFNLFVBQVUsR0FBRyxJQUFJLENBQUMscUJBQXFCLENBQUMsQ0FBQyxFQUFFLGtCQUFrQixDQUFFLENBQUM7WUFFdEUsaUVBQWlFO1lBQ2pFLGdFQUFnRTtZQUNoRSxJQUFJLFVBQVUsS0FBSyxTQUFTLEVBQUU7Z0JBQzVCLElBQUksQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLENBQUM7YUFDckI7aUJBQU0sSUFBSSxVQUFVLENBQUMsS0FBSyxHQUFHLFFBQVEsRUFBRTtnQkFDdEMsSUFBSSxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsQ0FBQzthQUNyQjtpQkFBTSxJQUFJLFVBQVUsQ0FBQyxLQUFLLEtBQUssUUFBUSxFQUFFO2dCQUN4QyxPQUFPLEVBQUUsS0FBSyxFQUFFLENBQUMsRUFBRSxjQUFjLEVBQUUsSUFBSSxFQUFFLENBQUM7YUFDM0M7aUJBQU07Z0JBQ0wsSUFBSSxDQUFDLElBQUksQ0FBQyxRQUFRLEdBQUcsVUFBVSxDQUFDLEtBQUssQ0FBQyxDQUFDO2FBQ3hDO1NBQ0Y7UUFDRCxNQUFNLFFBQVEsR0FBRyxJQUFJLENBQUMsWUFBWSxDQUFDLElBQUksQ0FBQyxDQUFDO1FBQ3pDLE9BQU8sRUFBRSxLQUFLLEVBQUUsUUFBUSxFQUFFLGNBQWMsRUFBRSxLQUFLLEVBQUUsQ0FBQztJQUNwRCxDQUFDO0lBRUQ7Ozs7O09BS0c7SUFDSSxxQkFBcUIsQ0FBQyxLQUFhLEVBQUUsa0JBQTJCO1FBQ3JFLE1BQU0sSUFBSSxHQUFHLENBQUMsa0JBQWtCLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxZQUFZLENBQUMsS0FBSyxDQUFDLElBQUksSUFBSSxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUN2RyxPQUFPLElBQUk7WUFDVCxDQUFDLENBQUU7Z0JBQ0MsS0FBSyxFQUFFLElBQUksQ0FBQyxLQUFLO2dCQUNqQixTQUFTLEVBQUUsSUFBSSxDQUFDLFNBQVM7Z0JBQ3pCLFNBQVMsRUFBRSxJQUFJLENBQUMsU0FBUzthQUNiO1lBQ2hCLENBQUMsQ0FBQyxTQUFTLENBQUM7SUFDaEIsQ0FBQztJQUVEOzs7O09BSUc7SUFDSyxLQUFLLENBQUMsVUFBVSxDQUFDLElBQVk7UUFDbkMsTUFBTSxRQUFRLEdBQUcsVUFBVSxDQUFDLElBQUksQ0FBQyxDQUFDO1FBRWxDLG1DQUFtQztRQUNuQyxJQUFJLFFBQVEsS0FBSyxFQUFFLEVBQUU7WUFDbkIsTUFBTSxPQUFPLEdBQUcsQ0FBQyxJQUFJLENBQUMsVUFBVSxJQUFJLElBQUksQ0FBQyxJQUFJLENBQUMsR0FBRyxFQUFFLENBQUM7WUFDcEQsSUFBSSxPQUFPLEdBQUcsRUFBRSxHQUFHLElBQUksQ0FBQyxRQUFRLEVBQUU7Z0JBQ2hDLE1BQU0sS0FBSyxDQUFDLDZDQUE2QyxJQUFJLENBQUMsUUFBUSxFQUFFLENBQUMsQ0FBQzthQUMzRTtZQUNELElBQUksQ0FBQyxVQUFVLEdBQUcsT0FBTyxDQUFDO1lBQzFCLE9BQU87U0FDUjtRQUVELE1BQU0sZUFBZSxHQUFHLElBQUksQ0FBQyx3QkFBd0IsQ0FBQyxRQUFRLEVBQUUsSUFBSSxDQUFDLENBQUM7UUFDdEUsTUFBTSxnQkFBZ0IsR0FBRyxJQUFJLENBQUMscUJBQXFCLENBQUMsZUFBZSxDQUFDLEtBQUssRUFBRSxJQUFJLENBQUMsQ0FBQztRQUVqRixJQUFJLGdCQUFnQixLQUFLLFNBQVMsRUFBRTtZQUNsQyxNQUFNLElBQUksS0FBSyxDQUFDLDBCQUEwQixDQUFDLENBQUM7U0FDN0M7UUFDRCxNQUFNLE9BQU8sR0FBRztZQUNkLEtBQUssRUFBRSxRQUFRO1lBQ2YsU0FBUyxFQUFFLGdCQUFnQixDQUFDLFNBQVM7WUFDckMsU0FBUyxFQUFFLGdCQUFnQixDQUFDLFNBQVM7U0FDMUIsQ0FBQztRQUNkLElBQUksZUFBZSxDQUFDLGNBQWMsRUFBRTtZQUNsQyxPQUFPO1NBQ1I7UUFDRCx5RkFBeUY7UUFDekYsTUFBTSxXQUFXLEdBQUcsSUFBSSxDQUFDLFlBQVksQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUM1QyxnQkFBZ0IsQ0FBQyxTQUFTLEdBQUcsTUFBTSxDQUFDLFdBQVcsQ0FBQyxDQUFDO1FBQ2pELGdCQUFnQixDQUFDLFNBQVMsR0FBRyxPQUFPLENBQUMsS0FBSyxDQUFDO1FBQzNDLElBQUksQ0FBQyxZQUFZLENBQUMsTUFBTSxDQUFDLFdBQVcsQ0FBQyxDQUFDLEdBQUcsT0FBTyxDQUFDO1FBQ2pELElBQUksQ0FBQyxZQUFZLENBQUMsTUFBTSxDQUFDLGVBQWUsQ0FBQyxLQUFLLENBQUMsQ0FBQyxHQUFHLGdCQUFnQixDQUFDO1FBQ3BFLE1BQU0sSUFBSSxDQUFDLFdBQVcsQ0FBQyxvQkFBb0IsQ0FBQyxnQkFBZ0IsRUFBRSxJQUFJLENBQUMsTUFBTSxDQUFDLEVBQUUsTUFBTSxDQUFDLGVBQWUsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDO1FBQzNHLE1BQU0sSUFBSSxDQUFDLFdBQVcsQ0FBQyxvQkFBb0IsQ0FBQyxPQUFPLEVBQUUsSUFBSSxDQUFDLE1BQU0sQ0FBQyxFQUFFLElBQUksQ0FBQyxZQUFZLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQztJQUM5RixDQUFDO0lBRUQ7Ozs7T0FJRztJQUNLLFlBQVksQ0FBQyxNQUFnQjtRQUNuQyxJQUFJLENBQUMsTUFBTSxDQUFDLE1BQU0sRUFBRTtZQUNsQixPQUFPLENBQUMsQ0FBQztTQUNWO1FBQ0QsSUFBSSxRQUFRLEdBQUcsQ0FBQyxDQUFDO1FBQ2pCLEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxNQUFNLENBQUMsTUFBTSxFQUFFLENBQUMsRUFBRSxFQUFFO1lBQ3RDLElBQUksTUFBTSxDQUFDLFFBQVEsQ0FBQyxHQUFHLE1BQU0sQ0FBQyxDQUFDLENBQUMsRUFBRTtnQkFDaEMsUUFBUSxHQUFHLENBQUMsQ0FBQzthQUNkO1NBQ0Y7UUFDRCxPQUFPLFFBQVEsQ0FBQztJQUNsQixDQUFDO0lBRUQ7Ozs7T0FJRztJQUNJLEtBQUssQ0FBQyxJQUFJLENBQUMsYUFBcUI7UUFDckMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsV0FBVyxDQUFDLENBQUM7UUFDOUIsTUFBTSxJQUFJLENBQUMsV0FBVyxDQUFDLG9CQUFvQixDQUFDLFdBQVcsRUFBRSxJQUFJLENBQUMsTUFBTSxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUM7UUFFM0UsS0FBSyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLGFBQWEsRUFBRSxDQUFDLEVBQUUsRUFBRTtZQUN0QyxNQUFNLElBQUksQ0FBQyxVQUFVLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztTQUN6QztRQUVELE1BQU0sSUFBSSxDQUFDLE1BQU0sRUFBRSxDQUFDO0lBQ3RCLENBQUM7SUFFRDs7T0FFRztJQUNJLEtBQUssQ0FBQyxVQUFVO1FBQ3JCLE1BQU0sYUFBYSxHQUFHLEVBQUUsQ0FBQztRQUN6QixNQUFNLE1BQU0sR0FBZSxFQUFFLENBQUM7UUFDOUIsTUFBTSxPQUFPLEdBQUcsSUFBSSxPQUFPLENBQU8sQ0FBQyxPQUFPLEVBQUUsTUFBTSxFQUFFLEVBQUU7WUFDcEQsSUFBSSxDQUFDLEVBQUU7aUJBQ0osZ0JBQWdCLENBQUM7Z0JBQ2hCLEdBQUcsRUFBRSxjQUFjLENBQUMsSUFBSSxDQUFDLE9BQU8sRUFBRSxFQUFFLGFBQWEsQ0FBQztnQkFDbEQsR0FBRyxFQUFFLGNBQWMsQ0FBQyxJQUFJLENBQUMsT0FBTyxFQUFFLEVBQUUsRUFBRSxJQUFJLE1BQU0sQ0FBQyxJQUFJLENBQUMsUUFBUSxFQUFFLENBQUMsQ0FBQzthQUNuRSxDQUFDO2lCQUNELEVBQUUsQ0FBQyxNQUFNLEVBQUUsVUFBVSxJQUFJO2dCQUN4QixNQUFNLEtBQUssR0FBRyxNQUFNLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDO2dCQUMvQixNQUFNLENBQUMsS0FBSyxDQUFDLEdBQUcsZUFBZSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQztZQUM5QyxDQUFDLENBQUM7aUJBQ0QsRUFBRSxDQUFDLE9BQU8sRUFBRSxjQUFhLENBQUMsQ0FBQztpQkFDM0IsRUFBRSxDQUFDLEtBQUssRUFBRTtnQkFDVCxPQUFPLEVBQUUsQ0FBQztZQUNaLENBQUMsQ0FBQztpQkFDRCxFQUFFLENBQUMsT0FBTyxFQUFFO2dCQUNYLEdBQUcsQ0FBQyxjQUFjLENBQUMsQ0FBQztnQkFDcEIsTUFBTSxFQUFFLENBQUM7WUFDWCxDQUFDLENBQUMsQ0FBQztRQUNQLENBQUMsQ0FBQyxDQUFDO1FBQ0gsTUFBTSxPQUFPLENBQUM7UUFDZCxJQUFJLENBQUMsTUFBTSxHQUFHLE1BQU0sQ0FBQztJQUN2QixDQUFDO0lBRUQ7O09BRUc7SUFDSyxLQUFLLENBQUMsWUFBWTtRQUN4QixNQUFNLEtBQUssR0FBRyxJQUFJLENBQUMsRUFBRSxDQUFDLEtBQUssRUFBRSxDQUFDO1FBQzlCLE1BQU0sSUFBSSxHQUFHLE1BQU0sQ0FBQyxtQkFBbUIsQ0FBQyxJQUFJLENBQUMsWUFBWSxDQUFDLENBQUM7UUFDM0QsS0FBSyxNQUFNLEdBQUcsSUFBSSxJQUFJLEVBQUU7WUFDdEIsTUFBTSxLQUFLLEdBQUcsTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFDO1lBQzFCLEtBQUssQ0FBQyxHQUFHLENBQUMsR0FBRyxFQUFFLElBQUksQ0FBQyxZQUFZLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQztZQUN6QyxJQUFJLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxHQUFHLElBQUksQ0FBQyxZQUFZLENBQUMsS0FBSyxDQUFDLENBQUM7U0FDL0M7UUFDRCxNQUFNLEtBQUssQ0FBQyxLQUFLLEVBQUUsQ0FBQztRQUNwQixJQUFJLENBQUMsaUJBQWlCLEVBQUUsQ0FBQztJQUMzQixDQUFDO0lBRUQ7O09BRUc7SUFDSyxpQkFBaUI7UUFDdkIsSUFBSSxDQUFDLFlBQVksR0FBRyxFQUFFLENBQUM7SUFDekIsQ0FBQztJQUVEOzs7O09BSUc7SUFDSCxxRUFBcUU7SUFDN0QsS0FBSyxDQUFDLFdBQVcsQ0FBQyxJQUFZLEVBQUUsS0FBYTtRQUNuRCxJQUFJLEtBQUssR0FBRyxJQUFJLENBQUMsUUFBUSxFQUFFO1lBQ3pCLE1BQU0sS0FBSyxDQUFDLDhCQUE4QixLQUFLLGdCQUFnQixJQUFJLENBQUMsUUFBUSxHQUFHLENBQUMsQ0FBQztTQUNsRjtRQUNELE1BQU0sSUFBSSxDQUFDLDJCQUEyQixDQUFDLElBQUksRUFBRSxLQUFLLENBQUMsQ0FBQztRQUNwRCxNQUFNLFNBQVMsR0FBRyxJQUFJLENBQUMsWUFBWSxDQUFDLElBQUksQ0FBQyxDQUFDO1FBQzFDLElBQUksS0FBSyxJQUFJLFNBQVMsRUFBRTtZQUN0QixJQUFJLENBQUMsVUFBVSxHQUFHLEtBQUssR0FBRyxFQUFFLENBQUM7U0FDOUI7SUFDSCxDQUFDO0lBRUQ7Ozs7T0FJRztJQUNILGtHQUFrRztJQUMzRixLQUFLLENBQUMsVUFBVSxDQUFDLElBQWMsRUFBRSxLQUFhO1FBQ25ELElBQUksV0FBVyxDQUFDO1FBQ2hCLElBQUksSUFBSSxDQUFDLEtBQUssSUFBSSxFQUFFLEVBQUU7WUFDcEIsV0FBVyxHQUFHLFVBQVUsQ0FBQyxFQUFFLEVBQUUsRUFBRSxDQUFDLENBQUM7U0FDbEM7YUFBTTtZQUNMLFdBQVcsR0FBRyxvQkFBb0IsQ0FBQyxJQUFJLEVBQUUsSUFBSSxDQUFDLE1BQU0sQ0FBQyxDQUFDO1NBQ3ZEO1FBQ0QsSUFBSSxDQUFDLFlBQVksQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLENBQUMsR0FBRyxJQUFJLENBQUM7UUFDeEMsTUFBTSxJQUFJLENBQUMsV0FBVyxDQUFDLFdBQVcsRUFBRSxLQUFLLENBQUMsQ0FBQztJQUM3QyxDQUFDO0lBRUQsZ0VBQWdFO0lBQ2hFLHFGQUFxRjtJQUVyRjs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7T0E4R0c7SUFDSSxLQUFLLENBQUMsV0FBVyxDQUt0QixNQUFnQixFQUNoQixVQUFzQixFQUN0QixhQUE0QjtRQUs1QixtQ0FBbUM7UUFDbkMsTUFBTSxPQUFPLEdBQUcsSUFBSSxHQUFHLEVBQW9CLENBQUM7UUFFNUMsTUFBTSxtQkFBbUIsR0FBRyxzQkFBc0IsQ0FBQyxVQUFVLENBQUMsQ0FBQztRQUMvRCxlQUFlO1FBQ2YsTUFBTSxrQkFBa0IsR0FBcUMsRUFBRSxDQUFDO1FBQ2hFLE1BQU0sdUJBQXVCLEdBQWUsRUFBRSxDQUFDO1FBRS9DLGFBQWE7UUFDYixNQUFNLG1CQUFtQixHQUFHLElBQUksQ0FBQyxZQUFZLENBQUMsSUFBSSxDQUFDLENBQUM7UUFFcEQsbUNBQW1DO1FBQ25DLEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxNQUFNLENBQUMsTUFBTSxFQUFFLENBQUMsRUFBRSxFQUFFO1lBQ3RDLE1BQU0sUUFBUSxHQUFHLFVBQVUsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztZQUV2Qyx5Q0FBeUM7WUFDekMsSUFBSSxRQUFRLEtBQUssRUFBRSxFQUFFO2dCQUNuQix1QkFBdUIsQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLENBQUM7Z0JBQ3ZDLGtCQUFrQixDQUFDLElBQUksQ0FBQyxtQkFBbUIsQ0FBQyxDQUFDO2dCQUM3QyxTQUFTO2FBQ1Y7WUFFRCxNQUFNLGVBQWUsR0FBRyxJQUFJLENBQUMsd0JBQXdCLENBQUMsUUFBUSxFQUFFLElBQUksQ0FBQyxDQUFDO1lBRXRFLDRFQUE0RTtZQUM1RSxNQUFNLFNBQVMsR0FBRyxPQUFPLENBQUMsR0FBRyxDQUFDLGVBQWUsQ0FBQyxLQUFLLENBQUMsQ0FBQztZQUNyRCxJQUFJLFNBQVMsSUFBSSxTQUFTLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxHQUFHLFFBQVEsQ0FBQyxFQUFFO2dCQUNsRCxrRUFBa0U7Z0JBQ2xFLGlFQUFpRTtnQkFDakUsS0FBSyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLHVCQUF1QixDQUFDLE1BQU0sRUFBRSxDQUFDLEVBQUUsRUFBRTtvQkFDdkQsSUFBSSx1QkFBdUIsQ0FBQyxDQUFDLENBQUMsQ0FBQyxLQUFLLEtBQUssRUFBRTt3QkFBRSxTQUFTO29CQUV0RCxJQUNFLHVCQUF1QixDQUFDLENBQUMsQ0FBQyxDQUFDLEtBQUssR0FBRyxRQUFRO3dCQUMzQyxDQUFDLHVCQUF1QixDQUFDLENBQUMsQ0FBQyxDQUFDLFNBQVMsR0FBRyxRQUFRLElBQUksdUJBQXVCLENBQUMsQ0FBQyxDQUFDLENBQUMsU0FBUyxLQUFLLEVBQUUsQ0FBQyxFQUNoRzt3QkFDQSxrREFBa0Q7d0JBQ2xELE1BQU0sY0FBYyxHQUFhOzRCQUMvQixLQUFLLEVBQUUsUUFBUTs0QkFDZixTQUFTLEVBQUUsdUJBQXVCLENBQUMsQ0FBQyxDQUFDLENBQUMsU0FBUzs0QkFDL0MsU0FBUyxFQUFFLHVCQUF1QixDQUFDLENBQUMsQ0FBQyxDQUFDLFNBQVM7eUJBQ2hELENBQUM7d0JBRUYsdUJBQXVCLENBQUMsSUFBSSxDQUFDLGNBQWMsQ0FBQyxDQUFDO3dCQUU3Qyx3REFBd0Q7d0JBQ3hELHVCQUF1QixDQUFDLENBQUMsQ0FBQyxDQUFDLFNBQVMsR0FBRyxRQUFRLENBQUM7d0JBQ2hELHVCQUF1QixDQUFDLENBQUMsQ0FBQyxDQUFDLFNBQVMsR0FBRyxtQkFBbUIsR0FBRyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUM7d0JBRXZFLE1BQU07cUJBQ1A7aUJBQ0Y7Z0JBRUQsMkdBQTJHO2dCQUMzRyxrQkFBa0IsQ0FBQyxJQUFJLENBQUMsbUJBQW1CLENBQUMsQ0FBQzthQUM5QztpQkFBTTtnQkFDTCw2QkFBNkI7Z0JBQzdCLElBQUksU0FBUyxFQUFFO29CQUNiLFNBQVMsQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLENBQUM7b0JBQ3pCLE9BQU8sQ0FBQyxHQUFHLENBQUMsZUFBZSxDQUFDLEtBQUssRUFBRSxTQUFTLENBQUMsQ0FBQztpQkFDL0M7cUJBQU07b0JBQ0wsT0FBTyxDQUFDLEdBQUcsQ0FBQyxlQUFlLENBQUMsS0FBSyxFQUFFLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQztpQkFDaEQ7Z0JBRUQsbUJBQW1CO2dCQUNuQixNQUFNLE9BQU8sR0FBRyxJQUFJLENBQUMscUJBQXFCLENBQUMsZUFBZSxDQUFDLEtBQUssRUFBRSxJQUFJLENBQUMsQ0FBQztnQkFDeEUsSUFBSSxPQUFPLEtBQUssU0FBUyxFQUFFO29CQUN6QixPQUFPLENBQUMsU0FBUyxFQUFFLE1BQU0sSUFBSSxDQUFDLHFCQUFxQixDQUFDLGFBQWEsRUFBRSxJQUFJLENBQUMsQ0FBQyxDQUFDO2lCQUMzRTtnQkFDRCxNQUFNLFdBQVcsR0FBRyxNQUFNLElBQUksQ0FBQyxjQUFjLENBQWEsTUFBTSxDQUFDLGVBQWUsQ0FBQyxLQUFLLENBQUMsRUFBRSxJQUFJLENBQUMsQ0FBQztnQkFFL0YsTUFBTSxPQUFPLEdBQW1DO29CQUM5QyxRQUFRLEVBQUUsRUFBRSxHQUFHLE9BQU8sRUFBRTtvQkFDeEIsS0FBSyxFQUFFLE1BQU0sQ0FBQyxlQUFlLENBQUMsS0FBSyxDQUFDO29CQUNwQyxXQUFXO2lCQUNaLENBQUM7Z0JBRUYsMkJBQTJCO2dCQUMzQixrQkFBa0IsQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUM7Z0JBRWpDLE1BQU0sY0FBYyxHQUFhO29CQUMvQixLQUFLLEVBQUUsUUFBUTtvQkFDZixTQUFTLEVBQUUsT0FBTyxDQUFDLFNBQVM7b0JBQzVCLFNBQVMsRUFBRSxPQUFPLENBQUMsU0FBUztpQkFDN0IsQ0FBQztnQkFFRix1QkFBdUIsQ0FBQyxJQUFJLENBQUMsY0FBYyxDQUFDLENBQUM7Z0JBRTdDLE9BQU8sQ0FBQyxTQUFTLEdBQUcsUUFBUSxDQUFDO2dCQUM3QixPQUFPLENBQUMsU0FBUyxHQUFHLG1CQUFtQixHQUFHLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQztnQkFFcEQsTUFBTSxJQUFJLENBQUMsVUFBVSxDQUFDLE9BQU8sRUFBRSxNQUFNLENBQUMsZUFBZSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUM7YUFDL0Q7U0FDRjtRQUVELE1BQU0scUJBQXFCLEdBQUcsTUFBTSxJQUFJLENBQUMscUJBQXFCLENBQzVELGFBQWEsRUFDYixJQUFJLENBQ0wsQ0FBQztRQUVGLGdEQUFnRDtRQUNoRCxLQUFLLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsdUJBQXVCLENBQUMsTUFBTSxFQUFFLENBQUMsRUFBRSxFQUFFO1lBQ3ZELE1BQU0sSUFBSSxDQUFDLFVBQVUsQ0FBQyx1QkFBdUIsQ0FBQyxDQUFDLENBQUMsRUFBRSxtQkFBbUIsR0FBRyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztTQUNwRjtRQUVELE9BQU8sQ0FBQyxrQkFBa0IsRUFBRSxxQkFBcUIsQ0FBQyxDQUFDO0lBQ3JELENBQUM7SUFFRCxLQUFLLENBQUMscUJBQXFCLENBQ3pCLGFBQTRCLEVBQzVCLGtCQUEyQjtRQUUzQixNQUFNLHNCQUFzQixHQUFHLElBQUksQ0FBQyxZQUFZLENBQUMsa0JBQWtCLENBQUMsQ0FBQztRQUNyRSxNQUFNLGVBQWUsR0FBRyxNQUFNLElBQUksQ0FBQyxjQUFjLENBQUMsc0JBQXNCLEVBQUUsa0JBQWtCLENBQUMsQ0FBQztRQUU5RiwyRkFBMkY7UUFDM0YsT0FBTyxlQUFlLENBQUMscUJBQXFCLENBQUMsYUFBYSxDQUFDLENBQUM7SUFDOUQsQ0FBQztDQUNGIn0=
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"standard_indexed_tree.test.d.ts","sourceRoot":"","sources":["../../src/standard_indexed_tree/standard_indexed_tree.test.ts"],"names":[],"mappings":""}
|