This commit is contained in:
Sergio Chouhy 2025-11-20 19:25:56 -03:00
parent b90837edb6
commit b59cd0da92
6 changed files with 140 additions and 80 deletions

View File

@ -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(

View File

@ -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<ProgramId, Program>,
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();

View File

@ -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<ProgramId, Program>,
}
impl ProgramWithDependencies {
pub fn new(program: Program, dependencies: HashMap<ProgramId, Program>) -> Self {
Self {
program,
dependencies,
}
}
}
impl From<Program> 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 {

View File

@ -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);
}

View File

@ -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();

View File

@ -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();