From f31bb465208787352f629dd1b5bf2dbc3ea27c6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9ophile=20BR=C3=89ZOT?= Date: Thu, 18 Jan 2024 11:47:44 +0100 Subject: [PATCH] WIP: fix: benches Since the breaking change of the partial coordinates, old benches do not currently work. This is due to the fact that the encryption and user policies are used in a different fashion to generate coordinates, making some combinations incompatible. This is not an easy fix (in particular, it seems difficult possible to decrypt a hybridized unitary encapsulation using a USK associated to a unique coordinate). --- benches/benches.rs | 367 ++++++++++++++++++++++----------------------- 1 file changed, 177 insertions(+), 190 deletions(-) diff --git a/benches/benches.rs b/benches/benches.rs index 394e1a39..4e5e4a0f 100644 --- a/benches/benches.rs +++ b/benches/benches.rs @@ -6,17 +6,15 @@ use criterion::{criterion_group, criterion_main, BatchSize, Criterion}; // Policy settings fn policy() -> Result { - #[cfg(not(feature = "hybridized_bench"))] let (security_level, department) = { ( DimensionBuilder::new( - "Security Level", + "Security", vec![ - ("Protected", EncryptionHint::Classic), - ("Confidential", EncryptionHint::Classic), - ("Top Secret", EncryptionHint::Classic), + ("Classic", EncryptionHint::Classic), + ("Hybridized", EncryptionHint::Hybridized), ], - true, + false, ), DimensionBuilder::new( "Department", @@ -25,32 +23,7 @@ fn policy() -> Result { ("HR", EncryptionHint::Classic), ("MKG", EncryptionHint::Classic), ("FIN", EncryptionHint::Classic), - ("CYBER", EncryptionHint::Classic), - ], - false, - ), - ) - }; - #[cfg(feature = "hybridized_bench")] - let (security_level, department) = { - ( - DimensionBuilder::new( - "Security Level", - vec![ - ("Protected", EncryptionHint::Hybridized), - ("Confidential", EncryptionHint::Hybridized), - ("Top Secret", EncryptionHint::Hybridized), - ], - true, - ), - DimensionBuilder::new( - "Department", - vec![ - ("R&D", EncryptionHint::Hybridized), - ("HR", EncryptionHint::Hybridized), - ("MKG", EncryptionHint::Hybridized), - ("FIN", EncryptionHint::Hybridized), - ("CYBER", EncryptionHint::Hybridized), + ("CYB", EncryptionHint::Classic), ], false, ), @@ -106,104 +79,62 @@ fn bench_policy_editing(c: &mut Criterion) { }); } -/// Generate access policies up to 5 partitions along with a user access policy -/// that allows decrypting headers for all these access policies. -/// -/// Access policies with more than one partition are generated only if -/// `--features full_bench` is passed. -/// -/// Access policies with hybridization hints are generated only if -/// `--features hybridized_bench` is passed -fn get_access_policies() -> (Vec, Vec) { - // Access policy with 1 partition - #[allow(unused_mut)] - let mut access_policies = - vec![ - AccessPolicy::from_boolean_expression("Department::FIN && Security Level::Protected") - .unwrap(), - ]; - - #[cfg(feature = "full_bench")] - { - // Access policy with 2 partition - access_policies.push( - AccessPolicy::from_boolean_expression( - "(Department::FIN && Security Level::Protected) || (Department::HR && Security \ - Level::Confidential)", - ) - .unwrap(), - ); - - // Access policy with 3 partition - access_policies.push( - AccessPolicy::from_boolean_expression( - "(Department::FIN && Security Level::Protected) || ((Department::HR || \ - Department::MKG) && Security Level::Confidential)", +/// Generates encryption policies up to 5 partitions, Hybridized if `is_hybridized` is set to +/// `true`. +fn get_encryption_policy(n_coordinates: usize, is_hybridized: bool) -> AccessPolicy { + let base_ap = if is_hybridized { + AccessPolicy::from_boolean_expression("Security::Hybridized").unwrap() + } else { + AccessPolicy::from_boolean_expression("Security::Classic").unwrap() + }; + match n_coordinates { + 1 => base_ap, + 2 => AccessPolicy::from_boolean_expression("Department::FIN").unwrap() & base_ap.clone() | base_ap, + 3 => AccessPolicy::from_boolean_expression( + "Department::FIN || Department::MKG || Department::HR", ) - .unwrap(), - ); - - // Access policy with 4 partition - access_policies.push( - AccessPolicy::from_boolean_expression( - "(Department::FIN && Security Level::Protected) || ((Department::HR || \ - Department::MKG || Department::R&D) && Security Level::Confidential)", + .unwrap() + & base_ap, + 4 => AccessPolicy::from_boolean_expression( + "Department::FIN || Department::MKG || Department::HR || Department::R&D", ) - .unwrap(), - ); - - // Access policy with 5 partition - access_policies.push( - AccessPolicy::from_boolean_expression( - "(Department::FIN && Security Level::Protected) || ((Department::HR || \ - Department::MKG || Department::R&D) && Security Level::Confidential) || \ - (Department::HR && Security Level::Top Secret)", + .unwrap() + & base_ap, + 5 => AccessPolicy::from_boolean_expression( + "Department::FIN || Department::MKG || Department::HR || Department::R&D || Department::CYB", ) - .unwrap(), - ); + .unwrap() + & base_ap, + _ => panic!("cannot generate encryption policy for {n_coordinates} coordinates"), } +} - // The intersection between the user access policies and the encryption - // policies is always "Department::FIN && Security Level::Protected" only. - #[allow(unused_mut)] - let mut user_access_policies = - vec![ - AccessPolicy::from_boolean_expression("Department::FIN && Security Level::Protected") - .unwrap(), - ]; - - #[cfg(feature = "full_bench")] - { - user_access_policies.push( - AccessPolicy::from_boolean_expression( - "(Department::FIN && Department::MKG) && Security Level::Protected", +fn get_user_policy(n_coordinates: usize, is_hybridized: bool) -> AccessPolicy { + let base_ap = if is_hybridized { + AccessPolicy::from_boolean_expression("Security::Hybridized").unwrap() + } else { + AccessPolicy::from_boolean_expression("Security::Classic").unwrap() + }; + match n_coordinates { + 2 => AccessPolicy::from_boolean_expression("Department::FIN || Department::MKG").unwrap() + | base_ap, + 3 => AccessPolicy::from_boolean_expression( + "Department::FIN || Department::MKG || Department::HR", ) - .unwrap(), - ); - user_access_policies.push( - AccessPolicy::from_boolean_expression( - "(Department::FIN && Department::MKG && Department::HR) && Security \ - Level::Protected", + .unwrap() + | base_ap, + 4 => AccessPolicy::from_boolean_expression( + "Department::FIN || Department::MKG || Department::HR || Department::R&D", ) - .unwrap(), - ); - user_access_policies.push( - AccessPolicy::from_boolean_expression( - "(Department::R&D && Department::FIN && Department::MKG && Department::HR) && \ - Security Level::Protected", + .unwrap() + | base_ap, + 5 => AccessPolicy::from_boolean_expression( + "Department::FIN || Department::MKG || Department::HR || Department::R&D || Department::CYB", ) - .unwrap(), - ); - user_access_policies.push( - AccessPolicy::from_boolean_expression( - "(Department::R&D && Department::FIN && Department::MKG && Department::HR && \ - Department::CYBER) && Security Level::Protected", - ) - .unwrap(), - ); + .unwrap() + | base_ap, + _ => panic!("cannot generate encryption policy for {n_coordinates} coordinates"), } - - (user_access_policies, access_policies) } #[cfg(feature = "full_bench")] @@ -211,7 +142,6 @@ fn bench_serialization(c: &mut Criterion) { use cosmian_crypto_core::bytes_ser_de::Serializable; let policy = policy().expect("cannot generate policy"); - let (user_access_policies, access_policies) = get_access_policies(); let cover_crypt = Covercrypt::default(); let (msk, mpk) = cover_crypt .generate_master_keys(&policy) @@ -219,29 +149,48 @@ fn bench_serialization(c: &mut Criterion) { println!("bench header encryption size: "); - for (i, access_policy) in access_policies.iter().enumerate() { - let (_, encrypted_header) = - EncryptedHeader::generate(&cover_crypt, &policy, &mpk, access_policy, None, None) - .expect("cannot encrypt header 1"); + #[cfg(feature = "hybridized_bench")] + let is_hybridized = true; + #[cfg(not(feature = "hybridized_bench"))] + let is_hybridized = false; + + for n_coordinates in 1..=5 { + let (_, encrypted_header) = EncryptedHeader::generate( + &cover_crypt, + &policy, + &mpk, + &get_encryption_policy(n_coordinates, is_hybridized), + None, + None, + ) + .expect("cannot encrypt header 1"); println!( - "{} partition(s): {} bytes", - i + 1, + "{} coordinate(s): {} bytes", + n_coordinates + 1, encrypted_header.serialize().unwrap().len(), ); } - for (i, ap) in user_access_policies.iter().enumerate() { + for n_coordinates in 1..=5 { let usk = cover_crypt - .generate_user_secret_key(&msk, ap, &policy) + .generate_user_secret_key( + &msk, + &get_user_policy(n_coordinates, is_hybridized), + &policy, + ) .unwrap(); println!( - "{} usk partition(s): {} bytes", - i + 1, + "{} usk coordinate(s): {} bytes", + n_coordinates + 1, usk.serialize().unwrap().len(), ); } + // Bench the serialization of the MSK, MPK and a USK with only one coordinate. { + let usk = cover_crypt + .generate_user_secret_key(&msk, &get_user_policy(1, is_hybridized), &policy) + .unwrap(); let mut group = c.benchmark_group("Key serialization"); group.bench_function("MSK", |b| { b.iter(|| msk.serialize().expect("cannot serialize msk")); @@ -249,117 +198,155 @@ fn bench_serialization(c: &mut Criterion) { group.bench_function("MPK", |b| { b.iter(|| mpk.serialize().expect("cannot serialize mpk")); }); - - let usk = cover_crypt - .generate_user_secret_key(&msk, &user_access_policies[0], &policy) - .unwrap(); - group.bench_function("USK 1 partition", |b| { + group.bench_function("USK 1 coordinate", |b| { b.iter(|| usk.serialize().expect("cannot serialize usk")); }); } - let mut group = c.benchmark_group("Header serialization"); - for (n_partition, access_policy) in access_policies.iter().enumerate() { - let (_, encrypted_header) = - EncryptedHeader::generate(&cover_crypt, &policy, &mpk, access_policy, None, None) - .expect("cannot encrypt header 1"); - group.bench_function(&format!("{} partition(s)", n_partition + 1), |b| { - b.iter(|| { - encrypted_header.serialize().unwrap_or_else(|_| { - panic!( - "cannot serialize header for {} partition(s)", - n_partition + 1 - ) - }) + // Bench the serialization of the header for two to five coordinates. + { + let mut group = c.benchmark_group("Header serialization"); + for n_coordinates in 2..=5 { + let (_, encrypted_header) = EncryptedHeader::generate( + &cover_crypt, + &policy, + &mpk, + &get_encryption_policy(n_coordinates, is_hybridized), + None, + None, + ) + .expect("cannot encrypt header 1"); + group.bench_function( + &format!("Header serialization with {} coordinate(s)", n_coordinates), + |b| { + b.iter(|| { + encrypted_header.serialize().unwrap_or_else(|_| { + panic!("cannot serialize header for {} partition(s)", n_coordinates) + }) + }); + }, + ); + } + } + + // Bench the serialization of the USK for two to five coordinates. + { + let mut group = c.benchmark_group("USK serialization"); + for n_coordinates in 2..=5 { + let usk = cover_crypt + .generate_user_secret_key( + &msk, + &get_user_policy(n_coordinates, is_hybridized), + &policy, + ) + .unwrap(); + group.bench_function(&format!("USK with {} coordinate(s)", n_coordinates), |b| { + b.iter(|| { + usk.serialize().unwrap_or_else(|_| { + panic!("cannot serialize header for {} partition(s)", n_coordinates) + }) + }); }); - }); + } } } fn bench_header_encryption(c: &mut Criterion) { let policy = policy().expect("cannot generate policy"); - let (_, access_policies) = get_access_policies(); let cover_crypt = Covercrypt::default(); let (_, mpk) = cover_crypt .generate_master_keys(&policy) .expect("cannot generate master keys"); + #[cfg(feature = "hybridized_bench")] + let is_hybridized = true; + #[cfg(not(feature = "hybridized_bench"))] + let is_hybridized = false; + let mut group = c.benchmark_group("Header encryption"); - for (n_partition, access_policy) in access_policies.iter().enumerate() { - group.bench_function( - &format!("{} partition(s), 1 access", n_partition + 1), - |b| { - b.iter(|| { - EncryptedHeader::generate( - &cover_crypt, - &policy, - &mpk, - access_policy, - None, - None, - ) - .unwrap_or_else(|_| { - panic!("cannot encrypt header for {} partition(s)", n_partition + 1) - }) - }); - }, - ); + for n_coordinates in 1..=5 { + group.bench_function(&format!("{} coordinates(s)", n_coordinates), |b| { + b.iter(|| { + EncryptedHeader::generate( + &cover_crypt, + &policy, + &mpk, + &get_encryption_policy(n_coordinates, is_hybridized), + None, + None, + ) + .unwrap_or_else(|_| { + panic!("cannot encrypt header for {} partition(s)", n_coordinates) + }) + }); + }); } } fn bench_header_decryption(c: &mut Criterion) { let policy = policy().expect("cannot generate policy"); let authenticated_data = vec![1, 2, 3, 4, 5, 6, 7, 8, 9]; - let (user_access_policies, access_policies) = get_access_policies(); let cover_crypt = Covercrypt::default(); let (msk, mpk) = cover_crypt .generate_master_keys(&policy) .expect("cannot generate master keys"); + + #[cfg(feature = "hybridized_bench")] + let is_hybridized = true; + #[cfg(not(feature = "hybridized_bench"))] + let is_hybridized = false; + let mut group = c.benchmark_group("Header encryption and decryption"); - for (n_user, user_access_policy) in user_access_policies.iter().enumerate() { - for (n_partition_ct, access_policy) in access_policies.iter().enumerate() { + for n_user_coordinates in 1..=5 { + for n_encapsulations in 1..=5 { group.bench_function( &format!( - "ciphertexts with {} partition(s), usk with {} partitions", - n_partition_ct + 1, - n_user + 1 + "Encpasulations with {} coordinates(s), USK with {} coordinate(s)", + n_encapsulations, n_user_coordinates ), |b| { b.iter_batched( || { + // Setup: creates the USK and encapsulation with the correct number of + // coordinates. let usk = cover_crypt - .generate_user_secret_key(&msk, user_access_policy, &policy) + .generate_user_secret_key( + &msk, + &get_user_policy(n_user_coordinates, is_hybridized), + &policy, + ) .expect("cannot generate user private key"); let (_, encrypted_header) = EncryptedHeader::generate( &cover_crypt, &policy, &mpk, - access_policy, + &get_encryption_policy(n_encapsulations, is_hybridized), None, Some(&authenticated_data), ) .unwrap_or_else(|_| { panic!( - "cannot encrypt header for {} ciphertext partition(s), {} usk \ - partition(s)", - n_partition_ct + 1, - n_user + "cannot encrypt header for {} ciphertext coordinate(s)", + n_encapsulations, ) }); - (usk, encrypted_header) - }, - |(usk, encrypted_header)| { encrypted_header .decrypt(&cover_crypt, &usk, Some(&authenticated_data)) .unwrap_or_else(|_| { panic!( - "cannot decrypt header for {} ciphertext partition(s), {} \ - usk partition(s)", - n_partition_ct + 1, - n_user + "cannot decrypt header for {} ciphertext partition(s), {} usk partition(s)", + n_encapsulations, n_user_coordinates ) }); + (usk, encrypted_header) }, + + |(usk, encrypted_header)| { + encrypted_header + .decrypt(&cover_crypt, &usk, Some(&authenticated_data)) + .unwrap(); + }, + BatchSize::SmallInput, ); },