1use bellman::groth16::{create_random_proof, Proof};
4use bls12_381::Bls12;
5use rand_core::RngCore;
6
7use crate::{
8 bundle::GrothProofBytes,
9 circuit,
10 constants::GROTH_PROOF_SIZE,
11 keys::EphemeralSecretKey,
12 value::{NoteValue, ValueCommitTrapdoor},
13 MerklePath,
14};
15
16use super::{
17 circuit::{Output, OutputParameters, Spend, SpendParameters, ValueCommitmentOpening},
18 Diversifier, Note, PaymentAddress, ProofGenerationKey, Rseed,
19};
20
21pub trait SpendProver {
23 type Proof;
25
26 #[allow(clippy::too_many_arguments)]
30 fn prepare_circuit(
31 proof_generation_key: ProofGenerationKey,
32 diversifier: Diversifier,
33 rseed: Rseed,
34 value: NoteValue,
35 alpha: jubjub::Fr,
36 rcv: ValueCommitTrapdoor,
37 anchor: bls12_381::Scalar,
38 merkle_path: MerklePath,
39 ) -> Option<circuit::Spend>;
40
41 fn create_proof<R: RngCore>(&self, circuit: circuit::Spend, rng: &mut R) -> Self::Proof;
45
46 fn encode_proof(proof: Self::Proof) -> GrothProofBytes;
50}
51
52pub trait OutputProver {
54 type Proof;
56
57 fn prepare_circuit(
61 esk: &EphemeralSecretKey,
62 payment_address: PaymentAddress,
63 rcm: jubjub::Fr,
64 value: NoteValue,
65 rcv: ValueCommitTrapdoor,
66 ) -> circuit::Output;
67
68 fn create_proof<R: RngCore>(&self, circuit: circuit::Output, rng: &mut R) -> Self::Proof;
72
73 fn encode_proof(proof: Self::Proof) -> GrothProofBytes;
77}
78
79impl SpendProver for SpendParameters {
80 type Proof = Proof<Bls12>;
81
82 fn prepare_circuit(
83 proof_generation_key: ProofGenerationKey,
84 diversifier: Diversifier,
85 rseed: Rseed,
86 value: NoteValue,
87 alpha: jubjub::Fr,
88 rcv: ValueCommitTrapdoor,
89 anchor: bls12_381::Scalar,
90 merkle_path: MerklePath,
91 ) -> Option<Spend> {
92 let value_commitment_opening = ValueCommitmentOpening {
94 value,
95 randomness: rcv.inner(),
96 };
97
98 let viewing_key = proof_generation_key.to_viewing_key();
100
101 let payment_address = viewing_key.to_payment_address(diversifier)?;
103
104 let note = Note::from_parts(payment_address, value, rseed);
105
106 let pos: u64 = merkle_path.position().into();
108 Some(Spend {
109 value_commitment_opening: Some(value_commitment_opening),
110 proof_generation_key: Some(proof_generation_key),
111 payment_address: Some(payment_address),
112 commitment_randomness: Some(note.rcm()),
113 ar: Some(alpha),
114 auth_path: merkle_path
115 .path_elems()
116 .iter()
117 .enumerate()
118 .map(|(i, node)| Some(((*node).into(), (pos >> i) & 0x1 == 1)))
119 .collect(),
120 anchor: Some(anchor),
121 })
122 }
123
124 fn create_proof<R: RngCore>(&self, circuit: Spend, rng: &mut R) -> Self::Proof {
125 create_random_proof(circuit, &self.0, rng).expect("proving should not fail")
126 }
127
128 fn encode_proof(proof: Self::Proof) -> GrothProofBytes {
129 let mut zkproof = [0u8; GROTH_PROOF_SIZE];
130 proof
131 .write(&mut zkproof[..])
132 .expect("should be able to serialize a proof");
133 zkproof
134 }
135}
136
137impl OutputProver for OutputParameters {
138 type Proof = Proof<Bls12>;
139
140 fn prepare_circuit(
141 esk: &EphemeralSecretKey,
142 payment_address: PaymentAddress,
143 rcm: jubjub::Fr,
144 value: NoteValue,
145 rcv: ValueCommitTrapdoor,
146 ) -> Output {
147 let value_commitment_opening = ValueCommitmentOpening {
149 value,
150 randomness: rcv.inner(),
151 };
152
153 Output {
155 value_commitment_opening: Some(value_commitment_opening),
156 payment_address: Some(payment_address),
157 commitment_randomness: Some(rcm),
158 esk: Some(esk.0),
159 }
160 }
161
162 fn create_proof<R: RngCore>(&self, circuit: Output, rng: &mut R) -> Self::Proof {
163 create_random_proof(circuit, &self.0, rng).expect("proving should not fail")
164 }
165
166 fn encode_proof(proof: Self::Proof) -> GrothProofBytes {
167 let mut zkproof = [0u8; GROTH_PROOF_SIZE];
168 proof
169 .write(&mut zkproof[..])
170 .expect("should be able to serialize a proof");
171 zkproof
172 }
173}
174
175#[cfg(any(test, feature = "test-dependencies"))]
176#[cfg_attr(docsrs, doc(cfg(feature = "test-dependencies")))]
177pub mod mock {
178 use ff::Field;
179
180 use super::{OutputProver, SpendProver};
181 use crate::{
182 bundle::GrothProofBytes,
183 circuit::{self, ValueCommitmentOpening},
184 constants::GROTH_PROOF_SIZE,
185 keys::EphemeralSecretKey,
186 value::{NoteValue, ValueCommitTrapdoor},
187 Diversifier, MerklePath, PaymentAddress, ProofGenerationKey, Rseed,
188 };
189
190 pub struct MockSpendProver;
191
192 impl SpendProver for MockSpendProver {
193 type Proof = GrothProofBytes;
194
195 fn prepare_circuit(
196 proof_generation_key: ProofGenerationKey,
197 diversifier: Diversifier,
198 _rseed: Rseed,
199 value: NoteValue,
200 alpha: jubjub::Fr,
201 rcv: ValueCommitTrapdoor,
202 anchor: bls12_381::Scalar,
203 _merkle_path: MerklePath,
204 ) -> Option<circuit::Spend> {
205 let payment_address = proof_generation_key
206 .to_viewing_key()
207 .ivk()
208 .to_payment_address(diversifier);
209 Some(circuit::Spend {
210 value_commitment_opening: Some(ValueCommitmentOpening {
211 value,
212 randomness: rcv.inner(),
213 }),
214 proof_generation_key: Some(proof_generation_key),
215 payment_address,
216 commitment_randomness: Some(jubjub::Scalar::ZERO),
217 ar: Some(alpha),
218 auth_path: vec![],
219 anchor: Some(anchor),
220 })
221 }
222
223 fn create_proof<R: rand_core::RngCore>(
224 &self,
225 _circuit: circuit::Spend,
226 _rng: &mut R,
227 ) -> Self::Proof {
228 [0u8; GROTH_PROOF_SIZE]
229 }
230
231 fn encode_proof(proof: Self::Proof) -> GrothProofBytes {
232 proof
233 }
234 }
235
236 pub struct MockOutputProver;
237
238 impl OutputProver for MockOutputProver {
239 type Proof = GrothProofBytes;
240
241 fn prepare_circuit(
242 esk: &EphemeralSecretKey,
243 payment_address: PaymentAddress,
244 rcm: jubjub::Fr,
245 value: NoteValue,
246 rcv: ValueCommitTrapdoor,
247 ) -> circuit::Output {
248 circuit::Output {
249 value_commitment_opening: Some(ValueCommitmentOpening {
250 value,
251 randomness: rcv.inner(),
252 }),
253 payment_address: Some(payment_address),
254 commitment_randomness: Some(rcm),
255 esk: Some(esk.0),
256 }
257 }
258
259 fn create_proof<R: rand_core::RngCore>(
260 &self,
261 _circuit: circuit::Output,
262 _rng: &mut R,
263 ) -> Self::Proof {
264 [0u8; GROTH_PROOF_SIZE]
265 }
266
267 fn encode_proof(proof: Self::Proof) -> GrothProofBytes {
268 proof
269 }
270 }
271}