use std::ffi::c_void;
use std::ptr::null_mut;
use crate::bindgen;
use crate::data_structures::PolynomialArray;
use crate::error::*;
use crate::{Ciphertext, Context, Plaintext, PublicKey, SecretKey};
pub struct Encryptor {
handle: *mut c_void,
}
unsafe impl Sync for Encryptor {}
unsafe impl Send for Encryptor {}
impl Encryptor {
pub fn with_public_and_secret_key(
ctx: &Context,
public_key: &PublicKey,
secret_key: &SecretKey,
) -> Result<Encryptor> {
let mut handle: *mut c_void = null_mut();
convert_seal_error(unsafe {
bindgen::Encryptor_Create(
ctx.get_handle(),
public_key.get_handle(),
secret_key.get_handle(),
&mut handle,
)
})?;
Ok(Encryptor { handle })
}
pub fn with_public_key(ctx: &Context, public_key: &PublicKey) -> Result<Encryptor> {
let mut handle: *mut c_void = null_mut();
convert_seal_error(unsafe {
bindgen::Encryptor_Create(
ctx.get_handle(),
public_key.get_handle(),
null_mut(),
&mut handle,
)
})?;
Ok(Encryptor { handle })
}
pub fn encrypt(&self, plaintext: &Plaintext) -> Result<Ciphertext> {
let ciphertext = Ciphertext::new()?;
convert_seal_error(unsafe {
bindgen::Encryptor_Encrypt(
self.handle,
plaintext.get_handle(),
ciphertext.get_handle(),
null_mut(),
)
})?;
Ok(ciphertext)
}
pub fn encrypt_return_components(
&self,
plaintext: &Plaintext,
) -> Result<(Ciphertext, PolynomialArray, PolynomialArray, Plaintext)> {
let ciphertext = Ciphertext::new()?;
let u_destination = PolynomialArray::new()?;
let e_destination = PolynomialArray::new()?;
let fix_destination = Plaintext::new()?;
convert_seal_error(unsafe {
bindgen::Encryptor_EncryptReturnComponents(
self.handle,
plaintext.get_handle(),
true,
ciphertext.get_handle(),
u_destination.get_handle(),
e_destination.get_handle(),
fix_destination.get_handle(),
null_mut(),
)
})?;
Ok((ciphertext, u_destination, e_destination, fix_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 fix_destination = Plaintext::new()?;
convert_seal_error(unsafe {
bindgen::Encryptor_EncryptReturnComponentsSetSeed(
self.handle,
plaintext.get_handle(),
false,
ciphertext.get_handle(),
u_destination.get_handle(),
e_destination.get_handle(),
fix_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, PolynomialArray, PolynomialArray, Plaintext)> {
let ciphertext = Ciphertext::new()?;
let u_destination = PolynomialArray::new()?;
let e_destination = PolynomialArray::new()?;
let fix_destination = Plaintext::new()?;
convert_seal_error(unsafe {
bindgen::Encryptor_EncryptReturnComponentsSetSeed(
self.handle,
plaintext.get_handle(),
true,
ciphertext.get_handle(),
u_destination.get_handle(),
e_destination.get_handle(),
fix_destination.get_handle(),
seed.as_ptr() as *mut c_void,
null_mut(),
)
})?;
Ok((ciphertext, u_destination, e_destination, fix_destination))
}
}
impl Drop for Encryptor {
fn drop(&mut self) {
convert_seal_error(unsafe { bindgen::Encryptor_Destroy(self.handle) })
.expect("Internal error in Enryptor::drop");
}
}
pub struct Decryptor {
handle: *mut c_void,
}
unsafe impl Sync for Decryptor {}
unsafe impl Send for Decryptor {}
impl Decryptor {
pub fn new(ctx: &Context, secret_key: &SecretKey) -> Result<Self> {
let mut handle = null_mut();
convert_seal_error(unsafe {
bindgen::Decryptor_Create(ctx.get_handle(), secret_key.get_handle(), &mut handle)
})?;
Ok(Self { handle })
}
pub fn decrypt(&self, ciphertext: &Ciphertext) -> Result<Plaintext> {
let plaintext = Plaintext::new()?;
convert_seal_error(unsafe {
bindgen::Decryptor_Decrypt(self.handle, ciphertext.get_handle(), plaintext.get_handle())
})?;
Ok(plaintext)
}
pub fn invariant_noise_budget(&self, ciphertext: &Ciphertext) -> Result<u32> {
let mut noise: i32 = 0;
convert_seal_error(unsafe {
bindgen::Decryptor_InvariantNoiseBudget(
self.handle,
ciphertext.get_handle(),
&mut noise,
)
})?;
Ok(noise as u32)
}
pub fn invariant_noise(&self, ciphertext: &Ciphertext) -> Result<f64> {
let mut noise: f64 = 0f64;
convert_seal_error(unsafe {
bindgen::Decryptor_InvariantNoise(self.handle, ciphertext.get_handle(), &mut noise)
})?;
Ok(noise)
}
}
impl Drop for Decryptor {
fn drop(&mut self) {
convert_seal_error(unsafe { bindgen::Decryptor_Destroy(self.handle) })
.expect("Internal error Decryptor::drop().");
}
}
#[cfg(test)]
mod tests {
use crate::*;
#[test]
fn can_create_encryptor_from_public_key() {
let params = BfvEncryptionParametersBuilder::new()
.set_poly_modulus_degree(8192)
.set_coefficient_modulus(
CoefficientModulus::create(8192, &[50, 30, 30, 50, 50]).unwrap(),
)
.set_plain_modulus_u64(1234)
.build()
.unwrap();
let ctx = Context::new(¶ms, false, SecurityLevel::TC128).unwrap();
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_public_and_secret_key() {
let params = BfvEncryptionParametersBuilder::new()
.set_poly_modulus_degree(8192)
.set_coefficient_modulus(
CoefficientModulus::create(8192, &[50, 30, 30, 50, 50]).unwrap(),
)
.set_plain_modulus_u64(1234)
.build()
.unwrap();
let ctx = Context::new(¶ms, false, SecurityLevel::TC128).unwrap();
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);
}
#[test]
fn can_create_and_destroy_decryptor() {
let params = BfvEncryptionParametersBuilder::new()
.set_poly_modulus_degree(8192)
.set_coefficient_modulus(
CoefficientModulus::create(8192, &[50, 30, 30, 50, 50]).unwrap(),
)
.set_plain_modulus_u64(1234)
.build()
.unwrap();
let ctx = Context::new(¶ms, false, SecurityLevel::TC128).unwrap();
let gen = KeyGenerator::new(&ctx).unwrap();
let secret_key = gen.secret_key();
let decryptor = Decryptor::new(&ctx, &secret_key);
std::mem::drop(decryptor);
}
#[test]
fn can_encrypt_and_decrypt_unsigned() {
let params = BfvEncryptionParametersBuilder::new()
.set_poly_modulus_degree(8192)
.set_coefficient_modulus(
CoefficientModulus::create(8192, &[50, 30, 30, 50, 50]).unwrap(),
)
.set_plain_modulus(PlainModulus::batching(8192, 20).unwrap())
.build()
.unwrap();
let ctx = Context::new(¶ms, false, SecurityLevel::TC128).unwrap();
let gen = KeyGenerator::new(&ctx).unwrap();
let encoder = BFVEncoder::new(&ctx).unwrap();
let mut data = vec![];
for i in 0..encoder.get_slot_count() {
data.push(i as u64)
}
let plaintext = encoder.encode_unsigned(&data).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();
let decryptor = Decryptor::new(&ctx, &secret_key).unwrap();
let ciphertext = encryptor.encrypt(&plaintext).unwrap();
let decrypted = decryptor.decrypt(&ciphertext).unwrap();
let data_2 = encoder.decode_unsigned(&decrypted).unwrap();
assert_eq!(data, data_2);
}
#[test]
fn can_encrypt_and_decrypt_signed() {
let params = BfvEncryptionParametersBuilder::new()
.set_poly_modulus_degree(8192)
.set_coefficient_modulus(
CoefficientModulus::create(8192, &[50, 30, 30, 50, 50]).unwrap(),
)
.set_plain_modulus(PlainModulus::batching(8192, 20).unwrap())
.build()
.unwrap();
let ctx = Context::new(¶ms, false, SecurityLevel::TC128).unwrap();
let gen = KeyGenerator::new(&ctx).unwrap();
let encoder = BFVEncoder::new(&ctx).unwrap();
let mut data = vec![];
for i in 0..encoder.get_slot_count() {
data.push(encoder.get_slot_count() as i64 / 2i64 - i as i64)
}
let plaintext = encoder.encode_signed(&data).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();
let decryptor = Decryptor::new(&ctx, &secret_key).unwrap();
let ciphertext = encryptor.encrypt(&plaintext).unwrap();
let decrypted = decryptor.decrypt(&ciphertext).unwrap();
let data_2 = encoder.decode_signed(&decrypted).unwrap();
assert_eq!(data, data_2);
}
#[test]
fn can_encrypt_and_decrypt_from_return_components() {
let params = BfvEncryptionParametersBuilder::new()
.set_poly_modulus_degree(8192)
.set_coefficient_modulus(
CoefficientModulus::create(8192, &[50, 30, 30, 50, 50]).unwrap(),
)
.set_plain_modulus(PlainModulus::batching(8192, 20).unwrap())
.build()
.unwrap();
let ctx = Context::new(¶ms, false, SecurityLevel::TC128).unwrap();
let gen = KeyGenerator::new(&ctx).unwrap();
let encoder = BFVEncoder::new(&ctx).unwrap();
let mut data = vec![];
for i in 0..encoder.get_slot_count() {
data.push(i as u64);
}
let plaintext = encoder.encode_unsigned(&data).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();
let decryptor = Decryptor::new(&ctx, &secret_key).unwrap();
let ciphertext = encryptor.encrypt_return_components(&plaintext).unwrap().0;
let decrypted = decryptor.decrypt(&ciphertext).unwrap();
let data_2 = encoder.decode_unsigned(&decrypted).unwrap();
assert_eq!(data, data_2);
}
#[cfg(feature = "deterministic")]
mod deterministic {
use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};
use crate::*;
#[test]
fn encrypt_deterministic() {
let params = BfvEncryptionParametersBuilder::new()
.set_poly_modulus_degree(8192)
.set_coefficient_modulus(
CoefficientModulus::create(8192, &[50, 30, 30, 50, 50]).unwrap(),
)
.set_plain_modulus(PlainModulus::batching(8192, 20).unwrap())
.build()
.unwrap();
let ctx = Context::new(¶ms, false, SecurityLevel::TC128).unwrap();
let encoder = BFVEncoder::new(&ctx).unwrap();
let mut data = vec![];
for i in 0..encoder.get_slot_count() {
data.push(i as u64);
}
let plaintext = encoder.encode_unsigned(&data).unwrap();
let public_key_bytes = include_bytes!("../tests/data/public_key.bin");
let secret_key_bytes = include_bytes!("../tests/data/secret_key.bin");
let public_key = PublicKey::from_bytes(&ctx, public_key_bytes).unwrap();
let secret_key = SecretKey::from_bytes(&ctx, secret_key_bytes).unwrap();
let encryptor =
Encryptor::with_public_and_secret_key(&ctx, &public_key, &secret_key).unwrap();
let decryptor = Decryptor::new(&ctx, &secret_key).unwrap();
let ciphertext = encryptor
.encrypt_deterministic(&plaintext, &[0, 0, 0, 0, 0, 0, 0, 0])
.unwrap();
let decrypted = decryptor.decrypt(&ciphertext).unwrap();
let data_2 = encoder.decode_unsigned(&decrypted).unwrap();
assert_eq!(data, data_2);
let cipher_bytes = ciphertext.as_bytes().unwrap();
let mut s = DefaultHasher::new();
cipher_bytes.hash(&mut s);
let hash = s.finish();
assert_eq!(
hash,
if cfg!(target_os = "macos") {
14319785560025809101
} else {
9942548233613012008
}
);
}
}
#[cfg(feature = "deterministic")]
pub use deterministic::*;
}