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