Skip to main content

pczt/roles/redactor/
orchard.rs

1use crate::orchard::{Action, Bundle, EncCiphertext, MEMO_SIZE, MemoPlaintext};
2
3impl super::Redactor {
4    /// Redacts the Orchard bundle with the given closure.
5    pub fn redact_orchard_with<F>(mut self, f: F) -> Self
6    where
7        F: FnOnce(OrchardRedactor<'_>),
8    {
9        f(OrchardRedactor(&mut self.pczt.orchard));
10        self
11    }
12
13    pub fn redact_ironwood_with<F>(mut self, f: F) -> Self
14    where
15        F: FnOnce(OrchardRedactor<'_>),
16    {
17        f(OrchardRedactor(&mut self.pczt.ironwood));
18        self
19    }
20}
21
22/// A Redactor for the Orchard bundle.
23pub struct OrchardRedactor<'a>(&'a mut Bundle);
24
25impl OrchardRedactor<'_> {
26    /// Compacts fields that can be resolved from the remaining action data.
27    ///
28    /// For every action, this removes `cv_net` and `cmx` when the remaining
29    /// fields derive the same values, and replaces a decryptable encrypted note
30    /// plaintext with its stripped memo plaintext when re-encryption reproduces
31    /// the original ciphertext. The receiver can restore these fields with
32    /// [`Bundle::resolve_fields`](crate::orchard::Bundle::resolve_fields).
33    ///
34    /// Encrypted note plaintexts that cannot be decrypted from the remaining
35    /// action data are left unchanged. Memo recovery runs before `cmx` is
36    /// removed because it needs the original note commitment. A bundle with
37    /// these fields compacted requires the v2 PCZT encoding.
38    #[cfg(feature = "orchard")]
39    pub fn compact_resolvable_fields(&mut self) {
40        let note_version = self.0.note_version;
41        self.redact_actions(|mut action| {
42            action.redact(|action| action.compact_resolvable_fields(note_version));
43        });
44    }
45
46    /// Redacts all actions in the same way.
47    pub fn redact_actions<F>(&mut self, f: F)
48    where
49        F: FnOnce(ActionRedactor<'_>),
50    {
51        f(ActionRedactor(Actions::All(&mut self.0.actions)));
52    }
53
54    /// Redacts the action at the given index.
55    ///
56    /// Does nothing if the index is out of range.
57    pub fn redact_action<F>(&mut self, index: usize, f: F)
58    where
59        F: FnOnce(ActionRedactor<'_>),
60    {
61        if let Some(action) = self.0.actions.get_mut(index) {
62            f(ActionRedactor(Actions::One(action)));
63        }
64    }
65
66    /// Removes the proof.
67    pub fn clear_zkproof(&mut self) {
68        self.0.zkproof = None;
69    }
70
71    /// Removes the proof.
72    pub fn clear_bsk(&mut self) {
73        self.0.bsk = None;
74    }
75
76    /// Removes the bundle anchor.
77    ///
78    /// Parsed roles require the real anchor, so a receiver must restore it before
79    /// parsing this bundle.
80    pub fn clear_anchor(&mut self) {
81        self.0.anchor = None;
82    }
83}
84
85/// A Redactor for Orchard actions.
86pub struct ActionRedactor<'a>(Actions<'a>);
87
88enum Actions<'a> {
89    All(&'a mut [Action]),
90    One(&'a mut Action),
91}
92
93impl ActionRedactor<'_> {
94    fn redact<F>(&mut self, f: F)
95    where
96        F: Fn(&mut Action),
97    {
98        match &mut self.0 {
99            Actions::All(actions) => {
100                for action in actions.iter_mut() {
101                    f(action);
102                }
103            }
104            Actions::One(action) => {
105                f(action);
106            }
107        }
108    }
109
110    /// Removes the action's net value commitment.
111    ///
112    /// The receiver recomputes `cv_net` from the spend and output values and `rcv`.
113    pub fn clear_cv_net(&mut self) {
114        self.redact(|action| {
115            action.cv_net = None;
116        });
117    }
118
119    /// Removes the output note commitment.
120    ///
121    /// The receiver recomputes `cmx` from the output note fields and the
122    /// action's spend nullifier.
123    pub fn clear_cmx(&mut self) {
124        self.redact(|action| {
125            action.output.cmx = None;
126        });
127    }
128
129    /// Removes the spend authorizing signature.
130    pub fn clear_spend_auth_sig(&mut self) {
131        self.redact(|action| {
132            action.spend.spend_auth_sig = None;
133        });
134    }
135
136    /// Removes the spend's recipient.
137    pub fn clear_spend_recipient(&mut self) {
138        self.redact(|action| {
139            action.spend.recipient = None;
140        });
141    }
142
143    /// Removes the spend's value.
144    pub fn clear_spend_value(&mut self) {
145        self.redact(|action| {
146            action.spend.value = None;
147        });
148    }
149
150    /// Removes the rho value for the note being spent.
151    pub fn clear_spend_rho(&mut self) {
152        self.redact(|action| {
153            action.spend.rho = None;
154        });
155    }
156
157    /// Removes the seed randomness for the note being spent.
158    pub fn clear_spend_rseed(&mut self) {
159        self.redact(|action| {
160            action.spend.rseed = None;
161        });
162    }
163
164    /// Removes the spend's full viewing key.
165    pub fn clear_spend_fvk(&mut self) {
166        self.redact(|action| {
167            action.spend.fvk = None;
168        });
169    }
170
171    /// Removes the witness from the spent note to the bundle's anchor.
172    pub fn clear_spend_witness(&mut self) {
173        self.redact(|action| {
174            action.spend.witness = None;
175        });
176    }
177
178    /// Removes the spend authorization randomizer.
179    pub fn clear_spend_alpha(&mut self) {
180        self.redact(|action| {
181            action.spend.alpha = None;
182        });
183    }
184
185    /// Removes the ZIP 32 derivation path at which the spending key can be found for the
186    /// note being spent.
187    pub fn clear_spend_zip32_derivation(&mut self) {
188        self.redact(|action| {
189            action.spend.zip32_derivation = None;
190        });
191    }
192
193    /// Removes the spending key for this spent note, if it is a dummy note.
194    pub fn clear_spend_dummy_sk(&mut self) {
195        self.redact(|action| {
196            action.spend.dummy_sk = None;
197        });
198    }
199
200    /// Redacts the spend-specific proprietary value at the given key.
201    pub fn redact_spend_proprietary(&mut self, key: &str) {
202        self.redact(|action| {
203            action.spend.proprietary.remove(key);
204        });
205    }
206
207    /// Removes all spend-specific proprietary values.
208    pub fn clear_spend_proprietary(&mut self) {
209        self.redact(|action| {
210            action.spend.proprietary.clear();
211        });
212    }
213
214    /// Replaces the output's encrypted note plaintext with a stripped memo
215    /// plaintext.
216    ///
217    /// The PCZT consumer can recompute
218    /// [`Output::enc_ciphertext`](crate::orchard::Output::enc_ciphertext) from
219    /// this memo, the output note fields, and the action's spend nullifier.
220    pub fn replace_enc_ciphertext_with_memo_plaintext(&mut self, memo: [u8; MEMO_SIZE]) {
221        self.redact(|action| {
222            action.output.enc_ciphertext =
223                EncCiphertext::MemoPlaintext(MemoPlaintext::from_memo(memo));
224        });
225    }
226
227    /// Replaces the output's encrypted note plaintext with its decrypted,
228    /// stripped memo plaintext, if decryption succeeds.
229    ///
230    /// Actions that already carry memo plaintext, lack required output note
231    /// fields, or fail decryption are left unchanged.
232    #[cfg(feature = "orchard")]
233    pub fn replace_enc_ciphertext_with_decrypted_memo_plaintext(
234        &mut self,
235        note_version: ::orchard::note::NoteVersion,
236    ) {
237        self.redact(|action| {
238            action.replace_enc_ciphertext_with_decrypted_memo_plaintext(note_version);
239        });
240    }
241
242    /// Removes the output's recipient.
243    pub fn clear_output_recipient(&mut self) {
244        self.redact(|action| {
245            action.output.recipient = None;
246        });
247    }
248
249    /// Removes the output's value.
250    pub fn clear_output_value(&mut self) {
251        self.redact(|action| {
252            action.output.value = None;
253        });
254    }
255
256    /// Removes the seed randomness for the note being created.
257    pub fn clear_output_rseed(&mut self) {
258        self.redact(|action| {
259            action.output.rseed = None;
260        });
261    }
262
263    /// Removes the `ock` value used to encrypt `out_ciphertext`.
264    pub fn clear_output_ock(&mut self) {
265        self.redact(|action| {
266            action.output.ock = None;
267        });
268    }
269
270    /// Removes the ZIP 32 derivation path at which the spending key can be found for the
271    /// note being created.
272    pub fn clear_output_zip32_derivation(&mut self) {
273        self.redact(|action| {
274            action.output.zip32_derivation = None;
275        });
276    }
277
278    /// Removes the user-facing address to which the output is being sent, if any.
279    pub fn clear_output_user_address(&mut self) {
280        self.redact(|spend| {
281            spend.output.user_address = None;
282        });
283    }
284
285    /// Redacts the output-specific proprietary value at the given key.
286    pub fn redact_output_proprietary(&mut self, key: &str) {
287        self.redact(|action| {
288            action.output.proprietary.remove(key);
289        });
290    }
291
292    /// Removes all output-specific proprietary values.
293    pub fn clear_output_proprietary(&mut self) {
294        self.redact(|action| {
295            action.output.proprietary.clear();
296        });
297    }
298
299    /// Removes the value commitment randomness.
300    pub fn clear_rcv(&mut self) {
301        self.redact(|action| {
302            action.rcv = None;
303        });
304    }
305}