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
133
134
135
136
137
138
|
# Merkle Tree
This is an implementation in Rust of [Merkle
Trees](https://search.proquest.com/openview/1ae50982b34bee7e3f1b8e232bb98e42/1?pq-origsite=gscholar&cbl=18750&diss=y).
## Basic example
You can test this library using the example `merkletree_blake3.rs` in the
`examples/` folder.
```
cargo run --example merkletree_blake3 -- tests/pics/cubbit.png.enc.0 tests/pics/cubbit.png.enc.1 tests/pics/cubbit.png.enc.2
```
And then check the proof with the `proofer_blake3.rs` example.
```
cargo run --example proofer_blake3 -- f03bad5df0a10c74de32ec9c7119b65db9c4dee145fa390c7f36af94411d04cb tests/pics/cubbit.png.enc.0 tests/pics/cubbit.png.enc.1 tests/pics/cubbit.png.enc.2
```
These two should be seen as a single Rust example code which check if the passed
hash is the same generated by the Merkle tree algorithm.
```rust
use mt_rs::{
hasher::Blake3Hasher,
merkletree::MerkleTree,
proof::{DefaultProofer, Proofer},
};
fn main() {
let root_hash = match std::env::args().nth(1) {
Some(hash) => hash,
None => {
std::process::exit(1);
}
};
let filenames: Vec<String> = std::env::args().skip(2).collect();
if filenames.is_empty() {
std::process::exit(1);
}
let mut file_contents = Vec::new();
for filename in &filenames {
match std::fs::read(filename) {
Ok(contents) => file_contents.push(contents),
Err(e) => {
eprintln!("Failed to read file '{}': {}", filename, e);
std::process::exit(1);
}
}
}
let hasher = Blake3Hasher::new();
let tree = MerkleTree::new(hasher.clone(), file_contents.clone());
let proofer = DefaultProofer::new(hasher, tree.leaves());
let proof = proofer.generate(0).expect("Couldn't generate proof");
assert!(tree.root().hash() == root_hash);
assert!(proofer.verify(&proof, std::fs::read(&filenames[0]).unwrap(), tree.root().hash()));
}
```
## Advanced example
1. Define an hasher.
```rust
use mt_rs::hasher::Hasher;
pub struct FooHasher;
impl Hasher for FooHasher {
fn hash(&self, input: &[u8]) -> String {
let sum: u32 = input.iter().map(|&b| b as u32).sum();
format!("foo_{:x}", sum)
}
}
```
2. Define a proofer.
```rust
use mt_rs::proof::Proofer;
pub struct FooProofer;
impl<H> Proofer for FooProfer<H>
where
H: Hasher,
{
fn generate(&self, index: usize) -> Option<MerkleProof> {
// ...
}
fn verify<T>(&self, proof: &MerkleProof, data: T, root_hash: &str) -> bool
where
T: AsRef<[u8]>,
{
// ...
}
}
```
3. Now we can proceed with the tree creation.
```rust
let hasher = FooHasher;
let data: &[&[u8]; ...] = ...;
let tree = MerkleTree::new(hasher.clone(), data);
println!("{}", tree.root().hash());
let proofer = FooProofer::new(hasher, tree.leaves().clone());
let proof = proofer.generate(0).unwrap();
assert!(proofer.verify(&proof, data[0], tree.root().hash()));
```
## Configuration
Currently we have tree hashers:
- `SHA256HAsher`
- `Keccak256Hasher`
- `Blake3Hasher`
And a proofer `DefaultProofer`.
## Benchmark
You can run a benchmark to test which hasher is faster via
```
$ cargo bench --bench bigfile
```
|