2014-07-18 13:56:17 +00:00
|
|
|
// Rust Bitcoin Library
|
|
|
|
// Written in 2014 by
|
|
|
|
// Andrew Poelstra <apoelstra@wpsoftware.net>
|
|
|
|
// 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/>.
|
|
|
|
//
|
|
|
|
|
|
|
|
//! # Hash functions
|
|
|
|
//!
|
|
|
|
//! 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;
|
2014-07-18 13:56:17 +00:00
|
|
|
use std::fmt;
|
2015-04-04 17:56:40 +00:00
|
|
|
use std::io::Cursor;
|
2014-07-18 13:56:17 +00:00
|
|
|
use std::mem::transmute;
|
2014-08-06 02:08:06 +00:00
|
|
|
use std::hash;
|
2015-04-06 00:10:37 +00:00
|
|
|
use serde;
|
2014-07-18 13:56:17 +00:00
|
|
|
|
2015-03-26 19:21:48 +00:00
|
|
|
use byteorder::{ByteOrder, LittleEndian};
|
2014-07-18 13:56:17 +00:00
|
|
|
use crypto::digest::Digest;
|
2014-09-01 16:24:17 +00:00
|
|
|
use crypto::sha2::Sha256;
|
|
|
|
use crypto::ripemd160::Ripemd160;
|
2014-07-18 13:56:17 +00:00
|
|
|
|
2014-08-01 16:01:39 +00:00
|
|
|
use network::encodable::{ConsensusDecodable, ConsensusEncodable};
|
2014-08-22 18:32:42 +00:00
|
|
|
use network::serialize::{RawEncoder, BitcoinHash, SimpleDecoder};
|
2014-07-18 13:56:17 +00:00
|
|
|
use util::uint::Uint256;
|
|
|
|
|
|
|
|
/// 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
|
|
|
|
2015-03-26 15:35:31 +00:00
|
|
|
impl ::std::fmt::Debug for Sha256dHash {
|
2014-08-31 16:50:46 +00:00
|
|
|
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
|
|
|
write!(f, "{}", self.be_hex_string().as_slice())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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
|
|
|
|
2014-08-22 18:32:42 +00:00
|
|
|
/// A 32-bit hash obtained by truncating a real hash
|
2015-03-26 15:35:31 +00:00
|
|
|
#[derive(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-03-26 15:35:31 +00:00
|
|
|
#[derive(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-03-26 15:35:31 +00:00
|
|
|
#[derive(Clone, PartialEq, Eq, Debug)]
|
2014-08-22 18:32:42 +00:00
|
|
|
pub struct Hash64((u8, u8, u8, u8, u8, u8, u8, u8));
|
|
|
|
|
2014-09-01 16:24:17 +00:00
|
|
|
impl Ripemd160Hash {
|
|
|
|
/// Create a hash by hashing some data
|
|
|
|
pub fn from_data(data: &[u8]) -> Ripemd160Hash {
|
2015-01-18 18:16:01 +00:00
|
|
|
let mut ret = [0; 20];
|
2014-09-01 16:24:17 +00:00
|
|
|
let mut rmd = Ripemd160::new();
|
|
|
|
rmd.input(data);
|
|
|
|
rmd.result(ret.as_mut_slice());
|
|
|
|
Ripemd160Hash(ret)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// This doesn't make much sense to me, but is implicit behaviour
|
|
|
|
// in the C++ reference client
|
2014-08-06 02:08:06 +00:00
|
|
|
impl Default for Sha256dHash {
|
|
|
|
#[inline]
|
2015-01-18 18:16:01 +00:00
|
|
|
fn default() -> Sha256dHash { Sha256dHash([0u8; 32]) }
|
2014-08-06 02:08:06 +00:00
|
|
|
}
|
2014-07-18 13:56:17 +00:00
|
|
|
|
|
|
|
impl Sha256dHash {
|
|
|
|
/// Create a hash by hashing some data
|
|
|
|
pub fn from_data(data: &[u8]) -> Sha256dHash {
|
2014-08-06 02:08:06 +00:00
|
|
|
let Sha256dHash(mut ret): Sha256dHash = Default::default();
|
2014-09-01 16:24:17 +00:00
|
|
|
let mut sha2 = Sha256::new();
|
2014-07-18 13:56:17 +00:00
|
|
|
sha2.input(data);
|
|
|
|
sha2.result(ret.as_mut_slice());
|
|
|
|
sha2.reset();
|
|
|
|
sha2.input(ret.as_slice());
|
|
|
|
sha2.result(ret.as_mut_slice());
|
|
|
|
Sha256dHash(ret)
|
|
|
|
}
|
|
|
|
|
2014-08-03 21:52:59 +00:00
|
|
|
/// Converts a hash to a little-endian Uint256
|
2014-08-06 02:08:06 +00:00
|
|
|
#[inline]
|
2014-08-24 19:28:02 +00:00
|
|
|
pub fn into_le(self) -> Uint256 {
|
2014-08-01 16:01:39 +00:00
|
|
|
let Sha256dHash(data) = self;
|
2015-01-18 18:16:01 +00:00
|
|
|
let mut ret: [u64; 4] = unsafe { transmute(data) };
|
|
|
|
for x in ret.as_mut_slice().iter_mut() { *x = x.to_le(); }
|
2014-08-24 19:28:02 +00:00
|
|
|
Uint256(ret)
|
2014-07-18 13:56:17 +00:00
|
|
|
}
|
|
|
|
|
2014-08-24 19:28:02 +00:00
|
|
|
/// Converts a hash to a big-endian Uint256
|
2014-08-06 02:08:06 +00:00
|
|
|
#[inline]
|
2014-08-24 19:28:02 +00:00
|
|
|
pub fn into_be(self) -> Uint256 {
|
|
|
|
let Sha256dHash(mut data) = self;
|
|
|
|
data.reverse();
|
2015-01-18 18:16:01 +00:00
|
|
|
let mut ret: [u64; 4] = unsafe { transmute(data) };
|
|
|
|
for x in ret.iter_mut() { *x = x.to_be(); }
|
2014-08-24 19:28:02 +00:00
|
|
|
Uint256(ret)
|
2014-07-18 13:56:17 +00:00
|
|
|
}
|
|
|
|
|
2014-08-22 18:32:42 +00:00
|
|
|
/// Converts a hash to a Hash32 by truncation
|
|
|
|
#[inline]
|
|
|
|
pub fn into_hash32(self) -> Hash32 {
|
|
|
|
let Sha256dHash(data) = self;
|
|
|
|
unsafe { 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 { transmute([data[0], data[6], data[12], data[18], data[24], data[30]]) }
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Human-readable hex output
|
|
|
|
|
|
|
|
/// Converts a hash to a Hash64 by truncation
|
|
|
|
#[inline]
|
|
|
|
pub fn into_hash64(self) -> Hash64 {
|
|
|
|
let Sha256dHash(data) = self;
|
|
|
|
unsafe { transmute([data[0], data[4], data[8], data[12],
|
|
|
|
data[16], data[20], data[24], data[28]]) }
|
|
|
|
}
|
|
|
|
|
2014-07-18 13:56:17 +00:00
|
|
|
/// Human-readable hex output
|
|
|
|
pub fn le_hex_string(&self) -> String {
|
|
|
|
let &Sha256dHash(data) = self;
|
|
|
|
let mut ret = String::with_capacity(64);
|
2015-04-05 17:58:49 +00:00
|
|
|
for i in 0..32 {
|
2015-01-18 18:16:01 +00:00
|
|
|
ret.push_char(from_digit((data[i] / 0x10) as usize, 16).unwrap());
|
|
|
|
ret.push_char(from_digit((data[i] & 0x0f) as usize, 16).unwrap());
|
2014-07-18 13:56:17 +00:00
|
|
|
}
|
|
|
|
ret
|
|
|
|
}
|
2014-08-01 17:52:10 +00:00
|
|
|
|
|
|
|
/// Human-readable hex output
|
|
|
|
pub fn be_hex_string(&self) -> String {
|
|
|
|
let &Sha256dHash(data) = self;
|
|
|
|
let mut ret = String::with_capacity(64);
|
2015-04-05 17:58:49 +00:00
|
|
|
for i in (0..32).rev() {
|
2015-01-18 18:16:01 +00:00
|
|
|
ret.push_char(from_digit((data[i] / 0x10) as usize, 16).unwrap());
|
|
|
|
ret.push_char(from_digit((data[i] & 0x0f) as usize, 16).unwrap());
|
2014-08-01 17:52:10 +00:00
|
|
|
}
|
|
|
|
ret
|
|
|
|
}
|
2014-08-01 16:01:39 +00:00
|
|
|
}
|
|
|
|
|
2014-07-29 03:12:10 +00:00
|
|
|
// 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
|
2014-08-01 16:01:39 +00:00
|
|
|
// little-endian and should be done using the consensus `encodable::ConsensusEncodable`
|
2014-07-29 03:12:10 +00:00
|
|
|
// interface.
|
2015-04-06 00:10:37 +00:00
|
|
|
impl serde::Serialize for Sha256dHash {
|
|
|
|
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
|
|
|
|
where S: serde::Serializer,
|
|
|
|
{
|
|
|
|
serializer.visit_str(&self.be_hex_string())
|
2014-08-01 17:52:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-04-06 00:10:37 +00:00
|
|
|
impl serde::Deserialize for Sha256dHash {
|
2014-08-01 17:52:10 +00:00
|
|
|
#[inline]
|
2015-04-06 00:10:37 +00:00
|
|
|
fn deserialize<D>(d: &mut D) -> Result<Sha256dHash, D::Error>
|
|
|
|
where D: serde::Deserializer
|
|
|
|
{
|
2014-08-01 17:52:10 +00:00
|
|
|
use serialize::hex::FromHex;
|
|
|
|
|
2015-04-06 00:10:37 +00:00
|
|
|
struct Sha256dHashVisitor;
|
|
|
|
impl serde::de::Visitor for Sha256dHashVisitor {
|
|
|
|
type Value = Sha256dHash;
|
|
|
|
|
|
|
|
fn visit_string<E>(&mut self, v: String) -> Result<Sha256dHash, E>
|
|
|
|
where E: serde::de::Error
|
|
|
|
{
|
|
|
|
self.visit_str(&v)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn visit_str<E>(&mut self, hex_str: &str) -> Result<Sha256dHash, E>
|
|
|
|
where E: serde::de::Error
|
|
|
|
{
|
|
|
|
if hex_str.len() != 64 {
|
|
|
|
return Err(serde::de::Error::syntax_error());
|
|
|
|
}
|
|
|
|
let raw_str = try!(hex_str.as_slice().from_hex()
|
|
|
|
.map_err(|_| serde::de::Error::syntax_error()));
|
|
|
|
let mut ret = [0u8; 32];
|
|
|
|
for i in 0..32 {
|
|
|
|
ret[i] = raw_str[31 - i];
|
|
|
|
}
|
|
|
|
Ok(Sha256dHash(ret))
|
|
|
|
}
|
2014-08-01 17:52:10 +00:00
|
|
|
}
|
2015-04-06 00:10:37 +00:00
|
|
|
|
|
|
|
d.visit(Sha256dHashVisitor)
|
2014-08-01 17:52:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Consensus encoding (little-endian)
|
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
|
|
|
|
|
|
|
impl fmt::LowerHex for Sha256dHash {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
2014-08-10 19:58:15 +00:00
|
|
|
let &Sha256dHash(data) = self;
|
2015-01-18 18:16:01 +00:00
|
|
|
let mut rv = [0; 64];
|
2014-07-18 13:56:17 +00:00
|
|
|
let mut hex = data.iter().rev().map(|n| *n).enumerate();
|
|
|
|
for (i, ch) in hex {
|
2015-01-18 18:16:01 +00:00
|
|
|
rv[2*i] = from_digit(ch as usize / 16, 16).unwrap() as u8;
|
|
|
|
rv[2*i + 1] = from_digit(ch as usize % 16, 16).unwrap() as u8;
|
2014-07-18 13:56:17 +00:00
|
|
|
}
|
|
|
|
f.write(rv.as_slice())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-19 23:03:45 +00:00
|
|
|
/// Any collection of objects for which a merkle root makes sense to calculate
|
|
|
|
pub trait MerkleRoot {
|
|
|
|
/// Construct a merkle tree from a collection, with elements ordered as
|
|
|
|
/// they were in the original collection, and return the merkle root.
|
|
|
|
fn merkle_root(&self) -> Sha256dHash;
|
|
|
|
}
|
|
|
|
|
2014-08-01 16:01:39 +00:00
|
|
|
impl<'a, T: BitcoinHash> MerkleRoot for &'a [T] {
|
2014-07-19 23:03:45 +00:00
|
|
|
fn merkle_root(&self) -> Sha256dHash {
|
2014-07-18 13:56:17 +00:00
|
|
|
fn merkle_root(data: Vec<Sha256dHash>) -> Sha256dHash {
|
|
|
|
// Base case
|
|
|
|
if data.len() < 1 {
|
2014-08-06 02:08:06 +00:00
|
|
|
return Default::default();
|
2014-07-18 13:56:17 +00:00
|
|
|
}
|
|
|
|
if data.len() < 2 {
|
|
|
|
return data[0];
|
|
|
|
}
|
|
|
|
// Recursion
|
|
|
|
let mut next = vec![];
|
2015-04-05 17:58:49 +00:00
|
|
|
for idx in 0..((data.len() + 1) / 2) {
|
2014-07-18 13:56:17 +00:00
|
|
|
let idx1 = 2 * idx;
|
|
|
|
let idx2 = min(idx1 + 1, data.len() - 1);
|
2015-04-04 17:56:40 +00:00
|
|
|
let mut encoder = RawEncoder::new(Cursor::new(vec![]));
|
2014-08-01 16:01:39 +00:00
|
|
|
data[idx1].consensus_encode(&mut encoder).unwrap();
|
|
|
|
data[idx2].consensus_encode(&mut encoder).unwrap();
|
|
|
|
next.push(encoder.unwrap().unwrap().bitcoin_hash());
|
2014-07-18 13:56:17 +00:00
|
|
|
}
|
|
|
|
merkle_root(next)
|
|
|
|
}
|
2014-07-19 23:03:45 +00:00
|
|
|
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> {
|
2014-07-19 23:03:45 +00:00
|
|
|
fn merkle_root(&self) -> Sha256dHash {
|
|
|
|
self.as_slice().merkle_root()
|
|
|
|
}
|
|
|
|
}
|
2014-07-18 13:56:17 +00:00
|
|
|
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
use std::prelude::*;
|
2015-04-04 17:56:40 +00:00
|
|
|
use std::io::Cursor;
|
2014-08-01 17:52:10 +00:00
|
|
|
use std::str::from_utf8;
|
|
|
|
use serialize::Encodable;
|
|
|
|
use serialize::json;
|
2014-08-03 21:52:59 +00:00
|
|
|
|
|
|
|
use network::serialize::{serialize, deserialize};
|
2014-07-18 13:56:17 +00:00
|
|
|
use util::hash::Sha256dHash;
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_sha256d() {
|
2014-08-03 21:52:59 +00:00
|
|
|
// 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
|
2014-07-18 13:56:17 +00:00
|
|
|
assert_eq!(Sha256dHash::from_data(&[]).le_hex_string(),
|
2014-08-03 21:52:59 +00:00
|
|
|
"5df6e0e2761359d30a8275058e299fcc0381534545f55cf43e41983f5d4c9456".to_string());
|
|
|
|
assert_eq!(Sha256dHash::from_data(&[]).be_hex_string(),
|
2014-07-18 13:56:17 +00:00
|
|
|
"56944c5d3f98413ef45cf54545538103cc9f298e0575820ad3591376e2e0f65d".to_string());
|
2014-08-03 21:52:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_consenus_encode_roundtrip() {
|
|
|
|
let hash = Sha256dHash::from_data(&[]);
|
|
|
|
let serial = serialize(&hash).unwrap();
|
|
|
|
let deserial = deserialize(serial).unwrap();
|
|
|
|
assert_eq!(hash, deserial);
|
2014-07-18 13:56:17 +00:00
|
|
|
}
|
|
|
|
|
2014-08-01 17:52:10 +00:00
|
|
|
#[test]
|
|
|
|
fn test_hash_encode_decode() {
|
|
|
|
let hash = Sha256dHash::from_data(&[]);
|
2015-04-04 17:56:40 +00:00
|
|
|
let mut writer = Cursor::new(vec![]);
|
2014-08-01 17:52:10 +00:00
|
|
|
{
|
|
|
|
let mut encoder = json::Encoder::new(&mut writer);
|
|
|
|
assert!(hash.encode(&mut encoder).is_ok());
|
|
|
|
}
|
|
|
|
let res = writer.unwrap();
|
|
|
|
assert_eq!(res.as_slice(),
|
2014-08-06 02:08:06 +00:00
|
|
|
"\"56944c5d3f98413ef45cf54545538103cc9f298e0575820ad3591376e2e0f65d\"".as_bytes());
|
2014-08-01 17:52:10 +00:00
|
|
|
assert_eq!(json::decode(from_utf8(res.as_slice()).unwrap()), Ok(hash));
|
|
|
|
}
|
2014-08-24 19:28:02 +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]);
|
|
|
|
assert_eq!(Some(one.into_le()), FromPrimitive::from_u64(1));
|
|
|
|
assert_eq!(Some(one.into_le().low_128()), FromPrimitive::from_u64(1));
|
|
|
|
}
|
2014-07-18 13:56:17 +00:00
|
|
|
}
|
|
|
|
|