Merge pull request #1007 from zcash/sapling-trymapauth-etc
Changes to Sapling bundle mapping
This commit is contained in:
commit
a47b512f59
|
@ -12,9 +12,20 @@ and this library adheres to Rust's notion of
|
||||||
- `circuit` module (moved from `zcash_proofs::circuit::sapling`).
|
- `circuit` module (moved from `zcash_proofs::circuit::sapling`).
|
||||||
- `constants` module.
|
- `constants` module.
|
||||||
- `prover::{SpendProver, OutputProver}`
|
- `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:
|
- Test helpers, behind the `test-dependencies` feature flag:
|
||||||
- `zcash_primitives::prover::mock::{MockSpendProver, MockOutputProver}`
|
- `zcash_primitives::prover::mock::{MockSpendProver, MockOutputProver}`
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- `zcash_primitives::transaction::components::sapling`:
|
||||||
|
- `MapAuth` trait methods now take `&mut self` instead of `&self`.
|
||||||
|
|
||||||
### Removed
|
### Removed
|
||||||
- `zcash_primitives::constants`:
|
- `zcash_primitives::constants`:
|
||||||
- All `const` values (moved to `zcash_primitives::sapling::constants`).
|
- All `const` values (moved to `zcash_primitives::sapling::constants`).
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
//! The Sapling circuits.
|
//! The Sapling circuits.
|
||||||
|
|
||||||
|
use core::fmt;
|
||||||
|
|
||||||
use group::{ff::PrimeField, Curve};
|
use group::{ff::PrimeField, Curve};
|
||||||
|
|
||||||
use bellman::{Circuit, ConstraintSystem, SynthesisError};
|
use bellman::{Circuit, ConstraintSystem, SynthesisError};
|
||||||
|
@ -46,6 +48,7 @@ impl ValueCommitmentOpening {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This is an instance of the `Spend` circuit.
|
/// This is an instance of the `Spend` circuit.
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct Spend {
|
pub struct Spend {
|
||||||
/// The opening of a Pedersen commitment to the value being spent.
|
/// The opening of a Pedersen commitment to the value being spent.
|
||||||
pub value_commitment_opening: Option<ValueCommitmentOpening>,
|
pub value_commitment_opening: Option<ValueCommitmentOpening>,
|
||||||
|
@ -71,7 +74,16 @@ pub struct Spend {
|
||||||
pub anchor: Option<bls12_381::Scalar>,
|
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.
|
/// This is an output circuit instance.
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct Output {
|
pub struct Output {
|
||||||
/// The opening of a Pedersen commitment to the value being spent.
|
/// The opening of a Pedersen commitment to the value being spent.
|
||||||
pub value_commitment_opening: Option<ValueCommitmentOpening>,
|
pub value_commitment_opening: Option<ValueCommitmentOpening>,
|
||||||
|
@ -86,6 +98,12 @@ pub struct Output {
|
||||||
pub esk: Option<jubjub::Fr>,
|
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
|
/// Exposes a Pedersen commitment to the value as an
|
||||||
/// input to the circuit
|
/// input to the circuit
|
||||||
fn expose_value_commitment<CS>(
|
fn expose_value_commitment<CS>(
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
//!
|
//!
|
||||||
//! [section 4.2.2]: https://zips.z.cash/protocol/protocol.pdf#saplingkeycomponents
|
//! [section 4.2.2]: https://zips.z.cash/protocol/protocol.pdf#saplingkeycomponents
|
||||||
|
|
||||||
|
use std::fmt;
|
||||||
use std::io::{self, Read, Write};
|
use std::io::{self, Read, Write};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
|
@ -46,6 +47,13 @@ pub struct ExpandedSpendingKey {
|
||||||
pub ovk: OutgoingViewingKey,
|
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 {
|
impl ExpandedSpendingKey {
|
||||||
pub fn from_spending_key(sk: &[u8]) -> Self {
|
pub fn from_spending_key(sk: &[u8]) -> Self {
|
||||||
let ask = jubjub::Fr::from_bytes_wide(prf_expand(sk, &[0x00]).as_array());
|
let ask = jubjub::Fr::from_bytes_wide(prf_expand(sk, &[0x00]).as_array());
|
||||||
|
@ -119,6 +127,14 @@ pub struct ProofGenerationKey {
|
||||||
pub nsk: jubjub::Fr,
|
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 {
|
impl ProofGenerationKey {
|
||||||
pub fn to_viewing_key(&self) -> ViewingKey {
|
pub fn to_viewing_key(&self) -> ViewingKey {
|
||||||
ViewingKey {
|
ViewingKey {
|
||||||
|
@ -473,16 +489,9 @@ impl SharedSecret {
|
||||||
pub mod testing {
|
pub mod testing {
|
||||||
use proptest::collection::vec;
|
use proptest::collection::vec;
|
||||||
use proptest::prelude::*;
|
use proptest::prelude::*;
|
||||||
use std::fmt::{self, Debug, Formatter};
|
|
||||||
|
|
||||||
use super::{ExpandedSpendingKey, FullViewingKey, SaplingIvk};
|
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! {
|
prop_compose! {
|
||||||
pub fn arb_expanded_spending_key()(v in vec(any::<u8>(), 32..252)) -> ExpandedSpendingKey {
|
pub fn arb_expanded_spending_key()(v in vec(any::<u8>(), 32..252)) -> ExpandedSpendingKey {
|
||||||
ExpandedSpendingKey::from_spending_key(&v)
|
ExpandedSpendingKey::from_spending_key(&v)
|
||||||
|
|
|
@ -56,11 +56,14 @@ impl Authorization for Authorized {
|
||||||
type AuthSig = redjubjub::Signature;
|
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> {
|
pub trait MapAuth<A: Authorization, B: Authorization> {
|
||||||
fn map_spend_proof(&self, p: A::SpendProof) -> B::SpendProof;
|
fn map_spend_proof(&mut self, p: A::SpendProof) -> B::SpendProof;
|
||||||
fn map_output_proof(&self, p: A::OutputProof) -> B::OutputProof;
|
fn map_output_proof(&mut self, p: A::OutputProof) -> B::OutputProof;
|
||||||
fn map_auth_sig(&self, s: A::AuthSig) -> B::AuthSig;
|
fn map_auth_sig(&mut self, s: A::AuthSig) -> B::AuthSig;
|
||||||
fn map_authorization(&self, a: A) -> B;
|
fn map_authorization(&mut self, a: A) -> B;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The identity map.
|
/// The identity map.
|
||||||
|
@ -71,31 +74,98 @@ pub trait MapAuth<A: Authorization, B: Authorization> {
|
||||||
/// [`TransactionData::map_authorization`]: crate::transaction::TransactionData::map_authorization
|
/// [`TransactionData::map_authorization`]: crate::transaction::TransactionData::map_authorization
|
||||||
impl MapAuth<Authorized, Authorized> for () {
|
impl MapAuth<Authorized, Authorized> for () {
|
||||||
fn map_spend_proof(
|
fn map_spend_proof(
|
||||||
&self,
|
&mut self,
|
||||||
p: <Authorized as Authorization>::SpendProof,
|
p: <Authorized as Authorization>::SpendProof,
|
||||||
) -> <Authorized as Authorization>::SpendProof {
|
) -> <Authorized as Authorization>::SpendProof {
|
||||||
p
|
p
|
||||||
}
|
}
|
||||||
|
|
||||||
fn map_output_proof(
|
fn map_output_proof(
|
||||||
&self,
|
&mut self,
|
||||||
p: <Authorized as Authorization>::OutputProof,
|
p: <Authorized as Authorization>::OutputProof,
|
||||||
) -> <Authorized as Authorization>::OutputProof {
|
) -> <Authorized as Authorization>::OutputProof {
|
||||||
p
|
p
|
||||||
}
|
}
|
||||||
|
|
||||||
fn map_auth_sig(
|
fn map_auth_sig(
|
||||||
&self,
|
&mut self,
|
||||||
s: <Authorized as Authorization>::AuthSig,
|
s: <Authorized as Authorization>::AuthSig,
|
||||||
) -> <Authorized as Authorization>::AuthSig {
|
) -> <Authorized as Authorization>::AuthSig {
|
||||||
s
|
s
|
||||||
}
|
}
|
||||||
|
|
||||||
fn map_authorization(&self, a: Authorized) -> Authorized {
|
fn map_authorization(&mut self, a: Authorized) -> Authorized {
|
||||||
a
|
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)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Bundle<A: Authorization> {
|
pub struct Bundle<A: Authorization> {
|
||||||
shielded_spends: Vec<SpendDescription<A>>,
|
shielded_spends: Vec<SpendDescription<A>>,
|
||||||
|
@ -160,7 +230,8 @@ impl<A: Authorization> Bundle<A> {
|
||||||
&self.authorization
|
&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 {
|
Bundle {
|
||||||
shielded_spends: self
|
shielded_spends: self
|
||||||
.shielded_spends
|
.shielded_spends
|
||||||
|
@ -190,6 +261,45 @@ impl<A: Authorization> Bundle<A> {
|
||||||
authorization: f.map_authorization(self.authorization),
|
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> {
|
impl DynamicUsage for Bundle<Authorized> {
|
||||||
|
|
Loading…
Reference in New Issue