mirror of
https://github.com/logos-blockchain/logos-execution-zone.git
synced 2026-06-29 18:39:30 +00:00
feat!: remove output index from the ciphertext encryption/decryption
BREAKING: Before: KDF for ChaCha ciphertext had the position index as an argument After: No such argument provided Mitigation: Remove the index when generating the decoding key
This commit is contained in:
parent
f1f76247da
commit
ed4329103e
@ -87,13 +87,12 @@ impl EncryptionScheme {
|
||||
kind: &PrivateAccountKind,
|
||||
shared_secret: &SharedSecretKey,
|
||||
commitment: &Commitment,
|
||||
output_index: u32,
|
||||
) -> Ciphertext {
|
||||
// Plaintext: PrivateAccountKind::HEADER_LEN bytes header || account bytes.
|
||||
// Both variants produce the same header length — see PrivateAccountKind::to_header_bytes.
|
||||
let mut buffer = kind.to_header_bytes().to_vec();
|
||||
buffer.extend_from_slice(&account.to_bytes());
|
||||
Self::symmetric_transform(&mut buffer, shared_secret, commitment, output_index);
|
||||
Self::symmetric_transform(&mut buffer, shared_secret, commitment);
|
||||
Ciphertext(buffer)
|
||||
}
|
||||
|
||||
@ -101,43 +100,32 @@ impl EncryptionScheme {
|
||||
buffer: &mut [u8],
|
||||
shared_secret: &SharedSecretKey,
|
||||
commitment: &Commitment,
|
||||
output_index: u32,
|
||||
) {
|
||||
let key = Self::kdf(shared_secret, commitment, output_index);
|
||||
let key = Self::kdf(shared_secret, commitment);
|
||||
let mut cipher = ChaCha20::new(&key.into(), &[0; 12].into());
|
||||
cipher.apply_keystream(buffer);
|
||||
}
|
||||
|
||||
fn kdf(
|
||||
shared_secret: &SharedSecretKey,
|
||||
commitment: &Commitment,
|
||||
output_index: u32,
|
||||
) -> [u8; 32] {
|
||||
fn kdf(shared_secret: &SharedSecretKey, commitment: &Commitment) -> [u8; 32] {
|
||||
let mut bytes = Vec::new();
|
||||
|
||||
bytes.extend_from_slice(b"LEE/v0.2/KDF-SHA256/");
|
||||
bytes.extend_from_slice(&shared_secret.0);
|
||||
bytes.extend_from_slice(&commitment.to_byte_array());
|
||||
bytes.extend_from_slice(&output_index.to_le_bytes());
|
||||
|
||||
Impl::hash_bytes(&bytes).as_bytes().try_into().unwrap()
|
||||
}
|
||||
|
||||
#[cfg(feature = "host")]
|
||||
#[expect(
|
||||
clippy::print_stdout,
|
||||
reason = "This is the current way to debug things. TODO: fix later"
|
||||
)]
|
||||
#[must_use]
|
||||
pub fn decrypt(
|
||||
ciphertext: &Ciphertext,
|
||||
shared_secret: &SharedSecretKey,
|
||||
commitment: &Commitment,
|
||||
output_index: u32,
|
||||
) -> Option<(PrivateAccountKind, Account)> {
|
||||
use std::io::Cursor;
|
||||
let mut buffer = ciphertext.0.clone();
|
||||
Self::symmetric_transform(&mut buffer, shared_secret, commitment, output_index);
|
||||
Self::symmetric_transform(&mut buffer, shared_secret, commitment);
|
||||
|
||||
if buffer.len() < PrivateAccountKind::HEADER_LEN {
|
||||
return None;
|
||||
@ -148,16 +136,6 @@ impl EncryptionScheme {
|
||||
|
||||
let mut cursor = Cursor::new(&buffer[PrivateAccountKind::HEADER_LEN..]);
|
||||
Account::from_cursor(&mut cursor)
|
||||
.inspect_err(|err| {
|
||||
println!(
|
||||
"Failed to decode {ciphertext:?} \n
|
||||
with secret {:?} ,\n
|
||||
commitment {commitment:?} ,\n
|
||||
and output_index {output_index} ,\n
|
||||
with error {err:?}",
|
||||
shared_secret.0
|
||||
);
|
||||
})
|
||||
.ok()
|
||||
.map(|account| (kind, account))
|
||||
}
|
||||
@ -182,7 +160,6 @@ mod tests {
|
||||
&PrivateAccountKind::Regular(42),
|
||||
&secret,
|
||||
&commitment,
|
||||
0,
|
||||
);
|
||||
let pda_ct = EncryptionScheme::encrypt(
|
||||
&account,
|
||||
@ -193,7 +170,6 @@ mod tests {
|
||||
},
|
||||
&secret,
|
||||
&commitment,
|
||||
0,
|
||||
);
|
||||
|
||||
assert_eq!(account_ct.0.len(), pda_ct.0.len());
|
||||
@ -219,9 +195,9 @@ mod tests {
|
||||
let kind = PrivateAccountKind::Regular(0);
|
||||
let commitment = crate::Commitment::new(&AccountId::new([7_u8; 32]), &account);
|
||||
|
||||
let ct = EncryptionScheme::encrypt(&account, &kind, &sender_ss, &commitment, 0);
|
||||
let ct = EncryptionScheme::encrypt(&account, &kind, &sender_ss, &commitment);
|
||||
let (decoded_kind, decoded_account) =
|
||||
EncryptionScheme::decrypt(&ct, &receiver_ss, &commitment, 0)
|
||||
EncryptionScheme::decrypt(&ct, &receiver_ss, &commitment)
|
||||
.expect("decryption must succeed with correct shared secret");
|
||||
|
||||
assert_eq!(decoded_account, account);
|
||||
@ -229,7 +205,7 @@ mod tests {
|
||||
|
||||
// Wrong shared secret must not decrypt correctly.
|
||||
let wrong_ss = SharedSecretKey([0_u8; 32]);
|
||||
let bad = EncryptionScheme::decrypt(&ct, &wrong_ss, &commitment, 0);
|
||||
let bad = EncryptionScheme::decrypt(&ct, &wrong_ss, &commitment);
|
||||
assert!(
|
||||
bad.is_none() || bad.is_some_and(|(_, a)| a.balance != 999),
|
||||
"wrong shared secret must not produce the correct plaintext"
|
||||
|
||||
@ -205,7 +205,6 @@ pub mod tests {
|
||||
&PrivateAccountKind::Regular(0),
|
||||
&shared_secret,
|
||||
&commitment,
|
||||
2,
|
||||
);
|
||||
let encrypted_account_data =
|
||||
EncryptedAccountData::new(ciphertext.clone(), &npk, &vpk, epk.clone());
|
||||
|
||||
@ -30,7 +30,6 @@ pub fn compute_circuit_output(
|
||||
"Invalid account_identities length"
|
||||
);
|
||||
|
||||
let mut output_index = 0;
|
||||
for (pos, (account_identity, (pre_state, post_state))) in
|
||||
account_identities.iter().zip(states_iter).enumerate()
|
||||
{
|
||||
@ -68,7 +67,6 @@ pub fn compute_circuit_output(
|
||||
|
||||
emit_private_output(
|
||||
&mut output,
|
||||
&mut output_index,
|
||||
post_state,
|
||||
&account_id,
|
||||
&PrivateAccountKind::Regular(*identifier),
|
||||
@ -106,7 +104,6 @@ pub fn compute_circuit_output(
|
||||
|
||||
emit_private_output(
|
||||
&mut output,
|
||||
&mut output_index,
|
||||
post_state,
|
||||
&account_id,
|
||||
&PrivateAccountKind::Regular(*identifier),
|
||||
@ -145,7 +142,6 @@ pub fn compute_circuit_output(
|
||||
|
||||
emit_private_output(
|
||||
&mut output,
|
||||
&mut output_index,
|
||||
post_state,
|
||||
&account_id,
|
||||
&PrivateAccountKind::Regular(*identifier),
|
||||
@ -192,7 +188,6 @@ pub fn compute_circuit_output(
|
||||
.expect("PrivatePdaInit position must be in pda_seed_by_position");
|
||||
emit_private_output(
|
||||
&mut output,
|
||||
&mut output_index,
|
||||
post_state,
|
||||
&account_id,
|
||||
&PrivateAccountKind::Pda {
|
||||
@ -240,7 +235,6 @@ pub fn compute_circuit_output(
|
||||
.expect("PrivatePdaUpdate position must be in pda_seed_by_position");
|
||||
emit_private_output(
|
||||
&mut output,
|
||||
&mut output_index,
|
||||
post_state,
|
||||
&account_id,
|
||||
&PrivateAccountKind::Pda {
|
||||
@ -267,7 +261,6 @@ pub fn compute_circuit_output(
|
||||
)]
|
||||
fn emit_private_output(
|
||||
output: &mut PrivacyPreservingCircuitOutput,
|
||||
output_index: &mut u32,
|
||||
post_state: Account,
|
||||
account_id: &AccountId,
|
||||
kind: &PrivateAccountKind,
|
||||
@ -288,7 +281,6 @@ fn emit_private_output(
|
||||
kind,
|
||||
shared_secret,
|
||||
&commitment_post,
|
||||
*output_index,
|
||||
);
|
||||
|
||||
output.new_commitments.push(commitment_post);
|
||||
@ -299,9 +291,6 @@ fn emit_private_output(
|
||||
epk: epk.clone(),
|
||||
view_tag,
|
||||
});
|
||||
*output_index = output_index
|
||||
.checked_add(1)
|
||||
.unwrap_or_else(|| panic!("Too many private accounts, output index overflow"));
|
||||
}
|
||||
|
||||
fn compute_update_nullifier_and_set_digest(
|
||||
|
||||
@ -52,16 +52,14 @@ fn bench_encryption(c: &mut Criterion) {
|
||||
let commitment = Commitment::new(&account_id, &account);
|
||||
let (shared, _epk) = SharedSecretKey::encapsulate(&recipient_kc.viewing_public_key);
|
||||
let kind = PrivateAccountKind::Regular(0_u128);
|
||||
let output_index: u32 = 0;
|
||||
|
||||
let mut g = c.benchmark_group("encryption");
|
||||
g.sample_size(50).noise_threshold(0.05);
|
||||
g.bench_function("encrypt", |b| {
|
||||
b.iter(|| EncryptionScheme::encrypt(&account, &kind, &shared, &commitment, output_index));
|
||||
b.iter(|| EncryptionScheme::encrypt(&account, &kind, &shared, &commitment));
|
||||
});
|
||||
let ct = EncryptionScheme::encrypt(&account, &kind, &shared, &commitment, output_index);
|
||||
let ct = EncryptionScheme::encrypt(&account, &kind, &shared, &commitment);
|
||||
g.bench_function("decrypt", |b| {
|
||||
b.iter(|| EncryptionScheme::decrypt(&ct, &shared, &commitment, output_index));
|
||||
b.iter(|| EncryptionScheme::decrypt(&ct, &shared, &commitment));
|
||||
});
|
||||
g.finish();
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user