sapling_crypto/pczt/
io_finalizer.rs1use alloc::vec::Vec;
2use rand::{CryptoRng, RngCore};
3
4use crate::value::{CommitmentSum, TrapdoorSum};
5
6use super::SignerError;
7
8impl super::Bundle {
9 pub fn finalize_io<R: RngCore + CryptoRng>(
11 &mut self,
12 sighash: [u8; 32],
13 mut rng: R,
14 ) -> Result<(), IoFinalizerError> {
15 let bsk = {
17 let spend_rcvs = self
18 .spends
19 .iter()
20 .map(|spend| {
21 spend
22 .rcv
23 .as_ref()
24 .ok_or(IoFinalizerError::MissingValueCommitTrapdoor)
25 })
26 .collect::<Result<Vec<_>, _>>()?;
27
28 let output_rcvs = self
29 .outputs
30 .iter()
31 .map(|output| {
32 output
33 .rcv
34 .as_ref()
35 .ok_or(IoFinalizerError::MissingValueCommitTrapdoor)
36 })
37 .collect::<Result<Vec<_>, _>>()?;
38
39 let spends: TrapdoorSum = spend_rcvs.into_iter().sum();
40 let outputs: TrapdoorSum = output_rcvs.into_iter().sum();
41 (spends - outputs).into_bsk()
42 };
43
44 let bvk = {
46 let spends = self
47 .spends
48 .iter()
49 .map(|spend| spend.cv())
50 .sum::<CommitmentSum>();
51 let outputs = self
52 .outputs
53 .iter()
54 .map(|output| output.cv())
55 .sum::<CommitmentSum>();
56 (spends - outputs).into_bvk(
57 i64::try_from(self.value_sum).map_err(|_| IoFinalizerError::InvalidValueSum)?,
58 )
59 };
60 if redjubjub::VerificationKey::from(&bsk) != bvk {
61 return Err(IoFinalizerError::ValueCommitMismatch);
62 }
63 self.bsk = Some(bsk);
64
65 for spend in self.spends.iter_mut() {
67 if let Some(ask) = spend.dummy_ask.take() {
70 spend
71 .sign(sighash, &ask, &mut rng)
72 .map_err(IoFinalizerError::DummySignature)?;
73 }
74 }
75
76 Ok(())
77 }
78}
79
80#[derive(Debug)]
82pub enum IoFinalizerError {
83 DummySignature(SignerError),
85 InvalidValueSum,
87 MissingValueCommitTrapdoor,
89 ValueCommitMismatch,
92}