From c02a80440422ac948746265fe6812c0067d4fe5c Mon Sep 17 00:00:00 2001 From: Sergio Chouhy Date: Fri, 18 Jul 2025 10:29:41 -0300 Subject: [PATCH] add missing files --- .../client/transfer_deshielded.rs | 1 + .../sequencer/process_privacy_execution.rs | 77 +++++++++++++++++++ .../sequencer/process_public_execution.rs | 72 +++++++++++++++++ 3 files changed, 150 insertions(+) create mode 100644 risc0-selective-privacy-poc/examples/mocked_components/sequencer/process_privacy_execution.rs create mode 100644 risc0-selective-privacy-poc/examples/mocked_components/sequencer/process_public_execution.rs diff --git a/risc0-selective-privacy-poc/examples/mocked_components/client/transfer_deshielded.rs b/risc0-selective-privacy-poc/examples/mocked_components/client/transfer_deshielded.rs index 919b775..e47b861 100644 --- a/risc0-selective-privacy-poc/examples/mocked_components/client/transfer_deshielded.rs +++ b/risc0-selective-privacy-poc/examples/mocked_components/client/transfer_deshielded.rs @@ -20,6 +20,7 @@ impl MockedClient { let receiver_addr = to_address; let mut receiver_account = Self::fresh_account_for_mint(*receiver_addr); let visibilities = [InputVisibiility::Public, InputVisibiility::Private(None)]; + let private_outputs = Self::prove_and_send_to_sequencer::( &[sender_account, receiver_account], balance_to_move, diff --git a/risc0-selective-privacy-poc/examples/mocked_components/sequencer/process_privacy_execution.rs b/risc0-selective-privacy-poc/examples/mocked_components/sequencer/process_privacy_execution.rs new file mode 100644 index 0000000..d620d37 --- /dev/null +++ b/risc0-selective-privacy-poc/examples/mocked_components/sequencer/process_privacy_execution.rs @@ -0,0 +1,77 @@ +use core::{ + account::Account, + types::{Commitment, Nullifier}, +}; + +use risc0_zkvm::Receipt; + +use super::MockedSequencer; + +impl MockedSequencer { + pub fn process_privacy_execution(&mut self, receipt: Receipt) -> Result<(), ()> { + let output: (Vec, Vec, Vec, [u32; 8]) = + receipt.journal.decode().unwrap(); + let (public_inputs_outputs, nullifiers, commitments, commitment_tree_root) = output; + + if commitment_tree_root != self.get_commitment_tree_root() { + return Err(()); + } + + if public_inputs_outputs.len() % 2 != 0 { + return Err(()); + } + + let num_input_public = public_inputs_outputs.len() >> 1; + for account in public_inputs_outputs.iter().take(num_input_public) { + let current_account = self.get_account(&account.address).ok_or(())?; + if ¤t_account != account { + return Err(()); + } + } + + // Check that nullifiers have not been added before + if nullifiers + .iter() + .any(|nullifier| self.nullifier_set.contains(nullifier)) + { + return Err(()); + } + + // Check that commitments are new too + if commitments + .iter() + .any(|commitment| self.commitment_tree.values().contains(commitment)) + { + return Err(()); + } + + // Verify consistency between public accounts, nullifiers and commitments + nssa::verify_privacy_execution( + receipt, + &public_inputs_outputs, + &nullifiers, + &commitments, + &commitment_tree_root, + )?; + + // Update accounts + public_inputs_outputs + .iter() + .cloned() + .skip(num_input_public) + .for_each(|account_post_state| { + self.accounts + .insert(account_post_state.address, account_post_state); + }); + + // Add nullifiers + self.nullifier_set.extend(nullifiers); + + // Add commitments + for commitment in commitments.iter() { + self.commitment_tree.add_value(*commitment); + } + + Ok(()) + } +} diff --git a/risc0-selective-privacy-poc/examples/mocked_components/sequencer/process_public_execution.rs b/risc0-selective-privacy-poc/examples/mocked_components/sequencer/process_public_execution.rs new file mode 100644 index 0000000..b05e35d --- /dev/null +++ b/risc0-selective-privacy-poc/examples/mocked_components/sequencer/process_public_execution.rs @@ -0,0 +1,72 @@ +use core::{account::Account, types::Address}; + +use super::MockedSequencer; + +impl MockedSequencer { + pub fn process_public_execution( + &mut self, + input_account_addresses: &[Address], + instruction_data: P::InstructionData, + ) -> Result<(), ()> { + // Fetch accounts + let input_accounts: Vec = input_account_addresses + .iter() + .map(|address| self.get_account(address).ok_or(())) + .collect::>()?; + + // Execute + let inputs_outputs = nssa::execute::

(&input_accounts, instruction_data)?; + + // Perform consistency checks + if !self.inputs_outputs_are_consistent(&input_accounts, &inputs_outputs) { + return Err(()); + } + + // Update accounts + inputs_outputs + .into_iter() + .skip(input_accounts.len()) + .for_each(|account_post_state| { + self.accounts + .insert(account_post_state.address, account_post_state); + }); + Ok(()) + } + + fn inputs_outputs_are_consistent( + &self, + input_accounts: &[Account], + inputs_outputs: &[Account], + ) -> bool { + let num_inputs = input_accounts.len(); + if inputs_outputs.len() != num_inputs * 2 { + return false; + } + + let (claimed_accounts_pre, accounts_post) = inputs_outputs.split_at(num_inputs); + if claimed_accounts_pre != input_accounts { + return false; + } + + for (account_pre, account_post) in input_accounts.iter().zip(accounts_post) { + if account_pre.address != account_post.address { + return false; + } + if account_pre.nonce != account_post.nonce { + return false; + } + // Redundant with previous checks, but better make it explicit. + if !self.accounts.contains_key(&account_post.address) { + return false; + } + } + let accounts_pre_total_balance: u128 = + input_accounts.iter().map(|account| account.balance).sum(); + let accounts_post_total_balance: u128 = + accounts_post.iter().map(|account| account.balance).sum(); + if accounts_pre_total_balance != accounts_post_total_balance { + return false; + } + return true; + } +}