add test and other fixes

This commit is contained in:
jonesmarvin8 2026-05-20 16:00:57 -04:00 committed by Marvin Jones
parent 05484a5cef
commit 690ae36324
22 changed files with 225 additions and 172 deletions

5
Cargo.lock generated
View File

@ -2357,7 +2357,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1dd6dbb5841937940781866fa1281a1ff7bd3bf827091440879f9994983d5c2"
dependencies = [
"block-buffer 0.12.0",
"crypto-common 0.2.1",
"crypto-common 0.2.2",
]
[[package]]
@ -4570,7 +4570,7 @@ version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "01737161ba802849cfd486b5bd209d38ba4943494c249a8126005170c7621edd"
dependencies = [
"crypto-common 0.2.1",
"crypto-common 0.2.2",
"rand_core 0.10.1",
]
@ -4700,6 +4700,7 @@ dependencies = [
"bytesize",
"chacha20",
"k256",
"ml-kem",
"risc0-zkvm",
"serde",
"serde_json",

View File

@ -12,7 +12,7 @@ use lee::{
};
use lee_core::{
InputAccountIdentity, NullifierPublicKey, account::AccountWithMetadata,
encryption::shared_key_derivation::Secp256k1Point,
encryption::{EphemeralPublicKey, ViewingPublicKey},
};
use log::info;
use sequencer_service_rpc::RpcClient as _;
@ -71,7 +71,7 @@ async fn private_transfer_to_foreign_account() -> Result<()> {
let from: AccountId = ctx.existing_private_accounts()[0];
let to_npk = NullifierPublicKey([42; 32]);
let to_npk_string = hex::encode(to_npk.0);
let to_vpk = ViewingPublicKey::from_seed(&to_npk.0, &[0u8; 32]);
let to_vpk = ViewingPublicKey::from_seed(&to_npk.0, &[0_u8; 32]);
let command = Command::AuthTransfer(AuthTransferSubcommand::Send {
from: private_mention(from),
@ -274,7 +274,7 @@ async fn shielded_transfer_to_foreign_account() -> Result<()> {
let to_npk = NullifierPublicKey([42; 32]);
let to_npk_string = hex::encode(to_npk.0);
let to_vpk = ViewingPublicKey::from_seed(&to_npk.0, &[0u8; 32]);
let to_vpk = ViewingPublicKey::from_seed(&to_npk.0, &[0_u8; 32]);
let from: AccountId = ctx.existing_public_accounts()[0];
let command = Command::AuthTransfer(AuthTransferSubcommand::Send {
@ -654,8 +654,9 @@ async fn ppt_cant_chain_call_faucet() -> Result<()> {
let auth_transfer_program_id = Program::authenticated_transfer_program().id();
let nsk: lee_core::NullifierSecretKey = [3; 32];
let npk = NullifierPublicKey::from(&nsk);
let vpk = Secp256k1Point::from_scalar([4; 32]);
let ssk = SharedSecretKey::new([55; 32], &vpk);
let vpk = ViewingPublicKey(vec![4_u8; 1184]);
let ssk = SharedSecretKey([55_u8; 32]);
let epk = EphemeralPublicKey(vec![55_u8; 1088]);
let attacker_vault_id = {
let seed = vault_core::compute_vault_seed(attacker_id);
AccountId::for_private_pda(&vault_program_id, &seed, &npk, 1337)

View File

@ -272,10 +272,10 @@ async fn private_pda_family_members_receive_and_spend() -> Result<()> {
// Fresh recipients — hardcoded npks not in any wallet.
let recipient_npk_0 = NullifierPublicKey([0xAA; 32]);
let recipient_vpk_0 = ViewingPublicKey::from_seed(&recipient_npk_0.0, &[0u8; 32]);
let recipient_vpk_0 = ViewingPublicKey::from_seed(&recipient_npk_0.0, &[0_u8; 32]);
let recipient_npk_1 = NullifierPublicKey([0xBB; 32]);
let recipient_vpk_1 = ViewingPublicKey::from_seed(&recipient_npk_1.0, &[0u8; 32]);
let recipient_vpk_1 = ViewingPublicKey::from_seed(&recipient_npk_1.0, &[0_u8; 32]);
let amount_spend_0: u128 = 13;
let amount_spend_1: u128 = 37;

View File

@ -256,7 +256,7 @@ pub async fn tps_test() -> Result<()> {
fn build_privacy_transaction() -> PrivacyPreservingTransaction {
let program = Program::authenticated_transfer_program();
let sender_nsk = [1; 32];
let sender_vpk = ViewingPublicKey::from_seed(&[99u8; 32], &[100u8; 32]);
let sender_vpk = ViewingPublicKey::from_seed(&[99_u8; 32], &[100_u8; 32]);
let sender_npk = NullifierPublicKey::from(&sender_nsk);
let sender_pre = AccountWithMetadata::new(
Account {
@ -269,7 +269,7 @@ fn build_privacy_transaction() -> PrivacyPreservingTransaction {
AccountId::for_regular_private_account(&sender_npk, 0),
);
let recipient_nsk = [2; 32];
let recipient_vpk = ViewingPublicKey::from_seed(&[99u8; 32], &[100u8; 32]);
let recipient_vpk = ViewingPublicKey::from_seed(&[99_u8; 32], &[100_u8; 32]);
let recipient_npk = NullifierPublicKey::from(&recipient_nsk);
let recipient_pre = AccountWithMetadata::new(
Account::default(),

View File

@ -6,7 +6,7 @@ use lee_core::{
/// Ephemeral key holder for the sender side of a KEM-based shared-secret exchange.
///
/// Non-clonable as intended for one-time use: construction encapsulates once and
/// stores both the shared secret and the ciphertext (EphemeralPublicKey) that must
/// stores both the shared secret and the ciphertext (`EphemeralPublicKey`) that must
/// be sent to the receiver.
pub struct EphemeralKeyHolder {
shared_secret: SharedSecretKey,
@ -36,15 +36,15 @@ impl EphemeralKeyHolder {
}
}
/// Returns the KEM ciphertext to be transmitted to the receiver as the EphemeralPublicKey.
/// Returns the KEM ciphertext to be transmitted to the receiver as the `EphemeralPublicKey`.
#[must_use]
pub fn ephemeral_public_key(&self) -> &EphemeralPublicKey {
pub const fn ephemeral_public_key(&self) -> &EphemeralPublicKey {
&self.ephemeral_public_key
}
/// Returns the sender-side shared secret (established at construction time).
#[must_use]
pub fn calculate_shared_secret_sender(&self) -> SharedSecretKey {
pub const fn calculate_shared_secret_sender(&self) -> SharedSecretKey {
self.shared_secret
}
}

View File

@ -328,6 +328,80 @@ mod tests {
/// Pins the end-to-end derivation for a fixed (GMS, `ProgramId`, `PdaSeed`). Any change
/// to `secret_spending_key_for_pda`, the `PrivateKeyHolder` nsk/npk chain, or the
/// `AccountId::for_private_pda` formula breaks this test.
#[test]
fn pinned_end_to_end_derivation_for_private_pda() {
use lee_core::{account::AccountId, program::ProgramId};
let gms = [42_u8; 32];
let seed = PdaSeed::new([1; 32]);
let program_id: ProgramId = [9; 8];
let holder = GroupKeyHolder::from_gms(gms);
let npk = holder
.derive_keys_for_pda(&TEST_PROGRAM_ID, &seed)
.generate_nullifier_public_key();
let account_id = AccountId::for_private_pda(&program_id, &seed, &npk, u128::MAX);
let expected_npk = NullifierPublicKey([
136, 176, 234, 71, 208, 8, 143, 142, 126, 155, 132, 18, 71, 27, 88, 56, 100, 90, 79,
215, 76, 92, 60, 166, 104, 35, 51, 91, 16, 114, 188, 112,
]);
let expected_account_id =
AccountId::for_private_pda(&program_id, &seed, &expected_npk, u128::MAX);
assert_eq!(npk, expected_npk);
assert_eq!(account_id, expected_account_id);
}
/// Wallets persist `GroupKeyHolder` to disk and reload it on startup.
#[test]
fn gms_serde_round_trip_preserves_derivation() {
let original = GroupKeyHolder::from_gms([7_u8; 32]);
let encoded = bincode::serialize(&original).expect("serialize");
let restored: GroupKeyHolder = bincode::deserialize(&encoded).expect("deserialize");
let seed = PdaSeed::new([1; 32]);
let npk_original = original
.derive_keys_for_pda(&TEST_PROGRAM_ID, &seed)
.generate_nullifier_public_key();
let npk_restored = restored
.derive_keys_for_pda(&TEST_PROGRAM_ID, &seed)
.generate_nullifier_public_key();
assert_eq!(npk_original, npk_restored);
assert_eq!(original.dangerous_raw_gms(), restored.dangerous_raw_gms());
}
/// A `GroupKeyHolder` constructed from the same 32 bytes as a personal
/// `SecretSpendingKey` must not derive the same `NullifierPublicKey`.
#[test]
fn group_derivation_does_not_collide_with_personal_path_at_shared_bytes() {
let shared_bytes = [13_u8; 32];
let seed = PdaSeed::new([5; 32]);
let group_npk = GroupKeyHolder::from_gms(shared_bytes)
.derive_keys_for_pda(&TEST_PROGRAM_ID, &seed)
.generate_nullifier_public_key();
let personal_npk = SecretSpendingKey(shared_bytes)
.produce_private_key_holder(None)
.generate_nullifier_public_key();
assert_ne!(group_npk, personal_npk);
}
/// Seal then unseal recovers the same GMS and derived keys.
#[test]
fn seal_unseal_round_trip() {
let holder = GroupKeyHolder::from_gms([42_u8; 32]);
let recipient_ssk = SecretSpendingKey([7_u8; 32]);
let recipient_keys = recipient_ssk.produce_private_key_holder(None);
let recipient_vpk = recipient_keys.generate_viewing_public_key();
let recipient_vsk = recipient_keys.viewing_secret_key;
let sealed = holder.seal_for(&SealingPublicKey::from_bytes(recipient_vpk.0));
let restored = GroupKeyHolder::unseal(&sealed, &recipient_vsk).expect("unseal");
assert_eq!(restored.dangerous_raw_gms(), holder.dangerous_raw_gms());
@ -355,8 +429,7 @@ mod tests {
let wrong_vsk = SecretSpendingKey([99_u8; 32])
.produce_private_key_holder(None)
.viewing_secret_key
.clone();
.viewing_secret_key;
let sealed = holder.seal_for(&SealingPublicKey::from_bytes(recipient_vpk.0));
let result = GroupKeyHolder::unseal(&sealed, &wrong_vsk);
@ -371,7 +444,7 @@ mod tests {
let recipient_ssk = SecretSpendingKey([7_u8; 32]);
let recipient_keys = recipient_ssk.produce_private_key_holder(None);
let recipient_vpk = recipient_keys.generate_viewing_public_key();
let recipient_vsk = recipient_keys.viewing_secret_key.clone();
let recipient_vsk = recipient_keys.viewing_secret_key;
let mut sealed = holder.seal_for(&SealingPublicKey::from_bytes(recipient_vpk.0));
// Flip a byte in the AES-GCM ciphertext portion (after KEM ciphertext + nonce).
@ -453,7 +526,7 @@ mod tests {
let bob_ssk = SecretSpendingKey([77_u8; 32]);
let bob_keys = bob_ssk.produce_private_key_holder(None);
let bob_vpk = bob_keys.generate_viewing_public_key();
let bob_vsk = bob_keys.viewing_secret_key.clone();
let bob_vsk = bob_keys.viewing_secret_key;
let sealed = alice_holder.seal_for(&SealingPublicKey::from_bytes(bob_vpk.0));
let bob_holder =

View File

@ -62,7 +62,7 @@ impl ChildKeysPrivate {
pub fn nth_child(&self, cci: u32) -> Self {
let mut parent_hash = sha2::Sha256::new();
parent_hash.update(b"LEE/keys");
parent_hash.update([0u8; 16]);
parent_hash.update([0_u8; 16]);
parent_hash.update([9_u8]);
parent_hash.update(self.value.0.private_key_holder.nullifier_secret_key);
parent_hash.update(self.value.0.private_key_holder.viewing_secret_key.d);
@ -147,7 +147,7 @@ mod tests {
let keys = ChildKeysPrivate::root(seed);
let expected_ssk: SecretSpendingKey = key_management::secret_holders::SecretSpendingKey([
let expected_ssk = key_management::secret_holders::SecretSpendingKey([
246, 79, 26, 124, 135, 95, 52, 51, 201, 27, 48, 194, 2, 144, 51, 219, 245, 128, 139,
222, 42, 195, 105, 33, 115, 97, 186, 0, 97, 14, 218, 191,
]);
@ -260,11 +260,10 @@ mod tests {
114, 39, 38, 118, 197, 205, 225,
];
// Marvin-pq this test currently fails
let root_node = ChildKeysPrivate::root(seed);
let child_node = ChildKeysPrivate::nth_child(&root_node, 42_u32);
let expected_ssk: SecretSpendingKey = key_management::secret_holders::SecretSpendingKey([
let expected_ssk = key_management::secret_holders::SecretSpendingKey([
215, 207, 70, 52, 161, 220, 88, 88, 241, 149, 81, 130, 217, 214, 252, 170, 51, 232,
230, 158, 195, 173, 174, 37, 27, 101, 49, 35, 79, 13, 44, 225,
]);

View File

@ -22,7 +22,7 @@ pub struct SeedHolder {
pub struct SecretSpendingKey(pub [u8; 32]);
/// Viewing secret key: the KEM seed split into its two 32-byte halves `d` and `r` (= z in
/// FIPS 203), from which the ML-KEM 768 decapsulation key is derived deterministically.
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct ViewingSecretKey {
pub d: [u8; 32],
pub r: [u8; 32],
@ -30,7 +30,7 @@ pub struct ViewingSecretKey {
/// Private key holder. Produces public keys. Can produce `account_id`. Can produce shared secret
/// for recepient.
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct PrivateKeyHolder {
pub nullifier_secret_key: NullifierSecretKey,
pub viewing_secret_key: ViewingSecretKey,
@ -153,7 +153,7 @@ impl SecretSpendingKey {
}
#[must_use]
pub fn generate_viewing_secret_key(seed: [u8; 64]) -> ViewingSecretKey {
pub const fn generate_viewing_secret_key(seed: [u8; 64]) -> ViewingSecretKey {
ViewingSecretKey {
d: *seed.first_chunk::<32>().expect("seed is 64 bytes"),
r: *seed.last_chunk::<32>().expect("seed is 64 bytes"),
@ -172,11 +172,11 @@ impl SecretSpendingKey {
impl From<&ViewingSecretKey> for ViewingPublicKey {
fn from(sk: &ViewingSecretKey) -> Self {
use ml_kem::{Kem, KeyExport as _, MlKem768, Seed};
let mut seed_bytes = [0u8; 64];
let mut seed_bytes = [0_u8; 64];
seed_bytes[..32].copy_from_slice(&sk.d);
seed_bytes[32..].copy_from_slice(&sk.r);
let dk = <MlKem768 as Kem>::DecapsulationKey::from_seed(Seed::from(seed_bytes));
ViewingPublicKey(dk.encapsulation_key().to_bytes().to_vec())
Self(dk.encapsulation_key().to_bytes().to_vec())
}
}

View File

@ -7,7 +7,7 @@ use std::io::Read as _;
#[cfg(feature = "host")]
use crate::Nullifier;
#[cfg(feature = "host")]
use crate::encryption::{EphemeralPublicKey, shared_key_derivation::Secp256k1Point};
use crate::encryption::EphemeralPublicKey;
#[cfg(feature = "host")]
use crate::error::LeeCoreError;
use crate::{
@ -157,25 +157,6 @@ impl Ciphertext {
}
}
#[cfg(feature = "host")]
impl Secp256k1Point {
/// Converts the point to bytes.
#[must_use]
pub fn to_bytes(&self) -> [u8; 33] {
self.0.clone().try_into().unwrap()
}
/// Deserializes a secp256k1 point from a cursor.
pub fn from_cursor(cursor: &mut Cursor<&[u8]>) -> Result<Self, LeeCoreError> {
let mut value = vec![0; 33];
cursor.read_exact(&mut value)?;
Ok(Self(value))
}
}
// Marvin-pq: EphemeralPublicKey is now the ML-KEM-768 ciphertext (1088 bytes) produced by
// SharedSecretKey::encapsulate. It replaces the old Secp256k1Point (33 bytes) on the wire.
// Fixed size: 1088 bytes for ML-KEM-768 (EncodedUSize + EncodedVSize per FIPS 203 §7.2).
#[cfg(feature = "host")]
impl EphemeralPublicKey {
/// Serializes the ML-KEM-768 ciphertext to bytes (always 1088 bytes).
@ -187,7 +168,7 @@ impl EphemeralPublicKey {
/// Deserializes an ML-KEM-768 ciphertext from a cursor.
/// Reads exactly 1088 bytes — the fixed ciphertext size for ML-KEM-768.
pub fn from_cursor(cursor: &mut Cursor<&[u8]>) -> Result<Self, NssaCoreError> {
let mut value = vec![0u8; 1088];
let mut value = vec![0_u8; 1088];
cursor.read_exact(&mut value)?;
Ok(Self(value))
}

View File

@ -154,4 +154,41 @@ mod tests {
assert_eq!(account_ct.0.len(), pda_ct.0.len());
}
/// Verifies the full account-note pipeline: ML-KEM-768 encapsulation/decapsulation
/// feeds the correct shared secret into the SHA-256 KDF and ChaCha20 round-trip.
#[cfg(feature = "host")]
#[test]
fn kem_to_chacha20_round_trip() {
let d = [1_u8; 32];
let r = [2_u8; 32];
let vpk = shared_key_derivation::ViewingPublicKey::from_seed(&d, &r);
let (sender_ss, epk) = SharedSecretKey::encapsulate(&vpk);
let receiver_ss = SharedSecretKey::decapsulate(&epk, &d, &r);
let account = Account {
program_owner: [12_u32; 8],
balance: 999,
..Account::default()
};
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 (decoded_kind, decoded_account) =
EncryptionScheme::decrypt(&ct, &receiver_ss, &commitment, 0)
.expect("decryption must succeed with correct shared secret");
assert_eq!(decoded_account, account);
assert_eq!(decoded_kind, kind);
// Wrong shared secret must not decrypt correctly.
let wrong_ss = SharedSecretKey([0_u8; 32]);
let bad = EncryptionScheme::decrypt(&ct, &wrong_ss, &commitment, 0);
assert!(
bad.is_none() || bad.is_some_and(|(_, a)| a.balance != 999),
"wrong shared secret must not produce the correct plaintext"
);
}
}

View File

@ -1,48 +1,8 @@
#![expect(
clippy::arithmetic_side_effects,
reason = "Multiplication of finite field elements can't overflow"
)]
use std::fmt::Write as _;
use borsh::{BorshDeserialize, BorshSerialize};
use k256::{
AffinePoint, FieldBytes, ProjectivePoint,
elliptic_curve::{PrimeField as _, sec1::ToEncodedPoint as _},
};
use ml_kem::{Decapsulate as _, Encapsulate as _, KeyExport as _, Seed};
use serde::{Deserialize, Serialize};
use crate::{SharedSecretKey, encryption::Scalar};
/// A compressed secp256k1 point (33 bytes).
/// Kept for backward compatibility with Phase-2+ callers; no longer used as `EphemeralPublicKey`.
#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)]
pub struct Secp256k1Point(pub Vec<u8>);
impl std::fmt::Debug for Secp256k1Point {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let hex: String = self.0.iter().fold(String::new(), |mut acc, b| {
write!(acc, "{b:02x}").expect("writing to string should not fail");
acc
});
write!(f, "Secp256k1Point({hex})")
}
}
impl Secp256k1Point {
#[must_use]
pub fn from_scalar(value: Scalar) -> Self {
let x_bytes: FieldBytes = value.into();
let x = k256::Scalar::from_repr(x_bytes).unwrap();
let p = ProjectivePoint::GENERATOR * x;
let q = AffinePoint::from(p);
let enc = q.to_encoded_point(true);
Self(enc.as_bytes().to_vec())
}
}
use crate::SharedSecretKey;
/// The ML-KEM-768 ciphertext produced during encapsulation; transmitted on-wire in place of the
/// former ECDH ephemeral public key. Always 1088 bytes for ML-KEM-768.
@ -50,7 +10,7 @@ impl Secp256k1Point {
pub struct EphemeralPublicKey(pub Vec<u8>);
/// ML-KEM-768 encapsulation key bytes (1184 bytes, opaque to this crate).
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, BorshSerialize, BorshDeserialize)]
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, BorshSerialize, BorshDeserialize)]
pub struct ViewingPublicKey(pub Vec<u8>);
impl ViewingPublicKey {
@ -113,7 +73,7 @@ impl SharedSecretKey {
input.extend_from_slice(message_hash);
input.extend_from_slice(&output_index.to_le_bytes());
let hash = Impl::hash_bytes(&input);
let m: ml_kem::B32 = ml_kem::array::Array::try_from(hash.as_bytes() as &[u8])
let m: ml_kem::B32 = ml_kem::array::Array::try_from(hash.as_bytes())
.expect("SHA-256 output is 32 bytes");
let ek_bytes: ml_kem::kem::Key<ml_kem::EncapsulationKey768> = vpk
@ -159,8 +119,8 @@ mod tests {
#[test]
fn encapsulate_decapsulate_round_trip() {
let d = [1u8; 32];
let r = [2u8; 32];
let d = [1_u8; 32];
let r = [2_u8; 32];
let mut seed = Seed::default();
seed[..32].copy_from_slice(&d);
@ -184,8 +144,8 @@ mod tests {
#[test]
fn different_vpks_produce_different_shared_secrets() {
let (d1, r1) = ([1u8; 32], [2u8; 32]);
let (d2, r2) = ([3u8; 32], [4u8; 32]);
let (d1, r1) = ([1_u8; 32], [2_u8; 32]);
let (d2, r2) = ([3_u8; 32], [4_u8; 32]);
let vpk1 = {
let mut seed = Seed::default();

View File

@ -244,7 +244,7 @@ mod tests {
let expected_sender_pre = sender.clone();
let shared_secret =
SharedSecretKey::encapsulate_deterministic(&recipient_keys.vpk(), &[0u8; 32], 0).0;
SharedSecretKey::encapsulate_deterministic(&recipient_keys.vpk(), &[0_u8; 32], 0).0;
let (output, proof) = execute_and_prove(
vec![sender, recipient],
@ -341,10 +341,10 @@ mod tests {
];
let shared_secret_1 =
SharedSecretKey::encapsulate_deterministic(&sender_keys.vpk(), &[0u8; 32], 0).0;
SharedSecretKey::encapsulate_deterministic(&sender_keys.vpk(), &[0_u8; 32], 0).0;
let shared_secret_2 =
SharedSecretKey::encapsulate_deterministic(&recipient_keys.vpk(), &[0u8; 32], 1).0;
SharedSecretKey::encapsulate_deterministic(&recipient_keys.vpk(), &[0_u8; 32], 1).0;
let (output, proof) = execute_and_prove(
vec![sender_pre, recipient],
@ -419,7 +419,7 @@ mod tests {
.unwrap();
let shared_secret =
SharedSecretKey::encapsulate_deterministic(&account_keys.vpk(), &[0u8; 32], 0).0;
SharedSecretKey::encapsulate_deterministic(&account_keys.vpk(), &[0_u8; 32], 0).0;
let program_with_deps = ProgramWithDependencies::new(
validity_window_chain_caller,
@ -450,7 +450,7 @@ mod tests {
let seed = PdaSeed::new([42; 32]);
let identifier: u128 = 99;
let shared_secret =
SharedSecretKey::encapsulate_deterministic(&keys.vpk(), &[0u8; 32], 0).0;
SharedSecretKey::encapsulate_deterministic(&keys.vpk(), &[0_u8; 32], 0).0;
let account_id = AccountId::for_private_pda(&program.id(), &seed, &npk, identifier);
let pre_state = AccountWithMetadata::new(Account::default(), false, account_id);
@ -489,7 +489,7 @@ mod tests {
let npk = keys.npk();
let seed = PdaSeed::new([42; 32]);
let shared_secret_pda =
SharedSecretKey::encapsulate_deterministic(&keys.vpk(), &[0u8; 32], 0).0;
SharedSecretKey::encapsulate_deterministic(&keys.vpk(), &[0_u8; 32], 0).0;
// PDA (new, private PDA)
let pda_id = AccountId::for_private_pda(&program.id(), &seed, &npk, 0);
@ -529,7 +529,7 @@ mod tests {
let npk = keys.npk();
let seed = PdaSeed::new([42; 32]);
let shared_secret_pda =
SharedSecretKey::encapsulate_deterministic(&keys.vpk(), &[0u8; 32], 0).0;
SharedSecretKey::encapsulate_deterministic(&keys.vpk(), &[0_u8; 32], 0).0;
// PDA (new, private PDA)
let pda_id = AccountId::for_private_pda(&program.id(), &seed, &npk, 0);
@ -585,7 +585,7 @@ mod tests {
let shared_npk = shared_keys.npk();
let shared_identifier: u128 = 42;
let shared_secret =
SharedSecretKey::encapsulate_deterministic(&shared_keys.vpk(), &[0u8; 32], 0).0;
SharedSecretKey::encapsulate_deterministic(&shared_keys.vpk(), &[0_u8; 32], 0).0;
// Sender: public account with balance, owned by auth-transfer
let sender_id = AccountId::new([99; 32]);
@ -636,7 +636,7 @@ mod tests {
let program = Program::authenticated_transfer_program();
let keys = test_private_account_keys_1();
let identifier: u128 = 99;
let ssk = SharedSecretKey::encapsulate_deterministic(&keys.vpk(), &[0u8; 32], 0).0;
let ssk = SharedSecretKey::encapsulate_deterministic(&keys.vpk(), &[0_u8; 32], 0).0;
let account_id = AccountId::for_regular_private_account(&keys.npk(), identifier);
let pre = AccountWithMetadata::new(Account::default(), true, account_id);
@ -666,7 +666,7 @@ mod tests {
let program = Program::authenticated_transfer_program();
let keys = test_private_account_keys_1();
let identifier: u128 = 99;
let ssk = SharedSecretKey::encapsulate_deterministic(&keys.vpk(), &[0u8; 32], 0).0;
let ssk = SharedSecretKey::encapsulate_deterministic(&keys.vpk(), &[0_u8; 32], 0).0;
let sender = AccountWithMetadata::new(
Account {
@ -711,7 +711,7 @@ mod tests {
let program = Program::authenticated_transfer_program();
let keys = test_private_account_keys_1();
let identifier: u128 = 99;
let ssk = SharedSecretKey::encapsulate_deterministic(&keys.vpk(), &[0u8; 32], 0).0;
let ssk = SharedSecretKey::encapsulate_deterministic(&keys.vpk(), &[0_u8; 32], 0).0;
let account_id = AccountId::for_regular_private_account(&keys.npk(), identifier);
let account = Account {
program_owner: program.id(),
@ -760,7 +760,7 @@ mod tests {
let npk = keys.npk();
let seed = PdaSeed::new([42; 32]);
let identifier: u128 = 99;
let ssk = SharedSecretKey::encapsulate_deterministic(&keys.vpk(), &[0u8; 32], 0).0;
let ssk = SharedSecretKey::encapsulate_deterministic(&keys.vpk(), &[0_u8; 32], 0).0;
let auth_transfer_id = auth_transfer.id();
let pda_id = AccountId::for_private_pda(&program.id(), &seed, &npk, identifier);
@ -816,7 +816,7 @@ mod tests {
let npk = keys.npk();
let seed = PdaSeed::new([42; 32]);
let shared_secret =
SharedSecretKey::encapsulate_deterministic(&keys.vpk(), &[0u8; 32], 0).0;
SharedSecretKey::encapsulate_deterministic(&keys.vpk(), &[0_u8; 32], 0).0;
let account_id = AccountId::for_private_pda(&program.id(), &seed, &npk, 5);
let pre_state = AccountWithMetadata::new(Account::default(), false, account_id);
@ -843,7 +843,7 @@ mod tests {
let keys = test_private_account_keys_1();
let npk = keys.npk();
let seed = PdaSeed::new([42; 32]);
let ssk = SharedSecretKey::encapsulate_deterministic(&keys.vpk(), &[0u8; 32], 0).0;
let ssk = SharedSecretKey::encapsulate_deterministic(&keys.vpk(), &[0_u8; 32], 0).0;
let auth_transfer_id = auth_transfer.id();
let pda_id = AccountId::for_private_pda(&program.id(), &seed, &npk, 5);

View File

@ -208,7 +208,7 @@ pub mod tests {
let nonces_bytes: &[u8] = &[1, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
// all remaining vec fields are empty: u32 len=0
let empty_vec_bytes: &[u8] = &[0_u8; 4];
// validity windows: unbounded = {from: None (0u8), to: None (0u8)}
// validity windows: unbounded = {from: None (0_u8), to: None (0_u8)}
let unbounded_window_bytes: &[u8] = &[0_u8; 2];
let expected_borsh_vec: Vec<u8> = [
@ -246,11 +246,11 @@ pub mod tests {
#[test]
fn encrypted_account_data_constructor() {
let npk = NullifierPublicKey::from(&[1; 32]);
let vpk = ViewingPublicKey::from_seed(&[2u8; 32], &[3u8; 32]);
let vpk = ViewingPublicKey::from_seed(&[2_u8; 32], &[3_u8; 32]);
let account = Account::default();
let account_id = lee_core::account::AccountId::for_regular_private_account(&npk, 0);
let commitment = Commitment::new(&account_id, &account);
let (shared_secret, epk) = SharedSecretKey::encapsulate_deterministic(&vpk, &[0u8; 32], 0);
let (shared_secret, epk) = SharedSecretKey::encapsulate_deterministic(&vpk, &[0_u8; 32], 0);
let ciphertext = EncryptionScheme::encrypt(
&account,
&PrivateAccountKind::Regular(0),

View File

@ -1365,7 +1365,7 @@ pub mod tests {
AccountWithMetadata::new(Account::default(), false, (&recipient_keys.npk(), 0));
let (shared_secret, epk) =
SharedSecretKey::encapsulate_deterministic(&recipient_keys.vpk(), &[0u8; 32], 0);
SharedSecretKey::encapsulate_deterministic(&recipient_keys.vpk(), &[0_u8; 32], 0);
let (output, proof) = circuit::execute_and_prove(
vec![sender, recipient],
@ -1416,10 +1416,10 @@ pub mod tests {
AccountWithMetadata::new(Account::default(), false, (&recipient_keys.npk(), 0));
let (shared_secret_1, epk_1) =
SharedSecretKey::encapsulate_deterministic(&sender_keys.vpk(), &[0u8; 32], 0);
SharedSecretKey::encapsulate_deterministic(&sender_keys.vpk(), &[0_u8; 32], 0);
let (shared_secret_2, epk_2) =
SharedSecretKey::encapsulate_deterministic(&recipient_keys.vpk(), &[0u8; 32], 1);
SharedSecretKey::encapsulate_deterministic(&recipient_keys.vpk(), &[0_u8; 32], 1);
let (output, proof) = circuit::execute_and_prove(
vec![sender_pre, recipient_pre],
@ -1484,7 +1484,7 @@ pub mod tests {
);
let (shared_secret, epk) =
SharedSecretKey::encapsulate_deterministic(&sender_keys.vpk(), &[0u8; 32], 0);
SharedSecretKey::encapsulate_deterministic(&sender_keys.vpk(), &[0_u8; 32], 0);
let (output, proof) = circuit::execute_and_prove(
vec![sender_pre, recipient_pre],
@ -1994,7 +1994,7 @@ pub mod tests {
InputAccountIdentity::PrivateAuthorizedUpdate {
ssk: SharedSecretKey::encapsulate_deterministic(
&sender_keys.vpk(),
&[0u8; 32],
&[0_u8; 32],
0,
)
.0,
@ -2006,7 +2006,7 @@ pub mod tests {
npk: recipient_keys.npk(),
ssk: SharedSecretKey::encapsulate_deterministic(
&recipient_keys.vpk(),
&[0u8; 32],
&[0_u8; 32],
0,
)
.0,
@ -2050,7 +2050,7 @@ pub mod tests {
InputAccountIdentity::PrivateAuthorizedUpdate {
ssk: SharedSecretKey::encapsulate_deterministic(
&sender_keys.vpk(),
&[0u8; 32],
&[0_u8; 32],
0,
)
.0,
@ -2062,7 +2062,7 @@ pub mod tests {
npk: recipient_keys.npk(),
ssk: SharedSecretKey::encapsulate_deterministic(
&recipient_keys.vpk(),
&[0u8; 32],
&[0_u8; 32],
0,
)
.0,
@ -2106,7 +2106,7 @@ pub mod tests {
InputAccountIdentity::PrivateAuthorizedUpdate {
ssk: SharedSecretKey::encapsulate_deterministic(
&sender_keys.vpk(),
&[0u8; 32],
&[0_u8; 32],
0,
)
.0,
@ -2118,7 +2118,7 @@ pub mod tests {
npk: recipient_keys.npk(),
ssk: SharedSecretKey::encapsulate_deterministic(
&recipient_keys.vpk(),
&[0u8; 32],
&[0_u8; 32],
0,
)
.0,
@ -2162,7 +2162,7 @@ pub mod tests {
InputAccountIdentity::PrivateAuthorizedUpdate {
ssk: SharedSecretKey::encapsulate_deterministic(
&sender_keys.vpk(),
&[0u8; 32],
&[0_u8; 32],
0,
)
.0,
@ -2174,7 +2174,7 @@ pub mod tests {
npk: recipient_keys.npk(),
ssk: SharedSecretKey::encapsulate_deterministic(
&recipient_keys.vpk(),
&[0u8; 32],
&[0_u8; 32],
0,
)
.0,
@ -2218,7 +2218,7 @@ pub mod tests {
InputAccountIdentity::PrivateAuthorizedUpdate {
ssk: SharedSecretKey::encapsulate_deterministic(
&sender_keys.vpk(),
&[0u8; 32],
&[0_u8; 32],
0,
)
.0,
@ -2230,7 +2230,7 @@ pub mod tests {
npk: recipient_keys.npk(),
ssk: SharedSecretKey::encapsulate_deterministic(
&recipient_keys.vpk(),
&[0u8; 32],
&[0_u8; 32],
0,
)
.0,
@ -2272,7 +2272,7 @@ pub mod tests {
InputAccountIdentity::PrivateAuthorizedUpdate {
ssk: SharedSecretKey::encapsulate_deterministic(
&sender_keys.vpk(),
&[0u8; 32],
&[0_u8; 32],
0,
)
.0,
@ -2284,7 +2284,7 @@ pub mod tests {
npk: recipient_keys.npk(),
ssk: SharedSecretKey::encapsulate_deterministic(
&recipient_keys.vpk(),
&[0u8; 32],
&[0_u8; 32],
0,
)
.0,
@ -2307,7 +2307,7 @@ pub mod tests {
let keys = test_private_account_keys_1();
let npk = keys.npk();
let shared_secret =
SharedSecretKey::encapsulate_deterministic(&keys.vpk(), &[0u8; 32], 0).0;
SharedSecretKey::encapsulate_deterministic(&keys.vpk(), &[0_u8; 32], 0).0;
let public_account_1 = AccountWithMetadata::new(
Account {
program_owner: program.id(),
@ -2350,7 +2350,7 @@ pub mod tests {
let npk = keys.npk();
let seed = PdaSeed::new([42; 32]);
let shared_secret =
SharedSecretKey::encapsulate_deterministic(&keys.vpk(), &[0u8; 32], 0).0;
SharedSecretKey::encapsulate_deterministic(&keys.vpk(), &[0_u8; 32], 0).0;
let account_id = AccountId::for_private_pda(&program.id(), &seed, &npk, u128::MAX);
let pre_state = AccountWithMetadata::new(Account::default(), false, account_id);
@ -2388,7 +2388,7 @@ pub mod tests {
let npk_b = keys_b.npk();
let seed = PdaSeed::new([42; 32]);
let shared_secret =
SharedSecretKey::encapsulate_deterministic(&keys_b.vpk(), &[0u8; 32], 0).0;
SharedSecretKey::encapsulate_deterministic(&keys_b.vpk(), &[0_u8; 32], 0).0;
// `account_id` is derived from `npk_a`, but `npk_b` is supplied for this pre_state.
// `AccountId::for_private_pda(program, seed, npk_b) != account_id`, so the claim check in
@ -2424,7 +2424,7 @@ pub mod tests {
let npk = keys.npk();
let seed = PdaSeed::new([77; 32]);
let shared_secret =
SharedSecretKey::encapsulate_deterministic(&keys.vpk(), &[0u8; 32], 0).0;
SharedSecretKey::encapsulate_deterministic(&keys.vpk(), &[0_u8; 32], 0).0;
let account_id = AccountId::for_private_pda(&delegator.id(), &seed, &npk, u128::MAX);
let pre_state = AccountWithMetadata::new(Account::default(), false, account_id);
@ -2464,7 +2464,7 @@ pub mod tests {
let claim_seed = PdaSeed::new([77; 32]);
let wrong_delegated_seed = PdaSeed::new([88; 32]);
let shared_secret =
SharedSecretKey::encapsulate_deterministic(&keys.vpk(), &[0u8; 32], 0).0;
SharedSecretKey::encapsulate_deterministic(&keys.vpk(), &[0_u8; 32], 0).0;
let account_id = AccountId::for_private_pda(&delegator.id(), &claim_seed, &npk, u128::MAX);
let pre_state = AccountWithMetadata::new(Account::default(), false, account_id);
@ -2502,8 +2502,8 @@ pub mod tests {
let keys_a = test_private_account_keys_1();
let keys_b = test_private_account_keys_2();
let seed = PdaSeed::new([55; 32]);
let shared_a = SharedSecretKey::encapsulate_deterministic(&keys_a.vpk(), &[0u8; 32], 0).0;
let shared_b = SharedSecretKey::encapsulate_deterministic(&keys_b.vpk(), &[0u8; 32], 0).0;
let shared_a = SharedSecretKey::encapsulate_deterministic(&keys_a.vpk(), &[0_u8; 32], 0).0;
let shared_b = SharedSecretKey::encapsulate_deterministic(&keys_b.vpk(), &[0_u8; 32], 0).0;
let account_a = AccountId::for_private_pda(&program.id(), &seed, &keys_a.npk(), u128::MAX);
let account_b = AccountId::for_private_pda(&program.id(), &seed, &keys_b.npk(), u128::MAX);
@ -2545,7 +2545,7 @@ pub mod tests {
let keys = test_private_account_keys_1();
let npk = keys.npk();
let shared_secret =
SharedSecretKey::encapsulate_deterministic(&keys.vpk(), &[0u8; 32], 0).0;
SharedSecretKey::encapsulate_deterministic(&keys.vpk(), &[0_u8; 32], 0).0;
let seed = PdaSeed::new([99; 32]);
// Simulate a previously-claimed private PDA: program_owner != DEFAULT, is_authorized =
@ -2646,7 +2646,7 @@ pub mod tests {
);
let shared_secret =
SharedSecretKey::encapsulate_deterministic(&sender_keys.vpk(), &[0u8; 32], 0).0;
SharedSecretKey::encapsulate_deterministic(&sender_keys.vpk(), &[0_u8; 32], 0).0;
let result = execute_and_prove(
vec![private_account_1.clone(), private_account_1],
Program::serialize_instruction(100_u128).unwrap(),
@ -2991,7 +2991,7 @@ pub mod tests {
let recipient_pre =
AccountWithMetadata::new(Account::default(), true, recipient_account_id);
let (shared_secret, epk) =
SharedSecretKey::encapsulate_deterministic(&sender_keys.vpk(), &[0u8; 32], 0);
SharedSecretKey::encapsulate_deterministic(&sender_keys.vpk(), &[0_u8; 32], 0);
let balance = 37;
@ -3096,10 +3096,10 @@ pub mod tests {
);
let (from_ss, from_epk) =
SharedSecretKey::encapsulate_deterministic(&from_keys.vpk(), &[0u8; 32], 0);
SharedSecretKey::encapsulate_deterministic(&from_keys.vpk(), &[0_u8; 32], 0);
let (to_ss, to_epk) =
SharedSecretKey::encapsulate_deterministic(&to_keys.vpk(), &[0u8; 32], 1);
SharedSecretKey::encapsulate_deterministic(&to_keys.vpk(), &[0_u8; 32], 1);
let mut dependencies = HashMap::new();
@ -3397,7 +3397,7 @@ pub mod tests {
// Set up parameters for the new account
let (shared_secret, epk) =
SharedSecretKey::encapsulate_deterministic(&private_keys.vpk(), &[0u8; 32], 0);
SharedSecretKey::encapsulate_deterministic(&private_keys.vpk(), &[0_u8; 32], 0);
let instruction = authenticated_transfer_core::Instruction::Initialize;
@ -3448,7 +3448,7 @@ pub mod tests {
let program = Program::claimer();
let (shared_secret, epk) =
SharedSecretKey::encapsulate_deterministic(&private_keys.vpk(), &[0u8; 32], 0);
SharedSecretKey::encapsulate_deterministic(&private_keys.vpk(), &[0_u8; 32], 0);
let (output, proof) = execute_and_prove(
vec![unauthorized_account],
@ -3497,7 +3497,7 @@ pub mod tests {
// Set up parameters for claiming the new account
let (shared_secret, epk) =
SharedSecretKey::encapsulate_deterministic(&private_keys.vpk(), &[0u8; 32], 0);
SharedSecretKey::encapsulate_deterministic(&private_keys.vpk(), &[0_u8; 32], 0);
let instruction = authenticated_transfer_core::Instruction::Initialize;
@ -3546,7 +3546,7 @@ pub mod tests {
let noop_program = Program::noop();
let shared_secret2 =
SharedSecretKey::encapsulate_deterministic(&private_keys.vpk(), &[0u8; 32], 0).0;
SharedSecretKey::encapsulate_deterministic(&private_keys.vpk(), &[0_u8; 32], 0).0;
// Step 3: Try to execute noop program with authentication but without initialization
let res = execute_and_prove(
@ -3630,7 +3630,7 @@ pub mod tests {
vec![private_account],
Program::serialize_instruction(instruction).unwrap(),
vec![InputAccountIdentity::PrivateAuthorizedUpdate {
ssk: SharedSecretKey::encapsulate_deterministic(&sender_keys.vpk(), &[0u8; 32], 0)
ssk: SharedSecretKey::encapsulate_deterministic(&sender_keys.vpk(), &[0_u8; 32], 0)
.0,
nsk: sender_keys.nsk,
membership_proof: (0, vec![]),
@ -3657,7 +3657,7 @@ pub mod tests {
vec![private_account],
Program::serialize_instruction(instruction).unwrap(),
vec![InputAccountIdentity::PrivateAuthorizedUpdate {
ssk: SharedSecretKey::encapsulate_deterministic(&sender_keys.vpk(), &[0u8; 32], 0)
ssk: SharedSecretKey::encapsulate_deterministic(&sender_keys.vpk(), &[0_u8; 32], 0)
.0,
nsk: sender_keys.nsk,
membership_proof: (0, vec![]),
@ -3705,7 +3705,7 @@ pub mod tests {
let instruction = (balance_to_transfer, auth_transfers.id());
let recipient =
SharedSecretKey::encapsulate_deterministic(&recipient_keys.vpk(), &[0u8; 32], 0).0;
SharedSecretKey::encapsulate_deterministic(&recipient_keys.vpk(), &[0_u8; 32], 0).0;
let mut dependencies = HashMap::new();
dependencies.insert(auth_transfers.id(), auth_transfers);
@ -3862,7 +3862,7 @@ pub mod tests {
let mut state = V03State::new_with_genesis_accounts(&[], vec![], 0).with_test_programs();
let tx = {
let (shared_secret, epk) =
SharedSecretKey::encapsulate_deterministic(&account_keys.vpk(), &[0u8; 32], 0);
SharedSecretKey::encapsulate_deterministic(&account_keys.vpk(), &[0_u8; 32], 0);
let instruction = (
block_validity_window,
@ -3931,7 +3931,7 @@ pub mod tests {
let mut state = V03State::new_with_genesis_accounts(&[], vec![], 0).with_test_programs();
let tx = {
let (shared_secret, epk) =
SharedSecretKey::encapsulate_deterministic(&account_keys.vpk(), &[0u8; 32], 0);
SharedSecretKey::encapsulate_deterministic(&account_keys.vpk(), &[0_u8; 32], 0);
let instruction = (
BlockValidityWindow::new_unbounded(),
@ -4486,9 +4486,9 @@ pub mod tests {
};
let (alice_shared_0, alice_epk_0) =
SharedSecretKey::encapsulate_deterministic(&alice_keys.vpk(), &[0u8; 32], 0);
SharedSecretKey::encapsulate_deterministic(&alice_keys.vpk(), &[0_u8; 32], 0);
let (alice_shared_1, alice_epk_1) =
SharedSecretKey::encapsulate_deterministic(&alice_keys.vpk(), &[0u8; 32], 1);
SharedSecretKey::encapsulate_deterministic(&alice_keys.vpk(), &[0_u8; 32], 1);
// Fund alice_pda_0 via authenticated_transfer directly.
{
@ -4603,7 +4603,7 @@ pub mod tests {
let message = Message::try_from_circuit_output(
vec![recipient_id],
vec![Nonce(0)],
vec![(alice_npk, alice_keys.vpk(), alice_epk_0.clone())],
vec![(alice_npk, alice_keys.vpk(), alice_epk_0)],
output,
)
.unwrap();
@ -4644,7 +4644,7 @@ pub mod tests {
let message = Message::try_from_circuit_output(
vec![recipient_id],
vec![],
vec![(alice_npk, alice_keys.vpk(), alice_epk_1.clone())],
vec![(alice_npk, alice_keys.vpk(), alice_epk_1)],
output,
)
.unwrap();

View File

@ -129,20 +129,20 @@ pub fn initial_priv_accounts_private_keys() -> Vec<PrivateAccountPrivateInitialD
secret_spending_key: SecretSpendingKey(SSK_PRIV_ACC_A),
private_key_holder: PrivateKeyHolder {
nullifier_secret_key: NSK_PRIV_ACC_A,
viewing_secret_key: ViewingSecretKey { d: VSK_PRIV_ACC_A, r: [0u8; 32] },
viewing_secret_key: ViewingSecretKey { d: VSK_PRIV_ACC_A, r: [0_u8; 32] },
},
nullifier_public_key: NullifierPublicKey(NPK_PRIV_ACC_A),
viewing_public_key: ViewingPublicKey::from_seed(&VSK_PRIV_ACC_A, &[0u8; 32]),
viewing_public_key: ViewingPublicKey::from_seed(&VSK_PRIV_ACC_A, &[0_u8; 32]),
};
let key_chain_2 = KeyChain {
secret_spending_key: SecretSpendingKey(SSK_PRIV_ACC_B),
private_key_holder: PrivateKeyHolder {
nullifier_secret_key: NSK_PRIV_ACC_B,
viewing_secret_key: ViewingSecretKey { d: VSK_PRIV_ACC_B, r: [0u8; 32] },
viewing_secret_key: ViewingSecretKey { d: VSK_PRIV_ACC_B, r: [0_u8; 32] },
},
nullifier_public_key: NullifierPublicKey(NPK_PRIV_ACC_B),
viewing_public_key: ViewingPublicKey::from_seed(&VSK_PRIV_ACC_B, &[0u8; 32]),
viewing_public_key: ViewingPublicKey::from_seed(&VSK_PRIV_ACC_B, &[0_u8; 32]),
};
vec![

View File

@ -125,7 +125,7 @@ pub unsafe extern "C" fn wallet_ffi_get_private_account_keys(
// NPK is a 32-byte array
let npk_bytes = key_chain.nullifier_public_key.0;
// VPK is a compressed secp256k1 point (33 bytes)
// VPK is an ML-KEM-768 encapsulation key (1184 bytes)
let vpk_bytes = key_chain.viewing_public_key.to_bytes();
let vpk_len = vpk_bytes.len();
let vpk_vec = vpk_bytes.to_vec();

View File

@ -71,9 +71,9 @@ impl Default for FfiAccount {
pub struct FfiPrivateAccountKeys {
/// Nullifier public key (32 bytes).
pub nullifier_public_key: FfiBytes32,
/// viewing public key (compressed secp256k1 point).
/// Viewing public key (ML-KEM-768 encapsulation key, 1184 bytes).
pub viewing_public_key: *const u8,
/// Length of viewing public key (typically 33 bytes).
/// Length of viewing public key (always 1184 bytes for ML-KEM-768).
pub viewing_public_key_len: usize,
}

View File

@ -135,11 +135,11 @@ typedef struct FfiPrivateAccountKeys {
*/
struct FfiBytes32 nullifier_public_key;
/**
* viewing public key (compressed secp256k1 point).
* Viewing public key (ML-KEM-768 encapsulation key, 1184 bytes).
*/
const uint8_t *viewing_public_key;
/**
* Length of viewing public key (typically 33 bytes).
* Length of viewing public key (always 1184 bytes for ML-KEM-768).
*/
uintptr_t viewing_public_key_len;
} FfiPrivateAccountKeys;

View File

@ -431,7 +431,7 @@ mod tests {
let acc = AccountIdentity::PrivateShared {
nsk: [0; 32],
npk: NullifierPublicKey([1; 32]),
vpk: ViewingPublicKey::from_seed(&[2u8; 32], &[3u8; 32]),
vpk: ViewingPublicKey::from_seed(&[2_u8; 32], &[3_u8; 32]),
identifier: 42,
};
assert!(acc.is_private());

View File

@ -269,7 +269,7 @@ impl WalletCore {
}
/// Set the wallet's dedicated sealing secret key.
pub fn set_sealing_secret_key(&mut self, key: key_protocol::key_management::secret_holders::ViewingSecretKey) {
pub const fn set_sealing_secret_key(&mut self, key: key_protocol::key_management::secret_holders::ViewingSecretKey) {
self.storage.key_chain_mut().set_sealing_secret_key(key);
}

View File

@ -6,7 +6,7 @@ use key_protocol::key_management::{
KeyChain,
group_key_holder::GroupKeyHolder,
key_tree::{KeyTreePrivate, KeyTreePublic, chain_index::ChainIndex, traits::KeyTreeNode as _},
secret_holders::SeedHolder,
secret_holders::{SeedHolder, ViewingSecretKey},
};
use lee::{Account, AccountId};
use lee_core::{Identifier, PrivateAccountKind};
@ -79,7 +79,7 @@ pub struct UserKeyChain {
/// Dedicated sealing secret key for GMS distribution. Generated once via
/// `wallet group new-sealing-key`. The corresponding public key is shared with
/// group members so they can seal GMS for this wallet.
sealing_secret_key: Option<lee_core::encryption::Scalar>,
sealing_secret_key: Option<ViewingSecretKey>,
}
impl UserKeyChain {
@ -509,12 +509,12 @@ impl UserKeyChain {
/// Returns the sealing secret key for GMS distribution, if it exists.
#[must_use]
pub const fn sealing_secret_key(&self) -> Option<lee_core::encryption::Scalar> {
self.sealing_secret_key
pub const fn sealing_secret_key(&self) -> Option<&ViewingSecretKey> {
self.sealing_secret_key.as_ref()
}
/// Sets the sealing secret key for GMS distribution.
pub const fn set_sealing_secret_key(&mut self, key: lee_core::encryption::Scalar) {
pub const fn set_sealing_secret_key(&mut self, key: ViewingSecretKey) {
self.sealing_secret_key = Some(key);
}
@ -584,7 +584,7 @@ impl UserKeyChain {
KeyChainPersistentData {
accounts,
sealing_secret_key: *sealing_secret_key,
sealing_secret_key: sealing_secret_key.clone(),
group_key_holders: group_key_holders.clone(),
shared_private_accounts: shared_private_accounts.clone(),
}

View File

@ -5,6 +5,7 @@ use key_protocol::key_management::{
key_tree::{
chain_index::ChainIndex, keys_private::ChildKeysPrivate, keys_public::ChildKeysPublic,
},
secret_holders::ViewingSecretKey,
};
use serde::{Deserialize, Serialize};
use testnet_initial_state::{PrivateAccountPrivateInitialData, PublicAccountPrivateInitialData};
@ -26,7 +27,7 @@ pub struct PersistentStorage {
pub struct KeyChainPersistentData {
pub accounts: Vec<PersistentAccountData>,
#[serde(default)]
pub sealing_secret_key: Option<lee_core::encryption::Scalar>,
pub sealing_secret_key: Option<ViewingSecretKey>,
#[serde(default)]
pub group_key_holders: BTreeMap<Label, GroupKeyHolder>,
#[serde(default)]