diff --git a/integration_tests/src/tps_test_utils.rs b/integration_tests/src/tps_test_utils.rs index 1e31c02..23ce944 100644 --- a/integration_tests/src/tps_test_utils.rs +++ b/integration_tests/src/tps_test_utils.rs @@ -169,7 +169,7 @@ fn build_privacy_transaction() -> PrivacyPreservingTransaction { (recipient_npk.clone(), recipient_ss), ], &[(sender_nsk, proof)], - &program, + &program.into(), ) .unwrap(); let message = pptx::message::Message::try_from_circuit_output( diff --git a/nssa/src/privacy_preserving_transaction/circuit.rs b/nssa/src/privacy_preserving_transaction/circuit.rs index e0df466..2b5c655 100644 --- a/nssa/src/privacy_preserving_transaction/circuit.rs +++ b/nssa/src/privacy_preserving_transaction/circuit.rs @@ -8,7 +8,11 @@ use nssa_core::{ }; use risc0_zkvm::{ExecutorEnv, InnerReceipt, Receipt, default_prover}; -use crate::{error::NssaError, program::Program, state::MAX_NUMBER_CHAINED_CALLS}; +use crate::{ + error::NssaError, + program::{Program, ProgramWithDependencies}, + state::MAX_NUMBER_CHAINED_CALLS, +}; use crate::program_methods::{PRIVACY_PRESERVING_CIRCUIT_ELF, PRIVACY_PRESERVING_CIRCUIT_ID}; @@ -25,17 +29,17 @@ pub fn execute_and_prove( private_account_nonces: &[u128], private_account_keys: &[(NullifierPublicKey, SharedSecretKey)], private_account_auth: &[(NullifierSecretKey, MembershipProof)], - program: &Program, - programs: &HashMap, + program_with_dependencies: &ProgramWithDependencies, ) -> Result<(PrivacyPreservingCircuitOutput, Proof), NssaError> { - let mut program = program; + let mut program = &program_with_dependencies.program; + let dependencies = &program_with_dependencies.dependencies; let mut instruction_data = instruction_data.clone(); let mut pre_states = pre_states.to_vec(); let mut env_builder = ExecutorEnv::builder(); let mut program_outputs = Vec::new(); for _i in 0..MAX_NUMBER_CHAINED_CALLS { - let inner_receipt = execute_and_prove_program(program, &pre_states, &instruction_data)?; + let inner_receipt = execute_and_prove_program(&program, &pre_states, &instruction_data)?; let program_output: ProgramOutput = inner_receipt .journal @@ -49,8 +53,9 @@ pub fn execute_and_prove( env_builder.add_assumption(inner_receipt); if let Some(next_call) = program_output.chained_call { - // TODO: remove unwrap - program = programs.get(&next_call.program_id).unwrap(); + program = dependencies + .get(&next_call.program_id) + .ok_or(NssaError::InvalidProgramBehavior)?; instruction_data = next_call.instruction_data.clone(); // Build post states with metadata for next call let mut post_states_with_metadata = Vec::new(); @@ -85,7 +90,7 @@ pub fn execute_and_prove( private_account_nonces: private_account_nonces.to_vec(), private_account_keys: private_account_keys.to_vec(), private_account_auth: private_account_auth.to_vec(), - program_id: program.id(), + program_id: program_with_dependencies.program.id(), }; env_builder.write(&circuit_input).unwrap(); @@ -198,7 +203,7 @@ mod tests { &[0xdeadbeef], &[(recipient_keys.npk(), shared_secret.clone())], &[], - &Program::authenticated_transfer_program(), + &Program::authenticated_transfer_program().into(), ) .unwrap(); @@ -299,7 +304,7 @@ mod tests { sender_keys.nsk, commitment_set.get_proof_for(&commitment_sender).unwrap(), )], - &program, + &program.into(), ) .unwrap(); diff --git a/nssa/src/program.rs b/nssa/src/program.rs index 11eb413..bca6fb9 100644 --- a/nssa/src/program.rs +++ b/nssa/src/program.rs @@ -1,3 +1,5 @@ +use std::collections::HashMap; + use crate::program_methods::{AUTHENTICATED_TRANSFER_ELF, PINATA_ELF, TOKEN_ELF}; use nssa_core::{ account::AccountWithMetadata, @@ -96,6 +98,27 @@ impl Program { } } +pub struct ProgramWithDependencies { + pub program: Program, + // TODO: this will have a copy of each dependency bytecode in each program + pub dependencies: HashMap, +} + +impl ProgramWithDependencies { + pub fn new(program: Program, dependencies: HashMap) -> Self { + Self { + program, + dependencies, + } + } +} + +impl From for ProgramWithDependencies { + fn from(program: Program) -> Self { + ProgramWithDependencies::new(program, HashMap::new()) + } +} + // TODO: Testnet only. Refactor to prevent compilation on mainnet. impl Program { pub fn pinata() -> Self { diff --git a/nssa/src/state.rs b/nssa/src/state.rs index 0521aa7..726ff77 100644 --- a/nssa/src/state.rs +++ b/nssa/src/state.rs @@ -250,7 +250,7 @@ pub mod tests { privacy_preserving_transaction::{ PrivacyPreservingTransaction, circuit, message::Message, witness_set::WitnessSet, }, - program::Program, + program::{Program, ProgramWithDependencies}, public_transaction, signature::PrivateKey, }; @@ -838,7 +838,7 @@ pub mod tests { &[0xdeadbeef], &[(recipient_keys.npk(), shared_secret)], &[], - &Program::authenticated_transfer_program(), + &Program::authenticated_transfer_program().into(), ) .unwrap(); @@ -890,7 +890,7 @@ pub mod tests { sender_keys.nsk, state.get_proof_for_commitment(&sender_commitment).unwrap(), )], - &program, + &program.into(), ) .unwrap(); @@ -942,7 +942,7 @@ pub mod tests { sender_keys.nsk, state.get_proof_for_commitment(&sender_commitment).unwrap(), )], - &program, + &program.into(), ) .unwrap(); @@ -1154,7 +1154,7 @@ pub mod tests { &[], &[], &[], - &program, + &program.into(), ); assert!(matches!(result, Err(NssaError::CircuitProvingError(_)))); @@ -1180,7 +1180,7 @@ pub mod tests { &[], &[], &[], - &program, + &program.into(), ); assert!(matches!(result, Err(NssaError::CircuitProvingError(_)))); @@ -1206,7 +1206,7 @@ pub mod tests { &[], &[], &[], - &program, + &program.into(), ); assert!(matches!(result, Err(NssaError::CircuitProvingError(_)))); @@ -1232,7 +1232,7 @@ pub mod tests { &[], &[], &[], - &program, + &program.into(), ); assert!(matches!(result, Err(NssaError::CircuitProvingError(_)))); @@ -1258,7 +1258,7 @@ pub mod tests { &[], &[], &[], - &program, + &program.into(), ); assert!(matches!(result, Err(NssaError::CircuitProvingError(_)))); @@ -1293,7 +1293,7 @@ pub mod tests { &[], &[], &[], - &program, + &program.into(), ); assert!(matches!(result, Err(NssaError::CircuitProvingError(_)))); @@ -1319,7 +1319,7 @@ pub mod tests { &[], &[], &[], - &program, + &program.into(), ); assert!(matches!(result, Err(NssaError::CircuitProvingError(_)))); @@ -1354,7 +1354,7 @@ pub mod tests { &[], &[], &[], - &program, + &program.into(), ); assert!(matches!(result, Err(NssaError::CircuitProvingError(_)))); @@ -1391,7 +1391,7 @@ pub mod tests { &[], &[], &[], - &program, + &program.into(), ); assert!(matches!(result, Err(NssaError::CircuitProvingError(_)))); @@ -1432,7 +1432,7 @@ pub mod tests { ), ], &[(sender_keys.nsk, (0, vec![]))], - &program, + &program.into(), ); assert!(matches!(result, Err(NssaError::CircuitProvingError(_)))); @@ -1466,7 +1466,7 @@ pub mod tests { &[0xdeadbeef1, 0xdeadbeef2], &private_account_keys, &[(sender_keys.nsk, (0, vec![]))], - &program, + &program.into(), ); assert!(matches!(result, Err(NssaError::CircuitProvingError(_)))); @@ -1507,7 +1507,7 @@ pub mod tests { ), ], &private_account_auth, - &program, + &program.into(), ); assert!(matches!(result, Err(NssaError::CircuitProvingError(_)))); @@ -1555,7 +1555,7 @@ pub mod tests { &[0xdeadbeef1, 0xdeadbeef2], &private_account_keys, &private_account_auth, - &program, + &program.into(), ); assert!(matches!(result, Err(NssaError::CircuitProvingError(_)))); @@ -1601,7 +1601,7 @@ pub mod tests { ), ], &[(sender_keys.nsk, (0, vec![]))], - &program, + &program.into(), ); assert!(matches!(result, Err(NssaError::CircuitProvingError(_)))); @@ -1648,7 +1648,7 @@ pub mod tests { ), ], &[(sender_keys.nsk, (0, vec![]))], - &program, + &program.into(), ); assert!(matches!(result, Err(NssaError::CircuitProvingError(_)))); @@ -1694,7 +1694,7 @@ pub mod tests { ), ], &[(sender_keys.nsk, (0, vec![]))], - &program, + &program.into(), ); assert!(matches!(result, Err(NssaError::CircuitProvingError(_)))); @@ -1740,7 +1740,7 @@ pub mod tests { ), ], &[(sender_keys.nsk, (0, vec![]))], - &program, + &program.into(), ); assert!(matches!(result, Err(NssaError::CircuitProvingError(_)))); @@ -1784,7 +1784,7 @@ pub mod tests { ), ], &[(sender_keys.nsk, (0, vec![]))], - &program, + &program.into(), ); assert!(matches!(result, Err(NssaError::CircuitProvingError(_)))); @@ -1813,7 +1813,7 @@ pub mod tests { &[], &[], &[], - &program, + &program.into(), ); assert!(matches!(result, Err(NssaError::CircuitProvingError(_)))); @@ -1855,7 +1855,7 @@ pub mod tests { ), ], &[(sender_keys.nsk, (0, vec![]))], - &program, + &program.into(), ); assert!(matches!(result, Err(NssaError::CircuitProvingError(_)))); @@ -1901,7 +1901,7 @@ pub mod tests { &[0xdeadbeef1, 0xdeadbeef2], &private_account_keys, &[(sender_keys.nsk, (0, vec![]))], - &program, + &program.into(), ); assert!(matches!(result, Err(NssaError::CircuitProvingError(_)))); @@ -1947,7 +1947,7 @@ pub mod tests { ), ], &private_account_auth, - &program, + &program.into(), ); assert!(matches!(result, Err(NssaError::CircuitProvingError(_)))); @@ -2038,7 +2038,7 @@ pub mod tests { (sender_keys.npk(), shared_secret), ], &private_account_auth, - &program, + &program.into(), ); assert!(matches!(result, Err(NssaError::CircuitProvingError(_)))); @@ -2122,61 +2122,93 @@ pub mod tests { #[test] fn test_private_chained_call() { - let program = Program::chain_caller(); + let chain_caller = Program::chain_caller(); + let auth_transfers = Program::authenticated_transfer_program(); let from_keys = test_private_account_keys_1(); - let to_keys = test_private_account_keys_1(); + let to_keys = test_private_account_keys_2(); let initial_balance = 100; let from_account = AccountWithMetadata::new( Account { - program_owner: Program::authenticated_transfer_program().id(), + program_owner: auth_transfers.id(), balance: initial_balance, ..Account::default() }, true, &from_keys.npk(), ); - let to_account = AccountWithMetadata::new(Account::default(), true, &from_keys.npk()); + let to_account = AccountWithMetadata::new( + Account { + program_owner: auth_transfers.id(), + ..Account::default() + }, + true, + &to_keys.npk(), + ); let from_commitment = Commitment::new(&from_keys.npk(), &from_account.account); - let mut state = V02State::new_with_genesis_accounts(&[], &[from_commitment.clone()]) - .with_test_programs(); - // let from = address; - // let from_key = key; - // let to = Address::new([2; 32]); + let to_commitment = Commitment::new(&to_keys.npk(), &to_account.account); + let state = V02State::new_with_genesis_accounts( + &[], + &[from_commitment.clone(), to_commitment.clone()], + ) + .with_test_programs(); let amount: u128 = 37; let instruction: (u128, ProgramId) = (amount, Program::authenticated_transfer_program().id()); let from_esk = [3; 32]; let from_ss = SharedSecretKey::new(&from_esk, &from_keys.ivk()); - let from_epk = EphemeralPublicKey::from_scalar(from_esk); + // let from_epk = EphemeralPublicKey::from_scalar(from_esk); - let to_esk = [4; 32]; + let to_esk = [3; 32]; let to_ss = SharedSecretKey::new(&to_esk, &to_keys.ivk()); - let to_epk = EphemeralPublicKey::from_scalar(to_esk); + // let to_epk = EphemeralPublicKey::from_scalar(to_esk); + // + let mut dependencies = HashMap::new(); - let (output, proof) = execute_and_prove( - &[from_account, to_account], + dependencies.insert(auth_transfers.id(), auth_transfers); + let program_with_deps = ProgramWithDependencies::new(chain_caller, dependencies); + + let result = execute_and_prove( + &[to_account, from_account], &Program::serialize_instruction(instruction).unwrap(), - &[1, 2], + &[1, 1], &[0xdeadbeef1, 0xdeadbeef2], - &[(from_keys.npk(), from_ss), (to_keys.npk(), to_ss)], - &[( - from_keys.nsk, - state.get_proof_for_commitment(&from_commitment).unwrap(), - )], - &program, + &[(to_keys.npk(), from_ss), (from_keys.npk(), to_ss)], + &[ + ( + to_keys.nsk, + state.get_proof_for_commitment(&to_commitment).unwrap(), + ), + ( + from_keys.nsk, + state.get_proof_for_commitment(&from_commitment).unwrap(), + ), + ], + &program_with_deps, ) .unwrap(); - - let message = Message::try_from_circuit_output(vec![], vec![], vec![], output).unwrap(); - let witness_set = WitnessSet::for_message(&message, proof, &[]); - let tx = PrivacyPreservingTransaction::new(message, witness_set); - // - // state.transition_from_public_transaction(&tx).unwrap(); - // - // let from_post = state.get_account_by_address(&from); - // let to_post = state.get_account_by_address(&to); - // assert_eq!(from_post.balance, initial_balance - amount); - // assert_eq!(to_post, expected_to_post); } + + // let expected_to_post = Account { + // program_owner: Program::chain_caller().id(), + // balance: amount, + // ..Account::default() + // }; + // + // let message = public_transaction::Message::try_new( + // program.id(), + // vec![to, from], //The chain_caller program permutes the account order in the chain call + // vec![0], + // instruction, + // ) + // .unwrap(); + // let witness_set = public_transaction::WitnessSet::for_message(&message, &[&from_key]); + // let tx = PublicTransaction::new(message, witness_set); + // + // state.transition_from_public_transaction(&tx).unwrap(); + // + // let from_post = state.get_account_by_address(&from); + // let to_post = state.get_account_by_address(&to); + // assert_eq!(from_post.balance, initial_balance - amount); + // assert_eq!(to_post, expected_to_post); } diff --git a/wallet/src/pinata_interactions.rs b/wallet/src/pinata_interactions.rs index 6e3e5ce..0f20475 100644 --- a/wallet/src/pinata_interactions.rs +++ b/wallet/src/pinata_interactions.rs @@ -59,7 +59,7 @@ impl WalletCore { &produce_random_nonces(1), &[(winner_npk.clone(), shared_secret_winner.clone())], &[(winner_nsk.unwrap(), winner_proof)], - &program, + &program.into(), ) .unwrap(); @@ -125,7 +125,7 @@ impl WalletCore { &produce_random_nonces(1), &[(winner_npk.clone(), shared_secret_winner.clone())], &[], - &program, + &program.into(), ) .unwrap(); diff --git a/wallet/src/transaction_utils.rs b/wallet/src/transaction_utils.rs index 2dd69ca..d99a480 100644 --- a/wallet/src/transaction_utils.rs +++ b/wallet/src/transaction_utils.rs @@ -110,7 +110,7 @@ impl WalletCore { (from_nsk.unwrap(), from_proof.unwrap()), (to_nsk.unwrap(), to_proof), ], - &program, + &program.into(), ) .unwrap(); @@ -184,7 +184,7 @@ impl WalletCore { (to_npk.clone(), shared_secret_to.clone()), ], &[(from_nsk.unwrap(), from_proof.unwrap())], - &program, + &program.into(), ) .unwrap(); @@ -254,7 +254,7 @@ impl WalletCore { (to_npk.clone(), shared_secret_to.clone()), ], &[(from_nsk.unwrap(), from_proof.unwrap())], - &program, + &program.into(), ) .unwrap(); @@ -321,7 +321,7 @@ impl WalletCore { &produce_random_nonces(1), &[(from_npk.clone(), shared_secret.clone())], &[(from_nsk.unwrap(), from_proof.unwrap())], - &program, + &program.into(), ) .unwrap(); @@ -382,7 +382,7 @@ impl WalletCore { &produce_random_nonces(1), &[(to_npk.clone(), shared_secret.clone())], &[(to_nsk.unwrap(), to_proof)], - &program, + &program.into(), ) .unwrap(); @@ -448,7 +448,7 @@ impl WalletCore { &produce_random_nonces(1), &[(to_npk.clone(), shared_secret.clone())], &[], - &program, + &program.into(), ) .unwrap(); @@ -510,7 +510,7 @@ impl WalletCore { &produce_random_nonces(1), &[(to_npk.clone(), shared_secret.clone())], &[], - &program, + &program.into(), ) .unwrap(); @@ -562,7 +562,7 @@ impl WalletCore { &produce_random_nonces(1), &[(from_npk.clone(), shared_secret_from.clone())], &[], - &Program::authenticated_transfer_program(), + &Program::authenticated_transfer_program().into(), ) .unwrap();