diff --git a/src/lib.rs b/src/lib.rs index d0285b2..7701d36 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,18 +7,13 @@ extern crate alloc; mod bit; pub mod hash; pub mod merkle; +pub mod utils; // RE-EXPORTS // ================================================================================================ pub use winter_crypto::{RandomCoin, RandomCoinError}; pub use winter_math::{fields::f64::BaseElement as Felt, FieldElement, StarkField}; -pub mod utils { - pub use winter_utils::{ - collections, string, uninit_vector, ByteReader, ByteWriter, Deserializable, - DeserializationError, Serializable, SliceReader, - }; -} // TYPE ALIASES // ================================================================================================ diff --git a/src/merkle/merkle_tree.rs b/src/merkle/merkle_tree.rs index 5f8b08e..434c8e7 100644 --- a/src/merkle/merkle_tree.rs +++ b/src/merkle/merkle_tree.rs @@ -1,6 +1,9 @@ use super::{Felt, MerkleError, MerklePath, NodeIndex, Rpo256, RpoDigest, Vec, Word}; -use crate::{utils::uninit_vector, FieldElement}; -use core::slice; +use crate::{ + utils::{string::String, uninit_vector, word_to_hex}, + FieldElement, +}; +use core::{fmt, slice}; use winter_math::log2; // MERKLE TREE @@ -157,6 +160,52 @@ impl MerkleTree { } } +/// Utility to vizualize a [MerkleTree] in text. +pub fn tree_to_text(tree: &MerkleTree) -> Result { + let indent = " "; + let mut s = String::new(); + s.push_str(&word_to_hex(&tree.root())?); + s.push('\n'); + for d in 1..=tree.depth() { + let entries = 2u64.pow(d.into()); + for i in 0..entries { + let index = NodeIndex::new(d, i); + + let node = tree + .get_node(index) + .expect("The index must always be valid"); + + for _ in 0..d { + s.push_str(indent); + } + s.push_str(&word_to_hex(&node)?); + s.push('\n'); + } + } + + Ok(s) +} + +/// Utility to vizualize a [MerklePath] in text. +pub fn path_to_text(path: &MerklePath) -> Result { + let mut s = String::new(); + s.push('['); + + for el in path.iter() { + s.push_str(&word_to_hex(el)?); + s.push_str(", "); + } + + // remove the last ", " + if path.len() != 0 { + s.pop(); + s.pop(); + } + s.push(']'); + + Ok(s) +} + // TESTS // ================================================================================================ diff --git a/src/merkle/mod.rs b/src/merkle/mod.rs index 5b204ac..b0c7b2d 100644 --- a/src/merkle/mod.rs +++ b/src/merkle/mod.rs @@ -15,7 +15,7 @@ mod index; pub use index::NodeIndex; mod merkle_tree; -pub use merkle_tree::MerkleTree; +pub use merkle_tree::{path_to_text, tree_to_text, MerkleTree}; mod path; pub use path::{MerklePath, RootPath, ValuePath}; diff --git a/src/utils.rs b/src/utils.rs new file mode 100644 index 0000000..522d9ea --- /dev/null +++ b/src/utils.rs @@ -0,0 +1,21 @@ +use super::Word; +use crate::utils::string::String; +use core::fmt::{self, Write}; + +// RE-EXPORTS +// ================================================================================================ +pub use winter_utils::{ + collections, string, uninit_vector, ByteReader, ByteWriter, Deserializable, + DeserializationError, Serializable, SliceReader, +}; + +/// Converts a [Word] into hex. +pub fn word_to_hex(w: &Word) -> Result { + let mut s = String::new(); + + for byte in w.iter().flat_map(|e| e.to_bytes()) { + write!(s, "{byte:02x}")?; + } + + Ok(s) +}