updated repo for publishing (#74)

This commit is contained in:
Jean-Philippe Bossuat
2025-08-17 14:57:39 +02:00
committed by GitHub
parent 0be569eca0
commit 62eb87cc07
244 changed files with 374 additions and 539 deletions

View File

@@ -0,0 +1,117 @@
use poulpy_backend::hal::{
api::{FillUniform, Reset, VecZnxCopy, VecZnxFillUniform},
layouts::{Backend, Data, DataMut, DataRef, MatZnx, Module, ReaderFrom, WriterTo},
source::Source,
};
use crate::layouts::{
GGLWEAutomorphismKey, Infos,
compressed::{Decompress, GGLWESwitchingKeyCompressed},
};
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use std::fmt;
#[derive(PartialEq, Eq, Clone)]
pub struct GGLWEAutomorphismKeyCompressed<D: Data> {
pub(crate) key: GGLWESwitchingKeyCompressed<D>,
pub(crate) p: i64,
}
impl<D: DataRef> fmt::Debug for GGLWEAutomorphismKeyCompressed<D> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self)
}
}
impl<D: DataMut> FillUniform for GGLWEAutomorphismKeyCompressed<D> {
fn fill_uniform(&mut self, source: &mut Source) {
self.key.fill_uniform(source);
}
}
impl<D: DataMut> Reset for GGLWEAutomorphismKeyCompressed<D>
where
MatZnx<D>: Reset,
{
fn reset(&mut self) {
self.key.reset();
self.p = 0;
}
}
impl<D: DataRef> fmt::Display for GGLWEAutomorphismKeyCompressed<D> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "(AutomorphismKeyCompressed: p={}) {}", self.p, self.key)
}
}
impl GGLWEAutomorphismKeyCompressed<Vec<u8>> {
pub fn alloc(n: usize, basek: usize, k: usize, rows: usize, digits: usize, rank: usize) -> Self {
GGLWEAutomorphismKeyCompressed {
key: GGLWESwitchingKeyCompressed::alloc(n, basek, k, rows, digits, rank, rank),
p: 0,
}
}
pub fn bytes_of(n: usize, basek: usize, k: usize, rows: usize, digits: usize, rank: usize) -> usize {
GGLWESwitchingKeyCompressed::<Vec<u8>>::bytes_of(n, basek, k, rows, digits, rank)
}
}
impl<D: Data> Infos for GGLWEAutomorphismKeyCompressed<D> {
type Inner = MatZnx<D>;
fn inner(&self) -> &Self::Inner {
self.key.inner()
}
fn basek(&self) -> usize {
self.key.basek()
}
fn k(&self) -> usize {
self.key.k()
}
}
impl<D: Data> GGLWEAutomorphismKeyCompressed<D> {
pub fn rank(&self) -> usize {
self.key.rank()
}
pub fn digits(&self) -> usize {
self.key.digits()
}
pub fn rank_in(&self) -> usize {
self.key.rank_in()
}
pub fn rank_out(&self) -> usize {
self.key.rank_out()
}
}
impl<D: DataMut> ReaderFrom for GGLWEAutomorphismKeyCompressed<D> {
fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> {
self.p = reader.read_u64::<LittleEndian>()? as i64;
self.key.read_from(reader)
}
}
impl<D: DataRef> WriterTo for GGLWEAutomorphismKeyCompressed<D> {
fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
writer.write_u64::<LittleEndian>(self.p as u64)?;
self.key.write_to(writer)
}
}
impl<D: DataMut, DR: DataRef, B: Backend> Decompress<B, GGLWEAutomorphismKeyCompressed<DR>> for GGLWEAutomorphismKey<D> {
fn decompress(&mut self, module: &Module<B>, other: &GGLWEAutomorphismKeyCompressed<DR>)
where
Module<B>: VecZnxFillUniform + VecZnxCopy,
{
self.key.decompress(module, &other.key);
self.p = other.p;
}
}

View File

@@ -0,0 +1,254 @@
use poulpy_backend::hal::{
api::{FillUniform, Reset, VecZnxCopy, VecZnxFillUniform},
layouts::{Backend, Data, DataMut, DataRef, MatZnx, Module, ReaderFrom, WriterTo},
source::Source,
};
use crate::layouts::{
GGLWECiphertext, Infos,
compressed::{Decompress, GLWECiphertextCompressed},
};
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use std::fmt;
#[derive(PartialEq, Eq, Clone)]
pub struct GGLWECiphertextCompressed<D: Data> {
pub(crate) data: MatZnx<D>,
pub(crate) basek: usize,
pub(crate) k: usize,
pub(crate) rank_out: usize,
pub(crate) digits: usize,
pub(crate) seed: Vec<[u8; 32]>,
}
impl<D: DataRef> fmt::Debug for GGLWECiphertextCompressed<D> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self)
}
}
impl<D: DataMut> FillUniform for GGLWECiphertextCompressed<D> {
fn fill_uniform(&mut self, source: &mut Source) {
self.data.fill_uniform(source);
}
}
impl<D: DataMut> Reset for GGLWECiphertextCompressed<D>
where
MatZnx<D>: Reset,
{
fn reset(&mut self) {
self.data.reset();
self.basek = 0;
self.k = 0;
self.digits = 0;
self.rank_out = 0;
self.seed = Vec::new();
}
}
impl<D: DataRef> fmt::Display for GGLWECiphertextCompressed<D> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"(GGLWECiphertextCompressed: basek={} k={} digits={}) {}",
self.basek, self.k, self.digits, self.data
)
}
}
impl GGLWECiphertextCompressed<Vec<u8>> {
pub fn alloc(n: usize, basek: usize, k: usize, rows: usize, digits: usize, rank_in: usize, rank_out: usize) -> Self {
let size: usize = k.div_ceil(basek);
debug_assert!(
size > digits,
"invalid gglwe: ceil(k/basek): {} <= digits: {}",
size,
digits
);
assert!(
rows * digits <= size,
"invalid gglwe: rows: {} * digits:{} > ceil(k/basek): {}",
rows,
digits,
size
);
Self {
data: MatZnx::alloc(n, rows, rank_in, 1, size),
basek,
k,
rank_out,
digits,
seed: vec![[0u8; 32]; rows * rank_in],
}
}
pub fn bytes_of(n: usize, basek: usize, k: usize, rows: usize, digits: usize, rank_in: usize) -> usize {
let size: usize = k.div_ceil(basek);
debug_assert!(
size > digits,
"invalid gglwe: ceil(k/basek): {} <= digits: {}",
size,
digits
);
assert!(
rows * digits <= size,
"invalid gglwe: rows: {} * digits:{} > ceil(k/basek): {}",
rows,
digits,
size
);
MatZnx::alloc_bytes(n, rows, rank_in, 1, rows)
}
}
impl<D: Data> Infos for GGLWECiphertextCompressed<D> {
type Inner = MatZnx<D>;
fn inner(&self) -> &Self::Inner {
&self.data
}
fn basek(&self) -> usize {
self.basek
}
fn k(&self) -> usize {
self.k
}
}
impl<D: Data> GGLWECiphertextCompressed<D> {
pub fn rank(&self) -> usize {
self.rank_out
}
pub fn digits(&self) -> usize {
self.digits
}
pub fn rank_in(&self) -> usize {
self.data.cols_in()
}
pub fn rank_out(&self) -> usize {
self.rank_out
}
}
impl<D: DataRef> GGLWECiphertextCompressed<D> {
pub(crate) fn at(&self, row: usize, col: usize) -> GLWECiphertextCompressed<&[u8]> {
GLWECiphertextCompressed {
data: self.data.at(row, col),
basek: self.basek,
k: self.k,
rank: self.rank_out,
seed: self.seed[self.rank_in() * row + col],
}
}
}
impl<D: DataMut> GGLWECiphertextCompressed<D> {
pub(crate) fn at_mut(&mut self, row: usize, col: usize) -> GLWECiphertextCompressed<&mut [u8]> {
let rank_in: usize = self.rank_in();
GLWECiphertextCompressed {
data: self.data.at_mut(row, col),
basek: self.basek,
k: self.k,
rank: self.rank_out,
seed: self.seed[rank_in * row + col], // Warning: value is copied and not borrow mut
}
}
}
impl<D: DataMut> ReaderFrom for GGLWECiphertextCompressed<D> {
fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> {
self.k = reader.read_u64::<LittleEndian>()? as usize;
self.basek = reader.read_u64::<LittleEndian>()? as usize;
self.digits = reader.read_u64::<LittleEndian>()? as usize;
self.rank_out = reader.read_u64::<LittleEndian>()? as usize;
let seed_len = reader.read_u64::<LittleEndian>()? as usize;
self.seed = vec![[0u8; 32]; seed_len];
for s in &mut self.seed {
reader.read_exact(s)?;
}
self.data.read_from(reader)
}
}
impl<D: DataRef> WriterTo for GGLWECiphertextCompressed<D> {
fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
writer.write_u64::<LittleEndian>(self.k as u64)?;
writer.write_u64::<LittleEndian>(self.basek as u64)?;
writer.write_u64::<LittleEndian>(self.digits as u64)?;
writer.write_u64::<LittleEndian>(self.rank_out as u64)?;
writer.write_u64::<LittleEndian>(self.seed.len() as u64)?;
for s in &self.seed {
writer.write_all(s)?;
}
self.data.write_to(writer)
}
}
impl<D: DataMut, B: Backend, DR: DataRef> Decompress<B, GGLWECiphertextCompressed<DR>> for GGLWECiphertext<D> {
fn decompress(&mut self, module: &Module<B>, other: &GGLWECiphertextCompressed<DR>)
where
Module<B>: VecZnxFillUniform + VecZnxCopy,
{
#[cfg(debug_assertions)]
{
use poulpy_backend::hal::api::ZnxInfos;
assert_eq!(
self.n(),
other.data.n(),
"invalid receiver: self.n()={} != other.n()={}",
self.n(),
other.data.n()
);
assert_eq!(
self.size(),
other.size(),
"invalid receiver: self.size()={} != other.size()={}",
self.size(),
other.size()
);
assert_eq!(
self.rank_in(),
other.rank_in(),
"invalid receiver: self.rank_in()={} != other.rank_in()={}",
self.rank_in(),
other.rank_in()
);
assert_eq!(
self.rank_out(),
other.rank_out(),
"invalid receiver: self.rank_out()={} != other.rank_out()={}",
self.rank_out(),
other.rank_out()
);
assert_eq!(
self.rows(),
other.rows(),
"invalid receiver: self.rows()={} != other.rows()={}",
self.rows(),
other.rows()
);
}
let rank_in: usize = self.rank_in();
let rows: usize = self.rows();
(0..rank_in).for_each(|col_i| {
(0..rows).for_each(|row_i| {
self.at_mut(row_i, col_i)
.decompress(module, &other.at(row_i, col_i));
});
});
}
}

View File

@@ -0,0 +1,127 @@
use poulpy_backend::hal::{
api::{FillUniform, Reset, VecZnxCopy, VecZnxFillUniform},
layouts::{Backend, Data, DataMut, DataRef, MatZnx, Module, ReaderFrom, WriterTo},
source::Source,
};
use crate::layouts::{
GGLWESwitchingKey, Infos,
compressed::{Decompress, GGLWECiphertextCompressed},
};
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use std::fmt;
#[derive(PartialEq, Eq, Clone)]
pub struct GGLWESwitchingKeyCompressed<D: Data> {
pub(crate) key: GGLWECiphertextCompressed<D>,
pub(crate) sk_in_n: usize, // Degree of sk_in
pub(crate) sk_out_n: usize, // Degree of sk_out
}
impl<D: DataRef> fmt::Debug for GGLWESwitchingKeyCompressed<D> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self)
}
}
impl<D: DataMut> FillUniform for GGLWESwitchingKeyCompressed<D> {
fn fill_uniform(&mut self, source: &mut Source) {
self.key.fill_uniform(source);
}
}
impl<D: DataMut> Reset for GGLWESwitchingKeyCompressed<D>
where
MatZnx<D>: Reset,
{
fn reset(&mut self) {
self.key.reset();
self.sk_in_n = 0;
self.sk_out_n = 0;
}
}
impl<D: DataRef> fmt::Display for GGLWESwitchingKeyCompressed<D> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"(GLWESwitchingKeyCompressed: sk_in_n={} sk_out_n={}) {}",
self.sk_in_n, self.sk_out_n, self.key.data
)
}
}
impl<D: Data> Infos for GGLWESwitchingKeyCompressed<D> {
type Inner = MatZnx<D>;
fn inner(&self) -> &Self::Inner {
self.key.inner()
}
fn basek(&self) -> usize {
self.key.basek()
}
fn k(&self) -> usize {
self.key.k()
}
}
impl<D: Data> GGLWESwitchingKeyCompressed<D> {
pub fn rank(&self) -> usize {
self.key.rank()
}
pub fn digits(&self) -> usize {
self.key.digits()
}
pub fn rank_in(&self) -> usize {
self.key.rank_in()
}
pub fn rank_out(&self) -> usize {
self.key.rank_out()
}
}
impl GGLWESwitchingKeyCompressed<Vec<u8>> {
pub fn alloc(n: usize, basek: usize, k: usize, rows: usize, digits: usize, rank_in: usize, rank_out: usize) -> Self {
GGLWESwitchingKeyCompressed {
key: GGLWECiphertextCompressed::alloc(n, basek, k, rows, digits, rank_in, rank_out),
sk_in_n: 0,
sk_out_n: 0,
}
}
pub fn bytes_of(n: usize, basek: usize, k: usize, rows: usize, digits: usize, rank_in: usize) -> usize {
GGLWECiphertextCompressed::bytes_of(n, basek, k, rows, digits, rank_in)
}
}
impl<D: DataMut> ReaderFrom for GGLWESwitchingKeyCompressed<D> {
fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> {
self.sk_in_n = reader.read_u64::<LittleEndian>()? as usize;
self.sk_out_n = reader.read_u64::<LittleEndian>()? as usize;
self.key.read_from(reader)
}
}
impl<D: DataRef> WriterTo for GGLWESwitchingKeyCompressed<D> {
fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
writer.write_u64::<LittleEndian>(self.sk_in_n as u64)?;
writer.write_u64::<LittleEndian>(self.sk_out_n as u64)?;
self.key.write_to(writer)
}
}
impl<D: DataMut, DR: DataRef, B: Backend> Decompress<B, GGLWESwitchingKeyCompressed<DR>> for GGLWESwitchingKey<D> {
fn decompress(&mut self, module: &Module<B>, other: &GGLWESwitchingKeyCompressed<DR>)
where
Module<B>: VecZnxFillUniform + VecZnxCopy,
{
self.key.decompress(module, &other.key);
self.sk_in_n = other.sk_in_n;
self.sk_out_n = other.sk_out_n;
}
}

View File

@@ -0,0 +1,165 @@
use poulpy_backend::hal::{
api::{FillUniform, Reset, VecZnxCopy, VecZnxFillUniform},
layouts::{Backend, Data, DataMut, DataRef, MatZnx, Module, ReaderFrom, WriterTo},
source::Source,
};
use crate::layouts::{
GGLWETensorKey, Infos,
compressed::{Decompress, GGLWESwitchingKeyCompressed},
};
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use std::fmt;
#[derive(PartialEq, Eq, Clone)]
pub struct GGLWETensorKeyCompressed<D: Data> {
pub(crate) keys: Vec<GGLWESwitchingKeyCompressed<D>>,
}
impl<D: DataRef> fmt::Debug for GGLWETensorKeyCompressed<D> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self)
}
}
impl<D: DataMut> FillUniform for GGLWETensorKeyCompressed<D> {
fn fill_uniform(&mut self, source: &mut Source) {
self.keys
.iter_mut()
.for_each(|key: &mut GGLWESwitchingKeyCompressed<D>| key.fill_uniform(source))
}
}
impl<D: DataMut> Reset for GGLWETensorKeyCompressed<D>
where
MatZnx<D>: Reset,
{
fn reset(&mut self) {
self.keys
.iter_mut()
.for_each(|key: &mut GGLWESwitchingKeyCompressed<D>| key.reset())
}
}
impl<D: DataRef> fmt::Display for GGLWETensorKeyCompressed<D> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
writeln!(f, "(GLWETensorKeyCompressed)",)?;
for (i, key) in self.keys.iter().enumerate() {
write!(f, "{}: {}", i, key)?;
}
Ok(())
}
}
impl GGLWETensorKeyCompressed<Vec<u8>> {
pub fn alloc(n: usize, basek: usize, k: usize, rows: usize, digits: usize, rank: usize) -> Self {
let mut keys: Vec<GGLWESwitchingKeyCompressed<Vec<u8>>> = Vec::new();
let pairs: usize = (((rank + 1) * rank) >> 1).max(1);
(0..pairs).for_each(|_| {
keys.push(GGLWESwitchingKeyCompressed::alloc(
n, basek, k, rows, digits, 1, rank,
));
});
Self { keys }
}
pub fn bytes_of(n: usize, basek: usize, k: usize, rows: usize, digits: usize, rank: usize) -> usize {
let pairs: usize = (((rank + 1) * rank) >> 1).max(1);
pairs * GGLWESwitchingKeyCompressed::bytes_of(n, basek, k, rows, digits, 1)
}
}
impl<D: Data> Infos for GGLWETensorKeyCompressed<D> {
type Inner = MatZnx<D>;
fn inner(&self) -> &Self::Inner {
self.keys[0].inner()
}
fn basek(&self) -> usize {
self.keys[0].basek()
}
fn k(&self) -> usize {
self.keys[0].k()
}
}
impl<D: Data> GGLWETensorKeyCompressed<D> {
pub fn rank(&self) -> usize {
self.keys[0].rank()
}
pub fn digits(&self) -> usize {
self.keys[0].digits()
}
pub fn rank_in(&self) -> usize {
self.keys[0].rank_in()
}
pub fn rank_out(&self) -> usize {
self.keys[0].rank_out()
}
}
impl<D: DataMut> ReaderFrom for GGLWETensorKeyCompressed<D> {
fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> {
let len: usize = reader.read_u64::<LittleEndian>()? as usize;
if self.keys.len() != len {
return Err(std::io::Error::new(
std::io::ErrorKind::InvalidData,
format!("self.keys.len()={} != read len={}", self.keys.len(), len),
));
}
for key in &mut self.keys {
key.read_from(reader)?;
}
Ok(())
}
}
impl<D: DataRef> WriterTo for GGLWETensorKeyCompressed<D> {
fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
writer.write_u64::<LittleEndian>(self.keys.len() as u64)?;
for key in &self.keys {
key.write_to(writer)?;
}
Ok(())
}
}
impl<D: DataMut> GGLWETensorKeyCompressed<D> {
pub(crate) fn at_mut(&mut self, mut i: usize, mut j: usize) -> &mut GGLWESwitchingKeyCompressed<D> {
if i > j {
std::mem::swap(&mut i, &mut j);
};
let rank: usize = self.rank();
&mut self.keys[i * rank + j - (i * (i + 1) / 2)]
}
}
impl<D: DataMut, DR: DataRef, B: Backend> Decompress<B, GGLWETensorKeyCompressed<DR>> for GGLWETensorKey<D> {
fn decompress(&mut self, module: &Module<B>, other: &GGLWETensorKeyCompressed<DR>)
where
Module<B>: VecZnxFillUniform + VecZnxCopy,
{
#[cfg(debug_assertions)]
{
assert_eq!(
self.keys.len(),
other.keys.len(),
"invalid receiver: self.keys.len()={} != other.keys.len()={}",
self.keys.len(),
other.keys.len()
);
}
self.keys
.iter_mut()
.zip(other.keys.iter())
.for_each(|(a, b)| {
a.decompress(module, b);
});
}
}

View File

@@ -0,0 +1,207 @@
use poulpy_backend::hal::{
api::{FillUniform, Reset, VecZnxCopy, VecZnxFillUniform},
layouts::{Backend, Data, DataMut, DataRef, MatZnx, Module, ReaderFrom, WriterTo},
source::Source,
};
use crate::layouts::{
GGSWCiphertext, Infos,
compressed::{Decompress, GLWECiphertextCompressed},
};
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use std::fmt;
#[derive(PartialEq, Eq, Clone)]
pub struct GGSWCiphertextCompressed<D: Data> {
pub(crate) data: MatZnx<D>,
pub(crate) basek: usize,
pub(crate) k: usize,
pub(crate) digits: usize,
pub(crate) rank: usize,
pub(crate) seed: Vec<[u8; 32]>,
}
impl<D: DataRef> fmt::Debug for GGSWCiphertextCompressed<D> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.data)
}
}
impl<D: DataRef> fmt::Display for GGSWCiphertextCompressed<D> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"(GGSWCiphertextCompressed: basek={} k={} digits={}) {}",
self.basek, self.k, self.digits, self.data
)
}
}
impl<D: DataMut> Reset for GGSWCiphertextCompressed<D> {
fn reset(&mut self) {
self.data.reset();
self.basek = 0;
self.k = 0;
self.digits = 0;
self.rank = 0;
self.seed = Vec::new();
}
}
impl<D: DataMut> FillUniform for GGSWCiphertextCompressed<D> {
fn fill_uniform(&mut self, source: &mut Source) {
self.data.fill_uniform(source);
}
}
impl GGSWCiphertextCompressed<Vec<u8>> {
pub fn alloc(n: usize, basek: usize, k: usize, rows: usize, digits: usize, rank: usize) -> Self {
let size: usize = k.div_ceil(basek);
debug_assert!(digits > 0, "invalid ggsw: `digits` == 0");
debug_assert!(
size > digits,
"invalid ggsw: ceil(k/basek): {} <= digits: {}",
size,
digits
);
assert!(
rows * digits <= size,
"invalid ggsw: rows: {} * digits:{} > ceil(k/basek): {}",
rows,
digits,
size
);
Self {
data: MatZnx::alloc(n, rows, rank + 1, 1, k.div_ceil(basek)),
basek,
k,
digits,
rank,
seed: Vec::new(),
}
}
pub fn bytes_of(n: usize, basek: usize, k: usize, rows: usize, digits: usize, rank: usize) -> usize {
let size: usize = k.div_ceil(basek);
debug_assert!(
size > digits,
"invalid ggsw: ceil(k/basek): {} <= digits: {}",
size,
digits
);
assert!(
rows * digits <= size,
"invalid ggsw: rows: {} * digits:{} > ceil(k/basek): {}",
rows,
digits,
size
);
MatZnx::alloc_bytes(n, rows, rank + 1, 1, size)
}
}
impl<D: DataRef> GGSWCiphertextCompressed<D> {
pub fn at(&self, row: usize, col: usize) -> GLWECiphertextCompressed<&[u8]> {
GLWECiphertextCompressed {
data: self.data.at(row, col),
basek: self.basek,
k: self.k,
rank: self.rank(),
seed: self.seed[row * (self.rank() + 1) + col],
}
}
}
impl<D: DataMut> GGSWCiphertextCompressed<D> {
pub fn at_mut(&mut self, row: usize, col: usize) -> GLWECiphertextCompressed<&mut [u8]> {
let rank: usize = self.rank();
GLWECiphertextCompressed {
data: self.data.at_mut(row, col),
basek: self.basek,
k: self.k,
rank,
seed: self.seed[row * (rank + 1) + col],
}
}
}
impl<D: Data> Infos for GGSWCiphertextCompressed<D> {
type Inner = MatZnx<D>;
fn inner(&self) -> &Self::Inner {
&self.data
}
fn basek(&self) -> usize {
self.basek
}
fn k(&self) -> usize {
self.k
}
}
impl<D: Data> GGSWCiphertextCompressed<D> {
pub fn rank(&self) -> usize {
self.rank
}
pub fn digits(&self) -> usize {
self.digits
}
}
impl<D: DataMut> ReaderFrom for GGSWCiphertextCompressed<D> {
fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> {
self.k = reader.read_u64::<LittleEndian>()? as usize;
self.basek = reader.read_u64::<LittleEndian>()? as usize;
self.digits = reader.read_u64::<LittleEndian>()? as usize;
self.rank = reader.read_u64::<LittleEndian>()? as usize;
let seed_len = reader.read_u64::<LittleEndian>()? as usize;
self.seed = vec![[0u8; 32]; seed_len];
for s in &mut self.seed {
reader.read_exact(s)?;
}
self.data.read_from(reader)
}
}
impl<D: DataRef> WriterTo for GGSWCiphertextCompressed<D> {
fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
writer.write_u64::<LittleEndian>(self.k as u64)?;
writer.write_u64::<LittleEndian>(self.basek as u64)?;
writer.write_u64::<LittleEndian>(self.digits as u64)?;
writer.write_u64::<LittleEndian>(self.rank as u64)?;
writer.write_u64::<LittleEndian>(self.seed.len() as u64)?;
for s in &self.seed {
writer.write_all(s)?;
}
self.data.write_to(writer)
}
}
impl<D: DataMut, B: Backend, DR: DataRef> Decompress<B, GGSWCiphertextCompressed<DR>> for GGSWCiphertext<D> {
fn decompress(&mut self, module: &Module<B>, other: &GGSWCiphertextCompressed<DR>)
where
Module<B>: VecZnxFillUniform + VecZnxCopy,
{
#[cfg(debug_assertions)]
{
assert_eq!(self.rank(), other.rank())
}
let rows: usize = self.rows();
let rank: usize = self.rank();
(0..rows).for_each(|row_i| {
(0..rank + 1).for_each(|col_j| {
self.at_mut(row_i, col_j)
.decompress(module, &other.at(row_i, col_j));
});
});
}
}

View File

@@ -0,0 +1,177 @@
use poulpy_backend::hal::{
api::{FillUniform, Reset, VecZnxCopy, VecZnxFillUniform},
layouts::{Backend, Data, DataMut, DataRef, Module, ReaderFrom, VecZnx, WriterTo},
source::Source,
};
use crate::layouts::{GLWECiphertext, Infos, compressed::Decompress};
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use std::fmt;
#[derive(PartialEq, Eq, Clone)]
pub struct GLWECiphertextCompressed<D: Data> {
pub(crate) data: VecZnx<D>,
pub(crate) basek: usize,
pub(crate) k: usize,
pub(crate) rank: usize,
pub(crate) seed: [u8; 32],
}
impl<D: DataRef> fmt::Debug for GLWECiphertextCompressed<D> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self)
}
}
impl<D: DataRef> fmt::Display for GLWECiphertextCompressed<D> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"GLWECiphertextCompressed: basek={} k={} rank={} seed={:?}: {}",
self.basek(),
self.k(),
self.rank,
self.seed,
self.data
)
}
}
impl<D: DataMut> Reset for GLWECiphertextCompressed<D> {
fn reset(&mut self) {
self.data.reset();
self.basek = 0;
self.k = 0;
self.rank = 0;
self.seed = [0u8; 32];
}
}
impl<D: DataMut> FillUniform for GLWECiphertextCompressed<D> {
fn fill_uniform(&mut self, source: &mut Source) {
self.data.fill_uniform(source);
}
}
impl<D: Data> Infos for GLWECiphertextCompressed<D> {
type Inner = VecZnx<D>;
fn inner(&self) -> &Self::Inner {
&self.data
}
fn basek(&self) -> usize {
self.basek
}
fn k(&self) -> usize {
self.k
}
}
impl<D: Data> GLWECiphertextCompressed<D> {
pub fn rank(&self) -> usize {
self.rank
}
}
impl GLWECiphertextCompressed<Vec<u8>> {
pub fn alloc(n: usize, basek: usize, k: usize, rank: usize) -> Self {
Self {
data: VecZnx::alloc(n, 1, k.div_ceil(basek)),
basek,
k,
rank,
seed: [0u8; 32],
}
}
pub fn bytes_of(n: usize, basek: usize, k: usize) -> usize {
GLWECiphertext::bytes_of(n, basek, k, 1)
}
}
impl<D: DataMut> ReaderFrom for GLWECiphertextCompressed<D> {
fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> {
self.k = reader.read_u64::<LittleEndian>()? as usize;
self.basek = reader.read_u64::<LittleEndian>()? as usize;
self.rank = reader.read_u64::<LittleEndian>()? as usize;
reader.read_exact(&mut self.seed)?;
self.data.read_from(reader)
}
}
impl<D: DataRef> WriterTo for GLWECiphertextCompressed<D> {
fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
writer.write_u64::<LittleEndian>(self.k as u64)?;
writer.write_u64::<LittleEndian>(self.basek as u64)?;
writer.write_u64::<LittleEndian>(self.rank as u64)?;
writer.write_all(&self.seed)?;
self.data.write_to(writer)
}
}
impl<D: DataMut, B: Backend, DR: DataRef> Decompress<B, GLWECiphertextCompressed<DR>> for GLWECiphertext<D> {
fn decompress(&mut self, module: &Module<B>, other: &GLWECiphertextCompressed<DR>)
where
Module<B>: VecZnxCopy + VecZnxFillUniform,
{
#[cfg(debug_assertions)]
{
use poulpy_backend::hal::api::ZnxInfos;
assert_eq!(
self.n(),
other.data.n(),
"invalid receiver: self.n()={} != other.n()={}",
self.n(),
other.data.n()
);
assert_eq!(
self.size(),
other.size(),
"invalid receiver: self.size()={} != other.size()={}",
self.size(),
other.size()
);
assert_eq!(
self.rank(),
other.rank(),
"invalid receiver: self.rank()={} != other.rank()={}",
self.rank(),
other.rank()
);
}
let mut source: Source = Source::new(other.seed);
self.decompress_internal(module, other, &mut source);
}
}
impl<D: DataMut> GLWECiphertext<D> {
pub(crate) fn decompress_internal<DataOther, B: Backend>(
&mut self,
module: &Module<B>,
other: &GLWECiphertextCompressed<DataOther>,
source: &mut Source,
) where
DataOther: DataRef,
Module<B>: VecZnxCopy + VecZnxFillUniform,
{
#[cfg(debug_assertions)]
{
assert_eq!(self.rank(), other.rank())
}
let k: usize = other.k;
let basek: usize = other.basek;
let cols: usize = other.rank() + 1;
module.vec_znx_copy(&mut self.data, 0, &other.data, 0);
(1..cols).for_each(|i| {
module.vec_znx_fill_uniform(basek, &mut self.data, i, k, source);
});
self.basek = basek;
self.k = k;
}
}

View File

@@ -0,0 +1,117 @@
use std::fmt;
use poulpy_backend::hal::{
api::{FillUniform, Reset},
api::{
SvpApplyInplace, SvpPPolAlloc, SvpPPolAllocBytes, SvpPrepare, VecZnxAddInplace, VecZnxAddNormal, VecZnxBigNormalize,
VecZnxDftAllocBytes, VecZnxDftFromVecZnx, VecZnxDftToVecZnxBigConsume, VecZnxFillUniform, VecZnxNormalize,
VecZnxNormalizeInplace, VecZnxNormalizeTmpBytes, VecZnxSub, VecZnxSubABInplace,
},
layouts::{Backend, Data, DataMut, DataRef, MatZnx, Module, ReaderFrom, WriterTo},
source::Source,
};
use crate::layouts::{GLWEToLWESwitchingKey, Infos, compressed::GGLWESwitchingKeyCompressed};
#[derive(PartialEq, Eq, Clone)]
pub struct GLWEToLWESwitchingKeyCompressed<D: Data>(pub(crate) GGLWESwitchingKeyCompressed<D>);
impl<D: DataRef> fmt::Debug for GLWEToLWESwitchingKeyCompressed<D> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self)
}
}
impl<D: DataMut> FillUniform for GLWEToLWESwitchingKeyCompressed<D> {
fn fill_uniform(&mut self, source: &mut Source) {
self.0.fill_uniform(source);
}
}
impl<D: DataMut> Reset for GLWEToLWESwitchingKeyCompressed<D> {
fn reset(&mut self) {
self.0.reset();
}
}
impl<D: DataRef> fmt::Display for GLWEToLWESwitchingKeyCompressed<D> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "(GLWEToLWESwitchingKeyCompressed) {}", self.0)
}
}
impl<D: Data> Infos for GLWEToLWESwitchingKeyCompressed<D> {
type Inner = MatZnx<D>;
fn inner(&self) -> &Self::Inner {
self.0.inner()
}
fn basek(&self) -> usize {
self.0.basek()
}
fn k(&self) -> usize {
self.0.k()
}
}
impl<D: Data> GLWEToLWESwitchingKeyCompressed<D> {
pub fn digits(&self) -> usize {
self.0.digits()
}
pub fn rank(&self) -> usize {
self.0.rank()
}
pub fn rank_in(&self) -> usize {
self.0.rank_in()
}
pub fn rank_out(&self) -> usize {
self.0.rank_out()
}
}
impl<D: DataMut> ReaderFrom for GLWEToLWESwitchingKeyCompressed<D> {
fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> {
self.0.read_from(reader)
}
}
impl<D: DataRef> WriterTo for GLWEToLWESwitchingKeyCompressed<D> {
fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
self.0.write_to(writer)
}
}
impl GLWEToLWESwitchingKeyCompressed<Vec<u8>> {
pub fn alloc(n: usize, basek: usize, k: usize, rows: usize, rank_in: usize) -> Self {
Self(GGLWESwitchingKeyCompressed::alloc(
n, basek, k, rows, 1, rank_in, 1,
))
}
pub fn encrypt_sk_scratch_space<B: Backend>(module: &Module<B>, n: usize, basek: usize, k: usize, rank_in: usize) -> usize
where
Module<B>: VecZnxDftAllocBytes
+ VecZnxBigNormalize<B>
+ VecZnxDftFromVecZnx<B>
+ SvpApplyInplace<B>
+ VecZnxDftToVecZnxBigConsume<B>
+ VecZnxNormalizeTmpBytes
+ VecZnxFillUniform
+ VecZnxSubABInplace
+ VecZnxAddInplace
+ VecZnxNormalizeInplace<B>
+ VecZnxAddNormal
+ VecZnxNormalize<B>
+ VecZnxSub
+ SvpPrepare<B>
+ SvpPPolAllocBytes
+ SvpPPolAlloc<B>,
{
GLWEToLWESwitchingKey::encrypt_sk_scratch_space(module, n, basek, k, rank_in)
}
}

View File

@@ -0,0 +1,131 @@
use std::fmt;
use poulpy_backend::hal::{
api::{FillUniform, Reset, VecZnxFillUniform, ZnxInfos, ZnxView, ZnxViewMut},
layouts::{Backend, Data, DataMut, DataRef, Module, ReaderFrom, VecZnx, WriterTo},
source::Source,
};
use crate::layouts::{Infos, LWECiphertext, SetMetaData, compressed::Decompress};
#[derive(PartialEq, Eq, Clone)]
pub struct LWECiphertextCompressed<D: Data> {
pub(crate) data: VecZnx<D>,
pub(crate) k: usize,
pub(crate) basek: usize,
pub(crate) seed: [u8; 32],
}
impl<D: DataRef> fmt::Debug for LWECiphertextCompressed<D> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self)
}
}
impl<D: DataRef> fmt::Display for LWECiphertextCompressed<D> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"LWECiphertextCompressed: basek={} k={} seed={:?}: {}",
self.basek(),
self.k(),
self.seed,
self.data
)
}
}
impl<D: DataMut> Reset for LWECiphertextCompressed<D>
where
VecZnx<D>: Reset,
{
fn reset(&mut self) {
self.data.reset();
self.basek = 0;
self.k = 0;
self.seed = [0u8; 32];
}
}
impl<D: DataMut> FillUniform for LWECiphertextCompressed<D> {
fn fill_uniform(&mut self, source: &mut Source) {
self.data.fill_uniform(source);
}
}
impl LWECiphertextCompressed<Vec<u8>> {
pub fn alloc(basek: usize, k: usize) -> Self {
Self {
data: VecZnx::alloc(1, 1, k.div_ceil(basek)),
k,
basek,
seed: [0u8; 32],
}
}
}
impl<D: Data> Infos for LWECiphertextCompressed<D>
where
VecZnx<D>: ZnxInfos,
{
type Inner = VecZnx<D>;
fn n(&self) -> usize {
&self.inner().n() - 1
}
fn inner(&self) -> &Self::Inner {
&self.data
}
fn basek(&self) -> usize {
self.basek
}
fn k(&self) -> usize {
self.k
}
}
impl<DataSelf: DataMut> SetMetaData for LWECiphertextCompressed<DataSelf> {
fn set_k(&mut self, k: usize) {
self.k = k
}
fn set_basek(&mut self, basek: usize) {
self.basek = basek
}
}
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
impl<D: DataMut> ReaderFrom for LWECiphertextCompressed<D> {
fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> {
self.k = reader.read_u64::<LittleEndian>()? as usize;
self.basek = reader.read_u64::<LittleEndian>()? as usize;
reader.read_exact(&mut self.seed)?;
self.data.read_from(reader)
}
}
impl<D: DataRef> WriterTo for LWECiphertextCompressed<D> {
fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
writer.write_u64::<LittleEndian>(self.k as u64)?;
writer.write_u64::<LittleEndian>(self.basek as u64)?;
writer.write_all(&self.seed)?;
self.data.write_to(writer)
}
}
impl<D: DataMut, B: Backend, DR: DataRef> Decompress<B, LWECiphertextCompressed<DR>> for LWECiphertext<D> {
fn decompress(&mut self, module: &Module<B>, other: &LWECiphertextCompressed<DR>)
where
Module<B>: VecZnxFillUniform,
{
let mut source = Source::new(other.seed);
module.vec_znx_fill_uniform(other.basek(), &mut self.data, 0, other.k(), &mut source);
(0..self.size()).for_each(|i| {
self.data.at_mut(0, i)[0] = other.data.at(0, i)[0];
});
}
}

View File

@@ -0,0 +1,127 @@
use poulpy_backend::hal::{
api::{
FillUniform, Reset, SvpApplyInplace, SvpPPolAlloc, SvpPPolAllocBytes, SvpPrepare, VecZnxAddInplace, VecZnxAddNormal,
VecZnxBigNormalize, VecZnxCopy, VecZnxDftAllocBytes, VecZnxDftFromVecZnx, VecZnxDftToVecZnxBigConsume, VecZnxFillUniform,
VecZnxNormalize, VecZnxNormalizeInplace, VecZnxNormalizeTmpBytes, VecZnxSub, VecZnxSubABInplace,
},
layouts::{Backend, Data, DataMut, DataRef, MatZnx, Module, ReaderFrom, WriterTo},
source::Source,
};
use crate::layouts::{
Infos, LWESwitchingKey,
compressed::{Decompress, GGLWESwitchingKeyCompressed},
};
use std::fmt;
#[derive(PartialEq, Eq, Clone)]
pub struct LWESwitchingKeyCompressed<D: Data>(pub(crate) GGLWESwitchingKeyCompressed<D>);
impl<D: DataRef> fmt::Debug for LWESwitchingKeyCompressed<D> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self)
}
}
impl<D: DataMut> FillUniform for LWESwitchingKeyCompressed<D> {
fn fill_uniform(&mut self, source: &mut Source) {
self.0.fill_uniform(source);
}
}
impl<D: DataMut> Reset for LWESwitchingKeyCompressed<D> {
fn reset(&mut self) {
self.0.reset();
}
}
impl<D: DataRef> fmt::Display for LWESwitchingKeyCompressed<D> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "(LWESwitchingKeyCompressed) {}", self.0)
}
}
impl<D: Data> Infos for LWESwitchingKeyCompressed<D> {
type Inner = MatZnx<D>;
fn inner(&self) -> &Self::Inner {
self.0.inner()
}
fn basek(&self) -> usize {
self.0.basek()
}
fn k(&self) -> usize {
self.0.k()
}
}
impl<D: Data> LWESwitchingKeyCompressed<D> {
pub fn digits(&self) -> usize {
self.0.digits()
}
pub fn rank(&self) -> usize {
self.0.rank()
}
pub fn rank_in(&self) -> usize {
self.0.rank_in()
}
pub fn rank_out(&self) -> usize {
self.0.rank_out()
}
}
impl<D: DataMut> ReaderFrom for LWESwitchingKeyCompressed<D> {
fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> {
self.0.read_from(reader)
}
}
impl<D: DataRef> WriterTo for LWESwitchingKeyCompressed<D> {
fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
self.0.write_to(writer)
}
}
impl LWESwitchingKeyCompressed<Vec<u8>> {
pub fn alloc(n: usize, basek: usize, k: usize, rows: usize) -> Self {
Self(GGLWESwitchingKeyCompressed::alloc(
n, basek, k, rows, 1, 1, 1,
))
}
pub fn encrypt_sk_scratch_space<B: Backend>(module: &Module<B>, n: usize, basek: usize, k: usize) -> usize
where
Module<B>: VecZnxDftAllocBytes
+ VecZnxBigNormalize<B>
+ VecZnxDftFromVecZnx<B>
+ SvpApplyInplace<B>
+ VecZnxDftToVecZnxBigConsume<B>
+ VecZnxNormalizeTmpBytes
+ VecZnxFillUniform
+ VecZnxSubABInplace
+ VecZnxAddInplace
+ VecZnxNormalizeInplace<B>
+ VecZnxAddNormal
+ VecZnxNormalize<B>
+ VecZnxSub
+ SvpPrepare<B>
+ SvpPPolAllocBytes
+ SvpPPolAlloc<B>,
{
LWESwitchingKey::encrypt_sk_scratch_space(module, n, basek, k)
}
}
impl<D: DataMut, DR: DataRef, B: Backend> Decompress<B, LWESwitchingKeyCompressed<DR>> for LWESwitchingKey<D> {
fn decompress(&mut self, module: &Module<B>, other: &LWESwitchingKeyCompressed<DR>)
where
Module<B>: VecZnxCopy + VecZnxFillUniform,
{
self.0.decompress(module, &other.0);
}
}

View File

@@ -0,0 +1,128 @@
use poulpy_backend::hal::{
api::{FillUniform, Reset},
api::{
SvpApplyInplace, SvpPPolAlloc, SvpPPolAllocBytes, SvpPrepare, VecZnxAddInplace, VecZnxAddNormal, VecZnxBigNormalize,
VecZnxCopy, VecZnxDftAllocBytes, VecZnxDftFromVecZnx, VecZnxDftToVecZnxBigConsume, VecZnxFillUniform, VecZnxNormalize,
VecZnxNormalizeInplace, VecZnxNormalizeTmpBytes, VecZnxSub, VecZnxSubABInplace,
},
layouts::{Backend, Data, DataMut, DataRef, MatZnx, Module, ReaderFrom, WriterTo},
source::Source,
};
use crate::layouts::{
Infos, LWEToGLWESwitchingKey,
compressed::{Decompress, GGLWESwitchingKeyCompressed},
};
use std::fmt;
#[derive(PartialEq, Eq, Clone)]
pub struct LWEToGLWESwitchingKeyCompressed<D: Data>(pub(crate) GGLWESwitchingKeyCompressed<D>);
impl<D: DataRef> fmt::Debug for LWEToGLWESwitchingKeyCompressed<D> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self)
}
}
impl<D: DataMut> FillUniform for LWEToGLWESwitchingKeyCompressed<D> {
fn fill_uniform(&mut self, source: &mut Source) {
self.0.fill_uniform(source);
}
}
impl<D: DataMut> Reset for LWEToGLWESwitchingKeyCompressed<D> {
fn reset(&mut self) {
self.0.reset();
}
}
impl<D: DataRef> fmt::Display for LWEToGLWESwitchingKeyCompressed<D> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "(LWEToGLWESwitchingKeyCompressed) {}", self.0)
}
}
impl<D: Data> Infos for LWEToGLWESwitchingKeyCompressed<D> {
type Inner = MatZnx<D>;
fn inner(&self) -> &Self::Inner {
self.0.inner()
}
fn basek(&self) -> usize {
self.0.basek()
}
fn k(&self) -> usize {
self.0.k()
}
}
impl<D: Data> LWEToGLWESwitchingKeyCompressed<D> {
pub fn digits(&self) -> usize {
self.0.digits()
}
pub fn rank(&self) -> usize {
self.0.rank()
}
pub fn rank_in(&self) -> usize {
self.0.rank_in()
}
pub fn rank_out(&self) -> usize {
self.0.rank_out()
}
}
impl<D: DataMut> ReaderFrom for LWEToGLWESwitchingKeyCompressed<D> {
fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> {
self.0.read_from(reader)
}
}
impl<D: DataRef> WriterTo for LWEToGLWESwitchingKeyCompressed<D> {
fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
self.0.write_to(writer)
}
}
impl LWEToGLWESwitchingKeyCompressed<Vec<u8>> {
pub fn alloc(n: usize, basek: usize, k: usize, rows: usize, rank_out: usize) -> Self {
Self(GGLWESwitchingKeyCompressed::alloc(
n, basek, k, rows, 1, 1, rank_out,
))
}
pub fn encrypt_sk_scratch_space<B: Backend>(module: &Module<B>, n: usize, basek: usize, k: usize, rank_out: usize) -> usize
where
Module<B>: VecZnxDftAllocBytes
+ VecZnxBigNormalize<B>
+ VecZnxDftFromVecZnx<B>
+ SvpApplyInplace<B>
+ VecZnxDftToVecZnxBigConsume<B>
+ VecZnxNormalizeTmpBytes
+ VecZnxFillUniform
+ VecZnxSubABInplace
+ VecZnxAddInplace
+ VecZnxNormalizeInplace<B>
+ VecZnxAddNormal
+ VecZnxNormalize<B>
+ VecZnxSub
+ SvpPrepare<B>
+ SvpPPolAllocBytes
+ SvpPPolAlloc<B>,
{
LWEToGLWESwitchingKey::encrypt_sk_scratch_space(module, n, basek, k, rank_out)
}
}
impl<D: DataMut, DR: DataRef, B: Backend> Decompress<B, LWEToGLWESwitchingKeyCompressed<DR>> for LWEToGLWESwitchingKey<D> {
fn decompress(&mut self, module: &Module<B>, other: &LWEToGLWESwitchingKeyCompressed<DR>)
where
Module<B>: VecZnxCopy + VecZnxFillUniform,
{
self.0.decompress(module, &other.0);
}
}

View File

@@ -0,0 +1,32 @@
mod gglwe_atk;
mod gglwe_ct;
mod gglwe_ksk;
mod gglwe_tsk;
mod ggsw_ct;
mod glwe_ct;
mod glwe_to_lwe_ksk;
mod lwe_ct;
mod lwe_ksk;
mod lwe_to_glwe_ksk;
pub use gglwe_atk::*;
pub use gglwe_ct::*;
pub use gglwe_ksk::*;
pub use gglwe_tsk::*;
pub use ggsw_ct::*;
pub use glwe_ct::*;
pub use glwe_to_lwe_ksk::*;
pub use lwe_ct::*;
pub use lwe_ksk::*;
pub use lwe_to_glwe_ksk::*;
use poulpy_backend::hal::{
api::{VecZnxCopy, VecZnxFillUniform},
layouts::{Backend, Module},
};
pub trait Decompress<B: Backend, C> {
fn decompress(&mut self, module: &Module<B>, other: &C)
where
Module<B>: VecZnxFillUniform + VecZnxCopy;
}

View File

@@ -0,0 +1,121 @@
use poulpy_backend::hal::{
api::{FillUniform, Reset},
layouts::{Data, DataMut, DataRef, MatZnx, ReaderFrom, WriterTo},
source::Source,
};
use crate::layouts::{GGLWESwitchingKey, GLWECiphertext, Infos};
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use std::fmt;
#[derive(PartialEq, Eq, Clone)]
pub struct GGLWEAutomorphismKey<D: Data> {
pub(crate) key: GGLWESwitchingKey<D>,
pub(crate) p: i64,
}
impl<D: DataRef> fmt::Debug for GGLWEAutomorphismKey<D> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self)
}
}
impl<D: DataMut> FillUniform for GGLWEAutomorphismKey<D> {
fn fill_uniform(&mut self, source: &mut Source) {
self.key.fill_uniform(source);
}
}
impl<D: DataMut> Reset for GGLWEAutomorphismKey<D>
where
MatZnx<D>: Reset,
{
fn reset(&mut self) {
self.key.reset();
self.p = 0;
}
}
impl<D: DataRef> fmt::Display for GGLWEAutomorphismKey<D> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "(AutomorphismKey: p={}) {}", self.p, self.key)
}
}
impl GGLWEAutomorphismKey<Vec<u8>> {
pub fn alloc(n: usize, basek: usize, k: usize, rows: usize, digits: usize, rank: usize) -> Self {
GGLWEAutomorphismKey {
key: GGLWESwitchingKey::alloc(n, basek, k, rows, digits, rank, rank),
p: 0,
}
}
pub fn bytes_of(n: usize, basek: usize, k: usize, rows: usize, digits: usize, rank: usize) -> usize {
GGLWESwitchingKey::bytes_of(n, basek, k, rows, digits, rank, rank)
}
}
impl<D: Data> Infos for GGLWEAutomorphismKey<D> {
type Inner = MatZnx<D>;
fn inner(&self) -> &Self::Inner {
self.key.inner()
}
fn basek(&self) -> usize {
self.key.basek()
}
fn k(&self) -> usize {
self.key.k()
}
}
impl<D: Data> GGLWEAutomorphismKey<D> {
pub fn p(&self) -> i64 {
self.p
}
pub fn digits(&self) -> usize {
self.key.digits()
}
pub fn rank(&self) -> usize {
self.key.rank()
}
pub fn rank_in(&self) -> usize {
self.key.rank_in()
}
pub fn rank_out(&self) -> usize {
self.key.rank_out()
}
}
impl<D: DataRef> GGLWEAutomorphismKey<D> {
pub fn at(&self, row: usize, col: usize) -> GLWECiphertext<&[u8]> {
self.key.at(row, col)
}
}
impl<D: DataMut> GGLWEAutomorphismKey<D> {
pub fn at_mut(&mut self, row: usize, col: usize) -> GLWECiphertext<&mut [u8]> {
self.key.at_mut(row, col)
}
}
impl<D: DataMut> ReaderFrom for GGLWEAutomorphismKey<D> {
fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> {
self.p = reader.read_u64::<LittleEndian>()? as i64;
self.key.read_from(reader)
}
}
impl<D: DataRef> WriterTo for GGLWEAutomorphismKey<D> {
fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
writer.write_u64::<LittleEndian>(self.p as u64)?;
self.key.write_to(writer)
}
}

View File

@@ -0,0 +1,168 @@
use poulpy_backend::hal::{
api::{FillUniform, Reset},
layouts::{Data, DataMut, DataRef, MatZnx, ReaderFrom, WriterTo},
source::Source,
};
use crate::layouts::{GLWECiphertext, Infos};
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use std::fmt;
#[derive(PartialEq, Eq, Clone)]
pub struct GGLWECiphertext<D: Data> {
pub(crate) data: MatZnx<D>,
pub(crate) basek: usize,
pub(crate) k: usize,
pub(crate) digits: usize,
}
impl<D: DataRef> fmt::Debug for GGLWECiphertext<D> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self)
}
}
impl<D: DataMut> FillUniform for GGLWECiphertext<D> {
fn fill_uniform(&mut self, source: &mut Source) {
self.data.fill_uniform(source);
}
}
impl<D: DataMut> Reset for GGLWECiphertext<D> {
fn reset(&mut self) {
self.data.reset();
self.basek = 0;
self.k = 0;
self.digits = 0;
}
}
impl<D: DataRef> fmt::Display for GGLWECiphertext<D> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"(GGLWECiphertext: basek={} k={} digits={}) {}",
self.basek, self.k, self.digits, self.data
)
}
}
impl<D: DataRef> GGLWECiphertext<D> {
pub fn at(&self, row: usize, col: usize) -> GLWECiphertext<&[u8]> {
GLWECiphertext {
data: self.data.at(row, col),
basek: self.basek,
k: self.k,
}
}
}
impl<D: DataMut> GGLWECiphertext<D> {
pub fn at_mut(&mut self, row: usize, col: usize) -> GLWECiphertext<&mut [u8]> {
GLWECiphertext {
data: self.data.at_mut(row, col),
basek: self.basek,
k: self.k,
}
}
}
impl GGLWECiphertext<Vec<u8>> {
pub fn alloc(n: usize, basek: usize, k: usize, rows: usize, digits: usize, rank_in: usize, rank_out: usize) -> Self {
let size: usize = k.div_ceil(basek);
debug_assert!(
size > digits,
"invalid gglwe: ceil(k/basek): {} <= digits: {}",
size,
digits
);
assert!(
rows * digits <= size,
"invalid gglwe: rows: {} * digits:{} > ceil(k/basek): {}",
rows,
digits,
size
);
Self {
data: MatZnx::alloc(n, rows, rank_in, rank_out + 1, size),
basek,
k,
digits,
}
}
pub fn bytes_of(n: usize, basek: usize, k: usize, rows: usize, digits: usize, rank_in: usize, rank_out: usize) -> usize {
let size: usize = k.div_ceil(basek);
debug_assert!(
size > digits,
"invalid gglwe: ceil(k/basek): {} <= digits: {}",
size,
digits
);
assert!(
rows * digits <= size,
"invalid gglwe: rows: {} * digits:{} > ceil(k/basek): {}",
rows,
digits,
size
);
MatZnx::alloc_bytes(n, rows, rank_in, rank_out + 1, rows)
}
}
impl<D: Data> Infos for GGLWECiphertext<D> {
type Inner = MatZnx<D>;
fn inner(&self) -> &Self::Inner {
&self.data
}
fn basek(&self) -> usize {
self.basek
}
fn k(&self) -> usize {
self.k
}
}
impl<D: Data> GGLWECiphertext<D> {
pub fn rank(&self) -> usize {
self.data.cols_out() - 1
}
pub fn digits(&self) -> usize {
self.digits
}
pub fn rank_in(&self) -> usize {
self.data.cols_in()
}
pub fn rank_out(&self) -> usize {
self.data.cols_out() - 1
}
}
impl<D: DataMut> ReaderFrom for GGLWECiphertext<D> {
fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> {
self.k = reader.read_u64::<LittleEndian>()? as usize;
self.basek = reader.read_u64::<LittleEndian>()? as usize;
self.digits = reader.read_u64::<LittleEndian>()? as usize;
self.data.read_from(reader)
}
}
impl<D: DataRef> WriterTo for GGLWECiphertext<D> {
fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
writer.write_u64::<LittleEndian>(self.k as u64)?;
writer.write_u64::<LittleEndian>(self.basek as u64)?;
writer.write_u64::<LittleEndian>(self.digits as u64)?;
self.data.write_to(writer)
}
}

View File

@@ -0,0 +1,134 @@
use poulpy_backend::hal::{
api::{FillUniform, Reset},
layouts::{Data, DataMut, DataRef, MatZnx, ReaderFrom, WriterTo},
source::Source,
};
use crate::layouts::{GGLWECiphertext, GLWECiphertext, Infos};
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use std::fmt;
#[derive(PartialEq, Eq, Clone)]
pub struct GGLWESwitchingKey<D: Data> {
pub(crate) key: GGLWECiphertext<D>,
pub(crate) sk_in_n: usize, // Degree of sk_in
pub(crate) sk_out_n: usize, // Degree of sk_out
}
impl<D: DataRef> fmt::Debug for GGLWESwitchingKey<D> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self)
}
}
impl<D: DataRef> fmt::Display for GGLWESwitchingKey<D> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"(GLWESwitchingKey: sk_in_n={} sk_out_n={}) {}",
self.sk_in_n, self.sk_out_n, self.key.data
)
}
}
impl<D: DataMut> FillUniform for GGLWESwitchingKey<D> {
fn fill_uniform(&mut self, source: &mut Source) {
self.key.fill_uniform(source);
}
}
impl<D: DataMut> Reset for GGLWESwitchingKey<D>
where
MatZnx<D>: Reset,
{
fn reset(&mut self) {
self.key.reset();
self.sk_in_n = 0;
self.sk_out_n = 0;
}
}
impl GGLWESwitchingKey<Vec<u8>> {
pub fn alloc(n: usize, basek: usize, k: usize, rows: usize, digits: usize, rank_in: usize, rank_out: usize) -> Self {
GGLWESwitchingKey {
key: GGLWECiphertext::alloc(n, basek, k, rows, digits, rank_in, rank_out),
sk_in_n: 0,
sk_out_n: 0,
}
}
pub fn bytes_of(n: usize, basek: usize, k: usize, rows: usize, digits: usize, rank_in: usize, rank_out: usize) -> usize {
GGLWECiphertext::<Vec<u8>>::bytes_of(n, basek, k, rows, digits, rank_in, rank_out)
}
}
impl<D: Data> Infos for GGLWESwitchingKey<D> {
type Inner = MatZnx<D>;
fn inner(&self) -> &Self::Inner {
self.key.inner()
}
fn basek(&self) -> usize {
self.key.basek()
}
fn k(&self) -> usize {
self.key.k()
}
}
impl<D: Data> GGLWESwitchingKey<D> {
pub fn rank(&self) -> usize {
self.key.data.cols_out() - 1
}
pub fn rank_in(&self) -> usize {
self.key.data.cols_in()
}
pub fn rank_out(&self) -> usize {
self.key.data.cols_out() - 1
}
pub fn digits(&self) -> usize {
self.key.digits()
}
pub fn sk_degree_in(&self) -> usize {
self.sk_in_n
}
pub fn sk_degree_out(&self) -> usize {
self.sk_out_n
}
}
impl<D: DataRef> GGLWESwitchingKey<D> {
pub fn at(&self, row: usize, col: usize) -> GLWECiphertext<&[u8]> {
self.key.at(row, col)
}
}
impl<D: DataMut> GGLWESwitchingKey<D> {
pub fn at_mut(&mut self, row: usize, col: usize) -> GLWECiphertext<&mut [u8]> {
self.key.at_mut(row, col)
}
}
impl<D: DataMut> ReaderFrom for GGLWESwitchingKey<D> {
fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> {
self.sk_in_n = reader.read_u64::<LittleEndian>()? as usize;
self.sk_out_n = reader.read_u64::<LittleEndian>()? as usize;
self.key.read_from(reader)
}
}
impl<D: DataRef> WriterTo for GGLWESwitchingKey<D> {
fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
writer.write_u64::<LittleEndian>(self.sk_in_n as u64)?;
writer.write_u64::<LittleEndian>(self.sk_out_n as u64)?;
self.key.write_to(writer)
}
}

View File

@@ -0,0 +1,148 @@
use poulpy_backend::hal::{
api::{FillUniform, Reset},
layouts::{Data, DataMut, DataRef, MatZnx, ReaderFrom, WriterTo},
source::Source,
};
use crate::layouts::{GGLWESwitchingKey, Infos};
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use std::fmt;
#[derive(PartialEq, Eq, Clone)]
pub struct GGLWETensorKey<D: Data> {
pub(crate) keys: Vec<GGLWESwitchingKey<D>>,
}
impl<D: DataRef> fmt::Debug for GGLWETensorKey<D> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self)
}
}
impl<D: DataMut> FillUniform for GGLWETensorKey<D> {
fn fill_uniform(&mut self, source: &mut Source) {
self.keys
.iter_mut()
.for_each(|key: &mut GGLWESwitchingKey<D>| key.fill_uniform(source))
}
}
impl<D: DataMut> Reset for GGLWETensorKey<D>
where
MatZnx<D>: Reset,
{
fn reset(&mut self) {
self.keys
.iter_mut()
.for_each(|key: &mut GGLWESwitchingKey<D>| key.reset())
}
}
impl<D: DataRef> fmt::Display for GGLWETensorKey<D> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
writeln!(f, "(GLWETensorKey)",)?;
for (i, key) in self.keys.iter().enumerate() {
write!(f, "{}: {}", i, key)?;
}
Ok(())
}
}
impl GGLWETensorKey<Vec<u8>> {
pub fn alloc(n: usize, basek: usize, k: usize, rows: usize, digits: usize, rank: usize) -> Self {
let mut keys: Vec<GGLWESwitchingKey<Vec<u8>>> = Vec::new();
let pairs: usize = (((rank + 1) * rank) >> 1).max(1);
(0..pairs).for_each(|_| {
keys.push(GGLWESwitchingKey::alloc(n, basek, k, rows, digits, 1, rank));
});
Self { keys }
}
pub fn bytes_of(n: usize, basek: usize, k: usize, rows: usize, digits: usize, rank: usize) -> usize {
let pairs: usize = (((rank + 1) * rank) >> 1).max(1);
pairs * GGLWESwitchingKey::<Vec<u8>>::bytes_of(n, basek, k, rows, digits, 1, rank)
}
}
impl<D: Data> Infos for GGLWETensorKey<D> {
type Inner = MatZnx<D>;
fn inner(&self) -> &Self::Inner {
self.keys[0].inner()
}
fn basek(&self) -> usize {
self.keys[0].basek()
}
fn k(&self) -> usize {
self.keys[0].k()
}
}
impl<D: Data> GGLWETensorKey<D> {
pub fn rank(&self) -> usize {
self.keys[0].rank()
}
pub fn rank_in(&self) -> usize {
self.keys[0].rank_in()
}
pub fn rank_out(&self) -> usize {
self.keys[0].rank_out()
}
pub fn digits(&self) -> usize {
self.keys[0].digits()
}
}
impl<D: DataMut> GGLWETensorKey<D> {
// Returns a mutable reference to GLWESwitchingKey_{s}(s[i] * s[j])
pub fn at_mut(&mut self, mut i: usize, mut j: usize) -> &mut GGLWESwitchingKey<D> {
if i > j {
std::mem::swap(&mut i, &mut j);
};
let rank: usize = self.rank();
&mut self.keys[i * rank + j - (i * (i + 1) / 2)]
}
}
impl<D: DataRef> GGLWETensorKey<D> {
// Returns a reference to GLWESwitchingKey_{s}(s[i] * s[j])
pub fn at(&self, mut i: usize, mut j: usize) -> &GGLWESwitchingKey<D> {
if i > j {
std::mem::swap(&mut i, &mut j);
};
let rank: usize = self.rank();
&self.keys[i * rank + j - (i * (i + 1) / 2)]
}
}
impl<D: DataMut> ReaderFrom for GGLWETensorKey<D> {
fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> {
let len: usize = reader.read_u64::<LittleEndian>()? as usize;
if self.keys.len() != len {
return Err(std::io::Error::new(
std::io::ErrorKind::InvalidData,
format!("self.keys.len()={} != read len={}", self.keys.len(), len),
));
}
for key in &mut self.keys {
key.read_from(reader)?;
}
Ok(())
}
}
impl<D: DataRef> WriterTo for GGLWETensorKey<D> {
fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
writer.write_u64::<LittleEndian>(self.keys.len() as u64)?;
for key in &self.keys {
key.write_to(writer)?;
}
Ok(())
}
}

View File

@@ -0,0 +1,162 @@
use poulpy_backend::hal::{
api::{FillUniform, Reset},
layouts::{Data, DataMut, DataRef, MatZnx, ReaderFrom, WriterTo},
source::Source,
};
use std::fmt;
use crate::layouts::{GLWECiphertext, Infos};
#[derive(PartialEq, Eq, Clone)]
pub struct GGSWCiphertext<D: Data> {
pub(crate) data: MatZnx<D>,
pub(crate) basek: usize,
pub(crate) k: usize,
pub(crate) digits: usize,
}
impl<D: DataRef> fmt::Debug for GGSWCiphertext<D> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.data)
}
}
impl<D: DataRef> fmt::Display for GGSWCiphertext<D> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"(GGSWCiphertext: basek={} k={} digits={}) {}",
self.basek, self.k, self.digits, self.data
)
}
}
impl<D: DataMut> Reset for GGSWCiphertext<D> {
fn reset(&mut self) {
self.data.reset();
self.basek = 0;
self.k = 0;
self.digits = 0;
}
}
impl<D: DataMut> FillUniform for GGSWCiphertext<D> {
fn fill_uniform(&mut self, source: &mut Source) {
self.data.fill_uniform(source);
}
}
impl<D: DataRef> GGSWCiphertext<D> {
pub fn at(&self, row: usize, col: usize) -> GLWECiphertext<&[u8]> {
GLWECiphertext {
data: self.data.at(row, col),
basek: self.basek,
k: self.k,
}
}
}
impl<D: DataMut> GGSWCiphertext<D> {
pub fn at_mut(&mut self, row: usize, col: usize) -> GLWECiphertext<&mut [u8]> {
GLWECiphertext {
data: self.data.at_mut(row, col),
basek: self.basek,
k: self.k,
}
}
}
impl GGSWCiphertext<Vec<u8>> {
pub fn alloc(n: usize, basek: usize, k: usize, rows: usize, digits: usize, rank: usize) -> Self {
let size: usize = k.div_ceil(basek);
debug_assert!(digits > 0, "invalid ggsw: `digits` == 0");
debug_assert!(
size > digits,
"invalid ggsw: ceil(k/basek): {} <= digits: {}",
size,
digits
);
assert!(
rows * digits <= size,
"invalid ggsw: rows: {} * digits:{} > ceil(k/basek): {}",
rows,
digits,
size
);
Self {
data: MatZnx::alloc(n, rows, rank + 1, rank + 1, k.div_ceil(basek)),
basek,
k,
digits,
}
}
pub fn bytes_of(n: usize, basek: usize, k: usize, rows: usize, digits: usize, rank: usize) -> usize {
let size: usize = k.div_ceil(basek);
debug_assert!(
size > digits,
"invalid ggsw: ceil(k/basek): {} <= digits: {}",
size,
digits
);
assert!(
rows * digits <= size,
"invalid ggsw: rows: {} * digits:{} > ceil(k/basek): {}",
rows,
digits,
size
);
MatZnx::alloc_bytes(n, rows, rank + 1, rank + 1, size)
}
}
impl<D: Data> Infos for GGSWCiphertext<D> {
type Inner = MatZnx<D>;
fn inner(&self) -> &Self::Inner {
&self.data
}
fn basek(&self) -> usize {
self.basek
}
fn k(&self) -> usize {
self.k
}
}
impl<D: Data> GGSWCiphertext<D> {
pub fn rank(&self) -> usize {
self.data.cols_out() - 1
}
pub fn digits(&self) -> usize {
self.digits
}
}
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
impl<D: DataMut> ReaderFrom for GGSWCiphertext<D> {
fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> {
self.k = reader.read_u64::<LittleEndian>()? as usize;
self.basek = reader.read_u64::<LittleEndian>()? as usize;
self.digits = reader.read_u64::<LittleEndian>()? as usize;
self.data.read_from(reader)
}
}
impl<D: DataRef> WriterTo for GGSWCiphertext<D> {
fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
writer.write_u64::<LittleEndian>(self.k as u64)?;
writer.write_u64::<LittleEndian>(self.basek as u64)?;
writer.write_u64::<LittleEndian>(self.digits as u64)?;
self.data.write_to(writer)
}
}

View File

@@ -0,0 +1,152 @@
use poulpy_backend::hal::{
api::{FillUniform, Reset},
layouts::{Data, DataMut, DataRef, ReaderFrom, ToOwnedDeep, VecZnx, VecZnxToMut, VecZnxToRef, WriterTo},
source::Source,
};
use crate::layouts::{Infos, SetMetaData};
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use std::fmt;
#[derive(PartialEq, Eq, Clone)]
pub struct GLWECiphertext<D: Data> {
pub data: VecZnx<D>,
pub basek: usize,
pub k: usize,
}
impl<D: DataRef> ToOwnedDeep for GLWECiphertext<D> {
type Owned = GLWECiphertext<Vec<u8>>;
fn to_owned_deep(&self) -> Self::Owned {
GLWECiphertext {
data: self.data.to_owned_deep(),
basek: self.basek,
k: self.k,
}
}
}
impl<D: DataRef> fmt::Debug for GLWECiphertext<D> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self)
}
}
impl<D: DataRef> fmt::Display for GLWECiphertext<D> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"GLWECiphertext: basek={} k={}: {}",
self.basek(),
self.k(),
self.data
)
}
}
impl<D: DataMut> Reset for GLWECiphertext<D>
where
VecZnx<D>: Reset,
{
fn reset(&mut self) {
self.data.reset();
self.basek = 0;
self.k = 0;
}
}
impl<D: DataMut> FillUniform for GLWECiphertext<D> {
fn fill_uniform(&mut self, source: &mut Source) {
self.data.fill_uniform(source);
}
}
impl GLWECiphertext<Vec<u8>> {
pub fn alloc(n: usize, basek: usize, k: usize, rank: usize) -> Self {
Self {
data: VecZnx::alloc(n, rank + 1, k.div_ceil(basek)),
basek,
k,
}
}
pub fn bytes_of(n: usize, basek: usize, k: usize, rank: usize) -> usize {
VecZnx::alloc_bytes(n, rank + 1, k.div_ceil(basek))
}
}
impl<D: Data> Infos for GLWECiphertext<D> {
type Inner = VecZnx<D>;
fn inner(&self) -> &Self::Inner {
&self.data
}
fn basek(&self) -> usize {
self.basek
}
fn k(&self) -> usize {
self.k
}
}
impl<D: Data> GLWECiphertext<D> {
pub fn rank(&self) -> usize {
self.cols() - 1
}
}
impl<D: DataMut> SetMetaData for GLWECiphertext<D> {
fn set_k(&mut self, k: usize) {
self.k = k
}
fn set_basek(&mut self, basek: usize) {
self.basek = basek
}
}
pub trait GLWECiphertextToRef: Infos {
fn to_ref(&self) -> GLWECiphertext<&[u8]>;
}
impl<D: DataRef> GLWECiphertextToRef for GLWECiphertext<D> {
fn to_ref(&self) -> GLWECiphertext<&[u8]> {
GLWECiphertext {
data: self.data.to_ref(),
basek: self.basek,
k: self.k,
}
}
}
pub trait GLWECiphertextToMut: Infos {
fn to_mut(&mut self) -> GLWECiphertext<&mut [u8]>;
}
impl<D: DataMut> GLWECiphertextToMut for GLWECiphertext<D> {
fn to_mut(&mut self) -> GLWECiphertext<&mut [u8]> {
GLWECiphertext {
data: self.data.to_mut(),
basek: self.basek,
k: self.k,
}
}
}
impl<D: DataMut> ReaderFrom for GLWECiphertext<D> {
fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> {
self.k = reader.read_u64::<LittleEndian>()? as usize;
self.basek = reader.read_u64::<LittleEndian>()? as usize;
self.data.read_from(reader)
}
}
impl<D: DataRef> WriterTo for GLWECiphertext<D> {
fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
writer.write_u64::<LittleEndian>(self.k as u64)?;
writer.write_u64::<LittleEndian>(self.basek as u64)?;
self.data.write_to(writer)
}
}

View File

@@ -0,0 +1,73 @@
use poulpy_backend::hal::layouts::{Data, DataMut, DataRef, ReaderFrom, VecZnx, WriterTo};
use crate::{dist::Distribution, layouts::Infos};
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
#[derive(PartialEq, Eq)]
pub struct GLWEPublicKey<D: Data> {
pub(crate) data: VecZnx<D>,
pub(crate) basek: usize,
pub(crate) k: usize,
pub(crate) dist: Distribution,
}
impl GLWEPublicKey<Vec<u8>> {
pub fn alloc(n: usize, basek: usize, k: usize, rank: usize) -> Self {
Self {
data: VecZnx::alloc(n, rank + 1, k.div_ceil(basek)),
basek,
k,
dist: Distribution::NONE,
}
}
pub fn bytes_of(n: usize, basek: usize, k: usize, rank: usize) -> usize {
VecZnx::alloc_bytes(n, rank + 1, k.div_ceil(basek))
}
}
impl<D: Data> Infos for GLWEPublicKey<D> {
type Inner = VecZnx<D>;
fn inner(&self) -> &Self::Inner {
&self.data
}
fn basek(&self) -> usize {
self.basek
}
fn k(&self) -> usize {
self.k
}
}
impl<D: Data> GLWEPublicKey<D> {
pub fn rank(&self) -> usize {
self.cols() - 1
}
}
impl<D: DataMut> ReaderFrom for GLWEPublicKey<D> {
fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> {
self.k = reader.read_u64::<LittleEndian>()? as usize;
self.basek = reader.read_u64::<LittleEndian>()? as usize;
match Distribution::read_from(reader) {
Ok(dist) => self.dist = dist,
Err(e) => return Err(e),
}
self.data.read_from(reader)
}
}
impl<D: DataRef> WriterTo for GLWEPublicKey<D> {
fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
writer.write_u64::<LittleEndian>(self.k as u64)?;
writer.write_u64::<LittleEndian>(self.basek as u64)?;
match self.dist.write_to(writer) {
Ok(()) => {}
Err(e) => return Err(e),
}
self.data.write_to(writer)
}
}

View File

@@ -0,0 +1,83 @@
use std::fmt;
use poulpy_backend::hal::layouts::{Data, DataMut, DataRef, VecZnx, VecZnxToMut, VecZnxToRef};
use crate::layouts::{GLWECiphertext, GLWECiphertextToMut, GLWECiphertextToRef, Infos, SetMetaData};
pub struct GLWEPlaintext<D: Data> {
pub data: VecZnx<D>,
pub basek: usize,
pub k: usize,
}
impl<D: DataRef> fmt::Display for GLWEPlaintext<D> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"GLWEPlaintext: basek={} k={}: {}",
self.basek(),
self.k(),
self.data
)
}
}
impl<D: Data> Infos for GLWEPlaintext<D> {
type Inner = VecZnx<D>;
fn inner(&self) -> &Self::Inner {
&self.data
}
fn basek(&self) -> usize {
self.basek
}
fn k(&self) -> usize {
self.k
}
}
impl<D: DataMut> SetMetaData for GLWEPlaintext<D> {
fn set_k(&mut self, k: usize) {
self.k = k
}
fn set_basek(&mut self, basek: usize) {
self.basek = basek
}
}
impl GLWEPlaintext<Vec<u8>> {
pub fn alloc(n: usize, basek: usize, k: usize) -> Self {
Self {
data: VecZnx::alloc(n, 1, k.div_ceil(basek)),
basek,
k,
}
}
pub fn byte_of(n: usize, basek: usize, k: usize) -> usize {
VecZnx::alloc_bytes(n, 1, k.div_ceil(basek))
}
}
impl<D: DataRef> GLWECiphertextToRef for GLWEPlaintext<D> {
fn to_ref(&self) -> GLWECiphertext<&[u8]> {
GLWECiphertext {
data: self.data.to_ref(),
basek: self.basek,
k: self.k,
}
}
}
impl<D: DataMut> GLWECiphertextToMut for GLWEPlaintext<D> {
fn to_mut(&mut self) -> GLWECiphertext<&mut [u8]> {
GLWECiphertext {
data: self.data.to_mut(),
basek: self.basek,
k: self.k,
}
}
}

View File

@@ -0,0 +1,102 @@
use poulpy_backend::hal::{
api::{ZnxInfos, ZnxZero},
layouts::{Data, DataMut, DataRef, ReaderFrom, ScalarZnx, WriterTo},
source::Source,
};
use crate::dist::Distribution;
#[derive(PartialEq, Eq, Clone)]
pub struct GLWESecret<D: Data> {
pub(crate) data: ScalarZnx<D>,
pub(crate) dist: Distribution,
}
impl GLWESecret<Vec<u8>> {
pub fn alloc(n: usize, rank: usize) -> Self {
Self {
data: ScalarZnx::alloc(n, rank),
dist: Distribution::NONE,
}
}
pub fn bytes_of(n: usize, rank: usize) -> usize {
ScalarZnx::alloc_bytes(n, rank)
}
}
impl<D: Data> GLWESecret<D> {
pub fn n(&self) -> usize {
self.data.n()
}
pub fn log_n(&self) -> usize {
self.data.log_n()
}
pub fn rank(&self) -> usize {
self.data.cols()
}
}
impl<D: DataMut> GLWESecret<D> {
pub fn fill_ternary_prob(&mut self, prob: f64, source: &mut Source) {
(0..self.rank()).for_each(|i| {
self.data.fill_ternary_prob(i, prob, source);
});
self.dist = Distribution::TernaryProb(prob);
}
pub fn fill_ternary_hw(&mut self, hw: usize, source: &mut Source) {
(0..self.rank()).for_each(|i| {
self.data.fill_ternary_hw(i, hw, source);
});
self.dist = Distribution::TernaryFixed(hw);
}
pub fn fill_binary_prob(&mut self, prob: f64, source: &mut Source) {
(0..self.rank()).for_each(|i| {
self.data.fill_binary_prob(i, prob, source);
});
self.dist = Distribution::BinaryProb(prob);
}
pub fn fill_binary_hw(&mut self, hw: usize, source: &mut Source) {
(0..self.rank()).for_each(|i| {
self.data.fill_binary_hw(i, hw, source);
});
self.dist = Distribution::BinaryFixed(hw);
}
pub fn fill_binary_block(&mut self, block_size: usize, source: &mut Source) {
(0..self.rank()).for_each(|i| {
self.data.fill_binary_block(i, block_size, source);
});
self.dist = Distribution::BinaryBlock(block_size);
}
pub fn fill_zero(&mut self) {
self.data.zero();
self.dist = Distribution::ZERO;
}
}
impl<D: DataMut> ReaderFrom for GLWESecret<D> {
fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> {
match Distribution::read_from(reader) {
Ok(dist) => self.dist = dist,
Err(e) => return Err(e),
}
self.data.read_from(reader)
}
}
impl<D: DataRef> WriterTo for GLWESecret<D> {
fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
match self.dist.write_to(writer) {
Ok(()) => {}
Err(e) => return Err(e),
}
self.data.write_to(writer)
}
}

View File

@@ -0,0 +1,89 @@
use poulpy_backend::hal::{
api::{FillUniform, Reset},
layouts::{Data, DataMut, DataRef, MatZnx, ReaderFrom, WriterTo},
source::Source,
};
use crate::layouts::{GGLWESwitchingKey, Infos};
use std::fmt;
/// A special [GLWESwitchingKey] required to for the conversion from [GLWECiphertext] to [LWECiphertext].
#[derive(PartialEq, Eq, Clone)]
pub struct GLWEToLWESwitchingKey<D: Data>(pub(crate) GGLWESwitchingKey<D>);
impl<D: DataRef> fmt::Debug for GLWEToLWESwitchingKey<D> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self)
}
}
impl<D: DataMut> FillUniform for GLWEToLWESwitchingKey<D> {
fn fill_uniform(&mut self, source: &mut Source) {
self.0.fill_uniform(source);
}
}
impl<D: DataMut> Reset for GLWEToLWESwitchingKey<D> {
fn reset(&mut self) {
self.0.reset();
}
}
impl<D: DataRef> fmt::Display for GLWEToLWESwitchingKey<D> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "(GLWEToLWESwitchingKey) {}", self.0)
}
}
impl<D: Data> Infos for GLWEToLWESwitchingKey<D> {
type Inner = MatZnx<D>;
fn inner(&self) -> &Self::Inner {
self.0.inner()
}
fn basek(&self) -> usize {
self.0.basek()
}
fn k(&self) -> usize {
self.0.k()
}
}
impl<D: Data> GLWEToLWESwitchingKey<D> {
pub fn digits(&self) -> usize {
self.0.digits()
}
pub fn rank(&self) -> usize {
self.0.rank()
}
pub fn rank_in(&self) -> usize {
self.0.rank_in()
}
pub fn rank_out(&self) -> usize {
self.0.rank_out()
}
}
impl<D: DataMut> ReaderFrom for GLWEToLWESwitchingKey<D> {
fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> {
self.0.read_from(reader)
}
}
impl<D: DataRef> WriterTo for GLWEToLWESwitchingKey<D> {
fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
self.0.write_to(writer)
}
}
impl GLWEToLWESwitchingKey<Vec<u8>> {
pub fn alloc(n: usize, basek: usize, k: usize, rows: usize, rank_in: usize) -> Self {
Self(GGLWESwitchingKey::alloc(n, basek, k, rows, 1, rank_in, 1))
}
}

View File

@@ -0,0 +1,54 @@
use poulpy_backend::hal::api::ZnxInfos;
pub trait Infos {
type Inner: ZnxInfos;
fn inner(&self) -> &Self::Inner;
/// Returns the ring degree of the polynomials.
fn n(&self) -> usize {
self.inner().n()
}
/// Returns the base two logarithm of the ring dimension of the polynomials.
fn log_n(&self) -> usize {
self.inner().log_n()
}
/// Returns the number of rows.
fn rows(&self) -> usize {
self.inner().rows()
}
/// Returns the number of polynomials in each row.
fn cols(&self) -> usize {
self.inner().cols()
}
fn rank(&self) -> usize {
self.cols() - 1
}
/// Returns the number of size per polynomial.
fn size(&self) -> usize {
let size: usize = self.inner().size();
debug_assert!(size >= self.k().div_ceil(self.basek()));
size
}
/// Returns the total number of small polynomials.
fn poly_count(&self) -> usize {
self.rows() * self.cols() * self.size()
}
/// Returns the base 2 logarithm of the ciphertext base.
fn basek(&self) -> usize;
/// Returns the bit precision of the ciphertext.
fn k(&self) -> usize;
}
pub trait SetMetaData {
fn set_basek(&mut self, basek: usize);
fn set_k(&mut self, k: usize);
}

View File

@@ -0,0 +1,153 @@
use std::fmt;
use poulpy_backend::hal::{
api::{FillUniform, Reset, ZnxInfos},
layouts::{Data, DataMut, DataRef, ReaderFrom, VecZnx, VecZnxToMut, VecZnxToRef, WriterTo},
source::Source,
};
#[derive(PartialEq, Eq, Clone)]
pub struct LWECiphertext<D: Data> {
pub(crate) data: VecZnx<D>,
pub(crate) k: usize,
pub(crate) basek: usize,
}
impl<D: DataRef> LWECiphertext<D> {
pub fn data(&self) -> &VecZnx<D> {
&self.data
}
}
impl<D: DataMut> LWECiphertext<D> {
pub fn data_mut(&mut self) -> &VecZnx<D> {
&mut self.data
}
}
impl<D: DataRef> fmt::Debug for LWECiphertext<D> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self)
}
}
impl<D: DataRef> fmt::Display for LWECiphertext<D> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"LWECiphertext: basek={} k={}: {}",
self.basek(),
self.k(),
self.data
)
}
}
impl<D: DataMut> Reset for LWECiphertext<D> {
fn reset(&mut self) {
self.data.reset();
self.basek = 0;
self.k = 0;
}
}
impl<D: DataMut> FillUniform for LWECiphertext<D>
where
VecZnx<D>: FillUniform,
{
fn fill_uniform(&mut self, source: &mut Source) {
self.data.fill_uniform(source);
}
}
impl LWECiphertext<Vec<u8>> {
pub fn alloc(n: usize, basek: usize, k: usize) -> Self {
Self {
data: VecZnx::alloc(n + 1, 1, k.div_ceil(basek)),
k,
basek,
}
}
}
impl<D: Data> Infos for LWECiphertext<D>
where
VecZnx<D>: ZnxInfos,
{
type Inner = VecZnx<D>;
fn n(&self) -> usize {
&self.inner().n() - 1
}
fn inner(&self) -> &Self::Inner {
&self.data
}
fn basek(&self) -> usize {
self.basek
}
fn k(&self) -> usize {
self.k
}
}
impl<DataSelf: DataMut> SetMetaData for LWECiphertext<DataSelf> {
fn set_k(&mut self, k: usize) {
self.k = k
}
fn set_basek(&mut self, basek: usize) {
self.basek = basek
}
}
pub trait LWECiphertextToRef {
fn to_ref(&self) -> LWECiphertext<&[u8]>;
}
impl<D: DataRef> LWECiphertextToRef for LWECiphertext<D> {
fn to_ref(&self) -> LWECiphertext<&[u8]> {
LWECiphertext {
data: self.data.to_ref(),
basek: self.basek,
k: self.k,
}
}
}
pub trait LWECiphertextToMut {
#[allow(dead_code)]
fn to_mut(&mut self) -> LWECiphertext<&mut [u8]>;
}
impl<D: DataMut> LWECiphertextToMut for LWECiphertext<D> {
fn to_mut(&mut self) -> LWECiphertext<&mut [u8]> {
LWECiphertext {
data: self.data.to_mut(),
basek: self.basek,
k: self.k,
}
}
}
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use crate::layouts::{Infos, SetMetaData};
impl<D: DataMut> ReaderFrom for LWECiphertext<D> {
fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> {
self.k = reader.read_u64::<LittleEndian>()? as usize;
self.basek = reader.read_u64::<LittleEndian>()? as usize;
self.data.read_from(reader)
}
}
impl<D: DataRef> WriterTo for LWECiphertext<D> {
fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
writer.write_u64::<LittleEndian>(self.k as u64)?;
writer.write_u64::<LittleEndian>(self.basek as u64)?;
self.data.write_to(writer)
}
}

View File

@@ -0,0 +1,88 @@
use std::fmt;
use poulpy_backend::hal::{
api::{FillUniform, Reset},
layouts::{Data, DataMut, DataRef, MatZnx, ReaderFrom, WriterTo},
source::Source,
};
use crate::layouts::{GGLWESwitchingKey, Infos};
#[derive(PartialEq, Eq, Clone)]
pub struct LWESwitchingKey<D: Data>(pub(crate) GGLWESwitchingKey<D>);
impl LWESwitchingKey<Vec<u8>> {
pub fn alloc(n: usize, basek: usize, k: usize, rows: usize) -> Self {
Self(GGLWESwitchingKey::alloc(n, basek, k, rows, 1, 1, 1))
}
}
impl<D: DataRef> fmt::Debug for LWESwitchingKey<D> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self)
}
}
impl<D: DataMut> FillUniform for LWESwitchingKey<D> {
fn fill_uniform(&mut self, source: &mut Source) {
self.0.fill_uniform(source);
}
}
impl<D: DataMut> Reset for LWESwitchingKey<D> {
fn reset(&mut self) {
self.0.reset();
}
}
impl<D: DataRef> fmt::Display for LWESwitchingKey<D> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "(LWESwitchingKey) {}", self.0)
}
}
impl<D: Data> Infos for LWESwitchingKey<D> {
type Inner = MatZnx<D>;
fn inner(&self) -> &Self::Inner {
self.0.inner()
}
fn basek(&self) -> usize {
self.0.basek()
}
fn k(&self) -> usize {
self.0.k()
}
}
impl<D: Data> LWESwitchingKey<D> {
pub fn digits(&self) -> usize {
self.0.digits()
}
pub fn rank(&self) -> usize {
self.0.rank()
}
pub fn rank_in(&self) -> usize {
self.0.rank_in()
}
pub fn rank_out(&self) -> usize {
self.0.rank_out()
}
}
impl<D: DataMut> ReaderFrom for LWESwitchingKey<D> {
fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> {
self.0.read_from(reader)
}
}
impl<D: DataRef> WriterTo for LWESwitchingKey<D> {
fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
self.0.write_to(writer)
}
}

View File

@@ -0,0 +1,95 @@
use std::fmt;
use poulpy_backend::hal::layouts::{Data, DataMut, DataRef, VecZnx, VecZnxToMut, VecZnxToRef};
use crate::layouts::{Infos, SetMetaData};
pub struct LWEPlaintext<D: Data> {
pub(crate) data: VecZnx<D>,
pub(crate) k: usize,
pub(crate) basek: usize,
}
impl LWEPlaintext<Vec<u8>> {
pub fn alloc(basek: usize, k: usize) -> Self {
Self {
data: VecZnx::alloc(1, 1, k.div_ceil(basek)),
k,
basek,
}
}
}
impl<D: DataRef> fmt::Display for LWEPlaintext<D> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"LWEPlaintext: basek={} k={}: {}",
self.basek(),
self.k(),
self.data
)
}
}
impl<D: Data> Infos for LWEPlaintext<D> {
type Inner = VecZnx<D>;
fn inner(&self) -> &Self::Inner {
&self.data
}
fn basek(&self) -> usize {
self.basek
}
fn k(&self) -> usize {
self.k
}
}
impl<D: DataMut> SetMetaData for LWEPlaintext<D> {
fn set_k(&mut self, k: usize) {
self.k = k
}
fn set_basek(&mut self, basek: usize) {
self.basek = basek
}
}
pub trait LWEPlaintextToRef {
#[allow(dead_code)]
fn to_ref(&self) -> LWEPlaintext<&[u8]>;
}
impl<D: DataRef> LWEPlaintextToRef for LWEPlaintext<D> {
fn to_ref(&self) -> LWEPlaintext<&[u8]> {
LWEPlaintext {
data: self.data.to_ref(),
basek: self.basek,
k: self.k,
}
}
}
pub trait LWEPlaintextToMut {
#[allow(dead_code)]
fn to_mut(&mut self) -> LWEPlaintext<&mut [u8]>;
}
impl<D: DataMut> LWEPlaintextToMut for LWEPlaintext<D> {
fn to_mut(&mut self) -> LWEPlaintext<&mut [u8]> {
LWEPlaintext {
data: self.data.to_mut(),
basek: self.basek,
k: self.k,
}
}
}
impl<D: DataMut> LWEPlaintext<D> {
pub fn data_mut(&mut self) -> &mut VecZnx<D> {
&mut self.data
}
}

View File

@@ -0,0 +1,81 @@
use poulpy_backend::hal::{
api::{ZnxInfos, ZnxView, ZnxZero},
layouts::{Data, DataMut, DataRef, ScalarZnx},
source::Source,
};
use crate::dist::Distribution;
pub struct LWESecret<D: Data> {
pub(crate) data: ScalarZnx<D>,
pub(crate) dist: Distribution,
}
impl LWESecret<Vec<u8>> {
pub fn alloc(n: usize) -> Self {
Self {
data: ScalarZnx::alloc(n, 1),
dist: Distribution::NONE,
}
}
}
impl<D: DataRef> LWESecret<D> {
pub fn raw(&self) -> &[i64] {
self.data.at(0, 0)
}
pub fn dist(&self) -> Distribution {
self.dist
}
pub fn data(&self) -> &ScalarZnx<D> {
&self.data
}
}
impl<D: Data> LWESecret<D> {
pub fn n(&self) -> usize {
self.data.n()
}
pub fn log_n(&self) -> usize {
self.data.log_n()
}
pub fn rank(&self) -> usize {
self.data.cols()
}
}
impl<D: DataMut> LWESecret<D> {
pub fn fill_ternary_prob(&mut self, prob: f64, source: &mut Source) {
self.data.fill_ternary_prob(0, prob, source);
self.dist = Distribution::TernaryProb(prob);
}
pub fn fill_ternary_hw(&mut self, hw: usize, source: &mut Source) {
self.data.fill_ternary_hw(0, hw, source);
self.dist = Distribution::TernaryFixed(hw);
}
pub fn fill_binary_prob(&mut self, prob: f64, source: &mut Source) {
self.data.fill_binary_prob(0, prob, source);
self.dist = Distribution::BinaryProb(prob);
}
pub fn fill_binary_hw(&mut self, hw: usize, source: &mut Source) {
self.data.fill_binary_hw(0, hw, source);
self.dist = Distribution::BinaryFixed(hw);
}
pub fn fill_binary_block(&mut self, block_size: usize, source: &mut Source) {
self.data.fill_binary_block(0, block_size, source);
self.dist = Distribution::BinaryBlock(block_size);
}
pub fn fill_zero(&mut self) {
self.data.zero();
self.dist = Distribution::ZERO;
}
}

View File

@@ -0,0 +1,88 @@
use std::fmt;
use poulpy_backend::hal::{
api::{FillUniform, Reset},
layouts::{Data, DataMut, DataRef, MatZnx, ReaderFrom, WriterTo},
source::Source,
};
use crate::layouts::{GGLWESwitchingKey, Infos};
#[derive(PartialEq, Eq, Clone)]
pub struct LWEToGLWESwitchingKey<D: Data>(pub(crate) GGLWESwitchingKey<D>);
impl<D: DataRef> fmt::Debug for LWEToGLWESwitchingKey<D> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self)
}
}
impl<D: DataMut> FillUniform for LWEToGLWESwitchingKey<D> {
fn fill_uniform(&mut self, source: &mut Source) {
self.0.fill_uniform(source);
}
}
impl<D: DataMut> Reset for LWEToGLWESwitchingKey<D> {
fn reset(&mut self) {
self.0.reset();
}
}
impl<D: DataRef> fmt::Display for LWEToGLWESwitchingKey<D> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "(LWEToGLWESwitchingKey) {}", self.0)
}
}
impl<D: Data> Infos for LWEToGLWESwitchingKey<D> {
type Inner = MatZnx<D>;
fn inner(&self) -> &Self::Inner {
self.0.inner()
}
fn basek(&self) -> usize {
self.0.basek()
}
fn k(&self) -> usize {
self.0.k()
}
}
impl<D: Data> LWEToGLWESwitchingKey<D> {
pub fn digits(&self) -> usize {
self.0.digits()
}
pub fn rank(&self) -> usize {
self.0.rank()
}
pub fn rank_in(&self) -> usize {
self.0.rank_in()
}
pub fn rank_out(&self) -> usize {
self.0.rank_out()
}
}
impl<D: DataMut> ReaderFrom for LWEToGLWESwitchingKey<D> {
fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> {
self.0.read_from(reader)
}
}
impl<D: DataRef> WriterTo for LWEToGLWESwitchingKey<D> {
fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
self.0.write_to(writer)
}
}
impl LWEToGLWESwitchingKey<Vec<u8>> {
pub fn alloc(n: usize, basek: usize, k: usize, rows: usize, rank_out: usize) -> Self {
Self(GGLWESwitchingKey::alloc(n, basek, k, rows, 1, 1, rank_out))
}
}

View File

@@ -0,0 +1,36 @@
mod gglwe_atk;
mod gglwe_ct;
mod gglwe_ksk;
mod gglwe_tsk;
mod ggsw_ct;
mod glwe_ct;
mod glwe_pk;
mod glwe_pt;
mod glwe_sk;
mod glwe_to_lwe_ksk;
mod infos;
mod lwe_ct;
mod lwe_ksk;
mod lwe_pt;
mod lwe_sk;
mod lwe_to_glwe_ksk;
pub mod compressed;
pub mod prepared;
pub use gglwe_atk::*;
pub use gglwe_ct::*;
pub use gglwe_ksk::*;
pub use gglwe_tsk::*;
pub use ggsw_ct::*;
pub use glwe_ct::*;
pub use glwe_pk::*;
pub use glwe_pt::*;
pub use glwe_sk::*;
pub use glwe_to_lwe_ksk::*;
pub use infos::*;
pub use lwe_ct::*;
pub use lwe_ksk::*;
pub use lwe_pt::*;
pub use lwe_sk::*;
pub use lwe_to_glwe_ksk::*;

View File

@@ -0,0 +1,101 @@
use poulpy_backend::hal::{
api::{VmpPMatAlloc, VmpPMatAllocBytes, VmpPrepare},
layouts::{Backend, Data, DataMut, DataRef, Module, Scratch, VmpPMat},
};
use crate::layouts::{
GGLWEAutomorphismKey, Infos,
prepared::{GGLWESwitchingKeyPrepared, Prepare, PrepareAlloc},
};
#[derive(PartialEq, Eq)]
pub struct GGLWEAutomorphismKeyPrepared<D: Data, B: Backend> {
pub(crate) key: GGLWESwitchingKeyPrepared<D, B>,
pub(crate) p: i64,
}
impl<B: Backend> GGLWEAutomorphismKeyPrepared<Vec<u8>, B> {
pub fn alloc(module: &Module<B>, n: usize, basek: usize, k: usize, rows: usize, digits: usize, rank: usize) -> Self
where
Module<B>: VmpPMatAlloc<B>,
{
GGLWEAutomorphismKeyPrepared::<Vec<u8>, B> {
key: GGLWESwitchingKeyPrepared::alloc(module, n, basek, k, rows, digits, rank, rank),
p: 0,
}
}
pub fn bytes_of(module: &Module<B>, n: usize, basek: usize, k: usize, rows: usize, digits: usize, rank: usize) -> usize
where
Module<B>: VmpPMatAllocBytes,
{
GGLWESwitchingKeyPrepared::bytes_of(module, n, basek, k, rows, digits, rank, rank)
}
}
impl<D: Data, B: Backend> Infos for GGLWEAutomorphismKeyPrepared<D, B> {
type Inner = VmpPMat<D, B>;
fn inner(&self) -> &Self::Inner {
self.key.inner()
}
fn basek(&self) -> usize {
self.key.basek()
}
fn k(&self) -> usize {
self.key.k()
}
}
impl<D: Data, B: Backend> GGLWEAutomorphismKeyPrepared<D, B> {
pub fn p(&self) -> i64 {
self.p
}
pub fn digits(&self) -> usize {
self.key.digits()
}
pub fn rank(&self) -> usize {
self.key.rank()
}
pub fn rank_in(&self) -> usize {
self.key.rank_in()
}
pub fn rank_out(&self) -> usize {
self.key.rank_out()
}
}
impl<D: DataMut, DR: DataRef, B: Backend> Prepare<B, GGLWEAutomorphismKey<DR>> for GGLWEAutomorphismKeyPrepared<D, B>
where
Module<B>: VmpPrepare<B>,
{
fn prepare(&mut self, module: &Module<B>, other: &GGLWEAutomorphismKey<DR>, scratch: &mut Scratch<B>) {
self.key.prepare(module, &other.key, scratch);
self.p = other.p;
}
}
impl<D: DataRef, B: Backend> PrepareAlloc<B, GGLWEAutomorphismKeyPrepared<Vec<u8>, B>> for GGLWEAutomorphismKey<D>
where
Module<B>: VmpPMatAlloc<B> + VmpPrepare<B>,
{
fn prepare_alloc(&self, module: &Module<B>, scratch: &mut Scratch<B>) -> GGLWEAutomorphismKeyPrepared<Vec<u8>, B> {
let mut atk_prepared: GGLWEAutomorphismKeyPrepared<Vec<u8>, B> = GGLWEAutomorphismKeyPrepared::alloc(
module,
self.n(),
self.basek(),
self.k(),
self.rows(),
self.digits(),
self.rank(),
);
atk_prepared.prepare(module, self, scratch);
atk_prepared
}
}

View File

@@ -0,0 +1,156 @@
use poulpy_backend::hal::{
api::{VmpPMatAlloc, VmpPMatAllocBytes, VmpPrepare},
layouts::{Backend, Data, DataMut, DataRef, Module, Scratch, VmpPMat},
};
use crate::layouts::{
GGLWECiphertext, Infos,
prepared::{Prepare, PrepareAlloc},
};
#[derive(PartialEq, Eq)]
pub struct GGLWECiphertextPrepared<D: Data, B: Backend> {
pub(crate) data: VmpPMat<D, B>,
pub(crate) basek: usize,
pub(crate) k: usize,
pub(crate) digits: usize,
}
impl<B: Backend> GGLWECiphertextPrepared<Vec<u8>, B> {
#[allow(clippy::too_many_arguments)]
pub fn alloc(
module: &Module<B>,
n: usize,
basek: usize,
k: usize,
rows: usize,
digits: usize,
rank_in: usize,
rank_out: usize,
) -> Self
where
Module<B>: VmpPMatAlloc<B>,
{
let size: usize = k.div_ceil(basek);
debug_assert!(
size > digits,
"invalid gglwe: ceil(k/basek): {} <= digits: {}",
size,
digits
);
assert!(
rows * digits <= size,
"invalid gglwe: rows: {} * digits:{} > ceil(k/basek): {}",
rows,
digits,
size
);
Self {
data: module.vmp_pmat_alloc(n, rows, rank_in, rank_out + 1, size),
basek,
k,
digits,
}
}
#[allow(clippy::too_many_arguments)]
pub fn bytes_of(
module: &Module<B>,
n: usize,
basek: usize,
k: usize,
rows: usize,
digits: usize,
rank_in: usize,
rank_out: usize,
) -> usize
where
Module<B>: VmpPMatAllocBytes,
{
let size: usize = k.div_ceil(basek);
debug_assert!(
size > digits,
"invalid gglwe: ceil(k/basek): {} <= digits: {}",
size,
digits
);
assert!(
rows * digits <= size,
"invalid gglwe: rows: {} * digits:{} > ceil(k/basek): {}",
rows,
digits,
size
);
module.vmp_pmat_alloc_bytes(n, rows, rank_in, rank_out + 1, rows)
}
}
impl<D: Data, B: Backend> Infos for GGLWECiphertextPrepared<D, B> {
type Inner = VmpPMat<D, B>;
fn inner(&self) -> &Self::Inner {
&self.data
}
fn basek(&self) -> usize {
self.basek
}
fn k(&self) -> usize {
self.k
}
}
impl<D: Data, B: Backend> GGLWECiphertextPrepared<D, B> {
pub fn rank(&self) -> usize {
self.data.cols_out() - 1
}
pub fn digits(&self) -> usize {
self.digits
}
pub fn rank_in(&self) -> usize {
self.data.cols_in()
}
pub fn rank_out(&self) -> usize {
self.data.cols_out() - 1
}
}
impl<D: DataMut, DR: DataRef, B: Backend> Prepare<B, GGLWECiphertext<DR>> for GGLWECiphertextPrepared<D, B>
where
Module<B>: VmpPrepare<B>,
{
fn prepare(&mut self, module: &Module<B>, other: &GGLWECiphertext<DR>, scratch: &mut Scratch<B>) {
module.vmp_prepare(&mut self.data, &other.data, scratch);
self.basek = other.basek;
self.k = other.k;
self.digits = other.digits;
}
}
impl<D: DataRef, B: Backend> PrepareAlloc<B, GGLWECiphertextPrepared<Vec<u8>, B>> for GGLWECiphertext<D>
where
Module<B>: VmpPMatAlloc<B> + VmpPrepare<B>,
{
fn prepare_alloc(&self, module: &Module<B>, scratch: &mut Scratch<B>) -> GGLWECiphertextPrepared<Vec<u8>, B> {
let mut atk_prepared: GGLWECiphertextPrepared<Vec<u8>, B> = GGLWECiphertextPrepared::alloc(
module,
self.n(),
self.basek(),
self.k(),
self.rows(),
self.digits(),
self.rank_in(),
self.rank_out(),
);
atk_prepared.prepare(module, self, scratch);
atk_prepared
}
}

View File

@@ -0,0 +1,129 @@
use poulpy_backend::hal::{
api::{VmpPMatAlloc, VmpPMatAllocBytes, VmpPrepare},
layouts::{Backend, Data, DataMut, DataRef, Module, Scratch, VmpPMat},
};
use crate::layouts::{
GGLWESwitchingKey, Infos,
prepared::{GGLWECiphertextPrepared, Prepare, PrepareAlloc},
};
#[derive(PartialEq, Eq)]
pub struct GGLWESwitchingKeyPrepared<D: Data, B: Backend> {
pub(crate) key: GGLWECiphertextPrepared<D, B>,
pub(crate) sk_in_n: usize, // Degree of sk_in
pub(crate) sk_out_n: usize, // Degree of sk_out
}
impl<B: Backend> GGLWESwitchingKeyPrepared<Vec<u8>, B> {
#[allow(clippy::too_many_arguments)]
pub fn alloc(
module: &Module<B>,
n: usize,
basek: usize,
k: usize,
rows: usize,
digits: usize,
rank_in: usize,
rank_out: usize,
) -> Self
where
Module<B>: VmpPMatAlloc<B>,
{
GGLWESwitchingKeyPrepared::<Vec<u8>, B> {
key: GGLWECiphertextPrepared::alloc(module, n, basek, k, rows, digits, rank_in, rank_out),
sk_in_n: 0,
sk_out_n: 0,
}
}
#[allow(clippy::too_many_arguments)]
pub fn bytes_of(
module: &Module<B>,
n: usize,
basek: usize,
k: usize,
rows: usize,
digits: usize,
rank_in: usize,
rank_out: usize,
) -> usize
where
Module<B>: VmpPMatAllocBytes,
{
GGLWECiphertextPrepared::bytes_of(module, n, basek, k, rows, digits, rank_in, rank_out)
}
}
impl<D: Data, B: Backend> Infos for GGLWESwitchingKeyPrepared<D, B> {
type Inner = VmpPMat<D, B>;
fn inner(&self) -> &Self::Inner {
self.key.inner()
}
fn basek(&self) -> usize {
self.key.basek()
}
fn k(&self) -> usize {
self.key.k()
}
}
impl<D: Data, B: Backend> GGLWESwitchingKeyPrepared<D, B> {
pub fn rank(&self) -> usize {
self.key.data.cols_out() - 1
}
pub fn rank_in(&self) -> usize {
self.key.data.cols_in()
}
pub fn rank_out(&self) -> usize {
self.key.data.cols_out() - 1
}
pub fn digits(&self) -> usize {
self.key.digits()
}
pub fn sk_degree_in(&self) -> usize {
self.sk_in_n
}
pub fn sk_degree_out(&self) -> usize {
self.sk_out_n
}
}
impl<D: DataMut, DR: DataRef, B: Backend> Prepare<B, GGLWESwitchingKey<DR>> for GGLWESwitchingKeyPrepared<D, B>
where
Module<B>: VmpPrepare<B>,
{
fn prepare(&mut self, module: &Module<B>, other: &GGLWESwitchingKey<DR>, scratch: &mut Scratch<B>) {
self.key.prepare(module, &other.key, scratch);
self.sk_in_n = other.sk_in_n;
self.sk_out_n = other.sk_out_n;
}
}
impl<D: DataRef, B: Backend> PrepareAlloc<B, GGLWESwitchingKeyPrepared<Vec<u8>, B>> for GGLWESwitchingKey<D>
where
Module<B>: VmpPMatAlloc<B> + VmpPrepare<B>,
{
fn prepare_alloc(&self, module: &Module<B>, scratch: &mut Scratch<B>) -> GGLWESwitchingKeyPrepared<Vec<u8>, B> {
let mut atk_prepared: GGLWESwitchingKeyPrepared<Vec<u8>, B> = GGLWESwitchingKeyPrepared::alloc(
module,
self.n(),
self.basek(),
self.k(),
self.rows(),
self.digits(),
self.rank_in(),
self.rank_out(),
);
atk_prepared.prepare(module, self, scratch);
atk_prepared
}
}

View File

@@ -0,0 +1,131 @@
use poulpy_backend::hal::{
api::{VmpPMatAlloc, VmpPMatAllocBytes, VmpPrepare},
layouts::{Backend, Data, DataMut, DataRef, Module, Scratch, VmpPMat},
};
use crate::layouts::{
GGLWETensorKey, Infos,
prepared::{GGLWESwitchingKeyPrepared, Prepare, PrepareAlloc},
};
#[derive(PartialEq, Eq)]
pub struct GGLWETensorKeyPrepared<D: Data, B: Backend> {
pub(crate) keys: Vec<GGLWESwitchingKeyPrepared<D, B>>,
}
impl<B: Backend> GGLWETensorKeyPrepared<Vec<u8>, B> {
pub fn alloc(module: &Module<B>, n: usize, basek: usize, k: usize, rows: usize, digits: usize, rank: usize) -> Self
where
Module<B>: VmpPMatAlloc<B>,
{
let mut keys: Vec<GGLWESwitchingKeyPrepared<Vec<u8>, B>> = Vec::new();
let pairs: usize = (((rank + 1) * rank) >> 1).max(1);
(0..pairs).for_each(|_| {
keys.push(GGLWESwitchingKeyPrepared::alloc(
module, n, basek, k, rows, digits, 1, rank,
));
});
Self { keys }
}
pub fn bytes_of(module: &Module<B>, n: usize, basek: usize, k: usize, rows: usize, digits: usize, rank: usize) -> usize
where
Module<B>: VmpPMatAllocBytes,
{
let pairs: usize = (((rank + 1) * rank) >> 1).max(1);
pairs * GGLWESwitchingKeyPrepared::bytes_of(module, n, basek, k, rows, digits, 1, rank)
}
}
impl<D: Data, B: Backend> Infos for GGLWETensorKeyPrepared<D, B> {
type Inner = VmpPMat<D, B>;
fn inner(&self) -> &Self::Inner {
self.keys[0].inner()
}
fn basek(&self) -> usize {
self.keys[0].basek()
}
fn k(&self) -> usize {
self.keys[0].k()
}
}
impl<D: Data, B: Backend> GGLWETensorKeyPrepared<D, B> {
pub fn rank(&self) -> usize {
self.keys[0].rank()
}
pub fn rank_in(&self) -> usize {
self.keys[0].rank_in()
}
pub fn rank_out(&self) -> usize {
self.keys[0].rank_out()
}
pub fn digits(&self) -> usize {
self.keys[0].digits()
}
}
impl<D: DataMut, B: Backend> GGLWETensorKeyPrepared<D, B> {
// Returns a mutable reference to GLWESwitchingKey_{s}(s[i] * s[j])
pub fn at_mut(&mut self, mut i: usize, mut j: usize) -> &mut GGLWESwitchingKeyPrepared<D, B> {
if i > j {
std::mem::swap(&mut i, &mut j);
};
let rank: usize = self.rank();
&mut self.keys[i * rank + j - (i * (i + 1) / 2)]
}
}
impl<D: DataRef, B: Backend> GGLWETensorKeyPrepared<D, B> {
// Returns a reference to GLWESwitchingKey_{s}(s[i] * s[j])
pub fn at(&self, mut i: usize, mut j: usize) -> &GGLWESwitchingKeyPrepared<D, B> {
if i > j {
std::mem::swap(&mut i, &mut j);
};
let rank: usize = self.rank();
&self.keys[i * rank + j - (i * (i + 1) / 2)]
}
}
impl<D: DataMut, DR: DataRef, B: Backend> Prepare<B, GGLWETensorKey<DR>> for GGLWETensorKeyPrepared<D, B>
where
Module<B>: VmpPrepare<B>,
{
fn prepare(&mut self, module: &Module<B>, other: &GGLWETensorKey<DR>, scratch: &mut Scratch<B>) {
#[cfg(debug_assertions)]
{
assert_eq!(self.keys.len(), other.keys.len());
}
self.keys
.iter_mut()
.zip(other.keys.iter())
.for_each(|(a, b)| {
a.prepare(module, b, scratch);
});
}
}
impl<D: DataRef, B: Backend> PrepareAlloc<B, GGLWETensorKeyPrepared<Vec<u8>, B>> for GGLWETensorKey<D>
where
Module<B>: VmpPMatAlloc<B> + VmpPrepare<B>,
{
fn prepare_alloc(&self, module: &Module<B>, scratch: &mut Scratch<B>) -> GGLWETensorKeyPrepared<Vec<u8>, B> {
let mut tsk_prepared: GGLWETensorKeyPrepared<Vec<u8>, B> = GGLWETensorKeyPrepared::alloc(
module,
self.n(),
self.basek(),
self.k(),
self.rows(),
self.digits(),
self.rank(),
);
tsk_prepared.prepare(module, self, scratch);
tsk_prepared
}
}

View File

@@ -0,0 +1,135 @@
use poulpy_backend::hal::{
api::{VmpPMatAlloc, VmpPMatAllocBytes, VmpPrepare},
layouts::{Backend, Data, DataMut, DataRef, Module, Scratch, VmpPMat},
};
use crate::layouts::{
GGSWCiphertext, Infos,
prepared::{Prepare, PrepareAlloc},
};
#[derive(PartialEq, Eq)]
pub struct GGSWCiphertextPrepared<D: Data, B: Backend> {
pub(crate) data: VmpPMat<D, B>,
pub(crate) basek: usize,
pub(crate) k: usize,
pub(crate) digits: usize,
}
impl<B: Backend> GGSWCiphertextPrepared<Vec<u8>, B> {
pub fn alloc(module: &Module<B>, n: usize, basek: usize, k: usize, rows: usize, digits: usize, rank: usize) -> Self
where
Module<B>: VmpPMatAlloc<B>,
{
let size: usize = k.div_ceil(basek);
debug_assert!(digits > 0, "invalid ggsw: `digits` == 0");
debug_assert!(
size > digits,
"invalid ggsw: ceil(k/basek): {} <= digits: {}",
size,
digits
);
assert!(
rows * digits <= size,
"invalid ggsw: rows: {} * digits:{} > ceil(k/basek): {}",
rows,
digits,
size
);
Self {
data: module.vmp_pmat_alloc(n, rows, rank + 1, rank + 1, k.div_ceil(basek)),
basek,
k,
digits,
}
}
pub fn bytes_of(module: &Module<B>, n: usize, basek: usize, k: usize, rows: usize, digits: usize, rank: usize) -> usize
where
Module<B>: VmpPMatAllocBytes,
{
let size: usize = k.div_ceil(basek);
debug_assert!(
size > digits,
"invalid ggsw: ceil(k/basek): {} <= digits: {}",
size,
digits
);
assert!(
rows * digits <= size,
"invalid ggsw: rows: {} * digits:{} > ceil(k/basek): {}",
rows,
digits,
size
);
module.vmp_pmat_alloc_bytes(n, rows, rank + 1, rank + 1, size)
}
}
impl<D: Data, B: Backend> Infos for GGSWCiphertextPrepared<D, B> {
type Inner = VmpPMat<D, B>;
fn inner(&self) -> &Self::Inner {
&self.data
}
fn basek(&self) -> usize {
self.basek
}
fn k(&self) -> usize {
self.k
}
}
impl<D: Data, B: Backend> GGSWCiphertextPrepared<D, B> {
pub fn rank(&self) -> usize {
self.data.cols_out() - 1
}
pub fn digits(&self) -> usize {
self.digits
}
}
impl<D: DataRef, B: Backend> GGSWCiphertextPrepared<D, B> {
pub fn data(&self) -> &VmpPMat<D, B> {
&self.data
}
}
impl<D: DataMut, DR: DataRef, B: Backend> Prepare<B, GGSWCiphertext<DR>> for GGSWCiphertextPrepared<D, B>
where
Module<B>: VmpPrepare<B>,
{
fn prepare(&mut self, module: &Module<B>, other: &GGSWCiphertext<DR>, scratch: &mut Scratch<B>) {
module.vmp_prepare(&mut self.data, &other.data, scratch);
self.k = other.k;
self.basek = other.basek;
self.digits = other.digits;
}
}
impl<D: DataRef, B: Backend> PrepareAlloc<B, GGSWCiphertextPrepared<Vec<u8>, B>> for GGSWCiphertext<D>
where
Module<B>: VmpPMatAlloc<B> + VmpPrepare<B>,
{
fn prepare_alloc(&self, module: &Module<B>, scratch: &mut Scratch<B>) -> GGSWCiphertextPrepared<Vec<u8>, B> {
let mut ggsw_prepared: GGSWCiphertextPrepared<Vec<u8>, B> = GGSWCiphertextPrepared::alloc(
module,
self.n(),
self.basek(),
self.k(),
self.rows(),
self.digits(),
self.rank(),
);
ggsw_prepared.prepare(module, self, scratch);
ggsw_prepared
}
}

View File

@@ -0,0 +1,177 @@
use poulpy_backend::hal::{
api::{FillUniform, Reset, VecZnxCopy, VecZnxFillUniform},
layouts::{Backend, Data, DataMut, DataRef, Module, ReaderFrom, VecZnx, WriterTo},
};
use crate::layouts::{GLWECiphertext, Infos, compressed::Decompress};
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use std::fmt;
#[derive(PartialEq, Eq, Clone)]
pub struct GLWECiphertextCompressed<D: Data> {
pub(crate) data: VecZnx<D>,
pub(crate) basek: usize,
pub(crate) k: usize,
pub(crate) rank: usize,
pub(crate) seed: [u8; 32],
}
impl<D: DataRef> fmt::Debug for GLWECiphertextCompressed<D> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self)
}
}
impl<D: DataRef> fmt::Display for GLWECiphertextCompressed<D> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"GLWECiphertextCompressed: basek={} k={} rank={} seed={:?}: {}",
self.basek(),
self.k(),
self.rank,
self.seed,
self.data
)
}
}
impl<D: DataMut> Reset for GLWECiphertextCompressed<D> {
fn reset(&mut self) {
self.data.reset();
self.basek = 0;
self.k = 0;
self.rank = 0;
self.seed = [0u8; 32];
}
}
impl<D: DataMut> FillUniform for GLWECiphertextCompressed<D> {
fn fill_uniform(&mut self, source: &mut Source) {
self.data.fill_uniform(source);
}
}
impl<D: Data> Infos for GLWECiphertextCompressed<D> {
type Inner = VecZnx<D>;
fn inner(&self) -> &Self::Inner {
&self.data
}
fn basek(&self) -> usize {
self.basek
}
fn k(&self) -> usize {
self.k
}
}
impl<D: Data> GLWECiphertextCompressed<D> {
pub fn rank(&self) -> usize {
self.rank
}
}
impl GLWECiphertextCompressed<Vec<u8>> {
pub fn alloc(n: usize, basek: usize, k: usize, rank: usize) -> Self {
Self {
data: VecZnx::alloc(n, 1, k.div_ceil(basek)),
basek,
k,
rank,
seed: [0u8; 32],
}
}
pub fn bytes_of(n: usize, basek: usize, k: usize) -> usize {
GLWECiphertext::bytes_of(n, basek, k, 1)
}
}
impl<D: DataMut> ReaderFrom for GLWECiphertextCompressed<D> {
fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> {
self.k = reader.read_u64::<LittleEndian>()? as usize;
self.basek = reader.read_u64::<LittleEndian>()? as usize;
self.rank = reader.read_u64::<LittleEndian>()? as usize;
reader.read_exact(&mut self.seed)?;
self.data.read_from(reader)
}
}
impl<D: DataRef> WriterTo for GLWECiphertextCompressed<D> {
fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
writer.write_u64::<LittleEndian>(self.k as u64)?;
writer.write_u64::<LittleEndian>(self.basek as u64)?;
writer.write_u64::<LittleEndian>(self.rank as u64)?;
writer.write_all(&self.seed)?;
self.data.write_to(writer)
}
}
impl<D: DataMut, B: Backend, DR: DataRef> Decompress<B, GLWECiphertextCompressed<DR>> for GLWECiphertext<D> {
fn decompress(&mut self, module: &Module<B>, other: &GLWECiphertextCompressed<DR>)
where
Module<B>: VecZnxCopy + VecZnxFillUniform,
{
#[cfg(debug_assertions)]
{
use poulpy_backend::hal::api::ZnxInfos;
assert_eq!(
self.n(),
other.data.n(),
"invalid receiver: self.n()={} != other.n()={}",
self.n(),
other.data.n()
);
assert_eq!(
self.size(),
other.size(),
"invalid receiver: self.size()={} != other.size()={}",
self.size(),
other.size()
);
assert_eq!(
self.rank(),
other.rank(),
"invalid receiver: self.rank()={} != other.rank()={}",
self.rank(),
other.rank()
);
}
let mut source: Source = Source::new(other.seed);
self.decompress_internal(module, other, &mut source);
}
}
impl<D: DataMut> GLWECiphertext<D> {
pub(crate) fn decompress_internal<DataOther, B: Backend>(
&mut self,
module: &Module<B>,
other: &GLWECiphertextCompressed<DataOther>,
source: &mut Source,
) where
DataOther: DataRef,
Module<B>: VecZnxCopy + VecZnxFillUniform,
{
#[cfg(debug_assertions)]
{
assert_eq!(self.rank(), other.rank())
}
let k: usize = other.k;
let basek: usize = other.basek;
let cols: usize = other.rank() + 1;
module.vec_znx_copy(&mut self.data, 0, &other.data, 0);
(1..cols).for_each(|i| {
module.vec_znx_fill_uniform(basek, &mut self.data, i, k, source);
});
self.basek = basek;
self.k = k;
}
}

View File

@@ -0,0 +1,95 @@
use poulpy_backend::hal::{
api::{VecZnxDftAlloc, VecZnxDftAllocBytes, VecZnxDftFromVecZnx},
layouts::{Backend, Data, DataMut, DataRef, Module, Scratch, VecZnxDft},
};
use crate::{
dist::Distribution,
layouts::{
GLWEPublicKey, Infos,
prepared::{Prepare, PrepareAlloc},
},
};
#[derive(PartialEq, Eq)]
pub struct GLWEPublicKeyPrepared<D: Data, B: Backend> {
pub(crate) data: VecZnxDft<D, B>,
pub(crate) basek: usize,
pub(crate) k: usize,
pub(crate) dist: Distribution,
}
impl<D: Data, B: Backend> Infos for GLWEPublicKeyPrepared<D, B> {
type Inner = VecZnxDft<D, B>;
fn inner(&self) -> &Self::Inner {
&self.data
}
fn basek(&self) -> usize {
self.basek
}
fn k(&self) -> usize {
self.k
}
}
impl<D: Data, B: Backend> GLWEPublicKeyPrepared<D, B> {
pub fn rank(&self) -> usize {
self.cols() - 1
}
}
impl<B: Backend> GLWEPublicKeyPrepared<Vec<u8>, B> {
pub fn alloc(module: &Module<B>, n: usize, basek: usize, k: usize, rank: usize) -> Self
where
Module<B>: VecZnxDftAlloc<B>,
{
Self {
data: module.vec_znx_dft_alloc(n, rank + 1, k.div_ceil(basek)),
basek,
k,
dist: Distribution::NONE,
}
}
pub fn bytes_of(module: &Module<B>, n: usize, basek: usize, k: usize, rank: usize) -> usize
where
Module<B>: VecZnxDftAllocBytes,
{
module.vec_znx_dft_alloc_bytes(n, rank + 1, k.div_ceil(basek))
}
}
impl<D: DataRef, B: Backend> PrepareAlloc<B, GLWEPublicKeyPrepared<Vec<u8>, B>> for GLWEPublicKey<D>
where
Module<B>: VecZnxDftAlloc<B> + VecZnxDftFromVecZnx<B>,
{
fn prepare_alloc(&self, module: &Module<B>, scratch: &mut Scratch<B>) -> GLWEPublicKeyPrepared<Vec<u8>, B> {
let mut pk_prepared: GLWEPublicKeyPrepared<Vec<u8>, B> =
GLWEPublicKeyPrepared::alloc(module, self.n(), self.basek(), self.k(), self.rank());
pk_prepared.prepare(module, self, scratch);
pk_prepared
}
}
impl<DM: DataMut, DR: DataRef, B: Backend> Prepare<B, GLWEPublicKey<DR>> for GLWEPublicKeyPrepared<DM, B>
where
Module<B>: VecZnxDftFromVecZnx<B>,
{
fn prepare(&mut self, module: &Module<B>, other: &GLWEPublicKey<DR>, _scratch: &mut Scratch<B>) {
#[cfg(debug_assertions)]
{
assert_eq!(self.n(), other.n());
assert_eq!(self.size(), other.size());
}
(0..self.cols()).for_each(|i| {
module.vec_znx_dft_from_vec_znx(1, 0, &mut self.data, i, &other.data, i);
});
self.k = other.k;
self.basek = other.basek;
self.dist = other.dist;
}
}

View File

@@ -0,0 +1,77 @@
use poulpy_backend::hal::{
api::{SvpPPolAlloc, SvpPPolAllocBytes, SvpPrepare, ZnxInfos},
layouts::{Backend, Data, DataMut, DataRef, Module, SvpPPol},
};
use crate::{
dist::Distribution,
layouts::{
GLWESecret,
prepared::{Prepare, PrepareAlloc},
},
};
pub struct GLWESecretPrepared<D: Data, B: Backend> {
pub(crate) data: SvpPPol<D, B>,
pub(crate) dist: Distribution,
}
impl<B: Backend> GLWESecretPrepared<Vec<u8>, B> {
pub fn alloc(module: &Module<B>, n: usize, rank: usize) -> Self
where
Module<B>: SvpPPolAlloc<B>,
{
Self {
data: module.svp_ppol_alloc(n, rank),
dist: Distribution::NONE,
}
}
pub fn bytes_of(module: &Module<B>, n: usize, rank: usize) -> usize
where
Module<B>: SvpPPolAllocBytes,
{
module.svp_ppol_alloc_bytes(n, rank)
}
}
impl<D: Data, B: Backend> GLWESecretPrepared<D, B> {
pub fn n(&self) -> usize {
self.data.n()
}
pub fn log_n(&self) -> usize {
self.data.log_n()
}
pub fn rank(&self) -> usize {
self.data.cols()
}
}
impl<D: DataRef, B: Backend> PrepareAlloc<B, GLWESecretPrepared<Vec<u8>, B>> for GLWESecret<D>
where
Module<B>: SvpPrepare<B> + SvpPPolAlloc<B>,
{
fn prepare_alloc(
&self,
module: &Module<B>,
scratch: &mut poulpy_backend::hal::layouts::Scratch<B>,
) -> GLWESecretPrepared<Vec<u8>, B> {
let mut sk_dft: GLWESecretPrepared<Vec<u8>, B> = GLWESecretPrepared::alloc(module, self.n(), self.rank());
sk_dft.prepare(module, self, scratch);
sk_dft
}
}
impl<DM: DataMut, DR: DataRef, B: Backend> Prepare<B, GLWESecret<DR>> for GLWESecretPrepared<DM, B>
where
Module<B>: SvpPrepare<B>,
{
fn prepare(&mut self, module: &Module<B>, other: &GLWESecret<DR>, _scratch: &mut poulpy_backend::hal::layouts::Scratch<B>) {
(0..self.rank()).for_each(|i| {
module.svp_prepare(&mut self.data, i, &other.data, i);
});
self.dist = other.dist
}
}

View File

@@ -0,0 +1,91 @@
use poulpy_backend::hal::{
api::{VmpPMatAlloc, VmpPMatAllocBytes, VmpPrepare},
layouts::{Backend, Data, DataMut, DataRef, Module, Scratch, VmpPMat},
};
use crate::layouts::{
GLWEToLWESwitchingKey, Infos,
prepared::{GGLWESwitchingKeyPrepared, Prepare, PrepareAlloc},
};
#[derive(PartialEq, Eq)]
pub struct GLWEToLWESwitchingKeyPrepared<D: Data, B: Backend>(pub(crate) GGLWESwitchingKeyPrepared<D, B>);
impl<D: Data, B: Backend> Infos for GLWEToLWESwitchingKeyPrepared<D, B> {
type Inner = VmpPMat<D, B>;
fn inner(&self) -> &Self::Inner {
self.0.inner()
}
fn basek(&self) -> usize {
self.0.basek()
}
fn k(&self) -> usize {
self.0.k()
}
}
impl<D: Data, B: Backend> GLWEToLWESwitchingKeyPrepared<D, B> {
pub fn digits(&self) -> usize {
self.0.digits()
}
pub fn rank(&self) -> usize {
self.0.rank()
}
pub fn rank_in(&self) -> usize {
self.0.rank_in()
}
pub fn rank_out(&self) -> usize {
self.0.rank_out()
}
}
impl<B: Backend> GLWEToLWESwitchingKeyPrepared<Vec<u8>, B> {
pub fn alloc(module: &Module<B>, n: usize, basek: usize, k: usize, rows: usize, rank_in: usize) -> Self
where
Module<B>: VmpPMatAlloc<B>,
{
Self(GGLWESwitchingKeyPrepared::alloc(
module, n, basek, k, rows, 1, rank_in, 1,
))
}
pub fn bytes_of(module: &Module<B>, n: usize, basek: usize, k: usize, rows: usize, digits: usize, rank_in: usize) -> usize
where
Module<B>: VmpPMatAllocBytes,
{
GGLWESwitchingKeyPrepared::<Vec<u8>, B>::bytes_of(module, n, basek, k, rows, digits, rank_in, 1)
}
}
impl<D: DataRef, B: Backend> PrepareAlloc<B, GLWEToLWESwitchingKeyPrepared<Vec<u8>, B>> for GLWEToLWESwitchingKey<D>
where
Module<B>: VmpPrepare<B> + VmpPMatAlloc<B>,
{
fn prepare_alloc(&self, module: &Module<B>, scratch: &mut Scratch<B>) -> GLWEToLWESwitchingKeyPrepared<Vec<u8>, B> {
let mut ksk_prepared: GLWEToLWESwitchingKeyPrepared<Vec<u8>, B> = GLWEToLWESwitchingKeyPrepared::alloc(
module,
self.0.n(),
self.0.basek(),
self.0.k(),
self.0.rows(),
self.0.rank_in(),
);
ksk_prepared.prepare(module, self, scratch);
ksk_prepared
}
}
impl<DM: DataMut, DR: DataRef, B: Backend> Prepare<B, GLWEToLWESwitchingKey<DR>> for GLWEToLWESwitchingKeyPrepared<DM, B>
where
Module<B>: VmpPrepare<B>,
{
fn prepare(&mut self, module: &Module<B>, other: &GLWEToLWESwitchingKey<DR>, scratch: &mut Scratch<B>) {
self.0.prepare(module, &other.0, scratch);
}
}

View File

@@ -0,0 +1,90 @@
use poulpy_backend::hal::{
api::{VmpPMatAlloc, VmpPMatAllocBytes, VmpPrepare},
layouts::{Backend, Data, DataMut, DataRef, Module, Scratch, VmpPMat},
};
use crate::layouts::{
Infos, LWESwitchingKey,
prepared::{GGLWESwitchingKeyPrepared, Prepare, PrepareAlloc},
};
#[derive(PartialEq, Eq)]
pub struct LWESwitchingKeyPrepared<D: Data, B: Backend>(pub(crate) GGLWESwitchingKeyPrepared<D, B>);
impl<D: Data, B: Backend> Infos for LWESwitchingKeyPrepared<D, B> {
type Inner = VmpPMat<D, B>;
fn inner(&self) -> &Self::Inner {
self.0.inner()
}
fn basek(&self) -> usize {
self.0.basek()
}
fn k(&self) -> usize {
self.0.k()
}
}
impl<D: Data, B: Backend> LWESwitchingKeyPrepared<D, B> {
pub fn digits(&self) -> usize {
self.0.digits()
}
pub fn rank(&self) -> usize {
self.0.rank()
}
pub fn rank_in(&self) -> usize {
self.0.rank_in()
}
pub fn rank_out(&self) -> usize {
self.0.rank_out()
}
}
impl<B: Backend> LWESwitchingKeyPrepared<Vec<u8>, B> {
pub fn alloc(module: &Module<B>, n: usize, basek: usize, k: usize, rows: usize) -> Self
where
Module<B>: VmpPMatAlloc<B>,
{
Self(GGLWESwitchingKeyPrepared::alloc(
module, n, basek, k, rows, 1, 1, 1,
))
}
pub fn bytes_of(module: &Module<B>, n: usize, basek: usize, k: usize, rows: usize, digits: usize) -> usize
where
Module<B>: VmpPMatAllocBytes,
{
GGLWESwitchingKeyPrepared::<Vec<u8>, B>::bytes_of(module, n, basek, k, rows, digits, 1, 1)
}
}
impl<D: DataRef, B: Backend> PrepareAlloc<B, LWESwitchingKeyPrepared<Vec<u8>, B>> for LWESwitchingKey<D>
where
Module<B>: VmpPrepare<B> + VmpPMatAlloc<B>,
{
fn prepare_alloc(&self, module: &Module<B>, scratch: &mut Scratch<B>) -> LWESwitchingKeyPrepared<Vec<u8>, B> {
let mut ksk_prepared: LWESwitchingKeyPrepared<Vec<u8>, B> = LWESwitchingKeyPrepared::alloc(
module,
self.0.n(),
self.0.basek(),
self.0.k(),
self.0.rows(),
);
ksk_prepared.prepare(module, self, scratch);
ksk_prepared
}
}
impl<DM: DataMut, DR: DataRef, B: Backend> Prepare<B, LWESwitchingKey<DR>> for LWESwitchingKeyPrepared<DM, B>
where
Module<B>: VmpPrepare<B>,
{
fn prepare(&mut self, module: &Module<B>, other: &LWESwitchingKey<DR>, scratch: &mut Scratch<B>) {
self.0.prepare(module, &other.0, scratch);
}
}

View File

@@ -0,0 +1,92 @@
use poulpy_backend::hal::{
api::{VmpPMatAlloc, VmpPMatAllocBytes, VmpPrepare},
layouts::{Backend, Data, DataMut, DataRef, Module, Scratch, VmpPMat},
};
use crate::layouts::{
Infos, LWEToGLWESwitchingKey,
prepared::{GGLWESwitchingKeyPrepared, Prepare, PrepareAlloc},
};
/// A special [GLWESwitchingKey] required to for the conversion from [LWECiphertext] to [GLWECiphertext].
#[derive(PartialEq, Eq)]
pub struct LWEToGLWESwitchingKeyPrepared<D: Data, B: Backend>(pub(crate) GGLWESwitchingKeyPrepared<D, B>);
impl<D: Data, B: Backend> Infos for LWEToGLWESwitchingKeyPrepared<D, B> {
type Inner = VmpPMat<D, B>;
fn inner(&self) -> &Self::Inner {
self.0.inner()
}
fn basek(&self) -> usize {
self.0.basek()
}
fn k(&self) -> usize {
self.0.k()
}
}
impl<D: Data, B: Backend> LWEToGLWESwitchingKeyPrepared<D, B> {
pub fn digits(&self) -> usize {
self.0.digits()
}
pub fn rank(&self) -> usize {
self.0.rank()
}
pub fn rank_in(&self) -> usize {
self.0.rank_in()
}
pub fn rank_out(&self) -> usize {
self.0.rank_out()
}
}
impl<B: Backend> LWEToGLWESwitchingKeyPrepared<Vec<u8>, B> {
pub fn alloc(module: &Module<B>, n: usize, basek: usize, k: usize, rows: usize, rank_out: usize) -> Self
where
Module<B>: VmpPMatAlloc<B>,
{
Self(GGLWESwitchingKeyPrepared::alloc(
module, n, basek, k, rows, 1, 1, rank_out,
))
}
pub fn bytes_of(module: &Module<B>, n: usize, basek: usize, k: usize, rows: usize, digits: usize, rank_out: usize) -> usize
where
Module<B>: VmpPMatAllocBytes,
{
GGLWESwitchingKeyPrepared::<Vec<u8>, B>::bytes_of(module, n, basek, k, rows, digits, 1, rank_out)
}
}
impl<D: DataRef, B: Backend> PrepareAlloc<B, LWEToGLWESwitchingKeyPrepared<Vec<u8>, B>> for LWEToGLWESwitchingKey<D>
where
Module<B>: VmpPrepare<B> + VmpPMatAlloc<B>,
{
fn prepare_alloc(&self, module: &Module<B>, scratch: &mut Scratch<B>) -> LWEToGLWESwitchingKeyPrepared<Vec<u8>, B> {
let mut ksk_prepared: LWEToGLWESwitchingKeyPrepared<Vec<u8>, B> = LWEToGLWESwitchingKeyPrepared::alloc(
module,
self.0.n(),
self.0.basek(),
self.0.k(),
self.0.rows(),
self.0.rank_out(),
);
ksk_prepared.prepare(module, self, scratch);
ksk_prepared
}
}
impl<DM: DataMut, DR: DataRef, B: Backend> Prepare<B, LWEToGLWESwitchingKey<DR>> for LWEToGLWESwitchingKeyPrepared<DM, B>
where
Module<B>: VmpPrepare<B>,
{
fn prepare(&mut self, module: &Module<B>, other: &LWEToGLWESwitchingKey<DR>, scratch: &mut Scratch<B>) {
self.0.prepare(module, &other.0, scratch);
}
}

View File

@@ -0,0 +1,30 @@
mod gglwe_atk;
mod gglwe_ct;
mod gglwe_ksk;
mod gglwe_tsk;
mod ggsw_ct;
mod glwe_pk;
mod glwe_sk;
mod glwe_to_lwe_ksk;
mod lwe_ksk;
mod lwe_to_glwe_ksk;
pub use gglwe_atk::*;
pub use gglwe_ct::*;
pub use gglwe_ksk::*;
pub use gglwe_tsk::*;
pub use ggsw_ct::*;
pub use glwe_pk::*;
pub use glwe_sk::*;
pub use glwe_to_lwe_ksk::*;
pub use lwe_ksk::*;
pub use lwe_to_glwe_ksk::*;
use poulpy_backend::hal::layouts::{Backend, Module, Scratch};
pub trait PrepareAlloc<B: Backend, T> {
fn prepare_alloc(&self, module: &Module<B>, scratch: &mut Scratch<B>) -> T;
}
pub trait Prepare<B: Backend, T> {
fn prepare(&mut self, module: &Module<B>, other: &T, scratch: &mut Scratch<B>);
}