diff --git a/hacspec-scrambledb/scrambledb/src/data_transformations.rs b/hacspec-scrambledb/scrambledb/src/data_transformations.rs new file mode 100644 index 0000000..fe6f568 --- /dev/null +++ b/hacspec-scrambledb/scrambledb/src/data_transformations.rs @@ -0,0 +1,213 @@ +//! This module defines ScrambleDB transformations at the level of individual +//! pieces of data as defined in [`data_types`](crate::data_types). +//! +//! These transformations are: +//! - blinding identifiable and pseudonymous data +//! - pseudonymizing blinded identifiable data +//! - converting blinded pseudonymous data +//! - finalizing blinded pseudonymous data + +use hacspec_lib::Randomness; +use oprf::coprf::{ + coprf_online::{blind, blind_convert, blind_evaluate, prepare_blind_convert}, + coprf_setup::{derive_key, BlindingPublicKey, CoPRFEvaluatorContext}, +}; + +use crate::{data_types::*, error::Error, setup::StoreContext}; + +use self::double_hpke::{hpke_open_level_2, hpke_seal_level_1, hpke_seal_level_2}; + +pub(crate) mod double_hpke; + +/// CoPRF context string for domain separation of intial pseudonymization. +const PSEUDONYMIZATION_CONTEXT: &[u8] = b"CoPRF-Context-Pseudonymization"; + +/// Blind an identifiable datum as a first step in initial pseudonym +/// generation. +/// +/// Inputs: +/// - `bpk`: Receiver's blinding public key +/// - `ek`: Receiver's public encryption key +/// - `datum`: Identifiable data +/// - `randomness`: Random bytes +/// +/// Output: +/// [Blinded data](crate::data_types::BlindedIdentifiableData) such that the +/// datum's handle is blinded for CoPRF evaluation and the datum's value is +/// level-1 encrypted. +pub fn blind_identifiable_datum( + bpk: &BlindingPublicKey, + ek: &[u8], + datum: &IdentifiableData, + randomness: &mut Randomness, +) -> Result { + // Blind orthonym towards receiver. + let blinded_handle = BlindedIdentifiableHandle(blind( + *bpk, + datum.handle.as_bytes(), + PSEUDONYMIZATION_CONTEXT.to_vec(), + randomness, + )?); + + // Level-1 encrypt data value towards receiver. + let encrypted_data_value = hpke_seal_level_1(&datum.data_value, ek, randomness)?; + + Ok(BlindedIdentifiableData { + blinded_handle, + encrypted_data_value, + }) +} + +/// Blind a pseudonymous datum as a first step in pseudonym +/// conversion. +/// +/// Inputs: +/// - `store_context`: The data store's long term private state including the pseudonym +/// hardening keys +/// - `bpk`: Receiver's blinding public key +/// - `ek`: Receiver's public encryption key +/// - `datum`: Pseudonymized data +/// - `randomness`: Random bytes +/// +/// Output: +/// [Blinded pseudonymized data](BlindedPseudonymizedData) such that the +/// datum's handle is blinded for CoPRF conversion and the datum's value is +/// level-1 encrypted. +pub fn blind_pseudonymized_datum( + store_context: &StoreContext, + bpk: &BlindingPublicKey, + ek: &[u8], + datum: &PseudonymizedData, + randomness: &mut Randomness, +) -> Result { + // Blind recovered raw pseudonym towards receiver. + let blinded_handle = BlindedPseudonymizedHandle(prepare_blind_convert( + *bpk, + store_context.recover_raw_pseudonym(datum.handle.0)?, + randomness, + )?); + + // Level-1 encrypt data value towards receiver. + let encrypted_data_value = hpke_seal_level_1(&datum.data_value, ek, randomness)?; + + Ok(BlindedPseudonymizedData { + blinded_handle, + encrypted_data_value, + }) +} + +/// Obliviously pseudonymmize a blinded identifiable datum. +/// +/// Inputs: +/// - `coprf_context`: The converter's CoPRF evaluation context +/// - `bpk`: The receiver's blinding public key +/// - `ek`: The receiver's public encryption key +/// - `datum`: A blinded datum output by [`blind_identifiable_datum`] +/// - `randomness`: Random bytes +/// +/// Output: +/// [Blinded pseudonymized data](BlindedPseudonymizedData) such that the +/// datum's blinded handle has been obliviously evaluated to a pseudonym and +/// the datum's value has been level-2 encrypted towards the receiver. +pub fn pseudonymize_blinded_datum( + coprf_context: &CoPRFEvaluatorContext, + bpk: &BlindingPublicKey, + ek: &[u8], + datum: &BlindedIdentifiableData, + randomness: &mut Randomness, +) -> Result { + let key = derive_key( + &coprf_context, + datum.encrypted_data_value.attribute_name.as_bytes(), + )?; + + // Obliviously generate raw pseudonym. + let blinded_handle = BlindedPseudonymizedHandle(blind_evaluate( + key, + *bpk, + datum.blinded_handle.0, + randomness, + )?); + + // Level-2 encrypt data value towards receiver. + let encrypted_data_value = hpke_seal_level_2(&datum.encrypted_data_value, ek, randomness)?; + + Ok(BlindedPseudonymizedData { + blinded_handle, + encrypted_data_value, + }) +} + +/// Obliviously convert a blinded pseudonymous datum to a given target pseudonym key. +/// +/// Inputs: +/// - `coprf_context`: The Converters CoPRF evaluation context +/// - `bpk`: The receiver's blinding public key +/// - `ek`: The receiver's public encryption key +/// - `conversion_target`: Target pseudonym key identifier +/// - `randomness`: Random bytes +/// +/// Output: +/// [Blinded pseudonymized data](BlindedPseudonymizedData)such that the +/// datum's pseudonymous handle is converted to the target pseudonym key and +/// the datum's value is level-2 encrypted towards the receiver. +pub fn convert_blinded_datum( + coprf_context: &CoPRFEvaluatorContext, + bpk: &BlindingPublicKey, + ek: &[u8], + conversion_target: &[u8], + datum: &BlindedPseudonymizedData, + randomness: &mut Randomness, +) -> Result { + // Re-derive original pseudonymization key. + let key_from = derive_key( + &coprf_context, + datum.encrypted_data_value.attribute_name.as_bytes(), + )?; + + // Derive target key. + let key_to = derive_key(&coprf_context, conversion_target)?; + + // Obliviously convert pseudonym. + let blinded_handle = BlindedPseudonymizedHandle(blind_convert( + *bpk, + key_from, + key_to, + datum.blinded_handle.0, + randomness, + )?); + + // Level-2 encrypt data value towards receiver. + let encrypted_data_value = hpke_seal_level_2(&datum.encrypted_data_value, ek, randomness)?; + + Ok(BlindedPseudonymizedData { + blinded_handle, + encrypted_data_value, + }) +} + +/// Finalize a blinded pseudonymous datum for storage or analysis. +/// +/// Inputs: +/// - `store_context`: The data store's long term private state including the +/// receiver's coPRF unblinding key, private decryption key, as well as +/// pseudonym hardening key +/// - `datum`: blinded pseudonymous datum output by [`convert_blinded_datum`] or +/// [`pseudonymize_blinded_datum`] +/// +/// Output: +/// [Pseudonymized data](PseudonymizedData) such that the datum's pseudonymous +/// handle has been unblinded and hardened and the datum's value has been +/// decrypted. +pub fn finalize_blinded_datum( + store_context: &StoreContext, + datum: &BlindedPseudonymizedData, +) -> Result { + // Finalize pseudonym for storage. + let handle = FinalizedPseudonym(store_context.finalize_pseudonym(datum.blinded_handle.0)?); + + // Decrypt data value for storage. + let data_value = hpke_open_level_2(&datum.encrypted_data_value, &store_context.hpke_sk)?; + + Ok(PseudonymizedData { handle, data_value }) +} diff --git a/hacspec-scrambledb/scrambledb/src/data_transformations/double_hpke.rs b/hacspec-scrambledb/scrambledb/src/data_transformations/double_hpke.rs new file mode 100644 index 0000000..0a98979 --- /dev/null +++ b/hacspec-scrambledb/scrambledb/src/data_transformations/double_hpke.rs @@ -0,0 +1,166 @@ +//! This module defines HPKE-based double encryption and decryption for use in +//! individual data tranformations as defined in +//! [`data_transformations`](crate::data_transformations). +//! +//! A plain text data value can be encrypted once to obtain a level-1 +//! encryption of the data value. +//! +//! A level-1 encrypted data value can be encrypted a second time to obtain a +//! level-2 encryption of the data value. +//! +//! Only level-2 encrypted data values can be decrypted, and only if both +//! encryptions were performed towards the same receiver. + +use libcrux::hpke::kem::Nsk; + +use libcrux::hpke::{HpkeOpen, HpkeSeal}; + +use crate::SerializedHPKE; + +use crate::data_types::{DataValue, EncryptedDataValue}; + +use libcrux::hpke::HPKEConfig; + +use crate::error::Error; + +use hacspec_lib::Randomness; + +/// HPKE double encryption level 1 `info` string. +const HPKE_LEVEL_1_INFO: &[u8] = b"Hpke-Level-1"; + +/// HPKE double encryption level 2 `info` string. +const HPKE_LEVEL_2_INFO: &[u8] = b"Hpke-Level-2"; + +/// Level-1 encrypt a plain text data value. +/// +/// Inputs: +/// - `data_value`: A plain text data value +/// - `ek`: The receivers public encryption key +/// - `randomness`: Random bytes +/// +/// Output: +/// A level-1 encrypted data value. +/// +/// Raises: +/// - `CorruptedData`: If the internal encryption fails. +/// +/// Panics: +/// - on insufficient randomness +pub(crate) fn hpke_seal_level_1( + data_value: &DataValue, + ek: &[u8], + randomness: &mut Randomness, +) -> Result { + let HPKEConfig(_, kem, _, _) = crate::HPKE_CONF; + let encrypted_data_value = EncryptedDataValue { + attribute_name: data_value.attribute_name.clone(), + value: SerializedHPKE::from_hpke_ct(&HpkeSeal( + crate::HPKE_CONF, + ek, + HPKE_LEVEL_1_INFO, + b"", + &data_value.value, + None, + None, + None, + randomness.bytes(Nsk(kem)).unwrap().to_vec(), + )?) + .to_bytes(), + encryption_level: 1u8, + }; + Ok(encrypted_data_value) +} + +/// Level-2 encrypt a level-1 encrypted data value. +/// +/// Inputs: +/// - `data_value`: A level-1 encrypted data value +/// - `ek`: The receivers public encryption key +/// - `randomness`: Random bytes +/// +/// Output: +/// A level-2 encrypted data value. +/// +/// Raises: +/// - `InvalidInput`: If the input data value is not level-1 encrypted. +/// - `CorruptedData`: If the internal encryption fails. +/// +/// Panics: +/// - on insufficient randomness +pub(crate) fn hpke_seal_level_2( + data_value: &EncryptedDataValue, + ek: &[u8], + randomness: &mut Randomness, +) -> Result { + if data_value.encryption_level != 1u8 { + return Err(Error::InvalidInput); + } + + let HPKEConfig(_, kem, _, _) = crate::HPKE_CONF; + let data_value = EncryptedDataValue { + attribute_name: data_value.attribute_name.clone(), + value: SerializedHPKE::from_hpke_ct(&HpkeSeal( + crate::HPKE_CONF, + ek, + HPKE_LEVEL_2_INFO, + b"", + &data_value.value, + None, + None, + None, + randomness.bytes(Nsk(kem)).unwrap().to_vec(), + )?) + .to_bytes(), + encryption_level: 2u8, + }; + Ok(data_value) +} + +/// Decrypt a level-2 encrypted data value. +/// +/// Inputs: +/// - `data_value`: A Level-2 encrypted data value +/// - `sk`: The receiver's decryption key +/// +/// Outputs: +/// A plain text data value. +/// +/// Raises: +/// - `InvalidInput`: If the input data value is not level-2 encrypted. +/// - `CorruptedData`: If the internal decryption fails, e.g. because of +/// inconsistent level-1 and level-2 receivers. +pub(crate) fn hpke_open_level_2( + data_value: &EncryptedDataValue, + sk: &[u8], +) -> Result { + if data_value.encryption_level != 2u8 { + return Err(Error::InvalidInput); + } + + let outer_encryption = SerializedHPKE::from_bytes(&data_value.value).to_hpke_ct(); + let inner_encryption = SerializedHPKE::from_bytes(&HpkeOpen( + crate::HPKE_CONF, + &outer_encryption, + sk, + HPKE_LEVEL_2_INFO, + b"", + None, + None, + None, + )?) + .to_hpke_ct(); + let data_value = DataValue { + attribute_name: data_value.attribute_name.clone(), + value: HpkeOpen( + crate::HPKE_CONF, + &inner_encryption, + sk, + HPKE_LEVEL_1_INFO, + b"", + None, + None, + None, + )?, + }; + Ok(data_value) +} diff --git a/hacspec-scrambledb/scrambledb/src/data_types.rs b/hacspec-scrambledb/scrambledb/src/data_types.rs new file mode 100644 index 0000000..f3089ad --- /dev/null +++ b/hacspec-scrambledb/scrambledb/src/data_types.rs @@ -0,0 +1,66 @@ +//! This module defines data structures for indvidual pieces of data in +//! ScrambleDB. +//! +//! A value generally consists of a handle and a data value. Handles can be +//! identifiable or pseudonymous and either form can also be blinded. Data +//! values may be in plain text or encrypted and always carry with them the +//! name of the attribute they belong to in plain text. + +use oprf::coprf::coprf_online::{BlindInput, BlindOutput}; + +/// A type for finalized pseudonyms, i.e. those which have been hardened for +/// storage by applying a PRP. +pub struct FinalizedPseudonym(pub(crate) [u8; 64]); +/// A type for blinded identifiable handles. +pub struct BlindedIdentifiableHandle(pub(crate) BlindInput); +/// A type for blinded pseudonymous handles. +pub struct BlindedPseudonymizedHandle(pub(crate) BlindOutput); + +/// A plain text data value. +pub struct DataValue { + /// A byte string encoding the data value. + pub(crate) value: Vec, + /// The name of the attribute the value belongs to. + pub(crate) attribute_name: String, +} +/// An encrypted data value. +pub struct EncryptedDataValue { + /// A byte string encoding the encrypted data value. + pub(crate) value: Vec, + /// The name of the attribute the value belongs to. + pub(crate) attribute_name: String, + /// The encryption level, as understood in terms of [crate::data_transformations::double_hpke]. + pub(crate) encryption_level: u8, +} + +/// An identifiable piece of data. +pub struct IdentifiableData { + /// A plain text handle. + pub(crate) handle: String, + /// A plain text data value. + pub(crate) data_value: DataValue, +} + +/// The blinded version of an identifiable piece of data. +pub struct BlindedIdentifiableData { + /// A blinded plain text handle. + pub(crate) blinded_handle: BlindedIdentifiableHandle, + /// An encrypted data value. + pub(crate) encrypted_data_value: EncryptedDataValue, +} + +/// The blinded version of a pseudonymized piece of data. +pub struct BlindedPseudonymizedData { + /// A blinded pseudonymous handle. + pub(crate) blinded_handle: BlindedPseudonymizedHandle, + /// An encrypted data value. + pub(crate) encrypted_data_value: EncryptedDataValue, +} + +/// A pseudonymized piece of data. +pub struct PseudonymizedData { + /// A pseudonymous handle. + pub(crate) handle: FinalizedPseudonym, + /// A plain text data value. + pub(crate) data_value: DataValue, +} diff --git a/hacspec-scrambledb/scrambledb/src/error.rs b/hacspec-scrambledb/scrambledb/src/error.rs index 2128489..d9c1010 100644 --- a/hacspec-scrambledb/scrambledb/src/error.rs +++ b/hacspec-scrambledb/scrambledb/src/error.rs @@ -2,6 +2,7 @@ pub enum Error { RandomnessError, CorruptedData, + InvalidInput, } impl From for Error { diff --git a/hacspec-scrambledb/scrambledb/src/finalize.rs b/hacspec-scrambledb/scrambledb/src/finalize.rs index fe1ecc5..23940b1 100644 --- a/hacspec-scrambledb/scrambledb/src/finalize.rs +++ b/hacspec-scrambledb/scrambledb/src/finalize.rs @@ -1,11 +1,11 @@ //! # Conversion Finalization -use libcrux::hpke::HpkeOpen; use crate::{ + data_transformations::finalize_blinded_datum, + data_types::{BlindedPseudonymizedData, BlindedPseudonymizedHandle, EncryptedDataValue}, error::Error, setup::StoreContext, table::{Column, ConvertedTable, PseudonymizedTable}, - SerializedHPKE, }; /// The result of a split or join conversion is a set of blinded @@ -26,34 +26,22 @@ pub fn finalize_conversion( let mut pseudonymized_column_data = Vec::new(); for (blinded_pseudonym, encrypted_value) in blinded_table.column().data() { - let pseudonym = store_context.finalize_pseudonym(blinded_pseudonym)?; - - let outer_encryption = SerializedHPKE::from_bytes(&encrypted_value).to_hpke_ct(); - - let inner_encryption = SerializedHPKE::from_bytes(&HpkeOpen( - crate::HPKE_CONF, - &outer_encryption, - &store_context.hpke_sk, - b"Level-2", - b"", - None, - None, - None, - )?) - .to_hpke_ct(); - - let value = HpkeOpen( - crate::HPKE_CONF, - &inner_encryption, - &store_context.hpke_sk, - b"Level-1", - b"", - None, - None, - None, - )?; - - pseudonymized_column_data.push((pseudonym, value)); + let blinded_pseudonymized_datum = BlindedPseudonymizedData { + blinded_handle: BlindedPseudonymizedHandle(blinded_pseudonym), + encrypted_data_value: EncryptedDataValue { + attribute_name: blinded_table.column().attribute(), + value: encrypted_value, + encryption_level: 2u8, + }, + }; + + let pseudonymized_datum = + finalize_blinded_datum(&store_context, &blinded_pseudonymized_datum)?; + + pseudonymized_column_data.push(( + pseudonymized_datum.handle.0, + pseudonymized_datum.data_value.value, + )); } let mut pseudonymized_column = Column::new( diff --git a/hacspec-scrambledb/scrambledb/src/join.rs b/hacspec-scrambledb/scrambledb/src/join.rs index 7e7e514..31c107b 100644 --- a/hacspec-scrambledb/scrambledb/src/join.rs +++ b/hacspec-scrambledb/scrambledb/src/join.rs @@ -1,16 +1,18 @@ //! ## Join Conversion use hacspec_lib::Randomness; -use libcrux::hpke::{kem::Nsk, HPKEConfig, HpkePublicKey, HpkeSeal}; -use oprf::coprf::{ - coprf_online::{blind_convert, prepare_blind_convert}, - coprf_setup::{derive_key, BlindingPublicKey}, -}; +use libcrux::hpke::HpkePublicKey; +use oprf::coprf::coprf_setup::BlindingPublicKey; use crate::{ + data_transformations::{blind_pseudonymized_datum, convert_blinded_datum}, + data_types::{ + BlindedPseudonymizedData, BlindedPseudonymizedHandle, DataValue, EncryptedDataValue, + FinalizedPseudonym, PseudonymizedData, + }, error::Error, setup::{ConverterContext, StoreContext}, table::{BlindTable, Column, ConvertedTable, PseudonymizedTable}, - SerializedHPKE, SECPAR_BYTES, + SECPAR_BYTES, }; /// ### Preparation @@ -60,8 +62,8 @@ use crate::{ /// return blind_tables /// ``` pub fn prepare_join_conversion( - origin_context: &StoreContext, - bpk_target: BlindingPublicKey, + store_context: &StoreContext, + bpk_receiver: BlindingPublicKey, ek_receiver: &HpkePublicKey, pseudonymized_tables: Vec, randomness: &mut Randomness, @@ -72,24 +74,25 @@ pub fn prepare_join_conversion( let mut blind_column_data = Vec::new(); for (pseudonym, value) in table.column().data() { - let raw_pseudonym = origin_context.recover_raw_pseudonym(pseudonym)?; - let blinded_pseudonym = prepare_blind_convert(bpk_target, raw_pseudonym, randomness)?; - - let HPKEConfig(_, kem, _, _) = crate::HPKE_CONF; - let encrypted_value = SerializedHPKE::from_hpke_ct(&HpkeSeal( - crate::HPKE_CONF, - ek_receiver, - b"Level-1", - b"", - &value, - None, - None, - None, - randomness.bytes(Nsk(kem))?.to_vec(), - )?) - .to_bytes(); - - blind_column_data.push((blinded_pseudonym, encrypted_value)); + let pseudonymized_datum = PseudonymizedData { + handle: FinalizedPseudonym(pseudonym), + data_value: DataValue { + attribute_name: table.column().attribute(), + value: value, + }, + }; + let blinded_pseudonymized_datum = blind_pseudonymized_datum( + &store_context, + &bpk_receiver, + &ek_receiver, + &pseudonymized_datum, + randomness, + )?; + + blind_column_data.push(( + blinded_pseudonymized_datum.blinded_handle.0, + blinded_pseudonymized_datum.encrypted_data_value.value, + )); } let mut blind_column = Column::new(table.column().attribute(), blind_column_data); @@ -118,47 +121,41 @@ pub fn join_identifier(identifier: String) -> String { /// pub fn join_conversion( converter_context: &ConverterContext, - bpk_target: BlindingPublicKey, - ek_target: &HpkePublicKey, + bpk_receiver: BlindingPublicKey, + ek_receiver: &HpkePublicKey, tables: Vec, randomness: &mut Randomness, ) -> Result, Error> { let mut converted_tables = Vec::new(); - let join_conversion_key = derive_key( - &converter_context.coprf_context, - randomness.bytes(SECPAR_BYTES)?, - )?; + let conversion_target = randomness.bytes(SECPAR_BYTES)?.to_owned(); for table in tables { for blind_column in table.columns() { let attribute = blind_column.attribute(); - let pseudonym_key = derive_key(&converter_context.coprf_context, attribute.as_bytes())?; let mut converted_data = Vec::new(); for (blind_identifier, encrypted_value) in blind_column.data() { - let blind_pseudonym = blind_convert( - bpk_target, - pseudonym_key, - join_conversion_key, - blind_identifier, + let blinded_pseudonymized_datum = BlindedPseudonymizedData { + blinded_handle: BlindedPseudonymizedHandle(blind_identifier), + encrypted_data_value: EncryptedDataValue { + attribute_name: attribute.clone(), + value: encrypted_value, + encryption_level: 1u8, + }, + }; + let blinded_pseudonymized_datum = convert_blinded_datum( + &converter_context.coprf_context, + &bpk_receiver, + &ek_receiver, + &conversion_target, + &blinded_pseudonymized_datum, randomness, )?; - let HPKEConfig(_, kem, _, _) = crate::HPKE_CONF; - let encrypted_value = SerializedHPKE::from_hpke_ct(&HpkeSeal( - crate::HPKE_CONF, - ek_target, - b"Level-2", - b"", - &encrypted_value, - None, - None, - None, - randomness.bytes(Nsk(kem))?.to_vec(), - )?) - .to_bytes(); - - converted_data.push((blind_pseudonym, encrypted_value)); + converted_data.push(( + blinded_pseudonymized_datum.blinded_handle.0, + blinded_pseudonymized_datum.encrypted_data_value.value, + )); } let mut converted_table_column = Column::new(attribute.clone(), converted_data); converted_table_column.sort(); diff --git a/hacspec-scrambledb/scrambledb/src/lib.rs b/hacspec-scrambledb/scrambledb/src/lib.rs index aabefb7..b084d0b 100644 --- a/hacspec-scrambledb/scrambledb/src/lib.rs +++ b/hacspec-scrambledb/scrambledb/src/lib.rs @@ -269,6 +269,8 @@ pub mod setup; pub mod split; pub mod join; pub mod finalize; +pub mod data_transformations; +pub mod data_types; pub mod error; diff --git a/hacspec-scrambledb/scrambledb/src/split.rs b/hacspec-scrambledb/scrambledb/src/split.rs index df19375..3c08a9c 100644 --- a/hacspec-scrambledb/scrambledb/src/split.rs +++ b/hacspec-scrambledb/scrambledb/src/split.rs @@ -1,29 +1,23 @@ //! # Split Conversion use hacspec_lib::Randomness; -use libcrux::hpke::{kem::Nsk, HPKEConfig, HpkePublicKey, HpkeSeal}; -use oprf::coprf::{ - coprf_online::{blind, blind_evaluate}, - coprf_setup::{derive_key, BlindingPublicKey}, -}; +use libcrux::hpke::HpkePublicKey; +use oprf::coprf::coprf_setup::BlindingPublicKey; use crate::{ + data_transformations::{blind_identifiable_datum, pseudonymize_blinded_datum}, + data_types::{BlindedIdentifiableData, DataValue, EncryptedDataValue, IdentifiableData}, error::Error, setup::ConverterContext, table::{BlindTable, Column, ConvertedTable, PlainTable}, - SerializedHPKE, }; -pub fn split_identifier(identifier: String, attribute: String) -> String { +fn split_identifier(identifier: String, attribute: String) -> String { let mut split_identifier = identifier; split_identifier.push('-'); split_identifier.push_str(&attribute); split_identifier } -pub fn split_conversion_context() -> Vec { - b"Split-".to_vec() -} - /// ## Preparation /// /// - For each column of the table, go entry by entry, blinding the table key for the @@ -44,29 +38,20 @@ pub fn prepare_split_conversion( let mut blinded_column_data = Vec::new(); for (plaintext_id, plaintext_value) in column.data() { - let blinded_id = blind( - bpk_receiver, - plaintext_id.as_bytes(), - split_conversion_context(), - randomness, - )?; - - let HPKEConfig(_, kem, _, _) = crate::HPKE_CONF; - - let encrypted_value = SerializedHPKE::from_hpke_ct(&HpkeSeal( - crate::HPKE_CONF, - ek_receiver, - b"Level-1", - b"", - &plaintext_value, - None, - None, - None, - randomness.bytes(Nsk(kem))?.to_vec(), - )?) - .to_bytes(); - - blinded_column_data.push((blinded_id, encrypted_value)); + let datum = IdentifiableData { + handle: plaintext_id, + data_value: DataValue { + attribute_name: attribute.clone(), + value: plaintext_value, + }, + }; + let blinded_datum = + blind_identifiable_datum(&bpk_receiver, ek_receiver, &datum, randomness)?; + + blinded_column_data.push(( + blinded_datum.blinded_handle.0, + blinded_datum.encrypted_data_value.value, + )); } let mut blinded_column = Column::new(attribute, blinded_column_data); blinded_column.sort(); @@ -101,29 +86,29 @@ pub fn split_conversion( for blinded_column in blinded_table.columns() { let attribute = blinded_column.attribute(); - let conversion_key = derive_key(&converter_context.coprf_context, attribute.as_bytes())?; - let mut converted_column_data = Vec::new(); for (blind_identifier, encrypted_value) in blinded_column.data() { - let blinded_pseudonym = - blind_evaluate(conversion_key, bpk_receiver, blind_identifier, randomness)?; - - let HPKEConfig(_, kem, _, _) = crate::HPKE_CONF; - let hpke_ct = HpkeSeal( - crate::HPKE_CONF, + let blinded_datum = BlindedIdentifiableData { + blinded_handle: crate::data_types::BlindedIdentifiableHandle(blind_identifier), + encrypted_data_value: EncryptedDataValue { + attribute_name: attribute.clone(), + value: encrypted_value, + encryption_level: 1u8, + }, + }; + + let blinded_pseudonymized_datum = pseudonymize_blinded_datum( + &converter_context.coprf_context, + &bpk_receiver, ek_receiver, - b"Level-2", - b"", - &encrypted_value, - None, - None, - None, - randomness.bytes(Nsk(kem))?.to_vec(), + &blinded_datum, + randomness, )?; - let encrypted_value = SerializedHPKE::from_hpke_ct(&hpke_ct).to_bytes(); - - converted_column_data.push((blinded_pseudonym, encrypted_value)); + converted_column_data.push(( + blinded_pseudonymized_datum.blinded_handle.0, + blinded_pseudonymized_datum.encrypted_data_value.value, + )); } let mut converted_column = Column::new(attribute.clone(), converted_column_data);