use crate::{
hasher::NodeHasher,
proof::{
path_proof::{hash_path, shared_bits},
KeyOutOfScope, PathProof, PathProofTerminal,
},
trie::{InternalData, KeyPath, LeafData, Node, NodeKind, ValueHash, TERMINATOR},
};
#[cfg(not(feature = "std"))]
use alloc::{vec, vec::Vec};
use bitvec::prelude::*;
use core::{cmp::Ordering, ops::Range};
#[derive(Debug, Clone)]
#[cfg_attr(
feature = "borsh",
derive(borsh::BorshDeserialize, borsh::BorshSerialize)
)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct MultiPathProof {
pub terminal: PathProofTerminal,
pub depth: usize,
}
#[derive(Debug, Clone)]
#[cfg_attr(
feature = "borsh",
derive(borsh::BorshDeserialize, borsh::BorshSerialize)
)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct MultiProof {
pub paths: Vec<MultiPathProof>,
pub siblings: Vec<Node>,
}
struct PathProofRange {
lower: usize,
upper: usize,
path_bit_index: usize,
}
enum PathProofRangeStep {
Bisect {
left: PathProofRange,
right: PathProofRange,
},
Advance {
sibling: Node,
},
}
impl PathProofRange {
fn prove_unique_path_remainder(
&self,
path_proofs: &[PathProof],
) -> Option<(MultiPathProof, Vec<Node>)> {
if self.lower != self.upper - 1 {
return None;
}
let path_proof = &path_proofs[self.lower];
let unique_siblings: Vec<Node> = path_proof
.siblings
.iter()
.skip(self.path_bit_index)
.copied()
.collect();
Some((
MultiPathProof {
terminal: path_proof.terminal.clone(),
depth: self.path_bit_index + unique_siblings.len(),
},
unique_siblings,
))
}
fn step(&mut self, path_proofs: &[PathProof]) -> PathProofRangeStep {
let path_lower = path_proofs[self.lower].terminal.path();
let path_upper = path_proofs[self.upper - 1].terminal.path();
if path_lower[self.path_bit_index] != path_upper[self.path_bit_index] {
let mid = self.lower
+ path_proofs[self.lower..self.upper]
.binary_search_by(|path_proof| {
if !path_proof.terminal.path()[self.path_bit_index] {
core::cmp::Ordering::Less
} else {
core::cmp::Ordering::Greater
}
})
.unwrap_err();
let left = PathProofRange {
path_bit_index: self.path_bit_index + 1,
lower: self.lower,
upper: mid,
};
let right = PathProofRange {
path_bit_index: self.path_bit_index + 1,
lower: mid,
upper: self.upper,
};
PathProofRangeStep::Bisect { left, right }
} else {
let sibling = path_proofs[self.lower].siblings[self.path_bit_index];
self.path_bit_index += 1;
PathProofRangeStep::Advance { sibling }
}
}
}
impl MultiProof {
pub fn from_path_proofs(path_proofs: Vec<PathProof>) -> Self {
if path_proofs.is_empty() {
return MultiProof {
paths: Vec::new(),
siblings: Vec::new(),
};
}
let mut paths: Vec<MultiPathProof> = vec![];
let mut siblings: Vec<Node> = vec![];
let mut proof_range = PathProofRange {
path_bit_index: 0,
lower: 0,
upper: path_proofs.len(),
};
let mut common_siblings: Vec<Node> = vec![];
let mut stack: Vec<PathProofRange> = vec![];
loop {
if let Some((sub_path_proof, unique_siblings)) =
proof_range.prove_unique_path_remainder(&path_proofs)
{
paths.push(sub_path_proof);
siblings.extend(unique_siblings);
assert!(common_siblings.is_empty());
proof_range = match stack.pop() {
Some(v) => v,
None => break,
};
continue;
}
match proof_range.step(&path_proofs) {
PathProofRangeStep::Bisect { left, right } => {
siblings.extend(common_siblings.drain(..));
proof_range = left;
stack.push(right);
}
PathProofRangeStep::Advance { sibling } => common_siblings.push(sibling),
};
}
Self { paths, siblings }
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum MultiProofVerificationError {
RootMismatch,
PathsOutOfOrder,
TooManySiblings,
}
#[derive(Debug, Clone)]
struct VerifiedMultiPath {
terminal: PathProofTerminal,
depth: usize,
unique_siblings: Range<usize>,
}
#[derive(Debug, Clone)]
struct VerifiedBisection {
start_depth: usize,
common_siblings: Range<usize>,
}
#[derive(Debug, Clone)]
#[must_use = "VerifiedMultiProof only checks the consistency of the trie, not the values"]
pub struct VerifiedMultiProof {
inner: Vec<VerifiedMultiPath>,
bisections: Vec<VerifiedBisection>,
siblings: Vec<Node>,
root: Node,
}
impl VerifiedMultiProof {
pub fn find_index_for(&self, key_path: &KeyPath) -> Result<usize, KeyOutOfScope> {
let search_result = self.inner.binary_search_by(|v| {
v.terminal.path()[..v.depth].cmp(&key_path.view_bits::<Msb0>()[..v.depth])
});
search_result.map_err(|_| KeyOutOfScope)
}
pub fn confirm_nonexistence(&self, key_path: &KeyPath) -> Result<bool, KeyOutOfScope> {
let index = self.find_index_for(key_path)?;
Ok(self.confirm_nonexistence_inner(key_path, index))
}
pub fn confirm_value(&self, expected_leaf: &LeafData) -> Result<bool, KeyOutOfScope> {
let index = self.find_index_for(&expected_leaf.key_path)?;
Ok(self.confirm_value_inner(&expected_leaf, index))
}
pub fn confirm_nonexistence_with_index(
&self,
key_path: &KeyPath,
index: usize,
) -> Result<bool, KeyOutOfScope> {
let path = &self.inner[index];
let depth = path.depth;
let in_scope = path.terminal.path()[..depth] == key_path.view_bits::<Msb0>()[..depth];
if in_scope {
Ok(self.confirm_nonexistence_inner(key_path, index))
} else {
Err(KeyOutOfScope)
}
}
pub fn confirm_value_with_index(
&self,
expected_leaf: &LeafData,
index: usize,
) -> Result<bool, KeyOutOfScope> {
let path = &self.inner[index];
let depth = path.depth;
let in_scope =
path.terminal.path()[..depth] == expected_leaf.key_path.view_bits::<Msb0>()[..depth];
if in_scope {
Ok(self.confirm_value_inner(&expected_leaf, index))
} else {
Err(KeyOutOfScope)
}
}
fn confirm_nonexistence_inner(&self, key_path: &KeyPath, index: usize) -> bool {
match self.inner[index].terminal {
PathProofTerminal::Terminator(_) => true,
PathProofTerminal::Leaf(ref leaf_data) => &leaf_data.key_path != key_path,
}
}
fn confirm_value_inner(&self, expected_leaf: &LeafData, index: usize) -> bool {
match self.inner[index].terminal {
PathProofTerminal::Terminator(_) => false,
PathProofTerminal::Leaf(ref leaf_data) => leaf_data == expected_leaf,
}
}
}
pub fn verify<H: NodeHasher>(
multi_proof: &MultiProof,
root: Node,
) -> Result<VerifiedMultiProof, MultiProofVerificationError> {
let mut verified_paths = Vec::with_capacity(multi_proof.paths.len());
let mut verified_bisections = Vec::new();
for i in 0..multi_proof.paths.len() {
let path = &multi_proof.paths[i];
if i > 0 {
if path.terminal.path() <= multi_proof.paths[i - 1].terminal.path() {
return Err(MultiProofVerificationError::PathsOutOfOrder);
}
}
}
let (new_root, siblings_used) = verify_range::<H>(
0,
&multi_proof.paths,
&multi_proof.siblings,
0,
&mut verified_paths,
&mut verified_bisections,
)?;
if root != new_root {
return Err(MultiProofVerificationError::RootMismatch);
}
if siblings_used != multi_proof.siblings.len() {
return Err(MultiProofVerificationError::TooManySiblings);
}
Ok(VerifiedMultiProof {
inner: verified_paths,
bisections: verified_bisections,
siblings: multi_proof.siblings.clone(),
root: root,
})
}
fn verify_range<H: NodeHasher>(
start_depth: usize,
paths: &[MultiPathProof],
siblings: &[Node],
sibling_offset: usize,
verified_paths: &mut Vec<VerifiedMultiPath>,
verified_bisections: &mut Vec<VerifiedBisection>,
) -> Result<(Node, usize), MultiProofVerificationError> {
if paths.is_empty() {
verified_paths.push(VerifiedMultiPath {
terminal: PathProofTerminal::Terminator(crate::trie_pos::TriePosition::new()),
depth: 0,
unique_siblings: Range { start: 0, end: 0 },
});
return Ok((TERMINATOR, 0));
}
if paths.len() == 1 {
let terminal_path = &paths[0];
let unique_len = terminal_path.depth - start_depth;
let node = hash_path::<H>(
terminal_path.terminal.node::<H>(),
&terminal_path.terminal.path()[start_depth..start_depth + unique_len],
siblings[..unique_len].iter().rev().copied(),
);
verified_paths.push(VerifiedMultiPath {
terminal: terminal_path.terminal.clone(),
depth: terminal_path.depth,
unique_siblings: Range {
start: sibling_offset,
end: sibling_offset + unique_len,
},
});
return Ok((node, unique_len));
}
let start_path = &paths[0];
let end_path = &paths[paths.len() - 1];
let common_bits = shared_bits(
&start_path.terminal.path()[start_depth..],
&end_path.terminal.path()[start_depth..],
);
let common_len = start_depth + common_bits;
let uncommon_start_len = common_len + 1;
let search_result = paths.binary_search_by(|item| {
if !item.terminal.path()[uncommon_start_len - 1] {
Ordering::Less
} else {
Ordering::Greater
}
});
let bisect_idx = search_result.unwrap_err();
if common_bits > 0 {
verified_bisections.push(VerifiedBisection {
start_depth,
common_siblings: Range {
start: sibling_offset,
end: sibling_offset + common_bits,
},
});
}
let (left_node, left_siblings_used) = verify_range::<H>(
uncommon_start_len,
&paths[..bisect_idx],
&siblings[common_bits..],
sibling_offset + common_bits,
verified_paths,
verified_bisections,
)?;
let (right_node, right_siblings_used) = verify_range::<H>(
uncommon_start_len,
&paths[bisect_idx..],
&siblings[common_bits + left_siblings_used..],
sibling_offset + common_bits + left_siblings_used,
verified_paths,
verified_bisections,
)?;
let total_siblings_used = common_bits + left_siblings_used + right_siblings_used;
let node = hash_path::<H>(
H::hash_internal(&InternalData {
left: left_node,
right: right_node,
}),
&start_path.terminal.path()[start_depth..common_len], siblings[..common_bits].iter().rev().copied(),
);
Ok((node, total_siblings_used))
}
#[derive(Debug, Clone, Copy)]
pub enum MultiVerifyUpdateError {
OpsOutOfOrder,
OpOutOfScope,
RootMismatch,
PathPrefixOfAnother,
}
fn terminal_contains(terminal: &VerifiedMultiPath, key_path: &KeyPath) -> bool {
key_path.view_bits::<Msb0>()[..terminal.depth] == terminal.terminal.path()[..terminal.depth]
}
#[derive(Debug)]
struct CommonSiblings {
bisection_stack: Vec<VerifiedBisection>,
stack: Vec<(usize, Node)>,
taken_siblings: usize,
terminal_index: usize,
bisection_index: usize,
}
impl CommonSiblings {
fn new() -> Self {
CommonSiblings {
bisection_stack: Vec::new(),
stack: Vec::new(),
taken_siblings: 0,
terminal_index: 0,
bisection_index: 0,
}
}
fn advance(&mut self, proof: &VerifiedMultiProof) {
let next_terminal = &proof.inner[self.terminal_index];
let mut prune = true;
while next_terminal.unique_siblings.start != self.taken_siblings {
let next_bisection = &proof.bisections[self.bisection_index];
self.bisection_index += 1;
assert_eq!(next_bisection.common_siblings.start, self.taken_siblings);
if prune {
self.pop_to(next_bisection.start_depth);
prune = false;
}
self.extend(
next_bisection.start_depth + 1,
next_bisection.common_siblings.end,
&proof.siblings,
false,
);
self.bisection_stack.push(next_bisection.clone());
}
let terminal_n = next_terminal.unique_siblings.end - next_terminal.unique_siblings.start;
self.extend(
next_terminal.depth - terminal_n + 1,
next_terminal.unique_siblings.end,
&proof.siblings,
true,
);
self.terminal_index += 1;
}
fn pop_to(&mut self, depth: usize) {
while self
.bisection_stack
.last()
.map_or(false, |b| b.start_depth >= depth)
{
let _ = self.bisection_stack.pop();
}
while self.stack.last().map_or(false, |(d, _)| *d >= depth) {
let _ = self.stack.pop();
}
}
fn extend(&mut self, start_depth: usize, end: usize, siblings: &[Node], reverse: bool) {
if reverse {
for (i, sibling) in siblings[self.taken_siblings..end].iter().rev().enumerate() {
self.stack.push((start_depth + i, *sibling))
}
} else {
for (i, sibling) in siblings[self.taken_siblings..end].iter().enumerate() {
self.stack.push((start_depth + i, *sibling))
}
}
self.taken_siblings = end;
}
fn pop_if_at_depth(&mut self, depth: usize) -> Option<Node> {
if self.stack.last().map_or(false, |(d, _)| *d == depth) {
self.stack.pop().map(|(_, n)| n)
} else {
None
}
}
}
pub fn verify_update<H: NodeHasher>(
proof: &VerifiedMultiProof,
ops: Vec<(KeyPath, Option<ValueHash>)>,
) -> Result<Node, MultiVerifyUpdateError> {
if ops.is_empty() {
return Ok(proof.root);
}
let mut pending_siblings: Vec<(Node, usize)> = Vec::new();
let mut last_key = None;
let mut last_terminal_index = None;
let mut next_pending_terminal_index = None;
let mut working_ops = Vec::new();
let mut common_siblings = CommonSiblings::new();
let ops_len = ops.len();
for (i, (key, op)) in ops.into_iter().chain(Some(([0u8; 32], None))).enumerate() {
let is_last = i == ops_len;
if is_last {
let updated_terminal_index = last_terminal_index.unwrap_or(0);
let start = next_pending_terminal_index.unwrap_or(0);
for terminal_index in start..proof.inner.len() {
let next = if terminal_index == proof.inner.len() - 1 {
None
} else {
Some(terminal_index + 1)
};
let terminal = &proof.inner[terminal_index];
let next_terminal = next.map(|n| &proof.inner[n]);
let ops = if terminal_index == updated_terminal_index {
&working_ops[..]
} else {
&[]
};
common_siblings.advance(&proof);
hash_and_compact_terminal::<H>(
&mut pending_siblings,
terminal,
next_terminal,
&mut common_siblings,
ops,
)?;
}
} else {
if let Some(last_key) = last_key {
if key <= last_key {
return Err(MultiVerifyUpdateError::OpsOutOfOrder);
}
}
last_key = Some(key);
let mut next_terminal_index = last_terminal_index.unwrap_or(0);
if proof.inner.len() <= next_terminal_index {
return Err(MultiVerifyUpdateError::OpOutOfScope);
}
while !terminal_contains(&proof.inner[next_terminal_index], &key) {
next_terminal_index += 1;
if proof.inner.len() <= next_terminal_index {
return Err(MultiVerifyUpdateError::OpOutOfScope);
}
}
if last_terminal_index.map_or(true, |x| x == next_terminal_index) {
last_terminal_index = Some(next_terminal_index);
working_ops.push((key, op));
continue;
}
let updated_index = last_terminal_index.unwrap();
last_terminal_index = Some(next_terminal_index);
let start = next_pending_terminal_index.unwrap_or(0);
for terminal_index in start..updated_index {
let terminal = &proof.inner[terminal_index];
let next_terminal = Some(&proof.inner[terminal_index + 1]);
common_siblings.advance(&proof);
hash_and_compact_terminal::<H>(
&mut pending_siblings,
terminal,
next_terminal,
&mut common_siblings,
&[],
)?;
}
let ops = core::mem::replace(&mut working_ops, Vec::new());
working_ops.push((key, op));
let terminal = &proof.inner[updated_index];
let next_terminal = proof.inner.get(updated_index + 1);
common_siblings.advance(&proof);
hash_and_compact_terminal::<H>(
&mut pending_siblings,
terminal,
next_terminal,
&mut common_siblings,
&ops,
)?;
next_pending_terminal_index = Some(updated_index + 1);
};
}
Ok(pending_siblings.pop().map(|n| n.0).unwrap_or(proof.root))
}
fn hash_and_compact_terminal<H: NodeHasher>(
pending_siblings: &mut Vec<(Node, usize)>,
terminal: &VerifiedMultiPath,
next_terminal: Option<&VerifiedMultiPath>,
common_siblings: &mut CommonSiblings,
ops: &[(KeyPath, Option<ValueHash>)],
) -> Result<(), MultiVerifyUpdateError> {
let leaf = terminal.terminal.as_leaf_option();
let skip = terminal.depth;
let up_layers = if let Some(next_terminal) = next_terminal {
let n = shared_bits(terminal.terminal.path(), next_terminal.terminal.path());
if n == skip {
return Err(MultiVerifyUpdateError::PathPrefixOfAnother);
}
skip - (n + 1)
} else {
skip };
let ops = crate::update::leaf_ops_spliced(leaf, &ops);
let sub_root = crate::update::build_trie::<H>(skip, ops, |_| {});
let mut cur_node = sub_root;
let mut cur_layer = skip;
let end_layer = skip - up_layers;
for bit in terminal.terminal.path()[..terminal.depth]
.iter()
.by_vals()
.rev()
.take(up_layers)
{
let sibling = if pending_siblings.last().map_or(false, |p| p.1 == cur_layer) {
let _ = common_siblings.pop_if_at_depth(cur_layer);
pending_siblings.pop().unwrap().0
} else {
common_siblings.pop_if_at_depth(cur_layer).unwrap()
};
match (NodeKind::of::<H>(&cur_node), NodeKind::of::<H>(&sibling)) {
(NodeKind::Terminator, NodeKind::Terminator) => {}
(NodeKind::Leaf, NodeKind::Terminator) => {}
(NodeKind::Terminator, NodeKind::Leaf) => {
cur_node = sibling;
}
_ => {
let node_data = if bit {
InternalData {
left: sibling,
right: cur_node,
}
} else {
InternalData {
left: cur_node,
right: sibling,
}
};
cur_node = H::hash_internal(&node_data);
}
}
cur_layer -= 1;
}
pending_siblings.push((cur_node, end_layer));
Ok(())
}
#[cfg(test)]
mod tests {
use super::{verify, verify_update, MultiProof};
use crate::proof::multi_proof::{
MultiVerifyUpdateError, VerifiedMultiPath, VerifiedMultiProof,
};
use crate::{
hasher::{Blake3Hasher, NodeHasher},
proof::{PathProof, PathProofTerminal},
trie::{InternalData, KeyPath, LeafData, ValueHash, TERMINATOR},
trie_pos::TriePosition,
update::build_trie,
};
use bitvec::prelude::*;
#[test]
pub fn test_multiproof_creation_single_path_proof() {
let mut key_path = [0; 32];
key_path[0] = 0b10000000;
let sibling1 = [1; 32];
let sibling2 = [2; 32];
let path_proof = PathProof {
terminal: PathProofTerminal::Terminator(TriePosition::from_path_and_depth(
key_path, 256,
)),
siblings: vec![sibling1, sibling2],
};
let multi_proof = MultiProof::from_path_proofs(vec![path_proof]);
assert_eq!(multi_proof.paths.len(), 1);
assert_eq!(
multi_proof.paths[0].terminal,
PathProofTerminal::Terminator(TriePosition::from_path_and_depth(key_path, 256))
);
assert_eq!(multi_proof.paths[0].depth, 2);
assert_eq!(multi_proof.siblings.len(), 2);
assert_eq!(multi_proof.siblings, vec![sibling1, sibling2]);
}
#[test]
pub fn test_multiproof_creation_two_path_proofs() {
let mut key_path_1 = [0; 32];
key_path_1[0] = 0b00000000;
let mut key_path_2 = [0; 32];
key_path_2[0] = 0b00111000;
let sibling1 = [1; 32];
let sibling2 = [2; 32];
let sibling3 = [3; 32];
let sibling4 = [4; 32];
let sibling5 = [5; 32];
let sibling6 = [6; 32];
let sibling_x = [b'x'; 32];
let path_proof_1 = PathProof {
terminal: PathProofTerminal::Terminator(TriePosition::from_path_and_depth(
key_path_1, 256,
)),
siblings: vec![sibling1, sibling2, sibling_x, sibling3, sibling4],
};
let path_proof_2 = PathProof {
terminal: PathProofTerminal::Terminator(TriePosition::from_path_and_depth(
key_path_2, 256,
)),
siblings: vec![sibling1, sibling2, sibling_x, sibling5, sibling6],
};
let multi_proof = MultiProof::from_path_proofs(vec![path_proof_1, path_proof_2]);
assert_eq!(multi_proof.paths.len(), 2);
assert_eq!(multi_proof.siblings.len(), 6);
assert_eq!(
multi_proof.paths[0].terminal,
PathProofTerminal::Terminator(TriePosition::from_path_and_depth(key_path_1, 256))
);
assert_eq!(
multi_proof.paths[1].terminal,
PathProofTerminal::Terminator(TriePosition::from_path_and_depth(key_path_2, 256))
);
assert_eq!(multi_proof.paths[0].depth, 5);
assert_eq!(multi_proof.paths[1].depth, 5);
assert_eq!(
multi_proof.siblings,
vec![sibling1, sibling2, sibling3, sibling4, sibling5, sibling6]
);
}
#[test]
pub fn test_multiproof_creation_two_path_proofs_256_depth() {
let mut key_path_1 = [0; 32];
key_path_1[31] = 0b00000000;
let mut key_path_2 = [0; 32];
key_path_2[31] = 0b00000001;
let mut siblings_1: Vec<[u8; 32]> = (0..255).map(|i| [i; 32]).collect();
let mut siblings_2 = siblings_1.clone();
siblings_1.push([b'2'; 32]);
siblings_2.push([b'1'; 32]);
let path_proof_1 = PathProof {
terminal: PathProofTerminal::Terminator(TriePosition::from_path_and_depth(
key_path_1, 256,
)),
siblings: siblings_1.clone(),
};
let path_proof_2 = PathProof {
terminal: PathProofTerminal::Terminator(TriePosition::from_path_and_depth(
key_path_2, 256,
)),
siblings: siblings_2,
};
let multi_proof = MultiProof::from_path_proofs(vec![path_proof_1, path_proof_2]);
assert_eq!(multi_proof.paths.len(), 2);
assert_eq!(multi_proof.siblings.len(), 255);
assert_eq!(
multi_proof.paths[0].terminal,
PathProofTerminal::Terminator(TriePosition::from_path_and_depth(key_path_1, 256))
);
assert_eq!(
multi_proof.paths[1].terminal,
PathProofTerminal::Terminator(TriePosition::from_path_and_depth(key_path_2, 256))
);
assert_eq!(multi_proof.paths[0].depth, 256);
assert_eq!(multi_proof.paths[1].depth, 256);
siblings_1.pop();
assert_eq!(multi_proof.siblings, siblings_1);
}
#[test]
pub fn test_multiproof_creation_multiple_path_proofs() {
let mut key_path_1 = [0; 32];
key_path_1[0] = 0b00000000;
let mut key_path_2 = [0; 32];
key_path_2[0] = 0b01000000;
let mut key_path_3 = [0; 32];
key_path_3[0] = 0b01001100;
let mut key_path_4 = [0; 32];
key_path_4[0] = 0b11101100;
let mut key_path_5 = [0; 32];
key_path_5[0] = 0b11110100;
let mut key_path_6 = [0; 32];
key_path_6[0] = 0b11111000;
let sibling1 = [1; 32];
let sibling2 = [2; 32];
let sibling3 = [3; 32];
let sibling4 = [4; 32];
let sibling5 = [5; 32];
let sibling6 = [6; 32];
let sibling7 = [7; 32];
let sibling8 = [8; 32];
let sibling9 = [9; 32];
let sibling10 = [10; 32];
let sibling11 = [11; 32];
let sibling12 = [12; 32];
let sibling13 = [13; 32];
let sibling14 = [14; 32];
let sibling15 = [15; 32];
let sibling16 = [16; 32];
let sibling17 = [17; 32];
let sibling18 = [18; 32];
let sibling19 = [19; 32];
let path_proof_1 = PathProof {
terminal: PathProofTerminal::Terminator(TriePosition::from_path_and_depth(
key_path_1, 256,
)),
siblings: vec![sibling1, sibling2],
};
let path_proof_2 = PathProof {
terminal: PathProofTerminal::Terminator(TriePosition::from_path_and_depth(
key_path_2, 256,
)),
siblings: vec![sibling1, sibling3, sibling4, sibling5, sibling6, sibling7],
};
let path_proof_3 = PathProof {
terminal: PathProofTerminal::Terminator(TriePosition::from_path_and_depth(
key_path_3, 256,
)),
siblings: vec![sibling1, sibling3, sibling4, sibling5, sibling8, sibling9],
};
let path_proof_4 = PathProof {
terminal: PathProofTerminal::Terminator(TriePosition::from_path_and_depth(
key_path_4, 256,
)),
siblings: vec![
sibling10, sibling11, sibling12, sibling13, sibling14, sibling15,
],
};
let path_proof_5 = PathProof {
terminal: PathProofTerminal::Terminator(TriePosition::from_path_and_depth(
key_path_5, 256,
)),
siblings: vec![
sibling10, sibling11, sibling12, sibling16, sibling17, sibling18,
],
};
let path_proof_6 = PathProof {
terminal: PathProofTerminal::Terminator(TriePosition::from_path_and_depth(
key_path_6, 256,
)),
siblings: vec![sibling10, sibling11, sibling12, sibling16, sibling19],
};
let multi_proof = MultiProof::from_path_proofs(vec![
path_proof_1,
path_proof_2,
path_proof_3,
path_proof_4,
path_proof_5,
path_proof_6,
]);
assert_eq!(multi_proof.paths.len(), 6);
assert_eq!(multi_proof.siblings.len(), 9);
assert_eq!(
multi_proof.paths[0].terminal,
PathProofTerminal::Terminator(TriePosition::from_path_and_depth(key_path_1, 256))
);
assert_eq!(
multi_proof.paths[1].terminal,
PathProofTerminal::Terminator(TriePosition::from_path_and_depth(key_path_2, 256))
);
assert_eq!(
multi_proof.paths[2].terminal,
PathProofTerminal::Terminator(TriePosition::from_path_and_depth(key_path_3, 256))
);
assert_eq!(
multi_proof.paths[3].terminal,
PathProofTerminal::Terminator(TriePosition::from_path_and_depth(key_path_4, 256))
);
assert_eq!(
multi_proof.paths[4].terminal,
PathProofTerminal::Terminator(TriePosition::from_path_and_depth(key_path_5, 256))
);
assert_eq!(
multi_proof.paths[5].terminal,
PathProofTerminal::Terminator(TriePosition::from_path_and_depth(key_path_6, 256))
);
assert_eq!(multi_proof.paths[0].depth, 2);
assert_eq!(multi_proof.paths[1].depth, 6);
assert_eq!(multi_proof.paths[2].depth, 6);
assert_eq!(multi_proof.paths[3].depth, 6);
assert_eq!(multi_proof.paths[4].depth, 6);
assert_eq!(multi_proof.paths[5].depth, 5);
assert_eq!(
multi_proof.siblings,
vec![
sibling4, sibling5, sibling7, sibling9, sibling11, sibling12, sibling14, sibling15,
sibling18
]
);
}
#[test]
pub fn test_multiproof_creation_ext_siblings_order() {
let mut key_path_0 = [0; 32];
key_path_0[0] = 0b00001000;
let mut key_path_1 = [0; 32];
key_path_1[0] = 0b00010000;
let mut key_path_2 = [0; 32];
key_path_2[0] = 0b10000000;
let mut key_path_3 = [0; 32];
key_path_3[0] = 0b10000010;
let mut key_path_4 = [0; 32];
key_path_4[0] = 0b10010001;
let mut key_path_5 = [0; 32];
key_path_5[0] = 0b10010011;
let sibling1 = [1; 32];
let sibling2 = [2; 32];
let sibling3 = [3; 32];
let sibling4 = [4; 32];
let sibling5 = [5; 32];
let sibling6 = [6; 32];
let sibling7 = [7; 32];
let sibling8 = [8; 32];
let sibling9 = [9; 32];
let sibling10 = [10; 32];
let sibling11 = [11; 32];
let sibling12 = [12; 32];
let sibling13 = [13; 32];
let sibling14 = [14; 32];
let sibling15 = [15; 32];
let sibling16 = [16; 32];
let sibling17 = [17; 32];
let sibling18 = [18; 32];
let sibling19 = [19; 32];
let sibling20 = [20; 32];
let sibling21 = [21; 32];
let sibling22 = [22; 32];
let sibling23 = [23; 32];
let sibling24 = [24; 32];
let path_proof_0 = PathProof {
terminal: PathProofTerminal::Terminator(TriePosition::from_path_and_depth(
key_path_0, 256,
)),
siblings: vec![sibling1, sibling2, sibling3, sibling4, sibling5],
};
let path_proof_1 = PathProof {
terminal: PathProofTerminal::Terminator(TriePosition::from_path_and_depth(
key_path_1, 256,
)),
siblings: vec![sibling1, sibling2, sibling3, sibling6, sibling7],
};
let path_proof_2 = PathProof {
terminal: PathProofTerminal::Terminator(TriePosition::from_path_and_depth(
key_path_2, 256,
)),
siblings: vec![
sibling8, sibling9, sibling10, sibling11, sibling12, sibling13, sibling14,
sibling15,
],
};
let path_proof_3 = PathProof {
terminal: PathProofTerminal::Terminator(TriePosition::from_path_and_depth(
key_path_3, 256,
)),
siblings: vec![
sibling8, sibling9, sibling10, sibling11, sibling12, sibling13, sibling16,
sibling17,
],
};
let path_proof_4 = PathProof {
terminal: PathProofTerminal::Terminator(TriePosition::from_path_and_depth(
key_path_4, 256,
)),
siblings: vec![
sibling8, sibling9, sibling10, sibling18, sibling19, sibling20, sibling21,
sibling22,
],
};
let path_proof_5 = PathProof {
terminal: PathProofTerminal::Terminator(TriePosition::from_path_and_depth(
key_path_5, 256,
)),
siblings: vec![
sibling8, sibling9, sibling10, sibling18, sibling19, sibling20, sibling23,
sibling24,
],
};
let multi_proof = MultiProof::from_path_proofs(vec![
path_proof_0,
path_proof_1,
path_proof_2,
path_proof_3,
path_proof_4,
path_proof_5,
]);
assert_eq!(multi_proof.paths.len(), 6);
assert_eq!(multi_proof.siblings.len(), 14);
assert_eq!(
multi_proof.siblings,
vec![
sibling2, sibling3, sibling5, sibling7, sibling9, sibling10, sibling12, sibling13,
sibling15, sibling17, sibling19, sibling20, sibling22, sibling24
]
);
}
#[test]
fn multi_proof_failure_empty_witness() {
let multi_proof = MultiProof::from_path_proofs(Vec::new());
let _verified_multi_proof = verify::<Blake3Hasher>(&multi_proof, TERMINATOR).unwrap();
}
#[test]
fn multi_proof_verify_empty() {
let multi_proof = MultiProof::from_path_proofs(Vec::new());
let verified_multi_proof = verify::<Blake3Hasher>(&multi_proof, TERMINATOR).unwrap();
assert_eq!(
verify_update::<Blake3Hasher>(&verified_multi_proof, Vec::new()).unwrap(),
TERMINATOR,
);
}
#[test]
fn multi_proof_verify_empty_with_provided_updates() {
let multi_proof = MultiProof::from_path_proofs(Vec::new());
let verified_multi_proof = verify::<Blake3Hasher>(&multi_proof, TERMINATOR).unwrap();
let mut key_path_0 = [0; 32];
key_path_0[0] = 0b00001000;
let mut key_path_1 = [0; 32];
key_path_1[0] = 0b00010000;
let mut key_path_2 = [0; 32];
key_path_2[0] = 0b10000000;
let ops = vec![
(key_path_0, Some([1; 32])),
(key_path_1, Some([1; 32])),
(key_path_2, Some([1; 32])),
];
let expected_root = build_trie::<Blake3Hasher>(
0,
ops.clone().into_iter().map(|(k, v)| (k, v.unwrap())),
|_| {},
);
assert_eq!(
verify_update::<Blake3Hasher>(&verified_multi_proof, ops).unwrap(),
expected_root,
);
}
#[test]
pub fn test_verify_multiproof_two_leafs() {
let mut key_path_0 = [0; 32];
key_path_0[0] = 0b00000000;
let mut key_path_1 = [0; 32];
key_path_1[0] = 0b10000000;
let mut key_path_2 = [0; 32];
key_path_2[0] = 0b01000000;
let leaf_0 = LeafData {
key_path: key_path_0,
value_hash: [0; 32],
};
let leaf_1 = LeafData {
key_path: key_path_1,
value_hash: [1; 32],
};
let leaf_2 = LeafData {
key_path: key_path_2,
value_hash: [2; 32],
};
let v0 = Blake3Hasher::hash_leaf(&leaf_0);
let v1 = Blake3Hasher::hash_leaf(&leaf_1);
let v2 = Blake3Hasher::hash_leaf(&leaf_2);
let s3 = Blake3Hasher::hash_internal(&InternalData {
left: v0.clone(),
right: v2,
});
let root = Blake3Hasher::hash_internal(&InternalData {
left: s3,
right: v1,
});
let path_proof_0 = PathProof {
terminal: PathProofTerminal::Leaf(leaf_0.clone()),
siblings: vec![v1, v2],
};
let path_proof_1 = PathProof {
terminal: PathProofTerminal::Leaf(leaf_1.clone()),
siblings: vec![s3],
};
let multi_proof =
MultiProof::from_path_proofs(vec![path_proof_0.clone(), path_proof_1.clone()]);
let verified = verify::<Blake3Hasher>(&multi_proof, root).unwrap();
assert!(verified.confirm_value(&leaf_0).unwrap());
assert!(verified.confirm_value(&leaf_1).unwrap());
}
#[test]
fn multi_proof_verify_2_leaves_with_provided_updates() {
let mut key_path_0 = [0; 32];
key_path_0[0] = 0b00000000;
let mut key_path_1 = [0; 32];
key_path_1[0] = 0b10000000;
let mut key_path_2 = [0; 32];
key_path_2[0] = 0b01000000;
let leaf_0 = LeafData {
key_path: key_path_0,
value_hash: [0; 32],
};
let leaf_1 = LeafData {
key_path: key_path_1,
value_hash: [1; 32],
};
let leaf_2 = LeafData {
key_path: key_path_2,
value_hash: [2; 32],
};
let v0 = Blake3Hasher::hash_leaf(&leaf_0);
let v1 = Blake3Hasher::hash_leaf(&leaf_1);
let v2 = Blake3Hasher::hash_leaf(&leaf_2);
let s3 = Blake3Hasher::hash_internal(&InternalData {
left: v0.clone(),
right: v2,
});
let root = Blake3Hasher::hash_internal(&InternalData {
left: s3,
right: v1,
});
let path_proof_0 = PathProof {
terminal: PathProofTerminal::Leaf(leaf_0.clone()),
siblings: vec![v1, v2],
};
let path_proof_1 = PathProof {
terminal: PathProofTerminal::Leaf(leaf_1.clone()),
siblings: vec![s3],
};
let multi_proof =
MultiProof::from_path_proofs(vec![path_proof_0.clone(), path_proof_1.clone()]);
let verified = verify::<Blake3Hasher>(&multi_proof, root).unwrap();
let mut key_path_3 = key_path_1;
key_path_3[0] = 0b10100000;
let mut key_path_4 = key_path_0;
key_path_4[0] = 0b00000100;
let ops = vec![
(key_path_0, Some([2; 32])),
(key_path_4, Some([1; 32])),
(key_path_1, None),
(key_path_3, Some([1; 32])),
];
let final_state = vec![
(key_path_0, [2; 32]),
(key_path_4, [1; 32]),
(key_path_2, [2; 32]),
(key_path_3, [1; 32]),
];
let expected_root = build_trie::<Blake3Hasher>(0, final_state, |_| {});
assert_eq!(
verify_update::<Blake3Hasher>(&verified, ops).unwrap(),
expected_root,
);
}
#[test]
fn multi_proof_verify_4_leaves_with_long_bisections() {
let make_leaf = |key_path, value_byte| {
let leaf_data = LeafData {
key_path,
value_hash: [value_byte; 32],
};
let hash = Blake3Hasher::hash_leaf(&leaf_data);
(leaf_data, hash)
};
let internal_hash =
|left, right| Blake3Hasher::hash_internal(&InternalData { left, right });
let mut key_path_0 = [0; 32];
key_path_0[0] = 0b00000000;
let mut key_path_1 = [0; 32];
key_path_1[0] = 0b00000001;
let mut key_path_2 = [0; 32];
key_path_2[0] = 0b00001000;
let mut key_path_3 = [0; 32];
key_path_3[0] = 0b00001001;
let (leaf_a, l8a) = make_leaf(key_path_0, 1);
let (leaf_b, l8b) = make_leaf(key_path_1, 1);
let (leaf_c, l8c) = make_leaf(key_path_2, 1);
let (leaf_d, l8d) = make_leaf(key_path_3, 1);
let i7a = internal_hash(l8a, l8b);
let i7b = internal_hash(l8c, l8d);
let i6a = internal_hash(i7a, [7; 32]);
let i6b = internal_hash(i7b, [7; 32]);
let i5a = internal_hash(i6a, [6; 32]);
let i5b = internal_hash(i6b, [6; 32]);
let i4 = internal_hash(i5a, i5b);
let i3 = internal_hash(i4, [4; 32]);
let i2 = internal_hash(i3, [3; 32]);
let i1 = internal_hash(i2, [2; 32]);
let root = internal_hash(i1, [1; 32]);
let path_proof_a = PathProof {
terminal: PathProofTerminal::Leaf(leaf_a.clone()),
siblings: vec![
[1; 32], [2; 32], [3; 32], [4; 32], i5b, [6; 32], [7; 32], l8b,
],
};
let path_proof_b = PathProof {
terminal: PathProofTerminal::Leaf(leaf_b.clone()),
siblings: vec![
[1; 32], [2; 32], [3; 32], [4; 32], i5b, [6; 32], [7; 32], l8a,
],
};
let path_proof_c = PathProof {
terminal: PathProofTerminal::Leaf(leaf_c.clone()),
siblings: vec![
[1; 32], [2; 32], [3; 32], [4; 32], i5a, [6; 32], [7; 32], l8d,
],
};
let path_proof_d = PathProof {
terminal: PathProofTerminal::Leaf(leaf_d.clone()),
siblings: vec![
[1; 32], [2; 32], [3; 32], [4; 32], i5a, [6; 32], [7; 32], l8c,
],
};
let multi_proof = MultiProof::from_path_proofs(vec![
path_proof_a.clone(),
path_proof_b.clone(),
path_proof_c.clone(),
path_proof_d.clone(),
]);
let verified = verify::<Blake3Hasher>(&multi_proof, root).unwrap();
let ops = vec![(key_path_0, Some([69; 32])), (key_path_3, Some([69; 32]))];
let (_, l8a) = make_leaf(key_path_0, 69);
let (_, l8b) = make_leaf(key_path_1, 1);
let (_, l8c) = make_leaf(key_path_2, 1);
let (_, l8d) = make_leaf(key_path_3, 69);
let i7a = internal_hash(l8a, l8b);
let i7b = internal_hash(l8c, l8d);
let i6a = internal_hash(i7a, [7; 32]);
let i6b = internal_hash(i7b, [7; 32]);
let i5a = internal_hash(i6a, [6; 32]);
let i5b = internal_hash(i6b, [6; 32]);
let i4 = internal_hash(i5a, i5b);
let i3 = internal_hash(i4, [4; 32]);
let i2 = internal_hash(i3, [3; 32]);
let i1 = internal_hash(i2, [2; 32]);
let post_root = internal_hash(i1, [1; 32]);
assert_eq!(
verify_update::<Blake3Hasher>(&verified, ops).unwrap(),
post_root,
);
}
#[test]
pub fn test_verify_multiproof_multiple_leafs() {
let path = |byte| [byte; 32];
let k0 = path(0b00000000);
let k1 = path(0b00011000);
let k2 = path(0b00101101);
let k3 = path(0b10101010);
let k4 = path(0b11000011);
let k5 = path(0b11100010);
let make_leaf = |key_path| {
let leaf_data = LeafData {
key_path,
value_hash: [key_path[0]; 32],
};
let hash = Blake3Hasher::hash_leaf(&leaf_data);
(leaf_data, hash)
};
let internal_hash =
|left, right| Blake3Hasher::hash_internal(&InternalData { left, right });
let (l0, v0) = make_leaf(k0);
let (l1, v1) = make_leaf(k1);
let (l2, v2) = make_leaf(k2);
let (l3, v3) = make_leaf(k3);
let (l4, v4) = make_leaf(k4);
let (l5, v5) = make_leaf(k5);
let i1 = internal_hash(v0, v1);
let i2 = internal_hash(i1, v2);
let i3 = internal_hash(i2, TERMINATOR);
let i4 = internal_hash(v4, TERMINATOR);
let i5 = internal_hash(i4, v5);
let i6 = internal_hash(v3, i5);
let root = internal_hash(i3, i6);
let leaf_proof = |leaf, siblings| PathProof {
terminal: PathProofTerminal::Leaf(leaf),
siblings,
};
let path_proof_0 = leaf_proof(l0.clone(), vec![i6, TERMINATOR, v2, v1]);
let path_proof_1 = leaf_proof(l1.clone(), vec![i6, TERMINATOR, v2, v0]);
let path_proof_2 = leaf_proof(l2.clone(), vec![i6, TERMINATOR, i1]);
let path_proof_3 = leaf_proof(l3.clone(), vec![i3, i5]);
let path_proof_4 = leaf_proof(l4.clone(), vec![i3, v3, v5, TERMINATOR]);
let path_proof_5 = leaf_proof(l5.clone(), vec![i3, v3, i4]);
let multi_proof = MultiProof::from_path_proofs(vec![
path_proof_0.clone(),
path_proof_1.clone(),
path_proof_2.clone(),
path_proof_3.clone(),
path_proof_4.clone(),
path_proof_5.clone(),
]);
let verified = verify::<Blake3Hasher>(&multi_proof, root).unwrap();
assert!(verified.confirm_value(&l0).unwrap());
assert!(verified.confirm_value(&l1).unwrap());
assert!(verified.confirm_value(&l2).unwrap());
assert!(verified.confirm_value(&l3).unwrap());
assert!(verified.confirm_value(&l4).unwrap());
assert!(verified.confirm_value(&l5).unwrap());
}
#[test]
pub fn test_verify_multiproof_siblings_structure() {
let path = |byte| [byte; 32];
let k0 = path(0b00000000);
let k1 = path(0b10000000);
let k2 = path(0b10000001);
let k3 = path(0b10011100);
let k4 = path(0b10011110);
let make_leaf = |key_path| {
let leaf_data = LeafData {
key_path,
value_hash: [key_path[0]; 32],
};
let hash = Blake3Hasher::hash_leaf(&leaf_data);
(leaf_data, hash)
};
let internal_hash =
|left, right| Blake3Hasher::hash_internal(&InternalData { left, right });
let (_l0, v0) = make_leaf(k0);
let (l1, v1) = make_leaf(k1);
let (l2, v2) = make_leaf(k2);
let (l3, v3) = make_leaf(k3);
let (l4, v4) = make_leaf(k4);
let e1 = [1; 32];
let e2 = [2; 32];
let e3 = [3; 32];
let e4 = [4; 32];
let e5 = [5; 32];
let e6 = [6; 32];
let e7 = TERMINATOR;
let i1 = internal_hash(v1, v2);
let i2 = internal_hash(i1, e1);
let i3 = internal_hash(i2, e2);
let i4 = internal_hash(i3, e3);
let i5 = internal_hash(v3, v4);
let i6 = internal_hash(e4, i5);
let i7 = internal_hash(e5, i6);
let i8 = internal_hash(i4, i7);
let i9 = internal_hash(i8, e6);
let i10 = internal_hash(i9, e7);
let root = internal_hash(v0, i10);
let leaf_proof = |leaf, siblings| PathProof {
terminal: PathProofTerminal::Leaf(leaf),
siblings,
};
let path_proof_1 = leaf_proof(l1.clone(), vec![v0, e7, e6, i7, e3, e2, e1, v2]);
let path_proof_2 = leaf_proof(l2.clone(), vec![v0, e7, e6, i7, e3, e2, e1, v1]);
let path_proof_3 = leaf_proof(l3.clone(), vec![v0, e7, e6, i4, e5, e4, v4]);
let path_proof_4 = leaf_proof(l4.clone(), vec![v0, e7, e6, i4, e5, e4, v3]);
let multi_proof = MultiProof::from_path_proofs(vec![
path_proof_1.clone(),
path_proof_2.clone(),
path_proof_3.clone(),
path_proof_4.clone(),
]);
assert_eq!(multi_proof.siblings, vec![v0, e7, e6, e3, e2, e1, e5, e4]);
let verified = verify::<Blake3Hasher>(&multi_proof, root).unwrap();
assert!(verified.confirm_value(&l1).unwrap());
assert!(verified.confirm_value(&l2).unwrap());
assert!(verified.confirm_value(&l3).unwrap());
assert!(verified.confirm_value(&l4).unwrap());
}
#[test]
fn test_verify_update_underflow_prefix_paths() {
let bits_prefix = bitvec![u8, Msb0; 1, 0, 1, 0]; let bits_longer = bitvec![u8, Msb0; 1, 0, 1, 0, 1, 1];
let keypath_from_bits = |bits: &BitSlice<u8, Msb0>| -> KeyPath {
let mut kp = KeyPath::default();
for (i, bit) in bits.iter().by_vals().enumerate() {
if i >= 256 {
break;
}
if bit {
kp[i / 8] |= 1 << (7 - (i % 8));
}
}
kp
};
let kp_prefix = keypath_from_bits(&bits_prefix);
let kp_longer = keypath_from_bits(&bits_longer);
let leaf_prefix = LeafData {
key_path: kp_prefix,
value_hash: [1; 32],
};
let leaf_longer = LeafData {
key_path: kp_longer,
value_hash: [2; 32],
};
let node_prefix = Blake3Hasher::hash_leaf(&leaf_prefix);
let node_longer = Blake3Hasher::hash_leaf(&leaf_longer);
let vmp_prefix = VerifiedMultiPath {
terminal: PathProofTerminal::Leaf(leaf_prefix.clone()),
depth: bits_prefix.len(),
unique_siblings: 0..0, };
let vmp_longer = VerifiedMultiPath {
terminal: PathProofTerminal::Leaf(leaf_longer.clone()),
depth: bits_longer.len(),
unique_siblings: 0..0, };
let plausible_root = Blake3Hasher::hash_internal(&InternalData {
left: node_prefix,
right: node_longer,
});
let verified_proof = VerifiedMultiProof {
inner: vec![vmp_prefix, vmp_longer],
bisections: Vec::new(),
siblings: Vec::new(),
root: plausible_root,
};
let mut key_op1_bits = bits_prefix.clone();
key_op1_bits.push(false);
let key_op1 = keypath_from_bits(&key_op1_bits);
let mut key_op2_bits = bits_longer.clone();
key_op2_bits.push(true);
let key_op2 = keypath_from_bits(&key_op2_bits);
let ops = vec![
(key_op1, Some(ValueHash::default())), (key_op2, Some(ValueHash::default())), ];
assert!(ops[0].0 < ops[1].0);
match verify_update::<Blake3Hasher>(&verified_proof, ops).unwrap_err() {
MultiVerifyUpdateError::PathPrefixOfAnother => (),
_ => panic!(),
}
}
}