2014-07-18 13:56:17 +00:00
|
|
|
// Rust Bitcoin Library
|
|
|
|
// Written in 2014 by
|
2015-04-07 22:51:57 +00:00
|
|
|
// Andrew Poelstra <apoelstra@wpsoftware.net>
|
2014-07-18 13:56:17 +00:00
|
|
|
// To the extent possible under law, the author(s) have dedicated all
|
|
|
|
// copyright and related and neighboring rights to this software to
|
|
|
|
// the public domain worldwide. This software is distributed without
|
|
|
|
// any warranty.
|
|
|
|
//
|
|
|
|
// You should have received a copy of the CC0 Public Domain Dedication
|
|
|
|
// along with this software.
|
|
|
|
// If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
|
|
|
|
//
|
|
|
|
|
2018-08-08 21:38:50 +00:00
|
|
|
//! Hash functions
|
2014-07-18 13:56:17 +00:00
|
|
|
//!
|
|
|
|
//! Utility functions related to hashing data, including merkleization
|
|
|
|
|
2015-04-05 17:58:49 +00:00
|
|
|
use std::char::from_digit;
|
|
|
|
use std::cmp::min;
|
2014-07-20 23:52:00 +00:00
|
|
|
use std::default::Default;
|
2015-11-30 16:26:13 +00:00
|
|
|
use std::error;
|
2016-05-27 18:36:42 +00:00
|
|
|
use std::fmt;
|
2018-09-16 21:36:46 +00:00
|
|
|
use std::io::{self, Write};
|
2015-11-30 16:26:13 +00:00
|
|
|
use std::mem;
|
2018-08-20 16:37:19 +00:00
|
|
|
#[cfg(feature = "serde")] use serde;
|
2014-07-18 13:56:17 +00:00
|
|
|
|
|
|
|
use crypto::digest::Digest;
|
2014-09-01 16:24:17 +00:00
|
|
|
use crypto::ripemd160::Ripemd160;
|
2019-01-16 20:45:31 +00:00
|
|
|
use bitcoin_hashes::{sha256d, Hash};
|
2014-07-18 13:56:17 +00:00
|
|
|
|
2018-09-16 21:36:46 +00:00
|
|
|
use consensus::encode::{Encodable, Decodable};
|
2014-07-18 13:56:17 +00:00
|
|
|
use util::uint::Uint256;
|
|
|
|
|
2018-12-04 00:31:13 +00:00
|
|
|
#[cfg(feature="fuzztarget")] use fuzz_util::sha2::Sha256;
|
2018-03-20 16:05:33 +00:00
|
|
|
#[cfg(not(feature="fuzztarget"))] use crypto::sha2::Sha256;
|
2018-09-20 01:09:55 +00:00
|
|
|
use std::str::FromStr;
|
2018-03-20 16:05:33 +00:00
|
|
|
|
2015-11-30 16:26:13 +00:00
|
|
|
/// 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"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-18 13:56:17 +00:00
|
|
|
/// A Bitcoin hash, 32-bytes, computed from x as SHA256(SHA256(x))
|
2015-01-18 18:16:01 +00:00
|
|
|
pub struct Sha256dHash([u8; 32]);
|
|
|
|
impl_array_newtype!(Sha256dHash, u8, 32);
|
2014-08-06 02:08:06 +00:00
|
|
|
|
2017-12-06 16:46:31 +00:00
|
|
|
/// An object that allows serializing data into a sha256d
|
|
|
|
pub struct Sha256dEncoder(Sha256);
|
|
|
|
|
2014-08-06 02:08:06 +00:00
|
|
|
/// A RIPEMD-160 hash
|
2015-01-18 18:16:01 +00:00
|
|
|
pub struct Ripemd160Hash([u8; 20]);
|
|
|
|
impl_array_newtype!(Ripemd160Hash, u8, 20);
|
2014-08-06 02:08:06 +00:00
|
|
|
|
2015-10-14 20:29:19 +00:00
|
|
|
/// A Bitcoin hash160, 20-bytes, computed from x as RIPEMD160(SHA256(x))
|
|
|
|
pub struct Hash160([u8; 20]);
|
|
|
|
impl_array_newtype!(Hash160, u8, 20);
|
|
|
|
|
2014-08-22 18:32:42 +00:00
|
|
|
/// A 32-bit hash obtained by truncating a real hash
|
2015-04-10 23:15:57 +00:00
|
|
|
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
2014-08-22 18:32:42 +00:00
|
|
|
pub struct Hash32((u8, u8, u8, u8));
|
|
|
|
|
|
|
|
/// A 48-bit hash obtained by truncating a real hash
|
2015-04-10 23:15:57 +00:00
|
|
|
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
2014-08-22 18:32:42 +00:00
|
|
|
pub struct Hash48((u8, u8, u8, u8, u8, u8));
|
|
|
|
|
|
|
|
/// A 64-bit hash obtained by truncating a real hash
|
2015-04-10 23:15:57 +00:00
|
|
|
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
2014-08-22 18:32:42 +00:00
|
|
|
pub struct Hash64((u8, u8, u8, u8, u8, u8, u8, u8));
|
|
|
|
|
2017-12-06 16:46:31 +00:00
|
|
|
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)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-09-16 21:36:46 +00:00
|
|
|
impl Write for Sha256dEncoder {
|
|
|
|
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
|
|
|
self.0.input(buf);
|
|
|
|
Ok(buf.len())
|
2017-12-06 16:46:31 +00:00
|
|
|
}
|
|
|
|
|
2018-09-16 21:36:46 +00:00
|
|
|
fn flush(&mut self) -> io::Result<()> {
|
2017-12-06 16:46:31 +00:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-09-01 16:24:17 +00:00
|
|
|
impl Ripemd160Hash {
|
2015-04-07 22:51:57 +00:00
|
|
|
/// 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)
|
|
|
|
}
|
2014-09-01 16:24:17 +00:00
|
|
|
}
|
|
|
|
|
2015-10-14 20:29:19 +00:00
|
|
|
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)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-09-01 16:24:17 +00:00
|
|
|
// This doesn't make much sense to me, but is implicit behaviour
|
2015-10-14 20:29:19 +00:00
|
|
|
// in the C++ reference client, so we need it for consensus.
|
2014-08-06 02:08:06 +00:00
|
|
|
impl Default for Sha256dHash {
|
2015-04-07 22:51:57 +00:00
|
|
|
#[inline]
|
|
|
|
fn default() -> Sha256dHash { Sha256dHash([0u8; 32]) }
|
2014-08-06 02:08:06 +00:00
|
|
|
}
|
2014-07-18 13:56:17 +00:00
|
|
|
|
|
|
|
impl Sha256dHash {
|
2015-04-07 22:51:57 +00:00
|
|
|
/// 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;
|
2015-11-30 16:26:13 +00:00
|
|
|
let mut ret: [u64; 4] = unsafe { mem::transmute(data) };
|
2015-04-07 22:51:57 +00:00
|
|
|
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();
|
2015-11-30 16:26:13 +00:00
|
|
|
let mut ret: [u64; 4] = unsafe { mem::transmute(data) };
|
2015-04-07 22:51:57 +00:00
|
|
|
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;
|
2015-11-30 16:26:13 +00:00
|
|
|
unsafe { mem::transmute([data[0], data[8], data[16], data[24]]) }
|
2015-04-07 22:51:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Converts a hash to a Hash48 by truncation
|
|
|
|
#[inline]
|
|
|
|
pub fn into_hash48(self) -> Hash48 {
|
|
|
|
let Sha256dHash(data) = self;
|
2015-11-30 16:26:13 +00:00
|
|
|
unsafe { mem::transmute([data[0], data[6], data[12], data[18], data[24], data[30]]) }
|
2014-07-18 13:56:17 +00:00
|
|
|
}
|
2015-04-07 22:51:57 +00:00
|
|
|
|
2015-11-30 16:26:13 +00:00
|
|
|
// Human-readable hex output
|
|
|
|
|
|
|
|
/// Decodes a big-endian (i.e. reversed vs sha256sum output) hex string as a Sha256dHash
|
|
|
|
#[inline]
|
2016-02-18 19:25:40 +00:00
|
|
|
pub fn from_hex(s: &str) -> Result<Sha256dHash, HexError> {
|
2015-11-30 16:26:13 +00:00
|
|
|
if s.len() != 64 {
|
|
|
|
return Err(HexError::BadLength(s.len()));
|
|
|
|
}
|
|
|
|
|
|
|
|
let bytes = s.as_bytes();
|
2018-02-14 16:44:02 +00:00
|
|
|
let mut ret = [0; 32];
|
2015-11-30 16:26:13 +00:00
|
|
|
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))
|
|
|
|
}
|
2015-04-07 22:51:57 +00:00
|
|
|
|
|
|
|
/// Converts a hash to a Hash64 by truncation
|
|
|
|
#[inline]
|
|
|
|
pub fn into_hash64(self) -> Hash64 {
|
|
|
|
let Sha256dHash(data) = self;
|
2015-11-30 16:26:13 +00:00
|
|
|
unsafe { mem::transmute([data[0], data[4], data[8], data[12],
|
2015-04-07 22:51:57 +00:00
|
|
|
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);
|
2016-02-18 19:25:40 +00:00
|
|
|
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());
|
2015-04-07 22:51:57 +00:00
|
|
|
}
|
|
|
|
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
|
2014-08-01 17:52:10 +00:00
|
|
|
}
|
2014-08-01 16:01:39 +00:00
|
|
|
}
|
|
|
|
|
2018-08-20 16:37:19 +00:00
|
|
|
#[cfg(feature = "serde")]
|
|
|
|
impl<'de> serde::Deserialize<'de> for Sha256dHash {
|
2015-04-07 22:51:57 +00:00
|
|
|
#[inline]
|
2018-08-20 16:37:19 +00:00
|
|
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
|
|
|
where
|
|
|
|
D: serde::Deserializer<'de>,
|
2015-04-07 22:51:57 +00:00
|
|
|
{
|
2018-08-20 16:37:19 +00:00
|
|
|
use std::fmt::{self, Formatter};
|
|
|
|
|
|
|
|
struct Visitor;
|
|
|
|
impl<'de> serde::de::Visitor<'de> for Visitor {
|
2015-04-07 22:51:57 +00:00
|
|
|
type Value = Sha256dHash;
|
|
|
|
|
2018-08-20 16:37:19 +00:00
|
|
|
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,
|
2015-04-07 22:51:57 +00:00
|
|
|
{
|
2018-08-20 16:37:19 +00:00
|
|
|
Sha256dHash::from_hex(v).map_err(E::custom)
|
2015-04-07 22:51:57 +00:00
|
|
|
}
|
|
|
|
|
2018-08-20 16:37:19 +00:00
|
|
|
fn visit_borrowed_str<E>(self, v: &'de str) -> Result<Self::Value, E>
|
|
|
|
where
|
|
|
|
E: serde::de::Error,
|
2015-04-07 22:51:57 +00:00
|
|
|
{
|
2018-08-20 16:37:19 +00:00
|
|
|
self.visit_str(v)
|
2015-04-07 22:51:57 +00:00
|
|
|
}
|
2018-08-20 16:37:19 +00:00
|
|
|
|
|
|
|
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
|
Move relevant names into consensus::encode
- Move network::encodable::* to consensus::encode::*
- Rename Consensus{En,De}codable to {En,De}codable (now under
consensus::encode)
- Move network::serialize::Error to consensus::encode::Error
- Remove Raw{En,De}coder, implement {En,De}coder for T: {Write,Read}
instead
- Move network::serialize::Simple{En,De}coder to
consensus::encode::{En,De}coder
- Rename util::Error::Serialize to util::Error::Encode
- Modify comments to refer to new names
- Modify files to refer to new names
- Expose {En,De}cod{able,er}, {de,}serialize, Params
- Do not return Result for serialize{,_hex} as serializing to a Vec
should never fail
2018-09-20 10:15:45 +00:00
|
|
|
/// [`Encodable`][1] interface.
|
2018-08-20 16:37:19 +00:00
|
|
|
///
|
Move relevant names into consensus::encode
- Move network::encodable::* to consensus::encode::*
- Rename Consensus{En,De}codable to {En,De}codable (now under
consensus::encode)
- Move network::serialize::Error to consensus::encode::Error
- Remove Raw{En,De}coder, implement {En,De}coder for T: {Write,Read}
instead
- Move network::serialize::Simple{En,De}coder to
consensus::encode::{En,De}coder
- Rename util::Error::Serialize to util::Error::Encode
- Modify comments to refer to new names
- Modify files to refer to new names
- Expose {En,De}cod{able,er}, {de,}serialize, Params
- Do not return Result for serialize{,_hex} as serializing to a Vec
should never fail
2018-09-20 10:15:45 +00:00
|
|
|
/// [1]: ../../network/encodable/trait.Encodable.html
|
2018-08-20 16:37:19 +00:00
|
|
|
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;
|
2015-04-06 00:10:37 +00:00
|
|
|
}
|
|
|
|
|
2018-08-20 16:37:19 +00:00
|
|
|
let hex_str = unsafe { str::from_utf8_unchecked(&string) };
|
|
|
|
serializer.serialize_str(hex_str)
|
2015-04-07 22:51:57 +00:00
|
|
|
}
|
2014-08-01 17:52:10 +00:00
|
|
|
}
|
|
|
|
|
2019-01-21 22:00:46 +00:00
|
|
|
// Debug encodings
|
2018-03-09 18:08:13 +00:00
|
|
|
impl fmt::Debug for Sha256dHash {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
2019-01-21 22:00:46 +00:00
|
|
|
fmt::LowerHex::fmt(self, f)
|
2018-03-09 18:08:13 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl fmt::Debug for Hash160 {
|
2018-03-12 20:02:21 +00:00
|
|
|
/// Output the raw hash160 hash, not reversing it (nothing reverses the output of ripemd160 in Bitcoin)
|
2018-03-09 18:08:13 +00:00
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
let &Hash160(data) = self;
|
|
|
|
for ch in data.iter() {
|
2018-08-12 16:47:31 +00:00
|
|
|
write!(f, "{:02x}", ch)?;
|
2018-03-09 18:08:13 +00:00
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Consensus encoding (no reversing)
|
2015-01-18 18:16:01 +00:00
|
|
|
impl_newtype_consensus_encoding!(Hash32);
|
|
|
|
impl_newtype_consensus_encoding!(Hash48);
|
|
|
|
impl_newtype_consensus_encoding!(Hash64);
|
|
|
|
impl_newtype_consensus_encoding!(Sha256dHash);
|
2014-07-18 13:56:17 +00:00
|
|
|
|
2018-03-09 18:08:13 +00:00
|
|
|
// User RPC/display encoding (reversed)
|
2015-11-30 15:19:53 +00:00
|
|
|
impl fmt::Display for Sha256dHash {
|
2018-03-12 20:02:21 +00:00
|
|
|
/// Output the sha256d hash in reverse, copying Bitcoin Core's behaviour
|
2015-11-30 15:19:53 +00:00
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::LowerHex::fmt(self, f) }
|
|
|
|
}
|
|
|
|
|
2014-07-18 13:56:17 +00:00
|
|
|
impl fmt::LowerHex for Sha256dHash {
|
2018-03-12 20:02:21 +00:00
|
|
|
/// Output the sha256d hash in reverse, copying Bitcoin Core's behaviour
|
2015-04-07 22:51:57 +00:00
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
let &Sha256dHash(data) = self;
|
|
|
|
for ch in data.iter().rev() {
|
2018-08-12 16:47:31 +00:00
|
|
|
write!(f, "{:02x}", ch)?;
|
2015-04-07 22:51:57 +00:00
|
|
|
}
|
|
|
|
Ok(())
|
2014-07-18 13:56:17 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-30 15:19:53 +00:00
|
|
|
impl fmt::UpperHex for Sha256dHash {
|
2018-03-12 20:02:21 +00:00
|
|
|
/// Output the sha256d hash in reverse, copying Bitcoin Core's behaviour
|
2015-11-30 15:19:53 +00:00
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
let &Sha256dHash(data) = self;
|
|
|
|
for ch in data.iter().rev() {
|
2018-08-12 16:47:31 +00:00
|
|
|
write!(f, "{:02X}", ch)?;
|
2015-11-30 15:19:53 +00:00
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-09-20 01:09:55 +00:00
|
|
|
impl FromStr for Sha256dHash {
|
|
|
|
type Err = HexError;
|
|
|
|
|
|
|
|
fn from_str(s: &str) -> Result<Self, <Self as FromStr>::Err> {
|
|
|
|
Sha256dHash::from_hex(s)
|
|
|
|
}
|
|
|
|
}
|
2015-11-30 15:19:53 +00:00
|
|
|
|
2014-07-19 23:03:45 +00:00
|
|
|
/// Any collection of objects for which a merkle root makes sense to calculate
|
|
|
|
pub trait MerkleRoot {
|
2015-04-07 22:51:57 +00:00
|
|
|
/// Construct a merkle tree from a collection, with elements ordered as
|
|
|
|
/// they were in the original collection, and return the merkle root.
|
2019-01-16 20:45:31 +00:00
|
|
|
fn merkle_root(&self) -> sha256d::Hash;
|
2014-07-19 23:03:45 +00:00
|
|
|
}
|
|
|
|
|
2018-06-01 22:46:10 +00:00
|
|
|
/// Calculates the merkle root of a list of txids hashes directly
|
2019-01-16 20:45:31 +00:00
|
|
|
pub fn bitcoin_merkle_root(data: Vec<sha256d::Hash>) -> sha256d::Hash {
|
2018-06-01 22:46:10 +00:00
|
|
|
// Base case
|
|
|
|
if data.len() < 1 {
|
|
|
|
return Default::default();
|
|
|
|
}
|
|
|
|
if data.len() < 2 {
|
|
|
|
return data[0];
|
|
|
|
}
|
|
|
|
// Recursion
|
|
|
|
let mut next = vec![];
|
|
|
|
for idx in 0..((data.len() + 1) / 2) {
|
|
|
|
let idx1 = 2 * idx;
|
|
|
|
let idx2 = min(idx1 + 1, data.len() - 1);
|
2019-01-16 20:45:31 +00:00
|
|
|
let mut encoder = sha256d::Hash::engine();
|
2018-06-01 22:46:10 +00:00
|
|
|
data[idx1].consensus_encode(&mut encoder).unwrap();
|
|
|
|
data[idx2].consensus_encode(&mut encoder).unwrap();
|
2019-01-16 20:45:31 +00:00
|
|
|
next.push(sha256d::Hash::from_engine(encoder));
|
2018-06-01 22:46:10 +00:00
|
|
|
}
|
|
|
|
bitcoin_merkle_root(next)
|
|
|
|
}
|
|
|
|
|
2014-08-01 16:01:39 +00:00
|
|
|
impl<'a, T: BitcoinHash> MerkleRoot for &'a [T] {
|
2019-01-16 20:45:31 +00:00
|
|
|
fn merkle_root(&self) -> sha256d::Hash {
|
2018-06-01 22:46:10 +00:00
|
|
|
bitcoin_merkle_root(self.iter().map(|obj| obj.bitcoin_hash()).collect())
|
2014-07-18 13:56:17 +00:00
|
|
|
}
|
2014-07-19 23:03:45 +00:00
|
|
|
}
|
|
|
|
|
2014-08-01 16:01:39 +00:00
|
|
|
impl <T: BitcoinHash> MerkleRoot for Vec<T> {
|
2019-01-16 20:45:31 +00:00
|
|
|
fn merkle_root(&self) -> sha256d::Hash {
|
2015-04-07 22:51:57 +00:00
|
|
|
(&self[..]).merkle_root()
|
|
|
|
}
|
2014-07-19 23:03:45 +00:00
|
|
|
}
|
2014-07-18 13:56:17 +00:00
|
|
|
|
2018-09-03 05:41:08 +00:00
|
|
|
/// Objects which are referred to by hash
|
|
|
|
pub trait BitcoinHash {
|
|
|
|
/// Produces a Sha256dHash which can be used to refer to the object
|
2019-01-16 20:45:31 +00:00
|
|
|
fn bitcoin_hash(&self) -> sha256d::Hash;
|
2018-09-03 05:41:08 +00:00
|
|
|
}
|
2014-07-18 13:56:17 +00:00
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
2018-08-20 16:37:19 +00:00
|
|
|
#[cfg(all(feature = "serde", feature = "strason"))]
|
|
|
|
use strason::Json;
|
2015-04-07 22:51:57 +00:00
|
|
|
|
Move relevant names into consensus::encode
- Move network::encodable::* to consensus::encode::*
- Rename Consensus{En,De}codable to {En,De}codable (now under
consensus::encode)
- Move network::serialize::Error to consensus::encode::Error
- Remove Raw{En,De}coder, implement {En,De}coder for T: {Write,Read}
instead
- Move network::serialize::Simple{En,De}coder to
consensus::encode::{En,De}coder
- Rename util::Error::Serialize to util::Error::Encode
- Modify comments to refer to new names
- Modify files to refer to new names
- Expose {En,De}cod{able,er}, {de,}serialize, Params
- Do not return Result for serialize{,_hex} as serializing to a Vec
should never fail
2018-09-20 10:15:45 +00:00
|
|
|
use consensus::encode::{Encodable, VarInt};
|
|
|
|
use consensus::encode::{serialize, deserialize};
|
2018-02-18 15:21:05 +00:00
|
|
|
use util::uint::{Uint128, Uint256};
|
2017-12-06 16:46:31 +00:00
|
|
|
use super::*;
|
2015-04-07 22:51:57 +00:00
|
|
|
|
|
|
|
#[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(),
|
2015-11-30 15:19:53 +00:00
|
|
|
"5df6e0e2761359d30a8275058e299fcc0381534545f55cf43e41983f5d4c9456");
|
2015-04-07 22:51:57 +00:00
|
|
|
assert_eq!(Sha256dHash::from_data(&[]).be_hex_string(),
|
2015-11-30 15:19:53 +00:00
|
|
|
"56944c5d3f98413ef45cf54545538103cc9f298e0575820ad3591376e2e0f65d");
|
|
|
|
|
|
|
|
assert_eq!(format!("{}", Sha256dHash::from_data(&[])),
|
|
|
|
"56944c5d3f98413ef45cf54545538103cc9f298e0575820ad3591376e2e0f65d");
|
|
|
|
assert_eq!(format!("{:?}", Sha256dHash::from_data(&[])),
|
2019-01-21 22:00:46 +00:00
|
|
|
"56944c5d3f98413ef45cf54545538103cc9f298e0575820ad3591376e2e0f65d");
|
2015-11-30 15:19:53 +00:00
|
|
|
assert_eq!(format!("{:x}", Sha256dHash::from_data(&[])),
|
|
|
|
"56944c5d3f98413ef45cf54545538103cc9f298e0575820ad3591376e2e0f65d");
|
|
|
|
assert_eq!(format!("{:X}", Sha256dHash::from_data(&[])),
|
|
|
|
"56944C5D3F98413EF45CF54545538103CC9F298E0575820AD3591376E2E0F65D");
|
2015-04-07 22:51:57 +00:00
|
|
|
}
|
|
|
|
|
2018-09-20 01:09:55 +00:00
|
|
|
#[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)
|
|
|
|
}
|
|
|
|
|
2018-05-16 09:44:30 +00:00
|
|
|
#[test]
|
|
|
|
fn test_sha256d_data() {
|
|
|
|
assert_eq!(
|
2018-08-20 21:20:43 +00:00
|
|
|
Sha256dHash::from_data(&[]).as_bytes(),
|
|
|
|
&[
|
2018-05-16 09:44:30 +00:00
|
|
|
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,
|
|
|
|
]
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2017-12-06 16:46:31 +00:00
|
|
|
#[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());
|
Move relevant names into consensus::encode
- Move network::encodable::* to consensus::encode::*
- Rename Consensus{En,De}codable to {En,De}codable (now under
consensus::encode)
- Move network::serialize::Error to consensus::encode::Error
- Remove Raw{En,De}coder, implement {En,De}coder for T: {Write,Read}
instead
- Move network::serialize::Simple{En,De}coder to
consensus::encode::{En,De}coder
- Rename util::Error::Serialize to util::Error::Encode
- Modify comments to refer to new names
- Modify files to refer to new names
- Expose {En,De}cod{able,er}, {de,}serialize, Params
- Do not return Result for serialize{,_hex} as serializing to a Vec
should never fail
2018-09-20 10:15:45 +00:00
|
|
|
assert_eq!(enc.into_hash(), Sha256dHash::from_data(&serialize(&test)));
|
2017-12-06 16:46:31 +00:00
|
|
|
|
|
|
|
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());
|
Move relevant names into consensus::encode
- Move network::encodable::* to consensus::encode::*
- Rename Consensus{En,De}codable to {En,De}codable (now under
consensus::encode)
- Move network::serialize::Error to consensus::encode::Error
- Remove Raw{En,De}coder, implement {En,De}coder for T: {Write,Read}
instead
- Move network::serialize::Simple{En,De}coder to
consensus::encode::{En,De}coder
- Rename util::Error::Serialize to util::Error::Encode
- Modify comments to refer to new names
- Modify files to refer to new names
- Expose {En,De}cod{able,er}, {de,}serialize, Params
- Do not return Result for serialize{,_hex} as serializing to a Vec
should never fail
2018-09-20 10:15:45 +00:00
|
|
|
assert_eq!(enc.into_hash(), Sha256dHash::from_data(&serialize(&test[..])));
|
2017-12-06 16:46:31 +00:00
|
|
|
|
|
|
|
// 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());
|
|
|
|
}
|
Move relevant names into consensus::encode
- Move network::encodable::* to consensus::encode::*
- Rename Consensus{En,De}codable to {En,De}codable (now under
consensus::encode)
- Move network::serialize::Error to consensus::encode::Error
- Remove Raw{En,De}coder, implement {En,De}coder for T: {Write,Read}
instead
- Move network::serialize::Simple{En,De}coder to
consensus::encode::{En,De}coder
- Rename util::Error::Serialize to util::Error::Encode
- Modify comments to refer to new names
- Modify files to refer to new names
- Expose {En,De}cod{able,er}, {de,}serialize, Params
- Do not return Result for serialize{,_hex} as serializing to a Vec
should never fail
2018-09-20 10:15:45 +00:00
|
|
|
assert_eq!(enc.into_hash(), Sha256dHash::from_data(&serialize(&test[..])));
|
2017-12-06 16:46:31 +00:00
|
|
|
})
|
|
|
|
);
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2015-04-07 22:51:57 +00:00
|
|
|
#[test]
|
|
|
|
fn test_consenus_encode_roundtrip() {
|
|
|
|
let hash = Sha256dHash::from_data(&[]);
|
Move relevant names into consensus::encode
- Move network::encodable::* to consensus::encode::*
- Rename Consensus{En,De}codable to {En,De}codable (now under
consensus::encode)
- Move network::serialize::Error to consensus::encode::Error
- Remove Raw{En,De}coder, implement {En,De}coder for T: {Write,Read}
instead
- Move network::serialize::Simple{En,De}coder to
consensus::encode::{En,De}coder
- Rename util::Error::Serialize to util::Error::Encode
- Modify comments to refer to new names
- Modify files to refer to new names
- Expose {En,De}cod{able,er}, {de,}serialize, Params
- Do not return Result for serialize{,_hex} as serializing to a Vec
should never fail
2018-09-20 10:15:45 +00:00
|
|
|
let serial = serialize(&hash);
|
2015-04-08 22:23:45 +00:00
|
|
|
let deserial = deserialize(&serial).unwrap();
|
2015-04-07 22:51:57 +00:00
|
|
|
assert_eq!(hash, deserial);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2018-08-20 16:37:19 +00:00
|
|
|
#[cfg(all(feature = "serde", feature = "strason"))]
|
2015-04-07 22:51:57 +00:00
|
|
|
fn test_hash_encode_decode() {
|
|
|
|
let hash = Sha256dHash::from_data(&[]);
|
2018-08-20 16:37:19 +00:00
|
|
|
let encoded = Json::from_serialize(&hash).unwrap();
|
2016-02-18 18:02:04 +00:00
|
|
|
assert_eq!(encoded.to_bytes(),
|
|
|
|
"\"56944c5d3f98413ef45cf54545538103cc9f298e0575820ad3591376e2e0f65d\"".as_bytes());
|
2015-11-22 15:46:05 +00:00
|
|
|
let decoded = encoded.into_deserialize().unwrap();
|
|
|
|
assert_eq!(hash, decoded);
|
2015-04-07 22:51:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[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]);
|
2018-02-18 15:21:05 +00:00
|
|
|
assert_eq!(Some(one.into_le()), Uint256::from_u64(1));
|
|
|
|
assert_eq!(Some(one.into_le().low_128()), Uint128::from_u64(1));
|
2014-08-01 17:52:10 +00:00
|
|
|
}
|
2014-07-18 13:56:17 +00:00
|
|
|
}
|
|
|
|
|