diff --git a/eth2/types/src/attestation.rs b/eth2/types/src/attestation.rs index bef35bc78..c7ce07ab6 100644 --- a/eth2/types/src/attestation.rs +++ b/eth2/types/src/attestation.rs @@ -1,5 +1,5 @@ use super::bls::AggregateSignature; -use super::ssz::{Decodable, DecodeError, Encodable, SszStream}; +use super::ssz::{hash, Decodable, DecodeError, Encodable, SszStream, TreeHash}; use super::{AttestationData, Bitfield}; use crate::test_utils::TestRandom; use rand::RngCore; @@ -49,6 +49,17 @@ impl Attestation { } } +impl TreeHash for Attestation { + fn hash_tree_root(&self) -> Vec { + let mut result: Vec = vec![]; + result.append(&mut self.data.hash_tree_root()); + result.append(&mut self.aggregation_bitfield.hash_tree_root()); + result.append(&mut self.custody_bitfield.hash_tree_root()); + result.append(&mut self.aggregate_signature.hash_tree_root()); + hash(&result) + } +} + impl TestRandom for Attestation { fn random_for_test(rng: &mut T) -> Self { Self { @@ -76,4 +87,16 @@ mod tests { assert_eq!(original, decoded); } + + #[test] + pub fn test_hash_tree_root() { + let mut rng = XorShiftRng::from_seed([42; 16]); + let original = Attestation::random_for_test(&mut rng); + + let result = original.hash_tree_root(); + + assert_eq!(result.len(), 32); + // TODO: Add further tests + // https://github.com/sigp/lighthouse/issues/170 + } } diff --git a/eth2/types/src/attestation_data.rs b/eth2/types/src/attestation_data.rs index c1e895d6c..1744f0dd0 100644 --- a/eth2/types/src/attestation_data.rs +++ b/eth2/types/src/attestation_data.rs @@ -1,4 +1,4 @@ -use super::ssz::{Decodable, DecodeError, Encodable, SszStream}; +use super::ssz::{hash, Decodable, DecodeError, Encodable, SszStream, TreeHash}; use super::Hash256; use crate::test_utils::TestRandom; use rand::RngCore; @@ -85,6 +85,21 @@ impl Decodable for AttestationData { } } +impl TreeHash for AttestationData { + fn hash_tree_root(&self) -> Vec { + let mut result: Vec = vec![]; + result.append(&mut self.slot.hash_tree_root()); + result.append(&mut self.shard.hash_tree_root()); + result.append(&mut self.beacon_block_root.hash_tree_root()); + result.append(&mut self.epoch_boundary_root.hash_tree_root()); + result.append(&mut self.shard_block_root.hash_tree_root()); + result.append(&mut self.latest_crosslink_root.hash_tree_root()); + result.append(&mut self.justified_slot.hash_tree_root()); + result.append(&mut self.justified_block_root.hash_tree_root()); + hash(&result) + } +} + impl TestRandom for AttestationData { fn random_for_test(rng: &mut T) -> Self { Self { @@ -116,4 +131,16 @@ mod tests { assert_eq!(original, decoded); } + + #[test] + pub fn test_hash_tree_root() { + let mut rng = XorShiftRng::from_seed([42; 16]); + let original = AttestationData::random_for_test(&mut rng); + + let result = original.hash_tree_root(); + + assert_eq!(result.len(), 32); + // TODO: Add further tests + // https://github.com/sigp/lighthouse/issues/170 + } } diff --git a/eth2/types/src/attestation_data_and_custody_bit.rs b/eth2/types/src/attestation_data_and_custody_bit.rs index 66584b0d9..6265c0d06 100644 --- a/eth2/types/src/attestation_data_and_custody_bit.rs +++ b/eth2/types/src/attestation_data_and_custody_bit.rs @@ -1,4 +1,4 @@ -use super::ssz::{Decodable, DecodeError, Encodable, SszStream}; +use super::ssz::{Decodable, DecodeError, Encodable, hash, TreeHash, SszStream}; use rand::RngCore; use crate::test_utils::TestRandom; use super::AttestationData; @@ -30,6 +30,16 @@ impl Decodable for AttestationDataAndCustodyBit { } } +impl TreeHash for AttestationDataAndCustodyBit { + fn hash_tree_root(&self) -> Vec { + let result: Vec = vec![]; + result.append(&mut self.data.hash_tree_root()); + // TODO: add bool ssz + // result.append(custody_bit.hash_tree_root()); + ssz::hash(&result) + } +} + impl TestRandom for AttestationDataAndCustodyBit { fn random_for_test(rng: &mut T) -> Self { Self { @@ -57,4 +67,16 @@ mod test { assert_eq!(original, decoded); } + + #[test] + pub fn test_hash_tree_root() { + let mut rng = XorShiftRng::from_seed([42; 16]); + let original = AttestationDataAndCustodyBit::random_for_test(&mut rng); + + let result = original.hash_tree_root(); + + assert_eq!(result.len(), 32); + // TODO: Add further tests + // https://github.com/sigp/lighthouse/issues/170 + } } diff --git a/eth2/types/src/beacon_block.rs b/eth2/types/src/beacon_block.rs index 4dff199f3..50945df8b 100644 --- a/eth2/types/src/beacon_block.rs +++ b/eth2/types/src/beacon_block.rs @@ -1,4 +1,4 @@ -use super::ssz::{ssz_encode, Decodable, DecodeError, Encodable, SszStream}; +use super::ssz::{hash, ssz_encode, Decodable, DecodeError, Encodable, SszStream, TreeHash}; use super::{BeaconBlockBody, Eth1Data, Hash256}; use crate::test_utils::TestRandom; use bls::Signature; @@ -61,6 +61,20 @@ impl Decodable for BeaconBlock { } } +impl TreeHash for BeaconBlock { + fn hash_tree_root(&self) -> Vec { + let mut result: Vec = vec![]; + result.append(&mut self.slot.hash_tree_root()); + result.append(&mut self.parent_root.hash_tree_root()); + result.append(&mut self.state_root.hash_tree_root()); + result.append(&mut self.randao_reveal.hash_tree_root()); + result.append(&mut self.eth1_data.hash_tree_root()); + result.append(&mut self.signature.hash_tree_root()); + result.append(&mut self.body.hash_tree_root()); + hash(&result) + } +} + impl TestRandom for BeaconBlock { fn random_for_test(rng: &mut T) -> Self { Self { @@ -91,4 +105,16 @@ mod tests { assert_eq!(original, decoded); } + + #[test] + pub fn test_hash_tree_root() { + let mut rng = XorShiftRng::from_seed([42; 16]); + let original = BeaconBlock::random_for_test(&mut rng); + + let result = original.hash_tree_root(); + + assert_eq!(result.len(), 32); + // TODO: Add further tests + // https://github.com/sigp/lighthouse/issues/170 + } } diff --git a/eth2/types/src/beacon_block_body.rs b/eth2/types/src/beacon_block_body.rs index 67fa34d91..d530e74dc 100644 --- a/eth2/types/src/beacon_block_body.rs +++ b/eth2/types/src/beacon_block_body.rs @@ -1,4 +1,4 @@ -use super::ssz::{Decodable, DecodeError, Encodable, SszStream}; +use super::ssz::{hash, Decodable, DecodeError, Encodable, SszStream, TreeHash}; use super::{Attestation, CasperSlashing, Deposit, Exit, ProposerSlashing}; use crate::test_utils::TestRandom; use rand::RngCore; @@ -61,6 +61,21 @@ impl Decodable for BeaconBlockBody { } } +impl TreeHash for BeaconBlockBody { + fn hash_tree_root(&self) -> Vec { + let mut result: Vec = vec![]; + result.append(&mut self.proposer_slashings.hash_tree_root()); + result.append(&mut self.casper_slashings.hash_tree_root()); + result.append(&mut self.attestations.hash_tree_root()); + result.append(&mut self.custody_reseeds.hash_tree_root()); + result.append(&mut self.custody_challenges.hash_tree_root()); + result.append(&mut self.custody_responses.hash_tree_root()); + result.append(&mut self.deposits.hash_tree_root()); + result.append(&mut self.exits.hash_tree_root()); + hash(&result) + } +} + impl TestRandom for BeaconBlockBody { fn random_for_test(rng: &mut T) -> Self { Self { @@ -92,4 +107,16 @@ mod tests { assert_eq!(original, decoded); } + + #[test] + pub fn test_hash_tree_root() { + let mut rng = XorShiftRng::from_seed([42; 16]); + let original = BeaconBlockBody::random_for_test(&mut rng); + + let result = original.hash_tree_root(); + + assert_eq!(result.len(), 32); + // TODO: Add further tests + // https://github.com/sigp/lighthouse/issues/170 + } } diff --git a/eth2/types/src/beacon_state.rs b/eth2/types/src/beacon_state.rs index 34afeaa83..0de06fa60 100644 --- a/eth2/types/src/beacon_state.rs +++ b/eth2/types/src/beacon_state.rs @@ -3,12 +3,12 @@ use super::eth1_data::Eth1Data; use super::eth1_data_vote::Eth1DataVote; use super::fork::Fork; use super::pending_attestation::PendingAttestation; +use super::ssz::{hash, ssz_encode, Decodable, DecodeError, Encodable, SszStream, TreeHash}; use super::validator::Validator; use super::Hash256; use crate::test_utils::TestRandom; use hashing::canonical_hash; use rand::RngCore; -use ssz::{ssz_encode, Decodable, DecodeError, Encodable, SszStream}; // Custody will not be added to the specs until Phase 1 (Sharding Phase) so dummy class used. type CustodyChallenge = usize; @@ -166,6 +166,41 @@ impl Decodable for BeaconState { } } +impl TreeHash for BeaconState { + fn hash_tree_root(&self) -> Vec { + let mut result: Vec = vec![]; + result.append(&mut self.slot.hash_tree_root()); + result.append(&mut self.genesis_time.hash_tree_root()); + result.append(&mut self.fork_data.hash_tree_root()); + result.append(&mut self.validator_registry.hash_tree_root()); + result.append(&mut self.validator_balances.hash_tree_root()); + result.append(&mut self.validator_registry_update_slot.hash_tree_root()); + result.append(&mut self.validator_registry_exit_count.hash_tree_root()); + result.append(&mut self.validator_registry_delta_chain_tip.hash_tree_root()); + result.append(&mut self.latest_randao_mixes.hash_tree_root()); + result.append(&mut self.latest_vdf_outputs.hash_tree_root()); + result.append(&mut self.previous_epoch_start_shard.hash_tree_root()); + result.append(&mut self.current_epoch_start_shard.hash_tree_root()); + result.append(&mut self.previous_epoch_calculation_slot.hash_tree_root()); + result.append(&mut self.current_epoch_calculation_slot.hash_tree_root()); + result.append(&mut self.previous_epoch_randao_mix.hash_tree_root()); + result.append(&mut self.current_epoch_randao_mix.hash_tree_root()); + result.append(&mut self.custody_challenges.hash_tree_root()); + result.append(&mut self.previous_justified_slot.hash_tree_root()); + result.append(&mut self.justified_slot.hash_tree_root()); + result.append(&mut self.justification_bitfield.hash_tree_root()); + result.append(&mut self.finalized_slot.hash_tree_root()); + result.append(&mut self.latest_crosslinks.hash_tree_root()); + result.append(&mut self.latest_block_roots.hash_tree_root()); + result.append(&mut self.latest_penalized_exit_balances.hash_tree_root()); + result.append(&mut self.latest_attestations.hash_tree_root()); + result.append(&mut self.batched_block_roots.hash_tree_root()); + result.append(&mut self.latest_eth1_data.hash_tree_root()); + result.append(&mut self.eth1_data_votes.hash_tree_root()); + hash(&result) + } +} + impl TestRandom for BeaconState { fn random_for_test(rng: &mut T) -> Self { Self { @@ -217,4 +252,16 @@ mod tests { assert_eq!(original, decoded); } + + #[test] + pub fn test_hash_tree_root() { + let mut rng = XorShiftRng::from_seed([42; 16]); + let original = BeaconState::random_for_test(&mut rng); + + let result = original.hash_tree_root(); + + assert_eq!(result.len(), 32); + // TODO: Add further tests + // https://github.com/sigp/lighthouse/issues/170 + } } diff --git a/eth2/types/src/casper_slashing.rs b/eth2/types/src/casper_slashing.rs index 08dbd9ff3..62bad76dd 100644 --- a/eth2/types/src/casper_slashing.rs +++ b/eth2/types/src/casper_slashing.rs @@ -1,4 +1,4 @@ -use super::ssz::{Decodable, DecodeError, Encodable, SszStream}; +use super::ssz::{hash, Decodable, DecodeError, Encodable, SszStream, TreeHash}; use super::SlashableVoteData; use crate::test_utils::TestRandom; use rand::RngCore; @@ -31,6 +31,15 @@ impl Decodable for CasperSlashing { } } +impl TreeHash for CasperSlashing { + fn hash_tree_root(&self) -> Vec { + let mut result: Vec = vec![]; + result.append(&mut self.slashable_vote_data_1.hash_tree_root()); + result.append(&mut self.slashable_vote_data_2.hash_tree_root()); + hash(&result) + } +} + impl TestRandom for CasperSlashing { fn random_for_test(rng: &mut T) -> Self { Self { @@ -56,4 +65,16 @@ mod tests { assert_eq!(original, decoded); } + + #[test] + pub fn test_hash_tree_root() { + let mut rng = XorShiftRng::from_seed([42; 16]); + let original = CasperSlashing::random_for_test(&mut rng); + + let result = original.hash_tree_root(); + + assert_eq!(result.len(), 32); + // TODO: Add further tests + // https://github.com/sigp/lighthouse/issues/170 + } } diff --git a/eth2/types/src/crosslink.rs b/eth2/types/src/crosslink.rs index 69f94662a..dfb02993d 100644 --- a/eth2/types/src/crosslink.rs +++ b/eth2/types/src/crosslink.rs @@ -1,4 +1,4 @@ -use super::ssz::{Decodable, DecodeError, Encodable, SszStream}; +use super::ssz::{hash, Decodable, DecodeError, Encodable, SszStream, TreeHash}; use super::Hash256; use crate::test_utils::TestRandom; use rand::RngCore; @@ -41,6 +41,15 @@ impl Decodable for Crosslink { } } +impl TreeHash for Crosslink { + fn hash_tree_root(&self) -> Vec { + let mut result: Vec = vec![]; + result.append(&mut self.slot.hash_tree_root()); + result.append(&mut self.shard_block_root.hash_tree_root()); + hash(&result) + } +} + impl TestRandom for Crosslink { fn random_for_test(rng: &mut T) -> Self { Self { @@ -66,4 +75,16 @@ mod tests { assert_eq!(original, decoded); } + + #[test] + pub fn test_hash_tree_root() { + let mut rng = XorShiftRng::from_seed([42; 16]); + let original = Crosslink::random_for_test(&mut rng); + + let result = original.hash_tree_root(); + + assert_eq!(result.len(), 32); + // TODO: Add further tests + // https://github.com/sigp/lighthouse/issues/170 + } } diff --git a/eth2/types/src/deposit.rs b/eth2/types/src/deposit.rs index 9d84bc278..d2f112ec8 100644 --- a/eth2/types/src/deposit.rs +++ b/eth2/types/src/deposit.rs @@ -1,4 +1,4 @@ -use super::ssz::{Decodable, DecodeError, Encodable, SszStream}; +use super::ssz::{hash, Decodable, DecodeError, Encodable, SszStream, TreeHash}; use super::{DepositData, Hash256}; use crate::test_utils::TestRandom; use rand::RngCore; @@ -35,6 +35,16 @@ impl Decodable for Deposit { } } +impl TreeHash for Deposit { + fn hash_tree_root(&self) -> Vec { + let mut result: Vec = vec![]; + result.append(&mut self.merkle_branch.hash_tree_root()); + result.append(&mut self.merkle_tree_index.hash_tree_root()); + result.append(&mut self.deposit_data.hash_tree_root()); + hash(&result) + } +} + impl TestRandom for Deposit { fn random_for_test(rng: &mut T) -> Self { Self { @@ -61,4 +71,16 @@ mod tests { assert_eq!(original, decoded); } + + #[test] + pub fn test_hash_tree_root() { + let mut rng = XorShiftRng::from_seed([42; 16]); + let original = Deposit::random_for_test(&mut rng); + + let result = original.hash_tree_root(); + + assert_eq!(result.len(), 32); + // TODO: Add further tests + // https://github.com/sigp/lighthouse/issues/170 + } } diff --git a/eth2/types/src/deposit_data.rs b/eth2/types/src/deposit_data.rs index b85a95708..21ca6cd51 100644 --- a/eth2/types/src/deposit_data.rs +++ b/eth2/types/src/deposit_data.rs @@ -1,4 +1,4 @@ -use super::ssz::{Decodable, DecodeError, Encodable, SszStream}; +use super::ssz::{hash, Decodable, DecodeError, Encodable, SszStream, TreeHash}; use super::DepositInput; use crate::test_utils::TestRandom; use rand::RngCore; @@ -35,6 +35,16 @@ impl Decodable for DepositData { } } +impl TreeHash for DepositData { + fn hash_tree_root(&self) -> Vec { + let mut result: Vec = vec![]; + result.append(&mut self.amount.hash_tree_root()); + result.append(&mut self.timestamp.hash_tree_root()); + result.append(&mut self.deposit_input.hash_tree_root()); + hash(&result) + } +} + impl TestRandom for DepositData { fn random_for_test(rng: &mut T) -> Self { Self { @@ -61,4 +71,16 @@ mod tests { assert_eq!(original, decoded); } + + #[test] + pub fn test_hash_tree_root() { + let mut rng = XorShiftRng::from_seed([42; 16]); + let original = DepositData::random_for_test(&mut rng); + + let result = original.hash_tree_root(); + + assert_eq!(result.len(), 32); + // TODO: Add further tests + // https://github.com/sigp/lighthouse/issues/170 + } } diff --git a/eth2/types/src/deposit_input.rs b/eth2/types/src/deposit_input.rs index 4f2d71096..5377926d6 100644 --- a/eth2/types/src/deposit_input.rs +++ b/eth2/types/src/deposit_input.rs @@ -1,4 +1,4 @@ -use super::ssz::{Decodable, DecodeError, Encodable, SszStream}; +use super::ssz::{hash, Decodable, DecodeError, Encodable, SszStream, TreeHash}; use super::Hash256; use crate::test_utils::TestRandom; use bls::{PublicKey, Signature}; @@ -36,6 +36,16 @@ impl Decodable for DepositInput { } } +impl TreeHash for DepositInput { + fn hash_tree_root(&self) -> Vec { + let mut result: Vec = vec![]; + result.append(&mut self.pubkey.hash_tree_root()); + result.append(&mut self.withdrawal_credentials.hash_tree_root()); + result.append(&mut self.proof_of_possession.hash_tree_root()); + hash(&result) + } +} + impl TestRandom for DepositInput { fn random_for_test(rng: &mut T) -> Self { Self { @@ -62,4 +72,16 @@ mod tests { assert_eq!(original, decoded); } + + #[test] + pub fn test_hash_tree_root() { + let mut rng = XorShiftRng::from_seed([42; 16]); + let original = DepositInput::random_for_test(&mut rng); + + let result = original.hash_tree_root(); + + assert_eq!(result.len(), 32); + // TODO: Add further tests + // https://github.com/sigp/lighthouse/issues/170 + } } diff --git a/eth2/types/src/eth1_data.rs b/eth2/types/src/eth1_data.rs index a20559e18..6d9e67a4a 100644 --- a/eth2/types/src/eth1_data.rs +++ b/eth2/types/src/eth1_data.rs @@ -1,4 +1,4 @@ -use super::ssz::{Decodable, DecodeError, Encodable, SszStream}; +use super::ssz::{hash, Decodable, DecodeError, Encodable, SszStream, TreeHash}; use super::Hash256; use crate::test_utils::TestRandom; use rand::RngCore; @@ -32,6 +32,15 @@ impl Decodable for Eth1Data { } } +impl TreeHash for Eth1Data { + fn hash_tree_root(&self) -> Vec { + let mut result: Vec = vec![]; + result.append(&mut self.deposit_root.hash_tree_root()); + result.append(&mut self.block_hash.hash_tree_root()); + hash(&result) + } +} + impl TestRandom for Eth1Data { fn random_for_test(rng: &mut T) -> Self { Self { @@ -57,4 +66,16 @@ mod tests { assert_eq!(original, decoded); } + + #[test] + pub fn test_hash_tree_root() { + let mut rng = XorShiftRng::from_seed([42; 16]); + let original = Eth1Data::random_for_test(&mut rng); + + let result = original.hash_tree_root(); + + assert_eq!(result.len(), 32); + // TODO: Add further tests + // https://github.com/sigp/lighthouse/issues/170 + } } diff --git a/eth2/types/src/eth1_data_vote.rs b/eth2/types/src/eth1_data_vote.rs index c4d9d01af..09a9a7954 100644 --- a/eth2/types/src/eth1_data_vote.rs +++ b/eth2/types/src/eth1_data_vote.rs @@ -1,4 +1,4 @@ -use super::ssz::{Decodable, DecodeError, Encodable, SszStream}; +use super::ssz::{hash, Decodable, DecodeError, Encodable, SszStream, TreeHash}; use super::Eth1Data; use crate::test_utils::TestRandom; use rand::RngCore; @@ -32,6 +32,15 @@ impl Decodable for Eth1DataVote { } } +impl TreeHash for Eth1DataVote { + fn hash_tree_root(&self) -> Vec { + let mut result: Vec = vec![]; + result.append(&mut self.eth1_data.hash_tree_root()); + result.append(&mut self.vote_count.hash_tree_root()); + hash(&result) + } +} + impl TestRandom for Eth1DataVote { fn random_for_test(rng: &mut T) -> Self { Self { @@ -57,4 +66,16 @@ mod tests { assert_eq!(original, decoded); } + + #[test] + pub fn test_hash_tree_root() { + let mut rng = XorShiftRng::from_seed([42; 16]); + let original = Eth1DataVote::random_for_test(&mut rng); + + let result = original.hash_tree_root(); + + assert_eq!(result.len(), 32); + // TODO: Add further tests + // https://github.com/sigp/lighthouse/issues/170 + } } diff --git a/eth2/types/src/exit.rs b/eth2/types/src/exit.rs index eeac11ce7..f70d26e41 100644 --- a/eth2/types/src/exit.rs +++ b/eth2/types/src/exit.rs @@ -1,4 +1,4 @@ -use super::ssz::{Decodable, DecodeError, Encodable, SszStream}; +use super::ssz::{hash, Decodable, DecodeError, Encodable, SszStream, TreeHash}; use crate::test_utils::TestRandom; use bls::Signature; use rand::RngCore; @@ -35,6 +35,16 @@ impl Decodable for Exit { } } +impl TreeHash for Exit { + fn hash_tree_root(&self) -> Vec { + let mut result: Vec = vec![]; + result.append(&mut self.slot.hash_tree_root()); + result.append(&mut self.validator_index.hash_tree_root()); + result.append(&mut self.signature.hash_tree_root()); + hash(&result) + } +} + impl TestRandom for Exit { fn random_for_test(rng: &mut T) -> Self { Self { @@ -61,4 +71,16 @@ mod tests { assert_eq!(original, decoded); } + + #[test] + pub fn test_hash_tree_root() { + let mut rng = XorShiftRng::from_seed([42; 16]); + let original = Exit::random_for_test(&mut rng); + + let result = original.hash_tree_root(); + + assert_eq!(result.len(), 32); + // TODO: Add further tests + // https://github.com/sigp/lighthouse/issues/170 + } } diff --git a/eth2/types/src/fork.rs b/eth2/types/src/fork.rs index b70dafccc..7915299a1 100644 --- a/eth2/types/src/fork.rs +++ b/eth2/types/src/fork.rs @@ -1,4 +1,4 @@ -use super::ssz::{Decodable, DecodeError, Encodable, SszStream}; +use super::ssz::{hash, Decodable, DecodeError, Encodable, SszStream, TreeHash}; use crate::test_utils::TestRandom; use rand::RngCore; @@ -34,6 +34,16 @@ impl Decodable for Fork { } } +impl TreeHash for Fork { + fn hash_tree_root(&self) -> Vec { + let mut result: Vec = vec![]; + result.append(&mut self.pre_fork_version.hash_tree_root()); + result.append(&mut self.post_fork_version.hash_tree_root()); + result.append(&mut self.fork_slot.hash_tree_root()); + hash(&result) + } +} + impl TestRandom for Fork { fn random_for_test(rng: &mut T) -> Self { Self { @@ -60,4 +70,16 @@ mod tests { assert_eq!(original, decoded); } + + #[test] + pub fn test_hash_tree_root() { + let mut rng = XorShiftRng::from_seed([42; 16]); + let original = Fork::random_for_test(&mut rng); + + let result = original.hash_tree_root(); + + assert_eq!(result.len(), 32); + // TODO: Add further tests + // https://github.com/sigp/lighthouse/issues/170 + } } diff --git a/eth2/types/src/pending_attestation.rs b/eth2/types/src/pending_attestation.rs index ad3dbb782..89ac7b07c 100644 --- a/eth2/types/src/pending_attestation.rs +++ b/eth2/types/src/pending_attestation.rs @@ -1,4 +1,4 @@ -use super::ssz::{Decodable, DecodeError, Encodable, SszStream}; +use super::ssz::{hash, Decodable, DecodeError, Encodable, SszStream, TreeHash}; use super::{AttestationData, Bitfield}; use crate::test_utils::TestRandom; use rand::RngCore; @@ -39,6 +39,17 @@ impl Decodable for PendingAttestation { } } +impl TreeHash for PendingAttestation { + fn hash_tree_root(&self) -> Vec { + let mut result: Vec = vec![]; + result.append(&mut self.data.hash_tree_root()); + result.append(&mut self.aggregation_bitfield.hash_tree_root()); + result.append(&mut self.custody_bitfield.hash_tree_root()); + result.append(&mut self.custody_bitfield.hash_tree_root()); + hash(&result) + } +} + impl TestRandom for PendingAttestation { fn random_for_test(rng: &mut T) -> Self { Self { @@ -66,4 +77,16 @@ mod tests { assert_eq!(original, decoded); } + + #[test] + pub fn test_hash_tree_root() { + let mut rng = XorShiftRng::from_seed([42; 16]); + let original = PendingAttestation::random_for_test(&mut rng); + + let result = original.hash_tree_root(); + + assert_eq!(result.len(), 32); + // TODO: Add further tests + // https://github.com/sigp/lighthouse/issues/170 + } } diff --git a/eth2/types/src/proposal_signed_data.rs b/eth2/types/src/proposal_signed_data.rs index e38a9cadb..41f0cda81 100644 --- a/eth2/types/src/proposal_signed_data.rs +++ b/eth2/types/src/proposal_signed_data.rs @@ -1,4 +1,4 @@ -use super::ssz::{Decodable, DecodeError, Encodable, SszStream}; +use super::ssz::{hash, Decodable, DecodeError, Encodable, SszStream, TreeHash}; use super::Hash256; use crate::test_utils::TestRandom; use rand::RngCore; @@ -35,6 +35,16 @@ impl Decodable for ProposalSignedData { } } +impl TreeHash for ProposalSignedData { + fn hash_tree_root(&self) -> Vec { + let mut result: Vec = vec![]; + result.append(&mut self.slot.hash_tree_root()); + result.append(&mut self.shard.hash_tree_root()); + result.append(&mut self.block_root.hash_tree_root()); + hash(&result) + } +} + impl TestRandom for ProposalSignedData { fn random_for_test(rng: &mut T) -> Self { Self { @@ -61,4 +71,16 @@ mod tests { assert_eq!(original, decoded); } + + #[test] + pub fn test_hash_tree_root() { + let mut rng = XorShiftRng::from_seed([42; 16]); + let original = ProposalSignedData::random_for_test(&mut rng); + + let result = original.hash_tree_root(); + + assert_eq!(result.len(), 32); + // TODO: Add further tests + // https://github.com/sigp/lighthouse/issues/170 + } } diff --git a/eth2/types/src/proposer_slashing.rs b/eth2/types/src/proposer_slashing.rs index 3754c3b32..8d9a843e2 100644 --- a/eth2/types/src/proposer_slashing.rs +++ b/eth2/types/src/proposer_slashing.rs @@ -1,4 +1,4 @@ -use super::ssz::{Decodable, DecodeError, Encodable, SszStream}; +use super::ssz::{hash, Decodable, DecodeError, Encodable, SszStream, TreeHash}; use super::ProposalSignedData; use crate::test_utils::TestRandom; use bls::Signature; @@ -44,6 +44,18 @@ impl Decodable for ProposerSlashing { } } +impl TreeHash for ProposerSlashing { + fn hash_tree_root(&self) -> Vec { + let mut result: Vec = vec![]; + result.append(&mut self.proposer_index.hash_tree_root()); + result.append(&mut self.proposal_data_1.hash_tree_root()); + result.append(&mut self.proposal_signature_1.hash_tree_root()); + result.append(&mut self.proposal_data_2.hash_tree_root()); + result.append(&mut self.proposal_signature_2.hash_tree_root()); + hash(&result) + } +} + impl TestRandom for ProposerSlashing { fn random_for_test(rng: &mut T) -> Self { Self { @@ -72,4 +84,16 @@ mod tests { assert_eq!(original, decoded); } + + #[test] + pub fn test_hash_tree_root() { + let mut rng = XorShiftRng::from_seed([42; 16]); + let original = ProposerSlashing::random_for_test(&mut rng); + + let result = original.hash_tree_root(); + + assert_eq!(result.len(), 32); + // TODO: Add further tests + // https://github.com/sigp/lighthouse/issues/170 + } } diff --git a/eth2/types/src/shard_committee.rs b/eth2/types/src/shard_committee.rs index d920f7db3..3e7202b2a 100644 --- a/eth2/types/src/shard_committee.rs +++ b/eth2/types/src/shard_committee.rs @@ -1,4 +1,4 @@ -use super::ssz::{Decodable, DecodeError, Encodable, SszStream}; +use super::ssz::{hash, Decodable, DecodeError, Encodable, SszStream, TreeHash}; use crate::test_utils::TestRandom; use rand::RngCore; @@ -24,6 +24,15 @@ impl Decodable for ShardCommittee { } } +impl TreeHash for ShardCommittee { + fn hash_tree_root(&self) -> Vec { + let mut result: Vec = vec![]; + result.append(&mut self.shard.hash_tree_root()); + result.append(&mut self.committee.hash_tree_root()); + hash(&result) + } +} + impl TestRandom for ShardCommittee { fn random_for_test(rng: &mut T) -> Self { Self { @@ -49,4 +58,16 @@ mod tests { assert_eq!(original, decoded); } + + #[test] + pub fn test_hash_tree_root() { + let mut rng = XorShiftRng::from_seed([42; 16]); + let original = ShardCommittee::random_for_test(&mut rng); + + let result = original.hash_tree_root(); + + assert_eq!(result.len(), 32); + // TODO: Add further tests + // https://github.com/sigp/lighthouse/issues/170 + } } diff --git a/eth2/types/src/shard_reassignment_record.rs b/eth2/types/src/shard_reassignment_record.rs index 9bc014689..8f48692fc 100644 --- a/eth2/types/src/shard_reassignment_record.rs +++ b/eth2/types/src/shard_reassignment_record.rs @@ -1,4 +1,4 @@ -use super::ssz::{Decodable, DecodeError, Encodable, SszStream}; +use super::ssz::{hash, Decodable, DecodeError, Encodable, SszStream, TreeHash}; use crate::test_utils::TestRandom; use rand::RngCore; @@ -34,6 +34,16 @@ impl Decodable for ShardReassignmentRecord { } } +impl TreeHash for ShardReassignmentRecord { + fn hash_tree_root(&self) -> Vec { + let mut result: Vec = vec![]; + result.append(&mut self.validator_index.hash_tree_root()); + result.append(&mut self.shard.hash_tree_root()); + result.append(&mut self.slot.hash_tree_root()); + hash(&result) + } +} + impl TestRandom for ShardReassignmentRecord { fn random_for_test(rng: &mut T) -> Self { Self { @@ -60,4 +70,16 @@ mod tests { assert_eq!(original, decoded); } + + #[test] + pub fn test_hash_tree_root() { + let mut rng = XorShiftRng::from_seed([42; 16]); + let original = ShardReassignmentRecord::random_for_test(&mut rng); + + let result = original.hash_tree_root(); + + assert_eq!(result.len(), 32); + // TODO: Add further tests + // https://github.com/sigp/lighthouse/issues/170 + } } diff --git a/eth2/types/src/slashable_vote_data.rs b/eth2/types/src/slashable_vote_data.rs index e6fa36bc1..3f088034f 100644 --- a/eth2/types/src/slashable_vote_data.rs +++ b/eth2/types/src/slashable_vote_data.rs @@ -1,4 +1,4 @@ -use super::ssz::{Decodable, DecodeError, Encodable, SszStream}; +use super::ssz::{hash, Decodable, DecodeError, Encodable, SszStream, TreeHash}; use super::AttestationData; use crate::test_utils::TestRandom; use bls::AggregateSignature; @@ -40,6 +40,17 @@ impl Decodable for SlashableVoteData { } } +impl TreeHash for SlashableVoteData { + fn hash_tree_root(&self) -> Vec { + let mut result: Vec = vec![]; + result.append(&mut self.custody_bit_0_indices.hash_tree_root()); + result.append(&mut self.custody_bit_1_indices.hash_tree_root()); + result.append(&mut self.data.hash_tree_root()); + result.append(&mut self.aggregate_signature.hash_tree_root()); + hash(&result) + } +} + impl TestRandom for SlashableVoteData { fn random_for_test(rng: &mut T) -> Self { Self { @@ -67,4 +78,16 @@ mod tests { assert_eq!(original, decoded); } + + #[test] + pub fn test_hash_tree_root() { + let mut rng = XorShiftRng::from_seed([42; 16]); + let original = SlashableVoteData::random_for_test(&mut rng); + + let result = original.hash_tree_root(); + + assert_eq!(result.len(), 32); + // TODO: Add further tests + // https://github.com/sigp/lighthouse/issues/170 + } } diff --git a/eth2/types/src/special_record.rs b/eth2/types/src/special_record.rs index 0a0a6978a..21e9c88f6 100644 --- a/eth2/types/src/special_record.rs +++ b/eth2/types/src/special_record.rs @@ -1,4 +1,4 @@ -use super::ssz::{Decodable, DecodeError, Encodable, SszStream}; +use ssz::{hash, Decodable, DecodeError, Encodable, SszStream, TreeHash}; /// The value of the "type" field of SpecialRecord. /// @@ -71,6 +71,15 @@ impl Decodable for SpecialRecord { } } +impl TreeHash for SpecialRecord { + fn hash_tree_root(&self) -> Vec { + let mut result: Vec = vec![]; + result.append(&mut self.kind.hash_tree_root()); + result.append(&mut self.data.as_slice().hash_tree_root()); + hash(&result) + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/eth2/types/src/validator.rs b/eth2/types/src/validator.rs index 8408e7423..256be68df 100644 --- a/eth2/types/src/validator.rs +++ b/eth2/types/src/validator.rs @@ -2,7 +2,7 @@ use super::bls::PublicKey; use super::Hash256; use crate::test_utils::TestRandom; use rand::RngCore; -use ssz::{Decodable, DecodeError, Encodable, SszStream}; +use ssz::{hash, Decodable, DecodeError, Encodable, SszStream, TreeHash}; const STATUS_FLAG_INITIATED_EXIT: u8 = 1; const STATUS_FLAG_WITHDRAWABLE: u8 = 2; @@ -142,6 +142,24 @@ impl Decodable for Validator { } } +impl TreeHash for Validator { + fn hash_tree_root(&self) -> Vec { + let mut result: Vec = vec![]; + result.append(&mut self.pubkey.hash_tree_root()); + result.append(&mut self.withdrawal_credentials.hash_tree_root()); + result.append(&mut self.proposer_slots.hash_tree_root()); + result.append(&mut self.activation_slot.hash_tree_root()); + result.append(&mut self.exit_slot.hash_tree_root()); + result.append(&mut self.withdrawal_slot.hash_tree_root()); + result.append(&mut self.penalized_slot.hash_tree_root()); + result.append(&mut self.exit_count.hash_tree_root()); + result.append(&mut (status_flag_to_byte(self.status_flags) as u64).hash_tree_root()); + result.append(&mut self.latest_custody_reseed_slot.hash_tree_root()); + result.append(&mut self.penultimate_custody_reseed_slot.hash_tree_root()); + hash(&result) + } +} + impl TestRandom for Validator { fn random_for_test(rng: &mut T) -> Self { Self { @@ -198,4 +216,16 @@ mod tests { } } } + + #[test] + pub fn test_hash_tree_root() { + let mut rng = XorShiftRng::from_seed([42; 16]); + let original = Validator::random_for_test(&mut rng); + + let result = original.hash_tree_root(); + + assert_eq!(result.len(), 32); + // TODO: Add further tests + // https://github.com/sigp/lighthouse/issues/170 + } } diff --git a/eth2/types/src/validator_registry_delta_block.rs b/eth2/types/src/validator_registry_delta_block.rs index 57aa469df..c8bf41c94 100644 --- a/eth2/types/src/validator_registry_delta_block.rs +++ b/eth2/types/src/validator_registry_delta_block.rs @@ -2,7 +2,7 @@ use super::Hash256; use crate::test_utils::TestRandom; use bls::PublicKey; use rand::RngCore; -use ssz::{Decodable, DecodeError, Encodable, SszStream}; +use ssz::{hash, Decodable, DecodeError, Encodable, SszStream, TreeHash}; // The information gathered from the PoW chain validator registration function. #[derive(Debug, Clone, PartialEq)] @@ -58,6 +58,18 @@ impl Decodable for ValidatorRegistryDeltaBlock { } } +impl TreeHash for ValidatorRegistryDeltaBlock { + fn hash_tree_root(&self) -> Vec { + let mut result: Vec = vec![]; + result.append(&mut self.latest_registry_delta_root.hash_tree_root()); + result.append(&mut self.validator_index.hash_tree_root()); + result.append(&mut self.pubkey.hash_tree_root()); + result.append(&mut self.slot.hash_tree_root()); + result.append(&mut self.flag.hash_tree_root()); + hash(&result) + } +} + impl TestRandom for ValidatorRegistryDeltaBlock { fn random_for_test(rng: &mut T) -> Self { Self { @@ -86,4 +98,16 @@ mod tests { assert_eq!(original, decoded); } + + #[test] + pub fn test_hash_tree_root() { + let mut rng = XorShiftRng::from_seed([42; 16]); + let original = ValidatorRegistryDeltaBlock::random_for_test(&mut rng); + + let result = original.hash_tree_root(); + + assert_eq!(result.len(), 32); + // TODO: Add further tests + // https://github.com/sigp/lighthouse/issues/170 + } } diff --git a/eth2/utils/bls/src/aggregate_signature.rs b/eth2/utils/bls/src/aggregate_signature.rs index 6012f78c1..6bccf128e 100644 --- a/eth2/utils/bls/src/aggregate_signature.rs +++ b/eth2/utils/bls/src/aggregate_signature.rs @@ -1,4 +1,4 @@ -use super::ssz::{decode_ssz_list, Decodable, DecodeError, Encodable, SszStream}; +use super::ssz::{decode_ssz_list, hash, Decodable, DecodeError, Encodable, SszStream, TreeHash}; use super::{AggregatePublicKey, Signature}; use bls_aggregates::AggregateSignature as RawAggregateSignature; @@ -44,6 +44,12 @@ impl Decodable for AggregateSignature { } } +impl TreeHash for AggregateSignature { + fn hash_tree_root(&self) -> Vec { + hash(&self.0.as_bytes()) + } +} + #[cfg(test)] mod tests { use super::super::ssz::ssz_encode; diff --git a/eth2/utils/bls/src/public_key.rs b/eth2/utils/bls/src/public_key.rs index 4a53893f0..d0635e6f5 100644 --- a/eth2/utils/bls/src/public_key.rs +++ b/eth2/utils/bls/src/public_key.rs @@ -1,7 +1,9 @@ use super::SecretKey; use bls_aggregates::PublicKey as RawPublicKey; use hex::encode as hex_encode; -use ssz::{decode_ssz_list, ssz_encode, Decodable, DecodeError, Encodable, SszStream}; +use ssz::{ + decode_ssz_list, hash, ssz_encode, Decodable, DecodeError, Encodable, SszStream, TreeHash, +}; use std::default; use std::hash::{Hash, Hasher}; @@ -53,6 +55,12 @@ impl Decodable for PublicKey { } } +impl TreeHash for PublicKey { + fn hash_tree_root(&self) -> Vec { + hash(&self.0.as_bytes()) + } +} + impl PartialEq for PublicKey { fn eq(&self, other: &PublicKey) -> bool { ssz_encode(self) == ssz_encode(other) diff --git a/eth2/utils/bls/src/secret_key.rs b/eth2/utils/bls/src/secret_key.rs index e86e8dec0..3327d94d6 100644 --- a/eth2/utils/bls/src/secret_key.rs +++ b/eth2/utils/bls/src/secret_key.rs @@ -1,5 +1,5 @@ use bls_aggregates::{DecodeError as BlsDecodeError, SecretKey as RawSecretKey}; -use ssz::{decode_ssz_list, Decodable, DecodeError, Encodable, SszStream}; +use ssz::{decode_ssz_list, Decodable, DecodeError, Encodable, SszStream, TreeHash}; /// A single BLS signature. /// @@ -40,6 +40,12 @@ impl Decodable for SecretKey { } } +impl TreeHash for SecretKey { + fn hash_tree_root(&self) -> Vec { + self.0.as_bytes().clone() + } +} + #[cfg(test)] mod tests { use super::super::ssz::ssz_encode; diff --git a/eth2/utils/bls/src/signature.rs b/eth2/utils/bls/src/signature.rs index 7f9e61718..9e4945bb7 100644 --- a/eth2/utils/bls/src/signature.rs +++ b/eth2/utils/bls/src/signature.rs @@ -1,4 +1,4 @@ -use super::ssz::{decode_ssz_list, Decodable, DecodeError, Encodable, SszStream}; +use super::ssz::{decode_ssz_list, hash, Decodable, DecodeError, Encodable, SszStream, TreeHash}; use super::{PublicKey, SecretKey}; use bls_aggregates::Signature as RawSignature; @@ -57,6 +57,12 @@ impl Decodable for Signature { } } +impl TreeHash for Signature { + fn hash_tree_root(&self) -> Vec { + hash(&self.0.as_bytes()) + } +} + #[cfg(test)] mod tests { use super::super::ssz::ssz_encode; diff --git a/eth2/utils/boolean-bitfield/src/lib.rs b/eth2/utils/boolean-bitfield/src/lib.rs index 98518d70c..33c461361 100644 --- a/eth2/utils/boolean-bitfield/src/lib.rs +++ b/eth2/utils/boolean-bitfield/src/lib.rs @@ -149,6 +149,12 @@ impl ssz::Decodable for BooleanBitfield { } } +impl ssz::TreeHash for BooleanBitfield { + fn hash_tree_root(&self) -> Vec { + self.to_bytes().hash_tree_root() + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/eth2/utils/ssz/src/impl_encode.rs b/eth2/utils/ssz/src/impl_encode.rs index 63de18058..8714cf75f 100644 --- a/eth2/utils/ssz/src/impl_encode.rs +++ b/eth2/utils/ssz/src/impl_encode.rs @@ -79,6 +79,14 @@ mod tests { assert_eq!(ssz.drain(), vec![0; 32]); } + #[test] + fn test_ssz_encode_address() { + let h = Address::zero(); + let mut ssz = SszStream::new(); + ssz.append(&h); + assert_eq!(ssz.drain(), vec![0; 20]); + } + #[test] fn test_ssz_encode_u8() { let x: u8 = 0; diff --git a/eth2/utils/ssz/src/impl_tree_hash.rs b/eth2/utils/ssz/src/impl_tree_hash.rs index 229b5549a..9463283cb 100644 --- a/eth2/utils/ssz/src/impl_tree_hash.rs +++ b/eth2/utils/ssz/src/impl_tree_hash.rs @@ -1,51 +1,54 @@ -extern crate hashing; - -use self::hashing::canonical_hash; use super::ethereum_types::{Address, H256}; -use super::{merkle_hash, ssz_encode, TreeHash}; -use std::cmp::Ord; -use std::collections::HashMap; -use std::hash::Hash; +use super::{hash, merkle_hash, ssz_encode, TreeHash}; impl TreeHash for u8 { - fn tree_hash(&self) -> Vec { + fn hash_tree_root(&self) -> Vec { ssz_encode(self) } } impl TreeHash for u16 { - fn tree_hash(&self) -> Vec { + fn hash_tree_root(&self) -> Vec { ssz_encode(self) } } impl TreeHash for u32 { - fn tree_hash(&self) -> Vec { + fn hash_tree_root(&self) -> Vec { ssz_encode(self) } } impl TreeHash for u64 { - fn tree_hash(&self) -> Vec { + fn hash_tree_root(&self) -> Vec { + ssz_encode(self) + } +} + +impl TreeHash for usize { + fn hash_tree_root(&self) -> Vec { ssz_encode(self) } } impl TreeHash for Address { - fn tree_hash(&self) -> Vec { + fn hash_tree_root(&self) -> Vec { ssz_encode(self) } } impl TreeHash for H256 { - fn tree_hash(&self) -> Vec { + fn hash_tree_root(&self) -> Vec { ssz_encode(self) } } impl TreeHash for [u8] { - fn tree_hash(&self) -> Vec { - hash(&self) + fn hash_tree_root(&self) -> Vec { + if self.len() > 32 { + return hash(&self); + } + self.to_vec() } } @@ -53,71 +56,23 @@ impl TreeHash for Vec where T: TreeHash, { - /// Returns the merkle_hash of a list of tree_hash values created + /// Returns the merkle_hash of a list of hash_tree_root values created /// from the given list. /// Note: A byte vector, Vec, must be converted to a slice (as_slice()) /// to be handled properly (i.e. hashed) as byte array. - fn tree_hash(&self) -> Vec { - let mut tree_hashes = self.iter().map(|x| x.tree_hash()).collect(); + fn hash_tree_root(&self) -> Vec { + let mut tree_hashes = self.iter().map(|x| x.hash_tree_root()).collect(); merkle_hash(&mut tree_hashes) } } -impl TreeHash for HashMap -where - K: Eq, - K: Hash, - K: Ord, - V: TreeHash, -{ - /// Appends the tree_hash for each value of 'self, sorted by key, - /// into a byte array and returns the hash of said byte array - fn tree_hash(&self) -> Vec { - let mut items: Vec<_> = self.iter().collect(); - items.sort_by(|a, b| a.0.cmp(b.0)); - let mut result = Vec::new(); - for item in items { - result.append(&mut item.1.tree_hash()); - } - - hash(&result) - } -} - -fn hash(data: &[u8]) -> Vec { - canonical_hash(data) -} - #[cfg(test)] mod tests { use super::*; #[test] fn test_impl_tree_hash_vec() { - let result = vec![1u32, 2, 3, 4, 5, 6, 7].tree_hash(); + let result = vec![1u32, 2, 3, 4, 5, 6, 7].hash_tree_root(); assert_eq!(result.len(), 32); } - - #[test] - fn test_impl_tree_hash_hashmap() { - let mut map = HashMap::new(); - map.insert("c", 3); - map.insert("b", 2); - map.insert("g", 7); - map.insert("d", 6); - map.insert("e", 4); - map.insert("a", 1u32); - map.insert("f", 5); - let result = map.tree_hash(); - - // TODO: create tests that tie-out to an offical result - assert_eq!( - result, - [ - 130, 215, 165, 255, 224, 6, 144, 225, 14, 139, 67, 238, 205, 240, 20, 173, 53, 0, - 105, 62, 49, 174, 244, 160, 114, 92, 232, 11, 102, 200, 112, 24 - ] - ); - } - } diff --git a/eth2/utils/ssz/src/lib.rs b/eth2/utils/ssz/src/lib.rs index bea15c054..206040c2d 100644 --- a/eth2/utils/ssz/src/lib.rs +++ b/eth2/utils/ssz/src/lib.rs @@ -20,7 +20,7 @@ mod impl_tree_hash; pub use crate::decode::{decode_ssz, decode_ssz_list, Decodable, DecodeError}; pub use crate::encode::{Encodable, SszStream}; -pub use crate::tree_hash::{merkle_hash, TreeHash}; +pub use crate::tree_hash::{hash, merkle_hash, TreeHash}; pub const LENGTH_BYTES: usize = 4; pub const MAX_LIST_SIZE: usize = 1 << (4 * 8); diff --git a/eth2/utils/ssz/src/tree_hash.rs b/eth2/utils/ssz/src/tree_hash.rs index 912be110a..5f62c1c7b 100644 --- a/eth2/utils/ssz/src/tree_hash.rs +++ b/eth2/utils/ssz/src/tree_hash.rs @@ -1,48 +1,41 @@ +use hashing::canonical_hash; + const SSZ_CHUNK_SIZE: usize = 128; const HASHSIZE: usize = 32; pub trait TreeHash { - fn tree_hash(&self) -> Vec; + fn hash_tree_root(&self) -> Vec; } /// Returns a 32 byte hash of 'list' - a vector of byte vectors. /// Note that this will consume 'list'. pub fn merkle_hash(list: &mut Vec>) -> Vec { // flatten list - let (chunk_size, mut data) = list_to_blob(list); + let (chunk_size, mut chunkz) = list_to_blob(list); // get data_len as bytes. It will hashed will the merkle root - let dlen = list.len() as u64; - let data_len_bytes = &mut dlen.tree_hash(); - data_len_bytes.resize(32, 0); + let datalen = list.len().to_le_bytes(); - // merklize - let mut mhash = hash_level(&mut data, chunk_size); - while mhash.len() > HASHSIZE { - mhash = hash_level(&mut mhash, HASHSIZE); - } + // Tree-hash + while chunkz.len() > HASHSIZE { + let mut new_chunkz: Vec = Vec::new(); - mhash.append(data_len_bytes); - mhash.as_slice().tree_hash() -} - -/// Takes a flat vector of bytes. It then hashes 'chunk_size * 2' slices into -/// a byte vector of hashes, divisible by HASHSIZE -fn hash_level(data: &mut Vec, chunk_size: usize) -> Vec { - let mut result: Vec = Vec::new(); - for two_chunks in data.chunks(chunk_size * 2) { - if two_chunks.len() == chunk_size && data.len() > chunk_size { - // if there is only one chunk here, hash it with a zero-byte - // SSZ_CHUNK_SIZE vector - let mut c = two_chunks.to_vec(); - c.append(&mut vec![0; SSZ_CHUNK_SIZE]); - result.append(&mut c.as_slice().tree_hash()); - } else { - result.append(&mut two_chunks.tree_hash()); + for two_chunks in chunkz.chunks(chunk_size * 2) { + if two_chunks.len() == chunk_size { + // Odd number of chunks + let mut c = two_chunks.to_vec(); + c.append(&mut vec![0; SSZ_CHUNK_SIZE]); + new_chunkz.append(&mut hash(&c)); + } else { + // Hash two chuncks together + new_chunkz.append(&mut hash(two_chunks)); + } } + chunkz = new_chunkz; } - result + chunkz.append(&mut datalen.to_vec()); + hash(&chunkz) } fn list_to_blob(list: &mut Vec>) -> (usize, Vec) { @@ -67,10 +60,13 @@ fn list_to_blob(list: &mut Vec>) -> (usize, Vec) { data.append(item); } } - (chunk_size, data) } +pub fn hash(data: &[u8]) -> Vec { + canonical_hash(data) +} + #[cfg(test)] mod tests { use super::*;