Skip to content

Commit

Permalink
Merge pull request #1007 from zcash/sapling-trymapauth-etc
Browse files Browse the repository at this point in the history
Changes to Sapling bundle mapping
  • Loading branch information
nuttycom authored Oct 7, 2023
2 parents 4737839 + e1a4238 commit a47b512
Show file tree
Hide file tree
Showing 4 changed files with 164 additions and 16 deletions.
11 changes: 11 additions & 0 deletions zcash_primitives/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,20 @@ 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}`
- `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}`

### 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`).
Expand Down
18 changes: 18 additions & 0 deletions zcash_primitives/src/sapling/circuit.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
//! The Sapling circuits.

use core::fmt;

use group::{ff::PrimeField, Curve};

use bellman::{Circuit, ConstraintSystem, SynthesisError};
Expand Down Expand Up @@ -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<ValueCommitmentOpening>,
Expand All @@ -71,7 +74,16 @@ pub struct Spend {
pub anchor: Option<bls12_381::Scalar>,
}

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<ValueCommitmentOpening>,
Expand All @@ -86,6 +98,12 @@ pub struct Output {
pub esk: Option<jubjub::Fr>,
}

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<CS>(
Expand Down
23 changes: 16 additions & 7 deletions zcash_primitives/src/sapling/keys.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::{
Expand Down Expand Up @@ -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());
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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::<u8>(), 32..252)) -> ExpandedSpendingKey {
ExpandedSpendingKey::from_spending_key(&v)
Expand Down
128 changes: 119 additions & 9 deletions zcash_primitives/src/transaction/components/sapling.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<A: Authorization, B: Authorization> {
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.
Expand All @@ -71,31 +74,98 @@ pub trait MapAuth<A: Authorization, B: Authorization> {
/// [`TransactionData::map_authorization`]: crate::transaction::TransactionData::map_authorization
impl MapAuth<Authorized, Authorized> for () {
fn map_spend_proof(
&self,
&mut self,
p: <Authorized as Authorization>::SpendProof,
) -> <Authorized as Authorization>::SpendProof {
p
}

fn map_output_proof(
&self,
&mut self,
p: <Authorized as Authorization>::OutputProof,
) -> <Authorized as Authorization>::OutputProof {
p
}

fn map_auth_sig(
&self,
&mut self,
s: <Authorized as Authorization>::AuthSig,
) -> <Authorized as Authorization>::AuthSig {
s
}

fn map_authorization(&self, a: Authorized) -> Authorized {
fn map_authorization(&mut self, a: Authorized) -> Authorized {
a
}
}

/// A helper for implementing `MapAuth` with a set of closures.
impl<A, B, F, G, H, I> MapAuth<A, B> 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`].
pub trait TryMapAuth<A: Authorization, B: Authorization> {
type Error;
fn try_map_spend_proof(&mut self, p: A::SpendProof) -> Result<B::SpendProof, Self::Error>;
fn try_map_output_proof(&mut self, p: A::OutputProof) -> Result<B::OutputProof, Self::Error>;
fn try_map_auth_sig(&mut self, s: A::AuthSig) -> Result<B::AuthSig, Self::Error>;
fn try_map_authorization(&mut self, a: A) -> Result<B, Self::Error>;
}

/// A helper for implementing `TryMapAuth` with a set of closures.
impl<A, B, E, F, G, H, I> TryMapAuth<A, B> for (F, G, H, I)
where
A: Authorization,
B: Authorization,
F: FnMut(A::SpendProof) -> Result<B::SpendProof, E>,
G: FnMut(A::OutputProof) -> Result<B::OutputProof, E>,
H: FnMut(A::AuthSig) -> Result<B::AuthSig, E>,
I: FnMut(A) -> Result<B, E>,
{
type Error = E;

fn try_map_spend_proof(&mut self, p: A::SpendProof) -> Result<B::SpendProof, Self::Error> {
self.0(p)
}

fn try_map_output_proof(&mut self, p: A::OutputProof) -> Result<B::OutputProof, Self::Error> {
self.1(p)
}

fn try_map_auth_sig(&mut self, s: A::AuthSig) -> Result<B::AuthSig, Self::Error> {
self.2(s)
}

fn try_map_authorization(&mut self, a: A) -> Result<B, Self::Error> {
self.3(a)
}
}

#[derive(Debug, Clone)]
pub struct Bundle<A: Authorization> {
shielded_spends: Vec<SpendDescription<A>>,
Expand Down Expand Up @@ -160,7 +230,8 @@ impl<A: Authorization> Bundle<A> {
&self.authorization
}

pub fn map_authorization<B: Authorization, F: MapAuth<A, B>>(self, f: F) -> Bundle<B> {
/// Transitions this bundle from one authorization state to another.
pub fn map_authorization<B: Authorization, F: MapAuth<A, B>>(self, mut f: F) -> Bundle<B> {
Bundle {
shielded_spends: self
.shielded_spends
Expand Down Expand Up @@ -190,6 +261,45 @@ impl<A: Authorization> Bundle<A> {
authorization: f.map_authorization(self.authorization),
}
}

/// Transitions this bundle from one authorization state to another.
pub fn try_map_authorization<B: Authorization, F: TryMapAuth<A, B>>(
self,
mut f: F,
) -> Result<Bundle<B>, 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::<Result<_, _>>()?,
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::<Result<_, _>>()?,
value_balance: self.value_balance,
authorization: f.try_map_authorization(self.authorization)?,
})
}
}

impl DynamicUsage for Bundle<Authorized> {
Expand Down

0 comments on commit a47b512

Please sign in to comment.