mirror of
https://github.com/arnaucube/poulpy.git
synced 2026-02-10 05:06:44 +01:00
Dev serialization (#64)
* Added compressed serialization for GLWECiphertext + Ciphertext decompression * Added compressed serialization for GGLWECiphertext & GLWESwitchingkey * generalized automorphism test * Removed ops on scalar_znx, replaced by as_vec_znx/as_vec_znx_mut and then call op on vec_znx * Added tests for automorphism key encryption * Added tensorkey compressed * added ggsw compressed
This commit is contained in:
committed by
GitHub
parent
4c59733566
commit
9aa4b1f1e2
47
Cargo.lock
generated
47
Cargo.lock
generated
@@ -50,6 +50,7 @@ dependencies = [
|
|||||||
"rug",
|
"rug",
|
||||||
"sampling",
|
"sampling",
|
||||||
"utils",
|
"utils",
|
||||||
|
"zstd",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -82,6 +83,8 @@ version = "1.2.31"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c3a42d84bb6b69d3a8b3eaacf0d88f179e1929695e1ad012b6cf64d9caaa5fd2"
|
checksum = "c3a42d84bb6b69d3a8b3eaacf0d88f179e1929695e1ad012b6cf64d9caaa5fd2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"jobserver",
|
||||||
|
"libc",
|
||||||
"shlex",
|
"shlex",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -160,6 +163,7 @@ dependencies = [
|
|||||||
"byteorder",
|
"byteorder",
|
||||||
"criterion",
|
"criterion",
|
||||||
"itertools 0.14.0",
|
"itertools 0.14.0",
|
||||||
|
"rand_core",
|
||||||
"rand_distr",
|
"rand_distr",
|
||||||
"rug",
|
"rug",
|
||||||
"sampling",
|
"sampling",
|
||||||
@@ -297,6 +301,15 @@ version = "1.0.14"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674"
|
checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "jobserver"
|
||||||
|
version = "0.1.32"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "js-sys"
|
name = "js-sys"
|
||||||
version = "0.3.76"
|
version = "0.3.76"
|
||||||
@@ -359,6 +372,12 @@ version = "1.0.15"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
|
checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pkg-config"
|
||||||
|
version = "0.3.32"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "plotters"
|
name = "plotters"
|
||||||
version = "0.3.7"
|
version = "0.3.7"
|
||||||
@@ -819,3 +838,31 @@ dependencies = [
|
|||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zstd"
|
||||||
|
version = "0.13.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a"
|
||||||
|
dependencies = [
|
||||||
|
"zstd-safe",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zstd-safe"
|
||||||
|
version = "7.2.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8f49c4d5f0abb602a93fb8736af2a4f4dd9512e36f7f570d66e65ff867ed3b9d"
|
||||||
|
dependencies = [
|
||||||
|
"zstd-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zstd-sys"
|
||||||
|
version = "2.0.15+zstd.1.5.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "eb81183ddd97d0c74cedf1d50d85c8d08c1b8b68ee863bdee9e706eedba1a237"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"pkg-config",
|
||||||
|
]
|
||||||
|
|||||||
@@ -11,3 +11,4 @@ rand_distr = "0.5.1"
|
|||||||
itertools = "0.14.0"
|
itertools = "0.14.0"
|
||||||
criterion = "0.7.0"
|
criterion = "0.7.0"
|
||||||
byteorder = "1.5.0"
|
byteorder = "1.5.0"
|
||||||
|
zstd = "0.13.3"
|
||||||
11
backend/.vscode/settings.json
vendored
11
backend/.vscode/settings.json
vendored
@@ -1,11 +0,0 @@
|
|||||||
{
|
|
||||||
"github.copilot.enable": {
|
|
||||||
"*": false,
|
|
||||||
"plaintext": false,
|
|
||||||
"markdown": false,
|
|
||||||
"scminput": false
|
|
||||||
},
|
|
||||||
"files.associations": {
|
|
||||||
"random": "c"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -15,6 +15,7 @@ sampling = { path = "../sampling" }
|
|||||||
utils = { path = "../utils" }
|
utils = { path = "../utils" }
|
||||||
paste = "1.0.15"
|
paste = "1.0.15"
|
||||||
byteorder = {workspace = true}
|
byteorder = {workspace = true}
|
||||||
|
zstd = {workspace = true}
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
cmake = "0.1.54"
|
cmake = "0.1.54"
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
pub fn build() {
|
pub fn build() {
|
||||||
let dst: PathBuf = cmake::Config::new("src/implementation/cpu_spqlios/spqlios-arithmetic").define("ENABLE_TESTING", "FALSE").build();
|
let dst: PathBuf = cmake::Config::new("src/implementation/cpu_spqlios/spqlios-arithmetic")
|
||||||
|
.define("ENABLE_TESTING", "FALSE")
|
||||||
|
.build();
|
||||||
|
|
||||||
let lib_dir: PathBuf = dst.join("lib");
|
let lib_dir: PathBuf = dst.join("lib");
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use crate::hal::layouts::{ScalarZnxOwned, ScalarZnxToMut, ScalarZnxToRef};
|
use crate::hal::layouts::ScalarZnxOwned;
|
||||||
|
|
||||||
/// Allocates as [crate::hal::layouts::ScalarZnx].
|
/// Allocates as [crate::hal::layouts::ScalarZnx].
|
||||||
pub trait ScalarZnxAlloc {
|
pub trait ScalarZnxAlloc {
|
||||||
@@ -15,33 +15,3 @@ pub trait ScalarZnxAllocBytes {
|
|||||||
pub trait ScalarZnxFromBytes {
|
pub trait ScalarZnxFromBytes {
|
||||||
fn scalar_znx_from_bytes(&self, cols: usize, bytes: Vec<u8>) -> ScalarZnxOwned;
|
fn scalar_znx_from_bytes(&self, cols: usize, bytes: Vec<u8>) -> ScalarZnxOwned;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Applies the mapping X -> X^k to a\[a_col\] and write the result on res\[res_col\].
|
|
||||||
pub trait ScalarZnxAutomorphism {
|
|
||||||
fn scalar_znx_automorphism<R, A>(&self, k: i64, res: &mut R, res_col: usize, a: &A, a_col: usize)
|
|
||||||
where
|
|
||||||
R: ScalarZnxToMut,
|
|
||||||
A: ScalarZnxToRef;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Applies the mapping X -> X^k on res\[res_col\].
|
|
||||||
pub trait ScalarZnxAutomorphismInplace {
|
|
||||||
fn scalar_znx_automorphism_inplace<R>(&self, k: i64, res: &mut R, res_col: usize)
|
|
||||||
where
|
|
||||||
R: ScalarZnxToMut;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Multiply a\[a_col\] with (X^p - 1) and write the result on res\[res_col\].
|
|
||||||
pub trait ScalarZnxMulXpMinusOne {
|
|
||||||
fn scalar_znx_mul_xp_minus_one<R, A>(&self, p: i64, r: &mut R, r_col: usize, a: &A, a_col: usize)
|
|
||||||
where
|
|
||||||
R: ScalarZnxToMut,
|
|
||||||
A: ScalarZnxToRef;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Multiply res\[res_col\] with (X^p - 1).
|
|
||||||
pub trait ScalarZnxMulXpMinusOneInplace {
|
|
||||||
fn scalar_znx_mul_xp_minus_one_inplace<R>(&self, p: i64, res: &mut R, res_col: usize)
|
|
||||||
where
|
|
||||||
R: ScalarZnxToMut;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
use crate::hal::layouts::{Data, DataMut, DataRef};
|
use crate::hal::layouts::{Data, DataMut, DataRef};
|
||||||
use rand_distr::num_traits::Zero;
|
use rand_distr::num_traits::Zero;
|
||||||
|
use sampling::source::Source;
|
||||||
|
|
||||||
pub trait ZnxInfos {
|
pub trait ZnxInfos {
|
||||||
/// Returns the ring degree of the polynomials.
|
/// Returns the ring degree of the polynomials.
|
||||||
@@ -108,3 +109,7 @@ where
|
|||||||
fn zero(&mut self);
|
fn zero(&mut self);
|
||||||
fn zero_at(&mut self, i: usize, j: usize);
|
fn zero_at(&mut self, i: usize, j: usize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub trait FillUniform {
|
||||||
|
fn fill_uniform(&mut self, source: &mut Source);
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,13 +1,7 @@
|
|||||||
use crate::hal::{
|
use crate::hal::{
|
||||||
api::{
|
api::{ScalarZnxAlloc, ScalarZnxAllocBytes},
|
||||||
ScalarZnxAlloc, ScalarZnxAllocBytes, ScalarZnxAutomorphism, ScalarZnxAutomorphismInplace, ScalarZnxFromBytes,
|
layouts::{Backend, Module, ScalarZnxOwned},
|
||||||
ScalarZnxMulXpMinusOne, ScalarZnxMulXpMinusOneInplace,
|
oep::{ScalarZnxAllocBytesImpl, ScalarZnxAllocImpl},
|
||||||
},
|
|
||||||
layouts::{Backend, Module, ScalarZnxOwned, ScalarZnxToMut, ScalarZnxToRef},
|
|
||||||
oep::{
|
|
||||||
ScalarZnxAllocBytesImpl, ScalarZnxAllocImpl, ScalarZnxAutomorphismImpl, ScalarZnxAutomorphismInplaceIml,
|
|
||||||
ScalarZnxFromBytesImpl, ScalarZnxMulXpMinusOneImpl, ScalarZnxMulXpMinusOneInplaceImpl,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
impl<B> ScalarZnxAllocBytes for Module<B>
|
impl<B> ScalarZnxAllocBytes for Module<B>
|
||||||
@@ -27,62 +21,3 @@ where
|
|||||||
B::scalar_znx_alloc_impl(self.n(), cols)
|
B::scalar_znx_alloc_impl(self.n(), cols)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<B> ScalarZnxFromBytes for Module<B>
|
|
||||||
where
|
|
||||||
B: Backend + ScalarZnxFromBytesImpl<B>,
|
|
||||||
{
|
|
||||||
fn scalar_znx_from_bytes(&self, cols: usize, bytes: Vec<u8>) -> ScalarZnxOwned {
|
|
||||||
B::scalar_znx_from_bytes_impl(self.n(), cols, bytes)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<B> ScalarZnxAutomorphism for Module<B>
|
|
||||||
where
|
|
||||||
B: Backend + ScalarZnxAutomorphismImpl<B>,
|
|
||||||
{
|
|
||||||
fn scalar_znx_automorphism<R, A>(&self, k: i64, res: &mut R, res_col: usize, a: &A, a_col: usize)
|
|
||||||
where
|
|
||||||
R: ScalarZnxToMut,
|
|
||||||
A: ScalarZnxToRef,
|
|
||||||
{
|
|
||||||
B::scalar_znx_automorphism_impl(self, k, res, res_col, a, a_col);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<B> ScalarZnxAutomorphismInplace for Module<B>
|
|
||||||
where
|
|
||||||
B: Backend + ScalarZnxAutomorphismInplaceIml<B>,
|
|
||||||
{
|
|
||||||
fn scalar_znx_automorphism_inplace<A>(&self, k: i64, a: &mut A, a_col: usize)
|
|
||||||
where
|
|
||||||
A: ScalarZnxToMut,
|
|
||||||
{
|
|
||||||
B::scalar_znx_automorphism_inplace_impl(self, k, a, a_col);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<B> ScalarZnxMulXpMinusOne for Module<B>
|
|
||||||
where
|
|
||||||
B: Backend + ScalarZnxMulXpMinusOneImpl<B>,
|
|
||||||
{
|
|
||||||
fn scalar_znx_mul_xp_minus_one<R, A>(&self, p: i64, r: &mut R, r_col: usize, a: &A, a_col: usize)
|
|
||||||
where
|
|
||||||
R: ScalarZnxToMut,
|
|
||||||
A: ScalarZnxToRef,
|
|
||||||
{
|
|
||||||
B::scalar_znx_mul_xp_minus_one_impl(self, p, r, r_col, a, a_col);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<B> ScalarZnxMulXpMinusOneInplace for Module<B>
|
|
||||||
where
|
|
||||||
B: Backend + ScalarZnxMulXpMinusOneInplaceImpl<B>,
|
|
||||||
{
|
|
||||||
fn scalar_znx_mul_xp_minus_one_inplace<R>(&self, p: i64, r: &mut R, r_col: usize)
|
|
||||||
where
|
|
||||||
R: ScalarZnxToMut,
|
|
||||||
{
|
|
||||||
B::scalar_znx_mul_xp_minus_one_inplace_impl(self, p, r, r_col);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,12 +1,17 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
alloc_aligned,
|
alloc_aligned,
|
||||||
hal::{
|
hal::{
|
||||||
api::{DataView, DataViewMut, ZnxInfos, ZnxSliceSize, ZnxView},
|
api::{DataView, DataViewMut, FillUniform, ZnxInfos, ZnxSliceSize, ZnxView, ZnxViewMut, ZnxZero},
|
||||||
layouts::{Data, DataMut, DataRef, ReaderFrom, VecZnx, WriterTo},
|
layouts::{Data, DataMut, DataRef, ReaderFrom, VecZnx, WriterTo},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
#[derive(PartialEq, Eq)]
|
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
|
||||||
|
use rand::RngCore;
|
||||||
|
use sampling::source::Source;
|
||||||
|
|
||||||
|
#[derive(PartialEq, Eq, Clone)]
|
||||||
pub struct MatZnx<D: Data> {
|
pub struct MatZnx<D: Data> {
|
||||||
data: D,
|
data: D,
|
||||||
n: usize,
|
n: usize,
|
||||||
@@ -16,6 +21,12 @@ pub struct MatZnx<D: Data> {
|
|||||||
cols_out: usize,
|
cols_out: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<D: DataRef> fmt::Debug for MatZnx<D> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(f, "{}", self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<D: Data> ZnxInfos for MatZnx<D> {
|
impl<D: Data> ZnxInfos for MatZnx<D> {
|
||||||
fn cols(&self) -> usize {
|
fn cols(&self) -> usize {
|
||||||
self.cols_in
|
self.cols_in
|
||||||
@@ -74,7 +85,7 @@ impl<D: DataRef> MatZnx<D> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<D: DataRef + From<Vec<u8>>> MatZnx<D> {
|
impl<D: DataRef + From<Vec<u8>>> MatZnx<D> {
|
||||||
pub(crate) fn new(n: usize, rows: usize, cols_in: usize, cols_out: usize, size: usize) -> Self {
|
pub(crate) fn alloc(n: usize, rows: usize, cols_in: usize, cols_out: usize, size: usize) -> Self {
|
||||||
let data: Vec<u8> = alloc_aligned(Self::bytes_of(n, rows, cols_in, cols_out, size));
|
let data: Vec<u8> = alloc_aligned(Self::bytes_of(n, rows, cols_in, cols_out, size));
|
||||||
Self {
|
Self {
|
||||||
data: data.into(),
|
data: data.into(),
|
||||||
@@ -86,7 +97,7 @@ impl<D: DataRef + From<Vec<u8>>> MatZnx<D> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn new_from_bytes(
|
pub(crate) fn from_bytes(
|
||||||
n: usize,
|
n: usize,
|
||||||
rows: usize,
|
rows: usize,
|
||||||
cols_in: usize,
|
cols_in: usize,
|
||||||
@@ -158,6 +169,12 @@ impl<D: DataMut> MatZnx<D> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<D: DataMut> FillUniform for MatZnx<D> {
|
||||||
|
fn fill_uniform(&mut self, source: &mut Source) {
|
||||||
|
source.fill_bytes(self.data.as_mut());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub type MatZnxOwned = MatZnx<Vec<u8>>;
|
pub type MatZnxOwned = MatZnx<Vec<u8>>;
|
||||||
pub type MatZnxMut<'a> = MatZnx<&'a mut [u8]>;
|
pub type MatZnxMut<'a> = MatZnx<&'a mut [u8]>;
|
||||||
pub type MatZnxRef<'a> = MatZnx<&'a [u8]>;
|
pub type MatZnxRef<'a> = MatZnx<&'a [u8]>;
|
||||||
@@ -209,8 +226,6 @@ impl<D: Data> MatZnx<D> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
|
|
||||||
|
|
||||||
impl<D: DataMut> ReaderFrom for MatZnx<D> {
|
impl<D: DataMut> ReaderFrom for MatZnx<D> {
|
||||||
fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> {
|
fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> {
|
||||||
self.n = reader.read_u64::<LittleEndian>()? as usize;
|
self.n = reader.read_u64::<LittleEndian>()? as usize;
|
||||||
@@ -244,3 +259,32 @@ impl<D: DataRef> WriterTo for MatZnx<D> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<D: DataRef> fmt::Display for MatZnx<D> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
writeln!(
|
||||||
|
f,
|
||||||
|
"MatZnx(n={}, rows={}, cols_in={}, cols_out={}, size={})",
|
||||||
|
self.n, self.rows, self.cols_in, self.cols_out, self.size
|
||||||
|
)?;
|
||||||
|
|
||||||
|
for row_i in 0..self.rows {
|
||||||
|
writeln!(f, "Row {}:", row_i)?;
|
||||||
|
for col_i in 0..self.cols_in {
|
||||||
|
writeln!(f, "cols_in {}:", col_i)?;
|
||||||
|
writeln!(f, "{}:", self.at(row_i, col_i))?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D: DataMut> ZnxZero for MatZnx<D> {
|
||||||
|
fn zero(&mut self) {
|
||||||
|
self.raw_mut().fill(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn zero_at(&mut self, i: usize, j: usize) {
|
||||||
|
self.at_mut(i, j).zero();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -6,12 +6,12 @@ use sampling::source::Source;
|
|||||||
use crate::{
|
use crate::{
|
||||||
alloc_aligned,
|
alloc_aligned,
|
||||||
hal::{
|
hal::{
|
||||||
api::{DataView, DataViewMut, ZnxInfos, ZnxSliceSize, ZnxView, ZnxViewMut, ZnxZero},
|
api::{DataView, DataViewMut, FillUniform, ZnxInfos, ZnxSliceSize, ZnxView, ZnxViewMut, ZnxZero},
|
||||||
layouts::{Data, DataMut, DataRef, ReaderFrom, VecZnx, VecZnxToMut, VecZnxToRef, WriterTo},
|
layouts::{Data, DataMut, DataRef, ReaderFrom, VecZnx, WriterTo},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(PartialEq, Eq)]
|
#[derive(PartialEq, Eq, Debug, Clone)]
|
||||||
pub struct ScalarZnx<D: Data> {
|
pub struct ScalarZnx<D: Data> {
|
||||||
pub(crate) data: D,
|
pub(crate) data: D,
|
||||||
pub(crate) n: usize,
|
pub(crate) n: usize,
|
||||||
@@ -114,7 +114,7 @@ impl<D: DataRef> ScalarZnx<D> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<D: DataRef + From<Vec<u8>>> ScalarZnx<D> {
|
impl<D: DataRef + From<Vec<u8>>> ScalarZnx<D> {
|
||||||
pub fn new(n: usize, cols: usize) -> Self {
|
pub fn alloc(n: usize, cols: usize) -> Self {
|
||||||
let data: Vec<u8> = alloc_aligned::<u8>(Self::bytes_of(n, cols));
|
let data: Vec<u8> = alloc_aligned::<u8>(Self::bytes_of(n, cols));
|
||||||
Self {
|
Self {
|
||||||
data: data.into(),
|
data: data.into(),
|
||||||
@@ -123,7 +123,7 @@ impl<D: DataRef + From<Vec<u8>>> ScalarZnx<D> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn new_from_bytes(n: usize, cols: usize, bytes: impl Into<Vec<u8>>) -> Self {
|
pub(crate) fn from_bytes(n: usize, cols: usize, bytes: impl Into<Vec<u8>>) -> Self {
|
||||||
let data: Vec<u8> = bytes.into();
|
let data: Vec<u8> = bytes.into();
|
||||||
assert!(data.len() == Self::bytes_of(n, cols));
|
assert!(data.len() == Self::bytes_of(n, cols));
|
||||||
Self {
|
Self {
|
||||||
@@ -143,6 +143,12 @@ impl<D: DataMut> ZnxZero for ScalarZnx<D> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<D: DataMut> FillUniform for ScalarZnx<D> {
|
||||||
|
fn fill_uniform(&mut self, source: &mut Source) {
|
||||||
|
source.fill_bytes(self.data.as_mut());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub type ScalarZnxOwned = ScalarZnx<Vec<u8>>;
|
pub type ScalarZnxOwned = ScalarZnx<Vec<u8>>;
|
||||||
|
|
||||||
impl<D: Data> ScalarZnx<D> {
|
impl<D: Data> ScalarZnx<D> {
|
||||||
@@ -179,8 +185,8 @@ impl<D: DataMut> ScalarZnxToMut for ScalarZnx<D> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<D: DataRef> VecZnxToRef for ScalarZnx<D> {
|
impl<D: DataRef> ScalarZnx<D> {
|
||||||
fn to_ref(&self) -> VecZnx<&[u8]> {
|
pub fn as_vec_znx(&self) -> VecZnx<&[u8]> {
|
||||||
VecZnx {
|
VecZnx {
|
||||||
data: self.data.as_ref(),
|
data: self.data.as_ref(),
|
||||||
n: self.n,
|
n: self.n,
|
||||||
@@ -191,8 +197,8 @@ impl<D: DataRef> VecZnxToRef for ScalarZnx<D> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<D: DataMut> VecZnxToMut for ScalarZnx<D> {
|
impl<D: DataMut> ScalarZnx<D> {
|
||||||
fn to_mut(&mut self) -> VecZnx<&mut [u8]> {
|
pub fn as_vec_znx_mut(&mut self) -> VecZnx<&mut [u8]> {
|
||||||
VecZnx {
|
VecZnx {
|
||||||
data: self.data.as_mut(),
|
data: self.data.as_mut(),
|
||||||
n: self.n,
|
n: self.n,
|
||||||
|
|||||||
@@ -3,12 +3,12 @@ use std::fmt;
|
|||||||
use crate::{
|
use crate::{
|
||||||
alloc_aligned,
|
alloc_aligned,
|
||||||
hal::{
|
hal::{
|
||||||
api::{DataView, DataViewMut, ZnxInfos, ZnxSliceSize, ZnxView, ZnxViewMut, ZnxZero},
|
api::{DataView, DataViewMut, FillUniform, ZnxInfos, ZnxSliceSize, ZnxView, ZnxViewMut, ZnxZero},
|
||||||
layouts::{Data, DataMut, DataRef, ReaderFrom, WriterTo},
|
layouts::{Data, DataMut, DataRef, ReaderFrom, WriterTo},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(PartialEq, Eq)]
|
#[derive(PartialEq, Eq, Clone)]
|
||||||
pub struct VecZnx<D: Data> {
|
pub struct VecZnx<D: Data> {
|
||||||
pub(crate) data: D,
|
pub(crate) data: D,
|
||||||
pub(crate) n: usize,
|
pub(crate) n: usize,
|
||||||
@@ -86,7 +86,7 @@ impl<D: DataRef> VecZnx<D> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<D: DataRef + From<Vec<u8>>> VecZnx<D> {
|
impl<D: DataRef + From<Vec<u8>>> VecZnx<D> {
|
||||||
pub fn new<Scalar: Sized>(n: usize, cols: usize, size: usize) -> Self {
|
pub fn alloc<Scalar: Sized>(n: usize, cols: usize, size: usize) -> Self {
|
||||||
let data: Vec<u8> = alloc_aligned::<u8>(Self::alloc_bytes::<Scalar>(n, cols, size));
|
let data: Vec<u8> = alloc_aligned::<u8>(Self::alloc_bytes::<Scalar>(n, cols, size));
|
||||||
Self {
|
Self {
|
||||||
data: data.into(),
|
data: data.into(),
|
||||||
@@ -157,6 +157,12 @@ impl<D: DataRef> fmt::Display for VecZnx<D> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<D: DataMut> FillUniform for VecZnx<D> {
|
||||||
|
fn fill_uniform(&mut self, source: &mut Source) {
|
||||||
|
source.fill_bytes(self.data.as_mut());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub type VecZnxOwned = VecZnx<Vec<u8>>;
|
pub type VecZnxOwned = VecZnx<Vec<u8>>;
|
||||||
pub type VecZnxMut<'a> = VecZnx<&'a mut [u8]>;
|
pub type VecZnxMut<'a> = VecZnx<&'a mut [u8]>;
|
||||||
pub type VecZnxRef<'a> = VecZnx<&'a [u8]>;
|
pub type VecZnxRef<'a> = VecZnx<&'a [u8]>;
|
||||||
@@ -207,6 +213,8 @@ impl<D: DataRef> VecZnx<D> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
|
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
|
||||||
|
use rand::RngCore;
|
||||||
|
use sampling::source::Source;
|
||||||
|
|
||||||
impl<D: DataMut> ReaderFrom for VecZnx<D> {
|
impl<D: DataMut> ReaderFrom for VecZnx<D> {
|
||||||
fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> {
|
fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use crate::hal::layouts::{Backend, Module, ScalarZnxOwned, ScalarZnxToMut, ScalarZnxToRef};
|
use crate::hal::layouts::{Backend, ScalarZnxOwned};
|
||||||
|
|
||||||
pub unsafe trait ScalarZnxFromBytesImpl<B: Backend> {
|
pub unsafe trait ScalarZnxFromBytesImpl<B: Backend> {
|
||||||
fn scalar_znx_from_bytes_impl(n: usize, cols: usize, bytes: Vec<u8>) -> ScalarZnxOwned;
|
fn scalar_znx_from_bytes_impl(n: usize, cols: usize, bytes: Vec<u8>) -> ScalarZnxOwned;
|
||||||
@@ -11,29 +11,3 @@ pub unsafe trait ScalarZnxAllocBytesImpl<B: Backend> {
|
|||||||
pub unsafe trait ScalarZnxAllocImpl<B: Backend> {
|
pub unsafe trait ScalarZnxAllocImpl<B: Backend> {
|
||||||
fn scalar_znx_alloc_impl(n: usize, cols: usize) -> ScalarZnxOwned;
|
fn scalar_znx_alloc_impl(n: usize, cols: usize) -> ScalarZnxOwned;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe trait ScalarZnxAutomorphismImpl<B: Backend> {
|
|
||||||
fn scalar_znx_automorphism_impl<R, A>(module: &Module<B>, k: i64, res: &mut R, res_col: usize, a: &A, a_col: usize)
|
|
||||||
where
|
|
||||||
R: ScalarZnxToMut,
|
|
||||||
A: ScalarZnxToRef;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub unsafe trait ScalarZnxAutomorphismInplaceIml<B: Backend> {
|
|
||||||
fn scalar_znx_automorphism_inplace_impl<A>(module: &Module<B>, k: i64, a: &mut A, a_col: usize)
|
|
||||||
where
|
|
||||||
A: ScalarZnxToMut;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub unsafe trait ScalarZnxMulXpMinusOneImpl<B: Backend> {
|
|
||||||
fn scalar_znx_mul_xp_minus_one_impl<R, A>(module: &Module<B>, p: i64, r: &mut R, r_col: usize, a: &A, a_col: usize)
|
|
||||||
where
|
|
||||||
R: ScalarZnxToMut,
|
|
||||||
A: ScalarZnxToRef;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub unsafe trait ScalarZnxMulXpMinusOneInplaceImpl<B: Backend> {
|
|
||||||
fn scalar_znx_mul_xp_minus_one_inplace_impl<R>(module: &Module<B>, p: i64, r: &mut R, r_col: usize)
|
|
||||||
where
|
|
||||||
R: ScalarZnxToMut;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1 +1,2 @@
|
|||||||
|
pub mod serialization;
|
||||||
pub mod vec_znx;
|
pub mod vec_znx;
|
||||||
|
|||||||
56
backend/src/hal/tests/serialization.rs
Normal file
56
backend/src/hal/tests/serialization.rs
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
use std::fmt::Debug;
|
||||||
|
|
||||||
|
use sampling::source::Source;
|
||||||
|
|
||||||
|
use crate::hal::{
|
||||||
|
api::{FillUniform, ZnxZero},
|
||||||
|
layouts::{ReaderFrom, WriterTo},
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Generic test for serialization and deserialization.
|
||||||
|
///
|
||||||
|
/// - `T` must implement I/O traits, zeroing, cloning, and random filling.
|
||||||
|
pub fn test_reader_writer_interface<T>(mut original: T)
|
||||||
|
where
|
||||||
|
T: WriterTo + ReaderFrom + PartialEq + Eq + Debug + Clone + ZnxZero + FillUniform,
|
||||||
|
{
|
||||||
|
// Fill original with uniform random data
|
||||||
|
let mut source = Source::new([0u8; 32]);
|
||||||
|
original.fill_uniform(&mut source);
|
||||||
|
|
||||||
|
// Serialize into a buffer
|
||||||
|
let mut buffer = Vec::new();
|
||||||
|
original.write_to(&mut buffer).expect("write_to failed");
|
||||||
|
|
||||||
|
// Prepare receiver: same shape, but zeroed
|
||||||
|
let mut receiver = original.clone();
|
||||||
|
receiver.zero();
|
||||||
|
|
||||||
|
// Deserialize from buffer
|
||||||
|
let mut reader: &[u8] = &buffer;
|
||||||
|
receiver.read_from(&mut reader).expect("read_from failed");
|
||||||
|
|
||||||
|
// Ensure serialization round-trip correctness
|
||||||
|
assert_eq!(
|
||||||
|
&original, &receiver,
|
||||||
|
"Deserialized object does not match the original"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn scalar_znx_serialize() {
|
||||||
|
let original: crate::hal::layouts::ScalarZnx<Vec<u8>> = crate::hal::layouts::ScalarZnx::alloc(1024, 3);
|
||||||
|
test_reader_writer_interface(original);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn vec_znx_serialize() {
|
||||||
|
let original: crate::hal::layouts::VecZnx<Vec<u8>> = crate::hal::layouts::VecZnx::alloc::<i64>(1024, 3, 4);
|
||||||
|
test_reader_writer_interface(original);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn mat_znx_serialize() {
|
||||||
|
let original: crate::hal::layouts::MatZnx<Vec<u8>> = crate::hal::layouts::MatZnx::alloc(1024, 3, 2, 2, 4);
|
||||||
|
test_reader_writer_interface(original);
|
||||||
|
}
|
||||||
@@ -11,7 +11,7 @@ where
|
|||||||
B: CPUAVX,
|
B: CPUAVX,
|
||||||
{
|
{
|
||||||
fn mat_znx_alloc_impl(module: &Module<B>, rows: usize, cols_in: usize, cols_out: usize, size: usize) -> MatZnxOwned {
|
fn mat_znx_alloc_impl(module: &Module<B>, rows: usize, cols_in: usize, cols_out: usize, size: usize) -> MatZnxOwned {
|
||||||
MatZnxOwned::new(module.n(), rows, cols_in, cols_out, size)
|
MatZnxOwned::alloc(module.n(), rows, cols_in, cols_out, size)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -36,6 +36,6 @@ where
|
|||||||
size: usize,
|
size: usize,
|
||||||
bytes: Vec<u8>,
|
bytes: Vec<u8>,
|
||||||
) -> MatZnxOwned {
|
) -> MatZnxOwned {
|
||||||
MatZnxOwned::new_from_bytes(module.n(), rows, cols_in, cols_out, size, bytes)
|
MatZnxOwned::from_bytes(module.n(), rows, cols_in, cols_out, size, bytes)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,9 @@ pub use module_fft64::*;
|
|||||||
pub use module_ntt120::*;
|
pub use module_ntt120::*;
|
||||||
|
|
||||||
/// For external documentation
|
/// For external documentation
|
||||||
pub use vec_znx::{vec_znx_copy_ref, vec_znx_lsh_inplace_ref, vec_znx_merge_ref, vec_znx_rsh_inplace_ref, vec_znx_split_ref, vec_znx_switch_degree_ref};
|
pub use vec_znx::{
|
||||||
|
vec_znx_copy_ref, vec_znx_lsh_inplace_ref, vec_znx_merge_ref, vec_znx_rsh_inplace_ref, vec_znx_split_ref,
|
||||||
|
vec_znx_switch_degree_ref,
|
||||||
|
};
|
||||||
|
|
||||||
pub trait CPUAVX {}
|
pub trait CPUAVX {}
|
||||||
|
|||||||
@@ -1,16 +1,9 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
hal::{
|
hal::{
|
||||||
api::{ZnxInfos, ZnxSliceSize, ZnxView, ZnxViewMut},
|
layouts::{Backend, ScalarZnxOwned},
|
||||||
layouts::{Backend, Module, ScalarZnx, ScalarZnxOwned, ScalarZnxToMut, ScalarZnxToRef},
|
oep::{ScalarZnxAllocBytesImpl, ScalarZnxAllocImpl, ScalarZnxFromBytesImpl},
|
||||||
oep::{
|
|
||||||
ScalarZnxAllocBytesImpl, ScalarZnxAllocImpl, ScalarZnxAutomorphismImpl, ScalarZnxAutomorphismInplaceIml,
|
|
||||||
ScalarZnxFromBytesImpl,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
implementation::cpu_spqlios::{
|
|
||||||
CPUAVX,
|
|
||||||
ffi::{module::module_info_t, vec_znx},
|
|
||||||
},
|
},
|
||||||
|
implementation::cpu_spqlios::CPUAVX,
|
||||||
};
|
};
|
||||||
|
|
||||||
unsafe impl<B: Backend> ScalarZnxAllocBytesImpl<B> for B
|
unsafe impl<B: Backend> ScalarZnxAllocBytesImpl<B> for B
|
||||||
@@ -27,7 +20,7 @@ where
|
|||||||
B: CPUAVX,
|
B: CPUAVX,
|
||||||
{
|
{
|
||||||
fn scalar_znx_alloc_impl(n: usize, cols: usize) -> ScalarZnxOwned {
|
fn scalar_znx_alloc_impl(n: usize, cols: usize) -> ScalarZnxOwned {
|
||||||
ScalarZnxOwned::new(n, cols)
|
ScalarZnxOwned::alloc(n, cols)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -36,65 +29,6 @@ where
|
|||||||
B: CPUAVX,
|
B: CPUAVX,
|
||||||
{
|
{
|
||||||
fn scalar_znx_from_bytes_impl(n: usize, cols: usize, bytes: Vec<u8>) -> ScalarZnxOwned {
|
fn scalar_znx_from_bytes_impl(n: usize, cols: usize, bytes: Vec<u8>) -> ScalarZnxOwned {
|
||||||
ScalarZnxOwned::new_from_bytes(n, cols, bytes)
|
ScalarZnxOwned::from_bytes(n, cols, bytes)
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl<B: Backend> ScalarZnxAutomorphismImpl<B> for B
|
|
||||||
where
|
|
||||||
B: CPUAVX,
|
|
||||||
{
|
|
||||||
fn scalar_znx_automorphism_impl<R, A>(module: &Module<B>, k: i64, res: &mut R, res_col: usize, a: &A, a_col: usize)
|
|
||||||
where
|
|
||||||
R: ScalarZnxToMut,
|
|
||||||
A: ScalarZnxToRef,
|
|
||||||
{
|
|
||||||
let a: ScalarZnx<&[u8]> = a.to_ref();
|
|
||||||
let mut res: ScalarZnx<&mut [u8]> = res.to_mut();
|
|
||||||
#[cfg(debug_assertions)]
|
|
||||||
{
|
|
||||||
assert_eq!(a.n(), module.n());
|
|
||||||
assert_eq!(res.n(), module.n());
|
|
||||||
}
|
|
||||||
unsafe {
|
|
||||||
vec_znx::vec_znx_automorphism(
|
|
||||||
module.ptr() as *const module_info_t,
|
|
||||||
k,
|
|
||||||
res.at_mut_ptr(res_col, 0),
|
|
||||||
res.size() as u64,
|
|
||||||
res.sl() as u64,
|
|
||||||
a.at_ptr(a_col, 0),
|
|
||||||
a.size() as u64,
|
|
||||||
a.sl() as u64,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl<B: Backend> ScalarZnxAutomorphismInplaceIml<B> for B
|
|
||||||
where
|
|
||||||
B: CPUAVX,
|
|
||||||
{
|
|
||||||
fn scalar_znx_automorphism_inplace_impl<A>(module: &Module<B>, k: i64, a: &mut A, a_col: usize)
|
|
||||||
where
|
|
||||||
A: ScalarZnxToMut,
|
|
||||||
{
|
|
||||||
let mut a: ScalarZnx<&mut [u8]> = a.to_mut();
|
|
||||||
#[cfg(debug_assertions)]
|
|
||||||
{
|
|
||||||
assert_eq!(a.n(), module.n());
|
|
||||||
}
|
|
||||||
unsafe {
|
|
||||||
vec_znx::vec_znx_automorphism(
|
|
||||||
module.ptr() as *const module_info_t,
|
|
||||||
k,
|
|
||||||
a.at_mut_ptr(a_col, 0),
|
|
||||||
a.size() as u64,
|
|
||||||
a.sl() as u64,
|
|
||||||
a.at_ptr(a_col, 0),
|
|
||||||
a.size() as u64,
|
|
||||||
a.sl() as u64,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ where
|
|||||||
B: CPUAVX,
|
B: CPUAVX,
|
||||||
{
|
{
|
||||||
fn vec_znx_alloc_impl(n: usize, cols: usize, size: usize) -> VecZnxOwned {
|
fn vec_znx_alloc_impl(n: usize, cols: usize, size: usize) -> VecZnxOwned {
|
||||||
VecZnxOwned::new::<i64>(n, cols, size)
|
VecZnxOwned::alloc::<i64>(n, cols, size)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ sampling = {path="../sampling"}
|
|||||||
rand_distr = {workspace = true}
|
rand_distr = {workspace = true}
|
||||||
itertools = {workspace = true}
|
itertools = {workspace = true}
|
||||||
byteorder = {workspace = true}
|
byteorder = {workspace = true}
|
||||||
|
rand_core = {workspace = true}
|
||||||
|
|
||||||
[[bench]]
|
[[bench]]
|
||||||
name = "external_product_glwe_fft64"
|
name = "external_product_glwe_fft64"
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ impl LookUpTable {
|
|||||||
let size: usize = self.k.div_ceil(self.basek);
|
let size: usize = self.k.div_ceil(self.basek);
|
||||||
|
|
||||||
// Equivalent to AUTO([f(0), -f(n-1), -f(n-2), ..., -f(1)], -1)
|
// Equivalent to AUTO([f(0), -f(n-1), -f(n-2), ..., -f(1)], -1)
|
||||||
let mut lut_full: VecZnx<Vec<u8>> = VecZnx::new::<i64>(domain_size, 1, size);
|
let mut lut_full: VecZnx<Vec<u8>> = VecZnx::alloc::<i64>(domain_size, 1, size);
|
||||||
|
|
||||||
let lut_at: &mut [i64] = lut_full.at_mut(0, limbs - 1);
|
let lut_at: &mut [i64] = lut_full.at_mut(0, limbs - 1);
|
||||||
|
|
||||||
|
|||||||
@@ -1,187 +0,0 @@
|
|||||||
use backend::hal::{
|
|
||||||
api::{MatZnxAlloc, MatZnxAllocBytes},
|
|
||||||
layouts::{Backend, Data, DataMut, DataRef, MatZnx, Module, ReaderFrom, Scratch, VmpPMat, WriterTo},
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::{GGLWEExecLayoutFamily, GLWECiphertext, GLWESwitchingKey, GLWESwitchingKeyExec, Infos};
|
|
||||||
|
|
||||||
#[derive(PartialEq, Eq)]
|
|
||||||
pub struct AutomorphismKey<D: Data> {
|
|
||||||
pub(crate) key: GLWESwitchingKey<D>,
|
|
||||||
pub(crate) p: i64,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AutomorphismKey<Vec<u8>> {
|
|
||||||
pub fn alloc<B: Backend>(module: &Module<B>, basek: usize, k: usize, rows: usize, digits: usize, rank: usize) -> Self
|
|
||||||
where
|
|
||||||
Module<B>: MatZnxAlloc,
|
|
||||||
{
|
|
||||||
AutomorphismKey {
|
|
||||||
key: GLWESwitchingKey::alloc(module, basek, k, rows, digits, rank, rank),
|
|
||||||
p: 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn bytes_of<B: Backend>(module: &Module<B>, basek: usize, k: usize, rows: usize, digits: usize, rank: usize) -> usize
|
|
||||||
where
|
|
||||||
Module<B>: MatZnxAllocBytes,
|
|
||||||
{
|
|
||||||
GLWESwitchingKey::<Vec<u8>>::bytes_of(module, basek, k, rows, digits, rank, rank)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<D: Data> Infos for AutomorphismKey<D> {
|
|
||||||
type Inner = MatZnx<D>;
|
|
||||||
|
|
||||||
fn inner(&self) -> &Self::Inner {
|
|
||||||
&self.key.inner()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn basek(&self) -> usize {
|
|
||||||
self.key.basek()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn k(&self) -> usize {
|
|
||||||
self.key.k()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<D: Data> AutomorphismKey<D> {
|
|
||||||
pub fn p(&self) -> i64 {
|
|
||||||
self.p
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn digits(&self) -> usize {
|
|
||||||
self.key.digits()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn rank(&self) -> usize {
|
|
||||||
self.key.rank()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn rank_in(&self) -> usize {
|
|
||||||
self.key.rank_in()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn rank_out(&self) -> usize {
|
|
||||||
self.key.rank_out()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<D: DataRef> AutomorphismKey<D> {
|
|
||||||
pub fn at(&self, row: usize, col: usize) -> GLWECiphertext<&[u8]> {
|
|
||||||
self.key.at(row, col)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<D: DataMut> AutomorphismKey<D> {
|
|
||||||
pub fn at_mut(&mut self, row: usize, col: usize) -> GLWECiphertext<&mut [u8]> {
|
|
||||||
self.key.at_mut(row, col)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
|
|
||||||
|
|
||||||
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 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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(PartialEq, Eq)]
|
|
||||||
pub struct AutomorphismKeyExec<D: Data, B: Backend> {
|
|
||||||
pub(crate) key: GLWESwitchingKeyExec<D, B>,
|
|
||||||
pub(crate) p: i64,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<B: Backend> AutomorphismKeyExec<Vec<u8>, B> {
|
|
||||||
pub fn alloc(module: &Module<B>, basek: usize, k: usize, rows: usize, digits: usize, rank: usize) -> Self
|
|
||||||
where
|
|
||||||
Module<B>: GGLWEExecLayoutFamily<B>,
|
|
||||||
{
|
|
||||||
AutomorphismKeyExec::<Vec<u8>, B> {
|
|
||||||
key: GLWESwitchingKeyExec::alloc(module, basek, k, rows, digits, rank, rank),
|
|
||||||
p: 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn bytes_of(module: &Module<B>, basek: usize, k: usize, rows: usize, digits: usize, rank: usize) -> usize
|
|
||||||
where
|
|
||||||
Module<B>: GGLWEExecLayoutFamily<B>,
|
|
||||||
{
|
|
||||||
GLWESwitchingKeyExec::<Vec<u8>, B>::bytes_of(module, basek, k, rows, digits, rank, rank)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn from<DataOther: DataRef>(module: &Module<B>, other: &AutomorphismKey<DataOther>, scratch: &mut Scratch<B>) -> Self
|
|
||||||
where
|
|
||||||
Module<B>: GGLWEExecLayoutFamily<B>,
|
|
||||||
{
|
|
||||||
let mut atk_exec: AutomorphismKeyExec<Vec<u8>, B> = Self::alloc(
|
|
||||||
module,
|
|
||||||
other.basek(),
|
|
||||||
other.k(),
|
|
||||||
other.rows(),
|
|
||||||
other.digits(),
|
|
||||||
other.rank(),
|
|
||||||
);
|
|
||||||
atk_exec.prepare(module, other, scratch);
|
|
||||||
atk_exec
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<D: DataMut, B: Backend> AutomorphismKeyExec<D, B> {
|
|
||||||
pub fn prepare<DataOther>(&mut self, module: &Module<B>, other: &AutomorphismKey<DataOther>, scratch: &mut Scratch<B>)
|
|
||||||
where
|
|
||||||
DataOther: DataRef,
|
|
||||||
Module<B>: GGLWEExecLayoutFamily<B>,
|
|
||||||
{
|
|
||||||
self.key.prepare(module, &other.key, scratch);
|
|
||||||
self.p = other.p;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<D: Data, B: Backend> Infos for AutomorphismKeyExec<D, B> {
|
|
||||||
type Inner = VmpPMat<D, B>;
|
|
||||||
|
|
||||||
fn inner(&self) -> &Self::Inner {
|
|
||||||
&self.key.inner()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn basek(&self) -> usize {
|
|
||||||
self.key.basek()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn k(&self) -> usize {
|
|
||||||
self.key.k()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<D: Data, B: Backend> AutomorphismKeyExec<D, B> {
|
|
||||||
pub fn p(&self) -> i64 {
|
|
||||||
self.p
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn digits(&self) -> usize {
|
|
||||||
self.key.digits()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn rank(&self) -> usize {
|
|
||||||
self.key.rank()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn rank_in(&self) -> usize {
|
|
||||||
self.key.rank_in()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn rank_out(&self) -> usize {
|
|
||||||
self.key.rank_out()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
use backend::hal::{
|
use backend::hal::{
|
||||||
api::{
|
api::{
|
||||||
ScalarZnxAllocBytes, ScalarZnxAutomorphism, ScratchAvailable, SvpApply, TakeScalarZnx, TakeVecZnx, TakeVecZnxBig,
|
ScalarZnxAllocBytes, ScratchAvailable, SvpApply, TakeScalarZnx, TakeVecZnx, TakeVecZnxBig, TakeVecZnxDft,
|
||||||
TakeVecZnxDft, VecZnxAddScalarInplace, VecZnxAllocBytes, VecZnxBigAllocBytes, VecZnxDftToVecZnxBigTmpA,
|
VecZnxAddScalarInplace, VecZnxAllocBytes, VecZnxAutomorphism, VecZnxBigAllocBytes, VecZnxDftToVecZnxBigTmpA,
|
||||||
VecZnxNormalizeInplace, VecZnxNormalizeTmpBytes, VecZnxSwithcDegree, ZnxZero,
|
VecZnxNormalizeInplace, VecZnxNormalizeTmpBytes, VecZnxSwithcDegree, ZnxZero,
|
||||||
},
|
},
|
||||||
layouts::{Backend, DataMut, DataRef, Module, ScalarZnx, Scratch},
|
layouts::{Backend, DataMut, DataRef, Module, ScalarZnx, Scratch},
|
||||||
@@ -9,8 +9,10 @@ use backend::hal::{
|
|||||||
use sampling::source::Source;
|
use sampling::source::Source;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
AutomorphismKey, GGLWECiphertext, GLWECiphertext, GLWEDecryptFamily, GLWEEncryptSkFamily, GLWEPlaintext, GLWESecret,
|
AutomorphismKey, AutomorphismKeyCompressed, GGLWECiphertext, GGLWECiphertextCompressed, GLWECiphertext, GLWEDecryptFamily,
|
||||||
GLWESecretExec, GLWESecretFamily, GLWESwitchingKey, GLWETensorKey, Infos, TakeGLWEPt, TakeGLWESecret, TakeGLWESecretExec,
|
GLWEEncryptSkFamily, GLWEPlaintext, GLWESecret, GLWESecretExec, GLWESecretFamily, GLWESwitchingKey,
|
||||||
|
GLWESwitchingKeyCompressed, GLWETensorKey, GLWETensorKeyCompressed, Infos, TakeGLWEPt, TakeGLWESecret, TakeGLWESecretExec,
|
||||||
|
encrypt_sk_internal,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub trait GGLWEEncryptSkFamily<B: Backend> = GLWEEncryptSkFamily<B> + GLWESecretFamily<B>;
|
pub trait GGLWEEncryptSkFamily<B: Backend> = GLWEEncryptSkFamily<B> + GLWESecretFamily<B>;
|
||||||
@@ -122,6 +124,112 @@ impl<DataSelf: DataMut> GGLWECiphertext<DataSelf> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl GGLWECiphertextCompressed<Vec<u8>> {
|
||||||
|
pub fn encrypt_sk_scratch_space<B: Backend>(module: &Module<B>, basek: usize, k: usize) -> usize
|
||||||
|
where
|
||||||
|
Module<B>: GLWESwitchingKeyEncryptSkFamily<B> + VecZnxAllocBytes,
|
||||||
|
{
|
||||||
|
GGLWECiphertext::encrypt_sk_scratch_space(module, basek, k)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D: DataMut> GGLWECiphertextCompressed<D> {
|
||||||
|
pub fn encrypt_sk<DataPt: DataRef, DataSk: DataRef, B: Backend>(
|
||||||
|
&mut self,
|
||||||
|
module: &Module<B>,
|
||||||
|
pt: &ScalarZnx<DataPt>,
|
||||||
|
sk: &GLWESecretExec<DataSk, B>,
|
||||||
|
seed: [u8; 32],
|
||||||
|
source_xe: &mut Source,
|
||||||
|
sigma: f64,
|
||||||
|
scratch: &mut Scratch<B>,
|
||||||
|
) where
|
||||||
|
Module<B>: GGLWEEncryptSkFamily<B> + VecZnxAllocBytes + VecZnxAddScalarInplace,
|
||||||
|
Scratch<B>: TakeVecZnxDft<B> + ScratchAvailable + TakeVecZnx<B>,
|
||||||
|
{
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
{
|
||||||
|
use backend::hal::api::ZnxInfos;
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
self.rank_in(),
|
||||||
|
pt.cols(),
|
||||||
|
"self.rank_in(): {} != pt.cols(): {}",
|
||||||
|
self.rank_in(),
|
||||||
|
pt.cols()
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
self.rank_out(),
|
||||||
|
sk.rank(),
|
||||||
|
"self.rank_out(): {} != sk.rank(): {}",
|
||||||
|
self.rank_out(),
|
||||||
|
sk.rank()
|
||||||
|
);
|
||||||
|
assert_eq!(self.n(), module.n());
|
||||||
|
assert_eq!(sk.n(), module.n());
|
||||||
|
assert_eq!(pt.n(), module.n());
|
||||||
|
assert!(
|
||||||
|
scratch.available() >= GGLWECiphertextCompressed::encrypt_sk_scratch_space(module, self.basek(), self.k()),
|
||||||
|
"scratch.available: {} < GGLWECiphertext::encrypt_sk_scratch_space(module, self.rank()={}, self.size()={}): {}",
|
||||||
|
scratch.available(),
|
||||||
|
self.rank(),
|
||||||
|
self.size(),
|
||||||
|
GGLWECiphertextCompressed::encrypt_sk_scratch_space(module, self.basek(), self.k())
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
self.rows() * self.digits() * self.basek() <= self.k(),
|
||||||
|
"self.rows() : {} * self.digits() : {} * self.basek() : {} = {} >= self.k() = {}",
|
||||||
|
self.rows(),
|
||||||
|
self.digits(),
|
||||||
|
self.basek(),
|
||||||
|
self.rows() * self.digits() * self.basek(),
|
||||||
|
self.k()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let rows: usize = self.rows();
|
||||||
|
let digits: usize = self.digits();
|
||||||
|
let basek: usize = self.basek();
|
||||||
|
let k: usize = self.k();
|
||||||
|
let rank_in: usize = self.rank_in();
|
||||||
|
|
||||||
|
let mut source_xa = Source::new(seed);
|
||||||
|
|
||||||
|
let (mut tmp_pt, scrach_1) = scratch.take_glwe_pt(module, basek, k);
|
||||||
|
(0..rank_in).for_each(|col_i| {
|
||||||
|
(0..rows).for_each(|row_i| {
|
||||||
|
// Adds the scalar_znx_pt to the i-th limb of the vec_znx_pt
|
||||||
|
tmp_pt.data.zero(); // zeroes for next iteration
|
||||||
|
module.vec_znx_add_scalar_inplace(
|
||||||
|
&mut tmp_pt.data,
|
||||||
|
0,
|
||||||
|
(digits - 1) + row_i * digits,
|
||||||
|
pt,
|
||||||
|
col_i,
|
||||||
|
);
|
||||||
|
module.vec_znx_normalize_inplace(basek, &mut tmp_pt.data, 0, scrach_1);
|
||||||
|
|
||||||
|
let (seed, mut source_xa_tmp) = source_xa.branch();
|
||||||
|
self.seed[col_i * rows + row_i] = seed;
|
||||||
|
|
||||||
|
encrypt_sk_internal(
|
||||||
|
module,
|
||||||
|
self.basek(),
|
||||||
|
self.k(),
|
||||||
|
&mut self.at_mut(row_i, col_i).data,
|
||||||
|
true,
|
||||||
|
Some((&tmp_pt, 0)),
|
||||||
|
sk,
|
||||||
|
&mut source_xa_tmp,
|
||||||
|
source_xe,
|
||||||
|
sigma,
|
||||||
|
scrach_1,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub trait GLWESwitchingKeyEncryptSkFamily<B: Backend> = GGLWEEncryptSkFamily<B>;
|
pub trait GLWESwitchingKeyEncryptSkFamily<B: Backend> = GGLWEEncryptSkFamily<B>;
|
||||||
|
|
||||||
impl GLWESwitchingKey<Vec<u8>> {
|
impl GLWESwitchingKey<Vec<u8>> {
|
||||||
@@ -197,14 +305,19 @@ impl<DataSelf: DataMut> GLWESwitchingKey<DataSelf> {
|
|||||||
|
|
||||||
let (mut sk_in_tmp, scratch1) = scratch.take_scalar_znx(module, sk_in.rank());
|
let (mut sk_in_tmp, scratch1) = scratch.take_scalar_znx(module, sk_in.rank());
|
||||||
(0..sk_in.rank()).for_each(|i| {
|
(0..sk_in.rank()).for_each(|i| {
|
||||||
module.vec_znx_switch_degree(&mut sk_in_tmp, i, &sk_in.data, i);
|
module.vec_znx_switch_degree(
|
||||||
|
&mut sk_in_tmp.as_vec_znx_mut(),
|
||||||
|
i,
|
||||||
|
&sk_in.data.as_vec_znx(),
|
||||||
|
i,
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
let (mut sk_out_tmp, scratch2) = scratch1.take_glwe_secret_exec(module, sk_out.rank());
|
let (mut sk_out_tmp, scratch2) = scratch1.take_glwe_secret_exec(module, sk_out.rank());
|
||||||
{
|
{
|
||||||
let (mut tmp, _) = scratch2.take_scalar_znx(module, 1);
|
let (mut tmp, _) = scratch2.take_scalar_znx(module, 1);
|
||||||
(0..sk_out.rank()).for_each(|i| {
|
(0..sk_out.rank()).for_each(|i| {
|
||||||
module.vec_znx_switch_degree(&mut tmp, 0, &sk_out.data, i);
|
module.vec_znx_switch_degree(&mut tmp.as_vec_znx_mut(), 0, &sk_out.data.as_vec_znx(), i);
|
||||||
module.svp_prepare(&mut sk_out_tmp.data, i, &tmp, 0);
|
module.svp_prepare(&mut sk_out_tmp.data, i, &tmp, 0);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -223,6 +336,100 @@ impl<DataSelf: DataMut> GLWESwitchingKey<DataSelf> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl GLWESwitchingKeyCompressed<Vec<u8>> {
|
||||||
|
pub fn encrypt_sk_scratch_space<B: Backend>(
|
||||||
|
module: &Module<B>,
|
||||||
|
basek: usize,
|
||||||
|
k: usize,
|
||||||
|
rank_in: usize,
|
||||||
|
rank_out: usize,
|
||||||
|
) -> usize
|
||||||
|
where
|
||||||
|
Module<B>: GLWESwitchingKeyEncryptSkFamily<B> + ScalarZnxAllocBytes + VecZnxAllocBytes,
|
||||||
|
{
|
||||||
|
(GGLWECiphertext::encrypt_sk_scratch_space(module, basek, k) | module.scalar_znx_alloc_bytes(1))
|
||||||
|
+ module.scalar_znx_alloc_bytes(rank_in)
|
||||||
|
+ GLWESecretExec::bytes_of(module, rank_out)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<DataSelf: DataMut> GLWESwitchingKeyCompressed<DataSelf> {
|
||||||
|
pub fn encrypt_sk<DataSkIn: DataRef, DataSkOut: DataRef, B: Backend>(
|
||||||
|
&mut self,
|
||||||
|
module: &Module<B>,
|
||||||
|
sk_in: &GLWESecret<DataSkIn>,
|
||||||
|
sk_out: &GLWESecret<DataSkOut>,
|
||||||
|
seed_xa: [u8; 32],
|
||||||
|
source_xe: &mut Source,
|
||||||
|
sigma: f64,
|
||||||
|
scratch: &mut Scratch<B>,
|
||||||
|
) where
|
||||||
|
Module<B>: GLWESwitchingKeyEncryptSkFamily<B>
|
||||||
|
+ ScalarZnxAllocBytes
|
||||||
|
+ VecZnxSwithcDegree
|
||||||
|
+ VecZnxAllocBytes
|
||||||
|
+ VecZnxAddScalarInplace,
|
||||||
|
Scratch<B>:
|
||||||
|
ScratchAvailable + TakeScalarZnx<B> + TakeVecZnxDft<B> + TakeGLWESecretExec<B> + ScratchAvailable + TakeVecZnx<B>,
|
||||||
|
{
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
{
|
||||||
|
assert!(sk_in.n() <= module.n());
|
||||||
|
assert!(sk_out.n() <= module.n());
|
||||||
|
assert!(
|
||||||
|
scratch.available()
|
||||||
|
>= GLWESwitchingKey::encrypt_sk_scratch_space(
|
||||||
|
module,
|
||||||
|
self.basek(),
|
||||||
|
self.k(),
|
||||||
|
self.rank_in(),
|
||||||
|
self.rank_out()
|
||||||
|
),
|
||||||
|
"scratch.available()={} < GLWESwitchingKey::encrypt_sk_scratch_space={}",
|
||||||
|
scratch.available(),
|
||||||
|
GLWESwitchingKey::encrypt_sk_scratch_space(
|
||||||
|
module,
|
||||||
|
self.basek(),
|
||||||
|
self.k(),
|
||||||
|
self.rank_in(),
|
||||||
|
self.rank_out()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
let (mut sk_in_tmp, scratch1) = scratch.take_scalar_znx(module, sk_in.rank());
|
||||||
|
(0..sk_in.rank()).for_each(|i| {
|
||||||
|
module.vec_znx_switch_degree(
|
||||||
|
&mut sk_in_tmp.as_vec_znx_mut(),
|
||||||
|
i,
|
||||||
|
&sk_in.data.as_vec_znx(),
|
||||||
|
i,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
let (mut sk_out_tmp, scratch2) = scratch1.take_glwe_secret_exec(module, sk_out.rank());
|
||||||
|
{
|
||||||
|
let (mut tmp, _) = scratch2.take_scalar_znx(module, 1);
|
||||||
|
(0..sk_out.rank()).for_each(|i| {
|
||||||
|
module.vec_znx_switch_degree(&mut tmp.as_vec_znx_mut(), 0, &sk_out.data.as_vec_znx(), i);
|
||||||
|
module.svp_prepare(&mut sk_out_tmp.data, i, &tmp, 0);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
self.key.encrypt_sk(
|
||||||
|
module,
|
||||||
|
&sk_in_tmp,
|
||||||
|
&sk_out_tmp,
|
||||||
|
seed_xa,
|
||||||
|
source_xe,
|
||||||
|
sigma,
|
||||||
|
scratch2,
|
||||||
|
);
|
||||||
|
self.sk_in_n = sk_in.n();
|
||||||
|
self.sk_out_n = sk_out.n();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub trait AutomorphismKeyEncryptSkFamily<B: Backend> = GGLWEEncryptSkFamily<B>;
|
pub trait AutomorphismKeyEncryptSkFamily<B: Backend> = GGLWEEncryptSkFamily<B>;
|
||||||
|
|
||||||
impl AutomorphismKey<Vec<u8>> {
|
impl AutomorphismKey<Vec<u8>> {
|
||||||
@@ -250,9 +457,9 @@ impl<DataSelf: DataMut> AutomorphismKey<DataSelf> {
|
|||||||
scratch: &mut Scratch<B>,
|
scratch: &mut Scratch<B>,
|
||||||
) where
|
) where
|
||||||
Module<B>: AutomorphismKeyEncryptSkFamily<B>
|
Module<B>: AutomorphismKeyEncryptSkFamily<B>
|
||||||
+ ScalarZnxAutomorphism
|
|
||||||
+ ScalarZnxAllocBytes
|
+ ScalarZnxAllocBytes
|
||||||
+ VecZnxAllocBytes
|
+ VecZnxAllocBytes
|
||||||
|
+ VecZnxAutomorphism
|
||||||
+ VecZnxSwithcDegree
|
+ VecZnxSwithcDegree
|
||||||
+ VecZnxAddScalarInplace,
|
+ VecZnxAddScalarInplace,
|
||||||
Scratch<B>: ScratchAvailable + TakeScalarZnx<B> + TakeVecZnxDft<B> + TakeGLWESecretExec<B> + TakeVecZnx<B>,
|
Scratch<B>: ScratchAvailable + TakeScalarZnx<B> + TakeVecZnxDft<B> + TakeGLWESecretExec<B> + TakeVecZnx<B>,
|
||||||
@@ -277,11 +484,11 @@ impl<DataSelf: DataMut> AutomorphismKey<DataSelf> {
|
|||||||
|
|
||||||
{
|
{
|
||||||
(0..self.rank()).for_each(|i| {
|
(0..self.rank()).for_each(|i| {
|
||||||
module.scalar_znx_automorphism(
|
module.vec_znx_automorphism(
|
||||||
module.galois_element_inv(p),
|
module.galois_element_inv(p),
|
||||||
&mut sk_out.data,
|
&mut sk_out.data.as_vec_znx_mut(),
|
||||||
i,
|
i,
|
||||||
&sk.data,
|
&sk.data.as_vec_znx(),
|
||||||
i,
|
i,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@@ -294,6 +501,72 @@ impl<DataSelf: DataMut> AutomorphismKey<DataSelf> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl AutomorphismKeyCompressed<Vec<u8>> {
|
||||||
|
pub fn encrypt_sk_scratch_space<B: Backend>(module: &Module<B>, basek: usize, k: usize, rank: usize) -> usize
|
||||||
|
where
|
||||||
|
Module<B>: AutomorphismKeyEncryptSkFamily<B> + ScalarZnxAllocBytes + VecZnxAllocBytes,
|
||||||
|
{
|
||||||
|
GLWESwitchingKeyCompressed::encrypt_sk_scratch_space(module, basek, k, rank, rank) + GLWESecret::bytes_of(module, rank)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<DataSelf: DataMut> AutomorphismKeyCompressed<DataSelf> {
|
||||||
|
pub fn encrypt_sk<DataSk: DataRef, B: Backend>(
|
||||||
|
&mut self,
|
||||||
|
module: &Module<B>,
|
||||||
|
p: i64,
|
||||||
|
sk: &GLWESecret<DataSk>,
|
||||||
|
seed_xa: [u8; 32],
|
||||||
|
source_xe: &mut Source,
|
||||||
|
sigma: f64,
|
||||||
|
scratch: &mut Scratch<B>,
|
||||||
|
) where
|
||||||
|
Module<B>: AutomorphismKeyEncryptSkFamily<B>
|
||||||
|
+ ScalarZnxAllocBytes
|
||||||
|
+ VecZnxAllocBytes
|
||||||
|
+ VecZnxSwithcDegree
|
||||||
|
+ VecZnxAutomorphism
|
||||||
|
+ VecZnxAddScalarInplace,
|
||||||
|
Scratch<B>: ScratchAvailable + TakeScalarZnx<B> + TakeVecZnxDft<B> + TakeGLWESecretExec<B> + TakeVecZnx<B>,
|
||||||
|
{
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
{
|
||||||
|
assert_eq!(self.n(), module.n());
|
||||||
|
assert_eq!(sk.n(), module.n());
|
||||||
|
assert_eq!(self.rank_out(), self.rank_in());
|
||||||
|
assert_eq!(sk.rank(), self.rank());
|
||||||
|
assert!(
|
||||||
|
scratch.available()
|
||||||
|
>= AutomorphismKeyCompressed::encrypt_sk_scratch_space(module, self.basek(), self.k(), self.rank()),
|
||||||
|
"scratch.available(): {} < AutomorphismKey::encrypt_sk_scratch_space(module, self.rank()={}, self.size()={}): {}",
|
||||||
|
scratch.available(),
|
||||||
|
self.rank(),
|
||||||
|
self.size(),
|
||||||
|
AutomorphismKeyCompressed::encrypt_sk_scratch_space(module, self.basek(), self.k(), self.rank())
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
let (mut sk_out, scratch_1) = scratch.take_glwe_secret(module, sk.rank());
|
||||||
|
|
||||||
|
{
|
||||||
|
(0..self.rank()).for_each(|i| {
|
||||||
|
module.vec_znx_automorphism(
|
||||||
|
module.galois_element_inv(p),
|
||||||
|
&mut sk_out.data.as_vec_znx_mut(),
|
||||||
|
i,
|
||||||
|
&sk.data.as_vec_znx(),
|
||||||
|
i,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
self.key
|
||||||
|
.encrypt_sk(module, &sk, &sk_out, seed_xa, source_xe, sigma, scratch_1);
|
||||||
|
|
||||||
|
self.p = p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub trait GLWETensorKeyEncryptSkFamily<B: Backend> =
|
pub trait GLWETensorKeyEncryptSkFamily<B: Backend> =
|
||||||
GGLWEEncryptSkFamily<B> + VecZnxBigAllocBytes + VecZnxDftToVecZnxBigTmpA<B> + SvpApply<B>;
|
GGLWEEncryptSkFamily<B> + VecZnxBigAllocBytes + VecZnxDftToVecZnxBigTmpA<B> + SvpApply<B>;
|
||||||
|
|
||||||
@@ -344,7 +617,7 @@ impl<DataSelf: DataMut> GLWETensorKey<DataSelf> {
|
|||||||
let (mut sk_dft, scratch2) = scratch1.take_vec_znx_dft(module, rank, 1);
|
let (mut sk_dft, scratch2) = scratch1.take_vec_znx_dft(module, rank, 1);
|
||||||
|
|
||||||
(0..rank).for_each(|i| {
|
(0..rank).for_each(|i| {
|
||||||
module.vec_znx_dft_from_vec_znx(1, 0, &mut sk_dft, i, &sk.data, i);
|
module.vec_znx_dft_from_vec_znx(1, 0, &mut sk_dft, i, &sk.data.as_vec_znx(), i);
|
||||||
});
|
});
|
||||||
|
|
||||||
let (mut sk_ij_big, scratch3) = scratch2.take_vec_znx_big(module, 1, 1);
|
let (mut sk_ij_big, scratch3) = scratch2.take_vec_znx_big(module, 1, 1);
|
||||||
@@ -356,7 +629,14 @@ impl<DataSelf: DataMut> GLWETensorKey<DataSelf> {
|
|||||||
module.svp_apply(&mut sk_ij_dft, 0, &sk_dft_prep.data, j, &sk_dft, i);
|
module.svp_apply(&mut sk_ij_dft, 0, &sk_dft_prep.data, j, &sk_dft, i);
|
||||||
|
|
||||||
module.vec_znx_dft_to_vec_znx_big_tmp_a(&mut sk_ij_big, 0, &mut sk_ij_dft, 0);
|
module.vec_znx_dft_to_vec_znx_big_tmp_a(&mut sk_ij_big, 0, &mut sk_ij_dft, 0);
|
||||||
module.vec_znx_big_normalize(self.basek(), &mut sk_ij.data, 0, &sk_ij_big, 0, scratch5);
|
module.vec_znx_big_normalize(
|
||||||
|
self.basek(),
|
||||||
|
&mut sk_ij.data.as_vec_znx_mut(),
|
||||||
|
0,
|
||||||
|
&sk_ij_big,
|
||||||
|
0,
|
||||||
|
scratch5,
|
||||||
|
);
|
||||||
|
|
||||||
self.at_mut(i, j)
|
self.at_mut(i, j)
|
||||||
.encrypt_sk(module, &sk_ij, sk, source_xa, source_xe, sigma, scratch5);
|
.encrypt_sk(module, &sk_ij, sk, source_xa, source_xe, sigma, scratch5);
|
||||||
@@ -364,3 +644,77 @@ impl<DataSelf: DataMut> GLWETensorKey<DataSelf> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl GLWETensorKeyCompressed<Vec<u8>> {
|
||||||
|
pub fn encrypt_sk_scratch_space<B: Backend>(module: &Module<B>, basek: usize, k: usize, rank: usize) -> usize
|
||||||
|
where
|
||||||
|
Module<B>: GLWETensorKeyEncryptSkFamily<B> + ScalarZnxAllocBytes + VecZnxAllocBytes,
|
||||||
|
{
|
||||||
|
GLWETensorKey::encrypt_sk_scratch_space(module, basek, k, rank)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<DataSelf: DataMut> GLWETensorKeyCompressed<DataSelf> {
|
||||||
|
pub fn encrypt_sk<DataSk: DataRef, B: Backend>(
|
||||||
|
&mut self,
|
||||||
|
module: &Module<B>,
|
||||||
|
sk: &GLWESecret<DataSk>,
|
||||||
|
seed_xa: [u8; 32],
|
||||||
|
source_xe: &mut Source,
|
||||||
|
sigma: f64,
|
||||||
|
scratch: &mut Scratch<B>,
|
||||||
|
) where
|
||||||
|
Module<B>: GLWETensorKeyEncryptSkFamily<B>
|
||||||
|
+ ScalarZnxAllocBytes
|
||||||
|
+ VecZnxSwithcDegree
|
||||||
|
+ VecZnxAllocBytes
|
||||||
|
+ VecZnxAddScalarInplace,
|
||||||
|
Scratch<B>:
|
||||||
|
ScratchAvailable + TakeVecZnxDft<B> + TakeVecZnxBig<B> + TakeGLWESecretExec<B> + TakeScalarZnx<B> + TakeVecZnx<B>,
|
||||||
|
{
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
{
|
||||||
|
assert_eq!(self.rank(), sk.rank());
|
||||||
|
assert_eq!(self.n(), module.n());
|
||||||
|
assert_eq!(sk.n(), module.n());
|
||||||
|
}
|
||||||
|
|
||||||
|
let rank: usize = self.rank();
|
||||||
|
|
||||||
|
let (mut sk_dft_prep, scratch1) = scratch.take_glwe_secret_exec(module, rank);
|
||||||
|
sk_dft_prep.prepare(module, &sk);
|
||||||
|
|
||||||
|
let (mut sk_dft, scratch2) = scratch1.take_vec_znx_dft(module, rank, 1);
|
||||||
|
|
||||||
|
(0..rank).for_each(|i| {
|
||||||
|
module.vec_znx_dft_from_vec_znx(1, 0, &mut sk_dft, i, &sk.data.as_vec_znx(), i);
|
||||||
|
});
|
||||||
|
|
||||||
|
let (mut sk_ij_big, scratch3) = scratch2.take_vec_znx_big(module, 1, 1);
|
||||||
|
let (mut sk_ij, scratch4) = scratch3.take_glwe_secret(module, 1);
|
||||||
|
let (mut sk_ij_dft, scratch5) = scratch4.take_vec_znx_dft(module, 1, 1);
|
||||||
|
|
||||||
|
let mut source_xa: Source = Source::new(seed_xa);
|
||||||
|
|
||||||
|
(0..rank).for_each(|i| {
|
||||||
|
(i..rank).for_each(|j| {
|
||||||
|
module.svp_apply(&mut sk_ij_dft, 0, &sk_dft_prep.data, j, &sk_dft, i);
|
||||||
|
|
||||||
|
module.vec_znx_dft_to_vec_znx_big_tmp_a(&mut sk_ij_big, 0, &mut sk_ij_dft, 0);
|
||||||
|
module.vec_znx_big_normalize(
|
||||||
|
self.basek(),
|
||||||
|
&mut sk_ij.data.as_vec_znx_mut(),
|
||||||
|
0,
|
||||||
|
&sk_ij_big,
|
||||||
|
0,
|
||||||
|
scratch5,
|
||||||
|
);
|
||||||
|
|
||||||
|
let (seed_xa_tmp, _) = source_xa.branch();
|
||||||
|
|
||||||
|
self.at_mut(i, j)
|
||||||
|
.encrypt_sk(module, &sk_ij, sk, seed_xa_tmp, source_xe, sigma, scratch5);
|
||||||
|
});
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,227 +0,0 @@
|
|||||||
use backend::hal::{
|
|
||||||
api::{MatZnxAlloc, MatZnxAllocBytes},
|
|
||||||
layouts::{Backend, Data, DataMut, DataRef, MatZnx, Module, ReaderFrom, Scratch, VmpPMat, WriterTo},
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::{GGLWECiphertext, GGLWECiphertextExec, GGLWEExecLayoutFamily, GLWECiphertext, Infos};
|
|
||||||
|
|
||||||
#[derive(PartialEq, Eq)]
|
|
||||||
pub struct GLWESwitchingKey<D: Data> {
|
|
||||||
pub(crate) key: GGLWECiphertext<D>,
|
|
||||||
pub(crate) sk_in_n: usize, // Degree of sk_in
|
|
||||||
pub(crate) sk_out_n: usize, // Degree of sk_out
|
|
||||||
}
|
|
||||||
|
|
||||||
impl GLWESwitchingKey<Vec<u8>> {
|
|
||||||
pub fn alloc<B: Backend>(
|
|
||||||
module: &Module<B>,
|
|
||||||
basek: usize,
|
|
||||||
k: usize,
|
|
||||||
rows: usize,
|
|
||||||
digits: usize,
|
|
||||||
rank_in: usize,
|
|
||||||
rank_out: usize,
|
|
||||||
) -> Self
|
|
||||||
where
|
|
||||||
Module<B>: MatZnxAlloc,
|
|
||||||
{
|
|
||||||
GLWESwitchingKey {
|
|
||||||
key: GGLWECiphertext::alloc(module, basek, k, rows, digits, rank_in, rank_out),
|
|
||||||
sk_in_n: 0,
|
|
||||||
sk_out_n: 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn bytes_of<B: Backend>(
|
|
||||||
module: &Module<B>,
|
|
||||||
basek: usize,
|
|
||||||
k: usize,
|
|
||||||
rows: usize,
|
|
||||||
digits: usize,
|
|
||||||
rank_in: usize,
|
|
||||||
rank_out: usize,
|
|
||||||
) -> usize
|
|
||||||
where
|
|
||||||
Module<B>: MatZnxAllocBytes,
|
|
||||||
{
|
|
||||||
GGLWECiphertext::<Vec<u8>>::bytes_of(module, basek, k, rows, digits, rank_in, rank_out)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<D: Data> Infos for GLWESwitchingKey<D> {
|
|
||||||
type Inner = MatZnx<D>;
|
|
||||||
|
|
||||||
fn inner(&self) -> &Self::Inner {
|
|
||||||
self.key.inner()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn basek(&self) -> usize {
|
|
||||||
self.key.basek()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn k(&self) -> usize {
|
|
||||||
self.key.k()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<D: Data> GLWESwitchingKey<D> {
|
|
||||||
pub fn rank(&self) -> usize {
|
|
||||||
self.key.data.cols_out() - 1
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn rank_in(&self) -> usize {
|
|
||||||
self.key.data.cols_in()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn rank_out(&self) -> usize {
|
|
||||||
self.key.data.cols_out() - 1
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn digits(&self) -> usize {
|
|
||||||
self.key.digits()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn sk_degree_in(&self) -> usize {
|
|
||||||
self.sk_in_n
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn sk_degree_out(&self) -> usize {
|
|
||||||
self.sk_out_n
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<D: DataRef> GLWESwitchingKey<D> {
|
|
||||||
pub fn at(&self, row: usize, col: usize) -> GLWECiphertext<&[u8]> {
|
|
||||||
self.key.at(row, col)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<D: DataMut> GLWESwitchingKey<D> {
|
|
||||||
pub fn at_mut(&mut self, row: usize, col: usize) -> GLWECiphertext<&mut [u8]> {
|
|
||||||
self.key.at_mut(row, col)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
|
|
||||||
|
|
||||||
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;
|
|
||||||
self.key.read_from(reader)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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)?;
|
|
||||||
self.key.write_to(writer)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(PartialEq, Eq)]
|
|
||||||
pub struct GLWESwitchingKeyExec<D: Data, B: Backend> {
|
|
||||||
pub(crate) key: GGLWECiphertextExec<D, B>,
|
|
||||||
pub(crate) sk_in_n: usize, // Degree of sk_in
|
|
||||||
pub(crate) sk_out_n: usize, // Degree of sk_out
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<B: Backend> GLWESwitchingKeyExec<Vec<u8>, B> {
|
|
||||||
pub fn alloc(module: &Module<B>, basek: usize, k: usize, rows: usize, digits: usize, rank_in: usize, rank_out: usize) -> Self
|
|
||||||
where
|
|
||||||
Module<B>: GGLWEExecLayoutFamily<B>,
|
|
||||||
{
|
|
||||||
GLWESwitchingKeyExec::<Vec<u8>, B> {
|
|
||||||
key: GGLWECiphertextExec::alloc(module, basek, k, rows, digits, rank_in, rank_out),
|
|
||||||
sk_in_n: 0,
|
|
||||||
sk_out_n: 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn bytes_of(
|
|
||||||
module: &Module<B>,
|
|
||||||
basek: usize,
|
|
||||||
k: usize,
|
|
||||||
rows: usize,
|
|
||||||
digits: usize,
|
|
||||||
rank_in: usize,
|
|
||||||
rank_out: usize,
|
|
||||||
) -> usize
|
|
||||||
where
|
|
||||||
Module<B>: GGLWEExecLayoutFamily<B>,
|
|
||||||
{
|
|
||||||
GGLWECiphertextExec::bytes_of(module, basek, k, rows, digits, rank_in, rank_out)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn from<DataOther: DataRef>(module: &Module<B>, other: &GLWESwitchingKey<DataOther>, scratch: &mut Scratch<B>) -> Self
|
|
||||||
where
|
|
||||||
Module<B>: GGLWEExecLayoutFamily<B>,
|
|
||||||
{
|
|
||||||
let mut ksk_exec: GLWESwitchingKeyExec<Vec<u8>, B> = Self::alloc(
|
|
||||||
module,
|
|
||||||
other.basek(),
|
|
||||||
other.k(),
|
|
||||||
other.rows(),
|
|
||||||
other.digits(),
|
|
||||||
other.rank_in(),
|
|
||||||
other.rank_out(),
|
|
||||||
);
|
|
||||||
ksk_exec.prepare(module, other, scratch);
|
|
||||||
ksk_exec
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<D: Data, B: Backend> Infos for GLWESwitchingKeyExec<D, B> {
|
|
||||||
type Inner = VmpPMat<D, B>;
|
|
||||||
|
|
||||||
fn inner(&self) -> &Self::Inner {
|
|
||||||
self.key.inner()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn basek(&self) -> usize {
|
|
||||||
self.key.basek()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn k(&self) -> usize {
|
|
||||||
self.key.k()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<D: Data, B: Backend> GLWESwitchingKeyExec<D, B> {
|
|
||||||
pub fn rank(&self) -> usize {
|
|
||||||
self.key.data.cols_out() - 1
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn rank_in(&self) -> usize {
|
|
||||||
self.key.data.cols_in()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn rank_out(&self) -> usize {
|
|
||||||
self.key.data.cols_out() - 1
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn digits(&self) -> usize {
|
|
||||||
self.key.digits()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn sk_degree_in(&self) -> usize {
|
|
||||||
self.sk_in_n
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn sk_degree_out(&self) -> usize {
|
|
||||||
self.sk_out_n
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<D: DataMut, B: Backend> GLWESwitchingKeyExec<D, B> {
|
|
||||||
pub fn prepare<DataOther>(&mut self, module: &Module<B>, other: &GLWESwitchingKey<DataOther>, scratch: &mut Scratch<B>)
|
|
||||||
where
|
|
||||||
DataOther: DataRef,
|
|
||||||
Module<B>: GGLWEExecLayoutFamily<B>,
|
|
||||||
{
|
|
||||||
self.key.prepare(module, &other.key, scratch);
|
|
||||||
self.sk_in_n = other.sk_in_n;
|
|
||||||
self.sk_out_n = other.sk_out_n;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,9 +1,10 @@
|
|||||||
use backend::hal::{
|
use backend::hal::{
|
||||||
api::{MatZnxAlloc, MatZnxAllocBytes, VmpPMatAlloc, VmpPMatAllocBytes, VmpPMatPrepare},
|
api::{MatZnxAlloc, MatZnxAllocBytes, VmpPMatAlloc, VmpPMatAllocBytes, VmpPMatPrepare},
|
||||||
layouts::{Backend, Data, DataMut, DataRef, MatZnx, Module, ReaderFrom, Scratch, VmpPMat, WriterTo},
|
layouts::{Backend, Data, DataMut, DataRef, MatZnx, Module, ReaderFrom, WriterTo},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{GLWECiphertext, Infos};
|
use crate::{GLWECiphertext, Infos};
|
||||||
|
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
|
||||||
|
|
||||||
pub trait GGLWEExecLayoutFamily<B: Backend> = VmpPMatAlloc<B> + VmpPMatAllocBytes + VmpPMatPrepare<B>;
|
pub trait GGLWEExecLayoutFamily<B: Backend> = VmpPMatAlloc<B> + VmpPMatAllocBytes + VmpPMatPrepare<B>;
|
||||||
|
|
||||||
@@ -138,8 +139,6 @@ impl<D: Data> GGLWECiphertext<D> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
|
|
||||||
|
|
||||||
impl<D: DataMut> ReaderFrom for GGLWECiphertext<D> {
|
impl<D: DataMut> ReaderFrom for GGLWECiphertext<D> {
|
||||||
fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> {
|
fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> {
|
||||||
self.k = reader.read_u64::<LittleEndian>()? as usize;
|
self.k = reader.read_u64::<LittleEndian>()? as usize;
|
||||||
@@ -159,43 +158,33 @@ impl<D: DataRef> WriterTo for GGLWECiphertext<D> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Eq)]
|
#[derive(PartialEq, Eq)]
|
||||||
pub struct GGLWECiphertextExec<D: Data, B: Backend> {
|
pub struct GLWESwitchingKey<D: Data> {
|
||||||
pub(crate) data: VmpPMat<D, B>,
|
pub(crate) key: GGLWECiphertext<D>,
|
||||||
pub(crate) basek: usize,
|
pub(crate) sk_in_n: usize, // Degree of sk_in
|
||||||
pub(crate) k: usize,
|
pub(crate) sk_out_n: usize, // Degree of sk_out
|
||||||
pub(crate) digits: usize,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<B: Backend> GGLWECiphertextExec<Vec<u8>, B> {
|
impl GLWESwitchingKey<Vec<u8>> {
|
||||||
pub fn alloc(module: &Module<B>, basek: usize, k: usize, rows: usize, digits: usize, rank_in: usize, rank_out: usize) -> Self
|
pub fn alloc<B: Backend>(
|
||||||
|
module: &Module<B>,
|
||||||
|
basek: usize,
|
||||||
|
k: usize,
|
||||||
|
rows: usize,
|
||||||
|
digits: usize,
|
||||||
|
rank_in: usize,
|
||||||
|
rank_out: usize,
|
||||||
|
) -> Self
|
||||||
where
|
where
|
||||||
Module<B>: GGLWEExecLayoutFamily<B>,
|
Module<B>: MatZnxAlloc,
|
||||||
{
|
{
|
||||||
let size: usize = k.div_ceil(basek);
|
GLWESwitchingKey {
|
||||||
debug_assert!(
|
key: GGLWECiphertext::alloc(module, basek, k, rows, digits, rank_in, rank_out),
|
||||||
size > digits,
|
sk_in_n: 0,
|
||||||
"invalid gglwe: ceil(k/basek): {} <= digits: {}",
|
sk_out_n: 0,
|
||||||
size,
|
|
||||||
digits
|
|
||||||
);
|
|
||||||
|
|
||||||
assert!(
|
|
||||||
rows * digits <= size,
|
|
||||||
"invalid gglwe: rows: {} * digits:{} > ceil(k/basek): {}",
|
|
||||||
rows,
|
|
||||||
digits,
|
|
||||||
size
|
|
||||||
);
|
|
||||||
|
|
||||||
Self {
|
|
||||||
data: module.vmp_pmat_alloc(rows, rank_in, rank_out + 1, size),
|
|
||||||
basek: basek,
|
|
||||||
k,
|
|
||||||
digits,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn bytes_of(
|
pub fn bytes_of<B: Backend>(
|
||||||
module: &Module<B>,
|
module: &Module<B>,
|
||||||
basek: usize,
|
basek: usize,
|
||||||
k: usize,
|
k: usize,
|
||||||
@@ -205,71 +194,278 @@ impl<B: Backend> GGLWECiphertextExec<Vec<u8>, B> {
|
|||||||
rank_out: usize,
|
rank_out: usize,
|
||||||
) -> usize
|
) -> usize
|
||||||
where
|
where
|
||||||
Module<B>: GGLWEExecLayoutFamily<B>,
|
Module<B>: MatZnxAllocBytes,
|
||||||
{
|
{
|
||||||
let size: usize = k.div_ceil(basek);
|
GGLWECiphertext::<Vec<u8>>::bytes_of(module, basek, k, rows, digits, rank_in, rank_out)
|
||||||
debug_assert!(
|
|
||||||
size > digits,
|
|
||||||
"invalid gglwe: ceil(k/basek): {} <= digits: {}",
|
|
||||||
size,
|
|
||||||
digits
|
|
||||||
);
|
|
||||||
|
|
||||||
assert!(
|
|
||||||
rows * digits <= size,
|
|
||||||
"invalid gglwe: rows: {} * digits:{} > ceil(k/basek): {}",
|
|
||||||
rows,
|
|
||||||
digits,
|
|
||||||
size
|
|
||||||
);
|
|
||||||
|
|
||||||
module.vmp_pmat_alloc_bytes(rows, rank_in, rank_out + 1, rows)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<D: Data, B: Backend> Infos for GGLWECiphertextExec<D, B> {
|
impl<D: Data> Infos for GLWESwitchingKey<D> {
|
||||||
type Inner = VmpPMat<D, B>;
|
type Inner = MatZnx<D>;
|
||||||
|
|
||||||
fn inner(&self) -> &Self::Inner {
|
fn inner(&self) -> &Self::Inner {
|
||||||
&self.data
|
self.key.inner()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn basek(&self) -> usize {
|
fn basek(&self) -> usize {
|
||||||
self.basek
|
self.key.basek()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn k(&self) -> usize {
|
fn k(&self) -> usize {
|
||||||
self.k
|
self.key.k()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<D: Data, B: Backend> GGLWECiphertextExec<D, B> {
|
impl<D: Data> GLWESwitchingKey<D> {
|
||||||
pub fn rank(&self) -> usize {
|
pub fn rank(&self) -> usize {
|
||||||
self.data.cols_out() - 1
|
self.key.data.cols_out() - 1
|
||||||
}
|
|
||||||
|
|
||||||
pub fn digits(&self) -> usize {
|
|
||||||
self.digits
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn rank_in(&self) -> usize {
|
pub fn rank_in(&self) -> usize {
|
||||||
self.data.cols_in()
|
self.key.data.cols_in()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn rank_out(&self) -> usize {
|
pub fn rank_out(&self) -> usize {
|
||||||
self.data.cols_out() - 1
|
self.key.data.cols_out() - 1
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn digits(&self) -> usize {
|
||||||
|
self.key.digits()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sk_degree_in(&self) -> usize {
|
||||||
|
self.sk_in_n
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sk_degree_out(&self) -> usize {
|
||||||
|
self.sk_out_n
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<D: DataMut, B: Backend> GGLWECiphertextExec<D, B> {
|
impl<D: DataRef> GLWESwitchingKey<D> {
|
||||||
pub fn prepare<DataOther>(&mut self, module: &Module<B>, other: &GGLWECiphertext<DataOther>, scratch: &mut Scratch<B>)
|
pub fn at(&self, row: usize, col: usize) -> GLWECiphertext<&[u8]> {
|
||||||
|
self.key.at(row, col)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D: DataMut> GLWESwitchingKey<D> {
|
||||||
|
pub fn at_mut(&mut self, row: usize, col: usize) -> GLWECiphertext<&mut [u8]> {
|
||||||
|
self.key.at_mut(row, col)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D: DataMut> ReaderFrom for 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;
|
||||||
|
self.key.read_from(reader)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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)?;
|
||||||
|
self.key.write_to(writer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq, Eq)]
|
||||||
|
pub struct AutomorphismKey<D: Data> {
|
||||||
|
pub(crate) key: GLWESwitchingKey<D>,
|
||||||
|
pub(crate) p: i64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AutomorphismKey<Vec<u8>> {
|
||||||
|
pub fn alloc<B: Backend>(module: &Module<B>, basek: usize, k: usize, rows: usize, digits: usize, rank: usize) -> Self
|
||||||
where
|
where
|
||||||
DataOther: DataRef,
|
Module<B>: MatZnxAlloc,
|
||||||
Module<B>: GGLWEExecLayoutFamily<B>,
|
|
||||||
{
|
{
|
||||||
module.vmp_prepare(&mut self.data, &other.data, scratch);
|
AutomorphismKey {
|
||||||
self.basek = other.basek;
|
key: GLWESwitchingKey::alloc(module, basek, k, rows, digits, rank, rank),
|
||||||
self.k = other.k;
|
p: 0,
|
||||||
self.digits = other.digits;
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn bytes_of<B: Backend>(module: &Module<B>, basek: usize, k: usize, rows: usize, digits: usize, rank: usize) -> usize
|
||||||
|
where
|
||||||
|
Module<B>: MatZnxAllocBytes,
|
||||||
|
{
|
||||||
|
GLWESwitchingKey::<Vec<u8>>::bytes_of(module, basek, k, rows, digits, rank, rank)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D: Data> Infos for AutomorphismKey<D> {
|
||||||
|
type Inner = MatZnx<D>;
|
||||||
|
|
||||||
|
fn inner(&self) -> &Self::Inner {
|
||||||
|
&self.key.inner()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn basek(&self) -> usize {
|
||||||
|
self.key.basek()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn k(&self) -> usize {
|
||||||
|
self.key.k()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D: Data> AutomorphismKey<D> {
|
||||||
|
pub fn p(&self) -> i64 {
|
||||||
|
self.p
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn digits(&self) -> usize {
|
||||||
|
self.key.digits()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn rank(&self) -> usize {
|
||||||
|
self.key.rank()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn rank_in(&self) -> usize {
|
||||||
|
self.key.rank_in()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn rank_out(&self) -> usize {
|
||||||
|
self.key.rank_out()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D: DataRef> AutomorphismKey<D> {
|
||||||
|
pub fn at(&self, row: usize, col: usize) -> GLWECiphertext<&[u8]> {
|
||||||
|
self.key.at(row, col)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D: DataMut> AutomorphismKey<D> {
|
||||||
|
pub fn at_mut(&mut self, row: usize, col: usize) -> GLWECiphertext<&mut [u8]> {
|
||||||
|
self.key.at_mut(row, col)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D: DataMut> ReaderFrom for 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 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq, Eq)]
|
||||||
|
pub struct GLWETensorKey<D: Data> {
|
||||||
|
pub(crate) keys: Vec<GLWESwitchingKey<D>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GLWETensorKey<Vec<u8>> {
|
||||||
|
pub fn alloc<B: Backend>(module: &Module<B>, basek: usize, k: usize, rows: usize, digits: usize, rank: usize) -> Self
|
||||||
|
where
|
||||||
|
Module<B>: MatZnxAlloc,
|
||||||
|
{
|
||||||
|
let mut keys: Vec<GLWESwitchingKey<Vec<u8>>> = Vec::new();
|
||||||
|
let pairs: usize = (((rank + 1) * rank) >> 1).max(1);
|
||||||
|
(0..pairs).for_each(|_| {
|
||||||
|
keys.push(GLWESwitchingKey::alloc(
|
||||||
|
module, basek, k, rows, digits, 1, rank,
|
||||||
|
));
|
||||||
|
});
|
||||||
|
Self { keys: keys }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn bytes_of<B: Backend>(module: &Module<B>, basek: usize, k: usize, rows: usize, digits: usize, rank: usize) -> usize
|
||||||
|
where
|
||||||
|
Module<B>: MatZnxAllocBytes,
|
||||||
|
{
|
||||||
|
let pairs: usize = (((rank + 1) * rank) >> 1).max(1);
|
||||||
|
pairs * GLWESwitchingKey::<Vec<u8>>::bytes_of(module, basek, k, rows, digits, 1, rank)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D: Data> Infos for GLWETensorKey<D> {
|
||||||
|
type Inner = MatZnx<D>;
|
||||||
|
|
||||||
|
fn inner(&self) -> &Self::Inner {
|
||||||
|
&self.keys[0].inner()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn basek(&self) -> usize {
|
||||||
|
self.keys[0].basek()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn k(&self) -> usize {
|
||||||
|
self.keys[0].k()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D: Data> GLWETensorKey<D> {
|
||||||
|
pub fn rank(&self) -> usize {
|
||||||
|
self.keys[0].rank()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn rank_in(&self) -> usize {
|
||||||
|
self.keys[0].rank_in()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn rank_out(&self) -> usize {
|
||||||
|
self.keys[0].rank_out()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn digits(&self) -> usize {
|
||||||
|
self.keys[0].digits()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D: DataMut> GLWETensorKey<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 GLWESwitchingKey<D> {
|
||||||
|
if i > j {
|
||||||
|
std::mem::swap(&mut i, &mut j);
|
||||||
|
};
|
||||||
|
let rank: usize = self.rank();
|
||||||
|
&mut self.keys[i * rank + j - (i * (i + 1) / 2)]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D: DataRef> GLWETensorKey<D> {
|
||||||
|
// Returns a reference to GLWESwitchingKey_{s}(s[i] * s[j])
|
||||||
|
pub fn at(&self, mut i: usize, mut j: usize) -> &GLWESwitchingKey<D> {
|
||||||
|
if i > j {
|
||||||
|
std::mem::swap(&mut i, &mut j);
|
||||||
|
};
|
||||||
|
let rank: usize = self.rank();
|
||||||
|
&self.keys[i * rank + j - (i * (i + 1) / 2)]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D: DataMut> ReaderFrom for GLWETensorKey<D> {
|
||||||
|
fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> {
|
||||||
|
let len: usize = reader.read_u64::<LittleEndian>()? as usize;
|
||||||
|
if self.keys.len() != len {
|
||||||
|
return Err(std::io::Error::new(
|
||||||
|
std::io::ErrorKind::InvalidData,
|
||||||
|
format!("self.keys.len()={} != read len={}", self.keys.len(), len),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
for key in &mut self.keys {
|
||||||
|
key.read_from(reader)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D: DataRef> WriterTo for GLWETensorKey<D> {
|
||||||
|
fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
|
||||||
|
writer.write_u64::<LittleEndian>(self.keys.len() as u64)?;
|
||||||
|
for key in &self.keys {
|
||||||
|
key.write_to(writer)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
535
core/src/gglwe/layouts_compressed.rs
Normal file
535
core/src/gglwe/layouts_compressed.rs
Normal file
@@ -0,0 +1,535 @@
|
|||||||
|
use backend::hal::{
|
||||||
|
api::{MatZnxAlloc, MatZnxAllocBytes, VecZnxCopy, VecZnxFillUniform},
|
||||||
|
layouts::{Backend, Data, DataMut, DataRef, MatZnx, Module, ReaderFrom, WriterTo},
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::{AutomorphismKey, GGLWECiphertext, GLWECiphertextCompressed, GLWESwitchingKey, GLWETensorKey, Infos};
|
||||||
|
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
|
||||||
|
|
||||||
|
#[derive(PartialEq, Eq)]
|
||||||
|
pub struct GGLWECiphertextCompressed<D: Data> {
|
||||||
|
pub(crate) data: MatZnx<D>,
|
||||||
|
pub(crate) basek: usize,
|
||||||
|
pub(crate) k: usize,
|
||||||
|
pub(crate) rank_out: usize,
|
||||||
|
pub(crate) digits: usize,
|
||||||
|
pub(crate) seed: Vec<[u8; 32]>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GGLWECiphertextCompressed<Vec<u8>> {
|
||||||
|
pub fn alloc<B: Backend>(
|
||||||
|
module: &Module<B>,
|
||||||
|
basek: usize,
|
||||||
|
k: usize,
|
||||||
|
rows: usize,
|
||||||
|
digits: usize,
|
||||||
|
rank_in: usize,
|
||||||
|
rank_out: usize,
|
||||||
|
) -> Self
|
||||||
|
where
|
||||||
|
Module<B>: MatZnxAlloc,
|
||||||
|
{
|
||||||
|
let size: usize = k.div_ceil(basek);
|
||||||
|
debug_assert!(
|
||||||
|
size > digits,
|
||||||
|
"invalid gglwe: ceil(k/basek): {} <= digits: {}",
|
||||||
|
size,
|
||||||
|
digits
|
||||||
|
);
|
||||||
|
|
||||||
|
assert!(
|
||||||
|
rows * digits <= size,
|
||||||
|
"invalid gglwe: rows: {} * digits:{} > ceil(k/basek): {}",
|
||||||
|
rows,
|
||||||
|
digits,
|
||||||
|
size
|
||||||
|
);
|
||||||
|
|
||||||
|
Self {
|
||||||
|
data: module.mat_znx_alloc(rows, rank_in, 1, size),
|
||||||
|
basek: basek,
|
||||||
|
k,
|
||||||
|
rank_out,
|
||||||
|
digits,
|
||||||
|
seed: vec![[0u8; 32]; rows * rank_in],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn bytes_of<B: Backend>(module: &Module<B>, basek: usize, k: usize, rows: usize, digits: usize, rank_in: usize) -> usize
|
||||||
|
where
|
||||||
|
Module<B>: MatZnxAllocBytes,
|
||||||
|
{
|
||||||
|
let size: usize = k.div_ceil(basek);
|
||||||
|
debug_assert!(
|
||||||
|
size > digits,
|
||||||
|
"invalid gglwe: ceil(k/basek): {} <= digits: {}",
|
||||||
|
size,
|
||||||
|
digits
|
||||||
|
);
|
||||||
|
|
||||||
|
assert!(
|
||||||
|
rows * digits <= size,
|
||||||
|
"invalid gglwe: rows: {} * digits:{} > ceil(k/basek): {}",
|
||||||
|
rows,
|
||||||
|
digits,
|
||||||
|
size
|
||||||
|
);
|
||||||
|
|
||||||
|
module.mat_znx_alloc_bytes(rows, rank_in, 1, rows)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D: Data> Infos for GGLWECiphertextCompressed<D> {
|
||||||
|
type Inner = MatZnx<D>;
|
||||||
|
|
||||||
|
fn inner(&self) -> &Self::Inner {
|
||||||
|
&self.data
|
||||||
|
}
|
||||||
|
|
||||||
|
fn basek(&self) -> usize {
|
||||||
|
self.basek
|
||||||
|
}
|
||||||
|
|
||||||
|
fn k(&self) -> usize {
|
||||||
|
self.k
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D: Data> GGLWECiphertextCompressed<D> {
|
||||||
|
pub fn rank(&self) -> usize {
|
||||||
|
self.rank_out
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn digits(&self) -> usize {
|
||||||
|
self.digits
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn rank_in(&self) -> usize {
|
||||||
|
self.data.cols_in()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn rank_out(&self) -> usize {
|
||||||
|
self.rank_out
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D: DataRef> GGLWECiphertextCompressed<D> {
|
||||||
|
pub(crate) fn at(&self, row: usize, col: usize) -> GLWECiphertextCompressed<&[u8]> {
|
||||||
|
GLWECiphertextCompressed {
|
||||||
|
data: self.data.at(row, col),
|
||||||
|
basek: self.basek,
|
||||||
|
k: self.k,
|
||||||
|
rank: self.rank_out,
|
||||||
|
seed: self.seed[self.rank_in() * row + col],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D: DataMut> GGLWECiphertextCompressed<D> {
|
||||||
|
pub(crate) fn at_mut(&mut self, row: usize, col: usize) -> GLWECiphertextCompressed<&mut [u8]> {
|
||||||
|
let rank_in: usize = self.rank_in();
|
||||||
|
GLWECiphertextCompressed {
|
||||||
|
data: self.data.at_mut(row, col),
|
||||||
|
basek: self.basek,
|
||||||
|
k: self.k,
|
||||||
|
rank: self.rank_out,
|
||||||
|
seed: self.seed[rank_in * row + col], // Warning: value is copied and not borrow mut
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D: DataMut> ReaderFrom for GGLWECiphertextCompressed<D> {
|
||||||
|
fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> {
|
||||||
|
self.k = reader.read_u64::<LittleEndian>()? as usize;
|
||||||
|
self.basek = reader.read_u64::<LittleEndian>()? as usize;
|
||||||
|
self.digits = reader.read_u64::<LittleEndian>()? as usize;
|
||||||
|
self.rank_out = reader.read_u64::<LittleEndian>()? as usize;
|
||||||
|
let seed_len = reader.read_u64::<LittleEndian>()? as usize;
|
||||||
|
if seed_len != self.seed.len() {
|
||||||
|
} else {
|
||||||
|
for s in &mut self.seed {
|
||||||
|
reader.read_exact(s)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.data.read_from(reader)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D: DataRef> WriterTo for GGLWECiphertextCompressed<D> {
|
||||||
|
fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
|
||||||
|
writer.write_u64::<LittleEndian>(self.k as u64)?;
|
||||||
|
writer.write_u64::<LittleEndian>(self.basek as u64)?;
|
||||||
|
writer.write_u64::<LittleEndian>(self.digits as u64)?;
|
||||||
|
writer.write_u64::<LittleEndian>(self.rank_out as u64)?;
|
||||||
|
writer.write_u64::<LittleEndian>(self.seed.len() as u64)?;
|
||||||
|
for s in &self.seed {
|
||||||
|
writer.write_all(s)?;
|
||||||
|
}
|
||||||
|
self.data.write_to(writer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D: DataMut> GGLWECiphertext<D> {
|
||||||
|
pub fn decompress<DataOther: DataRef, B: Backend>(&mut self, module: &Module<B>, other: &GGLWECiphertextCompressed<DataOther>)
|
||||||
|
where
|
||||||
|
Module<B>: VecZnxFillUniform + VecZnxCopy,
|
||||||
|
{
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
{
|
||||||
|
use backend::hal::api::ZnxInfos;
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
self.n(),
|
||||||
|
other.data.n(),
|
||||||
|
"invalid receiver: self.n()={} != other.n()={}",
|
||||||
|
self.n(),
|
||||||
|
other.data.n()
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
self.size(),
|
||||||
|
other.size(),
|
||||||
|
"invalid receiver: self.size()={} != other.size()={}",
|
||||||
|
self.size(),
|
||||||
|
other.size()
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
self.rank_in(),
|
||||||
|
other.rank_in(),
|
||||||
|
"invalid receiver: self.rank_in()={} != other.rank_in()={}",
|
||||||
|
self.rank_in(),
|
||||||
|
other.rank_in()
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
self.rank_out(),
|
||||||
|
other.rank_out(),
|
||||||
|
"invalid receiver: self.rank_out()={} != other.rank_out()={}",
|
||||||
|
self.rank_out(),
|
||||||
|
other.rank_out()
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
self.rows(),
|
||||||
|
other.rows(),
|
||||||
|
"invalid receiver: self.rows()={} != other.rows()={}",
|
||||||
|
self.rows(),
|
||||||
|
other.rows()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let rank_in: usize = self.rank_in();
|
||||||
|
let rows: usize = self.rows();
|
||||||
|
|
||||||
|
(0..rank_in).for_each(|col_i| {
|
||||||
|
(0..rows).for_each(|row_i| {
|
||||||
|
self.at_mut(row_i, col_i)
|
||||||
|
.decompress(module, &other.at(row_i, col_i));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq, Eq)]
|
||||||
|
pub struct GLWESwitchingKeyCompressed<D: Data> {
|
||||||
|
pub(crate) key: GGLWECiphertextCompressed<D>,
|
||||||
|
pub(crate) sk_in_n: usize, // Degree of sk_in
|
||||||
|
pub(crate) sk_out_n: usize, // Degree of sk_out
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D: Data> Infos for GLWESwitchingKeyCompressed<D> {
|
||||||
|
type Inner = MatZnx<D>;
|
||||||
|
|
||||||
|
fn inner(&self) -> &Self::Inner {
|
||||||
|
&self.key.inner()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn basek(&self) -> usize {
|
||||||
|
self.key.basek()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn k(&self) -> usize {
|
||||||
|
self.key.k()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D: Data> GLWESwitchingKeyCompressed<D> {
|
||||||
|
pub fn rank(&self) -> usize {
|
||||||
|
self.key.rank()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn digits(&self) -> usize {
|
||||||
|
self.key.digits()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn rank_in(&self) -> usize {
|
||||||
|
self.key.rank_in()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn rank_out(&self) -> usize {
|
||||||
|
self.key.rank_out()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GLWESwitchingKeyCompressed<Vec<u8>> {
|
||||||
|
pub fn alloc<B: Backend>(
|
||||||
|
module: &Module<B>,
|
||||||
|
basek: usize,
|
||||||
|
k: usize,
|
||||||
|
rows: usize,
|
||||||
|
digits: usize,
|
||||||
|
rank_in: usize,
|
||||||
|
rank_out: usize,
|
||||||
|
) -> Self
|
||||||
|
where
|
||||||
|
Module<B>: MatZnxAlloc,
|
||||||
|
{
|
||||||
|
GLWESwitchingKeyCompressed {
|
||||||
|
key: GGLWECiphertextCompressed::alloc(module, basek, k, rows, digits, rank_in, rank_out),
|
||||||
|
sk_in_n: 0,
|
||||||
|
sk_out_n: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn bytes_of<B: Backend>(module: &Module<B>, basek: usize, k: usize, rows: usize, digits: usize, rank_in: usize) -> usize
|
||||||
|
where
|
||||||
|
Module<B>: MatZnxAllocBytes,
|
||||||
|
{
|
||||||
|
GGLWECiphertextCompressed::<Vec<u8>>::bytes_of(module, basek, k, rows, digits, rank_in)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
self.key.read_from(reader)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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)?;
|
||||||
|
self.key.write_to(writer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D: DataMut> GLWESwitchingKey<D> {
|
||||||
|
pub fn decompress<DataOther: DataRef, B: Backend>(
|
||||||
|
&mut self,
|
||||||
|
module: &Module<B>,
|
||||||
|
other: &GLWESwitchingKeyCompressed<DataOther>,
|
||||||
|
) where
|
||||||
|
Module<B>: VecZnxFillUniform + VecZnxCopy,
|
||||||
|
{
|
||||||
|
self.key.decompress(module, &other.key);
|
||||||
|
self.sk_in_n = other.sk_in_n;
|
||||||
|
self.sk_out_n = other.sk_out_n;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq, Eq)]
|
||||||
|
pub struct AutomorphismKeyCompressed<D: Data> {
|
||||||
|
pub(crate) key: GLWESwitchingKeyCompressed<D>,
|
||||||
|
pub(crate) p: i64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AutomorphismKeyCompressed<Vec<u8>> {
|
||||||
|
pub fn alloc<B: Backend>(module: &Module<B>, basek: usize, k: usize, rows: usize, digits: usize, rank: usize) -> Self
|
||||||
|
where
|
||||||
|
Module<B>: MatZnxAlloc,
|
||||||
|
{
|
||||||
|
AutomorphismKeyCompressed {
|
||||||
|
key: GLWESwitchingKeyCompressed::alloc(module, basek, k, rows, digits, rank, rank),
|
||||||
|
p: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn bytes_of<B: Backend>(module: &Module<B>, basek: usize, k: usize, rows: usize, digits: usize, rank: usize) -> usize
|
||||||
|
where
|
||||||
|
Module<B>: MatZnxAllocBytes,
|
||||||
|
{
|
||||||
|
GLWESwitchingKeyCompressed::<Vec<u8>>::bytes_of(module, basek, k, rows, digits, rank)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D: Data> Infos for AutomorphismKeyCompressed<D> {
|
||||||
|
type Inner = MatZnx<D>;
|
||||||
|
|
||||||
|
fn inner(&self) -> &Self::Inner {
|
||||||
|
&self.key.inner()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn basek(&self) -> usize {
|
||||||
|
self.key.basek()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn k(&self) -> usize {
|
||||||
|
self.key.k()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D: Data> AutomorphismKeyCompressed<D> {
|
||||||
|
pub fn rank(&self) -> usize {
|
||||||
|
self.key.rank()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn digits(&self) -> usize {
|
||||||
|
self.key.digits()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn rank_in(&self) -> usize {
|
||||||
|
self.key.rank_in()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn rank_out(&self) -> usize {
|
||||||
|
self.key.rank_out()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D: DataMut> ReaderFrom for 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 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> AutomorphismKey<D> {
|
||||||
|
pub fn decompress<DataOther: DataRef, B: Backend>(&mut self, module: &Module<B>, other: &AutomorphismKeyCompressed<DataOther>)
|
||||||
|
where
|
||||||
|
Module<B>: VecZnxFillUniform + VecZnxCopy,
|
||||||
|
{
|
||||||
|
self.key.decompress(module, &other.key);
|
||||||
|
self.p = other.p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq, Eq)]
|
||||||
|
pub struct GLWETensorKeyCompressed<D: Data> {
|
||||||
|
pub(crate) keys: Vec<GLWESwitchingKeyCompressed<D>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GLWETensorKeyCompressed<Vec<u8>> {
|
||||||
|
pub fn alloc<B: Backend>(module: &Module<B>, basek: usize, k: usize, rows: usize, digits: usize, rank: usize) -> Self
|
||||||
|
where
|
||||||
|
Module<B>: MatZnxAlloc,
|
||||||
|
{
|
||||||
|
let mut keys: Vec<GLWESwitchingKeyCompressed<Vec<u8>>> = Vec::new();
|
||||||
|
let pairs: usize = (((rank + 1) * rank) >> 1).max(1);
|
||||||
|
(0..pairs).for_each(|_| {
|
||||||
|
keys.push(GLWESwitchingKeyCompressed::alloc(
|
||||||
|
module, basek, k, rows, digits, 1, rank,
|
||||||
|
));
|
||||||
|
});
|
||||||
|
Self { keys: keys }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn bytes_of<B: Backend>(module: &Module<B>, basek: usize, k: usize, rows: usize, digits: usize, rank: usize) -> usize
|
||||||
|
where
|
||||||
|
Module<B>: MatZnxAllocBytes,
|
||||||
|
{
|
||||||
|
let pairs: usize = (((rank + 1) * rank) >> 1).max(1);
|
||||||
|
pairs * GLWESwitchingKeyCompressed::<Vec<u8>>::bytes_of(module, basek, k, rows, digits, 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D: Data> Infos for GLWETensorKeyCompressed<D> {
|
||||||
|
type Inner = MatZnx<D>;
|
||||||
|
|
||||||
|
fn inner(&self) -> &Self::Inner {
|
||||||
|
&self.keys[0].inner()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn basek(&self) -> usize {
|
||||||
|
self.keys[0].basek()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn k(&self) -> usize {
|
||||||
|
self.keys[0].k()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D: Data> GLWETensorKeyCompressed<D> {
|
||||||
|
pub fn rank(&self) -> usize {
|
||||||
|
self.keys[0].rank()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn digits(&self) -> usize {
|
||||||
|
self.keys[0].digits()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn rank_in(&self) -> usize {
|
||||||
|
self.keys[0].rank_in()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn rank_out(&self) -> usize {
|
||||||
|
self.keys[0].rank_out()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D: DataMut> ReaderFrom for GLWETensorKeyCompressed<D> {
|
||||||
|
fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> {
|
||||||
|
let len: usize = reader.read_u64::<LittleEndian>()? as usize;
|
||||||
|
if self.keys.len() != len {
|
||||||
|
return Err(std::io::Error::new(
|
||||||
|
std::io::ErrorKind::InvalidData,
|
||||||
|
format!("self.keys.len()={} != read len={}", self.keys.len(), len),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
for key in &mut self.keys {
|
||||||
|
key.read_from(reader)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D: DataRef> WriterTo for GLWETensorKeyCompressed<D> {
|
||||||
|
fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
|
||||||
|
writer.write_u64::<LittleEndian>(self.keys.len() as u64)?;
|
||||||
|
for key in &self.keys {
|
||||||
|
key.write_to(writer)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D: DataMut> GLWETensorKeyCompressed<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);
|
||||||
|
};
|
||||||
|
let rank: usize = self.rank();
|
||||||
|
&mut self.keys[i * rank + j - (i * (i + 1) / 2)]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D: DataMut> GLWETensorKey<D> {
|
||||||
|
pub fn decompress<DataOther: DataRef, B: Backend>(&mut self, module: &Module<B>, other: &GLWETensorKeyCompressed<DataOther>)
|
||||||
|
where
|
||||||
|
Module<B>: VecZnxFillUniform + VecZnxCopy,
|
||||||
|
{
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
{
|
||||||
|
assert_eq!(
|
||||||
|
self.keys.len(),
|
||||||
|
other.keys.len(),
|
||||||
|
"invalid receiver: self.keys.len()={} != other.keys.len()={}",
|
||||||
|
self.keys.len(),
|
||||||
|
other.keys.len()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.keys
|
||||||
|
.iter_mut()
|
||||||
|
.zip(other.keys.iter())
|
||||||
|
.for_each(|(a, b)| {
|
||||||
|
a.decompress(module, b);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
422
core/src/gglwe/layouts_exec.rs
Normal file
422
core/src/gglwe/layouts_exec.rs
Normal file
@@ -0,0 +1,422 @@
|
|||||||
|
use backend::hal::{
|
||||||
|
api::{VmpPMatAlloc, VmpPMatAllocBytes, VmpPMatPrepare},
|
||||||
|
layouts::{Backend, Data, DataMut, DataRef, Module, Scratch, VmpPMat},
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::{AutomorphismKey, GGLWECiphertext, GGLWEExecLayoutFamily, GLWESwitchingKey, GLWETensorKey, Infos};
|
||||||
|
|
||||||
|
#[derive(PartialEq, Eq)]
|
||||||
|
pub struct GGLWECiphertextExec<D: Data, B: Backend> {
|
||||||
|
pub(crate) data: VmpPMat<D, B>,
|
||||||
|
pub(crate) basek: usize,
|
||||||
|
pub(crate) k: usize,
|
||||||
|
pub(crate) digits: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<B: Backend> GGLWECiphertextExec<Vec<u8>, B> {
|
||||||
|
pub fn alloc(module: &Module<B>, basek: usize, k: usize, rows: usize, digits: usize, rank_in: usize, rank_out: usize) -> Self
|
||||||
|
where
|
||||||
|
Module<B>: GGLWEExecLayoutFamily<B>,
|
||||||
|
{
|
||||||
|
let size: usize = k.div_ceil(basek);
|
||||||
|
debug_assert!(
|
||||||
|
size > digits,
|
||||||
|
"invalid gglwe: ceil(k/basek): {} <= digits: {}",
|
||||||
|
size,
|
||||||
|
digits
|
||||||
|
);
|
||||||
|
|
||||||
|
assert!(
|
||||||
|
rows * digits <= size,
|
||||||
|
"invalid gglwe: rows: {} * digits:{} > ceil(k/basek): {}",
|
||||||
|
rows,
|
||||||
|
digits,
|
||||||
|
size
|
||||||
|
);
|
||||||
|
|
||||||
|
Self {
|
||||||
|
data: module.vmp_pmat_alloc(rows, rank_in, rank_out + 1, size),
|
||||||
|
basek: basek,
|
||||||
|
k,
|
||||||
|
digits,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn bytes_of(
|
||||||
|
module: &Module<B>,
|
||||||
|
basek: usize,
|
||||||
|
k: usize,
|
||||||
|
rows: usize,
|
||||||
|
digits: usize,
|
||||||
|
rank_in: usize,
|
||||||
|
rank_out: usize,
|
||||||
|
) -> usize
|
||||||
|
where
|
||||||
|
Module<B>: GGLWEExecLayoutFamily<B>,
|
||||||
|
{
|
||||||
|
let size: usize = k.div_ceil(basek);
|
||||||
|
debug_assert!(
|
||||||
|
size > digits,
|
||||||
|
"invalid gglwe: ceil(k/basek): {} <= digits: {}",
|
||||||
|
size,
|
||||||
|
digits
|
||||||
|
);
|
||||||
|
|
||||||
|
assert!(
|
||||||
|
rows * digits <= size,
|
||||||
|
"invalid gglwe: rows: {} * digits:{} > ceil(k/basek): {}",
|
||||||
|
rows,
|
||||||
|
digits,
|
||||||
|
size
|
||||||
|
);
|
||||||
|
|
||||||
|
module.vmp_pmat_alloc_bytes(rows, rank_in, rank_out + 1, rows)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D: Data, B: Backend> Infos for GGLWECiphertextExec<D, B> {
|
||||||
|
type Inner = VmpPMat<D, B>;
|
||||||
|
|
||||||
|
fn inner(&self) -> &Self::Inner {
|
||||||
|
&self.data
|
||||||
|
}
|
||||||
|
|
||||||
|
fn basek(&self) -> usize {
|
||||||
|
self.basek
|
||||||
|
}
|
||||||
|
|
||||||
|
fn k(&self) -> usize {
|
||||||
|
self.k
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D: Data, B: Backend> GGLWECiphertextExec<D, B> {
|
||||||
|
pub fn rank(&self) -> usize {
|
||||||
|
self.data.cols_out() - 1
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn digits(&self) -> usize {
|
||||||
|
self.digits
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn rank_in(&self) -> usize {
|
||||||
|
self.data.cols_in()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn rank_out(&self) -> usize {
|
||||||
|
self.data.cols_out() - 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D: DataMut, B: Backend> GGLWECiphertextExec<D, B> {
|
||||||
|
pub fn prepare<DataOther>(&mut self, module: &Module<B>, other: &GGLWECiphertext<DataOther>, scratch: &mut Scratch<B>)
|
||||||
|
where
|
||||||
|
DataOther: DataRef,
|
||||||
|
Module<B>: GGLWEExecLayoutFamily<B>,
|
||||||
|
{
|
||||||
|
module.vmp_prepare(&mut self.data, &other.data, scratch);
|
||||||
|
self.basek = other.basek;
|
||||||
|
self.k = other.k;
|
||||||
|
self.digits = other.digits;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq, Eq)]
|
||||||
|
pub struct GLWESwitchingKeyExec<D: Data, B: Backend> {
|
||||||
|
pub(crate) key: GGLWECiphertextExec<D, B>,
|
||||||
|
pub(crate) sk_in_n: usize, // Degree of sk_in
|
||||||
|
pub(crate) sk_out_n: usize, // Degree of sk_out
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<B: Backend> GLWESwitchingKeyExec<Vec<u8>, B> {
|
||||||
|
pub fn alloc(module: &Module<B>, basek: usize, k: usize, rows: usize, digits: usize, rank_in: usize, rank_out: usize) -> Self
|
||||||
|
where
|
||||||
|
Module<B>: GGLWEExecLayoutFamily<B>,
|
||||||
|
{
|
||||||
|
GLWESwitchingKeyExec::<Vec<u8>, B> {
|
||||||
|
key: GGLWECiphertextExec::alloc(module, basek, k, rows, digits, rank_in, rank_out),
|
||||||
|
sk_in_n: 0,
|
||||||
|
sk_out_n: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn bytes_of(
|
||||||
|
module: &Module<B>,
|
||||||
|
basek: usize,
|
||||||
|
k: usize,
|
||||||
|
rows: usize,
|
||||||
|
digits: usize,
|
||||||
|
rank_in: usize,
|
||||||
|
rank_out: usize,
|
||||||
|
) -> usize
|
||||||
|
where
|
||||||
|
Module<B>: GGLWEExecLayoutFamily<B>,
|
||||||
|
{
|
||||||
|
GGLWECiphertextExec::bytes_of(module, basek, k, rows, digits, rank_in, rank_out)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from<DataOther: DataRef>(module: &Module<B>, other: &GLWESwitchingKey<DataOther>, scratch: &mut Scratch<B>) -> Self
|
||||||
|
where
|
||||||
|
Module<B>: GGLWEExecLayoutFamily<B>,
|
||||||
|
{
|
||||||
|
let mut ksk_exec: GLWESwitchingKeyExec<Vec<u8>, B> = Self::alloc(
|
||||||
|
module,
|
||||||
|
other.basek(),
|
||||||
|
other.k(),
|
||||||
|
other.rows(),
|
||||||
|
other.digits(),
|
||||||
|
other.rank_in(),
|
||||||
|
other.rank_out(),
|
||||||
|
);
|
||||||
|
ksk_exec.prepare(module, other, scratch);
|
||||||
|
ksk_exec
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D: Data, B: Backend> Infos for GLWESwitchingKeyExec<D, B> {
|
||||||
|
type Inner = VmpPMat<D, B>;
|
||||||
|
|
||||||
|
fn inner(&self) -> &Self::Inner {
|
||||||
|
self.key.inner()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn basek(&self) -> usize {
|
||||||
|
self.key.basek()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn k(&self) -> usize {
|
||||||
|
self.key.k()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D: Data, B: Backend> GLWESwitchingKeyExec<D, B> {
|
||||||
|
pub fn rank(&self) -> usize {
|
||||||
|
self.key.data.cols_out() - 1
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn rank_in(&self) -> usize {
|
||||||
|
self.key.data.cols_in()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn rank_out(&self) -> usize {
|
||||||
|
self.key.data.cols_out() - 1
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn digits(&self) -> usize {
|
||||||
|
self.key.digits()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sk_degree_in(&self) -> usize {
|
||||||
|
self.sk_in_n
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sk_degree_out(&self) -> usize {
|
||||||
|
self.sk_out_n
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D: DataMut, B: Backend> GLWESwitchingKeyExec<D, B> {
|
||||||
|
pub fn prepare<DataOther>(&mut self, module: &Module<B>, other: &GLWESwitchingKey<DataOther>, scratch: &mut Scratch<B>)
|
||||||
|
where
|
||||||
|
DataOther: DataRef,
|
||||||
|
Module<B>: GGLWEExecLayoutFamily<B>,
|
||||||
|
{
|
||||||
|
self.key.prepare(module, &other.key, scratch);
|
||||||
|
self.sk_in_n = other.sk_in_n;
|
||||||
|
self.sk_out_n = other.sk_out_n;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq, Eq)]
|
||||||
|
pub struct AutomorphismKeyExec<D: Data, B: Backend> {
|
||||||
|
pub(crate) key: GLWESwitchingKeyExec<D, B>,
|
||||||
|
pub(crate) p: i64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<B: Backend> AutomorphismKeyExec<Vec<u8>, B> {
|
||||||
|
pub fn alloc(module: &Module<B>, basek: usize, k: usize, rows: usize, digits: usize, rank: usize) -> Self
|
||||||
|
where
|
||||||
|
Module<B>: GGLWEExecLayoutFamily<B>,
|
||||||
|
{
|
||||||
|
AutomorphismKeyExec::<Vec<u8>, B> {
|
||||||
|
key: GLWESwitchingKeyExec::alloc(module, basek, k, rows, digits, rank, rank),
|
||||||
|
p: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn bytes_of(module: &Module<B>, basek: usize, k: usize, rows: usize, digits: usize, rank: usize) -> usize
|
||||||
|
where
|
||||||
|
Module<B>: GGLWEExecLayoutFamily<B>,
|
||||||
|
{
|
||||||
|
GLWESwitchingKeyExec::<Vec<u8>, B>::bytes_of(module, basek, k, rows, digits, rank, rank)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from<DataOther: DataRef>(module: &Module<B>, other: &AutomorphismKey<DataOther>, scratch: &mut Scratch<B>) -> Self
|
||||||
|
where
|
||||||
|
Module<B>: GGLWEExecLayoutFamily<B>,
|
||||||
|
{
|
||||||
|
let mut atk_exec: AutomorphismKeyExec<Vec<u8>, B> = Self::alloc(
|
||||||
|
module,
|
||||||
|
other.basek(),
|
||||||
|
other.k(),
|
||||||
|
other.rows(),
|
||||||
|
other.digits(),
|
||||||
|
other.rank(),
|
||||||
|
);
|
||||||
|
atk_exec.prepare(module, other, scratch);
|
||||||
|
atk_exec
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D: DataMut, B: Backend> AutomorphismKeyExec<D, B> {
|
||||||
|
pub fn prepare<DataOther>(&mut self, module: &Module<B>, other: &AutomorphismKey<DataOther>, scratch: &mut Scratch<B>)
|
||||||
|
where
|
||||||
|
DataOther: DataRef,
|
||||||
|
Module<B>: GGLWEExecLayoutFamily<B>,
|
||||||
|
{
|
||||||
|
self.key.prepare(module, &other.key, scratch);
|
||||||
|
self.p = other.p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D: Data, B: Backend> Infos for AutomorphismKeyExec<D, B> {
|
||||||
|
type Inner = VmpPMat<D, B>;
|
||||||
|
|
||||||
|
fn inner(&self) -> &Self::Inner {
|
||||||
|
&self.key.inner()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn basek(&self) -> usize {
|
||||||
|
self.key.basek()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn k(&self) -> usize {
|
||||||
|
self.key.k()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D: Data, B: Backend> AutomorphismKeyExec<D, B> {
|
||||||
|
pub fn p(&self) -> i64 {
|
||||||
|
self.p
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn digits(&self) -> usize {
|
||||||
|
self.key.digits()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn rank(&self) -> usize {
|
||||||
|
self.key.rank()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn rank_in(&self) -> usize {
|
||||||
|
self.key.rank_in()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn rank_out(&self) -> usize {
|
||||||
|
self.key.rank_out()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq, Eq)]
|
||||||
|
pub struct GLWETensorKeyExec<D: Data, B: Backend> {
|
||||||
|
pub(crate) keys: Vec<GLWESwitchingKeyExec<D, B>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<B: Backend> GLWETensorKeyExec<Vec<u8>, B> {
|
||||||
|
pub fn alloc(module: &Module<B>, basek: usize, k: usize, rows: usize, digits: usize, rank: usize) -> Self
|
||||||
|
where
|
||||||
|
Module<B>: GGLWEExecLayoutFamily<B>,
|
||||||
|
{
|
||||||
|
let mut keys: Vec<GLWESwitchingKeyExec<Vec<u8>, B>> = Vec::new();
|
||||||
|
let pairs: usize = (((rank + 1) * rank) >> 1).max(1);
|
||||||
|
(0..pairs).for_each(|_| {
|
||||||
|
keys.push(GLWESwitchingKeyExec::alloc(
|
||||||
|
module, basek, k, rows, digits, 1, rank,
|
||||||
|
));
|
||||||
|
});
|
||||||
|
Self { keys }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn bytes_of(module: &Module<B>, basek: usize, k: usize, rows: usize, digits: usize, rank: usize) -> usize
|
||||||
|
where
|
||||||
|
Module<B>: GGLWEExecLayoutFamily<B>,
|
||||||
|
{
|
||||||
|
let pairs: usize = (((rank + 1) * rank) >> 1).max(1);
|
||||||
|
pairs * GLWESwitchingKeyExec::<Vec<u8>, B>::bytes_of(module, basek, k, rows, digits, 1, rank)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D: Data, B: Backend> Infos for GLWETensorKeyExec<D, B> {
|
||||||
|
type Inner = VmpPMat<D, B>;
|
||||||
|
|
||||||
|
fn inner(&self) -> &Self::Inner {
|
||||||
|
&self.keys[0].inner()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn basek(&self) -> usize {
|
||||||
|
self.keys[0].basek()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn k(&self) -> usize {
|
||||||
|
self.keys[0].k()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D: Data, B: Backend> GLWETensorKeyExec<D, B> {
|
||||||
|
pub fn rank(&self) -> usize {
|
||||||
|
self.keys[0].rank()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn rank_in(&self) -> usize {
|
||||||
|
self.keys[0].rank_in()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn rank_out(&self) -> usize {
|
||||||
|
self.keys[0].rank_out()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn digits(&self) -> usize {
|
||||||
|
self.keys[0].digits()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D: DataMut, B: Backend> GLWETensorKeyExec<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 GLWESwitchingKeyExec<D, B> {
|
||||||
|
if i > j {
|
||||||
|
std::mem::swap(&mut i, &mut j);
|
||||||
|
};
|
||||||
|
let rank: usize = self.rank();
|
||||||
|
&mut self.keys[i * rank + j - (i * (i + 1) / 2)]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D: DataRef, B: Backend> GLWETensorKeyExec<D, B> {
|
||||||
|
// Returns a reference to GLWESwitchingKey_{s}(s[i] * s[j])
|
||||||
|
pub fn at(&self, mut i: usize, mut j: usize) -> &GLWESwitchingKeyExec<D, B> {
|
||||||
|
if i > j {
|
||||||
|
std::mem::swap(&mut i, &mut j);
|
||||||
|
};
|
||||||
|
let rank: usize = self.rank();
|
||||||
|
&self.keys[i * rank + j - (i * (i + 1) / 2)]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D: DataMut, B: Backend> GLWETensorKeyExec<D, B> {
|
||||||
|
pub fn prepare<DataOther>(&mut self, module: &Module<B>, other: &GLWETensorKey<DataOther>, scratch: &mut Scratch<B>)
|
||||||
|
where
|
||||||
|
DataOther: DataRef,
|
||||||
|
Module<B>: GGLWEExecLayoutFamily<B>,
|
||||||
|
{
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
{
|
||||||
|
assert_eq!(self.keys.len(), other.keys.len());
|
||||||
|
}
|
||||||
|
self.keys
|
||||||
|
.iter_mut()
|
||||||
|
.zip(other.keys.iter())
|
||||||
|
.for_each(|(a, b)| {
|
||||||
|
a.prepare(module, b, scratch);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,20 +1,16 @@
|
|||||||
mod automorphism;
|
mod automorphism;
|
||||||
mod automorphism_key;
|
|
||||||
mod encryption;
|
mod encryption;
|
||||||
mod external_product;
|
mod external_product;
|
||||||
mod keyswitch;
|
mod keyswitch;
|
||||||
mod keyswitch_key;
|
|
||||||
mod layout;
|
mod layout;
|
||||||
|
mod layouts_compressed;
|
||||||
|
mod layouts_exec;
|
||||||
mod noise;
|
mod noise;
|
||||||
mod tensor_key;
|
|
||||||
|
|
||||||
pub use automorphism_key::{AutomorphismKey, AutomorphismKeyExec};
|
pub use encryption::*;
|
||||||
pub use encryption::{
|
pub use layout::*;
|
||||||
AutomorphismKeyEncryptSkFamily, GGLWEEncryptSkFamily, GLWESwitchingKeyEncryptSkFamily, GLWETensorKeyEncryptSkFamily,
|
pub use layouts_compressed::*;
|
||||||
};
|
pub use layouts_exec::*;
|
||||||
pub use keyswitch_key::{GLWESwitchingKey, GLWESwitchingKeyExec};
|
|
||||||
pub use layout::{GGLWECiphertext, GGLWECiphertextExec, GGLWEExecLayoutFamily};
|
|
||||||
pub use tensor_key::{GLWETensorKey, GLWETensorKeyExec};
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test;
|
mod tests;
|
||||||
|
|||||||
@@ -1,223 +0,0 @@
|
|||||||
use backend::hal::{
|
|
||||||
api::{MatZnxAlloc, MatZnxAllocBytes},
|
|
||||||
layouts::{Backend, Data, DataMut, DataRef, MatZnx, Module, ReaderFrom, Scratch, VmpPMat, WriterTo},
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::{GGLWEExecLayoutFamily, GLWESwitchingKey, GLWESwitchingKeyExec, Infos};
|
|
||||||
|
|
||||||
#[derive(PartialEq, Eq)]
|
|
||||||
pub struct GLWETensorKey<D: Data> {
|
|
||||||
pub(crate) keys: Vec<GLWESwitchingKey<D>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl GLWETensorKey<Vec<u8>> {
|
|
||||||
pub fn alloc<B: Backend>(module: &Module<B>, basek: usize, k: usize, rows: usize, digits: usize, rank: usize) -> Self
|
|
||||||
where
|
|
||||||
Module<B>: MatZnxAlloc,
|
|
||||||
{
|
|
||||||
let mut keys: Vec<GLWESwitchingKey<Vec<u8>>> = Vec::new();
|
|
||||||
let pairs: usize = (((rank + 1) * rank) >> 1).max(1);
|
|
||||||
(0..pairs).for_each(|_| {
|
|
||||||
keys.push(GLWESwitchingKey::alloc(
|
|
||||||
module, basek, k, rows, digits, 1, rank,
|
|
||||||
));
|
|
||||||
});
|
|
||||||
Self { keys: keys }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn bytes_of<B: Backend>(module: &Module<B>, basek: usize, k: usize, rows: usize, digits: usize, rank: usize) -> usize
|
|
||||||
where
|
|
||||||
Module<B>: MatZnxAllocBytes,
|
|
||||||
{
|
|
||||||
let pairs: usize = (((rank + 1) * rank) >> 1).max(1);
|
|
||||||
pairs * GLWESwitchingKey::<Vec<u8>>::bytes_of(module, basek, k, rows, digits, 1, rank)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<D: Data> Infos for GLWETensorKey<D> {
|
|
||||||
type Inner = MatZnx<D>;
|
|
||||||
|
|
||||||
fn inner(&self) -> &Self::Inner {
|
|
||||||
&self.keys[0].inner()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn basek(&self) -> usize {
|
|
||||||
self.keys[0].basek()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn k(&self) -> usize {
|
|
||||||
self.keys[0].k()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<D: Data> GLWETensorKey<D> {
|
|
||||||
pub fn rank(&self) -> usize {
|
|
||||||
self.keys[0].rank()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn rank_in(&self) -> usize {
|
|
||||||
self.keys[0].rank_in()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn rank_out(&self) -> usize {
|
|
||||||
self.keys[0].rank_out()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn digits(&self) -> usize {
|
|
||||||
self.keys[0].digits()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<D: DataMut> GLWETensorKey<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 GLWESwitchingKey<D> {
|
|
||||||
if i > j {
|
|
||||||
std::mem::swap(&mut i, &mut j);
|
|
||||||
};
|
|
||||||
let rank: usize = self.rank();
|
|
||||||
&mut self.keys[i * rank + j - (i * (i + 1) / 2)]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<D: DataRef> GLWETensorKey<D> {
|
|
||||||
// Returns a reference to GLWESwitchingKey_{s}(s[i] * s[j])
|
|
||||||
pub fn at(&self, mut i: usize, mut j: usize) -> &GLWESwitchingKey<D> {
|
|
||||||
if i > j {
|
|
||||||
std::mem::swap(&mut i, &mut j);
|
|
||||||
};
|
|
||||||
let rank: usize = self.rank();
|
|
||||||
&self.keys[i * rank + j - (i * (i + 1) / 2)]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
|
|
||||||
|
|
||||||
impl<D: DataMut> ReaderFrom for GLWETensorKey<D> {
|
|
||||||
fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> {
|
|
||||||
let len: usize = reader.read_u64::<LittleEndian>()? as usize;
|
|
||||||
if self.keys.len() != len {
|
|
||||||
return Err(std::io::Error::new(
|
|
||||||
std::io::ErrorKind::InvalidData,
|
|
||||||
format!("self.keys.len()={} != read len={}", self.keys.len(), len),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
for key in &mut self.keys {
|
|
||||||
key.read_from(reader)?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<D: DataRef> WriterTo for GLWETensorKey<D> {
|
|
||||||
fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
|
|
||||||
writer.write_u64::<LittleEndian>(self.keys.len() as u64)?;
|
|
||||||
for key in &self.keys {
|
|
||||||
key.write_to(writer)?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(PartialEq, Eq)]
|
|
||||||
pub struct GLWETensorKeyExec<D: Data, B: Backend> {
|
|
||||||
pub(crate) keys: Vec<GLWESwitchingKeyExec<D, B>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<B: Backend> GLWETensorKeyExec<Vec<u8>, B> {
|
|
||||||
pub fn alloc(module: &Module<B>, basek: usize, k: usize, rows: usize, digits: usize, rank: usize) -> Self
|
|
||||||
where
|
|
||||||
Module<B>: GGLWEExecLayoutFamily<B>,
|
|
||||||
{
|
|
||||||
let mut keys: Vec<GLWESwitchingKeyExec<Vec<u8>, B>> = Vec::new();
|
|
||||||
let pairs: usize = (((rank + 1) * rank) >> 1).max(1);
|
|
||||||
(0..pairs).for_each(|_| {
|
|
||||||
keys.push(GLWESwitchingKeyExec::alloc(
|
|
||||||
module, basek, k, rows, digits, 1, rank,
|
|
||||||
));
|
|
||||||
});
|
|
||||||
Self { keys }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn bytes_of(module: &Module<B>, basek: usize, k: usize, rows: usize, digits: usize, rank: usize) -> usize
|
|
||||||
where
|
|
||||||
Module<B>: GGLWEExecLayoutFamily<B>,
|
|
||||||
{
|
|
||||||
let pairs: usize = (((rank + 1) * rank) >> 1).max(1);
|
|
||||||
pairs * GLWESwitchingKeyExec::<Vec<u8>, B>::bytes_of(module, basek, k, rows, digits, 1, rank)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<D: Data, B: Backend> Infos for GLWETensorKeyExec<D, B> {
|
|
||||||
type Inner = VmpPMat<D, B>;
|
|
||||||
|
|
||||||
fn inner(&self) -> &Self::Inner {
|
|
||||||
&self.keys[0].inner()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn basek(&self) -> usize {
|
|
||||||
self.keys[0].basek()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn k(&self) -> usize {
|
|
||||||
self.keys[0].k()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<D: Data, B: Backend> GLWETensorKeyExec<D, B> {
|
|
||||||
pub fn rank(&self) -> usize {
|
|
||||||
self.keys[0].rank()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn rank_in(&self) -> usize {
|
|
||||||
self.keys[0].rank_in()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn rank_out(&self) -> usize {
|
|
||||||
self.keys[0].rank_out()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn digits(&self) -> usize {
|
|
||||||
self.keys[0].digits()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<D: DataMut, B: Backend> GLWETensorKeyExec<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 GLWESwitchingKeyExec<D, B> {
|
|
||||||
if i > j {
|
|
||||||
std::mem::swap(&mut i, &mut j);
|
|
||||||
};
|
|
||||||
let rank: usize = self.rank();
|
|
||||||
&mut self.keys[i * rank + j - (i * (i + 1) / 2)]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<D: DataRef, B: Backend> GLWETensorKeyExec<D, B> {
|
|
||||||
// Returns a reference to GLWESwitchingKey_{s}(s[i] * s[j])
|
|
||||||
pub fn at(&self, mut i: usize, mut j: usize) -> &GLWESwitchingKeyExec<D, B> {
|
|
||||||
if i > j {
|
|
||||||
std::mem::swap(&mut i, &mut j);
|
|
||||||
};
|
|
||||||
let rank: usize = self.rank();
|
|
||||||
&self.keys[i * rank + j - (i * (i + 1) / 2)]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<D: DataMut, B: Backend> GLWETensorKeyExec<D, B> {
|
|
||||||
pub fn prepare<DataOther>(&mut self, module: &Module<B>, other: &GLWETensorKey<DataOther>, scratch: &mut Scratch<B>)
|
|
||||||
where
|
|
||||||
DataOther: DataRef,
|
|
||||||
Module<B>: GGLWEExecLayoutFamily<B>,
|
|
||||||
{
|
|
||||||
#[cfg(debug_assertions)]
|
|
||||||
{
|
|
||||||
assert_eq!(self.keys.len(), other.keys.len());
|
|
||||||
}
|
|
||||||
self.keys
|
|
||||||
.iter_mut()
|
|
||||||
.zip(other.keys.iter())
|
|
||||||
.for_each(|(a, b)| {
|
|
||||||
a.prepare(module, b, scratch);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,138 +0,0 @@
|
|||||||
use backend::{
|
|
||||||
hal::{api::ModuleNew, layouts::Module},
|
|
||||||
implementation::cpu_spqlios::FFT64,
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::gglwe::test::gglwe_generic::{
|
|
||||||
test_encrypt_sk, test_external_product, test_external_product_inplace, test_keyswitch, test_keyswitch_inplace,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn encrypt_sk() {
|
|
||||||
let log_n: usize = 8;
|
|
||||||
let module: Module<FFT64> = Module::<FFT64>::new(1 << log_n);
|
|
||||||
let basek: usize = 12;
|
|
||||||
let k_ksk: usize = 54;
|
|
||||||
let digits: usize = k_ksk / basek;
|
|
||||||
(1..4).for_each(|rank_in| {
|
|
||||||
(1..4).for_each(|rank_out| {
|
|
||||||
(1..digits + 1).for_each(|di| {
|
|
||||||
println!(
|
|
||||||
"test encrypt_sk digits: {} ranks: ({} {})",
|
|
||||||
di, rank_in, rank_out
|
|
||||||
);
|
|
||||||
test_encrypt_sk(&module, basek, k_ksk, di, rank_in, rank_out, 3.2);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn keyswitch() {
|
|
||||||
let log_n: usize = 8;
|
|
||||||
let module: Module<FFT64> = Module::<FFT64>::new(1 << log_n);
|
|
||||||
let basek: usize = 12;
|
|
||||||
let k_in: usize = 60;
|
|
||||||
let digits: usize = k_in.div_ceil(basek);
|
|
||||||
(1..4).for_each(|rank_in_s0s1| {
|
|
||||||
(1..4).for_each(|rank_out_s0s1| {
|
|
||||||
(1..4).for_each(|rank_out_s1s2| {
|
|
||||||
(1..digits + 1).for_each(|di| {
|
|
||||||
let k_ksk: usize = k_in + basek * di;
|
|
||||||
println!(
|
|
||||||
"test key_switch digits: {} ranks: ({},{},{})",
|
|
||||||
di, rank_in_s0s1, rank_out_s0s1, rank_out_s1s2
|
|
||||||
);
|
|
||||||
let k_out: usize = k_ksk; // Better capture noise.
|
|
||||||
test_keyswitch(
|
|
||||||
&module,
|
|
||||||
basek,
|
|
||||||
k_out,
|
|
||||||
k_in,
|
|
||||||
k_ksk,
|
|
||||||
di,
|
|
||||||
rank_in_s0s1,
|
|
||||||
rank_out_s0s1,
|
|
||||||
rank_out_s1s2,
|
|
||||||
3.2,
|
|
||||||
);
|
|
||||||
})
|
|
||||||
})
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn keyswitch_inplace() {
|
|
||||||
let log_n: usize = 8;
|
|
||||||
let module: Module<FFT64> = Module::<FFT64>::new(1 << log_n);
|
|
||||||
let basek: usize = 12;
|
|
||||||
let k_ct: usize = 60;
|
|
||||||
let digits: usize = k_ct.div_ceil(basek);
|
|
||||||
(1..4).for_each(|rank_in_s0s1| {
|
|
||||||
(1..4).for_each(|rank_out_s0s1| {
|
|
||||||
(1..digits + 1).for_each(|di| {
|
|
||||||
let k_ksk: usize = k_ct + basek * di;
|
|
||||||
println!(
|
|
||||||
"test key_switch_inplace digits: {} ranks: ({},{})",
|
|
||||||
di, rank_in_s0s1, rank_out_s0s1
|
|
||||||
);
|
|
||||||
test_keyswitch_inplace(
|
|
||||||
&module,
|
|
||||||
basek,
|
|
||||||
k_ct,
|
|
||||||
k_ksk,
|
|
||||||
di,
|
|
||||||
rank_in_s0s1,
|
|
||||||
rank_out_s0s1,
|
|
||||||
3.2,
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn external_product() {
|
|
||||||
let log_n: usize = 8;
|
|
||||||
let module: Module<FFT64> = Module::<FFT64>::new(1 << log_n);
|
|
||||||
let basek: usize = 12;
|
|
||||||
let k_in: usize = 60;
|
|
||||||
let digits: usize = k_in.div_ceil(basek);
|
|
||||||
(1..4).for_each(|rank_in| {
|
|
||||||
(1..4).for_each(|rank_out| {
|
|
||||||
(1..digits + 1).for_each(|di| {
|
|
||||||
let k_ggsw: usize = k_in + basek * di;
|
|
||||||
println!(
|
|
||||||
"test external_product digits: {} ranks: ({} {})",
|
|
||||||
di, rank_in, rank_out
|
|
||||||
);
|
|
||||||
let k_out: usize = k_in; // Better capture noise.
|
|
||||||
test_external_product(
|
|
||||||
&module, basek, k_out, k_in, k_ggsw, di, rank_in, rank_out, 3.2,
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn external_product_inplace() {
|
|
||||||
let log_n: usize = 5;
|
|
||||||
let module: Module<FFT64> = Module::<FFT64>::new(1 << log_n);
|
|
||||||
let basek: usize = 12;
|
|
||||||
let k_ct: usize = 60;
|
|
||||||
let digits: usize = k_ct.div_ceil(basek);
|
|
||||||
(1..4).for_each(|rank_in| {
|
|
||||||
(1..4).for_each(|rank_out| {
|
|
||||||
(1..digits).for_each(|di| {
|
|
||||||
let k_ggsw: usize = k_ct + basek * di;
|
|
||||||
println!(
|
|
||||||
"test external_product_inplace digits: {} ranks: ({} {})",
|
|
||||||
di, rank_in, rank_out
|
|
||||||
);
|
|
||||||
test_external_product_inplace(&module, basek, k_ct, k_ggsw, di, rank_in, rank_out, 3.2);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
mod automorphism_key;
|
|
||||||
mod gglwe_fft64;
|
|
||||||
mod gglwe_generic;
|
|
||||||
mod tensor_key_fft64;
|
|
||||||
mod tensor_key_generic;
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
use backend::{
|
|
||||||
hal::{api::ModuleNew, layouts::Module},
|
|
||||||
implementation::cpu_spqlios::FFT64,
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::gglwe::test::tensor_key_generic::test_encrypt_sk;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn encrypt_sk() {
|
|
||||||
let log_n: usize = 8;
|
|
||||||
let module: Module<FFT64> = Module::<FFT64>::new(1 << log_n);
|
|
||||||
(1..4).for_each(|rank| {
|
|
||||||
println!("test encrypt_sk rank: {}", rank);
|
|
||||||
test_encrypt_sk(&module, 16, 54, 3.2, rank);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
259
core/src/gglwe/tests/cpu_spqlios/fft64.rs
Normal file
259
core/src/gglwe/tests/cpu_spqlios/fft64.rs
Normal file
@@ -0,0 +1,259 @@
|
|||||||
|
use backend::{
|
||||||
|
hal::{api::ModuleNew, layouts::Module},
|
||||||
|
implementation::cpu_spqlios::FFT64,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::gglwe::tests::{
|
||||||
|
generics_automorphism_key::{
|
||||||
|
test_automorphisk_key_encrypt_sk, test_automorphisk_key_encrypt_sk_compressed, test_gglwe_automorphism,
|
||||||
|
test_gglwe_automorphism_inplace,
|
||||||
|
},
|
||||||
|
generics_gglwe::{
|
||||||
|
test_gglwe_encrypt_sk, test_gglwe_encrypt_sk_compressed, test_gglwe_external_product,
|
||||||
|
test_gglwe_external_product_inplace, test_gglwe_keyswitch, test_gglwe_keyswitch_inplace,
|
||||||
|
},
|
||||||
|
generics_tensor_key::{test_tensor_key_encrypt_sk, test_tensor_key_encrypt_sk_compressed},
|
||||||
|
};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn gglwe_encrypt_sk() {
|
||||||
|
let log_n: usize = 8;
|
||||||
|
let module: Module<FFT64> = Module::<FFT64>::new(1 << log_n);
|
||||||
|
let basek: usize = 12;
|
||||||
|
let k_ksk: usize = 54;
|
||||||
|
let digits: usize = k_ksk / basek;
|
||||||
|
(1..4).for_each(|rank_in| {
|
||||||
|
(1..4).for_each(|rank_out| {
|
||||||
|
(1..digits + 1).for_each(|di| {
|
||||||
|
println!(
|
||||||
|
"test gglwe_encrypt_sk digits: {} ranks: ({} {})",
|
||||||
|
di, rank_in, rank_out
|
||||||
|
);
|
||||||
|
test_gglwe_encrypt_sk(&module, basek, k_ksk, di, rank_in, rank_out, 3.2);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn gglwe_encrypt_sk_compressed() {
|
||||||
|
let log_n: usize = 8;
|
||||||
|
let module: Module<FFT64> = Module::<FFT64>::new(1 << log_n);
|
||||||
|
let basek: usize = 12;
|
||||||
|
let k_ksk: usize = 54;
|
||||||
|
let digits: usize = k_ksk / basek;
|
||||||
|
(1..4).for_each(|rank_in| {
|
||||||
|
(1..4).for_each(|rank_out| {
|
||||||
|
(1..digits + 1).for_each(|di| {
|
||||||
|
println!(
|
||||||
|
"test gglwe_encrypt_sk_compressed digits: {} ranks: ({} {})",
|
||||||
|
di, rank_in, rank_out
|
||||||
|
);
|
||||||
|
test_gglwe_encrypt_sk_compressed(&module, basek, k_ksk, di, rank_in, rank_out, 3.2);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn gglwe_keyswitch() {
|
||||||
|
let log_n: usize = 8;
|
||||||
|
let module: Module<FFT64> = Module::<FFT64>::new(1 << log_n);
|
||||||
|
let basek: usize = 12;
|
||||||
|
let k_in: usize = 60;
|
||||||
|
let digits: usize = k_in.div_ceil(basek);
|
||||||
|
(1..4).for_each(|rank_in_s0s1| {
|
||||||
|
(1..4).for_each(|rank_out_s0s1| {
|
||||||
|
(1..4).for_each(|rank_out_s1s2| {
|
||||||
|
(1..digits + 1).for_each(|di| {
|
||||||
|
let k_ksk: usize = k_in + basek * di;
|
||||||
|
println!(
|
||||||
|
"test gglwe_keyswitch digits: {} ranks: ({},{},{})",
|
||||||
|
di, rank_in_s0s1, rank_out_s0s1, rank_out_s1s2
|
||||||
|
);
|
||||||
|
let k_out: usize = k_ksk; // Better capture noise.
|
||||||
|
test_gglwe_keyswitch(
|
||||||
|
&module,
|
||||||
|
basek,
|
||||||
|
k_out,
|
||||||
|
k_in,
|
||||||
|
k_ksk,
|
||||||
|
di,
|
||||||
|
rank_in_s0s1,
|
||||||
|
rank_out_s0s1,
|
||||||
|
rank_out_s1s2,
|
||||||
|
3.2,
|
||||||
|
);
|
||||||
|
})
|
||||||
|
})
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn gglwe_keyswitch_inplace() {
|
||||||
|
let log_n: usize = 8;
|
||||||
|
let module: Module<FFT64> = Module::<FFT64>::new(1 << log_n);
|
||||||
|
let basek: usize = 12;
|
||||||
|
let k_ct: usize = 60;
|
||||||
|
let digits: usize = k_ct.div_ceil(basek);
|
||||||
|
(1..4).for_each(|rank_in_s0s1| {
|
||||||
|
(1..4).for_each(|rank_out_s0s1| {
|
||||||
|
(1..digits + 1).for_each(|di| {
|
||||||
|
let k_ksk: usize = k_ct + basek * di;
|
||||||
|
println!(
|
||||||
|
"test gglwe_keyswitch_inplace digits: {} ranks: ({},{})",
|
||||||
|
di, rank_in_s0s1, rank_out_s0s1
|
||||||
|
);
|
||||||
|
test_gglwe_keyswitch_inplace(
|
||||||
|
&module,
|
||||||
|
basek,
|
||||||
|
k_ct,
|
||||||
|
k_ksk,
|
||||||
|
di,
|
||||||
|
rank_in_s0s1,
|
||||||
|
rank_out_s0s1,
|
||||||
|
3.2,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn gglwe_external_product() {
|
||||||
|
let log_n: usize = 8;
|
||||||
|
let module: Module<FFT64> = Module::<FFT64>::new(1 << log_n);
|
||||||
|
let basek: usize = 12;
|
||||||
|
let k_in: usize = 60;
|
||||||
|
let digits: usize = k_in.div_ceil(basek);
|
||||||
|
(1..4).for_each(|rank_in| {
|
||||||
|
(1..4).for_each(|rank_out| {
|
||||||
|
(1..digits + 1).for_each(|di| {
|
||||||
|
let k_ggsw: usize = k_in + basek * di;
|
||||||
|
println!(
|
||||||
|
"test gglwe_external_product digits: {} ranks: ({} {})",
|
||||||
|
di, rank_in, rank_out
|
||||||
|
);
|
||||||
|
let k_out: usize = k_in; // Better capture noise.
|
||||||
|
test_gglwe_external_product(
|
||||||
|
&module, basek, k_out, k_in, k_ggsw, di, rank_in, rank_out, 3.2,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn gglwe_external_product_inplace() {
|
||||||
|
let log_n: usize = 5;
|
||||||
|
let module: Module<FFT64> = Module::<FFT64>::new(1 << log_n);
|
||||||
|
let basek: usize = 12;
|
||||||
|
let k_ct: usize = 60;
|
||||||
|
let digits: usize = k_ct.div_ceil(basek);
|
||||||
|
(1..4).for_each(|rank_in| {
|
||||||
|
(1..4).for_each(|rank_out| {
|
||||||
|
(1..digits).for_each(|di| {
|
||||||
|
let k_ggsw: usize = k_ct + basek * di;
|
||||||
|
println!(
|
||||||
|
"test gglwe_external_product_inplace digits: {} ranks: ({} {})",
|
||||||
|
di, rank_in, rank_out
|
||||||
|
);
|
||||||
|
test_gglwe_external_product_inplace(&module, basek, k_ct, k_ggsw, di, rank_in, rank_out, 3.2);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn automorphism_key_encrypt_sk() {
|
||||||
|
let log_n: usize = 8;
|
||||||
|
let module: Module<FFT64> = Module::<FFT64>::new(1 << log_n);
|
||||||
|
let basek: usize = 12;
|
||||||
|
let k: usize = 60;
|
||||||
|
let digits: usize = k.div_ceil(basek) - 1;
|
||||||
|
let sigma: f64 = 3.2;
|
||||||
|
(1..4).for_each(|rank| {
|
||||||
|
(2..digits + 1).for_each(|di| {
|
||||||
|
println!(
|
||||||
|
"test automorphism key encrypt sk digits: {} rank: {}",
|
||||||
|
di, rank
|
||||||
|
);
|
||||||
|
test_automorphisk_key_encrypt_sk(&module, basek, k, di, rank, sigma);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn automorphism_key_encrypt_sk_compressed() {
|
||||||
|
let log_n: usize = 8;
|
||||||
|
let module: Module<FFT64> = Module::<FFT64>::new(1 << log_n);
|
||||||
|
let basek: usize = 12;
|
||||||
|
let k: usize = 60;
|
||||||
|
let digits: usize = k.div_ceil(basek) - 1;
|
||||||
|
let sigma: f64 = 3.2;
|
||||||
|
(1..4).for_each(|rank| {
|
||||||
|
(2..digits + 1).for_each(|di| {
|
||||||
|
println!(
|
||||||
|
"test automorphism key encrypt sk compressed digits: {} rank: {}",
|
||||||
|
di, rank
|
||||||
|
);
|
||||||
|
test_automorphisk_key_encrypt_sk_compressed(&module, basek, k, di, rank, sigma);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn gglwe_automorphism() {
|
||||||
|
let log_n: usize = 8;
|
||||||
|
let module: Module<FFT64> = Module::<FFT64>::new(1 << log_n);
|
||||||
|
let basek: usize = 12;
|
||||||
|
let k_in: usize = 60;
|
||||||
|
let k_out: usize = 40;
|
||||||
|
let digits: usize = k_in.div_ceil(basek);
|
||||||
|
let sigma: f64 = 3.2;
|
||||||
|
(1..4).for_each(|rank| {
|
||||||
|
(2..digits + 1).for_each(|di| {
|
||||||
|
println!("test automorphism digits: {} rank: {}", di, rank);
|
||||||
|
let k_apply: usize = (digits + di) * basek;
|
||||||
|
test_gglwe_automorphism(&module, -1, 5, basek, di, k_in, k_out, k_apply, sigma, rank);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn gglwe_automorphism_inplace() {
|
||||||
|
let log_n: usize = 8;
|
||||||
|
let module: Module<FFT64> = Module::<FFT64>::new(1 << log_n);
|
||||||
|
let basek: usize = 12;
|
||||||
|
let k_in: usize = 60;
|
||||||
|
let digits: usize = k_in.div_ceil(basek);
|
||||||
|
let sigma: f64 = 3.2;
|
||||||
|
(1..4).for_each(|rank| {
|
||||||
|
(2..digits + 1).for_each(|di| {
|
||||||
|
println!("test automorphism_inplace digits: {} rank: {}", di, rank);
|
||||||
|
let k_apply: usize = (digits + di) * basek;
|
||||||
|
test_gglwe_automorphism_inplace(&module, -1, 5, basek, di, k_in, k_apply, sigma, rank);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn tensor_key_encrypt_sk() {
|
||||||
|
let log_n: usize = 8;
|
||||||
|
let module: Module<FFT64> = Module::<FFT64>::new(1 << log_n);
|
||||||
|
(1..4).for_each(|rank| {
|
||||||
|
println!("test encrypt_sk rank: {}", rank);
|
||||||
|
test_tensor_key_encrypt_sk(&module, 16, 54, 3.2, rank);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn tensor_key_encrypt_sk_compressed() {
|
||||||
|
let log_n: usize = 8;
|
||||||
|
let module: Module<FFT64> = Module::<FFT64>::new(1 << log_n);
|
||||||
|
(1..4).for_each(|rank| {
|
||||||
|
println!("test encrypt_sk_compressed rank: {}", rank);
|
||||||
|
test_tensor_key_encrypt_sk_compressed(&module, 16, 54, 3.2, rank);
|
||||||
|
});
|
||||||
|
}
|
||||||
1
core/src/gglwe/tests/cpu_spqlios/mod.rs
Normal file
1
core/src/gglwe/tests/cpu_spqlios/mod.rs
Normal file
@@ -0,0 +1 @@
|
|||||||
|
mod fft64;
|
||||||
@@ -1,53 +1,168 @@
|
|||||||
use backend::{
|
use backend::hal::{
|
||||||
hal::{
|
api::{
|
||||||
api::{ModuleNew, ScalarZnxAutomorphism, ScratchOwnedAlloc, ScratchOwnedBorrow, VecZnxStd, VecZnxSubScalarInplace},
|
MatZnxAlloc, ScalarZnxAlloc, ScalarZnxAllocBytes, ScratchOwnedAlloc, ScratchOwnedBorrow, VecZnxAddScalarInplace,
|
||||||
layouts::{Module, ScratchOwned},
|
VecZnxAlloc, VecZnxAllocBytes, VecZnxAutomorphism, VecZnxAutomorphismInplace, VecZnxCopy, VecZnxStd,
|
||||||
|
VecZnxSubScalarInplace, VecZnxSwithcDegree,
|
||||||
|
},
|
||||||
|
layouts::{Backend, Module, ScratchOwned},
|
||||||
|
oep::{
|
||||||
|
ScratchAvailableImpl, ScratchOwnedAllocImpl, ScratchOwnedBorrowImpl, TakeScalarZnxImpl, TakeSvpPPolImpl,
|
||||||
|
TakeVecZnxBigImpl, TakeVecZnxDftImpl, TakeVecZnxImpl,
|
||||||
},
|
},
|
||||||
implementation::cpu_spqlios::FFT64,
|
|
||||||
};
|
};
|
||||||
use sampling::source::Source;
|
use sampling::source::Source;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
AutomorphismKey, AutomorphismKeyExec, GLWEPlaintext, GLWESecret, GLWESecretExec, Infos, noise::log2_std_noise_gglwe_product,
|
AutomorphismKey, AutomorphismKeyCompressed, AutomorphismKeyEncryptSkFamily, AutomorphismKeyExec, GGLWEExecLayoutFamily,
|
||||||
|
GLWEDecryptFamily, GLWEKeyswitchFamily, GLWEPlaintext, GLWESecret, GLWESecretExec, Infos,
|
||||||
|
noise::log2_std_noise_gglwe_product,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[test]
|
pub(crate) trait AutomorphismTestModuleFamily<B: Backend> = MatZnxAlloc
|
||||||
fn automorphism() {
|
+ AutomorphismKeyEncryptSkFamily<B>
|
||||||
let log_n: usize = 8;
|
+ ScalarZnxAllocBytes
|
||||||
let basek: usize = 12;
|
+ VecZnxAllocBytes
|
||||||
let k_in: usize = 60;
|
+ GLWEKeyswitchFamily<B>
|
||||||
let k_out: usize = 40;
|
+ ScalarZnxAlloc
|
||||||
let digits: usize = k_in.div_ceil(basek);
|
+ VecZnxAutomorphism
|
||||||
let sigma: f64 = 3.2;
|
+ GGLWEExecLayoutFamily<B>
|
||||||
(1..4).for_each(|rank| {
|
+ VecZnxSwithcDegree
|
||||||
(2..digits + 1).for_each(|di| {
|
+ VecZnxAddScalarInplace
|
||||||
println!("test automorphism digits: {} rank: {}", di, rank);
|
+ VecZnxAutomorphism
|
||||||
let k_apply: usize = (digits + di) * basek;
|
+ VecZnxAutomorphismInplace
|
||||||
test_automorphism(-1, 5, log_n, basek, di, k_in, k_out, k_apply, sigma, rank);
|
+ VecZnxAlloc
|
||||||
});
|
+ GLWEDecryptFamily<B>
|
||||||
|
+ VecZnxSubScalarInplace
|
||||||
|
+ VecZnxStd
|
||||||
|
+ VecZnxCopy;
|
||||||
|
pub(crate) trait AutomorphismTestScratchFamily<B: Backend> = ScratchOwnedAllocImpl<B>
|
||||||
|
+ ScratchOwnedBorrowImpl<B>
|
||||||
|
+ ScratchAvailableImpl<B>
|
||||||
|
+ TakeScalarZnxImpl<B>
|
||||||
|
+ TakeVecZnxDftImpl<B>
|
||||||
|
+ TakeVecZnxImpl<B>
|
||||||
|
+ TakeSvpPPolImpl<B>
|
||||||
|
+ TakeVecZnxBigImpl<B>;
|
||||||
|
|
||||||
|
pub(crate) fn test_automorphisk_key_encrypt_sk<B: Backend>(
|
||||||
|
module: &Module<B>,
|
||||||
|
basek: usize,
|
||||||
|
k_ksk: usize,
|
||||||
|
digits: usize,
|
||||||
|
rank: usize,
|
||||||
|
sigma: f64,
|
||||||
|
) where
|
||||||
|
Module<B>: AutomorphismTestModuleFamily<B>,
|
||||||
|
B: AutomorphismTestScratchFamily<B>,
|
||||||
|
{
|
||||||
|
let rows: usize = (k_ksk - digits * basek) / (digits * basek);
|
||||||
|
|
||||||
|
let mut atk: AutomorphismKey<Vec<u8>> = AutomorphismKey::alloc(module, basek, k_ksk, rows, digits, rank);
|
||||||
|
|
||||||
|
let mut source_xs: Source = Source::new([0u8; 32]);
|
||||||
|
let mut source_xe: Source = Source::new([0u8; 32]);
|
||||||
|
let mut source_xa: Source = Source::new([0u8; 32]);
|
||||||
|
|
||||||
|
let mut scratch: ScratchOwned<B> = ScratchOwned::alloc(AutomorphismKey::encrypt_sk_scratch_space(
|
||||||
|
module, basek, k_ksk, rank,
|
||||||
|
));
|
||||||
|
|
||||||
|
let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(module, rank);
|
||||||
|
sk.fill_ternary_prob(0.5, &mut source_xs);
|
||||||
|
|
||||||
|
let p = -5;
|
||||||
|
|
||||||
|
atk.encrypt_sk(
|
||||||
|
module,
|
||||||
|
p,
|
||||||
|
&sk,
|
||||||
|
&mut source_xa,
|
||||||
|
&mut source_xe,
|
||||||
|
sigma,
|
||||||
|
scratch.borrow(),
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut sk_out: GLWESecret<Vec<u8>> = sk.clone();
|
||||||
|
(0..atk.rank()).for_each(|i| {
|
||||||
|
module.vec_znx_automorphism(
|
||||||
|
module.galois_element_inv(p),
|
||||||
|
&mut sk_out.data.as_vec_znx_mut(),
|
||||||
|
i,
|
||||||
|
&sk.data.as_vec_znx(),
|
||||||
|
i,
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
let sk_out_exec = GLWESecretExec::from(module, &sk_out);
|
||||||
|
|
||||||
|
atk.key
|
||||||
|
.key
|
||||||
|
.assert_noise(module, &sk_out_exec, &sk.data, sigma);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
pub(crate) fn test_automorphisk_key_encrypt_sk_compressed<B: Backend>(
|
||||||
fn automorphism_inplace() {
|
module: &Module<B>,
|
||||||
let log_n: usize = 8;
|
basek: usize,
|
||||||
let basek: usize = 12;
|
k_ksk: usize,
|
||||||
let k_in: usize = 60;
|
digits: usize,
|
||||||
let digits: usize = k_in.div_ceil(basek);
|
rank: usize,
|
||||||
let sigma: f64 = 3.2;
|
sigma: f64,
|
||||||
(1..4).for_each(|rank| {
|
) where
|
||||||
(2..digits + 1).for_each(|di| {
|
Module<B>: AutomorphismTestModuleFamily<B>,
|
||||||
println!("test automorphism digits: {} rank: {}", di, rank);
|
B: AutomorphismTestScratchFamily<B>,
|
||||||
let k_apply: usize = (digits + di) * basek;
|
{
|
||||||
test_automorphism_inplace(-1, 5, log_n, basek, di, k_in, k_apply, sigma, rank);
|
let rows: usize = (k_ksk - digits * basek) / (digits * basek);
|
||||||
});
|
|
||||||
|
let mut atk_compressed: AutomorphismKeyCompressed<Vec<u8>> =
|
||||||
|
AutomorphismKeyCompressed::alloc(module, basek, k_ksk, rows, digits, rank);
|
||||||
|
|
||||||
|
let mut source_xs: Source = Source::new([0u8; 32]);
|
||||||
|
let mut source_xe: Source = Source::new([0u8; 32]);
|
||||||
|
|
||||||
|
let mut scratch: ScratchOwned<B> = ScratchOwned::alloc(AutomorphismKey::encrypt_sk_scratch_space(
|
||||||
|
module, basek, k_ksk, rank,
|
||||||
|
));
|
||||||
|
|
||||||
|
let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(module, rank);
|
||||||
|
sk.fill_ternary_prob(0.5, &mut source_xs);
|
||||||
|
|
||||||
|
let p = -5;
|
||||||
|
|
||||||
|
let seed_xa: [u8; 32] = [1u8; 32];
|
||||||
|
|
||||||
|
atk_compressed.encrypt_sk(
|
||||||
|
module,
|
||||||
|
p,
|
||||||
|
&sk,
|
||||||
|
seed_xa,
|
||||||
|
&mut source_xe,
|
||||||
|
sigma,
|
||||||
|
scratch.borrow(),
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut sk_out: GLWESecret<Vec<u8>> = sk.clone();
|
||||||
|
(0..atk_compressed.rank()).for_each(|i| {
|
||||||
|
module.vec_znx_automorphism(
|
||||||
|
module.galois_element_inv(p),
|
||||||
|
&mut sk_out.data.as_vec_znx_mut(),
|
||||||
|
i,
|
||||||
|
&sk.data.as_vec_znx(),
|
||||||
|
i,
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
let sk_out_exec = GLWESecretExec::from(module, &sk_out);
|
||||||
|
|
||||||
|
let mut atk: AutomorphismKey<Vec<u8>> = AutomorphismKey::alloc(module, basek, k_ksk, rows, digits, rank);
|
||||||
|
atk.decompress(module, &atk_compressed);
|
||||||
|
|
||||||
|
atk.key
|
||||||
|
.key
|
||||||
|
.assert_noise(module, &sk_out_exec, &sk.data, sigma);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_automorphism(
|
pub(crate) fn test_gglwe_automorphism<B: Backend>(
|
||||||
|
module: &Module<B>,
|
||||||
p0: i64,
|
p0: i64,
|
||||||
p1: i64,
|
p1: i64,
|
||||||
log_n: usize,
|
|
||||||
basek: usize,
|
basek: usize,
|
||||||
digits: usize,
|
digits: usize,
|
||||||
k_in: usize,
|
k_in: usize,
|
||||||
@@ -55,9 +170,10 @@ fn test_automorphism(
|
|||||||
k_apply: usize,
|
k_apply: usize,
|
||||||
sigma: f64,
|
sigma: f64,
|
||||||
rank: usize,
|
rank: usize,
|
||||||
) {
|
) where
|
||||||
let module: Module<FFT64> = Module::<FFT64>::new(1 << log_n);
|
Module<B>: AutomorphismTestModuleFamily<B>,
|
||||||
|
B: AutomorphismTestScratchFamily<B>,
|
||||||
|
{
|
||||||
let digits_in: usize = 1;
|
let digits_in: usize = 1;
|
||||||
|
|
||||||
let rows_in: usize = k_in / (basek * digits);
|
let rows_in: usize = k_in / (basek * digits);
|
||||||
@@ -71,7 +187,7 @@ fn test_automorphism(
|
|||||||
let mut source_xe: Source = Source::new([0u8; 32]);
|
let mut source_xe: Source = Source::new([0u8; 32]);
|
||||||
let mut source_xa: Source = Source::new([0u8; 32]);
|
let mut source_xa: Source = Source::new([0u8; 32]);
|
||||||
|
|
||||||
let mut scratch: ScratchOwned<FFT64> = ScratchOwned::alloc(
|
let mut scratch: ScratchOwned<B> = ScratchOwned::alloc(
|
||||||
AutomorphismKey::encrypt_sk_scratch_space(&module, basek, k_apply, rank)
|
AutomorphismKey::encrypt_sk_scratch_space(&module, basek, k_apply, rank)
|
||||||
| AutomorphismKey::automorphism_scratch_space(&module, basek, k_out, k_in, k_apply, digits, rank),
|
| AutomorphismKey::automorphism_scratch_space(&module, basek, k_out, k_in, k_apply, digits, rank),
|
||||||
);
|
);
|
||||||
@@ -101,7 +217,7 @@ fn test_automorphism(
|
|||||||
scratch.borrow(),
|
scratch.borrow(),
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut auto_key_apply_exec: AutomorphismKeyExec<Vec<u8>, FFT64> =
|
let mut auto_key_apply_exec: AutomorphismKeyExec<Vec<u8>, B> =
|
||||||
AutomorphismKeyExec::alloc(&module, basek, k_apply, rows_apply, digits, rank);
|
AutomorphismKeyExec::alloc(&module, basek, k_apply, rows_apply, digits, rank);
|
||||||
|
|
||||||
auto_key_apply_exec.prepare(&module, &auto_key_apply, scratch.borrow());
|
auto_key_apply_exec.prepare(&module, &auto_key_apply, scratch.borrow());
|
||||||
@@ -119,16 +235,16 @@ fn test_automorphism(
|
|||||||
let mut sk_auto: GLWESecret<Vec<u8>> = GLWESecret::alloc(&module, rank);
|
let mut sk_auto: GLWESecret<Vec<u8>> = GLWESecret::alloc(&module, rank);
|
||||||
sk_auto.fill_zero(); // Necessary to avoid panic of unfilled sk
|
sk_auto.fill_zero(); // Necessary to avoid panic of unfilled sk
|
||||||
(0..rank).for_each(|i| {
|
(0..rank).for_each(|i| {
|
||||||
module.scalar_znx_automorphism(
|
module.vec_znx_automorphism(
|
||||||
module.galois_element_inv(p0 * p1),
|
module.galois_element_inv(p0 * p1),
|
||||||
&mut sk_auto.data,
|
&mut sk_auto.data.as_vec_znx_mut(),
|
||||||
i,
|
i,
|
||||||
&sk.data,
|
&sk.data.as_vec_znx(),
|
||||||
i,
|
i,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
let sk_auto_dft: GLWESecretExec<Vec<u8>, FFT64> = GLWESecretExec::from(&module, &sk_auto);
|
let sk_auto_dft: GLWESecretExec<Vec<u8>, B> = GLWESecretExec::from(&module, &sk_auto);
|
||||||
|
|
||||||
(0..auto_key_out.rank_in()).for_each(|col_i| {
|
(0..auto_key_out.rank_in()).for_each(|col_i| {
|
||||||
(0..auto_key_out.rows()).for_each(|row_i| {
|
(0..auto_key_out.rows()).for_each(|row_i| {
|
||||||
@@ -168,19 +284,20 @@ fn test_automorphism(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_automorphism_inplace(
|
pub(crate) fn test_gglwe_automorphism_inplace<B: Backend>(
|
||||||
|
module: &Module<B>,
|
||||||
p0: i64,
|
p0: i64,
|
||||||
p1: i64,
|
p1: i64,
|
||||||
log_n: usize,
|
|
||||||
basek: usize,
|
basek: usize,
|
||||||
digits: usize,
|
digits: usize,
|
||||||
k_in: usize,
|
k_in: usize,
|
||||||
k_apply: usize,
|
k_apply: usize,
|
||||||
sigma: f64,
|
sigma: f64,
|
||||||
rank: usize,
|
rank: usize,
|
||||||
) {
|
) where
|
||||||
let module: Module<FFT64> = Module::<FFT64>::new(1 << log_n);
|
Module<B>: AutomorphismTestModuleFamily<B>,
|
||||||
|
B: AutomorphismTestScratchFamily<B>,
|
||||||
|
{
|
||||||
let digits_in: usize = 1;
|
let digits_in: usize = 1;
|
||||||
|
|
||||||
let rows_in: usize = k_in / (basek * digits);
|
let rows_in: usize = k_in / (basek * digits);
|
||||||
@@ -193,7 +310,7 @@ fn test_automorphism_inplace(
|
|||||||
let mut source_xe: Source = Source::new([0u8; 32]);
|
let mut source_xe: Source = Source::new([0u8; 32]);
|
||||||
let mut source_xa: Source = Source::new([0u8; 32]);
|
let mut source_xa: Source = Source::new([0u8; 32]);
|
||||||
|
|
||||||
let mut scratch: ScratchOwned<FFT64> = ScratchOwned::alloc(
|
let mut scratch: ScratchOwned<B> = ScratchOwned::alloc(
|
||||||
AutomorphismKey::encrypt_sk_scratch_space(&module, basek, k_apply, rank)
|
AutomorphismKey::encrypt_sk_scratch_space(&module, basek, k_apply, rank)
|
||||||
| AutomorphismKey::automorphism_inplace_scratch_space(&module, basek, k_in, k_apply, digits, rank),
|
| AutomorphismKey::automorphism_inplace_scratch_space(&module, basek, k_in, k_apply, digits, rank),
|
||||||
);
|
);
|
||||||
@@ -223,7 +340,7 @@ fn test_automorphism_inplace(
|
|||||||
scratch.borrow(),
|
scratch.borrow(),
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut auto_key_apply_exec: AutomorphismKeyExec<Vec<u8>, FFT64> =
|
let mut auto_key_apply_exec: AutomorphismKeyExec<Vec<u8>, B> =
|
||||||
AutomorphismKeyExec::alloc(&module, basek, k_apply, rows_apply, digits, rank);
|
AutomorphismKeyExec::alloc(&module, basek, k_apply, rows_apply, digits, rank);
|
||||||
|
|
||||||
auto_key_apply_exec.prepare(&module, &auto_key_apply, scratch.borrow());
|
auto_key_apply_exec.prepare(&module, &auto_key_apply, scratch.borrow());
|
||||||
@@ -237,16 +354,16 @@ fn test_automorphism_inplace(
|
|||||||
sk_auto.fill_zero(); // Necessary to avoid panic of unfilled sk
|
sk_auto.fill_zero(); // Necessary to avoid panic of unfilled sk
|
||||||
|
|
||||||
(0..rank).for_each(|i| {
|
(0..rank).for_each(|i| {
|
||||||
module.scalar_znx_automorphism(
|
module.vec_znx_automorphism(
|
||||||
module.galois_element_inv(p0 * p1),
|
module.galois_element_inv(p0 * p1),
|
||||||
&mut sk_auto.data,
|
&mut sk_auto.data.as_vec_znx_mut(),
|
||||||
i,
|
i,
|
||||||
&sk.data,
|
&sk.data.as_vec_znx(),
|
||||||
i,
|
i,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
let sk_auto_dft: GLWESecretExec<Vec<u8>, FFT64> = GLWESecretExec::from(&module, &sk_auto);
|
let sk_auto_dft: GLWESecretExec<Vec<u8>, B> = GLWESecretExec::from(&module, &sk_auto);
|
||||||
|
|
||||||
(0..auto_key.rank_in()).for_each(|col_i| {
|
(0..auto_key.rank_in()).for_each(|col_i| {
|
||||||
(0..auto_key.rows()).for_each(|row_i| {
|
(0..auto_key.rows()).for_each(|row_i| {
|
||||||
@@ -1,7 +1,8 @@
|
|||||||
use backend::hal::{
|
use backend::hal::{
|
||||||
api::{
|
api::{
|
||||||
MatZnxAlloc, ScalarZnxAlloc, ScalarZnxAllocBytes, ScratchOwnedAlloc, ScratchOwnedBorrow, VecZnxAddScalarInplace,
|
MatZnxAlloc, ScalarZnxAlloc, ScalarZnxAllocBytes, ScratchOwnedAlloc, ScratchOwnedBorrow, VecZnxAddScalarInplace,
|
||||||
VecZnxAlloc, VecZnxAllocBytes, VecZnxRotateInplace, VecZnxStd, VecZnxSubScalarInplace, VecZnxSwithcDegree, ZnxViewMut,
|
VecZnxAlloc, VecZnxAllocBytes, VecZnxCopy, VecZnxRotateInplace, VecZnxStd, VecZnxSubScalarInplace, VecZnxSwithcDegree,
|
||||||
|
ZnxViewMut,
|
||||||
},
|
},
|
||||||
layouts::{Backend, Module, ScalarZnx, ScalarZnxToMut, ScratchOwned},
|
layouts::{Backend, Module, ScalarZnx, ScalarZnxToMut, ScratchOwned},
|
||||||
oep::{
|
oep::{
|
||||||
@@ -13,7 +14,7 @@ use sampling::source::Source;
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
GGLWEEncryptSkFamily, GGLWEExecLayoutFamily, GGSWCiphertext, GGSWCiphertextExec, GGSWLayoutFamily, GLWEDecryptFamily,
|
GGLWEEncryptSkFamily, GGLWEExecLayoutFamily, GGSWCiphertext, GGSWCiphertextExec, GGSWLayoutFamily, GLWEDecryptFamily,
|
||||||
GLWEExternalProductFamily, GLWEKeyswitchFamily, GLWESecret, GLWESecretExec, GLWESwitchingKey,
|
GLWEExternalProductFamily, GLWEKeyswitchFamily, GLWESecret, GLWESecretExec, GLWESwitchingKey, GLWESwitchingKeyCompressed,
|
||||||
GLWESwitchingKeyEncryptSkFamily, GLWESwitchingKeyExec,
|
GLWESwitchingKeyEncryptSkFamily, GLWESwitchingKeyExec,
|
||||||
noise::{log2_std_noise_gglwe_product, noise_ggsw_product},
|
noise::{log2_std_noise_gglwe_product, noise_ggsw_product},
|
||||||
};
|
};
|
||||||
@@ -28,7 +29,8 @@ pub(crate) trait TestModuleFamily<B: Backend> = GGLWEEncryptSkFamily<B>
|
|||||||
+ VecZnxAddScalarInplace
|
+ VecZnxAddScalarInplace
|
||||||
+ VecZnxStd
|
+ VecZnxStd
|
||||||
+ VecZnxAlloc
|
+ VecZnxAlloc
|
||||||
+ VecZnxSubScalarInplace;
|
+ VecZnxSubScalarInplace
|
||||||
|
+ VecZnxCopy;
|
||||||
|
|
||||||
pub(crate) trait TestScratchFamily<B: Backend> = TakeVecZnxDftImpl<B>
|
pub(crate) trait TestScratchFamily<B: Backend> = TakeVecZnxDftImpl<B>
|
||||||
+ TakeVecZnxBigImpl<B>
|
+ TakeVecZnxBigImpl<B>
|
||||||
@@ -42,7 +44,7 @@ pub(crate) trait TestScratchFamily<B: Backend> = TakeVecZnxDftImpl<B>
|
|||||||
+ VecZnxBigAllocBytesImpl<B>
|
+ VecZnxBigAllocBytesImpl<B>
|
||||||
+ TakeSvpPPolImpl<B>;
|
+ TakeSvpPPolImpl<B>;
|
||||||
|
|
||||||
pub(crate) fn test_encrypt_sk<B: Backend>(
|
pub(crate) fn test_gglwe_encrypt_sk<B: Backend>(
|
||||||
module: &Module<B>,
|
module: &Module<B>,
|
||||||
basek: usize,
|
basek: usize,
|
||||||
k_ksk: usize,
|
k_ksk: usize,
|
||||||
@@ -87,7 +89,57 @@ pub(crate) fn test_encrypt_sk<B: Backend>(
|
|||||||
.assert_noise(module, &sk_out_exec, &sk_in.data, sigma);
|
.assert_noise(module, &sk_out_exec, &sk_in.data, sigma);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn test_keyswitch<B: Backend>(
|
pub(crate) fn test_gglwe_encrypt_sk_compressed<B: Backend>(
|
||||||
|
module: &Module<B>,
|
||||||
|
basek: usize,
|
||||||
|
k_ksk: usize,
|
||||||
|
digits: usize,
|
||||||
|
rank_in: usize,
|
||||||
|
rank_out: usize,
|
||||||
|
sigma: f64,
|
||||||
|
) where
|
||||||
|
Module<B>: TestModuleFamily<B>,
|
||||||
|
B: TestScratchFamily<B>,
|
||||||
|
{
|
||||||
|
let rows: usize = (k_ksk - digits * basek) / (digits * basek);
|
||||||
|
|
||||||
|
let mut ksk_compressed: GLWESwitchingKeyCompressed<Vec<u8>> =
|
||||||
|
GLWESwitchingKeyCompressed::alloc(module, basek, k_ksk, rows, digits, rank_in, rank_out);
|
||||||
|
|
||||||
|
let mut source_xs: Source = Source::new([0u8; 32]);
|
||||||
|
let mut source_xe: Source = Source::new([0u8; 32]);
|
||||||
|
|
||||||
|
let mut scratch: ScratchOwned<B> = ScratchOwned::alloc(GLWESwitchingKeyCompressed::encrypt_sk_scratch_space(
|
||||||
|
module, basek, k_ksk, rank_in, rank_out,
|
||||||
|
));
|
||||||
|
|
||||||
|
let mut sk_in: GLWESecret<Vec<u8>> = GLWESecret::alloc(module, rank_in);
|
||||||
|
sk_in.fill_ternary_prob(0.5, &mut source_xs);
|
||||||
|
|
||||||
|
let mut sk_out: GLWESecret<Vec<u8>> = GLWESecret::alloc(module, rank_out);
|
||||||
|
sk_out.fill_ternary_prob(0.5, &mut source_xs);
|
||||||
|
let sk_out_exec: GLWESecretExec<Vec<u8>, B> = GLWESecretExec::from(module, &sk_out);
|
||||||
|
|
||||||
|
let seed_xa = [1u8; 32];
|
||||||
|
|
||||||
|
ksk_compressed.encrypt_sk(
|
||||||
|
module,
|
||||||
|
&sk_in,
|
||||||
|
&sk_out,
|
||||||
|
seed_xa,
|
||||||
|
&mut source_xe,
|
||||||
|
sigma,
|
||||||
|
scratch.borrow(),
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut ksk: GLWESwitchingKey<Vec<u8>> = GLWESwitchingKey::alloc(module, basek, k_ksk, rows, digits, rank_in, rank_out);
|
||||||
|
ksk.decompress(module, &ksk_compressed);
|
||||||
|
|
||||||
|
ksk.key
|
||||||
|
.assert_noise(module, &sk_out_exec, &sk_in.data, sigma);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn test_gglwe_keyswitch<B: Backend>(
|
||||||
module: &Module<B>,
|
module: &Module<B>,
|
||||||
basek: usize,
|
basek: usize,
|
||||||
k_out: usize,
|
k_out: usize,
|
||||||
@@ -217,7 +269,7 @@ pub(crate) fn test_keyswitch<B: Backend>(
|
|||||||
.assert_noise(module, &sk2_exec, &sk0.data, max_noise + 0.5);
|
.assert_noise(module, &sk2_exec, &sk0.data, max_noise + 0.5);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn test_keyswitch_inplace<B: Backend>(
|
pub(crate) fn test_gglwe_keyswitch_inplace<B: Backend>(
|
||||||
module: &Module<B>,
|
module: &Module<B>,
|
||||||
basek: usize,
|
basek: usize,
|
||||||
k_ct: usize,
|
k_ct: usize,
|
||||||
@@ -317,7 +369,7 @@ pub(crate) fn test_keyswitch_inplace<B: Backend>(
|
|||||||
.assert_noise(module, &sk2_exec, &sk0.data, max_noise + 0.5);
|
.assert_noise(module, &sk2_exec, &sk0.data, max_noise + 0.5);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn test_external_product<B: Backend>(
|
pub(crate) fn test_gglwe_external_product<B: Backend>(
|
||||||
module: &Module<B>,
|
module: &Module<B>,
|
||||||
basek: usize,
|
basek: usize,
|
||||||
k_out: usize,
|
k_out: usize,
|
||||||
@@ -400,7 +452,7 @@ pub(crate) fn test_external_product<B: Backend>(
|
|||||||
ct_gglwe_out.external_product(module, &ct_gglwe_in, &ct_rgsw_exec, scratch.borrow());
|
ct_gglwe_out.external_product(module, &ct_gglwe_in, &ct_rgsw_exec, scratch.borrow());
|
||||||
|
|
||||||
(0..rank_in).for_each(|i| {
|
(0..rank_in).for_each(|i| {
|
||||||
module.vec_znx_rotate_inplace(r as i64, &mut sk_in.data, i); // * X^{r}
|
module.vec_znx_rotate_inplace(r as i64, &mut sk_in.data.as_vec_znx_mut(), i); // * X^{r}
|
||||||
});
|
});
|
||||||
|
|
||||||
let var_gct_err_lhs: f64 = sigma * sigma;
|
let var_gct_err_lhs: f64 = sigma * sigma;
|
||||||
@@ -429,7 +481,7 @@ pub(crate) fn test_external_product<B: Backend>(
|
|||||||
.assert_noise(module, &sk_out_exec, &sk_in.data, max_noise + 0.5);
|
.assert_noise(module, &sk_out_exec, &sk_in.data, max_noise + 0.5);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn test_external_product_inplace<B: Backend>(
|
pub(crate) fn test_gglwe_external_product_inplace<B: Backend>(
|
||||||
module: &Module<B>,
|
module: &Module<B>,
|
||||||
basek: usize,
|
basek: usize,
|
||||||
k_ct: usize,
|
k_ct: usize,
|
||||||
@@ -510,7 +562,7 @@ pub(crate) fn test_external_product_inplace<B: Backend>(
|
|||||||
ct_gglwe.external_product_inplace(module, &ct_rgsw_exec, scratch.borrow());
|
ct_gglwe.external_product_inplace(module, &ct_rgsw_exec, scratch.borrow());
|
||||||
|
|
||||||
(0..rank_in).for_each(|i| {
|
(0..rank_in).for_each(|i| {
|
||||||
module.vec_znx_rotate_inplace(r as i64, &mut sk_in.data, i); // * X^{r}
|
module.vec_znx_rotate_inplace(r as i64, &mut sk_in.data.as_vec_znx_mut(), i); // * X^{r}
|
||||||
});
|
});
|
||||||
|
|
||||||
let var_gct_err_lhs: f64 = sigma * sigma;
|
let var_gct_err_lhs: f64 = sigma * sigma;
|
||||||
@@ -1,7 +1,8 @@
|
|||||||
use backend::hal::{
|
use backend::hal::{
|
||||||
api::{
|
api::{
|
||||||
MatZnxAlloc, ScalarZnxAlloc, ScalarZnxAllocBytes, ScratchOwnedAlloc, ScratchOwnedBorrow, VecZnxAddScalarInplace,
|
MatZnxAlloc, ScalarZnxAlloc, ScalarZnxAllocBytes, ScratchOwnedAlloc, ScratchOwnedBorrow, VecZnxAddScalarInplace,
|
||||||
VecZnxAlloc, VecZnxAllocBytes, VecZnxBigAlloc, VecZnxDftAlloc, VecZnxStd, VecZnxSubScalarInplace, VecZnxSwithcDegree,
|
VecZnxAlloc, VecZnxAllocBytes, VecZnxBigAlloc, VecZnxCopy, VecZnxDftAlloc, VecZnxStd, VecZnxSubScalarInplace,
|
||||||
|
VecZnxSwithcDegree,
|
||||||
},
|
},
|
||||||
layouts::{Backend, Module, ScratchOwned, VecZnxDft},
|
layouts::{Backend, Module, ScratchOwned, VecZnxDft},
|
||||||
oep::{
|
oep::{
|
||||||
@@ -13,7 +14,7 @@ use sampling::source::Source;
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
GGLWEEncryptSkFamily, GGLWEExecLayoutFamily, GLWEDecryptFamily, GLWEPlaintext, GLWESecret, GLWESecretExec, GLWETensorKey,
|
GGLWEEncryptSkFamily, GGLWEExecLayoutFamily, GLWEDecryptFamily, GLWEPlaintext, GLWESecret, GLWESecretExec, GLWETensorKey,
|
||||||
GLWETensorKeyEncryptSkFamily, Infos,
|
GLWETensorKeyCompressed, GLWETensorKeyEncryptSkFamily, Infos,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub(crate) trait TestModuleFamily<B: Backend> = GGLWEEncryptSkFamily<B>
|
pub(crate) trait TestModuleFamily<B: Backend> = GGLWEEncryptSkFamily<B>
|
||||||
@@ -40,7 +41,7 @@ pub(crate) trait TestScratchFamily<B: Backend> = TakeVecZnxDftImpl<B>
|
|||||||
+ VecZnxBigAllocBytesImpl<B>
|
+ VecZnxBigAllocBytesImpl<B>
|
||||||
+ TakeSvpPPolImpl<B>;
|
+ TakeSvpPPolImpl<B>;
|
||||||
|
|
||||||
pub(crate) fn test_encrypt_sk<B: Backend>(module: &Module<B>, basek: usize, k: usize, sigma: f64, rank: usize)
|
pub(crate) fn test_tensor_key_encrypt_sk<B: Backend>(module: &Module<B>, basek: usize, k: usize, sigma: f64, rank: usize)
|
||||||
where
|
where
|
||||||
Module<B>: TestModuleFamily<B>
|
Module<B>: TestModuleFamily<B>
|
||||||
+ GGLWEExecLayoutFamily<B>
|
+ GGLWEExecLayoutFamily<B>
|
||||||
@@ -87,14 +88,111 @@ where
|
|||||||
let mut sk_dft: VecZnxDft<Vec<u8>, B> = module.vec_znx_dft_alloc(rank, 1);
|
let mut sk_dft: VecZnxDft<Vec<u8>, B> = module.vec_znx_dft_alloc(rank, 1);
|
||||||
|
|
||||||
(0..rank).for_each(|i| {
|
(0..rank).for_each(|i| {
|
||||||
module.vec_znx_dft_from_vec_znx(1, 0, &mut sk_dft, i, &sk.data, i);
|
module.vec_znx_dft_from_vec_znx(1, 0, &mut sk_dft, i, &sk.data.as_vec_znx(), i);
|
||||||
});
|
});
|
||||||
|
|
||||||
(0..rank).for_each(|i| {
|
(0..rank).for_each(|i| {
|
||||||
(0..rank).for_each(|j| {
|
(0..rank).for_each(|j| {
|
||||||
module.svp_apply(&mut sk_ij_dft, 0, &sk_exec.data, j, &sk_dft, i);
|
module.svp_apply(&mut sk_ij_dft, 0, &sk_exec.data, j, &sk_dft, i);
|
||||||
module.vec_znx_dft_to_vec_znx_big_tmp_a(&mut sk_ij_big, 0, &mut sk_ij_dft, 0);
|
module.vec_znx_dft_to_vec_znx_big_tmp_a(&mut sk_ij_big, 0, &mut sk_ij_dft, 0);
|
||||||
module.vec_znx_big_normalize(basek, &mut sk_ij.data, 0, &sk_ij_big, 0, scratch.borrow());
|
module.vec_znx_big_normalize(
|
||||||
|
basek,
|
||||||
|
&mut sk_ij.data.as_vec_znx_mut(),
|
||||||
|
0,
|
||||||
|
&sk_ij_big,
|
||||||
|
0,
|
||||||
|
scratch.borrow(),
|
||||||
|
);
|
||||||
|
(0..tensor_key.rank_in()).for_each(|col_i| {
|
||||||
|
(0..tensor_key.rows()).for_each(|row_i| {
|
||||||
|
tensor_key
|
||||||
|
.at(i, j)
|
||||||
|
.at(row_i, col_i)
|
||||||
|
.decrypt(&module, &mut pt, &sk_exec, scratch.borrow());
|
||||||
|
|
||||||
|
module.vec_znx_sub_scalar_inplace(&mut pt.data, 0, row_i, &sk_ij.data, col_i);
|
||||||
|
|
||||||
|
let std_pt: f64 = module.vec_znx_std(basek, &pt.data, 0) * (k as f64).exp2();
|
||||||
|
assert!((sigma - std_pt).abs() <= 0.5, "{} {}", sigma, std_pt);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn test_tensor_key_encrypt_sk_compressed<B: Backend>(
|
||||||
|
module: &Module<B>,
|
||||||
|
basek: usize,
|
||||||
|
k: usize,
|
||||||
|
sigma: f64,
|
||||||
|
rank: usize,
|
||||||
|
) where
|
||||||
|
Module<B>: TestModuleFamily<B>
|
||||||
|
+ GGLWEExecLayoutFamily<B>
|
||||||
|
+ GLWETensorKeyEncryptSkFamily<B>
|
||||||
|
+ GLWEDecryptFamily<B>
|
||||||
|
+ VecZnxDftAlloc<B>
|
||||||
|
+ VecZnxBigAlloc<B>
|
||||||
|
+ VecZnxCopy,
|
||||||
|
B: TestScratchFamily<B>,
|
||||||
|
{
|
||||||
|
let rows: usize = k / basek;
|
||||||
|
|
||||||
|
let mut tensor_key_compressed: GLWETensorKeyCompressed<Vec<u8>> =
|
||||||
|
GLWETensorKeyCompressed::alloc(&module, basek, k, rows, 1, rank);
|
||||||
|
|
||||||
|
let mut source_xs: Source = Source::new([0u8; 32]);
|
||||||
|
let mut source_xe: Source = Source::new([0u8; 32]);
|
||||||
|
|
||||||
|
let mut scratch: ScratchOwned<B> = ScratchOwned::alloc(GLWETensorKeyCompressed::encrypt_sk_scratch_space(
|
||||||
|
module,
|
||||||
|
basek,
|
||||||
|
tensor_key_compressed.k(),
|
||||||
|
rank,
|
||||||
|
));
|
||||||
|
|
||||||
|
let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(&module, rank);
|
||||||
|
sk.fill_ternary_prob(0.5, &mut source_xs);
|
||||||
|
let mut sk_exec: GLWESecretExec<Vec<u8>, B> = GLWESecretExec::from(&module, &sk);
|
||||||
|
sk_exec.prepare(module, &sk);
|
||||||
|
|
||||||
|
let seed_xa: [u8; 32] = [1u8; 32];
|
||||||
|
|
||||||
|
tensor_key_compressed.encrypt_sk(
|
||||||
|
module,
|
||||||
|
&sk,
|
||||||
|
seed_xa,
|
||||||
|
&mut source_xe,
|
||||||
|
sigma,
|
||||||
|
scratch.borrow(),
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut tensor_key: GLWETensorKey<Vec<u8>> = GLWETensorKey::alloc(&module, basek, k, rows, 1, rank);
|
||||||
|
tensor_key.decompress(module, &tensor_key_compressed);
|
||||||
|
|
||||||
|
let mut pt: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(&module, basek, k);
|
||||||
|
|
||||||
|
let mut sk_ij_dft = module.vec_znx_dft_alloc(1, 1);
|
||||||
|
let mut sk_ij_big = module.vec_znx_big_alloc(1, 1);
|
||||||
|
let mut sk_ij: GLWESecret<Vec<u8>> = GLWESecret::alloc(&module, 1);
|
||||||
|
let mut sk_dft: VecZnxDft<Vec<u8>, B> = module.vec_znx_dft_alloc(rank, 1);
|
||||||
|
|
||||||
|
(0..rank).for_each(|i| {
|
||||||
|
module.vec_znx_dft_from_vec_znx(1, 0, &mut sk_dft, i, &sk.data.as_vec_znx(), i);
|
||||||
|
});
|
||||||
|
|
||||||
|
(0..rank).for_each(|i| {
|
||||||
|
(0..rank).for_each(|j| {
|
||||||
|
module.svp_apply(&mut sk_ij_dft, 0, &sk_exec.data, j, &sk_dft, i);
|
||||||
|
module.vec_znx_dft_to_vec_znx_big_tmp_a(&mut sk_ij_big, 0, &mut sk_ij_dft, 0);
|
||||||
|
module.vec_znx_big_normalize(
|
||||||
|
basek,
|
||||||
|
&mut sk_ij.data.as_vec_znx_mut(),
|
||||||
|
0,
|
||||||
|
&sk_ij_big,
|
||||||
|
0,
|
||||||
|
scratch.borrow(),
|
||||||
|
);
|
||||||
(0..tensor_key.rank_in()).for_each(|col_i| {
|
(0..tensor_key.rank_in()).for_each(|col_i| {
|
||||||
(0..tensor_key.rows()).for_each(|row_i| {
|
(0..tensor_key.rows()).for_each(|row_i| {
|
||||||
tensor_key
|
tensor_key
|
||||||
4
core/src/gglwe/tests/mod.rs
Normal file
4
core/src/gglwe/tests/mod.rs
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
mod cpu_spqlios;
|
||||||
|
mod generics_automorphism_key;
|
||||||
|
mod generics_gglwe;
|
||||||
|
mod generics_tensor_key;
|
||||||
@@ -64,7 +64,7 @@ impl<DataSelf: DataMut> GGSWCiphertext<DataSelf> {
|
|||||||
(0..rank + 1).for_each(|col_j| {
|
(0..rank + 1).for_each(|col_j| {
|
||||||
// rlwe encrypt of vec_znx_pt into vec_znx_ct
|
// rlwe encrypt of vec_znx_pt into vec_znx_ct
|
||||||
|
|
||||||
self.at_mut(row_i, col_j).encrypt_sk_private(
|
self.at_mut(row_i, col_j).encrypt_sk_internal(
|
||||||
module,
|
module,
|
||||||
Some((&tmp_pt, col_j)),
|
Some((&tmp_pt, col_j)),
|
||||||
sk,
|
sk,
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use backend::hal::{
|
use backend::hal::{
|
||||||
api::{MatZnxAlloc, MatZnxAllocBytes, VmpPMatAlloc, VmpPMatAllocBytes, VmpPMatPrepare},
|
api::{MatZnxAlloc, MatZnxAllocBytes, VmpPMatAlloc, VmpPMatAllocBytes, VmpPMatPrepare},
|
||||||
layouts::{Backend, Data, DataMut, DataRef, MatZnx, Module, ReaderFrom, Scratch, VmpPMat, WriterTo},
|
layouts::{Backend, Data, DataMut, DataRef, MatZnx, Module, ReaderFrom, WriterTo},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{GLWECiphertext, Infos};
|
use crate::{GLWECiphertext, Infos};
|
||||||
@@ -135,125 +135,3 @@ impl<D: DataRef> WriterTo for GGSWCiphertext<D> {
|
|||||||
self.data.write_to(writer)
|
self.data.write_to(writer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Eq)]
|
|
||||||
pub struct GGSWCiphertextExec<D: Data, B: Backend> {
|
|
||||||
pub(crate) data: VmpPMat<D, B>,
|
|
||||||
pub(crate) basek: usize,
|
|
||||||
pub(crate) k: usize,
|
|
||||||
pub(crate) digits: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<B: Backend> GGSWCiphertextExec<Vec<u8>, B> {
|
|
||||||
pub fn alloc(module: &Module<B>, basek: usize, k: usize, rows: usize, digits: usize, rank: usize) -> Self
|
|
||||||
where
|
|
||||||
Module<B>: GGSWLayoutFamily<B>,
|
|
||||||
{
|
|
||||||
let size: usize = k.div_ceil(basek);
|
|
||||||
debug_assert!(digits > 0, "invalid ggsw: `digits` == 0");
|
|
||||||
|
|
||||||
debug_assert!(
|
|
||||||
size > digits,
|
|
||||||
"invalid ggsw: ceil(k/basek): {} <= digits: {}",
|
|
||||||
size,
|
|
||||||
digits
|
|
||||||
);
|
|
||||||
|
|
||||||
assert!(
|
|
||||||
rows * digits <= size,
|
|
||||||
"invalid ggsw: rows: {} * digits:{} > ceil(k/basek): {}",
|
|
||||||
rows,
|
|
||||||
digits,
|
|
||||||
size
|
|
||||||
);
|
|
||||||
|
|
||||||
Self {
|
|
||||||
data: module.vmp_pmat_alloc(rows, rank + 1, rank + 1, k.div_ceil(basek)),
|
|
||||||
basek,
|
|
||||||
k: k,
|
|
||||||
digits,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn bytes_of(module: &Module<B>, basek: usize, k: usize, rows: usize, digits: usize, rank: usize) -> usize
|
|
||||||
where
|
|
||||||
Module<B>: GGSWLayoutFamily<B>,
|
|
||||||
{
|
|
||||||
let size: usize = k.div_ceil(basek);
|
|
||||||
debug_assert!(
|
|
||||||
size > digits,
|
|
||||||
"invalid ggsw: ceil(k/basek): {} <= digits: {}",
|
|
||||||
size,
|
|
||||||
digits
|
|
||||||
);
|
|
||||||
|
|
||||||
assert!(
|
|
||||||
rows * digits <= size,
|
|
||||||
"invalid ggsw: rows: {} * digits:{} > ceil(k/basek): {}",
|
|
||||||
rows,
|
|
||||||
digits,
|
|
||||||
size
|
|
||||||
);
|
|
||||||
|
|
||||||
module.vmp_pmat_alloc_bytes(rows, rank + 1, rank + 1, size)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn from<DataOther: DataRef>(
|
|
||||||
module: &Module<B>,
|
|
||||||
other: &GGSWCiphertext<DataOther>,
|
|
||||||
scratch: &mut Scratch<B>,
|
|
||||||
) -> GGSWCiphertextExec<Vec<u8>, B>
|
|
||||||
where
|
|
||||||
Module<B>: GGSWLayoutFamily<B>,
|
|
||||||
{
|
|
||||||
let mut ggsw_exec: GGSWCiphertextExec<Vec<u8>, B> = Self::alloc(
|
|
||||||
module,
|
|
||||||
other.basek(),
|
|
||||||
other.k(),
|
|
||||||
other.rows(),
|
|
||||||
other.digits(),
|
|
||||||
other.rank(),
|
|
||||||
);
|
|
||||||
ggsw_exec.prepare(module, other, scratch);
|
|
||||||
ggsw_exec
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<D: Data, B: Backend> Infos for GGSWCiphertextExec<D, B> {
|
|
||||||
type Inner = VmpPMat<D, B>;
|
|
||||||
|
|
||||||
fn inner(&self) -> &Self::Inner {
|
|
||||||
&self.data
|
|
||||||
}
|
|
||||||
|
|
||||||
fn basek(&self) -> usize {
|
|
||||||
self.basek
|
|
||||||
}
|
|
||||||
|
|
||||||
fn k(&self) -> usize {
|
|
||||||
self.k
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<D: Data, B: Backend> GGSWCiphertextExec<D, B> {
|
|
||||||
pub fn rank(&self) -> usize {
|
|
||||||
self.data.cols_out() - 1
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn digits(&self) -> usize {
|
|
||||||
self.digits
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<DataSelf: DataMut, B: Backend> GGSWCiphertextExec<DataSelf, B> {
|
|
||||||
pub fn prepare<DataOther>(&mut self, module: &Module<B>, other: &GGSWCiphertext<DataOther>, scratch: &mut Scratch<B>)
|
|
||||||
where
|
|
||||||
DataOther: DataRef,
|
|
||||||
Module<B>: GGSWLayoutFamily<B>,
|
|
||||||
{
|
|
||||||
module.vmp_prepare(&mut self.data, &other.data, scratch);
|
|
||||||
self.k = other.k;
|
|
||||||
self.basek = other.basek;
|
|
||||||
self.digits = other.digits;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
80
core/src/ggsw/layout_compressed.rs
Normal file
80
core/src/ggsw/layout_compressed.rs
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
use backend::hal::{
|
||||||
|
api::{MatZnxAlloc, MatZnxAllocBytes, VecZnxCopy, VecZnxFillUniform},
|
||||||
|
layouts::{Backend, Data, DataMut, DataRef, MatZnx, Module, ReaderFrom, WriterTo},
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::{GGLWECiphertextCompressed, GGSWCiphertext, Infos};
|
||||||
|
|
||||||
|
#[derive(PartialEq, Eq)]
|
||||||
|
pub struct GGSWCiphertextCompressed<D: Data> {
|
||||||
|
pub(crate) data: GGLWECiphertextCompressed<D>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GGSWCiphertextCompressed<Vec<u8>> {
|
||||||
|
pub fn alloc<B: Backend>(module: &Module<B>, basek: usize, k: usize, rows: usize, digits: usize, rank: usize) -> Self
|
||||||
|
where
|
||||||
|
Module<B>: MatZnxAlloc,
|
||||||
|
{
|
||||||
|
GGSWCiphertextCompressed {
|
||||||
|
data: GGLWECiphertextCompressed::alloc(module, basek, k, rows, digits, rank, rank),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn bytes_of<B: Backend>(module: &Module<B>, basek: usize, k: usize, rows: usize, digits: usize, rank: usize) -> usize
|
||||||
|
where
|
||||||
|
Module<B>: MatZnxAllocBytes,
|
||||||
|
{
|
||||||
|
GGLWECiphertextCompressed::bytes_of(module, basek, k, rows, digits, rank)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D: Data> Infos for GGSWCiphertextCompressed<D> {
|
||||||
|
type Inner = MatZnx<D>;
|
||||||
|
|
||||||
|
fn inner(&self) -> &Self::Inner {
|
||||||
|
self.data.inner()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn basek(&self) -> usize {
|
||||||
|
self.data.basek()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn k(&self) -> usize {
|
||||||
|
self.data.k()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D: Data> GGSWCiphertextCompressed<D> {
|
||||||
|
pub fn rank(&self) -> usize {
|
||||||
|
self.data.rank()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn digits(&self) -> usize {
|
||||||
|
self.data.digits()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D: DataMut> ReaderFrom for GGSWCiphertextCompressed<D> {
|
||||||
|
fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> {
|
||||||
|
self.data.read_from(reader)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D: DataRef> WriterTo for GGSWCiphertextCompressed<D> {
|
||||||
|
fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
|
||||||
|
self.data.write_to(writer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D: DataMut> GGSWCiphertext<D> {
|
||||||
|
pub fn decompress<DataOther: DataRef, B: Backend>(&mut self, module: &Module<B>, other: &GGSWCiphertextCompressed<DataOther>)
|
||||||
|
where
|
||||||
|
Module<B>: VecZnxFillUniform + VecZnxCopy,
|
||||||
|
{
|
||||||
|
let rows = self.rows();
|
||||||
|
(0..rows).for_each(|row_i| {
|
||||||
|
self.at_mut(row_i, 0)
|
||||||
|
.decompress(module, &other.data.at(row_i, 0));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
128
core/src/ggsw/layout_exec.rs
Normal file
128
core/src/ggsw/layout_exec.rs
Normal file
@@ -0,0 +1,128 @@
|
|||||||
|
use backend::hal::{
|
||||||
|
api::{VmpPMatAlloc, VmpPMatAllocBytes, VmpPMatPrepare},
|
||||||
|
layouts::{Backend, Data, DataMut, DataRef, Module, Scratch, VmpPMat},
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::{GGSWCiphertext, GGSWLayoutFamily, Infos};
|
||||||
|
|
||||||
|
#[derive(PartialEq, Eq)]
|
||||||
|
pub struct GGSWCiphertextExec<D: Data, B: Backend> {
|
||||||
|
pub(crate) data: VmpPMat<D, B>,
|
||||||
|
pub(crate) basek: usize,
|
||||||
|
pub(crate) k: usize,
|
||||||
|
pub(crate) digits: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<B: Backend> GGSWCiphertextExec<Vec<u8>, B> {
|
||||||
|
pub fn alloc(module: &Module<B>, basek: usize, k: usize, rows: usize, digits: usize, rank: usize) -> Self
|
||||||
|
where
|
||||||
|
Module<B>: GGSWLayoutFamily<B>,
|
||||||
|
{
|
||||||
|
let size: usize = k.div_ceil(basek);
|
||||||
|
debug_assert!(digits > 0, "invalid ggsw: `digits` == 0");
|
||||||
|
|
||||||
|
debug_assert!(
|
||||||
|
size > digits,
|
||||||
|
"invalid ggsw: ceil(k/basek): {} <= digits: {}",
|
||||||
|
size,
|
||||||
|
digits
|
||||||
|
);
|
||||||
|
|
||||||
|
assert!(
|
||||||
|
rows * digits <= size,
|
||||||
|
"invalid ggsw: rows: {} * digits:{} > ceil(k/basek): {}",
|
||||||
|
rows,
|
||||||
|
digits,
|
||||||
|
size
|
||||||
|
);
|
||||||
|
|
||||||
|
Self {
|
||||||
|
data: module.vmp_pmat_alloc(rows, rank + 1, rank + 1, k.div_ceil(basek)),
|
||||||
|
basek,
|
||||||
|
k: k,
|
||||||
|
digits,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn bytes_of(module: &Module<B>, basek: usize, k: usize, rows: usize, digits: usize, rank: usize) -> usize
|
||||||
|
where
|
||||||
|
Module<B>: GGSWLayoutFamily<B>,
|
||||||
|
{
|
||||||
|
let size: usize = k.div_ceil(basek);
|
||||||
|
debug_assert!(
|
||||||
|
size > digits,
|
||||||
|
"invalid ggsw: ceil(k/basek): {} <= digits: {}",
|
||||||
|
size,
|
||||||
|
digits
|
||||||
|
);
|
||||||
|
|
||||||
|
assert!(
|
||||||
|
rows * digits <= size,
|
||||||
|
"invalid ggsw: rows: {} * digits:{} > ceil(k/basek): {}",
|
||||||
|
rows,
|
||||||
|
digits,
|
||||||
|
size
|
||||||
|
);
|
||||||
|
|
||||||
|
module.vmp_pmat_alloc_bytes(rows, rank + 1, rank + 1, size)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from<DataOther: DataRef>(
|
||||||
|
module: &Module<B>,
|
||||||
|
other: &GGSWCiphertext<DataOther>,
|
||||||
|
scratch: &mut Scratch<B>,
|
||||||
|
) -> GGSWCiphertextExec<Vec<u8>, B>
|
||||||
|
where
|
||||||
|
Module<B>: GGSWLayoutFamily<B>,
|
||||||
|
{
|
||||||
|
let mut ggsw_exec: GGSWCiphertextExec<Vec<u8>, B> = Self::alloc(
|
||||||
|
module,
|
||||||
|
other.basek(),
|
||||||
|
other.k(),
|
||||||
|
other.rows(),
|
||||||
|
other.digits(),
|
||||||
|
other.rank(),
|
||||||
|
);
|
||||||
|
ggsw_exec.prepare(module, other, scratch);
|
||||||
|
ggsw_exec
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D: Data, B: Backend> Infos for GGSWCiphertextExec<D, B> {
|
||||||
|
type Inner = VmpPMat<D, B>;
|
||||||
|
|
||||||
|
fn inner(&self) -> &Self::Inner {
|
||||||
|
&self.data
|
||||||
|
}
|
||||||
|
|
||||||
|
fn basek(&self) -> usize {
|
||||||
|
self.basek
|
||||||
|
}
|
||||||
|
|
||||||
|
fn k(&self) -> usize {
|
||||||
|
self.k
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D: Data, B: Backend> GGSWCiphertextExec<D, B> {
|
||||||
|
pub fn rank(&self) -> usize {
|
||||||
|
self.data.cols_out() - 1
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn digits(&self) -> usize {
|
||||||
|
self.digits
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<DataSelf: DataMut, B: Backend> GGSWCiphertextExec<DataSelf, B> {
|
||||||
|
pub fn prepare<DataOther>(&mut self, module: &Module<B>, other: &GGSWCiphertext<DataOther>, scratch: &mut Scratch<B>)
|
||||||
|
where
|
||||||
|
DataOther: DataRef,
|
||||||
|
Module<B>: GGSWLayoutFamily<B>,
|
||||||
|
{
|
||||||
|
module.vmp_prepare(&mut self.data, &other.data, scratch);
|
||||||
|
self.k = other.k;
|
||||||
|
self.basek = other.basek;
|
||||||
|
self.digits = other.digits;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,12 +3,16 @@ mod encryption;
|
|||||||
mod external_product;
|
mod external_product;
|
||||||
mod keyswitch;
|
mod keyswitch;
|
||||||
mod layout;
|
mod layout;
|
||||||
|
mod layout_compressed;
|
||||||
|
mod layout_exec;
|
||||||
mod noise;
|
mod noise;
|
||||||
|
|
||||||
pub use encryption::GGSWEncryptSkFamily;
|
pub use encryption::*;
|
||||||
pub use keyswitch::GGSWKeySwitchFamily;
|
pub use keyswitch::*;
|
||||||
pub use layout::{GGSWCiphertext, GGSWCiphertextExec, GGSWLayoutFamily};
|
pub use layout::*;
|
||||||
pub use noise::GGSWAssertNoiseFamily;
|
pub use layout_compressed::*;
|
||||||
|
pub use layout_exec::*;
|
||||||
|
pub use noise::*;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test;
|
mod test;
|
||||||
|
|||||||
1
core/src/ggsw/test/cpu_spqlios/mod.rs
Normal file
1
core/src/ggsw/test/cpu_spqlios/mod.rs
Normal file
@@ -0,0 +1 @@
|
|||||||
|
mod fft64;
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
use backend::hal::{
|
use backend::hal::{
|
||||||
api::{
|
api::{
|
||||||
MatZnxAlloc, ScalarZnxAlloc, ScalarZnxAllocBytes, ScalarZnxAutomorphism, ScalarZnxAutomorphismInplace, ScratchOwnedAlloc,
|
MatZnxAlloc, ScalarZnxAlloc, ScalarZnxAllocBytes, ScratchOwnedAlloc, ScratchOwnedBorrow, VecZnxAddScalarInplace,
|
||||||
ScratchOwnedBorrow, VecZnxAddScalarInplace, VecZnxAlloc, VecZnxAllocBytes, VecZnxAutomorphismInplace,
|
VecZnxAlloc, VecZnxAllocBytes, VecZnxAutomorphism, VecZnxAutomorphismInplace, VecZnxRotateInplace, VecZnxStd,
|
||||||
VecZnxRotateInplace, VecZnxStd, VecZnxSubABInplace, VecZnxSwithcDegree, ZnxViewMut,
|
VecZnxSubABInplace, VecZnxSwithcDegree, ZnxViewMut,
|
||||||
},
|
},
|
||||||
layouts::{Backend, Module, ScalarZnx, ScalarZnxToMut, ScratchOwned},
|
layouts::{Backend, Module, ScalarZnx, ScalarZnxToMut, ScratchOwned},
|
||||||
oep::{
|
oep::{
|
||||||
@@ -321,8 +321,8 @@ pub(crate) fn test_automorphism<B: Backend>(
|
|||||||
+ GGLWEExecLayoutFamily<B>
|
+ GGLWEExecLayoutFamily<B>
|
||||||
+ VecZnxSwithcDegree
|
+ VecZnxSwithcDegree
|
||||||
+ VecZnxAutomorphismInplace
|
+ VecZnxAutomorphismInplace
|
||||||
+ ScalarZnxAutomorphismInplace
|
+ VecZnxAutomorphismInplace
|
||||||
+ ScalarZnxAutomorphism,
|
+ VecZnxAutomorphism,
|
||||||
B: TestScratchFamily<B>,
|
B: TestScratchFamily<B>,
|
||||||
{
|
{
|
||||||
let rows: usize = k_in.div_ceil(basek * digits);
|
let rows: usize = k_in.div_ceil(basek * digits);
|
||||||
@@ -393,7 +393,7 @@ pub(crate) fn test_automorphism<B: Backend>(
|
|||||||
|
|
||||||
ct_out.automorphism(module, &ct_in, &auto_key_exec, &tsk_exec, scratch.borrow());
|
ct_out.automorphism(module, &ct_in, &auto_key_exec, &tsk_exec, scratch.borrow());
|
||||||
|
|
||||||
module.scalar_znx_automorphism_inplace(p, &mut pt_scalar, 0);
|
module.vec_znx_automorphism_inplace(p, &mut pt_scalar.as_vec_znx_mut(), 0);
|
||||||
|
|
||||||
let max_noise = |col_j: usize| -> f64 {
|
let max_noise = |col_j: usize| -> f64 {
|
||||||
noise_ggsw_keyswitch(
|
noise_ggsw_keyswitch(
|
||||||
@@ -433,8 +433,8 @@ pub(crate) fn test_automorphism_inplace<B: Backend>(
|
|||||||
+ GGLWEExecLayoutFamily<B>
|
+ GGLWEExecLayoutFamily<B>
|
||||||
+ VecZnxSwithcDegree
|
+ VecZnxSwithcDegree
|
||||||
+ VecZnxAutomorphismInplace
|
+ VecZnxAutomorphismInplace
|
||||||
+ ScalarZnxAutomorphismInplace
|
+ VecZnxAutomorphism
|
||||||
+ ScalarZnxAutomorphism,
|
+ VecZnxAutomorphismInplace,
|
||||||
B: TestScratchFamily<B>,
|
B: TestScratchFamily<B>,
|
||||||
{
|
{
|
||||||
let rows: usize = k_ct.div_ceil(digits * basek);
|
let rows: usize = k_ct.div_ceil(digits * basek);
|
||||||
@@ -501,7 +501,7 @@ pub(crate) fn test_automorphism_inplace<B: Backend>(
|
|||||||
|
|
||||||
ct.automorphism_inplace(module, &auto_key_exec, &tsk_exec, scratch.borrow());
|
ct.automorphism_inplace(module, &auto_key_exec, &tsk_exec, scratch.borrow());
|
||||||
|
|
||||||
module.scalar_znx_automorphism_inplace(p, &mut pt_scalar, 0);
|
module.vec_znx_automorphism_inplace(p, &mut pt_scalar.as_vec_znx_mut(), 0);
|
||||||
|
|
||||||
let max_noise = |col_j: usize| -> f64 {
|
let max_noise = |col_j: usize| -> f64 {
|
||||||
noise_ggsw_keyswitch(
|
noise_ggsw_keyswitch(
|
||||||
@@ -595,7 +595,7 @@ pub(crate) fn test_external_product<B: Backend>(
|
|||||||
|
|
||||||
ct_ggsw_lhs_out.external_product(module, &ct_ggsw_lhs_in, &ct_rhs_exec, scratch.borrow());
|
ct_ggsw_lhs_out.external_product(module, &ct_ggsw_lhs_in, &ct_rhs_exec, scratch.borrow());
|
||||||
|
|
||||||
module.vec_znx_rotate_inplace(k as i64, &mut pt_ggsw_lhs, 0);
|
module.vec_znx_rotate_inplace(k as i64, &mut pt_ggsw_lhs.as_vec_znx_mut(), 0);
|
||||||
|
|
||||||
let var_gct_err_lhs: f64 = sigma * sigma;
|
let var_gct_err_lhs: f64 = sigma * sigma;
|
||||||
let var_gct_err_rhs: f64 = 0f64;
|
let var_gct_err_rhs: f64 = 0f64;
|
||||||
@@ -695,7 +695,7 @@ pub(crate) fn test_external_product_inplace<B: Backend>(
|
|||||||
|
|
||||||
ct_ggsw_lhs.external_product_inplace(module, &ct_rhs_exec, scratch.borrow());
|
ct_ggsw_lhs.external_product_inplace(module, &ct_rhs_exec, scratch.borrow());
|
||||||
|
|
||||||
module.vec_znx_rotate_inplace(k as i64, &mut pt_ggsw_lhs, 0);
|
module.vec_znx_rotate_inplace(k as i64, &mut pt_ggsw_lhs.as_vec_znx_mut(), 0);
|
||||||
|
|
||||||
let var_gct_err_lhs: f64 = sigma * sigma;
|
let var_gct_err_lhs: f64 = sigma * sigma;
|
||||||
let var_gct_err_rhs: f64 = 0f64;
|
let var_gct_err_rhs: f64 = 0f64;
|
||||||
|
|||||||
@@ -1,2 +1,2 @@
|
|||||||
|
mod cpu_spqlios;
|
||||||
mod generic_tests;
|
mod generic_tests;
|
||||||
mod test_fft64;
|
|
||||||
|
|||||||
@@ -3,13 +3,17 @@ use backend::hal::{
|
|||||||
ScalarZnxAllocBytes, ScratchAvailable, SvpApply, SvpApplyInplace, SvpPPolAllocBytes, SvpPrepare, TakeScalarZnx,
|
ScalarZnxAllocBytes, ScratchAvailable, SvpApply, SvpApplyInplace, SvpPPolAllocBytes, SvpPrepare, TakeScalarZnx,
|
||||||
TakeSvpPPol, TakeVecZnx, TakeVecZnxDft, VecZnxAddInplace, VecZnxAddNormal, VecZnxBigAddNormal, VecZnxBigAddSmallInplace,
|
TakeSvpPPol, TakeVecZnx, TakeVecZnxDft, VecZnxAddInplace, VecZnxAddNormal, VecZnxBigAddNormal, VecZnxBigAddSmallInplace,
|
||||||
VecZnxBigAllocBytes, VecZnxBigNormalize, VecZnxDftAllocBytes, VecZnxDftFromVecZnx, VecZnxDftToVecZnxBigConsume,
|
VecZnxBigAllocBytes, VecZnxBigNormalize, VecZnxDftAllocBytes, VecZnxDftFromVecZnx, VecZnxDftToVecZnxBigConsume,
|
||||||
VecZnxFillUniform, VecZnxNormalize, VecZnxNormalizeInplace, VecZnxNormalizeTmpBytes, VecZnxSubABInplace, ZnxZero,
|
VecZnxFillUniform, VecZnxNormalize, VecZnxNormalizeInplace, VecZnxNormalizeTmpBytes, VecZnxSubABInplace, ZnxInfos,
|
||||||
|
ZnxZero,
|
||||||
},
|
},
|
||||||
layouts::{Backend, DataMut, DataRef, Module, Scratch, VecZnxBig},
|
layouts::{Backend, DataMut, DataRef, Module, Scratch, VecZnx, VecZnxBig},
|
||||||
};
|
};
|
||||||
use sampling::source::Source;
|
use sampling::source::Source;
|
||||||
|
|
||||||
use crate::{GLWECiphertext, GLWEPlaintext, GLWEPublicKeyExec, GLWESecretExec, Infos, SIX_SIGMA, dist::Distribution};
|
use crate::{
|
||||||
|
GLWECiphertext, GLWECiphertextCompressed, GLWEPlaintext, GLWEPublicKeyExec, GLWESecretExec, Infos, SIX_SIGMA,
|
||||||
|
dist::Distribution,
|
||||||
|
};
|
||||||
|
|
||||||
pub trait GLWEEncryptSkFamily<B: Backend> = VecZnxDftAllocBytes
|
pub trait GLWEEncryptSkFamily<B: Backend> = VecZnxDftAllocBytes
|
||||||
+ VecZnxBigNormalize<B>
|
+ VecZnxBigNormalize<B>
|
||||||
@@ -71,7 +75,20 @@ impl<DataSelf: DataMut> GLWECiphertext<DataSelf> {
|
|||||||
Module<B>: GLWEEncryptSkFamily<B>,
|
Module<B>: GLWEEncryptSkFamily<B>,
|
||||||
Scratch<B>: TakeVecZnxDft<B> + ScratchAvailable + TakeVecZnx<B>,
|
Scratch<B>: TakeVecZnxDft<B> + ScratchAvailable + TakeVecZnx<B>,
|
||||||
{
|
{
|
||||||
self.encrypt_sk_private(
|
#[cfg(debug_assertions)]
|
||||||
|
{
|
||||||
|
assert_eq!(self.rank(), sk.rank());
|
||||||
|
assert_eq!(sk.n(), self.n());
|
||||||
|
assert_eq!(pt.n(), self.n());
|
||||||
|
assert!(
|
||||||
|
scratch.available() >= GLWECiphertext::encrypt_sk_scratch_space(module, self.basek(), self.k()),
|
||||||
|
"scratch.available(): {} < GLWECiphertext::encrypt_sk_scratch_space: {}",
|
||||||
|
scratch.available(),
|
||||||
|
GLWECiphertext::encrypt_sk_scratch_space(module, self.basek(), self.k())
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
self.encrypt_sk_internal(
|
||||||
module,
|
module,
|
||||||
Some((pt, 0)),
|
Some((pt, 0)),
|
||||||
sk,
|
sk,
|
||||||
@@ -94,7 +111,18 @@ impl<DataSelf: DataMut> GLWECiphertext<DataSelf> {
|
|||||||
Module<B>: GLWEEncryptSkFamily<B>,
|
Module<B>: GLWEEncryptSkFamily<B>,
|
||||||
Scratch<B>: TakeVecZnxDft<B> + ScratchAvailable + TakeVecZnx<B>,
|
Scratch<B>: TakeVecZnxDft<B> + ScratchAvailable + TakeVecZnx<B>,
|
||||||
{
|
{
|
||||||
self.encrypt_sk_private(
|
#[cfg(debug_assertions)]
|
||||||
|
{
|
||||||
|
assert_eq!(self.rank(), sk.rank());
|
||||||
|
assert_eq!(sk.n(), self.n());
|
||||||
|
assert!(
|
||||||
|
scratch.available() >= GLWECiphertext::encrypt_sk_scratch_space(module, self.basek(), self.k()),
|
||||||
|
"scratch.available(): {} < GLWECiphertext::encrypt_sk_scratch_space: {}",
|
||||||
|
scratch.available(),
|
||||||
|
GLWECiphertext::encrypt_sk_scratch_space(module, self.basek(), self.k())
|
||||||
|
)
|
||||||
|
}
|
||||||
|
self.encrypt_sk_internal(
|
||||||
module,
|
module,
|
||||||
None::<(&GLWEPlaintext<Vec<u8>>, usize)>,
|
None::<(&GLWEPlaintext<Vec<u8>>, usize)>,
|
||||||
sk,
|
sk,
|
||||||
@@ -105,6 +133,34 @@ impl<DataSelf: DataMut> GLWECiphertext<DataSelf> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn encrypt_sk_internal<DataPt: DataRef, DataSk: DataRef, B: Backend>(
|
||||||
|
&mut self,
|
||||||
|
module: &Module<B>,
|
||||||
|
pt: Option<(&GLWEPlaintext<DataPt>, usize)>,
|
||||||
|
sk: &GLWESecretExec<DataSk, B>,
|
||||||
|
source_xa: &mut Source,
|
||||||
|
source_xe: &mut Source,
|
||||||
|
sigma: f64,
|
||||||
|
scratch: &mut Scratch<B>,
|
||||||
|
) where
|
||||||
|
Module<B>: GLWEEncryptSkFamily<B>,
|
||||||
|
Scratch<B>: TakeVecZnxDft<B> + ScratchAvailable + TakeVecZnx<B>,
|
||||||
|
{
|
||||||
|
encrypt_sk_internal(
|
||||||
|
module,
|
||||||
|
self.basek(),
|
||||||
|
self.k(),
|
||||||
|
&mut self.data,
|
||||||
|
false,
|
||||||
|
pt,
|
||||||
|
sk,
|
||||||
|
source_xa,
|
||||||
|
source_xe,
|
||||||
|
sigma,
|
||||||
|
scratch,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn encrypt_pk<DataPt: DataRef, DataPk: DataRef, B: Backend>(
|
pub fn encrypt_pk<DataPt: DataRef, DataPk: DataRef, B: Backend>(
|
||||||
&mut self,
|
&mut self,
|
||||||
module: &Module<B>,
|
module: &Module<B>,
|
||||||
@@ -118,7 +174,7 @@ impl<DataSelf: DataMut> GLWECiphertext<DataSelf> {
|
|||||||
Module<B>: GLWEEncryptPkFamily<B>,
|
Module<B>: GLWEEncryptPkFamily<B>,
|
||||||
Scratch<B>: TakeVecZnxDft<B> + TakeSvpPPol<B> + TakeScalarZnx<B>,
|
Scratch<B>: TakeVecZnxDft<B> + TakeSvpPPol<B> + TakeScalarZnx<B>,
|
||||||
{
|
{
|
||||||
self.encrypt_pk_private::<DataPt, DataPk, B>(
|
self.encrypt_pk_internal::<DataPt, DataPk, B>(
|
||||||
module,
|
module,
|
||||||
Some((pt, 0)),
|
Some((pt, 0)),
|
||||||
pk,
|
pk,
|
||||||
@@ -141,7 +197,7 @@ impl<DataSelf: DataMut> GLWECiphertext<DataSelf> {
|
|||||||
Module<B>: GLWEEncryptPkFamily<B>,
|
Module<B>: GLWEEncryptPkFamily<B>,
|
||||||
Scratch<B>: TakeVecZnxDft<B> + TakeSvpPPol<B> + TakeScalarZnx<B>,
|
Scratch<B>: TakeVecZnxDft<B> + TakeSvpPPol<B> + TakeScalarZnx<B>,
|
||||||
{
|
{
|
||||||
self.encrypt_pk_private::<Vec<u8>, DataPk, B>(
|
self.encrypt_pk_internal::<Vec<u8>, DataPk, B>(
|
||||||
module,
|
module,
|
||||||
None::<(&GLWEPlaintext<Vec<u8>>, usize)>,
|
None::<(&GLWEPlaintext<Vec<u8>>, usize)>,
|
||||||
pk,
|
pk,
|
||||||
@@ -152,89 +208,7 @@ impl<DataSelf: DataMut> GLWECiphertext<DataSelf> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn encrypt_sk_private<DataPt: DataRef, DataSk: DataRef, B: Backend>(
|
pub(crate) fn encrypt_pk_internal<DataPt: DataRef, DataPk: DataRef, B: Backend>(
|
||||||
&mut self,
|
|
||||||
module: &Module<B>,
|
|
||||||
pt: Option<(&GLWEPlaintext<DataPt>, usize)>,
|
|
||||||
sk: &GLWESecretExec<DataSk, B>,
|
|
||||||
source_xa: &mut Source,
|
|
||||||
source_xe: &mut Source,
|
|
||||||
sigma: f64,
|
|
||||||
scratch: &mut Scratch<B>,
|
|
||||||
) where
|
|
||||||
Module<B>: GLWEEncryptSkFamily<B>,
|
|
||||||
Scratch<B>: TakeVecZnxDft<B> + ScratchAvailable + TakeVecZnx<B>,
|
|
||||||
{
|
|
||||||
#[cfg(debug_assertions)]
|
|
||||||
{
|
|
||||||
assert_eq!(self.rank(), sk.rank());
|
|
||||||
assert_eq!(sk.n(), module.n());
|
|
||||||
assert_eq!(self.n(), module.n());
|
|
||||||
if let Some((pt, col)) = pt {
|
|
||||||
assert_eq!(pt.n(), module.n());
|
|
||||||
assert!(col < self.rank() + 1);
|
|
||||||
}
|
|
||||||
assert!(
|
|
||||||
scratch.available() >= GLWECiphertext::encrypt_sk_scratch_space(module, self.basek(), self.k()),
|
|
||||||
"scratch.available(): {} < GLWECiphertext::encrypt_sk_scratch_space: {}",
|
|
||||||
scratch.available(),
|
|
||||||
GLWECiphertext::encrypt_sk_scratch_space(module, self.basek(), self.k())
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
let basek: usize = self.basek();
|
|
||||||
let k: usize = self.k();
|
|
||||||
let size: usize = self.size();
|
|
||||||
let cols: usize = self.rank() + 1;
|
|
||||||
|
|
||||||
let (mut c0, scratch_1) = scratch.take_vec_znx(module, 1, size);
|
|
||||||
c0.zero();
|
|
||||||
|
|
||||||
{
|
|
||||||
// c[i] = uniform
|
|
||||||
// c[0] -= c[i] * s[i],
|
|
||||||
(1..cols).for_each(|i| {
|
|
||||||
let (mut ci_dft, scratch_2) = scratch_1.take_vec_znx_dft(module, 1, size);
|
|
||||||
|
|
||||||
// c[i] = uniform
|
|
||||||
module.vec_znx_fill_uniform(basek, &mut self.data, i, k, source_xa);
|
|
||||||
|
|
||||||
// c[i] = norm(IDFT(DFT(c[i]) * DFT(s[i])))
|
|
||||||
module.vec_znx_dft_from_vec_znx(1, 0, &mut ci_dft, 0, &self.data, i);
|
|
||||||
module.svp_apply_inplace(&mut ci_dft, 0, &sk.data, i - 1);
|
|
||||||
let ci_big: VecZnxBig<&mut [u8], B> = module.vec_znx_dft_to_vec_znx_big_consume(ci_dft);
|
|
||||||
|
|
||||||
// use c[0] as buffer, which is overwritten later by the normalization step
|
|
||||||
module.vec_znx_big_normalize(basek, &mut self.data, 0, &ci_big, 0, scratch_2);
|
|
||||||
|
|
||||||
// c0_tmp = -c[i] * s[i] (use c[0] as buffer)
|
|
||||||
module.vec_znx_sub_ab_inplace(&mut c0, 0, &self.data, 0);
|
|
||||||
|
|
||||||
// c[i] += m if col = i
|
|
||||||
if let Some((pt, col)) = pt {
|
|
||||||
if i == col {
|
|
||||||
module.vec_znx_add_inplace(&mut self.data, i, &pt.data, 0);
|
|
||||||
module.vec_znx_normalize_inplace(basek, &mut self.data, i, scratch_2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// c[0] += e
|
|
||||||
module.vec_znx_add_normal(basek, &mut c0, 0, k, source_xe, sigma, sigma * SIX_SIGMA);
|
|
||||||
|
|
||||||
// c[0] += m if col = 0
|
|
||||||
if let Some((pt, col)) = pt {
|
|
||||||
if col == 0 {
|
|
||||||
module.vec_znx_add_inplace(&mut c0, 0, &pt.data, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// c[0] = norm(c[0])
|
|
||||||
module.vec_znx_normalize(basek, &mut self.data, 0, &c0, 0, scratch_1);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn encrypt_pk_private<DataPt: DataRef, DataPk: DataRef, B: Backend>(
|
|
||||||
&mut self,
|
&mut self,
|
||||||
module: &Module<B>,
|
module: &Module<B>,
|
||||||
pt: Option<(&GLWEPlaintext<DataPt>, usize)>,
|
pt: Option<(&GLWEPlaintext<DataPt>, usize)>,
|
||||||
@@ -323,3 +297,158 @@ impl<DataSelf: DataMut> GLWECiphertext<DataSelf> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl GLWECiphertextCompressed<Vec<u8>> {
|
||||||
|
pub fn encrypt_sk_scratch_space<B: Backend>(module: &Module<B>, basek: usize, k: usize) -> usize
|
||||||
|
where
|
||||||
|
Module<B>: GLWEEncryptSkFamily<B>,
|
||||||
|
{
|
||||||
|
GLWECiphertext::encrypt_sk_scratch_space(module, basek, k)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<D: DataMut> GLWECiphertextCompressed<D> {
|
||||||
|
pub fn encrypt_sk<DataPt: DataRef, DataSk: DataRef, B: Backend>(
|
||||||
|
&mut self,
|
||||||
|
module: &Module<B>,
|
||||||
|
pt: &GLWEPlaintext<DataPt>,
|
||||||
|
sk: &GLWESecretExec<DataSk, B>,
|
||||||
|
seed_xa: [u8; 32],
|
||||||
|
source_xe: &mut Source,
|
||||||
|
sigma: f64,
|
||||||
|
scratch: &mut Scratch<B>,
|
||||||
|
) where
|
||||||
|
Module<B>: GLWEEncryptSkFamily<B>,
|
||||||
|
Scratch<B>: TakeVecZnxDft<B> + ScratchAvailable + TakeVecZnx<B>,
|
||||||
|
{
|
||||||
|
self.encrypt_sk_internal(
|
||||||
|
module,
|
||||||
|
Some((pt, 0)),
|
||||||
|
sk,
|
||||||
|
seed_xa,
|
||||||
|
source_xe,
|
||||||
|
sigma,
|
||||||
|
scratch,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn encrypt_sk_internal<DataPt: DataRef, DataSk: DataRef, B: Backend>(
|
||||||
|
&mut self,
|
||||||
|
module: &Module<B>,
|
||||||
|
pt: Option<(&GLWEPlaintext<DataPt>, usize)>,
|
||||||
|
sk: &GLWESecretExec<DataSk, B>,
|
||||||
|
seed_xa: [u8; 32],
|
||||||
|
source_xe: &mut Source,
|
||||||
|
sigma: f64,
|
||||||
|
scratch: &mut Scratch<B>,
|
||||||
|
) where
|
||||||
|
Module<B>: GLWEEncryptSkFamily<B>,
|
||||||
|
Scratch<B>: TakeVecZnxDft<B> + ScratchAvailable + TakeVecZnx<B>,
|
||||||
|
{
|
||||||
|
let mut source_xa = Source::new(seed_xa);
|
||||||
|
encrypt_sk_internal(
|
||||||
|
module,
|
||||||
|
self.basek(),
|
||||||
|
self.k(),
|
||||||
|
&mut self.data,
|
||||||
|
true,
|
||||||
|
pt,
|
||||||
|
sk,
|
||||||
|
&mut source_xa,
|
||||||
|
source_xe,
|
||||||
|
sigma,
|
||||||
|
scratch,
|
||||||
|
);
|
||||||
|
self.seed = seed_xa;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn encrypt_sk_internal<DataCt: DataMut, DataPt: DataRef, DataSk: DataRef, B: Backend>(
|
||||||
|
module: &Module<B>,
|
||||||
|
basek: usize,
|
||||||
|
k: usize,
|
||||||
|
ct: &mut VecZnx<DataCt>,
|
||||||
|
compressed: bool,
|
||||||
|
pt: Option<(&GLWEPlaintext<DataPt>, usize)>,
|
||||||
|
sk: &GLWESecretExec<DataSk, B>,
|
||||||
|
source_xa: &mut Source,
|
||||||
|
source_xe: &mut Source,
|
||||||
|
sigma: f64,
|
||||||
|
scratch: &mut Scratch<B>,
|
||||||
|
) where
|
||||||
|
Module<B>: GLWEEncryptSkFamily<B>,
|
||||||
|
Scratch<B>: TakeVecZnxDft<B> + ScratchAvailable + TakeVecZnx<B>,
|
||||||
|
{
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
{
|
||||||
|
if compressed {
|
||||||
|
if let Some((_, col)) = pt {
|
||||||
|
assert_eq!(
|
||||||
|
col, 0,
|
||||||
|
"invalid plaintext: cannot put pt in col>0 if compressed encryption"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
assert_eq!(
|
||||||
|
ct.cols(),
|
||||||
|
1,
|
||||||
|
"invalid ciphertext: compressed tag=true but #cols={} != 1",
|
||||||
|
ct.cols()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let size: usize = ct.size();
|
||||||
|
let cols: usize = ct.cols();
|
||||||
|
|
||||||
|
let (mut c0, scratch_1) = scratch.take_vec_znx(module, 1, size);
|
||||||
|
c0.zero();
|
||||||
|
|
||||||
|
{
|
||||||
|
// c[i] = uniform
|
||||||
|
// c[0] -= c[i] * s[i],
|
||||||
|
(1..cols).for_each(|i| {
|
||||||
|
let col_ct: usize;
|
||||||
|
if compressed {
|
||||||
|
col_ct = 0;
|
||||||
|
} else {
|
||||||
|
col_ct = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
let (mut ci_dft, scratch_2) = scratch_1.take_vec_znx_dft(module, 1, size);
|
||||||
|
|
||||||
|
// c[i] = uniform
|
||||||
|
module.vec_znx_fill_uniform(basek, ct, col_ct, k, source_xa);
|
||||||
|
|
||||||
|
// c[i] = norm(IDFT(DFT(c[i]) * DFT(s[i])))
|
||||||
|
module.vec_znx_dft_from_vec_znx(1, 0, &mut ci_dft, 0, ct, col_ct);
|
||||||
|
module.svp_apply_inplace(&mut ci_dft, 0, &sk.data, i - 1);
|
||||||
|
let ci_big: VecZnxBig<&mut [u8], B> = module.vec_znx_dft_to_vec_znx_big_consume(ci_dft);
|
||||||
|
|
||||||
|
// use c[0] as buffer, which is overwritten later by the normalization step
|
||||||
|
module.vec_znx_big_normalize(basek, ct, 0, &ci_big, 0, scratch_2);
|
||||||
|
|
||||||
|
// c0_tmp = -c[i] * s[i] (use c[0] as buffer)
|
||||||
|
module.vec_znx_sub_ab_inplace(&mut c0, 0, ct, 0);
|
||||||
|
|
||||||
|
// c[i] += m if col = i
|
||||||
|
// note: case cannot happen if compressed = true
|
||||||
|
if let Some((pt, col)) = pt {
|
||||||
|
if i == col {
|
||||||
|
module.vec_znx_add_inplace(ct, i, &pt.data, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// c[0] += e
|
||||||
|
module.vec_znx_add_normal(basek, &mut c0, 0, k, source_xe, sigma, sigma * SIX_SIGMA);
|
||||||
|
|
||||||
|
// c[0] += m if col = 0
|
||||||
|
if let Some((pt, col)) = pt {
|
||||||
|
if col == 0 {
|
||||||
|
module.vec_znx_add_inplace(&mut c0, 0, &pt.data, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// c[0] = norm(c[0])
|
||||||
|
module.vec_znx_normalize(basek, ct, 0, &c0, 0, scratch_1);
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,17 +1,54 @@
|
|||||||
|
use std::fmt::Debug;
|
||||||
|
|
||||||
use backend::hal::{
|
use backend::hal::{
|
||||||
api::{VecZnxAlloc, VecZnxAllocBytes},
|
api::{FillUniform, VecZnxAlloc, VecZnxAllocBytes, VecZnxCopy, VecZnxFillUniform, ZnxInfos, ZnxZero},
|
||||||
layouts::{Backend, Data, DataMut, DataRef, Module, ReaderFrom, VecZnx, VecZnxToMut, VecZnxToRef, WriterTo},
|
layouts::{Backend, Data, DataMut, DataRef, Module, ReaderFrom, VecZnx, VecZnxToMut, VecZnxToRef, WriterTo},
|
||||||
};
|
};
|
||||||
|
use sampling::source::Source;
|
||||||
|
|
||||||
use crate::{GLWEOps, Infos, SetMetaData};
|
use crate::{GLWEOps, Infos, SetMetaData};
|
||||||
|
|
||||||
#[derive(PartialEq, Eq)]
|
#[derive(PartialEq, Eq, Clone)]
|
||||||
pub struct GLWECiphertext<D: Data> {
|
pub struct GLWECiphertext<D: Data> {
|
||||||
pub data: VecZnx<D>,
|
pub data: VecZnx<D>,
|
||||||
pub basek: usize,
|
pub basek: usize,
|
||||||
pub k: usize,
|
pub k: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<D: DataRef> Debug for GLWECiphertext<D> {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"GLWECiphertext: basek={} k={}: {}",
|
||||||
|
self.basek(),
|
||||||
|
self.k(),
|
||||||
|
self.data
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D: DataMut> ZnxZero for GLWECiphertext<D>
|
||||||
|
where
|
||||||
|
VecZnx<D>: ZnxZero,
|
||||||
|
{
|
||||||
|
fn zero(&mut self) {
|
||||||
|
self.data.zero()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn zero_at(&mut self, i: usize, j: usize) {
|
||||||
|
self.data.zero_at(i, j);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D: DataMut> FillUniform for GLWECiphertext<D>
|
||||||
|
where
|
||||||
|
VecZnx<D>: FillUniform,
|
||||||
|
{
|
||||||
|
fn fill_uniform(&mut self, source: &mut Source) {
|
||||||
|
self.data.fill_uniform(source);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl GLWECiphertext<Vec<u8>> {
|
impl GLWECiphertext<Vec<u8>> {
|
||||||
pub fn alloc<B: Backend>(module: &Module<B>, basek: usize, k: usize, rank: usize) -> Self
|
pub fn alloc<B: Backend>(module: &Module<B>, basek: usize, k: usize, rank: usize) -> Self
|
||||||
where
|
where
|
||||||
@@ -121,3 +158,165 @@ impl<D: DataRef> WriterTo for GLWECiphertext<D> {
|
|||||||
self.data.write_to(writer)
|
self.data.write_to(writer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq, Eq, Clone)]
|
||||||
|
pub struct GLWECiphertextCompressed<D: Data> {
|
||||||
|
pub(crate) data: VecZnx<D>,
|
||||||
|
pub(crate) basek: usize,
|
||||||
|
pub(crate) k: usize,
|
||||||
|
pub(crate) rank: usize,
|
||||||
|
pub(crate) seed: [u8; 32],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D: DataRef> Debug for GLWECiphertextCompressed<D> {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"GLWECiphertext: basek={} k={}: {}",
|
||||||
|
self.basek(),
|
||||||
|
self.k(),
|
||||||
|
self.data
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D: DataMut> ZnxZero for GLWECiphertextCompressed<D>
|
||||||
|
where
|
||||||
|
VecZnx<D>: ZnxZero,
|
||||||
|
{
|
||||||
|
fn zero(&mut self) {
|
||||||
|
self.data.zero()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn zero_at(&mut self, i: usize, j: usize) {
|
||||||
|
self.data.zero_at(i, j);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D: DataMut> FillUniform for GLWECiphertextCompressed<D>
|
||||||
|
where
|
||||||
|
VecZnx<D>: FillUniform,
|
||||||
|
{
|
||||||
|
fn fill_uniform(&mut self, source: &mut Source) {
|
||||||
|
self.data.fill_uniform(source);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D: Data> Infos for GLWECiphertextCompressed<D> {
|
||||||
|
type Inner = VecZnx<D>;
|
||||||
|
|
||||||
|
fn inner(&self) -> &Self::Inner {
|
||||||
|
&self.data
|
||||||
|
}
|
||||||
|
|
||||||
|
fn basek(&self) -> usize {
|
||||||
|
self.basek
|
||||||
|
}
|
||||||
|
|
||||||
|
fn k(&self) -> usize {
|
||||||
|
self.k
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D: Data> GLWECiphertextCompressed<D> {
|
||||||
|
pub fn rank(&self) -> usize {
|
||||||
|
self.rank
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GLWECiphertextCompressed<Vec<u8>> {
|
||||||
|
pub fn alloc<B: Backend>(module: &Module<B>, basek: usize, k: usize, rank: usize) -> Self
|
||||||
|
where
|
||||||
|
Module<B>: VecZnxAlloc,
|
||||||
|
{
|
||||||
|
Self {
|
||||||
|
data: module.vec_znx_alloc(1, k.div_ceil(basek)),
|
||||||
|
basek,
|
||||||
|
k,
|
||||||
|
rank,
|
||||||
|
seed: [0u8; 32],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn bytes_of<B: Backend>(module: &Module<B>, basek: usize, k: usize) -> usize
|
||||||
|
where
|
||||||
|
Module<B>: VecZnxAllocBytes,
|
||||||
|
{
|
||||||
|
GLWECiphertext::bytes_of(module, basek, k, 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D: DataMut> ReaderFrom for GLWECiphertextCompressed<D> {
|
||||||
|
fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> {
|
||||||
|
self.k = reader.read_u64::<LittleEndian>()? as usize;
|
||||||
|
self.basek = reader.read_u64::<LittleEndian>()? as usize;
|
||||||
|
self.rank = reader.read_u64::<LittleEndian>()? as usize;
|
||||||
|
reader.read(&mut self.seed)?;
|
||||||
|
self.data.read_from(reader)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D: DataRef> WriterTo for GLWECiphertextCompressed<D> {
|
||||||
|
fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
|
||||||
|
writer.write_u64::<LittleEndian>(self.k as u64)?;
|
||||||
|
writer.write_u64::<LittleEndian>(self.basek as u64)?;
|
||||||
|
writer.write_u64::<LittleEndian>(self.rank as u64)?;
|
||||||
|
writer.write_all(&self.seed)?;
|
||||||
|
self.data.write_to(writer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D: DataMut> GLWECiphertext<D> {
|
||||||
|
pub fn decompress<DataOther, B: Backend>(&mut self, module: &Module<B>, other: &GLWECiphertextCompressed<DataOther>)
|
||||||
|
where
|
||||||
|
DataOther: DataRef,
|
||||||
|
Module<B>: VecZnxFillUniform + VecZnxCopy,
|
||||||
|
{
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
{
|
||||||
|
assert_eq!(
|
||||||
|
self.n(),
|
||||||
|
other.data.n(),
|
||||||
|
"invalid receiver: self.n()={} != other.n()={}",
|
||||||
|
self.n(),
|
||||||
|
other.data.n()
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
self.size(),
|
||||||
|
other.size(),
|
||||||
|
"invalid receiver: self.size()={} != other.size()={}",
|
||||||
|
self.size(),
|
||||||
|
other.size()
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
self.rank(),
|
||||||
|
other.rank(),
|
||||||
|
"invalid receiver: self.rank()={} != other.rank()={}",
|
||||||
|
self.rank(),
|
||||||
|
other.rank()
|
||||||
|
);
|
||||||
|
let mut source: Source = Source::new(other.seed);
|
||||||
|
self.decompress_internal(module, other, &mut source);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn decompress_internal<DataOther, B: Backend>(
|
||||||
|
&mut self,
|
||||||
|
module: &Module<B>,
|
||||||
|
other: &GLWECiphertextCompressed<DataOther>,
|
||||||
|
source: &mut Source,
|
||||||
|
) where
|
||||||
|
DataOther: DataRef,
|
||||||
|
Module<B>: VecZnxFillUniform + VecZnxCopy,
|
||||||
|
{
|
||||||
|
let k: usize = other.k;
|
||||||
|
let basek: usize = other.basek;
|
||||||
|
let cols: usize = other.cols();
|
||||||
|
module.vec_znx_copy(&mut self.data, 0, &other.data, 0);
|
||||||
|
(1..cols).for_each(|i| {
|
||||||
|
module.vec_znx_fill_uniform(basek, &mut self.data, i, k, source);
|
||||||
|
});
|
||||||
|
self.basek = basek;
|
||||||
|
self.k = k;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -12,6 +12,9 @@ mod public_key;
|
|||||||
mod secret;
|
mod secret;
|
||||||
mod trace;
|
mod trace;
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests;
|
||||||
|
|
||||||
pub use decryption::*;
|
pub use decryption::*;
|
||||||
pub use encryption::*;
|
pub use encryption::*;
|
||||||
pub use external_product::*;
|
pub use external_product::*;
|
||||||
@@ -22,6 +25,3 @@ pub use packing::*;
|
|||||||
pub use plaintext::*;
|
pub use plaintext::*;
|
||||||
pub use public_key::*;
|
pub use public_key::*;
|
||||||
pub use secret::*;
|
pub use secret::*;
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod test_fft64;
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ use crate::dist::Distribution;
|
|||||||
|
|
||||||
pub trait GLWESecretFamily<B: Backend> = SvpPrepare<B> + SvpPPolAllocBytes + SvpPPolAlloc<B>;
|
pub trait GLWESecretFamily<B: Backend> = SvpPrepare<B> + SvpPPolAllocBytes + SvpPPolAlloc<B>;
|
||||||
|
|
||||||
#[derive(PartialEq, Eq)]
|
#[derive(PartialEq, Eq, Clone)]
|
||||||
pub struct GLWESecret<D: Data> {
|
pub struct GLWESecret<D: Data> {
|
||||||
pub(crate) data: ScalarZnx<D>,
|
pub(crate) data: ScalarZnx<D>,
|
||||||
pub(crate) dist: Distribution,
|
pub(crate) dist: Distribution,
|
||||||
|
|||||||
@@ -1,6 +0,0 @@
|
|||||||
pub mod automorphism;
|
|
||||||
pub mod encryption;
|
|
||||||
pub mod external_product;
|
|
||||||
pub mod keyswitch;
|
|
||||||
pub mod packing;
|
|
||||||
pub mod trace;
|
|
||||||
191
core/src/glwe/tests/cpu_spqlios/fft64.rs
Normal file
191
core/src/glwe/tests/cpu_spqlios/fft64.rs
Normal file
@@ -0,0 +1,191 @@
|
|||||||
|
use backend::{
|
||||||
|
hal::{api::ModuleNew, layouts::Module},
|
||||||
|
implementation::cpu_spqlios::FFT64,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::glwe::tests::{
|
||||||
|
generic_automorphism::{test_automorphism, test_automorphism_inplace},
|
||||||
|
generic_encryption::{test_encrypt_pk, test_encrypt_sk, test_encrypt_sk_compressed, test_encrypt_zero_sk},
|
||||||
|
generic_external_product::{test_external_product, test_external_product_inplace},
|
||||||
|
generic_keyswitch::{test_keyswitch, test_keyswitch_inplace},
|
||||||
|
generic_serialization::{test_serialization, test_serialization_compressed},
|
||||||
|
packing::test_packing,
|
||||||
|
trace::test_trace_inplace,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn encrypt_sk() {
|
||||||
|
let log_n: usize = 8;
|
||||||
|
let module: Module<FFT64> = Module::<FFT64>::new(1 << log_n);
|
||||||
|
(1..4).for_each(|rank| {
|
||||||
|
println!("test encrypt_sk rank: {}", rank);
|
||||||
|
test_encrypt_sk(&module, 8, 54, 30, 3.2, rank);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn encrypt_sk_compressed() {
|
||||||
|
let log_n: usize = 8;
|
||||||
|
let module: Module<FFT64> = Module::<FFT64>::new(1 << log_n);
|
||||||
|
(1..4).for_each(|rank| {
|
||||||
|
println!("test encrypt_sk rank: {}", rank);
|
||||||
|
test_encrypt_sk_compressed(&module, 8, 54, 30, 3.2, rank);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn encrypt_zero_sk() {
|
||||||
|
let log_n: usize = 8;
|
||||||
|
let module: Module<FFT64> = Module::<FFT64>::new(1 << log_n);
|
||||||
|
(1..4).for_each(|rank| {
|
||||||
|
println!("test encrypt_zero_sk rank: {}", rank);
|
||||||
|
test_encrypt_zero_sk(&module, 8, 64, 3.2, rank);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn encrypt_pk() {
|
||||||
|
let log_n: usize = 8;
|
||||||
|
let module: Module<FFT64> = Module::<FFT64>::new(1 << log_n);
|
||||||
|
(1..4).for_each(|rank| {
|
||||||
|
println!("test encrypt_pk rank: {}", rank);
|
||||||
|
test_encrypt_pk(&module, 8, 64, 64, 3.2, rank)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn apply() {
|
||||||
|
let log_n: usize = 8;
|
||||||
|
let module: Module<FFT64> = Module::<FFT64>::new(1 << log_n);
|
||||||
|
let basek: usize = 12;
|
||||||
|
let k_in: usize = 45;
|
||||||
|
let digits: usize = k_in.div_ceil(basek);
|
||||||
|
(1..4).for_each(|rank_in| {
|
||||||
|
(1..4).for_each(|rank_out| {
|
||||||
|
(1..digits + 1).for_each(|di| {
|
||||||
|
let k_ksk: usize = k_in + basek * di;
|
||||||
|
let k_out: usize = k_ksk; // better capture noise
|
||||||
|
println!(
|
||||||
|
"test keyswitch digits: {} rank_in: {} rank_out: {}",
|
||||||
|
di, rank_in, rank_out
|
||||||
|
);
|
||||||
|
test_keyswitch(
|
||||||
|
&module, basek, k_out, k_in, k_ksk, di, rank_in, rank_out, 3.2,
|
||||||
|
);
|
||||||
|
})
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn apply_inplace() {
|
||||||
|
let log_n: usize = 8;
|
||||||
|
let module: Module<FFT64> = Module::<FFT64>::new(1 << log_n);
|
||||||
|
let basek: usize = 12;
|
||||||
|
let k_ct: usize = 45;
|
||||||
|
let digits: usize = k_ct.div_ceil(basek);
|
||||||
|
(1..4).for_each(|rank| {
|
||||||
|
(1..digits + 1).for_each(|di| {
|
||||||
|
let k_ksk: usize = k_ct + basek * di;
|
||||||
|
println!("test keyswitch_inplace digits: {} rank: {}", di, rank);
|
||||||
|
test_keyswitch_inplace(&module, basek, k_ct, k_ksk, di, rank, 3.2);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn automorphism_inplace() {
|
||||||
|
let log_n: usize = 8;
|
||||||
|
let module: Module<FFT64> = Module::<FFT64>::new(1 << log_n);
|
||||||
|
let basek: usize = 12;
|
||||||
|
let k_ct: usize = 60;
|
||||||
|
let digits: usize = k_ct.div_ceil(basek);
|
||||||
|
(1..4).for_each(|rank| {
|
||||||
|
(1..digits + 1).for_each(|di| {
|
||||||
|
let k_ksk: usize = k_ct + basek * di;
|
||||||
|
println!("test automorphism_inplace digits: {} rank: {}", di, rank);
|
||||||
|
test_automorphism_inplace(&module, basek, -5, k_ct, k_ksk, di, rank, 3.2);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn automorphism() {
|
||||||
|
let log_n: usize = 8;
|
||||||
|
let module: Module<FFT64> = Module::<FFT64>::new(1 << log_n);
|
||||||
|
let basek: usize = 12;
|
||||||
|
let k_in: usize = 60;
|
||||||
|
let digits: usize = k_in.div_ceil(basek);
|
||||||
|
(1..4).for_each(|rank| {
|
||||||
|
(1..digits + 1).for_each(|di| {
|
||||||
|
let k_ksk: usize = k_in + basek * di;
|
||||||
|
let k_out: usize = k_ksk; // Better capture noise.
|
||||||
|
println!("test automorphism digits: {} rank: {}", di, rank);
|
||||||
|
test_automorphism(&module, basek, -5, k_out, k_in, k_ksk, di, rank, 3.2);
|
||||||
|
})
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn external_product() {
|
||||||
|
let log_n: usize = 8;
|
||||||
|
let module: Module<FFT64> = Module::<FFT64>::new(1 << log_n);
|
||||||
|
let basek: usize = 12;
|
||||||
|
let k_in: usize = 45;
|
||||||
|
let digits: usize = k_in.div_ceil(basek);
|
||||||
|
(1..4).for_each(|rank| {
|
||||||
|
(1..digits + 1).for_each(|di| {
|
||||||
|
let k_ggsw: usize = k_in + basek * di;
|
||||||
|
let k_out: usize = k_ggsw; // Better capture noise
|
||||||
|
println!("test external_product digits: {} rank: {}", di, rank);
|
||||||
|
test_external_product(&module, basek, k_out, k_in, k_ggsw, di, rank, 3.2);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn external_product_inplace() {
|
||||||
|
let log_n: usize = 8;
|
||||||
|
let module: Module<FFT64> = Module::<FFT64>::new(1 << log_n);
|
||||||
|
let basek: usize = 12;
|
||||||
|
let k_ct: usize = 60;
|
||||||
|
let digits: usize = k_ct.div_ceil(basek);
|
||||||
|
(1..4).for_each(|rank| {
|
||||||
|
(1..digits + 1).for_each(|di| {
|
||||||
|
let k_ggsw: usize = k_ct + basek * di;
|
||||||
|
println!("test external_product digits: {} rank: {}", di, rank);
|
||||||
|
test_external_product_inplace(&module, basek, k_ct, k_ggsw, di, rank, 3.2);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn trace_inplace() {
|
||||||
|
let log_n: usize = 8;
|
||||||
|
let module: Module<FFT64> = Module::<FFT64>::new(1 << log_n);
|
||||||
|
(1..4).for_each(|rank| {
|
||||||
|
println!("test trace_inplace rank: {}", rank);
|
||||||
|
test_trace_inplace(&module, 8, 54, 3.2, rank);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn packing() {
|
||||||
|
let log_n: usize = 5;
|
||||||
|
let module: Module<FFT64> = Module::<FFT64>::new(1 << log_n);
|
||||||
|
test_packing(&module);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn serialization() {
|
||||||
|
let log_n: usize = 5;
|
||||||
|
let module: Module<FFT64> = Module::<FFT64>::new(1 << log_n);
|
||||||
|
test_serialization(&module);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn serialization_compressed() {
|
||||||
|
let log_n: usize = 5;
|
||||||
|
let module: Module<FFT64> = Module::<FFT64>::new(1 << log_n);
|
||||||
|
test_serialization_compressed(&module);
|
||||||
|
}
|
||||||
1
core/src/glwe/tests/cpu_spqlios/mod.rs
Normal file
1
core/src/glwe/tests/cpu_spqlios/mod.rs
Normal file
@@ -0,0 +1 @@
|
|||||||
|
mod fft64;
|
||||||
@@ -1,17 +1,14 @@
|
|||||||
use backend::{
|
use backend::hal::{
|
||||||
hal::{
|
|
||||||
api::{
|
api::{
|
||||||
MatZnxAlloc, ModuleNew, ScalarZnxAlloc, ScalarZnxAllocBytes, ScalarZnxAutomorphism, ScratchOwnedAlloc,
|
MatZnxAlloc, ScalarZnxAlloc, ScalarZnxAllocBytes, ScratchOwnedAlloc, ScratchOwnedBorrow, VecZnxAddScalarInplace,
|
||||||
ScratchOwnedBorrow, VecZnxAddScalarInplace, VecZnxAlloc, VecZnxAllocBytes, VecZnxAutomorphismInplace,
|
VecZnxAlloc, VecZnxAllocBytes, VecZnxAutomorphism, VecZnxAutomorphismInplace, VecZnxFillUniform, VecZnxStd,
|
||||||
VecZnxFillUniform, VecZnxStd, VecZnxSwithcDegree,
|
VecZnxSwithcDegree,
|
||||||
},
|
},
|
||||||
layouts::{Backend, Module, ScratchOwned},
|
layouts::{Backend, Module, ScratchOwned},
|
||||||
oep::{
|
oep::{
|
||||||
ScratchAvailableImpl, ScratchOwnedAllocImpl, ScratchOwnedBorrowImpl, TakeScalarZnxImpl, TakeSvpPPolImpl,
|
ScratchAvailableImpl, ScratchOwnedAllocImpl, ScratchOwnedBorrowImpl, TakeScalarZnxImpl, TakeSvpPPolImpl,
|
||||||
TakeVecZnxBigImpl, TakeVecZnxDftImpl, TakeVecZnxImpl,
|
TakeVecZnxBigImpl, TakeVecZnxDftImpl, TakeVecZnxImpl,
|
||||||
},
|
},
|
||||||
},
|
|
||||||
implementation::cpu_spqlios::FFT64,
|
|
||||||
};
|
};
|
||||||
use sampling::source::Source;
|
use sampling::source::Source;
|
||||||
|
|
||||||
@@ -21,39 +18,6 @@ use crate::{
|
|||||||
noise::log2_std_noise_gglwe_product,
|
noise::log2_std_noise_gglwe_product,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn apply_inplace() {
|
|
||||||
let log_n: usize = 8;
|
|
||||||
let module: Module<FFT64> = Module::<FFT64>::new(1 << log_n);
|
|
||||||
let basek: usize = 12;
|
|
||||||
let k_ct: usize = 60;
|
|
||||||
let digits: usize = k_ct.div_ceil(basek);
|
|
||||||
(1..4).for_each(|rank| {
|
|
||||||
(1..digits + 1).for_each(|di| {
|
|
||||||
let k_ksk: usize = k_ct + basek * di;
|
|
||||||
println!("test automorphism_inplace digits: {} rank: {}", di, rank);
|
|
||||||
test_automorphism_inplace(&module, basek, -5, k_ct, k_ksk, di, rank, 3.2);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn apply() {
|
|
||||||
let log_n: usize = 8;
|
|
||||||
let module: Module<FFT64> = Module::<FFT64>::new(1 << log_n);
|
|
||||||
let basek: usize = 12;
|
|
||||||
let k_in: usize = 60;
|
|
||||||
let digits: usize = k_in.div_ceil(basek);
|
|
||||||
(1..4).for_each(|rank| {
|
|
||||||
(1..digits + 1).for_each(|di| {
|
|
||||||
let k_ksk: usize = k_in + basek * di;
|
|
||||||
let k_out: usize = k_ksk; // Better capture noise.
|
|
||||||
println!("test automorphism digits: {} rank: {}", di, rank);
|
|
||||||
test_automorphism(&module, basek, -5, k_out, k_in, k_ksk, di, rank, 3.2);
|
|
||||||
})
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) trait AutomorphismTestModuleFamily<B: Backend> = AutomorphismKeyEncryptSkFamily<B>
|
pub(crate) trait AutomorphismTestModuleFamily<B: Backend> = AutomorphismKeyEncryptSkFamily<B>
|
||||||
+ GLWEDecryptFamily<B>
|
+ GLWEDecryptFamily<B>
|
||||||
+ GGLWEExecLayoutFamily<B>
|
+ GGLWEExecLayoutFamily<B>
|
||||||
@@ -62,7 +26,7 @@ pub(crate) trait AutomorphismTestModuleFamily<B: Backend> = AutomorphismKeyEncry
|
|||||||
+ VecZnxAlloc
|
+ VecZnxAlloc
|
||||||
+ ScalarZnxAllocBytes
|
+ ScalarZnxAllocBytes
|
||||||
+ VecZnxAllocBytes
|
+ VecZnxAllocBytes
|
||||||
+ ScalarZnxAutomorphism
|
+ VecZnxAutomorphism
|
||||||
+ VecZnxSwithcDegree
|
+ VecZnxSwithcDegree
|
||||||
+ ScalarZnxAlloc
|
+ ScalarZnxAlloc
|
||||||
+ VecZnxAddScalarInplace
|
+ VecZnxAddScalarInplace
|
||||||
@@ -77,7 +41,7 @@ pub(crate) trait AutomorphismTestScratchFamily<B: Backend> = TakeVecZnxDftImpl<B
|
|||||||
+ TakeScalarZnxImpl<B>
|
+ TakeScalarZnxImpl<B>
|
||||||
+ TakeVecZnxImpl<B>;
|
+ TakeVecZnxImpl<B>;
|
||||||
|
|
||||||
fn test_automorphism<B: Backend>(
|
pub(crate) fn test_automorphism<B: Backend>(
|
||||||
module: &Module<B>,
|
module: &Module<B>,
|
||||||
basek: usize,
|
basek: usize,
|
||||||
p: i64,
|
p: i64,
|
||||||
@@ -166,7 +130,7 @@ fn test_automorphism<B: Backend>(
|
|||||||
ct_out.assert_noise(module, &sk_exec, &pt_want, max_noise + 1.0);
|
ct_out.assert_noise(module, &sk_exec, &pt_want, max_noise + 1.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_automorphism_inplace<B: Backend>(
|
pub(crate) fn test_automorphism_inplace<B: Backend>(
|
||||||
module: &Module<B>,
|
module: &Module<B>,
|
||||||
basek: usize,
|
basek: usize,
|
||||||
p: i64,
|
p: i64,
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
use backend::{
|
use backend::hal::{
|
||||||
hal::{
|
|
||||||
api::{
|
api::{
|
||||||
ModuleNew, ScalarZnxAlloc, ScratchOwnedAlloc, ScratchOwnedBorrow, VecZnxAlloc, VecZnxDftAlloc, VecZnxFillUniform,
|
ScalarZnxAlloc, ScratchOwnedAlloc, ScratchOwnedBorrow, VecZnxAlloc, VecZnxCopy, VecZnxDftAlloc, VecZnxFillUniform,
|
||||||
VecZnxStd, VecZnxSubABInplace,
|
VecZnxStd, VecZnxSubABInplace,
|
||||||
},
|
},
|
||||||
layouts::{Backend, Module, ScratchOwned},
|
layouts::{Backend, Module, ScratchOwned},
|
||||||
@@ -9,46 +8,14 @@ use backend::{
|
|||||||
ScratchAvailableImpl, ScratchOwnedAllocImpl, ScratchOwnedBorrowImpl, TakeScalarZnxImpl, TakeSvpPPolImpl,
|
ScratchAvailableImpl, ScratchOwnedAllocImpl, ScratchOwnedBorrowImpl, TakeScalarZnxImpl, TakeSvpPPolImpl,
|
||||||
TakeVecZnxBigImpl, TakeVecZnxDftImpl, TakeVecZnxImpl,
|
TakeVecZnxBigImpl, TakeVecZnxDftImpl, TakeVecZnxImpl,
|
||||||
},
|
},
|
||||||
},
|
|
||||||
implementation::cpu_spqlios::FFT64,
|
|
||||||
};
|
};
|
||||||
use sampling::source::Source;
|
use sampling::source::Source;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
GLWECiphertext, GLWEDecryptFamily, GLWEEncryptPkFamily, GLWEEncryptSkFamily, GLWEOps, GLWEPlaintext, GLWEPublicKey,
|
GLWECiphertext, GLWECiphertextCompressed, GLWEDecryptFamily, GLWEEncryptPkFamily, GLWEEncryptSkFamily, GLWEOps,
|
||||||
GLWEPublicKeyExec, GLWESecret, GLWESecretExec, GLWESecretFamily, Infos,
|
GLWEPlaintext, GLWEPublicKey, GLWEPublicKeyExec, GLWESecret, GLWESecretExec, GLWESecretFamily, Infos,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn encrypt_sk() {
|
|
||||||
let log_n: usize = 8;
|
|
||||||
let module: Module<FFT64> = Module::<FFT64>::new(1 << log_n);
|
|
||||||
(1..4).for_each(|rank| {
|
|
||||||
println!("test encrypt_sk rank: {}", rank);
|
|
||||||
test_encrypt_sk(&module, 8, 54, 30, 3.2, rank);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn encrypt_zero_sk() {
|
|
||||||
let log_n: usize = 8;
|
|
||||||
let module: Module<FFT64> = Module::<FFT64>::new(1 << log_n);
|
|
||||||
(1..4).for_each(|rank| {
|
|
||||||
println!("test encrypt_zero_sk rank: {}", rank);
|
|
||||||
test_encrypt_zero_sk(&module, 8, 64, 3.2, rank);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn encrypt_pk() {
|
|
||||||
let log_n: usize = 8;
|
|
||||||
let module: Module<FFT64> = Module::<FFT64>::new(1 << log_n);
|
|
||||||
(1..4).for_each(|rank| {
|
|
||||||
println!("test encrypt_pk rank: {}", rank);
|
|
||||||
test_encrypt_pk(&module, 8, 64, 64, 3.2, rank)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) trait EncryptionTestModuleFamily<B: Backend> =
|
pub(crate) trait EncryptionTestModuleFamily<B: Backend> =
|
||||||
GLWEDecryptFamily<B> + GLWESecretFamily<B> + VecZnxAlloc + ScalarZnxAlloc + VecZnxStd;
|
GLWEDecryptFamily<B> + GLWESecretFamily<B> + VecZnxAlloc + ScalarZnxAlloc + VecZnxStd;
|
||||||
|
|
||||||
@@ -61,7 +28,7 @@ pub(crate) trait EncryptionTestScratchFamily<B: Backend> = TakeVecZnxDftImpl<B>
|
|||||||
+ TakeScalarZnxImpl<B>
|
+ TakeScalarZnxImpl<B>
|
||||||
+ TakeVecZnxImpl<B>;
|
+ TakeVecZnxImpl<B>;
|
||||||
|
|
||||||
fn test_encrypt_sk<B: Backend>(module: &Module<B>, basek: usize, k_ct: usize, k_pt: usize, sigma: f64, rank: usize)
|
pub(crate) fn test_encrypt_sk<B: Backend>(module: &Module<B>, basek: usize, k_ct: usize, k_pt: usize, sigma: f64, rank: usize)
|
||||||
where
|
where
|
||||||
Module<B>: EncryptionTestModuleFamily<B> + GLWEEncryptSkFamily<B>,
|
Module<B>: EncryptionTestModuleFamily<B> + GLWEEncryptSkFamily<B>,
|
||||||
B: EncryptionTestScratchFamily<B>,
|
B: EncryptionTestScratchFamily<B>,
|
||||||
@@ -105,7 +72,63 @@ where
|
|||||||
assert!(noise_have <= noise_want + 0.2);
|
assert!(noise_have <= noise_want + 0.2);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_encrypt_zero_sk<B: Backend>(module: &Module<B>, basek: usize, k_ct: usize, sigma: f64, rank: usize)
|
pub(crate) fn test_encrypt_sk_compressed<B: Backend>(
|
||||||
|
module: &Module<B>,
|
||||||
|
basek: usize,
|
||||||
|
k_ct: usize,
|
||||||
|
k_pt: usize,
|
||||||
|
sigma: f64,
|
||||||
|
rank: usize,
|
||||||
|
) where
|
||||||
|
Module<B>: EncryptionTestModuleFamily<B> + GLWEEncryptSkFamily<B> + VecZnxCopy,
|
||||||
|
B: EncryptionTestScratchFamily<B>,
|
||||||
|
{
|
||||||
|
let mut ct_compressed: GLWECiphertextCompressed<Vec<u8>> = GLWECiphertextCompressed::alloc(module, basek, k_ct, rank);
|
||||||
|
|
||||||
|
let mut pt_want: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(module, basek, k_pt);
|
||||||
|
let mut pt_have: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(module, basek, k_pt);
|
||||||
|
|
||||||
|
let mut source_xs: Source = Source::new([0u8; 32]);
|
||||||
|
let mut source_xe: Source = Source::new([0u8; 32]);
|
||||||
|
let mut source_xa: Source = Source::new([0u8; 32]);
|
||||||
|
|
||||||
|
let mut scratch: ScratchOwned<B> = ScratchOwned::alloc(
|
||||||
|
GLWECiphertextCompressed::encrypt_sk_scratch_space(module, basek, k_ct)
|
||||||
|
| GLWECiphertext::decrypt_scratch_space(module, basek, k_ct),
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(module, rank);
|
||||||
|
sk.fill_ternary_prob(0.5, &mut source_xs);
|
||||||
|
let sk_exec: GLWESecretExec<Vec<u8>, B> = GLWESecretExec::from(module, &sk);
|
||||||
|
|
||||||
|
module.vec_znx_fill_uniform(basek, &mut pt_want.data, 0, k_pt, &mut source_xa);
|
||||||
|
|
||||||
|
let seed_xa: [u8; 32] = [1u8; 32];
|
||||||
|
|
||||||
|
ct_compressed.encrypt_sk(
|
||||||
|
module,
|
||||||
|
&pt_want,
|
||||||
|
&sk_exec,
|
||||||
|
seed_xa,
|
||||||
|
&mut source_xe,
|
||||||
|
sigma,
|
||||||
|
scratch.borrow(),
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut ct: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(module, basek, k_ct, rank);
|
||||||
|
ct.decompress(module, &ct_compressed);
|
||||||
|
|
||||||
|
ct.decrypt(module, &mut pt_have, &sk_exec, scratch.borrow());
|
||||||
|
|
||||||
|
pt_want.sub_inplace_ab(module, &pt_have);
|
||||||
|
|
||||||
|
let noise_have: f64 = module.vec_znx_std(basek, &pt_want.data, 0) * (ct.k() as f64).exp2();
|
||||||
|
let noise_want: f64 = sigma;
|
||||||
|
|
||||||
|
assert!(noise_have <= noise_want + 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn test_encrypt_zero_sk<B: Backend>(module: &Module<B>, basek: usize, k_ct: usize, sigma: f64, rank: usize)
|
||||||
where
|
where
|
||||||
Module<B>: EncryptionTestModuleFamily<B> + GLWEEncryptSkFamily<B>,
|
Module<B>: EncryptionTestModuleFamily<B> + GLWEEncryptSkFamily<B>,
|
||||||
B: EncryptionTestScratchFamily<B>,
|
B: EncryptionTestScratchFamily<B>,
|
||||||
@@ -140,7 +163,7 @@ where
|
|||||||
assert!((sigma - module.vec_znx_std(basek, &pt.data, 0) * (k_ct as f64).exp2()) <= 0.2);
|
assert!((sigma - module.vec_znx_std(basek, &pt.data, 0) * (k_ct as f64).exp2()) <= 0.2);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_encrypt_pk<B: Backend>(module: &Module<B>, basek: usize, k_ct: usize, k_pk: usize, sigma: f64, rank: usize)
|
pub(crate) fn test_encrypt_pk<B: Backend>(module: &Module<B>, basek: usize, k_ct: usize, k_pk: usize, sigma: f64, rank: usize)
|
||||||
where
|
where
|
||||||
Module<B>: EncryptionTestModuleFamily<B>
|
Module<B>: EncryptionTestModuleFamily<B>
|
||||||
+ GLWEEncryptPkFamily<B>
|
+ GLWEEncryptPkFamily<B>
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
use backend::{
|
use backend::hal::{
|
||||||
hal::{
|
|
||||||
api::{
|
api::{
|
||||||
MatZnxAlloc, ModuleNew, ScalarZnxAlloc, ScratchOwnedAlloc, ScratchOwnedBorrow, VecZnxAddScalarInplace, VecZnxAlloc,
|
MatZnxAlloc, ScalarZnxAlloc, ScratchOwnedAlloc, ScratchOwnedBorrow, VecZnxAddScalarInplace, VecZnxAlloc,
|
||||||
VecZnxAllocBytes, VecZnxFillUniform, VecZnxRotateInplace, VecZnxStd, ZnxViewMut,
|
VecZnxAllocBytes, VecZnxFillUniform, VecZnxRotateInplace, VecZnxStd, ZnxViewMut,
|
||||||
},
|
},
|
||||||
layouts::{Backend, Module, ScalarZnx, ScratchOwned},
|
layouts::{Backend, Module, ScalarZnx, ScratchOwned},
|
||||||
@@ -9,8 +8,6 @@ use backend::{
|
|||||||
ScratchAvailableImpl, ScratchOwnedAllocImpl, ScratchOwnedBorrowImpl, TakeScalarZnxImpl, TakeSvpPPolImpl,
|
ScratchAvailableImpl, ScratchOwnedAllocImpl, ScratchOwnedBorrowImpl, TakeScalarZnxImpl, TakeSvpPPolImpl,
|
||||||
TakeVecZnxBigImpl, TakeVecZnxDftImpl, TakeVecZnxImpl,
|
TakeVecZnxBigImpl, TakeVecZnxDftImpl, TakeVecZnxImpl,
|
||||||
},
|
},
|
||||||
},
|
|
||||||
implementation::cpu_spqlios::FFT64,
|
|
||||||
};
|
};
|
||||||
use sampling::source::Source;
|
use sampling::source::Source;
|
||||||
|
|
||||||
@@ -19,39 +16,6 @@ use crate::{
|
|||||||
GLWEExternalProductFamily, GLWEPlaintext, GLWESecret, GLWESecretExec, GLWESecretFamily, Infos, noise::noise_ggsw_product,
|
GLWEExternalProductFamily, GLWEPlaintext, GLWESecret, GLWESecretExec, GLWESecretFamily, Infos, noise::noise_ggsw_product,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn apply() {
|
|
||||||
let log_n: usize = 8;
|
|
||||||
let module: Module<FFT64> = Module::<FFT64>::new(1 << log_n);
|
|
||||||
let basek: usize = 12;
|
|
||||||
let k_in: usize = 45;
|
|
||||||
let digits: usize = k_in.div_ceil(basek);
|
|
||||||
(1..4).for_each(|rank| {
|
|
||||||
(1..digits + 1).for_each(|di| {
|
|
||||||
let k_ggsw: usize = k_in + basek * di;
|
|
||||||
let k_out: usize = k_ggsw; // Better capture noise
|
|
||||||
println!("test external_product digits: {} rank: {}", di, rank);
|
|
||||||
test_external_product(&module, basek, k_out, k_in, k_ggsw, di, rank, 3.2);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn apply_inplace() {
|
|
||||||
let log_n: usize = 8;
|
|
||||||
let module: Module<FFT64> = Module::<FFT64>::new(1 << log_n);
|
|
||||||
let basek: usize = 12;
|
|
||||||
let k_ct: usize = 60;
|
|
||||||
let digits: usize = k_ct.div_ceil(basek);
|
|
||||||
(1..4).for_each(|rank| {
|
|
||||||
(1..digits + 1).for_each(|di| {
|
|
||||||
let k_ggsw: usize = k_ct + basek * di;
|
|
||||||
println!("test external_product digits: {} rank: {}", di, rank);
|
|
||||||
test_external_product_inplace(&module, basek, k_ct, k_ggsw, di, rank, 3.2);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) trait ExternalProductTestModuleFamily<B: Backend> = GLWEEncryptSkFamily<B>
|
pub(crate) trait ExternalProductTestModuleFamily<B: Backend> = GLWEEncryptSkFamily<B>
|
||||||
+ GLWEDecryptFamily<B>
|
+ GLWEDecryptFamily<B>
|
||||||
+ GLWESecretFamily<B>
|
+ GLWESecretFamily<B>
|
||||||
@@ -74,7 +38,7 @@ pub(crate) trait ExternalProductTestScratchFamily<B: Backend> = TakeVecZnxDftImp
|
|||||||
+ TakeScalarZnxImpl<B>
|
+ TakeScalarZnxImpl<B>
|
||||||
+ TakeVecZnxImpl<B>;
|
+ TakeVecZnxImpl<B>;
|
||||||
|
|
||||||
fn test_external_product<B: Backend>(
|
pub(crate) fn test_external_product<B: Backend>(
|
||||||
module: &Module<B>,
|
module: &Module<B>,
|
||||||
basek: usize,
|
basek: usize,
|
||||||
k_out: usize,
|
k_out: usize,
|
||||||
@@ -176,7 +140,7 @@ fn test_external_product<B: Backend>(
|
|||||||
ct_glwe_out.assert_noise(module, &sk_exec, &pt_want, max_noise + 0.5);
|
ct_glwe_out.assert_noise(module, &sk_exec, &pt_want, max_noise + 0.5);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_external_product_inplace<B: Backend>(
|
pub(crate) fn test_external_product_inplace<B: Backend>(
|
||||||
module: &Module<B>,
|
module: &Module<B>,
|
||||||
basek: usize,
|
basek: usize,
|
||||||
k_ct: usize,
|
k_ct: usize,
|
||||||
@@ -1,16 +1,13 @@
|
|||||||
use backend::{
|
use backend::hal::{
|
||||||
hal::{
|
|
||||||
api::{
|
api::{
|
||||||
MatZnxAlloc, ModuleNew, ScalarZnxAlloc, ScalarZnxAllocBytes, ScratchOwnedAlloc, ScratchOwnedBorrow,
|
MatZnxAlloc, ScalarZnxAlloc, ScalarZnxAllocBytes, ScratchOwnedAlloc, ScratchOwnedBorrow, VecZnxAddScalarInplace,
|
||||||
VecZnxAddScalarInplace, VecZnxAlloc, VecZnxAllocBytes, VecZnxFillUniform, VecZnxStd, VecZnxSwithcDegree,
|
VecZnxAlloc, VecZnxAllocBytes, VecZnxFillUniform, VecZnxStd, VecZnxSwithcDegree,
|
||||||
},
|
},
|
||||||
layouts::{Backend, Module, ScratchOwned},
|
layouts::{Backend, Module, ScratchOwned},
|
||||||
oep::{
|
oep::{
|
||||||
ScratchAvailableImpl, ScratchOwnedAllocImpl, ScratchOwnedBorrowImpl, TakeScalarZnxImpl, TakeSvpPPolImpl,
|
ScratchAvailableImpl, ScratchOwnedAllocImpl, ScratchOwnedBorrowImpl, TakeScalarZnxImpl, TakeSvpPPolImpl,
|
||||||
TakeVecZnxBigImpl, TakeVecZnxDftImpl, TakeVecZnxImpl,
|
TakeVecZnxBigImpl, TakeVecZnxDftImpl, TakeVecZnxImpl,
|
||||||
},
|
},
|
||||||
},
|
|
||||||
implementation::cpu_spqlios::FFT64,
|
|
||||||
};
|
};
|
||||||
use sampling::source::Source;
|
use sampling::source::Source;
|
||||||
|
|
||||||
@@ -20,46 +17,6 @@ use crate::{
|
|||||||
noise::log2_std_noise_gglwe_product,
|
noise::log2_std_noise_gglwe_product,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn apply() {
|
|
||||||
let log_n: usize = 8;
|
|
||||||
let module: Module<FFT64> = Module::<FFT64>::new(1 << log_n);
|
|
||||||
let basek: usize = 12;
|
|
||||||
let k_in: usize = 45;
|
|
||||||
let digits: usize = k_in.div_ceil(basek);
|
|
||||||
(1..4).for_each(|rank_in| {
|
|
||||||
(1..4).for_each(|rank_out| {
|
|
||||||
(1..digits + 1).for_each(|di| {
|
|
||||||
let k_ksk: usize = k_in + basek * di;
|
|
||||||
let k_out: usize = k_ksk; // better capture noise
|
|
||||||
println!(
|
|
||||||
"test keyswitch digits: {} rank_in: {} rank_out: {}",
|
|
||||||
di, rank_in, rank_out
|
|
||||||
);
|
|
||||||
test_keyswitch(
|
|
||||||
&module, basek, k_out, k_in, k_ksk, di, rank_in, rank_out, 3.2,
|
|
||||||
);
|
|
||||||
})
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn apply_inplace() {
|
|
||||||
let log_n: usize = 8;
|
|
||||||
let module: Module<FFT64> = Module::<FFT64>::new(1 << log_n);
|
|
||||||
let basek: usize = 12;
|
|
||||||
let k_ct: usize = 45;
|
|
||||||
let digits: usize = k_ct.div_ceil(basek);
|
|
||||||
(1..4).for_each(|rank| {
|
|
||||||
(1..digits + 1).for_each(|di| {
|
|
||||||
let k_ksk: usize = k_ct + basek * di;
|
|
||||||
println!("test keyswitch_inplace digits: {} rank: {}", di, rank);
|
|
||||||
test_keyswitch_inplace(&module, basek, k_ct, k_ksk, di, rank, 3.2);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) trait KeySwitchTestModuleFamily<B: Backend> = GLWESecretFamily<B>
|
pub(crate) trait KeySwitchTestModuleFamily<B: Backend> = GLWESecretFamily<B>
|
||||||
+ GLWESwitchingKeyEncryptSkFamily<B>
|
+ GLWESwitchingKeyEncryptSkFamily<B>
|
||||||
+ GLWEKeyswitchFamily<B>
|
+ GLWEKeyswitchFamily<B>
|
||||||
@@ -83,7 +40,7 @@ pub(crate) trait KeySwitchTestScratchFamily<B: Backend> = TakeVecZnxDftImpl<B>
|
|||||||
+ TakeScalarZnxImpl<B>
|
+ TakeScalarZnxImpl<B>
|
||||||
+ TakeVecZnxImpl<B>;
|
+ TakeVecZnxImpl<B>;
|
||||||
|
|
||||||
fn test_keyswitch<B: Backend>(
|
pub(crate) fn test_keyswitch<B: Backend>(
|
||||||
module: &Module<B>,
|
module: &Module<B>,
|
||||||
basek: usize,
|
basek: usize,
|
||||||
k_out: usize,
|
k_out: usize,
|
||||||
@@ -173,7 +130,7 @@ fn test_keyswitch<B: Backend>(
|
|||||||
ct_out.assert_noise(module, &sk_out_exec, &pt_want, max_noise + 0.5);
|
ct_out.assert_noise(module, &sk_out_exec, &pt_want, max_noise + 0.5);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_keyswitch_inplace<B: Backend>(
|
pub(crate) fn test_keyswitch_inplace<B: Backend>(
|
||||||
module: &Module<B>,
|
module: &Module<B>,
|
||||||
basek: usize,
|
basek: usize,
|
||||||
k_ct: usize,
|
k_ct: usize,
|
||||||
23
core/src/glwe/tests/generic_serialization.rs
Normal file
23
core/src/glwe/tests/generic_serialization.rs
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
use backend::hal::{
|
||||||
|
api::VecZnxAlloc,
|
||||||
|
layouts::{Backend, Module},
|
||||||
|
tests::serialization::test_reader_writer_interface,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::{GLWECiphertext, GLWECiphertextCompressed};
|
||||||
|
|
||||||
|
pub(crate) fn test_serialization<B: Backend>(module: &Module<B>)
|
||||||
|
where
|
||||||
|
Module<B>: VecZnxAlloc,
|
||||||
|
{
|
||||||
|
let original: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(module, 12, 54, 3);
|
||||||
|
test_reader_writer_interface(original);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn test_serialization_compressed<B: Backend>(module: &Module<B>)
|
||||||
|
where
|
||||||
|
Module<B>: VecZnxAlloc,
|
||||||
|
{
|
||||||
|
let original: GLWECiphertextCompressed<Vec<u8>> = GLWECiphertextCompressed::alloc(module, 12, 54, 3);
|
||||||
|
test_reader_writer_interface(original);
|
||||||
|
}
|
||||||
8
core/src/glwe/tests/mod.rs
Normal file
8
core/src/glwe/tests/mod.rs
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
mod cpu_spqlios;
|
||||||
|
mod generic_automorphism;
|
||||||
|
mod generic_encryption;
|
||||||
|
mod generic_external_product;
|
||||||
|
mod generic_keyswitch;
|
||||||
|
mod generic_serialization;
|
||||||
|
mod packing;
|
||||||
|
mod trace;
|
||||||
@@ -1,19 +1,16 @@
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use backend::{
|
use backend::hal::{
|
||||||
hal::{
|
|
||||||
api::{
|
api::{
|
||||||
MatZnxAlloc, ModuleNew, ScalarZnxAlloc, ScalarZnxAllocBytes, ScalarZnxAutomorphism, ScratchOwnedAlloc,
|
MatZnxAlloc, ScalarZnxAlloc, ScalarZnxAllocBytes, ScratchOwnedAlloc, ScratchOwnedBorrow, VecZnxAddScalarInplace,
|
||||||
ScratchOwnedBorrow, VecZnxAddScalarInplace, VecZnxAlloc, VecZnxAllocBytes, VecZnxBigSubSmallBInplace,
|
VecZnxAlloc, VecZnxAllocBytes, VecZnxAutomorphism, VecZnxBigSubSmallBInplace, VecZnxEncodeVeci64, VecZnxRotateInplace,
|
||||||
VecZnxEncodeVeci64, VecZnxRotateInplace, VecZnxStd, VecZnxSwithcDegree,
|
VecZnxStd, VecZnxSwithcDegree,
|
||||||
},
|
},
|
||||||
layouts::{Backend, Module, ScratchOwned},
|
layouts::{Backend, Module, ScratchOwned},
|
||||||
oep::{
|
oep::{
|
||||||
ScratchAvailableImpl, ScratchOwnedAllocImpl, ScratchOwnedBorrowImpl, TakeScalarZnxImpl, TakeSvpPPolImpl,
|
ScratchAvailableImpl, ScratchOwnedAllocImpl, ScratchOwnedBorrowImpl, TakeScalarZnxImpl, TakeSvpPPolImpl,
|
||||||
TakeVecZnxBigImpl, TakeVecZnxDftImpl, TakeVecZnxImpl,
|
TakeVecZnxBigImpl, TakeVecZnxDftImpl, TakeVecZnxImpl,
|
||||||
},
|
},
|
||||||
},
|
|
||||||
implementation::cpu_spqlios::FFT64,
|
|
||||||
};
|
};
|
||||||
use sampling::source::Source;
|
use sampling::source::Source;
|
||||||
|
|
||||||
@@ -22,13 +19,6 @@ use crate::{
|
|||||||
GLWEPacker, GLWEPackingFamily, GLWEPlaintext, GLWESecret, GLWESecretExec, GLWESecretFamily, GLWESwitchingKeyEncryptSkFamily,
|
GLWEPacker, GLWEPackingFamily, GLWEPlaintext, GLWESecret, GLWESecretExec, GLWESecretFamily, GLWESwitchingKeyEncryptSkFamily,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn trace() {
|
|
||||||
let log_n: usize = 5;
|
|
||||||
let module: Module<FFT64> = Module::<FFT64>::new(1 << log_n);
|
|
||||||
test_packing(&module);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) trait PackingTestModuleFamily<B: Backend> = GLWEPackingFamily<B>
|
pub(crate) trait PackingTestModuleFamily<B: Backend> = GLWEPackingFamily<B>
|
||||||
+ GLWESecretFamily<B>
|
+ GLWESecretFamily<B>
|
||||||
+ GLWESwitchingKeyEncryptSkFamily<B>
|
+ GLWESwitchingKeyEncryptSkFamily<B>
|
||||||
@@ -44,8 +34,8 @@ pub(crate) trait PackingTestModuleFamily<B: Backend> = GLWEPackingFamily<B>
|
|||||||
+ VecZnxSwithcDegree
|
+ VecZnxSwithcDegree
|
||||||
+ VecZnxAddScalarInplace
|
+ VecZnxAddScalarInplace
|
||||||
+ VecZnxEncodeVeci64
|
+ VecZnxEncodeVeci64
|
||||||
+ ScalarZnxAutomorphism
|
|
||||||
+ VecZnxRotateInplace
|
+ VecZnxRotateInplace
|
||||||
|
+ VecZnxAutomorphism
|
||||||
+ VecZnxBigSubSmallBInplace<B>;
|
+ VecZnxBigSubSmallBInplace<B>;
|
||||||
|
|
||||||
pub(crate) trait PackingTestScratchFamily<B: Backend> = TakeVecZnxDftImpl<B>
|
pub(crate) trait PackingTestScratchFamily<B: Backend> = TakeVecZnxDftImpl<B>
|
||||||
@@ -1,20 +1,17 @@
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use backend::{
|
use backend::hal::{
|
||||||
hal::{
|
|
||||||
api::{
|
api::{
|
||||||
MatZnxAlloc, ModuleNew, ScalarZnxAlloc, ScalarZnxAllocBytes, ScalarZnxAutomorphism, ScratchOwnedAlloc,
|
MatZnxAlloc, ScalarZnxAlloc, ScalarZnxAllocBytes, ScratchOwnedAlloc, ScratchOwnedBorrow, VecZnxAddScalarInplace,
|
||||||
ScratchOwnedBorrow, VecZnxAddScalarInplace, VecZnxAlloc, VecZnxAllocBytes, VecZnxBigAutomorphismInplace,
|
VecZnxAlloc, VecZnxAllocBytes, VecZnxAutomorphism, VecZnxBigAutomorphismInplace, VecZnxBigSubSmallBInplace, VecZnxCopy,
|
||||||
VecZnxBigSubSmallBInplace, VecZnxCopy, VecZnxEncodeVeci64, VecZnxFillUniform, VecZnxNormalizeInplace,
|
VecZnxEncodeVeci64, VecZnxFillUniform, VecZnxNormalizeInplace, VecZnxRotateInplace, VecZnxRshInplace, VecZnxStd,
|
||||||
VecZnxRotateInplace, VecZnxRshInplace, VecZnxStd, VecZnxSubABInplace, VecZnxSwithcDegree, ZnxView, ZnxViewMut,
|
VecZnxSubABInplace, VecZnxSwithcDegree, ZnxView, ZnxViewMut,
|
||||||
},
|
},
|
||||||
layouts::{Backend, Module, ScratchOwned},
|
layouts::{Backend, Module, ScratchOwned},
|
||||||
oep::{
|
oep::{
|
||||||
ScratchAvailableImpl, ScratchOwnedAllocImpl, ScratchOwnedBorrowImpl, TakeScalarZnxImpl, TakeSvpPPolImpl,
|
ScratchAvailableImpl, ScratchOwnedAllocImpl, ScratchOwnedBorrowImpl, TakeScalarZnxImpl, TakeSvpPPolImpl,
|
||||||
TakeVecZnxBigImpl, TakeVecZnxDftImpl, TakeVecZnxImpl,
|
TakeVecZnxBigImpl, TakeVecZnxDftImpl, TakeVecZnxImpl,
|
||||||
},
|
},
|
||||||
},
|
|
||||||
implementation::cpu_spqlios::FFT64,
|
|
||||||
};
|
};
|
||||||
use sampling::source::Source;
|
use sampling::source::Source;
|
||||||
|
|
||||||
@@ -24,16 +21,6 @@ use crate::{
|
|||||||
noise::var_noise_gglwe_product,
|
noise::var_noise_gglwe_product,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn apply_inplace() {
|
|
||||||
let log_n: usize = 8;
|
|
||||||
let module: Module<FFT64> = Module::<FFT64>::new(1 << log_n);
|
|
||||||
(1..4).for_each(|rank| {
|
|
||||||
println!("test trace_inplace rank: {}", rank);
|
|
||||||
test_trace_inplace(&module, 8, 54, 3.2, rank);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) trait TraceTestModuleFamily<B: Backend> = GLWESecretFamily<B>
|
pub(crate) trait TraceTestModuleFamily<B: Backend> = GLWESecretFamily<B>
|
||||||
+ GLWESwitchingKeyEncryptSkFamily<B>
|
+ GLWESwitchingKeyEncryptSkFamily<B>
|
||||||
+ GLWEKeyswitchFamily<B>
|
+ GLWEKeyswitchFamily<B>
|
||||||
@@ -48,11 +35,11 @@ pub(crate) trait TraceTestModuleFamily<B: Backend> = GLWESecretFamily<B>
|
|||||||
+ VecZnxSwithcDegree
|
+ VecZnxSwithcDegree
|
||||||
+ VecZnxAddScalarInplace
|
+ VecZnxAddScalarInplace
|
||||||
+ VecZnxEncodeVeci64
|
+ VecZnxEncodeVeci64
|
||||||
+ ScalarZnxAutomorphism
|
|
||||||
+ VecZnxRotateInplace
|
+ VecZnxRotateInplace
|
||||||
+ VecZnxBigSubSmallBInplace<B>
|
+ VecZnxBigSubSmallBInplace<B>
|
||||||
+ VecZnxBigAutomorphismInplace<B>
|
+ VecZnxBigAutomorphismInplace<B>
|
||||||
+ VecZnxCopy
|
+ VecZnxCopy
|
||||||
|
+ VecZnxAutomorphism
|
||||||
+ VecZnxRshInplace;
|
+ VecZnxRshInplace;
|
||||||
|
|
||||||
pub(crate) trait TraceTestScratchFamily<B: Backend> = TakeVecZnxDftImpl<B>
|
pub(crate) trait TraceTestScratchFamily<B: Backend> = TakeVecZnxDftImpl<B>
|
||||||
@@ -64,7 +51,7 @@ pub(crate) trait TraceTestScratchFamily<B: Backend> = TakeVecZnxDftImpl<B>
|
|||||||
+ TakeScalarZnxImpl<B>
|
+ TakeScalarZnxImpl<B>
|
||||||
+ TakeVecZnxImpl<B>;
|
+ TakeVecZnxImpl<B>;
|
||||||
|
|
||||||
fn test_trace_inplace<B: Backend>(module: &Module<B>, basek: usize, k: usize, sigma: f64, rank: usize)
|
pub(crate) fn test_trace_inplace<B: Backend>(module: &Module<B>, basek: usize, k: usize, sigma: f64, rank: usize)
|
||||||
where
|
where
|
||||||
Module<B>: TraceTestModuleFamily<B>,
|
Module<B>: TraceTestModuleFamily<B>,
|
||||||
B: TraceTestScratchFamily<B>,
|
B: TraceTestScratchFamily<B>,
|
||||||
@@ -14,7 +14,7 @@ pub struct LWECiphertext<D: Data> {
|
|||||||
impl LWECiphertext<Vec<u8>> {
|
impl LWECiphertext<Vec<u8>> {
|
||||||
pub fn alloc(n: usize, basek: usize, k: usize) -> Self {
|
pub fn alloc(n: usize, basek: usize, k: usize) -> Self {
|
||||||
Self {
|
Self {
|
||||||
data: VecZnx::new::<i64>(n + 1, 1, k.div_ceil(basek)),
|
data: VecZnx::alloc::<i64>(n + 1, 1, k.div_ceil(basek)),
|
||||||
k: k,
|
k: k,
|
||||||
basek: basek,
|
basek: basek,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ impl<DataSelf: DataMut> LWECiphertext<DataSelf> {
|
|||||||
|
|
||||||
module.vec_znx_fill_uniform(basek, &mut self.data, 0, k, source_xa);
|
module.vec_znx_fill_uniform(basek, &mut self.data, 0, k, source_xa);
|
||||||
|
|
||||||
let mut tmp_znx: VecZnx<Vec<u8>> = VecZnx::<Vec<u8>>::new::<i64>(1, 1, self.size());
|
let mut tmp_znx: VecZnx<Vec<u8>> = VecZnx::<Vec<u8>>::alloc::<i64>(1, 1, self.size());
|
||||||
|
|
||||||
let min_size = self.size().min(pt.size());
|
let min_size = self.size().min(pt.size());
|
||||||
|
|
||||||
|
|||||||
@@ -126,7 +126,7 @@ impl<D: DataMut> GLWEToLWESwitchingKey<D> {
|
|||||||
let (mut sk_lwe_as_glwe, scratch1) = scratch.take_glwe_secret(module, 1);
|
let (mut sk_lwe_as_glwe, scratch1) = scratch.take_glwe_secret(module, 1);
|
||||||
sk_lwe_as_glwe.data.zero();
|
sk_lwe_as_glwe.data.zero();
|
||||||
sk_lwe_as_glwe.data.at_mut(0, 0)[..sk_lwe.n()].copy_from_slice(sk_lwe.data.at(0, 0));
|
sk_lwe_as_glwe.data.at_mut(0, 0)[..sk_lwe.n()].copy_from_slice(sk_lwe.data.at(0, 0));
|
||||||
module.vec_znx_automorphism_inplace(-1, &mut sk_lwe_as_glwe.data, 0);
|
module.vec_znx_automorphism_inplace(-1, &mut sk_lwe_as_glwe.data.as_vec_znx_mut(), 0);
|
||||||
|
|
||||||
self.0.encrypt_sk(
|
self.0.encrypt_sk(
|
||||||
module,
|
module,
|
||||||
@@ -252,7 +252,7 @@ impl<D: DataMut> LWEToGLWESwitchingKey<D> {
|
|||||||
let (mut sk_lwe_as_glwe, scratch1) = scratch.take_glwe_secret(module, 1);
|
let (mut sk_lwe_as_glwe, scratch1) = scratch.take_glwe_secret(module, 1);
|
||||||
sk_lwe_as_glwe.data.at_mut(0, 0)[..sk_lwe.n()].copy_from_slice(sk_lwe.data.at(0, 0));
|
sk_lwe_as_glwe.data.at_mut(0, 0)[..sk_lwe.n()].copy_from_slice(sk_lwe.data.at(0, 0));
|
||||||
sk_lwe_as_glwe.data.at_mut(0, 0)[sk_lwe.n()..].fill(0);
|
sk_lwe_as_glwe.data.at_mut(0, 0)[sk_lwe.n()..].fill(0);
|
||||||
module.vec_znx_automorphism_inplace(-1, &mut sk_lwe_as_glwe.data, 0);
|
module.vec_znx_automorphism_inplace(-1, &mut sk_lwe_as_glwe.data.as_vec_znx_mut(), 0);
|
||||||
|
|
||||||
self.0.encrypt_sk(
|
self.0.encrypt_sk(
|
||||||
module,
|
module,
|
||||||
@@ -368,11 +368,11 @@ impl<D: DataMut> LWESwitchingKey<D> {
|
|||||||
|
|
||||||
sk_out_glwe.data.at_mut(0, 0)[..sk_lwe_out.n()].copy_from_slice(sk_lwe_out.data.at(0, 0));
|
sk_out_glwe.data.at_mut(0, 0)[..sk_lwe_out.n()].copy_from_slice(sk_lwe_out.data.at(0, 0));
|
||||||
sk_out_glwe.data.at_mut(0, 0)[sk_lwe_out.n()..].fill(0);
|
sk_out_glwe.data.at_mut(0, 0)[sk_lwe_out.n()..].fill(0);
|
||||||
module.vec_znx_automorphism_inplace(-1, &mut sk_out_glwe.data, 0);
|
module.vec_znx_automorphism_inplace(-1, &mut sk_out_glwe.data.as_vec_znx_mut(), 0);
|
||||||
|
|
||||||
sk_in_glwe.data.at_mut(0, 0)[..sk_lwe_in.n()].copy_from_slice(sk_lwe_in.data.at(0, 0));
|
sk_in_glwe.data.at_mut(0, 0)[..sk_lwe_in.n()].copy_from_slice(sk_lwe_in.data.at(0, 0));
|
||||||
sk_in_glwe.data.at_mut(0, 0)[sk_lwe_in.n()..].fill(0);
|
sk_in_glwe.data.at_mut(0, 0)[sk_lwe_in.n()..].fill(0);
|
||||||
module.vec_znx_automorphism_inplace(-1, &mut sk_in_glwe.data, 0);
|
module.vec_znx_automorphism_inplace(-1, &mut sk_in_glwe.data.as_vec_znx_mut(), 0);
|
||||||
|
|
||||||
self.0.encrypt_sk(
|
self.0.encrypt_sk(
|
||||||
module,
|
module,
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ pub struct LWEPlaintext<D: Data> {
|
|||||||
impl LWEPlaintext<Vec<u8>> {
|
impl LWEPlaintext<Vec<u8>> {
|
||||||
pub fn alloc(basek: usize, k: usize) -> Self {
|
pub fn alloc(basek: usize, k: usize) -> Self {
|
||||||
Self {
|
Self {
|
||||||
data: VecZnx::new::<i64>(1, 1, k.div_ceil(basek)),
|
data: VecZnx::alloc::<i64>(1, 1, k.div_ceil(basek)),
|
||||||
k: k,
|
k: k,
|
||||||
basek: basek,
|
basek: basek,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ pub struct LWESecret<D: Data> {
|
|||||||
impl LWESecret<Vec<u8>> {
|
impl LWESecret<Vec<u8>> {
|
||||||
pub fn alloc(n: usize) -> Self {
|
pub fn alloc(n: usize) -> Self {
|
||||||
Self {
|
Self {
|
||||||
data: ScalarZnx::new(n, 1),
|
data: ScalarZnx::alloc(n, 1),
|
||||||
dist: Distribution::NONE,
|
dist: Distribution::NONE,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,11 +14,10 @@ impl Source {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn branch(&mut self) -> Self {
|
pub fn branch(&mut self) -> ([u8; 32], Self) {
|
||||||
let mut seed = [0; 32];
|
let mut seed = [0; 32];
|
||||||
self.source.fill_bytes(&mut seed);
|
self.source.fill_bytes(&mut seed);
|
||||||
|
(seed, Source::new(seed))
|
||||||
Source::new(seed)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
|||||||
Reference in New Issue
Block a user