From 241a1a36607a3b1eb7b8129425d7745ba98cf336 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Fri, 6 Oct 2023 20:45:19 +0000 Subject: [PATCH 1/4] zcash_primitives: Add some more `Clone` and `Debug` impls --- zcash_primitives/CHANGELOG.md | 1 + zcash_primitives/src/sapling/circuit.rs | 18 ++++++++++++++++++ zcash_primitives/src/sapling/keys.rs | 23 ++++++++++++++++------- 3 files changed, 35 insertions(+), 7 deletions(-) diff --git a/zcash_primitives/CHANGELOG.md b/zcash_primitives/CHANGELOG.md index 0cc06dc31..f8a26f20e 100644 --- a/zcash_primitives/CHANGELOG.md +++ b/zcash_primitives/CHANGELOG.md @@ -12,6 +12,7 @@ and this library adheres to Rust's notion of - `circuit` module (moved from `zcash_proofs::circuit::sapling`). - `constants` module. - `prover::{SpendProver, OutputProver}` + - `impl Debug for keys::{ExpandedSpendingKey, ProofGenerationKey}` - Test helpers, behind the `test-dependencies` feature flag: - `zcash_primitives::prover::mock::{MockSpendProver, MockOutputProver}` diff --git a/zcash_primitives/src/sapling/circuit.rs b/zcash_primitives/src/sapling/circuit.rs index 78ef9b847..036941f22 100644 --- a/zcash_primitives/src/sapling/circuit.rs +++ b/zcash_primitives/src/sapling/circuit.rs @@ -1,5 +1,7 @@ //! The Sapling circuits. +use core::fmt; + use group::{ff::PrimeField, Curve}; use bellman::{Circuit, ConstraintSystem, SynthesisError}; @@ -46,6 +48,7 @@ impl ValueCommitmentOpening { } /// This is an instance of the `Spend` circuit. +#[derive(Clone)] pub struct Spend { /// The opening of a Pedersen commitment to the value being spent. pub value_commitment_opening: Option, @@ -71,7 +74,16 @@ pub struct Spend { pub anchor: Option, } +impl fmt::Debug for Spend { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Spend") + .field("anchor", &self.anchor) + .finish_non_exhaustive() + } +} + /// This is an output circuit instance. +#[derive(Clone)] pub struct Output { /// The opening of a Pedersen commitment to the value being spent. pub value_commitment_opening: Option, @@ -86,6 +98,12 @@ pub struct Output { pub esk: Option, } +impl fmt::Debug for Output { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Output").finish_non_exhaustive() + } +} + /// Exposes a Pedersen commitment to the value as an /// input to the circuit fn expose_value_commitment( diff --git a/zcash_primitives/src/sapling/keys.rs b/zcash_primitives/src/sapling/keys.rs index 3fd458f49..aa26edd6a 100644 --- a/zcash_primitives/src/sapling/keys.rs +++ b/zcash_primitives/src/sapling/keys.rs @@ -4,6 +4,7 @@ //! //! [section 4.2.2]: https://zips.z.cash/protocol/protocol.pdf#saplingkeycomponents +use std::fmt; use std::io::{self, Read, Write}; use super::{ @@ -46,6 +47,13 @@ pub struct ExpandedSpendingKey { pub ovk: OutgoingViewingKey, } +impl fmt::Debug for ExpandedSpendingKey { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("ExpandedSpendingKey") + .finish_non_exhaustive() + } +} + impl ExpandedSpendingKey { pub fn from_spending_key(sk: &[u8]) -> Self { let ask = jubjub::Fr::from_bytes_wide(prf_expand(sk, &[0x00]).as_array()); @@ -119,6 +127,14 @@ pub struct ProofGenerationKey { pub nsk: jubjub::Fr, } +impl fmt::Debug for ProofGenerationKey { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("ProofGenerationKey") + .field("ak", &self.ak) + .finish_non_exhaustive() + } +} + impl ProofGenerationKey { pub fn to_viewing_key(&self) -> ViewingKey { ViewingKey { @@ -473,16 +489,9 @@ impl SharedSecret { pub mod testing { use proptest::collection::vec; use proptest::prelude::*; - use std::fmt::{self, Debug, Formatter}; use super::{ExpandedSpendingKey, FullViewingKey, SaplingIvk}; - impl Debug for ExpandedSpendingKey { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - write!(f, "Spending keys cannot be Debug-formatted.") - } - } - prop_compose! { pub fn arb_expanded_spending_key()(v in vec(any::(), 32..252)) -> ExpandedSpendingKey { ExpandedSpendingKey::from_spending_key(&v) From b09b435135cff7f10c1a9d64b8577fc32c8dd255 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Fri, 6 Oct 2023 23:12:47 +0000 Subject: [PATCH 2/4] zcash_primitives: Change `sapling::MapAuth` to take `&mut self` --- zcash_primitives/CHANGELOG.md | 4 ++++ .../src/transaction/components/sapling.rs | 22 +++++++++++-------- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/zcash_primitives/CHANGELOG.md b/zcash_primitives/CHANGELOG.md index f8a26f20e..a4367d97e 100644 --- a/zcash_primitives/CHANGELOG.md +++ b/zcash_primitives/CHANGELOG.md @@ -16,6 +16,10 @@ and this library adheres to Rust's notion of - Test helpers, behind the `test-dependencies` feature flag: - `zcash_primitives::prover::mock::{MockSpendProver, MockOutputProver}` +### Changed +- `zcash_primitives::transaction::components::sapling`: + - `MapAuth` trait methods now take `&mut self` instead of `&self`. + ### Removed - `zcash_primitives::constants`: - All `const` values (moved to `zcash_primitives::sapling::constants`). diff --git a/zcash_primitives/src/transaction/components/sapling.rs b/zcash_primitives/src/transaction/components/sapling.rs index f899155e8..fc275f1ed 100644 --- a/zcash_primitives/src/transaction/components/sapling.rs +++ b/zcash_primitives/src/transaction/components/sapling.rs @@ -56,11 +56,14 @@ impl Authorization for Authorized { type AuthSig = redjubjub::Signature; } +/// A map from one bundle authorization to another. +/// +/// For use with [`Bundle::map_authorization`]. pub trait MapAuth { - fn map_spend_proof(&self, p: A::SpendProof) -> B::SpendProof; - fn map_output_proof(&self, p: A::OutputProof) -> B::OutputProof; - fn map_auth_sig(&self, s: A::AuthSig) -> B::AuthSig; - fn map_authorization(&self, a: A) -> B; + fn map_spend_proof(&mut self, p: A::SpendProof) -> B::SpendProof; + fn map_output_proof(&mut self, p: A::OutputProof) -> B::OutputProof; + fn map_auth_sig(&mut self, s: A::AuthSig) -> B::AuthSig; + fn map_authorization(&mut self, a: A) -> B; } /// The identity map. @@ -71,27 +74,27 @@ pub trait MapAuth { /// [`TransactionData::map_authorization`]: crate::transaction::TransactionData::map_authorization impl MapAuth for () { fn map_spend_proof( - &self, + &mut self, p: ::SpendProof, ) -> ::SpendProof { p } fn map_output_proof( - &self, + &mut self, p: ::OutputProof, ) -> ::OutputProof { p } fn map_auth_sig( - &self, + &mut self, s: ::AuthSig, ) -> ::AuthSig { s } - fn map_authorization(&self, a: Authorized) -> Authorized { + fn map_authorization(&mut self, a: Authorized) -> Authorized { a } } @@ -160,7 +163,8 @@ impl Bundle { &self.authorization } - pub fn map_authorization>(self, f: F) -> Bundle { + /// Transitions this bundle from one authorization state to another. + pub fn map_authorization>(self, mut f: F) -> Bundle { Bundle { shielded_spends: self .shielded_spends From 65efee1a16e169b34b411e039782196d835c9e30 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Fri, 6 Oct 2023 23:16:59 +0000 Subject: [PATCH 3/4] zcash_primitives: Add `sapling::Bundle::try_map_authorization` --- zcash_primitives/CHANGELOG.md | 3 ++ .../src/transaction/components/sapling.rs | 50 +++++++++++++++++++ 2 files changed, 53 insertions(+) diff --git a/zcash_primitives/CHANGELOG.md b/zcash_primitives/CHANGELOG.md index a4367d97e..33895ad82 100644 --- a/zcash_primitives/CHANGELOG.md +++ b/zcash_primitives/CHANGELOG.md @@ -13,6 +13,9 @@ and this library adheres to Rust's notion of - `constants` module. - `prover::{SpendProver, OutputProver}` - `impl Debug for keys::{ExpandedSpendingKey, ProofGenerationKey}` +- `zcash_primitives::transaction::components::sapling`: + - `Bundle::try_map_authorization` + - `TryMapAuth` - Test helpers, behind the `test-dependencies` feature flag: - `zcash_primitives::prover::mock::{MockSpendProver, MockOutputProver}` diff --git a/zcash_primitives/src/transaction/components/sapling.rs b/zcash_primitives/src/transaction/components/sapling.rs index fc275f1ed..bfd4d2492 100644 --- a/zcash_primitives/src/transaction/components/sapling.rs +++ b/zcash_primitives/src/transaction/components/sapling.rs @@ -99,6 +99,17 @@ impl MapAuth for () { } } +/// A fallible map from one bundle authorization to another. +/// +/// For use with [`Bundle::try_map_authorization`]. +pub trait TryMapAuth { + type Error; + fn try_map_spend_proof(&mut self, p: A::SpendProof) -> Result; + fn try_map_output_proof(&mut self, p: A::OutputProof) -> Result; + fn try_map_auth_sig(&mut self, s: A::AuthSig) -> Result; + fn try_map_authorization(&mut self, a: A) -> Result; +} + #[derive(Debug, Clone)] pub struct Bundle { shielded_spends: Vec>, @@ -194,6 +205,45 @@ impl Bundle { authorization: f.map_authorization(self.authorization), } } + + /// Transitions this bundle from one authorization state to another. + pub fn try_map_authorization>( + self, + mut f: F, + ) -> Result, F::Error> { + Ok(Bundle { + shielded_spends: self + .shielded_spends + .into_iter() + .map(|d| { + Ok(SpendDescription { + cv: d.cv, + anchor: d.anchor, + nullifier: d.nullifier, + rk: d.rk, + zkproof: f.try_map_spend_proof(d.zkproof)?, + spend_auth_sig: f.try_map_auth_sig(d.spend_auth_sig)?, + }) + }) + .collect::>()?, + shielded_outputs: self + .shielded_outputs + .into_iter() + .map(|o| { + Ok(OutputDescription { + cv: o.cv, + cmu: o.cmu, + ephemeral_key: o.ephemeral_key, + enc_ciphertext: o.enc_ciphertext, + out_ciphertext: o.out_ciphertext, + zkproof: f.try_map_output_proof(o.zkproof)?, + }) + }) + .collect::>()?, + value_balance: self.value_balance, + authorization: f.try_map_authorization(self.authorization)?, + }) + } } impl DynamicUsage for Bundle { From e1a4238a71474bb3bb23b081e3443f670d7550f0 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Fri, 6 Oct 2023 23:40:32 +0000 Subject: [PATCH 4/4] zcash_primitives: Add helper impls of `{Try}MapAuth` for closures --- zcash_primitives/CHANGELOG.md | 3 + .../src/transaction/components/sapling.rs | 56 +++++++++++++++++++ 2 files changed, 59 insertions(+) diff --git a/zcash_primitives/CHANGELOG.md b/zcash_primitives/CHANGELOG.md index 33895ad82..20bb1e4d2 100644 --- a/zcash_primitives/CHANGELOG.md +++ b/zcash_primitives/CHANGELOG.md @@ -16,6 +16,9 @@ and this library adheres to Rust's notion of - `zcash_primitives::transaction::components::sapling`: - `Bundle::try_map_authorization` - `TryMapAuth` + - `impl {MapAuth, TryMapAuth} for (FnMut, FnMut, FnMut, FnMut)` helpers to + enable calling `Bundle::{map_authorization, try_map_authorization}` with a + set of closures. - Test helpers, behind the `test-dependencies` feature flag: - `zcash_primitives::prover::mock::{MockSpendProver, MockOutputProver}` diff --git a/zcash_primitives/src/transaction/components/sapling.rs b/zcash_primitives/src/transaction/components/sapling.rs index bfd4d2492..1c17eaf36 100644 --- a/zcash_primitives/src/transaction/components/sapling.rs +++ b/zcash_primitives/src/transaction/components/sapling.rs @@ -99,6 +99,33 @@ impl MapAuth for () { } } +/// A helper for implementing `MapAuth` with a set of closures. +impl MapAuth for (F, G, H, I) +where + A: Authorization, + B: Authorization, + F: FnMut(A::SpendProof) -> B::SpendProof, + G: FnMut(A::OutputProof) -> B::OutputProof, + H: FnMut(A::AuthSig) -> B::AuthSig, + I: FnMut(A) -> B, +{ + fn map_spend_proof(&mut self, p: A::SpendProof) -> B::SpendProof { + self.0(p) + } + + fn map_output_proof(&mut self, p: A::OutputProof) -> B::OutputProof { + self.1(p) + } + + fn map_auth_sig(&mut self, s: A::AuthSig) -> B::AuthSig { + self.2(s) + } + + fn map_authorization(&mut self, a: A) -> B { + self.3(a) + } +} + /// A fallible map from one bundle authorization to another. /// /// For use with [`Bundle::try_map_authorization`]. @@ -110,6 +137,35 @@ pub trait TryMapAuth { fn try_map_authorization(&mut self, a: A) -> Result; } +/// A helper for implementing `TryMapAuth` with a set of closures. +impl TryMapAuth for (F, G, H, I) +where + A: Authorization, + B: Authorization, + F: FnMut(A::SpendProof) -> Result, + G: FnMut(A::OutputProof) -> Result, + H: FnMut(A::AuthSig) -> Result, + I: FnMut(A) -> Result, +{ + type Error = E; + + fn try_map_spend_proof(&mut self, p: A::SpendProof) -> Result { + self.0(p) + } + + fn try_map_output_proof(&mut self, p: A::OutputProof) -> Result { + self.1(p) + } + + fn try_map_auth_sig(&mut self, s: A::AuthSig) -> Result { + self.2(s) + } + + fn try_map_authorization(&mut self, a: A) -> Result { + self.3(a) + } +} + #[derive(Debug, Clone)] pub struct Bundle { shielded_spends: Vec>,