zebra_chain/orchard/
action.rs

1use std::io;
2
3use halo2::pasta::pallas;
4use reddsa::orchard::SpendAuth;
5
6use crate::serialization::{
7    serde_helpers, ReadZcashExt, SerializationError, ZcashDeserialize, ZcashSerialize,
8};
9
10use super::{
11    commitment::{self, ValueCommitment},
12    keys,
13    note::{self, Nullifier},
14};
15
16/// An Action description, as described in the [Zcash specification §7.3][actiondesc].
17///
18/// Action transfers can optionally perform a spend, and optionally perform an
19/// output.  Action descriptions are data included in a transaction that
20/// describe Action transfers.
21///
22/// [actiondesc]: https://zips.z.cash/protocol/nu5.pdf#actiondesc
23#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
24pub struct Action {
25    /// A value commitment to net value of the input note minus the output note
26    pub cv: commitment::ValueCommitment,
27    /// The nullifier of the input note being spent.
28    pub nullifier: note::Nullifier,
29    /// The randomized validating key for spendAuthSig,
30    pub rk: reddsa::VerificationKeyBytes<SpendAuth>,
31    /// The x-coordinate of the note commitment for the output note.
32    #[serde(with = "serde_helpers::Base")]
33    pub cm_x: pallas::Base,
34    /// An encoding of an ephemeral Pallas public key corresponding to the
35    /// encrypted private key in `out_ciphertext`.
36    pub ephemeral_key: keys::EphemeralPublicKey,
37    /// A ciphertext component for the encrypted output note.
38    pub enc_ciphertext: note::EncryptedNote,
39    /// A ciphertext component that allows the holder of a full viewing key to
40    /// recover the recipient diversified transmission key and the ephemeral
41    /// private key (and therefore the entire note plaintext).
42    pub out_ciphertext: note::WrappedNoteKey,
43}
44
45impl ZcashSerialize for Action {
46    fn zcash_serialize<W: io::Write>(&self, mut writer: W) -> Result<(), io::Error> {
47        self.cv.zcash_serialize(&mut writer)?;
48        writer.write_all(&<[u8; 32]>::from(self.nullifier)[..])?;
49        writer.write_all(&<[u8; 32]>::from(self.rk)[..])?;
50        writer.write_all(&<[u8; 32]>::from(self.cm_x)[..])?;
51        self.ephemeral_key.zcash_serialize(&mut writer)?;
52        self.enc_ciphertext.zcash_serialize(&mut writer)?;
53        self.out_ciphertext.zcash_serialize(&mut writer)?;
54        Ok(())
55    }
56}
57
58impl ZcashDeserialize for Action {
59    fn zcash_deserialize<R: io::Read>(mut reader: R) -> Result<Self, SerializationError> {
60        // # Consensus
61        //
62        // > Elements of an Action description MUST be canonical encodings of the types given above.
63        //
64        // https://zips.z.cash/protocol/protocol.pdf#actiondesc
65        //
66        // > LEOS2IP_{256}(cmx) MUST be less than 𝑞_ℙ.
67        //
68        // https://zips.z.cash/protocol/protocol.pdf#actionencodingandconsensus
69        //
70        // See comments below for each specific type.
71        Ok(Action {
72            // Type is ValueCommit^{Orchard}.Output, i.e. ℙ.
73            // https://zips.z.cash/protocol/protocol.pdf#abstractcommit
74            // See [`ValueCommitment::zcash_deserialize`].
75            cv: ValueCommitment::zcash_deserialize(&mut reader)?,
76            // Type is `{0 .. 𝑞_ℙ − 1}`. See [`Nullifier::try_from`].
77            nullifier: Nullifier::try_from(reader.read_32_bytes()?)?,
78            // Type is SpendAuthSig^{Orchard}.Public, i.e. ℙ.
79            // https://zips.z.cash/protocol/protocol.pdf#concretespendauthsig
80            // https://zips.z.cash/protocol/protocol.pdf#concretereddsa
81            // This only reads the 32-byte buffer. The type is enforced
82            // on signature verification; see [`reddsa::batch`]
83            rk: reader.read_32_bytes()?.into(),
84            // Type is `{0 .. 𝑞_ℙ − 1}`. Note that the second rule quoted above
85            // is also enforced here and it is technically redundant with the first.
86            // See [`pallas::Base::zcash_deserialize`].
87            cm_x: pallas::Base::zcash_deserialize(&mut reader)?,
88            // Denoted by `epk` in the spec. Type is KA^{Orchard}.Public, i.e. ℙ^*.
89            // https://zips.z.cash/protocol/protocol.pdf#concreteorchardkeyagreement
90            // See [`keys::EphemeralPublicKey::zcash_deserialize`].
91            ephemeral_key: keys::EphemeralPublicKey::zcash_deserialize(&mut reader)?,
92            // Type is `Sym.C`, i.e. `𝔹^Y^{\[N\]}`, i.e. arbitrary-sized byte arrays
93            // https://zips.z.cash/protocol/protocol.pdf#concretesym but fixed to
94            // 580 bytes in https://zips.z.cash/protocol/protocol.pdf#outputencodingandconsensus
95            // See [`note::EncryptedNote::zcash_deserialize`].
96            enc_ciphertext: note::EncryptedNote::zcash_deserialize(&mut reader)?,
97            // Type is `Sym.C`, i.e. `𝔹^Y^{\[N\]}`, i.e. arbitrary-sized byte arrays
98            // https://zips.z.cash/protocol/protocol.pdf#concretesym but fixed to
99            // 80 bytes in https://zips.z.cash/protocol/protocol.pdf#outputencodingandconsensus
100            // See [`note::WrappedNoteKey::zcash_deserialize`].
101            out_ciphertext: note::WrappedNoteKey::zcash_deserialize(&mut reader)?,
102        })
103    }
104}