From c58ef27224dce045f413f4eeec8ddefeab97df11 Mon Sep 17 00:00:00 2001 From: Oleksandr Pravdyvyi Date: Thu, 25 Sep 2025 11:53:42 +0300 Subject: [PATCH 01/24] feat: first db update --- Cargo.toml | 1 + common/Cargo.toml | 2 + common/src/block.rs | 79 +--- common/src/sequencer_client/mod.rs | 2 +- common/src/transaction.rs | 26 +- key_protocol/Cargo.toml | 1 - .../key_management/ephemeral_key_holder.rs | 8 - key_protocol/src/key_management/mod.rs | 39 +- sequencer_rpc/Cargo.toml | 1 + sequencer_rpc/src/process.rs | 8 +- storage/Cargo.toml | 3 +- storage/src/error.rs | 6 +- storage/src/lib.rs | 416 ++++++------------ storage/src/sc_db_utils.rs | 160 ------- wallet/Cargo.toml | 1 + wallet/src/lib.rs | 2 +- 16 files changed, 176 insertions(+), 579 deletions(-) delete mode 100644 storage/src/sc_db_utils.rs diff --git a/Cargo.toml b/Cargo.toml index 82f6736..11e3144 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -44,6 +44,7 @@ base64 = "0.22.1" bip39 = "2.2.0" hmac-sha512 = "1.1.7" chrono = "0.4.41" +borsh = "1.5.7" rocksdb = { version = "0.21.0", default-features = false, features = [ "snappy", diff --git a/common/Cargo.toml b/common/Cargo.toml index dcb5f60..4725386 100644 --- a/common/Cargo.toml +++ b/common/Cargo.toml @@ -17,6 +17,8 @@ log.workspace = true elliptic-curve.workspace = true hex.workspace = true +borsh.workspace = true + [dependencies.secp256k1-zkp] workspace = true features = ["std", "rand-std", "rand", "serde", "global-context"] diff --git a/common/src/block.rs b/common/src/block.rs index 64bce30..20f3aa7 100644 --- a/common/src/block.rs +++ b/common/src/block.rs @@ -1,5 +1,5 @@ +use borsh::{BorshDeserialize, BorshSerialize}; use rs_merkle::Hasher; -use std::io::{Cursor, Read}; use crate::{OwnHasher, transaction::EncodedTransaction}; @@ -27,7 +27,7 @@ pub struct Block { pub body: BlockBody, } -#[derive(Debug, PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq, BorshSerialize, BorshDeserialize)] pub struct HashableBlockData { pub block_id: BlockId, pub prev_block_hash: BlockHash, @@ -37,7 +37,7 @@ pub struct HashableBlockData { impl HashableBlockData { pub fn into_block(self, signing_key: &nssa::PrivateKey) -> Block { - let data_bytes = self.to_bytes(); + let data_bytes = borsh::to_vec(&self).unwrap(); let signature = nssa::Signature::new(signing_key, &data_bytes); let hash = OwnHasher::hash(&data_bytes); Block { @@ -66,75 +66,6 @@ impl From for HashableBlockData { } } -impl HashableBlockData { - pub fn to_bytes(&self) -> Vec { - let mut bytes = Vec::new(); - bytes.extend_from_slice(&self.block_id.to_le_bytes()); - bytes.extend_from_slice(&self.prev_block_hash); - bytes.extend_from_slice(&self.timestamp.to_le_bytes()); - let num_transactions: u32 = self.transactions.len() as u32; - bytes.extend_from_slice(&num_transactions.to_le_bytes()); - for tx in &self.transactions { - let transaction_bytes = tx.to_bytes(); - let num_transaction_bytes: u32 = transaction_bytes.len() as u32; - - bytes.extend_from_slice(&num_transaction_bytes.to_le_bytes()); - bytes.extend_from_slice(&tx.to_bytes()); - } - bytes - } - - // TODO: Improve error handling. Remove unwraps. - pub fn from_bytes(data: &[u8]) -> Self { - let mut cursor = Cursor::new(data); - - let block_id = u64_from_cursor(&mut cursor); - - let mut prev_block_hash = [0u8; 32]; - cursor.read_exact(&mut prev_block_hash).unwrap(); - - let timestamp = u64_from_cursor(&mut cursor); - - let num_transactions = u32_from_cursor(&mut cursor) as usize; - - let mut transactions = Vec::with_capacity(num_transactions); - for _ in 0..num_transactions { - let tx_len = u32_from_cursor(&mut cursor) as usize; - let mut tx_bytes = Vec::with_capacity(tx_len); - - for _ in 0..tx_len { - let mut buff = [0; 1]; - cursor.read_exact(&mut buff).unwrap(); - tx_bytes.push(buff[0]); - } - - let tx = EncodedTransaction::from_bytes(tx_bytes); - transactions.push(tx); - } - - Self { - block_id, - prev_block_hash, - timestamp, - transactions, - } - } -} - -// TODO: Improve error handling. Remove unwraps. -pub fn u32_from_cursor(cursor: &mut Cursor<&[u8]>) -> u32 { - let mut word_buf = [0u8; 4]; - cursor.read_exact(&mut word_buf).unwrap(); - u32::from_le_bytes(word_buf) -} - -// TODO: Improve error handling. Remove unwraps. -pub fn u64_from_cursor(cursor: &mut Cursor<&[u8]>) -> u64 { - let mut word_buf = [0u8; 8]; - cursor.read_exact(&mut word_buf).unwrap(); - u64::from_le_bytes(word_buf) -} - #[cfg(test)] mod tests { use crate::{block::HashableBlockData, test_utils}; @@ -144,8 +75,8 @@ mod tests { let transactions = vec![test_utils::produce_dummy_empty_transaction()]; let block = test_utils::produce_dummy_block(1, Some([1; 32]), transactions); let hashable = HashableBlockData::from(block); - let bytes = hashable.to_bytes(); - let block_from_bytes = HashableBlockData::from_bytes(&bytes); + let bytes = borsh::to_vec(&hashable).unwrap(); + let block_from_bytes = borsh::from_slice::(&bytes).unwrap(); assert_eq!(hashable, block_from_bytes); } } diff --git a/common/src/sequencer_client/mod.rs b/common/src/sequencer_client/mod.rs index 92bcd62..a75649d 100644 --- a/common/src/sequencer_client/mod.rs +++ b/common/src/sequencer_client/mod.rs @@ -150,7 +150,7 @@ impl SequencerClient { let transaction = EncodedTransaction::from(NSSATransaction::Public(transaction)); let tx_req = SendTxRequest { - transaction: transaction.to_bytes(), + transaction: borsh::to_vec(&transaction).unwrap(), }; let req = serde_json::to_value(tx_req)?; diff --git a/common/src/transaction.rs b/common/src/transaction.rs index d196687..3a2bda1 100644 --- a/common/src/transaction.rs +++ b/common/src/transaction.rs @@ -1,3 +1,4 @@ +use borsh::{BorshDeserialize, BorshSerialize}; use k256::ecdsa::{Signature, SigningKey, VerifyingKey}; use log::info; use serde::{Deserialize, Serialize}; @@ -34,13 +35,15 @@ pub type CipherText = Vec; pub type Nonce = GenericArray, B1>, B0>, B0>>; pub type Tag = u8; -#[derive(Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq)] +#[derive( + Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq, BorshSerialize, BorshDeserialize, +)] pub enum TxKind { Public, PrivacyPreserving, } -#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)] +#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)] ///General transaction object pub struct EncodedTransaction { pub tx_kind: TxKind, @@ -174,23 +177,12 @@ impl ActionData { impl EncodedTransaction { /// Computes and returns the SHA-256 hash of the JSON-serialized representation of `self`. pub fn hash(&self) -> TreeHashType { - let bytes_to_hash = self.to_bytes(); + let bytes_to_hash = borsh::to_vec(&self).unwrap(); let mut hasher = sha2::Sha256::new(); hasher.update(&bytes_to_hash); TreeHashType::from(hasher.finalize_fixed()) } - pub fn to_bytes(&self) -> Vec { - // TODO: Remove `unwrap` by implementing a `to_bytes` method - // that deterministically encodes all transaction fields to bytes - // and guarantees serialization will succeed. - serde_json::to_vec(&self).unwrap() - } - - pub fn from_bytes(bytes: Vec) -> Self { - serde_json::from_slice(&bytes).unwrap() - } - pub fn log(&self) { info!("Transaction hash is {:?}", hex::encode(self.hash())); info!("Transaction tx_kind is {:?}", self.tx_kind); @@ -221,7 +213,7 @@ mod tests { fn test_transaction_hash_is_sha256_of_json_bytes() { let body = test_transaction_body(); let expected_hash = { - let data = body.to_bytes(); + let data = borsh::to_vec(&body).unwrap(); let mut hasher = sha2::Sha256::new(); hasher.update(&data); TreeHashType::from(hasher.finalize_fixed()) @@ -236,8 +228,8 @@ mod tests { fn test_to_bytes_from_bytes() { let body = test_transaction_body(); - let body_bytes = body.to_bytes(); - let body_new = EncodedTransaction::from_bytes(body_bytes); + let body_bytes = borsh::to_vec(&body).unwrap(); + let body_new = borsh::from_slice::(&body_bytes).unwrap(); assert_eq!(body, body_new); } diff --git a/key_protocol/Cargo.toml b/key_protocol/Cargo.toml index d453753..8e4c542 100644 --- a/key_protocol/Cargo.toml +++ b/key_protocol/Cargo.toml @@ -5,7 +5,6 @@ edition = "2024" [dependencies] anyhow.workspace = true -serde_json.workspace = true log.workspace = true serde.workspace = true k256.workspace = true diff --git a/key_protocol/src/key_management/ephemeral_key_holder.rs b/key_protocol/src/key_management/ephemeral_key_holder.rs index b4835ff..9ae3842 100644 --- a/key_protocol/src/key_management/ephemeral_key_holder.rs +++ b/key_protocol/src/key_management/ephemeral_key_holder.rs @@ -1,4 +1,3 @@ -use log::info; use nssa_core::{ NullifierPublicKey, SharedSecretKey, encryption::{EphemeralPublicKey, EphemeralSecretKey, IncomingViewingPublicKey}, @@ -48,11 +47,4 @@ impl EphemeralKeyHolder { &receiver_incoming_viewing_public_key, ) } - - pub fn log(&self) { - info!( - "Ephemeral private key is {:?}", - hex::encode(serde_json::to_vec(&self.ephemeral_secret_key).unwrap()) - ); - } } diff --git a/key_protocol/src/key_management/mod.rs b/key_protocol/src/key_management/mod.rs index 5f5f2aa..e31b373 100644 --- a/key_protocol/src/key_management/mod.rs +++ b/key_protocol/src/key_management/mod.rs @@ -1,5 +1,4 @@ use common::TreeHashType; -use log::info; use nssa_core::{ NullifierPublicKey, SharedSecretKey, encryption::{EphemeralPublicKey, IncomingViewingPublicKey}, @@ -62,43 +61,13 @@ impl KeyChain { &ephemeral_public_key_sender, ) } - - pub fn log(&self) { - info!( - "Secret spending key is {:?}", - hex::encode(serde_json::to_vec(&self.secret_spending_key).unwrap()), - ); - info!( - "Nulifier secret key is {:?}", - hex::encode(serde_json::to_vec(&self.private_key_holder.nullifier_secret_key).unwrap()), - ); - info!( - "Viewing secret key is {:?}", - hex::encode( - serde_json::to_vec(&self.private_key_holder.incoming_viewing_secret_key).unwrap() - ), - ); - info!( - "Viewing secret key is {:?}", - hex::encode( - serde_json::to_vec(&self.private_key_holder.outgoing_viewing_secret_key).unwrap() - ), - ); - info!( - "Nullifier public key is {:?}", - hex::encode(serde_json::to_vec(&self.nullifer_public_key).unwrap()), - ); - info!( - "Viewing public key is {:?}", - hex::encode(serde_json::to_vec(&self.incoming_viewing_public_key).unwrap()), - ); - } } #[cfg(test)] mod tests { use aes_gcm::aead::OsRng; use k256::AffinePoint; + use k256::elliptic_curve::group::GroupEncoding; use rand::RngCore; use super::*; @@ -147,7 +116,7 @@ mod tests { println!( "Group generator {:?}", - hex::encode(serde_json::to_vec(&AffinePoint::GENERATOR).unwrap()) + hex::encode(AffinePoint::GENERATOR.to_bytes()) ); println!(); @@ -164,11 +133,11 @@ mod tests { println!("Address{:?}", hex::encode(address.value())); println!( "Nulifier public key {:?}", - hex::encode(serde_json::to_vec(&nullifer_public_key).unwrap()) + hex::encode(nullifer_public_key.to_byte_array()) ); println!( "Viewing public key {:?}", - hex::encode(serde_json::to_vec(&viewing_public_key).unwrap()) + hex::encode(viewing_public_key.to_bytes()) ); } } diff --git a/sequencer_rpc/Cargo.toml b/sequencer_rpc/Cargo.toml index 7972342..af7e011 100644 --- a/sequencer_rpc/Cargo.toml +++ b/sequencer_rpc/Cargo.toml @@ -16,6 +16,7 @@ base64.workspace = true actix-web.workspace = true tokio.workspace = true +borsh.workspace = true [dependencies.sequencer_core] path = "../sequencer_core" diff --git a/sequencer_rpc/src/process.rs b/sequencer_rpc/src/process.rs index 00c5724..db3b4c4 100644 --- a/sequencer_rpc/src/process.rs +++ b/sequencer_rpc/src/process.rs @@ -75,7 +75,7 @@ impl JsonHandler { async fn process_send_tx(&self, request: Request) -> Result { let send_tx_req = SendTxRequest::parse(Some(request.params))?; - let tx = EncodedTransaction::from_bytes(send_tx_req.transaction); + let tx = borsh::from_slice::(&send_tx_req.transaction).unwrap(); let tx_hash = hex::encode(tx.hash()); { @@ -105,7 +105,7 @@ impl JsonHandler { }; let helperstruct = GetBlockDataResponse { - block: HashableBlockData::from(block).to_bytes(), + block: borsh::to_vec(&HashableBlockData::from(block)).unwrap(), }; respond(helperstruct) @@ -241,7 +241,7 @@ impl JsonHandler { .store .block_store .get_transaction_by_hash(hash) - .map(|tx| tx.to_bytes()) + .map(|tx| borsh::to_vec(&tx).unwrap()) }; let base64_encoded = transaction.map(|tx| general_purpose::STANDARD.encode(tx)); let helperstruct = GetTransactionByHashResponse { @@ -625,7 +625,7 @@ mod tests { async fn test_get_transaction_by_hash_for_existing_transaction() { let (json_handler, _, tx) = components_for_tests(); let tx_hash_hex = hex::encode(tx.hash()); - let expected_base64_encoded = general_purpose::STANDARD.encode(tx.to_bytes()); + let expected_base64_encoded = general_purpose::STANDARD.encode(borsh::to_vec(&tx).unwrap()); let request = serde_json::json!({ "jsonrpc": "2.0", diff --git a/storage/Cargo.toml b/storage/Cargo.toml index 604b2fe..1bc9d07 100644 --- a/storage/Cargo.toml +++ b/storage/Cargo.toml @@ -5,9 +5,8 @@ edition = "2024" [dependencies] anyhow.workspace = true -serde_json.workspace = true -serde.workspace = true thiserror.workspace = true +borsh.workspace = true rocksdb.workspace = true diff --git a/storage/src/error.rs b/storage/src/error.rs index feb36f6..a3fd80b 100644 --- a/storage/src/error.rs +++ b/storage/src/error.rs @@ -7,7 +7,7 @@ pub enum DbError { }, #[error("Serialization error")] SerializationError { - error: serde_json::Error, + error: borsh::io::Error, additional_info: Option, }, #[error("Logic Error")] @@ -22,9 +22,9 @@ impl DbError { } } - pub fn serde_cast_message(serr: serde_json::Error, message: Option) -> Self { + pub fn borsh_cast_message(berr: borsh::io::Error, message: Option) -> Self { Self::SerializationError { - error: serr, + error: berr, additional_info: message, } } diff --git a/storage/src/lib.rs b/storage/src/lib.rs index d06fc0c..37d5971 100644 --- a/storage/src/lib.rs +++ b/storage/src/lib.rs @@ -5,10 +5,8 @@ use error::DbError; use rocksdb::{ BoundColumnFamily, ColumnFamilyDescriptor, DBWithThreadMode, MultiThreaded, Options, }; -use sc_db_utils::{DataBlob, DataBlobChangeVariant, produce_blob_from_fit_vec}; pub mod error; -pub mod sc_db_utils; ///Maximal size of stored blocks in base /// @@ -22,9 +20,6 @@ pub const BUFF_SIZE_ROCKSDB: usize = usize::MAX; ///Keeping small to not run out of memory pub const CACHE_SIZE: usize = 1000; -///Size in bytes of a singular smart contract data blob, stored in db -pub const SC_DATA_BLOB_SIZE: usize = 256; - ///Key base for storing metainformation about id of first block in db pub const DB_META_FIRST_BLOCK_IN_DB_KEY: &str = "first_block_in_db"; ///Key base for storing metainformation about id of last current block in db @@ -36,14 +31,6 @@ pub const DB_META_SC_LIST: &str = "sc_list"; ///Key base for storing snapshot which describe block id pub const DB_SNAPSHOT_BLOCK_ID_KEY: &str = "block_id"; -///Key base for storing snapshot which describe commitment -pub const DB_SNAPSHOT_COMMITMENT_KEY: &str = "commitment"; -///Key base for storing snapshot which describe transaction -pub const DB_SNAPSHOT_TRANSACTION_KEY: &str = "transaction"; -///Key base for storing snapshot which describe nullifier -pub const DB_SNAPSHOT_NULLIFIER_KEY: &str = "nullifier"; -///Key base for storing snapshot which describe account -pub const DB_SNAPSHOT_ACCOUNT_KEY: &str = "account"; ///Name of block column family pub const CF_BLOCK_NAME: &str = "cf_block"; @@ -54,9 +41,6 @@ pub const CF_SC_NAME: &str = "cf_sc"; ///Name of snapshot column family pub const CF_SNAPSHOT_NAME: &str = "cf_snapshot"; -///Suffix, used to mark field, which contain length of smart contract -pub const SC_LEN_SUFFIX: &str = "sc_len"; - pub type DbResult = Result; pub struct RocksDBIO { @@ -142,11 +126,24 @@ impl RocksDBIO { let cf_meta = self.meta_column(); let res = self .db - .get_cf(&cf_meta, DB_META_FIRST_BLOCK_IN_DB_KEY) + .get_cf( + &cf_meta, + borsh::to_vec(&DB_META_FIRST_BLOCK_IN_DB_KEY).map_err(|err| { + DbError::borsh_cast_message( + err, + Some("Failed to serialize DB_META_FIRST_BLOCK_IN_DB_KEY".to_string()), + ) + })?, + ) .map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?; if let Some(data) = res { - Ok(u64::from_be_bytes(data.try_into().unwrap())) + Ok(borsh::from_slice::(&data).map_err(|err| { + DbError::borsh_cast_message( + err, + Some("Failed to deserialize first block".to_string()), + ) + })?) } else { Err(DbError::db_interaction_error( "First block not found".to_string(), @@ -158,11 +155,24 @@ impl RocksDBIO { let cf_meta = self.meta_column(); let res = self .db - .get_cf(&cf_meta, DB_META_LAST_BLOCK_IN_DB_KEY) + .get_cf( + &cf_meta, + borsh::to_vec(&DB_META_LAST_BLOCK_IN_DB_KEY).map_err(|err| { + DbError::borsh_cast_message( + err, + Some("Failed to serialize DB_META_LAST_BLOCK_IN_DB_KEY".to_string()), + ) + })?, + ) .map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?; if let Some(data) = res { - Ok(u64::from_be_bytes(data.try_into().unwrap())) + Ok(borsh::from_slice::(&data).map_err(|err| { + DbError::borsh_cast_message( + err, + Some("Failed to deserialize last block".to_string()), + ) + })?) } else { Err(DbError::db_interaction_error( "Last block not found".to_string(), @@ -174,7 +184,15 @@ impl RocksDBIO { let cf_meta = self.meta_column(); let res = self .db - .get_cf(&cf_meta, DB_META_FIRST_BLOCK_SET_KEY) + .get_cf( + &cf_meta, + borsh::to_vec(&DB_META_FIRST_BLOCK_SET_KEY).map_err(|err| { + DbError::borsh_cast_message( + err, + Some("Failed to serialize DB_META_FIRST_BLOCK_SET_KEY".to_string()), + ) + })?, + ) .map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?; Ok(res.is_some()) @@ -185,8 +203,18 @@ impl RocksDBIO { self.db .put_cf( &cf_meta, - DB_META_FIRST_BLOCK_IN_DB_KEY.as_bytes(), - block.header.block_id.to_be_bytes(), + borsh::to_vec(&DB_META_FIRST_BLOCK_IN_DB_KEY).map_err(|err| { + DbError::borsh_cast_message( + err, + Some("Failed to serialize DB_META_FIRST_BLOCK_IN_DB_KEY".to_string()), + ) + })?, + borsh::to_vec(&block.header.block_id).map_err(|err| { + DbError::borsh_cast_message( + err, + Some("Failed to serialize first block id".to_string()), + ) + })?, ) .map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?; @@ -199,8 +227,18 @@ impl RocksDBIO { self.db .put_cf( &cf_meta, - DB_META_LAST_BLOCK_IN_DB_KEY.as_bytes(), - block_id.to_be_bytes(), + borsh::to_vec(&DB_META_LAST_BLOCK_IN_DB_KEY).map_err(|err| { + DbError::borsh_cast_message( + err, + Some("Failed to serialize DB_META_LAST_BLOCK_IN_DB_KEY".to_string()), + ) + })?, + borsh::to_vec(&block_id).map_err(|err| { + DbError::borsh_cast_message( + err, + Some("Failed to serialize last block id".to_string()), + ) + })?, ) .map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?; Ok(()) @@ -212,8 +250,18 @@ impl RocksDBIO { self.db .put_cf( &cf_meta, - DB_META_SC_LIST.as_bytes(), - serde_json::to_vec(&sc_list).unwrap(), + borsh::to_vec(&DB_META_SC_LIST).map_err(|err| { + DbError::borsh_cast_message( + err, + Some("Failed to serialize DB_META_SC_LIST".to_string()), + ) + })?, + borsh::to_vec(&sc_list).map_err(|err| { + DbError::borsh_cast_message( + err, + Some("Failed to serialize list of sc".to_string()), + ) + })?, ) .map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?; Ok(()) @@ -222,7 +270,16 @@ impl RocksDBIO { pub fn put_meta_is_first_block_set(&self) -> DbResult<()> { let cf_meta = self.meta_column(); self.db - .put_cf(&cf_meta, DB_META_FIRST_BLOCK_SET_KEY.as_bytes(), [1u8; 1]) + .put_cf( + &cf_meta, + borsh::to_vec(&DB_META_FIRST_BLOCK_SET_KEY).map_err(|err| { + DbError::borsh_cast_message( + err, + Some("Failed to serialize DB_META_FIRST_BLOCK_SET_KEY".to_string()), + ) + })?, + [1u8; 1], + ) .map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?; Ok(()) } @@ -241,8 +298,18 @@ impl RocksDBIO { self.db .put_cf( &cf_block, - block.header.block_id.to_be_bytes(), - HashableBlockData::from(block).to_bytes(), + borsh::to_vec(&block.header.block_id).map_err(|err| { + DbError::borsh_cast_message( + err, + Some("Failed to serialize block id".to_string()), + ) + })?, + borsh::to_vec(&HashableBlockData::from(block)).map_err(|err| { + DbError::borsh_cast_message( + err, + Some("Failed to serialize block data".to_string()), + ) + })?, ) .map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?; Ok(()) @@ -252,11 +319,26 @@ impl RocksDBIO { let cf_block = self.block_column(); let res = self .db - .get_cf(&cf_block, block_id.to_be_bytes()) + .get_cf( + &cf_block, + borsh::to_vec(&block_id).map_err(|err| { + DbError::borsh_cast_message( + err, + Some("Failed to serialize block id".to_string()), + ) + })?, + ) .map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?; if let Some(data) = res { - Ok(HashableBlockData::from_bytes(&data)) + Ok( + borsh::from_slice::(&data).map_err(|serr| { + DbError::borsh_cast_message( + serr, + Some("Failed to deserialize block data".to_string()), + ) + })?, + ) } else { Err(DbError::db_interaction_error( "Block on this id not found".to_string(), @@ -269,17 +351,23 @@ impl RocksDBIO { let cf_meta = self.meta_column(); let sc_list = self .db - .get_cf(&cf_meta, DB_META_SC_LIST) - .map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?; - if let Some(data) = sc_list { - Ok( - serde_json::from_slice::>(&data).map_err(|serr| { - DbError::serde_cast_message( - serr, - Some("List of Sc Deserialization failed".to_string()), + .get_cf( + &cf_meta, + borsh::to_vec(&DB_META_SC_LIST).map_err(|err| { + DbError::borsh_cast_message( + err, + Some("Failed to serialize DB_META_SC_LIST".to_string()), ) })?, ) + .map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?; + if let Some(data) = sc_list { + Ok(borsh::from_slice::>(&data).map_err(|serr| { + DbError::borsh_cast_message( + serr, + Some("List of Sc Deserialization failed".to_string()), + ) + })?) } else { Err(DbError::db_interaction_error( "Sc list not found".to_string(), @@ -297,250 +385,32 @@ impl RocksDBIO { Ok(()) } - ///Put/Modify sc state in db - pub fn put_sc_sc_state( - &self, - sc_addr: &str, - length: usize, - modifications: Vec, - ) -> DbResult<()> { - self.put_meta_sc(sc_addr.to_string())?; - - let cf_sc = self.sc_column(); - - let sc_addr_loc = format!("{sc_addr:?}{SC_LEN_SUFFIX}"); - let sc_len_addr = sc_addr_loc.as_bytes(); - - self.db - .put_cf(&cf_sc, sc_len_addr, length.to_be_bytes()) - .map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?; - - for data_change in modifications { - match data_change { - DataBlobChangeVariant::Created { id, blob } => { - let blob_addr = produce_address_for_data_blob_at_id(sc_addr, id); - - self.db - .put_cf(&cf_sc, blob_addr, blob) - .map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?; - } - DataBlobChangeVariant::Modified { - id, - blob_old: _, - blob_new, - } => { - let blob_addr = produce_address_for_data_blob_at_id(sc_addr, id); - - self.db - .put_cf(&cf_sc, blob_addr, blob_new) - .map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?; - } - DataBlobChangeVariant::Deleted { id } => { - let blob_addr = produce_address_for_data_blob_at_id(sc_addr, id); - - self.db - .delete_cf(&cf_sc, blob_addr) - .map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?; - } - } - } - - Ok(()) - } - - ///Get sc state length in blobs from DB - pub fn get_sc_sc_state_len(&self, sc_addr: &str) -> DbResult { - let cf_sc = self.sc_column(); - let sc_addr_loc = format!("{sc_addr:?}{SC_LEN_SUFFIX}"); - - let sc_len_addr = sc_addr_loc.as_bytes(); - - let sc_len = self - .db - .get_cf(&cf_sc, sc_len_addr) - .map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?; - - if let Some(sc_len) = sc_len { - Ok(usize::from_be_bytes(sc_len.as_slice().try_into().unwrap())) - } else { - Err(DbError::db_interaction_error(format!( - "Sc len for {sc_addr:?} not found" - ))) - } - } - - ///Get full sc state from DB - pub fn get_sc_sc_state(&self, sc_addr: &str) -> DbResult> { - let cf_sc = self.sc_column(); - let sc_len = self.get_sc_sc_state_len(sc_addr)?; - let mut data_blob_list = vec![]; - - for id in 0..sc_len { - let blob_addr = produce_address_for_data_blob_at_id(sc_addr, id); - - let blob = self - .db - .get_cf(&cf_sc, blob_addr) - .map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?; - - if let Some(blob_data) = blob { - data_blob_list.push(produce_blob_from_fit_vec(blob_data)); - } else { - return Err(DbError::db_interaction_error(format!( - "Blob for {sc_addr:?} at id {id} not found" - ))); - } - } - - Ok(data_blob_list) - } - pub fn get_snapshot_block_id(&self) -> DbResult { let cf_snapshot = self.snapshot_column(); let res = self .db - .get_cf(&cf_snapshot, DB_SNAPSHOT_BLOCK_ID_KEY) + .get_cf( + &cf_snapshot, + borsh::to_vec(&DB_SNAPSHOT_BLOCK_ID_KEY).map_err(|err| { + DbError::borsh_cast_message( + err, + Some("Failed to serialize DB_SNAPSHOT_BLOCK_ID_KEY".to_string()), + ) + })?, + ) .map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?; if let Some(data) = res { - Ok(u64::from_be_bytes(data.try_into().unwrap())) + Ok(borsh::from_slice::(&data).map_err(|err| { + DbError::borsh_cast_message( + err, + Some("Failed to deserialize last block".to_string()), + ) + })?) } else { Err(DbError::db_interaction_error( "Snapshot block ID not found".to_string(), )) } } - - pub fn get_snapshot_commitment(&self) -> DbResult> { - let cf_snapshot = self.snapshot_column(); - let res = self - .db - .get_cf(&cf_snapshot, DB_SNAPSHOT_COMMITMENT_KEY) - .map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?; - - if let Some(data) = res { - Ok(data) - } else { - Err(DbError::db_interaction_error( - "Snapshot commitment not found".to_string(), - )) - } - } - - pub fn get_snapshot_transaction(&self) -> DbResult> { - let cf_snapshot = self.snapshot_column(); - let res = self - .db - .get_cf(&cf_snapshot, DB_SNAPSHOT_TRANSACTION_KEY) - .map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?; - - if let Some(data) = res { - Ok(data) - } else { - Err(DbError::db_interaction_error( - "Snapshot transaction not found".to_string(), - )) - } - } - - pub fn get_snapshot_nullifier(&self) -> DbResult> { - let cf_snapshot = self.snapshot_column(); - let res = self - .db - .get_cf(&cf_snapshot, DB_SNAPSHOT_NULLIFIER_KEY) - .map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?; - - if let Some(data) = res { - Ok(data) - } else { - Err(DbError::db_interaction_error( - "Snapshot nullifier not found".to_string(), - )) - } - } - - pub fn get_snapshot_account(&self) -> DbResult> { - let cf_snapshot = self.snapshot_column(); - let res = self - .db - .get_cf(&cf_snapshot, DB_SNAPSHOT_ACCOUNT_KEY) - .map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?; - - if let Some(data) = res { - Ok(data) - } else { - Err(DbError::db_interaction_error( - "Snapshot account not found".to_string(), - )) - } - } - - pub fn put_snapshot_block_id_db(&self, block_id: u64) -> DbResult<()> { - let cf_snapshot = self.snapshot_column(); - self.db - .put_cf( - &cf_snapshot, - DB_SNAPSHOT_BLOCK_ID_KEY.as_bytes(), - block_id.to_be_bytes(), - ) - .map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?; - Ok(()) - } - - pub fn put_snapshot_commitement_db(&self, commitment: Vec) -> DbResult<()> { - let cf_snapshot = self.snapshot_column(); - self.db - .put_cf( - &cf_snapshot, - DB_SNAPSHOT_COMMITMENT_KEY.as_bytes(), - commitment, - ) - .map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?; - Ok(()) - } - - pub fn put_snapshot_transaction_db(&self, transaction: Vec) -> DbResult<()> { - let cf_snapshot = self.snapshot_column(); - self.db - .put_cf( - &cf_snapshot, - DB_SNAPSHOT_TRANSACTION_KEY.as_bytes(), - transaction, - ) - .map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?; - Ok(()) - } - - pub fn put_snapshot_nullifier_db(&self, nullifier: Vec) -> DbResult<()> { - let cf_snapshot = self.snapshot_column(); - self.db - .put_cf( - &cf_snapshot, - DB_SNAPSHOT_NULLIFIER_KEY.as_bytes(), - nullifier, - ) - .map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?; - Ok(()) - } - - pub fn put_snapshot_account_db(&self, account: Vec) -> DbResult<()> { - let cf_snapshot = self.snapshot_column(); - self.db - .put_cf(&cf_snapshot, DB_SNAPSHOT_ACCOUNT_KEY.as_bytes(), account) - .map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?; - Ok(()) - } -} - -///Creates address for sc data blob at corresponding id -fn produce_address_for_data_blob_at_id(sc_addr: &str, id: usize) -> Vec { - let mut prefix_bytes: Vec = sc_addr.as_bytes().to_vec(); - - let id_bytes = id.to_be_bytes(); - - for byte in id_bytes { - prefix_bytes.push(byte); - } - - prefix_bytes } diff --git a/storage/src/sc_db_utils.rs b/storage/src/sc_db_utils.rs deleted file mode 100644 index af982cf..0000000 --- a/storage/src/sc_db_utils.rs +++ /dev/null @@ -1,160 +0,0 @@ -use serde::{Deserialize, Serialize, de::Error}; - -use crate::SC_DATA_BLOB_SIZE; - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub struct DataBlob(pub [u8; SC_DATA_BLOB_SIZE]); - -impl From<[u8; SC_DATA_BLOB_SIZE]> for DataBlob { - fn from(value: [u8; SC_DATA_BLOB_SIZE]) -> Self { - Self(value) - } -} - -impl Serialize for DataBlob { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - let data_vec = self.0.to_vec(); - data_vec.serialize(serializer) - } -} - -impl AsRef<[u8]> for DataBlob { - fn as_ref(&self) -> &[u8] { - self.0.as_ref() - } -} - -impl<'de> Deserialize<'de> for DataBlob { - fn deserialize(deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - { - let data_vec = Vec::::deserialize(deserializer)?; - let chunk: [u8; SC_DATA_BLOB_SIZE] = data_vec - .try_into() - .map_err(|data| { - anyhow::anyhow!("failed to fit vec {data:?} to {:?}", SC_DATA_BLOB_SIZE) - }) - .map_err(D::Error::custom)?; - Ok(Self(chunk)) - } -} - -impl DataBlob { - pub fn to_vec(&self) -> Vec { - self.0.to_vec() - } -} - -#[allow(clippy::large_enum_variant)] -#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)] -pub enum DataBlobChangeVariant { - Created { - id: usize, - blob: DataBlob, - }, - Modified { - id: usize, - blob_old: DataBlob, - blob_new: DataBlob, - }, - Deleted { - id: usize, - }, -} - -///Produce `DataBlob` from vector of size <= `SC_DATA_BLOB_SIZE` -/// -///Extends to `SC_DATA_BLOB_SIZE`, if necessary. -/// -///Panics, if size > `SC_DATA_BLOB_SIZE` -pub fn produce_blob_from_fit_vec(data: Vec) -> DataBlob { - let data_len = data.len(); - - assert!(data_len <= SC_DATA_BLOB_SIZE); - let mut blob: DataBlob = [0; SC_DATA_BLOB_SIZE].into(); - - for (idx, item) in data.into_iter().enumerate() { - blob.0[idx] = item - } - - blob -} - -#[cfg(test)] -mod tests { - use super::*; - use serde_json; - - const TEST_BLOB_SIZE: usize = 256; // Define a test blob size for simplicity - static SC_DATA_BLOB_SIZE: usize = TEST_BLOB_SIZE; - - fn sample_vec() -> Vec { - (0..SC_DATA_BLOB_SIZE) - .collect::>() - .iter() - .map(|&x| x as u8) - .collect() - } - - fn sample_data_blob() -> DataBlob { - let vec: Vec = sample_vec(); - produce_blob_from_fit_vec(vec) - } - - #[test] - fn test_serialize_data_blob() { - let blob = sample_data_blob(); - let json = serde_json::to_string(&blob).unwrap(); - - let expected_json = serde_json::to_string(&sample_vec()).unwrap(); - assert_eq!(json, expected_json); - } - - #[test] - fn test_deserialize_data_blob() { - let data = sample_vec(); - let json = serde_json::to_string(&data).unwrap(); - let deserialized: DataBlob = serde_json::from_str(&json).unwrap(); - assert_eq!(deserialized.to_vec(), data); - } - - #[test] - fn test_serialize_deserialize_data_blob_change_variant() { - let blob1 = sample_data_blob(); - let blob2 = produce_blob_from_fit_vec((50..50 + SC_DATA_BLOB_SIZE as u8).collect()); - - let variants = vec![ - DataBlobChangeVariant::Created { id: 1, blob: blob1 }, - DataBlobChangeVariant::Modified { - id: 2, - blob_old: blob1, - blob_new: blob2, - }, - DataBlobChangeVariant::Deleted { id: 3 }, - ]; - - for variant in variants { - let json = serde_json::to_string(&variant).unwrap(); - let deserialized: DataBlobChangeVariant = serde_json::from_str(&json).unwrap(); - assert_eq!(variant, deserialized); - } - } - - #[test] - fn test_produce_blob_from_fit_vec() { - let data = (0..255).collect(); - let blob = produce_blob_from_fit_vec(data); - assert_eq!(blob.0[..4], [0, 1, 2, 3]); - } - - #[test] - #[should_panic] - fn test_produce_blob_from_fit_vec_panic() { - let data = vec![0; SC_DATA_BLOB_SIZE + 1]; - let _ = produce_blob_from_fit_vec(data); - } -} diff --git a/wallet/Cargo.toml b/wallet/Cargo.toml index e37586b..af669ad 100644 --- a/wallet/Cargo.toml +++ b/wallet/Cargo.toml @@ -15,6 +15,7 @@ clap.workspace = true nssa-core = { path = "../nssa/core" } base64.workspace = true bytemuck = "1.23.2" +borsh.workspace = true [dependencies.key_protocol] path = "../key_protocol" diff --git a/wallet/src/lib.rs b/wallet/src/lib.rs index 13d1c38..cf60658 100644 --- a/wallet/src/lib.rs +++ b/wallet/src/lib.rs @@ -175,7 +175,7 @@ impl WalletCore { pub async fn poll_public_native_token_transfer(&self, hash: String) -> Result { let transaction_encoded = self.poller.poll_tx(hash).await?; let tx_base64_decode = BASE64.decode(transaction_encoded)?; - let pub_tx = EncodedTransaction::from_bytes(tx_base64_decode); + let pub_tx = borsh::from_slice::(&tx_base64_decode).unwrap(); Ok(NSSATransaction::try_from(&pub_tx)?) } From 3b99bf60c753f09677d8b9c3deaeb03f7d2f2326 Mon Sep 17 00:00:00 2001 From: Oleksandr Pravdyvyi Date: Fri, 26 Sep 2025 08:51:24 +0300 Subject: [PATCH 02/24] fix: ci simplification --- ci_scripts/lint-ubuntu.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ci_scripts/lint-ubuntu.sh b/ci_scripts/lint-ubuntu.sh index 35a0e4a..8c60825 100755 --- a/ci_scripts/lint-ubuntu.sh +++ b/ci_scripts/lint-ubuntu.sh @@ -6,5 +6,4 @@ cargo install taplo-cli --locked cargo fmt -- --check taplo fmt --check -export RISC0_SKIP_BUILD=1 -cargo clippy --workspace --all-targets -- -D warnings +RISC0_SKIP_BUILD=1 cargo clippy --workspace --all-targets -- -D warnings From f49d79d0e46c35f3301c108e28e79154153d0534 Mon Sep 17 00:00:00 2001 From: Sergio Chouhy Date: Tue, 30 Sep 2025 14:13:12 -0300 Subject: [PATCH 03/24] Rename GetProofForCommitment --- common/src/rpc_primitives/requests.rs | 6 +++--- common/src/sequencer_client/mod.rs | 6 +++--- sequencer_rpc/src/process.rs | 8 ++++---- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/common/src/rpc_primitives/requests.rs b/common/src/rpc_primitives/requests.rs index 616d482..94c2ddc 100644 --- a/common/src/rpc_primitives/requests.rs +++ b/common/src/rpc_primitives/requests.rs @@ -54,7 +54,7 @@ pub struct GetAccountRequest { } #[derive(Serialize, Deserialize, Debug)] -pub struct GetProofByCommitmentRequest { +pub struct GetProofForCommitmentRequest { pub commitment: nssa_core::Commitment, } @@ -68,7 +68,7 @@ parse_request!(GetInitialTestnetAccountsRequest); parse_request!(GetAccountBalanceRequest); parse_request!(GetTransactionByHashRequest); parse_request!(GetAccountsNoncesRequest); -parse_request!(GetProofByCommitmentRequest); +parse_request!(GetProofForCommitmentRequest); parse_request!(GetAccountRequest); #[derive(Serialize, Deserialize, Debug)] @@ -123,6 +123,6 @@ pub struct GetAccountResponse { } #[derive(Serialize, Deserialize, Debug)] -pub struct GetProofByCommitmentResponse { +pub struct GetProofForCommitmentResponse { pub membership_proof: Option, } diff --git a/common/src/sequencer_client/mod.rs b/common/src/sequencer_client/mod.rs index 88595b7..dade286 100644 --- a/common/src/sequencer_client/mod.rs +++ b/common/src/sequencer_client/mod.rs @@ -9,7 +9,7 @@ use serde_json::Value; use crate::rpc_primitives::requests::{ GetAccountRequest, GetAccountResponse, GetAccountsNoncesRequest, GetAccountsNoncesResponse, - GetProofByCommitmentRequest, GetProofByCommitmentResponse, GetTransactionByHashRequest, + GetProofForCommitmentRequest, GetProofForCommitmentResponse, GetTransactionByHashRequest, GetTransactionByHashResponse, }; use crate::sequencer_client::json::AccountInitialData; @@ -222,7 +222,7 @@ impl SequencerClient { &self, commitment: nssa_core::Commitment, ) -> Result, SequencerClientError> { - let acc_req = GetProofByCommitmentRequest { commitment }; + let acc_req = GetProofForCommitmentRequest { commitment }; let req = serde_json::to_value(acc_req).unwrap(); @@ -231,7 +231,7 @@ impl SequencerClient { .await .unwrap(); - let resp_deser = serde_json::from_value::(resp) + let resp_deser = serde_json::from_value::(resp) .unwrap() .membership_proof; diff --git a/sequencer_rpc/src/process.rs b/sequencer_rpc/src/process.rs index 4ebb293..1492d19 100644 --- a/sequencer_rpc/src/process.rs +++ b/sequencer_rpc/src/process.rs @@ -14,8 +14,8 @@ use common::{ requests::{ GetAccountBalanceRequest, GetAccountBalanceResponse, GetAccountRequest, GetAccountResponse, GetAccountsNoncesRequest, GetAccountsNoncesResponse, - GetInitialTestnetAccountsRequest, GetProofByCommitmentRequest, - GetProofByCommitmentResponse, GetTransactionByHashRequest, + GetInitialTestnetAccountsRequest, GetProofForCommitmentRequest, + GetProofForCommitmentResponse, GetTransactionByHashRequest, GetTransactionByHashResponse, }, }, @@ -254,7 +254,7 @@ impl JsonHandler { /// Returns the commitment proof, corresponding to commitment async fn process_get_proof_by_commitment(&self, request: Request) -> Result { - let get_proof_req = GetProofByCommitmentRequest::parse(Some(request.params))?; + let get_proof_req = GetProofForCommitmentRequest::parse(Some(request.params))?; let membership_proof = { let state = self.sequencer_state.lock().await; @@ -263,7 +263,7 @@ impl JsonHandler { .state .get_proof_for_commitment(&get_proof_req.commitment) }; - let helperstruct = GetProofByCommitmentResponse { membership_proof }; + let helperstruct = GetProofForCommitmentResponse { membership_proof }; respond(helperstruct) } From f707d3893d4941553411e70e11819a1a4608deda Mon Sep 17 00:00:00 2001 From: Sergio Chouhy Date: Tue, 30 Sep 2025 14:15:50 -0300 Subject: [PATCH 04/24] remove unused function --- key_protocol/src/key_management/mod.rs | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/key_protocol/src/key_management/mod.rs b/key_protocol/src/key_management/mod.rs index 4154095..02aecef 100644 --- a/key_protocol/src/key_management/mod.rs +++ b/key_protocol/src/key_management/mod.rs @@ -22,17 +22,6 @@ pub struct KeyChain { pub incoming_viewing_public_key: IncomingViewingPublicKey, } -pub fn produce_user_address_foreign_account( - npk: &NullifierPublicKey, - ipk: &IncomingViewingPublicKey, -) -> [u8; 32] { - let mut hasher = sha2::Sha256::new(); - - hasher.update(npk); - hasher.update(ipk.to_bytes()); - - ::from(hasher.finalize_fixed()) -} impl KeyChain { pub fn new_os_random() -> Self { From 23afa1e05a2992f2191724294429c205f75fe4e6 Mon Sep 17 00:00:00 2001 From: Sergio Chouhy Date: Tue, 30 Sep 2025 14:17:46 -0300 Subject: [PATCH 05/24] nit --- wallet/src/lib.rs | 2 +- wallet/src/token_transfers/shielded.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/wallet/src/lib.rs b/wallet/src/lib.rs index bbbbc79..4eb99c3 100644 --- a/wallet/src/lib.rs +++ b/wallet/src/lib.rs @@ -565,7 +565,7 @@ pub async fn execute_subcommand(command: Command) -> Result Date: Tue, 30 Sep 2025 14:31:04 -0300 Subject: [PATCH 06/24] minor refactor --- wallet/src/token_transfers/deshielded.rs | 9 ++++----- wallet/src/token_transfers/private.rs | 16 ++++++++-------- wallet/src/token_transfers/shielded.rs | 12 ++++-------- 3 files changed, 16 insertions(+), 21 deletions(-) diff --git a/wallet/src/token_transfers/deshielded.rs b/wallet/src/token_transfers/deshielded.rs index adf0614..65a4b18 100644 --- a/wallet/src/token_transfers/deshielded.rs +++ b/wallet/src/token_transfers/deshielded.rs @@ -12,14 +12,13 @@ impl WalletCore { to: Address, balance_to_move: u128, ) -> Result<(SendTxResponse, nssa_core::SharedSecretKey), ExecutionFailureKind> { - let from_data = self.storage.user_data.get_private_account(&from).cloned(); - let to_data = self.get_account(to).await; - - let Some((from_keys, mut from_acc)) = from_data else { + let Some((from_keys, mut from_acc)) = + self.storage.user_data.get_private_account(&from).cloned() + else { return Err(ExecutionFailureKind::KeyNotFoundError); }; - let Ok(to_acc) = to_data else { + let Ok(to_acc) = self.get_account(to).await else { return Err(ExecutionFailureKind::KeyNotFoundError); }; diff --git a/wallet/src/token_transfers/private.rs b/wallet/src/token_transfers/private.rs index 11ae6dc..b707570 100644 --- a/wallet/src/token_transfers/private.rs +++ b/wallet/src/token_transfers/private.rs @@ -12,9 +12,9 @@ impl WalletCore { to_ipk: nssa_core::encryption::IncomingViewingPublicKey, balance_to_move: u128, ) -> Result<(SendTxResponse, nssa_core::SharedSecretKey), ExecutionFailureKind> { - let from_data = self.storage.user_data.get_private_account(&from).cloned(); - - let Some((from_keys, mut from_acc)) = from_data else { + let Some((from_keys, mut from_acc)) = + self.storage.user_data.get_private_account(&from).cloned() + else { return Err(ExecutionFailureKind::KeyNotFoundError); }; @@ -116,14 +116,14 @@ impl WalletCore { to: Address, balance_to_move: u128, ) -> Result<(SendTxResponse, nssa_core::SharedSecretKey), ExecutionFailureKind> { - let from_data = self.storage.user_data.get_private_account(&from).cloned(); - let to_data = self.storage.user_data.get_private_account(&to).cloned(); - - let Some((from_keys, mut from_acc)) = from_data else { + let Some((from_keys, mut from_acc)) = + self.storage.user_data.get_private_account(&from).cloned() + else { return Err(ExecutionFailureKind::KeyNotFoundError); }; - let Some((to_keys, mut to_acc)) = to_data else { + let Some((to_keys, mut to_acc)) = self.storage.user_data.get_private_account(&to).cloned() + else { return Err(ExecutionFailureKind::KeyNotFoundError); }; diff --git a/wallet/src/token_transfers/shielded.rs b/wallet/src/token_transfers/shielded.rs index 3d6fd06..2db3ff8 100644 --- a/wallet/src/token_transfers/shielded.rs +++ b/wallet/src/token_transfers/shielded.rs @@ -11,14 +11,12 @@ impl WalletCore { to: Address, balance_to_move: u128, ) -> Result<(SendTxResponse, nssa_core::SharedSecretKey), ExecutionFailureKind> { - let from_data = self.get_account(from).await; - let to_data = self.storage.user_data.get_private_account(&to).cloned(); - - let Ok(from_acc) = from_data else { + let Ok(from_acc) = self.get_account(from).await else { return Err(ExecutionFailureKind::KeyNotFoundError); }; - let Some((to_keys, mut to_acc)) = to_data else { + let Some((to_keys, mut to_acc)) = self.storage.user_data.get_private_account(&to).cloned() + else { return Err(ExecutionFailureKind::KeyNotFoundError); }; @@ -107,9 +105,7 @@ impl WalletCore { to_ipk: nssa_core::encryption::IncomingViewingPublicKey, balance_to_move: u128, ) -> Result<(SendTxResponse, nssa_core::SharedSecretKey), ExecutionFailureKind> { - let from_data = self.get_account(from).await; - - let Ok(from_acc) = from_data else { + let Ok(from_acc) = self.get_account(from).await else { return Err(ExecutionFailureKind::KeyNotFoundError); }; From 64048ccf1dfd0ea420ee5c7c8a93beea5756b1a5 Mon Sep 17 00:00:00 2001 From: Sergio Chouhy Date: Tue, 30 Sep 2025 14:44:43 -0300 Subject: [PATCH 07/24] rename --- integration_tests/src/lib.rs | 2 +- wallet/src/lib.rs | 8 ++++---- wallet/src/token_transfers/private.rs | 2 +- wallet/src/token_transfers/shielded.rs | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/integration_tests/src/lib.rs b/integration_tests/src/lib.rs index da4f7c5..988e974 100644 --- a/integration_tests/src/lib.rs +++ b/integration_tests/src/lib.rs @@ -452,7 +452,7 @@ pub async fn test_success_token_program() { pub async fn test_success_private_transfer_to_another_owned_account() { info!("test_success_private_transfer_to_another_owned_account"); - let command = Command::SendNativeTokenTransferPrivate { + let command = Command::SendNativeTokenTransferPrivateOwnedAccount { from: ACC_SENDER_PRIVATE.to_string(), to: ACC_RECEIVER_PRIVATE.to_string(), amount: 100, diff --git a/wallet/src/lib.rs b/wallet/src/lib.rs index 4eb99c3..69b0755 100644 --- a/wallet/src/lib.rs +++ b/wallet/src/lib.rs @@ -216,7 +216,7 @@ pub enum Command { ///Send native token transfer from `from` to `to` for `amount` /// /// Private operation - SendNativeTokenTransferPrivate { + SendNativeTokenTransferPrivateOwnedAccount { ///from - valid 32 byte hex string #[arg(long)] from: String, @@ -401,12 +401,12 @@ pub async fn execute_subcommand(command: Command) -> Result { + Command::SendNativeTokenTransferPrivateOwnedAccount { from, to, amount } => { let from = produce_account_addr_from_hex(from)?; let to = produce_account_addr_from_hex(to)?; let (res, secret) = wallet_core - .send_private_native_token_transfer(from, to, amount) + .send_private_native_token_transfer_owned_account(from, to, amount) .await?; println!("Results of tx send is {res:#?}"); @@ -614,7 +614,7 @@ pub async fn execute_subcommand(command: Command) -> Result Date: Tue, 30 Sep 2025 15:30:28 -0300 Subject: [PATCH 08/24] wip --- nssa/core/Cargo.toml | 3 +- nssa/core/src/address.rs | 132 +++++++++++++++++++++ nssa/core/src/lib.rs | 3 + nssa/src/lib.rs | 4 +- nssa/src/public_transaction/transaction.rs | 4 +- nssa/src/signature/public_key.rs | 9 ++ nssa/src/state.rs | 6 +- 7 files changed, 151 insertions(+), 10 deletions(-) create mode 100644 nssa/core/src/address.rs diff --git a/nssa/core/Cargo.toml b/nssa/core/Cargo.toml index 3b841fd..e1951c4 100644 --- a/nssa/core/Cargo.toml +++ b/nssa/core/Cargo.toml @@ -10,7 +10,8 @@ thiserror = { version = "2.0.12", optional = true } bytemuck = { version = "1.13", optional = true } chacha20 = { version = "0.9", default-features = false } k256 = { version = "0.13.3", optional = true } +hex = { version = "0.4.3", optional = true } [features] default = [] -host = ["thiserror", "bytemuck", "k256"] +host = ["thiserror", "bytemuck", "k256", "hex"] diff --git a/nssa/core/src/address.rs b/nssa/core/src/address.rs new file mode 100644 index 0000000..69a6979 --- /dev/null +++ b/nssa/core/src/address.rs @@ -0,0 +1,132 @@ +use risc0_zkvm::sha::{Impl, Sha256}; +use std::{fmt::Display, str::FromStr}; + +use serde::{Deserialize, Serialize}; + +use crate::account::AccountId; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)] +pub struct Address { + value: [u8; 32], +} + +impl Address { + pub fn new(value: [u8; 32]) -> Self { + Self { value } + } + + pub fn value(&self) -> &[u8; 32] { + &self.value + } +} + +impl AsRef<[u8]> for Address { + fn as_ref(&self) -> &[u8] { + &self.value + } +} + +#[derive(Debug, thiserror::Error)] +pub enum AddressError { + #[error("invalid hex")] + InvalidHex(#[from] hex::FromHexError), + #[error("invalid length: expected 32 bytes, got {0}")] + InvalidLength(usize), +} + +impl FromStr for Address { + type Err = AddressError; + fn from_str(s: &str) -> Result { + let bytes = hex::decode(s)?; + if bytes.len() != 32 { + return Err(AddressError::InvalidLength(bytes.len())); + } + let mut value = [0u8; 32]; + value.copy_from_slice(&bytes); + Ok(Address { value }) + } +} + +impl Display for Address { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", hex::encode(self.value)) + } +} + +impl Serialize for Address { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + let hex_string = self.to_string(); + + hex_string.serialize(serializer) + } +} + +impl<'de> Deserialize<'de> for Address { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + let hex_string = String::deserialize(deserializer)?; + + Address::from_str(&hex_string).map_err(serde::de::Error::custom) + } +} + +impl From<&Address> for AccountId { + fn from(address: &Address) -> Self { + const PUBLIC_ACCOUNT_ID_PREFIX: &[u8; 32] = b"/NSSA/v0.1/AccountId/Public/\x00\x00\x00\x00"; + + let mut bytes = PUBLIC_ACCOUNT_ID_PREFIX.to_vec(); + bytes.extend_from_slice(&address.value); + AccountId::new(Impl::hash_bytes(&bytes).as_bytes().try_into().unwrap()) + } +} + +#[cfg(test)] +mod tests { + use super::{Address, AddressError}; + + #[test] + fn parse_valid_address() { + let hex_str = "00".repeat(32); // 64 hex chars = 32 bytes + let addr: Address = hex_str.parse().unwrap(); + assert_eq!(addr.value, [0u8; 32]); + } + + #[test] + fn parse_invalid_hex() { + let hex_str = "zz".repeat(32); // invalid hex chars + let result = hex_str.parse::
().unwrap_err(); + assert!(matches!(result, AddressError::InvalidHex(_))); + } + + #[test] + fn parse_wrong_length_short() { + let hex_str = "00".repeat(31); // 62 chars = 31 bytes + let result = hex_str.parse::
().unwrap_err(); + assert!(matches!(result, AddressError::InvalidLength(_))); + } + + #[test] + fn parse_wrong_length_long() { + let hex_str = "00".repeat(33); // 66 chars = 33 bytes + let result = hex_str.parse::
().unwrap_err(); + assert!(matches!(result, AddressError::InvalidLength(_))); + } + + // #[test] + // fn test_account_id_from_address() { + // let address: Address = "37".repeat(32).parse().unwrap(); + // let expected_account_id = AccountId::new([ + // 93, 223, 66, 245, 78, 230, 157, 188, 110, 161, 134, 255, 137, 177, 220, 88, 37, 44, + // 243, 91, 236, 4, 36, 147, 185, 112, 21, 49, 234, 4, 107, 185, + // ]); + // + // let account_id = AccountId::from(&address); + // + // assert_eq!(account_id, expected_account_id); + // } +} diff --git a/nssa/core/src/lib.rs b/nssa/core/src/lib.rs index 2275e31..5a8ca2b 100644 --- a/nssa/core/src/lib.rs +++ b/nssa/core/src/lib.rs @@ -6,6 +6,9 @@ pub mod encryption; mod nullifier; pub mod program; +#[cfg(feature = "host")] +pub mod address; + pub use circuit_io::{PrivacyPreservingCircuitInput, PrivacyPreservingCircuitOutput}; pub use commitment::{Commitment, CommitmentSetDigest, MembershipProof, compute_digest_for_path}; pub use encryption::{EncryptionScheme, SharedSecretKey}; diff --git a/nssa/src/lib.rs b/nssa/src/lib.rs index 31591ad..e3ef5cf 100644 --- a/nssa/src/lib.rs +++ b/nssa/src/lib.rs @@ -1,4 +1,4 @@ -pub mod address; +// pub mod address; pub mod encoding; pub mod error; mod merkle_tree; @@ -8,7 +8,7 @@ pub mod public_transaction; mod signature; mod state; -pub use address::Address; +pub use nssa_core::address::Address; pub use nssa_core::account::{Account, AccountId}; pub use privacy_preserving_transaction::{ PrivacyPreservingTransaction, circuit::execute_and_prove, diff --git a/nssa/src/public_transaction/transaction.rs b/nssa/src/public_transaction/transaction.rs index 8af9212..dea77e9 100644 --- a/nssa/src/public_transaction/transaction.rs +++ b/nssa/src/public_transaction/transaction.rs @@ -1,14 +1,12 @@ use std::collections::{HashMap, HashSet}; use nssa_core::{ - account::{Account, AccountWithMetadata}, - program::validate_execution, + account::{Account, AccountWithMetadata}, address::Address, program::validate_execution }; use sha2::{Digest, digest::FixedOutput}; use crate::{ V01State, - address::Address, error::NssaError, public_transaction::{Message, WitnessSet}, }; diff --git a/nssa/src/signature/public_key.rs b/nssa/src/signature/public_key.rs index ac163d8..2feb6a7 100644 --- a/nssa/src/signature/public_key.rs +++ b/nssa/src/signature/public_key.rs @@ -1,3 +1,5 @@ +use nssa_core::address::Address; + use crate::{PrivateKey, error::NssaError}; #[derive(Debug, Clone, PartialEq, Eq)] @@ -27,6 +29,13 @@ impl PublicKey { } } +impl From<&PublicKey> for Address { + fn from(value: &PublicKey) -> Self { + // TODO: Check specs + Self::new(*value.value()) + } +} + #[cfg(test)] mod test { use crate::{PublicKey, error::NssaError, signature::bip340_test_vectors}; diff --git a/nssa/src/state.rs b/nssa/src/state.rs index 65b440f..ddb659f 100644 --- a/nssa/src/state.rs +++ b/nssa/src/state.rs @@ -1,12 +1,10 @@ use crate::{ - address::Address, error::NssaError, merkle_tree::MerkleTree, + error::NssaError, merkle_tree::MerkleTree, privacy_preserving_transaction::PrivacyPreservingTransaction, program::Program, public_transaction::PublicTransaction, }; use nssa_core::{ - Commitment, CommitmentSetDigest, MembershipProof, Nullifier, - account::Account, - program::{DEFAULT_PROGRAM_ID, ProgramId}, + account::Account, address::Address, program::{ProgramId, DEFAULT_PROGRAM_ID}, Commitment, CommitmentSetDigest, MembershipProof, Nullifier }; use std::collections::{HashMap, HashSet}; From 60702132328e2c1c25b60874df44c59967562957 Mon Sep 17 00:00:00 2001 From: Sergio Chouhy Date: Tue, 30 Sep 2025 16:45:25 -0300 Subject: [PATCH 09/24] wip --- nssa/core/src/account.rs | 23 ++++++------- nssa/core/src/address.rs | 58 +++++++++++++-------------------- nssa/core/src/encoding.rs | 2 +- nssa/core/src/lib.rs | 1 - wallet/src/chain_storage/mod.rs | 5 +-- wallet/src/config.rs | 8 ++--- 6 files changed, 43 insertions(+), 54 deletions(-) diff --git a/nssa/core/src/account.rs b/nssa/core/src/account.rs index ddae797..889592d 100644 --- a/nssa/core/src/account.rs +++ b/nssa/core/src/account.rs @@ -1,4 +1,4 @@ -use crate::program::ProgramId; +use crate::{address::Address, program::ProgramId}; use serde::{Deserialize, Serialize}; pub type Nonce = u128; @@ -14,16 +14,17 @@ pub struct Account { pub nonce: Nonce, } -/// A fingerprint of the owner of an account. This can be, for example, an `Address` in case the account -/// is public, or a `NullifierPublicKey` in case the account is private. -#[derive(Serialize, Deserialize, Clone, PartialEq, Eq)] -#[cfg_attr(any(feature = "host", test), derive(Debug))] -pub struct AccountId(pub(super) [u8; 32]); -impl AccountId { - pub fn new(value: [u8; 32]) -> Self { - Self(value) - } -} +// /// A fingerprint of the owner of an account. This can be, for example, an `Address` in case the account +// /// is public, or a `NullifierPublicKey` in case the account is private. +// #[derive(Serialize, Deserialize, Clone, PartialEq, Eq)] +// #[cfg_attr(any(feature = "host", test), derive(Debug))] +// pub struct AccountId(pub(super) [u8; 32]); +// impl AccountId { +// pub fn new(value: [u8; 32]) -> Self { +// Self(value) +// } +// } +pub type AccountId = Address; #[derive(Serialize, Deserialize, Clone)] #[cfg_attr(any(feature = "host", test), derive(Debug, PartialEq, Eq))] diff --git a/nssa/core/src/address.rs b/nssa/core/src/address.rs index 69a6979..2774211 100644 --- a/nssa/core/src/address.rs +++ b/nssa/core/src/address.rs @@ -5,7 +5,11 @@ use serde::{Deserialize, Serialize}; use crate::account::AccountId; -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)] +#[derive(Serialize, Deserialize, Clone, PartialEq, Eq)] +#[cfg_attr( + any(feature = "host", test), + derive(Debug, Copy, PartialOrd, Ord, Hash, Default) +)] pub struct Address { value: [u8; 32], } @@ -26,6 +30,7 @@ impl AsRef<[u8]> for Address { } } +#[cfg(feature = "host")] #[derive(Debug, thiserror::Error)] pub enum AddressError { #[error("invalid hex")] @@ -34,6 +39,7 @@ pub enum AddressError { InvalidLength(usize), } +#[cfg(feature = "host")] impl FromStr for Address { type Err = AddressError; fn from_str(s: &str) -> Result { @@ -47,34 +53,14 @@ impl FromStr for Address { } } +#[cfg(feature = "host")] impl Display for Address { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{}", hex::encode(self.value)) } } -impl Serialize for Address { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - let hex_string = self.to_string(); - - hex_string.serialize(serializer) - } -} - -impl<'de> Deserialize<'de> for Address { - fn deserialize(deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - { - let hex_string = String::deserialize(deserializer)?; - - Address::from_str(&hex_string).map_err(serde::de::Error::custom) - } -} - +#[cfg(feature = "host")] impl From<&Address> for AccountId { fn from(address: &Address) -> Self { const PUBLIC_ACCOUNT_ID_PREFIX: &[u8; 32] = b"/NSSA/v0.1/AccountId/Public/\x00\x00\x00\x00"; @@ -87,6 +73,8 @@ impl From<&Address> for AccountId { #[cfg(test)] mod tests { + use crate::account::AccountId; + use super::{Address, AddressError}; #[test] @@ -117,16 +105,16 @@ mod tests { assert!(matches!(result, AddressError::InvalidLength(_))); } - // #[test] - // fn test_account_id_from_address() { - // let address: Address = "37".repeat(32).parse().unwrap(); - // let expected_account_id = AccountId::new([ - // 93, 223, 66, 245, 78, 230, 157, 188, 110, 161, 134, 255, 137, 177, 220, 88, 37, 44, - // 243, 91, 236, 4, 36, 147, 185, 112, 21, 49, 234, 4, 107, 185, - // ]); - // - // let account_id = AccountId::from(&address); - // - // assert_eq!(account_id, expected_account_id); - // } + #[test] + fn test_account_id_from_address() { + let address: Address = "37".repeat(32).parse().unwrap(); + let expected_account_id = AccountId::new([ + 93, 223, 66, 245, 78, 230, 157, 188, 110, 161, 134, 255, 137, 177, 220, 88, 37, 44, + 243, 91, 236, 4, 36, 147, 185, 112, 21, 49, 234, 4, 107, 185, + ]); + + let account_id = AccountId::from(&address); + + assert_eq!(account_id, expected_account_id); + } } diff --git a/nssa/core/src/encoding.rs b/nssa/core/src/encoding.rs index d7fc8b8..59844d3 100644 --- a/nssa/core/src/encoding.rs +++ b/nssa/core/src/encoding.rs @@ -140,7 +140,7 @@ impl Secp256k1Point { impl AccountId { pub fn to_bytes(&self) -> [u8; 32] { - self.0 + *self.value() } } diff --git a/nssa/core/src/lib.rs b/nssa/core/src/lib.rs index 5a8ca2b..1aa63b4 100644 --- a/nssa/core/src/lib.rs +++ b/nssa/core/src/lib.rs @@ -6,7 +6,6 @@ pub mod encryption; mod nullifier; pub mod program; -#[cfg(feature = "host")] pub mod address; pub use circuit_io::{PrivacyPreservingCircuitInput, PrivacyPreservingCircuitOutput}; diff --git a/wallet/src/chain_storage/mod.rs b/wallet/src/chain_storage/mod.rs index e2923fe..8dc85e1 100644 --- a/wallet/src/chain_storage/mod.rs +++ b/wallet/src/chain_storage/mod.rs @@ -18,10 +18,11 @@ impl WalletChainStore { for init_acc_data in config.initial_accounts.clone() { match init_acc_data { InitialAccountData::Public(data) => { - public_init_acc_map.insert(data.address, data.pub_sign_key); + public_init_acc_map.insert(data.address.parse()?, data.pub_sign_key); } InitialAccountData::Private(data) => { - private_init_acc_map.insert(data.address, (data.key_chain, data.account)); + private_init_acc_map + .insert(data.address.parse()?, (data.key_chain, data.account)); } } } diff --git a/wallet/src/config.rs b/wallet/src/config.rs index b5d861c..aa9b5ba 100644 --- a/wallet/src/config.rs +++ b/wallet/src/config.rs @@ -4,7 +4,7 @@ use std::path::PathBuf; #[derive(Debug, Clone, Serialize, Deserialize)] pub struct InitialAccountDataPublic { - pub address: nssa::Address, + pub address: String, pub pub_sign_key: nssa::PrivateKey, } @@ -16,7 +16,7 @@ pub struct PersistentAccountDataPublic { #[derive(Debug, Clone, Serialize, Deserialize)] pub struct InitialAccountDataPrivate { - pub address: nssa::Address, + pub address: String, pub account: nssa_core::account::Account, pub key_chain: KeyChain, } @@ -49,8 +49,8 @@ pub enum PersistentAccountData { impl InitialAccountData { pub fn address(&self) -> nssa::Address { match &self { - Self::Public(acc) => acc.address, - Self::Private(acc) => acc.address, + Self::Public(acc) => acc.address.parse().unwrap(), + Self::Private(acc) => acc.address.parse().unwrap(), } } } From a00773d5aad575015ebf79d9a58b031e90e09daf Mon Sep 17 00:00:00 2001 From: Sergio Chouhy Date: Tue, 30 Sep 2025 17:14:09 -0300 Subject: [PATCH 10/24] wip --- .../configs/debug/wallet/wallet_config.json | 6 +++--- integration_tests/src/lib.rs | 4 ++-- key_protocol/src/key_management/mod.rs | 16 ++++++++-------- key_protocol/src/key_protocol_core/mod.rs | 10 +++++++--- 4 files changed, 20 insertions(+), 16 deletions(-) diff --git a/integration_tests/configs/debug/wallet/wallet_config.json b/integration_tests/configs/debug/wallet/wallet_config.json index f30c9a5..555256c 100644 --- a/integration_tests/configs/debug/wallet/wallet_config.json +++ b/integration_tests/configs/debug/wallet/wallet_config.json @@ -87,7 +87,7 @@ }, { "Private": { - "address": "6ffe0893c4b2c956fdb769b11fe4e3b2dd36ac4bd0ad90c810844051747c8c04", + "address": "9cb6b0035320266e430eac9d96745769e7efcf30d2b9cc21ff000b3f873dc2a8", "account": { "program_owner": [ 0, @@ -316,7 +316,7 @@ }, { "Private": { - "address": "4ee9de60e33da96fd72929f1485fb365bcc9c1634dd44e4ba55b1ab96692674b", + "address": "a55f4f98d2f265c91d8a9868564242d8070b9bf7180a29363f52eb76988636fd", "account": { "program_owner": [ 0, @@ -544,4 +544,4 @@ } } ] -} \ No newline at end of file +} diff --git a/integration_tests/src/lib.rs b/integration_tests/src/lib.rs index 988e974..ddb1fbb 100644 --- a/integration_tests/src/lib.rs +++ b/integration_tests/src/lib.rs @@ -30,9 +30,9 @@ pub const ACC_SENDER: &str = "1b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c pub const ACC_RECEIVER: &str = "4d4b6cd1361032ca9bd2aeb9d900aa4d45d9ead80ac9423374c451a7254d0766"; pub const ACC_SENDER_PRIVATE: &str = - "6ffe0893c4b2c956fdb769b11fe4e3b2dd36ac4bd0ad90c810844051747c8c04"; + "9cb6b0035320266e430eac9d96745769e7efcf30d2b9cc21ff000b3f873dc2a8"; pub const ACC_RECEIVER_PRIVATE: &str = - "4ee9de60e33da96fd72929f1485fb365bcc9c1634dd44e4ba55b1ab96692674b"; + "a55f4f98d2f265c91d8a9868564242d8070b9bf7180a29363f52eb76988636fd"; pub const TIME_TO_WAIT_FOR_BLOCK_SECONDS: u64 = 12; diff --git a/key_protocol/src/key_management/mod.rs b/key_protocol/src/key_management/mod.rs index 02aecef..73e1ab5 100644 --- a/key_protocol/src/key_management/mod.rs +++ b/key_protocol/src/key_management/mod.rs @@ -43,14 +43,14 @@ impl KeyChain { } } - pub fn produce_user_address(&self) -> [u8; 32] { - let mut hasher = sha2::Sha256::new(); - - hasher.update(&self.nullifer_public_key); - hasher.update(self.incoming_viewing_public_key.to_bytes()); - - ::from(hasher.finalize_fixed()) - } + // pub fn produce_user_address(&self) -> [u8; 32] { + // let mut hasher = sha2::Sha256::new(); + // + // hasher.update(&self.nullifer_public_key); + // hasher.update(self.incoming_viewing_public_key.to_bytes()); + // + // ::from(hasher.finalize_fixed()) + // } pub fn calculate_shared_secret_receiver( &self, diff --git a/key_protocol/src/key_protocol_core/mod.rs b/key_protocol/src/key_protocol_core/mod.rs index 24bb26e..df5502e 100644 --- a/key_protocol/src/key_protocol_core/mod.rs +++ b/key_protocol/src/key_protocol_core/mod.rs @@ -22,7 +22,9 @@ impl NSSAUserData { ) -> bool { let mut check_res = true; for (addr, key) in accounts_keys_map { - if &nssa::Address::from(&nssa::PublicKey::new_from_private_key(key)) != addr { + let expected_addr = nssa::Address::from(&nssa::PublicKey::new_from_private_key(key)); + if &expected_addr != addr { + println!("{}, {}", expected_addr, addr); check_res = false; } } @@ -34,7 +36,9 @@ impl NSSAUserData { ) -> bool { let mut check_res = true; for (addr, (key, _)) in accounts_keys_map { - if nssa::Address::new(key.produce_user_address()) != *addr { + let expected_addr = nssa::Address::from(&key.nullifer_public_key); + if expected_addr != *addr { + println!("{}, {}", expected_addr, addr); check_res = false; } } @@ -88,7 +92,7 @@ impl NSSAUserData { /// Returns the address of new account pub fn generate_new_privacy_preserving_transaction_key_chain(&mut self) -> nssa::Address { let key_chain = KeyChain::new_os_random(); - let address = nssa::Address::new(key_chain.produce_user_address()); + let address = nssa::Address::from(&key_chain.nullifer_public_key); self.user_private_accounts .insert(address, (key_chain, nssa_core::account::Account::default())); From 86f61e5ac972448127b9d07fa1e5db5fb8a44a33 Mon Sep 17 00:00:00 2001 From: Sergio Chouhy Date: Thu, 2 Oct 2025 08:39:53 -0300 Subject: [PATCH 11/24] fix impl --- .../debug/sequencer/sequencer_config.json | 6 +- .../configs/debug/wallet/wallet_config.json | 4 +- integration_tests/src/lib.rs | 19 +-- nssa/core/src/address.rs | 24 --- nssa/src/address.rs | 143 ------------------ nssa/src/lib.rs | 1 - .../transaction.rs | 2 +- nssa/src/public_transaction/transaction.rs | 14 +- nssa/src/signature/public_key.rs | 12 +- nssa/src/state.rs | 4 +- sequencer_core/src/lib.rs | 8 +- sequencer_rpc/src/process.rs | 12 +- .../configs/debug/sequencer_config.json | 4 +- wallet/src/chain_storage/mod.rs | 4 +- wallet/src/token_transfers/deshielded.rs | 2 +- wallet/src/token_transfers/shielded.rs | 4 +- 16 files changed, 47 insertions(+), 216 deletions(-) delete mode 100644 nssa/src/address.rs diff --git a/integration_tests/configs/debug/sequencer/sequencer_config.json b/integration_tests/configs/debug/sequencer/sequencer_config.json index 824d0a7..87624ae 100644 --- a/integration_tests/configs/debug/sequencer/sequencer_config.json +++ b/integration_tests/configs/debug/sequencer/sequencer_config.json @@ -8,11 +8,11 @@ "port": 3040, "initial_accounts": [ { - "addr": "1b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078f", + "addr": "0eee24287296ba55278f1e5403be014754866366388730303c2889be17ada065", "balance": 10000 }, { - "addr": "4d4b6cd1361032ca9bd2aeb9d900aa4d45d9ead80ac9423374c451a7254d0766", + "addr": "9e3d8e654d440e95293aa2dceceb137899a59535e952f747068e7a0ee30965f2", "balance": 20000 } ], @@ -154,4 +154,4 @@ 37, 37 ] -} \ No newline at end of file +} diff --git a/integration_tests/configs/debug/wallet/wallet_config.json b/integration_tests/configs/debug/wallet/wallet_config.json index 555256c..09209f6 100644 --- a/integration_tests/configs/debug/wallet/wallet_config.json +++ b/integration_tests/configs/debug/wallet/wallet_config.json @@ -9,7 +9,7 @@ "initial_accounts": [ { "Public": { - "address": "1b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078f", + "address": "0eee24287296ba55278f1e5403be014754866366388730303c2889be17ada065", "pub_sign_key": [ 1, 1, @@ -48,7 +48,7 @@ }, { "Public": { - "address": "4d4b6cd1361032ca9bd2aeb9d900aa4d45d9ead80ac9423374c451a7254d0766", + "address": "9e3d8e654d440e95293aa2dceceb137899a59535e952f747068e7a0ee30965f2", "pub_sign_key": [ 2, 2, diff --git a/integration_tests/src/lib.rs b/integration_tests/src/lib.rs index ddb1fbb..87df4b1 100644 --- a/integration_tests/src/lib.rs +++ b/integration_tests/src/lib.rs @@ -26,8 +26,8 @@ struct Args { test_name: String, } -pub const ACC_SENDER: &str = "1b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078f"; -pub const ACC_RECEIVER: &str = "4d4b6cd1361032ca9bd2aeb9d900aa4d45d9ead80ac9423374c451a7254d0766"; +pub const ACC_SENDER: &str = "0eee24287296ba55278f1e5403be014754866366388730303c2889be17ada065"; +pub const ACC_RECEIVER: &str = "9e3d8e654d440e95293aa2dceceb137899a59535e952f747068e7a0ee30965f2"; pub const ACC_SENDER_PRIVATE: &str = "9cb6b0035320266e430eac9d96745769e7efcf30d2b9cc21ff000b3f873dc2a8"; @@ -389,10 +389,7 @@ pub async fn test_success_token_program() { // Bytes from 1 to 33 represent the id of the token this account is associated with. // In this example, this is a token account of the newly created token, so it is expected // to be equal to the address of the token definition account. - assert_eq!( - &supply_acc.data[1..33], - nssa::AccountId::from(&definition_addr).to_bytes() - ); + assert_eq!(&supply_acc.data[1..33], definition_addr.to_bytes()); assert_eq!( u128::from_le_bytes(supply_acc.data[33..].try_into().unwrap()), 37 @@ -419,10 +416,7 @@ pub async fn test_success_token_program() { // First byte equal to 1 means it's a token holding account assert_eq!(supply_acc.data[0], 1); // Bytes from 1 to 33 represent the id of the token this account is associated with. - assert_eq!( - &supply_acc.data[1..33], - nssa::AccountId::from(&definition_addr).to_bytes() - ); + assert_eq!(&supply_acc.data[1..33], definition_addr.to_bytes()); assert_eq!( u128::from_le_bytes(supply_acc.data[33..].try_into().unwrap()), 30 @@ -440,10 +434,7 @@ pub async fn test_success_token_program() { // First byte equal to 1 means it's a token holding account assert_eq!(recipient_acc.data[0], 1); // Bytes from 1 to 33 represent the id of the token this account is associated with. - assert_eq!( - &recipient_acc.data[1..33], - nssa::AccountId::from(&definition_addr).to_bytes() - ); + assert_eq!(&recipient_acc.data[1..33], definition_addr.to_bytes()); assert_eq!( u128::from_le_bytes(recipient_acc.data[33..].try_into().unwrap()), 7 diff --git a/nssa/core/src/address.rs b/nssa/core/src/address.rs index 2774211..14a3018 100644 --- a/nssa/core/src/address.rs +++ b/nssa/core/src/address.rs @@ -60,17 +60,6 @@ impl Display for Address { } } -#[cfg(feature = "host")] -impl From<&Address> for AccountId { - fn from(address: &Address) -> Self { - const PUBLIC_ACCOUNT_ID_PREFIX: &[u8; 32] = b"/NSSA/v0.1/AccountId/Public/\x00\x00\x00\x00"; - - let mut bytes = PUBLIC_ACCOUNT_ID_PREFIX.to_vec(); - bytes.extend_from_slice(&address.value); - AccountId::new(Impl::hash_bytes(&bytes).as_bytes().try_into().unwrap()) - } -} - #[cfg(test)] mod tests { use crate::account::AccountId; @@ -104,17 +93,4 @@ mod tests { let result = hex_str.parse::
().unwrap_err(); assert!(matches!(result, AddressError::InvalidLength(_))); } - - #[test] - fn test_account_id_from_address() { - let address: Address = "37".repeat(32).parse().unwrap(); - let expected_account_id = AccountId::new([ - 93, 223, 66, 245, 78, 230, 157, 188, 110, 161, 134, 255, 137, 177, 220, 88, 37, 44, - 243, 91, 236, 4, 36, 147, 185, 112, 21, 49, 234, 4, 107, 185, - ]); - - let account_id = AccountId::from(&address); - - assert_eq!(account_id, expected_account_id); - } } diff --git a/nssa/src/address.rs b/nssa/src/address.rs deleted file mode 100644 index 72144b2..0000000 --- a/nssa/src/address.rs +++ /dev/null @@ -1,143 +0,0 @@ -use std::{fmt::Display, str::FromStr}; - -use nssa_core::account::AccountId; -use serde::{Deserialize, Serialize}; -use sha2::{Digest, Sha256}; - -use crate::signature::PublicKey; - -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)] -pub struct Address { - value: [u8; 32], -} - -impl Address { - pub fn new(value: [u8; 32]) -> Self { - Self { value } - } - - pub fn value(&self) -> &[u8; 32] { - &self.value - } -} - -impl AsRef<[u8]> for Address { - fn as_ref(&self) -> &[u8] { - &self.value - } -} - -impl From<&PublicKey> for Address { - fn from(value: &PublicKey) -> Self { - // TODO: Check specs - Self::new(*value.value()) - } -} - -#[derive(Debug, thiserror::Error)] -pub enum AddressError { - #[error("invalid hex")] - InvalidHex(#[from] hex::FromHexError), - #[error("invalid length: expected 32 bytes, got {0}")] - InvalidLength(usize), -} - -impl FromStr for Address { - type Err = AddressError; - fn from_str(s: &str) -> Result { - let bytes = hex::decode(s)?; - if bytes.len() != 32 { - return Err(AddressError::InvalidLength(bytes.len())); - } - let mut value = [0u8; 32]; - value.copy_from_slice(&bytes); - Ok(Address { value }) - } -} - -impl Display for Address { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", hex::encode(self.value)) - } -} - -impl Serialize for Address { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - let hex_string = self.to_string(); - - hex_string.serialize(serializer) - } -} - -impl<'de> Deserialize<'de> for Address { - fn deserialize(deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - { - let hex_string = String::deserialize(deserializer)?; - - Address::from_str(&hex_string).map_err(serde::de::Error::custom) - } -} - -impl From<&Address> for AccountId { - fn from(address: &Address) -> Self { - const PUBLIC_ACCOUNT_ID_PREFIX: &[u8; 32] = b"/NSSA/v0.1/AccountId/Public/\x00\x00\x00\x00"; - - let mut hasher = Sha256::new(); - hasher.update(PUBLIC_ACCOUNT_ID_PREFIX); - hasher.update(address.value); - AccountId::new(hasher.finalize().into()) - } -} - -#[cfg(test)] -mod tests { - use nssa_core::account::AccountId; - - use crate::{Address, address::AddressError}; - - #[test] - fn parse_valid_address() { - let hex_str = "00".repeat(32); // 64 hex chars = 32 bytes - let addr: Address = hex_str.parse().unwrap(); - assert_eq!(addr.value, [0u8; 32]); - } - - #[test] - fn parse_invalid_hex() { - let hex_str = "zz".repeat(32); // invalid hex chars - let result = hex_str.parse::
().unwrap_err(); - assert!(matches!(result, AddressError::InvalidHex(_))); - } - - #[test] - fn parse_wrong_length_short() { - let hex_str = "00".repeat(31); // 62 chars = 31 bytes - let result = hex_str.parse::
().unwrap_err(); - assert!(matches!(result, AddressError::InvalidLength(_))); - } - - #[test] - fn parse_wrong_length_long() { - let hex_str = "00".repeat(33); // 66 chars = 33 bytes - let result = hex_str.parse::
().unwrap_err(); - assert!(matches!(result, AddressError::InvalidLength(_))); - } - - #[test] - fn test_account_id_from_address() { - let address: Address = "37".repeat(32).parse().unwrap(); - let expected_account_id = AccountId::new([ - 93, 223, 66, 245, 78, 230, 157, 188, 110, 161, 134, 255, 137, 177, 220, 88, 37, 44, - 243, 91, 236, 4, 36, 147, 185, 112, 21, 49, 234, 4, 107, 185, - ]); - - let account_id = AccountId::from(&address); - - assert_eq!(account_id, expected_account_id); - } -} diff --git a/nssa/src/lib.rs b/nssa/src/lib.rs index e3ef5cf..bf90598 100644 --- a/nssa/src/lib.rs +++ b/nssa/src/lib.rs @@ -1,4 +1,3 @@ -// pub mod address; pub mod encoding; pub mod error; mod merkle_tree; diff --git a/nssa/src/privacy_preserving_transaction/transaction.rs b/nssa/src/privacy_preserving_transaction/transaction.rs index 7e75d35..cdf02c2 100644 --- a/nssa/src/privacy_preserving_transaction/transaction.rs +++ b/nssa/src/privacy_preserving_transaction/transaction.rs @@ -94,7 +94,7 @@ impl PrivacyPreservingTransaction { AccountWithMetadata::new( state.get_account_by_address(address), signer_addresses.contains(address), - address, + *address, ) }) .collect(); diff --git a/nssa/src/public_transaction/transaction.rs b/nssa/src/public_transaction/transaction.rs index dea77e9..d6b9614 100644 --- a/nssa/src/public_transaction/transaction.rs +++ b/nssa/src/public_transaction/transaction.rs @@ -1,7 +1,9 @@ use std::collections::{HashMap, HashSet}; use nssa_core::{ - account::{Account, AccountWithMetadata}, address::Address, program::validate_execution + account::{Account, AccountWithMetadata}, + address::Address, + program::validate_execution, }; use sha2::{Digest, digest::FixedOutput}; @@ -93,7 +95,7 @@ impl PublicTransaction { AccountWithMetadata::new( state.get_account_by_address(address), signer_addresses.contains(address), - address, + *address, ) }) .collect(); @@ -185,12 +187,12 @@ pub mod tests { let tx = transaction_for_tests(); let expected_signer_addresses = vec![ Address::new([ - 27, 132, 197, 86, 123, 18, 100, 64, 153, 93, 62, 213, 170, 186, 5, 101, 215, 30, - 24, 52, 96, 72, 25, 255, 156, 23, 245, 233, 213, 221, 7, 143, + 14, 238, 36, 40, 114, 150, 186, 85, 39, 143, 30, 84, 3, 190, 1, 71, 84, 134, 99, + 102, 56, 135, 48, 48, 60, 40, 137, 190, 23, 173, 160, 101, ]), Address::new([ - 77, 75, 108, 209, 54, 16, 50, 202, 155, 210, 174, 185, 217, 0, 170, 77, 69, 217, - 234, 216, 10, 201, 66, 51, 116, 196, 81, 167, 37, 77, 7, 102, + 158, 61, 142, 101, 77, 68, 14, 149, 41, 58, 162, 220, 236, 235, 19, 120, 153, 165, + 149, 53, 233, 82, 247, 71, 6, 142, 122, 14, 227, 9, 101, 242, ]), ]; let signer_addresses = tx.signer_addresses(); diff --git a/nssa/src/signature/public_key.rs b/nssa/src/signature/public_key.rs index 2feb6a7..efa732b 100644 --- a/nssa/src/signature/public_key.rs +++ b/nssa/src/signature/public_key.rs @@ -2,6 +2,8 @@ use nssa_core::address::Address; use crate::{PrivateKey, error::NssaError}; +use sha2::{Digest, Sha256}; + #[derive(Debug, Clone, PartialEq, Eq)] pub struct PublicKey([u8; 32]); @@ -30,9 +32,13 @@ impl PublicKey { } impl From<&PublicKey> for Address { - fn from(value: &PublicKey) -> Self { - // TODO: Check specs - Self::new(*value.value()) + fn from(key: &PublicKey) -> Self { + const PUBLIC_ACCOUNT_ID_PREFIX: &[u8; 32] = b"/NSSA/v0.1/AccountId/Public/\x00\x00\x00\x00"; + + let mut hasher = Sha256::new(); + hasher.update(PUBLIC_ACCOUNT_ID_PREFIX); + hasher.update(key.0); + Self::new(hasher.finalize().into()) } } diff --git a/nssa/src/state.rs b/nssa/src/state.rs index ddb659f..ff7431a 100644 --- a/nssa/src/state.rs +++ b/nssa/src/state.rs @@ -808,7 +808,7 @@ pub mod tests { let sender = AccountWithMetadata::new( state.get_account_by_address(&sender_keys.address()), true, - &sender_keys.address(), + sender_keys.address(), ); let sender_nonce = sender.account.nonce; @@ -913,7 +913,7 @@ pub mod tests { let recipient_pre = AccountWithMetadata::new( state.get_account_by_address(recipient_address), false, - recipient_address, + *recipient_address, ); let esk = [3; 32]; diff --git a/sequencer_core/src/lib.rs b/sequencer_core/src/lib.rs index 6c54a50..7da9fab 100644 --- a/sequencer_core/src/lib.rs +++ b/sequencer_core/src/lib.rs @@ -231,13 +231,13 @@ mod tests { fn setup_sequencer_config() -> SequencerConfig { let acc1_addr = vec![ - 27, 132, 197, 86, 123, 18, 100, 64, 153, 93, 62, 213, 170, 186, 5, 101, 215, 30, 24, - 52, 96, 72, 25, 255, 156, 23, 245, 233, 213, 221, 7, 143, + 14, 238, 36, 40, 114, 150, 186, 85, 39, 143, 30, 84, 3, 190, 1, 71, 84, 134, 99, 102, + 56, 135, 48, 48, 60, 40, 137, 190, 23, 173, 160, 101, ]; let acc2_addr = vec![ - 77, 75, 108, 209, 54, 16, 50, 202, 155, 210, 174, 185, 217, 0, 170, 77, 69, 217, 234, - 216, 10, 201, 66, 51, 116, 196, 81, 167, 37, 77, 7, 102, + 158, 61, 142, 101, 77, 68, 14, 149, 41, 58, 162, 220, 236, 235, 19, 120, 153, 165, 149, + 53, 233, 82, 247, 71, 6, 142, 122, 14, 227, 9, 101, 242, ]; let initial_acc1 = AccountInitialData { diff --git a/sequencer_rpc/src/process.rs b/sequencer_rpc/src/process.rs index 1492d19..578c9bd 100644 --- a/sequencer_rpc/src/process.rs +++ b/sequencer_rpc/src/process.rs @@ -308,13 +308,13 @@ mod tests { let tempdir = tempdir().unwrap(); let home = tempdir.path().to_path_buf(); let acc1_addr = vec![ - 27, 132, 197, 86, 123, 18, 100, 64, 153, 93, 62, 213, 170, 186, 5, 101, 215, 30, 24, - 52, 96, 72, 25, 255, 156, 23, 245, 233, 213, 221, 7, 143, + 14, 238, 36, 40, 114, 150, 186, 85, 39, 143, 30, 84, 3, 190, 1, 71, 84, 134, 99, 102, + 56, 135, 48, 48, 60, 40, 137, 190, 23, 173, 160, 101, ]; let acc2_addr = vec![ - 77, 75, 108, 209, 54, 16, 50, 202, 155, 210, 174, 185, 217, 0, 170, 77, 69, 217, 234, - 216, 10, 201, 66, 51, 116, 196, 81, 167, 37, 77, 7, 102, + 158, 61, 142, 101, 77, 68, 14, 149, 41, 58, 162, 220, 236, 235, 19, 120, 153, 165, 149, + 53, 233, 82, 247, 71, 6, 142, 122, 14, 227, 9, 101, 242, ]; let initial_acc1 = AccountInitialData { @@ -352,8 +352,8 @@ mod tests { let balance_to_move = 10; let tx = common::test_utils::create_transaction_native_token_transfer( [ - 27, 132, 197, 86, 123, 18, 100, 64, 153, 93, 62, 213, 170, 186, 5, 101, 215, 30, - 24, 52, 96, 72, 25, 255, 156, 23, 245, 233, 213, 221, 7, 143, + 14, 238, 36, 40, 114, 150, 186, 85, 39, 143, 30, 84, 3, 190, 1, 71, 84, 134, 99, + 102, 56, 135, 48, 48, 60, 40, 137, 190, 23, 173, 160, 101, ], 0, [2; 32], diff --git a/sequencer_runner/configs/debug/sequencer_config.json b/sequencer_runner/configs/debug/sequencer_config.json index f7c6369..75ccf00 100644 --- a/sequencer_runner/configs/debug/sequencer_config.json +++ b/sequencer_runner/configs/debug/sequencer_config.json @@ -8,11 +8,11 @@ "port": 3040, "initial_accounts": [ { - "addr": "1b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078f", + "addr": "0eee24287296ba55278f1e5403be014754866366388730303c2889be17ada065", "balance": 10000 }, { - "addr": "4d4b6cd1361032ca9bd2aeb9d900aa4d45d9ead80ac9423374c451a7254d0766", + "addr": "9e3d8e654d440e95293aa2dceceb137899a59535e952f747068e7a0ee30965f2", "balance": 20000 } ] diff --git a/wallet/src/chain_storage/mod.rs b/wallet/src/chain_storage/mod.rs index 8dc85e1..fdc9abd 100644 --- a/wallet/src/chain_storage/mod.rs +++ b/wallet/src/chain_storage/mod.rs @@ -71,14 +71,14 @@ mod tests { fn create_initial_accounts() -> Vec { let initial_acc1 = serde_json::from_str(r#"{ "Public": { - "address": "1b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078f", + "address": "0eee24287296ba55278f1e5403be014754866366388730303c2889be17ada065", "pub_sign_key": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] } }"#).unwrap(); let initial_acc2 = serde_json::from_str(r#"{ "Public": { - "address": "4d4b6cd1361032ca9bd2aeb9d900aa4d45d9ead80ac9423374c451a7254d0766", + "address": "9e3d8e654d440e95293aa2dceceb137899a59535e952f747068e7a0ee30965f2", "pub_sign_key": [2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2] } }"#).unwrap(); diff --git a/wallet/src/token_transfers/deshielded.rs b/wallet/src/token_transfers/deshielded.rs index 65a4b18..caba8e8 100644 --- a/wallet/src/token_transfers/deshielded.rs +++ b/wallet/src/token_transfers/deshielded.rs @@ -38,7 +38,7 @@ impl WalletCore { let recipient_pre = nssa_core::account::AccountWithMetadata { account: to_acc.clone(), is_authorized: false, - account_id: (&to).into(), + account_id: to, }; //Move into different function diff --git a/wallet/src/token_transfers/shielded.rs b/wallet/src/token_transfers/shielded.rs index b17a452..dcba7a8 100644 --- a/wallet/src/token_transfers/shielded.rs +++ b/wallet/src/token_transfers/shielded.rs @@ -34,7 +34,7 @@ impl WalletCore { let sender_pre = nssa_core::account::AccountWithMetadata { account: from_acc.clone(), is_authorized: true, - account_id: (&from).into(), + account_id: from, }; let recipient_pre = nssa_core::account::AccountWithMetadata { account: to_acc.clone(), @@ -117,7 +117,7 @@ impl WalletCore { let sender_pre = nssa_core::account::AccountWithMetadata { account: from_acc.clone(), is_authorized: true, - account_id: (&from).into(), + account_id: from, }; let recipient_pre = nssa_core::account::AccountWithMetadata { From aa8b1389450ffdbb92cdb1862fe3f4f97492b477 Mon Sep 17 00:00:00 2001 From: Sergio Chouhy Date: Thu, 2 Oct 2025 08:57:03 -0300 Subject: [PATCH 12/24] fmt clippy --- key_protocol/src/key_management/mod.rs | 2 -- nssa/core/src/account.rs | 2 +- nssa/core/src/address.rs | 5 +---- nssa/src/lib.rs | 2 +- nssa/src/state.rs | 5 ++++- 5 files changed, 7 insertions(+), 9 deletions(-) diff --git a/key_protocol/src/key_management/mod.rs b/key_protocol/src/key_management/mod.rs index 73e1ab5..e939fcc 100644 --- a/key_protocol/src/key_management/mod.rs +++ b/key_protocol/src/key_management/mod.rs @@ -1,4 +1,3 @@ -use common::TreeHashType; use log::info; use nssa_core::{ NullifierPublicKey, SharedSecretKey, @@ -6,7 +5,6 @@ use nssa_core::{ }; use secret_holders::{PrivateKeyHolder, SecretSpendingKey, SeedHolder}; use serde::{Deserialize, Serialize}; -use sha2::{Digest, digest::FixedOutput}; pub type PublicAccountSigningKey = [u8; 32]; diff --git a/nssa/core/src/account.rs b/nssa/core/src/account.rs index 889592d..8bce23c 100644 --- a/nssa/core/src/account.rs +++ b/nssa/core/src/account.rs @@ -90,7 +90,7 @@ mod tests { }; let fingerprint = AccountId::new([8; 32]); let new_acc_with_metadata = - AccountWithMetadata::new(account.clone(), true, fingerprint.clone()); + AccountWithMetadata::new(account.clone(), true, fingerprint); assert_eq!(new_acc_with_metadata.account, account); assert!(new_acc_with_metadata.is_authorized); assert_eq!(new_acc_with_metadata.account_id, fingerprint); diff --git a/nssa/core/src/address.rs b/nssa/core/src/address.rs index 14a3018..bbfc6f2 100644 --- a/nssa/core/src/address.rs +++ b/nssa/core/src/address.rs @@ -1,10 +1,7 @@ -use risc0_zkvm::sha::{Impl, Sha256}; use std::{fmt::Display, str::FromStr}; use serde::{Deserialize, Serialize}; -use crate::account::AccountId; - #[derive(Serialize, Deserialize, Clone, PartialEq, Eq)] #[cfg_attr( any(feature = "host", test), @@ -62,7 +59,7 @@ impl Display for Address { #[cfg(test)] mod tests { - use crate::account::AccountId; + use super::{Address, AddressError}; diff --git a/nssa/src/lib.rs b/nssa/src/lib.rs index bf90598..21defa9 100644 --- a/nssa/src/lib.rs +++ b/nssa/src/lib.rs @@ -7,8 +7,8 @@ pub mod public_transaction; mod signature; mod state; -pub use nssa_core::address::Address; pub use nssa_core::account::{Account, AccountId}; +pub use nssa_core::address::Address; pub use privacy_preserving_transaction::{ PrivacyPreservingTransaction, circuit::execute_and_prove, }; diff --git a/nssa/src/state.rs b/nssa/src/state.rs index ff7431a..d9bff5a 100644 --- a/nssa/src/state.rs +++ b/nssa/src/state.rs @@ -4,7 +4,10 @@ use crate::{ public_transaction::PublicTransaction, }; use nssa_core::{ - account::Account, address::Address, program::{ProgramId, DEFAULT_PROGRAM_ID}, Commitment, CommitmentSetDigest, MembershipProof, Nullifier + Commitment, CommitmentSetDigest, MembershipProof, Nullifier, + account::Account, + address::Address, + program::{DEFAULT_PROGRAM_ID, ProgramId}, }; use std::collections::{HashMap, HashSet}; From ddc127f591edd47410ceada85c666edadd6b5ca5 Mon Sep 17 00:00:00 2001 From: Sergio Chouhy Date: Thu, 2 Oct 2025 09:17:19 -0300 Subject: [PATCH 13/24] machete --- common/Cargo.toml | 4 ---- integration_tests/Cargo.toml | 1 - key_protocol/Cargo.toml | 2 -- nssa/Cargo.toml | 1 - nssa/core/src/address.rs | 5 +++-- sequencer_rpc/Cargo.toml | 1 - 6 files changed, 3 insertions(+), 11 deletions(-) diff --git a/common/Cargo.toml b/common/Cargo.toml index 0bb6491..ea01279 100644 --- a/common/Cargo.toml +++ b/common/Cargo.toml @@ -18,9 +18,5 @@ elliptic-curve.workspace = true hex.workspace = true nssa-core = { path = "../nssa/core", features = ["host"] } -[dependencies.secp256k1-zkp] -workspace = true -features = ["std", "rand-std", "rand", "serde", "global-context"] - [dependencies.nssa] path = "../nssa" diff --git a/integration_tests/Cargo.toml b/integration_tests/Cargo.toml index 6d64f98..a5f975b 100644 --- a/integration_tests/Cargo.toml +++ b/integration_tests/Cargo.toml @@ -8,7 +8,6 @@ anyhow.workspace = true env_logger.workspace = true log.workspace = true actix.workspace = true -bytemuck = "1.23.2" actix-web.workspace = true tokio.workspace = true diff --git a/key_protocol/Cargo.toml b/key_protocol/Cargo.toml index d453753..dadc58d 100644 --- a/key_protocol/Cargo.toml +++ b/key_protocol/Cargo.toml @@ -11,10 +11,8 @@ serde.workspace = true k256.workspace = true sha2.workspace = true rand.workspace = true -elliptic-curve.workspace = true hex.workspace = true aes-gcm.workspace = true -lazy_static.workspace = true bip39.workspace = true hmac-sha512.workspace = true nssa-core = { path = "../nssa/core", features = ["host"] } diff --git a/nssa/Cargo.toml b/nssa/Cargo.toml index 4d21e46..93553a8 100644 --- a/nssa/Cargo.toml +++ b/nssa/Cargo.toml @@ -14,7 +14,6 @@ secp256k1 = "0.31.1" rand = "0.8" borsh = "1.5.7" hex = "0.4.3" -k256 = "0.13.3" [dev-dependencies] test-program-methods = { path = "test_program_methods" } diff --git a/nssa/core/src/address.rs b/nssa/core/src/address.rs index bbfc6f2..7b8f4db 100644 --- a/nssa/core/src/address.rs +++ b/nssa/core/src/address.rs @@ -1,7 +1,8 @@ -use std::{fmt::Display, str::FromStr}; - use serde::{Deserialize, Serialize}; +#[cfg(feature = "host")] +use std::{fmt::Display, str::FromStr}; + #[derive(Serialize, Deserialize, Clone, PartialEq, Eq)] #[cfg_attr( any(feature = "host", test), diff --git a/sequencer_rpc/Cargo.toml b/sequencer_rpc/Cargo.toml index 64c69af..7972342 100644 --- a/sequencer_rpc/Cargo.toml +++ b/sequencer_rpc/Cargo.toml @@ -12,7 +12,6 @@ actix-cors.workspace = true futures.workspace = true hex.workspace = true tempfile.workspace = true -nssa-core = { path = "../nssa/core", features = ["host"] } base64.workspace = true actix-web.workspace = true From e69fb8b1b8a5570ecfb543a42dba9c33afb61f1a Mon Sep 17 00:00:00 2001 From: Sergio Chouhy Date: Thu, 2 Oct 2025 22:30:33 -0300 Subject: [PATCH 14/24] fix eph key computation --- .../key_management/ephemeral_key_holder.rs | 21 +-- .../configs/debug/sequencer_config.json | 138 ++++++++++++++++++ wallet/src/lib.rs | 22 ++- wallet/src/token_transfers/deshielded.rs | 29 ++-- wallet/src/token_transfers/private.rs | 89 +++++------ wallet/src/token_transfers/shielded.rs | 22 ++- 6 files changed, 222 insertions(+), 99 deletions(-) diff --git a/key_protocol/src/key_management/ephemeral_key_holder.rs b/key_protocol/src/key_management/ephemeral_key_holder.rs index 63ae2b3..4aef8f9 100644 --- a/key_protocol/src/key_management/ephemeral_key_holder.rs +++ b/key_protocol/src/key_management/ephemeral_key_holder.rs @@ -3,7 +3,7 @@ use nssa_core::{ NullifierPublicKey, SharedSecretKey, encryption::{EphemeralPublicKey, EphemeralSecretKey, IncomingViewingPublicKey}, }; -use rand::{RngCore, rngs::OsRng}; +use rand::{rngs::OsRng, RngCore}; use sha2::Digest; use crate::key_management::secret_holders::OutgoingViewingSecretKey; @@ -27,20 +27,13 @@ pub fn produce_one_sided_shared_secret_receiver( impl EphemeralKeyHolder { pub fn new( - receiver_nullifier_public_key: NullifierPublicKey, - sender_outgoing_viewing_secret_key: OutgoingViewingSecretKey, - nonce: u64, + receiver_nullifier_public_key: &NullifierPublicKey, ) -> Self { + let mut nonce_bytes = [0; 16]; + OsRng.fill_bytes(&mut nonce_bytes); let mut hasher = sha2::Sha256::new(); hasher.update(receiver_nullifier_public_key); - hasher.update(nonce.to_le_bytes()); - hasher.update([0; 24]); - - let hash_recepient = hasher.finalize(); - - let mut hasher = sha2::Sha256::new(); - hasher.update(sender_outgoing_viewing_secret_key); - hasher.update(hash_recepient); + hasher.update(nonce_bytes); Self { ephemeral_secret_key: hasher.finalize().into(), @@ -53,11 +46,11 @@ impl EphemeralKeyHolder { pub fn calculate_shared_secret_sender( &self, - receiver_incoming_viewing_public_key: IncomingViewingPublicKey, + receiver_incoming_viewing_public_key: &IncomingViewingPublicKey, ) -> SharedSecretKey { SharedSecretKey::new( &self.ephemeral_secret_key, - &receiver_incoming_viewing_public_key, + receiver_incoming_viewing_public_key, ) } diff --git a/sequencer_runner/configs/debug/sequencer_config.json b/sequencer_runner/configs/debug/sequencer_config.json index 75ccf00..14de2c1 100644 --- a/sequencer_runner/configs/debug/sequencer_config.json +++ b/sequencer_runner/configs/debug/sequencer_config.json @@ -15,5 +15,143 @@ "addr": "9e3d8e654d440e95293aa2dceceb137899a59535e952f747068e7a0ee30965f2", "balance": 20000 } + ], + "initial_commitments": [ + { + "npk": [ + 193, + 209, + 150, + 113, + 47, + 241, + 48, + 145, + 250, + 79, + 235, + 51, + 119, + 40, + 184, + 232, + 5, + 221, + 36, + 21, + 201, + 106, + 90, + 210, + 129, + 106, + 71, + 99, + 208, + 153, + 75, + 215 + ], + "account": { + "program_owner": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + "balance": 10000, + "data": [], + "nonce": 0 + } + }, + { + "npk": [ + 27, + 250, + 136, + 142, + 88, + 128, + 138, + 21, + 49, + 183, + 118, + 160, + 117, + 114, + 110, + 47, + 136, + 87, + 60, + 70, + 59, + 60, + 18, + 223, + 23, + 147, + 241, + 5, + 184, + 103, + 225, + 105 + ], + "account": { + "program_owner": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + "balance": 20000, + "data": [], + "nonce": 0 + } + } + ], + "signing_key": [ + 37, + 37, + 37, + 37, + 37, + 37, + 37, + 37, + 37, + 37, + 37, + 37, + 37, + 37, + 37, + 37, + 37, + 37, + 37, + 37, + 37, + 37, + 37, + 37, + 37, + 37, + 37, + 37, + 37, + 37, + 37, + 37 ] } diff --git a/wallet/src/lib.rs b/wallet/src/lib.rs index 69b0755..f63515d 100644 --- a/wallet/src/lib.rs +++ b/wallet/src/lib.rs @@ -405,7 +405,7 @@ pub async fn execute_subcommand(command: Command) -> Result Result Result Result Result Result= balance_to_move { let program = nssa::program::Program::authenticated_transfer_program(); + let npk_from = from_keys.nullifer_public_key; + let ipk_from = from_keys.incoming_viewing_public_key; + from_acc.program_owner = program.id(); - let sender_commitment = - nssa_core::Commitment::new(&from_keys.nullifer_public_key, &from_acc); + let sender_commitment = nssa_core::Commitment::new(&npk_from, &from_acc); - let sender_pre = nssa_core::account::AccountWithMetadata { - account: from_acc.clone(), - is_authorized: true, - account_id: (&from_keys.nullifer_public_key).into(), - }; + let sender_pre = + nssa_core::account::AccountWithMetadata::new(from_acc.clone(), true, &npk_from); let recipient_pre = nssa_core::account::AccountWithMetadata { account: to_acc.clone(), is_authorized: false, account_id: to, }; - //Move into different function - let mut esk = [0; 32]; - OsRng.fill_bytes(&mut esk); - let shared_secret = SharedSecretKey::new(&esk, &from_keys.incoming_viewing_public_key); - let epk = EphemeralPublicKey::from_scalar(esk); + let eph_holder = EphemeralKeyHolder::new(&npk_from); + let shared_secret = eph_holder.calculate_shared_secret_sender(&ipk_from); let (output, proof) = nssa::privacy_preserving_transaction::circuit::execute_and_prove( &[sender_pre, recipient_pre], &nssa::program::Program::serialize_instruction(balance_to_move).unwrap(), &[1, 0], &[from_acc.nonce + 1], - &[(from_keys.nullifer_public_key.clone(), shared_secret.clone())], + &[(npk_from.clone(), shared_secret.clone())], &[( from_keys.private_key_holder.nullifier_secret_key, self.sequencer_client @@ -70,9 +67,9 @@ impl WalletCore { vec![to], vec![], vec![( - from_keys.nullifer_public_key.clone(), - from_keys.incoming_viewing_public_key.clone(), - epk, + npk_from.clone(), + ipk_from.clone(), + eph_holder.generate_ephemeral_public_key(), )], output, ) diff --git a/wallet/src/token_transfers/private.rs b/wallet/src/token_transfers/private.rs index abd5620..b11da79 100644 --- a/wallet/src/token_transfers/private.rs +++ b/wallet/src/token_transfers/private.rs @@ -11,7 +11,7 @@ impl WalletCore { to_npk: nssa_core::NullifierPublicKey, to_ipk: nssa_core::encryption::IncomingViewingPublicKey, balance_to_move: u128, - ) -> Result<(SendTxResponse, nssa_core::SharedSecretKey), ExecutionFailureKind> { + ) -> Result<(SendTxResponse, [nssa_core::SharedSecretKey; 2]), ExecutionFailureKind> { let Some((from_keys, mut from_acc)) = self.storage.user_data.get_private_account(&from).cloned() else { @@ -23,30 +23,23 @@ impl WalletCore { if from_acc.balance >= balance_to_move { let program = nssa::program::Program::authenticated_transfer_program(); + let from_npk = from_keys.nullifer_public_key; + let from_ipk = from_keys.incoming_viewing_public_key; + from_acc.program_owner = program.id(); - let sender_commitment = - nssa_core::Commitment::new(&from_keys.nullifer_public_key, &from_acc); + let sender_commitment = nssa_core::Commitment::new(&from_npk, &from_acc); - let sender_pre = nssa_core::account::AccountWithMetadata { - account: from_acc.clone(), - is_authorized: true, - account_id: (&from_keys.nullifer_public_key).into(), - }; + let sender_pre = + nssa_core::account::AccountWithMetadata::new(from_acc.clone(), true, &from_npk); - let recipient_pre = nssa_core::account::AccountWithMetadata { - account: to_acc.clone(), - is_authorized: false, - account_id: (&to_npk).into(), - }; + let recipient_pre = + nssa_core::account::AccountWithMetadata::new(to_acc.clone(), false, &to_npk); - let eph_holder = EphemeralKeyHolder::new( - to_npk.clone(), - from_keys.private_key_holder.outgoing_viewing_secret_key, - from_acc.nonce.try_into().unwrap(), - ); + let eph_holder = EphemeralKeyHolder::new(&to_npk); - let shared_secret = eph_holder.calculate_shared_secret_sender(to_ipk.clone()); + 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) = nssa::privacy_preserving_transaction::circuit::execute_and_prove( &[sender_pre, recipient_pre], @@ -54,8 +47,8 @@ impl WalletCore { &[1, 2], &[from_acc.nonce + 1, to_acc.nonce + 1], &[ - (from_keys.nullifer_public_key.clone(), shared_secret.clone()), - (to_npk.clone(), shared_secret.clone()), + (from_npk.clone(), shared_secret_from.clone()), + (to_npk.clone(), shared_secret_to.clone()), ], &[( from_keys.private_key_holder.nullifier_secret_key, @@ -75,8 +68,8 @@ impl WalletCore { vec![], vec![ ( - from_keys.nullifer_public_key.clone(), - from_keys.incoming_viewing_public_key.clone(), + from_npk.clone(), + from_ipk.clone(), eph_holder.generate_ephemeral_public_key(), ), ( @@ -103,7 +96,7 @@ impl WalletCore { Ok(( self.sequencer_client.send_tx_private(tx).await?, - shared_secret, + [shared_secret_from, shared_secret_to], )) } else { Err(ExecutionFailureKind::InsufficientFundsError) @@ -115,7 +108,7 @@ impl WalletCore { from: Address, to: Address, balance_to_move: u128, - ) -> Result<(SendTxResponse, nssa_core::SharedSecretKey), ExecutionFailureKind> { + ) -> Result<(SendTxResponse, [nssa_core::SharedSecretKey; 2]), ExecutionFailureKind> { let Some((from_keys, mut from_acc)) = self.storage.user_data.get_private_account(&from).cloned() else { @@ -127,6 +120,8 @@ impl WalletCore { 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(); @@ -136,29 +131,19 @@ impl WalletCore { from_acc.program_owner = program.id(); to_acc.program_owner = program.id(); - let sender_commitment = - nssa_core::Commitment::new(&from_keys.nullifer_public_key, &from_acc); - let receiver_commitment = - nssa_core::Commitment::new(&to_keys.nullifer_public_key, &to_acc); + let sender_commitment = nssa_core::Commitment::new(&from_npk, &from_acc); + let receiver_commitment = nssa_core::Commitment::new(&to_npk, &to_acc); - let sender_pre = nssa_core::account::AccountWithMetadata { - account: from_acc.clone(), - is_authorized: true, - account_id: (&from_keys.nullifer_public_key).into(), - }; - let recipient_pre = nssa_core::account::AccountWithMetadata { - account: to_acc.clone(), - is_authorized: true, - account_id: (&to_npk).into(), - }; + let sender_pre = + nssa_core::account::AccountWithMetadata::new(from_acc.clone(), true, &from_npk); + let recipient_pre = + nssa_core::account::AccountWithMetadata::new(to_acc.clone(), true, &to_npk); - let eph_holder = EphemeralKeyHolder::new( - to_npk.clone(), - from_keys.private_key_holder.outgoing_viewing_secret_key, - from_acc.nonce.try_into().unwrap(), - ); + let eph_holder_from = EphemeralKeyHolder::new(&from_npk); + let shared_secret_from = eph_holder_from.calculate_shared_secret_sender(&from_ipk); - let shared_secret = eph_holder.calculate_shared_secret_sender(to_ipk.clone()); + let eph_holder_to = EphemeralKeyHolder::new(&to_npk); + let shared_secret_to = eph_holder_to.calculate_shared_secret_sender(&to_ipk); let (output, proof) = nssa::privacy_preserving_transaction::circuit::execute_and_prove( &[sender_pre, recipient_pre], @@ -166,8 +151,8 @@ impl WalletCore { &[1, 1], &[from_acc.nonce + 1, to_acc.nonce + 1], &[ - (from_keys.nullifer_public_key.clone(), shared_secret.clone()), - (to_npk.clone(), shared_secret.clone()), + (from_npk.clone(), shared_secret_from.clone()), + (to_npk.clone(), shared_secret_to.clone()), ], &[ ( @@ -197,14 +182,14 @@ impl WalletCore { vec![], vec![ ( - from_keys.nullifer_public_key.clone(), - from_keys.incoming_viewing_public_key.clone(), - eph_holder.generate_ephemeral_public_key(), + from_npk.clone(), + from_ipk.clone(), + eph_holder_from.generate_ephemeral_public_key(), ), ( to_npk.clone(), to_ipk.clone(), - eph_holder.generate_ephemeral_public_key(), + eph_holder_to.generate_ephemeral_public_key(), ), ], output, @@ -225,7 +210,7 @@ impl WalletCore { Ok(( self.sequencer_client.send_tx_private(tx).await?, - shared_secret, + [shared_secret_from, shared_secret_to], )) } else { Err(ExecutionFailureKind::InsufficientFundsError) diff --git a/wallet/src/token_transfers/shielded.rs b/wallet/src/token_transfers/shielded.rs index dcba7a8..0c9a9e7 100644 --- a/wallet/src/token_transfers/shielded.rs +++ b/wallet/src/token_transfers/shielded.rs @@ -1,5 +1,7 @@ use common::{ExecutionFailureKind, sequencer_client::json::SendTxResponse}; -use key_protocol::key_management::ephemeral_key_holder::produce_one_sided_shared_secret_receiver; +use key_protocol::key_management::ephemeral_key_holder::{ + EphemeralKeyHolder, produce_one_sided_shared_secret_receiver, +}; use nssa::Address; use crate::WalletCore; @@ -42,7 +44,8 @@ impl WalletCore { account_id: (&to_npk).into(), }; - let (shared_secret, epk) = produce_one_sided_shared_secret_receiver(&to_ipk); + let eph_holder = EphemeralKeyHolder::new(&to_npk); + let shared_secret = eph_holder.calculate_shared_secret_sender(&to_ipk); let (output, proof) = nssa::privacy_preserving_transaction::circuit::execute_and_prove( &[sender_pre, recipient_pre], @@ -66,7 +69,11 @@ impl WalletCore { nssa::privacy_preserving_transaction::message::Message::try_from_circuit_output( vec![from], vec![from_acc.nonce], - vec![(to_npk.clone(), to_ipk.clone(), epk)], + vec![( + to_npk.clone(), + to_ipk.clone(), + eph_holder.generate_ephemeral_public_key(), + )], output, ) .unwrap(); @@ -126,7 +133,8 @@ impl WalletCore { account_id: (&to_npk).into(), }; - let (shared_secret, epk) = produce_one_sided_shared_secret_receiver(&to_ipk); + let eph_holder = EphemeralKeyHolder::new(&to_npk); + let shared_secret = eph_holder.calculate_shared_secret_sender(&to_ipk); let (output, proof) = nssa::privacy_preserving_transaction::circuit::execute_and_prove( &[sender_pre, recipient_pre], @@ -143,7 +151,11 @@ impl WalletCore { nssa::privacy_preserving_transaction::message::Message::try_from_circuit_output( vec![from], vec![from_acc.nonce], - vec![(to_npk.clone(), to_ipk.clone(), epk)], + vec![( + to_npk.clone(), + to_ipk.clone(), + eph_holder.generate_ephemeral_public_key(), + )], output, ) .unwrap(); From d54ea96bba2d801f81e3de09f9c21de1623c1589 Mon Sep 17 00:00:00 2001 From: Sergio Chouhy Date: Fri, 3 Oct 2025 00:44:46 -0300 Subject: [PATCH 15/24] remove resetting program owner in wallet privacy commands --- wallet/src/chain_storage/mod.rs | 9 +++++++-- wallet/src/lib.rs | 25 +++++++++++++++++------- wallet/src/token_transfers/deshielded.rs | 2 -- wallet/src/token_transfers/private.rs | 5 ----- wallet/src/token_transfers/shielded.rs | 2 -- 5 files changed, 25 insertions(+), 18 deletions(-) diff --git a/wallet/src/chain_storage/mod.rs b/wallet/src/chain_storage/mod.rs index fdc9abd..825d51c 100644 --- a/wallet/src/chain_storage/mod.rs +++ b/wallet/src/chain_storage/mod.rs @@ -2,6 +2,7 @@ use std::collections::HashMap; use anyhow::Result; use key_protocol::key_protocol_core::NSSAUserData; +use nssa::program::Program; use crate::config::{InitialAccountData, PersistentAccountData, WalletConfig}; @@ -21,8 +22,12 @@ impl WalletChainStore { public_init_acc_map.insert(data.address.parse()?, data.pub_sign_key); } InitialAccountData::Private(data) => { - private_init_acc_map - .insert(data.address.parse()?, (data.key_chain, data.account)); + let mut account = data.account; + // TODO: Program owner is only known after code is compiled and can't be set in + // the config. Therefore we overwrite it here on startup. Fix this when program + // id can be fetched from the node and queried from the wallet. + account.program_owner = Program::authenticated_transfer_program().id(); + private_init_acc_map.insert(data.address.parse()?, (data.key_chain, account)); } } } diff --git a/wallet/src/lib.rs b/wallet/src/lib.rs index f63515d..116c19e 100644 --- a/wallet/src/lib.rs +++ b/wallet/src/lib.rs @@ -431,9 +431,13 @@ pub async fn execute_subcommand(command: Command) -> Result Result Result= balance_to_move { let program = nssa::program::Program::authenticated_transfer_program(); - from_acc.program_owner = program.id(); - to_acc.program_owner = program.id(); - let sender_commitment = nssa_core::Commitment::new(&from_npk, &from_acc); let receiver_commitment = nssa_core::Commitment::new(&to_npk, &to_acc); diff --git a/wallet/src/token_transfers/shielded.rs b/wallet/src/token_transfers/shielded.rs index 0c9a9e7..5f8dd75 100644 --- a/wallet/src/token_transfers/shielded.rs +++ b/wallet/src/token_transfers/shielded.rs @@ -28,8 +28,6 @@ impl WalletCore { if from_acc.balance >= balance_to_move { let program = nssa::program::Program::authenticated_transfer_program(); - to_acc.program_owner = program.id(); - let receiver_commitment = nssa_core::Commitment::new(&to_keys.nullifer_public_key, &to_acc); From 9141fbf06c9c43ade5d368888357ec9d50aaadf1 Mon Sep 17 00:00:00 2001 From: Sergio Chouhy Date: Fri, 3 Oct 2025 01:30:40 -0300 Subject: [PATCH 16/24] use random nonces for private accounts in wallet --- wallet/Cargo.toml | 1 + wallet/src/helperfunctions.rs | 11 +++++++++++ wallet/src/token_transfers/deshielded.rs | 4 ++-- wallet/src/token_transfers/private.rs | 6 +++--- wallet/src/token_transfers/shielded.rs | 6 +++--- 5 files changed, 20 insertions(+), 8 deletions(-) diff --git a/wallet/Cargo.toml b/wallet/Cargo.toml index 5884ffa..1bbd79e 100644 --- a/wallet/Cargo.toml +++ b/wallet/Cargo.toml @@ -17,6 +17,7 @@ base64.workspace = true k256 = { version = "0.13.3" } bytemuck = "1.23.2" hex.workspace = true +rand.workspace = true [dependencies.key_protocol] path = "../key_protocol" diff --git a/wallet/src/helperfunctions.rs b/wallet/src/helperfunctions.rs index b46fe19..ff0ccf9 100644 --- a/wallet/src/helperfunctions.rs +++ b/wallet/src/helperfunctions.rs @@ -1,4 +1,6 @@ use base64::{Engine, engine::general_purpose::STANDARD as BASE64}; +use nssa_core::account::Nonce; +use rand::{RngCore, rngs::OsRng}; use std::{fs::File, io::BufReader, path::PathBuf, str::FromStr}; use anyhow::Result; @@ -82,6 +84,15 @@ pub fn produce_data_for_storage(user_data: &NSSAUserData) -> Vec Vec { + let mut result = vec![[0; 16]; size]; + result.iter_mut().for_each(|bytes| OsRng.fill_bytes(bytes)); + result + .into_iter() + .map(Nonce::from_le_bytes) + .collect() +} + /// Human-readable representation of an account. #[derive(Serialize)] pub(crate) struct HumanReadableAccount { diff --git a/wallet/src/token_transfers/deshielded.rs b/wallet/src/token_transfers/deshielded.rs index 094afe7..f01b8f5 100644 --- a/wallet/src/token_transfers/deshielded.rs +++ b/wallet/src/token_transfers/deshielded.rs @@ -4,7 +4,7 @@ use key_protocol::key_management::ephemeral_key_holder::EphemeralKeyHolder; use nssa::Address; use nssa_core::{SharedSecretKey, encryption::EphemeralPublicKey}; -use crate::WalletCore; +use crate::{helperfunctions::produce_random_nonces, WalletCore}; impl WalletCore { pub async fn send_deshielded_native_token_transfer( @@ -46,7 +46,7 @@ impl WalletCore { &[sender_pre, recipient_pre], &nssa::program::Program::serialize_instruction(balance_to_move).unwrap(), &[1, 0], - &[from_acc.nonce + 1], + &produce_random_nonces(1), &[(npk_from.clone(), shared_secret.clone())], &[( from_keys.private_key_holder.nullifier_secret_key, diff --git a/wallet/src/token_transfers/private.rs b/wallet/src/token_transfers/private.rs index 4120571..c46ea85 100644 --- a/wallet/src/token_transfers/private.rs +++ b/wallet/src/token_transfers/private.rs @@ -2,7 +2,7 @@ use common::{ExecutionFailureKind, sequencer_client::json::SendTxResponse}; use key_protocol::key_management::ephemeral_key_holder::EphemeralKeyHolder; use nssa::Address; -use crate::WalletCore; +use crate::{WalletCore, helperfunctions::produce_random_nonces}; impl WalletCore { pub async fn send_private_native_token_transfer_outer_account( @@ -43,7 +43,7 @@ impl WalletCore { &[sender_pre, recipient_pre], &nssa::program::Program::serialize_instruction(balance_to_move).unwrap(), &[1, 2], - &[from_acc.nonce + 1, to_acc.nonce + 1], + &produce_random_nonces(2), &[ (from_npk.clone(), shared_secret_from.clone()), (to_npk.clone(), shared_secret_to.clone()), @@ -144,7 +144,7 @@ impl WalletCore { &[sender_pre, recipient_pre], &nssa::program::Program::serialize_instruction(balance_to_move).unwrap(), &[1, 1], - &[from_acc.nonce + 1, to_acc.nonce + 1], + &produce_random_nonces(2), &[ (from_npk.clone(), shared_secret_from.clone()), (to_npk.clone(), shared_secret_to.clone()), diff --git a/wallet/src/token_transfers/shielded.rs b/wallet/src/token_transfers/shielded.rs index 5f8dd75..a81af1e 100644 --- a/wallet/src/token_transfers/shielded.rs +++ b/wallet/src/token_transfers/shielded.rs @@ -4,7 +4,7 @@ use key_protocol::key_management::ephemeral_key_holder::{ }; use nssa::Address; -use crate::WalletCore; +use crate::{WalletCore, helperfunctions::produce_random_nonces}; impl WalletCore { pub async fn send_shielded_native_token_transfer( @@ -49,7 +49,7 @@ impl WalletCore { &[sender_pre, recipient_pre], &nssa::program::Program::serialize_instruction(balance_to_move).unwrap(), &[0, 1], - &[to_acc.nonce + 1], + &produce_random_nonces(1), &[(to_npk.clone(), shared_secret.clone())], &[( to_keys.private_key_holder.nullifier_secret_key, @@ -138,7 +138,7 @@ impl WalletCore { &[sender_pre, recipient_pre], &nssa::program::Program::serialize_instruction(balance_to_move).unwrap(), &[0, 2], - &[to_acc.nonce + 1], + &produce_random_nonces(1), &[(to_npk.clone(), shared_secret.clone())], &[], &program, From 46f899ac95862146c13c322c9c78fffb20a4a5b4 Mon Sep 17 00:00:00 2001 From: Sergio Chouhy Date: Fri, 3 Oct 2025 08:08:54 -0300 Subject: [PATCH 17/24] fmt --- key_protocol/src/key_management/ephemeral_key_holder.rs | 8 ++------ key_protocol/src/key_management/mod.rs | 1 - nssa/core/src/account.rs | 3 +-- nssa/core/src/address.rs | 5 ++--- wallet/src/helperfunctions.rs | 5 +---- wallet/src/lib.rs | 4 ++-- wallet/src/token_transfers/deshielded.rs | 6 ++---- wallet/src/token_transfers/private.rs | 6 +++--- wallet/src/token_transfers/shielded.rs | 6 ++---- 9 files changed, 15 insertions(+), 29 deletions(-) diff --git a/key_protocol/src/key_management/ephemeral_key_holder.rs b/key_protocol/src/key_management/ephemeral_key_holder.rs index 4aef8f9..8d4b3ac 100644 --- a/key_protocol/src/key_management/ephemeral_key_holder.rs +++ b/key_protocol/src/key_management/ephemeral_key_holder.rs @@ -3,11 +3,9 @@ use nssa_core::{ NullifierPublicKey, SharedSecretKey, encryption::{EphemeralPublicKey, EphemeralSecretKey, IncomingViewingPublicKey}, }; -use rand::{rngs::OsRng, RngCore}; +use rand::{RngCore, rngs::OsRng}; use sha2::Digest; -use crate::key_management::secret_holders::OutgoingViewingSecretKey; - #[derive(Debug)] ///Ephemeral secret key holder. Non-clonable as intended for one-time use. Produces ephemeral public keys. Can produce shared secret for sender. pub struct EphemeralKeyHolder { @@ -26,9 +24,7 @@ pub fn produce_one_sided_shared_secret_receiver( } impl EphemeralKeyHolder { - pub fn new( - receiver_nullifier_public_key: &NullifierPublicKey, - ) -> Self { + pub fn new(receiver_nullifier_public_key: &NullifierPublicKey) -> Self { let mut nonce_bytes = [0; 16]; OsRng.fill_bytes(&mut nonce_bytes); let mut hasher = sha2::Sha256::new(); diff --git a/key_protocol/src/key_management/mod.rs b/key_protocol/src/key_management/mod.rs index e939fcc..66e86e3 100644 --- a/key_protocol/src/key_management/mod.rs +++ b/key_protocol/src/key_management/mod.rs @@ -20,7 +20,6 @@ pub struct KeyChain { pub incoming_viewing_public_key: IncomingViewingPublicKey, } - impl KeyChain { pub fn new_os_random() -> Self { //Currently dropping SeedHolder at the end of initialization. diff --git a/nssa/core/src/account.rs b/nssa/core/src/account.rs index 8bce23c..fbd2e66 100644 --- a/nssa/core/src/account.rs +++ b/nssa/core/src/account.rs @@ -89,8 +89,7 @@ mod tests { nonce: 0xdeadbeef, }; let fingerprint = AccountId::new([8; 32]); - let new_acc_with_metadata = - AccountWithMetadata::new(account.clone(), true, fingerprint); + let new_acc_with_metadata = AccountWithMetadata::new(account.clone(), true, fingerprint); assert_eq!(new_acc_with_metadata.account, account); assert!(new_acc_with_metadata.is_authorized); assert_eq!(new_acc_with_metadata.account_id, fingerprint); diff --git a/nssa/core/src/address.rs b/nssa/core/src/address.rs index 7b8f4db..2627368 100644 --- a/nssa/core/src/address.rs +++ b/nssa/core/src/address.rs @@ -3,10 +3,10 @@ use serde::{Deserialize, Serialize}; #[cfg(feature = "host")] use std::{fmt::Display, str::FromStr}; -#[derive(Serialize, Deserialize, Clone, PartialEq, Eq)] +#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, Hash)] #[cfg_attr( any(feature = "host", test), - derive(Debug, Copy, PartialOrd, Ord, Hash, Default) + derive(Debug, Copy, PartialOrd, Ord, Default) )] pub struct Address { value: [u8; 32], @@ -60,7 +60,6 @@ impl Display for Address { #[cfg(test)] mod tests { - use super::{Address, AddressError}; diff --git a/wallet/src/helperfunctions.rs b/wallet/src/helperfunctions.rs index ff0ccf9..d08f206 100644 --- a/wallet/src/helperfunctions.rs +++ b/wallet/src/helperfunctions.rs @@ -87,10 +87,7 @@ pub fn produce_data_for_storage(user_data: &NSSAUserData) -> Vec Vec { let mut result = vec![[0; 16]; size]; result.iter_mut().for_each(|bytes| OsRng.fill_bytes(bytes)); - result - .into_iter() - .map(Nonce::from_le_bytes) - .collect() + result.into_iter().map(Nonce::from_le_bytes).collect() } /// Human-readable representation of an account. diff --git a/wallet/src/lib.rs b/wallet/src/lib.rs index 116c19e..3308248 100644 --- a/wallet/src/lib.rs +++ b/wallet/src/lib.rs @@ -712,7 +712,7 @@ pub async fn execute_subcommand(command: Command) -> Result { let addr = wallet_core.create_new_account_private(); - let (key, account) = wallet_core + let (key, _) = wallet_core .storage .user_data .get_private_account(&addr) @@ -722,7 +722,7 @@ pub async fn execute_subcommand(command: Command) -> Result Result<(SendTxResponse, nssa_core::SharedSecretKey), ExecutionFailureKind> { - let Some((from_keys, mut from_acc)) = + let Some((from_keys, from_acc)) = self.storage.user_data.get_private_account(&from).cloned() else { return Err(ExecutionFailureKind::KeyNotFoundError); diff --git a/wallet/src/token_transfers/private.rs b/wallet/src/token_transfers/private.rs index c46ea85..afdbb52 100644 --- a/wallet/src/token_transfers/private.rs +++ b/wallet/src/token_transfers/private.rs @@ -12,7 +12,7 @@ impl WalletCore { to_ipk: nssa_core::encryption::IncomingViewingPublicKey, balance_to_move: u128, ) -> Result<(SendTxResponse, [nssa_core::SharedSecretKey; 2]), ExecutionFailureKind> { - let Some((from_keys, mut from_acc)) = + let Some((from_keys, from_acc)) = self.storage.user_data.get_private_account(&from).cloned() else { return Err(ExecutionFailureKind::KeyNotFoundError); @@ -107,13 +107,13 @@ impl WalletCore { to: Address, balance_to_move: u128, ) -> Result<(SendTxResponse, [nssa_core::SharedSecretKey; 2]), ExecutionFailureKind> { - let Some((from_keys, mut from_acc)) = + let Some((from_keys, from_acc)) = self.storage.user_data.get_private_account(&from).cloned() else { return Err(ExecutionFailureKind::KeyNotFoundError); }; - let Some((to_keys, mut to_acc)) = self.storage.user_data.get_private_account(&to).cloned() + let Some((to_keys, to_acc)) = self.storage.user_data.get_private_account(&to).cloned() else { return Err(ExecutionFailureKind::KeyNotFoundError); }; diff --git a/wallet/src/token_transfers/shielded.rs b/wallet/src/token_transfers/shielded.rs index a81af1e..5de293c 100644 --- a/wallet/src/token_transfers/shielded.rs +++ b/wallet/src/token_transfers/shielded.rs @@ -1,7 +1,5 @@ use common::{ExecutionFailureKind, sequencer_client::json::SendTxResponse}; -use key_protocol::key_management::ephemeral_key_holder::{ - EphemeralKeyHolder, produce_one_sided_shared_secret_receiver, -}; +use key_protocol::key_management::ephemeral_key_holder::EphemeralKeyHolder; use nssa::Address; use crate::{WalletCore, helperfunctions::produce_random_nonces}; @@ -17,7 +15,7 @@ impl WalletCore { return Err(ExecutionFailureKind::KeyNotFoundError); }; - let Some((to_keys, mut to_acc)) = self.storage.user_data.get_private_account(&to).cloned() + let Some((to_keys, to_acc)) = self.storage.user_data.get_private_account(&to).cloned() else { return Err(ExecutionFailureKind::KeyNotFoundError); }; From b6e70195883152564b9ad1b2c76145eb046489e1 Mon Sep 17 00:00:00 2001 From: Sergio Chouhy Date: Fri, 3 Oct 2025 08:44:15 -0300 Subject: [PATCH 18/24] use account with metadata constructor --- wallet/src/token_transfers/deshielded.rs | 10 +++------ wallet/src/token_transfers/private.rs | 7 +++--- wallet/src/token_transfers/shielded.rs | 28 ++++++------------------ 3 files changed, 13 insertions(+), 32 deletions(-) diff --git a/wallet/src/token_transfers/deshielded.rs b/wallet/src/token_transfers/deshielded.rs index f193c63..5c8415e 100644 --- a/wallet/src/token_transfers/deshielded.rs +++ b/wallet/src/token_transfers/deshielded.rs @@ -1,6 +1,7 @@ use common::{ExecutionFailureKind, sequencer_client::json::SendTxResponse}; use key_protocol::key_management::ephemeral_key_holder::EphemeralKeyHolder; use nssa::Address; +use nssa_core::account::AccountWithMetadata; use crate::{WalletCore, helperfunctions::produce_random_nonces}; @@ -29,13 +30,8 @@ impl WalletCore { let sender_commitment = nssa_core::Commitment::new(&npk_from, &from_acc); - let sender_pre = - nssa_core::account::AccountWithMetadata::new(from_acc.clone(), true, &npk_from); - let recipient_pre = nssa_core::account::AccountWithMetadata { - account: to_acc.clone(), - is_authorized: false, - account_id: to, - }; + 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); diff --git a/wallet/src/token_transfers/private.rs b/wallet/src/token_transfers/private.rs index afdbb52..4b1c5fa 100644 --- a/wallet/src/token_transfers/private.rs +++ b/wallet/src/token_transfers/private.rs @@ -1,6 +1,7 @@ use common::{ExecutionFailureKind, sequencer_client::json::SendTxResponse}; use key_protocol::key_management::ephemeral_key_holder::EphemeralKeyHolder; use nssa::Address; +use nssa_core::account::AccountWithMetadata; use crate::{WalletCore, helperfunctions::produce_random_nonces}; @@ -129,10 +130,8 @@ impl WalletCore { let sender_commitment = nssa_core::Commitment::new(&from_npk, &from_acc); let receiver_commitment = nssa_core::Commitment::new(&to_npk, &to_acc); - let sender_pre = - nssa_core::account::AccountWithMetadata::new(from_acc.clone(), true, &from_npk); - let recipient_pre = - nssa_core::account::AccountWithMetadata::new(to_acc.clone(), true, &to_npk); + 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); diff --git a/wallet/src/token_transfers/shielded.rs b/wallet/src/token_transfers/shielded.rs index 5de293c..c0a2d1c 100644 --- a/wallet/src/token_transfers/shielded.rs +++ b/wallet/src/token_transfers/shielded.rs @@ -1,6 +1,7 @@ use common::{ExecutionFailureKind, sequencer_client::json::SendTxResponse}; use key_protocol::key_management::ephemeral_key_holder::EphemeralKeyHolder; use nssa::Address; +use nssa_core::account::AccountWithMetadata; use crate::{WalletCore, helperfunctions::produce_random_nonces}; @@ -29,16 +30,10 @@ impl WalletCore { let receiver_commitment = nssa_core::Commitment::new(&to_keys.nullifer_public_key, &to_acc); - let sender_pre = nssa_core::account::AccountWithMetadata { - account: from_acc.clone(), - is_authorized: true, - account_id: from, - }; - let recipient_pre = nssa_core::account::AccountWithMetadata { - account: to_acc.clone(), - is_authorized: true, - account_id: (&to_npk).into(), - }; + let sender_pre = + nssa_core::account::AccountWithMetadata::new(from_acc.clone(), true, from); + let recipient_pre = + nssa_core::account::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); @@ -117,17 +112,8 @@ impl WalletCore { if from_acc.balance >= balance_to_move { let program = nssa::program::Program::authenticated_transfer_program(); - let sender_pre = nssa_core::account::AccountWithMetadata { - account: from_acc.clone(), - is_authorized: true, - account_id: from, - }; - - let recipient_pre = nssa_core::account::AccountWithMetadata { - account: to_acc.clone(), - is_authorized: false, - account_id: (&to_npk).into(), - }; + 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); From 8f874a6b4ff6ba03757c2eba0bda0a1a3227fb0a Mon Sep 17 00:00:00 2001 From: Sergio Chouhy Date: Fri, 3 Oct 2025 15:59:27 -0300 Subject: [PATCH 19/24] refactor --- integration_tests/Cargo.toml | 2 +- integration_tests/src/lib.rs | 526 +++++++++-------------- wallet/src/chain_storage/mod.rs | 1 + wallet/src/helperfunctions.rs | 5 - wallet/src/lib.rs | 60 ++- wallet/src/token_transfers/deshielded.rs | 53 ++- wallet/src/token_transfers/private.rs | 142 +++--- wallet/src/token_transfers/public.rs | 21 +- wallet/src/token_transfers/shielded.rs | 115 +++-- 9 files changed, 395 insertions(+), 530 deletions(-) diff --git a/integration_tests/Cargo.toml b/integration_tests/Cargo.toml index a5f975b..75edf51 100644 --- a/integration_tests/Cargo.toml +++ b/integration_tests/Cargo.toml @@ -8,8 +8,8 @@ anyhow.workspace = true env_logger.workspace = true log.workspace = true actix.workspace = true - actix-web.workspace = true +base64.workspace = true tokio.workspace = true hex.workspace = true tempfile.workspace = true diff --git a/integration_tests/src/lib.rs b/integration_tests/src/lib.rs index 87df4b1..58d2edc 100644 --- a/integration_tests/src/lib.rs +++ b/integration_tests/src/lib.rs @@ -1,12 +1,18 @@ +use base64::{Engine, engine::general_purpose::STANDARD as BASE64}; use std::{path::PathBuf, time::Duration}; use actix_web::dev::ServerHandle; use anyhow::Result; use clap::Parser; -use common::sequencer_client::SequencerClient; +use common::{ + sequencer_client::SequencerClient, + transaction::{EncodedTransaction, NSSATransaction}, +}; use log::{info, warn}; -use nssa::program::Program; -use nssa_core::{NullifierPublicKey, encryption::shared_key_derivation::Secp256k1Point}; +use nssa::{Address, PrivacyPreservingTransaction, program::Program}; +use nssa_core::{ + Commitment, NullifierPublicKey, encryption::shared_key_derivation::Secp256k1Point, +}; use sequencer_core::config::SequencerConfig; use sequencer_runner::startup_sequencer; use tempfile::TempDir; @@ -14,7 +20,7 @@ use tokio::task::JoinHandle; use wallet::{ Command, SubcommandReturnValue, WalletCore, config::PersistentAccountData, - helperfunctions::{fetch_config, fetch_persistent_accounts, produce_account_addr_from_hex}, + helperfunctions::{fetch_config, fetch_persistent_accounts}, }; #[derive(Parser, Debug)] @@ -443,159 +449,118 @@ pub async fn test_success_token_program() { pub async fn test_success_private_transfer_to_another_owned_account() { info!("test_success_private_transfer_to_another_owned_account"); + let from: Address = ACC_SENDER_PRIVATE.parse().unwrap(); + let to: Address = ACC_RECEIVER_PRIVATE.parse().unwrap(); + let command = Command::SendNativeTokenTransferPrivateOwnedAccount { - from: ACC_SENDER_PRIVATE.to_string(), - to: ACC_RECEIVER_PRIVATE.to_string(), + from: from.to_string(), + to: to.to_string(), amount: 100, }; - let from = produce_account_addr_from_hex(ACC_SENDER_PRIVATE.to_string()).unwrap(); - let to = produce_account_addr_from_hex(ACC_RECEIVER_PRIVATE.to_string()).unwrap(); - - let wallet_config = fetch_config().unwrap(); - - let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap(); - - let mut wallet_storage = WalletCore::start_from_config_update_chain(wallet_config).unwrap(); - - wallet::execute_subcommand(command).await.unwrap(); + let SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash } = + wallet::execute_subcommand(command).await.unwrap() + else { + panic!("invalid subcommand return value"); + }; info!("Waiting for next block creation"); tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; - let new_commitment1 = { - let from_acc = wallet_storage - .storage - .user_data - .get_private_account_mut(&from) - .unwrap(); - - from_acc.1.program_owner = nssa::program::Program::authenticated_transfer_program().id(); - from_acc.1.balance -= 100; - from_acc.1.nonce += 1; - - nssa_core::Commitment::new(&from_acc.0.nullifer_public_key, &from_acc.1) + let command = Command::ClaimPrivateAccount { + tx_hash: tx_hash.clone(), + acc_addr: from.to_string(), + ciph_id: 0, }; + wallet::execute_subcommand(command).await.unwrap(); - let new_commitment2 = { - let to_acc = wallet_storage - .storage - .user_data - .get_private_account_mut(&to) - .unwrap(); - - to_acc.1.program_owner = nssa::program::Program::authenticated_transfer_program().id(); - to_acc.1.balance += 100; - to_acc.1.nonce += 1; - - nssa_core::Commitment::new(&to_acc.0.nullifer_public_key, &to_acc.1) + let command = Command::ClaimPrivateAccount { + tx_hash, + acc_addr: to.to_string(), + ciph_id: 1, }; + wallet::execute_subcommand(command).await.unwrap(); - let proof1 = seq_client - .get_proof_for_commitment(new_commitment1) - .await - .unwrap() - .unwrap(); - let proof2 = seq_client - .get_proof_for_commitment(new_commitment2) - .await - .unwrap() - .unwrap(); + let wallet_config = fetch_config().unwrap(); + let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap(); + let wallet_storage = WalletCore::start_from_config_update_chain(wallet_config).unwrap(); - println!("New proof is {proof1:#?}"); - println!("New proof is {proof2:#?}"); + let new_commitment1 = wallet_storage + .get_private_account_commitment(&from) + .unwrap(); + assert!(verify_commitment_is_in_state(new_commitment1, &seq_client).await); + + let new_commitment2 = wallet_storage.get_private_account_commitment(&to).unwrap(); + assert!(verify_commitment_is_in_state(new_commitment2, &seq_client).await); info!("Success!"); } pub async fn test_success_private_transfer_to_another_foreign_account() { info!("test_success_private_transfer_to_another_foreign_account"); - let to_npk_orig = NullifierPublicKey([42; 32]); - let to_npk = hex::encode(to_npk_orig.0); - let to_ipk = Secp256k1Point::from_scalar(to_npk_orig.0); + let from: Address = ACC_SENDER_PRIVATE.parse().unwrap(); + let to_npk = NullifierPublicKey([42; 32]); + let to_npk_string = hex::encode(to_npk.0); + let to_ipk = Secp256k1Point::from_scalar(to_npk.0); let command = Command::SendNativeTokenTransferPrivateForeignAccount { - from: ACC_SENDER_PRIVATE.to_string(), - to_npk, + from: from.to_string(), + to_npk: to_npk_string, to_ipk: hex::encode(to_ipk.0), amount: 100, }; - let from = produce_account_addr_from_hex(ACC_SENDER_PRIVATE.to_string()).unwrap(); - - let wallet_config = fetch_config().unwrap(); - - let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap(); - - let mut wallet_storage = WalletCore::start_from_config_update_chain(wallet_config).unwrap(); - - let sub_ret = wallet::execute_subcommand(command).await.unwrap(); - - println!("SUB RET is {sub_ret:#?}"); + let SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash } = + wallet::execute_subcommand(command).await.unwrap() + else { + panic!("invalid subcommand return value"); + }; info!("Waiting for next block creation"); tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; - let new_commitment1 = { - let from_acc = wallet_storage - .storage - .user_data - .get_private_account_mut(&from) - .unwrap(); - - from_acc.1.program_owner = nssa::program::Program::authenticated_transfer_program().id(); - from_acc.1.balance -= 100; - from_acc.1.nonce += 1; - - nssa_core::Commitment::new(&from_acc.0.nullifer_public_key, &from_acc.1) + let command = Command::ClaimPrivateAccount { + tx_hash: tx_hash.clone(), + acc_addr: from.to_string(), + ciph_id: 0, }; + wallet::execute_subcommand(command).await.unwrap(); - let new_commitment2 = { - let to_acc = nssa_core::account::Account { - program_owner: nssa::program::Program::authenticated_transfer_program().id(), - balance: 100, - data: vec![], - nonce: 1, - }; + let wallet_config = fetch_config().unwrap(); + let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap(); + let wallet_storage = WalletCore::start_from_config_update_chain(wallet_config).unwrap(); - nssa_core::Commitment::new(&to_npk_orig, &to_acc) - }; - - let proof1 = seq_client - .get_proof_for_commitment(new_commitment1) - .await - .unwrap() - .unwrap(); - let proof2 = seq_client - .get_proof_for_commitment(new_commitment2) - .await - .unwrap() + let new_commitment1 = wallet_storage + .get_private_account_commitment(&from) .unwrap(); - println!("New proof is {proof1:#?}"); - println!("New proof is {proof2:#?}"); + let tx = fetch_privacy_preserving_tx(&seq_client, tx_hash.clone()).await; + assert_eq!(tx.message.new_commitments[0], new_commitment1); + + assert_eq!(tx.message.new_commitments.len(), 2); + for commitment in tx.message.new_commitments.into_iter() { + assert!(verify_commitment_is_in_state(commitment, &seq_client).await); + } info!("Success!"); } pub async fn test_success_private_transfer_to_another_owned_account_claiming_path() { info!("test_success_private_transfer_to_another_owned_account_claiming_path"); + let from: Address = ACC_SENDER_PRIVATE.parse().unwrap(); + let command = Command::RegisterAccountPrivate {}; let sub_ret = wallet::execute_subcommand(command).await.unwrap(); - let SubcommandReturnValue::RegisterAccount { addr: to_addr } = sub_ret else { panic!("FAILED TO REGISTER ACCOUNT"); }; let wallet_config = fetch_config().unwrap(); - let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap(); + let wallet_storage = WalletCore::start_from_config_update_chain(wallet_config.clone()).unwrap(); - let mut wallet_storage = - WalletCore::start_from_config_update_chain(wallet_config.clone()).unwrap(); - - let (to_keys, mut to_acc) = wallet_storage + let (to_keys, _) = wallet_storage .storage .user_data .user_private_accounts @@ -604,74 +569,38 @@ pub async fn test_success_private_transfer_to_another_owned_account_claiming_pat .unwrap(); let command = Command::SendNativeTokenTransferPrivateForeignAccount { - from: ACC_SENDER_PRIVATE.to_string(), + from: from.to_string(), to_npk: hex::encode(to_keys.nullifer_public_key.0), to_ipk: hex::encode(to_keys.incoming_viewing_public_key.0), amount: 100, }; - let from = produce_account_addr_from_hex(ACC_SENDER_PRIVATE.to_string()).unwrap(); - let sub_ret = wallet::execute_subcommand(command).await.unwrap(); - let SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash } = sub_ret else { panic!("FAILED TO SEND TX"); }; - info!("Waiting for next block creation"); - tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; - - let new_commitment1 = { - let from_acc = wallet_storage - .storage - .user_data - .get_private_account_mut(&from) - .unwrap(); - - from_acc.1.program_owner = nssa::program::Program::authenticated_transfer_program().id(); - from_acc.1.balance -= 100; - from_acc.1.nonce += 1; - - nssa_core::Commitment::new(&from_acc.0.nullifer_public_key, &from_acc.1) - }; - - let new_commitment2 = { - to_acc.program_owner = nssa::program::Program::authenticated_transfer_program().id(); - to_acc.balance = 100; - to_acc.nonce = 1; - - nssa_core::Commitment::new(&to_keys.nullifer_public_key, &to_acc) - }; - - let proof1 = seq_client - .get_proof_for_commitment(new_commitment1) - .await - .unwrap() - .unwrap(); - let proof2 = seq_client - .get_proof_for_commitment(new_commitment2) - .await - .unwrap() - .unwrap(); - - println!("New proof is {proof1:#?}"); - println!("New proof is {proof2:#?}"); + let tx = fetch_privacy_preserving_tx(&seq_client, tx_hash.clone()).await; let command = Command::ClaimPrivateAccount { tx_hash, - acc_addr: hex::encode(to_addr), + acc_addr: to_addr.to_string(), ciph_id: 1, }; - wallet::execute_subcommand(command).await.unwrap(); - let wallet_storage = WalletCore::start_from_config_update_chain(wallet_config).unwrap(); - let (_, to_res_acc) = wallet_storage - .storage - .user_data - .get_private_account(&to_addr) + let new_commitment1 = wallet_storage + .get_private_account_commitment(&from) .unwrap(); + assert_eq!(tx.message.new_commitments[0], new_commitment1); + + assert_eq!(tx.message.new_commitments.len(), 2); + for commitment in tx.message.new_commitments.into_iter() { + assert!(verify_commitment_is_in_state(commitment, &seq_client).await); + } + + let to_res_acc = wallet_storage.get_account_private(&to_addr).unwrap(); assert_eq!(to_res_acc.balance, 100); @@ -680,51 +609,50 @@ pub async fn test_success_private_transfer_to_another_owned_account_claiming_pat pub async fn test_success_deshielded_transfer_to_another_account() { info!("test_success_deshielded_transfer_to_another_account"); + let from: Address = ACC_SENDER_PRIVATE.parse().unwrap(); + let to: Address = ACC_RECEIVER.parse().unwrap(); let command = Command::SendNativeTokenTransferDeshielded { - from: ACC_SENDER_PRIVATE.to_string(), - to: ACC_RECEIVER.to_string(), + from: from.to_string(), + to: to.to_string(), amount: 100, }; - let from = produce_account_addr_from_hex(ACC_SENDER_PRIVATE.to_string()).unwrap(); - let wallet_config = fetch_config().unwrap(); - let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap(); + let wallet_storage = WalletCore::start_from_config_update_chain(wallet_config.clone()).unwrap(); - let mut wallet_storage = WalletCore::start_from_config_update_chain(wallet_config).unwrap(); + let from_acc = wallet_storage.get_account_private(&from).unwrap(); + assert_eq!(from_acc.balance, 10000); - wallet::execute_subcommand(command).await.unwrap(); + let SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash } = + wallet::execute_subcommand(command).await.unwrap() + else { + panic!("invalid subcommand return value"); + }; info!("Waiting for next block creation"); tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; - let new_commitment1 = { - let from_acc = wallet_storage - .storage - .user_data - .get_private_account_mut(&from) - .unwrap(); - - from_acc.1.program_owner = nssa::program::Program::authenticated_transfer_program().id(); - from_acc.1.balance -= 100; - from_acc.1.nonce += 1; - - nssa_core::Commitment::new(&from_acc.0.nullifer_public_key, &from_acc.1) + let command = Command::ClaimPrivateAccount { + tx_hash, + acc_addr: from.to_string(), + ciph_id: 0, }; + wallet::execute_subcommand(command).await.unwrap(); + let wallet_storage = WalletCore::start_from_config_update_chain(wallet_config).unwrap(); - let proof1 = seq_client - .get_proof_for_commitment(new_commitment1) - .await - .unwrap() + let from_acc = wallet_storage.get_account_private(&from).unwrap(); + let new_commitment = wallet_storage + .get_private_account_commitment(&from) .unwrap(); + assert!(verify_commitment_is_in_state(new_commitment, &seq_client).await); let acc_2_balance = seq_client - .get_account_balance(ACC_RECEIVER.to_string()) + .get_account_balance(to.to_string()) .await .unwrap(); - println!("New proof is {proof1:#?}"); + assert_eq!(from_acc.balance, 10000 - 100); assert_eq!(acc_2_balance.balance, 20100); info!("Success!"); @@ -732,66 +660,59 @@ pub async fn test_success_deshielded_transfer_to_another_account() { pub async fn test_success_shielded_transfer_to_another_owned_account() { info!("test_success_shielded_transfer_to_another_owned_account"); + let from: Address = ACC_SENDER.parse().unwrap(); + let to: Address = ACC_RECEIVER_PRIVATE.parse().unwrap(); let command = Command::SendNativeTokenTransferShielded { - from: ACC_SENDER.to_string(), - to: ACC_RECEIVER_PRIVATE.to_string(), + from: from.to_string(), + to: to.to_string(), amount: 100, }; - let to = produce_account_addr_from_hex(ACC_RECEIVER_PRIVATE.to_string()).unwrap(); - let wallet_config = fetch_config().unwrap(); - let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap(); - let mut wallet_storage = WalletCore::start_from_config_update_chain(wallet_config).unwrap(); - - wallet::execute_subcommand(command).await.unwrap(); + let SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash } = + wallet::execute_subcommand(command).await.unwrap() + else { + panic!("invalid subcommand return value"); + }; info!("Waiting for next block creation"); tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; - let new_commitment2 = { - let to_acc = wallet_storage - .storage - .user_data - .get_private_account_mut(&to) - .unwrap(); - - to_acc.1.program_owner = nssa::program::Program::authenticated_transfer_program().id(); - to_acc.1.balance += 100; - to_acc.1.nonce += 1; - - nssa_core::Commitment::new(&to_acc.0.nullifer_public_key, &to_acc.1) + let command = Command::ClaimPrivateAccount { + tx_hash, + acc_addr: to.to_string(), + ciph_id: 0, }; + wallet::execute_subcommand(command).await.unwrap(); + let wallet_storage = WalletCore::start_from_config_update_chain(wallet_config).unwrap(); - let acc_1_balance = seq_client - .get_account_balance(ACC_SENDER.to_string()) + let acc_to = wallet_storage.get_account_private(&to).unwrap(); + let new_commitment = wallet_storage.get_private_account_commitment(&to).unwrap(); + assert!(verify_commitment_is_in_state(new_commitment, &seq_client).await); + + let acc_from_balance = seq_client + .get_account_balance(from.to_string()) .await .unwrap(); - let proof2 = seq_client - .get_proof_for_commitment(new_commitment2) - .await - .unwrap() - .unwrap(); - - assert_eq!(acc_1_balance.balance, 9900); - - println!("New proof is {proof2:#?}"); + assert_eq!(acc_from_balance.balance, 9900); + assert_eq!(acc_to.balance, 20000 + 100); info!("Success!"); } pub async fn test_success_shielded_transfer_to_another_foreign_account() { info!("test_success_shielded_transfer_to_another_foreign_account"); - let to_npk_orig = NullifierPublicKey([42; 32]); - let to_npk = hex::encode(to_npk_orig.0); - let to_ipk = Secp256k1Point::from_scalar(to_npk_orig.0); + let to_npk = NullifierPublicKey([42; 32]); + let to_npk_string = hex::encode(to_npk.0); + let to_ipk = Secp256k1Point::from_scalar(to_npk.0); + let from: Address = ACC_SENDER.parse().unwrap(); let command = Command::SendNativeTokenTransferShieldedForeignAccount { - from: ACC_SENDER.to_string(), - to_npk, + from: from.to_string(), + to_npk: to_npk_string, to_ipk: hex::encode(to_ipk.0), amount: 100, }; @@ -800,118 +721,27 @@ pub async fn test_success_shielded_transfer_to_another_foreign_account() { let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap(); - wallet::execute_subcommand(command).await.unwrap(); - - info!("Waiting for next block creation"); - tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; - - let new_commitment2 = { - let to_acc = nssa_core::account::Account { - program_owner: nssa::program::Program::authenticated_transfer_program().id(), - balance: 100, - data: vec![], - nonce: 1, - }; - - nssa_core::Commitment::new(&to_npk_orig, &to_acc) - }; - - let acc_1_balance = seq_client - .get_account_balance(ACC_SENDER.to_string()) - .await - .unwrap(); - - let proof2 = seq_client - .get_proof_for_commitment(new_commitment2) - .await - .unwrap() - .unwrap(); - - assert_eq!(acc_1_balance.balance, 9900); - println!("New proof is {proof2:#?}"); - - info!("Success!"); -} - -pub async fn test_success_shielded_transfer_to_another_owned_account_claiming_path() { - info!("test_success_shielded_transfer_to_another_owned_account_claiming_path"); - let command = Command::RegisterAccountPrivate {}; - - let sub_ret = wallet::execute_subcommand(command).await.unwrap(); - - let SubcommandReturnValue::RegisterAccount { addr: to_addr } = sub_ret else { - panic!("FAILED TO REGISTER ACCOUNT"); - }; - - let wallet_config = fetch_config().unwrap(); - - let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap(); - - let wallet_storage = WalletCore::start_from_config_update_chain(wallet_config.clone()).unwrap(); - - let (to_keys, mut to_acc) = wallet_storage - .storage - .user_data - .user_private_accounts - .get(&to_addr) - .cloned() - .unwrap(); - - let command = Command::SendNativeTokenTransferShieldedForeignAccount { - from: ACC_SENDER.to_string(), - to_npk: hex::encode(to_keys.nullifer_public_key.0), - to_ipk: hex::encode(to_keys.incoming_viewing_public_key.0), - amount: 100, - }; - - let sub_ret = wallet::execute_subcommand(command).await.unwrap(); - - let SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash } = sub_ret else { - panic!("FAILED TO SEND TX"); + let SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash } = + wallet::execute_subcommand(command).await.unwrap() + else { + panic!("invalid subcommand return value"); }; info!("Waiting for next block creation"); tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; - let new_commitment2 = { - to_acc.program_owner = nssa::program::Program::authenticated_transfer_program().id(); - to_acc.balance = 100; - to_acc.nonce = 1; - - nssa_core::Commitment::new(&to_keys.nullifer_public_key, &to_acc) - }; + let tx = fetch_privacy_preserving_tx(&seq_client, tx_hash).await; let acc_1_balance = seq_client - .get_account_balance(ACC_SENDER.to_string()) + .get_account_balance(from.to_string()) .await .unwrap(); - let proof2 = seq_client - .get_proof_for_commitment(new_commitment2) - .await - .unwrap() - .unwrap(); + assert!( + verify_commitment_is_in_state(tx.message.new_commitments[0].clone(), &seq_client).await + ); assert_eq!(acc_1_balance.balance, 9900); - println!("New proof is {proof2:#?}"); - - let command = Command::ClaimPrivateAccount { - tx_hash, - acc_addr: hex::encode(to_addr), - ciph_id: 0, - }; - - wallet::execute_subcommand(command).await.unwrap(); - - let wallet_storage = WalletCore::start_from_config_update_chain(wallet_config).unwrap(); - - let (_, to_res_acc) = wallet_storage - .storage - .user_data - .get_private_account(&to_addr) - .unwrap(); - - assert_eq!(to_res_acc.balance, 100); info!("Success!"); } @@ -1038,12 +868,6 @@ pub async fn main_tests_runner() -> Result<()> { test_success_shielded_transfer_to_another_foreign_account ); } - "test_success_shielded_transfer_to_another_owned_account_claiming_path" => { - test_cleanup_wrap!( - home_dir, - test_success_shielded_transfer_to_another_owned_account_claiming_path - ); - } "test_pinata" => { test_cleanup_wrap!(home_dir, test_pinata); } @@ -1077,11 +901,33 @@ pub async fn main_tests_runner() -> Result<()> { home_dir, test_success_private_transfer_to_another_owned_account_claiming_path ); + test_cleanup_wrap!(home_dir, test_pinata); + } + "all_private" => { test_cleanup_wrap!( home_dir, - test_success_shielded_transfer_to_another_owned_account_claiming_path + test_success_private_transfer_to_another_owned_account + ); + test_cleanup_wrap!( + home_dir, + test_success_private_transfer_to_another_foreign_account + ); + test_cleanup_wrap!( + home_dir, + test_success_deshielded_transfer_to_another_account + ); + test_cleanup_wrap!( + home_dir, + test_success_shielded_transfer_to_another_owned_account + ); + test_cleanup_wrap!( + home_dir, + test_success_shielded_transfer_to_another_foreign_account + ); + test_cleanup_wrap!( + home_dir, + test_success_private_transfer_to_another_owned_account_claiming_path ); - test_cleanup_wrap!(home_dir, test_pinata); } _ => { anyhow::bail!("Unknown test name"); @@ -1090,3 +936,33 @@ pub async fn main_tests_runner() -> Result<()> { Ok(()) } + +async fn fetch_privacy_preserving_tx( + seq_client: &SequencerClient, + tx_hash: String, +) -> PrivacyPreservingTransaction { + let transaction_encoded = seq_client + .get_transaction_by_hash(tx_hash.clone()) + .await + .unwrap() + .transaction + .unwrap(); + + let tx_base64_decode = BASE64.decode(transaction_encoded).unwrap(); + match NSSATransaction::try_from(&EncodedTransaction::from_bytes(tx_base64_decode)).unwrap() { + NSSATransaction::PrivacyPreserving(privacy_preserving_transaction) => { + privacy_preserving_transaction + } + _ => panic!("Invalid tx type"), + } +} + +async fn verify_commitment_is_in_state( + commitment: Commitment, + seq_client: &SequencerClient, +) -> bool { + match seq_client.get_proof_for_commitment(commitment).await { + Ok(Some(_)) => true, + _ => false, + } +} diff --git a/wallet/src/chain_storage/mod.rs b/wallet/src/chain_storage/mod.rs index 825d51c..d4123d6 100644 --- a/wallet/src/chain_storage/mod.rs +++ b/wallet/src/chain_storage/mod.rs @@ -43,6 +43,7 @@ impl WalletChainStore { addr: nssa::Address, account: nssa_core::account::Account, ) { + println!("inserting at addres {}, this account {:?}", addr, account); self.user_data .user_private_accounts .entry(addr) diff --git a/wallet/src/helperfunctions.rs b/wallet/src/helperfunctions.rs index d08f206..5b2c456 100644 --- a/wallet/src/helperfunctions.rs +++ b/wallet/src/helperfunctions.rs @@ -30,11 +30,6 @@ pub fn fetch_config() -> Result { Ok(serde_json::from_reader(reader)?) } -// ToDo: Replace with structures conversion in future -pub fn produce_account_addr_from_hex(hex_str: String) -> Result
{ - Ok(hex_str.parse()?) -} - /// Fetch list of accounts stored at `NSSA_WALLET_HOME_DIR/curr_accounts.json` /// /// If file not present, it is considered as empty list of persistent accounts diff --git a/wallet/src/lib.rs b/wallet/src/lib.rs index 3308248..e89a28a 100644 --- a/wallet/src/lib.rs +++ b/wallet/src/lib.rs @@ -14,11 +14,12 @@ use log::info; use nssa::{Account, Address}; use clap::{Parser, Subcommand}; +use nssa_core::Commitment; use crate::{ helperfunctions::{ HumanReadableAccount, fetch_config, fetch_persistent_accounts, get_home, - produce_account_addr_from_hex, produce_data_for_storage, + produce_data_for_storage, }, poller::TxPoller, }; @@ -180,11 +181,24 @@ impl WalletCore { } ///Get account - pub async fn get_account(&self, addr: Address) -> Result { + pub async fn get_account_public(&self, addr: Address) -> Result { let response = self.sequencer_client.get_account(addr.to_string()).await?; Ok(response.account) } + pub fn get_account_private(&self, addr: &Address) -> Option { + self.storage + .user_data + .user_private_accounts + .get(addr) + .map(|value| value.1.clone()) + } + + pub fn get_private_account_commitment(&self, addr: &Address) -> Option { + let (keys, account) = self.storage.user_data.user_private_accounts.get(addr)?; + Some(Commitment::new(&keys.nullifer_public_key, account)) + } + ///Poll transactions pub async fn poll_native_token_transfer(&self, hash: String) -> Result { let transaction_encoded = self.poller.poll_tx(hash).await?; @@ -301,6 +315,11 @@ pub enum Command { #[arg(long)] ciph_id: usize, }, + ///Get private account with `addr` from storage + GetPrivateAccount { + #[arg(short, long)] + addr: String, + }, ///Register new public account RegisterAccountPublic {}, ///Register new private account @@ -373,6 +392,7 @@ pub struct Args { pub enum SubcommandReturnValue { PrivacyPreservingTransfer { tx_hash: String }, RegisterAccount { addr: nssa::Address }, + Account(nssa::Account), Empty, } @@ -382,8 +402,8 @@ pub async fn execute_subcommand(command: Command) -> Result { - let from = produce_account_addr_from_hex(from)?; - let to = produce_account_addr_from_hex(to)?; + let from: Address = from.parse().unwrap(); + let to: Address = to.parse().unwrap(); let res = wallet_core .send_public_native_token_transfer(from, to, amount) @@ -402,8 +422,8 @@ pub async fn execute_subcommand(command: Command) -> Result { - let from = produce_account_addr_from_hex(from)?; - let to = produce_account_addr_from_hex(to)?; + let from: Address = from.parse().unwrap(); + let to: Address = to.parse().unwrap(); let (res, [secret_from, secret_to]) = wallet_core .send_private_native_token_transfer_owned_account(from, to, amount) @@ -464,7 +484,7 @@ pub async fn execute_subcommand(command: Command) -> Result { - let from = produce_account_addr_from_hex(from)?; + let from: Address = from.parse().unwrap(); let to_npk_res = hex::decode(to_npk)?; let mut to_npk = [0; 32]; to_npk.copy_from_slice(&to_npk_res); @@ -527,8 +547,8 @@ pub async fn execute_subcommand(command: Command) -> Result { - let from = produce_account_addr_from_hex(from)?; - let to = produce_account_addr_from_hex(to)?; + let from: Address = from.parse().unwrap(); + let to: Address = to.parse().unwrap(); let (res, secret) = wallet_core .send_deshielded_native_token_transfer(from, to, amount) @@ -569,8 +589,8 @@ pub async fn execute_subcommand(command: Command) -> Result { - let from = produce_account_addr_from_hex(from)?; - let to = produce_account_addr_from_hex(to)?; + let from: Address = from.parse().unwrap(); + let to: Address = to.parse().unwrap(); let (res, secret) = wallet_core .send_shielded_native_token_transfer(from, to, amount) @@ -608,7 +628,7 @@ pub async fn execute_subcommand(command: Command) -> Result { - let from = produce_account_addr_from_hex(from)?; + let from: Address = from.parse().unwrap(); let to_npk_res = hex::decode(to_npk)?; let mut to_npk = [0; 32]; @@ -656,7 +676,7 @@ pub async fn execute_subcommand(command: Command) -> Result { - let acc_addr = produce_account_addr_from_hex(acc_addr)?; + let acc_addr: Address = acc_addr.parse().unwrap(); let account_key_chain = wallet_core .storage @@ -759,9 +779,19 @@ pub async fn execute_subcommand(command: Command) -> Result { let addr: Address = addr.parse()?; - let account: HumanReadableAccount = wallet_core.get_account(addr).await?.into(); - println!("{}", serde_json::to_string(&account).unwrap()); + let account = wallet_core.get_account_public(addr).await?; + let account_hr: HumanReadableAccount = account.clone().into(); + println!("{}", serde_json::to_string(&account_hr).unwrap()); + SubcommandReturnValue::Account(account) + } + Command::GetPrivateAccount { addr } => { + let addr: Address = addr.parse()?; + if let Some(account) = wallet_core.get_account_private(&addr) { + println!("{}", serde_json::to_string(&account).unwrap()); + } else { + println!("Private account not found."); + } SubcommandReturnValue::Empty } Command::CreateNewToken { diff --git a/wallet/src/token_transfers/deshielded.rs b/wallet/src/token_transfers/deshielded.rs index 5c8415e..6bc812b 100644 --- a/wallet/src/token_transfers/deshielded.rs +++ b/wallet/src/token_transfers/deshielded.rs @@ -1,7 +1,11 @@ use common::{ExecutionFailureKind, sequencer_client::json::SendTxResponse}; use key_protocol::key_management::ephemeral_key_holder::EphemeralKeyHolder; -use nssa::Address; -use nssa_core::account::AccountWithMetadata; +use nssa::{ + Address, PrivacyPreservingTransaction, + privacy_preserving_transaction::{circuit, message::Message, witness_set::WitnessSet}, + program::Program, +}; +use nssa_core::{Commitment, account::AccountWithMetadata}; use crate::{WalletCore, helperfunctions::produce_random_nonces}; @@ -18,17 +22,17 @@ impl WalletCore { return Err(ExecutionFailureKind::KeyNotFoundError); }; - let Ok(to_acc) = self.get_account(to).await else { + let Ok(to_acc) = self.get_account_public(to).await else { return Err(ExecutionFailureKind::KeyNotFoundError); }; if from_acc.balance >= balance_to_move { - let program = nssa::program::Program::authenticated_transfer_program(); + 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 = nssa_core::Commitment::new(&npk_from, &from_acc); + 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); @@ -36,9 +40,9 @@ impl WalletCore { let eph_holder = EphemeralKeyHolder::new(&npk_from); let shared_secret = eph_holder.calculate_shared_secret_sender(&ipk_from); - let (output, proof) = nssa::privacy_preserving_transaction::circuit::execute_and_prove( + let (output, proof) = circuit::execute_and_prove( &[sender_pre, recipient_pre], - &nssa::program::Program::serialize_instruction(balance_to_move).unwrap(), + &Program::serialize_instruction(balance_to_move).unwrap(), &[1, 0], &produce_random_nonces(1), &[(npk_from.clone(), shared_secret.clone())], @@ -54,30 +58,21 @@ impl WalletCore { ) .unwrap(); - let message = - nssa::privacy_preserving_transaction::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 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 = - nssa::privacy_preserving_transaction::witness_set::WitnessSet::for_message( - &message, - proof, - &[], - ); + let witness_set = WitnessSet::for_message(&message, proof, &[]); - let tx = nssa::privacy_preserving_transaction::PrivacyPreservingTransaction::new( - message, - witness_set, - ); + let tx = PrivacyPreservingTransaction::new(message, witness_set); Ok(( self.sequencer_client.send_tx_private(tx).await?, diff --git a/wallet/src/token_transfers/private.rs b/wallet/src/token_transfers/private.rs index 4b1c5fa..5253acd 100644 --- a/wallet/src/token_transfers/private.rs +++ b/wallet/src/token_transfers/private.rs @@ -1,7 +1,14 @@ use common::{ExecutionFailureKind, sequencer_client::json::SendTxResponse}; use key_protocol::key_management::ephemeral_key_holder::EphemeralKeyHolder; -use nssa::Address; -use nssa_core::account::AccountWithMetadata; +use nssa::{ + Address, PrivacyPreservingTransaction, + privacy_preserving_transaction::{circuit, message::Message, witness_set::WitnessSet}, + program::Program, +}; +use nssa_core::{ + Commitment, NullifierPublicKey, SharedSecretKey, account::AccountWithMetadata, + encryption::IncomingViewingPublicKey, +}; use crate::{WalletCore, helperfunctions::produce_random_nonces}; @@ -9,10 +16,10 @@ impl WalletCore { pub async fn send_private_native_token_transfer_outer_account( &self, from: Address, - to_npk: nssa_core::NullifierPublicKey, - to_ipk: nssa_core::encryption::IncomingViewingPublicKey, + to_npk: NullifierPublicKey, + to_ipk: IncomingViewingPublicKey, balance_to_move: u128, - ) -> Result<(SendTxResponse, [nssa_core::SharedSecretKey; 2]), ExecutionFailureKind> { + ) -> Result<(SendTxResponse, [SharedSecretKey; 2]), ExecutionFailureKind> { let Some((from_keys, from_acc)) = self.storage.user_data.get_private_account(&from).cloned() else { @@ -22,27 +29,25 @@ impl WalletCore { let to_acc = nssa_core::account::Account::default(); if from_acc.balance >= balance_to_move { - let program = nssa::program::Program::authenticated_transfer_program(); + let program = Program::authenticated_transfer_program(); let from_npk = from_keys.nullifer_public_key; let from_ipk = from_keys.incoming_viewing_public_key; - let sender_commitment = nssa_core::Commitment::new(&from_npk, &from_acc); + let sender_commitment = Commitment::new(&from_npk, &from_acc); - let sender_pre = - nssa_core::account::AccountWithMetadata::new(from_acc.clone(), true, &from_npk); + let sender_pre = AccountWithMetadata::new(from_acc.clone(), true, &from_npk); - let recipient_pre = - nssa_core::account::AccountWithMetadata::new(to_acc.clone(), false, &to_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) = nssa::privacy_preserving_transaction::circuit::execute_and_prove( + let (output, proof) = circuit::execute_and_prove( &[sender_pre, recipient_pre], - &nssa::program::Program::serialize_instruction(balance_to_move).unwrap(), + &Program::serialize_instruction(balance_to_move).unwrap(), &[1, 2], &produce_random_nonces(2), &[ @@ -61,37 +66,28 @@ impl WalletCore { ) .unwrap(); - let message = - nssa::privacy_preserving_transaction::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 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 = - nssa::privacy_preserving_transaction::witness_set::WitnessSet::for_message( - &message, - proof, - &[], - ); + let witness_set = WitnessSet::for_message(&message, proof, &[]); - let tx = nssa::privacy_preserving_transaction::PrivacyPreservingTransaction::new( - message, - witness_set, - ); + let tx = PrivacyPreservingTransaction::new(message, witness_set); Ok(( self.sequencer_client.send_tx_private(tx).await?, @@ -107,7 +103,7 @@ impl WalletCore { from: Address, to: Address, balance_to_move: u128, - ) -> Result<(SendTxResponse, [nssa_core::SharedSecretKey; 2]), ExecutionFailureKind> { + ) -> Result<(SendTxResponse, [SharedSecretKey; 2]), ExecutionFailureKind> { let Some((from_keys, from_acc)) = self.storage.user_data.get_private_account(&from).cloned() else { @@ -125,10 +121,10 @@ impl WalletCore { let to_ipk = to_keys.incoming_viewing_public_key.clone(); if from_acc.balance >= balance_to_move { - let program = nssa::program::Program::authenticated_transfer_program(); + let program = Program::authenticated_transfer_program(); - let sender_commitment = nssa_core::Commitment::new(&from_npk, &from_acc); - let receiver_commitment = nssa_core::Commitment::new(&to_npk, &to_acc); + let sender_commitment = Commitment::new(&from_npk, &from_acc); + let receiver_commitment = Commitment::new(&to_npk, &to_acc); let sender_pre = AccountWithMetadata::new(from_acc.clone(), true, &from_npk); let recipient_pre = AccountWithMetadata::new(to_acc.clone(), true, &to_npk); @@ -139,9 +135,9 @@ impl WalletCore { let eph_holder_to = EphemeralKeyHolder::new(&to_npk); let shared_secret_to = eph_holder_to.calculate_shared_secret_sender(&to_ipk); - let (output, proof) = nssa::privacy_preserving_transaction::circuit::execute_and_prove( + let (output, proof) = circuit::execute_and_prove( &[sender_pre, recipient_pre], - &nssa::program::Program::serialize_instruction(balance_to_move).unwrap(), + &Program::serialize_instruction(balance_to_move).unwrap(), &[1, 1], &produce_random_nonces(2), &[ @@ -170,37 +166,27 @@ impl WalletCore { ) .unwrap(); - let message = - nssa::privacy_preserving_transaction::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 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 = - nssa::privacy_preserving_transaction::witness_set::WitnessSet::for_message( - &message, - proof, - &[], - ); - - let tx = nssa::privacy_preserving_transaction::PrivacyPreservingTransaction::new( - message, - witness_set, - ); + let witness_set = WitnessSet::for_message(&message, proof, &[]); + let tx = PrivacyPreservingTransaction::new(message, witness_set); Ok(( self.sequencer_client.send_tx_private(tx).await?, diff --git a/wallet/src/token_transfers/public.rs b/wallet/src/token_transfers/public.rs index 7a5a78e..22d50eb 100644 --- a/wallet/src/token_transfers/public.rs +++ b/wallet/src/token_transfers/public.rs @@ -1,5 +1,9 @@ use common::{ExecutionFailureKind, sequencer_client::json::SendTxResponse}; -use nssa::Address; +use nssa::{ + Address, PublicTransaction, + program::Program, + public_transaction::{Message, WitnessSet}, +}; use crate::WalletCore; @@ -20,14 +24,8 @@ impl WalletCore { }; let addresses = vec![from, to]; - let program_id = nssa::program::Program::authenticated_transfer_program().id(); - let message = nssa::public_transaction::Message::try_new( - program_id, - addresses, - nonces, - balance_to_move, - ) - .unwrap(); + let program_id = Program::authenticated_transfer_program().id(); + let message = Message::try_new(program_id, addresses, nonces, balance_to_move).unwrap(); let signing_key = self.storage.user_data.get_pub_account_signing_key(&from); @@ -35,10 +33,9 @@ impl WalletCore { return Err(ExecutionFailureKind::KeyNotFoundError); }; - let witness_set = - nssa::public_transaction::WitnessSet::for_message(&message, &[signing_key]); + let witness_set = WitnessSet::for_message(&message, &[signing_key]); - let tx = nssa::PublicTransaction::new(message, witness_set); + let tx = PublicTransaction::new(message, witness_set); Ok(self.sequencer_client.send_tx_public(tx).await?) } else { diff --git a/wallet/src/token_transfers/shielded.rs b/wallet/src/token_transfers/shielded.rs index c0a2d1c..1cf1cb7 100644 --- a/wallet/src/token_transfers/shielded.rs +++ b/wallet/src/token_transfers/shielded.rs @@ -1,7 +1,14 @@ use common::{ExecutionFailureKind, sequencer_client::json::SendTxResponse}; use key_protocol::key_management::ephemeral_key_holder::EphemeralKeyHolder; -use nssa::Address; -use nssa_core::account::AccountWithMetadata; +use nssa::{ + Account, Address, PrivacyPreservingTransaction, + privacy_preserving_transaction::{circuit, message::Message, witness_set::WitnessSet}, + program::Program, +}; +use nssa_core::{ + Commitment, NullifierPublicKey, SharedSecretKey, account::AccountWithMetadata, + encryption::IncomingViewingPublicKey, +}; use crate::{WalletCore, helperfunctions::produce_random_nonces}; @@ -11,8 +18,8 @@ impl WalletCore { from: Address, to: Address, balance_to_move: u128, - ) -> Result<(SendTxResponse, nssa_core::SharedSecretKey), ExecutionFailureKind> { - let Ok(from_acc) = self.get_account(from).await else { + ) -> Result<(SendTxResponse, SharedSecretKey), ExecutionFailureKind> { + let Ok(from_acc) = self.get_account_public(from).await else { return Err(ExecutionFailureKind::KeyNotFoundError); }; @@ -25,20 +32,17 @@ impl WalletCore { let to_ipk = to_keys.incoming_viewing_public_key.clone(); if from_acc.balance >= balance_to_move { - let program = nssa::program::Program::authenticated_transfer_program(); + let program = Program::authenticated_transfer_program(); - let receiver_commitment = - nssa_core::Commitment::new(&to_keys.nullifer_public_key, &to_acc); + let receiver_commitment = Commitment::new(&to_npk, &to_acc); - let sender_pre = - nssa_core::account::AccountWithMetadata::new(from_acc.clone(), true, from); - let recipient_pre = - nssa_core::account::AccountWithMetadata::new(to_acc.clone(), true, &to_npk); + 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) = nssa::privacy_preserving_transaction::circuit::execute_and_prove( + let (output, proof) = circuit::execute_and_prove( &[sender_pre, recipient_pre], &nssa::program::Program::serialize_instruction(balance_to_move).unwrap(), &[0, 1], @@ -56,18 +60,17 @@ impl WalletCore { ) .unwrap(); - let message = - nssa::privacy_preserving_transaction::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 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); @@ -75,17 +78,9 @@ impl WalletCore { return Err(ExecutionFailureKind::KeyNotFoundError); }; - let witness_set = - nssa::privacy_preserving_transaction::witness_set::WitnessSet::for_message( - &message, - proof, - &[signing_key], - ); + let witness_set = WitnessSet::for_message(&message, proof, &[signing_key]); - let tx = nssa::privacy_preserving_transaction::PrivacyPreservingTransaction::new( - message, - witness_set, - ); + let tx = PrivacyPreservingTransaction::new(message, witness_set); Ok(( self.sequencer_client.send_tx_private(tx).await?, @@ -99,18 +94,18 @@ impl WalletCore { pub async fn send_shielded_native_token_transfer_outer_account( &self, from: Address, - to_npk: nssa_core::NullifierPublicKey, - to_ipk: nssa_core::encryption::IncomingViewingPublicKey, + to_npk: NullifierPublicKey, + to_ipk: IncomingViewingPublicKey, balance_to_move: u128, - ) -> Result<(SendTxResponse, nssa_core::SharedSecretKey), ExecutionFailureKind> { - let Ok(from_acc) = self.get_account(from).await else { + ) -> Result<(SendTxResponse, SharedSecretKey), ExecutionFailureKind> { + let Ok(from_acc) = self.get_account_public(from).await else { return Err(ExecutionFailureKind::KeyNotFoundError); }; - let to_acc = nssa_core::account::Account::default(); + let to_acc = Account::default(); if from_acc.balance >= balance_to_move { - let program = nssa::program::Program::authenticated_transfer_program(); + 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); @@ -118,9 +113,9 @@ impl WalletCore { let eph_holder = EphemeralKeyHolder::new(&to_npk); let shared_secret = eph_holder.calculate_shared_secret_sender(&to_ipk); - let (output, proof) = nssa::privacy_preserving_transaction::circuit::execute_and_prove( + let (output, proof) = circuit::execute_and_prove( &[sender_pre, recipient_pre], - &nssa::program::Program::serialize_instruction(balance_to_move).unwrap(), + &Program::serialize_instruction(balance_to_move).unwrap(), &[0, 2], &produce_random_nonces(1), &[(to_npk.clone(), shared_secret.clone())], @@ -129,18 +124,17 @@ impl WalletCore { ) .unwrap(); - let message = - nssa::privacy_preserving_transaction::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 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); @@ -148,17 +142,8 @@ impl WalletCore { return Err(ExecutionFailureKind::KeyNotFoundError); }; - let witness_set = - nssa::privacy_preserving_transaction::witness_set::WitnessSet::for_message( - &message, - proof, - &[signing_key], - ); - - let tx = nssa::privacy_preserving_transaction::PrivacyPreservingTransaction::new( - message, - witness_set, - ); + 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?, From 313425f6f8dfede3c786c24ceaf7028d96f8cef5 Mon Sep 17 00:00:00 2001 From: Sergio Chouhy Date: Fri, 3 Oct 2025 17:06:45 -0300 Subject: [PATCH 20/24] rename --- integration_tests/src/lib.rs | 32 ++++++++++++++++---------------- wallet/src/lib.rs | 22 +++++++++++----------- 2 files changed, 27 insertions(+), 27 deletions(-) diff --git a/integration_tests/src/lib.rs b/integration_tests/src/lib.rs index 58d2edc..f27669c 100644 --- a/integration_tests/src/lib.rs +++ b/integration_tests/src/lib.rs @@ -467,17 +467,17 @@ pub async fn test_success_private_transfer_to_another_owned_account() { info!("Waiting for next block creation"); tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; - let command = Command::ClaimPrivateAccount { + let command = Command::FetchPrivateAccount { tx_hash: tx_hash.clone(), acc_addr: from.to_string(), - ciph_id: 0, + output_id: 0, }; wallet::execute_subcommand(command).await.unwrap(); - let command = Command::ClaimPrivateAccount { + let command = Command::FetchPrivateAccount { tx_hash, acc_addr: to.to_string(), - ciph_id: 1, + output_id: 1, }; wallet::execute_subcommand(command).await.unwrap(); @@ -519,10 +519,10 @@ pub async fn test_success_private_transfer_to_another_foreign_account() { info!("Waiting for next block creation"); tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; - let command = Command::ClaimPrivateAccount { + let command = Command::FetchPrivateAccount { tx_hash: tx_hash.clone(), acc_addr: from.to_string(), - ciph_id: 0, + output_id: 0, }; wallet::execute_subcommand(command).await.unwrap(); @@ -582,10 +582,10 @@ pub async fn test_success_private_transfer_to_another_owned_account_claiming_pat let tx = fetch_privacy_preserving_tx(&seq_client, tx_hash.clone()).await; - let command = Command::ClaimPrivateAccount { + let command = Command::FetchPrivateAccount { tx_hash, acc_addr: to_addr.to_string(), - ciph_id: 1, + output_id: 1, }; wallet::execute_subcommand(command).await.unwrap(); let wallet_storage = WalletCore::start_from_config_update_chain(wallet_config).unwrap(); @@ -633,10 +633,10 @@ pub async fn test_success_deshielded_transfer_to_another_account() { info!("Waiting for next block creation"); tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; - let command = Command::ClaimPrivateAccount { + let command = Command::FetchPrivateAccount { tx_hash, acc_addr: from.to_string(), - ciph_id: 0, + output_id: 0, }; wallet::execute_subcommand(command).await.unwrap(); let wallet_storage = WalletCore::start_from_config_update_chain(wallet_config).unwrap(); @@ -680,10 +680,10 @@ pub async fn test_success_shielded_transfer_to_another_owned_account() { info!("Waiting for next block creation"); tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; - let command = Command::ClaimPrivateAccount { + let command = Command::FetchPrivateAccount { tx_hash, acc_addr: to.to_string(), - ciph_id: 0, + output_id: 0, }; wallet::execute_subcommand(command).await.unwrap(); let wallet_storage = WalletCore::start_from_config_update_chain(wallet_config).unwrap(); @@ -961,8 +961,8 @@ async fn verify_commitment_is_in_state( commitment: Commitment, seq_client: &SequencerClient, ) -> bool { - match seq_client.get_proof_for_commitment(commitment).await { - Ok(Some(_)) => true, - _ => false, - } + matches!( + seq_client.get_proof_for_commitment(commitment).await, + Ok(Some(_)) + ) } diff --git a/wallet/src/lib.rs b/wallet/src/lib.rs index e89a28a..d3bcc8e 100644 --- a/wallet/src/lib.rs +++ b/wallet/src/lib.rs @@ -304,16 +304,16 @@ pub enum Command { amount: u128, }, ///Claim account `acc_addr` generated in transaction `tx_hash`, using secret `sh_secret` at ciphertext id `ciph_id` - ClaimPrivateAccount { + FetchPrivateAccount { ///tx_hash - valid 32 byte hex string #[arg(long)] tx_hash: String, ///acc_addr - valid 32 byte hex string #[arg(long)] acc_addr: String, - ///ciph_id - id of cipher in transaction + ///output_id - id of the output in the transaction #[arg(long)] - ciph_id: usize, + output_id: usize, }, ///Get private account with `addr` from storage GetPrivateAccount { @@ -330,17 +330,17 @@ pub enum Command { tx_hash: String, }, ///Get account `addr` balance - GetAccountBalance { + GetPublicAccountBalance { #[arg(short, long)] addr: String, }, ///Get account `addr` nonce - GetAccountNonce { + GetPublicAccountNonce { #[arg(short, long)] addr: String, }, ///Get account at address `addr` - GetAccount { + GetPublicAccount { #[arg(short, long)] addr: String, }, @@ -671,10 +671,10 @@ pub async fn execute_subcommand(command: Command) -> Result { let acc_addr: Address = acc_addr.parse().unwrap(); @@ -761,7 +761,7 @@ pub async fn execute_subcommand(command: Command) -> Result { + Command::GetPublicAccountBalance { addr } => { let addr = Address::from_str(&addr)?; let balance = wallet_core.get_account_balance(addr).await?; @@ -769,7 +769,7 @@ pub async fn execute_subcommand(command: Command) -> Result { + Command::GetPublicAccountNonce { addr } => { let addr = Address::from_str(&addr)?; let nonce = wallet_core.get_accounts_nonces(vec![addr]).await?[0]; @@ -777,7 +777,7 @@ pub async fn execute_subcommand(command: Command) -> Result { + Command::GetPublicAccount { addr } => { let addr: Address = addr.parse()?; let account = wallet_core.get_account_public(addr).await?; let account_hr: HumanReadableAccount = account.clone().into(); From f8153c6fb99f8ac60e9e286c5ffa3646c525005c Mon Sep 17 00:00:00 2001 From: Sergio Chouhy Date: Fri, 3 Oct 2025 17:07:15 -0300 Subject: [PATCH 21/24] fmt, clippy --- wallet/src/helperfunctions.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wallet/src/helperfunctions.rs b/wallet/src/helperfunctions.rs index 5b2c456..20f4eec 100644 --- a/wallet/src/helperfunctions.rs +++ b/wallet/src/helperfunctions.rs @@ -5,7 +5,7 @@ use std::{fs::File, io::BufReader, path::PathBuf, str::FromStr}; use anyhow::Result; use key_protocol::key_protocol_core::NSSAUserData; -use nssa::{Account, Address}; +use nssa::Account; use serde::Serialize; use crate::{ From b2e51990c95f63ad85605cae6bc0f309c028c6c0 Mon Sep 17 00:00:00 2001 From: Sergio Chouhy Date: Fri, 3 Oct 2025 23:05:11 -0300 Subject: [PATCH 22/24] remove commented code --- key_protocol/src/key_management/mod.rs | 9 --------- 1 file changed, 9 deletions(-) diff --git a/key_protocol/src/key_management/mod.rs b/key_protocol/src/key_management/mod.rs index 66e86e3..b74d3e4 100644 --- a/key_protocol/src/key_management/mod.rs +++ b/key_protocol/src/key_management/mod.rs @@ -40,15 +40,6 @@ impl KeyChain { } } - // pub fn produce_user_address(&self) -> [u8; 32] { - // let mut hasher = sha2::Sha256::new(); - // - // hasher.update(&self.nullifer_public_key); - // hasher.update(self.incoming_viewing_public_key.to_bytes()); - // - // ::from(hasher.finalize_fixed()) - // } - pub fn calculate_shared_secret_receiver( &self, ephemeral_public_key_sender: EphemeralPublicKey, From bc01fe0dc7ea777ecf9f68663c12bd785733da2d Mon Sep 17 00:00:00 2001 From: Oleksandr Pravdyvyi Date: Mon, 6 Oct 2025 13:20:56 +0300 Subject: [PATCH 23/24] fix: merge dep fix --- Cargo.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 38fc6c9..11e3144 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -41,7 +41,6 @@ ark-bn254 = "0.5.0" ark-ff = "0.5.0" tiny-keccak = { version = "2.0.2", features = ["keccak"] } base64 = "0.22.1" -chrono = "0.4.41" bip39 = "2.2.0" hmac-sha512 = "1.1.7" chrono = "0.4.41" From 33e3db9f1933a978c911a5570f033d2785f17695 Mon Sep 17 00:00:00 2001 From: Oleksandr Pravdyvyi Date: Mon, 6 Oct 2025 13:25:05 +0300 Subject: [PATCH 24/24] fix: merge fix --- common/src/sequencer_client/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/src/sequencer_client/mod.rs b/common/src/sequencer_client/mod.rs index abd0e55..2550969 100644 --- a/common/src/sequencer_client/mod.rs +++ b/common/src/sequencer_client/mod.rs @@ -171,7 +171,7 @@ impl SequencerClient { let transaction = EncodedTransaction::from(NSSATransaction::PrivacyPreserving(transaction)); let tx_req = SendTxRequest { - transaction: transaction.to_bytes(), + transaction: borsh::to_vec(&transaction).unwrap(), }; let req = serde_json::to_value(tx_req)?;