sapling_crypto/pczt/
prover.rs

1use core::fmt;
2
3use rand::{CryptoRng, RngCore};
4
5use crate::{
6    prover::{OutputProver, SpendProver},
7    Note, Rseed,
8};
9
10impl super::Bundle {
11    /// Adds a proof to this PCZT bundle.
12    pub fn create_proofs<S, O, R: RngCore + CryptoRng>(
13        &mut self,
14        spend_prover: &S,
15        output_prover: &O,
16        mut rng: R,
17    ) -> Result<(), ProverError>
18    where
19        S: SpendProver,
20        O: OutputProver,
21    {
22        for spend in &mut self.spends {
23            let proof_generation_key = spend
24                .proof_generation_key
25                .clone()
26                .ok_or(ProverError::MissingProofGenerationKey)?;
27
28            let note = Note::from_parts(
29                spend.recipient.ok_or(ProverError::MissingRecipient)?,
30                spend.value.ok_or(ProverError::MissingValue)?,
31                spend.rseed.ok_or(ProverError::MissingRandomSeed)?,
32            );
33
34            let alpha = spend.alpha.ok_or(ProverError::MissingSpendAuthRandomizer)?;
35
36            let rcv = spend
37                .rcv
38                .clone()
39                .ok_or(ProverError::MissingValueCommitTrapdoor)?;
40
41            let merkle_path = spend.witness.clone().ok_or(ProverError::MissingWitness)?;
42
43            let circuit = S::prepare_circuit(
44                proof_generation_key,
45                *note.recipient().diversifier(),
46                *note.rseed(),
47                note.value(),
48                alpha,
49                rcv,
50                self.anchor.inner(),
51                merkle_path,
52            )
53            .ok_or(ProverError::InvalidDiversifier)?;
54
55            let proof = spend_prover.create_proof(circuit, &mut rng);
56            spend.zkproof = Some(S::encode_proof(proof));
57        }
58
59        for output in &mut self.outputs {
60            let recipient = output.recipient.ok_or(ProverError::MissingRecipient)?;
61            let value = output.value.ok_or(ProverError::MissingValue)?;
62
63            let note = Note::from_parts(
64                recipient,
65                value,
66                output
67                    .rseed
68                    .map(Rseed::AfterZip212)
69                    .ok_or(ProverError::MissingRandomSeed)?,
70            );
71
72            let esk = note.generate_or_derive_esk(&mut rng);
73            let rcm = note.rcm();
74
75            let rcv = output
76                .rcv
77                .clone()
78                .ok_or(ProverError::MissingValueCommitTrapdoor)?;
79
80            let circuit = O::prepare_circuit(&esk, recipient, rcm, value, rcv);
81            let proof = output_prover.create_proof(circuit, &mut rng);
82            output.zkproof = Some(O::encode_proof(proof));
83        }
84
85        Ok(())
86    }
87}
88
89/// Errors that can occur while creating Sapling proofs for a PCZT.
90#[derive(Debug)]
91#[non_exhaustive]
92pub enum ProverError {
93    /// The `recipient` field has an invalid diversifier.
94    ///
95    /// This should instead present as a [`ParseError::InvalidRecipient`] earlier on when
96    /// processing a PCZT.
97    ///
98    /// [`ParseError::InvalidRecipient`]: super::ParseError::InvalidRecipient
99    InvalidDiversifier,
100    /// The Prover role requires all `proof_generation_key` fields to be set.
101    MissingProofGenerationKey,
102    /// The Prover role requires all `rseed` fields to be set.
103    MissingRandomSeed,
104    /// The Prover role requires all `recipient` fields to be set.
105    MissingRecipient,
106    /// The Prover role requires all `alpha` fields to be set.
107    MissingSpendAuthRandomizer,
108    /// The Prover role requires all `value` fields to be set.
109    MissingValue,
110    /// The Prover role requires all `rcv` fields to be set.
111    MissingValueCommitTrapdoor,
112    /// The Prover role requires all `witness` fields to be set.
113    MissingWitness,
114}
115
116impl fmt::Display for ProverError {
117    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
118        match self {
119            ProverError::InvalidDiversifier => {
120                write!(f, "`recipient` has invalid diversifier")
121            }
122            ProverError::MissingProofGenerationKey => {
123                write!(f, "`proof_generation_key` must be set for the Prover role")
124            }
125            ProverError::MissingRandomSeed => {
126                write!(f, "`rseed` fields must be set for the Prover role")
127            }
128            ProverError::MissingRecipient => {
129                write!(f, "`recipient` fields must be set for the Prover role")
130            }
131            ProverError::MissingSpendAuthRandomizer => {
132                write!(f, "`alpha` must be set for the Prover role")
133            }
134            ProverError::MissingValue => {
135                write!(f, "`value` fields must be set for the Prover role")
136            }
137            ProverError::MissingValueCommitTrapdoor => {
138                write!(f, "`rcv` must be set for the Prover role")
139            }
140            ProverError::MissingWitness => write!(f, "`witness` must be set for the Prover role"),
141        }
142    }
143}
144
145#[cfg(feature = "std")]
146impl std::error::Error for ProverError {}