tornado-core/lib/MerkleTree.js

195 lines
5.9 KiB
JavaScript
Raw Normal View History

2019-07-16 19:27:20 +02:00
const jsStorage = require('./Storage')
const mimcHasher = require('./MiMC')
2019-07-11 12:38:22 +02:00
class MerkleTree {
constructor(n_levels, zero_value, defaultElements, prefix, storage, hasher) {
2019-07-16 19:27:20 +02:00
this.prefix = prefix
this.storage = storage || new jsStorage()
this.hasher = hasher || new mimcHasher()
this.n_levels = n_levels
this.zero_values = []
this.totalElements = 0
let current_zero_value = zero_value || 0
this.zero_values.push(current_zero_value)
2019-07-11 12:38:22 +02:00
for (let i = 0; i < n_levels; i++) {
2019-07-16 19:27:20 +02:00
current_zero_value = this.hasher.hash(i, current_zero_value, current_zero_value)
2019-07-11 12:38:22 +02:00
this.zero_values.push(
current_zero_value.toString(),
2019-07-16 19:27:20 +02:00
)
2019-07-11 12:38:22 +02:00
}
2019-07-11 16:04:36 +02:00
if (defaultElements) {
2019-07-16 19:27:20 +02:00
let level = 0
this.totalElements = defaultElements.length
defaultElements.forEach((element, i) => {
this.storage.put(MerkleTree.index_to_key(prefix, level, i), element)
})
level++
2019-07-22 23:19:50 +02:00
let numberOfElementsInLevel = Math.ceil(defaultElements.length / 2)
2019-07-16 19:27:20 +02:00
for (level; level <= this.n_levels; level++) {
2019-07-22 23:19:50 +02:00
for(let i = 0; i < numberOfElementsInLevel; i++) {
2019-07-16 19:27:20 +02:00
const leftKey = MerkleTree.index_to_key(prefix, level - 1, 2 * i)
const rightKey = MerkleTree.index_to_key(prefix, level - 1, 2 * i + 1)
const left = this.storage.get(leftKey)
const right = this.storage.get_or_element(rightKey, this.zero_values[level - 1])
const subRoot = this.hasher.hash(null, left, right)
this.storage.put(MerkleTree.index_to_key(prefix, level, i), subRoot)
2019-07-11 16:04:36 +02:00
}
2019-07-22 23:19:50 +02:00
numberOfElementsInLevel = Math.ceil(numberOfElementsInLevel / 2)
2019-07-16 19:27:20 +02:00
}
2019-07-11 16:04:36 +02:00
}
2019-07-11 12:38:22 +02:00
}
static index_to_key(prefix, level, index) {
2019-07-16 19:27:20 +02:00
const key = `${prefix}_tree_${level}_${index}`
return key
2019-07-11 12:38:22 +02:00
}
async root() {
let root = await this.storage.get_or_element(
MerkleTree.index_to_key(this.prefix, this.n_levels, 0),
this.zero_values[this.n_levels],
2019-07-16 19:27:20 +02:00
)
2019-07-11 12:38:22 +02:00
2019-07-16 19:27:20 +02:00
return root
2019-07-11 12:38:22 +02:00
}
async path(index) {
class PathTraverser {
constructor(prefix, storage, zero_values) {
2019-07-16 19:27:20 +02:00
this.prefix = prefix
this.storage = storage
this.zero_values = zero_values
this.path_elements = []
this.path_index = []
2019-07-11 12:38:22 +02:00
}
async handle_index(level, element_index, sibling_index) {
const sibling = await this.storage.get_or_element(
MerkleTree.index_to_key(this.prefix, level, sibling_index),
this.zero_values[level],
2019-07-16 19:27:20 +02:00
)
this.path_elements.push(sibling)
this.path_index.push(element_index % 2)
2019-07-11 12:38:22 +02:00
}
}
2019-07-16 19:27:20 +02:00
let traverser = new PathTraverser(this.prefix, this.storage, this.zero_values)
2019-07-11 12:38:22 +02:00
const root = await this.storage.get_or_element(
MerkleTree.index_to_key(this.prefix, this.n_levels, 0),
this.zero_values[this.n_levels],
2019-07-16 19:27:20 +02:00
)
2019-07-11 12:38:22 +02:00
const element = await this.storage.get_or_element(
MerkleTree.index_to_key(this.prefix, 0, index),
this.zero_values[0],
2019-07-16 19:27:20 +02:00
)
2019-07-11 12:38:22 +02:00
2019-07-16 19:27:20 +02:00
await this.traverse(index, traverser)
2019-07-11 12:38:22 +02:00
return {
root,
path_elements: traverser.path_elements,
path_index: traverser.path_index,
element
2019-07-16 19:27:20 +02:00
}
2019-07-11 12:38:22 +02:00
}
2019-07-12 12:24:59 +02:00
async update(index, element, insert = false) {
if (!insert && index >= this.totalElements) {
throw Error('Use insert method for new elements.')
} else if(insert && index < this.totalElements) {
throw Error('Use update method for existing elements.')
}
2019-07-11 12:38:22 +02:00
try {
class UpdateTraverser {
constructor(prefix, storage, hasher, element, zero_values) {
2019-07-16 19:27:20 +02:00
this.prefix = prefix
this.current_element = element
this.zero_values = zero_values
this.storage = storage
this.hasher = hasher
this.key_values_to_put = []
2019-07-11 12:38:22 +02:00
}
async handle_index(level, element_index, sibling_index) {
if (level == 0) {
this.original_element = await this.storage.get_or_element(
MerkleTree.index_to_key(this.prefix, level, element_index),
this.zero_values[level],
2019-07-16 19:27:20 +02:00
)
2019-07-11 12:38:22 +02:00
}
const sibling = await this.storage.get_or_element(
MerkleTree.index_to_key(this.prefix, level, sibling_index),
this.zero_values[level],
2019-07-16 19:27:20 +02:00
)
let left, right
2019-07-11 12:38:22 +02:00
if (element_index % 2 == 0) {
2019-07-16 19:27:20 +02:00
left = this.current_element
right = sibling
2019-07-11 12:38:22 +02:00
} else {
2019-07-16 19:27:20 +02:00
left = sibling
right = this.current_element
2019-07-11 12:38:22 +02:00
}
this.key_values_to_put.push({
key: MerkleTree.index_to_key(this.prefix, level, element_index),
value: this.current_element,
2019-07-16 19:27:20 +02:00
})
this.current_element = this.hasher.hash(level, left, right)
2019-07-11 12:38:22 +02:00
}
}
let traverser = new UpdateTraverser(
this.prefix,
this.storage,
this.hasher,
element,
this.zero_values
2019-07-16 19:27:20 +02:00
)
2019-07-11 12:38:22 +02:00
2019-07-16 19:27:20 +02:00
await this.traverse(index, traverser)
2019-07-11 12:38:22 +02:00
traverser.key_values_to_put.push({
key: MerkleTree.index_to_key(this.prefix, this.n_levels, 0),
value: traverser.current_element,
2019-07-16 19:27:20 +02:00
})
2019-07-11 12:38:22 +02:00
2019-07-16 19:27:20 +02:00
await this.storage.put_batch(traverser.key_values_to_put)
2019-07-11 16:04:36 +02:00
} catch(e) {
2019-07-16 19:27:20 +02:00
console.error(e)
2019-07-11 12:38:22 +02:00
}
}
2019-07-12 12:24:59 +02:00
async insert(element) {
const index = this.totalElements
await this.update(index, element, true)
this.totalElements++
}
2019-07-11 12:38:22 +02:00
async traverse(index, handler) {
2019-07-16 19:27:20 +02:00
let current_index = index
2019-07-11 12:38:22 +02:00
for (let i = 0; i < this.n_levels; i++) {
2019-07-16 19:27:20 +02:00
let sibling_index = current_index
if (current_index % 2 == 0) {
sibling_index += 1
} else {
sibling_index -= 1
2019-07-11 12:38:22 +02:00
}
2019-07-16 19:27:20 +02:00
await handler.handle_index(i, current_index, sibling_index)
current_index = Math.floor(current_index / 2)
}
2019-07-11 12:38:22 +02:00
}
2019-07-17 23:25:16 +02:00
getIndexByElement(element) {
for(let i = this.totalElements - 1; i >= 0; i--) {
const elementFromTree = this.storage.get(MerkleTree.index_to_key(this.prefix, 0, i))
if (elementFromTree === element) {
return i
}
}
return false
}
2019-07-11 12:38:22 +02:00
}
2019-07-16 19:27:20 +02:00
module.exports = MerkleTree