Implement efficient incremental merkle tree.

This commit is contained in:
Kris Nuttycombe 2021-06-17 19:32:50 -06:00
parent 1267c8ec07
commit c1fcd83329
4 changed files with 1140 additions and 46 deletions

View File

@ -4,9 +4,8 @@ version = "0.1.0"
authors = ["Sean Bowe <ewillbefull@gmail.com>"]
edition = "2018"
# [dependencies]
# rand = "0.8"
# typenum = "1.12"
[dependencies]
serde = { version = "1.0", features = ["derive"] }
[dev-dependencies]
proptest = "0.10"

View File

@ -0,0 +1,16 @@
# Seeds for failure cases proptest has generated in the past. It is
# automatically read and these particular cases re-run before any
# novel cases are generated.
#
# It is recommended to check this file in to source control so that
# everyone who runs the test benefits from these saved cases.
cc 03d2e6d3f1b4481ff13703db7ae68090186d46f53b32b120ea7c8fd074d989bf # shrinks to ops = [Append(0)]
cc a5db6c7b12d4e62269748d5de35ec6c1d9ecad60d40648e4b13e70e62fb9d4c6 # shrinks to ops = [Checkpoint, Rewind, Append(0)]
cc 7db76fac780991d1809e66ea8313881b40942655d8acecd70a3764741aef061b # shrinks to ops = [Append(25), Witness, Authpath(25)]
cc 25abc8160aaeb3e31332e11b939fee7fc8df15e84c75c115b2b9b0e301a01c35 # shrinks to ops = [Append("a"), Append("a"), Checkpoint, Append("a"), Witness, Rewind]
cc 3aeb3f6da0d628f572f2c8eb0a96880f19ab6eabda0f755a2b7aa488857c5d05 # shrinks to ops = [Append("n"), Witness, Checkpoint, Append("n"), Witness, Rewind]
cc 05d84777b24be0fec28e8863e270a8394c1c1ada96d09653fe863e6f1fe22cd5 # shrinks to ops = [Append("a"), Append("a"), Append("a"), Append("a"), Append("a"), Append("a"), Append("a"), Append("a"), Append("a"), Append("a"), Append("l"), Witness, Append("a"), Authpath("l")]
cc 630bea6389a30231ca8a7bfbd52ff855ccb313e966683ad15e0e27c97fdb5812 # shrinks to ops = [Append("i"), Witness, Witness, Unwitness("i"), Unwitness("i")]
cc e235eeed24a308c7bd63636148fba5f70b2b764147d97f7ad742ae0aab246f3e # shrinks to ops = [Append("k"), Witness, Checkpoint, Rewind, Append("a"), Append("a"), Append("a"), Append("a"), Witness, Append("a"), Append("a"), Append("a"), Authpath("k")]
cc b2e8571f71e494c3a8f3eda094360ef35945b9761d2ec43eb1661abbc959b2d4 # shrinks to ops = [Append("a"), Checkpoint, Witness, Rewind]
cc f363fe92d0b7071b8e1a72098c169b5a2ae62ebb99ff8d8b7d1fffd6907901d1 # shrinks to ops = [Append("a"), Append("a"), Append("a"), Append("a"), Append("a"), Append("a"), Append("a"), Append("a"), Append("a"), Append("a"), Append("a"), Append("a"), Append("p"), Witness, Append("u"), Witness, Append("x"), Append("h"), Authpath("p")]

File diff suppressed because it is too large Load Diff

View File

@ -24,13 +24,14 @@
//! checkpoints that we're no longer interested in. It should be possible to
//! roll back to any previous checkpoint.
pub mod sample;
pub mod bridgetree;
pub mod sample;
use serde::{Deserialize, Serialize};
use std::ops::Add;
use std::ops::Sub;
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
#[repr(transparent)]
pub struct Level(u32);
@ -150,21 +151,21 @@ pub(crate) mod tests {
use std::hash::Hasher;
use std::hash::SipHasher;
use super::bridgetree::{EfficientRecording, EfficientTree};
use super::bridgetree::{BridgeRecording, BridgeTree};
use super::sample::{lazy_root, CompleteRecording, CompleteTree};
use super::{Hashable, Level, Recording, Tree};
#[derive(Clone)]
pub struct CombinedTree<H: Hashable + Hash + Eq> {
inefficient: CompleteTree<H>,
bridgetree: EfficientTree<H>,
efficient: BridgeTree<H>,
}
impl<H: Hashable + Hash + Eq + Clone> CombinedTree<H> {
pub fn new(depth: usize) -> Self {
CombinedTree {
inefficient: CompleteTree::new(depth, 100),
bridgetree: EfficientTree::new(depth),
efficient: BridgeTree::new(depth, 100),
}
}
}
@ -174,7 +175,7 @@ pub(crate) mod tests {
fn append(&mut self, value: &H) -> bool {
let a = self.inefficient.append(value);
let b = self.bridgetree.append(value);
let b = self.efficient.append(value);
assert_eq!(a, b);
a
}
@ -182,7 +183,7 @@ pub(crate) mod tests {
/// Obtains the current root of this Merkle tree.
fn root(&self) -> H {
let a = self.inefficient.root();
let b = self.bridgetree.root();
let b = self.efficient.root();
assert_eq!(a, b);
a
}
@ -191,7 +192,7 @@ pub(crate) mod tests {
/// witnessing. Returns true if successful and false if the tree is empty.
fn witness(&mut self) -> bool {
let a = self.inefficient.witness();
let b = self.bridgetree.witness();
let b = self.efficient.witness();
assert_eq!(a, b);
a
}
@ -201,7 +202,7 @@ pub(crate) mod tests {
/// specified value.
fn authentication_path(&self, value: &H) -> Option<(usize, Vec<H>)> {
let a = self.inefficient.authentication_path(value);
let b = self.bridgetree.authentication_path(value);
let b = self.efficient.authentication_path(value);
assert_eq!(a, b);
a
}
@ -211,7 +212,7 @@ pub(crate) mod tests {
/// false if the value is not a known witness.
fn remove_witness(&mut self, value: &H) -> bool {
let a = self.inefficient.remove_witness(value);
let b = self.bridgetree.remove_witness(value);
let b = self.efficient.remove_witness(value);
assert_eq!(a, b);
a
}
@ -220,7 +221,7 @@ pub(crate) mod tests {
/// checkpoint.
fn checkpoint(&mut self) {
self.inefficient.checkpoint();
self.bridgetree.checkpoint();
self.efficient.checkpoint();
}
/// Rewinds the tree state to the previous checkpoint. This function will
@ -228,7 +229,7 @@ pub(crate) mod tests {
/// witness data would be destroyed in the process.
fn rewind(&mut self) -> bool {
let a = self.inefficient.rewind();
let b = self.bridgetree.rewind();
let b = self.efficient.rewind();
assert_eq!(a, b);
a
}
@ -237,7 +238,7 @@ pub(crate) mod tests {
fn recording(&self) -> CombinedRecording<H> {
CombinedRecording {
inefficient: self.inefficient.recording(),
bridgetree: self.bridgetree.recording(),
efficient: self.efficient.recording(),
}
}
@ -245,7 +246,7 @@ pub(crate) mod tests {
/// and false if the recording is incompatible with the current tree state.
fn play(&mut self, recording: &CombinedRecording<H>) -> bool {
let a = self.inefficient.play(&recording.inefficient);
let b = self.bridgetree.play(&recording.bridgetree);
let b = self.efficient.play(&recording.efficient);
assert_eq!(a, b);
a
}
@ -254,20 +255,20 @@ pub(crate) mod tests {
#[derive(Clone)]
pub struct CombinedRecording<H: Hashable> {
inefficient: CompleteRecording<H>,
bridgetree: EfficientRecording<H>,
efficient: BridgeRecording<H>,
}
impl<H: Hashable + Clone + PartialEq> Recording<H> for CombinedRecording<H> {
fn append(&mut self, value: &H) -> bool {
let a = self.inefficient.append(value);
let b = self.bridgetree.append(value);
let b = self.efficient.append(value);
assert_eq!(a, b);
a
}
fn play(&mut self, recording: &Self) -> bool {
let a = self.inefficient.play(&recording.inefficient);
let b = self.bridgetree.play(&recording.bridgetree);
let b = self.efficient.play(&recording.efficient);
assert_eq!(a, b);
a
}