This commit is contained in:
Pro7ech
2025-10-12 21:34:10 +02:00
committed by Jean-Philippe Bossuat
parent f72363cc4b
commit 2b2b994f7d
169 changed files with 8705 additions and 7677 deletions

View File

@@ -1,24 +1,28 @@
use poulpy_hal::{
api::{VecZnxCopy, VecZnxFillUniform},
layouts::{Backend, Data, DataMut, DataRef, FillUniform, Module, ReaderFrom, WriterTo},
source::Source,
};
use crate::layouts::{
Base2K, Degree, Dnum, Dsize, GGLWEAutomorphismKey, GGLWEInfos, GLWEInfos, LWEInfos, Rank, TorusPrecision,
compressed::{Decompress, GGLWESwitchingKeyCompressed},
AutomorphismKey, AutomorphismKeyToMut, Base2K, Dnum, Dsize, GGLWEInfos, GLWEInfos, LWEInfos, Rank, RingDegree,
TorusPrecision,
compressed::{
GLWESwitchingKeyCompressed, GLWESwitchingKeyCompressedAlloc, GLWESwitchingKeyCompressedToMut,
GLWESwitchingKeyCompressedToRef, GLWESwitchingKeyDecompress,
},
prepared::{GetAutomorphismGaloisElement, SetAutomorphismGaloisElement},
};
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use std::fmt;
#[derive(PartialEq, Eq, Clone)]
pub struct GGLWEAutomorphismKeyCompressed<D: Data> {
pub(crate) key: GGLWESwitchingKeyCompressed<D>,
pub struct AutomorphismKeyCompressed<D: Data> {
pub(crate) key: GLWESwitchingKeyCompressed<D>,
pub(crate) p: i64,
}
impl<D: Data> LWEInfos for GGLWEAutomorphismKeyCompressed<D> {
fn n(&self) -> Degree {
impl<D: Data> LWEInfos for AutomorphismKeyCompressed<D> {
fn n(&self) -> RingDegree {
self.key.n()
}
@@ -34,13 +38,13 @@ impl<D: Data> LWEInfos for GGLWEAutomorphismKeyCompressed<D> {
self.key.size()
}
}
impl<D: Data> GLWEInfos for GGLWEAutomorphismKeyCompressed<D> {
impl<D: Data> GLWEInfos for AutomorphismKeyCompressed<D> {
fn rank(&self) -> Rank {
self.rank_out()
}
}
impl<D: Data> GGLWEInfos for GGLWEAutomorphismKeyCompressed<D> {
impl<D: Data> GGLWEInfos for AutomorphismKeyCompressed<D> {
fn rank_in(&self) -> Rank {
self.key.rank_in()
}
@@ -58,76 +62,185 @@ impl<D: Data> GGLWEInfos for GGLWEAutomorphismKeyCompressed<D> {
}
}
impl<D: DataRef> fmt::Debug for GGLWEAutomorphismKeyCompressed<D> {
impl<D: DataRef> fmt::Debug for AutomorphismKeyCompressed<D> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{self}")
}
}
impl<D: DataMut> FillUniform for GGLWEAutomorphismKeyCompressed<D> {
impl<D: DataMut> FillUniform for AutomorphismKeyCompressed<D> {
fn fill_uniform(&mut self, log_bound: usize, source: &mut Source) {
self.key.fill_uniform(log_bound, source);
}
}
impl<D: DataRef> fmt::Display for GGLWEAutomorphismKeyCompressed<D> {
impl<D: DataRef> fmt::Display for AutomorphismKeyCompressed<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<A>(infos: &A) -> Self
where
A: GGLWEInfos,
{
debug_assert_eq!(infos.rank_in(), infos.rank_out());
Self {
key: GGLWESwitchingKeyCompressed::alloc(infos),
pub trait AutomorphismKeyCompressedAlloc
where
Self: GLWESwitchingKeyCompressedAlloc,
{
fn alloc_automorphism_key_compressed(
&self,
base2k: Base2K,
k: TorusPrecision,
rank: Rank,
dnum: Dnum,
dsize: Dsize,
) -> AutomorphismKeyCompressed<Vec<u8>> {
AutomorphismKeyCompressed {
key: self.alloc_glwe_switching_key_compressed(base2k, k, rank, rank, dnum, dsize),
p: 0,
}
}
pub fn alloc_with(n: Degree, base2k: Base2K, k: TorusPrecision, rank: Rank, dnum: Dnum, dsize: Dsize) -> Self {
Self {
key: GGLWESwitchingKeyCompressed::alloc_with(n, base2k, k, rank, rank, dnum, dsize),
p: 0,
}
}
pub fn alloc_bytes<A>(infos: &A) -> usize
fn alloc_automorphism_key_compressed_from_infos<A>(&self, infos: &A) -> AutomorphismKeyCompressed<Vec<u8>>
where
A: GGLWEInfos,
{
debug_assert_eq!(infos.rank_in(), infos.rank_out());
GGLWESwitchingKeyCompressed::alloc_bytes(infos)
assert_eq!(infos.rank_in(), infos.rank_out());
self.alloc_automorphism_key_compressed(
infos.base2k(),
infos.k(),
infos.rank(),
infos.dnum(),
infos.dsize(),
)
}
pub fn alloc_bytes_with(n: Degree, base2k: Base2K, k: TorusPrecision, rank: Rank, dnum: Dnum, dsize: Dsize) -> usize {
GGLWESwitchingKeyCompressed::alloc_bytes_with(n, base2k, k, rank, dnum, dsize)
fn bytes_of_automorphism_key_compressed(
&self,
base2k: Base2K,
k: TorusPrecision,
rank: Rank,
dnum: Dnum,
dsize: Dsize,
) -> usize {
self.bytes_of_glwe_switching_key_compressed(base2k, k, rank, dnum, dsize)
}
fn bytes_of_automorphism_key_compressed_from_infos<A>(&self, infos: &A) -> usize
where
A: GGLWEInfos,
{
assert_eq!(infos.rank_in(), infos.rank_out());
self.bytes_of_automorphism_key_compressed(
infos.base2k(),
infos.k(),
infos.rank(),
infos.dnum(),
infos.dsize(),
)
}
}
impl<D: DataMut> ReaderFrom for GGLWEAutomorphismKeyCompressed<D> {
impl AutomorphismKeyCompressed<Vec<u8>> {
pub fn alloc_from_infos<A, M>(module: &M, infos: &A) -> Self
where
A: GGLWEInfos,
M: AutomorphismKeyCompressedAlloc,
{
module.alloc_automorphism_key_compressed_from_infos(infos)
}
pub fn alloc<M>(module: &M, base2k: Base2K, k: TorusPrecision, rank: Rank, dnum: Dnum, dsize: Dsize) -> Self
where
M: AutomorphismKeyCompressedAlloc,
{
module.alloc_automorphism_key_compressed(base2k, k, rank, dnum, dsize)
}
pub fn bytes_of_from_infos<A, M>(module: &M, infos: &A) -> usize
where
A: GGLWEInfos,
M: AutomorphismKeyCompressedAlloc,
{
module.bytes_of_automorphism_key_compressed_from_infos(infos)
}
pub fn bytes_of<M>(module: &M, base2k: Base2K, k: TorusPrecision, rank: Rank, dnum: Dnum, dsize: Dsize) -> usize
where
M: AutomorphismKeyCompressedAlloc,
{
module.bytes_of_automorphism_key_compressed(base2k, k, rank, dnum, dsize)
}
}
impl<D: DataMut> ReaderFrom for AutomorphismKeyCompressed<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> {
impl<D: DataRef> WriterTo for AutomorphismKeyCompressed<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>
pub trait AutomorphismKeyDecompress
where
Module<B>: VecZnxFillUniform + VecZnxCopy,
Self: GLWESwitchingKeyDecompress,
{
fn decompress(&mut self, module: &Module<B>, other: &GGLWEAutomorphismKeyCompressed<DR>) {
self.key.decompress(module, &other.key);
self.p = other.p;
fn decompress_automorphism_key<R, O>(&self, res: &mut R, other: &O)
where
R: AutomorphismKeyToMut + SetAutomorphismGaloisElement,
O: AutomorphismKeyCompressedToRef + GetAutomorphismGaloisElement,
{
self.decompress_glwe_switching_key(&mut res.to_mut().key, &other.to_ref().key);
res.set_p(other.p());
}
}
impl<B: Backend> AutomorphismKeyDecompress for Module<B> where Self: AutomorphismKeyDecompress {}
impl<D: DataMut> AutomorphismKey<D>
where
Self: SetAutomorphismGaloisElement,
{
pub fn decompress<O, M>(&mut self, module: &M, other: &O)
where
O: AutomorphismKeyCompressedToRef + GetAutomorphismGaloisElement,
M: AutomorphismKeyDecompress,
{
module.decompress_automorphism_key(self, other);
}
}
pub trait AutomorphismKeyCompressedToRef {
fn to_ref(&self) -> AutomorphismKeyCompressed<&[u8]>;
}
impl<D: DataRef> AutomorphismKeyCompressedToRef for AutomorphismKeyCompressed<D>
where
GLWESwitchingKeyCompressed<D>: GLWESwitchingKeyCompressedToRef,
{
fn to_ref(&self) -> AutomorphismKeyCompressed<&[u8]> {
AutomorphismKeyCompressed {
key: self.key.to_ref(),
p: self.p,
}
}
}
pub trait AutomorphismKeyCompressedToMut {
fn to_mut(&mut self) -> AutomorphismKeyCompressed<&mut [u8]>;
}
impl<D: DataMut> AutomorphismKeyCompressedToMut for AutomorphismKeyCompressed<D>
where
GLWESwitchingKeyCompressed<D>: GLWESwitchingKeyCompressedToMut,
{
fn to_mut(&mut self) -> AutomorphismKeyCompressed<&mut [u8]> {
AutomorphismKeyCompressed {
p: self.p,
key: self.key.to_mut(),
}
}
}

View File

@@ -1,18 +1,20 @@
use poulpy_hal::{
api::{VecZnxCopy, VecZnxFillUniform},
layouts::{Backend, Data, DataMut, DataRef, FillUniform, MatZnx, Module, ReaderFrom, WriterTo, ZnxInfos},
layouts::{
Backend, Data, DataMut, DataRef, FillUniform, MatZnx, MatZnxToMut, MatZnxToRef, Module, ReaderFrom, WriterTo, ZnxInfos,
},
source::Source,
};
use crate::layouts::{
Base2K, Degree, Dnum, Dsize, GGLWECiphertext, GGLWEInfos, GLWEInfos, LWEInfos, Rank, TorusPrecision,
compressed::{Decompress, GLWECiphertextCompressed},
Base2K, Dnum, Dsize, GGLWE, GGLWEInfos, GGLWEToMut, GLWEInfos, GetRingDegree, LWEInfos, Rank, RingDegree, TorusPrecision,
compressed::{GLWECompressed, GLWEDecompress},
};
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use std::fmt;
#[derive(PartialEq, Eq, Clone)]
pub struct GGLWECiphertextCompressed<D: Data> {
pub struct GGLWECompressed<D: Data> {
pub(crate) data: MatZnx<D>,
pub(crate) base2k: Base2K,
pub(crate) k: TorusPrecision,
@@ -21,9 +23,9 @@ pub struct GGLWECiphertextCompressed<D: Data> {
pub(crate) seed: Vec<[u8; 32]>,
}
impl<D: Data> LWEInfos for GGLWECiphertextCompressed<D> {
fn n(&self) -> Degree {
Degree(self.data.n() as u32)
impl<D: Data> LWEInfos for GGLWECompressed<D> {
fn n(&self) -> RingDegree {
RingDegree(self.data.n() as u32)
}
fn base2k(&self) -> Base2K {
@@ -38,13 +40,13 @@ impl<D: Data> LWEInfos for GGLWECiphertextCompressed<D> {
self.data.size()
}
}
impl<D: Data> GLWEInfos for GGLWECiphertextCompressed<D> {
impl<D: Data> GLWEInfos for GGLWECompressed<D> {
fn rank(&self) -> Rank {
self.rank_out()
}
}
impl<D: Data> GGLWEInfos for GGLWECiphertextCompressed<D> {
impl<D: Data> GGLWEInfos for GGLWECompressed<D> {
fn rank_in(&self) -> Rank {
Rank(self.data.cols_in() as u32)
}
@@ -62,53 +64,41 @@ impl<D: Data> GGLWEInfos for GGLWECiphertextCompressed<D> {
}
}
impl<D: DataRef> fmt::Debug for GGLWECiphertextCompressed<D> {
impl<D: DataRef> fmt::Debug for GGLWECompressed<D> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{self}")
}
}
impl<D: DataMut> FillUniform for GGLWECiphertextCompressed<D> {
impl<D: DataMut> FillUniform for GGLWECompressed<D> {
fn fill_uniform(&mut self, log_bound: usize, source: &mut Source) {
self.data.fill_uniform(log_bound, source);
}
}
impl<D: DataRef> fmt::Display for GGLWECiphertextCompressed<D> {
impl<D: DataRef> fmt::Display for GGLWECompressed<D> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"(GGLWECiphertextCompressed: base2k={} k={} dsize={}) {}",
"(GGLWECompressed: base2k={} k={} dsize={}) {}",
self.base2k.0, self.k.0, self.dsize.0, self.data
)
}
}
impl GGLWECiphertextCompressed<Vec<u8>> {
pub fn alloc<A>(infos: &A) -> Self
where
A: GGLWEInfos,
{
Self::alloc_with(
infos.n(),
infos.base2k(),
infos.k(),
infos.rank_in(),
infos.rank_out(),
infos.dnum(),
infos.dsize(),
)
}
pub fn alloc_with(
n: Degree,
pub trait GGLWECompressedAlloc
where
Self: GetRingDegree,
{
fn alloc_gglwe_compressed(
&self,
base2k: Base2K,
k: TorusPrecision,
rank_in: Rank,
rank_out: Rank,
dnum: Dnum,
dsize: Dsize,
) -> Self {
) -> GGLWECompressed<Vec<u8>> {
let size: usize = k.0.div_ceil(base2k.0) as usize;
debug_assert!(
size as u32 > dsize.0,
@@ -123,9 +113,9 @@ impl GGLWECiphertextCompressed<Vec<u8>> {
dsize.0,
);
Self {
GGLWECompressed {
data: MatZnx::alloc(
n.into(),
self.ring_degree().into(),
dnum.into(),
rank_in.into(),
1,
@@ -139,21 +129,22 @@ impl GGLWECiphertextCompressed<Vec<u8>> {
}
}
pub fn alloc_bytes<A>(infos: &A) -> usize
fn alloc_gglwe_compressed_from_infos<A>(&self, infos: &A) -> GGLWECompressed<Vec<u8>>
where
A: GGLWEInfos,
{
Self::alloc_bytes_with(
infos.n(),
assert_eq!(infos.n(), self.ring_degree());
self.alloc_gglwe_compressed(
infos.base2k(),
infos.k(),
infos.rank_in(),
infos.rank_out(),
infos.dnum(),
infos.dsize(),
)
}
pub fn alloc_bytes_with(n: Degree, base2k: Base2K, k: TorusPrecision, rank_in: Rank, dnum: Dnum, dsize: Dsize) -> usize {
fn bytes_of_gglwe_compressed(&self, base2k: Base2K, k: TorusPrecision, rank_in: Rank, dnum: Dnum, dsize: Dsize) -> usize {
let size: usize = k.0.div_ceil(base2k.0) as usize;
debug_assert!(
size as u32 > dsize.0,
@@ -168,20 +159,76 @@ impl GGLWECiphertextCompressed<Vec<u8>> {
dsize.0,
);
MatZnx::alloc_bytes(
n.into(),
MatZnx::bytes_of(
self.ring_degree().into(),
dnum.into(),
rank_in.into(),
1,
k.0.div_ceil(base2k.0) as usize,
)
}
fn bytes_of_gglwe_compressed_from_infos<A>(&self, infos: &A) -> usize
where
A: GGLWEInfos,
{
assert_eq!(infos.n(), self.ring_degree());
self.bytes_of_gglwe_compressed(
infos.base2k(),
infos.k(),
infos.rank_in(),
infos.dnum(),
infos.dsize(),
)
}
}
impl<D: DataRef> GGLWECiphertextCompressed<D> {
pub(crate) fn at(&self, row: usize, col: usize) -> GLWECiphertextCompressed<&[u8]> {
impl<B: Backend> GGLWECompressedAlloc for Module<B> where Self: GetRingDegree {}
impl GGLWECompressed<Vec<u8>> {
pub fn alloc_from_infos<A, M>(module: &M, infos: &A) -> Self
where
A: GGLWEInfos,
M: GGLWECompressedAlloc,
{
module.alloc_gglwe_compressed_from_infos(infos)
}
pub fn alloc<M>(
module: &M,
base2k: Base2K,
k: TorusPrecision,
rank_in: Rank,
rank_out: Rank,
dnum: Dnum,
dsize: Dsize,
) -> Self
where
M: GGLWECompressedAlloc,
{
module.alloc_gglwe_compressed(base2k, k, rank_in, rank_out, dnum, dsize)
}
pub fn bytes_of_from_infos<A, M>(module: &M, infos: &A) -> usize
where
A: GGLWEInfos,
M: GGLWECompressedAlloc,
{
module.bytes_of_gglwe_compressed_from_infos(infos)
}
pub fn byte_of<M>(module: &M, base2k: Base2K, k: TorusPrecision, rank_in: Rank, dnum: Dnum, dsize: Dsize) -> usize
where
M: GGLWECompressedAlloc,
{
module.bytes_of_gglwe_compressed(base2k, k, rank_in, dnum, dsize)
}
}
impl<D: DataRef> GGLWECompressed<D> {
pub(crate) fn at(&self, row: usize, col: usize) -> GLWECompressed<&[u8]> {
let rank_in: usize = self.rank_in().into();
GLWECiphertextCompressed {
GLWECompressed {
data: self.data.at(row, col),
k: self.k,
base2k: self.base2k,
@@ -191,10 +238,10 @@ impl<D: DataRef> GGLWECiphertextCompressed<D> {
}
}
impl<D: DataMut> GGLWECiphertextCompressed<D> {
pub(crate) fn at_mut(&mut self, row: usize, col: usize) -> GLWECiphertextCompressed<&mut [u8]> {
impl<D: DataMut> GGLWECompressed<D> {
pub(crate) fn at_mut(&mut self, row: usize, col: usize) -> GLWECompressed<&mut [u8]> {
let rank_in: usize = self.rank_in().into();
GLWECiphertextCompressed {
GLWECompressed {
k: self.k,
base2k: self.base2k,
rank: self.rank_out,
@@ -204,7 +251,7 @@ impl<D: DataMut> GGLWECiphertextCompressed<D> {
}
}
impl<D: DataMut> ReaderFrom for GGLWECiphertextCompressed<D> {
impl<D: DataMut> ReaderFrom for GGLWECompressed<D> {
fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> {
self.k = TorusPrecision(reader.read_u32::<LittleEndian>()?);
self.base2k = Base2K(reader.read_u32::<LittleEndian>()?);
@@ -219,7 +266,7 @@ impl<D: DataMut> ReaderFrom for GGLWECiphertextCompressed<D> {
}
}
impl<D: DataRef> WriterTo for GGLWECiphertextCompressed<D> {
impl<D: DataRef> WriterTo for GGLWECompressed<D> {
fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
writer.write_u32::<LittleEndian>(self.k.into())?;
writer.write_u32::<LittleEndian>(self.base2k.into())?;
@@ -233,59 +280,73 @@ impl<D: DataRef> WriterTo for GGLWECiphertextCompressed<D> {
}
}
impl<D: DataMut, B: Backend, DR: DataRef> Decompress<B, GGLWECiphertextCompressed<DR>> for GGLWECiphertext<D>
pub trait GGLWEDecompress
where
Module<B>: VecZnxFillUniform + VecZnxCopy,
Self: GLWEDecompress,
{
fn decompress(&mut self, module: &Module<B>, other: &GGLWECiphertextCompressed<DR>) {
#[cfg(debug_assertions)]
{
assert_eq!(
self.n(),
other.n(),
"invalid receiver: self.n()={} != other.n()={}",
self.n(),
other.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()
);
fn decompress_gglwe<R, O>(&self, res: &mut R, other: &O)
where
R: GGLWEToMut,
O: GGLWECompressedToRef,
{
let res: &mut GGLWE<&mut [u8]> = &mut res.to_mut();
let other: &GGLWECompressed<&[u8]> = &other.to_ref();
assert_eq!(
self.dnum(),
other.dnum(),
"invalid receiver: self.dnum()={} != other.dnum()={}",
self.dnum(),
other.dnum()
);
assert_eq!(res.gglwe_layout(), other.gglwe_layout());
let rank_in: usize = res.rank_in().into();
let dnum: usize = res.dnum().into();
for row_i in 0..dnum {
for col_i in 0..rank_in {
self.decompress_glwe(&mut res.at_mut(row_i, col_i), &other.at(row_i, col_i));
}
}
}
}
impl<B: Backend> GGLWEDecompress for Module<B> where Self: VecZnxFillUniform + VecZnxCopy {}
impl<D: DataMut> GGLWE<D> {
pub fn decompress<O, M>(&mut self, module: &M, other: &O)
where
O: GGLWECompressedToRef,
M: GGLWEDecompress,
{
module.decompress_gglwe(self, other);
}
}
pub trait GGLWECompressedToMut {
fn to_mut(&mut self) -> GGLWECompressed<&mut [u8]>;
}
impl<D: DataMut> GGLWECompressedToMut for GGLWECompressed<D> {
fn to_mut(&mut self) -> GGLWECompressed<&mut [u8]> {
GGLWECompressed {
k: self.k(),
base2k: self.base2k(),
dsize: self.dsize(),
seed: self.seed.clone(),
rank_out: self.rank_out,
data: self.data.to_mut(),
}
}
}
pub trait GGLWECompressedToRef {
fn to_ref(&self) -> GGLWECompressed<&[u8]>;
}
impl<D: DataRef> GGLWECompressedToRef for GGLWECompressed<D> {
fn to_ref(&self) -> GGLWECompressed<&[u8]> {
GGLWECompressed {
k: self.k(),
base2k: self.base2k(),
dsize: self.dsize(),
seed: self.seed.clone(),
rank_out: self.rank_out,
data: self.data.to_ref(),
}
let rank_in: usize = self.rank_in().into();
let dnum: usize = self.dnum().into();
(0..rank_in).for_each(|col_i| {
(0..dnum).for_each(|row_i| {
self.at_mut(row_i, col_i)
.decompress(module, &other.at(row_i, col_i));
});
});
}
}

View File

@@ -1,25 +1,25 @@
use poulpy_hal::{
api::{VecZnxCopy, VecZnxFillUniform},
layouts::{Backend, Data, DataMut, DataRef, FillUniform, Module, ReaderFrom, WriterTo},
source::Source,
};
use crate::layouts::{
Base2K, Degree, Dnum, Dsize, GGLWEInfos, GGLWESwitchingKey, GLWEInfos, LWEInfos, Rank, TorusPrecision,
compressed::{Decompress, GGLWECiphertextCompressed},
Base2K, Dnum, Dsize, GGLWEInfos, GLWEInfos, GLWESwitchingKey, GLWESwitchingKeySetMetaData, GLWESwitchingKeyToMut, LWEInfos,
Rank, RingDegree, TorusPrecision,
compressed::{GGLWECompressed, GGLWECompressedAlloc, GGLWECompressedToMut, GGLWECompressedToRef, GGLWEDecompress},
};
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use std::fmt;
#[derive(PartialEq, Eq, Clone)]
pub struct GGLWESwitchingKeyCompressed<D: Data> {
pub(crate) key: GGLWECiphertextCompressed<D>,
pub struct GLWESwitchingKeyCompressed<D: Data> {
pub(crate) key: GGLWECompressed<D>,
pub(crate) sk_in_n: usize, // Degree of sk_in
pub(crate) sk_out_n: usize, // Degree of sk_out
}
impl<D: Data> LWEInfos for GGLWESwitchingKeyCompressed<D> {
fn n(&self) -> Degree {
impl<D: Data> LWEInfos for GLWESwitchingKeyCompressed<D> {
fn n(&self) -> RingDegree {
self.key.n()
}
@@ -35,13 +35,13 @@ impl<D: Data> LWEInfos for GGLWESwitchingKeyCompressed<D> {
self.key.size()
}
}
impl<D: Data> GLWEInfos for GGLWESwitchingKeyCompressed<D> {
impl<D: Data> GLWEInfos for GLWESwitchingKeyCompressed<D> {
fn rank(&self) -> Rank {
self.rank_out()
}
}
impl<D: Data> GGLWEInfos for GGLWESwitchingKeyCompressed<D> {
impl<D: Data> GGLWEInfos for GLWESwitchingKeyCompressed<D> {
fn rank_in(&self) -> Rank {
self.key.rank_in()
}
@@ -59,19 +59,19 @@ impl<D: Data> GGLWEInfos for GGLWESwitchingKeyCompressed<D> {
}
}
impl<D: DataRef> fmt::Debug for GGLWESwitchingKeyCompressed<D> {
impl<D: DataRef> fmt::Debug for GLWESwitchingKeyCompressed<D> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{self}")
}
}
impl<D: DataMut> FillUniform for GGLWESwitchingKeyCompressed<D> {
impl<D: DataMut> FillUniform for GLWESwitchingKeyCompressed<D> {
fn fill_uniform(&mut self, log_bound: usize, source: &mut Source) {
self.key.fill_uniform(log_bound, source);
}
}
impl<D: DataRef> fmt::Display for GGLWESwitchingKeyCompressed<D> {
impl<D: DataRef> fmt::Display for GLWESwitchingKeyCompressed<D> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
@@ -81,47 +81,100 @@ impl<D: DataRef> fmt::Display for GGLWESwitchingKeyCompressed<D> {
}
}
impl GGLWESwitchingKeyCompressed<Vec<u8>> {
pub fn alloc<A>(infos: &A) -> Self
where
A: GGLWEInfos,
{
GGLWESwitchingKeyCompressed {
key: GGLWECiphertextCompressed::alloc(infos),
sk_in_n: 0,
sk_out_n: 0,
}
}
pub fn alloc_with(
n: Degree,
pub trait GLWESwitchingKeyCompressedAlloc
where
Self: GGLWECompressedAlloc,
{
fn alloc_glwe_switching_key_compressed(
&self,
base2k: Base2K,
k: TorusPrecision,
rank_in: Rank,
rank_out: Rank,
dnum: Dnum,
dsize: Dsize,
) -> Self {
GGLWESwitchingKeyCompressed {
key: GGLWECiphertextCompressed::alloc_with(n, base2k, k, rank_in, rank_out, dnum, dsize),
) -> GLWESwitchingKeyCompressed<Vec<u8>> {
GLWESwitchingKeyCompressed {
key: self.alloc_gglwe_compressed(base2k, k, rank_in, rank_out, dnum, dsize),
sk_in_n: 0,
sk_out_n: 0,
}
}
pub fn alloc_bytes<A>(infos: &A) -> usize
fn alloc_glwe_switching_key_compressed_from_infos<A>(&self, infos: &A) -> GLWESwitchingKeyCompressed<Vec<u8>>
where
A: GGLWEInfos,
{
GGLWECiphertextCompressed::alloc_bytes(infos)
self.alloc_glwe_switching_key_compressed(
infos.base2k(),
infos.k(),
infos.rank_in(),
infos.rank_out(),
infos.dnum(),
infos.dsize(),
)
}
pub fn alloc_bytes_with(n: Degree, base2k: Base2K, k: TorusPrecision, rank_in: Rank, dnum: Dnum, dsize: Dsize) -> usize {
GGLWECiphertextCompressed::alloc_bytes_with(n, base2k, k, rank_in, dnum, dsize)
fn bytes_of_glwe_switching_key_compressed(
&self,
base2k: Base2K,
k: TorusPrecision,
rank_in: Rank,
dnum: Dnum,
dsize: Dsize,
) -> usize {
self.bytes_of_gglwe_compressed(base2k, k, rank_in, dnum, dsize)
}
fn bytes_of_glwe_switching_key_compressed_from_infos<A>(&self, infos: &A) -> usize
where
A: GGLWEInfos,
{
self.bytes_of_gglwe_compressed_from_infos(infos)
}
}
impl<D: DataMut> ReaderFrom for GGLWESwitchingKeyCompressed<D> {
impl GLWESwitchingKeyCompressed<Vec<u8>> {
pub fn alloc_from_infos<A, M>(module: &M, infos: &A) -> Self
where
A: GGLWEInfos,
M: GLWESwitchingKeyCompressedAlloc,
{
module.alloc_glwe_switching_key_compressed_from_infos(infos)
}
pub fn alloc<M>(
module: &M,
base2k: Base2K,
k: TorusPrecision,
rank_in: Rank,
rank_out: Rank,
dnum: Dnum,
dsize: Dsize,
) -> Self
where
M: GLWESwitchingKeyCompressedAlloc,
{
module.alloc_glwe_switching_key_compressed(base2k, k, rank_in, rank_out, dnum, dsize)
}
pub fn bytes_of_from_infos<A, M>(module: &M, infos: &A) -> usize
where
A: GGLWEInfos,
M: GLWESwitchingKeyCompressedAlloc,
{
module.bytes_of_glwe_switching_key_compressed_from_infos(infos)
}
pub fn bytes_of<M>(module: &M, base2k: Base2K, k: TorusPrecision, rank_in: Rank, dnum: Dnum, dsize: Dsize) -> usize
where
M: GLWESwitchingKeyCompressedAlloc,
{
module.bytes_of_glwe_switching_key_compressed(base2k, k, rank_in, dnum, dsize)
}
}
impl<D: DataMut> ReaderFrom for GLWESwitchingKeyCompressed<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;
@@ -129,7 +182,7 @@ impl<D: DataMut> ReaderFrom for GGLWESwitchingKeyCompressed<D> {
}
}
impl<D: DataRef> WriterTo for GGLWESwitchingKeyCompressed<D> {
impl<D: DataRef> WriterTo for GLWESwitchingKeyCompressed<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)?;
@@ -137,13 +190,64 @@ impl<D: DataRef> WriterTo for GGLWESwitchingKeyCompressed<D> {
}
}
impl<D: DataMut, DR: DataRef, B: Backend> Decompress<B, GGLWESwitchingKeyCompressed<DR>> for GGLWESwitchingKey<D>
pub trait GLWESwitchingKeyDecompress
where
Module<B>: VecZnxFillUniform + VecZnxCopy,
Self: GGLWEDecompress,
{
fn decompress(&mut self, module: &Module<B>, other: &GGLWESwitchingKeyCompressed<DR>) {
self.key.decompress(module, &other.key);
self.sk_in_n = other.sk_in_n;
self.sk_out_n = other.sk_out_n;
fn decompress_glwe_switching_key<R, O>(&self, res: &mut R, other: &O)
where
R: GLWESwitchingKeyToMut + GLWESwitchingKeySetMetaData,
O: GLWESwitchingKeyCompressedToRef,
{
let other: &GLWESwitchingKeyCompressed<&[u8]> = &other.to_ref();
self.decompress_gglwe(&mut res.to_mut().key, &other.key);
res.set_sk_in_n(other.sk_in_n);
res.set_sk_out_n(other.sk_out_n);
}
}
impl<B: Backend> GLWESwitchingKeyDecompress for Module<B> where Self: GGLWEDecompress {}
impl<D: DataMut> GLWESwitchingKey<D> {
pub fn decompress<O, M>(&mut self, module: &M, other: &O)
where
O: GLWESwitchingKeyCompressedToRef,
M: GLWESwitchingKeyDecompress,
{
module.decompress_glwe_switching_key(self, other);
}
}
pub trait GLWESwitchingKeyCompressedToMut {
fn to_mut(&mut self) -> GLWESwitchingKeyCompressed<&mut [u8]>;
}
impl<D: DataMut> GLWESwitchingKeyCompressedToMut for GLWESwitchingKeyCompressed<D>
where
GGLWECompressed<D>: GGLWECompressedToMut,
{
fn to_mut(&mut self) -> GLWESwitchingKeyCompressed<&mut [u8]> {
GLWESwitchingKeyCompressed {
sk_in_n: self.sk_in_n,
sk_out_n: self.sk_out_n,
key: self.key.to_mut(),
}
}
}
pub trait GLWESwitchingKeyCompressedToRef {
fn to_ref(&self) -> GLWESwitchingKeyCompressed<&[u8]>;
}
impl<D: DataRef> GLWESwitchingKeyCompressedToRef for GLWESwitchingKeyCompressed<D>
where
GGLWECompressed<D>: GGLWECompressedToRef,
{
fn to_ref(&self) -> GLWESwitchingKeyCompressed<&[u8]> {
GLWESwitchingKeyCompressed {
sk_in_n: self.sk_in_n,
sk_out_n: self.sk_out_n,
key: self.key.to_ref(),
}
}
}

View File

@@ -1,23 +1,25 @@
use poulpy_hal::{
api::{VecZnxCopy, VecZnxFillUniform},
layouts::{Backend, Data, DataMut, DataRef, FillUniform, Module, ReaderFrom, WriterTo},
source::Source,
};
use crate::layouts::{
Base2K, Degree, Dnum, Dsize, GGLWEInfos, GGLWETensorKey, GLWEInfos, LWEInfos, Rank, TorusPrecision,
compressed::{Decompress, GGLWESwitchingKeyCompressed},
Base2K, Dnum, Dsize, GGLWEInfos, GLWEInfos, LWEInfos, Rank, RingDegree, TensorKey, TensorKeyToMut, TorusPrecision,
compressed::{
GLWESwitchingKeyCompressed, GLWESwitchingKeyCompressedAlloc, GLWESwitchingKeyCompressedToMut,
GLWESwitchingKeyCompressedToRef, GLWESwitchingKeyDecompress,
},
};
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use std::fmt;
#[derive(PartialEq, Eq, Clone)]
pub struct GGLWETensorKeyCompressed<D: Data> {
pub(crate) keys: Vec<GGLWESwitchingKeyCompressed<D>>,
pub struct TensorKeyCompressed<D: Data> {
pub(crate) keys: Vec<GLWESwitchingKeyCompressed<D>>,
}
impl<D: Data> LWEInfos for GGLWETensorKeyCompressed<D> {
fn n(&self) -> Degree {
impl<D: Data> LWEInfos for TensorKeyCompressed<D> {
fn n(&self) -> RingDegree {
self.keys[0].n()
}
@@ -32,13 +34,13 @@ impl<D: Data> LWEInfos for GGLWETensorKeyCompressed<D> {
self.keys[0].size()
}
}
impl<D: Data> GLWEInfos for GGLWETensorKeyCompressed<D> {
impl<D: Data> GLWEInfos for TensorKeyCompressed<D> {
fn rank(&self) -> Rank {
self.rank_out()
}
}
impl<D: Data> GGLWEInfos for GGLWETensorKeyCompressed<D> {
impl<D: Data> GGLWEInfos for TensorKeyCompressed<D> {
fn rank_in(&self) -> Rank {
self.rank_out()
}
@@ -56,21 +58,21 @@ impl<D: Data> GGLWEInfos for GGLWETensorKeyCompressed<D> {
}
}
impl<D: DataRef> fmt::Debug for GGLWETensorKeyCompressed<D> {
impl<D: DataRef> fmt::Debug for TensorKeyCompressed<D> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{self}")
}
}
impl<D: DataMut> FillUniform for GGLWETensorKeyCompressed<D> {
impl<D: DataMut> FillUniform for TensorKeyCompressed<D> {
fn fill_uniform(&mut self, log_bound: usize, source: &mut Source) {
self.keys
.iter_mut()
.for_each(|key: &mut GGLWESwitchingKeyCompressed<D>| key.fill_uniform(log_bound, source))
.for_each(|key: &mut GLWESwitchingKeyCompressed<D>| key.fill_uniform(log_bound, source))
}
}
impl<D: DataRef> fmt::Display for GGLWETensorKeyCompressed<D> {
impl<D: DataRef> fmt::Display for TensorKeyCompressed<D> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
writeln!(f, "(GLWETensorKeyCompressed)",)?;
for (i, key) in self.keys.iter().enumerate() {
@@ -80,8 +82,27 @@ impl<D: DataRef> fmt::Display for GGLWETensorKeyCompressed<D> {
}
}
impl GGLWETensorKeyCompressed<Vec<u8>> {
pub fn alloc<A>(infos: &A) -> Self
pub trait TensorKeyCompressedAlloc
where
Self: GLWESwitchingKeyCompressedAlloc,
{
fn alloc_tensor_key_compressed(
&self,
base2k: Base2K,
k: TorusPrecision,
rank: Rank,
dnum: Dnum,
dsize: Dsize,
) -> TensorKeyCompressed<Vec<u8>> {
let pairs: u32 = (((rank.as_u32() + 1) * rank.as_u32()) >> 1).max(1);
TensorKeyCompressed {
keys: (0..pairs)
.map(|_| self.alloc_glwe_switching_key_compressed(base2k, k, Rank(1), rank, dnum, dsize))
.collect(),
}
}
fn alloc_tensor_key_compressed_from_infos<A>(&self, infos: &A) -> TensorKeyCompressed<Vec<u8>>
where
A: GGLWEInfos,
{
@@ -90,62 +111,67 @@ impl GGLWETensorKeyCompressed<Vec<u8>> {
infos.rank_out(),
"rank_in != rank_out is not supported for GGLWETensorKeyCompressed"
);
Self::alloc_with(
infos.n(),
self.alloc_tensor_key_compressed(
infos.base2k(),
infos.k(),
infos.rank_out(),
infos.rank(),
infos.dnum(),
infos.dsize(),
)
}
pub fn alloc_with(n: Degree, base2k: Base2K, k: TorusPrecision, rank: Rank, dnum: Dnum, dsize: Dsize) -> Self {
let mut keys: Vec<GGLWESwitchingKeyCompressed<Vec<u8>>> = Vec::new();
let pairs: u32 = (((rank.0 + 1) * rank.0) >> 1).max(1);
(0..pairs).for_each(|_| {
keys.push(GGLWESwitchingKeyCompressed::alloc_with(
n,
base2k,
k,
Rank(1),
rank,
dnum,
dsize,
));
});
Self { keys }
fn bytes_of_tensor_key_compressed(&self, base2k: Base2K, k: TorusPrecision, rank: Rank, dnum: Dnum, dsize: Dsize) -> usize {
let pairs: usize = (((rank.0 + 1) * rank.0) >> 1).max(1) as usize;
pairs * self.bytes_of_glwe_switching_key_compressed(base2k, k, Rank(1), dnum, dsize)
}
pub fn alloc_bytes<A>(infos: &A) -> usize
fn bytes_of_tensor_key_compressed_from_infos<A>(&self, infos: &A) -> usize
where
A: GGLWEInfos,
{
assert_eq!(
infos.rank_in(),
infos.rank_out(),
"rank_in != rank_out is not supported for GGLWETensorKeyCompressed"
);
let rank_out: usize = infos.rank_out().into();
let pairs: usize = (((rank_out + 1) * rank_out) >> 1).max(1);
pairs
* GGLWESwitchingKeyCompressed::alloc_bytes_with(
infos.n(),
infos.base2k(),
infos.k(),
Rank(1),
infos.dnum(),
infos.dsize(),
)
}
pub fn alloc_bytes_with(n: Degree, base2k: Base2K, k: TorusPrecision, rank: Rank, dnum: Dnum, dsize: Dsize) -> usize {
let pairs: usize = (((rank.0 + 1) * rank.0) >> 1).max(1) as usize;
pairs * GGLWESwitchingKeyCompressed::alloc_bytes_with(n, base2k, k, Rank(1), dnum, dsize)
self.bytes_of_tensor_key_compressed(
infos.base2k(),
infos.k(),
infos.rank(),
infos.dnum(),
infos.dsize(),
)
}
}
impl<D: DataMut> ReaderFrom for GGLWETensorKeyCompressed<D> {
impl TensorKeyCompressed<Vec<u8>> {
pub fn alloc_from_infos<A, M>(module: &M, infos: &A) -> Self
where
A: GGLWEInfos,
M: TensorKeyCompressedAlloc,
{
module.alloc_tensor_key_compressed_from_infos(infos)
}
pub fn alloc<M>(module: &M, base2k: Base2K, k: TorusPrecision, rank: Rank, dnum: Dnum, dsize: Dsize) -> Self
where
M: TensorKeyCompressedAlloc,
{
module.alloc_tensor_key_compressed(base2k, k, rank, dnum, dsize)
}
pub fn bytes_of_from_infos<A, M>(module: &M, infos: &A) -> usize
where
A: GGLWEInfos,
M: TensorKeyCompressedAlloc,
{
module.bytes_of_tensor_key_compressed_from_infos(infos)
}
pub fn bytes_of<M>(module: &M, base2k: Base2K, k: TorusPrecision, rank: Rank, dnum: Dnum, dsize: Dsize) -> usize
where
M: TensorKeyCompressedAlloc,
{
module.bytes_of_tensor_key_compressed(base2k, k, rank, dnum, dsize)
}
}
impl<D: DataMut> ReaderFrom for TensorKeyCompressed<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 {
@@ -161,7 +187,7 @@ impl<D: DataMut> ReaderFrom for GGLWETensorKeyCompressed<D> {
}
}
impl<D: DataRef> WriterTo for GGLWETensorKeyCompressed<D> {
impl<D: DataRef> WriterTo for TensorKeyCompressed<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 {
@@ -171,8 +197,8 @@ impl<D: DataRef> WriterTo for GGLWETensorKeyCompressed<D> {
}
}
impl<D: DataMut> GGLWETensorKeyCompressed<D> {
pub(crate) fn at_mut(&mut self, mut i: usize, mut j: usize) -> &mut GGLWESwitchingKeyCompressed<D> {
impl<D: DataMut> TensorKeyCompressed<D> {
pub(crate) fn at_mut(&mut self, mut i: usize, mut j: usize) -> &mut GLWESwitchingKeyCompressed<D> {
if i > j {
std::mem::swap(&mut i, &mut j);
};
@@ -181,27 +207,70 @@ impl<D: DataMut> GGLWETensorKeyCompressed<D> {
}
}
impl<D: DataMut, DR: DataRef, B: Backend> Decompress<B, GGLWETensorKeyCompressed<DR>> for GGLWETensorKey<D>
pub trait TensorKeyDecompress
where
Module<B>: VecZnxFillUniform + VecZnxCopy,
Self: GLWESwitchingKeyDecompress,
{
fn decompress(&mut self, module: &Module<B>, other: &GGLWETensorKeyCompressed<DR>) {
#[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()
);
}
fn decompress_tensor_key<R, O>(&self, res: &mut R, other: &O)
where
R: TensorKeyToMut,
O: TensorKeyCompressedToRef,
{
let res: &mut TensorKey<&mut [u8]> = &mut res.to_mut();
let other: &TensorKeyCompressed<&[u8]> = &other.to_ref();
self.keys
.iter_mut()
.zip(other.keys.iter())
.for_each(|(a, b)| {
a.decompress(module, b);
});
assert_eq!(
res.keys.len(),
other.keys.len(),
"invalid receiver: res.keys.len()={} != other.keys.len()={}",
res.keys.len(),
other.keys.len()
);
for (a, b) in res.keys.iter_mut().zip(other.keys.iter()) {
self.decompress_glwe_switching_key(a, b);
}
}
}
impl<B: Backend> TensorKeyDecompress for Module<B> where Self: GLWESwitchingKeyDecompress {}
impl<D: DataMut> TensorKey<D> {
pub fn decompress<O, M>(&mut self, module: &M, other: &O)
where
O: TensorKeyCompressedToRef,
M: TensorKeyDecompress,
{
module.decompress_tensor_key(self, other);
}
}
pub trait TensorKeyCompressedToMut {
fn to_mut(&mut self) -> TensorKeyCompressed<&mut [u8]>;
}
impl<D: DataMut> TensorKeyCompressedToMut for TensorKeyCompressed<D>
where
GLWESwitchingKeyCompressed<D>: GLWESwitchingKeyCompressedToMut,
{
fn to_mut(&mut self) -> TensorKeyCompressed<&mut [u8]> {
TensorKeyCompressed {
keys: self.keys.iter_mut().map(|c| c.to_mut()).collect(),
}
}
}
pub trait TensorKeyCompressedToRef {
fn to_ref(&self) -> TensorKeyCompressed<&[u8]>;
}
impl<D: DataRef> TensorKeyCompressedToRef for TensorKeyCompressed<D>
where
GLWESwitchingKeyCompressed<D>: GLWESwitchingKeyCompressedToRef,
{
fn to_ref(&self) -> TensorKeyCompressed<&[u8]> {
TensorKeyCompressed {
keys: self.keys.iter().map(|c| c.to_ref()).collect(),
}
}
}

View File

@@ -1,18 +1,19 @@
use poulpy_hal::{
api::{VecZnxCopy, VecZnxFillUniform},
layouts::{Backend, Data, DataMut, DataRef, FillUniform, MatZnx, Module, ReaderFrom, WriterTo, ZnxInfos},
layouts::{
Backend, Data, DataMut, DataRef, FillUniform, MatZnx, MatZnxToMut, MatZnxToRef, Module, ReaderFrom, WriterTo, ZnxInfos,
},
source::Source,
};
use crate::layouts::{
Base2K, Degree, Dnum, Dsize, GGSWCiphertext, GGSWInfos, GLWEInfos, LWEInfos, Rank, TorusPrecision,
compressed::{Decompress, GLWECiphertextCompressed},
Base2K, Dnum, Dsize, GGSW, GGSWInfos, GGSWToMut, GLWEInfos, GetRingDegree, LWEInfos, Rank, RingDegree, TorusPrecision,
compressed::{GLWECompressed, GLWEDecompress},
};
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use std::fmt;
#[derive(PartialEq, Eq, Clone)]
pub struct GGSWCiphertextCompressed<D: Data> {
pub struct GGSWCompressed<D: Data> {
pub(crate) data: MatZnx<D>,
pub(crate) k: TorusPrecision,
pub(crate) base2k: Base2K,
@@ -21,9 +22,9 @@ pub struct GGSWCiphertextCompressed<D: Data> {
pub(crate) seed: Vec<[u8; 32]>,
}
impl<D: Data> LWEInfos for GGSWCiphertextCompressed<D> {
fn n(&self) -> Degree {
Degree(self.data.n() as u32)
impl<D: Data> LWEInfos for GGSWCompressed<D> {
fn n(&self) -> RingDegree {
RingDegree(self.data.n() as u32)
}
fn base2k(&self) -> Base2K {
@@ -37,13 +38,13 @@ impl<D: Data> LWEInfos for GGSWCiphertextCompressed<D> {
self.data.size()
}
}
impl<D: Data> GLWEInfos for GGSWCiphertextCompressed<D> {
impl<D: Data> GLWEInfos for GGSWCompressed<D> {
fn rank(&self) -> Rank {
self.rank
}
}
impl<D: Data> GGSWInfos for GGSWCiphertextCompressed<D> {
impl<D: Data> GGSWInfos for GGSWCompressed<D> {
fn dsize(&self) -> Dsize {
self.dsize
}
@@ -53,46 +54,42 @@ impl<D: Data> GGSWInfos for GGSWCiphertextCompressed<D> {
}
}
impl<D: DataRef> fmt::Debug for GGSWCiphertextCompressed<D> {
impl<D: DataRef> fmt::Debug for GGSWCompressed<D> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.data)
}
}
impl<D: DataRef> fmt::Display for GGSWCiphertextCompressed<D> {
impl<D: DataRef> fmt::Display for GGSWCompressed<D> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"(GGSWCiphertextCompressed: base2k={} k={} dsize={}) {}",
"(GGSWCompressed: base2k={} k={} dsize={}) {}",
self.base2k, self.k, self.dsize, self.data
)
}
}
impl<D: DataMut> FillUniform for GGSWCiphertextCompressed<D> {
impl<D: DataMut> FillUniform for GGSWCompressed<D> {
fn fill_uniform(&mut self, log_bound: usize, source: &mut Source) {
self.data.fill_uniform(log_bound, source);
}
}
impl GGSWCiphertextCompressed<Vec<u8>> {
pub fn alloc<A>(infos: &A) -> Self
where
A: GGSWInfos,
{
Self::alloc_with(
infos.n(),
infos.base2k(),
infos.k(),
infos.rank(),
infos.dnum(),
infos.dsize(),
)
}
pub fn alloc_with(n: Degree, base2k: Base2K, k: TorusPrecision, rank: Rank, dnum: Dnum, dsize: Dsize) -> Self {
pub trait GGSWCompressedAlloc
where
Self: GetRingDegree,
{
fn alloc_ggsw_compressed(
&self,
base2k: Base2K,
k: TorusPrecision,
rank: Rank,
dnum: Dnum,
dsize: Dsize,
) -> GGSWCompressed<Vec<u8>> {
let size: usize = k.0.div_ceil(base2k.0) as usize;
debug_assert!(
assert!(
size as u32 > dsize.0,
"invalid ggsw: ceil(k/base2k): {size} <= dsize: {}",
dsize.0
@@ -105,9 +102,9 @@ impl GGSWCiphertextCompressed<Vec<u8>> {
dsize.0,
);
Self {
GGSWCompressed {
data: MatZnx::alloc(
n.into(),
self.ring_degree().into(),
dnum.into(),
(rank + 1).into(),
1,
@@ -121,12 +118,11 @@ impl GGSWCiphertextCompressed<Vec<u8>> {
}
}
pub fn alloc_bytes<A>(infos: &A) -> usize
fn alloc_ggsw_compressed_from_infos<A>(&self, infos: &A) -> GGSWCompressed<Vec<u8>>
where
A: GGSWInfos,
{
Self::alloc_bytes_with(
infos.n(),
self.alloc_ggsw_compressed(
infos.base2k(),
infos.k(),
infos.rank(),
@@ -135,9 +131,9 @@ impl GGSWCiphertextCompressed<Vec<u8>> {
)
}
pub fn alloc_bytes_with(n: Degree, base2k: Base2K, k: TorusPrecision, rank: Rank, dnum: Dnum, dsize: Dsize) -> usize {
fn bytes_of_ggsw_compressed(&self, base2k: Base2K, k: TorusPrecision, rank: Rank, dnum: Dnum, dsize: Dsize) -> usize {
let size: usize = k.0.div_ceil(base2k.0) as usize;
debug_assert!(
assert!(
size as u32 > dsize.0,
"invalid ggsw: ceil(k/base2k): {size} <= dsize: {}",
dsize.0
@@ -150,20 +146,65 @@ impl GGSWCiphertextCompressed<Vec<u8>> {
dsize.0,
);
MatZnx::alloc_bytes(
n.into(),
MatZnx::bytes_of(
self.ring_degree().into(),
dnum.into(),
(rank + 1).into(),
1,
k.0.div_ceil(base2k.0) as usize,
)
}
fn bytes_of_ggsw_compressed_key_from_infos<A>(&self, infos: &A) -> usize
where
A: GGSWInfos,
{
self.bytes_of_ggsw_compressed(
infos.base2k(),
infos.k(),
infos.rank(),
infos.dnum(),
infos.dsize(),
)
}
}
impl<D: DataRef> GGSWCiphertextCompressed<D> {
pub fn at(&self, row: usize, col: usize) -> GLWECiphertextCompressed<&[u8]> {
impl GGSWCompressed<Vec<u8>> {
pub fn alloc_from_infos<A, M>(module: &M, infos: &A) -> Self
where
A: GGSWInfos,
M: GGSWCompressedAlloc,
{
module.alloc_ggsw_compressed_from_infos(infos)
}
pub fn alloc<M>(module: &M, base2k: Base2K, k: TorusPrecision, rank: Rank, dnum: Dnum, dsize: Dsize) -> Self
where
M: GGSWCompressedAlloc,
{
module.alloc_ggsw_compressed(base2k, k, rank, dnum, dsize)
}
pub fn bytes_of_from_infos<A, M>(module: &M, infos: &A) -> usize
where
A: GGSWInfos,
M: GGSWCompressedAlloc,
{
module.bytes_of_ggsw_compressed_key_from_infos(infos)
}
pub fn bytes_of<M>(module: &M, base2k: Base2K, k: TorusPrecision, rank: Rank, dnum: Dnum, dsize: Dsize) -> usize
where
M: GGSWCompressedAlloc,
{
module.bytes_of_ggsw_compressed(base2k, k, rank, dnum, dsize)
}
}
impl<D: DataRef> GGSWCompressed<D> {
pub fn at(&self, row: usize, col: usize) -> GLWECompressed<&[u8]> {
let rank: usize = self.rank().into();
GLWECiphertextCompressed {
GLWECompressed {
data: self.data.at(row, col),
k: self.k,
base2k: self.base2k,
@@ -173,10 +214,10 @@ impl<D: DataRef> GGSWCiphertextCompressed<D> {
}
}
impl<D: DataMut> GGSWCiphertextCompressed<D> {
pub fn at_mut(&mut self, row: usize, col: usize) -> GLWECiphertextCompressed<&mut [u8]> {
impl<D: DataMut> GGSWCompressed<D> {
pub fn at_mut(&mut self, row: usize, col: usize) -> GLWECompressed<&mut [u8]> {
let rank: usize = self.rank().into();
GLWECiphertextCompressed {
GLWECompressed {
data: self.data.at_mut(row, col),
k: self.k,
base2k: self.base2k,
@@ -186,7 +227,7 @@ impl<D: DataMut> GGSWCiphertextCompressed<D> {
}
}
impl<D: DataMut> ReaderFrom for GGSWCiphertextCompressed<D> {
impl<D: DataMut> ReaderFrom for GGSWCompressed<D> {
fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> {
self.k = TorusPrecision(reader.read_u32::<LittleEndian>()?);
self.base2k = Base2K(reader.read_u32::<LittleEndian>()?);
@@ -201,7 +242,7 @@ impl<D: DataMut> ReaderFrom for GGSWCiphertextCompressed<D> {
}
}
impl<D: DataRef> WriterTo for GGSWCiphertextCompressed<D> {
impl<D: DataRef> WriterTo for GGSWCompressed<D> {
fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
writer.write_u32::<LittleEndian>(self.k.into())?;
writer.write_u32::<LittleEndian>(self.base2k.into())?;
@@ -215,23 +256,72 @@ impl<D: DataRef> WriterTo for GGSWCiphertextCompressed<D> {
}
}
impl<D: DataMut, B: Backend, DR: DataRef> Decompress<B, GGSWCiphertextCompressed<DR>> for GGSWCiphertext<D>
pub trait GGSWDecompress
where
Module<B>: VecZnxFillUniform + VecZnxCopy,
Self: GLWEDecompress,
{
fn decompress(&mut self, module: &Module<B>, other: &GGSWCiphertextCompressed<DR>) {
#[cfg(debug_assertions)]
{
assert_eq!(self.rank(), other.rank())
}
fn decompress_ggsw<R, O>(&self, res: &mut R, other: &O)
where
R: GGSWToMut,
O: GGSWCompressedToRef,
{
let res: &mut GGSW<&mut [u8]> = &mut res.to_mut();
let other: &GGSWCompressed<&[u8]> = &other.to_ref();
let dnum: usize = self.dnum().into();
let rank: usize = self.rank().into();
(0..dnum).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));
});
});
assert_eq!(res.rank(), other.rank());
let dnum: usize = res.dnum().into();
let rank: usize = res.rank().into();
for row_i in 0..dnum {
for col_j in 0..rank + 1 {
self.decompress_glwe(&mut res.at_mut(row_i, col_j), &other.at(row_i, col_j));
}
}
}
}
impl<B: Backend> GGSWDecompress for Module<B> where Self: GGSWDecompress {}
impl<D: DataMut> GGSW<D> {
pub fn decompress<O, M>(&mut self, module: &M, other: &O)
where
O: GGSWCompressedToRef,
M: GGSWDecompress,
{
module.decompress_ggsw(self, other);
}
}
pub trait GGSWCompressedToMut {
fn to_mut(&mut self) -> GGSWCompressed<&mut [u8]>;
}
impl<D: DataMut> GGSWCompressedToMut for GGSWCompressed<D> {
fn to_mut(&mut self) -> GGSWCompressed<&mut [u8]> {
GGSWCompressed {
k: self.k(),
base2k: self.base2k(),
dsize: self.dsize(),
rank: self.rank(),
seed: self.seed.clone(),
data: self.data.to_mut(),
}
}
}
pub trait GGSWCompressedToRef {
fn to_ref(&self) -> GGSWCompressed<&[u8]>;
}
impl<D: DataRef> GGSWCompressedToRef for GGSWCompressed<D> {
fn to_ref(&self) -> GGSWCompressed<&[u8]> {
GGSWCompressed {
k: self.k(),
base2k: self.base2k(),
dsize: self.dsize(),
rank: self.rank(),
seed: self.seed.clone(),
data: self.data.to_ref(),
}
}
}

View File

@@ -1,15 +1,19 @@
use poulpy_hal::{
api::{VecZnxCopy, VecZnxFillUniform},
layouts::{Backend, Data, DataMut, DataRef, FillUniform, Module, ReaderFrom, VecZnx, WriterTo, ZnxInfos},
layouts::{
Backend, Data, DataMut, DataRef, FillUniform, Module, ReaderFrom, VecZnx, VecZnxToMut, VecZnxToRef, WriterTo, ZnxInfos,
},
source::Source,
};
use crate::layouts::{Base2K, Degree, GLWECiphertext, GLWEInfos, LWEInfos, Rank, TorusPrecision, compressed::Decompress};
use crate::layouts::{
Base2K, GLWE, GLWEInfos, GLWEToMut, GetRingDegree, LWEInfos, Rank, RingDegree, SetGLWEInfos, TorusPrecision,
};
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use std::fmt;
#[derive(PartialEq, Eq, Clone)]
pub struct GLWECiphertextCompressed<D: Data> {
pub struct GLWECompressed<D: Data> {
pub(crate) data: VecZnx<D>,
pub(crate) base2k: Base2K,
pub(crate) k: TorusPrecision,
@@ -17,7 +21,7 @@ pub struct GLWECiphertextCompressed<D: Data> {
pub(crate) seed: [u8; 32],
}
impl<D: Data> LWEInfos for GLWECiphertextCompressed<D> {
impl<D: Data> LWEInfos for GLWECompressed<D> {
fn base2k(&self) -> Base2K {
self.base2k
}
@@ -30,27 +34,27 @@ impl<D: Data> LWEInfos for GLWECiphertextCompressed<D> {
self.data.size()
}
fn n(&self) -> Degree {
Degree(self.data.n() as u32)
fn n(&self) -> RingDegree {
RingDegree(self.data.n() as u32)
}
}
impl<D: Data> GLWEInfos for GLWECiphertextCompressed<D> {
impl<D: Data> GLWEInfos for GLWECompressed<D> {
fn rank(&self) -> Rank {
self.rank
}
}
impl<D: DataRef> fmt::Debug for GLWECiphertextCompressed<D> {
impl<D: DataRef> fmt::Debug for GLWECompressed<D> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{self}")
}
}
impl<D: DataRef> fmt::Display for GLWECiphertextCompressed<D> {
impl<D: DataRef> fmt::Display for GLWECompressed<D> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"GLWECiphertextCompressed: base2k={} k={} rank={} seed={:?}: {}",
"GLWECompressed: base2k={} k={} rank={} seed={:?}: {}",
self.base2k(),
self.k(),
self.rank(),
@@ -60,23 +64,23 @@ impl<D: DataRef> fmt::Display for GLWECiphertextCompressed<D> {
}
}
impl<D: DataMut> FillUniform for GLWECiphertextCompressed<D> {
impl<D: DataMut> FillUniform for GLWECompressed<D> {
fn fill_uniform(&mut self, log_bound: usize, source: &mut Source) {
self.data.fill_uniform(log_bound, source);
}
}
impl GLWECiphertextCompressed<Vec<u8>> {
pub fn alloc<A>(infos: &A) -> Self
where
A: GLWEInfos,
{
Self::alloc_with(infos.n(), infos.base2k(), infos.k(), infos.rank())
}
pub fn alloc_with(n: Degree, base2k: Base2K, k: TorusPrecision, rank: Rank) -> Self {
Self {
data: VecZnx::alloc(n.into(), 1, k.0.div_ceil(base2k.0) as usize),
pub trait GLWECompressedAlloc
where
Self: GetRingDegree,
{
fn alloc_glwe_compressed(&self, base2k: Base2K, k: TorusPrecision, rank: Rank) -> GLWECompressed<Vec<u8>> {
GLWECompressed {
data: VecZnx::alloc(
self.ring_degree().into(),
1,
k.0.div_ceil(base2k.0) as usize,
),
base2k,
k,
rank,
@@ -84,19 +88,66 @@ impl GLWECiphertextCompressed<Vec<u8>> {
}
}
pub fn alloc_bytes<A>(infos: &A) -> usize
fn alloc_glwe_compressed_from_infos<A>(&self, infos: &A) -> GLWECompressed<Vec<u8>>
where
A: GLWEInfos,
{
Self::alloc_bytes_with(infos.n(), infos.base2k(), infos.k())
assert_eq!(self.ring_degree(), infos.n());
self.alloc_glwe_compressed(infos.base2k(), infos.k(), infos.rank())
}
pub fn alloc_bytes_with(n: Degree, base2k: Base2K, k: TorusPrecision) -> usize {
VecZnx::alloc_bytes(n.into(), 1, k.0.div_ceil(base2k.0) as usize)
fn bytes_of_glwe_compressed(&self, base2k: Base2K, k: TorusPrecision) -> usize {
VecZnx::bytes_of(
self.ring_degree().into(),
1,
k.0.div_ceil(base2k.0) as usize,
)
}
fn bytes_of_glwe_compressed_from_infos<A>(&self, infos: &A) -> usize
where
A: GLWEInfos,
{
assert_eq!(self.ring_degree(), infos.n());
self.bytes_of_glwe_compressed(infos.base2k(), infos.k())
}
}
impl<D: DataMut> ReaderFrom for GLWECiphertextCompressed<D> {
impl<B: Backend> GLWECompressedAlloc for Module<B> where Self: GetRingDegree {}
impl GLWECompressed<Vec<u8>> {
pub fn alloc_from_infos<A, M>(module: &M, infos: &A) -> Self
where
A: GLWEInfos,
M: GLWECompressedAlloc,
{
module.alloc_glwe_compressed_from_infos(infos)
}
pub fn alloc<M>(module: &M, base2k: Base2K, k: TorusPrecision, rank: Rank) -> Self
where
M: GLWECompressedAlloc,
{
module.alloc_glwe_compressed(base2k, k, rank)
}
pub fn bytes_of_from_infos<A, M>(module: &M, infos: &A) -> usize
where
A: GLWEInfos,
M: GLWECompressedAlloc,
{
module.bytes_of_glwe_compressed_from_infos(infos)
}
pub fn bytes_of<M>(module: &M, base2k: Base2K, k: TorusPrecision) -> usize
where
M: GLWECompressedAlloc,
{
module.bytes_of_glwe_compressed(base2k, k)
}
}
impl<D: DataMut> ReaderFrom for GLWECompressed<D> {
fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> {
self.k = TorusPrecision(reader.read_u32::<LittleEndian>()?);
self.base2k = Base2K(reader.read_u32::<LittleEndian>()?);
@@ -106,7 +157,7 @@ impl<D: DataMut> ReaderFrom for GLWECiphertextCompressed<D> {
}
}
impl<D: DataRef> WriterTo for GLWECiphertextCompressed<D> {
impl<D: DataRef> WriterTo for GLWECompressed<D> {
fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
writer.write_u32::<LittleEndian>(self.k.into())?;
writer.write_u32::<LittleEndian>(self.base2k.into())?;
@@ -116,63 +167,82 @@ impl<D: DataRef> WriterTo for GLWECiphertextCompressed<D> {
}
}
impl<D: DataMut, B: Backend, DR: DataRef> Decompress<B, GLWECiphertextCompressed<DR>> for GLWECiphertext<D>
pub trait GLWEDecompress
where
Module<B>: VecZnxFillUniform + VecZnxCopy,
Self: GetRingDegree + VecZnxFillUniform + VecZnxCopy,
{
fn decompress(&mut self, module: &Module<B>, other: &GLWECiphertextCompressed<DR>) {
#[cfg(debug_assertions)]
{
assert_eq!(
self.n(),
other.n(),
"invalid receiver: self.n()={} != other.n()={}",
self.n(),
other.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,
fn decompress_glwe<R, O>(&self, res: &mut R, other: &O)
where
R: GLWEToMut + SetGLWEInfos,
O: GLWECompressedToRef + GLWEInfos,
{
#[cfg(debug_assertions)]
{
assert_eq!(self.rank(), other.rank());
debug_assert_eq!(self.size(), other.size());
let res: &mut GLWE<&mut [u8]> = &mut res.to_mut();
let other: &GLWECompressed<&[u8]> = &other.to_ref();
assert_eq!(
res.n(),
self.ring_degree(),
"invalid receiver: res.n()={} != other.n()={}",
res.n(),
self.ring_degree()
);
assert_eq!(res.lwe_layout(), other.lwe_layout());
assert_eq!(res.glwe_layout(), other.glwe_layout());
let mut source: Source = Source::new(other.seed);
self.vec_znx_copy(&mut res.data, 0, &other.data, 0);
(1..(other.rank() + 1).into()).for_each(|i| {
self.vec_znx_fill_uniform(other.base2k.into(), &mut res.data, i, &mut source);
});
}
module.vec_znx_copy(&mut self.data, 0, &other.data, 0);
(1..(other.rank() + 1).into()).for_each(|i| {
module.vec_znx_fill_uniform(other.base2k.into(), &mut self.data, i, source);
});
self.base2k = other.base2k;
self.k = other.k;
res.set_base2k(other.base2k());
res.set_k(other.k());
}
}
impl<B: Backend> GLWEDecompress for Module<B> where Self: GetRingDegree + VecZnxFillUniform + VecZnxCopy {}
impl<D: DataMut> GLWE<D> {
pub fn decompress<O, M>(&mut self, module: &M, other: &O)
where
O: GLWECompressedToRef + GLWEInfos,
M: GLWEDecompress,
{
module.decompress_glwe(self, other);
}
}
pub trait GLWECompressedToRef {
fn to_ref(&self) -> GLWECompressed<&[u8]>;
}
impl<D: DataRef> GLWECompressedToRef for GLWECompressed<D> {
fn to_ref(&self) -> GLWECompressed<&[u8]> {
GLWECompressed {
seed: self.seed.clone(),
base2k: self.base2k,
k: self.k,
rank: self.rank,
data: self.data.to_ref(),
}
}
}
pub trait GLWECompressedToMut {
fn to_mut(&mut self) -> GLWECompressed<&mut [u8]>;
}
impl<D: DataMut> GLWECompressedToMut for GLWECompressed<D> {
fn to_mut(&mut self) -> GLWECompressed<&mut [u8]> {
GLWECompressed {
seed: self.seed.clone(),
base2k: self.base2k,
k: self.k,
rank: self.rank,
data: self.data.to_mut(),
}
}
}

View File

@@ -1,16 +1,21 @@
use std::fmt;
use poulpy_hal::{
layouts::{Data, DataMut, DataRef, FillUniform, ReaderFrom, WriterTo},
layouts::{Backend, Data, DataMut, DataRef, FillUniform, Module, ReaderFrom, WriterTo},
source::Source,
};
use crate::layouts::{
Base2K, Degree, Dnum, Dsize, GGLWEInfos, GLWEInfos, LWEInfos, Rank, TorusPrecision, compressed::GGLWESwitchingKeyCompressed,
Base2K, Dnum, Dsize, GGLWEInfos, GLWEInfos, GLWEToLWESwitchingKey, GLWEToLWESwitchingKeyToMut, LWEInfos, Rank, RingDegree,
TorusPrecision,
compressed::{
GLWESwitchingKeyCompressed, GLWESwitchingKeyCompressedAlloc, GLWESwitchingKeyCompressedToMut,
GLWESwitchingKeyCompressedToRef, GLWESwitchingKeyDecompress,
},
};
#[derive(PartialEq, Eq, Clone)]
pub struct GLWEToLWESwitchingKeyCompressed<D: Data>(pub(crate) GGLWESwitchingKeyCompressed<D>);
pub struct GLWEToLWESwitchingKeyCompressed<D: Data>(pub(crate) GLWESwitchingKeyCompressed<D>);
impl<D: Data> LWEInfos for GLWEToLWESwitchingKeyCompressed<D> {
fn base2k(&self) -> Base2K {
@@ -21,7 +26,7 @@ impl<D: Data> LWEInfos for GLWEToLWESwitchingKeyCompressed<D> {
self.0.k()
}
fn n(&self) -> Degree {
fn n(&self) -> RingDegree {
self.0.n()
}
fn size(&self) -> usize {
@@ -83,54 +88,146 @@ impl<D: DataRef> WriterTo for GLWEToLWESwitchingKeyCompressed<D> {
}
}
impl GLWEToLWESwitchingKeyCompressed<Vec<u8>> {
pub fn alloc<A>(infos: &A) -> Self
pub trait GLWEToLWESwitchingKeyCompressedAlloc
where
Self: GLWESwitchingKeyCompressedAlloc,
{
fn alloc_glwe_to_lwe_switching_key_compressed(
&self,
base2k: Base2K,
k: TorusPrecision,
rank_in: Rank,
dnum: Dnum,
) -> GLWEToLWESwitchingKeyCompressed<Vec<u8>> {
GLWEToLWESwitchingKeyCompressed(self.alloc_glwe_switching_key_compressed(base2k, k, rank_in, Rank(1), dnum, Dsize(1)))
}
fn alloc_glwe_to_lwe_switching_key_compressed_from_infos<A>(&self, infos: &A) -> GLWEToLWESwitchingKeyCompressed<Vec<u8>>
where
A: GGLWEInfos,
{
debug_assert_eq!(
assert_eq!(
infos.rank_out().0,
1,
"rank_out > 1 is unsupported for GLWEToLWESwitchingKeyCompressed"
);
debug_assert_eq!(
assert_eq!(
infos.dsize().0,
1,
"dsize > 1 is unsupported for GLWEToLWESwitchingKeyCompressed"
);
Self(GGLWESwitchingKeyCompressed::alloc(infos))
self.alloc_glwe_to_lwe_switching_key_compressed(infos.base2k(), infos.k(), infos.rank_in(), infos.dnum())
}
pub fn alloc_with(n: Degree, base2k: Base2K, k: TorusPrecision, rank_in: Rank, dnum: Dnum) -> Self {
Self(GGLWESwitchingKeyCompressed::alloc_with(
n,
base2k,
k,
rank_in,
Rank(1),
dnum,
Dsize(1),
))
fn bytes_of_glwe_to_lwe_switching_key_compressed(
&self,
base2k: Base2K,
k: TorusPrecision,
rank_in: Rank,
dnum: Dnum,
) -> usize {
self.bytes_of_glwe_switching_key_compressed(base2k, k, rank_in, dnum, Dsize(1))
}
pub fn alloc_bytes<A>(infos: &A) -> usize
fn bytes_of_glwe_to_lwe_switching_key_compressed_from_infos<A>(&self, infos: &A) -> usize
where
A: GGLWEInfos,
{
debug_assert_eq!(
assert_eq!(
infos.rank_out().0,
1,
"rank_out > 1 is unsupported for GLWEToLWESwitchingKeyCompressed"
);
debug_assert_eq!(
assert_eq!(
infos.dsize().0,
1,
"dsize > 1 is unsupported for GLWEToLWESwitchingKeyCompressed"
);
GGLWESwitchingKeyCompressed::alloc_bytes(infos)
}
pub fn alloc_bytes_with(n: Degree, base2k: Base2K, k: TorusPrecision, dnum: Dnum, rank_in: Rank) -> usize {
GGLWESwitchingKeyCompressed::alloc_bytes_with(n, base2k, k, rank_in, dnum, Dsize(1))
self.bytes_of_glwe_switching_key_compressed_from_infos(infos)
}
}
impl<B: Backend> GLWEToLWESwitchingKeyCompressedAlloc for Module<B> where Self: GLWESwitchingKeyCompressedAlloc {}
impl GLWEToLWESwitchingKeyCompressed<Vec<u8>> {
pub fn alloc_from_infos<A, M>(module: &M, infos: &A) -> Self
where
A: GGLWEInfos,
M: GLWEToLWESwitchingKeyCompressedAlloc,
{
module.alloc_glwe_to_lwe_switching_key_compressed_from_infos(infos)
}
pub fn alloc<M>(module: &M, base2k: Base2K, k: TorusPrecision, rank_in: Rank, dnum: Dnum) -> Self
where
M: GLWEToLWESwitchingKeyCompressedAlloc,
{
module.alloc_glwe_to_lwe_switching_key_compressed(base2k, k, rank_in, dnum)
}
pub fn bytes_of_from_infos<A, M>(module: &M, infos: &A) -> usize
where
A: GGLWEInfos,
M: GLWEToLWESwitchingKeyCompressedAlloc,
{
module.bytes_of_glwe_to_lwe_switching_key_compressed_from_infos(infos)
}
pub fn bytes_of<M>(module: &M, base2k: Base2K, k: TorusPrecision, dnum: Dnum, rank_in: Rank) -> usize
where
M: GLWEToLWESwitchingKeyCompressedAlloc,
{
module.bytes_of_glwe_to_lwe_switching_key_compressed(base2k, k, rank_in, dnum)
}
}
pub trait GLWEToLWESwitchingKeyDecompress
where
Self: GLWESwitchingKeyDecompress,
{
fn decompress_glwe_to_lwe_switching_key<R, O>(&self, res: &mut R, other: &O)
where
R: GLWEToLWESwitchingKeyToMut,
O: GLWEToLWESwitchingKeyCompressedToRef,
{
self.decompress_glwe_switching_key(&mut res.to_mut().0, &other.to_ref().0);
}
}
impl<B: Backend> GLWEToLWESwitchingKeyDecompress for Module<B> where Self: GLWESwitchingKeyDecompress {}
impl<D: DataMut> GLWEToLWESwitchingKey<D> {
pub fn decompress<O, M>(&mut self, module: &M, other: &O)
where
O: GLWEToLWESwitchingKeyCompressedToRef,
M: GLWEToLWESwitchingKeyDecompress,
{
module.decompress_glwe_to_lwe_switching_key(self, other);
}
}
pub trait GLWEToLWESwitchingKeyCompressedToRef {
fn to_ref(&self) -> GLWEToLWESwitchingKeyCompressed<&[u8]>;
}
impl<D: DataRef> GLWEToLWESwitchingKeyCompressedToRef for GLWEToLWESwitchingKeyCompressed<D>
where
GLWESwitchingKeyCompressed<D>: GLWESwitchingKeyCompressedToRef,
{
fn to_ref(&self) -> GLWEToLWESwitchingKeyCompressed<&[u8]> {
GLWEToLWESwitchingKeyCompressed(self.0.to_ref())
}
}
pub trait GLWEToLWESwitchingKeyCompressedToMut {
fn to_mut(&mut self) -> GLWEToLWESwitchingKeyCompressed<&mut [u8]>;
}
impl<D: DataMut> GLWEToLWESwitchingKeyCompressedToMut for GLWEToLWESwitchingKeyCompressed<D>
where
GLWESwitchingKeyCompressed<D>: GLWESwitchingKeyCompressedToMut,
{
fn to_mut(&mut self) -> GLWEToLWESwitchingKeyCompressed<&mut [u8]> {
GLWEToLWESwitchingKeyCompressed(self.0.to_mut())
}
}

View File

@@ -2,21 +2,24 @@ use std::fmt;
use poulpy_hal::{
api::ZnFillUniform,
layouts::{Backend, Data, DataMut, DataRef, FillUniform, Module, ReaderFrom, WriterTo, Zn, ZnxInfos, ZnxView, ZnxViewMut},
layouts::{
Backend, Data, DataMut, DataRef, FillUniform, Module, ReaderFrom, WriterTo, Zn, ZnToMut, ZnToRef, ZnxInfos, ZnxView,
ZnxViewMut,
},
source::Source,
};
use crate::layouts::{Base2K, Degree, LWECiphertext, LWEInfos, TorusPrecision, compressed::Decompress};
use crate::layouts::{Base2K, LWE, LWEInfos, LWEToMut, RingDegree, TorusPrecision};
#[derive(PartialEq, Eq, Clone)]
pub struct LWECiphertextCompressed<D: Data> {
pub struct LWECompressed<D: Data> {
pub(crate) data: Zn<D>,
pub(crate) k: TorusPrecision,
pub(crate) base2k: Base2K,
pub(crate) seed: [u8; 32],
}
impl<D: Data> LWEInfos for LWECiphertextCompressed<D> {
impl<D: Data> LWEInfos for LWECompressed<D> {
fn base2k(&self) -> Base2K {
self.base2k
}
@@ -25,8 +28,8 @@ impl<D: Data> LWEInfos for LWECiphertextCompressed<D> {
self.k
}
fn n(&self) -> Degree {
Degree(self.data.n() as u32)
fn n(&self) -> RingDegree {
RingDegree(self.data.n() as u32)
}
fn size(&self) -> usize {
@@ -34,17 +37,17 @@ impl<D: Data> LWEInfos for LWECiphertextCompressed<D> {
}
}
impl<D: DataRef> fmt::Debug for LWECiphertextCompressed<D> {
impl<D: DataRef> fmt::Debug for LWECompressed<D> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{self}")
}
}
impl<D: DataRef> fmt::Display for LWECiphertextCompressed<D> {
impl<D: DataRef> fmt::Display for LWECompressed<D> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"LWECiphertextCompressed: base2k={} k={} seed={:?}: {}",
"LWECompressed: base2k={} k={} seed={:?}: {}",
self.base2k(),
self.k(),
self.seed,
@@ -53,22 +56,15 @@ impl<D: DataRef> fmt::Display for LWECiphertextCompressed<D> {
}
}
impl<D: DataMut> FillUniform for LWECiphertextCompressed<D> {
impl<D: DataMut> FillUniform for LWECompressed<D> {
fn fill_uniform(&mut self, log_bound: usize, source: &mut Source) {
self.data.fill_uniform(log_bound, source);
}
}
impl LWECiphertextCompressed<Vec<u8>> {
pub fn alloc<A>(infos: &A) -> Self
where
A: LWEInfos,
{
Self::alloc_with(infos.base2k(), infos.k())
}
pub fn alloc_with(base2k: Base2K, k: TorusPrecision) -> Self {
Self {
pub trait LWECompressedAlloc {
fn alloc_lwe_compressed(&self, base2k: Base2K, k: TorusPrecision) -> LWECompressed<Vec<u8>> {
LWECompressed {
data: Zn::alloc(1, 1, k.0.div_ceil(base2k.0) as usize),
k,
base2k,
@@ -76,21 +72,62 @@ impl LWECiphertextCompressed<Vec<u8>> {
}
}
pub fn alloc_bytes<A>(infos: &A) -> usize
fn alloc_lwe_compressed_from_infos<A>(&self, infos: &A) -> LWECompressed<Vec<u8>>
where
A: LWEInfos,
{
Self::alloc_bytes_with(infos.base2k(), infos.k())
self.alloc_lwe_compressed(infos.base2k(), infos.k())
}
pub fn alloc_bytes_with(base2k: Base2K, k: TorusPrecision) -> usize {
Zn::alloc_bytes(1, 1, k.0.div_ceil(base2k.0) as usize)
fn bytes_of_lwe_compressed(&self, base2k: Base2K, k: TorusPrecision) -> usize {
Zn::bytes_of(1, 1, k.0.div_ceil(base2k.0) as usize)
}
fn bytes_of_lwe_compressed_from_infos<A>(&self, infos: &A) -> usize
where
A: LWEInfos,
{
self.bytes_of_lwe_compressed(infos.base2k(), infos.k())
}
}
impl<B: Backend> LWECompressedAlloc for Module<B> {}
impl LWECompressed<Vec<u8>> {
pub fn alloc_from_infos<A, M>(module: &M, infos: &A) -> Self
where
A: LWEInfos,
M: LWECompressedAlloc,
{
module.alloc_lwe_compressed_from_infos(infos)
}
pub fn alloc<M>(module: &M, base2k: Base2K, k: TorusPrecision) -> Self
where
M: LWECompressedAlloc,
{
module.alloc_lwe_compressed(base2k, k)
}
pub fn bytes_of_from_infos<A, M>(module: &M, infos: &A) -> usize
where
A: LWEInfos,
M: LWECompressedAlloc,
{
module.bytes_of_lwe_compressed_from_infos(infos)
}
pub fn bytes_of<M>(module: &M, base2k: Base2K, k: TorusPrecision) -> usize
where
M: LWECompressedAlloc,
{
module.bytes_of_lwe_compressed(base2k, k)
}
}
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
impl<D: DataMut> ReaderFrom for LWECiphertextCompressed<D> {
impl<D: DataMut> ReaderFrom for LWECompressed<D> {
fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> {
self.k = TorusPrecision(reader.read_u32::<LittleEndian>()?);
self.base2k = Base2K(reader.read_u32::<LittleEndian>()?);
@@ -99,7 +136,7 @@ impl<D: DataMut> ReaderFrom for LWECiphertextCompressed<D> {
}
}
impl<D: DataRef> WriterTo for LWECiphertextCompressed<D> {
impl<D: DataRef> WriterTo for LWECompressed<D> {
fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
writer.write_u32::<LittleEndian>(self.k.into())?;
writer.write_u32::<LittleEndian>(self.base2k.into())?;
@@ -108,22 +145,72 @@ impl<D: DataRef> WriterTo for LWECiphertextCompressed<D> {
}
}
impl<D: DataMut, B: Backend, DR: DataRef> Decompress<B, LWECiphertextCompressed<DR>> for LWECiphertext<D>
pub trait LWEDecompress
where
Module<B>: ZnFillUniform,
Self: ZnFillUniform,
{
fn decompress(&mut self, module: &Module<B>, other: &LWECiphertextCompressed<DR>) {
debug_assert_eq!(self.size(), other.size());
fn decompress_lwe<R, O>(&self, res: &mut R, other: &O)
where
R: LWEToMut,
O: LWECompressedToRef,
{
let res: &mut LWE<&mut [u8]> = &mut res.to_mut();
let other: &LWECompressed<&[u8]> = &other.to_ref();
assert_eq!(res.lwe_layout(), other.lwe_layout());
let mut source: Source = Source::new(other.seed);
module.zn_fill_uniform(
self.n().into(),
self.zn_fill_uniform(
res.n().into(),
other.base2k().into(),
&mut self.data,
&mut res.data,
0,
&mut source,
);
(0..self.size()).for_each(|i| {
self.data.at_mut(0, i)[0] = other.data.at(0, i)[0];
});
for i in 0..res.size() {
res.data.at_mut(0, i)[0] = other.data.at(0, i)[0];
}
}
}
impl<B: Backend> LWEDecompress for Module<B> where Self: ZnFillUniform {}
impl<D: DataMut> LWE<D> {
pub fn decompress<O, M>(&mut self, module: &M, other: &O)
where
O: LWECompressedToRef,
M: LWEDecompress,
{
module.decompress_lwe(self, other);
}
}
pub trait LWECompressedToRef {
fn to_ref(&self) -> LWECompressed<&[u8]>;
}
impl<D: DataRef> LWECompressedToRef for LWECompressed<D> {
fn to_ref(&self) -> LWECompressed<&[u8]> {
LWECompressed {
k: self.k,
base2k: self.base2k,
seed: self.seed,
data: self.data.to_ref(),
}
}
}
pub trait LWECompressedToMut {
fn to_mut(&mut self) -> LWECompressed<&mut [u8]>;
}
impl<D: DataMut> LWECompressedToMut for LWECompressed<D> {
fn to_mut(&mut self) -> LWECompressed<&mut [u8]> {
LWECompressed {
k: self.k,
base2k: self.base2k,
seed: self.seed,
data: self.data.to_mut(),
}
}
}

View File

@@ -1,17 +1,20 @@
use poulpy_hal::{
api::{VecZnxCopy, VecZnxFillUniform},
layouts::{Backend, Data, DataMut, DataRef, FillUniform, Module, ReaderFrom, WriterTo},
source::Source,
};
use crate::layouts::{
Base2K, Degree, Dnum, Dsize, GGLWEInfos, GLWEInfos, LWEInfos, LWESwitchingKey, Rank, TorusPrecision,
compressed::{Decompress, GGLWESwitchingKeyCompressed},
Base2K, Dnum, Dsize, GGLWEInfos, GLWEInfos, LWEInfos, LWESwitchingKey, LWESwitchingKeyToMut, Rank, RingDegree,
TorusPrecision,
compressed::{
GLWESwitchingKeyCompressed, GLWESwitchingKeyCompressedAlloc, GLWESwitchingKeyCompressedToMut,
GLWESwitchingKeyCompressedToRef, GLWESwitchingKeyDecompress,
},
};
use std::fmt;
#[derive(PartialEq, Eq, Clone)]
pub struct LWESwitchingKeyCompressed<D: Data>(pub(crate) GGLWESwitchingKeyCompressed<D>);
pub struct LWESwitchingKeyCompressed<D: Data>(pub(crate) GLWESwitchingKeyCompressed<D>);
impl<D: Data> LWEInfos for LWESwitchingKeyCompressed<D> {
fn base2k(&self) -> Base2K {
@@ -22,7 +25,7 @@ impl<D: Data> LWEInfos for LWESwitchingKeyCompressed<D> {
self.0.k()
}
fn n(&self) -> Degree {
fn n(&self) -> RingDegree {
self.0.n()
}
fn size(&self) -> usize {
@@ -83,73 +86,149 @@ impl<D: DataRef> WriterTo for LWESwitchingKeyCompressed<D> {
}
}
impl LWESwitchingKeyCompressed<Vec<u8>> {
pub fn alloc<A>(infos: &A) -> Self
pub trait LWESwitchingKeyCompressedAlloc
where
Self: GLWESwitchingKeyCompressedAlloc,
{
fn alloc_lwe_switching_key_compressed(
&self,
base2k: Base2K,
k: TorusPrecision,
dnum: Dnum,
) -> LWESwitchingKeyCompressed<Vec<u8>> {
LWESwitchingKeyCompressed(self.alloc_glwe_switching_key_compressed(base2k, k, Rank(1), Rank(1), dnum, Dsize(1)))
}
fn alloc_lwe_switching_key_compressed_from_infos<A>(&self, infos: &A) -> LWESwitchingKeyCompressed<Vec<u8>>
where
A: GGLWEInfos,
{
debug_assert_eq!(
assert_eq!(
infos.dsize().0,
1,
"dsize > 1 is not supported for LWESwitchingKeyCompressed"
);
debug_assert_eq!(
assert_eq!(
infos.rank_in().0,
1,
"rank_in > 1 is not supported for LWESwitchingKeyCompressed"
);
debug_assert_eq!(
assert_eq!(
infos.rank_out().0,
1,
"rank_out > 1 is not supported for LWESwitchingKeyCompressed"
);
Self(GGLWESwitchingKeyCompressed::alloc(infos))
self.alloc_lwe_switching_key_compressed(infos.base2k(), infos.k(), infos.dnum())
}
pub fn alloc_with(n: Degree, base2k: Base2K, k: TorusPrecision, dnum: Dnum) -> Self {
Self(GGLWESwitchingKeyCompressed::alloc_with(
n,
base2k,
k,
Rank(1),
Rank(1),
dnum,
Dsize(1),
))
fn bytes_of_lwe_switching_key_compressed(&self, base2k: Base2K, k: TorusPrecision, dnum: Dnum) -> usize {
self.bytes_of_glwe_switching_key_compressed(base2k, k, Rank(1), dnum, Dsize(1))
}
pub fn alloc_bytes<A>(infos: &A) -> usize
fn bytes_of_lwe_switching_key_compressed_from_infos<A>(&self, infos: &A) -> usize
where
A: GGLWEInfos,
{
debug_assert_eq!(
assert_eq!(
infos.dsize().0,
1,
"dsize > 1 is not supported for LWESwitchingKey"
"dsize > 1 is not supported for LWESwitchingKeyCompressed"
);
debug_assert_eq!(
assert_eq!(
infos.rank_in().0,
1,
"rank_in > 1 is not supported for LWESwitchingKey"
"rank_in > 1 is not supported for LWESwitchingKeyCompressed"
);
debug_assert_eq!(
assert_eq!(
infos.rank_out().0,
1,
"rank_out > 1 is not supported for LWESwitchingKey"
"rank_out > 1 is not supported for LWESwitchingKeyCompressed"
);
GGLWESwitchingKeyCompressed::alloc_bytes(infos)
}
pub fn alloc_bytes_with(n: Degree, base2k: Base2K, k: TorusPrecision, dnum: Dnum) -> usize {
GGLWESwitchingKeyCompressed::alloc_bytes_with(n, base2k, k, Rank(1), dnum, Dsize(1))
self.bytes_of_glwe_switching_key_compressed_from_infos(infos)
}
}
impl<D: DataMut, DR: DataRef, B: Backend> Decompress<B, LWESwitchingKeyCompressed<DR>> for LWESwitchingKey<D>
impl<B: Backend> LWESwitchingKeyCompressedAlloc for Module<B> where Self: GLWESwitchingKeyCompressedAlloc {}
impl LWESwitchingKeyCompressed<Vec<u8>> {
pub fn alloc_from_infos<A, M>(module: &M, infos: &A) -> Self
where
A: GGLWEInfos,
M: LWESwitchingKeyCompressedAlloc,
{
module.alloc_lwe_switching_key_compressed_from_infos(infos)
}
pub fn alloc<M>(module: &M, base2k: Base2K, k: TorusPrecision, dnum: Dnum) -> Self
where
M: LWESwitchingKeyCompressedAlloc,
{
module.alloc_lwe_switching_key_compressed(base2k, k, dnum)
}
pub fn bytes_of_from_infos<A, M>(module: &M, infos: &A) -> usize
where
A: GGLWEInfos,
M: LWESwitchingKeyCompressedAlloc,
{
module.bytes_of_lwe_switching_key_compressed_from_infos(infos)
}
pub fn bytes_of<M>(module: &M, base2k: Base2K, k: TorusPrecision, dnum: Dnum) -> usize
where
M: LWESwitchingKeyCompressedAlloc,
{
module.bytes_of_lwe_switching_key_compressed(base2k, k, dnum)
}
}
pub trait LWESwitchingKeyDecompress
where
Module<B>: VecZnxFillUniform + VecZnxCopy,
Self: GLWESwitchingKeyDecompress,
{
fn decompress(&mut self, module: &Module<B>, other: &LWESwitchingKeyCompressed<DR>) {
self.0.decompress(module, &other.0);
fn decompress_lwe_switching_key<R, O>(&self, res: &mut R, other: &O)
where
R: LWESwitchingKeyToMut,
O: LWESwitchingKeyCompressedToRef,
{
self.decompress_glwe_switching_key(&mut res.to_mut().0, &other.to_ref().0);
}
}
impl<B: Backend> LWESwitchingKeyDecompress for Module<B> where Self: GLWESwitchingKeyDecompress {}
impl<D: DataMut> LWESwitchingKey<D> {
pub fn decompress<O, M>(&mut self, module: &M, other: &O)
where
O: LWESwitchingKeyCompressedToRef,
M: LWESwitchingKeyDecompress,
{
module.decompress_lwe_switching_key(self, other);
}
}
pub trait LWESwitchingKeyCompressedToRef {
fn to_ref(&self) -> LWESwitchingKeyCompressed<&[u8]>;
}
impl<D: DataRef> LWESwitchingKeyCompressedToRef for LWESwitchingKeyCompressed<D>
where
GLWESwitchingKeyCompressed<D>: GLWESwitchingKeyCompressedToRef,
{
fn to_ref(&self) -> LWESwitchingKeyCompressed<&[u8]> {
LWESwitchingKeyCompressed(self.0.to_ref())
}
}
pub trait LWESwitchingKeyCompressedToMut {
fn to_mut(&mut self) -> LWESwitchingKeyCompressed<&mut [u8]>;
}
impl<D: DataMut> LWESwitchingKeyCompressedToMut for LWESwitchingKeyCompressed<D>
where
GLWESwitchingKeyCompressed<D>: GLWESwitchingKeyCompressedToMut,
{
fn to_mut(&mut self) -> LWESwitchingKeyCompressed<&mut [u8]> {
LWESwitchingKeyCompressed(self.0.to_mut())
}
}

View File

@@ -1,20 +1,23 @@
use poulpy_hal::{
api::{VecZnxCopy, VecZnxFillUniform},
layouts::{Backend, Data, DataMut, DataRef, FillUniform, Module, ReaderFrom, WriterTo},
source::Source,
};
use crate::layouts::{
Base2K, Degree, Dnum, Dsize, GGLWEInfos, GLWEInfos, LWEInfos, LWEToGLWESwitchingKey, Rank, TorusPrecision,
compressed::{Decompress, GGLWESwitchingKeyCompressed},
Base2K, Dnum, Dsize, GGLWEInfos, GLWEInfos, LWEInfos, LWEToGLWESwitchingKey, LWEToGLWESwitchingKeyToMut, Rank, RingDegree,
TorusPrecision,
compressed::{
GLWESwitchingKeyCompressed, GLWESwitchingKeyCompressedAlloc, GLWESwitchingKeyCompressedToMut,
GLWESwitchingKeyCompressedToRef, GLWESwitchingKeyDecompress,
},
};
use std::fmt;
#[derive(PartialEq, Eq, Clone)]
pub struct LWEToGLWESwitchingKeyCompressed<D: Data>(pub(crate) GGLWESwitchingKeyCompressed<D>);
pub struct LWEToGLWESwitchingKeyCompressed<D: Data>(pub(crate) GLWESwitchingKeyCompressed<D>);
impl<D: Data> LWEInfos for LWEToGLWESwitchingKeyCompressed<D> {
fn n(&self) -> Degree {
fn n(&self) -> RingDegree {
self.0.n()
}
@@ -83,63 +86,138 @@ impl<D: DataRef> WriterTo for LWEToGLWESwitchingKeyCompressed<D> {
}
}
impl LWEToGLWESwitchingKeyCompressed<Vec<u8>> {
pub fn alloc<A>(infos: &A) -> Self
pub trait LWEToGLWESwitchingKeyCompressedAlloc
where
Self: GLWESwitchingKeyCompressedAlloc,
{
fn alloc_lwe_to_glwe_switching_key_compressed(
&self,
base2k: Base2K,
k: TorusPrecision,
rank_out: Rank,
dnum: Dnum,
) -> LWEToGLWESwitchingKeyCompressed<Vec<u8>> {
LWEToGLWESwitchingKeyCompressed(self.alloc_glwe_switching_key_compressed(base2k, k, Rank(1), rank_out, dnum, Dsize(1)))
}
fn alloc_lwe_to_glwe_switching_key_compressed_from_infos<A>(&self, infos: &A) -> LWEToGLWESwitchingKeyCompressed<Vec<u8>>
where
A: GGLWEInfos,
{
debug_assert_eq!(
assert_eq!(
infos.dsize().0,
1,
"dsize > 1 is not supported for LWEToGLWESwitchingKeyCompressed"
);
debug_assert_eq!(
assert_eq!(
infos.rank_in().0,
1,
"rank_in > 1 is not supported for LWEToGLWESwitchingKeyCompressed"
);
Self(GGLWESwitchingKeyCompressed::alloc(infos))
self.alloc_lwe_to_glwe_switching_key_compressed(infos.base2k(), infos.k(), infos.rank_out(), infos.dnum())
}
pub fn alloc_with(n: Degree, base2k: Base2K, k: TorusPrecision, rank_out: Rank, dnum: Dnum) -> Self {
Self(GGLWESwitchingKeyCompressed::alloc_with(
n,
base2k,
k,
Rank(1),
rank_out,
dnum,
Dsize(1),
))
fn bytes_of_lwe_to_glwe_switching_key_compressed(&self, base2k: Base2K, k: TorusPrecision, dnum: Dnum) -> usize {
self.bytes_of_glwe_switching_key_compressed(base2k, k, Rank(1), dnum, Dsize(1))
}
pub fn alloc_bytes<A>(infos: &A) -> usize
fn bytes_of_lwe_to_glwe_switching_key_compressed_from_infos<A>(&self, infos: &A) -> usize
where
A: GGLWEInfos,
{
debug_assert_eq!(
infos.rank_in().0,
1,
"rank_in > 1 is not supported for LWEToGLWESwitchingKey"
);
debug_assert_eq!(
assert_eq!(
infos.dsize().0,
1,
"dsize > 1 is not supported for LWEToGLWESwitchingKey"
"dsize > 1 is not supported for LWEToGLWESwitchingKeyCompressed"
);
GGLWESwitchingKeyCompressed::alloc_bytes(infos)
}
pub fn alloc_bytes_with(n: Degree, base2k: Base2K, k: TorusPrecision, dnum: Dnum) -> usize {
GGLWESwitchingKeyCompressed::alloc_bytes_with(n, base2k, k, Rank(1), dnum, Dsize(1))
assert_eq!(
infos.rank_in().0,
1,
"rank_in > 1 is not supported for LWEToGLWESwitchingKeyCompressed"
);
self.bytes_of_lwe_to_glwe_switching_key_compressed(infos.base2k(), infos.k(), infos.dnum())
}
}
impl<D: DataMut, DR: DataRef, B: Backend> Decompress<B, LWEToGLWESwitchingKeyCompressed<DR>> for LWEToGLWESwitchingKey<D>
impl LWEToGLWESwitchingKeyCompressed<Vec<u8>> {
pub fn alloc<A, M>(module: &M, infos: &A) -> Self
where
A: GGLWEInfos,
M: LWEToGLWESwitchingKeyCompressedAlloc,
{
module.alloc_lwe_to_glwe_switching_key_compressed_from_infos(infos)
}
pub fn alloc_with<M>(module: &M, base2k: Base2K, k: TorusPrecision, rank_out: Rank, dnum: Dnum) -> Self
where
M: LWEToGLWESwitchingKeyCompressedAlloc,
{
module.alloc_lwe_to_glwe_switching_key_compressed(base2k, k, rank_out, dnum)
}
pub fn bytes_of_from_infos<A, M>(module: &M, infos: &A) -> usize
where
A: GGLWEInfos,
M: LWEToGLWESwitchingKeyCompressedAlloc,
{
module.bytes_of_lwe_to_glwe_switching_key_compressed_from_infos(infos)
}
pub fn bytes_of<M>(module: &M, base2k: Base2K, k: TorusPrecision, dnum: Dnum) -> usize
where
M: LWEToGLWESwitchingKeyCompressedAlloc,
{
module.bytes_of_lwe_to_glwe_switching_key_compressed(base2k, k, dnum)
}
}
pub trait LWEToGLWESwitchingKeyDecompress
where
Module<B>: VecZnxFillUniform + VecZnxCopy,
Self: GLWESwitchingKeyDecompress,
{
fn decompress(&mut self, module: &Module<B>, other: &LWEToGLWESwitchingKeyCompressed<DR>) {
self.0.decompress(module, &other.0);
fn decompress_lwe_to_glwe_switching_key<R, O>(&self, res: &mut R, other: &O)
where
R: LWEToGLWESwitchingKeyToMut,
O: LWEToGLWESwitchingKeyCompressedToRef,
{
self.decompress_glwe_switching_key(&mut res.to_mut().0, &other.to_ref().0);
}
}
impl<B: Backend> LWEToGLWESwitchingKeyDecompress for Module<B> where Self: GLWESwitchingKeyDecompress {}
impl<D: DataMut> LWEToGLWESwitchingKey<D> {
pub fn decompress<O, M>(&mut self, module: &M, other: &O)
where
O: LWEToGLWESwitchingKeyCompressedToRef,
M: LWEToGLWESwitchingKeyDecompress,
{
module.decompress_lwe_to_glwe_switching_key(self, other);
}
}
pub trait LWEToGLWESwitchingKeyCompressedToRef {
fn to_ref(&self) -> LWEToGLWESwitchingKeyCompressed<&[u8]>;
}
impl<D: DataRef> LWEToGLWESwitchingKeyCompressedToRef for LWEToGLWESwitchingKeyCompressed<D>
where
GLWESwitchingKeyCompressed<D>: GLWESwitchingKeyCompressedToRef,
{
fn to_ref(&self) -> LWEToGLWESwitchingKeyCompressed<&[u8]> {
LWEToGLWESwitchingKeyCompressed(self.0.to_ref())
}
}
pub trait LWEToGLWESwitchingKeyCompressedToMut {
fn to_mut(&mut self) -> LWEToGLWESwitchingKeyCompressed<&mut [u8]>;
}
impl<D: DataMut> LWEToGLWESwitchingKeyCompressedToMut for LWEToGLWESwitchingKeyCompressed<D>
where
GLWESwitchingKeyCompressed<D>: GLWESwitchingKeyCompressedToMut,
{
fn to_mut(&mut self) -> LWEToGLWESwitchingKeyCompressed<&mut [u8]> {
LWEToGLWESwitchingKeyCompressed(self.0.to_mut())
}
}

View File

@@ -19,9 +19,3 @@ pub use glwe_to_lwe_ksk::*;
pub use lwe_ct::*;
pub use lwe_ksk::*;
pub use lwe_to_glwe_ksk::*;
use poulpy_hal::layouts::{Backend, Module};
pub trait Decompress<B: Backend, C> {
fn decompress(&mut self, module: &Module<B>, other: &C);
}

View File

@@ -1,18 +1,19 @@
use poulpy_hal::{
layouts::{Data, DataMut, DataRef, FillUniform, ReaderFrom, WriterTo},
layouts::{Backend, Data, DataMut, DataRef, FillUniform, Module, ReaderFrom, WriterTo},
source::Source,
};
use crate::layouts::{
Base2K, Degree, Dnum, Dsize, GGLWEInfos, GGLWESwitchingKey, GLWECiphertext, GLWEInfos, LWEInfos, Rank, TorusPrecision,
Base2K, Dnum, Dsize, GGLWEInfos, GLWE, GLWEInfos, GLWESwitchingKey, GLWESwitchingKeyAlloc, GLWESwitchingKeyToMut,
GLWESwitchingKeyToRef, LWEInfos, Rank, RingDegree, TorusPrecision,
};
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use std::fmt;
#[derive(PartialEq, Eq, Copy, Clone, Debug)]
pub struct GGLWEAutomorphismKeyLayout {
pub n: Degree,
pub struct AutomorphismKeyLayout {
pub n: RingDegree,
pub base2k: Base2K,
pub k: TorusPrecision,
pub rank: Rank,
@@ -21,19 +22,19 @@ pub struct GGLWEAutomorphismKeyLayout {
}
#[derive(PartialEq, Eq, Clone)]
pub struct GGLWEAutomorphismKey<D: Data> {
pub(crate) key: GGLWESwitchingKey<D>,
pub struct AutomorphismKey<D: Data> {
pub(crate) key: GLWESwitchingKey<D>,
pub(crate) p: i64,
}
impl<D: Data> GGLWEAutomorphismKey<D> {
impl<D: Data> AutomorphismKey<D> {
pub fn p(&self) -> i64 {
self.p
}
}
impl<D: Data> LWEInfos for GGLWEAutomorphismKey<D> {
fn n(&self) -> Degree {
impl<D: Data> LWEInfos for AutomorphismKey<D> {
fn n(&self) -> RingDegree {
self.key.n()
}
@@ -50,13 +51,13 @@ impl<D: Data> LWEInfos for GGLWEAutomorphismKey<D> {
}
}
impl<D: Data> GLWEInfos for GGLWEAutomorphismKey<D> {
impl<D: Data> GLWEInfos for AutomorphismKey<D> {
fn rank(&self) -> Rank {
self.rank_out()
}
}
impl<D: Data> GGLWEInfos for GGLWEAutomorphismKey<D> {
impl<D: Data> GGLWEInfos for AutomorphismKey<D> {
fn rank_in(&self) -> Rank {
self.key.rank_in()
}
@@ -74,7 +75,7 @@ impl<D: Data> GGLWEInfos for GGLWEAutomorphismKey<D> {
}
}
impl LWEInfos for GGLWEAutomorphismKeyLayout {
impl LWEInfos for AutomorphismKeyLayout {
fn base2k(&self) -> Base2K {
self.base2k
}
@@ -83,18 +84,18 @@ impl LWEInfos for GGLWEAutomorphismKeyLayout {
self.k
}
fn n(&self) -> Degree {
fn n(&self) -> RingDegree {
self.n
}
}
impl GLWEInfos for GGLWEAutomorphismKeyLayout {
impl GLWEInfos for AutomorphismKeyLayout {
fn rank(&self) -> Rank {
self.rank
}
}
impl GGLWEInfos for GGLWEAutomorphismKeyLayout {
impl GGLWEInfos for AutomorphismKeyLayout {
fn rank_in(&self) -> Rank {
self.rank
}
@@ -112,84 +113,164 @@ impl GGLWEInfos for GGLWEAutomorphismKeyLayout {
}
}
impl<D: DataRef> fmt::Debug for GGLWEAutomorphismKey<D> {
impl<D: DataRef> fmt::Debug for AutomorphismKey<D> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{self}")
}
}
impl<D: DataMut> FillUniform for GGLWEAutomorphismKey<D> {
impl<D: DataMut> FillUniform for AutomorphismKey<D> {
fn fill_uniform(&mut self, log_bound: usize, source: &mut Source) {
self.key.fill_uniform(log_bound, source);
}
}
impl<D: DataRef> fmt::Display for GGLWEAutomorphismKey<D> {
impl<D: DataRef> fmt::Display for AutomorphismKey<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<A>(infos: &A) -> Self
impl<B: Backend> AutomorphismKeyAlloc for Module<B> where Self: GLWESwitchingKeyAlloc {}
pub trait AutomorphismKeyAlloc
where
Self: GLWESwitchingKeyAlloc,
{
fn alloc_automorphism_key(
&self,
base2k: Base2K,
k: TorusPrecision,
rank: Rank,
dnum: Dnum,
dsize: Dsize,
) -> AutomorphismKey<Vec<u8>> {
AutomorphismKey {
key: self.alloc_glwe_switching_key(base2k, k, rank, rank, dnum, dsize),
p: 0,
}
}
fn alloc_automorphism_key_from_infos<A>(&self, infos: &A) -> AutomorphismKey<Vec<u8>>
where
A: GGLWEInfos,
{
self.alloc_automorphism_key(
infos.base2k(),
infos.k(),
infos.rank(),
infos.dnum(),
infos.dsize(),
)
}
fn bytes_of_automorphism_key(&self, base2k: Base2K, k: TorusPrecision, rank: Rank, dnum: Dnum, dsize: Dsize) -> usize {
self.bytes_of_glwe_switching_key(base2k, k, rank, rank, dnum, dsize)
}
fn bytes_of_automorphism_key_from_infos<A>(&self, infos: &A) -> usize
where
A: GGLWEInfos,
{
assert_eq!(
infos.rank_in(),
infos.rank_out(),
"rank_in != rank_out is not supported for GGLWEAutomorphismKey"
"rank_in != rank_out is not supported for AutomorphismKey"
);
GGLWEAutomorphismKey {
key: GGLWESwitchingKey::alloc(infos),
p: 0,
}
}
pub fn alloc_with(n: Degree, base2k: Base2K, k: TorusPrecision, rank: Rank, dnum: Dnum, dsize: Dsize) -> Self {
GGLWEAutomorphismKey {
key: GGLWESwitchingKey::alloc_with(n, base2k, k, rank, rank, dnum, dsize),
p: 0,
}
}
pub fn alloc_bytes<A>(infos: &A) -> usize
where
A: GGLWEInfos,
{
assert_eq!(
infos.rank_in(),
infos.rank_out(),
"rank_in != rank_out is not supported for GGLWEAutomorphismKey"
);
GGLWESwitchingKey::alloc_bytes(infos)
}
pub fn bytes_of(n: Degree, base2k: Base2K, k: TorusPrecision, rank: Rank, dnum: Dnum, dsize: Dsize) -> usize {
GGLWESwitchingKey::alloc_bytes_with(n, base2k, k, rank, rank, dnum, dsize)
self.bytes_of_automorphism_key(
infos.base2k(),
infos.k(),
infos.rank(),
infos.dnum(),
infos.dsize(),
)
}
}
impl<D: DataRef> GGLWEAutomorphismKey<D> {
pub fn at(&self, row: usize, col: usize) -> GLWECiphertext<&[u8]> {
impl AutomorphismKey<Vec<u8>> {
pub fn alloc_from_infos<A, M>(module: &M, infos: &A) -> Self
where
A: GGLWEInfos,
M: AutomorphismKeyAlloc,
{
module.alloc_automorphism_key_from_infos(infos)
}
pub fn alloc_with<M>(module: &M, base2k: Base2K, k: TorusPrecision, rank: Rank, dnum: Dnum, dsize: Dsize) -> Self
where
M: AutomorphismKeyAlloc,
{
module.alloc_automorphism_key(base2k, k, rank, dnum, dsize)
}
pub fn bytes_of_from_infos<A, M>(module: &M, infos: &A) -> usize
where
A: GGLWEInfos,
M: AutomorphismKeyAlloc,
{
module.bytes_of_automorphism_key_from_infos(infos)
}
pub fn bytes_of<M>(module: &M, base2k: Base2K, k: TorusPrecision, rank: Rank, dnum: Dnum, dsize: Dsize) -> usize
where
M: AutomorphismKeyAlloc,
{
module.bytes_of_automorphism_key(base2k, k, rank, dnum, dsize)
}
}
pub trait AutomorphismKeyToMut {
fn to_mut(&mut self) -> AutomorphismKey<&mut [u8]>;
}
impl<D: DataMut> AutomorphismKeyToMut for AutomorphismKey<D>
where
GLWESwitchingKey<D>: GLWESwitchingKeyToMut,
{
fn to_mut(&mut self) -> AutomorphismKey<&mut [u8]> {
AutomorphismKey {
key: self.key.to_mut(),
p: self.p,
}
}
}
pub trait AutomorphismKeyToRef {
fn to_ref(&self) -> AutomorphismKey<&[u8]>;
}
impl<D: DataRef> AutomorphismKeyToRef for AutomorphismKey<D>
where
GLWESwitchingKey<D>: GLWESwitchingKeyToRef,
{
fn to_ref(&self) -> AutomorphismKey<&[u8]> {
AutomorphismKey {
p: self.p,
key: self.key.to_ref(),
}
}
}
impl<D: DataRef> AutomorphismKey<D> {
pub fn at(&self, row: usize, col: usize) -> GLWE<&[u8]> {
self.key.at(row, col)
}
}
impl<D: DataMut> GGLWEAutomorphismKey<D> {
pub fn at_mut(&mut self, row: usize, col: usize) -> GLWECiphertext<&mut [u8]> {
impl<D: DataMut> AutomorphismKey<D> {
pub fn at_mut(&mut self, row: usize, col: usize) -> GLWE<&mut [u8]> {
self.key.at_mut(row, col)
}
}
impl<D: DataMut> ReaderFrom for GGLWEAutomorphismKey<D> {
impl<D: DataMut> ReaderFrom for AutomorphismKey<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> {
impl<D: DataRef> WriterTo for AutomorphismKey<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

@@ -1,9 +1,11 @@
use poulpy_hal::{
layouts::{Data, DataMut, DataRef, FillUniform, MatZnx, ReaderFrom, WriterTo, ZnxInfos},
layouts::{
Backend, Data, DataMut, DataRef, FillUniform, MatZnx, MatZnxToMut, MatZnxToRef, Module, ReaderFrom, WriterTo, ZnxInfos,
},
source::Source,
};
use crate::layouts::{Base2K, BuildError, Degree, Dnum, Dsize, GLWECiphertext, GLWEInfos, LWEInfos, Rank, TorusPrecision};
use crate::layouts::{Base2K, Dnum, Dsize, GLWE, GLWEInfos, GetRingDegree, LWEInfos, Rank, RingDegree, TorusPrecision};
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use std::fmt;
@@ -16,8 +18,8 @@ where
fn dsize(&self) -> Dsize;
fn rank_in(&self) -> Rank;
fn rank_out(&self) -> Rank;
fn layout(&self) -> GGLWECiphertextLayout {
GGLWECiphertextLayout {
fn gglwe_layout(&self) -> GGLWELayout {
GGLWELayout {
n: self.n(),
base2k: self.base2k(),
k: self.k(),
@@ -29,9 +31,13 @@ where
}
}
pub trait SetGGLWEInfos {
fn set_dsize(&mut self, dsize: usize);
}
#[derive(PartialEq, Eq, Copy, Clone, Debug)]
pub struct GGLWECiphertextLayout {
pub n: Degree,
pub struct GGLWELayout {
pub n: RingDegree,
pub base2k: Base2K,
pub k: TorusPrecision,
pub rank_in: Rank,
@@ -40,7 +46,7 @@ pub struct GGLWECiphertextLayout {
pub dsize: Dsize,
}
impl LWEInfos for GGLWECiphertextLayout {
impl LWEInfos for GGLWELayout {
fn base2k(&self) -> Base2K {
self.base2k
}
@@ -49,18 +55,18 @@ impl LWEInfos for GGLWECiphertextLayout {
self.k
}
fn n(&self) -> Degree {
fn n(&self) -> RingDegree {
self.n
}
}
impl GLWEInfos for GGLWECiphertextLayout {
impl GLWEInfos for GGLWELayout {
fn rank(&self) -> Rank {
self.rank_out
}
}
impl GGLWEInfos for GGLWECiphertextLayout {
impl GGLWEInfos for GGLWELayout {
fn rank_in(&self) -> Rank {
self.rank_in
}
@@ -79,14 +85,14 @@ impl GGLWEInfos for GGLWECiphertextLayout {
}
#[derive(PartialEq, Eq, Clone)]
pub struct GGLWECiphertext<D: Data> {
pub struct GGLWE<D: Data> {
pub(crate) data: MatZnx<D>,
pub(crate) k: TorusPrecision,
pub(crate) base2k: Base2K,
pub(crate) dsize: Dsize,
}
impl<D: Data> LWEInfos for GGLWECiphertext<D> {
impl<D: Data> LWEInfos for GGLWE<D> {
fn base2k(&self) -> Base2K {
self.base2k
}
@@ -95,8 +101,8 @@ impl<D: Data> LWEInfos for GGLWECiphertext<D> {
self.k
}
fn n(&self) -> Degree {
Degree(self.data.n() as u32)
fn n(&self) -> RingDegree {
RingDegree(self.data.n() as u32)
}
fn size(&self) -> usize {
@@ -104,13 +110,13 @@ impl<D: Data> LWEInfos for GGLWECiphertext<D> {
}
}
impl<D: Data> GLWEInfos for GGLWECiphertext<D> {
impl<D: Data> GLWEInfos for GGLWE<D> {
fn rank(&self) -> Rank {
self.rank_out()
}
}
impl<D: Data> GGLWEInfos for GGLWECiphertext<D> {
impl<D: Data> GGLWEInfos for GGLWE<D> {
fn rank_in(&self) -> Rank {
Rank(self.data.cols_in() as u32)
}
@@ -128,136 +134,35 @@ impl<D: Data> GGLWEInfos for GGLWECiphertext<D> {
}
}
pub struct GGLWECiphertextBuilder<D: Data> {
data: Option<MatZnx<D>>,
base2k: Option<Base2K>,
k: Option<TorusPrecision>,
dsize: Option<Dsize>,
}
impl<D: Data> GGLWECiphertext<D> {
#[inline]
pub fn builder() -> GGLWECiphertextBuilder<D> {
GGLWECiphertextBuilder {
data: None,
base2k: None,
k: None,
dsize: None,
}
}
}
impl GGLWECiphertextBuilder<Vec<u8>> {
#[inline]
pub fn layout<A>(mut self, infos: &A) -> Self
where
A: GGLWEInfos,
{
self.data = Some(MatZnx::alloc(
infos.n().into(),
infos.dnum().into(),
infos.rank_in().into(),
(infos.rank_out() + 1).into(),
infos.size(),
));
self.base2k = Some(infos.base2k());
self.k = Some(infos.k());
self.dsize = Some(infos.dsize());
self
}
}
impl<D: Data> GGLWECiphertextBuilder<D> {
#[inline]
pub fn data(mut self, data: MatZnx<D>) -> Self {
self.data = Some(data);
self
}
#[inline]
pub fn base2k(mut self, base2k: Base2K) -> Self {
self.base2k = Some(base2k);
self
}
#[inline]
pub fn k(mut self, k: TorusPrecision) -> Self {
self.k = Some(k);
self
}
#[inline]
pub fn dsize(mut self, dsize: Dsize) -> Self {
self.dsize = Some(dsize);
self
}
pub fn build(self) -> Result<GGLWECiphertext<D>, BuildError> {
let data: MatZnx<D> = self.data.ok_or(BuildError::MissingData)?;
let base2k: Base2K = self.base2k.ok_or(BuildError::MissingBase2K)?;
let k: TorusPrecision = self.k.ok_or(BuildError::MissingK)?;
let dsize: Dsize = self.dsize.ok_or(BuildError::MissingDigits)?;
if base2k == 0_u32 {
return Err(BuildError::ZeroBase2K);
}
if dsize == 0_u32 {
return Err(BuildError::ZeroBase2K);
}
if k == 0_u32 {
return Err(BuildError::ZeroTorusPrecision);
}
if data.n() == 0 {
return Err(BuildError::ZeroDegree);
}
if data.cols() == 0 {
return Err(BuildError::ZeroCols);
}
if data.size() == 0 {
return Err(BuildError::ZeroLimbs);
}
Ok(GGLWECiphertext {
data,
base2k,
k,
dsize,
})
}
}
impl<D: DataRef> GGLWECiphertext<D> {
impl<D: DataRef> GGLWE<D> {
pub fn data(&self) -> &MatZnx<D> {
&self.data
}
}
impl<D: DataMut> GGLWECiphertext<D> {
impl<D: DataMut> GGLWE<D> {
pub fn data_mut(&mut self) -> &mut MatZnx<D> {
&mut self.data
}
}
impl<D: DataRef> fmt::Debug for GGLWECiphertext<D> {
impl<D: DataRef> fmt::Debug for GGLWE<D> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{self}")
}
}
impl<D: DataMut> FillUniform for GGLWECiphertext<D> {
impl<D: DataMut> FillUniform for GGLWE<D> {
fn fill_uniform(&mut self, log_bound: usize, source: &mut Source) {
self.data.fill_uniform(log_bound, source);
}
}
impl<D: DataRef> fmt::Display for GGLWECiphertext<D> {
impl<D: DataRef> fmt::Display for GGLWE<D> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"(GGLWECiphertext: k={} base2k={} dsize={}) {}",
"(GGLWE: k={} base2k={} dsize={}) {}",
self.k().0,
self.base2k().0,
self.dsize().0,
@@ -266,53 +171,39 @@ impl<D: DataRef> fmt::Display for GGLWECiphertext<D> {
}
}
impl<D: DataRef> GGLWECiphertext<D> {
pub fn at(&self, row: usize, col: usize) -> GLWECiphertext<&[u8]> {
GLWECiphertext::builder()
.data(self.data.at(row, col))
.base2k(self.base2k())
.k(self.k())
.build()
.unwrap()
impl<D: DataRef> GGLWE<D> {
pub fn at(&self, row: usize, col: usize) -> GLWE<&[u8]> {
GLWE {
k: self.k,
base2k: self.base2k,
data: self.data.at(row, col),
}
}
}
impl<D: DataMut> GGLWECiphertext<D> {
pub fn at_mut(&mut self, row: usize, col: usize) -> GLWECiphertext<&mut [u8]> {
GLWECiphertext::builder()
.base2k(self.base2k())
.k(self.k())
.data(self.data.at_mut(row, col))
.build()
.unwrap()
impl<D: DataMut> GGLWE<D> {
pub fn at_mut(&mut self, row: usize, col: usize) -> GLWE<&mut [u8]> {
GLWE {
k: self.k,
base2k: self.base2k,
data: self.data.at_mut(row, col),
}
}
}
impl GGLWECiphertext<Vec<u8>> {
pub fn alloc<A>(infos: &A) -> Self
where
A: GGLWEInfos,
{
Self::alloc_with(
infos.n(),
infos.base2k(),
infos.k(),
infos.rank_in(),
infos.rank_out(),
infos.dnum(),
infos.dsize(),
)
}
pub fn alloc_with(
n: Degree,
pub trait GGLWEAlloc
where
Self: GetRingDegree,
{
fn alloc_gglwe(
&self,
base2k: Base2K,
k: TorusPrecision,
rank_in: Rank,
rank_out: Rank,
dnum: Dnum,
dsize: Dsize,
) -> Self {
) -> GGLWE<Vec<u8>> {
let size: usize = k.0.div_ceil(base2k.0) as usize;
debug_assert!(
size as u32 > dsize.0,
@@ -327,9 +218,9 @@ impl GGLWECiphertext<Vec<u8>> {
dsize.0,
);
Self {
GGLWE {
data: MatZnx::alloc(
n.into(),
self.ring_degree().into(),
dnum.into(),
rank_in.into(),
(rank_out + 1).into(),
@@ -341,12 +232,11 @@ impl GGLWECiphertext<Vec<u8>> {
}
}
pub fn alloc_bytes<A>(infos: &A) -> usize
fn alloc_glwe_from_infos<A>(&self, infos: &A) -> GGLWE<Vec<u8>>
where
A: GGLWEInfos,
{
Self::alloc_bytes_with(
infos.n(),
self.alloc_gglwe(
infos.base2k(),
infos.k(),
infos.rank_in(),
@@ -356,8 +246,8 @@ impl GGLWECiphertext<Vec<u8>> {
)
}
pub fn alloc_bytes_with(
n: Degree,
fn bytes_of_gglwe(
&self,
base2k: Base2K,
k: TorusPrecision,
rank_in: Rank,
@@ -379,17 +269,111 @@ impl GGLWECiphertext<Vec<u8>> {
dsize.0,
);
MatZnx::alloc_bytes(
n.into(),
MatZnx::bytes_of(
self.ring_degree().into(),
dnum.into(),
rank_in.into(),
(rank_out + 1).into(),
k.0.div_ceil(base2k.0) as usize,
)
}
fn bytes_of_gglwe_from_infos<A>(&self, infos: &A) -> usize
where
A: GGLWEInfos,
{
self.bytes_of_gglwe(
infos.base2k(),
infos.k(),
infos.rank_in(),
infos.rank_out(),
infos.dnum(),
infos.dsize(),
)
}
}
impl<D: DataMut> ReaderFrom for GGLWECiphertext<D> {
impl<B: Backend> GGLWEAlloc for Module<B> where Self: GetRingDegree {}
impl GGLWE<Vec<u8>> {
pub fn alloc_from_infos<A, M>(module: &M, infos: &A) -> Self
where
A: GGLWEInfos,
M: GGLWEAlloc,
{
module.alloc_glwe_from_infos(infos)
}
pub fn alloc<M>(
module: &M,
base2k: Base2K,
k: TorusPrecision,
rank_in: Rank,
rank_out: Rank,
dnum: Dnum,
dsize: Dsize,
) -> Self
where
M: GGLWEAlloc,
{
module.alloc_gglwe(base2k, k, rank_in, rank_out, dnum, dsize)
}
pub fn bytes_of_from_infos<A, M>(module: &M, infos: &A) -> usize
where
A: GGLWEInfos,
M: GGLWEAlloc,
{
module.bytes_of_gglwe_from_infos(infos)
}
pub fn bytes_of<M>(
module: &M,
base2k: Base2K,
k: TorusPrecision,
rank_in: Rank,
rank_out: Rank,
dnum: Dnum,
dsize: Dsize,
) -> usize
where
M: GGLWEAlloc,
{
module.bytes_of_gglwe(base2k, k, rank_in, rank_out, dnum, dsize)
}
}
pub trait GGLWEToMut {
fn to_mut(&mut self) -> GGLWE<&mut [u8]>;
}
impl<D: DataMut> GGLWEToMut for GGLWE<D> {
fn to_mut(&mut self) -> GGLWE<&mut [u8]> {
GGLWE {
k: self.k(),
base2k: self.base2k(),
dsize: self.dsize(),
data: self.data.to_mut(),
}
}
}
pub trait GGLWEToRef {
fn to_ref(&self) -> GGLWE<&[u8]>;
}
impl<D: DataRef> GGLWEToRef for GGLWE<D> {
fn to_ref(&self) -> GGLWE<&[u8]> {
GGLWE {
k: self.k(),
base2k: self.base2k(),
dsize: self.dsize(),
data: self.data.to_ref(),
}
}
}
impl<D: DataMut> ReaderFrom for GGLWE<D> {
fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> {
self.k = TorusPrecision(reader.read_u32::<LittleEndian>()?);
self.base2k = Base2K(reader.read_u32::<LittleEndian>()?);
@@ -398,7 +382,7 @@ impl<D: DataMut> ReaderFrom for GGLWECiphertext<D> {
}
}
impl<D: DataRef> WriterTo for GGLWECiphertext<D> {
impl<D: DataRef> WriterTo for GGLWE<D> {
fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
writer.write_u32::<LittleEndian>(self.k.0)?;
writer.write_u32::<LittleEndian>(self.base2k.0)?;

View File

@@ -1,18 +1,19 @@
use poulpy_hal::{
layouts::{Data, DataMut, DataRef, FillUniform, ReaderFrom, WriterTo},
layouts::{Backend, Data, DataMut, DataRef, FillUniform, Module, ReaderFrom, WriterTo},
source::Source,
};
use crate::layouts::{
Base2K, Degree, Dnum, Dsize, GGLWECiphertext, GGLWEInfos, GLWECiphertext, GLWEInfos, LWEInfos, Rank, TorusPrecision,
Base2K, Dnum, Dsize, GGLWE, GGLWEAlloc, GGLWEInfos, GGLWEToMut, GGLWEToRef, GLWE, GLWEInfos, LWEInfos, Rank, RingDegree,
TorusPrecision,
};
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use std::fmt;
#[derive(PartialEq, Eq, Copy, Clone, Debug)]
pub struct GGLWESwitchingKeyLayout {
pub n: Degree,
pub struct GLWESwitchingKeyLayout {
pub n: RingDegree,
pub base2k: Base2K,
pub k: TorusPrecision,
pub rank_in: Rank,
@@ -21,8 +22,8 @@ pub struct GGLWESwitchingKeyLayout {
pub dsize: Dsize,
}
impl LWEInfos for GGLWESwitchingKeyLayout {
fn n(&self) -> Degree {
impl LWEInfos for GLWESwitchingKeyLayout {
fn n(&self) -> RingDegree {
self.n
}
@@ -35,13 +36,13 @@ impl LWEInfos for GGLWESwitchingKeyLayout {
}
}
impl GLWEInfos for GGLWESwitchingKeyLayout {
impl GLWEInfos for GLWESwitchingKeyLayout {
fn rank(&self) -> Rank {
self.rank_out()
}
}
impl GGLWEInfos for GGLWESwitchingKeyLayout {
impl GGLWEInfos for GLWESwitchingKeyLayout {
fn rank_in(&self) -> Rank {
self.rank_in
}
@@ -60,14 +61,44 @@ impl GGLWEInfos for GGLWESwitchingKeyLayout {
}
#[derive(PartialEq, Eq, Clone)]
pub struct GGLWESwitchingKey<D: Data> {
pub(crate) key: GGLWECiphertext<D>,
pub struct GLWESwitchingKey<D: Data> {
pub(crate) key: GGLWE<D>,
pub(crate) sk_in_n: usize, // Degree of sk_in
pub(crate) sk_out_n: usize, // Degree of sk_out
}
impl<D: Data> LWEInfos for GGLWESwitchingKey<D> {
fn n(&self) -> Degree {
pub(crate) trait GLWESwitchingKeySetMetaData {
fn set_sk_in_n(&mut self, sk_in_n: usize);
fn set_sk_out_n(&mut self, sk_out_n: usize);
}
impl<D: DataMut> GLWESwitchingKeySetMetaData for GLWESwitchingKey<D> {
fn set_sk_in_n(&mut self, sk_in_n: usize) {
self.sk_in_n = sk_in_n
}
fn set_sk_out_n(&mut self, sk_out_n: usize) {
self.sk_out_n = sk_out_n
}
}
pub(crate) trait GLWESwtichingKeyGetMetaData {
fn sk_in_n(&self) -> usize;
fn sk_out_n(&self) -> usize;
}
impl<D: DataRef> GLWESwtichingKeyGetMetaData for GLWESwitchingKey<D> {
fn sk_in_n(&self) -> usize {
self.sk_in_n
}
fn sk_out_n(&self) -> usize {
self.sk_out_n
}
}
impl<D: Data> LWEInfos for GLWESwitchingKey<D> {
fn n(&self) -> RingDegree {
self.key.n()
}
@@ -84,13 +115,13 @@ impl<D: Data> LWEInfos for GGLWESwitchingKey<D> {
}
}
impl<D: Data> GLWEInfos for GGLWESwitchingKey<D> {
impl<D: Data> GLWEInfos for GLWESwitchingKey<D> {
fn rank(&self) -> Rank {
self.rank_out()
}
}
impl<D: Data> GGLWEInfos for GGLWESwitchingKey<D> {
impl<D: Data> GGLWEInfos for GLWESwitchingKey<D> {
fn rank_in(&self) -> Rank {
self.key.rank_in()
}
@@ -108,13 +139,13 @@ impl<D: Data> GGLWEInfos for GGLWESwitchingKey<D> {
}
}
impl<D: DataRef> fmt::Debug for GGLWESwitchingKey<D> {
impl<D: DataRef> fmt::Debug for GLWESwitchingKey<D> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{self}")
}
}
impl<D: DataRef> fmt::Display for GGLWESwitchingKey<D> {
impl<D: DataRef> fmt::Display for GLWESwitchingKey<D> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
@@ -126,49 +157,48 @@ impl<D: DataRef> fmt::Display for GGLWESwitchingKey<D> {
}
}
impl<D: DataMut> FillUniform for GGLWESwitchingKey<D> {
impl<D: DataMut> FillUniform for GLWESwitchingKey<D> {
fn fill_uniform(&mut self, log_bound: usize, source: &mut Source) {
self.key.fill_uniform(log_bound, source);
}
}
impl GGLWESwitchingKey<Vec<u8>> {
pub fn alloc<A>(infos: &A) -> Self
where
A: GGLWEInfos,
{
GGLWESwitchingKey {
key: GGLWECiphertext::alloc(infos),
sk_in_n: 0,
sk_out_n: 0,
}
}
pub fn alloc_with(
n: Degree,
pub trait GLWESwitchingKeyAlloc
where
Self: GGLWEAlloc,
{
fn alloc_glwe_switching_key(
&self,
base2k: Base2K,
k: TorusPrecision,
rank_in: Rank,
rank_out: Rank,
dnum: Dnum,
dsize: Dsize,
) -> Self {
GGLWESwitchingKey {
key: GGLWECiphertext::alloc_with(n, base2k, k, rank_in, rank_out, dnum, dsize),
) -> GLWESwitchingKey<Vec<u8>> {
GLWESwitchingKey {
key: self.alloc_gglwe(base2k, k, rank_in, rank_out, dnum, dsize),
sk_in_n: 0,
sk_out_n: 0,
}
}
pub fn alloc_bytes<A>(infos: &A) -> usize
fn alloc_glwe_switching_key_from_infos<A>(&self, infos: &A) -> GLWESwitchingKey<Vec<u8>>
where
A: GGLWEInfos,
{
GGLWECiphertext::alloc_bytes(infos)
self.alloc_glwe_switching_key(
infos.base2k(),
infos.k(),
infos.rank_in(),
infos.rank_out(),
infos.dnum(),
infos.dsize(),
)
}
pub fn alloc_bytes_with(
n: Degree,
fn bytes_of_glwe_switching_key(
&self,
base2k: Base2K,
k: TorusPrecision,
rank_in: Rank,
@@ -176,23 +206,121 @@ impl GGLWESwitchingKey<Vec<u8>> {
dnum: Dnum,
dsize: Dsize,
) -> usize {
GGLWECiphertext::alloc_bytes_with(n, base2k, k, rank_in, rank_out, dnum, dsize)
self.bytes_of_gglwe(base2k, k, rank_in, rank_out, dnum, dsize)
}
fn bytes_of_glwe_switching_key_from_infos<A>(&self, infos: &A) -> usize
where
A: GGLWEInfos,
{
self.bytes_of_glwe_switching_key(
infos.base2k(),
infos.k(),
infos.rank_in(),
infos.rank_out(),
infos.dnum(),
infos.dsize(),
)
}
}
impl<D: DataRef> GGLWESwitchingKey<D> {
pub fn at(&self, row: usize, col: usize) -> GLWECiphertext<&[u8]> {
impl<B: Backend> GLWESwitchingKeyAlloc for Module<B> where Self: GGLWEAlloc {}
impl GLWESwitchingKey<Vec<u8>> {
pub fn alloc_from_infos<A, M>(module: &M, infos: &A) -> Self
where
A: GGLWEInfos,
M: GLWESwitchingKeyAlloc,
{
module.alloc_glwe_switching_key_from_infos(infos)
}
pub fn alloc<M>(
module: &M,
base2k: Base2K,
k: TorusPrecision,
rank_in: Rank,
rank_out: Rank,
dnum: Dnum,
dsize: Dsize,
) -> Self
where
M: GLWESwitchingKeyAlloc,
{
module.alloc_glwe_switching_key(base2k, k, rank_in, rank_out, dnum, dsize)
}
pub fn bytes_of_from_infos<A, M>(module: &M, infos: &A) -> usize
where
A: GGLWEInfos,
M: GLWESwitchingKeyAlloc,
{
module.bytes_of_glwe_switching_key_from_infos(infos)
}
pub fn bytes_of<M>(
module: &M,
base2k: Base2K,
k: TorusPrecision,
rank_in: Rank,
rank_out: Rank,
dnum: Dnum,
dsize: Dsize,
) -> usize
where
M: GLWESwitchingKeyAlloc,
{
module.bytes_of_glwe_switching_key(base2k, k, rank_in, rank_out, dnum, dsize)
}
}
pub trait GLWESwitchingKeyToMut {
fn to_mut(&mut self) -> GLWESwitchingKey<&mut [u8]>;
}
impl<D: DataMut> GLWESwitchingKeyToMut for GLWESwitchingKey<D>
where
GGLWE<D>: GGLWEToMut,
{
fn to_mut(&mut self) -> GLWESwitchingKey<&mut [u8]> {
GLWESwitchingKey {
key: self.key.to_mut(),
sk_in_n: self.sk_in_n,
sk_out_n: self.sk_out_n,
}
}
}
pub trait GLWESwitchingKeyToRef {
fn to_ref(&self) -> GLWESwitchingKey<&[u8]>;
}
impl<D: DataRef> GLWESwitchingKeyToRef for GLWESwitchingKey<D>
where
GGLWE<D>: GGLWEToRef,
{
fn to_ref(&self) -> GLWESwitchingKey<&[u8]> {
GLWESwitchingKey {
key: self.key.to_ref(),
sk_in_n: self.sk_in_n,
sk_out_n: self.sk_out_n,
}
}
}
impl<D: DataRef> GLWESwitchingKey<D> {
pub fn at(&self, row: usize, col: usize) -> GLWE<&[u8]> {
self.key.at(row, col)
}
}
impl<D: DataMut> GGLWESwitchingKey<D> {
pub fn at_mut(&mut self, row: usize, col: usize) -> GLWECiphertext<&mut [u8]> {
impl<D: DataMut> GLWESwitchingKey<D> {
pub fn at_mut(&mut self, row: usize, col: usize) -> GLWE<&mut [u8]> {
self.key.at_mut(row, col)
}
}
impl<D: DataMut> ReaderFrom for GGLWESwitchingKey<D> {
impl<D: DataMut> ReaderFrom for GLWESwitchingKey<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;
@@ -200,7 +328,7 @@ impl<D: DataMut> ReaderFrom for GGLWESwitchingKey<D> {
}
}
impl<D: DataRef> WriterTo for GGLWESwitchingKey<D> {
impl<D: DataRef> WriterTo for GLWESwitchingKey<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)?;

View File

@@ -1,16 +1,19 @@
use poulpy_hal::{
layouts::{Data, DataMut, DataRef, FillUniform, ReaderFrom, WriterTo},
layouts::{Backend, Data, DataMut, DataRef, FillUniform, Module, ReaderFrom, WriterTo},
source::Source,
};
use crate::layouts::{Base2K, Degree, Dnum, Dsize, GGLWEInfos, GGLWESwitchingKey, GLWEInfos, LWEInfos, Rank, TorusPrecision};
use crate::layouts::{
Base2K, Dnum, Dsize, GGLWEInfos, GLWEInfos, GLWESwitchingKey, GLWESwitchingKeyAlloc, GLWESwitchingKeyToMut,
GLWESwitchingKeyToRef, LWEInfos, Rank, RingDegree, TorusPrecision,
};
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use std::fmt;
#[derive(PartialEq, Eq, Copy, Clone, Debug)]
pub struct GGLWETensorKeyLayout {
pub n: Degree,
pub struct TensorKeyLayout {
pub n: RingDegree,
pub base2k: Base2K,
pub k: TorusPrecision,
pub rank: Rank,
@@ -19,12 +22,12 @@ pub struct GGLWETensorKeyLayout {
}
#[derive(PartialEq, Eq, Clone)]
pub struct GGLWETensorKey<D: Data> {
pub(crate) keys: Vec<GGLWESwitchingKey<D>>,
pub struct TensorKey<D: Data> {
pub(crate) keys: Vec<GLWESwitchingKey<D>>,
}
impl<D: Data> LWEInfos for GGLWETensorKey<D> {
fn n(&self) -> Degree {
impl<D: Data> LWEInfos for TensorKey<D> {
fn n(&self) -> RingDegree {
self.keys[0].n()
}
@@ -41,13 +44,13 @@ impl<D: Data> LWEInfos for GGLWETensorKey<D> {
}
}
impl<D: Data> GLWEInfos for GGLWETensorKey<D> {
impl<D: Data> GLWEInfos for TensorKey<D> {
fn rank(&self) -> Rank {
self.keys[0].rank_out()
}
}
impl<D: Data> GGLWEInfos for GGLWETensorKey<D> {
impl<D: Data> GGLWEInfos for TensorKey<D> {
fn rank_in(&self) -> Rank {
self.rank_out()
}
@@ -65,8 +68,8 @@ impl<D: Data> GGLWEInfos for GGLWETensorKey<D> {
}
}
impl LWEInfos for GGLWETensorKeyLayout {
fn n(&self) -> Degree {
impl LWEInfos for TensorKeyLayout {
fn n(&self) -> RingDegree {
self.n
}
@@ -79,13 +82,13 @@ impl LWEInfos for GGLWETensorKeyLayout {
}
}
impl GLWEInfos for GGLWETensorKeyLayout {
impl GLWEInfos for TensorKeyLayout {
fn rank(&self) -> Rank {
self.rank_out()
}
}
impl GGLWEInfos for GGLWETensorKeyLayout {
impl GGLWEInfos for TensorKeyLayout {
fn rank_in(&self) -> Rank {
self.rank
}
@@ -103,21 +106,21 @@ impl GGLWEInfos for GGLWETensorKeyLayout {
}
}
impl<D: DataRef> fmt::Debug for GGLWETensorKey<D> {
impl<D: DataRef> fmt::Debug for TensorKey<D> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{self}")
}
}
impl<D: DataMut> FillUniform for GGLWETensorKey<D> {
impl<D: DataMut> FillUniform for TensorKey<D> {
fn fill_uniform(&mut self, log_bound: usize, source: &mut Source) {
self.keys
.iter_mut()
.for_each(|key: &mut GGLWESwitchingKey<D>| key.fill_uniform(log_bound, source))
.for_each(|key: &mut GLWESwitchingKey<D>| key.fill_uniform(log_bound, source))
}
}
impl<D: DataRef> fmt::Display for GGLWETensorKey<D> {
impl<D: DataRef> fmt::Display for TensorKey<D> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
writeln!(f, "(GLWETensorKey)",)?;
for (i, key) in self.keys.iter().enumerate() {
@@ -127,8 +130,20 @@ impl<D: DataRef> fmt::Display for GGLWETensorKey<D> {
}
}
impl GGLWETensorKey<Vec<u8>> {
pub fn alloc<A>(infos: &A) -> Self
pub trait TensorKeyAlloc
where
Self: GLWESwitchingKeyAlloc,
{
fn alloc_tensor_key(&self, base2k: Base2K, k: TorusPrecision, rank: Rank, dnum: Dnum, dsize: Dsize) -> TensorKey<Vec<u8>> {
let pairs: u32 = (((rank.0 + 1) * rank.0) >> 1).max(1);
TensorKey {
keys: (0..pairs)
.map(|_| self.alloc_glwe_switching_key(base2k, k, Rank(1), rank, dnum, dsize))
.collect(),
}
}
fn alloc_tensor_key_from_infos<A>(&self, infos: &A) -> TensorKey<Vec<u8>>
where
A: GGLWEInfos,
{
@@ -137,34 +152,21 @@ impl GGLWETensorKey<Vec<u8>> {
infos.rank_out(),
"rank_in != rank_out is not supported for GGLWETensorKey"
);
Self::alloc_with(
infos.n(),
self.alloc_tensor_key(
infos.base2k(),
infos.k(),
infos.rank_out(),
infos.rank(),
infos.dnum(),
infos.dsize(),
)
}
pub fn alloc_with(n: Degree, base2k: Base2K, k: TorusPrecision, rank: Rank, dnum: Dnum, dsize: Dsize) -> Self {
let mut keys: Vec<GGLWESwitchingKey<Vec<u8>>> = Vec::new();
let pairs: u32 = (((rank.0 + 1) * rank.0) >> 1).max(1);
(0..pairs).for_each(|_| {
keys.push(GGLWESwitchingKey::alloc_with(
n,
base2k,
k,
Rank(1),
rank,
dnum,
dsize,
));
});
Self { keys }
fn bytes_of_tensor_key(&self, base2k: Base2K, k: TorusPrecision, rank: Rank, dnum: Dnum, dsize: Dsize) -> usize {
let pairs: usize = (((rank.0 + 1) * rank.0) >> 1).max(1) as usize;
pairs * self.bytes_of_glwe_switching_key(base2k, k, Rank(1), rank, dnum, dsize)
}
pub fn alloc_bytes<A>(infos: &A) -> usize
fn bytes_of_tensor_key_from_infos<A>(&self, infos: &A) -> usize
where
A: GGLWEInfos,
{
@@ -173,29 +175,53 @@ impl GGLWETensorKey<Vec<u8>> {
infos.rank_out(),
"rank_in != rank_out is not supported for GGLWETensorKey"
);
let rank_out: usize = infos.rank_out().into();
let pairs: usize = (((rank_out + 1) * rank_out) >> 1).max(1);
pairs
* GGLWESwitchingKey::alloc_bytes_with(
infos.n(),
infos.base2k(),
infos.k(),
Rank(1),
infos.rank_out(),
infos.dnum(),
infos.dsize(),
)
}
pub fn alloc_bytes_with(n: Degree, base2k: Base2K, k: TorusPrecision, rank: Rank, dnum: Dnum, dsize: Dsize) -> usize {
let pairs: usize = (((rank.0 + 1) * rank.0) >> 1).max(1) as usize;
pairs * GGLWESwitchingKey::alloc_bytes_with(n, base2k, k, Rank(1), rank, dnum, dsize)
self.bytes_of_tensor_key(
infos.base2k(),
infos.k(),
infos.rank(),
infos.dnum(),
infos.dsize(),
)
}
}
impl<D: DataMut> GGLWETensorKey<D> {
impl<B: Backend> TensorKeyAlloc for Module<B> where Self: GLWESwitchingKeyAlloc {}
impl TensorKey<Vec<u8>> {
pub fn alloc_from_infos<A, M>(module: &M, infos: &A) -> Self
where
A: GGLWEInfos,
M: TensorKeyAlloc,
{
module.alloc_tensor_key_from_infos(infos)
}
pub fn alloc<M>(module: &M, base2k: Base2K, k: TorusPrecision, rank: Rank, dnum: Dnum, dsize: Dsize) -> Self
where
M: TensorKeyAlloc,
{
module.alloc_tensor_key(base2k, k, rank, dnum, dsize)
}
pub fn bytes_of_from_infos<A, M>(module: &M, infos: &A) -> usize
where
A: GGLWEInfos,
M: TensorKeyAlloc,
{
module.bytes_of_tensor_key_from_infos(infos)
}
pub fn bytes_of<M>(module: &M, base2k: Base2K, k: TorusPrecision, rank: Rank, dnum: Dnum, dsize: Dsize) -> usize
where
M: TensorKeyAlloc,
{
module.bytes_of_tensor_key(base2k, k, rank, dnum, dsize)
}
}
impl<D: DataMut> TensorKey<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> {
pub fn at_mut(&mut self, mut i: usize, mut j: usize) -> &mut GLWESwitchingKey<D> {
if i > j {
std::mem::swap(&mut i, &mut j);
};
@@ -204,9 +230,9 @@ impl<D: DataMut> GGLWETensorKey<D> {
}
}
impl<D: DataRef> GGLWETensorKey<D> {
impl<D: DataRef> TensorKey<D> {
// Returns a reference to GLWESwitchingKey_{s}(s[i] * s[j])
pub fn at(&self, mut i: usize, mut j: usize) -> &GGLWESwitchingKey<D> {
pub fn at(&self, mut i: usize, mut j: usize) -> &GLWESwitchingKey<D> {
if i > j {
std::mem::swap(&mut i, &mut j);
};
@@ -215,7 +241,7 @@ impl<D: DataRef> GGLWETensorKey<D> {
}
}
impl<D: DataMut> ReaderFrom for GGLWETensorKey<D> {
impl<D: DataMut> ReaderFrom for TensorKey<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 {
@@ -231,7 +257,7 @@ impl<D: DataMut> ReaderFrom for GGLWETensorKey<D> {
}
}
impl<D: DataRef> WriterTo for GGLWETensorKey<D> {
impl<D: DataRef> WriterTo for TensorKey<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 {
@@ -240,3 +266,33 @@ impl<D: DataRef> WriterTo for GGLWETensorKey<D> {
Ok(())
}
}
pub trait TensorKeyToRef {
fn to_ref(&self) -> TensorKey<&[u8]>;
}
impl<D: DataRef> TensorKeyToRef for TensorKey<D>
where
GLWESwitchingKey<D>: GLWESwitchingKeyToRef,
{
fn to_ref(&self) -> TensorKey<&[u8]> {
TensorKey {
keys: self.keys.iter().map(|c| c.to_ref()).collect(),
}
}
}
pub trait TensorKeyToMut {
fn to_mut(&mut self) -> TensorKey<&mut [u8]>;
}
impl<D: DataMut> TensorKeyToMut for TensorKey<D>
where
GLWESwitchingKey<D>: GLWESwitchingKeyToMut,
{
fn to_mut(&mut self) -> TensorKey<&mut [u8]> {
TensorKey {
keys: self.keys.iter_mut().map(|c| c.to_mut()).collect(),
}
}
}

View File

@@ -1,10 +1,12 @@
use poulpy_hal::{
layouts::{Data, DataMut, DataRef, FillUniform, MatZnx, ReaderFrom, WriterTo, ZnxInfos},
layouts::{
Backend, Data, DataMut, DataRef, FillUniform, MatZnx, MatZnxToMut, MatZnxToRef, Module, ReaderFrom, WriterTo, ZnxInfos,
},
source::Source,
};
use std::fmt;
use crate::layouts::{Base2K, BuildError, Degree, Dnum, Dsize, GLWECiphertext, GLWEInfos, LWEInfos, Rank, TorusPrecision};
use crate::layouts::{Base2K, Dnum, Dsize, GLWE, GLWEInfos, GetRingDegree, LWEInfos, Rank, RingDegree, TorusPrecision};
pub trait GGSWInfos
where
@@ -12,8 +14,8 @@ where
{
fn dnum(&self) -> Dnum;
fn dsize(&self) -> Dsize;
fn ggsw_layout(&self) -> GGSWCiphertextLayout {
GGSWCiphertextLayout {
fn ggsw_layout(&self) -> GGSWLayout {
GGSWLayout {
n: self.n(),
base2k: self.base2k(),
k: self.k(),
@@ -25,8 +27,8 @@ where
}
#[derive(PartialEq, Eq, Copy, Clone, Debug)]
pub struct GGSWCiphertextLayout {
pub n: Degree,
pub struct GGSWLayout {
pub n: RingDegree,
pub base2k: Base2K,
pub k: TorusPrecision,
pub rank: Rank,
@@ -34,7 +36,7 @@ pub struct GGSWCiphertextLayout {
pub dsize: Dsize,
}
impl LWEInfos for GGSWCiphertextLayout {
impl LWEInfos for GGSWLayout {
fn base2k(&self) -> Base2K {
self.base2k
}
@@ -43,17 +45,17 @@ impl LWEInfos for GGSWCiphertextLayout {
self.k
}
fn n(&self) -> Degree {
fn n(&self) -> RingDegree {
self.n
}
}
impl GLWEInfos for GGSWCiphertextLayout {
impl GLWEInfos for GGSWLayout {
fn rank(&self) -> Rank {
self.rank
}
}
impl GGSWInfos for GGSWCiphertextLayout {
impl GGSWInfos for GGSWLayout {
fn dsize(&self) -> Dsize {
self.dsize
}
@@ -64,16 +66,16 @@ impl GGSWInfos for GGSWCiphertextLayout {
}
#[derive(PartialEq, Eq, Clone)]
pub struct GGSWCiphertext<D: Data> {
pub struct GGSW<D: Data> {
pub(crate) data: MatZnx<D>,
pub(crate) k: TorusPrecision,
pub(crate) base2k: Base2K,
pub(crate) dsize: Dsize,
}
impl<D: Data> LWEInfos for GGSWCiphertext<D> {
fn n(&self) -> Degree {
Degree(self.data.n() as u32)
impl<D: Data> LWEInfos for GGSW<D> {
fn n(&self) -> RingDegree {
RingDegree(self.data.n() as u32)
}
fn base2k(&self) -> Base2K {
@@ -89,13 +91,13 @@ impl<D: Data> LWEInfos for GGSWCiphertext<D> {
}
}
impl<D: Data> GLWEInfos for GGSWCiphertext<D> {
impl<D: Data> GLWEInfos for GGSW<D> {
fn rank(&self) -> Rank {
Rank(self.data.cols_out() as u32 - 1)
}
}
impl<D: Data> GGSWInfos for GGSWCiphertext<D> {
impl<D: Data> GGSWInfos for GGSW<D> {
fn dsize(&self) -> Dsize {
self.dsize
}
@@ -105,133 +107,17 @@ impl<D: Data> GGSWInfos for GGSWCiphertext<D> {
}
}
pub struct GGSWCiphertextBuilder<D: Data> {
data: Option<MatZnx<D>>,
base2k: Option<Base2K>,
k: Option<TorusPrecision>,
dsize: Option<Dsize>,
}
impl<D: Data> GGSWCiphertext<D> {
#[inline]
pub fn builder() -> GGSWCiphertextBuilder<D> {
GGSWCiphertextBuilder {
data: None,
base2k: None,
k: None,
dsize: None,
}
}
}
impl GGSWCiphertextBuilder<Vec<u8>> {
#[inline]
pub fn layout<A>(mut self, infos: &A) -> Self
where
A: GGSWInfos,
{
debug_assert!(
infos.size() as u32 > infos.dsize().0,
"invalid ggsw: ceil(k/base2k): {} <= dsize: {}",
infos.size(),
infos.dsize()
);
assert!(
infos.dnum().0 * infos.dsize().0 <= infos.size() as u32,
"invalid ggsw: dnum: {} * dsize:{} > ceil(k/base2k): {}",
infos.dnum(),
infos.dsize(),
infos.size(),
);
self.data = Some(MatZnx::alloc(
infos.n().into(),
infos.dnum().into(),
(infos.rank() + 1).into(),
(infos.rank() + 1).into(),
infos.size(),
));
self.base2k = Some(infos.base2k());
self.k = Some(infos.k());
self.dsize = Some(infos.dsize());
self
}
}
impl<D: Data> GGSWCiphertextBuilder<D> {
#[inline]
pub fn data(mut self, data: MatZnx<D>) -> Self {
self.data = Some(data);
self
}
#[inline]
pub fn base2k(mut self, base2k: Base2K) -> Self {
self.base2k = Some(base2k);
self
}
#[inline]
pub fn k(mut self, k: TorusPrecision) -> Self {
self.k = Some(k);
self
}
#[inline]
pub fn dsize(mut self, dsize: Dsize) -> Self {
self.dsize = Some(dsize);
self
}
pub fn build(self) -> Result<GGSWCiphertext<D>, BuildError> {
let data: MatZnx<D> = self.data.ok_or(BuildError::MissingData)?;
let base2k: Base2K = self.base2k.ok_or(BuildError::MissingBase2K)?;
let k: TorusPrecision = self.k.ok_or(BuildError::MissingK)?;
let dsize: Dsize = self.dsize.ok_or(BuildError::MissingDigits)?;
if base2k == 0_u32 {
return Err(BuildError::ZeroBase2K);
}
if dsize == 0_u32 {
return Err(BuildError::ZeroBase2K);
}
if k == 0_u32 {
return Err(BuildError::ZeroTorusPrecision);
}
if data.n() == 0 {
return Err(BuildError::ZeroDegree);
}
if data.cols() == 0 {
return Err(BuildError::ZeroCols);
}
if data.size() == 0 {
return Err(BuildError::ZeroLimbs);
}
Ok(GGSWCiphertext {
data,
base2k,
k,
dsize,
})
}
}
impl<D: DataRef> fmt::Debug for GGSWCiphertext<D> {
impl<D: DataRef> fmt::Debug for GGSW<D> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.data)
}
}
impl<D: DataRef> fmt::Display for GGSWCiphertext<D> {
impl<D: DataRef> fmt::Display for GGSW<D> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"(GGSWCiphertext: k: {} base2k: {} dsize: {}) {}",
"(GGSW: k: {} base2k: {} dsize: {}) {}",
self.k().0,
self.base2k().0,
self.dsize().0,
@@ -240,50 +126,39 @@ impl<D: DataRef> fmt::Display for GGSWCiphertext<D> {
}
}
impl<D: DataMut> FillUniform for GGSWCiphertext<D> {
impl<D: DataMut> FillUniform for GGSW<D> {
fn fill_uniform(&mut self, log_bound: usize, source: &mut Source) {
self.data.fill_uniform(log_bound, source);
}
}
impl<D: DataRef> GGSWCiphertext<D> {
pub fn at(&self, row: usize, col: usize) -> GLWECiphertext<&[u8]> {
GLWECiphertext::builder()
.data(self.data.at(row, col))
.base2k(self.base2k())
.k(self.k())
.build()
.unwrap()
impl<D: DataRef> GGSW<D> {
pub fn at(&self, row: usize, col: usize) -> GLWE<&[u8]> {
GLWE {
k: self.k,
base2k: self.base2k,
data: self.data.at(row, col),
}
}
}
impl<D: DataMut> GGSWCiphertext<D> {
pub fn at_mut(&mut self, row: usize, col: usize) -> GLWECiphertext<&mut [u8]> {
GLWECiphertext::builder()
.base2k(self.base2k())
.k(self.k())
.data(self.data.at_mut(row, col))
.build()
.unwrap()
impl<D: DataMut> GGSW<D> {
pub fn at_mut(&mut self, row: usize, col: usize) -> GLWE<&mut [u8]> {
GLWE {
k: self.k,
base2k: self.base2k,
data: self.data.at_mut(row, col),
}
}
}
impl GGSWCiphertext<Vec<u8>> {
pub fn alloc<A>(infos: &A) -> Self
where
A: GGSWInfos,
{
Self::alloc_with(
infos.n(),
infos.base2k(),
infos.k(),
infos.rank(),
infos.dnum(),
infos.dsize(),
)
}
impl<B: Backend> GGSWAlloc for Module<B> where Self: GetRingDegree {}
pub fn alloc_with(n: Degree, base2k: Base2K, k: TorusPrecision, rank: Rank, dnum: Dnum, dsize: Dsize) -> Self {
pub trait GGSWAlloc
where
Self: GetRingDegree,
{
fn alloc_ggsw(&self, base2k: Base2K, k: TorusPrecision, rank: Rank, dnum: Dnum, dsize: Dsize) -> GGSW<Vec<u8>> {
let size: usize = k.0.div_ceil(base2k.0) as usize;
debug_assert!(
size as u32 > dsize.0,
@@ -298,9 +173,9 @@ impl GGSWCiphertext<Vec<u8>> {
dsize.0,
);
Self {
GGSW {
data: MatZnx::alloc(
n.into(),
self.ring_degree().into(),
dnum.into(),
(rank + 1).into(),
(rank + 1).into(),
@@ -312,12 +187,11 @@ impl GGSWCiphertext<Vec<u8>> {
}
}
pub fn alloc_bytes<A>(infos: &A) -> usize
fn alloc_ggsw_from_infos<A>(&self, infos: &A) -> GGSW<Vec<u8>>
where
A: GGSWInfos,
{
Self::alloc_bytes_with(
infos.n(),
self.alloc_ggsw(
infos.base2k(),
infos.k(),
infos.rank(),
@@ -326,7 +200,7 @@ impl GGSWCiphertext<Vec<u8>> {
)
}
pub fn alloc_bytes_with(n: Degree, base2k: Base2K, k: TorusPrecision, rank: Rank, dnum: Dnum, dsize: Dsize) -> usize {
fn bytes_of_ggsw(&self, base2k: Base2K, k: TorusPrecision, rank: Rank, dnum: Dnum, dsize: Dsize) -> usize {
let size: usize = k.0.div_ceil(base2k.0) as usize;
debug_assert!(
size as u32 > dsize.0,
@@ -341,19 +215,64 @@ impl GGSWCiphertext<Vec<u8>> {
dsize.0,
);
MatZnx::alloc_bytes(
n.into(),
MatZnx::bytes_of(
self.ring_degree().into(),
dnum.into(),
(rank + 1).into(),
(rank + 1).into(),
k.0.div_ceil(base2k.0) as usize,
)
}
fn bytes_of_ggsw_from_infos<A>(&self, infos: &A) -> usize
where
A: GGSWInfos,
{
self.bytes_of_ggsw(
infos.base2k(),
infos.k(),
infos.rank(),
infos.dnum(),
infos.dsize(),
)
}
}
impl GGSW<Vec<u8>> {
pub fn alloc_from_infos<A, M>(module: &M, infos: &A) -> Self
where
A: GGSWInfos,
M: GGSWAlloc,
{
module.alloc_ggsw_from_infos(infos)
}
pub fn alloc<M>(module: &M, base2k: Base2K, k: TorusPrecision, rank: Rank, dnum: Dnum, dsize: Dsize) -> Self
where
M: GGSWAlloc,
{
module.alloc_ggsw(base2k, k, rank, dnum, dsize)
}
pub fn bytes_of_from_infos<A, M>(module: &M, infos: &A) -> usize
where
A: GGSWInfos,
M: GGSWAlloc,
{
module.bytes_of_ggsw_from_infos(infos)
}
pub fn bytes_of<M>(module: &M, base2k: Base2K, k: TorusPrecision, rank: Rank, dnum: Dnum, dsize: Dsize) -> usize
where
M: GGSWAlloc,
{
module.bytes_of_ggsw(base2k, k, rank, dnum, dsize)
}
}
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
impl<D: DataMut> ReaderFrom for GGSWCiphertext<D> {
impl<D: DataMut> ReaderFrom for GGSW<D> {
fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> {
self.k = TorusPrecision(reader.read_u32::<LittleEndian>()?);
self.base2k = Base2K(reader.read_u32::<LittleEndian>()?);
@@ -362,7 +281,7 @@ impl<D: DataMut> ReaderFrom for GGSWCiphertext<D> {
}
}
impl<D: DataRef> WriterTo for GGSWCiphertext<D> {
impl<D: DataRef> WriterTo for GGSW<D> {
fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
writer.write_u32::<LittleEndian>(self.k.into())?;
writer.write_u32::<LittleEndian>(self.base2k.into())?;
@@ -370,3 +289,33 @@ impl<D: DataRef> WriterTo for GGSWCiphertext<D> {
self.data.write_to(writer)
}
}
pub trait GGSWToMut {
fn to_mut(&mut self) -> GGSW<&mut [u8]>;
}
impl<D: DataMut> GGSWToMut for GGSW<D> {
fn to_mut(&mut self) -> GGSW<&mut [u8]> {
GGSW {
dsize: self.dsize,
k: self.k,
base2k: self.base2k,
data: self.data.to_mut(),
}
}
}
pub trait GGSWToRef {
fn to_ref(&self) -> GGSW<&[u8]>;
}
impl<D: DataRef> GGSWToRef for GGSW<D> {
fn to_ref(&self) -> GGSW<&[u8]> {
GGSW {
dsize: self.dsize,
k: self.k,
base2k: self.base2k,
data: self.data.to_ref(),
}
}
}

View File

@@ -1,11 +1,12 @@
use poulpy_hal::{
layouts::{
Data, DataMut, DataRef, FillUniform, ReaderFrom, ToOwnedDeep, VecZnx, VecZnxToMut, VecZnxToRef, WriterTo, ZnxInfos,
Backend, Data, DataMut, DataRef, FillUniform, Module, ReaderFrom, ToOwnedDeep, VecZnx, VecZnxToMut, VecZnxToRef,
WriterTo, ZnxInfos,
},
source::Source,
};
use crate::layouts::{Base2K, BuildError, Degree, LWEInfos, Rank, TorusPrecision};
use crate::layouts::{Base2K, GetRingDegree, LWEInfos, Rank, RingDegree, TorusPrecision};
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use std::fmt;
@@ -14,8 +15,8 @@ where
Self: LWEInfos,
{
fn rank(&self) -> Rank;
fn glwe_layout(&self) -> GLWECiphertextLayout {
GLWECiphertextLayout {
fn glwe_layout(&self) -> GLWELayout {
GLWELayout {
n: self.n(),
base2k: self.base2k(),
k: self.k(),
@@ -24,21 +25,21 @@ where
}
}
pub trait GLWELayoutSet {
pub trait SetGLWEInfos {
fn set_k(&mut self, k: TorusPrecision);
fn set_basek(&mut self, base2k: Base2K);
fn set_base2k(&mut self, base2k: Base2K);
}
#[derive(PartialEq, Eq, Copy, Clone, Debug)]
pub struct GLWECiphertextLayout {
pub n: Degree,
pub struct GLWELayout {
pub n: RingDegree,
pub base2k: Base2K,
pub k: TorusPrecision,
pub rank: Rank,
}
impl LWEInfos for GLWECiphertextLayout {
fn n(&self) -> Degree {
impl LWEInfos for GLWELayout {
fn n(&self) -> RingDegree {
self.n
}
@@ -51,21 +52,21 @@ impl LWEInfos for GLWECiphertextLayout {
}
}
impl GLWEInfos for GLWECiphertextLayout {
impl GLWEInfos for GLWELayout {
fn rank(&self) -> Rank {
self.rank
}
}
#[derive(PartialEq, Eq, Clone)]
pub struct GLWECiphertext<D: Data> {
pub struct GLWE<D: Data> {
pub(crate) data: VecZnx<D>,
pub(crate) base2k: Base2K,
pub(crate) k: TorusPrecision,
}
impl<D: DataMut> GLWELayoutSet for GLWECiphertext<D> {
fn set_basek(&mut self, base2k: Base2K) {
impl<D: DataMut> SetGLWEInfos for GLWE<D> {
fn set_base2k(&mut self, base2k: Base2K) {
self.base2k = base2k
}
@@ -74,99 +75,19 @@ impl<D: DataMut> GLWELayoutSet for GLWECiphertext<D> {
}
}
impl<D: DataRef> GLWECiphertext<D> {
impl<D: DataRef> GLWE<D> {
pub fn data(&self) -> &VecZnx<D> {
&self.data
}
}
impl<D: DataMut> GLWECiphertext<D> {
impl<D: DataMut> GLWE<D> {
pub fn data_mut(&mut self) -> &mut VecZnx<D> {
&mut self.data
}
}
pub struct GLWECiphertextBuilder<D: Data> {
data: Option<VecZnx<D>>,
base2k: Option<Base2K>,
k: Option<TorusPrecision>,
}
impl<D: Data> GLWECiphertext<D> {
#[inline]
pub fn builder() -> GLWECiphertextBuilder<D> {
GLWECiphertextBuilder {
data: None,
base2k: None,
k: None,
}
}
}
impl GLWECiphertextBuilder<Vec<u8>> {
#[inline]
pub fn layout<A>(mut self, layout: &A) -> Self
where
A: GLWEInfos,
{
self.data = Some(VecZnx::alloc(
layout.n().into(),
(layout.rank() + 1).into(),
layout.size(),
));
self.base2k = Some(layout.base2k());
self.k = Some(layout.k());
self
}
}
impl<D: Data> GLWECiphertextBuilder<D> {
#[inline]
pub fn data(mut self, data: VecZnx<D>) -> Self {
self.data = Some(data);
self
}
#[inline]
pub fn base2k(mut self, base2k: Base2K) -> Self {
self.base2k = Some(base2k);
self
}
#[inline]
pub fn k(mut self, k: TorusPrecision) -> Self {
self.k = Some(k);
self
}
pub fn build(self) -> Result<GLWECiphertext<D>, BuildError> {
let data: VecZnx<D> = self.data.ok_or(BuildError::MissingData)?;
let base2k: Base2K = self.base2k.ok_or(BuildError::MissingBase2K)?;
let k: TorusPrecision = self.k.ok_or(BuildError::MissingK)?;
if base2k == 0_u32 {
return Err(BuildError::ZeroBase2K);
}
if k == 0_u32 {
return Err(BuildError::ZeroTorusPrecision);
}
if data.n() == 0 {
return Err(BuildError::ZeroDegree);
}
if data.cols() == 0 {
return Err(BuildError::ZeroCols);
}
if data.size() == 0 {
return Err(BuildError::ZeroLimbs);
}
Ok(GLWECiphertext { data, base2k, k })
}
}
impl<D: Data> LWEInfos for GLWECiphertext<D> {
impl<D: Data> LWEInfos for GLWE<D> {
fn base2k(&self) -> Base2K {
self.base2k
}
@@ -175,8 +96,8 @@ impl<D: Data> LWEInfos for GLWECiphertext<D> {
self.k
}
fn n(&self) -> Degree {
Degree(self.data.n() as u32)
fn n(&self) -> RingDegree {
RingDegree(self.data.n() as u32)
}
fn size(&self) -> usize {
@@ -184,16 +105,16 @@ impl<D: Data> LWEInfos for GLWECiphertext<D> {
}
}
impl<D: Data> GLWEInfos for GLWECiphertext<D> {
impl<D: Data> GLWEInfos for GLWE<D> {
fn rank(&self) -> Rank {
Rank(self.data.cols() as u32 - 1)
}
}
impl<D: DataRef> ToOwnedDeep for GLWECiphertext<D> {
type Owned = GLWECiphertext<Vec<u8>>;
impl<D: DataRef> ToOwnedDeep for GLWE<D> {
type Owned = GLWE<Vec<u8>>;
fn to_owned_deep(&self) -> Self::Owned {
GLWECiphertext {
GLWE {
data: self.data.to_owned_deep(),
k: self.k,
base2k: self.base2k,
@@ -201,17 +122,17 @@ impl<D: DataRef> ToOwnedDeep for GLWECiphertext<D> {
}
}
impl<D: DataRef> fmt::Debug for GLWECiphertext<D> {
impl<D: DataRef> fmt::Debug for GLWE<D> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{self}")
}
}
impl<D: DataRef> fmt::Display for GLWECiphertext<D> {
impl<D: DataRef> fmt::Display for GLWE<D> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"GLWECiphertext: base2k={} k={}: {}",
"GLWE: base2k={} k={}: {}",
self.base2k().0,
self.k().0,
self.data
@@ -219,71 +140,86 @@ impl<D: DataRef> fmt::Display for GLWECiphertext<D> {
}
}
impl<D: DataMut> FillUniform for GLWECiphertext<D> {
impl<D: DataMut> FillUniform for GLWE<D> {
fn fill_uniform(&mut self, log_bound: usize, source: &mut Source) {
self.data.fill_uniform(log_bound, source);
}
}
impl GLWECiphertext<Vec<u8>> {
pub fn alloc<A>(infos: &A) -> Self
where
A: GLWEInfos,
{
Self::alloc_with(infos.n(), infos.base2k(), infos.k(), infos.rank())
}
pub fn alloc_with(n: Degree, base2k: Base2K, k: TorusPrecision, rank: Rank) -> Self {
Self {
data: VecZnx::alloc(n.into(), (rank + 1).into(), k.0.div_ceil(base2k.0) as usize),
pub trait GLWEAlloc
where
Self: GetRingDegree,
{
fn alloc_glwe(&self, base2k: Base2K, k: TorusPrecision, rank: Rank) -> GLWE<Vec<u8>> {
GLWE {
data: VecZnx::alloc(
self.ring_degree().into(),
(rank + 1).into(),
k.0.div_ceil(base2k.0) as usize,
),
base2k,
k,
}
}
pub fn alloc_bytes<A>(infos: &A) -> usize
fn alloc_glwe_from_infos<A>(&self, infos: &A) -> GLWE<Vec<u8>>
where
A: GLWEInfos,
{
Self::alloc_bytes_with(infos.n(), infos.base2k(), infos.k(), infos.rank())
self.alloc_glwe(infos.base2k(), infos.k(), infos.rank())
}
pub fn alloc_bytes_with(n: Degree, base2k: Base2K, k: TorusPrecision, rank: Rank) -> usize {
VecZnx::alloc_bytes(n.into(), (rank + 1).into(), k.0.div_ceil(base2k.0) as usize)
fn bytes_of_glwe(&self, base2k: Base2K, k: TorusPrecision, rank: Rank) -> usize {
VecZnx::bytes_of(
self.ring_degree().into(),
(rank + 1).into(),
k.0.div_ceil(base2k.0) as usize,
)
}
fn bytes_of_glwe_from_infos<A>(&self, infos: &A) -> usize
where
A: GLWEInfos,
{
self.bytes_of_glwe(infos.base2k(), infos.k(), infos.rank())
}
}
pub trait GLWECiphertextToRef {
fn to_ref(&self) -> GLWECiphertext<&[u8]>;
}
impl<B: Backend> GLWEAlloc for Module<B> where Self: GetRingDegree {}
impl<D: DataRef> GLWECiphertextToRef for GLWECiphertext<D> {
fn to_ref(&self) -> GLWECiphertext<&[u8]> {
GLWECiphertext::builder()
.k(self.k())
.base2k(self.base2k())
.data(self.data.to_ref())
.build()
.unwrap()
impl GLWE<Vec<u8>> {
pub fn alloc_from_infos<A, M>(module: &M, infos: &A) -> Self
where
A: GLWEInfos,
M: GLWEAlloc,
{
module.alloc_glwe_from_infos(infos)
}
pub fn alloc<M>(module: &M, base2k: Base2K, k: TorusPrecision, rank: Rank) -> Self
where
M: GLWEAlloc,
{
module.alloc_glwe(base2k, k, rank)
}
pub fn bytes_of_from_infos<A, M>(module: &M, infos: &A) -> usize
where
A: GLWEInfos,
M: GLWEAlloc,
{
module.bytes_of_glwe_from_infos(infos)
}
pub fn bytes_of<M>(module: &M, base2k: Base2K, k: TorusPrecision, rank: Rank) -> usize
where
M: GLWEAlloc,
{
module.bytes_of_glwe(base2k, k, rank)
}
}
pub trait GLWECiphertextToMut {
fn to_mut(&mut self) -> GLWECiphertext<&mut [u8]>;
}
impl<D: DataMut> GLWECiphertextToMut for GLWECiphertext<D> {
fn to_mut(&mut self) -> GLWECiphertext<&mut [u8]> {
GLWECiphertext::builder()
.k(self.k())
.base2k(self.base2k())
.data(self.data.to_mut())
.build()
.unwrap()
}
}
impl<D: DataMut> ReaderFrom for GLWECiphertext<D> {
impl<D: DataMut> ReaderFrom for GLWE<D> {
fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> {
self.k = TorusPrecision(reader.read_u32::<LittleEndian>()?);
self.base2k = Base2K(reader.read_u32::<LittleEndian>()?);
@@ -291,10 +227,38 @@ impl<D: DataMut> ReaderFrom for GLWECiphertext<D> {
}
}
impl<D: DataRef> WriterTo for GLWECiphertext<D> {
impl<D: DataRef> WriterTo for GLWE<D> {
fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
writer.write_u32::<LittleEndian>(self.k.0)?;
writer.write_u32::<LittleEndian>(self.base2k.0)?;
self.data.write_to(writer)
}
}
pub trait GLWEToRef {
fn to_ref(&self) -> GLWE<&[u8]>;
}
impl<D: DataRef> GLWEToRef for GLWE<D> {
fn to_ref(&self) -> GLWE<&[u8]> {
GLWE {
k: self.k,
base2k: self.base2k,
data: self.data.to_ref(),
}
}
}
pub trait GLWEToMut {
fn to_mut(&mut self) -> GLWE<&mut [u8]>;
}
impl<D: DataMut> GLWEToMut for GLWE<D> {
fn to_mut(&mut self) -> GLWE<&mut [u8]> {
GLWE {
k: self.k,
base2k: self.base2k,
data: self.data.to_mut(),
}
}
}

View File

@@ -1,8 +1,10 @@
use poulpy_hal::layouts::{Data, DataMut, DataRef, ReaderFrom, VecZnx, WriterTo, ZnxInfos};
use poulpy_hal::layouts::{
Backend, Data, DataMut, DataRef, Module, ReaderFrom, VecZnx, VecZnxToMut, VecZnxToRef, WriterTo, ZnxInfos,
};
use crate::{
dist::Distribution,
layouts::{Base2K, BuildError, Degree, GLWEInfos, LWEInfos, Rank, TorusPrecision},
layouts::{Base2K, GLWEInfos, GetRingDegree, LWEInfos, Rank, RingDegree, TorusPrecision},
};
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
@@ -16,12 +18,22 @@ pub struct GLWEPublicKey<D: Data> {
#[derive(PartialEq, Eq, Copy, Clone, Debug)]
pub struct GLWEPublicKeyLayout {
pub n: Degree,
pub n: RingDegree,
pub base2k: Base2K,
pub k: TorusPrecision,
pub rank: Rank,
}
pub trait GetDist {
fn get_dist(&self) -> Distribution;
}
impl<D: DataRef> GetDist for GLWEPublicKey<D> {
fn get_dist(&self) -> Distribution {
self.dist
}
}
impl<D: Data> LWEInfos for GLWEPublicKey<D> {
fn base2k(&self) -> Base2K {
self.base2k
@@ -31,8 +43,8 @@ impl<D: Data> LWEInfos for GLWEPublicKey<D> {
self.k
}
fn n(&self) -> Degree {
Degree(self.data.n() as u32)
fn n(&self) -> RingDegree {
RingDegree(self.data.n() as u32)
}
fn size(&self) -> usize {
@@ -55,7 +67,7 @@ impl LWEInfos for GLWEPublicKeyLayout {
self.k
}
fn n(&self) -> Degree {
fn n(&self) -> RingDegree {
self.n
}
@@ -70,117 +82,77 @@ impl GLWEInfos for GLWEPublicKeyLayout {
}
}
pub struct GLWEPublicKeyBuilder<D: Data> {
data: Option<VecZnx<D>>,
base2k: Option<Base2K>,
k: Option<TorusPrecision>,
}
impl<D: Data> GLWEPublicKey<D> {
#[inline]
pub fn builder() -> GLWEPublicKeyBuilder<D> {
GLWEPublicKeyBuilder {
data: None,
base2k: None,
k: None,
}
}
}
impl GLWEPublicKeyBuilder<Vec<u8>> {
#[inline]
pub fn layout<A>(mut self, layout: &A) -> Self
where
A: GLWEInfos,
{
self.data = Some(VecZnx::alloc(
layout.n().into(),
(layout.rank() + 1).into(),
layout.size(),
));
self.base2k = Some(layout.base2k());
self.k = Some(layout.k());
self
}
}
impl<D: Data> GLWEPublicKeyBuilder<D> {
#[inline]
pub fn data(mut self, data: VecZnx<D>) -> Self {
self.data = Some(data);
self
}
#[inline]
pub fn base2k(mut self, base2k: Base2K) -> Self {
self.base2k = Some(base2k);
self
}
#[inline]
pub fn k(mut self, k: TorusPrecision) -> Self {
self.k = Some(k);
self
}
pub fn build(self) -> Result<GLWEPublicKey<D>, BuildError> {
let data: VecZnx<D> = self.data.ok_or(BuildError::MissingData)?;
let base2k: Base2K = self.base2k.ok_or(BuildError::MissingBase2K)?;
let k: TorusPrecision = self.k.ok_or(BuildError::MissingK)?;
if base2k == 0_u32 {
return Err(BuildError::ZeroBase2K);
}
if k == 0_u32 {
return Err(BuildError::ZeroTorusPrecision);
}
if data.n() == 0 {
return Err(BuildError::ZeroDegree);
}
if data.cols() == 0 {
return Err(BuildError::ZeroCols);
}
if data.size() == 0 {
return Err(BuildError::ZeroLimbs);
}
Ok(GLWEPublicKey {
data,
pub trait GLWEPublicKeyAlloc
where
Self: GetRingDegree,
{
fn alloc_glwe_public_key(&self, base2k: Base2K, k: TorusPrecision, rank: Rank) -> GLWEPublicKey<Vec<u8>> {
GLWEPublicKey {
data: VecZnx::alloc(
self.ring_degree().into(),
(rank + 1).into(),
k.0.div_ceil(base2k.0) as usize,
),
base2k,
k,
dist: Distribution::NONE,
})
}
}
fn alloc_glwe_public_key_from_infos<A>(&self, infos: &A) -> GLWEPublicKey<Vec<u8>>
where
A: GLWEInfos,
{
self.alloc_glwe_public_key(infos.base2k(), infos.k(), infos.rank())
}
fn bytes_of_glwe_public_key(&self, base2k: Base2K, k: TorusPrecision, rank: Rank) -> usize {
VecZnx::bytes_of(
self.ring_degree().into(),
(rank + 1).into(),
k.0.div_ceil(base2k.0) as usize,
)
}
fn bytes_of_glwe_public_key_from_infos<A>(&self, infos: &A) -> usize
where
A: GLWEInfos,
{
self.bytes_of_glwe_public_key(infos.base2k(), infos.k(), infos.rank())
}
}
impl<B: Backend> GLWEPublicKeyAlloc for Module<B> where Self: GetRingDegree {}
impl GLWEPublicKey<Vec<u8>> {
pub fn alloc<A>(infos: &A) -> Self
pub fn alloc_from_infos<A, M>(module: &M, infos: &A) -> Self
where
A: GLWEInfos,
M: GLWEPublicKeyAlloc,
{
Self::alloc_with(infos.n(), infos.base2k(), infos.k(), infos.rank())
module.alloc_glwe_public_key_from_infos(infos)
}
pub fn alloc_with(n: Degree, base2k: Base2K, k: TorusPrecision, rank: Rank) -> Self {
Self {
data: VecZnx::alloc(n.into(), (rank + 1).into(), k.0.div_ceil(base2k.0) as usize),
base2k,
k,
dist: Distribution::NONE,
}
pub fn alloc<M>(module: &M, base2k: Base2K, k: TorusPrecision, rank: Rank) -> Self
where
M: GLWEPublicKeyAlloc,
{
module.alloc_glwe_public_key(base2k, k, rank)
}
pub fn alloc_bytes<A>(infos: &A) -> usize
pub fn bytes_of_from_infos<A, M>(module: &M, infos: &A) -> usize
where
A: GLWEInfos,
M: GLWEPublicKeyAlloc,
{
Self::alloc_bytes_with(infos.n(), infos.base2k(), infos.k(), infos.rank())
module.bytes_of_glwe_public_key_from_infos(infos)
}
pub fn alloc_bytes_with(n: Degree, base2k: Base2K, k: TorusPrecision, rank: Rank) -> usize {
VecZnx::alloc_bytes(n.into(), (rank + 1).into(), k.0.div_ceil(base2k.0) as usize)
pub fn bytes_of<M>(module: &M, base2k: Base2K, k: TorusPrecision, rank: Rank) -> usize
where
M: GLWEPublicKeyAlloc,
{
module.bytes_of_glwe_public_key(base2k, k, rank)
}
}
@@ -207,3 +179,33 @@ impl<D: DataRef> WriterTo for GLWEPublicKey<D> {
self.data.write_to(writer)
}
}
pub trait GLWEPublicKeyToRef {
fn to_ref(&self) -> GLWEPublicKey<&[u8]>;
}
impl<D: DataRef> GLWEPublicKeyToRef for GLWEPublicKey<D> {
fn to_ref(&self) -> GLWEPublicKey<&[u8]> {
GLWEPublicKey {
data: self.data.to_ref(),
base2k: self.base2k,
k: self.k,
dist: self.dist,
}
}
}
pub trait GLWEPublicKeyToMut {
fn to_mut(&mut self) -> GLWEPublicKey<&mut [u8]>;
}
impl<D: DataMut> GLWEPublicKeyToMut for GLWEPublicKey<D> {
fn to_mut(&mut self) -> GLWEPublicKey<&mut [u8]> {
GLWEPublicKey {
base2k: self.base2k,
k: self.k,
dist: self.dist,
data: self.data.to_mut(),
}
}
}

View File

@@ -1,15 +1,14 @@
use std::fmt;
use poulpy_hal::layouts::{Data, DataMut, DataRef, VecZnx, VecZnxToMut, VecZnxToRef, ZnxInfos};
use poulpy_hal::layouts::{Backend, Data, DataMut, DataRef, Module, VecZnx, VecZnxToMut, VecZnxToRef, ZnxInfos};
use crate::layouts::{
Base2K, BuildError, Degree, GLWECiphertext, GLWECiphertextToMut, GLWECiphertextToRef, GLWEInfos, GLWELayoutSet, LWEInfos,
Rank, TorusPrecision,
Base2K, GLWE, GLWEInfos, GLWEToMut, GLWEToRef, GetRingDegree, LWEInfos, Rank, RingDegree, SetGLWEInfos, TorusPrecision,
};
#[derive(PartialEq, Eq, Copy, Clone, Debug)]
pub struct GLWEPlaintextLayout {
pub n: Degree,
pub n: RingDegree,
pub base2k: Base2K,
pub k: TorusPrecision,
}
@@ -23,7 +22,7 @@ impl LWEInfos for GLWEPlaintextLayout {
self.k
}
fn n(&self) -> Degree {
fn n(&self) -> RingDegree {
self.n
}
}
@@ -40,8 +39,8 @@ pub struct GLWEPlaintext<D: Data> {
pub k: TorusPrecision,
}
impl<D: DataMut> GLWELayoutSet for GLWEPlaintext<D> {
fn set_basek(&mut self, base2k: Base2K) {
impl<D: DataMut> SetGLWEInfos for GLWEPlaintext<D> {
fn set_base2k(&mut self, base2k: Base2K) {
self.base2k = base2k
}
@@ -63,8 +62,8 @@ impl<D: Data> LWEInfos for GLWEPlaintext<D> {
self.data.size()
}
fn n(&self) -> Degree {
Degree(self.data.n() as u32)
fn n(&self) -> RingDegree {
RingDegree(self.data.n() as u32)
}
}
@@ -74,69 +73,6 @@ impl<D: Data> GLWEInfos for GLWEPlaintext<D> {
}
}
pub struct GLWEPlaintextBuilder<D: Data> {
data: Option<VecZnx<D>>,
base2k: Option<Base2K>,
k: Option<TorusPrecision>,
}
impl<D: Data> GLWEPlaintext<D> {
#[inline]
pub fn builder() -> GLWEPlaintextBuilder<D> {
GLWEPlaintextBuilder {
data: None,
base2k: None,
k: None,
}
}
}
impl<D: Data> GLWEPlaintextBuilder<D> {
#[inline]
pub fn data(mut self, data: VecZnx<D>) -> Self {
self.data = Some(data);
self
}
#[inline]
pub fn base2k(mut self, base2k: Base2K) -> Self {
self.base2k = Some(base2k);
self
}
#[inline]
pub fn k(mut self, k: TorusPrecision) -> Self {
self.k = Some(k);
self
}
pub fn build(self) -> Result<GLWEPlaintext<D>, BuildError> {
let data: VecZnx<D> = self.data.ok_or(BuildError::MissingData)?;
let base2k: Base2K = self.base2k.ok_or(BuildError::MissingBase2K)?;
let k: TorusPrecision = self.k.ok_or(BuildError::MissingK)?;
if base2k.0 == 0 {
return Err(BuildError::ZeroBase2K);
}
if k.0 == 0 {
return Err(BuildError::ZeroTorusPrecision);
}
if data.n() == 0 {
return Err(BuildError::ZeroDegree);
}
if data.cols() != 1 {
return Err(BuildError::ZeroCols);
}
if data.size() == 0 {
return Err(BuildError::ZeroLimbs);
}
Ok(GLWEPlaintext { data, base2k, k })
}
}
impl<D: DataRef> fmt::Display for GLWEPlaintext<D> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
@@ -149,54 +85,123 @@ impl<D: DataRef> fmt::Display for GLWEPlaintext<D> {
}
}
impl GLWEPlaintext<Vec<u8>> {
pub fn alloc<A>(infos: &A) -> Self
where
A: GLWEInfos,
{
Self::alloc_with(infos.n(), infos.base2k(), infos.k(), Rank(0))
}
pub fn alloc_with(n: Degree, base2k: Base2K, k: TorusPrecision, rank: Rank) -> Self {
debug_assert!(rank.0 == 0);
Self {
data: VecZnx::alloc(n.into(), (rank + 1).into(), k.0.div_ceil(base2k.0) as usize),
pub trait GLWEPlaintextAlloc
where
Self: GetRingDegree,
{
fn alloc_glwe_plaintext(&self, base2k: Base2K, k: TorusPrecision) -> GLWEPlaintext<Vec<u8>> {
GLWEPlaintext {
data: VecZnx::alloc(
self.ring_degree().into(),
1,
k.0.div_ceil(base2k.0) as usize,
),
base2k,
k,
}
}
pub fn alloc_bytes<A>(infos: &A) -> usize
fn alloc_glwe_plaintext_from_infos<A>(&self, infos: &A) -> GLWEPlaintext<Vec<u8>>
where
A: GLWEInfos,
{
Self::alloc_bytes_with(infos.n(), infos.base2k(), infos.k(), Rank(0))
self.alloc_glwe_plaintext(infos.base2k(), infos.k())
}
pub fn alloc_bytes_with(n: Degree, base2k: Base2K, k: TorusPrecision, rank: Rank) -> usize {
debug_assert!(rank.0 == 0);
VecZnx::alloc_bytes(n.into(), (rank + 1).into(), k.0.div_ceil(base2k.0) as usize)
fn bytes_of_glwe_plaintext(&self, base2k: Base2K, k: TorusPrecision) -> usize {
VecZnx::bytes_of(
self.ring_degree().into(),
1,
k.0.div_ceil(base2k.0) as usize,
)
}
fn bytes_of_glwe_plaintext_from_infos<A>(&self, infos: &A) -> usize
where
A: GLWEInfos,
{
self.bytes_of_glwe_plaintext(infos.base2k(), infos.k())
}
}
impl<D: DataRef> GLWECiphertextToRef for GLWEPlaintext<D> {
fn to_ref(&self) -> GLWECiphertext<&[u8]> {
GLWECiphertext::builder()
.data(self.data.to_ref())
.k(self.k())
.base2k(self.base2k())
.build()
.unwrap()
impl<B: Backend> GLWEPlaintextAlloc for Module<B> where Self: GetRingDegree {}
impl GLWEPlaintext<Vec<u8>> {
pub fn alloc_from_infos<A, M>(module: &M, infos: &A) -> Self
where
A: GLWEInfos,
M: GLWEPlaintextAlloc,
{
module.alloc_glwe_plaintext_from_infos(infos)
}
pub fn alloc<M>(module: &M, base2k: Base2K, k: TorusPrecision) -> Self
where
M: GLWEPlaintextAlloc,
{
module.alloc_glwe_plaintext(base2k, k)
}
pub fn bytes_of_from_infos<A, M>(module: &M, infos: &A) -> usize
where
A: GLWEInfos,
M: GLWEPlaintextAlloc,
{
module.bytes_of_glwe_plaintext_from_infos(infos)
}
pub fn bytes_of<M>(module: &M, base2k: Base2K, k: TorusPrecision) -> usize
where
M: GLWEPlaintextAlloc,
{
module.bytes_of_glwe_plaintext(base2k, k)
}
}
impl<D: DataMut> GLWECiphertextToMut for GLWEPlaintext<D> {
fn to_mut(&mut self) -> GLWECiphertext<&mut [u8]> {
GLWECiphertext::builder()
.k(self.k())
.base2k(self.base2k())
.data(self.data.to_mut())
.build()
.unwrap()
impl<D: DataRef> GLWEToRef for GLWEPlaintext<D> {
fn to_ref(&self) -> GLWE<&[u8]> {
GLWE {
k: self.k,
base2k: self.base2k,
data: self.data.to_ref(),
}
}
}
impl<D: DataMut> GLWEToMut for GLWEPlaintext<D> {
fn to_mut(&mut self) -> GLWE<&mut [u8]> {
GLWE {
k: self.k,
base2k: self.base2k,
data: self.data.to_mut(),
}
}
}
pub trait GLWEPlaintextToRef {
fn to_ref(&self) -> GLWEPlaintext<&[u8]>;
}
impl<D: DataRef> GLWEPlaintextToRef for GLWEPlaintext<D> {
fn to_ref(&self) -> GLWEPlaintext<&[u8]> {
GLWEPlaintext {
data: self.data.to_ref(),
base2k: self.base2k,
k: self.k,
}
}
}
pub trait GLWEPlaintextToMut {
fn to_ref(&mut self) -> GLWEPlaintext<&mut [u8]>;
}
impl<D: DataMut> GLWEPlaintextToMut for GLWEPlaintext<D> {
fn to_ref(&mut self) -> GLWEPlaintext<&mut [u8]> {
GLWEPlaintext {
base2k: self.base2k,
k: self.k,
data: self.data.to_mut(),
}
}
}

View File

@@ -1,16 +1,19 @@
use poulpy_hal::{
layouts::{Data, DataMut, DataRef, ReaderFrom, ScalarZnx, WriterTo, ZnxInfos, ZnxZero},
layouts::{
Backend, Data, DataMut, DataRef, Module, ReaderFrom, ScalarZnx, ScalarZnxToMut, ScalarZnxToRef, WriterTo, ZnxInfos,
ZnxZero,
},
source::Source,
};
use crate::{
dist::Distribution,
layouts::{Base2K, Degree, GLWEInfos, LWEInfos, Rank, TorusPrecision},
layouts::{Base2K, GLWEInfos, GetRingDegree, LWEInfos, Rank, RingDegree, TorusPrecision},
};
#[derive(PartialEq, Eq, Copy, Clone, Debug)]
pub struct GLWESecretLayout {
pub n: Degree,
pub n: RingDegree,
pub rank: Rank,
}
@@ -23,7 +26,7 @@ impl LWEInfos for GLWESecretLayout {
TorusPrecision(0)
}
fn n(&self) -> Degree {
fn n(&self) -> RingDegree {
self.n
}
@@ -52,8 +55,8 @@ impl<D: Data> LWEInfos for GLWESecret<D> {
TorusPrecision(0)
}
fn n(&self) -> Degree {
Degree(self.data.n() as u32)
fn n(&self) -> RingDegree {
RingDegree(self.data.n() as u32)
}
fn size(&self) -> usize {
@@ -67,30 +70,67 @@ impl<D: Data> GLWEInfos for GLWESecret<D> {
}
}
impl GLWESecret<Vec<u8>> {
pub fn alloc<A>(infos: &A) -> Self
where
A: GLWEInfos,
{
Self::alloc_with(infos.n(), infos.rank())
}
pub fn alloc_with(n: Degree, rank: Rank) -> Self {
Self {
data: ScalarZnx::alloc(n.into(), rank.into()),
pub trait GLWESecretAlloc
where
Self: GetRingDegree,
{
fn alloc_glwe_secret(&self, rank: Rank) -> GLWESecret<Vec<u8>> {
GLWESecret {
data: ScalarZnx::alloc(self.ring_degree().into(), rank.into()),
dist: Distribution::NONE,
}
}
pub fn alloc_bytes<A>(infos: &A) -> usize
fn alloc_glwe_secret_from_infos<A>(&self, infos: &A) -> GLWESecret<Vec<u8>>
where
A: GLWEInfos,
{
Self::alloc_bytes_with(infos.n(), infos.rank())
self.alloc_glwe_secret(infos.rank())
}
pub fn alloc_bytes_with(n: Degree, rank: Rank) -> usize {
ScalarZnx::alloc_bytes(n.into(), rank.into())
fn bytes_of_glwe_secret(&self, rank: Rank) -> usize {
ScalarZnx::bytes_of(self.ring_degree().into(), rank.into())
}
fn bytes_of_glwe_secret_from_infos<A>(&self, infos: &A) -> usize
where
A: GLWEInfos,
{
self.bytes_of_glwe_secret(infos.rank())
}
}
impl<B: Backend> GLWESecretAlloc for Module<B> where Self: GetRingDegree {}
impl GLWESecret<Vec<u8>> {
pub fn alloc_from_infos<A, M>(module: &M, infos: &A) -> Self
where
A: GLWEInfos,
M: GLWESecretAlloc,
{
module.alloc_glwe_secret_from_infos(infos)
}
pub fn alloc<M>(module: &M, rank: Rank) -> Self
where
M: GLWESecretAlloc,
{
module.alloc_glwe_secret(rank)
}
pub fn bytes_of_from_infos<A, M>(module: &M, infos: &A) -> usize
where
A: GLWEInfos,
M: GLWESecretAlloc,
{
module.bytes_of_glwe_secret_from_infos(infos)
}
pub fn bytes_of<M>(module: &M, rank: Rank) -> usize
where
M: GLWESecretAlloc,
{
module.bytes_of_glwe_secret(rank)
}
}
@@ -136,6 +176,32 @@ impl<D: DataMut> GLWESecret<D> {
}
}
pub trait GLWESecretToMut {
fn to_mut(&mut self) -> GLWESecret<&mut [u8]>;
}
impl<D: DataMut> GLWESecretToMut for GLWESecret<D> {
fn to_mut(&mut self) -> GLWESecret<&mut [u8]> {
GLWESecret {
dist: self.dist,
data: self.data.to_mut(),
}
}
}
pub trait GLWESecretToRef {
fn to_ref(&self) -> GLWESecret<&[u8]>;
}
impl<D: DataRef> GLWESecretToRef for GLWESecret<D> {
fn to_ref(&self) -> GLWESecret<&[u8]> {
GLWESecret {
data: self.data.to_ref(),
dist: self.dist,
}
}
}
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) {

View File

@@ -1,15 +1,18 @@
use poulpy_hal::{
layouts::{Data, DataMut, DataRef, FillUniform, ReaderFrom, WriterTo},
layouts::{Backend, Data, DataMut, DataRef, FillUniform, Module, ReaderFrom, WriterTo},
source::Source,
};
use crate::layouts::{Base2K, Degree, Dnum, Dsize, GGLWEInfos, GGLWESwitchingKey, GLWEInfos, LWEInfos, Rank, TorusPrecision};
use crate::layouts::{
Base2K, Dnum, Dsize, GGLWEInfos, GLWEInfos, GLWESwitchingKey, GLWESwitchingKeyAlloc, GLWESwitchingKeyToMut,
GLWESwitchingKeyToRef, LWEInfos, Rank, RingDegree, TorusPrecision,
};
use std::fmt;
#[derive(PartialEq, Eq, Copy, Clone, Debug)]
pub struct GLWEToLWEKeyLayout {
pub n: Degree,
pub n: RingDegree,
pub base2k: Base2K,
pub k: TorusPrecision,
pub rank_in: Rank,
@@ -17,7 +20,7 @@ pub struct GLWEToLWEKeyLayout {
}
impl LWEInfos for GLWEToLWEKeyLayout {
fn n(&self) -> Degree {
fn n(&self) -> RingDegree {
self.n
}
@@ -54,11 +57,11 @@ impl GGLWEInfos for GLWEToLWEKeyLayout {
}
}
/// A special [GLWESwitchingKey] required to for the conversion from [GLWECiphertext] to [LWECiphertext].
/// A special [GLWESwitchingKey] required to for the conversion from [GLWE] to [LWE].
#[derive(PartialEq, Eq, Clone)]
pub struct GLWEToLWEKey<D: Data>(pub(crate) GGLWESwitchingKey<D>);
pub struct GLWEToLWESwitchingKey<D: Data>(pub(crate) GLWESwitchingKey<D>);
impl<D: Data> LWEInfos for GLWEToLWEKey<D> {
impl<D: Data> LWEInfos for GLWEToLWESwitchingKey<D> {
fn base2k(&self) -> Base2K {
self.0.base2k()
}
@@ -67,7 +70,7 @@ impl<D: Data> LWEInfos for GLWEToLWEKey<D> {
self.0.k()
}
fn n(&self) -> Degree {
fn n(&self) -> RingDegree {
self.0.n()
}
@@ -76,12 +79,12 @@ impl<D: Data> LWEInfos for GLWEToLWEKey<D> {
}
}
impl<D: Data> GLWEInfos for GLWEToLWEKey<D> {
impl<D: Data> GLWEInfos for GLWEToLWESwitchingKey<D> {
fn rank(&self) -> Rank {
self.rank_out()
}
}
impl<D: Data> GGLWEInfos for GLWEToLWEKey<D> {
impl<D: Data> GGLWEInfos for GLWEToLWESwitchingKey<D> {
fn rank_in(&self) -> Rank {
self.0.rank_in()
}
@@ -99,84 +102,145 @@ impl<D: Data> GGLWEInfos for GLWEToLWEKey<D> {
}
}
impl<D: DataRef> fmt::Debug for GLWEToLWEKey<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 GLWEToLWEKey<D> {
impl<D: DataMut> FillUniform for GLWEToLWESwitchingKey<D> {
fn fill_uniform(&mut self, log_bound: usize, source: &mut Source) {
self.0.fill_uniform(log_bound, source);
}
}
impl<D: DataRef> fmt::Display for GLWEToLWEKey<D> {
impl<D: DataRef> fmt::Display for GLWEToLWESwitchingKey<D> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "(GLWEToLWESwitchingKey) {}", self.0)
}
}
impl<D: DataMut> ReaderFrom for GLWEToLWEKey<D> {
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 GLWEToLWEKey<D> {
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 GLWEToLWEKey<Vec<u8>> {
pub fn alloc<A>(infos: &A) -> Self
pub trait GLWEToLWESwitchingKeyAlloc
where
Self: GLWESwitchingKeyAlloc,
{
fn alloc_glwe_to_lwe_switching_key(
&self,
base2k: Base2K,
k: TorusPrecision,
rank_in: Rank,
dnum: Dnum,
) -> GLWEToLWESwitchingKey<Vec<u8>> {
GLWEToLWESwitchingKey(self.alloc_glwe_switching_key(base2k, k, rank_in, Rank(1), dnum, Dsize(1)))
}
fn alloc_glwe_to_lwe_switching_key_from_infos<A>(&self, infos: &A) -> GLWEToLWESwitchingKey<Vec<u8>>
where
A: GGLWEInfos,
{
debug_assert_eq!(
assert_eq!(
infos.rank_out().0,
1,
"rank_out > 1 is not supported for GLWEToLWESwitchingKey"
);
debug_assert_eq!(
assert_eq!(
infos.dsize().0,
1,
"dsize > 1 is not supported for GLWEToLWESwitchingKey"
);
Self(GGLWESwitchingKey::alloc(infos))
self.alloc_glwe_to_lwe_switching_key(infos.base2k(), infos.k(), infos.rank_in(), infos.dnum())
}
pub fn alloc_with(n: Degree, base2k: Base2K, k: TorusPrecision, rank_in: Rank, dnum: Dnum) -> Self {
Self(GGLWESwitchingKey::alloc_with(
n,
base2k,
k,
rank_in,
Rank(1),
dnum,
Dsize(1),
))
fn bytes_of_glwe_to_lwe_switching_key(&self, base2k: Base2K, k: TorusPrecision, rank_in: Rank, dnum: Dnum) -> usize {
self.bytes_of_glwe_switching_key(base2k, k, rank_in, Rank(1), dnum, Dsize(1))
}
pub fn alloc_bytes<A>(infos: &A) -> usize
fn bytes_of_glwe_to_lwe_switching_key_from_infos<A>(&self, infos: &A) -> usize
where
A: GGLWEInfos,
{
debug_assert_eq!(
assert_eq!(
infos.rank_out().0,
1,
"rank_out > 1 is not supported for GLWEToLWESwitchingKey"
);
debug_assert_eq!(
assert_eq!(
infos.dsize().0,
1,
"dsize > 1 is not supported for GLWEToLWESwitchingKey"
);
GGLWESwitchingKey::alloc_bytes(infos)
}
pub fn alloc_bytes_with(n: Degree, base2k: Base2K, k: TorusPrecision, rank_in: Rank, dnum: Dnum) -> usize {
GGLWESwitchingKey::alloc_bytes_with(n, base2k, k, rank_in, Rank(1), dnum, Dsize(1))
self.bytes_of_glwe_to_lwe_switching_key(infos.base2k(), infos.k(), infos.rank_in(), infos.dnum())
}
}
impl<B: Backend> GLWEToLWESwitchingKeyAlloc for Module<B> where Self: GLWESwitchingKeyAlloc {}
impl GLWEToLWESwitchingKey<Vec<u8>> {
pub fn alloc_from_infos<A, M>(module: &M, infos: &A) -> Self
where
A: GGLWEInfos,
M: GLWEToLWESwitchingKeyAlloc,
{
module.alloc_glwe_to_lwe_switching_key_from_infos(infos)
}
pub fn alloc<M>(module: &M, base2k: Base2K, k: TorusPrecision, rank_in: Rank, dnum: Dnum) -> Self
where
M: GLWEToLWESwitchingKeyAlloc,
{
module.alloc_glwe_to_lwe_switching_key(base2k, k, rank_in, dnum)
}
pub fn bytes_of_from_infos<A, M>(module: &M, infos: &A) -> usize
where
A: GGLWEInfos,
M: GLWEToLWESwitchingKeyAlloc,
{
module.bytes_of_glwe_to_lwe_switching_key_from_infos(infos)
}
pub fn bytes_of<M>(module: &M, base2k: Base2K, k: TorusPrecision, rank_in: Rank, dnum: Dnum) -> usize
where
M: GLWEToLWESwitchingKeyAlloc,
{
module.bytes_of_glwe_to_lwe_switching_key(base2k, k, rank_in, dnum)
}
}
pub trait GLWEToLWESwitchingKeyToRef {
fn to_ref(&self) -> GLWEToLWESwitchingKey<&[u8]>;
}
impl<D: DataRef> GLWEToLWESwitchingKeyToRef for GLWEToLWESwitchingKey<D>
where
GLWESwitchingKey<D>: GLWESwitchingKeyToRef,
{
fn to_ref(&self) -> GLWEToLWESwitchingKey<&[u8]> {
GLWEToLWESwitchingKey(self.0.to_ref())
}
}
pub trait GLWEToLWESwitchingKeyToMut {
fn to_mut(&mut self) -> GLWEToLWESwitchingKey<&mut [u8]>;
}
impl<D: DataMut> GLWEToLWESwitchingKeyToMut for GLWEToLWESwitchingKey<D>
where
GLWESwitchingKey<D>: GLWESwitchingKeyToMut,
{
fn to_mut(&mut self) -> GLWEToLWESwitchingKey<&mut [u8]> {
GLWEToLWESwitchingKey(self.0.to_mut())
}
}

View File

@@ -1,15 +1,15 @@
use std::fmt;
use poulpy_hal::{
layouts::{Data, DataMut, DataRef, FillUniform, ReaderFrom, WriterTo, Zn, ZnToMut, ZnToRef, ZnxInfos},
layouts::{Backend, Data, DataMut, DataRef, FillUniform, Module, ReaderFrom, WriterTo, Zn, ZnToMut, ZnToRef, ZnxInfos},
source::Source,
};
use crate::layouts::{Base2K, BuildError, Degree, TorusPrecision};
use crate::layouts::{Base2K, RingDegree, TorusPrecision};
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
pub trait LWEInfos {
fn n(&self) -> Degree;
fn n(&self) -> RingDegree;
fn k(&self) -> TorusPrecision;
fn max_k(&self) -> TorusPrecision {
TorusPrecision(self.k().0 * self.size() as u32)
@@ -18,8 +18,8 @@ pub trait LWEInfos {
fn size(&self) -> usize {
self.k().0.div_ceil(self.base2k().0) as usize
}
fn lwe_layout(&self) -> LWECiphertextLayout {
LWECiphertextLayout {
fn lwe_layout(&self) -> LWELayout {
LWELayout {
n: self.n(),
k: self.k(),
base2k: self.base2k(),
@@ -27,14 +27,19 @@ pub trait LWEInfos {
}
}
pub trait SetLWEInfos {
fn set_k(&mut self, k: TorusPrecision);
fn set_base2k(&mut self, base2k: Base2K);
}
#[derive(PartialEq, Eq, Copy, Clone, Debug)]
pub struct LWECiphertextLayout {
pub n: Degree,
pub struct LWELayout {
pub n: RingDegree,
pub k: TorusPrecision,
pub base2k: Base2K,
}
impl LWEInfos for LWECiphertextLayout {
impl LWEInfos for LWELayout {
fn base2k(&self) -> Base2K {
self.base2k
}
@@ -43,19 +48,18 @@ impl LWEInfos for LWECiphertextLayout {
self.k
}
fn n(&self) -> Degree {
fn n(&self) -> RingDegree {
self.n
}
}
#[derive(PartialEq, Eq, Clone)]
pub struct LWECiphertext<D: Data> {
pub struct LWE<D: Data> {
pub(crate) data: Zn<D>,
pub(crate) k: TorusPrecision,
pub(crate) base2k: Base2K,
}
impl<D: Data> LWEInfos for LWECiphertext<D> {
impl<D: Data> LWEInfos for LWE<D> {
fn base2k(&self) -> Base2K {
self.base2k
}
@@ -63,8 +67,8 @@ impl<D: Data> LWEInfos for LWECiphertext<D> {
fn k(&self) -> TorusPrecision {
self.k
}
fn n(&self) -> Degree {
Degree(self.data.n() as u32 - 1)
fn n(&self) -> RingDegree {
RingDegree(self.data.n() as u32 - 1)
}
fn size(&self) -> usize {
@@ -72,29 +76,39 @@ impl<D: Data> LWEInfos for LWECiphertext<D> {
}
}
impl<D: DataRef> LWECiphertext<D> {
impl<D: Data> SetLWEInfos for LWE<D> {
fn set_base2k(&mut self, base2k: Base2K) {
self.base2k = base2k
}
fn set_k(&mut self, k: TorusPrecision) {
self.k = k
}
}
impl<D: DataRef> LWE<D> {
pub fn data(&self) -> &Zn<D> {
&self.data
}
}
impl<D: DataMut> LWECiphertext<D> {
impl<D: DataMut> LWE<D> {
pub fn data_mut(&mut self) -> &Zn<D> {
&mut self.data
}
}
impl<D: DataRef> fmt::Debug for LWECiphertext<D> {
impl<D: DataRef> fmt::Debug for LWE<D> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{self}")
}
}
impl<D: DataRef> fmt::Display for LWECiphertext<D> {
impl<D: DataRef> fmt::Display for LWE<D> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"LWECiphertext: base2k={} k={}: {}",
"LWE: base2k={} k={}: {}",
self.base2k().0,
self.k().0,
self.data
@@ -102,7 +116,7 @@ impl<D: DataRef> fmt::Display for LWECiphertext<D> {
}
}
impl<D: DataMut> FillUniform for LWECiphertext<D>
impl<D: DataMut> FillUniform for LWE<D>
where
Zn<D>: FillUniform,
{
@@ -111,142 +125,98 @@ where
}
}
impl LWECiphertext<Vec<u8>> {
pub fn alloc<A>(infos: &A) -> Self
where
A: LWEInfos,
{
Self::alloc_with(infos.n(), infos.base2k(), infos.k())
}
pub fn alloc_with(n: Degree, base2k: Base2K, k: TorusPrecision) -> Self {
Self {
pub trait LWEAlloc {
fn alloc_lwe(&self, n: RingDegree, base2k: Base2K, k: TorusPrecision) -> LWE<Vec<u8>> {
LWE {
data: Zn::alloc((n + 1).into(), 1, k.0.div_ceil(base2k.0) as usize),
k,
base2k,
}
}
pub fn alloc_bytes<A>(infos: &A) -> usize
fn alloc_lwe_from_infos<A>(&self, infos: &A) -> LWE<Vec<u8>>
where
A: LWEInfos,
{
Self::alloc_bytes_with(infos.n(), infos.base2k(), infos.k())
self.alloc_lwe(infos.n(), infos.base2k(), infos.k())
}
pub fn alloc_bytes_with(n: Degree, base2k: Base2K, k: TorusPrecision) -> usize {
Zn::alloc_bytes((n + 1).into(), 1, k.0.div_ceil(base2k.0) as usize)
fn bytes_of_lwe(&self, n: RingDegree, base2k: Base2K, k: TorusPrecision) -> usize {
Zn::bytes_of((n + 1).into(), 1, k.0.div_ceil(base2k.0) as usize)
}
}
impl LWECiphertextBuilder<Vec<u8>> {
#[inline]
pub fn layout<A>(mut self, layout: A) -> Self
fn bytes_of_lwe_from_infos<A>(&self, infos: &A) -> usize
where
A: LWEInfos,
{
self.data = Some(Zn::alloc((layout.n() + 1).into(), 1, layout.size()));
self.base2k = Some(layout.base2k());
self.k = Some(layout.k());
self
self.bytes_of_lwe(infos.n(), infos.base2k(), infos.k())
}
}
pub struct LWECiphertextBuilder<D: Data> {
data: Option<Zn<D>>,
base2k: Option<Base2K>,
k: Option<TorusPrecision>,
impl<B: Backend> LWEAlloc for Module<B> {}
impl LWE<Vec<u8>> {
pub fn alloc_from_infos<A, M>(module: &M, infos: &A) -> Self
where
A: LWEInfos,
M: LWEAlloc,
{
module.alloc_lwe_from_infos(infos)
}
pub fn alloc<M>(module: &M, n: RingDegree, base2k: Base2K, k: TorusPrecision) -> Self
where
M: LWEAlloc,
{
module.alloc_lwe(n, base2k, k)
}
pub fn bytes_of_from_infos<A, M>(module: &M, infos: &A) -> usize
where
A: LWEInfos,
M: LWEAlloc,
{
module.bytes_of_lwe_from_infos(infos)
}
pub fn bytes_of<M>(module: &M, n: RingDegree, base2k: Base2K, k: TorusPrecision) -> usize
where
M: LWEAlloc,
{
module.bytes_of_lwe(n, base2k, k)
}
}
impl<D: Data> LWECiphertext<D> {
#[inline]
pub fn builder() -> LWECiphertextBuilder<D> {
LWECiphertextBuilder {
data: None,
base2k: None,
k: None,
pub trait LWEToRef {
fn to_ref(&self) -> LWE<&[u8]>;
}
impl<D: DataRef> LWEToRef for LWE<D> {
fn to_ref(&self) -> LWE<&[u8]> {
LWE {
k: self.k,
base2k: self.base2k,
data: self.data.to_ref(),
}
}
}
impl<D: Data> LWECiphertextBuilder<D> {
#[inline]
pub fn data(mut self, data: Zn<D>) -> Self {
self.data = Some(data);
self
}
#[inline]
pub fn base2k(mut self, base2k: Base2K) -> Self {
self.base2k = Some(base2k);
self
}
#[inline]
pub fn k(mut self, k: TorusPrecision) -> Self {
self.k = Some(k);
self
}
pub fn build(self) -> Result<LWECiphertext<D>, BuildError> {
let data: Zn<D> = self.data.ok_or(BuildError::MissingData)?;
let base2k: Base2K = self.base2k.ok_or(BuildError::MissingBase2K)?;
let k: TorusPrecision = self.k.ok_or(BuildError::MissingK)?;
if base2k.0 == 0 {
return Err(BuildError::ZeroBase2K);
}
if k.0 == 0 {
return Err(BuildError::ZeroTorusPrecision);
}
if data.n() == 0 {
return Err(BuildError::ZeroDegree);
}
if data.cols() == 0 {
return Err(BuildError::ZeroCols);
}
if data.size() == 0 {
return Err(BuildError::ZeroLimbs);
}
Ok(LWECiphertext { data, base2k, k })
}
}
pub trait LWECiphertextToRef {
fn to_ref(&self) -> LWECiphertext<&[u8]>;
}
impl<D: DataRef> LWECiphertextToRef for LWECiphertext<D> {
fn to_ref(&self) -> LWECiphertext<&[u8]> {
LWECiphertext::builder()
.base2k(self.base2k())
.k(self.k())
.data(self.data.to_ref())
.build()
.unwrap()
}
}
pub trait LWECiphertextToMut {
pub trait LWEToMut {
#[allow(dead_code)]
fn to_mut(&mut self) -> LWECiphertext<&mut [u8]>;
fn to_mut(&mut self) -> LWE<&mut [u8]>;
}
impl<D: DataMut> LWECiphertextToMut for LWECiphertext<D> {
fn to_mut(&mut self) -> LWECiphertext<&mut [u8]> {
LWECiphertext::builder()
.base2k(self.base2k())
.k(self.k())
.data(self.data.to_mut())
.build()
.unwrap()
impl<D: DataMut> LWEToMut for LWE<D> {
fn to_mut(&mut self) -> LWE<&mut [u8]> {
LWE {
k: self.k,
base2k: self.base2k,
data: self.data.to_mut(),
}
}
}
impl<D: DataMut> ReaderFrom for LWECiphertext<D> {
impl<D: DataMut> ReaderFrom for LWE<D> {
fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> {
self.k = TorusPrecision(reader.read_u32::<LittleEndian>()?);
self.base2k = Base2K(reader.read_u32::<LittleEndian>()?);
@@ -254,7 +224,7 @@ impl<D: DataMut> ReaderFrom for LWECiphertext<D> {
}
}
impl<D: DataRef> WriterTo for LWECiphertext<D> {
impl<D: DataRef> WriterTo for LWE<D> {
fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
writer.write_u32::<LittleEndian>(self.k.into())?;
writer.write_u32::<LittleEndian>(self.base2k.into())?;

View File

@@ -1,22 +1,25 @@
use std::fmt;
use poulpy_hal::{
layouts::{Data, DataMut, DataRef, FillUniform, ReaderFrom, WriterTo},
layouts::{Backend, Data, DataMut, DataRef, FillUniform, Module, ReaderFrom, WriterTo},
source::Source,
};
use crate::layouts::{Base2K, Degree, Dnum, Dsize, GGLWEInfos, GGLWESwitchingKey, GLWEInfos, LWEInfos, Rank, TorusPrecision};
use crate::layouts::{
Base2K, Dnum, Dsize, GGLWEInfos, GLWEInfos, GLWESwitchingKey, GLWESwitchingKeyAlloc, GLWESwitchingKeyToMut,
GLWESwitchingKeyToRef, LWEInfos, Rank, RingDegree, TorusPrecision,
};
#[derive(PartialEq, Eq, Copy, Clone, Debug)]
pub struct LWESwitchingKeyLayout {
pub n: Degree,
pub n: RingDegree,
pub base2k: Base2K,
pub k: TorusPrecision,
pub dnum: Dnum,
}
impl LWEInfos for LWESwitchingKeyLayout {
fn n(&self) -> Degree {
fn n(&self) -> RingDegree {
self.n
}
@@ -54,7 +57,7 @@ impl GGLWEInfos for LWESwitchingKeyLayout {
}
#[derive(PartialEq, Eq, Clone)]
pub struct LWESwitchingKey<D: Data>(pub(crate) GGLWESwitchingKey<D>);
pub struct LWESwitchingKey<D: Data>(pub(crate) GLWESwitchingKey<D>);
impl<D: Data> LWEInfos for LWESwitchingKey<D> {
fn base2k(&self) -> Base2K {
@@ -65,7 +68,7 @@ impl<D: Data> LWEInfos for LWESwitchingKey<D> {
self.0.k()
}
fn n(&self) -> Degree {
fn n(&self) -> RingDegree {
self.0.n()
}
@@ -98,65 +101,94 @@ impl<D: Data> GGLWEInfos for LWESwitchingKey<D> {
}
}
pub trait LWESwitchingKeyAlloc
where
Self: GLWESwitchingKeyAlloc,
{
fn alloc_lwe_switching_key(&self, base2k: Base2K, k: TorusPrecision, dnum: Dnum) -> LWESwitchingKey<Vec<u8>> {
LWESwitchingKey(self.alloc_glwe_switching_key(base2k, k, Rank(1), Rank(1), dnum, Dsize(1)))
}
fn alloc_lwe_switching_key_from_infos<A>(&self, infos: &A) -> LWESwitchingKey<Vec<u8>>
where
A: GGLWEInfos,
{
assert_eq!(
infos.dsize().0,
1,
"dsize > 1 is not supported for LWESwitchingKey"
);
assert_eq!(
infos.rank_in().0,
1,
"rank_in > 1 is not supported for LWESwitchingKey"
);
assert_eq!(
infos.rank_out().0,
1,
"rank_out > 1 is not supported for LWESwitchingKey"
);
self.alloc_lwe_switching_key(infos.base2k(), infos.k(), infos.dnum())
}
fn bytes_of_lwe_switching_key(&self, base2k: Base2K, k: TorusPrecision, dnum: Dnum) -> usize {
self.bytes_of_glwe_switching_key(base2k, k, Rank(1), Rank(1), dnum, Dsize(1))
}
fn bytes_of_lwe_switching_key_from_infos<A>(&self, infos: &A) -> usize
where
A: GGLWEInfos,
{
assert_eq!(
infos.dsize().0,
1,
"dsize > 1 is not supported for LWESwitchingKey"
);
assert_eq!(
infos.rank_in().0,
1,
"rank_in > 1 is not supported for LWESwitchingKey"
);
assert_eq!(
infos.rank_out().0,
1,
"rank_out > 1 is not supported for LWESwitchingKey"
);
self.bytes_of_lwe_switching_key(infos.base2k(), infos.k(), infos.dnum())
}
}
impl<B: Backend> LWESwitchingKeyAlloc for Module<B> where Self: GLWESwitchingKeyAlloc {}
impl LWESwitchingKey<Vec<u8>> {
pub fn alloc<A>(infos: &A) -> Self
pub fn alloc_from_infos<A, M>(module: &M, infos: &A) -> Self
where
A: GGLWEInfos,
M: LWESwitchingKeyAlloc,
{
debug_assert_eq!(
infos.dsize().0,
1,
"dsize > 1 is not supported for LWESwitchingKey"
);
debug_assert_eq!(
infos.rank_in().0,
1,
"rank_in > 1 is not supported for LWESwitchingKey"
);
debug_assert_eq!(
infos.rank_out().0,
1,
"rank_out > 1 is not supported for LWESwitchingKey"
);
Self(GGLWESwitchingKey::alloc(infos))
module.alloc_lwe_switching_key_from_infos(infos)
}
pub fn alloc_with(n: Degree, base2k: Base2K, k: TorusPrecision, dnum: Dnum) -> Self {
Self(GGLWESwitchingKey::alloc_with(
n,
base2k,
k,
Rank(1),
Rank(1),
dnum,
Dsize(1),
))
pub fn alloc<M>(module: &M, base2k: Base2K, k: TorusPrecision, dnum: Dnum) -> Self
where
M: LWESwitchingKeyAlloc,
{
module.alloc_lwe_switching_key(base2k, k, dnum)
}
pub fn alloc_bytes<A>(infos: &A) -> usize
pub fn bytes_of_from_infos<A, M>(module: &M, infos: &A) -> usize
where
A: GGLWEInfos,
M: LWESwitchingKeyAlloc,
{
debug_assert_eq!(
infos.dsize().0,
1,
"dsize > 1 is not supported for LWESwitchingKey"
);
debug_assert_eq!(
infos.rank_in().0,
1,
"rank_in > 1 is not supported for LWESwitchingKey"
);
debug_assert_eq!(
infos.rank_out().0,
1,
"rank_out > 1 is not supported for LWESwitchingKey"
);
GGLWESwitchingKey::alloc_bytes(infos)
module.bytes_of_glwe_switching_key_from_infos(infos)
}
pub fn alloc_bytes_with(n: Degree, base2k: Base2K, k: TorusPrecision, dnum: Dnum) -> usize {
GGLWESwitchingKey::alloc_bytes_with(n, base2k, k, Rank(1), Rank(1), dnum, Dsize(1))
pub fn bytes_of<M>(module: &M, base2k: Base2K, k: TorusPrecision, dnum: Dnum) -> usize
where
M: LWESwitchingKeyAlloc,
{
module.bytes_of_lwe_switching_key(base2k, k, dnum)
}
}
@@ -189,3 +221,29 @@ impl<D: DataRef> WriterTo for LWESwitchingKey<D> {
self.0.write_to(writer)
}
}
pub trait LWESwitchingKeyToRef {
fn to_ref(&self) -> LWESwitchingKey<&[u8]>;
}
impl<D: DataRef> LWESwitchingKeyToRef for LWESwitchingKey<D>
where
GLWESwitchingKey<D>: GLWESwitchingKeyToRef,
{
fn to_ref(&self) -> LWESwitchingKey<&[u8]> {
LWESwitchingKey(self.0.to_ref())
}
}
pub trait LWESwitchingKeyToMut {
fn to_mut(&mut self) -> LWESwitchingKey<&mut [u8]>;
}
impl<D: DataMut> LWESwitchingKeyToMut for LWESwitchingKey<D>
where
GLWESwitchingKey<D>: GLWESwitchingKeyToMut,
{
fn to_mut(&mut self) -> LWESwitchingKey<&mut [u8]> {
LWESwitchingKey(self.0.to_mut())
}
}

View File

@@ -1,8 +1,8 @@
use std::fmt;
use poulpy_hal::layouts::{Data, DataMut, DataRef, Zn, ZnToMut, ZnToRef, ZnxInfos};
use poulpy_hal::layouts::{Backend, Data, DataMut, DataRef, Module, Zn, ZnToMut, ZnToRef, ZnxInfos};
use crate::layouts::{Base2K, Degree, LWEInfos, TorusPrecision};
use crate::layouts::{Base2K, LWEInfos, RingDegree, TorusPrecision};
#[derive(PartialEq, Eq, Copy, Clone, Debug)]
pub struct LWEPlaintextLayout {
@@ -19,8 +19,8 @@ impl LWEInfos for LWEPlaintextLayout {
self.k
}
fn n(&self) -> Degree {
Degree(0)
fn n(&self) -> RingDegree {
RingDegree(0)
}
fn size(&self) -> usize {
@@ -43,8 +43,8 @@ impl<D: Data> LWEInfos for LWEPlaintext<D> {
self.k
}
fn n(&self) -> Degree {
Degree(self.data.n() as u32 - 1)
fn n(&self) -> RingDegree {
RingDegree(self.data.n() as u32 - 1)
}
fn size(&self) -> usize {
@@ -52,21 +52,40 @@ impl<D: Data> LWEInfos for LWEPlaintext<D> {
}
}
impl LWEPlaintext<Vec<u8>> {
pub fn alloc<A>(infos: &A) -> Self
where
A: LWEInfos,
{
Self::alloc_with(infos.base2k(), infos.k())
}
pub fn alloc_with(base2k: Base2K, k: TorusPrecision) -> Self {
Self {
pub trait LWEPlaintextAlloc {
fn alloc_lwe_plaintext(&self, base2k: Base2K, k: TorusPrecision) -> LWEPlaintext<Vec<u8>> {
LWEPlaintext {
data: Zn::alloc(1, 1, k.0.div_ceil(base2k.0) as usize),
k,
base2k,
}
}
fn alloc_lwe_plaintext_from_infos<A>(&self, infos: &A) -> LWEPlaintext<Vec<u8>>
where
A: LWEInfos,
{
self.alloc_lwe_plaintext(infos.base2k(), infos.k())
}
}
impl<B: Backend> LWEPlaintextAlloc for Module<B> {}
impl LWEPlaintext<Vec<u8>> {
pub fn alloc_from_infos<A, M>(module: &M, infos: &A) -> Self
where
A: LWEInfos,
M: LWEPlaintextAlloc,
{
module.alloc_lwe_plaintext_from_infos(infos)
}
pub fn alloc<M>(module: &M, base2k: Base2K, k: TorusPrecision) -> Self
where
M: LWEPlaintextAlloc,
{
module.alloc_lwe_plaintext(base2k, k)
}
}
impl<D: DataRef> fmt::Display for LWEPlaintext<D> {

View File

@@ -1,11 +1,11 @@
use poulpy_hal::{
layouts::{Data, DataMut, DataRef, ScalarZnx, ZnxInfos, ZnxView, ZnxZero},
layouts::{Backend, Data, DataMut, DataRef, Module, ScalarZnx, ScalarZnxToMut, ScalarZnxToRef, ZnxInfos, ZnxView, ZnxZero},
source::Source,
};
use crate::{
dist::Distribution,
layouts::{Base2K, Degree, LWEInfos, TorusPrecision},
layouts::{Base2K, LWEInfos, RingDegree, TorusPrecision},
};
pub struct LWESecret<D: Data> {
@@ -13,15 +13,26 @@ pub struct LWESecret<D: Data> {
pub(crate) dist: Distribution,
}
impl LWESecret<Vec<u8>> {
pub fn alloc(n: Degree) -> Self {
Self {
pub trait LWESecretAlloc {
fn alloc_lwe_secret(&self, n: RingDegree) -> LWESecret<Vec<u8>> {
LWESecret {
data: ScalarZnx::alloc(n.into(), 1),
dist: Distribution::NONE,
}
}
}
impl<B: Backend> LWESecretAlloc for Module<B> {}
impl LWESecret<Vec<u8>> {
pub fn alloc<M>(module: &M, n: RingDegree) -> Self
where
M: LWESecretAlloc,
{
module.alloc_lwe_secret(n)
}
}
impl<D: DataRef> LWESecret<D> {
pub fn raw(&self) -> &[i64] {
self.data.at(0, 0)
@@ -44,8 +55,8 @@ impl<D: Data> LWEInfos for LWESecret<D> {
TorusPrecision(0)
}
fn n(&self) -> Degree {
Degree(self.data.n() as u32)
fn n(&self) -> RingDegree {
RingDegree(self.data.n() as u32)
}
fn size(&self) -> usize {
@@ -84,3 +95,29 @@ impl<D: DataMut> LWESecret<D> {
self.dist = Distribution::ZERO;
}
}
pub trait LWESecretToRef {
fn to_ref(&self) -> LWESecret<&[u8]>;
}
impl<D: DataRef> LWESecretToRef for LWESecret<D> {
fn to_ref(&self) -> LWESecret<&[u8]> {
LWESecret {
dist: self.dist,
data: self.data.to_ref(),
}
}
}
pub trait LWESecretToMut {
fn to_mut(&mut self) -> LWESecret<&mut [u8]>;
}
impl<D: DataMut> LWESecretToMut for LWESecret<D> {
fn to_mut(&mut self) -> LWESecret<&mut [u8]> {
LWESecret {
dist: self.dist,
data: self.data.to_mut(),
}
}
}

View File

@@ -1,15 +1,18 @@
use std::fmt;
use poulpy_hal::{
layouts::{Data, DataMut, DataRef, FillUniform, ReaderFrom, WriterTo},
layouts::{Backend, Data, DataMut, DataRef, FillUniform, Module, ReaderFrom, WriterTo},
source::Source,
};
use crate::layouts::{Base2K, Degree, Dnum, Dsize, GGLWEInfos, GGLWESwitchingKey, GLWEInfos, LWEInfos, Rank, TorusPrecision};
use crate::layouts::{
Base2K, Dnum, Dsize, GGLWEInfos, GLWEInfos, GLWESwitchingKey, GLWESwitchingKeyAlloc, GLWESwitchingKeyToMut,
GLWESwitchingKeyToRef, LWEInfos, Rank, RingDegree, TorusPrecision,
};
#[derive(PartialEq, Eq, Copy, Clone, Debug)]
pub struct LWEToGLWESwitchingKeyLayout {
pub n: Degree,
pub n: RingDegree,
pub base2k: Base2K,
pub k: TorusPrecision,
pub rank_out: Rank,
@@ -25,7 +28,7 @@ impl LWEInfos for LWEToGLWESwitchingKeyLayout {
self.k
}
fn n(&self) -> Degree {
fn n(&self) -> RingDegree {
self.n
}
}
@@ -55,7 +58,7 @@ impl GGLWEInfos for LWEToGLWESwitchingKeyLayout {
}
#[derive(PartialEq, Eq, Clone)]
pub struct LWEToGLWESwitchingKey<D: Data>(pub(crate) GGLWESwitchingKey<D>);
pub struct LWEToGLWESwitchingKey<D: Data>(pub(crate) GLWESwitchingKey<D>);
impl<D: Data> LWEInfos for LWEToGLWESwitchingKey<D> {
fn base2k(&self) -> Base2K {
@@ -66,7 +69,7 @@ impl<D: Data> LWEInfos for LWEToGLWESwitchingKey<D> {
self.0.k()
}
fn n(&self) -> Degree {
fn n(&self) -> RingDegree {
self.0.n()
}
@@ -128,54 +131,116 @@ impl<D: DataRef> WriterTo for LWEToGLWESwitchingKey<D> {
}
}
impl LWEToGLWESwitchingKey<Vec<u8>> {
pub fn alloc<A>(infos: &A) -> Self
pub trait LWEToGLWESwitchingKeyAlloc
where
Self: GLWESwitchingKeyAlloc,
{
fn alloc_lwe_to_glwe_switching_key(
&self,
base2k: Base2K,
k: TorusPrecision,
rank_out: Rank,
dnum: Dnum,
) -> LWEToGLWESwitchingKey<Vec<u8>> {
LWEToGLWESwitchingKey(self.alloc_glwe_switching_key(base2k, k, Rank(1), rank_out, dnum, Dsize(1)))
}
fn alloc_lwe_to_glwe_switching_key_from_infos<A>(&self, infos: &A) -> LWEToGLWESwitchingKey<Vec<u8>>
where
A: GGLWEInfos,
{
debug_assert_eq!(
assert_eq!(
infos.rank_in().0,
1,
"rank_in > 1 is not supported for LWEToGLWESwitchingKey"
);
debug_assert_eq!(
assert_eq!(
infos.dsize().0,
1,
"dsize > 1 is not supported for LWEToGLWESwitchingKey"
);
Self(GGLWESwitchingKey::alloc(infos))
self.alloc_lwe_to_glwe_switching_key(infos.base2k(), infos.k(), infos.rank_out(), infos.dnum())
}
pub fn alloc_with(n: Degree, base2k: Base2K, k: TorusPrecision, rank_out: Rank, dnum: Dnum) -> Self {
Self(GGLWESwitchingKey::alloc_with(
n,
base2k,
k,
Rank(1),
rank_out,
dnum,
Dsize(1),
))
fn bytes_of_lwe_to_glwe_switching_key(&self, base2k: Base2K, k: TorusPrecision, rank_out: Rank, dnum: Dnum) -> usize {
self.bytes_of_glwe_switching_key(base2k, k, Rank(1), rank_out, dnum, Dsize(1))
}
pub fn alloc_bytes<A>(infos: &A) -> usize
fn bytes_of_lwe_to_glwe_switching_key_from_infos<A>(&self, infos: &A) -> usize
where
A: GGLWEInfos,
{
debug_assert_eq!(
assert_eq!(
infos.rank_in().0,
1,
"rank_in > 1 is not supported for LWEToGLWESwitchingKey"
);
debug_assert_eq!(
assert_eq!(
infos.dsize().0,
1,
"dsize > 1 is not supported for LWEToGLWESwitchingKey"
);
GGLWESwitchingKey::alloc_bytes(infos)
}
pub fn alloc_bytes_with(n: Degree, base2k: Base2K, k: TorusPrecision, dnum: Dnum, rank_out: Rank) -> usize {
GGLWESwitchingKey::alloc_bytes_with(n, base2k, k, Rank(1), rank_out, dnum, Dsize(1))
self.bytes_of_lwe_to_glwe_switching_key(infos.base2k(), infos.k(), infos.rank_out(), infos.dnum())
}
}
impl<B: Backend> LWEToGLWESwitchingKeyAlloc for Module<B> where Self: GLWESwitchingKeyAlloc {}
impl LWEToGLWESwitchingKey<Vec<u8>> {
pub fn alloc_from_infos<A, M>(module: &M, infos: &A) -> Self
where
A: GGLWEInfos,
M: LWEToGLWESwitchingKeyAlloc,
{
module.alloc_lwe_to_glwe_switching_key_from_infos(infos)
}
pub fn alloc<M>(module: &M, base2k: Base2K, k: TorusPrecision, rank_out: Rank, dnum: Dnum) -> Self
where
M: LWEToGLWESwitchingKeyAlloc,
{
module.alloc_lwe_to_glwe_switching_key(base2k, k, rank_out, dnum)
}
pub fn bytes_of_from_infos<A, M>(module: &M, infos: &A) -> usize
where
A: GGLWEInfos,
M: LWEToGLWESwitchingKeyAlloc,
{
module.bytes_of_lwe_to_glwe_switching_key_from_infos(infos)
}
pub fn bytes_of<M>(module: &M, base2k: Base2K, k: TorusPrecision, dnum: Dnum, rank_out: Rank) -> usize
where
M: LWEToGLWESwitchingKeyAlloc,
{
module.bytes_of_lwe_to_glwe_switching_key(base2k, k, rank_out, dnum)
}
}
pub trait LWEToGLWESwitchingKeyToRef {
fn to_ref(&self) -> LWEToGLWESwitchingKey<&[u8]>;
}
impl<D: DataRef> LWEToGLWESwitchingKeyToRef for LWEToGLWESwitchingKey<D>
where
GLWESwitchingKey<D>: GLWESwitchingKeyToRef,
{
fn to_ref(&self) -> LWEToGLWESwitchingKey<&[u8]> {
LWEToGLWESwitchingKey(self.0.to_ref())
}
}
pub trait LWEToGLWESwitchingKeyToMut {
fn to_mut(&mut self) -> LWEToGLWESwitchingKey<&mut [u8]>;
}
impl<D: DataMut> LWEToGLWESwitchingKeyToMut for LWEToGLWESwitchingKey<D>
where
GLWESwitchingKey<D>: GLWESwitchingKeyToMut,
{
fn to_mut(&mut self) -> LWEToGLWESwitchingKey<&mut [u8]> {
LWEToGLWESwitchingKey(self.0.to_mut())
}
}

View File

@@ -33,20 +33,16 @@ pub use lwe_pt::*;
pub use lwe_sk::*;
pub use lwe_to_glwe_ksk::*;
#[derive(Debug)]
pub enum BuildError {
MissingData,
MissingBase2K,
MissingK,
MissingDigits,
ZeroDegree,
NonPowerOfTwoDegree,
ZeroBase2K,
ZeroTorusPrecision,
ZeroCols,
ZeroLimbs,
ZeroRank,
ZeroDigits,
use poulpy_hal::layouts::{Backend, Module};
pub trait GetRingDegree {
fn ring_degree(&self) -> RingDegree;
}
impl<B: Backend> GetRingDegree for Module<B> {
fn ring_degree(&self) -> RingDegree {
Self::n(&self).into()
}
}
/// Newtype over `u32` with arithmetic and comparisons against same type and `u32`.
@@ -206,14 +202,14 @@ macro_rules! newtype_u32 {
};
}
newtype_u32!(Degree);
newtype_u32!(RingDegree);
newtype_u32!(TorusPrecision);
newtype_u32!(Base2K);
newtype_u32!(Dnum);
newtype_u32!(Rank);
newtype_u32!(Dsize);
impl Degree {
impl RingDegree {
pub fn log2(&self) -> usize {
let n: usize = self.0 as usize;
(usize::BITS - (n - 1).leading_zeros()) as _

View File

@@ -1,27 +1,21 @@
use poulpy_hal::{
api::{VmpPMatAlloc, VmpPMatAllocBytes, VmpPrepare},
layouts::{Backend, Data, DataMut, DataRef, Module, Scratch},
};
use poulpy_hal::layouts::{Backend, Data, DataMut, DataRef, Module, Scratch};
use crate::layouts::{
Base2K, Degree, Dnum, Dsize, GGLWEAutomorphismKey, GGLWEInfos, GLWEInfos, LWEInfos, Rank, TorusPrecision,
prepared::{GGLWESwitchingKeyPrepared, Prepare, PrepareAlloc, PrepareScratchSpace},
AutomorphismKeyToRef, Base2K, Dnum, Dsize, GGLWEInfos, GLWEInfos, LWEInfos, Rank, RingDegree, TorusPrecision,
prepared::{
GLWESwitchingKeyPrepare, GLWESwitchingKeyPrepared, GLWESwitchingKeyPreparedAlloc, GLWESwitchingKeyPreparedToMut,
GLWESwitchingKeyPreparedToRef,
},
};
#[derive(PartialEq, Eq)]
pub struct GGLWEAutomorphismKeyPrepared<D: Data, B: Backend> {
pub(crate) key: GGLWESwitchingKeyPrepared<D, B>,
pub struct AutomorphismKeyPrepared<D: Data, B: Backend> {
pub(crate) key: GLWESwitchingKeyPrepared<D, B>,
pub(crate) p: i64,
}
impl<D: Data, B: Backend> GGLWEAutomorphismKeyPrepared<D, B> {
pub fn p(&self) -> i64 {
self.p
}
}
impl<D: Data, B: Backend> LWEInfos for GGLWEAutomorphismKeyPrepared<D, B> {
fn n(&self) -> Degree {
impl<D: Data, B: Backend> LWEInfos for AutomorphismKeyPrepared<D, B> {
fn n(&self) -> RingDegree {
self.key.n()
}
@@ -38,13 +32,33 @@ impl<D: Data, B: Backend> LWEInfos for GGLWEAutomorphismKeyPrepared<D, B> {
}
}
impl<D: Data, B: Backend> GLWEInfos for GGLWEAutomorphismKeyPrepared<D, B> {
pub trait GetAutomorphismGaloisElement {
fn p(&self) -> i64;
}
impl<D: Data, B: Backend> GetAutomorphismGaloisElement for AutomorphismKeyPrepared<D, B> {
fn p(&self) -> i64 {
self.p
}
}
pub trait SetAutomorphismGaloisElement {
fn set_p(&mut self, p: i64);
}
impl<D: Data, B: Backend> SetAutomorphismGaloisElement for AutomorphismKeyPrepared<D, B> {
fn set_p(&mut self, p: i64) {
self.p = p
}
}
impl<D: Data, B: Backend> GLWEInfos for AutomorphismKeyPrepared<D, B> {
fn rank(&self) -> Rank {
self.rank_out()
}
}
impl<D: Data, B: Backend> GGLWEInfos for GGLWEAutomorphismKeyPrepared<D, B> {
impl<D: Data, B: Backend> GGLWEInfos for AutomorphismKeyPrepared<D, B> {
fn rank_in(&self) -> Rank {
self.key.rank_in()
}
@@ -62,80 +76,170 @@ impl<D: Data, B: Backend> GGLWEInfos for GGLWEAutomorphismKeyPrepared<D, B> {
}
}
impl<B: Backend> GGLWEAutomorphismKeyPrepared<Vec<u8>, B> {
pub fn alloc<A>(module: &Module<B>, infos: &A) -> Self
pub trait AutomorphismKeyPreparedAlloc<B: Backend>
where
Self: GLWESwitchingKeyPreparedAlloc<B>,
{
fn alloc_automorphism_key_prepared(
&self,
base2k: Base2K,
k: TorusPrecision,
rank: Rank,
dnum: Dnum,
dsize: Dsize,
) -> AutomorphismKeyPrepared<Vec<u8>, B> {
AutomorphismKeyPrepared::<Vec<u8>, B> {
key: self.alloc_glwe_switching_key_prepared(base2k, k, rank, rank, dnum, dsize),
p: 0,
}
}
fn alloc_automorphism_key_prepared_from_infos<A>(&self, infos: &A) -> AutomorphismKeyPrepared<Vec<u8>, B>
where
A: GGLWEInfos,
{
assert_eq!(
infos.rank_in(),
infos.rank_out(),
"rank_in != rank_out is not supported for AutomorphismKeyPrepared"
);
self.alloc_automorphism_key_prepared(
infos.base2k(),
infos.k(),
infos.rank(),
infos.dnum(),
infos.dsize(),
)
}
fn bytes_of_automorphism_key_prepared(
&self,
base2k: Base2K,
k: TorusPrecision,
rank: Rank,
dnum: Dnum,
dsize: Dsize,
) -> usize {
self.bytes_of_glwe_switching_key_prepared(base2k, k, rank, rank, dnum, dsize)
}
fn bytes_of_automorphism_key_prepared_from_infos<A>(&self, infos: &A) -> usize
where
A: GGLWEInfos,
Module<B>: VmpPMatAlloc<B>,
{
assert_eq!(
infos.rank_in(),
infos.rank_out(),
"rank_in != rank_out is not supported for GGLWEAutomorphismKeyPrepared"
);
GGLWEAutomorphismKeyPrepared::<Vec<u8>, B> {
key: GGLWESwitchingKeyPrepared::alloc(module, infos),
p: 0,
}
self.bytes_of_automorphism_key_prepared(
infos.base2k(),
infos.k(),
infos.rank(),
infos.dnum(),
infos.dsize(),
)
}
}
pub fn alloc_with(module: &Module<B>, base2k: Base2K, k: TorusPrecision, rank: Rank, dnum: Dnum, dsize: Dsize) -> Self
where
Module<B>: VmpPMatAlloc<B>,
{
GGLWEAutomorphismKeyPrepared {
key: GGLWESwitchingKeyPrepared::alloc_with(module, base2k, k, rank, rank, dnum, dsize),
p: 0,
}
}
impl<B: Backend> AutomorphismKeyPreparedAlloc<B> for Module<B> where Module<B>: GLWESwitchingKeyPreparedAlloc<B> {}
pub fn alloc_bytes<A>(module: &Module<B>, infos: &A) -> usize
impl<B: Backend> AutomorphismKeyPrepared<Vec<u8>, B> {
pub fn alloc_from_infos<A, M>(module: &M, infos: &A) -> Self
where
A: GGLWEInfos,
Module<B>: VmpPMatAllocBytes,
M: AutomorphismKeyPreparedAlloc<B>,
{
assert_eq!(
infos.rank_in(),
infos.rank_out(),
"rank_in != rank_out is not supported for GGLWEAutomorphismKeyPrepared"
);
GGLWESwitchingKeyPrepared::alloc_bytes(module, infos)
module.alloc_automorphism_key_prepared_from_infos(infos)
}
pub fn alloc_bytes_with(module: &Module<B>, base2k: Base2K, k: TorusPrecision, rank: Rank, dnum: Dnum, dsize: Dsize) -> usize
pub fn alloc<M>(module: &M, base2k: Base2K, k: TorusPrecision, rank: Rank, dnum: Dnum, dsize: Dsize) -> Self
where
Module<B>: VmpPMatAllocBytes,
M: AutomorphismKeyPreparedAlloc<B>,
{
GGLWESwitchingKeyPrepared::alloc_bytes_with(module, base2k, k, rank, rank, dnum, dsize)
module.alloc_automorphism_key_prepared(base2k, k, rank, dnum, dsize)
}
pub fn bytes_of_from_infos<A, M>(module: &M, infos: &A) -> usize
where
A: GGLWEInfos,
M: AutomorphismKeyPreparedAlloc<B>,
{
module.bytes_of_automorphism_key_prepared_from_infos(infos)
}
pub fn bytes_of<M>(module: &M, base2k: Base2K, k: TorusPrecision, rank: Rank, dnum: Dnum, dsize: Dsize) -> usize
where
M: AutomorphismKeyPreparedAlloc<B>,
{
module.bytes_of_automorphism_key_prepared(base2k, k, rank, dnum, dsize)
}
}
impl<B: Backend, A: GGLWEInfos> PrepareScratchSpace<B, A> for GGLWEAutomorphismKeyPrepared<Vec<u8>, B>
pub trait PrepareAutomorphismKey<B: Backend>
where
GGLWESwitchingKeyPrepared<Vec<u8>, B>: PrepareScratchSpace<B, A>,
Self: GLWESwitchingKeyPrepare<B>,
{
fn prepare_scratch_space(module: &Module<B>, infos: &A) -> usize {
GGLWESwitchingKeyPrepared::prepare_scratch_space(module, infos)
fn prepare_automorphism_key_tmp_bytes<A>(&self, infos: &A) -> usize
where
A: GGLWEInfos,
{
self.prepare_glwe_switching_key_tmp_bytes(infos)
}
fn prepare_automorphism_key<R, O>(&self, res: &mut R, other: &O, scratch: &mut Scratch<B>)
where
R: AutomorphismKeyPreparedToMut<B> + SetAutomorphismGaloisElement,
O: AutomorphismKeyToRef + GetAutomorphismGaloisElement,
{
self.prepare_glwe_switching(&mut res.to_mut().key, &other.to_ref().key, scratch);
res.set_p(other.p());
}
}
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<B: Backend> PrepareAutomorphismKey<B> for Module<B> where Module<B>: GLWESwitchingKeyPrepare<B> {}
impl<B: Backend> AutomorphismKeyPrepared<Vec<u8>, B> {
pub fn prepare_tmp_bytes<M>(&self, module: &M) -> usize
where
M: PrepareAutomorphismKey<B>,
{
module.prepare_automorphism_key_tmp_bytes(self)
}
}
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);
atk_prepared.prepare(module, self, scratch);
atk_prepared
impl<D: DataMut, B: Backend> AutomorphismKeyPrepared<D, B> {
pub fn prepare<O, M>(&mut self, module: &M, other: &O, scratch: &mut Scratch<B>)
where
O: AutomorphismKeyToRef + GetAutomorphismGaloisElement,
M: PrepareAutomorphismKey<B>,
{
module.prepare_automorphism_key(self, other, scratch);
}
}
pub trait AutomorphismKeyPreparedToMut<B: Backend> {
fn to_mut(&mut self) -> AutomorphismKeyPrepared<&mut [u8], B>;
}
impl<D: DataMut, B: Backend> AutomorphismKeyPreparedToMut<B> for AutomorphismKeyPrepared<D, B> {
fn to_mut(&mut self) -> AutomorphismKeyPrepared<&mut [u8], B> {
AutomorphismKeyPrepared {
p: self.p,
key: self.key.to_mut(),
}
}
}
pub trait AutomorphismKeyPreparedToRef<B: Backend> {
fn to_ref(&self) -> AutomorphismKeyPrepared<&[u8], B>;
}
impl<D: DataRef, B: Backend> AutomorphismKeyPreparedToRef<B> for AutomorphismKeyPrepared<D, B> {
fn to_ref(&self) -> AutomorphismKeyPrepared<&[u8], B> {
AutomorphismKeyPrepared {
p: self.p,
key: self.key.to_ref(),
}
}
}

View File

@@ -1,25 +1,23 @@
use poulpy_hal::{
api::{VmpPMatAlloc, VmpPMatAllocBytes, VmpPrepare, VmpPrepareTmpBytes},
layouts::{Backend, Data, DataMut, DataRef, Module, Scratch, VmpPMat, ZnxInfos},
oep::VmpPMatAllocBytesImpl,
api::{VmpPMatAlloc, VmpPMatBytesOf, VmpPrepare, VmpPrepareTmpBytes},
layouts::{Backend, Data, DataMut, DataRef, Module, Scratch, VmpPMat, VmpPMatToMut, VmpPMatToRef, ZnxInfos},
};
use crate::layouts::{
Base2K, BuildError, Degree, Dnum, Dsize, GGLWECiphertext, GGLWEInfos, GLWEInfos, LWEInfos, Rank, TorusPrecision,
prepared::{Prepare, PrepareAlloc, PrepareScratchSpace},
Base2K, Dnum, Dsize, GGLWE, GGLWEInfos, GGLWEToRef, GLWEInfos, GetRingDegree, LWEInfos, Rank, RingDegree, TorusPrecision,
};
#[derive(PartialEq, Eq)]
pub struct GGLWECiphertextPrepared<D: Data, B: Backend> {
pub struct GGLWEPrepared<D: Data, B: Backend> {
pub(crate) data: VmpPMat<D, B>,
pub(crate) k: TorusPrecision,
pub(crate) base2k: Base2K,
pub(crate) dsize: Dsize,
}
impl<D: Data, B: Backend> LWEInfos for GGLWECiphertextPrepared<D, B> {
fn n(&self) -> Degree {
Degree(self.data.n() as u32)
impl<D: Data, B: Backend> LWEInfos for GGLWEPrepared<D, B> {
fn n(&self) -> RingDegree {
RingDegree(self.data.n() as u32)
}
fn base2k(&self) -> Base2K {
@@ -35,13 +33,13 @@ impl<D: Data, B: Backend> LWEInfos for GGLWECiphertextPrepared<D, B> {
}
}
impl<D: Data, B: Backend> GLWEInfos for GGLWECiphertextPrepared<D, B> {
impl<D: Data, B: Backend> GLWEInfos for GGLWEPrepared<D, B> {
fn rank(&self) -> Rank {
self.rank_out()
}
}
impl<D: Data, B: Backend> GGLWEInfos for GGLWECiphertextPrepared<D, B> {
impl<D: Data, B: Backend> GGLWEInfos for GGLWEPrepared<D, B> {
fn rank_in(&self) -> Rank {
Rank(self.data.cols_in() as u32)
}
@@ -59,117 +57,47 @@ impl<D: Data, B: Backend> GGLWEInfos for GGLWECiphertextPrepared<D, B> {
}
}
pub struct GGLWECiphertextPreparedBuilder<D: Data, B: Backend> {
data: Option<VmpPMat<D, B>>,
base2k: Option<Base2K>,
k: Option<TorusPrecision>,
dsize: Option<Dsize>,
}
pub trait GGLWEPreparedAlloc<B: Backend>
where
Self: GetRingDegree + VmpPMatAlloc<B> + VmpPMatBytesOf,
{
fn alloc_gglwe_prepared(
&self,
base2k: Base2K,
k: TorusPrecision,
rank_in: Rank,
rank_out: Rank,
dnum: Dnum,
dsize: Dsize,
) -> GGLWEPrepared<Vec<u8>, B> {
let size: usize = k.0.div_ceil(base2k.0) as usize;
debug_assert!(
size as u32 > dsize.0,
"invalid gglwe: ceil(k/base2k): {size} <= dsize: {}",
dsize.0
);
impl<D: Data, B: Backend> GGLWECiphertextPrepared<D, B> {
#[inline]
pub fn builder() -> GGLWECiphertextPreparedBuilder<D, B> {
GGLWECiphertextPreparedBuilder {
data: None,
base2k: None,
k: None,
dsize: None,
}
}
}
assert!(
dnum.0 * dsize.0 <= size as u32,
"invalid gglwe: dnum: {} * dsize:{} > ceil(k/base2k): {size}",
dnum.0,
dsize.0,
);
impl<B: Backend> GGLWECiphertextPreparedBuilder<Vec<u8>, B> {
#[inline]
pub fn layout<A>(mut self, infos: &A) -> Self
where
A: GGLWEInfos,
B: VmpPMatAllocBytesImpl<B>,
{
self.data = Some(VmpPMat::alloc(
infos.n().into(),
infos.dnum().into(),
infos.rank_in().into(),
(infos.rank_out() + 1).into(),
infos.size(),
));
self.base2k = Some(infos.base2k());
self.k = Some(infos.k());
self.dsize = Some(infos.dsize());
self
}
}
impl<D: Data, B: Backend> GGLWECiphertextPreparedBuilder<D, B> {
#[inline]
pub fn data(mut self, data: VmpPMat<D, B>) -> Self {
self.data = Some(data);
self
}
#[inline]
pub fn base2k(mut self, base2k: Base2K) -> Self {
self.base2k = Some(base2k);
self
}
#[inline]
pub fn k(mut self, k: TorusPrecision) -> Self {
self.k = Some(k);
self
}
#[inline]
pub fn dsize(mut self, dsize: Dsize) -> Self {
self.dsize = Some(dsize);
self
}
pub fn build(self) -> Result<GGLWECiphertextPrepared<D, B>, BuildError> {
let data: VmpPMat<D, B> = self.data.ok_or(BuildError::MissingData)?;
let base2k: Base2K = self.base2k.ok_or(BuildError::MissingBase2K)?;
let k: TorusPrecision = self.k.ok_or(BuildError::MissingK)?;
let dsize: Dsize = self.dsize.ok_or(BuildError::MissingDigits)?;
if base2k == 0_u32 {
return Err(BuildError::ZeroBase2K);
}
if dsize == 0_u32 {
return Err(BuildError::ZeroBase2K);
}
if k == 0_u32 {
return Err(BuildError::ZeroTorusPrecision);
}
if data.n() == 0 {
return Err(BuildError::ZeroDegree);
}
if data.cols() == 0 {
return Err(BuildError::ZeroCols);
}
if data.size() == 0 {
return Err(BuildError::ZeroLimbs);
}
Ok(GGLWECiphertextPrepared {
data,
base2k,
GGLWEPrepared {
data: self.vmp_pmat_alloc(dnum.into(), rank_in.into(), (rank_out + 1).into(), size),
k,
base2k,
dsize,
})
}
}
}
impl<B: Backend> GGLWECiphertextPrepared<Vec<u8>, B> {
pub fn alloc<A>(module: &Module<B>, infos: &A) -> Self
fn alloc_gglwe_prepared_from_infos<A>(&self, infos: &A) -> GGLWEPrepared<Vec<u8>, B>
where
A: GGLWEInfos,
Module<B>: VmpPMatAlloc<B>,
{
debug_assert_eq!(module.n(), infos.n().0 as usize, "module.n() != infos.n()");
Self::alloc_with(
module,
assert_eq!(self.ring_degree(), infos.n());
self.alloc_gglwe_prepared(
infos.base2k(),
infos.k(),
infos.rank_in(),
@@ -179,8 +107,61 @@ impl<B: Backend> GGLWECiphertextPrepared<Vec<u8>, B> {
)
}
pub fn alloc_with(
module: &Module<B>,
fn bytes_of_gglwe_prepared(
&self,
base2k: Base2K,
k: TorusPrecision,
rank_in: Rank,
rank_out: Rank,
dnum: Dnum,
dsize: Dsize,
) -> usize {
let size: usize = k.0.div_ceil(base2k.0) as usize;
debug_assert!(
size as u32 > dsize.0,
"invalid gglwe: ceil(k/base2k): {size} <= dsize: {}",
dsize.0
);
assert!(
dnum.0 * dsize.0 <= size as u32,
"invalid gglwe: dnum: {} * dsize:{} > ceil(k/base2k): {size}",
dnum.0,
dsize.0,
);
self.bytes_of_vmp_pmat(dnum.into(), rank_in.into(), (rank_out + 1).into(), size)
}
fn bytes_of_gglwe_prepared_from_infos<A>(&self, infos: &A) -> usize
where
A: GGLWEInfos,
{
assert_eq!(self.ring_degree(), infos.n());
self.bytes_of_gglwe_prepared(
infos.base2k(),
infos.k(),
infos.rank_in(),
infos.rank_out(),
infos.dnum(),
infos.dsize(),
)
}
}
impl<B: Backend> GGLWEPreparedAlloc<B> for Module<B> where Module<B>: GetRingDegree + VmpPMatAlloc<B> + VmpPMatBytesOf {}
impl<B: Backend> GGLWEPrepared<Vec<u8>, B> {
pub fn alloc_from_infos<A, M>(module: &M, infos: &A) -> Self
where
A: GGLWEInfos,
M: GGLWEPreparedAlloc<B>,
{
module.alloc_gglwe_prepared_from_infos(infos)
}
pub fn alloc<M>(
module: &M,
base2k: Base2K,
k: TorusPrecision,
rank_in: Rank,
@@ -189,49 +170,21 @@ impl<B: Backend> GGLWECiphertextPrepared<Vec<u8>, B> {
dsize: Dsize,
) -> Self
where
Module<B>: VmpPMatAlloc<B>,
M: GGLWEPreparedAlloc<B>,
{
let size: usize = k.0.div_ceil(base2k.0) as usize;
debug_assert!(
size as u32 > dsize.0,
"invalid gglwe: ceil(k/base2k): {size} <= dsize: {}",
dsize.0
);
assert!(
dnum.0 * dsize.0 <= size as u32,
"invalid gglwe: dnum: {} * dsize:{} > ceil(k/base2k): {size}",
dnum.0,
dsize.0,
);
Self {
data: module.vmp_pmat_alloc(dnum.into(), rank_in.into(), (rank_out + 1).into(), size),
k,
base2k,
dsize,
}
module.alloc_gglwe_prepared(base2k, k, rank_in, rank_out, dnum, dsize)
}
pub fn alloc_bytes<A>(module: &Module<B>, infos: &A) -> usize
pub fn bytes_of_from_infos<A, M>(module: &M, infos: &A) -> usize
where
A: GGLWEInfos,
Module<B>: VmpPMatAllocBytes,
M: GGLWEPreparedAlloc<B>,
{
debug_assert_eq!(module.n(), infos.n().0 as usize, "module.n() != infos.n()");
Self::alloc_bytes_with(
module,
infos.base2k(),
infos.k(),
infos.rank_in(),
infos.rank_out(),
infos.dnum(),
infos.dsize(),
)
module.bytes_of_gglwe_prepared_from_infos(infos)
}
pub fn alloc_bytes_with(
module: &Module<B>,
pub fn bytes_of<M>(
module: &M,
base2k: Base2K,
k: TorusPrecision,
rank_in: Rank,
@@ -240,59 +193,93 @@ impl<B: Backend> GGLWECiphertextPrepared<Vec<u8>, B> {
dsize: Dsize,
) -> usize
where
Module<B>: VmpPMatAllocBytes,
M: GGLWEPreparedAlloc<B>,
{
let size: usize = k.0.div_ceil(base2k.0) as usize;
debug_assert!(
size as u32 > dsize.0,
"invalid gglwe: ceil(k/base2k): {size} <= dsize: {}",
dsize.0
);
assert!(
dnum.0 * dsize.0 <= size as u32,
"invalid gglwe: dnum: {} * dsize:{} > ceil(k/base2k): {size}",
dnum.0,
dsize.0,
);
module.vmp_pmat_alloc_bytes(dnum.into(), rank_in.into(), (rank_out + 1).into(), size)
module.bytes_of_gglwe_prepared(base2k, k, rank_in, rank_out, dnum, dsize)
}
}
impl<B: Backend, A: GGLWEInfos> PrepareScratchSpace<B, A> for GGLWECiphertextPrepared<Vec<u8>, B>
pub trait GGLWEPrepare<B: Backend>
where
Module<B>: VmpPrepareTmpBytes,
Self: GetRingDegree + VmpPrepareTmpBytes + VmpPrepare<B>,
{
fn prepare_scratch_space(module: &Module<B>, infos: &A) -> usize {
module.vmp_prepare_tmp_bytes(
fn prepare_gglwe_tmp_bytes<A>(&self, infos: &A) -> usize
where
A: GGLWEInfos,
{
self.vmp_prepare_tmp_bytes(
infos.dnum().into(),
infos.rank_in().into(),
(infos.rank() + 1).into(),
infos.size(),
)
}
}
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.k = other.k;
self.base2k = other.base2k;
self.dsize = other.dsize;
fn prepare_gglwe<R, O>(&self, res: &mut R, other: &O, scratch: &mut Scratch<B>)
where
R: GGLWEPreparedToMut<B>,
O: GGLWEToRef,
{
let mut res: GGLWEPrepared<&mut [u8], B> = res.to_mut();
let other: GGLWE<&[u8]> = other.to_ref();
assert_eq!(res.n(), self.ring_degree());
assert_eq!(other.n(), self.ring_degree());
assert_eq!(res.base2k, other.base2k);
assert_eq!(res.k, other.k);
assert_eq!(res.dsize, other.dsize);
self.vmp_prepare(&mut res.data, &other.data, scratch);
}
}
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);
atk_prepared.prepare(module, self, scratch);
atk_prepared
impl<B: Backend> GGLWEPrepare<B> for Module<B> where Self: GetRingDegree + VmpPrepareTmpBytes + VmpPrepare<B> {}
impl<D: DataMut, B: Backend> GGLWEPrepared<D, B> {
pub fn prepare<O, M>(&mut self, module: &M, other: &O, scratch: &mut Scratch<B>)
where
O: GGLWEToRef,
M: GGLWEPrepare<B>,
{
module.prepare_gglwe(self, other, scratch);
}
}
impl<B: Backend> GGLWEPrepared<Vec<u8>, B> {
pub fn prepare_tmp_bytes<M>(&self, module: &M) -> usize
where
M: GGLWEPrepare<B>,
{
module.prepare_gglwe_tmp_bytes(self)
}
}
pub trait GGLWEPreparedToMut<B: Backend> {
fn to_mut(&mut self) -> GGLWEPrepared<&mut [u8], B>;
}
impl<D: DataMut, B: Backend> GGLWEPreparedToMut<B> for GGLWEPrepared<D, B> {
fn to_mut(&mut self) -> GGLWEPrepared<&mut [u8], B> {
GGLWEPrepared {
k: self.k,
base2k: self.base2k,
dsize: self.dsize,
data: self.data.to_mut(),
}
}
}
pub trait GGLWEPreparedToRef<B: Backend> {
fn to_ref(&self) -> GGLWEPrepared<&[u8], B>;
}
impl<D: DataRef, B: Backend> GGLWEPreparedToRef<B> for GGLWEPrepared<D, B> {
fn to_ref(&self) -> GGLWEPrepared<&[u8], B> {
GGLWEPrepared {
k: self.k,
base2k: self.base2k,
dsize: self.dsize,
data: self.data.to_ref(),
}
}
}

View File

@@ -1,22 +1,40 @@
use poulpy_hal::{
api::{VmpPMatAlloc, VmpPMatAllocBytes, VmpPrepare},
layouts::{Backend, Data, DataMut, DataRef, Module, Scratch},
};
use poulpy_hal::layouts::{Backend, Data, DataMut, DataRef, Module, Scratch};
use crate::layouts::{
Base2K, Degree, Dnum, Dsize, GGLWEInfos, GGLWESwitchingKey, GLWEInfos, LWEInfos, Rank, TorusPrecision,
prepared::{GGLWECiphertextPrepared, Prepare, PrepareAlloc, PrepareScratchSpace},
Base2K, Dnum, Dsize, GGLWEInfos, GLWEInfos, GLWESwitchingKeySetMetaData, GLWESwitchingKeyToRef, GLWESwtichingKeyGetMetaData,
LWEInfos, Rank, RingDegree, TorusPrecision,
prepared::{GGLWEPrepare, GGLWEPrepared, GGLWEPreparedAlloc, GGLWEPreparedToMut, GGLWEPreparedToRef},
};
#[derive(PartialEq, Eq)]
pub struct GGLWESwitchingKeyPrepared<D: Data, B: Backend> {
pub(crate) key: GGLWECiphertextPrepared<D, B>,
pub struct GLWESwitchingKeyPrepared<D: Data, B: Backend> {
pub(crate) key: GGLWEPrepared<D, B>,
pub(crate) sk_in_n: usize, // Degree of sk_in
pub(crate) sk_out_n: usize, // Degree of sk_out
}
impl<D: Data, B: Backend> LWEInfos for GGLWESwitchingKeyPrepared<D, B> {
fn n(&self) -> Degree {
impl<D: DataMut, B: Backend> GLWESwitchingKeySetMetaData for GLWESwitchingKeyPrepared<D, B> {
fn set_sk_in_n(&mut self, sk_in_n: usize) {
self.sk_in_n = sk_in_n
}
fn set_sk_out_n(&mut self, sk_out_n: usize) {
self.sk_out_n = sk_out_n
}
}
impl<D: DataRef, B: Backend> GLWESwtichingKeyGetMetaData for GLWESwitchingKeyPrepared<D, B> {
fn sk_in_n(&self) -> usize {
self.sk_in_n
}
fn sk_out_n(&self) -> usize {
self.sk_out_n
}
}
impl<D: Data, B: Backend> LWEInfos for GLWESwitchingKeyPrepared<D, B> {
fn n(&self) -> RingDegree {
self.key.n()
}
@@ -33,13 +51,13 @@ impl<D: Data, B: Backend> LWEInfos for GGLWESwitchingKeyPrepared<D, B> {
}
}
impl<D: Data, B: Backend> GLWEInfos for GGLWESwitchingKeyPrepared<D, B> {
impl<D: Data, B: Backend> GLWEInfos for GLWESwitchingKeyPrepared<D, B> {
fn rank(&self) -> Rank {
self.rank_out()
}
}
impl<D: Data, B: Backend> GGLWEInfos for GGLWESwitchingKeyPrepared<D, B> {
impl<D: Data, B: Backend> GGLWEInfos for GLWESwitchingKeyPrepared<D, B> {
fn rank_in(&self) -> Rank {
self.key.rank_in()
}
@@ -57,22 +75,80 @@ impl<D: Data, B: Backend> GGLWEInfos for GGLWESwitchingKeyPrepared<D, B> {
}
}
impl<B: Backend> GGLWESwitchingKeyPrepared<Vec<u8>, B> {
pub fn alloc<A>(module: &Module<B>, infos: &A) -> Self
where
A: GGLWEInfos,
Module<B>: VmpPMatAlloc<B>,
{
debug_assert_eq!(module.n() as u32, infos.n(), "module.n() != infos.n()");
GGLWESwitchingKeyPrepared::<Vec<u8>, B> {
key: GGLWECiphertextPrepared::alloc(module, infos),
pub trait GLWESwitchingKeyPreparedAlloc<B: Backend>
where
Self: GGLWEPreparedAlloc<B>,
{
fn alloc_glwe_switching_key_prepared(
&self,
base2k: Base2K,
k: TorusPrecision,
rank_in: Rank,
rank_out: Rank,
dnum: Dnum,
dsize: Dsize,
) -> GLWESwitchingKeyPrepared<Vec<u8>, B> {
GLWESwitchingKeyPrepared::<Vec<u8>, B> {
key: self.alloc_gglwe_prepared(base2k, k, rank_in, rank_out, dnum, dsize),
sk_in_n: 0,
sk_out_n: 0,
}
}
pub fn alloc_with(
module: &Module<B>,
fn alloc_glwe_switching_key_prepared_from_infos<A>(&self, infos: &A) -> GLWESwitchingKeyPrepared<Vec<u8>, B>
where
A: GGLWEInfos,
{
self.alloc_glwe_switching_key_prepared(
infos.base2k(),
infos.k(),
infos.rank_in(),
infos.rank_out(),
infos.dnum(),
infos.dsize(),
)
}
fn bytes_of_glwe_switching_key_prepared(
&self,
base2k: Base2K,
k: TorusPrecision,
rank_in: Rank,
rank_out: Rank,
dnum: Dnum,
dsize: Dsize,
) -> usize {
self.bytes_of_gglwe_prepared(base2k, k, rank_in, rank_out, dnum, dsize)
}
fn bytes_of_glwe_switching_key_prepared_from_infos<A>(&self, infos: &A) -> usize
where
A: GGLWEInfos,
{
self.bytes_of_glwe_switching_key_prepared(
infos.base2k(),
infos.k(),
infos.rank_in(),
infos.rank_out(),
infos.dnum(),
infos.dsize(),
)
}
}
impl<B: Backend> GLWESwitchingKeyPreparedAlloc<B> for Module<B> where Self: GGLWEPreparedAlloc<B> {}
impl<B: Backend> GLWESwitchingKeyPrepared<Vec<u8>, B> {
pub fn alloc_from_infos<A, M>(module: &M, infos: &A) -> Self
where
A: GGLWEInfos,
M: GLWESwitchingKeyPreparedAlloc<B>,
{
module.alloc_glwe_switching_key_prepared_from_infos(infos)
}
pub fn alloc<M>(
module: &M,
base2k: Base2K,
k: TorusPrecision,
rank_in: Rank,
@@ -81,26 +157,21 @@ impl<B: Backend> GGLWESwitchingKeyPrepared<Vec<u8>, B> {
dsize: Dsize,
) -> Self
where
Module<B>: VmpPMatAlloc<B>,
M: GLWESwitchingKeyPreparedAlloc<B>,
{
GGLWESwitchingKeyPrepared::<Vec<u8>, B> {
key: GGLWECiphertextPrepared::alloc_with(module, base2k, k, rank_in, rank_out, dnum, dsize),
sk_in_n: 0,
sk_out_n: 0,
}
module.alloc_glwe_switching_key_prepared(base2k, k, rank_in, rank_out, dnum, dsize)
}
pub fn alloc_bytes<A>(module: &Module<B>, infos: &A) -> usize
pub fn bytes_of_from_infos<A, M>(module: &M, infos: &A) -> usize
where
A: GGLWEInfos,
Module<B>: VmpPMatAllocBytes,
M: GLWESwitchingKeyPreparedAlloc<B>,
{
debug_assert_eq!(module.n() as u32, infos.n(), "module.n() != infos.n()");
GGLWECiphertextPrepared::alloc_bytes(module, infos)
module.bytes_of_glwe_switching_key_prepared_from_infos(infos)
}
pub fn alloc_bytes_with(
module: &Module<B>,
pub fn bytes_of<M>(
module: &M,
base2k: Base2K,
k: TorusPrecision,
rank_in: Rank,
@@ -109,39 +180,79 @@ impl<B: Backend> GGLWESwitchingKeyPrepared<Vec<u8>, B> {
dsize: Dsize,
) -> usize
where
Module<B>: VmpPMatAllocBytes,
M: GLWESwitchingKeyPreparedAlloc<B>,
{
GGLWECiphertextPrepared::alloc_bytes_with(module, base2k, k, rank_in, rank_out, dnum, dsize)
module.bytes_of_glwe_switching_key_prepared(base2k, k, rank_in, rank_out, dnum, dsize)
}
}
impl<B: Backend, A: GGLWEInfos> PrepareScratchSpace<B, A> for GGLWESwitchingKeyPrepared<Vec<u8>, B>
pub trait GLWESwitchingKeyPrepare<B: Backend>
where
GGLWECiphertextPrepared<Vec<u8>, B>: PrepareScratchSpace<B, A>,
Self: GGLWEPrepare<B>,
{
fn prepare_scratch_space(module: &Module<B>, infos: &A) -> usize {
GGLWECiphertextPrepared::prepare_scratch_space(module, infos)
fn prepare_glwe_switching_key_tmp_bytes<A>(&self, infos: &A) -> usize
where
A: GGLWEInfos,
{
self.prepare_gglwe_tmp_bytes(infos)
}
fn prepare_glwe_switching<R, O>(&self, res: &mut R, other: &O, scratch: &mut Scratch<B>)
where
R: GLWESwitchingKeyPreparedToMut<B> + GLWESwitchingKeySetMetaData,
O: GLWESwitchingKeyToRef + GLWESwtichingKeyGetMetaData,
{
self.prepare_gglwe(&mut res.to_mut().key, &other.to_ref().key, scratch);
res.set_sk_in_n(other.sk_in_n());
res.set_sk_out_n(other.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<B: Backend> GLWESwitchingKeyPrepare<B> for Module<B> where Self: GGLWEPrepare<B> {}
impl<D: DataMut, B: Backend> GLWESwitchingKeyPrepared<D, B> {
pub fn prepare<O, M>(&mut self, module: &M, other: &O, scratch: &mut Scratch<B>)
where
O: GLWESwitchingKeyToRef + GLWESwtichingKeyGetMetaData,
M: GLWESwitchingKeyPrepare<B>,
{
module.prepare_glwe_switching(self, other, scratch);
}
}
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);
atk_prepared.prepare(module, self, scratch);
atk_prepared
impl<B: Backend> GLWESwitchingKeyPrepared<Vec<u8>, B> {
pub fn prepare_tmp_bytes<M>(&self, module: &M) -> usize
where
M: GLWESwitchingKeyPrepare<B>,
{
module.prepare_glwe_switching_key_tmp_bytes(self)
}
}
pub trait GLWESwitchingKeyPreparedToMut<B: Backend> {
fn to_mut(&mut self) -> GLWESwitchingKeyPrepared<&mut [u8], B>;
}
impl<D: DataMut, B: Backend> GLWESwitchingKeyPreparedToMut<B> for GLWESwitchingKeyPrepared<D, B> {
fn to_mut(&mut self) -> GLWESwitchingKeyPrepared<&mut [u8], B> {
GLWESwitchingKeyPrepared {
sk_in_n: self.sk_in_n,
sk_out_n: self.sk_out_n,
key: self.key.to_mut(),
}
}
}
pub trait GLWESwitchingKeyPreparedToRef<B: Backend> {
fn to_ref(&self) -> GLWESwitchingKeyPrepared<&[u8], B>;
}
impl<D: DataRef, B: Backend> GLWESwitchingKeyPreparedToRef<B> for GLWESwitchingKeyPrepared<D, B> {
fn to_ref(&self) -> GLWESwitchingKeyPrepared<&[u8], B> {
GLWESwitchingKeyPrepared {
sk_in_n: self.sk_in_n,
sk_out_n: self.sk_out_n,
key: self.key.to_ref(),
}
}
}

View File

@@ -1,20 +1,20 @@
use poulpy_hal::{
api::{VmpPMatAlloc, VmpPMatAllocBytes, VmpPrepare},
layouts::{Backend, Data, DataMut, DataRef, Module, Scratch},
};
use poulpy_hal::layouts::{Backend, Data, DataMut, DataRef, Module, Scratch};
use crate::layouts::{
Base2K, Degree, Dnum, Dsize, GGLWEInfos, GGLWETensorKey, GLWEInfos, LWEInfos, Rank, TorusPrecision,
prepared::{GGLWESwitchingKeyPrepared, Prepare, PrepareAlloc, PrepareScratchSpace},
Base2K, Dnum, Dsize, GGLWEInfos, GLWEInfos, LWEInfos, Rank, RingDegree, TensorKey, TensorKeyToRef, TorusPrecision,
prepared::{
GLWESwitchingKeyPrepare, GLWESwitchingKeyPrepared, GLWESwitchingKeyPreparedAlloc, GLWESwitchingKeyPreparedToMut,
GLWESwitchingKeyPreparedToRef,
},
};
#[derive(PartialEq, Eq)]
pub struct GGLWETensorKeyPrepared<D: Data, B: Backend> {
pub(crate) keys: Vec<GGLWESwitchingKeyPrepared<D, B>>,
pub struct TensorKeyPrepared<D: Data, B: Backend> {
pub(crate) keys: Vec<GLWESwitchingKeyPrepared<D, B>>,
}
impl<D: Data, B: Backend> LWEInfos for GGLWETensorKeyPrepared<D, B> {
fn n(&self) -> Degree {
impl<D: Data, B: Backend> LWEInfos for TensorKeyPrepared<D, B> {
fn n(&self) -> RingDegree {
self.keys[0].n()
}
@@ -31,13 +31,13 @@ impl<D: Data, B: Backend> LWEInfos for GGLWETensorKeyPrepared<D, B> {
}
}
impl<D: Data, B: Backend> GLWEInfos for GGLWETensorKeyPrepared<D, B> {
impl<D: Data, B: Backend> GLWEInfos for TensorKeyPrepared<D, B> {
fn rank(&self) -> Rank {
self.rank_out()
}
}
impl<D: Data, B: Backend> GGLWEInfos for GGLWETensorKeyPrepared<D, B> {
impl<D: Data, B: Backend> GGLWEInfos for TensorKeyPrepared<D, B> {
fn rank_in(&self) -> Rank {
self.rank_out()
}
@@ -55,19 +55,36 @@ impl<D: Data, B: Backend> GGLWEInfos for GGLWETensorKeyPrepared<D, B> {
}
}
impl<B: Backend> GGLWETensorKeyPrepared<Vec<u8>, B> {
pub fn alloc<A>(module: &Module<B>, infos: &A) -> Self
pub trait TensorKeyPreparedAlloc<B: Backend>
where
Self: GLWESwitchingKeyPreparedAlloc<B>,
{
fn alloc_tensor_key_prepared(
&self,
base2k: Base2K,
k: TorusPrecision,
dnum: Dnum,
dsize: Dsize,
rank: Rank,
) -> TensorKeyPrepared<Vec<u8>, B> {
let pairs: u32 = (((rank.as_u32() + 1) * rank.as_u32()) >> 1).max(1);
TensorKeyPrepared {
keys: (0..pairs)
.map(|_| self.alloc_glwe_switching_key_prepared(base2k, k, Rank(1), rank, dnum, dsize))
.collect(),
}
}
fn alloc_tensor_key_prepared_from_infos<A>(&self, infos: &A) -> TensorKeyPrepared<Vec<u8>, B>
where
A: GGLWEInfos,
Module<B>: VmpPMatAlloc<B>,
{
assert_eq!(
infos.rank_in(),
infos.rank_out(),
"rank_in != rank_out is not supported for GGLWETensorKeyPrepared"
);
Self::alloc_with(
module,
self.alloc_tensor_key_prepared(
infos.base2k(),
infos.k(),
infos.dnum(),
@@ -76,62 +93,62 @@ impl<B: Backend> GGLWETensorKeyPrepared<Vec<u8>, B> {
)
}
pub fn alloc_with(module: &Module<B>, base2k: Base2K, k: TorusPrecision, dnum: Dnum, dsize: Dsize, rank: Rank) -> Self
where
Module<B>: VmpPMatAlloc<B>,
{
let mut keys: Vec<GGLWESwitchingKeyPrepared<Vec<u8>, B>> = Vec::new();
let pairs: u32 = (((rank.0 + 1) * rank.0) >> 1).max(1);
(0..pairs).for_each(|_| {
keys.push(GGLWESwitchingKeyPrepared::alloc_with(
module,
base2k,
k,
Rank(1),
rank,
dnum,
dsize,
));
});
Self { keys }
fn bytes_of_tensor_key_prepared(&self, base2k: Base2K, k: TorusPrecision, rank: Rank, dnum: Dnum, dsize: Dsize) -> usize {
let pairs: usize = (((rank.0 + 1) * rank.0) >> 1).max(1) as usize;
pairs * self.bytes_of_glwe_switching_key_prepared(base2k, k, Rank(1), rank, dnum, dsize)
}
pub fn alloc_bytes<A>(module: &Module<B>, infos: &A) -> usize
fn bytes_of_tensor_key_prepared_from_infos<A>(&self, infos: &A) -> usize
where
A: GGLWEInfos,
Module<B>: VmpPMatAllocBytes,
{
assert_eq!(
infos.rank_in(),
infos.rank_out(),
"rank_in != rank_out is not supported for GGLWETensorKey"
);
let rank_out: usize = infos.rank_out().into();
let pairs: usize = (((rank_out + 1) * rank_out) >> 1).max(1);
pairs
* GGLWESwitchingKeyPrepared::alloc_bytes_with(
module,
infos.base2k(),
infos.k(),
Rank(1),
infos.rank_out(),
infos.dnum(),
infos.dsize(),
)
}
pub fn alloc_bytes_with(module: &Module<B>, base2k: Base2K, k: TorusPrecision, rank: Rank, dnum: Dnum, dsize: Dsize) -> usize
where
Module<B>: VmpPMatAllocBytes,
{
let pairs: usize = (((rank.0 + 1) * rank.0) >> 1).max(1) as usize;
pairs * GGLWESwitchingKeyPrepared::alloc_bytes_with(module, base2k, k, Rank(1), rank, dnum, dsize)
self.bytes_of_tensor_key_prepared(
infos.base2k(),
infos.k(),
infos.rank(),
infos.dnum(),
infos.dsize(),
)
}
}
impl<D: DataMut, B: Backend> GGLWETensorKeyPrepared<D, B> {
impl<B: Backend> TensorKeyPreparedAlloc<B> for Module<B> where Module<B>: GLWESwitchingKeyPreparedAlloc<B> {}
impl<B: Backend> TensorKeyPrepared<Vec<u8>, B> {
pub fn alloc_from_infos<A, M>(module: &M, infos: &A) -> Self
where
A: GGLWEInfos,
M: TensorKeyPreparedAlloc<B>,
{
module.alloc_tensor_key_prepared_from_infos(infos)
}
pub fn alloc_with<M>(module: &M, base2k: Base2K, k: TorusPrecision, dnum: Dnum, dsize: Dsize, rank: Rank) -> Self
where
M: TensorKeyPreparedAlloc<B>,
{
module.alloc_tensor_key_prepared(base2k, k, dnum, dsize, rank)
}
pub fn bytes_of_from_infos<A, M>(module: &M, infos: &A) -> usize
where
A: GGLWEInfos,
M: TensorKeyPreparedAlloc<B>,
{
module.bytes_of_tensor_key_prepared_from_infos(infos)
}
pub fn bytes_of<M>(module: &M, base2k: Base2K, k: TorusPrecision, rank: Rank, dnum: Dnum, dsize: Dsize) -> usize
where
M: TensorKeyPreparedAlloc<B>,
{
module.bytes_of_tensor_key_prepared(base2k, k, rank, dnum, dsize)
}
}
impl<D: DataMut, B: Backend> TensorKeyPrepared<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> {
pub fn at_mut(&mut self, mut i: usize, mut j: usize) -> &mut GLWESwitchingKeyPrepared<D, B> {
if i > j {
std::mem::swap(&mut i, &mut j);
};
@@ -140,9 +157,9 @@ impl<D: DataMut, B: Backend> GGLWETensorKeyPrepared<D, B> {
}
}
impl<D: DataRef, B: Backend> GGLWETensorKeyPrepared<D, B> {
impl<D: DataRef, B: Backend> TensorKeyPrepared<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> {
pub fn at(&self, mut i: usize, mut j: usize) -> &GLWESwitchingKeyPrepared<D, B> {
if i > j {
std::mem::swap(&mut i, &mut j);
};
@@ -151,40 +168,81 @@ impl<D: DataRef, B: Backend> GGLWETensorKeyPrepared<D, B> {
}
}
impl<B: Backend, A: GGLWEInfos> PrepareScratchSpace<B, A> for GGLWETensorKeyPrepared<Vec<u8>, B>
pub trait TensorKeyPrepare<B: Backend>
where
GGLWESwitchingKeyPrepared<Vec<u8>, B>: PrepareScratchSpace<B, A>,
Self: GLWESwitchingKeyPrepare<B>,
{
fn prepare_scratch_space(module: &Module<B>, infos: &A) -> usize {
GGLWESwitchingKeyPrepared::prepare_scratch_space(module, infos)
fn prepare_tensor_key_tmp_bytes<A>(&self, infos: &A) -> usize
where
A: GGLWEInfos,
{
self.prepare_glwe_switching_key_tmp_bytes(infos)
}
}
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());
fn prepare_tensor_key<R, O>(&self, res: &mut R, other: &O, scratch: &mut Scratch<B>)
where
R: TensorKeyPreparedToMut<B>,
O: TensorKeyToRef,
{
let mut res: TensorKeyPrepared<&mut [u8], B> = res.to_mut();
let other: TensorKey<&[u8]> = other.to_ref();
assert_eq!(res.keys.len(), other.keys.len());
for (a, b) in res.keys.iter_mut().zip(other.keys.iter()) {
self.prepare_glwe_switching(a, b, scratch);
}
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);
tsk_prepared.prepare(module, self, scratch);
tsk_prepared
impl<B: Backend> TensorKeyPrepare<B> for Module<B> where Self: GLWESwitchingKeyPrepare<B> {}
impl<B: Backend> TensorKeyPrepared<Vec<u8>, B> {
fn prepare_tmp_bytes<A, M>(&self, module: &M, infos: &A) -> usize
where
A: GGLWEInfos,
M: TensorKeyPrepare<B>,
{
module.prepare_tensor_key_tmp_bytes(infos)
}
}
impl<D: DataMut, B: Backend> TensorKeyPrepared<D, B> {
fn prepare<O, M>(&mut self, module: &M, other: &O, scratch: &mut Scratch<B>)
where
O: TensorKeyToRef,
M: TensorKeyPrepare<B>,
{
module.prepare_tensor_key(self, other, scratch);
}
}
pub trait TensorKeyPreparedToMut<B: Backend> {
fn to_mut(&mut self) -> TensorKeyPrepared<&mut [u8], B>;
}
impl<D: DataMut, B: Backend> TensorKeyPreparedToMut<B> for TensorKeyPrepared<D, B>
where
GLWESwitchingKeyPrepared<D, B>: GLWESwitchingKeyPreparedToMut<B>,
{
fn to_mut(&mut self) -> TensorKeyPrepared<&mut [u8], B> {
TensorKeyPrepared {
keys: self.keys.iter_mut().map(|c| c.to_mut()).collect(),
}
}
}
pub trait TensorKeyPreparedToRef<B: Backend> {
fn to_ref(&self) -> TensorKeyPrepared<&[u8], B>;
}
impl<D: DataRef, B: Backend> TensorKeyPreparedToRef<B> for TensorKeyPrepared<D, B>
where
GLWESwitchingKeyPrepared<D, B>: GLWESwitchingKeyPreparedToRef<B>,
{
fn to_ref(&self) -> TensorKeyPrepared<&[u8], B> {
TensorKeyPrepared {
keys: self.keys.iter().map(|c| c.to_ref()).collect(),
}
}
}

View File

@@ -1,25 +1,23 @@
use poulpy_hal::{
api::{VmpPMatAlloc, VmpPMatAllocBytes, VmpPrepare, VmpPrepareTmpBytes},
layouts::{Backend, Data, DataMut, DataRef, Module, Scratch, VmpPMat, VmpPMatToRef, ZnxInfos},
oep::VmpPMatAllocBytesImpl,
api::{VmpPMatAlloc, VmpPMatBytesOf, VmpPrepare, VmpPrepareTmpBytes},
layouts::{Backend, Data, DataMut, DataRef, Module, Scratch, VmpPMat, VmpPMatToMut, VmpPMatToRef, ZnxInfos},
};
use crate::layouts::{
Base2K, BuildError, Degree, Dnum, Dsize, GGSWCiphertext, GGSWInfos, GLWEInfos, LWEInfos, Rank, TorusPrecision,
prepared::{Prepare, PrepareAlloc, PrepareScratchSpace},
Base2K, Dnum, Dsize, GGSW, GGSWInfos, GGSWToRef, GLWEInfos, GetRingDegree, LWEInfos, Rank, RingDegree, TorusPrecision,
};
#[derive(PartialEq, Eq)]
pub struct GGSWCiphertextPrepared<D: Data, B: Backend> {
pub struct GGSWPrepared<D: Data, B: Backend> {
pub(crate) data: VmpPMat<D, B>,
pub(crate) k: TorusPrecision,
pub(crate) base2k: Base2K,
pub(crate) dsize: Dsize,
}
impl<D: Data, B: Backend> LWEInfos for GGSWCiphertextPrepared<D, B> {
fn n(&self) -> Degree {
Degree(self.data.n() as u32)
impl<D: Data, B: Backend> LWEInfos for GGSWPrepared<D, B> {
fn n(&self) -> RingDegree {
RingDegree(self.data.n() as u32)
}
fn base2k(&self) -> Base2K {
@@ -35,13 +33,13 @@ impl<D: Data, B: Backend> LWEInfos for GGSWCiphertextPrepared<D, B> {
}
}
impl<D: Data, B: Backend> GLWEInfos for GGSWCiphertextPrepared<D, B> {
impl<D: Data, B: Backend> GLWEInfos for GGSWPrepared<D, B> {
fn rank(&self) -> Rank {
Rank(self.data.cols_out() as u32 - 1)
}
}
impl<D: Data, B: Backend> GGSWInfos for GGSWCiphertextPrepared<D, B> {
impl<D: Data, B: Backend> GGSWInfos for GGSWPrepared<D, B> {
fn dsize(&self) -> Dsize {
self.dsize
}
@@ -51,143 +49,18 @@ impl<D: Data, B: Backend> GGSWInfos for GGSWCiphertextPrepared<D, B> {
}
}
pub struct GGSWCiphertextPreparedBuilder<D: Data, B: Backend> {
data: Option<VmpPMat<D, B>>,
base2k: Option<Base2K>,
k: Option<TorusPrecision>,
dsize: Option<Dsize>,
}
impl<D: Data, B: Backend> GGSWCiphertextPrepared<D, B> {
#[inline]
pub fn builder() -> GGSWCiphertextPreparedBuilder<D, B> {
GGSWCiphertextPreparedBuilder {
data: None,
base2k: None,
k: None,
dsize: None,
}
}
}
impl<B: Backend> GGSWCiphertextPreparedBuilder<Vec<u8>, B> {
#[inline]
pub fn layout<A>(mut self, infos: &A) -> Self
where
A: GGSWInfos,
B: VmpPMatAllocBytesImpl<B>,
{
debug_assert!(
infos.size() as u32 > infos.dsize().0,
"invalid ggsw: ceil(k/base2k): {} <= dsize: {}",
infos.size(),
infos.dsize()
);
assert!(
infos.dnum().0 * infos.dsize().0 <= infos.size() as u32,
"invalid ggsw: dnum: {} * dsize:{} > ceil(k/base2k): {}",
infos.dnum(),
infos.dsize(),
infos.size(),
);
self.data = Some(VmpPMat::alloc(
infos.n().into(),
infos.dnum().into(),
(infos.rank() + 1).into(),
(infos.rank() + 1).into(),
infos.size(),
));
self.base2k = Some(infos.base2k());
self.k = Some(infos.k());
self.dsize = Some(infos.dsize());
self
}
}
impl<D: Data, B: Backend> GGSWCiphertextPreparedBuilder<D, B> {
#[inline]
pub fn data(mut self, data: VmpPMat<D, B>) -> Self {
self.data = Some(data);
self
}
#[inline]
pub fn base2k(mut self, base2k: Base2K) -> Self {
self.base2k = Some(base2k);
self
}
#[inline]
pub fn k(mut self, k: TorusPrecision) -> Self {
self.k = Some(k);
self
}
#[inline]
pub fn dsize(mut self, dsize: Dsize) -> Self {
self.dsize = Some(dsize);
self
}
pub fn build(self) -> Result<GGSWCiphertextPrepared<D, B>, BuildError> {
let data: VmpPMat<D, B> = self.data.ok_or(BuildError::MissingData)?;
let base2k: Base2K = self.base2k.ok_or(BuildError::MissingBase2K)?;
let k: TorusPrecision = self.k.ok_or(BuildError::MissingK)?;
let dsize: Dsize = self.dsize.ok_or(BuildError::MissingDigits)?;
if base2k == 0_u32 {
return Err(BuildError::ZeroBase2K);
}
if dsize == 0_u32 {
return Err(BuildError::ZeroBase2K);
}
if k == 0_u32 {
return Err(BuildError::ZeroTorusPrecision);
}
if data.n() == 0 {
return Err(BuildError::ZeroDegree);
}
if data.cols() == 0 {
return Err(BuildError::ZeroCols);
}
if data.size() == 0 {
return Err(BuildError::ZeroLimbs);
}
Ok(GGSWCiphertextPrepared {
data,
base2k,
k,
dsize,
})
}
}
impl<B: Backend> GGSWCiphertextPrepared<Vec<u8>, B> {
pub fn alloc<A>(module: &Module<B>, infos: &A) -> Self
where
A: GGSWInfos,
Module<B>: VmpPMatAlloc<B>,
{
Self::alloc_with(
module,
infos.base2k(),
infos.k(),
infos.dnum(),
infos.dsize(),
infos.rank(),
)
}
pub fn alloc_with(module: &Module<B>, base2k: Base2K, k: TorusPrecision, dnum: Dnum, dsize: Dsize, rank: Rank) -> Self
where
Module<B>: VmpPMatAlloc<B>,
{
pub trait GGSWPreparedAlloc<B: Backend>
where
Self: GetRingDegree + VmpPMatAlloc<B> + VmpPMatBytesOf,
{
fn alloc_ggsw_prepared(
&self,
base2k: Base2K,
k: TorusPrecision,
dnum: Dnum,
dsize: Dsize,
rank: Rank,
) -> GGSWPrepared<Vec<u8>, B> {
let size: usize = k.0.div_ceil(base2k.0) as usize;
debug_assert!(
size as u32 > dsize.0,
@@ -202,8 +75,8 @@ impl<B: Backend> GGSWCiphertextPrepared<Vec<u8>, B> {
dsize.0,
);
Self {
data: module.vmp_pmat_alloc(
GGSWPrepared {
data: self.vmp_pmat_alloc(
dnum.into(),
(rank + 1).into(),
(rank + 1).into(),
@@ -215,13 +88,12 @@ impl<B: Backend> GGSWCiphertextPrepared<Vec<u8>, B> {
}
}
pub fn alloc_bytes<A>(module: &Module<B>, infos: &A) -> usize
fn alloc_ggsw_prepared_from_infos<A>(&self, infos: &A) -> GGSWPrepared<Vec<u8>, B>
where
A: GGSWInfos,
Module<B>: VmpPMatAllocBytes,
{
Self::alloc_bytes_with(
module,
assert_eq!(self.ring_degree(), infos.n());
self.alloc_ggsw_prepared(
infos.base2k(),
infos.k(),
infos.dnum(),
@@ -230,10 +102,7 @@ impl<B: Backend> GGSWCiphertextPrepared<Vec<u8>, B> {
)
}
pub fn alloc_bytes_with(module: &Module<B>, base2k: Base2K, k: TorusPrecision, dnum: Dnum, dsize: Dsize, rank: Rank) -> usize
where
Module<B>: VmpPMatAllocBytes,
{
fn bytes_of_ggsw_prepared(&self, base2k: Base2K, k: TorusPrecision, dnum: Dnum, dsize: Dsize, rank: Rank) -> usize {
let size: usize = k.0.div_ceil(base2k.0) as usize;
debug_assert!(
size as u32 > dsize.0,
@@ -248,65 +117,144 @@ impl<B: Backend> GGSWCiphertextPrepared<Vec<u8>, B> {
dsize.0,
);
module.vmp_pmat_alloc_bytes(dnum.into(), (rank + 1).into(), (rank + 1).into(), size)
self.bytes_of_vmp_pmat(dnum.into(), (rank + 1).into(), (rank + 1).into(), size)
}
fn bytes_of_ggsw_prepared_from_infos<A>(&self, infos: &A) -> usize
where
A: GGSWInfos,
{
assert_eq!(self.ring_degree(), infos.n());
self.bytes_of_ggsw_prepared(
infos.base2k(),
infos.k(),
infos.dnum(),
infos.dsize(),
infos.rank(),
)
}
}
impl<D: DataRef, B: Backend> GGSWCiphertextPrepared<D, B> {
impl<B: Backend> GGSWPreparedAlloc<B> for Module<B> where Self: GetRingDegree + VmpPMatAlloc<B> + VmpPMatBytesOf {}
impl<B: Backend> GGSWPrepared<Vec<u8>, B> {
pub fn alloc_from_infos<A, M>(module: &M, infos: &A) -> Self
where
A: GGSWInfos,
M: GGSWPreparedAlloc<B>,
{
module.alloc_ggsw_prepared_from_infos(infos)
}
pub fn alloc<M>(module: &M, base2k: Base2K, k: TorusPrecision, dnum: Dnum, dsize: Dsize, rank: Rank) -> Self
where
M: GGSWPreparedAlloc<B>,
{
module.alloc_ggsw_prepared(base2k, k, dnum, dsize, rank)
}
pub fn bytes_of_from_infos<A, M>(module: &M, infos: &A) -> usize
where
A: GGSWInfos,
M: GGSWPreparedAlloc<B>,
{
module.bytes_of_ggsw_prepared_from_infos(infos)
}
pub fn bytes_of<M>(module: &M, base2k: Base2K, k: TorusPrecision, dnum: Dnum, dsize: Dsize, rank: Rank) -> usize
where
M: GGSWPreparedAlloc<B>,
{
module.bytes_of_ggsw_prepared(base2k, k, dnum, dsize, rank)
}
}
impl<D: DataRef, B: Backend> GGSWPrepared<D, B> {
pub fn data(&self) -> &VmpPMat<D, B> {
&self.data
}
}
impl<B: Backend, A: GGSWInfos> PrepareScratchSpace<B, A> for GGSWCiphertextPrepared<Vec<u8>, B>
pub trait GGSWPrepare<B: Backend>
where
Module<B>: VmpPrepareTmpBytes,
Self: GetRingDegree + VmpPrepareTmpBytes + VmpPrepare<B>,
{
fn prepare_scratch_space(module: &Module<B>, infos: &A) -> usize {
module.vmp_prepare_tmp_bytes(
fn ggsw_prepare_tmp_bytes<A>(&self, infos: &A) -> usize
where
A: GGSWInfos,
{
assert_eq!(self.ring_degree(), infos.n());
self.vmp_prepare_tmp_bytes(
infos.dnum().into(),
(infos.rank() + 1).into(),
(infos.rank() + 1).into(),
infos.size(),
)
}
}
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.base2k = other.base2k;
self.dsize = other.dsize;
fn ggsw_prepare<R, O>(&self, res: &mut R, other: &O, scratch: &mut Scratch<B>)
where
R: GGSWPreparedToMut<B>,
O: GGSWToRef,
{
let mut res: GGSWPrepared<&mut [u8], B> = res.to_mut();
let other: GGSW<&[u8]> = other.to_ref();
assert_eq!(res.n(), self.ring_degree());
assert_eq!(other.n(), self.ring_degree());
assert_eq!(res.k, other.k);
assert_eq!(res.base2k, other.base2k);
assert_eq!(res.dsize, other.dsize);
self.vmp_prepare(&mut res.data, &other.data, scratch);
}
}
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);
ggsw_prepared.prepare(module, self, scratch);
ggsw_prepared
impl<B: Backend> GGSWPrepare<B> for Module<B> where Self: GetRingDegree + VmpPrepareTmpBytes + VmpPrepare<B> {}
impl<B: Backend> GGSWPrepared<Vec<u8>, B> {
pub fn prepare_tmp_bytes<A, M>(&self, module: &M, infos: &A) -> usize
where
A: GGSWInfos,
M: GGSWPrepare<B>,
{
module.ggsw_prepare_tmp_bytes(infos)
}
}
pub trait GGSWCiphertextPreparedToRef<B: Backend> {
fn to_ref(&self) -> GGSWCiphertextPrepared<&[u8], B>;
}
impl<D: DataRef, B: Backend> GGSWCiphertextPreparedToRef<B> for GGSWCiphertextPrepared<D, B> {
fn to_ref(&self) -> GGSWCiphertextPrepared<&[u8], B> {
GGSWCiphertextPrepared::builder()
.base2k(self.base2k())
.dsize(self.dsize())
.k(self.k())
.data(self.data.to_ref())
.build()
.unwrap()
impl<D: DataMut, B: Backend> GGSWPrepared<D, B> {
pub fn prepare<O, M>(&mut self, module: &M, other: &O, scratch: &mut Scratch<B>)
where
O: GGSWToRef,
M: GGSWPrepare<B>,
{
module.ggsw_prepare(self, other, scratch);
}
}
pub trait GGSWPreparedToMut<B: Backend> {
fn to_mut(&mut self) -> GGSWPrepared<&mut [u8], B>;
}
impl<D: DataMut, B: Backend> GGSWPreparedToMut<B> for GGSWPrepared<D, B> {
fn to_mut(&mut self) -> GGSWPrepared<&mut [u8], B> {
GGSWPrepared {
base2k: self.base2k,
k: self.k,
dsize: self.dsize,
data: self.data.to_mut(),
}
}
}
pub trait GGSWPreparedToRef<B: Backend> {
fn to_ref(&self) -> GGSWPrepared<&[u8], B>;
}
impl<D: DataRef, B: Backend> GGSWPreparedToRef<B> for GGSWPrepared<D, B> {
fn to_ref(&self) -> GGSWPrepared<&[u8], B> {
GGSWPrepared {
base2k: self.base2k,
k: self.k,
dsize: self.dsize,
data: self.data.to_ref(),
}
}
}

View File

@@ -1,14 +1,12 @@
use poulpy_hal::{
api::{VecZnxDftAlloc, VecZnxDftAllocBytes, VecZnxDftApply},
layouts::{Backend, Data, DataMut, DataRef, Module, Scratch, VecZnxDft, ZnxInfos},
oep::VecZnxDftAllocBytesImpl,
api::{VecZnxDftAlloc, VecZnxDftApply, VecZnxDftBytesOf},
layouts::{Backend, Data, DataMut, DataRef, Module, VecZnxDft, VecZnxDftToMut, VecZnxDftToRef, ZnxInfos},
};
use crate::{
dist::Distribution,
layouts::{
Base2K, BuildError, Degree, GLWEInfos, GLWEPublicKey, LWEInfos, Rank, TorusPrecision,
prepared::{Prepare, PrepareAlloc, PrepareScratchSpace},
Base2K, GLWEInfos, GLWEPublicKey, GLWEPublicKeyToRef, GetDist, GetRingDegree, LWEInfos, Rank, RingDegree, TorusPrecision,
},
};
@@ -20,6 +18,16 @@ pub struct GLWEPublicKeyPrepared<D: Data, B: Backend> {
pub(crate) dist: Distribution,
}
pub(crate) trait SetDist {
fn set_dist(&mut self, dist: Distribution);
}
impl<D: Data, B: Backend> SetDist for GLWEPublicKeyPrepared<D, B> {
fn set_dist(&mut self, dist: Distribution) {
self.dist = dist
}
}
impl<D: Data, B: Backend> LWEInfos for GLWEPublicKeyPrepared<D, B> {
fn base2k(&self) -> Base2K {
self.base2k
@@ -33,8 +41,8 @@ impl<D: Data, B: Backend> LWEInfos for GLWEPublicKeyPrepared<D, B> {
self.data.size()
}
fn n(&self) -> Degree {
Degree(self.data.n() as u32)
fn n(&self) -> RingDegree {
RingDegree(self.data.n() as u32)
}
}
@@ -44,164 +52,138 @@ impl<D: Data, B: Backend> GLWEInfos for GLWEPublicKeyPrepared<D, B> {
}
}
pub struct GLWEPublicKeyPreparedBuilder<D: Data, B: Backend> {
data: Option<VecZnxDft<D, B>>,
base2k: Option<Base2K>,
k: Option<TorusPrecision>,
}
impl<D: Data, B: Backend> GLWEPublicKeyPrepared<D, B> {
#[inline]
pub fn builder() -> GLWEPublicKeyPreparedBuilder<D, B> {
GLWEPublicKeyPreparedBuilder {
data: None,
base2k: None,
k: None,
}
}
}
impl<B: Backend> GLWEPublicKeyPreparedBuilder<Vec<u8>, B> {
#[inline]
pub fn layout<A>(mut self, layout: &A) -> Self
where
A: GLWEInfos,
B: VecZnxDftAllocBytesImpl<B>,
{
self.data = Some(VecZnxDft::alloc(
layout.n().into(),
(layout.rank() + 1).into(),
layout.size(),
));
self.base2k = Some(layout.base2k());
self.k = Some(layout.k());
self
}
}
impl<D: Data, B: Backend> GLWEPublicKeyPreparedBuilder<D, B> {
#[inline]
pub fn data(mut self, data: VecZnxDft<D, B>) -> Self {
self.data = Some(data);
self
}
#[inline]
pub fn base2k(mut self, base2k: Base2K) -> Self {
self.base2k = Some(base2k);
self
}
#[inline]
pub fn k(mut self, k: TorusPrecision) -> Self {
self.k = Some(k);
self
}
pub fn build(self) -> Result<GLWEPublicKeyPrepared<D, B>, BuildError> {
let data: VecZnxDft<D, B> = self.data.ok_or(BuildError::MissingData)?;
let base2k: Base2K = self.base2k.ok_or(BuildError::MissingBase2K)?;
let k: TorusPrecision = self.k.ok_or(BuildError::MissingK)?;
if base2k == 0_u32 {
return Err(BuildError::ZeroBase2K);
}
if k == 0_u32 {
return Err(BuildError::ZeroTorusPrecision);
}
if data.n() == 0 {
return Err(BuildError::ZeroDegree);
}
if data.cols() == 0 {
return Err(BuildError::ZeroCols);
}
if data.size() == 0 {
return Err(BuildError::ZeroLimbs);
}
Ok(GLWEPublicKeyPrepared {
data,
pub trait GLWEPublicKeyPreparedAlloc<B: Backend>
where
Self: GetRingDegree + VecZnxDftAlloc<B> + VecZnxDftBytesOf,
{
fn alloc_glwe_public_key_prepared(&self, base2k: Base2K, k: TorusPrecision, rank: Rank) -> GLWEPublicKeyPrepared<Vec<u8>, B> {
GLWEPublicKeyPrepared {
data: self.vec_znx_dft_alloc((rank + 1).into(), k.0.div_ceil(base2k.0) as usize),
base2k,
k,
dist: Distribution::NONE,
})
}
}
fn alloc_glwe_public_key_prepared_from_infos<A>(&self, infos: &A) -> GLWEPublicKeyPrepared<Vec<u8>, B>
where
A: GLWEInfos,
{
self.alloc_glwe_public_key_prepared(infos.base2k(), infos.k(), infos.rank())
}
fn bytes_of_glwe_public_key_prepared(&self, base2k: Base2K, k: TorusPrecision, rank: Rank) -> usize {
self.bytes_of_vec_znx_dft((rank + 1).into(), k.0.div_ceil(base2k.0) as usize)
}
fn bytes_of_glwe_public_key_prepared_from_infos<A>(&self, infos: &A) -> usize
where
A: GLWEInfos,
{
self.bytes_of_glwe_public_key_prepared(infos.base2k(), infos.k(), infos.rank())
}
}
impl<B: Backend> GLWEPublicKeyPreparedAlloc<B> for Module<B> where Self: VecZnxDftAlloc<B> + VecZnxDftBytesOf {}
impl<B: Backend> GLWEPublicKeyPrepared<Vec<u8>, B> {
pub fn alloc<A>(module: &Module<B>, infos: &A) -> Self
pub fn alloc_from_infos<A, M>(module: &M, infos: &A) -> Self
where
A: GLWEInfos,
Module<B>: VecZnxDftAlloc<B>,
M: GLWEPublicKeyPreparedAlloc<B>,
{
debug_assert_eq!(module.n(), infos.n().0 as usize, "module.n() != infos.n()");
Self::alloc_with(module, infos.base2k(), infos.k(), infos.rank())
module.alloc_glwe_public_key_prepared_from_infos(infos)
}
pub fn alloc_with(module: &Module<B>, base2k: Base2K, k: TorusPrecision, rank: Rank) -> Self
pub fn alloc<M>(module: &M, base2k: Base2K, k: TorusPrecision, rank: Rank) -> Self
where
Module<B>: VecZnxDftAlloc<B>,
M: GLWEPublicKeyPreparedAlloc<B>,
{
Self {
data: module.vec_znx_dft_alloc((rank + 1).into(), k.0.div_ceil(base2k.0) as usize),
base2k,
k,
dist: Distribution::NONE,
}
module.alloc_glwe_public_key_prepared(base2k, k, rank)
}
pub fn alloc_bytes<A>(module: &Module<B>, infos: &A) -> usize
pub fn bytes_of_from_infos<A, M>(module: &M, infos: &A) -> usize
where
A: GLWEInfos,
Module<B>: VecZnxDftAllocBytes,
M: GLWEPublicKeyPreparedAlloc<B>,
{
debug_assert_eq!(module.n(), infos.n().0 as usize, "module.n() != infos.n()");
Self::alloc_bytes_with(module, infos.base2k(), infos.k(), infos.rank())
module.bytes_of_glwe_public_key_prepared_from_infos(infos)
}
pub fn alloc_bytes_with(module: &Module<B>, base2k: Base2K, k: TorusPrecision, rank: Rank) -> usize
pub fn bytes_of<M>(module: &M, base2k: Base2K, k: TorusPrecision, rank: Rank) -> usize
where
Module<B>: VecZnxDftAllocBytes,
M: GLWEPublicKeyPreparedAlloc<B>,
{
module.vec_znx_dft_alloc_bytes((rank + 1).into(), k.0.div_ceil(base2k.0) as usize)
module.bytes_of_glwe_public_key_prepared(base2k, k, rank)
}
}
impl<D: DataRef, B: Backend> PrepareAlloc<B, GLWEPublicKeyPrepared<Vec<u8>, B>> for GLWEPublicKey<D>
pub trait GLWEPublicKeyPrepare<B: Backend>
where
Module<B>: VecZnxDftAlloc<B> + VecZnxDftApply<B>,
Self: GetRingDegree + VecZnxDftApply<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);
pk_prepared.prepare(module, self, scratch);
pk_prepared
}
}
impl<B: Backend, A: GLWEInfos> PrepareScratchSpace<B, A> for GLWEPublicKeyPrepared<Vec<u8>, B> {
fn prepare_scratch_space(_module: &Module<B>, _infos: &A) -> usize {
0
}
}
impl<DM: DataMut, DR: DataRef, B: Backend> Prepare<B, GLWEPublicKey<DR>> for GLWEPublicKeyPrepared<DM, B>
where
Module<B>: VecZnxDftApply<B>,
{
fn prepare(&mut self, module: &Module<B>, other: &GLWEPublicKey<DR>, _scratch: &mut Scratch<B>) {
#[cfg(debug_assertions)]
fn prepare_glwe_public_key<R, O>(&self, res: &mut R, other: &O)
where
R: GLWEPublicKeyPreparedToMut<B> + SetDist,
O: GLWEPublicKeyToRef + GetDist,
{
{
assert_eq!(self.n(), other.n());
assert_eq!(self.size(), other.size());
let mut res: GLWEPublicKeyPrepared<&mut [u8], B> = res.to_mut();
let other: GLWEPublicKey<&[u8]> = other.to_ref();
assert_eq!(res.n(), self.ring_degree());
assert_eq!(other.n(), self.ring_degree());
assert_eq!(res.size(), other.size());
assert_eq!(res.k(), other.k());
assert_eq!(res.base2k(), other.base2k());
for i in 0..(res.rank() + 1).into() {
self.vec_znx_dft_apply(1, 0, &mut res.data, i, &other.data, i);
}
}
(0..(self.rank() + 1).into()).for_each(|i| {
module.vec_znx_dft_apply(1, 0, &mut self.data, i, &other.data, i);
});
self.k = other.k();
self.base2k = other.base2k();
self.dist = other.dist;
res.set_dist(other.get_dist());
}
}
impl<B: Backend> GLWEPublicKeyPrepare<B> for Module<B> where Self: GetRingDegree + VecZnxDftApply<B> {}
impl<D: DataMut, B: Backend> GLWEPublicKeyPrepared<D, B> {
pub fn prepare<O, M>(&mut self, module: &M, other: &O)
where
O: GLWEPublicKeyToRef + GetDist,
M: GLWEPublicKeyPrepare<B>,
{
module.prepare_glwe_public_key(self, other);
}
}
pub trait GLWEPublicKeyPreparedToMut<B: Backend> {
fn to_mut(&mut self) -> GLWEPublicKeyPrepared<&mut [u8], B>;
}
impl<D: DataMut, B: Backend> GLWEPublicKeyPreparedToMut<B> for GLWEPublicKeyPrepared<D, B> {
fn to_mut(&mut self) -> GLWEPublicKeyPrepared<&mut [u8], B> {
GLWEPublicKeyPrepared {
dist: self.dist,
k: self.k,
base2k: self.base2k,
data: self.data.to_mut(),
}
}
}
pub trait GLWEPublicKeyPreparedToRef<B: Backend> {
fn to_ref(&self) -> GLWEPublicKeyPrepared<&[u8], B>;
}
impl<D: DataRef, B: Backend> GLWEPublicKeyPreparedToRef<B> for GLWEPublicKeyPrepared<D, B> {
fn to_ref(&self) -> GLWEPublicKeyPrepared<&[u8], B> {
GLWEPublicKeyPrepared {
data: self.data.to_ref(),
dist: self.dist,
k: self.k,
base2k: self.base2k,
}
}
}

View File

@@ -1,13 +1,13 @@
use poulpy_hal::{
api::{SvpPPolAlloc, SvpPPolAllocBytes, SvpPrepare},
layouts::{Backend, Data, DataMut, DataRef, Module, Scratch, SvpPPol, ZnxInfos},
api::{SvpPPolAlloc, SvpPPolBytesOf, SvpPrepare},
layouts::{Backend, Data, DataMut, DataRef, Module, SvpPPol, SvpPPolToMut, SvpPPolToRef, ZnxInfos},
};
use crate::{
dist::Distribution,
layouts::{
Base2K, Degree, GLWEInfos, GLWESecret, LWEInfos, Rank, TorusPrecision,
prepared::{Prepare, PrepareAlloc, PrepareScratchSpace},
Base2K, GLWEInfos, GLWESecret, GLWESecretToRef, GetDist, GetRingDegree, LWEInfos, Rank, RingDegree, TorusPrecision,
prepared::SetDist,
},
};
@@ -16,6 +16,12 @@ pub struct GLWESecretPrepared<D: Data, B: Backend> {
pub(crate) dist: Distribution,
}
impl<D: DataRef, B: Backend> SetDist for GLWESecretPrepared<D, B> {
fn set_dist(&mut self, dist: Distribution) {
self.dist = dist
}
}
impl<D: Data, B: Backend> LWEInfos for GLWESecretPrepared<D, B> {
fn base2k(&self) -> Base2K {
Base2K(0)
@@ -25,8 +31,8 @@ impl<D: Data, B: Backend> LWEInfos for GLWESecretPrepared<D, B> {
TorusPrecision(0)
}
fn n(&self) -> Degree {
Degree(self.data.n() as u32)
fn n(&self) -> RingDegree {
RingDegree(self.data.n() as u32)
}
fn size(&self) -> usize {
@@ -38,46 +44,74 @@ impl<D: Data, B: Backend> GLWEInfos for GLWESecretPrepared<D, B> {
Rank(self.data.cols() as u32)
}
}
impl<B: Backend> GLWESecretPrepared<Vec<u8>, B> {
pub fn alloc<A>(module: &Module<B>, infos: &A) -> Self
where
A: GLWEInfos,
Module<B>: SvpPPolAlloc<B>,
{
assert_eq!(module.n() as u32, infos.n());
Self::alloc_with(module, infos.rank())
}
pub fn alloc_with(module: &Module<B>, rank: Rank) -> Self
where
Module<B>: SvpPPolAlloc<B>,
{
Self {
data: module.svp_ppol_alloc(rank.into()),
pub trait GLWESecretPreparedAlloc<B: Backend>
where
Self: GetRingDegree + SvpPPolBytesOf + SvpPPolAlloc<B>,
{
fn alloc_glwe_secret_prepared(&self, rank: Rank) -> GLWESecretPrepared<Vec<u8>, B> {
GLWESecretPrepared {
data: self.svp_ppol_alloc(rank.into()),
dist: Distribution::NONE,
}
}
pub fn alloc_bytes<A>(module: &Module<B>, infos: &A) -> usize
fn alloc_glwe_secret_prepared_from_infos<A>(&self, infos: &A) -> GLWESecretPrepared<Vec<u8>, B>
where
A: GLWEInfos,
Module<B>: SvpPPolAllocBytes,
{
assert_eq!(module.n() as u32, infos.n());
Self::alloc_bytes_with(module, infos.rank())
assert_eq!(self.ring_degree(), infos.n());
self.alloc_glwe_secret_prepared(infos.rank())
}
pub fn alloc_bytes_with(module: &Module<B>, rank: Rank) -> usize
fn bytes_of_glwe_secret(&self, rank: Rank) -> usize {
self.bytes_of_svp_ppol(rank.into())
}
fn bytes_of_glwe_secret_from_infos<A>(&self, infos: &A) -> usize
where
Module<B>: SvpPPolAllocBytes,
A: GLWEInfos,
{
module.svp_ppol_alloc_bytes(rank.into())
assert_eq!(self.ring_degree(), infos.n());
self.bytes_of_glwe_secret(infos.rank())
}
}
impl<B: Backend> GLWESecretPreparedAlloc<B> for Module<B> where Self: GetRingDegree + SvpPPolBytesOf + SvpPPolAlloc<B> {}
impl<B: Backend> GLWESecretPrepared<Vec<u8>, B> {
pub fn alloc_from_infos<A, M>(module: &M, infos: &A) -> Self
where
A: GLWEInfos,
M: GLWESecretPreparedAlloc<B>,
{
module.alloc_glwe_secret_prepared_from_infos(infos)
}
pub fn alloc<M>(module: &M, rank: Rank) -> Self
where
M: GLWESecretPreparedAlloc<B>,
{
module.alloc_glwe_secret_prepared(rank)
}
pub fn bytes_of_from_infos<A, M>(module: &M, infos: &A) -> usize
where
A: GLWEInfos,
M: GLWESecretPreparedAlloc<B>,
{
module.bytes_of_glwe_secret_from_infos(infos)
}
pub fn bytes_of<M>(module: &M, rank: Rank) -> usize
where
M: GLWESecretPreparedAlloc<B>,
{
module.bytes_of_glwe_secret(rank)
}
}
impl<D: Data, B: Backend> GLWESecretPrepared<D, B> {
pub fn n(&self) -> Degree {
Degree(self.data.n() as u32)
pub fn n(&self) -> RingDegree {
RingDegree(self.data.n() as u32)
}
pub fn rank(&self) -> Rank {
@@ -85,31 +119,62 @@ impl<D: Data, B: Backend> GLWESecretPrepared<D, B> {
}
}
impl<B: Backend, A: GLWEInfos> PrepareScratchSpace<B, A> for GLWESecretPrepared<Vec<u8>, B> {
fn prepare_scratch_space(_module: &Module<B>, _infos: &A) -> usize {
0
pub trait GLWESecretPrepare<B: Backend>
where
Self: SvpPrepare<B>,
{
fn prepare_glwe_secret<R, O>(&self, res: &mut R, other: &O)
where
R: GLWESecretPreparedToMut<B> + SetDist,
O: GLWESecretToRef + GetDist,
{
{
let mut res: GLWESecretPrepared<&mut [u8], _> = res.to_mut();
let other: GLWESecret<&[u8]> = other.to_ref();
for i in 0..res.rank().into() {
self.svp_prepare(&mut res.data, i, &other.data, i);
}
}
res.set_dist(other.get_dist());
}
}
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 Scratch<B>) -> GLWESecretPrepared<Vec<u8>, B> {
let mut sk_dft: GLWESecretPrepared<Vec<u8>, B> = GLWESecretPrepared::alloc(module, self);
sk_dft.prepare(module, self, _scratch);
sk_dft
impl<B: Backend> GLWESecretPrepare<B> for Module<B> where Self: SvpPrepare<B> {}
impl<D: DataMut, B: Backend> GLWESecretPrepared<D, B> {
pub fn prepare<M, O>(&mut self, module: &M, other: &O)
where
M: GLWESecretPrepare<B>,
O: GLWESecretToRef + GetDist,
{
module.prepare_glwe_secret(self, other);
}
}
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 Scratch<B>) {
(0..self.rank().into()).for_each(|i| {
module.svp_prepare(&mut self.data, i, &other.data, i);
});
self.dist = other.dist
pub trait GLWESecretPreparedToRef<B: Backend> {
fn to_ref(&self) -> GLWESecretPrepared<&[u8], B>;
}
impl<D: DataRef, B: Backend> GLWESecretPreparedToRef<B> for GLWESecretPrepared<D, B> {
fn to_ref(&self) -> GLWESecretPrepared<&[u8], B> {
GLWESecretPrepared {
data: self.data.to_ref(),
dist: self.dist,
}
}
}
pub trait GLWESecretPreparedToMut<B: Backend> {
fn to_mut(&mut self) -> GLWESecretPrepared<&mut [u8], B>;
}
impl<D: DataMut, B: Backend> GLWESecretPreparedToMut<B> for GLWESecretPrepared<D, B> {
fn to_mut(&mut self) -> GLWESecretPrepared<&mut [u8], B> {
GLWESecretPrepared {
dist: self.dist,
data: self.data.to_mut(),
}
}
}

View File

@@ -1,15 +1,15 @@
use poulpy_hal::{
api::{VmpPMatAlloc, VmpPMatAllocBytes, VmpPrepare},
layouts::{Backend, Data, DataMut, DataRef, Module, Scratch},
};
use poulpy_hal::layouts::{Backend, Data, DataMut, DataRef, Module, Scratch};
use crate::layouts::{
Base2K, Degree, Dnum, Dsize, GGLWEInfos, GLWEInfos, GLWEToLWEKey, LWEInfos, Rank, TorusPrecision,
prepared::{GGLWESwitchingKeyPrepared, Prepare, PrepareAlloc, PrepareScratchSpace},
Base2K, Dnum, Dsize, GGLWEInfos, GLWEInfos, GLWEToLWESwitchingKeyToRef, LWEInfos, Rank, RingDegree, TorusPrecision,
prepared::{
GLWESwitchingKeyPrepare, GLWESwitchingKeyPrepared, GLWESwitchingKeyPreparedAlloc, GLWESwitchingKeyPreparedToMut,
GLWESwitchingKeyPreparedToRef,
},
};
#[derive(PartialEq, Eq)]
pub struct GLWEToLWESwitchingKeyPrepared<D: Data, B: Backend>(pub(crate) GGLWESwitchingKeyPrepared<D, B>);
pub struct GLWEToLWESwitchingKeyPrepared<D: Data, B: Backend>(pub(crate) GLWESwitchingKeyPrepared<D, B>);
impl<D: Data, B: Backend> LWEInfos for GLWEToLWESwitchingKeyPrepared<D, B> {
fn base2k(&self) -> Base2K {
@@ -20,7 +20,7 @@ impl<D: Data, B: Backend> LWEInfos for GLWEToLWESwitchingKeyPrepared<D, B> {
self.0.k()
}
fn n(&self) -> Degree {
fn n(&self) -> RingDegree {
self.0.n()
}
@@ -53,91 +53,156 @@ impl<D: Data, B: Backend> GGLWEInfos for GLWEToLWESwitchingKeyPrepared<D, B> {
}
}
pub trait GLWEToLWESwitchingKeyPreparedAlloc<B: Backend>
where
Self: GLWESwitchingKeyPreparedAlloc<B>,
{
fn alloc_glwe_to_lwe_switching_key_prepared(
&self,
base2k: Base2K,
k: TorusPrecision,
rank_in: Rank,
dnum: Dnum,
) -> GLWEToLWESwitchingKeyPrepared<Vec<u8>, B> {
GLWEToLWESwitchingKeyPrepared(self.alloc_glwe_switching_key_prepared(base2k, k, rank_in, Rank(1), dnum, Dsize(1)))
}
fn alloc_glwe_to_lwe_switching_key_prepared_from_infos<A>(&self, infos: &A) -> GLWEToLWESwitchingKeyPrepared<Vec<u8>, B>
where
A: GGLWEInfos,
{
debug_assert_eq!(
infos.rank_out().0,
1,
"rank_out > 1 is not supported for GLWEToLWESwitchingKeyPrepared"
);
debug_assert_eq!(
infos.dsize().0,
1,
"dsize > 1 is not supported for GLWEToLWESwitchingKeyPrepared"
);
self.alloc_glwe_to_lwe_switching_key_prepared(infos.base2k(), infos.k(), infos.rank_in(), infos.dnum())
}
fn bytes_of_glwe_to_lwe_switching_key_prepared(&self, base2k: Base2K, k: TorusPrecision, rank_in: Rank, dnum: Dnum) -> usize {
self.bytes_of_glwe_switching_key_prepared(base2k, k, rank_in, Rank(1), dnum, Dsize(1))
}
fn bytes_of_glwe_to_lwe_switching_key_prepared_from_infos<A>(&self, infos: &A) -> usize
where
A: GGLWEInfos,
{
debug_assert_eq!(
infos.rank_out().0,
1,
"rank_out > 1 is not supported for GLWEToLWESwitchingKeyPrepared"
);
debug_assert_eq!(
infos.dsize().0,
1,
"dsize > 1 is not supported for GLWEToLWESwitchingKeyPrepared"
);
self.bytes_of_glwe_to_lwe_switching_key_prepared(infos.base2k(), infos.k(), infos.rank_in(), infos.dnum())
}
}
impl<B: Backend> GLWEToLWESwitchingKeyPreparedAlloc<B> for Module<B> where Self: GLWESwitchingKeyPreparedAlloc<B> {}
impl<B: Backend> GLWEToLWESwitchingKeyPrepared<Vec<u8>, B> {
pub fn alloc<A>(module: &Module<B>, infos: &A) -> Self
pub fn alloc_from_infos<A, M>(module: &M, infos: &A) -> Self
where
A: GGLWEInfos,
Module<B>: VmpPMatAlloc<B>,
M: GLWEToLWESwitchingKeyPreparedAlloc<B>,
{
debug_assert_eq!(
infos.rank_out().0,
1,
"rank_out > 1 is not supported for GLWEToLWESwitchingKeyPrepared"
);
debug_assert_eq!(
infos.dsize().0,
1,
"dsize > 1 is not supported for GLWEToLWESwitchingKeyPrepared"
);
Self(GGLWESwitchingKeyPrepared::alloc(module, infos))
module.alloc_glwe_to_lwe_switching_key_prepared_from_infos(infos)
}
pub fn alloc_with(module: &Module<B>, base2k: Base2K, k: TorusPrecision, rank_in: Rank, dnum: Dnum) -> Self
pub fn alloc<M>(module: &M, base2k: Base2K, k: TorusPrecision, rank_in: Rank, dnum: Dnum) -> Self
where
Module<B>: VmpPMatAlloc<B>,
M: GLWEToLWESwitchingKeyPreparedAlloc<B>,
{
Self(GGLWESwitchingKeyPrepared::alloc_with(
module,
base2k,
k,
rank_in,
Rank(1),
dnum,
Dsize(1),
))
module.alloc_glwe_to_lwe_switching_key_prepared(base2k, k, rank_in, dnum)
}
pub fn alloc_bytes<A>(module: &Module<B>, infos: &A) -> usize
pub fn bytes_of_from_infos<A, M>(module: &M, infos: &A) -> usize
where
A: GGLWEInfos,
Module<B>: VmpPMatAllocBytes,
M: GLWEToLWESwitchingKeyPreparedAlloc<B>,
{
debug_assert_eq!(
infos.rank_out().0,
1,
"rank_out > 1 is not supported for GLWEToLWESwitchingKeyPrepared"
);
debug_assert_eq!(
infos.dsize().0,
1,
"dsize > 1 is not supported for GLWEToLWESwitchingKeyPrepared"
);
GGLWESwitchingKeyPrepared::alloc_bytes(module, infos)
module.bytes_of_glwe_to_lwe_switching_key_prepared_from_infos(infos)
}
pub fn alloc_bytes_with(module: &Module<B>, base2k: Base2K, k: TorusPrecision, rank_in: Rank, dnum: Dnum) -> usize
pub fn bytes_of<M>(module: &M, base2k: Base2K, k: TorusPrecision, rank_in: Rank, dnum: Dnum) -> usize
where
Module<B>: VmpPMatAllocBytes,
M: GLWEToLWESwitchingKeyPreparedAlloc<B>,
{
GGLWESwitchingKeyPrepared::alloc_bytes_with(module, base2k, k, rank_in, Rank(1), dnum, Dsize(1))
module.bytes_of_glwe_to_lwe_switching_key_prepared(base2k, k, rank_in, dnum)
}
}
impl<B: Backend, A: GGLWEInfos> PrepareScratchSpace<B, A> for GLWEToLWESwitchingKeyPrepared<Vec<u8>, B>
pub trait GLWEToLWESwitchingKeyPrepare<B: Backend>
where
GGLWESwitchingKeyPrepared<Vec<u8>, B>: PrepareScratchSpace<B, A>,
Self: GLWESwitchingKeyPrepare<B>,
{
fn prepare_scratch_space(module: &Module<B>, infos: &A) -> usize {
GGLWESwitchingKeyPrepared::prepare_scratch_space(module, infos)
fn prepare_glwe_to_lwe_switching_key_tmp_bytes<A>(&self, infos: &A)
where
A: GGLWEInfos,
{
self.prepare_glwe_switching_key_tmp_bytes(infos);
}
fn prepare_glwe_to_lwe_switching_key<R, O>(&self, res: &mut R, other: &O, scratch: &mut Scratch<B>)
where
R: GLWEToLWESwitchingKeyPreparedToMut<B>,
O: GLWEToLWESwitchingKeyToRef,
{
self.prepare_glwe_switching(&mut res.to_mut().0, &other.to_ref().0, scratch);
}
}
impl<D: DataRef, B: Backend> PrepareAlloc<B, GLWEToLWESwitchingKeyPrepared<Vec<u8>, B>> for GLWEToLWEKey<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);
ksk_prepared.prepare(module, self, scratch);
ksk_prepared
impl<B: Backend> GLWEToLWESwitchingKeyPrepare<B> for Module<B> where Self: GLWESwitchingKeyPrepare<B> {}
impl<B: Backend> GLWEToLWESwitchingKeyPrepared<Vec<u8>, B> {
pub fn prepare_tmp_bytes<A, M>(&self, module: &M, infos: &A)
where
A: GGLWEInfos,
M: GLWEToLWESwitchingKeyPrepare<B>,
{
module.prepare_glwe_to_lwe_switching_key_tmp_bytes(infos);
}
}
impl<DM: DataMut, DR: DataRef, B: Backend> Prepare<B, GLWEToLWEKey<DR>> for GLWEToLWESwitchingKeyPrepared<DM, B>
where
Module<B>: VmpPrepare<B>,
{
fn prepare(&mut self, module: &Module<B>, other: &GLWEToLWEKey<DR>, scratch: &mut Scratch<B>) {
self.0.prepare(module, &other.0, scratch);
impl<D: DataMut, B: Backend> GLWEToLWESwitchingKeyPrepared<D, B> {
fn prepare<O, M>(&mut self, module: &M, other: &O, scratch: &mut Scratch<B>)
where
O: GLWEToLWESwitchingKeyToRef,
M: GLWEToLWESwitchingKeyPrepare<B>,
{
module.prepare_glwe_to_lwe_switching_key(self, other, scratch);
}
}
pub trait GLWEToLWESwitchingKeyPreparedToRef<B: Backend> {
fn to_ref(&self) -> GLWEToLWESwitchingKeyPrepared<&[u8], B>;
}
impl<D: DataRef, B: Backend> GLWEToLWESwitchingKeyPreparedToRef<B> for GLWEToLWESwitchingKeyPrepared<D, B>
where
GLWESwitchingKeyPrepared<D, B>: GLWESwitchingKeyPreparedToRef<B>,
{
fn to_ref(&self) -> GLWEToLWESwitchingKeyPrepared<&[u8], B> {
GLWEToLWESwitchingKeyPrepared(self.0.to_ref())
}
}
pub trait GLWEToLWESwitchingKeyPreparedToMut<B: Backend> {
fn to_mut(&mut self) -> GLWEToLWESwitchingKeyPrepared<&mut [u8], B>;
}
impl<D: DataMut, B: Backend> GLWEToLWESwitchingKeyPreparedToMut<B> for GLWEToLWESwitchingKeyPrepared<D, B>
where
GLWESwitchingKeyPrepared<D, B>: GLWESwitchingKeyPreparedToMut<B>,
{
fn to_mut(&mut self) -> GLWEToLWESwitchingKeyPrepared<&mut [u8], B> {
GLWEToLWESwitchingKeyPrepared(self.0.to_mut())
}
}

View File

@@ -1,15 +1,15 @@
use poulpy_hal::{
api::{VmpPMatAlloc, VmpPMatAllocBytes, VmpPrepare},
layouts::{Backend, Data, DataMut, DataRef, Module, Scratch},
};
use poulpy_hal::layouts::{Backend, Data, DataMut, DataRef, Module, Scratch};
use crate::layouts::{
Base2K, Degree, Dnum, Dsize, GGLWEInfos, GLWEInfos, LWEInfos, LWESwitchingKey, Rank, TorusPrecision,
prepared::{GGLWESwitchingKeyPrepared, Prepare, PrepareAlloc, PrepareScratchSpace},
Base2K, Dnum, Dsize, GGLWEInfos, GLWEInfos, LWEInfos, LWESwitchingKeyToRef, Rank, RingDegree, TorusPrecision,
prepared::{
GLWESwitchingKeyPrepare, GLWESwitchingKeyPrepared, GLWESwitchingKeyPreparedAlloc, GLWESwitchingKeyPreparedToMut,
GLWESwitchingKeyPreparedToRef,
},
};
#[derive(PartialEq, Eq)]
pub struct LWESwitchingKeyPrepared<D: Data, B: Backend>(pub(crate) GGLWESwitchingKeyPrepared<D, B>);
pub struct LWESwitchingKeyPrepared<D: Data, B: Backend>(pub(crate) GLWESwitchingKeyPrepared<D, B>);
impl<D: Data, B: Backend> LWEInfos for LWESwitchingKeyPrepared<D, B> {
fn base2k(&self) -> Base2K {
@@ -20,7 +20,7 @@ impl<D: Data, B: Backend> LWEInfos for LWESwitchingKeyPrepared<D, B> {
self.0.k()
}
fn n(&self) -> Degree {
fn n(&self) -> RingDegree {
self.0.n()
}
@@ -52,101 +52,165 @@ impl<D: Data, B: Backend> GGLWEInfos for LWESwitchingKeyPrepared<D, B> {
}
}
pub trait LWESwitchingKeyPreparedAlloc<B: Backend>
where
Self: GLWESwitchingKeyPreparedAlloc<B>,
{
fn alloc_lwe_switching_key_prepared(
&self,
base2k: Base2K,
k: TorusPrecision,
dnum: Dnum,
) -> LWESwitchingKeyPrepared<Vec<u8>, B> {
LWESwitchingKeyPrepared(self.alloc_glwe_switching_key_prepared(base2k, k, Rank(1), Rank(1), dnum, Dsize(1)))
}
fn alloc_lwe_switching_key_prepared_from_infos<A>(&self, infos: &A) -> LWESwitchingKeyPrepared<Vec<u8>, B>
where
A: GGLWEInfos,
{
debug_assert_eq!(
infos.dsize().0,
1,
"dsize > 1 is not supported for LWESwitchingKey"
);
debug_assert_eq!(
infos.rank_in().0,
1,
"rank_in > 1 is not supported for LWESwitchingKey"
);
debug_assert_eq!(
infos.rank_out().0,
1,
"rank_out > 1 is not supported for LWESwitchingKey"
);
self.alloc_lwe_switching_key_prepared(infos.base2k(), infos.k(), infos.dnum())
}
fn bytes_of_lwe_switching_key_prepared(&self, base2k: Base2K, k: TorusPrecision, dnum: Dnum) -> usize {
self.bytes_of_glwe_switching_key_prepared(base2k, k, Rank(1), Rank(1), dnum, Dsize(1))
}
fn bytes_of_lwe_switching_key_prepared_from_infos<A>(&self, infos: &A) -> usize
where
A: GGLWEInfos,
{
debug_assert_eq!(
infos.dsize().0,
1,
"dsize > 1 is not supported for LWESwitchingKey"
);
debug_assert_eq!(
infos.rank_in().0,
1,
"rank_in > 1 is not supported for LWESwitchingKey"
);
debug_assert_eq!(
infos.rank_out().0,
1,
"rank_out > 1 is not supported for LWESwitchingKey"
);
self.bytes_of_lwe_switching_key_prepared(infos.base2k(), infos.k(), infos.dnum())
}
}
impl<B: Backend> LWESwitchingKeyPreparedAlloc<B> for Module<B> where Self: GLWESwitchingKeyPreparedAlloc<B> {}
impl<B: Backend> LWESwitchingKeyPrepared<Vec<u8>, B> {
pub fn alloc<A>(module: &Module<B>, infos: &A) -> Self
pub fn alloc_from_infos<A, M>(module: &M, infos: &A) -> Self
where
A: GGLWEInfos,
Module<B>: VmpPMatAlloc<B>,
M: LWESwitchingKeyPreparedAlloc<B>,
{
debug_assert_eq!(
infos.dsize().0,
1,
"dsize > 1 is not supported for LWESwitchingKey"
);
debug_assert_eq!(
infos.rank_in().0,
1,
"rank_in > 1 is not supported for LWESwitchingKey"
);
debug_assert_eq!(
infos.rank_out().0,
1,
"rank_out > 1 is not supported for LWESwitchingKey"
);
Self(GGLWESwitchingKeyPrepared::alloc(module, infos))
module.alloc_lwe_switching_key_prepared_from_infos(infos)
}
pub fn alloc_with(module: &Module<B>, base2k: Base2K, k: TorusPrecision, dnum: Dnum) -> Self
pub fn alloc<M>(module: &M, base2k: Base2K, k: TorusPrecision, dnum: Dnum) -> Self
where
Module<B>: VmpPMatAlloc<B>,
M: LWESwitchingKeyPreparedAlloc<B>,
{
Self(GGLWESwitchingKeyPrepared::alloc_with(
module,
base2k,
k,
Rank(1),
Rank(1),
dnum,
Dsize(1),
))
module.alloc_lwe_switching_key_prepared(base2k, k, dnum)
}
pub fn alloc_bytes<A>(module: &Module<B>, infos: &A) -> usize
pub fn bytes_of_from_infos<A, M>(module: &M, infos: &A) -> usize
where
A: GGLWEInfos,
Module<B>: VmpPMatAllocBytes,
M: LWESwitchingKeyPreparedAlloc<B>,
{
debug_assert_eq!(
infos.dsize().0,
1,
"dsize > 1 is not supported for LWESwitchingKey"
);
debug_assert_eq!(
infos.rank_in().0,
1,
"rank_in > 1 is not supported for LWESwitchingKey"
);
debug_assert_eq!(
infos.rank_out().0,
1,
"rank_out > 1 is not supported for LWESwitchingKey"
);
GGLWESwitchingKeyPrepared::alloc_bytes(module, infos)
module.bytes_of_lwe_switching_key_prepared_from_infos(infos)
}
pub fn alloc_bytes_with(module: &Module<B>, base2k: Base2K, k: TorusPrecision, dnum: Dnum) -> usize
pub fn bytes_of<M>(module: &M, base2k: Base2K, k: TorusPrecision, dnum: Dnum) -> usize
where
Module<B>: VmpPMatAllocBytes,
M: LWESwitchingKeyPreparedAlloc<B>,
{
GGLWESwitchingKeyPrepared::alloc_bytes_with(module, base2k, k, Rank(1), Rank(1), dnum, Dsize(1))
module.bytes_of_lwe_switching_key_prepared(base2k, k, dnum)
}
}
impl<B: Backend, A: GGLWEInfos> PrepareScratchSpace<B, A> for LWESwitchingKeyPrepared<Vec<u8>, B>
pub trait LWESwitchingKeyPrepare<B: Backend>
where
GGLWESwitchingKeyPrepared<Vec<u8>, B>: PrepareScratchSpace<B, A>,
Self: GLWESwitchingKeyPrepare<B>,
{
fn prepare_scratch_space(module: &Module<B>, infos: &A) -> usize {
GGLWESwitchingKeyPrepared::prepare_scratch_space(module, infos)
fn prepare_lwe_switching_key_tmp_bytes<A>(&self, infos: &A)
where
A: GGLWEInfos,
{
self.prepare_glwe_switching_key_tmp_bytes(infos);
}
fn prepare_lwe_switching_key<R, O>(&self, res: &mut R, other: &O, scratch: &mut Scratch<B>)
where
R: LWESwitchingKeyPreparedToMut<B>,
O: LWESwitchingKeyToRef,
{
self.prepare_glwe_switching(&mut res.to_mut().0, &other.to_ref().0, scratch);
}
}
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);
ksk_prepared.prepare(module, self, scratch);
ksk_prepared
impl<B: Backend> LWESwitchingKeyPrepare<B> for Module<B> where Self: GLWESwitchingKeyPrepare<B> {}
impl<B: Backend> LWESwitchingKeyPrepared<Vec<u8>, B> {
pub fn prepare_tmp_bytes<A, M>(&self, module: &M, infos: &A)
where
A: GGLWEInfos,
M: LWESwitchingKeyPrepare<B>,
{
module.prepare_lwe_switching_key_tmp_bytes(infos);
}
}
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);
impl<D: DataMut, B: Backend> LWESwitchingKeyPrepared<D, B> {
fn prepare<O, M>(&mut self, module: &M, other: &O, scratch: &mut Scratch<B>)
where
O: LWESwitchingKeyToRef,
M: LWESwitchingKeyPrepare<B>,
{
module.prepare_lwe_switching_key(self, other, scratch);
}
}
pub trait LWESwitchingKeyPreparedToRef<B: Backend> {
fn to_ref(&self) -> LWESwitchingKeyPrepared<&[u8], B>;
}
impl<D: DataRef, B: Backend> LWESwitchingKeyPreparedToRef<B> for LWESwitchingKeyPrepared<D, B>
where
GLWESwitchingKeyPrepared<D, B>: GLWESwitchingKeyPreparedToRef<B>,
{
fn to_ref(&self) -> LWESwitchingKeyPrepared<&[u8], B> {
LWESwitchingKeyPrepared(self.0.to_ref())
}
}
pub trait LWESwitchingKeyPreparedToMut<B: Backend> {
fn to_mut(&mut self) -> LWESwitchingKeyPrepared<&mut [u8], B>;
}
impl<D: DataMut, B: Backend> LWESwitchingKeyPreparedToMut<B> for LWESwitchingKeyPrepared<D, B>
where
GLWESwitchingKeyPrepared<D, B>: GLWESwitchingKeyPreparedToMut<B>,
{
fn to_mut(&mut self) -> LWESwitchingKeyPrepared<&mut [u8], B> {
LWESwitchingKeyPrepared(self.0.to_mut())
}
}

View File

@@ -1,16 +1,16 @@
use poulpy_hal::{
api::{VmpPMatAlloc, VmpPMatAllocBytes, VmpPrepare},
layouts::{Backend, Data, DataMut, DataRef, Module, Scratch},
};
use poulpy_hal::layouts::{Backend, Data, DataMut, DataRef, Module, Scratch};
use crate::layouts::{
Base2K, Degree, Dnum, Dsize, GGLWEInfos, GLWEInfos, LWEInfos, LWEToGLWESwitchingKey, Rank, TorusPrecision,
prepared::{GGLWESwitchingKeyPrepared, Prepare, PrepareAlloc, PrepareScratchSpace},
Base2K, Dnum, Dsize, GGLWEInfos, GLWEInfos, LWEInfos, LWEToGLWESwitchingKeyToRef, Rank, RingDegree, TorusPrecision,
prepared::{
GLWESwitchingKeyPrepare, GLWESwitchingKeyPrepared, GLWESwitchingKeyPreparedAlloc, GLWESwitchingKeyPreparedToMut,
GLWESwitchingKeyPreparedToRef,
},
};
/// A special [GLWESwitchingKey] required to for the conversion from [LWECiphertext] to [GLWECiphertext].
/// A special [GLWESwitchingKey] required to for the conversion from [LWE] to [GLWE].
#[derive(PartialEq, Eq)]
pub struct LWEToGLWESwitchingKeyPrepared<D: Data, B: Backend>(pub(crate) GGLWESwitchingKeyPrepared<D, B>);
pub struct LWEToGLWESwitchingKeyPrepared<D: Data, B: Backend>(pub(crate) GLWESwitchingKeyPrepared<D, B>);
impl<D: Data, B: Backend> LWEInfos for LWEToGLWESwitchingKeyPrepared<D, B> {
fn base2k(&self) -> Base2K {
@@ -21,7 +21,7 @@ impl<D: Data, B: Backend> LWEInfos for LWEToGLWESwitchingKeyPrepared<D, B> {
self.0.k()
}
fn n(&self) -> Degree {
fn n(&self) -> RingDegree {
self.0.n()
}
@@ -54,91 +54,162 @@ impl<D: Data, B: Backend> GGLWEInfos for LWEToGLWESwitchingKeyPrepared<D, B> {
}
}
pub trait LWEToGLWESwitchingKeyPreparedAlloc<B: Backend>
where
Self: GLWESwitchingKeyPreparedAlloc<B>,
{
fn alloc_lwe_to_glwe_switching_key_prepared(
&self,
base2k: Base2K,
k: TorusPrecision,
rank_out: Rank,
dnum: Dnum,
) -> LWEToGLWESwitchingKeyPrepared<Vec<u8>, B> {
LWEToGLWESwitchingKeyPrepared(self.alloc_glwe_switching_key_prepared(base2k, k, Rank(1), rank_out, dnum, Dsize(1)))
}
fn alloc_lwe_to_glwe_switching_key_prepared_from_infos<A>(&self, infos: &A) -> LWEToGLWESwitchingKeyPrepared<Vec<u8>, B>
where
A: GGLWEInfos,
{
debug_assert_eq!(
infos.rank_in().0,
1,
"rank_in > 1 is not supported for LWEToGLWESwitchingKey"
);
debug_assert_eq!(
infos.dsize().0,
1,
"dsize > 1 is not supported for LWEToGLWESwitchingKey"
);
self.alloc_lwe_to_glwe_switching_key_prepared(infos.base2k(), infos.k(), infos.rank_out(), infos.dnum())
}
fn bytes_of_lwe_to_glwe_switching_key_prepared(
&self,
base2k: Base2K,
k: TorusPrecision,
rank_out: Rank,
dnum: Dnum,
) -> usize {
self.bytes_of_glwe_switching_key_prepared(base2k, k, Rank(1), rank_out, dnum, Dsize(1))
}
fn bytes_of_lwe_to_glwe_switching_key_prepared_from_infos<A>(&self, infos: &A) -> usize
where
A: GGLWEInfos,
{
debug_assert_eq!(
infos.rank_in().0,
1,
"rank_in > 1 is not supported for LWEToGLWESwitchingKey"
);
debug_assert_eq!(
infos.dsize().0,
1,
"dsize > 1 is not supported for LWEToGLWESwitchingKey"
);
self.bytes_of_lwe_to_glwe_switching_key_prepared(infos.base2k(), infos.k(), infos.rank_out(), infos.dnum())
}
}
impl<B: Backend> LWEToGLWESwitchingKeyPreparedAlloc<B> for Module<B> where Self: GLWESwitchingKeyPreparedAlloc<B> {}
impl<B: Backend> LWEToGLWESwitchingKeyPrepared<Vec<u8>, B> {
pub fn alloc<A>(module: &Module<B>, infos: &A) -> Self
pub fn alloc_from_infos<A, M>(module: &M, infos: &A) -> Self
where
A: GGLWEInfos,
Module<B>: VmpPMatAlloc<B>,
M: LWEToGLWESwitchingKeyPreparedAlloc<B>,
{
debug_assert_eq!(
infos.rank_in().0,
1,
"rank_in > 1 is not supported for LWEToGLWESwitchingKey"
);
debug_assert_eq!(
infos.dsize().0,
1,
"dsize > 1 is not supported for LWEToGLWESwitchingKey"
);
Self(GGLWESwitchingKeyPrepared::alloc(module, infos))
module.alloc_lwe_to_glwe_switching_key_prepared_from_infos(infos)
}
pub fn alloc_with(module: &Module<B>, base2k: Base2K, k: TorusPrecision, rank_out: Rank, dnum: Dnum) -> Self
pub fn alloc<M>(module: &M, base2k: Base2K, k: TorusPrecision, rank_out: Rank, dnum: Dnum) -> Self
where
Module<B>: VmpPMatAlloc<B>,
M: LWEToGLWESwitchingKeyPreparedAlloc<B>,
{
Self(GGLWESwitchingKeyPrepared::alloc_with(
module,
base2k,
k,
Rank(1),
rank_out,
dnum,
Dsize(1),
))
module.alloc_lwe_to_glwe_switching_key_prepared(base2k, k, rank_out, dnum)
}
pub fn alloc_bytes<A>(module: &Module<B>, infos: &A) -> usize
pub fn bytes_of_from_infos<A, M>(module: &M, infos: &A) -> usize
where
A: GGLWEInfos,
Module<B>: VmpPMatAllocBytes,
M: LWEToGLWESwitchingKeyPreparedAlloc<B>,
{
debug_assert_eq!(
infos.rank_in().0,
1,
"rank_in > 1 is not supported for LWEToGLWESwitchingKey"
);
debug_assert_eq!(
infos.dsize().0,
1,
"dsize > 1 is not supported for LWEToGLWESwitchingKey"
);
GGLWESwitchingKeyPrepared::alloc_bytes(module, infos)
module.bytes_of_lwe_to_glwe_switching_key_prepared_from_infos(infos)
}
pub fn alloc_bytes_with(module: &Module<B>, base2k: Base2K, k: TorusPrecision, dnum: Dnum, rank_out: Rank) -> usize
pub fn bytes_of<M>(module: &M, base2k: Base2K, k: TorusPrecision, rank_out: Rank, dnum: Dnum) -> usize
where
Module<B>: VmpPMatAllocBytes,
M: LWEToGLWESwitchingKeyPreparedAlloc<B>,
{
GGLWESwitchingKeyPrepared::alloc_bytes_with(module, base2k, k, Rank(1), rank_out, dnum, Dsize(1))
module.bytes_of_lwe_to_glwe_switching_key_prepared(base2k, k, rank_out, dnum)
}
}
impl<B: Backend, A: GGLWEInfos> PrepareScratchSpace<B, A> for LWEToGLWESwitchingKeyPrepared<Vec<u8>, B>
pub trait LWEToGLWESwitchingKeyPrepare<B: Backend>
where
GGLWESwitchingKeyPrepared<Vec<u8>, B>: PrepareScratchSpace<B, A>,
Self: GLWESwitchingKeyPrepare<B>,
{
fn prepare_scratch_space(module: &Module<B>, infos: &A) -> usize {
GGLWESwitchingKeyPrepared::prepare_scratch_space(module, infos)
fn prepare_lwe_to_glwe_switching_key_tmp_bytes<A>(&self, infos: &A)
where
A: GGLWEInfos,
{
self.prepare_glwe_switching_key_tmp_bytes(infos);
}
fn prepare_lwe_to_glwe_switching_key<R, O>(&self, res: &mut R, other: &O, scratch: &mut Scratch<B>)
where
R: LWEToGLWESwitchingKeyPreparedToMut<B>,
O: LWEToGLWESwitchingKeyToRef,
{
self.prepare_glwe_switching(&mut res.to_mut().0, &other.to_ref().0, scratch);
}
}
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);
ksk_prepared.prepare(module, self, scratch);
ksk_prepared
impl<B: Backend> LWEToGLWESwitchingKeyPrepare<B> for Module<B> where Self: GLWESwitchingKeyPrepare<B> {}
impl<B: Backend> LWEToGLWESwitchingKeyPrepared<Vec<u8>, B> {
pub fn prepare_tmp_bytes<A, M>(&self, module: &M, infos: &A)
where
A: GGLWEInfos,
M: LWEToGLWESwitchingKeyPrepare<B>,
{
module.prepare_lwe_to_glwe_switching_key_tmp_bytes(infos);
}
}
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);
impl<D: DataMut, B: Backend> LWEToGLWESwitchingKeyPrepared<D, B> {
fn prepare<O, M>(&mut self, module: &M, other: &O, scratch: &mut Scratch<B>)
where
O: LWEToGLWESwitchingKeyToRef,
M: LWEToGLWESwitchingKeyPrepare<B>,
{
module.prepare_lwe_to_glwe_switching_key(self, other, scratch);
}
}
pub trait LWEToGLWESwitchingKeyPreparedToRef<B: Backend> {
fn to_ref(&self) -> LWEToGLWESwitchingKeyPrepared<&[u8], B>;
}
impl<D: DataRef, B: Backend> LWEToGLWESwitchingKeyPreparedToRef<B> for LWEToGLWESwitchingKeyPrepared<D, B>
where
GLWESwitchingKeyPrepared<D, B>: GLWESwitchingKeyPreparedToRef<B>,
{
fn to_ref(&self) -> LWEToGLWESwitchingKeyPrepared<&[u8], B> {
LWEToGLWESwitchingKeyPrepared(self.0.to_ref())
}
}
pub trait LWEToGLWESwitchingKeyPreparedToMut<B: Backend> {
fn to_mut(&mut self) -> LWEToGLWESwitchingKeyPrepared<&mut [u8], B>;
}
impl<D: DataMut, B: Backend> LWEToGLWESwitchingKeyPreparedToMut<B> for LWEToGLWESwitchingKeyPrepared<D, B>
where
GLWESwitchingKeyPrepared<D, B>: GLWESwitchingKeyPreparedToMut<B>,
{
fn to_mut(&mut self) -> LWEToGLWESwitchingKeyPrepared<&mut [u8], B> {
LWEToGLWESwitchingKeyPrepared(self.0.to_mut())
}
}

View File

@@ -19,16 +19,3 @@ pub use glwe_sk::*;
pub use glwe_to_lwe_ksk::*;
pub use lwe_ksk::*;
pub use lwe_to_glwe_ksk::*;
use poulpy_hal::layouts::{Backend, Module, Scratch};
pub trait PrepareScratchSpace<B: Backend, T> {
fn prepare_scratch_space(module: &Module<B>, infos: &T) -> usize;
}
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>);
}