fix: private account preparation unified

This commit is contained in:
Oleksandr Pravdyvyi 2025-10-21 15:15:41 +03:00
parent 5b7e162e4d
commit a01bfe3688
No known key found for this signature in database
GPG Key ID: 9F8955C63C443871
2 changed files with 148 additions and 153 deletions

View File

@ -3,7 +3,9 @@ use key_protocol::key_management::ephemeral_key_holder::EphemeralKeyHolder;
use nssa::{Address, privacy_preserving_transaction::circuit}; use nssa::{Address, privacy_preserving_transaction::circuit};
use nssa_core::{MembershipProof, SharedSecretKey, account::AccountWithMetadata}; use nssa_core::{MembershipProof, SharedSecretKey, account::AccountWithMetadata};
use crate::{WalletCore, helperfunctions::produce_random_nonces}; use crate::{
WalletCore, helperfunctions::produce_random_nonces, transaction_utils::AccountPreparedData,
};
impl WalletCore { impl WalletCore {
pub async fn claim_pinata( pub async fn claim_pinata(
@ -31,24 +33,21 @@ impl WalletCore {
solution: u128, solution: u128,
winner_proof: MembershipProof, winner_proof: MembershipProof,
) -> Result<(SendTxResponse, [SharedSecretKey; 1]), ExecutionFailureKind> { ) -> Result<(SendTxResponse, [SharedSecretKey; 1]), ExecutionFailureKind> {
let Some((winner_keys, winner_acc)) = self let AccountPreparedData {
.storage nsk: winner_nsk,
.user_data npk: winner_npk,
.get_private_account(&winner_addr) ipk: winner_ipk,
.cloned() auth_acc: winner_pre,
else { proof: _,
return Err(ExecutionFailureKind::KeyNotFoundError); } = self
}; .private_acc_preparation(winner_addr, true, false)
.await?;
let pinata_acc = self.get_account_public(pinata_addr).await.unwrap(); let pinata_acc = self.get_account_public(pinata_addr).await.unwrap();
let winner_npk = winner_keys.nullifer_public_key;
let winner_ipk = winner_keys.incoming_viewing_public_key;
let program = nssa::program::Program::pinata(); let program = nssa::program::Program::pinata();
let pinata_pre = AccountWithMetadata::new(pinata_acc.clone(), false, pinata_addr); let pinata_pre = AccountWithMetadata::new(pinata_acc.clone(), false, pinata_addr);
let winner_pre = AccountWithMetadata::new(winner_acc.clone(), true, &winner_npk);
let eph_holder_winner = EphemeralKeyHolder::new(&winner_npk); let eph_holder_winner = EphemeralKeyHolder::new(&winner_npk);
let shared_secret_winner = eph_holder_winner.calculate_shared_secret_sender(&winner_ipk); let shared_secret_winner = eph_holder_winner.calculate_shared_secret_sender(&winner_ipk);
@ -59,10 +58,7 @@ impl WalletCore {
&[0, 1], &[0, 1],
&produce_random_nonces(1), &produce_random_nonces(1),
&[(winner_npk.clone(), shared_secret_winner.clone())], &[(winner_npk.clone(), shared_secret_winner.clone())],
&[( &[(winner_nsk.unwrap(), winner_proof)],
winner_keys.private_key_holder.nullifier_secret_key,
winner_proof,
)],
&program, &program,
) )
.unwrap(); .unwrap();
@ -103,24 +99,21 @@ impl WalletCore {
winner_addr: Address, winner_addr: Address,
solution: u128, solution: u128,
) -> Result<(SendTxResponse, [SharedSecretKey; 1]), ExecutionFailureKind> { ) -> Result<(SendTxResponse, [SharedSecretKey; 1]), ExecutionFailureKind> {
let Some((winner_keys, winner_acc)) = self let AccountPreparedData {
.storage nsk: _,
.user_data npk: winner_npk,
.get_private_account(&winner_addr) ipk: winner_ipk,
.cloned() auth_acc: winner_pre,
else { proof: _,
return Err(ExecutionFailureKind::KeyNotFoundError); } = self
}; .private_acc_preparation(winner_addr, false, false)
.await?;
let pinata_acc = self.get_account_public(pinata_addr).await.unwrap(); let pinata_acc = self.get_account_public(pinata_addr).await.unwrap();
let winner_npk = winner_keys.nullifer_public_key;
let winner_ipk = winner_keys.incoming_viewing_public_key;
let program = nssa::program::Program::pinata(); let program = nssa::program::Program::pinata();
let pinata_pre = AccountWithMetadata::new(pinata_acc.clone(), false, pinata_addr); let pinata_pre = AccountWithMetadata::new(pinata_acc.clone(), false, pinata_addr);
let winner_pre = AccountWithMetadata::new(winner_acc.clone(), false, &winner_npk);
let eph_holder_winner = EphemeralKeyHolder::new(&winner_npk); let eph_holder_winner = EphemeralKeyHolder::new(&winner_npk);
let shared_secret_winner = eph_holder_winner.calculate_shared_secret_sender(&winner_ipk); let shared_secret_winner = eph_holder_winner.calculate_shared_secret_sender(&winner_ipk);

View File

@ -6,13 +6,64 @@ use nssa::{
program::Program, program::Program,
}; };
use nssa_core::{ use nssa_core::{
Commitment, MembershipProof, NullifierPublicKey, SharedSecretKey, account::AccountWithMetadata, Commitment, MembershipProof, NullifierPublicKey, NullifierSecretKey, SharedSecretKey,
encryption::IncomingViewingPublicKey, program::InstructionData, account::AccountWithMetadata, encryption::IncomingViewingPublicKey, program::InstructionData,
}; };
use crate::{WalletCore, helperfunctions::produce_random_nonces}; use crate::{WalletCore, helperfunctions::produce_random_nonces};
pub(crate) struct AccountPreparedData {
pub nsk: Option<NullifierSecretKey>,
pub npk: NullifierPublicKey,
pub ipk: IncomingViewingPublicKey,
pub auth_acc: AccountWithMetadata,
pub proof: Option<MembershipProof>,
}
impl WalletCore { impl WalletCore {
pub(crate) async fn private_acc_preparation(
&self,
addr: Address,
is_authorized: bool,
needs_proof: bool,
) -> Result<AccountPreparedData, ExecutionFailureKind> {
let Some((from_keys, from_acc)) =
self.storage.user_data.get_private_account(&addr).cloned()
else {
return Err(ExecutionFailureKind::KeyNotFoundError);
};
let mut nsk = None;
let mut proof = None;
let from_npk = from_keys.nullifer_public_key;
let from_ipk = from_keys.incoming_viewing_public_key;
let sender_commitment = Commitment::new(&from_npk, &from_acc);
let sender_pre = AccountWithMetadata::new(from_acc.clone(), is_authorized, &from_npk);
if is_authorized {
nsk = Some(from_keys.private_key_holder.nullifier_secret_key);
}
if needs_proof {
proof = self
.sequencer_client
.get_proof_for_commitment(sender_commitment)
.await
.unwrap();
}
Ok(AccountPreparedData {
nsk,
npk: from_npk,
ipk: from_ipk,
auth_acc: sender_pre,
proof,
})
}
pub(crate) async fn private_tx_two_accs_all_init( pub(crate) async fn private_tx_two_accs_all_init(
&self, &self,
from: Address, from: Address,
@ -22,28 +73,23 @@ impl WalletCore {
program: Program, program: Program,
to_proof: MembershipProof, to_proof: MembershipProof,
) -> Result<(SendTxResponse, [SharedSecretKey; 2]), ExecutionFailureKind> { ) -> Result<(SendTxResponse, [SharedSecretKey; 2]), ExecutionFailureKind> {
let Some((from_keys, from_acc)) = let AccountPreparedData {
self.storage.user_data.get_private_account(&from).cloned() nsk: from_nsk,
else { npk: from_npk,
return Err(ExecutionFailureKind::KeyNotFoundError); ipk: from_ipk,
}; auth_acc: sender_pre,
proof: from_proof,
} = self.private_acc_preparation(from, true, true).await?;
let Some((to_keys, to_acc)) = self.storage.user_data.get_private_account(&to).cloned() let AccountPreparedData {
else { nsk: to_nsk,
return Err(ExecutionFailureKind::KeyNotFoundError); npk: to_npk,
}; ipk: to_ipk,
auth_acc: recipient_pre,
proof: _,
} = self.private_acc_preparation(to, true, false).await?;
tx_pre_check(&from_acc, &to_acc)?; tx_pre_check(&sender_pre.account, &recipient_pre.account)?;
let from_npk = from_keys.nullifer_public_key;
let from_ipk = from_keys.incoming_viewing_public_key;
let to_npk = to_keys.nullifer_public_key.clone();
let to_ipk = to_keys.incoming_viewing_public_key.clone();
let sender_commitment = Commitment::new(&from_npk, &from_acc);
let sender_pre = AccountWithMetadata::new(from_acc.clone(), true, &from_npk);
let recipient_pre = AccountWithMetadata::new(to_acc.clone(), true, &to_npk);
let eph_holder_from = EphemeralKeyHolder::new(&from_npk); let eph_holder_from = EphemeralKeyHolder::new(&from_npk);
let shared_secret_from = eph_holder_from.calculate_shared_secret_sender(&from_ipk); let shared_secret_from = eph_holder_from.calculate_shared_secret_sender(&from_ipk);
@ -61,15 +107,8 @@ impl WalletCore {
(to_npk.clone(), shared_secret_to.clone()), (to_npk.clone(), shared_secret_to.clone()),
], ],
&[ &[
( (from_nsk.unwrap(), from_proof.unwrap()),
from_keys.private_key_holder.nullifier_secret_key, (to_nsk.unwrap(), to_proof),
self.sequencer_client
.get_proof_for_commitment(sender_commitment)
.await
.unwrap()
.unwrap(),
),
(to_keys.private_key_holder.nullifier_secret_key, to_proof),
], ],
&program, &program,
) )
@ -111,28 +150,23 @@ impl WalletCore {
tx_pre_check: impl FnOnce(&Account, &Account) -> Result<(), ExecutionFailureKind>, tx_pre_check: impl FnOnce(&Account, &Account) -> Result<(), ExecutionFailureKind>,
program: Program, program: Program,
) -> Result<(SendTxResponse, [SharedSecretKey; 2]), ExecutionFailureKind> { ) -> Result<(SendTxResponse, [SharedSecretKey; 2]), ExecutionFailureKind> {
let Some((from_keys, from_acc)) = let AccountPreparedData {
self.storage.user_data.get_private_account(&from).cloned() nsk: from_nsk,
else { npk: from_npk,
return Err(ExecutionFailureKind::KeyNotFoundError); ipk: from_ipk,
}; auth_acc: sender_pre,
proof: from_proof,
} = self.private_acc_preparation(from, true, true).await?;
let Some((to_keys, to_acc)) = self.storage.user_data.get_private_account(&to).cloned() let AccountPreparedData {
else { nsk: _,
return Err(ExecutionFailureKind::KeyNotFoundError); npk: to_npk,
}; ipk: to_ipk,
auth_acc: recipient_pre,
proof: _,
} = self.private_acc_preparation(to, false, false).await?;
tx_pre_check(&from_acc, &to_acc)?; tx_pre_check(&sender_pre.account, &recipient_pre.account)?;
let from_npk = from_keys.nullifer_public_key;
let from_ipk = from_keys.incoming_viewing_public_key;
let to_npk = to_keys.nullifer_public_key.clone();
let to_ipk = to_keys.incoming_viewing_public_key.clone();
let sender_commitment = Commitment::new(&from_npk, &from_acc);
let sender_pre = AccountWithMetadata::new(from_acc.clone(), true, &from_npk);
let recipient_pre = AccountWithMetadata::new(to_acc.clone(), false, &to_npk);
let eph_holder_from = EphemeralKeyHolder::new(&from_npk); let eph_holder_from = EphemeralKeyHolder::new(&from_npk);
let shared_secret_from = eph_holder_from.calculate_shared_secret_sender(&from_ipk); let shared_secret_from = eph_holder_from.calculate_shared_secret_sender(&from_ipk);
@ -149,14 +183,7 @@ impl WalletCore {
(from_npk.clone(), shared_secret_from.clone()), (from_npk.clone(), shared_secret_from.clone()),
(to_npk.clone(), shared_secret_to.clone()), (to_npk.clone(), shared_secret_to.clone()),
], ],
&[( &[(from_nsk.unwrap(), from_proof.unwrap())],
from_keys.private_key_holder.nullifier_secret_key,
self.sequencer_client
.get_proof_for_commitment(sender_commitment)
.await
.unwrap()
.unwrap(),
)],
&program, &program,
) )
.unwrap(); .unwrap();
@ -198,22 +225,17 @@ impl WalletCore {
tx_pre_check: impl FnOnce(&Account, &Account) -> Result<(), ExecutionFailureKind>, tx_pre_check: impl FnOnce(&Account, &Account) -> Result<(), ExecutionFailureKind>,
program: Program, program: Program,
) -> Result<(SendTxResponse, [SharedSecretKey; 2]), ExecutionFailureKind> { ) -> Result<(SendTxResponse, [SharedSecretKey; 2]), ExecutionFailureKind> {
let Some((from_keys, from_acc)) = let AccountPreparedData {
self.storage.user_data.get_private_account(&from).cloned() nsk: from_nsk,
else { npk: from_npk,
return Err(ExecutionFailureKind::KeyNotFoundError); ipk: from_ipk,
}; auth_acc: sender_pre,
proof: from_proof,
} = self.private_acc_preparation(from, true, true).await?;
let to_acc = nssa_core::account::Account::default(); let to_acc = nssa_core::account::Account::default();
tx_pre_check(&from_acc, &to_acc)?; tx_pre_check(&sender_pre.account, &to_acc)?;
let from_npk = from_keys.nullifer_public_key;
let from_ipk = from_keys.incoming_viewing_public_key;
let sender_commitment = Commitment::new(&from_npk, &from_acc);
let sender_pre = AccountWithMetadata::new(from_acc.clone(), true, &from_npk);
let recipient_pre = AccountWithMetadata::new(to_acc.clone(), false, &to_npk); let recipient_pre = AccountWithMetadata::new(to_acc.clone(), false, &to_npk);
@ -231,14 +253,7 @@ impl WalletCore {
(from_npk.clone(), shared_secret_from.clone()), (from_npk.clone(), shared_secret_from.clone()),
(to_npk.clone(), shared_secret_to.clone()), (to_npk.clone(), shared_secret_to.clone()),
], ],
&[( &[(from_nsk.unwrap(), from_proof.unwrap())],
from_keys.private_key_holder.nullifier_secret_key,
self.sequencer_client
.get_proof_for_commitment(sender_commitment)
.await
.unwrap()
.unwrap(),
)],
&program, &program,
) )
.unwrap(); .unwrap();
@ -280,43 +295,32 @@ impl WalletCore {
tx_pre_check: impl FnOnce(&Account, &Account) -> Result<(), ExecutionFailureKind>, tx_pre_check: impl FnOnce(&Account, &Account) -> Result<(), ExecutionFailureKind>,
program: Program, program: Program,
) -> Result<(SendTxResponse, [nssa_core::SharedSecretKey; 1]), ExecutionFailureKind> { ) -> Result<(SendTxResponse, [nssa_core::SharedSecretKey; 1]), ExecutionFailureKind> {
let Some((from_keys, from_acc)) = let AccountPreparedData {
self.storage.user_data.get_private_account(&from).cloned() nsk: from_nsk,
else { npk: from_npk,
return Err(ExecutionFailureKind::KeyNotFoundError); ipk: from_ipk,
}; auth_acc: sender_pre,
proof: from_proof,
} = self.private_acc_preparation(from, true, true).await?;
let Ok(to_acc) = self.get_account_public(to).await else { let Ok(to_acc) = self.get_account_public(to).await else {
return Err(ExecutionFailureKind::KeyNotFoundError); return Err(ExecutionFailureKind::KeyNotFoundError);
}; };
tx_pre_check(&from_acc, &to_acc)?; tx_pre_check(&sender_pre.account, &to_acc)?;
let npk_from = from_keys.nullifer_public_key;
let ipk_from = from_keys.incoming_viewing_public_key;
let sender_commitment = Commitment::new(&npk_from, &from_acc);
let sender_pre = AccountWithMetadata::new(from_acc.clone(), true, &npk_from);
let recipient_pre = AccountWithMetadata::new(to_acc.clone(), false, to); let recipient_pre = AccountWithMetadata::new(to_acc.clone(), false, to);
let eph_holder = EphemeralKeyHolder::new(&npk_from); let eph_holder = EphemeralKeyHolder::new(&from_npk);
let shared_secret = eph_holder.calculate_shared_secret_sender(&ipk_from); let shared_secret = eph_holder.calculate_shared_secret_sender(&from_ipk);
let (output, proof) = circuit::execute_and_prove( let (output, proof) = circuit::execute_and_prove(
&[sender_pre, recipient_pre], &[sender_pre, recipient_pre],
&instruction_data, &instruction_data,
&[1, 0], &[1, 0],
&produce_random_nonces(1), &produce_random_nonces(1),
&[(npk_from.clone(), shared_secret.clone())], &[(from_npk.clone(), shared_secret.clone())],
&[( &[(from_nsk.unwrap(), from_proof.unwrap())],
from_keys.private_key_holder.nullifier_secret_key,
self.sequencer_client
.get_proof_for_commitment(sender_commitment)
.await
.unwrap()
.unwrap(),
)],
&program, &program,
) )
.unwrap(); .unwrap();
@ -325,8 +329,8 @@ impl WalletCore {
vec![to], vec![to],
vec![], vec![],
vec![( vec![(
npk_from.clone(), from_npk.clone(),
ipk_from.clone(), from_ipk.clone(),
eph_holder.generate_ephemeral_public_key(), eph_holder.generate_ephemeral_public_key(),
)], )],
output, output,
@ -356,18 +360,17 @@ impl WalletCore {
return Err(ExecutionFailureKind::KeyNotFoundError); return Err(ExecutionFailureKind::KeyNotFoundError);
}; };
let Some((to_keys, to_acc)) = self.storage.user_data.get_private_account(&to).cloned() let AccountPreparedData {
else { nsk: to_nsk,
return Err(ExecutionFailureKind::KeyNotFoundError); npk: to_npk,
}; ipk: to_ipk,
auth_acc: recipient_pre,
proof: _,
} = self.private_acc_preparation(to, true, false).await?;
let to_npk = to_keys.nullifer_public_key.clone(); tx_pre_check(&from_acc, &recipient_pre.account)?;
let to_ipk = to_keys.incoming_viewing_public_key.clone();
tx_pre_check(&from_acc, &to_acc)?;
let sender_pre = AccountWithMetadata::new(from_acc.clone(), true, from); let sender_pre = AccountWithMetadata::new(from_acc.clone(), true, from);
let recipient_pre = AccountWithMetadata::new(to_acc.clone(), true, &to_npk);
let eph_holder = EphemeralKeyHolder::new(&to_npk); let eph_holder = EphemeralKeyHolder::new(&to_npk);
let shared_secret = eph_holder.calculate_shared_secret_sender(&to_ipk); let shared_secret = eph_holder.calculate_shared_secret_sender(&to_ipk);
@ -378,7 +381,7 @@ impl WalletCore {
&[0, 1], &[0, 1],
&produce_random_nonces(1), &produce_random_nonces(1),
&[(to_npk.clone(), shared_secret.clone())], &[(to_npk.clone(), shared_secret.clone())],
&[(to_keys.private_key_holder.nullifier_secret_key, to_proof)], &[(to_nsk.unwrap(), to_proof)],
&program, &program,
) )
.unwrap(); .unwrap();
@ -423,18 +426,17 @@ impl WalletCore {
return Err(ExecutionFailureKind::KeyNotFoundError); return Err(ExecutionFailureKind::KeyNotFoundError);
}; };
let Some((to_keys, to_acc)) = self.storage.user_data.get_private_account(&to).cloned() let AccountPreparedData {
else { nsk: _,
return Err(ExecutionFailureKind::KeyNotFoundError); npk: to_npk,
}; ipk: to_ipk,
auth_acc: recipient_pre,
proof: _,
} = self.private_acc_preparation(to, false, false).await?;
let to_npk = to_keys.nullifer_public_key.clone(); tx_pre_check(&from_acc, &recipient_pre.account)?;
let to_ipk = to_keys.incoming_viewing_public_key.clone();
tx_pre_check(&from_acc, &to_acc)?;
let sender_pre = AccountWithMetadata::new(from_acc.clone(), true, from); let sender_pre = AccountWithMetadata::new(from_acc.clone(), true, from);
let recipient_pre = AccountWithMetadata::new(to_acc.clone(), false, &to_npk);
let eph_holder = EphemeralKeyHolder::new(&to_npk); let eph_holder = EphemeralKeyHolder::new(&to_npk);
let shared_secret = eph_holder.calculate_shared_secret_sender(&to_ipk); let shared_secret = eph_holder.calculate_shared_secret_sender(&to_ipk);