diff --git a/risc0-selective-privacy-poc/core/src/lib.rs b/risc0-selective-privacy-poc/core/src/lib.rs index 7650de1..990071f 100644 --- a/risc0-selective-privacy-poc/core/src/lib.rs +++ b/risc0-selective-privacy-poc/core/src/lib.rs @@ -2,7 +2,10 @@ pub mod account; pub mod types; pub mod visibility; -use crate::types::{AuthenticationPath, Commitment, Key, Nullifier}; +use crate::{ + account::Account, + types::{AuthenticationPath, Commitment, Key, Nullifier}, +}; use risc0_zkvm::sha::{Impl, Sha256}; pub fn hash(bytes: &[u32]) -> [u32; 8] { diff --git a/risc0-selective-privacy-poc/core/src/types.rs b/risc0-selective-privacy-poc/core/src/types.rs index ff05508..f742c30 100644 --- a/risc0-selective-privacy-poc/core/src/types.rs +++ b/risc0-selective-privacy-poc/core/src/types.rs @@ -1,3 +1,7 @@ +use serde::{Deserialize, Serialize}; + +use crate::account::Account; + /// For this POC we consider 32-bit commitments pub type Commitment = u32; pub type Nullifier = [u32; 8]; @@ -6,3 +10,12 @@ pub type Nonce = [u32; 8]; pub type Key = [u32; 8]; pub type AuthenticationPath = [[u32; 8]; 32]; pub type ProgramId = [u32; 8]; + +#[derive(Serialize, Deserialize)] +pub struct PrivacyExecutionOutput { + pub public_accounts_pre: Vec, + pub public_accounts_post: Vec, + pub private_output_commitments: Vec, + pub nullifiers: Vec, + pub commitment_tree_root: [u32; 8], +} 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 index 3a28015..ce1715a 100644 --- 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 @@ -1,6 +1,6 @@ use core::{ account::Account, - types::{Commitment, Nullifier}, + types::{Commitment, Nullifier, PrivacyExecutionOutput}, }; use risc0_zkvm::Receipt; @@ -11,27 +11,22 @@ impl MockedSequencer { /// Processes a privacy execution request. /// Verifies the proof of the privacy execution and updates the state of the chain. pub fn process_privacy_execution(&mut self, receipt: Receipt) -> Result<(), ()> { - // Parse the output of the proof. - // This is the output of the "outer" program - let output: (Vec, Vec, Vec, [u32; 8]) = receipt.journal.decode().unwrap(); - let (public_inputs_outputs, nullifiers, commitments, commitment_tree_root) = output; + // Parse the output of the "outer" program + let output: PrivacyExecutionOutput = receipt.journal.decode().unwrap(); // Reject in case the root used in the privacy execution is not the current root. - if commitment_tree_root != self.get_commitment_tree_root() { + if output.commitment_tree_root != self.get_commitment_tree_root() { return Err(()); } - // Reject in case the number of accounts in the public_inputs_outputs is not even. - // This is because it is expected to contain the pre and post-states of public the accounts - // of the inner execution. - if public_inputs_outputs.len() % 2 != 0 { + // Reject in case the number of accounts pre states is different from the post states + if output.public_accounts_pre.len() != output.public_accounts_post.len() { return Err(()); } // Reject if the states of the public input accounts used in the inner execution do not // coincide with the on-chain state. - let num_input_public = public_inputs_outputs.len() >> 1; - for account in public_inputs_outputs.iter().take(num_input_public) { + for account in output.public_accounts_pre.iter() { let current_account = self.get_account(&account.address).ok_or(())?; if ¤t_account != account { return Err(()); @@ -39,7 +34,8 @@ impl MockedSequencer { } // Reject if the nullifiers of this privacy execution have already been published. - if nullifiers + if output + .nullifiers .iter() .any(|nullifier| self.nullifier_set.contains(nullifier)) { @@ -47,7 +43,8 @@ impl MockedSequencer { } // Reject if the commitments have already been seen. - if commitments + if output + .private_output_commitments .iter() .any(|commitment| self.commitment_tree.values().contains(commitment)) { @@ -61,30 +58,21 @@ impl MockedSequencer { // - The given nullifiers correctly correspond to commitments that currently belong to // the commitment tree. // - The given commitments are correctly computed from valid accounts. - nssa::verify_privacy_execution( - receipt, - &public_inputs_outputs, - &nullifiers, - &commitments, - &commitment_tree_root, - )?; + nssa::verify_privacy_execution(receipt)?; // At this point the privacy execution is considered valid. // // Update the state of the public accounts with the post-state of this privacy execution - public_inputs_outputs - .iter() - .cloned() - .skip(num_input_public) - .for_each(|account_post_state| { - self.accounts.insert(account_post_state.address, account_post_state); - }); + + output.public_accounts_post.into_iter().for_each(|account_post_state| { + self.accounts.insert(account_post_state.address, account_post_state); + }); // Add all nullifiers to the nullifier set. - self.nullifier_set.extend(nullifiers); + self.nullifier_set.extend(output.nullifiers); // Add commitments to the commitment tree. - for commitment in commitments.iter() { + for commitment in output.private_output_commitments.iter() { self.commitment_tree.add_value(*commitment); } diff --git a/risc0-selective-privacy-poc/examples/private_execution.rs b/risc0-selective-privacy-poc/examples/private_execution.rs index 316ab04..6963598 100644 --- a/risc0-selective-privacy-poc/examples/private_execution.rs +++ b/risc0-selective-privacy-poc/examples/private_execution.rs @@ -61,8 +61,7 @@ fn main() { .unwrap(); // Verify the proof - let output: (Vec, Vec, Vec, [u32; 8]) = receipt.journal.decode().unwrap(); - assert!(nssa::verify_privacy_execution(receipt, &output.0, &output.1, &output.2, &output.3).is_ok()); + assert!(nssa::verify_privacy_execution(receipt).is_ok()); println!("OK!"); } 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 1499a21..bf75dbb 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 @@ -1,7 +1,7 @@ use core::{ account::Account, compute_nullifier, hash, is_in_tree, - types::{Nonce, ProgramId}, + types::{Nonce, PrivacyExecutionOutput, ProgramId}, visibility::AccountVisibility, }; use risc0_zkvm::{guest::env, serde::to_vec}; @@ -110,24 +110,29 @@ fn main() { 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_inputs_outputs = Vec::new(); - for (account, visibility) in inputs - .iter() - .chain(outputs.iter()) + let mut public_accounts_pre = Vec::new(); + let mut public_accounts_post = Vec::new(); + for ((account_pre, account_post), visibility) in inputs + .into_iter() + .zip(outputs.into_iter()) .zip(account_visibilities.iter().chain(account_visibilities.iter())) { match visibility { AccountVisibility::Public => { - public_inputs_outputs.push(account); + public_accounts_pre.push(account_pre); + public_accounts_post.push(account_post); } AccountVisibility::Private(_) => continue, } } - env::commit(&( - public_inputs_outputs, - nullifiers, + let output = PrivacyExecutionOutput { + public_accounts_pre, + public_accounts_post, private_output_commitments, + nullifiers, commitment_tree_root, - )); + }; + + env::commit(&output); } diff --git a/risc0-selective-privacy-poc/src/lib.rs b/risc0-selective-privacy-poc/src/lib.rs index d8deed0..08c17df 100644 --- a/risc0-selective-privacy-poc/src/lib.rs +++ b/risc0-selective-privacy-poc/src/lib.rs @@ -129,23 +129,6 @@ pub fn execute_offchain( } /// Verifies a proof of the outer program for the given parameters. -pub fn verify_privacy_execution( - receipt: Receipt, - public_accounts_inputs_outputs: &[Account], - nullifiers: &[Nullifier], - private_output_commitments: &[Commitment], - commitment_tree_root: &[u32; 8], -) -> Result<(), ()> { - let output: (Vec, Vec, Vec, [u32; 8]) = receipt.journal.decode().unwrap(); - let expected_output = ( - public_accounts_inputs_outputs.to_vec(), - nullifiers.to_vec(), - private_output_commitments.to_vec(), - commitment_tree_root.to_owned(), - ); - if output != expected_output { - Err(()) - } else { - receipt.verify(OUTER_ID).map_err(|_| ()) - } +pub fn verify_privacy_execution(receipt: Receipt) -> Result<(), ()> { + receipt.verify(OUTER_ID).map_err(|_| ()) }