From 4ec2607323be8feb806696dd95aa4b27b2107694 Mon Sep 17 00:00:00 2001 From: Alfredo Garcia Date: Mon, 13 May 2024 18:03:08 -0300 Subject: [PATCH 1/7] upgrade zcash_primitives and orchard only for zebra-chain crate --- Cargo.lock | 8 ++- zebra-chain/Cargo.toml | 5 +- zebra-chain/src/primitives/address.rs | 1 - .../src/primitives/viewing_key/sapling.rs | 10 ++-- .../src/primitives/zcash_note_encryption.rs | 8 ++- .../src/primitives/zcash_primitives.rs | 50 ++++++++----------- zebra-chain/src/transaction/serialize.rs | 17 ++++--- 7 files changed, 46 insertions(+), 53 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a58df8593d2..ecc4b70e584 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5825,7 +5825,6 @@ dependencies = [ "ff", "fpe", "group", - "hdwallet", "hex", "incrementalmerkletree", "jubjub", @@ -5835,8 +5834,6 @@ dependencies = [ "orchard 0.6.0", "rand 0.8.5", "rand_core 0.6.4", - "ripemd", - "secp256k1", "sha2", "subtle", "zcash_address", @@ -6012,7 +6009,7 @@ dependencies = [ "jubjub", "lazy_static", "num-integer", - "orchard 0.6.0", + "orchard 0.7.1", "primitive-types", "proptest", "proptest-derive", @@ -6023,6 +6020,7 @@ dependencies = [ "reddsa", "redjubjub", "ripemd", + "sapling-crypto", "secp256k1", "serde", "serde-big-array", @@ -6042,7 +6040,7 @@ dependencies = [ "zcash_encoding", "zcash_history", "zcash_note_encryption", - "zcash_primitives 0.13.0", + "zcash_primitives 0.14.0", "zcash_protocol", "zebra-test", ] diff --git a/zebra-chain/Cargo.toml b/zebra-chain/Cargo.toml index 23b63ae718f..00d0067fdf7 100644 --- a/zebra-chain/Cargo.toml +++ b/zebra-chain/Cargo.toml @@ -93,11 +93,12 @@ x25519-dalek = { version = "2.0.1", features = ["serde"] } # ECC deps halo2 = { package = "halo2_proofs", version = "0.3.0" } -orchard = "0.6.0" +orchard = "0.7.0" zcash_encoding = "0.2.0" zcash_history = "0.4.0" zcash_note_encryption = "0.4.0" -zcash_primitives = { version = "0.13.0", features = ["transparent-inputs"] } +zcash_primitives = { version = "0.14.0", features = ["transparent-inputs"] } +sapling = { package = "sapling-crypto", version = "0.1" } zcash_protocol = { version = "0.1.1" } zcash_address = { version = "0.3.2" } diff --git a/zebra-chain/src/primitives/address.rs b/zebra-chain/src/primitives/address.rs index 86d524b8dba..f076c0c3322 100644 --- a/zebra-chain/src/primitives/address.rs +++ b/zebra-chain/src/primitives/address.rs @@ -3,7 +3,6 @@ //! Usage: use zcash_address::unified::{self, Container}; -use zcash_primitives::sapling; use crate::{parameters::NetworkKind, transparent, BoxError}; diff --git a/zebra-chain/src/primitives/viewing_key/sapling.rs b/zebra-chain/src/primitives/viewing_key/sapling.rs index e8d423a7fc0..3e483def126 100644 --- a/zebra-chain/src/primitives/viewing_key/sapling.rs +++ b/zebra-chain/src/primitives/viewing_key/sapling.rs @@ -1,11 +1,11 @@ //! Defines types and implements methods for parsing Sapling viewing keys and converting them to `zebra-chain` types -use zcash_client_backend::encoding::decode_extended_full_viewing_key; -use zcash_primitives::{ - constants::*, - sapling::keys::{FullViewingKey as SaplingFvk, SaplingIvk}, - zip32::DiversifiableFullViewingKey as SaplingDfvk, +use sapling::keys::{FullViewingKey as SaplingFvk, SaplingIvk}; +use zcash_client_backend::{ + encoding::decode_extended_full_viewing_key, + keys::sapling::DiversifiableFullViewingKey as SaplingDfvk, }; +use zcash_primitives::constants::*; use crate::parameters::Network; diff --git a/zebra-chain/src/primitives/zcash_note_encryption.rs b/zebra-chain/src/primitives/zcash_note_encryption.rs index f8e47fbad47..457a5c04b94 100644 --- a/zebra-chain/src/primitives/zcash_note_encryption.rs +++ b/zebra-chain/src/primitives/zcash_note_encryption.rs @@ -20,16 +20,14 @@ pub fn decrypts_successfully(transaction: &Transaction, network: &Network, heigh let alt_tx = convert_tx_to_librustzcash(transaction, network_upgrade) .expect("zcash_primitives and Zebra transaction formats must be compatible"); - let alt_height = height.0.into(); - let null_sapling_ovk = zcash_primitives::keys::OutgoingViewingKey([0u8; 32]); + let null_sapling_ovk = sapling::keys::OutgoingViewingKey([0u8; 32]); if let Some(bundle) = alt_tx.sapling_bundle() { for output in bundle.shielded_outputs().iter() { - let recovery = zcash_primitives::sapling::note_encryption::try_sapling_output_recovery( - network, - alt_height, + let recovery = sapling::note_encryption::try_sapling_output_recovery( &null_sapling_ovk, output, + sapling::note_encryption::Zip212Enforcement::GracePeriod, ); if recovery.is_none() { return false; diff --git a/zebra-chain/src/primitives/zcash_primitives.rs b/zebra-chain/src/primitives/zcash_primitives.rs index 564afab095e..c622c6d262a 100644 --- a/zebra-chain/src/primitives/zcash_primitives.rs +++ b/zebra-chain/src/primitives/zcash_primitives.rs @@ -29,11 +29,11 @@ impl zp_tx::components::transparent::Authorization for TransparentAuth<'_> { // In this block we convert our Output to a librustzcash to TxOut. // (We could do the serialize/deserialize route but it's simple enough to convert manually) impl zp_tx::sighash::TransparentAuthorizingContext for TransparentAuth<'_> { - fn input_amounts(&self) -> Vec { + fn input_amounts(&self) -> Vec { self.all_prev_outputs .iter() .map(|prevout| { - zp_tx::components::amount::Amount::from_nonnegative_i64_le_bytes( + zp_tx::components::amount::NonNegativeAmount::from_nonnegative_i64_le_bytes( prevout.value.to_bytes(), ) .expect("will not fail since it was previously validated") @@ -83,39 +83,31 @@ impl<'a> struct IdentityMap; -impl - zp_tx::components::sapling::MapAuth< - zp_tx::components::sapling::Authorized, - zp_tx::components::sapling::Authorized, - > for IdentityMap +impl zp_tx::components::sapling::MapAuth + for IdentityMap { fn map_spend_proof( - &self, - p: ::SpendProof, - ) -> ::SpendProof - { + &mut self, + p: ::SpendProof, + ) -> ::SpendProof { p } fn map_output_proof( - &self, - p: ::OutputProof, - ) -> ::OutputProof - { + &mut self, + p: ::OutputProof, + ) -> ::OutputProof { p } fn map_auth_sig( - &self, - s: ::AuthSig, - ) -> ::AuthSig{ + &mut self, + s: ::AuthSig, + ) -> ::AuthSig { s } - fn map_authorization( - &self, - a: zp_tx::components::sapling::Authorized, - ) -> zp_tx::components::sapling::Authorized { + fn map_authorization(&mut self, a: sapling::bundle::Authorized) -> sapling::bundle::Authorized { a } } @@ -141,7 +133,7 @@ struct PrecomputedAuth<'a> { impl<'a> zp_tx::Authorization for PrecomputedAuth<'a> { type TransparentAuth = TransparentAuth<'a>; - type SaplingAuth = zp_tx::components::sapling::Authorized; + type SaplingAuth = sapling::bundle::Authorized; type OrchardAuth = orchard::bundle::Authorized; } @@ -269,10 +261,10 @@ pub(crate) fn sighash( index: input_index, script_code: &script, script_pubkey: &script, - value: output - .value - .try_into() - .expect("amount was previously validated"), + value: zp_tx::components::amount::NonNegativeAmount::from_nonnegative_i64_le_bytes( + output.value.to_bytes(), + ) + .expect("amount was previously validated"), } } None => zp_tx::sighash::SignableInput::Shielded, @@ -327,10 +319,10 @@ pub(crate) fn transparent_output_address( let alt_addr = tx_out.recipient_address(); match alt_addr { - Some(zcash_primitives::legacy::TransparentAddress::PublicKey(pub_key_hash)) => Some( + Some(zcash_primitives::legacy::TransparentAddress::PublicKeyHash(pub_key_hash)) => Some( transparent::Address::from_pub_key_hash(network.kind(), pub_key_hash), ), - Some(zcash_primitives::legacy::TransparentAddress::Script(script_hash)) => Some( + Some(zcash_primitives::legacy::TransparentAddress::ScriptHash(script_hash)) => Some( transparent::Address::from_script_hash(network.kind(), script_hash), ), None => None, diff --git a/zebra-chain/src/transaction/serialize.rs b/zebra-chain/src/transaction/serialize.rs index 044db7d5109..612680c2e35 100644 --- a/zebra-chain/src/transaction/serialize.rs +++ b/zebra-chain/src/transaction/serialize.rs @@ -21,7 +21,7 @@ use crate::{ }; use super::*; -use sapling::{Output, SharedAnchor, Spend}; +use crate::sapling::SharedAnchor; impl ZcashDeserialize for jubjub::Fq { fn zcash_deserialize(mut reader: R) -> Result { @@ -140,8 +140,11 @@ impl ZcashSerialize for sapling::ShieldedData { let (spend_proofs, spend_sigs) = spend_proofs_sigs.into_iter().unzip(); // Collect arrays for Outputs - let (output_prefixes, output_proofs): (Vec<_>, _) = - self.outputs().cloned().map(Output::into_v5_parts).unzip(); + let (output_prefixes, output_proofs): (Vec<_>, _) = self + .outputs() + .cloned() + .map(sapling::Output::into_v5_parts) + .unzip(); // Denoted as `nSpendsSapling` and `vSpendsSapling` in the spec. spend_prefixes.zcash_serialize(&mut writer)?; @@ -269,14 +272,16 @@ impl ZcashDeserialize for Option> { .into_iter() .zip(spend_proofs) .zip(spend_sigs) - .map(|((prefix, proof), sig)| Spend::::from_v5_parts(prefix, proof, sig)) + .map(|((prefix, proof), sig)| { + sapling::Spend::::from_v5_parts(prefix, proof, sig) + }) .collect(); // Create shielded outputs from deserialized parts let outputs = output_prefixes .into_iter() .zip(output_proofs) - .map(|(prefix, proof)| Output::from_v5_parts(prefix, proof)) + .map(|(prefix, proof)| sapling::Output::from_v5_parts(prefix, proof)) .collect(); // Create transfers @@ -823,7 +828,7 @@ impl ZcashDeserialize for Transaction { let shielded_outputs = Vec::::zcash_deserialize(&mut limited_reader)? .into_iter() - .map(Output::from_v4) + .map(sapling::Output::from_v4) .collect(); // A bundle of fields denoted in the spec as `nJoinSplit`, `vJoinSplit`, From 617fc03b5780cd322de41bb273507d811b53afd0 Mon Sep 17 00:00:00 2001 From: Alfredo Garcia Date: Fri, 17 May 2024 13:32:37 -0300 Subject: [PATCH 2/7] update and use TryFrom for amounts --- zebra-chain/src/primitives/zcash_primitives.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/zebra-chain/src/primitives/zcash_primitives.rs b/zebra-chain/src/primitives/zcash_primitives.rs index c622c6d262a..fd78eba12f1 100644 --- a/zebra-chain/src/primitives/zcash_primitives.rs +++ b/zebra-chain/src/primitives/zcash_primitives.rs @@ -205,12 +205,12 @@ impl TryFrom for zp_tx::components::TxOut { } } -/// Convert a Zebra Amount into a librustzcash one. -impl TryFrom> for zp_tx::components::Amount { +/// Convert a Zebra non-negative Amount into a librustzcash one. +impl TryFrom> for zp_tx::components::amount::NonNegativeAmount { type Error = (); fn try_from(amount: Amount) -> Result { - zp_tx::components::Amount::from_u64(amount.into()) + zp_tx::components::amount::NonNegativeAmount::from_nonnegative_i64(amount.into()) } } @@ -261,10 +261,10 @@ pub(crate) fn sighash( index: input_index, script_code: &script, script_pubkey: &script, - value: zp_tx::components::amount::NonNegativeAmount::from_nonnegative_i64_le_bytes( - output.value.to_bytes(), - ) - .expect("amount was previously validated"), + value: output + .value + .try_into() + .expect("amount was previously validated"), } } None => zp_tx::sighash::SignableInput::Shielded, From 1da71d8888782d25f82118f6810421075f31c246 Mon Sep 17 00:00:00 2001 From: Alfredo Garcia Date: Fri, 17 May 2024 13:45:49 -0300 Subject: [PATCH 3/7] fix imports in serialize --- zebra-chain/src/transaction/serialize.rs | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/zebra-chain/src/transaction/serialize.rs b/zebra-chain/src/transaction/serialize.rs index 612680c2e35..346ae91e561 100644 --- a/zebra-chain/src/transaction/serialize.rs +++ b/zebra-chain/src/transaction/serialize.rs @@ -21,7 +21,7 @@ use crate::{ }; use super::*; -use crate::sapling::SharedAnchor; +use crate::sapling::{Output, SharedAnchor, Spend}; impl ZcashDeserialize for jubjub::Fq { fn zcash_deserialize(mut reader: R) -> Result { @@ -134,17 +134,14 @@ impl ZcashSerialize for sapling::ShieldedData { let (spend_prefixes, spend_proofs_sigs): (Vec<_>, Vec<_>) = self .spends() .cloned() - .map(sapling::Spend::::into_v5_parts) + .map(Spend::::into_v5_parts) .map(|(prefix, proof, sig)| (prefix, (proof, sig))) .unzip(); let (spend_proofs, spend_sigs) = spend_proofs_sigs.into_iter().unzip(); // Collect arrays for Outputs - let (output_prefixes, output_proofs): (Vec<_>, _) = self - .outputs() - .cloned() - .map(sapling::Output::into_v5_parts) - .unzip(); + let (output_prefixes, output_proofs): (Vec<_>, _) = + self.outputs().cloned().map(Output::into_v5_parts).unzip(); // Denoted as `nSpendsSapling` and `vSpendsSapling` in the spec. spend_prefixes.zcash_serialize(&mut writer)?; @@ -272,16 +269,14 @@ impl ZcashDeserialize for Option> { .into_iter() .zip(spend_proofs) .zip(spend_sigs) - .map(|((prefix, proof), sig)| { - sapling::Spend::::from_v5_parts(prefix, proof, sig) - }) + .map(|((prefix, proof), sig)| Spend::::from_v5_parts(prefix, proof, sig)) .collect(); // Create shielded outputs from deserialized parts let outputs = output_prefixes .into_iter() .zip(output_proofs) - .map(|(prefix, proof)| sapling::Output::from_v5_parts(prefix, proof)) + .map(|(prefix, proof)| Output::from_v5_parts(prefix, proof)) .collect(); // Create transfers @@ -297,7 +292,7 @@ impl ZcashDeserialize for Option> { // // This rule is also implemented in // [`zebra_state::service::check::anchor`] and - // [`zebra_chain::sapling::spend`]. + // [`zebra_chain::Spend`]. // // The "anchor encoding for v5 transactions" is implemented here. let transfers = match shared_anchor { @@ -828,7 +823,7 @@ impl ZcashDeserialize for Transaction { let shielded_outputs = Vec::::zcash_deserialize(&mut limited_reader)? .into_iter() - .map(sapling::Output::from_v4) + .map(Output::from_v4) .collect(); // A bundle of fields denoted in the spec as `nJoinSplit`, `vJoinSplit`, From 66894df6b842185e4e720c8b25455a1745ff3655 Mon Sep 17 00:00:00 2001 From: Alfredo Garcia Date: Fri, 17 May 2024 13:48:16 -0300 Subject: [PATCH 4/7] leave doc as it was --- zebra-chain/src/transaction/serialize.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zebra-chain/src/transaction/serialize.rs b/zebra-chain/src/transaction/serialize.rs index 346ae91e561..1b5cd98f491 100644 --- a/zebra-chain/src/transaction/serialize.rs +++ b/zebra-chain/src/transaction/serialize.rs @@ -292,7 +292,7 @@ impl ZcashDeserialize for Option> { // // This rule is also implemented in // [`zebra_state::service::check::anchor`] and - // [`zebra_chain::Spend`]. + // [`zebra_chain::sapling::Spend`]. // // The "anchor encoding for v5 transactions" is implemented here. let transfers = match shared_anchor { From ba7fc7b8cf52fdbf5a0febbc9c982e25c2a3c5e5 Mon Sep 17 00:00:00 2001 From: Alfredo Garcia Date: Fri, 17 May 2024 13:50:10 -0300 Subject: [PATCH 5/7] leave doc as it was 2 --- zebra-chain/src/transaction/serialize.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zebra-chain/src/transaction/serialize.rs b/zebra-chain/src/transaction/serialize.rs index 1b5cd98f491..2b3eafb8966 100644 --- a/zebra-chain/src/transaction/serialize.rs +++ b/zebra-chain/src/transaction/serialize.rs @@ -292,7 +292,7 @@ impl ZcashDeserialize for Option> { // // This rule is also implemented in // [`zebra_state::service::check::anchor`] and - // [`zebra_chain::sapling::Spend`]. + // [`zebra_chain::sapling::spend`]. // // The "anchor encoding for v5 transactions" is implemented here. let transfers = match shared_anchor { From bca2c287469a158532f2c34c482252b1bc710a54 Mon Sep 17 00:00:00 2001 From: Alfredo Garcia Date: Sat, 18 May 2024 16:36:05 -0300 Subject: [PATCH 6/7] use `try_into` for amount --- zebra-chain/src/primitives/zcash_primitives.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/zebra-chain/src/primitives/zcash_primitives.rs b/zebra-chain/src/primitives/zcash_primitives.rs index fd78eba12f1..2e7aa339639 100644 --- a/zebra-chain/src/primitives/zcash_primitives.rs +++ b/zebra-chain/src/primitives/zcash_primitives.rs @@ -33,10 +33,10 @@ impl zp_tx::sighash::TransparentAuthorizingContext for TransparentAuth<'_> { self.all_prev_outputs .iter() .map(|prevout| { - zp_tx::components::amount::NonNegativeAmount::from_nonnegative_i64_le_bytes( - prevout.value.to_bytes(), - ) - .expect("will not fail since it was previously validated") + prevout + .value + .try_into() + .expect("will not fail since it was previously validated") }) .collect() } From 3e4aa041a427457b8feea2279105c3176aa63ea3 Mon Sep 17 00:00:00 2001 From: Alfredo Garcia Date: Sat, 18 May 2024 16:46:01 -0300 Subject: [PATCH 7/7] use `zip_212_enforcement` --- zebra-chain/src/parameters/network_upgrade.rs | 2 +- zebra-chain/src/primitives/zcash_note_encryption.rs | 8 +++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/zebra-chain/src/parameters/network_upgrade.rs b/zebra-chain/src/parameters/network_upgrade.rs index 1cd2be65c38..3c6a0544f32 100644 --- a/zebra-chain/src/parameters/network_upgrade.rs +++ b/zebra-chain/src/parameters/network_upgrade.rs @@ -30,7 +30,7 @@ pub const NETWORK_UPGRADES_IN_ORDER: [NetworkUpgrade; 8] = [ /// /// Network upgrades can change the Zcash network protocol or consensus rules in /// incompatible ways. -#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)] +#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize, Ord, PartialOrd)] #[cfg_attr(any(test, feature = "proptest-impl"), derive(Arbitrary))] pub enum NetworkUpgrade { /// The Zcash protocol for a Genesis block. diff --git a/zebra-chain/src/primitives/zcash_note_encryption.rs b/zebra-chain/src/primitives/zcash_note_encryption.rs index 457a5c04b94..06a43a70f21 100644 --- a/zebra-chain/src/primitives/zcash_note_encryption.rs +++ b/zebra-chain/src/primitives/zcash_note_encryption.rs @@ -22,12 +22,18 @@ pub fn decrypts_successfully(transaction: &Transaction, network: &Network, heigh let null_sapling_ovk = sapling::keys::OutgoingViewingKey([0u8; 32]); + let zip_212_enforcement = if network_upgrade >= NetworkUpgrade::Canopy { + sapling::note_encryption::Zip212Enforcement::On + } else { + sapling::note_encryption::Zip212Enforcement::Off + }; + if let Some(bundle) = alt_tx.sapling_bundle() { for output in bundle.shielded_outputs().iter() { let recovery = sapling::note_encryption::try_sapling_output_recovery( &null_sapling_ovk, output, - sapling::note_encryption::Zip212Enforcement::GracePeriod, + zip_212_enforcement, ); if recovery.is_none() { return false;