use std::ffi::c_void;
use std::ptr::null_mut;
use std::sync::atomic::AtomicPtr;
use std::sync::atomic::Ordering;
use crate::bindgen;
use crate::error::*;
use crate::serialization::CompressionType;
use crate::try_seal;
use crate::{Context, FromBytes, ToBytes};
use serde::ser::Error;
use serde::{Serialize, Serializer};
#[derive(Debug)]
pub struct KeyGenerator {
handle: AtomicPtr<c_void>,
}
impl KeyGenerator {
pub fn new(ctx: &Context) -> Result<Self> {
let mut handle = null_mut();
try_seal!(unsafe { bindgen::KeyGenerator_Create1(ctx.get_handle(), &mut handle) })?;
Ok(KeyGenerator {
handle: AtomicPtr::new(handle),
})
}
pub fn new_from_secret_key(
ctx: &Context,
secret_key: &SecretKey,
) -> Result<Self> {
let mut handle = null_mut();
try_seal!(unsafe {
bindgen::KeyGenerator_Create2(ctx.get_handle(), secret_key.handle, &mut handle)
})?;
Ok(KeyGenerator {
handle: AtomicPtr::new(handle),
})
}
pub fn secret_key(&self) -> SecretKey {
let mut handle = null_mut();
try_seal!(unsafe { bindgen::KeyGenerator_SecretKey(self.get_handle(), &mut handle) })
.expect("Fatal error in KeyGenerator::secret_key");
SecretKey {
handle,
}
}
pub(crate) unsafe fn get_handle(&self) -> *mut c_void {
self.handle.load(Ordering::SeqCst)
}
pub fn create_public_key(&self) -> PublicKey {
self.create_public_key_internal(false)
}
pub fn create_compact_public_key(&self) -> CompactPublicKey {
CompactPublicKey(self.create_public_key_internal(true))
}
fn create_public_key_internal(
&self,
save_seed: bool,
) -> PublicKey {
let mut handle = null_mut();
try_seal!(unsafe {
bindgen::KeyGenerator_CreatePublicKey(self.get_handle(), save_seed, &mut handle)
})
.expect("Fatal error in KeyGenerator::public_key");
PublicKey {
handle,
}
}
pub fn create_relinearization_keys(&self) -> Result<RelinearizationKey> {
self.create_relinearization_keys_internal(false)
}
pub fn create_compact_relinearization_keys(&self) -> Result<CompactRelinearizationKey> {
Ok(CompactRelinearizationKey(
self.create_relinearization_keys_internal(true)?,
))
}
fn create_relinearization_keys_internal(
&self,
save_seed: bool,
) -> Result<RelinearizationKey> {
let mut handle = null_mut();
try_seal!(unsafe {
bindgen::KeyGenerator_CreateRelinKeys(self.get_handle(), save_seed, &mut handle)
})?;
Ok(RelinearizationKey {
handle,
})
}
pub fn create_compact_galois_keys(&self) -> Result<CompactGaloisKeys> {
Ok(CompactGaloisKeys(self.create_galois_keys_internal(true)?))
}
pub fn create_galois_keys(&self) -> Result<GaloisKey> {
self.create_galois_keys_internal(false)
}
fn create_galois_keys_internal(
&self,
save_seed: bool,
) -> Result<GaloisKey> {
let mut handle = null_mut();
try_seal!(unsafe {
bindgen::KeyGenerator_CreateGaloisKeysAll(self.get_handle(), save_seed, &mut handle)
})?;
Ok(GaloisKey {
handle,
})
}
}
impl Drop for KeyGenerator {
fn drop(&mut self) {
try_seal!(unsafe { bindgen::KeyGenerator_Destroy(self.get_handle()) })
.expect("Fatal error in KeyGenerator::drop");
}
}
#[derive(Debug)]
pub struct PublicKey {
handle: *mut c_void,
}
unsafe impl Sync for PublicKey {}
unsafe impl Send for PublicKey {}
impl ToBytes for PublicKey {
fn as_bytes(&self) -> Result<Vec<u8>> {
let mut num_bytes: i64 = 0;
try_seal!(unsafe {
bindgen::PublicKey_SaveSize(self.handle, CompressionType::ZStd as u8, &mut num_bytes)
})?;
let mut data: Vec<u8> = Vec::with_capacity(num_bytes as usize);
let mut bytes_written: i64 = 0;
try_seal!(unsafe {
let data_ptr = data.as_mut_ptr();
bindgen::PublicKey_Save(
self.handle,
data_ptr,
num_bytes as u64,
CompressionType::ZStd as u8,
&mut bytes_written,
)
})?;
unsafe { data.set_len(bytes_written as usize) };
Ok(data)
}
}
impl PartialEq for PublicKey {
fn eq(
&self,
other: &Self,
) -> bool {
self.as_bytes() == other.as_bytes()
}
}
impl FromBytes for PublicKey {
type State = Context;
fn from_bytes(
context: &Context,
bytes: &[u8],
) -> Result<Self> {
let key = PublicKey::new()?;
let mut bytes_read = 0;
try_seal!(unsafe {
bindgen::PublicKey_Load(
key.handle,
context.get_handle(),
bytes.as_ptr() as *mut u8,
bytes.len() as u64,
&mut bytes_read,
)
})?;
Ok(key)
}
}
impl PublicKey {
pub fn new() -> Result<Self> {
let mut handle: *mut c_void = null_mut();
try_seal!(unsafe { bindgen::PublicKey_Create1(&mut handle) })?;
Ok(Self {
handle,
})
}
pub fn get_handle(&self) -> *mut c_void {
self.handle
}
}
impl Drop for PublicKey {
fn drop(&mut self) {
try_seal!(unsafe { bindgen::PublicKey_Destroy(self.handle) })
.expect("Fatal error in PublicKey::drop")
}
}
impl Clone for PublicKey {
fn clone(&self) -> Self {
let mut handle: *mut c_void = null_mut();
try_seal!(unsafe { bindgen::PublicKey_Create2(self.handle, &mut handle) })
.expect("Fatal error in PublicKey::clone");
Self {
handle,
}
}
}
impl AsRef<PublicKey> for PublicKey {
fn as_ref(&self) -> &PublicKey {
self
}
}
pub struct CompactPublicKey(PublicKey);
impl CompactPublicKey {
pub fn as_bytes(&self) -> Result<Vec<u8>> {
self.0.as_bytes()
}
}
pub struct SecretKey {
handle: *mut c_void,
}
unsafe impl Sync for SecretKey {}
unsafe impl Send for SecretKey {}
impl SecretKey {
pub fn new() -> Result<Self> {
let mut handle: *mut c_void = null_mut();
try_seal!(unsafe { bindgen::SecretKey_Create1(&mut handle) })?;
Ok(Self {
handle,
})
}
pub fn get_handle(&self) -> *mut c_void {
self.handle
}
}
impl PartialEq for SecretKey {
fn eq(
&self,
other: &Self,
) -> bool {
self.as_bytes() == other.as_bytes()
}
}
impl ToBytes for SecretKey {
fn as_bytes(&self) -> Result<Vec<u8>> {
let mut num_bytes: i64 = 0;
try_seal!(unsafe {
bindgen::SecretKey_SaveSize(self.handle, CompressionType::ZStd as u8, &mut num_bytes)
})?;
let mut data: Vec<u8> = Vec::with_capacity(num_bytes as usize);
let mut bytes_written: i64 = 0;
try_seal!(unsafe {
let data_ptr = data.as_mut_ptr();
bindgen::SecretKey_Save(
self.handle,
data_ptr,
num_bytes as u64,
CompressionType::ZStd as u8,
&mut bytes_written,
)
})?;
unsafe { data.set_len(bytes_written as usize) };
Ok(data)
}
}
impl FromBytes for SecretKey {
type State = Context;
fn from_bytes(
context: &Context,
bytes: &[u8],
) -> Result<Self> {
let key = SecretKey::new()?;
let mut bytes_read = 0;
try_seal!(unsafe {
bindgen::SecretKey_Load(
key.handle,
context.get_handle(),
bytes.as_ptr() as *mut u8,
bytes.len() as u64,
&mut bytes_read,
)
})?;
Ok(key)
}
}
impl Drop for SecretKey {
fn drop(&mut self) {
try_seal!(unsafe { bindgen::SecretKey_Destroy(self.handle) })
.expect("Fatal error in SecretKey::drop")
}
}
impl Serialize for SecretKey {
fn serialize<S>(
&self,
serializer: S,
) -> std::result::Result<S::Ok, S::Error>
where
S: Serializer,
{
let data = self
.as_bytes()
.map_err(|e| S::Error::custom(format!("Failed to get secret key bytes: {}", e)))?;
serializer.serialize_bytes(&data)
}
}
impl Clone for SecretKey {
fn clone(&self) -> Self {
let mut handle: *mut c_void = null_mut();
try_seal!(unsafe { bindgen::SecretKey_Create2(self.handle, &mut handle) })
.expect("Fatal error in SecretKey::clone");
Self {
handle,
}
}
}
impl core::fmt::Debug for SecretKey {
fn fmt(
&self,
f: &mut core::fmt::Formatter,
) -> core::fmt::Result {
f.debug_struct("SecretKey")
.field("handle", &"<ELIDED>")
.finish()
}
}
impl AsRef<SecretKey> for SecretKey {
fn as_ref(&self) -> &SecretKey {
self
}
}
#[derive(Debug)]
pub struct RelinearizationKey {
handle: *mut c_void,
}
unsafe impl Sync for RelinearizationKey {}
unsafe impl Send for RelinearizationKey {}
impl RelinearizationKey {
pub fn get_handle(&self) -> *mut c_void {
self.handle
}
pub fn new() -> Result<Self> {
let mut handle: *mut c_void = null_mut();
try_seal!(unsafe { bindgen::KSwitchKeys_Create1(&mut handle) })?;
Ok(Self {
handle,
})
}
pub fn as_bytes(&self) -> Result<Vec<u8>> {
let mut num_bytes: i64 = 0;
try_seal!(unsafe {
bindgen::KSwitchKeys_SaveSize(self.handle, CompressionType::ZStd as u8, &mut num_bytes)
})?;
let mut data: Vec<u8> = Vec::with_capacity(num_bytes as usize);
let mut bytes_written: i64 = 0;
try_seal!(unsafe {
let data_ptr = data.as_mut_ptr();
bindgen::KSwitchKeys_Save(
self.handle,
data_ptr,
num_bytes as u64,
CompressionType::ZStd as u8,
&mut bytes_written,
)
})?;
unsafe { data.set_len(bytes_written as usize) };
Ok(data)
}
}
impl PartialEq for RelinearizationKey {
fn eq(
&self,
other: &Self,
) -> bool {
self.as_bytes() == other.as_bytes()
}
}
impl ToBytes for RelinearizationKey {
fn as_bytes(&self) -> Result<Vec<u8>> {
let mut num_bytes: i64 = 0;
try_seal!(unsafe {
bindgen::KSwitchKeys_SaveSize(self.handle, CompressionType::ZStd as u8, &mut num_bytes)
})?;
let mut data: Vec<u8> = Vec::with_capacity(num_bytes as usize);
let mut bytes_written: i64 = 0;
try_seal!(unsafe {
let data_ptr = data.as_mut_ptr();
bindgen::KSwitchKeys_Save(
self.handle,
data_ptr,
num_bytes as u64,
CompressionType::ZStd as u8,
&mut bytes_written,
)
})?;
unsafe { data.set_len(bytes_written as usize) };
Ok(data)
}
}
impl FromBytes for RelinearizationKey {
type State = Context;
fn from_bytes(
context: &Context,
bytes: &[u8],
) -> Result<Self> {
let keys = RelinearizationKey::new()?;
let mut write_bytes: i64 = 0;
try_seal!(unsafe {
bindgen::KSwitchKeys_Load(
keys.handle,
context.get_handle(),
bytes.as_ptr() as *mut u8,
bytes.len() as u64,
&mut write_bytes,
)
})?;
Ok(keys)
}
}
impl Drop for RelinearizationKey {
fn drop(&mut self) {
try_seal!(unsafe {
bindgen::KSwitchKeys_Destroy(self.handle)
})
.expect("Fatal error in PublicKey::drop()")
}
}
impl Clone for RelinearizationKey {
fn clone(&self) -> Self {
let mut handle: *mut c_void = null_mut();
try_seal!(unsafe {
bindgen::KSwitchKeys_Create2(self.handle, &mut handle)
})
.expect("Failed to clone Galois keys.");
Self {
handle,
}
}
}
#[derive(PartialEq)]
pub struct CompactRelinearizationKey(RelinearizationKey);
impl CompactRelinearizationKey {
pub fn as_bytes(&self) -> Result<Vec<u8>> {
self.0.as_bytes()
}
}
#[derive(Debug)]
pub struct GaloisKey {
handle: *mut c_void,
}
unsafe impl Sync for GaloisKey {}
unsafe impl Send for GaloisKey {}
impl GaloisKey {
pub fn get_handle(&self) -> *mut c_void {
self.handle
}
pub fn new() -> Result<GaloisKey> {
let mut handle: *mut c_void = null_mut();
try_seal!(unsafe { bindgen::KSwitchKeys_Create1(&mut handle) })?;
Ok(Self {
handle,
})
}
}
impl PartialEq for GaloisKey {
fn eq(
&self,
other: &Self,
) -> bool {
self.as_bytes() == other.as_bytes()
}
}
impl ToBytes for GaloisKey {
fn as_bytes(&self) -> Result<Vec<u8>> {
let mut num_bytes: i64 = 0;
try_seal!(unsafe {
bindgen::KSwitchKeys_SaveSize(self.handle, CompressionType::ZStd as u8, &mut num_bytes)
})?;
let mut data: Vec<u8> = Vec::with_capacity(num_bytes as usize);
let mut bytes_written: i64 = 0;
try_seal!(unsafe {
let data_ptr = data.as_mut_ptr();
bindgen::KSwitchKeys_Save(
self.handle,
data_ptr,
num_bytes as u64,
CompressionType::ZStd as u8,
&mut bytes_written,
)
})?;
unsafe { data.set_len(bytes_written as usize) };
Ok(data)
}
}
impl FromBytes for GaloisKey {
type State = Context;
fn from_bytes(
context: &Context,
bytes: &[u8],
) -> Result<Self> {
let keys = GaloisKey::new()?;
let mut write_bytes: i64 = 0;
try_seal!(unsafe {
bindgen::KSwitchKeys_Load(
keys.handle,
context.get_handle(),
bytes.as_ptr() as *mut u8,
bytes.len() as u64,
&mut write_bytes,
)
})?;
Ok(keys)
}
}
impl Drop for GaloisKey {
fn drop(&mut self) {
try_seal!(unsafe {
bindgen::KSwitchKeys_Destroy(self.handle)
})
.expect("Fatal error in GaloisKeys::drop()")
}
}
impl Clone for GaloisKey {
fn clone(&self) -> Self {
let mut handle: *mut c_void = null_mut();
try_seal!(unsafe {
bindgen::KSwitchKeys_Create2(self.handle, &mut handle)
})
.expect("Failed to clone Galois keys.");
Self {
handle,
}
}
}
#[derive(PartialEq)]
pub struct CompactGaloisKeys(GaloisKey);
impl CompactGaloisKeys {
pub fn as_bytes(&self) -> Result<Vec<u8>> {
self.0.as_bytes()
}
}
#[cfg(test)]
mod tests {
use crate::*;
#[test]
fn can_create_secret_key() {
let params = 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)
.build()
.unwrap();
let ctx = Context::new(¶ms, false, SecurityLevel::TC128).unwrap();
let gen = KeyGenerator::new(&ctx).unwrap();
let secret_key = gen.secret_key();
let gen = KeyGenerator::new(&ctx).unwrap();
let secret_key_2 = gen.secret_key();
assert_ne!(
serde_json::to_string(&secret_key_2).unwrap(),
serde_json::to_string(&secret_key).unwrap()
);
}
#[test]
fn can_create_public_key() {
let params = 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)
.build()
.unwrap();
let ctx = Context::new(¶ms, false, SecurityLevel::TC128).unwrap();
let gen = KeyGenerator::new(&ctx).unwrap();
gen.create_public_key();
}
#[test]
fn can_create_relin_key() {
let params = 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)
.build()
.unwrap();
let ctx = Context::new(¶ms, false, SecurityLevel::TC128).unwrap();
let gen = KeyGenerator::new(&ctx).unwrap();
gen.create_relinearization_keys().unwrap();
}
#[test]
fn can_create_galois_key() {
let params = BFVEncryptionParametersBuilder::new()
.set_poly_modulus_degree(DegreeType::D8192)
.set_coefficient_modulus(
CoefficientModulusFactory::bfv(DegreeType::D8192, SecurityLevel::TC128).unwrap(),
)
.set_plain_modulus(PlainModulusFactory::batching(DegreeType::D8192, 32).unwrap())
.build()
.unwrap();
let ctx = Context::new(¶ms, false, SecurityLevel::TC128).unwrap();
let gen = KeyGenerator::new(&ctx).unwrap();
gen.create_galois_keys().unwrap();
}
#[test]
fn can_init_from_existing_secret_key() {
let params = 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)
.build()
.unwrap();
let ctx = Context::new(¶ms, false, SecurityLevel::TC128).unwrap();
let gen = KeyGenerator::new(&ctx).unwrap();
let secret_key = gen.secret_key();
let gen = KeyGenerator::new_from_secret_key(&ctx, &secret_key).unwrap();
let secret_key_2 = gen.secret_key();
assert_eq!(
serde_json::to_string(&secret_key_2).unwrap(),
serde_json::to_string(&secret_key).unwrap()
);
}
}