diff --git a/wallet/src/cli/native_token_transfer_program.rs b/wallet/src/cli/native_token_transfer_program.rs index 666ea68..b568931 100644 --- a/wallet/src/cli/native_token_transfer_program.rs +++ b/wallet/src/cli/native_token_transfer_program.rs @@ -224,7 +224,7 @@ impl WalletSubcommand for NativeTokenTransferProgramSubcommandShielded { let to_initialization = wallet_core.check_private_account_initialized(&to).await?; - let (res, secret) = if let Some(to_proof) = to_initialization { + let (res, [secret]) = if let Some(to_proof) = to_initialization { wallet_core .send_shielded_native_token_transfer_already_initialized( from, to, amount, to_proof, @@ -277,7 +277,7 @@ impl WalletSubcommand for NativeTokenTransferProgramSubcommandShielded { let to_ipk = nssa_core::encryption::shared_key_derivation::Secp256k1Point(to_ipk.to_vec()); - let (res, _) = wallet_core + let res = wallet_core .send_shielded_native_token_transfer_outer_account(from, to_npk, to_ipk, amount) .await?; @@ -311,7 +311,7 @@ impl WalletSubcommand for NativeTokenTransferProgramSubcommand { let from: Address = from.parse().unwrap(); let to: Address = to.parse().unwrap(); - let (res, secret) = wallet_core + let (res, [secret]) = wallet_core .send_deshielded_native_token_transfer(from, to, amount) .await?; diff --git a/wallet/src/lib.rs b/wallet/src/lib.rs index 5adfa39..833422f 100644 --- a/wallet/src/lib.rs +++ b/wallet/src/lib.rs @@ -43,6 +43,7 @@ pub mod pinata_interactions; pub mod poller; pub mod token_program_interactions; pub mod token_transfers; +pub mod transaction_utils; pub struct WalletCore { pub storage: WalletChainStore, diff --git a/wallet/src/token_program_interactions.rs b/wallet/src/token_program_interactions.rs index a77a512..4e30a4b 100644 --- a/wallet/src/token_program_interactions.rs +++ b/wallet/src/token_program_interactions.rs @@ -1,14 +1,50 @@ use common::{ExecutionFailureKind, sequencer_client::json::SendTxResponse}; -use key_protocol::key_management::ephemeral_key_holder::EphemeralKeyHolder; -use nssa::{Address, privacy_preserving_transaction::circuit, program::Program}; +use nssa::{Account, Address, program::Program}; use nssa_core::{ - Commitment, MembershipProof, NullifierPublicKey, SharedSecretKey, account::AccountWithMetadata, - encryption::IncomingViewingPublicKey, + MembershipProof, NullifierPublicKey, SharedSecretKey, encryption::IncomingViewingPublicKey, + program::InstructionData, }; -use crate::{WalletCore, helperfunctions::produce_random_nonces}; +use crate::WalletCore; impl WalletCore { + pub fn token_program_preparation_transfer( + amount: u128, + ) -> ( + InstructionData, + Program, + impl FnOnce(&Account, &Account) -> Result<(), ExecutionFailureKind>, + ) { + // Instruction must be: [0x01 || amount (little-endian 16 bytes) || 0x00 || 0x00 || 0x00 || 0x00 || 0x00 || 0x00]. + let mut instruction = [0; 23]; + instruction[0] = 0x01; + instruction[1..17].copy_from_slice(&amount.to_le_bytes()); + let instruction_data = Program::serialize_instruction(instruction).unwrap(); + let program = Program::token(); + let tx_pre_check = |_: &Account, _: &Account| Ok(()); + + (instruction_data, program, tx_pre_check) + } + + pub fn token_program_preparation_definition( + name: [u8; 6], + total_supply: u128, + ) -> ( + InstructionData, + Program, + impl FnOnce(&Account, &Account) -> Result<(), ExecutionFailureKind>, + ) { + // Instruction must be: [0x00 || total_supply (little-endian 16 bytes) || name (6 bytes)] + let mut instruction = [0; 23]; + instruction[1..17].copy_from_slice(&total_supply.to_le_bytes()); + instruction[17..].copy_from_slice(&name); + let instruction_data = Program::serialize_instruction(instruction).unwrap(); + let program = Program::token(); + let tx_pre_check = |_: &Account, _: &Account| Ok(()); + + (instruction_data, program, tx_pre_check) + } + pub async fn send_new_token_definition( &self, definition_address: Address, @@ -40,71 +76,19 @@ impl WalletCore { name: [u8; 6], total_supply: u128, ) -> Result<(SendTxResponse, [SharedSecretKey; 1]), ExecutionFailureKind> { - let Some((supply_keys, supply_acc)) = self - .storage - .user_data - .get_private_account(&supply_addr) - .cloned() - else { - return Err(ExecutionFailureKind::KeyNotFoundError); - }; + let (instruction_data, program, tx_pre_check) = + WalletCore::token_program_preparation_definition(name, total_supply); - //It makes more sence to have definition acc as public - let definition_acc = self.get_account_public(definition_addr).await.unwrap(); - - let supply_npk = supply_keys.nullifer_public_key; - let supply_ipk = supply_keys.incoming_viewing_public_key; - - let program = nssa::program::Program::token(); - - let definition_pre = - AccountWithMetadata::new(definition_acc.clone(), false, definition_addr); - let supply_pre = AccountWithMetadata::new(supply_acc.clone(), false, &supply_npk); - - let eph_holder_supply = EphemeralKeyHolder::new(&supply_npk); - let shared_secret_supply = eph_holder_supply.calculate_shared_secret_sender(&supply_ipk); - - // Instruction must be: [0x00 || total_supply (little-endian 16 bytes) || name (6 bytes)] - let mut instruction = [0; 23]; - instruction[1..17].copy_from_slice(&total_supply.to_le_bytes()); - instruction[17..].copy_from_slice(&name); - - let (output, proof) = circuit::execute_and_prove( - &[definition_pre, supply_pre], - &nssa::program::Program::serialize_instruction(instruction).unwrap(), - &[0, 2], - &produce_random_nonces(1), - &[(supply_npk.clone(), shared_secret_supply.clone())], - &[], - &program, + // Kind of non-obvious naming + // Basically this funtion is called because authentication mask is [0, 2] + self.shielded_two_accs_receiver_uninit( + definition_addr, + supply_addr, + instruction_data, + tx_pre_check, + program, ) - .unwrap(); - - let message = - nssa::privacy_preserving_transaction::message::Message::try_from_circuit_output( - vec![definition_addr], - vec![], - vec![( - supply_npk.clone(), - supply_ipk.clone(), - eph_holder_supply.generate_ephemeral_public_key(), - )], - output, - ) - .unwrap(); - - let witness_set = - nssa::privacy_preserving_transaction::witness_set::WitnessSet::for_message( - &message, - proof, - &[], - ); - let tx = nssa::PrivacyPreservingTransaction::new(message, witness_set); - - Ok(( - self.sequencer_client.send_tx_private(tx).await?, - [shared_secret_supply], - )) + .await } pub async fn send_transfer_token_transaction( @@ -148,107 +132,18 @@ impl WalletCore { amount: u128, recipient_proof: MembershipProof, ) -> Result<(SendTxResponse, [SharedSecretKey; 2]), ExecutionFailureKind> { - let Some((sender_keys, sender_acc)) = self - .storage - .user_data - .get_private_account(&sender_address) - .cloned() - else { - return Err(ExecutionFailureKind::KeyNotFoundError); - }; + let (instruction_data, program, tx_pre_check) = + WalletCore::token_program_preparation_transfer(amount); - let Some((recipient_keys, recipient_acc)) = self - .storage - .user_data - .get_private_account(&recipient_address) - .cloned() - else { - return Err(ExecutionFailureKind::KeyNotFoundError); - }; - - let sender_npk = sender_keys.nullifer_public_key; - let sender_ipk = sender_keys.incoming_viewing_public_key; - let recipient_npk = recipient_keys.nullifer_public_key.clone(); - let recipient_ipk = recipient_keys.incoming_viewing_public_key.clone(); - - let program = Program::token(); - - let sender_commitment = Commitment::new(&sender_npk, &sender_acc); - - let sender_pre = AccountWithMetadata::new(sender_acc.clone(), true, &sender_npk); - let recipient_pre = AccountWithMetadata::new(recipient_acc.clone(), true, &recipient_npk); - - let eph_holder_sender = EphemeralKeyHolder::new(&sender_npk); - let shared_secret_sender = eph_holder_sender.calculate_shared_secret_sender(&sender_ipk); - - let eph_holder_recipient = EphemeralKeyHolder::new(&recipient_npk); - let shared_secret_recipient = - eph_holder_recipient.calculate_shared_secret_sender(&recipient_ipk); - - // Instruction must be: [0x01 || amount (little-endian 16 bytes) || 0x00 || 0x00 || 0x00 || 0x00 || 0x00 || 0x00]. - let mut instruction = [0; 23]; - instruction[0] = 0x01; - instruction[1..17].copy_from_slice(&amount.to_le_bytes()); - - let (output, proof) = circuit::execute_and_prove( - &[sender_pre, recipient_pre], - &Program::serialize_instruction(instruction).unwrap(), - &[1, 1], - &produce_random_nonces(2), - &[ - (sender_npk.clone(), shared_secret_sender.clone()), - (recipient_npk.clone(), shared_secret_recipient.clone()), - ], - &[ - ( - sender_keys.private_key_holder.nullifier_secret_key, - self.sequencer_client - .get_proof_for_commitment(sender_commitment) - .await - .unwrap() - .unwrap(), - ), - ( - recipient_keys.private_key_holder.nullifier_secret_key, - recipient_proof, - ), - ], - &program, + self.private_tx_two_accs_all_init( + sender_address, + recipient_address, + instruction_data, + tx_pre_check, + program, + recipient_proof, ) - .unwrap(); - - let message = - nssa::privacy_preserving_transaction::message::Message::try_from_circuit_output( - vec![], - vec![], - vec![ - ( - sender_npk.clone(), - sender_ipk.clone(), - eph_holder_sender.generate_ephemeral_public_key(), - ), - ( - recipient_npk.clone(), - recipient_ipk.clone(), - eph_holder_recipient.generate_ephemeral_public_key(), - ), - ], - output, - ) - .unwrap(); - - let witness_set = - nssa::privacy_preserving_transaction::witness_set::WitnessSet::for_message( - &message, - proof, - &[], - ); - let tx = nssa::PrivacyPreservingTransaction::new(message, witness_set); - - Ok(( - self.sequencer_client.send_tx_private(tx).await?, - [shared_secret_sender, shared_secret_recipient], - )) + .await } pub async fn send_transfer_token_transaction_private_owned_account_not_initialized( @@ -257,101 +152,17 @@ impl WalletCore { recipient_address: Address, amount: u128, ) -> Result<(SendTxResponse, [SharedSecretKey; 2]), ExecutionFailureKind> { - let Some((sender_keys, sender_acc)) = self - .storage - .user_data - .get_private_account(&sender_address) - .cloned() - else { - return Err(ExecutionFailureKind::KeyNotFoundError); - }; + let (instruction_data, program, tx_pre_check) = + WalletCore::token_program_preparation_transfer(amount); - let Some((recipient_keys, recipient_acc)) = self - .storage - .user_data - .get_private_account(&recipient_address) - .cloned() - else { - return Err(ExecutionFailureKind::KeyNotFoundError); - }; - - let sender_npk = sender_keys.nullifer_public_key; - let sender_ipk = sender_keys.incoming_viewing_public_key; - let recipient_npk = recipient_keys.nullifer_public_key.clone(); - let recipient_ipk = recipient_keys.incoming_viewing_public_key.clone(); - - let program = Program::token(); - - let sender_commitment = Commitment::new(&sender_npk, &sender_acc); - - let sender_pre = AccountWithMetadata::new(sender_acc.clone(), true, &sender_npk); - let recipient_pre = AccountWithMetadata::new(recipient_acc.clone(), false, &recipient_npk); - - let eph_holder_sender = EphemeralKeyHolder::new(&sender_npk); - let shared_secret_sender = eph_holder_sender.calculate_shared_secret_sender(&sender_ipk); - - let eph_holder_recipient = EphemeralKeyHolder::new(&recipient_npk); - let shared_secret_recipient = - eph_holder_recipient.calculate_shared_secret_sender(&recipient_ipk); - - // Instruction must be: [0x01 || amount (little-endian 16 bytes) || 0x00 || 0x00 || 0x00 || 0x00 || 0x00 || 0x00]. - let mut instruction = [0; 23]; - instruction[0] = 0x01; - instruction[1..17].copy_from_slice(&amount.to_le_bytes()); - - let (output, proof) = circuit::execute_and_prove( - &[sender_pre, recipient_pre], - &Program::serialize_instruction(instruction).unwrap(), - &[1, 2], - &produce_random_nonces(2), - &[ - (sender_npk.clone(), shared_secret_sender.clone()), - (recipient_npk.clone(), shared_secret_recipient.clone()), - ], - &[( - sender_keys.private_key_holder.nullifier_secret_key, - self.sequencer_client - .get_proof_for_commitment(sender_commitment) - .await - .unwrap() - .unwrap(), - )], - &program, + self.private_tx_two_accs_receiver_uninit( + sender_address, + recipient_address, + instruction_data, + tx_pre_check, + program, ) - .unwrap(); - - let message = - nssa::privacy_preserving_transaction::message::Message::try_from_circuit_output( - vec![], - vec![], - vec![ - ( - sender_npk.clone(), - sender_ipk.clone(), - eph_holder_sender.generate_ephemeral_public_key(), - ), - ( - recipient_npk.clone(), - recipient_ipk.clone(), - eph_holder_recipient.generate_ephemeral_public_key(), - ), - ], - output, - ) - .unwrap(); - - let witness_set = - nssa::privacy_preserving_transaction::witness_set::WitnessSet::for_message( - &message, - proof, - &[], - ); - let tx = nssa::PrivacyPreservingTransaction::new(message, witness_set); - - Ok(( - self.sequencer_client.send_tx_private(tx).await?, - [shared_secret_sender, shared_secret_recipient], - )) + .await } pub async fn send_transfer_token_transaction_private_foreign_account( @@ -361,92 +172,18 @@ impl WalletCore { recipient_ipk: IncomingViewingPublicKey, amount: u128, ) -> Result<(SendTxResponse, [SharedSecretKey; 2]), ExecutionFailureKind> { - let Some((sender_keys, sender_acc)) = self - .storage - .user_data - .get_private_account(&sender_address) - .cloned() - else { - return Err(ExecutionFailureKind::KeyNotFoundError); - }; + let (instruction_data, program, tx_pre_check) = + WalletCore::token_program_preparation_transfer(amount); - let recipient_acc = nssa_core::account::Account::default(); - - let sender_npk = sender_keys.nullifer_public_key; - let sender_ipk = sender_keys.incoming_viewing_public_key; - - let program = Program::token(); - - let sender_commitment = Commitment::new(&sender_npk, &sender_acc); - - let sender_pre = AccountWithMetadata::new(sender_acc.clone(), true, &sender_npk); - let recipient_pre = AccountWithMetadata::new(recipient_acc.clone(), false, &recipient_npk); - - let eph_holder_sender = EphemeralKeyHolder::new(&sender_npk); - let shared_secret_sender = eph_holder_sender.calculate_shared_secret_sender(&sender_ipk); - - let eph_holder_recipient = EphemeralKeyHolder::new(&recipient_npk); - let shared_secret_recipient = - eph_holder_recipient.calculate_shared_secret_sender(&recipient_ipk); - - // Instruction must be: [0x01 || amount (little-endian 16 bytes) || 0x00 || 0x00 || 0x00 || 0x00 || 0x00 || 0x00]. - let mut instruction = [0; 23]; - instruction[0] = 0x01; - instruction[1..17].copy_from_slice(&amount.to_le_bytes()); - - let (output, proof) = circuit::execute_and_prove( - &[sender_pre, recipient_pre], - &Program::serialize_instruction(instruction).unwrap(), - &[1, 2], - &produce_random_nonces(2), - &[ - (sender_npk.clone(), shared_secret_sender.clone()), - (recipient_npk.clone(), shared_secret_recipient.clone()), - ], - &[( - sender_keys.private_key_holder.nullifier_secret_key, - self.sequencer_client - .get_proof_for_commitment(sender_commitment) - .await - .unwrap() - .unwrap(), - )], - &program, + self.private_tx_two_accs_receiver_outer( + sender_address, + recipient_npk, + recipient_ipk, + instruction_data, + tx_pre_check, + program, ) - .unwrap(); - - let message = - nssa::privacy_preserving_transaction::message::Message::try_from_circuit_output( - vec![], - vec![], - vec![ - ( - sender_npk.clone(), - sender_ipk.clone(), - eph_holder_sender.generate_ephemeral_public_key(), - ), - ( - recipient_npk.clone(), - recipient_ipk.clone(), - eph_holder_recipient.generate_ephemeral_public_key(), - ), - ], - output, - ) - .unwrap(); - - let witness_set = - nssa::privacy_preserving_transaction::witness_set::WitnessSet::for_message( - &message, - proof, - &[], - ); - let tx = nssa::PrivacyPreservingTransaction::new(message, witness_set); - - Ok(( - self.sequencer_client.send_tx_private(tx).await?, - [shared_secret_sender, shared_secret_recipient], - )) + .await } pub async fn send_transfer_token_transaction_deshielded( @@ -455,81 +192,17 @@ impl WalletCore { recipient_address: Address, amount: u128, ) -> Result<(SendTxResponse, [SharedSecretKey; 1]), ExecutionFailureKind> { - let Some((sender_keys, sender_acc)) = self - .storage - .user_data - .get_private_account(&sender_address) - .cloned() - else { - return Err(ExecutionFailureKind::KeyNotFoundError); - }; + let (instruction_data, program, tx_pre_check) = + WalletCore::token_program_preparation_transfer(amount); - let Ok(recipient_acc) = self.get_account_public(recipient_address).await else { - return Err(ExecutionFailureKind::KeyNotFoundError); - }; - - let sender_npk = sender_keys.nullifer_public_key; - let sender_ipk = sender_keys.incoming_viewing_public_key; - - let program = Program::token(); - - let sender_commitment = Commitment::new(&sender_npk, &sender_acc); - - let sender_pre = AccountWithMetadata::new(sender_acc.clone(), true, &sender_npk); - let recipient_pre = - AccountWithMetadata::new(recipient_acc.clone(), false, recipient_address); - - let eph_holder_sender = EphemeralKeyHolder::new(&sender_npk); - let shared_secret_sender = eph_holder_sender.calculate_shared_secret_sender(&sender_ipk); - - // Instruction must be: [0x01 || amount (little-endian 16 bytes) || 0x00 || 0x00 || 0x00 || 0x00 || 0x00 || 0x00]. - let mut instruction = [0; 23]; - instruction[0] = 0x01; - instruction[1..17].copy_from_slice(&amount.to_le_bytes()); - - let (output, proof) = circuit::execute_and_prove( - &[sender_pre, recipient_pre], - &Program::serialize_instruction(instruction).unwrap(), - &[1, 0], - &produce_random_nonces(1), - &[(sender_npk.clone(), shared_secret_sender.clone())], - &[( - sender_keys.private_key_holder.nullifier_secret_key, - self.sequencer_client - .get_proof_for_commitment(sender_commitment) - .await - .unwrap() - .unwrap(), - )], - &program, + self.deshielded_tx_two_accs( + sender_address, + recipient_address, + instruction_data, + tx_pre_check, + program, ) - .unwrap(); - - let message = - nssa::privacy_preserving_transaction::message::Message::try_from_circuit_output( - vec![recipient_address], - vec![], - vec![( - sender_npk.clone(), - sender_ipk.clone(), - eph_holder_sender.generate_ephemeral_public_key(), - )], - output, - ) - .unwrap(); - - let witness_set = - nssa::privacy_preserving_transaction::witness_set::WitnessSet::for_message( - &message, - proof, - &[], - ); - let tx = nssa::PrivacyPreservingTransaction::new(message, witness_set); - - Ok(( - self.sequencer_client.send_tx_private(tx).await?, - [shared_secret_sender], - )) + .await } pub async fn send_transfer_token_transaction_shielded_owned_account_already_initialized( @@ -539,83 +212,18 @@ impl WalletCore { amount: u128, recipient_proof: MembershipProof, ) -> Result<(SendTxResponse, [SharedSecretKey; 1]), ExecutionFailureKind> { - let Ok(sender_acc) = self.get_account_public(sender_address).await else { - return Err(ExecutionFailureKind::KeyNotFoundError); - }; + let (instruction_data, program, tx_pre_check) = + WalletCore::token_program_preparation_transfer(amount); - let Some(sender_priv_key) = self - .storage - .user_data - .get_pub_account_signing_key(&sender_address) - else { - return Err(ExecutionFailureKind::KeyNotFoundError); - }; - - let Some((recipient_keys, recipient_acc)) = self - .storage - .user_data - .get_private_account(&recipient_address) - .cloned() - else { - return Err(ExecutionFailureKind::KeyNotFoundError); - }; - - let recipient_npk = recipient_keys.nullifer_public_key.clone(); - let recipient_ipk = recipient_keys.incoming_viewing_public_key.clone(); - - let program = Program::token(); - - let sender_pre = AccountWithMetadata::new(sender_acc.clone(), true, sender_address); - let recipient_pre = AccountWithMetadata::new(recipient_acc.clone(), true, &recipient_npk); - - let eph_holder_recipient = EphemeralKeyHolder::new(&recipient_npk); - let shared_secret_recipient = - eph_holder_recipient.calculate_shared_secret_sender(&recipient_ipk); - - // Instruction must be: [0x01 || amount (little-endian 16 bytes) || 0x00 || 0x00 || 0x00 || 0x00 || 0x00 || 0x00]. - let mut instruction = [0; 23]; - instruction[0] = 0x01; - instruction[1..17].copy_from_slice(&amount.to_le_bytes()); - - let (output, proof) = circuit::execute_and_prove( - &[sender_pre, recipient_pre], - &Program::serialize_instruction(instruction).unwrap(), - &[0, 1], - &produce_random_nonces(1), - &[(recipient_npk.clone(), shared_secret_recipient.clone())], - &[( - recipient_keys.private_key_holder.nullifier_secret_key, - recipient_proof, - )], - &program, + self.shielded_two_accs_all_init( + sender_address, + recipient_address, + instruction_data, + tx_pre_check, + program, + recipient_proof, ) - .unwrap(); - - let message = - nssa::privacy_preserving_transaction::message::Message::try_from_circuit_output( - vec![sender_address], - vec![sender_acc.nonce], - vec![( - recipient_npk.clone(), - recipient_ipk.clone(), - eph_holder_recipient.generate_ephemeral_public_key(), - )], - output, - ) - .unwrap(); - - let witness_set = - nssa::privacy_preserving_transaction::witness_set::WitnessSet::for_message( - &message, - proof, - &[sender_priv_key], - ); - let tx = nssa::PrivacyPreservingTransaction::new(message, witness_set); - - Ok(( - self.sequencer_client.send_tx_private(tx).await?, - [shared_secret_recipient], - )) + .await } pub async fn send_transfer_token_transaction_shielded_owned_account_not_initialized( @@ -624,80 +232,17 @@ impl WalletCore { recipient_address: Address, amount: u128, ) -> Result<(SendTxResponse, [SharedSecretKey; 1]), ExecutionFailureKind> { - let Ok(sender_acc) = self.get_account_public(sender_address).await else { - return Err(ExecutionFailureKind::KeyNotFoundError); - }; + let (instruction_data, program, tx_pre_check) = + WalletCore::token_program_preparation_transfer(amount); - let Some(sender_priv_key) = self - .storage - .user_data - .get_pub_account_signing_key(&sender_address) - else { - return Err(ExecutionFailureKind::KeyNotFoundError); - }; - - let Some((recipient_keys, recipient_acc)) = self - .storage - .user_data - .get_private_account(&recipient_address) - .cloned() - else { - return Err(ExecutionFailureKind::KeyNotFoundError); - }; - - let recipient_npk = recipient_keys.nullifer_public_key.clone(); - let recipient_ipk = recipient_keys.incoming_viewing_public_key.clone(); - - let program = Program::token(); - - let sender_pre = AccountWithMetadata::new(sender_acc.clone(), true, sender_address); - let recipient_pre = AccountWithMetadata::new(recipient_acc.clone(), false, &recipient_npk); - - let eph_holder_recipient = EphemeralKeyHolder::new(&recipient_npk); - let shared_secret_recipient = - eph_holder_recipient.calculate_shared_secret_sender(&recipient_ipk); - - // Instruction must be: [0x01 || amount (little-endian 16 bytes) || 0x00 || 0x00 || 0x00 || 0x00 || 0x00 || 0x00]. - let mut instruction = [0; 23]; - instruction[0] = 0x01; - instruction[1..17].copy_from_slice(&amount.to_le_bytes()); - - let (output, proof) = circuit::execute_and_prove( - &[sender_pre, recipient_pre], - &Program::serialize_instruction(instruction).unwrap(), - &[0, 2], - &produce_random_nonces(1), - &[(recipient_npk.clone(), shared_secret_recipient.clone())], - &[], - &program, + self.shielded_two_accs_receiver_uninit( + sender_address, + recipient_address, + instruction_data, + tx_pre_check, + program, ) - .unwrap(); - - let message = - nssa::privacy_preserving_transaction::message::Message::try_from_circuit_output( - vec![sender_address], - vec![sender_acc.nonce], - vec![( - recipient_npk.clone(), - recipient_ipk.clone(), - eph_holder_recipient.generate_ephemeral_public_key(), - )], - output, - ) - .unwrap(); - - let witness_set = - nssa::privacy_preserving_transaction::witness_set::WitnessSet::for_message( - &message, - proof, - &[sender_priv_key], - ); - let tx = nssa::PrivacyPreservingTransaction::new(message, witness_set); - - Ok(( - self.sequencer_client.send_tx_private(tx).await?, - [shared_secret_recipient], - )) + .await } pub async fn send_transfer_token_transaction_shielded_foreign_account( @@ -707,66 +252,17 @@ impl WalletCore { recipient_ipk: IncomingViewingPublicKey, amount: u128, ) -> Result { - let Ok(sender_acc) = self.get_account_public(sender_address).await else { - return Err(ExecutionFailureKind::KeyNotFoundError); - }; + let (instruction_data, program, tx_pre_check) = + WalletCore::token_program_preparation_transfer(amount); - let Some(sender_priv_key) = self - .storage - .user_data - .get_pub_account_signing_key(&sender_address) - else { - return Err(ExecutionFailureKind::KeyNotFoundError); - }; - - let recipient_acc = nssa_core::account::Account::default(); - - let program = Program::token(); - - let sender_pre = AccountWithMetadata::new(sender_acc.clone(), true, sender_address); - let recipient_pre = AccountWithMetadata::new(recipient_acc.clone(), false, &recipient_npk); - - let eph_holder_recipient = EphemeralKeyHolder::new(&recipient_npk); - let shared_secret_recipient = - eph_holder_recipient.calculate_shared_secret_sender(&recipient_ipk); - - // Instruction must be: [0x01 || amount (little-endian 16 bytes) || 0x00 || 0x00 || 0x00 || 0x00 || 0x00 || 0x00]. - let mut instruction = [0; 23]; - instruction[0] = 0x01; - instruction[1..17].copy_from_slice(&amount.to_le_bytes()); - - let (output, proof) = circuit::execute_and_prove( - &[sender_pre, recipient_pre], - &Program::serialize_instruction(instruction).unwrap(), - &[0, 2], - &produce_random_nonces(1), - &[(recipient_npk.clone(), shared_secret_recipient.clone())], - &[], - &program, + self.shielded_two_accs_receiver_outer( + sender_address, + recipient_npk, + recipient_ipk, + instruction_data, + tx_pre_check, + program, ) - .unwrap(); - - let message = - nssa::privacy_preserving_transaction::message::Message::try_from_circuit_output( - vec![sender_address], - vec![sender_acc.nonce], - vec![( - recipient_npk.clone(), - recipient_ipk.clone(), - eph_holder_recipient.generate_ephemeral_public_key(), - )], - output, - ) - .unwrap(); - - let witness_set = - nssa::privacy_preserving_transaction::witness_set::WitnessSet::for_message( - &message, - proof, - &[sender_priv_key], - ); - let tx = nssa::PrivacyPreservingTransaction::new(message, witness_set); - - Ok(self.sequencer_client.send_tx_private(tx).await?) + .await } } diff --git a/wallet/src/token_transfers/deshielded.rs b/wallet/src/token_transfers/deshielded.rs index 6bc812b..c724425 100644 --- a/wallet/src/token_transfers/deshielded.rs +++ b/wallet/src/token_transfers/deshielded.rs @@ -1,13 +1,7 @@ use common::{ExecutionFailureKind, sequencer_client::json::SendTxResponse}; -use key_protocol::key_management::ephemeral_key_holder::EphemeralKeyHolder; -use nssa::{ - Address, PrivacyPreservingTransaction, - privacy_preserving_transaction::{circuit, message::Message, witness_set::WitnessSet}, - program::Program, -}; -use nssa_core::{Commitment, account::AccountWithMetadata}; +use nssa::Address; -use crate::{WalletCore, helperfunctions::produce_random_nonces}; +use crate::WalletCore; impl WalletCore { pub async fn send_deshielded_native_token_transfer( @@ -15,71 +9,11 @@ impl WalletCore { from: Address, to: Address, balance_to_move: u128, - ) -> Result<(SendTxResponse, nssa_core::SharedSecretKey), ExecutionFailureKind> { - let Some((from_keys, from_acc)) = - self.storage.user_data.get_private_account(&from).cloned() - else { - return Err(ExecutionFailureKind::KeyNotFoundError); - }; + ) -> Result<(SendTxResponse, [nssa_core::SharedSecretKey; 1]), ExecutionFailureKind> { + let (instruction_data, program, tx_pre_check) = + WalletCore::auth_transfer_preparation(balance_to_move); - let Ok(to_acc) = self.get_account_public(to).await else { - return Err(ExecutionFailureKind::KeyNotFoundError); - }; - - if from_acc.balance >= balance_to_move { - let program = Program::authenticated_transfer_program(); - - let npk_from = from_keys.nullifer_public_key; - let ipk_from = from_keys.incoming_viewing_public_key; - - let sender_commitment = Commitment::new(&npk_from, &from_acc); - - let sender_pre = AccountWithMetadata::new(from_acc.clone(), true, &npk_from); - let recipient_pre = AccountWithMetadata::new(to_acc.clone(), false, to); - - let eph_holder = EphemeralKeyHolder::new(&npk_from); - let shared_secret = eph_holder.calculate_shared_secret_sender(&ipk_from); - - let (output, proof) = circuit::execute_and_prove( - &[sender_pre, recipient_pre], - &Program::serialize_instruction(balance_to_move).unwrap(), - &[1, 0], - &produce_random_nonces(1), - &[(npk_from.clone(), shared_secret.clone())], - &[( - from_keys.private_key_holder.nullifier_secret_key, - self.sequencer_client - .get_proof_for_commitment(sender_commitment) - .await - .unwrap() - .unwrap(), - )], - &program, - ) - .unwrap(); - - let message = Message::try_from_circuit_output( - vec![to], - vec![], - vec![( - npk_from.clone(), - ipk_from.clone(), - eph_holder.generate_ephemeral_public_key(), - )], - output, - ) - .unwrap(); - - let witness_set = WitnessSet::for_message(&message, proof, &[]); - - let tx = PrivacyPreservingTransaction::new(message, witness_set); - - Ok(( - self.sequencer_client.send_tx_private(tx).await?, - shared_secret, - )) - } else { - Err(ExecutionFailureKind::InsufficientFundsError) - } + self.deshielded_tx_two_accs(from, to, instruction_data, tx_pre_check, program) + .await } } diff --git a/wallet/src/token_transfers/mod.rs b/wallet/src/token_transfers/mod.rs index edfbe3e..e87ce9a 100644 --- a/wallet/src/token_transfers/mod.rs +++ b/wallet/src/token_transfers/mod.rs @@ -1,4 +1,32 @@ +use common::ExecutionFailureKind; +use nssa::{Account, program::Program}; +use nssa_core::program::InstructionData; + +use crate::WalletCore; + pub mod deshielded; pub mod private; pub mod public; pub mod shielded; + +impl WalletCore { + pub fn auth_transfer_preparation( + balance_to_move: u128, + ) -> ( + InstructionData, + Program, + impl FnOnce(&Account, &Account) -> Result<(), ExecutionFailureKind>, + ) { + let instruction_data = Program::serialize_instruction(balance_to_move).unwrap(); + let program = Program::authenticated_transfer_program(); + let tx_pre_check = move |from: &Account, _: &Account| { + if from.balance >= balance_to_move { + Ok(()) + } else { + Err(ExecutionFailureKind::InsufficientFundsError) + } + }; + + (instruction_data, program, tx_pre_check) + } +} diff --git a/wallet/src/token_transfers/private.rs b/wallet/src/token_transfers/private.rs index 0c6751b..35a9145 100644 --- a/wallet/src/token_transfers/private.rs +++ b/wallet/src/token_transfers/private.rs @@ -1,16 +1,10 @@ use common::{ExecutionFailureKind, sequencer_client::json::SendTxResponse}; -use key_protocol::key_management::ephemeral_key_holder::EphemeralKeyHolder; -use nssa::{ - Address, PrivacyPreservingTransaction, - privacy_preserving_transaction::{circuit, message::Message, witness_set::WitnessSet}, - program::Program, -}; +use nssa::Address; use nssa_core::{ - Commitment, MembershipProof, NullifierPublicKey, SharedSecretKey, account::AccountWithMetadata, - encryption::IncomingViewingPublicKey, + MembershipProof, NullifierPublicKey, SharedSecretKey, encryption::IncomingViewingPublicKey, }; -use crate::{WalletCore, helperfunctions::produce_random_nonces}; +use crate::WalletCore; impl WalletCore { pub async fn send_private_native_token_transfer_outer_account( @@ -20,82 +14,31 @@ impl WalletCore { to_ipk: IncomingViewingPublicKey, balance_to_move: u128, ) -> Result<(SendTxResponse, [SharedSecretKey; 2]), ExecutionFailureKind> { - let Some((from_keys, from_acc)) = - self.storage.user_data.get_private_account(&from).cloned() - else { - return Err(ExecutionFailureKind::KeyNotFoundError); - }; + let (instruction_data, program, tx_pre_check) = + WalletCore::auth_transfer_preparation(balance_to_move); - let to_acc = nssa_core::account::Account::default(); + self.private_tx_two_accs_receiver_outer( + from, + to_npk, + to_ipk, + instruction_data, + tx_pre_check, + program, + ) + .await + } - if from_acc.balance >= balance_to_move { - let program = Program::authenticated_transfer_program(); + pub async fn send_private_native_token_transfer_owned_account_not_initialized( + &self, + from: Address, + to: Address, + balance_to_move: u128, + ) -> Result<(SendTxResponse, [SharedSecretKey; 2]), ExecutionFailureKind> { + let (instruction_data, program, tx_pre_check) = + WalletCore::auth_transfer_preparation(balance_to_move); - let from_npk = from_keys.nullifer_public_key; - let from_ipk = from_keys.incoming_viewing_public_key; - - let sender_commitment = Commitment::new(&from_npk, &from_acc); - - let sender_pre = AccountWithMetadata::new(from_acc.clone(), true, &from_npk); - - let recipient_pre = AccountWithMetadata::new(to_acc.clone(), false, &to_npk); - - let eph_holder = EphemeralKeyHolder::new(&to_npk); - - let shared_secret_from = eph_holder.calculate_shared_secret_sender(&from_ipk); - let shared_secret_to = eph_holder.calculate_shared_secret_sender(&to_ipk); - - let (output, proof) = circuit::execute_and_prove( - &[sender_pre, recipient_pre], - &Program::serialize_instruction(balance_to_move).unwrap(), - &[1, 2], - &produce_random_nonces(2), - &[ - (from_npk.clone(), shared_secret_from.clone()), - (to_npk.clone(), shared_secret_to.clone()), - ], - &[( - from_keys.private_key_holder.nullifier_secret_key, - self.sequencer_client - .get_proof_for_commitment(sender_commitment) - .await - .unwrap() - .unwrap(), - )], - &program, - ) - .unwrap(); - - let message = Message::try_from_circuit_output( - vec![], - vec![], - vec![ - ( - from_npk.clone(), - from_ipk.clone(), - eph_holder.generate_ephemeral_public_key(), - ), - ( - to_npk.clone(), - to_ipk.clone(), - eph_holder.generate_ephemeral_public_key(), - ), - ], - output, - ) - .unwrap(); - - let witness_set = WitnessSet::for_message(&message, proof, &[]); - - let tx = PrivacyPreservingTransaction::new(message, witness_set); - - Ok(( - self.sequencer_client.send_tx_private(tx).await?, - [shared_secret_from, shared_secret_to], - )) - } else { - Err(ExecutionFailureKind::InsufficientFundsError) - } + self.private_tx_two_accs_receiver_uninit(from, to, instruction_data, tx_pre_check, program) + .await } pub async fn send_private_native_token_transfer_owned_account_already_initialized( @@ -105,176 +48,17 @@ impl WalletCore { balance_to_move: u128, to_proof: MembershipProof, ) -> Result<(SendTxResponse, [SharedSecretKey; 2]), ExecutionFailureKind> { - let Some((from_keys, from_acc)) = - self.storage.user_data.get_private_account(&from).cloned() - else { - return Err(ExecutionFailureKind::KeyNotFoundError); - }; + let (instruction_data, program, tx_pre_check) = + WalletCore::auth_transfer_preparation(balance_to_move); - let Some((to_keys, to_acc)) = self.storage.user_data.get_private_account(&to).cloned() - else { - return Err(ExecutionFailureKind::KeyNotFoundError); - }; - - let from_npk = from_keys.nullifer_public_key; - let from_ipk = from_keys.incoming_viewing_public_key; - let to_npk = to_keys.nullifer_public_key.clone(); - let to_ipk = to_keys.incoming_viewing_public_key.clone(); - - if from_acc.balance >= balance_to_move { - let program = Program::authenticated_transfer_program(); - - let sender_commitment = Commitment::new(&from_npk, &from_acc); - - let sender_pre = AccountWithMetadata::new(from_acc.clone(), true, &from_npk); - let recipient_pre = AccountWithMetadata::new(to_acc.clone(), true, &to_npk); - - let eph_holder_from = EphemeralKeyHolder::new(&from_npk); - let shared_secret_from = eph_holder_from.calculate_shared_secret_sender(&from_ipk); - - let eph_holder_to = EphemeralKeyHolder::new(&to_npk); - let shared_secret_to = eph_holder_to.calculate_shared_secret_sender(&to_ipk); - - let (output, proof) = circuit::execute_and_prove( - &[sender_pre, recipient_pre], - &Program::serialize_instruction(balance_to_move).unwrap(), - &[1, 1], - &produce_random_nonces(2), - &[ - (from_npk.clone(), shared_secret_from.clone()), - (to_npk.clone(), shared_secret_to.clone()), - ], - &[ - ( - from_keys.private_key_holder.nullifier_secret_key, - self.sequencer_client - .get_proof_for_commitment(sender_commitment) - .await - .unwrap() - .unwrap(), - ), - (to_keys.private_key_holder.nullifier_secret_key, to_proof), - ], - &program, - ) - .unwrap(); - - let message = Message::try_from_circuit_output( - vec![], - vec![], - vec![ - ( - from_npk.clone(), - from_ipk.clone(), - eph_holder_from.generate_ephemeral_public_key(), - ), - ( - to_npk.clone(), - to_ipk.clone(), - eph_holder_to.generate_ephemeral_public_key(), - ), - ], - output, - ) - .unwrap(); - - let witness_set = WitnessSet::for_message(&message, proof, &[]); - let tx = PrivacyPreservingTransaction::new(message, witness_set); - - Ok(( - self.sequencer_client.send_tx_private(tx).await?, - [shared_secret_from, shared_secret_to], - )) - } else { - Err(ExecutionFailureKind::InsufficientFundsError) - } - } - - pub async fn send_private_native_token_transfer_owned_account_not_initialized( - &self, - from: Address, - to: Address, - balance_to_move: u128, - ) -> Result<(SendTxResponse, [SharedSecretKey; 2]), ExecutionFailureKind> { - let Some((from_keys, from_acc)) = - self.storage.user_data.get_private_account(&from).cloned() - else { - return Err(ExecutionFailureKind::KeyNotFoundError); - }; - - let Some((to_keys, to_acc)) = self.storage.user_data.get_private_account(&to).cloned() - else { - return Err(ExecutionFailureKind::KeyNotFoundError); - }; - - let from_npk = from_keys.nullifer_public_key; - let from_ipk = from_keys.incoming_viewing_public_key; - let to_npk = to_keys.nullifer_public_key.clone(); - let to_ipk = to_keys.incoming_viewing_public_key.clone(); - - if from_acc.balance >= balance_to_move { - let program = Program::authenticated_transfer_program(); - - let sender_commitment = Commitment::new(&from_npk, &from_acc); - - let sender_pre = AccountWithMetadata::new(from_acc.clone(), true, &from_npk); - let recipient_pre = AccountWithMetadata::new(to_acc.clone(), false, &to_npk); - - let eph_holder_from = EphemeralKeyHolder::new(&from_npk); - let shared_secret_from = eph_holder_from.calculate_shared_secret_sender(&from_ipk); - - let eph_holder_to = EphemeralKeyHolder::new(&to_npk); - let shared_secret_to = eph_holder_to.calculate_shared_secret_sender(&to_ipk); - - let (output, proof) = circuit::execute_and_prove( - &[sender_pre, recipient_pre], - &Program::serialize_instruction(balance_to_move).unwrap(), - &[1, 2], - &produce_random_nonces(2), - &[ - (from_npk.clone(), shared_secret_from.clone()), - (to_npk.clone(), shared_secret_to.clone()), - ], - &[( - from_keys.private_key_holder.nullifier_secret_key, - self.sequencer_client - .get_proof_for_commitment(sender_commitment) - .await - .unwrap() - .unwrap(), - )], - &program, - ) - .unwrap(); - - let message = Message::try_from_circuit_output( - vec![], - vec![], - vec![ - ( - from_npk.clone(), - from_ipk.clone(), - eph_holder_from.generate_ephemeral_public_key(), - ), - ( - to_npk.clone(), - to_ipk.clone(), - eph_holder_to.generate_ephemeral_public_key(), - ), - ], - output, - ) - .unwrap(); - - let witness_set = WitnessSet::for_message(&message, proof, &[]); - let tx = PrivacyPreservingTransaction::new(message, witness_set); - - Ok(( - self.sequencer_client.send_tx_private(tx).await?, - [shared_secret_from, shared_secret_to], - )) - } else { - Err(ExecutionFailureKind::InsufficientFundsError) - } + self.private_tx_two_accs_all_init( + from, + to, + instruction_data, + tx_pre_check, + program, + to_proof, + ) + .await } } diff --git a/wallet/src/token_transfers/shielded.rs b/wallet/src/token_transfers/shielded.rs index 8fabedd..ce7c0d3 100644 --- a/wallet/src/token_transfers/shielded.rs +++ b/wallet/src/token_transfers/shielded.rs @@ -1,16 +1,10 @@ use common::{ExecutionFailureKind, sequencer_client::json::SendTxResponse}; -use key_protocol::key_management::ephemeral_key_holder::EphemeralKeyHolder; -use nssa::{ - Account, Address, PrivacyPreservingTransaction, - privacy_preserving_transaction::{circuit, message::Message, witness_set::WitnessSet}, - program::Program, -}; +use nssa::Address; use nssa_core::{ - MembershipProof, NullifierPublicKey, SharedSecretKey, account::AccountWithMetadata, - encryption::IncomingViewingPublicKey, + MembershipProof, NullifierPublicKey, SharedSecretKey, encryption::IncomingViewingPublicKey, }; -use crate::{WalletCore, helperfunctions::produce_random_nonces}; +use crate::WalletCore; impl WalletCore { pub async fn send_shielded_native_token_transfer_already_initialized( @@ -19,68 +13,12 @@ impl WalletCore { to: Address, balance_to_move: u128, to_proof: MembershipProof, - ) -> Result<(SendTxResponse, SharedSecretKey), ExecutionFailureKind> { - let Ok(from_acc) = self.get_account_public(from).await else { - return Err(ExecutionFailureKind::KeyNotFoundError); - }; + ) -> Result<(SendTxResponse, [SharedSecretKey; 1]), ExecutionFailureKind> { + let (instruction_data, program, tx_pre_check) = + WalletCore::auth_transfer_preparation(balance_to_move); - let Some((to_keys, to_acc)) = self.storage.user_data.get_private_account(&to).cloned() - else { - return Err(ExecutionFailureKind::KeyNotFoundError); - }; - - let to_npk = to_keys.nullifer_public_key.clone(); - let to_ipk = to_keys.incoming_viewing_public_key.clone(); - - if from_acc.balance >= balance_to_move { - let program = Program::authenticated_transfer_program(); - - let sender_pre = AccountWithMetadata::new(from_acc.clone(), true, from); - let recipient_pre = AccountWithMetadata::new(to_acc.clone(), true, &to_npk); - - let eph_holder = EphemeralKeyHolder::new(&to_npk); - let shared_secret = eph_holder.calculate_shared_secret_sender(&to_ipk); - - let (output, proof) = circuit::execute_and_prove( - &[sender_pre, recipient_pre], - &nssa::program::Program::serialize_instruction(balance_to_move).unwrap(), - &[0, 1], - &produce_random_nonces(1), - &[(to_npk.clone(), shared_secret.clone())], - &[(to_keys.private_key_holder.nullifier_secret_key, to_proof)], - &program, - ) - .unwrap(); - - let message = Message::try_from_circuit_output( - vec![from], - vec![from_acc.nonce], - vec![( - to_npk.clone(), - to_ipk.clone(), - eph_holder.generate_ephemeral_public_key(), - )], - output, - ) - .unwrap(); - - let signing_key = self.storage.user_data.get_pub_account_signing_key(&from); - - let Some(signing_key) = signing_key else { - return Err(ExecutionFailureKind::KeyNotFoundError); - }; - - let witness_set = WitnessSet::for_message(&message, proof, &[signing_key]); - - let tx = PrivacyPreservingTransaction::new(message, witness_set); - - Ok(( - self.sequencer_client.send_tx_private(tx).await?, - shared_secret, - )) - } else { - Err(ExecutionFailureKind::InsufficientFundsError) - } + self.shielded_two_accs_all_init(from, to, instruction_data, tx_pre_check, program, to_proof) + .await } pub async fn send_shielded_native_token_transfer_not_initialized( @@ -88,68 +26,12 @@ impl WalletCore { from: Address, to: Address, balance_to_move: u128, - ) -> Result<(SendTxResponse, SharedSecretKey), ExecutionFailureKind> { - let Ok(from_acc) = self.get_account_public(from).await else { - return Err(ExecutionFailureKind::KeyNotFoundError); - }; + ) -> Result<(SendTxResponse, [SharedSecretKey; 1]), ExecutionFailureKind> { + let (instruction_data, program, tx_pre_check) = + WalletCore::auth_transfer_preparation(balance_to_move); - let Some((to_keys, to_acc)) = self.storage.user_data.get_private_account(&to).cloned() - else { - return Err(ExecutionFailureKind::KeyNotFoundError); - }; - - let to_npk = to_keys.nullifer_public_key.clone(); - let to_ipk = to_keys.incoming_viewing_public_key.clone(); - - if from_acc.balance >= balance_to_move { - let program = Program::authenticated_transfer_program(); - - let sender_pre = AccountWithMetadata::new(from_acc.clone(), true, from); - let recipient_pre = AccountWithMetadata::new(to_acc.clone(), false, &to_npk); - - let eph_holder = EphemeralKeyHolder::new(&to_npk); - let shared_secret = eph_holder.calculate_shared_secret_sender(&to_ipk); - - let (output, proof) = circuit::execute_and_prove( - &[sender_pre, recipient_pre], - &nssa::program::Program::serialize_instruction(balance_to_move).unwrap(), - &[0, 2], - &produce_random_nonces(1), - &[(to_npk.clone(), shared_secret.clone())], - &[], - &program, - ) - .unwrap(); - - let message = Message::try_from_circuit_output( - vec![from], - vec![from_acc.nonce], - vec![( - to_npk.clone(), - to_ipk.clone(), - eph_holder.generate_ephemeral_public_key(), - )], - output, - ) - .unwrap(); - - let signing_key = self.storage.user_data.get_pub_account_signing_key(&from); - - let Some(signing_key) = signing_key else { - return Err(ExecutionFailureKind::KeyNotFoundError); - }; - - let witness_set = WitnessSet::for_message(&message, proof, &[signing_key]); - - let tx = PrivacyPreservingTransaction::new(message, witness_set); - - Ok(( - self.sequencer_client.send_tx_private(tx).await?, - shared_secret, - )) - } else { - Err(ExecutionFailureKind::InsufficientFundsError) - } + self.shielded_two_accs_receiver_uninit(from, to, instruction_data, tx_pre_check, program) + .await } pub async fn send_shielded_native_token_transfer_outer_account( @@ -158,60 +40,18 @@ impl WalletCore { to_npk: NullifierPublicKey, to_ipk: IncomingViewingPublicKey, balance_to_move: u128, - ) -> Result<(SendTxResponse, SharedSecretKey), ExecutionFailureKind> { - let Ok(from_acc) = self.get_account_public(from).await else { - return Err(ExecutionFailureKind::KeyNotFoundError); - }; + ) -> Result { + let (instruction_data, program, tx_pre_check) = + WalletCore::auth_transfer_preparation(balance_to_move); - let to_acc = Account::default(); - - if from_acc.balance >= balance_to_move { - let program = Program::authenticated_transfer_program(); - - let sender_pre = AccountWithMetadata::new(from_acc.clone(), true, from); - let recipient_pre = AccountWithMetadata::new(to_acc.clone(), false, &to_npk); - - let eph_holder = EphemeralKeyHolder::new(&to_npk); - let shared_secret = eph_holder.calculate_shared_secret_sender(&to_ipk); - - let (output, proof) = circuit::execute_and_prove( - &[sender_pre, recipient_pre], - &Program::serialize_instruction(balance_to_move).unwrap(), - &[0, 2], - &produce_random_nonces(1), - &[(to_npk.clone(), shared_secret.clone())], - &[], - &program, - ) - .unwrap(); - - let message = Message::try_from_circuit_output( - vec![from], - vec![from_acc.nonce], - vec![( - to_npk.clone(), - to_ipk.clone(), - eph_holder.generate_ephemeral_public_key(), - )], - output, - ) - .unwrap(); - - let signing_key = self.storage.user_data.get_pub_account_signing_key(&from); - - let Some(signing_key) = signing_key else { - return Err(ExecutionFailureKind::KeyNotFoundError); - }; - - let witness_set = WitnessSet::for_message(&message, proof, &[signing_key]); - let tx = PrivacyPreservingTransaction::new(message, witness_set); - - Ok(( - self.sequencer_client.send_tx_private(tx).await?, - shared_secret, - )) - } else { - Err(ExecutionFailureKind::InsufficientFundsError) - } + self.shielded_two_accs_receiver_outer( + from, + to_npk, + to_ipk, + instruction_data, + tx_pre_check, + program, + ) + .await } } diff --git a/wallet/src/transaction_utils.rs b/wallet/src/transaction_utils.rs new file mode 100644 index 0000000..355b908 --- /dev/null +++ b/wallet/src/transaction_utils.rs @@ -0,0 +1,538 @@ +use common::{ExecutionFailureKind, sequencer_client::json::SendTxResponse}; +use key_protocol::key_management::ephemeral_key_holder::EphemeralKeyHolder; +use nssa::{ + Account, Address, PrivacyPreservingTransaction, + privacy_preserving_transaction::{circuit, message::Message, witness_set::WitnessSet}, + program::Program, +}; +use nssa_core::{ + Commitment, MembershipProof, NullifierPublicKey, SharedSecretKey, account::AccountWithMetadata, + encryption::IncomingViewingPublicKey, program::InstructionData, +}; + +use crate::{WalletCore, helperfunctions::produce_random_nonces}; + +impl WalletCore { + pub(crate) async fn private_tx_two_accs_all_init( + &self, + from: Address, + to: Address, + instruction_data: InstructionData, + tx_pre_check: impl FnOnce(&Account, &Account) -> Result<(), ExecutionFailureKind>, + program: Program, + to_proof: MembershipProof, + ) -> Result<(SendTxResponse, [SharedSecretKey; 2]), ExecutionFailureKind> { + let Some((from_keys, from_acc)) = + self.storage.user_data.get_private_account(&from).cloned() + else { + return Err(ExecutionFailureKind::KeyNotFoundError); + }; + + let Some((to_keys, to_acc)) = self.storage.user_data.get_private_account(&to).cloned() + else { + return Err(ExecutionFailureKind::KeyNotFoundError); + }; + + tx_pre_check(&from_acc, &to_acc)?; + + let from_npk = from_keys.nullifer_public_key; + let from_ipk = from_keys.incoming_viewing_public_key; + let to_npk = to_keys.nullifer_public_key.clone(); + let to_ipk = to_keys.incoming_viewing_public_key.clone(); + + let sender_commitment = Commitment::new(&from_npk, &from_acc); + + let sender_pre = AccountWithMetadata::new(from_acc.clone(), true, &from_npk); + let recipient_pre = AccountWithMetadata::new(to_acc.clone(), true, &to_npk); + + let eph_holder_from = EphemeralKeyHolder::new(&from_npk); + let shared_secret_from = eph_holder_from.calculate_shared_secret_sender(&from_ipk); + + let eph_holder_to = EphemeralKeyHolder::new(&to_npk); + let shared_secret_to = eph_holder_to.calculate_shared_secret_sender(&to_ipk); + + let (output, proof) = circuit::execute_and_prove( + &[sender_pre, recipient_pre], + &instruction_data, + &[1, 1], + &produce_random_nonces(2), + &[ + (from_npk.clone(), shared_secret_from.clone()), + (to_npk.clone(), shared_secret_to.clone()), + ], + &[ + ( + from_keys.private_key_holder.nullifier_secret_key, + self.sequencer_client + .get_proof_for_commitment(sender_commitment) + .await + .unwrap() + .unwrap(), + ), + (to_keys.private_key_holder.nullifier_secret_key, to_proof), + ], + &program, + ) + .unwrap(); + + let message = Message::try_from_circuit_output( + vec![], + vec![], + vec![ + ( + from_npk.clone(), + from_ipk.clone(), + eph_holder_from.generate_ephemeral_public_key(), + ), + ( + to_npk.clone(), + to_ipk.clone(), + eph_holder_to.generate_ephemeral_public_key(), + ), + ], + output, + ) + .unwrap(); + + let witness_set = WitnessSet::for_message(&message, proof, &[]); + let tx = PrivacyPreservingTransaction::new(message, witness_set); + + Ok(( + self.sequencer_client.send_tx_private(tx).await?, + [shared_secret_from, shared_secret_to], + )) + } + + pub(crate) async fn private_tx_two_accs_receiver_uninit( + &self, + from: Address, + to: Address, + instruction_data: InstructionData, + tx_pre_check: impl FnOnce(&Account, &Account) -> Result<(), ExecutionFailureKind>, + program: Program, + ) -> Result<(SendTxResponse, [SharedSecretKey; 2]), ExecutionFailureKind> { + let Some((from_keys, from_acc)) = + self.storage.user_data.get_private_account(&from).cloned() + else { + return Err(ExecutionFailureKind::KeyNotFoundError); + }; + + let Some((to_keys, to_acc)) = self.storage.user_data.get_private_account(&to).cloned() + else { + return Err(ExecutionFailureKind::KeyNotFoundError); + }; + + tx_pre_check(&from_acc, &to_acc)?; + + let from_npk = from_keys.nullifer_public_key; + let from_ipk = from_keys.incoming_viewing_public_key; + let to_npk = to_keys.nullifer_public_key.clone(); + let to_ipk = to_keys.incoming_viewing_public_key.clone(); + + let sender_commitment = Commitment::new(&from_npk, &from_acc); + + let sender_pre = AccountWithMetadata::new(from_acc.clone(), true, &from_npk); + let recipient_pre = AccountWithMetadata::new(to_acc.clone(), false, &to_npk); + + let eph_holder_from = EphemeralKeyHolder::new(&from_npk); + let shared_secret_from = eph_holder_from.calculate_shared_secret_sender(&from_ipk); + + let eph_holder_to = EphemeralKeyHolder::new(&to_npk); + let shared_secret_to = eph_holder_to.calculate_shared_secret_sender(&to_ipk); + + let (output, proof) = circuit::execute_and_prove( + &[sender_pre, recipient_pre], + &instruction_data, + &[1, 2], + &produce_random_nonces(2), + &[ + (from_npk.clone(), shared_secret_from.clone()), + (to_npk.clone(), shared_secret_to.clone()), + ], + &[( + from_keys.private_key_holder.nullifier_secret_key, + self.sequencer_client + .get_proof_for_commitment(sender_commitment) + .await + .unwrap() + .unwrap(), + )], + &program, + ) + .unwrap(); + + let message = Message::try_from_circuit_output( + vec![], + vec![], + vec![ + ( + from_npk.clone(), + from_ipk.clone(), + eph_holder_from.generate_ephemeral_public_key(), + ), + ( + to_npk.clone(), + to_ipk.clone(), + eph_holder_to.generate_ephemeral_public_key(), + ), + ], + output, + ) + .unwrap(); + + let witness_set = WitnessSet::for_message(&message, proof, &[]); + let tx = PrivacyPreservingTransaction::new(message, witness_set); + + Ok(( + self.sequencer_client.send_tx_private(tx).await?, + [shared_secret_from, shared_secret_to], + )) + } + + pub(crate) async fn private_tx_two_accs_receiver_outer( + &self, + from: Address, + to_npk: NullifierPublicKey, + to_ipk: IncomingViewingPublicKey, + instruction_data: InstructionData, + tx_pre_check: impl FnOnce(&Account, &Account) -> Result<(), ExecutionFailureKind>, + program: Program, + ) -> Result<(SendTxResponse, [SharedSecretKey; 2]), ExecutionFailureKind> { + let Some((from_keys, from_acc)) = + self.storage.user_data.get_private_account(&from).cloned() + else { + return Err(ExecutionFailureKind::KeyNotFoundError); + }; + + let to_acc = nssa_core::account::Account::default(); + + tx_pre_check(&from_acc, &to_acc)?; + + let from_npk = from_keys.nullifer_public_key; + let from_ipk = from_keys.incoming_viewing_public_key; + + let sender_commitment = Commitment::new(&from_npk, &from_acc); + + let sender_pre = AccountWithMetadata::new(from_acc.clone(), true, &from_npk); + + let recipient_pre = AccountWithMetadata::new(to_acc.clone(), false, &to_npk); + + let eph_holder = EphemeralKeyHolder::new(&to_npk); + + let shared_secret_from = eph_holder.calculate_shared_secret_sender(&from_ipk); + let shared_secret_to = eph_holder.calculate_shared_secret_sender(&to_ipk); + + let (output, proof) = circuit::execute_and_prove( + &[sender_pre, recipient_pre], + &instruction_data, + &[1, 2], + &produce_random_nonces(2), + &[ + (from_npk.clone(), shared_secret_from.clone()), + (to_npk.clone(), shared_secret_to.clone()), + ], + &[( + from_keys.private_key_holder.nullifier_secret_key, + self.sequencer_client + .get_proof_for_commitment(sender_commitment) + .await + .unwrap() + .unwrap(), + )], + &program, + ) + .unwrap(); + + let message = Message::try_from_circuit_output( + vec![], + vec![], + vec![ + ( + from_npk.clone(), + from_ipk.clone(), + eph_holder.generate_ephemeral_public_key(), + ), + ( + to_npk.clone(), + to_ipk.clone(), + eph_holder.generate_ephemeral_public_key(), + ), + ], + output, + ) + .unwrap(); + + let witness_set = WitnessSet::for_message(&message, proof, &[]); + + let tx = PrivacyPreservingTransaction::new(message, witness_set); + + Ok(( + self.sequencer_client.send_tx_private(tx).await?, + [shared_secret_from, shared_secret_to], + )) + } + + pub(crate) async fn deshielded_tx_two_accs( + &self, + from: Address, + to: Address, + instruction_data: InstructionData, + tx_pre_check: impl FnOnce(&Account, &Account) -> Result<(), ExecutionFailureKind>, + program: Program, + ) -> Result<(SendTxResponse, [nssa_core::SharedSecretKey; 1]), ExecutionFailureKind> { + let Some((from_keys, from_acc)) = + self.storage.user_data.get_private_account(&from).cloned() + else { + return Err(ExecutionFailureKind::KeyNotFoundError); + }; + + let Ok(to_acc) = self.get_account_public(to).await else { + return Err(ExecutionFailureKind::KeyNotFoundError); + }; + + tx_pre_check(&from_acc, &to_acc)?; + + let npk_from = from_keys.nullifer_public_key; + let ipk_from = from_keys.incoming_viewing_public_key; + + let sender_commitment = Commitment::new(&npk_from, &from_acc); + + let sender_pre = AccountWithMetadata::new(from_acc.clone(), true, &npk_from); + let recipient_pre = AccountWithMetadata::new(to_acc.clone(), false, to); + + let eph_holder = EphemeralKeyHolder::new(&npk_from); + let shared_secret = eph_holder.calculate_shared_secret_sender(&ipk_from); + + let (output, proof) = circuit::execute_and_prove( + &[sender_pre, recipient_pre], + &instruction_data, + &[1, 0], + &produce_random_nonces(1), + &[(npk_from.clone(), shared_secret.clone())], + &[( + from_keys.private_key_holder.nullifier_secret_key, + self.sequencer_client + .get_proof_for_commitment(sender_commitment) + .await + .unwrap() + .unwrap(), + )], + &program, + ) + .unwrap(); + + let message = Message::try_from_circuit_output( + vec![to], + vec![], + vec![( + npk_from.clone(), + ipk_from.clone(), + eph_holder.generate_ephemeral_public_key(), + )], + output, + ) + .unwrap(); + + let witness_set = WitnessSet::for_message(&message, proof, &[]); + + let tx = PrivacyPreservingTransaction::new(message, witness_set); + + Ok(( + self.sequencer_client.send_tx_private(tx).await?, + [shared_secret], + )) + } + + pub(crate) async fn shielded_two_accs_all_init( + &self, + from: Address, + to: Address, + instruction_data: InstructionData, + tx_pre_check: impl FnOnce(&Account, &Account) -> Result<(), ExecutionFailureKind>, + program: Program, + to_proof: MembershipProof, + ) -> Result<(SendTxResponse, [SharedSecretKey; 1]), ExecutionFailureKind> { + let Ok(from_acc) = self.get_account_public(from).await else { + return Err(ExecutionFailureKind::KeyNotFoundError); + }; + + let Some((to_keys, to_acc)) = self.storage.user_data.get_private_account(&to).cloned() + else { + return Err(ExecutionFailureKind::KeyNotFoundError); + }; + + let to_npk = to_keys.nullifer_public_key.clone(); + let to_ipk = to_keys.incoming_viewing_public_key.clone(); + + tx_pre_check(&from_acc, &to_acc)?; + + let sender_pre = AccountWithMetadata::new(from_acc.clone(), true, from); + let recipient_pre = AccountWithMetadata::new(to_acc.clone(), true, &to_npk); + + let eph_holder = EphemeralKeyHolder::new(&to_npk); + let shared_secret = eph_holder.calculate_shared_secret_sender(&to_ipk); + + let (output, proof) = circuit::execute_and_prove( + &[sender_pre, recipient_pre], + &instruction_data, + &[0, 1], + &produce_random_nonces(1), + &[(to_npk.clone(), shared_secret.clone())], + &[(to_keys.private_key_holder.nullifier_secret_key, to_proof)], + &program, + ) + .unwrap(); + + let message = Message::try_from_circuit_output( + vec![from], + vec![from_acc.nonce], + vec![( + to_npk.clone(), + to_ipk.clone(), + eph_holder.generate_ephemeral_public_key(), + )], + output, + ) + .unwrap(); + + let signing_key = self.storage.user_data.get_pub_account_signing_key(&from); + + let Some(signing_key) = signing_key else { + return Err(ExecutionFailureKind::KeyNotFoundError); + }; + + let witness_set = WitnessSet::for_message(&message, proof, &[signing_key]); + + let tx = PrivacyPreservingTransaction::new(message, witness_set); + + Ok(( + self.sequencer_client.send_tx_private(tx).await?, + [shared_secret], + )) + } + + pub(crate) async fn shielded_two_accs_receiver_uninit( + &self, + from: Address, + to: Address, + instruction_data: InstructionData, + tx_pre_check: impl FnOnce(&Account, &Account) -> Result<(), ExecutionFailureKind>, + program: Program, + ) -> Result<(SendTxResponse, [SharedSecretKey; 1]), ExecutionFailureKind> { + let Ok(from_acc) = self.get_account_public(from).await else { + return Err(ExecutionFailureKind::KeyNotFoundError); + }; + + let Some((to_keys, to_acc)) = self.storage.user_data.get_private_account(&to).cloned() + else { + return Err(ExecutionFailureKind::KeyNotFoundError); + }; + + let to_npk = to_keys.nullifer_public_key.clone(); + let to_ipk = to_keys.incoming_viewing_public_key.clone(); + + tx_pre_check(&from_acc, &to_acc)?; + + let sender_pre = AccountWithMetadata::new(from_acc.clone(), true, from); + let recipient_pre = AccountWithMetadata::new(to_acc.clone(), false, &to_npk); + + let eph_holder = EphemeralKeyHolder::new(&to_npk); + let shared_secret = eph_holder.calculate_shared_secret_sender(&to_ipk); + + let (output, proof) = circuit::execute_and_prove( + &[sender_pre, recipient_pre], + &instruction_data, + &[0, 2], + &produce_random_nonces(1), + &[(to_npk.clone(), shared_secret.clone())], + &[], + &program, + ) + .unwrap(); + + let message = Message::try_from_circuit_output( + vec![from], + vec![from_acc.nonce], + vec![( + to_npk.clone(), + to_ipk.clone(), + eph_holder.generate_ephemeral_public_key(), + )], + output, + ) + .unwrap(); + + let signing_key = self.storage.user_data.get_pub_account_signing_key(&from); + + let Some(signing_key) = signing_key else { + return Err(ExecutionFailureKind::KeyNotFoundError); + }; + + let witness_set = WitnessSet::for_message(&message, proof, &[signing_key]); + + let tx = PrivacyPreservingTransaction::new(message, witness_set); + + Ok(( + self.sequencer_client.send_tx_private(tx).await?, + [shared_secret], + )) + } + + pub(crate) async fn shielded_two_accs_receiver_outer( + &self, + from: Address, + to_npk: NullifierPublicKey, + to_ipk: IncomingViewingPublicKey, + instruction_data: InstructionData, + tx_pre_check: impl FnOnce(&Account, &Account) -> Result<(), ExecutionFailureKind>, + program: Program, + ) -> Result { + let Ok(from_acc) = self.get_account_public(from).await else { + return Err(ExecutionFailureKind::KeyNotFoundError); + }; + + let to_acc = Account::default(); + + tx_pre_check(&from_acc, &to_acc)?; + + let sender_pre = AccountWithMetadata::new(from_acc.clone(), true, from); + let recipient_pre = AccountWithMetadata::new(to_acc.clone(), false, &to_npk); + + let eph_holder = EphemeralKeyHolder::new(&to_npk); + let shared_secret = eph_holder.calculate_shared_secret_sender(&to_ipk); + + let (output, proof) = circuit::execute_and_prove( + &[sender_pre, recipient_pre], + &instruction_data, + &[0, 2], + &produce_random_nonces(1), + &[(to_npk.clone(), shared_secret.clone())], + &[], + &program, + ) + .unwrap(); + + let message = Message::try_from_circuit_output( + vec![from], + vec![from_acc.nonce], + vec![( + to_npk.clone(), + to_ipk.clone(), + eph_holder.generate_ephemeral_public_key(), + )], + output, + ) + .unwrap(); + + let signing_key = self.storage.user_data.get_pub_account_signing_key(&from); + + let Some(signing_key) = signing_key else { + return Err(ExecutionFailureKind::KeyNotFoundError); + }; + + let witness_set = WitnessSet::for_message(&message, proof, &[signing_key]); + let tx = PrivacyPreservingTransaction::new(message, witness_set); + + Ok(self.sequencer_client.send_tx_private(tx).await?) + } +}