Skip to content

Commit

Permalink
feat: store MPK subkeys in regular HashMap
Browse files Browse the repository at this point in the history
  • Loading branch information
Hugo Rosenkranz-Costa committed Nov 29, 2023
1 parent 10d5cdb commit 4d01909
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 42 deletions.
20 changes: 17 additions & 3 deletions src/core/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use cosmian_crypto_core::{
use crate::{
abe_policy::{AccessPolicy, Policy},
core::{
primitives::{decaps, encaps, keygen, refresh, setup, update},
primitives::{decaps, encaps, keygen, refresh, rekey, setup, update},
Encapsulation, MasterPublicKey, MasterSecretKey, UserSecretKey, SYM_KEY_LENGTH,
},
Error,
Expand Down Expand Up @@ -74,6 +74,22 @@ impl Covercrypt {
)
}

/// Generates new key pairs for a given AccessPolicy
pub fn rekey_master_keys(
&self,
access_policy: &AccessPolicy,
policy: &Policy,
msk: &mut MasterSecretKey,
mpk: &mut MasterPublicKey,
) -> Result<(), Error> {
rekey(
&mut *self.rng.lock().expect("Mutex lock failed!"),
msk,
mpk,
&policy.access_policy_to_partitions(access_policy, false)?,
)
}

/// Generates a user secret key.
///
/// A new user secret key does NOT include to old (i.e. rotated) partitions.
Expand Down Expand Up @@ -103,7 +119,6 @@ impl Covercrypt {
///
/// - `usk` : the user key to refresh
/// - `msk` : master secret key
/// - `policy` : global policy of the master secret key
/// - `keep_old_accesses` : whether access to old partitions (i.e. before
/// rotation) should be kept
pub fn refresh_user_secret_key(
Expand All @@ -112,7 +127,6 @@ impl Covercrypt {
msk: &MasterSecretKey,
keep_old_rights: bool,
) -> Result<(), Error> {
// TODO: use keep_old_rotations
refresh(msk, usk, keep_old_rights)
}

Expand Down
8 changes: 6 additions & 2 deletions src/core/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
//! Implements the core functionalities of `Covercrypt`.
use std::{collections::HashSet, hash::Hash, ops::Deref};
use std::{
collections::{HashMap, HashSet},
hash::Hash,
ops::Deref,
};

use cosmian_crypto_core::{R25519PrivateKey, R25519PublicKey, SymmetricKey};
use pqc_kyber::{KYBER_INDCPA_BYTES, KYBER_INDCPA_PUBLICKEYBYTES, KYBER_INDCPA_SECRETKEYBYTES};
Expand Down Expand Up @@ -63,7 +67,7 @@ impl Deref for KyberSecretKey {
pub struct MasterPublicKey {
g1: R25519PublicKey,
g2: R25519PublicKey,
pub(crate) subkeys: RevisionMap<Partition, (Option<KyberPublicKey>, R25519PublicKey)>,
pub(crate) subkeys: HashMap<Partition, (Option<KyberPublicKey>, R25519PublicKey)>,
}

type Subkey = (Option<KyberSecretKey>, R25519PrivateKey);
Expand Down
32 changes: 19 additions & 13 deletions src/core/primitives.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ pub fn setup(
let g2 = R25519PublicKey::from(&s2);

let mut sub_sk = RevisionMap::with_capacity(partitions.len());
let mut sub_pk = RevisionMap::with_capacity(partitions.len());
let mut sub_pk = HashMap::with_capacity(partitions.len());

for (partition, &(is_hybridized, _)) in partitions {
let ((pk_i, pk_pq), (sk_i, sk_pq)) = create_key_pair(rng, &h, is_hybridized);
Expand Down Expand Up @@ -197,7 +197,7 @@ pub fn encaps(
let c2 = &mpk.g2 * &r;
let mut encs = HashSet::with_capacity(encryption_set.len());
for partition in encryption_set {
if let Some((pk_i, h_i)) = mpk.subkeys.get_current_revision(partition) {
if let Some((pk_i, h_i)) = mpk.subkeys.get(partition) {
let mut e_i = [0; SYM_KEY_LENGTH];
kdf256!(&mut e_i, &(h_i * &r).to_bytes());
xor_in_place(&mut e_i, &seed);
Expand Down Expand Up @@ -306,11 +306,11 @@ pub fn update(
partitions_set: &HashMap<Partition, (EncryptionHint, AttributeStatus)>,
) -> Result<(), Error> {
let mut new_sub_sk = RevisionMap::with_capacity(partitions_set.len());
let mut new_sub_pk = RevisionMap::with_capacity(partitions_set.len());
let mut new_sub_pk = HashMap::with_capacity(partitions_set.len());
let h = R25519PublicKey::from(&msk.s);

for (partition, &(is_hybridized, write_status)) in partitions_set {
// TODO: get all revisions
// only regenerate public subkey for current subkey in master secret key
if let Some((sk_i, x_i)) = msk.subkeys.get_current_revision(partition) {
// regenerate the public sub-key.
let h_i = &h * x_i;
Expand All @@ -319,7 +319,7 @@ pub fn update(
if sk_i.is_some() {
let pk_i = mpk
.subkeys
.get_current_revision(partition)
.get(partition)
.map(|(pk_i, _)| pk_i)
.unwrap_or(&None);
(sk_i.clone(), pk_i.clone())
Expand Down Expand Up @@ -373,20 +373,26 @@ pub fn update(
Ok(())
}

pub fn rotate(
pub fn rekey(
rng: &mut impl CryptoRngCore,
msk: &mut MasterSecretKey,
mpk: &mut MasterPublicKey,
partitions_to_rotate: &HashMap<Partition, (EncryptionHint, AttributeStatus)>,
partitions_to_rotate: &HashSet<Partition>,
) -> Result<(), Error> {
// let partitions_to_rotate =
// self.access_policy_to_partitions(&AccessPolicy::Attr(attr.clone()),
// false)?;
let h = R25519PublicKey::from(&msk.s);
for (partition, (is_hybridized, write_status)) in partitions_to_rotate {
let ((pk_i, pk_pq), (sk_i, sk_pq)) = create_key_pair(rng, &h, *is_hybridized);
for partition in partitions_to_rotate {
// write a `get_encryption`` function in a dedicated Subkey class?
let is_hybridized = EncryptionHint::new(
msk.subkeys
.get_current_revision(partition)
.and_then(|(sk_i, _)| sk_i.as_ref())
.is_some(),
);
let ((pk_i, pk_pq), (sk_i, sk_pq)) = create_key_pair(rng, &h, is_hybridized);
msk.subkeys.insert(partition.clone(), (sk_pq, sk_i));
if *write_status == AttributeStatus::EncryptDecrypt {

// update public subkey if partition is not read only
if mpk.subkeys.contains_key(partition) {
mpk.subkeys.insert(partition.clone(), (pk_pq, pk_i));
}
}
Expand Down
37 changes: 13 additions & 24 deletions src/core/serialization.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! Implements the serialization methods for the `Covercrypt` objects.
use std::collections::{HashSet, LinkedList};
use std::collections::{HashMap, HashSet, LinkedList};

use cosmian_crypto_core::{
bytes_ser_de::{to_leb128_len, Deserializer, Serializable, Serializer},
Expand Down Expand Up @@ -61,29 +61,23 @@ impl Serializable for MasterPublicKey {
fn length(&self) -> usize {
let mut length = 2 * R25519PublicKey::LENGTH
// subkeys serialization
+ to_leb128_len(self.subkeys.nb_chains())
+ to_leb128_len(self.subkeys.len())
+ self.subkeys.len() * R25519PublicKey::LENGTH;
for (partition, chain) in &self.subkeys.map {
for (partition, (pk_i, _)) in &self.subkeys {
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 += serialize_len_option!(pk_i, _value, KYBER_INDCPA_PUBLICKEYBYTES);
}
length
}

fn write(&self, ser: &mut Serializer) -> Result<usize, Self::Error> {
let mut n = ser.write_array(&self.g1.to_bytes())?;
n += ser.write_array(&self.g2.to_bytes())?;
n += ser.write_leb128_u64(self.subkeys.nb_chains() as u64)?;
for (partition, chain) in &self.subkeys.map {
n += ser.write_leb128_u64(self.subkeys.len() as u64)?;
for (partition, (pk_i, h_i)) in &self.subkeys {
n += ser.write_vec(partition)?;
n += ser.write_leb128_u64(chain.len() as u64)?;
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())?;
}
serialize_option!(ser, n, pk_i, value, ser.write_array(value));
n += ser.write_array(&h_i.to_bytes())?;
}
Ok(n)
}
Expand All @@ -92,18 +86,13 @@ impl Serializable for MasterPublicKey {
let g1 = R25519PublicKey::try_from_bytes(de.read_array::<{ R25519PublicKey::LENGTH }>()?)?;
let g2 = R25519PublicKey::try_from_bytes(de.read_array::<{ R25519PublicKey::LENGTH }>()?)?;
let n_partitions = <usize>::try_from(de.read_leb128_u64()?)?;
let mut subkeys = RevisionMap::with_capacity(n_partitions);
let mut subkeys = HashMap::with_capacity(n_partitions);
for _ in 0..n_partitions {
let partition = Partition::from(de.read_vec()?);
let n_keys = <usize>::try_from(de.read_leb128_u64()?)?;
let chain: Result<LinkedList<_>, Self::Error> = (0..n_keys)
.map(|_| {
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?);
let pk_i = deserialize_option!(de, KyberPublicKey(de.read_array()?));
let h_i =
R25519PublicKey::try_from_bytes(de.read_array::<{ R25519PublicKey::LENGTH }>()?)?;
subkeys.insert(partition, (pk_i, h_i));
}
Ok(Self { g1, g2, subkeys })
}
Expand Down

0 comments on commit 4d01909

Please sign in to comment.