From 939553cc8514cfcd59e4ecd9ef0cbb14140be7a7 Mon Sep 17 00:00:00 2001 From: Oleksandr Pravdyvyi Date: Wed, 13 Aug 2025 13:42:00 +0300 Subject: [PATCH] fix: structural upgrades finalized --- accounts/src/account_core/mod.rs | 38 ++- accounts/src/key_management/mod.rs | 2 +- .../configs/debug/wallet/wallet_config.json | 8 +- nssa/Cargo.toml | 5 +- nssa/program_methods/Cargo.toml | 1 - nssa/program_methods/guest/Cargo.toml | 3 +- nssa/rust-toolchain.toml | 1 - nssa/src/address.rs | 222 +++++++++++++++++- nssa/src/lib.rs | 2 +- nssa/src/public_transaction/transaction.rs | 8 +- nssa/src/public_transaction/witness_set.rs | 4 +- nssa/src/state.rs | 45 ++-- nssa/test_program_methods/Cargo.toml | 1 - nssa/test_program_methods/guest/Cargo.toml | 3 +- sc_core/Cargo.toml | 3 + sc_core/src/proofs_circuits.rs | 5 +- sc_core/src/public_context.rs | 16 +- sequencer_core/src/sequencer_store/mod.rs | 5 +- wallet/src/chain_storage/accounts_store.rs | 9 +- wallet/src/chain_storage/mod.rs | 11 +- wallet/src/helperfunctions.rs | 9 +- wallet/src/lib.rs | 11 +- zkvm/Cargo.toml | 3 + zkvm/src/lib.rs | 56 ++--- 24 files changed, 345 insertions(+), 126 deletions(-) diff --git a/accounts/src/account_core/mod.rs b/accounts/src/account_core/mod.rs index 2447868..da6aa27 100644 --- a/accounts/src/account_core/mod.rs +++ b/accounts/src/account_core/mod.rs @@ -4,18 +4,14 @@ use anyhow::Result; use common::{merkle_tree_public::TreeHashType, transaction::Tag}; use k256::AffinePoint; use log::info; +use nssa::Address; use serde::{Deserialize, Serialize}; use utxo::utxo_core::UTXO; -pub mod address; - -use crate::{ - account_core::address::AccountAddress, - key_management::{ - constants_types::{CipherText, Nonce}, - ephemeral_key_holder::EphemeralKeyHolder, - AddressKeyHolder, - }, +use crate::key_management::{ + constants_types::{CipherText, Nonce}, + ephemeral_key_holder::EphemeralKeyHolder, + AddressKeyHolder, }; pub type PublicKey = AffinePoint; @@ -23,7 +19,7 @@ pub type PublicKey = AffinePoint; #[derive(Clone, Debug)] pub struct Account { pub key_holder: AddressKeyHolder, - pub address: AccountAddress, + pub address: Address, pub balance: u64, pub utxos: HashMap, } @@ -31,7 +27,7 @@ pub struct Account { #[derive(Serialize, Deserialize, Clone, Debug)] pub struct AccountForSerialization { pub key_holder: AddressKeyHolder, - pub address: AccountAddress, + pub address: Address, pub balance: u64, pub utxos: HashMap, } @@ -95,7 +91,7 @@ impl<'de> Deserialize<'de> for Account { pub struct AccountPublicMask { pub nullifier_public_key: AffinePoint, pub viewing_public_key: AffinePoint, - pub address: AccountAddress, + pub address: Address, pub balance: u64, } @@ -110,7 +106,7 @@ impl AccountPublicMask { } pub fn make_tag(&self) -> Tag { - self.address[0] + self.address.tag() } } @@ -119,13 +115,13 @@ impl Account { let key_holder = AddressKeyHolder::new_os_random(); let public_key = nssa::PublicKey::new_from_private_key(key_holder.get_pub_account_signing_key()); - let address = nssa::Address::from_public_key(&public_key); + let address = nssa::Address::from(&public_key); let balance = 0; let utxos = HashMap::new(); Self { key_holder, - address: *address.value(), + address, balance, utxos, } @@ -135,12 +131,12 @@ impl Account { let key_holder = AddressKeyHolder::new_os_random(); let public_key = nssa::PublicKey::new_from_private_key(key_holder.get_pub_account_signing_key()); - let address = nssa::Address::from_public_key(&public_key); + let address = nssa::Address::from(&public_key); let utxos = HashMap::new(); Self { key_holder, - address: *address.value(), + address, balance, utxos, } @@ -185,7 +181,7 @@ impl Account { privacy_flag: bool, ) -> Result<()> { let asset_utxo = UTXO::new( - self.address, + *self.address.value(), serde_json::to_vec(&asset)?, amount, privacy_flag, @@ -203,7 +199,7 @@ impl Account { } pub fn make_tag(&self) -> Tag { - self.address[0] + self.address.tag() } ///Produce account public mask @@ -241,8 +237,8 @@ mod tests { #[test] fn test_add_new_utxo_outputs() { let mut account = Account::new(); - let utxo1 = generate_dummy_utxo(account.address, 100); - let utxo2 = generate_dummy_utxo(account.address, 200); + let utxo1 = generate_dummy_utxo(*account.address.value(), 100); + let utxo2 = generate_dummy_utxo(*account.address.value(), 200); let result = account.add_new_utxo_outputs(vec![utxo1.clone(), utxo2.clone()]); diff --git a/accounts/src/key_management/mod.rs b/accounts/src/key_management/mod.rs index a9cb196..9e48cbd 100644 --- a/accounts/src/key_management/mod.rs +++ b/accounts/src/key_management/mod.rs @@ -343,7 +343,7 @@ mod tests { let public_key = nssa::PublicKey::new_from_private_key(&pub_account_signing_key); - let address = nssa::Address::from_public_key(&public_key); + let address = nssa::Address::from(&public_key); println!("======Prerequisites======"); println!(); diff --git a/integration_tests/configs/debug/wallet/wallet_config.json b/integration_tests/configs/debug/wallet/wallet_config.json index ab6191d..6085a36 100644 --- a/integration_tests/configs/debug/wallet/wallet_config.json +++ b/integration_tests/configs/debug/wallet/wallet_config.json @@ -5,10 +5,10 @@ "seq_poll_timeout_secs": 10, "initial_accounts": [ { - "address": [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], + "address": "1b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078f", "balance": 10000, "key_holder": { - "address": [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], + "address": "1b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078f", "nullifer_public_key": "03A340BECA9FAAB444CED0140681D72EA1318B5C611704FEE017DA9836B17DB718", "pub_account_signing_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], "top_secret_key_holder": { @@ -23,10 +23,10 @@ "utxos": {} }, { - "address": [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], + "address": "4d4b6cd1361032ca9bd2aeb9d900aa4d45d9ead80ac9423374c451a7254d0766", "balance": 20000, "key_holder": { - "address": [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], + "address": "4d4b6cd1361032ca9bd2aeb9d900aa4d45d9ead80ac9423374c451a7254d0766", "nullifer_public_key": "02172F50274DE67C4087C344F5D58E11DF761D90285B095060E0994FAA6BCDE271", "pub_account_signing_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], "top_secret_key_holder": { diff --git a/nssa/Cargo.toml b/nssa/Cargo.toml index fef52ef..540dd62 100644 --- a/nssa/Cargo.toml +++ b/nssa/Cargo.toml @@ -12,7 +12,10 @@ serde = "1.0.219" sha2 = "0.10.9" secp256k1 = "0.31.1" rand = "0.8" +hex = "0.4.3" +anyhow.workspace = true +serde_json.workspace = true [dev-dependencies] test-program-methods = { path = "test_program_methods" } -hex = "0.4.3" + diff --git a/nssa/program_methods/Cargo.toml b/nssa/program_methods/Cargo.toml index 0f31c9b..ea7e36b 100644 --- a/nssa/program_methods/Cargo.toml +++ b/nssa/program_methods/Cargo.toml @@ -8,4 +8,3 @@ risc0-build = { version = "2.3.1" } [package.metadata.risc0] methods = ["guest"] - diff --git a/nssa/program_methods/guest/Cargo.toml b/nssa/program_methods/guest/Cargo.toml index 12bddbf..4b377c8 100644 --- a/nssa/program_methods/guest/Cargo.toml +++ b/nssa/program_methods/guest/Cargo.toml @@ -7,5 +7,4 @@ edition = "2021" [dependencies] risc0-zkvm = { version = "2.3.1", default-features = false, features = ['std'] } -nssa-core = {path = "../../core"} - +nssa-core = { path = "../../core" } diff --git a/nssa/rust-toolchain.toml b/nssa/rust-toolchain.toml index 8663d46..36614c3 100644 --- a/nssa/rust-toolchain.toml +++ b/nssa/rust-toolchain.toml @@ -2,4 +2,3 @@ channel = "stable" components = ["rustfmt", "rust-src"] profile = "minimal" - diff --git a/nssa/src/address.rs b/nssa/src/address.rs index 4aa4c45..6604fdd 100644 --- a/nssa/src/address.rs +++ b/nssa/src/address.rs @@ -1,8 +1,11 @@ -use serde::{Deserialize, Serialize}; +use anyhow::anyhow; +use serde::{Deserialize, Serialize, de::Visitor}; use crate::signature::PublicKey; -#[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize, Deserialize)] +pub const LENGTH_MISMATCH_ERROR_MESSAGE: &str = "Slice length != 32 "; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)] pub struct Address { value: [u8; 32], } @@ -12,12 +15,221 @@ impl Address { Self { value } } - pub fn from_public_key(public_key: &PublicKey) -> Self { - // TODO: Check specs - Address::new(*public_key.value()) + pub fn tag(&self) -> u8 { + self.value[0] } pub fn value(&self) -> &[u8; 32] { &self.value } } + +impl AsRef<[u8]> for Address { + fn as_ref(&self) -> &[u8] { + &self.value + } +} + +impl TryFrom> for Address { + type Error = anyhow::Error; + + fn try_from(value: Vec) -> Result { + let addr_val: [u8; 32] = value + .try_into() + .map_err(|_| anyhow!(LENGTH_MISMATCH_ERROR_MESSAGE))?; + + Ok(Address::new(addr_val)) + } +} + +impl From<&PublicKey> for Address { + fn from(value: &PublicKey) -> Self { + // TODO: Check specs + Self::new(*value.value()) + } +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct HexString(String); + +impl HexString { + pub fn inner(&self) -> &str { + &self.0 + } +} + +#[derive(Debug, thiserror::Error)] +pub enum HexStringConsistencyError { + #[error("Hex decode error")] + HexError(#[from] hex::FromHexError), + #[error("Decode slice does not fit 32 bytes")] + SizeError(#[from] anyhow::Error), +} + +impl TryFrom<&str> for HexString { + type Error = HexStringConsistencyError; + + fn try_from(value: &str) -> Result { + let decoded_str = hex::decode(value)?; + let _: Address = decoded_str.try_into()?; + + Ok(Self(value.to_string())) + } +} + +impl Serialize for HexString { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + serializer.serialize_str(&self.0) + } +} + +struct HexStringVisitor; + +impl<'de> Visitor<'de> for HexStringVisitor { + type Value = String; + + fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { + formatter.write_str("expected a valid string") + } + + fn visit_string(self, v: String) -> Result + where + E: serde::de::Error, + { + Ok(v) + } + + fn visit_str(self, v: &str) -> Result + where + E: serde::de::Error, + { + Ok(v.to_string()) + } +} + +impl<'de> Deserialize<'de> for HexString { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + let str_cand = deserializer.deserialize_string(HexStringVisitor)?; + + let hex_string = + HexString::try_from(str_cand.as_str()).map_err(|err| serde::de::Error::custom(err))?; + + Ok(hex_string) + } +} + +impl From for Address { + fn from(value: HexString) -> Self { + Address::try_from(hex::decode(value.inner()).unwrap()).unwrap() + } +} + +impl From
for HexString { + fn from(value: Address) -> Self { + HexString::try_from(hex::encode(value).as_str()).unwrap() + } +} + +impl Serialize for Address { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + let hex_string: HexString = (*self).into(); + + hex_string.serialize(serializer) + } +} + +impl<'de> Deserialize<'de> for Address { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + let hex_sring = HexString::deserialize(deserializer)?; + + Ok(hex_sring.into()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[derive(Debug, Serialize, Deserialize)] + struct Ser1 { + f1: String, + } + + #[derive(Debug, Serialize, Deserialize, PartialEq)] + struct Ser2 { + f1: HexString, + } + + #[derive(Debug, Serialize, Deserialize, PartialEq)] + struct Ser3 { + f1: Address, + } + + #[test] + fn test_hex_ser() { + let str_for_tests = hex::encode([42; 32]); + + let hex_str_for_tests = HexString::try_from(str_for_tests.as_str()).unwrap(); + + let ser1_str = Ser1 { f1: str_for_tests }; + + let ser2_str = Ser2 { + f1: hex_str_for_tests, + }; + + let ser1_str_ser = serde_json::to_string(&ser1_str).unwrap(); + let ser2_str_ser = serde_json::to_string(&ser2_str).unwrap(); + + println!("{ser2_str_ser:#?}"); + + assert_eq!(ser1_str_ser, ser2_str_ser); + } + + #[test] + fn test_hex_deser() { + let raw_json = r#"{ + "f1": "2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a" + }"#; + + let str_for_tests = hex::encode([42; 32]); + + let hex_str_for_tests = HexString::try_from(str_for_tests.as_str()).unwrap(); + + let ser2_str = Ser2 { + f1: hex_str_for_tests, + }; + + let ser1_str: Ser2 = serde_json::from_str(raw_json).unwrap(); + + assert_eq!(ser1_str, ser2_str); + } + + #[test] + fn test_addr_deser() { + let raw_json = r#"{ + "f1": "2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a" + }"#; + + let addr_for_tests = Address::new([42; 32]); + + let ser2_str = Ser3 { + f1: addr_for_tests, + }; + + let ser1_str: Ser3 = serde_json::from_str(raw_json).unwrap(); + + assert_eq!(ser1_str, ser2_str); + } +} diff --git a/nssa/src/lib.rs b/nssa/src/lib.rs index ab4fe02..9555b14 100644 --- a/nssa/src/lib.rs +++ b/nssa/src/lib.rs @@ -1,4 +1,4 @@ -mod address; +pub mod address; pub mod error; pub mod program; pub mod public_transaction; diff --git a/nssa/src/public_transaction/transaction.rs b/nssa/src/public_transaction/transaction.rs index bd16644..9b56575 100644 --- a/nssa/src/public_transaction/transaction.rs +++ b/nssa/src/public_transaction/transaction.rs @@ -39,7 +39,7 @@ impl PublicTransaction { self.witness_set .signatures_and_public_keys() .iter() - .map(|(_, public_key)| Address::from_public_key(public_key)) + .map(|(_, public_key)| Address::from(public_key)) .collect() } @@ -129,14 +129,14 @@ pub mod tests { fn keys_for_tests() -> (PrivateKey, PrivateKey, Address, Address) { let key1 = PrivateKey::try_new([1; 32]).unwrap(); let key2 = PrivateKey::try_new([2; 32]).unwrap(); - let addr1 = Address::from_public_key(&PublicKey::new_from_private_key(&key1)); - let addr2 = Address::from_public_key(&PublicKey::new_from_private_key(&key2)); + let addr1 = Address::from(&PublicKey::new_from_private_key(&key1)); + let addr2 = Address::from(&PublicKey::new_from_private_key(&key2)); (key1, key2, addr1, addr2) } fn state_for_tests() -> V01State { let (_, _, addr1, addr2) = keys_for_tests(); - let initial_data = [(*addr1.value(), 10000), (*addr2.value(), 20000)]; + let initial_data = [(addr1, 10000), (addr2, 20000)]; V01State::new_with_genesis_accounts(&initial_data) } diff --git a/nssa/src/public_transaction/witness_set.rs b/nssa/src/public_transaction/witness_set.rs index ae87080..f0e5c6b 100644 --- a/nssa/src/public_transaction/witness_set.rs +++ b/nssa/src/public_transaction/witness_set.rs @@ -49,8 +49,8 @@ mod tests { let key2 = PrivateKey::try_new([2; 32]).unwrap(); let pubkey1 = PublicKey::new_from_private_key(&key1); let pubkey2 = PublicKey::new_from_private_key(&key2); - let addr1 = Address::from_public_key(&pubkey1); - let addr2 = Address::from_public_key(&pubkey2); + let addr1 = Address::from(&pubkey1); + let addr2 = Address::from(&pubkey2); let nonces = vec![1, 2]; let instruction = vec![1, 2, 3, 4]; let message = Message::try_new([0; 8], vec![addr1, addr2], nonces, instruction).unwrap(); diff --git a/nssa/src/state.rs b/nssa/src/state.rs index f6d932e..ab5d7a1 100644 --- a/nssa/src/state.rs +++ b/nssa/src/state.rs @@ -10,18 +10,17 @@ pub struct V01State { } impl V01State { - pub fn new_with_genesis_accounts(initial_data: &[([u8; 32], u128)]) -> Self { + pub fn new_with_genesis_accounts(initial_data: &[(Address, u128)]) -> Self { let authenticated_transfer_program = Program::authenticated_transfer_program(); let public_state = initial_data .iter() .copied() - .map(|(address_value, balance)| { + .map(|(address, balance)| { let account = Account { balance, program_owner: authenticated_transfer_program.id(), ..Account::default() }; - let address = Address::new(address_value); (address, account) }) .collect(); @@ -106,9 +105,9 @@ mod tests { fn test_new_with_genesis() { let key1 = PrivateKey::try_new([1; 32]).unwrap(); let key2 = PrivateKey::try_new([2; 32]).unwrap(); - let addr1 = Address::from_public_key(&PublicKey::new_from_private_key(&key1)); - let addr2 = Address::from_public_key(&PublicKey::new_from_private_key(&key2)); - let initial_data = [(*addr1.value(), 100u128), (*addr2.value(), 151u128)]; + let addr1 = Address::from(&PublicKey::new_from_private_key(&key1)); + let addr2 = Address::from(&PublicKey::new_from_private_key(&key2)); + let initial_data = [(addr1, 100u128), (addr2, 151u128)]; let program = Program::authenticated_transfer_program(); let expected_public_state = { let mut this = HashMap::new(); @@ -157,8 +156,8 @@ mod tests { #[test] fn test_get_account_by_address_non_default_account() { let key = PrivateKey::try_new([1; 32]).unwrap(); - let addr = Address::from_public_key(&PublicKey::new_from_private_key(&key)); - let initial_data = [(*addr.value(), 100u128)]; + let addr = Address::from(&PublicKey::new_from_private_key(&key)); + let initial_data = [(addr, 100u128)]; let state = V01State::new_with_genesis_accounts(&initial_data); let expected_account = state.public_state.get(&addr).unwrap(); @@ -190,8 +189,8 @@ mod tests { #[test] fn transition_from_authenticated_transfer_program_invocation_default_account_destination() { let key = PrivateKey::try_new([1; 32]).unwrap(); - let address = Address::from_public_key(&PublicKey::new_from_private_key(&key)); - let initial_data = [(*address.value(), 100)]; + let address = Address::from(&PublicKey::new_from_private_key(&key)); + let initial_data = [(address, 100)]; let mut state = V01State::new_with_genesis_accounts(&initial_data); let from = address; let to = Address::new([2; 32]); @@ -210,8 +209,8 @@ mod tests { #[test] fn transition_from_authenticated_transfer_program_invocation_insuficient_balance() { let key = PrivateKey::try_new([1; 32]).unwrap(); - let address = Address::from_public_key(&PublicKey::new_from_private_key(&key)); - let initial_data = [(*address.value(), 100)]; + let address = Address::from(&PublicKey::new_from_private_key(&key)); + let initial_data = [(address, 100)]; let mut state = V01State::new_with_genesis_accounts(&initial_data); let from = address; let from_key = key; @@ -233,9 +232,9 @@ mod tests { fn transition_from_authenticated_transfer_program_invocation_non_default_account_destination() { let key1 = PrivateKey::try_new([1; 32]).unwrap(); let key2 = PrivateKey::try_new([2; 32]).unwrap(); - let address1 = Address::from_public_key(&PublicKey::new_from_private_key(&key1)); - let address2 = Address::from_public_key(&PublicKey::new_from_private_key(&key2)); - let initial_data = [(*address1.value(), 100), (*address2.value(), 200)]; + let address1 = Address::from(&PublicKey::new_from_private_key(&key1)); + let address2 = Address::from(&PublicKey::new_from_private_key(&key2)); + let initial_data = [(address1, 100), (address2, 200)]; let mut state = V01State::new_with_genesis_accounts(&initial_data); let from = address2; let from_key = key2; @@ -255,10 +254,10 @@ mod tests { #[test] fn transition_from_chained_authenticated_transfer_program_invocations() { let key1 = PrivateKey::try_new([8; 32]).unwrap(); - let address1 = Address::from_public_key(&PublicKey::new_from_private_key(&key1)); + let address1 = Address::from(&PublicKey::new_from_private_key(&key1)); let key2 = PrivateKey::try_new([2; 32]).unwrap(); - let address2 = Address::from_public_key(&PublicKey::new_from_private_key(&key2)); - let initial_data = [(*address1.value(), 100)]; + let address2 = Address::from(&PublicKey::new_from_private_key(&key2)); + let initial_data = [(address1, 100)]; let mut state = V01State::new_with_genesis_accounts(&initial_data); let address3 = Address::new([3; 32]); let balance_to_move = 5; @@ -336,7 +335,7 @@ mod tests { #[test] fn test_program_should_fail_if_modifies_nonces() { - let initial_data = [([1; 32], 100)]; + let initial_data = [(Address::new([1; 32]), 100)]; let mut state = V01State::new_with_genesis_accounts(&initial_data).with_test_programs(); let addresses = vec![Address::new([1; 32])]; let program_id = Program::nonce_changer_program().id(); @@ -352,7 +351,7 @@ mod tests { #[test] fn test_program_should_fail_if_output_accounts_exceed_inputs() { - let initial_data = [([1; 32], 100)]; + let initial_data = [(Address::new([1; 32]), 100)]; let mut state = V01State::new_with_genesis_accounts(&initial_data).with_test_programs(); let addresses = vec![Address::new([1; 32])]; let program_id = Program::extra_output_program().id(); @@ -368,7 +367,7 @@ mod tests { #[test] fn test_program_should_fail_with_missing_output_accounts() { - let initial_data = [([1; 32], 100)]; + let initial_data = [(Address::new([1; 32]), 100)]; let mut state = V01State::new_with_genesis_accounts(&initial_data).with_test_programs(); let addresses = vec![Address::new([1; 32]), Address::new([2; 32])]; let program_id = Program::missing_output_program().id(); @@ -384,7 +383,7 @@ mod tests { #[test] fn test_program_should_fail_if_modifies_program_owner_with_only_non_default_program_owner() { - let initial_data = [([1; 32], 0)]; + let initial_data = [(Address::new([1; 32]), 0)]; let mut state = V01State::new_with_genesis_accounts(&initial_data).with_test_programs(); let address = Address::new([1; 32]); let account = state.get_account_by_address(&address); @@ -478,7 +477,7 @@ mod tests { #[test] fn test_program_should_fail_if_transfers_balance_from_non_owned_account() { - let initial_data = [([1; 32], 100)]; + let initial_data = [(Address::new([1; 32]), 100)]; let mut state = V01State::new_with_genesis_accounts(&initial_data).with_test_programs(); let sender_address = Address::new([1; 32]); let receiver_address = Address::new([2; 32]); diff --git a/nssa/test_program_methods/Cargo.toml b/nssa/test_program_methods/Cargo.toml index 7da210b..dded508 100644 --- a/nssa/test_program_methods/Cargo.toml +++ b/nssa/test_program_methods/Cargo.toml @@ -8,4 +8,3 @@ risc0-build = { version = "2.3.1" } [package.metadata.risc0] methods = ["guest"] - diff --git a/nssa/test_program_methods/guest/Cargo.toml b/nssa/test_program_methods/guest/Cargo.toml index 12bddbf..4b377c8 100644 --- a/nssa/test_program_methods/guest/Cargo.toml +++ b/nssa/test_program_methods/guest/Cargo.toml @@ -7,5 +7,4 @@ edition = "2021" [dependencies] risc0-zkvm = { version = "2.3.1", default-features = false, features = ['std'] } -nssa-core = {path = "../../core"} - +nssa-core = { path = "../../core" } diff --git a/sc_core/Cargo.toml b/sc_core/Cargo.toml index d83264b..8a615a0 100644 --- a/sc_core/Cargo.toml +++ b/sc_core/Cargo.toml @@ -33,6 +33,9 @@ path = "../utxo" [dependencies.common] path = "../common" +[dependencies.nssa] +path = "../nssa" + [dependencies.secp256k1-zkp] workspace = true features = ["std", "rand-std", "rand", "serde", "global-context"] diff --git a/sc_core/src/proofs_circuits.rs b/sc_core/src/proofs_circuits.rs index 08ce431..d6fbbc2 100644 --- a/sc_core/src/proofs_circuits.rs +++ b/sc_core/src/proofs_circuits.rs @@ -1,5 +1,6 @@ use bincode; use common::merkle_tree_public::merkle_tree::UTXOCommitmentsMerkleTree; +use nssa::Address; use rand::{thread_rng, RngCore}; use secp256k1_zkp::{CommitmentSecrets, Generator, PedersenCommitment, Tag, Tweak, SECP256K1}; use sha2::{Digest, Sha256}; @@ -82,7 +83,7 @@ pub fn private_circuit( for in_utxo in input_utxos { let nullifier_public_key = public_context .account_masks - .get(&in_utxo.owner) + .get(&Address::new(in_utxo.owner)) .unwrap() .nullifier_public_key; @@ -125,7 +126,7 @@ pub fn deshielded_circuit( for in_utxo in input_utxos { let nullifier_public_key = public_context .account_masks - .get(&in_utxo.owner) + .get(&Address::new(in_utxo.owner)) .unwrap() .nullifier_public_key; diff --git a/sc_core/src/public_context.rs b/sc_core/src/public_context.rs index e225513..cb14bbc 100644 --- a/sc_core/src/public_context.rs +++ b/sc_core/src/public_context.rs @@ -1,7 +1,8 @@ use std::collections::BTreeMap; -use accounts::account_core::{address::AccountAddress, AccountPublicMask}; +use accounts::account_core::AccountPublicMask; use common::merkle_tree_public::{merkle_tree::UTXOCommitmentsMerkleTree, TreeHashType}; +use nssa::Address; use serde::{ser::SerializeStruct, Serialize}; pub const PUBLIC_SC_CONTEXT: &str = "PublicSCContext"; @@ -16,9 +17,9 @@ pub const NULLIFIERS_SET: &str = "nullifiers_set"; ///Strucutre, representing context, given to a smart contract on a call pub struct PublicSCContext { - pub caller_address: AccountAddress, + pub caller_address: Address, pub caller_balance: u64, - pub account_masks: BTreeMap, + pub account_masks: BTreeMap, pub comitment_store_root: TreeHashType, pub commitments_tree: UTXOCommitmentsMerkleTree, } @@ -28,7 +29,12 @@ impl Serialize for PublicSCContext { where S: serde::Serializer, { - let mut account_masks_keys: Vec<[u8; 32]> = self.account_masks.keys().cloned().collect(); + let mut account_masks_keys: Vec<[u8; 32]> = self + .account_masks + .keys() + .cloned() + .map(|addr| *addr.value()) + .collect(); account_masks_keys.sort(); let mut account_mask_values: Vec = @@ -94,7 +100,7 @@ mod tests { use super::*; fn create_test_context() -> PublicSCContext { - let caller_address = [1; 32]; + let caller_address = Address::new([1; 32]); let comitment_store_root = [3; 32]; let commitments_tree = diff --git a/sequencer_core/src/sequencer_store/mod.rs b/sequencer_core/src/sequencer_store/mod.rs index fd39473..3d9708d 100644 --- a/sequencer_core/src/sequencer_store/mod.rs +++ b/sequencer_core/src/sequencer_store/mod.rs @@ -1,9 +1,8 @@ use std::path::Path; -use accounts::account_core::address::AccountAddress; use block_store::SequecerBlockStore; use common::block::HashableBlockData; -use nssa; +use nssa::{self, Address}; use rand::{rngs::OsRng, RngCore}; use crate::config::AccountInitialData; @@ -22,7 +21,7 @@ impl SequecerChainStore { is_genesis_random: bool, initial_accounts: &[AccountInitialData], ) -> Self { - let init_accs: Vec<(AccountAddress, u128)> = initial_accounts + let init_accs: Vec<(Address, u128)> = initial_accounts .iter() .map(|acc_data| { ( diff --git a/wallet/src/chain_storage/accounts_store.rs b/wallet/src/chain_storage/accounts_store.rs index cd46a6f..4dad474 100644 --- a/wallet/src/chain_storage/accounts_store.rs +++ b/wallet/src/chain_storage/accounts_store.rs @@ -1,8 +1,9 @@ -use accounts::account_core::{address::AccountAddress, Account}; +use accounts::account_core::Account; +use nssa::Address; use std::collections::HashMap; pub struct WalletAccountsStore { - pub accounts: HashMap, + pub accounts: HashMap, } impl WalletAccountsStore { @@ -16,7 +17,7 @@ impl WalletAccountsStore { self.accounts.insert(account.address, account); } - pub fn unregister_account(&mut self, account_addr: AccountAddress) { + pub fn unregister_account(&mut self, account_addr: Address) { self.accounts.remove(&account_addr); } } @@ -82,7 +83,7 @@ mod tests { let mut store = WalletAccountsStore::new(); let account_addr: [u8; 32] = pad_to_32("nonexistent".to_string().as_bytes()); - store.unregister_account(account_addr); + store.unregister_account(Address::new(account_addr)); assert!(store.accounts.is_empty()); } diff --git a/wallet/src/chain_storage/mod.rs b/wallet/src/chain_storage/mod.rs index 4467162..c04483b 100644 --- a/wallet/src/chain_storage/mod.rs +++ b/wallet/src/chain_storage/mod.rs @@ -1,8 +1,9 @@ use std::collections::{BTreeMap, HashMap}; -use accounts::account_core::{address::AccountAddress, Account}; +use accounts::account_core::Account; use anyhow::Result; use common::merkle_tree_public::merkle_tree::UTXOCommitmentsMerkleTree; +use nssa::Address; use sc_core::public_context::PublicSCContext; use serde::{Deserialize, Serialize}; @@ -37,7 +38,7 @@ impl From for HashMap<[u8; 32], Account> { } pub struct WalletChainStore { - pub acc_map: HashMap, + pub acc_map: HashMap, pub utxo_commitments_store: UTXOCommitmentsMerkleTree, pub wallet_config: WalletConfig, } @@ -54,7 +55,7 @@ impl WalletChainStore { }) } - pub fn produce_context(&self, caller: AccountAddress) -> PublicSCContext { + pub fn produce_context(&self, caller: Address) -> PublicSCContext { let mut account_masks = BTreeMap::new(); for (acc_addr, acc) in &self.acc_map { @@ -80,7 +81,7 @@ mod tests { fn create_initial_accounts() -> Vec { let initial_acc1 = serde_json::from_str(r#"{ - "address": [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], + "address": "1b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078f", "balance": 100, "key_holder": { "nullifer_public_key": "03A340BECA9FAAB444CED0140681D72EA1318B5C611704FEE017DA9836B17DB718", @@ -98,7 +99,7 @@ mod tests { }"#).unwrap(); let initial_acc2 = serde_json::from_str(r#"{ - "address": [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], + "address": "4d4b6cd1361032ca9bd2aeb9d900aa4d45d9ead80ac9423374c451a7254d0766", "balance": 200, "key_holder": { "nullifer_public_key": "02172F50274DE67C4087C344F5D58E11DF761D90285B095060E0994FAA6BCDE271", diff --git a/wallet/src/helperfunctions.rs b/wallet/src/helperfunctions.rs index aefb331..e5a328b 100644 --- a/wallet/src/helperfunctions.rs +++ b/wallet/src/helperfunctions.rs @@ -1,6 +1,7 @@ use std::{fs::File, io::BufReader, path::PathBuf, str::FromStr}; -use anyhow::{anyhow, Result}; +use anyhow::Result; +use nssa::{address::HexString, Address}; use crate::{config::WalletConfig, HOME_DIR_ENV_VAR}; @@ -19,8 +20,6 @@ pub fn fetch_config() -> Result { } //ToDo: Replace with structures conversion in future -pub fn produce_account_addr_from_hex(hex_str: String) -> Result<[u8; 32]> { - hex::decode(hex_str)? - .try_into() - .map_err(|_| anyhow!("Failed conversion to 32 bytes")) +pub fn produce_account_addr_from_hex(hex_str: String) -> Result
{ + Ok(HexString::try_from(hex_str.as_str())?.into()) } diff --git a/wallet/src/lib.rs b/wallet/src/lib.rs index f4add81..b2fb090 100644 --- a/wallet/src/lib.rs +++ b/wallet/src/lib.rs @@ -5,11 +5,12 @@ use common::{ ExecutionFailureKind, }; -use accounts::account_core::{address::AccountAddress, Account}; +use accounts::account_core::Account; use anyhow::Result; use chain_storage::WalletChainStore; use config::WalletConfig; use log::info; +use nssa::Address; use tokio::sync::RwLock; use clap::{Parser, Subcommand}; @@ -47,7 +48,7 @@ impl WalletCore { }) } - pub async fn create_new_account(&mut self) -> AccountAddress { + pub async fn create_new_account(&mut self) -> Address { let account = Account::new(); account.log(); @@ -64,9 +65,9 @@ impl WalletCore { pub async fn send_public_native_token_transfer( &self, - from: AccountAddress, + from: Address, nonce: u128, - to: AccountAddress, + to: Address, balance_to_move: u128, ) -> Result { { @@ -75,7 +76,7 @@ impl WalletCore { let account = read_guard.acc_map.get(&from); if let Some(account) = account { - let addresses = vec![nssa::Address::new(from), nssa::Address::new(to)]; + let addresses = vec![from, to]; let nonces = vec![nonce]; let program_id = nssa::program::Program::authenticated_transfer_program().id(); let message = nssa::public_transaction::Message::try_new( diff --git a/zkvm/Cargo.toml b/zkvm/Cargo.toml index b518109..dc3cdae 100644 --- a/zkvm/Cargo.toml +++ b/zkvm/Cargo.toml @@ -24,6 +24,9 @@ path = "../utxo" [dependencies.common] path = "../common" +[dependencies.nssa] +path = "../nssa" + [features] cuda = ["risc0-zkvm/cuda"] default = [] diff --git a/zkvm/src/lib.rs b/zkvm/src/lib.rs index 191456f..5bab1a3 100644 --- a/zkvm/src/lib.rs +++ b/zkvm/src/lib.rs @@ -1,5 +1,5 @@ -use accounts::account_core::address::AccountAddress; use common::ExecutionFailureKind; +use nssa::Address; use rand::{rngs::OsRng, RngCore}; use risc0_zkvm::{default_executor, default_prover, sha::Digest, ExecutorEnv, Receipt}; use serde::Serialize; @@ -35,7 +35,7 @@ pub fn gas_limits_check( #[allow(clippy::result_large_err)] pub fn prove_mint_utxo( amount_to_mint: u128, - owner: AccountAddress, + owner: Address, ) -> Result<(UTXO, Receipt), ExecutionFailureKind> { let mut builder = ExecutorEnv::builder(); @@ -74,8 +74,8 @@ pub fn prove_mint_utxo( #[allow(clippy::result_large_err)] pub fn prove_send_utxo( spent_utxo: UTXO, - owners_parts: Vec<(u128, AccountAddress)>, -) -> Result<(Vec<(UTXO, AccountAddress)>, Receipt), ExecutionFailureKind> { + owners_parts: Vec<(u128, Address)>, +) -> Result<(Vec<(UTXO, Address)>, Receipt), ExecutionFailureKind> { let cumulative_spent = owners_parts.iter().fold(0, |acc, item| acc + item.0); if cumulative_spent != spent_utxo.amount { @@ -113,7 +113,7 @@ pub fn prove_send_utxo( .map_err(ExecutionFailureKind::prove_error)? .receipt; - let digest: Vec<(UTXOPayload, AccountAddress)> = receipt + let digest: Vec<(UTXOPayload, Address)> = receipt .journal .decode() .map_err(|e| ExecutionFailureKind::DecodeError(e.to_string()))?; @@ -131,7 +131,7 @@ pub fn prove_send_utxo( pub fn prove_send_utxo_multiple_assets_one_receiver( spent_utxos: Vec, number_to_send: usize, - receiver: AccountAddress, + receiver: Address, ) -> Result<(Vec, Vec, Receipt), ExecutionFailureKind> { if number_to_send > spent_utxos.len() { return Err(ExecutionFailureKind::AmountMismatchError); @@ -186,17 +186,17 @@ pub fn prove_send_utxo_multiple_assets_one_receiver( #[allow(clippy::result_large_err)] pub fn prove_send_utxo_shielded( - owner: AccountAddress, + owner: Address, amount: u128, - owners_parts: Vec<(u128, AccountAddress)>, -) -> Result<(Vec<(UTXO, AccountAddress)>, Receipt), ExecutionFailureKind> { + owners_parts: Vec<(u128, Address)>, +) -> Result<(Vec<(UTXO, Address)>, Receipt), ExecutionFailureKind> { let cumulative_spent = owners_parts.iter().fold(0, |acc, item| acc + item.0); if cumulative_spent != amount { return Err(ExecutionFailureKind::AmountMismatchError); } - let temp_utxo_to_spend = UTXO::new(owner, vec![], amount, true); + let temp_utxo_to_spend = UTXO::new(*owner.value(), vec![], amount, true); let utxo_payload = temp_utxo_to_spend.into_payload(); let mut builder = ExecutorEnv::builder(); @@ -229,7 +229,7 @@ pub fn prove_send_utxo_shielded( .map_err(ExecutionFailureKind::prove_error)? .receipt; - let digest: Vec<(UTXOPayload, AccountAddress)> = receipt + let digest: Vec<(UTXOPayload, Address)> = receipt .journal .decode() .map_err(|e| ExecutionFailureKind::DecodeError(e.to_string()))?; @@ -246,8 +246,8 @@ pub fn prove_send_utxo_shielded( #[allow(clippy::result_large_err)] pub fn prove_send_utxo_deshielded( spent_utxo: UTXO, - owners_parts: Vec<(u128, AccountAddress)>, -) -> Result<(Vec<(u128, AccountAddress)>, Receipt), ExecutionFailureKind> { + owners_parts: Vec<(u128, Address)>, +) -> Result<(Vec<(u128, Address)>, Receipt), ExecutionFailureKind> { let cumulative_spent = owners_parts.iter().fold(0, |acc, item| acc + item.0); if cumulative_spent != spent_utxo.amount { @@ -285,7 +285,7 @@ pub fn prove_send_utxo_deshielded( .map_err(ExecutionFailureKind::prove_error)? .receipt; - let digest: Vec<(UTXOPayload, AccountAddress)> = receipt + let digest: Vec<(UTXOPayload, Address)> = receipt .journal .decode() .map_err(|e| ExecutionFailureKind::DecodeError(e.to_string()))?; @@ -303,7 +303,7 @@ pub fn prove_send_utxo_deshielded( pub fn prove_mint_utxo_multiple_assets( amount_to_mint: u128, number_of_assets: usize, - owner: AccountAddress, + owner: Address, ) -> Result<(Vec, Receipt), ExecutionFailureKind> { let mut builder = ExecutorEnv::builder(); @@ -344,7 +344,7 @@ pub fn prove_mint_utxo_multiple_assets( pub fn execute_mint_utxo( amount_to_mint: u128, - owner: AccountAddress, + owner: Address, randomness: [u8; 32], ) -> anyhow::Result { let mut builder = ExecutorEnv::builder(); @@ -366,8 +366,8 @@ pub fn execute_mint_utxo( pub fn execute_send_utxo( spent_utxo: UTXO, - owners_parts: Vec<(u128, AccountAddress)>, -) -> anyhow::Result<(UTXO, Vec<(UTXO, AccountAddress)>)> { + owners_parts: Vec<(u128, Address)>, +) -> anyhow::Result<(UTXO, Vec<(UTXO, Address)>)> { let mut builder = ExecutorEnv::builder(); let utxo_payload = spent_utxo.into_payload(); @@ -390,7 +390,7 @@ pub fn execute_send_utxo( let receipt = executor.execute(env, test_methods::SEND_UTXO_ELF)?; - let digest: (UTXOPayload, Vec<(UTXOPayload, AccountAddress)>) = receipt.journal.decode()?; + let digest: (UTXOPayload, Vec<(UTXOPayload, Address)>) = receipt.journal.decode()?; Ok(( UTXO::create_utxo_from_payload(digest.0), @@ -572,29 +572,29 @@ mod tests { #[test] fn test_execute_mint_utxo() { - let owner = AccountAddress::default(); + let owner = Address::default(); let amount = 123456789; let mut randomness = [0u8; 32]; OsRng.fill_bytes(&mut randomness); let utxo_exec = execute_mint_utxo(amount, owner, randomness).expect("execution failed"); assert_eq!(utxo_exec.amount, amount); - assert_eq!(utxo_exec.owner, owner); + assert_eq!(utxo_exec.owner, *owner.value()); } #[test] fn test_prove_mint_utxo() { - let owner = AccountAddress::default(); + let owner = Address::default(); let amount = 123456789; let (utxo, _) = prove_mint_utxo(amount, owner).expect("proof failed"); assert_eq!(utxo.amount, amount); - assert_eq!(utxo.owner, owner); + assert_eq!(utxo.owner, *owner.value()); } #[test] fn test_prove_send_utxo() { - let owner = AccountAddress::default(); + let owner = Address::default(); let amount = 100; let (input_utxo, _) = prove_mint_utxo(amount, owner).expect("mint failed"); @@ -608,7 +608,7 @@ mod tests { #[test] fn test_prove_send_utxo_deshielded() { - let owner = AccountAddress::default(); + let owner = Address::default(); let amount = 100; let (utxo, _) = prove_mint_utxo(amount, owner).unwrap(); let parts = vec![(60, owner), (40, owner)]; @@ -622,7 +622,7 @@ mod tests { #[test] fn test_prove_send_utxo_shielded() { - let owner = AccountAddress::default(); + let owner = Address::default(); let amount = 100; let parts = vec![(60, owner), (40, owner)]; @@ -635,8 +635,8 @@ mod tests { #[test] fn test_prove_send_utxo_multiple_assets_one_receiver() { - let owner = AccountAddress::default(); - let receiver = AccountAddress::default(); + let owner = Address::default(); + let receiver = Address::default(); let utxos = vec![ prove_mint_utxo(100, owner).unwrap().0,