From 546ba72c52fa23a03572f335b74ffa765717354f Mon Sep 17 00:00:00 2001 From: Manuthor Date: Fri, 23 Jun 2023 08:58:46 +0200 Subject: [PATCH] test: impl Display trait on structs used in callbacks for logging --- Cargo.toml | 1 + src/callbacks.rs | 17 ++++---- src/compact.rs | 16 ++++---- src/compact_live.rs | 34 ++++++++-------- src/in_memory_example.rs | 33 +++++++++------- src/lib.rs | 5 ++- src/search.rs | 10 ++--- src/structs.rs | 85 ++++++++++++++++++++++++++++++++++++++-- src/upsert.rs | 4 +- 9 files changed, 147 insertions(+), 58 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 3e0746f1..158e4948 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,6 +29,7 @@ in_memory = [] live_compact = [] [dependencies] +base64 = "0.21.2" cosmian_crypto_core = "7.0.0" futures = "0.3" rand = "0.8" diff --git a/src/callbacks.rs b/src/callbacks.rs index 57f44224..74e7aa07 100644 --- a/src/callbacks.rs +++ b/src/callbacks.rs @@ -4,8 +4,9 @@ use cosmian_crypto_core::symmetric_crypto::Dem; use crate::{ chain_table::{ChainTableValue, KwiChainUids}, + structs::EncryptedMultiTable, CallbackError, EncryptedTable, Error, IndexedValue, KeyingMaterial, Keyword, Location, Uid, - UpsertData, CHAIN_TABLE_KEY_DERIVATION_INFO, + Uids, UpsertData, CHAIN_TABLE_KEY_DERIVATION_INFO, }; /// Trait implementing all callbacks needed by Findex. @@ -21,7 +22,7 @@ pub trait FindexCallbacks Result; /// Fetch all the UIDs from the entry table - async fn fetch_all_entry_table_uids(&self) -> Result>, Error>; + async fn fetch_all_entry_table_uids(&self) -> Result, Error>; /// Fetch the lines with the given UIDs from the Entry Table. The returned /// values are encrypted since they are stored that way. The decryption @@ -39,8 +40,8 @@ pub trait FindexCallbacks>, - ) -> Result, Vec)>, Error>; + entry_table_uids: Uids, + ) -> Result, Error>; /// Fetch the lines with the given UIDs from the Chain Table. The returned /// values are encrypted since they are stored that way. The decryption is @@ -58,7 +59,7 @@ pub trait FindexCallbacks>, + chain_table_uids: Uids, ) -> Result, Error>; /// Upserts lines in the Entry Table. The input data maps each Entry Table @@ -146,7 +147,7 @@ pub trait FindexCallbacks>, + chain_table_uids_to_remove: Uids, new_entry_table_items: EncryptedTable, new_chain_table_items: EncryptedTable, ) -> Result<(), Error>; @@ -174,7 +175,7 @@ pub trait FindexCallbacks>) -> Result<(), Error>; + async fn delete_chain(&mut self, uids: Uids) -> Result<(), Error>; } pub trait FetchChains< @@ -206,7 +207,7 @@ pub trait FetchChains< Error, > { // Collect to a `HashSet` to mix UIDs between chains. - let chain_table_uids = kwi_chain_table_uids.values().flatten().cloned().collect(); + let chain_table_uids = Uids(kwi_chain_table_uids.values().flatten().cloned().collect()); let encrypted_items = self.fetch_chain_table(chain_table_uids).await?; diff --git a/src/compact.rs b/src/compact.rs index 806acebf..e284b179 100644 --- a/src/compact.rs +++ b/src/compact.rs @@ -16,7 +16,7 @@ use crate::{ error::CallbackError, parameters::check_parameter_constraints, structs::{BlockType, EncryptedTable, IndexedValue, Label}, - Error, FindexCallbacks, KeyingMaterial, CHAIN_TABLE_KEY_DERIVATION_INFO, + Error, FindexCallbacks, KeyingMaterial, Uids, CHAIN_TABLE_KEY_DERIVATION_INFO, ENTRY_TABLE_KEY_DERIVATION_INFO, }; @@ -48,7 +48,7 @@ pub trait FindexCompact< { /// Replaces all the Index Entry Table UIDs and values. New UIDs are derived /// using the given label and the KMAC key derived from the new master key. - /// The values are dectypted using the DEM key derived from the master key + /// The values are decrypted using the DEM key derived from the master key /// and re-encrypted using the DEM key derived from the new master key. /// /// Randomly selects index entries and recompact their associated chains. @@ -152,11 +152,13 @@ pub trait FindexCompact< // // Remove all reindexed Chain Table items. Chains are recomputed entirely. // - let chain_table_uids_to_remove = chains_to_reindex - .values() - .flat_map(|chain| chain.iter().map(|(k, _)| k)) - .cloned() - .collect(); + let chain_table_uids_to_remove = Uids( + chains_to_reindex + .values() + .flat_map(|chain| chain.iter().map(|(k, _)| k)) + .cloned() + .collect(), + ); // Get the values stored in the reindexed chains. let mut reindexed_chain_values = HashMap::with_capacity(chains_to_reindex.len()); diff --git a/src/compact_live.rs b/src/compact_live.rs index b1db41b3..c5145d14 100644 --- a/src/compact_live.rs +++ b/src/compact_live.rs @@ -13,7 +13,7 @@ use crate::{ entry_table::{EntryTable, EntryTableValue}, structs::{BlockType, ChainData}, CallbackError, EncryptedTable, Error, FindexCallbacks, FindexCompact, IndexedValue, - KeyingMaterial, Location, Uid, UpsertData, CHAIN_TABLE_KEY_DERIVATION_INFO, + KeyingMaterial, Location, Uid, Uids, UpsertData, CHAIN_TABLE_KEY_DERIVATION_INFO, ENTRY_TABLE_KEY_DERIVATION_INFO, }; @@ -116,7 +116,7 @@ pub trait FindexLiveCompact< &self, rng: &mut impl CryptoRngCore, num_reindexing_before_full_set: u32 - ) -> Result<(Vec>, HashSet>), Error> { + ) -> Result<(Vec>, Uids), Error> { let entry_table_uids = self.fetch_all_entry_table_uids().await?; @@ -137,16 +137,16 @@ pub trait FindexLiveCompact< // and `gamma` is the Euler's constant. // // See the [coupon collector's problem](https://wikipedia.org/wiki/Coupon_collector's_problem). - let entry_table_length = entry_table_uids.len() as f64; + let entry_table_length = entry_table_uids.0.len() as f64; let n_compact = ((entry_table_length * (entry_table_length.log2() + GAMMA)) / f64::from(num_reindexing_before_full_set)) .ceil() as usize; // The number of compacted UIDs should leave enough unused UIDs for the noise. - if (n_compact as f64 * (1f64 + Self::NOISE_RATIO)) > entry_table_uids.len() as f64 { + if (n_compact as f64 * (1f64 + Self::NOISE_RATIO)) > entry_table_uids.0.len() as f64 { return Err(Error::CryptoError(format!( "Number of Entry Table UIDs to compact ({n_compact}) should not be greater than {}", - entry_table_uids.len() as f64 / (1f64 + Self::NOISE_RATIO) + entry_table_uids.0.len() as f64 / (1f64 + Self::NOISE_RATIO) ))); } @@ -157,11 +157,11 @@ pub trait FindexLiveCompact< let mut mixed_uids = Vec::with_capacity(2 * n_compact); // Needed because `uids` is moved in the loop condition. - let n_uids = entry_table_uids.len(); + let n_uids = entry_table_uids.0.len(); let n_noise_candidates = n_uids - n_compact; let n_noise = (Self::NOISE_RATIO * n_compact as f64) as usize; - for uid in entry_table_uids { + for uid in entry_table_uids.0 { let tmp = rng.next_u32() as usize; if tmp % n_uids < n_compact { // Randomly select ~ `n_compact` target UIDs. @@ -173,7 +173,7 @@ pub trait FindexLiveCompact< } } - Ok((mixed_uids, noise_uids)) + Ok((mixed_uids, Uids(noise_uids))) } /// Fetch all useful information for the compact from the Chain Table: @@ -269,7 +269,7 @@ pub trait FindexLiveCompact< &self, rng: &mut impl CryptoRngCore, k_value: &DemScheme::Key, - noise: &HashSet>, + noise: &Uids, noisy_remaining_locations: &HashSet, noisy_encrypted_entry_table: &EncryptedTable, noisy_chain_values: &HashMap, HashSet>, @@ -281,15 +281,15 @@ pub trait FindexLiveCompact< Error, > { let mut noisy_entry_table = EntryTable::with_capacity(noisy_chain_values.len()); - let mut compacted_chains = HashMap::with_capacity(noisy_chain_values.len() - noise.len()); - let mut cache = HashMap::with_capacity(noisy_chain_values.len() - noise.len()); + let mut compacted_chains = HashMap::with_capacity(noisy_chain_values.len() - noise.0.len()); + let mut cache = HashMap::with_capacity(noisy_chain_values.len() - noise.0.len()); for (uid, encrypted_value) in noisy_encrypted_entry_table.iter() { let entry_table_value = EntryTableValue::decrypt::( k_value, encrypted_value )?; - if noise.contains(uid) { + if noise.0.contains(uid) { // Noise entries are simply re-encrypted. noisy_entry_table.insert(*uid, entry_table_value); } else { @@ -343,8 +343,8 @@ pub trait FindexLiveCompact< &mut self, rng: &mut impl CryptoRngCore, k_value: &DemScheme::Key, - mixed_uids: HashSet>, - noise_uids: &HashSet>, + mixed_uids: Uids, + noise_uids: &Uids, ) -> Result<(), Error> { // Fetch both target and noise values from the Entry Table. let mut encrypted_entry_table = self @@ -408,7 +408,7 @@ pub trait FindexLiveCompact< // which leads to the same number of clone operations, or less) let mut old_chains_to_remove = Vec::with_capacity(chains.chain_uids.len()); for uid in chains.chain_uids.keys() { - if !encrypted_entry_table.contains_key(uid) && !noise_uids.contains(uid) { + if !encrypted_entry_table.contains_key(uid) && !noise_uids.0.contains(uid) { old_chains_to_remove.push(*uid); } } @@ -419,7 +419,7 @@ pub trait FindexLiveCompact< chains_to_delete.extend(chain); } - self.delete_chain(chains_to_delete).await?; + self.delete_chain(Uids(chains_to_delete)).await?; } Ok(()) @@ -451,7 +451,7 @@ pub trait FindexLiveCompact< self.live_compact_uids( &mut rng, &k_value, - batch.iter().cloned().collect(), + Uids(batch.iter().cloned().collect()), &noise_uids, ).await?; } diff --git a/src/in_memory_example.rs b/src/in_memory_example.rs index 26541987..f948f422 100644 --- a/src/in_memory_example.rs +++ b/src/in_memory_example.rs @@ -7,8 +7,9 @@ use cosmian_crypto_core::{reexport::rand_core::SeedableRng, CsRng}; use rand::Rng; use crate::{ - callbacks::FetchChains, parameters::UID_LENGTH, EncryptedTable, FindexCallbacks, FindexCompact, - FindexSearch, FindexUpsert, IndexedValue, Keyword, Location, Uid, UpsertData, + callbacks::FetchChains, parameters::UID_LENGTH, structs::EncryptedMultiTable, EncryptedTable, + FindexCallbacks, FindexCompact, FindexSearch, FindexUpsert, IndexedValue, Keyword, Location, + Uids, UpsertData, }; #[cfg(feature = "live_compact")] use crate::{compact_live::FindexLiveCompact, parameters::*}; @@ -97,16 +98,17 @@ impl FindexCallbacks Ok(!self.progress_callback_cancel) } - async fn fetch_all_entry_table_uids(&self) -> Result>, ExampleError> { - let uids = self.entry_table.keys().cloned().collect(); + async fn fetch_all_entry_table_uids(&self) -> Result, ExampleError> { + let uids = Uids(self.entry_table.keys().cloned().collect()); Ok(uids) } async fn fetch_entry_table( &self, - entry_table_uids: HashSet>, - ) -> Result, Vec)>, ExampleError> { - Ok(entry_table_uids + entry_table_uids: Uids, + ) -> Result, ExampleError> { + let items = entry_table_uids + .0 .into_iter() .filter_map(|uid| { self.entry_table @@ -114,15 +116,16 @@ impl FindexCallbacks .cloned() .map(|value| (uid, value)) }) - .collect()) + .collect::>(); + Ok(EncryptedMultiTable(items)) } async fn fetch_chain_table( &self, - chain_table_uids: HashSet>, + chain_table_uids: Uids, ) -> Result, ExampleError> { - let mut items = EncryptedTable::with_capacity(chain_table_uids.len()); - for uid in chain_table_uids { + let mut items = EncryptedTable::with_capacity(chain_table_uids.0.len()); + for uid in chain_table_uids.0 { if let Some(value) = self.chain_table.get(&uid) { items.insert(uid, value.clone()); } @@ -165,7 +168,7 @@ impl FindexCallbacks fn update_lines( &mut self, - chain_table_uids_to_remove: HashSet>, + chain_table_uids_to_remove: Uids, new_encrypted_entry_table_items: EncryptedTable, new_encrypted_chain_table_items: EncryptedTable, ) -> Result<(), ExampleError> { @@ -178,7 +181,7 @@ impl FindexCallbacks ); } - for removed_chain_table_uid in chain_table_uids_to_remove { + for removed_chain_table_uid in chain_table_uids_to_remove.0 { self.chain_table.remove(&removed_chain_table_uid); } @@ -204,8 +207,8 @@ impl FindexCallbacks } #[cfg(feature = "live_compact")] - async fn delete_chain(&mut self, uids: HashSet>) -> Result<(), ExampleError> { - self.chain_table.retain(|uid, _| !uids.contains(uid)); + async fn delete_chain(&mut self, uids: Uids) -> Result<(), ExampleError> { + self.chain_table.retain(|uid, _| !uids.0.contains(uid)); Ok(()) } } diff --git a/src/lib.rs b/src/lib.rs index 4286d70a..ae763979 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -51,5 +51,8 @@ pub use compact_live::FindexLiveCompact; pub use error::{CallbackError, CoreError, Error}; pub use keys::KeyingMaterial; pub use search::FindexSearch; -pub use structs::{EncryptedTable, IndexedValue, Keyword, Label, Location, Uid, UpsertData}; +pub use structs::{ + EncryptedMultiTable, EncryptedTable, IndexedValue, Keyword, Label, Location, Uid, Uids, + UpsertData, +}; pub use upsert::FindexUpsert; diff --git a/src/search.rs b/src/search.rs index d3631b6c..e83d732a 100644 --- a/src/search.rs +++ b/src/search.rs @@ -11,7 +11,7 @@ use crate::{ error::CallbackError, parameters::check_parameter_constraints, structs::{IndexedValue, Keyword, Label, Location}, - Error, KeyingMaterial, CHAIN_TABLE_KEY_DERIVATION_INFO, ENTRY_TABLE_KEY_DERIVATION_INFO, + Error, KeyingMaterial, Uids, CHAIN_TABLE_KEY_DERIVATION_INFO, ENTRY_TABLE_KEY_DERIVATION_INFO, }; /// Trait implementing the search functionality of Findex. @@ -72,13 +72,13 @@ pub trait FindexSearch< // Query the Entry Table for these UIDs. let entry_table = self - .fetch_entry_table(entry_table_uid_map.keys().copied().collect()) + .fetch_entry_table(Uids(entry_table_uid_map.keys().copied().collect())) .await?; // Unchain all Entry Table values. - let mut kwi_chain_table_uids = KwiChainUids::with_capacity(entry_table.len()); - let mut kwi_to_keyword = HashMap::with_capacity(entry_table.len()); - for (uid, encrypted_value) in entry_table.into_iter() { + let mut kwi_chain_table_uids = KwiChainUids::with_capacity(entry_table.0.len()); + let mut kwi_to_keyword = HashMap::with_capacity(entry_table.0.len()); + for (uid, encrypted_value) in entry_table.0.into_iter() { let keyword = entry_table_uid_map.get(&uid).ok_or_else(|| { Error::::CryptoError(format!( "Could not find keyword associated to UID {uid:?}." diff --git a/src/structs.rs b/src/structs.rs index f051393b..f4af1952 100644 --- a/src/structs.rs +++ b/src/structs.rs @@ -2,11 +2,12 @@ use std::{ collections::{hash_map::IntoKeys, HashMap, HashSet}, - fmt::Debug, + fmt::{Debug, Display}, ops::{Deref, DerefMut}, vec::Vec, }; +use base64::{engine::general_purpose::STANDARD, Engine as _}; use cosmian_crypto_core::{ bytes_ser_de::{to_leb128_len, Deserializer, Serializable, Serializer}, reexport::rand_core::CryptoRngCore, @@ -435,14 +436,47 @@ impl Serializable for IndexedValue { #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] pub struct Uid([u8; LENGTH]); +impl Display for Uid { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", STANDARD.encode(self.0)) + } +} + impl_byte_array!(Uid); +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct Uids(pub HashSet>); + +impl Display for Uids { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let mut output = String::new(); + for uid in self.0.clone() { + output = format!("uid: {}\n{output}", STANDARD.encode(uid)); + } + write!(f, "{output}") + } +} + /// An encrypted table maps [`Uid`]s to encrypted values. // NOTE TBZ: need struct to implement `Serializable` #[must_use] #[derive(Default, Debug, Clone)] pub struct EncryptedTable(HashMap, Vec>); +impl Display for EncryptedTable { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let mut output = String::new(); + for (uid, value) in self.0.clone() { + output = format!( + "uid: {}, value: {}, \n{output}", + STANDARD.encode(uid.0), + STANDARD.encode(value), + ); + } + write!(f, "{output}") + } +} + impl EncryptedTable { pub fn with_capacity(capacity: usize) -> Self { Self(HashMap::with_capacity(capacity)) @@ -481,13 +515,14 @@ impl From<::Target> for EncryptedTable TryFrom, Vec)>> +impl TryFrom> for EncryptedTable { type Error = Error; - fn try_from(value: Vec<(Uid, Vec)>) -> Result { + fn try_from(value: EncryptedMultiTable) -> Result { value + .0 .into_iter() .try_fold(Self::default(), |mut acc, (k, v)| { let old_value = acc.insert(k, v); @@ -502,6 +537,24 @@ impl TryFrom, Vec)>> } } +#[derive(Default, Debug)] +pub struct EncryptedMultiTable(pub Vec<(Uid, Vec)>); + +impl Display for EncryptedMultiTable { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let mut output = String::new(); + for (uid, value) in self.0.clone() { + output = format!( + "uid: {}, values: {}, \n{}", + STANDARD.encode(uid), + STANDARD.encode(value), + output, + ); + } + write!(f, "{output}") + } +} + impl IntoIterator for EncryptedTable { type IntoIter = <::Target as IntoIterator>::IntoIter; type Item = (Uid, Vec); @@ -579,6 +632,32 @@ pub struct UpsertData( HashMap, (Option>, Vec)>, ); +impl Display for UpsertData { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let mut output = String::new(); + for (uid, (old_value, new_value)) in self.0.clone() { + match old_value { + Some(old) => { + output = format!( + "uid: {} old_value: {} new_value: {}, \n{output}", + STANDARD.encode(uid.0), + STANDARD.encode(old), + STANDARD.encode(new_value) + ) + } + None => { + output = format!( + "uid: {} old_value: '' new_value: {}, \n{output}", + STANDARD.encode(uid.0), + STANDARD.encode(new_value) + ) + } + } + } + write!(f, "{output}") + } +} + impl UpsertData { /// Build the upsert data from the old and new tables. /// diff --git a/src/upsert.rs b/src/upsert.rs index 8984234a..4750e6ba 100644 --- a/src/upsert.rs +++ b/src/upsert.rs @@ -17,7 +17,7 @@ use crate::{ structs::{ BlockType, EncryptedTable, IndexedValue, Keyword, KeywordHash, Label, Uid, UpsertData, }, - FindexCallbacks, ENTRY_TABLE_KEY_DERIVATION_INFO, + FindexCallbacks, Uids, ENTRY_TABLE_KEY_DERIVATION_INFO, }; /// This the public trait exposed to the users of the Findex Upsert API. @@ -125,7 +125,7 @@ pub trait FindexUpsert< // Query the Entry Table for these UIDs. let mut encrypted_entry_table = self - .fetch_entry_table(new_chains.keys().cloned().collect()) + .fetch_entry_table(Uids(new_chains.keys().cloned().collect())) .await? .try_into()?;