use std::io;
use derive_getters::Getters;
use crate::{
block::MAX_BLOCK_BYTES,
primitives::Groth16Proof,
serialization::{
serde_helpers, SerializationError, TrustedPreallocate, ZcashDeserialize, ZcashSerialize,
},
};
use super::{commitment, keys, note};
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Getters)]
pub struct Output {
pub cv: commitment::ValueCommitment,
#[serde(with = "serde_helpers::SaplingExtractedNoteCommitment")]
pub cm_u: sapling_crypto::note::ExtractedNoteCommitment,
pub ephemeral_key: keys::EphemeralPublicKey,
pub enc_ciphertext: note::EncryptedNote,
pub out_ciphertext: note::WrappedNoteKey,
pub zkproof: Groth16Proof,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct OutputInTransactionV4(pub Output);
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
pub struct OutputPrefixInTransactionV5 {
pub cv: commitment::ValueCommitment,
#[serde(with = "serde_helpers::SaplingExtractedNoteCommitment")]
pub cm_u: sapling_crypto::note::ExtractedNoteCommitment,
pub ephemeral_key: keys::EphemeralPublicKey,
pub enc_ciphertext: note::EncryptedNote,
pub out_ciphertext: note::WrappedNoteKey,
}
impl Output {
pub fn from_v4(output: OutputInTransactionV4) -> Output {
output.0
}
pub fn into_v4(self) -> OutputInTransactionV4 {
OutputInTransactionV4(self)
}
pub fn from_v5_parts(prefix: OutputPrefixInTransactionV5, zkproof: Groth16Proof) -> Output {
Output {
cv: prefix.cv,
cm_u: prefix.cm_u,
ephemeral_key: prefix.ephemeral_key,
enc_ciphertext: prefix.enc_ciphertext,
out_ciphertext: prefix.out_ciphertext,
zkproof,
}
}
pub fn into_v5_parts(self) -> (OutputPrefixInTransactionV5, Groth16Proof) {
let prefix = OutputPrefixInTransactionV5 {
cv: self.cv,
cm_u: self.cm_u,
ephemeral_key: self.ephemeral_key,
enc_ciphertext: self.enc_ciphertext,
out_ciphertext: self.out_ciphertext,
};
(prefix, self.zkproof)
}
}
impl OutputInTransactionV4 {
pub fn from_output(output: Output) -> OutputInTransactionV4 {
OutputInTransactionV4(output)
}
pub fn into_output(self) -> Output {
self.0
}
}
impl ZcashSerialize for OutputInTransactionV4 {
fn zcash_serialize<W: io::Write>(&self, mut writer: W) -> Result<(), io::Error> {
let output = self.0.clone();
writer.write_all(&output.cv.0.to_bytes())?;
writer.write_all(&output.cm_u.to_bytes())?;
output.ephemeral_key.zcash_serialize(&mut writer)?;
output.enc_ciphertext.zcash_serialize(&mut writer)?;
output.out_ciphertext.zcash_serialize(&mut writer)?;
output.zkproof.zcash_serialize(&mut writer)?;
Ok(())
}
}
impl ZcashDeserialize for OutputInTransactionV4 {
fn zcash_deserialize<R: io::Read>(mut reader: R) -> Result<Self, SerializationError> {
Ok(OutputInTransactionV4(Output {
cv: commitment::ValueCommitment(
sapling_crypto::value::ValueCommitment::zcash_deserialize(&mut reader)?,
),
cm_u: sapling_crypto::note::ExtractedNoteCommitment::zcash_deserialize(&mut reader)?,
ephemeral_key: keys::EphemeralPublicKey::zcash_deserialize(&mut reader)?,
enc_ciphertext: note::EncryptedNote::zcash_deserialize(&mut reader)?,
out_ciphertext: note::WrappedNoteKey::zcash_deserialize(&mut reader)?,
zkproof: Groth16Proof::zcash_deserialize(&mut reader)?,
}))
}
}
impl ZcashSerialize for OutputPrefixInTransactionV5 {
fn zcash_serialize<W: io::Write>(&self, mut writer: W) -> Result<(), io::Error> {
writer.write_all(&self.cv.0.to_bytes())?;
writer.write_all(&self.cm_u.to_bytes())?;
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 OutputPrefixInTransactionV5 {
fn zcash_deserialize<R: io::Read>(mut reader: R) -> Result<Self, SerializationError> {
Ok(OutputPrefixInTransactionV5 {
cv: commitment::ValueCommitment(
sapling_crypto::value::ValueCommitment::zcash_deserialize(&mut reader)?,
),
cm_u: sapling_crypto::note::ExtractedNoteCommitment::zcash_deserialize(&mut reader)?,
ephemeral_key: keys::EphemeralPublicKey::zcash_deserialize(&mut reader)?,
enc_ciphertext: note::EncryptedNote::zcash_deserialize(&mut reader)?,
out_ciphertext: note::WrappedNoteKey::zcash_deserialize(&mut reader)?,
})
}
}
pub(crate) const OUTPUT_PREFIX_SIZE: u64 = 32 + 32 + 32 + 580 + 80;
pub(crate) const OUTPUT_SIZE: u64 = OUTPUT_PREFIX_SIZE + 192;
impl TrustedPreallocate for OutputInTransactionV4 {
fn max_allocation() -> u64 {
const MAX: u64 = (MAX_BLOCK_BYTES - 1) / OUTPUT_SIZE;
static_assertions::const_assert!(MAX < (1 << 16));
MAX
}
}
impl TrustedPreallocate for OutputPrefixInTransactionV5 {
fn max_allocation() -> u64 {
OutputInTransactionV4::max_allocation()
}
}