Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 9 additions & 10 deletions src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -442,12 +442,12 @@ impl OutputInfo {
cv_net: &ValueCommitment,
nf_old: Nullifier,
rng: impl RngCore,
) -> crate::pczt::Output<D> {
let (note, cmx, encrypted_note) = self.build(cv_net, nf_old, rng);
) -> crate::pczt::Output {
let (note, cmx, encrypted_note) = self.build::<D>(cv_net, nf_old, rng);

crate::pczt::Output {
cmx,
encrypted_note,
encrypted_note: encrypted_note.into(),
recipient: Some(self.recipient),
value: Some(self.value),
rseed: Some(*note.rseed()),
Expand Down Expand Up @@ -532,10 +532,7 @@ impl ActionInfo {
)
}

fn build_for_pczt<D: OrchardDomainCommon>(
self,
mut rng: impl RngCore,
) -> crate::pczt::Action<D> {
fn build_for_pczt<D: OrchardDomainCommon>(self, mut rng: impl RngCore) -> crate::pczt::Action {
assert_eq!(
self.spend.note.asset(),
self.output.asset,
Expand All @@ -545,7 +542,9 @@ impl ActionInfo {
let cv_net = ValueCommitment::derive(v_net, self.rcv, self.spend.note.asset());

let spend = self.spend.into_pczt(&mut rng);
let output = self.output.into_pczt(&cv_net, spend.nullifier, &mut rng);
let output = self
.output
.into_pczt::<D>(&cv_net, spend.nullifier, &mut rng);

crate::pczt::Action {
cv_net,
Expand Down Expand Up @@ -778,7 +777,7 @@ impl Builder {
pub fn build_for_pczt<D: OrchardDomainCommon>(
self,
rng: impl RngCore,
) -> Result<(crate::pczt::Bundle<D>, BundleMetadata), BuildError> {
) -> Result<(crate::pczt::Bundle, BundleMetadata), BuildError> {
build_bundle(
rng,
self.anchor,
Expand All @@ -790,7 +789,7 @@ impl Builder {
// Create the actions.
let actions = pre_actions
.into_iter()
.map(|a| a.build_for_pczt(&mut rng))
.map(|a| a.build_for_pczt::<D>(&mut rng))
.collect::<Vec<_>>();

Ok((
Expand Down
6 changes: 6 additions & 0 deletions src/issuance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,12 @@ impl IssueAction {
/// Defines the authorization type of an Issue bundle.
pub trait IssueAuth: fmt::Debug + Clone {}

/// Marker type for a bundle that contains no authorizing data.
#[derive(Clone, Debug)]
pub struct EffectsOnly;

impl IssueAuth for EffectsOnly {}

/// Marker for an unsigned bundle with no nullifier and no sighash injected.
#[derive(Debug, Clone)]
pub struct AwaitingNullifier;
Expand Down
56 changes: 45 additions & 11 deletions src/pczt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use core::fmt;

use getset::Getters;
use pasta_curves::pallas;
use zcash_note_encryption_zsa::note_bytes::NoteBytes;
use zcash_note_encryption_zsa::OutgoingCipherKey;
use zip32::ChildIndex;

Expand Down Expand Up @@ -54,12 +55,12 @@ pub use tx_extractor::{TxExtractorError, Unbound};
/// [the regular `Bundle` struct]: crate::Bundle
#[derive(Debug, Getters)]
#[getset(get = "pub")]
pub struct Bundle<D: OrchardDomainCommon> {
pub struct Bundle {
/// The Orchard actions in this bundle.
///
/// Entries are added by the Constructor, and modified by an Updater, IO Finalizer,
/// Signer, Combiner, or Spend Finalizer.
pub(crate) actions: Vec<Action<D>>,
pub(crate) actions: Vec<Action>,

/// The flags for the Orchard bundle.
///
Expand Down Expand Up @@ -104,14 +105,14 @@ pub struct Bundle<D: OrchardDomainCommon> {
pub(crate) bsk: Option<redpallas::SigningKey<Binding>>,
}

impl<D: OrchardDomainCommon> Bundle<D> {
impl Bundle {
/// Returns a mutable reference to the actions in this bundle.
///
/// This is used by Signers to apply signatures with [`Action::sign`].
///
/// Note: updating the `Action`s via the returned slice will not update other
/// fields of the bundle dependent on them, such as `value_sum` and `bsk`.
pub fn actions_mut(&mut self) -> &mut [Action<D>] {
pub fn actions_mut(&mut self) -> &mut [Action] {
&mut self.actions
}
}
Expand All @@ -124,15 +125,15 @@ impl<D: OrchardDomainCommon> Bundle<D> {
/// [the regular `Action` struct]: crate::Action
#[derive(Debug, Getters)]
#[getset(get = "pub")]
pub struct Action<D: OrchardDomainCommon> {
pub struct Action {
/// A commitment to the net value created or consumed by this action.
pub(crate) cv_net: ValueCommitment,

/// The spend half of this action.
pub(crate) spend: Spend,

/// The output half of this action.
pub(crate) output: Output<D>,
pub(crate) output: Output,

/// The value commitment randomness.
///
Expand Down Expand Up @@ -248,7 +249,7 @@ pub struct Spend {
/// Information about an Orchard output within a transaction.
#[derive(Getters)]
#[getset(get = "pub")]
pub struct Output<D: OrchardDomainCommon> {
pub struct Output {
/// A commitment to the new note being created.
pub(crate) cmx: ExtractedNoteCommitment,

Expand All @@ -258,7 +259,7 @@ pub struct Output<D: OrchardDomainCommon> {
/// - `ephemeral_key`
/// - `enc_ciphertext`
/// - `out_ciphertext`
pub(crate) encrypted_note: TransmittedNoteCiphertext<D>,
pub(crate) encrypted_note: PcztTransmittedNoteCiphertext,

/// The address that will receive the output.
///
Expand Down Expand Up @@ -309,7 +310,7 @@ pub struct Output<D: OrchardDomainCommon> {
pub(crate) proprietary: BTreeMap<String, Vec<u8>>,
}

impl<D: OrchardDomainCommon> fmt::Debug for Output<D> {
impl fmt::Debug for Output {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Output")
.field("cmx", &self.cmx)
Expand Down Expand Up @@ -364,6 +365,39 @@ impl Zip32Derivation {
}
}

/// An encrypted note.
#[derive(Clone, Debug)]
pub struct PcztTransmittedNoteCiphertext {
/// The serialization of the ephemeral public key
pub epk_bytes: [u8; 32],
/// The encrypted note ciphertext
pub enc_ciphertext: Vec<u8>,
/// An encrypted value that allows the holder of the outgoing cipher
/// key for the note to recover the note plaintext.
pub out_ciphertext: [u8; 80],
}

impl<D: OrchardDomainCommon> From<TransmittedNoteCiphertext<D>> for PcztTransmittedNoteCiphertext {
fn from(transmitted: TransmittedNoteCiphertext<D>) -> Self {
PcztTransmittedNoteCiphertext {
epk_bytes: transmitted.epk_bytes,
enc_ciphertext: transmitted.enc_ciphertext.as_ref().to_vec(),
out_ciphertext: transmitted.out_ciphertext,
}
}
}

impl<D: OrchardDomainCommon> From<PcztTransmittedNoteCiphertext> for TransmittedNoteCiphertext<D> {
fn from(ciphertext: PcztTransmittedNoteCiphertext) -> Self {
TransmittedNoteCiphertext {
epk_bytes: ciphertext.epk_bytes,
enc_ciphertext: D::NoteCiphertextBytes::from_slice(&ciphertext.enc_ciphertext)
.expect("Failed to parse enc_ciphertext: data may be corrupt or incorrect size"),
out_ciphertext: ciphertext.out_ciphertext,
}
}
}

#[cfg(test)]
mod tests {
use crate::orchard_flavor::{OrchardFlavor, OrchardVanilla, OrchardZSA};
Expand Down Expand Up @@ -418,7 +452,7 @@ mod tests {
pczt_bundle.create_proof::<FL, _>(&pk, rng.clone()).unwrap();

// Run the Transaction Extractor role.
let bundle = pczt_bundle.extract::<i64>().unwrap().unwrap();
let bundle = pczt_bundle.extract::<i64, FL>().unwrap().unwrap();

let orchard_digest = hash_bundle_txid_data(&bundle);

Expand Down Expand Up @@ -574,7 +608,7 @@ mod tests {
}

// Run the Transaction Extractor role.
let bundle = pczt_bundle.extract::<i64>().unwrap().unwrap();
let bundle = pczt_bundle.extract::<i64, FL>().unwrap().unwrap();

let orchard_digest = hash_bundle_txid_data(&bundle);

Expand Down
6 changes: 3 additions & 3 deletions src/pczt/io_finalizer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ use rand::{CryptoRng, RngCore};

use super::SignerError;
use crate::{
bundle::derive_bvk_raw, domain::OrchardDomainCommon, keys::SpendAuthorizingKey,
primitives::redpallas, value::ValueCommitTrapdoor,
bundle::derive_bvk_raw, keys::SpendAuthorizingKey, primitives::redpallas,
value::ValueCommitTrapdoor,
};

impl<D: OrchardDomainCommon> super::Bundle<D> {
impl super::Bundle {
/// Finalizes the IO for this bundle.
pub fn finalize_io<R: RngCore + CryptoRng>(
&mut self,
Expand Down
24 changes: 10 additions & 14 deletions src/pczt/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,29 +5,26 @@ use alloc::vec::Vec;
use ff::PrimeField;
use incrementalmerkletree::Hashable;
use pasta_curves::pallas;
use zcash_note_encryption_zsa::{note_bytes::NoteBytes, OutgoingCipherKey};
use zcash_note_encryption_zsa::OutgoingCipherKey;
use zip32::ChildIndex;

use super::{Action, Bundle, Output, Spend, Zip32Derivation};
use super::{Action, Bundle, Output, PcztTransmittedNoteCiphertext, Spend, Zip32Derivation};
use crate::{
bundle::Flags,
domain::OrchardDomainCommon,
keys::{FullViewingKey, SpendingKey},
note::{
AssetBase, ExtractedNoteCommitment, Nullifier, RandomSeed, Rho, TransmittedNoteCiphertext,
},
note::{AssetBase, ExtractedNoteCommitment, Nullifier, RandomSeed, Rho},
primitives::redpallas::{self, SpendAuth},
tree::{MerkleHashOrchard, MerklePath},
value::{NoteValue, Sign, ValueCommitTrapdoor, ValueCommitment, ValueSum},
Address, Anchor, Proof, NOTE_COMMITMENT_TREE_DEPTH,
};

impl<D: OrchardDomainCommon> Bundle<D> {
impl Bundle {
/// Parses a PCZT bundle from its component parts.
/// `value_sum` is represented as `(magnitude, is_negative)`.
#[allow(clippy::too_many_arguments)]
pub fn parse(
actions: Vec<Action<D>>,
actions: Vec<Action>,
flags: u8,
value_sum: (u64, bool),
anchor: [u8; 32],
Expand Down Expand Up @@ -85,12 +82,12 @@ impl<D: OrchardDomainCommon> Bundle<D> {
}
}

impl<D: OrchardDomainCommon> Action<D> {
impl Action {
/// Parses a PCZT action from its component parts.
pub fn parse(
cv_net: [u8; 32],
spend: Spend,
output: Output<D>,
output: Output,
rcv: Option<[u8; 32]>,
) -> Result<Self, ParseError> {
let cv_net = ValueCommitment::from_bytes(&cv_net)
Expand Down Expand Up @@ -240,7 +237,7 @@ impl Spend {
}
}

impl<D: OrchardDomainCommon> Output<D> {
impl Output {
/// Parses a PCZT output from its component parts, and the corresponding `Spend`'s
/// nullifier.
#[allow(clippy::too_many_arguments)]
Expand All @@ -262,10 +259,9 @@ impl<D: OrchardDomainCommon> Output<D> {
.into_option()
.ok_or(ParseError::InvalidExtractedNoteCommitment)?;

let encrypted_note = TransmittedNoteCiphertext {
let encrypted_note = PcztTransmittedNoteCiphertext {
epk_bytes: ephemeral_key,
enc_ciphertext: D::NoteCiphertextBytes::from_slice(enc_ciphertext.as_slice())
.ok_or(ParseError::InvalidEncCiphertext)?,
enc_ciphertext: enc_ciphertext.to_vec(),
out_ciphertext: out_ciphertext
.as_slice()
.try_into()
Expand Down
3 changes: 1 addition & 2 deletions src/pczt/prover.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,12 @@ use rand::{CryptoRng, RngCore};
use crate::{
builder::SpendInfo,
circuit::{Circuit, Instance, ProvingKey, Witnesses},
domain::OrchardDomainCommon,
note::Rho,
orchard_flavor::OrchardFlavor,
Note, Proof,
};

impl<D: OrchardDomainCommon> super::Bundle<D> {
impl super::Bundle {
/// Adds a proof to this PCZT bundle.
pub fn create_proof<FL: OrchardFlavor, R: RngCore + CryptoRng>(
&mut self,
Expand Down
4 changes: 2 additions & 2 deletions src/pczt/signer.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use rand::{CryptoRng, RngCore};

use crate::{domain::OrchardDomainCommon, keys::SpendAuthorizingKey, primitives::redpallas};
use crate::{keys::SpendAuthorizingKey, primitives::redpallas};

impl<D: OrchardDomainCommon> super::Action<D> {
impl super::Action {
/// Signs the Orchard spend with the given spend authorizing key.
///
/// It is the caller's responsibility to perform any semantic validity checks on the
Expand Down
13 changes: 7 additions & 6 deletions src/pczt/tx_extractor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@ use crate::{
Proof,
};

impl<D: OrchardDomainCommon> super::Bundle<D> {
impl super::Bundle {
/// Extracts the effects of this PCZT bundle as a [regular `Bundle`].
///
/// This is used by the Signer role to produce the transaction sighash.
///
/// [regular `Bundle`]: crate::Bundle
pub fn extract_effects<V: TryFrom<i64>>(
pub fn extract_effects<V: TryFrom<i64>, D: OrchardDomainCommon>(
&self,
) -> Result<Option<crate::Bundle<EffectsOnly, V, D>>, TxExtractorError> {
self.to_tx_data(|_| Ok(()), |_| Ok(EffectsOnly))
Expand All @@ -26,7 +26,7 @@ impl<D: OrchardDomainCommon> super::Bundle<D> {
/// This is used by the Transaction Extractor role to produce the final transaction.
///
/// [regular `Bundle`]: crate::Bundle
pub fn extract<V: TryFrom<i64>>(
pub fn extract<V: TryFrom<i64>, D: OrchardDomainCommon>(
self,
) -> Result<Option<crate::Bundle<Unbound, V, D>>, TxExtractorError> {
self.to_tx_data(
Expand All @@ -52,17 +52,18 @@ impl<D: OrchardDomainCommon> super::Bundle<D> {
}

/// Converts this PCZT bundle into a regular bundle with the given authorizations.
fn to_tx_data<A, V, E, F, G>(
fn to_tx_data<A, V, E, F, G, D>(
&self,
action_auth: F,
bundle_auth: G,
) -> Result<Option<crate::Bundle<A, V, D>>, E>
where
A: Authorization,
E: From<TxExtractorError>,
F: Fn(&Action<D>) -> Result<<A as Authorization>::SpendAuth, E>,
F: Fn(&Action) -> Result<<A as Authorization>::SpendAuth, E>,
G: FnOnce(&Self) -> Result<A, E>,
V: TryFrom<i64>,
D: OrchardDomainCommon,
{
let actions = self
.actions
Expand All @@ -74,7 +75,7 @@ impl<D: OrchardDomainCommon> super::Bundle<D> {
action.spend.nullifier,
action.spend.rk.clone(),
action.output.cmx,
action.output.encrypted_note.clone(),
action.output.encrypted_note.clone().into(),
action.cv_net.clone(),
authorization,
))
Expand Down
Loading
Loading