pczt/roles/prover/
sapling.rs1use rand_core::{CryptoRng, Rng};
2use sapling::prover::{OutputProver, SpendProver};
3
4use crate::{Pczt, common::AnchorRequirement};
5
6impl super::Prover {
7 pub fn create_sapling_proofs<S, O, R>(
11 self,
12 rng: R,
13 spend_prover: &S,
14 output_prover: &O,
15 ) -> Result<Self, SaplingError>
16 where
17 S: SpendProver,
18 O: OutputProver,
19 R: Rng + CryptoRng,
20 {
21 let Pczt {
22 global,
23 transparent,
24 sapling,
25 orchard,
26 ironwood,
27 } = self.pczt;
28
29 let mut parsed = sapling
30 .into_parsed(AnchorRequirement::Required)
31 .map_err(SaplingError::Parser)?;
32
33 crate::sapling::verify_witnesses_root_to_anchor(&parsed.bundle, *parsed.bundle.anchor())
34 .map_err(SaplingError::InconsistentWitness)?;
35
36 parsed
37 .bundle
38 .create_proofs(spend_prover, output_prover, rng)
39 .map_err(SaplingError::Prover)?;
40
41 Ok(Self {
42 pczt: Pczt {
43 global,
44 transparent,
45 sapling: parsed.reserialize(),
46 orchard,
47 ironwood,
48 },
49 })
50 }
51}
52
53#[derive(Debug)]
55pub enum SaplingError {
56 InconsistentWitness(crate::sapling::AnchorConsistencyError),
58 Parser(crate::sapling::ParseError),
59 Prover(sapling::pczt::ProverError),
60}
61
62#[cfg(test)]
63mod tests {
64 use alloc::collections::BTreeMap;
65 use rand::{rand_core::UnwrapErr, rngs::SysRng};
66
67 use zcash_proofs::prover::LocalTxProver;
68 use zcash_protocol::consensus::BranchId;
69
70 use super::SaplingError;
71 use crate::{roles::creator::Creator, roles::prover::Prover, sapling::Spend};
72
73 #[test]
74 fn create_sapling_proofs_fails_when_anchor_absent() {
75 let mut pczt = Creator::new(BranchId::Nu6_3.into(), 100, 133, None, None)
76 .unwrap()
77 .build()
78 .unwrap();
79 pczt.sapling.spends.push(Spend {
82 cv: [1; 32],
83 nullifier: [2; 32],
84 rk: [3; 32],
85 zkproof: None,
86 spend_auth_sig: None,
87 recipient: None,
88 value: None,
89 rcm: None,
90 rseed: None,
91 rcv: None,
92 proof_generation_key: None,
93 witness: None,
94 alpha: None,
95 zip32_derivation: None,
96 dummy_ask: None,
97 proprietary: BTreeMap::new(),
98 });
99
100 let prover = LocalTxProver::bundled();
101 assert!(matches!(
102 Prover::new(pczt).create_sapling_proofs(UnwrapErr(SysRng), &prover, &prover),
103 Err(SaplingError::Parser(
104 crate::sapling::ParseError::MissingAnchor
105 ))
106 ));
107 }
108
109 #[test]
115 fn create_sapling_proofs_preserves_absent_anchor_for_untouched_bundle() {
116 let pczt = Creator::new(BranchId::Nu6_3.into(), 100, 133, None, None)
117 .unwrap()
118 .build()
119 .unwrap();
120
121 let prover = LocalTxProver::bundled();
122 let pczt = Prover::new(pczt)
123 .create_sapling_proofs(UnwrapErr(SysRng), &prover, &prover)
124 .unwrap()
125 .finish();
126
127 assert_eq!(pczt.sapling, crate::sapling::EMPTY_BUNDLE);
128
129 let bytes = pczt.clone().serialize().unwrap();
130 assert_eq!(
131 crate::parse(&bytes).unwrap().sapling,
132 crate::sapling::EMPTY_BUNDLE
133 );
134 }
135}