Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add option to write path info to file when verifying inclusion proof #163

Merged
merged 9 commits into from
May 28, 2024
46 changes: 30 additions & 16 deletions src/binary_tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
//! `x` coordinate (their `y` coordinate will be 0).

use serde::{Deserialize, Serialize};
use std::fmt;
use std::fmt::{self, Debug};

mod utils;

Expand All @@ -47,7 +47,9 @@ pub use tree_builder::{
};

mod path_siblings;
pub use path_siblings::{PathSiblings, PathSiblingsBuildError, PathSiblingsError};
pub use path_siblings::{
PathSiblings, PathSiblingsBuildError, PathSiblingsError, PathSiblingsWriteError,
};

mod height;
pub use height::{Height, HeightError, MAX_HEIGHT, MIN_HEIGHT};
Expand Down Expand Up @@ -83,7 +85,7 @@ pub const MIN_RECOMMENDED_SPARSITY: u8 = 2;
///
/// The generic type `C` is for the content contained within each node.
#[derive(Serialize, Deserialize)]
pub struct BinaryTree<C> {
pub struct BinaryTree<C: fmt::Display> {
root: Node<C>,
store: Store<C>,
height: Height,
Expand All @@ -93,7 +95,7 @@ pub struct BinaryTree<C> {
/// The data contained in the node is completely generic, requiring only to have
/// an associated merge function.
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct Node<C> {
pub struct Node<C: fmt::Display> {
pub coord: Coordinate,
pub content: C,
}
Expand All @@ -118,15 +120,15 @@ pub struct Coordinate {
/// traits; for more details see
/// [this issue](https://github.com/dtolnay/typetag/issues/1).
#[derive(Serialize, Deserialize)]
pub enum Store<C> {
pub enum Store<C: fmt::Display> {
MultiThreadedStore(multi_threaded::DashMapStore<C>),
SingleThreadedStore(single_threaded::HashMapStore<C>),
}

// -------------------------------------------------------------------------------------------------
// Accessor methods.

impl<C: Clone> BinaryTree<C> {
impl<C: Clone + fmt::Display> BinaryTree<C> {
pub fn height(&self) -> &Height {
&self.height
}
Expand Down Expand Up @@ -265,7 +267,7 @@ impl Coordinate {
}
}

impl<C> Node<C> {
impl<C: fmt::Display> Node<C> {
/// Returns left if this node is a left sibling and vice versa for right.
/// Since we are working with a binary tree we can tell if the node is a
/// left sibling of the above layer by checking the x_coord modulus 2.
Expand Down Expand Up @@ -318,15 +320,15 @@ impl<C> Node<C> {
}

/// Convert a `Node<C>` to a `Node<B>`.
pub fn convert<B: From<C>>(self) -> Node<B> {
pub fn convert<B: From<C> + fmt::Display>(self) -> Node<B> {
Node {
content: self.content.into(),
coord: self.coord,
}
}
}

impl<C: Clone> Store<C> {
impl<C: Clone + fmt::Display> Store<C> {
/// Simply delegate the call to the wrapped store.
fn get_node(&self, coord: &Coordinate) -> Option<Node<C>> {
match self {
Expand All @@ -346,9 +348,21 @@ impl<C: Clone> Store<C> {

/// We can't use the default Debug implementation because it prints the whole
/// store.
impl<C: fmt::Debug + Clone> fmt::Debug for BinaryTree<C> {
impl<C: fmt::Display + Clone> fmt::Debug for BinaryTree<C> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "root: {}, height: {:?}", self.root, self.height)
}
}

impl<C: fmt::Display> fmt::Display for Node<C> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "(content: {}, coord: {:?})", self.content, self.coord)
}
}

impl fmt::Display for Coordinate {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "root: {:?}, height: {:?}", self.root, self.height)
write!(f, "(x: {:?}, y: {:?})", self.x, self.y)
}
}

Expand All @@ -364,18 +378,18 @@ enum NodeOrientation {

/// Used to orient nodes inside a sibling pair so that the compiler can
/// guarantee a left node is actually a left node.
enum Sibling<C> {
enum Sibling<C: fmt::Display> {
Left(Node<C>),
Right(Node<C>),
}

/// A pair of sibling nodes.
struct MatchedPair<C> {
struct MatchedPair<C: fmt::Display> {
left: Node<C>,
right: Node<C>,
}

impl<C> From<Node<C>> for Sibling<C> {
impl<C: fmt::Display> From<Node<C>> for Sibling<C> {
/// Move a generic node into the left/right sibling type.
fn from(node: Node<C>) -> Self {
match node.orientation() {
Expand All @@ -385,7 +399,7 @@ impl<C> From<Node<C>> for Sibling<C> {
}
}

impl<C: Mergeable> MatchedPair<C> {
impl<C: Mergeable + fmt::Display> MatchedPair<C> {
/// Create a parent node by merging the 2 nodes in the pair.
fn merge(&self) -> Node<C> {
Node {
Expand All @@ -395,7 +409,7 @@ impl<C: Mergeable> MatchedPair<C> {
}
}

impl<C> From<(Node<C>, Node<C>)> for MatchedPair<C> {
impl<C: fmt::Display> From<(Node<C>, Node<C>)> for MatchedPair<C> {
/// Construct a [MatchedPair] using the 2 given nodes.
///
/// Only build the pair if the 2 nodes are siblings, otherwise panic.
Expand Down
22 changes: 20 additions & 2 deletions src/binary_tree/node_content/full_node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ impl FullNodeContent {
}

// -------------------------------------------------------------------------------------------------
// Implement Mergeable trait
// Implement traits

impl Mergeable for FullNodeContent {
/// Returns the parent node content by merging two child node contents.
Expand All @@ -169,7 +169,7 @@ impl Mergeable for FullNodeContent {
let parent_blinding_factor = left_sibling.blinding_factor + right_sibling.blinding_factor;
let parent_commitment = left_sibling.commitment + right_sibling.commitment;

// `hash = H(left.com | right.com | left.hash | right.hash`
// `hash = H(left.com | right.com | left.hash | right.hash)`
let parent_hash = {
let mut hasher = Hasher::new();
hasher.update(left_sibling.commitment.compress().as_bytes());
Expand All @@ -188,6 +188,24 @@ impl Mergeable for FullNodeContent {
}
}

use std::fmt;

impl fmt::Display for FullNodeContent {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
// This allows us to get the same format for hash & commitment.
// If we just try convert the compressed RistrettoPoint to string we
// get a [u8; 32] array, while the H256 type formats to a nice hex
// string.
let commitment_bytes = H256::from_slice(self.commitment.compress().as_bytes());

write!(
f,
"(liability: {}, blinding factor: {:?}, hash: {:?}, commitment: {:?})",
self.liability, self.blinding_factor, self.hash, commitment_bytes
)
}
}

// -------------------------------------------------------------------------------------------------
// Unit tests

Expand Down
18 changes: 16 additions & 2 deletions src/binary_tree/node_content/hidden_node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ impl From<FullNodeContent> for HiddenNodeContent {
}

// -------------------------------------------------------------------------------------------------
// Implement merge trait
// Implement trait

impl Mergeable for HiddenNodeContent {
/// Returns the parent node content by merging two child node contents.
Expand All @@ -121,7 +121,7 @@ impl Mergeable for HiddenNodeContent {
fn merge(left_sibling: &Self, right_sibling: &Self) -> Self {
let parent_commitment = left_sibling.commitment + right_sibling.commitment;

// `hash = H(left.com | right.com | left.hash | right.hash`
// `hash = H(left.com | right.com | left.hash | right.hash)`
let parent_hash = {
let mut hasher = Hasher::new();
hasher.update(left_sibling.commitment.compress().as_bytes());
Expand All @@ -138,6 +138,20 @@ impl Mergeable for HiddenNodeContent {
}
}

use std::fmt;

impl fmt::Display for HiddenNodeContent {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
// This allows us to get the same format for hash & commitment.
// If we just try convert the compressed RistrettoPoint to string we
// get a [u8; 32] array, while the H256 type formats to a nice hex
// string.
let commitment_bytes = H256::from_slice(self.commitment.compress().as_bytes());

write!(f, "(hash: {:x?}, commitment: {:?})", self.hash, commitment_bytes)
}
}

// -------------------------------------------------------------------------------------------------
// Unit tests

Expand Down
Loading