1use 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
22pub struct LocalTxProver {
25 spend_params: SpendParameters,
26 output_params: OutputParameters,
27}
28
29impl LocalTxProver {
30 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 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 #[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 #[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 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}