sapling_crypto/pczt/
updater.rs

1use core::fmt;
2
3use alloc::string::String;
4use alloc::vec::Vec;
5
6use crate::ProofGenerationKey;
7
8use super::{Bundle, Output, Spend, Zip32Derivation};
9
10impl Bundle {
11    /// Updates the bundle with information provided in the given closure.
12    pub fn update_with<F>(&mut self, f: F) -> Result<(), UpdaterError>
13    where
14        F: FnOnce(Updater<'_>) -> Result<(), UpdaterError>,
15    {
16        f(Updater(self))
17    }
18}
19
20/// An updater for a Sapling PCZT bundle.
21pub struct Updater<'a>(&'a mut Bundle);
22
23impl Updater<'_> {
24    /// Provides read access to the bundle being updated.
25    pub fn bundle(&self) -> &Bundle {
26        self.0
27    }
28
29    /// Updates the spend at the given index with information provided in the given
30    /// closure.
31    pub fn update_spend_with<F>(&mut self, index: usize, f: F) -> Result<(), UpdaterError>
32    where
33        F: FnOnce(SpendUpdater<'_>) -> Result<(), UpdaterError>,
34    {
35        f(SpendUpdater(
36            self.0
37                .spends
38                .get_mut(index)
39                .ok_or(UpdaterError::InvalidIndex)?,
40        ))
41    }
42
43    /// Updates the output at the given index with information provided in the given
44    /// closure.
45    pub fn update_output_with<F>(&mut self, index: usize, f: F) -> Result<(), UpdaterError>
46    where
47        F: FnOnce(OutputUpdater<'_>) -> Result<(), UpdaterError>,
48    {
49        f(OutputUpdater(
50            self.0
51                .outputs
52                .get_mut(index)
53                .ok_or(UpdaterError::InvalidIndex)?,
54        ))
55    }
56}
57
58/// An updater for a Sapling PCZT spend.
59pub struct SpendUpdater<'a>(&'a mut Spend);
60
61impl SpendUpdater<'_> {
62    /// Sets the proof generation key for this spend.
63    ///
64    /// Returns an error if the proof generation key does not match the spend.
65    pub fn set_proof_generation_key(
66        &mut self,
67        proof_generation_key: ProofGenerationKey,
68    ) -> Result<(), UpdaterError> {
69        // TODO: Verify that the proof generation key matches the spend, if possible.
70        self.0.proof_generation_key = Some(proof_generation_key);
71        Ok(())
72    }
73
74    /// Sets the ZIP 32 derivation path for the spent note's signing key.
75    pub fn set_zip32_derivation(&mut self, derivation: Zip32Derivation) {
76        self.0.zip32_derivation = Some(derivation);
77    }
78
79    /// Stores the given proprietary value at the given key.
80    pub fn set_proprietary(&mut self, key: String, value: Vec<u8>) {
81        self.0.proprietary.insert(key, value);
82    }
83}
84
85/// An updater for a Sapling PCZT output.
86pub struct OutputUpdater<'a>(&'a mut Output);
87
88impl OutputUpdater<'_> {
89    /// Sets the ZIP 32 derivation path for the new note's signing key.
90    pub fn set_zip32_derivation(&mut self, derivation: Zip32Derivation) {
91        self.0.zip32_derivation = Some(derivation);
92    }
93
94    /// Sets the user-facing address that the new note is being sent to.
95    pub fn set_user_address(&mut self, user_address: String) {
96        self.0.user_address = Some(user_address);
97    }
98
99    /// Stores the given proprietary value at the given key.
100    pub fn set_proprietary(&mut self, key: String, value: Vec<u8>) {
101        self.0.proprietary.insert(key, value);
102    }
103}
104
105/// Errors that can occur while updating a Sapling bundle in a PCZT.
106#[derive(Debug)]
107#[non_exhaustive]
108pub enum UpdaterError {
109    /// An out-of-bounds index was provided when looking up a spend or output.
110    InvalidIndex,
111    /// The provided `proof_generation_key` does not match the spend.
112    WrongProofGenerationKey,
113}
114
115impl fmt::Display for UpdaterError {
116    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
117        match self {
118            UpdaterError::InvalidIndex => write!(f, "Spend or output index is out-of-bounds"),
119            UpdaterError::WrongProofGenerationKey => {
120                write!(f, "`proof_generation_key` does not own the spent note")
121            }
122        }
123    }
124}
125
126#[cfg(feature = "std")]
127impl std::error::Error for UpdaterError {}