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::try_seal;
use serde::{Deserialize, Serialize};
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, Serialize, Deserialize)]
#[repr(i32)]
pub enum SecurityLevel {
TC128 = 128,
TC192 = 192,
TC256 = 256,
}
impl TryFrom<i32> for SecurityLevel {
type Error = Error;
fn try_from(val: i32) -> Result<SecurityLevel> {
Ok(match val {
128 => SecurityLevel::TC128,
192 => SecurityLevel::TC192,
256 => SecurityLevel::TC256,
_ => Err(Error::SerializationError(Box::new(format!(
"Invalid security level: {}",
val
))))?,
})
}
}
impl From<SecurityLevel> for i32 {
fn from(val: SecurityLevel) -> Self {
match val {
SecurityLevel::TC128 => 128,
SecurityLevel::TC192 => 192,
SecurityLevel::TC256 => 256,
}
}
}
impl Default for SecurityLevel {
fn default() -> Self {
Self::TC128
}
}
#[allow(missing_docs)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum DegreeType {
D256,
D512,
D1024,
D2048,
D4096,
D8192,
D16384,
D32768,
}
impl From<DegreeType> for u64 {
fn from(value: DegreeType) -> Self {
match value {
DegreeType::D256 => 256,
DegreeType::D512 => 512,
DegreeType::D1024 => 1024,
DegreeType::D2048 => 2048,
DegreeType::D4096 => 4096,
DegreeType::D8192 => 8192,
DegreeType::D16384 => 16384,
DegreeType::D32768 => 32768,
}
}
}
impl TryFrom<u64> for DegreeType {
type Error = Error;
fn try_from(value: u64) -> std::result::Result<Self, Self::Error> {
match value {
256 => Ok(DegreeType::D256),
512 => Ok(DegreeType::D512),
1024 => Ok(DegreeType::D1024),
2048 => Ok(DegreeType::D2048),
4096 => Ok(DegreeType::D4096),
8192 => Ok(DegreeType::D8192),
16384 => Ok(DegreeType::D16384),
32768 => Ok(DegreeType::D32768),
_ => Err(Error::DegreeNotSet),
}
}
}
pub struct Modulus {
handle: AtomicPtr<c_void>,
}
impl Modulus {
pub fn new(value: u64) -> Result<Self> {
let mut handle: *mut c_void = null_mut();
try_seal!(unsafe { bindgen::Modulus_Create1(value, &mut handle) })?;
Ok(Modulus {
handle: AtomicPtr::new(handle),
})
}
pub(crate) unsafe fn new_unchecked_from_handle(handle: *mut c_void) -> Self {
Modulus {
handle: AtomicPtr::new(handle),
}
}
pub fn value(&self) -> u64 {
let mut val: u64 = 0;
try_seal!(unsafe { bindgen::Modulus_Value(self.get_handle(), &mut val) })
.expect("Internal error. Could not get modulus value.");
val
}
pub(crate) unsafe fn get_handle(&self) -> *mut c_void {
self.handle.load(Ordering::SeqCst)
}
}
impl std::fmt::Debug for Modulus {
fn fmt(
&self,
f: &mut std::fmt::Formatter<'_>,
) -> std::result::Result<(), std::fmt::Error> {
write!(f, "{}", self.value())
}
}
impl PartialEq for Modulus {
fn eq(
&self,
other: &Self,
) -> bool {
self.value() == other.value()
}
}
impl Drop for Modulus {
fn drop(&mut self) {
try_seal!(unsafe { bindgen::Modulus_Destroy(self.get_handle()) })
.expect("Internal error in Modulus::drop().");
}
}
impl Clone for Modulus {
fn clone(&self) -> Self {
let mut copy = null_mut();
unsafe {
try_seal!(bindgen::Modulus_Create2(self.get_handle(), &mut copy))
.expect("Failed to clone modulus")
};
Self {
handle: AtomicPtr::new(copy),
}
}
}
#[derive(Debug, Clone)]
pub struct CoefficientModulusFactory;
impl CoefficientModulusFactory {
pub fn build(
degree: DegreeType,
bit_sizes: &[i32],
) -> Result<Vec<Modulus>> {
let mut bit_sizes = bit_sizes.to_owned();
let length = bit_sizes.len() as u64;
let mut coefficients: Vec<*mut c_void> = Vec::with_capacity(bit_sizes.len());
let coefficients_ptr = coefficients.as_mut_ptr();
try_seal!(unsafe {
bindgen::CoeffModulus_Create1(
degree.into(),
length,
bit_sizes.as_mut_ptr(),
coefficients_ptr,
)
})?;
unsafe { coefficients.set_len(length as usize) };
let coeff_mod = unsafe {
coefficients
.into_iter()
.map(|ptr| Modulus::new_unchecked_from_handle(ptr))
.collect()
};
Ok(coeff_mod)
}
pub fn bfv(
degree: DegreeType,
security_level: SecurityLevel,
) -> Result<Vec<Modulus>> {
let mut len: u64 = 0;
try_seal!(unsafe {
bindgen::CoeffModulus_BFVDefault(
degree.into(),
security_level as i32,
&mut len,
null_mut(),
)
})?;
let mut coefficients: Vec<*mut c_void> = Vec::with_capacity(len as usize);
let coefficients_ptr = coefficients.as_mut_ptr();
try_seal!(unsafe {
bindgen::CoeffModulus_BFVDefault(
degree.into(),
security_level as i32,
&mut len,
coefficients_ptr,
)
})?;
unsafe { coefficients.set_len(len as usize) };
let coeff_mod = unsafe {
coefficients
.into_iter()
.map(|ptr| Modulus::new_unchecked_from_handle(ptr))
.collect()
};
Ok(coeff_mod)
}
pub fn max_bit_count(
degree: u64,
security_level: SecurityLevel,
) -> u32 {
let mut bits: i32 = 0;
unsafe { bindgen::CoeffModulus_MaxBitCount(degree, security_level as i32, &mut bits) };
assert!(bits > 0);
bits as u32
}
}
pub struct PlainModulusFactory;
impl PlainModulusFactory {
pub fn raw(val: u64) -> Result<Modulus> {
Modulus::new(val)
}
pub fn batching(
degree: DegreeType,
bit_size: u32,
) -> Result<Modulus> {
let bit_sizes = vec![bit_size as i32];
let modulus_chain = CoefficientModulusFactory::build(degree, bit_sizes.as_slice())?;
Ok(modulus_chain.first().ok_or(Error::Unexpected)?.clone())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn can_create_plain_modulus() {
let modulus = PlainModulusFactory::batching(DegreeType::D1024, 20).unwrap();
assert_eq!(modulus.value(), 1038337);
}
#[test]
fn can_create_default_coefficient_modulus() {
let modulus =
CoefficientModulusFactory::bfv(DegreeType::D1024, SecurityLevel::TC128).unwrap();
assert_eq!(modulus.len(), 1);
assert_eq!(modulus[0].value(), 132120577);
let modulus =
CoefficientModulusFactory::bfv(DegreeType::D1024, SecurityLevel::TC192).unwrap();
assert_eq!(modulus.len(), 1);
assert_eq!(modulus[0].value(), 520193);
let modulus =
CoefficientModulusFactory::bfv(DegreeType::D1024, SecurityLevel::TC256).unwrap();
assert_eq!(modulus.len(), 1);
assert_eq!(modulus[0].value(), 12289);
}
#[test]
fn can_create_custom_coefficient_modulus() {
let modulus =
CoefficientModulusFactory::build(DegreeType::D8192, &[50, 30, 30, 50, 50]).unwrap();
assert_eq!(modulus.len(), 5);
assert_eq!(modulus[0].value(), 1125899905744897);
assert_eq!(modulus[1].value(), 1073643521);
assert_eq!(modulus[2].value(), 1073692673);
assert_eq!(modulus[3].value(), 1125899906629633);
assert_eq!(modulus[4].value(), 1125899906826241);
}
#[test]
fn can_roundtrip_security_level() {
for sec in [
SecurityLevel::TC128,
SecurityLevel::TC192,
SecurityLevel::TC256,
] {
let sec_2: i32 = sec.into();
let sec_2 = SecurityLevel::try_from(sec_2).unwrap();
assert_eq!(sec, sec_2);
}
}
}