diff --git a/artifacts/program_methods/amm.bin b/artifacts/program_methods/amm.bin index a8ca1f4e..f058acd6 100644 Binary files a/artifacts/program_methods/amm.bin and b/artifacts/program_methods/amm.bin differ diff --git a/artifacts/program_methods/authenticated_transfer.bin b/artifacts/program_methods/authenticated_transfer.bin index 0bc3de67..88ddb2c5 100644 Binary files a/artifacts/program_methods/authenticated_transfer.bin and b/artifacts/program_methods/authenticated_transfer.bin differ diff --git a/artifacts/program_methods/pinata.bin b/artifacts/program_methods/pinata.bin index 64aaa346..bf6b7a5e 100644 Binary files a/artifacts/program_methods/pinata.bin and b/artifacts/program_methods/pinata.bin differ diff --git a/artifacts/program_methods/pinata_token.bin b/artifacts/program_methods/pinata_token.bin index a47d90f4..c4b23989 100644 Binary files a/artifacts/program_methods/pinata_token.bin and b/artifacts/program_methods/pinata_token.bin differ diff --git a/artifacts/program_methods/privacy_preserving_circuit.bin b/artifacts/program_methods/privacy_preserving_circuit.bin index 8e151aa7..4a7b82c0 100644 Binary files a/artifacts/program_methods/privacy_preserving_circuit.bin and b/artifacts/program_methods/privacy_preserving_circuit.bin differ diff --git a/artifacts/program_methods/token.bin b/artifacts/program_methods/token.bin index 9a1269c5..7c116318 100644 Binary files a/artifacts/program_methods/token.bin and b/artifacts/program_methods/token.bin differ diff --git a/artifacts/test_program_methods/burner.bin b/artifacts/test_program_methods/burner.bin index b055fbdb..514166ff 100644 Binary files a/artifacts/test_program_methods/burner.bin and b/artifacts/test_program_methods/burner.bin differ diff --git a/artifacts/test_program_methods/chain_caller.bin b/artifacts/test_program_methods/chain_caller.bin index c650f1f9..6e3c3ae4 100644 Binary files a/artifacts/test_program_methods/chain_caller.bin and b/artifacts/test_program_methods/chain_caller.bin differ diff --git a/artifacts/test_program_methods/changer_claimer.bin b/artifacts/test_program_methods/changer_claimer.bin index 2dea3a0d..9e3a452d 100644 Binary files a/artifacts/test_program_methods/changer_claimer.bin and b/artifacts/test_program_methods/changer_claimer.bin differ diff --git a/artifacts/test_program_methods/claimer.bin b/artifacts/test_program_methods/claimer.bin index fb881bbc..8b7c04b0 100644 Binary files a/artifacts/test_program_methods/claimer.bin and b/artifacts/test_program_methods/claimer.bin differ diff --git a/artifacts/test_program_methods/data_changer.bin b/artifacts/test_program_methods/data_changer.bin index 5a7a8600..861b7be4 100644 Binary files a/artifacts/test_program_methods/data_changer.bin and b/artifacts/test_program_methods/data_changer.bin differ diff --git a/artifacts/test_program_methods/extra_output.bin b/artifacts/test_program_methods/extra_output.bin index fc8dc194..758ae8a2 100644 Binary files a/artifacts/test_program_methods/extra_output.bin and b/artifacts/test_program_methods/extra_output.bin differ diff --git a/artifacts/test_program_methods/malicious_authorization_changer.bin b/artifacts/test_program_methods/malicious_authorization_changer.bin index 99dcd50f..33e01400 100644 Binary files a/artifacts/test_program_methods/malicious_authorization_changer.bin and b/artifacts/test_program_methods/malicious_authorization_changer.bin differ diff --git a/artifacts/test_program_methods/minter.bin b/artifacts/test_program_methods/minter.bin index 7ea603a5..20781cba 100644 Binary files a/artifacts/test_program_methods/minter.bin and b/artifacts/test_program_methods/minter.bin differ diff --git a/artifacts/test_program_methods/missing_output.bin b/artifacts/test_program_methods/missing_output.bin index 3b2379c7..95b412b6 100644 Binary files a/artifacts/test_program_methods/missing_output.bin and b/artifacts/test_program_methods/missing_output.bin differ diff --git a/artifacts/test_program_methods/modified_transfer.bin b/artifacts/test_program_methods/modified_transfer.bin index 48900c0c..7b7438ee 100644 Binary files a/artifacts/test_program_methods/modified_transfer.bin and b/artifacts/test_program_methods/modified_transfer.bin differ diff --git a/artifacts/test_program_methods/nonce_changer.bin b/artifacts/test_program_methods/nonce_changer.bin index b5ef1b9a..97b23f93 100644 Binary files a/artifacts/test_program_methods/nonce_changer.bin and b/artifacts/test_program_methods/nonce_changer.bin differ diff --git a/artifacts/test_program_methods/noop.bin b/artifacts/test_program_methods/noop.bin index c3b1d1d6..e487da6b 100644 Binary files a/artifacts/test_program_methods/noop.bin and b/artifacts/test_program_methods/noop.bin differ diff --git a/artifacts/test_program_methods/program_owner_changer.bin b/artifacts/test_program_methods/program_owner_changer.bin index b697cc70..d318cbda 100644 Binary files a/artifacts/test_program_methods/program_owner_changer.bin and b/artifacts/test_program_methods/program_owner_changer.bin differ diff --git a/artifacts/test_program_methods/simple_balance_transfer.bin b/artifacts/test_program_methods/simple_balance_transfer.bin index b54383e2..ca22e0f5 100644 Binary files a/artifacts/test_program_methods/simple_balance_transfer.bin and b/artifacts/test_program_methods/simple_balance_transfer.bin differ diff --git a/explorer_service/src/components/account_preview.rs b/explorer_service/src/components/account_preview.rs index c40391a8..bbe59c0f 100644 --- a/explorer_service/src/components/account_preview.rs +++ b/explorer_service/src/components/account_preview.rs @@ -31,7 +31,7 @@ pub fn AccountPreview(account_id: AccountId, account: Account) -> impl IntoView
"Nonce: " - {nonce.0.to_string()} + {nonce.to_string()}
"Data: " diff --git a/explorer_service/src/pages/account_page.rs b/explorer_service/src/pages/account_page.rs index fdee3bb6..a02a8b7c 100644 --- a/explorer_service/src/pages/account_page.rs +++ b/explorer_service/src/pages/account_page.rs @@ -97,7 +97,7 @@ pub fn AccountPage() -> impl IntoView { let account_id_str = acc_id.to_string(); let program_id = program_owner.to_string(); let balance_str = balance.to_string(); - let nonce_str = nonce.0.to_string(); + let nonce_str = nonce.to_string(); let data_len = data.0.len(); view! {
diff --git a/explorer_service/src/pages/transaction_page.rs b/explorer_service/src/pages/transaction_page.rs index 41b0d311..211dc505 100644 --- a/explorer_service/src/pages/transaction_page.rs +++ b/explorer_service/src/pages/transaction_page.rs @@ -126,7 +126,7 @@ pub fn TransactionPage() -> impl IntoView { {account_id_str} - " (nonce: " {nonce.0.to_string()} ")" + " (nonce: " {nonce.to_string()} ")"
} @@ -229,7 +229,7 @@ pub fn TransactionPage() -> impl IntoView { {account_id_str} - " (nonce: " {nonce.0.to_string()} ")" + " (nonce: " {nonce.to_string()} ")"
} diff --git a/indexer/service/protocol/src/convert.rs b/indexer/service/protocol/src/convert.rs index cbafa0b3..499baa4c 100644 --- a/indexer/service/protocol/src/convert.rs +++ b/indexer/service/protocol/src/convert.rs @@ -1,5 +1,7 @@ //! Conversions between `indexer_service_protocol` types and `nssa/nssa_core` types. +use nssa_core::account::Nonce; + use crate::{ Account, AccountId, BedrockStatus, Block, BlockBody, BlockHeader, Ciphertext, Commitment, CommitmentSetDigest, Data, EncryptedAccountData, EphemeralPublicKey, HashType, MantleMsgId, @@ -52,7 +54,7 @@ impl From for Account { program_owner: program_owner.into(), balance, data: data.into(), - nonce, + nonce: nonce.0, } } } @@ -72,7 +74,7 @@ impl TryFrom for nssa_core::account::Account { program_owner: program_owner.into(), balance, data: data.try_into()?, - nonce, + nonce: Nonce(nonce), }) } } @@ -250,7 +252,7 @@ impl From for PublicMessage { Self { program_id: program_id.into(), account_ids: account_ids.into_iter().map(Into::into).collect(), - nonces, + nonces: nonces.iter().map(|x| x.0).collect(), instruction_data, } } @@ -267,7 +269,10 @@ impl From for nssa::public_transaction::Message { Self::new_preserialized( program_id.into(), account_ids.into_iter().map(Into::into).collect(), - nonces, + nonces + .iter() + .map(|x| nssa_core::account::Nonce(*x)) + .collect(), instruction_data, ) } @@ -285,7 +290,7 @@ impl From for PrivacyPre } = value; Self { public_account_ids: public_account_ids.into_iter().map(Into::into).collect(), - nonces, + nonces: nonces.iter().map(|x| x.0).collect(), public_post_states: public_post_states.into_iter().map(Into::into).collect(), encrypted_private_post_states: encrypted_private_post_states .into_iter() @@ -314,7 +319,10 @@ impl TryFrom for nssa::privacy_preserving_transaction: } = value; Ok(Self { public_account_ids: public_account_ids.into_iter().map(Into::into).collect(), - nonces, + nonces: nonces + .iter() + .map(|x| nssa_core::account::Nonce(*x)) + .collect(), public_post_states: public_post_states .into_iter() .map(TryInto::try_into) diff --git a/integration_tests/tests/tps.rs b/integration_tests/tests/tps.rs index c89ee761..1dee3a85 100644 --- a/integration_tests/tests/tps.rs +++ b/integration_tests/tests/tps.rs @@ -27,7 +27,7 @@ use nssa::{ }; use nssa_core::{ MembershipProof, NullifierPublicKey, - account::{AccountWithMetadata, data::Data}, + account::{AccountWithMetadata, Nonce, data::Data}, encryption::ViewingPublicKey, }; use tokio::test; @@ -78,7 +78,7 @@ impl TpsTestManager { let message = putx::Message::try_new( program.id(), [pair[0].1, pair[1].1].to_vec(), - [0_u128].to_vec(), + [Nonce(0_u128)].to_vec(), amount, ) .unwrap(); @@ -107,7 +107,7 @@ impl TpsTestManager { let key_chain = KeyChain::new_os_random(); let account = Account { balance: 100, - nonce: 0xdead_beef, + nonce: Nonce(0xdead_beef), program_owner: Program::authenticated_transfer_program().id(), data: Data::default(), }; @@ -216,7 +216,7 @@ fn build_privacy_transaction() -> PrivacyPreservingTransaction { let sender_pre = AccountWithMetadata::new( Account { balance: 100, - nonce: 0xdead_beef, + nonce: Nonce(0xdead_beef), program_owner: program.id(), data: Data::default(), }, @@ -250,7 +250,6 @@ fn build_privacy_transaction() -> PrivacyPreservingTransaction { vec![sender_pre, recipient_pre], Program::serialize_instruction(balance_to_move).unwrap(), vec![1, 2], - vec![0xdead_beef1, 0xdead_beef2], vec![ (sender_npk.clone(), sender_ss), (recipient_npk.clone(), recipient_ss), diff --git a/nssa/core/src/account.rs b/nssa/core/src/account.rs index 29c967f7..fd62628f 100644 --- a/nssa/core/src/account.rs +++ b/nssa/core/src/account.rs @@ -6,7 +6,7 @@ use std::{ use base58::{FromBase58 as _, ToBase58 as _}; use borsh::{BorshDeserialize, BorshSerialize}; pub use data::Data; -use risc0_zkvm::sha::{Impl, Sha256}; +use risc0_zkvm::sha::{Impl, Sha256 as _}; use serde::{Deserialize, Serialize}; use serde_with::{DeserializeFromStr, SerializeDisplay}; @@ -18,27 +18,32 @@ pub mod data; pub struct Nonce(pub u128); impl Nonce { - pub fn public_account_nonce_increment(&mut self) { - self.0 += 1; + pub const fn public_account_nonce_increment(&mut self) { + self.0 = self + .0 + .checked_add(1) + .expect("Overflow when incrementing nonce"); } - pub fn private_account_nonce_init(npk: &NullifierPublicKey) -> Nonce { - let mut bytes: [u8; 64] = [0u8; 64]; + #[must_use] + pub fn private_account_nonce_init(npk: &NullifierPublicKey) -> Self { + let mut bytes: [u8; 64] = [0_u8; 64]; bytes[..32].copy_from_slice(&npk.0); let result: [u8; 32] = Impl::hash_bytes(&bytes).as_bytes().try_into().unwrap(); let result = result.first_chunk::<16>().unwrap(); - Nonce(u128::from_le_bytes(*result)) + Self(u128::from_le_bytes(*result)) } - pub fn private_account_nonce_increment(self, nsk: &NullifierSecretKey) -> Nonce { - let mut bytes: [u8; 64] = [0u8; 64]; + #[must_use] + pub fn private_account_nonce_increment(self, nsk: &NullifierSecretKey) -> Self { + let mut bytes: [u8; 64] = [0_u8; 64]; bytes[..32].copy_from_slice(nsk); bytes[32..48].copy_from_slice(&self.0.to_le_bytes()); let result: [u8; 32] = Impl::hash_bytes(&bytes).as_bytes().try_into().unwrap(); let result = result.first_chunk::<16>().unwrap(); - Nonce(u128::from_le_bytes(*result)) + Self(u128::from_le_bytes(*result)) } } diff --git a/nssa/core/src/encoding.rs b/nssa/core/src/encoding.rs index 2bbbbc8d..f4c7931d 100644 --- a/nssa/core/src/encoding.rs +++ b/nssa/core/src/encoding.rs @@ -26,7 +26,7 @@ impl Account { } bytes.extend_from_slice(&self.balance.to_le_bytes()); bytes.extend_from_slice(&self.nonce.0.to_le_bytes()); - let data_length: u32 = self.data.len() as u32; + let data_length: u32 = u32::try_from(self.data.len()).expect("Invalid u32"); bytes.extend_from_slice(&data_length.to_le_bytes()); bytes.extend_from_slice(self.data.as_ref()); bytes diff --git a/nssa/src/privacy_preserving_transaction/circuit.rs b/nssa/src/privacy_preserving_transaction/circuit.rs index 084b05db..ee312dc5 100644 --- a/nssa/src/privacy_preserving_transaction/circuit.rs +++ b/nssa/src/privacy_preserving_transaction/circuit.rs @@ -68,7 +68,6 @@ pub fn execute_and_prove( pre_states: Vec, instruction_data: InstructionData, visibility_mask: Vec, - private_account_nonces: Vec, private_account_keys: Vec<(NullifierPublicKey, SharedSecretKey)>, private_account_nsks: Vec, private_account_membership_proofs: Vec>, @@ -127,7 +126,6 @@ pub fn execute_and_prove( let circuit_input = PrivacyPreservingCircuitInput { program_outputs, visibility_mask, - private_account_nonces, private_account_keys, private_account_nsks, private_account_membership_proofs, @@ -177,7 +175,7 @@ mod tests { use nssa_core::{ Commitment, DUMMY_COMMITMENT_HASH, EncryptionScheme, Nullifier, - account::{Account, AccountId, AccountWithMetadata, data::Data}, + account::{Account, AccountId, AccountWithMetadata, Nonce, data::Data}, }; use super::*; @@ -215,14 +213,14 @@ mod tests { let expected_sender_post = Account { program_owner: program.id(), balance: 100 - balance_to_move, - nonce: 0, + nonce: Nonce::default(), data: Data::default(), }; let expected_recipient_post = Account { program_owner: program.id(), balance: balance_to_move, - nonce: 0xdead_beef, + nonce: Nonce(0xdead_beef), data: Data::default(), }; @@ -235,7 +233,6 @@ mod tests { vec![sender, recipient], Program::serialize_instruction(balance_to_move).unwrap(), vec![0, 2], - vec![0xdead_beef], vec![(recipient_keys.npk(), shared_secret)], vec![], vec![None], @@ -269,10 +266,11 @@ mod tests { let sender_keys = test_private_account_keys_1(); let recipient_keys = test_private_account_keys_2(); + let sender_nonce = Nonce(0xdead_beef); let sender_pre = AccountWithMetadata::new( Account { balance: 100, - nonce: 0xdead_beef, + nonce: sender_nonce, program_owner: program.id(), data: Data::default(), }, @@ -307,13 +305,13 @@ mod tests { let expected_private_account_1 = Account { program_owner: program.id(), balance: 100 - balance_to_move, - nonce: 0xdead_beef1, + nonce: sender_nonce.private_account_nonce_increment(&sender_keys.nsk), ..Default::default() }; let expected_private_account_2 = Account { program_owner: program.id(), balance: balance_to_move, - nonce: 0xdead_beef2, + nonce: Nonce::private_account_nonce_init(&recipient_keys.npk()), ..Default::default() }; let expected_new_commitments = vec![ @@ -331,7 +329,6 @@ mod tests { vec![sender_pre, recipient], Program::serialize_instruction(balance_to_move).unwrap(), vec![1, 2], - vec![0xdead_beef1, 0xdead_beef2], vec![ (sender_keys.npk(), shared_secret_1), (recipient_keys.npk(), shared_secret_2), diff --git a/nssa/src/state.rs b/nssa/src/state.rs index c1f72b4c..f45d7aa3 100644 --- a/nssa/src/state.rs +++ b/nssa/src/state.rs @@ -3,7 +3,7 @@ use std::collections::{BTreeSet, HashMap, HashSet}; use borsh::{BorshDeserialize, BorshSerialize}; use nssa_core::{ Commitment, CommitmentSetDigest, DUMMY_COMMITMENT, MembershipProof, Nullifier, - account::{Account, AccountId}, + account::{Account, AccountId, Nonce}, program::ProgramId, }; @@ -172,10 +172,7 @@ impl V02State { for account_id in tx.signer_account_ids() { let current_account = self.get_account_by_id_mut(account_id); - current_account.nonce = current_account - .nonce - .checked_add(1) - .ok_or(NssaError::MaxAccountNonceReached)?; + current_account.nonce.public_account_nonce_increment(); } Ok(()) @@ -215,10 +212,7 @@ impl V02State { // 5. Increment nonces for public signers for account_id in tx.signer_account_ids() { let current_account = self.get_account_by_id_mut(account_id); - current_account.nonce = current_account - .nonce - .checked_add(1) - .ok_or(NssaError::MaxAccountNonceReached)?; + current_account.nonce.public_account_nonce_increment(); } Ok(()) @@ -303,7 +297,7 @@ impl V02State { balance: 1_500_000, // Difficulty: 3 data: vec![3; 33].try_into().expect("should fit"), - nonce: 0, + nonce: Nonce::default(), }, ); } @@ -389,7 +383,7 @@ pub mod tests { ..Account::default() }; let account_with_default_values_except_nonce = Account { - nonce: 37, + nonce: Nonce(37), ..Account::default() }; let account_with_default_values_except_data = Account { @@ -463,7 +457,7 @@ pub mod tests { balance: u128, ) -> PublicTransaction { let account_ids = vec![from, to]; - let nonces = vec![nonce]; + let nonces = vec![Nonce(nonce)]; let program_id = Program::authenticated_transfer_program().id(); let message = public_transaction::Message::try_new(program_id, account_ids, nonces, balance).unwrap(); @@ -577,8 +571,8 @@ pub mod tests { assert_eq!(state.get_account_by_id(from).balance, 95); assert_eq!(state.get_account_by_id(to).balance, 5); - assert_eq!(state.get_account_by_id(from).nonce, 1); - assert_eq!(state.get_account_by_id(to).nonce, 0); + assert_eq!(state.get_account_by_id(from).nonce, Nonce(1)); + assert_eq!(state.get_account_by_id(to).nonce, Nonce(0)); } #[test] @@ -599,8 +593,8 @@ pub mod tests { assert!(matches!(result, Err(NssaError::ProgramExecutionFailed(_)))); assert_eq!(state.get_account_by_id(from).balance, 100); assert_eq!(state.get_account_by_id(to).balance, 0); - assert_eq!(state.get_account_by_id(from).nonce, 0); - assert_eq!(state.get_account_by_id(to).nonce, 0); + assert_eq!(state.get_account_by_id(from).nonce, Nonce(0)); + assert_eq!(state.get_account_by_id(to).nonce, Nonce(0)); } #[test] @@ -622,8 +616,8 @@ pub mod tests { assert_eq!(state.get_account_by_id(from).balance, 192); assert_eq!(state.get_account_by_id(to).balance, 108); - assert_eq!(state.get_account_by_id(from).nonce, 1); - assert_eq!(state.get_account_by_id(to).nonce, 0); + assert_eq!(state.get_account_by_id(from).nonce, Nonce(1)); + assert_eq!(state.get_account_by_id(to).nonce, Nonce(0)); } #[test] @@ -646,9 +640,9 @@ pub mod tests { assert_eq!(state.get_account_by_id(account_id1).balance, 95); assert_eq!(state.get_account_by_id(account_id2).balance, 2); assert_eq!(state.get_account_by_id(account_id3).balance, 3); - assert_eq!(state.get_account_by_id(account_id1).nonce, 1); - assert_eq!(state.get_account_by_id(account_id2).nonce, 1); - assert_eq!(state.get_account_by_id(account_id3).nonce, 0); + assert_eq!(state.get_account_by_id(account_id1).nonce, Nonce(1)); + assert_eq!(state.get_account_by_id(account_id2).nonce, Nonce(1)); + assert_eq!(state.get_account_by_id(account_id3).nonce, Nonce(0)); } #[test] @@ -942,7 +936,6 @@ pub mod tests { vec![sender, recipient], Program::serialize_instruction(balance_to_move).unwrap(), vec![0, 2], - vec![0xdead_beef], vec![(recipient_keys.npk(), shared_secret)], vec![], vec![None], @@ -967,7 +960,6 @@ pub mod tests { sender_private_account: &Account, recipient_keys: &TestPrivateKeys, balance_to_move: u128, - new_nonces: [Nonce; 2], state: &V02State, ) -> PrivacyPreservingTransaction { let program = Program::authenticated_transfer_program(); @@ -989,7 +981,6 @@ pub mod tests { vec![sender_pre, recipient_pre], Program::serialize_instruction(balance_to_move).unwrap(), vec![1, 2], - new_nonces.to_vec(), vec![ (sender_keys.npk(), shared_secret_1), (recipient_keys.npk(), shared_secret_2), @@ -1021,7 +1012,6 @@ pub mod tests { sender_private_account: &Account, recipient_account_id: &AccountId, balance_to_move: u128, - new_nonce: Nonce, state: &V02State, ) -> PrivacyPreservingTransaction { let program = Program::authenticated_transfer_program(); @@ -1042,7 +1032,6 @@ pub mod tests { vec![sender_pre, recipient_pre], Program::serialize_instruction(balance_to_move).unwrap(), vec![1, 0], - vec![new_nonce], vec![(sender_keys.npk(), shared_secret)], vec![sender_keys.nsk], vec![state.get_proof_for_commitment(&sender_commitment)], @@ -1083,7 +1072,7 @@ pub mod tests { let expected_sender_post = { let mut this = state.get_account_by_id(sender_keys.account_id()); this.balance -= balance_to_move; - this.nonce += 1; + this.nonce.public_account_nonce_increment(); this }; @@ -1107,10 +1096,12 @@ pub mod tests { #[test] fn transition_from_privacy_preserving_transaction_private() { let sender_keys = test_private_account_keys_1(); + let sender_nonce = Nonce(0xdead_beef); + let sender_private_account = Account { program_owner: Program::authenticated_transfer_program().id(), balance: 100, - nonce: 0xdead_beef, + nonce: sender_nonce, data: Data::default(), }; let recipient_keys = test_private_account_keys_2(); @@ -1125,7 +1116,6 @@ pub mod tests { &sender_private_account, &recipient_keys, balance_to_move, - [0xcafe_cafe, 0xfeca_feca], &state, ); @@ -1133,7 +1123,7 @@ pub mod tests { &sender_keys.npk(), &Account { program_owner: Program::authenticated_transfer_program().id(), - nonce: 0xcafe_cafe, + nonce: sender_nonce.private_account_nonce_increment(&sender_keys.nsk), balance: sender_private_account.balance - balance_to_move, data: Data::default(), }, @@ -1147,7 +1137,7 @@ pub mod tests { &recipient_keys.npk(), &Account { program_owner: Program::authenticated_transfer_program().id(), - nonce: 0xfeca_feca, + nonce: Nonce::private_account_nonce_init(&recipient_keys.npk()), balance: balance_to_move, ..Account::default() }, @@ -1173,10 +1163,12 @@ pub mod tests { #[test] fn transition_from_privacy_preserving_transaction_deshielded() { let sender_keys = test_private_account_keys_1(); + let sender_nonce = Nonce(0xdead_beef); + let sender_private_account = Account { program_owner: Program::authenticated_transfer_program().id(), balance: 100, - nonce: 0xdead_beef, + nonce: sender_nonce, data: Data::default(), }; let recipient_keys = test_public_account_keys_1(); @@ -1200,7 +1192,6 @@ pub mod tests { &sender_private_account, &recipient_keys.account_id(), balance_to_move, - 0xcafe_cafe, &state, ); @@ -1208,7 +1199,7 @@ pub mod tests { &sender_keys.npk(), &Account { program_owner: Program::authenticated_transfer_program().id(), - nonce: 0xcafe_cafe, + nonce: sender_nonce.private_account_nonce_increment(&sender_keys.nsk), balance: sender_private_account.balance - balance_to_move, data: Data::default(), }, @@ -1257,7 +1248,6 @@ pub mod tests { vec![], vec![], vec![], - vec![], &program.into(), ); @@ -1284,7 +1274,6 @@ pub mod tests { vec![], vec![], vec![], - vec![], &program.into(), ); @@ -1311,7 +1300,6 @@ pub mod tests { vec![], vec![], vec![], - vec![], &program.into(), ); @@ -1338,7 +1326,6 @@ pub mod tests { vec![], vec![], vec![], - vec![], &program.into(), ); @@ -1373,7 +1360,6 @@ pub mod tests { vec![], vec![], vec![], - vec![], &program.into(), ); @@ -1400,7 +1386,6 @@ pub mod tests { vec![], vec![], vec![], - vec![], &program.into(), ); @@ -1436,7 +1421,6 @@ pub mod tests { vec![], vec![], vec![], - vec![], &program.into(), ); @@ -1463,7 +1447,6 @@ pub mod tests { vec![], vec![], vec![], - vec![], &program.into(), ); @@ -1499,7 +1482,6 @@ pub mod tests { vec![], vec![], vec![], - vec![], &program.into(), ); @@ -1537,7 +1519,6 @@ pub mod tests { vec![], vec![], vec![], - vec![], &program.into(), ); @@ -1561,13 +1542,10 @@ pub mod tests { let private_account_2 = AccountWithMetadata::new(Account::default(), false, &recipient_keys.npk()); - // Setting only one nonce for an execution with two private accounts. - let private_account_nonces = [0xdead_beef1]; let result = execute_and_prove( vec![private_account_1, private_account_2], Program::serialize_instruction(10_u128).unwrap(), vec![1, 2], - private_account_nonces.to_vec(), vec![ ( sender_keys.npk(), @@ -1611,7 +1589,6 @@ pub mod tests { vec![private_account_1, private_account_2], Program::serialize_instruction(10_u128).unwrap(), vec![1, 2], - vec![0xdead_beef1, 0xdead_beef2], private_account_keys.to_vec(), vec![sender_keys.nsk], vec![Some((0, vec![]))], @@ -1644,7 +1621,6 @@ pub mod tests { vec![private_account_1, private_account_2], Program::serialize_instruction(10_u128).unwrap(), vec![1, 2], - vec![0xdead_beef1, 0xdead_beef2], vec![ ( sender_keys.npk(), @@ -1686,7 +1662,6 @@ pub mod tests { vec![private_account_1, private_account_2], Program::serialize_instruction(10_u128).unwrap(), vec![1, 2], - vec![0xdead_beef1, 0xdead_beef2], vec![ ( sender_keys.npk(), @@ -1744,7 +1719,6 @@ pub mod tests { vec![private_account_1, private_account_2], Program::serialize_instruction(10_u128).unwrap(), vec![1, 2], - vec![0xdead_beef1, 0xdead_beef2], private_account_keys.to_vec(), private_account_nsks.to_vec(), private_account_membership_proofs.to_vec(), @@ -1782,7 +1756,6 @@ pub mod tests { vec![private_account_1, private_account_2], Program::serialize_instruction(10_u128).unwrap(), vec![1, 2], - vec![0xdead_beef1, 0xdead_beef2], vec![ ( sender_keys.npk(), @@ -1829,7 +1802,6 @@ pub mod tests { vec![private_account_1, private_account_2], Program::serialize_instruction(10_u128).unwrap(), vec![1, 2], - vec![0xdead_beef1, 0xdead_beef2], vec![ ( sender_keys.npk(), @@ -1876,7 +1848,6 @@ pub mod tests { vec![private_account_1, private_account_2], Program::serialize_instruction(10_u128).unwrap(), vec![1, 2], - vec![0xdead_beef1, 0xdead_beef2], vec![ ( sender_keys.npk(), @@ -1912,7 +1883,7 @@ pub mod tests { let private_account_2 = AccountWithMetadata::new( Account { // Non default nonce - nonce: 0xdead_beef, + nonce: Nonce(0xdead_beef), ..Account::default() }, false, @@ -1923,7 +1894,6 @@ pub mod tests { vec![private_account_1, private_account_2], Program::serialize_instruction(10_u128).unwrap(), vec![1, 2], - vec![0xdead_beef1, 0xdead_beef2], vec![ ( sender_keys.npk(), @@ -1968,7 +1938,6 @@ pub mod tests { vec![private_account_1, private_account_2], Program::serialize_instruction(10_u128).unwrap(), vec![1, 2], - vec![0xdead_beef1, 0xdead_beef2], vec![ ( sender_keys.npk(), @@ -2010,7 +1979,6 @@ pub mod tests { vec![], vec![], vec![], - vec![], &program.into(), ); @@ -2034,14 +2002,10 @@ pub mod tests { let private_account_2 = AccountWithMetadata::new(Account::default(), false, &recipient_keys.npk()); - // Setting three new private account nonces for a circuit execution with only two private - // accounts. - let private_account_nonces = [0xdead_beef1, 0xdead_beef2, 0xdead_beef3]; let result = execute_and_prove( vec![private_account_1, private_account_2], Program::serialize_instruction(10_u128).unwrap(), vec![1, 2], - private_account_nonces.to_vec(), vec![ ( sender_keys.npk(), @@ -2097,7 +2061,6 @@ pub mod tests { vec![private_account_1, private_account_2], Program::serialize_instruction(10_u128).unwrap(), vec![1, 2], - vec![0xdead_beef1, 0xdead_beef2], private_account_keys.to_vec(), vec![sender_keys.nsk], vec![Some((0, vec![]))], @@ -2133,7 +2096,6 @@ pub mod tests { vec![private_account_1, private_account_2], Program::serialize_instruction(10_u128).unwrap(), visibility_mask.to_vec(), - vec![0xdead_beef1, 0xdead_beef2], vec![ ( sender_keys.npk(), @@ -2158,7 +2120,7 @@ pub mod tests { let sender_private_account = Account { program_owner: Program::authenticated_transfer_program().id(), balance: 100, - nonce: 0xdead_beef, + nonce: Nonce(0xdead_beef), data: Data::default(), }; let recipient_keys = test_private_account_keys_2(); @@ -2173,7 +2135,6 @@ pub mod tests { &sender_private_account, &recipient_keys, balance_to_move, - [0xcafe_cafe, 0xfeca_feca], &state, ); @@ -2184,7 +2145,7 @@ pub mod tests { let sender_private_account = Account { program_owner: Program::authenticated_transfer_program().id(), balance: 100 - balance_to_move, - nonce: 0xcafe_cafe, + nonce: Nonce(0xdeaf_beef), data: Data::default(), }; @@ -2193,7 +2154,6 @@ pub mod tests { &sender_private_account, &recipient_keys, balance_to_move, - [0x1234, 0x5678], &state, ); @@ -2229,7 +2189,6 @@ pub mod tests { vec![private_account_1.clone(), private_account_1], Program::serialize_instruction(100_u128).unwrap(), visibility_mask.to_vec(), - vec![0xdead_beef1, 0xdead_beef2], vec![ (sender_keys.npk(), shared_secret), (sender_keys.npk(), shared_secret), @@ -2265,9 +2224,13 @@ pub mod tests { ..Account::default() }; - let message = - public_transaction::Message::try_new(program.id(), vec![from, to], vec![0], amount) - .unwrap(); + let message = public_transaction::Message::try_new( + program.id(), + vec![from, to], + vec![Nonce(0)], + amount, + ) + .unwrap(); let witness_set = public_transaction::WitnessSet::for_message(&message, &[&from_key]); let tx = PublicTransaction::new(message, witness_set); @@ -2307,7 +2270,7 @@ pub mod tests { program.id(), vec![to, from], // The chain_caller program permutes the account order in the chain // call - vec![0], + vec![Nonce(0)], instruction, ) .unwrap(); @@ -2347,7 +2310,7 @@ pub mod tests { program.id(), vec![to, from], // The chain_caller program permutes the account order in the chain // call - vec![0], + vec![Nonce(0)], instruction, ) .unwrap(); @@ -2444,7 +2407,7 @@ pub mod tests { chain_caller.id(), vec![to, from], // The chain_caller program permutes the account order in the chain // call - vec![0], + vec![Nonce(0)], instruction, ) .unwrap(); @@ -2514,8 +2477,8 @@ pub mod tests { dependencies.insert(auth_transfers.id(), auth_transfers); let program_with_deps = ProgramWithDependencies::new(chain_caller, dependencies); - let from_new_nonce = 0xdead_beef1; - let to_new_nonce = 0xdead_beef2; + let from_new_nonce = Nonce::default().private_account_nonce_increment(&from_keys.nsk); + let to_new_nonce = Nonce::default().private_account_nonce_increment(&to_keys.nsk); let from_expected_post = Account { balance: initial_balance - u128::from(number_of_calls) * amount, @@ -2536,7 +2499,6 @@ pub mod tests { vec![to_account, from_account], Program::serialize_instruction(instruction).unwrap(), vec![1, 1], - vec![from_new_nonce, to_new_nonce], vec![(from_keys.npk(), to_ss), (to_keys.npk(), from_ss)], vec![from_keys.nsk, to_keys.nsk], vec![ @@ -2732,14 +2694,14 @@ pub mod tests { let expected_sender_post = { let mut this = state.get_account_by_id(sender_id); this.balance = sender_init_balance; - this.nonce = 0; + this.nonce = Nonce(0); this }; let expected_recipient_post = { let mut this = state.get_account_by_id(sender_id); this.balance = recipient_init_balance; - this.nonce = 0; + this.nonce = Nonce(0); this }; @@ -2768,14 +2730,11 @@ pub mod tests { // Balance to initialize the account with (0 for a new account) let balance: u128 = 0; - let nonce = 0xdead_beef1; - // Execute and prove the circuit with the authorized account but no commitment proof let (output, proof) = execute_and_prove( vec![authorized_account], Program::serialize_instruction(balance).unwrap(), vec![1], - vec![nonce], vec![(private_keys.npk(), shared_secret)], vec![private_keys.nsk], vec![None], @@ -2821,14 +2780,12 @@ pub mod tests { let epk = EphemeralPublicKey::from_scalar(esk); let balance: u128 = 0; - let nonce = 0xdead_beef1; // Step 2: Execute claimer program to claim the account with authentication let (output, proof) = execute_and_prove( vec![authorized_account.clone()], Program::serialize_instruction(balance).unwrap(), vec![1], - vec![nonce], vec![(private_keys.npk(), shared_secret)], vec![private_keys.nsk], vec![None], @@ -2869,14 +2826,11 @@ pub mod tests { let esk2 = [4; 32]; let shared_secret2 = SharedSecretKey::new(&esk2, &private_keys.vpk()); - let nonce2 = 0xdead_beef2; - // Step 3: Try to execute noop program with authentication but without initialization let res = execute_and_prove( vec![account_metadata], Program::serialize_instruction(()).unwrap(), vec![1], - vec![nonce2], vec![(private_keys.npk(), shared_secret2)], vec![private_keys.nsk], vec![None], @@ -2946,7 +2900,6 @@ pub mod tests { vec![private_account], Program::serialize_instruction(instruction).unwrap(), vec![1], - vec![2], vec![( sender_keys.npk(), SharedSecretKey::new(&[3; 32], &sender_keys.vpk()), @@ -2974,7 +2927,6 @@ pub mod tests { vec![private_account], Program::serialize_instruction(instruction).unwrap(), vec![1], - vec![2], vec![( sender_keys.npk(), SharedSecretKey::new(&[3; 32], &sender_keys.vpk()), @@ -3026,14 +2978,11 @@ pub mod tests { dependencies.insert(auth_transfers.id(), auth_transfers); let program_with_deps = ProgramWithDependencies::new(malicious_program, dependencies); - let recipient_new_nonce = 0xdead_beef1; - // Act - execute the malicious program - this should fail during proving let result = execute_and_prove( vec![sender_account, recipient_account], Program::serialize_instruction(instruction).unwrap(), vec![0, 1], - vec![recipient_new_nonce], vec![(recipient_keys.npk(), recipient)], vec![recipient_keys.nsk], vec![state.get_proof_for_commitment(&recipient_commitment)], diff --git a/program_methods/guest/src/bin/privacy_preserving_circuit.rs b/program_methods/guest/src/bin/privacy_preserving_circuit.rs index b74b3e65..c2b07ef8 100644 --- a/program_methods/guest/src/bin/privacy_preserving_circuit.rs +++ b/program_methods/guest/src/bin/privacy_preserving_circuit.rs @@ -200,7 +200,6 @@ impl ExecutionState { fn compute_circuit_output( execution_state: ExecutionState, visibility_mask: &[u8], - private_account_nonces: &[Nonce], private_account_keys: &[(NullifierPublicKey, SharedSecretKey)], private_account_nsks: &[NullifierSecretKey], private_account_membership_proofs: &[Option], @@ -220,7 +219,6 @@ fn compute_circuit_output( "Invalid visibility mask length" ); - let mut private_nonces_iter = private_account_nonces.iter(); let mut private_keys_iter = private_account_keys.iter(); let mut private_nsks_iter = private_account_nsks.iter(); let mut private_membership_proofs_iter = private_account_membership_proofs.iter(); @@ -246,7 +244,7 @@ fn compute_circuit_output( "AccountId mismatch" ); - let new_nullifier = if account_visibility_mask == 1 { + let (new_nullifier, new_nonce) = if account_visibility_mask == 1 { // Private account with authentication let Some(nsk) = private_nsks_iter.next() else { @@ -270,12 +268,19 @@ fn compute_circuit_output( panic!("Missing membership proof"); }; - compute_nullifier_and_set_digest( + let new_nullifier = compute_nullifier_and_set_digest( membership_proof_opt.as_ref(), &pre_state.account, npk, nsk, - ) + ); + + let new_nonce = pre_state + .account + .nonce + .private_account_nonce_increment(&nsk); + + (new_nullifier, new_nonce) } else { // Private account without authentication @@ -300,16 +305,16 @@ fn compute_circuit_output( ); let nullifier = Nullifier::for_account_initialization(npk); - (nullifier, DUMMY_COMMITMENT_HASH) + + let new_nonce = Nonce::private_account_nonce_init(npk); + + ((nullifier, DUMMY_COMMITMENT_HASH), new_nonce) }; output.new_nullifiers.push(new_nullifier); // Update post-state with new nonce let mut post_with_updated_nonce = post_state; - let Some(new_nonce) = private_nonces_iter.next() else { - panic!("Missing private account nonce"); - }; - post_with_updated_nonce.nonce = *new_nonce; + post_with_updated_nonce.nonce = new_nonce; // Compute commitment let commitment_post = Commitment::new(npk, &post_with_updated_nonce); @@ -332,8 +337,6 @@ fn compute_circuit_output( } } - assert!(private_nonces_iter.next().is_none(), "Too many nonces"); - assert!( private_keys_iter.next().is_none(), "Too many private account keys" @@ -386,7 +389,6 @@ fn main() { let PrivacyPreservingCircuitInput { program_outputs, visibility_mask, - private_account_nonces, private_account_keys, private_account_nsks, private_account_membership_proofs, @@ -398,7 +400,6 @@ fn main() { let output = compute_circuit_output( execution_state, &visibility_mask, - &private_account_nonces, &private_account_keys, &private_account_nsks, &private_account_membership_proofs, diff --git a/wallet/src/helperfunctions.rs b/wallet/src/helperfunctions.rs index c7be5811..bfa28970 100644 --- a/wallet/src/helperfunctions.rs +++ b/wallet/src/helperfunctions.rs @@ -44,7 +44,7 @@ impl From for HumanReadableAccount { balance: account.balance, program_owner, data, - nonce: account.nonce, + nonce: account.nonce.0, } } } @@ -145,12 +145,16 @@ pub fn produce_data_for_storage( } } +#[expect(dead_code)] pub(crate) fn produce_random_nonces(size: usize) -> Vec { let mut result = vec![[0; 16]; size]; for bytes in &mut result { OsRng.fill_bytes(bytes); } - result.into_iter().map(Nonce::from_le_bytes).collect() + result + .into_iter() + .map(|x| Nonce(u128::from_le_bytes(x))) + .collect() } pub(crate) fn parse_addr_with_privacy_prefix( diff --git a/wallet/src/lib.rs b/wallet/src/lib.rs index a3c58a97..c253797b 100644 --- a/wallet/src/lib.rs +++ b/wallet/src/lib.rs @@ -32,7 +32,7 @@ use tokio::io::AsyncWriteExt as _; use crate::{ config::{PersistentStorage, WalletConfigOverrides}, - helperfunctions::{produce_data_for_storage, produce_random_nonces}, + helperfunctions::produce_data_for_storage, poller::TxPoller, }; @@ -364,7 +364,6 @@ impl WalletCore { pre_states, instruction_data, acc_manager.visibility_mask().to_vec(), - produce_random_nonces(private_account_keys.len()), private_account_keys .iter() .map(|keys| (keys.npk.clone(), keys.ssk)) diff --git a/wallet/src/program_facades/amm.rs b/wallet/src/program_facades/amm.rs index 251970bc..19a51f29 100644 --- a/wallet/src/program_facades/amm.rs +++ b/wallet/src/program_facades/amm.rs @@ -80,7 +80,10 @@ impl Amm<'_> { let message = nssa::public_transaction::Message::try_new( program.id(), account_ids, - nonces, + nonces + .iter() + .map(|x| nssa_core::account::Nonce(*x)) + .collect(), instruction, ) .unwrap(); @@ -187,7 +190,10 @@ impl Amm<'_> { let message = nssa::public_transaction::Message::try_new( program.id(), account_ids, - nonces, + nonces + .iter() + .map(|x| nssa_core::account::Nonce(*x)) + .collect(), instruction, ) .unwrap(); @@ -274,7 +280,10 @@ impl Amm<'_> { let message = nssa::public_transaction::Message::try_new( program.id(), account_ids, - nonces, + nonces + .iter() + .map(|x| nssa_core::account::Nonce(*x)) + .collect(), instruction, ) .unwrap(); @@ -356,7 +365,10 @@ impl Amm<'_> { let message = nssa::public_transaction::Message::try_new( program.id(), account_ids, - nonces, + nonces + .iter() + .map(|x| nssa_core::account::Nonce(*x)) + .collect(), instruction, ) .unwrap(); diff --git a/wallet/src/program_facades/native_token_transfer/public.rs b/wallet/src/program_facades/native_token_transfer/public.rs index eb2adc9a..eefaa1fe 100644 --- a/wallet/src/program_facades/native_token_transfer/public.rs +++ b/wallet/src/program_facades/native_token_transfer/public.rs @@ -29,8 +29,16 @@ impl NativeTokenTransfer<'_> { let account_ids = vec![from, to]; let program_id = Program::authenticated_transfer_program().id(); - let message = - Message::try_new(program_id, account_ids, nonces, balance_to_move).unwrap(); + let message = Message::try_new( + program_id, + account_ids, + nonces + .iter() + .map(|x| nssa_core::account::Nonce(*x)) + .collect(), + balance_to_move, + ) + .unwrap(); let signing_key = self.0.storage.user_data.get_pub_account_signing_key(from); @@ -61,7 +69,16 @@ impl NativeTokenTransfer<'_> { let instruction: u128 = 0; let account_ids = vec![from]; let program_id = Program::authenticated_transfer_program().id(); - let message = Message::try_new(program_id, account_ids, nonces, instruction).unwrap(); + let message = Message::try_new( + program_id, + account_ids, + nonces + .iter() + .map(|x| nssa_core::account::Nonce(*x)) + .collect(), + instruction, + ) + .unwrap(); let signing_key = self.0.storage.user_data.get_pub_account_signing_key(from); diff --git a/wallet/src/program_facades/token.rs b/wallet/src/program_facades/token.rs index fe5165ff..bdacae37 100644 --- a/wallet/src/program_facades/token.rs +++ b/wallet/src/program_facades/token.rs @@ -141,7 +141,10 @@ impl Token<'_> { let message = nssa::public_transaction::Message::try_new( program_id, account_ids, - nonces, + nonces + .iter() + .map(|x| nssa_core::account::Nonce(*x)) + .collect(), instruction, ) .unwrap(); @@ -342,7 +345,10 @@ impl Token<'_> { let message = nssa::public_transaction::Message::try_new( Program::token().id(), account_ids, - nonces, + nonces + .iter() + .map(|x| nssa_core::account::Nonce(*x)) + .collect(), instruction, ) .expect("Instruction should serialize"); @@ -472,7 +478,10 @@ impl Token<'_> { let message = nssa::public_transaction::Message::try_new( Program::token().id(), account_ids, - nonces, + nonces + .iter() + .map(|x| nssa_core::account::Nonce(*x)) + .collect(), instruction, ) .unwrap();