sapling_crypto/
pczt.rs

1//! PCZT support for Sapling.
2
3use alloc::collections::BTreeMap;
4use alloc::string::String;
5use alloc::vec::Vec;
6use core::fmt;
7
8use getset::Getters;
9use redjubjub::{Binding, SpendAuth};
10use zcash_note_encryption::{
11    EphemeralKeyBytes, OutgoingCipherKey, ENC_CIPHERTEXT_SIZE, OUT_CIPHERTEXT_SIZE,
12};
13use zip32::ChildIndex;
14
15use crate::{
16    bundle::GrothProofBytes,
17    keys::SpendAuthorizingKey,
18    note::ExtractedNoteCommitment,
19    value::{NoteValue, ValueCommitTrapdoor, ValueCommitment, ValueSum},
20    Anchor, MerklePath, Nullifier, PaymentAddress, ProofGenerationKey, Rseed,
21};
22
23mod parse;
24pub use parse::ParseError;
25
26mod verify;
27pub use verify::VerifyError;
28
29mod io_finalizer;
30pub use io_finalizer::IoFinalizerError;
31
32mod updater;
33pub use updater::{OutputUpdater, SpendUpdater, Updater, UpdaterError};
34
35#[cfg(feature = "circuit")]
36mod prover;
37#[cfg(feature = "circuit")]
38pub use prover::ProverError;
39
40mod signer;
41pub use signer::SignerError;
42
43mod tx_extractor;
44pub use tx_extractor::{TxExtractorError, Unbound};
45
46/// PCZT fields that are specific to producing the transaction's Sapling bundle (if any).
47///
48/// This struct is for representing Sapling in a partially-created transaction. If you
49/// have a fully-created transaction, use [the regular `Bundle` struct].
50///
51/// [the regular `Bundle` struct]: crate::Bundle
52#[derive(Debug, Getters)]
53#[getset(get = "pub")]
54pub struct Bundle {
55    /// The Sapling spends in this bundle.
56    ///
57    /// Entries are added by the Constructor, and modified by an Updater, IO Finalizer,
58    /// Prover, Signer, Combiner, or Spend Finalizer.
59    pub(crate) spends: Vec<Spend>,
60
61    /// The Sapling outputs in this bundle.
62    ///
63    /// Entries are added by the Constructor, and modified by an Updater, IO Finalizer,
64    /// Prover, Signer, Combiner, or Spend Finalizer.
65    pub(crate) outputs: Vec<Output>,
66
67    /// The net value of Sapling `spends` minus `outputs`.
68    ///
69    /// This is initialized by the Creator, and updated by the Constructor as spends or
70    /// outputs are added to the PCZT. It enables per-spend and per-output values to be
71    /// redacted from the PCZT after they are no longer necessary.
72    pub(crate) value_sum: ValueSum,
73
74    /// The Sapling anchor for this transaction.
75    ///
76    /// Set by the Creator.
77    pub(crate) anchor: Anchor,
78
79    /// The Sapling binding signature signing key.
80    ///
81    /// - This is `None` until it is set by the IO Finalizer.
82    /// - The Transaction Extractor uses this to produce the binding signature.
83    pub(crate) bsk: Option<redjubjub::SigningKey<Binding>>,
84}
85
86impl Bundle {
87    /// Returns a mutable reference to the spends in this bundle.
88    ///
89    /// This is used by Signers to apply signatures with [`Spend::sign`].
90    pub fn spends_mut(&mut self) -> &mut [Spend] {
91        &mut self.spends
92    }
93}
94
95/// Information about a Sapling spend within a transaction.
96///
97/// This struct is for representing Sapling spends in a partially-created transaction. If
98/// you have a fully-created transaction, use [the regular `SpendDescription` struct].
99///
100/// [the regular `SpendDescription` struct]: crate::bundle::SpendDescription
101#[derive(Debug, Getters)]
102#[getset(get = "pub")]
103pub struct Spend {
104    /// A commitment to the value consumed by this spend.
105    pub(crate) cv: ValueCommitment,
106
107    /// The nullifier of the note being spent.
108    pub(crate) nullifier: Nullifier,
109
110    /// The randomized verification key for the note being spent.
111    pub(crate) rk: redjubjub::VerificationKey<SpendAuth>,
112
113    /// The Spend proof.
114    ///
115    /// This is set by the Prover.
116    pub(crate) zkproof: Option<GrothProofBytes>,
117
118    /// The spend authorization signature.
119    ///
120    /// This is set by the Signer.
121    pub(crate) spend_auth_sig: Option<redjubjub::Signature<SpendAuth>>,
122
123    /// The address that received the note being spent.
124    ///
125    /// - This is set by the Constructor (or Updater?).
126    /// - This is required by the Prover.
127    pub(crate) recipient: Option<PaymentAddress>,
128
129    /// The value of the input being spent.
130    ///
131    /// This may be used by Signers to verify that the value matches `cv`, and to confirm
132    /// the values and change involved in the transaction.
133    ///
134    /// This exposes the input value to all participants. For Signers who don't need this
135    /// information, or after signatures have been applied, this can be redacted.
136    pub(crate) value: Option<NoteValue>,
137
138    /// The seed randomness for the note being spent.
139    ///
140    /// - This is set by the Constructor.
141    /// - This is required by the Prover.
142    pub(crate) rseed: Option<Rseed>,
143
144    /// The value commitment randomness.
145    ///
146    /// - This is set by the Constructor.
147    /// - The IO Finalizer compresses it into the `bsk`.
148    /// - This is required by the Prover.
149    /// - This may be used by Signers to verify that the value correctly matches `cv`.
150    ///
151    /// This opens `cv` for all participants. For Signers who don't need this information,
152    /// or after proofs / signatures have been applied, this can be redacted.
153    pub(crate) rcv: Option<ValueCommitTrapdoor>,
154
155    /// The proof generation key `(ak, nsk)` corresponding to the recipient that received
156    /// the note being spent.
157    ///
158    /// - This is set by the Updater.
159    /// - This is required by the Prover.
160    pub(crate) proof_generation_key: Option<ProofGenerationKey>,
161
162    /// A witness from the note to the bundle's anchor.
163    ///
164    /// - This is set by the Updater.
165    /// - This is required by the Prover.
166    pub(crate) witness: Option<MerklePath>,
167
168    /// The spend authorization randomizer.
169    ///
170    /// - This is chosen by the Constructor.
171    /// - This is required by the Signer for creating `spend_auth_sig`, and may be used to
172    ///   validate `rk`.
173    /// - After`zkproof` / `spend_auth_sig` has been set, this can be redacted.
174    pub(crate) alpha: Option<jubjub::Scalar>,
175
176    /// The ZIP 32 derivation path at which the spending key can be found for the note
177    /// being spent.
178    pub(crate) zip32_derivation: Option<Zip32Derivation>,
179
180    /// The spend authorizing key for this spent note, if it is a dummy note.
181    ///
182    /// - This is chosen by the Constructor.
183    /// - This is required by the IO Finalizer, and is cleared by it once used.
184    /// - Signers MUST reject PCZTs that contain `dummy_ask` values.
185    pub(crate) dummy_ask: Option<SpendAuthorizingKey>,
186
187    /// Proprietary fields related to the note being spent.
188    pub(crate) proprietary: BTreeMap<String, Vec<u8>>,
189}
190
191/// Information about a Sapling output within a transaction.
192///
193/// This struct is for representing Sapling outputs in a partially-created transaction. If
194/// you have a fully-created transaction, use [the regular `OutputDescription` struct].
195///
196/// [the regular `OutputDescription` struct]: crate::bundle::OutputDescription
197#[derive(Getters)]
198#[getset(get = "pub")]
199pub struct Output {
200    /// A commitment to the value created by this output.
201    pub(crate) cv: ValueCommitment,
202
203    /// A commitment to the new note being created.
204    pub(crate) cmu: ExtractedNoteCommitment,
205
206    /// The ephemeral key used to encrypt the note plaintext.
207    pub(crate) ephemeral_key: EphemeralKeyBytes,
208
209    /// The encrypted note plaintext for the output.
210    ///
211    /// Once we have memo bundles, we will be able to set memos independently of Outputs.
212    /// For now, the Constructor sets both at the same time.
213    pub(crate) enc_ciphertext: [u8; ENC_CIPHERTEXT_SIZE],
214
215    /// The encrypted output plaintext for the output.
216    pub(crate) out_ciphertext: [u8; OUT_CIPHERTEXT_SIZE],
217
218    /// The Output proof.
219    ///
220    /// This is set by the Prover.
221    pub(crate) zkproof: Option<GrothProofBytes>,
222
223    /// The address that will receive the output.
224    ///
225    /// - This is set by the Constructor.
226    /// - This is required by the Prover.
227    /// - The Signer can use `recipient` and `rseed` (if present) to verify that
228    ///   `enc_ciphertext` is correctly encrypted (and contains a note plaintext matching
229    ///   the public commitments), and to confirm the value of the memo.
230    pub(crate) recipient: Option<PaymentAddress>,
231
232    /// The value of the output.
233    ///
234    /// This may be used by Signers to verify that the value matches `cv`, and to confirm
235    /// the values and change involved in the transaction.
236    ///
237    /// This exposes the output value to all participants. For Signers who don't need this
238    /// information, or after signatures have been applied, this can be redacted.
239    pub(crate) value: Option<NoteValue>,
240
241    /// The seed randomness for the output.
242    ///
243    /// - This is set by the Constructor.
244    /// - This is required by the Prover.
245    /// - The Signer can use `recipient` and `rseed` (if present) to verify that
246    ///   `enc_ciphertext` is correctly encrypted (and contains a note plaintext matching
247    ///   the public commitments), and to confirm the value of the memo.
248    pub(crate) rseed: Option<[u8; 32]>,
249
250    /// The value commitment randomness.
251    ///
252    /// - This is set by the Constructor.
253    /// - The IO Finalizer compresses it into the bsk.
254    /// - This is required by the Prover.
255    /// - This may be used by Signers to verify that the value correctly matches `cv`.
256    ///
257    /// This opens `cv` for all participants. For Signers who don't need this information,
258    /// or after proofs / signatures have been applied, this can be redacted.
259    pub(crate) rcv: Option<ValueCommitTrapdoor>,
260
261    /// The `ock` value used to encrypt `out_ciphertext`.
262    ///
263    /// This enables Signers to verify that `out_ciphertext` is correctly encrypted.
264    ///
265    /// This may be `None` if the Constructor added the output using an OVK policy of
266    /// "None", to make the output unrecoverable from the chain by the sender.
267    pub(crate) ock: Option<OutgoingCipherKey>,
268
269    /// The ZIP 32 derivation path at which the spending key can be found for the output.
270    pub(crate) zip32_derivation: Option<Zip32Derivation>,
271
272    /// The user-facing address to which this output is being sent, if any.
273    ///
274    /// - This is set by an Updater.
275    /// - Signers must parse this address (if present) and confirm that it contains
276    ///   `recipient` (either directly, or e.g. as a receiver within a Unified Address).
277    pub(crate) user_address: Option<String>,
278
279    /// Proprietary fields related to the note being created.
280    pub(crate) proprietary: BTreeMap<String, Vec<u8>>,
281}
282
283impl fmt::Debug for Output {
284    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
285        f.debug_struct("Output")
286            .field("cv", &self.cv)
287            .field("cmu", &self.cmu)
288            .field("ephemeral_key", &self.ephemeral_key)
289            .field("enc_ciphertext", &self.enc_ciphertext)
290            .field("out_ciphertext", &self.out_ciphertext)
291            .field("zkproof", &self.zkproof)
292            .field("recipient", &self.recipient)
293            .field("value", &self.value)
294            .field("rseed", &self.rseed)
295            .field("rcv", &self.rcv)
296            .field("zip32_derivation", &self.zip32_derivation)
297            .field("user_address", &self.user_address)
298            .field("proprietary", &self.proprietary)
299            .finish_non_exhaustive()
300    }
301}
302
303/// The ZIP 32 derivation path at which a key can be found.
304#[derive(Debug, Getters, PartialEq, Eq)]
305#[getset(get = "pub")]
306pub struct Zip32Derivation {
307    /// The [ZIP 32 seed fingerprint](https://zips.z.cash/zip-0032#seed-fingerprints).
308    seed_fingerprint: [u8; 32],
309
310    /// The sequence of indices corresponding to the shielded HD path.
311    derivation_path: Vec<ChildIndex>,
312}
313
314impl Zip32Derivation {
315    /// Extracts the ZIP 32 account index from this derivation path.
316    ///
317    /// Returns `None` if the seed fingerprints don't match, or if this is a non-standard
318    /// derivation path.
319    pub fn extract_account_index(
320        &self,
321        seed_fp: &zip32::fingerprint::SeedFingerprint,
322        expected_coin_type: zip32::ChildIndex,
323    ) -> Option<zip32::AccountId> {
324        if self.seed_fingerprint == seed_fp.to_bytes() {
325            match &self.derivation_path[..] {
326                [purpose, coin_type, account_index]
327                    if purpose == &zip32::ChildIndex::hardened(32)
328                        && coin_type == &expected_coin_type =>
329                {
330                    Some(
331                        zip32::AccountId::try_from(account_index.index() - (1 << 31))
332                            .expect("zip32::ChildIndex only supports hardened"),
333                    )
334                }
335                _ => None,
336            }
337        } else {
338            None
339        }
340    }
341}