fix(wallet): encapsulate dummy note epk in wallet

This commit is contained in:
Artem Gureev 2026-07-06 10:41:15 +00:00 committed by agureev
parent 173956579b
commit 84b5d66346
3 changed files with 14 additions and 5 deletions

View File

@ -271,12 +271,20 @@ pub fn compute_circuit_output(
}
fn emit_dummy_output(output: &mut PrivacyPreservingCircuitOutput, dummy: DummyInput) {
// Note: the nullifiers and commitments are generated from seeds.
// The prover is responsible for their randomness.
let nullifier = Nullifier::for_dummy(&dummy.nullifier_seed);
let commitment = Commitment::for_dummy(&nullifier, &dummy.commitment_seed);
output
.new_nullifiers
.push((nullifier, dummy.commitment_root));
output.new_commitments.push(commitment);
// Note: the encrypted post states are pushed as fed into the circuit.
// That means that the prover is responsible for managing the randomness
// so as to not reveal the padding.
//
// In particular, it is recommended to generate the ML KEM ciphertext
// explicitly as these are not uniformly random.
output.encrypted_private_post_states.push(dummy.note);
}

View File

@ -8,8 +8,7 @@ use lee_core::{
MembershipProof, NullifierPublicKey, NullifierSecretKey, PrivateAccountKind, SharedSecretKey,
account::{Account, AccountWithMetadata, Nonce},
encryption::{
Ciphertext, EncryptedAccountData, EphemeralPublicKey, ML_KEM_768_CIPHERTEXT_LEN, ViewTag,
ViewingPublicKey,
Ciphertext, EncryptedAccountData, MlKem768EncapsulationKey, ViewTag, ViewingPublicKey,
},
};
use rand::{RngCore as _, rngs::OsRng};
@ -651,16 +650,18 @@ fn random_vec(len: usize) -> Vec<u8> {
bytes
}
/// Generates a dummy note: random bytes sized to a default-account ciphertext, a
/// random epk, and a random view tag. Not decryptable — it only pads the journal.
/// Generates a dummy note: random bytes sized to a default-account ciphertext, a real
/// ML-KEM ciphertext epk toward a throwaway key, and a random view tag.
fn random_dummy_note() -> EncryptedAccountData {
// Sized to a default-account ciphertext; matching real data sizes is a separate issue.
let ciphertext_len = PrivateAccountKind::HEADER_LEN
.checked_add(Account::default().to_bytes().len())
.expect("dummy ciphertext length fits in usize");
let throwaway_ek = MlKem768EncapsulationKey::from_seed(&random_bytes(), &random_bytes());
let (_, epk) = SharedSecretKey::encapsulate(&throwaway_ek);
EncryptedAccountData {
ciphertext: Ciphertext::from_inner(random_vec(ciphertext_len)),
epk: EphemeralPublicKey(random_vec(ML_KEM_768_CIPHERTEXT_LEN)),
epk,
view_tag: random_view_tag(),
}
}