1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
use crypto::digest::Digest;
use merkledigest::{ MerkleDigest };
use tree::{ Tree };
pub struct Proof<D, T> {
pub digest: D,
pub root_hash: Vec<u8>,
pub block: ProofBlock,
pub value: T
}
impl <D, T> Proof<D, T> where D: Digest + Clone, T: Into<Vec<u8>> + Clone {
pub fn validate(&self, root_hash: &Vec<u8>) -> bool {
if self.root_hash != *root_hash || self.block.node_hash != *root_hash {
return false
}
self.validate_block(&self.block, &mut self.digest.clone())
}
pub fn validate_block(&self, block: &ProofBlock, digest: &mut D) -> bool {
match block.sub_proof {
None =>
block.sibling_hash == Positioned::Nowhere,
Some(ref sub) =>
match block.sibling_hash {
Positioned::Nowhere =>
false,
Positioned::Left(ref hash) => {
let hashes_match = digest.combine_hashes(&hash, &sub.node_hash) == block.node_hash;
hashes_match && self.validate_block(sub, digest)
}
Positioned::Right(ref hash) => {
let hashes_match = digest.combine_hashes(&sub.node_hash, &hash) == block.node_hash;
hashes_match && self.validate_block(sub, digest)
}
}
}
}
}
pub struct ProofBlock {
pub node_hash: Vec<u8>,
pub sibling_hash: Positioned<Vec<u8>>,
pub sub_proof: Option<Box<ProofBlock>>
}
impl ProofBlock {
pub fn new<T>(tree: &Tree<T>, needle: &Vec<u8>) -> Option<ProofBlock>
where T: Into<Vec<u8>> + Clone
{
match *tree {
Tree::Leaf { ref hash, .. } =>
ProofBlock::new_leaf_proof(hash, needle),
Tree::Node { ref hash, ref left, ref right } =>
ProofBlock::new_tree_proof(hash, needle, left, right)
}
}
fn new_leaf_proof(hash: &Vec<u8>, needle: &Vec<u8>) -> Option<ProofBlock> {
if *hash == *needle {
Some(ProofBlock {
node_hash: hash.clone(),
sibling_hash: Positioned::Nowhere,
sub_proof: None
})
} else {
None
}
}
fn new_tree_proof<T>(hash: &Vec<u8>, needle: &Vec<u8>, left: &Tree<T>, right: &Tree<T>) -> Option<ProofBlock>
where T: Into<Vec<u8>> + Clone
{
ProofBlock::new(left, needle)
.map(|block| {
let right_hash = right.get_hash().clone();
let sub_proof = Positioned::Right(right_hash);
(block, sub_proof)
})
.or_else(|| {
let sub_proof = ProofBlock::new(right, needle);
sub_proof.map(|block| {
let left_hash = left.get_hash().clone();
let sub_proof = Positioned::Left(left_hash);
(block, sub_proof)
})
})
.map(|(sub_proof, sibling_hash)| {
ProofBlock {
node_hash: hash.clone(),
sibling_hash: sibling_hash,
sub_proof: Some(Box::new(sub_proof))
}
})
}
}
#[derive(PartialEq)]
pub enum Positioned<T> {
Nowhere,
Left(T),
Right(T)
}