zcash_proofs/
prover.rs

1//! Abstractions over the proving system and parameters for ease of use.
2
3use bellman::groth16::Proof;
4use bls12_381::Bls12;
5use std::path::Path;
6
7use sapling::{
8    bundle::GrothProofBytes,
9    circuit::{OutputVerifyingKey, SpendVerifyingKey},
10    keys::EphemeralSecretKey,
11    prover::{OutputProver, SpendProver},
12    value::{NoteValue, ValueCommitTrapdoor},
13    Diversifier, MerklePath, PaymentAddress, ProofGenerationKey, Rseed,
14};
15use zcash_primitives::transaction::components::GROTH_PROOF_SIZE;
16
17use crate::{load_parameters, parse_parameters, OutputParameters, SpendParameters};
18
19#[cfg(feature = "local-prover")]
20use crate::{default_params_folder, SAPLING_OUTPUT_NAME, SAPLING_SPEND_NAME};
21
22/// An implementation of [`SpendProver`] and [`OutputProver`] using Sapling Spend and
23/// Output parameters from locally-accessible paths.
24pub struct LocalTxProver {
25    spend_params: SpendParameters,
26    output_params: OutputParameters,
27}
28
29impl LocalTxProver {
30    /// Creates a `LocalTxProver` using parameters from the given local paths.
31    ///
32    /// # Examples
33    ///
34    /// ```should_panic
35    /// use std::path::Path;
36    /// use zcash_proofs::prover::LocalTxProver;
37    ///
38    /// let tx_prover = LocalTxProver::new(
39    ///     Path::new("/path/to/sapling-spend.params"),
40    ///     Path::new("/path/to/sapling-output.params"),
41    /// );
42    /// ```
43    ///
44    /// # Panics
45    ///
46    /// This function will panic if the paths do not point to valid parameter files with
47    /// the expected hashes.
48    pub fn new(spend_path: &Path, output_path: &Path) -> Self {
49        let p = load_parameters(spend_path, output_path, None);
50        LocalTxProver {
51            spend_params: p.spend_params,
52            output_params: p.output_params,
53        }
54    }
55
56    /// Creates a `LocalTxProver` using parameters specified as byte arrays.
57    ///
58    /// # Examples
59    ///
60    /// ```should_panic
61    /// use std::path::Path;
62    /// use zcash_proofs::prover::LocalTxProver;
63    ///
64    /// let tx_prover = LocalTxProver::from_bytes(&[0u8], &[0u8]);
65    /// ```
66    ///
67    /// # Panics
68    ///
69    /// This function will panic if the byte arrays do not contain valid parameters with
70    /// the expected hashes.
71    pub fn from_bytes(spend_param_bytes: &[u8], output_param_bytes: &[u8]) -> Self {
72        let p = parse_parameters(spend_param_bytes, output_param_bytes, None);
73
74        LocalTxProver {
75            spend_params: p.spend_params,
76            output_params: p.output_params,
77        }
78    }
79
80    /// Attempts to create a `LocalTxProver` using parameters from the default local
81    /// location.
82    ///
83    /// Returns `None` if any of the parameters cannot be found in the default local
84    /// location.
85    ///
86    /// # Examples
87    ///
88    /// ```
89    /// use zcash_proofs::prover::LocalTxProver;
90    ///
91    /// match LocalTxProver::with_default_location() {
92    ///     Some(tx_prover) => (),
93    ///     None => println!("Please run zcash-fetch-params or fetch-params.sh to download the parameters."),
94    /// }
95    /// ```
96    ///
97    /// # Panics
98    ///
99    /// This function will panic if the parameters in the default local location do not
100    /// have the expected hashes.
101    #[cfg(feature = "local-prover")]
102    pub fn with_default_location() -> Option<Self> {
103        let params_dir = default_params_folder()?;
104        let (spend_path, output_path) = if params_dir.exists() {
105            (
106                params_dir.join(SAPLING_SPEND_NAME),
107                params_dir.join(SAPLING_OUTPUT_NAME),
108            )
109        } else {
110            return None;
111        };
112        if !(spend_path.exists() && output_path.exists()) {
113            return None;
114        }
115
116        Some(LocalTxProver::new(&spend_path, &output_path))
117    }
118
119    /// Creates a `LocalTxProver` using Sapling parameters bundled inside the binary.
120    ///
121    /// This requires the `bundled-prover` feature, which will increase the binary size by
122    /// around 50 MiB.
123    #[cfg(feature = "bundled-prover")]
124    pub fn bundled() -> Self {
125        let (spend_buf, output_buf) = wagyu_zcash_parameters::load_sapling_parameters();
126        let p = parse_parameters(&spend_buf[..], &output_buf[..], None);
127
128        LocalTxProver {
129            spend_params: p.spend_params,
130            output_params: p.output_params,
131        }
132    }
133
134    /// Returns the verifying keys for the Sapling circuits.
135    pub fn verifying_keys(&self) -> (SpendVerifyingKey, OutputVerifyingKey) {
136        (
137            self.spend_params.verifying_key(),
138            self.output_params.verifying_key(),
139        )
140    }
141}
142
143impl SpendProver for LocalTxProver {
144    type Proof = Proof<Bls12>;
145
146    fn prepare_circuit(
147        proof_generation_key: ProofGenerationKey,
148        diversifier: Diversifier,
149        rseed: Rseed,
150        value: NoteValue,
151        alpha: jubjub::Fr,
152        rcv: ValueCommitTrapdoor,
153        anchor: bls12_381::Scalar,
154        merkle_path: MerklePath,
155    ) -> Option<sapling::circuit::Spend> {
156        SpendParameters::prepare_circuit(
157            proof_generation_key,
158            diversifier,
159            rseed,
160            value,
161            alpha,
162            rcv,
163            anchor,
164            merkle_path,
165        )
166    }
167
168    fn create_proof<R: rand_core::RngCore>(
169        &self,
170        circuit: sapling::circuit::Spend,
171        rng: &mut R,
172    ) -> Self::Proof {
173        self.spend_params.create_proof(circuit, rng)
174    }
175
176    fn encode_proof(proof: Self::Proof) -> GrothProofBytes {
177        let mut zkproof = [0u8; GROTH_PROOF_SIZE];
178        proof
179            .write(&mut zkproof[..])
180            .expect("should be able to serialize a proof");
181        zkproof
182    }
183}
184
185impl OutputProver for LocalTxProver {
186    type Proof = Proof<Bls12>;
187
188    fn prepare_circuit(
189        esk: &EphemeralSecretKey,
190        payment_address: PaymentAddress,
191        rcm: jubjub::Fr,
192        value: NoteValue,
193        rcv: ValueCommitTrapdoor,
194    ) -> sapling::circuit::Output {
195        OutputParameters::prepare_circuit(esk, payment_address, rcm, value, rcv)
196    }
197
198    fn create_proof<R: rand_core::RngCore>(
199        &self,
200        circuit: sapling::circuit::Output,
201        rng: &mut R,
202    ) -> Self::Proof {
203        self.output_params.create_proof(circuit, rng)
204    }
205
206    fn encode_proof(proof: Self::Proof) -> GrothProofBytes {
207        let mut zkproof = [0u8; GROTH_PROOF_SIZE];
208        proof
209            .write(&mut zkproof[..])
210            .expect("should be able to serialize a proof");
211        zkproof
212    }
213}