use core::fmt;
use rand_core::{CryptoRng, RngCore};
#[cfg(feature = "default-rng")]
use rand_core::OsRng;
use crate::capsule::{Capsule, OpenReencryptedError};
use crate::capsule_frag::VerifiedCapsuleFrag;
use crate::dem::{DecryptionError, EncryptionError, DEM};
use crate::key_frag::{KeyFragBase, VerifiedKeyFrag};
use crate::keys::{PublicKey, SecretKey, Signer};
use alloc::boxed::Box;
use alloc::vec::Vec;
#[derive(Debug, PartialEq, Eq)]
pub enum ReencryptionError {
OnOpen(OpenReencryptedError),
OnDecryption(DecryptionError),
}
impl fmt::Display for ReencryptionError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::OnOpen(err) => write!(f, "Re-encryption error on open: {err}"),
Self::OnDecryption(err) => write!(f, "Re-encryption error on decryption: {err}"),
}
}
}
pub fn encrypt_with_rng(
rng: &mut (impl CryptoRng + RngCore),
delegating_pk: &PublicKey,
plaintext: &[u8],
) -> Result<(Capsule, Box<[u8]>), EncryptionError> {
let (capsule, key_seed) = Capsule::from_public_key(rng, delegating_pk);
let dem = DEM::new(key_seed.as_secret());
dem.encrypt(rng, plaintext, &capsule.to_bytes_simple())
.map(|ciphertext| (capsule, ciphertext))
}
#[cfg(feature = "default-rng")]
pub fn encrypt(
delegating_pk: &PublicKey,
plaintext: &[u8],
) -> Result<(Capsule, Box<[u8]>), EncryptionError> {
encrypt_with_rng(&mut OsRng, delegating_pk, plaintext)
}
pub fn decrypt_original(
delegating_sk: &SecretKey,
capsule: &Capsule,
ciphertext: impl AsRef<[u8]>,
) -> Result<Box<[u8]>, DecryptionError> {
let key_seed = capsule.open_original(delegating_sk);
let dem = DEM::new(key_seed.as_secret());
dem.decrypt(ciphertext, &capsule.to_bytes_simple())
}
#[allow(clippy::too_many_arguments)]
pub fn generate_kfrags_with_rng(
rng: &mut (impl CryptoRng + RngCore),
delegating_sk: &SecretKey,
receiving_pk: &PublicKey,
signer: &Signer,
threshold: usize,
shares: usize,
sign_delegating_key: bool,
sign_receiving_key: bool,
) -> Box<[VerifiedKeyFrag]> {
let base = KeyFragBase::new(rng, delegating_sk, receiving_pk, signer, threshold);
let mut result = Vec::<VerifiedKeyFrag>::new();
for _ in 0..shares {
result.push(VerifiedKeyFrag::from_base(
rng,
&base,
sign_delegating_key,
sign_receiving_key,
));
}
result.into_boxed_slice()
}
#[cfg(feature = "default-rng")]
#[allow(clippy::too_many_arguments)]
pub fn generate_kfrags(
delegating_sk: &SecretKey,
receiving_pk: &PublicKey,
signer: &Signer,
threshold: usize,
shares: usize,
sign_delegating_key: bool,
sign_receiving_key: bool,
) -> Box<[VerifiedKeyFrag]> {
generate_kfrags_with_rng(
&mut OsRng,
delegating_sk,
receiving_pk,
signer,
threshold,
shares,
sign_delegating_key,
sign_receiving_key,
)
}
pub fn reencrypt_with_rng(
rng: &mut (impl CryptoRng + RngCore),
capsule: &Capsule,
verified_kfrag: VerifiedKeyFrag,
) -> VerifiedCapsuleFrag {
VerifiedCapsuleFrag::reencrypted(rng, capsule, verified_kfrag.unverify())
}
#[cfg(feature = "default-rng")]
pub fn reencrypt(capsule: &Capsule, verified_kfrag: VerifiedKeyFrag) -> VerifiedCapsuleFrag {
reencrypt_with_rng(&mut OsRng, capsule, verified_kfrag)
}
pub fn decrypt_reencrypted(
receiving_sk: &SecretKey,
delegating_pk: &PublicKey,
capsule: &Capsule,
verified_cfrags: impl IntoIterator<Item = VerifiedCapsuleFrag>,
ciphertext: impl AsRef<[u8]>,
) -> Result<Box<[u8]>, ReencryptionError> {
let cfrags: Vec<_> = verified_cfrags
.into_iter()
.map(|vcfrag| vcfrag.unverify())
.collect();
let key_seed = capsule
.open_reencrypted(receiving_sk, delegating_pk, &cfrags)
.map_err(ReencryptionError::OnOpen)?;
let dem = DEM::new(key_seed.as_secret());
dem.decrypt(&ciphertext, &capsule.to_bytes_simple())
.map_err(ReencryptionError::OnDecryption)
}
#[cfg(test)]
mod tests {
use alloc::vec::Vec;
use crate::{SecretKey, Signer, VerifiedCapsuleFrag};
use super::{decrypt_original, decrypt_reencrypted, encrypt, generate_kfrags, reencrypt};
#[test]
fn test_simple_api() {
let threshold: usize = 2;
let num_frags: usize = threshold + 1;
let delegating_sk = SecretKey::random();
let delegating_pk = delegating_sk.public_key();
let signer = Signer::new(SecretKey::random());
let verifying_pk = signer.verifying_key();
let receiving_sk = SecretKey::random();
let receiving_pk = receiving_sk.public_key();
let plaintext = b"peace at dawn";
let (capsule, ciphertext) = encrypt(&delegating_pk, plaintext).unwrap();
let plaintext_alice = decrypt_original(&delegating_sk, &capsule, &ciphertext).unwrap();
assert_eq!(&plaintext_alice as &[u8], plaintext);
let verified_kfrags = generate_kfrags(
&delegating_sk,
&receiving_pk,
&signer,
threshold,
num_frags,
true,
true,
);
let kfrags = verified_kfrags
.iter()
.cloned()
.map(|vkfrag| vkfrag.unverify());
let verified_kfrags: Vec<_> = kfrags
.into_iter()
.map(|kfrag| {
kfrag
.verify(&verifying_pk, Some(&delegating_pk), Some(&receiving_pk))
.unwrap()
})
.collect();
let verified_cfrags: Vec<VerifiedCapsuleFrag> = verified_kfrags[0..threshold]
.iter()
.map(|vkfrag| reencrypt(&capsule, vkfrag.clone()))
.collect();
let cfrags = verified_cfrags
.iter()
.cloned()
.map(|vcfrag| vcfrag.unverify());
let verified_cfrags: Vec<_> = cfrags
.into_iter()
.map(|cfrag| {
cfrag
.verify(&capsule, &verifying_pk, &delegating_pk, &receiving_pk)
.unwrap()
})
.collect();
let plaintext_bob = decrypt_reencrypted(
&receiving_sk,
&delegating_pk,
&capsule,
verified_cfrags,
&ciphertext,
)
.unwrap();
assert_eq!(&plaintext_bob as &[u8], plaintext);
}
}