Skip to content

Commit

Permalink
fix full_decaps
Browse files Browse the repository at this point in the history
  • Loading branch information
tbrezot committed Feb 11, 2025
1 parent 06da809 commit f44a970
Show file tree
Hide file tree
Showing 6 changed files with 146 additions and 86 deletions.
1 change: 1 addition & 0 deletions examples/encrypt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use cosmian_crypto_core::{
Aes256Gcm,
};

#[allow(dead_code)]
/// Generates a new USK and encrypted header and prints them.
fn generate_new(cc: &Covercrypt, msk: &mut MasterSecretKey, mpk: &MasterPublicKey) {
let ap = AccessPolicy::parse("DPT::FIN && SEC::TOP").unwrap();
Expand Down
32 changes: 16 additions & 16 deletions src/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use super::{
};
use crate::{
core::{
primitives::{decaps, encaps, refresh, rekey, setup},
primitives::{decaps, encaps, full_decaps, refresh, rekey, setup},
MasterPublicKey, MasterSecretKey, UserSecretKey, XEnc, SHARED_SECRET_LENGTH,
},
traits::{KemAc, PkeAc},
Expand Down Expand Up @@ -147,21 +147,21 @@ impl Covercrypt {
)
}

// /// Returns a new encapsulation with the same rights as the one given, along
// /// with a freshly generated shared secret.
// pub fn recaps(
// &self,
// msk: &MasterSecretKey,
// mpk: &MasterPublicKey,
// encapsulation: &XEnc,
// ) -> Result<(Secret<32>, XEnc), Error> {
// let (_ss, rights) = full_decaps(msk, encapsulation)?;
// encaps(
// &mut *self.rng.lock().expect("Mutex lock failed!"),
// mpk,
// &rights,
// )
// }
/// Returns a new encapsulation with the same rights as the one given, along
/// with a freshly generated shared secret.
pub fn recaps(
&self,
msk: &MasterSecretKey,
mpk: &MasterPublicKey,
encapsulation: &XEnc,
) -> Result<(Secret<32>, XEnc), Error> {
let (_ss, rights) = full_decaps(msk, encapsulation)?;
encaps(
&mut *self.rng.lock().expect("Mutex lock failed!"),
mpk,
&rights,
)
}
}

impl KemAc<SHARED_SECRET_LENGTH> for Covercrypt {
Expand Down
21 changes: 12 additions & 9 deletions src/core/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -158,15 +158,15 @@ impl UserId {
#[derive(Debug, PartialEq, Eq)]
struct TracingSecretKey {
s: Scalar,
tracers: LinkedList<Scalar>,
tracers: LinkedList<(Scalar, EcPoint)>,
users: HashSet<UserId>,
}

impl TracingSecretKey {
fn new_with_level(level: usize, rng: &mut impl CryptoRngCore) -> Result<Self, Error> {
let s = nike::Scalar::new(rng);
let tracers = (0..=level)
.map(|_| R25519::keygen(rng).map(|kp| kp.0))
.map(|_| R25519::keygen(rng))
.collect::<Result<_, _>>()?;
let users = HashSet::new();

Expand All @@ -178,14 +178,18 @@ impl TracingSecretKey {
self.tracers.len() - 1
}

fn set_traps(&self, r: &Scalar) -> Vec<EcPoint> {
self.tracers.iter().map(|(_, Pi)| Pi * r).collect()
}

/// Generates a new tracer. Returns the associated trap.
fn _increase_tracing(&mut self, rng: &mut impl CryptoRngCore) -> Result<(), Error> {
self.tracers.push_back(R25519::keygen(rng)?.0);
self.tracers.push_back(R25519::keygen(rng)?);
Ok(())
}

/// Drops the oldest tracer and returns it.
fn _decrease_tracing(&mut self) -> Result<Scalar, Error> {
fn _decrease_tracing(&mut self) -> Result<(Scalar, EcPoint), Error> {
if self.tracing_level() == MIN_TRACING_LEVEL {
Err(Error::OperationNotPermitted(format!(
"tracing level cannot be lower than {MIN_TRACING_LEVEL}"
Expand Down Expand Up @@ -236,7 +240,7 @@ impl TracingSecretKey {
/// Generates the associated tracing public key.
#[must_use]
fn tpk(&self) -> TracingPublicKey {
TracingPublicKey(self.tracers.iter().map(|s| s.into()).collect())
TracingPublicKey(self.tracers.iter().map(|(_, Pi)| Pi).cloned().collect())
}

/// Returns the binding points.
Expand All @@ -246,7 +250,7 @@ impl TracingSecretKey {

/// Generates a new ID and adds it to the list of known user IDs.
fn generate_user_id(&mut self, rng: &mut impl CryptoRngCore) -> Result<UserId, Error> {
if let Some(last_tracer) = self.tracers.back() {
if let Some((last_tracer, _)) = self.tracers.back() {
// Generate all but the last marker at random.
let mut markers: LinkedList<Scalar> = self
.tracers
Expand All @@ -260,7 +264,7 @@ impl TracingSecretKey {
.tracers
.iter()
.zip(markers.iter())
.map(|(sk_i, a_i)| sk_i * a_i)
.map(|((sk_i, _), a_i)| sk_i * a_i)
.fold(Scalar::zero(), |acc, x_i| &acc + &x_i))
/ last_tracer;

Expand All @@ -279,7 +283,7 @@ impl TracingSecretKey {
== id
.iter()
.zip(self.tracers.iter())
.map(|(identifier, tracer)| identifier * tracer)
.map(|(identifier, (tracer, _))| identifier * tracer)
.sum()
}

Expand Down Expand Up @@ -488,7 +492,6 @@ impl XEnc {
self.c.len() - 1
}

#[cfg(any(test, feature = "test-utils"))]
pub fn count(&self) -> usize {
match &self.encapsulations {
Encapsulations::HEncs(vec) => vec.len(),
Expand Down
156 changes: 103 additions & 53 deletions src/core/primitives.rs
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ pub fn usk_keygen(

Ok(UserSecretKey {
id,
ps: msk.tsk.tracers.iter().map(EcPoint::from).collect(),
ps: msk.tsk.tracers.iter().map(|(_, gi)| gi).cloned().collect(),
secrets: coordinate_keys,
signature,
})
Expand Down Expand Up @@ -432,58 +432,108 @@ pub fn decaps(
}
}

// /// Recover the encapsulated shared secret and set of rights used in the
// /// encapsulation.
// pub fn full_decaps(
// msk: &MasterSecretKey,
// encapsulation: &XEnc,
// ) -> Result<(Secret<SHARED_SECRET_LENGTH>, HashSet<Right>), Error> {
// let A = {
// let c_0 = encapsulation
// .c
// .first()
// .ok_or_else(|| Error::Kem("invalid encapsulation: C is empty".to_string()))?;
// let t_0 = msk
// .tsk
// .tracers
// .front()
// .ok_or_else(|| Error::KeyError("MSK has no tracer".to_string()))?;

// c_0 * &(&msk.tsk.s / t_0)
// };

// let T = {
// let mut hasher = Shake::v256();
// for c in encapsulation.c.iter() {
// hasher.update(&c.to_bytes());
// }
// for enc in encapsulation.encapsulations.iter() {
// if let Encapsulation::Hybridized { E, F: _ } = enc {
// hasher.update(&E.serialize()?)
// }
// }
// let mut T = Secret::<SHARED_SECRET_LENGTH>::new();
// hasher.finalize(&mut *T);
// T
// };

// let mut rights = HashSet::with_capacity(encapsulation.encapsulations.len());
// let ss = Secret::new();
// for enc in &encapsulation.encapsulations {
// for (right, secrets) in msk.secrets.iter() {
// for (_, secret) in secrets {
// if let Some(S) = try_decaps(secret, enc, &A, &T)? {
// let (tag, ss) = j_hash(&S, &encapsulation.c, &encapsulation.encapsulations)?;
// if tag == encapsulation.tag {
// drop(ss);
// rights.insert(right.clone());
// }
// }
// }
// }
// }
// Ok((ss, rights))
// }
/// Recover the encapsulated shared secret and set of rights used in the
/// encapsulation.
pub fn full_decaps(
msk: &MasterSecretKey,
encapsulation: &XEnc,
) -> Result<(Secret<SHARED_SECRET_LENGTH>, HashSet<Right>), Error> {
let A = {
let c_0 = encapsulation
.c
.first()
.ok_or_else(|| Error::Kem("invalid encapsulation: C is empty".to_string()))?;
let t_0 = msk
.tsk
.tracers
.front()
.map(|(si, _)| si)
.ok_or_else(|| Error::KeyError("MSK has no tracer".to_string()))?;

c_0 * &(&msk.tsk.s / t_0)
};

let T = {
let mut hasher = Shake::v256();
encapsulation
.c
.iter()
.for_each(|c| hasher.update(&c.to_bytes()));

if let Encapsulations::HEncs(encs) = &encapsulation.encapsulations {
encs.iter().try_for_each(|(E, _)| {
hasher.update(&E.serialize()?);
Ok::<_, Error>(())
})?;
}
hasher
};

let J = {
let mut hasher = T.clone();
match &encapsulation.encapsulations {
Encapsulations::HEncs(encs) => encs.iter().for_each(|(_, F)| hasher.update(F)),
Encapsulations::CEncs(encs) => encs.iter().for_each(|F| hasher.update(F)),
}
hasher
};

let mut enc_ss = None;
let mut rights = HashSet::with_capacity(encapsulation.count());
let mut try_decaps =
|right: &Right, K1: &mut EcPoint, K2: Option<Secret<SHARED_SECRET_LENGTH>>, F| {
let S_ij = xor_in_place(H_hash(T.clone(), K1, K2.as_ref()), F);
let (tag_ij, ss) = J_hash(J.clone(), &S_ij);
if encapsulation.tag == tag_ij {
// Fujisaki-Okamoto
let r = G_hash(&S_ij)?;
let c_ij = msk.tsk.set_traps(&r);
if encapsulation.c == c_ij {
K1.zeroize();
enc_ss = Some(ss);
rights.insert(right.clone());
}
}
Ok::<_, Error>(())
};

match &encapsulation.encapsulations {
Encapsulations::HEncs(encs) => {
for (E, F) in encs {
for (right, secret_set) in msk.secrets.iter() {
for (is_activated, secret) in secret_set {
if *is_activated {
if let RightSecretKey::Hybridized { sk, dk } = secret {
let mut K1 = R25519::session_key(sk, &A)?;
let K2 = MlKem512::dec(dk, E)?;
try_decaps(right, &mut K1, Some(K2), F)?;
}
}
}
}
}
}
Encapsulations::CEncs(encs) => {
for F in encs {
for (right, secret_set) in msk.secrets.iter() {
for (is_activated, secret) in secret_set {
if *is_activated {
let sk = match secret {
RightSecretKey::Hybridized { sk, .. } => sk,
RightSecretKey::Classic { sk } => sk,
};
let mut K1 = R25519::session_key(sk, &A)?;
try_decaps(right, &mut K1, None, F)?;
}
}
}
}
}
}
enc_ss
.map(|ss| (ss, rights))
.ok_or_else(|| Error::Kem("could not open the encapsulation".to_string()))
}

/// Updates the MSK such that it has at least one secret per right given, and no
/// secret for rights that are not given. Updates hybridization of the remaining
Expand Down
12 changes: 9 additions & 3 deletions src/core/serialization/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -138,15 +138,20 @@ impl Serializable for TracingSecretKey {
+ to_leb128_len(self.users.len())
+ self.users.iter().map(Serializable::length).sum::<usize>()
+ to_leb128_len(self.tracers.len())
+ self.tracers.iter().map(|sk| sk.length()).sum::<usize>()
+ self
.tracers
.iter()
.map(|(sk, pk)| sk.length() + pk.length())
.sum::<usize>()
}

fn write(&self, ser: &mut Serializer) -> Result<usize, Self::Error> {
let mut n = self.s.write(ser)?;

n += ser.write_leb128_u64(self.tracers.len() as u64)?;
for sk in &self.tracers {
for (sk, pk) in &self.tracers {
n += ser.write(sk)?;
n += ser.write(pk)?;
}

n = ser.write_leb128_u64(self.users.len() as u64)?;
Expand All @@ -164,7 +169,8 @@ impl Serializable for TracingSecretKey {
let mut tracers = LinkedList::new();
for _ in 0..n_tracers {
let sk = de.read()?;
tracers.push_back(sk);
let pk = de.read()?;
tracers.push_back((sk, pk));
}

let n_users = <usize>::try_from(de.read_leb128_u64()?)?;
Expand Down
10 changes: 5 additions & 5 deletions src/core/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -264,11 +264,11 @@ fn test_reencrypt_with_msk() {
assert_eq!(Some(&old_key), decaps(&usk, &old_enc).unwrap().as_ref());

cc.rekey(&mut msk, &ap).unwrap();
// let new_mpk = msk.mpk().unwrap();
// let (new_key, new_enc) = cc.recaps(&msk, &new_mpk, &old_enc).unwrap();
// cc.refresh_usk(&mut msk, &mut usk, true).unwrap();
// assert_eq!(Some(new_key), decaps(&usk, &new_enc).unwrap());
// assert_ne!(Some(old_key), decaps(&usk, &new_enc).unwrap());
let new_mpk = msk.mpk().unwrap();
let (new_key, new_enc) = cc.recaps(&msk, &new_mpk, &old_enc).unwrap();
cc.refresh_usk(&mut msk, &mut usk, true).unwrap();
assert_eq!(Some(new_key), decaps(&usk, &new_enc).unwrap());
assert_ne!(Some(old_key), decaps(&usk, &new_enc).unwrap());
}

#[test]
Expand Down

0 comments on commit f44a970

Please sign in to comment.