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::{PROOFSIZE, REWARD};
|
||||||
use core::hash::{Hash, Hashed, ZERO_HASH};
|
use core::hash::{Hash, Hashed, ZERO_HASH};
|
||||||
use core::transaction::MAX_IN_OUT_LEN;
|
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.
|
/// Block header, fairly standard compared to other blockchains.
|
||||||
pub struct BlockHeader {
|
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
|
/// A block as expressed in the MimbleWimble protocol. The reward is
|
||||||
/// non-explicit, assumed to be deductible from block height (similar to
|
/// non-explicit, assumed to be deductible from block height (similar to
|
||||||
/// bitcoin's schedule) and expressed as a global transaction fee (added v.H),
|
/// bitcoin's schedule) and expressed as a global transaction fee (added v.H),
|
||||||
|
|
|
@ -17,10 +17,12 @@
|
||||||
//! Primary hash function used in the protocol
|
//! Primary hash function used in the protocol
|
||||||
//!
|
//!
|
||||||
|
|
||||||
|
use byteorder::{ByteOrder, WriteBytesExt, BigEndian};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
use tiny_keccak::Keccak;
|
use tiny_keccak::Keccak;
|
||||||
|
|
||||||
|
use ser::{self, AsFixedBytes};
|
||||||
|
|
||||||
/// A hash to uniquely (or close enough) identify one of the main blockchain
|
/// A hash to uniquely (or close enough) identify one of the main blockchain
|
||||||
/// constructs. Used pervasively for blocks, transactions and ouputs.
|
/// constructs. Used pervasively for blocks, transactions and ouputs.
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||||
|
@ -56,27 +58,58 @@ impl Hash {
|
||||||
|
|
||||||
pub const ZERO_HASH: Hash = Hash([0; 32]);
|
pub const ZERO_HASH: Hash = Hash([0; 32]);
|
||||||
|
|
||||||
/// A trait for types that get their hash (double SHA256) from their byte
|
/// Serializer that outputs a hash of the serialized object
|
||||||
/// serialzation.
|
pub struct HashWriter {
|
||||||
pub trait Hashed {
|
state: Keccak
|
||||||
fn hash(&self) -> Hash {
|
|
||||||
let data = self.bytes();
|
|
||||||
Hash(sha3(data))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn bytes(&self) -> Vec<u8>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sha3(data: Vec<u8>) -> [u8; 32] {
|
impl HashWriter {
|
||||||
let mut sha3 = Keccak::new_sha3_256();
|
fn finalize(self, output: &mut [u8]) {
|
||||||
let mut buf = [0; 32];
|
self.state.finalize(output);
|
||||||
sha3.update(&data);
|
}
|
||||||
sha3.finalize(&mut buf);
|
}
|
||||||
buf
|
|
||||||
|
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] {
|
impl Hashed for [u8] {
|
||||||
fn bytes(&self) -> Vec<u8> {
|
fn hash(&self) -> Hash {
|
||||||
self.to_owned()
|
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
|
/// Two hashes that will get hashed together in a Merkle tree to build the next
|
||||||
/// level up.
|
/// level up.
|
||||||
struct HPair(Hash, Hash);
|
struct HPair(Hash, Hash);
|
||||||
impl Hashed for HPair {
|
|
||||||
fn bytes(&self) -> Vec<u8> {
|
impl Writeable for HPair {
|
||||||
let mut data = Vec::with_capacity(64);
|
fn write(&self, writer: &mut Writer) -> Result<(), Error> {
|
||||||
data.extend_from_slice(self.0.to_slice());
|
try!(writer.write_bytes(&self.0.to_slice()));
|
||||||
data.extend_from_slice(self.1.to_slice());
|
try!(writer.write_bytes(&self.1.to_slice()));
|
||||||
return data;
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// An iterator over hashes in a vector that pairs them to build a row in a
|
/// 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::Committed;
|
||||||
use core::MerkleRow;
|
use core::MerkleRow;
|
||||||
use core::hash::{Hashed, Hash};
|
use core::hash::{Hash, Hashed};
|
||||||
use ser::{self, Reader, Writer, Readable, Writeable};
|
use ser::{self, Reader, Writer, Readable, Writeable};
|
||||||
|
|
||||||
use secp::{self, Secp256k1, Message, Signature};
|
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)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
pub enum Output {
|
pub enum Output {
|
||||||
BlindOutput {
|
BlindOutput {
|
||||||
|
@ -303,8 +296,12 @@ pub enum Output {
|
||||||
/// an Output as binary.
|
/// an Output as binary.
|
||||||
impl Writeable for Output {
|
impl Writeable for Output {
|
||||||
fn write(&self, writer: &mut Writer) -> Result<(), ser::Error> {
|
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()));
|
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
|
/// Utility function to calculate the Merkle root of vectors of inputs and
|
||||||
/// outputs.
|
/// outputs.
|
||||||
pub fn merkle_inputs_outputs(inputs: &Vec<Input>, outputs: &Vec<Output>) -> Hash {
|
pub fn merkle_inputs_outputs(inputs: &Vec<Input>, outputs: &Vec<Output>) -> Hash {
|
||||||
|
@ -418,12 +404,12 @@ mod test {
|
||||||
let ref secp = new_secp();
|
let ref secp = new_secp();
|
||||||
|
|
||||||
let tx = tx2i1o(secp, &mut rng);
|
let tx = tx2i1o(secp, &mut rng);
|
||||||
let mut btx = tx.blind(&secp).unwrap();
|
let btx = tx.blind(&secp).unwrap();
|
||||||
let mut vec = Vec::new();
|
let mut vec = Vec::new();
|
||||||
serialize(&mut vec, &btx).expect("serialization failed");
|
serialize(&mut vec, &btx).expect("serialization failed");
|
||||||
// let mut dtx = Transaction::read(&mut BinReader { source: &mut &vec[..]
|
// let mut dtx = Transaction::read(&mut BinReader { source: &mut &vec[..]
|
||||||
// }).unwrap();
|
// }).unwrap();
|
||||||
let mut dtx: Transaction = deserialize(&mut &vec[..]).unwrap();
|
let dtx: Transaction = deserialize(&mut &vec[..]).unwrap();
|
||||||
assert_eq!(dtx.fee, 1);
|
assert_eq!(dtx.fee, 1);
|
||||||
assert_eq!(dtx.inputs.len(), 2);
|
assert_eq!(dtx.inputs.len(), 2);
|
||||||
assert_eq!(dtx.outputs.len(), 1);
|
assert_eq!(dtx.outputs.len(), 1);
|
||||||
|
@ -437,15 +423,15 @@ mod test {
|
||||||
let ref secp = new_secp();
|
let ref secp = new_secp();
|
||||||
|
|
||||||
let tx = tx2i1o(secp, &mut rng);
|
let tx = tx2i1o(secp, &mut rng);
|
||||||
let mut btx = tx.blind(&secp).unwrap();
|
let btx = tx.blind(&secp).unwrap();
|
||||||
|
|
||||||
let mut vec = Vec::new();
|
let mut vec = Vec::new();
|
||||||
assert!(serialize(&mut vec, &btx).is_ok());
|
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();
|
let mut vec2 = Vec::new();
|
||||||
assert!(serialize(&mut vec2, &btx).is_ok());
|
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!(btx.hash(), dtx.hash());
|
||||||
assert_eq!(dtx.hash(), dtx2.hash());
|
assert_eq!(dtx.hash(), dtx2.hash());
|
||||||
|
@ -532,10 +518,10 @@ mod test {
|
||||||
let mut rng = OsRng::new().unwrap();
|
let mut rng = OsRng::new().unwrap();
|
||||||
|
|
||||||
let tx1 = tx2i1o(secp, &mut rng);
|
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 tx2 = tx1i1o(secp, &mut rng);
|
||||||
let mut btx2 = tx2.blind(&secp).unwrap();
|
let btx2 = tx2.blind(&secp).unwrap();
|
||||||
|
|
||||||
if btx1.hash() == btx2.hash() {
|
if btx1.hash() == btx2.hash() {
|
||||||
panic!("diff txs have same 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 {
|
impl PowHeader {
|
||||||
fn from_block(b: &Block) -> PowHeader {
|
fn from_block(b: &Block) -> PowHeader {
|
||||||
let ref h = b.header;
|
let ref h = b.header;
|
||||||
|
|
|
@ -81,9 +81,24 @@ pub trait AsFixedBytes {
|
||||||
fn as_fixed_bytes(&self) -> &[u8];
|
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
|
/// Implementations defined how different numbers and binary structures are
|
||||||
/// written to an underlying stream or container (depending on implementation).
|
/// written to an underlying stream or container (depending on implementation).
|
||||||
pub trait Writer {
|
pub trait Writer {
|
||||||
|
/// The mode this serializer is writing in
|
||||||
|
fn serialization_mode(&self) -> SerializationMode;
|
||||||
|
|
||||||
/// Writes a u8 as bytes
|
/// Writes a u8 as bytes
|
||||||
fn write_u8(&mut self, n: u8) -> Result<(), Error> {
|
fn write_u8(&mut self, n: u8) -> Result<(), Error> {
|
||||||
self.write_fixed_bytes(&[n])
|
self.write_fixed_bytes(&[n])
|
||||||
|
@ -252,6 +267,10 @@ struct BinWriter<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Writer for 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> {
|
fn write_fixed_bytes(&mut self, fixed: &AsFixedBytes) -> Result<(), Error> {
|
||||||
let bs = fixed.as_fixed_bytes();
|
let bs = fixed.as_fixed_bytes();
|
||||||
try!(self.sink.write_all(bs));
|
try!(self.sink.write_all(bs));
|
||||||
|
|
Loading…
Reference in a new issue