diff --git a/src/abe_policy/access_policy.rs b/src/abe_policy/access_policy.rs index 5dabb1ce..ab6c8ce6 100644 --- a/src/abe_policy/access_policy.rs +++ b/src/abe_policy/access_policy.rs @@ -362,7 +362,6 @@ impl AccessPolicy { .ok_or_else(|| Error::DimensionNotFound(attr.dimension.to_string()))?; let mut res = vec![vec![attr.clone()]]; if include_lower_attributes_from_dim && dim_parameters.is_ordered() { - // TODO: optimize `Dict` for this step // add attribute values for all attributes below the given one for name in dim_parameters .get_attributes_name() diff --git a/src/abe_policy/policy.rs b/src/abe_policy/policy.rs index 533852d2..c7cc8274 100644 --- a/src/abe_policy/policy.rs +++ b/src/abe_policy/policy.rs @@ -270,23 +270,18 @@ impl Policy { /// partitions. /// /// - `access_policy` : access policy to convert - /// - `follow_hierarchical_axes` : set to `true` to combine lower dim + /// - `follow_hierarchical_dim` : set to `true` to combine lower dim /// attributes pub fn access_policy_to_partitions( &self, access_policy: &AccessPolicy, - follow_hierarchical_axes: bool, - include_old_rotations: bool, + follow_hierarchical_dim: bool, ) -> Result, Error> { let attr_combinations = - access_policy.to_attribute_combinations(self, follow_hierarchical_axes)?; + access_policy.to_attribute_combinations(self, follow_hierarchical_dim)?; let mut res = HashSet::with_capacity(attr_combinations.len()); for attr_combination in &attr_combinations { - for partition in generate_current_attribute_partitions( - attr_combination, - self, - include_old_rotations, - )? { + for partition in generate_attribute_partitions(attr_combination, self)? { let is_unique = res.insert(partition); if !is_unique { return Err(Error::ExistingCombination(format!("{attr_combination:?}"))); @@ -318,16 +313,16 @@ impl TryFrom<&Policy> for Vec { /// /// - `attributes` : list of attributes /// - `policy` : global policy data -fn generate_current_attribute_partitions( +fn generate_attribute_partitions( attributes: &[Attribute], policy: &Policy, - _include_old_partitions: bool, ) -> Result, Error> { let mut attr_params_per_dim = HashMap::>::with_capacity( policy.dimensions.len(), ); // maximum bound for attribute in attributes.iter() { + // TODO: move logic to dimension? let entry = attr_params_per_dim .entry(attribute.dimension.clone()) .or_default(); @@ -393,11 +388,8 @@ mod tests { // this should create the combination of the first attribute // with all those of the second dim - let partitions_0 = generate_current_attribute_partitions( - &[axes_attributes[0][0].0.clone()], - &policy, - false, - )?; + let partitions_0 = + generate_attribute_partitions(&[axes_attributes[0][0].0.clone()], &policy)?; assert_eq!(axes_attributes[1].len(), partitions_0.len()); let att_0_0 = axes_attributes[0][0].1; for (_attribute, value) in &axes_attributes[1] { @@ -407,13 +399,12 @@ mod tests { // this should create the single combination of the first attribute // of the first dim with that of the second dim - let partitions_1 = generate_current_attribute_partitions( + let partitions_1 = generate_attribute_partitions( &[ axes_attributes[0][0].0.clone(), axes_attributes[1][0].0.clone(), ], &policy, - false, )?; assert_eq!(partitions_1.len(), 1); let att_1_0 = axes_attributes[1][0].1; @@ -421,14 +412,13 @@ mod tests { // this should create the 2 combinations of the first attribute // of the first dim with that the wo of the second dim - let partitions_2 = generate_current_attribute_partitions( + let partitions_2 = generate_attribute_partitions( &[ axes_attributes[0][0].0.clone(), axes_attributes[1][0].0.clone(), axes_attributes[1][1].0.clone(), ], &policy, - false, )?; assert_eq!(partitions_2.len(), 2); let att_1_0 = axes_attributes[1][0].1; @@ -442,13 +432,12 @@ mod tests { // this should create the single combination of the first attribute // of the first dim with that of the second dim - let partitions_3 = generate_current_attribute_partitions( + let partitions_3 = generate_attribute_partitions( &[ axes_attributes[0][0].0.clone(), axes_attributes[1][0].0.clone(), ], &policy, - false, )?; assert_eq!(partitions_3.len(), 1); let att_1_0 = axes_attributes[1][0].1; @@ -474,7 +463,7 @@ mod tests { // // create partitions from access policy - let partitions = policy.access_policy_to_partitions(&access_policy, true, false)?; + let partitions = policy.access_policy_to_partitions(&access_policy, true)?; // // manually create the partitions @@ -514,7 +503,7 @@ mod tests { ) .unwrap(); let partition_4 = policy - .access_policy_to_partitions(&policy_attributes_4, true, false) + .access_policy_to_partitions(&policy_attributes_4, true) .unwrap(); let policy_attributes_5 = AccessPolicy::from_boolean_expression( @@ -523,7 +512,7 @@ mod tests { ) .unwrap(); let partition_5 = policy - .access_policy_to_partitions(&policy_attributes_5, true, false) + .access_policy_to_partitions(&policy_attributes_5, true) .unwrap(); assert_eq!(partition_4.len(), 4); assert_eq!(partition_5.len(), 5); diff --git a/src/core/api.rs b/src/core/api.rs index de2fb11f..3ac8f5f3 100644 --- a/src/core/api.rs +++ b/src/core/api.rs @@ -90,7 +90,7 @@ impl Covercrypt { Ok(keygen( &mut *self.rng.lock().expect("Mutex lock failed!"), msk, - &policy.access_policy_to_partitions(access_policy, true, false)?, + &policy.access_policy_to_partitions(access_policy, true)?, )) } @@ -113,12 +113,13 @@ impl Covercrypt { access_policy: &AccessPolicy, msk: &MasterSecretKey, policy: &Policy, - keep_old_rotations: bool, + _keep_old_rotations: bool, ) -> Result<(), Error> { + // TODO: use keep_old_rotations refresh( msk, usk, - &policy.access_policy_to_partitions(access_policy, true, keep_old_rotations)?, + &policy.access_policy_to_partitions(access_policy, true)?, ) } @@ -138,7 +139,7 @@ impl Covercrypt { encaps( &mut *self.rng.lock().expect("Mutex lock failed!"), pk, - &policy.access_policy_to_partitions(access_policy, false, false)?, + &policy.access_policy_to_partitions(access_policy, false)?, ) } diff --git a/src/core/mod.rs b/src/core/mod.rs index 16e6c627..d9982619 100644 --- a/src/core/mod.rs +++ b/src/core/mod.rs @@ -8,7 +8,7 @@ use zeroize::ZeroizeOnDrop; use crate::{ abe_policy::Partition, - data_struct::{RevisionMap, VersionedHashMap, VersionedVec}, + data_struct::{RevisionMap, VersionedVec}, }; #[macro_use] @@ -59,8 +59,6 @@ impl Deref for KyberSecretKey { } } -type Subkey = (Option, R25519PrivateKey); - #[derive(Debug, PartialEq, Eq)] pub struct MasterPublicKey { g1: R25519PublicKey, @@ -68,12 +66,13 @@ pub struct MasterPublicKey { pub(crate) subkeys: RevisionMap, R25519PublicKey)>, } +type Subkey = (Option, R25519PrivateKey); #[derive(Debug, PartialEq, Eq)] pub struct MasterSecretKey { s: R25519PrivateKey, s1: R25519PrivateKey, s2: R25519PrivateKey, - pub(crate) subkeys: VersionedHashMap, + pub(crate) subkeys: RevisionMap, kmac_key: Option>, } diff --git a/src/core/primitives.rs b/src/core/primitives.rs index 19c1703f..fb6808af 100644 --- a/src/core/primitives.rs +++ b/src/core/primitives.rs @@ -24,7 +24,7 @@ use super::{ use crate::{ abe_policy::{AttributeStatus, EncryptionHint, Partition}, core::{Encapsulation, KeyEncapsulation, MasterPublicKey, MasterSecretKey, UserSecretKey}, - data_struct::{RevisionMap, VersionedHashMap, VersionedVec}, + data_struct::{RevisionMap, VersionedVec}, Error, }; @@ -90,7 +90,7 @@ pub fn setup( let g1 = R25519PublicKey::from(&s1); let g2 = R25519PublicKey::from(&s2); - let mut sub_sk = VersionedHashMap::with_capacity(partitions.len()); + let mut sub_sk = RevisionMap::with_capacity(partitions.len()); let mut sub_pk = RevisionMap::with_capacity(partitions.len()); for (partition, &(is_hybridized, _)) in partitions { @@ -108,9 +108,7 @@ pub fn setup( (None, None) }; - sub_sk - .insert_root(partition.clone(), (sk_pq, sk_i)) - .expect("Partitions are unique"); + sub_sk.insert(partition.clone(), (sk_pq, sk_i)); sub_pk.insert(partition.clone(), (pk_pq, pk_i)); } @@ -149,12 +147,13 @@ pub fn keygen( ) -> UserSecretKey { let a = R25519PrivateKey::new(rng); let b = &(&msk.s - &(&a * &msk.s1)) / &msk.s2; - // Only the last partitions rotation are used + // Use the last key for each partitions in the decryption set + // TODO: error out if missing partitions? let subkeys: VersionedVec<_> = decryption_set .iter() .filter_map(|partition| { msk.subkeys - .get(partition) + .get_current_revision(partition) .map(|subkey| (partition.clone(), subkey.clone())) }) .collect(); @@ -298,12 +297,13 @@ pub fn update( mpk: &mut MasterPublicKey, partitions_set: &HashMap, ) -> Result<(), Error> { - let mut new_sub_sk = VersionedHashMap::with_capacity(partitions_set.len()); + let mut new_sub_sk = RevisionMap::with_capacity(partitions_set.len()); let mut new_sub_pk = RevisionMap::with_capacity(partitions_set.len()); let h = R25519PublicKey::from(&msk.s); for (partition, &(is_hybridized, write_status)) in partitions_set { - if let Some((sk_i, x_i)) = msk.subkeys.get(partition) { + // TODO: get all revisions + if let Some((sk_i, x_i)) = msk.subkeys.get_current_revision(partition) { // regenerate the public sub-key. let h_i = &h * x_i; // Set the correct hybridization property. @@ -336,9 +336,7 @@ pub fn update( } new_sub_pk.insert(partition.clone(), (pk_i, h_i)); } - new_sub_sk - .insert_root(partition.clone(), (sk_i, x_i.clone())) - .expect("Partitions are unique"); + new_sub_sk.insert(partition.clone(), (sk_i, x_i.clone())); } else { // Create new entry. let x_i = R25519PrivateKey::new(rng); @@ -353,9 +351,7 @@ pub fn update( } else { (None, None) }; - new_sub_sk - .insert_root(partition.clone(), (sk_pq, x_i)) - .expect("Partitions are unique"); + new_sub_sk.insert(partition.clone(), (sk_pq, x_i)); if write_status == AttributeStatus::EncryptDecrypt { // Only add non read only partition to the public key new_sub_pk.insert(partition.clone(), (pk_pq, h_i)); @@ -395,7 +391,7 @@ pub fn refresh( usk.subkeys.clear(); for partition in decryption_set { - if let Some(x_i) = msk.subkeys.get(partition) { + if let Some(x_i) = msk.subkeys.get_current_revision(partition) { usk.subkeys .insert_new_chain(iter::once((partition.clone(), x_i.clone()))) } @@ -454,12 +450,12 @@ mod tests { let (mut msk, mut mpk) = setup(&mut rng, &partitions_set); // The admin partition matches a hybridized sub-key. - let admin_secret_subkeys = msk.subkeys.get(&admin_partition); + let admin_secret_subkeys = msk.subkeys.get_current_revision(&admin_partition); assert!(admin_secret_subkeys.is_some()); assert!(admin_secret_subkeys.unwrap().0.is_some()); // The developer partition matches a classic sub-key. - let dev_secret_subkeys = msk.subkeys.get(&dev_partition); + let dev_secret_subkeys = msk.subkeys.get_current_revision(&dev_partition); assert!(dev_secret_subkeys.is_some()); assert!(dev_secret_subkeys.unwrap().0.is_none()); @@ -504,12 +500,12 @@ mod tests { refresh(&msk, &mut dev_usk, &HashSet::from([dev_partition.clone()]))?; // The dev partition matches a hybridized sub-key. - let dev_secret_subkeys = msk.subkeys.get(&dev_partition); + let dev_secret_subkeys = msk.subkeys.get_current_revision(&dev_partition); assert!(dev_secret_subkeys.is_some()); assert!(dev_secret_subkeys.unwrap().0.is_some()); // The client partition matches a classic sub-key. - let client_secret_subkeys = msk.subkeys.get(&client_partition); + let client_secret_subkeys = msk.subkeys.get_current_revision(&client_partition); assert!(client_secret_subkeys.is_some()); assert!(client_secret_subkeys.unwrap().0.is_none()); @@ -655,26 +651,44 @@ mod tests { &mut usk, &HashSet::from([partition_2.clone(), partition_4.clone()]), )?; - assert!(!usk.subkeys.iter().any(|x| x - == &( + assert!(!usk.subkeys.iter().any(|x| { + x == &( partition_1.clone(), - old_msk.subkeys.get(&partition_1).unwrap().clone() - ))); - assert!(usk.subkeys.iter().any(|x| x - == &( + old_msk + .subkeys + .get_current_revision(&partition_1) + .unwrap() + .clone(), + ) + })); + assert!(usk.subkeys.iter().any(|x| { + x == &( partition_2.clone(), - msk.subkeys.get(&partition_2).unwrap().clone() - ))); - assert!(!usk.subkeys.iter().any(|x| x - == &( + msk.subkeys + .get_current_revision(&partition_2) + .unwrap() + .clone(), + ) + })); + assert!(!usk.subkeys.iter().any(|x| { + x == &( partition_3.clone(), - old_msk.subkeys.get(&partition_3).unwrap().clone() - ))); - assert!(usk.subkeys.iter().any(|x| x - == &( + old_msk + .subkeys + .get_current_revision(&partition_3) + .unwrap() + .clone(), + ) + })); + assert!(usk.subkeys.iter().any(|x| { + x == &( partition_4.clone(), - msk.subkeys.get(&partition_4).unwrap().clone() - ))); + msk.subkeys + .get_current_revision(&partition_4) + .unwrap() + .clone(), + ) + })); Ok(()) } diff --git a/src/core/serialization.rs b/src/core/serialization.rs index 5e578e82..640475f7 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::{RevisionMap, VersionedHashMap, VersionedVec}, + data_struct::{RevisionMap, VersionedVec}, CleartextHeader, EncryptedHeader, Error, }; @@ -62,13 +62,13 @@ impl Serializable for MasterPublicKey { let mut length = 2 * R25519PublicKey::LENGTH // subkeys serialization + to_leb128_len(self.subkeys.nb_chains()) - // upper bound on chains leb128 length - + self.subkeys.nb_chains() * to_leb128_len(self.subkeys.len()) + self.subkeys.len() * R25519PublicKey::LENGTH; - for (partition, (pk_i, _)) in self.subkeys.iter() { - // TODO: partitions should only be counted once - length += (to_leb128_len(partition.len()) + partition.len()) - + serialize_len_option!(pk_i, _value, KYBER_INDCPA_PUBLICKEYBYTES); + for (partition, chain) in &self.subkeys.map { + length += to_leb128_len(partition.len()) + partition.len(); + length += to_leb128_len(chain.len()); + for (pk_i, _) in chain { + length += serialize_len_option!(pk_i, _value, KYBER_INDCPA_PUBLICKEYBYTES); + } } length } @@ -80,9 +80,9 @@ impl Serializable for MasterPublicKey { for (partition, chain) in &self.subkeys.map { n += ser.write_vec(partition)?; n += ser.write_leb128_u64(chain.len() as u64)?; - for (sk_i, x_i) in chain { - serialize_option!(ser, n, sk_i, value, ser.write_array(value)); - n += ser.write_array(&x_i.to_bytes())?; + for (pk_i, h_i) in chain { + serialize_option!(ser, n, pk_i, value, ser.write_array(value)); + n += ser.write_array(&h_i.to_bytes())?; } } Ok(n) @@ -98,9 +98,9 @@ impl Serializable for MasterPublicKey { let n_keys = ::try_from(de.read_leb128_u64()?)?; let chain: Result, Self::Error> = (0..n_keys) .map(|_| { - let sk_i = deserialize_option!(de, KyberPublicKey(de.read_array()?)); - let x_i = de.read_array::<{ R25519PublicKey::LENGTH }>()?; - Ok((sk_i, R25519PublicKey::try_from_bytes(x_i)?)) + let pk_i = deserialize_option!(de, KyberPublicKey(de.read_array()?)); + let h_i = de.read_array::<{ R25519PublicKey::LENGTH }>()?; + Ok((pk_i, R25519PublicKey::try_from_bytes(h_i)?)) }) .collect(); subkeys.map.insert(partition, chain?); @@ -113,17 +113,16 @@ impl Serializable for MasterSecretKey { type Error = Error; fn length(&self) -> usize { - let mut length = 3 * R25519PrivateKey::LENGTH - + self.kmac_key.as_ref().map_or_else(|| 0, |key| key.len()) + let mut length = 2 * R25519PublicKey::LENGTH // subkeys serialization - + to_leb128_len(self.subkeys.len()) - + self.subkeys.len() * R25519PrivateKey::LENGTH; - for (partition, entry) in &self.subkeys.map { - let (sk_i, _) = &entry.value; - length += (to_leb128_len(partition.len()) + partition.len()) - + serialize_len_option!(&entry.next_key, v, to_leb128_len(v.len()) + v.len()) - + serialize_len_option!(&entry.prev_key, v, to_leb128_len(v.len()) + v.len()) - + serialize_len_option!(sk_i, _value, KYBER_INDCPA_SECRETKEYBYTES); + + to_leb128_len(self.subkeys.nb_chains()) + + self.subkeys.len() * R25519PublicKey::LENGTH; + for (partition, chain) in &self.subkeys.map { + length += to_leb128_len(partition.len()) + partition.len(); + length += to_leb128_len(chain.len()); + for (sk_i, _) in chain { + length += serialize_len_option!(sk_i, _value, KYBER_INDCPA_SECRETKEYBYTES); + } } length } @@ -132,17 +131,14 @@ impl Serializable for MasterSecretKey { let mut n = ser.write_array(&self.s1.to_bytes())?; n += ser.write_array(&self.s2.to_bytes())?; n += ser.write_array(&self.s.to_bytes())?; - n += ser.write_leb128_u64(self.subkeys.len() as u64)?; - for (partition, entry) in &self.subkeys.map { - // serialize partition, next and prev + n += ser.write_leb128_u64(self.subkeys.nb_chains() as u64)?; + for (partition, chain) in &self.subkeys.map { n += ser.write_vec(partition)?; - serialize_option!(ser, n, entry.next_key, value, ser.write_vec(value)); - serialize_option!(ser, n, entry.prev_key, value, ser.write_vec(value)); - - // serialize key values - let (sk_i, x_i) = &entry.value; - serialize_option!(ser, n, sk_i, value, ser.write_array(value)); - n += ser.write_array(&x_i.to_bytes())?; + n += ser.write_leb128_u64(chain.len() as u64)?; + for (sk_i, x_i) in chain { + serialize_option!(ser, n, sk_i, value, ser.write_array(value)); + n += ser.write_array(&x_i.to_bytes())?; + } } if let Some(kmac_key) = &self.kmac_key { n += ser.write_array(kmac_key)?; @@ -159,16 +155,18 @@ impl Serializable for MasterSecretKey { let s = R25519PrivateKey::try_from_bytes(de.read_array::<{ R25519PrivateKey::LENGTH }>()?)?; let n_partitions = ::try_from(de.read_leb128_u64()?)?; - let mut subkeys = VersionedHashMap::with_capacity(n_partitions); + let mut subkeys = RevisionMap::with_capacity(n_partitions); for _ in 0..n_partitions { let partition = Partition::from(de.read_vec()?); - let next = deserialize_option!(de, de.read_vec()?).map(Partition::from); - let prev = deserialize_option!(de, de.read_vec()?).map(Partition::from); - - let sk_i = deserialize_option!(de, KyberSecretKey(de.read_array()?)); - let x_i = de.read_array::<{ R25519PrivateKey::LENGTH }>()?; - let value = (sk_i, R25519PrivateKey::try_from_bytes(x_i)?); - subkeys.insert_entry(partition, next, prev, value); + let n_keys = ::try_from(de.read_leb128_u64()?)?; + 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 }>()?; + Ok((sk_i, R25519PrivateKey::try_from_bytes(x_i)?)) + }) + .collect(); + subkeys.map.insert(partition, chain?); } let kmac_key = match de.read_array::<{ KMAC_KEY_LENGTH }>() { @@ -234,7 +232,6 @@ impl Serializable for UserSecretKey { let n_partitions = ::try_from(de.read_leb128_u64()?)?; let it = (0..n_partitions) .map(|_| { - // TODO: extract in function or macro? let partition = de.read_vec()?; let sk_i = deserialize_option!(de, KyberSecretKey(de.read_array()?)); let x_i = de.read_array::<{ R25519PrivateKey::LENGTH }>()?; diff --git a/src/data_struct/versioned_hashmap.rs b/src/data_struct/versioned_hashmap.rs index da0a911b..07e5d57f 100644 --- a/src/data_struct/versioned_hashmap.rs +++ b/src/data_struct/versioned_hashmap.rs @@ -124,24 +124,6 @@ where self.map.get(key) } - /// Internal insertion method - pub(crate) fn insert_entry( - &mut self, - key: K, - next_key: Option, - prev_key: Option, - value: V, - ) -> Option> { - self.map.insert( - key, - VersionedEntry { - value, - prev_key, - next_key, - }, - ) - } - pub fn insert_root(&mut self, key: K, value: V) -> Result<(), Error> { match self.map.entry(key.clone()) { Entry::Occupied(_) => Err(Error::existing_entry(&key)), diff --git a/src/test_utils/mod.rs b/src/test_utils/mod.rs index f04f06c5..f43f4e2f 100644 --- a/src/test_utils/mod.rs +++ b/src/test_utils/mod.rs @@ -190,7 +190,7 @@ mod tests { let part = Partition::from(vec![1, 6]); usk.subkeys.insert_new_chain(iter::once(( part.clone(), - msk.subkeys.get(&part).unwrap().clone(), + msk.subkeys.get_current_revision(&part).unwrap().clone(), ))); assert!(cover_crypt .refresh_user_secret_key(&mut usk, &decryption_policy, &msk, &policy, false)