diff --git a/risc0-selective-privacy-poc/core/src/account.rs b/risc0-selective-privacy-poc/core/src/account.rs index 1c0b67b..f76e82c 100644 --- a/risc0-selective-privacy-poc/core/src/account.rs +++ b/risc0-selective-privacy-poc/core/src/account.rs @@ -9,6 +9,7 @@ pub type Nullifier = [u32; 8]; pub type Address = [u32; 8]; pub type Nonce = [u32; 8]; pub type Key = [u32; 8]; +pub type AuthenticationPath = [[u32; 8]; 32]; #[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)] pub struct Account { @@ -47,7 +48,11 @@ pub fn hash(bytes: &[u32]) -> [u32; 8] { } /// Dummy implementation -pub fn is_in_commitment_tree(_commitment: Commitment, _tree_root: [u32; 8]) -> bool { +pub fn is_in_tree( + _commitment: Commitment, + _auth_path: &AuthenticationPath, + _tree_root: [u32; 8], +) -> bool { true } @@ -58,3 +63,11 @@ pub fn compute_nullifier(commitment: &Commitment, private_key: &Key) -> Nullifie bytes_to_hash[1..].copy_from_slice(private_key); hash(&bytes_to_hash) } + +pub fn bytes_to_words(bytes: [u8; 32]) -> [u32; 8] { + let mut words = [0; 8]; + for (i, chunk) in bytes.chunks(4).enumerate() { + words[i] = u32::from_le_bytes(chunk.try_into().unwrap()); + } + words +} diff --git a/risc0-selective-privacy-poc/core/src/input.rs b/risc0-selective-privacy-poc/core/src/input.rs index 9c303f0..fc7930f 100644 --- a/risc0-selective-privacy-poc/core/src/input.rs +++ b/risc0-selective-privacy-poc/core/src/input.rs @@ -1,4 +1,4 @@ -use crate::account::Key; +use crate::account::{AuthenticationPath, Key}; use serde::{Deserialize, Serialize}; #[derive(Serialize, Deserialize)] @@ -6,5 +6,5 @@ pub enum InputVisibiility { // A public account Public, // A private account - Private(Option), + Private(Option<(Key, AuthenticationPath)>), } diff --git a/risc0-selective-privacy-poc/core/src/lib.rs b/risc0-selective-privacy-poc/core/src/lib.rs index 873929a..2b84523 100644 --- a/risc0-selective-privacy-poc/core/src/lib.rs +++ b/risc0-selective-privacy-poc/core/src/lib.rs @@ -1,3 +1,5 @@ pub mod account; pub mod input; + + diff --git a/risc0-selective-privacy-poc/outer_methods/guest/src/bin/outer.rs b/risc0-selective-privacy-poc/outer_methods/guest/src/bin/outer.rs index c64a3f6..bcfa30e 100644 --- a/risc0-selective-privacy-poc/outer_methods/guest/src/bin/outer.rs +++ b/risc0-selective-privacy-poc/outer_methods/guest/src/bin/outer.rs @@ -1,6 +1,6 @@ use risc0_zkvm::{guest::env, serde::to_vec}; use toy_example_core::{ - account::{compute_nullifier, hash, is_in_commitment_tree, Account, Nonce}, + account::{compute_nullifier, hash, is_in_tree, Account, Nonce}, input::InputVisibiility, }; @@ -49,14 +49,14 @@ fn main() { let mut nullifiers = Vec::new(); for (visibility, input_account) in input_visibilities.iter().zip(inputs.iter()) { match visibility { - InputVisibiility::Private(Some(private_key)) => { + InputVisibiility::Private(Some((private_key, auth_path))) => { // Prove ownership of input accounts by proving // knowledge of the pre-image of their addresses. assert_eq!(hash(private_key), input_account.address); // Check the input account was created by a previous transaction // by checking it belongs to the commitments tree. let commitment = input_account.commitment(); - assert!(is_in_commitment_tree(commitment, commitment_tree_root)); + assert!(is_in_tree(commitment, auth_path, commitment_tree_root)); // Compute nullifier to nullify this private input account. let nullifier = compute_nullifier(&commitment, private_key); nullifiers.push(nullifier); diff --git a/risc0-selective-privacy-poc/src/private_execution.rs b/risc0-selective-privacy-poc/src/private_execution.rs index c41c1a4..2d476f2 100644 --- a/risc0-selective-privacy-poc/src/private_execution.rs +++ b/risc0-selective-privacy-poc/src/private_execution.rs @@ -1,14 +1,13 @@ use outer_methods::{OUTER_ELF, OUTER_ID}; use rand::{rngs::OsRng, Rng}; use risc0_zkvm::{default_prover, ExecutorEnv, Receipt}; +use sparse_merkle_tree::SparseMerkleTree; use toy_example_core::{ - account::{Account, Address, Commitment, Nonce, Nullifier}, + account::{bytes_to_words, Account, Address, Commitment, Nonce, Nullifier}, input::InputVisibiility, }; use transfer_methods::{TRANSFER_ELF, TRANSFER_ID}; -const COMMITMENT_TREE_ROOT: [u32; 8] = [0xdd, 0xee, 0xaa, 0xdd, 0xbb, 0xee, 0xee, 0xff]; - pub fn new_random_nonce() -> Nonce { let mut rng = OsRng; std::array::from_fn(|_| rng.gen()) @@ -32,6 +31,9 @@ fn run_private_execution_of_transfer_program() { account.balance = 150; account }; + let commitment_tree = SparseMerkleTree::new([sender.commitment()].into_iter().collect()); + let root = bytes_to_words(commitment_tree.root()); + let auth_path = commitment_tree.get_authentication_path_for_value(sender.commitment()); let balance_to_move: u128 = 3; @@ -44,7 +46,7 @@ fn run_private_execution_of_transfer_program() { let (inner_receipt, inputs_outputs) = prove_inner(&sender, &receiver, balance_to_move); let visibilities = vec![ - InputVisibiility::Private(Some(sender_private_key)), + InputVisibiility::Private(Some((sender_private_key, [[0; 8]; 32]))), InputVisibiility::Private(None), ]; @@ -63,7 +65,7 @@ fn run_private_execution_of_transfer_program() { env_builder.write(&inputs_outputs).unwrap(); env_builder.write(&visibilities).unwrap(); env_builder.write(&output_nonces).unwrap(); - env_builder.write(&COMMITMENT_TREE_ROOT).unwrap(); + env_builder.write(&root).unwrap(); env_builder.write(&TRANSFER_ID).unwrap(); let env = env_builder.build().unwrap();