diff --git a/zcash_primitives/src/transaction/builder.rs b/zcash_primitives/src/transaction/builder.rs index b22d69071..6628783ad 100644 --- a/zcash_primitives/src/transaction/builder.rs +++ b/zcash_primitives/src/transaction/builder.rs @@ -21,7 +21,6 @@ use crate::{ components::{ amount::{Amount, BalanceError}, transparent::{self, builder::TransparentBuilder, TxOut}, - Orchard, Sapling, }, fees::FeeRule, sighash::{signature_hash, SignableInput}, @@ -757,14 +756,7 @@ impl<'a, P: consensus::Parameters, U: sapling::builder::ProverProgress> Builder< let txid_parts = unauthed_tx.digest(TxIdDigester); let transparent_bundle = unauthed_tx.transparent_bundle.clone().map(|b| { - b.apply_signatures::, - >, Orchard< - orchard::builder::InProgress< - orchard::builder::Unproven, - orchard::builder::Unauthorized, - >, - >>( + b.apply_signatures( #[cfg(feature = "transparent-inputs")] &unauthed_tx, #[cfg(feature = "transparent-inputs")] diff --git a/zcash_primitives/src/transaction/components.rs b/zcash_primitives/src/transaction/components.rs index 920cfd2a0..4265aeb96 100644 --- a/zcash_primitives/src/transaction/components.rs +++ b/zcash_primitives/src/transaction/components.rs @@ -36,9 +36,40 @@ pub use crate::sapling::bundle::{OutputDescription, SpendDescription}; #[cfg(zcash_unstable = "zfuture")] pub use self::tze::{TzeIn, TzeOut}; +use super::Authorization; + // π_A + π_B + π_C pub const GROTH_PROOF_SIZE: usize = 48 + 96 + 48; +pub trait Bundles { + type Transparent: TransparentPart; + type Sapling: SaplingPart; + type Orchard: OrchardPart; +} + +#[derive(Debug)] +pub struct AllBundles { + _auth: PhantomData, +} + +impl Bundles for AllBundles { + type Transparent = Transparent; + type Sapling = Sapling; + type Orchard = Orchard; +} + +pub struct SomeBundles { + _transparent: PhantomData, + _sapling: PhantomData, + _orchard: PhantomData, +} + +impl Bundles for SomeBundles { + type Transparent = T; + type Sapling = S; + type Orchard = O; +} + pub trait ShieldedValueBalance { fn value_balance(&self) -> Amount; } diff --git a/zcash_primitives/src/transaction/components/transparent/builder.rs b/zcash_primitives/src/transaction/components/transparent/builder.rs index 7b9ba964a..4df16310b 100644 --- a/zcash_primitives/src/transaction/components/transparent/builder.rs +++ b/zcash_primitives/src/transaction/components/transparent/builder.rs @@ -9,7 +9,6 @@ use crate::{ components::{ amount::{Amount, BalanceError, NonNegativeAmount}, transparent::{self, Authorization, Authorized, Bundle, TxIn, TxOut}, - OrchardPart, }, sighash::TransparentAuthorizingContext, }, @@ -240,13 +239,12 @@ impl TransparentAuthorizingContext for Unauthorized { } impl Bundle { - pub fn apply_signatures( + pub fn apply_signatures< + S: tx::sighash_v4::SaplingSigDigester, + B: tx::Bundles, Sapling = S>, + >( self, - #[cfg(feature = "transparent-inputs")] mtx: &TransactionData< - tx::Transparent, - S, - O, - >, + #[cfg(feature = "transparent-inputs")] mtx: &TransactionData, #[cfg(feature = "transparent-inputs")] txid_parts_cache: &TxDigests, ) -> Bundle { #[cfg(feature = "transparent-inputs")] diff --git a/zcash_primitives/src/transaction/mod.rs b/zcash_primitives/src/transaction/mod.rs index efc6105c1..5d4dd778a 100644 --- a/zcash_primitives/src/transaction/mod.rs +++ b/zcash_primitives/src/transaction/mod.rs @@ -31,8 +31,9 @@ use self::{ amount::{Amount, BalanceError}, orchard as orchard_serialization, sapling as sapling_serialization, sprout::{self, JsDescription}, - transparent, Orchard, OrchardEnc, OrchardPart, OutPoint, Sapling, SaplingEnc, SaplingPart, - ShieldedValueBalance, Transparent, TransparentEnc, TransparentPart, + transparent, AllBundles, Bundles, Orchard, OrchardEnc, OrchardPart, OutPoint, Sapling, + SaplingEnc, SaplingPart, ShieldedValueBalance, Transparent, TransparentEnc, + TransparentPart, }, txid::{to_txid, BlockTxCommitmentDigester, TxIdDigester}, util::sha256d::{HashReader, HashWriter}, @@ -299,11 +300,7 @@ impl Authorization for Unauthorized { } /// A Zcash transaction. -pub type Transaction = TransactionWith< - Transparent, - Sapling, - Orchard, ->; +pub type Transaction = TransactionWith>; /// An authorized Zcash transaction with configurable support in the type system for the /// various transparent and shielded pools. @@ -313,24 +310,26 @@ pub type Transaction = TransactionWith< /// - The serialization APIs will encode an empty bundle for that pool. /// - The parsing APIs will return an error when parsing a transaction with spends or /// outputs in that pool. -pub struct TransactionWith +pub struct TransactionWith where - T: TransparentPart, - S: SaplingPart, - O: OrchardPart, + B: Bundles, + B::Transparent: TransparentPart, + B::Sapling: SaplingPart, + B::Orchard: OrchardPart, { txid: TxId, - data: TransactionData, + data: TransactionData, } -impl fmt::Debug for TransactionWith +impl fmt::Debug for TransactionWith where - T: TransparentPart + fmt::Debug, - S: SaplingPart + fmt::Debug, - O: OrchardPart + fmt::Debug, - T::Bundle: fmt::Debug, - S::Bundle: fmt::Debug, - O::Bundle: fmt::Debug, + B: Bundles + fmt::Debug, + B::Transparent: TransparentPart + fmt::Debug, + B::Sapling: SaplingPart + fmt::Debug, + B::Orchard: OrchardPart + fmt::Debug, + ::Bundle: fmt::Debug, + ::Bundle: fmt::Debug, + ::Bundle: fmt::Debug, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("TransactionWith") @@ -340,60 +339,77 @@ where } } -impl Deref for TransactionWith +impl Deref for TransactionWith where - T: TransparentPart, - S: SaplingPart, - O: OrchardPart, + B: Bundles, + B::Transparent: TransparentPart, + B::Sapling: SaplingPart, + B::Orchard: OrchardPart, { - type Target = TransactionData; + type Target = TransactionData; - fn deref(&self) -> &TransactionData { + fn deref(&self) -> &TransactionData { &self.data } } -impl PartialEq for TransactionWith +impl PartialEq for TransactionWith where - T: TransparentPart, - S: SaplingPart, - O: OrchardPart, + B: Bundles, + B::Transparent: TransparentPart, + B::Sapling: SaplingPart, + B::Orchard: OrchardPart, { fn eq(&self, other: &Self) -> bool { self.txid == other.txid } } -type UnauthorizedTransactionDataWithSaplingProofs = TransactionData< - Transparent, - Sapling>, - Orchard< - orchard::builder::InProgress, - >, ->; +type UnauthorizedTransactionDataWithSaplingProofs = TransactionData>; -pub type AuthorizedTransactionData = TransactionData< - Transparent, - Sapling, - Orchard, ->; +pub type AuthorizedTransactionData = TransactionData>; /// The information contained in a Zcash transaction. -#[derive(Debug)] -pub struct TransactionData { +pub struct TransactionData { version: TxVersion, consensus_branch_id: BranchId, lock_time: u32, expiry_height: BlockHeight, - transparent_bundle: Option, + transparent_bundle: Option<::Bundle>, sprout_bundle: Option, - sapling_bundle: Option, - orchard_bundle: Option, + sapling_bundle: Option<::Bundle>, + orchard_bundle: Option<::Bundle>, #[cfg(zcash_unstable = "zfuture")] tze_bundle: Option>, } -impl TransactionData { +impl fmt::Debug for TransactionData +where + B: Bundles + fmt::Debug, + B::Transparent: TransparentPart + fmt::Debug, + B::Sapling: SaplingPart + fmt::Debug, + B::Orchard: OrchardPart + fmt::Debug, + ::Bundle: fmt::Debug, + ::Bundle: fmt::Debug, + ::Bundle: fmt::Debug, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut s = f.debug_struct("TransactionData"); + s.field("version", &self.version) + .field("consensus_branch_id", &self.consensus_branch_id) + .field("lock_time", &self.lock_time) + .field("expiry_height", &self.expiry_height) + .field("transparent_bundle", &self.transparent_bundle) + .field("sprout_bundle", &self.sprout_bundle) + .field("sapling_bundle", &self.sapling_bundle) + .field("orchard_bundle", &self.orchard_bundle); + #[cfg(zcash_unstable = "zfuture")] + s.field("tze_bundle", &self.tze_bundle); + s.finish() + } +} + +impl TransactionData { /// Constructs a `TransactionData` from its constituent parts. #[allow(clippy::too_many_arguments)] pub fn from_parts( @@ -401,10 +417,10 @@ impl TransactionData, + transparent_bundle: Option<::Bundle>, sprout_bundle: Option, - sapling_bundle: Option, - orchard_bundle: Option, + sapling_bundle: Option<::Bundle>, + orchard_bundle: Option<::Bundle>, ) -> Self { TransactionData { version, @@ -467,37 +483,31 @@ impl TransactionData - TransactionData, S, O> -{ +impl>> TransactionData { pub fn transparent_bundle(&self) -> Option<&transparent::Bundle> { self.transparent_bundle.as_ref() } } -impl TransactionData { +impl TransactionData { pub fn sprout_bundle(&self) -> Option<&sprout::Bundle> { self.sprout_bundle.as_ref() } } -impl - TransactionData, O> -{ +impl>> TransactionData { pub fn sapling_bundle(&self) -> Option<&sapling::Bundle> { self.sapling_bundle.as_ref() } } -impl - TransactionData> -{ +impl>> TransactionData { pub fn orchard_bundle(&self) -> Option<&orchard::Bundle> { self.orchard_bundle.as_ref() } } -impl TransactionData { +impl TransactionData { #[cfg(zcash_unstable = "zfuture")] pub fn tze_bundle(&self) -> Option<&tze::Bundle> { self.tze_bundle.as_ref() @@ -512,9 +522,10 @@ impl TransactionData Result, { let value_balances = [ - self.transparent_bundle - .as_ref() - .map_or_else(|| Ok(Amount::zero()), |b| T::value_balance(b, get_prevout))?, + self.transparent_bundle.as_ref().map_or_else( + || Ok(Amount::zero()), + |b| B::Transparent::value_balance(b, get_prevout), + )?, self.sprout_bundle.as_ref().map_or_else( || Ok(Amount::zero()), |b| b.value_balance().ok_or(BalanceError::Overflow), @@ -533,7 +544,7 @@ impl TransactionData>(&self, digester: D) -> D::Digest { + pub fn digest>(&self, digester: D) -> D::Digest { digester.combine( digester.digest_header( self.version, @@ -553,16 +564,22 @@ impl TransactionData( + pub fn map_bundles( self, - f_transparent: impl FnOnce(Option) -> Option, - f_sapling: impl FnOnce(Option) -> Option, - f_orchard: impl FnOnce(Option) -> Option, + f_transparent: impl FnOnce( + Option<::Bundle>, + ) -> Option<::Bundle>, + f_sapling: impl FnOnce( + Option<::Bundle>, + ) -> Option<::Bundle>, + f_orchard: impl FnOnce( + Option<::Bundle>, + ) -> Option<::Bundle>, #[cfg(zcash_unstable = "zfuture")] f_tze: impl FnOnce( Option>, ) -> Option>, - ) -> TransactionData { + ) -> TransactionData { TransactionData { version: self.version, consensus_branch_id: self.consensus_branch_id, @@ -578,24 +595,14 @@ impl TransactionData TransactionData, Sapling, Orchard> -where - TA: transparent::Authorization, - SA: sapling::bundle::Authorization, - OA: orchard::bundle::Authorization, -{ - pub fn map_authorization( +impl TransactionData> { + pub fn map_authorization( self, - f_transparent: impl transparent::MapAuth, - mut f_sapling: impl sapling_serialization::MapAuth, - mut f_orchard: impl orchard_serialization::MapAuth, - #[cfg(zcash_unstable = "zfuture")] f_tze: impl tze::MapAuth, - ) -> TransactionData, Sapling, Orchard> - where - TB: transparent::Authorization, - SB: sapling::bundle::Authorization, - OB: orchard::bundle::Authorization, - { + f_transparent: impl transparent::MapAuth, + mut f_sapling: impl sapling_serialization::MapAuth, + mut f_orchard: impl orchard_serialization::MapAuth, + #[cfg(zcash_unstable = "zfuture")] f_tze: impl tze::MapAuth, + ) -> TransactionData> { TransactionData { version: self.version, consensus_branch_id: self.consensus_branch_id, @@ -627,9 +634,7 @@ where } } -impl - TransactionData, O> -{ +impl>> TransactionData { pub fn sapling_value_balance(&self) -> Amount { self.sapling_bundle .as_ref() @@ -637,24 +642,26 @@ impl } } -impl TransactionData +impl TransactionData where - T: TransparentEnc + txid::TransparentDigester, - S: SaplingEnc + txid::SaplingDigester, - O: OrchardEnc + txid::OrchardDigester, + B: Bundles, + B::Transparent: TransparentEnc + txid::TransparentDigester, + B::Sapling: SaplingEnc + txid::SaplingDigester, + B::Orchard: OrchardEnc + txid::OrchardDigester, { - pub fn freeze(self) -> io::Result> { + pub fn freeze(self) -> io::Result> { TransactionWith::from_data(self) } } -impl TransactionWith +impl TransactionWith where - T: TransparentEnc + txid::TransparentDigester, - S: SaplingEnc + txid::SaplingDigester, - O: OrchardEnc + txid::OrchardDigester, + B: Bundles, + B::Transparent: TransparentEnc + txid::TransparentDigester, + B::Sapling: SaplingEnc + txid::SaplingDigester, + B::Orchard: OrchardEnc + txid::OrchardDigester, { - fn from_data(data: TransactionData) -> io::Result { + fn from_data(data: TransactionData) -> io::Result { match data.version { TxVersion::Sprout(_) | TxVersion::Overwinter | TxVersion::Sapling => { Self::from_data_v4(data) @@ -665,7 +672,7 @@ where } } - fn from_data_v4(data: TransactionData) -> io::Result { + fn from_data_v4(data: TransactionData) -> io::Result { let mut tx = TransactionWith { txid: TxId([0; 32]), data, @@ -676,7 +683,7 @@ where Ok(tx) } - fn from_data_v5(data: TransactionData) -> Self { + fn from_data_v5(data: TransactionData) -> Self { let txid = to_txid( data.version, data.consensus_branch_id, @@ -686,7 +693,7 @@ where TransactionWith { txid, data } } - pub fn into_data(self) -> TransactionData { + pub fn into_data(self) -> TransactionData { self.data } @@ -714,7 +721,7 @@ where version: TxVersion, consensus_branch_id: BranchId, ) -> io::Result { - let transparent_bundle = T::read(&mut reader)?; + let transparent_bundle = B::Transparent::read(&mut reader)?; let lock_time = reader.read_u32::()?; let expiry_height: BlockHeight = if version.has_overwinter() { @@ -723,7 +730,7 @@ where 0u32.into() }; - let components = S::read_v4_components(&mut reader, version.has_sapling())?; + let components = B::Sapling::read_v4_components(&mut reader, version.has_sapling())?; let sprout_bundle = if version.has_sprout() { let joinsplits = Vector::read(&mut reader, |r| { @@ -747,7 +754,7 @@ where }; let sapling_bundle = - S::read_v4_binding_sig(&mut reader, version.has_sapling(), components)?; + B::Sapling::read_v4_binding_sig(&mut reader, version.has_sapling(), components)?; let mut txid = [0; 32]; let hash_bytes = reader.into_hash(); @@ -780,9 +787,9 @@ where fn read_v5(mut reader: R, version: TxVersion) -> io::Result { let (consensus_branch_id, lock_time, expiry_height) = Self::read_v5_header_fragment(&mut reader)?; - let transparent_bundle = T::read(&mut reader)?; - let sapling_bundle = S::read_v5_bundle(&mut reader)?; - let orchard_bundle = O::read_v5_bundle(&mut reader)?; + let transparent_bundle = B::Transparent::read(&mut reader)?; + let sapling_bundle = B::Sapling::read_v5_bundle(&mut reader)?; + let orchard_bundle = B::Orchard::read_v5_bundle(&mut reader)?; #[cfg(zcash_unstable = "zfuture")] let tze_bundle = if version.has_tze() { @@ -863,7 +870,7 @@ where writer.write_u32::(u32::from(self.expiry_height))?; } - S::write_v4_components( + B::Sapling::write_v4_components( self.sapling_bundle.as_ref(), &mut writer, self.version.has_sapling(), @@ -879,7 +886,7 @@ where } } - S::write_v4_binding_sig( + B::Sapling::write_v4_binding_sig( self.sapling_bundle.as_ref(), &mut writer, self.version.has_sapling(), @@ -896,7 +903,7 @@ where } pub fn write_transparent(&self, writer: W) -> io::Result<()> { - T::write(self.transparent_bundle.as_ref(), writer) + B::Transparent::write(self.transparent_bundle.as_ref(), writer) } pub fn write_v5(&self, mut writer: W) -> io::Result<()> { @@ -909,7 +916,7 @@ where self.write_v5_header(&mut writer)?; self.write_transparent(&mut writer)?; self.write_v5_sapling(&mut writer)?; - O::write_v5_bundle(self.orchard_bundle.as_ref(), &mut writer)?; + B::Orchard::write_v5_bundle(self.orchard_bundle.as_ref(), &mut writer)?; #[cfg(zcash_unstable = "zfuture")] self.write_tze(&mut writer)?; Ok(()) @@ -932,7 +939,7 @@ where } pub fn write_v5_sapling(&self, writer: W) -> io::Result<()> { - S::write_v5_bundle(self.sapling_bundle.as_ref(), writer) + B::Sapling::write_v5_bundle(self.sapling_bundle.as_ref(), writer) } #[cfg(zcash_unstable = "zfuture")] @@ -949,13 +956,7 @@ where } } -impl - TransactionWith< - Transparent, - Sapling, - Orchard, - > -{ +impl Transaction { // TODO: should this be moved to `from_data` and stored? pub fn auth_commitment(&self) -> Blake2bHash { self.data.digest(BlockTxCommitmentDigester) @@ -986,7 +987,7 @@ pub struct TxDigests { pub tze_digests: Option>, } -pub trait TransactionDigest { +pub trait TransactionDigest { type HeaderDigest; type TransparentDigest; type SaplingDigest; @@ -1005,12 +1006,20 @@ pub trait TransactionDigest expiry_height: BlockHeight, ) -> Self::HeaderDigest; - fn digest_transparent(&self, transparent_bundle: Option<&T::Bundle>) - -> Self::TransparentDigest; + fn digest_transparent( + &self, + transparent_bundle: Option<&::Bundle>, + ) -> Self::TransparentDigest; - fn digest_sapling(&self, sapling_bundle: Option<&S::Bundle>) -> Self::SaplingDigest; + fn digest_sapling( + &self, + sapling_bundle: Option<&::Bundle>, + ) -> Self::SaplingDigest; - fn digest_orchard(&self, orchard_bundle: Option<&O::Bundle>) -> Self::OrchardDigest; + fn digest_orchard( + &self, + orchard_bundle: Option<&::Bundle>, + ) -> Self::OrchardDigest; #[cfg(zcash_unstable = "zfuture")] fn digest_tze(&self, tze_bundle: Option<&tze::Bundle>) -> Self::TzeDigest; diff --git a/zcash_primitives/src/transaction/sighash.rs b/zcash_primitives/src/transaction/sighash.rs index c98933ec0..e9f9d441e 100644 --- a/zcash_primitives/src/transaction/sighash.rs +++ b/zcash_primitives/src/transaction/sighash.rs @@ -1,7 +1,7 @@ use blake2b_simd::Hash as Blake2bHash; use super::{ - components::{amount::NonNegativeAmount, transparent, OrchardPart}, + components::{amount::NonNegativeAmount, transparent, Bundles}, sighash_v4::{self, v4_signature_hash}, sighash_v5::{self, v5_signature_hash}, TransactionData, TxDigests, TxVersion, @@ -72,15 +72,15 @@ pub trait TransparentAuthorizingContext: transparent::Authorization { /// the full data of the transaction, the input being signed, and the /// set of precomputed hashes produced in the construction of the /// transaction ID. -pub fn signature_hash<'a, T, S, O>( - tx: &TransactionData, +pub fn signature_hash<'a, B>( + tx: &TransactionData, signable_input: &SignableInput<'a>, txid_parts: &TxDigests, ) -> SignatureHash where - T: sighash_v4::TransparentSigDigester + sighash_v5::TransparentSigDigester, - S: sighash_v4::SaplingSigDigester, - O: OrchardPart, + B: Bundles, + B::Transparent: sighash_v4::TransparentSigDigester + sighash_v5::TransparentSigDigester, + B::Sapling: sighash_v4::SaplingSigDigester, { SignatureHash(match tx.version { TxVersion::Sprout(_) | TxVersion::Overwinter | TxVersion::Sapling => { diff --git a/zcash_primitives/src/transaction/sighash_v4.rs b/zcash_primitives/src/transaction/sighash_v4.rs index 527bf35d4..8a01e0631 100644 --- a/zcash_primitives/src/transaction/sighash_v4.rs +++ b/zcash_primitives/src/transaction/sighash_v4.rs @@ -15,8 +15,8 @@ use super::{ sapling as sapling_serialization, sprout::JsDescription, transparent::{self, TxIn, TxOut}, - NoSapling, NoTransparent, OrchardPart, Sapling, SaplingPart, ShieldedValueBalance, - Transparent, TransparentPart, + Bundles, NoSapling, NoTransparent, Sapling, SaplingPart, ShieldedValueBalance, Transparent, + TransparentPart, }, sighash::{SignableInput, SIGHASH_ANYONECANPAY, SIGHASH_MASK, SIGHASH_NONE, SIGHASH_SINGLE}, TransactionData, @@ -289,14 +289,14 @@ fn shielded_outputs_hash(shielded_outputs: &[OutputDescription] .hash(&data) } -pub fn v4_signature_hash( - tx: &TransactionData, +pub fn v4_signature_hash( + tx: &TransactionData, signable_input: &SignableInput<'_>, ) -> Blake2bHash where - T: TransparentSigDigester, - S: SaplingSigDigester, - O: OrchardPart, + B: Bundles, + B::Transparent: TransparentSigDigester, + B::Sapling: SaplingSigDigester, { let hash_type = signable_input.hash_type(); if tx.version.has_overwinter() { @@ -314,22 +314,22 @@ where update_hash!( h, hash_type & SIGHASH_ANYONECANPAY == 0, - T::digest_prevout(tx.transparent_bundle.as_ref()) + B::Transparent::digest_prevout(tx.transparent_bundle.as_ref()) ); update_hash!( h, (hash_type & SIGHASH_ANYONECANPAY) == 0 && (hash_type & SIGHASH_MASK) != SIGHASH_SINGLE && (hash_type & SIGHASH_MASK) != SIGHASH_NONE, - T::digest_sequence(tx.transparent_bundle.as_ref()) + B::Transparent::digest_sequence(tx.transparent_bundle.as_ref()) ); if (hash_type & SIGHASH_MASK) != SIGHASH_SINGLE && (hash_type & SIGHASH_MASK) != SIGHASH_NONE { - h.update(T::digest_outputs(tx.transparent_bundle.as_ref()).as_bytes()); + h.update(B::Transparent::digest_outputs(tx.transparent_bundle.as_ref()).as_bytes()); } else if (hash_type & SIGHASH_MASK) == SIGHASH_SINGLE { - h.update(&T::digest_single_output( + h.update(&B::Transparent::digest_single_output( tx.transparent_bundle.as_ref(), signable_input, )); @@ -353,8 +353,8 @@ where ); if tx.version.has_sapling() { - h.update(&S::digest_spends(tx.sapling_bundle.as_ref())); - h.update(&S::digest_outputs(tx.sapling_bundle.as_ref())); + h.update(&B::Sapling::digest_spends(tx.sapling_bundle.as_ref())); + h.update(&B::Sapling::digest_outputs(tx.sapling_bundle.as_ref())); } h.update(&tx.lock_time.to_le_bytes()); h.update(&u32::from(tx.expiry_height).to_le_bytes()); @@ -371,7 +371,7 @@ where match signable_input { SignableInput::Shielded => (), SignableInput::Transparent { .. } => { - h.update(&T::digest_signable_input( + h.update(&B::Transparent::digest_signable_input( tx.transparent_bundle.as_ref(), signable_input, )); diff --git a/zcash_primitives/src/transaction/sighash_v5.rs b/zcash_primitives/src/transaction/sighash_v5.rs index cf3896364..e74f7aa81 100644 --- a/zcash_primitives/src/transaction/sighash_v5.rs +++ b/zcash_primitives/src/transaction/sighash_v5.rs @@ -6,7 +6,7 @@ use zcash_encoding::Array; use crate::transaction::{ components::{ transparent::{self, TxOut}, - NoTransparent, OrchardPart, SaplingPart, Transparent, TransparentPart, + Bundles, NoTransparent, Transparent, TransparentPart, }, sighash::{ SignableInput, TransparentAuthorizingContext, SIGHASH_ANYONECANPAY, SIGHASH_MASK, @@ -199,15 +199,14 @@ fn tze_input_sigdigests( } /// Implements the [Signature Digest section of ZIP 244](https://zips.z.cash/zip-0244#signature-digest) -pub fn v5_signature_hash( - tx: &TransactionData, +pub fn v5_signature_hash( + tx: &TransactionData, signable_input: &SignableInput<'_>, txid_parts: &TxDigests, ) -> Blake2bHash where - T: TransparentSigDigester, - S: SaplingPart, - O: OrchardPart, + B: Bundles, + B::Transparent: TransparentSigDigester, { // The caller must provide the transparent digests if and only if the transaction has a // transparent component. @@ -220,7 +219,7 @@ where tx.version, tx.consensus_branch_id, txid_parts.header_digest, - T::digest( + B::Transparent::digest( tx.transparent_bundle .as_ref() .zip(txid_parts.transparent_digests.as_ref()), diff --git a/zcash_primitives/src/transaction/tests.rs b/zcash_primitives/src/transaction/tests.rs index 92ece27c2..251d85837 100644 --- a/zcash_primitives/src/transaction/tests.rs +++ b/zcash_primitives/src/transaction/tests.rs @@ -18,7 +18,7 @@ use super::{ testing::arb_tx, transparent::{self, TxIn}, txid::TxIdDigester, - Orchard, Sapling, Transaction, TransactionData, Transparent, TxDigests, + AllBundles, Authorization, Transaction, TransactionData, TxDigests, }; #[cfg(zcash_unstable = "zfuture")] @@ -195,11 +195,18 @@ impl TransparentAuthorizingContext for TestTransparentAuth { } } -type TestUnauthorizedTransactionData = TransactionData< - Transparent, - Sapling, - Orchard, ->; +struct TestUnauthorized; + +impl Authorization for TestUnauthorized { + type TransparentAuth = TestTransparentAuth; + type SaplingAuth = sapling::bundle::Authorized; + type OrchardAuth = orchard::bundle::Authorized; + + #[cfg(zcash_unstable = "zfuture")] + type TzeAuth = tze::Authorized; +} + +type TestUnauthorizedTransactionData = TransactionData>; #[test] fn zip_0244() { diff --git a/zcash_primitives/src/transaction/txid.rs b/zcash_primitives/src/transaction/txid.rs index 71ae51934..04d38458d 100644 --- a/zcash_primitives/src/transaction/txid.rs +++ b/zcash_primitives/src/transaction/txid.rs @@ -19,10 +19,10 @@ use super::{ components::{ amount::Amount, transparent::{self, TxIn, TxOut}, - NoOrchard, NoSapling, NoTransparent, Orchard, OrchardPart, Sapling, SaplingPart, - Transparent, TransparentPart, + AllBundles, Bundles, NoOrchard, NoSapling, NoTransparent, Orchard, OrchardPart, Sapling, + SaplingPart, Transparent, TransparentPart, }, - TransactionDigest, TransparentDigests, TxDigests, TxId, TxVersion, + Authorized, TransactionDigest, TransparentDigests, TxDigests, TxId, TxVersion, }; #[cfg(zcash_unstable = "zfuture")] @@ -350,11 +350,12 @@ fn hash_tze_txid_data(tze_digests: Option<&TzeDigests>) -> Blake2bH /// This implements the [TxId Digest section of ZIP 244](https://zips.z.cash/zip-0244#txid-digest) pub struct TxIdDigester; -impl TransactionDigest for TxIdDigester +impl TransactionDigest for TxIdDigester where - T: TransparentDigester, - S: SaplingDigester, - O: OrchardDigester, + B: Bundles, + B::Transparent: TransparentDigester, + B::Sapling: SaplingDigester, + B::Orchard: OrchardDigester, { type HeaderDigest = Blake2bHash; type TransparentDigest = Option>; @@ -378,17 +379,23 @@ where fn digest_transparent( &self, - transparent_bundle: Option<&T::Bundle>, + transparent_bundle: Option<&::Bundle>, ) -> Self::TransparentDigest { - T::digest(transparent_bundle) + B::Transparent::digest(transparent_bundle) } - fn digest_sapling(&self, sapling_bundle: Option<&S::Bundle>) -> Self::SaplingDigest { - S::digest(sapling_bundle) + fn digest_sapling( + &self, + sapling_bundle: Option<&::Bundle>, + ) -> Self::SaplingDigest { + B::Sapling::digest(sapling_bundle) } - fn digest_orchard(&self, orchard_bundle: Option<&O::Bundle>) -> Self::OrchardDigest { - O::digest(orchard_bundle) + fn digest_orchard( + &self, + orchard_bundle: Option<&::Bundle>, + ) -> Self::OrchardDigest { + B::Orchard::digest(orchard_bundle) } #[cfg(zcash_unstable = "zfuture")] @@ -536,13 +543,7 @@ impl OrchardWitnessDigester for Orchard { /// function. pub struct BlockTxCommitmentDigester; -impl - TransactionDigest< - Transparent, - Sapling, - Orchard, - > for BlockTxCommitmentDigester -{ +impl TransactionDigest> for BlockTxCommitmentDigester { /// We use the header digest to pass the transaction ID into /// where it needs to be used for personalization string construction. type HeaderDigest = BranchId;