Skip to content

Commit 93a0270

Browse files
Add vectorized merkle tree (#454)
* 512 hash * 512 hash * Final version * Fixed comment * Add batch tree * Add batch trees * Fmt * Remove duplicated import --------- Co-authored-by: Mariano Nicolini <[email protected]>
1 parent ba1526d commit 93a0270

File tree

8 files changed

+180
-22
lines changed

8 files changed

+180
-22
lines changed

crypto/benches/criterion_merkle.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use core::time::Duration;
22
use criterion::{criterion_group, criterion_main, Criterion};
3-
use lambdaworks_crypto::merkle_tree::{merkle::MerkleTree, backends::sha3_256::Sha3_256Tree};
3+
use lambdaworks_crypto::merkle_tree::{backends::sha3_256::Sha3_256Tree, merkle::MerkleTree};
44
use lambdaworks_math::{
55
field::element::FieldElement,
66
field::fields::fft_friendly::stark_252_prime_field::Stark252PrimeField,
@@ -23,9 +23,7 @@ fn merkle_tree_benchmarks(c: &mut Criterion) {
2323
"build",
2424
unhashed_leaves.as_slice(),
2525
|bench, unhashed_leaves| {
26-
bench.iter_with_large_drop(|| {
27-
MerkleTree::<Sha3_256Tree<F>>::build(unhashed_leaves)
28-
});
26+
bench.iter_with_large_drop(|| MerkleTree::<Sha3_256Tree<F>>::build(unhashed_leaves));
2927
},
3028
);
3129
}

crypto/benches/iai_merkle.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use core::hint::black_box;
22
use lambdaworks_crypto::{
33
hash::sha3::Sha3Hasher,
4-
merkle_tree::{merkle::MerkleTree, backends::sha3_256::Sha3_256Tree},
4+
merkle_tree::{backends::sha3_256::Sha3_256Tree, merkle::MerkleTree},
55
};
66
use lambdaworks_math::{
77
field::element::FieldElement,
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
use std::marker::PhantomData;
2+
3+
use lambdaworks_math::{
4+
field::{element::FieldElement, traits::IsField},
5+
traits::ByteConversion,
6+
};
7+
use sha3::{Digest, Sha3_256};
8+
9+
use crate::merkle_tree::traits::IsMerkleTreeBackend;
10+
11+
#[derive(Clone)]
12+
pub struct BatchSha3_256Tree<F> {
13+
phantom: PhantomData<F>,
14+
}
15+
16+
impl<F> Default for BatchSha3_256Tree<F> {
17+
fn default() -> Self {
18+
Self {
19+
phantom: PhantomData,
20+
}
21+
}
22+
}
23+
24+
impl<F> IsMerkleTreeBackend for BatchSha3_256Tree<F>
25+
where
26+
F: IsField,
27+
FieldElement<F>: ByteConversion,
28+
{
29+
type Node = [u8; 32];
30+
type Data = Vec<FieldElement<F>>;
31+
32+
fn hash_data(&self, input: &Vec<FieldElement<F>>) -> [u8; 32] {
33+
let mut hasher = Sha3_256::new();
34+
for element in input.iter() {
35+
hasher.update(element.to_bytes_be());
36+
}
37+
let mut result_hash = [0_u8; 32];
38+
result_hash.copy_from_slice(&hasher.finalize());
39+
result_hash
40+
}
41+
42+
fn hash_new_parent(&self, left: &[u8; 32], right: &[u8; 32]) -> [u8; 32] {
43+
let mut hasher = Sha3_256::new();
44+
hasher.update(left);
45+
hasher.update(right);
46+
let mut result_hash = [0_u8; 32];
47+
result_hash.copy_from_slice(&hasher.finalize());
48+
result_hash
49+
}
50+
}
51+
52+
#[cfg(test)]
53+
mod tests {
54+
use lambdaworks_math::field::{
55+
element::FieldElement, fields::fft_friendly::stark_252_prime_field::Stark252PrimeField,
56+
};
57+
58+
use crate::merkle_tree::{backends::batch_sha3_256::BatchSha3_256Tree, merkle::MerkleTree};
59+
60+
type F = Stark252PrimeField;
61+
type FE = FieldElement<F>;
62+
63+
#[test]
64+
fn hash_data_field_element_backend_works() {
65+
let values = [
66+
vec![FE::from(2u64), FE::from(11u64)],
67+
vec![FE::from(3u64), FE::from(14u64)],
68+
vec![FE::from(4u64), FE::from(7u64)],
69+
vec![FE::from(5u64), FE::from(3u64)],
70+
vec![FE::from(6u64), FE::from(5u64)],
71+
vec![FE::from(7u64), FE::from(16u64)],
72+
vec![FE::from(8u64), FE::from(19u64)],
73+
vec![FE::from(9u64), FE::from(21u64)],
74+
];
75+
let merkle_tree = MerkleTree::<BatchSha3_256Tree<F>>::build(&values);
76+
let proof = merkle_tree.get_proof_by_pos(0).unwrap();
77+
assert!(proof.verify::<BatchSha3_256Tree<F>>(&merkle_tree.root, 0, &values[0]));
78+
}
79+
}
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
use std::marker::PhantomData;
2+
3+
use lambdaworks_math::{
4+
field::{element::FieldElement, traits::IsField},
5+
traits::ByteConversion,
6+
};
7+
use sha3::{Digest, Sha3_512};
8+
9+
use crate::merkle_tree::traits::IsMerkleTreeBackend;
10+
11+
#[derive(Clone)]
12+
pub struct BatchSha3_512Tree<F> {
13+
phantom: PhantomData<F>,
14+
}
15+
16+
impl<F> Default for BatchSha3_512Tree<F> {
17+
fn default() -> Self {
18+
Self {
19+
phantom: PhantomData,
20+
}
21+
}
22+
}
23+
24+
impl<F> IsMerkleTreeBackend for BatchSha3_512Tree<F>
25+
where
26+
F: IsField,
27+
FieldElement<F>: ByteConversion,
28+
{
29+
type Node = [u8; 64];
30+
type Data = Vec<FieldElement<F>>;
31+
32+
fn hash_data(&self, input: &Vec<FieldElement<F>>) -> [u8; 64] {
33+
let mut hasher = Sha3_512::new();
34+
for element in input.iter() {
35+
hasher.update(element.to_bytes_be());
36+
}
37+
let mut result_hash = [0_u8; 64];
38+
result_hash.copy_from_slice(&hasher.finalize());
39+
result_hash
40+
}
41+
42+
fn hash_new_parent(&self, left: &[u8; 64], right: &[u8; 64]) -> [u8; 64] {
43+
let mut hasher = Sha3_512::new();
44+
hasher.update(left);
45+
hasher.update(right);
46+
let mut result_hash = [0_u8; 64];
47+
result_hash.copy_from_slice(&hasher.finalize());
48+
result_hash
49+
}
50+
}
51+
52+
#[cfg(test)]
53+
mod tests {
54+
use lambdaworks_math::field::{
55+
element::FieldElement, fields::fft_friendly::stark_252_prime_field::Stark252PrimeField,
56+
};
57+
58+
use crate::merkle_tree::{backends::batch_sha3_512::BatchSha3_512Tree, merkle::MerkleTree};
59+
60+
type F = Stark252PrimeField;
61+
type FE = FieldElement<F>;
62+
63+
#[test]
64+
fn hash_data_field_element_backend_works() {
65+
let values = [
66+
vec![FE::from(2u64), FE::from(11u64)],
67+
vec![FE::from(3u64), FE::from(14u64)],
68+
vec![FE::from(4u64), FE::from(7u64)],
69+
vec![FE::from(5u64), FE::from(3u64)],
70+
vec![FE::from(6u64), FE::from(5u64)],
71+
vec![FE::from(7u64), FE::from(16u64)],
72+
vec![FE::from(8u64), FE::from(19u64)],
73+
vec![FE::from(9u64), FE::from(21u64)],
74+
];
75+
let merkle_tree = MerkleTree::<BatchSha3_512Tree<F>>::build(&values);
76+
let proof = merkle_tree.get_proof_by_pos(0).unwrap();
77+
assert!(proof.verify::<BatchSha3_512Tree<F>>(&merkle_tree.root, 0, &values[0]));
78+
}
79+
}

crypto/src/merkle_tree/backends/sha3_256.rs

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
1-
use std::marker::PhantomData;
2-
use lambdaworks_math::{field::{traits::IsField, element::FieldElement}, traits::ByteConversion};
3-
use sha3::{Digest, Sha3_256};
41
use crate::merkle_tree::traits::IsMerkleTreeBackend;
2+
use lambdaworks_math::{
3+
field::{element::FieldElement, traits::IsField},
4+
traits::ByteConversion,
5+
};
6+
use sha3::{Digest, Sha3_256};
7+
use std::marker::PhantomData;
58

69
#[derive(Clone)]
710
pub struct Sha3_256Tree<F> {
@@ -42,11 +45,12 @@ where
4245

4346
#[cfg(test)]
4447
mod tests {
45-
use lambdaworks_math::field::{fields::u64_prime_field::U64PrimeField, element::FieldElement};
48+
use lambdaworks_math::field::{element::FieldElement, fields::u64_prime_field::U64PrimeField};
4649

47-
use crate::merkle_tree::{merkle::MerkleTree, test_merkle::TestBackend, backends::sha3_256::Sha3_256Tree};
50+
use crate::merkle_tree::{
51+
backends::sha3_256::Sha3_256Tree, merkle::MerkleTree, test_merkle::TestBackend,
52+
};
4853

49-
5054
const MODULUS: u64 = 13;
5155
type U64PF = U64PrimeField<MODULUS>;
5256
type FE = FieldElement<U64PF>;

crypto/src/merkle_tree/backends/sha3_512.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1-
2-
use std::marker::PhantomData;
3-
use lambdaworks_math::{field::{traits::IsField, element::FieldElement}, traits::ByteConversion};
4-
use sha3::{Digest, Sha3_512};
51
use crate::merkle_tree::traits::IsMerkleTreeBackend;
2+
use lambdaworks_math::{
3+
field::{element::FieldElement, traits::IsField},
4+
traits::ByteConversion,
5+
};
6+
use sha3::{Digest, Sha3_512};
7+
use std::marker::PhantomData;
68

79
#[derive(Clone)]
810
pub struct Sha3_512Tree<F> {
@@ -48,11 +50,10 @@ where
4850

4951
#[cfg(test)]
5052
mod tests {
51-
use lambdaworks_math::field::{fields::u64_prime_field::U64PrimeField, element::FieldElement};
53+
use lambdaworks_math::field::{element::FieldElement, fields::u64_prime_field::U64PrimeField};
5254

53-
use crate::merkle_tree::{merkle::MerkleTree, backends::{sha3_512::Sha3_512Tree}};
55+
use crate::merkle_tree::{backends::sha3_512::Sha3_512Tree, merkle::MerkleTree};
5456

55-
5657
const MODULUS: u64 = 13;
5758
type U64PF = U64PrimeField<MODULUS>;
5859
type FE = FieldElement<U64PF>;
@@ -64,4 +65,3 @@ mod tests {
6465
assert!(proof.verify::<Sha3_512Tree<U64PF>>(&merkle_tree.root, 0, &values[0]));
6566
}
6667
}
67-

crypto/src/merkle_tree/merkle.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,6 @@ where
5858
}
5959
}
6060

61-
62-
6361
#[cfg(test)]
6462
mod tests {
6563
use lambdaworks_math::field::{element::FieldElement, fields::u64_prime_field::U64PrimeField};

crypto/src/merkle_tree/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1+
pub mod backends;
12
pub mod merkle;
23
pub mod proof;
3-
pub mod backends;
44
#[cfg(test)]
55
pub mod test_merkle;
66
pub mod traits;

0 commit comments

Comments
 (0)