diff --git a/ssz-rs/src/boolean.rs b/ssz-rs/src/boolean.rs index bb463fbd..8f83a871 100644 --- a/ssz-rs/src/boolean.rs +++ b/ssz-rs/src/boolean.rs @@ -2,8 +2,8 @@ use crate::{ de::{Deserialize, DeserializeError}, lib::*, merkleization::{ - proofs::{NoChilden, Prove}, - GeneralizedIndexable, HashTreeRoot, MerkleizationError, Node, + proofs::Prove, GeneralizedIndexable, HashTreeRoot, MerkleizationError, Node, + BYTES_PER_CHUNK, }, ser::{Serialize, SerializeError}, Serializable, SimpleSerialize, @@ -63,14 +63,14 @@ impl GeneralizedIndexable for bool { } impl Prove for bool { - type Child = NoChilden; + type InnerElement = (); fn chunks(&mut self) -> Result, MerkleizationError> { - let mut node = Node::default(); + let mut vec = vec![0u8; BYTES_PER_CHUNK]; if *self { - node.as_mut()[0] = 1; + vec[0] = 1; } - Ok(node.to_vec()) + Ok(vec) } } diff --git a/ssz-rs/src/merkleization/mod.rs b/ssz-rs/src/merkleization/mod.rs index d41f54be..faa022b9 100644 --- a/ssz-rs/src/merkleization/mod.rs +++ b/ssz-rs/src/merkleization/mod.rs @@ -6,7 +6,7 @@ pub mod proofs; use crate::{lib::*, ser::SerializeError}; pub use generalized_index::{ - get_power_of_two_ceil, GeneralizedIndex, GeneralizedIndexable, Path, PathElement, + get_power_of_two_ceil, log_2, GeneralizedIndex, GeneralizedIndexable, Path, PathElement, }; pub use merkleize::*; pub use node::*; @@ -31,7 +31,10 @@ pub enum MerkleizationError { InvalidPath(Vec), InvalidDepth, InvalidIndex, - NoChildren, + /// Attempt to prove an inner element for a "basic" type that doesn't have one + NoInnerElement, + /// Attempt to turn an instance of a type in Merkle chunks when this is not supported + NotChunkable, } impl From for MerkleizationError { @@ -53,10 +56,13 @@ impl Display for MerkleizationError { Self::InvalidPath(path) => write!(f, "invalid path {path:?}"), Self::InvalidDepth => write!(f, "error computing depth for proof"), Self::InvalidIndex => write!(f, "error computing index for proof"), - Self::NoChildren => write!( + Self::NoInnerElement => write!( f, - "requested to compute proof for a child which does not exist for this type" + "requested to compute proof for an inner element which does not exist for this type" ), + Self::NotChunkable => { + write!(f, "requested to compute chunks for a type which does not support this") + } } } } diff --git a/ssz-rs/src/merkleization/proofs.rs b/ssz-rs/src/merkleization/proofs.rs index 7cf78e49..30fe8eb1 100644 --- a/ssz-rs/src/merkleization/proofs.rs +++ b/ssz-rs/src/merkleization/proofs.rs @@ -77,7 +77,7 @@ impl Prover { parent_index / local_generalized_index + 1 }; self.proof.index = child_index; - let child = data.child(local_index)?; + let child = data.inner_element(local_index)?; self.compute_proof(child)?; self.proof.index = parent_index; } else { @@ -122,29 +122,40 @@ impl From for Prover { } } -/// Types that can produce Merkle proofs against themselves given a `GeneralizedIndex`. +/// Required functionality to support computing Merkle proofs. pub trait Prove: GeneralizedIndexable { - type Child: Prove; + type InnerElement: Prove; - fn chunks(&mut self) -> Result, Error>; + /// Compute the "chunks" of this type as required for the SSZ merkle tree computation. + /// Default implementation signals an error. Implementing types should override + /// to provide the correct behavior. + fn chunks(&mut self) -> Result, Error> { + Err(Error::NotChunkable) + } - fn child(&mut self, _index: usize) -> Result<&mut Self::Child, Error> { - Err(Error::NoChildren) + /// Provide a reference to a member element of a composite type. + /// Default implementation signals an error. Implementing types should override + /// to provide the correct behavior. + fn inner_element(&mut self, _index: usize) -> Result<&mut Self::InnerElement, Error> { + Err(Error::NoInnerElement) } } -pub struct NoChilden; - -impl GeneralizedIndexable for NoChilden {} - -impl Prove for NoChilden { - type Child = bool; - - fn chunks(&mut self) -> Result, Error> { - Err(Error::NoChildren) +// Implement `GeneralizedIndexable` for `()` for use as a marker type in `Prove`. +impl GeneralizedIndexable for () { + fn compute_generalized_index( + _parent: GeneralizedIndex, + path: Path, + ) -> Result { + Err(Error::InvalidPath(path.to_vec())) } } +// Implement the default `Prove` functionality for use of `()` as a marker type. +impl Prove for () { + type InnerElement = (); +} + /// Produce a Merkle proof (and corresponding witness) for the type `T` at the given `path` relative /// to `T`. pub fn prove(data: &mut T, path: Path) -> Result { diff --git a/ssz-rs/src/uint.rs b/ssz-rs/src/uint.rs index db16ac0f..581cbcac 100644 --- a/ssz-rs/src/uint.rs +++ b/ssz-rs/src/uint.rs @@ -2,9 +2,8 @@ use crate::{ de::{Deserialize, DeserializeError}, lib::*, merkleization::{ - pack_bytes, - proofs::{NoChilden, Prove}, - GeneralizedIndexable, HashTreeRoot, MerkleizationError, Node, BYTES_PER_CHUNK, + pack_bytes, proofs::Prove, GeneralizedIndexable, HashTreeRoot, MerkleizationError, Node, + BYTES_PER_CHUNK, }, ser::{Serialize, SerializeError}, Serializable, SimpleSerialize, BITS_PER_BYTE, @@ -74,7 +73,7 @@ macro_rules! define_uint { } impl Prove for $uint { - type Child = NoChilden; + type InnerElement = (); fn chunks(&mut self) -> Result, MerkleizationError> { let mut root = Vec::with_capacity(BYTES_PER_CHUNK); @@ -156,7 +155,7 @@ impl GeneralizedIndexable for U256 { } impl Prove for U256 { - type Child = NoChilden; + type InnerElement = (); fn chunks(&mut self) -> Result, MerkleizationError> { Ok(self.as_le_bytes().to_vec()) diff --git a/ssz-rs/src/vector.rs b/ssz-rs/src/vector.rs index aae05364..8ee11df1 100644 --- a/ssz-rs/src/vector.rs +++ b/ssz-rs/src/vector.rs @@ -284,13 +284,16 @@ impl Prove for Vector where T: SimpleSerialize + Prove, { - type Child = T; + type InnerElement = T; fn chunks(&mut self) -> Result, MerkleizationError> { self.assemble_chunks() } - fn child(&mut self, index: usize) -> Result<&mut Self::Child, MerkleizationError> { + fn inner_element( + &mut self, + index: usize, + ) -> Result<&mut Self::InnerElement, MerkleizationError> { if index >= N { Err(MerkleizationError::InvalidIndex) } else {