From 5a1665df3c54bfe3301a37dfcd92d44be0c86593 Mon Sep 17 00:00:00 2001 From: Song Xuyang Date: Wed, 20 Sep 2023 20:55:28 +0800 Subject: [PATCH] move the binding_sig_r into ptx --- .../cascaded_partial_transactions.rs | 9 +- .../partial_fulfillment_token_swap.rs | 22 +- taiga_halo2/examples/tx_examples/token.rs | 2 +- .../tx_examples/token_swap_with_intent.rs | 22 +- .../tx_examples/token_swap_without_intent.rs | 16 +- taiga_halo2/src/shielded_ptx.rs | 39 ++- taiga_halo2/src/transaction.rs | 287 +++++++----------- 7 files changed, 163 insertions(+), 234 deletions(-) diff --git a/taiga_halo2/examples/tx_examples/cascaded_partial_transactions.rs b/taiga_halo2/examples/tx_examples/cascaded_partial_transactions.rs index 99141997..e73eb0dd 100644 --- a/taiga_halo2/examples/tx_examples/cascaded_partial_transactions.rs +++ b/taiga_halo2/examples/tx_examples/cascaded_partial_transactions.rs @@ -19,7 +19,7 @@ use taiga_halo2::{ note::{InputNoteProvingInfo, OutputNoteProvingInfo}, nullifier::{Nullifier, NullifierKeyContainer}, shielded_ptx::ShieldedPartialTransaction, - transaction::{ShieldedPartialTxBundle, Transaction}, + transaction::{ShieldedPartialTxBundle, Transaction, TransparentPartialTxBundle}, }; pub fn create_transaction(mut rng: R) -> Transaction { @@ -71,7 +71,7 @@ pub fn create_transaction(mut rng: R) -> Transaction { // The first partial transaction: // Alice consumes 1 "BTC" and 2 "ETH". // Alice creates a cascade intent note and 1 "BTC" to Bob. - let (ptx_1, r_1) = { + let ptx_1 = { let input_notes = [input_note_1, input_note_2]; let output_notes = [output_note_1, cascade_intent_note]; // Create the input note proving info @@ -128,7 +128,7 @@ pub fn create_transaction(mut rng: R) -> Transaction { // The second partial transaction: // Alice consumes the intent note and 3 "XAN"; // Alice creates 2 "ETH" and 3 "XAN" to Bob - let (ptx_2, r_2) = { + let ptx_2 = { let input_notes = [cascade_intent_note, input_note_3]; let output_notes = [output_note_2, output_note_3]; // Create the input note proving info @@ -185,7 +185,8 @@ pub fn create_transaction(mut rng: R) -> Transaction { // Create the final transaction let shielded_tx_bundle = ShieldedPartialTxBundle::build(vec![ptx_1, ptx_2]); - Transaction::build(&mut rng, Some(shielded_tx_bundle), None, vec![r_1, r_2]) + let transparent_ptx_bundle = TransparentPartialTxBundle::default(); + Transaction::build(&mut rng, shielded_tx_bundle, transparent_ptx_bundle) } #[test] diff --git a/taiga_halo2/examples/tx_examples/partial_fulfillment_token_swap.rs b/taiga_halo2/examples/tx_examples/partial_fulfillment_token_swap.rs index 774b3ddc..de9918e3 100644 --- a/taiga_halo2/examples/tx_examples/partial_fulfillment_token_swap.rs +++ b/taiga_halo2/examples/tx_examples/partial_fulfillment_token_swap.rs @@ -24,7 +24,7 @@ use taiga_halo2::{ note::{InputNoteProvingInfo, Note, OutputNoteProvingInfo}, nullifier::{Nullifier, NullifierKeyContainer}, shielded_ptx::ShieldedPartialTransaction, - transaction::{ShieldedPartialTxBundle, Transaction}, + transaction::{ShieldedPartialTxBundle, Transaction, TransparentPartialTxBundle}, }; pub fn create_token_intent_ptx( @@ -35,7 +35,6 @@ pub fn create_token_intent_ptx( input_nk: NullifierKeyContainer, // NullifierKeyContainer::Key ) -> ( ShieldedPartialTransaction, - pallas::Scalar, NullifierKeyContainer, pallas::Base, pallas::Base, @@ -114,7 +113,7 @@ pub fn create_token_intent_ptx( ); // Create shielded partial tx - let (ptx, r) = ShieldedPartialTransaction::build( + let ptx = ShieldedPartialTransaction::build( [input_note_proving_info, padding_input_note_proving_info], [intent_note_proving_info, padding_output_note_proving_info], &mut rng, @@ -122,7 +121,6 @@ pub fn create_token_intent_ptx( ( ptx, - r, input_nk, input_note_nk_com, input_note.app_data_dynamic, @@ -142,7 +140,7 @@ pub fn consume_token_intent_ptx( receiver_nk_com: pallas::Base, receiver_app_data_dynamic: pallas::Base, output_auth_pk: pallas::Point, -) -> (ShieldedPartialTransaction, pallas::Scalar) { +) -> ShieldedPartialTransaction { // input intent note let intent_note = create_intent_note( &mut rng, @@ -255,7 +253,7 @@ pub fn create_token_swap_transaction(mut rng: R) -> Tran name: "eth".to_string(), value: 10u64, }; - let (alice_ptx, alice_r, intent_nk, receiver_nk_com, receiver_app_data_dynamic, intent_rho) = + let (alice_ptx, intent_nk, receiver_nk_com, receiver_app_data_dynamic, intent_rho) = create_token_intent_ptx(&mut rng, sell.clone(), buy.clone(), alice_auth_sk, alice_nk); // Bob creates the partial transaction with 1 DOLPHIN input and 5 BTC output @@ -263,7 +261,7 @@ pub fn create_token_swap_transaction(mut rng: R) -> Tran let bob_auth_pk = generator * bob_auth_sk; let bob_nk = NullifierKeyContainer::random_key(&mut rng); - let (bob_ptx, bob_r) = create_token_swap_ptx( + let bob_ptx = create_token_swap_ptx( &mut rng, "eth", 5, @@ -277,7 +275,7 @@ pub fn create_token_swap_transaction(mut rng: R) -> Tran // Solver/Bob creates the partial transaction to consume the intent note // The bob_ptx and solver_ptx can be merged to one ptx. - let (solver_ptx, solver_r) = consume_token_intent_ptx( + let solver_ptx = consume_token_intent_ptx( &mut rng, sell, buy, @@ -292,12 +290,8 @@ pub fn create_token_swap_transaction(mut rng: R) -> Tran // Solver creates the final transaction let shielded_tx_bundle = ShieldedPartialTxBundle::build(vec![alice_ptx, bob_ptx, solver_ptx]); - Transaction::build( - &mut rng, - Some(shielded_tx_bundle), - None, - vec![alice_r, bob_r, solver_r], - ) + let transparent_ptx_bundle = TransparentPartialTxBundle::default(); + Transaction::build(&mut rng, shielded_tx_bundle, transparent_ptx_bundle) } #[test] diff --git a/taiga_halo2/examples/tx_examples/token.rs b/taiga_halo2/examples/tx_examples/token.rs index 0aecb384..8daa43c2 100644 --- a/taiga_halo2/examples/tx_examples/token.rs +++ b/taiga_halo2/examples/tx_examples/token.rs @@ -52,7 +52,7 @@ pub fn create_token_swap_ptx( output_value: u64, output_auth_pk: pallas::Point, output_nk_com: NullifierKeyContainer, // NullifierKeyContainer::Commitment -) -> (ShieldedPartialTransaction, pallas::Scalar) { +) -> ShieldedPartialTransaction { let input_auth = TokenAuthorization::from_sk_vk(&input_auth_sk, &COMPRESSED_TOKEN_AUTH_VK); // input note diff --git a/taiga_halo2/examples/tx_examples/token_swap_with_intent.rs b/taiga_halo2/examples/tx_examples/token_swap_with_intent.rs index 3ceb7335..2615b2a5 100644 --- a/taiga_halo2/examples/tx_examples/token_swap_with_intent.rs +++ b/taiga_halo2/examples/tx_examples/token_swap_with_intent.rs @@ -24,7 +24,7 @@ use taiga_halo2::{ note::{InputNoteProvingInfo, Note, OutputNoteProvingInfo}, nullifier::{Nullifier, NullifierKeyContainer}, shielded_ptx::ShieldedPartialTransaction, - transaction::{ShieldedPartialTxBundle, Transaction}, + transaction::{ShieldedPartialTxBundle, Transaction, TransparentPartialTxBundle}, }; pub fn create_token_intent_ptx( @@ -37,7 +37,6 @@ pub fn create_token_intent_ptx( input_nk: NullifierKeyContainer, // NullifierKeyContainer::Key ) -> ( ShieldedPartialTransaction, - pallas::Scalar, NullifierKeyContainer, pallas::Base, pallas::Base, @@ -122,7 +121,7 @@ pub fn create_token_intent_ptx( ); // Create shielded partial tx - let (ptx, r) = ShieldedPartialTransaction::build( + let ptx = ShieldedPartialTransaction::build( [input_note_proving_info, padding_input_note_proving_info], [intent_note_proving_info, padding_output_note_proving_info], &mut rng, @@ -130,7 +129,6 @@ pub fn create_token_intent_ptx( ( ptx, - r, input_nk, input_note_nk_com, input_note.app_data_dynamic, @@ -150,7 +148,7 @@ pub fn consume_token_intent_ptx( output_token: &str, output_value: u64, output_auth_pk: pallas::Point, -) -> (ShieldedPartialTransaction, pallas::Scalar) { +) -> ShieldedPartialTransaction { // input intent note let intent_note = create_intent_note( &mut rng, @@ -252,7 +250,7 @@ pub fn create_token_swap_intent_transaction(mut rng: R) token_name: "monkey".to_string(), token_value: 2u64, }; - let (alice_ptx, alice_r, intent_nk, receiver_nk_com, receiver_app_data_dynamic, intent_rho) = + let (alice_ptx, intent_nk, receiver_nk_com, receiver_app_data_dynamic, intent_rho) = create_token_intent_ptx( &mut rng, condition1.clone(), @@ -268,7 +266,7 @@ pub fn create_token_swap_intent_transaction(mut rng: R) let bob_auth_pk = generator * bob_auth_sk; let bob_nk = NullifierKeyContainer::random_key(&mut rng); - let (bob_ptx, bob_r) = create_token_swap_ptx( + let bob_ptx = create_token_swap_ptx( &mut rng, "dolphin", 1, @@ -282,7 +280,7 @@ pub fn create_token_swap_intent_transaction(mut rng: R) // Solver/Bob creates the partial transaction to consume the intent note // The bob_ptx and solver_ptx can be merged to one ptx. - let (solver_ptx, solver_r) = consume_token_intent_ptx( + let solver_ptx = consume_token_intent_ptx( &mut rng, condition1, condition2, @@ -297,12 +295,8 @@ pub fn create_token_swap_intent_transaction(mut rng: R) // Solver creates the final transaction let shielded_tx_bundle = ShieldedPartialTxBundle::build(vec![alice_ptx, bob_ptx, solver_ptx]); - Transaction::build( - &mut rng, - Some(shielded_tx_bundle), - None, - vec![alice_r, bob_r, solver_r], - ) + let transparent_ptx_bundle = TransparentPartialTxBundle::default(); + Transaction::build(&mut rng, shielded_tx_bundle, transparent_ptx_bundle) } #[test] diff --git a/taiga_halo2/examples/tx_examples/token_swap_without_intent.rs b/taiga_halo2/examples/tx_examples/token_swap_without_intent.rs index dde4dae3..0c3cd672 100644 --- a/taiga_halo2/examples/tx_examples/token_swap_without_intent.rs +++ b/taiga_halo2/examples/tx_examples/token_swap_without_intent.rs @@ -10,7 +10,7 @@ use pasta_curves::{group::Curve, pallas}; use rand::{CryptoRng, RngCore}; use taiga_halo2::{ nullifier::NullifierKeyContainer, - transaction::{ShieldedPartialTxBundle, Transaction}, + transaction::{ShieldedPartialTxBundle, Transaction, TransparentPartialTxBundle}, }; pub fn create_token_swap_transaction(mut rng: R) -> Transaction { @@ -21,7 +21,7 @@ pub fn create_token_swap_transaction(mut rng: R) -> Tran let alice_auth_pk = generator * alice_auth_sk; let alice_nk = NullifierKeyContainer::random_key(&mut rng); - let (alice_ptx, alice_r) = create_token_swap_ptx( + let alice_ptx = create_token_swap_ptx( &mut rng, "btc", 5, @@ -38,7 +38,7 @@ pub fn create_token_swap_transaction(mut rng: R) -> Tran let bob_auth_pk = generator * bob_auth_sk; let bob_nk = NullifierKeyContainer::random_key(&mut rng); - let (bob_ptx, bob_r) = create_token_swap_ptx( + let bob_ptx = create_token_swap_ptx( &mut rng, "eth", 10, @@ -55,7 +55,7 @@ pub fn create_token_swap_transaction(mut rng: R) -> Tran let carol_auth_pk = generator * carol_auth_sk; let carol_nk = NullifierKeyContainer::random_key(&mut rng); - let (carol_ptx, carol_r) = create_token_swap_ptx( + let carol_ptx = create_token_swap_ptx( &mut rng, "xan", 15, @@ -69,12 +69,8 @@ pub fn create_token_swap_transaction(mut rng: R) -> Tran // Solver creates the final transaction let shielded_tx_bundle = ShieldedPartialTxBundle::build(vec![alice_ptx, bob_ptx, carol_ptx]); - Transaction::build( - &mut rng, - Some(shielded_tx_bundle), - None, - vec![alice_r, bob_r, carol_r], - ) + let transparent_ptx_bundle = TransparentPartialTxBundle::default(); + Transaction::build(&mut rng, shielded_tx_bundle, transparent_ptx_bundle) } #[test] diff --git a/taiga_halo2/src/shielded_ptx.rs b/taiga_halo2/src/shielded_ptx.rs index c33e43ec..391f1baa 100644 --- a/taiga_halo2/src/shielded_ptx.rs +++ b/taiga_halo2/src/shielded_ptx.rs @@ -22,6 +22,8 @@ use serde; #[cfg(feature = "borsh")] use borsh::{BorshDeserialize, BorshSerialize}; +#[cfg(feature = "borsh")] +use ff::PrimeField; #[derive(Debug, Clone)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] @@ -29,6 +31,7 @@ pub struct ShieldedPartialTransaction { actions: [ActionVerifyingInfo; NUM_NOTE], inputs: [NoteVPVerifyingInfoSet; NUM_NOTE], outputs: [NoteVPVerifyingInfoSet; NUM_NOTE], + binding_sig_r: pallas::Scalar, } #[derive(Debug, Clone)] @@ -61,6 +64,7 @@ struct ShieldedPartialTransactionProxy { actions: Vec, inputs: Vec, outputs: Vec, + binding_sig_r: pallas::Scalar, } impl ShieldedPartialTransaction { @@ -68,7 +72,7 @@ impl ShieldedPartialTransaction { input_info: [InputNoteProvingInfo; NUM_NOTE], output_info: [OutputNoteProvingInfo; NUM_NOTE], mut rng: R, - ) -> (Self, pallas::Scalar) { + ) -> Self { let inputs: Vec = input_info .iter() .map(|input_note| { @@ -98,14 +102,12 @@ impl ShieldedPartialTransaction { }) .collect(); - ( - Self { - actions: actions.try_into().unwrap(), - inputs: inputs.try_into().unwrap(), - outputs: outputs.try_into().unwrap(), - }, - rcv_sum, - ) + Self { + actions: actions.try_into().unwrap(), + inputs: inputs.try_into().unwrap(), + outputs: outputs.try_into().unwrap(), + binding_sig_r: rcv_sum, + } } // verify zk proof @@ -197,8 +199,13 @@ impl ShieldedPartialTransaction { actions: self.actions.to_vec(), inputs: self.inputs.to_vec(), outputs: self.outputs.to_vec(), + binding_sig_r: self.binding_sig_r, } } + + pub fn get_binding_sig_r(&self) -> pallas::Scalar { + self.binding_sig_r + } } impl ShieldedPartialTransactionProxy { @@ -210,6 +217,7 @@ impl ShieldedPartialTransactionProxy { actions, inputs, outputs, + binding_sig_r: self.binding_sig_r, }) } } @@ -266,6 +274,8 @@ impl BorshSerialize for ShieldedPartialTransaction { output.serialize(writer)?; } + writer.write_all(&self.binding_sig_r.to_repr())?; + Ok(()) } } @@ -282,10 +292,19 @@ impl BorshDeserialize for ShieldedPartialTransaction { let outputs: Vec<_> = (0..NUM_NOTE) .map(|_| NoteVPVerifyingInfoSet::deserialize_reader(reader)) .collect::>()?; + let binding_sig_r_bytes = <[u8; 32]>::deserialize_reader(reader)?; + let binding_sig_r = Option::from(pallas::Scalar::from_repr(binding_sig_r_bytes)) + .ok_or_else(|| { + std::io::Error::new( + std::io::ErrorKind::InvalidData, + "binding_sig_r not in field", + ) + })?; Ok(ShieldedPartialTransaction { actions: actions.try_into().unwrap(), inputs: inputs.try_into().unwrap(), outputs: outputs.try_into().unwrap(), + binding_sig_r, }) } } @@ -413,7 +432,7 @@ pub mod testing { use pasta_curves::pallas; use rand::rngs::OsRng; - pub fn create_shielded_ptx() -> (ShieldedPartialTransaction, pallas::Scalar) { + pub fn create_shielded_ptx() -> ShieldedPartialTransaction { let mut rng = OsRng; // Create empty VP circuit without note info diff --git a/taiga_halo2/src/transaction.rs b/taiga_halo2/src/transaction.rs index 283115cb..90e2691d 100644 --- a/taiga_halo2/src/transaction.rs +++ b/taiga_halo2/src/transaction.rs @@ -27,28 +27,18 @@ use borsh::{BorshDeserialize, BorshSerialize}; #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Transaction { // TODO: Other parameters to be added. - shielded_ptx_bundle: Option, - transparent_ptx_bundle: Option, + shielded_ptx_bundle: ShieldedPartialTxBundle, + transparent_ptx_bundle: TransparentPartialTxBundle, // binding signature to check balance - signature: InProgressBindingSignature, + signature: BindingSignature, } -#[derive(Debug, Clone)] -#[cfg_attr(feature = "borsh", derive(BorshSerialize, BorshDeserialize))] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub enum InProgressBindingSignature { - Authorized(BindingSignature), - Unauthorized(BindingSigningKey), -} - -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Default)] #[cfg_attr(feature = "nif", derive(NifRecord))] #[cfg_attr(feature = "nif", tag = "bundle")] #[cfg_attr(feature = "borsh", derive(BorshSerialize, BorshDeserialize))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct ShieldedPartialTxBundle { - partial_txs: Vec, -} +pub struct ShieldedPartialTxBundle(Vec); #[derive(Debug, Clone, PartialEq, Eq)] #[cfg_attr(feature = "nif", derive(NifStruct))] @@ -59,12 +49,10 @@ pub struct ShieldedResult { pub output_cms: Vec, } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Default)] #[cfg_attr(feature = "borsh", derive(BorshSerialize, BorshDeserialize))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct TransparentPartialTxBundle { - partial_txs: Vec, -} +pub struct TransparentPartialTxBundle(Vec); // TODO: add other outputs if needed. #[derive(Debug, Clone)] @@ -74,19 +62,19 @@ pub struct TransparentResult { } impl Transaction { - // Init the transaction with shielded_ptx_bundle, transparent_ptx_bundle and the key of BindingSignature - pub fn init( - shielded_ptx_bundle: Option, - transparent_ptx_bundle: Option, - // random from value commitment - rcv_vec: Vec, + // Generate the transaction + pub fn build( + rng: R, + shielded_ptx_bundle: ShieldedPartialTxBundle, + transparent_ptx_bundle: TransparentPartialTxBundle, ) -> Self { - assert!(shielded_ptx_bundle.is_some() || transparent_ptx_bundle.is_some()); - assert!(!rcv_vec.is_empty()); - let sk = rcv_vec - .iter() - .fold(pallas::Scalar::zero(), |acc, rcv| acc + rcv); - let signature = InProgressBindingSignature::Unauthorized(BindingSigningKey::from(sk)); + assert!(!(shielded_ptx_bundle.is_empty() && transparent_ptx_bundle.is_empty())); + let shielded_sk = shielded_ptx_bundle.get_bindig_sig_r(); + let transparent_sk = transparent_ptx_bundle.get_bindig_sig_r(); + let binding_sk = BindingSigningKey::from(shielded_sk + transparent_sk); + let sig_hash = Self::digest(&shielded_ptx_bundle, &transparent_ptx_bundle); + let signature = binding_sk.sign(rng, &sig_hash); + Self { shielded_ptx_bundle, transparent_ptx_bundle, @@ -94,50 +82,10 @@ impl Transaction { } } - // Finalize the transaction and complete the Binding Signature. - pub fn finalize(&mut self, rng: R) { - if let InProgressBindingSignature::Unauthorized(sk) = &self.signature { - let vk = self.get_binding_vk(); - assert_eq!(vk, sk.get_vk(), "The notes value is unbalanced"); - let sig_hash = self.digest(); - let signature = sk.sign(rng, &sig_hash); - self.signature = InProgressBindingSignature::Authorized(signature); - } - } - - // Init and finalize the transaction - pub fn build( - rng: R, - shielded_ptx_bundle: Option, - transparent_ptx_bundle: Option, - rcv_vec: Vec, - ) -> Self { - let mut tx = Self::init(shielded_ptx_bundle, transparent_ptx_bundle, rcv_vec); - tx.finalize(rng); - tx - } - - pub fn transparent_bundle(&self) -> Option<&TransparentPartialTxBundle> { - self.transparent_ptx_bundle.as_ref() - } - - pub fn shielded_bundle(&self) -> Option<&ShieldedPartialTxBundle> { - self.shielded_ptx_bundle.as_ref() - } - #[allow(clippy::type_complexity)] - pub fn execute( - &self, - ) -> Result<(Option, Option), TransactionError> { - let shielded_result = match self.shielded_bundle() { - Some(bundle) => Some(bundle.execute()?), - None => None, - }; - - let transparent_result = match self.transparent_bundle() { - Some(bundle) => Some(bundle.execute()?), - None => None, - }; + pub fn execute(&self) -> Result<(ShieldedResult, TransparentResult), TransactionError> { + let shielded_result = self.shielded_ptx_bundle.execute()?; + let transparent_result = self.transparent_ptx_bundle.execute()?; // check balance self.verify_binding_sig()?; @@ -147,72 +95,69 @@ impl Transaction { fn verify_binding_sig(&self) -> Result<(), TransactionError> { let binding_vk = self.get_binding_vk(); - let sig_hash = self.digest(); - if let InProgressBindingSignature::Authorized(sig) = &self.signature { - binding_vk - .verify(&sig_hash, sig) - .map_err(|_| TransactionError::InvalidBindingSignature)?; - } else { - return Err(TransactionError::MissingBindingSignatures); - } - - Ok(()) + let sig_hash = Self::digest(&self.shielded_ptx_bundle, &self.transparent_ptx_bundle); + binding_vk + .verify(&sig_hash, &self.signature) + .map_err(|_| TransactionError::InvalidBindingSignature) } fn get_binding_vk(&self) -> BindingVerificationKey { let mut vk = pallas::Point::identity(); - if let Some(bundle) = self.shielded_bundle() { - vk = bundle - .get_value_commitments() - .iter() - .fold(vk, |acc, cv| acc + cv.inner()); - } + vk = self + .shielded_ptx_bundle + .get_value_commitments() + .iter() + .fold(vk, |acc, cv| acc + cv.inner()); - if let Some(bundle) = self.transparent_bundle() { - vk = bundle - .get_value_commitments() - .iter() - .fold(vk, |acc, cv| acc + cv.inner()); - } + vk = self + .transparent_ptx_bundle + .get_value_commitments() + .iter() + .fold(vk, |acc, cv| acc + cv.inner()); BindingVerificationKey::from(vk) } - fn digest(&self) -> [u8; 32] { + fn digest( + shielded_bundle: &ShieldedPartialTxBundle, + transparent_bundle: &TransparentPartialTxBundle, + ) -> [u8; 32] { let mut h = Blake2bParams::new() .hash_length(32) .personal(TRANSACTION_BINDING_HASH_PERSONALIZATION) .to_state(); - if let Some(bundle) = self.shielded_bundle() { - bundle.get_nullifiers().iter().for_each(|nf| { - h.update(&nf.to_bytes()); - }); - bundle.get_output_cms().iter().for_each(|cm_x| { - h.update(&cm_x.to_repr()); - }); - bundle.get_value_commitments().iter().for_each(|vc| { + shielded_bundle.get_nullifiers().iter().for_each(|nf| { + h.update(&nf.to_bytes()); + }); + shielded_bundle.get_output_cms().iter().for_each(|cm_x| { + h.update(&cm_x.to_repr()); + }); + shielded_bundle + .get_value_commitments() + .iter() + .for_each(|vc| { h.update(&vc.to_bytes()); }); - bundle.get_anchors().iter().for_each(|anchor| { - h.update(&anchor.to_repr()); - }); - } + shielded_bundle.get_anchors().iter().for_each(|anchor| { + h.update(&anchor.to_repr()); + }); // TODO: the transparent digest may be not reasonable, fix it once the transparent execution is nailed down. - if let Some(bundle) = self.transparent_bundle() { - bundle.get_nullifiers().iter().for_each(|nf| { - h.update(&nf.to_bytes()); - }); - bundle.get_output_cms().iter().for_each(|cm| { - h.update(&cm.to_repr()); - }); - bundle.get_value_commitments().iter().for_each(|vc| { + transparent_bundle.get_nullifiers().iter().for_each(|nf| { + h.update(&nf.to_bytes()); + }); + transparent_bundle.get_output_cms().iter().for_each(|cm| { + h.update(&cm.to_repr()); + }); + transparent_bundle + .get_value_commitments() + .iter() + .for_each(|vc| { h.update(&vc.to_bytes()); }); - bundle.get_anchors().iter().for_each(|anchor| { - h.update(&anchor.to_repr()); - }); - } + transparent_bundle.get_anchors().iter().for_each(|anchor| { + h.update(&anchor.to_repr()); + }); h.finalize().as_bytes().try_into().unwrap() } @@ -241,7 +186,7 @@ impl<'a> Decoder<'a> for Transaction { fn decode(term: Term<'a>) -> NifResult { let (term, shielded_ptx_bundle, transparent_bytes, sig_bytes): ( atom::Atom, - Option, + ShieldedPartialTxBundle, Vec, Vec, ) = term.decode()?; @@ -263,23 +208,27 @@ impl<'a> Decoder<'a> for Transaction { } impl ShieldedPartialTxBundle { - pub fn new() -> Self { - Self { - partial_txs: vec![], - } + pub fn is_empty(&self) -> bool { + self.0.is_empty() + } + + pub fn get_bindig_sig_r(&self) -> pallas::Scalar { + self.0.iter().fold(pallas::Scalar::zero(), |acc, ptx| { + acc + ptx.get_binding_sig_r() + }) } pub fn build(partial_txs: Vec) -> Self { - Self { partial_txs } + Self(partial_txs) } pub fn add_partial_tx(&mut self, ptx: ShieldedPartialTransaction) { - self.partial_txs.push(ptx); + self.0.push(ptx); } #[allow(clippy::type_complexity)] pub fn execute(&self) -> Result { - for partial_tx in self.partial_txs.iter() { + for partial_tx in self.0.iter() { partial_tx.execute()?; } @@ -292,31 +241,22 @@ impl ShieldedPartialTxBundle { } pub fn get_value_commitments(&self) -> Vec { - self.partial_txs + self.0 .iter() .flat_map(|ptx| ptx.get_value_commitments()) .collect() } pub fn get_nullifiers(&self) -> Vec { - self.partial_txs - .iter() - .flat_map(|ptx| ptx.get_nullifiers()) - .collect() + self.0.iter().flat_map(|ptx| ptx.get_nullifiers()).collect() } pub fn get_output_cms(&self) -> Vec { - self.partial_txs - .iter() - .flat_map(|ptx| ptx.get_output_cms()) - .collect() + self.0.iter().flat_map(|ptx| ptx.get_output_cms()).collect() } pub fn get_anchors(&self) -> Vec { - self.partial_txs - .iter() - .flat_map(|ptx| ptx.get_anchors()) - .collect() + self.0.iter().flat_map(|ptx| ptx.get_anchors()).collect() } fn get_binding_vk(&self) -> BindingVerificationKey { @@ -329,23 +269,21 @@ impl ShieldedPartialTxBundle { } } -impl Default for ShieldedPartialTxBundle { - fn default() -> Self { - Self::new() +impl TransparentPartialTxBundle { + pub fn is_empty(&self) -> bool { + self.0.is_empty() } -} -impl TransparentPartialTxBundle { pub fn build(partial_txs: Vec) -> Self { - Self { partial_txs } + Self(partial_txs) } pub fn add_partial_tx(&mut self, ptx: TransparentPartialTransaction) { - self.partial_txs.push(ptx); + self.0.push(ptx); } pub fn execute(&self) -> Result { - for partial_tx in self.partial_txs.iter() { + for partial_tx in self.0.iter() { partial_tx.execute()?; } @@ -356,28 +294,25 @@ impl TransparentPartialTxBundle { } pub fn get_value_commitments(&self) -> Vec { - unimplemented!() + // TODO: add the real value commitments + vec![] } pub fn get_nullifiers(&self) -> Vec { - self.partial_txs - .iter() - .flat_map(|ptx| ptx.get_nullifiers()) - .collect() + self.0.iter().flat_map(|ptx| ptx.get_nullifiers()).collect() } pub fn get_output_cms(&self) -> Vec { - self.partial_txs - .iter() - .flat_map(|ptx| ptx.get_output_cms()) - .collect() + self.0.iter().flat_map(|ptx| ptx.get_output_cms()).collect() } pub fn get_anchors(&self) -> Vec { - self.partial_txs - .iter() - .flat_map(|ptx| ptx.get_anchors()) - .collect() + self.0.iter().flat_map(|ptx| ptx.get_anchors()).collect() + } + + pub fn get_bindig_sig_r(&self) -> pallas::Scalar { + // TODO: add the real r + pallas::Scalar::zero() } } @@ -385,19 +320,14 @@ impl TransparentPartialTxBundle { pub mod testing { use crate::shielded_ptx::testing::create_shielded_ptx; use crate::transaction::ShieldedPartialTxBundle; - use pasta_curves::pallas; - pub fn create_shielded_ptx_bundle( - num: usize, - ) -> (ShieldedPartialTxBundle, Vec) { - let mut bundle = ShieldedPartialTxBundle::new(); - let mut r_vec = vec![]; + pub fn create_shielded_ptx_bundle(num: usize) -> ShieldedPartialTxBundle { + let mut bundle = vec![]; for _ in 0..num { - let (ptx, r) = create_shielded_ptx(); - bundle.add_partial_tx(ptx); - r_vec.push(r); + let ptx = create_shielded_ptx(); + bundle.push(ptx); } - (bundle, r_vec) + ShieldedPartialTxBundle::build(bundle) } #[test] @@ -407,15 +337,10 @@ pub mod testing { let rng = OsRng; - let (shielded_ptx_bundle, r_vec) = create_shielded_ptx_bundle(2); + let shielded_ptx_bundle = create_shielded_ptx_bundle(2); // TODO: add transparent_ptx_bundle test - let transparent_ptx_bundle = None; - let tx = Transaction::build( - rng, - Some(shielded_ptx_bundle), - transparent_ptx_bundle, - r_vec, - ); + let transparent_ptx_bundle = TransparentPartialTxBundle::default(); + let tx = Transaction::build(rng, shielded_ptx_bundle, transparent_ptx_bundle); let (_shielded_ret, _) = tx.execute().unwrap(); #[cfg(feature = "borsh")]