initial commit for Zcash support

This commit is contained in:
Svyatoslav Nikolsky 2018-05-16 12:13:04 +03:00
parent 160e8c636f
commit a32a223395
9 changed files with 132 additions and 4 deletions

View File

@ -5,6 +5,9 @@ use crypto::dhash256;
use compact::Compact; use compact::Compact;
use hash::H256; use hash::H256;
#[derive(Debug, PartialEq, Default, Clone)]
pub struct EquihashSolution(pub Vec<u8>); // TODO: len = 1344
#[derive(PartialEq, Clone, Serializable, Deserializable)] #[derive(PartialEq, Clone, Serializable, Deserializable)]
pub struct BlockHeader { pub struct BlockHeader {
pub version: u32, pub version: u32,
@ -13,6 +16,7 @@ pub struct BlockHeader {
pub time: u32, pub time: u32,
pub bits: Compact, pub bits: Compact,
pub nonce: u32, pub nonce: u32,
pub equihash_solution: Option<EquihashSolution>,
} }
impl BlockHeader { impl BlockHeader {

83
chain/src/join_split.rs Normal file
View File

@ -0,0 +1,83 @@
use std::io;
use rustc_serialize::hex::ToHex;
use hash::{H256, H512};
use ser::{Error, Serializable, Deserializable, Stream, Reader};
#[derive(Clone, Serializable, Deserializable)]
pub struct ZKProof(pub Vec<u8>); // TODO: len == 296
impl ::std::fmt::Debug for ZKProof {
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
write!(f, "ZKProof({})", self.0.to_hex())
}
}
impl Default for ZKProof {
fn default() -> Self {
ZKProof([0; 296].to_vec())
}
}
impl PartialEq for ZKProof {
fn eq(&self, c: &ZKProof) -> bool {
self.0.iter().zip(c.0.iter()).all(|(l, r)| l == r)
}
}
#[derive(Clone, Serializable, Deserializable)]
pub struct CipherText(pub Vec<u8>); // TODO: len == 601
impl PartialEq for CipherText {
fn eq(&self, c: &CipherText) -> bool {
self.0.iter().zip(c.0.iter()).all(|(l, r)| l == r)
}
}
impl ::std::fmt::Debug for CipherText {
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
write!(f, "CipherText({})", self.0.to_hex())
}
}
impl Default for CipherText {
fn default() -> Self {
CipherText([0; 601].to_vec())
}
}
#[derive(Debug, PartialEq, Default, Clone)]
pub struct JointSplit {
pub descriptions: Vec<JointSplitDescription>,
pub pubkey: H256,
pub sig: H512,
}
#[derive(Debug, PartialEq, Default, Clone, Serializable, Deserializable)]
pub struct JointSplitDescription {
pub value_pub_old: u64,
pub value_pub_new: u64,
pub anchor: H256,
pub nullifiers: Vec<H256>,
pub commitments: Vec<H256>,
pub ephemeral_key: H256,
pub random_seed: H256,
pub macs: Vec<H256>,
pub zkproof: ZKProof,
pub ciphertexts: CipherText,
}
pub fn deserialize_joint_split<T>(reader: &mut Reader<T>) -> Result<Option<JointSplit>, Error> where T: io::Read {
let descriptions: Vec<JointSplitDescription> = reader.read_list()?;
if descriptions.is_empty() {
return Ok(None);
}
let pubkey = reader.read()?;
let sig = reader.read()?;
Ok(Some(JointSplit {
descriptions,
pubkey,
sig,
}))
}

View File

@ -10,6 +10,7 @@ pub mod constants;
mod block; mod block;
mod block_header; mod block_header;
mod join_split;
mod merkle_root; mod merkle_root;
mod transaction; mod transaction;
@ -28,6 +29,7 @@ pub use primitives::{hash, bytes, bigint, compact};
pub use block::Block; pub use block::Block;
pub use block_header::BlockHeader; pub use block_header::BlockHeader;
pub use join_split::{JointSplit, JointSplitDescription};
pub use merkle_root::{merkle_root, merkle_node_hash}; pub use merkle_root::{merkle_root, merkle_node_hash};
pub use transaction::{Transaction, TransactionInput, TransactionOutput, OutPoint}; pub use transaction::{Transaction, TransactionInput, TransactionOutput, OutPoint};

View File

@ -9,6 +9,7 @@ use ser::{deserialize, serialize, serialize_with_flags, SERIALIZE_TRANSACTION_WI
use crypto::dhash256; use crypto::dhash256;
use hash::H256; use hash::H256;
use constants::{SEQUENCE_FINAL, LOCKTIME_THRESHOLD}; use constants::{SEQUENCE_FINAL, LOCKTIME_THRESHOLD};
use join_split::{JointSplit, deserialize_joint_split};
use ser::{Error, Serializable, Deserializable, Stream, Reader}; use ser::{Error, Serializable, Deserializable, Stream, Reader};
/// Must be zero. /// Must be zero.
@ -96,6 +97,7 @@ pub struct Transaction {
pub inputs: Vec<TransactionInput>, pub inputs: Vec<TransactionInput>,
pub outputs: Vec<TransactionOutput>, pub outputs: Vec<TransactionOutput>,
pub lock_time: u32, pub lock_time: u32,
pub joint_split: Option<JointSplit>,
} }
impl From<&'static str> for Transaction { impl From<&'static str> for Transaction {
@ -232,7 +234,8 @@ impl Deserializable for Transaction {
fn deserialize<T>(reader: &mut Reader<T>) -> Result<Self, Error> where Self: Sized, T: io::Read { fn deserialize<T>(reader: &mut Reader<T>) -> Result<Self, Error> where Self: Sized, T: io::Read {
let version = reader.read()?; let version = reader.read()?;
let mut inputs: Vec<TransactionInput> = reader.read_list()?; let mut inputs: Vec<TransactionInput> = reader.read_list()?;
let read_witness = if inputs.is_empty() {
let read_witness = if reader.read_transaction_witness() && inputs.is_empty() {
let witness_flag: u8 = reader.read()?; let witness_flag: u8 = reader.read()?;
if witness_flag != WITNESS_FLAG { if witness_flag != WITNESS_FLAG {
return Err(Error::MalformedData); return Err(Error::MalformedData);
@ -250,11 +253,18 @@ impl Deserializable for Transaction {
} }
} }
let joint_split = if version >= 2 && reader.read_transaction_joint_split() {
deserialize_joint_split(reader)?
} else {
None
};
Ok(Transaction { Ok(Transaction {
version: version, version: version,
inputs: inputs, inputs: inputs,
outputs: outputs, outputs: outputs,
lock_time: reader.read()?, lock_time: reader.read()?,
joint_split: joint_split,
}) })
} }
} }

View File

@ -84,6 +84,7 @@ impl RawClientCore {
inputs: inputs, inputs: inputs,
outputs: outputs, outputs: outputs,
lock_time: lock_time, lock_time: lock_time,
joint_split: None,
}; };
Ok(transaction) Ok(transaction)

View File

@ -225,6 +225,7 @@ impl TransactionInputSigner {
outputs: outputs, outputs: outputs,
version: self.version, version: self.version,
lock_time: self.lock_time, lock_time: self.lock_time,
joint_split: None, // TODO
}; };
let mut stream = Stream::default(); let mut stream = Stream::default();

View File

@ -11,9 +11,11 @@ pub use primitives::{hash, bytes, compact};
pub use compact_integer::CompactInteger; pub use compact_integer::CompactInteger;
pub use list::List; pub use list::List;
pub use reader::{Reader, Deserializable, deserialize, deserialize_iterator, ReadIterator, Error}; pub use reader::{Reader, Deserializable, deserialize, deserialize_iterator, ReadIterator, Error,
DESERIALIZE_TRANSACTION_JOINT_SPLIT,
};
pub use stream::{ pub use stream::{
Stream, Serializable, serialize, serialize_with_flags, serialize_list, serialized_list_size, Stream, Serializable, serialize, serialize_with_flags, serialize_list, serialized_list_size,
serialized_list_size_with_flags, SERIALIZE_TRANSACTION_WITNESS, serialized_list_size_with_flags, SERIALIZE_TRANSACTION_WITNESS, SERIALIZE_TRANSACTION_JOINT_SPLIT,
}; };

View File

@ -1,6 +1,11 @@
use std::{io, marker}; use std::{io, marker};
use compact_integer::CompactInteger; use compact_integer::CompactInteger;
/// Deserialize transaction witness data.
pub const DESERIALIZE_TRANSACTION_WITNESS: u32 = 0x40000000;
/// Deserialize transaction joint split data.
pub const DESERIALIZE_TRANSACTION_JOINT_SPLIT: u32 = 0x80000000;
pub fn deserialize<R, T>(buffer: R) -> Result<T, Error> where R: io::Read, T: Deserializable { pub fn deserialize<R, T>(buffer: R) -> Result<T, Error> where R: io::Read, T: Deserializable {
let mut reader = Reader::from_read(buffer); let mut reader = Reader::from_read(buffer);
let result = try!(reader.read()); let result = try!(reader.read());
@ -41,6 +46,7 @@ pub trait Deserializable {
pub struct Reader<T> { pub struct Reader<T> {
buffer: T, buffer: T,
peeked: Option<u8>, peeked: Option<u8>,
flags: u32,
} }
impl<'a> Reader<&'a [u8]> { impl<'a> Reader<&'a [u8]> {
@ -49,6 +55,7 @@ impl<'a> Reader<&'a [u8]> {
Reader { Reader {
buffer: buffer, buffer: buffer,
peeked: None, peeked: None,
flags: 0,
} }
} }
} }
@ -77,9 +84,20 @@ impl<R> Reader<R> where R: io::Read {
Reader { Reader {
buffer: read, buffer: read,
peeked: None, peeked: None,
flags: 0,
} }
} }
/// Are transactions read from this stream with witness data?
pub fn read_transaction_witness(&self) -> bool {
(self.flags & DESERIALIZE_TRANSACTION_WITNESS) != 0
}
/// Are transactions read from this stream with the joint split data?
pub fn read_transaction_joint_split(&self) -> bool {
(self.flags & DESERIALIZE_TRANSACTION_JOINT_SPLIT) != 0
}
pub fn read<T>(&mut self) -> Result<T, Error> where T: Deserializable { pub fn read<T>(&mut self) -> Result<T, Error> where T: Deserializable {
T::deserialize(self) T::deserialize(self)
} }

View File

@ -4,8 +4,10 @@ use std::borrow::Borrow;
use compact_integer::CompactInteger; use compact_integer::CompactInteger;
use bytes::Bytes; use bytes::Bytes;
/// Do not serialize transaction witness data. /// Serialize transaction witness data.
pub const SERIALIZE_TRANSACTION_WITNESS: u32 = 0x40000000; pub const SERIALIZE_TRANSACTION_WITNESS: u32 = 0x40000000;
/// Serialize transaction joint split data.
pub const SERIALIZE_TRANSACTION_JOINT_SPLIT: u32 = 0x80000000;
pub fn serialize<T>(t: &T) -> Bytes where T: Serializable{ pub fn serialize<T>(t: &T) -> Bytes where T: Serializable{
let mut stream = Stream::default(); let mut stream = Stream::default();
@ -75,6 +77,11 @@ impl Stream {
(self.flags & SERIALIZE_TRANSACTION_WITNESS) != 0 (self.flags & SERIALIZE_TRANSACTION_WITNESS) != 0
} }
/// Are transactions written to this stream with the joint split data?
pub fn include_transaction_joint_split(&self) -> bool {
(self.flags & SERIALIZE_TRANSACTION_JOINT_SPLIT) != 0
}
/// Serializes the struct and appends it to the end of stream. /// Serializes the struct and appends it to the end of stream.
pub fn append<T>(&mut self, t: &T) -> &mut Self where T: Serializable { pub fn append<T>(&mut self, t: &T) -> &mut Self where T: Serializable {
t.serialize(self); t.serialize(self);