diff --git a/tree_hash/Cargo.toml b/tree_hash/Cargo.toml index f3e6d35..9c23ea2 100644 --- a/tree_hash/Cargo.toml +++ b/tree_hash/Cargo.toml @@ -21,6 +21,7 @@ typenum = "1.12.0" rand = "0.8.5" tree_hash_derive = { path = "../tree_hash_derive", version = "0.10.0" } ethereum_ssz_derive = "0.9.0" +ssz_types = "0.11.0" [features] arbitrary = ["alloy-primitives/arbitrary"] diff --git a/tree_hash/src/lib.rs b/tree_hash/src/lib.rs index e5ac66f..20f0ef8 100644 --- a/tree_hash/src/lib.rs +++ b/tree_hash/src/lib.rs @@ -2,6 +2,7 @@ pub mod impls; mod merkle_hasher; mod merkleize_padded; mod merkleize_standard; +pub mod prototype; pub use merkle_hasher::{Error, MerkleHasher}; pub use merkleize_padded::merkleize_padded; diff --git a/tree_hash/src/prototype.rs b/tree_hash/src/prototype.rs new file mode 100644 index 0000000..4f89e43 --- /dev/null +++ b/tree_hash/src/prototype.rs @@ -0,0 +1,90 @@ +use crate::{Hash256, TreeHash, TreeHashType, BYTES_PER_CHUNK}; +use std::marker::PhantomData; + +pub enum Error { + Oops, +} + +pub trait MerkleProof: TreeHash { + fn compute_proof(&self) -> Result, Error> + where + Self: Resolve, + { + let gindex = >::gindex(1); + self.compute_proof_for_gindex(gindex) + } + + fn compute_proof_for_gindex(&self, gindex: usize) -> Result, Error>; +} + +// A path is a sequence of field accesses like `self.foo.bar`. +// +// We can resolve these at compile time, because we're sickos. +pub struct Path(PhantomData<(First, Rest)>); + +// The field trait is implemented for all struct fields. +// +// It provides conversion from a named field type to a numeric field index. +pub trait Field { + const NUM_FIELDS: usize; + const INDEX: usize; +} + +// If T implements Resolve it means T has a field named Field of type Output. +pub trait Resolve { + type Output; + + fn gindex(parent_index: usize) -> usize; +} + +// This impl defines how paths are resolved and converted to gindices. +impl Resolve> for T +where + Self: Resolve, + First: Field, + >::Output: Resolve, +{ + type Output = <>::Output as Resolve>::Output; + + fn gindex(parent_index: usize) -> usize { + // From `get_generalized_index`: + // https://github.com/ethereum/consensus-specs/blob/dev/ssz/merkle-proofs.md#ssz-object-to-index + let new_parent_index = >::gindex(parent_index); + >::Output::gindex(new_parent_index) + } +} + +// FIXME: we don't currently enforce I < N at compile-time +pub struct VecIndex; + +impl Field for VecIndex { + const NUM_FIELDS: usize = N; + const INDEX: usize = I; +} + +pub fn item_length() -> usize { + if T::tree_hash_type() == TreeHashType::Basic { + BYTES_PER_CHUNK / T::tree_hash_packing_factor() + } else { + BYTES_PER_CHUNK + } +} + +pub fn vector_chunk_count(length: usize) -> usize { + (length * item_length::()).div_ceil(BYTES_PER_CHUNK) +} + +pub fn get_vector_item_position(index: usize) -> usize { + let start = index * item_length::(); + start / BYTES_PER_CHUNK +} + +/* +impl TreeHash for u64 { + fn get_field(&self, _: usize) -> Result<&dyn TreeHash, Error> { + Err(Error::Oops) + } + + fn merkle_proof(&self) +} +*/