From 50d402880c34fd88ce97c264605549c80be2e34a Mon Sep 17 00:00:00 2001 From: Sergio Chouhy Date: Mon, 6 Apr 2026 16:25:53 -0300 Subject: [PATCH] add nullifiers for preconfigured accounts on genesis --- indexer/core/src/lib.rs | 17 ++++----- nssa/src/state.rs | 62 ++++++++++++++++++++++++++++---- sequencer/core/src/lib.rs | 36 ++++++++++--------- testnet_initial_state/src/lib.rs | 24 +++++++------ 4 files changed, 97 insertions(+), 42 deletions(-) diff --git a/indexer/core/src/lib.rs b/indexer/core/src/lib.rs index bcd99ad7..732dc922 100644 --- a/indexer/core/src/lib.rs +++ b/indexer/core/src/lib.rs @@ -57,11 +57,9 @@ impl IndexerCore { let channel_genesis_msg_id = [0; 32]; let genesis_block = hashable_data.into_pending_block(&signing_key, channel_genesis_msg_id); - let initial_commitments: Option> = config - .initial_private_accounts - .as_ref() - .map(|initial_commitments| { - initial_commitments + let initial_private_accounts: Option> = + config.initial_private_accounts.as_ref().map(|accounts| { + accounts .iter() .map(|init_comm_data| { let npk = &init_comm_data.npk; @@ -71,7 +69,10 @@ impl IndexerCore { acc.program_owner = nssa::program::Program::authenticated_transfer_program().id(); - nssa_core::Commitment::new(npk, &acc) + ( + nssa_core::Nullifier::for_account_initialization(npk), + nssa_core::Commitment::new(npk, &acc), + ) }) .collect() }); @@ -88,10 +89,10 @@ impl IndexerCore { // If initial commitments or accounts are present in config, need to construct state from // them - let state = if initial_commitments.is_some() || init_accs.is_some() { + let state = if initial_private_accounts.is_some() || init_accs.is_some() { let mut state = V03State::new_with_genesis_accounts( &init_accs.unwrap_or_default(), - &initial_commitments.unwrap_or_default(), + &initial_private_accounts.unwrap_or_default(), ); // ToDo: Remove after testnet diff --git a/nssa/src/state.rs b/nssa/src/state.rs index ec37884e..6c9445d5 100644 --- a/nssa/src/state.rs +++ b/nssa/src/state.rs @@ -118,7 +118,7 @@ impl V03State { #[must_use] pub fn new_with_genesis_accounts( initial_data: &[(AccountId, u128)], - initial_commitments: &[nssa_core::Commitment], + initial_private_accounts: &[(Nullifier, Commitment)], ) -> Self { let authenticated_transfer_program = Program::authenticated_transfer_program(); let public_state = initial_data @@ -134,13 +134,24 @@ impl V03State { }) .collect(); + let initial_commitments: Vec = initial_private_accounts + .iter() + .map(|(_, c)| c.clone()) + .collect(); let mut private_state = CommitmentSet::with_capacity(32); private_state.extend(&[DUMMY_COMMITMENT]); - private_state.extend(initial_commitments); + private_state.extend(&initial_commitments); + + let init_nullifiers: Vec = initial_private_accounts + .iter() + .map(|(n, _)| n.clone()) + .collect(); + let mut nullifier_set = NullifierSet::new(); + nullifier_set.extend(init_nullifiers); let mut this = Self { public_state, - private_state: (private_state, NullifierSet::new()), + private_state: (private_state, nullifier_set), programs: HashMap::new(), }; @@ -523,6 +534,34 @@ pub mod tests { assert_eq!(state.programs, expected_builtin_programs); } + #[test] + fn new_with_genesis_includes_nullifiers_for_private_accounts() { + let keys1 = test_private_account_keys_1(); + let keys2 = test_private_account_keys_2(); + + let account = Account { + balance: 100, + program_owner: Program::authenticated_transfer_program().id(), + ..Account::default() + }; + + let npk1 = keys1.npk(); + let npk2 = keys2.npk(); + + let init_nullifier1 = Nullifier::for_account_initialization(&npk1); + let init_nullifier2 = Nullifier::for_account_initialization(&npk2); + + let initial_private_accounts = vec![ + (init_nullifier1.clone(), Commitment::new(&npk1, &account)), + (init_nullifier2.clone(), Commitment::new(&npk2, &account)), + ]; + + let state = V03State::new_with_genesis_accounts(&[], &initial_private_accounts); + + assert!(state.private_state.1.contains(&init_nullifier1)); + assert!(state.private_state.1.contains(&init_nullifier2)); + } + #[test] fn insert_program() { let mut state = V03State::new_with_genesis_accounts(&[], &[]); @@ -2542,8 +2581,11 @@ pub mod tests { ..Account::default() }; let sender_commitment = Commitment::new(&sender_keys.npk(), &sender_private_account); - let mut state = - V03State::new_with_genesis_accounts(&[], std::slice::from_ref(&sender_commitment)); + let sender_init_nullifier = Nullifier::for_account_initialization(&sender_keys.npk()); + let mut state = V03State::new_with_genesis_accounts( + &[], + &[(sender_init_nullifier, sender_commitment.clone())], + ); let sender_pre = AccountWithMetadata::new(sender_private_account, true, &sender_keys.npk()); let recipient_private_key = PrivateKey::try_new([2; 32]).unwrap(); let recipient_account_id = @@ -2623,9 +2665,14 @@ pub mod tests { let from_commitment = Commitment::new(&from_keys.npk(), &from_account.account); let to_commitment = Commitment::new(&to_keys.npk(), &to_account.account); + let from_init_nullifier = Nullifier::for_account_initialization(&from_keys.npk()); + let to_init_nullifier = Nullifier::for_account_initialization(&to_keys.npk()); let mut state = V03State::new_with_genesis_accounts( &[], - &[from_commitment.clone(), to_commitment.clone()], + &[ + (from_init_nullifier, from_commitment.clone()), + (to_init_nullifier, to_commitment.clone()), + ], ) .with_test_programs(); let amount: u128 = 37; @@ -3192,9 +3239,10 @@ pub mod tests { let recipient_commitment = Commitment::new(&recipient_keys.npk(), &recipient_account.account); + let recipient_init_nullifier = Nullifier::for_account_initialization(&recipient_keys.npk()); let state = V03State::new_with_genesis_accounts( &[(sender_account.account_id, sender_account.account.balance)], - std::slice::from_ref(&recipient_commitment), + &[(recipient_init_nullifier, recipient_commitment.clone())], ) .with_test_programs(); diff --git a/sequencer/core/src/lib.rs b/sequencer/core/src/lib.rs index 16667051..418ff2d4 100644 --- a/sequencer/core/src/lib.rs +++ b/sequencer/core/src/lib.rs @@ -104,24 +104,26 @@ impl SequencerCore> = config - .initial_private_accounts - .clone() - .map(|initial_commitments| { - initial_commitments - .iter() - .map(|init_comm_data| { - let npk = &init_comm_data.npk; + let initial_private_accounts: Option< + Vec<(nssa_core::Nullifier, nssa_core::Commitment)>, + > = config.initial_private_accounts.clone().map(|accounts| { + accounts + .iter() + .map(|init_comm_data| { + let npk = &init_comm_data.npk; - let mut acc = init_comm_data.account.clone(); + let mut acc = init_comm_data.account.clone(); - acc.program_owner = - nssa::program::Program::authenticated_transfer_program().id(); + acc.program_owner = + nssa::program::Program::authenticated_transfer_program().id(); - nssa_core::Commitment::new(npk, &acc) - }) - .collect() - }); + ( + nssa_core::Nullifier::for_account_initialization(npk), + nssa_core::Commitment::new(npk, &acc), + ) + }) + .collect() + }); let init_accs: Option> = config .initial_public_accounts @@ -135,10 +137,10 @@ impl SequencerCore Vec { #[must_use] pub fn initial_state() -> V03State { - let initial_commitments: Vec = initial_commitments() - .iter() - .map(|init_comm_data| { - let npk = &init_comm_data.npk; + let initial_private_accounts: Vec<(nssa_core::Nullifier, nssa_core::Commitment)> = + initial_commitments() + .iter() + .map(|init_comm_data| { + let npk = &init_comm_data.npk; - let mut acc = init_comm_data.account.clone(); + let mut acc = init_comm_data.account.clone(); - acc.program_owner = nssa::program::Program::authenticated_transfer_program().id(); + acc.program_owner = nssa::program::Program::authenticated_transfer_program().id(); - nssa_core::Commitment::new(npk, &acc) - }) - .collect(); + ( + nssa_core::Nullifier::for_account_initialization(npk), + nssa_core::Commitment::new(npk, &acc), + ) + }) + .collect(); let init_accs: Vec<(nssa::AccountId, u128)> = initial_accounts() .iter() .map(|acc_data| (acc_data.account_id, acc_data.balance)) .collect(); - nssa::V03State::new_with_genesis_accounts(&init_accs, &initial_commitments) + nssa::V03State::new_with_genesis_accounts(&init_accs, &initial_private_accounts) } #[must_use]