Split `sapling::Authorization::Proof` type into Spend and Output types

While the Groth16 proofs have identical encodings, they are technically
for different circuits, and we need the ability to differentiate them
during bundle building.
This commit is contained in:
Jack Grigg 2023-01-06 11:11:46 +00:00
parent 79f3f10714
commit 0a26c812e0
5 changed files with 39 additions and 18 deletions

View File

@ -30,6 +30,10 @@ and this library adheres to Rust's notion of
- `zcash_primitives::transaction::components`:
- `sapling::{Bundle, SpendDescription, OutputDescription}` have had their
fields replaced by getter methods.
- The associated type `sapling::Authorization::Proof` has been replaced by
`Authorization::{SpendProof, OutputProof}`.
- `sapling::MapAuth::map_proof` has been replaced by
`MapAuth::{map_spend_proof, map_output_proof}`.
### Removed
- `zcash_primitives::sapling`:

View File

@ -26,8 +26,10 @@ pub type GrothProofBytes = [u8; GROTH_PROOF_SIZE];
pub mod builder;
pub mod fees;
/// Defines the authorization type of a Sapling bundle.
pub trait Authorization: Debug {
type Proof: Clone + Debug;
type SpendProof: Clone + Debug;
type OutputProof: Clone + Debug;
type AuthSig: Clone + Debug;
}
@ -35,22 +37,27 @@ pub trait Authorization: Debug {
pub struct Unproven;
impl Authorization for Unproven {
type Proof = ();
type SpendProof = ();
type OutputProof = ();
type AuthSig = ();
}
/// Authorizing data for a bundle of Sapling spends and outputs, ready to be committed to
/// the ledger.
#[derive(Debug, Copy, Clone)]
pub struct Authorized {
pub binding_sig: redjubjub::Signature,
}
impl Authorization for Authorized {
type Proof = GrothProofBytes;
type SpendProof = GrothProofBytes;
type OutputProof = GrothProofBytes;
type AuthSig = redjubjub::Signature;
}
pub trait MapAuth<A: Authorization, B: Authorization> {
fn map_proof(&self, p: A::Proof) -> B::Proof;
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;
}
@ -62,10 +69,17 @@ pub trait MapAuth<A: Authorization, B: Authorization> {
///
/// [`TransactionData::map_authorization`]: crate::transaction::TransactionData::map_authorization
impl MapAuth<Authorized, Authorized> for () {
fn map_proof(
fn map_spend_proof(
&self,
p: <Authorized as Authorization>::Proof,
) -> <Authorized as Authorization>::Proof {
p: <Authorized as Authorization>::SpendProof,
) -> <Authorized as Authorization>::SpendProof {
p
}
fn map_output_proof(
&self,
p: <Authorized as Authorization>::OutputProof,
) -> <Authorized as Authorization>::OutputProof {
p
}
@ -84,7 +98,7 @@ impl MapAuth<Authorized, Authorized> for () {
#[derive(Debug, Clone)]
pub struct Bundle<A: Authorization> {
shielded_spends: Vec<SpendDescription<A>>,
shielded_outputs: Vec<OutputDescription<A::Proof>>,
shielded_outputs: Vec<OutputDescription<A::OutputProof>>,
value_balance: Amount,
authorization: A,
}
@ -93,7 +107,7 @@ impl<A: Authorization> Bundle<A> {
/// Constructs a `Bundle` from its constituent parts.
pub(crate) fn from_parts(
shielded_spends: Vec<SpendDescription<A>>,
shielded_outputs: Vec<OutputDescription<A::Proof>>,
shielded_outputs: Vec<OutputDescription<A::OutputProof>>,
value_balance: Amount,
authorization: A,
) -> Self {
@ -111,7 +125,7 @@ impl<A: Authorization> Bundle<A> {
}
/// Returns the list of outputs in this bundle.
pub fn shielded_outputs(&self) -> &[OutputDescription<A::Proof>] {
pub fn shielded_outputs(&self) -> &[OutputDescription<A::OutputProof>] {
&self.shielded_outputs
}
@ -139,7 +153,7 @@ impl<A: Authorization> Bundle<A> {
anchor: d.anchor,
nullifier: d.nullifier,
rk: d.rk,
zkproof: f.map_proof(d.zkproof),
zkproof: f.map_spend_proof(d.zkproof),
spend_auth_sig: f.map_auth_sig(d.spend_auth_sig),
})
.collect(),
@ -152,7 +166,7 @@ impl<A: Authorization> Bundle<A> {
ephemeral_key: o.ephemeral_key,
enc_ciphertext: o.enc_ciphertext,
out_ciphertext: o.out_ciphertext,
zkproof: f.map_proof(o.zkproof),
zkproof: f.map_output_proof(o.zkproof),
})
.collect(),
value_balance: self.value_balance,
@ -167,7 +181,7 @@ pub struct SpendDescription<A: Authorization> {
anchor: bls12_381::Scalar,
nullifier: Nullifier,
rk: PublicKey,
zkproof: A::Proof,
zkproof: A::SpendProof,
spend_auth_sig: A::AuthSig,
}
@ -203,7 +217,7 @@ impl<A: Authorization> SpendDescription<A> {
}
/// Returns the proof for this spend.
pub fn zkproof(&self) -> &A::Proof {
pub fn zkproof(&self) -> &A::SpendProof {
&self.zkproof
}

View File

@ -227,7 +227,8 @@ impl std::fmt::Debug for Unauthorized {
}
impl Authorization for Unauthorized {
type Proof = GrothProofBytes;
type SpendProof = GrothProofBytes;
type OutputProof = GrothProofBytes;
type AuthSig = SpendDescriptionInfo;
}

View File

@ -78,7 +78,7 @@ pub trait TransparentAuthorizingContext: transparent::Authorization {
pub fn signature_hash<
'a,
TA: TransparentAuthorizingContext,
SA: sapling::Authorization<Proof = GrothProofBytes>,
SA: sapling::Authorization<SpendProof = GrothProofBytes, OutputProof = GrothProofBytes>,
A: Authorization<SaplingAuth = SA, TransparentAuth = TA>,
>(
tx: &TransactionData<A>,

View File

@ -104,7 +104,9 @@ fn joinsplits_hash(
.hash(&data)
}
fn shielded_spends_hash<A: sapling::Authorization<Proof = GrothProofBytes>>(
fn shielded_spends_hash<
A: sapling::Authorization<SpendProof = GrothProofBytes, OutputProof = GrothProofBytes>,
>(
shielded_spends: &[SpendDescription<A>],
) -> Blake2bHash {
let mut data = Vec::with_capacity(shielded_spends.len() * 384);
@ -133,7 +135,7 @@ fn shielded_outputs_hash(shielded_outputs: &[OutputDescription<GrothProofBytes>]
}
pub fn v4_signature_hash<
SA: sapling::Authorization<Proof = GrothProofBytes>,
SA: sapling::Authorization<SpendProof = GrothProofBytes, OutputProof = GrothProofBytes>,
A: Authorization<SaplingAuth = SA>,
>(
tx: &TransactionData<A>,