diff --git a/Cargo.lock b/Cargo.lock index d783a6e9..ddd40fbd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -115,6 +115,8 @@ version = "0.5.0" dependencies = [ "either", "proptest", + "rand", + "rand_core", ] [[package]] diff --git a/incrementalmerkletree/Cargo.toml b/incrementalmerkletree/Cargo.toml index 065a7c71..4239dfa5 100644 --- a/incrementalmerkletree/Cargo.toml +++ b/incrementalmerkletree/Cargo.toml @@ -20,9 +20,13 @@ rustdoc-args = ["--cfg", "docsrs"] [dependencies] either = "1.8" proptest = { version = "1.0.0", optional = true } +rand = { version = "0.8", optional = true } +rand_core = { version = "0.6", optional = true } [dev-dependencies] proptest = "1.0.0" +rand = "0.8" +rand_core = "0.6" [features] # The legacy-api feature guards types and functions that were previously @@ -31,4 +35,4 @@ proptest = "1.0.0" legacy-api = [] # The test-dependencies feature guards types and functions that are # useful for testing incremental Merkle trees and Merkle tree frontiers. -test-dependencies = ["proptest"] +test-dependencies = ["dep:proptest", "dep:rand", "dep:rand_core"] diff --git a/incrementalmerkletree/src/frontier.rs b/incrementalmerkletree/src/frontier.rs index e2342c6b..dd73ee58 100644 --- a/incrementalmerkletree/src/frontier.rs +++ b/incrementalmerkletree/src/frontier.rs @@ -6,6 +6,12 @@ use crate::{Address, Hashable, Level, MerklePath, Position, Source}; #[cfg(feature = "legacy-api")] use {std::collections::VecDeque, std::iter::repeat}; +#[cfg(any(test, feature = "test-dependencies"))] +use rand::{ + distributions::{Distribution, Standard}, + Rng, RngCore, +}; + /// Validation errors that can occur during reconstruction of a Merkle frontier from /// its constituent parts. #[derive(Clone, Debug, PartialEq, Eq)] @@ -287,6 +293,29 @@ impl Frontier { } } +#[cfg(any(test, feature = "test-dependencies"))] +impl Frontier +where + Standard: Distribution, +{ + /// Generates a random frontier of a Merkle tree having the specified size. + pub fn random_of_size(rng: &mut R, tree_size: u64) -> Self { + if tree_size == 0 { + Frontier::empty() + } else { + let position = tree_size.into(); + Frontier::from_parts( + position, + rng.gen(), + std::iter::repeat_with(|| rng.gen()) + .take(position.past_ommer_count().into()) + .collect(), + ) + .unwrap() + } + } +} + #[cfg(feature = "legacy-api")] #[cfg_attr(docsrs, doc(cfg(feature = "legacy-api")))] pub struct PathFiller {