use std::ffi::c_void;
use std::ptr::null_mut;
use crate::bindgen;
use crate::error::*;
use crate::{Context, Plaintext};
pub struct BFVEncoder {
handle: *mut c_void,
}
unsafe impl Sync for BFVEncoder {}
unsafe impl Send for BFVEncoder {}
impl BFVEncoder {
pub fn new(ctx: &Context) -> Result<Self> {
let mut handle: *mut c_void = null_mut();
convert_seal_error(unsafe { bindgen::BatchEncoder_Create(ctx.get_handle(), &mut handle) })?;
Ok(Self { handle })
}
pub fn encode_unsigned(&self, data: &[u64]) -> Result<Plaintext> {
let plaintext = Plaintext::new()?;
convert_seal_error(unsafe {
bindgen::BatchEncoder_Encode1(
self.handle,
data.len() as u64,
data.as_ptr() as *mut u64,
plaintext.get_handle(),
)
})?;
Ok(plaintext)
}
pub fn encode_signed(&self, data: &[i64]) -> Result<Plaintext> {
let plaintext = Plaintext::new()?;
convert_seal_error(unsafe {
bindgen::BatchEncoder_Encode2(
self.handle,
data.len() as u64,
data.as_ptr() as *mut i64,
plaintext.get_handle(),
)
})?;
Ok(plaintext)
}
pub fn decode_unsigned(&self, plaintext: &Plaintext) -> Result<Vec<u64>> {
let mut data = Vec::with_capacity(self.get_slot_count());
let data_ptr = data.as_mut_ptr();
let mut size: u64 = 0;
convert_seal_error(unsafe {
bindgen::BatchEncoder_Decode1(
self.handle,
plaintext.get_handle(),
&mut size,
data_ptr,
null_mut(),
)
})?;
if data.capacity() < size as usize {
panic!("Allocation overflow BVTEncoder::decode_unsigned");
}
unsafe {
data.set_len(size as usize);
}
Ok(data)
}
pub fn decode_signed(&self, plaintext: &Plaintext) -> Result<Vec<i64>> {
let mut data = Vec::with_capacity(self.get_slot_count());
let data_ptr = data.as_mut_ptr();
let mut size: u64 = 0;
convert_seal_error(unsafe {
bindgen::BatchEncoder_Decode2(
self.handle,
plaintext.get_handle(),
&mut size,
data_ptr,
null_mut(),
)
})?;
if data.capacity() < size as usize {
panic!("Allocation overflow BVTEncoder::decode_unsigned");
}
unsafe {
data.set_len(size as usize);
}
Ok(data)
}
pub fn get_slot_count(&self) -> usize {
let mut count: u64 = 0;
convert_seal_error(unsafe { bindgen::BatchEncoder_GetSlotCount(self.handle, &mut count) })
.expect("Internal error in BVTEncoder::get_slot_count().");
count as usize
}
}
impl Drop for BFVEncoder {
fn drop(&mut self) {
convert_seal_error(unsafe { bindgen::BatchEncoder_Destroy(self.handle) })
.expect("Internal error in BFVEncoder::drop.");
}
}
pub struct BFVScalarEncoder {}
impl BFVScalarEncoder {
pub fn new() -> Self {
Self {}
}
pub fn encode_unsigned(&self, val: u64) -> Result<Plaintext> {
Plaintext::from_hex_string(&format!("{:x}", val))
}
pub fn encode_signed(&self, val: i64) -> Result<Plaintext> {
let as_u64: u64 = unsafe { std::mem::transmute(val) };
Plaintext::from_hex_string(&format!("{:x}", as_u64))
}
pub fn decode_unsigned(&self, p: &Plaintext) -> Result<u64> {
let mut len: u64 = 0;
let mut coeff: u64 = 0;
convert_seal_error(unsafe { bindgen::Plaintext_CoeffCount(p.get_handle(), &mut len) })?;
convert_seal_error(unsafe { bindgen::Plaintext_CoeffAt(p.get_handle(), 0, &mut coeff) })?;
Ok(coeff)
}
pub fn decode_signed(&self, p: &Plaintext) -> Result<i64> {
let mut len: u64 = 0;
let mut coeff: i64 = 0;
convert_seal_error(unsafe { bindgen::Plaintext_CoeffCount(p.get_handle(), &mut len) })?;
convert_seal_error(unsafe {
bindgen::Plaintext_CoeffAt(p.get_handle(), 0, &mut coeff as *mut i64 as *mut u64)
})?;
Ok(coeff)
}
}
impl Default for BFVScalarEncoder {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use crate::*;
#[test]
fn can_create_and_drop_bfv_encoder() {
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();
std::mem::drop(encoder);
}
#[test]
fn can_get_slots_bfv_encoder() {
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();
assert_eq!(encoder.get_slot_count(), 8192);
}
#[test]
fn can_get_encode_and_decode_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 encoder = BFVEncoder::new(&ctx).unwrap();
let mut data = Vec::with_capacity(8192);
for i in 0..encoder.get_slot_count() {
data.push(i as u64);
}
let plaintext = encoder.encode_unsigned(data.as_slice()).unwrap();
let data_2 = encoder.decode_unsigned(&plaintext).unwrap();
assert_eq!(data, data_2);
}
#[test]
fn can_get_encode_and_decode_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 encoder = BFVEncoder::new(&ctx).unwrap();
let mut data = Vec::with_capacity(8192);
for i in 0..encoder.get_slot_count() {
data.push(i as i64);
}
let plaintext = encoder.encode_signed(data.as_slice()).unwrap();
let data_2 = encoder.decode_signed(&plaintext).unwrap();
assert_eq!(data, data_2);
}
#[test]
fn scalar_encoder_can_encode_decode_signed() {
let encoder = BFVScalarEncoder::new();
let p = encoder.encode_signed(-15).unwrap();
assert_eq!(encoder.decode_signed(&p).unwrap(), -15);
}
#[test]
fn scalar_encoder_can_encode_decode_unsigned() {
let encoder = BFVScalarEncoder::new();
let p = encoder.encode_signed(42).unwrap();
assert_eq!(encoder.decode_signed(&p).unwrap(), 42);
}
}