From d24969387c563bbc3ca4fb852403edd02dd8d5dc Mon Sep 17 00:00:00 2001 From: Sergio Chouhy Date: Mon, 8 Sep 2025 19:29:56 -0300 Subject: [PATCH 1/9] wip --- nssa/core/src/account.rs | 4 +++- nssa/core/src/circuit_io.rs | 4 ++-- nssa/core/src/program.rs | 7 ++++--- .../privacy_preserving_transaction/circuit.rs | 18 ++++++++++++------ .../transaction.rs | 2 +- nssa/src/program.rs | 15 +++++++++------ nssa/src/public_transaction/transaction.rs | 2 +- nssa/src/state.rs | 12 ++++++------ 8 files changed, 38 insertions(+), 26 deletions(-) diff --git a/nssa/core/src/account.rs b/nssa/core/src/account.rs index 688611e..1932de0 100644 --- a/nssa/core/src/account.rs +++ b/nssa/core/src/account.rs @@ -14,11 +14,13 @@ pub struct Account { pub nonce: Nonce, } +pub type FingerPrint = [u8; 32]; + #[derive(Serialize, Deserialize, Clone)] #[cfg_attr(any(feature = "host", test), derive(Debug, PartialEq, Eq))] pub struct AccountWithMetadata { pub account: Account, - pub is_authorized: bool, + pub fingerprint: FingerPrint, } #[cfg(test)] diff --git a/nssa/core/src/circuit_io.rs b/nssa/core/src/circuit_io.rs index e619b2d..da989f0 100644 --- a/nssa/core/src/circuit_io.rs +++ b/nssa/core/src/circuit_io.rs @@ -56,7 +56,7 @@ mod tests { data: b"test data".to_vec(), nonce: 18446744073709551614, }, - is_authorized: true, + fingerprint: [0; 32], }, AccountWithMetadata { account: Account { @@ -65,7 +65,7 @@ mod tests { data: b"test data".to_vec(), nonce: 9999999999999999999999, }, - is_authorized: false, + fingerprint: [1; 32], }, ], public_post_states: vec![Account { diff --git a/nssa/core/src/program.rs b/nssa/core/src/program.rs index d284bbc..aa2684e 100644 --- a/nssa/core/src/program.rs +++ b/nssa/core/src/program.rs @@ -1,4 +1,4 @@ -use crate::account::{Account, AccountWithMetadata}; +use crate::account::{Account, AccountWithMetadata, FingerPrint}; use risc0_zkvm::serde::Deserializer; use risc0_zkvm::{DeserializeOwned, guest::env}; use serde::{Deserialize, Serialize}; @@ -21,8 +21,9 @@ pub struct ProgramOutput { pub fn read_nssa_inputs() -> ProgramInput { let pre_states: Vec = env::read(); - let words: InstructionData = env::read(); - let instruction = T::deserialize(&mut Deserializer::new(words.as_ref())).unwrap(); + let instruction_words: InstructionData = env::read(); + let authorized_fingerprints: Vec = env::read(); + let instruction = T::deserialize(&mut Deserializer::new(instruction_words.as_ref())).unwrap(); ProgramInput { pre_states, instruction, diff --git a/nssa/src/privacy_preserving_transaction/circuit.rs b/nssa/src/privacy_preserving_transaction/circuit.rs index ed32f98..e681c78 100644 --- a/nssa/src/privacy_preserving_transaction/circuit.rs +++ b/nssa/src/privacy_preserving_transaction/circuit.rs @@ -1,7 +1,7 @@ use nssa_core::{ MembershipProof, NullifierPublicKey, NullifierSecretKey, PrivacyPreservingCircuitInput, PrivacyPreservingCircuitOutput, SharedSecretKey, - account::AccountWithMetadata, + account::{AccountWithMetadata, FingerPrint}, program::{InstructionData, ProgramOutput}, }; use risc0_zkvm::{ExecutorEnv, InnerReceipt, Receipt, default_prover}; @@ -72,10 +72,16 @@ fn execute_and_prove_program( program: &Program, pre_states: &[AccountWithMetadata], instruction_data: &InstructionData, + authorized_fingerprints: &[FingerPrint], ) -> Result { // Write inputs to the program let mut env_builder = ExecutorEnv::builder(); - Program::write_inputs(pre_states, instruction_data, &mut env_builder)?; + Program::write_inputs( + pre_states, + instruction_data, + authorized_fingerprints, + &mut env_builder, + )?; let env = env_builder.build().unwrap(); // Prove the program @@ -112,12 +118,12 @@ mod tests { balance: 100, ..Account::default() }, - is_authorized: true, + fingerprint: [0; 32], }; let recipient = AccountWithMetadata { account: Account::default(), - is_authorized: false, + fingerprint: [1; 32], }; let balance_to_move: u128 = 37; @@ -181,7 +187,7 @@ mod tests { nonce: 0xdeadbeef, ..Account::default() }, - is_authorized: true, + fingerprint: [0; 32], }; let sender_keys = test_private_account_keys_1(); let recipient_keys = test_private_account_keys_2(); @@ -189,7 +195,7 @@ mod tests { let recipient = AccountWithMetadata { account: Account::default(), - is_authorized: false, + fingerprint: [1; 32], }; let balance_to_move: u128 = 37; diff --git a/nssa/src/privacy_preserving_transaction/transaction.rs b/nssa/src/privacy_preserving_transaction/transaction.rs index 9aac54e..c782d01 100644 --- a/nssa/src/privacy_preserving_transaction/transaction.rs +++ b/nssa/src/privacy_preserving_transaction/transaction.rs @@ -92,7 +92,7 @@ impl PrivacyPreservingTransaction { .iter() .map(|address| AccountWithMetadata { account: state.get_account_by_address(address), - is_authorized: signer_addresses.contains(address), + fingerprint: *address.value(), }) .collect(); diff --git a/nssa/src/program.rs b/nssa/src/program.rs index 66358e9..a40fdf9 100644 --- a/nssa/src/program.rs +++ b/nssa/src/program.rs @@ -1,5 +1,5 @@ use nssa_core::{ - account::{Account, AccountWithMetadata}, + account::{Account, AccountWithMetadata, FingerPrint}, program::{InstructionData, ProgramId, ProgramOutput}, }; use program_methods::{AUTHENTICATED_TRANSFER_ELF, AUTHENTICATED_TRANSFER_ID}; @@ -33,10 +33,11 @@ impl Program { &self, pre_states: &[AccountWithMetadata], instruction_data: &InstructionData, + authorized_fingerprints: &[FingerPrint] ) -> Result, NssaError> { // Write inputs to the program let mut env_builder = ExecutorEnv::builder(); - Self::write_inputs(pre_states, instruction_data, &mut env_builder)?; + Self::write_inputs(pre_states, instruction_data, authorized_fingerprints, &mut env_builder)?; let env = env_builder.build().unwrap(); // Execute the program (without proving) @@ -58,11 +59,13 @@ impl Program { pub(crate) fn write_inputs( pre_states: &[AccountWithMetadata], instruction_data: &[u32], + authorized_fingerprints: &[FingerPrint], env_builder: &mut ExecutorEnvBuilder, ) -> Result<(), NssaError> { let pre_states = pre_states.to_vec(); + let authorized_fingerprints = authorized_fingerprints.to_vec(); env_builder - .write(&(pre_states, instruction_data)) + .write(&(pre_states, instruction_data, authorized_fingerprints)) .map_err(|e| NssaError::ProgramWriteInputFailed(e.to_string()))?; Ok(()) } @@ -173,11 +176,11 @@ mod tests { balance: 77665544332211, ..Account::default() }, - is_authorized: false, + fingerprint: [0; 32] }; let recipient = AccountWithMetadata { account: Account::default(), - is_authorized: false, + fingerprint: [1; 32] }; let expected_sender_post = Account { @@ -189,7 +192,7 @@ mod tests { ..Account::default() }; let [sender_post, recipient_post] = program - .execute(&[sender, recipient], &instruction_data) + .execute(&[sender, recipient], &instruction_data, &[]) .unwrap() .try_into() .unwrap(); diff --git a/nssa/src/public_transaction/transaction.rs b/nssa/src/public_transaction/transaction.rs index 20b2729..bce7eaa 100644 --- a/nssa/src/public_transaction/transaction.rs +++ b/nssa/src/public_transaction/transaction.rs @@ -93,7 +93,7 @@ impl PublicTransaction { .iter() .map(|address| AccountWithMetadata { account: state.get_account_by_address(address), - is_authorized: signer_addresses.contains(address), + fingerprint: *address.value() }) .collect(); diff --git a/nssa/src/state.rs b/nssa/src/state.rs index f980370..5ed4252 100644 --- a/nssa/src/state.rs +++ b/nssa/src/state.rs @@ -778,14 +778,14 @@ pub mod tests { ) -> PrivacyPreservingTransaction { let sender = AccountWithMetadata { account: state.get_account_by_address(&sender_keys.address()), - is_authorized: true, + fingerprint: *sender_keys.address().value(), }; let sender_nonce = sender.account.nonce; let recipient = AccountWithMetadata { account: Account::default(), - is_authorized: false, + fingerprint: recipient_keys.npk().to_byte_array(), }; let esk = [3; 32]; @@ -827,11 +827,11 @@ pub mod tests { let sender_commitment = Commitment::new(&sender_keys.npk(), sender_private_account); let sender_pre = AccountWithMetadata { account: sender_private_account.clone(), - is_authorized: true, + fingerprint: sender_keys.npk().to_byte_array(), }; let recipient_pre = AccountWithMetadata { account: Account::default(), - is_authorized: false, + fingerprint: recipient_keys.npk().to_byte_array(), }; let esk_1 = [3; 32]; @@ -887,11 +887,11 @@ pub mod tests { let sender_commitment = Commitment::new(&sender_keys.npk(), sender_private_account); let sender_pre = AccountWithMetadata { account: sender_private_account.clone(), - is_authorized: true, + fingerprint: sender_keys.npk().to_byte_array(), }; let recipient_pre = AccountWithMetadata { account: state.get_account_by_address(recipient_address), - is_authorized: false, + fingerprint: *recipient_address.value(), }; let esk = [3; 32]; From d63cde85b9034fbe4c0d01f75156c9018c5db187 Mon Sep 17 00:00:00 2001 From: Sergio Chouhy Date: Tue, 9 Sep 2025 17:03:58 -0300 Subject: [PATCH 2/9] rollback to is_authorized field --- nssa/core/src/account.rs | 1 + nssa/core/src/circuit_io.rs | 2 ++ nssa/core/src/program.rs | 1 - .../src/privacy_preserving_transaction/circuit.rs | 6 ++++-- .../privacy_preserving_transaction/transaction.rs | 1 + nssa/src/program.rs | 15 +++++++-------- nssa/src/public_transaction/transaction.rs | 1 + nssa/src/state.rs | 6 ++++++ 8 files changed, 22 insertions(+), 11 deletions(-) diff --git a/nssa/core/src/account.rs b/nssa/core/src/account.rs index 1932de0..94986c2 100644 --- a/nssa/core/src/account.rs +++ b/nssa/core/src/account.rs @@ -20,6 +20,7 @@ pub type FingerPrint = [u8; 32]; #[cfg_attr(any(feature = "host", test), derive(Debug, PartialEq, Eq))] pub struct AccountWithMetadata { pub account: Account, + pub is_authorized: bool, pub fingerprint: FingerPrint, } diff --git a/nssa/core/src/circuit_io.rs b/nssa/core/src/circuit_io.rs index da989f0..194b371 100644 --- a/nssa/core/src/circuit_io.rs +++ b/nssa/core/src/circuit_io.rs @@ -56,6 +56,7 @@ mod tests { data: b"test data".to_vec(), nonce: 18446744073709551614, }, + is_authorized: true, fingerprint: [0; 32], }, AccountWithMetadata { @@ -65,6 +66,7 @@ mod tests { data: b"test data".to_vec(), nonce: 9999999999999999999999, }, + is_authorized: false, fingerprint: [1; 32], }, ], diff --git a/nssa/core/src/program.rs b/nssa/core/src/program.rs index aa2684e..48593d8 100644 --- a/nssa/core/src/program.rs +++ b/nssa/core/src/program.rs @@ -22,7 +22,6 @@ pub struct ProgramOutput { pub fn read_nssa_inputs() -> ProgramInput { let pre_states: Vec = env::read(); let instruction_words: InstructionData = env::read(); - let authorized_fingerprints: Vec = env::read(); let instruction = T::deserialize(&mut Deserializer::new(instruction_words.as_ref())).unwrap(); ProgramInput { pre_states, diff --git a/nssa/src/privacy_preserving_transaction/circuit.rs b/nssa/src/privacy_preserving_transaction/circuit.rs index e681c78..ba7647c 100644 --- a/nssa/src/privacy_preserving_transaction/circuit.rs +++ b/nssa/src/privacy_preserving_transaction/circuit.rs @@ -72,14 +72,12 @@ fn execute_and_prove_program( program: &Program, pre_states: &[AccountWithMetadata], instruction_data: &InstructionData, - authorized_fingerprints: &[FingerPrint], ) -> Result { // Write inputs to the program let mut env_builder = ExecutorEnv::builder(); Program::write_inputs( pre_states, instruction_data, - authorized_fingerprints, &mut env_builder, )?; let env = env_builder.build().unwrap(); @@ -118,11 +116,13 @@ mod tests { balance: 100, ..Account::default() }, + is_authorized: true, fingerprint: [0; 32], }; let recipient = AccountWithMetadata { account: Account::default(), + is_authorized: false, fingerprint: [1; 32], }; @@ -187,6 +187,7 @@ mod tests { nonce: 0xdeadbeef, ..Account::default() }, + is_authorized: true, fingerprint: [0; 32], }; let sender_keys = test_private_account_keys_1(); @@ -195,6 +196,7 @@ mod tests { let recipient = AccountWithMetadata { account: Account::default(), + is_authorized: false, fingerprint: [1; 32], }; let balance_to_move: u128 = 37; diff --git a/nssa/src/privacy_preserving_transaction/transaction.rs b/nssa/src/privacy_preserving_transaction/transaction.rs index c782d01..ee8eeba 100644 --- a/nssa/src/privacy_preserving_transaction/transaction.rs +++ b/nssa/src/privacy_preserving_transaction/transaction.rs @@ -92,6 +92,7 @@ impl PrivacyPreservingTransaction { .iter() .map(|address| AccountWithMetadata { account: state.get_account_by_address(address), + is_authorized: signer_addresses.contains(address), fingerprint: *address.value(), }) .collect(); diff --git a/nssa/src/program.rs b/nssa/src/program.rs index a40fdf9..0c05902 100644 --- a/nssa/src/program.rs +++ b/nssa/src/program.rs @@ -33,11 +33,10 @@ impl Program { &self, pre_states: &[AccountWithMetadata], instruction_data: &InstructionData, - authorized_fingerprints: &[FingerPrint] ) -> Result, NssaError> { // Write inputs to the program let mut env_builder = ExecutorEnv::builder(); - Self::write_inputs(pre_states, instruction_data, authorized_fingerprints, &mut env_builder)?; + Self::write_inputs(pre_states, instruction_data, &mut env_builder)?; let env = env_builder.build().unwrap(); // Execute the program (without proving) @@ -59,13 +58,11 @@ impl Program { pub(crate) fn write_inputs( pre_states: &[AccountWithMetadata], instruction_data: &[u32], - authorized_fingerprints: &[FingerPrint], env_builder: &mut ExecutorEnvBuilder, ) -> Result<(), NssaError> { let pre_states = pre_states.to_vec(); - let authorized_fingerprints = authorized_fingerprints.to_vec(); env_builder - .write(&(pre_states, instruction_data, authorized_fingerprints)) + .write(&(pre_states, instruction_data)) .map_err(|e| NssaError::ProgramWriteInputFailed(e.to_string()))?; Ok(()) } @@ -176,11 +173,13 @@ mod tests { balance: 77665544332211, ..Account::default() }, - fingerprint: [0; 32] + is_authorized: true, + fingerprint: [0; 32], }; let recipient = AccountWithMetadata { account: Account::default(), - fingerprint: [1; 32] + is_authorized: false, + fingerprint: [1; 32], }; let expected_sender_post = Account { @@ -192,7 +191,7 @@ mod tests { ..Account::default() }; let [sender_post, recipient_post] = program - .execute(&[sender, recipient], &instruction_data, &[]) + .execute(&[sender, recipient], &instruction_data) .unwrap() .try_into() .unwrap(); diff --git a/nssa/src/public_transaction/transaction.rs b/nssa/src/public_transaction/transaction.rs index bce7eaa..f3a8ed6 100644 --- a/nssa/src/public_transaction/transaction.rs +++ b/nssa/src/public_transaction/transaction.rs @@ -93,6 +93,7 @@ impl PublicTransaction { .iter() .map(|address| AccountWithMetadata { account: state.get_account_by_address(address), + is_authorized: signer_addresses.contains(address), fingerprint: *address.value() }) .collect(); diff --git a/nssa/src/state.rs b/nssa/src/state.rs index 5ed4252..8662323 100644 --- a/nssa/src/state.rs +++ b/nssa/src/state.rs @@ -778,6 +778,7 @@ pub mod tests { ) -> PrivacyPreservingTransaction { let sender = AccountWithMetadata { account: state.get_account_by_address(&sender_keys.address()), + is_authorized: true, fingerprint: *sender_keys.address().value(), }; @@ -785,6 +786,7 @@ pub mod tests { let recipient = AccountWithMetadata { account: Account::default(), + is_authorized: false, fingerprint: recipient_keys.npk().to_byte_array(), }; @@ -827,10 +829,12 @@ pub mod tests { let sender_commitment = Commitment::new(&sender_keys.npk(), sender_private_account); let sender_pre = AccountWithMetadata { account: sender_private_account.clone(), + is_authorized: true, fingerprint: sender_keys.npk().to_byte_array(), }; let recipient_pre = AccountWithMetadata { account: Account::default(), + is_authorized: false, fingerprint: recipient_keys.npk().to_byte_array(), }; @@ -887,10 +891,12 @@ pub mod tests { let sender_commitment = Commitment::new(&sender_keys.npk(), sender_private_account); let sender_pre = AccountWithMetadata { account: sender_private_account.clone(), + is_authorized: true, fingerprint: sender_keys.npk().to_byte_array(), }; let recipient_pre = AccountWithMetadata { account: state.get_account_by_address(recipient_address), + is_authorized: false, fingerprint: *recipient_address.value(), }; From 3a9d9af8150a2ea0710b73657ad7e4231be23039 Mon Sep 17 00:00:00 2001 From: Sergio Chouhy Date: Wed, 10 Sep 2025 18:56:34 -0300 Subject: [PATCH 3/9] wip --- nssa/core/src/account.rs | 11 ++++++++-- nssa/core/src/circuit_io.rs | 7 +++---- nssa/core/src/nullifier.rs | 14 ++++++++++++- .../src/bin/privacy_preserving_circuit.rs | 11 +++++----- nssa/src/address.rs | 15 +++++++++++++ .../privacy_preserving_transaction/circuit.rs | 21 ++++++++----------- .../transaction.rs | 2 +- nssa/src/program.rs | 6 +++--- nssa/src/public_transaction/transaction.rs | 2 +- nssa/src/state.rs | 12 +++++------ 10 files changed, 65 insertions(+), 36 deletions(-) diff --git a/nssa/core/src/account.rs b/nssa/core/src/account.rs index 94986c2..45e6e2c 100644 --- a/nssa/core/src/account.rs +++ b/nssa/core/src/account.rs @@ -1,4 +1,4 @@ -use crate::program::ProgramId; +use crate::{NullifierPublicKey, program::ProgramId}; use serde::{Deserialize, Serialize}; pub type Nonce = u128; @@ -14,7 +14,14 @@ pub struct Account { pub nonce: Nonce, } -pub type FingerPrint = [u8; 32]; +#[derive(Serialize, Deserialize, Clone, PartialEq, Eq)] +#[cfg_attr(any(feature = "host", test), derive(Debug))] +pub struct FingerPrint([u8; 32]); +impl FingerPrint { + pub fn new(value: [u8; 32]) -> Self { + Self(value) + } +} #[derive(Serialize, Deserialize, Clone)] #[cfg_attr(any(feature = "host", test), derive(Debug, PartialEq, Eq))] diff --git a/nssa/core/src/circuit_io.rs b/nssa/core/src/circuit_io.rs index 194b371..2473475 100644 --- a/nssa/core/src/circuit_io.rs +++ b/nssa/core/src/circuit_io.rs @@ -40,8 +40,7 @@ impl PrivacyPreservingCircuitOutput { mod tests { use super::*; use crate::{ - Commitment, Nullifier, NullifierPublicKey, - account::{Account, AccountWithMetadata}, + account::{Account, AccountWithMetadata, FingerPrint}, Commitment, Nullifier, NullifierPublicKey }; use risc0_zkvm::serde::from_slice; @@ -57,7 +56,7 @@ mod tests { nonce: 18446744073709551614, }, is_authorized: true, - fingerprint: [0; 32], + fingerprint: FingerPrint::new([0; 32]), }, AccountWithMetadata { account: Account { @@ -67,7 +66,7 @@ mod tests { nonce: 9999999999999999999999, }, is_authorized: false, - fingerprint: [1; 32], + fingerprint: FingerPrint::new([1; 32]), }, ], public_post_states: vec![Account { diff --git a/nssa/core/src/nullifier.rs b/nssa/core/src/nullifier.rs index d1410de..c783091 100644 --- a/nssa/core/src/nullifier.rs +++ b/nssa/core/src/nullifier.rs @@ -1,12 +1,24 @@ use risc0_zkvm::sha::{Impl, Sha256}; use serde::{Deserialize, Serialize}; -use crate::Commitment; +use crate::{Commitment, account::FingerPrint}; #[derive(Serialize, Deserialize, PartialEq, Eq)] #[cfg_attr(any(feature = "host", test), derive(Debug, Clone, Hash))] pub struct NullifierPublicKey(pub(super) [u8; 32]); +impl From<&NullifierPublicKey> for FingerPrint { + fn from(value: &NullifierPublicKey) -> Self { + FingerPrint::new(value.0) + } +} + +impl From for FingerPrint { + fn from(value: NullifierPublicKey) -> Self { + FingerPrint::new(value.0) + } +} + impl From<&NullifierSecretKey> for NullifierPublicKey { fn from(value: &NullifierSecretKey) -> Self { let mut bytes = Vec::new(); diff --git a/nssa/program_methods/guest/src/bin/privacy_preserving_circuit.rs b/nssa/program_methods/guest/src/bin/privacy_preserving_circuit.rs index 83f593a..346682d 100644 --- a/nssa/program_methods/guest/src/bin/privacy_preserving_circuit.rs +++ b/nssa/program_methods/guest/src/bin/privacy_preserving_circuit.rs @@ -1,12 +1,7 @@ use risc0_zkvm::{guest::env, serde::to_vec}; use nssa_core::{ - account::{Account, AccountWithMetadata}, - compute_digest_for_path, - encryption::Ciphertext, - program::{validate_execution, ProgramOutput, DEFAULT_PROGRAM_ID}, - Commitment, CommitmentSetDigest, EncryptionScheme, Nullifier, NullifierPublicKey, - PrivacyPreservingCircuitInput, PrivacyPreservingCircuitOutput, + account::{Account, AccountWithMetadata, FingerPrint}, compute_digest_for_path, encryption::Ciphertext, program::{validate_execution, ProgramOutput, DEFAULT_PROGRAM_ID}, Commitment, CommitmentSetDigest, EncryptionScheme, Nullifier, NullifierPublicKey, PrivacyPreservingCircuitInput, PrivacyPreservingCircuitOutput }; fn main() { @@ -70,6 +65,10 @@ fn main() { let new_nonce = private_nonces_iter.next().expect("Missing private nonce"); let (npk, shared_secret) = private_keys_iter.next().expect("Missing keys"); + if FingerPrint::from(npk) != pre_states[i].fingerprint { + panic!("Fingerprint mismatch"); + } + if visibility_mask[i] == 1 { // Private account with authentication let (nsk, membership_proof) = diff --git a/nssa/src/address.rs b/nssa/src/address.rs index 93304d5..0dba65a 100644 --- a/nssa/src/address.rs +++ b/nssa/src/address.rs @@ -1,5 +1,6 @@ use std::{fmt::Display, str::FromStr}; +use nssa_core::account::FingerPrint; use serde::{Deserialize, Serialize}; use crate::signature::PublicKey; @@ -81,6 +82,20 @@ impl<'de> Deserialize<'de> for Address { } } + +impl From<&Address> for FingerPrint { + fn from(address: &Address) -> Self { + FingerPrint::new(address.value) + } +} + +impl From
for FingerPrint { + fn from(address: Address) -> Self { + FingerPrint::new(address.value) + } +} + + #[cfg(test)] mod tests { use crate::{Address, address::AddressError}; diff --git a/nssa/src/privacy_preserving_transaction/circuit.rs b/nssa/src/privacy_preserving_transaction/circuit.rs index ba7647c..c1afe39 100644 --- a/nssa/src/privacy_preserving_transaction/circuit.rs +++ b/nssa/src/privacy_preserving_transaction/circuit.rs @@ -75,11 +75,7 @@ fn execute_and_prove_program( ) -> Result { // Write inputs to the program let mut env_builder = ExecutorEnv::builder(); - Program::write_inputs( - pre_states, - instruction_data, - &mut env_builder, - )?; + Program::write_inputs(pre_states, instruction_data, &mut env_builder)?; let env = env_builder.build().unwrap(); // Prove the program @@ -110,6 +106,7 @@ mod tests { #[test] fn prove_privacy_preserving_execution_circuit_public_and_private_pre_accounts() { + let recipient_keys = test_private_account_keys_1(); let program = Program::authenticated_transfer_program(); let sender = AccountWithMetadata { account: Account { @@ -117,13 +114,13 @@ mod tests { ..Account::default() }, is_authorized: true, - fingerprint: [0; 32], + fingerprint: FingerPrint::new([0; 32]), }; let recipient = AccountWithMetadata { account: Account::default(), is_authorized: false, - fingerprint: [1; 32], + fingerprint: recipient_keys.npk().into(), }; let balance_to_move: u128 = 37; @@ -143,7 +140,6 @@ mod tests { }; let expected_sender_pre = sender.clone(); - let recipient_keys = test_private_account_keys_1(); let esk = [3; 32]; let shared_secret = SharedSecretKey::new(&esk, &recipient_keys.ivk()); @@ -181,6 +177,9 @@ mod tests { #[test] fn prove_privacy_preserving_execution_circuit_fully_private() { + let sender_keys = test_private_account_keys_1(); + let recipient_keys = test_private_account_keys_2(); + let sender_pre = AccountWithMetadata { account: Account { balance: 100, @@ -188,16 +187,14 @@ mod tests { ..Account::default() }, is_authorized: true, - fingerprint: [0; 32], + fingerprint: sender_keys.npk().into(), }; - let sender_keys = test_private_account_keys_1(); - let recipient_keys = test_private_account_keys_2(); let commitment_sender = Commitment::new(&sender_keys.npk(), &sender_pre.account); let recipient = AccountWithMetadata { account: Account::default(), is_authorized: false, - fingerprint: [1; 32], + fingerprint: recipient_keys.npk().into(), }; let balance_to_move: u128 = 37; diff --git a/nssa/src/privacy_preserving_transaction/transaction.rs b/nssa/src/privacy_preserving_transaction/transaction.rs index ee8eeba..a683f85 100644 --- a/nssa/src/privacy_preserving_transaction/transaction.rs +++ b/nssa/src/privacy_preserving_transaction/transaction.rs @@ -93,7 +93,7 @@ impl PrivacyPreservingTransaction { .map(|address| AccountWithMetadata { account: state.get_account_by_address(address), is_authorized: signer_addresses.contains(address), - fingerprint: *address.value(), + fingerprint: address.into(), }) .collect(); diff --git a/nssa/src/program.rs b/nssa/src/program.rs index 0c05902..cf7c9da 100644 --- a/nssa/src/program.rs +++ b/nssa/src/program.rs @@ -77,7 +77,7 @@ impl Program { #[cfg(test)] mod tests { - use nssa_core::account::{Account, AccountWithMetadata}; + use nssa_core::account::{Account, AccountWithMetadata, FingerPrint}; use crate::program::Program; @@ -174,12 +174,12 @@ mod tests { ..Account::default() }, is_authorized: true, - fingerprint: [0; 32], + fingerprint: FingerPrint::new([0; 32]), }; let recipient = AccountWithMetadata { account: Account::default(), is_authorized: false, - fingerprint: [1; 32], + fingerprint: FingerPrint::new([1; 32]), }; let expected_sender_post = Account { diff --git a/nssa/src/public_transaction/transaction.rs b/nssa/src/public_transaction/transaction.rs index f3a8ed6..64e0707 100644 --- a/nssa/src/public_transaction/transaction.rs +++ b/nssa/src/public_transaction/transaction.rs @@ -94,7 +94,7 @@ impl PublicTransaction { .map(|address| AccountWithMetadata { account: state.get_account_by_address(address), is_authorized: signer_addresses.contains(address), - fingerprint: *address.value() + fingerprint: address.into() }) .collect(); diff --git a/nssa/src/state.rs b/nssa/src/state.rs index 8662323..347102a 100644 --- a/nssa/src/state.rs +++ b/nssa/src/state.rs @@ -779,7 +779,7 @@ pub mod tests { let sender = AccountWithMetadata { account: state.get_account_by_address(&sender_keys.address()), is_authorized: true, - fingerprint: *sender_keys.address().value(), + fingerprint: sender_keys.address().into(), }; let sender_nonce = sender.account.nonce; @@ -787,7 +787,7 @@ pub mod tests { let recipient = AccountWithMetadata { account: Account::default(), is_authorized: false, - fingerprint: recipient_keys.npk().to_byte_array(), + fingerprint: recipient_keys.npk().into(), }; let esk = [3; 32]; @@ -830,12 +830,12 @@ pub mod tests { let sender_pre = AccountWithMetadata { account: sender_private_account.clone(), is_authorized: true, - fingerprint: sender_keys.npk().to_byte_array(), + fingerprint: sender_keys.npk().into(), }; let recipient_pre = AccountWithMetadata { account: Account::default(), is_authorized: false, - fingerprint: recipient_keys.npk().to_byte_array(), + fingerprint: recipient_keys.npk().into(), }; let esk_1 = [3; 32]; @@ -892,12 +892,12 @@ pub mod tests { let sender_pre = AccountWithMetadata { account: sender_private_account.clone(), is_authorized: true, - fingerprint: sender_keys.npk().to_byte_array(), + fingerprint: sender_keys.npk().into(), }; let recipient_pre = AccountWithMetadata { account: state.get_account_by_address(recipient_address), is_authorized: false, - fingerprint: *recipient_address.value(), + fingerprint: recipient_address.into(), }; let esk = [3; 32]; From e8ace6838f15b6ebeda3ab3d14b4f1c0628b24fa Mon Sep 17 00:00:00 2001 From: Sergio Chouhy Date: Thu, 11 Sep 2025 15:49:54 -0300 Subject: [PATCH 4/9] fmt, clippy --- nssa/core/src/account.rs | 2 +- nssa/core/src/circuit_io.rs | 7 ++++--- nssa/core/src/program.rs | 2 +- nssa/src/address.rs | 2 -- nssa/src/privacy_preserving_transaction/circuit.rs | 4 ++-- nssa/src/program.rs | 2 +- nssa/src/public_transaction/transaction.rs | 2 +- 7 files changed, 10 insertions(+), 11 deletions(-) diff --git a/nssa/core/src/account.rs b/nssa/core/src/account.rs index 45e6e2c..c3d5580 100644 --- a/nssa/core/src/account.rs +++ b/nssa/core/src/account.rs @@ -1,4 +1,4 @@ -use crate::{NullifierPublicKey, program::ProgramId}; +use crate::program::ProgramId; use serde::{Deserialize, Serialize}; pub type Nonce = u128; diff --git a/nssa/core/src/circuit_io.rs b/nssa/core/src/circuit_io.rs index 2473475..ecc25fc 100644 --- a/nssa/core/src/circuit_io.rs +++ b/nssa/core/src/circuit_io.rs @@ -40,7 +40,8 @@ impl PrivacyPreservingCircuitOutput { mod tests { use super::*; use crate::{ - account::{Account, AccountWithMetadata, FingerPrint}, Commitment, Nullifier, NullifierPublicKey + Commitment, Nullifier, NullifierPublicKey, + account::{Account, AccountWithMetadata, FingerPrint}, }; use risc0_zkvm::serde::from_slice; @@ -55,7 +56,7 @@ mod tests { data: b"test data".to_vec(), nonce: 18446744073709551614, }, - is_authorized: true, + is_authorized: true, fingerprint: FingerPrint::new([0; 32]), }, AccountWithMetadata { @@ -65,7 +66,7 @@ mod tests { data: b"test data".to_vec(), nonce: 9999999999999999999999, }, - is_authorized: false, + is_authorized: false, fingerprint: FingerPrint::new([1; 32]), }, ], diff --git a/nssa/core/src/program.rs b/nssa/core/src/program.rs index 48593d8..a4e6722 100644 --- a/nssa/core/src/program.rs +++ b/nssa/core/src/program.rs @@ -1,4 +1,4 @@ -use crate::account::{Account, AccountWithMetadata, FingerPrint}; +use crate::account::{Account, AccountWithMetadata}; use risc0_zkvm::serde::Deserializer; use risc0_zkvm::{DeserializeOwned, guest::env}; use serde::{Deserialize, Serialize}; diff --git a/nssa/src/address.rs b/nssa/src/address.rs index 0dba65a..04bd99d 100644 --- a/nssa/src/address.rs +++ b/nssa/src/address.rs @@ -82,7 +82,6 @@ impl<'de> Deserialize<'de> for Address { } } - impl From<&Address> for FingerPrint { fn from(address: &Address) -> Self { FingerPrint::new(address.value) @@ -95,7 +94,6 @@ impl From
for FingerPrint { } } - #[cfg(test)] mod tests { use crate::{Address, address::AddressError}; diff --git a/nssa/src/privacy_preserving_transaction/circuit.rs b/nssa/src/privacy_preserving_transaction/circuit.rs index c1afe39..82ba860 100644 --- a/nssa/src/privacy_preserving_transaction/circuit.rs +++ b/nssa/src/privacy_preserving_transaction/circuit.rs @@ -1,7 +1,7 @@ use nssa_core::{ MembershipProof, NullifierPublicKey, NullifierSecretKey, PrivacyPreservingCircuitInput, PrivacyPreservingCircuitOutput, SharedSecretKey, - account::{AccountWithMetadata, FingerPrint}, + account::AccountWithMetadata, program::{InstructionData, ProgramOutput}, }; use risc0_zkvm::{ExecutorEnv, InnerReceipt, Receipt, default_prover}; @@ -90,7 +90,7 @@ fn execute_and_prove_program( mod tests { use nssa_core::{ Commitment, EncryptionScheme, Nullifier, - account::{Account, AccountWithMetadata}, + account::{Account, AccountWithMetadata, FingerPrint}, }; use crate::{ diff --git a/nssa/src/program.rs b/nssa/src/program.rs index cf7c9da..d105f51 100644 --- a/nssa/src/program.rs +++ b/nssa/src/program.rs @@ -1,5 +1,5 @@ use nssa_core::{ - account::{Account, AccountWithMetadata, FingerPrint}, + account::{Account, AccountWithMetadata}, program::{InstructionData, ProgramId, ProgramOutput}, }; use program_methods::{AUTHENTICATED_TRANSFER_ELF, AUTHENTICATED_TRANSFER_ID}; diff --git a/nssa/src/public_transaction/transaction.rs b/nssa/src/public_transaction/transaction.rs index 64e0707..14dcc6f 100644 --- a/nssa/src/public_transaction/transaction.rs +++ b/nssa/src/public_transaction/transaction.rs @@ -94,7 +94,7 @@ impl PublicTransaction { .map(|address| AccountWithMetadata { account: state.get_account_by_address(address), is_authorized: signer_addresses.contains(address), - fingerprint: address.into() + fingerprint: address.into(), }) .collect(); From e12fe4492b887eed1b465edada735e14faa080e5 Mon Sep 17 00:00:00 2001 From: Sergio Chouhy Date: Thu, 11 Sep 2025 16:37:28 -0300 Subject: [PATCH 5/9] refactor --- nssa/core/src/account.rs | 29 ++++++++++++ nssa/core/src/circuit_io.rs | 20 ++++---- nssa/core/src/nullifier.rs | 6 --- nssa/src/address.rs | 6 --- .../privacy_preserving_transaction/circuit.rs | 40 ++++++++-------- .../transaction.rs | 10 ++-- nssa/src/program.rs | 17 +++---- nssa/src/public_transaction/transaction.rs | 10 ++-- nssa/src/state.rs | 47 +++++++------------ 9 files changed, 95 insertions(+), 90 deletions(-) diff --git a/nssa/core/src/account.rs b/nssa/core/src/account.rs index c3d5580..54d0196 100644 --- a/nssa/core/src/account.rs +++ b/nssa/core/src/account.rs @@ -14,6 +14,8 @@ 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 FingerPrint([u8; 32]); @@ -31,6 +33,17 @@ pub struct AccountWithMetadata { pub fingerprint: FingerPrint, } +#[cfg(feature = "host")] +impl AccountWithMetadata { + pub fn new(account: Account, is_authorized: bool, fingerprint: impl Into) -> Self { + Self { + account, + is_authorized, + fingerprint: fingerprint.into(), + } + } +} + #[cfg(test)] mod tests { use crate::program::DEFAULT_PROGRAM_ID; @@ -64,4 +77,20 @@ mod tests { assert_eq!(new_acc.program_owner, DEFAULT_PROGRAM_ID); } + + #[test] + fn test_account_with_metadata_constructor() { + let account = Account { + program_owner: [1, 2, 3, 4, 5, 6, 7, 8], + balance: 1337, + data: b"testing_account_with_metadata_constructor".to_vec(), + nonce: 0xdeadbeef, + }; + let fingerprint = FingerPrint::new([8; 32]); + let new_acc_with_metadata = + AccountWithMetadata::new(account.clone(), true, fingerprint.clone()); + assert_eq!(new_acc_with_metadata.account, account); + assert!(new_acc_with_metadata.is_authorized); + assert_eq!(new_acc_with_metadata.fingerprint, fingerprint); + } } diff --git a/nssa/core/src/circuit_io.rs b/nssa/core/src/circuit_io.rs index ecc25fc..beae76a 100644 --- a/nssa/core/src/circuit_io.rs +++ b/nssa/core/src/circuit_io.rs @@ -49,26 +49,26 @@ mod tests { fn test_privacy_preserving_circuit_output_to_bytes_is_compatible_with_from_slice() { let output = PrivacyPreservingCircuitOutput { public_pre_states: vec![ - AccountWithMetadata { - account: Account { + AccountWithMetadata::new( + Account { program_owner: [1, 2, 3, 4, 5, 6, 7, 8], balance: 12345678901234567890, data: b"test data".to_vec(), nonce: 18446744073709551614, }, - is_authorized: true, - fingerprint: FingerPrint::new([0; 32]), - }, - AccountWithMetadata { - account: Account { + true, + FingerPrint::new([0; 32]), + ), + AccountWithMetadata::new( + Account { program_owner: [9, 9, 9, 8, 8, 8, 7, 7], balance: 123123123456456567112, data: b"test data".to_vec(), nonce: 9999999999999999999999, }, - is_authorized: false, - fingerprint: FingerPrint::new([1; 32]), - }, + false, + FingerPrint::new([1; 32]), + ), ], public_post_states: vec![Account { program_owner: [1, 2, 3, 4, 5, 6, 7, 8], diff --git a/nssa/core/src/nullifier.rs b/nssa/core/src/nullifier.rs index c783091..e852af4 100644 --- a/nssa/core/src/nullifier.rs +++ b/nssa/core/src/nullifier.rs @@ -13,12 +13,6 @@ impl From<&NullifierPublicKey> for FingerPrint { } } -impl From for FingerPrint { - fn from(value: NullifierPublicKey) -> Self { - FingerPrint::new(value.0) - } -} - impl From<&NullifierSecretKey> for NullifierPublicKey { fn from(value: &NullifierSecretKey) -> Self { let mut bytes = Vec::new(); diff --git a/nssa/src/address.rs b/nssa/src/address.rs index 04bd99d..f9d085e 100644 --- a/nssa/src/address.rs +++ b/nssa/src/address.rs @@ -88,12 +88,6 @@ impl From<&Address> for FingerPrint { } } -impl From
for FingerPrint { - fn from(address: Address) -> Self { - FingerPrint::new(address.value) - } -} - #[cfg(test)] mod tests { use crate::{Address, address::AddressError}; diff --git a/nssa/src/privacy_preserving_transaction/circuit.rs b/nssa/src/privacy_preserving_transaction/circuit.rs index 82ba860..281d59b 100644 --- a/nssa/src/privacy_preserving_transaction/circuit.rs +++ b/nssa/src/privacy_preserving_transaction/circuit.rs @@ -108,20 +108,20 @@ mod tests { fn prove_privacy_preserving_execution_circuit_public_and_private_pre_accounts() { let recipient_keys = test_private_account_keys_1(); let program = Program::authenticated_transfer_program(); - let sender = AccountWithMetadata { - account: Account { + let sender = AccountWithMetadata::new( + Account { balance: 100, ..Account::default() }, - is_authorized: true, - fingerprint: FingerPrint::new([0; 32]), - }; + true, + FingerPrint::new([0; 32]), + ); - let recipient = AccountWithMetadata { - account: Account::default(), - is_authorized: false, - fingerprint: recipient_keys.npk().into(), - }; + let recipient = AccountWithMetadata::new( + Account::default(), + false, + FingerPrint::from(&recipient_keys.npk()), + ); let balance_to_move: u128 = 37; @@ -180,22 +180,22 @@ mod tests { let sender_keys = test_private_account_keys_1(); let recipient_keys = test_private_account_keys_2(); - let sender_pre = AccountWithMetadata { - account: Account { + let sender_pre = AccountWithMetadata::new( + Account { balance: 100, nonce: 0xdeadbeef, ..Account::default() }, - is_authorized: true, - fingerprint: sender_keys.npk().into(), - }; + true, + FingerPrint::from(&sender_keys.npk()), + ); let commitment_sender = Commitment::new(&sender_keys.npk(), &sender_pre.account); - let recipient = AccountWithMetadata { - account: Account::default(), - is_authorized: false, - fingerprint: recipient_keys.npk().into(), - }; + let recipient = AccountWithMetadata::new( + Account::default(), + false, + FingerPrint::from(&recipient_keys.npk()), + ); let balance_to_move: u128 = 37; let mut commitment_set = CommitmentSet::with_capacity(2); diff --git a/nssa/src/privacy_preserving_transaction/transaction.rs b/nssa/src/privacy_preserving_transaction/transaction.rs index a683f85..6992b2f 100644 --- a/nssa/src/privacy_preserving_transaction/transaction.rs +++ b/nssa/src/privacy_preserving_transaction/transaction.rs @@ -90,10 +90,12 @@ impl PrivacyPreservingTransaction { let public_pre_states: Vec<_> = message .public_addresses .iter() - .map(|address| AccountWithMetadata { - account: state.get_account_by_address(address), - is_authorized: signer_addresses.contains(address), - fingerprint: address.into(), + .map(|address| { + AccountWithMetadata::new( + state.get_account_by_address(address), + signer_addresses.contains(address), + address, + ) }) .collect(); diff --git a/nssa/src/program.rs b/nssa/src/program.rs index d105f51..552c436 100644 --- a/nssa/src/program.rs +++ b/nssa/src/program.rs @@ -168,19 +168,16 @@ mod tests { let program = Program::simple_balance_transfer(); let balance_to_move: u128 = 11223344556677; let instruction_data = Program::serialize_instruction(balance_to_move).unwrap(); - let sender = AccountWithMetadata { - account: Account { + let sender = AccountWithMetadata::new( + Account { balance: 77665544332211, ..Account::default() }, - is_authorized: true, - fingerprint: FingerPrint::new([0; 32]), - }; - let recipient = AccountWithMetadata { - account: Account::default(), - is_authorized: false, - fingerprint: FingerPrint::new([1; 32]), - }; + true, + FingerPrint::new([0; 32]), + ); + let recipient = + AccountWithMetadata::new(Account::default(), false, FingerPrint::new([1; 32])); let expected_sender_post = Account { balance: 77665544332211 - balance_to_move, diff --git a/nssa/src/public_transaction/transaction.rs b/nssa/src/public_transaction/transaction.rs index 14dcc6f..e5c8b5a 100644 --- a/nssa/src/public_transaction/transaction.rs +++ b/nssa/src/public_transaction/transaction.rs @@ -91,10 +91,12 @@ impl PublicTransaction { let pre_states: Vec<_> = message .addresses .iter() - .map(|address| AccountWithMetadata { - account: state.get_account_by_address(address), - is_authorized: signer_addresses.contains(address), - fingerprint: address.into(), + .map(|address| { + AccountWithMetadata::new( + state.get_account_by_address(address), + signer_addresses.contains(address), + address, + ) }) .collect(); diff --git a/nssa/src/state.rs b/nssa/src/state.rs index 347102a..4b8b25b 100644 --- a/nssa/src/state.rs +++ b/nssa/src/state.rs @@ -776,19 +776,15 @@ pub mod tests { balance_to_move: u128, state: &V01State, ) -> PrivacyPreservingTransaction { - let sender = AccountWithMetadata { - account: state.get_account_by_address(&sender_keys.address()), - is_authorized: true, - fingerprint: sender_keys.address().into(), - }; + let sender = AccountWithMetadata::new( + state.get_account_by_address(&sender_keys.address()), + true, + &sender_keys.address(), + ); let sender_nonce = sender.account.nonce; - let recipient = AccountWithMetadata { - account: Account::default(), - is_authorized: false, - fingerprint: recipient_keys.npk().into(), - }; + let recipient = AccountWithMetadata::new(Account::default(), false, &recipient_keys.npk()); let esk = [3; 32]; let shared_secret = SharedSecretKey::new(&esk, &recipient_keys.ivk()); @@ -827,16 +823,10 @@ pub mod tests { ) -> PrivacyPreservingTransaction { let program = Program::authenticated_transfer_program(); let sender_commitment = Commitment::new(&sender_keys.npk(), sender_private_account); - let sender_pre = AccountWithMetadata { - account: sender_private_account.clone(), - is_authorized: true, - fingerprint: sender_keys.npk().into(), - }; - let recipient_pre = AccountWithMetadata { - account: Account::default(), - is_authorized: false, - fingerprint: recipient_keys.npk().into(), - }; + let sender_pre = + AccountWithMetadata::new(sender_private_account.clone(), true, &sender_keys.npk()); + let recipient_pre = + AccountWithMetadata::new(Account::default(), false, &recipient_keys.npk()); let esk_1 = [3; 32]; let shared_secret_1 = SharedSecretKey::new(&esk_1, &sender_keys.ivk()); @@ -889,16 +879,13 @@ pub mod tests { ) -> PrivacyPreservingTransaction { let program = Program::authenticated_transfer_program(); let sender_commitment = Commitment::new(&sender_keys.npk(), sender_private_account); - let sender_pre = AccountWithMetadata { - account: sender_private_account.clone(), - is_authorized: true, - fingerprint: sender_keys.npk().into(), - }; - let recipient_pre = AccountWithMetadata { - account: state.get_account_by_address(recipient_address), - is_authorized: false, - fingerprint: recipient_address.into(), - }; + let sender_pre = + AccountWithMetadata::new(sender_private_account.clone(), true, &sender_keys.npk()); + let recipient_pre = AccountWithMetadata::new( + state.get_account_by_address(recipient_address), + false, + recipient_address, + ); let esk = [3; 32]; let shared_secret = SharedSecretKey::new(&esk, &sender_keys.ivk()); From f31bbe4876becdde6a94b73f31dd16010680e42f Mon Sep 17 00:00:00 2001 From: Sergio Chouhy Date: Fri, 12 Sep 2025 09:18:40 -0300 Subject: [PATCH 6/9] rename fingerprint to account_id --- nssa/core/src/account.rs | 14 +++++++------- nssa/core/src/circuit_io.rs | 6 +++--- nssa/core/src/nullifier.rs | 6 +++--- .../guest/src/bin/privacy_preserving_circuit.rs | 6 +++--- nssa/src/address.rs | 6 +++--- nssa/src/privacy_preserving_transaction/circuit.rs | 10 +++++----- nssa/src/program.rs | 6 +++--- 7 files changed, 27 insertions(+), 27 deletions(-) diff --git a/nssa/core/src/account.rs b/nssa/core/src/account.rs index 54d0196..fdd51e1 100644 --- a/nssa/core/src/account.rs +++ b/nssa/core/src/account.rs @@ -18,8 +18,8 @@ pub struct 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 FingerPrint([u8; 32]); -impl FingerPrint { +pub struct AccountId([u8; 32]); +impl AccountId { pub fn new(value: [u8; 32]) -> Self { Self(value) } @@ -30,16 +30,16 @@ impl FingerPrint { pub struct AccountWithMetadata { pub account: Account, pub is_authorized: bool, - pub fingerprint: FingerPrint, + pub account_id: AccountId, } #[cfg(feature = "host")] impl AccountWithMetadata { - pub fn new(account: Account, is_authorized: bool, fingerprint: impl Into) -> Self { + pub fn new(account: Account, is_authorized: bool, account_id: impl Into) -> Self { Self { account, is_authorized, - fingerprint: fingerprint.into(), + account_id: account_id.into(), } } } @@ -86,11 +86,11 @@ mod tests { data: b"testing_account_with_metadata_constructor".to_vec(), nonce: 0xdeadbeef, }; - let fingerprint = FingerPrint::new([8; 32]); + let fingerprint = AccountId::new([8; 32]); let new_acc_with_metadata = AccountWithMetadata::new(account.clone(), true, fingerprint.clone()); assert_eq!(new_acc_with_metadata.account, account); assert!(new_acc_with_metadata.is_authorized); - assert_eq!(new_acc_with_metadata.fingerprint, fingerprint); + assert_eq!(new_acc_with_metadata.account_id, fingerprint); } } diff --git a/nssa/core/src/circuit_io.rs b/nssa/core/src/circuit_io.rs index beae76a..deeedbd 100644 --- a/nssa/core/src/circuit_io.rs +++ b/nssa/core/src/circuit_io.rs @@ -41,7 +41,7 @@ mod tests { use super::*; use crate::{ Commitment, Nullifier, NullifierPublicKey, - account::{Account, AccountWithMetadata, FingerPrint}, + account::{Account, AccountWithMetadata, AccountId}, }; use risc0_zkvm::serde::from_slice; @@ -57,7 +57,7 @@ mod tests { nonce: 18446744073709551614, }, true, - FingerPrint::new([0; 32]), + AccountId::new([0; 32]), ), AccountWithMetadata::new( Account { @@ -67,7 +67,7 @@ mod tests { nonce: 9999999999999999999999, }, false, - FingerPrint::new([1; 32]), + AccountId::new([1; 32]), ), ], public_post_states: vec![Account { diff --git a/nssa/core/src/nullifier.rs b/nssa/core/src/nullifier.rs index e852af4..405bb56 100644 --- a/nssa/core/src/nullifier.rs +++ b/nssa/core/src/nullifier.rs @@ -1,15 +1,15 @@ use risc0_zkvm::sha::{Impl, Sha256}; use serde::{Deserialize, Serialize}; -use crate::{Commitment, account::FingerPrint}; +use crate::{Commitment, account::AccountId}; #[derive(Serialize, Deserialize, PartialEq, Eq)] #[cfg_attr(any(feature = "host", test), derive(Debug, Clone, Hash))] pub struct NullifierPublicKey(pub(super) [u8; 32]); -impl From<&NullifierPublicKey> for FingerPrint { +impl From<&NullifierPublicKey> for AccountId { fn from(value: &NullifierPublicKey) -> Self { - FingerPrint::new(value.0) + AccountId::new(value.0) } } diff --git a/nssa/program_methods/guest/src/bin/privacy_preserving_circuit.rs b/nssa/program_methods/guest/src/bin/privacy_preserving_circuit.rs index 346682d..398bfc6 100644 --- a/nssa/program_methods/guest/src/bin/privacy_preserving_circuit.rs +++ b/nssa/program_methods/guest/src/bin/privacy_preserving_circuit.rs @@ -1,7 +1,7 @@ use risc0_zkvm::{guest::env, serde::to_vec}; use nssa_core::{ - account::{Account, AccountWithMetadata, FingerPrint}, compute_digest_for_path, encryption::Ciphertext, program::{validate_execution, ProgramOutput, DEFAULT_PROGRAM_ID}, Commitment, CommitmentSetDigest, EncryptionScheme, Nullifier, NullifierPublicKey, PrivacyPreservingCircuitInput, PrivacyPreservingCircuitOutput + account::{Account, AccountWithMetadata, AccountId}, compute_digest_for_path, encryption::Ciphertext, program::{validate_execution, ProgramOutput, DEFAULT_PROGRAM_ID}, Commitment, CommitmentSetDigest, EncryptionScheme, Nullifier, NullifierPublicKey, PrivacyPreservingCircuitInput, PrivacyPreservingCircuitOutput }; fn main() { @@ -65,8 +65,8 @@ fn main() { let new_nonce = private_nonces_iter.next().expect("Missing private nonce"); let (npk, shared_secret) = private_keys_iter.next().expect("Missing keys"); - if FingerPrint::from(npk) != pre_states[i].fingerprint { - panic!("Fingerprint mismatch"); + if AccountId::from(npk) != pre_states[i].account_id { + panic!("AccountId mismatch"); } if visibility_mask[i] == 1 { diff --git a/nssa/src/address.rs b/nssa/src/address.rs index f9d085e..319b236 100644 --- a/nssa/src/address.rs +++ b/nssa/src/address.rs @@ -1,6 +1,6 @@ use std::{fmt::Display, str::FromStr}; -use nssa_core::account::FingerPrint; +use nssa_core::account::AccountId; use serde::{Deserialize, Serialize}; use crate::signature::PublicKey; @@ -82,9 +82,9 @@ impl<'de> Deserialize<'de> for Address { } } -impl From<&Address> for FingerPrint { +impl From<&Address> for AccountId { fn from(address: &Address) -> Self { - FingerPrint::new(address.value) + AccountId::new(address.value) } } diff --git a/nssa/src/privacy_preserving_transaction/circuit.rs b/nssa/src/privacy_preserving_transaction/circuit.rs index 281d59b..3d6f594 100644 --- a/nssa/src/privacy_preserving_transaction/circuit.rs +++ b/nssa/src/privacy_preserving_transaction/circuit.rs @@ -90,7 +90,7 @@ fn execute_and_prove_program( mod tests { use nssa_core::{ Commitment, EncryptionScheme, Nullifier, - account::{Account, AccountWithMetadata, FingerPrint}, + account::{Account, AccountWithMetadata, AccountId}, }; use crate::{ @@ -114,13 +114,13 @@ mod tests { ..Account::default() }, true, - FingerPrint::new([0; 32]), + AccountId::new([0; 32]), ); let recipient = AccountWithMetadata::new( Account::default(), false, - FingerPrint::from(&recipient_keys.npk()), + AccountId::from(&recipient_keys.npk()), ); let balance_to_move: u128 = 37; @@ -187,14 +187,14 @@ mod tests { ..Account::default() }, true, - FingerPrint::from(&sender_keys.npk()), + AccountId::from(&sender_keys.npk()), ); let commitment_sender = Commitment::new(&sender_keys.npk(), &sender_pre.account); let recipient = AccountWithMetadata::new( Account::default(), false, - FingerPrint::from(&recipient_keys.npk()), + AccountId::from(&recipient_keys.npk()), ); let balance_to_move: u128 = 37; diff --git a/nssa/src/program.rs b/nssa/src/program.rs index 552c436..6def822 100644 --- a/nssa/src/program.rs +++ b/nssa/src/program.rs @@ -77,7 +77,7 @@ impl Program { #[cfg(test)] mod tests { - use nssa_core::account::{Account, AccountWithMetadata, FingerPrint}; + use nssa_core::account::{Account, AccountWithMetadata, AccountId}; use crate::program::Program; @@ -174,10 +174,10 @@ mod tests { ..Account::default() }, true, - FingerPrint::new([0; 32]), + AccountId::new([0; 32]), ); let recipient = - AccountWithMetadata::new(Account::default(), false, FingerPrint::new([1; 32])); + AccountWithMetadata::new(Account::default(), false, AccountId::new([1; 32])); let expected_sender_post = Account { balance: 77665544332211 - balance_to_move, From 2c2c4fed764708ee142fc3ec02ac58e244e2fbbd Mon Sep 17 00:00:00 2001 From: Sergio Chouhy Date: Fri, 12 Sep 2025 09:36:26 -0300 Subject: [PATCH 7/9] add tests --- nssa/core/src/nullifier.rs | 17 +++++++++++++++++ nssa/src/address.rs | 12 ++++++++++++ 2 files changed, 29 insertions(+) diff --git a/nssa/core/src/nullifier.rs b/nssa/core/src/nullifier.rs index 405bb56..c7ee26e 100644 --- a/nssa/core/src/nullifier.rs +++ b/nssa/core/src/nullifier.rs @@ -71,4 +71,21 @@ mod tests { let npk = NullifierPublicKey::from(&nsk); assert_eq!(npk, expected_npk); } + + #[test] + fn test_account_id_from_nullifier_public_key() { + let nsk = [ + 57, 5, 64, 115, 153, 56, 184, 51, 207, 238, 99, 165, 147, 214, 213, 151, 30, 251, 30, + 196, 134, 22, 224, 211, 237, 120, 136, 225, 188, 220, 249, 28, + ]; + let npk = NullifierPublicKey::from(&nsk); + let expected_account_id = AccountId::new([ + 202, 120, 42, 189, 194, 218, 78, 244, 31, 6, 108, 169, 29, 61, 22, 221, 69, 138, 197, + 161, 241, 39, 142, 242, 242, 50, 188, 201, 99, 28, 176, 238, + ]); + + let account_id = AccountId::from(&npk); + + assert_eq!(account_id, expected_account_id); + } } diff --git a/nssa/src/address.rs b/nssa/src/address.rs index 319b236..24fc7cf 100644 --- a/nssa/src/address.rs +++ b/nssa/src/address.rs @@ -90,6 +90,8 @@ impl From<&Address> for AccountId { #[cfg(test)] mod tests { + use nssa_core::account::AccountId; + use crate::{Address, address::AddressError}; #[test] @@ -119,4 +121,14 @@ 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([55; 32]); + + let account_id = AccountId::from(&address); + + assert_eq!(account_id, expected_account_id); + } } From d91b07a785efcb373992b78afcd2fc4fa44aa44f Mon Sep 17 00:00:00 2001 From: Sergio Chouhy Date: Fri, 12 Sep 2025 09:39:08 -0300 Subject: [PATCH 8/9] fmt --- nssa/core/src/circuit_io.rs | 2 +- nssa/src/address.rs | 2 +- nssa/src/privacy_preserving_transaction/circuit.rs | 2 +- nssa/src/program.rs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/nssa/core/src/circuit_io.rs b/nssa/core/src/circuit_io.rs index deeedbd..14feef7 100644 --- a/nssa/core/src/circuit_io.rs +++ b/nssa/core/src/circuit_io.rs @@ -41,7 +41,7 @@ mod tests { use super::*; use crate::{ Commitment, Nullifier, NullifierPublicKey, - account::{Account, AccountWithMetadata, AccountId}, + account::{Account, AccountId, AccountWithMetadata}, }; use risc0_zkvm::serde::from_slice; diff --git a/nssa/src/address.rs b/nssa/src/address.rs index 24fc7cf..5837e20 100644 --- a/nssa/src/address.rs +++ b/nssa/src/address.rs @@ -126,7 +126,7 @@ mod tests { fn test_account_id_from_address() { let address: Address = "37".repeat(32).parse().unwrap(); let expected_account_id = AccountId::new([55; 32]); - + let account_id = AccountId::from(&address); assert_eq!(account_id, expected_account_id); diff --git a/nssa/src/privacy_preserving_transaction/circuit.rs b/nssa/src/privacy_preserving_transaction/circuit.rs index 3d6f594..d8e5701 100644 --- a/nssa/src/privacy_preserving_transaction/circuit.rs +++ b/nssa/src/privacy_preserving_transaction/circuit.rs @@ -90,7 +90,7 @@ fn execute_and_prove_program( mod tests { use nssa_core::{ Commitment, EncryptionScheme, Nullifier, - account::{Account, AccountWithMetadata, AccountId}, + account::{Account, AccountId, AccountWithMetadata}, }; use crate::{ diff --git a/nssa/src/program.rs b/nssa/src/program.rs index 6def822..1096df8 100644 --- a/nssa/src/program.rs +++ b/nssa/src/program.rs @@ -77,7 +77,7 @@ impl Program { #[cfg(test)] mod tests { - use nssa_core::account::{Account, AccountWithMetadata, AccountId}; + use nssa_core::account::{Account, AccountId, AccountWithMetadata}; use crate::program::Program; From 75b7fdd069f59b98a304d71fb6f547a2cf3d6722 Mon Sep 17 00:00:00 2001 From: Sergio Chouhy Date: Tue, 16 Sep 2025 07:51:40 -0300 Subject: [PATCH 9/9] add domain separation for private and public account ids --- nssa/core/src/account.rs | 1 + nssa/core/src/nullifier.rs | 11 ++++++++--- nssa/src/address.rs | 13 +++++++++++-- 3 files changed, 20 insertions(+), 5 deletions(-) diff --git a/nssa/core/src/account.rs b/nssa/core/src/account.rs index fdd51e1..e7f8558 100644 --- a/nssa/core/src/account.rs +++ b/nssa/core/src/account.rs @@ -78,6 +78,7 @@ mod tests { assert_eq!(new_acc.program_owner, DEFAULT_PROGRAM_ID); } + #[cfg(feature = "host")] #[test] fn test_account_with_metadata_constructor() { let account = Account { diff --git a/nssa/core/src/nullifier.rs b/nssa/core/src/nullifier.rs index c7ee26e..cafa47c 100644 --- a/nssa/core/src/nullifier.rs +++ b/nssa/core/src/nullifier.rs @@ -9,7 +9,12 @@ pub struct NullifierPublicKey(pub(super) [u8; 32]); impl From<&NullifierPublicKey> for AccountId { fn from(value: &NullifierPublicKey) -> Self { - AccountId::new(value.0) + const PRIVATE_ACCOUNT_ID_PREFIX: &[u8; 32] = b"/NSSA/v0.1/AccountId/Private/\x00\x00\x00"; + + let mut bytes = [0; 64]; + bytes[0..32].copy_from_slice(PRIVATE_ACCOUNT_ID_PREFIX); + bytes[32..].copy_from_slice(&value.0); + AccountId::new(Impl::hash_bytes(&bytes).as_bytes().try_into().unwrap()) } } @@ -80,8 +85,8 @@ mod tests { ]; let npk = NullifierPublicKey::from(&nsk); let expected_account_id = AccountId::new([ - 202, 120, 42, 189, 194, 218, 78, 244, 31, 6, 108, 169, 29, 61, 22, 221, 69, 138, 197, - 161, 241, 39, 142, 242, 242, 50, 188, 201, 99, 28, 176, 238, + 69, 160, 50, 67, 12, 56, 150, 116, 62, 145, 17, 161, 17, 45, 24, 53, 33, 167, 83, 178, + 47, 114, 111, 233, 251, 30, 54, 244, 184, 22, 100, 236, ]); let account_id = AccountId::from(&npk); diff --git a/nssa/src/address.rs b/nssa/src/address.rs index 5837e20..72144b2 100644 --- a/nssa/src/address.rs +++ b/nssa/src/address.rs @@ -2,6 +2,7 @@ use std::{fmt::Display, str::FromStr}; use nssa_core::account::AccountId; use serde::{Deserialize, Serialize}; +use sha2::{Digest, Sha256}; use crate::signature::PublicKey; @@ -84,7 +85,12 @@ impl<'de> Deserialize<'de> for Address { impl From<&Address> for AccountId { fn from(address: &Address) -> Self { - AccountId::new(address.value) + 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()) } } @@ -125,7 +131,10 @@ mod tests { #[test] fn test_account_id_from_address() { let address: Address = "37".repeat(32).parse().unwrap(); - let expected_account_id = AccountId::new([55; 32]); + 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);