From 90205c6330eaba881bb49dbd1b846bbe4b7a6e71 Mon Sep 17 00:00:00 2001 From: Oleksandr Pravdyvyi Date: Tue, 15 Jul 2025 12:49:19 +0300 Subject: [PATCH] fix: account masks updates to safe state --- accounts/src/account_core/mod.rs | 22 ++- accounts/src/key_management/mod.rs | 14 +- node_core/src/chain_storage/mod.rs | 9 +- node_core/src/chain_storage/public_context.rs | 180 ------------------ node_core/src/lib.rs | 17 +- sc_core/src/transaction_payloads_tools.rs | 4 +- 6 files changed, 37 insertions(+), 209 deletions(-) delete mode 100644 node_core/src/chain_storage/public_context.rs diff --git a/accounts/src/account_core/mod.rs b/accounts/src/account_core/mod.rs index 079e725..b1b4a91 100644 --- a/accounts/src/account_core/mod.rs +++ b/accounts/src/account_core/mod.rs @@ -85,6 +85,8 @@ impl<'de> Deserialize<'de> for Account { ///A strucure, which represents all the visible(public) information /// /// known to each node about account `address` +/// +/// Main usage is to encode data for other account #[derive(Serialize, Clone)] pub struct AccountPublicMask { pub nullifier_public_key: AffinePoint, @@ -99,16 +101,13 @@ impl AccountPublicMask { viewing_public_key_receiver: AffinePoint, data: &[u8], ) -> (CipherText, Nonce) { - ephemeral_key_holder.encrypt_data(viewing_public_key_receiver, data) + //Using of parent Account fuction + Account::encrypt_data(ephemeral_key_holder, viewing_public_key_receiver, data) } pub fn make_tag(&self) -> Tag { self.address[0] } - - pub fn produce_ephemeral_key_holder(&self) -> EphemeralKeyHolder { - EphemeralKeyHolder::new_os_random() - } } impl Account { @@ -139,10 +138,6 @@ impl Account { } } - pub fn produce_ephemeral_key_holder(&self) -> EphemeralKeyHolder { - self.key_holder.produce_ephemeral_key_holder() - } - pub fn encrypt_data( ephemeral_key_holder: &EphemeralKeyHolder, viewing_public_key_receiver: AffinePoint, @@ -267,4 +262,13 @@ mod tests { assert!(result.is_ok()); assert_eq!(account.utxos.len(), 1); } + + #[test] + fn accounts_accounts_mask_tag_consistency() { + let account = Account::new(); + + let account_mask = account.make_account_public_mask(); + + assert_eq!(account.make_tag(), account_mask.make_tag()); + } } diff --git a/accounts/src/key_management/mod.rs b/accounts/src/key_management/mod.rs index 69b8ce0..24ac045 100644 --- a/accounts/src/key_management/mod.rs +++ b/accounts/src/key_management/mod.rs @@ -2,7 +2,6 @@ use aes_gcm::{aead::Aead, Aes256Gcm, KeyInit}; use common::merkle_tree_public::TreeHashType; use constants_types::{CipherText, Nonce}; use elliptic_curve::point::AffineCoordinates; -use ephemeral_key_holder::EphemeralKeyHolder; use k256::AffinePoint; use log::info; use secret_holders::{SeedHolder, TopSecretKeyHolder, UTXOSecretKeyHolder}; @@ -55,10 +54,6 @@ impl AddressKeyHolder { (ephemeral_public_key_sender * self.utxo_secret_key_holder.viewing_secret_key).into() } - pub fn produce_ephemeral_key_holder(&self) -> EphemeralKeyHolder { - EphemeralKeyHolder::new_os_random() - } - pub fn decrypt_data( &self, ephemeral_public_key_sender: AffinePoint, @@ -114,6 +109,8 @@ mod tests { use elliptic_curve::point::AffineCoordinates; use k256::{AffinePoint, ProjectivePoint, Scalar}; + use crate::key_management::ephemeral_key_holder::EphemeralKeyHolder; + use super::*; #[test] @@ -136,7 +133,7 @@ mod tests { // Generate a random ephemeral public key sender let scalar = Scalar::random(&mut OsRng); - let ephemeral_public_key_sender = (ProjectivePoint::generator() * scalar).to_affine(); + let ephemeral_public_key_sender = (ProjectivePoint::GENERATOR * scalar).to_affine(); // Calculate shared secret let shared_secret = @@ -151,9 +148,8 @@ mod tests { let address_key_holder = AddressKeyHolder::new_os_random(); // Generate an ephemeral key and shared secret - let ephemeral_public_key_sender = address_key_holder - .produce_ephemeral_key_holder() - .generate_ephemeral_public_key(); + let ephemeral_public_key_sender = + EphemeralKeyHolder::new_os_random().generate_ephemeral_public_key(); let shared_secret = address_key_holder.calculate_shared_secret_receiver(ephemeral_public_key_sender); diff --git a/node_core/src/chain_storage/mod.rs b/node_core/src/chain_storage/mod.rs index f6b1343..d8e8065 100644 --- a/node_core/src/chain_storage/mod.rs +++ b/node_core/src/chain_storage/mod.rs @@ -11,7 +11,7 @@ use common::{ }; use k256::AffinePoint; use log::{info, warn}; -use public_context::PublicSCContext; +use sc_core::public_context::PublicSCContext; use serde::{Deserialize, Serialize}; use utxo::utxo_core::UTXO; @@ -19,7 +19,6 @@ use crate::{config::NodeConfig, ActionData}; pub mod accounts_store; pub mod block_store; -pub mod public_context; #[derive(Deserialize, Serialize)] pub struct AccMap { @@ -267,6 +266,12 @@ impl NodeChainStore { account_masks, comitment_store_root: self.utxo_commitments_store.get_root().unwrap_or([0; 32]), pub_tx_store_root: self.pub_tx_store.get_root().unwrap_or([0; 32]), + nullifiers_set: self + .nullifier_store + .iter() + .map(|item| item.utxo_hash) + .collect(), + commitments_tree: self.utxo_commitments_store.clone(), } } } diff --git a/node_core/src/chain_storage/public_context.rs b/node_core/src/chain_storage/public_context.rs deleted file mode 100644 index 438fa50..0000000 --- a/node_core/src/chain_storage/public_context.rs +++ /dev/null @@ -1,180 +0,0 @@ -use std::collections::BTreeMap; - -use accounts::account_core::{AccountAddress, AccountPublicMask}; -use common::merkle_tree_public::TreeHashType; -use serde::{ser::SerializeStruct, Serialize}; - -pub const PUBLIC_SC_CONTEXT: &str = "PublicSCContext"; -pub const CALLER_ADDRESS: &str = "caller_address"; -pub const CALLER_BALANCE: &str = "caller_balance"; -pub const ACCOUNT_MASKS_KEYS_SORTED: &str = "account_masks_keys_sorted"; -pub const ACCOUNT_MASKS_VALUES_SORTED: &str = "account_masks_values_sorted"; -pub const COMMITMENT_STORE_ROOT: &str = "commitment_store_root"; -pub const PUT_TX_STORE_ROOT: &str = "put_tx_store_root"; - -///Strucutre, representing context, given to a smart contract on a call -pub struct PublicSCContext { - pub caller_address: AccountAddress, - pub caller_balance: u64, - pub account_masks: BTreeMap, - pub comitment_store_root: TreeHashType, - pub pub_tx_store_root: TreeHashType, -} - -impl Serialize for PublicSCContext { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - let mut account_masks_keys: Vec<[u8; 32]> = self.account_masks.keys().cloned().collect(); - account_masks_keys.sort(); - - let mut account_mask_values: Vec = - self.account_masks.values().cloned().collect(); - account_mask_values.sort_by(|left, right| left.address.cmp(&right.address)); - - let mut s = serializer.serialize_struct(PUBLIC_SC_CONTEXT, 7)?; - - s.serialize_field(CALLER_ADDRESS, &self.caller_address)?; - s.serialize_field(CALLER_BALANCE, &self.caller_balance)?; - s.serialize_field(ACCOUNT_MASKS_KEYS_SORTED, &account_masks_keys)?; - s.serialize_field(ACCOUNT_MASKS_VALUES_SORTED, &account_mask_values)?; - s.serialize_field(COMMITMENT_STORE_ROOT, &self.comitment_store_root)?; - s.serialize_field(PUT_TX_STORE_ROOT, &self.pub_tx_store_root)?; - - s.end() - } -} - -impl PublicSCContext { - ///Produces `u64` from bytes in a vector - /// - /// Assumes, that vector of le_bytes - pub fn produce_u64_from_fit_vec(data: Vec) -> u64 { - let data_len = data.len(); - - assert!(data_len <= 8); - let mut le_bytes: [u8; 8] = [0; 8]; - - for (idx, item) in data.into_iter().enumerate() { - le_bytes[idx] = item - } - - u64::from_le_bytes(le_bytes) - } - - ///Produces vector of `u64` from context - pub fn produce_u64_list_from_context(&self) -> Result, serde_json::Error> { - let mut u64_list = vec![]; - - let ser_data = serde_json::to_vec(self)?; - - //`ToDo` Replace with `next_chunk` usage, when feature stabilizes in Rust - for i in 0..=(ser_data.len() / 8) { - let next_chunk: Vec; - - if (i + 1) * 8 < ser_data.len() { - next_chunk = ser_data[(i * 8)..((i + 1) * 8)].iter().cloned().collect(); - } else { - next_chunk = ser_data[(i * 8)..(ser_data.len())] - .iter() - .cloned() - .collect(); - } - - u64_list.push(PublicSCContext::produce_u64_from_fit_vec(next_chunk)); - } - - Ok(u64_list) - } -} - -#[cfg(test)] -mod tests { - use accounts::account_core::Account; - - use super::*; - - fn create_test_context() -> PublicSCContext { - let caller_address = [1; 32]; - let comitment_store_root = [3; 32]; - let pub_tx_store_root = [4; 32]; - - let mut account_masks = BTreeMap::new(); - - let acc_1 = Account::new(); - let acc_2 = Account::new(); - let acc_3 = Account::new(); - - account_masks.insert(acc_1.address, acc_1.make_account_public_mask()); - account_masks.insert(acc_2.address, acc_2.make_account_public_mask()); - account_masks.insert(acc_3.address, acc_3.make_account_public_mask()); - - PublicSCContext { - caller_address, - caller_balance: 100, - account_masks, - comitment_store_root, - pub_tx_store_root, - } - } - - #[test] - fn bin_ser_stability_test() { - let test_context = create_test_context(); - - let serialization_1 = serde_json::to_vec(&test_context).unwrap(); - let serialization_2 = serde_json::to_vec(&test_context).unwrap(); - - assert_eq!(serialization_1, serialization_2); - } - - #[test] - fn correct_u64_production_from_fit_vec() { - let le_vec = vec![1, 1, 1, 1, 2, 1, 1, 1]; - - let num = PublicSCContext::produce_u64_from_fit_vec(le_vec); - - assert_eq!(num, 72340177133043969); - } - - #[test] - fn correct_u64_production_from_small_vec() { - //7 items instead of 8 - let le_vec = vec![1, 1, 1, 1, 2, 1, 1]; - - let num = PublicSCContext::produce_u64_from_fit_vec(le_vec); - - assert_eq!(num, 282583095116033); - } - - #[test] - fn correct_u64_production_from_small_vec_le_bytes() { - //7 items instead of 8 - let le_vec = vec![1, 1, 1, 1, 2, 1, 1]; - let le_vec_res = [1, 1, 1, 1, 2, 1, 1, 0]; - - let num = PublicSCContext::produce_u64_from_fit_vec(le_vec); - - assert_eq!(num.to_le_bytes(), le_vec_res); - } - - #[test] - #[should_panic] - fn correct_u64_production_from_unfit_vec_should_panic() { - //9 items instead of 8 - let le_vec = vec![1, 1, 1, 1, 2, 1, 1, 1, 1]; - - PublicSCContext::produce_u64_from_fit_vec(le_vec); - } - - #[test] - fn consistent_len_of_context_commitments() { - let test_context = create_test_context(); - - let context_num_vec1 = test_context.produce_u64_list_from_context().unwrap(); - let context_num_vec2 = test_context.produce_u64_list_from_context().unwrap(); - - assert_eq!(context_num_vec1.len(), context_num_vec2.len()); - } -} diff --git a/node_core/src/lib.rs b/node_core/src/lib.rs index 49f1285..2ef3595 100644 --- a/node_core/src/lib.rs +++ b/node_core/src/lib.rs @@ -5,7 +5,10 @@ use std::sync::{ use common::ExecutionFailureKind; -use accounts::account_core::{Account, AccountAddress}; +use accounts::{ + account_core::{Account, AccountAddress}, + key_management::ephemeral_key_holder::EphemeralKeyHolder, +}; use anyhow::Result; use chain_storage::NodeChainStore; use common::transaction::{Transaction, TransactionPayload, TxKind}; @@ -197,7 +200,7 @@ impl NodeCore { let account = acc_map_read_guard.acc_map.get(&acc).unwrap(); - let ephm_key_holder = &account.produce_ephemeral_key_holder(); + let ephm_key_holder = EphemeralKeyHolder::new_os_random(); ephm_key_holder.log(); let eph_pub_key = @@ -286,7 +289,7 @@ impl NodeCore { let account = acc_map_read_guard.acc_map.get(&acc).unwrap(); - let ephm_key_holder = &account.produce_ephemeral_key_holder(); + let ephm_key_holder = EphemeralKeyHolder::new_os_random(); ephm_key_holder.log(); let eph_pub_key = @@ -401,7 +404,7 @@ impl NodeCore { .map(|(utxo, _)| utxo.clone()) .collect(); - let ephm_key_holder = &account.produce_ephemeral_key_holder(); + let ephm_key_holder = EphemeralKeyHolder::new_os_random(); ephm_key_holder.log(); let eph_pub_key = @@ -523,7 +526,7 @@ impl NodeCore { .map(|utxo| utxo.hash) .collect(); - let ephm_key_holder = &account.produce_ephemeral_key_holder(); + let ephm_key_holder = EphemeralKeyHolder::new_os_random(); ephm_key_holder.log(); let eph_pub_key = @@ -669,7 +672,7 @@ impl NodeCore { .map(|(utxo, _)| utxo.clone()) .collect(); - let ephm_key_holder = &account.produce_ephemeral_key_holder(); + let ephm_key_holder = EphemeralKeyHolder::new_os_random(); ephm_key_holder.log(); let eph_pub_key = @@ -1387,7 +1390,7 @@ impl NodeCore { .map(|(utxo, _)| utxo.clone()) .collect(); - let ephm_key_holder = &account.produce_ephemeral_key_holder(); + let ephm_key_holder = EphemeralKeyHolder::new_os_random(); ephm_key_holder.log(); let eph_pub_key = diff --git a/sc_core/src/transaction_payloads_tools.rs b/sc_core/src/transaction_payloads_tools.rs index 24ad8f2..cba56dc 100644 --- a/sc_core/src/transaction_payloads_tools.rs +++ b/sc_core/src/transaction_payloads_tools.rs @@ -1,4 +1,4 @@ -use accounts::account_core::Account; +use accounts::{account_core::Account, key_management::ephemeral_key_holder::EphemeralKeyHolder}; use anyhow::Result; use common::transaction::{TransactionPayload, TxKind}; use rand::thread_rng; @@ -40,7 +40,7 @@ pub fn encode_utxos_to_receivers( let mut all_encoded_data = vec![]; for (utxo, receiver) in utxos_receivers { - let ephm_key_holder = &receiver.produce_ephemeral_key_holder(); + let ephm_key_holder = EphemeralKeyHolder::new_os_random(); let encoded_data = Account::encrypt_data( &ephm_key_holder,