Skip to content

Commit

Permalink
feat: use RevisionMap to store MasterSecretKey subkeys
Browse files Browse the repository at this point in the history
  • Loading branch information
Hugo Rosenkranz-Costa committed Nov 27, 2023
1 parent 5478832 commit 0ac541b
Show file tree
Hide file tree
Showing 8 changed files with 112 additions and 131 deletions.
1 change: 0 additions & 1 deletion src/abe_policy/access_policy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
39 changes: 14 additions & 25 deletions src/abe_policy/policy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<HashSet<Partition>, 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:?}")));
Expand Down Expand Up @@ -318,16 +313,16 @@ impl TryFrom<&Policy> for Vec<u8> {
///
/// - `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<HashSet<Partition>, Error> {
let mut attr_params_per_dim =
HashMap::<String, Vec<(u32, EncryptionHint, AttributeStatus)>>::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();
Expand Down Expand Up @@ -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] {
Expand All @@ -407,28 +399,26 @@ 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;
assert!(partitions_1.contains(&Partition::from_attribute_ids(vec![att_0_0, att_1_0])?));

// 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;
Expand All @@ -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;
Expand All @@ -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
Expand Down Expand Up @@ -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(
Expand All @@ -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);
Expand Down
9 changes: 5 additions & 4 deletions src/core/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)?,
))
}

Expand All @@ -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)?,
)
}

Expand All @@ -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)?,
)
}

Expand Down
7 changes: 3 additions & 4 deletions src/core/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use zeroize::ZeroizeOnDrop;

use crate::{
abe_policy::Partition,
data_struct::{RevisionMap, VersionedHashMap, VersionedVec},
data_struct::{RevisionMap, VersionedVec},
};

#[macro_use]
Expand Down Expand Up @@ -59,21 +59,20 @@ impl Deref for KyberSecretKey {
}
}

type Subkey = (Option<KyberSecretKey>, R25519PrivateKey);

#[derive(Debug, PartialEq, Eq)]
pub struct MasterPublicKey {
g1: R25519PublicKey,
g2: R25519PublicKey,
pub(crate) subkeys: RevisionMap<Partition, (Option<KyberPublicKey>, R25519PublicKey)>,
}

type Subkey = (Option<KyberSecretKey>, R25519PrivateKey);
#[derive(Debug, PartialEq, Eq)]
pub struct MasterSecretKey {
s: R25519PrivateKey,
s1: R25519PrivateKey,
s2: R25519PrivateKey,
pub(crate) subkeys: VersionedHashMap<Partition, Subkey>,
pub(crate) subkeys: RevisionMap<Partition, Subkey>,
kmac_key: Option<SymmetricKey<KMAC_KEY_LENGTH>>,
}

Expand Down
86 changes: 50 additions & 36 deletions src/core/primitives.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};

Expand Down Expand Up @@ -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 {
Expand All @@ -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));
}

Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -298,12 +297,13 @@ pub fn update(
mpk: &mut MasterPublicKey,
partitions_set: &HashMap<Partition, (EncryptionHint, AttributeStatus)>,
) -> 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.
Expand Down Expand Up @@ -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);
Expand All @@ -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));
Expand Down Expand Up @@ -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())))
}
Expand Down Expand Up @@ -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());

Expand Down Expand Up @@ -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());

Expand Down Expand Up @@ -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(())
}

Expand Down
Loading

0 comments on commit 0ac541b

Please sign in to comment.