use std::ffi::c_void;
use std::marker::PhantomData;
use std::ptr::null_mut;
use std::sync::atomic::AtomicPtr;
use std::sync::atomic::Ordering;
use crate::bindgen;
use crate::component_marker;
use crate::error::*;
use crate::poly_array::PolynomialArray;
use crate::try_seal;
use crate::{
Asym, AsymmetricComponents, Ciphertext, Context, Plaintext, PublicKey, SecretKey, Sym, SymAsym,
SymmetricComponents,
};
pub struct Encryptor<T = ()> {
handle: AtomicPtr<c_void>,
_marker: PhantomData<T>,
}
pub type SymmetricEncryptor = Encryptor<Sym>;
pub type AsymmetricEncryptor = Encryptor<Asym>;
pub type SymAsymEncryptor = Encryptor<SymAsym>;
impl<T> Encryptor<T> {
pub(crate) unsafe fn get_handle(&self) -> *mut c_void {
self.handle.load(Ordering::SeqCst)
}
}
impl Encryptor {
pub fn with_public_and_secret_key(
ctx: &Context,
public_key: &PublicKey,
secret_key: &SecretKey,
) -> Result<Encryptor<SymAsym>> {
let mut handle: *mut c_void = null_mut();
try_seal!(unsafe {
bindgen::Encryptor_Create(
ctx.get_handle(),
public_key.get_handle(),
secret_key.get_handle(),
&mut handle,
)
})?;
Ok(Encryptor {
handle: AtomicPtr::new(handle),
_marker: PhantomData,
})
}
pub fn with_public_key(
ctx: &Context,
public_key: &PublicKey,
) -> Result<AsymmetricEncryptor> {
let mut handle: *mut c_void = null_mut();
try_seal!(unsafe {
bindgen::Encryptor_Create(
ctx.get_handle(),
public_key.get_handle(),
null_mut(),
&mut handle,
)
})?;
Ok(Encryptor {
handle: AtomicPtr::new(handle),
_marker: PhantomData,
})
}
pub fn with_secret_key(
ctx: &Context,
secret_key: &SecretKey,
) -> Result<SymmetricEncryptor> {
let mut handle: *mut c_void = null_mut();
try_seal!(unsafe {
bindgen::Encryptor_Create(
ctx.get_handle(),
null_mut(),
secret_key.get_handle(),
&mut handle,
)
})?;
Ok(Encryptor {
handle: AtomicPtr::new(handle),
_marker: PhantomData,
})
}
}
impl AsymmetricEncryptor {
pub fn new(
ctx: &Context,
public_key: &PublicKey,
) -> Result<Self> {
Encryptor::with_public_key(ctx, public_key)
}
}
impl SymmetricEncryptor {
pub fn new(
ctx: &Context,
secret_key: &SecretKey,
) -> Result<Self> {
Encryptor::with_secret_key(ctx, secret_key)
}
}
impl SymAsymEncryptor {
pub fn new(
ctx: &Context,
public_key: &PublicKey,
secret_key: &SecretKey,
) -> Result<Self> {
Encryptor::with_public_and_secret_key(ctx, public_key, secret_key)
}
}
impl<T: component_marker::Asym> Encryptor<T> {
pub fn encrypt(
&self,
plaintext: &Plaintext,
) -> Result<Ciphertext> {
let ciphertext = Ciphertext::new()?;
try_seal!(unsafe {
bindgen::Encryptor_Encrypt(
self.get_handle(),
plaintext.get_handle(),
ciphertext.get_handle(),
null_mut(),
)
})?;
Ok(ciphertext)
}
pub fn encrypt_return_components(
&self,
plaintext: &Plaintext,
) -> Result<(Ciphertext, AsymmetricComponents)> {
let ciphertext = Ciphertext::new()?;
let u_destination = PolynomialArray::new()?;
let e_destination = PolynomialArray::new()?;
let r_destination = Plaintext::new()?;
try_seal!(unsafe {
bindgen::Encryptor_EncryptReturnComponents(
self.get_handle(),
plaintext.get_handle(),
true,
ciphertext.get_handle(),
u_destination.get_handle(),
e_destination.get_handle(),
r_destination.get_handle(),
null_mut(),
)
})?;
Ok((
ciphertext,
AsymmetricComponents::new(u_destination, e_destination, r_destination),
))
}
#[cfg(feature = "deterministic")]
pub fn encrypt_deterministic(
&self,
plaintext: &Plaintext,
seed: &[u64; 8],
) -> Result<Ciphertext> {
let ciphertext = Ciphertext::new()?;
let u_destination = PolynomialArray::new()?;
let e_destination = PolynomialArray::new()?;
let r_destination = Plaintext::new()?;
try_seal!(unsafe {
bindgen::Encryptor_EncryptReturnComponentsSetSeed(
self.get_handle(),
plaintext.get_handle(),
false,
ciphertext.get_handle(),
u_destination.get_handle(),
e_destination.get_handle(),
r_destination.get_handle(),
seed.as_ptr() as *mut c_void,
null_mut(),
)
})?;
Ok(ciphertext)
}
#[cfg(feature = "deterministic")]
pub fn encrypt_return_components_deterministic(
&self,
plaintext: &Plaintext,
seed: &[u64; 8],
) -> Result<(Ciphertext, AsymmetricComponents)> {
let ciphertext = Ciphertext::new()?;
let u_destination = PolynomialArray::new()?;
let e_destination = PolynomialArray::new()?;
let r_destination = Plaintext::new()?;
try_seal!(unsafe {
bindgen::Encryptor_EncryptReturnComponentsSetSeed(
self.get_handle(),
plaintext.get_handle(),
true,
ciphertext.get_handle(),
u_destination.get_handle(),
e_destination.get_handle(),
r_destination.get_handle(),
seed.as_ptr() as *mut c_void,
null_mut(),
)
})?;
Ok((
ciphertext,
AsymmetricComponents::new(u_destination, e_destination, r_destination),
))
}
}
impl<T: component_marker::Sym> Encryptor<T> {
pub fn encrypt_symmetric(
&self,
plaintext: &Plaintext,
) -> Result<Ciphertext> {
let ciphertext = Ciphertext::new()?;
try_seal!(unsafe {
bindgen::Encryptor_EncryptSymmetric(
self.get_handle(),
plaintext.get_handle(),
false,
ciphertext.get_handle(),
null_mut(),
)
})?;
Ok(ciphertext)
}
#[cfg(feature = "deterministic")]
pub fn encrypt_symmetric_deterministic(
&self,
plaintext: &Plaintext,
seed: &[u64; 8],
) -> Result<Ciphertext> {
let ciphertext = Ciphertext::new()?;
let e_destination = PolynomialArray::new()?;
let r_destination = Plaintext::new()?;
try_seal!(unsafe {
bindgen::Encryptor_EncryptSymmetricReturnComponentsSetSeed(
self.get_handle(),
plaintext.get_handle(),
ciphertext.get_handle(),
e_destination.get_handle(),
r_destination.get_handle(),
seed.as_ptr() as *mut c_void,
null_mut(),
)
})?;
Ok(ciphertext)
}
pub fn encrypt_symmetric_return_components(
&self,
plaintext: &Plaintext,
) -> Result<(Ciphertext, SymmetricComponents)> {
let ciphertext = Ciphertext::new()?;
let e_destination = PolynomialArray::new()?;
let r_destination = Plaintext::new()?;
try_seal!(unsafe {
bindgen::Encryptor_EncryptSymmetricReturnComponents(
self.get_handle(),
plaintext.get_handle(),
ciphertext.get_handle(),
e_destination.get_handle(),
r_destination.get_handle(),
null_mut(),
)
})?;
Ok((
ciphertext,
SymmetricComponents::new(e_destination, r_destination),
))
}
#[cfg(feature = "deterministic")]
pub fn encrypt_symmetric_return_components_deterministic(
&self,
plaintext: &Plaintext,
seed: &[u64; 8],
) -> Result<(Ciphertext, SymmetricComponents)> {
let ciphertext = Ciphertext::new()?;
let e_destination = PolynomialArray::new()?;
let r_destination = Plaintext::new()?;
try_seal!(unsafe {
bindgen::Encryptor_EncryptSymmetricReturnComponentsSetSeed(
self.get_handle(),
plaintext.get_handle(),
ciphertext.get_handle(),
e_destination.get_handle(),
r_destination.get_handle(),
seed.as_ptr() as *mut c_void,
null_mut(),
)
})?;
Ok((
ciphertext,
SymmetricComponents::new(e_destination, r_destination),
))
}
}
impl<T> Drop for Encryptor<T> {
fn drop(&mut self) {
try_seal!(unsafe { bindgen::Encryptor_Destroy(self.get_handle()) })
.expect("Internal error in Enryptor::drop");
}
}
#[cfg(test)]
mod tests {
use crate::*;
fn mk_ctx<F>(enc_modifier: F) -> Context
where
F: FnOnce(BFVEncryptionParametersBuilder) -> BFVEncryptionParametersBuilder,
{
let builder = BFVEncryptionParametersBuilder::new()
.set_poly_modulus_degree(DegreeType::D8192)
.set_coefficient_modulus(
CoefficientModulusFactory::build(DegreeType::D8192, &[50, 30, 30, 50, 50]).unwrap(),
)
.set_plain_modulus_u64(1234);
let params = enc_modifier(builder).build().unwrap();
Context::new(¶ms, false, SecurityLevel::TC128).unwrap()
}
#[test]
fn can_create_encryptor_from_public_key() {
let ctx = mk_ctx(|b| b);
let gen = KeyGenerator::new(&ctx).unwrap();
let public_key = gen.create_public_key();
let encryptor = Encryptor::with_public_key(&ctx, &public_key).unwrap();
std::mem::drop(encryptor);
}
#[test]
fn can_create_encryptor_from_secret_key() {
let ctx = mk_ctx(|b| b);
let gen = KeyGenerator::new(&ctx).unwrap();
let secret_key = gen.secret_key();
let encryptor = Encryptor::with_secret_key(&ctx, &secret_key).unwrap();
std::mem::drop(encryptor);
}
#[test]
fn can_create_encryptor_from_public_and_secret_key() {
let ctx = mk_ctx(|b| b);
let gen = KeyGenerator::new(&ctx).unwrap();
let public_key = gen.create_public_key();
let secret_key = gen.secret_key();
let encryptor =
Encryptor::with_public_and_secret_key(&ctx, &public_key, &secret_key).unwrap();
std::mem::drop(encryptor);
}
}