use std::ffi::c_void;
use std::ptr::null_mut;
use crate::bindgen;
use crate::error::*;
use crate::serialization::CompressionType;
use crate::{Context, FromBytes, ToBytes};
use serde::ser::Error;
use serde::{Serialize, Serializer};
pub struct KeyGenerator {
handle: *mut c_void,
}
unsafe impl Sync for KeyGenerator {}
unsafe impl Send for KeyGenerator {}
impl KeyGenerator {
pub fn new(ctx: &Context) -> Result<Self> {
let mut handle = null_mut();
convert_seal_error(unsafe {
bindgen::KeyGenerator_Create1(ctx.get_handle(), &mut handle)
})?;
Ok(KeyGenerator { handle })
}
pub fn new_from_secret_key(ctx: &Context, secret_key: &SecretKey) -> Result<Self> {
let mut handle = null_mut();
convert_seal_error(unsafe {
bindgen::KeyGenerator_Create2(ctx.get_handle(), secret_key.handle, &mut handle)
})?;
Ok(KeyGenerator { handle })
}
pub fn secret_key(&self) -> SecretKey {
let mut handle = null_mut();
convert_seal_error(unsafe { bindgen::KeyGenerator_SecretKey(self.handle, &mut handle) })
.expect("Fatal error in KeyGenerator::secret_key");
SecretKey { handle }
}
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();
convert_seal_error(unsafe {
bindgen::KeyGenerator_CreatePublicKey(self.handle, save_seed, &mut handle)
})
.expect("Fatal error in KeyGenerator::public_key");
PublicKey { handle }
}
pub fn create_relinearization_keys(&self) -> Result<RelinearizationKeys> {
self.create_relinearization_keys_internal(false)
}
pub fn create_compact_relinearization_keys(&self) -> Result<CompactRelinearizationKeys> {
Ok(CompactRelinearizationKeys(
self.create_relinearization_keys_internal(true)?,
))
}
fn create_relinearization_keys_internal(&self, save_seed: bool) -> Result<RelinearizationKeys> {
let mut handle = null_mut();
convert_seal_error(unsafe {
bindgen::KeyGenerator_CreateRelinKeys(self.handle, save_seed, &mut handle)
})?;
Ok(RelinearizationKeys { 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<GaloisKeys> {
self.create_galois_keys_internal(false)
}
fn create_galois_keys_internal(&self, save_seed: bool) -> Result<GaloisKeys> {
let mut handle = null_mut();
convert_seal_error(unsafe {
bindgen::KeyGenerator_CreateGaloisKeysAll(self.handle, save_seed, &mut handle)
})?;
Ok(GaloisKeys { handle })
}
}
impl Drop for KeyGenerator {
fn drop(&mut self) {
convert_seal_error(unsafe { bindgen::KeyGenerator_Destroy(self.handle) })
.expect("Fatal error in KeyGenerator::drop");
}
}
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;
convert_seal_error(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;
convert_seal_error(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 {
fn from_bytes(context: &Context, bytes: &[u8]) -> Result<Self> {
let key = PublicKey::new()?;
let mut bytes_read = 0;
convert_seal_error(unsafe {
bindgen::PublicKey_Load(
key.handle,
context.handle,
bytes.as_ptr() as *mut u8,
bytes.len() as u64,
&mut bytes_read,
)
})?;
Ok(key)
}
}
impl PublicKey {
fn new() -> Result<Self> {
let mut handle: *mut c_void = null_mut();
convert_seal_error(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) {
convert_seal_error(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();
convert_seal_error(unsafe { bindgen::PublicKey_Create2(self.handle, &mut handle) })
.expect("Fatal error in PublicKey::clone");
Self { handle }
}
}
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 {
fn new() -> Result<Self> {
let mut handle: *mut c_void = null_mut();
convert_seal_error(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;
convert_seal_error(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;
convert_seal_error(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 {
fn from_bytes(context: &Context, bytes: &[u8]) -> Result<Self> {
let key = SecretKey::new()?;
let mut bytes_read = 0;
convert_seal_error(unsafe {
bindgen::SecretKey_Load(
key.handle,
context.handle,
bytes.as_ptr() as *mut u8,
bytes.len() as u64,
&mut bytes_read,
)
})?;
Ok(key)
}
}
impl Drop for SecretKey {
fn drop(&mut self) {
convert_seal_error(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();
convert_seal_error(unsafe { bindgen::SecretKey_Create2(self.handle, &mut handle) })
.expect("Fatal error in SecretKey::clone");
Self { handle }
}
}
pub struct RelinearizationKeys {
handle: *mut c_void,
}
unsafe impl Sync for RelinearizationKeys {}
unsafe impl Send for RelinearizationKeys {}
impl RelinearizationKeys {
pub fn get_handle(&self) -> *mut c_void {
self.handle
}
fn new() -> Result<RelinearizationKeys> {
let mut handle: *mut c_void = null_mut();
convert_seal_error(unsafe { bindgen::KSwitchKeys_Create1(&mut handle) })?;
Ok(Self { handle })
}
pub fn as_bytes(&self) -> Result<Vec<u8>> {
let mut num_bytes: i64 = 0;
convert_seal_error(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;
convert_seal_error(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 RelinearizationKeys {
fn eq(&self, other: &Self) -> bool {
self.as_bytes() == other.as_bytes()
}
}
impl ToBytes for RelinearizationKeys {
fn as_bytes(&self) -> Result<Vec<u8>> {
let mut num_bytes: i64 = 0;
convert_seal_error(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;
convert_seal_error(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 RelinearizationKeys {
fn from_bytes(context: &Context, bytes: &[u8]) -> Result<Self> {
let keys = RelinearizationKeys::new()?;
let mut write_bytes: i64 = 0;
convert_seal_error(unsafe {
bindgen::KSwitchKeys_Load(
keys.handle,
context.handle,
bytes.as_ptr() as *mut u8,
bytes.len() as u64,
&mut write_bytes,
)
})?;
Ok(keys)
}
}
impl Drop for RelinearizationKeys {
fn drop(&mut self) {
convert_seal_error(unsafe {
bindgen::KSwitchKeys_Destroy(self.handle)
})
.expect("Fatal error in PublicKey::drop()")
}
}
impl Clone for RelinearizationKeys {
fn clone(&self) -> Self {
let mut handle: *mut c_void = null_mut();
convert_seal_error(unsafe {
bindgen::KSwitchKeys_Create2(self.handle, &mut handle)
})
.expect("Failed to clone Galois keys.");
Self { handle }
}
}
#[derive(PartialEq)]
pub struct CompactRelinearizationKeys(RelinearizationKeys);
impl CompactRelinearizationKeys {
pub fn as_bytes(&self) -> Result<Vec<u8>> {
self.0.as_bytes()
}
}
pub struct GaloisKeys {
handle: *mut c_void,
}
unsafe impl Sync for GaloisKeys {}
unsafe impl Send for GaloisKeys {}
impl GaloisKeys {
pub fn get_handle(&self) -> *mut c_void {
self.handle
}
fn new() -> Result<GaloisKeys> {
let mut handle: *mut c_void = null_mut();
convert_seal_error(unsafe { bindgen::KSwitchKeys_Create1(&mut handle) })?;
Ok(Self { handle })
}
}
impl PartialEq for GaloisKeys {
fn eq(&self, other: &Self) -> bool {
self.as_bytes() == other.as_bytes()
}
}
impl ToBytes for GaloisKeys {
fn as_bytes(&self) -> Result<Vec<u8>> {
let mut num_bytes: i64 = 0;
convert_seal_error(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;
convert_seal_error(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 GaloisKeys {
fn from_bytes(context: &Context, bytes: &[u8]) -> Result<Self> {
let keys = GaloisKeys::new()?;
let mut write_bytes: i64 = 0;
convert_seal_error(unsafe {
bindgen::KSwitchKeys_Load(
keys.handle,
context.handle,
bytes.as_ptr() as *mut u8,
bytes.len() as u64,
&mut write_bytes,
)
})?;
Ok(keys)
}
}
impl Drop for GaloisKeys {
fn drop(&mut self) {
convert_seal_error(unsafe {
bindgen::KSwitchKeys_Destroy(self.handle)
})
.expect("Fatal error in GaloisKeys::drop()")
}
}
impl Clone for GaloisKeys {
fn clone(&self) -> Self {
let mut handle: *mut c_void = null_mut();
convert_seal_error(unsafe {
bindgen::KSwitchKeys_Create2(self.handle, &mut handle)
})
.expect("Failed to clone Galois keys.");
Self { handle }
}
}
#[derive(PartialEq)]
pub struct CompactGaloisKeys(GaloisKeys);
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(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 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(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();
gen.create_public_key();
}
#[test]
fn can_create_relin_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();
gen.create_relinearization_keys().unwrap();
}
#[test]
fn can_create_galois_key() {
let params = BfvEncryptionParametersBuilder::new()
.set_poly_modulus_degree(8192)
.set_coefficient_modulus(
CoefficientModulus::bfv_default(8192, SecurityLevel::TC128).unwrap(),
)
.set_plain_modulus(PlainModulus::batching(8192, 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(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 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()
);
}
}