Move `{Spend,Output}Parameters` from `zcash_proofs` to `zcash_primitives`

This commit is contained in:
Jack Grigg 2023-11-03 06:38:27 +00:00
parent 8bb9c4e7ba
commit 1b9f26c984
7 changed files with 159 additions and 135 deletions

View File

@ -12,6 +12,7 @@ and this library adheres to Rust's notion of
- `BatchValidator` (moved from `zcash_proofs::sapling`).
- `SaplingVerificationContext` (moved from `zcash_proofs::sapling`).
- `circuit` module (moved from `zcash_proofs::circuit::sapling`).
- `circuit::{SpendParameters, OutputParameters}`
- `constants` module.
- `prover::{SpendProver, OutputProver}`
- `value`:

View File

@ -1,10 +1,12 @@
//! The Sapling circuits.
use core::fmt;
use std::io;
use group::{ff::PrimeField, Curve};
use bellman::{Circuit, ConstraintSystem, SynthesisError};
use bellman::{groth16, Circuit, ConstraintSystem, SynthesisError};
use bls12_381::Bls12;
use super::{value::NoteValue, PaymentAddress, ProofGenerationKey};
@ -551,6 +553,42 @@ impl Circuit<bls12_381::Scalar> for Output {
}
}
/// The parameters for the Sapling Spend circuit.
pub struct SpendParameters(pub(crate) groth16::Parameters<Bls12>);
impl SpendParameters {
/// Reads the parameters from their encoding.
///
/// Only set `verify_point_encodings` to false if you are verifying the parameters in
/// another way (such as checking the hash of the parameters file on disk).
pub fn read<R: io::Read>(reader: R, verify_point_encodings: bool) -> io::Result<Self> {
groth16::Parameters::<Bls12>::read(reader, verify_point_encodings).map(Self)
}
/// Returns the verifying key for the Sapling Spend circuit.
pub fn verifying_key(&self) -> &groth16::VerifyingKey<Bls12> {
&self.0.vk
}
}
/// The parameters for the Sapling Output circuit.
pub struct OutputParameters(pub(crate) groth16::Parameters<Bls12>);
impl OutputParameters {
/// Reads the parameters from their encoding.
///
/// Only set `verify_point_encodings` to false if you are verifying the parameters in
/// another way (such as checking the hash of the parameters file on disk).
pub fn read<R: io::Read>(reader: R, verify_point_encodings: bool) -> io::Result<Self> {
groth16::Parameters::<Bls12>::read(reader, verify_point_encodings).map(Self)
}
/// Returns the verifying key for the Sapling Output circuit.
pub fn verifying_key(&self) -> &groth16::VerifyingKey<Bls12> {
&self.0.vk
}
}
#[test]
fn test_input_circuit_with_bls12_381() {
use crate::sapling::{pedersen_hash, Diversifier, Note, ProofGenerationKey, Rseed};

View File

@ -1,5 +1,7 @@
//! Abstractions over the proving system and parameters.
use bellman::groth16::{create_random_proof, Proof};
use bls12_381::Bls12;
use rand_core::RngCore;
use crate::{
@ -8,10 +10,13 @@ use crate::{
value::{NoteValue, ValueCommitTrapdoor},
MerklePath,
},
transaction::components::sapling::GrothProofBytes,
transaction::components::{sapling::GrothProofBytes, GROTH_PROOF_SIZE},
};
use super::{Diversifier, PaymentAddress, ProofGenerationKey, Rseed};
use super::{
circuit::{Output, OutputParameters, Spend, SpendParameters, ValueCommitmentOpening},
Diversifier, Note, PaymentAddress, ProofGenerationKey, Rseed,
};
/// Interface for creating Sapling Spend proofs.
pub trait SpendProver {
@ -79,6 +84,102 @@ pub trait OutputProver {
fn encode_proof(proof: Self::Proof) -> GrothProofBytes;
}
impl SpendProver for SpendParameters {
type Proof = Proof<Bls12>;
fn prepare_circuit(
proof_generation_key: ProofGenerationKey,
diversifier: Diversifier,
rseed: Rseed,
value: NoteValue,
alpha: jubjub::Fr,
rcv: ValueCommitTrapdoor,
anchor: bls12_381::Scalar,
merkle_path: MerklePath,
) -> Option<Spend> {
// Construct the value commitment
let value_commitment_opening = ValueCommitmentOpening {
value,
randomness: rcv.inner(),
};
// Construct the viewing key
let viewing_key = proof_generation_key.to_viewing_key();
// Construct the payment address with the viewing key / diversifier
let payment_address = viewing_key.to_payment_address(diversifier)?;
let note = Note::from_parts(payment_address, value, rseed);
// We now have the full witness for our circuit
let pos: u64 = merkle_path.position().into();
Some(Spend {
value_commitment_opening: Some(value_commitment_opening),
proof_generation_key: Some(proof_generation_key),
payment_address: Some(payment_address),
commitment_randomness: Some(note.rcm()),
ar: Some(alpha),
auth_path: merkle_path
.path_elems()
.iter()
.enumerate()
.map(|(i, node)| Some(((*node).into(), pos >> i & 0x1 == 1)))
.collect(),
anchor: Some(anchor),
})
}
fn create_proof<R: RngCore>(&self, circuit: Spend, rng: &mut R) -> Self::Proof {
create_random_proof(circuit, &self.0, rng).expect("proving should not fail")
}
fn encode_proof(proof: Self::Proof) -> GrothProofBytes {
let mut zkproof = [0u8; GROTH_PROOF_SIZE];
proof
.write(&mut zkproof[..])
.expect("should be able to serialize a proof");
zkproof
}
}
impl OutputProver for OutputParameters {
type Proof = Proof<Bls12>;
fn prepare_circuit(
esk: jubjub::Fr,
payment_address: PaymentAddress,
rcm: jubjub::Fr,
value: NoteValue,
rcv: ValueCommitTrapdoor,
) -> Output {
// Construct the value commitment for the proof instance
let value_commitment_opening = ValueCommitmentOpening {
value,
randomness: rcv.inner(),
};
// We now have a full witness for the output proof.
Output {
value_commitment_opening: Some(value_commitment_opening),
payment_address: Some(payment_address),
commitment_randomness: Some(rcm),
esk: Some(esk),
}
}
fn create_proof<R: RngCore>(&self, circuit: Output, rng: &mut R) -> Self::Proof {
create_random_proof(circuit, &self.0, rng).expect("proving should not fail")
}
fn encode_proof(proof: Self::Proof) -> GrothProofBytes {
let mut zkproof = [0u8; GROTH_PROOF_SIZE];
proof
.write(&mut zkproof[..])
.expect("should be able to serialize a proof");
zkproof
}
}
#[cfg(any(test, feature = "test-dependencies"))]
pub mod mock {
use ff::Field;

View File

@ -7,13 +7,13 @@ and this library adheres to Rust's notion of
## [Unreleased]
### Added
- `zcash_proofs::{SpendParameters, OutputParameters}`
- `impl zcash_primitives::sapling::prover::{SpendProver, OutputProver}` for
`zcash_proofs::prover::LocalTxProver`
### Changed
- The `zcash_proofs::ZcashParameters::{spend_params, output_params}` fields
now have types `SpendParameters` and `OutputParameters` respectively.
now have types `zcash_primitives::sapling::circuit::SpendParameters` and
`zcash_primitives::sapling::circuit::OutputParameters` respectively.
### Removed
- `zcash_proofs::circuit::sapling` (moved to `zcash_primitives::sapling::circuit`).

View File

@ -9,8 +9,10 @@
// Temporary until we have addressed all Result<T, ()> cases.
#![allow(clippy::result_unit_err)]
use bellman::groth16::{prepare_verifying_key, Parameters, PreparedVerifyingKey, VerifyingKey};
use bellman::groth16::{prepare_verifying_key, PreparedVerifyingKey, VerifyingKey};
use bls12_381::Bls12;
use zcash_primitives::sapling::circuit::{OutputParameters, SpendParameters};
use std::fs::File;
use std::io::{self, BufReader};
use std::path::Path;
@ -20,7 +22,6 @@ use std::path::PathBuf;
pub mod circuit;
mod hashreader;
pub mod sapling;
pub mod sprout;
#[cfg(any(feature = "local-prover", feature = "bundled-prover"))]
@ -283,12 +284,6 @@ fn stream_params_downloads_to_disk(
Ok(())
}
/// The parameters for the Sapling Spend circuit.
pub struct SpendParameters(Parameters<Bls12>);
/// The parameters for the Sapling Output circuit.
pub struct OutputParameters(Parameters<Bls12>);
/// Zcash Sprout and Sapling groth16 circuit parameters.
pub struct ZcashParameters {
pub spend_params: SpendParameters,
@ -355,9 +350,11 @@ pub fn load_parameters(
)
}
/// Parse Bls12 keys from bytes as serialized by [`Parameters::write`].
/// Parse Bls12 keys from bytes as serialized by [`groth16::Parameters::write`].
///
/// This function will panic if it encounters unparsable data.
///
/// [`groth16::Parameters::write`]: bellman::groth16::Parameters::write
pub fn parse_parameters<R: io::Read>(
spend_fs: R,
output_fs: R,
@ -368,10 +365,10 @@ pub fn parse_parameters<R: io::Read>(
let mut sprout_fs = sprout_fs.map(hashreader::HashReader::new);
// Deserialize params
let spend_params = Parameters::<Bls12>::read(&mut spend_fs, false)
.expect("couldn't deserialize Sapling spend parameters file");
let output_params = Parameters::<Bls12>::read(&mut output_fs, false)
.expect("couldn't deserialize Sapling spend parameters file");
let spend_params = SpendParameters::read(&mut spend_fs, false)
.expect("couldn't deserialize Sapling spend parameters");
let output_params = OutputParameters::read(&mut output_fs, false)
.expect("couldn't deserialize Sapling spend parameters");
// We only deserialize the verifying key for the Sprout parameters, which
// appears at the beginning of the parameter file. The rest is loaded
@ -430,14 +427,14 @@ pub fn parse_parameters<R: io::Read>(
}
// Prepare verifying keys
let spend_vk = prepare_verifying_key(&spend_params.vk);
let output_vk = prepare_verifying_key(&output_params.vk);
let spend_vk = prepare_verifying_key(spend_params.verifying_key());
let output_vk = prepare_verifying_key(output_params.verifying_key());
let sprout_vk = sprout_vk.map(|vk| prepare_verifying_key(&vk));
ZcashParameters {
spend_params: SpendParameters(spend_params),
spend_params,
spend_vk,
output_params: OutputParameters(output_params),
output_params,
output_vk,
sprout_vk,
}

View File

@ -1,3 +0,0 @@
//! Helpers for creating Sapling proofs.
mod prover;

View File

@ -1,110 +0,0 @@
use bellman::groth16::{create_random_proof, Proof};
use bls12_381::Bls12;
use rand_core::RngCore;
use zcash_primitives::{
sapling::{
circuit::{Output, Spend, ValueCommitmentOpening},
prover::{OutputProver, SpendProver},
value::{NoteValue, ValueCommitTrapdoor},
Diversifier, MerklePath, Note, PaymentAddress, ProofGenerationKey, Rseed,
},
transaction::components::{sapling::GrothProofBytes, GROTH_PROOF_SIZE},
};
use crate::{OutputParameters, SpendParameters};
impl SpendProver for SpendParameters {
type Proof = Proof<Bls12>;
fn prepare_circuit(
proof_generation_key: ProofGenerationKey,
diversifier: Diversifier,
rseed: Rseed,
value: NoteValue,
alpha: jubjub::Fr,
rcv: ValueCommitTrapdoor,
anchor: bls12_381::Scalar,
merkle_path: MerklePath,
) -> Option<Spend> {
// Construct the value commitment
let value_commitment_opening = ValueCommitmentOpening {
value,
randomness: rcv.inner(),
};
// Construct the viewing key
let viewing_key = proof_generation_key.to_viewing_key();
// Construct the payment address with the viewing key / diversifier
let payment_address = viewing_key.to_payment_address(diversifier)?;
let note = Note::from_parts(payment_address, value, rseed);
// We now have the full witness for our circuit
let pos: u64 = merkle_path.position().into();
Some(Spend {
value_commitment_opening: Some(value_commitment_opening),
proof_generation_key: Some(proof_generation_key),
payment_address: Some(payment_address),
commitment_randomness: Some(note.rcm()),
ar: Some(alpha),
auth_path: merkle_path
.path_elems()
.iter()
.enumerate()
.map(|(i, node)| Some(((*node).into(), pos >> i & 0x1 == 1)))
.collect(),
anchor: Some(anchor),
})
}
fn create_proof<R: RngCore>(&self, circuit: Spend, rng: &mut R) -> Self::Proof {
create_random_proof(circuit, &self.0, rng).expect("proving should not fail")
}
fn encode_proof(proof: Self::Proof) -> GrothProofBytes {
let mut zkproof = [0u8; GROTH_PROOF_SIZE];
proof
.write(&mut zkproof[..])
.expect("should be able to serialize a proof");
zkproof
}
}
impl OutputProver for OutputParameters {
type Proof = Proof<Bls12>;
fn prepare_circuit(
esk: jubjub::Fr,
payment_address: PaymentAddress,
rcm: jubjub::Fr,
value: NoteValue,
rcv: ValueCommitTrapdoor,
) -> Output {
// Construct the value commitment for the proof instance
let value_commitment_opening = ValueCommitmentOpening {
value,
randomness: rcv.inner(),
};
// We now have a full witness for the output proof.
Output {
value_commitment_opening: Some(value_commitment_opening),
payment_address: Some(payment_address),
commitment_randomness: Some(rcm),
esk: Some(esk),
}
}
fn create_proof<R: RngCore>(&self, circuit: Output, rng: &mut R) -> Self::Proof {
create_random_proof(circuit, &self.0, rng).expect("proving should not fail")
}
fn encode_proof(proof: Self::Proof) -> GrothProofBytes {
let mut zkproof = [0u8; GROTH_PROOF_SIZE];
proof
.write(&mut zkproof[..])
.expect("should be able to serialize a proof");
zkproof
}
}