From b36fe8f937f779d0b6b06ef726182b04ea90d9f1 Mon Sep 17 00:00:00 2001 From: Henry de Valence Date: Fri, 14 Aug 2020 22:45:11 -0700 Subject: [PATCH] chain: move sha256d to serialization module. This extracts the SHA256d code from being split across two modules and puts it in one module, under serialization. The code is unchanged except for three deleted tests: * `sha256d_flush` in `sha256d_writer` (not a meaningful test); * `transactionhash_debug` (constructs an invalid transaction hash, and the behavior is tested in the next test); * `decode_state_debug` (we do not need to test the Debug output of DecodeState); --- zebra-chain/src/block/hash.rs | 7 +- zebra-chain/src/block/tests.rs | 7 +- zebra-chain/src/lib.rs | 1 - zebra-chain/src/merkle_tree.rs | 5 +- zebra-chain/src/serialization.rs | 2 + zebra-chain/src/serialization/sha256d.rs | 77 ++++++++++++++++++++ zebra-chain/src/sha256d_writer.rs | 51 ------------- zebra-chain/src/transaction/hash.rs | 25 +------ zebra-chain/src/types.rs | 48 ------------ zebra-network/src/protocol/external/codec.rs | 36 ++------- 10 files changed, 97 insertions(+), 162 deletions(-) create mode 100644 zebra-chain/src/serialization/sha256d.rs delete mode 100644 zebra-chain/src/sha256d_writer.rs diff --git a/zebra-chain/src/block/hash.rs b/zebra-chain/src/block/hash.rs index 5b0472bdf..7c4198e80 100644 --- a/zebra-chain/src/block/hash.rs +++ b/zebra-chain/src/block/hash.rs @@ -4,9 +4,8 @@ use std::{fmt, io}; use proptest_derive::Arbitrary; use serde::{Deserialize, Serialize}; -use crate::{ - serialization::{ReadZcashExt, SerializationError, ZcashDeserialize, ZcashSerialize}, - sha256d_writer::Sha256dWriter, +use crate::serialization::{ + sha256d, ReadZcashExt, SerializationError, ZcashDeserialize, ZcashSerialize, }; use super::BlockHeader; @@ -37,7 +36,7 @@ impl fmt::Debug for BlockHeaderHash { impl<'a> From<&'a BlockHeader> for BlockHeaderHash { fn from(block_header: &'a BlockHeader) -> Self { - let mut hash_writer = Sha256dWriter::default(); + let mut hash_writer = sha256d::Writer::default(); block_header .zcash_serialize(&mut hash_writer) .expect("Sha256dWriter is infallible"); diff --git a/zebra-chain/src/block/tests.rs b/zebra-chain/src/block/tests.rs index 97aec1f3c..faa67082e 100644 --- a/zebra-chain/src/block/tests.rs +++ b/zebra-chain/src/block/tests.rs @@ -4,11 +4,12 @@ use crate::block::{difficulty::CompactDifficulty, light_client::LightClientRootH use crate::equihash_solution::EquihashSolution; use crate::merkle_tree::MerkleTreeRootHash; use crate::serialization::{ - SerializationError, ZcashDeserialize, ZcashDeserializeInto, ZcashSerialize, + sha256d, SerializationError, ZcashDeserialize, ZcashDeserializeInto, ZcashSerialize, }; use crate::types::LockTime; use crate::Network; -use crate::{sha256d_writer::Sha256dWriter, test::generate}; + +use crate::test::generate; use chrono::{DateTime, Duration, LocalResult, TimeZone, Utc}; use proptest::{ @@ -79,7 +80,7 @@ impl Arbitrary for BlockHeader { #[test] fn blockheaderhash_debug() { let preimage = b"foo bar baz"; - let mut sha_writer = Sha256dWriter::default(); + let mut sha_writer = sha256d::Writer::default(); let _ = sha_writer.write_all(preimage); let hash = BlockHeaderHash(sha_writer.finish()); diff --git a/zebra-chain/src/lib.rs b/zebra-chain/src/lib.rs index 2259f48b2..2fc7fe67c 100644 --- a/zebra-chain/src/lib.rs +++ b/zebra-chain/src/lib.rs @@ -13,7 +13,6 @@ extern crate serde; mod merkle_tree; mod serde_helpers; -mod sha256d_writer; pub mod addresses; pub mod block; diff --git a/zebra-chain/src/merkle_tree.rs b/zebra-chain/src/merkle_tree.rs index 6af26ac08..9e6f7aa25 100644 --- a/zebra-chain/src/merkle_tree.rs +++ b/zebra-chain/src/merkle_tree.rs @@ -7,8 +7,7 @@ use std::{fmt, io}; #[cfg(test)] use proptest_derive::Arbitrary; -use crate::serialization::{SerializationError, ZcashDeserialize, ZcashSerialize}; -use crate::sha256d_writer::Sha256dWriter; +use crate::serialization::{sha256d, SerializationError, ZcashDeserialize, ZcashSerialize}; use crate::transaction::Transaction; /// A binary hash tree of SHA256d (two rounds of SHA256) hashes for @@ -38,7 +37,7 @@ pub struct MerkleTreeRootHash(pub [u8; 32]); impl From> for MerkleTreeRootHash { fn from(merkle_tree: MerkleTree) -> Self { - let mut hash_writer = Sha256dWriter::default(); + let mut hash_writer = sha256d::Writer::default(); merkle_tree .zcash_serialize(&mut hash_writer) .expect("Sha256dWriter is infallible"); diff --git a/zebra-chain/src/serialization.rs b/zebra-chain/src/serialization.rs index 493af7cfa..834f2bee3 100644 --- a/zebra-chain/src/serialization.rs +++ b/zebra-chain/src/serialization.rs @@ -12,6 +12,8 @@ mod write_zcash; mod zcash_deserialize; mod zcash_serialize; +pub mod sha256d; + pub use error::SerializationError; pub use read_zcash::ReadZcashExt; pub use write_zcash::WriteZcashExt; diff --git a/zebra-chain/src/serialization/sha256d.rs b/zebra-chain/src/serialization/sha256d.rs new file mode 100644 index 000000000..2c6b511dc --- /dev/null +++ b/zebra-chain/src/serialization/sha256d.rs @@ -0,0 +1,77 @@ +//! SHA256d, a.k.a., double SHA2, a.k.a., 2 SHA 2 Furious + +use std::{fmt, io::prelude::*}; + +use sha2::{Digest, Sha256}; + +/// An `io::Write` instance that produces a SHA256d output. +#[derive(Default)] +pub struct Writer { + hash: Sha256, +} + +impl Writer { + /// Consume the Writer and produce the hash result. + pub fn finish(self) -> [u8; 32] { + let result1 = self.hash.result(); + let result2 = Sha256::digest(&result1); + let mut buffer = [0u8; 32]; + buffer[0..32].copy_from_slice(&result2[0..32]); + buffer + } +} + +impl Write for Writer { + fn write(&mut self, buf: &[u8]) -> std::io::Result { + self.hash.input(buf); + Ok(buf.len()) + } + + fn flush(&mut self) -> std::io::Result<()> { + Ok(()) + } +} + +/// A 4-byte checksum using truncated double-SHA256 (two rounds of SHA256). +#[derive(Copy, Clone, Eq, PartialEq)] +pub struct Checksum(pub [u8; 4]); + +impl<'a> From<&'a [u8]> for Checksum { + fn from(bytes: &'a [u8]) -> Self { + let hash1 = Sha256::digest(bytes); + let hash2 = Sha256::digest(&hash1); + let mut checksum = [0u8; 4]; + checksum[0..4].copy_from_slice(&hash2[0..4]); + Self(checksum) + } +} + +impl fmt::Debug for Checksum { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_tuple("Sha256dChecksum") + .field(&hex::encode(&self.0)) + .finish() + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn sha256d_checksum() { + // https://en.bitcoin.it/wiki/Protocol_documentation#Hashes + let input = b"hello"; + let checksum = Checksum::from(&input[..]); + let expected = Checksum([0x95, 0x95, 0xc9, 0xdf]); + assert_eq!(checksum, expected); + } + + #[test] + fn sha256d_checksum_debug() { + let input = b"hello"; + let checksum = Checksum::from(&input[..]); + + assert_eq!(format!("{:?}", checksum), "Sha256dChecksum(\"9595c9df\")"); + } +} diff --git a/zebra-chain/src/sha256d_writer.rs b/zebra-chain/src/sha256d_writer.rs deleted file mode 100644 index 53c75bf28..000000000 --- a/zebra-chain/src/sha256d_writer.rs +++ /dev/null @@ -1,51 +0,0 @@ -//! A Writer for Sha256d-related (two rounds of SHA256) types. - -use std::io::prelude::*; - -use sha2::{Digest, Sha256}; - -/// A type that lets you write out SHA256d (double-SHA256, as in two rounds). -#[derive(Default)] -pub struct Sha256dWriter { - hash: Sha256, -} - -impl Sha256dWriter { - /// Consume the Writer and produce the hash result. - pub fn finish(self) -> [u8; 32] { - let result1 = self.hash.result(); - let result2 = Sha256::digest(&result1); - let mut buffer = [0u8; 32]; - buffer[0..32].copy_from_slice(&result2[0..32]); - buffer - } -} - -impl Write for Sha256dWriter { - fn write(&mut self, buf: &[u8]) -> std::io::Result { - self.hash.input(buf); - Ok(buf.len()) - } - - fn flush(&mut self) -> std::io::Result<()> { - Ok(()) - } -} - -#[cfg(test)] -mod tests { - - use std::io::Write; - - use crate::sha256d_writer::Sha256dWriter; - - #[test] - // Just checking that `flush()` succeeds without error. - fn sha256d_flush() { - let preimage = b"foo bar baz"; - let mut sha_writer = Sha256dWriter::default(); - let _ = sha_writer.write_all(preimage); - - sha_writer.flush().unwrap(); - } -} diff --git a/zebra-chain/src/transaction/hash.rs b/zebra-chain/src/transaction/hash.rs index 6095d2491..94b50df3f 100644 --- a/zebra-chain/src/transaction/hash.rs +++ b/zebra-chain/src/transaction/hash.rs @@ -5,10 +5,7 @@ use std::fmt; use proptest_derive::Arbitrary; use serde::{Deserialize, Serialize}; -use crate::{ - serialization::{SerializationError, ZcashSerialize}, - sha256d_writer::Sha256dWriter, -}; +use crate::serialization::{sha256d, SerializationError, ZcashSerialize}; use super::Transaction; @@ -22,7 +19,7 @@ pub struct TransactionHash(pub [u8; 32]); impl From for TransactionHash { fn from(transaction: Transaction) -> Self { - let mut hash_writer = Sha256dWriter::default(); + let mut hash_writer = sha256d::Writer::default(); transaction .zcash_serialize(&mut hash_writer) .expect("Transactions must serialize into the hash."); @@ -53,26 +50,8 @@ impl std::str::FromStr for TransactionHash { #[cfg(test)] mod tests { - use std::io::Write; - - use crate::sha256d_writer::Sha256dWriter; - use super::*; - #[test] - fn transactionhash_debug() { - let preimage = b"foo bar baz"; - let mut sha_writer = Sha256dWriter::default(); - let _ = sha_writer.write_all(preimage); - - let hash = TransactionHash(sha_writer.finish()); - - assert_eq!( - format!("{:?}", hash), - r#"TransactionHash("bf46b4b5030752fedac6f884976162bbfb29a9398f104a280b3e34d51b416631")"# - ); - } - #[test] fn transactionhash_from_str() { let hash: TransactionHash = diff --git a/zebra-chain/src/types.rs b/zebra-chain/src/types.rs index 9f9375adf..ef37ceaa8 100644 --- a/zebra-chain/src/types.rs +++ b/zebra-chain/src/types.rs @@ -216,57 +216,11 @@ impl ZcashDeserialize for Script { } } -/// A 4-byte checksum using truncated double-SHA256 (two rounds of SHA256). -#[derive(Copy, Clone, Eq, PartialEq)] -pub struct Sha256dChecksum(pub [u8; 4]); - -impl<'a> From<&'a [u8]> for Sha256dChecksum { - fn from(bytes: &'a [u8]) -> Self { - use sha2::{Digest, Sha256}; - let hash1 = Sha256::digest(bytes); - let hash2 = Sha256::digest(&hash1); - let mut checksum = [0u8; 4]; - checksum[0..4].copy_from_slice(&hash2[0..4]); - Self(checksum) - } -} - -impl fmt::Debug for Sha256dChecksum { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_tuple("Sha256dChecksum") - .field(&hex::encode(&self.0)) - .finish() - } -} - #[cfg(test)] use proptest::prelude::*; -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn sha256d_checksum() { - // https://en.bitcoin.it/wiki/Protocol_documentation#Hashes - let input = b"hello"; - let checksum = Sha256dChecksum::from(&input[..]); - let expected = Sha256dChecksum([0x95, 0x95, 0xc9, 0xdf]); - assert_eq!(checksum, expected); - } - - #[test] - fn sha256d_checksum_debug() { - let input = b"hello"; - let checksum = Sha256dChecksum::from(&input[..]); - - assert_eq!(format!("{:?}", checksum), "Sha256dChecksum(\"9595c9df\")"); - } -} - #[cfg(test)] mod proptests { - use std::io::Cursor; use proptest::prelude::*; @@ -275,7 +229,6 @@ mod proptests { use crate::serialization::{ZcashDeserialize, ZcashSerialize}; proptest! { - #[test] fn locktime_roundtrip(locktime in any::()) { let mut bytes = Cursor::new(Vec::new()); @@ -297,6 +250,5 @@ mod proptests { prop_assert_eq![script, other_script]; } - } } diff --git a/zebra-network/src/protocol/external/codec.rs b/zebra-network/src/protocol/external/codec.rs index 7cee5c19f..d81a0bf29 100644 --- a/zebra-network/src/protocol/external/codec.rs +++ b/zebra-network/src/protocol/external/codec.rs @@ -11,10 +11,11 @@ use tokio_util::codec::{Decoder, Encoder}; use zebra_chain::{ block::{Block, BlockHeaderHash}, serialization::{ - ReadZcashExt, SerializationError as Error, WriteZcashExt, ZcashDeserialize, ZcashSerialize, + sha256d, ReadZcashExt, SerializationError as Error, WriteZcashExt, ZcashDeserialize, + ZcashSerialize, }, transaction::Transaction, - types::{BlockHeight, Sha256dChecksum}, + types::BlockHeight, Network, }; @@ -162,7 +163,7 @@ impl Encoder for Codec { header_writer.write_all(&Magic::from(self.builder.network).0[..])?; header_writer.write_all(command)?; header_writer.write_u32::(body.len() as u32)?; - header_writer.write_all(&Sha256dChecksum::from(&body[..]).0)?; + header_writer.write_all(&sha256d::Checksum::from(&body[..]).0)?; dst.reserve(HEADER_LEN + body.len()); dst.extend_from_slice(&header); @@ -276,7 +277,7 @@ enum DecodeState { Body { body_len: usize, command: [u8; 12], - checksum: Sha256dChecksum, + checksum: sha256d::Checksum, }, } @@ -321,7 +322,7 @@ impl Decoder for Codec { let magic = Magic(header_reader.read_4_bytes()?); let command = header_reader.read_12_bytes()?; let body_len = header_reader.read_u32::()? as usize; - let checksum = Sha256dChecksum(header_reader.read_4_bytes()?); + let checksum = sha256d::Checksum(header_reader.read_4_bytes()?); trace!( ?self.state, ?magic, @@ -371,7 +372,7 @@ impl Decoder for Codec { let body = src.split_to(body_len); self.state = DecodeState::Head; - if checksum != Sha256dChecksum::from(&body[..]) { + if checksum != sha256d::Checksum::from(&body[..]) { return Err(Parse( "supplied message checksum does not match computed checksum", )); @@ -691,29 +692,6 @@ mod tests { }); } - #[test] - fn decode_state_debug() { - assert_eq!(format!("{:?}", DecodeState::Head), "DecodeState::Head"); - - let decode_state = DecodeState::Body { - body_len: 43, - command: [118, 101, 114, 115, 105, 111, 110, 0, 0, 0, 0, 0], - checksum: Sha256dChecksum([186, 250, 162, 227]), - }; - - assert_eq!(format!("{:?}", decode_state), - "DecodeState::Body { body_len: 43, command: \"version\\u{0}\\u{0}\\u{0}\\u{0}\\u{0}\", checksum: Sha256dChecksum(\"bafaa2e3\") }"); - - let decode_state = DecodeState::Body { - body_len: 43, - command: [118, 240, 144, 128, 105, 111, 110, 0, 0, 0, 0, 0], - checksum: Sha256dChecksum([186, 250, 162, 227]), - }; - - assert_eq!(format!("{:?}", decode_state), - "DecodeState::Body { body_len: 43, command: \"v�ion\\u{0}\\u{0}\\u{0}\\u{0}\\u{0}\", checksum: Sha256dChecksum(\"bafaa2e3\") }"); - } - #[test] fn max_msg_size_round_trip() { use std::sync::Arc;