From b20641ae58bcbfa54ac62872eadca058ec14f27b Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Thu, 2 Nov 2023 02:00:21 +0000 Subject: [PATCH 1/2] zcash_primitives: Remove `sapling::prover::TxProver` Removed ------- - `zcash_primitives::sapling`: - `prover::TxProver` (use `SpendProver` and `OutputProver` instead). - `prover::mock::MockTxProver` (use `MockSpendProver` and `MockOutputProver` instead). --- zcash_client_backend/src/data_api/wallet.rs | 25 +++- zcash_primitives/CHANGELOG.md | 2 +- zcash_primitives/src/sapling/prover.rs | 122 +------------------- zcash_proofs/src/prover.rs | 77 +----------- 4 files changed, 29 insertions(+), 197 deletions(-) diff --git a/zcash_client_backend/src/data_api/wallet.rs b/zcash_client_backend/src/data_api/wallet.rs index a8c5151ca..79d2509ad 100644 --- a/zcash_client_backend/src/data_api/wallet.rs +++ b/zcash_client_backend/src/data_api/wallet.rs @@ -105,7 +105,10 @@ where /// Parameters: /// * `wallet_db`: A read/write reference to the wallet database /// * `params`: Consensus parameters -/// * `prover`: The [`sapling::TxProver`] to use in constructing the shielded transaction. +/// * `spend_prover`: The [`sapling::SpendProver`] to use in constructing the shielded +/// transaction. +/// * `output_prover`: The [`sapling::OutputProver`] to use in constructing the shielded +/// transaction. /// * `usk`: The unified spending key that controls the funds that will be spent /// in the resulting transaction. This procedure will return an error if the /// USK does not correspond to an account known to the wallet. @@ -182,7 +185,9 @@ where /// # } /// # } /// ``` -/// [`sapling::TxProver`]: zcash_primitives::sapling::prover::TxProver +/// +/// [`sapling::SpendProver`]: zcash_primitives::sapling::prover::SpendProver +/// [`sapling::OutputProver`]: zcash_primitives::sapling::prover::OutputProver #[allow(clippy::too_many_arguments)] #[allow(clippy::type_complexity)] #[deprecated( @@ -276,7 +281,10 @@ where /// Parameters: /// * `wallet_db`: A read/write reference to the wallet database /// * `params`: Consensus parameters -/// * `prover`: The [`sapling::TxProver`] to use in constructing the shielded transaction. +/// * `spend_prover`: The [`sapling::SpendProver`] to use in constructing the shielded +/// transaction. +/// * `output_prover`: The [`sapling::OutputProver`] to use in constructing the shielded +/// transaction. /// * `input_selector`: The [`InputSelector`] that will be used to select available /// inputs from the wallet database, choose change amounts and compute required /// transaction fees. @@ -292,7 +300,8 @@ where /// spent. A value of 10 confirmations is recommended and 0-conf transactions are /// not supported. /// -/// [`sapling::TxProver`]: zcash_primitives::sapling::prover::TxProver +/// [`sapling::SpendProver`]: zcash_primitives::sapling::prover::SpendProver +/// [`sapling::OutputProver`]: zcash_primitives::sapling::prover::OutputProver #[allow(clippy::too_many_arguments)] #[allow(clippy::type_complexity)] pub fn spend( @@ -764,7 +773,10 @@ where /// Parameters: /// * `wallet_db`: A read/write reference to the wallet database /// * `params`: Consensus parameters -/// * `prover`: The [`sapling::TxProver`] to use in constructing the shielded transaction. +/// * `spend_prover`: The [`sapling::SpendProver`] to use in constructing the shielded +/// transaction. +/// * `output_prover`: The [`sapling::OutputProver`] to use in constructing the shielded +/// transaction. /// * `input_selector`: The [`InputSelector`] to for note selection and change and fee /// determination /// * `usk`: The unified spending key that will be used to detect and spend transparent UTXOs, @@ -781,7 +793,8 @@ where /// spent. A value of 10 confirmations is recommended and 0-conf transactions are /// not supported. /// -/// [`sapling::TxProver`]: zcash_primitives::sapling::prover::TxProver +/// [`sapling::SpendProver`]: zcash_primitives::sapling::prover::SpendProver +/// [`sapling::OutputProver`]: zcash_primitives::sapling::prover::OutputProver #[cfg(feature = "transparent-inputs")] #[allow(clippy::too_many_arguments)] #[allow(clippy::type_complexity)] diff --git a/zcash_primitives/CHANGELOG.md b/zcash_primitives/CHANGELOG.md index 0b0cb00ab..f0e89b1d8 100644 --- a/zcash_primitives/CHANGELOG.md +++ b/zcash_primitives/CHANGELOG.md @@ -42,7 +42,7 @@ and this library adheres to Rust's notion of - `P2PKH_STANDARD_INPUT_SIZE` - `P2PKH_STANDARD_OUTPUT_SIZE` - Test helpers, behind the `test-dependencies` feature flag: - - `zcash_primitives::prover::mock::{MockSpendProver, MockOutputProver}` + - `zcash_primitives::sapling::prover::mock::{MockSpendProver, MockOutputProver}` - Additions related to `zcash_primitive::components::amount::Amount` and `zcash_primitive::components::amount::NonNegativeAmount`: - `impl TryFrom for u64` diff --git a/zcash_primitives/src/sapling/prover.rs b/zcash_primitives/src/sapling/prover.rs index 07c4b2e55..0933e8c20 100644 --- a/zcash_primitives/src/sapling/prover.rs +++ b/zcash_primitives/src/sapling/prover.rs @@ -5,11 +5,10 @@ use rand_core::RngCore; use crate::{ sapling::{ self, - redjubjub::{PublicKey, Signature}, - value::{NoteValue, ValueCommitTrapdoor, ValueCommitment}, + value::{NoteValue, ValueCommitTrapdoor}, MerklePath, }, - transaction::components::{sapling::GrothProofBytes, Amount, GROTH_PROOF_SIZE}, + transaction::components::sapling::GrothProofBytes, }; use super::{Diversifier, PaymentAddress, ProofGenerationKey, Rseed}; @@ -80,73 +79,19 @@ pub trait OutputProver { fn encode_proof(proof: Self::Proof) -> GrothProofBytes; } -/// Interface for creating zero-knowledge proofs for shielded transactions. -pub trait TxProver { - /// Type for persisting any necessary context across multiple Sapling proofs. - type SaplingProvingContext; - - /// Instantiate a new Sapling proving context. - fn new_sapling_proving_context(&self) -> Self::SaplingProvingContext; - - /// Create the value commitment, re-randomized key, and proof for a Sapling - /// [`SpendDescription`], while accumulating its value commitment randomness inside - /// the context for later use. - /// - /// [`SpendDescription`]: crate::transaction::components::SpendDescription - #[allow(clippy::too_many_arguments)] - fn spend_proof( - &self, - ctx: &mut Self::SaplingProvingContext, - proof_generation_key: ProofGenerationKey, - diversifier: Diversifier, - rseed: Rseed, - ar: jubjub::Fr, - value: u64, - anchor: bls12_381::Scalar, - merkle_path: sapling::MerklePath, - ) -> Result<([u8; GROTH_PROOF_SIZE], ValueCommitment, PublicKey), ()>; - - /// Create the value commitment and proof for a Sapling [`OutputDescription`], - /// while accumulating its value commitment randomness inside the context for later - /// use. - /// - /// [`OutputDescription`]: crate::transaction::components::OutputDescription - fn output_proof( - &self, - ctx: &mut Self::SaplingProvingContext, - esk: jubjub::Fr, - payment_address: PaymentAddress, - rcm: jubjub::Fr, - value: u64, - ) -> ([u8; GROTH_PROOF_SIZE], ValueCommitment); - - /// Create the `bindingSig` for a Sapling transaction. All calls to - /// [`TxProver::spend_proof`] and [`TxProver::output_proof`] must be completed before - /// calling this function. - fn binding_sig( - &self, - ctx: &mut Self::SaplingProvingContext, - value_balance: Amount, - sighash: &[u8; 32], - ) -> Result; -} - #[cfg(any(test, feature = "test-dependencies"))] pub mod mock { use ff::Field; - use rand_core::OsRng; - use super::{OutputProver, SpendProver, TxProver}; + use super::{OutputProver, SpendProver}; use crate::{ sapling::{ self, circuit::ValueCommitmentOpening, - constants::SPENDING_KEY_GENERATOR, - redjubjub::{PublicKey, Signature}, - value::{NoteValue, ValueCommitTrapdoor, ValueCommitment}, + value::{NoteValue, ValueCommitTrapdoor}, Diversifier, PaymentAddress, ProofGenerationKey, Rseed, }, - transaction::components::{sapling::GrothProofBytes, Amount, GROTH_PROOF_SIZE}, + transaction::components::{sapling::GrothProofBytes, GROTH_PROOF_SIZE}, }; pub struct MockSpendProver; @@ -230,61 +175,4 @@ pub mod mock { proof } } - - pub struct MockTxProver; - - impl TxProver for MockTxProver { - type SaplingProvingContext = (); - - fn new_sapling_proving_context(&self) -> Self::SaplingProvingContext {} - - fn spend_proof( - &self, - _ctx: &mut Self::SaplingProvingContext, - proof_generation_key: ProofGenerationKey, - _diversifier: Diversifier, - _rcm: Rseed, - ar: jubjub::Fr, - value: u64, - _anchor: bls12_381::Scalar, - _merkle_path: sapling::MerklePath, - ) -> Result<([u8; GROTH_PROOF_SIZE], ValueCommitment, PublicKey), ()> { - let mut rng = OsRng; - - let value = NoteValue::from_raw(value); - let rcv = ValueCommitTrapdoor::random(&mut rng); - let cv = ValueCommitment::derive(value, rcv); - - let rk = - PublicKey(proof_generation_key.ak.into()).randomize(ar, SPENDING_KEY_GENERATOR); - - Ok(([0u8; GROTH_PROOF_SIZE], cv, rk)) - } - - fn output_proof( - &self, - _ctx: &mut Self::SaplingProvingContext, - _esk: jubjub::Fr, - _payment_address: PaymentAddress, - _rcm: jubjub::Fr, - value: u64, - ) -> ([u8; GROTH_PROOF_SIZE], ValueCommitment) { - let mut rng = OsRng; - - let value = NoteValue::from_raw(value); - let rcv = ValueCommitTrapdoor::random(&mut rng); - let cv = ValueCommitment::derive(value, rcv); - - ([0u8; GROTH_PROOF_SIZE], cv) - } - - fn binding_sig( - &self, - _ctx: &mut Self::SaplingProvingContext, - _value_balance: Amount, - _sighash: &[u8; 32], - ) -> Result { - Err(()) - } - } } diff --git a/zcash_proofs/src/prover.rs b/zcash_proofs/src/prover.rs index 3ddbcfcd4..18fad71cf 100644 --- a/zcash_proofs/src/prover.rs +++ b/zcash_proofs/src/prover.rs @@ -6,18 +6,14 @@ use std::path::Path; use zcash_primitives::{ sapling::{ self, - prover::{OutputProver, SpendProver, TxProver}, - redjubjub::{PublicKey, Signature}, - value::{NoteValue, ValueCommitTrapdoor, ValueCommitment}, + prover::{OutputProver, SpendProver}, + value::{NoteValue, ValueCommitTrapdoor}, Diversifier, MerklePath, PaymentAddress, ProofGenerationKey, Rseed, }, - transaction::components::{sapling::GrothProofBytes, Amount, GROTH_PROOF_SIZE}, + transaction::components::{sapling::GrothProofBytes, GROTH_PROOF_SIZE}, }; -use crate::{ - load_parameters, parse_parameters, sapling::SaplingProvingContext, OutputParameters, - SpendParameters, -}; +use crate::{load_parameters, parse_parameters, OutputParameters, SpendParameters}; #[cfg(feature = "local-prover")] use crate::{default_params_folder, SAPLING_OUTPUT_NAME, SAPLING_SPEND_NAME}; @@ -215,68 +211,3 @@ impl OutputProver for LocalTxProver { zkproof } } - -impl TxProver for LocalTxProver { - type SaplingProvingContext = SaplingProvingContext; - - fn new_sapling_proving_context(&self) -> Self::SaplingProvingContext { - SaplingProvingContext::new() - } - - fn spend_proof( - &self, - ctx: &mut Self::SaplingProvingContext, - proof_generation_key: ProofGenerationKey, - diversifier: Diversifier, - rseed: Rseed, - ar: jubjub::Fr, - value: u64, - anchor: bls12_381::Scalar, - merkle_path: MerklePath, - ) -> Result<([u8; GROTH_PROOF_SIZE], ValueCommitment, PublicKey), ()> { - let (proof, cv, rk) = ctx.spend_proof( - proof_generation_key, - diversifier, - rseed, - ar, - value, - anchor, - merkle_path, - &self.spend_params, - )?; - - let mut zkproof = [0u8; GROTH_PROOF_SIZE]; - proof - .write(&mut zkproof[..]) - .expect("should be able to serialize a proof"); - - Ok((zkproof, cv, rk)) - } - - fn output_proof( - &self, - ctx: &mut Self::SaplingProvingContext, - esk: jubjub::Fr, - payment_address: PaymentAddress, - rcm: jubjub::Fr, - value: u64, - ) -> ([u8; GROTH_PROOF_SIZE], ValueCommitment) { - let (proof, cv) = ctx.output_proof(esk, payment_address, rcm, value, &self.output_params); - - let mut zkproof = [0u8; GROTH_PROOF_SIZE]; - proof - .write(&mut zkproof[..]) - .expect("should be able to serialize a proof"); - - (zkproof, cv) - } - - fn binding_sig( - &self, - ctx: &mut Self::SaplingProvingContext, - value_balance: Amount, - sighash: &[u8; 32], - ) -> Result { - ctx.binding_sig(value_balance, sighash) - } -} From 6e42d839cd054c5202e6a9c4574c568a476e2487 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Fri, 3 Nov 2023 01:46:34 +0000 Subject: [PATCH 2/2] zcash_proofs: Remove `sapling::SaplingProvingContext` --- zcash_proofs/CHANGELOG.md | 13 +-- zcash_proofs/src/sapling/mod.rs | 1 - zcash_proofs/src/sapling/prover.rs | 160 +---------------------------- 3 files changed, 6 insertions(+), 168 deletions(-) diff --git a/zcash_proofs/CHANGELOG.md b/zcash_proofs/CHANGELOG.md index 1971f9359..d95bcf422 100644 --- a/zcash_proofs/CHANGELOG.md +++ b/zcash_proofs/CHANGELOG.md @@ -12,21 +12,14 @@ and this library adheres to Rust's notion of `zcash_proofs::prover::LocalTxProver` ### Changed -- The new `SpendParameters` and `OutputParameters` types are used in the - following places: - - `zcash_proofs::ZcashParameters::{spend_params, output_params}` fields. - - `zcash_proofs::sapling::prover`: - - `SaplingProvingContext::{spend_proof, output_proof}` (the `proving_key` - arguments). -- `zcash_proofs::sapling::prover`: - - The `verifying_key` argument `SaplingProvingContext::spend_proof` has been - removed. Callers should instead use `SaplingVerifyingContext` to verify - proofs after they have been created. +- The `zcash_proofs::ZcashParameters::{spend_params, output_params}` fields + now have types `SpendParameters` and `OutputParameters` respectively. ### Removed - `zcash_proofs::circuit::sapling` (moved to `zcash_primitives::sapling::circuit`). - `zcash_proofs::circuit::{ecc, pedersen_hash}` - `zcash_proofs::constants` +- `zcash_proofs::sapling::SaplingProvingContext` ## [0.13.0] - 2023-09-25 ### Changed diff --git a/zcash_proofs/src/sapling/mod.rs b/zcash_proofs/src/sapling/mod.rs index 3aae724be..1faf0ab09 100644 --- a/zcash_proofs/src/sapling/mod.rs +++ b/zcash_proofs/src/sapling/mod.rs @@ -3,5 +3,4 @@ mod prover; mod verifier; -pub use self::prover::SaplingProvingContext; pub use self::verifier::{BatchValidator, SaplingVerificationContext}; diff --git a/zcash_proofs/src/sapling/prover.rs b/zcash_proofs/src/sapling/prover.rs index b028e3e96..f7c1d59dd 100644 --- a/zcash_proofs/src/sapling/prover.rs +++ b/zcash_proofs/src/sapling/prover.rs @@ -1,17 +1,14 @@ use bellman::groth16::{create_random_proof, Proof}; use bls12_381::Bls12; -use group::GroupEncoding; -use rand_core::{OsRng, RngCore}; +use rand_core::RngCore; use zcash_primitives::{ sapling::{ circuit::{Output, Spend, ValueCommitmentOpening}, - constants::{SPENDING_KEY_GENERATOR, VALUE_COMMITMENT_RANDOMNESS_GENERATOR}, prover::{OutputProver, SpendProver}, - redjubjub::{PublicKey, Signature}, - value::{CommitmentSum, NoteValue, TrapdoorSum, ValueCommitTrapdoor, ValueCommitment}, + value::{NoteValue, ValueCommitTrapdoor}, Diversifier, MerklePath, Note, PaymentAddress, ProofGenerationKey, Rseed, }, - transaction::components::{sapling::GrothProofBytes, Amount, GROTH_PROOF_SIZE}, + transaction::components::{sapling::GrothProofBytes, GROTH_PROOF_SIZE}, }; use crate::{OutputParameters, SpendParameters}; @@ -111,154 +108,3 @@ impl OutputProver for OutputParameters { zkproof } } - -/// A context object for creating the Sapling components of a Zcash transaction. -pub struct SaplingProvingContext { - bsk: TrapdoorSum, - // (sum of the Spend value commitments) - (sum of the Output value commitments) - cv_sum: CommitmentSum, -} - -impl Default for SaplingProvingContext { - fn default() -> Self { - SaplingProvingContext::new() - } -} - -impl SaplingProvingContext { - /// Construct a new context to be used with a single transaction. - pub fn new() -> Self { - SaplingProvingContext { - bsk: TrapdoorSum::zero(), - cv_sum: CommitmentSum::zero(), - } - } - - /// Create the value commitment, re-randomized key, and proof for a Sapling - /// SpendDescription, while accumulating its value commitment randomness - /// inside the context for later use. - #[allow(clippy::too_many_arguments)] - pub fn spend_proof( - &mut self, - proof_generation_key: ProofGenerationKey, - diversifier: Diversifier, - rseed: Rseed, - ar: jubjub::Fr, - value: u64, - anchor: bls12_381::Scalar, - merkle_path: MerklePath, - proving_key: &SpendParameters, - ) -> Result<(Proof, ValueCommitment, PublicKey), ()> { - // Initialize secure RNG - let mut rng = OsRng; - - // We create the randomness of the value commitment - let rcv = ValueCommitTrapdoor::random(&mut rng); - - // Accumulate the value commitment randomness in the context - self.bsk += &rcv; - - // Construct the value commitment - let value = NoteValue::from_raw(value); - let value_commitment = ValueCommitment::derive(value, rcv.clone()); - - // This is the result of the re-randomization, we compute it for the caller - let rk = PublicKey(proof_generation_key.ak.into()).randomize(ar, SPENDING_KEY_GENERATOR); - - let instance = SpendParameters::prepare_circuit( - proof_generation_key, - diversifier, - rseed, - value, - ar, - rcv, - anchor, - merkle_path, - ) - .ok_or(())?; - - // Create proof - let proof = proving_key.create_proof(instance, &mut rng); - - // Accumulate the value commitment in the context - self.cv_sum += &value_commitment; - - Ok((proof, value_commitment, rk)) - } - - /// Create the value commitment and proof for a Sapling OutputDescription, - /// while accumulating its value commitment randomness inside the context - /// for later use. - pub fn output_proof( - &mut self, - esk: jubjub::Fr, - payment_address: PaymentAddress, - rcm: jubjub::Fr, - value: u64, - proving_key: &OutputParameters, - ) -> (Proof, ValueCommitment) { - // Initialize secure RNG - let mut rng = OsRng; - - // We construct ephemeral randomness for the value commitment. This - // randomness is not given back to the caller, but the synthetic - // blinding factor `bsk` is accumulated in the context. - let rcv = ValueCommitTrapdoor::random(&mut rng); - - // Accumulate the value commitment randomness in the context - self.bsk -= &rcv; // Outputs subtract from the total. - - // Construct the value commitment for the proof instance - let value = NoteValue::from_raw(value); - let value_commitment = ValueCommitment::derive(value, rcv.clone()); - - // We now have a full witness for the output proof. - let instance = OutputParameters::prepare_circuit(esk, payment_address, rcm, value, rcv); - - // Create proof - let proof = proving_key.create_proof(instance, &mut rng); - - // Accumulate the value commitment in the context. We do this to check internal consistency. - self.cv_sum -= &value_commitment; // Outputs subtract from the total. - - (proof, value_commitment) - } - - /// Create the bindingSig for a Sapling transaction. All calls to spend_proof() - /// and output_proof() must be completed before calling this function. - pub fn binding_sig(&self, value_balance: Amount, sighash: &[u8; 32]) -> Result { - // Initialize secure RNG - let mut rng = OsRng; - - // Grab the current `bsk` from the context - let bsk = self.bsk.into_bsk(); - - // Grab the `bvk` using DerivePublic. - let bvk = PublicKey::from_private(&bsk, VALUE_COMMITMENT_RANDOMNESS_GENERATOR); - - // In order to check internal consistency, let's use the accumulated value - // commitments (as the verifier would) and apply value_balance to compare - // against our derived bvk. - { - // Compute the final bvk. - let final_bvk = self.cv_sum.into_bvk(value_balance); - - // The result should be the same, unless the provided valueBalance is wrong. - if bvk.0 != final_bvk.0 { - return Err(()); - } - } - - // Construct signature message - let mut data_to_be_signed = [0u8; 64]; - data_to_be_signed[0..32].copy_from_slice(&bvk.0.to_bytes()); - data_to_be_signed[32..64].copy_from_slice(&sighash[..]); - - // Sign - Ok(bsk.sign( - &data_to_be_signed, - &mut rng, - VALUE_COMMITMENT_RANDOMNESS_GENERATOR, - )) - } -}