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
use std::io;
use halo2::pasta::pallas;
use reddsa::orchard::SpendAuth;
use crate::serialization::{
serde_helpers, ReadZcashExt, SerializationError, ZcashDeserialize, ZcashSerialize,
};
use super::{
commitment::{self, ValueCommitment},
keys,
note::{self, Nullifier},
};
/// An Action description, as described in the [Zcash specification ยง7.3][actiondesc].
///
/// Action transfers can optionally perform a spend, and optionally perform an
/// output. Action descriptions are data included in a transaction that
/// describe Action transfers.
///
/// [actiondesc]: https://zips.z.cash/protocol/nu5.pdf#actiondesc
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct Action {
/// A value commitment to net value of the input note minus the output note
pub cv: commitment::ValueCommitment,
/// The nullifier of the input note being spent.
pub nullifier: note::Nullifier,
/// The randomized validating key for spendAuthSig,
pub rk: reddsa::VerificationKeyBytes<SpendAuth>,
/// The x-coordinate of the note commitment for the output note.
#[serde(with = "serde_helpers::Base")]
pub cm_x: pallas::Base,
/// An encoding of an ephemeral Pallas public key corresponding to the
/// encrypted private key in `out_ciphertext`.
pub ephemeral_key: keys::EphemeralPublicKey,
/// A ciphertext component for the encrypted output note.
pub enc_ciphertext: note::EncryptedNote,
/// A ciphertext component that allows the holder of a full viewing key to
/// recover the recipient diversified transmission key and the ephemeral
/// private key (and therefore the entire note plaintext).
pub out_ciphertext: note::WrappedNoteKey,
}
impl ZcashSerialize for Action {
fn zcash_serialize<W: io::Write>(&self, mut writer: W) -> Result<(), io::Error> {
self.cv.zcash_serialize(&mut writer)?;
writer.write_all(&<[u8; 32]>::from(self.nullifier)[..])?;
writer.write_all(&<[u8; 32]>::from(self.rk)[..])?;
writer.write_all(&<[u8; 32]>::from(self.cm_x)[..])?;
self.ephemeral_key.zcash_serialize(&mut writer)?;
self.enc_ciphertext.zcash_serialize(&mut writer)?;
self.out_ciphertext.zcash_serialize(&mut writer)?;
Ok(())
}
}
impl ZcashDeserialize for Action {
fn zcash_deserialize<R: io::Read>(mut reader: R) -> Result<Self, SerializationError> {
// # Consensus
//
// > Elements of an Action description MUST be canonical encodings of the types given above.
//
// https://zips.z.cash/protocol/protocol.pdf#actiondesc
//
// > LEOS2IP_{256}(cmx) MUST be less than ๐_โ.
//
// https://zips.z.cash/protocol/protocol.pdf#actionencodingandconsensus
//
// See comments below for each specific type.
Ok(Action {
// Type is ValueCommit^{Orchard}.Output, i.e. โ.
// https://zips.z.cash/protocol/protocol.pdf#abstractcommit
// See [`ValueCommitment::zcash_deserialize`].
cv: ValueCommitment::zcash_deserialize(&mut reader)?,
// Type is `{0 .. ๐_โ โ 1}`. See [`Nullifier::try_from`].
nullifier: Nullifier::try_from(reader.read_32_bytes()?)?,
// Type is SpendAuthSig^{Orchard}.Public, i.e. โ.
// https://zips.z.cash/protocol/protocol.pdf#concretespendauthsig
// https://zips.z.cash/protocol/protocol.pdf#concretereddsa
// This only reads the 32-byte buffer. The type is enforced
// on signature verification; see [`reddsa::batch`]
rk: reader.read_32_bytes()?.into(),
// Type is `{0 .. ๐_โ โ 1}`. Note that the second rule quoted above
// is also enforced here and it is technically redundant with the first.
// See [`pallas::Base::zcash_deserialize`].
cm_x: pallas::Base::zcash_deserialize(&mut reader)?,
// Denoted by `epk` in the spec. Type is KA^{Orchard}.Public, i.e. โ^*.
// https://zips.z.cash/protocol/protocol.pdf#concreteorchardkeyagreement
// See [`keys::EphemeralPublicKey::zcash_deserialize`].
ephemeral_key: keys::EphemeralPublicKey::zcash_deserialize(&mut reader)?,
// Type is `Sym.C`, i.e. `๐น^Y^{\[N\]}`, i.e. arbitrary-sized byte arrays
// https://zips.z.cash/protocol/protocol.pdf#concretesym but fixed to
// 580 bytes in https://zips.z.cash/protocol/protocol.pdf#outputencodingandconsensus
// See [`note::EncryptedNote::zcash_deserialize`].
enc_ciphertext: note::EncryptedNote::zcash_deserialize(&mut reader)?,
// Type is `Sym.C`, i.e. `๐น^Y^{\[N\]}`, i.e. arbitrary-sized byte arrays
// https://zips.z.cash/protocol/protocol.pdf#concretesym but fixed to
// 80 bytes in https://zips.z.cash/protocol/protocol.pdf#outputencodingandconsensus
// See [`note::WrappedNoteKey::zcash_deserialize`].
out_ciphertext: note::WrappedNoteKey::zcash_deserialize(&mut reader)?,
})
}
}