diff --git a/lee/privacy_preserving_circuit/src/main.rs b/lee/privacy_preserving_circuit/src/main.rs index d0054dba..1fc06157 100644 --- a/lee/privacy_preserving_circuit/src/main.rs +++ b/lee/privacy_preserving_circuit/src/main.rs @@ -18,8 +18,7 @@ fn main() { program_outputs, ); - let output = - output::compute_circuit_output(execution_state, &account_identities, dummy_inputs); + let output = output::compute_circuit_output(execution_state, &account_identities, dummy_inputs); env::commit(&output); } diff --git a/lee/privacy_preserving_circuit/src/output.rs b/lee/privacy_preserving_circuit/src/output.rs index 12c556a6..1576e80e 100644 --- a/lee/privacy_preserving_circuit/src/output.rs +++ b/lee/privacy_preserving_circuit/src/output.rs @@ -1,7 +1,7 @@ use lee_core::{ - Commitment, CommitmentSetDigest, DummyInput, EncryptedAccountData, EncryptionScheme, EphemeralSecretKey, - InputAccountIdentity, MembershipProof, Nullifier, NullifierPublicKey, NullifierSecretKey, - PrivacyPreservingCircuitOutput, PrivateAccountKind, SharedSecretKey, + Commitment, CommitmentSetDigest, DummyInput, EncryptedAccountData, EncryptionScheme, + EphemeralSecretKey, InputAccountIdentity, MembershipProof, Nullifier, NullifierPublicKey, + NullifierSecretKey, PrivacyPreservingCircuitOutput, PrivateAccountKind, SharedSecretKey, account::{Account, AccountId, Nonce}, compute_digest_for_path, encryption::{ViewTag, ViewingPublicKey}, @@ -273,7 +273,9 @@ pub fn compute_circuit_output( fn emit_dummy_output(output: &mut PrivacyPreservingCircuitOutput, dummy: DummyInput) { let nullifier = Nullifier::for_dummy(&dummy.nullifier_seed); let commitment = Commitment::for_dummy(&nullifier, &dummy.commitment_seed); - output.new_nullifiers.push((nullifier, dummy.commitment_root)); + output + .new_nullifiers + .push((nullifier, dummy.commitment_root)); output.new_commitments.push(commitment); output.encrypted_private_post_states.push(dummy.note); } diff --git a/lee/state_machine/src/privacy_preserving_transaction/circuit/mod.rs b/lee/state_machine/src/privacy_preserving_transaction/circuit/mod.rs index 088b772c..5127531a 100644 --- a/lee/state_machine/src/privacy_preserving_transaction/circuit/mod.rs +++ b/lee/state_machine/src/privacy_preserving_transaction/circuit/mod.rs @@ -2,7 +2,8 @@ use std::collections::{HashMap, VecDeque}; use borsh::{BorshDeserialize, BorshSerialize}; use lee_core::{ - DummyInput, InputAccountIdentity, PrivacyPreservingCircuitInput, PrivacyPreservingCircuitOutput, + DummyInput, InputAccountIdentity, PrivacyPreservingCircuitInput, + PrivacyPreservingCircuitOutput, account::AccountWithMetadata, program::{ChainedCall, InstructionData, ProgramId, ProgramOutput}, }; diff --git a/lez/wallet/src/account_manager.rs b/lez/wallet/src/account_manager.rs index 55e1d01d..b1df1255 100644 --- a/lez/wallet/src/account_manager.rs +++ b/lez/wallet/src/account_manager.rs @@ -4,10 +4,14 @@ use anyhow::Result; use keycard_wallet::{KeycardWallet, python_path}; use lee::{AccountId, PrivateKey, PublicKey, Signature}; use lee_core::{ - CommitmentSetDigest, DUMMY_COMMITMENT_HASH, Identifier, InputAccountIdentity, MembershipProof, - NullifierPublicKey, NullifierSecretKey, SharedSecretKey, - account::{AccountWithMetadata, Nonce}, - encryption::{ViewTag, ViewingPublicKey}, + Commitment, CommitmentSetDigest, DUMMY_COMMITMENT_HASH, DummyInput, EncryptionScheme, + Identifier, InputAccountIdentity, MembershipProof, NullifierPublicKey, NullifierSecretKey, + PrivateAccountKind, SharedSecretKey, + account::{Account, AccountWithMetadata, Nonce}, + encryption::{ + EncryptedAccountData, EphemeralPublicKey, ML_KEM_768_CIPHERTEXT_LEN, ViewTag, + ViewingPublicKey, + }, }; use rand::{RngCore as _, rngs::OsRng}; @@ -410,6 +414,19 @@ impl AccountManager { .collect() } + /// Given a count, generate that many dummy inputs with randomized seeds and notes. + /// Uses the given commitment root from the account. + pub fn dummy_inputs(&self, count: usize) -> Vec { + std::iter::repeat_with(|| DummyInput { + nullifier_seed: random_bytes(), + commitment_seed: random_bytes(), + note: random_dummy_note(), + commitment_root: self.dummy_commitment_root, + }) + .take(count) + .collect() + } + /// Build the per-account input vec for the privacy-preserving circuit. Each variant carries /// exactly the fields the circuit's code path for that account needs, with the ephemeral /// keys (`ssk`) drawn from the cached values that `private_account_keys` and the message @@ -627,6 +644,36 @@ fn random_view_tag() -> ViewTag { byte[0] } +fn random_bytes() -> [u8; 32] { + let mut bytes = [0; 32]; + OsRng.fill_bytes(&mut bytes); + bytes +} + +/// Generates a random note by encoding a default account with random secret key, +/// then generating a random epk value (not connected to the original key) as well +/// as a random tag. +fn random_dummy_note() -> EncryptedAccountData { + let mut secret = [0; 32]; + OsRng.fill_bytes(&mut secret); + // The cipher is currently assumed to have default data. The data padding + // leak is a separate issue. + let ciphertext = EncryptionScheme::encrypt( + &Account::default(), + &PrivateAccountKind::Regular(0), + &SharedSecretKey(secret), + &Commitment::new(&AccountId::new([0; 32]), &Account::default()), + 0, + ); + let mut epk = vec![0; ML_KEM_768_CIPHERTEXT_LEN]; + OsRng.fill_bytes(&mut epk); + EncryptedAccountData { + ciphertext, + epk: EphemeralPublicKey(epk), + view_tag: random_view_tag(), + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/lez/wallet/src/lib.rs b/lez/wallet/src/lib.rs index bac5739d..f57e9e76 100644 --- a/lez/wallet/src/lib.rs +++ b/lez/wallet/src/lib.rs @@ -569,9 +569,13 @@ impl WalletCore { instruction_data: InstructionData, program: &ProgramWithDependencies, ) -> Result<(HashType, Vec), ExecutionFailureKind> { - self.send_privacy_preserving_tx_with_pre_check(accounts, instruction_data, program, |_| { - Ok(()) - }) + self.send_privacy_preserving_tx_with_pre_check( + accounts, + instruction_data, + program, + |_| Ok(()), + 0, + ) .await } @@ -581,6 +585,7 @@ impl WalletCore { instruction_data: InstructionData, program: &ProgramWithDependencies, tx_pre_check: impl FnOnce(&[&Account]) -> Result<(), ExecutionFailureKind>, + dummy_count: usize, ) -> Result<(HashType, Vec), ExecutionFailureKind> { let acc_manager = account_manager::AccountManager::new(self, accounts).await?; @@ -594,12 +599,14 @@ impl WalletCore { )?; let private_account_keys = acc_manager.private_account_keys(); - let (output, proof) = lee::privacy_preserving_transaction::circuit::execute_and_prove( - pre_states, - instruction_data, - acc_manager.account_identities(), - &program.to_owned(), - )?; + let (output, proof) = + lee::privacy_preserving_transaction::circuit::execute_and_prove_with_dummy_inputs( + pre_states, + instruction_data, + acc_manager.account_identities(), + acc_manager.dummy_inputs(dummy_count), + &program.to_owned(), + )?; let message = lee::privacy_preserving_transaction::message::Message::try_from_circuit_output( diff --git a/lez/wallet/src/program_facades/native_token_transfer/deshielded.rs b/lez/wallet/src/program_facades/native_token_transfer/deshielded.rs index f060e0fa..be70fe1d 100644 --- a/lez/wallet/src/program_facades/native_token_transfer/deshielded.rs +++ b/lez/wallet/src/program_facades/native_token_transfer/deshielded.rs @@ -24,6 +24,7 @@ impl NativeTokenTransfer<'_> { instruction_data, &program.into(), tx_pre_check, + 0, ) .await .map(|(resp, secrets)| { diff --git a/lez/wallet/src/program_facades/native_token_transfer/private.rs b/lez/wallet/src/program_facades/native_token_transfer/private.rs index 712d6774..52503ced 100644 --- a/lez/wallet/src/program_facades/native_token_transfer/private.rs +++ b/lez/wallet/src/program_facades/native_token_transfer/private.rs @@ -58,6 +58,7 @@ impl NativeTokenTransfer<'_> { instruction_data, &program.into(), tx_pre_check, + 0, ) .await .map(|(resp, secrets)| { @@ -91,6 +92,7 @@ impl NativeTokenTransfer<'_> { instruction_data, &program.into(), tx_pre_check, + 0, ) .await .map(|(resp, secrets)| { diff --git a/lez/wallet/src/program_facades/native_token_transfer/shielded.rs b/lez/wallet/src/program_facades/native_token_transfer/shielded.rs index 002b1176..fb935ab0 100644 --- a/lez/wallet/src/program_facades/native_token_transfer/shielded.rs +++ b/lez/wallet/src/program_facades/native_token_transfer/shielded.rs @@ -24,6 +24,7 @@ impl NativeTokenTransfer<'_> { instruction_data, &program.into(), tx_pre_check, + 0, ) .await .map(|(resp, secrets)| { @@ -57,6 +58,7 @@ impl NativeTokenTransfer<'_> { instruction_data, &program.into(), tx_pre_check, + 0, ) .await .map(|(resp, secrets)| {