mirror of
https://github.com/mimblewimble/grin.git
synced 2025-01-20 19:11:08 +03:00
core: unify Hashed and Writeable to simplify things and remove allocations
This commit is contained in:
parent
245f0a8b56
commit
ca89dae7e1
6 changed files with 90 additions and 66 deletions
|
@ -26,7 +26,7 @@ use core::transaction::merkle_inputs_outputs;
|
|||
use core::{PROOFSIZE, REWARD};
|
||||
use core::hash::{Hash, Hashed, ZERO_HASH};
|
||||
use core::transaction::MAX_IN_OUT_LEN;
|
||||
use ser::{self, Readable, Reader, Writeable, Writer, ser_vec};
|
||||
use ser::{self, Readable, Reader, Writeable, Writer};
|
||||
|
||||
/// Block header, fairly standard compared to other blockchains.
|
||||
pub struct BlockHeader {
|
||||
|
@ -79,13 +79,6 @@ impl Writeable for BlockHeader {
|
|||
}
|
||||
}
|
||||
|
||||
impl Hashed for BlockHeader {
|
||||
fn bytes(&self) -> Vec<u8> {
|
||||
// no serialization errors are applicable in this specific case
|
||||
ser_vec(self).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
/// A block as expressed in the MimbleWimble protocol. The reward is
|
||||
/// non-explicit, assumed to be deductible from block height (similar to
|
||||
/// bitcoin's schedule) and expressed as a global transaction fee (added v.H),
|
||||
|
|
|
@ -17,10 +17,12 @@
|
|||
//! Primary hash function used in the protocol
|
||||
//!
|
||||
|
||||
use byteorder::{ByteOrder, WriteBytesExt, BigEndian};
|
||||
use std::fmt;
|
||||
|
||||
use tiny_keccak::Keccak;
|
||||
|
||||
use ser::{self, AsFixedBytes};
|
||||
|
||||
/// 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)]
|
||||
|
@ -56,27 +58,58 @@ impl Hash {
|
|||
|
||||
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<u8>;
|
||||
/// Serializer that outputs a hash of the serialized object
|
||||
pub struct HashWriter {
|
||||
state: Keccak
|
||||
}
|
||||
|
||||
fn sha3(data: Vec<u8>) -> [u8; 32] {
|
||||
let mut sha3 = Keccak::new_sha3_256();
|
||||
let mut buf = [0; 32];
|
||||
sha3.update(&data);
|
||||
sha3.finalize(&mut buf);
|
||||
buf
|
||||
impl HashWriter {
|
||||
fn finalize(self, output: &mut [u8]) {
|
||||
self.state.finalize(output);
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for HashWriter {
|
||||
fn default() -> HashWriter {
|
||||
HashWriter {
|
||||
state: Keccak::new_sha3_256()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ser::Writer for HashWriter {
|
||||
fn serialization_mode(&self) -> ser::SerializationMode {
|
||||
ser::SerializationMode::Hash
|
||||
}
|
||||
|
||||
fn write_fixed_bytes(&mut self, b32: &AsFixedBytes) -> Result<(), ser::Error> {
|
||||
self.state.update(b32.as_fixed_bytes());
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// A trait for types that have a canonical hash
|
||||
pub trait Hashed {
|
||||
fn hash(&self) -> Hash;
|
||||
}
|
||||
|
||||
impl<W: ser::Writeable> Hashed for W {
|
||||
fn hash(&self) -> Hash {
|
||||
let mut hasher = HashWriter::default();
|
||||
ser::Writeable::write(self, &mut hasher).unwrap();
|
||||
let mut ret = [0; 32];
|
||||
hasher.finalize(&mut ret);
|
||||
Hash(ret)
|
||||
}
|
||||
}
|
||||
|
||||
impl Hashed for [u8] {
|
||||
fn bytes(&self) -> Vec<u8> {
|
||||
self.to_owned()
|
||||
fn hash(&self) -> Hash {
|
||||
let mut hasher = HashWriter::default();
|
||||
let mut ret = [0; 32];
|
||||
ser::Writer::write_bytes(&mut hasher, &self).unwrap();
|
||||
hasher.finalize(&mut ret);
|
||||
Hash(ret)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -154,12 +154,12 @@ impl Proof {
|
|||
/// Two hashes that will get hashed together in a Merkle tree to build the next
|
||||
/// level up.
|
||||
struct HPair(Hash, Hash);
|
||||
impl Hashed for HPair {
|
||||
fn bytes(&self) -> Vec<u8> {
|
||||
let mut data = Vec::with_capacity(64);
|
||||
data.extend_from_slice(self.0.to_slice());
|
||||
data.extend_from_slice(self.1.to_slice());
|
||||
return data;
|
||||
|
||||
impl Writeable for HPair {
|
||||
fn write(&self, writer: &mut Writer) -> Result<(), Error> {
|
||||
try!(writer.write_bytes(&self.0.to_slice()));
|
||||
try!(writer.write_bytes(&self.1.to_slice()));
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
/// An iterator over hashes in a vector that pairs them to build a row in a
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
|
||||
use core::Committed;
|
||||
use core::MerkleRow;
|
||||
use core::hash::{Hashed, Hash};
|
||||
use core::hash::{Hash, Hashed};
|
||||
use ser::{self, Reader, Writer, Readable, Writeable};
|
||||
|
||||
use secp::{self, Secp256k1, Message, Signature};
|
||||
|
@ -283,13 +283,6 @@ impl Input {
|
|||
}
|
||||
}
|
||||
|
||||
/// The hash of an input is the hash of the output hash it references.
|
||||
impl Hashed for Input {
|
||||
fn bytes(&self) -> Vec<u8> {
|
||||
self.output_hash().to_vec()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub enum Output {
|
||||
BlindOutput {
|
||||
|
@ -303,8 +296,12 @@ pub enum Output {
|
|||
/// an Output as binary.
|
||||
impl Writeable for Output {
|
||||
fn write(&self, writer: &mut Writer) -> Result<(), ser::Error> {
|
||||
// The hash of an output is only the hash of its commitment.
|
||||
try!(writer.write_fixed_bytes(&self.commitment().unwrap()));
|
||||
writer.write_bytes(&self.proof().unwrap().bytes())
|
||||
if writer.serialization_mode() == ser::SerializationMode::Full {
|
||||
try!(writer.write_bytes(&self.proof().unwrap().bytes()))
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -363,17 +360,6 @@ impl Output {
|
|||
}
|
||||
}
|
||||
|
||||
/// The hash of an output is the hash of its commitment.
|
||||
impl Hashed for Output {
|
||||
fn bytes(&self) -> Vec<u8> {
|
||||
if let &Output::BlindOutput { commit, .. } = self {
|
||||
return commit.bytes().to_vec();
|
||||
} else {
|
||||
panic!("cannot hash an overt output");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Utility function to calculate the Merkle root of vectors of inputs and
|
||||
/// outputs.
|
||||
pub fn merkle_inputs_outputs(inputs: &Vec<Input>, outputs: &Vec<Output>) -> Hash {
|
||||
|
@ -418,12 +404,12 @@ mod test {
|
|||
let ref secp = new_secp();
|
||||
|
||||
let tx = tx2i1o(secp, &mut rng);
|
||||
let mut btx = tx.blind(&secp).unwrap();
|
||||
let btx = tx.blind(&secp).unwrap();
|
||||
let mut vec = Vec::new();
|
||||
serialize(&mut vec, &btx).expect("serialization failed");
|
||||
// let mut dtx = Transaction::read(&mut BinReader { source: &mut &vec[..]
|
||||
// }).unwrap();
|
||||
let mut dtx: Transaction = deserialize(&mut &vec[..]).unwrap();
|
||||
let dtx: Transaction = deserialize(&mut &vec[..]).unwrap();
|
||||
assert_eq!(dtx.fee, 1);
|
||||
assert_eq!(dtx.inputs.len(), 2);
|
||||
assert_eq!(dtx.outputs.len(), 1);
|
||||
|
@ -437,15 +423,15 @@ mod test {
|
|||
let ref secp = new_secp();
|
||||
|
||||
let tx = tx2i1o(secp, &mut rng);
|
||||
let mut btx = tx.blind(&secp).unwrap();
|
||||
let btx = tx.blind(&secp).unwrap();
|
||||
|
||||
let mut vec = Vec::new();
|
||||
assert!(serialize(&mut vec, &btx).is_ok());
|
||||
let mut dtx: Transaction = deserialize(&mut &vec[..]).unwrap();
|
||||
let dtx: Transaction = deserialize(&mut &vec[..]).unwrap();
|
||||
|
||||
let mut vec2 = Vec::new();
|
||||
assert!(serialize(&mut vec2, &btx).is_ok());
|
||||
let mut dtx2: Transaction = deserialize(&mut &vec2[..]).unwrap();
|
||||
let dtx2: Transaction = deserialize(&mut &vec2[..]).unwrap();
|
||||
|
||||
assert_eq!(btx.hash(), dtx.hash());
|
||||
assert_eq!(dtx.hash(), dtx2.hash());
|
||||
|
@ -532,10 +518,10 @@ mod test {
|
|||
let mut rng = OsRng::new().unwrap();
|
||||
|
||||
let tx1 = tx2i1o(secp, &mut rng);
|
||||
let mut btx1 = tx1.blind(&secp).unwrap();
|
||||
let btx1 = tx1.blind(&secp).unwrap();
|
||||
|
||||
let tx2 = tx1i1o(secp, &mut rng);
|
||||
let mut btx2 = tx2.blind(&secp).unwrap();
|
||||
let btx2 = tx2.blind(&secp).unwrap();
|
||||
|
||||
if btx1.hash() == btx2.hash() {
|
||||
panic!("diff txs have same hash")
|
||||
|
|
|
@ -85,13 +85,6 @@ impl Writeable for PowHeader {
|
|||
}
|
||||
}
|
||||
|
||||
impl Hashed for PowHeader {
|
||||
fn bytes(&self) -> Vec<u8> {
|
||||
// no serialization errors are applicable in this specific case
|
||||
ser_vec(self).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl PowHeader {
|
||||
fn from_block(b: &Block) -> PowHeader {
|
||||
let ref h = b.header;
|
||||
|
|
|
@ -81,9 +81,24 @@ pub trait AsFixedBytes {
|
|||
fn as_fixed_bytes(&self) -> &[u8];
|
||||
}
|
||||
|
||||
|
||||
/// Signal to a serializable object how much of its data should be serialized
|
||||
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||
pub enum SerializationMode {
|
||||
/// Serialize everything sufficiently to fully reconstruct the object
|
||||
Full,
|
||||
/// Serialize the data that defines the object
|
||||
Hash,
|
||||
/// Serialize everything that a signer of the object should know
|
||||
SigHash
|
||||
}
|
||||
|
||||
/// Implementations defined how different numbers and binary structures are
|
||||
/// written to an underlying stream or container (depending on implementation).
|
||||
pub trait Writer {
|
||||
/// The mode this serializer is writing in
|
||||
fn serialization_mode(&self) -> SerializationMode;
|
||||
|
||||
/// Writes a u8 as bytes
|
||||
fn write_u8(&mut self, n: u8) -> Result<(), Error> {
|
||||
self.write_fixed_bytes(&[n])
|
||||
|
@ -252,6 +267,10 @@ struct BinWriter<'a> {
|
|||
}
|
||||
|
||||
impl<'a> Writer for BinWriter<'a> {
|
||||
fn serialization_mode(&self) -> SerializationMode {
|
||||
SerializationMode::Full
|
||||
}
|
||||
|
||||
fn write_fixed_bytes(&mut self, fixed: &AsFixedBytes) -> Result<(), Error> {
|
||||
let bs = fixed.as_fixed_bytes();
|
||||
try!(self.sink.write_all(bs));
|
||||
|
|
Loading…
Reference in a new issue