From 1e955346109a6d5edb6a1dae3116669185680ddd Mon Sep 17 00:00:00 2001 From: Sergio Chouhy Date: Sun, 20 Jul 2025 19:58:02 -0300 Subject: [PATCH] refactor outer program for readability --- .../program_methods/guest/src/bin/outer.rs | 147 ++++++++++-------- 1 file changed, 86 insertions(+), 61 deletions(-) diff --git a/risc0-selective-privacy-poc/program_methods/guest/src/bin/outer.rs b/risc0-selective-privacy-poc/program_methods/guest/src/bin/outer.rs index 0c5c747..97c35b6 100644 --- a/risc0-selective-privacy-poc/program_methods/guest/src/bin/outer.rs +++ b/risc0-selective-privacy-poc/program_methods/guest/src/bin/outer.rs @@ -33,8 +33,8 @@ fn main() { let num_inputs = inner_program_output.accounts_pre.len(); // Read visibilities - let account_visibilities: Vec = env::read(); - assert_eq!(account_visibilities.len(), num_inputs); + let visibilities: Vec = env::read(); + assert_eq!(visibilities.len(), num_inputs); // Read nonces for outputs let output_nonces: Vec = env::read(); @@ -45,8 +45,89 @@ fn main() { let program_id: ProgramId = env::read(); // Authentication step: - // Check private accounts are owned by caller and that they are consistent - // with the commitments tree. + let nullifiers = verify_and_nullify_private_inputs(&inner_program_output, &visibilities, commitment_tree_root); + + // Verify pre states and post states of accounts are consistent + // with the execution of the `program_id` program + env::verify(program_id, &to_vec(&inner_program_output).unwrap()).unwrap(); + + // Assert accounts pre- and post-states preserve chains invariants + assert!(inputs_outputs_preserve_invariants( + &inner_program_output.accounts_pre, + &inner_program_output.accounts_post + )); + + // From this point on the execution is considered valid + + let output = assemble_privacy_execution_output( + inner_program_output, + visibilities, + output_nonces, + commitment_tree_root, + nullifiers, + ); + + env::commit(&output); +} + +fn assemble_privacy_execution_output( + inner_program_output: ProgramOutput, + visibilities: Vec, + output_nonces: Vec<[u32; 8]>, + commitment_tree_root: [u32; 8], + nullifiers: Vec<[u32; 8]>, +) -> PrivacyExecutionOutput { + // Insert new nonces in outputs (including public ones) + let accounts_pre = inner_program_output.accounts_pre; + let mut accounts_post = inner_program_output.accounts_post; + accounts_post + .iter_mut() + .zip(output_nonces) + .for_each(|(account, new_nonce)| account.nonce = new_nonce); + + // Compute commitments for every private output + let mut private_outputs = Vec::new(); + for (output, visibility) in accounts_post.iter().zip(visibilities.iter()) { + match visibility { + AccountVisibility::Public => continue, + AccountVisibility::Private(_) => private_outputs.push(output), + } + } + let private_output_commitments: Vec<_> = private_outputs.iter().map(|account| account.commitment()).collect(); + + // Get the list of public accounts pre and post states + let mut public_accounts_pre = Vec::new(); + let mut public_accounts_post = Vec::new(); + for ((account_pre, account_post), visibility) in accounts_pre + .into_iter() + .zip(accounts_post.into_iter()) + .zip(visibilities) + { + match visibility { + AccountVisibility::Public => { + public_accounts_pre.push(account_pre); + public_accounts_post.push(account_post); + } + AccountVisibility::Private(_) => continue, + } + } + + let output = PrivacyExecutionOutput { + public_accounts_pre, + public_accounts_post, + private_output_commitments, + nullifiers, + commitment_tree_root, + }; + output +} + +/// Compute nullifiers of private accounts pre states and check that their commitments belong to the commitments tree +fn verify_and_nullify_private_inputs( + inner_program_output: &ProgramOutput, + account_visibilities: &Vec, + commitment_tree_root: [u32; 8], +) -> Vec<[u32; 8]> { let mut nullifiers = Vec::new(); for (visibility, input_account) in account_visibilities .iter() @@ -73,61 +154,5 @@ fn main() { AccountVisibility::Public => continue, } } - - // Verify pre states and post states of accounts are consistent - // with the execution of the `program_id` program - env::verify(program_id, &to_vec(&inner_program_output).unwrap()).unwrap(); - - // Assert accounts pre- and post-states preserve chains invariants - assert!(inputs_outputs_preserve_invariants( - &inner_program_output.accounts_pre, - &inner_program_output.accounts_post - )); - - // From this point on the execution is considered valid - // - // Insert new nonces in outputs (including public ones) - let accounts_pre = inner_program_output.accounts_pre; - let mut accounts_post = inner_program_output.accounts_post; - accounts_post - .iter_mut() - .zip(output_nonces) - .for_each(|(account, new_nonce)| account.nonce = new_nonce); - - // Compute commitments for every private output - let mut private_outputs = Vec::new(); - for (output, visibility) in accounts_post.iter().zip(account_visibilities.iter()) { - match visibility { - AccountVisibility::Public => continue, - AccountVisibility::Private(_) => private_outputs.push(output), - } - } - let private_output_commitments: Vec<_> = private_outputs.iter().map(|account| account.commitment()).collect(); - - // Get the list of public accounts pre and post states - let mut public_accounts_pre = Vec::new(); - let mut public_accounts_post = Vec::new(); - for ((account_pre, account_post), visibility) in accounts_pre - .into_iter() - .zip(accounts_post.into_iter()) - .zip(account_visibilities) - { - match visibility { - AccountVisibility::Public => { - public_accounts_pre.push(account_pre); - public_accounts_post.push(account_post); - } - AccountVisibility::Private(_) => continue, - } - } - - let output = PrivacyExecutionOutput { - public_accounts_pre, - public_accounts_post, - private_output_commitments, - nullifiers, - commitment_tree_root, - }; - - env::commit(&output); + nullifiers }