sapling_crypto/pczt/
prover.rs

1use rand::{CryptoRng, RngCore};
2
3use crate::{
4    prover::{OutputProver, SpendProver},
5    Note, Rseed,
6};
7
8impl super::Bundle {
9    /// Adds a proof to this PCZT bundle.
10    pub fn create_proofs<S, O, R: RngCore + CryptoRng>(
11        &mut self,
12        spend_prover: &S,
13        output_prover: &O,
14        mut rng: R,
15    ) -> Result<(), ProverError>
16    where
17        S: SpendProver,
18        O: OutputProver,
19    {
20        for spend in &mut self.spends {
21            let proof_generation_key = spend
22                .proof_generation_key
23                .clone()
24                .ok_or(ProverError::MissingProofGenerationKey)?;
25
26            let note = Note::from_parts(
27                spend.recipient.ok_or(ProverError::MissingRecipient)?,
28                spend.value.ok_or(ProverError::MissingValue)?,
29                spend.rseed.ok_or(ProverError::MissingRandomSeed)?,
30            );
31
32            let alpha = spend.alpha.ok_or(ProverError::MissingSpendAuthRandomizer)?;
33
34            let rcv = spend
35                .rcv
36                .clone()
37                .ok_or(ProverError::MissingValueCommitTrapdoor)?;
38
39            let merkle_path = spend.witness.clone().ok_or(ProverError::MissingWitness)?;
40
41            let circuit = S::prepare_circuit(
42                proof_generation_key,
43                *note.recipient().diversifier(),
44                *note.rseed(),
45                note.value(),
46                alpha,
47                rcv,
48                self.anchor.inner(),
49                merkle_path,
50            )
51            .ok_or(ProverError::InvalidDiversifier)?;
52
53            let proof = spend_prover.create_proof(circuit, &mut rng);
54            spend.zkproof = Some(S::encode_proof(proof));
55        }
56
57        for output in &mut self.outputs {
58            let recipient = output.recipient.ok_or(ProverError::MissingRecipient)?;
59            let value = output.value.ok_or(ProverError::MissingValue)?;
60
61            let note = Note::from_parts(
62                recipient,
63                value,
64                output
65                    .rseed
66                    .map(Rseed::AfterZip212)
67                    .ok_or(ProverError::MissingRandomSeed)?,
68            );
69
70            let esk = note.generate_or_derive_esk(&mut rng);
71            let rcm = note.rcm();
72
73            let rcv = output
74                .rcv
75                .clone()
76                .ok_or(ProverError::MissingValueCommitTrapdoor)?;
77
78            let circuit = O::prepare_circuit(&esk, recipient, rcm, value, rcv);
79            let proof = output_prover.create_proof(circuit, &mut rng);
80            output.zkproof = Some(O::encode_proof(proof));
81        }
82
83        Ok(())
84    }
85}
86
87/// Errors that can occur while creating Sapling proofs for a PCZT.
88#[derive(Debug)]
89pub enum ProverError {
90    InvalidDiversifier,
91    /// The Prover role requires all `proof_generation_key` fields to be set.
92    MissingProofGenerationKey,
93    /// The Prover role requires all `rseed` fields to be set.
94    MissingRandomSeed,
95    /// The Prover role requires all `recipient` fields to be set.
96    MissingRecipient,
97    /// The Prover role requires all `alpha` fields to be set.
98    MissingSpendAuthRandomizer,
99    /// The Prover role requires all `value` fields to be set.
100    MissingValue,
101    /// The Prover role requires all `rcv` fields to be set.
102    MissingValueCommitTrapdoor,
103    /// The Prover role requires all `witness` fields to be set.
104    MissingWitness,
105}