-
Notifications
You must be signed in to change notification settings - Fork 252
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
10 changed files
with
416 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,7 @@ | ||
pub mod creator; | ||
|
||
pub mod constructor; | ||
|
||
#[cfg(feature = "io-finalizer")] | ||
pub mod io_finalizer; | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
use crate::Pczt; | ||
|
||
#[cfg(feature = "orchard")] | ||
mod orchard; | ||
|
||
// #[cfg(feature = "sapling")] | ||
// mod sapling; | ||
|
||
#[cfg(feature = "transparent")] | ||
mod transparent; | ||
|
||
pub struct Constructor { | ||
pczt: Pczt, | ||
} | ||
|
||
impl Constructor { | ||
/// Instantiates the Constructor role with the given PCZT. | ||
pub fn new(pczt: Pczt) -> Self { | ||
Self { pczt } | ||
} | ||
|
||
/// Finishes the Constructor role, returning the updated PCZT. | ||
pub fn finish(self) -> Pczt { | ||
self.pczt | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
use std::collections::BTreeMap; | ||
|
||
use ff::{Field, PrimeField}; | ||
use orchard::{ | ||
keys::{EphemeralPublicKey, FullViewingKey, SpendValidatingKey}, | ||
note::ExtractedNoteCommitment, | ||
note_encryption::OrchardDomain, | ||
value::{ValueCommitTrapdoor, ValueCommitment}, | ||
}; | ||
use pasta_curves::pallas; | ||
use rand_core::OsRng; | ||
use zcash_note_encryption::Domain; | ||
|
||
impl super::Constructor { | ||
/// Adds an Orchard action to the PCZT. | ||
pub fn add_orchard_action( | ||
&mut self, | ||
spend_fvk: &FullViewingKey, | ||
spend_note: &orchard::Note, | ||
output_note: &orchard::Note, | ||
epk: &EphemeralPublicKey, | ||
enc_ciphertext: &[u8; 580], | ||
out_ciphertext: &[u8; 80], | ||
rcv: &ValueCommitTrapdoor, | ||
) -> Result<(), OrchardError> { | ||
let action_balance = spend_note.value() - output_note.value(); | ||
|
||
self.pczt.orchard.value_balance = self | ||
.pczt | ||
.orchard | ||
.value_balance | ||
.checked_add_signed( | ||
// TODO: This can throw an error for a technically legitimate action | ||
// balance. | ||
i64::try_from(action_balance).map_err(|_| OrchardError::BalanceViolation)?, | ||
) | ||
.ok_or(OrchardError::BalanceViolation)?; | ||
|
||
let cv = ValueCommitment::derive(action_balance, rcv.clone()); | ||
|
||
let alpha = pallas::Scalar::random(OsRng); | ||
let ak = SpendValidatingKey::from(spend_fvk.clone()); | ||
let rk = ak.randomize(&alpha); | ||
|
||
self.pczt.orchard.actions.push(crate::orchard::Action { | ||
cv: cv.to_bytes(), | ||
spend: crate::orchard::Spend { | ||
nullifier: spend_note.nullifier(spend_fvk).to_bytes(), | ||
rk: rk.into(), | ||
spend_auth_sig: None, | ||
recipient: Some(spend_note.recipient().to_raw_address_bytes()), | ||
value: Some(spend_note.value().inner()), | ||
rho: Some(spend_note.rho().to_bytes()), | ||
rseed: Some(*spend_note.rseed().as_bytes()), | ||
// TODO: Documented as being set by the Updater, but the Constructor needs | ||
// it to derive rk. | ||
fvk: Some(spend_fvk.to_bytes()), | ||
witness: None, | ||
alpha: Some(alpha.to_repr()), | ||
zip32_derivation: None, | ||
proprietary: BTreeMap::new(), | ||
}, | ||
output: crate::orchard::Output { | ||
cmx: ExtractedNoteCommitment::from(output_note.commitment()).to_bytes(), | ||
ephemeral_key: OrchardDomain::epk_bytes(&epk).0, | ||
enc_ciphertext: enc_ciphertext.to_vec(), | ||
out_ciphertext: out_ciphertext.to_vec(), | ||
recipient: Some(output_note.recipient().to_raw_address_bytes()), | ||
value: Some(output_note.value().inner()), | ||
rseed: Some(*output_note.rseed().as_bytes()), | ||
shared_secret: None, | ||
ock: None, | ||
zip32_derivation: None, | ||
proprietary: BTreeMap::new(), | ||
}, | ||
rcv: Some(rcv.to_bytes()), | ||
}); | ||
|
||
Ok(()) | ||
} | ||
} | ||
|
||
/// Errors that can occur while adding Orchard actions to a PCZT. | ||
#[derive(Debug)] | ||
pub enum OrchardError { | ||
BalanceViolation, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
use std::collections::BTreeMap; | ||
|
||
use ff::Field; | ||
use rand_core::OsRng; | ||
use sapling::{ | ||
keys::{EphemeralPublicKey, FullViewingKey}, | ||
note_encryption::SaplingDomain, | ||
value::{ValueCommitTrapdoor, ValueCommitment}, | ||
Note, | ||
}; | ||
use zcash_note_encryption::Domain; | ||
|
||
impl super::Constructor { | ||
/// Adds a Sapling note to be spent in this transaction. | ||
pub fn add_sapling_spend( | ||
&mut self, | ||
fvk: &FullViewingKey, | ||
note: &Note, | ||
position: u64, | ||
rcv: &ValueCommitTrapdoor, | ||
) -> Result<(), SaplingError> { | ||
self.pczt.sapling.value_balance = self | ||
.pczt | ||
.sapling | ||
.value_balance | ||
.checked_add(note.value().inner()) | ||
.ok_or(SaplingError::BalanceViolation)?; | ||
|
||
let cv = ValueCommitment::derive(note.value(), rcv.clone()); | ||
|
||
let alpha = jubjub::Scalar::random(OsRng); | ||
let rk = fvk.vk.ak.randomize(&alpha); | ||
|
||
self.pczt.sapling.spends.push(crate::sapling::Spend { | ||
cv: cv.to_bytes(), | ||
nullifier: note.nf(&fvk.vk.nk, position).0, | ||
rk: rk.into(), | ||
zkproof: None, | ||
spend_auth_sig: None, | ||
recipient: Some(note.recipient().to_bytes()), | ||
value: Some(note.value().inner()), | ||
rseed: Some(note.rseed()), | ||
rcv: Some(rcv.inner().to_bytes()), | ||
proof_generation_key: None, | ||
witness: None, | ||
alpha: Some(alpha.to_bytes()), | ||
zip32_derivation: None, | ||
proprietary: BTreeMap::new(), | ||
}); | ||
Ok(()) | ||
} | ||
|
||
/// Adds a Sapling address to send funds to. | ||
pub fn add_sapling_output( | ||
&mut self, | ||
note: &Note, | ||
epk: &EphemeralPublicKey, | ||
enc_ciphertext: &[u8; 580], | ||
out_ciphertext: &[u8; 80], | ||
rcv: &ValueCommitTrapdoor, | ||
) -> Result<(), SaplingError> { | ||
self.pczt.sapling.value_balance = self | ||
.pczt | ||
.sapling | ||
.value_balance | ||
.checked_sub(note.value().inner()) | ||
.ok_or(SaplingError::BalanceViolation)?; | ||
|
||
let cv = ValueCommitment::derive(note.value(), rcv.clone()); | ||
|
||
self.pczt.sapling.outputs.push(crate::sapling::Output { | ||
cv: cv.to_bytes(), | ||
cmu: note.cmu().to_bytes(), | ||
ephemeral_key: SaplingDomain::epk_bytes(epk).0, | ||
enc_ciphertext: enc_ciphertext.to_vec(), | ||
out_ciphertext: out_ciphertext.to_vec(), | ||
zkproof: None, | ||
recipient: Some(note.recipient().to_bytes()), | ||
value: Some(note.value().inner()), | ||
rseed: Some(note.rseed()), | ||
rcv: Some(rcv.inner().to_bytes()), | ||
shared_secret: None, | ||
ock: None, | ||
zip32_derivation: None, | ||
proprietary: BTreeMap::new(), | ||
}); | ||
|
||
Ok(()) | ||
} | ||
} | ||
|
||
/// Errors that can occur while adding Sapling spends or outputs to a PCZT. | ||
#[derive(Debug)] | ||
pub enum SaplingError { | ||
BalanceViolation, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
use std::collections::BTreeMap; | ||
|
||
use zcash_primitives::{ | ||
legacy::TransparentAddress, | ||
transaction::components::{transparent, TxOut}, | ||
}; | ||
use zcash_protocol::value::Zatoshis; | ||
|
||
impl super::Constructor { | ||
/// Adds a transparent coin to be spent in this transaction. | ||
pub fn add_transparent_input( | ||
&mut self, | ||
utxo: transparent::OutPoint, | ||
coin: TxOut, | ||
sequence: u32, | ||
required_locktime: u32, | ||
sighash_type: u32, | ||
) { | ||
self.pczt | ||
.transparent | ||
.inputs | ||
.push(crate::transparent::Input { | ||
prevout_txid: *utxo.hash(), | ||
prevout_index: utxo.n(), | ||
sequence, | ||
required_locktime, | ||
script_sig: None, | ||
value: coin.value.into_u64(), | ||
script_pubkey: coin.script_pubkey.0, | ||
redeem_script: None, | ||
partial_signatures: BTreeMap::new(), | ||
sighash_type, | ||
bip32_derivation: BTreeMap::new(), | ||
ripemd160_preimages: BTreeMap::new(), | ||
sha256_preimages: BTreeMap::new(), | ||
hash160_preimages: BTreeMap::new(), | ||
hash256_preimages: BTreeMap::new(), | ||
proprietary: BTreeMap::new(), | ||
}); | ||
} | ||
|
||
/// Adds a transparent address to send funds to. | ||
pub fn add_transparent_output(&mut self, to: &TransparentAddress, value: Zatoshis) { | ||
self.pczt | ||
.transparent | ||
.outputs | ||
.push(crate::transparent::Output { | ||
value: value.into_u64(), | ||
script_pubkey: to.script().0, | ||
redeem_script: None, | ||
bip32_derivation: BTreeMap::new(), | ||
proprietary: BTreeMap::new(), | ||
}); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.