diff --git a/core/src/core/hash.rs b/core/src/core/hash.rs new file mode 100644 index 000000000..0ed193809 --- /dev/null +++ b/core/src/core/hash.rs @@ -0,0 +1,83 @@ +// Copyright 2016 The Developers +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Hash Function +//! +//! Primary hash function used in the protocol +//! + +use std::fmt; + +use tiny_keccak::Keccak; + +/// A hash to uniquely (or close enough) identify one of the main blockchain +/// constructs. Used pervasively for blocks, transactions and ouputs. +#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +pub struct Hash(pub [u8; 32]); + +impl fmt::Display for Hash { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + for i in self.0[..].iter().cloned() { + try!(write!(f, "{:02x}", i)); + } + Ok(()) + } +} + +impl Hash { + /// Creates a new hash from a vector + pub fn from_vec(v: Vec) -> Hash { + let mut a = [0; 32]; + for i in 0..a.len() { + a[i] = v[i]; + } + Hash(a) + } + /// Converts the hash to a byte vector + pub fn to_vec(&self) -> Vec { + self.0.to_vec() + } + /// Converts the hash to a byte slice + pub fn to_slice(&self) -> &[u8] { + &self.0 + } +} + +pub const ZERO_HASH: Hash = Hash([0; 32]); + +/// A trait for types that get their hash (double SHA256) from their byte +/// serialzation. +pub trait Hashed { + fn hash(&self) -> Hash { + let data = self.bytes(); + Hash(sha3(data)) + } + + fn bytes(&self) -> Vec; +} + +fn sha3(data: Vec) -> [u8; 32] { + let mut sha3 = Keccak::new_sha3_256(); + let mut buf = [0; 32]; + sha3.update(&data); + sha3.finalize(&mut buf); + buf +} + +impl Hashed for [u8] { + fn bytes(&self) -> Vec { + self.to_owned() + } +} + diff --git a/core/src/core/mod.rs b/core/src/core/mod.rs index 6644a0565..6cf5a78bb 100644 --- a/core/src/core/mod.rs +++ b/core/src/core/mod.rs @@ -14,9 +14,12 @@ //! Core types +pub mod hash; #[allow(dead_code)] #[macro_use] mod ser; + +use self::hash::{Hash, Hashed, ZERO_HASH}; use ser::{Writeable, Writer, Error, ser_vec}; use time; @@ -41,60 +44,6 @@ pub const BLOCK_TIME_SEC: u8 = 15; /// Cuckoo-cycle proof size (cycle length) pub const PROOFSIZE: usize = 42; -/// A hash to uniquely (or close enough) identify one of the main blockchain -/// constructs. Used pervasively for blocks, transactions and ouputs. -#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] -pub struct Hash(pub [u8; 32]); - -impl fmt::Display for Hash { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - for i in self.0[..].iter().cloned() { - try!(write!(f, "{:02x}", i)); - } - Ok(()) - } -} - -impl Hash { - /// Creates a new hash from a vector - pub fn from_vec(v: Vec) -> Hash { - let mut a = [0; 32]; - for i in 0..a.len() { - a[i] = v[i]; - } - Hash(a) - } - /// Converts the hash to a byte vector - pub fn to_vec(&self) -> Vec { - self.0.to_vec() - } - /// Converts the hash to a byte slice - pub fn to_slice(&self) -> &[u8] { - &self.0 - } -} - -pub const ZERO_HASH: Hash = Hash([0; 32]); - -/// A trait for types that get their hash (double SHA256) from their byte -/// serialzation. -pub trait Hashed { - fn hash(&self) -> Hash { - let data = self.bytes(); - Hash(sha3(data)) - } - - fn bytes(&self) -> Vec; -} - -fn sha3(data: Vec) -> [u8; 32] { - let mut sha3 = Keccak::new_sha3_256(); - let mut buf = [0; 32]; - sha3.update(&data); - sha3.finalize(&mut buf); - buf -} - /// Implemented by types that hold inputs and outputs including Pedersen /// commitments. Handles the collection of the commitments as well as their /// summing, taking potential explicit overages of fees into account. @@ -755,7 +704,7 @@ impl MerkleRow { } fn root(&self) -> Hash { if self.0.len() == 0 { - Hash(sha3(vec![])) + vec![].hash() } else if self.0.len() == 1 { self.0[0].hash() } else { @@ -767,6 +716,7 @@ impl MerkleRow { #[cfg(test)] mod test { use super::*; + use super::hash::{Hash, Hashed, ZERO_HASH}; use secp; use secp::Secp256k1; use secp::key::SecretKey; diff --git a/core/src/core/ser.rs b/core/src/core/ser.rs index aabe3cc62..0a1c1124d 100644 --- a/core/src/core/ser.rs +++ b/core/src/core/ser.rs @@ -19,7 +19,7 @@ use time; use std::io::{Write, Read}; -use core; +use core::{self, hash}; use ser::*; use secp::Signature; @@ -43,7 +43,7 @@ impl_slice_bytes!(Signature); impl_slice_bytes!(Commitment); impl_slice_bytes!(Vec); -impl AsFixedBytes for core::Hash { +impl AsFixedBytes for hash::Hash { fn as_fixed_bytes(&self) -> &[u8] { self.to_slice() } @@ -124,7 +124,7 @@ impl Writeable for core::Block { impl Readable for core::Input { fn read(reader: &mut Reader) -> Result { reader.read_fixed_bytes(32) - .map(|h| core::Input::BareInput { output: core::Hash::from_vec(h) }) + .map(|h| core::Input::BareInput { output: hash::Hash::from_vec(h) }) } } @@ -210,14 +210,14 @@ impl Readable for core::Block { Ok(core::Block { header: core::BlockHeader { height: height, - previous: core::Hash::from_vec(previous), + previous: hash::Hash::from_vec(previous), timestamp: time::at_utc(time::Timespec { sec: timestamp, nsec: 0, }), td: td, - utxo_merkle: core::Hash::from_vec(utxo_merkle), - tx_merkle: core::Hash::from_vec(tx_merkle), + utxo_merkle: hash::Hash::from_vec(utxo_merkle), + tx_merkle: hash::Hash::from_vec(tx_merkle), total_fees: total_fees, pow: core::Proof(pow), nonce: nonce, @@ -237,6 +237,7 @@ mod test { use secp::*; use secp::key::*; use core::*; + use core::hash::ZERO_HASH; use rand::Rng; use rand::os::OsRng; diff --git a/core/src/genesis.rs b/core/src/genesis.rs index 02a225dd2..1fa92d7bb 100644 --- a/core/src/genesis.rs +++ b/core/src/genesis.rs @@ -31,7 +31,7 @@ pub fn genesis() -> core::Block { core::Block { header: core::BlockHeader { height: 0, - previous: core::ZERO_HASH, + previous: core::hash::ZERO_HASH, timestamp: time::Tm { tm_year: 1997, tm_mon: 7, @@ -39,8 +39,8 @@ pub fn genesis() -> core::Block { ..time::empty_tm() }, td: 0, - utxo_merkle: core::Hash::from_vec(empty_h.to_vec()), - tx_merkle: core::Hash::from_vec(empty_h.to_vec()), + utxo_merkle: core::hash::Hash::from_vec(empty_h.to_vec()), + tx_merkle: core::hash::Hash::from_vec(empty_h.to_vec()), total_fees: 0, nonce: 0, pow: core::Proof::zero(), // TODO get actual PoW solution diff --git a/core/src/pow/mod.rs b/core/src/pow/mod.rs index 7b41878c3..df1808666 100644 --- a/core/src/pow/mod.rs +++ b/core/src/pow/mod.rs @@ -27,7 +27,8 @@ mod cuckoo; use time; -use core::{Block, BlockHeader, Hashed, Hash, Proof, PROOFSIZE}; +use core::{Block, BlockHeader, Proof, PROOFSIZE}; +use core::hash::{Hash, Hashed}; use pow::cuckoo::{Cuckoo, Miner, Error}; use ser; @@ -175,7 +176,8 @@ fn pow_size(b: &Block, target: Proof, sizeshift: u32) -> Result<(Proof, u64), Er #[cfg(test)] mod test { use super::*; - use core::{BlockHeader, Hash, Proof}; + use core::{BlockHeader, Proof}; + use core::hash::Hash; use std::time::Instant; use genesis;