diff --git a/src/kem/kyber768.rs b/src/kem/kyber768.rs index 9726b510f..0437b5bef 100644 --- a/src/kem/kyber768.rs +++ b/src/kem/kyber768.rs @@ -1,15 +1,17 @@ mod arithmetic; mod compress; +mod constant_time_ops; +mod conversions; mod ind_cpa; mod ntt; mod parameters; mod sampling; mod serialize; -mod conversions; -mod constant_time_ops; +use constant_time_ops::{ + compare_ciphertexts_in_constant_time, select_shared_secret_in_constant_time, +}; use conversions::ArrayConversion; -use constant_time_ops::{compare_ciphertexts_in_constant_time, select_shared_secret_in_constant_time}; use parameters::{ hash_functions::{G, H, H_DIGEST_SIZE, KDF}, @@ -84,7 +86,8 @@ pub fn decapsulate( let decrypted = ind_cpa::decrypt(&ind_cpa_secret_key.as_array(), &ciphertext); - let mut to_hash: [u8; CPA_PKE_MESSAGE_SIZE + H_DIGEST_SIZE] = decrypted.as_ref().into_padded_array(); + let mut to_hash: [u8; CPA_PKE_MESSAGE_SIZE + H_DIGEST_SIZE] = + decrypted.as_ref().into_padded_array(); to_hash[CPA_PKE_MESSAGE_SIZE..].copy_from_slice(ind_cpa_public_key_hash); let hashed = G(&to_hash); @@ -103,7 +106,8 @@ pub fn decapsulate( implicit_rejection_value.as_array() }; - let mut to_hash: [u8; SHARED_SECRET_SIZE + H_DIGEST_SIZE] = to_hash.as_ref().into_padded_array(); + let mut to_hash: [u8; SHARED_SECRET_SIZE + H_DIGEST_SIZE] = + to_hash.as_ref().into_padded_array(); to_hash[SHARED_SECRET_SIZE..].copy_from_slice(&H(&ciphertext)); KDF(&to_hash) diff --git a/src/kem/kyber768/constant_time_ops.rs b/src/kem/kyber768/constant_time_ops.rs index bf16f2779..bf2d28596 100644 --- a/src/kem/kyber768/constant_time_ops.rs +++ b/src/kem/kyber768/constant_time_ops.rs @@ -1,6 +1,5 @@ use crate::kem::kyber768::{CIPHERTEXT_SIZE, SHARED_SECRET_SIZE}; - // TODO: Attribute this to RustCrypto #[inline] fn is_non_zero(value: u8) -> u8 { @@ -14,7 +13,7 @@ pub(crate) fn compare_ciphertexts_in_constant_time(lhs: &[u8], rhs: &[u8]) -> u8 debug_assert_eq!(lhs.len(), rhs.len()); debug_assert_eq!(lhs.len(), CIPHERTEXT_SIZE); - let mut r : u8 = 0; + let mut r: u8 = 0; for i in 0..CIPHERTEXT_SIZE { r |= lhs[i] ^ rhs[i]; } @@ -23,7 +22,11 @@ pub(crate) fn compare_ciphertexts_in_constant_time(lhs: &[u8], rhs: &[u8]) -> u8 } // Select |lhs| if |selector| == 0, |rhs| otherwise. -pub(crate) fn select_shared_secret_in_constant_time(lhs: &[u8], rhs: &[u8], selector: u8) -> [u8; SHARED_SECRET_SIZE] { +pub(crate) fn select_shared_secret_in_constant_time( + lhs: &[u8], + rhs: &[u8], + selector: u8, +) -> [u8; SHARED_SECRET_SIZE] { debug_assert_eq!(lhs.len(), rhs.len()); debug_assert_eq!(lhs.len(), SHARED_SECRET_SIZE); diff --git a/src/kem/kyber768/ind_cpa.rs b/src/kem/kyber768/ind_cpa.rs index 5659f5758..614cc7d78 100644 --- a/src/kem/kyber768/ind_cpa.rs +++ b/src/kem/kyber768/ind_cpa.rs @@ -3,7 +3,7 @@ use crate::kem::kyber768::conversions::{ }; use crate::kem::kyber768::{ - arithmetic::{KyberPolynomialRingElement, barrett_reduce}, + arithmetic::{barrett_reduce, KyberPolynomialRingElement}, compress::{compress, decompress}, ntt::{ kyber_polynomial_ring_element_mod::{invert_ntt, ntt_representation}, @@ -170,17 +170,14 @@ pub(crate) fn generate_keypair( // pk := (Encode_12(tˆ mod^{+}q) || ρ) let public_key_serialized = UpdatableArray::new([0u8; CPA_PKE_PUBLIC_KEY_SIZE]) - .push(&encode_12(t_as_ntt)) - .push(seed_for_A) - .array(); + .push(&encode_12(t_as_ntt)) + .push(seed_for_A) + .array(); // sk := Encode_12(sˆ mod^{+}q) let secret_key_serialized = encode_12(secret_as_ntt); - Ok(KeyPair::new( - secret_key_serialized, - public_key_serialized, - )) + Ok(KeyPair::new(secret_key_serialized, public_key_serialized)) } fn compress_then_encode_u( diff --git a/tests/kyber768.rs b/tests/kyber768.rs index a82883092..d4858b70d 100644 --- a/tests/kyber768.rs +++ b/tests/kyber768.rs @@ -1,14 +1,14 @@ use libcrux::{ + digest::{self, sha3_256, shake256}, drbg::{Drbg, RngCore}, kem::{self, Algorithm}, - digest::{self, sha3_256, shake256} }; const SHARED_SECRET_SIZE: usize = 32; const SECRET_KEY_SIZE: usize = 2400; const CIPHERTEXT_SIZE: u32 = 1088; -const SECRET_KEY_REJECTION_VALUE_POSITION : usize = SECRET_KEY_SIZE - SHARED_SECRET_SIZE; +const SECRET_KEY_REJECTION_VALUE_POSITION: usize = SECRET_KEY_SIZE - SHARED_SECRET_SIZE; #[test] fn consistency() { @@ -57,8 +57,10 @@ fn modified_ciphertext() { // failing. } -fn compute_implicit_rejection_shared_secret(ciphertext : [u8; CIPHERTEXT_SIZE as usize], implicit_rejection_value : [u8; SHARED_SECRET_SIZE]) -> [u8; SHARED_SECRET_SIZE] -{ +fn compute_implicit_rejection_shared_secret( + ciphertext: [u8; CIPHERTEXT_SIZE as usize], + implicit_rejection_value: [u8; SHARED_SECRET_SIZE], +) -> [u8; SHARED_SECRET_SIZE] { let mut to_hash = [0u8; SHARED_SECRET_SIZE + digest::digest_size(digest::Algorithm::Sha3_256)]; to_hash[0..SHARED_SECRET_SIZE].copy_from_slice(&implicit_rejection_value); @@ -67,7 +69,6 @@ fn compute_implicit_rejection_shared_secret(ciphertext : [u8; CIPHERTEXT_SIZE as shake256(&to_hash) } - #[test] fn modified_secret_key() { let mut drbg = Drbg::new(digest::Algorithm::Sha256).unwrap(); @@ -91,7 +92,12 @@ fn modified_secret_key() { assert_ne!(shared_secret, shared_secret_decapsulated); - let implicit_rejection_shared_secret = compute_implicit_rejection_shared_secret(ciphertext.try_into().unwrap(), secret_key[(SECRET_KEY_SIZE - SHARED_SECRET_SIZE)..].try_into().unwrap()); + let implicit_rejection_shared_secret = compute_implicit_rejection_shared_secret( + ciphertext.try_into().unwrap(), + secret_key[(SECRET_KEY_SIZE - SHARED_SECRET_SIZE)..] + .try_into() + .unwrap(), + ); assert_eq!(shared_secret_decapsulated, implicit_rejection_shared_secret); } @@ -121,7 +127,9 @@ fn modified_ciphertext_and_implicit_rejection_value() { random_byte_for_secret_key += 1; } - let rejection_value_position: usize = ((random_u32 >> 8) % SHARED_SECRET_SIZE as u32).try_into().unwrap(); + let rejection_value_position: usize = ((random_u32 >> 8) % SHARED_SECRET_SIZE as u32) + .try_into() + .unwrap(); if let Ok((mut secret_key, public_key)) = kem::key_gen(Algorithm::Kyber768, &mut drbg) { if let Ok((_, mut ciphertext)) = @@ -131,14 +139,23 @@ fn modified_ciphertext_and_implicit_rejection_value() { let shared_secret_decapsulated = kem::decapsulate(Algorithm::Kyber768, &ciphertext, &secret_key).unwrap(); - secret_key[SECRET_KEY_REJECTION_VALUE_POSITION + rejection_value_position] ^= random_byte_for_secret_key; + secret_key[SECRET_KEY_REJECTION_VALUE_POSITION + rejection_value_position] ^= + random_byte_for_secret_key; let shared_secret_decapsulated_1 = kem::decapsulate(Algorithm::Kyber768, &ciphertext, &secret_key).unwrap(); assert_ne!(shared_secret_decapsulated, shared_secret_decapsulated_1); - let implicit_rejection_shared_secret = compute_implicit_rejection_shared_secret(ciphertext.try_into().unwrap(), secret_key[SECRET_KEY_REJECTION_VALUE_POSITION..].try_into().unwrap()); - assert_eq!(shared_secret_decapsulated_1, implicit_rejection_shared_secret); + let implicit_rejection_shared_secret = compute_implicit_rejection_shared_secret( + ciphertext.try_into().unwrap(), + secret_key[SECRET_KEY_REJECTION_VALUE_POSITION..] + .try_into() + .unwrap(), + ); + assert_eq!( + shared_secret_decapsulated_1, + implicit_rejection_shared_secret + ); } } // If the randomness was not enough for the rejection sampling step