use crate::ibe::cgw::{CipherText, Msg, CGW, USK_BYTES as CPA_USK_BYTES};
use crate::ibe::IBE;
use crate::kem::{Error, SharedSecret, IBKEM};
use crate::util::*;
use crate::Compress;
use arrayref::{array_refs, mut_array_refs};
use group::Group;
use rand::{CryptoRng, Rng};
use subtle::{ConstantTimeEq, CtOption};
pub use crate::ibe::cgw::{PublicKey, SecretKey, CT_BYTES, MSG_BYTES, PK_BYTES, SK_BYTES};
pub const USK_BYTES: usize = CPA_USK_BYTES + ID_BYTES;
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct UserSecretKey {
usk: crate::ibe::cgw::UserSecretKey,
id: Identity,
}
impl Compress for UserSecretKey {
const OUTPUT_SIZE: usize = USK_BYTES;
type Output = [u8; Self::OUTPUT_SIZE];
fn to_bytes(&self) -> [u8; USK_BYTES] {
let mut buf = [0u8; USK_BYTES];
let (usk, id) = mut_array_refs![&mut buf, CPA_USK_BYTES, ID_BYTES];
*usk = self.usk.to_bytes();
id.copy_from_slice(&self.id.0);
buf
}
fn from_bytes(bytes: &[u8; USK_BYTES]) -> CtOption<Self> {
let (usk, rid) = array_refs![&bytes, CPA_USK_BYTES, ID_BYTES];
let usk = crate::ibe::cgw::UserSecretKey::from_bytes(usk);
let id = Identity(*rid);
usk.map(|usk| UserSecretKey { usk, id })
}
}
#[derive(Debug, Clone, Copy)]
pub struct CGWFO;
impl IBKEM for CGWFO {
const IDENTIFIER: &'static str = "cgwfo";
type Pk = PublicKey;
type Sk = SecretKey;
type Usk = UserSecretKey;
type Ct = CipherText;
type Id = Identity;
const PK_BYTES: usize = PK_BYTES;
const USK_BYTES: usize = USK_BYTES;
const SK_BYTES: usize = SK_BYTES;
const CT_BYTES: usize = CT_BYTES;
fn setup<R: Rng + CryptoRng>(rng: &mut R) -> (PublicKey, SecretKey) {
CGW::setup(rng)
}
fn extract_usk<R: Rng + CryptoRng>(
_pk: Option<&PublicKey>,
sk: &SecretKey,
id: &Identity,
rng: &mut R,
) -> UserSecretKey {
let usk = CGW::extract_usk(None, sk, id, rng);
UserSecretKey { usk, id: *id }
}
fn encaps<R: Rng + CryptoRng>(
pk: &PublicKey,
id: &Identity,
rng: &mut R,
) -> (CipherText, SharedSecret) {
let m = Msg::random(rng);
let mut pre_coins = [0u8; MSG_BYTES + ID_BYTES];
pre_coins[..MSG_BYTES].copy_from_slice(&m.to_bytes());
pre_coins[MSG_BYTES..].copy_from_slice(&id.0);
let coins = sha3_512(&pre_coins);
let ct = CGW::encrypt(pk, id, &m, &coins);
(ct, SharedSecret::from(&m))
}
fn decaps(
opk: Option<&PublicKey>,
usk: &UserSecretKey,
c: &CipherText,
) -> Result<SharedSecret, Error> {
let pk = opk.unwrap();
let m = CGW::decrypt(&usk.usk, c);
let mut pre_coins = [0u8; MSG_BYTES + ID_BYTES];
pre_coins[..MSG_BYTES].copy_from_slice(&m.to_bytes());
pre_coins[MSG_BYTES..].copy_from_slice(&usk.id.0);
let coins = sha3_512(&pre_coins);
let c2 = CGW::encrypt(pk, &usk.id, &m, &coins);
if c.ct_eq(&c2).into() {
Ok(SharedSecret::from(&m))
} else {
Err(Error)
}
}
}
#[cfg(feature = "mkem")]
impl crate::kem::mkem::MultiRecipient for CGWFO {}
#[cfg(test)]
mod tests {
use super::*;
use crate::Derive;
test_kem!(CGWFO);
#[cfg(feature = "mkem")]
test_multi_kem!(CGWFO);
}