Skip to content

Commit 296c63a

Browse files
committed
modules path and commitment
Apply suggestions from code review Co-authored-by: Jean-Philippe Raynaud <[email protected]> review suggestions applied
1 parent 8f69409 commit 296c63a

File tree

8 files changed

+255
-255
lines changed

8 files changed

+255
-255
lines changed

mithril-stm/src/error.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
//! Crate specific errors
22
3-
use crate::merkle_tree::basic::Path;
4-
use crate::merkle_tree::batch_compatible::BatchPath;
3+
use crate::merkle_tree::{BatchPath, Path};
54
use blake2::digest::{Digest, FixedOutput};
65
use {
76
crate::multi_sig::{Signature, VerificationKey, VerificationKeyPoP},

mithril-stm/src/key_reg.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
//! Key registration functionality.
22
use super::stm::Stake;
33
use crate::error::RegisterError;
4-
use crate::merkle_tree::leaf::MTLeaf;
5-
use crate::merkle_tree::tree::MerkleTree;
4+
use crate::merkle_tree::{MTLeaf, MerkleTree};
65
use crate::multi_sig::{VerificationKey, VerificationKeyPoP};
76
use blake2::digest::{Digest, FixedOutput};
87
use std::collections::hash_map::Entry;

mithril-stm/src/merkle_tree/basic.rs

Lines changed: 0 additions & 122 deletions
This file was deleted.

mithril-stm/src/merkle_tree/batch_compatible.rs renamed to mithril-stm/src/merkle_tree/commitment.rs

Lines changed: 47 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -1,91 +1,64 @@
11
use crate::error::MerkleTreeError;
2-
use crate::merkle_tree::leaf::MTLeaf;
3-
use crate::merkle_tree::tree::{parent, sibling};
2+
use crate::merkle_tree::{parent, sibling};
3+
use crate::merkle_tree::{BatchPath, MTLeaf, Path};
44
use blake2::digest::{Digest, FixedOutput};
55
use serde::{Deserialize, Serialize};
66
use std::marker::PhantomData;
77

8-
/// Path of hashes for a batch of indices.
9-
/// Contains the hashes and the corresponding merkle tree indices of given batch.
10-
/// Used to verify the signatures are issued by the registered signers.
11-
#[derive(Default, Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
12-
pub struct BatchPath<D: Digest + FixedOutput> {
13-
pub(crate) values: Vec<Vec<u8>>,
14-
pub(crate) indices: Vec<usize>,
15-
pub(crate) hasher: PhantomData<D>,
8+
/// `MerkleTree` commitment.
9+
/// This structure differs from `MerkleTree` in that it does not contain all elements, which are not always necessary.
10+
/// Instead, it only contains the root of the tree.
11+
#[derive(Debug, Clone, Serialize, Deserialize)]
12+
pub struct MerkleTreeCommitment<D: Digest> {
13+
/// Root of the merkle commitment.
14+
pub root: Vec<u8>,
15+
hasher: PhantomData<D>,
1616
}
1717

18-
impl<D: Digest + FixedOutput> BatchPath<D> {
19-
pub(crate) fn new(values: Vec<Vec<u8>>, indices: Vec<usize>) -> BatchPath<D> {
20-
Self {
21-
values,
22-
indices,
23-
hasher: Default::default(),
18+
impl<D: Digest + FixedOutput> MerkleTreeCommitment<D> {
19+
pub(crate) fn new(root: Vec<u8>) -> Self {
20+
MerkleTreeCommitment {
21+
root,
22+
hasher: PhantomData,
2423
}
2524
}
2625

27-
/// Convert the `BatchPath` into byte representation.
28-
///
29-
/// # Layout
30-
/// The layout of a `BatchPath` is
31-
/// * Length of values
32-
/// * Length of indices
33-
/// * Values
34-
/// * Indices
35-
pub fn to_bytes(&self) -> Vec<u8> {
36-
let mut output = Vec::new();
37-
let len_v = self.values.len();
38-
let len_i = self.indices.len();
39-
40-
output.extend_from_slice(&u64::try_from(len_v).unwrap().to_be_bytes());
41-
output.extend_from_slice(&u64::try_from(len_i).unwrap().to_be_bytes());
42-
43-
for value in &self.values {
44-
output.extend_from_slice(value.as_slice())
26+
/// Check an inclusion proof that `val` is part of the tree by traveling the whole path until the root.
27+
/// # Error
28+
/// If the merkle tree path is invalid, then the function fails.
29+
pub fn check(&self, val: &MTLeaf, proof: &Path<D>) -> Result<(), MerkleTreeError<D>>
30+
where
31+
D: FixedOutput + Clone,
32+
{
33+
let mut idx = proof.index;
34+
35+
let mut h = D::digest(val.to_bytes()).to_vec();
36+
for p in &proof.values {
37+
if (idx & 0b1) == 0 {
38+
h = D::new().chain_update(h).chain_update(p).finalize().to_vec();
39+
} else {
40+
h = D::new().chain_update(p).chain_update(h).finalize().to_vec();
41+
}
42+
idx >>= 1;
4543
}
4644

47-
for &index in &self.indices {
48-
output.extend_from_slice(&u64::try_from(index).unwrap().to_be_bytes());
45+
if h == self.root {
46+
return Ok(());
4947
}
50-
output
48+
Err(MerkleTreeError::PathInvalid(proof.clone()))
5149
}
5250

53-
/// Try to convert a byte string into a `BatchPath`.
54-
// todo: We should not panic if the size of the slice is invalid (I believe `bytes[offset + i * 8..offset + (i + 1) * 8]` will panic if bytes is not large enough.
55-
pub fn from_bytes(bytes: &[u8]) -> Result<Self, MerkleTreeError<D>> {
56-
let mut u64_bytes = [0u8; 8];
57-
u64_bytes.copy_from_slice(&bytes[..8]);
58-
let len_v = usize::try_from(u64::from_be_bytes(u64_bytes))
59-
.map_err(|_| MerkleTreeError::SerializationError)?;
60-
61-
u64_bytes.copy_from_slice(&bytes[8..16]);
62-
let len_i = usize::try_from(u64::from_be_bytes(u64_bytes))
63-
.map_err(|_| MerkleTreeError::SerializationError)?;
64-
65-
let mut values = Vec::with_capacity(len_v);
66-
for i in 0..len_v {
67-
values.push(
68-
bytes[16 + i * <D as Digest>::output_size()
69-
..16 + (i + 1) * <D as Digest>::output_size()]
70-
.to_vec(),
71-
);
72-
}
73-
let offset = 16 + len_v * <D as Digest>::output_size();
74-
75-
let mut indices = Vec::with_capacity(len_v);
76-
for i in 0..len_i {
77-
u64_bytes.copy_from_slice(&bytes[offset + i * 8..offset + (i + 1) * 8]);
78-
indices.push(
79-
usize::try_from(u64::from_be_bytes(u64_bytes))
80-
.map_err(|_| MerkleTreeError::SerializationError)?,
81-
);
82-
}
51+
/// Serializes the Merkle Tree commitment together with a message in a single vector of bytes.
52+
/// Outputs `msg || self` as a vector of bytes.
53+
pub fn concat_with_msg(&self, msg: &[u8]) -> Vec<u8>
54+
where
55+
D: Digest,
56+
{
57+
let mut msgp = msg.to_vec();
58+
let mut bytes = self.root.clone();
59+
msgp.append(&mut bytes);
8360

84-
Ok(BatchPath {
85-
values,
86-
indices,
87-
hasher: PhantomData,
88-
})
61+
msgp
8962
}
9063
}
9164

@@ -110,7 +83,7 @@ impl<D: Digest> MerkleTreeCommitmentBatchCompat<D> {
11083
}
11184
}
11285

113-
#[allow(dead_code)]
86+
#[cfg(test)]
11487
/// Used in property test of `tree`: `test_bytes_tree_commitment_batch_compat`
11588
pub(crate) fn get_nr_leaves(&self) -> usize {
11689
self.nr_leaves
@@ -119,8 +92,7 @@ impl<D: Digest> MerkleTreeCommitmentBatchCompat<D> {
11992
/// Serializes the Merkle Tree commitment together with a message in a single vector of bytes.
12093
/// Outputs `msg || self` as a vector of bytes.
12194
// todo: Do we need to concat msg to whole commitment (nr_leaves and root) or just the root?
122-
pub fn concat_with_msg(&self, msg: &[u8]) -> Vec<u8>
123-
{
95+
pub fn concat_with_msg(&self, msg: &[u8]) -> Vec<u8> {
12496
let mut msgp = msg.to_vec();
12597
let mut bytes = self.root.clone();
12698
msgp.append(&mut bytes);

mithril-stm/src/merkle_tree/mod.rs

Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,41 @@
11
//! Merkle tree implementation for STM
22
3-
pub(super) mod basic;
4-
pub(super) mod batch_compatible;
5-
pub(super) mod leaf;
6-
pub(super) mod tree;
3+
mod leaf;
4+
pub use leaf::MTLeaf;
5+
6+
mod tree;
7+
pub use tree::MerkleTree;
8+
9+
mod commitment;
10+
pub use commitment::{MerkleTreeCommitment, MerkleTreeCommitmentBatchCompat};
11+
12+
mod path;
13+
pub use path::{BatchPath, Path};
14+
15+
// ---------------------------------------------------------------------
16+
// Heap Helpers
17+
// ---------------------------------------------------------------------
18+
fn parent(i: usize) -> usize {
19+
assert!(i > 0, "The root node does not have a parent");
20+
(i - 1) / 2
21+
}
22+
23+
fn left_child(i: usize) -> usize {
24+
(2 * i) + 1
25+
}
26+
27+
fn right_child(i: usize) -> usize {
28+
(2 * i) + 2
29+
}
30+
31+
fn sibling(i: usize) -> usize {
32+
assert!(i > 0, "The root node does not have a sibling");
33+
// In the heap representation, the left sibling is always odd
34+
// And the right sibling is the next node
35+
// We're assuming that the heap is complete
36+
if i % 2 == 1 {
37+
i + 1
38+
} else {
39+
i - 1
40+
}
41+
}

0 commit comments

Comments
 (0)