Skip to content
Open
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
8ef1e59
Initial plan
Copilot Dec 8, 2025
c3b75c7
Add ProgressiveMerkleHasher implementation with basic tests
Copilot Dec 8, 2025
74331be
Add byte buffering and comprehensive tests for ProgressiveMerkleHasher
Copilot Dec 8, 2025
f5ecf94
Export ProgressiveMerkleHasherError from lib.rs
Copilot Dec 8, 2025
3e30512
Add clarifying comment about hash order in progressive merkleization
Copilot Dec 8, 2025
0746652
Refactor ProgressiveMerkleHasher for efficiency - hash chunks as they…
Copilot Dec 8, 2025
16fc4a0
Address code review feedback - improve documentation and extract help…
Copilot Dec 8, 2025
733344a
Refactor ProgressiveMerkleHasher to use MerkleHasher internally for b…
Copilot Dec 9, 2025
8277f30
Fmt
michaelsproul Dec 9, 2025
4fb08f8
Start implementing derive macro
michaelsproul Dec 10, 2025
0a5ed99
Implement TreeHash for ProgressiveBitList
michaelsproul Dec 10, 2025
26fc12f
Remove unnecessary max_leaves from ProgressiveMerkleHasher
michaelsproul Dec 10, 2025
f101c04
mix in length
michaelsproul Dec 11, 2025
f13637a
Add workaround for empty progressive bitlist
michaelsproul Dec 17, 2025
7400510
Use active_fields correctly
michaelsproul Dec 18, 2025
2fd8071
Implement compatible union support with manual selectors
michaelsproul Jan 12, 2026
4f73499
Read/verify ssz attributes as well as tree_hash
michaelsproul Jan 13, 2026
656b85e
Document quirk of bitfield hashing
michaelsproul Jan 13, 2026
9248e51
Remove inelegant temporary hasher
michaelsproul Jan 13, 2026
528a1a7
Remove from_slice
michaelsproul Jan 13, 2026
2f96e24
Document TreeHashType choice
michaelsproul Jan 13, 2026
817387c
Reverse tree order to match spec
macladson Feb 3, 2026
4c9b040
Fix clippy
macladson Feb 3, 2026
858514b
Use git dep instead of path dep
macladson Feb 3, 2026
ab57ec3
Merge branch 'main' into progressive
macladson Feb 3, 2026
ca07459
Fix typo in expect
macladson Feb 5, 2026
5e272f3
General tidy up
macladson Jun 29, 2026
2976d8c
Fix SSZ API
michaelsproul Jul 27, 2026
58c37e8
Merge remote-tracking branch 'origin/main' into progressive
michaelsproul Jul 27, 2026
de9e268
Pin ethereum_ssz
michaelsproul Jul 27, 2026
2bd2335
Merge variant selectors from tree_hash and ssz attributes field-by-field
michaelsproul Jul 27, 2026
58b0279
Give a clear error for enum variants with named fields
michaelsproul Jul 27, 2026
5bfc5c5
Reject 0-variant compatible unions explicitly
michaelsproul Jul 27, 2026
03d9fa4
Reject manual selectors on transparent enums
michaelsproul Jul 27, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,6 @@ readme = "README.md"
repository = "https://github.com/sigp/tree_hash"
keywords = ["ethereum"]
categories = ["cryptography::cryptocurrencies"]

[patch.crates-io]
ethereum_ssz = { path = "../ethereum_ssz/ssz" }
38 changes: 37 additions & 1 deletion tree_hash/src/impls.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use super::*;
use alloy_primitives::{Address, FixedBytes, U128, U256};
use ssz::{Bitfield, Fixed, Variable};
use ssz::{Bitfield, Fixed, Progressive, Variable};
use std::sync::Arc;
use typenum::Unsigned;

Expand Down Expand Up @@ -208,6 +208,42 @@ impl<N: Unsigned + Clone> TreeHash for Bitfield<Variable<N>> {
}
}

impl TreeHash for Bitfield<Progressive> {
fn tree_hash_type() -> TreeHashType {
TreeHashType::List
}

fn tree_hash_packed_encoding(&self) -> PackedEncoding {
unreachable!("ProgressiveBitField should never be packed.")
}

fn tree_hash_packing_factor() -> usize {
unreachable!("ProgressiveBitField should never be packed.")
}

fn tree_hash_root(&self) -> Hash256 {
// XXX: This is a workaround for the fact that the internal representation of bitfields is
// misaligned with the spec.
//
// See:
//
// - https://github.com/sigp/ethereum_ssz/pull/68
if self.is_empty() {
return mix_in_length(&Hash256::ZERO, 0);
}

let mut hasher = ProgressiveMerkleHasher::new();
hasher
.write(self.as_slice())
.expect("ProgessiveBitList should not exceed tree hash leaf limit");

let bitfield_root = hasher
.finish()
.expect("ProgressiveBitList tree hash buffer should not exceed leaf limit");
mix_in_length(&bitfield_root, self.len())
}
}

impl<N: Unsigned + Clone> TreeHash for Bitfield<Fixed<N>> {
fn tree_hash_type() -> TreeHashType {
TreeHashType::Vector
Expand Down
11 changes: 11 additions & 0 deletions tree_hash/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,14 @@ pub mod impls;
mod merkle_hasher;
mod merkleize_padded;
mod merkleize_standard;
mod progressive_merkle_hasher;

pub use merkle_hasher::{Error, MerkleHasher};
pub use merkleize_padded::merkleize_padded;
pub use merkleize_standard::merkleize_standard;
pub use progressive_merkle_hasher::{
Error as ProgressiveMerkleHasherError, ProgressiveMerkleHasher,
};

use ethereum_hashing::{hash_fixed, ZERO_HASHES, ZERO_HASHES_MAX_INDEX};
use smallvec::SmallVec;
Expand Down Expand Up @@ -89,6 +93,13 @@ pub fn mix_in_selector(root: &Hash256, selector: u8) -> Option<Hash256> {
Some(Hash256::from_slice(&root))
}

pub fn mix_in_active_fields(root: Hash256, active_fields: [u8; BYTES_PER_CHUNK]) -> Hash256 {
Comment thread
macladson marked this conversation as resolved.
Outdated
Hash256::from(ethereum_hashing::hash32_concat(
root.as_slice(),
&active_fields,
))
}

/// Returns a cached padding node for a given height.
fn get_zero_hash(height: usize) -> &'static [u8] {
if height <= ZERO_HASHES_MAX_INDEX {
Expand Down
Loading
Loading