diff --git a/.travis.yml b/.travis.yml index d01a8575..6300003a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,8 +14,8 @@ script: - cargo test --verbose - cargo build --verbose --features=bitcoinconsensus - cargo test --verbose --features=bitcoinconsensus - - cargo build --verbose --features=serde - - cargo test --verbose --features=serde + - cargo build --verbose --features=use-serde + - cargo test --verbose --features=use-serde - cargo build --verbose --features=serde-decimal - cargo test --verbose --features=serde-decimal - if [ "$(rustup show | grep default | grep stable)" != "" ]; then cd fuzz && cargo test --verbose && ./travis-fuzz.sh; fi diff --git a/Cargo.toml b/Cargo.toml index fd294d71..92c78923 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,15 +15,16 @@ name = "bitcoin" path = "src/lib.rs" [features] -fuzztarget = ["secp256k1/fuzztarget"] -serde-decimal = ["serde", "strason"] +fuzztarget = ["secp256k1/fuzztarget", "bitcoin_hashes/fuzztarget"] +serde-decimal = ["use-serde", "strason"] unstable = [] +use-serde = ["serde", "bitcoin_hashes/serde"] [dependencies] bitcoin-bech32 = "0.8.0" byteorder = "1.2" rand = "0.3" -rust-crypto = "0.2" +bitcoin_hashes = "0.3" bitcoinconsensus = { version = "0.16", optional = true } [dependencies.serde] diff --git a/src/blockdata/block.rs b/src/blockdata/block.rs index ca098519..cd81c8f4 100644 --- a/src/blockdata/block.rs +++ b/src/blockdata/block.rs @@ -20,9 +20,11 @@ //! these blocks and the blockchain. //! +use bitcoin_hashes::{sha256d, Hash}; + use util; use util::Error::{SpvBadTarget, SpvBadProofOfWork}; -use util::hash::{BitcoinHash, Sha256dHash}; +use util::hash::BitcoinHash; use util::uint::Uint256; use consensus::encode::VarInt; use network::constants::Network; @@ -36,9 +38,9 @@ pub struct BlockHeader { /// The protocol version. Should always be 1. pub version: u32, /// Reference to the previous block in the chain - pub prev_blockhash: Sha256dHash, + pub prev_blockhash: sha256d::Hash, /// The root hash of the merkle tree of transactions in the block - pub merkle_root: Sha256dHash, + pub merkle_root: sha256d::Hash, /// The timestamp of the block, as claimed by the miner pub time: u32, /// The target value below which the blockhash must lie, encoded as a @@ -120,11 +122,16 @@ impl BlockHeader { /// is correct, but does not verify that the transactions are valid or encoded /// correctly. pub fn spv_validate(&self, required_target: &Uint256) -> Result<(), util::Error> { + use byteorder::{ByteOrder, LittleEndian}; + let target = &self.target(); if target != required_target { return Err(SpvBadTarget); } - let hash = &self.bitcoin_hash().into_le(); + let data: [u8; 32] = self.bitcoin_hash().into_inner(); + let mut ret = [0u64; 4]; + LittleEndian::read_u64_into(&data, &mut ret); + let hash = &Uint256(ret); if hash <= target { Ok(()) } else { Err(SpvBadProofOfWork) } } @@ -141,14 +148,14 @@ impl BlockHeader { } impl BitcoinHash for BlockHeader { - fn bitcoin_hash(&self) -> Sha256dHash { + fn bitcoin_hash(&self) -> sha256d::Hash { use consensus::encode::serialize; - Sha256dHash::from_data(&serialize(self)) + sha256d::Hash::hash(&serialize(self)) } } impl BitcoinHash for Block { - fn bitcoin_hash(&self) -> Sha256dHash { + fn bitcoin_hash(&self) -> sha256d::Hash { self.header.bitcoin_hash() } } diff --git a/src/blockdata/constants.rs b/src/blockdata/constants.rs index 3f0ebcc9..76f040b8 100644 --- a/src/blockdata/constants.rs +++ b/src/blockdata/constants.rs @@ -166,7 +166,7 @@ mod test { assert_eq!(gen.output[0].value, 50 * COIN_VALUE); assert_eq!(gen.lock_time, 0); - assert_eq!(gen.bitcoin_hash().be_hex_string(), + assert_eq!(format!("{:x}", gen.bitcoin_hash()), "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b".to_string()); } @@ -176,12 +176,12 @@ mod test { assert_eq!(gen.header.version, 1); assert_eq!(gen.header.prev_blockhash, Default::default()); - assert_eq!(gen.header.merkle_root.be_hex_string(), + assert_eq!(format!("{:x}", gen.header.merkle_root), "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b".to_string()); assert_eq!(gen.header.time, 1231006505); assert_eq!(gen.header.bits, 0x1d00ffff); assert_eq!(gen.header.nonce, 2083236893); - assert_eq!(gen.header.bitcoin_hash().be_hex_string(), + assert_eq!(format!("{:x}", gen.header.bitcoin_hash()), "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f".to_string()); } @@ -190,12 +190,12 @@ mod test { let gen = genesis_block(Network::Testnet); assert_eq!(gen.header.version, 1); assert_eq!(gen.header.prev_blockhash, Default::default()); - assert_eq!(gen.header.merkle_root.be_hex_string(), + assert_eq!(format!("{:x}", gen.header.merkle_root), "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b".to_string()); assert_eq!(gen.header.time, 1296688602); assert_eq!(gen.header.bits, 0x1d00ffff); assert_eq!(gen.header.nonce, 414098458); - assert_eq!(gen.header.bitcoin_hash().be_hex_string(), + assert_eq!(format!("{:x}", gen.header.bitcoin_hash()), "000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943".to_string()); } } diff --git a/src/blockdata/script.rs b/src/blockdata/script.rs index 8cb1b9e6..a053bc37 100644 --- a/src/blockdata/script.rs +++ b/src/blockdata/script.rs @@ -27,19 +27,15 @@ use std::default::Default; use std::{error, fmt}; -use crypto::digest::Digest; #[cfg(feature = "serde")] use serde; use blockdata::opcodes; use consensus::encode::{Decodable, Encodable}; use consensus::encode::{self, Decoder, Encoder}; -use util::hash::Hash160; +use bitcoin_hashes::{hash160, sha256, Hash}; #[cfg(feature="bitcoinconsensus")] use bitcoinconsensus; #[cfg(feature="bitcoinconsensus")] use std::convert; -#[cfg(feature="bitcoinconsensus")] use util::hash::Sha256dHash; - -#[cfg(feature="fuzztarget")] use fuzz_util::sha2::Sha256; -#[cfg(not(feature="fuzztarget"))] use crypto::sha2::Sha256; +#[cfg(feature="bitcoinconsensus")] use bitcoin_hashes::sha256d; #[derive(Clone, Default, PartialOrd, Ord, PartialEq, Eq, Hash)] /// A Bitcoin script @@ -163,7 +159,7 @@ pub enum Error { BitcoinConsensus(bitcoinconsensus::Error), #[cfg(feature="bitcoinconsensus")] /// Can not find the spent transaction - UnknownSpentTransaction(Sha256dHash), + UnknownSpentTransaction(sha256d::Hash), #[cfg(feature="bitcoinconsensus")] /// The spent transaction does not have the referred output WrongSpentOutputIndex(usize), @@ -305,7 +301,7 @@ impl Script { /// Compute the P2SH output corresponding to this redeem script pub fn to_p2sh(&self) -> Script { Builder::new().push_opcode(opcodes::all::OP_HASH160) - .push_slice(&Hash160::from_data(&self.0)[..]) + .push_slice(&hash160::Hash::hash(&self.0)[..]) .push_opcode(opcodes::all::OP_EQUAL) .into_script() } @@ -313,12 +309,8 @@ impl Script { /// Compute the P2WSH output corresponding to this witnessScript (aka the "witness redeem /// script") pub fn to_v0_p2wsh(&self) -> Script { - let mut tmp = [0; 32]; - let mut sha2 = Sha256::new(); - sha2.input(&self.0); - sha2.result(&mut tmp); Builder::new().push_int(0) - .push_slice(&tmp) + .push_slice(&sha256::Hash::hash(&self.0)[..]) .into_script() } diff --git a/src/blockdata/transaction.rs b/src/blockdata/transaction.rs index 227f87c4..dbe1b111 100644 --- a/src/blockdata/transaction.rs +++ b/src/blockdata/transaction.rs @@ -28,7 +28,10 @@ use std::default::Default; use std::fmt; #[cfg(feature="bitcoinconsensus")] use std::collections::HashMap; -use util::hash::{BitcoinHash, Sha256dHash, HexError}; +use bitcoin_hashes::{self, sha256d, Hash}; +use bitcoin_hashes::hex::FromHex; + +use util::hash::BitcoinHash; #[cfg(feature="bitcoinconsensus")] use blockdata::script; use blockdata::script::Script; use consensus::encode::{self, serialize, Encoder, Decoder}; @@ -38,7 +41,7 @@ use consensus::encode::{Encodable, Decodable, VarInt}; #[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)] pub struct OutPoint { /// The referenced transaction's txid - pub txid: Sha256dHash, + pub txid: sha256d::Hash, /// The index of the referenced output in its transaction's vout pub vout: u32, } @@ -93,7 +96,7 @@ impl fmt::Display for OutPoint { #[derive(Clone, PartialEq, Eq, Debug)] pub enum ParseOutPointError { /// Error in TXID part. - Txid(HexError), + Txid(bitcoin_hashes::Error), /// Error in vout part. Vout(::std::num::ParseIntError), /// Error in general format. @@ -164,7 +167,7 @@ impl ::std::str::FromStr for OutPoint { return Err(ParseOutPointError::Format); } Ok(OutPoint { - txid: Sha256dHash::from_hex(&s[..colon]).map_err(ParseOutPointError::Txid)?, + txid: sha256d::Hash::from_hex(&s[..colon]).map_err(ParseOutPointError::Txid)?, vout: parse_vout(&s[colon+1..])?, }) } @@ -257,7 +260,7 @@ impl Transaction { /// Computes a "normalized TXID" which does not include any signatures. /// This gives a way to identify a transaction that is ``the same'' as /// another in the sense of having same inputs and outputs. - pub fn ntxid(&self) -> Sha256dHash { + pub fn ntxid(&self) -> sha256d::Hash { let cloned_tx = Transaction { version: self.version, lock_time: self.lock_time, @@ -271,15 +274,13 @@ impl Transaction { /// to the output of `BitcoinHash::bitcoin_hash()`, but for segwit transactions, /// this will give the correct txid (not including witnesses) while `bitcoin_hash` /// will also hash witnesses. - pub fn txid(&self) -> Sha256dHash { - use util::hash::Sha256dEncoder; - - let mut enc = Sha256dEncoder::new(); + pub fn txid(&self) -> sha256d::Hash { + let mut enc = sha256d::Hash::engine(); self.version.consensus_encode(&mut enc).unwrap(); self.input.consensus_encode(&mut enc).unwrap(); self.output.consensus_encode(&mut enc).unwrap(); self.lock_time.consensus_encode(&mut enc).unwrap(); - enc.into_hash() + sha256d::Hash::from_engine(enc) } /// Computes a signature hash for a given input index with a given sighash flag. @@ -295,17 +296,17 @@ impl Transaction { /// # Panics /// Panics if `input_index` is greater than or equal to `self.input.len()` /// - pub fn signature_hash(&self, input_index: usize, script_pubkey: &Script, sighash_u32: u32) -> Sha256dHash { + pub fn signature_hash(&self, input_index: usize, script_pubkey: &Script, sighash_u32: u32) -> sha256d::Hash { assert!(input_index < self.input.len()); // Panic on OOB let (sighash, anyone_can_pay) = SigHashType::from_u32(sighash_u32).split_anyonecanpay_flag(); // Special-case sighash_single bug because this is easy enough. if sighash == SigHashType::Single && input_index >= self.output.len() { - return Sha256dHash::from(&[1, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0][..]); + return sha256d::Hash::from_slice(&[1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0]).unwrap(); } // Build tx to sign @@ -350,7 +351,7 @@ impl Transaction { // hash the result let mut raw_vec = serialize(&tx); raw_vec.write_u32::(sighash_u32).unwrap(); - Sha256dHash::from_data(&raw_vec) + sha256d::Hash::hash(&raw_vec) } /// Gets the "weight" of this transaction, as defined by BIP141. For transactions with an empty @@ -397,7 +398,7 @@ impl Transaction { #[cfg(feature="bitcoinconsensus")] /// Verify that this transaction is able to spend some outputs of spent transactions - pub fn verify(&self, spent: &HashMap) -> Result<(), script::Error> { + pub fn verify(&self, spent: &HashMap) -> Result<(), script::Error> { let tx = serialize(&*self); for (idx, input) in self.input.iter().enumerate() { if let Some(ref s) = spent.get(&input.previous_output.txid) { @@ -420,12 +421,10 @@ impl Transaction { } impl BitcoinHash for Transaction { - fn bitcoin_hash(&self) -> Sha256dHash { - use util::hash::Sha256dEncoder; - - let mut enc = Sha256dEncoder::new(); + fn bitcoin_hash(&self) -> sha256d::Hash { + let mut enc = sha256d::Hash::engine(); self.consensus_encode(&mut enc).unwrap(); - enc.into_hash() + sha256d::Hash::from_engine(enc) } } @@ -599,9 +598,12 @@ mod tests { use blockdata::script::Script; use consensus::encode::serialize; use consensus::encode::deserialize; - use util::hash::{BitcoinHash, Sha256dHash}; + use util::hash::BitcoinHash; use util::misc::hex_bytes; + use bitcoin_hashes::{sha256d, Hash}; + use bitcoin_hashes::hex::FromHex; + #[test] fn test_outpoint() { assert_eq!(OutPoint::from_str("i don't care"), @@ -617,20 +619,20 @@ mod tests { assert_eq!(OutPoint::from_str("5df6e0e2761359d30a8275058e299fcc0381534545f55cf43e41983f5d4c9456:+42"), Err(ParseOutPointError::VoutNotCanonical)); assert_eq!(OutPoint::from_str("i don't care:1"), - Err(ParseOutPointError::Txid(Sha256dHash::from_hex("i don't care").unwrap_err()))); + Err(ParseOutPointError::Txid(sha256d::Hash::from_hex("i don't care").unwrap_err()))); assert_eq!(OutPoint::from_str("5df6e0e2761359d30a8275058e299fcc0381534545f55cf43e41983f5d4c945X:1"), - Err(ParseOutPointError::Txid(Sha256dHash::from_hex("5df6e0e2761359d30a8275058e299fcc0381534545f55cf43e41983f5d4c945X").unwrap_err()))); + Err(ParseOutPointError::Txid(sha256d::Hash::from_hex("5df6e0e2761359d30a8275058e299fcc0381534545f55cf43e41983f5d4c945X").unwrap_err()))); assert_eq!(OutPoint::from_str("5df6e0e2761359d30a8275058e299fcc0381534545f55cf43e41983f5d4c9456:lol"), Err(ParseOutPointError::Vout(u32::from_str("lol").unwrap_err()))); assert_eq!(OutPoint::from_str("5df6e0e2761359d30a8275058e299fcc0381534545f55cf43e41983f5d4c9456:42"), Ok(OutPoint{ - txid: Sha256dHash::from_hex("5df6e0e2761359d30a8275058e299fcc0381534545f55cf43e41983f5d4c9456").unwrap(), + txid: sha256d::Hash::from_hex("5df6e0e2761359d30a8275058e299fcc0381534545f55cf43e41983f5d4c9456").unwrap(), vout: 42, })); assert_eq!(OutPoint::from_str("5df6e0e2761359d30a8275058e299fcc0381534545f55cf43e41983f5d4c9456:0"), Ok(OutPoint{ - txid: Sha256dHash::from_hex("5df6e0e2761359d30a8275058e299fcc0381534545f55cf43e41983f5d4c9456").unwrap(), + txid: sha256d::Hash::from_hex("5df6e0e2761359d30a8275058e299fcc0381534545f55cf43e41983f5d4c9456").unwrap(), vout: 0, })); } @@ -665,13 +667,13 @@ mod tests { assert_eq!(realtx.input.len(), 1); // In particular this one is easy to get backward -- in bitcoin hashes are encoded // as little-endian 256-bit numbers rather than as data strings. - assert_eq!(realtx.input[0].previous_output.txid.be_hex_string(), + assert_eq!(format!("{:x}", realtx.input[0].previous_output.txid), "ce9ea9f6f5e422c6a9dbcddb3b9a14d1c78fab9ab520cb281aa2a74a09575da1".to_string()); assert_eq!(realtx.input[0].previous_output.vout, 1); assert_eq!(realtx.output.len(), 1); assert_eq!(realtx.lock_time, 0); - assert_eq!(realtx.bitcoin_hash().be_hex_string(), + assert_eq!(format!("{:x}", realtx.bitcoin_hash()), "a6eab3c14ab5272a58a5ba91505ba1a4b6d7a3a9fcbd187b6cd99a7b6d548cb7".to_string()); assert_eq!(realtx.get_weight(), 193*4); } @@ -696,7 +698,7 @@ mod tests { let mut tx: Transaction = deserialize(&hex_tx).unwrap(); let old_ntxid = tx.ntxid(); - assert_eq!(old_ntxid.be_hex_string(), "c3573dbea28ce24425c59a189391937e00d255150fa973d59d61caf3a06b601d"); + assert_eq!(format!("{:x}", old_ntxid), "c3573dbea28ce24425c59a189391937e00d255150fa973d59d61caf3a06b601d"); // changing sigs does not affect it tx.input[0].script_sig = Script::new(); assert_eq!(old_ntxid, tx.ntxid()); @@ -740,8 +742,8 @@ mod tests { ).unwrap(); let tx: Transaction = deserialize(&hex_tx).unwrap(); - assert_eq!(tx.bitcoin_hash().be_hex_string(), "d6ac4a5e61657c4c604dcde855a1db74ec6b3e54f32695d72c5e11c7761ea1b4"); - assert_eq!(tx.txid().be_hex_string(), "9652aa62b0e748caeec40c4cb7bc17c6792435cc3dfe447dd1ca24f912a1c6ec"); + assert_eq!(format!("{:x}", tx.bitcoin_hash()), "d6ac4a5e61657c4c604dcde855a1db74ec6b3e54f32695d72c5e11c7761ea1b4"); + assert_eq!(format!("{:x}", tx.txid()), "9652aa62b0e748caeec40c4cb7bc17c6792435cc3dfe447dd1ca24f912a1c6ec"); assert_eq!(tx.get_weight(), 2718); // non-segwit tx from my mempool @@ -755,8 +757,8 @@ mod tests { ).unwrap(); let tx: Transaction = deserialize(&hex_tx).unwrap(); - assert_eq!(tx.bitcoin_hash().be_hex_string(), "971ed48a62c143bbd9c87f4bafa2ef213cfa106c6e140f111931d0be307468dd"); - assert_eq!(tx.txid().be_hex_string(), "971ed48a62c143bbd9c87f4bafa2ef213cfa106c6e140f111931d0be307468dd"); + assert_eq!(format!("{:x}", tx.bitcoin_hash()), "971ed48a62c143bbd9c87f4bafa2ef213cfa106c6e140f111931d0be307468dd"); + assert_eq!(format!("{:x}", tx.txid()), "971ed48a62c143bbd9c87f4bafa2ef213cfa106c6e140f111931d0be307468dd"); } #[test] @@ -775,7 +777,7 @@ mod tests { let script = Script::from(hex_bytes(script).unwrap()); let mut raw_expected = hex_bytes(expected_result).unwrap(); raw_expected.reverse(); - let expected_result = Sha256dHash::from(&raw_expected[..]); + let expected_result = sha256d::Hash::from_slice(&raw_expected[..]).unwrap(); let actual_result = tx.signature_hash(input_index, &script, hash_type as u32); assert_eq!(actual_result, expected_result); diff --git a/src/consensus/encode.rs b/src/consensus/encode.rs index 521cd8ee..cdbe2732 100644 --- a/src/consensus/encode.rs +++ b/src/consensus/encode.rs @@ -33,8 +33,6 @@ use std::collections::HashMap; use std::hash::Hash; use std::{mem, u32}; -use util::hash::Sha256dHash; - use std::error; use std::fmt; use std::io; @@ -43,6 +41,7 @@ use byteorder::{LittleEndian, WriteBytesExt, ReadBytesExt}; use hex::encode as hex_encode; use bitcoin_bech32; +use bitcoin_hashes::{sha256d, Hash as HashTrait}; use util::base58; @@ -565,7 +564,7 @@ impl> Decodable for Option { /// Do a double-SHA256 on some data and return the first 4 bytes fn sha2_checksum(data: &[u8]) -> [u8; 4] { - let checksum = Sha256dHash::from_data(data); + let checksum = ::hash(data); [checksum[0], checksum[1], checksum[2], checksum[3]] } @@ -678,7 +677,18 @@ impl Decodable for HashMap } } +impl Encodable for sha256d::Hash { + fn consensus_encode(&self, s: &mut S) -> Result<(), self::Error> { + self.into_inner().consensus_encode(s) + } +} +impl Decodable for sha256d::Hash { + fn consensus_decode(d: &mut D) -> Result { + let inner: [u8; 32] = Decodable::consensus_decode(d)?; + Ok(sha256d::Hash::from_slice(&inner).unwrap()) + } +} // Tests #[cfg(test)] diff --git a/src/fuzz_util/mod.rs b/src/fuzz_util/mod.rs deleted file mode 100644 index bbf67d3d..00000000 --- a/src/fuzz_util/mod.rs +++ /dev/null @@ -1,4 +0,0 @@ -//! This module contains all mocks that are used for fuzz testing. Never use anything from this -//! module in production. - -pub mod sha2; \ No newline at end of file diff --git a/src/fuzz_util/sha2.rs b/src/fuzz_util/sha2.rs deleted file mode 100644 index 40b4e5b4..00000000 --- a/src/fuzz_util/sha2.rs +++ /dev/null @@ -1,63 +0,0 @@ -//! fuzztarget-only Sha2 context with a dummy Sha256 and Sha512 hashers. - -use crypto::digest::Digest; - -#[derive(Clone, Copy)] -/// Dummy Sha256 that hashes the input, but only returns the first byte of output, masking the -/// rest to 0s. -pub struct Sha256 { - state: u8, -} - -impl Sha256 { - /// Constructs a new dummy Sha256 context - pub fn new() -> Sha256 { - Sha256 { - state: 0, - } - } -} - -impl Digest for Sha256 { - fn result(&mut self, data: &mut [u8]) { - data[0] = self.state; - for i in 1..32 { - data[i] = 0; - } - } - - fn input(&mut self, data: &[u8]) { for i in data { self.state ^= i; } } - fn reset(&mut self) { self.state = 0; } - fn output_bits(&self) -> usize { 256 } - fn block_size(&self) -> usize { 64 } -} - -#[derive(Clone, Copy)] -/// Dummy Sha512 that hashes the input, but only returns the first byte of output, masking the -/// rest to 0s. -pub struct Sha512 { - state: u8, -} - -impl Sha512 { - /// Constructs a new dummy Sha512 context - pub fn new() -> Sha512 { - Sha512 { - state: 0xff, - } - } -} - -impl Digest for Sha512 { - fn result(&mut self, data: &mut [u8]) { - data[0] = self.state; - for i in 1..64 { - data[i] = 0; - } - } - - fn input(&mut self, data: &[u8]) { for i in data { self.state ^= i; } } - fn reset(&mut self) { self.state = 0xff; } - fn output_bits(&self) -> usize { 512 } - fn block_size(&self) -> usize { 128 } -} diff --git a/src/internal_macros.rs b/src/internal_macros.rs index 8d5d51fa..afa6b332 100644 --- a/src/internal_macros.rs +++ b/src/internal_macros.rs @@ -38,25 +38,6 @@ macro_rules! impl_consensus_encoding { ); } -macro_rules! impl_newtype_consensus_encoding { - ($thing:ident) => ( - impl ::consensus::encode::Encodable for $thing { - #[inline] - fn consensus_encode(&self, s: &mut S) -> Result<(), ::consensus::encode::Error> { - let &$thing(ref data) = self; - data.consensus_encode(s) - } - } - - impl ::consensus::encode::Decodable for $thing { - #[inline] - fn consensus_decode(d: &mut D) -> Result<$thing, ::consensus::encode::Error> { - Ok($thing(Decodable::consensus_decode(d)?)) - } - } - ); -} - macro_rules! impl_array_newtype { ($thing:ident, $ty:ty, $len:expr) => { impl $thing { @@ -299,7 +280,7 @@ macro_rules! display_from_debug { macro_rules! hex_script (($s:expr) => (::blockdata::script::Script::from(::hex::decode($s).unwrap()))); #[cfg(test)] -macro_rules! hex_hash (($s:expr) => (::util::hash::Sha256dHash::from(&::hex::decode($s).unwrap()[..]))); +macro_rules! hex_hash (($s:expr) => (::bitcoin_hashes::sha256d::Hash::from_slice(&::hex::decode($s).unwrap()).unwrap())); macro_rules! serde_struct_impl { ($name:ident, $($fe:ident),*) => ( diff --git a/src/lib.rs b/src/lib.rs index 362f0591..a4277e93 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -42,8 +42,8 @@ #![deny(missing_docs)] extern crate bitcoin_bech32; +extern crate bitcoin_hashes; extern crate byteorder; -extern crate crypto; extern crate hex; extern crate rand; extern crate secp256k1; @@ -79,6 +79,3 @@ pub use util::hash::BitcoinHash; pub use util::privkey::Privkey; pub use util::decimal::Decimal; pub use util::decimal::UDecimal; - -#[cfg(feature = "fuzztarget")] -pub mod fuzz_util; diff --git a/src/network/message_blockdata.rs b/src/network/message_blockdata.rs index 8c9755f1..67834d86 100644 --- a/src/network/message_blockdata.rs +++ b/src/network/message_blockdata.rs @@ -21,7 +21,7 @@ use network::constants; use consensus::encode::{Decodable, Encodable}; use consensus::encode::{self, Decoder, Encoder}; -use util::hash::Sha256dHash; +use bitcoin_hashes::sha256d; #[derive(PartialEq, Eq, Clone, Debug)] /// The type of an inventory object @@ -48,9 +48,9 @@ pub struct GetBlocksMessage { /// Locator hashes --- ordered newest to oldest. The remote peer will /// reply with its longest known chain, starting from a locator hash /// if possible and block 1 otherwise. - pub locator_hashes: Vec, + pub locator_hashes: Vec, /// References the block to stop at, or zero to just fetch the maximum 500 blocks - pub stop_hash: Sha256dHash + pub stop_hash: sha256d::Hash, } /// The `getheaders` message @@ -61,9 +61,9 @@ pub struct GetHeadersMessage { /// Locator hashes --- ordered newest to oldest. The remote peer will /// reply with its longest known chain, starting from a locator hash /// if possible and block 1 otherwise. - pub locator_hashes: Vec, + pub locator_hashes: Vec, /// References the header to stop at, or zero to just fetch the maximum 2000 headers - pub stop_hash: Sha256dHash + pub stop_hash: sha256d::Hash } /// An inventory object --- a reference to a Bitcoin object @@ -72,12 +72,12 @@ pub struct Inventory { /// The type of object that is referenced pub inv_type: InvType, /// The object's hash - pub hash: Sha256dHash + pub hash: sha256d::Hash } impl GetBlocksMessage { /// Construct a new `getblocks` message - pub fn new(locator_hashes: Vec, stop_hash: Sha256dHash) -> GetBlocksMessage { + pub fn new(locator_hashes: Vec, stop_hash: sha256d::Hash) -> GetBlocksMessage { GetBlocksMessage { version: constants::PROTOCOL_VERSION, locator_hashes: locator_hashes.clone(), @@ -90,7 +90,7 @@ impl_consensus_encoding!(GetBlocksMessage, version, locator_hashes, stop_hash); impl GetHeadersMessage { /// Construct a new `getheaders` message - pub fn new(locator_hashes: Vec, stop_hash: Sha256dHash) -> GetHeadersMessage { + pub fn new(locator_hashes: Vec, stop_hash: sha256d::Hash) -> GetHeadersMessage { GetHeadersMessage { version: constants::PROTOCOL_VERSION, locator_hashes: locator_hashes, diff --git a/src/util/address.rs b/src/util/address.rs index 08787ab3..74ca6a43 100644 --- a/src/util/address.rs +++ b/src/util/address.rs @@ -51,6 +51,7 @@ use std::fmt::{self, Display, Formatter}; use std::str::FromStr; use bitcoin_bech32::{self, WitnessProgram, u5}; +use bitcoin_hashes::{hash160, Hash}; use secp256k1::key::PublicKey; #[cfg(feature = "serde")] @@ -60,7 +61,6 @@ use blockdata::opcodes; use blockdata::script; use network::constants::Network; use consensus::encode; -use util::hash::Hash160; use util::base58; /// The method used to produce an address @@ -69,9 +69,9 @@ pub enum Payload { /// pay-to-pubkey Pubkey(PublicKey), /// pay-to-pkhash address - PubkeyHash(Hash160), + PubkeyHash(hash160::Hash), /// P2SH address - ScriptHash(Hash160), + ScriptHash(hash160::Hash), /// Segwit address WitnessProgram(WitnessProgram), } @@ -92,7 +92,7 @@ impl Address { pub fn p2pkh(pk: &PublicKey, network: Network) -> Address { Address { network: network, - payload: Payload::PubkeyHash(Hash160::from_data(&pk.serialize()[..])) + payload: Payload::PubkeyHash(hash160::Hash::hash(&pk.serialize()[..])) } } @@ -103,7 +103,7 @@ impl Address { pub fn p2upkh(pk: &PublicKey, network: Network) -> Address { Address { network: network, - payload: Payload::PubkeyHash(Hash160::from_data(&pk.serialize_uncompressed()[..])) + payload: Payload::PubkeyHash(hash160::Hash::hash(&pk.serialize_uncompressed()[..])) } } @@ -124,7 +124,7 @@ impl Address { pub fn p2sh(script: &script::Script, network: Network) -> Address { Address { network: network, - payload: Payload::ScriptHash(Hash160::from_data(&script[..])) + payload: Payload::ScriptHash(hash160::Hash::hash(&script[..])) } } @@ -136,7 +136,7 @@ impl Address { payload: Payload::WitnessProgram( // unwrap is safe as witness program is known to be correct as above WitnessProgram::new(u5::try_from_u8(0).expect("0<32"), - Hash160::from_data(&pk.serialize()[..])[..].to_vec(), + hash160::Hash::hash(&pk.serialize()[..])[..].to_vec(), Address::bech_network(network)).unwrap()) } } @@ -146,24 +146,19 @@ impl Address { pub fn p2shwpkh (pk: &PublicKey, network: Network) -> Address { let builder = script::Builder::new() .push_int(0) - .push_slice(&Hash160::from_data(&pk.serialize()[..])[..]); + .push_slice(&hash160::Hash::hash(&pk.serialize()[..])[..]); Address { network: network, payload: Payload::ScriptHash( - Hash160::from_data(builder.into_script().as_bytes()) + hash160::Hash::hash(builder.into_script().as_bytes()) ) } } /// Create a witness pay to script hash address pub fn p2wsh (script: &script::Script, network: Network) -> Address { - use crypto::sha2::Sha256; - use crypto::digest::Digest; - - let mut digest = Sha256::new(); - digest.input(script.as_bytes()); - let mut d = [0u8; 32]; - digest.result(&mut d); + use bitcoin_hashes::sha256; + use bitcoin_hashes::Hash; Address { network: network, @@ -171,7 +166,7 @@ impl Address { // unwrap is safe as witness program is known to be correct as above WitnessProgram::new( u5::try_from_u8(0).expect("0<32"), - d.to_vec(), + sha256::Hash::hash(&script[..])[..].to_vec(), Address::bech_network(network) ).unwrap() ) @@ -181,18 +176,17 @@ impl Address { /// Create a pay to script address that embeds a witness pay to script hash address /// This is a segwit address type that looks familiar (as p2sh) to legacy clients pub fn p2shwsh (script: &script::Script, network: Network) -> Address { - use crypto::sha2::Sha256; - use crypto::digest::Digest; + use bitcoin_hashes::sha256; + use bitcoin_hashes::Hash; + use bitcoin_hashes::hash160; - let mut digest = Sha256::new(); - digest.input(script.as_bytes()); - let mut d = [0u8; 32]; - digest.result(&mut d); - let ws = script::Builder::new().push_int(0).push_slice(&d).into_script(); + let ws = script::Builder::new().push_int(0) + .push_slice(&sha256::Hash::hash(&script[..])[..]) + .into_script(); Address { network: network, - payload: Payload::ScriptHash(Hash160::from_data(ws.as_bytes())) + payload: Payload::ScriptHash(hash160::Hash::hash(&ws[..])) } } @@ -242,7 +236,7 @@ impl Display for Address { match self.payload { // note: serialization for pay-to-pk is defined, but is irreversible Payload::Pubkey(ref pk) => { - let hash = &Hash160::from_data(&pk.serialize_uncompressed()[..]); + let hash = &hash160::Hash::hash(&pk.serialize_uncompressed()[..]); let mut prefixed = [0; 21]; prefixed[0] = match self.network { Network::Bitcoin => 0, @@ -315,19 +309,19 @@ impl FromStr for Address { let (network, payload) = match data[0] { 0 => ( Network::Bitcoin, - Payload::PubkeyHash(Hash160::from(&data[1..])) + Payload::PubkeyHash(hash160::Hash::from_slice(&data[1..]).unwrap()) ), 5 => ( Network::Bitcoin, - Payload::ScriptHash(Hash160::from(&data[1..])) + Payload::ScriptHash(hash160::Hash::from_slice(&data[1..]).unwrap()) ), 111 => ( Network::Testnet, - Payload::PubkeyHash(Hash160::from(&data[1..])) + Payload::PubkeyHash(hash160::Hash::from_slice(&data[1..]).unwrap()) ), 196 => ( Network::Testnet, - Payload::ScriptHash(Hash160::from(&data[1..])) + Payload::ScriptHash(hash160::Hash::from_slice(&data[1..]).unwrap()) ), x => return Err(encode::Error::Base58(base58::Error::InvalidVersion(vec![x]))) }; @@ -403,24 +397,25 @@ mod tests { use std::str::FromStr; use std::string::ToString; + use bitcoin_hashes::{hash160, Hash}; use secp256k1::key::PublicKey; use hex::decode as hex_decode; use blockdata::script::Script; use network::constants::Network::{Bitcoin, Testnet, Regtest}; - use util::hash::Hash160; use super::*; macro_rules! hex (($hex:expr) => (hex_decode($hex).unwrap())); macro_rules! hex_key (($hex:expr) => (PublicKey::from_slice(&hex!($hex)).unwrap())); macro_rules! hex_script (($hex:expr) => (Script::from(hex!($hex)))); + macro_rules! hex_hash160 (($hex:expr) => (hash160::Hash::from_slice(&hex!($hex)).unwrap())); #[test] fn test_p2pkh_address_58() { let addr = Address { network: Bitcoin, payload: Payload::PubkeyHash( - Hash160::from(&hex_decode("162c5ea71c0b23f5b9022ef047c4a86470a5b070").unwrap()[..]) + hex_hash160!("162c5ea71c0b23f5b9022ef047c4a86470a5b070") ) }; @@ -453,7 +448,7 @@ mod tests { let addr = Address { network: Bitcoin, payload: Payload::ScriptHash( - Hash160::from(&hex_decode("162c5ea71c0b23f5b9022ef047c4a86470a5b070").unwrap()[..]) + hex_hash160!("162c5ea71c0b23f5b9022ef047c4a86470a5b070") ) }; diff --git a/src/util/base58.rs b/src/util/base58.rs index 296bef53..8036e8d8 100644 --- a/src/util/base58.rs +++ b/src/util/base58.rs @@ -17,7 +17,8 @@ use std::{error, fmt, str, slice, iter}; use byteorder::{ByteOrder, LittleEndian}; -use util::hash::Sha256dHash; + +use bitcoin_hashes::{sha256d, Hash}; /// An error that might occur during base58 decoding #[derive(Debug, PartialEq, Eq, Clone)] @@ -161,7 +162,7 @@ pub fn from_check(data: &str) -> Result, Error> { return Err(Error::TooShort(ret.len())); } let ck_start = ret.len() - 4; - let expected = Sha256dHash::from_data(&ret[..ck_start]).into_le().low_u32(); + let expected = LittleEndian::read_u32(&sha256d::Hash::hash(&ret[..ck_start])[..4]); let actual = LittleEndian::read_u32(&ret[ck_start..(ck_start + 4)]); if expected != actual { return Err(Error::BadChecksum(expected, actual)); @@ -230,7 +231,7 @@ pub fn encode_slice(data: &[u8]) -> String { /// Obtain a string with the base58check encoding of a slice /// (Tack the first 4 256-digits of the object's Bitcoin hash onto the end.) pub fn check_encode_slice(data: &[u8]) -> String { - let checksum = Sha256dHash::from_data(&data); + let checksum = sha256d::Hash::hash(&data); encode_iter( data.iter() .cloned() @@ -241,7 +242,7 @@ pub fn check_encode_slice(data: &[u8]) -> String { /// Obtain a string with the base58check encoding of a slice /// (Tack the first 4 256-digits of the object's Bitcoin hash onto the end.) pub fn check_encode_slice_to_fmt(fmt: &mut fmt::Formatter, data: &[u8]) -> fmt::Result { - let checksum = Sha256dHash::from_data(&data); + let checksum = sha256d::Hash::hash(&data); let iter = data.iter() .cloned() .chain(checksum[0..4].iter().cloned()); diff --git a/src/util/bip143.rs b/src/util/bip143.rs index 525b4ec5..72712f19 100644 --- a/src/util/bip143.rs +++ b/src/util/bip143.rs @@ -19,10 +19,11 @@ //! signatures, which are placed in the scriptSig. //! +use bitcoin_hashes::{sha256d, Hash}; + use blockdata::script::Script; use blockdata::transaction::{Transaction, TxIn}; use consensus::encode::Encodable; -use util::hash::{Sha256dHash, Sha256dEncoder}; /// Parts of a sighash which are common across inputs or signatures, and which are /// sufficient (in conjunction with a private key) to sign the transaction @@ -31,11 +32,11 @@ pub struct SighashComponents { tx_version: u32, tx_locktime: u32, /// Hash of all the previous outputs - pub hash_prevouts: Sha256dHash, + pub hash_prevouts: sha256d::Hash, /// Hash of all the input sequence nos - pub hash_sequence: Sha256dHash, + pub hash_sequence: sha256d::Hash, /// Hash of all the outputs in this transaction - pub hash_outputs: Sha256dHash, + pub hash_outputs: sha256d::Hash, } impl SighashComponents { @@ -45,27 +46,27 @@ impl SighashComponents { /// script_sig and witnesses. pub fn new(tx: &Transaction) -> SighashComponents { let hash_prevouts = { - let mut enc = Sha256dEncoder::new(); + let mut enc = sha256d::Hash::engine(); for txin in &tx.input { txin.previous_output.consensus_encode(&mut enc).unwrap(); } - enc.into_hash() + sha256d::Hash::from_engine(enc) }; let hash_sequence = { - let mut enc = Sha256dEncoder::new(); + let mut enc = sha256d::Hash::engine(); for txin in &tx.input { txin.sequence.consensus_encode(&mut enc).unwrap(); } - enc.into_hash() + sha256d::Hash::from_engine(enc) }; let hash_outputs = { - let mut enc = Sha256dEncoder::new(); + let mut enc = sha256d::Hash::engine(); for txout in &tx.output { txout.consensus_encode(&mut enc).unwrap(); } - enc.into_hash() + sha256d::Hash::from_engine(enc) }; SighashComponents { @@ -79,8 +80,8 @@ impl SighashComponents { /// Compute the BIP143 sighash for a `SIGHASH_ALL` signature for the given /// input. - pub fn sighash_all(&self, txin: &TxIn, witness_script: &Script, value: u64) -> Sha256dHash { - let mut enc = Sha256dEncoder::new(); + pub fn sighash_all(&self, txin: &TxIn, witness_script: &Script, value: u64) -> sha256d::Hash { + let mut enc = sha256d::Hash::engine(); self.tx_version.consensus_encode(&mut enc).unwrap(); self.hash_prevouts.consensus_encode(&mut enc).unwrap(); self.hash_sequence.consensus_encode(&mut enc).unwrap(); @@ -94,7 +95,7 @@ impl SighashComponents { self.hash_outputs.consensus_encode(&mut enc).unwrap(); self.tx_locktime.consensus_encode(&mut enc).unwrap(); 1u32.consensus_encode(&mut enc).unwrap(); // hashtype - enc.into_hash() + sha256d::Hash::from_engine(enc) } } diff --git a/src/util/bip32.rs b/src/util/bip32.rs index a250dc3a..dc2f6eeb 100644 --- a/src/util/bip32.rs +++ b/src/util/bip32.rs @@ -23,19 +23,13 @@ use std::str::FromStr; #[cfg(feature = "serde")] use serde; use byteorder::{BigEndian, ByteOrder, ReadBytesExt}; -use crypto::digest::Digest; -use crypto::hmac::Hmac; -use crypto::mac::Mac; -use crypto::ripemd160::Ripemd160; +use bitcoin_hashes::{hash160, sha512, Hash, HashEngine, Hmac, HmacEngine}; use secp256k1::key::{PublicKey, SecretKey}; use secp256k1::{self, Secp256k1}; use network::constants::Network; use util::base58; -#[cfg(feature="fuzztarget")] use fuzz_util::sha2::{Sha256, Sha512}; -#[cfg(not(feature="fuzztarget"))] use crypto::sha2::{Sha256, Sha512}; - /// A chain code pub struct ChainCode([u8; 32]); impl_array_newtype!(ChainCode, u8, 32); @@ -49,7 +43,7 @@ impl_array_newtype_show!(Fingerprint); impl_array_newtype_encodable!(Fingerprint, u8, 4); impl Default for Fingerprint { - fn default() -> Fingerprint { Fingerprint([0, 0, 0, 0]) } + fn default() -> Fingerprint { Fingerprint([0; 4]) } } /// Extended private key @@ -237,18 +231,17 @@ impl From for Error { impl ExtendedPrivKey { /// Construct a new master key from a seed value pub fn new_master(network: Network, seed: &[u8]) -> Result { - let mut result = [0; 64]; - let mut hmac = Hmac::new(Sha512::new(), b"Bitcoin seed"); - hmac.input(seed); - hmac.raw_result(&mut result); + let mut hmac_engine: HmacEngine = HmacEngine::new(b"Bitcoin seed"); + hmac_engine.input(seed); + let hmac_result: Hmac = Hmac::from_engine(hmac_engine); Ok(ExtendedPrivKey { network: network, depth: 0, parent_fingerprint: Default::default(), child_number: ChildNumber::from_normal_idx(0), - secret_key: SecretKey::from_slice(&result[..32]).map_err(Error::Ecdsa)?, - chain_code: ChainCode::from(&result[32..]) + secret_key: SecretKey::from_slice(&hmac_result[..32]).map_err(Error::Ecdsa)?, + chain_code: ChainCode::from(&hmac_result[32..]), }) } @@ -267,25 +260,24 @@ impl ExtendedPrivKey { /// Private->Private child key derivation pub fn ckd_priv(&self, secp: &Secp256k1, i: ChildNumber) -> Result { - let mut result = [0; 64]; - let mut hmac = Hmac::new(Sha512::new(), &self.chain_code[..]); + let mut hmac_engine: HmacEngine = HmacEngine::new(&self.chain_code[..]); let mut be_n = [0; 4]; match i { ChildNumber::Normal {..} => { // Non-hardened key: compute public data and use that - hmac.input(&PublicKey::from_secret_key(secp, &self.secret_key).serialize()[..]); + hmac_engine.input(&PublicKey::from_secret_key(secp, &self.secret_key).serialize()[..]); } ChildNumber::Hardened {..} => { // Hardened key: use only secret data to prevent public derivation - hmac.input(&[0u8]); - hmac.input(&self.secret_key[..]); + hmac_engine.input(&[0u8]); + hmac_engine.input(&self.secret_key[..]); } } BigEndian::write_u32(&mut be_n, u32::from(i)); - hmac.input(&be_n); - hmac.raw_result(&mut result); - let mut sk = SecretKey::from_slice(&result[..32]).map_err(Error::Ecdsa)?; + hmac_engine.input(&be_n); + let hmac_result: Hmac = Hmac::from_engine(hmac_engine); + let mut sk = SecretKey::from_slice(&hmac_result[..32]).map_err(Error::Ecdsa)?; sk.add_assign(&self.secret_key[..]).map_err(Error::Ecdsa)?; Ok(ExtendedPrivKey { @@ -294,26 +286,13 @@ impl ExtendedPrivKey { parent_fingerprint: self.fingerprint(secp), child_number: i, secret_key: sk, - chain_code: ChainCode::from(&result[32..]) + chain_code: ChainCode::from(&hmac_result[32..]) }) } /// Returns the HASH160 of the chaincode - pub fn identifier(&self, secp: &Secp256k1) -> [u8; 20] { - let mut sha2_res = [0; 32]; - let mut ripemd_res = [0; 20]; - // Compute extended public key - let pk = ExtendedPubKey::from_private(secp, self); - // Do SHA256 of just the ECDSA pubkey - let mut sha2 = Sha256::new(); - sha2.input(&pk.public_key.serialize()[..]); - sha2.result(&mut sha2_res); - // do RIPEMD160 - let mut ripemd = Ripemd160::new(); - ripemd.input(&sha2_res); - ripemd.result(&mut ripemd_res); - // Return - ripemd_res + pub fn identifier(&self, secp: &Secp256k1) -> hash160::Hash { + ExtendedPubKey::from_private(secp, self).identifier() } /// Returns the first four bytes of the identifier @@ -355,17 +334,16 @@ impl ExtendedPubKey { Err(Error::CannotDeriveFromHardenedKey) } ChildNumber::Normal { index: n } => { - let mut hmac = Hmac::new(Sha512::new(), &self.chain_code[..]); - hmac.input(&self.public_key.serialize()[..]); + let mut hmac_engine: HmacEngine = HmacEngine::new(&self.chain_code[..]); + hmac_engine.input(&self.public_key.serialize()[..]); let mut be_n = [0; 4]; BigEndian::write_u32(&mut be_n, n); - hmac.input(&be_n); + hmac_engine.input(&be_n); - let mut result = [0; 64]; - hmac.raw_result(&mut result); + let hmac_result: Hmac = Hmac::from_engine(hmac_engine); - let secret_key = SecretKey::from_slice(&result[..32])?; - let chain_code = ChainCode::from(&result[32..]); + let secret_key = SecretKey::from_slice(&hmac_result[..32])?; + let chain_code = ChainCode::from(&hmac_result[32..]); Ok((secret_key, chain_code)) } } @@ -392,19 +370,8 @@ impl ExtendedPubKey { } /// Returns the HASH160 of the chaincode - pub fn identifier(&self) -> [u8; 20] { - let mut sha2_res = [0; 32]; - let mut ripemd_res = [0; 20]; - // Do SHA256 of just the ECDSA pubkey - let mut sha2 = Sha256::new(); - sha2.input(&self.public_key.serialize()[..]); - sha2.result(&mut sha2_res); - // do RIPEMD160 - let mut ripemd = Ripemd160::new(); - ripemd.input(&sha2_res); - ripemd.result(&mut ripemd_res); - // Return - ripemd_res + pub fn identifier(&self) -> hash160::Hash { + hash160::Hash::hash(&self.public_key.serialize()) } /// Returns the first four bytes of the identifier diff --git a/src/util/contracthash.rs b/src/util/contracthash.rs index 152da1d5..2bcd5842 100644 --- a/src/util/contracthash.rs +++ b/src/util/contracthash.rs @@ -20,17 +20,13 @@ use secp256k1::{self, Secp256k1}; use secp256k1::key::{PublicKey, SecretKey}; +use bitcoin_hashes::{hash160, sha256, Hash, HashEngine, Hmac, HmacEngine}; use blockdata::{opcodes, script}; -use crypto::hmac; -use crypto::mac::Mac; use std::{error, fmt}; use network::constants::Network; -use util::{address, hash}; - -#[cfg(feature="fuzztarget")] use fuzz_util::sha2; -#[cfg(not(feature="fuzztarget"))] use crypto::sha2; +use util::address; /// Encoding of "pubkey here" in script; from Bitcoin Core `src/script/script.h` static PUBKEY: u8 = 0xFE; @@ -173,11 +169,10 @@ impl<'a> From<&'a [u8]> for Template { pub fn tweak_keys(secp: &Secp256k1, keys: &[PublicKey], contract: &[u8]) -> Result, Error> { let mut ret = Vec::with_capacity(keys.len()); for mut key in keys.iter().cloned() { - let mut hmac_raw = [0; 32]; - let mut hmac = hmac::Hmac::new(sha2::Sha256::new(), &key.serialize()); - hmac.input(contract); - hmac.raw_result(&mut hmac_raw); - let hmac_sk = SecretKey::from_slice(&hmac_raw).map_err(Error::BadTweak)?; + let mut hmac_engine: HmacEngine = HmacEngine::new(&key.serialize()); + hmac_engine.input(contract); + let hmac_result: Hmac = Hmac::from_engine(hmac_engine); + let hmac_sk = SecretKey::from_slice(&hmac_result[..]).map_err(Error::BadTweak)?; key.add_exp_assign(secp, &hmac_sk[..]).map_err(Error::Secp)?; ret.push(key); } @@ -186,11 +181,10 @@ pub fn tweak_keys(secp: &Secp256k1, keys: &[Publi /// Compute a tweak from some given data for the given public key pub fn compute_tweak(pk: &PublicKey, contract: &[u8]) -> Result { - let mut hmac_raw = [0; 32]; - let mut hmac = hmac::Hmac::new(sha2::Sha256::new(), &pk.serialize()); - hmac.input(contract); - hmac.raw_result(&mut hmac_raw); - SecretKey::from_slice(&hmac_raw).map_err(Error::BadTweak) + let mut hmac_engine: HmacEngine = HmacEngine::new(&pk.serialize()); + hmac_engine.input(contract); + let hmac_result: Hmac = Hmac::from_engine(hmac_engine); + SecretKey::from_slice(&hmac_result[..]).map_err(Error::BadTweak) } /// Tweak a secret key using some arbitrary data (calls `compute_tweak` internally) @@ -218,7 +212,7 @@ pub fn create_address(secp: &Secp256k1, Ok(address::Address { network: network, payload: address::Payload::ScriptHash( - hash::Hash160::from_data(&script[..]) + hash160::Hash::hash(&script[..]) ) }) } diff --git a/src/util/hash.rs b/src/util/hash.rs index e0475b2c..1de0f1b5 100644 --- a/src/util/hash.rs +++ b/src/util/hash.rs @@ -15,386 +15,22 @@ //! //! Utility functions related to hashing data, including merkleization -use std::char::from_digit; use std::cmp::min; use std::default::Default; -use std::error; -use std::fmt; -use std::io::{self, Write}; -use std::mem; -#[cfg(feature = "serde")] use serde; -use crypto::digest::Digest; -use crypto::ripemd160::Ripemd160; +use bitcoin_hashes::{sha256d, Hash}; -use consensus::encode::{Encodable, Decodable}; -use util::uint::Uint256; - -#[cfg(feature="fuzztarget")] use fuzz_util::sha2::Sha256; -#[cfg(not(feature="fuzztarget"))] use crypto::sha2::Sha256; -use std::str::FromStr; - -/// Hex deserialization error -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub enum HexError { - /// Length was not 64 characters - BadLength(usize), - /// Non-hex character in string - BadCharacter(char) -} - -impl fmt::Display for HexError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - HexError::BadLength(n) => write!(f, "bad length {} for sha256d hex string", n), - HexError::BadCharacter(c) => write!(f, "bad character {} in sha256d hex string", c) - } - } -} - -impl error::Error for HexError { - fn cause(&self) -> Option<&error::Error> { None } - fn description(&self) -> &str { - match *self { - HexError::BadLength(_) => "sha256d hex string non-64 length", - HexError::BadCharacter(_) => "sha256d bad hex character" - } - } -} - -/// A Bitcoin hash, 32-bytes, computed from x as SHA256(SHA256(x)) -pub struct Sha256dHash([u8; 32]); -impl_array_newtype!(Sha256dHash, u8, 32); - -/// An object that allows serializing data into a sha256d -pub struct Sha256dEncoder(Sha256); - -/// A RIPEMD-160 hash -pub struct Ripemd160Hash([u8; 20]); -impl_array_newtype!(Ripemd160Hash, u8, 20); - -/// A Bitcoin hash160, 20-bytes, computed from x as RIPEMD160(SHA256(x)) -pub struct Hash160([u8; 20]); -impl_array_newtype!(Hash160, u8, 20); - -/// A 32-bit hash obtained by truncating a real hash -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub struct Hash32((u8, u8, u8, u8)); - -/// A 48-bit hash obtained by truncating a real hash -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub struct Hash48((u8, u8, u8, u8, u8, u8)); - -/// A 64-bit hash obtained by truncating a real hash -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub struct Hash64((u8, u8, u8, u8, u8, u8, u8, u8)); - -impl Sha256dEncoder { - /// Create a new encoder - pub fn new() -> Sha256dEncoder { - Sha256dEncoder(Sha256::new()) - } - - /// Extract the hash from an encoder - pub fn into_hash(mut self) -> Sha256dHash { - let mut second_sha = Sha256::new(); - let mut tmp = [0; 32]; - self.0.result(&mut tmp); - second_sha.input(&tmp); - second_sha.result(&mut tmp); - Sha256dHash(tmp) - } -} - -impl Write for Sha256dEncoder { - fn write(&mut self, buf: &[u8]) -> io::Result { - self.0.input(buf); - Ok(buf.len()) - } - - fn flush(&mut self) -> io::Result<()> { - Ok(()) - } -} - -impl Ripemd160Hash { - /// Create a hash by hashing some data - pub fn from_data(data: &[u8]) -> Ripemd160Hash { - let mut ret = [0; 20]; - let mut rmd = Ripemd160::new(); - rmd.input(data); - rmd.result(&mut ret); - Ripemd160Hash(ret) - } -} - -impl Hash160 { - /// Create a hash by hashing some data - pub fn from_data(data: &[u8]) -> Hash160 { - let mut tmp = [0; 32]; - let mut ret = [0; 20]; - let mut sha2 = Sha256::new(); - let mut rmd = Ripemd160::new(); - sha2.input(data); - sha2.result(&mut tmp); - rmd.input(&tmp); - rmd.result(&mut ret); - Hash160(ret) - } -} - -// This doesn't make much sense to me, but is implicit behaviour -// in the C++ reference client, so we need it for consensus. -impl Default for Sha256dHash { - #[inline] - fn default() -> Sha256dHash { Sha256dHash([0u8; 32]) } -} - -impl Sha256dHash { - /// Create a hash by hashing some data - pub fn from_data(data: &[u8]) -> Sha256dHash { - let Sha256dHash(mut ret): Sha256dHash = Default::default(); - let mut sha2 = Sha256::new(); - sha2.input(data); - sha2.result(&mut ret); - sha2.reset(); - sha2.input(&ret); - sha2.result(&mut ret); - Sha256dHash(ret) - } - - /// Converts a hash to a little-endian Uint256 - #[inline] - pub fn into_le(self) -> Uint256 { - let Sha256dHash(data) = self; - let mut ret: [u64; 4] = unsafe { mem::transmute(data) }; - for x in (&mut ret).iter_mut() { *x = x.to_le(); } - Uint256(ret) - } - - /// Converts a hash to a big-endian Uint256 - #[inline] - pub fn into_be(self) -> Uint256 { - let Sha256dHash(mut data) = self; - data.reverse(); - let mut ret: [u64; 4] = unsafe { mem::transmute(data) }; - for x in (&mut ret).iter_mut() { *x = x.to_be(); } - Uint256(ret) - } - - /// Converts a hash to a Hash32 by truncation - #[inline] - pub fn into_hash32(self) -> Hash32 { - let Sha256dHash(data) = self; - unsafe { mem::transmute([data[0], data[8], data[16], data[24]]) } - } - - /// Converts a hash to a Hash48 by truncation - #[inline] - pub fn into_hash48(self) -> Hash48 { - let Sha256dHash(data) = self; - unsafe { mem::transmute([data[0], data[6], data[12], data[18], data[24], data[30]]) } - } - - // Human-readable hex output - - /// Decodes a big-endian (i.e. reversed vs sha256sum output) hex string as a Sha256dHash - #[inline] - pub fn from_hex(s: &str) -> Result { - if s.len() != 64 { - return Err(HexError::BadLength(s.len())); - } - - let bytes = s.as_bytes(); - let mut ret = [0; 32]; - for i in 0..32 { - let hi = match bytes[2*i] { - b @ b'0'...b'9' => (b - b'0') as u8, - b @ b'a'...b'f' => (b - b'a' + 10) as u8, - b @ b'A'...b'F' => (b - b'A' + 10) as u8, - b => return Err(HexError::BadCharacter(b as char)) - }; - let lo = match bytes[2*i + 1] { - b @ b'0'...b'9' => (b - b'0') as u8, - b @ b'a'...b'f' => (b - b'a' + 10) as u8, - b @ b'A'...b'F' => (b - b'A' + 10) as u8, - b => return Err(HexError::BadCharacter(b as char)) - }; - ret[31 - i] = hi * 0x10 + lo; - } - Ok(Sha256dHash(ret)) - } - - /// Converts a hash to a Hash64 by truncation - #[inline] - pub fn into_hash64(self) -> Hash64 { - let Sha256dHash(data) = self; - unsafe { mem::transmute([data[0], data[4], data[8], data[12], - data[16], data[20], data[24], data[28]]) } - } - - /// Human-readable hex output - pub fn le_hex_string(&self) -> String { - let &Sha256dHash(data) = self; - let mut ret = String::with_capacity(64); - for item in data.iter().take(32) { - ret.push(from_digit((*item / 0x10) as u32, 16).unwrap()); - ret.push(from_digit((*item & 0x0f) as u32, 16).unwrap()); - } - ret - } - - /// Human-readable hex output - pub fn be_hex_string(&self) -> String { - let &Sha256dHash(data) = self; - let mut ret = String::with_capacity(64); - for i in (0..32).rev() { - ret.push(from_digit((data[i] / 0x10) as u32, 16).unwrap()); - ret.push(from_digit((data[i] & 0x0f) as u32, 16).unwrap()); - } - ret - } -} - -#[cfg(feature = "serde")] -impl<'de> serde::Deserialize<'de> for Sha256dHash { - #[inline] - fn deserialize(deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - { - use std::fmt::{self, Formatter}; - - struct Visitor; - impl<'de> serde::de::Visitor<'de> for Visitor { - type Value = Sha256dHash; - - fn expecting(&self, formatter: &mut Formatter) -> fmt::Result { - formatter.write_str("a SHA256d hash") - } - - fn visit_str(self, v: &str) -> Result - where - E: serde::de::Error, - { - Sha256dHash::from_hex(v).map_err(E::custom) - } - - fn visit_borrowed_str(self, v: &'de str) -> Result - where - E: serde::de::Error, - { - self.visit_str(v) - } - - fn visit_string(self, v: String) -> Result - where - E: serde::de::Error, - { - self.visit_str(&v) - } - } - - deserializer.deserialize_str(Visitor) - } -} - -#[cfg(feature = "serde")] -impl serde::Serialize for Sha256dHash { - /// Serialize a `Sha256dHash`. - /// - /// Note that this outputs hashes as big endian hex numbers, so this should be - /// used only for user-facing stuff. Internal and network serialization is - /// little-endian and should be done using the consensus - /// [`Encodable`][1] interface. - /// - /// [1]: ../../network/encodable/trait.Encodable.html - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - use std::{char, str}; - - let mut string = [0; 64]; - for i in 0..32 { - string[2 * i] = char::from_digit((self.0[31 - i] / 0x10) as u32, 16).unwrap() as u8; - string[2 * i + 1] = char::from_digit((self.0[31 - i] & 0x0f) as u32, 16).unwrap() as u8; - } - - let hex_str = unsafe { str::from_utf8_unchecked(&string) }; - serializer.serialize_str(hex_str) - } -} - -// Debug encodings -impl fmt::Debug for Sha256dHash { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::LowerHex::fmt(self, f) - } -} - -impl fmt::Debug for Hash160 { - /// Output the raw hash160 hash, not reversing it (nothing reverses the output of ripemd160 in Bitcoin) - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let &Hash160(data) = self; - for ch in data.iter() { - write!(f, "{:02x}", ch)?; - } - Ok(()) - } -} - -// Consensus encoding (no reversing) -impl_newtype_consensus_encoding!(Hash32); -impl_newtype_consensus_encoding!(Hash48); -impl_newtype_consensus_encoding!(Hash64); -impl_newtype_consensus_encoding!(Sha256dHash); - -// User RPC/display encoding (reversed) -impl fmt::Display for Sha256dHash { - /// Output the sha256d hash in reverse, copying Bitcoin Core's behaviour - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::LowerHex::fmt(self, f) } -} - -impl fmt::LowerHex for Sha256dHash { - /// Output the sha256d hash in reverse, copying Bitcoin Core's behaviour - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let &Sha256dHash(data) = self; - for ch in data.iter().rev() { - write!(f, "{:02x}", ch)?; - } - Ok(()) - } -} - -impl fmt::UpperHex for Sha256dHash { - /// Output the sha256d hash in reverse, copying Bitcoin Core's behaviour - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let &Sha256dHash(data) = self; - for ch in data.iter().rev() { - write!(f, "{:02X}", ch)?; - } - Ok(()) - } -} - -impl FromStr for Sha256dHash { - type Err = HexError; - - fn from_str(s: &str) -> Result::Err> { - Sha256dHash::from_hex(s) - } -} +use consensus::encode::Encodable; /// Any collection of objects for which a merkle root makes sense to calculate pub trait MerkleRoot { /// Construct a merkle tree from a collection, with elements ordered as /// they were in the original collection, and return the merkle root. - fn merkle_root(&self) -> Sha256dHash; + fn merkle_root(&self) -> sha256d::Hash; } /// Calculates the merkle root of a list of txids hashes directly -pub fn bitcoin_merkle_root(data: Vec) -> Sha256dHash { +pub fn bitcoin_merkle_root(data: Vec) -> sha256d::Hash { // Base case if data.len() < 1 { return Default::default(); @@ -407,22 +43,22 @@ pub fn bitcoin_merkle_root(data: Vec) -> Sha256dHash { for idx in 0..((data.len() + 1) / 2) { let idx1 = 2 * idx; let idx2 = min(idx1 + 1, data.len() - 1); - let mut encoder = Sha256dEncoder::new(); + let mut encoder = sha256d::Hash::engine(); data[idx1].consensus_encode(&mut encoder).unwrap(); data[idx2].consensus_encode(&mut encoder).unwrap(); - next.push(encoder.into_hash()); + next.push(sha256d::Hash::from_engine(encoder)); } bitcoin_merkle_root(next) } impl<'a, T: BitcoinHash> MerkleRoot for &'a [T] { - fn merkle_root(&self) -> Sha256dHash { + fn merkle_root(&self) -> sha256d::Hash { bitcoin_merkle_root(self.iter().map(|obj| obj.bitcoin_hash()).collect()) } } impl MerkleRoot for Vec { - fn merkle_root(&self) -> Sha256dHash { + fn merkle_root(&self) -> sha256d::Hash { (&self[..]).merkle_root() } } @@ -430,124 +66,5 @@ impl MerkleRoot for Vec { /// Objects which are referred to by hash pub trait BitcoinHash { /// Produces a Sha256dHash which can be used to refer to the object - fn bitcoin_hash(&self) -> Sha256dHash; + fn bitcoin_hash(&self) -> sha256d::Hash; } - -#[cfg(test)] -mod tests { - #[cfg(all(feature = "serde", feature = "strason"))] - use strason::Json; - - use consensus::encode::{Encodable, VarInt}; - use consensus::encode::{serialize, deserialize}; - use util::uint::{Uint128, Uint256}; - use super::*; - - #[test] - fn test_sha256d() { - // nb the 5df6... output is the one you get from sha256sum. this is the - // "little-endian" hex string since it matches the in-memory representation - // of a Uint256 (which is little-endian) after transmutation - assert_eq!(Sha256dHash::from_data(&[]).le_hex_string(), - "5df6e0e2761359d30a8275058e299fcc0381534545f55cf43e41983f5d4c9456"); - assert_eq!(Sha256dHash::from_data(&[]).be_hex_string(), - "56944c5d3f98413ef45cf54545538103cc9f298e0575820ad3591376e2e0f65d"); - - assert_eq!(format!("{}", Sha256dHash::from_data(&[])), - "56944c5d3f98413ef45cf54545538103cc9f298e0575820ad3591376e2e0f65d"); - assert_eq!(format!("{:?}", Sha256dHash::from_data(&[])), - "56944c5d3f98413ef45cf54545538103cc9f298e0575820ad3591376e2e0f65d"); - assert_eq!(format!("{:x}", Sha256dHash::from_data(&[])), - "56944c5d3f98413ef45cf54545538103cc9f298e0575820ad3591376e2e0f65d"); - assert_eq!(format!("{:X}", Sha256dHash::from_data(&[])), - "56944C5D3F98413EF45CF54545538103CC9F298E0575820AD3591376E2E0F65D"); - } - - #[test] - fn sha256d_from_str_parses_from_human_readable_hex() { - - let human_readable_hex_tx_id = "56944c5d3f98413ef45cf54545538103cc9f298e0575820ad3591376e2e0f65d"; - - let from_hex = Sha256dHash::from_hex(human_readable_hex_tx_id).unwrap(); - let from_str = human_readable_hex_tx_id.parse().unwrap(); - - assert_eq!(from_hex, from_str) - } - - #[test] - fn test_sha256d_data() { - assert_eq!( - Sha256dHash::from_data(&[]).as_bytes(), - &[ - 0x5d, 0xf6, 0xe0, 0xe2, 0x76, 0x13, 0x59, 0xd3, 0x0a, 0x82, 0x75, 0x05, 0x8e, 0x29, - 0x9f, 0xcc, 0x03, 0x81, 0x53, 0x45, 0x45, 0xf5, 0x5c, 0xf4, 0x3e, 0x41, 0x98, 0x3f, - 0x5d, 0x4c, 0x94, 0x56, - ] - ); - } - - #[test] - fn sha256d_encoder() { - let test = vec![true, false, true, true, false]; - let mut enc = Sha256dEncoder::new(); - assert!(test.consensus_encode(&mut enc).is_ok()); - assert_eq!(enc.into_hash(), Sha256dHash::from_data(&serialize(&test))); - - macro_rules! array_encode_test ( - ($ty:ty) => ({ - // try serializing the whole array - let test: [$ty; 1000] = [1; 1000]; - let mut enc = Sha256dEncoder::new(); - assert!((&test[..]).consensus_encode(&mut enc).is_ok()); - assert_eq!(enc.into_hash(), Sha256dHash::from_data(&serialize(&test[..]))); - - // try doing it just one object at a time - let mut enc = Sha256dEncoder::new(); - assert!(VarInt(test.len() as u64).consensus_encode(&mut enc).is_ok()); - for obj in &test[..] { - assert!(obj.consensus_encode(&mut enc).is_ok()); - } - assert_eq!(enc.into_hash(), Sha256dHash::from_data(&serialize(&test[..]))); - }) - ); - - array_encode_test!(u64); - array_encode_test!(u32); - array_encode_test!(u16); - array_encode_test!(u8); - array_encode_test!(i64); - array_encode_test!(i32); - array_encode_test!(i16); - array_encode_test!(i8); - } - - #[test] - fn test_consenus_encode_roundtrip() { - let hash = Sha256dHash::from_data(&[]); - let serial = serialize(&hash); - let deserial = deserialize(&serial).unwrap(); - assert_eq!(hash, deserial); - } - - #[test] - #[cfg(all(feature = "serde", feature = "strason"))] - fn test_hash_encode_decode() { - let hash = Sha256dHash::from_data(&[]); - let encoded = Json::from_serialize(&hash).unwrap(); - assert_eq!(encoded.to_bytes(), - "\"56944c5d3f98413ef45cf54545538103cc9f298e0575820ad3591376e2e0f65d\"".as_bytes()); - let decoded = encoded.into_deserialize().unwrap(); - assert_eq!(hash, decoded); - } - - #[test] - fn test_sighash_single_vec() { - let one = Sha256dHash([1, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0]); - assert_eq!(Some(one.into_le()), Uint256::from_u64(1)); - assert_eq!(Some(one.into_le().low_128()), Uint128::from_u64(1)); - } -} -