Examples, benchmarks, and minor changes for consistency, in BDD API

This commit is contained in:
Rasoul Akhavan Mahdavi
2025-12-01 00:41:31 -05:00
parent 0ce56938fc
commit 48407ccefc
16 changed files with 1364 additions and 54 deletions

View File

@@ -25,4 +25,12 @@ paste = "1.0.15"
[[bench]] [[bench]]
name = "circuit_bootstrapping" name = "circuit_bootstrapping"
harness = false
[[bench]]
name = "bdd_prepare"
harness = false
[[bench]]
name = "bdd_arithmetic"
harness = false harness = false

View File

@@ -9,7 +9,7 @@ See [./examples/circuit_bootstrapping.rs](./examples/circuit_bootstrapping.rs)
## Available Schemes ## Available Schemes
- **BIN FHE**: - **BIN FHE**:
- **bdd_arithmetic**: high level API for u32 arithmetic (u8 to u256 planned) using binary decision circuits. Also provides API for blind retrieval, blind rotation (using encpypted integers) and blind selection. - **bdd_arithmetic**: high level API for u32 arithmetic (u8 to u256 planned) using binary decision circuits. Also provides API for blind retrieval, blind rotation (using encrypted integers) and blind selection.
- **blind_rotation**: API for blind rotation (LWE(m) -> GLWE(X^m)) - **blind_rotation**: API for blind rotation (LWE(m) -> GLWE(X^m))
- **circuit_bootstrapping**: API for circuit bootstrapping (LWE(m) -> GGSW(m) or GGSW(X^m)). - **circuit_bootstrapping**: API for circuit bootstrapping (LWE(m) -> GGSW(m) or GGSW(X^m)).
- **CKKS**: planned - **CKKS**: planned

View File

@@ -0,0 +1,454 @@
use std::hint::black_box;
use criterion::{BenchmarkId, Criterion, criterion_group, criterion_main};
use poulpy_core::{
GGSWNoise, GLWEDecrypt, GLWEEncryptSk, GLWEExternalProduct, LWEEncryptSk, ScratchTakeCore,
layouts::{
Base2K, Degree, Dnum, Dsize, GGLWEToGGSWKeyLayout, GGSWLayout, GGSWPreparedFactory, GLWEAutomorphismKeyLayout,
GLWELayout, GLWESecret, GLWESecretPrepared, GLWESecretPreparedFactory, GLWESwitchingKeyLayout, GLWEToLWEKeyLayout,
LWESecret, Rank, TorusPrecision,
},
};
#[cfg(all(feature = "enable-avx", target_arch = "x86_64"))]
pub use poulpy_cpu_avx::FFT64Avx as BackendImpl;
#[cfg(not(all(feature = "enable-avx", target_arch = "x86_64")))]
pub use poulpy_cpu_ref::FFT64Ref as BackendImpl;
use poulpy_hal::{
api::{ModuleN, ModuleNew, ScratchOwnedAlloc, ScratchOwnedBorrow, VecZnxRotateInplace},
layouts::{Backend, Module, Scratch, ScratchOwned},
source::Source,
};
use poulpy_schemes::bin_fhe::{
bdd_arithmetic::{
Add, And, BDDKey, BDDKeyEncryptSk, BDDKeyLayout, BDDKeyPrepared, BDDKeyPreparedFactory, ExecuteBDDCircuit2WTo1W, FheUint,
FheUintPrepare, FheUintPrepared, Or, Sll, Slt, Sltu, Sra, Srl, Sub, Xor,
},
blind_rotation::{
BlindRotationAlgo, BlindRotationKey, BlindRotationKeyFactory, BlindRotationKeyInfos, BlindRotationKeyLayout, CGGI,
},
circuit_bootstrapping::{
CircuitBootstrappingKey, CircuitBootstrappingKeyEncryptSk, CircuitBootstrappingKeyLayout,
CircuitBootstrappingKeyPrepared, CircuitBootstrappingKeyPreparedFactory, CirtuitBootstrappingExecute,
},
};
// Common setup data structure
struct BenchmarkSetup<BE: Backend, BRA: BlindRotationAlgo> {
module: Module<BE>,
scratch: ScratchOwned<BE>,
a_enc_prepared: FheUintPrepared<Vec<u8>, u32, BE>,
b_enc_prepared: FheUintPrepared<Vec<u8>, u32, BE>,
bdd_key_prepared: BDDKeyPrepared<Vec<u8>, BRA, BE>,
glwe_layout: GLWELayout,
}
struct Params {
name: String,
block_size: usize,
glwe_layout: GLWELayout,
ggsw_layout: GGSWLayout,
bdd_layout: BDDKeyLayout,
}
fn setup_benchmark<BE: Backend, BRA: BlindRotationAlgo>(params: &Params) -> BenchmarkSetup<BE, BRA>
where
Module<BE>: ModuleNew<BE>
+ ModuleN
+ GLWESecretPreparedFactory<BE>
+ GLWEExternalProduct<BE>
+ GLWEDecrypt<BE>
+ LWEEncryptSk<BE>
+ CircuitBootstrappingKeyEncryptSk<BRA, BE>
+ CircuitBootstrappingKeyPreparedFactory<BRA, BE>
+ CirtuitBootstrappingExecute<BRA, BE>
+ GGSWPreparedFactory<BE>
+ GGSWNoise<BE>
+ GLWEEncryptSk<BE>
+ VecZnxRotateInplace<BE>
+ BDDKeyEncryptSk<BRA, BE>
+ BDDKeyPreparedFactory<BRA, BE>
+ FheUintPrepare<BRA, BE>
+ ExecuteBDDCircuit2WTo1W<BE>,
BlindRotationKey<Vec<u8>, BRA>: BlindRotationKeyFactory<BRA>,
ScratchOwned<BE>: ScratchOwnedAlloc<BE> + ScratchOwnedBorrow<BE>,
Scratch<BE>: ScratchTakeCore<BE>,
{
// Scratch space (16MB)
let mut scratch: ScratchOwned<BE> = ScratchOwned::alloc(1 << 24);
let n_glwe: poulpy_core::layouts::Degree = params.bdd_layout.cbt_layout.brk_layout.n_glwe();
let n_lwe: poulpy_core::layouts::Degree = params.bdd_layout.cbt_layout.brk_layout.n_lwe();
let rank: poulpy_core::layouts::Rank = params.bdd_layout.cbt_layout.brk_layout.rank;
let module: Module<BE> = Module::<BE>::new(n_glwe.as_u32() as u64);
let mut source_xs: Source = Source::new([1u8; 32]);
let mut source_xa: Source = Source::new([1u8; 32]);
let mut source_xe: Source = Source::new([1u8; 32]);
let mut sk_lwe: LWESecret<Vec<u8>> = LWESecret::alloc(n_lwe);
sk_lwe.fill_binary_block(params.block_size, &mut source_xs);
let mut sk_glwe: GLWESecret<Vec<u8>> = GLWESecret::alloc(n_glwe, rank);
sk_glwe.fill_ternary_prob(0.5, &mut source_xs);
// Circuit bootstrapping evaluation key
let mut cbt_key: CircuitBootstrappingKey<Vec<u8>, BRA> =
CircuitBootstrappingKey::alloc_from_infos(&params.bdd_layout.cbt_layout);
cbt_key.encrypt_sk(
&module,
&sk_lwe,
&sk_glwe,
&mut source_xa,
&mut source_xe,
scratch.borrow(),
);
let mut cbt_key_prepared: CircuitBootstrappingKeyPrepared<Vec<u8>, BRA, BE> =
CircuitBootstrappingKeyPrepared::alloc_from_infos(&module, &params.bdd_layout.cbt_layout);
cbt_key_prepared.prepare(&module, &cbt_key, scratch.borrow());
let mut sk_glwe_prepared = GLWESecretPrepared::alloc_from_infos(&module, &params.glwe_layout);
sk_glwe_prepared.prepare(&module, &sk_glwe);
let mut bdd_key: BDDKey<Vec<u8>, BRA> = BDDKey::alloc_from_infos(&params.bdd_layout);
bdd_key.encrypt_sk(
&module,
&sk_lwe,
&sk_glwe,
&mut source_xa,
&mut source_xe,
scratch.borrow(),
);
let input_a = 255_u32;
let input_b = 30_u32;
let mut a_enc: FheUint<Vec<u8>, u32> = FheUint::alloc_from_infos(&params.glwe_layout);
a_enc.encrypt_sk(
&module,
input_a,
&sk_glwe_prepared,
&mut source_xa,
&mut source_xe,
scratch.borrow(),
);
let mut b_enc: FheUint<Vec<u8>, u32> = FheUint::alloc_from_infos(&params.glwe_layout);
b_enc.encrypt_sk(
&module,
input_b,
&sk_glwe_prepared,
&mut source_xa,
&mut source_xe,
scratch.borrow(),
);
//////// Homomorphic computation starts here ////////
// Preparing the BDD Key
// The BDD key must be prepared once before any operation is performed
let mut bdd_key_prepared: BDDKeyPrepared<Vec<u8>, BRA, BE> = BDDKeyPrepared::alloc_from_infos(&module, &params.bdd_layout);
bdd_key_prepared.prepare(&module, &bdd_key, scratch.borrow());
// Input Preparation
// Before each operation, the inputs to that operation must be prepared
// Preparation extracts each bit of the integer into a seperate GLWE ciphertext and bootstraps it into a GGSW ciphertext
let mut a_enc_prepared: FheUintPrepared<Vec<u8>, u32, BE> = FheUintPrepared::alloc_from_infos(&module, &params.ggsw_layout);
a_enc_prepared.prepare(&module, &a_enc, &bdd_key_prepared, scratch.borrow());
let mut b_enc_prepared: FheUintPrepared<Vec<u8>, u32, BE> = FheUintPrepared::alloc_from_infos(&module, &params.ggsw_layout);
b_enc_prepared.prepare(&module, &b_enc, &bdd_key_prepared, scratch.borrow());
BenchmarkSetup {
module,
scratch,
a_enc_prepared,
b_enc_prepared,
bdd_key_prepared,
glwe_layout: params.glwe_layout.clone(),
}
}
fn create_runner<BE: Backend, BRA: BlindRotationAlgo, F>(setup: BenchmarkSetup<BE, BRA>, operation: F) -> impl FnMut()
where
Module<BE>: ExecuteBDDCircuit2WTo1W<BE>,
Scratch<BE>: ScratchTakeCore<BE>,
ScratchOwned<BE>: ScratchOwnedBorrow<BE>,
F: Fn(
&mut FheUint<Vec<u8>, u32>,
&Module<BE>,
&FheUintPrepared<Vec<u8>, u32, BE>,
&FheUintPrepared<Vec<u8>, u32, BE>,
&BDDKeyPrepared<Vec<u8>, BRA, BE>,
&mut Scratch<BE>,
),
{
let BenchmarkSetup {
module,
mut scratch,
a_enc_prepared,
b_enc_prepared,
bdd_key_prepared,
glwe_layout,
} = setup;
let mut c_enc: FheUint<Vec<u8>, u32> = FheUint::alloc_from_infos(&glwe_layout);
move || {
operation(
&mut c_enc,
&module,
&a_enc_prepared,
&b_enc_prepared,
&bdd_key_prepared,
scratch.borrow(),
);
black_box(());
}
}
fn bench_operation<BE: Backend, BRA: BlindRotationAlgo, F>(
group: &mut criterion::BenchmarkGroup<'_, criterion::measurement::WallTime>,
params: &Params,
operation_name: &str,
operation: F,
) where
Module<BE>: ModuleNew<BE>
+ ModuleN
+ GLWESecretPreparedFactory<BE>
+ GLWEExternalProduct<BE>
+ GLWEDecrypt<BE>
+ LWEEncryptSk<BE>
+ CircuitBootstrappingKeyEncryptSk<BRA, BE>
+ CircuitBootstrappingKeyPreparedFactory<BRA, BE>
+ CirtuitBootstrappingExecute<BRA, BE>
+ GGSWPreparedFactory<BE>
+ GGSWNoise<BE>
+ GLWEEncryptSk<BE>
+ VecZnxRotateInplace<BE>
+ BDDKeyEncryptSk<BRA, BE>
+ BDDKeyPreparedFactory<BRA, BE>
+ FheUintPrepare<BRA, BE>
+ ExecuteBDDCircuit2WTo1W<BE>,
BlindRotationKey<Vec<u8>, BRA>: BlindRotationKeyFactory<BRA>,
ScratchOwned<BE>: ScratchOwnedAlloc<BE> + ScratchOwnedBorrow<BE>,
Scratch<BE>: ScratchTakeCore<BE>,
F: Fn(
&mut FheUint<Vec<u8>, u32>,
&Module<BE>,
&FheUintPrepared<Vec<u8>, u32, BE>,
&FheUintPrepared<Vec<u8>, u32, BE>,
&BDDKeyPrepared<Vec<u8>, BRA, BE>,
&mut Scratch<BE>,
) + 'static,
{
let setup = setup_benchmark::<BE, BRA>(params);
let mut runner = create_runner(setup, operation);
let id = BenchmarkId::from_parameter(format!("{}_{}", params.name, operation_name));
group.bench_with_input(id, &(), |b, _| b.iter(&mut runner));
}
pub fn benc_bdd_arithmetic<BE: Backend, BRA: BlindRotationAlgo>(c: &mut Criterion, label: &str)
where
Module<BE>: ModuleNew<BE>
+ ModuleN
+ GLWESecretPreparedFactory<BE>
+ GLWEExternalProduct<BE>
+ GLWEDecrypt<BE>
+ LWEEncryptSk<BE>
+ CircuitBootstrappingKeyEncryptSk<BRA, BE>
+ CircuitBootstrappingKeyPreparedFactory<BRA, BE>
+ CirtuitBootstrappingExecute<BRA, BE>
+ GGSWPreparedFactory<BE>
+ GGSWNoise<BE>
+ GLWEEncryptSk<BE>
+ VecZnxRotateInplace<BE>
+ BDDKeyEncryptSk<BRA, BE>
+ BDDKeyPreparedFactory<BRA, BE>
+ FheUintPrepare<BRA, BE>
+ ExecuteBDDCircuit2WTo1W<BE>,
BlindRotationKey<Vec<u8>, BRA>: BlindRotationKeyFactory<BRA>, // TODO find a way to remove this bound or move it to CBT KEY
ScratchOwned<BE>: ScratchOwnedAlloc<BE> + ScratchOwnedBorrow<BE>,
Scratch<BE>: ScratchTakeCore<BE>,
{
let group_name: String = format!("bdd_arithmetic::{label}");
let mut group = c.benchmark_group(group_name);
const N_GLWE: u32 = 1024;
const N_LWE: u32 = 679;
const BINARY_BLOCK_SIZE: u32 = 7;
const BASE2K: u32 = 15;
const RANK: u32 = 2;
let params: Params = Params {
name: String::from(format!("n_glwe={N_GLWE}")),
block_size: BINARY_BLOCK_SIZE as usize,
glwe_layout: GLWELayout {
n: Degree(N_GLWE),
base2k: Base2K(BASE2K),
k: TorusPrecision(2 * BASE2K),
rank: Rank(RANK),
},
ggsw_layout: GGSWLayout {
n: Degree(N_GLWE),
base2k: Base2K(BASE2K),
k: TorusPrecision(3 * BASE2K),
rank: Rank(RANK),
dnum: Dnum(3),
dsize: Dsize(1),
},
bdd_layout: BDDKeyLayout {
cbt_layout: CircuitBootstrappingKeyLayout {
brk_layout: BlindRotationKeyLayout {
n_glwe: Degree(N_GLWE),
n_lwe: Degree(N_LWE),
base2k: Base2K(BASE2K),
k: TorusPrecision(4 * BASE2K),
dnum: Dnum(4),
rank: Rank(RANK),
},
atk_layout: GLWEAutomorphismKeyLayout {
n: Degree(N_GLWE),
base2k: Base2K(BASE2K),
k: TorusPrecision(4 * BASE2K),
dnum: Dnum(4),
dsize: Dsize(1),
rank: Rank(RANK),
},
tsk_layout: GGLWEToGGSWKeyLayout {
n: Degree(N_GLWE),
base2k: Base2K(BASE2K),
k: TorusPrecision(4 * BASE2K),
dnum: Dnum(4),
dsize: Dsize(1),
rank: Rank(RANK),
},
},
ks_glwe_layout: Some(GLWESwitchingKeyLayout {
n: Degree(N_GLWE),
base2k: Base2K(BASE2K),
k: TorusPrecision(4 * BASE2K),
dnum: Dnum(4),
dsize: Dsize(1),
rank_in: Rank(RANK),
rank_out: Rank(1),
}),
ks_lwe_layout: GLWEToLWEKeyLayout {
n: Degree(N_GLWE),
base2k: Base2K(BASE2K),
k: TorusPrecision(4 * BASE2K),
rank_in: Rank(1),
dnum: Dnum(4),
},
},
};
// Benchmark each operation
bench_operation::<BE, BRA, _>(
&mut group,
&params,
"add",
|c_enc, module, a, b, key, scratch| {
c_enc.add(module, a, b, key, scratch);
},
);
bench_operation::<BE, BRA, _>(
&mut group,
&params,
"sub",
|c_enc, module, a, b, key, scratch| {
c_enc.sub(module, a, b, key, scratch);
},
);
bench_operation::<BE, BRA, _>(
&mut group,
&params,
"sll",
|c_enc, module, a, b, key, scratch| {
c_enc.sll(module, a, b, key, scratch);
},
);
bench_operation::<BE, BRA, _>(
&mut group,
&params,
"sra",
|c_enc, module, a, b, key, scratch| {
c_enc.sra(module, a, b, key, scratch);
},
);
bench_operation::<BE, BRA, _>(
&mut group,
&params,
"srl",
|c_enc, module, a, b, key, scratch| {
c_enc.srl(module, a, b, key, scratch);
},
);
bench_operation::<BE, BRA, _>(
&mut group,
&params,
"slt",
|c_enc, module, a, b, key, scratch| {
c_enc.slt(module, a, b, key, scratch);
},
);
bench_operation::<BE, BRA, _>(
&mut group,
&params,
"sltu",
|c_enc, module, a, b, key, scratch| {
c_enc.sltu(module, a, b, key, scratch);
},
);
bench_operation::<BE, BRA, _>(
&mut group,
&params,
"or",
|c_enc, module, a, b, key, scratch| {
c_enc.or(module, a, b, key, scratch);
},
);
bench_operation::<BE, BRA, _>(
&mut group,
&params,
"and",
|c_enc, module, a, b, key, scratch| {
c_enc.and(module, a, b, key, scratch);
},
);
bench_operation::<BE, BRA, _>(
&mut group,
&params,
"xor",
|c_enc, module, a, b, key, scratch| {
c_enc.xor(module, a, b, key, scratch);
},
);
group.finish();
}
fn bench_bdd_arithmetic_fft64(c: &mut Criterion) {
#[cfg(all(feature = "enable-avx", target_arch = "x86_64"))]
let label = "fft64_avx";
#[cfg(not(all(feature = "enable-avx", target_arch = "x86_64")))]
let label = "fft64_ref";
benc_bdd_arithmetic::<BackendImpl, CGGI>(c, label);
}
criterion_group!(benches, bench_bdd_arithmetic_fft64);
criterion_main!(benches);

View File

@@ -0,0 +1,238 @@
use std::hint::black_box;
use criterion::{BenchmarkId, Criterion, criterion_group, criterion_main};
use poulpy_core::{
GGSWNoise, GLWEDecrypt, GLWEEncryptSk, GLWEExternalProduct, LWEEncryptSk, ScratchTakeCore,
layouts::{
Base2K, Degree, Dnum, Dsize, GGLWEToGGSWKeyLayout, GGSWLayout, GGSWPreparedFactory, GLWEAutomorphismKeyLayout,
GLWELayout, GLWESecret, GLWESecretPrepared, GLWESecretPreparedFactory, GLWESwitchingKeyLayout, GLWEToLWEKeyLayout,
LWESecret, Rank, TorusPrecision,
},
};
#[cfg(all(feature = "enable-avx", target_arch = "x86_64"))]
pub use poulpy_cpu_avx::FFT64Avx as BackendImpl;
#[cfg(not(all(feature = "enable-avx", target_arch = "x86_64")))]
pub use poulpy_cpu_ref::FFT64Ref as BackendImpl;
use poulpy_hal::{
api::{ModuleN, ModuleNew, ScratchOwnedAlloc, ScratchOwnedBorrow, VecZnxRotateInplace},
layouts::{Backend, Module, Scratch, ScratchOwned},
source::Source,
};
use poulpy_schemes::bin_fhe::{
bdd_arithmetic::{
BDDKey, BDDKeyEncryptSk, BDDKeyLayout, BDDKeyPrepared, BDDKeyPreparedFactory, ExecuteBDDCircuit2WTo1W, FheUint,
FheUintPrepare, FheUintPrepared,
},
blind_rotation::{
BlindRotationAlgo, BlindRotationKey, BlindRotationKeyFactory, BlindRotationKeyInfos, BlindRotationKeyLayout, CGGI,
},
circuit_bootstrapping::{
CircuitBootstrappingKeyEncryptSk, CircuitBootstrappingKeyLayout, CircuitBootstrappingKeyPreparedFactory,
CirtuitBootstrappingExecute,
},
};
pub fn benc_bdd_prepare<BE: Backend, BRA: BlindRotationAlgo>(c: &mut Criterion, label: &str)
where
Module<BE>: ModuleNew<BE>
+ ModuleN
+ GLWESecretPreparedFactory<BE>
+ GLWEExternalProduct<BE>
+ GLWEDecrypt<BE>
+ LWEEncryptSk<BE>
+ CircuitBootstrappingKeyEncryptSk<BRA, BE>
+ CircuitBootstrappingKeyPreparedFactory<BRA, BE>
+ CirtuitBootstrappingExecute<BRA, BE>
+ GGSWPreparedFactory<BE>
+ GGSWNoise<BE>
+ GLWEEncryptSk<BE>
+ VecZnxRotateInplace<BE>
+ BDDKeyEncryptSk<BRA, BE>
+ BDDKeyPreparedFactory<BRA, BE>
+ FheUintPrepare<BRA, BE>
+ ExecuteBDDCircuit2WTo1W<BE>,
BlindRotationKey<Vec<u8>, BRA>: BlindRotationKeyFactory<BRA>, // TODO find a way to remove this bound or move it to CBT KEY
ScratchOwned<BE>: ScratchOwnedAlloc<BE> + ScratchOwnedBorrow<BE>,
Scratch<BE>: ScratchTakeCore<BE>,
{
let group_name: String = format!("bdd_arithmetic::{label}");
let mut group = c.benchmark_group(group_name);
struct Params {
name: String,
block_size: usize,
glwe_layout: GLWELayout,
ggsw_layout: GGSWLayout,
bdd_layout: BDDKeyLayout,
}
fn runner<BE: Backend, BRA: BlindRotationAlgo>(params: &Params) -> impl FnMut()
where
Module<BE>: ModuleNew<BE>
+ ModuleN
+ GLWESecretPreparedFactory<BE>
+ GLWEExternalProduct<BE>
+ GLWEDecrypt<BE>
+ LWEEncryptSk<BE>
+ CircuitBootstrappingKeyEncryptSk<BRA, BE>
+ CircuitBootstrappingKeyPreparedFactory<BRA, BE>
+ CirtuitBootstrappingExecute<BRA, BE>
+ GGSWPreparedFactory<BE>
+ GGSWNoise<BE>
+ GLWEEncryptSk<BE>
+ VecZnxRotateInplace<BE>
+ BDDKeyEncryptSk<BRA, BE>
+ BDDKeyPreparedFactory<BRA, BE>
+ FheUintPrepare<BRA, BE>
+ ExecuteBDDCircuit2WTo1W<BE>,
BlindRotationKey<Vec<u8>, BRA>: BlindRotationKeyFactory<BRA>, /* TODO find a way to remove this bound or move it to CBT KEY */
ScratchOwned<BE>: ScratchOwnedAlloc<BE> + ScratchOwnedBorrow<BE>,
Scratch<BE>: ScratchTakeCore<BE>,
{
// Scratch space (4MB)
let mut scratch: ScratchOwned<BE> = ScratchOwned::alloc(1 << 25);
let n_glwe: poulpy_core::layouts::Degree = params.bdd_layout.cbt_layout.brk_layout.n_glwe();
let n_lwe: poulpy_core::layouts::Degree = params.bdd_layout.cbt_layout.brk_layout.n_lwe();
let rank: poulpy_core::layouts::Rank = params.bdd_layout.cbt_layout.brk_layout.rank;
let module: Module<BE> = Module::<BE>::new(n_glwe.as_u32() as u64);
let mut source_xs: Source = Source::new([1u8; 32]);
let mut source_xa: Source = Source::new([1u8; 32]);
let mut source_xe: Source = Source::new([1u8; 32]);
let mut sk_lwe: LWESecret<Vec<u8>> = LWESecret::alloc(n_lwe);
sk_lwe.fill_binary_block(params.block_size, &mut source_xs);
let mut sk_glwe: GLWESecret<Vec<u8>> = GLWESecret::alloc(n_glwe, rank);
sk_glwe.fill_ternary_prob(0.5, &mut source_xs);
let mut sk_glwe_prepared = GLWESecretPrepared::alloc_from_infos(&module, &params.glwe_layout);
sk_glwe_prepared.prepare(&module, &sk_glwe);
let mut bdd_key: BDDKey<Vec<u8>, BRA> = BDDKey::alloc_from_infos(&params.bdd_layout);
bdd_key.encrypt_sk(
&module,
&sk_lwe,
&sk_glwe,
&mut source_xa,
&mut source_xe,
scratch.borrow(),
);
let input_a = 255_u32;
let mut a_enc: FheUint<Vec<u8>, u32> = FheUint::alloc_from_infos(&params.glwe_layout);
a_enc.encrypt_sk(
&module,
input_a,
&sk_glwe_prepared,
&mut source_xa,
&mut source_xe,
scratch.borrow(),
);
let mut bdd_key_prepared: BDDKeyPrepared<Vec<u8>, BRA, BE> =
BDDKeyPrepared::alloc_from_infos(&module, &params.bdd_layout);
bdd_key_prepared.prepare(&module, &bdd_key, scratch.borrow());
let mut a_enc_prepared: FheUintPrepared<Vec<u8>, u32, BE> =
FheUintPrepared::alloc_from_infos(&module, &params.ggsw_layout);
move || {
a_enc_prepared.prepare(&module, &a_enc, &bdd_key_prepared, scratch.borrow());
black_box(());
}
}
const N_GLWE: u32 = 1024;
const N_LWE: u32 = 679;
const BINARY_BLOCK_SIZE: u32 = 7;
const BASE2K: u32 = 15;
const RANK: u32 = 2;
let params: Params = Params {
name: String::from(format!("n_glwe={N_GLWE}")),
block_size: BINARY_BLOCK_SIZE as usize,
glwe_layout: GLWELayout {
n: Degree(N_GLWE),
base2k: Base2K(BASE2K),
k: TorusPrecision(2 * BASE2K),
rank: Rank(RANK),
},
ggsw_layout: GGSWLayout {
n: Degree(N_GLWE),
base2k: Base2K(BASE2K),
k: TorusPrecision(3 * BASE2K),
rank: Rank(RANK),
dnum: Dnum(3),
dsize: Dsize(1),
},
bdd_layout: BDDKeyLayout {
cbt_layout: CircuitBootstrappingKeyLayout {
brk_layout: BlindRotationKeyLayout {
n_glwe: Degree(N_GLWE),
n_lwe: Degree(N_LWE),
base2k: Base2K(BASE2K),
k: TorusPrecision(4 * BASE2K),
dnum: Dnum(4),
rank: Rank(RANK),
},
atk_layout: GLWEAutomorphismKeyLayout {
n: Degree(N_GLWE),
base2k: Base2K(BASE2K),
k: TorusPrecision(4 * BASE2K),
dnum: Dnum(4),
dsize: Dsize(1),
rank: Rank(RANK),
},
tsk_layout: GGLWEToGGSWKeyLayout {
n: Degree(N_GLWE),
base2k: Base2K(BASE2K),
k: TorusPrecision(4 * BASE2K),
dnum: Dnum(4),
dsize: Dsize(1),
rank: Rank(RANK),
},
},
ks_glwe_layout: Some(GLWESwitchingKeyLayout {
n: Degree(N_GLWE),
base2k: Base2K(BASE2K),
k: TorusPrecision(4 * BASE2K),
dnum: Dnum(4),
dsize: Dsize(1),
rank_in: Rank(RANK),
rank_out: Rank(1),
}),
ks_lwe_layout: GLWEToLWEKeyLayout {
n: Degree(N_GLWE),
base2k: Base2K(BASE2K),
k: TorusPrecision(4 * BASE2K),
rank_in: Rank(1),
dnum: Dnum(4),
},
},
};
let id: BenchmarkId = BenchmarkId::from_parameter(params.name.clone());
let mut runner = runner::<BE, BRA>(&params);
group.bench_with_input(id, &(), |b, _| b.iter(&mut runner));
group.finish();
}
fn bench_bdd_prepare_fft64(c: &mut Criterion) {
#[cfg(all(feature = "enable-avx", target_arch = "x86_64"))]
let label = "fft64_avx";
#[cfg(not(all(feature = "enable-avx", target_arch = "x86_64")))]
let label = "fft64_ref";
benc_bdd_prepare::<BackendImpl, CGGI>(c, label);
}
criterion_group!(benches, bench_bdd_prepare_fft64);
criterion_main!(benches);

View File

@@ -85,9 +85,9 @@ where
// Scratch space (4MB) // Scratch space (4MB)
let mut scratch: ScratchOwned<BE> = ScratchOwned::alloc(1 << 22); let mut scratch: ScratchOwned<BE> = ScratchOwned::alloc(1 << 22);
let n_glwe: poulpy_core::layouts::Degree = params.cbt_infos.layout_brk.n_glwe(); let n_glwe: poulpy_core::layouts::Degree = params.cbt_infos.brk_layout.n_glwe();
let n_lwe: poulpy_core::layouts::Degree = params.cbt_infos.layout_brk.n_lwe(); let n_lwe: poulpy_core::layouts::Degree = params.cbt_infos.brk_layout.n_lwe();
let rank: poulpy_core::layouts::Rank = params.cbt_infos.layout_brk.rank; let rank: poulpy_core::layouts::Rank = params.cbt_infos.brk_layout.rank;
let module: Module<BE> = Module::<BE>::new(n_glwe.as_u32() as u64); let module: Module<BE> = Module::<BE>::new(n_glwe.as_u32() as u64);
@@ -97,7 +97,6 @@ where
let mut sk_lwe: LWESecret<Vec<u8>> = LWESecret::alloc(n_lwe); let mut sk_lwe: LWESecret<Vec<u8>> = LWESecret::alloc(n_lwe);
sk_lwe.fill_binary_block(params.block_size, &mut source_xs); sk_lwe.fill_binary_block(params.block_size, &mut source_xs);
sk_lwe.fill_zero();
let mut sk_glwe: GLWESecret<Vec<u8>> = GLWESecret::alloc(n_glwe, rank); let mut sk_glwe: GLWESecret<Vec<u8>> = GLWESecret::alloc(n_glwe, rank);
sk_glwe.fill_ternary_prob(0.5, &mut source_xs); sk_glwe.fill_ternary_prob(0.5, &mut source_xs);
@@ -151,7 +150,7 @@ where
rank: 2_u32.into(), rank: 2_u32.into(),
}, },
cbt_infos: CircuitBootstrappingKeyLayout { cbt_infos: CircuitBootstrappingKeyLayout {
layout_brk: BlindRotationKeyLayout { brk_layout: BlindRotationKeyLayout {
n_glwe: 1024_u32.into(), n_glwe: 1024_u32.into(),
n_lwe: 574_u32.into(), n_lwe: 574_u32.into(),
base2k: 13_u32.into(), base2k: 13_u32.into(),
@@ -159,7 +158,7 @@ where
dnum: 3_u32.into(), dnum: 3_u32.into(),
rank: 2_u32.into(), rank: 2_u32.into(),
}, },
layout_atk: GLWEAutomorphismKeyLayout { atk_layout: GLWEAutomorphismKeyLayout {
n: 1024_u32.into(), n: 1024_u32.into(),
base2k: 13_u32.into(), base2k: 13_u32.into(),
k: 52_u32.into(), k: 52_u32.into(),
@@ -167,7 +166,7 @@ where
dsize: Dsize(1), dsize: Dsize(1),
rank: 2_u32.into(), rank: 2_u32.into(),
}, },
layout_tsk: GGLWEToGGSWKeyLayout { tsk_layout: GGLWEToGGSWKeyLayout {
n: 1024_u32.into(), n: 1024_u32.into(),
base2k: 13_u32.into(), base2k: 13_u32.into(),
k: 52_u32.into(), k: 52_u32.into(),

View File

@@ -0,0 +1,332 @@
use std::collections::HashMap;
use poulpy_core::{
GLWEDecrypt, GLWEEncryptSk, GLWEExternalProduct, LWEEncryptSk, ScratchTakeCore,
layouts::{
Base2K, Degree, Dnum, Dsize, GGLWEToGGSWKeyLayout, GGSWLayout, GGSWPreparedFactory, GLWEAutomorphismKeyLayout,
GLWELayout, GLWESecret, GLWESecretPrepared, GLWESecretPreparedFactory, GLWESwitchingKeyLayout, GLWEToLWEKeyLayout,
LWESecret, Rank, TorusPrecision,
},
};
use poulpy_hal::{
api::{ModuleN, ModuleNew, ScratchOwnedAlloc, ScratchOwnedBorrow, VecZnxRotateInplace},
layouts::{Backend, Module, Scratch, ScratchOwned},
source::Source,
};
use poulpy_schemes::bin_fhe::{
bdd_arithmetic::{
Add, BDDKey, BDDKeyEncryptSk, BDDKeyLayout, BDDKeyPrepared, BDDKeyPreparedFactory, ExecuteBDDCircuit2WTo1W, FheUint,
FheUintPrepare, FheUintPrepared, GLWEBlindSelection, Xor,
},
blind_rotation::{BlindRotationAlgo, BlindRotationKey, BlindRotationKeyFactory, BlindRotationKeyLayout, CGGI},
circuit_bootstrapping::CircuitBootstrappingKeyLayout,
};
use rand::Rng;
#[cfg(all(feature = "enable-avx", target_arch = "x86_64"))]
use poulpy_cpu_avx::FFT64Avx;
#[cfg(not(all(feature = "enable-avx", target_arch = "x86_64")))]
use poulpy_cpu_ref::FFT64Ref;
// This example demonstrates and end-to-end example usage of the BDD arithmetic API
// It includes all steps including:
//
// - Parameter Selection
// - Key Generation
// - Input Encryption
//
// - Key preparation
// - Input Preparation
// - Operation Execution
//
// - Result Decryption
//
fn example_bdd_arithmetic<BE: Backend, BRA: BlindRotationAlgo>()
where
Module<BE>: ModuleNew<BE>
+ ModuleN
+ GLWESecretPreparedFactory<BE>
+ GLWEExternalProduct<BE>
+ GLWEDecrypt<BE>
+ LWEEncryptSk<BE>
+ GGSWPreparedFactory<BE>
+ GLWEEncryptSk<BE>
+ VecZnxRotateInplace<BE>
+ BDDKeyEncryptSk<BRA, BE>
+ BDDKeyPreparedFactory<BRA, BE>
+ FheUintPrepare<BRA, BE>
+ ExecuteBDDCircuit2WTo1W<BE>
+ GLWEBlindSelection<u32, BE>,
BlindRotationKey<Vec<u8>, BRA>: BlindRotationKeyFactory<BRA>, // TODO find a way to remove this bound or move it to CBT KEY
ScratchOwned<BE>: ScratchOwnedAlloc<BE> + ScratchOwnedBorrow<BE>,
Scratch<BE>: ScratchTakeCore<BE>,
{
////////// Parameter Selection
const N_GLWE: u32 = 1024;
const N_LWE: u32 = 567;
const BINARY_BLOCK_SIZE: u32 = 7;
const BASE2K: u32 = 17;
const RANK: u32 = 1;
// GLWE layout, used to generate GLWE Ciphertexts, keys, switching keys, etc
let glwe_layout = GLWELayout {
n: Degree(N_GLWE),
base2k: Base2K(BASE2K),
k: TorusPrecision(2 * BASE2K),
rank: Rank(RANK),
};
// Used to generate GGSW Ciphertexts
let ggsw_layout = GGSWLayout {
n: Degree(N_GLWE),
base2k: Base2K(BASE2K),
k: TorusPrecision(3 * BASE2K),
rank: Rank(RANK),
dnum: Dnum(3),
dsize: Dsize(1),
};
// Used to generate BDD Keys, for the arithmetic operations
let bdd_layout = BDDKeyLayout {
cbt_layout: CircuitBootstrappingKeyLayout {
brk_layout: BlindRotationKeyLayout {
n_glwe: Degree(N_GLWE),
n_lwe: Degree(N_LWE),
base2k: Base2K(BASE2K),
k: TorusPrecision(4 * BASE2K),
dnum: Dnum(4),
rank: Rank(RANK),
},
atk_layout: GLWEAutomorphismKeyLayout {
n: Degree(N_GLWE),
base2k: Base2K(BASE2K),
k: TorusPrecision(4 * BASE2K),
dnum: Dnum(4),
dsize: Dsize(1),
rank: Rank(RANK),
},
tsk_layout: GGLWEToGGSWKeyLayout {
n: Degree(N_GLWE),
base2k: Base2K(BASE2K),
k: TorusPrecision(4 * BASE2K),
dnum: Dnum(4),
dsize: Dsize(1),
rank: Rank(RANK),
},
},
ks_glwe_layout: Some(GLWESwitchingKeyLayout {
n: Degree(N_GLWE),
base2k: Base2K(BASE2K),
k: TorusPrecision(4 * BASE2K),
dnum: Dnum(4),
dsize: Dsize(1),
rank_in: Rank(RANK),
rank_out: Rank(1),
}),
ks_lwe_layout: GLWEToLWEKeyLayout {
n: Degree(N_GLWE),
base2k: Base2K(BASE2K),
k: TorusPrecision(4 * BASE2K),
rank_in: Rank(1),
dnum: Dnum(4),
},
};
let module = Module::<BE>::new(N_GLWE as u64);
// Secret key sampling source
let mut source_xs: Source = Source::new([1u8; 32]);
// Public randomness sampling source
let mut source_xa: Source = Source::new([1u8; 32]);
// Noise sampling source
let mut source_xe: Source = Source::new([1u8; 32]);
// Scratch space (4MB)
let mut scratch: ScratchOwned<BE> = ScratchOwned::alloc(1 << 22);
////////// Key Generation and Preparation
// Generating the GLWE and LWE key
let mut sk_glwe = GLWESecret::alloc_from_infos(&glwe_layout);
sk_glwe.fill_ternary_prob(0.5, &mut source_xs);
let mut sk_lwe = LWESecret::alloc(bdd_layout.cbt_layout.brk_layout.n_lwe);
sk_lwe.fill_binary_block(BINARY_BLOCK_SIZE as usize, &mut source_xs);
// Preparing the private keys
let mut sk_glwe_prepared = GLWESecretPrepared::alloc_from_infos(&module, &glwe_layout);
sk_glwe_prepared.prepare(&module, &sk_glwe);
// Creating the public BDD Key
// This key is required to prepare all Fhe Integers for operations,
// and for performing the operations themselves
let mut bdd_key: BDDKey<Vec<u8>, BRA> = BDDKey::alloc_from_infos(&bdd_layout);
bdd_key.encrypt_sk(
&module,
&sk_lwe,
&sk_glwe,
&mut source_xa,
&mut source_xe,
scratch.borrow(),
);
////////// Input Encryption
// Encrypting the inputs
let input_a = 255_u32;
let input_b = 30_u32;
let mut a_enc: FheUint<Vec<u8>, u32> = FheUint::alloc_from_infos(&glwe_layout);
a_enc.encrypt_sk(
&module,
input_a,
&sk_glwe_prepared,
&mut source_xa,
&mut source_xe,
scratch.borrow(),
);
let mut b_enc: FheUint<Vec<u8>, u32> = FheUint::alloc_from_infos(&glwe_layout);
b_enc.encrypt_sk(
&module,
input_b,
&sk_glwe_prepared,
&mut source_xa,
&mut source_xe,
scratch.borrow(),
);
//////// Homomorphic computation starts here ////////
// Preparing the BDD Key
// The BDD key must be prepared once before any operation is performed
let mut bdd_key_prepared: BDDKeyPrepared<Vec<u8>, BRA, BE> = BDDKeyPrepared::alloc_from_infos(&module, &bdd_layout);
bdd_key_prepared.prepare(&module, &bdd_key, scratch.borrow());
// Input Preparation
// Before each operation, the inputs to that operation must be prepared
// Preparation extracts each bit of the integer into a seperate GLWE ciphertext and bootstraps it into a GGSW ciphertext
let mut a_enc_prepared: FheUintPrepared<Vec<u8>, u32, BE> = FheUintPrepared::alloc_from_infos(&module, &ggsw_layout);
a_enc_prepared.prepare(&module, &a_enc, &bdd_key_prepared, scratch.borrow());
let mut b_enc_prepared: FheUintPrepared<Vec<u8>, u32, BE> = FheUintPrepared::alloc_from_infos(&module, &ggsw_layout);
b_enc_prepared.prepare(&module, &b_enc, &bdd_key_prepared, scratch.borrow());
// Allocating the intermediate ciphertext c_enc
let mut c_enc: FheUint<Vec<u8>, u32> = FheUint::alloc_from_infos(&glwe_layout);
// Performing the operation
c_enc.add(
&module,
&a_enc_prepared,
&b_enc_prepared,
&bdd_key_prepared,
scratch.borrow(),
);
// Preparing the intermediate result ciphertext, c_enc, for the next operation
let mut c_enc_prepared: FheUintPrepared<Vec<u8>, u32, BE> = FheUintPrepared::alloc_from_infos(&module, &ggsw_layout);
c_enc_prepared.prepare(&module, &c_enc, &bdd_key_prepared, scratch.borrow());
// Creating the output ciphertext d_enc
let mut selected_enc: FheUint<Vec<u8>, u32> = FheUint::alloc_from_infos(&glwe_layout);
selected_enc.xor(
&module,
&c_enc_prepared,
&a_enc_prepared,
&bdd_key_prepared,
scratch.borrow(),
);
//////// Homomorphic computation ends here ////////
// Decrypting the result
let d_dec = selected_enc.decrypt(&module, &sk_glwe_prepared, scratch.borrow());
// d = (a + b) ^ a
let d_correct = (input_a.wrapping_add(input_b)) ^ input_a;
println!("Result: {} == {}", d_dec, d_correct);
// List of available operations are:
// - add: addition
// - sub: subtraction
// - sll: left shift logical
// - sra: right shift arithmetic
// - srl: right shift logical
// - slt: less than
// - sltu: less than unsigned
// - and: bitwise and
// - or: bitwise or
// - xor: bitwise xor
///////////////////////////// GLWE Blind Selection
// This example demonstrates the use of the GLWE Blind Selection operation
// It can choose between any number of encrypted fheuint inputs
// using an encrypted fheuint selector
let log_2_number_of_inputs: usize = 5;
let number_of_inputs: usize = 1 << log_2_number_of_inputs;
let inputs_a_vec: Vec<u32> = (0..number_of_inputs)
.map(|_| rand::rng().random_range(0..u32::MAX - 1))
.collect();
let input_selector: u32 = rand::rng().random_range(0..number_of_inputs as u32);
let mut inputs_a_enc_vec: Vec<FheUint<Vec<u8>, u32>> = Vec::new();
for input in &inputs_a_vec {
let mut next_input: FheUint<Vec<u8>, u32> = FheUint::alloc_from_infos(&glwe_layout);
next_input.encrypt_sk(
&module,
*input,
&sk_glwe_prepared,
&mut source_xa,
&mut source_xe,
scratch.borrow(),
);
inputs_a_enc_vec.push(next_input);
}
let mut inputs_a_enc_vec_map: HashMap<usize, &mut FheUint<Vec<u8>, u32>> = HashMap::new();
for (i, input) in inputs_a_enc_vec.iter_mut().enumerate() {
inputs_a_enc_vec_map.insert(i, input);
}
let mut input_selector_enc: FheUint<Vec<u8>, u32> = FheUint::alloc_from_infos(&glwe_layout);
input_selector_enc.encrypt_sk(
&module,
input_selector,
&sk_glwe_prepared,
&mut source_xa,
&mut source_xe,
scratch.borrow(),
);
let mut input_selector_enc_prepared: FheUintPrepared<Vec<u8>, u32, BE> =
FheUintPrepared::alloc_from_infos(&module, &ggsw_layout);
input_selector_enc_prepared.prepare(
&module,
&input_selector_enc,
&bdd_key_prepared,
scratch.borrow(),
);
module.glwe_blind_selection(
&mut selected_enc,
inputs_a_enc_vec_map,
&input_selector_enc_prepared,
0,
log_2_number_of_inputs,
scratch.borrow(),
);
let selected_dec = selected_enc.decrypt(&module, &sk_glwe_prepared, scratch.borrow());
let selected_correct = inputs_a_vec[input_selector as usize];
println!("Result: {} == {}", selected_dec, selected_correct);
}
fn main() {
#[cfg(all(feature = "enable-avx", target_arch = "x86_64"))]
example_bdd_arithmetic::<FFT64Avx, CGGI>();
#[cfg(not(all(feature = "enable-avx", target_arch = "x86_64")))]
example_bdd_arithmetic::<FFT64Ref, CGGI>();
}

View File

@@ -77,8 +77,8 @@ fn main() {
// GGLWE tensor key modulus // GGLWE tensor key modulus
let k_tsk: usize = (rows_tsk + 1) * base2k; let k_tsk: usize = (rows_tsk + 1) * base2k;
let cbt_infos: CircuitBootstrappingKeyLayout = CircuitBootstrappingKeyLayout { let cbt_layout: CircuitBootstrappingKeyLayout = CircuitBootstrappingKeyLayout {
layout_brk: BlindRotationKeyLayout { brk_layout: BlindRotationKeyLayout {
n_glwe: n_glwe.into(), n_glwe: n_glwe.into(),
n_lwe: n_lwe.into(), n_lwe: n_lwe.into(),
base2k: base2k.into(), base2k: base2k.into(),
@@ -86,7 +86,7 @@ fn main() {
dnum: rows_brk.into(), dnum: rows_brk.into(),
rank: rank.into(), rank: rank.into(),
}, },
layout_atk: GLWEAutomorphismKeyLayout { atk_layout: GLWEAutomorphismKeyLayout {
n: n_glwe.into(), n: n_glwe.into(),
base2k: base2k.into(), base2k: base2k.into(),
k: k_trace.into(), k: k_trace.into(),
@@ -94,7 +94,7 @@ fn main() {
dsize: 1_u32.into(), dsize: 1_u32.into(),
rank: rank.into(), rank: rank.into(),
}, },
layout_tsk: GGLWEToGGSWKeyLayout { tsk_layout: GGLWEToGGSWKeyLayout {
n: n_glwe.into(), n: n_glwe.into(),
base2k: base2k.into(), base2k: base2k.into(),
k: k_tsk.into(), k: k_tsk.into(),
@@ -134,12 +134,12 @@ fn main() {
// LWE secret // LWE secret
let mut sk_lwe: LWESecret<Vec<u8>> = LWESecret::alloc(n_lwe.into()); let mut sk_lwe: LWESecret<Vec<u8>> = LWESecret::alloc(n_lwe.into());
sk_lwe.fill_binary_block(block_size, &mut source_xs); sk_lwe.fill_binary_block(block_size, &mut source_xs);
sk_lwe.fill_zero(); // sk_lwe.fill_zero(); // for testing
// GLWE secret // GLWE secret
let mut sk_glwe: GLWESecret<Vec<u8>> = GLWESecret::alloc(n_glwe.into(), rank.into()); let mut sk_glwe: GLWESecret<Vec<u8>> = GLWESecret::alloc(n_glwe.into(), rank.into());
sk_glwe.fill_ternary_prob(0.5, &mut source_xs); sk_glwe.fill_ternary_prob(0.5, &mut source_xs);
// sk_glwe.fill_zero(); // sk_glwe.fill_zero(); // for testing
// GLWE secret prepared (opaque backend dependant write only struct) // GLWE secret prepared (opaque backend dependant write only struct)
let mut sk_glwe_prepared: GLWESecretPrepared<Vec<u8>, BackendImpl> = GLWESecretPrepared::alloc(&module, rank.into()); let mut sk_glwe_prepared: GLWESecretPrepared<Vec<u8>, BackendImpl> = GLWESecretPrepared::alloc(&module, rank.into());
@@ -151,7 +151,7 @@ fn main() {
// LWE plaintext // LWE plaintext
let mut pt_lwe: LWEPlaintext<Vec<u8>> = LWEPlaintext::alloc(base2k.into(), k_lwe_pt.into()); let mut pt_lwe: LWEPlaintext<Vec<u8>> = LWEPlaintext::alloc(base2k.into(), k_lwe_pt.into());
// LWE plaintext(data * 2^{- (k_lwe_pt - 1)}) // LWE plaintext(data * 2^{- (k_lwe_pt + 1)})
pt_lwe.encode_i64(data, (k_lwe_pt + 1).into()); // +1 for padding bit pt_lwe.encode_i64(data, (k_lwe_pt + 1).into()); // +1 for padding bit
// Normalize plaintext to nicely print coefficients // Normalize plaintext to nicely print coefficients
@@ -174,7 +174,7 @@ fn main() {
let now: Instant = Instant::now(); let now: Instant = Instant::now();
// Circuit bootstrapping evaluation key // Circuit bootstrapping evaluation key
let mut cbt_key: CircuitBootstrappingKey<Vec<u8>, CGGI> = CircuitBootstrappingKey::alloc_from_infos(&cbt_infos); let mut cbt_key: CircuitBootstrappingKey<Vec<u8>, CGGI> = CircuitBootstrappingKey::alloc_from_infos(&cbt_layout);
cbt_key.encrypt_sk( cbt_key.encrypt_sk(
&module, &module,
@@ -192,7 +192,7 @@ fn main() {
// Circuit bootstrapping key prepared (opaque backend dependant write only struct) // Circuit bootstrapping key prepared (opaque backend dependant write only struct)
let mut cbt_prepared: CircuitBootstrappingKeyPrepared<Vec<u8>, CGGI, BackendImpl> = let mut cbt_prepared: CircuitBootstrappingKeyPrepared<Vec<u8>, CGGI, BackendImpl> =
CircuitBootstrappingKeyPrepared::alloc_from_infos(&module, &cbt_infos); CircuitBootstrappingKeyPrepared::alloc_from_infos(&module, &cbt_layout);
cbt_prepared.prepare(&module, &cbt_key, scratch.borrow()); cbt_prepared.prepare(&module, &cbt_key, scratch.borrow());
// Apply circuit bootstrapping: LWE(data * 2^{- (k_lwe_pt + 2)}) -> GGSW(data) // Apply circuit bootstrapping: LWE(data * 2^{- (k_lwe_pt + 2)}) -> GGSW(data)

View File

@@ -0,0 +1,259 @@
use std::collections::HashMap;
use poulpy_core::{
GLWECopy, GLWEDecrypt, GLWEEncryptSk, GLWEExternalProduct, LWEEncryptSk, ScratchTakeCore,
layouts::{
Base2K, Degree, Dnum, Dsize, GGLWEToGGSWKeyLayout, GGSWLayout, GGSWPreparedFactory, GLWEAutomorphismKeyLayout,
GLWELayout, GLWESecret, GLWESecretPrepared, GLWESecretPreparedFactory, GLWESwitchingKeyLayout, GLWEToLWEKeyLayout,
GLWEToMut, GLWEToRef, LWESecret, Rank, TorusPrecision,
},
};
use poulpy_hal::{
api::{ModuleN, ModuleNew, ScratchOwnedAlloc, ScratchOwnedBorrow, VecZnxRotateInplace},
layouts::{Backend, Module, Scratch, ScratchOwned},
source::Source,
};
use poulpy_schemes::bin_fhe::{
bdd_arithmetic::{
BDDKey, BDDKeyEncryptSk, BDDKeyLayout, BDDKeyPrepared, BDDKeyPreparedFactory, ExecuteBDDCircuit2WTo1W, FheUint,
FheUintPrepare, FheUintPrepared, GLWEBlindSelection, Sltu,
},
blind_rotation::{BlindRotationAlgo, BlindRotationKey, BlindRotationKeyFactory, BlindRotationKeyLayout, CGGI},
circuit_bootstrapping::CircuitBootstrappingKeyLayout,
};
use rand::Rng;
#[cfg(all(feature = "enable-avx", target_arch = "x86_64"))]
use poulpy_cpu_avx::FFT64Avx;
#[cfg(not(all(feature = "enable-avx", target_arch = "x86_64")))]
use poulpy_cpu_ref::FFT64Ref;
// This example demonstrates and end-to-end example usage of the BDD arithmetic API
// to compute the maximum of an array of integers.
fn example_max_array<BE: Backend, BRA: BlindRotationAlgo>()
where
Module<BE>: ModuleNew<BE>
+ ModuleN
+ GLWESecretPreparedFactory<BE>
+ GLWEExternalProduct<BE>
+ GLWEDecrypt<BE>
+ LWEEncryptSk<BE>
+ GGSWPreparedFactory<BE>
+ GLWEEncryptSk<BE>
+ VecZnxRotateInplace<BE>
+ BDDKeyEncryptSk<BRA, BE>
+ BDDKeyPreparedFactory<BRA, BE>
+ FheUintPrepare<BRA, BE>
+ ExecuteBDDCircuit2WTo1W<BE>
+ GLWEBlindSelection<u32, BE>,
BlindRotationKey<Vec<u8>, BRA>: BlindRotationKeyFactory<BRA>, // TODO find a way to remove this bound or move it to CBT KEY
ScratchOwned<BE>: ScratchOwnedAlloc<BE> + ScratchOwnedBorrow<BE>,
Scratch<BE>: ScratchTakeCore<BE>,
{
////////// Parameter Selection
const N_GLWE: u32 = 1024;
const N_LWE: u32 = 567;
const BINARY_BLOCK_SIZE: u32 = 7;
const BASE2K: u32 = 17;
const RANK: u32 = 1;
// GLWE layout, used to generate GLWE Ciphertexts, keys, switching keys, etc
let glwe_layout = GLWELayout {
n: Degree(N_GLWE),
base2k: Base2K(BASE2K),
k: TorusPrecision(2 * BASE2K),
rank: Rank(RANK),
};
// Used to generate GGSW Ciphertexts
let ggsw_layout = GGSWLayout {
n: Degree(N_GLWE),
base2k: Base2K(BASE2K),
k: TorusPrecision(3 * BASE2K),
rank: Rank(RANK),
dnum: Dnum(3),
dsize: Dsize(1),
};
// Used to generate CBT Keys
let cbt_layout = CircuitBootstrappingKeyLayout {
brk_layout: BlindRotationKeyLayout {
n_glwe: Degree(N_GLWE),
n_lwe: Degree(N_LWE),
base2k: Base2K(BASE2K),
k: TorusPrecision(4 * BASE2K),
dnum: Dnum(4),
rank: Rank(RANK),
},
atk_layout: GLWEAutomorphismKeyLayout {
n: Degree(N_GLWE),
base2k: Base2K(BASE2K),
k: TorusPrecision(4 * BASE2K),
dnum: Dnum(4),
dsize: Dsize(1),
rank: Rank(RANK),
},
tsk_layout: GGLWEToGGSWKeyLayout {
n: Degree(N_GLWE),
base2k: Base2K(BASE2K),
k: TorusPrecision(4 * BASE2K),
dnum: Dnum(4),
dsize: Dsize(1),
rank: Rank(RANK),
},
};
// Used to generate BDD Keys, for the arithmetic operations
let bdd_layout = BDDKeyLayout {
cbt_layout: cbt_layout,
ks_glwe_layout: Some(GLWESwitchingKeyLayout {
n: Degree(N_GLWE),
base2k: Base2K(BASE2K),
k: TorusPrecision(4 * BASE2K),
dnum: Dnum(4),
dsize: Dsize(1),
rank_in: Rank(RANK),
rank_out: Rank(1),
}),
ks_lwe_layout: GLWEToLWEKeyLayout {
n: Degree(N_GLWE),
base2k: Base2K(BASE2K),
k: TorusPrecision(4 * BASE2K),
rank_in: Rank(RANK),
dnum: Dnum(4),
},
};
let module = Module::<BE>::new(N_GLWE as u64);
// Secret key sampling source
let mut source_xs: Source = Source::new([1u8; 32]);
// Public randomness sampling source
let mut source_xa: Source = Source::new([1u8; 32]);
// Noise sampling source
let mut source_xe: Source = Source::new([1u8; 32]);
// Scratch space (4MB)
let mut scratch: ScratchOwned<BE> = ScratchOwned::alloc(1 << 22);
////////// Key Generation and Preparation
// Generating the GLWE and LWE key
let mut sk_glwe = GLWESecret::alloc_from_infos(&glwe_layout);
sk_glwe.fill_ternary_prob(0.5, &mut source_xs);
let mut sk_lwe = LWESecret::alloc(Degree(N_LWE));
sk_lwe.fill_binary_block(BINARY_BLOCK_SIZE as usize, &mut source_xs);
// Preparing the private keys
let mut sk_glwe_prepared = GLWESecretPrepared::alloc_from_infos(&module, &glwe_layout);
sk_glwe_prepared.prepare(&module, &sk_glwe);
// Creating the public BDD Key
// This key is required to prepare all Fhe Integers for operations,
// and for performing the operations themselves
let mut bdd_key: BDDKey<Vec<u8>, BRA> = BDDKey::alloc_from_infos(&bdd_layout);
bdd_key.encrypt_sk(
&module,
&sk_lwe,
&sk_glwe,
&mut source_xa,
&mut source_xe,
scratch.borrow(),
);
////////// Input Encryption
// Encrypting the inputs
let mut rng = rand::rng();
let inputs: Vec<u32> = (0..3).map(|_| rng.random_range(0..u32::MAX - 1)).collect();
let mut inputs_enc: Vec<FheUint<Vec<u8>, u32>> = Vec::new();
for input in &inputs {
let mut next_input = FheUint::alloc_from_infos(&glwe_layout);
next_input.encrypt_sk(
&module,
*input,
&sk_glwe_prepared,
&mut source_xa,
&mut source_xe,
scratch.borrow(),
);
inputs_enc.push(next_input);
}
//////// Homomorphic computation starts here ////////
// Preparing the BDD Key
// The BDD key must be prepared once before any operation is performed
let mut bdd_key_prepared: BDDKeyPrepared<Vec<u8>, BRA, BE> = BDDKeyPrepared::alloc_from_infos(&module, &bdd_layout);
bdd_key_prepared.prepare(&module, &bdd_key, scratch.borrow());
let mut max_enc: FheUint<Vec<u8>, u32> = FheUint::alloc_from_infos(&glwe_layout);
max_enc.encrypt_sk(
&module,
0,
&sk_glwe_prepared,
&mut source_xa,
&mut source_xe,
scratch.borrow(),
);
// Copy of max_enc for the HashMap
let mut max_enc_copy: FheUint<Vec<u8>, u32> = FheUint::alloc_from_infos(&glwe_layout);
// Allocating the intermediate ciphertext c_enc
let mut compare_enc: FheUint<Vec<u8>, u32> = FheUint::alloc_from_infos(&glwe_layout);
let mut compare_enc_prepared: FheUintPrepared<Vec<u8>, u32, BE> = FheUintPrepared::alloc_from_infos(&module, &ggsw_layout);
for input_i in inputs_enc.iter_mut() {
let mut max_enc_prepared: FheUintPrepared<Vec<u8>, u32, BE> = FheUintPrepared::alloc_from_infos(&module, &ggsw_layout);
max_enc_prepared.prepare(&module, &max_enc, &bdd_key_prepared, scratch.borrow());
let mut input_i_enc_prepared: FheUintPrepared<Vec<u8>, u32, BE> =
FheUintPrepared::alloc_from_infos(&module, &ggsw_layout);
input_i_enc_prepared.prepare(&module, &input_i, &bdd_key_prepared, scratch.borrow());
// b = (input_i < max)
compare_enc.sltu(
&module,
&input_i_enc_prepared,
&max_enc_prepared,
&bdd_key_prepared,
scratch.borrow(),
);
compare_enc_prepared.prepare(&module, &compare_enc, &bdd_key_prepared, scratch.borrow());
module.glwe_copy(&mut max_enc_copy.to_mut(), &max_enc.to_ref());
let cts = HashMap::from([(0, input_i), (1, &mut max_enc_copy)]);
<Module<BE> as GLWEBlindSelection<u32, BE>>::glwe_blind_selection(
&module,
&mut max_enc,
cts,
&compare_enc_prepared,
0,
1,
scratch.borrow(),
);
}
//////// Homomorphic computation ends here ////////
// Decrypting the result
let result_dec = max_enc.decrypt(&module, &sk_glwe_prepared, scratch.borrow());
// result = max of inputs
let result_correct = inputs.iter().max().unwrap();
println!("Result: {} == {}", result_dec, result_correct);
}
fn main() {
#[cfg(all(feature = "enable-avx", target_arch = "x86_64"))]
example_max_array::<FFT64Avx, CGGI>();
#[cfg(not(all(feature = "enable-avx", target_arch = "x86_64")))]
example_max_array::<FFT64Ref, CGGI>();
}

View File

@@ -188,15 +188,35 @@ macro_rules! impl_bdd_2w_to_1w_trait {
} }
}; };
} }
// a + b
define_bdd_2w_to_1w_trait!(pub Add, add); define_bdd_2w_to_1w_trait!(pub Add, add);
// a - b
define_bdd_2w_to_1w_trait!(pub Sub, sub); define_bdd_2w_to_1w_trait!(pub Sub, sub);
// a << b
define_bdd_2w_to_1w_trait!(pub Sll, sll); define_bdd_2w_to_1w_trait!(pub Sll, sll);
// a >> b arithmetic
define_bdd_2w_to_1w_trait!(pub Sra, sra); define_bdd_2w_to_1w_trait!(pub Sra, sra);
// a >> b logical
define_bdd_2w_to_1w_trait!(pub Srl, srl); define_bdd_2w_to_1w_trait!(pub Srl, srl);
// signed a < signed b
define_bdd_2w_to_1w_trait!(pub Slt, slt); define_bdd_2w_to_1w_trait!(pub Slt, slt);
// unsigned a < unsigned b
define_bdd_2w_to_1w_trait!(pub Sltu, sltu); define_bdd_2w_to_1w_trait!(pub Sltu, sltu);
// a or b
define_bdd_2w_to_1w_trait!(pub Or, or); define_bdd_2w_to_1w_trait!(pub Or, or);
// a and b
define_bdd_2w_to_1w_trait!(pub And, and); define_bdd_2w_to_1w_trait!(pub And, and);
// a xor b
define_bdd_2w_to_1w_trait!(pub Xor, xor); define_bdd_2w_to_1w_trait!(pub Xor, xor);
impl_bdd_2w_to_1w_trait!( impl_bdd_2w_to_1w_trait!(

View File

@@ -8,9 +8,9 @@ use poulpy_hal::layouts::{Backend, Module, Scratch, ZnxZero};
use crate::bin_fhe::bdd_arithmetic::{Cmux, GetGGSWBit, UnsignedInteger}; use crate::bin_fhe::bdd_arithmetic::{Cmux, GetGGSWBit, UnsignedInteger};
impl<T: UnsignedInteger, BE: Backend> GLWEBlinSelection<T, BE> for Module<BE> where Self: GLWECopy + Cmux<BE> + GLWEDecrypt<BE> {} impl<T: UnsignedInteger, BE: Backend> GLWEBlindSelection<T, BE> for Module<BE> where Self: GLWECopy + Cmux<BE> + GLWEDecrypt<BE> {}
pub trait GLWEBlinSelection<T: UnsignedInteger, BE: Backend> pub trait GLWEBlindSelection<T: UnsignedInteger, BE: Backend>
where where
Self: GLWECopy + Cmux<BE> + GLWEDecrypt<BE>, Self: GLWECopy + Cmux<BE> + GLWEDecrypt<BE>,
{ {

View File

@@ -87,7 +87,7 @@ impl<D: DataMut, T: UnsignedInteger + ToBits> FheUint<D, T> {
&mut self, &mut self,
module: &M, module: &M,
data: T, data: T,
sk: &S, sk_glwe: &S,
source_xa: &mut Source, source_xa: &mut Source,
source_xe: &mut Source, source_xe: &mut Source,
scratch: &mut Scratch<BE>, scratch: &mut Scratch<BE>,
@@ -100,7 +100,7 @@ impl<D: DataMut, T: UnsignedInteger + ToBits> FheUint<D, T> {
{ {
assert!(module.n().is_multiple_of(T::BITS as usize)); assert!(module.n().is_multiple_of(T::BITS as usize));
assert_eq!(self.n(), module.n() as u32); assert_eq!(self.n(), module.n() as u32);
assert_eq!(sk.n(), module.n() as u32); assert_eq!(sk_glwe.n(), module.n() as u32);
} }
let mut data_bits: Vec<i64> = vec![0i64; module.n()]; let mut data_bits: Vec<i64> = vec![0i64; module.n()];
@@ -122,7 +122,7 @@ impl<D: DataMut, T: UnsignedInteger + ToBits> FheUint<D, T> {
pt.encode_vec_i64(&data_bits, TorusPrecision(2)); pt.encode_vec_i64(&data_bits, TorusPrecision(2));
self.bits self.bits
.encrypt_sk(module, &pt, sk, source_xa, source_xe, scratch_1); .encrypt_sk(module, &pt, sk_glwe, source_xa, source_xe, scratch_1);
} }
} }
@@ -150,7 +150,7 @@ impl<D: DataRef, T: UnsignedInteger + FromBits> FheUint<D, T> {
self.bits.noise(module, &pt, sk, scratch_1) self.bits.noise(module, &pt, sk, scratch_1)
} }
pub fn decrypt<S, M, BE: Backend>(&self, module: &M, sk: &S, scratch: &mut Scratch<BE>) -> T pub fn decrypt<S, M, BE: Backend>(&self, module: &M, sk_glwe: &S, scratch: &mut Scratch<BE>) -> T
where where
S: GLWESecretPreparedToRef<BE> + GLWEInfos, S: GLWESecretPreparedToRef<BE> + GLWEInfos,
M: ModuleLogN + GLWEDecrypt<BE>, M: ModuleLogN + GLWEDecrypt<BE>,
@@ -160,7 +160,7 @@ impl<D: DataRef, T: UnsignedInteger + FromBits> FheUint<D, T> {
{ {
assert!(module.n().is_multiple_of(T::BITS as usize)); assert!(module.n().is_multiple_of(T::BITS as usize));
assert_eq!(self.n(), module.n() as u32); assert_eq!(self.n(), module.n() as u32);
assert_eq!(sk.n(), module.n() as u32); assert_eq!(sk_glwe.n(), module.n() as u32);
} }
let pt_infos = GLWEPlaintextLayout { let pt_infos = GLWEPlaintextLayout {
@@ -171,7 +171,7 @@ impl<D: DataRef, T: UnsignedInteger + FromBits> FheUint<D, T> {
let (mut pt, scratch_1) = scratch.take_glwe_plaintext(&pt_infos); let (mut pt, scratch_1) = scratch.take_glwe_plaintext(&pt_infos);
self.bits.decrypt(module, &mut pt, sk, scratch_1); self.bits.decrypt(module, &mut pt, sk_glwe, scratch_1);
let mut data_bits: Vec<i64> = vec![0i64; module.n()]; let mut data_bits: Vec<i64> = vec![0i64; module.n()];
pt.decode_vec_i64(&mut data_bits, TorusPrecision(2)); pt.decode_vec_i64(&mut data_bits, TorusPrecision(2));

View File

@@ -34,22 +34,22 @@ pub trait BDDKeyInfos {
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub struct BDDKeyLayout { pub struct BDDKeyLayout {
pub cbt: CircuitBootstrappingKeyLayout, pub cbt_layout: CircuitBootstrappingKeyLayout,
pub ks_glwe: Option<GLWESwitchingKeyLayout>, pub ks_glwe_layout: Option<GLWESwitchingKeyLayout>,
pub ks_lwe: GLWEToLWEKeyLayout, pub ks_lwe_layout: GLWEToLWEKeyLayout,
} }
impl BDDKeyInfos for BDDKeyLayout { impl BDDKeyInfos for BDDKeyLayout {
fn cbt_infos(&self) -> CircuitBootstrappingKeyLayout { fn cbt_infos(&self) -> CircuitBootstrappingKeyLayout {
self.cbt self.cbt_layout
} }
fn ks_glwe_infos(&self) -> Option<GLWESwitchingKeyLayout> { fn ks_glwe_infos(&self) -> Option<GLWESwitchingKeyLayout> {
self.ks_glwe self.ks_glwe_layout
} }
fn ks_lwe_infos(&self) -> GLWEToLWEKeyLayout { fn ks_lwe_infos(&self) -> GLWEToLWEKeyLayout {
self.ks_lwe self.ks_lwe_layout
} }
} }
@@ -176,9 +176,9 @@ where
impl<D: DataRef, BRA: BlindRotationAlgo, BE: Backend> BDDKeyInfos for BDDKeyPrepared<D, BRA, BE> { impl<D: DataRef, BRA: BlindRotationAlgo, BE: Backend> BDDKeyInfos for BDDKeyPrepared<D, BRA, BE> {
fn cbt_infos(&self) -> CircuitBootstrappingKeyLayout { fn cbt_infos(&self) -> CircuitBootstrappingKeyLayout {
CircuitBootstrappingKeyLayout { CircuitBootstrappingKeyLayout {
layout_brk: self.cbt.brk_infos(), brk_layout: self.cbt.brk_infos(),
layout_atk: self.cbt.atk_infos(), atk_layout: self.cbt.atk_infos(),
layout_tsk: self.cbt.tsk_infos(), tsk_layout: self.cbt.tsk_infos(),
} }
} }
fn ks_glwe_infos(&self) -> Option<GLWESwitchingKeyLayout> { fn ks_glwe_infos(&self) -> Option<GLWESwitchingKeyLayout> {

View File

@@ -16,7 +16,7 @@ use rand::RngCore;
use crate::bin_fhe::{ use crate::bin_fhe::{
bdd_arithmetic::{ bdd_arithmetic::{
FheUintPrepared, GLWEBlinSelection, FheUintPrepared, GLWEBlindSelection,
tests::test_suite::{TEST_FHEUINT_BASE2K, TEST_RANK, TestContext}, tests::test_suite::{TEST_FHEUINT_BASE2K, TEST_RANK, TestContext},
}, },
blind_rotation::BlindRotationAlgo, blind_rotation::BlindRotationAlgo,
@@ -28,7 +28,7 @@ where
+ GLWESecretPreparedFactory<BE> + GLWESecretPreparedFactory<BE>
+ GGSWPreparedFactory<BE> + GGSWPreparedFactory<BE>
+ GGSWEncryptSk<BE> + GGSWEncryptSk<BE>
+ GLWEBlinSelection<u32, BE> + GLWEBlindSelection<u32, BE>
+ GLWEDecrypt<BE> + GLWEDecrypt<BE>
+ GLWEEncryptSk<BE>, + GLWEEncryptSk<BE>,
ScratchOwned<BE>: ScratchOwnedAlloc<BE> + ScratchOwnedBorrow<BE>, ScratchOwned<BE>: ScratchOwnedAlloc<BE> + ScratchOwnedBorrow<BE>,

View File

@@ -165,8 +165,8 @@ pub(crate) static TEST_GGSW_INFOS: GGSWLayout = GGSWLayout {
}; };
pub(crate) static TEST_BDD_KEY_LAYOUT: BDDKeyLayout = BDDKeyLayout { pub(crate) static TEST_BDD_KEY_LAYOUT: BDDKeyLayout = BDDKeyLayout {
cbt: CircuitBootstrappingKeyLayout { cbt_layout: CircuitBootstrappingKeyLayout {
layout_brk: BlindRotationKeyLayout { brk_layout: BlindRotationKeyLayout {
n_glwe: Degree(TEST_N_GLWE), n_glwe: Degree(TEST_N_GLWE),
n_lwe: Degree(TEST_N_LWE), n_lwe: Degree(TEST_N_LWE),
base2k: Base2K(TEST_BRK_BASE2K), base2k: Base2K(TEST_BRK_BASE2K),
@@ -174,7 +174,7 @@ pub(crate) static TEST_BDD_KEY_LAYOUT: BDDKeyLayout = BDDKeyLayout {
dnum: Dnum(4), dnum: Dnum(4),
rank: Rank(TEST_RANK), rank: Rank(TEST_RANK),
}, },
layout_atk: GLWEAutomorphismKeyLayout { atk_layout: GLWEAutomorphismKeyLayout {
n: Degree(TEST_N_GLWE), n: Degree(TEST_N_GLWE),
base2k: Base2K(TEST_ATK_BASE2K), base2k: Base2K(TEST_ATK_BASE2K),
k: TorusPrecision(52), k: TorusPrecision(52),
@@ -182,7 +182,7 @@ pub(crate) static TEST_BDD_KEY_LAYOUT: BDDKeyLayout = BDDKeyLayout {
dnum: Dnum(4), dnum: Dnum(4),
dsize: Dsize(1), dsize: Dsize(1),
}, },
layout_tsk: GGLWEToGGSWKeyLayout { tsk_layout: GGLWEToGGSWKeyLayout {
n: Degree(TEST_N_GLWE), n: Degree(TEST_N_GLWE),
base2k: Base2K(TEST_TSK_BASE2K), base2k: Base2K(TEST_TSK_BASE2K),
k: TorusPrecision(52), k: TorusPrecision(52),
@@ -191,7 +191,7 @@ pub(crate) static TEST_BDD_KEY_LAYOUT: BDDKeyLayout = BDDKeyLayout {
dsize: Dsize(1), dsize: Dsize(1),
}, },
}, },
ks_glwe: Some(GLWESwitchingKeyLayout { ks_glwe_layout: Some(GLWESwitchingKeyLayout {
n: Degree(TEST_N_GLWE), n: Degree(TEST_N_GLWE),
base2k: Base2K(TEST_LWE_BASE2K), base2k: Base2K(TEST_LWE_BASE2K),
k: TorusPrecision(20), k: TorusPrecision(20),
@@ -200,7 +200,7 @@ pub(crate) static TEST_BDD_KEY_LAYOUT: BDDKeyLayout = BDDKeyLayout {
dnum: Dnum(3), dnum: Dnum(3),
dsize: Dsize(1), dsize: Dsize(1),
}), }),
ks_lwe: GLWEToLWEKeyLayout { ks_lwe_layout: GLWEToLWEKeyLayout {
n: Degree(TEST_N_GLWE), n: Degree(TEST_N_GLWE),
base2k: Base2K(TEST_LWE_BASE2K), base2k: Base2K(TEST_LWE_BASE2K),
k: TorusPrecision(16), k: TorusPrecision(16),

View File

@@ -27,9 +27,9 @@ pub trait CircuitBootstrappingKeyInfos {
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub struct CircuitBootstrappingKeyLayout { pub struct CircuitBootstrappingKeyLayout {
pub layout_brk: BlindRotationKeyLayout, pub brk_layout: BlindRotationKeyLayout,
pub layout_atk: GLWEAutomorphismKeyLayout, pub atk_layout: GLWEAutomorphismKeyLayout,
pub layout_tsk: GGLWEToGGSWKeyLayout, pub tsk_layout: GGLWEToGGSWKeyLayout,
} }
impl CircuitBootstrappingKeyInfos for CircuitBootstrappingKeyLayout { impl CircuitBootstrappingKeyInfos for CircuitBootstrappingKeyLayout {
@@ -38,15 +38,15 @@ impl CircuitBootstrappingKeyInfos for CircuitBootstrappingKeyLayout {
} }
fn atk_infos(&self) -> GLWEAutomorphismKeyLayout { fn atk_infos(&self) -> GLWEAutomorphismKeyLayout {
self.layout_atk self.atk_layout
} }
fn brk_infos(&self) -> BlindRotationKeyLayout { fn brk_infos(&self) -> BlindRotationKeyLayout {
self.layout_brk self.brk_layout
} }
fn tsk_infos(&self) -> GGLWEToGGSWKeyLayout { fn tsk_infos(&self) -> GGLWEToGGSWKeyLayout {
self.layout_tsk self.tsk_layout
} }
} }

View File

@@ -78,7 +78,7 @@ where
}; };
let cbt_infos: CircuitBootstrappingKeyLayout = CircuitBootstrappingKeyLayout { let cbt_infos: CircuitBootstrappingKeyLayout = CircuitBootstrappingKeyLayout {
layout_brk: BlindRotationKeyLayout { brk_layout: BlindRotationKeyLayout {
n_glwe: n_glwe.into(), n_glwe: n_glwe.into(),
n_lwe: n_lwe.into(), n_lwe: n_lwe.into(),
base2k: base2k_brk.into(), base2k: base2k_brk.into(),
@@ -86,7 +86,7 @@ where
dnum: rows_brk.into(), dnum: rows_brk.into(),
rank: rank.into(), rank: rank.into(),
}, },
layout_atk: GLWEAutomorphismKeyLayout { atk_layout: GLWEAutomorphismKeyLayout {
n: n_glwe.into(), n: n_glwe.into(),
base2k: base2k_atk.into(), base2k: base2k_atk.into(),
k: k_atk.into(), k: k_atk.into(),
@@ -94,7 +94,7 @@ where
rank: rank.into(), rank: rank.into(),
dsize: Dsize(1), dsize: Dsize(1),
}, },
layout_tsk: GGLWEToGGSWKeyLayout { tsk_layout: GGLWEToGGSWKeyLayout {
n: n_glwe.into(), n: n_glwe.into(),
base2k: base2k_tsk.into(), base2k: base2k_tsk.into(),
k: k_tsk.into(), k: k_tsk.into(),
@@ -285,7 +285,7 @@ where
}; };
let cbt_infos: CircuitBootstrappingKeyLayout = CircuitBootstrappingKeyLayout { let cbt_infos: CircuitBootstrappingKeyLayout = CircuitBootstrappingKeyLayout {
layout_brk: BlindRotationKeyLayout { brk_layout: BlindRotationKeyLayout {
n_glwe: n_glwe.into(), n_glwe: n_glwe.into(),
n_lwe: n_lwe.into(), n_lwe: n_lwe.into(),
base2k: base2k_brk.into(), base2k: base2k_brk.into(),
@@ -293,7 +293,7 @@ where
dnum: rows_brk.into(), dnum: rows_brk.into(),
rank: rank.into(), rank: rank.into(),
}, },
layout_atk: GLWEAutomorphismKeyLayout { atk_layout: GLWEAutomorphismKeyLayout {
n: n_glwe.into(), n: n_glwe.into(),
base2k: base2k_atk.into(), base2k: base2k_atk.into(),
k: k_atk.into(), k: k_atk.into(),
@@ -301,7 +301,7 @@ where
rank: rank.into(), rank: rank.into(),
dsize: Dsize(1), dsize: Dsize(1),
}, },
layout_tsk: GGLWEToGGSWKeyLayout { tsk_layout: GGLWEToGGSWKeyLayout {
n: n_glwe.into(), n: n_glwe.into(),
base2k: base2k_tsk.into(), base2k: base2k_tsk.into(),
k: k_tsk.into(), k: k_tsk.into(),