From 8e9928fef69038b901c17d456cc8fbec654e346b Mon Sep 17 00:00:00 2001 From: Hugo Rosenkranz-Costa Date: Thu, 11 Jan 2024 17:11:16 +0100 Subject: [PATCH] refacto: move `refresh` logic to an iterator struct --- benches/benches.rs | 65 ++-- src/core/primitives.rs | 94 ++++-- src/core/serialization.rs | 6 +- src/data_struct/README.md | 311 +----------------- src/data_struct/{revision_list.rs => list.rs} | 44 +-- src/data_struct/mod.rs | 4 +- src/data_struct/revision_map.rs | 20 +- src/data_struct/revision_vec.rs | 33 +- 8 files changed, 168 insertions(+), 409 deletions(-) rename src/data_struct/{revision_list.rs => list.rs} (87%) diff --git a/benches/benches.rs b/benches/benches.rs index a0ede274..394e1a39 100644 --- a/benches/benches.rs +++ b/benches/benches.rs @@ -310,57 +310,58 @@ fn bench_header_encryption(c: &mut Criterion) { 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_policy, access_policies) = get_access_policies(); + 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"); - let user_decryption_keys: Vec<_> = user_access_policy - .iter() - .map(|ap| { - cover_crypt - .generate_user_secret_key(&msk, ap, &policy) - .expect("cannot generate user private key") - }) - .collect(); let mut group = c.benchmark_group("Header encryption and decryption"); - for (n_partitions_usk, usk) in user_decryption_keys.iter().enumerate() { + for (n_user, user_access_policy) in user_access_policies.iter().enumerate() { for (n_partition_ct, access_policy) in access_policies.iter().enumerate() { group.bench_function( &format!( "ciphertexts with {} partition(s), usk with {} partitions", n_partition_ct + 1, - n_partitions_usk + 1 + n_user + 1 ), |b| { - b.iter(|| { - let (_, encrypted_header) = EncryptedHeader::generate( - &cover_crypt, - &policy, - &mpk, - access_policy, - None, - Some(&authenticated_data), - ) - .unwrap_or_else(|_| { - panic!( - "cannot encrypt header for {} ciphertext partition(s), {} usk \ - partition(s)", - n_partition_ct + 1, - n_partitions_usk + b.iter_batched( + || { + let usk = cover_crypt + .generate_user_secret_key(&msk, user_access_policy, &policy) + .expect("cannot generate user private key"); + let (_, encrypted_header) = EncryptedHeader::generate( + &cover_crypt, + &policy, + &mpk, + access_policy, + None, + Some(&authenticated_data), ) - }); - encrypted_header - .decrypt(&cover_crypt, usk, Some(&authenticated_data)) .unwrap_or_else(|_| { panic!( - "cannot decrypt header for {} ciphertext partition(s), {} usk \ + "cannot encrypt header for {} ciphertext partition(s), {} usk \ partition(s)", n_partition_ct + 1, - n_partitions_usk + n_user ) }); - }); + (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 + ) + }); + }, + BatchSize::SmallInput, + ); }, ); } diff --git a/src/core/primitives.rs b/src/core/primitives.rs index f6d91d10..49016f7a 100644 --- a/src/core/primitives.rs +++ b/src/core/primitives.rs @@ -25,7 +25,7 @@ use crate::{ EncryptionHint, Partition, }, core::{Encapsulation, KeyEncapsulation, MasterPublicKey, MasterSecretKey, UserSecretKey}, - data_struct::{Cursor, RevisionMap, RevisionVec}, + data_struct::{List, RevisionMap, RevisionVec}, Error, }; @@ -444,6 +444,54 @@ pub fn prune(msk: &mut MasterSecretKey, coordinates: &HashSet) -> Res Ok(()) } +struct Merge<'a, M, U> { + msk_subkeys: M, + usk_subkeys: U, + usk_first_subkey: &'a SecretSubkey, + prepend: bool, +} + +impl<'a, M, U> Merge<'a, M, U> +where + M: Iterator, + U: Iterator, +{ + pub fn new(msk_subkeys: M, mut usk_subkeys: U) -> Self { + let usk_first_subkey = usk_subkeys.next().expect("first key"); + Self { + msk_subkeys, + usk_subkeys, + usk_first_subkey, + prepend: true, + } + } +} + +impl<'a, M, U> Iterator for Merge<'a, M, U> +where + M: Iterator, + U: Iterator, +{ + type Item = SecretSubkey; + + fn next(&mut self) -> Option { + let msk_subkey = self.msk_subkeys.next()?; + if self.prepend { + if msk_subkey == self.usk_first_subkey { + self.prepend = false; + } + Some(msk_subkey.clone()) + } else { + let usk_subkey = self.usk_subkeys.next()?; + if msk_subkey == usk_subkey { + Some(usk_subkey.clone()) + } else { + None + } + } + } +} + /// Refresh a user key from the master secret key and the given decryption set. /// /// If `keep_old_rights` is set to false, old sub-keys are removed. @@ -463,32 +511,24 @@ pub fn refresh( ) -> Result<(), Error> { verify_user_key_kmac(msk, usk)?; - usk.subkeys - .retain(|coordinate| msk.subkeys.contains_key(coordinate)); - - for (partition, user_chain) in usk.subkeys.iter_mut() { - let master_chain = msk.subkeys.get(partition).expect("at least one key"); - // compare against all master subkeys or the last one to remove old rights - let mut master_chain = match keep_old_rights { - true => master_chain.iter().take(master_chain.len()).peekable(), - false => master_chain.iter().take(1).peekable(), - }; - - // 1 - add new master subkeys in user key if any - let user_first_key = user_chain.front().expect("have one key").clone(); - let mut cursor = Cursor::new(user_chain); - while let Some(new_master_subkey) = - master_chain.next_if(|&master_subkey| master_subkey != &user_first_key) - { - cursor = cursor.prepend(new_master_subkey.clone()); - } - - // 2 - go through the remaining matching keys between the master and user chain - cursor = cursor.skip_while(|user_subkey| Some(user_subkey) == master_chain.next()); - - // 3 - old keys in USK not present in the MSK should be removed - cursor.cutoff(); - } + usk.subkeys = usk + .subkeys + .iter() + .filter_map(|(coordinate, user_chain)| { + msk.subkeys.get(coordinate).map(|msk_chain| { + let msk_subkeys = if keep_old_rights { + msk_chain.iter().take(msk_chain.len()) + } else { + msk_chain.iter().take(1) + }; + let usk_subkeys = user_chain.iter(); + ( + coordinate.clone(), + Merge::new(msk_subkeys, usk_subkeys).collect::>(), + ) + }) + }) + .collect::>(); // Update user key KMAC usk.kmac = compute_user_key_kmac(msk, usk); diff --git a/src/core/serialization.rs b/src/core/serialization.rs index 00d952f5..f5369edd 100644 --- a/src/core/serialization.rs +++ b/src/core/serialization.rs @@ -15,7 +15,7 @@ use crate::{ Encapsulation, KeyEncapsulation, MasterPublicKey, MasterSecretKey, UserSecretKey, SYM_KEY_LENGTH, }, - data_struct::{RevisionList, RevisionMap, RevisionVec}, + data_struct::{List, RevisionMap, RevisionVec}, CleartextHeader, EncryptedHeader, Error, }; @@ -151,7 +151,7 @@ impl Serializable for MasterSecretKey { for _ in 0..n_partitions { let partition = Partition::from(de.read_vec()?); let n_keys = ::try_from(de.read_leb128_u64()?)?; - let chain: Result, Self::Error> = (0..n_keys) + let chain: Result, Self::Error> = (0..n_keys) .map(|_| { let sk_i = deserialize_option!(de, KyberSecretKey(de.read_array()?)); let x_i = de.read_array::<{ R25519PrivateKey::LENGTH }>()?; @@ -224,7 +224,7 @@ impl Serializable for UserSecretKey { let partition = Partition::from(de.read_vec()?); // read all keys forming a chain and inserting them all at once. let n_keys = ::try_from(de.read_leb128_u64()?)?; - let new_chain: Result, _> = (0..n_keys) + let new_chain: Result, _> = (0..n_keys) .map(|_| { let sk_i = deserialize_option!(de, KyberSecretKey(de.read_array()?)); let x_i = de.read_array::<{ R25519PrivateKey::LENGTH }>()?; diff --git a/src/data_struct/README.md b/src/data_struct/README.md index 2630c34d..035d222a 100644 --- a/src/data_struct/README.md +++ b/src/data_struct/README.md @@ -74,314 +74,17 @@ Cons: - serialization requires following each linked list -### RevisionList +### List -A `RevisionList` is a linked list with only next pointers. +A `List` is a linked list with only next pointers. It provided a `Cursor` interface to access and modify the elements while following the next pointers. This type of interface is not available in stable Rust `LinkedList`. It is used by both the `RevisionMap` and `RevisionVec`. -## Benchmark - -```text -Edit Policy/edit policy time: [346.46 µs 346.72 µs 346.98 µs] - change: [-25.395% -25.260% -25.136%] (p = 0.00 < 0.05) - Performance has improved. -Found 1552 outliers among 5000 measurements (31.04%) - 675 (13.50%) low mild - 317 (6.34%) high mild - 560 (11.20%) high severe - -Header encryption/1 partition(s), 1 access - time: [98.350 µs 98.387 µs 98.425 µs] - change: [-0.7784% -0.5652% -0.3640%] (p = 0.00 < 0.05) - Change within noise threshold. -Found 215 outliers among 5000 measurements (4.30%) - 138 (2.76%) low mild - 63 (1.26%) high mild - 14 (0.28%) high severe -Header encryption/2 partition(s), 1 access - time: [151.39 µs 151.45 µs 151.51 µs] - change: [-0.5608% -0.4164% -0.2837%] (p = 0.00 < 0.05) - Change within noise threshold. -Found 368 outliers among 5000 measurements (7.36%) - 251 (5.02%) low mild - 95 (1.90%) high mild - 22 (0.44%) high severe -Header encryption/3 partition(s), 1 access - time: [201.25 µs 201.37 µs 201.50 µs] - change: [-2.2096% -2.0478% -1.8971%] (p = 0.00 < 0.05) - Performance has improved. -Found 179 outliers among 5000 measurements (3.58%) - 2 (0.04%) low mild - 144 (2.88%) high mild - 33 (0.66%) high severe -Header encryption/4 partition(s), 1 access - time: [253.42 µs 253.56 µs 253.71 µs] - change: [-2.6348% -2.4339% -2.2435%] (p = 0.00 < 0.05) - Performance has improved. -Found 127 outliers among 5000 measurements (2.54%) - 109 (2.18%) high mild - 18 (0.36%) high severe -Header encryption/5 partition(s), 1 access - time: [310.58 µs 310.68 µs 310.79 µs] - change: [-10.531% -10.397% -10.275%] (p = 0.00 < 0.05) - Performance has improved. -Found 256 outliers among 5000 measurements (5.12%) - 85 (1.70%) low mild - 152 (3.04%) high mild - 19 (0.38%) high severe - -Benchmarking Header encryption and decryption/ciphertexts with 1 partition(s), usk with 1 partitions: Collecting 5000 samples in estimated 5.2264 -Header encryption and decryption/ciphertexts with 1 partition(s), usk with 1 partitions - time: [174.62 µs 174.69 µs 174.76 µs] - change: [+0.7357% +0.7906% +0.8508%] (p = 0.00 < 0.05) - Change within noise threshold. -Found 84 outliers among 5000 measurements (1.68%) - 2 (0.04%) low mild - 61 (1.22%) high mild - 21 (0.42%) high severe -Benchmarking Header encryption and decryption/ciphertexts with 2 partition(s), usk with 1 partitions: Collecting 5000 samples in estimated 6.1381 -Header encryption and decryption/ciphertexts with 2 partition(s), usk with 1 partitions - time: [243.74 µs 243.95 µs 244.16 µs] - change: [+0.6880% +0.8225% +0.9473%] (p = 0.00 < 0.05) - Change within noise threshold. -Found 39 outliers among 5000 measurements (0.78%) - 18 (0.36%) low mild - 20 (0.40%) high mild - 1 (0.02%) high severe -Benchmarking Header encryption and decryption/ciphertexts with 3 partition(s), usk with 1 partitions: Collecting 5000 samples in estimated 6.2358 -Header encryption and decryption/ciphertexts with 3 partition(s), usk with 1 partitions - time: [312.47 µs 312.84 µs 313.21 µs] - change: [+0.7563% +0.9329% +1.1015%] (p = 0.00 < 0.05) - Change within noise threshold. -Found 12 outliers among 5000 measurements (0.24%) - 3 (0.06%) low mild - 9 (0.18%) high mild -Benchmarking Header encryption and decryption/ciphertexts with 4 partition(s), usk with 1 partitions: Collecting 5000 samples in estimated 5.6795 -Header encryption and decryption/ciphertexts with 4 partition(s), usk with 1 partitions - time: [379.10 µs 379.67 µs 380.25 µs] - change: [+0.1993% +0.4121% +0.6339%] (p = 0.00 < 0.05) - Change within noise threshold. -Found 1 outliers among 5000 measurements (0.02%) - 1 (0.02%) high mild -Benchmarking Header encryption and decryption/ciphertexts with 5 partition(s), usk with 1 partitions: Collecting 5000 samples in estimated 6.6435 -Header encryption and decryption/ciphertexts with 5 partition(s), usk with 1 partitions - time: [442.68 µs 443.41 µs 444.15 µs] - change: [-2.1034% -1.8470% -1.5882%] (p = 0.00 < 0.05) - Performance has improved. -Found 8 outliers among 5000 measurements (0.16%) - 1 (0.02%) low mild - 7 (0.14%) high mild -Benchmarking Header encryption and decryption/ciphertexts with 1 partition(s), usk with 2 partitions: Collecting 5000 samples in estimated 5.2588 -Header encryption and decryption/ciphertexts with 1 partition(s), usk with 2 partitions - time: [175.06 µs 175.12 µs 175.19 µs] - change: [-14.201% -14.151% -14.103%] (p = 0.00 < 0.05) - Performance has improved. -Found 442 outliers among 5000 measurements (8.84%) - 364 (7.28%) low mild - 64 (1.28%) high mild - 14 (0.28%) high severe -Benchmarking Header encryption and decryption/ciphertexts with 2 partition(s), usk with 2 partitions: Collecting 5000 samples in estimated 5.1292 -Header encryption and decryption/ciphertexts with 2 partition(s), usk with 2 partitions - time: [255.61 µs 256.05 µs 256.49 µs] - change: [-11.225% -11.024% -10.826%] (p = 0.00 < 0.05) - Performance has improved. -Found 3 outliers among 5000 measurements (0.06%) - 3 (0.06%) high mild -Benchmarking Header encryption and decryption/ciphertexts with 3 partition(s), usk with 2 partitions: Collecting 5000 samples in estimated 5.0856 -Header encryption and decryption/ciphertexts with 3 partition(s), usk with 2 partitions - time: [338.08 µs 338.92 µs 339.76 µs] - change: [-9.3124% -9.0137% -8.7142%] (p = 0.00 < 0.05) - Performance has improved. -Found 6 outliers among 5000 measurements (0.12%) - 5 (0.10%) high mild - 1 (0.02%) high severe -Benchmarking Header encryption and decryption/ciphertexts with 4 partition(s), usk with 2 partitions: Collecting 5000 samples in estimated 6.3907 -Header encryption and decryption/ciphertexts with 4 partition(s), usk with 2 partitions - time: [425.62 µs 426.74 µs 427.87 µs] - change: [-6.6440% -6.3037% -5.9372%] (p = 0.00 < 0.05) - Performance has improved. -Found 1 outliers among 5000 measurements (0.02%) - 1 (0.02%) high mild -Benchmarking Header encryption and decryption/ciphertexts with 5 partition(s), usk with 2 partitions: Collecting 5000 samples in estimated 5.0413 -Header encryption and decryption/ciphertexts with 5 partition(s), usk with 2 partitions - time: [501.61 µs 503.34 µs 505.08 µs] - change: [-6.5008% -6.0734% -5.6270%] (p = 0.00 < 0.05) - Performance has improved. -Found 4 outliers among 5000 measurements (0.08%) - 4 (0.08%) high mild -Benchmarking Header encryption and decryption/ciphertexts with 1 partition(s), usk with 3 partitions: Collecting 5000 samples in estimated 5.2359 -Header encryption and decryption/ciphertexts with 1 partition(s), usk with 3 partitions - time: [190.48 µs 190.90 µs 191.33 µs] - change: [-6.8449% -6.6297% -6.4037%] (p = 0.00 < 0.05) - Performance has improved. -Found 3 outliers among 5000 measurements (0.06%) - 3 (0.06%) high severe -Benchmarking Header encryption and decryption/ciphertexts with 2 partition(s), usk with 3 partitions: Collecting 5000 samples in estimated 5.4179 -Header encryption and decryption/ciphertexts with 2 partition(s), usk with 3 partitions - time: [270.74 µs 271.38 µs 272.02 µs] - change: [-11.729% -11.406% -11.088%] (p = 0.00 < 0.05) - Performance has improved. -Benchmarking Header encryption and decryption/ciphertexts with 3 partition(s), usk with 3 partitions: Collecting 5000 samples in estimated 5.5672 -Header encryption and decryption/ciphertexts with 3 partition(s), usk with 3 partitions - time: [369.57 µs 370.79 µs 372.02 µs] - change: [-8.4226% -8.0060% -7.5889%] (p = 0.00 < 0.05) - Performance has improved. -Benchmarking Header encryption and decryption/ciphertexts with 4 partition(s), usk with 3 partitions: Collecting 5000 samples in estimated 7.0293 -Header encryption and decryption/ciphertexts with 4 partition(s), usk with 3 partitions - time: [466.25 µs 467.95 µs 469.65 µs] - change: [-6.9419% -6.4231% -5.9092%] (p = 0.00 < 0.05) - Performance has improved. -Benchmarking Header encryption and decryption/ciphertexts with 5 partition(s), usk with 3 partitions: Collecting 5000 samples in estimated 5.7422 -Header encryption and decryption/ciphertexts with 5 partition(s), usk with 3 partitions - time: [572.05 µs 574.71 µs 577.37 µs] - change: [-4.8369% -4.2561% -3.6419%] (p = 0.00 < 0.05) - Performance has improved. -Found 5 outliers among 5000 measurements (0.10%) - 5 (0.10%) high mild -Benchmarking Header encryption and decryption/ciphertexts with 1 partition(s), usk with 4 partitions: Collecting 5000 samples in estimated 5.7158 -Header encryption and decryption/ciphertexts with 1 partition(s), usk with 4 partitions - time: [203.77 µs 203.91 µs 204.05 µs] - change: [+17.477% +17.567% +17.665%] (p = 0.00 < 0.05) - Performance has regressed. -Found 193 outliers among 5000 measurements (3.86%) - 4 (0.08%) low severe - 18 (0.36%) low mild - 99 (1.98%) high mild - 72 (1.44%) high severe -Benchmarking Header encryption and decryption/ciphertexts with 2 partition(s), usk with 4 partitions: Collecting 5000 samples in estimated 5.7854 -Header encryption and decryption/ciphertexts with 2 partition(s), usk with 4 partitions - time: [290.66 µs 291.63 µs 292.61 µs] - change: [+1.1010% +1.5470% +2.0449%] (p = 0.00 < 0.05) - Performance has regressed. -Found 32 outliers among 5000 measurements (0.64%) - 22 (0.44%) high mild - 10 (0.20%) high severe -Benchmarking Header encryption and decryption/ciphertexts with 3 partition(s), usk with 4 partitions: Collecting 5000 samples in estimated 6.0392 -Header encryption and decryption/ciphertexts with 3 partition(s), usk with 4 partitions - time: [398.65 µs 400.31 µs 401.94 µs] - change: [-1.0342% -0.4658% +0.0952%] (p = 0.11 > 0.05) - No change in performance detected. -Benchmarking Header encryption and decryption/ciphertexts with 4 partition(s), usk with 4 partitions: Collecting 5000 samples in estimated 5.1925 -Header encryption and decryption/ciphertexts with 4 partition(s), usk with 4 partitions - time: [518.30 µs 521.03 µs 523.79 µs] - change: [-13.757% -13.117% -12.467%] (p = 0.00 < 0.05) - Performance has improved. -Found 3 outliers among 5000 measurements (0.06%) - 2 (0.04%) high mild - 1 (0.02%) high severe -Benchmarking Header encryption and decryption/ciphertexts with 5 partition(s), usk with 4 partitions: Collecting 5000 samples in estimated 7.2000 -Header encryption and decryption/ciphertexts with 5 partition(s), usk with 4 partitions - time: [716.16 µs 720.16 µs 724.19 µs] - change: [+12.240% +13.155% +14.062%] (p = 0.00 < 0.05) - Performance has regressed. -Found 1 outliers among 5000 measurements (0.02%) - 1 (0.02%) high mild -Benchmarking Header encryption and decryption/ciphertexts with 1 partition(s), usk with 5 partitions: Collecting 5000 samples in estimated 5.9475 -Header encryption and decryption/ciphertexts with 1 partition(s), usk with 5 partitions - time: [237.56 µs 237.90 µs 238.26 µs] - change: [-11.788% -11.613% -11.448%] (p = 0.00 < 0.05) - Performance has improved. -Found 82 outliers among 5000 measurements (1.64%) - 1 (0.02%) low mild - 28 (0.56%) high mild - 53 (1.06%) high severe -Benchmarking Header encryption and decryption/ciphertexts with 2 partition(s), usk with 5 partitions: Collecting 5000 samples in estimated 5.4984 -Header encryption and decryption/ciphertexts with 2 partition(s), usk with 5 partitions - time: [365.00 µs 366.27 µs 367.53 µs] - change: [-8.4883% -8.0219% -7.5736%] (p = 0.00 < 0.05) - Performance has improved. -Benchmarking Header encryption and decryption/ciphertexts with 3 partition(s), usk with 5 partitions: Collecting 5000 samples in estimated 7.3921 -Header encryption and decryption/ciphertexts with 3 partition(s), usk with 5 partitions - time: [491.27 µs 493.30 µs 495.33 µs] - change: [-8.4819% -7.8614% -7.2815%] (p = 0.00 < 0.05) - Performance has improved. -Benchmarking Header encryption and decryption/ciphertexts with 4 partition(s), usk with 5 partitions: Collecting 5000 samples in estimated 6.2096 -Header encryption and decryption/ciphertexts with 4 partition(s), usk with 5 partitions - time: [620.44 µs 623.86 µs 627.30 µs] - change: [-5.9588% -5.2564% -4.5034%] (p = 0.00 < 0.05) - Performance has improved. -Benchmarking Header encryption and decryption/ciphertexts with 5 partition(s), usk with 5 partitions: Collecting 5000 samples in estimated 7.5536 -Header encryption and decryption/ciphertexts with 5 partition(s), usk with 5 partitions - time: [758.17 µs 762.63 µs 767.09 µs] - change: [-4.4494% -3.6664% -2.8574%] (p = 0.00 < 0.05) - Performance has improved. - -bench header encryption size: -1 partition(s): 1171 bytes -2 partition(s): 2260 bytes -3 partition(s): 3349 bytes -4 partition(s): 4438 bytes -5 partition(s): 5527 bytes -1 usk partition(s): 1286 bytes -2 usk partition(s): 2475 bytes -3 usk partition(s): 3664 bytes -4 usk partition(s): 4853 bytes -5 usk partition(s): 6042 bytes -Key serialization/MSK time: [4.4242 µs 4.4278 µs 4.4314 µs] - change: [+2.3014% +2.4893% +2.6703%] (p = 0.00 < 0.05) - Performance has regressed. -Found 83 outliers among 5000 measurements (1.66%) - 50 (1.00%) high mild - 33 (0.66%) high severe -Key serialization/MPK time: [58.964 µs 59.056 µs 59.154 µs] - change: [+0.5632% +0.7261% +0.8992%] (p = 0.00 < 0.05) - Change within noise threshold. -Found 156 outliers among 5000 measurements (3.12%) - 12 (0.24%) low mild - 91 (1.82%) high mild - 53 (1.06%) high severe -Key serialization/USK 1 partition - time: [372.12 ns 372.27 ns 372.43 ns] - change: [+4.6778% +4.7747% +4.8727%] (p = 0.00 < 0.05) - Performance has regressed. -Found 243 outliers among 5000 measurements (4.86%) - 20 (0.40%) low severe - 60 (1.20%) low mild - 86 (1.72%) high mild - 77 (1.54%) high severe - -Header serialization/1 partition(s) - time: [6.6707 µs 6.6743 µs 6.6780 µs] - change: [-0.4660% -0.3933% -0.3223%] (p = 0.00 < 0.05) - Change within noise threshold. -Found 132 outliers among 5000 measurements (2.64%) - 21 (0.42%) low mild - 96 (1.92%) high mild - 15 (0.30%) high severe -Header serialization/2 partition(s) - time: [6.9437 µs 6.9474 µs 6.9511 µs] - change: [-0.3677% -0.2924% -0.2154%] (p = 0.00 < 0.05) - Change within noise threshold. -Found 107 outliers among 5000 measurements (2.14%) - 8 (0.16%) low mild - 88 (1.76%) high mild - 11 (0.22%) high severe -Header serialization/3 partition(s) - time: [7.2540 µs 7.2573 µs 7.2606 µs] - change: [-0.2912% -0.0941% +0.0812%] (p = 0.33 > 0.05) - No change in performance detected. -Found 87 outliers among 5000 measurements (1.74%) - 1 (0.02%) low severe - 7 (0.14%) low mild - 59 (1.18%) high mild - 20 (0.40%) high severe -Header serialization/4 partition(s) - time: [7.4640 µs 7.4678 µs 7.4715 µs] - change: [-1.0412% -0.8816% -0.7317%] (p = 0.00 < 0.05) - Change within noise threshold. -Found 104 outliers among 5000 measurements (2.08%) - 20 (0.40%) low mild - 81 (1.62%) high mild - 3 (0.06%) high severe -Header serialization/5 partition(s) - time: [7.8154 µs 7.8322 µs 7.8510 µs] - change: [+0.9561% +1.1993% +1.4289%] (p = 0.00 < 0.05) - Change within noise threshold. -Found 85 outliers among 5000 measurements (1.70%) - 35 (0.70%) high mild - 50 (1.00%) high severe -``` +## Operations + +### Master Secret Key + +### User Secret Key diff --git a/src/data_struct/revision_list.rs b/src/data_struct/list.rs similarity index 87% rename from src/data_struct/revision_list.rs rename to src/data_struct/list.rs index b3232b66..32514369 100644 --- a/src/data_struct/revision_list.rs +++ b/src/data_struct/list.rs @@ -16,12 +16,12 @@ impl Element { } #[derive(Default, Debug, PartialEq, Eq)] -pub struct RevisionList { +pub struct List { pub(crate) length: usize, pub(crate) head: Link, } -impl RevisionList { +impl List { #[must_use] pub fn new() -> Self { Self { @@ -60,34 +60,34 @@ impl RevisionList { } /// Keeps the n first elements of the list and returns the removed ones. - pub fn keep(&mut self, n: usize) -> RevisionListIter { + pub fn keep(&mut self, n: usize) -> ListIter { let mut current_element = &mut self.head; for _ in 0..n { if let Some(element) = current_element { current_element = &mut element.next; } else { - return RevisionListIter::new(None); + return ListIter::new(None); } } self.length = n; - RevisionListIter::new(current_element.take()) + ListIter::new(current_element.take()) } pub fn iter(&self) -> impl Iterator { - RefRevisionListIter::new(self) + RefListIter::new(self) } } -impl IntoIterator for RevisionList { - type IntoIter = RevisionListIter; +impl IntoIterator for List { + type IntoIter = ListIter; type Item = T; fn into_iter(self) -> Self::IntoIter { - RevisionListIter::new(self.head) + ListIter::new(self.head) } } -impl FromIterator for RevisionList { +impl FromIterator for List { /// Creates a `RevisionList` from an iterator by inserting elements in the /// order of arrival: first item in the iterator will end up at the front. fn from_iter>(iter: I) -> Self { @@ -122,7 +122,7 @@ pub struct Cursor<'a, T> { } impl<'a, T> Cursor<'a, T> { - pub fn new(rev_list: &'a mut RevisionList) -> Self { + pub fn new(rev_list: &'a mut List) -> Self { Self { list_length: &mut rev_list.length, link: &mut rev_list.head, @@ -165,19 +165,19 @@ impl<'a, T> Cursor<'a, T> { } } -pub struct RefRevisionListIter<'a, T> { +pub struct RefListIter<'a, T> { current_element: &'a Link, } -impl<'a, T> RefRevisionListIter<'a, T> { - pub fn new(rev_list: &'a RevisionList) -> Self { +impl<'a, T> RefListIter<'a, T> { + pub fn new(rev_list: &'a List) -> Self { Self { current_element: &rev_list.head, } } } -impl<'a, T> Iterator for RefRevisionListIter<'a, T> { +impl<'a, T> Iterator for RefListIter<'a, T> { type Item = &'a T; fn next(&mut self) -> Option { @@ -187,11 +187,11 @@ impl<'a, T> Iterator for RefRevisionListIter<'a, T> { } } -pub struct RevisionListIter { +pub struct ListIter { current_element: Link, } -impl RevisionListIter { +impl ListIter { pub fn new(start_element: Link) -> Self { Self { current_element: start_element, @@ -199,7 +199,7 @@ impl RevisionListIter { } } -impl Iterator for RevisionListIter { +impl Iterator for ListIter { type Item = T; fn next(&mut self) -> Option { @@ -216,7 +216,7 @@ mod tests { #[test] fn test_revision_list() { - let mut revision_list: RevisionList = RevisionList::new(); + let mut revision_list: List = List::new(); assert!(revision_list.is_empty()); assert_eq!(revision_list.front(), None); @@ -251,7 +251,7 @@ mod tests { fn test_revision_list_from_iterator() { // Test creating RevisionList from iterator let input_iter = vec![1, 2, 3].into_iter(); - let revision_list: RevisionList = input_iter.collect(); + let revision_list: List = input_iter.collect(); assert_eq!(revision_list.len(), 3); @@ -262,7 +262,7 @@ mod tests { assert_eq!(iter.next(), None); // Test iterator behavior on an empty list - let revision_list: RevisionList = RevisionList::new(); + let revision_list: List = List::new(); let mut iter = revision_list.iter(); assert_eq!(iter.next(), None); assert!(revision_list.is_empty()); @@ -270,7 +270,7 @@ mod tests { #[test] fn test_revision_list_cursor() { - let mut revision_list = RevisionList::new(); + let mut revision_list = List::new(); revision_list.push_front(1); // Add input while value is superior to 1 diff --git a/src/data_struct/mod.rs b/src/data_struct/mod.rs index daa71bf7..4250b263 100644 --- a/src/data_struct/mod.rs +++ b/src/data_struct/mod.rs @@ -1,10 +1,10 @@ mod dictionary; pub mod error; -mod revision_list; +mod list; mod revision_map; mod revision_vec; pub use dictionary::Dict; -pub use revision_list::{Cursor, Element, RevisionList}; +pub use list::{Cursor, Element, List}; pub use revision_map::RevisionMap; pub use revision_vec::RevisionVec; diff --git a/src/data_struct/revision_map.rs b/src/data_struct/revision_map.rs index c4096ed7..06c4efa0 100644 --- a/src/data_struct/revision_map.rs +++ b/src/data_struct/revision_map.rs @@ -8,7 +8,7 @@ use std::{ hash::Hash, }; -use super::RevisionList; +use super::List; /// A `RevisionMap` is a `HashMap` which keys are mapped to sequences of values. /// Upon insertion for an existing key, the new value is prepended to the @@ -30,7 +30,7 @@ where K: Debug + PartialEq + Eq + Hash, V: Debug, { - pub(crate) map: HashMap>, + pub(crate) map: HashMap>, } impl RevisionMap @@ -60,7 +60,7 @@ where /// Returns the total number of elements stored. pub fn count_elements(&self) -> usize { - self.map.values().map(RevisionList::len).sum() + self.map.values().map(List::len).sum() } pub fn chain_length(&self, key: &K) -> usize { @@ -72,13 +72,13 @@ where self.map.is_empty() } - fn insert_new_chain(entry: VacantEntry>, value: V) { - let mut new_chain = RevisionList::new(); + fn insert_new_chain(entry: VacantEntry>, value: V) { + let mut new_chain = List::new(); new_chain.push_front(value); entry.insert(new_chain); } - fn insert_in_chain(mut entry: OccupiedEntry>, value: V) { + fn insert_in_chain(mut entry: OccupiedEntry>, value: V) { let chain = entry.get_mut(); chain.push_front(value); } @@ -97,7 +97,7 @@ where K: Borrow, Q: Hash + Eq + ?Sized, { - self.map.get(key).and_then(RevisionList::front) + self.map.get(key).and_then(List::front) } /// Returns a mutable reference to the last revised value for a given key. @@ -106,7 +106,7 @@ where K: Borrow, Q: Hash + Eq + ?Sized, { - self.map.get_mut(key).and_then(RevisionList::front_mut) + self.map.get_mut(key).and_then(List::front_mut) } pub fn contains_key(&self, key: &K) -> bool { @@ -120,7 +120,7 @@ where /// Iterates through all revisions of a given key starting with the more /// recent one. - pub fn get(&self, key: &Q) -> Option<&RevisionList> + pub fn get(&self, key: &Q) -> Option<&List> //impl Iterator> where K: Borrow, @@ -135,7 +135,7 @@ where K: Borrow, Q: Hash + Eq + ?Sized, { - self.map.remove(key).map(RevisionList::into_iter) + self.map.remove(key).map(List::into_iter) } /// Keeps the n more recent values for a given key and returns the removed diff --git a/src/data_struct/revision_vec.rs b/src/data_struct/revision_vec.rs index d875823f..7d6c8a26 100644 --- a/src/data_struct/revision_vec.rs +++ b/src/data_struct/revision_vec.rs @@ -1,6 +1,6 @@ use std::collections::VecDeque; -use super::{Element, RevisionList}; +use super::{Element, List}; /// A `RevisionVec` is a vector that stores pairs containing a key /// and a sequence of values. Inserting a new value in the sequence @@ -18,7 +18,7 @@ use super::{Element, RevisionList}; /// This guarantees that the entry versions are always ordered. #[derive(Default, Debug, PartialEq, Eq)] pub struct RevisionVec { - chains: Vec<(K, RevisionList)>, + chains: Vec<(K, List)>, } impl RevisionVec { @@ -56,13 +56,13 @@ impl RevisionVec { // Be aware that inserting a value for a key that is already associated to a // chain breaks the CoverCrypt scheme as two chains will exist for the same key. - let mut new_chain = RevisionList::new(); + let mut new_chain = List::new(); new_chain.push_front(val); self.chains.push((key, new_chain)); } /// Inserts a new chain with a corresponding key. - pub fn insert_new_chain(&mut self, key: K, new_chain: RevisionList) { + pub fn insert_new_chain(&mut self, key: K, new_chain: List) { // Be aware that inserting a new chain for a key that is already associated to a // chain breaks the CoverCrypt scheme as two chains will exist for the same key. @@ -82,16 +82,13 @@ impl RevisionVec { /// Returns an iterator over each key-chains pair #[allow(clippy::map_identity)] // unpack &(x, y) to (&x, &y) - pub fn iter(&self) -> impl Iterator)> { + pub fn iter(&self) -> impl Iterator)> { self.chains.iter().map(|(key, chain)| (key, chain)) } /// Returns an iterator over each key-chains pair that allow modifying chain #[allow(clippy::map_identity)] // unpack &mut (x, y) to (&x, &mut y) - pub fn iter_mut(&mut self) -> impl Iterator)> - where - K: Clone, - { + pub fn iter_mut(&mut self) -> impl Iterator)> { self.chains.iter_mut().map(|(ref key, chain)| (key, chain)) } @@ -110,6 +107,15 @@ impl RevisionVec { } } +impl IntoIterator for RevisionVec { + type IntoIter = std::vec::IntoIter<(K, List)>; + type Item = (K, List); + + fn into_iter(self) -> Self::IntoIter { + self.chains.into_iter() + } +} + /// Breadth-first search iterator for `RevisionVec`. pub struct BfsQueue<'a, T> { queue: VecDeque<&'a Element>, @@ -142,6 +148,15 @@ impl<'a, T> Iterator for BfsQueue<'a, T> { } } +impl FromIterator<(K, List)> for RevisionVec { + /// Creates a `RevisionVec` from an iterator + fn from_iter)>>(iter: I) -> Self { + Self { + chains: iter.into_iter().collect(), + } + } +} + #[cfg(test)] mod tests {