diff --git a/lee/key_protocol/src/key_management/group_key_holder.rs b/lee/key_protocol/src/key_management/group_key_holder.rs index 70d503ac..4f324ba2 100644 --- a/lee/key_protocol/src/key_management/group_key_holder.rs +++ b/lee/key_protocol/src/key_management/group_key_holder.rs @@ -150,7 +150,7 @@ impl GroupKeyHolder { /// /// Uses ML-KEM-768 encapsulation to derive a shared secret, then AES-256-GCM to encrypt /// the payload. The returned bytes are - /// `kem_ciphertext (1088) || nonce (12) || ciphertext+tag (48)` = 1148 bytes. + /// `kem_ciphertext (ML_KEM_768_CIPHERTEXT_LEN) || nonce (12) || ciphertext+tag (48)`. /// /// Each call generates a fresh KEM encapsulation, so two seals of the same holder produce /// different ciphertexts. @@ -186,7 +186,7 @@ impl GroupKeyHolder { /// Returns `Err` if the ciphertext is too short or the AES-GCM authentication tag /// doesn't verify (wrong key or tampered data). pub fn unseal(sealed: &[u8], own_key: &SealingSecretKey) -> Result { - // kem_ciphertext (1088) + nonce (12) = header, then AES-GCM tag (16) minimum. + // kem_ciphertext (ML_KEM_768_CIPHERTEXT_LEN) + nonce (12) = header, then AES-GCM tag (16) minimum. const HEADER_LEN: usize = ML_KEM_768_CIPHERTEXT_LEN + 12; const MIN_LEN: usize = HEADER_LEN + 16; diff --git a/lee/key_protocol/src/key_management/key_tree/keys_private.rs b/lee/key_protocol/src/key_management/key_tree/keys_private.rs index e2b982cc..48b47975 100644 --- a/lee/key_protocol/src/key_management/key_tree/keys_private.rs +++ b/lee/key_protocol/src/key_management/key_tree/keys_private.rs @@ -150,6 +150,7 @@ mod tests { ], ); + // Length matches MlKem768EncapsulationKey::LEN. let expected_vpk: [u8; 1184] = [ 127, 229, 162, 212, 104, 117, 4, 150, 192, 103, 122, 195, 14, 35, 12, 60, 52, 23, 220, 150, 100, 203, 34, 34, 127, 232, 156, 43, 218, 109, 6, 160, 67, 35, 210, 194, 25, 181, @@ -257,6 +258,7 @@ mod tests { ], ); + // Length matches MlKem768EncapsulationKey::LEN. let expected_vpk: [u8; 1184] = [ 215, 229, 207, 120, 148, 177, 148, 197, 72, 222, 134, 3, 231, 146, 123, 226, 36, 84, 232, 179, 205, 16, 241, 142, 9, 81, 58, 54, 12, 115, 148, 182, 19, 245, 22, 203, 57, diff --git a/lee/key_protocol/src/key_management/secret_holders.rs b/lee/key_protocol/src/key_management/secret_holders.rs index 4035080d..b8225a4b 100644 --- a/lee/key_protocol/src/key_management/secret_holders.rs +++ b/lee/key_protocol/src/key_management/secret_holders.rs @@ -153,7 +153,7 @@ impl From<&ViewingSecretKey> for ViewingPublicKey { seed_bytes[32..].copy_from_slice(&sk.z); let dk = ::DecapsulationKey::from_seed(Seed::from(seed_bytes)); Self::from_bytes(dk.encapsulation_key().to_bytes().to_vec()) - .expect("key_protocol::secret_holders::From<&ViewingSecretKey>: ML-KEM-768 encapsulation key is always 1184 bytes") + .expect("key_protocol::secret_holders::From<&ViewingSecretKey>: ML-KEM-768 encapsulation key is always ViewingPublicKey::LEN bytes") } } diff --git a/lee/state_machine/core/src/encryption/shared_key_derivation.rs b/lee/state_machine/core/src/encryption/shared_key_derivation.rs index 71cd8ab5..d87e4107 100644 --- a/lee/state_machine/core/src/encryption/shared_key_derivation.rs +++ b/lee/state_machine/core/src/encryption/shared_key_derivation.rs @@ -64,7 +64,7 @@ impl SharedSecretKey { let ek_bytes: ml_kem::kem::Key = ek.0.as_slice() .try_into() - .expect("MlKem768EncapsulationKey must be 1184 bytes"); + .expect("MlKem768EncapsulationKey must be MlKem768EncapsulationKey::LEN bytes"); let ek_obj = ml_kem::EncapsulationKey768::new(&ek_bytes).expect( "MlKem768EncapsulationKey bytes must encode a valid ML-KEM-768 encapsulation key", ); @@ -104,7 +104,7 @@ impl SharedSecretKey { let ek_bytes: ml_kem::kem::Key = ek.0.as_slice() .try_into() - .expect("MlKem768EncapsulationKey must be 1184 bytes"); + .expect("MlKem768EncapsulationKey must be MlKem768EncapsulationKey::LEN bytes"); let ek_obj = ml_kem::EncapsulationKey768::new(&ek_bytes).expect( "MlKem768EncapsulationKey bytes must encode a valid ML-KEM-768 encapsulation key", ); @@ -118,7 +118,7 @@ impl SharedSecretKey { /// Receiver: decapsulate the shared secret from a KEM ciphertext. /// - /// Returns `None` if the `EphemeralPublicKey` is not exactly 1088 bytes — callers on + /// Returns `None` if the `EphemeralPublicKey` is not exactly [`ML_KEM_768_CIPHERTEXT_LEN`] bytes — callers on /// the wallet scan path should skip the output rather than panic on malformed chain data. /// /// `d` and `z` are the two 32-byte halves of the FIPS 203 `ViewingSecretKey` seed. @@ -168,12 +168,12 @@ mod tests { assert_eq!( epk.0.len(), ML_KEM_768_CIPHERTEXT_LEN, - "ML-KEM-768 ciphertext is 1088 bytes" + "ML-KEM-768 ciphertext length" ); assert_eq!( ek.0.len(), - 1184, - "ML-KEM-768 encapsulation key is 1184 bytes" + MlKem768EncapsulationKey::LEN, + "ML-KEM-768 encapsulation key length" ); } @@ -182,14 +182,14 @@ mod tests { let d = [1_u8; 32]; let z = [2_u8; 32]; - // Too short — 100 bytes instead of 1088. + // Too short — 100 bytes instead of ML_KEM_768_CIPHERTEXT_LEN. let short_epk = EphemeralPublicKey(vec![42_u8; 100]); assert!( SharedSecretKey::decapsulate(&short_epk, &d, &z).is_none(), "short EphemeralPublicKey must return None" ); - // Too long — 1089 bytes instead of 1088. + // Too long — ML_KEM_768_CIPHERTEXT_LEN + 1. let long_epk = EphemeralPublicKey(vec![42_u8; ML_KEM_768_CIPHERTEXT_LEN + 1]); assert!( SharedSecretKey::decapsulate(&long_epk, &d, &z).is_none(),