diff --git a/artifacts/lee/privacy_preserving_circuit/privacy_preserving_circuit.bin b/artifacts/lee/privacy_preserving_circuit/privacy_preserving_circuit.bin index f8f80c51..bb4060e0 100644 Binary files a/artifacts/lee/privacy_preserving_circuit/privacy_preserving_circuit.bin and b/artifacts/lee/privacy_preserving_circuit/privacy_preserving_circuit.bin differ diff --git a/artifacts/lez/programs/amm.bin b/artifacts/lez/programs/amm.bin index 00f5343d..bbecfb28 100644 Binary files a/artifacts/lez/programs/amm.bin and b/artifacts/lez/programs/amm.bin differ diff --git a/artifacts/lez/programs/associated_token_account.bin b/artifacts/lez/programs/associated_token_account.bin index 8f4b95ed..fb0e04f2 100644 Binary files a/artifacts/lez/programs/associated_token_account.bin and b/artifacts/lez/programs/associated_token_account.bin differ diff --git a/artifacts/lez/programs/authenticated_transfer.bin b/artifacts/lez/programs/authenticated_transfer.bin index 4f56b0f7..7986077a 100644 Binary files a/artifacts/lez/programs/authenticated_transfer.bin and b/artifacts/lez/programs/authenticated_transfer.bin differ diff --git a/artifacts/lez/programs/bridge.bin b/artifacts/lez/programs/bridge.bin index e4e4ec5e..16170125 100644 Binary files a/artifacts/lez/programs/bridge.bin and b/artifacts/lez/programs/bridge.bin differ diff --git a/artifacts/lez/programs/clock.bin b/artifacts/lez/programs/clock.bin index 663cc59b..ae8db775 100644 Binary files a/artifacts/lez/programs/clock.bin and b/artifacts/lez/programs/clock.bin differ diff --git a/artifacts/lez/programs/faucet.bin b/artifacts/lez/programs/faucet.bin index b26cfc6f..f28425e0 100644 Binary files a/artifacts/lez/programs/faucet.bin and b/artifacts/lez/programs/faucet.bin differ diff --git a/artifacts/lez/programs/pinata.bin b/artifacts/lez/programs/pinata.bin index f93e2c37..7b32974e 100644 Binary files a/artifacts/lez/programs/pinata.bin and b/artifacts/lez/programs/pinata.bin differ diff --git a/artifacts/lez/programs/pinata_token.bin b/artifacts/lez/programs/pinata_token.bin index 1ffa430d..1b4a4d02 100644 Binary files a/artifacts/lez/programs/pinata_token.bin and b/artifacts/lez/programs/pinata_token.bin differ diff --git a/artifacts/lez/programs/token.bin b/artifacts/lez/programs/token.bin index 210c7c3a..a0f25405 100644 Binary files a/artifacts/lez/programs/token.bin and b/artifacts/lez/programs/token.bin differ diff --git a/artifacts/lez/programs/vault.bin b/artifacts/lez/programs/vault.bin index e6766101..ec74232d 100644 Binary files a/artifacts/lez/programs/vault.bin and b/artifacts/lez/programs/vault.bin differ diff --git a/integration_tests/tests/auth_transfer/private.rs b/integration_tests/tests/auth_transfer/private.rs index 30f0cfdd..3e285472 100644 --- a/integration_tests/tests/auth_transfer/private.rs +++ b/integration_tests/tests/auth_transfer/private.rs @@ -11,8 +11,10 @@ use lee::{ privacy_preserving_transaction::circuit::ProgramWithDependencies, program::Program, }; use lee_core::{ - EncryptedAccountData, InputAccountIdentity, NullifierPublicKey, - account::AccountWithMetadata, + DUMMY_COMMITMENT, DUMMY_COMMITMENT_HASH, EncryptedAccountData, InputAccountIdentity, Nullifier, + NullifierPublicKey, + account::{Account, AccountWithMetadata}, + compute_digest_for_path, encryption::{EphemeralPublicKey, ViewingPublicKey}, }; use log::info; @@ -710,6 +712,7 @@ async fn ppt_cant_chain_call_faucet() -> Result<()> { npk, ssk, identifier: 1337, + commitment_root: DUMMY_COMMITMENT_HASH, seed: None, }, ], @@ -720,3 +723,100 @@ async fn ppt_cant_chain_call_faucet() -> Result<()> { Ok(()) } + +async fn prove_init_with_commitment_root( + ctx: &TestContext, + commitment_root: lee_core::CommitmentSetDigest, +) -> Result { + let program = programs::authenticated_transfer(); + let sender_id = ctx.existing_public_accounts()[0]; + let sender_pre = AccountWithMetadata::new( + ctx.sequencer_client().get_account(sender_id).await?, + true, + sender_id, + ); + + let nsk: lee_core::NullifierSecretKey = [7; 32]; + let npk = NullifierPublicKey::from(&nsk); + let vpk = ViewingPublicKey::from_bytes(vec![4_u8; 1184]).unwrap(); + let ssk = SharedSecretKey([55_u8; 32]); + let recipient_account_id = AccountId::for_regular_private_account(&npk, 0); + let recipient = AccountWithMetadata::new(Account::default(), false, recipient_account_id); + + let (output, _) = execute_and_prove( + vec![sender_pre, recipient], + Program::serialize_instruction(authenticated_transfer_core::Instruction::Transfer { + amount: 1, + })?, + vec![ + InputAccountIdentity::Public, + InputAccountIdentity::PrivateUnauthorized { + epk: EphemeralPublicKey(Vec::new()), + view_tag: EncryptedAccountData::compute_view_tag(&npk, &vpk), + npk, + ssk, + identifier: 0, + commitment_root, + }, + ], + &program.into(), + )?; + + Ok(output) +} + +#[test] +async fn init_with_dummy_commitment_root_produces_valid_root() -> Result<()> { + let ctx = TestContext::new().await?; + + let dummy_proof = ctx + .sequencer_client() + .get_proof_for_commitment(DUMMY_COMMITMENT) + .await? + .expect("DUMMY_COMMITMENT must be in genesis commitment set"); + let expected_digest = compute_digest_for_path(&DUMMY_COMMITMENT, &dummy_proof); + + let nsk: lee_core::NullifierSecretKey = [7; 32]; + let npk = NullifierPublicKey::from(&nsk); + let recipient_account_id = AccountId::for_regular_private_account(&npk, 0); + + let output = prove_init_with_commitment_root(&ctx, expected_digest).await?; + + assert_eq!(output.new_nullifiers.len(), 1); + let (nullifier, digest) = &output.new_nullifiers[0]; + assert_eq!( + *nullifier, + Nullifier::for_account_initialization(&recipient_account_id) + ); + assert_eq!(*digest, expected_digest); + assert_ne!(*digest, DUMMY_COMMITMENT_HASH); + + Ok(()) +} + +#[test] +async fn init_nullifier_digest_is_bound_to_commitment_root() -> Result<()> { + let ctx = TestContext::new().await?; + + let dummy_proof = ctx + .sequencer_client() + .get_proof_for_commitment(DUMMY_COMMITMENT) + .await? + .expect("DUMMY_COMMITMENT must be in genesis commitment set"); + let expected_digest = compute_digest_for_path(&DUMMY_COMMITMENT, &dummy_proof); + + let output_with_root = prove_init_with_commitment_root(&ctx, expected_digest).await?; + let output_without_root = prove_init_with_commitment_root(&ctx, DUMMY_COMMITMENT_HASH).await?; + + assert_eq!(output_with_root.new_nullifiers[0].1, expected_digest); + assert_eq!( + output_without_root.new_nullifiers[0].1, + DUMMY_COMMITMENT_HASH + ); + assert_ne!( + output_with_root.new_nullifiers[0].1, + output_without_root.new_nullifiers[0].1, + ); + + Ok(()) +} diff --git a/integration_tests/tests/private_pda.rs b/integration_tests/tests/private_pda.rs index f3136717..81ff8467 100644 --- a/integration_tests/tests/private_pda.rs +++ b/integration_tests/tests/private_pda.rs @@ -22,7 +22,7 @@ use lee::{ program::Program, }; use lee_core::{ - EncryptedAccountData, InputAccountIdentity, NullifierPublicKey, + DUMMY_COMMITMENT_HASH, EncryptedAccountData, InputAccountIdentity, NullifierPublicKey, account::{Account, AccountWithMetadata}, encryption::ViewingPublicKey, program::PdaSeed, @@ -78,6 +78,7 @@ async fn fund_private_pda( npk, ssk, identifier, + commitment_root: DUMMY_COMMITMENT_HASH, seed: Some((seed, authority_program_id)), }, ]; diff --git a/integration_tests/tests/tps.rs b/integration_tests/tests/tps.rs index a11668a8..0b9a1002 100644 --- a/integration_tests/tests/tps.rs +++ b/integration_tests/tests/tps.rs @@ -23,7 +23,8 @@ use lee::{ public_transaction as putx, }; use lee_core::{ - EncryptedAccountData, InputAccountIdentity, MembershipProof, NullifierPublicKey, + DUMMY_COMMITMENT_HASH, EncryptedAccountData, InputAccountIdentity, MembershipProof, + NullifierPublicKey, account::{AccountWithMetadata, Nonce, data::Data}, encryption::ViewingPublicKey, }; @@ -314,6 +315,7 @@ fn build_privacy_transaction() -> PrivacyPreservingTransaction { npk: recipient_npk, ssk: recipient_ss, identifier: 0, + commitment_root: DUMMY_COMMITMENT_HASH, }, ], &program.into(), diff --git a/lee/privacy_preserving_circuit/src/output.rs b/lee/privacy_preserving_circuit/src/output.rs index 559170e7..74c1cccc 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, DUMMY_COMMITMENT_HASH, EncryptedAccountData, EncryptionScheme, - EphemeralPublicKey, InputAccountIdentity, MembershipProof, Nullifier, NullifierPublicKey, - NullifierSecretKey, PrivacyPreservingCircuitOutput, PrivateAccountKind, SharedSecretKey, + Commitment, CommitmentSetDigest, EncryptedAccountData, EncryptionScheme, EphemeralPublicKey, + InputAccountIdentity, MembershipProof, Nullifier, NullifierPublicKey, NullifierSecretKey, + PrivacyPreservingCircuitOutput, PrivateAccountKind, SharedSecretKey, account::{Account, AccountId, Nonce}, compute_digest_for_path, }; @@ -20,7 +20,7 @@ struct PrivateOutputHandler<'ctx> { } impl PrivateOutputHandler<'_> { - fn authorized_init(self, nsk: &NullifierSecretKey) { + fn authorized_init(self, nsk: &NullifierSecretKey, commitment_root: &CommitmentSetDigest) { let npk = NullifierPublicKey::from(nsk); let account_id = derive_and_verify_account_id(&npk, self.identifier, self.pre_state.account_id); @@ -35,7 +35,7 @@ impl PrivateOutputHandler<'_> { "Found new private account with non default values" ); - let (new_nullifier, new_nonce) = init_nullifier_and_nonce(&account_id); + let (new_nullifier, new_nonce) = init_nullifier_and_nonce(&account_id, commitment_root); let kind = PrivateAccountKind::Regular(self.identifier); self.emit_private_output(&account_id, &kind, new_nullifier, new_nonce); @@ -67,7 +67,7 @@ impl PrivateOutputHandler<'_> { self.emit_private_output(&account_id, &kind, new_nullifier, new_nonce); } - fn unauthorized(self, npk: &NullifierPublicKey) { + fn unauthorized(self, npk: &NullifierPublicKey, commitment_root: &CommitmentSetDigest) { let account_id = derive_and_verify_account_id(npk, self.identifier, self.pre_state.account_id); @@ -81,7 +81,7 @@ impl PrivateOutputHandler<'_> { "Found new private account marked as authorized." ); - let (new_nullifier, new_nonce) = init_nullifier_and_nonce(&account_id); + let (new_nullifier, new_nonce) = init_nullifier_and_nonce(&account_id, commitment_root); let kind = PrivateAccountKind::Regular(self.identifier); self.emit_private_output(&account_id, &kind, new_nullifier, new_nonce); @@ -89,6 +89,7 @@ impl PrivateOutputHandler<'_> { fn pda_init( self, + commitment_root: &CommitmentSetDigest, pos: usize, pda_seed_by_position: &std::collections::HashMap< usize, @@ -108,7 +109,8 @@ impl PrivateOutputHandler<'_> { "New private PDA must be default" ); - let (new_nullifier, new_nonce) = init_nullifier_and_nonce(&self.pre_state.account_id); + let (new_nullifier, new_nonce) = + init_nullifier_and_nonce(&self.pre_state.account_id, commitment_root); let account_id = self.pre_state.account_id; let (authority_program_id, seed) = pda_seed_by_position @@ -203,10 +205,13 @@ impl PrivateOutputHandler<'_> { } } -fn init_nullifier_and_nonce(account_id: &AccountId) -> ((Nullifier, CommitmentSetDigest), Nonce) { +fn init_nullifier_and_nonce( + account_id: &AccountId, + commitment_root: &CommitmentSetDigest, +) -> ((Nullifier, CommitmentSetDigest), Nonce) { let nullifier = ( Nullifier::for_account_initialization(account_id), - DUMMY_COMMITMENT_HASH, + *commitment_root, ); let nonce = Nonce::private_account_nonce_init(account_id); (nullifier, nonce) @@ -271,6 +276,7 @@ pub fn compute_circuit_output( ssk, nsk, identifier, + commitment_root, } => PrivateOutputHandler { output: &mut output, output_index: &mut output_index, @@ -281,7 +287,7 @@ pub fn compute_circuit_output( ssk, identifier: *identifier, } - .authorized_init(nsk), + .authorized_init(nsk, commitment_root), InputAccountIdentity::PrivateAuthorizedUpdate { epk, view_tag, @@ -306,6 +312,7 @@ pub fn compute_circuit_output( npk, ssk, identifier, + commitment_root, } => PrivateOutputHandler { output: &mut output, output_index: &mut output_index, @@ -316,13 +323,14 @@ pub fn compute_circuit_output( ssk, identifier: *identifier, } - .unauthorized(npk), + .unauthorized(npk, commitment_root), InputAccountIdentity::PrivatePdaInit { epk, view_tag, npk: _, ssk, identifier, + commitment_root, seed: _, } => PrivateOutputHandler { output: &mut output, @@ -334,7 +342,7 @@ pub fn compute_circuit_output( ssk, identifier: *identifier, } - .pda_init(pos, &pda_seed_by_position), + .pda_init(commitment_root, pos, &pda_seed_by_position), InputAccountIdentity::PrivatePdaUpdate { epk, view_tag, diff --git a/lee/state_machine/core/src/circuit_io.rs b/lee/state_machine/core/src/circuit_io.rs index 78bfa24f..88b214d4 100644 --- a/lee/state_machine/core/src/circuit_io.rs +++ b/lee/state_machine/core/src/circuit_io.rs @@ -38,6 +38,7 @@ pub enum InputAccountIdentity { ssk: SharedSecretKey, nsk: NullifierSecretKey, identifier: Identifier, + commitment_root: CommitmentSetDigest, }, /// Update of an authorized standalone private account: existing on-chain commitment, with /// membership proof. @@ -57,6 +58,7 @@ pub enum InputAccountIdentity { npk: NullifierPublicKey, ssk: SharedSecretKey, identifier: Identifier, + commitment_root: CommitmentSetDigest, }, /// Init of a private PDA, unauthorized. The npk-to-account_id binding is proven upstream /// via `Claim::Pda(seed)` or a caller's `pda_seeds` match. The identifier diversifies the @@ -68,6 +70,7 @@ pub enum InputAccountIdentity { npk: NullifierPublicKey, ssk: SharedSecretKey, identifier: Identifier, + commitment_root: CommitmentSetDigest, /// When `Some((seed, authority_program_id))`, the circuit binds this position via the /// external derivation check /// `AccountId::for_private_pda(authority_program_id, seed, npk, identifier) == diff --git a/lee/state_machine/src/privacy_preserving_transaction/circuit.rs b/lee/state_machine/src/privacy_preserving_transaction/circuit.rs index 489ee373..e7d8f8d4 100644 --- a/lee/state_machine/src/privacy_preserving_transaction/circuit.rs +++ b/lee/state_machine/src/privacy_preserving_transaction/circuit.rs @@ -273,6 +273,7 @@ mod tests { npk: recipient_keys.npk(), ssk: shared_secret, identifier: 0, + commitment_root: DUMMY_COMMITMENT_HASH, }, ], &crate::test_methods::simple_balance_transfer().into(), @@ -387,6 +388,7 @@ mod tests { npk: recipient_keys.npk(), ssk: shared_secret_2, identifier: 0, + commitment_root: DUMMY_COMMITMENT_HASH, }, ], &program.into(), @@ -460,6 +462,7 @@ mod tests { npk: account_keys.npk(), ssk: shared_secret, identifier: 0, + commitment_root: DUMMY_COMMITMENT_HASH, }], &program_with_deps, ); @@ -491,6 +494,7 @@ mod tests { npk, ssk: shared_secret, identifier, + commitment_root: DUMMY_COMMITMENT_HASH, seed: None, }], &program.clone().into(), @@ -540,6 +544,7 @@ mod tests { npk, ssk: shared_secret_pda, identifier: 0, + commitment_root: DUMMY_COMMITMENT_HASH, seed: None, }], &program_with_deps, @@ -595,6 +600,7 @@ mod tests { npk, ssk: shared_secret_pda, identifier: 0, + commitment_root: DUMMY_COMMITMENT_HASH, seed: None, }, InputAccountIdentity::Public, @@ -653,6 +659,7 @@ mod tests { npk: shared_npk, ssk: shared_secret, identifier: shared_identifier, + commitment_root: DUMMY_COMMITMENT_HASH, }, ], &program.into(), @@ -683,6 +690,7 @@ mod tests { ssk, nsk: keys.nsk, identifier, + commitment_root: DUMMY_COMMITMENT_HASH, }], &program.into(), ) @@ -714,6 +722,7 @@ mod tests { npk: keys.npk(), ssk, identifier, + commitment_root: DUMMY_COMMITMENT_HASH, }], &program.into(), ) @@ -848,6 +857,7 @@ mod tests { npk, ssk: shared_secret, identifier: 99, + commitment_root: DUMMY_COMMITMENT_HASH, seed: None, }], &program.into(), diff --git a/lee/state_machine/src/state.rs b/lee/state_machine/src/state.rs index c399cea1..b8116833 100644 --- a/lee/state_machine/src/state.rs +++ b/lee/state_machine/src/state.rs @@ -2,8 +2,7 @@ use std::collections::{BTreeSet, HashMap, HashSet}; use borsh::{BorshDeserialize, BorshSerialize}; use lee_core::{ - BlockId, Commitment, CommitmentSetDigest, DUMMY_COMMITMENT, MembershipProof, Nullifier, - Timestamp, + BlockId, Commitment, CommitmentSetDigest, DUMMY_COMMITMENT, MembershipProof, Nullifier, Timestamp, account::{Account, AccountId}, program::ProgramId, }; @@ -327,8 +326,8 @@ pub mod tests { use std::collections::HashMap; use lee_core::{ - BlockId, Commitment, EncryptedAccountData, InputAccountIdentity, Nullifier, - NullifierPublicKey, NullifierSecretKey, SharedSecretKey, Timestamp, + BlockId, Commitment, DUMMY_COMMITMENT_HASH, EncryptedAccountData, InputAccountIdentity, + Nullifier, NullifierPublicKey, NullifierSecretKey, SharedSecretKey, Timestamp, account::{Account, AccountId, AccountWithMetadata, Nonce, data::Data}, encryption::{EphemeralPublicKey, ViewingPublicKey}, program::{ @@ -1192,6 +1191,7 @@ pub mod tests { npk: recipient_keys.npk(), ssk: shared_secret, identifier: 0, + commitment_root: DUMMY_COMMITMENT_HASH, }, ], &crate::test_methods::simple_balance_transfer().into(), @@ -1259,6 +1259,7 @@ pub mod tests { npk: recipient_keys.npk(), ssk: shared_secret_2, identifier: 0, + commitment_root: DUMMY_COMMITMENT_HASH, }, ], &program.into(), @@ -1908,6 +1909,7 @@ pub mod tests { 0, ) .0, + commitment_root: DUMMY_COMMITMENT_HASH, identifier: 0, }, ], @@ -1974,6 +1976,7 @@ pub mod tests { 0, ) .0, + commitment_root: DUMMY_COMMITMENT_HASH, identifier: 0, }, ], @@ -2040,6 +2043,7 @@ pub mod tests { 0, ) .0, + commitment_root: DUMMY_COMMITMENT_HASH, identifier: 0, }, ], @@ -2106,6 +2110,7 @@ pub mod tests { 0, ) .0, + commitment_root: DUMMY_COMMITMENT_HASH, identifier: 0, }, ], @@ -2172,6 +2177,7 @@ pub mod tests { 0, ) .0, + commitment_root: DUMMY_COMMITMENT_HASH, identifier: 0, }, ], @@ -2236,6 +2242,7 @@ pub mod tests { 0, ) .0, + commitment_root: DUMMY_COMMITMENT_HASH, identifier: 0, }, ], @@ -2279,6 +2286,7 @@ pub mod tests { npk, ssk: shared_secret, identifier: u128::MAX, + commitment_root: DUMMY_COMMITMENT_HASH, seed: None, }, ], @@ -2314,6 +2322,7 @@ pub mod tests { npk, ssk: shared_secret, identifier: u128::MAX, + commitment_root: DUMMY_COMMITMENT_HASH, seed: None, }], &program.into(), @@ -2357,6 +2366,7 @@ pub mod tests { npk: npk_b, ssk: shared_secret, identifier: u128::MAX, + commitment_root: DUMMY_COMMITMENT_HASH, seed: None, }], &program.into(), @@ -2396,6 +2406,7 @@ pub mod tests { npk, ssk: shared_secret, identifier: u128::MAX, + commitment_root: DUMMY_COMMITMENT_HASH, seed: None, }], &program_with_deps, @@ -2438,6 +2449,7 @@ pub mod tests { npk, ssk: shared_secret, identifier: u128::MAX, + commitment_root: DUMMY_COMMITMENT_HASH, seed: None, }], &program_with_deps, @@ -2479,6 +2491,7 @@ pub mod tests { npk: keys_a.npk(), ssk: shared_a, identifier: u128::MAX, + commitment_root: DUMMY_COMMITMENT_HASH, seed: None, }, InputAccountIdentity::PrivatePdaInit { @@ -2487,6 +2500,7 @@ pub mod tests { npk: keys_b.npk(), ssk: shared_b, identifier: u128::MAX, + commitment_root: DUMMY_COMMITMENT_HASH, seed: None, }, ], @@ -2531,6 +2545,7 @@ pub mod tests { npk, ssk: shared_secret, identifier: u128::MAX, + commitment_root: DUMMY_COMMITMENT_HASH, seed: None, }], &program.into(), @@ -3302,6 +3317,7 @@ pub mod tests { ssk: shared_secret, nsk: private_keys.nsk, identifier: 0, + commitment_root: DUMMY_COMMITMENT_HASH, }], &program.into(), ) @@ -3349,6 +3365,7 @@ pub mod tests { npk: private_keys.npk(), ssk: shared_secret, identifier: 0, + commitment_root: DUMMY_COMMITMENT_HASH, }], &program.into(), ) @@ -3400,6 +3417,7 @@ pub mod tests { ssk: shared_secret, nsk: private_keys.nsk, identifier: 0, + commitment_root: DUMMY_COMMITMENT_HASH, }], &claimer_program.into(), ) @@ -3446,6 +3464,7 @@ pub mod tests { ssk: shared_secret2, nsk: private_keys.nsk, identifier: 0, + commitment_root: DUMMY_COMMITMENT_HASH, }], &noop_program.into(), ); @@ -3788,6 +3807,7 @@ pub mod tests { npk: account_keys.npk(), ssk: shared_secret, identifier: 0, + commitment_root: DUMMY_COMMITMENT_HASH, }], &validity_window_program.into(), ) @@ -3856,6 +3876,7 @@ pub mod tests { npk: account_keys.npk(), ssk: shared_secret, identifier: 0, + commitment_root: DUMMY_COMMITMENT_HASH, }], &validity_window_program.into(), ) @@ -4200,6 +4221,7 @@ pub mod tests { npk: alice_npk, ssk: alice_shared_0, identifier: 0, + commitment_root: DUMMY_COMMITMENT_HASH, seed: Some((seed, proxy_id)), }, ], @@ -4240,6 +4262,7 @@ pub mod tests { npk: alice_npk, ssk: alice_shared_1, identifier: 1, + commitment_root: DUMMY_COMMITMENT_HASH, seed: Some((seed, proxy_id)), }, ], diff --git a/lez/wallet/src/account_manager.rs b/lez/wallet/src/account_manager.rs index ce9d1833..ae4e3945 100644 --- a/lez/wallet/src/account_manager.rs +++ b/lez/wallet/src/account_manager.rs @@ -5,8 +5,8 @@ use key_protocol::key_management::ephemeral_key_holder::EphemeralKeyHolder; use keycard_wallet::{KeycardWallet, python_path}; use lee::{AccountId, PrivateKey, PublicKey, Signature}; use lee_core::{ - Identifier, InputAccountIdentity, MembershipProof, NullifierPublicKey, NullifierSecretKey, - SharedSecretKey, + CommitmentSetDigest, DUMMY_COMMITMENT_HASH, Identifier, InputAccountIdentity, MembershipProof, + NullifierPublicKey, NullifierSecretKey, SharedSecretKey, account::{AccountWithMetadata, Nonce}, encryption::{EncryptedAccountData, EphemeralPublicKey, ViewingPublicKey}, }; @@ -187,6 +187,7 @@ enum State { pub struct AccountManager { states: Vec, pin: Option, + dummy_commitment_root: CommitmentSetDigest, } impl AccountManager { @@ -340,7 +341,24 @@ impl AccountManager { states.push(state); } - Ok(Self { states, pin }) + let has_init_account = states + .iter() + .any(|s| matches!(s, State::Private(pre) if pre.proof.is_none())); + let dummy_commitment_root = if has_init_account { + wallet + .get_commitment_root() + .await + .map_err(ExecutionFailureKind::SequencerError)? + .unwrap_or(DUMMY_COMMITMENT_HASH) + } else { + DUMMY_COMMITMENT_HASH + }; + + Ok(Self { + states, + pin, + dummy_commitment_root, + }) } pub fn pre_states(&self) -> Vec { @@ -404,6 +422,7 @@ impl AccountManager { npk: pre.npk, ssk: pre.ssk, identifier: pre.identifier, + commitment_root: self.dummy_commitment_root, seed: None, }, }, @@ -424,6 +443,7 @@ impl AccountManager { ssk: pre.ssk, nsk, identifier: pre.identifier, + commitment_root: self.dummy_commitment_root, }, (None, _) => InputAccountIdentity::PrivateUnauthorized { epk: pre.epk.clone(), @@ -431,6 +451,7 @@ impl AccountManager { npk: pre.npk, ssk: pre.ssk, identifier: pre.identifier, + commitment_root: self.dummy_commitment_root, }, }, }) diff --git a/lez/wallet/src/lib.rs b/lez/wallet/src/lib.rs index 80b42e17..27023a3e 100644 --- a/lez/wallet/src/lib.rs +++ b/lez/wallet/src/lib.rs @@ -22,7 +22,8 @@ use lee::{ }, }; use lee_core::{ - Commitment, MembershipProof, SharedSecretKey, account::Nonce, program::InstructionData, + Commitment, CommitmentSetDigest, DUMMY_COMMITMENT, MembershipProof, SharedSecretKey, + account::Nonce, compute_digest_for_path, program::InstructionData, }; use log::info; use sequencer_service_rpc::{RpcClient as _, SequencerClient, SequencerClientBuilder}; @@ -508,6 +509,14 @@ impl WalletCore { } } + pub async fn get_commitment_root(&self) -> Result> { + let proof = self + .sequencer_client + .get_proof_for_commitment(DUMMY_COMMITMENT) + .await?; + Ok(proof.map(|p| compute_digest_for_path(&DUMMY_COMMITMENT, &p))) + } + pub fn decode_insert_privacy_preserving_transaction_results( &mut self, tx: &lee::privacy_preserving_transaction::PrivacyPreservingTransaction,