From 0281de022fd7fb46b908af4b9adbaaff74ba4f09 Mon Sep 17 00:00:00 2001 From: Deirdre Connolly Date: Thu, 14 Nov 2019 16:04:22 -0500 Subject: [PATCH 01/14] Added a few more top-level fields for the Transaction struct --- zebra-chain/src/transaction.rs | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/zebra-chain/src/transaction.rs b/zebra-chain/src/transaction.rs index 7fc4ab56dd8..1e21318dbab 100644 --- a/zebra-chain/src/transaction.rs +++ b/zebra-chain/src/transaction.rs @@ -88,13 +88,21 @@ pub struct TransactionOutput { // transaction format: https://zips.z.cash/protocol/protocol.pdf #[derive(Clone, Debug, Eq, PartialEq)] pub struct Transaction { + /// Must not be set before Overwinter has activated. + pub overwintered: bool, + /// Transaction data format version (note, this is signed). pub version: i32, - /// A list of 1 or more transaction inputs or sources for coins. + /// Version group ID (nonzero). + pub version_group_id: u32, + + /// A list of 1 or more transparent transaction inputs or sources + /// for coins. pub tx_in: Vec, - /// A list of 1 or more transaction outputs or destinations for coins. + /// A list of 1 or more transparent transaction outputs or + /// destinations for coins. pub tx_out: Vec, /// The block number or timestamp at which this transaction is unlocked: @@ -109,6 +117,10 @@ pub struct Transaction { /// numbers, then lock_time is irrelevant. Otherwise, the /// transaction may not be added to a block until after `lock_time`. pub lock_time: u32, + + /// A block height in the range {1 .. 499999999} after which the + /// transaction will expire, or 0 to disable expiry ([ZIP-203]). + pub expiry_height: u32, } impl ZcashSerialize for Transaction { From f8ba3decc483ec4e6975fcc9d9fee778c7c897be Mon Sep 17 00:00:00 2001 From: Henry de Valence Date: Mon, 18 Nov 2019 13:39:18 -0800 Subject: [PATCH 02/14] Add a placeholder Script type. This could alternately use bytes::Bytes to save some allocations but I don't think this is important to get perfectly now. In the future, we will want to have all of the script handling code in the zebra-script crate, but we will need to have a container type for an encoded script in zebra-chain, because otherwise zebra-chain would depend on zebra-script and not the other way around. --- zebra-chain/src/transaction.rs | 13 +++++++------ zebra-chain/src/types.rs | 4 ++++ 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/zebra-chain/src/transaction.rs b/zebra-chain/src/transaction.rs index 1e21318dbab..4077bd9bc86 100644 --- a/zebra-chain/src/transaction.rs +++ b/zebra-chain/src/transaction.rs @@ -2,8 +2,11 @@ use std::io; -use crate::serialization::{SerializationError, ZcashDeserialize, ZcashSerialize}; -use crate::sha256d_writer::Sha256dWriter; +use crate::{ + serialization::{SerializationError, ZcashDeserialize, ZcashSerialize}, + sha256d_writer::Sha256dWriter, + types::Script, +}; /// A hash of a `Transaction` /// @@ -43,9 +46,7 @@ pub struct TransactionInput { pub previous_output: OutPoint, /// Computational Script for confirming transaction authorization. - // XXX pzec uses their own `Bytes` type that wraps a `Vec` - // with some extra methods. - pub signature_script: Vec, + pub signature_script: Script, /// Transaction version as defined by the sender. Intended for /// "replacement" of transactions when information is updated @@ -74,7 +75,7 @@ pub struct TransactionOutput { /// Usually contains the public key as a Bitcoin script setting up /// conditions to claim this output. - pub pk_script: Vec, + pub pk_script: Script, } /// Transaction diff --git a/zebra-chain/src/types.rs b/zebra-chain/src/types.rs index ca0b4634c0e..5d77ddab176 100644 --- a/zebra-chain/src/types.rs +++ b/zebra-chain/src/types.rs @@ -30,6 +30,10 @@ impl fmt::Debug for Sha256dChecksum { #[derive(Copy, Clone, Debug, Eq, PartialEq)] pub struct BlockHeight(pub u32); +/// An encoding of a Bitcoin script. +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct Script(pub Vec); + #[cfg(test)] mod tests { use super::*; From c0fbbfcc8903393d1ef759f20b7f0af604c0e62c Mon Sep 17 00:00:00 2001 From: Henry de Valence Date: Mon, 18 Nov 2019 13:44:16 -0800 Subject: [PATCH 03/14] Rename Transaction{Input,Output} -> Transparent{Input,Output}. These are only *transparent* inputs and outputs, so by putting Transparent in the name (instead of Transaction) it's more clear that a transaction's inputs or outputs can also be shielded. --- zebra-chain/src/transaction.rs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/zebra-chain/src/transaction.rs b/zebra-chain/src/transaction.rs index 4077bd9bc86..278596ff05b 100644 --- a/zebra-chain/src/transaction.rs +++ b/zebra-chain/src/transaction.rs @@ -38,10 +38,9 @@ pub struct OutPoint { pub index: u32, } -/// Transaction Input -// `Copy` cannot be implemented for `Vec` +/// A transparent input to a transaction. #[derive(Clone, Debug, Eq, PartialEq)] -pub struct TransactionInput { +pub struct TransparentInput { /// The previous output transaction reference. pub previous_output: OutPoint, @@ -54,7 +53,7 @@ pub struct TransactionInput { pub sequence: u32, } -/// Transaction Output +/// A transparent output from a transaction. /// /// The most fundamental building block of a transaction is a /// transaction output -- the ZEC you own in your "wallet" is in @@ -66,9 +65,8 @@ pub struct TransactionInput { /// I only own one UTXO worth 2 ZEC, I would construct a transaction /// that spends my UTXO and sends 1 ZEC to you and 1 ZEC back to me /// (just like receiving change). -// `Copy` cannot be implemented for `Vec` #[derive(Clone, Debug, Eq, PartialEq)] -pub struct TransactionOutput { +pub struct TransparentOutput { /// Transaction value. // At https://en.bitcoin.it/wiki/Protocol_documentation#tx, this is an i64. pub value: u64, @@ -100,11 +98,11 @@ pub struct Transaction { /// A list of 1 or more transparent transaction inputs or sources /// for coins. - pub tx_in: Vec, + pub tx_in: Vec, /// A list of 1 or more transparent transaction outputs or /// destinations for coins. - pub tx_out: Vec, + pub tx_out: Vec, /// The block number or timestamp at which this transaction is unlocked: /// From a8092bf334443777a392e4e605433ae9675ea095 Mon Sep 17 00:00:00 2001 From: Henry de Valence Date: Mon, 18 Nov 2019 14:50:21 -0800 Subject: [PATCH 04/14] Add a LockTime enum. --- zebra-chain/src/transaction.rs | 12 +++------ zebra-chain/src/types.rs | 48 +++++++++++++++++++++++++++++++++- 2 files changed, 50 insertions(+), 10 deletions(-) diff --git a/zebra-chain/src/transaction.rs b/zebra-chain/src/transaction.rs index 278596ff05b..1dc4b06bb09 100644 --- a/zebra-chain/src/transaction.rs +++ b/zebra-chain/src/transaction.rs @@ -5,7 +5,7 @@ use std::io; use crate::{ serialization::{SerializationError, ZcashDeserialize, ZcashSerialize}, sha256d_writer::Sha256dWriter, - types::Script, + types::{LockTime, Script}, }; /// A hash of a `Transaction` @@ -104,18 +104,12 @@ pub struct Transaction { /// destinations for coins. pub tx_out: Vec, - /// The block number or timestamp at which this transaction is unlocked: - /// - /// |Value |Description | - /// |------------|----------------------------------------------------| - /// |0 |Not locked (default) | - /// |< 500000000 |Block number at which this transaction is unlocked | - /// |>= 500000000|UNIX timestamp at which this transaction is unlocked| + /// The block number or timestamp at which this transaction is unlocked. /// /// If all `TransactionInput`s have final (0xffffffff) sequence /// numbers, then lock_time is irrelevant. Otherwise, the /// transaction may not be added to a block until after `lock_time`. - pub lock_time: u32, + pub lock_time: LockTime, /// A block height in the range {1 .. 499999999} after which the /// transaction will expire, or 0 to disable expiry ([ZIP-203]). diff --git a/zebra-chain/src/types.rs b/zebra-chain/src/types.rs index 5d77ddab176..4ba0e37508e 100644 --- a/zebra-chain/src/types.rs +++ b/zebra-chain/src/types.rs @@ -1,7 +1,12 @@ //! Newtype wrappers for primitive data types with semantic meaning. +use std::{fmt, io}; + +use byteorder::{BigEndian, LittleEndian, ReadBytesExt, WriteBytesExt}; +use chrono::{DateTime, TimeZone, Utc}; use hex; -use std::fmt; + +use crate::serialization::{SerializationError, ZcashDeserialize, ZcashSerialize}; /// A 4-byte checksum using truncated double-SHA256 (two rounds of SHA256). #[derive(Copy, Clone, Eq, PartialEq)] @@ -30,6 +35,47 @@ impl fmt::Debug for Sha256dChecksum { #[derive(Copy, Clone, Debug, Eq, PartialEq)] pub struct BlockHeight(pub u32); +/// A Bitcoin-style `locktime`, representing either a block height or an epoch +/// time. +/// +/// # Invariants +/// +/// Users should not construct a `LockTime` with `BlockHeight` greater than or +/// equal to `500_000_000` or a timestamp before 4 November 1985 (Unix timestamp +/// less than `500_000_000`). +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub enum LockTime { + /// Unlock at a particular block height. + Height(BlockHeight), + /// Unlock at a particular time. + Time(DateTime), +} + +impl ZcashSerialize for LockTime { + fn zcash_serialize(&self, mut writer: W) -> Result<(), SerializationError> { + // This implementation does not check the invariants on `LockTime` so that the + // serialization is fallible only if the underlying writer is. This ensures that + // we can always compute a hash of a transaction object. + use LockTime::*; + match self { + Height(BlockHeight(n)) => writer.write_u32::(*n)?, + Time(t) => writer.write_u32::(t.timestamp() as u32)?, + } + Ok(()) + } +} + +impl ZcashDeserialize for LockTime { + fn zcash_deserialize(mut reader: R) -> Result { + let n = reader.read_u32::()?; + if n < 500_000_000 { + Ok(LockTime::Height(BlockHeight(n))) + } else { + Ok(LockTime::Time(Utc.timestamp(n as i64, 0))) + } + } +} + /// An encoding of a Bitcoin script. #[derive(Clone, Debug, Eq, PartialEq)] pub struct Script(pub Vec); From 56b061ab5a3d60229fac39e33b539979c6e64bdc Mon Sep 17 00:00:00 2001 From: Henry de Valence Date: Mon, 18 Nov 2019 16:56:16 -0800 Subject: [PATCH 05/14] First attempt at a Transaction enum. This attempts to map the versioning and field presence rules into an ADT, so that structurally invalid transactions (e.g., a BCTV14 proof in a Sapling transaction) are unrepresentable. --- zebra-chain/src/transaction.rs | 161 +++++++++++++++++++++++++-------- 1 file changed, 125 insertions(+), 36 deletions(-) diff --git a/zebra-chain/src/transaction.rs b/zebra-chain/src/transaction.rs index 1dc4b06bb09..c854994be72 100644 --- a/zebra-chain/src/transaction.rs +++ b/zebra-chain/src/transaction.rs @@ -5,7 +5,7 @@ use std::io; use crate::{ serialization::{SerializationError, ZcashDeserialize, ZcashSerialize}, sha256d_writer::Sha256dWriter, - types::{LockTime, Script}, + types::{BlockHeight, LockTime, Script}, }; /// A hash of a `Transaction` @@ -76,44 +76,133 @@ pub struct TransparentOutput { pub pk_script: Script, } -/// Transaction -/// -/// A transaction is an encoded data structure that facilitates the -/// transfer of value between two public key addresses on the Zcash -/// ecosystem. Everything is designed to ensure that transactions can -/// created, propagated on the network, validated, and finally added -/// to the global ledger of transactions (the blockchain). -// This is not up to date with the data included in the Zcash -// transaction format: https://zips.z.cash/protocol/protocol.pdf -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct Transaction { - /// Must not be set before Overwinter has activated. - pub overwintered: bool, - - /// Transaction data format version (note, this is signed). - pub version: i32, - - /// Version group ID (nonzero). - pub version_group_id: u32, +/// unimplemented. +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct SpendDescription {} +/// unimplemented. +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct OutputDescription {} + +/// Sapling-on-Groth16 spend and output descriptions. +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct ShieldedData { + /// A sequence of spend descriptions for this transaction. + /// + /// https://zips.z.cash/protocol/protocol.pdf#spendencoding + pub shielded_spends: Vec, + /// A sequence of shielded outputs for this transaction. + /// + /// https://zips.z.cash/protocol/protocol.pdf#outputencoding + pub shielded_outputs: Vec, + /// A signature on the transaction hash. + // XXX refine this type to a RedJubjub signature. + // for now it's [u64; 8] rather than [u8; 64] to get trait impls + pub binding_sig: [u64; 8], +} - /// A list of 1 or more transparent transaction inputs or sources - /// for coins. - pub tx_in: Vec, +/// unimplemented. +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct JoinSplitBctv14 {} +/// unimplemented. +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct JoinSplitGroth16 {} + +/// Pre-Sapling JoinSplit data using Sprout-on-BCTV14 proofs. +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct LegacyJoinSplitData { + /// A sequence of JoinSplit descriptions using BCTV14 proofs. + pub joinsplits: Vec, + /// The public key for the JoinSplit signature. + // XXX refine to a Zcash-flavored Ed25519 pubkey. + pub pub_key: [u8; 32], + /// The JoinSplit signature. + // XXX refine to a Zcash-flavored Ed25519 signature. + // for now it's [u64; 8] rather than [u8; 64] to get trait impls + pub sig: [u64; 8], +} - /// A list of 1 or more transparent transaction outputs or - /// destinations for coins. - pub tx_out: Vec, +/// Post-Sapling JoinSplit data using Sprout-on-Groth16 proofs. +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct SaplingJoinSplitData { + /// A sequence of JoinSplit descriptions using BCTV14 proofs. + pub joinsplits: Vec, + /// The public key for the JoinSplit signature. + // XXX refine to a Zcash-flavored Ed25519 pubkey. + pub pub_key: [u8; 32], + /// The JoinSplit signature. + // XXX refine to a Zcash-flavored Ed25519 signature. + // for now it's [u64; 8] rather than [u8; 64] to get trait impls + pub sig: [u64; 8], +} - /// The block number or timestamp at which this transaction is unlocked. - /// - /// If all `TransactionInput`s have final (0xffffffff) sequence - /// numbers, then lock_time is irrelevant. Otherwise, the - /// transaction may not be added to a block until after `lock_time`. - pub lock_time: LockTime, - - /// A block height in the range {1 .. 499999999} after which the - /// transaction will expire, or 0 to disable expiry ([ZIP-203]). - pub expiry_height: u32, +/// A Zcash transaction. +/// +/// A transaction is an encoded data structure that facilitates the transfer of +/// value between two public key addresses on the Zcash ecosystem. Everything is +/// designed to ensure that transactions can created, propagated on the network, +/// validated, and finally added to the global ledger of transactions (the +/// blockchain). +/// +/// Zcash has a number of different transaction formats. They are represented +/// internally by different enum variants. Because we checkpoint on Sapling +/// activation, we do not parse any pre-Sapling transaction types. +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum Transaction { + /// A fully transparent transaction (`version = 1`). + Transparent { + /// The transparent inputs to the transaction. + inputs: Vec, + /// The transparent outputs from the transaction. + outputs: Vec, + /// The earliest time or block height that this transaction can be added to the + /// chain. + lock_time: LockTime, + }, + /// A Sprout transaction (`version = 2`). + Sprout { + /// The transparent inputs to the transaction. + inputs: Vec, + /// The transparent outputs from the transaction. + outputs: Vec, + /// The earliest time or block height that this transaction can be added to the + /// chain. + lock_time: LockTime, + /// The JoinSplit data for this transaction, if any. + joinsplit_data: Option, + }, + /// An Overwinter transaction (`version = 3`). + Overwinter { + /// The transparent inputs to the transaction. + inputs: Vec, + /// The transparent outputs from the transaction. + outputs: Vec, + /// The earliest time or block height that this transaction can be added to the + /// chain. + lock_time: LockTime, + /// The latest block height that this transaction can be added to the chain. + expiry_height: BlockHeight, + /// The JoinSplit data for this transaction, if any. + joinsplit_data: Option, + }, + /// A Sapling transaction (`version = 4`). + Sapling { + /// The transparent inputs to the transaction. + inputs: Vec, + /// The transparent outputs from the transaction. + outputs: Vec, + /// The earliest time or block height that this transaction can be added to the + /// chain. + lock_time: LockTime, + /// The latest block height that this transaction can be added to the chain. + expiry_height: BlockHeight, + /// The net value of Sapling spend transfers minus output transfers. + // XXX refine this to an Amount type. + value_balance: i64, + /// The shielded data for this transaction, if any. + shielded_data: Option, + /// The JoinSplit data for this transaction, if any. + joinsplit_data: Option, + }, } impl ZcashSerialize for Transaction { From 69e86d68c711e4ff1c16073d3dbdfbcb2aeab99b Mon Sep 17 00:00:00 2001 From: Henry de Valence Date: Tue, 19 Nov 2019 12:51:59 -0800 Subject: [PATCH 06/14] Update zebra-chain/src/transaction.rs Co-Authored-By: Daira Hopwood --- zebra-chain/src/transaction.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zebra-chain/src/transaction.rs b/zebra-chain/src/transaction.rs index c854994be72..166050d636e 100644 --- a/zebra-chain/src/transaction.rs +++ b/zebra-chain/src/transaction.rs @@ -124,7 +124,7 @@ pub struct LegacyJoinSplitData { /// Post-Sapling JoinSplit data using Sprout-on-Groth16 proofs. #[derive(Clone, Debug, PartialEq, Eq)] pub struct SaplingJoinSplitData { - /// A sequence of JoinSplit descriptions using BCTV14 proofs. + /// A sequence of JoinSplit descriptions using Groth16 proofs. pub joinsplits: Vec, /// The public key for the JoinSplit signature. // XXX refine to a Zcash-flavored Ed25519 pubkey. From 8155de9c2135fdc4ed26ecfcb6e1c4c352db1e28 Mon Sep 17 00:00:00 2001 From: Henry de Valence Date: Tue, 19 Nov 2019 18:10:31 -0800 Subject: [PATCH 07/14] Add fixme note on type refinement. --- zebra-chain/src/transaction.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/zebra-chain/src/transaction.rs b/zebra-chain/src/transaction.rs index 166050d636e..213709dcd31 100644 --- a/zebra-chain/src/transaction.rs +++ b/zebra-chain/src/transaction.rs @@ -69,6 +69,7 @@ pub struct TransparentInput { pub struct TransparentOutput { /// Transaction value. // At https://en.bitcoin.it/wiki/Protocol_documentation#tx, this is an i64. + // XXX refine to Amount ? pub value: u64, /// Usually contains the public key as a Bitcoin script setting up From f01b75d160a1a6944268999e50439b1fc4c35d41 Mon Sep 17 00:00:00 2001 From: Henry de Valence Date: Tue, 19 Nov 2019 18:13:15 -0800 Subject: [PATCH 08/14] Rename Transaction variants according to version. --- zebra-chain/src/transaction.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/zebra-chain/src/transaction.rs b/zebra-chain/src/transaction.rs index 213709dcd31..eebee68d621 100644 --- a/zebra-chain/src/transaction.rs +++ b/zebra-chain/src/transaction.rs @@ -150,7 +150,7 @@ pub struct SaplingJoinSplitData { #[derive(Clone, Debug, PartialEq, Eq)] pub enum Transaction { /// A fully transparent transaction (`version = 1`). - Transparent { + V1 { /// The transparent inputs to the transaction. inputs: Vec, /// The transparent outputs from the transaction. @@ -160,7 +160,7 @@ pub enum Transaction { lock_time: LockTime, }, /// A Sprout transaction (`version = 2`). - Sprout { + V2 { /// The transparent inputs to the transaction. inputs: Vec, /// The transparent outputs from the transaction. @@ -172,7 +172,7 @@ pub enum Transaction { joinsplit_data: Option, }, /// An Overwinter transaction (`version = 3`). - Overwinter { + V3 { /// The transparent inputs to the transaction. inputs: Vec, /// The transparent outputs from the transaction. @@ -186,7 +186,7 @@ pub enum Transaction { joinsplit_data: Option, }, /// A Sapling transaction (`version = 4`). - Sapling { + V4 { /// The transparent inputs to the transaction. inputs: Vec, /// The transparent outputs from the transaction. From 159d17d96c65c38203a66c0a9a517d6b5921e15a Mon Sep 17 00:00:00 2001 From: Henry de Valence Date: Wed, 27 Nov 2019 14:10:53 -0800 Subject: [PATCH 09/14] Split transaction.rs into submodules. --- zebra-chain/src/transaction.rs | 156 ++----------------- zebra-chain/src/transaction/hash.rs | 20 +++ zebra-chain/src/transaction/joinsplit.rs | 34 ++++ zebra-chain/src/transaction/serialize.rs | 20 +++ zebra-chain/src/transaction/shielded_data.rs | 25 +++ zebra-chain/src/transaction/tests.rs | 1 + zebra-chain/src/transaction/transparent.rs | 57 +++++++ 7 files changed, 169 insertions(+), 144 deletions(-) create mode 100644 zebra-chain/src/transaction/hash.rs create mode 100644 zebra-chain/src/transaction/joinsplit.rs create mode 100644 zebra-chain/src/transaction/serialize.rs create mode 100644 zebra-chain/src/transaction/shielded_data.rs create mode 100644 zebra-chain/src/transaction/tests.rs create mode 100644 zebra-chain/src/transaction/transparent.rs diff --git a/zebra-chain/src/transaction.rs b/zebra-chain/src/transaction.rs index eebee68d621..a4f2c7a08bd 100644 --- a/zebra-chain/src/transaction.rs +++ b/zebra-chain/src/transaction.rs @@ -1,140 +1,20 @@ //! Transaction types. -use std::io; +mod hash; +mod joinsplit; +mod serialize; +mod shielded_data; +mod transparent; -use crate::{ - serialization::{SerializationError, ZcashDeserialize, ZcashSerialize}, - sha256d_writer::Sha256dWriter, - types::{BlockHeight, LockTime, Script}, -}; +#[cfg(test)] +mod tests; -/// A hash of a `Transaction` -/// -/// TODO: I'm pretty sure this is also a SHA256d hash but I haven't -/// confirmed it yet. -#[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub struct TransactionHash(pub [u8; 32]); - -impl From for TransactionHash { - fn from(transaction: Transaction) -> Self { - let mut hash_writer = Sha256dWriter::default(); - transaction - .zcash_serialize(&mut hash_writer) - .expect("Transactions must serialize into the hash."); - Self(hash_writer.finish()) - } -} - -/// OutPoint -/// -/// A particular transaction output reference. -#[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub struct OutPoint { - /// References the transaction that contains the UTXO being spent. - pub hash: TransactionHash, - - /// Identifies which UTXO from that transaction is referenced; the - /// first output is 0, etc. - pub index: u32, -} - -/// A transparent input to a transaction. -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct TransparentInput { - /// The previous output transaction reference. - pub previous_output: OutPoint, - - /// Computational Script for confirming transaction authorization. - pub signature_script: Script, - - /// Transaction version as defined by the sender. Intended for - /// "replacement" of transactions when information is updated - /// before inclusion into a block. - pub sequence: u32, -} - -/// A transparent output from a transaction. -/// -/// The most fundamental building block of a transaction is a -/// transaction output -- the ZEC you own in your "wallet" is in -/// fact a subset of unspent transaction outputs (or "UTXO"s) of the -/// global UTXO set. -/// -/// UTXOs are indivisible, discrete units of value which can only be -/// consumed in their entirety. Thus, if I want to send you 1 ZEC and -/// I only own one UTXO worth 2 ZEC, I would construct a transaction -/// that spends my UTXO and sends 1 ZEC to you and 1 ZEC back to me -/// (just like receiving change). -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct TransparentOutput { - /// Transaction value. - // At https://en.bitcoin.it/wiki/Protocol_documentation#tx, this is an i64. - // XXX refine to Amount ? - pub value: u64, - - /// Usually contains the public key as a Bitcoin script setting up - /// conditions to claim this output. - pub pk_script: Script, -} - -/// unimplemented. -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct SpendDescription {} -/// unimplemented. -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct OutputDescription {} +pub use hash::TransactionHash; +pub use joinsplit::{JoinSplitBctv14, JoinSplitGroth16, LegacyJoinSplitData, SaplingJoinSplitData}; +pub use shielded_data::{OutputDescription, ShieldedData, SpendDescription}; +pub use transparent::{OutPoint, TransparentInput, TransparentOutput}; -/// Sapling-on-Groth16 spend and output descriptions. -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct ShieldedData { - /// A sequence of spend descriptions for this transaction. - /// - /// https://zips.z.cash/protocol/protocol.pdf#spendencoding - pub shielded_spends: Vec, - /// A sequence of shielded outputs for this transaction. - /// - /// https://zips.z.cash/protocol/protocol.pdf#outputencoding - pub shielded_outputs: Vec, - /// A signature on the transaction hash. - // XXX refine this type to a RedJubjub signature. - // for now it's [u64; 8] rather than [u8; 64] to get trait impls - pub binding_sig: [u64; 8], -} - -/// unimplemented. -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct JoinSplitBctv14 {} -/// unimplemented. -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct JoinSplitGroth16 {} - -/// Pre-Sapling JoinSplit data using Sprout-on-BCTV14 proofs. -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct LegacyJoinSplitData { - /// A sequence of JoinSplit descriptions using BCTV14 proofs. - pub joinsplits: Vec, - /// The public key for the JoinSplit signature. - // XXX refine to a Zcash-flavored Ed25519 pubkey. - pub pub_key: [u8; 32], - /// The JoinSplit signature. - // XXX refine to a Zcash-flavored Ed25519 signature. - // for now it's [u64; 8] rather than [u8; 64] to get trait impls - pub sig: [u64; 8], -} - -/// Post-Sapling JoinSplit data using Sprout-on-Groth16 proofs. -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct SaplingJoinSplitData { - /// A sequence of JoinSplit descriptions using Groth16 proofs. - pub joinsplits: Vec, - /// The public key for the JoinSplit signature. - // XXX refine to a Zcash-flavored Ed25519 pubkey. - pub pub_key: [u8; 32], - /// The JoinSplit signature. - // XXX refine to a Zcash-flavored Ed25519 signature. - // for now it's [u64; 8] rather than [u8; 64] to get trait impls - pub sig: [u64; 8], -} +use crate::types::{BlockHeight, LockTime}; /// A Zcash transaction. /// @@ -205,15 +85,3 @@ pub enum Transaction { joinsplit_data: Option, }, } - -impl ZcashSerialize for Transaction { - fn zcash_serialize(&self, _writer: W) -> Result<(), SerializationError> { - unimplemented!(); - } -} - -impl ZcashDeserialize for Transaction { - fn zcash_deserialize(_reader: R) -> Result { - unimplemented!(); - } -} diff --git a/zebra-chain/src/transaction/hash.rs b/zebra-chain/src/transaction/hash.rs new file mode 100644 index 00000000000..24d863ffef6 --- /dev/null +++ b/zebra-chain/src/transaction/hash.rs @@ -0,0 +1,20 @@ +use crate::{serialization::ZcashSerialize, sha256d_writer::Sha256dWriter}; + +use super::Transaction; + +/// A hash of a `Transaction` +/// +/// TODO: I'm pretty sure this is also a SHA256d hash but I haven't +/// confirmed it yet. +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub struct TransactionHash(pub [u8; 32]); + +impl From for TransactionHash { + fn from(transaction: Transaction) -> Self { + let mut hash_writer = Sha256dWriter::default(); + transaction + .zcash_serialize(&mut hash_writer) + .expect("Transactions must serialize into the hash."); + Self(hash_writer.finish()) + } +} diff --git a/zebra-chain/src/transaction/joinsplit.rs b/zebra-chain/src/transaction/joinsplit.rs new file mode 100644 index 00000000000..ca07a759ed5 --- /dev/null +++ b/zebra-chain/src/transaction/joinsplit.rs @@ -0,0 +1,34 @@ +/// unimplemented. +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct JoinSplitBctv14 {} +/// unimplemented. +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct JoinSplitGroth16 {} + +/// Pre-Sapling JoinSplit data using Sprout-on-BCTV14 proofs. +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct LegacyJoinSplitData { + /// A sequence of JoinSplit descriptions using BCTV14 proofs. + pub joinsplits: Vec, + /// The public key for the JoinSplit signature. + // XXX refine to a Zcash-flavored Ed25519 pubkey. + pub pub_key: [u8; 32], + /// The JoinSplit signature. + // XXX refine to a Zcash-flavored Ed25519 signature. + // for now it's [u64; 8] rather than [u8; 64] to get trait impls + pub sig: [u64; 8], +} + +/// Post-Sapling JoinSplit data using Sprout-on-Groth16 proofs. +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct SaplingJoinSplitData { + /// A sequence of JoinSplit descriptions using Groth16 proofs. + pub joinsplits: Vec, + /// The public key for the JoinSplit signature. + // XXX refine to a Zcash-flavored Ed25519 pubkey. + pub pub_key: [u8; 32], + /// The JoinSplit signature. + // XXX refine to a Zcash-flavored Ed25519 signature. + // for now it's [u64; 8] rather than [u8; 64] to get trait impls + pub sig: [u64; 8], +} diff --git a/zebra-chain/src/transaction/serialize.rs b/zebra-chain/src/transaction/serialize.rs new file mode 100644 index 00000000000..02c245b88c1 --- /dev/null +++ b/zebra-chain/src/transaction/serialize.rs @@ -0,0 +1,20 @@ +//! Contains impls of `ZcashSerialize`, `ZcashDeserialize` for all of the +//! transaction types, so that all of the serialization logic is in one place. + +use std::io; + +use crate::serialization::{SerializationError, ZcashDeserialize, ZcashSerialize}; + +use super::Transaction; + +impl ZcashSerialize for Transaction { + fn zcash_serialize(&self, _writer: W) -> Result<(), SerializationError> { + unimplemented!(); + } +} + +impl ZcashDeserialize for Transaction { + fn zcash_deserialize(_reader: R) -> Result { + unimplemented!(); + } +} diff --git a/zebra-chain/src/transaction/shielded_data.rs b/zebra-chain/src/transaction/shielded_data.rs new file mode 100644 index 00000000000..aa54bb00602 --- /dev/null +++ b/zebra-chain/src/transaction/shielded_data.rs @@ -0,0 +1,25 @@ +//! Transaction types. + +/// unimplemented. +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct SpendDescription {} +/// unimplemented. +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct OutputDescription {} + +/// Sapling-on-Groth16 spend and output descriptions. +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct ShieldedData { + /// A sequence of spend descriptions for this transaction. + /// + /// https://zips.z.cash/protocol/protocol.pdf#spendencoding + pub shielded_spends: Vec, + /// A sequence of shielded outputs for this transaction. + /// + /// https://zips.z.cash/protocol/protocol.pdf#outputencoding + pub shielded_outputs: Vec, + /// A signature on the transaction hash. + // XXX refine this type to a RedJubjub signature. + // for now it's [u64; 8] rather than [u8; 64] to get trait impls + pub binding_sig: [u64; 8], +} diff --git a/zebra-chain/src/transaction/tests.rs b/zebra-chain/src/transaction/tests.rs new file mode 100644 index 00000000000..8b137891791 --- /dev/null +++ b/zebra-chain/src/transaction/tests.rs @@ -0,0 +1 @@ + diff --git a/zebra-chain/src/transaction/transparent.rs b/zebra-chain/src/transaction/transparent.rs new file mode 100644 index 00000000000..9cfa7b1503f --- /dev/null +++ b/zebra-chain/src/transaction/transparent.rs @@ -0,0 +1,57 @@ +//! Transaction types. + +use crate::types::Script; + +use super::TransactionHash; + +/// OutPoint +/// +/// A particular transaction output reference. +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub struct OutPoint { + /// References the transaction that contains the UTXO being spent. + pub hash: TransactionHash, + + /// Identifies which UTXO from that transaction is referenced; the + /// first output is 0, etc. + pub index: u32, +} + +/// A transparent input to a transaction. +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct TransparentInput { + /// The previous output transaction reference. + pub previous_output: OutPoint, + + /// Computational Script for confirming transaction authorization. + pub signature_script: Script, + + /// Transaction version as defined by the sender. Intended for + /// "replacement" of transactions when information is updated + /// before inclusion into a block. + pub sequence: u32, +} + +/// A transparent output from a transaction. +/// +/// The most fundamental building block of a transaction is a +/// transaction output -- the ZEC you own in your "wallet" is in +/// fact a subset of unspent transaction outputs (or "UTXO"s) of the +/// global UTXO set. +/// +/// UTXOs are indivisible, discrete units of value which can only be +/// consumed in their entirety. Thus, if I want to send you 1 ZEC and +/// I only own one UTXO worth 2 ZEC, I would construct a transaction +/// that spends my UTXO and sends 1 ZEC to you and 1 ZEC back to me +/// (just like receiving change). +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct TransparentOutput { + /// Transaction value. + // At https://en.bitcoin.it/wiki/Protocol_documentation#tx, this is an i64. + // XXX refine to Amount ? + pub value: u64, + + /// Usually contains the public key as a Bitcoin script setting up + /// conditions to claim this output. + pub pk_script: Script, +} From bd7b71880707575b01432e7325523d3dd8446c5d Mon Sep 17 00:00:00 2001 From: Henry de Valence Date: Wed, 27 Nov 2019 15:16:44 -0800 Subject: [PATCH 10/14] Start filling in spend, output descriptions. --- zebra-chain/src/transaction/shielded_data.rs | 75 +++++++++++++++++--- 1 file changed, 65 insertions(+), 10 deletions(-) diff --git a/zebra-chain/src/transaction/shielded_data.rs b/zebra-chain/src/transaction/shielded_data.rs index aa54bb00602..e00e56f4085 100644 --- a/zebra-chain/src/transaction/shielded_data.rs +++ b/zebra-chain/src/transaction/shielded_data.rs @@ -1,22 +1,77 @@ -//! Transaction types. +// XXX this name seems too long? +use crate::note_commitment_tree::SaplingNoteTreeRootHash; -/// unimplemented. +/// A _Spend Description_, as described in [protocol specification §7.3][ps]. +/// +/// [ps]: https://zips.z.cash/protocol/protocol.pdf#spendencoding #[derive(Clone, Debug, PartialEq, Eq)] -pub struct SpendDescription {} -/// unimplemented. +pub struct SpendDescription { + /// A value commitment to the value of the input note. + /// + /// XXX refine to a specific type. + pub cv: [u8; 32], + /// A root of the Sapling note commitment tree at some block height in the past. + pub anchor: SaplingNoteTreeRootHash, + /// The nullifier of the input note. + /// + /// XXX refine to a specific type. + pub nullifier: [u8; 32], + /// The randomized public key for `spend_auth_sig`. + /// + /// XXX refine to a specific type. + pub rk: [u8; 32], + /// The ZK spend proof. + /// + /// XXX add proof types. + /// XXX for now it's [u64; 24] instead of [u8; 192] to get trait impls + pub zkproof: [u64; 24], + /// A signature authorizing this spend. + /// + /// XXX refine to a specific type: redjubjub signature? + /// XXX for now it's [u64; 8] instead of [u8; 64] to get trait impls + pub spend_auth_sig: [u64; 8], +} + +/// A _Output Description_, as described in [protocol specification §7.4][ps]. +/// +/// https://zips.z.cash/protocol/protocol.pdf#outputencoding #[derive(Clone, Debug, PartialEq, Eq)] -pub struct OutputDescription {} +pub struct OutputDescription { + /// A value commitment to the value of the input note. + /// + /// XXX refine to a specific type. + pub cv: [u8; 32], + /// The u-coordinate of the note commitment for the output note. + /// + /// XXX refine to a specific type. + pub cmu: [u8; 32], + /// An encoding of an ephemeral Jubjub public key. + /// + /// XXX refine to a specific type. + pub ephemeral_key: [u8; 32], + /// A ciphertext component for the encrypted output note. + /// + /// XXX refine to a specific type. + /// XXX this is a Vec rather than a [u8; 580] to get trait impls + pub enc_ciphertext: Vec, + /// A ciphertext component for the encrypted output note. + /// + /// XXX refine to a specific type. + /// XXX this is a [u64; 10] rather than a [u8; 80] to get trait impls + pub out_ciphertext: [u64; 10], + /// The ZK output proof. + /// + /// XXX add proof types. + /// XXX for now it's [u64; 24] instead of [u8; 192] to get trait impls + pub zkproof: [u64; 24], +} /// Sapling-on-Groth16 spend and output descriptions. #[derive(Clone, Debug, PartialEq, Eq)] pub struct ShieldedData { - /// A sequence of spend descriptions for this transaction. - /// - /// https://zips.z.cash/protocol/protocol.pdf#spendencoding + /// A sequence of [`SpendDescription`]s for this transaction. pub shielded_spends: Vec, /// A sequence of shielded outputs for this transaction. - /// - /// https://zips.z.cash/protocol/protocol.pdf#outputencoding pub shielded_outputs: Vec, /// A signature on the transaction hash. // XXX refine this type to a RedJubjub signature. From a71280642e92e04bbf6a442c709034b6f0b239cd Mon Sep 17 00:00:00 2001 From: Henry de Valence Date: Wed, 27 Nov 2019 16:17:10 -0800 Subject: [PATCH 11/14] Progress on JoinSplit data structures. This has a lot of duplication and should really use generics to abstract over Sprout-on-BCTV14 or Sprout-on-Groth16. --- zebra-chain/src/transaction/joinsplit.rs | 99 +++++++++++++++++++++++- 1 file changed, 95 insertions(+), 4 deletions(-) diff --git a/zebra-chain/src/transaction/joinsplit.rs b/zebra-chain/src/transaction/joinsplit.rs index ca07a759ed5..f0b86287467 100644 --- a/zebra-chain/src/transaction/joinsplit.rs +++ b/zebra-chain/src/transaction/joinsplit.rs @@ -1,9 +1,100 @@ -/// unimplemented. +/// Describes input notes to a Sprout transaction. +/// +/// The [protocol specification §7.2][ps] describes these fields as being encoded +/// separately into two arrays of the same length. Instead, by bundling them +/// together into one structure, we can ensure that it's not possible to create a +/// JoinSplit description with mismatched array lengths. This means we do not +/// need to maintain any invariants about equal array lengths. +/// +/// [ps]: https://zips.z.cash/protocol/protocol.pdf#joinsplitencoding #[derive(Clone, Debug, PartialEq, Eq)] -pub struct JoinSplitBctv14 {} -/// unimplemented. +pub struct SproutInputNoteData { + /// A nullifier for the input note. + /// + /// XXX refine type + pub nullifier: [u8; 32], + /// A message authentication tag. + /// + /// XXX refine type + pub vmac: [u8; 32], +} + +/// Describes output notes from a Sprout transaction. +/// +/// The [protocol specification §7.2][ps] describes these fields as being encoded +/// separately into two arrays of the same length. Instead, by bundling them +/// together into one structure, we can ensure that it's not possible to create a +/// JoinSplit description with mismatched array lengths. This means we do not +/// need to maintain any invariants about equal array lengths. +/// +/// [ps]: https://zips.z.cash/protocol/protocol.pdf#joinsplitencoding +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct SproutOutputNoteData { + /// A note commitment for this output note. + /// + /// XXX refine type + pub commitment: [u8; 32], + /// A ciphertext component for this output note. + /// + /// XXX refine type + /// XXX this should be a [u8; 601] but we need trait impls. + pub enc_ciphertext: Vec, +} + +/// A _JoinSplit Description_ using BCTV14 proofs, as described in [protocol +/// specification §7.2][ps]. +/// +/// [ps]: https://zips.z.cash/protocol/protocol.pdf#joinsplitencoding #[derive(Clone, Debug, PartialEq, Eq)] -pub struct JoinSplitGroth16 {} +pub struct JoinSplitBctv14 { + /// A value that the JoinSplit transfer removes from the transparent value + /// pool. + /// + /// XXX refine to an Amount + vpub_old: u64, + /// A value that the JoinSplit transfer inserts into the transparent value + /// pool. + /// + /// XXX refine to an Amount + vpub_new: u64, + + /// A root of the Sprout note commitment tree at some block height in the + /// past, or the root produced by a previous JoinSplit transfer in this + /// transaction. + /// + /// XXX refine type + anchor: [u8; 32], + + /// An X25519 public key. + /// + /// XXX refine to an x25519-dalek type? + ephemeral_key: [u8; 32], + + /// A 256-bit seed that must be chosen independently at random for each + /// JoinSplit description. + random_seed: [u8; 32], + + /// A sequence of input notes for this transaction. + input_notes: Vec, + + /// A sequence of output notes for this transaction. + output_notes: Vec, + + /// A ZK JoinSplit proof using BCTV14. + /// + /// XXX refine type + /// XXX this should be a [u8; 296] but trait impls. + zkproof: Vec, +} + +/// A _JoinSplit Description_ using Groth16 proofs, as described in [protocol +/// specification §7.2][ps]. +/// +/// [ps]: https://zips.z.cash/protocol/protocol.pdf#joinsplitencoding +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct JoinSplitGroth16 { + // XXX use generic's +} /// Pre-Sapling JoinSplit data using Sprout-on-BCTV14 proofs. #[derive(Clone, Debug, PartialEq, Eq)] From 2f3a7a0e848e6488ba945860aac21a54ac0200f9 Mon Sep 17 00:00:00 2001 From: Henry de Valence Date: Wed, 27 Nov 2019 16:32:54 -0800 Subject: [PATCH 12/14] Add data types for Bctv14 and Groth16 proofs. This also adds a trait to abstract over them. --- zebra-chain/src/lib.rs | 1 + zebra-chain/src/proofs.rs | 22 +++++++++++++++++++++ zebra-chain/src/proofs/bctv14.rs | 32 +++++++++++++++++++++++++++++++ zebra-chain/src/proofs/groth16.rs | 32 +++++++++++++++++++++++++++++++ 4 files changed, 87 insertions(+) create mode 100644 zebra-chain/src/proofs.rs create mode 100644 zebra-chain/src/proofs/bctv14.rs create mode 100644 zebra-chain/src/proofs/groth16.rs diff --git a/zebra-chain/src/lib.rs b/zebra-chain/src/lib.rs index d97b71ed658..76c79a6fdb3 100644 --- a/zebra-chain/src/lib.rs +++ b/zebra-chain/src/lib.rs @@ -7,6 +7,7 @@ mod sha256d_writer; pub mod block; pub mod equihash_solution; pub mod note_commitment_tree; +pub mod proofs; pub mod serialization; pub mod transaction; pub mod types; diff --git a/zebra-chain/src/proofs.rs b/zebra-chain/src/proofs.rs new file mode 100644 index 00000000000..b93815fb680 --- /dev/null +++ b/zebra-chain/src/proofs.rs @@ -0,0 +1,22 @@ +//! ZK proofs used in Zcash. + +use std::fmt::Debug; + +mod bctv14; +mod groth16; + +pub use bctv14::Bctv14Proof; +pub use groth16::Groth16Proof; + +/// A marker trait used to abstract over BCTV14 or Groth16 proofs. +pub trait ZkSnarkProof: Copy + Clone + Debug + PartialEq + Eq + private::Sealed {} +impl ZkSnarkProof for Bctv14Proof {} +impl ZkSnarkProof for Groth16Proof {} + +mod private { + use super::*; + + pub trait Sealed {} + impl Sealed for Bctv14Proof {} + impl Sealed for Groth16Proof {} +} diff --git a/zebra-chain/src/proofs/bctv14.rs b/zebra-chain/src/proofs/bctv14.rs new file mode 100644 index 00000000000..f10ebf4a86e --- /dev/null +++ b/zebra-chain/src/proofs/bctv14.rs @@ -0,0 +1,32 @@ +use std::fmt; + +/// An encoding of a BCTV14 proof, as used in Zcash. +pub struct Bctv14Proof(pub [u8; 296]); + +impl fmt::Debug for Bctv14Proof { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_tuple("Bctv14Proof") + .field(&hex::encode(&self.0[..])) + .finish() + } +} + +// These impls all only exist because of array length restrictions. + +impl Copy for Bctv14Proof {} + +impl Clone for Bctv14Proof { + fn clone(&self) -> Self { + let mut bytes = [0; 296]; + bytes[..].copy_from_slice(&self.0[..]); + Self(bytes) + } +} + +impl PartialEq for Bctv14Proof { + fn eq(&self, other: &Self) -> bool { + self.0[..] == other.0[..] + } +} + +impl Eq for Bctv14Proof {} diff --git a/zebra-chain/src/proofs/groth16.rs b/zebra-chain/src/proofs/groth16.rs new file mode 100644 index 00000000000..a2007e09640 --- /dev/null +++ b/zebra-chain/src/proofs/groth16.rs @@ -0,0 +1,32 @@ +use std::fmt; + +/// An encoding of a Groth16 proof, as used in Zcash. +pub struct Groth16Proof(pub [u8; 192]); + +impl fmt::Debug for Groth16Proof { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_tuple("Groth16Proof") + .field(&hex::encode(&self.0[..])) + .finish() + } +} + +// These impls all only exist because of array length restrictions. + +impl Copy for Groth16Proof {} + +impl Clone for Groth16Proof { + fn clone(&self) -> Self { + let mut bytes = [0; 192]; + bytes[..].copy_from_slice(&self.0[..]); + Self(bytes) + } +} + +impl PartialEq for Groth16Proof { + fn eq(&self, other: &Self) -> bool { + self.0[..] == other.0[..] + } +} + +impl Eq for Groth16Proof {} From 6950237f6b6d4704cda896a9c5e8924d39394c87 Mon Sep 17 00:00:00 2001 From: Henry de Valence Date: Wed, 27 Nov 2019 16:41:31 -0800 Subject: [PATCH 13/14] Make JoinSplit descriptions generic over the proof system. --- zebra-chain/src/transaction.rs | 9 +++-- zebra-chain/src/transaction/joinsplit.rs | 49 +++++------------------- 2 files changed, 14 insertions(+), 44 deletions(-) diff --git a/zebra-chain/src/transaction.rs b/zebra-chain/src/transaction.rs index a4f2c7a08bd..264ee6e84e0 100644 --- a/zebra-chain/src/transaction.rs +++ b/zebra-chain/src/transaction.rs @@ -10,10 +10,11 @@ mod transparent; mod tests; pub use hash::TransactionHash; -pub use joinsplit::{JoinSplitBctv14, JoinSplitGroth16, LegacyJoinSplitData, SaplingJoinSplitData}; +pub use joinsplit::{JoinSplit, JoinSplitData, SproutInputNoteData, SproutOutputNoteData}; pub use shielded_data::{OutputDescription, ShieldedData, SpendDescription}; pub use transparent::{OutPoint, TransparentInput, TransparentOutput}; +use crate::proofs::{Bctv14Proof, Groth16Proof}; use crate::types::{BlockHeight, LockTime}; /// A Zcash transaction. @@ -49,7 +50,7 @@ pub enum Transaction { /// chain. lock_time: LockTime, /// The JoinSplit data for this transaction, if any. - joinsplit_data: Option, + joinsplit_data: Option>, }, /// An Overwinter transaction (`version = 3`). V3 { @@ -63,7 +64,7 @@ pub enum Transaction { /// The latest block height that this transaction can be added to the chain. expiry_height: BlockHeight, /// The JoinSplit data for this transaction, if any. - joinsplit_data: Option, + joinsplit_data: Option>, }, /// A Sapling transaction (`version = 4`). V4 { @@ -82,6 +83,6 @@ pub enum Transaction { /// The shielded data for this transaction, if any. shielded_data: Option, /// The JoinSplit data for this transaction, if any. - joinsplit_data: Option, + joinsplit_data: Option>, }, } diff --git a/zebra-chain/src/transaction/joinsplit.rs b/zebra-chain/src/transaction/joinsplit.rs index f0b86287467..42d3be44074 100644 --- a/zebra-chain/src/transaction/joinsplit.rs +++ b/zebra-chain/src/transaction/joinsplit.rs @@ -1,3 +1,5 @@ +use crate::proofs::ZkSnarkProof; + /// Describes input notes to a Sprout transaction. /// /// The [protocol specification §7.2][ps] describes these fields as being encoded @@ -41,12 +43,11 @@ pub struct SproutOutputNoteData { pub enc_ciphertext: Vec, } -/// A _JoinSplit Description_ using BCTV14 proofs, as described in [protocol -/// specification §7.2][ps]. +/// A _JoinSplit Description_, as described in [protocol specification §7.2][ps]. /// /// [ps]: https://zips.z.cash/protocol/protocol.pdf#joinsplitencoding #[derive(Clone, Debug, PartialEq, Eq)] -pub struct JoinSplitBctv14 { +pub struct JoinSplit { /// A value that the JoinSplit transfer removes from the transparent value /// pool. /// @@ -57,64 +58,32 @@ pub struct JoinSplitBctv14 { /// /// XXX refine to an Amount vpub_new: u64, - /// A root of the Sprout note commitment tree at some block height in the /// past, or the root produced by a previous JoinSplit transfer in this /// transaction. /// /// XXX refine type anchor: [u8; 32], - /// An X25519 public key. /// /// XXX refine to an x25519-dalek type? ephemeral_key: [u8; 32], - /// A 256-bit seed that must be chosen independently at random for each /// JoinSplit description. random_seed: [u8; 32], - /// A sequence of input notes for this transaction. input_notes: Vec, - /// A sequence of output notes for this transaction. output_notes: Vec, - - /// A ZK JoinSplit proof using BCTV14. - /// - /// XXX refine type - /// XXX this should be a [u8; 296] but trait impls. - zkproof: Vec, -} - -/// A _JoinSplit Description_ using Groth16 proofs, as described in [protocol -/// specification §7.2][ps]. -/// -/// [ps]: https://zips.z.cash/protocol/protocol.pdf#joinsplitencoding -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct JoinSplitGroth16 { - // XXX use generic's + /// A ZK JoinSplit proof, either a [`Groth16Proof`] or a [`Bctv14Proof`]. + zkproof: P, } -/// Pre-Sapling JoinSplit data using Sprout-on-BCTV14 proofs. +/// A bundle of JoinSplit descriptions and signature data. #[derive(Clone, Debug, PartialEq, Eq)] -pub struct LegacyJoinSplitData { +pub struct JoinSplitData { /// A sequence of JoinSplit descriptions using BCTV14 proofs. - pub joinsplits: Vec, - /// The public key for the JoinSplit signature. - // XXX refine to a Zcash-flavored Ed25519 pubkey. - pub pub_key: [u8; 32], - /// The JoinSplit signature. - // XXX refine to a Zcash-flavored Ed25519 signature. - // for now it's [u64; 8] rather than [u8; 64] to get trait impls - pub sig: [u64; 8], -} - -/// Post-Sapling JoinSplit data using Sprout-on-Groth16 proofs. -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct SaplingJoinSplitData { - /// A sequence of JoinSplit descriptions using Groth16 proofs. - pub joinsplits: Vec, + pub joinsplits: Vec>, /// The public key for the JoinSplit signature. // XXX refine to a Zcash-flavored Ed25519 pubkey. pub pub_key: [u8; 32], From 76c64669bc7b77a08d0c62b236a1e1556294b694 Mon Sep 17 00:00:00 2001 From: Henry de Valence Date: Thu, 5 Dec 2019 10:05:52 -0800 Subject: [PATCH 14/14] Update zebra-chain/src/transaction/joinsplit.rs --- zebra-chain/src/transaction/joinsplit.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zebra-chain/src/transaction/joinsplit.rs b/zebra-chain/src/transaction/joinsplit.rs index 42d3be44074..0ac9618e070 100644 --- a/zebra-chain/src/transaction/joinsplit.rs +++ b/zebra-chain/src/transaction/joinsplit.rs @@ -82,7 +82,7 @@ pub struct JoinSplit { /// A bundle of JoinSplit descriptions and signature data. #[derive(Clone, Debug, PartialEq, Eq)] pub struct JoinSplitData { - /// A sequence of JoinSplit descriptions using BCTV14 proofs. + /// A sequence of JoinSplit descriptions using proofs of type `P`. pub joinsplits: Vec>, /// The public key for the JoinSplit signature. // XXX refine to a Zcash-flavored Ed25519 pubkey.