Merge pull request #215 from dongcarl/2018-12-integrate-bitcoin-hashes
Integrate bitcoin_hashes, remove rust-crypto and fuzz_util
This commit is contained in:
commit
51aba8bb21
|
@ -14,8 +14,8 @@ script:
|
||||||
- cargo test --verbose
|
- cargo test --verbose
|
||||||
- cargo build --verbose --features=bitcoinconsensus
|
- cargo build --verbose --features=bitcoinconsensus
|
||||||
- cargo test --verbose --features=bitcoinconsensus
|
- cargo test --verbose --features=bitcoinconsensus
|
||||||
- cargo build --verbose --features=serde
|
- cargo build --verbose --features=use-serde
|
||||||
- cargo test --verbose --features=serde
|
- cargo test --verbose --features=use-serde
|
||||||
- cargo build --verbose --features=serde-decimal
|
- cargo build --verbose --features=serde-decimal
|
||||||
- cargo test --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
|
- if [ "$(rustup show | grep default | grep stable)" != "" ]; then cd fuzz && cargo test --verbose && ./travis-fuzz.sh; fi
|
||||||
|
|
|
@ -15,15 +15,16 @@ name = "bitcoin"
|
||||||
path = "src/lib.rs"
|
path = "src/lib.rs"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
fuzztarget = ["secp256k1/fuzztarget"]
|
fuzztarget = ["secp256k1/fuzztarget", "bitcoin_hashes/fuzztarget"]
|
||||||
serde-decimal = ["serde", "strason"]
|
serde-decimal = ["use-serde", "strason"]
|
||||||
unstable = []
|
unstable = []
|
||||||
|
use-serde = ["serde", "bitcoin_hashes/serde"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
bitcoin-bech32 = "0.8.0"
|
bitcoin-bech32 = "0.8.0"
|
||||||
byteorder = "1.2"
|
byteorder = "1.2"
|
||||||
rand = "0.3"
|
rand = "0.3"
|
||||||
rust-crypto = "0.2"
|
bitcoin_hashes = "0.3"
|
||||||
bitcoinconsensus = { version = "0.16", optional = true }
|
bitcoinconsensus = { version = "0.16", optional = true }
|
||||||
|
|
||||||
[dependencies.serde]
|
[dependencies.serde]
|
||||||
|
|
|
@ -20,9 +20,11 @@
|
||||||
//! these blocks and the blockchain.
|
//! these blocks and the blockchain.
|
||||||
//!
|
//!
|
||||||
|
|
||||||
|
use bitcoin_hashes::{sha256d, Hash};
|
||||||
|
|
||||||
use util;
|
use util;
|
||||||
use util::Error::{SpvBadTarget, SpvBadProofOfWork};
|
use util::Error::{SpvBadTarget, SpvBadProofOfWork};
|
||||||
use util::hash::{BitcoinHash, Sha256dHash};
|
use util::hash::BitcoinHash;
|
||||||
use util::uint::Uint256;
|
use util::uint::Uint256;
|
||||||
use consensus::encode::VarInt;
|
use consensus::encode::VarInt;
|
||||||
use network::constants::Network;
|
use network::constants::Network;
|
||||||
|
@ -36,9 +38,9 @@ pub struct BlockHeader {
|
||||||
/// The protocol version. Should always be 1.
|
/// The protocol version. Should always be 1.
|
||||||
pub version: u32,
|
pub version: u32,
|
||||||
/// Reference to the previous block in the chain
|
/// 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
|
/// 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
|
/// The timestamp of the block, as claimed by the miner
|
||||||
pub time: u32,
|
pub time: u32,
|
||||||
/// The target value below which the blockhash must lie, encoded as a
|
/// 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
|
/// is correct, but does not verify that the transactions are valid or encoded
|
||||||
/// correctly.
|
/// correctly.
|
||||||
pub fn spv_validate(&self, required_target: &Uint256) -> Result<(), util::Error> {
|
pub fn spv_validate(&self, required_target: &Uint256) -> Result<(), util::Error> {
|
||||||
|
use byteorder::{ByteOrder, LittleEndian};
|
||||||
|
|
||||||
let target = &self.target();
|
let target = &self.target();
|
||||||
if target != required_target {
|
if target != required_target {
|
||||||
return Err(SpvBadTarget);
|
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) }
|
if hash <= target { Ok(()) } else { Err(SpvBadProofOfWork) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -141,14 +148,14 @@ impl BlockHeader {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BitcoinHash for BlockHeader {
|
impl BitcoinHash for BlockHeader {
|
||||||
fn bitcoin_hash(&self) -> Sha256dHash {
|
fn bitcoin_hash(&self) -> sha256d::Hash {
|
||||||
use consensus::encode::serialize;
|
use consensus::encode::serialize;
|
||||||
Sha256dHash::from_data(&serialize(self))
|
sha256d::Hash::hash(&serialize(self))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BitcoinHash for Block {
|
impl BitcoinHash for Block {
|
||||||
fn bitcoin_hash(&self) -> Sha256dHash {
|
fn bitcoin_hash(&self) -> sha256d::Hash {
|
||||||
self.header.bitcoin_hash()
|
self.header.bitcoin_hash()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -166,7 +166,7 @@ mod test {
|
||||||
assert_eq!(gen.output[0].value, 50 * COIN_VALUE);
|
assert_eq!(gen.output[0].value, 50 * COIN_VALUE);
|
||||||
assert_eq!(gen.lock_time, 0);
|
assert_eq!(gen.lock_time, 0);
|
||||||
|
|
||||||
assert_eq!(gen.bitcoin_hash().be_hex_string(),
|
assert_eq!(format!("{:x}", gen.bitcoin_hash()),
|
||||||
"4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b".to_string());
|
"4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b".to_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -176,12 +176,12 @@ mod test {
|
||||||
|
|
||||||
assert_eq!(gen.header.version, 1);
|
assert_eq!(gen.header.version, 1);
|
||||||
assert_eq!(gen.header.prev_blockhash, Default::default());
|
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());
|
"4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b".to_string());
|
||||||
assert_eq!(gen.header.time, 1231006505);
|
assert_eq!(gen.header.time, 1231006505);
|
||||||
assert_eq!(gen.header.bits, 0x1d00ffff);
|
assert_eq!(gen.header.bits, 0x1d00ffff);
|
||||||
assert_eq!(gen.header.nonce, 2083236893);
|
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());
|
"000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f".to_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -190,12 +190,12 @@ mod test {
|
||||||
let gen = genesis_block(Network::Testnet);
|
let gen = genesis_block(Network::Testnet);
|
||||||
assert_eq!(gen.header.version, 1);
|
assert_eq!(gen.header.version, 1);
|
||||||
assert_eq!(gen.header.prev_blockhash, Default::default());
|
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());
|
"4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b".to_string());
|
||||||
assert_eq!(gen.header.time, 1296688602);
|
assert_eq!(gen.header.time, 1296688602);
|
||||||
assert_eq!(gen.header.bits, 0x1d00ffff);
|
assert_eq!(gen.header.bits, 0x1d00ffff);
|
||||||
assert_eq!(gen.header.nonce, 414098458);
|
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());
|
"000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943".to_string());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,19 +27,15 @@
|
||||||
use std::default::Default;
|
use std::default::Default;
|
||||||
use std::{error, fmt};
|
use std::{error, fmt};
|
||||||
|
|
||||||
use crypto::digest::Digest;
|
|
||||||
#[cfg(feature = "serde")] use serde;
|
#[cfg(feature = "serde")] use serde;
|
||||||
|
|
||||||
use blockdata::opcodes;
|
use blockdata::opcodes;
|
||||||
use consensus::encode::{Decodable, Encodable};
|
use consensus::encode::{Decodable, Encodable};
|
||||||
use consensus::encode::{self, Decoder, Encoder};
|
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 bitcoinconsensus;
|
||||||
#[cfg(feature="bitcoinconsensus")] use std::convert;
|
#[cfg(feature="bitcoinconsensus")] use std::convert;
|
||||||
#[cfg(feature="bitcoinconsensus")] use util::hash::Sha256dHash;
|
#[cfg(feature="bitcoinconsensus")] use bitcoin_hashes::sha256d;
|
||||||
|
|
||||||
#[cfg(feature="fuzztarget")] use fuzz_util::sha2::Sha256;
|
|
||||||
#[cfg(not(feature="fuzztarget"))] use crypto::sha2::Sha256;
|
|
||||||
|
|
||||||
#[derive(Clone, Default, PartialOrd, Ord, PartialEq, Eq, Hash)]
|
#[derive(Clone, Default, PartialOrd, Ord, PartialEq, Eq, Hash)]
|
||||||
/// A Bitcoin script
|
/// A Bitcoin script
|
||||||
|
@ -163,7 +159,7 @@ pub enum Error {
|
||||||
BitcoinConsensus(bitcoinconsensus::Error),
|
BitcoinConsensus(bitcoinconsensus::Error),
|
||||||
#[cfg(feature="bitcoinconsensus")]
|
#[cfg(feature="bitcoinconsensus")]
|
||||||
/// Can not find the spent transaction
|
/// Can not find the spent transaction
|
||||||
UnknownSpentTransaction(Sha256dHash),
|
UnknownSpentTransaction(sha256d::Hash),
|
||||||
#[cfg(feature="bitcoinconsensus")]
|
#[cfg(feature="bitcoinconsensus")]
|
||||||
/// The spent transaction does not have the referred output
|
/// The spent transaction does not have the referred output
|
||||||
WrongSpentOutputIndex(usize),
|
WrongSpentOutputIndex(usize),
|
||||||
|
@ -305,7 +301,7 @@ impl Script {
|
||||||
/// Compute the P2SH output corresponding to this redeem script
|
/// Compute the P2SH output corresponding to this redeem script
|
||||||
pub fn to_p2sh(&self) -> Script {
|
pub fn to_p2sh(&self) -> Script {
|
||||||
Builder::new().push_opcode(opcodes::all::OP_HASH160)
|
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)
|
.push_opcode(opcodes::all::OP_EQUAL)
|
||||||
.into_script()
|
.into_script()
|
||||||
}
|
}
|
||||||
|
@ -313,12 +309,8 @@ impl Script {
|
||||||
/// Compute the P2WSH output corresponding to this witnessScript (aka the "witness redeem
|
/// Compute the P2WSH output corresponding to this witnessScript (aka the "witness redeem
|
||||||
/// script")
|
/// script")
|
||||||
pub fn to_v0_p2wsh(&self) -> 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)
|
Builder::new().push_int(0)
|
||||||
.push_slice(&tmp)
|
.push_slice(&sha256::Hash::hash(&self.0)[..])
|
||||||
.into_script()
|
.into_script()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,10 @@ use std::default::Default;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
#[cfg(feature="bitcoinconsensus")] use std::collections::HashMap;
|
#[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;
|
#[cfg(feature="bitcoinconsensus")] use blockdata::script;
|
||||||
use blockdata::script::Script;
|
use blockdata::script::Script;
|
||||||
use consensus::encode::{self, serialize, Encoder, Decoder};
|
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)]
|
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
|
||||||
pub struct OutPoint {
|
pub struct OutPoint {
|
||||||
/// The referenced transaction's txid
|
/// The referenced transaction's txid
|
||||||
pub txid: Sha256dHash,
|
pub txid: sha256d::Hash,
|
||||||
/// The index of the referenced output in its transaction's vout
|
/// The index of the referenced output in its transaction's vout
|
||||||
pub vout: u32,
|
pub vout: u32,
|
||||||
}
|
}
|
||||||
|
@ -93,7 +96,7 @@ impl fmt::Display for OutPoint {
|
||||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||||
pub enum ParseOutPointError {
|
pub enum ParseOutPointError {
|
||||||
/// Error in TXID part.
|
/// Error in TXID part.
|
||||||
Txid(HexError),
|
Txid(bitcoin_hashes::Error),
|
||||||
/// Error in vout part.
|
/// Error in vout part.
|
||||||
Vout(::std::num::ParseIntError),
|
Vout(::std::num::ParseIntError),
|
||||||
/// Error in general format.
|
/// Error in general format.
|
||||||
|
@ -164,7 +167,7 @@ impl ::std::str::FromStr for OutPoint {
|
||||||
return Err(ParseOutPointError::Format);
|
return Err(ParseOutPointError::Format);
|
||||||
}
|
}
|
||||||
Ok(OutPoint {
|
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..])?,
|
vout: parse_vout(&s[colon+1..])?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -257,7 +260,7 @@ impl Transaction {
|
||||||
/// Computes a "normalized TXID" which does not include any signatures.
|
/// Computes a "normalized TXID" which does not include any signatures.
|
||||||
/// This gives a way to identify a transaction that is ``the same'' as
|
/// This gives a way to identify a transaction that is ``the same'' as
|
||||||
/// another in the sense of having same inputs and outputs.
|
/// 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 {
|
let cloned_tx = Transaction {
|
||||||
version: self.version,
|
version: self.version,
|
||||||
lock_time: self.lock_time,
|
lock_time: self.lock_time,
|
||||||
|
@ -271,15 +274,13 @@ impl Transaction {
|
||||||
/// to the output of `BitcoinHash::bitcoin_hash()`, but for segwit transactions,
|
/// to the output of `BitcoinHash::bitcoin_hash()`, but for segwit transactions,
|
||||||
/// this will give the correct txid (not including witnesses) while `bitcoin_hash`
|
/// this will give the correct txid (not including witnesses) while `bitcoin_hash`
|
||||||
/// will also hash witnesses.
|
/// will also hash witnesses.
|
||||||
pub fn txid(&self) -> Sha256dHash {
|
pub fn txid(&self) -> sha256d::Hash {
|
||||||
use util::hash::Sha256dEncoder;
|
let mut enc = sha256d::Hash::engine();
|
||||||
|
|
||||||
let mut enc = Sha256dEncoder::new();
|
|
||||||
self.version.consensus_encode(&mut enc).unwrap();
|
self.version.consensus_encode(&mut enc).unwrap();
|
||||||
self.input.consensus_encode(&mut enc).unwrap();
|
self.input.consensus_encode(&mut enc).unwrap();
|
||||||
self.output.consensus_encode(&mut enc).unwrap();
|
self.output.consensus_encode(&mut enc).unwrap();
|
||||||
self.lock_time.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.
|
/// Computes a signature hash for a given input index with a given sighash flag.
|
||||||
|
@ -295,17 +296,17 @@ impl Transaction {
|
||||||
/// # Panics
|
/// # Panics
|
||||||
/// Panics if `input_index` is greater than or equal to `self.input.len()`
|
/// 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
|
assert!(input_index < self.input.len()); // Panic on OOB
|
||||||
|
|
||||||
let (sighash, anyone_can_pay) = SigHashType::from_u32(sighash_u32).split_anyonecanpay_flag();
|
let (sighash, anyone_can_pay) = SigHashType::from_u32(sighash_u32).split_anyonecanpay_flag();
|
||||||
|
|
||||||
// Special-case sighash_single bug because this is easy enough.
|
// Special-case sighash_single bug because this is easy enough.
|
||||||
if sighash == SigHashType::Single && input_index >= self.output.len() {
|
if sighash == SigHashType::Single && input_index >= self.output.len() {
|
||||||
return Sha256dHash::from(&[1, 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,
|
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
|
// Build tx to sign
|
||||||
|
@ -350,7 +351,7 @@ impl Transaction {
|
||||||
// hash the result
|
// hash the result
|
||||||
let mut raw_vec = serialize(&tx);
|
let mut raw_vec = serialize(&tx);
|
||||||
raw_vec.write_u32::<LittleEndian>(sighash_u32).unwrap();
|
raw_vec.write_u32::<LittleEndian>(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
|
/// Gets the "weight" of this transaction, as defined by BIP141. For transactions with an empty
|
||||||
|
@ -397,7 +398,7 @@ impl Transaction {
|
||||||
|
|
||||||
#[cfg(feature="bitcoinconsensus")]
|
#[cfg(feature="bitcoinconsensus")]
|
||||||
/// Verify that this transaction is able to spend some outputs of spent transactions
|
/// Verify that this transaction is able to spend some outputs of spent transactions
|
||||||
pub fn verify(&self, spent: &HashMap<Sha256dHash, Transaction>) -> Result<(), script::Error> {
|
pub fn verify(&self, spent: &HashMap<sha256d::Hash, Transaction>) -> Result<(), script::Error> {
|
||||||
let tx = serialize(&*self);
|
let tx = serialize(&*self);
|
||||||
for (idx, input) in self.input.iter().enumerate() {
|
for (idx, input) in self.input.iter().enumerate() {
|
||||||
if let Some(ref s) = spent.get(&input.previous_output.txid) {
|
if let Some(ref s) = spent.get(&input.previous_output.txid) {
|
||||||
|
@ -420,12 +421,10 @@ impl Transaction {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BitcoinHash for Transaction {
|
impl BitcoinHash for Transaction {
|
||||||
fn bitcoin_hash(&self) -> Sha256dHash {
|
fn bitcoin_hash(&self) -> sha256d::Hash {
|
||||||
use util::hash::Sha256dEncoder;
|
let mut enc = sha256d::Hash::engine();
|
||||||
|
|
||||||
let mut enc = Sha256dEncoder::new();
|
|
||||||
self.consensus_encode(&mut enc).unwrap();
|
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 blockdata::script::Script;
|
||||||
use consensus::encode::serialize;
|
use consensus::encode::serialize;
|
||||||
use consensus::encode::deserialize;
|
use consensus::encode::deserialize;
|
||||||
use util::hash::{BitcoinHash, Sha256dHash};
|
use util::hash::BitcoinHash;
|
||||||
use util::misc::hex_bytes;
|
use util::misc::hex_bytes;
|
||||||
|
|
||||||
|
use bitcoin_hashes::{sha256d, Hash};
|
||||||
|
use bitcoin_hashes::hex::FromHex;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_outpoint() {
|
fn test_outpoint() {
|
||||||
assert_eq!(OutPoint::from_str("i don't care"),
|
assert_eq!(OutPoint::from_str("i don't care"),
|
||||||
|
@ -617,20 +619,20 @@ mod tests {
|
||||||
assert_eq!(OutPoint::from_str("5df6e0e2761359d30a8275058e299fcc0381534545f55cf43e41983f5d4c9456:+42"),
|
assert_eq!(OutPoint::from_str("5df6e0e2761359d30a8275058e299fcc0381534545f55cf43e41983f5d4c9456:+42"),
|
||||||
Err(ParseOutPointError::VoutNotCanonical));
|
Err(ParseOutPointError::VoutNotCanonical));
|
||||||
assert_eq!(OutPoint::from_str("i don't care:1"),
|
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"),
|
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"),
|
assert_eq!(OutPoint::from_str("5df6e0e2761359d30a8275058e299fcc0381534545f55cf43e41983f5d4c9456:lol"),
|
||||||
Err(ParseOutPointError::Vout(u32::from_str("lol").unwrap_err())));
|
Err(ParseOutPointError::Vout(u32::from_str("lol").unwrap_err())));
|
||||||
|
|
||||||
assert_eq!(OutPoint::from_str("5df6e0e2761359d30a8275058e299fcc0381534545f55cf43e41983f5d4c9456:42"),
|
assert_eq!(OutPoint::from_str("5df6e0e2761359d30a8275058e299fcc0381534545f55cf43e41983f5d4c9456:42"),
|
||||||
Ok(OutPoint{
|
Ok(OutPoint{
|
||||||
txid: Sha256dHash::from_hex("5df6e0e2761359d30a8275058e299fcc0381534545f55cf43e41983f5d4c9456").unwrap(),
|
txid: sha256d::Hash::from_hex("5df6e0e2761359d30a8275058e299fcc0381534545f55cf43e41983f5d4c9456").unwrap(),
|
||||||
vout: 42,
|
vout: 42,
|
||||||
}));
|
}));
|
||||||
assert_eq!(OutPoint::from_str("5df6e0e2761359d30a8275058e299fcc0381534545f55cf43e41983f5d4c9456:0"),
|
assert_eq!(OutPoint::from_str("5df6e0e2761359d30a8275058e299fcc0381534545f55cf43e41983f5d4c9456:0"),
|
||||||
Ok(OutPoint{
|
Ok(OutPoint{
|
||||||
txid: Sha256dHash::from_hex("5df6e0e2761359d30a8275058e299fcc0381534545f55cf43e41983f5d4c9456").unwrap(),
|
txid: sha256d::Hash::from_hex("5df6e0e2761359d30a8275058e299fcc0381534545f55cf43e41983f5d4c9456").unwrap(),
|
||||||
vout: 0,
|
vout: 0,
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
@ -665,13 +667,13 @@ mod tests {
|
||||||
assert_eq!(realtx.input.len(), 1);
|
assert_eq!(realtx.input.len(), 1);
|
||||||
// In particular this one is easy to get backward -- in bitcoin hashes are encoded
|
// 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.
|
// 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());
|
"ce9ea9f6f5e422c6a9dbcddb3b9a14d1c78fab9ab520cb281aa2a74a09575da1".to_string());
|
||||||
assert_eq!(realtx.input[0].previous_output.vout, 1);
|
assert_eq!(realtx.input[0].previous_output.vout, 1);
|
||||||
assert_eq!(realtx.output.len(), 1);
|
assert_eq!(realtx.output.len(), 1);
|
||||||
assert_eq!(realtx.lock_time, 0);
|
assert_eq!(realtx.lock_time, 0);
|
||||||
|
|
||||||
assert_eq!(realtx.bitcoin_hash().be_hex_string(),
|
assert_eq!(format!("{:x}", realtx.bitcoin_hash()),
|
||||||
"a6eab3c14ab5272a58a5ba91505ba1a4b6d7a3a9fcbd187b6cd99a7b6d548cb7".to_string());
|
"a6eab3c14ab5272a58a5ba91505ba1a4b6d7a3a9fcbd187b6cd99a7b6d548cb7".to_string());
|
||||||
assert_eq!(realtx.get_weight(), 193*4);
|
assert_eq!(realtx.get_weight(), 193*4);
|
||||||
}
|
}
|
||||||
|
@ -696,7 +698,7 @@ mod tests {
|
||||||
let mut tx: Transaction = deserialize(&hex_tx).unwrap();
|
let mut tx: Transaction = deserialize(&hex_tx).unwrap();
|
||||||
|
|
||||||
let old_ntxid = tx.ntxid();
|
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
|
// changing sigs does not affect it
|
||||||
tx.input[0].script_sig = Script::new();
|
tx.input[0].script_sig = Script::new();
|
||||||
assert_eq!(old_ntxid, tx.ntxid());
|
assert_eq!(old_ntxid, tx.ntxid());
|
||||||
|
@ -740,8 +742,8 @@ mod tests {
|
||||||
).unwrap();
|
).unwrap();
|
||||||
let tx: Transaction = deserialize(&hex_tx).unwrap();
|
let tx: Transaction = deserialize(&hex_tx).unwrap();
|
||||||
|
|
||||||
assert_eq!(tx.bitcoin_hash().be_hex_string(), "d6ac4a5e61657c4c604dcde855a1db74ec6b3e54f32695d72c5e11c7761ea1b4");
|
assert_eq!(format!("{:x}", tx.bitcoin_hash()), "d6ac4a5e61657c4c604dcde855a1db74ec6b3e54f32695d72c5e11c7761ea1b4");
|
||||||
assert_eq!(tx.txid().be_hex_string(), "9652aa62b0e748caeec40c4cb7bc17c6792435cc3dfe447dd1ca24f912a1c6ec");
|
assert_eq!(format!("{:x}", tx.txid()), "9652aa62b0e748caeec40c4cb7bc17c6792435cc3dfe447dd1ca24f912a1c6ec");
|
||||||
assert_eq!(tx.get_weight(), 2718);
|
assert_eq!(tx.get_weight(), 2718);
|
||||||
|
|
||||||
// non-segwit tx from my mempool
|
// non-segwit tx from my mempool
|
||||||
|
@ -755,8 +757,8 @@ mod tests {
|
||||||
).unwrap();
|
).unwrap();
|
||||||
let tx: Transaction = deserialize(&hex_tx).unwrap();
|
let tx: Transaction = deserialize(&hex_tx).unwrap();
|
||||||
|
|
||||||
assert_eq!(tx.bitcoin_hash().be_hex_string(), "971ed48a62c143bbd9c87f4bafa2ef213cfa106c6e140f111931d0be307468dd");
|
assert_eq!(format!("{:x}", tx.bitcoin_hash()), "971ed48a62c143bbd9c87f4bafa2ef213cfa106c6e140f111931d0be307468dd");
|
||||||
assert_eq!(tx.txid().be_hex_string(), "971ed48a62c143bbd9c87f4bafa2ef213cfa106c6e140f111931d0be307468dd");
|
assert_eq!(format!("{:x}", tx.txid()), "971ed48a62c143bbd9c87f4bafa2ef213cfa106c6e140f111931d0be307468dd");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -775,7 +777,7 @@ mod tests {
|
||||||
let script = Script::from(hex_bytes(script).unwrap());
|
let script = Script::from(hex_bytes(script).unwrap());
|
||||||
let mut raw_expected = hex_bytes(expected_result).unwrap();
|
let mut raw_expected = hex_bytes(expected_result).unwrap();
|
||||||
raw_expected.reverse();
|
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);
|
let actual_result = tx.signature_hash(input_index, &script, hash_type as u32);
|
||||||
assert_eq!(actual_result, expected_result);
|
assert_eq!(actual_result, expected_result);
|
||||||
|
|
|
@ -33,8 +33,6 @@ use std::collections::HashMap;
|
||||||
use std::hash::Hash;
|
use std::hash::Hash;
|
||||||
use std::{mem, u32};
|
use std::{mem, u32};
|
||||||
|
|
||||||
use util::hash::Sha256dHash;
|
|
||||||
|
|
||||||
use std::error;
|
use std::error;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::io;
|
use std::io;
|
||||||
|
@ -43,6 +41,7 @@ use byteorder::{LittleEndian, WriteBytesExt, ReadBytesExt};
|
||||||
use hex::encode as hex_encode;
|
use hex::encode as hex_encode;
|
||||||
|
|
||||||
use bitcoin_bech32;
|
use bitcoin_bech32;
|
||||||
|
use bitcoin_hashes::{sha256d, Hash as HashTrait};
|
||||||
|
|
||||||
use util::base58;
|
use util::base58;
|
||||||
|
|
||||||
|
@ -565,7 +564,7 @@ impl<D: Decoder, T:Decodable<D>> Decodable<D> for Option<T> {
|
||||||
|
|
||||||
/// Do a double-SHA256 on some data and return the first 4 bytes
|
/// Do a double-SHA256 on some data and return the first 4 bytes
|
||||||
fn sha2_checksum(data: &[u8]) -> [u8; 4] {
|
fn sha2_checksum(data: &[u8]) -> [u8; 4] {
|
||||||
let checksum = Sha256dHash::from_data(data);
|
let checksum = <sha256d::Hash as HashTrait>::hash(data);
|
||||||
[checksum[0], checksum[1], checksum[2], checksum[3]]
|
[checksum[0], checksum[1], checksum[2], checksum[3]]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -678,7 +677,18 @@ impl<D, K, V> Decodable<D> for HashMap<K, V>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<S: Encoder> Encodable<S> for sha256d::Hash {
|
||||||
|
fn consensus_encode(&self, s: &mut S) -> Result<(), self::Error> {
|
||||||
|
self.into_inner().consensus_encode(s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D: Decoder> Decodable<D> for sha256d::Hash {
|
||||||
|
fn consensus_decode(d: &mut D) -> Result<sha256d::Hash, self::Error> {
|
||||||
|
let inner: [u8; 32] = Decodable::consensus_decode(d)?;
|
||||||
|
Ok(sha256d::Hash::from_slice(&inner).unwrap())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Tests
|
// Tests
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
|
@ -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;
|
|
|
@ -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 }
|
|
||||||
}
|
|
|
@ -38,25 +38,6 @@ macro_rules! impl_consensus_encoding {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! impl_newtype_consensus_encoding {
|
|
||||||
($thing:ident) => (
|
|
||||||
impl<S: ::consensus::encode::Encoder> ::consensus::encode::Encodable<S> for $thing {
|
|
||||||
#[inline]
|
|
||||||
fn consensus_encode(&self, s: &mut S) -> Result<(), ::consensus::encode::Error> {
|
|
||||||
let &$thing(ref data) = self;
|
|
||||||
data.consensus_encode(s)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<D: ::consensus::encode::Decoder> ::consensus::encode::Decodable<D> 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 {
|
macro_rules! impl_array_newtype {
|
||||||
($thing:ident, $ty:ty, $len:expr) => {
|
($thing:ident, $ty:ty, $len:expr) => {
|
||||||
impl $thing {
|
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())));
|
macro_rules! hex_script (($s:expr) => (::blockdata::script::Script::from(::hex::decode($s).unwrap())));
|
||||||
|
|
||||||
#[cfg(test)]
|
#[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 {
|
macro_rules! serde_struct_impl {
|
||||||
($name:ident, $($fe:ident),*) => (
|
($name:ident, $($fe:ident),*) => (
|
||||||
|
|
|
@ -42,8 +42,8 @@
|
||||||
#![deny(missing_docs)]
|
#![deny(missing_docs)]
|
||||||
|
|
||||||
extern crate bitcoin_bech32;
|
extern crate bitcoin_bech32;
|
||||||
|
extern crate bitcoin_hashes;
|
||||||
extern crate byteorder;
|
extern crate byteorder;
|
||||||
extern crate crypto;
|
|
||||||
extern crate hex;
|
extern crate hex;
|
||||||
extern crate rand;
|
extern crate rand;
|
||||||
extern crate secp256k1;
|
extern crate secp256k1;
|
||||||
|
@ -79,6 +79,3 @@ pub use util::hash::BitcoinHash;
|
||||||
pub use util::privkey::Privkey;
|
pub use util::privkey::Privkey;
|
||||||
pub use util::decimal::Decimal;
|
pub use util::decimal::Decimal;
|
||||||
pub use util::decimal::UDecimal;
|
pub use util::decimal::UDecimal;
|
||||||
|
|
||||||
#[cfg(feature = "fuzztarget")]
|
|
||||||
pub mod fuzz_util;
|
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
use network::constants;
|
use network::constants;
|
||||||
use consensus::encode::{Decodable, Encodable};
|
use consensus::encode::{Decodable, Encodable};
|
||||||
use consensus::encode::{self, Decoder, Encoder};
|
use consensus::encode::{self, Decoder, Encoder};
|
||||||
use util::hash::Sha256dHash;
|
use bitcoin_hashes::sha256d;
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, Clone, Debug)]
|
#[derive(PartialEq, Eq, Clone, Debug)]
|
||||||
/// The type of an inventory object
|
/// The type of an inventory object
|
||||||
|
@ -48,9 +48,9 @@ pub struct GetBlocksMessage {
|
||||||
/// Locator hashes --- ordered newest to oldest. The remote peer will
|
/// Locator hashes --- ordered newest to oldest. The remote peer will
|
||||||
/// reply with its longest known chain, starting from a locator hash
|
/// reply with its longest known chain, starting from a locator hash
|
||||||
/// if possible and block 1 otherwise.
|
/// if possible and block 1 otherwise.
|
||||||
pub locator_hashes: Vec<Sha256dHash>,
|
pub locator_hashes: Vec<sha256d::Hash>,
|
||||||
/// References the block to stop at, or zero to just fetch the maximum 500 blocks
|
/// 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
|
/// The `getheaders` message
|
||||||
|
@ -61,9 +61,9 @@ pub struct GetHeadersMessage {
|
||||||
/// Locator hashes --- ordered newest to oldest. The remote peer will
|
/// Locator hashes --- ordered newest to oldest. The remote peer will
|
||||||
/// reply with its longest known chain, starting from a locator hash
|
/// reply with its longest known chain, starting from a locator hash
|
||||||
/// if possible and block 1 otherwise.
|
/// if possible and block 1 otherwise.
|
||||||
pub locator_hashes: Vec<Sha256dHash>,
|
pub locator_hashes: Vec<sha256d::Hash>,
|
||||||
/// References the header to stop at, or zero to just fetch the maximum 2000 headers
|
/// 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
|
/// An inventory object --- a reference to a Bitcoin object
|
||||||
|
@ -72,12 +72,12 @@ pub struct Inventory {
|
||||||
/// The type of object that is referenced
|
/// The type of object that is referenced
|
||||||
pub inv_type: InvType,
|
pub inv_type: InvType,
|
||||||
/// The object's hash
|
/// The object's hash
|
||||||
pub hash: Sha256dHash
|
pub hash: sha256d::Hash
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GetBlocksMessage {
|
impl GetBlocksMessage {
|
||||||
/// Construct a new `getblocks` message
|
/// Construct a new `getblocks` message
|
||||||
pub fn new(locator_hashes: Vec<Sha256dHash>, stop_hash: Sha256dHash) -> GetBlocksMessage {
|
pub fn new(locator_hashes: Vec<sha256d::Hash>, stop_hash: sha256d::Hash) -> GetBlocksMessage {
|
||||||
GetBlocksMessage {
|
GetBlocksMessage {
|
||||||
version: constants::PROTOCOL_VERSION,
|
version: constants::PROTOCOL_VERSION,
|
||||||
locator_hashes: locator_hashes.clone(),
|
locator_hashes: locator_hashes.clone(),
|
||||||
|
@ -90,7 +90,7 @@ impl_consensus_encoding!(GetBlocksMessage, version, locator_hashes, stop_hash);
|
||||||
|
|
||||||
impl GetHeadersMessage {
|
impl GetHeadersMessage {
|
||||||
/// Construct a new `getheaders` message
|
/// Construct a new `getheaders` message
|
||||||
pub fn new(locator_hashes: Vec<Sha256dHash>, stop_hash: Sha256dHash) -> GetHeadersMessage {
|
pub fn new(locator_hashes: Vec<sha256d::Hash>, stop_hash: sha256d::Hash) -> GetHeadersMessage {
|
||||||
GetHeadersMessage {
|
GetHeadersMessage {
|
||||||
version: constants::PROTOCOL_VERSION,
|
version: constants::PROTOCOL_VERSION,
|
||||||
locator_hashes: locator_hashes,
|
locator_hashes: locator_hashes,
|
||||||
|
|
|
@ -51,6 +51,7 @@ use std::fmt::{self, Display, Formatter};
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
use bitcoin_bech32::{self, WitnessProgram, u5};
|
use bitcoin_bech32::{self, WitnessProgram, u5};
|
||||||
|
use bitcoin_hashes::{hash160, Hash};
|
||||||
use secp256k1::key::PublicKey;
|
use secp256k1::key::PublicKey;
|
||||||
|
|
||||||
#[cfg(feature = "serde")]
|
#[cfg(feature = "serde")]
|
||||||
|
@ -60,7 +61,6 @@ use blockdata::opcodes;
|
||||||
use blockdata::script;
|
use blockdata::script;
|
||||||
use network::constants::Network;
|
use network::constants::Network;
|
||||||
use consensus::encode;
|
use consensus::encode;
|
||||||
use util::hash::Hash160;
|
|
||||||
use util::base58;
|
use util::base58;
|
||||||
|
|
||||||
/// The method used to produce an address
|
/// The method used to produce an address
|
||||||
|
@ -69,9 +69,9 @@ pub enum Payload {
|
||||||
/// pay-to-pubkey
|
/// pay-to-pubkey
|
||||||
Pubkey(PublicKey),
|
Pubkey(PublicKey),
|
||||||
/// pay-to-pkhash address
|
/// pay-to-pkhash address
|
||||||
PubkeyHash(Hash160),
|
PubkeyHash(hash160::Hash),
|
||||||
/// P2SH address
|
/// P2SH address
|
||||||
ScriptHash(Hash160),
|
ScriptHash(hash160::Hash),
|
||||||
/// Segwit address
|
/// Segwit address
|
||||||
WitnessProgram(WitnessProgram),
|
WitnessProgram(WitnessProgram),
|
||||||
}
|
}
|
||||||
|
@ -92,7 +92,7 @@ impl Address {
|
||||||
pub fn p2pkh(pk: &PublicKey, network: Network) -> Address {
|
pub fn p2pkh(pk: &PublicKey, network: Network) -> Address {
|
||||||
Address {
|
Address {
|
||||||
network: network,
|
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 {
|
pub fn p2upkh(pk: &PublicKey, network: Network) -> Address {
|
||||||
Address {
|
Address {
|
||||||
network: network,
|
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 {
|
pub fn p2sh(script: &script::Script, network: Network) -> Address {
|
||||||
Address {
|
Address {
|
||||||
network: network,
|
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(
|
payload: Payload::WitnessProgram(
|
||||||
// unwrap is safe as witness program is known to be correct as above
|
// unwrap is safe as witness program is known to be correct as above
|
||||||
WitnessProgram::new(u5::try_from_u8(0).expect("0<32"),
|
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())
|
Address::bech_network(network)).unwrap())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -146,24 +146,19 @@ impl Address {
|
||||||
pub fn p2shwpkh (pk: &PublicKey, network: Network) -> Address {
|
pub fn p2shwpkh (pk: &PublicKey, network: Network) -> Address {
|
||||||
let builder = script::Builder::new()
|
let builder = script::Builder::new()
|
||||||
.push_int(0)
|
.push_int(0)
|
||||||
.push_slice(&Hash160::from_data(&pk.serialize()[..])[..]);
|
.push_slice(&hash160::Hash::hash(&pk.serialize()[..])[..]);
|
||||||
Address {
|
Address {
|
||||||
network: network,
|
network: network,
|
||||||
payload: Payload::ScriptHash(
|
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
|
/// Create a witness pay to script hash address
|
||||||
pub fn p2wsh (script: &script::Script, network: Network) -> Address {
|
pub fn p2wsh (script: &script::Script, network: Network) -> Address {
|
||||||
use crypto::sha2::Sha256;
|
use bitcoin_hashes::sha256;
|
||||||
use crypto::digest::Digest;
|
use bitcoin_hashes::Hash;
|
||||||
|
|
||||||
let mut digest = Sha256::new();
|
|
||||||
digest.input(script.as_bytes());
|
|
||||||
let mut d = [0u8; 32];
|
|
||||||
digest.result(&mut d);
|
|
||||||
|
|
||||||
Address {
|
Address {
|
||||||
network: network,
|
network: network,
|
||||||
|
@ -171,7 +166,7 @@ impl Address {
|
||||||
// unwrap is safe as witness program is known to be correct as above
|
// unwrap is safe as witness program is known to be correct as above
|
||||||
WitnessProgram::new(
|
WitnessProgram::new(
|
||||||
u5::try_from_u8(0).expect("0<32"),
|
u5::try_from_u8(0).expect("0<32"),
|
||||||
d.to_vec(),
|
sha256::Hash::hash(&script[..])[..].to_vec(),
|
||||||
Address::bech_network(network)
|
Address::bech_network(network)
|
||||||
).unwrap()
|
).unwrap()
|
||||||
)
|
)
|
||||||
|
@ -181,18 +176,17 @@ impl Address {
|
||||||
/// Create a pay to script address that embeds a witness pay to script hash 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
|
/// This is a segwit address type that looks familiar (as p2sh) to legacy clients
|
||||||
pub fn p2shwsh (script: &script::Script, network: Network) -> Address {
|
pub fn p2shwsh (script: &script::Script, network: Network) -> Address {
|
||||||
use crypto::sha2::Sha256;
|
use bitcoin_hashes::sha256;
|
||||||
use crypto::digest::Digest;
|
use bitcoin_hashes::Hash;
|
||||||
|
use bitcoin_hashes::hash160;
|
||||||
|
|
||||||
let mut digest = Sha256::new();
|
let ws = script::Builder::new().push_int(0)
|
||||||
digest.input(script.as_bytes());
|
.push_slice(&sha256::Hash::hash(&script[..])[..])
|
||||||
let mut d = [0u8; 32];
|
.into_script();
|
||||||
digest.result(&mut d);
|
|
||||||
let ws = script::Builder::new().push_int(0).push_slice(&d).into_script();
|
|
||||||
|
|
||||||
Address {
|
Address {
|
||||||
network: network,
|
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 {
|
match self.payload {
|
||||||
// note: serialization for pay-to-pk is defined, but is irreversible
|
// note: serialization for pay-to-pk is defined, but is irreversible
|
||||||
Payload::Pubkey(ref pk) => {
|
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];
|
let mut prefixed = [0; 21];
|
||||||
prefixed[0] = match self.network {
|
prefixed[0] = match self.network {
|
||||||
Network::Bitcoin => 0,
|
Network::Bitcoin => 0,
|
||||||
|
@ -315,19 +309,19 @@ impl FromStr for Address {
|
||||||
let (network, payload) = match data[0] {
|
let (network, payload) = match data[0] {
|
||||||
0 => (
|
0 => (
|
||||||
Network::Bitcoin,
|
Network::Bitcoin,
|
||||||
Payload::PubkeyHash(Hash160::from(&data[1..]))
|
Payload::PubkeyHash(hash160::Hash::from_slice(&data[1..]).unwrap())
|
||||||
),
|
),
|
||||||
5 => (
|
5 => (
|
||||||
Network::Bitcoin,
|
Network::Bitcoin,
|
||||||
Payload::ScriptHash(Hash160::from(&data[1..]))
|
Payload::ScriptHash(hash160::Hash::from_slice(&data[1..]).unwrap())
|
||||||
),
|
),
|
||||||
111 => (
|
111 => (
|
||||||
Network::Testnet,
|
Network::Testnet,
|
||||||
Payload::PubkeyHash(Hash160::from(&data[1..]))
|
Payload::PubkeyHash(hash160::Hash::from_slice(&data[1..]).unwrap())
|
||||||
),
|
),
|
||||||
196 => (
|
196 => (
|
||||||
Network::Testnet,
|
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])))
|
x => return Err(encode::Error::Base58(base58::Error::InvalidVersion(vec![x])))
|
||||||
};
|
};
|
||||||
|
@ -403,24 +397,25 @@ mod tests {
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use std::string::ToString;
|
use std::string::ToString;
|
||||||
|
|
||||||
|
use bitcoin_hashes::{hash160, Hash};
|
||||||
use secp256k1::key::PublicKey;
|
use secp256k1::key::PublicKey;
|
||||||
use hex::decode as hex_decode;
|
use hex::decode as hex_decode;
|
||||||
|
|
||||||
use blockdata::script::Script;
|
use blockdata::script::Script;
|
||||||
use network::constants::Network::{Bitcoin, Testnet, Regtest};
|
use network::constants::Network::{Bitcoin, Testnet, Regtest};
|
||||||
use util::hash::Hash160;
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
macro_rules! hex (($hex:expr) => (hex_decode($hex).unwrap()));
|
macro_rules! hex (($hex:expr) => (hex_decode($hex).unwrap()));
|
||||||
macro_rules! hex_key (($hex:expr) => (PublicKey::from_slice(&hex!($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_script (($hex:expr) => (Script::from(hex!($hex))));
|
||||||
|
macro_rules! hex_hash160 (($hex:expr) => (hash160::Hash::from_slice(&hex!($hex)).unwrap()));
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_p2pkh_address_58() {
|
fn test_p2pkh_address_58() {
|
||||||
let addr = Address {
|
let addr = Address {
|
||||||
network: Bitcoin,
|
network: Bitcoin,
|
||||||
payload: Payload::PubkeyHash(
|
payload: Payload::PubkeyHash(
|
||||||
Hash160::from(&hex_decode("162c5ea71c0b23f5b9022ef047c4a86470a5b070").unwrap()[..])
|
hex_hash160!("162c5ea71c0b23f5b9022ef047c4a86470a5b070")
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -453,7 +448,7 @@ mod tests {
|
||||||
let addr = Address {
|
let addr = Address {
|
||||||
network: Bitcoin,
|
network: Bitcoin,
|
||||||
payload: Payload::ScriptHash(
|
payload: Payload::ScriptHash(
|
||||||
Hash160::from(&hex_decode("162c5ea71c0b23f5b9022ef047c4a86470a5b070").unwrap()[..])
|
hex_hash160!("162c5ea71c0b23f5b9022ef047c4a86470a5b070")
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,8 @@
|
||||||
use std::{error, fmt, str, slice, iter};
|
use std::{error, fmt, str, slice, iter};
|
||||||
|
|
||||||
use byteorder::{ByteOrder, LittleEndian};
|
use byteorder::{ByteOrder, LittleEndian};
|
||||||
use util::hash::Sha256dHash;
|
|
||||||
|
use bitcoin_hashes::{sha256d, Hash};
|
||||||
|
|
||||||
/// An error that might occur during base58 decoding
|
/// An error that might occur during base58 decoding
|
||||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||||
|
@ -161,7 +162,7 @@ pub fn from_check(data: &str) -> Result<Vec<u8>, Error> {
|
||||||
return Err(Error::TooShort(ret.len()));
|
return Err(Error::TooShort(ret.len()));
|
||||||
}
|
}
|
||||||
let ck_start = ret.len() - 4;
|
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)]);
|
let actual = LittleEndian::read_u32(&ret[ck_start..(ck_start + 4)]);
|
||||||
if expected != actual {
|
if expected != actual {
|
||||||
return Err(Error::BadChecksum(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
|
/// 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.)
|
/// (Tack the first 4 256-digits of the object's Bitcoin hash onto the end.)
|
||||||
pub fn check_encode_slice(data: &[u8]) -> String {
|
pub fn check_encode_slice(data: &[u8]) -> String {
|
||||||
let checksum = Sha256dHash::from_data(&data);
|
let checksum = sha256d::Hash::hash(&data);
|
||||||
encode_iter(
|
encode_iter(
|
||||||
data.iter()
|
data.iter()
|
||||||
.cloned()
|
.cloned()
|
||||||
|
@ -241,7 +242,7 @@ pub fn check_encode_slice(data: &[u8]) -> String {
|
||||||
/// Obtain a string with the base58check encoding of a slice
|
/// 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.)
|
/// (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 {
|
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()
|
let iter = data.iter()
|
||||||
.cloned()
|
.cloned()
|
||||||
.chain(checksum[0..4].iter().cloned());
|
.chain(checksum[0..4].iter().cloned());
|
||||||
|
|
|
@ -19,10 +19,11 @@
|
||||||
//! signatures, which are placed in the scriptSig.
|
//! signatures, which are placed in the scriptSig.
|
||||||
//!
|
//!
|
||||||
|
|
||||||
|
use bitcoin_hashes::{sha256d, Hash};
|
||||||
|
|
||||||
use blockdata::script::Script;
|
use blockdata::script::Script;
|
||||||
use blockdata::transaction::{Transaction, TxIn};
|
use blockdata::transaction::{Transaction, TxIn};
|
||||||
use consensus::encode::Encodable;
|
use consensus::encode::Encodable;
|
||||||
use util::hash::{Sha256dHash, Sha256dEncoder};
|
|
||||||
|
|
||||||
/// Parts of a sighash which are common across inputs or signatures, and which are
|
/// 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
|
/// sufficient (in conjunction with a private key) to sign the transaction
|
||||||
|
@ -31,11 +32,11 @@ pub struct SighashComponents {
|
||||||
tx_version: u32,
|
tx_version: u32,
|
||||||
tx_locktime: u32,
|
tx_locktime: u32,
|
||||||
/// Hash of all the previous outputs
|
/// Hash of all the previous outputs
|
||||||
pub hash_prevouts: Sha256dHash,
|
pub hash_prevouts: sha256d::Hash,
|
||||||
/// Hash of all the input sequence nos
|
/// Hash of all the input sequence nos
|
||||||
pub hash_sequence: Sha256dHash,
|
pub hash_sequence: sha256d::Hash,
|
||||||
/// Hash of all the outputs in this transaction
|
/// Hash of all the outputs in this transaction
|
||||||
pub hash_outputs: Sha256dHash,
|
pub hash_outputs: sha256d::Hash,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SighashComponents {
|
impl SighashComponents {
|
||||||
|
@ -45,27 +46,27 @@ impl SighashComponents {
|
||||||
/// script_sig and witnesses.
|
/// script_sig and witnesses.
|
||||||
pub fn new(tx: &Transaction) -> SighashComponents {
|
pub fn new(tx: &Transaction) -> SighashComponents {
|
||||||
let hash_prevouts = {
|
let hash_prevouts = {
|
||||||
let mut enc = Sha256dEncoder::new();
|
let mut enc = sha256d::Hash::engine();
|
||||||
for txin in &tx.input {
|
for txin in &tx.input {
|
||||||
txin.previous_output.consensus_encode(&mut enc).unwrap();
|
txin.previous_output.consensus_encode(&mut enc).unwrap();
|
||||||
}
|
}
|
||||||
enc.into_hash()
|
sha256d::Hash::from_engine(enc)
|
||||||
};
|
};
|
||||||
|
|
||||||
let hash_sequence = {
|
let hash_sequence = {
|
||||||
let mut enc = Sha256dEncoder::new();
|
let mut enc = sha256d::Hash::engine();
|
||||||
for txin in &tx.input {
|
for txin in &tx.input {
|
||||||
txin.sequence.consensus_encode(&mut enc).unwrap();
|
txin.sequence.consensus_encode(&mut enc).unwrap();
|
||||||
}
|
}
|
||||||
enc.into_hash()
|
sha256d::Hash::from_engine(enc)
|
||||||
};
|
};
|
||||||
|
|
||||||
let hash_outputs = {
|
let hash_outputs = {
|
||||||
let mut enc = Sha256dEncoder::new();
|
let mut enc = sha256d::Hash::engine();
|
||||||
for txout in &tx.output {
|
for txout in &tx.output {
|
||||||
txout.consensus_encode(&mut enc).unwrap();
|
txout.consensus_encode(&mut enc).unwrap();
|
||||||
}
|
}
|
||||||
enc.into_hash()
|
sha256d::Hash::from_engine(enc)
|
||||||
};
|
};
|
||||||
|
|
||||||
SighashComponents {
|
SighashComponents {
|
||||||
|
@ -79,8 +80,8 @@ impl SighashComponents {
|
||||||
|
|
||||||
/// Compute the BIP143 sighash for a `SIGHASH_ALL` signature for the given
|
/// Compute the BIP143 sighash for a `SIGHASH_ALL` signature for the given
|
||||||
/// input.
|
/// input.
|
||||||
pub fn sighash_all(&self, txin: &TxIn, witness_script: &Script, value: u64) -> Sha256dHash {
|
pub fn sighash_all(&self, txin: &TxIn, witness_script: &Script, value: u64) -> sha256d::Hash {
|
||||||
let mut enc = Sha256dEncoder::new();
|
let mut enc = sha256d::Hash::engine();
|
||||||
self.tx_version.consensus_encode(&mut enc).unwrap();
|
self.tx_version.consensus_encode(&mut enc).unwrap();
|
||||||
self.hash_prevouts.consensus_encode(&mut enc).unwrap();
|
self.hash_prevouts.consensus_encode(&mut enc).unwrap();
|
||||||
self.hash_sequence.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.hash_outputs.consensus_encode(&mut enc).unwrap();
|
||||||
self.tx_locktime.consensus_encode(&mut enc).unwrap();
|
self.tx_locktime.consensus_encode(&mut enc).unwrap();
|
||||||
1u32.consensus_encode(&mut enc).unwrap(); // hashtype
|
1u32.consensus_encode(&mut enc).unwrap(); // hashtype
|
||||||
enc.into_hash()
|
sha256d::Hash::from_engine(enc)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,19 +23,13 @@ use std::str::FromStr;
|
||||||
#[cfg(feature = "serde")] use serde;
|
#[cfg(feature = "serde")] use serde;
|
||||||
|
|
||||||
use byteorder::{BigEndian, ByteOrder, ReadBytesExt};
|
use byteorder::{BigEndian, ByteOrder, ReadBytesExt};
|
||||||
use crypto::digest::Digest;
|
use bitcoin_hashes::{hash160, sha512, Hash, HashEngine, Hmac, HmacEngine};
|
||||||
use crypto::hmac::Hmac;
|
|
||||||
use crypto::mac::Mac;
|
|
||||||
use crypto::ripemd160::Ripemd160;
|
|
||||||
use secp256k1::key::{PublicKey, SecretKey};
|
use secp256k1::key::{PublicKey, SecretKey};
|
||||||
use secp256k1::{self, Secp256k1};
|
use secp256k1::{self, Secp256k1};
|
||||||
|
|
||||||
use network::constants::Network;
|
use network::constants::Network;
|
||||||
use util::base58;
|
use util::base58;
|
||||||
|
|
||||||
#[cfg(feature="fuzztarget")] use fuzz_util::sha2::{Sha256, Sha512};
|
|
||||||
#[cfg(not(feature="fuzztarget"))] use crypto::sha2::{Sha256, Sha512};
|
|
||||||
|
|
||||||
/// A chain code
|
/// A chain code
|
||||||
pub struct ChainCode([u8; 32]);
|
pub struct ChainCode([u8; 32]);
|
||||||
impl_array_newtype!(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_array_newtype_encodable!(Fingerprint, u8, 4);
|
||||||
|
|
||||||
impl Default for Fingerprint {
|
impl Default for Fingerprint {
|
||||||
fn default() -> Fingerprint { Fingerprint([0, 0, 0, 0]) }
|
fn default() -> Fingerprint { Fingerprint([0; 4]) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Extended private key
|
/// Extended private key
|
||||||
|
@ -237,18 +231,17 @@ impl From<secp256k1::Error> for Error {
|
||||||
impl ExtendedPrivKey {
|
impl ExtendedPrivKey {
|
||||||
/// Construct a new master key from a seed value
|
/// Construct a new master key from a seed value
|
||||||
pub fn new_master(network: Network, seed: &[u8]) -> Result<ExtendedPrivKey, Error> {
|
pub fn new_master(network: Network, seed: &[u8]) -> Result<ExtendedPrivKey, Error> {
|
||||||
let mut result = [0; 64];
|
let mut hmac_engine: HmacEngine<sha512::Hash> = HmacEngine::new(b"Bitcoin seed");
|
||||||
let mut hmac = Hmac::new(Sha512::new(), b"Bitcoin seed");
|
hmac_engine.input(seed);
|
||||||
hmac.input(seed);
|
let hmac_result: Hmac<sha512::Hash> = Hmac::from_engine(hmac_engine);
|
||||||
hmac.raw_result(&mut result);
|
|
||||||
|
|
||||||
Ok(ExtendedPrivKey {
|
Ok(ExtendedPrivKey {
|
||||||
network: network,
|
network: network,
|
||||||
depth: 0,
|
depth: 0,
|
||||||
parent_fingerprint: Default::default(),
|
parent_fingerprint: Default::default(),
|
||||||
child_number: ChildNumber::from_normal_idx(0),
|
child_number: ChildNumber::from_normal_idx(0),
|
||||||
secret_key: SecretKey::from_slice(&result[..32]).map_err(Error::Ecdsa)?,
|
secret_key: SecretKey::from_slice(&hmac_result[..32]).map_err(Error::Ecdsa)?,
|
||||||
chain_code: ChainCode::from(&result[32..])
|
chain_code: ChainCode::from(&hmac_result[32..]),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -267,25 +260,24 @@ impl ExtendedPrivKey {
|
||||||
|
|
||||||
/// Private->Private child key derivation
|
/// Private->Private child key derivation
|
||||||
pub fn ckd_priv<C: secp256k1::Signing>(&self, secp: &Secp256k1<C>, i: ChildNumber) -> Result<ExtendedPrivKey, Error> {
|
pub fn ckd_priv<C: secp256k1::Signing>(&self, secp: &Secp256k1<C>, i: ChildNumber) -> Result<ExtendedPrivKey, Error> {
|
||||||
let mut result = [0; 64];
|
let mut hmac_engine: HmacEngine<sha512::Hash> = HmacEngine::new(&self.chain_code[..]);
|
||||||
let mut hmac = Hmac::new(Sha512::new(), &self.chain_code[..]);
|
|
||||||
let mut be_n = [0; 4];
|
let mut be_n = [0; 4];
|
||||||
match i {
|
match i {
|
||||||
ChildNumber::Normal {..} => {
|
ChildNumber::Normal {..} => {
|
||||||
// Non-hardened key: compute public data and use that
|
// 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 {..} => {
|
ChildNumber::Hardened {..} => {
|
||||||
// Hardened key: use only secret data to prevent public derivation
|
// Hardened key: use only secret data to prevent public derivation
|
||||||
hmac.input(&[0u8]);
|
hmac_engine.input(&[0u8]);
|
||||||
hmac.input(&self.secret_key[..]);
|
hmac_engine.input(&self.secret_key[..]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
BigEndian::write_u32(&mut be_n, u32::from(i));
|
BigEndian::write_u32(&mut be_n, u32::from(i));
|
||||||
|
|
||||||
hmac.input(&be_n);
|
hmac_engine.input(&be_n);
|
||||||
hmac.raw_result(&mut result);
|
let hmac_result: Hmac<sha512::Hash> = Hmac::from_engine(hmac_engine);
|
||||||
let mut sk = SecretKey::from_slice(&result[..32]).map_err(Error::Ecdsa)?;
|
let mut sk = SecretKey::from_slice(&hmac_result[..32]).map_err(Error::Ecdsa)?;
|
||||||
sk.add_assign(&self.secret_key[..]).map_err(Error::Ecdsa)?;
|
sk.add_assign(&self.secret_key[..]).map_err(Error::Ecdsa)?;
|
||||||
|
|
||||||
Ok(ExtendedPrivKey {
|
Ok(ExtendedPrivKey {
|
||||||
|
@ -294,26 +286,13 @@ impl ExtendedPrivKey {
|
||||||
parent_fingerprint: self.fingerprint(secp),
|
parent_fingerprint: self.fingerprint(secp),
|
||||||
child_number: i,
|
child_number: i,
|
||||||
secret_key: sk,
|
secret_key: sk,
|
||||||
chain_code: ChainCode::from(&result[32..])
|
chain_code: ChainCode::from(&hmac_result[32..])
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the HASH160 of the chaincode
|
/// Returns the HASH160 of the chaincode
|
||||||
pub fn identifier<C: secp256k1::Signing>(&self, secp: &Secp256k1<C>) -> [u8; 20] {
|
pub fn identifier<C: secp256k1::Signing>(&self, secp: &Secp256k1<C>) -> hash160::Hash {
|
||||||
let mut sha2_res = [0; 32];
|
ExtendedPubKey::from_private(secp, self).identifier()
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the first four bytes of the identifier
|
/// Returns the first four bytes of the identifier
|
||||||
|
@ -355,17 +334,16 @@ impl ExtendedPubKey {
|
||||||
Err(Error::CannotDeriveFromHardenedKey)
|
Err(Error::CannotDeriveFromHardenedKey)
|
||||||
}
|
}
|
||||||
ChildNumber::Normal { index: n } => {
|
ChildNumber::Normal { index: n } => {
|
||||||
let mut hmac = Hmac::new(Sha512::new(), &self.chain_code[..]);
|
let mut hmac_engine: HmacEngine<sha512::Hash> = HmacEngine::new(&self.chain_code[..]);
|
||||||
hmac.input(&self.public_key.serialize()[..]);
|
hmac_engine.input(&self.public_key.serialize()[..]);
|
||||||
let mut be_n = [0; 4];
|
let mut be_n = [0; 4];
|
||||||
BigEndian::write_u32(&mut be_n, n);
|
BigEndian::write_u32(&mut be_n, n);
|
||||||
hmac.input(&be_n);
|
hmac_engine.input(&be_n);
|
||||||
|
|
||||||
let mut result = [0; 64];
|
let hmac_result: Hmac<sha512::Hash> = Hmac::from_engine(hmac_engine);
|
||||||
hmac.raw_result(&mut result);
|
|
||||||
|
|
||||||
let secret_key = SecretKey::from_slice(&result[..32])?;
|
let secret_key = SecretKey::from_slice(&hmac_result[..32])?;
|
||||||
let chain_code = ChainCode::from(&result[32..]);
|
let chain_code = ChainCode::from(&hmac_result[32..]);
|
||||||
Ok((secret_key, chain_code))
|
Ok((secret_key, chain_code))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -392,19 +370,8 @@ impl ExtendedPubKey {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the HASH160 of the chaincode
|
/// Returns the HASH160 of the chaincode
|
||||||
pub fn identifier(&self) -> [u8; 20] {
|
pub fn identifier(&self) -> hash160::Hash {
|
||||||
let mut sha2_res = [0; 32];
|
hash160::Hash::hash(&self.public_key.serialize())
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the first four bytes of the identifier
|
/// Returns the first four bytes of the identifier
|
||||||
|
|
|
@ -20,17 +20,13 @@
|
||||||
|
|
||||||
use secp256k1::{self, Secp256k1};
|
use secp256k1::{self, Secp256k1};
|
||||||
use secp256k1::key::{PublicKey, SecretKey};
|
use secp256k1::key::{PublicKey, SecretKey};
|
||||||
|
use bitcoin_hashes::{hash160, sha256, Hash, HashEngine, Hmac, HmacEngine};
|
||||||
use blockdata::{opcodes, script};
|
use blockdata::{opcodes, script};
|
||||||
use crypto::hmac;
|
|
||||||
use crypto::mac::Mac;
|
|
||||||
|
|
||||||
use std::{error, fmt};
|
use std::{error, fmt};
|
||||||
|
|
||||||
use network::constants::Network;
|
use network::constants::Network;
|
||||||
use util::{address, hash};
|
use util::address;
|
||||||
|
|
||||||
#[cfg(feature="fuzztarget")] use fuzz_util::sha2;
|
|
||||||
#[cfg(not(feature="fuzztarget"))] use crypto::sha2;
|
|
||||||
|
|
||||||
/// Encoding of "pubkey here" in script; from Bitcoin Core `src/script/script.h`
|
/// Encoding of "pubkey here" in script; from Bitcoin Core `src/script/script.h`
|
||||||
static PUBKEY: u8 = 0xFE;
|
static PUBKEY: u8 = 0xFE;
|
||||||
|
@ -173,11 +169,10 @@ impl<'a> From<&'a [u8]> for Template {
|
||||||
pub fn tweak_keys<C: secp256k1::Verification>(secp: &Secp256k1<C>, keys: &[PublicKey], contract: &[u8]) -> Result<Vec<PublicKey>, Error> {
|
pub fn tweak_keys<C: secp256k1::Verification>(secp: &Secp256k1<C>, keys: &[PublicKey], contract: &[u8]) -> Result<Vec<PublicKey>, Error> {
|
||||||
let mut ret = Vec::with_capacity(keys.len());
|
let mut ret = Vec::with_capacity(keys.len());
|
||||||
for mut key in keys.iter().cloned() {
|
for mut key in keys.iter().cloned() {
|
||||||
let mut hmac_raw = [0; 32];
|
let mut hmac_engine: HmacEngine<sha256::Hash> = HmacEngine::new(&key.serialize());
|
||||||
let mut hmac = hmac::Hmac::new(sha2::Sha256::new(), &key.serialize());
|
hmac_engine.input(contract);
|
||||||
hmac.input(contract);
|
let hmac_result: Hmac<sha256::Hash> = Hmac::from_engine(hmac_engine);
|
||||||
hmac.raw_result(&mut hmac_raw);
|
let hmac_sk = SecretKey::from_slice(&hmac_result[..]).map_err(Error::BadTweak)?;
|
||||||
let hmac_sk = SecretKey::from_slice(&hmac_raw).map_err(Error::BadTweak)?;
|
|
||||||
key.add_exp_assign(secp, &hmac_sk[..]).map_err(Error::Secp)?;
|
key.add_exp_assign(secp, &hmac_sk[..]).map_err(Error::Secp)?;
|
||||||
ret.push(key);
|
ret.push(key);
|
||||||
}
|
}
|
||||||
|
@ -186,11 +181,10 @@ pub fn tweak_keys<C: secp256k1::Verification>(secp: &Secp256k1<C>, keys: &[Publi
|
||||||
|
|
||||||
/// Compute a tweak from some given data for the given public key
|
/// Compute a tweak from some given data for the given public key
|
||||||
pub fn compute_tweak(pk: &PublicKey, contract: &[u8]) -> Result<SecretKey, Error> {
|
pub fn compute_tweak(pk: &PublicKey, contract: &[u8]) -> Result<SecretKey, Error> {
|
||||||
let mut hmac_raw = [0; 32];
|
let mut hmac_engine: HmacEngine<sha256::Hash> = HmacEngine::new(&pk.serialize());
|
||||||
let mut hmac = hmac::Hmac::new(sha2::Sha256::new(), &pk.serialize());
|
hmac_engine.input(contract);
|
||||||
hmac.input(contract);
|
let hmac_result: Hmac<sha256::Hash> = Hmac::from_engine(hmac_engine);
|
||||||
hmac.raw_result(&mut hmac_raw);
|
SecretKey::from_slice(&hmac_result[..]).map_err(Error::BadTweak)
|
||||||
SecretKey::from_slice(&hmac_raw).map_err(Error::BadTweak)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Tweak a secret key using some arbitrary data (calls `compute_tweak` internally)
|
/// Tweak a secret key using some arbitrary data (calls `compute_tweak` internally)
|
||||||
|
@ -218,7 +212,7 @@ pub fn create_address<C: secp256k1::Verification>(secp: &Secp256k1<C>,
|
||||||
Ok(address::Address {
|
Ok(address::Address {
|
||||||
network: network,
|
network: network,
|
||||||
payload: address::Payload::ScriptHash(
|
payload: address::Payload::ScriptHash(
|
||||||
hash::Hash160::from_data(&script[..])
|
hash160::Hash::hash(&script[..])
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
501
src/util/hash.rs
501
src/util/hash.rs
|
@ -15,386 +15,22 @@
|
||||||
//!
|
//!
|
||||||
//! Utility functions related to hashing data, including merkleization
|
//! Utility functions related to hashing data, including merkleization
|
||||||
|
|
||||||
use std::char::from_digit;
|
|
||||||
use std::cmp::min;
|
use std::cmp::min;
|
||||||
use std::default::Default;
|
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 bitcoin_hashes::{sha256d, Hash};
|
||||||
use crypto::ripemd160::Ripemd160;
|
|
||||||
|
|
||||||
use consensus::encode::{Encodable, Decodable};
|
use consensus::encode::Encodable;
|
||||||
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<usize> {
|
|
||||||
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<Sha256dHash, HexError> {
|
|
||||||
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<D>(deserializer: D) -> Result<Self, D::Error>
|
|
||||||
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<E>(self, v: &str) -> Result<Self::Value, E>
|
|
||||||
where
|
|
||||||
E: serde::de::Error,
|
|
||||||
{
|
|
||||||
Sha256dHash::from_hex(v).map_err(E::custom)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn visit_borrowed_str<E>(self, v: &'de str) -> Result<Self::Value, E>
|
|
||||||
where
|
|
||||||
E: serde::de::Error,
|
|
||||||
{
|
|
||||||
self.visit_str(v)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
|
|
||||||
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<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
|
||||||
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<Self, <Self as FromStr>::Err> {
|
|
||||||
Sha256dHash::from_hex(s)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Any collection of objects for which a merkle root makes sense to calculate
|
/// Any collection of objects for which a merkle root makes sense to calculate
|
||||||
pub trait MerkleRoot {
|
pub trait MerkleRoot {
|
||||||
/// Construct a merkle tree from a collection, with elements ordered as
|
/// Construct a merkle tree from a collection, with elements ordered as
|
||||||
/// they were in the original collection, and return the merkle root.
|
/// 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
|
/// Calculates the merkle root of a list of txids hashes directly
|
||||||
pub fn bitcoin_merkle_root(data: Vec<Sha256dHash>) -> Sha256dHash {
|
pub fn bitcoin_merkle_root(data: Vec<sha256d::Hash>) -> sha256d::Hash {
|
||||||
// Base case
|
// Base case
|
||||||
if data.len() < 1 {
|
if data.len() < 1 {
|
||||||
return Default::default();
|
return Default::default();
|
||||||
|
@ -407,22 +43,22 @@ pub fn bitcoin_merkle_root(data: Vec<Sha256dHash>) -> Sha256dHash {
|
||||||
for idx in 0..((data.len() + 1) / 2) {
|
for idx in 0..((data.len() + 1) / 2) {
|
||||||
let idx1 = 2 * idx;
|
let idx1 = 2 * idx;
|
||||||
let idx2 = min(idx1 + 1, data.len() - 1);
|
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[idx1].consensus_encode(&mut encoder).unwrap();
|
||||||
data[idx2].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)
|
bitcoin_merkle_root(next)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T: BitcoinHash> MerkleRoot for &'a [T] {
|
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())
|
bitcoin_merkle_root(self.iter().map(|obj| obj.bitcoin_hash()).collect())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl <T: BitcoinHash> MerkleRoot for Vec<T> {
|
impl <T: BitcoinHash> MerkleRoot for Vec<T> {
|
||||||
fn merkle_root(&self) -> Sha256dHash {
|
fn merkle_root(&self) -> sha256d::Hash {
|
||||||
(&self[..]).merkle_root()
|
(&self[..]).merkle_root()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -430,124 +66,5 @@ impl <T: BitcoinHash> MerkleRoot for Vec<T> {
|
||||||
/// Objects which are referred to by hash
|
/// Objects which are referred to by hash
|
||||||
pub trait BitcoinHash {
|
pub trait BitcoinHash {
|
||||||
/// Produces a Sha256dHash which can be used to refer to the object
|
/// 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));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue