diff --git a/commit_verify/src/merkle.rs b/commit_verify/src/merkle.rs index 39ca6a7d..c187e9e1 100644 --- a/commit_verify/src/merkle.rs +++ b/commit_verify/src/merkle.rs @@ -22,6 +22,7 @@ use core::{iter, slice}; use std::collections::{btree_set, BTreeSet}; use std::io::Write; +use std::ops::SubAssign; use amplify::confinement::Confined; use amplify::num::u5; @@ -202,3 +203,60 @@ where T: CommitmentId + Copy fn merkle_leaves(&self) -> Self::LeafIter<'_> { self.iter().copied() } } + +/// Helper struct to track depth when working with Merkle blocks. +// TODO: v0.11 Remove default generic from MerkleBuoy +#[derive(Clone, PartialEq, Eq, Debug, Default)] +pub struct MerkleBuoy + Default = u5> { + buoy: D, + stack: Option>>, +} + +impl + Default> MerkleBuoy { + pub fn new(top: D) -> Self { + Self { + buoy: top, + stack: None, + } + } + + /// Measure the current buoy level. + pub fn level(&self) -> D { + self.stack + .as_ref() + .map(Box::as_ref) + .map(MerkleBuoy::level) + .unwrap_or(self.buoy) + } + + /// Add new item to the buoy. + /// + /// Returns whether the buoy have surfaced in a result. + /// + /// The buoy surfaces each time the contents it has is reduced to two depth + /// of the same level. + pub fn push(&mut self, depth: D) -> bool { + if depth == D::default() { + return false; + } + match self + .stack + .as_mut() + .map(|stack| (stack.push(depth), stack.level())) + { + None if depth == self.buoy => { + self.buoy -= 1; + true + } + None => { + self.stack = Some(Box::new(MerkleBuoy::new(depth))); + false + } + Some((true, level)) => { + self.stack = None; + self.push(level) + } + Some((false, _)) => false, + } + } +} diff --git a/commit_verify/src/mpc/atoms.rs b/commit_verify/src/mpc/atoms.rs index d8291fe1..c6aae141 100644 --- a/commit_verify/src/mpc/atoms.rs +++ b/commit_verify/src/mpc/atoms.rs @@ -170,58 +170,3 @@ impl Default for MultiSource { } } } - -/// Helper struct to track depth when merging two merkle blocks. -pub struct MerkleBuoy { - buoy: u5, - stack: Option>, -} - -impl MerkleBuoy { - pub fn new(top: u5) -> Self { - Self { - buoy: top, - stack: None, - } - } - - /// Measure the current buoy level. - pub fn level(&self) -> u5 { - self.stack - .as_ref() - .map(Box::as_ref) - .map(MerkleBuoy::level) - .unwrap_or(self.buoy) - } - - /// Add new item to the buoy. - /// - /// Returns whether the buoy have surfaced in a result. - /// - /// The buoy surfaces each time the contents it has is reduced to two depth - /// of the same level. - pub fn push(&mut self, depth: u5) -> bool { - if depth == u5::ZERO { - return false; - } - match self - .stack - .as_mut() - .map(|stack| (stack.push(depth), stack.level())) - { - None if depth == self.buoy => { - self.buoy -= 1; - true - } - None => { - self.stack = Some(Box::new(MerkleBuoy::new(depth))); - false - } - Some((true, level)) => { - self.stack = None; - self.push(level) - } - Some((false, _)) => false, - } - } -} diff --git a/commit_verify/src/mpc/block.rs b/commit_verify/src/mpc/block.rs index 991d46fb..887dee6c 100644 --- a/commit_verify/src/mpc/block.rs +++ b/commit_verify/src/mpc/block.rs @@ -29,11 +29,11 @@ use amplify::num::u5; use strict_encoding::StrictEncode; use crate::id::CommitmentId; -use crate::merkle::MerkleNode; +use crate::merkle::{MerkleBuoy, MerkleNode}; use crate::mpc::atoms::Leaf; use crate::mpc::tree::protocol_id_pos; use crate::mpc::{ - Commitment, MerkleBuoy, MerkleTree, Message, MessageMap, Proof, ProtocolId, MERKLE_LNPBP4_TAG, + Commitment, MerkleTree, Message, MessageMap, Proof, ProtocolId, MERKLE_LNPBP4_TAG, }; use crate::{Conceal, LIB_NAME_COMMIT_VERIFY}; @@ -430,7 +430,7 @@ impl MerkleBlock { } Ordering::Less => { cross_section.push(n2); - let mut buoy = MerkleBuoy::new(n2_depth); + let mut buoy = MerkleBuoy::::new(n2_depth); let mut stop = false; last_b = None; cross_section.extend(b.by_ref().take_while(|n| { @@ -448,7 +448,7 @@ impl MerkleBlock { } Ordering::Greater => { cross_section.push(n1); - let mut buoy = MerkleBuoy::new(n1_depth); + let mut buoy = MerkleBuoy::::new(n1_depth); let mut stop = false; last_a = None; cross_section.extend(a.by_ref().take_while(|n| { diff --git a/commit_verify/src/mpc/mod.rs b/commit_verify/src/mpc/mod.rs index 8df462f8..3ccd157b 100644 --- a/commit_verify/src/mpc/mod.rs +++ b/commit_verify/src/mpc/mod.rs @@ -27,12 +27,15 @@ mod atoms; mod tree; mod block; -pub use atoms::{Commitment, Leaf, MerkleBuoy, Message, MessageMap, MultiSource, ProtocolId}; +pub use atoms::{Commitment, Leaf, Message, MessageMap, MultiSource, ProtocolId}; pub use block::{InvalidProof, LeafNotKnown, MergeError, MerkleBlock, MerkleProof}; #[cfg(feature = "rand")] pub use tree::Error; pub use tree::MerkleTree; +#[deprecated(since = "0.10.6", note = "use commit_verify::merkle::MerkleBuoy instead")] +pub use crate::merkle::MerkleBuoy; + pub const MERKLE_LNPBP4_TAG: u128 = u128::from_le_bytes(*b"urn:lnpbp:lnpbp4"); /// Marker trait for variates of LNPBP-4 commitment proofs, which differ by the