mirror of
https://github.com/logos-blockchain/logos-execution-zone.git
synced 2026-05-12 19:19:30 +00:00
feat: extend sync to scan shared accounts with GMS-derived keys
This commit is contained in:
parent
cd545819e7
commit
d0a88e91e1
@ -22,11 +22,15 @@ pub struct UserPrivateAccountData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Metadata for a shared account (GMS-derived), stored alongside the cached plaintext state.
|
/// Metadata for a shared account (GMS-derived), stored alongside the cached plaintext state.
|
||||||
/// The group label and identifier are needed to re-derive keys during sync.
|
/// The group label and identifier (or PDA seed) are needed to re-derive keys during sync.
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
pub struct SharedAccountEntry {
|
pub struct SharedAccountEntry {
|
||||||
pub group_label: String,
|
pub group_label: String,
|
||||||
pub identifier: Identifier,
|
pub identifier: Identifier,
|
||||||
|
/// For PDA accounts, the seed used to derive keys via `derive_keys_for_pda`.
|
||||||
|
/// `None` for regular shared accounts (keys derived from identifier via tag).
|
||||||
|
#[serde(default)]
|
||||||
|
pub pda_seed: Option<nssa_core::program::PdaSeed>,
|
||||||
pub account: Account,
|
pub account: Account,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -220,6 +220,7 @@ impl WalletSubcommand for NewSubcommand {
|
|||||||
account_id,
|
account_id,
|
||||||
group_name.clone(),
|
group_name.clone(),
|
||||||
u128::MAX,
|
u128::MAX,
|
||||||
|
Some(pda_seed),
|
||||||
);
|
);
|
||||||
|
|
||||||
println!("PDA shared account from group '{group_name}'");
|
println!("PDA shared account from group '{group_name}'");
|
||||||
@ -259,6 +260,7 @@ impl WalletSubcommand for NewSubcommand {
|
|||||||
account_id,
|
account_id,
|
||||||
group_name.clone(),
|
group_name.clone(),
|
||||||
identifier,
|
identifier,
|
||||||
|
None,
|
||||||
);
|
);
|
||||||
|
|
||||||
println!("Shared account from group '{group_name}'");
|
println!("Shared account from group '{group_name}'");
|
||||||
|
|||||||
@ -310,6 +310,7 @@ impl WalletCore {
|
|||||||
account_id: AccountId,
|
account_id: AccountId,
|
||||||
group_label: String,
|
group_label: String,
|
||||||
identifier: nssa_core::Identifier,
|
identifier: nssa_core::Identifier,
|
||||||
|
pda_seed: Option<nssa_core::program::PdaSeed>,
|
||||||
) {
|
) {
|
||||||
use key_protocol::key_protocol_core::SharedAccountEntry;
|
use key_protocol::key_protocol_core::SharedAccountEntry;
|
||||||
self.storage.user_data.shared_accounts.insert(
|
self.storage.user_data.shared_accounts.insert(
|
||||||
@ -317,6 +318,7 @@ impl WalletCore {
|
|||||||
SharedAccountEntry {
|
SharedAccountEntry {
|
||||||
group_label,
|
group_label,
|
||||||
identifier,
|
identifier,
|
||||||
|
pda_seed,
|
||||||
account: Account::default(),
|
account: Account::default(),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@ -592,6 +594,77 @@ impl WalletCore {
|
|||||||
self.storage
|
self.storage
|
||||||
.insert_private_account_data(affected_account_id, identifier, new_acc);
|
.insert_private_account_data(affected_account_id, identifier, new_acc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Scan for updates to shared accounts (GMS-derived).
|
||||||
|
self.sync_shared_accounts_with_tx(&tx);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sync_shared_accounts_with_tx(&mut self, tx: &PrivacyPreservingTransaction) {
|
||||||
|
let shared_keys: Vec<_> = self
|
||||||
|
.storage
|
||||||
|
.user_data
|
||||||
|
.shared_accounts
|
||||||
|
.iter()
|
||||||
|
.filter_map(|(&account_id, entry)| {
|
||||||
|
let holder = self
|
||||||
|
.storage
|
||||||
|
.user_data
|
||||||
|
.group_key_holders
|
||||||
|
.get(&entry.group_label)?;
|
||||||
|
|
||||||
|
let keys = entry.pda_seed.as_ref().map_or_else(
|
||||||
|
|| {
|
||||||
|
let tag = {
|
||||||
|
use sha2::Digest as _;
|
||||||
|
let mut hasher = sha2::Sha256::new();
|
||||||
|
hasher.update(b"/LEE/v0.3/SharedAccountTag/\x00\x00\x00\x00\x00");
|
||||||
|
hasher.update(entry.identifier.to_le_bytes());
|
||||||
|
let result: [u8; 32] = hasher.finalize().into();
|
||||||
|
result
|
||||||
|
};
|
||||||
|
holder.derive_keys_for_shared_account(&tag)
|
||||||
|
},
|
||||||
|
|pda_seed| holder.derive_keys_for_pda(pda_seed),
|
||||||
|
);
|
||||||
|
let npk = keys.generate_nullifier_public_key();
|
||||||
|
let vpk = keys.generate_viewing_public_key();
|
||||||
|
let vsk = keys.viewing_secret_key;
|
||||||
|
Some((account_id, npk, vpk, vsk))
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
for (account_id, npk, vpk, vsk) in shared_keys {
|
||||||
|
let view_tag = EncryptedAccountData::compute_view_tag(&npk, &vpk);
|
||||||
|
|
||||||
|
for (ciph_id, encrypted_data) in tx
|
||||||
|
.message()
|
||||||
|
.encrypted_private_post_states
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
{
|
||||||
|
if encrypted_data.view_tag != view_tag {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let shared_secret = SharedSecretKey::new(&vsk, &encrypted_data.epk);
|
||||||
|
let commitment = &tx.message.new_commitments[ciph_id];
|
||||||
|
|
||||||
|
if let Some((_decrypted_identifier, new_acc)) = nssa_core::EncryptionScheme::decrypt(
|
||||||
|
&encrypted_data.ciphertext,
|
||||||
|
&shared_secret,
|
||||||
|
commitment,
|
||||||
|
ciph_id
|
||||||
|
.try_into()
|
||||||
|
.expect("Ciphertext ID is expected to fit in u32"),
|
||||||
|
) {
|
||||||
|
info!("Synced shared account {account_id:#?} with new state {new_acc:#?}");
|
||||||
|
if let Some(entry) = self.storage.user_data.shared_accounts.get_mut(&account_id)
|
||||||
|
{
|
||||||
|
entry.account = new_acc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user