Add BDD Arithmetic (#98) * Added some circuit, evaluation + some layouts * Refactor + memory reduction * Rows -> Dnum, Digits -> Dsize * fix #96 + glwe_packing (indirectly CBT) * clippy
jump to
@@ -408,6 +408,7 @@ "itertools 0.14.0",
"poulpy-backend", "poulpy-core", "poulpy-hal", + "rand", ] [[package]]@@ -421,18 +422,18 @@ ]
[[package]] name = "proc-macro2" -version = "1.0.92" +version = "1.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" +checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.37" +version = "1.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1" dependencies = [ "proc-macro2", ]@@ -445,9 +446,9 @@ checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5"
[[package]] name = "rand" -version = "0.9.1" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97" +checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" dependencies = [ "rand_chacha", "rand_core",@@ -598,9 +599,9 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
[[package]] name = "syn" -version = "2.0.96" +version = "2.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5d0adab1ae378d7f53bdebc67a39f1f151407ef230f0ce2883572f5d8985c80" +checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" dependencies = [ "proc-macro2", "quote",
@@ -1124,6 +1124,7 @@ test_znx_normalize_final_step_avx_internal();
} } + #[allow(dead_code)] #[target_feature(enable = "avx2")] fn znx_extract_digit_addmul_internal() { let mut y0: [i64; 4] = [@@ -1168,6 +1169,7 @@ znx_extract_digit_addmul_internal();
} } + #[allow(dead_code)] #[target_feature(enable = "avx2")] fn znx_normalize_digit_internal() { let mut y0: [i64; 4] = [
@@ -1,5 +1,5 @@
use poulpy_core::layouts::{ - Base2K, Degree, Digits, GGSWCiphertext, GGSWCiphertextLayout, GLWECiphertext, GLWECiphertextLayout, GLWESecret, Rank, Rows, + Base2K, Degree, Dnum, Dsize, GGSWCiphertext, GGSWCiphertextLayout, GLWECiphertext, GLWECiphertextLayout, GLWESecret, Rank, TorusPrecision, prepared::{GGSWCiphertextPrepared, GLWESecretPrepared, PrepareAlloc}, };@@ -35,16 +35,16 @@ let k_ct_in: TorusPrecision = p.k_ct_in;
let k_ct_out: TorusPrecision = p.k_ct_out; let k_ggsw: TorusPrecision = p.k_ggsw; let rank: Rank = p.rank; - let digits: Digits = Digits(1); + let dsize: Dsize = Dsize(1); - let rows: Rows = Rows(1); //(p.k_ct_in.div_ceil(p.base2k); + let dnum: Dnum = Dnum(1); //(p.k_ct_in.div_ceil(p.base2k); let ggsw_layout: GGSWCiphertextLayout = GGSWCiphertextLayout { n, base2k, k: k_ggsw, - rows, - digits, + dnum: dnum, + dsize: dsize, rank, };@@ -143,16 +143,16 @@ let base2k: Base2K = p.base2k;
let k_glwe: TorusPrecision = p.k_ct; let k_ggsw: TorusPrecision = p.k_ggsw; let rank: Rank = p.rank; - let digits: Digits = Digits(1); + let dsize: Dsize = Dsize(1); - let rows: Rows = p.k_ct.div_ceil(p.base2k).into(); + let dnum: Dnum = p.k_ct.div_ceil(p.base2k).into(); let ggsw_layout: GGSWCiphertextLayout = GGSWCiphertextLayout { n, base2k, k: k_ggsw, - rows, - digits, + dnum: dnum, + dsize: dsize, rank, };
@@ -1,6 +1,6 @@
use poulpy_core::layouts::{ - Base2K, Degree, Digits, GGLWEAutomorphismKey, GGLWEAutomorphismKeyLayout, GGLWESwitchingKey, GGLWESwitchingKeyLayout, - GLWECiphertext, GLWECiphertextLayout, GLWESecret, Rank, Rows, TorusPrecision, + Base2K, Degree, Dnum, Dsize, GGLWEAutomorphismKey, GGLWEAutomorphismKeyLayout, GGLWESwitchingKey, GGLWESwitchingKeyLayout, + GLWECiphertext, GLWECiphertextLayout, GLWESecret, Rank, TorusPrecision, prepared::{GGLWEAutomorphismKeyPrepared, GGLWESwitchingKeyPrepared, GLWESecretPrepared, PrepareAlloc}, }; use std::{hint::black_box, time::Duration};@@ -22,7 +22,7 @@ base2k: Base2K,
k_ct_in: TorusPrecision, k_ct_out: TorusPrecision, k_ksk: TorusPrecision, - digits: Digits, + dsize: Dsize, rank: Rank, }@@ -35,17 +35,17 @@ let k_glwe_in: TorusPrecision = p.k_ct_in;
let k_glwe_out: TorusPrecision = p.k_ct_out; let k_gglwe: TorusPrecision = p.k_ksk; let rank: Rank = p.rank; - let digits: Digits = p.digits; + let dsize: Dsize = p.dsize; - let rows: Rows = p.k_ct_in.div_ceil(p.base2k.0 * digits.0).into(); + let dnum: Dnum = p.k_ct_in.div_ceil(p.base2k.0 * dsize.0).into(); let gglwe_atk_layout: GGLWEAutomorphismKeyLayout = GGLWEAutomorphismKeyLayout { n, base2k, k: k_gglwe, - rows, + dnum, rank, - digits, + dsize, }; let glwe_in_layout: GLWECiphertextLayout = GLWECiphertextLayout {@@ -111,15 +111,15 @@ }
} let base2k: usize = 19; - let digits = 1; + let dsize = 1; let params_set: Vec<Params> = vec![Params { log_n: 15, base2k: base2k.into(), - k_ct_in: (874 - digits * base2k).into(), - k_ct_out: (874 - digits * base2k).into(), + k_ct_in: (874 - dsize * base2k).into(), + k_ct_out: (874 - dsize * base2k).into(), k_ksk: 874_u32.into(), - digits: 1_u32.into(), + dsize: 1_u32.into(), rank: 1_u32.into(), }];@@ -153,16 +153,16 @@ let base2k: Base2K = p.base2k;
let k_ct: TorusPrecision = p.k_ct; let k_ksk: TorusPrecision = p.k_ksk; let rank: Rank = p.rank; - let digits: Digits = Digits(1); + let dsize: Dsize = Dsize(1); - let rows: Rows = p.k_ct.div_ceil(p.base2k).into(); + let dnum: Dnum = p.k_ct.div_ceil(p.base2k).into(); let gglwe_layout: GGLWESwitchingKeyLayout = GGLWESwitchingKeyLayout { n, base2k, k: k_ksk, - rows, - digits, + dnum, + dsize, rank_in: rank, rank_out: rank, };
@@ -7,7 +7,7 @@ },
layouts::{Backend, DataMut, DataRef, Module, Scratch, ZnxZero}, }; -use crate::layouts::{GGLWEAutomorphismKey, GGLWELayoutInfos, GLWECiphertext, prepared::GGLWEAutomorphismKeyPrepared}; +use crate::layouts::{GGLWEAutomorphismKey, GGLWEInfos, GLWECiphertext, prepared::GGLWEAutomorphismKeyPrepared}; impl GGLWEAutomorphismKey<Vec<u8>> { pub fn automorphism_scratch_space<B: Backend, OUT, IN, KEY>(@@ -17,9 +17,9 @@ in_infos: &IN,
key_infos: &KEY, ) -> usize where - OUT: GGLWELayoutInfos, - IN: GGLWELayoutInfos, - KEY: GGLWELayoutInfos, + OUT: GGLWEInfos, + IN: GGLWEInfos, + KEY: GGLWEInfos, Module<B>: VecZnxDftAllocBytes + VmpApplyDftToDftTmpBytes + VecZnxBigNormalizeTmpBytes + VecZnxNormalizeTmpBytes, { GLWECiphertext::keyswitch_scratch_space(@@ -32,8 +32,8 @@ }
pub fn automorphism_inplace_scratch_space<B: Backend, OUT, KEY>(module: &Module<B>, out_infos: &OUT, key_infos: &KEY) -> usize where - OUT: GGLWELayoutInfos, - KEY: GGLWELayoutInfos, + OUT: GGLWEInfos, + KEY: GGLWEInfos, Module<B>: VecZnxDftAllocBytes + VmpApplyDftToDftTmpBytes + VecZnxBigNormalizeTmpBytes + VecZnxNormalizeTmpBytes, { GGLWEAutomorphismKey::automorphism_scratch_space(module, out_infos, out_infos, key_infos)@@ -102,7 +102,7 @@ let p: i64 = lhs.p();
let p_inv: i64 = module.galois_element_inv(p); (0..self.rank_in().into()).for_each(|col_i| { - (0..self.rows().into()).for_each(|row_j| { + (0..self.dnum().into()).for_each(|row_j| { let mut res_ct: GLWECiphertext<&mut [u8]> = self.at_mut(row_j, col_i); let lhs_ct: GLWECiphertext<&[u8]> = lhs.at(row_j, col_i);@@ -121,7 +121,7 @@ });
}); }); - (self.rows().min(lhs.rows()).into()..self.rows().into()).for_each(|row_i| { + (self.dnum().min(lhs.dnum()).into()..self.dnum().into()).for_each(|row_i| { (0..self.rank_in().into()).for_each(|col_j| { self.at_mut(row_i, col_j).data.zero(); });@@ -175,7 +175,7 @@ let p: i64 = self.p();
let p_inv = module.galois_element_inv(p); (0..self.rank_in().into()).for_each(|col_i| { - (0..self.rows().into()).for_each(|row_j| { + (0..self.dnum().into()).for_each(|row_j| { let mut res_ct: GLWECiphertext<&mut [u8]> = self.at_mut(row_j, col_i); // Reverts the automorphism X^{-k}: (-pi^{-1}_{k}(s)a + s, a) to (-sa + pi_{k}(s), a)
@@ -9,7 +9,7 @@ layouts::{Backend, DataMut, DataRef, Module, Scratch},
}; use crate::layouts::{ - GGLWELayoutInfos, GGSWCiphertext, GGSWInfos, GLWECiphertext, + GGLWEInfos, GGSWCiphertext, GGSWInfos, GLWECiphertext, prepared::{GGLWEAutomorphismKeyPrepared, GGLWETensorKeyPrepared}, };@@ -24,8 +24,8 @@ ) -> usize
where OUT: GGSWInfos, IN: GGSWInfos, - KEY: GGLWELayoutInfos, - TSK: GGLWELayoutInfos, + KEY: GGLWEInfos, + TSK: GGLWEInfos, Module<B>: VecZnxDftAllocBytes + VmpApplyDftToDftTmpBytes + VecZnxBigAllocBytes@@ -52,8 +52,8 @@ tsk_infos: &TSK,
) -> usize where OUT: GGSWInfos, - KEY: GGLWELayoutInfos, - TSK: GGLWELayoutInfos, + KEY: GGLWEInfos, + TSK: GGLWEInfos, Module<B>: VecZnxDftAllocBytes + VmpApplyDftToDftTmpBytes + VecZnxBigAllocBytes@@ -125,7 +125,7 @@ assert!(scratch.available() >= GGSWCiphertext::automorphism_scratch_space(module, self, lhs, auto_key, tensor_key))
}; // Keyswitch the j-th row of the col 0 - (0..lhs.rows().into()).for_each(|row_i| { + (0..lhs.dnum().into()).for_each(|row_i| { // Key-switch column 0, i.e. // col 0: (-(a0s0 + a1s1 + a2s2) + M[i], a0, a1, a2) -> (-(a0pi^-1(s0) + a1pi^-1(s1) + a2pi^-1(s2)) + M[i], a0, a1, a2) self.at_mut(row_i, 0)@@ -160,7 +160,7 @@ + VecZnxNormalize<B>,
Scratch<B>: TakeVecZnxDft<B> + ScratchAvailable + TakeVecZnxBig<B> + TakeVecZnx, { // Keyswitch the j-th row of the col 0 - (0..self.rows().into()).for_each(|row_i| { + (0..self.dnum().into()).for_each(|row_i| { // Key-switch column 0, i.e. // col 0: (-(a0s0 + a1s1 + a2s2) + M[i], a0, a1, a2) -> (-(a0pi^-1(s0) + a1pi^-1(s1) + a2pi^-1(s2)) + M[i], a0, a1, a2) self.at_mut(row_i, 0)
@@ -8,7 +8,7 @@ },
layouts::{Backend, DataMut, DataRef, Module, Scratch, VecZnxBig}, }; -use crate::layouts::{GGLWELayoutInfos, GLWECiphertext, GLWEInfos, LWEInfos, prepared::GGLWEAutomorphismKeyPrepared}; +use crate::layouts::{GGLWEInfos, GLWECiphertext, GLWEInfos, LWEInfos, prepared::GGLWEAutomorphismKeyPrepared}; impl GLWECiphertext<Vec<u8>> { pub fn automorphism_scratch_space<B: Backend, OUT, IN, KEY>(@@ -20,7 +20,7 @@ ) -> usize
where OUT: GLWEInfos, IN: GLWEInfos, - KEY: GGLWELayoutInfos, + KEY: GGLWEInfos, Module<B>: VecZnxDftAllocBytes + VmpApplyDftToDftTmpBytes + VecZnxBigNormalizeTmpBytes + VecZnxNormalizeTmpBytes, { Self::keyswitch_scratch_space(module, out_infos, in_infos, key_infos)@@ -29,7 +29,7 @@
pub fn automorphism_inplace_scratch_space<B: Backend, OUT, KEY>(module: &Module<B>, out_infos: &OUT, key_infos: &KEY) -> usize where OUT: GLWEInfos, - KEY: GGLWELayoutInfos, + KEY: GGLWEInfos, Module<B>: VecZnxDftAllocBytes + VmpApplyDftToDftTmpBytes + VecZnxBigNormalizeTmpBytes + VecZnxNormalizeTmpBytes, { Self::keyswitch_inplace_scratch_space(module, out_infos, key_infos)
@@ -10,7 +10,7 @@
use crate::{ TakeGLWECt, layouts::{ - GGLWELayoutInfos, GLWECiphertext, GLWECiphertextLayout, GLWEInfos, LWECiphertext, LWEInfos, Rank, + GGLWEInfos, GLWECiphertext, GLWECiphertextLayout, GLWEInfos, LWECiphertext, LWEInfos, Rank, prepared::GLWEToLWESwitchingKeyPrepared, }, };@@ -25,7 +25,7 @@ ) -> usize
where OUT: LWEInfos, IN: GLWEInfos, - KEY: GGLWELayoutInfos, + KEY: GGLWEInfos, Module<B>: VecZnxDftAllocBytes + VmpApplyDftToDftTmpBytes + VecZnxBigNormalizeTmpBytes + VecZnxNormalizeTmpBytes, { let glwe_layout: GLWECiphertextLayout = GLWECiphertextLayout {
@@ -10,7 +10,7 @@
use crate::{ TakeGLWECt, layouts::{ - GGLWELayoutInfos, GLWECiphertext, GLWECiphertextLayout, GLWEInfos, LWECiphertext, LWEInfos, + GGLWEInfos, GLWECiphertext, GLWECiphertextLayout, GLWEInfos, LWECiphertext, LWEInfos, prepared::LWEToGLWESwitchingKeyPrepared, }, };@@ -25,7 +25,7 @@ ) -> usize
where OUT: GLWEInfos, IN: LWEInfos, - KEY: GGLWELayoutInfos, + KEY: GGLWEInfos, Module<B>: VecZnxDftAllocBytes + VmpApplyDftToDftTmpBytes + VecZnxBigNormalizeTmpBytes + VecZnxNormalizeTmpBytes, { let ct: usize = GLWECiphertext::alloc_bytes_with(
@@ -12,7 +12,7 @@
use crate::{ TakeGLWESecret, TakeGLWESecretPrepared, layouts::{ - GGLWELayoutInfos, GLWEInfos, GLWESecret, LWEInfos, + GGLWEInfos, GLWEInfos, GLWESecret, LWEInfos, compressed::{GGLWEAutomorphismKeyCompressed, GGLWESwitchingKeyCompressed}, }, };@@ -20,7 +20,7 @@
impl GGLWEAutomorphismKeyCompressed<Vec<u8>> { pub fn encrypt_sk_scratch_space<B: Backend, A>(module: &Module<B>, infos: &A) -> usize where - A: GGLWELayoutInfos, + A: GGLWEInfos, Module<B>: VecZnxNormalizeTmpBytes + VecZnxDftAllocBytes + VecZnxNormalizeTmpBytes + SvpPPolAllocBytes, { assert_eq!(module.n() as u32, infos.n());
@@ -11,13 +11,13 @@
use crate::{ TakeGLWEPt, encryption::{SIGMA, glwe_encrypt_sk_internal}, - layouts::{GGLWECiphertext, GGLWELayoutInfos, LWEInfos, compressed::GGLWECiphertextCompressed, prepared::GLWESecretPrepared}, + layouts::{GGLWECiphertext, GGLWEInfos, LWEInfos, compressed::GGLWECiphertextCompressed, prepared::GLWESecretPrepared}, }; impl GGLWECiphertextCompressed<Vec<u8>> { pub fn encrypt_sk_scratch_space<B: Backend, A>(module: &Module<B>, infos: &A) -> usize where - A: GGLWELayoutInfos, + A: GGLWEInfos, Module<B>: VecZnxNormalizeTmpBytes + VecZnxDftAllocBytes + VecZnxNormalizeTmpBytes, { GGLWECiphertext::encrypt_sk_scratch_space(module, infos)@@ -78,18 +78,18 @@ scratch.available(),
GGLWECiphertextCompressed::encrypt_sk_scratch_space(module, self) ); assert!( - self.rows().0 * self.digits().0 * self.base2k().0 <= self.k().0, - "self.rows() : {} * self.digits() : {} * self.base2k() : {} = {} >= self.k() = {}", - self.rows(), - self.digits(), + self.dnum().0 * self.dsize().0 * self.base2k().0 <= self.k().0, + "self.dnum() : {} * self.dsize() : {} * self.base2k() : {} = {} >= self.k() = {}", + self.dnum(), + self.dsize(), self.base2k(), - self.rows().0 * self.digits().0 * self.base2k().0, + self.dnum().0 * self.dsize().0 * self.base2k().0, self.k() ); } - let rows: usize = self.rows().into(); - let digits: usize = self.digits().into(); + let dnum: usize = self.dnum().into(); + let dsize: usize = self.dsize().into(); let base2k: usize = self.base2k().into(); let rank_in: usize = self.rank_in().into(); let cols: usize = (self.rank_out() + 1).into();@@ -98,26 +98,20 @@ let mut source_xa = Source::new(seed);
let (mut tmp_pt, scrach_1) = scratch.take_glwe_pt(self); (0..rank_in).for_each(|col_i| { - (0..rows).for_each(|row_i| { + (0..dnum).for_each(|d_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_add_scalar_inplace(&mut tmp_pt.data, 0, (dsize - 1) + d_i * dsize, pt, col_i); module.vec_znx_normalize_inplace(base2k, &mut tmp_pt.data, 0, scrach_1); let (seed, mut source_xa_tmp) = source_xa.branch(); - self.seed[col_i * rows + row_i] = seed; + self.seed[col_i * dnum + d_i] = seed; glwe_encrypt_sk_internal( module, self.base2k().into(), self.k().into(), - &mut self.at_mut(row_i, col_i).data, + &mut self.at_mut(d_i, col_i).data, cols, true, Some((&tmp_pt, 0)),
@@ -12,7 +12,7 @@
use crate::{ TakeGLWESecretPrepared, layouts::{ - Degree, GGLWECiphertext, GGLWELayoutInfos, GLWEInfos, GLWESecret, LWEInfos, compressed::GGLWESwitchingKeyCompressed, + Degree, GGLWECiphertext, GGLWEInfos, GLWEInfos, GLWESecret, LWEInfos, compressed::GGLWESwitchingKeyCompressed, prepared::GLWESecretPrepared, }, };@@ -20,7 +20,7 @@
impl GGLWESwitchingKeyCompressed<Vec<u8>> { pub fn encrypt_sk_scratch_space<B: Backend, A>(module: &Module<B>, infos: &A) -> usize where - A: GGLWELayoutInfos, + A: GGLWEInfos, Module<B>: VecZnxNormalizeTmpBytes + VecZnxDftAllocBytes + VecZnxNormalizeTmpBytes + SvpPPolAllocBytes, { (GGLWECiphertext::encrypt_sk_scratch_space(module, infos) | ScalarZnx::alloc_bytes(module.n(), 1))
@@ -12,7 +12,7 @@
use crate::{ TakeGLWESecret, TakeGLWESecretPrepared, layouts::{ - GGLWELayoutInfos, GGLWETensorKey, GLWEInfos, GLWESecret, LWEInfos, Rank, compressed::GGLWETensorKeyCompressed, + GGLWEInfos, GGLWETensorKey, GLWEInfos, GLWESecret, LWEInfos, Rank, compressed::GGLWETensorKeyCompressed, prepared::Prepare, }, };@@ -20,7 +20,7 @@
impl GGLWETensorKeyCompressed<Vec<u8>> { pub fn encrypt_sk_scratch_space<B: Backend, A>(module: &Module<B>, infos: &A) -> usize where - A: GGLWELayoutInfos, + A: GGLWEInfos, Module<B>: SvpPPolAllocBytes + VecZnxNormalizeTmpBytes + VecZnxDftAllocBytes + VecZnxNormalizeTmpBytes + VecZnxBigAllocBytes, {
@@ -65,19 +65,19 @@
let base2k: usize = self.base2k().into(); let rank: usize = self.rank().into(); let cols: usize = rank + 1; - let digits: usize = self.digits().into(); + let dsize: usize = self.dsize().into(); let (mut tmp_pt, scratch_1) = scratch.take_glwe_pt(&self.glwe_layout()); let mut source = Source::new(seed_xa); - self.seed = vec![[0u8; 32]; self.rows().0 as usize * cols]; + self.seed = vec![[0u8; 32]; self.dnum().0 as usize * cols]; - (0..self.rows().into()).for_each(|row_i| { + (0..self.dnum().into()).for_each(|row_i| { tmp_pt.data.zero(); // Adds the scalar_znx_pt to the i-th limb of the vec_znx_pt - module.vec_znx_add_scalar_inplace(&mut tmp_pt.data, 0, (digits - 1) + row_i * digits, pt, 0); + module.vec_znx_add_scalar_inplace(&mut tmp_pt.data, 0, (dsize - 1) + row_i * dsize, pt, 0); module.vec_znx_normalize_inplace(base2k, &mut tmp_pt.data, 0, scratch_1); (0..rank + 1).for_each(|col_j| {
@@ -11,13 +11,13 @@ };
use crate::{ TakeGLWESecret, TakeGLWESecretPrepared, - layouts::{GGLWEAutomorphismKey, GGLWELayoutInfos, GGLWESwitchingKey, GLWEInfos, GLWESecret, LWEInfos}, + layouts::{GGLWEAutomorphismKey, GGLWEInfos, GGLWESwitchingKey, GLWEInfos, GLWESecret, LWEInfos}, }; impl GGLWEAutomorphismKey<Vec<u8>> { pub fn encrypt_sk_scratch_space<B: Backend, A>(module: &Module<B>, infos: &A) -> usize where - A: GGLWELayoutInfos, + A: GGLWEInfos, Module<B>: SvpPPolAllocBytes + VecZnxNormalizeTmpBytes + VecZnxDftAllocBytes + VecZnxNormalizeTmpBytes, { assert_eq!(@@ -30,7 +30,7 @@ }
pub fn encrypt_pk_scratch_space<B: Backend, A>(module: &Module<B>, _infos: &A) -> usize where - A: GGLWELayoutInfos, + A: GGLWEInfos, { assert_eq!( _infos.rank_in(),
@@ -10,13 +10,13 @@ };
use crate::{ TakeGLWEPt, - layouts::{GGLWECiphertext, GGLWELayoutInfos, GLWECiphertext, GLWEPlaintext, LWEInfos, prepared::GLWESecretPrepared}, + layouts::{GGLWECiphertext, GGLWEInfos, GLWECiphertext, GLWEPlaintext, LWEInfos, prepared::GLWESecretPrepared}, }; impl GGLWECiphertext<Vec<u8>> { pub fn encrypt_sk_scratch_space<B: Backend, A>(module: &Module<B>, infos: &A) -> usize where - A: GGLWELayoutInfos, + A: GGLWEInfos, Module<B>: VecZnxNormalizeTmpBytes + VecZnxDftAllocBytes + VecZnxNormalizeTmpBytes, { GLWECiphertext::encrypt_sk_scratch_space(module, &infos.glwe_layout())@@ -25,7 +25,7 @@ }
pub fn encrypt_pk_scratch_space<B: Backend, A>(_module: &Module<B>, _infos: &A) -> usize where - A: GGLWELayoutInfos, + A: GGLWEInfos, { unimplemented!() }@@ -87,18 +87,18 @@ self.size(),
GGLWECiphertext::encrypt_sk_scratch_space(module, self) ); assert!( - self.rows().0 * self.digits().0 * self.base2k().0 <= self.k().0, - "self.rows() : {} * self.digits() : {} * self.base2k() : {} = {} >= self.k() = {}", - self.rows(), - self.digits(), + self.dnum().0 * self.dsize().0 * self.base2k().0 <= self.k().0, + "self.dnum() : {} * self.dsize() : {} * self.base2k() : {} = {} >= self.k() = {}", + self.dnum(), + self.dsize(), self.base2k(), - self.rows().0 * self.digits().0 * self.base2k().0, + self.dnum().0 * self.dsize().0 * self.base2k().0, self.k() ); } - let rows: usize = self.rows().into(); - let digits: usize = self.digits().into(); + let dnum: usize = self.dnum().into(); + let dsize: usize = self.dsize().into(); let base2k: usize = self.base2k().into(); let rank_in: usize = self.rank_in().into();@@ -115,16 +115,10 @@ //
// (-(a*s) + s0, a) // (-(b*s) + s1, b) (0..rank_in).for_each(|col_i| { - (0..rows).for_each(|row_i| { + (0..dnum).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_add_scalar_inplace(&mut tmp_pt.data, 0, (dsize - 1) + row_i * dsize, pt, col_i); module.vec_znx_normalize_inplace(base2k, &mut tmp_pt.data, 0, scrach_1); // rlwe encrypt of vec_znx_pt into vec_znx_ct
@@ -12,15 +12,14 @@
use crate::{ TakeGLWESecretPrepared, layouts::{ - Degree, GGLWECiphertext, GGLWELayoutInfos, GGLWESwitchingKey, GLWEInfos, GLWESecret, LWEInfos, - prepared::GLWESecretPrepared, + Degree, GGLWECiphertext, GGLWEInfos, GGLWESwitchingKey, GLWEInfos, GLWESecret, LWEInfos, prepared::GLWESecretPrepared, }, }; impl GGLWESwitchingKey<Vec<u8>> { pub fn encrypt_sk_scratch_space<B: Backend, A>(module: &Module<B>, infos: &A) -> usize where - A: GGLWELayoutInfos, + A: GGLWEInfos, Module<B>: SvpPPolAllocBytes + VecZnxNormalizeTmpBytes + VecZnxDftAllocBytes + VecZnxNormalizeTmpBytes, { (GGLWECiphertext::encrypt_sk_scratch_space(module, infos) | ScalarZnx::alloc_bytes(module.n(), 1))@@ -30,7 +29,7 @@ }
pub fn encrypt_pk_scratch_space<B: Backend, A>(module: &Module<B>, _infos: &A) -> usize where - A: GGLWELayoutInfos, + A: GGLWEInfos, { GGLWECiphertext::encrypt_pk_scratch_space(module, _infos) }
@@ -12,7 +12,7 @@
use crate::{ TakeGLWESecret, TakeGLWESecretPrepared, layouts::{ - Degree, GGLWELayoutInfos, GGLWESwitchingKey, GGLWETensorKey, GLWEInfos, GLWESecret, LWEInfos, Rank, + Degree, GGLWEInfos, GGLWESwitchingKey, GGLWETensorKey, GLWEInfos, GLWESecret, LWEInfos, Rank, prepared::{GLWESecretPrepared, Prepare}, }, };@@ -20,7 +20,7 @@
impl GGLWETensorKey<Vec<u8>> { pub fn encrypt_sk_scratch_space<B: Backend, A>(module: &Module<B>, infos: &A) -> usize where - A: GGLWELayoutInfos, + A: GGLWEInfos, Module<B>: SvpPPolAllocBytes + VecZnxNormalizeTmpBytes + VecZnxDftAllocBytes + VecZnxNormalizeTmpBytes + VecZnxBigAllocBytes, {
@@ -65,15 +65,15 @@ }
let base2k: usize = self.base2k().into(); let rank: usize = self.rank().into(); - let digits: usize = self.digits().into(); + let dsize: usize = self.dsize().into(); let (mut tmp_pt, scratch_1) = scratch.take_glwe_pt(&self.glwe_layout()); - (0..self.rows().into()).for_each(|row_i| { + (0..self.dnum().into()).for_each(|row_i| { tmp_pt.data.zero(); // Adds the scalar_znx_pt to the i-th limb of the vec_znx_pt - module.vec_znx_add_scalar_inplace(&mut tmp_pt.data, 0, (digits - 1) + row_i * digits, pt, 0); + module.vec_znx_add_scalar_inplace(&mut tmp_pt.data, 0, (dsize - 1) + row_i * dsize, pt, 0); module.vec_znx_normalize_inplace(base2k, &mut tmp_pt.data, 0, scratch_1); (0..rank + 1).for_each(|col_j| {
@@ -11,16 +11,13 @@ };
use crate::{ TakeGLWESecret, TakeGLWESecretPrepared, - layouts::{ - GGLWELayoutInfos, GGLWESwitchingKey, GLWESecret, GLWEToLWESwitchingKey, LWEInfos, LWESecret, Rank, - prepared::GLWESecretPrepared, - }, + layouts::{GGLWEInfos, GGLWESwitchingKey, GLWESecret, GLWEToLWEKey, LWEInfos, LWESecret, Rank, prepared::GLWESecretPrepared}, }; -impl GLWEToLWESwitchingKey<Vec<u8>> { +impl GLWEToLWEKey<Vec<u8>> { pub fn encrypt_sk_scratch_space<B: Backend, A>(module: &Module<B>, infos: &A) -> usize where - A: GGLWELayoutInfos, + A: GGLWEInfos, Module<B>: SvpPPolAllocBytes + VecZnxNormalizeTmpBytes + VecZnxDftAllocBytes + VecZnxNormalizeTmpBytes, { GLWESecretPrepared::alloc_bytes_with(module, infos.rank_in())@@ -29,7 +26,7 @@ | GLWESecret::alloc_bytes_with(infos.n(), infos.rank_in()))
} } -impl<D: DataMut> GLWEToLWESwitchingKey<D> { +impl<D: DataMut> GLWEToLWEKey<D> { #[allow(clippy::too_many_arguments)] pub fn encrypt_sk<DLwe, DGlwe, B: Backend>( &mut self,
@@ -12,7 +12,7 @@
use crate::{ TakeGLWESecret, TakeGLWESecretPrepared, layouts::{ - Degree, GGLWELayoutInfos, GGLWESwitchingKey, GLWESecret, LWEInfos, LWESecret, LWESwitchingKey, Rank, + Degree, GGLWEInfos, GGLWESwitchingKey, GLWESecret, LWEInfos, LWESecret, LWESwitchingKey, Rank, prepared::GLWESecretPrepared, }, };@@ -20,13 +20,13 @@
impl LWESwitchingKey<Vec<u8>> { pub fn encrypt_sk_scratch_space<B: Backend, A>(module: &Module<B>, infos: &A) -> usize where - A: GGLWELayoutInfos, + A: GGLWEInfos, Module<B>: SvpPPolAllocBytes + VecZnxNormalizeTmpBytes + VecZnxDftAllocBytes + VecZnxNormalizeTmpBytes, { debug_assert_eq!( - infos.digits().0, + infos.dsize().0, 1, - "digits > 1 is not supported for LWESwitchingKey" + "dsize > 1 is not supported for LWESwitchingKey" ); debug_assert_eq!( infos.rank_in().0,
@@ -11,13 +11,13 @@ };
use crate::{ TakeGLWESecret, TakeGLWESecretPrepared, - layouts::{Degree, GGLWELayoutInfos, GGLWESwitchingKey, GLWESecret, LWEInfos, LWESecret, LWEToGLWESwitchingKey, Rank}, + layouts::{Degree, GGLWEInfos, GGLWESwitchingKey, GLWESecret, LWEInfos, LWESecret, LWEToGLWESwitchingKey, Rank}, }; impl LWEToGLWESwitchingKey<Vec<u8>> { pub fn encrypt_sk_scratch_space<B: Backend, A>(module: &Module<B>, infos: &A) -> usize where - A: GGLWELayoutInfos, + A: GGLWEInfos, Module<B>: SvpPPolAllocBytes + VecZnxNormalizeTmpBytes + VecZnxDftAllocBytes + VecZnxNormalizeTmpBytes, { debug_assert_eq!(
@@ -7,7 +7,7 @@ },
layouts::{Backend, DataMut, DataRef, Module, Scratch}, }; -use crate::layouts::{GGLWEAutomorphismKey, GGLWELayoutInfos, GGLWESwitchingKey, GGSWInfos, prepared::GGSWCiphertextPrepared}; +use crate::layouts::{GGLWEAutomorphismKey, GGLWEInfos, GGLWESwitchingKey, GGSWInfos, prepared::GGSWCiphertextPrepared}; impl GGLWEAutomorphismKey<Vec<u8>> { pub fn external_product_scratch_space<B: Backend, OUT, IN, GGSW>(@@ -17,8 +17,8 @@ in_infos: &IN,
ggsw_infos: &GGSW, ) -> usize where - OUT: GGLWELayoutInfos, - IN: GGLWELayoutInfos, + OUT: GGLWEInfos, + IN: GGLWEInfos, GGSW: GGSWInfos, Module<B>: VecZnxDftAllocBytes + VmpApplyDftToDftTmpBytes + VecZnxNormalizeTmpBytes, {@@ -31,7 +31,7 @@ out_infos: &OUT,
ggsw_infos: &GGSW, ) -> usize where - OUT: GGLWELayoutInfos, + OUT: GGLWEInfos, GGSW: GGSWInfos, Module<B>: VecZnxDftAllocBytes + VmpApplyDftToDftTmpBytes + VecZnxNormalizeTmpBytes, {
@@ -7,7 +7,7 @@ },
layouts::{Backend, DataMut, DataRef, Module, Scratch, ZnxZero}, }; -use crate::layouts::{GGLWELayoutInfos, GGLWESwitchingKey, GGSWInfos, GLWECiphertext, prepared::GGSWCiphertextPrepared}; +use crate::layouts::{GGLWEInfos, GGLWESwitchingKey, GGSWInfos, GLWECiphertext, prepared::GGSWCiphertextPrepared}; impl GGLWESwitchingKey<Vec<u8>> { pub fn external_product_scratch_space<B: Backend, OUT, IN, GGSW>(@@ -17,8 +17,8 @@ in_infos: &IN,
ggsw_infos: &GGSW, ) -> usize where - OUT: GGLWELayoutInfos, - IN: GGLWELayoutInfos, + OUT: GGLWEInfos, + IN: GGLWEInfos, GGSW: GGSWInfos, Module<B>: VecZnxDftAllocBytes + VmpApplyDftToDftTmpBytes + VecZnxNormalizeTmpBytes, {@@ -36,7 +36,7 @@ out_infos: &OUT,
ggsw_infos: &GGSW, ) -> usize where - OUT: GGLWELayoutInfos, + OUT: GGLWEInfos, GGSW: GGSWInfos, Module<B>: VecZnxDftAllocBytes + VmpApplyDftToDftTmpBytes + VecZnxNormalizeTmpBytes, {@@ -91,13 +91,13 @@ );
} (0..self.rank_in().into()).for_each(|col_i| { - (0..self.rows().into()).for_each(|row_j| { + (0..self.dnum().into()).for_each(|row_j| { self.at_mut(row_j, col_i) .external_product(module, &lhs.at(row_j, col_i), rhs, scratch); }); }); - (self.rows().min(lhs.rows()).into()..self.rows().into()).for_each(|row_i| { + (self.dnum().min(lhs.dnum()).into()..self.dnum().into()).for_each(|row_i| { (0..self.rank_in().into()).for_each(|col_j| { self.at_mut(row_i, col_j).data.zero(); });@@ -135,7 +135,7 @@ );
} (0..self.rank_in().into()).for_each(|col_i| { - (0..self.rows().into()).for_each(|row_j| { + (0..self.dnum().into()).for_each(|row_j| { self.at_mut(row_j, col_i) .external_product_inplace(module, rhs, scratch); });
@@ -89,14 +89,14 @@
assert!(scratch.available() >= GGSWCiphertext::external_product_scratch_space(module, self, lhs, rhs)) } - let min_rows: usize = self.rows().min(lhs.rows()).into(); + let min_dnum: usize = self.dnum().min(lhs.dnum()).into(); (0..(self.rank() + 1).into()).for_each(|col_i| { - (0..min_rows).for_each(|row_j| { + (0..min_dnum).for_each(|row_j| { self.at_mut(row_j, col_i) .external_product(module, &lhs.at(row_j, col_i), rhs, scratch); }); - (min_rows..self.rows().into()).for_each(|row_i| { + (min_dnum..self.dnum().into()).for_each(|row_i| { self.at_mut(row_i, col_i).data.zero(); }); });@@ -134,7 +134,7 @@ );
} (0..(self.rank() + 1).into()).for_each(|col_i| { - (0..self.rows().into()).for_each(|row_j| { + (0..self.dnum().into()).for_each(|row_j| { self.at_mut(row_j, col_i) .external_product_inplace(module, rhs, scratch); });
@@ -7,7 +7,13 @@ },
layouts::{Backend, DataMut, DataRef, DataViewMut, Module, Scratch, VecZnx, VecZnxBig}, }; -use crate::layouts::{GGSWInfos, GLWECiphertext, GLWEInfos, LWEInfos, prepared::GGSWCiphertextPrepared}; +use crate::{ + GLWEExternalProduct, GLWEExternalProductInplace, + layouts::{ + GGSWInfos, GLWECiphertext, GLWECiphertextToMut, GLWECiphertextToRef, GLWEInfos, LWEInfos, + prepared::{GGSWCiphertextPrepared, GGSWCiphertextPreparedToRef}, + }, +}; impl GLWECiphertext<Vec<u8>> { #[allow(clippy::too_many_arguments)]@@ -26,7 +32,7 @@ {
let in_size: usize = in_infos .k() .div_ceil(apply_infos.base2k()) - .div_ceil(apply_infos.digits().into()) as usize; + .div_ceil(apply_infos.dsize().into()) as usize; let out_size: usize = out_infos.size(); let ggsw_size: usize = apply_infos.size(); let res_dft: usize = module.vec_znx_dft_alloc_bytes((apply_infos.rank() + 1).into(), ggsw_size);@@ -71,233 +77,268 @@ lhs: &GLWECiphertext<DataLhs>,
rhs: &GGSWCiphertextPrepared<DataRhs, B>, scratch: &mut Scratch<B>, ) where - Module<B>: VecZnxDftAllocBytes - + VmpApplyDftToDftTmpBytes - + VecZnxNormalizeTmpBytes - + VecZnxDftApply<B> - + VmpApplyDftToDft<B> - + VmpApplyDftToDftAdd<B> - + VecZnxIdftApplyConsume<B> - + VecZnxBigNormalize<B> - + VecZnxNormalize<B>, - Scratch<B>: TakeVecZnxDft<B> + ScratchAvailable + TakeVecZnx, + Module<B>: GLWEExternalProduct<B>, { - let basek_in: usize = lhs.base2k().into(); + module.external_product(self, lhs, rhs, scratch); + } + + pub fn external_product_inplace<DataRhs: DataRef, B: Backend>( + &mut self, + module: &Module<B>, + rhs: &GGSWCiphertextPrepared<DataRhs, B>, + scratch: &mut Scratch<B>, + ) where + Module<B>: GLWEExternalProductInplace<B>, + { + module.external_product_inplace(self, rhs, scratch); + } +} + +impl<BE: Backend> GLWEExternalProductInplace<BE> for Module<BE> +where + Module<BE>: VecZnxDftAllocBytes + + VmpApplyDftToDftTmpBytes + + VecZnxNormalizeTmpBytes + + VecZnxDftApply<BE> + + VmpApplyDftToDft<BE> + + VmpApplyDftToDftAdd<BE> + + VecZnxIdftApplyConsume<BE> + + VecZnxBigNormalize<BE> + + VecZnxNormalize<BE>, + Scratch<BE>: TakeVecZnxDft<BE> + ScratchAvailable + TakeVecZnx, +{ + fn external_product_inplace<R, D>(&self, res: &mut R, ggsw: &D, scratch: &mut Scratch<BE>) + where + R: GLWECiphertextToMut, + D: GGSWCiphertextPreparedToRef<BE>, + { + let res: &mut GLWECiphertext<&mut [u8]> = &mut res.to_mut(); + let rhs: &GGSWCiphertextPrepared<&[u8], BE> = &ggsw.to_ref(); + + let basek_in: usize = res.base2k().into(); let basek_ggsw: usize = rhs.base2k().into(); - let basek_out: usize = self.base2k().into(); #[cfg(debug_assertions)] { use poulpy_hal::api::ScratchAvailable; - assert_eq!(rhs.rank(), lhs.rank()); - assert_eq!(rhs.rank(), self.rank()); - assert_eq!(rhs.n(), self.n()); - assert_eq!(lhs.n(), self.n()); - assert!(scratch.available() >= GLWECiphertext::external_product_scratch_space(module, self, lhs, rhs)); + assert_eq!(rhs.rank(), res.rank()); + assert_eq!(rhs.n(), res.n()); + assert!(scratch.available() >= GLWECiphertext::external_product_inplace_scratch_space(self, res, rhs)); } let cols: usize = (rhs.rank() + 1).into(); - let digits: usize = rhs.digits().into(); + let dsize: usize = rhs.dsize().into(); + let a_size: usize = (res.size() * basek_in).div_ceil(basek_ggsw); - let a_size: usize = (lhs.size() * basek_in).div_ceil(basek_ggsw); - - let (mut res_dft, scratch_1) = scratch.take_vec_znx_dft(self.n().into(), cols, rhs.size()); // Todo optimise - let (mut a_dft, scratch_2) = scratch_1.take_vec_znx_dft(self.n().into(), cols, a_size.div_ceil(digits)); + let (mut res_dft, scratch_1) = scratch.take_vec_znx_dft(res.n().into(), cols, rhs.size()); // Todo optimise + let (mut a_dft, scratch_2) = scratch_1.take_vec_znx_dft(res.n().into(), cols, a_size.div_ceil(dsize)); a_dft.data_mut().fill(0); if basek_in == basek_ggsw { - for di in 0..digits { - // (lhs.size() + di) / digits = (a - (digit - di - 1)).div_ceil(digits) - a_dft.set_size((lhs.size() + di) / digits); + for di in 0..dsize { + // (lhs.size() + di) / dsize = (a - (digit - di - 1)).div_ceil(dsize) + a_dft.set_size((res.size() + di) / dsize); - // Small optimization for digits > 2 + // Small optimization for dsize > 2 // VMP produce some error e, and since we aggregate vmp * 2^{di * B}, then - // we also aggregate ei * 2^{di * B}, with the largest error being ei * 2^{(digits-1) * B}. - // As such we can ignore the last digits-2 limbs safely of the sum of vmp products. - // It is possible to further ignore the last digits-1 limbs, but this introduce + // we also aggregate ei * 2^{di * B}, with the largest error being ei * 2^{(dsize-1) * B}. + // As such we can ignore the last dsize-2 limbs safely of the sum of vmp products. + // It is possible to further ignore the last dsize-1 limbs, but this introduce // ~0.5 to 1 bit of additional noise, and thus not chosen here to ensure that the same // noise is kept with respect to the ideal functionality. - res_dft.set_size(rhs.size() - ((digits - di) as isize - 2).max(0) as usize); + res_dft.set_size(rhs.size() - ((dsize - di) as isize - 2).max(0) as usize); for j in 0..cols { - module.vec_znx_dft_apply(digits, digits - 1 - di, &mut a_dft, j, &lhs.data, j); + self.vec_znx_dft_apply(dsize, dsize - 1 - di, &mut a_dft, j, &res.data, j); } if di == 0 { - module.vmp_apply_dft_to_dft(&mut res_dft, &a_dft, &rhs.data, scratch_2); + self.vmp_apply_dft_to_dft(&mut res_dft, &a_dft, &rhs.data, scratch_2); } else { - module.vmp_apply_dft_to_dft_add(&mut res_dft, &a_dft, &rhs.data, di, scratch_2); + self.vmp_apply_dft_to_dft_add(&mut res_dft, &a_dft, &rhs.data, di, scratch_2); } } } else { - let (mut a_conv, scratch_3) = scratch_2.take_vec_znx(module.n(), cols, a_size); + let (mut a_conv, scratch_3) = scratch_2.take_vec_znx(self.n(), cols, a_size); for j in 0..cols { - module.vec_znx_normalize( + self.vec_znx_normalize( basek_ggsw, &mut a_conv, j, basek_in, - &lhs.data, + &res.data, j, scratch_3, ); } - for di in 0..digits { - // (lhs.size() + di) / digits = (a - (digit - di - 1)).div_ceil(digits) - a_dft.set_size((a_size + di) / digits); + for di in 0..dsize { + // (lhs.size() + di) / dsize = (a - (digit - di - 1)).div_ceil(dsize) + a_dft.set_size((res.size() + di) / dsize); - // Small optimization for digits > 2 + // Small optimization for dsize > 2 // VMP produce some error e, and since we aggregate vmp * 2^{di * B}, then - // we also aggregate ei * 2^{di * B}, with the largest error being ei * 2^{(digits-1) * B}. - // As such we can ignore the last digits-2 limbs safely of the sum of vmp products. - // It is possible to further ignore the last digits-1 limbs, but this introduce + // we also aggregate ei * 2^{di * B}, with the largest error being ei * 2^{(dsize-1) * B}. + // As such we can ignore the last dsize-2 limbs safely of the sum of vmp products. + // It is possible to further ignore the last dsize-1 limbs, but this introduce // ~0.5 to 1 bit of additional noise, and thus not chosen here to ensure that the same // noise is kept with respect to the ideal functionality. - res_dft.set_size(rhs.size() - ((digits - di) as isize - 2).max(0) as usize); + res_dft.set_size(rhs.size() - ((dsize - di) as isize - 2).max(0) as usize); for j in 0..cols { - module.vec_znx_dft_apply(digits, digits - 1 - di, &mut a_dft, j, &a_conv, j); + self.vec_znx_dft_apply(dsize, dsize - 1 - di, &mut a_dft, j, &res.data, j); } if di == 0 { - module.vmp_apply_dft_to_dft(&mut res_dft, &a_dft, &rhs.data, scratch_3); + self.vmp_apply_dft_to_dft(&mut res_dft, &a_dft, &rhs.data, scratch_2); } else { - module.vmp_apply_dft_to_dft_add(&mut res_dft, &a_dft, &rhs.data, di, scratch_3); + self.vmp_apply_dft_to_dft_add(&mut res_dft, &a_dft, &rhs.data, di, scratch_2); } } } - let res_big: VecZnxBig<&mut [u8], B> = module.vec_znx_idft_apply_consume(res_dft); + let res_big: VecZnxBig<&mut [u8], BE> = self.vec_znx_idft_apply_consume(res_dft); - (0..cols).for_each(|i| { - module.vec_znx_big_normalize( - basek_out, - &mut self.data, - i, + for j in 0..cols { + self.vec_znx_big_normalize( + basek_in, + &mut res.data, + j, basek_ggsw, &res_big, - i, + j, scratch_1, ); - }); + } } +} - pub fn external_product_inplace<DataRhs: DataRef, B: Backend>( - &mut self, - module: &Module<B>, - rhs: &GGSWCiphertextPrepared<DataRhs, B>, - scratch: &mut Scratch<B>, - ) where - Module<B>: VecZnxDftAllocBytes - + VmpApplyDftToDftTmpBytes - + VecZnxNormalizeTmpBytes - + VecZnxDftApply<B> - + VmpApplyDftToDft<B> - + VmpApplyDftToDftAdd<B> - + VecZnxIdftApplyConsume<B> - + VecZnxBigNormalize<B> - + VecZnxNormalize<B>, - Scratch<B>: TakeVecZnxDft<B> + ScratchAvailable + TakeVecZnx, +impl<BE: Backend> GLWEExternalProduct<BE> for Module<BE> +where + Module<BE>: VecZnxDftAllocBytes + + VmpApplyDftToDftTmpBytes + + VecZnxNormalizeTmpBytes + + VecZnxDftApply<BE> + + VmpApplyDftToDft<BE> + + VmpApplyDftToDftAdd<BE> + + VecZnxIdftApplyConsume<BE> + + VecZnxBigNormalize<BE> + + VecZnxNormalize<BE>, + Scratch<BE>: TakeVecZnxDft<BE> + ScratchAvailable + TakeVecZnx, +{ + fn external_product<R, A, D>(&self, res: &mut R, lhs: &A, rhs: &D, scratch: &mut Scratch<BE>) + where + R: GLWECiphertextToMut, + A: GLWECiphertextToRef, + D: GGSWCiphertextPreparedToRef<BE>, { - let basek_in: usize = self.base2k().into(); + let res: &mut GLWECiphertext<&mut [u8]> = &mut res.to_mut(); + let lhs: &GLWECiphertext<&[u8]> = &lhs.to_ref(); + + let rhs: &GGSWCiphertextPrepared<&[u8], BE> = &rhs.to_ref(); + + let basek_in: usize = lhs.base2k().into(); let basek_ggsw: usize = rhs.base2k().into(); + let basek_out: usize = res.base2k().into(); #[cfg(debug_assertions)] { use poulpy_hal::api::ScratchAvailable; - assert_eq!(rhs.rank(), self.rank()); - assert_eq!(rhs.n(), self.n()); - assert!(scratch.available() >= GLWECiphertext::external_product_inplace_scratch_space(module, self, rhs,)); + assert_eq!(rhs.rank(), lhs.rank()); + assert_eq!(rhs.rank(), res.rank()); + assert_eq!(rhs.n(), res.n()); + assert_eq!(lhs.n(), res.n()); + assert!(scratch.available() >= GLWECiphertext::external_product_scratch_space(self, res, lhs, rhs)); } let cols: usize = (rhs.rank() + 1).into(); - let digits: usize = rhs.digits().into(); - let a_size: usize = (self.size() * basek_in).div_ceil(basek_ggsw); + let dsize: usize = rhs.dsize().into(); - let (mut res_dft, scratch_1) = scratch.take_vec_znx_dft(self.n().into(), cols, rhs.size()); // Todo optimise - let (mut a_dft, scratch_2) = scratch_1.take_vec_znx_dft(self.n().into(), cols, a_size.div_ceil(digits)); + let a_size: usize = (lhs.size() * basek_in).div_ceil(basek_ggsw); + + let (mut res_dft, scratch_1) = scratch.take_vec_znx_dft(self.n(), cols, rhs.size()); // Todo optimise + let (mut a_dft, scratch_2) = scratch_1.take_vec_znx_dft(self.n(), cols, a_size.div_ceil(dsize)); a_dft.data_mut().fill(0); if basek_in == basek_ggsw { - for di in 0..digits { - // (lhs.size() + di) / digits = (a - (digit - di - 1)).div_ceil(digits) - a_dft.set_size((self.size() + di) / digits); + for di in 0..dsize { + // (lhs.size() + di) / dsize = (a - (digit - di - 1)).div_ceil(dsize) + a_dft.set_size((lhs.size() + di) / dsize); - // Small optimization for digits > 2 + // Small optimization for dsize > 2 // VMP produce some error e, and since we aggregate vmp * 2^{di * B}, then - // we also aggregate ei * 2^{di * B}, with the largest error being ei * 2^{(digits-1) * B}. - // As such we can ignore the last digits-2 limbs safely of the sum of vmp products. - // It is possible to further ignore the last digits-1 limbs, but this introduce + // we also aggregate ei * 2^{di * B}, with the largest error being ei * 2^{(dsize-1) * B}. + // As such we can ignore the last dsize-2 limbs safely of the sum of vmp products. + // It is possible to further ignore the last dsize-1 limbs, but this introduce // ~0.5 to 1 bit of additional noise, and thus not chosen here to ensure that the same // noise is kept with respect to the ideal functionality. - res_dft.set_size(rhs.size() - ((digits - di) as isize - 2).max(0) as usize); + res_dft.set_size(rhs.size() - ((dsize - di) as isize - 2).max(0) as usize); for j in 0..cols { - module.vec_znx_dft_apply(digits, digits - 1 - di, &mut a_dft, j, &self.data, j); + self.vec_znx_dft_apply(dsize, dsize - 1 - di, &mut a_dft, j, &lhs.data, j); } if di == 0 { - module.vmp_apply_dft_to_dft(&mut res_dft, &a_dft, &rhs.data, scratch_2); + self.vmp_apply_dft_to_dft(&mut res_dft, &a_dft, &rhs.data, scratch_2); } else { - module.vmp_apply_dft_to_dft_add(&mut res_dft, &a_dft, &rhs.data, di, scratch_2); + self.vmp_apply_dft_to_dft_add(&mut res_dft, &a_dft, &rhs.data, di, scratch_2); } } } else { - let (mut a_conv, scratch_3) = scratch_2.take_vec_znx(module.n(), cols, a_size); + let (mut a_conv, scratch_3) = scratch_2.take_vec_znx(self.n(), cols, a_size); for j in 0..cols { - module.vec_znx_normalize( + self.vec_znx_normalize( basek_ggsw, &mut a_conv, j, basek_in, - &self.data, + &lhs.data, j, scratch_3, ); } - for di in 0..digits { - // (lhs.size() + di) / digits = (a - (digit - di - 1)).div_ceil(digits) - a_dft.set_size((self.size() + di) / digits); + for di in 0..dsize { + // (lhs.size() + di) / dsize = (a - (digit - di - 1)).div_ceil(dsize) + a_dft.set_size((a_size + di) / dsize); - // Small optimization for digits > 2 + // Small optimization for dsize > 2 // VMP produce some error e, and since we aggregate vmp * 2^{di * B}, then - // we also aggregate ei * 2^{di * B}, with the largest error being ei * 2^{(digits-1) * B}. - // As such we can ignore the last digits-2 limbs safely of the sum of vmp products. - // It is possible to further ignore the last digits-1 limbs, but this introduce + // we also aggregate ei * 2^{di * B}, with the largest error being ei * 2^{(dsize-1) * B}. + // As such we can ignore the last dsize-2 limbs safely of the sum of vmp products. + // It is possible to further ignore the last dsize-1 limbs, but this introduce // ~0.5 to 1 bit of additional noise, and thus not chosen here to ensure that the same // noise is kept with respect to the ideal functionality. - res_dft.set_size(rhs.size() - ((digits - di) as isize - 2).max(0) as usize); + res_dft.set_size(rhs.size() - ((dsize - di) as isize - 2).max(0) as usize); for j in 0..cols { - module.vec_znx_dft_apply(digits, digits - 1 - di, &mut a_dft, j, &self.data, j); + self.vec_znx_dft_apply(dsize, dsize - 1 - di, &mut a_dft, j, &a_conv, j); } if di == 0 { - module.vmp_apply_dft_to_dft(&mut res_dft, &a_dft, &rhs.data, scratch_2); + self.vmp_apply_dft_to_dft(&mut res_dft, &a_dft, &rhs.data, scratch_3); } else { - module.vmp_apply_dft_to_dft_add(&mut res_dft, &a_dft, &rhs.data, di, scratch_2); + self.vmp_apply_dft_to_dft_add(&mut res_dft, &a_dft, &rhs.data, di, scratch_3); } } } - let res_big: VecZnxBig<&mut [u8], B> = module.vec_znx_idft_apply_consume(res_dft); + let res_big: VecZnxBig<&mut [u8], BE> = self.vec_znx_idft_apply_consume(res_dft); - for j in 0..cols { - module.vec_znx_big_normalize( - basek_in, - &mut self.data, - j, + (0..cols).for_each(|i| { + self.vec_znx_big_normalize( + basek_out, + res.data_mut(), + i, basek_ggsw, &res_big, - j, + i, scratch_1, ); - } + }); } }
@@ -1,4 +1,23 @@
+use poulpy_hal::layouts::{Backend, Scratch}; + +use crate::layouts::{GLWECiphertextToMut, GLWECiphertextToRef, prepared::GGSWCiphertextPreparedToRef}; + mod gglwe_atk; mod gglwe_ksk; mod ggsw_ct; mod glwe_ct; + +pub trait GLWEExternalProduct<BE: Backend> { + fn external_product<R, A, D>(&self, res: &mut R, a: &A, ggsw: &D, scratch: &mut Scratch<BE>) + where + R: GLWECiphertextToMut, + A: GLWECiphertextToRef, + D: GGSWCiphertextPreparedToRef<BE>; +} + +pub trait GLWEExternalProductInplace<BE: Backend> { + fn external_product_inplace<R, D>(&self, res: &mut R, ggsw: &D, scratch: &mut Scratch<BE>) + where + R: GLWECiphertextToMut, + D: GGSWCiphertextPreparedToRef<BE>; +}
@@ -4,16 +4,16 @@ use poulpy_hal::{
api::{ ScratchAvailable, TakeVecZnx, TakeVecZnxDft, VecZnxAddInplace, VecZnxAutomorphismInplace, VecZnxBigAddSmallInplace, VecZnxBigAutomorphismInplace, VecZnxBigNormalize, VecZnxBigNormalizeTmpBytes, VecZnxBigSubSmallNegateInplace, VecZnxCopy, - VecZnxDftAllocBytes, VecZnxDftApply, VecZnxIdftApplyConsume, VecZnxNegateInplace, VecZnxNormalize, - VecZnxNormalizeInplace, VecZnxNormalizeTmpBytes, VecZnxRotate, VecZnxRotateInplace, VecZnxRshInplace, VecZnxSub, - VecZnxSubInplace, VmpApplyDftToDft, VmpApplyDftToDftAdd, VmpApplyDftToDftTmpBytes, + VecZnxDftAllocBytes, VecZnxDftApply, VecZnxDftCopy, VecZnxIdftApplyConsume, VecZnxIdftApplyTmpA, VecZnxNegateInplace, + VecZnxNormalize, VecZnxNormalizeInplace, VecZnxNormalizeTmpBytes, VecZnxRotate, VecZnxRotateInplace, VecZnxRshInplace, + VecZnxSub, VecZnxSubInplace, VecZnxSwitchRing, VmpApplyDftToDft, VmpApplyDftToDftAdd, VmpApplyDftToDftTmpBytes, }, layouts::{Backend, DataMut, DataRef, Module, Scratch}, }; use crate::{ GLWEOperations, TakeGLWECt, - layouts::{GGLWELayoutInfos, GLWECiphertext, GLWEInfos, LWEInfos, prepared::GGLWEAutomorphismKeyPrepared}, + layouts::{GGLWEInfos, GLWECiphertext, GLWEInfos, LWEInfos, prepared::GGLWEAutomorphismKeyPrepared}, }; /// [GLWEPacker] enables only the fly GLWE packing@@ -93,7 +93,7 @@ /// Number of scratch space bytes required to call [Self::add].
pub fn scratch_space<B: Backend, OUT, KEY>(module: &Module<B>, out_infos: &OUT, key_infos: &KEY) -> usize where OUT: GLWEInfos, - KEY: GGLWELayoutInfos, + KEY: GGLWEInfos, Module<B>: VecZnxDftAllocBytes + VmpApplyDftToDftTmpBytes + VecZnxBigNormalizeTmpBytes + VecZnxNormalizeTmpBytes, { pack_core_scratch_space(module, out_infos, key_infos)@@ -180,7 +180,7 @@
fn pack_core_scratch_space<B: Backend, OUT, KEY>(module: &Module<B>, out_infos: &OUT, key_infos: &KEY) -> usize where OUT: GLWEInfos, - KEY: GGLWELayoutInfos, + KEY: GGLWEInfos, Module<B>: VecZnxDftAllocBytes + VmpApplyDftToDftTmpBytes + VecZnxBigNormalizeTmpBytes + VecZnxNormalizeTmpBytes, { combine_scratch_space(module, out_infos, key_infos)@@ -271,7 +271,7 @@
fn combine_scratch_space<B: Backend, OUT, KEY>(module: &Module<B>, out_infos: &OUT, key_infos: &KEY) -> usize where OUT: GLWEInfos, - KEY: GGLWELayoutInfos, + KEY: GGLWEInfos, Module<B>: VecZnxDftAllocBytes + VmpApplyDftToDftTmpBytes + VecZnxBigNormalizeTmpBytes + VecZnxNormalizeTmpBytes, { GLWECiphertext::alloc_bytes(out_infos)@@ -390,3 +390,165 @@
acc.value = true; } } + +/// Packs [x_0: GLWE(m_0), x_1: GLWE(m_1), ..., x_i: GLWE(m_i)] +/// to [0: GLWE(m_0 * X^x_0 + m_1 * X^x_1 + ... + m_i * X^x_i)] +pub fn glwe_packing<D: DataMut, ATK, B: Backend>( + module: &Module<B>, + cts: &mut HashMap<usize, &mut GLWECiphertext<D>>, + log_gap_out: usize, + auto_keys: &HashMap<i64, GGLWEAutomorphismKeyPrepared<ATK, B>>, + scratch: &mut Scratch<B>, +) where + ATK: DataRef, + Module<B>: VecZnxRotateInplace<B> + + VecZnxNormalizeInplace<B> + + VecZnxNormalizeTmpBytes + + VecZnxSwitchRing + + VecZnxBigAutomorphismInplace<B> + + VecZnxRshInplace<B> + + VecZnxDftCopy<B> + + VecZnxIdftApplyTmpA<B> + + VecZnxSub + + VecZnxAddInplace + + VecZnxNegateInplace + + VecZnxCopy + + VecZnxSubInplace + + VecZnxDftAllocBytes + + VmpApplyDftToDftTmpBytes + + VecZnxBigNormalizeTmpBytes + + VmpApplyDftToDft<B> + + VmpApplyDftToDftAdd<B> + + VecZnxDftApply<B> + + VecZnxIdftApplyConsume<B> + + VecZnxBigAddSmallInplace<B> + + VecZnxBigNormalize<B> + + VecZnxAutomorphismInplace<B> + + VecZnxBigSubSmallNegateInplace<B> + + VecZnxRotate + + VecZnxNormalize<B>, + Scratch<B>: TakeVecZnx + TakeVecZnxDft<B> + ScratchAvailable, +{ + #[cfg(debug_assertions)] + { + assert!(*cts.keys().max().unwrap() < module.n()) + } + + let log_n: usize = module.log_n(); + + (0..log_n - log_gap_out).for_each(|i| { + let t: usize = (1 << log_n).min(1 << (log_n - 1 - i)); + + let auto_key: &GGLWEAutomorphismKeyPrepared<ATK, B> = if i == 0 { + auto_keys.get(&-1).unwrap() + } else { + auto_keys.get(&module.galois_element(1 << (i - 1))).unwrap() + }; + + (0..t).for_each(|j| { + let mut a: Option<&mut GLWECiphertext<D>> = cts.remove(&j); + let mut b: Option<&mut GLWECiphertext<D>> = cts.remove(&(j + t)); + + pack_internal(module, &mut a, &mut b, i, auto_key, scratch); + + if let Some(a) = a { + cts.insert(j, a); + } else if let Some(b) = b { + cts.insert(j, b); + } + }); + }); +} + +#[allow(clippy::too_many_arguments)] +fn pack_internal<A: DataMut, D: DataMut, DataAK: DataRef, B: Backend>( + module: &Module<B>, + a: &mut Option<&mut GLWECiphertext<A>>, + b: &mut Option<&mut GLWECiphertext<D>>, + i: usize, + auto_key: &GGLWEAutomorphismKeyPrepared<DataAK, B>, + scratch: &mut Scratch<B>, +) where + Module<B>: VecZnxRotateInplace<B> + + VecZnxNormalizeInplace<B> + + VecZnxNormalizeTmpBytes + + VecZnxBigAutomorphismInplace<B> + + VecZnxRshInplace<B> + + VecZnxDftCopy<B> + + VecZnxIdftApplyTmpA<B> + + VecZnxSub + + VecZnxAddInplace + + VecZnxNegateInplace + + VecZnxCopy + + VecZnxSubInplace + + VecZnxDftAllocBytes + + VmpApplyDftToDftTmpBytes + + VecZnxBigNormalizeTmpBytes + + VmpApplyDftToDft<B> + + VmpApplyDftToDftAdd<B> + + VecZnxDftApply<B> + + VecZnxIdftApplyConsume<B> + + VecZnxBigAddSmallInplace<B> + + VecZnxBigNormalize<B> + + VecZnxAutomorphismInplace<B> + + VecZnxBigSubSmallNegateInplace<B> + + VecZnxRotate + + VecZnxNormalize<B>, + Scratch<B>: TakeVecZnx + TakeVecZnxDft<B> + ScratchAvailable, +{ + // Goal is to evaluate: a = a + b*X^t + phi(a - b*X^t)) + // We also use the identity: AUTO(a * X^t, g) = -X^t * AUTO(a, g) + // where t = 2^(log_n - i - 1) and g = 5^{2^(i - 1)} + // Different cases for wether a and/or b are zero. + // + // Implicite RSH without modulus switch, introduces extra I(X) * Q/2 on decryption. + // Necessary so that the scaling of the plaintext remains constant. + // It however is ok to do so here because coefficients are eventually + // either mapped to garbage or twice their value which vanishes I(X) + // since 2*(I(X) * Q/2) = I(X) * Q = 0 mod Q. + if let Some(a) = a.as_deref_mut() { + let t: i64 = 1 << (a.n().log2() - i - 1); + + if let Some(b) = b.as_deref_mut() { + let (mut tmp_b, scratch_1) = scratch.take_glwe_ct(a); + + // a = a * X^-t + a.rotate_inplace(module, -t, scratch_1); + + // tmp_b = a * X^-t - b + tmp_b.sub(module, a, b); + tmp_b.rsh(module, 1, scratch_1); + + // a = a * X^-t + b + a.add_inplace(module, b); + a.rsh(module, 1, scratch_1); + + tmp_b.normalize_inplace(module, scratch_1); + + // tmp_b = phi(a * X^-t - b) + tmp_b.automorphism_inplace(module, auto_key, scratch_1); + + // a = a * X^-t + b - phi(a * X^-t - b) + a.sub_inplace_ab(module, &tmp_b); + a.normalize_inplace(module, scratch_1); + + // a = a + b * X^t - phi(a * X^-t - b) * X^t + // = a + b * X^t - phi(a * X^-t - b) * - phi(X^t) + // = a + b * X^t + phi(a - b * X^t) + a.rotate_inplace(module, t, scratch_1); + } else { + a.rsh(module, 1, scratch); + // a = a + phi(a) + a.automorphism_add_inplace(module, auto_key, scratch); + } + } else if let Some(b) = b.as_deref_mut() { + let t: i64 = 1 << (b.n().log2() - i - 1); + + let (mut tmp_b, scratch_1) = scratch.take_glwe_ct(b); + tmp_b.rotate(module, t, b); + tmp_b.rsh(module, 1, scratch_1); + + // a = (b* X^t - phi(b* X^t)) + b.automorphism_sub_negate(module, &tmp_b, auto_key, scratch_1); + } +}
@@ -12,8 +12,7 @@
use crate::{ TakeGLWECt, layouts::{ - Base2K, GGLWELayoutInfos, GLWECiphertext, GLWECiphertextLayout, GLWEInfos, LWEInfos, - prepared::GGLWEAutomorphismKeyPrepared, + Base2K, GGLWEInfos, GLWECiphertext, GLWECiphertextLayout, GLWEInfos, LWEInfos, prepared::GGLWEAutomorphismKeyPrepared, }, operations::GLWEOperations, };@@ -40,7 +39,7 @@ ) -> usize
where OUT: GLWEInfos, IN: GLWEInfos, - KEY: GGLWELayoutInfos, + KEY: GGLWEInfos, Module<B>: VecZnxDftAllocBytes + VmpApplyDftToDftTmpBytes + VecZnxBigNormalizeTmpBytes + VecZnxNormalizeTmpBytes, { let trace: usize = Self::automorphism_inplace_scratch_space(module, out_infos, key_infos);@@ -59,7 +58,7 @@
pub fn trace_inplace_scratch_space<B: Backend, OUT, KEY>(module: &Module<B>, out_infos: &OUT, key_infos: &KEY) -> usize where OUT: GLWEInfos, - KEY: GGLWELayoutInfos, + KEY: GGLWEInfos, Module<B>: VecZnxDftAllocBytes + VmpApplyDftToDftTmpBytes + VecZnxBigNormalizeTmpBytes + VecZnxNormalizeTmpBytes, { Self::trace_scratch_space(module, out_infos, out_infos, key_infos)
@@ -8,7 +8,7 @@ layouts::{Backend, DataMut, DataRef, Module, Scratch, ZnxZero},
}; use crate::layouts::{ - GGLWEAutomorphismKey, GGLWELayoutInfos, GGLWESwitchingKey, GLWECiphertext, GLWEInfos, + GGLWEAutomorphismKey, GGLWEInfos, GGLWESwitchingKey, GLWECiphertext, GLWEInfos, prepared::{GGLWEAutomorphismKeyPrepared, GGLWESwitchingKeyPrepared}, };@@ -20,9 +20,9 @@ in_infos: &IN,
key_infos: &KEY, ) -> usize where - OUT: GGLWELayoutInfos, - IN: GGLWELayoutInfos, - KEY: GGLWELayoutInfos, + OUT: GGLWEInfos, + IN: GGLWEInfos, + KEY: GGLWEInfos, Module<B>: VecZnxDftAllocBytes + VmpApplyDftToDftTmpBytes + VecZnxBigNormalizeTmpBytes + VecZnxNormalizeTmpBytes, { GGLWESwitchingKey::keyswitch_scratch_space(module, out_infos, in_infos, key_infos)@@ -30,8 +30,8 @@ }
pub fn keyswitch_inplace_scratch_space<B: Backend, OUT, KEY>(module: &Module<B>, out_infos: &OUT, key_infos: &KEY) -> usize where - OUT: GGLWELayoutInfos, - KEY: GGLWELayoutInfos, + OUT: GGLWEInfos, + KEY: GGLWEInfos, Module<B>: VecZnxDftAllocBytes + VmpApplyDftToDftTmpBytes + VecZnxBigNormalizeTmpBytes + VecZnxNormalizeTmpBytes, { GGLWESwitchingKey::keyswitch_inplace_scratch_space(module, out_infos, key_infos)@@ -93,9 +93,9 @@ in_infos: &IN,
key_apply: &KEY, ) -> usize where - OUT: GGLWELayoutInfos, - IN: GGLWELayoutInfos, - KEY: GGLWELayoutInfos, + OUT: GGLWEInfos, + IN: GGLWEInfos, + KEY: GGLWEInfos, Module<B>: VecZnxDftAllocBytes + VmpApplyDftToDftTmpBytes + VecZnxBigNormalizeTmpBytes + VecZnxNormalizeTmpBytes, { GLWECiphertext::keyswitch_scratch_space(module, out_infos, in_infos, key_apply)@@ -103,8 +103,8 @@ }
pub fn keyswitch_inplace_scratch_space<B: Backend, OUT, KEY>(module: &Module<B>, out_infos: &OUT, key_apply: &KEY) -> usize where - OUT: GGLWELayoutInfos + GLWEInfos, - KEY: GGLWELayoutInfos + GLWEInfos, + OUT: GGLWEInfos + GLWEInfos, + KEY: GGLWEInfos + GLWEInfos, Module<B>: VecZnxDftAllocBytes + VmpApplyDftToDftTmpBytes + VecZnxBigNormalizeTmpBytes + VecZnxNormalizeTmpBytes, { GLWECiphertext::keyswitch_inplace_scratch_space(module, out_infos, key_apply)@@ -156,28 +156,28 @@ self.rank_out(),
rhs.rank_out() ); assert!( - self.rows() <= lhs.rows(), - "self.rows()={} > lhs.rows()={}", - self.rows(), - lhs.rows() + self.dnum() <= lhs.dnum(), + "self.dnum()={} > lhs.dnum()={}", + self.dnum(), + lhs.dnum() ); assert_eq!( - self.digits(), - lhs.digits(), - "ksk_out digits: {} != ksk_in digits: {}", - self.digits(), - lhs.digits() + self.dsize(), + lhs.dsize(), + "ksk_out dsize: {} != ksk_in dsize: {}", + self.dsize(), + lhs.dsize() ) } (0..self.rank_in().into()).for_each(|col_i| { - (0..self.rows().into()).for_each(|row_j| { + (0..self.dnum().into()).for_each(|row_j| { self.at_mut(row_j, col_i) .keyswitch(module, &lhs.at(row_j, col_i), rhs, scratch); }); }); - (self.rows().min(lhs.rows()).into()..self.rows().into()).for_each(|row_i| { + (self.dnum().min(lhs.dnum()).into()..self.dnum().into()).for_each(|row_i| { (0..self.rank_in().into()).for_each(|col_j| { self.at_mut(row_i, col_j).data.zero(); });@@ -215,7 +215,7 @@ );
} (0..self.rank_in().into()).for_each(|col_i| { - (0..self.rows().into()).for_each(|row_j| { + (0..self.dnum().into()).for_each(|row_j| { self.at_mut(row_j, col_i) .keyswitch_inplace(module, rhs, scratch) });
@@ -10,7 +10,7 @@ };
use crate::{ layouts::{ - GGLWECiphertext, GGLWELayoutInfos, GGSWCiphertext, GGSWInfos, GLWECiphertext, GLWEInfos, LWEInfos, + GGLWECiphertext, GGLWEInfos, GGSWCiphertext, GGSWInfos, GLWECiphertext, GLWEInfos, LWEInfos, prepared::{GGLWESwitchingKeyPrepared, GGLWETensorKeyPrepared}, }, operations::GLWEOperations,@@ -20,14 +20,14 @@ impl GGSWCiphertext<Vec<u8>> {
pub(crate) fn expand_row_scratch_space<B: Backend, OUT, TSK>(module: &Module<B>, out_infos: &OUT, tsk_infos: &TSK) -> usize where OUT: GGSWInfos, - TSK: GGLWELayoutInfos, + TSK: GGLWEInfos, Module<B>: VecZnxDftAllocBytes + VmpApplyDftToDftTmpBytes + VecZnxBigAllocBytes + VecZnxNormalizeTmpBytes, { let tsk_size: usize = tsk_infos.k().div_ceil(tsk_infos.base2k()) as usize; let size_in: usize = out_infos .k() .div_ceil(tsk_infos.base2k()) - .div_ceil(tsk_infos.digits().into()) as usize; + .div_ceil(tsk_infos.dsize().into()) as usize; let tmp_dft_i: usize = module.vec_znx_dft_alloc_bytes((tsk_infos.rank_out() + 1).into(), tsk_size); let tmp_a: usize = module.vec_znx_dft_alloc_bytes(1, size_in);@@ -56,8 +56,8 @@ ) -> usize
where OUT: GGSWInfos, IN: GGSWInfos, - KEY: GGLWELayoutInfos, - TSK: GGLWELayoutInfos, + KEY: GGLWEInfos, + TSK: GGLWEInfos, Module<B>: VecZnxDftAllocBytes + VmpApplyDftToDftTmpBytes + VecZnxBigAllocBytes@@ -101,8 +101,8 @@ tsk_infos: &TSK,
) -> usize where OUT: GGSWInfos, - KEY: GGLWELayoutInfos, - TSK: GGLWELayoutInfos, + KEY: GGLWEInfos, + TSK: GGLWEInfos, Module<B>: VecZnxDftAllocBytes + VmpApplyDftToDftTmpBytes + VecZnxBigAllocBytes@@ -143,12 +143,12 @@ {
use crate::layouts::{GLWEInfos, LWEInfos}; assert_eq!(self.rank(), a.rank_out()); - assert_eq!(self.rows(), a.rows()); + assert_eq!(self.dnum(), a.dnum()); assert_eq!(self.n(), module.n() as u32); assert_eq!(a.n(), module.n() as u32); assert_eq!(tsk.n(), module.n() as u32); } - (0..self.rows().into()).for_each(|row_i| { + (0..self.dnum().into()).for_each(|row_i| { self.at_mut(row_i, 0).copy(module, &a.at(row_i, 0)); }); self.expand_row(module, tsk, scratch);@@ -180,7 +180,7 @@ + VecZnxIdftApplyTmpA<B>
+ VecZnxNormalize<B>, Scratch<B>: ScratchAvailable + TakeVecZnxDft<B> + TakeVecZnxBig<B> + TakeVecZnx, { - (0..lhs.rows().into()).for_each(|row_i| { + (0..lhs.dnum().into()).for_each(|row_i| { // Key-switch column 0, i.e. // col 0: (-(a0s0 + a1s1 + a2s2) + M[i], a0, a1, a2) -> (-(a0s0' + a1s1' + a2s2') + M[i], a0, a1, a2) self.at_mut(row_i, 0)@@ -214,7 +214,7 @@ + VecZnxIdftApplyTmpA<B>
+ VecZnxNormalize<B>, Scratch<B>: ScratchAvailable + TakeVecZnxDft<B> + TakeVecZnxBig<B> + TakeVecZnx, { - (0..self.rows().into()).for_each(|row_i| { + (0..self.dnum().into()).for_each(|row_i| { // Key-switch column 0, i.e. // col 0: (-(a0s0 + a1s1 + a2s2) + M[i], a0, a1, a2) -> (-(a0s0' + a1s1' + a2s2') + M[i], a0, a1, a2) self.at_mut(row_i, 0)@@ -255,7 +255,7 @@
let a_size: usize = (self.size() * basek_in).div_ceil(basek_tsk); // Keyswitch the j-th row of the col 0 - for row_i in 0..self.rows().into() { + for row_i in 0..self.dnum().into() { let a = &self.at(row_i, 0).data; // Pre-compute DFT of (a0, a1, a2)@@ -277,7 +277,7 @@ for col_j in 1..cols {
// Example for rank 3: // // Note: M is a vector (m, Bm, B^2m, B^3m, ...), so each column is - // actually composed of that many rows and we focus on a specific row here + // actually composed of that many dnum and we focus on a specific row here // implicitely given ci_dft. // // # Input@@ -294,10 +294,10 @@ // col 1: (-(b0s0 + b1s1 + b2s2) , b0 + M[i], b1 , b2 )
// col 2: (-(c0s0 + c1s1 + c2s2) , c0 , c1 + M[i], c2 ) // col 3: (-(d0s0 + d1s1 + d2s2) , d0 , d1 , d2 + M[i]) - let digits: usize = tsk.digits().into(); + let dsize: usize = tsk.dsize().into(); let (mut tmp_dft_i, scratch_2) = scratch_1.take_vec_znx_dft(n, cols, tsk.size()); - let (mut tmp_a, scratch_3) = scratch_2.take_vec_znx_dft(n, 1, ci_dft.size().div_ceil(digits)); + let (mut tmp_a, scratch_3) = scratch_2.take_vec_znx_dft(n, 1, ci_dft.size().div_ceil(dsize)); { // Performs a key-switch for each combination of s[i]*s[j], i.e. for a0, a1, a2@@ -315,19 +315,19 @@ for col_i in 1..cols {
let pmat: &VmpPMat<DataTsk, B> = &tsk.at(col_i - 1, col_j - 1).key.data; // Selects Enc(s[i]s[j]) // Extracts a[i] and multipies with Enc(s[i]s[j]) - for di in 0..digits { - tmp_a.set_size((ci_dft.size() + di) / digits); + for di in 0..dsize { + tmp_a.set_size((ci_dft.size() + di) / dsize); - // Small optimization for digits > 2 + // Small optimization for dsize > 2 // VMP produce some error e, and since we aggregate vmp * 2^{di * B}, then - // we also aggregate ei * 2^{di * B}, with the largest error being ei * 2^{(digits-1) * B}. - // As such we can ignore the last digits-2 limbs safely of the sum of vmp products. - // It is possible to further ignore the last digits-1 limbs, but this introduce + // we also aggregate ei * 2^{di * B}, with the largest error being ei * 2^{(dsize-1) * B}. + // As such we can ignore the last dsize-2 limbs safely of the sum of vmp products. + // It is possible to further ignore the last dsize-1 limbs, but this introduce // ~0.5 to 1 bit of additional noise, and thus not chosen here to ensure that the same // noise is kept with respect to the ideal functionality. - tmp_dft_i.set_size(tsk.size() - ((digits - di) as isize - 2).max(0) as usize); + tmp_dft_i.set_size(tsk.size() - ((dsize - di) as isize - 2).max(0) as usize); - module.vec_znx_dft_copy(digits, digits - 1 - di, &mut tmp_a, 0, &ci_dft, col_i); + module.vec_znx_dft_copy(dsize, dsize - 1 - di, &mut tmp_a, 0, &ci_dft, col_i); if di == 0 && col_i == 1 { module.vmp_apply_dft_to_dft(&mut tmp_dft_i, &tmp_a, pmat, scratch_3); } else {
@@ -7,7 +7,7 @@ },
layouts::{Backend, DataMut, DataRef, DataViewMut, Module, Scratch, VecZnx, VecZnxBig, VecZnxDft, VmpPMat, ZnxInfos}, }; -use crate::layouts::{GGLWELayoutInfos, GLWECiphertext, GLWEInfos, LWEInfos, prepared::GGLWESwitchingKeyPrepared}; +use crate::layouts::{GGLWEInfos, GLWECiphertext, GLWEInfos, LWEInfos, prepared::GGLWESwitchingKeyPrepared}; impl GLWECiphertext<Vec<u8>> { pub fn keyswitch_scratch_space<B: Backend, OUT, IN, KEY>(@@ -19,13 +19,13 @@ ) -> usize
where OUT: GLWEInfos, IN: GLWEInfos, - KEY: GGLWELayoutInfos, + KEY: GGLWEInfos, Module<B>: VecZnxDftAllocBytes + VmpApplyDftToDftTmpBytes + VecZnxBigNormalizeTmpBytes + VecZnxNormalizeTmpBytes, { let in_size: usize = in_infos .k() .div_ceil(key_apply.base2k()) - .div_ceil(key_apply.digits().into()) as usize; + .div_ceil(key_apply.dsize().into()) as usize; let out_size: usize = out_infos.size(); let ksk_size: usize = key_apply.size(); let res_dft: usize = module.vec_znx_dft_alloc_bytes((key_apply.rank_out() + 1).into(), ksk_size); // TODO OPTIMIZE@@ -41,12 +41,12 @@ ) + module.vec_znx_dft_alloc_bytes((key_apply.rank_in()).into(), in_size);
let normalize_big: usize = module.vec_znx_big_normalize_tmp_bytes(); if in_infos.base2k() == key_apply.base2k() { res_dft + ((ai_dft + vmp) | normalize_big) - } else if key_apply.digits() == 1 { + } else if key_apply.dsize() == 1 { // In this case, we only need one column, temporary, that we can drop once a_dft is computed. let normalize_conv: usize = VecZnx::alloc_bytes(module.n(), 1, in_size) + module.vec_znx_normalize_tmp_bytes(); res_dft + (((ai_dft + normalize_conv) | vmp) | normalize_big) } else { - // Since we stride over a to get a_dft when digits > 1, we need to store the full columns of a with in the base conversion. + // Since we stride over a to get a_dft when dsize > 1, we need to store the full columns of a with in the base conversion. let normalize_conv: usize = VecZnx::alloc_bytes(module.n(), (key_apply.rank_in()).into(), in_size); res_dft + ((ai_dft + normalize_conv + (module.vec_znx_normalize_tmp_bytes() | vmp)) | normalize_big) }@@ -55,7 +55,7 @@
pub fn keyswitch_inplace_scratch_space<B: Backend, OUT, KEY>(module: &Module<B>, out_infos: &OUT, key_apply: &KEY) -> usize where OUT: GLWEInfos, - KEY: GGLWELayoutInfos, + KEY: GGLWEInfos, Module<B>: VecZnxDftAllocBytes + VmpApplyDftToDftTmpBytes + VecZnxBigNormalizeTmpBytes + VecZnxNormalizeTmpBytes, { Self::keyswitch_scratch_space(module, out_infos, out_infos, key_apply)@@ -105,7 +105,7 @@ lhs.base2k(),
lhs.k(), rhs.base2k(), rhs.k(), - rhs.digits(), + rhs.dsize(), rhs.rank_in(), rhs.rank_out(), )={scrach_needed}",@@ -256,7 +256,7 @@ + VecZnxBigNormalize<B>
+ VecZnxNormalize<B>, Scratch<B>: TakeVecZnxDft<B> + TakeVecZnx, { - if rhs.digits() == 1 { + if rhs.dsize() == 1 { return keyswitch_vmp_one_digit( module, self.base2k().into(),@@ -275,7 +275,7 @@ rhs.base2k().into(),
res_dft, &self.data, &rhs.key.data, - rhs.digits().into(), + rhs.dsize().into(), scratch, ) }@@ -333,7 +333,7 @@ basek_ksk: usize,
mut res_dft: VecZnxDft<DataRes, B>, a: &VecZnx<DataIn>, mat: &VmpPMat<DataVmp, B>, - digits: usize, + dsize: usize, scratch: &mut Scratch<B>, ) -> VecZnxBig<DataRes, B> where@@ -351,24 +351,24 @@ Scratch<B>: TakeVecZnxDft<B> + TakeVecZnx,
{ let cols: usize = a.cols(); let a_size: usize = (a.size() * basek_in).div_ceil(basek_ksk); - let (mut ai_dft, scratch_1) = scratch.take_vec_znx_dft(a.n(), cols - 1, a_size.div_ceil(digits)); + let (mut ai_dft, scratch_1) = scratch.take_vec_znx_dft(a.n(), cols - 1, a_size.div_ceil(dsize)); ai_dft.data_mut().fill(0); if basek_in == basek_ksk { - for di in 0..digits { - ai_dft.set_size((a_size + di) / digits); + for di in 0..dsize { + ai_dft.set_size((a_size + di) / dsize); - // Small optimization for digits > 2 + // Small optimization for dsize > 2 // VMP produce some error e, and since we aggregate vmp * 2^{di * B}, then - // we also aggregate ei * 2^{di * B}, with the largest error being ei * 2^{(digits-1) * B}. - // As such we can ignore the last digits-2 limbs safely of the sum of vmp products. - // It is possible to further ignore the last digits-1 limbs, but this introduce + // we also aggregate ei * 2^{di * B}, with the largest error being ei * 2^{(dsize-1) * B}. + // As such we can ignore the last dsize-2 limbs safely of the sum of vmp products. + // It is possible to further ignore the last dsize-1 limbs, but this introduce // ~0.5 to 1 bit of additional noise, and thus not chosen here to ensure that the same // noise is kept with respect to the ideal functionality. - res_dft.set_size(mat.size() - ((digits - di) as isize - 2).max(0) as usize); + res_dft.set_size(mat.size() - ((dsize - di) as isize - 2).max(0) as usize); for j in 0..cols - 1 { - module.vec_znx_dft_apply(digits, digits - di - 1, &mut ai_dft, j, a, j + 1); + module.vec_znx_dft_apply(dsize, dsize - di - 1, &mut ai_dft, j, a, j + 1); } if di == 0 {@@ -383,20 +383,20 @@ for j in 0..cols - 1 {
module.vec_znx_normalize(basek_ksk, &mut a_conv, j, basek_in, a, j + 1, scratch_2); } - for di in 0..digits { - ai_dft.set_size((a_size + di) / digits); + for di in 0..dsize { + ai_dft.set_size((a_size + di) / dsize); - // Small optimization for digits > 2 + // Small optimization for dsize > 2 // VMP produce some error e, and since we aggregate vmp * 2^{di * B}, then - // we also aggregate ei * 2^{di * B}, with the largest error being ei * 2^{(digits-1) * B}. - // As such we can ignore the last digits-2 limbs safely of the sum of vmp products. - // It is possible to further ignore the last digits-1 limbs, but this introduce + // we also aggregate ei * 2^{di * B}, with the largest error being ei * 2^{(dsize-1) * B}. + // As such we can ignore the last dsize-2 limbs safely of the sum of vmp products. + // It is possible to further ignore the last dsize-1 limbs, but this introduce // ~0.5 to 1 bit of additional noise, and thus not chosen here to ensure that the same // noise is kept with respect to the ideal functionality. - res_dft.set_size(mat.size() - ((digits - di) as isize - 2).max(0) as usize); + res_dft.set_size(mat.size() - ((dsize - di) as isize - 2).max(0) as usize); for j in 0..cols - 1 { - module.vec_znx_dft_apply(digits, digits - di - 1, &mut ai_dft, j, &a_conv, j); + module.vec_znx_dft_apply(dsize, dsize - di - 1, &mut ai_dft, j, &a_conv, j); } if di == 0 {
@@ -10,7 +10,7 @@
use crate::{ TakeGLWECt, layouts::{ - GGLWELayoutInfos, GLWECiphertext, GLWECiphertextLayout, LWECiphertext, LWEInfos, Rank, TorusPrecision, + GGLWEInfos, GLWECiphertext, GLWECiphertextLayout, LWECiphertext, LWEInfos, Rank, TorusPrecision, prepared::LWESwitchingKeyPrepared, }, };@@ -25,7 +25,7 @@ ) -> usize
where OUT: LWEInfos, IN: LWEInfos, - KEY: GGLWELayoutInfos, + KEY: GGLWEInfos, Module<B>: VecZnxDftAllocBytes + VmpApplyDftToDftTmpBytes + VecZnxBigNormalizeTmpBytes
@@ -5,7 +5,7 @@ source::Source,
}; use crate::layouts::{ - Base2K, Degree, Digits, GGLWEAutomorphismKey, GGLWELayoutInfos, GLWEInfos, LWEInfos, Rank, Rows, TorusPrecision, + Base2K, Degree, Dnum, Dsize, GGLWEAutomorphismKey, GGLWEInfos, GLWEInfos, LWEInfos, Rank, TorusPrecision, compressed::{Decompress, GGLWESwitchingKeyCompressed}, }; use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};@@ -40,7 +40,7 @@ self.rank_out()
} } -impl<D: Data> GGLWELayoutInfos for GGLWEAutomorphismKeyCompressed<D> { +impl<D: Data> GGLWEInfos for GGLWEAutomorphismKeyCompressed<D> { fn rank_in(&self) -> Rank { self.key.rank_in() }@@ -49,12 +49,12 @@ fn rank_out(&self) -> Rank {
self.key.rank_out() } - fn digits(&self) -> Digits { - self.key.digits() + fn dsize(&self) -> Dsize { + self.key.dsize() } - fn rows(&self) -> Rows { - self.key.rows() + fn dnum(&self) -> Dnum { + self.key.dnum() } }@@ -79,7 +79,7 @@
impl GGLWEAutomorphismKeyCompressed<Vec<u8>> { pub fn alloc<A>(infos: &A) -> Self where - A: GGLWELayoutInfos, + A: GGLWEInfos, { debug_assert_eq!(infos.rank_in(), infos.rank_out()); Self {@@ -88,23 +88,23 @@ p: 0,
} } - pub fn alloc_with(n: Degree, base2k: Base2K, k: TorusPrecision, rows: Rows, digits: Digits, rank: Rank) -> Self { + pub fn alloc_with(n: Degree, base2k: Base2K, k: TorusPrecision, rank: Rank, dnum: Dnum, dsize: Dsize) -> Self { Self { - key: GGLWESwitchingKeyCompressed::alloc_with(n, base2k, k, rows, digits, rank, rank), + key: GGLWESwitchingKeyCompressed::alloc_with(n, base2k, k, rank, rank, dnum, dsize), p: 0, } } pub fn alloc_bytes<A>(infos: &A) -> usize where - A: GGLWELayoutInfos, + A: GGLWEInfos, { debug_assert_eq!(infos.rank_in(), infos.rank_out()); GGLWESwitchingKeyCompressed::alloc_bytes(infos) } - pub fn alloc_bytes_with(n: Degree, base2k: Base2K, k: TorusPrecision, rows: Rows, digits: Digits, rank: Rank) -> usize { - GGLWESwitchingKeyCompressed::alloc_bytes_with(n, base2k, k, rows, digits, rank, rank) + pub fn alloc_bytes_with(n: Degree, base2k: Base2K, k: TorusPrecision, rank: Rank, dnum: Dnum, dsize: Dsize) -> usize { + GGLWESwitchingKeyCompressed::alloc_bytes_with(n, base2k, k, rank, dnum, dsize) } }
@@ -5,7 +5,7 @@ source::Source,
}; use crate::layouts::{ - Base2K, Degree, Digits, GGLWECiphertext, GGLWELayoutInfos, GLWEInfos, LWEInfos, Rank, Rows, TorusPrecision, + Base2K, Degree, Dnum, Dsize, GGLWECiphertext, GGLWEInfos, GLWEInfos, LWEInfos, Rank, TorusPrecision, compressed::{Decompress, GLWECiphertextCompressed}, }; use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};@@ -17,7 +17,7 @@ pub(crate) data: MatZnx<D>,
pub(crate) base2k: Base2K, pub(crate) k: TorusPrecision, pub(crate) rank_out: Rank, - pub(crate) digits: Digits, + pub(crate) dsize: Dsize, pub(crate) seed: Vec<[u8; 32]>, }@@ -44,7 +44,7 @@ self.rank_out()
} } -impl<D: Data> GGLWELayoutInfos for GGLWECiphertextCompressed<D> { +impl<D: Data> GGLWEInfos for GGLWECiphertextCompressed<D> { fn rank_in(&self) -> Rank { Rank(self.data.cols_in() as u32) }@@ -53,12 +53,12 @@ fn rank_out(&self) -> Rank {
self.rank_out } - fn digits(&self) -> Digits { - self.digits + fn dsize(&self) -> Dsize { + self.dsize } - fn rows(&self) -> Rows { - Rows(self.data.rows() as u32) + fn dnum(&self) -> Dnum { + Dnum(self.data.rows() as u32) } }@@ -78,8 +78,8 @@ impl<D: DataRef> fmt::Display for GGLWECiphertextCompressed<D> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( f, - "(GGLWECiphertextCompressed: base2k={} k={} digits={}) {}", - self.base2k.0, self.k.0, self.digits.0, self.data + "(GGLWECiphertextCompressed: base2k={} k={} dsize={}) {}", + self.base2k.0, self.k.0, self.dsize.0, self.data ) } }@@ -87,16 +87,16 @@
impl GGLWECiphertextCompressed<Vec<u8>> { pub fn alloc<A>(infos: &A) -> Self where - A: GGLWELayoutInfos, + A: GGLWEInfos, { Self::alloc_with( infos.n(), infos.base2k(), infos.k(), - infos.rows(), - infos.digits(), infos.rank_in(), infos.rank_out(), + infos.dnum(), + infos.dsize(), ) }@@ -104,82 +104,73 @@ pub fn alloc_with(
n: Degree, base2k: Base2K, k: TorusPrecision, - rows: Rows, - digits: Digits, rank_in: Rank, rank_out: Rank, + dnum: Dnum, + dsize: Dsize, ) -> Self { let size: usize = k.0.div_ceil(base2k.0) as usize; debug_assert!( - size as u32 > digits.0, - "invalid gglwe: ceil(k/base2k): {size} <= digits: {}", - digits.0 + size as u32 > dsize.0, + "invalid gglwe: ceil(k/base2k): {size} <= dsize: {}", + dsize.0 ); assert!( - rows.0 * digits.0 <= size as u32, - "invalid gglwe: rows: {} * digits:{} > ceil(k/base2k): {size}", - rows.0, - digits.0, + dnum.0 * dsize.0 <= size as u32, + "invalid gglwe: dnum: {} * dsize:{} > ceil(k/base2k): {size}", + dnum.0, + dsize.0, ); Self { data: MatZnx::alloc( n.into(), - rows.into(), + dnum.into(), rank_in.into(), 1, k.0.div_ceil(base2k.0) as usize, ), k, base2k, - digits, + dsize, rank_out, - seed: vec![[0u8; 32]; (rows.0 * rank_in.0) as usize], + seed: vec![[0u8; 32]; (dnum.0 * rank_in.0) as usize], } } pub fn alloc_bytes<A>(infos: &A) -> usize where - A: GGLWELayoutInfos, + A: GGLWEInfos, { Self::alloc_bytes_with( infos.n(), infos.base2k(), infos.k(), - infos.rows(), - infos.digits(), infos.rank_in(), - infos.rank_out(), + infos.dnum(), + infos.dsize(), ) } - pub fn alloc_bytes_with( - n: Degree, - base2k: Base2K, - k: TorusPrecision, - rows: Rows, - digits: Digits, - rank_in: Rank, - _rank_out: Rank, - ) -> usize { + pub fn alloc_bytes_with(n: Degree, base2k: Base2K, k: TorusPrecision, rank_in: Rank, dnum: Dnum, dsize: Dsize) -> usize { let size: usize = k.0.div_ceil(base2k.0) as usize; debug_assert!( - size as u32 > digits.0, - "invalid gglwe: ceil(k/base2k): {size} <= digits: {}", - digits.0 + size as u32 > dsize.0, + "invalid gglwe: ceil(k/base2k): {size} <= dsize: {}", + dsize.0 ); assert!( - rows.0 * digits.0 <= size as u32, - "invalid gglwe: rows: {} * digits:{} > ceil(k/base2k): {size}", - rows.0, - digits.0, + dnum.0 * dsize.0 <= size as u32, + "invalid gglwe: dnum: {} * dsize:{} > ceil(k/base2k): {size}", + dnum.0, + dsize.0, ); MatZnx::alloc_bytes( n.into(), - rows.into(), + dnum.into(), rank_in.into(), 1, k.0.div_ceil(base2k.0) as usize,@@ -217,7 +208,7 @@ impl<D: DataMut> ReaderFrom for GGLWECiphertextCompressed<D> {
fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> { self.k = TorusPrecision(reader.read_u32::<LittleEndian>()?); self.base2k = Base2K(reader.read_u32::<LittleEndian>()?); - self.digits = Digits(reader.read_u32::<LittleEndian>()?); + self.dsize = Dsize(reader.read_u32::<LittleEndian>()?); self.rank_out = Rank(reader.read_u32::<LittleEndian>()?); let seed_len: u32 = reader.read_u32::<LittleEndian>()?; self.seed = vec![[0u8; 32]; seed_len as usize];@@ -232,7 +223,7 @@ impl<D: DataRef> WriterTo for GGLWECiphertextCompressed<D> {
fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> { writer.write_u32::<LittleEndian>(self.k.into())?; writer.write_u32::<LittleEndian>(self.base2k.into())?; - writer.write_u32::<LittleEndian>(self.digits.into())?; + writer.write_u32::<LittleEndian>(self.dsize.into())?; writer.write_u32::<LittleEndian>(self.rank_out.into())?; writer.write_u32::<LittleEndian>(self.seed.len() as u32)?; for s in &self.seed {@@ -279,19 +270,19 @@ other.rank_out()
); assert_eq!( - self.rows(), - other.rows(), - "invalid receiver: self.rows()={} != other.rows()={}", - self.rows(), - other.rows() + self.dnum(), + other.dnum(), + "invalid receiver: self.dnum()={} != other.dnum()={}", + self.dnum(), + other.dnum() ); } let rank_in: usize = self.rank_in().into(); - let rows: usize = self.rows().into(); + let dnum: usize = self.dnum().into(); (0..rank_in).for_each(|col_i| { - (0..rows).for_each(|row_i| { + (0..dnum).for_each(|row_i| { self.at_mut(row_i, col_i) .decompress(module, &other.at(row_i, col_i)); });
@@ -5,7 +5,7 @@ source::Source,
}; use crate::layouts::{ - Base2K, Degree, Digits, GGLWELayoutInfos, GGLWESwitchingKey, GLWEInfos, LWEInfos, Rank, Rows, TorusPrecision, + Base2K, Degree, Dnum, Dsize, GGLWEInfos, GGLWESwitchingKey, GLWEInfos, LWEInfos, Rank, TorusPrecision, compressed::{Decompress, GGLWECiphertextCompressed}, }; use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};@@ -41,7 +41,7 @@ self.rank_out()
} } -impl<D: Data> GGLWELayoutInfos for GGLWESwitchingKeyCompressed<D> { +impl<D: Data> GGLWEInfos for GGLWESwitchingKeyCompressed<D> { fn rank_in(&self) -> Rank { self.key.rank_in() }@@ -50,12 +50,12 @@ fn rank_out(&self) -> Rank {
self.key.rank_out() } - fn digits(&self) -> Digits { - self.key.digits() + fn dsize(&self) -> Dsize { + self.key.dsize() } - fn rows(&self) -> Rows { - self.key.rows() + fn dnum(&self) -> Dnum { + self.key.dnum() } }@@ -84,7 +84,7 @@
impl GGLWESwitchingKeyCompressed<Vec<u8>> { pub fn alloc<A>(infos: &A) -> Self where - A: GGLWELayoutInfos, + A: GGLWEInfos, { GGLWESwitchingKeyCompressed { key: GGLWECiphertextCompressed::alloc(infos),@@ -97,13 +97,13 @@ pub fn alloc_with(
n: Degree, base2k: Base2K, k: TorusPrecision, - rows: Rows, - digits: Digits, rank_in: Rank, rank_out: Rank, + dnum: Dnum, + dsize: Dsize, ) -> Self { GGLWESwitchingKeyCompressed { - key: GGLWECiphertextCompressed::alloc_with(n, base2k, k, rows, digits, rank_in, rank_out), + key: GGLWECiphertextCompressed::alloc_with(n, base2k, k, rank_in, rank_out, dnum, dsize), sk_in_n: 0, sk_out_n: 0, }@@ -111,21 +111,13 @@ }
pub fn alloc_bytes<A>(infos: &A) -> usize where - A: GGLWELayoutInfos, + A: GGLWEInfos, { GGLWECiphertextCompressed::alloc_bytes(infos) } - pub fn alloc_bytes_with( - n: Degree, - base2k: Base2K, - k: TorusPrecision, - rows: Rows, - digits: Digits, - rank_in: Rank, - rank_out: Rank, - ) -> usize { - GGLWECiphertextCompressed::alloc_bytes_with(n, base2k, k, rows, digits, rank_in, rank_out) + pub fn alloc_bytes_with(n: Degree, base2k: Base2K, k: TorusPrecision, rank_in: Rank, dnum: Dnum, dsize: Dsize) -> usize { + GGLWECiphertextCompressed::alloc_bytes_with(n, base2k, k, rank_in, dnum, dsize) } }
@@ -5,7 +5,7 @@ source::Source,
}; use crate::layouts::{ - Base2K, Degree, Digits, GGLWELayoutInfos, GGLWETensorKey, GLWEInfos, LWEInfos, Rank, Rows, TorusPrecision, + Base2K, Degree, Dnum, Dsize, GGLWEInfos, GGLWETensorKey, GLWEInfos, LWEInfos, Rank, TorusPrecision, compressed::{Decompress, GGLWESwitchingKeyCompressed}, }; use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};@@ -38,7 +38,7 @@ self.rank_out()
} } -impl<D: Data> GGLWELayoutInfos for GGLWETensorKeyCompressed<D> { +impl<D: Data> GGLWEInfos for GGLWETensorKeyCompressed<D> { fn rank_in(&self) -> Rank { self.rank_out() }@@ -47,12 +47,12 @@ fn rank_out(&self) -> Rank {
self.keys[0].rank_out() } - fn digits(&self) -> Digits { - self.keys[0].digits() + fn dsize(&self) -> Dsize { + self.keys[0].dsize() } - fn rows(&self) -> Rows { - self.keys[0].rows() + fn dnum(&self) -> Dnum { + self.keys[0].dnum() } }@@ -83,7 +83,7 @@
impl GGLWETensorKeyCompressed<Vec<u8>> { pub fn alloc<A>(infos: &A) -> Self where - A: GGLWELayoutInfos, + A: GGLWEInfos, { assert_eq!( infos.rank_in(),@@ -94,13 +94,13 @@ Self::alloc_with(
infos.n(), infos.base2k(), infos.k(), - infos.rows(), - infos.digits(), infos.rank_out(), + infos.dnum(), + infos.dsize(), ) } - pub fn alloc_with(n: Degree, base2k: Base2K, k: TorusPrecision, rows: Rows, digits: Digits, rank: Rank) -> Self { + pub fn alloc_with(n: Degree, base2k: Base2K, k: TorusPrecision, rank: Rank, dnum: Dnum, dsize: Dsize) -> Self { let mut keys: Vec<GGLWESwitchingKeyCompressed<Vec<u8>>> = Vec::new(); let pairs: u32 = (((rank.0 + 1) * rank.0) >> 1).max(1); (0..pairs).for_each(|_| {@@ -108,10 +108,10 @@ keys.push(GGLWESwitchingKeyCompressed::alloc_with(
n, base2k, k, - rows, - digits, Rank(1), rank, + dnum, + dsize, )); }); Self { keys }@@ -119,7 +119,7 @@ }
pub fn alloc_bytes<A>(infos: &A) -> usize where - A: GGLWELayoutInfos, + A: GGLWEInfos, { assert_eq!( infos.rank_in(),@@ -133,16 +133,15 @@ * GGLWESwitchingKeyCompressed::alloc_bytes_with(
infos.n(), infos.base2k(), infos.k(), - infos.rows(), - infos.digits(), Rank(1), - infos.rank_out(), + infos.dnum(), + infos.dsize(), ) } - pub fn alloc_bytes_with(n: Degree, base2k: Base2K, k: TorusPrecision, rows: Rows, digits: Digits, rank: Rank) -> usize { + pub fn alloc_bytes_with(n: Degree, base2k: Base2K, k: TorusPrecision, rank: Rank, dnum: Dnum, dsize: Dsize) -> usize { let pairs: usize = (((rank.0 + 1) * rank.0) >> 1).max(1) as usize; - pairs * GGLWESwitchingKeyCompressed::alloc_bytes_with(n, base2k, k, rows, digits, Rank(1), rank) + pairs * GGLWESwitchingKeyCompressed::alloc_bytes_with(n, base2k, k, Rank(1), dnum, dsize) } }
@@ -5,7 +5,7 @@ source::Source,
}; use crate::layouts::{ - Base2K, Degree, Digits, GGSWCiphertext, GGSWInfos, GLWEInfos, LWEInfos, Rank, Rows, TorusPrecision, + Base2K, Degree, Dnum, Dsize, GGSWCiphertext, GGSWInfos, GLWEInfos, LWEInfos, Rank, TorusPrecision, compressed::{Decompress, GLWECiphertextCompressed}, }; use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};@@ -16,7 +16,7 @@ pub struct GGSWCiphertextCompressed<D: Data> {
pub(crate) data: MatZnx<D>, pub(crate) k: TorusPrecision, pub(crate) base2k: Base2K, - pub(crate) digits: Digits, + pub(crate) dsize: Dsize, pub(crate) rank: Rank, pub(crate) seed: Vec<[u8; 32]>, }@@ -44,12 +44,12 @@ }
} impl<D: Data> GGSWInfos for GGSWCiphertextCompressed<D> { - fn digits(&self) -> Digits { - self.digits + fn dsize(&self) -> Dsize { + self.dsize } - fn rows(&self) -> Rows { - Rows(self.data.rows() as u32) + fn dnum(&self) -> Dnum { + Dnum(self.data.rows() as u32) } }@@ -63,8 +63,8 @@ impl<D: DataRef> fmt::Display for GGSWCiphertextCompressed<D> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( f, - "(GGSWCiphertextCompressed: base2k={} k={} digits={}) {}", - self.base2k, self.k, self.digits, self.data + "(GGSWCiphertextCompressed: base2k={} k={} dsize={}) {}", + self.base2k, self.k, self.dsize, self.data ) } }@@ -84,38 +84,38 @@ Self::alloc_with(
infos.n(), infos.base2k(), infos.k(), - infos.rows(), - infos.digits(), infos.rank(), + infos.dnum(), + infos.dsize(), ) } - pub fn alloc_with(n: Degree, base2k: Base2K, k: TorusPrecision, rows: Rows, digits: Digits, rank: Rank) -> Self { + pub fn alloc_with(n: Degree, base2k: Base2K, k: TorusPrecision, rank: Rank, dnum: Dnum, dsize: Dsize) -> Self { let size: usize = k.0.div_ceil(base2k.0) as usize; debug_assert!( - size as u32 > digits.0, - "invalid ggsw: ceil(k/base2k): {size} <= digits: {}", - digits.0 + size as u32 > dsize.0, + "invalid ggsw: ceil(k/base2k): {size} <= dsize: {}", + dsize.0 ); assert!( - rows.0 * digits.0 <= size as u32, - "invalid ggsw: rows: {} * digits:{} > ceil(k/base2k): {size}", - rows.0, - digits.0, + dnum.0 * dsize.0 <= size as u32, + "invalid ggsw: dnum: {} * dsize:{} > ceil(k/base2k): {size}", + dnum.0, + dsize.0, ); Self { data: MatZnx::alloc( n.into(), - rows.into(), + dnum.into(), (rank + 1).into(), 1, k.0.div_ceil(base2k.0) as usize, ), k, base2k, - digits, + dsize, rank, seed: Vec::new(), }@@ -129,30 +129,30 @@ Self::alloc_bytes_with(
infos.n(), infos.base2k(), infos.k(), - infos.rows(), - infos.digits(), infos.rank(), + infos.dnum(), + infos.dsize(), ) } - pub fn alloc_bytes_with(n: Degree, base2k: Base2K, k: TorusPrecision, rows: Rows, digits: Digits, rank: Rank) -> usize { + pub fn alloc_bytes_with(n: Degree, base2k: Base2K, k: TorusPrecision, rank: Rank, dnum: Dnum, dsize: Dsize) -> usize { let size: usize = k.0.div_ceil(base2k.0) as usize; debug_assert!( - size as u32 > digits.0, - "invalid ggsw: ceil(k/base2k): {size} <= digits: {}", - digits.0 + size as u32 > dsize.0, + "invalid ggsw: ceil(k/base2k): {size} <= dsize: {}", + dsize.0 ); assert!( - rows.0 * digits.0 <= size as u32, - "invalid ggsw: rows: {} * digits:{} > ceil(k/base2k): {size}", - rows.0, - digits.0, + dnum.0 * dsize.0 <= size as u32, + "invalid ggsw: dnum: {} * dsize:{} > ceil(k/base2k): {size}", + dnum.0, + dsize.0, ); MatZnx::alloc_bytes( n.into(), - rows.into(), + dnum.into(), (rank + 1).into(), 1, k.0.div_ceil(base2k.0) as usize,@@ -190,7 +190,7 @@ impl<D: DataMut> ReaderFrom for GGSWCiphertextCompressed<D> {
fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> { self.k = TorusPrecision(reader.read_u32::<LittleEndian>()?); self.base2k = Base2K(reader.read_u32::<LittleEndian>()?); - self.digits = Digits(reader.read_u32::<LittleEndian>()?); + self.dsize = Dsize(reader.read_u32::<LittleEndian>()?); self.rank = Rank(reader.read_u32::<LittleEndian>()?); let seed_len: usize = reader.read_u32::<LittleEndian>()? as usize; self.seed = vec![[0u8; 32]; seed_len];@@ -205,7 +205,7 @@ impl<D: DataRef> WriterTo for GGSWCiphertextCompressed<D> {
fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> { writer.write_u32::<LittleEndian>(self.k.into())?; writer.write_u32::<LittleEndian>(self.base2k.into())?; - writer.write_u32::<LittleEndian>(self.digits.into())?; + writer.write_u32::<LittleEndian>(self.dsize.into())?; writer.write_u32::<LittleEndian>(self.rank.into())?; writer.write_u32::<LittleEndian>(self.seed.len() as u32)?; for s in &self.seed {@@ -225,9 +225,9 @@ {
assert_eq!(self.rank(), other.rank()) } - let rows: usize = self.rows().into(); + let dnum: usize = self.dnum().into(); let rank: usize = self.rank().into(); - (0..rows).for_each(|row_i| { + (0..dnum).for_each(|row_i| { (0..rank + 1).for_each(|col_j| { self.at_mut(row_i, col_j) .decompress(module, &other.at(row_i, col_j));
@@ -6,8 +6,7 @@ source::Source,
}; use crate::layouts::{ - Base2K, Degree, Digits, GGLWELayoutInfos, GLWEInfos, LWEInfos, Rank, Rows, TorusPrecision, - compressed::GGLWESwitchingKeyCompressed, + Base2K, Degree, Dnum, Dsize, GGLWEInfos, GLWEInfos, LWEInfos, Rank, TorusPrecision, compressed::GGLWESwitchingKeyCompressed, }; #[derive(PartialEq, Eq, Clone)]@@ -36,21 +35,21 @@ self.rank_out()
} } -impl<D: Data> GGLWELayoutInfos for GLWEToLWESwitchingKeyCompressed<D> { +impl<D: Data> GGLWEInfos for GLWEToLWESwitchingKeyCompressed<D> { fn rank_in(&self) -> Rank { self.0.rank_in() } - fn digits(&self) -> Digits { - self.0.digits() + fn dsize(&self) -> Dsize { + self.0.dsize() } fn rank_out(&self) -> Rank { self.0.rank_out() } - fn rows(&self) -> Rows { - self.0.rows() + fn dnum(&self) -> Dnum { + self.0.dnum() } }@@ -87,7 +86,7 @@
impl GLWEToLWESwitchingKeyCompressed<Vec<u8>> { pub fn alloc<A>(infos: &A) -> Self where - A: GGLWELayoutInfos, + A: GGLWEInfos, { debug_assert_eq!( infos.rank_out().0,@@ -95,28 +94,28 @@ 1,
"rank_out > 1 is unsupported for GLWEToLWESwitchingKeyCompressed" ); debug_assert_eq!( - infos.digits().0, + infos.dsize().0, 1, - "digits > 1 is unsupported for GLWEToLWESwitchingKeyCompressed" + "dsize > 1 is unsupported for GLWEToLWESwitchingKeyCompressed" ); Self(GGLWESwitchingKeyCompressed::alloc(infos)) } - pub fn alloc_with(n: Degree, base2k: Base2K, k: TorusPrecision, rows: Rows, rank_in: Rank) -> Self { + pub fn alloc_with(n: Degree, base2k: Base2K, k: TorusPrecision, rank_in: Rank, dnum: Dnum) -> Self { Self(GGLWESwitchingKeyCompressed::alloc_with( n, base2k, k, - rows, - Digits(1), rank_in, Rank(1), + dnum, + Dsize(1), )) } pub fn alloc_bytes<A>(infos: &A) -> usize where - A: GGLWELayoutInfos, + A: GGLWEInfos, { debug_assert_eq!( infos.rank_out().0,@@ -124,14 +123,14 @@ 1,
"rank_out > 1 is unsupported for GLWEToLWESwitchingKeyCompressed" ); debug_assert_eq!( - infos.digits().0, + infos.dsize().0, 1, - "digits > 1 is unsupported for GLWEToLWESwitchingKeyCompressed" + "dsize > 1 is unsupported for GLWEToLWESwitchingKeyCompressed" ); GGLWESwitchingKeyCompressed::alloc_bytes(infos) } - pub fn alloc_bytes_with(n: Degree, base2k: Base2K, k: TorusPrecision, rows: Rows, rank_in: Rank) -> usize { - GGLWESwitchingKeyCompressed::alloc_bytes_with(n, base2k, k, rows, Digits(1), rank_in, Rank(1)) + pub fn alloc_bytes_with(n: Degree, base2k: Base2K, k: TorusPrecision, dnum: Dnum, rank_in: Rank) -> usize { + GGLWESwitchingKeyCompressed::alloc_bytes_with(n, base2k, k, rank_in, dnum, Dsize(1)) } }
@@ -5,7 +5,7 @@ source::Source,
}; use crate::layouts::{ - Base2K, Degree, Digits, GGLWELayoutInfos, GLWEInfos, LWEInfos, LWESwitchingKey, Rank, Rows, TorusPrecision, + Base2K, Degree, Dnum, Dsize, GGLWEInfos, GLWEInfos, LWEInfos, LWESwitchingKey, Rank, TorusPrecision, compressed::{Decompress, GGLWESwitchingKeyCompressed}, }; use std::fmt;@@ -35,9 +35,9 @@ self.rank_out()
} } -impl<D: Data> GGLWELayoutInfos for LWESwitchingKeyCompressed<D> { - fn digits(&self) -> Digits { - self.0.digits() +impl<D: Data> GGLWEInfos for LWESwitchingKeyCompressed<D> { + fn dsize(&self) -> Dsize { + self.0.dsize() } fn rank_in(&self) -> Rank {@@ -48,8 +48,8 @@ fn rank_out(&self) -> Rank {
self.0.rank_out() } - fn rows(&self) -> Rows { - self.0.rows() + fn dnum(&self) -> Dnum { + self.0.dnum() } }@@ -86,12 +86,12 @@
impl LWESwitchingKeyCompressed<Vec<u8>> { pub fn alloc<A>(infos: &A) -> Self where - A: GGLWELayoutInfos, + A: GGLWEInfos, { debug_assert_eq!( - infos.digits().0, + infos.dsize().0, 1, - "digits > 1 is not supported for LWESwitchingKeyCompressed" + "dsize > 1 is not supported for LWESwitchingKeyCompressed" ); debug_assert_eq!( infos.rank_in().0,@@ -106,26 +106,26 @@ );
Self(GGLWESwitchingKeyCompressed::alloc(infos)) } - pub fn alloc_with(n: Degree, base2k: Base2K, k: TorusPrecision, rows: Rows) -> Self { + pub fn alloc_with(n: Degree, base2k: Base2K, k: TorusPrecision, dnum: Dnum) -> Self { Self(GGLWESwitchingKeyCompressed::alloc_with( n, base2k, k, - rows, - Digits(1), Rank(1), Rank(1), + dnum, + Dsize(1), )) } pub fn alloc_bytes<A>(infos: &A) -> usize where - A: GGLWELayoutInfos, + A: GGLWEInfos, { debug_assert_eq!( - infos.digits().0, + infos.dsize().0, 1, - "digits > 1 is not supported for LWESwitchingKey" + "dsize > 1 is not supported for LWESwitchingKey" ); debug_assert_eq!( infos.rank_in().0,@@ -140,8 +140,8 @@ );
GGLWESwitchingKeyCompressed::alloc_bytes(infos) } - pub fn alloc_bytes_with(n: Degree, base2k: Base2K, k: TorusPrecision, rows: Rows) -> usize { - GGLWESwitchingKeyCompressed::alloc_bytes_with(n, base2k, k, rows, Digits(1), Rank(1), Rank(1)) + pub fn alloc_bytes_with(n: Degree, base2k: Base2K, k: TorusPrecision, dnum: Dnum) -> usize { + GGLWESwitchingKeyCompressed::alloc_bytes_with(n, base2k, k, Rank(1), dnum, Dsize(1)) } }
@@ -5,7 +5,7 @@ source::Source,
}; use crate::layouts::{ - Base2K, Degree, Digits, GGLWELayoutInfos, GLWEInfos, LWEInfos, LWEToGLWESwitchingKey, Rank, Rows, TorusPrecision, + Base2K, Degree, Dnum, Dsize, GGLWEInfos, GLWEInfos, LWEInfos, LWEToGLWESwitchingKey, Rank, TorusPrecision, compressed::{Decompress, GGLWESwitchingKeyCompressed}, }; use std::fmt;@@ -35,9 +35,9 @@ self.rank_out()
} } -impl<D: Data> GGLWELayoutInfos for LWEToGLWESwitchingKeyCompressed<D> { - fn digits(&self) -> Digits { - self.0.digits() +impl<D: Data> GGLWEInfos for LWEToGLWESwitchingKeyCompressed<D> { + fn dsize(&self) -> Dsize { + self.0.dsize() } fn rank_in(&self) -> Rank {@@ -48,8 +48,8 @@ fn rank_out(&self) -> Rank {
self.0.rank_out() } - fn rows(&self) -> Rows { - self.0.rows() + fn dnum(&self) -> Dnum { + self.0.dnum() } }@@ -86,12 +86,12 @@
impl LWEToGLWESwitchingKeyCompressed<Vec<u8>> { pub fn alloc<A>(infos: &A) -> Self where - A: GGLWELayoutInfos, + A: GGLWEInfos, { debug_assert_eq!( - infos.digits().0, + infos.dsize().0, 1, - "digits > 1 is not supported for LWEToGLWESwitchingKeyCompressed" + "dsize > 1 is not supported for LWEToGLWESwitchingKeyCompressed" ); debug_assert_eq!( infos.rank_in().0,@@ -101,21 +101,21 @@ );
Self(GGLWESwitchingKeyCompressed::alloc(infos)) } - pub fn alloc_with(n: Degree, base2k: Base2K, k: TorusPrecision, rows: Rows, rank_out: Rank) -> Self { + pub fn alloc_with(n: Degree, base2k: Base2K, k: TorusPrecision, rank_out: Rank, dnum: Dnum) -> Self { Self(GGLWESwitchingKeyCompressed::alloc_with( n, base2k, k, - rows, - Digits(1), Rank(1), rank_out, + dnum, + Dsize(1), )) } pub fn alloc_bytes<A>(infos: &A) -> usize where - A: GGLWELayoutInfos, + A: GGLWEInfos, { debug_assert_eq!( infos.rank_in().0,@@ -123,15 +123,15 @@ 1,
"rank_in > 1 is not supported for LWEToGLWESwitchingKey" ); debug_assert_eq!( - infos.digits().0, + infos.dsize().0, 1, - "digits > 1 is not supported for LWEToGLWESwitchingKey" + "dsize > 1 is not supported for LWEToGLWESwitchingKey" ); GGLWESwitchingKeyCompressed::alloc_bytes(infos) } - pub fn alloc_bytes_with(n: Degree, base2k: Base2K, k: TorusPrecision, rows: Rows, rank_out: Rank) -> usize { - GGLWESwitchingKeyCompressed::alloc_bytes_with(n, base2k, k, rows, Digits(1), Rank(1), rank_out) + pub fn alloc_bytes_with(n: Degree, base2k: Base2K, k: TorusPrecision, dnum: Dnum) -> usize { + GGLWESwitchingKeyCompressed::alloc_bytes_with(n, base2k, k, Rank(1), dnum, Dsize(1)) } }
@@ -4,7 +4,7 @@ source::Source,
}; use crate::layouts::{ - Base2K, Degree, Digits, GGLWELayoutInfos, GGLWESwitchingKey, GLWECiphertext, GLWEInfos, LWEInfos, Rank, Rows, TorusPrecision, + Base2K, Degree, Dnum, Dsize, GGLWEInfos, GGLWESwitchingKey, GLWECiphertext, GLWEInfos, LWEInfos, Rank, TorusPrecision, }; use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};@@ -15,9 +15,9 @@ pub struct GGLWEAutomorphismKeyLayout {
pub n: Degree, pub base2k: Base2K, pub k: TorusPrecision, - pub rows: Rows, - pub digits: Digits, pub rank: Rank, + pub dnum: Dnum, + pub dsize: Dsize, } #[derive(PartialEq, Eq, Clone)]@@ -56,7 +56,7 @@ self.rank_out()
} } -impl<D: Data> GGLWELayoutInfos for GGLWEAutomorphismKey<D> { +impl<D: Data> GGLWEInfos for GGLWEAutomorphismKey<D> { fn rank_in(&self) -> Rank { self.key.rank_in() }@@ -65,12 +65,12 @@ fn rank_out(&self) -> Rank {
self.key.rank_out() } - fn digits(&self) -> Digits { - self.key.digits() + fn dsize(&self) -> Dsize { + self.key.dsize() } - fn rows(&self) -> Rows { - self.key.rows() + fn dnum(&self) -> Dnum { + self.key.dnum() } }@@ -94,21 +94,21 @@ self.rank
} } -impl GGLWELayoutInfos for GGLWEAutomorphismKeyLayout { +impl GGLWEInfos for GGLWEAutomorphismKeyLayout { fn rank_in(&self) -> Rank { self.rank } - fn digits(&self) -> Digits { - self.digits + fn dsize(&self) -> Dsize { + self.dsize } fn rank_out(&self) -> Rank { self.rank } - fn rows(&self) -> Rows { - self.rows + fn dnum(&self) -> Dnum { + self.dnum } }@@ -133,7 +133,7 @@
impl GGLWEAutomorphismKey<Vec<u8>> { pub fn alloc<A>(infos: &A) -> Self where - A: GGLWELayoutInfos, + A: GGLWEInfos, { assert_eq!( infos.rank_in(),@@ -146,16 +146,16 @@ p: 0,
} } - pub fn alloc_with(n: Degree, base2k: Base2K, k: TorusPrecision, rows: Rows, digits: Digits, rank: Rank) -> Self { + pub fn alloc_with(n: Degree, base2k: Base2K, k: TorusPrecision, rank: Rank, dnum: Dnum, dsize: Dsize) -> Self { GGLWEAutomorphismKey { - key: GGLWESwitchingKey::alloc_with(n, base2k, k, rows, digits, rank, rank), + key: GGLWESwitchingKey::alloc_with(n, base2k, k, rank, rank, dnum, dsize), p: 0, } } pub fn alloc_bytes<A>(infos: &A) -> usize where - A: GGLWELayoutInfos, + A: GGLWEInfos, { assert_eq!( infos.rank_in(),@@ -165,8 +165,8 @@ );
GGLWESwitchingKey::alloc_bytes(infos) } - pub fn bytes_of(n: Degree, base2k: Base2K, k: TorusPrecision, rows: Rows, digits: Digits, rank: Rank) -> usize { - GGLWESwitchingKey::alloc_bytes_with(n, base2k, k, rows, digits, rank, rank) + pub fn bytes_of(n: Degree, base2k: Base2K, k: TorusPrecision, rank: Rank, dnum: Dnum, dsize: Dsize) -> usize { + GGLWESwitchingKey::alloc_bytes_with(n, base2k, k, rank, rank, dnum, dsize) } }
@@ -3,17 +3,17 @@ layouts::{Data, DataMut, DataRef, FillUniform, MatZnx, ReaderFrom, WriterTo, ZnxInfos},
source::Source, }; -use crate::layouts::{Base2K, BuildError, Degree, Digits, GLWECiphertext, GLWEInfos, LWEInfos, Rank, Rows, TorusPrecision}; +use crate::layouts::{Base2K, BuildError, Degree, Dnum, Dsize, GLWECiphertext, GLWEInfos, LWEInfos, Rank, TorusPrecision}; use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; use std::fmt; -pub trait GGLWELayoutInfos +pub trait GGLWEInfos where Self: GLWEInfos, { - fn rows(&self) -> Rows; - fn digits(&self) -> Digits; + fn dnum(&self) -> Dnum; + fn dsize(&self) -> Dsize; fn rank_in(&self) -> Rank; fn rank_out(&self) -> Rank; fn layout(&self) -> GGLWECiphertextLayout {@@ -23,8 +23,8 @@ base2k: self.base2k(),
k: self.k(), rank_in: self.rank_in(), rank_out: self.rank_out(), - digits: self.digits(), - rows: self.rows(), + dsize: self.dsize(), + dnum: self.dnum(), } } }@@ -34,10 +34,10 @@ pub struct GGLWECiphertextLayout {
pub n: Degree, pub base2k: Base2K, pub k: TorusPrecision, - pub rows: Rows, - pub digits: Digits, pub rank_in: Rank, pub rank_out: Rank, + pub dnum: Dnum, + pub dsize: Dsize, } impl LWEInfos for GGLWECiphertextLayout {@@ -60,21 +60,21 @@ self.rank_out
} } -impl GGLWELayoutInfos for GGLWECiphertextLayout { +impl GGLWEInfos for GGLWECiphertextLayout { fn rank_in(&self) -> Rank { self.rank_in } - fn digits(&self) -> Digits { - self.digits + fn dsize(&self) -> Dsize { + self.dsize } fn rank_out(&self) -> Rank { self.rank_out } - fn rows(&self) -> Rows { - self.rows + fn dnum(&self) -> Dnum { + self.dnum } }@@ -83,7 +83,7 @@ pub struct GGLWECiphertext<D: Data> {
pub(crate) data: MatZnx<D>, pub(crate) k: TorusPrecision, pub(crate) base2k: Base2K, - pub(crate) digits: Digits, + pub(crate) dsize: Dsize, } impl<D: Data> LWEInfos for GGLWECiphertext<D> {@@ -110,7 +110,7 @@ self.rank_out()
} } -impl<D: Data> GGLWELayoutInfos for GGLWECiphertext<D> { +impl<D: Data> GGLWEInfos for GGLWECiphertext<D> { fn rank_in(&self) -> Rank { Rank(self.data.cols_in() as u32) }@@ -119,12 +119,12 @@ fn rank_out(&self) -> Rank {
Rank(self.data.cols_out() as u32 - 1) } - fn digits(&self) -> Digits { - self.digits + fn dsize(&self) -> Dsize { + self.dsize } - fn rows(&self) -> Rows { - Rows(self.data.rows() as u32) + fn dnum(&self) -> Dnum { + Dnum(self.data.rows() as u32) } }@@ -132,7 +132,7 @@ pub struct GGLWECiphertextBuilder<D: Data> {
data: Option<MatZnx<D>>, base2k: Option<Base2K>, k: Option<TorusPrecision>, - digits: Option<Digits>, + dsize: Option<Dsize>, } impl<D: Data> GGLWECiphertext<D> {@@ -142,7 +142,7 @@ GGLWECiphertextBuilder {
data: None, base2k: None, k: None, - digits: None, + dsize: None, } } }@@ -151,18 +151,18 @@ impl GGLWECiphertextBuilder<Vec<u8>> {
#[inline] pub fn layout<A>(mut self, infos: &A) -> Self where - A: GGLWELayoutInfos, + A: GGLWEInfos, { self.data = Some(MatZnx::alloc( infos.n().into(), - infos.rows().into(), + infos.dnum().into(), infos.rank_in().into(), (infos.rank_out() + 1).into(), infos.size(), )); self.base2k = Some(infos.base2k()); self.k = Some(infos.k()); - self.digits = Some(infos.digits()); + self.dsize = Some(infos.dsize()); self } }@@ -185,8 +185,8 @@ self
} #[inline] - pub fn digits(mut self, digits: Digits) -> Self { - self.digits = Some(digits); + pub fn dsize(mut self, dsize: Dsize) -> Self { + self.dsize = Some(dsize); self }@@ -194,13 +194,13 @@ pub fn build(self) -> Result<GGLWECiphertext<D>, BuildError> {
let data: MatZnx<D> = self.data.ok_or(BuildError::MissingData)?; let base2k: Base2K = self.base2k.ok_or(BuildError::MissingBase2K)?; let k: TorusPrecision = self.k.ok_or(BuildError::MissingK)?; - let digits: Digits = self.digits.ok_or(BuildError::MissingDigits)?; + let dsize: Dsize = self.dsize.ok_or(BuildError::MissingDigits)?; if base2k == 0_u32 { return Err(BuildError::ZeroBase2K); } - if digits == 0_u32 { + if dsize == 0_u32 { return Err(BuildError::ZeroBase2K); }@@ -224,7 +224,7 @@ Ok(GGLWECiphertext {
data, base2k, k, - digits, + dsize, }) } }@@ -257,10 +257,10 @@ impl<D: DataRef> fmt::Display for GGLWECiphertext<D> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( f, - "(GGLWECiphertext: k={} base2k={} digits={}) {}", + "(GGLWECiphertext: k={} base2k={} dsize={}) {}", self.k().0, self.base2k().0, - self.digits().0, + self.dsize().0, self.data ) }@@ -291,16 +291,16 @@
impl GGLWECiphertext<Vec<u8>> { pub fn alloc<A>(infos: &A) -> Self where - A: GGLWELayoutInfos, + A: GGLWEInfos, { Self::alloc_with( infos.n(), infos.base2k(), infos.k(), - infos.rows(), - infos.digits(), infos.rank_in(), infos.rank_out(), + infos.dnum(), + infos.dsize(), ) }@@ -308,51 +308,51 @@ pub fn alloc_with(
n: Degree, base2k: Base2K, k: TorusPrecision, - rows: Rows, - digits: Digits, rank_in: Rank, rank_out: Rank, + dnum: Dnum, + dsize: Dsize, ) -> Self { let size: usize = k.0.div_ceil(base2k.0) as usize; debug_assert!( - size as u32 > digits.0, - "invalid gglwe: ceil(k/base2k): {size} <= digits: {}", - digits.0 + size as u32 > dsize.0, + "invalid gglwe: ceil(k/base2k): {size} <= dsize: {}", + dsize.0 ); assert!( - rows.0 * digits.0 <= size as u32, - "invalid gglwe: rows: {} * digits:{} > ceil(k/base2k): {size}", - rows.0, - digits.0, + dnum.0 * dsize.0 <= size as u32, + "invalid gglwe: dnum: {} * dsize:{} > ceil(k/base2k): {size}", + dnum.0, + dsize.0, ); Self { data: MatZnx::alloc( n.into(), - rows.into(), + dnum.into(), rank_in.into(), (rank_out + 1).into(), k.0.div_ceil(base2k.0) as usize, ), k, base2k, - digits, + dsize, } } pub fn alloc_bytes<A>(infos: &A) -> usize where - A: GGLWELayoutInfos, + A: GGLWEInfos, { Self::alloc_bytes_with( infos.n(), infos.base2k(), infos.k(), - infos.rows(), - infos.digits(), infos.rank_in(), infos.rank_out(), + infos.dnum(), + infos.dsize(), ) }@@ -360,28 +360,28 @@ pub fn alloc_bytes_with(
n: Degree, base2k: Base2K, k: TorusPrecision, - rows: Rows, - digits: Digits, rank_in: Rank, rank_out: Rank, + dnum: Dnum, + dsize: Dsize, ) -> usize { let size: usize = k.0.div_ceil(base2k.0) as usize; debug_assert!( - size as u32 > digits.0, - "invalid gglwe: ceil(k/base2k): {size} <= digits: {}", - digits.0 + size as u32 > dsize.0, + "invalid gglwe: ceil(k/base2k): {size} <= dsize: {}", + dsize.0 ); assert!( - rows.0 * digits.0 <= size as u32, - "invalid gglwe: rows: {} * digits:{} > ceil(k/base2k): {size}", - rows.0, - digits.0, + dnum.0 * dsize.0 <= size as u32, + "invalid gglwe: dnum: {} * dsize:{} > ceil(k/base2k): {size}", + dnum.0, + dsize.0, ); MatZnx::alloc_bytes( n.into(), - rows.into(), + dnum.into(), rank_in.into(), (rank_out + 1).into(), k.0.div_ceil(base2k.0) as usize,@@ -393,7 +393,7 @@ impl<D: DataMut> ReaderFrom for GGLWECiphertext<D> {
fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> { self.k = TorusPrecision(reader.read_u32::<LittleEndian>()?); self.base2k = Base2K(reader.read_u32::<LittleEndian>()?); - self.digits = Digits(reader.read_u32::<LittleEndian>()?); + self.dsize = Dsize(reader.read_u32::<LittleEndian>()?); self.data.read_from(reader) } }@@ -402,7 +402,7 @@ impl<D: DataRef> WriterTo for GGLWECiphertext<D> {
fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> { writer.write_u32::<LittleEndian>(self.k.0)?; writer.write_u32::<LittleEndian>(self.base2k.0)?; - writer.write_u32::<LittleEndian>(self.digits.0)?; + writer.write_u32::<LittleEndian>(self.dsize.0)?; self.data.write_to(writer) } }
@@ -4,7 +4,7 @@ source::Source,
}; use crate::layouts::{ - Base2K, Degree, Digits, GGLWECiphertext, GGLWELayoutInfos, GLWECiphertext, GLWEInfos, LWEInfos, Rank, Rows, TorusPrecision, + Base2K, Degree, Dnum, Dsize, GGLWECiphertext, GGLWEInfos, GLWECiphertext, GLWEInfos, LWEInfos, Rank, TorusPrecision, }; use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};@@ -15,10 +15,10 @@ pub struct GGLWESwitchingKeyLayout {
pub n: Degree, pub base2k: Base2K, pub k: TorusPrecision, - pub rows: Rows, - pub digits: Digits, pub rank_in: Rank, pub rank_out: Rank, + pub dnum: Dnum, + pub dsize: Dsize, } impl LWEInfos for GGLWESwitchingKeyLayout {@@ -41,7 +41,7 @@ self.rank_out()
} } -impl GGLWELayoutInfos for GGLWESwitchingKeyLayout { +impl GGLWEInfos for GGLWESwitchingKeyLayout { fn rank_in(&self) -> Rank { self.rank_in }@@ -50,12 +50,12 @@ fn rank_out(&self) -> Rank {
self.rank_out } - fn digits(&self) -> Digits { - self.digits + fn dsize(&self) -> Dsize { + self.dsize } - fn rows(&self) -> Rows { - self.rows + fn dnum(&self) -> Dnum { + self.dnum } }@@ -90,7 +90,7 @@ self.rank_out()
} } -impl<D: Data> GGLWELayoutInfos for GGLWESwitchingKey<D> { +impl<D: Data> GGLWEInfos for GGLWESwitchingKey<D> { fn rank_in(&self) -> Rank { self.key.rank_in() }@@ -99,12 +99,12 @@ fn rank_out(&self) -> Rank {
self.key.rank_out() } - fn digits(&self) -> Digits { - self.key.digits() + fn dsize(&self) -> Dsize { + self.key.dsize() } - fn rows(&self) -> Rows { - self.key.rows() + fn dnum(&self) -> Dnum { + self.key.dnum() } }@@ -135,7 +135,7 @@
impl GGLWESwitchingKey<Vec<u8>> { pub fn alloc<A>(infos: &A) -> Self where - A: GGLWELayoutInfos, + A: GGLWEInfos, { GGLWESwitchingKey { key: GGLWECiphertext::alloc(infos),@@ -148,13 +148,13 @@ pub fn alloc_with(
n: Degree, base2k: Base2K, k: TorusPrecision, - rows: Rows, - digits: Digits, rank_in: Rank, rank_out: Rank, + dnum: Dnum, + dsize: Dsize, ) -> Self { GGLWESwitchingKey { - key: GGLWECiphertext::alloc_with(n, base2k, k, rows, digits, rank_in, rank_out), + key: GGLWECiphertext::alloc_with(n, base2k, k, rank_in, rank_out, dnum, dsize), sk_in_n: 0, sk_out_n: 0, }@@ -162,7 +162,7 @@ }
pub fn alloc_bytes<A>(infos: &A) -> usize where - A: GGLWELayoutInfos, + A: GGLWEInfos, { GGLWECiphertext::alloc_bytes(infos) }@@ -171,12 +171,12 @@ pub fn alloc_bytes_with(
n: Degree, base2k: Base2K, k: TorusPrecision, - rows: Rows, - digits: Digits, rank_in: Rank, rank_out: Rank, + dnum: Dnum, + dsize: Dsize, ) -> usize { - GGLWECiphertext::alloc_bytes_with(n, base2k, k, rows, digits, rank_in, rank_out) + GGLWECiphertext::alloc_bytes_with(n, base2k, k, rank_in, rank_out, dnum, dsize) } }
@@ -3,9 +3,7 @@ layouts::{Data, DataMut, DataRef, FillUniform, ReaderFrom, WriterTo},
source::Source, }; -use crate::layouts::{ - Base2K, Degree, Digits, GGLWELayoutInfos, GGLWESwitchingKey, GLWEInfos, LWEInfos, Rank, Rows, TorusPrecision, -}; +use crate::layouts::{Base2K, Degree, Dnum, Dsize, GGLWEInfos, GGLWESwitchingKey, GLWEInfos, LWEInfos, Rank, TorusPrecision}; use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; use std::fmt;@@ -15,9 +13,9 @@ pub struct GGLWETensorKeyLayout {
pub n: Degree, pub base2k: Base2K, pub k: TorusPrecision, - pub rows: Rows, - pub digits: Digits, pub rank: Rank, + pub dnum: Dnum, + pub dsize: Dsize, } #[derive(PartialEq, Eq, Clone)]@@ -49,7 +47,7 @@ self.keys[0].rank_out()
} } -impl<D: Data> GGLWELayoutInfos for GGLWETensorKey<D> { +impl<D: Data> GGLWEInfos for GGLWETensorKey<D> { fn rank_in(&self) -> Rank { self.rank_out() }@@ -58,12 +56,12 @@ fn rank_out(&self) -> Rank {
self.keys[0].rank_out() } - fn digits(&self) -> Digits { - self.keys[0].digits() + fn dsize(&self) -> Dsize { + self.keys[0].dsize() } - fn rows(&self) -> Rows { - self.keys[0].rows() + fn dnum(&self) -> Dnum { + self.keys[0].dnum() } }@@ -87,21 +85,21 @@ self.rank_out()
} } -impl GGLWELayoutInfos for GGLWETensorKeyLayout { +impl GGLWEInfos for GGLWETensorKeyLayout { fn rank_in(&self) -> Rank { self.rank } - fn digits(&self) -> Digits { - self.digits + fn dsize(&self) -> Dsize { + self.dsize } fn rank_out(&self) -> Rank { self.rank } - fn rows(&self) -> Rows { - self.rows + fn dnum(&self) -> Dnum { + self.dnum } }@@ -132,7 +130,7 @@
impl GGLWETensorKey<Vec<u8>> { pub fn alloc<A>(infos: &A) -> Self where - A: GGLWELayoutInfos, + A: GGLWEInfos, { assert_eq!( infos.rank_in(),@@ -143,13 +141,13 @@ Self::alloc_with(
infos.n(), infos.base2k(), infos.k(), - infos.rows(), - infos.digits(), infos.rank_out(), + infos.dnum(), + infos.dsize(), ) } - pub fn alloc_with(n: Degree, base2k: Base2K, k: TorusPrecision, rows: Rows, digits: Digits, rank: Rank) -> Self { + pub fn alloc_with(n: Degree, base2k: Base2K, k: TorusPrecision, rank: Rank, dnum: Dnum, dsize: Dsize) -> Self { let mut keys: Vec<GGLWESwitchingKey<Vec<u8>>> = Vec::new(); let pairs: u32 = (((rank.0 + 1) * rank.0) >> 1).max(1); (0..pairs).for_each(|_| {@@ -157,10 +155,10 @@ keys.push(GGLWESwitchingKey::alloc_with(
n, base2k, k, - rows, - digits, Rank(1), rank, + dnum, + dsize, )); }); Self { keys }@@ -168,7 +166,7 @@ }
pub fn alloc_bytes<A>(infos: &A) -> usize where - A: GGLWELayoutInfos, + A: GGLWEInfos, { assert_eq!( infos.rank_in(),@@ -182,16 +180,16 @@ * GGLWESwitchingKey::alloc_bytes_with(
infos.n(), infos.base2k(), infos.k(), - infos.rows(), - infos.digits(), Rank(1), infos.rank_out(), + infos.dnum(), + infos.dsize(), ) } - pub fn alloc_bytes_with(n: Degree, base2k: Base2K, k: TorusPrecision, rows: Rows, digits: Digits, rank: Rank) -> usize { + pub fn alloc_bytes_with(n: Degree, base2k: Base2K, k: TorusPrecision, rank: Rank, dnum: Dnum, dsize: Dsize) -> usize { let pairs: usize = (((rank.0 + 1) * rank.0) >> 1).max(1) as usize; - pairs * GGLWESwitchingKey::alloc_bytes_with(n, base2k, k, rows, digits, Rank(1), rank) + pairs * GGLWESwitchingKey::alloc_bytes_with(n, base2k, k, Rank(1), rank, dnum, dsize) } }
@@ -4,22 +4,22 @@ source::Source,
}; use std::fmt; -use crate::layouts::{Base2K, BuildError, Degree, Digits, GLWECiphertext, GLWEInfos, LWEInfos, Rank, Rows, TorusPrecision}; +use crate::layouts::{Base2K, BuildError, Degree, Dnum, Dsize, GLWECiphertext, GLWEInfos, LWEInfos, Rank, TorusPrecision}; pub trait GGSWInfos where Self: GLWEInfos, { - fn rows(&self) -> Rows; - fn digits(&self) -> Digits; + fn dnum(&self) -> Dnum; + fn dsize(&self) -> Dsize; fn layout(&self) -> GGSWCiphertextLayout { GGSWCiphertextLayout { n: self.n(), base2k: self.base2k(), k: self.k(), rank: self.rank(), - rows: self.rows(), - digits: self.digits(), + dnum: self.dnum(), + dsize: self.dsize(), } } }@@ -29,9 +29,9 @@ pub struct GGSWCiphertextLayout {
pub n: Degree, pub base2k: Base2K, pub k: TorusPrecision, - pub rows: Rows, - pub digits: Digits, pub rank: Rank, + pub dnum: Dnum, + pub dsize: Dsize, } impl LWEInfos for GGSWCiphertextLayout {@@ -54,12 +54,12 @@ }
} impl GGSWInfos for GGSWCiphertextLayout { - fn digits(&self) -> Digits { - self.digits + fn dsize(&self) -> Dsize { + self.dsize } - fn rows(&self) -> Rows { - self.rows + fn dnum(&self) -> Dnum { + self.dnum } }@@ -68,7 +68,7 @@ pub struct GGSWCiphertext<D: Data> {
pub(crate) data: MatZnx<D>, pub(crate) k: TorusPrecision, pub(crate) base2k: Base2K, - pub(crate) digits: Digits, + pub(crate) dsize: Dsize, } impl<D: Data> LWEInfos for GGSWCiphertext<D> {@@ -96,12 +96,12 @@ }
} impl<D: Data> GGSWInfos for GGSWCiphertext<D> { - fn digits(&self) -> Digits { - self.digits + fn dsize(&self) -> Dsize { + self.dsize } - fn rows(&self) -> Rows { - Rows(self.data.rows() as u32) + fn dnum(&self) -> Dnum { + Dnum(self.data.rows() as u32) } }@@ -109,7 +109,7 @@ pub struct GGSWCiphertextBuilder<D: Data> {
data: Option<MatZnx<D>>, base2k: Option<Base2K>, k: Option<TorusPrecision>, - digits: Option<Digits>, + dsize: Option<Dsize>, } impl<D: Data> GGSWCiphertext<D> {@@ -119,7 +119,7 @@ GGSWCiphertextBuilder {
data: None, base2k: None, k: None, - digits: None, + dsize: None, } } }@@ -131,30 +131,30 @@ where
A: GGSWInfos, { debug_assert!( - infos.size() as u32 > infos.digits().0, - "invalid ggsw: ceil(k/base2k): {} <= digits: {}", + infos.size() as u32 > infos.dsize().0, + "invalid ggsw: ceil(k/base2k): {} <= dsize: {}", infos.size(), - infos.digits() + infos.dsize() ); assert!( - infos.rows().0 * infos.digits().0 <= infos.size() as u32, - "invalid ggsw: rows: {} * digits:{} > ceil(k/base2k): {}", - infos.rows(), - infos.digits(), + infos.dnum().0 * infos.dsize().0 <= infos.size() as u32, + "invalid ggsw: dnum: {} * dsize:{} > ceil(k/base2k): {}", + infos.dnum(), + infos.dsize(), infos.size(), ); self.data = Some(MatZnx::alloc( infos.n().into(), - infos.rows().into(), + infos.dnum().into(), (infos.rank() + 1).into(), (infos.rank() + 1).into(), infos.size(), )); self.base2k = Some(infos.base2k()); self.k = Some(infos.k()); - self.digits = Some(infos.digits()); + self.dsize = Some(infos.dsize()); self } }@@ -177,8 +177,8 @@ self
} #[inline] - pub fn digits(mut self, digits: Digits) -> Self { - self.digits = Some(digits); + pub fn dsize(mut self, dsize: Dsize) -> Self { + self.dsize = Some(dsize); self }@@ -186,13 +186,13 @@ pub fn build(self) -> Result<GGSWCiphertext<D>, BuildError> {
let data: MatZnx<D> = self.data.ok_or(BuildError::MissingData)?; let base2k: Base2K = self.base2k.ok_or(BuildError::MissingBase2K)?; let k: TorusPrecision = self.k.ok_or(BuildError::MissingK)?; - let digits: Digits = self.digits.ok_or(BuildError::MissingDigits)?; + let dsize: Dsize = self.dsize.ok_or(BuildError::MissingDigits)?; if base2k == 0_u32 { return Err(BuildError::ZeroBase2K); } - if digits == 0_u32 { + if dsize == 0_u32 { return Err(BuildError::ZeroBase2K); }@@ -216,7 +216,7 @@ Ok(GGSWCiphertext {
data, base2k, k, - digits, + dsize, }) } }@@ -231,10 +231,10 @@ impl<D: DataRef> fmt::Display for GGSWCiphertext<D> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( f, - "(GGSWCiphertext: k: {} base2k: {} digits: {}) {}", + "(GGSWCiphertext: k: {} base2k: {} dsize: {}) {}", self.k().0, self.base2k().0, - self.digits().0, + self.dsize().0, self.data ) }@@ -277,38 +277,38 @@ Self::alloc_with(
infos.n(), infos.base2k(), infos.k(), - infos.rows(), - infos.digits(), infos.rank(), + infos.dnum(), + infos.dsize(), ) } - pub fn alloc_with(n: Degree, base2k: Base2K, k: TorusPrecision, rows: Rows, digits: Digits, rank: Rank) -> Self { + pub fn alloc_with(n: Degree, base2k: Base2K, k: TorusPrecision, rank: Rank, dnum: Dnum, dsize: Dsize) -> Self { let size: usize = k.0.div_ceil(base2k.0) as usize; debug_assert!( - size as u32 > digits.0, - "invalid ggsw: ceil(k/base2k): {size} <= digits: {}", - digits.0 + size as u32 > dsize.0, + "invalid ggsw: ceil(k/base2k): {size} <= dsize: {}", + dsize.0 ); assert!( - rows.0 * digits.0 <= size as u32, - "invalid ggsw: rows: {} * digits:{} > ceil(k/base2k): {size}", - rows.0, - digits.0, + dnum.0 * dsize.0 <= size as u32, + "invalid ggsw: dnum: {} * dsize:{} > ceil(k/base2k): {size}", + dnum.0, + dsize.0, ); Self { data: MatZnx::alloc( n.into(), - rows.into(), + dnum.into(), (rank + 1).into(), (rank + 1).into(), k.0.div_ceil(base2k.0) as usize, ), k, base2k, - digits, + dsize, } }@@ -320,30 +320,30 @@ Self::alloc_bytes_with(
infos.n(), infos.base2k(), infos.k(), - infos.rows(), - infos.digits(), infos.rank(), + infos.dnum(), + infos.dsize(), ) } - pub fn alloc_bytes_with(n: Degree, base2k: Base2K, k: TorusPrecision, rows: Rows, digits: Digits, rank: Rank) -> usize { + pub fn alloc_bytes_with(n: Degree, base2k: Base2K, k: TorusPrecision, rank: Rank, dnum: Dnum, dsize: Dsize) -> usize { let size: usize = k.0.div_ceil(base2k.0) as usize; debug_assert!( - size as u32 > digits.0, - "invalid ggsw: ceil(k/base2k): {size} <= digits: {}", - digits.0 + size as u32 > dsize.0, + "invalid ggsw: ceil(k/base2k): {size} <= dsize: {}", + dsize.0 ); assert!( - rows.0 * digits.0 <= size as u32, - "invalid ggsw: rows: {} * digits:{} > ceil(k/base2k): {size}", - rows.0, - digits.0, + dnum.0 * dsize.0 <= size as u32, + "invalid ggsw: dnum: {} * dsize:{} > ceil(k/base2k): {size}", + dnum.0, + dsize.0, ); MatZnx::alloc_bytes( n.into(), - rows.into(), + dnum.into(), (rank + 1).into(), (rank + 1).into(), k.0.div_ceil(base2k.0) as usize,@@ -357,7 +357,7 @@ impl<D: DataMut> ReaderFrom for GGSWCiphertext<D> {
fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> { self.k = TorusPrecision(reader.read_u32::<LittleEndian>()?); self.base2k = Base2K(reader.read_u32::<LittleEndian>()?); - self.digits = Digits(reader.read_u32::<LittleEndian>()?); + self.dsize = Dsize(reader.read_u32::<LittleEndian>()?); self.data.read_from(reader) } }@@ -366,7 +366,7 @@ impl<D: DataRef> WriterTo for GGSWCiphertext<D> {
fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> { writer.write_u32::<LittleEndian>(self.k.into())?; writer.write_u32::<LittleEndian>(self.base2k.into())?; - writer.write_u32::<LittleEndian>(self.digits.into())?; + writer.write_u32::<LittleEndian>(self.dsize.into())?; self.data.write_to(writer) } }
@@ -3,22 +3,20 @@ layouts::{Data, DataMut, DataRef, FillUniform, ReaderFrom, WriterTo},
source::Source, }; -use crate::layouts::{ - Base2K, Degree, Digits, GGLWELayoutInfos, GGLWESwitchingKey, GLWEInfos, LWEInfos, Rank, Rows, TorusPrecision, -}; +use crate::layouts::{Base2K, Degree, Dnum, Dsize, GGLWEInfos, GGLWESwitchingKey, GLWEInfos, LWEInfos, Rank, TorusPrecision}; use std::fmt; #[derive(PartialEq, Eq, Copy, Clone, Debug)] -pub struct GLWEToLWESwitchingKeyLayout { +pub struct GLWEToLWEKeyLayout { pub n: Degree, pub base2k: Base2K, pub k: TorusPrecision, - pub rows: Rows, pub rank_in: Rank, + pub dnum: Dnum, } -impl LWEInfos for GLWEToLWESwitchingKeyLayout { +impl LWEInfos for GLWEToLWEKeyLayout { fn n(&self) -> Degree { self.n }@@ -32,35 +30,35 @@ self.k
} } -impl GLWEInfos for GLWEToLWESwitchingKeyLayout { +impl GLWEInfos for GLWEToLWEKeyLayout { fn rank(&self) -> Rank { self.rank_out() } } -impl GGLWELayoutInfos for GLWEToLWESwitchingKeyLayout { +impl GGLWEInfos for GLWEToLWEKeyLayout { fn rank_in(&self) -> Rank { self.rank_in } - fn digits(&self) -> Digits { - Digits(1) + fn dsize(&self) -> Dsize { + Dsize(1) } fn rank_out(&self) -> Rank { Rank(1) } - fn rows(&self) -> Rows { - self.rows + fn dnum(&self) -> Dnum { + self.dnum } } /// A special [GLWESwitchingKey] required to for the conversion from [GLWECiphertext] to [LWECiphertext]. #[derive(PartialEq, Eq, Clone)] -pub struct GLWEToLWESwitchingKey<D: Data>(pub(crate) GGLWESwitchingKey<D>); +pub struct GLWEToLWEKey<D: Data>(pub(crate) GGLWESwitchingKey<D>); -impl<D: Data> LWEInfos for GLWEToLWESwitchingKey<D> { +impl<D: Data> LWEInfos for GLWEToLWEKey<D> { fn base2k(&self) -> Base2K { self.0.base2k() }@@ -78,63 +76,63 @@ self.0.size()
} } -impl<D: Data> GLWEInfos for GLWEToLWESwitchingKey<D> { +impl<D: Data> GLWEInfos for GLWEToLWEKey<D> { fn rank(&self) -> Rank { self.rank_out() } } -impl<D: Data> GGLWELayoutInfos for GLWEToLWESwitchingKey<D> { +impl<D: Data> GGLWEInfos for GLWEToLWEKey<D> { fn rank_in(&self) -> Rank { self.0.rank_in() } - fn digits(&self) -> Digits { - self.0.digits() + fn dsize(&self) -> Dsize { + self.0.dsize() } fn rank_out(&self) -> Rank { self.0.rank_out() } - fn rows(&self) -> Rows { - self.0.rows() + fn dnum(&self) -> Dnum { + self.0.dnum() } } -impl<D: DataRef> fmt::Debug for GLWEToLWESwitchingKey<D> { +impl<D: DataRef> fmt::Debug for GLWEToLWEKey<D> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{self}") } } -impl<D: DataMut> FillUniform for GLWEToLWESwitchingKey<D> { +impl<D: DataMut> FillUniform for GLWEToLWEKey<D> { fn fill_uniform(&mut self, log_bound: usize, source: &mut Source) { self.0.fill_uniform(log_bound, source); } } -impl<D: DataRef> fmt::Display for GLWEToLWESwitchingKey<D> { +impl<D: DataRef> fmt::Display for GLWEToLWEKey<D> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "(GLWEToLWESwitchingKey) {}", self.0) } } -impl<D: DataMut> ReaderFrom for GLWEToLWESwitchingKey<D> { +impl<D: DataMut> ReaderFrom for GLWEToLWEKey<D> { fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> { self.0.read_from(reader) } } -impl<D: DataRef> WriterTo for GLWEToLWESwitchingKey<D> { +impl<D: DataRef> WriterTo for GLWEToLWEKey<D> { fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> { self.0.write_to(writer) } } -impl GLWEToLWESwitchingKey<Vec<u8>> { +impl GLWEToLWEKey<Vec<u8>> { pub fn alloc<A>(infos: &A) -> Self where - A: GGLWELayoutInfos, + A: GGLWEInfos, { debug_assert_eq!( infos.rank_out().0,@@ -142,28 +140,28 @@ 1,
"rank_out > 1 is not supported for GLWEToLWESwitchingKey" ); debug_assert_eq!( - infos.digits().0, + infos.dsize().0, 1, - "digits > 1 is not supported for GLWEToLWESwitchingKey" + "dsize > 1 is not supported for GLWEToLWESwitchingKey" ); Self(GGLWESwitchingKey::alloc(infos)) } - pub fn alloc_with(n: Degree, base2k: Base2K, k: TorusPrecision, rows: Rows, rank_in: Rank) -> Self { + pub fn alloc_with(n: Degree, base2k: Base2K, k: TorusPrecision, rank_in: Rank, dnum: Dnum) -> Self { Self(GGLWESwitchingKey::alloc_with( n, base2k, k, - rows, - Digits(1), rank_in, Rank(1), + dnum, + Dsize(1), )) } pub fn alloc_bytes<A>(infos: &A) -> usize where - A: GGLWELayoutInfos, + A: GGLWEInfos, { debug_assert_eq!( infos.rank_out().0,@@ -171,14 +169,14 @@ 1,
"rank_out > 1 is not supported for GLWEToLWESwitchingKey" ); debug_assert_eq!( - infos.digits().0, + infos.dsize().0, 1, - "digits > 1 is not supported for GLWEToLWESwitchingKey" + "dsize > 1 is not supported for GLWEToLWESwitchingKey" ); GGLWESwitchingKey::alloc_bytes(infos) } - pub fn alloc_bytes_with(n: Degree, base2k: Base2K, k: TorusPrecision, rows: Rows, rank_in: Rank) -> usize { - GGLWESwitchingKey::alloc_bytes_with(n, base2k, k, rows, Digits(1), rank_in, Rank(1)) + pub fn alloc_bytes_with(n: Degree, base2k: Base2K, k: TorusPrecision, rank_in: Rank, dnum: Dnum) -> usize { + GGLWESwitchingKey::alloc_bytes_with(n, base2k, k, rank_in, Rank(1), dnum, Dsize(1)) } }
@@ -5,16 +5,14 @@ layouts::{Data, DataMut, DataRef, FillUniform, ReaderFrom, WriterTo},
source::Source, }; -use crate::layouts::{ - Base2K, Degree, Digits, GGLWELayoutInfos, GGLWESwitchingKey, GLWEInfos, LWEInfos, Rank, Rows, TorusPrecision, -}; +use crate::layouts::{Base2K, Degree, Dnum, Dsize, GGLWEInfos, GGLWESwitchingKey, GLWEInfos, LWEInfos, Rank, TorusPrecision}; #[derive(PartialEq, Eq, Copy, Clone, Debug)] pub struct LWESwitchingKeyLayout { pub n: Degree, pub base2k: Base2K, pub k: TorusPrecision, - pub rows: Rows, + pub dnum: Dnum, } impl LWEInfos for LWESwitchingKeyLayout {@@ -37,21 +35,21 @@ self.rank_out()
} } -impl GGLWELayoutInfos for LWESwitchingKeyLayout { +impl GGLWEInfos for LWESwitchingKeyLayout { fn rank_in(&self) -> Rank { Rank(1) } - fn digits(&self) -> Digits { - Digits(1) + fn dsize(&self) -> Dsize { + Dsize(1) } fn rank_out(&self) -> Rank { Rank(1) } - fn rows(&self) -> Rows { - self.rows + fn dnum(&self) -> Dnum { + self.dnum } }@@ -82,9 +80,9 @@ self.rank_out()
} } -impl<D: Data> GGLWELayoutInfos for LWESwitchingKey<D> { - fn digits(&self) -> Digits { - self.0.digits() +impl<D: Data> GGLWEInfos for LWESwitchingKey<D> { + fn dsize(&self) -> Dsize { + self.0.dsize() } fn rank_in(&self) -> Rank {@@ -95,20 +93,20 @@ fn rank_out(&self) -> Rank {
self.0.rank_out() } - fn rows(&self) -> Rows { - self.0.rows() + fn dnum(&self) -> Dnum { + self.0.dnum() } } impl LWESwitchingKey<Vec<u8>> { pub fn alloc<A>(infos: &A) -> Self where - A: GGLWELayoutInfos, + A: GGLWEInfos, { debug_assert_eq!( - infos.digits().0, + infos.dsize().0, 1, - "digits > 1 is not supported for LWESwitchingKey" + "dsize > 1 is not supported for LWESwitchingKey" ); debug_assert_eq!( infos.rank_in().0,@@ -123,26 +121,26 @@ );
Self(GGLWESwitchingKey::alloc(infos)) } - pub fn alloc_with(n: Degree, base2k: Base2K, k: TorusPrecision, rows: Rows) -> Self { + pub fn alloc_with(n: Degree, base2k: Base2K, k: TorusPrecision, dnum: Dnum) -> Self { Self(GGLWESwitchingKey::alloc_with( n, base2k, k, - rows, - Digits(1), Rank(1), Rank(1), + dnum, + Dsize(1), )) } pub fn alloc_bytes<A>(infos: &A) -> usize where - A: GGLWELayoutInfos, + A: GGLWEInfos, { debug_assert_eq!( - infos.digits().0, + infos.dsize().0, 1, - "digits > 1 is not supported for LWESwitchingKey" + "dsize > 1 is not supported for LWESwitchingKey" ); debug_assert_eq!( infos.rank_in().0,@@ -157,8 +155,8 @@ );
GGLWESwitchingKey::alloc_bytes(infos) } - pub fn alloc_bytes_with(n: Degree, base2k: Base2K, k: TorusPrecision, rows: Rows) -> usize { - GGLWESwitchingKey::alloc_bytes_with(n, base2k, k, rows, Digits(1), Rank(1), Rank(1)) + pub fn alloc_bytes_with(n: Degree, base2k: Base2K, k: TorusPrecision, dnum: Dnum) -> usize { + GGLWESwitchingKey::alloc_bytes_with(n, base2k, k, Rank(1), Rank(1), dnum, Dsize(1)) } }
@@ -5,17 +5,15 @@ layouts::{Data, DataMut, DataRef, FillUniform, ReaderFrom, WriterTo},
source::Source, }; -use crate::layouts::{ - Base2K, Degree, Digits, GGLWELayoutInfos, GGLWESwitchingKey, GLWEInfos, LWEInfos, Rank, Rows, TorusPrecision, -}; +use crate::layouts::{Base2K, Degree, Dnum, Dsize, GGLWEInfos, GGLWESwitchingKey, GLWEInfos, LWEInfos, Rank, TorusPrecision}; #[derive(PartialEq, Eq, Copy, Clone, Debug)] pub struct LWEToGLWESwitchingKeyLayout { pub n: Degree, pub base2k: Base2K, pub k: TorusPrecision, - pub rows: Rows, pub rank_out: Rank, + pub dnum: Dnum, } impl LWEInfos for LWEToGLWESwitchingKeyLayout {@@ -38,21 +36,21 @@ self.rank_out()
} } -impl GGLWELayoutInfos for LWEToGLWESwitchingKeyLayout { +impl GGLWEInfos for LWEToGLWESwitchingKeyLayout { fn rank_in(&self) -> Rank { Rank(1) } - fn digits(&self) -> Digits { - Digits(1) + fn dsize(&self) -> Dsize { + Dsize(1) } fn rank_out(&self) -> Rank { self.rank_out } - fn rows(&self) -> Rows { - self.rows + fn dnum(&self) -> Dnum { + self.dnum } }@@ -82,9 +80,9 @@ fn rank(&self) -> Rank {
self.rank_out() } } -impl<D: Data> GGLWELayoutInfos for LWEToGLWESwitchingKey<D> { - fn digits(&self) -> Digits { - self.0.digits() +impl<D: Data> GGLWEInfos for LWEToGLWESwitchingKey<D> { + fn dsize(&self) -> Dsize { + self.0.dsize() } fn rank_in(&self) -> Rank {@@ -95,8 +93,8 @@ fn rank_out(&self) -> Rank {
self.0.rank_out() } - fn rows(&self) -> Rows { - self.0.rows() + fn dnum(&self) -> Dnum { + self.0.dnum() } }@@ -133,7 +131,7 @@
impl LWEToGLWESwitchingKey<Vec<u8>> { pub fn alloc<A>(infos: &A) -> Self where - A: GGLWELayoutInfos, + A: GGLWEInfos, { debug_assert_eq!( infos.rank_in().0,@@ -141,28 +139,28 @@ 1,
"rank_in > 1 is not supported for LWEToGLWESwitchingKey" ); debug_assert_eq!( - infos.digits().0, + infos.dsize().0, 1, - "digits > 1 is not supported for LWEToGLWESwitchingKey" + "dsize > 1 is not supported for LWEToGLWESwitchingKey" ); Self(GGLWESwitchingKey::alloc(infos)) } - pub fn alloc_with(n: Degree, base2k: Base2K, k: TorusPrecision, rows: Rows, rank_out: Rank) -> Self { + pub fn alloc_with(n: Degree, base2k: Base2K, k: TorusPrecision, rank_out: Rank, dnum: Dnum) -> Self { Self(GGLWESwitchingKey::alloc_with( n, base2k, k, - rows, - Digits(1), Rank(1), rank_out, + dnum, + Dsize(1), )) } pub fn alloc_bytes<A>(infos: &A) -> usize where - A: GGLWELayoutInfos, + A: GGLWEInfos, { debug_assert_eq!( infos.rank_in().0,@@ -170,14 +168,14 @@ 1,
"rank_in > 1 is not supported for LWEToGLWESwitchingKey" ); debug_assert_eq!( - infos.digits().0, + infos.dsize().0, 1, - "digits > 1 is not supported for LWEToGLWESwitchingKey" + "dsize > 1 is not supported for LWEToGLWESwitchingKey" ); GGLWESwitchingKey::alloc_bytes(infos) } - pub fn alloc_bytes_with(n: Degree, base2k: Base2K, k: TorusPrecision, rows: Rows, rank_out: Rank) -> usize { - GGLWESwitchingKey::alloc_bytes_with(n, base2k, k, rows, Digits(1), Rank(1), rank_out) + pub fn alloc_bytes_with(n: Degree, base2k: Base2K, k: TorusPrecision, dnum: Dnum, rank_out: Rank) -> usize { + GGLWESwitchingKey::alloc_bytes_with(n, base2k, k, Rank(1), rank_out, dnum, Dsize(1)) } }
@@ -209,9 +209,9 @@
newtype_u32!(Degree); newtype_u32!(TorusPrecision); newtype_u32!(Base2K); -newtype_u32!(Rows); +newtype_u32!(Dnum); newtype_u32!(Rank); -newtype_u32!(Digits); +newtype_u32!(Dsize); impl Degree { pub fn log2(&self) -> usize {
@@ -4,7 +4,7 @@ layouts::{Backend, Data, DataMut, DataRef, Module, Scratch},
}; use crate::layouts::{ - Base2K, Degree, Digits, GGLWEAutomorphismKey, GGLWELayoutInfos, GLWEInfos, LWEInfos, Rank, Rows, TorusPrecision, + Base2K, Degree, Dnum, Dsize, GGLWEAutomorphismKey, GGLWEInfos, GLWEInfos, LWEInfos, Rank, TorusPrecision, prepared::{GGLWESwitchingKeyPrepared, Prepare, PrepareAlloc}, };@@ -44,7 +44,7 @@ self.rank_out()
} } -impl<D: Data, B: Backend> GGLWELayoutInfos for GGLWEAutomorphismKeyPrepared<D, B> { +impl<D: Data, B: Backend> GGLWEInfos for GGLWEAutomorphismKeyPrepared<D, B> { fn rank_in(&self) -> Rank { self.key.rank_in() }@@ -53,19 +53,19 @@ fn rank_out(&self) -> Rank {
self.key.rank_out() } - fn digits(&self) -> Digits { - self.key.digits() + fn dsize(&self) -> Dsize { + self.key.dsize() } - fn rows(&self) -> Rows { - self.key.rows() + fn dnum(&self) -> Dnum { + self.key.dnum() } } impl<B: Backend> GGLWEAutomorphismKeyPrepared<Vec<u8>, B> { pub fn alloc<A>(module: &Module<B>, infos: &A) -> Self where - A: GGLWELayoutInfos, + A: GGLWEInfos, Module<B>: VmpPMatAlloc<B>, { assert_eq!(@@ -79,19 +79,19 @@ p: 0,
} } - pub fn alloc_with(module: &Module<B>, base2k: Base2K, k: TorusPrecision, rows: Rows, digits: Digits, rank: Rank) -> Self + pub fn alloc_with(module: &Module<B>, base2k: Base2K, k: TorusPrecision, rank: Rank, dnum: Dnum, dsize: Dsize) -> Self where Module<B>: VmpPMatAlloc<B>, { GGLWEAutomorphismKeyPrepared { - key: GGLWESwitchingKeyPrepared::alloc_with(module, base2k, k, rows, digits, rank, rank), + key: GGLWESwitchingKeyPrepared::alloc_with(module, base2k, k, rank, rank, dnum, dsize), p: 0, } } pub fn alloc_bytes<A>(module: &Module<B>, infos: &A) -> usize where - A: GGLWELayoutInfos, + A: GGLWEInfos, Module<B>: VmpPMatAllocBytes, { assert_eq!(@@ -102,18 +102,11 @@ );
GGLWESwitchingKeyPrepared::alloc_bytes(module, infos) } - pub fn alloc_bytes_with( - module: &Module<B>, - base2k: Base2K, - k: TorusPrecision, - rows: Rows, - digits: Digits, - rank: Rank, - ) -> usize + pub fn alloc_bytes_with(module: &Module<B>, base2k: Base2K, k: TorusPrecision, rank: Rank, dnum: Dnum, dsize: Dsize) -> usize where Module<B>: VmpPMatAllocBytes, { - GGLWESwitchingKeyPrepared::alloc_bytes_with(module, base2k, k, rows, digits, rank, rank) + GGLWESwitchingKeyPrepared::alloc_bytes_with(module, base2k, k, rank, rank, dnum, dsize) } }
@@ -5,7 +5,7 @@ oep::VmpPMatAllocBytesImpl,
}; use crate::layouts::{ - Base2K, BuildError, Degree, Digits, GGLWECiphertext, GGLWELayoutInfos, GLWEInfos, LWEInfos, Rank, Rows, TorusPrecision, + Base2K, BuildError, Degree, Dnum, Dsize, GGLWECiphertext, GGLWEInfos, GLWEInfos, LWEInfos, Rank, TorusPrecision, prepared::{Prepare, PrepareAlloc}, };@@ -14,7 +14,7 @@ pub struct GGLWECiphertextPrepared<D: Data, B: Backend> {
pub(crate) data: VmpPMat<D, B>, pub(crate) k: TorusPrecision, pub(crate) base2k: Base2K, - pub(crate) digits: Digits, + pub(crate) dsize: Dsize, } impl<D: Data, B: Backend> LWEInfos for GGLWECiphertextPrepared<D, B> {@@ -41,7 +41,7 @@ self.rank_out()
} } -impl<D: Data, B: Backend> GGLWELayoutInfos for GGLWECiphertextPrepared<D, B> { +impl<D: Data, B: Backend> GGLWEInfos for GGLWECiphertextPrepared<D, B> { fn rank_in(&self) -> Rank { Rank(self.data.cols_in() as u32) }@@ -50,12 +50,12 @@ fn rank_out(&self) -> Rank {
Rank(self.data.cols_out() as u32 - 1) } - fn digits(&self) -> Digits { - self.digits + fn dsize(&self) -> Dsize { + self.dsize } - fn rows(&self) -> Rows { - Rows(self.data.rows() as u32) + fn dnum(&self) -> Dnum { + Dnum(self.data.rows() as u32) } }@@ -63,7 +63,7 @@ pub struct GGLWECiphertextPreparedBuilder<D: Data, B: Backend> {
data: Option<VmpPMat<D, B>>, base2k: Option<Base2K>, k: Option<TorusPrecision>, - digits: Option<Digits>, + dsize: Option<Dsize>, } impl<D: Data, B: Backend> GGLWECiphertextPrepared<D, B> {@@ -73,7 +73,7 @@ GGLWECiphertextPreparedBuilder {
data: None, base2k: None, k: None, - digits: None, + dsize: None, } } }@@ -82,19 +82,19 @@ impl<B: Backend> GGLWECiphertextPreparedBuilder<Vec<u8>, B> {
#[inline] pub fn layout<A>(mut self, infos: &A) -> Self where - A: GGLWELayoutInfos, + A: GGLWEInfos, B: VmpPMatAllocBytesImpl<B>, { self.data = Some(VmpPMat::alloc( infos.n().into(), - infos.rows().into(), + infos.dnum().into(), infos.rank_in().into(), (infos.rank_out() + 1).into(), infos.size(), )); self.base2k = Some(infos.base2k()); self.k = Some(infos.k()); - self.digits = Some(infos.digits()); + self.dsize = Some(infos.dsize()); self } }@@ -117,8 +117,8 @@ self
} #[inline] - pub fn digits(mut self, digits: Digits) -> Self { - self.digits = Some(digits); + pub fn dsize(mut self, dsize: Dsize) -> Self { + self.dsize = Some(dsize); self }@@ -126,13 +126,13 @@ pub fn build(self) -> Result<GGLWECiphertextPrepared<D, B>, BuildError> {
let data: VmpPMat<D, B> = self.data.ok_or(BuildError::MissingData)?; let base2k: Base2K = self.base2k.ok_or(BuildError::MissingBase2K)?; let k: TorusPrecision = self.k.ok_or(BuildError::MissingK)?; - let digits: Digits = self.digits.ok_or(BuildError::MissingDigits)?; + let dsize: Dsize = self.dsize.ok_or(BuildError::MissingDigits)?; if base2k == 0_u32 { return Err(BuildError::ZeroBase2K); } - if digits == 0_u32 { + if dsize == 0_u32 { return Err(BuildError::ZeroBase2K); }@@ -156,7 +156,7 @@ Ok(GGLWECiphertextPrepared {
data, base2k, k, - digits, + dsize, }) } }@@ -164,7 +164,7 @@
impl<B: Backend> GGLWECiphertextPrepared<Vec<u8>, B> { pub fn alloc<A>(module: &Module<B>, infos: &A) -> Self where - A: GGLWELayoutInfos, + A: GGLWEInfos, Module<B>: VmpPMatAlloc<B>, { debug_assert_eq!(module.n(), infos.n().0 as usize, "module.n() != infos.n()");@@ -172,10 +172,10 @@ Self::alloc_with(
module, infos.base2k(), infos.k(), - infos.rows(), - infos.digits(), infos.rank_in(), infos.rank_out(), + infos.dnum(), + infos.dsize(), ) }@@ -183,39 +183,39 @@ pub fn alloc_with(
module: &Module<B>, base2k: Base2K, k: TorusPrecision, - rows: Rows, - digits: Digits, rank_in: Rank, rank_out: Rank, + dnum: Dnum, + dsize: Dsize, ) -> Self where Module<B>: VmpPMatAlloc<B>, { let size: usize = k.0.div_ceil(base2k.0) as usize; debug_assert!( - size as u32 > digits.0, - "invalid gglwe: ceil(k/base2k): {size} <= digits: {}", - digits.0 + size as u32 > dsize.0, + "invalid gglwe: ceil(k/base2k): {size} <= dsize: {}", + dsize.0 ); assert!( - rows.0 * digits.0 <= size as u32, - "invalid gglwe: rows: {} * digits:{} > ceil(k/base2k): {size}", - rows.0, - digits.0, + dnum.0 * dsize.0 <= size as u32, + "invalid gglwe: dnum: {} * dsize:{} > ceil(k/base2k): {size}", + dnum.0, + dsize.0, ); Self { - data: module.vmp_pmat_alloc(rows.into(), rank_in.into(), (rank_out + 1).into(), size), + data: module.vmp_pmat_alloc(dnum.into(), rank_in.into(), (rank_out + 1).into(), size), k, base2k, - digits, + dsize, } } pub fn alloc_bytes<A>(module: &Module<B>, infos: &A) -> usize where - A: GGLWELayoutInfos, + A: GGLWEInfos, Module<B>: VmpPMatAllocBytes, { debug_assert_eq!(module.n(), infos.n().0 as usize, "module.n() != infos.n()");@@ -223,10 +223,10 @@ Self::alloc_bytes_with(
module, infos.base2k(), infos.k(), - infos.rows(), - infos.digits(), infos.rank_in(), infos.rank_out(), + infos.dnum(), + infos.dsize(), ) }@@ -234,29 +234,29 @@ pub fn alloc_bytes_with(
module: &Module<B>, base2k: Base2K, k: TorusPrecision, - rows: Rows, - digits: Digits, rank_in: Rank, rank_out: Rank, + dnum: Dnum, + dsize: Dsize, ) -> usize where Module<B>: VmpPMatAllocBytes, { let size: usize = k.0.div_ceil(base2k.0) as usize; debug_assert!( - size as u32 > digits.0, - "invalid gglwe: ceil(k/base2k): {size} <= digits: {}", - digits.0 + size as u32 > dsize.0, + "invalid gglwe: ceil(k/base2k): {size} <= dsize: {}", + dsize.0 ); assert!( - rows.0 * digits.0 <= size as u32, - "invalid gglwe: rows: {} * digits:{} > ceil(k/base2k): {size}", - rows.0, - digits.0, + dnum.0 * dsize.0 <= size as u32, + "invalid gglwe: dnum: {} * dsize:{} > ceil(k/base2k): {size}", + dnum.0, + dsize.0, ); - module.vmp_pmat_alloc_bytes(rows.into(), rank_in.into(), (rank_out + 1).into(), size) + module.vmp_pmat_alloc_bytes(dnum.into(), rank_in.into(), (rank_out + 1).into(), size) } }@@ -268,7 +268,7 @@ fn prepare(&mut self, module: &Module<B>, other: &GGLWECiphertext<DR>, scratch: &mut Scratch<B>) {
module.vmp_prepare(&mut self.data, &other.data, scratch); self.k = other.k; self.base2k = other.base2k; - self.digits = other.digits; + self.dsize = other.dsize; } }
@@ -4,7 +4,7 @@ layouts::{Backend, Data, DataMut, DataRef, Module, Scratch},
}; use crate::layouts::{ - Base2K, Degree, Digits, GGLWELayoutInfos, GGLWESwitchingKey, GLWEInfos, LWEInfos, Rank, Rows, TorusPrecision, + Base2K, Degree, Dnum, Dsize, GGLWEInfos, GGLWESwitchingKey, GLWEInfos, LWEInfos, Rank, TorusPrecision, prepared::{GGLWECiphertextPrepared, Prepare, PrepareAlloc}, };@@ -39,7 +39,7 @@ self.rank_out()
} } -impl<D: Data, B: Backend> GGLWELayoutInfos for GGLWESwitchingKeyPrepared<D, B> { +impl<D: Data, B: Backend> GGLWEInfos for GGLWESwitchingKeyPrepared<D, B> { fn rank_in(&self) -> Rank { self.key.rank_in() }@@ -48,19 +48,19 @@ fn rank_out(&self) -> Rank {
self.key.rank_out() } - fn digits(&self) -> Digits { - self.key.digits() + fn dsize(&self) -> Dsize { + self.key.dsize() } - fn rows(&self) -> Rows { - self.key.rows() + fn dnum(&self) -> Dnum { + self.key.dnum() } } impl<B: Backend> GGLWESwitchingKeyPrepared<Vec<u8>, B> { pub fn alloc<A>(module: &Module<B>, infos: &A) -> Self where - A: GGLWELayoutInfos, + A: GGLWEInfos, Module<B>: VmpPMatAlloc<B>, { debug_assert_eq!(module.n() as u32, infos.n(), "module.n() != infos.n()");@@ -75,16 +75,16 @@ pub fn alloc_with(
module: &Module<B>, base2k: Base2K, k: TorusPrecision, - rows: Rows, - digits: Digits, rank_in: Rank, rank_out: Rank, + dnum: Dnum, + dsize: Dsize, ) -> Self where Module<B>: VmpPMatAlloc<B>, { GGLWESwitchingKeyPrepared::<Vec<u8>, B> { - key: GGLWECiphertextPrepared::alloc_with(module, base2k, k, rows, digits, rank_in, rank_out), + key: GGLWECiphertextPrepared::alloc_with(module, base2k, k, rank_in, rank_out, dnum, dsize), sk_in_n: 0, sk_out_n: 0, }@@ -92,7 +92,7 @@ }
pub fn alloc_bytes<A>(module: &Module<B>, infos: &A) -> usize where - A: GGLWELayoutInfos, + A: GGLWEInfos, Module<B>: VmpPMatAllocBytes, { debug_assert_eq!(module.n() as u32, infos.n(), "module.n() != infos.n()");@@ -103,15 +103,15 @@ pub fn alloc_bytes_with(
module: &Module<B>, base2k: Base2K, k: TorusPrecision, - rows: Rows, - digits: Digits, rank_in: Rank, rank_out: Rank, + dnum: Dnum, + dsize: Dsize, ) -> usize where Module<B>: VmpPMatAllocBytes, { - GGLWECiphertextPrepared::alloc_bytes_with(module, base2k, k, rows, digits, rank_in, rank_out) + GGLWECiphertextPrepared::alloc_bytes_with(module, base2k, k, rank_in, rank_out, dnum, dsize) } }
@@ -4,7 +4,7 @@ layouts::{Backend, Data, DataMut, DataRef, Module, Scratch},
}; use crate::layouts::{ - Base2K, Degree, Digits, GGLWELayoutInfos, GGLWETensorKey, GLWEInfos, LWEInfos, Rank, Rows, TorusPrecision, + Base2K, Degree, Dnum, Dsize, GGLWEInfos, GGLWETensorKey, GLWEInfos, LWEInfos, Rank, TorusPrecision, prepared::{GGLWESwitchingKeyPrepared, Prepare, PrepareAlloc}, };@@ -37,7 +37,7 @@ self.rank_out()
} } -impl<D: Data, B: Backend> GGLWELayoutInfos for GGLWETensorKeyPrepared<D, B> { +impl<D: Data, B: Backend> GGLWEInfos for GGLWETensorKeyPrepared<D, B> { fn rank_in(&self) -> Rank { self.rank_out() }@@ -46,19 +46,19 @@ fn rank_out(&self) -> Rank {
self.keys[0].rank_out() } - fn digits(&self) -> Digits { - self.keys[0].digits() + fn dsize(&self) -> Dsize { + self.keys[0].dsize() } - fn rows(&self) -> Rows { - self.keys[0].rows() + fn dnum(&self) -> Dnum { + self.keys[0].dnum() } } impl<B: Backend> GGLWETensorKeyPrepared<Vec<u8>, B> { pub fn alloc<A>(module: &Module<B>, infos: &A) -> Self where - A: GGLWELayoutInfos, + A: GGLWEInfos, Module<B>: VmpPMatAlloc<B>, { assert_eq!(@@ -70,13 +70,13 @@ Self::alloc_with(
module, infos.base2k(), infos.k(), - infos.rows(), - infos.digits(), + infos.dnum(), + infos.dsize(), infos.rank_out(), ) } - pub fn alloc_with(module: &Module<B>, base2k: Base2K, k: TorusPrecision, rows: Rows, digits: Digits, rank: Rank) -> Self + pub fn alloc_with(module: &Module<B>, base2k: Base2K, k: TorusPrecision, dnum: Dnum, dsize: Dsize, rank: Rank) -> Self where Module<B>: VmpPMatAlloc<B>, {@@ -87,10 +87,10 @@ keys.push(GGLWESwitchingKeyPrepared::alloc_with(
module, base2k, k, - rows, - digits, Rank(1), rank, + dnum, + dsize, )); }); Self { keys }@@ -98,7 +98,7 @@ }
pub fn alloc_bytes<A>(module: &Module<B>, infos: &A) -> usize where - A: GGLWELayoutInfos, + A: GGLWEInfos, Module<B>: VmpPMatAllocBytes, { assert_eq!(@@ -113,26 +113,19 @@ * GGLWESwitchingKeyPrepared::alloc_bytes_with(
module, infos.base2k(), infos.k(), - infos.rows(), - infos.digits(), Rank(1), infos.rank_out(), + infos.dnum(), + infos.dsize(), ) } - pub fn alloc_bytes_with( - module: &Module<B>, - base2k: Base2K, - k: TorusPrecision, - rows: Rows, - digits: Digits, - rank: Rank, - ) -> usize + pub fn alloc_bytes_with(module: &Module<B>, base2k: Base2K, k: TorusPrecision, rank: Rank, dnum: Dnum, dsize: Dsize) -> usize where Module<B>: VmpPMatAllocBytes, { let pairs: usize = (((rank.0 + 1) * rank.0) >> 1).max(1) as usize; - pairs * GGLWESwitchingKeyPrepared::alloc_bytes_with(module, base2k, k, rows, digits, Rank(1), rank) + pairs * GGLWESwitchingKeyPrepared::alloc_bytes_with(module, base2k, k, Rank(1), rank, dnum, dsize) } }
@@ -1,11 +1,11 @@
use poulpy_hal::{ api::{VmpPMatAlloc, VmpPMatAllocBytes, VmpPrepare}, - layouts::{Backend, Data, DataMut, DataRef, Module, Scratch, VmpPMat, ZnxInfos}, + layouts::{Backend, Data, DataMut, DataRef, Module, Scratch, VmpPMat, VmpPMatToRef, ZnxInfos}, oep::VmpPMatAllocBytesImpl, }; use crate::layouts::{ - Base2K, BuildError, Degree, Digits, GGSWCiphertext, GGSWInfos, GLWEInfos, LWEInfos, Rank, Rows, TorusPrecision, + Base2K, BuildError, Degree, Dnum, Dsize, GGSWCiphertext, GGSWInfos, GLWEInfos, LWEInfos, Rank, TorusPrecision, prepared::{Prepare, PrepareAlloc}, };@@ -14,7 +14,7 @@ pub struct GGSWCiphertextPrepared<D: Data, B: Backend> {
pub(crate) data: VmpPMat<D, B>, pub(crate) k: TorusPrecision, pub(crate) base2k: Base2K, - pub(crate) digits: Digits, + pub(crate) dsize: Dsize, } impl<D: Data, B: Backend> LWEInfos for GGSWCiphertextPrepared<D, B> {@@ -42,12 +42,12 @@ }
} impl<D: Data, B: Backend> GGSWInfos for GGSWCiphertextPrepared<D, B> { - fn digits(&self) -> Digits { - self.digits + fn dsize(&self) -> Dsize { + self.dsize } - fn rows(&self) -> Rows { - Rows(self.data.rows() as u32) + fn dnum(&self) -> Dnum { + Dnum(self.data.rows() as u32) } }@@ -55,7 +55,7 @@ pub struct GGSWCiphertextPreparedBuilder<D: Data, B: Backend> {
data: Option<VmpPMat<D, B>>, base2k: Option<Base2K>, k: Option<TorusPrecision>, - digits: Option<Digits>, + dsize: Option<Dsize>, } impl<D: Data, B: Backend> GGSWCiphertextPrepared<D, B> {@@ -65,7 +65,7 @@ GGSWCiphertextPreparedBuilder {
data: None, base2k: None, k: None, - digits: None, + dsize: None, } } }@@ -78,30 +78,30 @@ A: GGSWInfos,
B: VmpPMatAllocBytesImpl<B>, { debug_assert!( - infos.size() as u32 > infos.digits().0, - "invalid ggsw: ceil(k/base2k): {} <= digits: {}", + infos.size() as u32 > infos.dsize().0, + "invalid ggsw: ceil(k/base2k): {} <= dsize: {}", infos.size(), - infos.digits() + infos.dsize() ); assert!( - infos.rows().0 * infos.digits().0 <= infos.size() as u32, - "invalid ggsw: rows: {} * digits:{} > ceil(k/base2k): {}", - infos.rows(), - infos.digits(), + infos.dnum().0 * infos.dsize().0 <= infos.size() as u32, + "invalid ggsw: dnum: {} * dsize:{} > ceil(k/base2k): {}", + infos.dnum(), + infos.dsize(), infos.size(), ); self.data = Some(VmpPMat::alloc( infos.n().into(), - infos.rows().into(), + infos.dnum().into(), (infos.rank() + 1).into(), (infos.rank() + 1).into(), infos.size(), )); self.base2k = Some(infos.base2k()); self.k = Some(infos.k()); - self.digits = Some(infos.digits()); + self.dsize = Some(infos.dsize()); self } }@@ -124,8 +124,8 @@ self
} #[inline] - pub fn digits(mut self, digits: Digits) -> Self { - self.digits = Some(digits); + pub fn dsize(mut self, dsize: Dsize) -> Self { + self.dsize = Some(dsize); self }@@ -133,13 +133,13 @@ pub fn build(self) -> Result<GGSWCiphertextPrepared<D, B>, BuildError> {
let data: VmpPMat<D, B> = self.data.ok_or(BuildError::MissingData)?; let base2k: Base2K = self.base2k.ok_or(BuildError::MissingBase2K)?; let k: TorusPrecision = self.k.ok_or(BuildError::MissingK)?; - let digits: Digits = self.digits.ok_or(BuildError::MissingDigits)?; + let dsize: Dsize = self.dsize.ok_or(BuildError::MissingDigits)?; if base2k == 0_u32 { return Err(BuildError::ZeroBase2K); } - if digits == 0_u32 { + if dsize == 0_u32 { return Err(BuildError::ZeroBase2K); }@@ -163,7 +163,7 @@ Ok(GGSWCiphertextPrepared {
data, base2k, k, - digits, + dsize, }) } }@@ -178,40 +178,40 @@ Self::alloc_with(
module, infos.base2k(), infos.k(), - infos.rows(), - infos.digits(), + infos.dnum(), + infos.dsize(), infos.rank(), ) } - pub fn alloc_with(module: &Module<B>, base2k: Base2K, k: TorusPrecision, rows: Rows, digits: Digits, rank: Rank) -> Self + pub fn alloc_with(module: &Module<B>, base2k: Base2K, k: TorusPrecision, dnum: Dnum, dsize: Dsize, rank: Rank) -> Self where Module<B>: VmpPMatAlloc<B>, { let size: usize = k.0.div_ceil(base2k.0) as usize; debug_assert!( - size as u32 > digits.0, - "invalid ggsw: ceil(k/base2k): {size} <= digits: {}", - digits.0 + size as u32 > dsize.0, + "invalid ggsw: ceil(k/base2k): {size} <= dsize: {}", + dsize.0 ); assert!( - rows.0 * digits.0 <= size as u32, - "invalid ggsw: rows: {} * digits:{} > ceil(k/base2k): {size}", - rows.0, - digits.0, + dnum.0 * dsize.0 <= size as u32, + "invalid ggsw: dnum: {} * dsize:{} > ceil(k/base2k): {size}", + dnum.0, + dsize.0, ); Self { data: module.vmp_pmat_alloc( - rows.into(), + dnum.into(), (rank + 1).into(), (rank + 1).into(), k.0.div_ceil(base2k.0) as usize, ), k, base2k, - digits, + dsize, } }@@ -224,38 +224,31 @@ Self::alloc_bytes_with(
module, infos.base2k(), infos.k(), - infos.rows(), - infos.digits(), + infos.dnum(), + infos.dsize(), infos.rank(), ) } - pub fn alloc_bytes_with( - module: &Module<B>, - base2k: Base2K, - k: TorusPrecision, - rows: Rows, - digits: Digits, - rank: Rank, - ) -> usize + pub fn alloc_bytes_with(module: &Module<B>, base2k: Base2K, k: TorusPrecision, dnum: Dnum, dsize: Dsize, rank: Rank) -> usize where Module<B>: VmpPMatAllocBytes, { let size: usize = k.0.div_ceil(base2k.0) as usize; debug_assert!( - size as u32 > digits.0, - "invalid ggsw: ceil(k/base2k): {size} <= digits: {}", - digits.0 + size as u32 > dsize.0, + "invalid ggsw: ceil(k/base2k): {size} <= dsize: {}", + dsize.0 ); assert!( - rows.0 * digits.0 <= size as u32, - "invalid ggsw: rows: {} * digits:{} > ceil(k/base2k): {size}", - rows.0, - digits.0, + dnum.0 * dsize.0 <= size as u32, + "invalid ggsw: dnum: {} * dsize:{} > ceil(k/base2k): {size}", + dnum.0, + dsize.0, ); - module.vmp_pmat_alloc_bytes(rows.into(), (rank + 1).into(), (rank + 1).into(), size) + module.vmp_pmat_alloc_bytes(dnum.into(), (rank + 1).into(), (rank + 1).into(), size) } }@@ -273,7 +266,7 @@ fn prepare(&mut self, module: &Module<B>, other: &GGSWCiphertext<DR>, scratch: &mut Scratch<B>) {
module.vmp_prepare(&mut self.data, &other.data, scratch); self.k = other.k; self.base2k = other.base2k; - self.digits = other.digits; + self.dsize = other.dsize; } }@@ -287,3 +280,19 @@ ggsw_prepared.prepare(module, self, scratch);
ggsw_prepared } } + +pub trait GGSWCiphertextPreparedToRef<B: Backend> { + fn to_ref(&self) -> GGSWCiphertextPrepared<&[u8], B>; +} + +impl<D: DataRef, B: Backend> GGSWCiphertextPreparedToRef<B> for GGSWCiphertextPrepared<D, B> { + fn to_ref(&self) -> GGSWCiphertextPrepared<&[u8], B> { + GGSWCiphertextPrepared::builder() + .base2k(self.base2k()) + .dsize(self.dsize()) + .k(self.k()) + .data(self.data.to_ref()) + .build() + .unwrap() + } +}
@@ -4,7 +4,7 @@ layouts::{Backend, Data, DataMut, DataRef, Module, Scratch},
}; use crate::layouts::{ - Base2K, Degree, Digits, GGLWELayoutInfos, GLWEInfos, GLWEToLWESwitchingKey, LWEInfos, Rank, Rows, TorusPrecision, + Base2K, Degree, Dnum, Dsize, GGLWEInfos, GLWEInfos, GLWEToLWEKey, LWEInfos, Rank, TorusPrecision, prepared::{GGLWESwitchingKeyPrepared, Prepare, PrepareAlloc}, };@@ -35,28 +35,28 @@ self.rank_out()
} } -impl<D: Data, B: Backend> GGLWELayoutInfos for GLWEToLWESwitchingKeyPrepared<D, B> { +impl<D: Data, B: Backend> GGLWEInfos for GLWEToLWESwitchingKeyPrepared<D, B> { fn rank_in(&self) -> Rank { self.0.rank_in() } - fn digits(&self) -> Digits { - self.0.digits() + fn dsize(&self) -> Dsize { + self.0.dsize() } fn rank_out(&self) -> Rank { self.0.rank_out() } - fn rows(&self) -> Rows { - self.0.rows() + fn dnum(&self) -> Dnum { + self.0.dnum() } } impl<B: Backend> GLWEToLWESwitchingKeyPrepared<Vec<u8>, B> { pub fn alloc<A>(module: &Module<B>, infos: &A) -> Self where - A: GGLWELayoutInfos, + A: GGLWEInfos, Module<B>: VmpPMatAlloc<B>, { debug_assert_eq!(@@ -65,14 +65,14 @@ 1,
"rank_out > 1 is not supported for GLWEToLWESwitchingKeyPrepared" ); debug_assert_eq!( - infos.digits().0, + infos.dsize().0, 1, - "digits > 1 is not supported for GLWEToLWESwitchingKeyPrepared" + "dsize > 1 is not supported for GLWEToLWESwitchingKeyPrepared" ); Self(GGLWESwitchingKeyPrepared::alloc(module, infos)) } - pub fn alloc_with(module: &Module<B>, base2k: Base2K, k: TorusPrecision, rows: Rows, rank_in: Rank) -> Self + pub fn alloc_with(module: &Module<B>, base2k: Base2K, k: TorusPrecision, rank_in: Rank, dnum: Dnum) -> Self where Module<B>: VmpPMatAlloc<B>, {@@ -80,16 +80,16 @@ Self(GGLWESwitchingKeyPrepared::alloc_with(
module, base2k, k, - rows, - Digits(1), rank_in, Rank(1), + dnum, + Dsize(1), )) } pub fn alloc_bytes<A>(module: &Module<B>, infos: &A) -> usize where - A: GGLWELayoutInfos, + A: GGLWEInfos, Module<B>: VmpPMatAllocBytes, { debug_assert_eq!(@@ -98,22 +98,22 @@ 1,
"rank_out > 1 is not supported for GLWEToLWESwitchingKeyPrepared" ); debug_assert_eq!( - infos.digits().0, + infos.dsize().0, 1, - "digits > 1 is not supported for GLWEToLWESwitchingKeyPrepared" + "dsize > 1 is not supported for GLWEToLWESwitchingKeyPrepared" ); GGLWESwitchingKeyPrepared::alloc_bytes(module, infos) } - pub fn alloc_bytes_with(module: &Module<B>, base2k: Base2K, k: TorusPrecision, rows: Rows, rank_in: Rank) -> usize + pub fn alloc_bytes_with(module: &Module<B>, base2k: Base2K, k: TorusPrecision, rank_in: Rank, dnum: Dnum) -> usize where Module<B>: VmpPMatAllocBytes, { - GGLWESwitchingKeyPrepared::alloc_bytes_with(module, base2k, k, rows, Digits(1), rank_in, Rank(1)) + GGLWESwitchingKeyPrepared::alloc_bytes_with(module, base2k, k, rank_in, Rank(1), dnum, Dsize(1)) } } -impl<D: DataRef, B: Backend> PrepareAlloc<B, GLWEToLWESwitchingKeyPrepared<Vec<u8>, B>> for GLWEToLWESwitchingKey<D> +impl<D: DataRef, B: Backend> PrepareAlloc<B, GLWEToLWESwitchingKeyPrepared<Vec<u8>, B>> for GLWEToLWEKey<D> where Module<B>: VmpPrepare<B> + VmpPMatAlloc<B>, {@@ -124,11 +124,11 @@ ksk_prepared
} } -impl<DM: DataMut, DR: DataRef, B: Backend> Prepare<B, GLWEToLWESwitchingKey<DR>> for GLWEToLWESwitchingKeyPrepared<DM, B> +impl<DM: DataMut, DR: DataRef, B: Backend> Prepare<B, GLWEToLWEKey<DR>> for GLWEToLWESwitchingKeyPrepared<DM, B> where Module<B>: VmpPrepare<B>, { - fn prepare(&mut self, module: &Module<B>, other: &GLWEToLWESwitchingKey<DR>, scratch: &mut Scratch<B>) { + fn prepare(&mut self, module: &Module<B>, other: &GLWEToLWEKey<DR>, scratch: &mut Scratch<B>) { self.0.prepare(module, &other.0, scratch); } }
@@ -4,7 +4,7 @@ layouts::{Backend, Data, DataMut, DataRef, Module, Scratch},
}; use crate::layouts::{ - Base2K, Degree, Digits, GGLWELayoutInfos, GLWEInfos, LWEInfos, LWESwitchingKey, Rank, Rows, TorusPrecision, + Base2K, Degree, Dnum, Dsize, GGLWEInfos, GLWEInfos, LWEInfos, LWESwitchingKey, Rank, TorusPrecision, prepared::{GGLWESwitchingKeyPrepared, Prepare, PrepareAlloc}, };@@ -34,9 +34,9 @@ self.rank_out()
} } -impl<D: Data, B: Backend> GGLWELayoutInfos for LWESwitchingKeyPrepared<D, B> { - fn digits(&self) -> Digits { - self.0.digits() +impl<D: Data, B: Backend> GGLWEInfos for LWESwitchingKeyPrepared<D, B> { + fn dsize(&self) -> Dsize { + self.0.dsize() } fn rank_in(&self) -> Rank {@@ -47,21 +47,21 @@ fn rank_out(&self) -> Rank {
self.0.rank_out() } - fn rows(&self) -> Rows { - self.0.rows() + fn dnum(&self) -> Dnum { + self.0.dnum() } } impl<B: Backend> LWESwitchingKeyPrepared<Vec<u8>, B> { pub fn alloc<A>(module: &Module<B>, infos: &A) -> Self where - A: GGLWELayoutInfos, + A: GGLWEInfos, Module<B>: VmpPMatAlloc<B>, { debug_assert_eq!( - infos.digits().0, + infos.dsize().0, 1, - "digits > 1 is not supported for LWESwitchingKey" + "dsize > 1 is not supported for LWESwitchingKey" ); debug_assert_eq!( infos.rank_in().0,@@ -76,7 +76,7 @@ );
Self(GGLWESwitchingKeyPrepared::alloc(module, infos)) } - pub fn alloc_with(module: &Module<B>, base2k: Base2K, k: TorusPrecision, rows: Rows) -> Self + pub fn alloc_with(module: &Module<B>, base2k: Base2K, k: TorusPrecision, dnum: Dnum) -> Self where Module<B>: VmpPMatAlloc<B>, {@@ -84,22 +84,22 @@ Self(GGLWESwitchingKeyPrepared::alloc_with(
module, base2k, k, - rows, - Digits(1), Rank(1), Rank(1), + dnum, + Dsize(1), )) } pub fn alloc_bytes<A>(module: &Module<B>, infos: &A) -> usize where - A: GGLWELayoutInfos, + A: GGLWEInfos, Module<B>: VmpPMatAllocBytes, { debug_assert_eq!( - infos.digits().0, + infos.dsize().0, 1, - "digits > 1 is not supported for LWESwitchingKey" + "dsize > 1 is not supported for LWESwitchingKey" ); debug_assert_eq!( infos.rank_in().0,@@ -114,11 +114,11 @@ );
GGLWESwitchingKeyPrepared::alloc_bytes(module, infos) } - pub fn alloc_bytes_with(module: &Module<B>, base2k: Base2K, k: TorusPrecision, rows: Rows) -> usize + pub fn alloc_bytes_with(module: &Module<B>, base2k: Base2K, k: TorusPrecision, dnum: Dnum) -> usize where Module<B>: VmpPMatAllocBytes, { - GGLWESwitchingKeyPrepared::alloc_bytes_with(module, base2k, k, rows, Digits(1), Rank(1), Rank(1)) + GGLWESwitchingKeyPrepared::alloc_bytes_with(module, base2k, k, Rank(1), Rank(1), dnum, Dsize(1)) } }
@@ -4,7 +4,7 @@ layouts::{Backend, Data, DataMut, DataRef, Module, Scratch},
}; use crate::layouts::{ - Base2K, Degree, Digits, GGLWELayoutInfos, GLWEInfos, LWEInfos, LWEToGLWESwitchingKey, Rank, Rows, TorusPrecision, + Base2K, Degree, Dnum, Dsize, GGLWEInfos, GLWEInfos, LWEInfos, LWEToGLWESwitchingKey, Rank, TorusPrecision, prepared::{GGLWESwitchingKeyPrepared, Prepare, PrepareAlloc}, };@@ -36,9 +36,9 @@ self.rank_out()
} } -impl<D: Data, B: Backend> GGLWELayoutInfos for LWEToGLWESwitchingKeyPrepared<D, B> { - fn digits(&self) -> Digits { - self.0.digits() +impl<D: Data, B: Backend> GGLWEInfos for LWEToGLWESwitchingKeyPrepared<D, B> { + fn dsize(&self) -> Dsize { + self.0.dsize() } fn rank_in(&self) -> Rank {@@ -49,15 +49,15 @@ fn rank_out(&self) -> Rank {
self.0.rank_out() } - fn rows(&self) -> Rows { - self.0.rows() + fn dnum(&self) -> Dnum { + self.0.dnum() } } impl<B: Backend> LWEToGLWESwitchingKeyPrepared<Vec<u8>, B> { pub fn alloc<A>(module: &Module<B>, infos: &A) -> Self where - A: GGLWELayoutInfos, + A: GGLWEInfos, Module<B>: VmpPMatAlloc<B>, { debug_assert_eq!(@@ -66,14 +66,14 @@ 1,
"rank_in > 1 is not supported for LWEToGLWESwitchingKey" ); debug_assert_eq!( - infos.digits().0, + infos.dsize().0, 1, - "digits > 1 is not supported for LWEToGLWESwitchingKey" + "dsize > 1 is not supported for LWEToGLWESwitchingKey" ); Self(GGLWESwitchingKeyPrepared::alloc(module, infos)) } - pub fn alloc_with(module: &Module<B>, base2k: Base2K, k: TorusPrecision, rows: Rows, rank_out: Rank) -> Self + pub fn alloc_with(module: &Module<B>, base2k: Base2K, k: TorusPrecision, rank_out: Rank, dnum: Dnum) -> Self where Module<B>: VmpPMatAlloc<B>, {@@ -81,16 +81,16 @@ Self(GGLWESwitchingKeyPrepared::alloc_with(
module, base2k, k, - rows, - Digits(1), Rank(1), rank_out, + dnum, + Dsize(1), )) } pub fn alloc_bytes<A>(module: &Module<B>, infos: &A) -> usize where - A: GGLWELayoutInfos, + A: GGLWEInfos, Module<B>: VmpPMatAllocBytes, { debug_assert_eq!(@@ -99,18 +99,18 @@ 1,
"rank_in > 1 is not supported for LWEToGLWESwitchingKey" ); debug_assert_eq!( - infos.digits().0, + infos.dsize().0, 1, - "digits > 1 is not supported for LWEToGLWESwitchingKey" + "dsize > 1 is not supported for LWEToGLWESwitchingKey" ); GGLWESwitchingKeyPrepared::alloc_bytes(module, infos) } - pub fn alloc_bytes_with(module: &Module<B>, base2k: Base2K, k: TorusPrecision, rows: Rows, rank_out: Rank) -> usize + pub fn alloc_bytes_with(module: &Module<B>, base2k: Base2K, k: TorusPrecision, dnum: Dnum, rank_out: Rank) -> usize where Module<B>: VmpPMatAllocBytes, { - GGLWESwitchingKeyPrepared::alloc_bytes_with(module, base2k, k, rows, Digits(1), Rank(1), rank_out) + GGLWESwitchingKeyPrepared::alloc_bytes_with(module, base2k, k, Rank(1), rank_out, dnum, Dsize(1)) } }
@@ -15,6 +15,7 @@
pub use operations::*; pub mod layouts; pub use dist::*; +pub use external_product::*; pub use glwe_packing::*; pub use encryption::SIGMA;
@@ -8,7 +8,7 @@ layouts::{Backend, DataRef, Module, ScalarZnx, ScratchOwned, ZnxZero},
oep::{ScratchOwnedAllocImpl, ScratchOwnedBorrowImpl, TakeVecZnxBigImpl, TakeVecZnxDftImpl}, }; -use crate::layouts::{GGLWECiphertext, GGLWELayoutInfos, GLWECiphertext, GLWEPlaintext, LWEInfos, prepared::GLWESecretPrepared}; +use crate::layouts::{GGLWECiphertext, GGLWEInfos, GLWECiphertext, GLWEPlaintext, LWEInfos, prepared::GLWESecretPrepared}; impl<D: DataRef> GGLWECiphertext<D> { pub fn assert_noise<B, DataSk, DataWant>(@@ -32,24 +32,18 @@ + VecZnxNormalizeTmpBytes
+ VecZnxSubScalarInplace, B: Backend + TakeVecZnxDftImpl<B> + TakeVecZnxBigImpl<B> + ScratchOwnedAllocImpl<B> + ScratchOwnedBorrowImpl<B>, { - let digits: usize = self.digits().into(); + let dsize: usize = self.dsize().into(); let base2k: usize = self.base2k().into(); let mut scratch: ScratchOwned<B> = ScratchOwned::alloc(GLWECiphertext::decrypt_scratch_space(module, self)); let mut pt: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(self); (0..self.rank_in().into()).for_each(|col_i| { - (0..self.rows().into()).for_each(|row_i| { + (0..self.dnum().into()).for_each(|row_i| { self.at(row_i, col_i) .decrypt(module, &mut pt, sk, scratch.borrow()); - module.vec_znx_sub_scalar_inplace( - &mut pt.data, - 0, - (digits - 1) + row_i * digits, - pt_want, - col_i, - ); + module.vec_znx_sub_scalar_inplace(&mut pt.data, 0, (dsize - 1) + row_i * dsize, pt_want, col_i); let noise_have: f64 = pt.data.std(base2k, 0).log2();
@@ -42,7 +42,7 @@ B: Backend + TakeVecZnxDftImpl<B> + TakeVecZnxBigImpl<B> + ScratchOwnedAllocImpl<B> + ScratchOwnedBorrowImpl<B>,
F: Fn(usize) -> f64, { let base2k: usize = self.base2k().into(); - let digits: usize = self.digits().into(); + let dsize: usize = self.dsize().into(); let mut pt: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(self); let mut pt_have: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(self);@@ -53,8 +53,8 @@ let mut scratch: ScratchOwned<B> =
ScratchOwned::alloc(GLWECiphertext::decrypt_scratch_space(module, self) | module.vec_znx_normalize_tmp_bytes()); (0..(self.rank() + 1).into()).for_each(|col_j| { - (0..self.rows().into()).for_each(|row_i| { - module.vec_znx_add_scalar_inplace(&mut pt.data, 0, (digits - 1) + row_i * digits, pt_want, 0); + (0..self.dnum().into()).for_each(|row_i| { + module.vec_znx_add_scalar_inplace(&mut pt.data, 0, (dsize - 1) + row_i * dsize, pt_want, 0); // mul with sk[col_j-1] if col_j > 0 {@@ -114,7 +114,7 @@ + VecZnxSubInplace,
B: Backend + TakeVecZnxDftImpl<B> + TakeVecZnxBigImpl<B> + ScratchOwnedAllocImpl<B> + ScratchOwnedBorrowImpl<B>, { let base2k: usize = self.base2k().into(); - let digits: usize = self.digits().into(); + let dsize: usize = self.dsize().into(); let mut pt: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(self); let mut pt_have: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(self);@@ -125,8 +125,8 @@ let mut scratch: ScratchOwned<B> =
ScratchOwned::alloc(GLWECiphertext::decrypt_scratch_space(module, self) | module.vec_znx_normalize_tmp_bytes()); (0..(self.rank() + 1).into()).for_each(|col_j| { - (0..self.rows().into()).for_each(|row_i| { - module.vec_znx_add_scalar_inplace(&mut pt.data, 0, (digits - 1) + row_i * digits, pt_want, 0); + (0..self.dnum().into()).for_each(|row_i| { + module.vec_znx_add_scalar_inplace(&mut pt.data, 0, (dsize - 1) + row_i * dsize, pt_want, 0); // mul with sk[col_j-1] if col_j > 0 {@@ -146,12 +146,12 @@ }
self.at(row_i, col_j) .decrypt(module, &mut pt_have, sk_prepared, scratch.borrow()); - module.vec_znx_sub_inplace(&mut pt_have.data, 0, &pt.data, 0); let std_pt: f64 = pt_have.data.std(base2k, 0).log2(); println!("col: {col_j} row: {row_i}: {std_pt}"); pt.data.zero(); + // println!(">>>>>>>>>>>>>>>>"); }); }); }
@@ -1,16 +1,44 @@
use poulpy_hal::{ api::{ - ScratchOwnedAlloc, ScratchOwnedBorrow, SvpApplyDftToDftInplace, VecZnxBigAddInplace, VecZnxBigAddSmallInplace, - VecZnxBigAllocBytes, VecZnxBigNormalize, VecZnxDftAllocBytes, VecZnxDftApply, VecZnxIdftApplyConsume, - VecZnxNormalizeInplace, VecZnxNormalizeTmpBytes, VecZnxSubInplace, + ScratchOwnedAlloc, ScratchOwnedBorrow, SvpApplyDftToDftInplace, TakeVecZnxBig, TakeVecZnxDft, VecZnxBigAddInplace, + VecZnxBigAddSmallInplace, VecZnxBigAllocBytes, VecZnxBigNormalize, VecZnxDftAllocBytes, VecZnxDftApply, + VecZnxIdftApplyConsume, VecZnxNormalizeInplace, VecZnxNormalizeTmpBytes, VecZnxSubInplace, }, - layouts::{Backend, DataRef, Module, ScratchOwned}, + layouts::{Backend, DataRef, Module, Scratch, ScratchOwned}, oep::{ScratchOwnedAllocImpl, ScratchOwnedBorrowImpl, TakeVecZnxBigImpl, TakeVecZnxDftImpl}, }; use crate::layouts::{GLWECiphertext, GLWEPlaintext, LWEInfos, prepared::GLWESecretPrepared}; impl<D: DataRef> GLWECiphertext<D> { + pub fn noise<B, DataSk, DataPt>( + &self, + module: &Module<B>, + sk_prepared: &GLWESecretPrepared<DataSk, B>, + pt_want: &GLWEPlaintext<DataPt>, + scratch: &mut Scratch<B>, + ) -> f64 + where + DataSk: DataRef, + DataPt: DataRef, + B: Backend, + Module<B>: VecZnxDftApply<B> + + VecZnxSubInplace + + VecZnxNormalizeInplace<B> + + SvpApplyDftToDftInplace<B> + + VecZnxIdftApplyConsume<B> + + VecZnxBigAddInplace<B> + + VecZnxBigAddSmallInplace<B> + + VecZnxBigNormalize<B>, + Scratch<B>: TakeVecZnxDft<B> + TakeVecZnxBig<B>, + { + let mut pt_have: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(self); + self.decrypt(module, &mut pt_have, sk_prepared, scratch); + module.vec_znx_sub_inplace(&mut pt_have.data, 0, &pt_want.data, 0); + module.vec_znx_normalize_inplace(self.base2k().into(), &mut pt_have.data, 0, scratch); + pt_have.data.std(self.base2k().into(), 0).log2() + } + pub fn assert_noise<B, DataSk, DataPt>( &self, module: &Module<B>,@@ -33,16 +61,8 @@ + VecZnxSubInplace
+ VecZnxNormalizeInplace<B>, B: Backend + TakeVecZnxDftImpl<B> + TakeVecZnxBigImpl<B> + ScratchOwnedAllocImpl<B> + ScratchOwnedBorrowImpl<B>, { - let mut pt_have: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(self); - let mut scratch: ScratchOwned<B> = ScratchOwned::alloc(GLWECiphertext::decrypt_scratch_space(module, self)); - - self.decrypt(module, &mut pt_have, sk_prepared, scratch.borrow()); - - module.vec_znx_sub_inplace(&mut pt_have.data, 0, &pt_want.data, 0); - module.vec_znx_normalize_inplace(self.base2k().into(), &mut pt_have.data, 0, scratch.borrow()); - - let noise_have: f64 = pt_have.data.std(self.base2k().into(), 0).log2(); + let noise_have: f64 = self.noise(module, sk_prepared, pt_want, scratch.borrow()); assert!(noise_have <= max_noise, "{noise_have} {max_noise}"); } }
@@ -6,8 +6,8 @@
use crate::{ dist::Distribution, layouts::{ - Degree, GGLWEAutomorphismKey, GGLWECiphertext, GGLWELayoutInfos, GGLWESwitchingKey, GGLWETensorKey, GGSWCiphertext, - GGSWInfos, GLWECiphertext, GLWEInfos, GLWEPlaintext, GLWEPublicKey, GLWESecret, Rank, + Degree, GGLWEAutomorphismKey, GGLWECiphertext, GGLWEInfos, GGLWESwitchingKey, GGLWETensorKey, GGSWCiphertext, GGSWInfos, + GLWECiphertext, GLWEInfos, GLWEPlaintext, GLWEPublicKey, GLWESecret, Rank, prepared::{ GGLWEAutomorphismKeyPrepared, GGLWECiphertextPrepared, GGLWESwitchingKeyPrepared, GGLWETensorKeyPrepared, GGSWCiphertextPrepared, GLWEPublicKeyPrepared, GLWESecretPrepared,@@ -36,13 +36,13 @@
pub trait TakeGGLWE { fn take_gglwe<A>(&mut self, infos: &A) -> (GGLWECiphertext<&mut [u8]>, &mut Self) where - A: GGLWELayoutInfos; + A: GGLWEInfos; } pub trait TakeGGLWEPrepared<B: Backend> { fn take_gglwe_prepared<A>(&mut self, infos: &A) -> (GGLWECiphertextPrepared<&mut [u8], B>, &mut Self) where - A: GGLWELayoutInfos; + A: GGLWEInfos; } pub trait TakeGGSW {@@ -80,37 +80,37 @@
pub trait TakeGLWESwitchingKey { fn take_glwe_switching_key<A>(&mut self, infos: &A) -> (GGLWESwitchingKey<&mut [u8]>, &mut Self) where - A: GGLWELayoutInfos; + A: GGLWEInfos; } pub trait TakeGGLWESwitchingKeyPrepared<B: Backend> { fn take_gglwe_switching_key_prepared<A>(&mut self, infos: &A) -> (GGLWESwitchingKeyPrepared<&mut [u8], B>, &mut Self) where - A: GGLWELayoutInfos; + A: GGLWEInfos; } pub trait TakeTensorKey { fn take_tensor_key<A>(&mut self, infos: &A) -> (GGLWETensorKey<&mut [u8]>, &mut Self) where - A: GGLWELayoutInfos; + A: GGLWEInfos; } pub trait TakeGGLWETensorKeyPrepared<B: Backend> { fn take_gglwe_tensor_key_prepared<A>(&mut self, infos: &A) -> (GGLWETensorKeyPrepared<&mut [u8], B>, &mut Self) where - A: GGLWELayoutInfos; + A: GGLWEInfos; } pub trait TakeGGLWEAutomorphismKey { fn take_gglwe_automorphism_key<A>(&mut self, infos: &A) -> (GGLWEAutomorphismKey<&mut [u8]>, &mut Self) where - A: GGLWELayoutInfos; + A: GGLWEInfos; } pub trait TakeGGLWEAutomorphismKeyPrepared<B: Backend> { fn take_gglwe_automorphism_key_prepared<A>(&mut self, infos: &A) -> (GGLWEAutomorphismKeyPrepared<&mut [u8], B>, &mut Self) where - A: GGLWELayoutInfos; + A: GGLWEInfos; } impl<B: Backend> TakeGLWECt for Scratch<B>@@ -180,11 +180,11 @@ Scratch<B>: TakeMatZnx,
{ fn take_gglwe<A>(&mut self, infos: &A) -> (GGLWECiphertext<&mut [u8]>, &mut Self) where - A: GGLWELayoutInfos, + A: GGLWEInfos, { let (data, scratch) = self.take_mat_znx( infos.n().into(), - infos.rows().0.div_ceil(infos.digits().0) as usize, + infos.dnum().0.div_ceil(infos.dsize().0) as usize, infos.rank_in().into(), (infos.rank_out() + 1).into(), infos.size(),@@ -193,7 +193,7 @@ (
GGLWECiphertext::builder() .base2k(infos.base2k()) .k(infos.k()) - .digits(infos.digits()) + .dsize(infos.dsize()) .data(data) .build() .unwrap(),@@ -208,11 +208,11 @@ Scratch<B>: TakeVmpPMat<B>,
{ fn take_gglwe_prepared<A>(&mut self, infos: &A) -> (GGLWECiphertextPrepared<&mut [u8], B>, &mut Self) where - A: GGLWELayoutInfos, + A: GGLWEInfos, { let (data, scratch) = self.take_vmp_pmat( infos.n().into(), - infos.rows().into(), + infos.dnum().into(), infos.rank_in().into(), (infos.rank_out() + 1).into(), infos.size(),@@ -220,7 +220,7 @@ );
( GGLWECiphertextPrepared::builder() .base2k(infos.base2k()) - .digits(infos.digits()) + .dsize(infos.dsize()) .k(infos.k()) .data(data) .build()@@ -240,7 +240,7 @@ A: GGSWInfos,
{ let (data, scratch) = self.take_mat_znx( infos.n().into(), - infos.rows().into(), + infos.dnum().into(), (infos.rank() + 1).into(), (infos.rank() + 1).into(), infos.size(),@@ -248,7 +248,7 @@ );
( GGSWCiphertext::builder() .base2k(infos.base2k()) - .digits(infos.digits()) + .dsize(infos.dsize()) .k(infos.k()) .data(data) .build()@@ -268,7 +268,7 @@ A: GGSWInfos,
{ let (data, scratch) = self.take_vmp_pmat( infos.n().into(), - infos.rows().into(), + infos.dnum().into(), (infos.rank() + 1).into(), (infos.rank() + 1).into(), infos.size(),@@ -276,7 +276,7 @@ );
( GGSWCiphertextPrepared::builder() .base2k(infos.base2k()) - .digits(infos.digits()) + .dsize(infos.dsize()) .k(infos.k()) .data(data) .build()@@ -367,7 +367,7 @@ Scratch<B>: TakeMatZnx,
{ fn take_glwe_switching_key<A>(&mut self, infos: &A) -> (GGLWESwitchingKey<&mut [u8]>, &mut Self) where - A: GGLWELayoutInfos, + A: GGLWEInfos, { let (data, scratch) = self.take_gglwe(infos); (@@ -387,7 +387,7 @@ Scratch<B>: TakeGGLWEPrepared<B>,
{ fn take_gglwe_switching_key_prepared<A>(&mut self, infos: &A) -> (GGLWESwitchingKeyPrepared<&mut [u8], B>, &mut Self) where - A: GGLWELayoutInfos, + A: GGLWEInfos, { let (data, scratch) = self.take_gglwe_prepared(infos); (@@ -407,7 +407,7 @@ Scratch<B>: TakeMatZnx,
{ fn take_gglwe_automorphism_key<A>(&mut self, infos: &A) -> (GGLWEAutomorphismKey<&mut [u8]>, &mut Self) where - A: GGLWELayoutInfos, + A: GGLWEInfos, { let (data, scratch) = self.take_glwe_switching_key(infos); (GGLWEAutomorphismKey { key: data, p: 0 }, scratch)@@ -420,7 +420,7 @@ Scratch<B>: TakeGGLWESwitchingKeyPrepared<B>,
{ fn take_gglwe_automorphism_key_prepared<A>(&mut self, infos: &A) -> (GGLWEAutomorphismKeyPrepared<&mut [u8], B>, &mut Self) where - A: GGLWELayoutInfos, + A: GGLWEInfos, { let (data, scratch) = self.take_gglwe_switching_key_prepared(infos); (GGLWEAutomorphismKeyPrepared { key: data, p: 0 }, scratch)@@ -433,7 +433,7 @@ Scratch<B>: TakeMatZnx,
{ fn take_tensor_key<A>(&mut self, infos: &A) -> (GGLWETensorKey<&mut [u8]>, &mut Self) where - A: GGLWELayoutInfos, + A: GGLWEInfos, { assert_eq!( infos.rank_in(),@@ -468,7 +468,7 @@ Scratch<B>: TakeVmpPMat<B>,
{ fn take_gglwe_tensor_key_prepared<A>(&mut self, infos: &A) -> (GGLWETensorKeyPrepared<&mut [u8], B>, &mut Self) where - A: GGLWELayoutInfos, + A: GGLWEInfos, { assert_eq!( infos.rank_in(),
@@ -1,8 +1,8 @@
use poulpy_hal::test_suite::serialization::test_reader_writer_interface; use crate::layouts::{ - Base2K, Degree, Digits, GGLWEAutomorphismKey, GGLWECiphertext, GGLWESwitchingKey, GGLWETensorKey, GGSWCiphertext, - GLWECiphertext, GLWEToLWESwitchingKey, LWECiphertext, LWESwitchingKey, LWEToGLWESwitchingKey, Rank, Rows, TorusPrecision, + Base2K, Degree, Dnum, Dsize, GGLWEAutomorphismKey, GGLWECiphertext, GGLWESwitchingKey, GGLWETensorKey, GGSWCiphertext, + GLWECiphertext, GLWEToLWEKey, LWECiphertext, LWESwitchingKey, LWEToGLWESwitchingKey, Rank, TorusPrecision, compressed::{ GGLWEAutomorphismKeyCompressed, GGLWECiphertextCompressed, GGLWESwitchingKeyCompressed, GGLWETensorKeyCompressed, GGSWCiphertextCompressed, GLWECiphertextCompressed, GLWEToLWESwitchingKeyCompressed, LWECiphertextCompressed,@@ -14,9 +14,9 @@ const N_GLWE: Degree = Degree(64);
const N_LWE: Degree = Degree(32); const BASE2K: Base2K = Base2K(12); const K: TorusPrecision = TorusPrecision(33); -const ROWS: Rows = Rows(3); +const DNUM: Dnum = Dnum(3); const RANK: Rank = Rank(2); -const DIGITS: Digits = Digits(1); +const DSIZE: Dsize = Dsize(1); #[test] fn glwe_serialization() {@@ -44,101 +44,101 @@ }
#[test] fn test_gglwe_serialization() { - let original: GGLWECiphertext<Vec<u8>> = GGLWECiphertext::alloc_with(N_GLWE, BASE2K, K, ROWS, DIGITS, RANK, RANK); + let original: GGLWECiphertext<Vec<u8>> = GGLWECiphertext::alloc_with(N_GLWE, BASE2K, K, RANK, RANK, DNUM, DSIZE); test_reader_writer_interface(original); } #[test] fn test_gglwe_compressed_serialization() { let original: GGLWECiphertextCompressed<Vec<u8>> = - GGLWECiphertextCompressed::alloc_with(N_GLWE, BASE2K, K, ROWS, DIGITS, RANK, RANK); + GGLWECiphertextCompressed::alloc_with(N_GLWE, BASE2K, K, RANK, RANK, DNUM, DSIZE); test_reader_writer_interface(original); } #[test] fn test_glwe_switching_key_serialization() { - let original: GGLWESwitchingKey<Vec<u8>> = GGLWESwitchingKey::alloc_with(N_GLWE, BASE2K, K, ROWS, DIGITS, RANK, RANK); + let original: GGLWESwitchingKey<Vec<u8>> = GGLWESwitchingKey::alloc_with(N_GLWE, BASE2K, K, RANK, RANK, DNUM, DSIZE); test_reader_writer_interface(original); } #[test] fn test_glwe_switching_key_compressed_serialization() { let original: GGLWESwitchingKeyCompressed<Vec<u8>> = - GGLWESwitchingKeyCompressed::alloc_with(N_GLWE, BASE2K, K, ROWS, DIGITS, RANK, RANK); + GGLWESwitchingKeyCompressed::alloc_with(N_GLWE, BASE2K, K, RANK, RANK, DNUM, DSIZE); test_reader_writer_interface(original); } #[test] fn test_automorphism_key_serialization() { - let original: GGLWEAutomorphismKey<Vec<u8>> = GGLWEAutomorphismKey::alloc_with(N_GLWE, BASE2K, K, ROWS, DIGITS, RANK); + let original: GGLWEAutomorphismKey<Vec<u8>> = GGLWEAutomorphismKey::alloc_with(N_GLWE, BASE2K, K, RANK, DNUM, DSIZE); test_reader_writer_interface(original); } #[test] fn test_automorphism_key_compressed_serialization() { let original: GGLWEAutomorphismKeyCompressed<Vec<u8>> = - GGLWEAutomorphismKeyCompressed::alloc_with(N_GLWE, BASE2K, K, ROWS, DIGITS, RANK); + GGLWEAutomorphismKeyCompressed::alloc_with(N_GLWE, BASE2K, K, RANK, DNUM, DSIZE); test_reader_writer_interface(original); } #[test] fn test_tensor_key_serialization() { - let original: GGLWETensorKey<Vec<u8>> = GGLWETensorKey::alloc_with(N_GLWE, BASE2K, K, ROWS, DIGITS, RANK); + let original: GGLWETensorKey<Vec<u8>> = GGLWETensorKey::alloc_with(N_GLWE, BASE2K, K, RANK, DNUM, DSIZE); test_reader_writer_interface(original); } #[test] fn test_tensor_key_compressed_serialization() { - let original: GGLWETensorKeyCompressed<Vec<u8>> = GGLWETensorKeyCompressed::alloc_with(N_GLWE, BASE2K, K, ROWS, DIGITS, RANK); + let original: GGLWETensorKeyCompressed<Vec<u8>> = GGLWETensorKeyCompressed::alloc_with(N_GLWE, BASE2K, K, RANK, DNUM, DSIZE); test_reader_writer_interface(original); } #[test] fn glwe_to_lwe_switching_key_serialization() { - let original: GLWEToLWESwitchingKey<Vec<u8>> = GLWEToLWESwitchingKey::alloc_with(N_GLWE, BASE2K, K, ROWS, RANK); + let original: GLWEToLWEKey<Vec<u8>> = GLWEToLWEKey::alloc_with(N_GLWE, BASE2K, K, RANK, DNUM); test_reader_writer_interface(original); } #[test] fn glwe_to_lwe_switching_key_compressed_serialization() { let original: GLWEToLWESwitchingKeyCompressed<Vec<u8>> = - GLWEToLWESwitchingKeyCompressed::alloc_with(N_GLWE, BASE2K, K, ROWS, RANK); + GLWEToLWESwitchingKeyCompressed::alloc_with(N_GLWE, BASE2K, K, RANK, DNUM); test_reader_writer_interface(original); } #[test] fn lwe_to_glwe_switching_key_serialization() { - let original: LWEToGLWESwitchingKey<Vec<u8>> = LWEToGLWESwitchingKey::alloc_with(N_GLWE, BASE2K, K, ROWS, RANK); + let original: LWEToGLWESwitchingKey<Vec<u8>> = LWEToGLWESwitchingKey::alloc_with(N_GLWE, BASE2K, K, RANK, DNUM); test_reader_writer_interface(original); } #[test] fn lwe_to_glwe_switching_key_compressed_serialization() { let original: LWEToGLWESwitchingKeyCompressed<Vec<u8>> = - LWEToGLWESwitchingKeyCompressed::alloc_with(N_GLWE, BASE2K, K, ROWS, RANK); + LWEToGLWESwitchingKeyCompressed::alloc_with(N_GLWE, BASE2K, K, RANK, DNUM); test_reader_writer_interface(original); } #[test] fn lwe_switching_key_serialization() { - let original: LWESwitchingKey<Vec<u8>> = LWESwitchingKey::alloc_with(N_GLWE, BASE2K, K, ROWS); + let original: LWESwitchingKey<Vec<u8>> = LWESwitchingKey::alloc_with(N_GLWE, BASE2K, K, DNUM); test_reader_writer_interface(original); } #[test] fn lwe_switching_key_compressed_serialization() { - let original: LWESwitchingKeyCompressed<Vec<u8>> = LWESwitchingKeyCompressed::alloc_with(N_GLWE, BASE2K, K, ROWS); + let original: LWESwitchingKeyCompressed<Vec<u8>> = LWESwitchingKeyCompressed::alloc_with(N_GLWE, BASE2K, K, DNUM); test_reader_writer_interface(original); } #[test] fn ggsw_serialization() { - let original: GGSWCiphertext<Vec<u8>> = GGSWCiphertext::alloc_with(N_GLWE, BASE2K, K, ROWS, DIGITS, RANK); + let original: GGSWCiphertext<Vec<u8>> = GGSWCiphertext::alloc_with(N_GLWE, BASE2K, K, RANK, DNUM, DSIZE); test_reader_writer_interface(original); } #[test] fn ggsw_compressed_serialization() { - let original: GGSWCiphertextCompressed<Vec<u8>> = GGSWCiphertextCompressed::alloc_with(N_GLWE, BASE2K, K, ROWS, DIGITS, RANK); + let original: GGSWCiphertextCompressed<Vec<u8>> = GGSWCiphertextCompressed::alloc_with(N_GLWE, BASE2K, K, RANK, DNUM, DSIZE); test_reader_writer_interface(original); }
@@ -18,7 +18,7 @@
use crate::{ encryption::SIGMA, layouts::{ - GGLWEAutomorphismKey, GGLWEAutomorphismKeyLayout, GGLWELayoutInfos, GLWEPlaintext, GLWESecret, + GGLWEAutomorphismKey, GGLWEAutomorphismKeyLayout, GGLWEInfos, GLWEPlaintext, GLWESecret, prepared::{GGLWEAutomorphismKeyPrepared, GLWESecretPrepared, Prepare, PrepareAlloc}, }, noise::log2_std_noise_gglwe_product,@@ -70,26 +70,26 @@ {
let base2k: usize = 12; let k_in: usize = 60; let k_out: usize = 40; - let digits: usize = k_in.div_ceil(base2k); + let dsize: usize = k_in.div_ceil(base2k); let p0: i64 = -1; let p1: i64 = -5; for rank in 1_usize..3 { - for di in 1..digits + 1 { - let k_apply: usize = (digits + di) * base2k; + for di in 1..dsize + 1 { + let k_apply: usize = (dsize + di) * base2k; let n: usize = module.n(); - let digits_in: usize = 1; + let dsize_in: usize = 1; - let rows_in: usize = k_in / (base2k * di); - let rows_out: usize = k_out / (base2k * di); - let rows_apply: usize = k_in.div_ceil(base2k * di); + let dnum_in: usize = k_in / (base2k * di); + let dnum_out: usize = k_out / (base2k * di); + let dnum_apply: usize = k_in.div_ceil(base2k * di); let auto_key_in_infos: GGLWEAutomorphismKeyLayout = GGLWEAutomorphismKeyLayout { n: n.into(), base2k: base2k.into(), k: k_in.into(), - rows: rows_in.into(), - digits: digits_in.into(), + dnum: dnum_in.into(), + dsize: dsize_in.into(), rank: rank.into(), };@@ -97,8 +97,8 @@ let auto_key_out_infos: GGLWEAutomorphismKeyLayout = GGLWEAutomorphismKeyLayout {
n: n.into(), base2k: base2k.into(), k: k_out.into(), - rows: rows_out.into(), - digits: digits_in.into(), + dnum: dnum_out.into(), + dsize: dsize_in.into(), rank: rank.into(), };@@ -106,8 +106,8 @@ let auto_key_apply_infos: GGLWEAutomorphismKeyLayout = GGLWEAutomorphismKeyLayout {
n: n.into(), base2k: base2k.into(), k: k_apply.into(), - rows: rows_apply.into(), - digits: di.into(), + dnum: dnum_apply.into(), + dsize: di.into(), rank: rank.into(), };@@ -183,7 +183,7 @@
let sk_auto_dft: GLWESecretPrepared<Vec<u8>, B> = sk_auto.prepare_alloc(module, scratch.borrow()); (0..auto_key_out.rank_in().into()).for_each(|col_i| { - (0..auto_key_out.rows().into()).for_each(|row_i| { + (0..auto_key_out.dnum().into()).for_each(|row_i| { auto_key_out .at(row_i, col_i) .decrypt(module, &mut pt, &sk_auto_dft, scratch.borrow());@@ -191,7 +191,7 @@
module.vec_znx_sub_scalar_inplace( &mut pt.data, 0, - (digits_in - 1) + row_i * digits_in, + (dsize_in - 1) + row_i * dsize_in, &sk.data, col_i, );@@ -280,25 +280,25 @@ + TakeVecZnxBigImpl<B>,
{ let base2k: usize = 12; let k_in: usize = 60; - let digits: usize = k_in.div_ceil(base2k); + let dsize: usize = k_in.div_ceil(base2k); let p0: i64 = -1; let p1: i64 = -5; for rank in 1_usize..3 { - for di in 1..digits + 1 { - let k_apply: usize = (digits + di) * base2k; + for di in 1..dsize + 1 { + let k_apply: usize = (dsize + di) * base2k; let n: usize = module.n(); - let digits_in: usize = 1; + let dsize_in: usize = 1; - let rows_in: usize = k_in / (base2k * di); - let rows_apply: usize = k_in.div_ceil(base2k * di); + let dnum_in: usize = k_in / (base2k * di); + let dnum_apply: usize = k_in.div_ceil(base2k * di); let auto_key_layout: GGLWEAutomorphismKeyLayout = GGLWEAutomorphismKeyLayout { n: n.into(), base2k: base2k.into(), k: k_in.into(), - rows: rows_in.into(), - digits: digits_in.into(), + dnum: dnum_in.into(), + dsize: dsize_in.into(), rank: rank.into(), };@@ -306,8 +306,8 @@ let auto_key_apply_layout: GGLWEAutomorphismKeyLayout = GGLWEAutomorphismKeyLayout {
n: n.into(), base2k: base2k.into(), k: k_apply.into(), - rows: rows_apply.into(), - digits: di.into(), + dnum: dnum_apply.into(), + dsize: di.into(), rank: rank.into(), };@@ -373,14 +373,14 @@
let sk_auto_dft: GLWESecretPrepared<Vec<u8>, B> = sk_auto.prepare_alloc(module, scratch.borrow()); (0..auto_key.rank_in().into()).for_each(|col_i| { - (0..auto_key.rows().into()).for_each(|row_i| { + (0..auto_key.dnum().into()).for_each(|row_i| { auto_key .at(row_i, col_i) .decrypt(module, &mut pt, &sk_auto_dft, scratch.borrow()); module.vec_znx_sub_scalar_inplace( &mut pt.data, 0, - (digits_in - 1) + row_i * digits_in, + (dsize_in - 1) + row_i * dsize_in, &sk.data, col_i, );
@@ -77,27 +77,27 @@ + TakeSvpPPolImpl<B>,
{ let base2k: usize = 12; let k_in: usize = 54; - let digits: usize = k_in.div_ceil(base2k); + let dsize: usize = k_in.div_ceil(base2k); let p: i64 = -5; for rank in 1_usize..3 { - for di in 1..digits + 1 { + for di in 1..dsize + 1 { let k_ksk: usize = k_in + base2k * di; let k_tsk: usize = k_ksk; let k_out: usize = k_ksk; // Better capture noise. let n: usize = module.n(); - let rows: usize = k_in.div_ceil(base2k * di); - let rows_in: usize = k_in.div_euclid(base2k * di); + let dnum: usize = k_in.div_ceil(base2k * di); + let dnum_in: usize = k_in.div_euclid(base2k * di); - let digits_in: usize = 1; + let dsize_in: usize = 1; let ggsw_in_layout: GGSWCiphertextLayout = GGSWCiphertextLayout { n: n.into(), base2k: base2k.into(), k: k_in.into(), - rows: rows_in.into(), - digits: digits_in.into(), + dnum: dnum_in.into(), + dsize: dsize_in.into(), rank: rank.into(), };@@ -105,8 +105,8 @@ let ggsw_out_layout: GGSWCiphertextLayout = GGSWCiphertextLayout {
n: n.into(), base2k: base2k.into(), k: k_out.into(), - rows: rows_in.into(), - digits: digits_in.into(), + dnum: dnum_in.into(), + dsize: dsize_in.into(), rank: rank.into(), };@@ -114,8 +114,8 @@ let tensor_key_layout: GGLWETensorKeyLayout = GGLWETensorKeyLayout {
n: n.into(), base2k: base2k.into(), k: k_tsk.into(), - rows: rows.into(), - digits: di.into(), + dnum: dnum.into(), + dsize: di.into(), rank: rank.into(), };@@ -123,8 +123,8 @@ let auto_key_layout: GGLWETensorKeyLayout = GGLWETensorKeyLayout {
n: n.into(), base2k: base2k.into(), k: k_ksk.into(), - rows: rows.into(), - digits: di.into(), + dnum: dnum.into(), + dsize: di.into(), rank: rank.into(), };@@ -270,24 +270,24 @@ + TakeSvpPPolImpl<B>,
{ let base2k: usize = 12; let k_out: usize = 54; - let digits: usize = k_out.div_ceil(base2k); + let dsize: usize = k_out.div_ceil(base2k); let p: i64 = -1; for rank in 1_usize..3 { - for di in 1..digits + 1 { + for di in 1..dsize + 1 { let k_ksk: usize = k_out + base2k * di; let k_tsk: usize = k_ksk; let n: usize = module.n(); - let rows: usize = k_out.div_ceil(di * base2k); - let rows_in: usize = k_out.div_euclid(base2k * di); - let digits_in: usize = 1; + let dnum: usize = k_out.div_ceil(di * base2k); + let dnum_in: usize = k_out.div_euclid(base2k * di); + let dsize_in: usize = 1; let ggsw_out_layout: GGSWCiphertextLayout = GGSWCiphertextLayout { n: n.into(), base2k: base2k.into(), k: k_out.into(), - rows: rows_in.into(), - digits: digits_in.into(), + dnum: dnum_in.into(), + dsize: dsize_in.into(), rank: rank.into(), };@@ -295,8 +295,8 @@ let tensor_key_layout: GGLWETensorKeyLayout = GGLWETensorKeyLayout {
n: n.into(), base2k: base2k.into(), k: k_tsk.into(), - rows: rows.into(), - digits: di.into(), + dnum: dnum.into(), + dsize: di.into(), rank: rank.into(), };@@ -304,8 +304,8 @@ let auto_key_layout: GGLWETensorKeyLayout = GGLWETensorKeyLayout {
n: n.into(), base2k: base2k.into(), k: k_ksk.into(), - rows: rows.into(), - digits: di.into(), + dnum: dnum.into(), + dsize: di.into(), rank: rank.into(), };
@@ -67,15 +67,15 @@ + TakeVecZnxImpl<B>,
{ let base2k: usize = 12; let k_in: usize = 60; - let digits: usize = k_in.div_ceil(base2k); + let dsize: usize = k_in.div_ceil(base2k); let p: i64 = -5; for rank in 1_usize..3 { - for di in 1..digits + 1 { + for di in 1..dsize + 1 { let k_ksk: usize = k_in + base2k * di; let k_out: usize = k_ksk; // Better capture noise. let n: usize = module.n(); - let rows: usize = k_in.div_ceil(base2k * digits); + let dnum: usize = k_in.div_ceil(base2k * dsize); let ct_in_infos: GLWECiphertextLayout = GLWECiphertextLayout { n: n.into(),@@ -96,8 +96,8 @@ n: n.into(),
base2k: base2k.into(), k: k_out.into(), rank: rank.into(), - rows: rows.into(), - digits: di.into(), + dnum: dnum.into(), + dsize: di.into(), }; let mut autokey: GGLWEAutomorphismKey<Vec<u8>> = GGLWEAutomorphismKey::alloc(&autokey_infos);@@ -148,7 +148,7 @@ ct_out.automorphism(module, &ct_in, &autokey_prepared, scratch.borrow());
let max_noise: f64 = log2_std_noise_gglwe_product( module.n() as f64, - base2k * digits, + base2k * dsize, 0.5, 0.5, 0f64,@@ -210,14 +210,14 @@ + TakeVecZnxImpl<B>,
{ let base2k: usize = 12; let k_out: usize = 60; - let digits: usize = k_out.div_ceil(base2k); + let dsize: usize = k_out.div_ceil(base2k); let p = -5; for rank in 1_usize..3 { - for di in 1..digits + 1 { + for di in 1..dsize + 1 { let k_ksk: usize = k_out + base2k * di; let n: usize = module.n(); - let rows: usize = k_out.div_ceil(base2k * digits); + let dnum: usize = k_out.div_ceil(base2k * dsize); let ct_out_infos: GLWECiphertextLayout = GLWECiphertextLayout { n: n.into(),@@ -231,8 +231,8 @@ n: n.into(),
base2k: base2k.into(), k: k_ksk.into(), rank: rank.into(), - rows: rows.into(), - digits: di.into(), + dnum: dnum.into(), + dsize: di.into(), }; let mut autokey: GGLWEAutomorphismKey<Vec<u8>> = GGLWEAutomorphismKey::alloc(&autokey_infos);@@ -282,7 +282,7 @@ ct.automorphism_inplace(module, &autokey_prepared, scratch.borrow());
let max_noise: f64 = log2_std_noise_gglwe_product( module.n() as f64, - base2k * digits, + base2k * dsize, 0.5, 0.5, 0f64,
@@ -16,9 +16,9 @@ source::Source,
}; use crate::layouts::{ - Base2K, Degree, GLWECiphertext, GLWECiphertextLayout, GLWEPlaintext, GLWESecret, GLWEToLWESwitchingKey, - GLWEToLWESwitchingKeyLayout, LWECiphertext, LWECiphertextLayout, LWEPlaintext, LWESecret, LWEToGLWESwitchingKey, - LWEToGLWESwitchingKeyLayout, Rank, Rows, TorusPrecision, + Base2K, Degree, Dnum, GLWECiphertext, GLWECiphertextLayout, GLWEPlaintext, GLWESecret, GLWEToLWEKey, GLWEToLWEKeyLayout, + LWECiphertext, LWECiphertextLayout, LWEPlaintext, LWESecret, LWEToGLWESwitchingKey, LWEToGLWESwitchingKeyLayout, Rank, + TorusPrecision, prepared::{GLWESecretPrepared, GLWEToLWESwitchingKeyPrepared, LWEToGLWESwitchingKeyPrepared, PrepareAlloc}, };@@ -79,7 +79,7 @@ let lwe_to_glwe_infos: LWEToGLWESwitchingKeyLayout = LWEToGLWESwitchingKeyLayout {
n: n_glwe, base2k: Base2K(17), k: TorusPrecision(51), - rows: Rows(2), + dnum: Dnum(2), rank_out: rank, };@@ -188,11 +188,11 @@
let rank: Rank = Rank(2); let k_lwe_pt: TorusPrecision = TorusPrecision(8); - let glwe_to_lwe_infos: GLWEToLWESwitchingKeyLayout = GLWEToLWESwitchingKeyLayout { + let glwe_to_lwe_infos: GLWEToLWEKeyLayout = GLWEToLWEKeyLayout { n: n_glwe, base2k: Base2K(17), k: TorusPrecision(51), - rows: Rows(2), + dnum: Dnum(2), rank_in: rank, };@@ -214,7 +214,7 @@ let mut source_xa: Source = Source::new([0u8; 32]);
let mut source_xe: Source = Source::new([0u8; 32]); let mut scratch: ScratchOwned<B> = ScratchOwned::alloc( - GLWEToLWESwitchingKey::encrypt_sk_scratch_space(module, &glwe_to_lwe_infos) + GLWEToLWEKey::encrypt_sk_scratch_space(module, &glwe_to_lwe_infos) | LWECiphertext::from_glwe_scratch_space(module, &lwe_infos, &glwe_infos, &glwe_to_lwe_infos) | GLWECiphertext::decrypt_scratch_space(module, &glwe_infos), );@@ -241,7 +241,7 @@ &mut source_xe,
scratch.borrow(), ); - let mut ksk: GLWEToLWESwitchingKey<Vec<u8>> = GLWEToLWESwitchingKey::alloc(&glwe_to_lwe_infos); + let mut ksk: GLWEToLWEKey<Vec<u8>> = GLWEToLWEKey::alloc(&glwe_to_lwe_infos); ksk.encrypt_sk( module,
@@ -69,18 +69,18 @@ + TakeVecZnxBigImpl<B>,
{ let base2k: usize = 12; let k_ksk: usize = 60; - let digits: usize = k_ksk.div_ceil(base2k) - 1; + let dsize: usize = k_ksk.div_ceil(base2k) - 1; for rank in 1_usize..3 { - for di in 1..digits + 1 { + for di in 1..dsize + 1 { let n: usize = module.n(); - let rows: usize = (k_ksk - di * base2k) / (di * base2k); + let dnum: usize = (k_ksk - di * base2k) / (di * base2k); let atk_infos: GGLWEAutomorphismKeyLayout = GGLWEAutomorphismKeyLayout { n: n.into(), base2k: base2k.into(), k: k_ksk.into(), - rows: rows.into(), - digits: di.into(), + dnum: dnum.into(), + dsize: di.into(), rank: rank.into(), };@@ -172,18 +172,18 @@ + TakeVecZnxBigImpl<B>,
{ let base2k: usize = 12; let k_ksk: usize = 60; - let digits: usize = k_ksk.div_ceil(base2k) - 1; + let dsize: usize = k_ksk.div_ceil(base2k) - 1; for rank in 1_usize..3 { - for di in 1..digits + 1 { + for di in 1..dsize + 1 { let n: usize = module.n(); - let rows: usize = (k_ksk - di * base2k) / (di * base2k); + let dnum: usize = (k_ksk - di * base2k) / (di * base2k); let atk_infos: GGLWEAutomorphismKeyLayout = GGLWEAutomorphismKeyLayout { n: n.into(), base2k: base2k.into(), k: k_ksk.into(), - rows: rows.into(), - digits: di.into(), + dnum: dnum.into(), + dsize: di.into(), rank: rank.into(), };
@@ -64,19 +64,19 @@ + TakeSvpPPolImpl<B>,
{ let base2k: usize = 12; let k_ksk: usize = 54; - let digits: usize = k_ksk / base2k; + let dsize: usize = k_ksk / base2k; for rank_in in 1_usize..3 { for rank_out in 1_usize..3 { - for di in 1_usize..digits + 1 { + for di in 1_usize..dsize + 1 { let n: usize = module.n(); - let rows: usize = (k_ksk - di * base2k) / (di * base2k); + let dnum: usize = (k_ksk - di * base2k) / (di * base2k); let gglwe_infos: GGLWECiphertextLayout = GGLWECiphertextLayout { n: n.into(), base2k: base2k.into(), k: k_ksk.into(), - rows: rows.into(), - digits: di.into(), + dnum: dnum.into(), + dsize: di.into(), rank_in: rank_in.into(), rank_out: rank_out.into(), };@@ -156,19 +156,19 @@ + TakeSvpPPolImpl<B>,
{ let base2k: usize = 12; let k_ksk: usize = 54; - let digits: usize = k_ksk / base2k; + let dsize: usize = k_ksk / base2k; for rank_in in 1_usize..3 { for rank_out in 1_usize..3 { - for di in 1_usize..digits + 1 { + for di in 1_usize..dsize + 1 { let n: usize = module.n(); - let rows: usize = (k_ksk - di * base2k) / (di * base2k); + let dnum: usize = (k_ksk - di * base2k) / (di * base2k); let gglwe_infos: GGLWECiphertextLayout = GGLWECiphertextLayout { n: n.into(), base2k: base2k.into(), k: k_ksk.into(), - rows: rows.into(), - digits: di.into(), + dnum: dnum.into(), + dsize: di.into(), rank_in: rank_in.into(), rank_out: rank_out.into(), };
@@ -67,18 +67,18 @@ + TakeSvpPPolImpl<B>,
{ let base2k: usize = 12; let k: usize = 54; - let digits: usize = k / base2k; + let dsize: usize = k / base2k; for rank in 1_usize..3 { - for di in 1..digits + 1 { + for di in 1..dsize + 1 { let n: usize = module.n(); - let rows: usize = (k - di * base2k) / (di * base2k); + let dnum: usize = (k - di * base2k) / (di * base2k); let ggsw_infos: GGSWCiphertextLayout = GGSWCiphertextLayout { n: n.into(), base2k: base2k.into(), k: k.into(), - rows: rows.into(), - digits: di.into(), + dnum: dnum.into(), + dsize: di.into(), rank: rank.into(), };@@ -160,18 +160,18 @@ + TakeSvpPPolImpl<B>,
{ let base2k: usize = 12; let k: usize = 54; - let digits: usize = k / base2k; + let dsize: usize = k / base2k; for rank in 1_usize..3 { - for di in 1..digits + 1 { + for di in 1..dsize + 1 { let n: usize = module.n(); - let rows: usize = (k - di * base2k) / (di * base2k); + let dnum: usize = (k - di * base2k) / (di * base2k); let ggsw_infos: GGSWCiphertextLayout = GGSWCiphertextLayout { n: n.into(), base2k: base2k.into(), k: k.into(), - rows: rows.into(), - digits: di.into(), + dnum: dnum.into(), + dsize: di.into(), rank: rank.into(), };
@@ -17,7 +17,7 @@
use crate::{ encryption::SIGMA, layouts::{ - Digits, GGLWETensorKey, GGLWETensorKeyLayout, GLWEPlaintext, GLWESecret, + Dsize, GGLWETensorKey, GGLWETensorKeyLayout, GLWEPlaintext, GLWESecret, compressed::{Decompress, GGLWETensorKeyCompressed}, prepared::{GLWESecretPrepared, PrepareAlloc}, },@@ -69,14 +69,14 @@ let k: usize = 54;
for rank in 1_usize..3 { let n: usize = module.n(); - let rows: usize = k / base2k; + let dnum: usize = k / base2k; let tensor_key_infos = GGLWETensorKeyLayout { n: n.into(), base2k: base2k.into(), k: k.into(), - rows: rows.into(), - digits: Digits(1), + dnum: dnum.into(), + dsize: Dsize(1), rank: rank.into(), };@@ -127,7 +127,7 @@ &sk_ij_big,
0, scratch.borrow(), ); - for row_i in 0..rows { + for row_i in 0..dnum { tensor_key .at(i, j) .at(row_i, 0)@@ -188,14 +188,14 @@ let base2k = 8;
let k = 54; for rank in 1_usize..3 { let n: usize = module.n(); - let rows: usize = k / base2k; + let dnum: usize = k / base2k; let tensor_key_infos: GGLWETensorKeyLayout = GGLWETensorKeyLayout { n: n.into(), base2k: base2k.into(), k: k.into(), - rows: rows.into(), - digits: Digits(1), + dnum: dnum.into(), + dsize: Dsize(1), rank: rank.into(), };@@ -244,7 +244,7 @@ &sk_ij_big,
0, scratch.borrow(), ); - for row_i in 0..rows { + for row_i in 0..dnum { tensor_key .at(i, j) .at(row_i, 0)
@@ -70,23 +70,23 @@ + TakeSvpPPolImpl<B>,
{ let base2k: usize = 12; let k_in: usize = 60; - let digits: usize = k_in.div_ceil(base2k); + let dsize: usize = k_in.div_ceil(base2k); for rank_in in 1_usize..3 { for rank_out in 1_usize..3 { - for di in 1_usize..digits + 1 { + for di in 1_usize..dsize + 1 { let k_ggsw: usize = k_in + base2k * di; let k_out: usize = k_in; // Better capture noise. let n: usize = module.n(); - let rows: usize = k_in.div_ceil(base2k * di); - let digits_in: usize = 1; + let dnum: usize = k_in.div_ceil(base2k * di); + let dsize_in: usize = 1; let gglwe_in_infos: GGLWESwitchingKeyLayout = GGLWESwitchingKeyLayout { n: n.into(), base2k: base2k.into(), k: k_in.into(), - rows: rows.into(), - digits: digits_in.into(), + dnum: dnum.into(), + dsize: dsize_in.into(), rank_in: rank_in.into(), rank_out: rank_out.into(), };@@ -95,8 +95,8 @@ let gglwe_out_infos: GGLWESwitchingKeyLayout = GGLWESwitchingKeyLayout {
n: n.into(), base2k: base2k.into(), k: k_out.into(), - rows: rows.into(), - digits: digits_in.into(), + dnum: dnum.into(), + dsize: dsize_in.into(), rank_in: rank_in.into(), rank_out: rank_out.into(), };@@ -105,8 +105,8 @@ let ggsw_infos: GGSWCiphertextLayout = GGSWCiphertextLayout {
n: n.into(), base2k: base2k.into(), k: k_ggsw.into(), - rows: rows.into(), - digits: di.into(), + dnum: dnum.into(), + dsize: di.into(), rank: rank_out.into(), };@@ -252,23 +252,23 @@ + TakeSvpPPolImpl<B>,
{ let base2k: usize = 12; let k_out: usize = 60; - let digits: usize = k_out.div_ceil(base2k); + let dsize: usize = k_out.div_ceil(base2k); for rank_in in 1_usize..3 { for rank_out in 1_usize..3 { - for di in 1_usize..digits + 1 { + for di in 1_usize..dsize + 1 { let k_ggsw: usize = k_out + base2k * di; let n: usize = module.n(); - let rows: usize = k_out.div_ceil(base2k * di); + let dnum: usize = k_out.div_ceil(base2k * di); - let digits_in: usize = 1; + let dsize_in: usize = 1; let gglwe_out_infos: GGLWESwitchingKeyLayout = GGLWESwitchingKeyLayout { n: n.into(), base2k: base2k.into(), k: k_out.into(), - rows: rows.into(), - digits: digits_in.into(), + dnum: dnum.into(), + dsize: dsize_in.into(), rank_in: rank_in.into(), rank_out: rank_out.into(), };@@ -277,8 +277,8 @@ let ggsw_infos: GGSWCiphertextLayout = GGSWCiphertextLayout {
n: n.into(), base2k: base2k.into(), k: k_ggsw.into(), - rows: rows.into(), - digits: di.into(), + dnum: dnum.into(), + dsize: di.into(), rank: rank_out.into(), };
@@ -72,24 +72,24 @@ + TakeSvpPPolImpl<B>,
{ let base2k: usize = 12; let k_in: usize = 60; - let digits: usize = k_in.div_ceil(base2k); + let dsize: usize = k_in.div_ceil(base2k); for rank in 1_usize..3 { - for di in 1..digits + 1 { + for di in 1..dsize + 1 { let k_apply: usize = k_in + base2k * di; let k_out: usize = k_in; // Better capture noise. let n: usize = module.n(); - let rows: usize = k_in.div_ceil(base2k * di); - let rows_in: usize = k_in.div_euclid(base2k * di); - let digits_in: usize = 1; + let dnum: usize = k_in.div_ceil(base2k * di); + let dnum_in: usize = k_in.div_euclid(base2k * di); + let dsize_in: usize = 1; let ggsw_in_infos: GGSWCiphertextLayout = GGSWCiphertextLayout { n: n.into(), base2k: base2k.into(), k: k_in.into(), - rows: rows_in.into(), - digits: digits_in.into(), + dnum: dnum_in.into(), + dsize: dsize_in.into(), rank: rank.into(), };@@ -97,8 +97,8 @@ let ggsw_out_infos: GGSWCiphertextLayout = GGSWCiphertextLayout {
n: n.into(), base2k: base2k.into(), k: k_out.into(), - rows: rows_in.into(), - digits: digits_in.into(), + dnum: dnum_in.into(), + dsize: dsize_in.into(), rank: rank.into(), };@@ -106,8 +106,8 @@ let ggsw_apply_infos: GGSWCiphertextLayout = GGSWCiphertextLayout {
n: n.into(), base2k: base2k.into(), k: k_apply.into(), - rows: rows.into(), - digits: di.into(), + dnum: dnum.into(), + dsize: di.into(), rank: rank.into(), };@@ -237,22 +237,22 @@ + TakeSvpPPolImpl<B>,
{ let base2k: usize = 12; let k_out: usize = 60; - let digits: usize = k_out.div_ceil(base2k); + let dsize: usize = k_out.div_ceil(base2k); for rank in 1_usize..3 { - for di in 1..digits + 1 { + for di in 1..dsize + 1 { let k_apply: usize = k_out + base2k * di; let n: usize = module.n(); - let rows: usize = k_out.div_ceil(di * base2k); - let rows_in: usize = k_out.div_euclid(base2k * di); - let digits_in: usize = 1; + let dnum: usize = k_out.div_ceil(di * base2k); + let dnum_in: usize = k_out.div_euclid(base2k * di); + let dsize_in: usize = 1; let ggsw_out_infos: GGSWCiphertextLayout = GGSWCiphertextLayout { n: n.into(), base2k: base2k.into(), k: k_out.into(), - rows: rows_in.into(), - digits: digits_in.into(), + dnum: dnum_in.into(), + dsize: dsize_in.into(), rank: rank.into(), };@@ -260,8 +260,8 @@ let ggsw_apply_infos: GGSWCiphertextLayout = GGSWCiphertextLayout {
n: n.into(), base2k: base2k.into(), k: k_apply.into(), - rows: rows.into(), - digits: di.into(), + dnum: dnum.into(), + dsize: di.into(), rank: rank.into(), };
@@ -64,14 +64,14 @@ + TakeVecZnxImpl<B>,
{ let base2k: usize = 12; let k_in: usize = 45; - let digits: usize = k_in.div_ceil(base2k); + let dsize: usize = k_in.div_ceil(base2k); for rank in 1_usize..3 { - for di in 1..digits + 1 { + for di in 1..dsize + 1 { let k_ggsw: usize = k_in + base2k * di; let k_out: usize = k_ggsw; // Better capture noise let n: usize = module.n(); - let rows: usize = k_in.div_ceil(base2k * digits); + let dnum: usize = k_in.div_ceil(base2k * dsize); let glwe_in_infos: GLWECiphertextLayout = GLWECiphertextLayout { n: n.into(),@@ -91,8 +91,8 @@ let ggsw_apply_infos: GGSWCiphertextLayout = GGSWCiphertextLayout {
n: n.into(), base2k: base2k.into(), k: k_ggsw.into(), - rows: rows.into(), - digits: di.into(), + dnum: dnum.into(), + dsize: di.into(), rank: rank.into(), };@@ -158,7 +158,7 @@ let var_a1_err: f64 = 1f64 / 12f64;
let max_noise: f64 = noise_ggsw_product( n as f64, - base2k * digits, + base2k * dsize, 0.5, var_msg, var_a0_err,@@ -216,13 +216,13 @@ + TakeVecZnxImpl<B>,
{ let base2k: usize = 12; let k_out: usize = 60; - let digits: usize = k_out.div_ceil(base2k); + let dsize: usize = k_out.div_ceil(base2k); for rank in 1_usize..3 { - for di in 1..digits + 1 { + for di in 1..dsize + 1 { let k_ggsw: usize = k_out + base2k * di; let n: usize = module.n(); - let rows: usize = k_out.div_ceil(base2k * digits); + let dnum: usize = k_out.div_ceil(base2k * dsize); let glwe_out_infos: GLWECiphertextLayout = GLWECiphertextLayout { n: n.into(),@@ -235,8 +235,8 @@ let ggsw_apply_infos: GGSWCiphertextLayout = GGSWCiphertextLayout {
n: n.into(), base2k: base2k.into(), k: k_ggsw.into(), - rows: rows.into(), - digits: di.into(), + dnum: dnum.into(), + dsize: di.into(), rank: rank.into(), };@@ -301,7 +301,7 @@ let var_a1_err: f64 = 1f64 / 12f64;
let max_noise: f64 = noise_ggsw_product( n as f64, - base2k * digits, + base2k * dsize, 0.5, var_msg, var_a0_err,
@@ -66,26 +66,26 @@ + TakeVecZnxImpl<B>,
{ let base2k: usize = 12; let k_in: usize = 60; - let digits: usize = k_in.div_ceil(base2k); + let dsize: usize = k_in.div_ceil(base2k); for rank_in_s0s1 in 1_usize..3 { for rank_out_s0s1 in 1_usize..3 { for rank_out_s1s2 in 1_usize..3 { - for di in 1_usize..digits + 1 { + for di in 1_usize..dsize + 1 { let k_ksk: usize = k_in + base2k * di; let k_out: usize = k_ksk; // Better capture noise. let n: usize = module.n(); - let rows: usize = k_in / base2k; - let rows_apply: usize = k_in.div_ceil(base2k * di); - let digits_in: usize = 1; + let dnum: usize = k_in / base2k; + let dnum_apply: usize = k_in.div_ceil(base2k * di); + let dsize_in: usize = 1; let gglwe_s0s1_infos: GGLWESwitchingKeyLayout = GGLWESwitchingKeyLayout { n: n.into(), base2k: base2k.into(), k: k_in.into(), - rows: rows.into(), - digits: digits_in.into(), + dnum: dnum.into(), + dsize: dsize_in.into(), rank_in: rank_in_s0s1.into(), rank_out: rank_out_s0s1.into(), };@@ -94,8 +94,8 @@ let gglwe_s1s2_infos: GGLWESwitchingKeyLayout = GGLWESwitchingKeyLayout {
n: n.into(), base2k: base2k.into(), k: k_ksk.into(), - rows: rows_apply.into(), - digits: di.into(), + dnum: dnum_apply.into(), + dsize: di.into(), rank_in: rank_out_s0s1.into(), rank_out: rank_out_s1s2.into(), };@@ -104,8 +104,8 @@ let gglwe_s0s2_infos: GGLWESwitchingKeyLayout = GGLWESwitchingKeyLayout {
n: n.into(), base2k: base2k.into(), k: k_out.into(), - rows: rows_apply.into(), - digits: digits_in.into(), + dnum: dnum_apply.into(), + dsize: dsize_in.into(), rank_in: rank_in_s0s1.into(), rank_out: rank_out_s1s2.into(), };@@ -236,22 +236,22 @@ + TakeVecZnxImpl<B>,
{ let base2k: usize = 12; let k_out: usize = 60; - let digits: usize = k_out.div_ceil(base2k); + let dsize: usize = k_out.div_ceil(base2k); for rank_in in 1_usize..3 { for rank_out in 1_usize..3 { - for di in 1_usize..digits + 1 { + for di in 1_usize..dsize + 1 { let k_ksk: usize = k_out + base2k * di; let n: usize = module.n(); - let rows: usize = k_out.div_ceil(base2k * di); - let digits_in: usize = 1; + let dnum: usize = k_out.div_ceil(base2k * di); + let dsize_in: usize = 1; let gglwe_s0s1_infos: GGLWESwitchingKeyLayout = GGLWESwitchingKeyLayout { n: n.into(), base2k: base2k.into(), k: k_out.into(), - rows: rows.into(), - digits: digits_in.into(), + dnum: dnum.into(), + dsize: dsize_in.into(), rank_in: rank_in.into(), rank_out: rank_out.into(), };@@ -260,8 +260,8 @@ let gglwe_s1s2_infos: GGLWESwitchingKeyLayout = GGLWESwitchingKeyLayout {
n: n.into(), base2k: base2k.into(), k: k_ksk.into(), - rows: rows.into(), - digits: di.into(), + dnum: dnum.into(), + dsize: di.into(), rank_in: rank_out.into(), rank_out: rank_out.into(), };
@@ -73,24 +73,24 @@ + TakeVecZnxImpl<B>,
{ let base2k: usize = 12; let k_in: usize = 54; - let digits: usize = k_in.div_ceil(base2k); + let dsize: usize = k_in.div_ceil(base2k); for rank in 1_usize..3 { - for di in 1..digits + 1 { + for di in 1..dsize + 1 { let k_ksk: usize = k_in + base2k * di; let k_tsk: usize = k_ksk; let k_out: usize = k_ksk; // Better capture noise. let n: usize = module.n(); - let rows: usize = k_in.div_ceil(di * base2k); + let dnum: usize = k_in.div_ceil(di * base2k); - let digits_in: usize = 1; + let dsize_in: usize = 1; let ggsw_in_infos: GGSWCiphertextLayout = GGSWCiphertextLayout { n: n.into(), base2k: base2k.into(), k: k_in.into(), - rows: rows.into(), - digits: digits_in.into(), + dnum: dnum.into(), + dsize: dsize_in.into(), rank: rank.into(), };@@ -98,8 +98,8 @@ let ggsw_out_infos: GGSWCiphertextLayout = GGSWCiphertextLayout {
n: n.into(), base2k: base2k.into(), k: k_out.into(), - rows: rows.into(), - digits: digits_in.into(), + dnum: dnum.into(), + dsize: dsize_in.into(), rank: rank.into(), };@@ -107,8 +107,8 @@ let tsk_infos: GGLWETensorKeyLayout = GGLWETensorKeyLayout {
n: n.into(), base2k: base2k.into(), k: k_tsk.into(), - rows: rows.into(), - digits: di.into(), + dnum: dnum.into(), + dsize: di.into(), rank: rank.into(), };@@ -116,8 +116,8 @@ let ksk_apply_infos: GGLWESwitchingKeyLayout = GGLWESwitchingKeyLayout {
n: n.into(), base2k: base2k.into(), k: k_ksk.into(), - rows: rows.into(), - digits: di.into(), + dnum: dnum.into(), + dsize: di.into(), rank_in: rank.into(), rank_out: rank.into(), };@@ -262,23 +262,23 @@ + TakeVecZnxImpl<B>,
{ let base2k: usize = 12; let k_out: usize = 54; - let digits: usize = k_out.div_ceil(base2k); + let dsize: usize = k_out.div_ceil(base2k); for rank in 1_usize..3 { - for di in 1..digits + 1 { + for di in 1..dsize + 1 { let k_ksk: usize = k_out + base2k * di; let k_tsk: usize = k_ksk; let n: usize = module.n(); - let rows: usize = k_out.div_ceil(di * base2k); + let dnum: usize = k_out.div_ceil(di * base2k); - let digits_in: usize = 1; + let dsize_in: usize = 1; let ggsw_out_infos: GGSWCiphertextLayout = GGSWCiphertextLayout { n: n.into(), base2k: base2k.into(), k: k_out.into(), - rows: rows.into(), - digits: digits_in.into(), + dnum: dnum.into(), + dsize: dsize_in.into(), rank: rank.into(), };@@ -286,8 +286,8 @@ let tsk_infos: GGLWETensorKeyLayout = GGLWETensorKeyLayout {
n: n.into(), base2k: base2k.into(), k: k_tsk.into(), - rows: rows.into(), - digits: di.into(), + dnum: dnum.into(), + dsize: di.into(), rank: rank.into(), };@@ -295,8 +295,8 @@ let ksk_apply_infos: GGLWESwitchingKeyLayout = GGLWESwitchingKeyLayout {
n: n.into(), base2k: base2k.into(), k: k_ksk.into(), - rows: rows.into(), - digits: di.into(), + dnum: dnum.into(), + dsize: di.into(), rank_in: rank.into(), rank_out: rank.into(), };
@@ -66,16 +66,16 @@ + TakeVecZnxImpl<B>,
{ let base2k: usize = 12; let k_in: usize = 45; - let digits: usize = k_in.div_ceil(base2k); + let dsize: usize = k_in.div_ceil(base2k); for rank_in in 1_usize..3 { for rank_out in 1_usize..3 { - for di in 1_usize..digits + 1 { + for di in 1_usize..dsize + 1 { let k_ksk: usize = k_in + base2k * di; let k_out: usize = k_ksk; // better capture noise let n: usize = module.n(); - let rows: usize = k_in.div_ceil(base2k * digits); + let dnum: usize = k_in.div_ceil(base2k * dsize); let glwe_in_infos: GLWECiphertextLayout = GLWECiphertextLayout { n: n.into(),@@ -95,8 +95,8 @@ let key_apply: GGLWESwitchingKeyLayout = GGLWESwitchingKeyLayout {
n: n.into(), base2k: base2k.into(), k: k_ksk.into(), - rows: rows.into(), - digits: di.into(), + dnum: dnum.into(), + dsize: di.into(), rank_in: rank_in.into(), rank_out: rank_out.into(), };@@ -150,7 +150,7 @@ glwe_out.keyswitch(module, &glwe_in, &ksk_prepared, scratch.borrow());
let max_noise: f64 = log2_std_noise_gglwe_product( module.n() as f64, - base2k * digits, + base2k * dsize, 0.5, 0.5, 0f64,@@ -208,14 +208,14 @@ + TakeVecZnxImpl<B>,
{ let base2k: usize = 12; let k_out: usize = 45; - let digits: usize = k_out.div_ceil(base2k); + let dsize: usize = k_out.div_ceil(base2k); for rank in 1_usize..3 { - for di in 1..digits + 1 { + for di in 1..dsize + 1 { let k_ksk: usize = k_out + base2k * di; let n: usize = module.n(); - let rows: usize = k_out.div_ceil(base2k * digits); + let dnum: usize = k_out.div_ceil(base2k * dsize); let glwe_out_infos: GLWECiphertextLayout = GLWECiphertextLayout { n: n.into(),@@ -228,8 +228,8 @@ let key_apply_infos: GGLWESwitchingKeyLayout = GGLWESwitchingKeyLayout {
n: n.into(), base2k: base2k.into(), k: k_ksk.into(), - rows: rows.into(), - digits: di.into(), + dnum: dnum.into(), + dsize: di.into(), rank_in: rank.into(), rank_out: rank.into(), };@@ -282,7 +282,7 @@ glwe_out.keyswitch_inplace(module, &ksk_prepared, scratch.borrow());
let max_noise: f64 = log2_std_noise_gglwe_product( module.n() as f64, - base2k * digits, + base2k * dsize, 0.5, 0.5, 0f64,
@@ -73,7 +73,7 @@ let k_lwe_ct: usize = 2 * base2k;
let k_lwe_pt: usize = 8; let k_ksk: usize = k_lwe_ct + base2k; - let rows: usize = k_lwe_ct.div_ceil(base2k); + let dnum: usize = k_lwe_ct.div_ceil(base2k); let mut source_xs: Source = Source::new([0u8; 32]); let mut source_xa: Source = Source::new([0u8; 32]);@@ -83,7 +83,7 @@ let key_apply_infos: LWESwitchingKeyLayout = LWESwitchingKeyLayout {
n: n.into(), base2k: base2k.into(), k: k_ksk.into(), - rows: rows.into(), + dnum: dnum.into(), }; let lwe_in_infos: LWECiphertextLayout = LWECiphertextLayout {
@@ -83,10 +83,10 @@ let base2k: usize = 18;
let k_ct: usize = 36; let pt_k: usize = 18; let rank: usize = 3; - let digits: usize = 1; - let k_ksk: usize = k_ct + base2k * digits; + let dsize: usize = 1; + let k_ksk: usize = k_ct + base2k * dsize; - let rows: usize = k_ct.div_ceil(base2k * digits); + let dnum: usize = k_ct.div_ceil(base2k * dsize); let glwe_out_infos: GLWECiphertextLayout = GLWECiphertextLayout { n: n.into(),@@ -100,8 +100,8 @@ n: n.into(),
base2k: base2k.into(), k: k_ksk.into(), rank: rank.into(), - digits: digits.into(), - rows: rows.into(), + dsize: dsize.into(), + dnum: dnum.into(), }; let mut scratch: ScratchOwned<B> = ScratchOwned::alloc(
@@ -80,8 +80,8 @@ for rank in 1_usize..3 {
let n: usize = module.n(); let k_autokey: usize = k + base2k; - let digits: usize = 1; - let rows: usize = k.div_ceil(base2k * digits); + let dsize: usize = 1; + let dnum: usize = k.div_ceil(base2k * dsize); let glwe_out_infos: GLWECiphertextLayout = GLWECiphertextLayout { n: n.into(),@@ -95,8 +95,8 @@ n: n.into(),
base2k: base2k.into(), k: k_autokey.into(), rank: rank.into(), - digits: digits.into(), - rows: rows.into(), + dsize: dsize.into(), + dnum: dnum.into(), }; let mut glwe_out: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(&glwe_out_infos);
@@ -2,8 +2,8 @@ use crate::reference::znx::{
ZnxAdd, ZnxAddInplace, ZnxAutomorphism, ZnxCopy, ZnxExtractDigitAddMul, ZnxMulAddPowerOfTwo, ZnxMulPowerOfTwo, ZnxMulPowerOfTwoInplace, ZnxNegate, ZnxNegateInplace, ZnxNormalizeDigit, ZnxNormalizeFinalStep, ZnxNormalizeFinalStepInplace, ZnxNormalizeFirstStep, ZnxNormalizeFirstStepCarryOnly, ZnxNormalizeFirstStepInplace, ZnxNormalizeMiddleStep, - ZnxNormalizeMiddleStepCarryOnly, ZnxNormalizeMiddleStepInplace, ZnxSub, ZnxSubInplace, ZnxSubNegateInplace, ZnxSwitchRing, - ZnxZero, + ZnxNormalizeMiddleStepCarryOnly, ZnxNormalizeMiddleStepInplace, ZnxRotate, ZnxSub, ZnxSubInplace, ZnxSubNegateInplace, + ZnxSwitchRing, ZnxZero, add::{znx_add_inplace_ref, znx_add_ref}, automorphism::znx_automorphism_ref, copy::znx_copy_ref,@@ -17,7 +17,7 @@ sub::{znx_sub_inplace_ref, znx_sub_negate_inplace_ref, znx_sub_ref},
switch_ring::znx_switch_ring_ref, zero::znx_zero_ref, znx_extract_digit_addmul_ref, znx_mul_add_power_of_two_ref, znx_mul_power_of_two_inplace_ref, znx_mul_power_of_two_ref, - znx_normalize_digit_ref, + znx_normalize_digit_ref, znx_rotate, }; pub struct ZnxRef {}@@ -26,6 +26,13 @@ impl ZnxAdd for ZnxRef {
#[inline(always)] fn znx_add(res: &mut [i64], a: &[i64], b: &[i64]) { znx_add_ref(res, a, b); + } +} + +impl ZnxRotate for ZnxRef { + #[inline(always)] + fn znx_rotate(p: i64, res: &mut [i64], src: &[i64]) { + znx_rotate::<Self>(p, res, src); } }
@@ -16,6 +16,8 @@ poulpy-core = {path="../poulpy-core"}
criterion = {workspace = true} itertools = "0.14.0" byteorder = "1.5.0" +rand = "0.9.2" + [[bench]] name = "circuit_bootstrapping"
@@ -3,7 +3,7 @@
use criterion::{BenchmarkId, Criterion, criterion_group, criterion_main}; use poulpy_backend::{FFT64Avx, FFT64Ref, FFT64Spqlios}; use poulpy_core::layouts::{ - Digits, GGLWEAutomorphismKeyLayout, GGLWETensorKeyLayout, GGSWCiphertext, GGSWCiphertextLayout, GLWESecret, LWECiphertext, + Dsize, GGLWEAutomorphismKeyLayout, GGLWETensorKeyLayout, GGSWCiphertext, GGSWCiphertextLayout, GLWESecret, LWECiphertext, LWECiphertextLayout, LWESecret, prepared::PrepareAlloc, }; use poulpy_hal::{@@ -20,8 +20,8 @@ VmpPrepare, ZnAddNormal, ZnFillUniform, ZnNormalizeInplace,
}, layouts::{Backend, Module, ScratchOwned}, oep::{ - ScratchAvailableImpl, ScratchOwnedAllocImpl, ScratchOwnedBorrowImpl, TakeMatZnxImpl, TakeScalarZnxImpl, TakeSvpPPolImpl, - TakeVecZnxBigImpl, TakeVecZnxDftImpl, TakeVecZnxDftSliceImpl, TakeVecZnxImpl, TakeVecZnxSliceImpl, + ScratchAvailableImpl, ScratchOwnedAllocImpl, ScratchOwnedBorrowImpl, TakeMatZnxImpl, TakeScalarZnxImpl, TakeSliceImpl, + TakeSvpPPolImpl, TakeVecZnxBigImpl, TakeVecZnxDftImpl, TakeVecZnxDftSliceImpl, TakeVecZnxImpl, TakeVecZnxSliceImpl, }, source::Source, };@@ -98,7 +98,8 @@ + TakeSvpPPolImpl<B>
+ TakeVecZnxBigImpl<B> + TakeVecZnxDftSliceImpl<B> + TakeMatZnxImpl<B> - + TakeVecZnxSliceImpl<B>, + + TakeVecZnxSliceImpl<B> + + TakeSliceImpl<B>, BlindRotationKey<Vec<u8>, BRA>: PrepareAlloc<B, BlindRotationKeyPrepared<Vec<u8>, BRA, B>>, BlindRotationKeyPrepared<Vec<u8>, BRA, B>: BlincRotationExecute<B>, BlindRotationKey<Vec<u8>, BRA>: BlindRotationKeyAlloc + BlindRotationKeyEncryptSk<B>,@@ -178,7 +179,8 @@ + TakeSvpPPolImpl<B>
+ TakeVecZnxBigImpl<B> + TakeVecZnxDftSliceImpl<B> + TakeMatZnxImpl<B> - + TakeVecZnxSliceImpl<B>, + + TakeVecZnxSliceImpl<B> + + TakeSliceImpl<B>, BlindRotationKey<Vec<u8>, BRA>: PrepareAlloc<B, BlindRotationKeyPrepared<Vec<u8>, BRA, B>>, BlindRotationKeyPrepared<Vec<u8>, BRA, B>: BlincRotationExecute<B>, BlindRotationKey<Vec<u8>, BRA>: BlindRotationKeyAlloc + BlindRotationKeyEncryptSk<B>,@@ -246,8 +248,8 @@ ggsw_infos: GGSWCiphertextLayout {
n: 1024_u32.into(), base2k: 13_u32.into(), k: 26_u32.into(), - rows: 2_u32.into(), - digits: 1_u32.into(), + dnum: 2_u32.into(), + dsize: 1_u32.into(), rank: 2_u32.into(), }, cbt_infos: CircuitBootstrappingKeyLayout {@@ -256,23 +258,23 @@ n_glwe: 1024_u32.into(),
n_lwe: 574_u32.into(), base2k: 13_u32.into(), k: 52_u32.into(), - rows: 3_u32.into(), + dnum: 3_u32.into(), rank: 2_u32.into(), }, layout_atk: GGLWEAutomorphismKeyLayout { n: 1024_u32.into(), base2k: 13_u32.into(), k: 52_u32.into(), - rows: 3_u32.into(), - digits: Digits(1), + dnum: 3_u32.into(), + dsize: Dsize(1), rank: 2_u32.into(), }, layout_tsk: GGLWETensorKeyLayout { n: 1024_u32.into(), base2k: 13_u32.into(), k: 52_u32.into(), - rows: 3_u32.into(), - digits: Digits(1), + dnum: 3_u32.into(), + dsize: Dsize(1), rank: 2_u32.into(), }, },
@@ -56,25 +56,25 @@
// LWE block binary key block size let block_size: usize = 7; - // GGSW output number of rows + // GGSW output number of dnum let rows_ggsw_res: usize = 2; // GGSW output modulus let k_ggsw_res: usize = (rows_ggsw_res + 1) * base2k; - // Blind rotation key GGSW number of rows + // Blind rotation key GGSW number of dnum let rows_brk: usize = rows_ggsw_res + 1; // Blind rotation key GGSW modulus let k_brk: usize = (rows_brk + 1) * base2k; - // GGLWE automorphism keys number of rows + // GGLWE automorphism keys number of dnum let rows_trace: usize = rows_ggsw_res + 1; // GGLWE automorphism keys modulus let k_trace: usize = (rows_trace + 1) * base2k; - // GGLWE tensor key number of rows + // GGLWE tensor key number of dnum let rows_tsk: usize = rows_ggsw_res + 1; // GGLWE tensor key modulus@@ -86,23 +86,23 @@ n_glwe: n_glwe.into(),
n_lwe: n_lwe.into(), base2k: base2k.into(), k: k_brk.into(), - rows: rows_brk.into(), + dnum: rows_brk.into(), rank: rank.into(), }, layout_atk: GGLWEAutomorphismKeyLayout { n: n_glwe.into(), base2k: base2k.into(), k: k_trace.into(), - rows: rows_trace.into(), - digits: 1_u32.into(), + dnum: rows_trace.into(), + dsize: 1_u32.into(), rank: rank.into(), }, layout_tsk: GGLWETensorKeyLayout { n: n_glwe.into(), base2k: base2k.into(), k: k_tsk.into(), - rows: rows_tsk.into(), - digits: 1_u32.into(), + dnum: rows_tsk.into(), + dsize: 1_u32.into(), rank: rank.into(), }, };@@ -111,8 +111,8 @@ let ggsw_infos: GGSWCiphertextLayout = GGSWCiphertextLayout {
n: n_glwe.into(), base2k: base2k.into(), k: k_ggsw_res.into(), - rows: rows_ggsw_res.into(), - digits: 1_u32.into(), + dnum: rows_ggsw_res.into(), + dsize: 1_u32.into(), rank: rank.into(), };
@@ -0,0 +1,220 @@
+use itertools::Itertools; +use poulpy_core::layouts::prepared::GGSWCiphertextPreparedToRef; +use poulpy_hal::layouts::{Backend, DataMut, DataRef, Module, Scratch}; + +use crate::tfhe::bdd_arithmetic::{ + BitCircuitInfo, Circuit, CircuitExecute, FheUintBlocks, FheUintBlocksPrep, UnsignedInteger, circuits, +}; + +/// Operations Z x Z -> Z +pub(crate) struct Circuits2WTo1W<C: BitCircuitInfo + 'static, const WORD_SIZE: usize>(pub &'static Circuit<C, WORD_SIZE>); + +pub trait EvalBDD2WTo1W<BE: Backend, T: UnsignedInteger> { + fn eval_bdd_2w_to_1w<R, A, B>( + &self, + module: &Module<BE>, + out: &mut FheUintBlocks<R, T>, + a: &FheUintBlocksPrep<A, BE, T>, + b: &FheUintBlocksPrep<B, BE, T>, + scratch: &mut Scratch<BE>, + ) where + R: DataMut, + A: DataRef, + B: DataRef; +} + +impl<C: BitCircuitInfo + 'static, const WORD_SIZE: usize, BE: Backend, T: UnsignedInteger> EvalBDD2WTo1W<BE, T> + for Circuits2WTo1W<C, WORD_SIZE> +where + Circuit<C, WORD_SIZE>: CircuitExecute<BE, T>, +{ + fn eval_bdd_2w_to_1w<R, A, B>( + &self, + module: &Module<BE>, + out: &mut FheUintBlocks<R, T>, + a: &FheUintBlocksPrep<A, BE, T>, + b: &FheUintBlocksPrep<B, BE, T>, + scratch: &mut Scratch<BE>, + ) where + R: DataMut, + A: DataRef, + B: DataRef, + { + eval_bdd_2w_to_1w(module, self.0, out, a, b, scratch); + } +} + +pub fn eval_bdd_2w_to_1w<R: DataMut, A: DataRef, B: DataRef, T: UnsignedInteger, C: CircuitExecute<BE, T>, BE: Backend>( + module: &Module<BE>, + circuit: &C, + out: &mut FheUintBlocks<R, T>, + a: &FheUintBlocksPrep<A, BE, T>, + b: &FheUintBlocksPrep<B, BE, T>, + scratch: &mut Scratch<BE>, +) { + #[cfg(debug_assertions)] + { + assert_eq!(out.blocks.len(), T::WORD_SIZE); + assert_eq!(b.blocks.len(), T::WORD_SIZE); + assert_eq!(b.blocks.len(), T::WORD_SIZE); + } + + // Collects inputs into a single array + let inputs: Vec<&dyn GGSWCiphertextPreparedToRef<BE>> = a + .blocks + .iter() + .map(|x| x as &dyn GGSWCiphertextPreparedToRef<BE>) + .chain( + b.blocks + .iter() + .map(|x| x as &dyn GGSWCiphertextPreparedToRef<BE>), + ) + .collect_vec(); + + // Evaluates out[i] = circuit[i](a, b) + circuit.execute(module, &mut out.blocks, &inputs, scratch); +} + +#[macro_export] +macro_rules! define_bdd_2w_to_1w_trait { + ($(#[$meta:meta])* $vis:vis $trait_name:ident, $method_name:ident) => { + $(#[$meta])* + $vis trait $trait_name<T: UnsignedInteger, BE: Backend> { + fn $method_name<A, B>( + &mut self, + module: &Module<BE>, + a: &FheUintBlocksPrep<A, BE, T>, + b: &FheUintBlocksPrep<B, BE, T>, + scratch: &mut Scratch<BE>, + ) where + A: DataRef, + B: DataRef; + } + }; +} + +#[macro_export] +macro_rules! impl_bdd_2w_to_1w_trait { + ($trait_name:ident, $method_name:ident, $ty:ty, $n:literal, $circuit_ty:ty, $output_circuits:path) => { + impl<D: DataMut, BE: Backend> $trait_name<$ty, BE> for FheUintBlocks<D, $ty> + where + Circuits2WTo1W<$circuit_ty, $n>: EvalBDD2WTo1W<BE, $ty>, + { + fn $method_name<A, B>( + &mut self, + module: &Module<BE>, + a: &FheUintBlocksPrep<A, BE, $ty>, + b: &FheUintBlocksPrep<B, BE, $ty>, + scratch: &mut Scratch<BE>, + ) where + A: DataRef, + B: DataRef, + { + const OP: Circuits2WTo1W<$circuit_ty, $n> = Circuits2WTo1W::<$circuit_ty, $n>(&$output_circuits); + + OP.eval_bdd_2w_to_1w(module, self, a, b, scratch); + } + } + }; +} + +define_bdd_2w_to_1w_trait!(pub Add, add); +define_bdd_2w_to_1w_trait!(pub Sub, sub); +define_bdd_2w_to_1w_trait!(pub Sll, sll); +define_bdd_2w_to_1w_trait!(pub Sra, sra); +define_bdd_2w_to_1w_trait!(pub Srl, srl); +define_bdd_2w_to_1w_trait!(pub Slt, slt); +define_bdd_2w_to_1w_trait!(pub Sltu, sltu); +define_bdd_2w_to_1w_trait!(pub Or, or); +define_bdd_2w_to_1w_trait!(pub And, and); +define_bdd_2w_to_1w_trait!(pub Xor, xor); + +impl_bdd_2w_to_1w_trait!( + Add, + add, + u32, + 32, + circuits::u32::add_codegen::AnyBitCircuit, + circuits::u32::add_codegen::OUTPUT_CIRCUITS +); + +impl_bdd_2w_to_1w_trait!( + Sub, + sub, + u32, + 32, + circuits::u32::sub_codegen::AnyBitCircuit, + circuits::u32::sub_codegen::OUTPUT_CIRCUITS +); + +impl_bdd_2w_to_1w_trait!( + Sll, + sll, + u32, + 32, + circuits::u32::sll_codegen::AnyBitCircuit, + circuits::u32::sll_codegen::OUTPUT_CIRCUITS +); + +impl_bdd_2w_to_1w_trait!( + Sra, + sra, + u32, + 32, + circuits::u32::sra_codegen::AnyBitCircuit, + circuits::u32::sra_codegen::OUTPUT_CIRCUITS +); + +impl_bdd_2w_to_1w_trait!( + Srl, + srl, + u32, + 32, + circuits::u32::srl_codegen::AnyBitCircuit, + circuits::u32::srl_codegen::OUTPUT_CIRCUITS +); + +impl_bdd_2w_to_1w_trait!( + Slt, + slt, + u32, + 1, + circuits::u32::slt_codegen::AnyBitCircuit, + circuits::u32::slt_codegen::OUTPUT_CIRCUITS +); + +impl_bdd_2w_to_1w_trait!( + Sltu, + sltu, + u32, + 1, + circuits::u32::sltu_codegen::AnyBitCircuit, + circuits::u32::sltu_codegen::OUTPUT_CIRCUITS +); + +impl_bdd_2w_to_1w_trait!( + And, + and, + u32, + 32, + circuits::u32::and_codegen::AnyBitCircuit, + circuits::u32::and_codegen::OUTPUT_CIRCUITS +); + +impl_bdd_2w_to_1w_trait!( + Or, + or, + u32, + 1, + circuits::u32::or_codegen::AnyBitCircuit, + circuits::u32::or_codegen::OUTPUT_CIRCUITS +); + +impl_bdd_2w_to_1w_trait!( + Xor, + xor, + u32, + 1, + circuits::u32::xor_codegen::AnyBitCircuit, + circuits::u32::xor_codegen::OUTPUT_CIRCUITS +);
@@ -0,0 +1,215 @@
+use std::marker::PhantomData; + +use poulpy_core::layouts::{Base2K, GLWECiphertext, GLWEInfos, GLWEPlaintextLayout, LWEInfos, Rank, TorusPrecision}; + +use poulpy_core::{TakeGLWEPt, layouts::prepared::GLWESecretPrepared}; +use poulpy_hal::api::VecZnxBigAllocBytes; +#[cfg(test)] +use poulpy_hal::api::{ + ScratchAvailable, TakeVecZnx, VecZnxAddInplace, VecZnxAddNormal, VecZnxFillUniform, VecZnxNormalize, VecZnxSub, +}; +#[cfg(test)] +use poulpy_hal::source::Source; +use poulpy_hal::{ + api::{ + TakeVecZnxBig, TakeVecZnxDft, VecZnxBigAddInplace, VecZnxBigAddSmallInplace, VecZnxBigNormalize, VecZnxDftAllocBytes, + VecZnxDftApply, VecZnxIdftApplyConsume, VecZnxNormalizeTmpBytes, + }, + layouts::{Backend, Data, DataMut, DataRef, Module, Scratch}, +}; + +use poulpy_hal::api::{SvpApplyDftToDftInplace, VecZnxNormalizeInplace, VecZnxSubInplace}; + +use crate::tfhe::bdd_arithmetic::{FromBits, ToBits, UnsignedInteger}; + +/// An FHE ciphertext encrypting the bits of an [UnsignedInteger]. +pub struct FheUintBlocks<D: Data, T: UnsignedInteger> { + pub(crate) blocks: Vec<GLWECiphertext<D>>, + pub(crate) _base: u8, + pub(crate) _phantom: PhantomData<T>, +} + +impl<D: DataRef, T: UnsignedInteger> LWEInfos for FheUintBlocks<D, T> { + fn base2k(&self) -> poulpy_core::layouts::Base2K { + self.blocks[0].base2k() + } + + fn k(&self) -> poulpy_core::layouts::TorusPrecision { + self.blocks[0].k() + } + + fn n(&self) -> poulpy_core::layouts::Degree { + self.blocks[0].n() + } +} + +impl<D: DataRef, T: UnsignedInteger> GLWEInfos for FheUintBlocks<D, T> { + fn rank(&self) -> poulpy_core::layouts::Rank { + self.blocks[0].rank() + } +} + +impl<T: UnsignedInteger> FheUintBlocks<Vec<u8>, T> { + #[allow(dead_code)] + pub(crate) fn alloc<A, BE: Backend>(module: &Module<BE>, infos: &A) -> Self + where + A: GLWEInfos, + { + Self::alloc_with(module, infos.base2k(), infos.k(), infos.rank()) + } + + #[allow(dead_code)] + pub(crate) fn alloc_with<BE: Backend>(module: &Module<BE>, base2k: Base2K, k: TorusPrecision, rank: Rank) -> Self { + Self { + blocks: (0..T::WORD_SIZE) + .map(|_| GLWECiphertext::alloc_with(module.n().into(), base2k, k, rank)) + .collect(), + _base: 1, + _phantom: PhantomData, + } + } +} + +impl<D: DataMut, T: UnsignedInteger + ToBits> FheUintBlocks<D, T> { + #[allow(dead_code)] + #[cfg(test)] + pub(crate) fn encrypt_sk<S, BE: Backend>( + &mut self, + module: &Module<BE>, + value: T, + sk: &GLWESecretPrepared<S, BE>, + source_xa: &mut Source, + source_xe: &mut Source, + scratch: &mut Scratch<BE>, + ) where + S: DataRef, + Module<BE>: VecZnxDftAllocBytes + + VecZnxBigNormalize<BE> + + VecZnxDftApply<BE> + + SvpApplyDftToDftInplace<BE> + + VecZnxIdftApplyConsume<BE> + + VecZnxNormalizeTmpBytes + + VecZnxFillUniform + + VecZnxSubInplace + + VecZnxAddInplace + + VecZnxNormalizeInplace<BE> + + VecZnxAddNormal + + VecZnxNormalize<BE> + + VecZnxSub, + Scratch<BE>: TakeVecZnxDft<BE> + ScratchAvailable + TakeVecZnx + TakeGLWEPt<BE>, + { + use poulpy_core::layouts::GLWEPlaintextLayout; + + #[cfg(debug_assertions)] + { + assert!(module.n().is_multiple_of(T::WORD_SIZE)); + assert_eq!(self.n(), module.n() as u32); + assert_eq!(sk.n(), module.n() as u32); + } + + let pt_infos = GLWEPlaintextLayout { + n: self.n(), + base2k: self.base2k(), + k: 1_usize.into(), + }; + + let (mut pt, scratch_1) = scratch.take_glwe_pt(&pt_infos); + + for i in 0..T::WORD_SIZE { + pt.encode_coeff_i64(value.bit(i) as i64, TorusPrecision(1), 0); + self.blocks[i].encrypt_sk(&module, &pt, sk, source_xa, source_xe, scratch_1); + } + } +} + +impl<D: DataRef, T: UnsignedInteger + FromBits + ToBits> FheUintBlocks<D, T> { + pub fn decrypt<S: DataRef, BE: Backend>( + &self, + module: &Module<BE>, + sk: &GLWESecretPrepared<S, BE>, + scratch: &mut Scratch<BE>, + ) -> T + where + Module<BE>: VecZnxDftApply<BE> + + SvpApplyDftToDftInplace<BE> + + VecZnxIdftApplyConsume<BE> + + VecZnxBigAddInplace<BE> + + VecZnxBigAddSmallInplace<BE> + + VecZnxBigNormalize<BE>, + Scratch<BE>: TakeVecZnxDft<BE> + TakeVecZnxBig<BE> + TakeGLWEPt<BE>, + { + #[cfg(debug_assertions)] + { + assert!(module.n().is_multiple_of(T::WORD_SIZE)); + assert_eq!(self.n(), module.n() as u32); + assert_eq!(sk.n(), module.n() as u32); + } + + let pt_infos = GLWEPlaintextLayout { + n: self.n(), + base2k: self.base2k(), + k: self.k(), + }; + + let (mut pt, scratch_1) = scratch.take_glwe_pt(&pt_infos); + + let mut bits: Vec<u8> = vec![0u8; T::WORD_SIZE]; + + let base2k: usize = self.base2k().into(); + let scale: f64 = 4.0 / ((1 << base2k) as f64); + + for (i, bit) in bits.iter_mut().enumerate().take(T::WORD_SIZE) { + self.blocks[i].decrypt(module, &mut pt, sk, scratch_1); + let value: i64 = pt.decode_coeff_i64(base2k.into(), 0); + *bit = ((value as f64) * scale).round() as u8; + } + + T::from_bits(&bits) + } + + pub fn noise<S: DataRef, BE: Backend>( + &self, + module: &Module<BE>, + sk: &GLWESecretPrepared<S, BE>, + want: T, + scratch: &mut Scratch<BE>, + ) -> Vec<f64> + where + Module<BE>: VecZnxDftAllocBytes + + VecZnxBigAllocBytes + + VecZnxDftApply<BE> + + SvpApplyDftToDftInplace<BE> + + VecZnxIdftApplyConsume<BE> + + VecZnxBigAddInplace<BE> + + VecZnxBigAddSmallInplace<BE> + + VecZnxBigNormalize<BE> + + VecZnxNormalizeTmpBytes + + VecZnxSubInplace + + VecZnxNormalizeInplace<BE>, + Scratch<BE>: TakeGLWEPt<BE> + TakeVecZnxDft<BE> + TakeVecZnxBig<BE>, + { + #[cfg(debug_assertions)] + { + assert!(module.n().is_multiple_of(T::WORD_SIZE)); + assert_eq!(self.n(), module.n() as u32); + assert_eq!(sk.n(), module.n() as u32); + } + + let pt_infos = GLWEPlaintextLayout { + n: self.n(), + base2k: self.base2k(), + k: 1_usize.into(), + }; + + let (mut pt_want, scratch_1) = scratch.take_glwe_pt(&pt_infos); + + let mut noise: Vec<f64> = vec![0f64; T::WORD_SIZE]; + + for (i, noise_i) in noise.iter_mut().enumerate().take(T::WORD_SIZE) { + pt_want.encode_coeff_i64(want.bit(i) as i64, TorusPrecision(2), 0); + *noise_i = self.blocks[i].noise(module, sk, &pt_want, scratch_1); + } + + noise + } +}
@@ -0,0 +1,282 @@
+use std::marker::PhantomData; + +use poulpy_core::layouts::{ + Base2K, Dnum, Dsize, GGSWInfos, GLWEInfos, LWEInfos, Rank, TorusPrecision, prepared::GGSWCiphertextPrepared, +}; +#[cfg(test)] +use poulpy_core::{ + TakeGGSW, + layouts::{GGSWCiphertext, prepared::GLWESecretPrepared}, +}; +use poulpy_hal::{ + api::VmpPMatAlloc, + layouts::{Backend, Data, DataMut, DataRef, Module, Scratch}, +}; +#[cfg(test)] +use poulpy_hal::{ + api::{ + ScratchAvailable, SvpApplyDftToDftInplace, TakeScalarZnx, TakeVecZnx, TakeVecZnxDft, VecZnxAddInplace, VecZnxAddNormal, + VecZnxAddScalarInplace, VecZnxBigAddInplace, VecZnxBigAddSmallInplace, VecZnxBigAlloc, VecZnxBigAllocBytes, + VecZnxBigNormalize, VecZnxBigNormalizeTmpBytes, VecZnxDftAlloc, VecZnxDftAllocBytes, VecZnxDftApply, VecZnxFillUniform, + VecZnxIdftApplyConsume, VecZnxIdftApplyTmpA, VecZnxNormalize, VecZnxNormalizeInplace, VecZnxNormalizeTmpBytes, VecZnxSub, + VecZnxSubInplace, VmpPrepare, + }, + oep::{ScratchOwnedAllocImpl, ScratchOwnedBorrowImpl, TakeVecZnxBigImpl, TakeVecZnxDftImpl}, + source::Source, +}; + +use crate::tfhe::bdd_arithmetic::{FheUintBlocks, FheUintPrepare, ToBits, UnsignedInteger}; + +#[cfg(test)] +pub(crate) struct FheUintBlocksPrepDebug<D: Data, T: UnsignedInteger> { + pub(crate) blocks: Vec<GGSWCiphertext<D>>, + pub(crate) _base: u8, + pub(crate) _phantom: PhantomData<T>, +} + +#[cfg(test)] +impl<T: UnsignedInteger> FheUintBlocksPrepDebug<Vec<u8>, T> { + #[allow(dead_code)] + pub(crate) fn alloc<A, BE: Backend>(module: &Module<BE>, infos: &A) -> Self + where + A: GGSWInfos, + { + Self::alloc_with( + module, + infos.base2k(), + infos.k(), + infos.dnum(), + infos.dsize(), + infos.rank(), + ) + } + + #[allow(dead_code)] + pub(crate) fn alloc_with<BE: Backend>( + module: &Module<BE>, + base2k: Base2K, + k: TorusPrecision, + dnum: Dnum, + dsize: Dsize, + rank: Rank, + ) -> Self { + Self { + blocks: (0..T::WORD_SIZE) + .map(|_| GGSWCiphertext::alloc_with(module.n().into(), base2k, k, rank, dnum, dsize)) + .collect(), + _base: 1, + _phantom: PhantomData, + } + } +} + +/// A prepared FHE ciphertext encrypting the bits of an [UnsignedInteger]. +pub struct FheUintBlocksPrep<D: Data, B: Backend, T: UnsignedInteger> { + pub(crate) blocks: Vec<GGSWCiphertextPrepared<D, B>>, + pub(crate) _base: u8, + pub(crate) _phantom: PhantomData<T>, +} + +impl<T: UnsignedInteger, BE: Backend> FheUintBlocksPrep<Vec<u8>, BE, T> +where + Module<BE>: VmpPMatAlloc<BE>, +{ + #[allow(dead_code)] + pub(crate) fn alloc<A>(module: &Module<BE>, infos: &A) -> Self + where + A: GGSWInfos, + { + Self::alloc_with( + module, + infos.base2k(), + infos.k(), + infos.dnum(), + infos.dsize(), + infos.rank(), + ) + } + + #[allow(dead_code)] + pub(crate) fn alloc_with(module: &Module<BE>, base2k: Base2K, k: TorusPrecision, dnum: Dnum, dsize: Dsize, rank: Rank) -> Self + where + Module<BE>: VmpPMatAlloc<BE>, + { + Self { + blocks: (0..T::WORD_SIZE) + .map(|_| GGSWCiphertextPrepared::alloc_with(module, base2k, k, dnum, dsize, rank)) + .collect(), + _base: 1, + _phantom: PhantomData, + } + } +} + +impl<D: DataMut, T: UnsignedInteger + ToBits, BE: Backend> FheUintBlocksPrep<D, BE, T> { + #[allow(dead_code)] + #[cfg(test)] + pub(crate) fn encrypt_sk<S>( + &mut self, + module: &Module<BE>, + value: T, + sk: &GLWESecretPrepared<S, BE>, + source_xa: &mut Source, + source_xe: &mut Source, + scratch: &mut Scratch<BE>, + ) where + S: DataRef, + Module<BE>: VecZnxAddScalarInplace + + VecZnxDftAllocBytes + + VecZnxBigNormalize<BE> + + VecZnxDftApply<BE> + + SvpApplyDftToDftInplace<BE> + + VecZnxIdftApplyConsume<BE> + + VecZnxNormalizeTmpBytes + + VecZnxFillUniform + + VecZnxSubInplace + + VecZnxAddInplace + + VecZnxNormalizeInplace<BE> + + VecZnxAddNormal + + VecZnxNormalize<BE> + + VecZnxSub + + VmpPrepare<BE>, + Scratch<BE>: TakeVecZnxDft<BE> + ScratchAvailable + TakeVecZnx + TakeGGSW + TakeScalarZnx, + { + #[cfg(debug_assertions)] + { + assert!(module.n().is_multiple_of(T::WORD_SIZE)); + assert_eq!(self.n(), module.n() as u32); + assert_eq!(sk.n(), module.n() as u32); + } + + let (mut tmp_ggsw, scratch_1) = scratch.take_ggsw(self); + let (mut pt, scratch_2) = scratch_1.take_scalar_znx(module.n(), 1); + + for i in 0..T::WORD_SIZE { + use poulpy_core::layouts::prepared::Prepare; + use poulpy_hal::layouts::ZnxViewMut; + + pt.at_mut(0, 0)[0] = value.bit(i) as i64; + tmp_ggsw.encrypt_sk(&module, &pt, sk, source_xa, source_xe, scratch_2); + self.blocks[i].prepare(module, &tmp_ggsw, scratch_2); + } + } + + /// Prepares [FheUintBits] to [FheUintBitsPrep]. + pub fn prepare<BIT, KEY>(&mut self, module: &Module<BE>, bits: &FheUintBlocks<BIT, T>, key: &KEY, scratch: &mut Scratch<BE>) + where + BIT: DataRef, + KEY: FheUintPrepare<BE, FheUintBlocksPrep<D, BE, T>, FheUintBlocks<BIT, T>>, + { + key.prepare(module, self, bits, scratch); + } +} + +#[cfg(test)] +impl<D: DataMut, T: UnsignedInteger + ToBits> FheUintBlocksPrepDebug<D, T> { + pub(crate) fn prepare<BIT, KEY, BE: Backend>( + &mut self, + module: &Module<BE>, + bits: &FheUintBlocks<BIT, T>, + key: &KEY, + scratch: &mut Scratch<BE>, + ) where + BIT: DataRef, + KEY: FheUintPrepare<BE, FheUintBlocksPrepDebug<D, T>, FheUintBlocks<BIT, T>>, + { + key.prepare(module, self, bits, scratch); + } +} + +#[cfg(test)] +impl<D: DataRef, T: UnsignedInteger + ToBits> FheUintBlocksPrepDebug<D, T> { + #[allow(dead_code)] + pub(crate) fn noise<S: DataRef, BE: Backend>(&self, module: &Module<BE>, sk: &GLWESecretPrepared<S, BE>, want: T) + where + Module<BE>: VecZnxDftAllocBytes + + VecZnxBigAllocBytes + + VecZnxDftApply<BE> + + SvpApplyDftToDftInplace<BE> + + VecZnxIdftApplyConsume<BE> + + VecZnxBigAddInplace<BE> + + VecZnxBigAddSmallInplace<BE> + + VecZnxBigNormalize<BE> + + VecZnxNormalizeTmpBytes + + VecZnxBigAlloc<BE> + + VecZnxDftAlloc<BE> + + VecZnxBigNormalizeTmpBytes + + VecZnxIdftApplyTmpA<BE> + + VecZnxAddScalarInplace + + VecZnxSubInplace, + BE: Backend + TakeVecZnxDftImpl<BE> + TakeVecZnxBigImpl<BE> + ScratchOwnedAllocImpl<BE> + ScratchOwnedBorrowImpl<BE>, + { + for (i, ggsw) in self.blocks.iter().enumerate() { + use poulpy_hal::layouts::{ScalarZnx, ZnxViewMut}; + let mut pt_want = ScalarZnx::alloc(self.n().into(), 1); + pt_want.at_mut(0, 0)[0] = want.bit(i) as i64; + ggsw.print_noise(module, sk, &pt_want); + } + } +} + +impl<D: DataRef, T: UnsignedInteger, B: Backend> LWEInfos for FheUintBlocksPrep<D, B, T> { + fn base2k(&self) -> poulpy_core::layouts::Base2K { + self.blocks[0].base2k() + } + + fn k(&self) -> poulpy_core::layouts::TorusPrecision { + self.blocks[0].k() + } + + fn n(&self) -> poulpy_core::layouts::Degree { + self.blocks[0].n() + } +} + +impl<D: DataRef, T: UnsignedInteger, B: Backend> GLWEInfos for FheUintBlocksPrep<D, B, T> { + fn rank(&self) -> poulpy_core::layouts::Rank { + self.blocks[0].rank() + } +} + +impl<D: DataRef, T: UnsignedInteger, B: Backend> GGSWInfos for FheUintBlocksPrep<D, B, T> { + fn dsize(&self) -> poulpy_core::layouts::Dsize { + self.blocks[0].dsize() + } + + fn dnum(&self) -> poulpy_core::layouts::Dnum { + self.blocks[0].dnum() + } +} + +#[cfg(test)] +impl<D: DataRef, T: UnsignedInteger> LWEInfos for FheUintBlocksPrepDebug<D, T> { + fn base2k(&self) -> poulpy_core::layouts::Base2K { + self.blocks[0].base2k() + } + + fn k(&self) -> poulpy_core::layouts::TorusPrecision { + self.blocks[0].k() + } + + fn n(&self) -> poulpy_core::layouts::Degree { + self.blocks[0].n() + } +} + +#[cfg(test)] +impl<D: DataRef, T: UnsignedInteger> GLWEInfos for FheUintBlocksPrepDebug<D, T> { + fn rank(&self) -> poulpy_core::layouts::Rank { + self.blocks[0].rank() + } +} + +#[cfg(test)] +impl<D: DataRef, T: UnsignedInteger> GGSWInfos for FheUintBlocksPrepDebug<D, T> { + fn dsize(&self) -> poulpy_core::layouts::Dsize { + self.blocks[0].dsize() + } + + fn dnum(&self) -> poulpy_core::layouts::Dnum { + self.blocks[0].dnum() + } +}
@@ -0,0 +1,7 @@
+mod block; +mod block_prepared; +mod word; + +pub use block::*; +pub use block_prepared::*; +pub use word::*;
@@ -0,0 +1,198 @@
+use itertools::Itertools; +use poulpy_core::{ + GLWEOperations, TakeGLWECtSlice, TakeGLWEPt, glwe_packing, + layouts::{ + GLWECiphertext, GLWEInfos, GLWEPlaintextLayout, LWEInfos, TorusPrecision, + prepared::{GGLWEAutomorphismKeyPrepared, GLWESecretPrepared}, + }, +}; +use poulpy_hal::{ + api::{ + ScratchAvailable, SvpApplyDftToDftInplace, TakeVecZnx, TakeVecZnxBig, TakeVecZnxDft, VecZnxAddInplace, VecZnxAddNormal, + VecZnxAddScalarInplace, VecZnxAutomorphismInplace, VecZnxBigAddInplace, VecZnxBigAddSmallInplace, + VecZnxBigAutomorphismInplace, VecZnxBigNormalize, VecZnxBigNormalizeTmpBytes, VecZnxBigSubSmallNegateInplace, VecZnxCopy, + VecZnxDftAllocBytes, VecZnxDftApply, VecZnxDftCopy, VecZnxFillUniform, VecZnxIdftApplyConsume, VecZnxIdftApplyTmpA, + VecZnxNegateInplace, VecZnxNormalize, VecZnxNormalizeInplace, VecZnxNormalizeTmpBytes, VecZnxRotate, VecZnxRotateInplace, + VecZnxRshInplace, VecZnxSub, VecZnxSubInplace, VecZnxSwitchRing, VmpApplyDftToDft, VmpApplyDftToDftAdd, + VmpApplyDftToDftTmpBytes, + }, + layouts::{Backend, Data, DataMut, DataRef, Module, Scratch}, + source::Source, +}; +use std::{collections::HashMap, marker::PhantomData}; + +use crate::tfhe::bdd_arithmetic::{FromBits, ToBits, UnsignedInteger}; + +/// A FHE ciphertext encrypting a [UnsignedInteger]. +pub struct FheUintWord<D: Data, T: UnsignedInteger>(pub(crate) GLWECiphertext<D>, pub(crate) PhantomData<T>); + +impl<D: DataMut, T: UnsignedInteger> FheUintWord<D, T> { + #[allow(dead_code)] + fn post_process<ATK, BE: Backend>( + &mut self, + module: &Module<BE>, + mut tmp_res: Vec<GLWECiphertext<&mut [u8]>>, + auto_keys: &HashMap<i64, GGLWEAutomorphismKeyPrepared<ATK, BE>>, + scratch: &mut Scratch<BE>, + ) where + ATK: DataRef, + Module<BE>: VecZnxSub + + VecZnxCopy + + VecZnxNegateInplace + + VecZnxDftAllocBytes + + VecZnxAddInplace + + VmpApplyDftToDftTmpBytes + + VecZnxNormalizeTmpBytes + + VecZnxDftApply<BE> + + VmpApplyDftToDft<BE> + + VmpApplyDftToDftAdd<BE> + + VecZnxIdftApplyConsume<BE> + + VecZnxBigNormalize<BE> + + VecZnxNormalize<BE> + + VecZnxRotateInplace<BE> + + VecZnxNormalizeInplace<BE> + + VecZnxSwitchRing + + VecZnxBigAutomorphismInplace<BE> + + VecZnxRshInplace<BE> + + VecZnxDftCopy<BE> + + VecZnxIdftApplyTmpA<BE> + + VecZnxSubInplace + + VecZnxBigNormalizeTmpBytes + + VecZnxBigAddSmallInplace<BE> + + VecZnxAutomorphismInplace<BE> + + VecZnxBigSubSmallNegateInplace<BE> + + VecZnxRotate, + Scratch<BE>: TakeVecZnxDft<BE> + ScratchAvailable + TakeVecZnx + TakeGLWECtSlice, + { + // Repacks the GLWE ciphertexts bits + let gap: usize = module.n() / T::WORD_SIZE; + let log_gap: usize = (usize::BITS - (gap - 1).leading_zeros()) as usize; + let mut cts: HashMap<usize, &mut GLWECiphertext<&mut [u8]>> = HashMap::new(); + for (i, ct) in tmp_res.iter_mut().enumerate().take(T::WORD_SIZE) { + cts.insert(i * gap, ct); + } + glwe_packing(module, &mut cts, log_gap, auto_keys, scratch); + + // And copies the repacked ciphertext on the receiver. + self.0.copy(module, cts.remove(&0).unwrap()) + } +} + +impl<D: DataRef, T: UnsignedInteger> LWEInfos for FheUintWord<D, T> { + fn base2k(&self) -> poulpy_core::layouts::Base2K { + self.0.base2k() + } + + fn k(&self) -> poulpy_core::layouts::TorusPrecision { + self.0.k() + } + + fn n(&self) -> poulpy_core::layouts::Degree { + self.0.n() + } +} + +impl<D: DataRef, T: UnsignedInteger> GLWEInfos for FheUintWord<D, T> { + fn rank(&self) -> poulpy_core::layouts::Rank { + self.0.rank() + } +} + +impl<D: DataMut, T: UnsignedInteger + ToBits> FheUintWord<D, T> { + pub fn encrypt_sk<S: DataRef, BE: Backend>( + &mut self, + module: &Module<BE>, + data: T, + sk: &GLWESecretPrepared<S, BE>, + source_xa: &mut Source, + source_xe: &mut Source, + scratch: &mut Scratch<BE>, + ) where + Module<BE>: VecZnxAddScalarInplace + + VecZnxDftAllocBytes + + VecZnxBigNormalize<BE> + + VecZnxDftApply<BE> + + SvpApplyDftToDftInplace<BE> + + VecZnxIdftApplyConsume<BE> + + VecZnxNormalizeTmpBytes + + VecZnxFillUniform + + VecZnxSubInplace + + VecZnxAddInplace + + VecZnxNormalizeInplace<BE> + + VecZnxAddNormal + + VecZnxNormalize<BE> + + VecZnxSub, + Scratch<BE>: TakeVecZnxDft<BE> + ScratchAvailable + TakeVecZnx + TakeGLWEPt<BE>, + { + #[cfg(debug_assertions)] + { + assert!(module.n().is_multiple_of(T::WORD_SIZE)); + assert_eq!(self.n(), module.n() as u32); + assert_eq!(sk.n(), module.n() as u32); + } + + let gap: usize = module.n() / T::WORD_SIZE; + + let mut data_bits: Vec<i64> = vec![0i64; module.n()]; + + for i in 0..T::WORD_SIZE { + data_bits[i * gap] = data.bit(i) as i64 + } + + let pt_infos = GLWEPlaintextLayout { + n: self.n(), + base2k: self.base2k(), + k: 1_usize.into(), + }; + + let (mut pt, scratch_1) = scratch.take_glwe_pt(&pt_infos); + + pt.encode_vec_i64(&data_bits, TorusPrecision(1)); + self.0 + .encrypt_sk(module, &pt, sk, source_xa, source_xe, scratch_1); + } +} + +impl<D: DataRef, T: UnsignedInteger + FromBits> FheUintWord<D, T> { + pub fn decrypt<S: DataRef, BE: Backend>( + &self, + module: &Module<BE>, + sk: &GLWESecretPrepared<S, BE>, + scratch: &mut Scratch<BE>, + ) -> T + where + Module<BE>: VecZnxDftApply<BE> + + SvpApplyDftToDftInplace<BE> + + VecZnxIdftApplyConsume<BE> + + VecZnxBigAddInplace<BE> + + VecZnxBigAddSmallInplace<BE> + + VecZnxBigNormalize<BE>, + Scratch<BE>: TakeVecZnxDft<BE> + TakeVecZnxBig<BE> + TakeGLWEPt<BE>, + { + #[cfg(debug_assertions)] + { + assert!(module.n().is_multiple_of(T::WORD_SIZE)); + assert_eq!(self.n(), module.n() as u32); + assert_eq!(sk.n(), module.n() as u32); + } + + let gap: usize = module.n() / T::WORD_SIZE; + + let pt_infos = GLWEPlaintextLayout { + n: self.n(), + base2k: self.base2k(), + k: 1_usize.into(), + }; + + let (mut pt, scratch_1) = scratch.take_glwe_pt(&pt_infos); + + self.0.decrypt(module, &mut pt, sk, scratch_1); + + let mut data: Vec<i64> = vec![0i64; module.n()]; + + pt.decode_vec_i64(&mut data, TorusPrecision(1)); + + let bits: Vec<u8> = data.iter().step_by(gap).map(|c| *c as u8).collect_vec(); + T::from_bits(&bits) + } +}
@@ -0,0 +1,3020 @@
+use crate::tfhe::bdd_arithmetic::{BitCircuit, BitCircuitInfo, Circuit, GetBitCircuitInfo, Node}; +pub(crate) enum AnyBitCircuit { + B0(BitCircuit<3, 2>), + B1(BitCircuit<7, 4>), + B2(BitCircuit<12, 6>), + B3(BitCircuit<17, 8>), + B4(BitCircuit<22, 10>), + B5(BitCircuit<27, 12>), + B6(BitCircuit<32, 14>), + B7(BitCircuit<37, 16>), + B8(BitCircuit<42, 18>), + B9(BitCircuit<47, 20>), + B10(BitCircuit<52, 22>), + B11(BitCircuit<57, 24>), + B12(BitCircuit<62, 26>), + B13(BitCircuit<67, 28>), + B14(BitCircuit<72, 30>), + B15(BitCircuit<77, 32>), + B16(BitCircuit<82, 34>), + B17(BitCircuit<87, 36>), + B18(BitCircuit<92, 38>), + B19(BitCircuit<97, 40>), + B20(BitCircuit<102, 42>), + B21(BitCircuit<107, 44>), + B22(BitCircuit<112, 46>), + B23(BitCircuit<117, 48>), + B24(BitCircuit<122, 50>), + B25(BitCircuit<127, 52>), + B26(BitCircuit<132, 54>), + B27(BitCircuit<137, 56>), + B28(BitCircuit<142, 58>), + B29(BitCircuit<147, 60>), + B30(BitCircuit<152, 62>), + B31(BitCircuit<157, 64>), +} + +impl BitCircuitInfo for AnyBitCircuit { + fn info(&self) -> (&[Node], &[usize], usize) { + match self { + AnyBitCircuit::B0(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B1(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B2(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B3(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B4(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B5(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B6(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B7(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B8(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B9(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B10(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B11(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B12(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B13(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B14(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B15(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B16(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B17(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B18(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B19(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B20(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B21(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B22(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B23(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B24(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B25(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B26(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B27(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B28(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B29(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B30(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B31(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + } + } +} + +impl GetBitCircuitInfo<u32> for Circuit<AnyBitCircuit, 32usize> { + fn input_size(&self) -> usize { + 2 * u32::BITS as usize + } + fn output_size(&self) -> usize { + u32::BITS as usize + } + fn get_circuit(&self, bit: usize) -> (&[Node], &[usize], usize) { + self.0[bit].info() + } +} + +pub(crate) static OUTPUT_CIRCUITS: Circuit<AnyBitCircuit, 32usize> = Circuit([ + AnyBitCircuit::B0(BitCircuit::new( + [Node::new(32, 1, 0), Node::new(32, 0, 1), Node::new(0, 1, 0)], + [0, 2], + 2, + )), + AnyBitCircuit::B1(BitCircuit::new( + [ + Node::new(33, 1, 0), + Node::new(33, 0, 1), + Node::new(1, 1, 0), + Node::new(1, 0, 1), + Node::new(1, 0, 0), + Node::new(32, 1, 0), + Node::new(0, 1, 0), + ], + [0, 2, 4, 6], + 2, + )), + AnyBitCircuit::B2(BitCircuit::new( + [ + Node::new(34, 1, 0), + Node::new(34, 0, 1), + Node::new(2, 1, 0), + Node::new(2, 0, 1), + Node::new(2, 0, 0), + Node::new(2, 1, 1), + Node::new(33, 1, 0), + Node::new(1, 2, 0), + Node::new(1, 1, 2), + Node::new(1, 0, 0), + Node::new(32, 1, 0), + Node::new(0, 1, 0), + ], + [0, 2, 4, 7, 9, 11], + 3, + )), + AnyBitCircuit::B3(BitCircuit::new( + [ + Node::new(35, 0, 1), + Node::new(35, 1, 0), + Node::new(3, 1, 0), + Node::new(3, 0, 1), + Node::new(3, 0, 0), + Node::new(3, 1, 1), + Node::new(34, 0, 1), + Node::new(2, 2, 1), + Node::new(2, 0, 2), + Node::new(2, 0, 0), + Node::new(2, 1, 1), + Node::new(33, 1, 0), + Node::new(1, 2, 0), + Node::new(1, 1, 2), + Node::new(1, 0, 0), + Node::new(32, 1, 0), + Node::new(0, 1, 0), + ], + [0, 2, 4, 7, 9, 12, 14, 16], + 3, + )), + AnyBitCircuit::B4(BitCircuit::new( + [ + Node::new(36, 1, 0), + Node::new(36, 0, 1), + Node::new(4, 1, 0), + Node::new(4, 0, 1), + Node::new(4, 0, 0), + Node::new(4, 1, 1), + Node::new(35, 1, 0), + Node::new(3, 2, 0), + Node::new(3, 1, 2), + Node::new(3, 0, 0), + Node::new(3, 1, 1), + Node::new(34, 1, 0), + Node::new(2, 2, 0), + Node::new(2, 1, 2), + Node::new(2, 0, 0), + Node::new(2, 1, 1), + Node::new(33, 1, 0), + Node::new(1, 2, 0), + Node::new(1, 1, 2), + Node::new(1, 0, 0), + Node::new(32, 1, 0), + Node::new(0, 1, 0), + ], + [0, 2, 4, 7, 9, 12, 14, 17, 19, 21], + 3, + )), + AnyBitCircuit::B5(BitCircuit::new( + [ + Node::new(37, 0, 1), + Node::new(37, 1, 0), + Node::new(5, 1, 0), + Node::new(5, 0, 1), + Node::new(5, 0, 0), + Node::new(5, 1, 1), + Node::new(36, 0, 1), + Node::new(4, 0, 2), + Node::new(4, 2, 1), + Node::new(4, 0, 0), + Node::new(4, 1, 1), + Node::new(35, 0, 1), + Node::new(3, 2, 1), + Node::new(3, 0, 2), + Node::new(3, 0, 0), + Node::new(3, 1, 1), + Node::new(34, 1, 0), + Node::new(2, 2, 0), + Node::new(2, 1, 2), + Node::new(2, 0, 0), + Node::new(2, 1, 1), + Node::new(33, 1, 0), + Node::new(1, 2, 0), + Node::new(1, 1, 2), + Node::new(1, 0, 0), + Node::new(32, 1, 0), + Node::new(0, 1, 0), + ], + [0, 2, 4, 7, 9, 12, 14, 17, 19, 22, 24, 26], + 3, + )), + AnyBitCircuit::B6(BitCircuit::new( + [ + Node::new(38, 0, 1), + Node::new(38, 1, 0), + Node::new(6, 0, 1), + Node::new(6, 1, 0), + Node::new(6, 0, 0), + Node::new(6, 1, 1), + Node::new(37, 1, 0), + Node::new(5, 2, 0), + Node::new(5, 1, 2), + Node::new(5, 0, 0), + Node::new(5, 1, 1), + Node::new(36, 1, 0), + Node::new(4, 2, 0), + Node::new(4, 1, 2), + Node::new(4, 0, 0), + Node::new(4, 1, 1), + Node::new(35, 1, 0), + Node::new(3, 2, 0), + Node::new(3, 1, 2), + Node::new(3, 0, 0), + Node::new(3, 1, 1), + Node::new(34, 1, 0), + Node::new(2, 2, 0), + Node::new(2, 1, 2), + Node::new(2, 0, 0), + Node::new(2, 1, 1), + Node::new(33, 1, 0), + Node::new(1, 2, 0), + Node::new(1, 1, 2), + Node::new(1, 0, 0), + Node::new(32, 1, 0), + Node::new(0, 1, 0), + ], + [0, 2, 4, 7, 9, 12, 14, 17, 19, 22, 24, 27, 29, 31], + 3, + )), + AnyBitCircuit::B7(BitCircuit::new( + [ + Node::new(39, 0, 1), + Node::new(39, 1, 0), + Node::new(7, 1, 0), + Node::new(7, 0, 1), + Node::new(7, 0, 0), + Node::new(7, 1, 1), + Node::new(38, 0, 1), + Node::new(6, 2, 1), + Node::new(6, 0, 2), + Node::new(6, 0, 0), + Node::new(6, 1, 1), + Node::new(37, 1, 0), + Node::new(5, 1, 2), + Node::new(5, 2, 0), + Node::new(5, 0, 0), + Node::new(5, 1, 1), + Node::new(36, 0, 1), + Node::new(4, 2, 1), + Node::new(4, 0, 2), + Node::new(4, 0, 0), + Node::new(4, 1, 1), + Node::new(35, 1, 0), + Node::new(3, 2, 0), + Node::new(3, 1, 2), + Node::new(3, 0, 0), + Node::new(3, 1, 1), + Node::new(34, 1, 0), + Node::new(2, 2, 0), + Node::new(2, 1, 2), + Node::new(2, 0, 0), + Node::new(2, 1, 1), + Node::new(33, 1, 0), + Node::new(1, 2, 0), + Node::new(1, 1, 2), + Node::new(1, 0, 0), + Node::new(32, 1, 0), + Node::new(0, 1, 0), + ], + [0, 2, 4, 7, 9, 12, 14, 17, 19, 22, 24, 27, 29, 32, 34, 36], + 3, + )), + AnyBitCircuit::B8(BitCircuit::new( + [ + Node::new(40, 1, 0), + Node::new(40, 0, 1), + Node::new(8, 0, 1), + Node::new(8, 1, 0), + Node::new(8, 0, 0), + Node::new(8, 1, 1), + Node::new(39, 0, 1), + Node::new(7, 0, 2), + Node::new(7, 2, 1), + Node::new(7, 0, 0), + Node::new(7, 1, 1), + Node::new(38, 0, 1), + Node::new(6, 2, 1), + Node::new(6, 0, 2), + Node::new(6, 0, 0), + Node::new(6, 1, 1), + Node::new(37, 1, 0), + Node::new(5, 2, 0), + Node::new(5, 1, 2), + Node::new(5, 0, 0), + Node::new(5, 1, 1), + Node::new(36, 1, 0), + Node::new(4, 2, 0), + Node::new(4, 1, 2), + Node::new(4, 0, 0), + Node::new(4, 1, 1), + Node::new(35, 1, 0), + Node::new(3, 1, 2), + Node::new(3, 2, 0), + Node::new(3, 0, 0), + Node::new(3, 1, 1), + Node::new(34, 0, 1), + Node::new(2, 2, 1), + Node::new(2, 0, 2), + Node::new(2, 0, 0), + Node::new(2, 1, 1), + Node::new(33, 1, 0), + Node::new(1, 2, 0), + Node::new(1, 1, 2), + Node::new(1, 0, 0), + Node::new(32, 1, 0), + Node::new(0, 1, 0), + ], + [ + 0, 2, 4, 7, 9, 12, 14, 17, 19, 22, 24, 27, 29, 32, 34, 37, 39, 41, + ], + 3, + )), + AnyBitCircuit::B9(BitCircuit::new( + [ + Node::new(41, 0, 1), + Node::new(41, 1, 0), + Node::new(9, 1, 0), + Node::new(9, 0, 1), + Node::new(9, 0, 0), + Node::new(9, 1, 1), + Node::new(40, 0, 1), + Node::new(8, 0, 2), + Node::new(8, 2, 1), + Node::new(8, 0, 0), + Node::new(8, 1, 1), + Node::new(39, 0, 1), + Node::new(7, 2, 1), + Node::new(7, 0, 2), + Node::new(7, 0, 0), + Node::new(7, 1, 1), + Node::new(38, 1, 0), + Node::new(6, 2, 0), + Node::new(6, 1, 2), + Node::new(6, 0, 0), + Node::new(6, 1, 1), + Node::new(37, 1, 0), + Node::new(5, 2, 0), + Node::new(5, 1, 2), + Node::new(5, 0, 0), + Node::new(5, 1, 1), + Node::new(36, 1, 0), + Node::new(4, 2, 0), + Node::new(4, 1, 2), + Node::new(4, 0, 0), + Node::new(4, 1, 1), + Node::new(35, 1, 0), + Node::new(3, 2, 0), + Node::new(3, 1, 2), + Node::new(3, 0, 0), + Node::new(3, 1, 1), + Node::new(34, 1, 0), + Node::new(2, 2, 0), + Node::new(2, 1, 2), + Node::new(2, 0, 0), + Node::new(2, 1, 1), + Node::new(33, 1, 0), + Node::new(1, 2, 0), + Node::new(1, 1, 2), + Node::new(1, 0, 0), + Node::new(32, 1, 0), + Node::new(0, 1, 0), + ], + [ + 0, 2, 4, 7, 9, 12, 14, 17, 19, 22, 24, 27, 29, 32, 34, 37, 39, 42, 44, 46, + ], + 3, + )), + AnyBitCircuit::B10(BitCircuit::new( + [ + Node::new(42, 0, 1), + Node::new(42, 1, 0), + Node::new(10, 1, 0), + Node::new(10, 0, 1), + Node::new(10, 0, 0), + Node::new(10, 1, 1), + Node::new(41, 0, 1), + Node::new(9, 0, 2), + Node::new(9, 2, 1), + Node::new(9, 0, 0), + Node::new(9, 1, 1), + Node::new(40, 0, 1), + Node::new(8, 2, 1), + Node::new(8, 0, 2), + Node::new(8, 0, 0), + Node::new(8, 1, 1), + Node::new(39, 1, 0), + Node::new(7, 1, 2), + Node::new(7, 2, 0), + Node::new(7, 0, 0), + Node::new(7, 1, 1), + Node::new(38, 0, 1), + Node::new(6, 0, 2), + Node::new(6, 2, 1), + Node::new(6, 0, 0), + Node::new(6, 1, 1), + Node::new(37, 0, 1), + Node::new(5, 0, 2), + Node::new(5, 2, 1), + Node::new(5, 0, 0), + Node::new(5, 1, 1), + Node::new(36, 0, 1), + Node::new(4, 0, 2), + Node::new(4, 2, 1), + Node::new(4, 0, 0), + Node::new(4, 1, 1), + Node::new(35, 0, 1), + Node::new(3, 0, 2), + Node::new(3, 2, 1), + Node::new(3, 0, 0), + Node::new(3, 1, 1), + Node::new(34, 0, 1), + Node::new(2, 0, 2), + Node::new(2, 2, 1), + Node::new(2, 0, 0), + Node::new(2, 1, 1), + Node::new(33, 0, 1), + Node::new(1, 2, 1), + Node::new(1, 0, 2), + Node::new(1, 0, 0), + Node::new(32, 1, 0), + Node::new(0, 1, 0), + ], + [ + 0, 2, 4, 7, 9, 12, 14, 17, 19, 22, 24, 27, 29, 32, 34, 37, 39, 42, 44, 47, 49, 51, + ], + 3, + )), + AnyBitCircuit::B11(BitCircuit::new( + [ + Node::new(43, 1, 0), + Node::new(43, 0, 1), + Node::new(11, 1, 0), + Node::new(11, 0, 1), + Node::new(11, 0, 0), + Node::new(11, 1, 1), + Node::new(42, 1, 0), + Node::new(10, 2, 0), + Node::new(10, 1, 2), + Node::new(10, 0, 0), + Node::new(10, 1, 1), + Node::new(41, 1, 0), + Node::new(9, 1, 2), + Node::new(9, 2, 0), + Node::new(9, 0, 0), + Node::new(9, 1, 1), + Node::new(40, 0, 1), + Node::new(8, 0, 2), + Node::new(8, 2, 1), + Node::new(8, 0, 0), + Node::new(8, 1, 1), + Node::new(39, 0, 1), + Node::new(7, 0, 2), + Node::new(7, 2, 1), + Node::new(7, 0, 0), + Node::new(7, 1, 1), + Node::new(38, 0, 1), + Node::new(6, 2, 1), + Node::new(6, 0, 2), + Node::new(6, 0, 0), + Node::new(6, 1, 1), + Node::new(37, 1, 0), + Node::new(5, 2, 0), + Node::new(5, 1, 2), + Node::new(5, 0, 0), + Node::new(5, 1, 1), + Node::new(36, 1, 0), + Node::new(4, 2, 0), + Node::new(4, 1, 2), + Node::new(4, 0, 0), + Node::new(4, 1, 1), + Node::new(35, 1, 0), + Node::new(3, 2, 0), + Node::new(3, 1, 2), + Node::new(3, 0, 0), + Node::new(3, 1, 1), + Node::new(34, 1, 0), + Node::new(2, 2, 0), + Node::new(2, 1, 2), + Node::new(2, 0, 0), + Node::new(2, 1, 1), + Node::new(33, 1, 0), + Node::new(1, 2, 0), + Node::new(1, 1, 2), + Node::new(1, 0, 0), + Node::new(32, 1, 0), + Node::new(0, 1, 0), + ], + [ + 0, 2, 4, 7, 9, 12, 14, 17, 19, 22, 24, 27, 29, 32, 34, 37, 39, 42, 44, 47, 49, 52, 54, 56, + ], + 3, + )), + AnyBitCircuit::B12(BitCircuit::new( + [ + Node::new(44, 0, 1), + Node::new(44, 1, 0), + Node::new(12, 0, 1), + Node::new(12, 1, 0), + Node::new(12, 0, 0), + Node::new(12, 1, 1), + Node::new(43, 1, 0), + Node::new(11, 2, 0), + Node::new(11, 1, 2), + Node::new(11, 0, 0), + Node::new(11, 1, 1), + Node::new(42, 1, 0), + Node::new(10, 1, 2), + Node::new(10, 2, 0), + Node::new(10, 0, 0), + Node::new(10, 1, 1), + Node::new(41, 0, 1), + Node::new(9, 2, 1), + Node::new(9, 0, 2), + Node::new(9, 0, 0), + Node::new(9, 1, 1), + Node::new(40, 1, 0), + Node::new(8, 2, 0), + Node::new(8, 1, 2), + Node::new(8, 0, 0), + Node::new(8, 1, 1), + Node::new(39, 1, 0), + Node::new(7, 1, 2), + Node::new(7, 2, 0), + Node::new(7, 0, 0), + Node::new(7, 1, 1), + Node::new(38, 0, 1), + Node::new(6, 0, 2), + Node::new(6, 2, 1), + Node::new(6, 0, 0), + Node::new(6, 1, 1), + Node::new(37, 0, 1), + Node::new(5, 0, 2), + Node::new(5, 2, 1), + Node::new(5, 0, 0), + Node::new(5, 1, 1), + Node::new(36, 0, 1), + Node::new(4, 2, 1), + Node::new(4, 0, 2), + Node::new(4, 0, 0), + Node::new(4, 1, 1), + Node::new(35, 1, 0), + Node::new(3, 1, 2), + Node::new(3, 2, 0), + Node::new(3, 0, 0), + Node::new(3, 1, 1), + Node::new(34, 0, 1), + Node::new(2, 0, 2), + Node::new(2, 2, 1), + Node::new(2, 0, 0), + Node::new(2, 1, 1), + Node::new(33, 0, 1), + Node::new(1, 2, 1), + Node::new(1, 0, 2), + Node::new(1, 0, 0), + Node::new(32, 1, 0), + Node::new(0, 1, 0), + ], + [ + 0, 2, 4, 7, 9, 12, 14, 17, 19, 22, 24, 27, 29, 32, 34, 37, 39, 42, 44, 47, 49, 52, 54, 57, 59, 61, + ], + 3, + )), + AnyBitCircuit::B13(BitCircuit::new( + [ + Node::new(45, 0, 1), + Node::new(45, 1, 0), + Node::new(13, 1, 0), + Node::new(13, 0, 1), + Node::new(13, 0, 0), + Node::new(13, 1, 1), + Node::new(44, 0, 1), + Node::new(12, 0, 2), + Node::new(12, 2, 1), + Node::new(12, 0, 0), + Node::new(12, 1, 1), + Node::new(43, 0, 1), + Node::new(11, 0, 2), + Node::new(11, 2, 1), + Node::new(11, 0, 0), + Node::new(11, 1, 1), + Node::new(42, 0, 1), + Node::new(10, 2, 1), + Node::new(10, 0, 2), + Node::new(10, 0, 0), + Node::new(10, 1, 1), + Node::new(41, 1, 0), + Node::new(9, 2, 0), + Node::new(9, 1, 2), + Node::new(9, 0, 0), + Node::new(9, 1, 1), + Node::new(40, 1, 0), + Node::new(8, 1, 2), + Node::new(8, 2, 0), + Node::new(8, 0, 0), + Node::new(8, 1, 1), + Node::new(39, 0, 1), + Node::new(7, 2, 1), + Node::new(7, 0, 2), + Node::new(7, 0, 0), + Node::new(7, 1, 1), + Node::new(38, 1, 0), + Node::new(6, 1, 2), + Node::new(6, 2, 0), + Node::new(6, 0, 0), + Node::new(6, 1, 1), + Node::new(37, 0, 1), + Node::new(5, 0, 2), + Node::new(5, 2, 1), + Node::new(5, 0, 0), + Node::new(5, 1, 1), + Node::new(36, 0, 1), + Node::new(4, 2, 1), + Node::new(4, 0, 2), + Node::new(4, 0, 0), + Node::new(4, 1, 1), + Node::new(35, 1, 0), + Node::new(3, 2, 0), + Node::new(3, 1, 2), + Node::new(3, 0, 0), + Node::new(3, 1, 1), + Node::new(34, 1, 0), + Node::new(2, 2, 0), + Node::new(2, 1, 2), + Node::new(2, 0, 0), + Node::new(2, 1, 1), + Node::new(33, 1, 0), + Node::new(1, 2, 0), + Node::new(1, 1, 2), + Node::new(1, 0, 0), + Node::new(32, 1, 0), + Node::new(0, 1, 0), + ], + [ + 0, 2, 4, 7, 9, 12, 14, 17, 19, 22, 24, 27, 29, 32, 34, 37, 39, 42, 44, 47, 49, 52, 54, 57, 59, 62, 64, 66, + ], + 3, + )), + AnyBitCircuit::B14(BitCircuit::new( + [ + Node::new(46, 1, 0), + Node::new(46, 0, 1), + Node::new(14, 1, 0), + Node::new(14, 0, 1), + Node::new(14, 0, 0), + Node::new(14, 1, 1), + Node::new(45, 1, 0), + Node::new(13, 1, 2), + Node::new(13, 2, 0), + Node::new(13, 0, 0), + Node::new(13, 1, 1), + Node::new(44, 0, 1), + Node::new(12, 2, 1), + Node::new(12, 0, 2), + Node::new(12, 0, 0), + Node::new(12, 1, 1), + Node::new(43, 1, 0), + Node::new(11, 2, 0), + Node::new(11, 1, 2), + Node::new(11, 0, 0), + Node::new(11, 1, 1), + Node::new(42, 1, 0), + Node::new(10, 2, 0), + Node::new(10, 1, 2), + Node::new(10, 0, 0), + Node::new(10, 1, 1), + Node::new(41, 1, 0), + Node::new(9, 2, 0), + Node::new(9, 1, 2), + Node::new(9, 0, 0), + Node::new(9, 1, 1), + Node::new(40, 1, 0), + Node::new(8, 2, 0), + Node::new(8, 1, 2), + Node::new(8, 0, 0), + Node::new(8, 1, 1), + Node::new(39, 1, 0), + Node::new(7, 1, 2), + Node::new(7, 2, 0), + Node::new(7, 0, 0), + Node::new(7, 1, 1), + Node::new(38, 0, 1), + Node::new(6, 0, 2), + Node::new(6, 2, 1), + Node::new(6, 0, 0), + Node::new(6, 1, 1), + Node::new(37, 0, 1), + Node::new(5, 0, 2), + Node::new(5, 2, 1), + Node::new(5, 0, 0), + Node::new(5, 1, 1), + Node::new(36, 0, 1), + Node::new(4, 0, 2), + Node::new(4, 2, 1), + Node::new(4, 0, 0), + Node::new(4, 1, 1), + Node::new(35, 0, 1), + Node::new(3, 0, 2), + Node::new(3, 2, 1), + Node::new(3, 0, 0), + Node::new(3, 1, 1), + Node::new(34, 0, 1), + Node::new(2, 0, 2), + Node::new(2, 2, 1), + Node::new(2, 0, 0), + Node::new(2, 1, 1), + Node::new(33, 0, 1), + Node::new(1, 2, 1), + Node::new(1, 0, 2), + Node::new(1, 0, 0), + Node::new(32, 1, 0), + Node::new(0, 1, 0), + ], + [ + 0, 2, 4, 7, 9, 12, 14, 17, 19, 22, 24, 27, 29, 32, 34, 37, 39, 42, 44, 47, 49, 52, 54, 57, 59, 62, 64, 67, 69, 71, + ], + 3, + )), + AnyBitCircuit::B15(BitCircuit::new( + [ + Node::new(47, 1, 0), + Node::new(47, 0, 1), + Node::new(15, 1, 0), + Node::new(15, 0, 1), + Node::new(15, 0, 0), + Node::new(15, 1, 1), + Node::new(46, 1, 0), + Node::new(14, 2, 0), + Node::new(14, 1, 2), + Node::new(14, 0, 0), + Node::new(14, 1, 1), + Node::new(45, 1, 0), + Node::new(13, 1, 2), + Node::new(13, 2, 0), + Node::new(13, 0, 0), + Node::new(13, 1, 1), + Node::new(44, 0, 1), + Node::new(12, 2, 1), + Node::new(12, 0, 2), + Node::new(12, 0, 0), + Node::new(12, 1, 1), + Node::new(43, 1, 0), + Node::new(11, 2, 0), + Node::new(11, 1, 2), + Node::new(11, 0, 0), + Node::new(11, 1, 1), + Node::new(42, 1, 0), + Node::new(10, 1, 2), + Node::new(10, 2, 0), + Node::new(10, 0, 0), + Node::new(10, 1, 1), + Node::new(41, 0, 1), + Node::new(9, 2, 1), + Node::new(9, 0, 2), + Node::new(9, 0, 0), + Node::new(9, 1, 1), + Node::new(40, 1, 0), + Node::new(8, 2, 0), + Node::new(8, 1, 2), + Node::new(8, 0, 0), + Node::new(8, 1, 1), + Node::new(39, 1, 0), + Node::new(7, 1, 2), + Node::new(7, 2, 0), + Node::new(7, 0, 0), + Node::new(7, 1, 1), + Node::new(38, 0, 1), + Node::new(6, 2, 1), + Node::new(6, 0, 2), + Node::new(6, 0, 0), + Node::new(6, 1, 1), + Node::new(37, 1, 0), + Node::new(5, 2, 0), + Node::new(5, 1, 2), + Node::new(5, 0, 0), + Node::new(5, 1, 1), + Node::new(36, 1, 0), + Node::new(4, 2, 0), + Node::new(4, 1, 2), + Node::new(4, 0, 0), + Node::new(4, 1, 1), + Node::new(35, 1, 0), + Node::new(3, 2, 0), + Node::new(3, 1, 2), + Node::new(3, 0, 0), + Node::new(3, 1, 1), + Node::new(34, 1, 0), + Node::new(2, 1, 2), + Node::new(2, 2, 0), + Node::new(2, 0, 0), + Node::new(2, 1, 1), + Node::new(33, 0, 1), + Node::new(1, 2, 1), + Node::new(1, 0, 2), + Node::new(1, 0, 0), + Node::new(32, 1, 0), + Node::new(0, 1, 0), + ], + [ + 0, 2, 4, 7, 9, 12, 14, 17, 19, 22, 24, 27, 29, 32, 34, 37, 39, 42, 44, 47, 49, 52, 54, 57, 59, 62, 64, 67, 69, 72, + 74, 76, + ], + 3, + )), + AnyBitCircuit::B16(BitCircuit::new( + [ + Node::new(48, 1, 0), + Node::new(48, 0, 1), + Node::new(16, 0, 1), + Node::new(16, 1, 0), + Node::new(16, 0, 0), + Node::new(16, 1, 1), + Node::new(47, 0, 1), + Node::new(15, 0, 2), + Node::new(15, 2, 1), + Node::new(15, 0, 0), + Node::new(15, 1, 1), + Node::new(46, 0, 1), + Node::new(14, 2, 1), + Node::new(14, 0, 2), + Node::new(14, 0, 0), + Node::new(14, 1, 1), + Node::new(45, 1, 0), + Node::new(13, 1, 2), + Node::new(13, 2, 0), + Node::new(13, 0, 0), + Node::new(13, 1, 1), + Node::new(44, 0, 1), + Node::new(12, 2, 1), + Node::new(12, 0, 2), + Node::new(12, 0, 0), + Node::new(12, 1, 1), + Node::new(43, 1, 0), + Node::new(11, 2, 0), + Node::new(11, 1, 2), + Node::new(11, 0, 0), + Node::new(11, 1, 1), + Node::new(42, 1, 0), + Node::new(10, 1, 2), + Node::new(10, 2, 0), + Node::new(10, 0, 0), + Node::new(10, 1, 1), + Node::new(41, 0, 1), + Node::new(9, 2, 1), + Node::new(9, 0, 2), + Node::new(9, 0, 0), + Node::new(9, 1, 1), + Node::new(40, 1, 0), + Node::new(8, 2, 0), + Node::new(8, 1, 2), + Node::new(8, 0, 0), + Node::new(8, 1, 1), + Node::new(39, 1, 0), + Node::new(7, 1, 2), + Node::new(7, 2, 0), + Node::new(7, 0, 0), + Node::new(7, 1, 1), + Node::new(38, 0, 1), + Node::new(6, 0, 2), + Node::new(6, 2, 1), + Node::new(6, 0, 0), + Node::new(6, 1, 1), + Node::new(37, 0, 1), + Node::new(5, 0, 2), + Node::new(5, 2, 1), + Node::new(5, 0, 0), + Node::new(5, 1, 1), + Node::new(36, 0, 1), + Node::new(4, 0, 2), + Node::new(4, 2, 1), + Node::new(4, 0, 0), + Node::new(4, 1, 1), + Node::new(35, 0, 1), + Node::new(3, 2, 1), + Node::new(3, 0, 2), + Node::new(3, 0, 0), + Node::new(3, 1, 1), + Node::new(34, 1, 0), + Node::new(2, 2, 0), + Node::new(2, 1, 2), + Node::new(2, 0, 0), + Node::new(2, 1, 1), + Node::new(33, 1, 0), + Node::new(1, 2, 0), + Node::new(1, 1, 2), + Node::new(1, 0, 0), + Node::new(32, 1, 0), + Node::new(0, 1, 0), + ], + [ + 0, 2, 4, 7, 9, 12, 14, 17, 19, 22, 24, 27, 29, 32, 34, 37, 39, 42, 44, 47, 49, 52, 54, 57, 59, 62, 64, 67, 69, 72, + 74, 77, 79, 81, + ], + 3, + )), + AnyBitCircuit::B17(BitCircuit::new( + [ + Node::new(49, 1, 0), + Node::new(49, 0, 1), + Node::new(17, 1, 0), + Node::new(17, 0, 1), + Node::new(17, 0, 0), + Node::new(17, 1, 1), + Node::new(48, 1, 0), + Node::new(16, 1, 2), + Node::new(16, 2, 0), + Node::new(16, 0, 0), + Node::new(16, 1, 1), + Node::new(47, 0, 1), + Node::new(15, 0, 2), + Node::new(15, 2, 1), + Node::new(15, 0, 0), + Node::new(15, 1, 1), + Node::new(46, 0, 1), + Node::new(14, 0, 2), + Node::new(14, 2, 1), + Node::new(14, 0, 0), + Node::new(14, 1, 1), + Node::new(45, 0, 1), + Node::new(13, 2, 1), + Node::new(13, 0, 2), + Node::new(13, 0, 0), + Node::new(13, 1, 1), + Node::new(44, 1, 0), + Node::new(12, 1, 2), + Node::new(12, 2, 0), + Node::new(12, 0, 0), + Node::new(12, 1, 1), + Node::new(43, 0, 1), + Node::new(11, 2, 1), + Node::new(11, 0, 2), + Node::new(11, 0, 0), + Node::new(11, 1, 1), + Node::new(42, 1, 0), + Node::new(10, 1, 2), + Node::new(10, 2, 0), + Node::new(10, 0, 0), + Node::new(10, 1, 1), + Node::new(41, 0, 1), + Node::new(9, 2, 1), + Node::new(9, 0, 2), + Node::new(9, 0, 0), + Node::new(9, 1, 1), + Node::new(40, 1, 0), + Node::new(8, 2, 0), + Node::new(8, 1, 2), + Node::new(8, 0, 0), + Node::new(8, 1, 1), + Node::new(39, 1, 0), + Node::new(7, 2, 0), + Node::new(7, 1, 2), + Node::new(7, 0, 0), + Node::new(7, 1, 1), + Node::new(38, 1, 0), + Node::new(6, 2, 0), + Node::new(6, 1, 2), + Node::new(6, 0, 0), + Node::new(6, 1, 1), + Node::new(37, 1, 0), + Node::new(5, 1, 2), + Node::new(5, 2, 0), + Node::new(5, 0, 0), + Node::new(5, 1, 1), + Node::new(36, 0, 1), + Node::new(4, 2, 1), + Node::new(4, 0, 2), + Node::new(4, 0, 0), + Node::new(4, 1, 1), + Node::new(35, 1, 0), + Node::new(3, 1, 2), + Node::new(3, 2, 0), + Node::new(3, 0, 0), + Node::new(3, 1, 1), + Node::new(34, 0, 1), + Node::new(2, 2, 1), + Node::new(2, 0, 2), + Node::new(2, 0, 0), + Node::new(2, 1, 1), + Node::new(33, 1, 0), + Node::new(1, 2, 0), + Node::new(1, 1, 2), + Node::new(1, 0, 0), + Node::new(32, 1, 0), + Node::new(0, 1, 0), + ], + [ + 0, 2, 4, 7, 9, 12, 14, 17, 19, 22, 24, 27, 29, 32, 34, 37, 39, 42, 44, 47, 49, 52, 54, 57, 59, 62, 64, 67, 69, 72, + 74, 77, 79, 82, 84, 86, + ], + 3, + )), + AnyBitCircuit::B18(BitCircuit::new( + [ + Node::new(50, 0, 1), + Node::new(50, 1, 0), + Node::new(18, 0, 1), + Node::new(18, 1, 0), + Node::new(18, 0, 0), + Node::new(18, 1, 1), + Node::new(49, 1, 0), + Node::new(17, 1, 2), + Node::new(17, 2, 0), + Node::new(17, 0, 0), + Node::new(17, 1, 1), + Node::new(48, 0, 1), + Node::new(16, 0, 2), + Node::new(16, 2, 1), + Node::new(16, 0, 0), + Node::new(16, 1, 1), + Node::new(47, 0, 1), + Node::new(15, 0, 2), + Node::new(15, 2, 1), + Node::new(15, 0, 0), + Node::new(15, 1, 1), + Node::new(46, 0, 1), + Node::new(14, 0, 2), + Node::new(14, 2, 1), + Node::new(14, 0, 0), + Node::new(14, 1, 1), + Node::new(45, 0, 1), + Node::new(13, 0, 2), + Node::new(13, 2, 1), + Node::new(13, 0, 0), + Node::new(13, 1, 1), + Node::new(44, 0, 1), + Node::new(12, 2, 1), + Node::new(12, 0, 2), + Node::new(12, 0, 0), + Node::new(12, 1, 1), + Node::new(43, 1, 0), + Node::new(11, 2, 0), + Node::new(11, 1, 2), + Node::new(11, 0, 0), + Node::new(11, 1, 1), + Node::new(42, 1, 0), + Node::new(10, 1, 2), + Node::new(10, 2, 0), + Node::new(10, 0, 0), + Node::new(10, 1, 1), + Node::new(41, 0, 1), + Node::new(9, 0, 2), + Node::new(9, 2, 1), + Node::new(9, 0, 0), + Node::new(9, 1, 1), + Node::new(40, 0, 1), + Node::new(8, 2, 1), + Node::new(8, 0, 2), + Node::new(8, 0, 0), + Node::new(8, 1, 1), + Node::new(39, 1, 0), + Node::new(7, 1, 2), + Node::new(7, 2, 0), + Node::new(7, 0, 0), + Node::new(7, 1, 1), + Node::new(38, 0, 1), + Node::new(6, 0, 2), + Node::new(6, 2, 1), + Node::new(6, 0, 0), + Node::new(6, 1, 1), + Node::new(37, 0, 1), + Node::new(5, 0, 2), + Node::new(5, 2, 1), + Node::new(5, 0, 0), + Node::new(5, 1, 1), + Node::new(36, 0, 1), + Node::new(4, 0, 2), + Node::new(4, 2, 1), + Node::new(4, 0, 0), + Node::new(4, 1, 1), + Node::new(35, 0, 1), + Node::new(3, 0, 2), + Node::new(3, 2, 1), + Node::new(3, 0, 0), + Node::new(3, 1, 1), + Node::new(34, 0, 1), + Node::new(2, 0, 2), + Node::new(2, 2, 1), + Node::new(2, 0, 0), + Node::new(2, 1, 1), + Node::new(33, 0, 1), + Node::new(1, 2, 1), + Node::new(1, 0, 2), + Node::new(1, 0, 0), + Node::new(32, 1, 0), + Node::new(0, 1, 0), + ], + [ + 0, 2, 4, 7, 9, 12, 14, 17, 19, 22, 24, 27, 29, 32, 34, 37, 39, 42, 44, 47, 49, 52, 54, 57, 59, 62, 64, 67, 69, 72, + 74, 77, 79, 82, 84, 87, 89, 91, + ], + 3, + )), + AnyBitCircuit::B19(BitCircuit::new( + [ + Node::new(51, 1, 0), + Node::new(51, 0, 1), + Node::new(19, 0, 1), + Node::new(19, 1, 0), + Node::new(19, 0, 0), + Node::new(19, 1, 1), + Node::new(50, 0, 1), + Node::new(18, 2, 1), + Node::new(18, 0, 2), + Node::new(18, 0, 0), + Node::new(18, 1, 1), + Node::new(49, 1, 0), + Node::new(17, 1, 2), + Node::new(17, 2, 0), + Node::new(17, 0, 0), + Node::new(17, 1, 1), + Node::new(48, 0, 1), + Node::new(16, 2, 1), + Node::new(16, 0, 2), + Node::new(16, 0, 0), + Node::new(16, 1, 1), + Node::new(47, 1, 0), + Node::new(15, 2, 0), + Node::new(15, 1, 2), + Node::new(15, 0, 0), + Node::new(15, 1, 1), + Node::new(46, 1, 0), + Node::new(14, 2, 0), + Node::new(14, 1, 2), + Node::new(14, 0, 0), + Node::new(14, 1, 1), + Node::new(45, 1, 0), + Node::new(13, 2, 0), + Node::new(13, 1, 2), + Node::new(13, 0, 0), + Node::new(13, 1, 1), + Node::new(44, 1, 0), + Node::new(12, 1, 2), + Node::new(12, 2, 0), + Node::new(12, 0, 0), + Node::new(12, 1, 1), + Node::new(43, 0, 1), + Node::new(11, 0, 2), + Node::new(11, 2, 1), + Node::new(11, 0, 0), + Node::new(11, 1, 1), + Node::new(42, 0, 1), + Node::new(10, 0, 2), + Node::new(10, 2, 1), + Node::new(10, 0, 0), + Node::new(10, 1, 1), + Node::new(41, 0, 1), + Node::new(9, 2, 1), + Node::new(9, 0, 2), + Node::new(9, 0, 0), + Node::new(9, 1, 1), + Node::new(40, 1, 0), + Node::new(8, 2, 0), + Node::new(8, 1, 2), + Node::new(8, 0, 0), + Node::new(8, 1, 1), + Node::new(39, 1, 0), + Node::new(7, 2, 0), + Node::new(7, 1, 2), + Node::new(7, 0, 0), + Node::new(7, 1, 1), + Node::new(38, 1, 0), + Node::new(6, 1, 2), + Node::new(6, 2, 0), + Node::new(6, 0, 0), + Node::new(6, 1, 1), + Node::new(37, 0, 1), + Node::new(5, 0, 2), + Node::new(5, 2, 1), + Node::new(5, 0, 0), + Node::new(5, 1, 1), + Node::new(36, 0, 1), + Node::new(4, 0, 2), + Node::new(4, 2, 1), + Node::new(4, 0, 0), + Node::new(4, 1, 1), + Node::new(35, 0, 1), + Node::new(3, 2, 1), + Node::new(3, 0, 2), + Node::new(3, 0, 0), + Node::new(3, 1, 1), + Node::new(34, 1, 0), + Node::new(2, 1, 2), + Node::new(2, 2, 0), + Node::new(2, 0, 0), + Node::new(2, 1, 1), + Node::new(33, 0, 1), + Node::new(1, 2, 1), + Node::new(1, 0, 2), + Node::new(1, 0, 0), + Node::new(32, 1, 0), + Node::new(0, 1, 0), + ], + [ + 0, 2, 4, 7, 9, 12, 14, 17, 19, 22, 24, 27, 29, 32, 34, 37, 39, 42, 44, 47, 49, 52, 54, 57, 59, 62, 64, 67, 69, 72, + 74, 77, 79, 82, 84, 87, 89, 92, 94, 96, + ], + 3, + )), + AnyBitCircuit::B20(BitCircuit::new( + [ + Node::new(52, 0, 1), + Node::new(52, 1, 0), + Node::new(20, 1, 0), + Node::new(20, 0, 1), + Node::new(20, 0, 0), + Node::new(20, 1, 1), + Node::new(51, 0, 1), + Node::new(19, 2, 1), + Node::new(19, 0, 2), + Node::new(19, 0, 0), + Node::new(19, 1, 1), + Node::new(50, 1, 0), + Node::new(18, 2, 0), + Node::new(18, 1, 2), + Node::new(18, 0, 0), + Node::new(18, 1, 1), + Node::new(49, 1, 0), + Node::new(17, 1, 2), + Node::new(17, 2, 0), + Node::new(17, 0, 0), + Node::new(17, 1, 1), + Node::new(48, 0, 1), + Node::new(16, 0, 2), + Node::new(16, 2, 1), + Node::new(16, 0, 0), + Node::new(16, 1, 1), + Node::new(47, 0, 1), + Node::new(15, 0, 2), + Node::new(15, 2, 1), + Node::new(15, 0, 0), + Node::new(15, 1, 1), + Node::new(46, 0, 1), + Node::new(14, 2, 1), + Node::new(14, 0, 2), + Node::new(14, 0, 0), + Node::new(14, 1, 1), + Node::new(45, 1, 0), + Node::new(13, 2, 0), + Node::new(13, 1, 2), + Node::new(13, 0, 0), + Node::new(13, 1, 1), + Node::new(44, 1, 0), + Node::new(12, 2, 0), + Node::new(12, 1, 2), + Node::new(12, 0, 0), + Node::new(12, 1, 1), + Node::new(43, 1, 0), + Node::new(11, 1, 2), + Node::new(11, 2, 0), + Node::new(11, 0, 0), + Node::new(11, 1, 1), + Node::new(42, 0, 1), + Node::new(10, 2, 1), + Node::new(10, 0, 2), + Node::new(10, 0, 0), + Node::new(10, 1, 1), + Node::new(41, 1, 0), + Node::new(9, 1, 2), + Node::new(9, 2, 0), + Node::new(9, 0, 0), + Node::new(9, 1, 1), + Node::new(40, 0, 1), + Node::new(8, 2, 1), + Node::new(8, 0, 2), + Node::new(8, 0, 0), + Node::new(8, 1, 1), + Node::new(39, 1, 0), + Node::new(7, 1, 2), + Node::new(7, 2, 0), + Node::new(7, 0, 0), + Node::new(7, 1, 1), + Node::new(38, 0, 1), + Node::new(6, 0, 2), + Node::new(6, 2, 1), + Node::new(6, 0, 0), + Node::new(6, 1, 1), + Node::new(37, 0, 1), + Node::new(5, 2, 1), + Node::new(5, 0, 2), + Node::new(5, 0, 0), + Node::new(5, 1, 1), + Node::new(36, 1, 0), + Node::new(4, 1, 2), + Node::new(4, 2, 0), + Node::new(4, 0, 0), + Node::new(4, 1, 1), + Node::new(35, 0, 1), + Node::new(3, 0, 2), + Node::new(3, 2, 1), + Node::new(3, 0, 0), + Node::new(3, 1, 1), + Node::new(34, 0, 1), + Node::new(2, 0, 2), + Node::new(2, 2, 1), + Node::new(2, 0, 0), + Node::new(2, 1, 1), + Node::new(33, 0, 1), + Node::new(1, 2, 1), + Node::new(1, 0, 2), + Node::new(1, 0, 0), + Node::new(32, 1, 0), + Node::new(0, 1, 0), + ], + [ + 0, 2, 4, 7, 9, 12, 14, 17, 19, 22, 24, 27, 29, 32, 34, 37, 39, 42, 44, 47, 49, 52, 54, 57, 59, 62, 64, 67, 69, 72, + 74, 77, 79, 82, 84, 87, 89, 92, 94, 97, 99, 101, + ], + 3, + )), + AnyBitCircuit::B21(BitCircuit::new( + [ + Node::new(53, 1, 0), + Node::new(53, 0, 1), + Node::new(21, 0, 1), + Node::new(21, 1, 0), + Node::new(21, 0, 0), + Node::new(21, 1, 1), + Node::new(52, 0, 1), + Node::new(20, 0, 2), + Node::new(20, 2, 1), + Node::new(20, 0, 0), + Node::new(20, 1, 1), + Node::new(51, 0, 1), + Node::new(19, 2, 1), + Node::new(19, 0, 2), + Node::new(19, 0, 0), + Node::new(19, 1, 1), + Node::new(50, 1, 0), + Node::new(18, 1, 2), + Node::new(18, 2, 0), + Node::new(18, 0, 0), + Node::new(18, 1, 1), + Node::new(49, 0, 1), + Node::new(17, 0, 2), + Node::new(17, 2, 1), + Node::new(17, 0, 0), + Node::new(17, 1, 1), + Node::new(48, 0, 1), + Node::new(16, 2, 1), + Node::new(16, 0, 2), + Node::new(16, 0, 0), + Node::new(16, 1, 1), + Node::new(47, 1, 0), + Node::new(15, 2, 0), + Node::new(15, 1, 2), + Node::new(15, 0, 0), + Node::new(15, 1, 1), + Node::new(46, 1, 0), + Node::new(14, 1, 2), + Node::new(14, 2, 0), + Node::new(14, 0, 0), + Node::new(14, 1, 1), + Node::new(45, 0, 1), + Node::new(13, 0, 2), + Node::new(13, 2, 1), + Node::new(13, 0, 0), + Node::new(13, 1, 1), + Node::new(44, 0, 1), + Node::new(12, 0, 2), + Node::new(12, 2, 1), + Node::new(12, 0, 0), + Node::new(12, 1, 1), + Node::new(43, 0, 1), + Node::new(11, 0, 2), + Node::new(11, 2, 1), + Node::new(11, 0, 0), + Node::new(11, 1, 1), + Node::new(42, 0, 1), + Node::new(10, 2, 1), + Node::new(10, 0, 2), + Node::new(10, 0, 0), + Node::new(10, 1, 1), + Node::new(41, 1, 0), + Node::new(9, 1, 2), + Node::new(9, 2, 0), + Node::new(9, 0, 0), + Node::new(9, 1, 1), + Node::new(40, 0, 1), + Node::new(8, 0, 2), + Node::new(8, 2, 1), + Node::new(8, 0, 0), + Node::new(8, 1, 1), + Node::new(39, 0, 1), + Node::new(7, 0, 2), + Node::new(7, 2, 1), + Node::new(7, 0, 0), + Node::new(7, 1, 1), + Node::new(38, 0, 1), + Node::new(6, 2, 1), + Node::new(6, 0, 2), + Node::new(6, 0, 0), + Node::new(6, 1, 1), + Node::new(37, 1, 0), + Node::new(5, 2, 0), + Node::new(5, 1, 2), + Node::new(5, 0, 0), + Node::new(5, 1, 1), + Node::new(36, 1, 0), + Node::new(4, 2, 0), + Node::new(4, 1, 2), + Node::new(4, 0, 0), + Node::new(4, 1, 1), + Node::new(35, 1, 0), + Node::new(3, 1, 2), + Node::new(3, 2, 0), + Node::new(3, 0, 0), + Node::new(3, 1, 1), + Node::new(34, 0, 1), + Node::new(2, 2, 1), + Node::new(2, 0, 2), + Node::new(2, 0, 0), + Node::new(2, 1, 1), + Node::new(33, 1, 0), + Node::new(1, 2, 0), + Node::new(1, 1, 2), + Node::new(1, 0, 0), + Node::new(32, 1, 0), + Node::new(0, 1, 0), + ], + [ + 0, 2, 4, 7, 9, 12, 14, 17, 19, 22, 24, 27, 29, 32, 34, 37, 39, 42, 44, 47, 49, 52, 54, 57, 59, 62, 64, 67, 69, 72, + 74, 77, 79, 82, 84, 87, 89, 92, 94, 97, 99, 102, 104, 106, + ], + 3, + )), + AnyBitCircuit::B22(BitCircuit::new( + [ + Node::new(54, 0, 1), + Node::new(54, 1, 0), + Node::new(22, 0, 1), + Node::new(22, 1, 0), + Node::new(22, 0, 0), + Node::new(22, 1, 1), + Node::new(53, 1, 0), + Node::new(21, 2, 0), + Node::new(21, 1, 2), + Node::new(21, 0, 0), + Node::new(21, 1, 1), + Node::new(52, 1, 0), + Node::new(20, 2, 0), + Node::new(20, 1, 2), + Node::new(20, 0, 0), + Node::new(20, 1, 1), + Node::new(51, 1, 0), + Node::new(19, 2, 0), + Node::new(19, 1, 2), + Node::new(19, 0, 0), + Node::new(19, 1, 1), + Node::new(50, 1, 0), + Node::new(18, 1, 2), + Node::new(18, 2, 0), + Node::new(18, 0, 0), + Node::new(18, 1, 1), + Node::new(49, 0, 1), + Node::new(17, 2, 1), + Node::new(17, 0, 2), + Node::new(17, 0, 0), + Node::new(17, 1, 1), + Node::new(48, 1, 0), + Node::new(16, 2, 0), + Node::new(16, 1, 2), + Node::new(16, 0, 0), + Node::new(16, 1, 1), + Node::new(47, 1, 0), + Node::new(15, 1, 2), + Node::new(15, 2, 0), + Node::new(15, 0, 0), + Node::new(15, 1, 1), + Node::new(46, 0, 1), + Node::new(14, 0, 2), + Node::new(14, 2, 1), + Node::new(14, 0, 0), + Node::new(14, 1, 1), + Node::new(45, 0, 1), + Node::new(13, 0, 2), + Node::new(13, 2, 1), + Node::new(13, 0, 0), + Node::new(13, 1, 1), + Node::new(44, 0, 1), + Node::new(12, 2, 1), + Node::new(12, 0, 2), + Node::new(12, 0, 0), + Node::new(12, 1, 1), + Node::new(43, 1, 0), + Node::new(11, 2, 0), + Node::new(11, 1, 2), + Node::new(11, 0, 0), + Node::new(11, 1, 1), + Node::new(42, 1, 0), + Node::new(10, 2, 0), + Node::new(10, 1, 2), + Node::new(10, 0, 0), + Node::new(10, 1, 1), + Node::new(41, 1, 0), + Node::new(9, 1, 2), + Node::new(9, 2, 0), + Node::new(9, 0, 0), + Node::new(9, 1, 1), + Node::new(40, 0, 1), + Node::new(8, 0, 2), + Node::new(8, 2, 1), + Node::new(8, 0, 0), + Node::new(8, 1, 1), + Node::new(39, 0, 1), + Node::new(7, 2, 1), + Node::new(7, 0, 2), + Node::new(7, 0, 0), + Node::new(7, 1, 1), + Node::new(38, 1, 0), + Node::new(6, 2, 0), + Node::new(6, 1, 2), + Node::new(6, 0, 0), + Node::new(6, 1, 1), + Node::new(37, 1, 0), + Node::new(5, 2, 0), + Node::new(5, 1, 2), + Node::new(5, 0, 0), + Node::new(5, 1, 1), + Node::new(36, 1, 0), + Node::new(4, 2, 0), + Node::new(4, 1, 2), + Node::new(4, 0, 0), + Node::new(4, 1, 1), + Node::new(35, 1, 0), + Node::new(3, 2, 0), + Node::new(3, 1, 2), + Node::new(3, 0, 0), + Node::new(3, 1, 1), + Node::new(34, 1, 0), + Node::new(2, 2, 0), + Node::new(2, 1, 2), + Node::new(2, 0, 0), + Node::new(2, 1, 1), + Node::new(33, 1, 0), + Node::new(1, 2, 0), + Node::new(1, 1, 2), + Node::new(1, 0, 0), + Node::new(32, 1, 0), + Node::new(0, 1, 0), + ], + [ + 0, 2, 4, 7, 9, 12, 14, 17, 19, 22, 24, 27, 29, 32, 34, 37, 39, 42, 44, 47, 49, 52, 54, 57, 59, 62, 64, 67, 69, 72, + 74, 77, 79, 82, 84, 87, 89, 92, 94, 97, 99, 102, 104, 107, 109, 111, + ], + 3, + )), + AnyBitCircuit::B23(BitCircuit::new( + [ + Node::new(55, 0, 1), + Node::new(55, 1, 0), + Node::new(23, 1, 0), + Node::new(23, 0, 1), + Node::new(23, 0, 0), + Node::new(23, 1, 1), + Node::new(54, 0, 1), + Node::new(22, 2, 1), + Node::new(22, 0, 2), + Node::new(22, 0, 0), + Node::new(22, 1, 1), + Node::new(53, 1, 0), + Node::new(21, 1, 2), + Node::new(21, 2, 0), + Node::new(21, 0, 0), + Node::new(21, 1, 1), + Node::new(52, 0, 1), + Node::new(20, 2, 1), + Node::new(20, 0, 2), + Node::new(20, 0, 0), + Node::new(20, 1, 1), + Node::new(51, 1, 0), + Node::new(19, 1, 2), + Node::new(19, 2, 0), + Node::new(19, 0, 0), + Node::new(19, 1, 1), + Node::new(50, 0, 1), + Node::new(18, 2, 1), + Node::new(18, 0, 2), + Node::new(18, 0, 0), + Node::new(18, 1, 1), + Node::new(49, 1, 0), + Node::new(17, 2, 0), + Node::new(17, 1, 2), + Node::new(17, 0, 0), + Node::new(17, 1, 1), + Node::new(48, 1, 0), + Node::new(16, 2, 0), + Node::new(16, 1, 2), + Node::new(16, 0, 0), + Node::new(16, 1, 1), + Node::new(47, 1, 0), + Node::new(15, 1, 2), + Node::new(15, 2, 0), + Node::new(15, 0, 0), + Node::new(15, 1, 1), + Node::new(46, 0, 1), + Node::new(14, 2, 1), + Node::new(14, 0, 2), + Node::new(14, 0, 0), + Node::new(14, 1, 1), + Node::new(45, 1, 0), + Node::new(13, 1, 2), + Node::new(13, 2, 0), + Node::new(13, 0, 0), + Node::new(13, 1, 1), + Node::new(44, 0, 1), + Node::new(12, 2, 1), + Node::new(12, 0, 2), + Node::new(12, 0, 0), + Node::new(12, 1, 1), + Node::new(43, 1, 0), + Node::new(11, 2, 0), + Node::new(11, 1, 2), + Node::new(11, 0, 0), + Node::new(11, 1, 1), + Node::new(42, 1, 0), + Node::new(10, 1, 2), + Node::new(10, 2, 0), + Node::new(10, 0, 0), + Node::new(10, 1, 1), + Node::new(41, 0, 1), + Node::new(9, 0, 2), + Node::new(9, 2, 1), + Node::new(9, 0, 0), + Node::new(9, 1, 1), + Node::new(40, 0, 1), + Node::new(8, 2, 1), + Node::new(8, 0, 2), + Node::new(8, 0, 0), + Node::new(8, 1, 1), + Node::new(39, 1, 0), + Node::new(7, 1, 2), + Node::new(7, 2, 0), + Node::new(7, 0, 0), + Node::new(7, 1, 1), + Node::new(38, 0, 1), + Node::new(6, 2, 1), + Node::new(6, 0, 2), + Node::new(6, 0, 0), + Node::new(6, 1, 1), + Node::new(37, 1, 0), + Node::new(5, 2, 0), + Node::new(5, 1, 2), + Node::new(5, 0, 0), + Node::new(5, 1, 1), + Node::new(36, 1, 0), + Node::new(4, 1, 2), + Node::new(4, 2, 0), + Node::new(4, 0, 0), + Node::new(4, 1, 1), + Node::new(35, 0, 1), + Node::new(3, 2, 1), + Node::new(3, 0, 2), + Node::new(3, 0, 0), + Node::new(3, 1, 1), + Node::new(34, 1, 0), + Node::new(2, 1, 2), + Node::new(2, 2, 0), + Node::new(2, 0, 0), + Node::new(2, 1, 1), + Node::new(33, 0, 1), + Node::new(1, 2, 1), + Node::new(1, 0, 2), + Node::new(1, 0, 0), + Node::new(32, 1, 0), + Node::new(0, 1, 0), + ], + [ + 0, 2, 4, 7, 9, 12, 14, 17, 19, 22, 24, 27, 29, 32, 34, 37, 39, 42, 44, 47, 49, 52, 54, 57, 59, 62, 64, 67, 69, 72, + 74, 77, 79, 82, 84, 87, 89, 92, 94, 97, 99, 102, 104, 107, 109, 112, 114, 116, + ], + 3, + )), + AnyBitCircuit::B24(BitCircuit::new( + [ + Node::new(56, 0, 1), + Node::new(56, 1, 0), + Node::new(24, 0, 1), + Node::new(24, 1, 0), + Node::new(24, 0, 0), + Node::new(24, 1, 1), + Node::new(55, 1, 0), + Node::new(23, 1, 2), + Node::new(23, 2, 0), + Node::new(23, 0, 0), + Node::new(23, 1, 1), + Node::new(54, 0, 1), + Node::new(22, 0, 2), + Node::new(22, 2, 1), + Node::new(22, 0, 0), + Node::new(22, 1, 1), + Node::new(53, 0, 1), + Node::new(21, 0, 2), + Node::new(21, 2, 1), + Node::new(21, 0, 0), + Node::new(21, 1, 1), + Node::new(52, 0, 1), + Node::new(20, 0, 2), + Node::new(20, 2, 1), + Node::new(20, 0, 0), + Node::new(20, 1, 1), + Node::new(51, 0, 1), + Node::new(19, 0, 2), + Node::new(19, 2, 1), + Node::new(19, 0, 0), + Node::new(19, 1, 1), + Node::new(50, 0, 1), + Node::new(18, 2, 1), + Node::new(18, 0, 2), + Node::new(18, 0, 0), + Node::new(18, 1, 1), + Node::new(49, 1, 0), + Node::new(17, 2, 0), + Node::new(17, 1, 2), + Node::new(17, 0, 0), + Node::new(17, 1, 1), + Node::new(48, 1, 0), + Node::new(16, 2, 0), + Node::new(16, 1, 2), + Node::new(16, 0, 0), + Node::new(16, 1, 1), + Node::new(47, 1, 0), + Node::new(15, 1, 2), + Node::new(15, 2, 0), + Node::new(15, 0, 0), + Node::new(15, 1, 1), + Node::new(46, 0, 1), + Node::new(14, 2, 1), + Node::new(14, 0, 2), + Node::new(14, 0, 0), + Node::new(14, 1, 1), + Node::new(45, 1, 0), + Node::new(13, 2, 0), + Node::new(13, 1, 2), + Node::new(13, 0, 0), + Node::new(13, 1, 1), + Node::new(44, 1, 0), + Node::new(12, 1, 2), + Node::new(12, 2, 0), + Node::new(12, 0, 0), + Node::new(12, 1, 1), + Node::new(43, 0, 1), + Node::new(11, 2, 1), + Node::new(11, 0, 2), + Node::new(11, 0, 0), + Node::new(11, 1, 1), + Node::new(42, 1, 0), + Node::new(10, 1, 2), + Node::new(10, 2, 0), + Node::new(10, 0, 0), + Node::new(10, 1, 1), + Node::new(41, 0, 1), + Node::new(9, 2, 1), + Node::new(9, 0, 2), + Node::new(9, 0, 0), + Node::new(9, 1, 1), + Node::new(40, 1, 0), + Node::new(8, 1, 2), + Node::new(8, 2, 0), + Node::new(8, 0, 0), + Node::new(8, 1, 1), + Node::new(39, 0, 1), + Node::new(7, 2, 1), + Node::new(7, 0, 2), + Node::new(7, 0, 0), + Node::new(7, 1, 1), + Node::new(38, 1, 0), + Node::new(6, 2, 0), + Node::new(6, 1, 2), + Node::new(6, 0, 0), + Node::new(6, 1, 1), + Node::new(37, 1, 0), + Node::new(5, 1, 2), + Node::new(5, 2, 0), + Node::new(5, 0, 0), + Node::new(5, 1, 1), + Node::new(36, 0, 1), + Node::new(4, 0, 2), + Node::new(4, 2, 1), + Node::new(4, 0, 0), + Node::new(4, 1, 1), + Node::new(35, 0, 1), + Node::new(3, 0, 2), + Node::new(3, 2, 1), + Node::new(3, 0, 0), + Node::new(3, 1, 1), + Node::new(34, 0, 1), + Node::new(2, 0, 2), + Node::new(2, 2, 1), + Node::new(2, 0, 0), + Node::new(2, 1, 1), + Node::new(33, 0, 1), + Node::new(1, 2, 1), + Node::new(1, 0, 2), + Node::new(1, 0, 0), + Node::new(32, 1, 0), + Node::new(0, 1, 0), + ], + [ + 0, 2, 4, 7, 9, 12, 14, 17, 19, 22, 24, 27, 29, 32, 34, 37, 39, 42, 44, 47, 49, 52, 54, 57, 59, 62, 64, 67, 69, 72, + 74, 77, 79, 82, 84, 87, 89, 92, 94, 97, 99, 102, 104, 107, 109, 112, 114, 117, 119, 121, + ], + 3, + )), + AnyBitCircuit::B25(BitCircuit::new( + [ + Node::new(57, 0, 1), + Node::new(57, 1, 0), + Node::new(25, 0, 1), + Node::new(25, 1, 0), + Node::new(25, 0, 0), + Node::new(25, 1, 1), + Node::new(56, 1, 0), + Node::new(24, 1, 2), + Node::new(24, 2, 0), + Node::new(24, 0, 0), + Node::new(24, 1, 1), + Node::new(55, 0, 1), + Node::new(23, 2, 1), + Node::new(23, 0, 2), + Node::new(23, 0, 0), + Node::new(23, 1, 1), + Node::new(54, 1, 0), + Node::new(22, 2, 0), + Node::new(22, 1, 2), + Node::new(22, 0, 0), + Node::new(22, 1, 1), + Node::new(53, 1, 0), + Node::new(21, 2, 0), + Node::new(21, 1, 2), + Node::new(21, 0, 0), + Node::new(21, 1, 1), + Node::new(52, 1, 0), + Node::new(20, 2, 0), + Node::new(20, 1, 2), + Node::new(20, 0, 0), + Node::new(20, 1, 1), + Node::new(51, 1, 0), + Node::new(19, 2, 0), + Node::new(19, 1, 2), + Node::new(19, 0, 0), + Node::new(19, 1, 1), + Node::new(50, 1, 0), + Node::new(18, 2, 0), + Node::new(18, 1, 2), + Node::new(18, 0, 0), + Node::new(18, 1, 1), + Node::new(49, 1, 0), + Node::new(17, 1, 2), + Node::new(17, 2, 0), + Node::new(17, 0, 0), + Node::new(17, 1, 1), + Node::new(48, 0, 1), + Node::new(16, 0, 2), + Node::new(16, 2, 1), + Node::new(16, 0, 0), + Node::new(16, 1, 1), + Node::new(47, 0, 1), + Node::new(15, 2, 1), + Node::new(15, 0, 2), + Node::new(15, 0, 0), + Node::new(15, 1, 1), + Node::new(46, 1, 0), + Node::new(14, 1, 2), + Node::new(14, 2, 0), + Node::new(14, 0, 0), + Node::new(14, 1, 1), + Node::new(45, 0, 1), + Node::new(13, 2, 1), + Node::new(13, 0, 2), + Node::new(13, 0, 0), + Node::new(13, 1, 1), + Node::new(44, 1, 0), + Node::new(12, 2, 0), + Node::new(12, 1, 2), + Node::new(12, 0, 0), + Node::new(12, 1, 1), + Node::new(43, 1, 0), + Node::new(11, 2, 0), + Node::new(11, 1, 2), + Node::new(11, 0, 0), + Node::new(11, 1, 1), + Node::new(42, 1, 0), + Node::new(10, 2, 0), + Node::new(10, 1, 2), + Node::new(10, 0, 0), + Node::new(10, 1, 1), + Node::new(41, 1, 0), + Node::new(9, 1, 2), + Node::new(9, 2, 0), + Node::new(9, 0, 0), + Node::new(9, 1, 1), + Node::new(40, 0, 1), + Node::new(8, 2, 1), + Node::new(8, 0, 2), + Node::new(8, 0, 0), + Node::new(8, 1, 1), + Node::new(39, 1, 0), + Node::new(7, 2, 0), + Node::new(7, 1, 2), + Node::new(7, 0, 0), + Node::new(7, 1, 1), + Node::new(38, 1, 0), + Node::new(6, 1, 2), + Node::new(6, 2, 0), + Node::new(6, 0, 0), + Node::new(6, 1, 1), + Node::new(37, 0, 1), + Node::new(5, 2, 1), + Node::new(5, 0, 2), + Node::new(5, 0, 0), + Node::new(5, 1, 1), + Node::new(36, 1, 0), + Node::new(4, 2, 0), + Node::new(4, 1, 2), + Node::new(4, 0, 0), + Node::new(4, 1, 1), + Node::new(35, 1, 0), + Node::new(3, 2, 0), + Node::new(3, 1, 2), + Node::new(3, 0, 0), + Node::new(3, 1, 1), + Node::new(34, 1, 0), + Node::new(2, 1, 2), + Node::new(2, 2, 0), + Node::new(2, 0, 0), + Node::new(2, 1, 1), + Node::new(33, 0, 1), + Node::new(1, 2, 1), + Node::new(1, 0, 2), + Node::new(1, 0, 0), + Node::new(32, 1, 0), + Node::new(0, 1, 0), + ], + [ + 0, 2, 4, 7, 9, 12, 14, 17, 19, 22, 24, 27, 29, 32, 34, 37, 39, 42, 44, 47, 49, 52, 54, 57, 59, 62, 64, 67, 69, 72, + 74, 77, 79, 82, 84, 87, 89, 92, 94, 97, 99, 102, 104, 107, 109, 112, 114, 117, 119, 122, 124, 126, + ], + 3, + )), + AnyBitCircuit::B26(BitCircuit::new( + [ + Node::new(58, 1, 0), + Node::new(58, 0, 1), + Node::new(26, 0, 1), + Node::new(26, 1, 0), + Node::new(26, 0, 0), + Node::new(26, 1, 1), + Node::new(57, 0, 1), + Node::new(25, 2, 1), + Node::new(25, 0, 2), + Node::new(25, 0, 0), + Node::new(25, 1, 1), + Node::new(56, 1, 0), + Node::new(24, 2, 0), + Node::new(24, 1, 2), + Node::new(24, 0, 0), + Node::new(24, 1, 1), + Node::new(55, 1, 0), + Node::new(23, 1, 2), + Node::new(23, 2, 0), + Node::new(23, 0, 0), + Node::new(23, 1, 1), + Node::new(54, 0, 1), + Node::new(22, 0, 2), + Node::new(22, 2, 1), + Node::new(22, 0, 0), + Node::new(22, 1, 1), + Node::new(53, 0, 1), + Node::new(21, 2, 1), + Node::new(21, 0, 2), + Node::new(21, 0, 0), + Node::new(21, 1, 1), + Node::new(52, 1, 0), + Node::new(20, 2, 0), + Node::new(20, 1, 2), + Node::new(20, 0, 0), + Node::new(20, 1, 1), + Node::new(51, 1, 0), + Node::new(19, 1, 2), + Node::new(19, 2, 0), + Node::new(19, 0, 0), + Node::new(19, 1, 1), + Node::new(50, 0, 1), + Node::new(18, 0, 2), + Node::new(18, 2, 1), + Node::new(18, 0, 0), + Node::new(18, 1, 1), + Node::new(49, 0, 1), + Node::new(17, 2, 1), + Node::new(17, 0, 2), + Node::new(17, 0, 0), + Node::new(17, 1, 1), + Node::new(48, 1, 0), + Node::new(16, 1, 2), + Node::new(16, 2, 0), + Node::new(16, 0, 0), + Node::new(16, 1, 1), + Node::new(47, 0, 1), + Node::new(15, 2, 1), + Node::new(15, 0, 2), + Node::new(15, 0, 0), + Node::new(15, 1, 1), + Node::new(46, 1, 0), + Node::new(14, 2, 0), + Node::new(14, 1, 2), + Node::new(14, 0, 0), + Node::new(14, 1, 1), + Node::new(45, 1, 0), + Node::new(13, 1, 2), + Node::new(13, 2, 0), + Node::new(13, 0, 0), + Node::new(13, 1, 1), + Node::new(44, 0, 1), + Node::new(12, 0, 2), + Node::new(12, 2, 1), + Node::new(12, 0, 0), + Node::new(12, 1, 1), + Node::new(43, 0, 1), + Node::new(11, 2, 1), + Node::new(11, 0, 2), + Node::new(11, 0, 0), + Node::new(11, 1, 1), + Node::new(42, 1, 0), + Node::new(10, 1, 2), + Node::new(10, 2, 0), + Node::new(10, 0, 0), + Node::new(10, 1, 1), + Node::new(41, 0, 1), + Node::new(9, 0, 2), + Node::new(9, 2, 1), + Node::new(9, 0, 0), + Node::new(9, 1, 1), + Node::new(40, 0, 1), + Node::new(8, 0, 2), + Node::new(8, 2, 1), + Node::new(8, 0, 0), + Node::new(8, 1, 1), + Node::new(39, 0, 1), + Node::new(7, 2, 1), + Node::new(7, 0, 2), + Node::new(7, 0, 0), + Node::new(7, 1, 1), + Node::new(38, 1, 0), + Node::new(6, 1, 2), + Node::new(6, 2, 0), + Node::new(6, 0, 0), + Node::new(6, 1, 1), + Node::new(37, 0, 1), + Node::new(5, 2, 1), + Node::new(5, 0, 2), + Node::new(5, 0, 0), + Node::new(5, 1, 1), + Node::new(36, 1, 0), + Node::new(4, 1, 2), + Node::new(4, 2, 0), + Node::new(4, 0, 0), + Node::new(4, 1, 1), + Node::new(35, 0, 1), + Node::new(3, 0, 2), + Node::new(3, 2, 1), + Node::new(3, 0, 0), + Node::new(3, 1, 1), + Node::new(34, 0, 1), + Node::new(2, 0, 2), + Node::new(2, 2, 1), + Node::new(2, 0, 0), + Node::new(2, 1, 1), + Node::new(33, 0, 1), + Node::new(1, 2, 1), + Node::new(1, 0, 2), + Node::new(1, 0, 0), + Node::new(32, 1, 0), + Node::new(0, 1, 0), + ], + [ + 0, 2, 4, 7, 9, 12, 14, 17, 19, 22, 24, 27, 29, 32, 34, 37, 39, 42, 44, 47, 49, 52, 54, 57, 59, 62, 64, 67, 69, 72, + 74, 77, 79, 82, 84, 87, 89, 92, 94, 97, 99, 102, 104, 107, 109, 112, 114, 117, 119, 122, 124, 127, 129, 131, + ], + 3, + )), + AnyBitCircuit::B27(BitCircuit::new( + [ + Node::new(59, 0, 1), + Node::new(59, 1, 0), + Node::new(27, 1, 0), + Node::new(27, 0, 1), + Node::new(27, 0, 0), + Node::new(27, 1, 1), + Node::new(58, 0, 1), + Node::new(26, 2, 1), + Node::new(26, 0, 2), + Node::new(26, 0, 0), + Node::new(26, 1, 1), + Node::new(57, 1, 0), + Node::new(25, 2, 0), + Node::new(25, 1, 2), + Node::new(25, 0, 0), + Node::new(25, 1, 1), + Node::new(56, 1, 0), + Node::new(24, 2, 0), + Node::new(24, 1, 2), + Node::new(24, 0, 0), + Node::new(24, 1, 1), + Node::new(55, 1, 0), + Node::new(23, 2, 0), + Node::new(23, 1, 2), + Node::new(23, 0, 0), + Node::new(23, 1, 1), + Node::new(54, 1, 0), + Node::new(22, 1, 2), + Node::new(22, 2, 0), + Node::new(22, 0, 0), + Node::new(22, 1, 1), + Node::new(53, 0, 1), + Node::new(21, 0, 2), + Node::new(21, 2, 1), + Node::new(21, 0, 0), + Node::new(21, 1, 1), + Node::new(52, 0, 1), + Node::new(20, 2, 1), + Node::new(20, 0, 2), + Node::new(20, 0, 0), + Node::new(20, 1, 1), + Node::new(51, 1, 0), + Node::new(19, 2, 0), + Node::new(19, 1, 2), + Node::new(19, 0, 0), + Node::new(19, 1, 1), + Node::new(50, 1, 0), + Node::new(18, 2, 0), + Node::new(18, 1, 2), + Node::new(18, 0, 0), + Node::new(18, 1, 1), + Node::new(49, 1, 0), + Node::new(17, 2, 0), + Node::new(17, 1, 2), + Node::new(17, 0, 0), + Node::new(17, 1, 1), + Node::new(48, 1, 0), + Node::new(16, 2, 0), + Node::new(16, 1, 2), + Node::new(16, 0, 0), + Node::new(16, 1, 1), + Node::new(47, 1, 0), + Node::new(15, 1, 2), + Node::new(15, 2, 0), + Node::new(15, 0, 0), + Node::new(15, 1, 1), + Node::new(46, 0, 1), + Node::new(14, 2, 1), + Node::new(14, 0, 2), + Node::new(14, 0, 0), + Node::new(14, 1, 1), + Node::new(45, 1, 0), + Node::new(13, 1, 2), + Node::new(13, 2, 0), + Node::new(13, 0, 0), + Node::new(13, 1, 1), + Node::new(44, 0, 1), + Node::new(12, 2, 1), + Node::new(12, 0, 2), + Node::new(12, 0, 0), + Node::new(12, 1, 1), + Node::new(43, 1, 0), + Node::new(11, 2, 0), + Node::new(11, 1, 2), + Node::new(11, 0, 0), + Node::new(11, 1, 1), + Node::new(42, 1, 0), + Node::new(10, 1, 2), + Node::new(10, 2, 0), + Node::new(10, 0, 0), + Node::new(10, 1, 1), + Node::new(41, 0, 1), + Node::new(9, 0, 2), + Node::new(9, 2, 1), + Node::new(9, 0, 0), + Node::new(9, 1, 1), + Node::new(40, 0, 1), + Node::new(8, 2, 1), + Node::new(8, 0, 2), + Node::new(8, 0, 0), + Node::new(8, 1, 1), + Node::new(39, 1, 0), + Node::new(7, 1, 2), + Node::new(7, 2, 0), + Node::new(7, 0, 0), + Node::new(7, 1, 1), + Node::new(38, 0, 1), + Node::new(6, 0, 2), + Node::new(6, 2, 1), + Node::new(6, 0, 0), + Node::new(6, 1, 1), + Node::new(37, 0, 1), + Node::new(5, 2, 1), + Node::new(5, 0, 2), + Node::new(5, 0, 0), + Node::new(5, 1, 1), + Node::new(36, 1, 0), + Node::new(4, 2, 0), + Node::new(4, 1, 2), + Node::new(4, 0, 0), + Node::new(4, 1, 1), + Node::new(35, 1, 0), + Node::new(3, 2, 0), + Node::new(3, 1, 2), + Node::new(3, 0, 0), + Node::new(3, 1, 1), + Node::new(34, 1, 0), + Node::new(2, 2, 0), + Node::new(2, 1, 2), + Node::new(2, 0, 0), + Node::new(2, 1, 1), + Node::new(33, 1, 0), + Node::new(1, 2, 0), + Node::new(1, 1, 2), + Node::new(1, 0, 0), + Node::new(32, 1, 0), + Node::new(0, 1, 0), + ], + [ + 0, 2, 4, 7, 9, 12, 14, 17, 19, 22, 24, 27, 29, 32, 34, 37, 39, 42, 44, 47, 49, 52, 54, 57, 59, 62, 64, 67, 69, 72, + 74, 77, 79, 82, 84, 87, 89, 92, 94, 97, 99, 102, 104, 107, 109, 112, 114, 117, 119, 122, 124, 127, 129, 132, 134, + 136, + ], + 3, + )), + AnyBitCircuit::B28(BitCircuit::new( + [ + Node::new(60, 1, 0), + Node::new(60, 0, 1), + Node::new(28, 1, 0), + Node::new(28, 0, 1), + Node::new(28, 0, 0), + Node::new(28, 1, 1), + Node::new(59, 1, 0), + Node::new(27, 1, 2), + Node::new(27, 2, 0), + Node::new(27, 0, 0), + Node::new(27, 1, 1), + Node::new(58, 0, 1), + Node::new(26, 0, 2), + Node::new(26, 2, 1), + Node::new(26, 0, 0), + Node::new(26, 1, 1), + Node::new(57, 0, 1), + Node::new(25, 0, 2), + Node::new(25, 2, 1), + Node::new(25, 0, 0), + Node::new(25, 1, 1), + Node::new(56, 0, 1), + Node::new(24, 2, 1), + Node::new(24, 0, 2), + Node::new(24, 0, 0), + Node::new(24, 1, 1), + Node::new(55, 1, 0), + Node::new(23, 1, 2), + Node::new(23, 2, 0), + Node::new(23, 0, 0), + Node::new(23, 1, 1), + Node::new(54, 0, 1), + Node::new(22, 0, 2), + Node::new(22, 2, 1), + Node::new(22, 0, 0), + Node::new(22, 1, 1), + Node::new(53, 0, 1), + Node::new(21, 2, 1), + Node::new(21, 0, 2), + Node::new(21, 0, 0), + Node::new(21, 1, 1), + Node::new(52, 1, 0), + Node::new(20, 1, 2), + Node::new(20, 2, 0), + Node::new(20, 0, 0), + Node::new(20, 1, 1), + Node::new(51, 0, 1), + Node::new(19, 0, 2), + Node::new(19, 2, 1), + Node::new(19, 0, 0), + Node::new(19, 1, 1), + Node::new(50, 0, 1), + Node::new(18, 0, 2), + Node::new(18, 2, 1), + Node::new(18, 0, 0), + Node::new(18, 1, 1), + Node::new(49, 0, 1), + Node::new(17, 2, 1), + Node::new(17, 0, 2), + Node::new(17, 0, 0), + Node::new(17, 1, 1), + Node::new(48, 1, 0), + Node::new(16, 1, 2), + Node::new(16, 2, 0), + Node::new(16, 0, 0), + Node::new(16, 1, 1), + Node::new(47, 0, 1), + Node::new(15, 2, 1), + Node::new(15, 0, 2), + Node::new(15, 0, 0), + Node::new(15, 1, 1), + Node::new(46, 1, 0), + Node::new(14, 2, 0), + Node::new(14, 1, 2), + Node::new(14, 0, 0), + Node::new(14, 1, 1), + Node::new(45, 1, 0), + Node::new(13, 1, 2), + Node::new(13, 2, 0), + Node::new(13, 0, 0), + Node::new(13, 1, 1), + Node::new(44, 0, 1), + Node::new(12, 2, 1), + Node::new(12, 0, 2), + Node::new(12, 0, 0), + Node::new(12, 1, 1), + Node::new(43, 1, 0), + Node::new(11, 1, 2), + Node::new(11, 2, 0), + Node::new(11, 0, 0), + Node::new(11, 1, 1), + Node::new(42, 0, 1), + Node::new(10, 0, 2), + Node::new(10, 2, 1), + Node::new(10, 0, 0), + Node::new(10, 1, 1), + Node::new(41, 0, 1), + Node::new(9, 0, 2), + Node::new(9, 2, 1), + Node::new(9, 0, 0), + Node::new(9, 1, 1), + Node::new(40, 0, 1), + Node::new(8, 2, 1), + Node::new(8, 0, 2), + Node::new(8, 0, 0), + Node::new(8, 1, 1), + Node::new(39, 1, 0), + Node::new(7, 2, 0), + Node::new(7, 1, 2), + Node::new(7, 0, 0), + Node::new(7, 1, 1), + Node::new(38, 1, 0), + Node::new(6, 1, 2), + Node::new(6, 2, 0), + Node::new(6, 0, 0), + Node::new(6, 1, 1), + Node::new(37, 0, 1), + Node::new(5, 0, 2), + Node::new(5, 2, 1), + Node::new(5, 0, 0), + Node::new(5, 1, 1), + Node::new(36, 0, 1), + Node::new(4, 0, 2), + Node::new(4, 2, 1), + Node::new(4, 0, 0), + Node::new(4, 1, 1), + Node::new(35, 0, 1), + Node::new(3, 2, 1), + Node::new(3, 0, 2), + Node::new(3, 0, 0), + Node::new(3, 1, 1), + Node::new(34, 1, 0), + Node::new(2, 1, 2), + Node::new(2, 2, 0), + Node::new(2, 0, 0), + Node::new(2, 1, 1), + Node::new(33, 0, 1), + Node::new(1, 2, 1), + Node::new(1, 0, 2), + Node::new(1, 0, 0), + Node::new(32, 1, 0), + Node::new(0, 1, 0), + ], + [ + 0, 2, 4, 7, 9, 12, 14, 17, 19, 22, 24, 27, 29, 32, 34, 37, 39, 42, 44, 47, 49, 52, 54, 57, 59, 62, 64, 67, 69, 72, + 74, 77, 79, 82, 84, 87, 89, 92, 94, 97, 99, 102, 104, 107, 109, 112, 114, 117, 119, 122, 124, 127, 129, 132, 134, + 137, 139, 141, + ], + 3, + )), + AnyBitCircuit::B29(BitCircuit::new( + [ + Node::new(61, 0, 1), + Node::new(61, 1, 0), + Node::new(29, 0, 1), + Node::new(29, 1, 0), + Node::new(29, 0, 0), + Node::new(29, 1, 1), + Node::new(60, 1, 0), + Node::new(28, 2, 0), + Node::new(28, 1, 2), + Node::new(28, 0, 0), + Node::new(28, 1, 1), + Node::new(59, 1, 0), + Node::new(27, 1, 2), + Node::new(27, 2, 0), + Node::new(27, 0, 0), + Node::new(27, 1, 1), + Node::new(58, 0, 1), + Node::new(26, 0, 2), + Node::new(26, 2, 1), + Node::new(26, 0, 0), + Node::new(26, 1, 1), + Node::new(57, 0, 1), + Node::new(25, 2, 1), + Node::new(25, 0, 2), + Node::new(25, 0, 0), + Node::new(25, 1, 1), + Node::new(56, 1, 0), + Node::new(24, 2, 0), + Node::new(24, 1, 2), + Node::new(24, 0, 0), + Node::new(24, 1, 1), + Node::new(55, 1, 0), + Node::new(23, 2, 0), + Node::new(23, 1, 2), + Node::new(23, 0, 0), + Node::new(23, 1, 1), + Node::new(54, 1, 0), + Node::new(22, 1, 2), + Node::new(22, 2, 0), + Node::new(22, 0, 0), + Node::new(22, 1, 1), + Node::new(53, 0, 1), + Node::new(21, 2, 1), + Node::new(21, 0, 2), + Node::new(21, 0, 0), + Node::new(21, 1, 1), + Node::new(52, 1, 0), + Node::new(20, 1, 2), + Node::new(20, 2, 0), + Node::new(20, 0, 0), + Node::new(20, 1, 1), + Node::new(51, 0, 1), + Node::new(19, 0, 2), + Node::new(19, 2, 1), + Node::new(19, 0, 0), + Node::new(19, 1, 1), + Node::new(50, 0, 1), + Node::new(18, 2, 1), + Node::new(18, 0, 2), + Node::new(18, 0, 0), + Node::new(18, 1, 1), + Node::new(49, 1, 0), + Node::new(17, 1, 2), + Node::new(17, 2, 0), + Node::new(17, 0, 0), + Node::new(17, 1, 1), + Node::new(48, 0, 1), + Node::new(16, 0, 2), + Node::new(16, 2, 1), + Node::new(16, 0, 0), + Node::new(16, 1, 1), + Node::new(47, 0, 1), + Node::new(15, 0, 2), + Node::new(15, 2, 1), + Node::new(15, 0, 0), + Node::new(15, 1, 1), + Node::new(46, 0, 1), + Node::new(14, 0, 2), + Node::new(14, 2, 1), + Node::new(14, 0, 0), + Node::new(14, 1, 1), + Node::new(45, 0, 1), + Node::new(13, 0, 2), + Node::new(13, 2, 1), + Node::new(13, 0, 0), + Node::new(13, 1, 1), + Node::new(44, 0, 1), + Node::new(12, 2, 1), + Node::new(12, 0, 2), + Node::new(12, 0, 0), + Node::new(12, 1, 1), + Node::new(43, 1, 0), + Node::new(11, 1, 2), + Node::new(11, 2, 0), + Node::new(11, 0, 0), + Node::new(11, 1, 1), + Node::new(42, 0, 1), + Node::new(10, 2, 1), + Node::new(10, 0, 2), + Node::new(10, 0, 0), + Node::new(10, 1, 1), + Node::new(41, 1, 0), + Node::new(9, 1, 2), + Node::new(9, 2, 0), + Node::new(9, 0, 0), + Node::new(9, 1, 1), + Node::new(40, 0, 1), + Node::new(8, 0, 2), + Node::new(8, 2, 1), + Node::new(8, 0, 0), + Node::new(8, 1, 1), + Node::new(39, 0, 1), + Node::new(7, 0, 2), + Node::new(7, 2, 1), + Node::new(7, 0, 0), + Node::new(7, 1, 1), + Node::new(38, 0, 1), + Node::new(6, 0, 2), + Node::new(6, 2, 1), + Node::new(6, 0, 0), + Node::new(6, 1, 1), + Node::new(37, 0, 1), + Node::new(5, 2, 1), + Node::new(5, 0, 2), + Node::new(5, 0, 0), + Node::new(5, 1, 1), + Node::new(36, 1, 0), + Node::new(4, 2, 0), + Node::new(4, 1, 2), + Node::new(4, 0, 0), + Node::new(4, 1, 1), + Node::new(35, 1, 0), + Node::new(3, 2, 0), + Node::new(3, 1, 2), + Node::new(3, 0, 0), + Node::new(3, 1, 1), + Node::new(34, 1, 0), + Node::new(2, 1, 2), + Node::new(2, 2, 0), + Node::new(2, 0, 0), + Node::new(2, 1, 1), + Node::new(33, 0, 1), + Node::new(1, 2, 1), + Node::new(1, 0, 2), + Node::new(1, 0, 0), + Node::new(32, 1, 0), + Node::new(0, 1, 0), + ], + [ + 0, 2, 4, 7, 9, 12, 14, 17, 19, 22, 24, 27, 29, 32, 34, 37, 39, 42, 44, 47, 49, 52, 54, 57, 59, 62, 64, 67, 69, 72, + 74, 77, 79, 82, 84, 87, 89, 92, 94, 97, 99, 102, 104, 107, 109, 112, 114, 117, 119, 122, 124, 127, 129, 132, 134, + 137, 139, 142, 144, 146, + ], + 3, + )), + AnyBitCircuit::B30(BitCircuit::new( + [ + Node::new(62, 0, 1), + Node::new(62, 1, 0), + Node::new(30, 1, 0), + Node::new(30, 0, 1), + Node::new(30, 0, 0), + Node::new(30, 1, 1), + Node::new(61, 0, 1), + Node::new(29, 2, 1), + Node::new(29, 0, 2), + Node::new(29, 0, 0), + Node::new(29, 1, 1), + Node::new(60, 1, 0), + Node::new(28, 2, 0), + Node::new(28, 1, 2), + Node::new(28, 0, 0), + Node::new(28, 1, 1), + Node::new(59, 1, 0), + Node::new(27, 2, 0), + Node::new(27, 1, 2), + Node::new(27, 0, 0), + Node::new(27, 1, 1), + Node::new(58, 1, 0), + Node::new(26, 2, 0), + Node::new(26, 1, 2), + Node::new(26, 0, 0), + Node::new(26, 1, 1), + Node::new(57, 1, 0), + Node::new(25, 1, 2), + Node::new(25, 2, 0), + Node::new(25, 0, 0), + Node::new(25, 1, 1), + Node::new(56, 0, 1), + Node::new(24, 0, 2), + Node::new(24, 2, 1), + Node::new(24, 0, 0), + Node::new(24, 1, 1), + Node::new(55, 0, 1), + Node::new(23, 2, 1), + Node::new(23, 0, 2), + Node::new(23, 0, 0), + Node::new(23, 1, 1), + Node::new(54, 1, 0), + Node::new(22, 2, 0), + Node::new(22, 1, 2), + Node::new(22, 0, 0), + Node::new(22, 1, 1), + Node::new(53, 1, 0), + Node::new(21, 2, 0), + Node::new(21, 1, 2), + Node::new(21, 0, 0), + Node::new(21, 1, 1), + Node::new(52, 1, 0), + Node::new(20, 2, 0), + Node::new(20, 1, 2), + Node::new(20, 0, 0), + Node::new(20, 1, 1), + Node::new(51, 1, 0), + Node::new(19, 1, 2), + Node::new(19, 2, 0), + Node::new(19, 0, 0), + Node::new(19, 1, 1), + Node::new(50, 0, 1), + Node::new(18, 0, 2), + Node::new(18, 2, 1), + Node::new(18, 0, 0), + Node::new(18, 1, 1), + Node::new(49, 0, 1), + Node::new(17, 2, 1), + Node::new(17, 0, 2), + Node::new(17, 0, 0), + Node::new(17, 1, 1), + Node::new(48, 1, 0), + Node::new(16, 2, 0), + Node::new(16, 1, 2), + Node::new(16, 0, 0), + Node::new(16, 1, 1), + Node::new(47, 1, 0), + Node::new(15, 1, 2), + Node::new(15, 2, 0), + Node::new(15, 0, 0), + Node::new(15, 1, 1), + Node::new(46, 0, 1), + Node::new(14, 0, 2), + Node::new(14, 2, 1), + Node::new(14, 0, 0), + Node::new(14, 1, 1), + Node::new(45, 0, 1), + Node::new(13, 2, 1), + Node::new(13, 0, 2), + Node::new(13, 0, 0), + Node::new(13, 1, 1), + Node::new(44, 1, 0), + Node::new(12, 1, 2), + Node::new(12, 2, 0), + Node::new(12, 0, 0), + Node::new(12, 1, 1), + Node::new(43, 0, 1), + Node::new(11, 0, 2), + Node::new(11, 2, 1), + Node::new(11, 0, 0), + Node::new(11, 1, 1), + Node::new(42, 0, 1), + Node::new(10, 2, 1), + Node::new(10, 0, 2), + Node::new(10, 0, 0), + Node::new(10, 1, 1), + Node::new(41, 1, 0), + Node::new(9, 2, 0), + Node::new(9, 1, 2), + Node::new(9, 0, 0), + Node::new(9, 1, 1), + Node::new(40, 1, 0), + Node::new(8, 2, 0), + Node::new(8, 1, 2), + Node::new(8, 0, 0), + Node::new(8, 1, 1), + Node::new(39, 1, 0), + Node::new(7, 2, 0), + Node::new(7, 1, 2), + Node::new(7, 0, 0), + Node::new(7, 1, 1), + Node::new(38, 1, 0), + Node::new(6, 1, 2), + Node::new(6, 2, 0), + Node::new(6, 0, 0), + Node::new(6, 1, 1), + Node::new(37, 0, 1), + Node::new(5, 2, 1), + Node::new(5, 0, 2), + Node::new(5, 0, 0), + Node::new(5, 1, 1), + Node::new(36, 1, 0), + Node::new(4, 2, 0), + Node::new(4, 1, 2), + Node::new(4, 0, 0), + Node::new(4, 1, 1), + Node::new(35, 1, 0), + Node::new(3, 1, 2), + Node::new(3, 2, 0), + Node::new(3, 0, 0), + Node::new(3, 1, 1), + Node::new(34, 0, 1), + Node::new(2, 2, 1), + Node::new(2, 0, 2), + Node::new(2, 0, 0), + Node::new(2, 1, 1), + Node::new(33, 1, 0), + Node::new(1, 2, 0), + Node::new(1, 1, 2), + Node::new(1, 0, 0), + Node::new(32, 1, 0), + Node::new(0, 1, 0), + ], + [ + 0, 2, 4, 7, 9, 12, 14, 17, 19, 22, 24, 27, 29, 32, 34, 37, 39, 42, 44, 47, 49, 52, 54, 57, 59, 62, 64, 67, 69, 72, + 74, 77, 79, 82, 84, 87, 89, 92, 94, 97, 99, 102, 104, 107, 109, 112, 114, 117, 119, 122, 124, 127, 129, 132, 134, + 137, 139, 142, 144, 147, 149, 151, + ], + 3, + )), + AnyBitCircuit::B31(BitCircuit::new( + [ + Node::new(63, 1, 0), + Node::new(63, 0, 1), + Node::new(31, 1, 0), + Node::new(31, 0, 1), + Node::new(31, 0, 0), + Node::new(31, 1, 1), + Node::new(62, 1, 0), + Node::new(30, 2, 0), + Node::new(30, 1, 2), + Node::new(30, 0, 0), + Node::new(30, 1, 1), + Node::new(61, 1, 0), + Node::new(29, 2, 0), + Node::new(29, 1, 2), + Node::new(29, 0, 0), + Node::new(29, 1, 1), + Node::new(60, 1, 0), + Node::new(28, 2, 0), + Node::new(28, 1, 2), + Node::new(28, 0, 0), + Node::new(28, 1, 1), + Node::new(59, 1, 0), + Node::new(27, 1, 2), + Node::new(27, 2, 0), + Node::new(27, 0, 0), + Node::new(27, 1, 1), + Node::new(58, 0, 1), + Node::new(26, 2, 1), + Node::new(26, 0, 2), + Node::new(26, 0, 0), + Node::new(26, 1, 1), + Node::new(57, 1, 0), + Node::new(25, 2, 0), + Node::new(25, 1, 2), + Node::new(25, 0, 0), + Node::new(25, 1, 1), + Node::new(56, 1, 0), + Node::new(24, 2, 0), + Node::new(24, 1, 2), + Node::new(24, 0, 0), + Node::new(24, 1, 1), + Node::new(55, 1, 0), + Node::new(23, 1, 2), + Node::new(23, 2, 0), + Node::new(23, 0, 0), + Node::new(23, 1, 1), + Node::new(54, 0, 1), + Node::new(22, 2, 1), + Node::new(22, 0, 2), + Node::new(22, 0, 0), + Node::new(22, 1, 1), + Node::new(53, 1, 0), + Node::new(21, 2, 0), + Node::new(21, 1, 2), + Node::new(21, 0, 0), + Node::new(21, 1, 1), + Node::new(52, 1, 0), + Node::new(20, 2, 0), + Node::new(20, 1, 2), + Node::new(20, 0, 0), + Node::new(20, 1, 1), + Node::new(51, 1, 0), + Node::new(19, 2, 0), + Node::new(19, 1, 2), + Node::new(19, 0, 0), + Node::new(19, 1, 1), + Node::new(50, 1, 0), + Node::new(18, 1, 2), + Node::new(18, 2, 0), + Node::new(18, 0, 0), + Node::new(18, 1, 1), + Node::new(49, 0, 1), + Node::new(17, 2, 1), + Node::new(17, 0, 2), + Node::new(17, 0, 0), + Node::new(17, 1, 1), + Node::new(48, 1, 0), + Node::new(16, 2, 0), + Node::new(16, 1, 2), + Node::new(16, 0, 0), + Node::new(16, 1, 1), + Node::new(47, 1, 0), + Node::new(15, 2, 0), + Node::new(15, 1, 2), + Node::new(15, 0, 0), + Node::new(15, 1, 1), + Node::new(46, 1, 0), + Node::new(14, 2, 0), + Node::new(14, 1, 2), + Node::new(14, 0, 0), + Node::new(14, 1, 1), + Node::new(45, 1, 0), + Node::new(13, 1, 2), + Node::new(13, 2, 0), + Node::new(13, 0, 0), + Node::new(13, 1, 1), + Node::new(44, 0, 1), + Node::new(12, 2, 1), + Node::new(12, 0, 2), + Node::new(12, 0, 0), + Node::new(12, 1, 1), + Node::new(43, 1, 0), + Node::new(11, 2, 0), + Node::new(11, 1, 2), + Node::new(11, 0, 0), + Node::new(11, 1, 1), + Node::new(42, 1, 0), + Node::new(10, 2, 0), + Node::new(10, 1, 2), + Node::new(10, 0, 0), + Node::new(10, 1, 1), + Node::new(41, 1, 0), + Node::new(9, 2, 0), + Node::new(9, 1, 2), + Node::new(9, 0, 0), + Node::new(9, 1, 1), + Node::new(40, 1, 0), + Node::new(8, 1, 2), + Node::new(8, 2, 0), + Node::new(8, 0, 0), + Node::new(8, 1, 1), + Node::new(39, 0, 1), + Node::new(7, 2, 1), + Node::new(7, 0, 2), + Node::new(7, 0, 0), + Node::new(7, 1, 1), + Node::new(38, 1, 0), + Node::new(6, 1, 2), + Node::new(6, 2, 0), + Node::new(6, 0, 0), + Node::new(6, 1, 1), + Node::new(37, 0, 1), + Node::new(5, 2, 1), + Node::new(5, 0, 2), + Node::new(5, 0, 0), + Node::new(5, 1, 1), + Node::new(36, 1, 0), + Node::new(4, 2, 0), + Node::new(4, 1, 2), + Node::new(4, 0, 0), + Node::new(4, 1, 1), + Node::new(35, 1, 0), + Node::new(3, 1, 2), + Node::new(3, 2, 0), + Node::new(3, 0, 0), + Node::new(3, 1, 1), + Node::new(34, 0, 1), + Node::new(2, 0, 2), + Node::new(2, 2, 1), + Node::new(2, 0, 0), + Node::new(2, 1, 1), + Node::new(33, 0, 1), + Node::new(1, 2, 1), + Node::new(1, 0, 2), + Node::new(1, 0, 0), + Node::new(32, 1, 0), + Node::new(0, 1, 0), + ], + [ + 0, 2, 4, 7, 9, 12, 14, 17, 19, 22, 24, 27, 29, 32, 34, 37, 39, 42, 44, 47, 49, 52, 54, 57, 59, 62, 64, 67, 69, 72, + 74, 77, 79, 82, 84, 87, 89, 92, 94, 97, 99, 102, 104, 107, 109, 112, 114, 117, 119, 122, 124, 127, 129, 132, 134, + 137, 139, 142, 144, 147, 149, 152, 154, 156, + ], + 3, + )), +]);
@@ -0,0 +1,465 @@
+use crate::tfhe::bdd_arithmetic::{BitCircuit, BitCircuitInfo, Circuit, GetBitCircuitInfo, Node}; +pub(crate) enum AnyBitCircuit { + B0(BitCircuit<3, 2>), + B1(BitCircuit<3, 2>), + B2(BitCircuit<3, 2>), + B3(BitCircuit<3, 2>), + B4(BitCircuit<3, 2>), + B5(BitCircuit<3, 2>), + B6(BitCircuit<3, 2>), + B7(BitCircuit<3, 2>), + B8(BitCircuit<3, 2>), + B9(BitCircuit<3, 2>), + B10(BitCircuit<3, 2>), + B11(BitCircuit<3, 2>), + B12(BitCircuit<3, 2>), + B13(BitCircuit<3, 2>), + B14(BitCircuit<3, 2>), + B15(BitCircuit<3, 2>), + B16(BitCircuit<3, 2>), + B17(BitCircuit<3, 2>), + B18(BitCircuit<3, 2>), + B19(BitCircuit<3, 2>), + B20(BitCircuit<3, 2>), + B21(BitCircuit<3, 2>), + B22(BitCircuit<3, 2>), + B23(BitCircuit<3, 2>), + B24(BitCircuit<3, 2>), + B25(BitCircuit<3, 2>), + B26(BitCircuit<3, 2>), + B27(BitCircuit<3, 2>), + B28(BitCircuit<3, 2>), + B29(BitCircuit<3, 2>), + B30(BitCircuit<3, 2>), + B31(BitCircuit<3, 2>), +} + +impl BitCircuitInfo for AnyBitCircuit { + fn info(&self) -> (&[Node], &[usize], usize) { + match self { + AnyBitCircuit::B0(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B1(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B2(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B3(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B4(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B5(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B6(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B7(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B8(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B9(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B10(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B11(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B12(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B13(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B14(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B15(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B16(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B17(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B18(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B19(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B20(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B21(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B22(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B23(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B24(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B25(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B26(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B27(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B28(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B29(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B30(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B31(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + } + } +} + +impl GetBitCircuitInfo<u32> for Circuit<AnyBitCircuit, 32usize> { + fn input_size(&self) -> usize { + 2 * u32::BITS as usize + } + fn output_size(&self) -> usize { + u32::BITS as usize + } + fn get_circuit(&self, bit: usize) -> (&[Node], &[usize], usize) { + self.0[bit].info() + } +} + +pub(crate) static OUTPUT_CIRCUITS: Circuit<AnyBitCircuit, 32usize> = Circuit([ + AnyBitCircuit::B0(BitCircuit::new( + [Node::new(0, 0, 0), Node::new(32, 1, 0), Node::new(0, 1, 0)], + [0, 2], + 2, + )), + AnyBitCircuit::B1(BitCircuit::new( + [Node::new(1, 0, 0), Node::new(33, 1, 0), Node::new(1, 1, 0)], + [0, 2], + 2, + )), + AnyBitCircuit::B2(BitCircuit::new( + [Node::new(2, 0, 0), Node::new(34, 1, 0), Node::new(2, 1, 0)], + [0, 2], + 2, + )), + AnyBitCircuit::B3(BitCircuit::new( + [Node::new(3, 0, 0), Node::new(35, 1, 0), Node::new(3, 1, 0)], + [0, 2], + 2, + )), + AnyBitCircuit::B4(BitCircuit::new( + [Node::new(4, 0, 0), Node::new(36, 1, 0), Node::new(4, 1, 0)], + [0, 2], + 2, + )), + AnyBitCircuit::B5(BitCircuit::new( + [Node::new(5, 0, 0), Node::new(37, 1, 0), Node::new(5, 1, 0)], + [0, 2], + 2, + )), + AnyBitCircuit::B6(BitCircuit::new( + [Node::new(6, 0, 0), Node::new(38, 1, 0), Node::new(6, 1, 0)], + [0, 2], + 2, + )), + AnyBitCircuit::B7(BitCircuit::new( + [Node::new(7, 0, 0), Node::new(39, 1, 0), Node::new(7, 1, 0)], + [0, 2], + 2, + )), + AnyBitCircuit::B8(BitCircuit::new( + [Node::new(8, 0, 0), Node::new(40, 1, 0), Node::new(8, 1, 0)], + [0, 2], + 2, + )), + AnyBitCircuit::B9(BitCircuit::new( + [Node::new(9, 0, 0), Node::new(41, 1, 0), Node::new(9, 1, 0)], + [0, 2], + 2, + )), + AnyBitCircuit::B10(BitCircuit::new( + [ + Node::new(10, 0, 0), + Node::new(42, 1, 0), + Node::new(10, 1, 0), + ], + [0, 2], + 2, + )), + AnyBitCircuit::B11(BitCircuit::new( + [ + Node::new(11, 0, 0), + Node::new(43, 1, 0), + Node::new(11, 1, 0), + ], + [0, 2], + 2, + )), + AnyBitCircuit::B12(BitCircuit::new( + [ + Node::new(12, 0, 0), + Node::new(44, 1, 0), + Node::new(12, 1, 0), + ], + [0, 2], + 2, + )), + AnyBitCircuit::B13(BitCircuit::new( + [ + Node::new(13, 0, 0), + Node::new(45, 1, 0), + Node::new(13, 1, 0), + ], + [0, 2], + 2, + )), + AnyBitCircuit::B14(BitCircuit::new( + [ + Node::new(14, 0, 0), + Node::new(46, 1, 0), + Node::new(14, 1, 0), + ], + [0, 2], + 2, + )), + AnyBitCircuit::B15(BitCircuit::new( + [ + Node::new(15, 0, 0), + Node::new(47, 1, 0), + Node::new(15, 1, 0), + ], + [0, 2], + 2, + )), + AnyBitCircuit::B16(BitCircuit::new( + [ + Node::new(16, 0, 0), + Node::new(48, 1, 0), + Node::new(16, 1, 0), + ], + [0, 2], + 2, + )), + AnyBitCircuit::B17(BitCircuit::new( + [ + Node::new(17, 0, 0), + Node::new(49, 1, 0), + Node::new(17, 1, 0), + ], + [0, 2], + 2, + )), + AnyBitCircuit::B18(BitCircuit::new( + [ + Node::new(18, 0, 0), + Node::new(50, 1, 0), + Node::new(18, 1, 0), + ], + [0, 2], + 2, + )), + AnyBitCircuit::B19(BitCircuit::new( + [ + Node::new(19, 0, 0), + Node::new(51, 1, 0), + Node::new(19, 1, 0), + ], + [0, 2], + 2, + )), + AnyBitCircuit::B20(BitCircuit::new( + [ + Node::new(20, 0, 0), + Node::new(52, 1, 0), + Node::new(20, 1, 0), + ], + [0, 2], + 2, + )), + AnyBitCircuit::B21(BitCircuit::new( + [ + Node::new(21, 0, 0), + Node::new(53, 1, 0), + Node::new(21, 1, 0), + ], + [0, 2], + 2, + )), + AnyBitCircuit::B22(BitCircuit::new( + [ + Node::new(22, 0, 0), + Node::new(54, 1, 0), + Node::new(22, 1, 0), + ], + [0, 2], + 2, + )), + AnyBitCircuit::B23(BitCircuit::new( + [ + Node::new(23, 0, 0), + Node::new(55, 1, 0), + Node::new(23, 1, 0), + ], + [0, 2], + 2, + )), + AnyBitCircuit::B24(BitCircuit::new( + [ + Node::new(24, 0, 0), + Node::new(56, 1, 0), + Node::new(24, 1, 0), + ], + [0, 2], + 2, + )), + AnyBitCircuit::B25(BitCircuit::new( + [ + Node::new(25, 0, 0), + Node::new(57, 1, 0), + Node::new(25, 1, 0), + ], + [0, 2], + 2, + )), + AnyBitCircuit::B26(BitCircuit::new( + [ + Node::new(26, 0, 0), + Node::new(58, 1, 0), + Node::new(26, 1, 0), + ], + [0, 2], + 2, + )), + AnyBitCircuit::B27(BitCircuit::new( + [ + Node::new(27, 0, 0), + Node::new(59, 1, 0), + Node::new(27, 1, 0), + ], + [0, 2], + 2, + )), + AnyBitCircuit::B28(BitCircuit::new( + [ + Node::new(28, 0, 0), + Node::new(60, 1, 0), + Node::new(28, 1, 0), + ], + [0, 2], + 2, + )), + AnyBitCircuit::B29(BitCircuit::new( + [ + Node::new(29, 0, 0), + Node::new(61, 1, 0), + Node::new(29, 1, 0), + ], + [0, 2], + 2, + )), + AnyBitCircuit::B30(BitCircuit::new( + [ + Node::new(30, 0, 0), + Node::new(62, 1, 0), + Node::new(30, 1, 0), + ], + [0, 2], + 2, + )), + AnyBitCircuit::B31(BitCircuit::new( + [ + Node::new(31, 0, 0), + Node::new(63, 1, 0), + Node::new(31, 1, 0), + ], + [0, 2], + 2, + )), +]);
@@ -0,0 +1,10 @@
+pub(crate) mod add_codegen; +pub(crate) mod and_codegen; +pub(crate) mod or_codegen; +pub(crate) mod sll_codegen; +pub(crate) mod slt_codegen; +pub(crate) mod sltu_codegen; +pub(crate) mod sra_codegen; +pub(crate) mod srl_codegen; +pub(crate) mod sub_codegen; +pub(crate) mod xor_codegen;
@@ -0,0 +1,34 @@
+use crate::tfhe::bdd_arithmetic::{BitCircuit, BitCircuitInfo, Circuit, GetBitCircuitInfo, Node}; +pub(crate) enum AnyBitCircuit { + B0(BitCircuit<3, 2>), +} + +impl BitCircuitInfo for AnyBitCircuit { + fn info(&self) -> (&[Node], &[usize], usize) { + match self { + AnyBitCircuit::B0(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + } + } +} + +impl GetBitCircuitInfo<u32> for Circuit<AnyBitCircuit, 1usize> { + fn input_size(&self) -> usize { + 2 * u32::BITS as usize + } + fn output_size(&self) -> usize { + u32::BITS as usize + } + fn get_circuit(&self, _bit: usize) -> (&[Node], &[usize], usize) { + self.0[0].info() + } +} + +pub(crate) static OUTPUT_CIRCUITS: Circuit<AnyBitCircuit, 1usize> = Circuit([AnyBitCircuit::B0(BitCircuit::new( + [Node::new(0, 0, 0), Node::new(1, 1, 0), Node::new(0, 1, 1)], + [0, 2], + 2, +))]);
@@ -0,0 +1,1830 @@
+use crate::tfhe::bdd_arithmetic::{BitCircuit, BitCircuitInfo, Circuit, GetBitCircuitInfo, Node}; +pub(crate) enum AnyBitCircuit { + B0(BitCircuit<11, 6>), + B1(BitCircuit<15, 6>), + B2(BitCircuit<19, 6>), + B3(BitCircuit<22, 6>), + B4(BitCircuit<25, 6>), + B5(BitCircuit<28, 6>), + B6(BitCircuit<31, 6>), + B7(BitCircuit<33, 6>), + B8(BitCircuit<35, 6>), + B9(BitCircuit<37, 6>), + B10(BitCircuit<39, 6>), + B11(BitCircuit<41, 6>), + B12(BitCircuit<43, 6>), + B13(BitCircuit<45, 6>), + B14(BitCircuit<47, 6>), + B15(BitCircuit<48, 6>), + B16(BitCircuit<49, 6>), + B17(BitCircuit<50, 6>), + B18(BitCircuit<51, 6>), + B19(BitCircuit<52, 6>), + B20(BitCircuit<53, 6>), + B21(BitCircuit<54, 6>), + B22(BitCircuit<55, 6>), + B23(BitCircuit<56, 6>), + B24(BitCircuit<57, 6>), + B25(BitCircuit<58, 6>), + B26(BitCircuit<59, 6>), + B27(BitCircuit<60, 6>), + B28(BitCircuit<61, 6>), + B29(BitCircuit<62, 6>), + B30(BitCircuit<63, 6>), + B31(BitCircuit<63, 6>), +} +impl BitCircuitInfo for AnyBitCircuit { + fn info(&self) -> (&[Node], &[usize], usize) { + match self { + AnyBitCircuit::B0(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B1(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B2(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B3(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B4(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B5(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B6(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B7(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B8(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B9(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B10(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B11(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B12(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B13(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B14(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B15(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B16(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B17(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B18(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B19(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B20(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B21(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B22(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B23(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B24(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B25(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B26(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B27(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B28(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B29(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B30(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B31(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + } + } +} + +impl GetBitCircuitInfo<u32> for Circuit<AnyBitCircuit, 32usize> { + fn input_size(&self) -> usize { + 2 * u32::BITS as usize + } + fn output_size(&self) -> usize { + u32::BITS as usize + } + fn get_circuit(&self, bit: usize) -> (&[Node], &[usize], usize) { + self.0[bit].info() + } +} + +pub(crate) static OUTPUT_CIRCUITS: Circuit<AnyBitCircuit, 32usize> = Circuit([ + AnyBitCircuit::B0(BitCircuit::new( + [ + Node::new(0, 0, 0), + Node::new(0, 1, 0), + Node::new(0, 0, 0), + Node::new(36, 0, 1), + Node::new(0, 0, 0), + Node::new(35, 0, 1), + Node::new(0, 0, 0), + Node::new(34, 0, 1), + Node::new(0, 0, 0), + Node::new(33, 0, 1), + Node::new(32, 0, 1), + ], + [0, 2, 4, 6, 8, 10], + 2, + )), + AnyBitCircuit::B1(BitCircuit::new( + [ + Node::new(0, 0, 0), + Node::new(0, 1, 0), + Node::new(1, 1, 0), + Node::new(0, 0, 0), + Node::new(36, 0, 2), + Node::new(36, 0, 1), + Node::new(0, 0, 0), + Node::new(35, 0, 1), + Node::new(35, 0, 2), + Node::new(0, 0, 0), + Node::new(34, 0, 1), + Node::new(34, 0, 2), + Node::new(33, 0, 1), + Node::new(33, 0, 2), + Node::new(32, 1, 0), + ], + [0, 3, 6, 9, 12, 14], + 3, + )), + AnyBitCircuit::B2(BitCircuit::new( + [ + Node::new(0, 0, 0), + Node::new(1, 1, 0), + Node::new(2, 1, 0), + Node::new(0, 1, 0), + Node::new(0, 0, 0), + Node::new(36, 0, 1), + Node::new(36, 0, 2), + Node::new(36, 0, 3), + Node::new(0, 0, 0), + Node::new(35, 0, 1), + Node::new(35, 0, 2), + Node::new(35, 0, 3), + Node::new(0, 0, 0), + Node::new(34, 0, 2), + Node::new(34, 0, 1), + Node::new(34, 0, 3), + Node::new(33, 0, 2), + Node::new(33, 3, 1), + Node::new(32, 0, 1), + ], + [0, 4, 8, 12, 16, 18], + 4, + )), + AnyBitCircuit::B3(BitCircuit::new( + [ + Node::new(0, 0, 0), + Node::new(3, 1, 0), + Node::new(1, 1, 0), + Node::new(2, 1, 0), + Node::new(0, 1, 0), + Node::new(0, 0, 0), + Node::new(36, 0, 2), + Node::new(36, 0, 4), + Node::new(36, 0, 3), + Node::new(36, 0, 1), + Node::new(0, 0, 0), + Node::new(35, 0, 3), + Node::new(35, 0, 4), + Node::new(35, 0, 2), + Node::new(35, 0, 1), + Node::new(34, 0, 3), + Node::new(34, 0, 2), + Node::new(34, 0, 4), + Node::new(34, 0, 1), + Node::new(33, 0, 3), + Node::new(33, 2, 1), + Node::new(32, 0, 1), + ], + [0, 5, 10, 15, 19, 21], + 5, + )), + AnyBitCircuit::B4(BitCircuit::new( + [ + Node::new(0, 0, 0), + Node::new(1, 1, 0), + Node::new(0, 1, 0), + Node::new(2, 1, 0), + Node::new(3, 1, 0), + Node::new(4, 1, 0), + Node::new(0, 0, 0), + Node::new(36, 0, 4), + Node::new(36, 0, 2), + Node::new(36, 0, 5), + Node::new(36, 0, 1), + Node::new(36, 0, 3), + Node::new(0, 0, 0), + Node::new(35, 0, 3), + Node::new(35, 0, 4), + Node::new(35, 0, 5), + Node::new(35, 0, 2), + Node::new(35, 0, 1), + Node::new(34, 0, 2), + Node::new(34, 0, 3), + Node::new(34, 4, 1), + Node::new(34, 0, 5), + Node::new(33, 0, 3), + Node::new(33, 1, 2), + Node::new(32, 0, 1), + ], + [0, 6, 12, 18, 22, 24], + 6, + )), + AnyBitCircuit::B5(BitCircuit::new( + [ + Node::new(0, 0, 0), + Node::new(0, 1, 0), + Node::new(4, 1, 0), + Node::new(2, 1, 0), + Node::new(1, 1, 0), + Node::new(3, 1, 0), + Node::new(5, 1, 0), + Node::new(0, 0, 0), + Node::new(36, 0, 5), + Node::new(36, 0, 1), + Node::new(36, 0, 3), + Node::new(36, 0, 4), + Node::new(36, 0, 6), + Node::new(36, 0, 2), + Node::new(0, 0, 0), + Node::new(35, 0, 5), + Node::new(35, 0, 3), + Node::new(35, 0, 1), + Node::new(35, 0, 2), + Node::new(35, 0, 4), + Node::new(35, 0, 6), + Node::new(34, 5, 1), + Node::new(34, 0, 3), + Node::new(34, 0, 2), + Node::new(34, 4, 6), + Node::new(33, 2, 3), + Node::new(33, 1, 0), + Node::new(32, 0, 1), + ], + [0, 7, 14, 21, 25, 27], + 7, + )), + AnyBitCircuit::B6(BitCircuit::new( + [ + Node::new(0, 0, 0), + Node::new(5, 1, 0), + Node::new(0, 1, 0), + Node::new(3, 1, 0), + Node::new(4, 1, 0), + Node::new(1, 1, 0), + Node::new(2, 1, 0), + Node::new(6, 1, 0), + Node::new(0, 0, 0), + Node::new(36, 0, 5), + Node::new(36, 0, 7), + Node::new(36, 0, 3), + Node::new(36, 0, 4), + Node::new(36, 0, 6), + Node::new(36, 0, 1), + Node::new(36, 0, 2), + Node::new(0, 0, 0), + Node::new(35, 0, 3), + Node::new(35, 0, 4), + Node::new(35, 0, 7), + Node::new(35, 0, 1), + Node::new(35, 0, 6), + Node::new(35, 0, 2), + Node::new(35, 0, 5), + Node::new(34, 0, 1), + Node::new(34, 4, 5), + Node::new(34, 7, 6), + Node::new(34, 3, 2), + Node::new(33, 3, 2), + Node::new(33, 0, 1), + Node::new(32, 1, 0), + ], + [0, 8, 16, 24, 28, 30], + 8, + )), + AnyBitCircuit::B7(BitCircuit::new( + [ + Node::new(0, 0, 0), + Node::new(4, 1, 0), + Node::new(3, 1, 0), + Node::new(7, 1, 0), + Node::new(0, 1, 0), + Node::new(5, 1, 0), + Node::new(1, 1, 0), + Node::new(6, 1, 0), + Node::new(2, 1, 0), + Node::new(0, 0, 0), + Node::new(36, 0, 6), + Node::new(36, 0, 5), + Node::new(36, 0, 1), + Node::new(36, 0, 4), + Node::new(36, 0, 7), + Node::new(36, 0, 3), + Node::new(36, 0, 8), + Node::new(36, 0, 2), + Node::new(35, 0, 8), + Node::new(35, 0, 4), + Node::new(35, 0, 2), + Node::new(35, 0, 1), + Node::new(35, 0, 3), + Node::new(35, 0, 7), + Node::new(35, 0, 5), + Node::new(35, 0, 6), + Node::new(34, 3, 2), + Node::new(34, 5, 6), + Node::new(34, 0, 7), + Node::new(34, 1, 4), + Node::new(33, 3, 1), + Node::new(33, 0, 2), + Node::new(32, 0, 1), + ], + [0, 9, 18, 26, 30, 32], + 9, + )), + AnyBitCircuit::B8(BitCircuit::new( + [ + Node::new(0, 0, 0), + Node::new(7, 1, 0), + Node::new(0, 1, 0), + Node::new(5, 1, 0), + Node::new(2, 1, 0), + Node::new(8, 1, 0), + Node::new(4, 1, 0), + Node::new(3, 1, 0), + Node::new(1, 1, 0), + Node::new(6, 1, 0), + Node::new(0, 0, 0), + Node::new(36, 0, 7), + Node::new(36, 0, 3), + Node::new(36, 0, 8), + Node::new(36, 0, 9), + Node::new(36, 0, 1), + Node::new(36, 0, 6), + Node::new(36, 0, 5), + Node::new(36, 0, 4), + Node::new(36, 0, 2), + Node::new(35, 0, 2), + Node::new(35, 0, 8), + Node::new(35, 9, 7), + Node::new(35, 0, 3), + Node::new(35, 0, 5), + Node::new(35, 0, 1), + Node::new(35, 0, 4), + Node::new(35, 0, 6), + Node::new(34, 1, 6), + Node::new(34, 5, 4), + Node::new(34, 3, 0), + Node::new(34, 7, 2), + Node::new(33, 2, 1), + Node::new(33, 0, 3), + Node::new(32, 0, 1), + ], + [0, 10, 20, 28, 32, 34], + 10, + )), + AnyBitCircuit::B9(BitCircuit::new( + [ + Node::new(0, 0, 0), + Node::new(0, 1, 0), + Node::new(6, 1, 0), + Node::new(9, 1, 0), + Node::new(4, 1, 0), + Node::new(3, 1, 0), + Node::new(1, 1, 0), + Node::new(2, 1, 0), + Node::new(7, 1, 0), + Node::new(5, 1, 0), + Node::new(8, 1, 0), + Node::new(0, 0, 0), + Node::new(36, 0, 8), + Node::new(36, 0, 7), + Node::new(36, 0, 10), + Node::new(36, 0, 6), + Node::new(36, 0, 4), + Node::new(36, 0, 5), + Node::new(36, 0, 3), + Node::new(36, 0, 2), + Node::new(36, 0, 1), + Node::new(36, 0, 9), + Node::new(35, 0, 1), + Node::new(35, 0, 2), + Node::new(35, 0, 10), + Node::new(35, 0, 8), + Node::new(35, 4, 7), + Node::new(35, 9, 3), + Node::new(35, 0, 6), + Node::new(35, 0, 5), + Node::new(34, 6, 0), + Node::new(34, 7, 5), + Node::new(34, 2, 4), + Node::new(34, 1, 3), + Node::new(33, 3, 1), + Node::new(33, 0, 2), + Node::new(32, 0, 1), + ], + [0, 11, 22, 30, 34, 36], + 11, + )), + AnyBitCircuit::B10(BitCircuit::new( + [ + Node::new(0, 0, 0), + Node::new(9, 1, 0), + Node::new(10, 1, 0), + Node::new(1, 1, 0), + Node::new(0, 1, 0), + Node::new(7, 1, 0), + Node::new(8, 1, 0), + Node::new(3, 1, 0), + Node::new(4, 1, 0), + Node::new(2, 1, 0), + Node::new(6, 1, 0), + Node::new(5, 1, 0), + Node::new(0, 0, 0), + Node::new(36, 0, 7), + Node::new(36, 0, 11), + Node::new(36, 0, 8), + Node::new(36, 0, 6), + Node::new(36, 0, 5), + Node::new(36, 0, 1), + Node::new(36, 0, 4), + Node::new(36, 0, 9), + Node::new(36, 0, 3), + Node::new(36, 0, 2), + Node::new(36, 0, 10), + Node::new(35, 7, 4), + Node::new(35, 0, 11), + Node::new(35, 0, 1), + Node::new(35, 8, 10), + Node::new(35, 9, 6), + Node::new(35, 0, 2), + Node::new(35, 0, 3), + Node::new(35, 0, 5), + Node::new(34, 2, 7), + Node::new(34, 5, 4), + Node::new(34, 1, 3), + Node::new(34, 6, 0), + Node::new(33, 0, 1), + Node::new(33, 3, 2), + Node::new(32, 0, 1), + ], + [0, 12, 24, 32, 36, 38], + 12, + )), + AnyBitCircuit::B11(BitCircuit::new( + [ + Node::new(0, 0, 0), + Node::new(8, 1, 0), + Node::new(3, 1, 0), + Node::new(7, 1, 0), + Node::new(6, 1, 0), + Node::new(5, 1, 0), + Node::new(2, 1, 0), + Node::new(10, 1, 0), + Node::new(0, 1, 0), + Node::new(1, 1, 0), + Node::new(11, 1, 0), + Node::new(4, 1, 0), + Node::new(9, 1, 0), + Node::new(0, 0, 0), + Node::new(36, 0, 5), + Node::new(36, 0, 12), + Node::new(36, 0, 3), + Node::new(36, 0, 7), + Node::new(36, 0, 2), + Node::new(36, 0, 8), + Node::new(36, 0, 6), + Node::new(36, 0, 4), + Node::new(36, 0, 1), + Node::new(36, 0, 10), + Node::new(36, 0, 11), + Node::new(36, 0, 9), + Node::new(35, 0, 11), + Node::new(35, 0, 1), + Node::new(35, 12, 2), + Node::new(35, 5, 10), + Node::new(35, 7, 4), + Node::new(35, 0, 3), + Node::new(35, 0, 8), + Node::new(35, 6, 9), + Node::new(34, 0, 7), + Node::new(34, 5, 3), + Node::new(34, 6, 4), + Node::new(34, 1, 2), + Node::new(33, 3, 1), + Node::new(33, 0, 2), + Node::new(32, 1, 0), + ], + [0, 13, 26, 34, 38, 40], + 13, + )), + AnyBitCircuit::B12(BitCircuit::new( + [ + Node::new(0, 0, 0), + Node::new(12, 1, 0), + Node::new(8, 1, 0), + Node::new(9, 1, 0), + Node::new(7, 1, 0), + Node::new(11, 1, 0), + Node::new(3, 1, 0), + Node::new(0, 1, 0), + Node::new(1, 1, 0), + Node::new(5, 1, 0), + Node::new(2, 1, 0), + Node::new(10, 1, 0), + Node::new(4, 1, 0), + Node::new(6, 1, 0), + Node::new(0, 0, 0), + Node::new(36, 0, 7), + Node::new(36, 0, 5), + Node::new(36, 0, 10), + Node::new(36, 0, 13), + Node::new(36, 0, 11), + Node::new(36, 0, 12), + Node::new(36, 0, 1), + Node::new(36, 0, 2), + Node::new(36, 0, 6), + Node::new(36, 0, 3), + Node::new(36, 0, 9), + Node::new(36, 0, 4), + Node::new(36, 0, 8), + Node::new(35, 3, 5), + Node::new(35, 0, 12), + Node::new(35, 1, 8), + Node::new(35, 13, 10), + Node::new(35, 9, 2), + Node::new(35, 6, 7), + Node::new(35, 0, 11), + Node::new(35, 0, 4), + Node::new(34, 7, 0), + Node::new(34, 2, 5), + Node::new(34, 1, 4), + Node::new(34, 6, 3), + Node::new(33, 3, 2), + Node::new(33, 0, 1), + Node::new(32, 0, 1), + ], + [0, 14, 28, 36, 40, 42], + 14, + )), + AnyBitCircuit::B13(BitCircuit::new( + [ + Node::new(0, 0, 0), + Node::new(10, 1, 0), + Node::new(13, 1, 0), + Node::new(3, 1, 0), + Node::new(12, 1, 0), + Node::new(11, 1, 0), + Node::new(1, 1, 0), + Node::new(6, 1, 0), + Node::new(8, 1, 0), + Node::new(9, 1, 0), + Node::new(2, 1, 0), + Node::new(4, 1, 0), + Node::new(7, 1, 0), + Node::new(0, 1, 0), + Node::new(5, 1, 0), + Node::new(0, 0, 0), + Node::new(36, 0, 12), + Node::new(36, 0, 7), + Node::new(36, 0, 13), + Node::new(36, 0, 5), + Node::new(36, 0, 3), + Node::new(36, 0, 1), + Node::new(36, 0, 4), + Node::new(36, 0, 9), + Node::new(36, 0, 10), + Node::new(36, 0, 2), + Node::new(36, 0, 8), + Node::new(36, 0, 6), + Node::new(36, 0, 11), + Node::new(36, 0, 14), + Node::new(35, 3, 11), + Node::new(35, 5, 4), + Node::new(35, 12, 8), + Node::new(35, 14, 10), + Node::new(35, 0, 2), + Node::new(35, 9, 6), + Node::new(35, 13, 7), + Node::new(35, 0, 1), + Node::new(34, 7, 1), + Node::new(34, 2, 3), + Node::new(34, 0, 6), + Node::new(34, 4, 5), + Node::new(33, 0, 1), + Node::new(33, 3, 2), + Node::new(32, 1, 0), + ], + [0, 15, 30, 38, 42, 44], + 15, + )), + AnyBitCircuit::B14(BitCircuit::new( + [ + Node::new(0, 0, 0), + Node::new(14, 1, 0), + Node::new(8, 1, 0), + Node::new(6, 1, 0), + Node::new(9, 1, 0), + Node::new(1, 1, 0), + Node::new(3, 1, 0), + Node::new(4, 1, 0), + Node::new(13, 1, 0), + Node::new(5, 1, 0), + Node::new(10, 1, 0), + Node::new(11, 1, 0), + Node::new(7, 1, 0), + Node::new(2, 1, 0), + Node::new(0, 1, 0), + Node::new(12, 1, 0), + Node::new(0, 0, 0), + Node::new(36, 0, 7), + Node::new(36, 0, 5), + Node::new(36, 0, 9), + Node::new(36, 0, 15), + Node::new(36, 0, 3), + Node::new(36, 0, 10), + Node::new(36, 0, 4), + Node::new(36, 0, 12), + Node::new(36, 0, 14), + Node::new(36, 0, 2), + Node::new(36, 0, 6), + Node::new(36, 0, 13), + Node::new(36, 0, 1), + Node::new(36, 0, 8), + Node::new(36, 0, 11), + Node::new(35, 5, 13), + Node::new(35, 12, 6), + Node::new(35, 2, 7), + Node::new(35, 3, 14), + Node::new(35, 9, 10), + Node::new(35, 1, 4), + Node::new(35, 11, 15), + Node::new(35, 0, 8), + Node::new(34, 2, 3), + Node::new(34, 7, 6), + Node::new(34, 1, 0), + Node::new(34, 4, 5), + Node::new(33, 3, 2), + Node::new(33, 1, 0), + Node::new(32, 1, 0), + ], + [0, 16, 32, 40, 44, 46], + 16, + )), + AnyBitCircuit::B15(BitCircuit::new( + [ + Node::new(0, 0, 0), + Node::new(6, 1, 0), + Node::new(7, 1, 0), + Node::new(11, 1, 0), + Node::new(4, 1, 0), + Node::new(15, 1, 0), + Node::new(2, 1, 0), + Node::new(5, 1, 0), + Node::new(8, 1, 0), + Node::new(3, 1, 0), + Node::new(9, 1, 0), + Node::new(1, 1, 0), + Node::new(10, 1, 0), + Node::new(0, 1, 0), + Node::new(14, 1, 0), + Node::new(13, 1, 0), + Node::new(12, 1, 0), + Node::new(36, 0, 2), + Node::new(36, 0, 16), + Node::new(36, 0, 13), + Node::new(36, 0, 1), + Node::new(36, 0, 10), + Node::new(36, 0, 4), + Node::new(36, 0, 8), + Node::new(36, 0, 9), + Node::new(36, 0, 14), + Node::new(36, 0, 3), + Node::new(36, 0, 11), + Node::new(36, 0, 5), + Node::new(36, 0, 12), + Node::new(36, 0, 6), + Node::new(36, 0, 15), + Node::new(36, 0, 7), + Node::new(35, 15, 14), + Node::new(35, 3, 8), + Node::new(35, 7, 9), + Node::new(35, 5, 1), + Node::new(35, 13, 12), + Node::new(35, 0, 11), + Node::new(35, 2, 6), + Node::new(35, 10, 4), + Node::new(34, 4, 1), + Node::new(34, 6, 3), + Node::new(34, 2, 5), + Node::new(34, 7, 0), + Node::new(33, 1, 0), + Node::new(33, 3, 2), + Node::new(32, 0, 1), + ], + [0, 17, 33, 41, 45, 47], + 17, + )), + AnyBitCircuit::B16(BitCircuit::new( + [ + Node::new(0, 0, 0), + Node::new(12, 1, 0), + Node::new(9, 1, 0), + Node::new(1, 1, 0), + Node::new(16, 1, 0), + Node::new(15, 1, 0), + Node::new(4, 1, 0), + Node::new(8, 1, 0), + Node::new(14, 1, 0), + Node::new(13, 1, 0), + Node::new(0, 1, 0), + Node::new(7, 1, 0), + Node::new(5, 1, 0), + Node::new(11, 1, 0), + Node::new(10, 1, 0), + Node::new(3, 1, 0), + Node::new(2, 1, 0), + Node::new(6, 1, 0), + Node::new(36, 0, 15), + Node::new(36, 0, 8), + Node::new(36, 0, 14), + Node::new(36, 0, 12), + Node::new(36, 0, 3), + Node::new(36, 0, 17), + Node::new(36, 0, 1), + Node::new(36, 0, 2), + Node::new(36, 0, 11), + Node::new(36, 0, 9), + Node::new(36, 0, 6), + Node::new(36, 0, 16), + Node::new(36, 0, 13), + Node::new(36, 0, 7), + Node::new(36, 0, 5), + Node::new(36, 10, 4), + Node::new(35, 8, 14), + Node::new(35, 10, 6), + Node::new(35, 0, 12), + Node::new(35, 13, 15), + Node::new(35, 4, 7), + Node::new(35, 3, 9), + Node::new(35, 11, 2), + Node::new(35, 5, 1), + Node::new(34, 2, 0), + Node::new(34, 6, 7), + Node::new(34, 4, 5), + Node::new(34, 1, 3), + Node::new(33, 1, 3), + Node::new(33, 2, 0), + Node::new(32, 1, 0), + ], + [0, 18, 34, 42, 46, 48], + 18, + )), + AnyBitCircuit::B17(BitCircuit::new( + [ + Node::new(0, 0, 0), + Node::new(9, 1, 0), + Node::new(0, 1, 0), + Node::new(12, 1, 0), + Node::new(10, 1, 0), + Node::new(1, 1, 0), + Node::new(8, 1, 0), + Node::new(2, 1, 0), + Node::new(6, 1, 0), + Node::new(5, 1, 0), + Node::new(7, 1, 0), + Node::new(13, 1, 0), + Node::new(15, 1, 0), + Node::new(16, 1, 0), + Node::new(3, 1, 0), + Node::new(4, 1, 0), + Node::new(14, 1, 0), + Node::new(17, 1, 0), + Node::new(11, 1, 0), + Node::new(36, 2, 13), + Node::new(36, 0, 16), + Node::new(36, 0, 8), + Node::new(36, 0, 7), + Node::new(36, 0, 3), + Node::new(36, 0, 1), + Node::new(36, 0, 10), + Node::new(36, 0, 11), + Node::new(36, 0, 12), + Node::new(36, 0, 18), + Node::new(36, 0, 9), + Node::new(36, 0, 6), + Node::new(36, 0, 14), + Node::new(36, 0, 4), + Node::new(36, 0, 15), + Node::new(36, 5, 17), + Node::new(35, 6, 8), + Node::new(35, 12, 9), + Node::new(35, 11, 0), + Node::new(35, 14, 4), + Node::new(35, 5, 15), + Node::new(35, 10, 7), + Node::new(35, 2, 1), + Node::new(35, 3, 13), + Node::new(34, 1, 0), + Node::new(34, 3, 2), + Node::new(34, 7, 6), + Node::new(34, 5, 4), + Node::new(33, 2, 1), + Node::new(33, 0, 3), + Node::new(32, 0, 1), + ], + [0, 19, 35, 43, 47, 49], + 19, + )), + AnyBitCircuit::B18(BitCircuit::new( + [ + Node::new(0, 0, 0), + Node::new(3, 1, 0), + Node::new(14, 1, 0), + Node::new(6, 1, 0), + Node::new(16, 1, 0), + Node::new(0, 1, 0), + Node::new(1, 1, 0), + Node::new(4, 1, 0), + Node::new(8, 1, 0), + Node::new(12, 1, 0), + Node::new(10, 1, 0), + Node::new(2, 1, 0), + Node::new(18, 1, 0), + Node::new(13, 1, 0), + Node::new(15, 1, 0), + Node::new(7, 1, 0), + Node::new(11, 1, 0), + Node::new(17, 1, 0), + Node::new(9, 1, 0), + Node::new(5, 1, 0), + Node::new(36, 5, 4), + Node::new(36, 6, 17), + Node::new(36, 0, 19), + Node::new(36, 0, 16), + Node::new(36, 0, 3), + Node::new(36, 0, 8), + Node::new(36, 0, 1), + Node::new(36, 0, 2), + Node::new(36, 0, 10), + Node::new(36, 0, 7), + Node::new(36, 0, 18), + Node::new(36, 0, 13), + Node::new(36, 0, 9), + Node::new(36, 11, 12), + Node::new(36, 0, 14), + Node::new(36, 0, 15), + Node::new(35, 6, 3), + Node::new(35, 5, 0), + Node::new(35, 9, 12), + Node::new(35, 8, 13), + Node::new(35, 4, 7), + Node::new(35, 2, 11), + Node::new(35, 15, 14), + Node::new(35, 10, 1), + Node::new(34, 4, 3), + Node::new(34, 0, 6), + Node::new(34, 5, 7), + Node::new(34, 2, 1), + Node::new(33, 3, 0), + Node::new(33, 1, 2), + Node::new(32, 1, 0), + ], + [0, 20, 36, 44, 48, 50], + 20, + )), + AnyBitCircuit::B19(BitCircuit::new( + [ + Node::new(0, 0, 0), + Node::new(7, 1, 0), + Node::new(0, 1, 0), + Node::new(19, 1, 0), + Node::new(8, 1, 0), + Node::new(10, 1, 0), + Node::new(5, 1, 0), + Node::new(18, 1, 0), + Node::new(9, 1, 0), + Node::new(11, 1, 0), + Node::new(14, 1, 0), + Node::new(16, 1, 0), + Node::new(4, 1, 0), + Node::new(15, 1, 0), + Node::new(2, 1, 0), + Node::new(6, 1, 0), + Node::new(17, 1, 0), + Node::new(1, 1, 0), + Node::new(3, 1, 0), + Node::new(12, 1, 0), + Node::new(13, 1, 0), + Node::new(36, 0, 15), + Node::new(36, 0, 1), + Node::new(36, 14, 7), + Node::new(36, 0, 20), + Node::new(36, 0, 12), + Node::new(36, 0, 8), + Node::new(36, 0, 6), + Node::new(36, 0, 13), + Node::new(36, 0, 10), + Node::new(36, 0, 4), + Node::new(36, 17, 16), + Node::new(36, 2, 11), + Node::new(36, 18, 3), + Node::new(36, 0, 9), + Node::new(36, 0, 5), + Node::new(36, 0, 19), + Node::new(35, 9, 11), + Node::new(35, 13, 12), + Node::new(35, 0, 8), + Node::new(35, 1, 7), + Node::new(35, 4, 15), + Node::new(35, 14, 2), + Node::new(35, 6, 3), + Node::new(35, 5, 10), + Node::new(34, 4, 0), + Node::new(34, 3, 1), + Node::new(34, 6, 7), + Node::new(34, 2, 5), + Node::new(33, 0, 3), + Node::new(33, 2, 1), + Node::new(32, 0, 1), + ], + [0, 21, 37, 45, 49, 51], + 21, + )), + AnyBitCircuit::B20(BitCircuit::new( + [ + Node::new(0, 0, 0), + Node::new(18, 1, 0), + Node::new(15, 1, 0), + Node::new(17, 1, 0), + Node::new(5, 1, 0), + Node::new(3, 1, 0), + Node::new(2, 1, 0), + Node::new(1, 1, 0), + Node::new(9, 1, 0), + Node::new(7, 1, 0), + Node::new(14, 1, 0), + Node::new(20, 1, 0), + Node::new(4, 1, 0), + Node::new(16, 1, 0), + Node::new(10, 1, 0), + Node::new(11, 1, 0), + Node::new(12, 1, 0), + Node::new(8, 1, 0), + Node::new(19, 1, 0), + Node::new(0, 1, 0), + Node::new(13, 1, 0), + Node::new(6, 1, 0), + Node::new(36, 0, 16), + Node::new(36, 12, 11), + Node::new(36, 0, 9), + Node::new(36, 0, 10), + Node::new(36, 0, 21), + Node::new(36, 0, 14), + Node::new(36, 5, 18), + Node::new(36, 6, 1), + Node::new(36, 0, 17), + Node::new(36, 19, 13), + Node::new(36, 0, 2), + Node::new(36, 0, 8), + Node::new(36, 7, 3), + Node::new(36, 0, 4), + Node::new(36, 0, 20), + Node::new(36, 0, 15), + Node::new(35, 0, 1), + Node::new(35, 4, 3), + Node::new(35, 8, 9), + Node::new(35, 5, 7), + Node::new(35, 15, 6), + Node::new(35, 2, 10), + Node::new(35, 11, 12), + Node::new(35, 13, 14), + Node::new(34, 1, 3), + Node::new(34, 2, 0), + Node::new(34, 5, 4), + Node::new(34, 7, 6), + Node::new(33, 3, 2), + Node::new(33, 0, 1), + Node::new(32, 0, 1), + ], + [0, 22, 38, 46, 50, 52], + 22, + )), + AnyBitCircuit::B21(BitCircuit::new( + [ + Node::new(0, 0, 0), + Node::new(15, 1, 0), + Node::new(13, 1, 0), + Node::new(18, 1, 0), + Node::new(16, 1, 0), + Node::new(9, 1, 0), + Node::new(7, 1, 0), + Node::new(17, 1, 0), + Node::new(4, 1, 0), + Node::new(21, 1, 0), + Node::new(12, 1, 0), + Node::new(1, 1, 0), + Node::new(5, 1, 0), + Node::new(2, 1, 0), + Node::new(19, 1, 0), + Node::new(0, 1, 0), + Node::new(14, 1, 0), + Node::new(6, 1, 0), + Node::new(8, 1, 0), + Node::new(3, 1, 0), + Node::new(11, 1, 0), + Node::new(10, 1, 0), + Node::new(20, 1, 0), + Node::new(36, 11, 7), + Node::new(36, 0, 10), + Node::new(36, 0, 21), + Node::new(36, 12, 9), + Node::new(36, 19, 14), + Node::new(36, 0, 5), + Node::new(36, 0, 20), + Node::new(36, 0, 1), + Node::new(36, 8, 22), + Node::new(36, 13, 3), + Node::new(36, 0, 18), + Node::new(36, 0, 16), + Node::new(36, 0, 6), + Node::new(36, 0, 2), + Node::new(36, 0, 17), + Node::new(36, 15, 4), + Node::new(35, 13, 3), + Node::new(35, 6, 4), + Node::new(35, 12, 7), + Node::new(35, 1, 8), + Node::new(35, 10, 15), + Node::new(35, 5, 0), + Node::new(35, 2, 9), + Node::new(35, 14, 11), + Node::new(34, 2, 1), + Node::new(34, 5, 0), + Node::new(34, 4, 3), + Node::new(34, 7, 6), + Node::new(33, 3, 2), + Node::new(33, 0, 1), + Node::new(32, 0, 1), + ], + [0, 23, 39, 47, 51, 53], + 23, + )), + AnyBitCircuit::B22(BitCircuit::new( + [ + Node::new(0, 0, 0), + Node::new(19, 1, 0), + Node::new(5, 1, 0), + Node::new(2, 1, 0), + Node::new(7, 1, 0), + Node::new(6, 1, 0), + Node::new(12, 1, 0), + Node::new(17, 1, 0), + Node::new(10, 1, 0), + Node::new(4, 1, 0), + Node::new(20, 1, 0), + Node::new(0, 1, 0), + Node::new(21, 1, 0), + Node::new(3, 1, 0), + Node::new(15, 1, 0), + Node::new(13, 1, 0), + Node::new(14, 1, 0), + Node::new(1, 1, 0), + Node::new(22, 1, 0), + Node::new(18, 1, 0), + Node::new(8, 1, 0), + Node::new(9, 1, 0), + Node::new(11, 1, 0), + Node::new(16, 1, 0), + Node::new(36, 13, 1), + Node::new(36, 0, 16), + Node::new(36, 3, 19), + Node::new(36, 11, 23), + Node::new(36, 0, 15), + Node::new(36, 0, 22), + Node::new(36, 5, 18), + Node::new(36, 0, 21), + Node::new(36, 9, 10), + Node::new(36, 0, 8), + Node::new(36, 0, 6), + Node::new(36, 17, 7), + Node::new(36, 0, 4), + Node::new(36, 2, 12), + Node::new(36, 0, 14), + Node::new(36, 0, 20), + Node::new(35, 10, 8), + Node::new(35, 4, 13), + Node::new(35, 12, 14), + Node::new(35, 5, 0), + Node::new(35, 7, 11), + Node::new(35, 1, 6), + Node::new(35, 15, 3), + Node::new(35, 9, 2), + Node::new(34, 6, 0), + Node::new(34, 7, 5), + Node::new(34, 2, 3), + Node::new(34, 4, 1), + Node::new(33, 0, 1), + Node::new(33, 2, 3), + Node::new(32, 1, 0), + ], + [0, 24, 40, 48, 52, 54], + 24, + )), + AnyBitCircuit::B23(BitCircuit::new( + [ + Node::new(0, 0, 0), + Node::new(9, 1, 0), + Node::new(22, 1, 0), + Node::new(12, 1, 0), + Node::new(3, 1, 0), + Node::new(23, 1, 0), + Node::new(10, 1, 0), + Node::new(16, 1, 0), + Node::new(2, 1, 0), + Node::new(21, 1, 0), + Node::new(17, 1, 0), + Node::new(19, 1, 0), + Node::new(20, 1, 0), + Node::new(8, 1, 0), + Node::new(7, 1, 0), + Node::new(11, 1, 0), + Node::new(13, 1, 0), + Node::new(0, 1, 0), + Node::new(1, 1, 0), + Node::new(18, 1, 0), + Node::new(6, 1, 0), + Node::new(14, 1, 0), + Node::new(5, 1, 0), + Node::new(15, 1, 0), + Node::new(4, 1, 0), + Node::new(36, 4, 11), + Node::new(36, 8, 19), + Node::new(36, 18, 10), + Node::new(36, 0, 1), + Node::new(36, 0, 21), + Node::new(36, 0, 23), + Node::new(36, 14, 5), + Node::new(36, 17, 7), + Node::new(36, 24, 12), + Node::new(36, 0, 6), + Node::new(36, 0, 16), + Node::new(36, 0, 15), + Node::new(36, 20, 2), + Node::new(36, 22, 9), + Node::new(36, 0, 3), + Node::new(36, 0, 13), + Node::new(35, 15, 7), + Node::new(35, 5, 6), + Node::new(35, 9, 1), + Node::new(35, 4, 12), + Node::new(35, 14, 8), + Node::new(35, 11, 0), + Node::new(35, 10, 13), + Node::new(35, 3, 2), + Node::new(34, 5, 1), + Node::new(34, 2, 3), + Node::new(34, 7, 6), + Node::new(34, 0, 4), + Node::new(33, 3, 1), + Node::new(33, 2, 0), + Node::new(32, 0, 1), + ], + [0, 25, 41, 49, 53, 55], + 25, + )), + AnyBitCircuit::B24(BitCircuit::new( + [ + Node::new(0, 0, 0), + Node::new(2, 1, 0), + Node::new(16, 1, 0), + Node::new(0, 1, 0), + Node::new(6, 1, 0), + Node::new(22, 1, 0), + Node::new(14, 1, 0), + Node::new(15, 1, 0), + Node::new(19, 1, 0), + Node::new(20, 1, 0), + Node::new(21, 1, 0), + Node::new(13, 1, 0), + Node::new(1, 1, 0), + Node::new(24, 1, 0), + Node::new(11, 1, 0), + Node::new(23, 1, 0), + Node::new(3, 1, 0), + Node::new(17, 1, 0), + Node::new(8, 1, 0), + Node::new(10, 1, 0), + Node::new(12, 1, 0), + Node::new(9, 1, 0), + Node::new(4, 1, 0), + Node::new(7, 1, 0), + Node::new(5, 1, 0), + Node::new(18, 1, 0), + Node::new(36, 23, 15), + Node::new(36, 0, 7), + Node::new(36, 0, 20), + Node::new(36, 12, 17), + Node::new(36, 0, 14), + Node::new(36, 0, 19), + Node::new(36, 1, 25), + Node::new(36, 18, 13), + Node::new(36, 0, 6), + Node::new(36, 0, 21), + Node::new(36, 16, 8), + Node::new(36, 22, 9), + Node::new(36, 24, 10), + Node::new(36, 3, 2), + Node::new(36, 4, 5), + Node::new(36, 0, 11), + Node::new(35, 1, 0), + Node::new(35, 8, 14), + Node::new(35, 13, 7), + Node::new(35, 4, 10), + Node::new(35, 9, 3), + Node::new(35, 2, 11), + Node::new(35, 5, 6), + Node::new(35, 15, 12), + Node::new(34, 5, 2), + Node::new(34, 3, 0), + Node::new(34, 4, 7), + Node::new(34, 6, 1), + Node::new(33, 3, 0), + Node::new(33, 2, 1), + Node::new(32, 1, 0), + ], + [0, 26, 42, 50, 54, 56], + 26, + )), + AnyBitCircuit::B25(BitCircuit::new( + [ + Node::new(0, 0, 0), + Node::new(7, 1, 0), + Node::new(21, 1, 0), + Node::new(5, 1, 0), + Node::new(19, 1, 0), + Node::new(23, 1, 0), + Node::new(9, 1, 0), + Node::new(8, 1, 0), + Node::new(6, 1, 0), + Node::new(18, 1, 0), + Node::new(0, 1, 0), + Node::new(12, 1, 0), + Node::new(20, 1, 0), + Node::new(10, 1, 0), + Node::new(11, 1, 0), + Node::new(17, 1, 0), + Node::new(13, 1, 0), + Node::new(1, 1, 0), + Node::new(14, 1, 0), + Node::new(15, 1, 0), + Node::new(24, 1, 0), + Node::new(25, 1, 0), + Node::new(22, 1, 0), + Node::new(3, 1, 0), + Node::new(4, 1, 0), + Node::new(16, 1, 0), + Node::new(2, 1, 0), + Node::new(36, 17, 15), + Node::new(36, 10, 25), + Node::new(36, 0, 11), + Node::new(36, 0, 13), + Node::new(36, 0, 19), + Node::new(36, 0, 16), + Node::new(36, 7, 20), + Node::new(36, 0, 14), + Node::new(36, 24, 12), + Node::new(36, 8, 22), + Node::new(36, 3, 2), + Node::new(36, 0, 18), + Node::new(36, 1, 5), + Node::new(36, 26, 9), + Node::new(36, 23, 4), + Node::new(36, 6, 21), + Node::new(35, 2, 8), + Node::new(35, 4, 12), + Node::new(35, 7, 14), + Node::new(35, 1, 6), + Node::new(35, 3, 13), + Node::new(35, 11, 9), + Node::new(35, 0, 15), + Node::new(35, 5, 10), + Node::new(34, 2, 1), + Node::new(34, 7, 6), + Node::new(34, 4, 5), + Node::new(34, 0, 3), + Node::new(33, 2, 3), + Node::new(33, 0, 1), + Node::new(32, 0, 1), + ], + [0, 27, 43, 51, 55, 57], + 27, + )), + AnyBitCircuit::B26(BitCircuit::new( + [ + Node::new(0, 0, 0), + Node::new(4, 1, 0), + Node::new(21, 1, 0), + Node::new(5, 1, 0), + Node::new(22, 1, 0), + Node::new(2, 1, 0), + Node::new(11, 1, 0), + Node::new(24, 1, 0), + Node::new(3, 1, 0), + Node::new(20, 1, 0), + Node::new(7, 1, 0), + Node::new(25, 1, 0), + Node::new(14, 1, 0), + Node::new(9, 1, 0), + Node::new(13, 1, 0), + Node::new(15, 1, 0), + Node::new(23, 1, 0), + Node::new(18, 1, 0), + Node::new(8, 1, 0), + Node::new(16, 1, 0), + Node::new(6, 1, 0), + Node::new(0, 1, 0), + Node::new(12, 1, 0), + Node::new(17, 1, 0), + Node::new(10, 1, 0), + Node::new(26, 1, 0), + Node::new(19, 1, 0), + Node::new(1, 1, 0), + Node::new(36, 0, 12), + Node::new(36, 0, 15), + Node::new(36, 13, 11), + Node::new(36, 21, 19), + Node::new(36, 10, 16), + Node::new(36, 1, 9), + Node::new(36, 3, 2), + Node::new(36, 0, 14), + Node::new(36, 20, 4), + Node::new(36, 5, 17), + Node::new(36, 27, 23), + Node::new(36, 8, 26), + Node::new(36, 0, 22), + Node::new(36, 0, 6), + Node::new(36, 24, 25), + Node::new(36, 18, 7), + Node::new(35, 1, 4), + Node::new(35, 0, 8), + Node::new(35, 13, 11), + Node::new(35, 3, 15), + Node::new(35, 9, 14), + Node::new(35, 7, 6), + Node::new(35, 12, 5), + Node::new(35, 10, 2), + Node::new(34, 6, 3), + Node::new(34, 1, 4), + Node::new(34, 5, 7), + Node::new(34, 2, 0), + Node::new(33, 3, 2), + Node::new(33, 0, 1), + Node::new(32, 0, 1), + ], + [0, 28, 44, 52, 56, 58], + 28, + )), + AnyBitCircuit::B27(BitCircuit::new( + [ + Node::new(0, 0, 0), + Node::new(6, 1, 0), + Node::new(22, 1, 0), + Node::new(18, 1, 0), + Node::new(13, 1, 0), + Node::new(24, 1, 0), + Node::new(17, 1, 0), + Node::new(9, 1, 0), + Node::new(0, 1, 0), + Node::new(2, 1, 0), + Node::new(20, 1, 0), + Node::new(10, 1, 0), + Node::new(11, 1, 0), + Node::new(5, 1, 0), + Node::new(14, 1, 0), + Node::new(4, 1, 0), + Node::new(7, 1, 0), + Node::new(26, 1, 0), + Node::new(19, 1, 0), + Node::new(16, 1, 0), + Node::new(27, 1, 0), + Node::new(21, 1, 0), + Node::new(3, 1, 0), + Node::new(15, 1, 0), + Node::new(25, 1, 0), + Node::new(1, 1, 0), + Node::new(8, 1, 0), + Node::new(12, 1, 0), + Node::new(23, 1, 0), + Node::new(36, 0, 27), + Node::new(36, 15, 10), + Node::new(36, 13, 21), + Node::new(36, 11, 17), + Node::new(36, 9, 3), + Node::new(36, 7, 24), + Node::new(36, 25, 6), + Node::new(36, 1, 2), + Node::new(36, 16, 28), + Node::new(36, 12, 20), + Node::new(36, 8, 19), + Node::new(36, 0, 4), + Node::new(36, 22, 18), + Node::new(36, 26, 5), + Node::new(36, 0, 14), + Node::new(36, 0, 23), + Node::new(35, 15, 8), + Node::new(35, 10, 13), + Node::new(35, 4, 3), + Node::new(35, 6, 5), + Node::new(35, 0, 1), + Node::new(35, 12, 9), + Node::new(35, 14, 7), + Node::new(35, 11, 2), + Node::new(34, 0, 5), + Node::new(34, 7, 3), + Node::new(34, 6, 2), + Node::new(34, 4, 1), + Node::new(33, 3, 2), + Node::new(33, 1, 0), + Node::new(32, 0, 1), + ], + [0, 29, 45, 53, 57, 59], + 29, + )), + AnyBitCircuit::B28(BitCircuit::new( + [ + Node::new(0, 0, 0), + Node::new(21, 1, 0), + Node::new(7, 1, 0), + Node::new(23, 1, 0), + Node::new(18, 1, 0), + Node::new(16, 1, 0), + Node::new(12, 1, 0), + Node::new(3, 1, 0), + Node::new(15, 1, 0), + Node::new(17, 1, 0), + Node::new(0, 1, 0), + Node::new(27, 1, 0), + Node::new(2, 1, 0), + Node::new(22, 1, 0), + Node::new(13, 1, 0), + Node::new(4, 1, 0), + Node::new(10, 1, 0), + Node::new(9, 1, 0), + Node::new(24, 1, 0), + Node::new(5, 1, 0), + Node::new(11, 1, 0), + Node::new(1, 1, 0), + Node::new(8, 1, 0), + Node::new(6, 1, 0), + Node::new(14, 1, 0), + Node::new(28, 1, 0), + Node::new(26, 1, 0), + Node::new(19, 1, 0), + Node::new(20, 1, 0), + Node::new(25, 1, 0), + Node::new(36, 16, 26), + Node::new(36, 17, 29), + Node::new(36, 23, 13), + Node::new(36, 7, 27), + Node::new(36, 0, 14), + Node::new(36, 15, 28), + Node::new(36, 19, 1), + Node::new(36, 12, 4), + Node::new(36, 0, 24), + Node::new(36, 0, 8), + Node::new(36, 22, 18), + Node::new(36, 21, 9), + Node::new(36, 10, 5), + Node::new(36, 20, 11), + Node::new(36, 6, 25), + Node::new(36, 2, 3), + Node::new(35, 9, 15), + Node::new(35, 11, 1), + Node::new(35, 4, 6), + Node::new(35, 5, 14), + Node::new(35, 3, 13), + Node::new(35, 7, 0), + Node::new(35, 12, 10), + Node::new(35, 8, 2), + Node::new(34, 0, 4), + Node::new(34, 2, 1), + Node::new(34, 6, 3), + Node::new(34, 7, 5), + Node::new(33, 1, 0), + Node::new(33, 3, 2), + Node::new(32, 0, 1), + ], + [0, 30, 46, 54, 58, 60], + 30, + )), + AnyBitCircuit::B29(BitCircuit::new( + [ + Node::new(0, 0, 0), + Node::new(15, 1, 0), + Node::new(8, 1, 0), + Node::new(10, 1, 0), + Node::new(19, 1, 0), + Node::new(25, 1, 0), + Node::new(22, 1, 0), + Node::new(20, 1, 0), + Node::new(16, 1, 0), + Node::new(4, 1, 0), + Node::new(5, 1, 0), + Node::new(28, 1, 0), + Node::new(24, 1, 0), + Node::new(12, 1, 0), + Node::new(0, 1, 0), + Node::new(1, 1, 0), + Node::new(11, 1, 0), + Node::new(27, 1, 0), + Node::new(9, 1, 0), + Node::new(18, 1, 0), + Node::new(3, 1, 0), + Node::new(17, 1, 0), + Node::new(29, 1, 0), + Node::new(14, 1, 0), + Node::new(26, 1, 0), + Node::new(6, 1, 0), + Node::new(21, 1, 0), + Node::new(23, 1, 0), + Node::new(2, 1, 0), + Node::new(7, 1, 0), + Node::new(13, 1, 0), + Node::new(36, 30, 22), + Node::new(36, 16, 17), + Node::new(36, 29, 27), + Node::new(36, 2, 12), + Node::new(36, 9, 7), + Node::new(36, 20, 4), + Node::new(36, 18, 5), + Node::new(36, 28, 19), + Node::new(36, 0, 23), + Node::new(36, 3, 24), + Node::new(36, 13, 11), + Node::new(36, 0, 1), + Node::new(36, 15, 21), + Node::new(36, 25, 6), + Node::new(36, 10, 26), + Node::new(36, 14, 8), + Node::new(35, 4, 10), + Node::new(35, 8, 13), + Node::new(35, 11, 2), + Node::new(35, 7, 9), + Node::new(35, 12, 6), + Node::new(35, 5, 1), + Node::new(35, 14, 0), + Node::new(35, 15, 3), + Node::new(34, 1, 3), + Node::new(34, 2, 5), + Node::new(34, 7, 0), + Node::new(34, 4, 6), + Node::new(33, 1, 3), + Node::new(33, 0, 2), + Node::new(32, 1, 0), + ], + [0, 31, 47, 55, 59, 61], + 31, + )), + AnyBitCircuit::B30(BitCircuit::new( + [ + Node::new(0, 0, 0), + Node::new(21, 1, 0), + Node::new(7, 1, 0), + Node::new(24, 1, 0), + Node::new(23, 1, 0), + Node::new(9, 1, 0), + Node::new(26, 1, 0), + Node::new(8, 1, 0), + Node::new(20, 1, 0), + Node::new(3, 1, 0), + Node::new(30, 1, 0), + Node::new(4, 1, 0), + Node::new(25, 1, 0), + Node::new(29, 1, 0), + Node::new(0, 1, 0), + Node::new(2, 1, 0), + Node::new(22, 1, 0), + Node::new(28, 1, 0), + Node::new(1, 1, 0), + Node::new(18, 1, 0), + Node::new(14, 1, 0), + Node::new(11, 1, 0), + Node::new(12, 1, 0), + Node::new(6, 1, 0), + Node::new(17, 1, 0), + Node::new(27, 1, 0), + Node::new(16, 1, 0), + Node::new(15, 1, 0), + Node::new(19, 1, 0), + Node::new(10, 1, 0), + Node::new(13, 1, 0), + Node::new(5, 1, 0), + Node::new(36, 0, 27), + Node::new(36, 29, 6), + Node::new(36, 31, 1), + Node::new(36, 30, 13), + Node::new(36, 21, 25), + Node::new(36, 15, 19), + Node::new(36, 23, 16), + Node::new(36, 7, 3), + Node::new(36, 9, 28), + Node::new(36, 11, 8), + Node::new(36, 14, 26), + Node::new(36, 20, 10), + Node::new(36, 22, 17), + Node::new(36, 18, 24), + Node::new(36, 5, 12), + Node::new(36, 2, 4), + Node::new(35, 5, 1), + Node::new(35, 6, 11), + Node::new(35, 10, 7), + Node::new(35, 13, 14), + Node::new(35, 8, 4), + Node::new(35, 0, 15), + Node::new(35, 2, 3), + Node::new(35, 9, 12), + Node::new(34, 3, 6), + Node::new(34, 2, 7), + Node::new(34, 0, 1), + Node::new(34, 5, 4), + Node::new(33, 3, 0), + Node::new(33, 1, 2), + Node::new(32, 0, 1), + ], + [0, 32, 48, 56, 60, 62], + 32, + )), + AnyBitCircuit::B31(BitCircuit::new( + [ + Node::new(16, 1, 0), + Node::new(12, 1, 0), + Node::new(1, 1, 0), + Node::new(2, 1, 0), + Node::new(23, 1, 0), + Node::new(6, 1, 0), + Node::new(14, 1, 0), + Node::new(8, 1, 0), + Node::new(5, 1, 0), + Node::new(26, 1, 0), + Node::new(15, 1, 0), + Node::new(3, 1, 0), + Node::new(20, 1, 0), + Node::new(7, 1, 0), + Node::new(28, 1, 0), + Node::new(13, 1, 0), + Node::new(0, 1, 0), + Node::new(22, 1, 0), + Node::new(29, 1, 0), + Node::new(30, 1, 0), + Node::new(27, 1, 0), + Node::new(17, 1, 0), + Node::new(9, 1, 0), + Node::new(11, 1, 0), + Node::new(21, 1, 0), + Node::new(4, 1, 0), + Node::new(19, 1, 0), + Node::new(10, 1, 0), + Node::new(18, 1, 0), + Node::new(24, 1, 0), + Node::new(25, 1, 0), + Node::new(31, 1, 0), + Node::new(36, 7, 29), + Node::new(36, 27, 9), + Node::new(36, 11, 26), + Node::new(36, 3, 28), + Node::new(36, 22, 30), + Node::new(36, 23, 20), + Node::new(36, 10, 31), + Node::new(36, 6, 19), + Node::new(36, 13, 4), + Node::new(36, 8, 24), + Node::new(36, 2, 21), + Node::new(36, 15, 18), + Node::new(36, 25, 12), + Node::new(36, 5, 17), + Node::new(36, 1, 14), + Node::new(36, 16, 0), + Node::new(35, 2, 5), + Node::new(35, 10, 4), + Node::new(35, 8, 6), + Node::new(35, 9, 11), + Node::new(35, 15, 0), + Node::new(35, 12, 14), + Node::new(35, 13, 7), + Node::new(35, 3, 1), + Node::new(34, 0, 2), + Node::new(34, 4, 5), + Node::new(34, 7, 6), + Node::new(34, 1, 3), + Node::new(33, 3, 0), + Node::new(33, 1, 2), + Node::new(32, 1, 0), + ], + [0, 32, 48, 56, 60, 62], + 32, + )), +]);
@@ -0,0 +1,257 @@
+use crate::tfhe::bdd_arithmetic::{BitCircuit, BitCircuitInfo, Circuit, GetBitCircuitInfo, Node}; +pub(crate) enum AnyBitCircuit { + B0(BitCircuit<219, 64>), +} +impl BitCircuitInfo for AnyBitCircuit { + fn info(&self) -> (&[Node], &[usize], usize) { + match self { + AnyBitCircuit::B0(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + } + } +} + +impl GetBitCircuitInfo<u32> for Circuit<AnyBitCircuit, 1usize> { + fn input_size(&self) -> usize { + 2 * u32::BITS as usize + } + fn output_size(&self) -> usize { + 1 + } + fn get_circuit(&self, bit: usize) -> (&[Node], &[usize], usize) { + self.0[bit].info() + } +} + +pub(crate) static OUTPUT_CIRCUITS: Circuit<AnyBitCircuit, 1usize> = Circuit([AnyBitCircuit::B0(BitCircuit::new( + [ + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(32, 1, 0), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(0, 0, 2), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(33, 1, 2), + Node::new(33, 2, 0), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(1, 3, 2), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(34, 1, 2), + Node::new(34, 2, 0), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(2, 3, 2), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(35, 2, 0), + Node::new(35, 1, 2), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(3, 2, 3), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(36, 1, 2), + Node::new(36, 2, 0), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(4, 3, 2), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(37, 1, 2), + Node::new(37, 2, 0), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(5, 3, 2), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(38, 2, 0), + Node::new(38, 1, 2), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(6, 2, 3), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(39, 2, 0), + Node::new(39, 1, 2), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(7, 2, 3), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(40, 1, 2), + Node::new(40, 2, 0), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(8, 3, 2), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(41, 1, 2), + Node::new(41, 2, 0), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(9, 3, 2), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(42, 2, 0), + Node::new(42, 1, 2), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(10, 2, 3), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(43, 2, 0), + Node::new(43, 1, 2), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(11, 2, 3), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(44, 1, 2), + Node::new(44, 2, 0), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(12, 3, 2), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(45, 1, 2), + Node::new(45, 2, 0), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(13, 3, 2), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(46, 2, 0), + Node::new(46, 1, 2), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(14, 2, 3), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(47, 1, 2), + Node::new(47, 2, 0), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(15, 3, 2), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(48, 2, 0), + Node::new(48, 1, 2), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(16, 2, 3), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(49, 1, 2), + Node::new(49, 2, 0), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(17, 3, 2), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(50, 2, 0), + Node::new(50, 1, 2), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(18, 2, 3), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(51, 2, 0), + Node::new(51, 1, 2), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(19, 2, 3), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(52, 1, 2), + Node::new(52, 2, 0), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(20, 3, 2), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(53, 2, 0), + Node::new(53, 1, 2), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(21, 2, 3), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(54, 1, 2), + Node::new(54, 2, 0), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(22, 3, 2), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(55, 1, 2), + Node::new(55, 2, 0), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(23, 3, 2), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(56, 2, 0), + Node::new(56, 1, 2), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(24, 2, 3), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(57, 1, 2), + Node::new(57, 2, 0), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(25, 3, 2), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(58, 2, 0), + Node::new(58, 1, 2), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(26, 2, 3), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(59, 2, 0), + Node::new(59, 1, 2), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(27, 2, 3), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(60, 2, 0), + Node::new(60, 1, 2), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(28, 2, 3), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(61, 1, 2), + Node::new(61, 2, 0), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(29, 3, 2), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(62, 1, 2), + Node::new(62, 2, 0), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(30, 3, 2), + Node::new(63, 2, 1), + Node::new(63, 0, 2), + Node::new(31, 0, 1), + ], + [ + 0, 3, 6, 10, 13, 17, 20, 24, 27, 31, 34, 38, 41, 45, 48, 52, 55, 59, 62, 66, 69, 73, 76, 80, 83, 87, 90, 94, 97, 101, + 104, 108, 111, 115, 118, 122, 125, 129, 132, 136, 139, 143, 146, 150, 153, 157, 160, 164, 167, 171, 174, 178, 181, 185, + 188, 192, 195, 199, 202, 206, 209, 213, 216, 218, + ], + 4, +))]);
@@ -0,0 +1,257 @@
+use crate::tfhe::bdd_arithmetic::{BitCircuit, BitCircuitInfo, Circuit, GetBitCircuitInfo, Node}; +pub(crate) enum AnyBitCircuit { + B0(BitCircuit<219, 64>), +} +impl BitCircuitInfo for AnyBitCircuit { + fn info(&self) -> (&[Node], &[usize], usize) { + match self { + AnyBitCircuit::B0(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + } + } +} + +impl GetBitCircuitInfo<u32> for Circuit<AnyBitCircuit, 1usize> { + fn input_size(&self) -> usize { + 2 * u32::BITS as usize + } + fn output_size(&self) -> usize { + 1 + } + fn get_circuit(&self, bit: usize) -> (&[Node], &[usize], usize) { + self.0[bit].info() + } +} + +pub(crate) static OUTPUT_CIRCUITS: Circuit<AnyBitCircuit, 1usize> = Circuit([AnyBitCircuit::B0(BitCircuit::new( + [ + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(32, 1, 0), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(0, 0, 2), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(33, 2, 0), + Node::new(33, 1, 2), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(1, 2, 3), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(34, 2, 0), + Node::new(34, 1, 2), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(2, 2, 3), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(35, 1, 2), + Node::new(35, 2, 0), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(3, 3, 2), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(36, 2, 0), + Node::new(36, 1, 2), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(4, 2, 3), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(37, 2, 0), + Node::new(37, 1, 2), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(5, 2, 3), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(38, 1, 2), + Node::new(38, 2, 0), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(6, 3, 2), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(39, 2, 0), + Node::new(39, 1, 2), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(7, 2, 3), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(40, 1, 2), + Node::new(40, 2, 0), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(8, 3, 2), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(41, 1, 2), + Node::new(41, 2, 0), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(9, 3, 2), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(42, 1, 2), + Node::new(42, 2, 0), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(10, 3, 2), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(43, 2, 0), + Node::new(43, 1, 2), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(11, 2, 3), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(44, 1, 2), + Node::new(44, 2, 0), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(12, 3, 2), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(45, 2, 0), + Node::new(45, 1, 2), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(13, 2, 3), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(46, 1, 2), + Node::new(46, 2, 0), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(14, 3, 2), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(47, 2, 0), + Node::new(47, 1, 2), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(15, 2, 3), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(48, 2, 0), + Node::new(48, 1, 2), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(16, 2, 3), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(49, 1, 2), + Node::new(49, 2, 0), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(17, 3, 2), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(50, 1, 2), + Node::new(50, 2, 0), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(18, 3, 2), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(51, 1, 2), + Node::new(51, 2, 0), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(19, 3, 2), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(52, 2, 0), + Node::new(52, 1, 2), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(20, 2, 3), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(53, 2, 0), + Node::new(53, 1, 2), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(21, 2, 3), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(54, 2, 0), + Node::new(54, 1, 2), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(22, 2, 3), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(55, 1, 2), + Node::new(55, 2, 0), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(23, 3, 2), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(56, 2, 0), + Node::new(56, 1, 2), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(24, 2, 3), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(57, 1, 2), + Node::new(57, 2, 0), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(25, 3, 2), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(58, 2, 0), + Node::new(58, 1, 2), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(26, 2, 3), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(59, 2, 0), + Node::new(59, 1, 2), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(27, 2, 3), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(60, 2, 0), + Node::new(60, 1, 2), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(28, 2, 3), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(61, 2, 0), + Node::new(61, 1, 2), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(29, 2, 3), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(62, 2, 0), + Node::new(62, 1, 2), + Node::new(0, 0, 0), + Node::new(0, 1, 1), + Node::new(30, 2, 3), + Node::new(63, 2, 0), + Node::new(63, 1, 2), + Node::new(31, 0, 1), + ], + [ + 0, 3, 6, 10, 13, 17, 20, 24, 27, 31, 34, 38, 41, 45, 48, 52, 55, 59, 62, 66, 69, 73, 76, 80, 83, 87, 90, 94, 97, 101, + 104, 108, 111, 115, 118, 122, 125, 129, 132, 136, 139, 143, 146, 150, 153, 157, 160, 164, 167, 171, 174, 178, 181, 185, + 188, 192, 195, 199, 202, 206, 209, 213, 216, 218, + ], + 4, +))]);
@@ -0,0 +1,1762 @@
+use crate::tfhe::bdd_arithmetic::{BitCircuit, BitCircuitInfo, Circuit, GetBitCircuitInfo, Node}; +pub(crate) enum AnyBitCircuit { + B0(BitCircuit<63, 6>), + B1(BitCircuit<62, 6>), + B2(BitCircuit<61, 6>), + B3(BitCircuit<60, 6>), + B4(BitCircuit<59, 6>), + B5(BitCircuit<58, 6>), + B6(BitCircuit<57, 6>), + B7(BitCircuit<56, 6>), + B8(BitCircuit<55, 6>), + B9(BitCircuit<54, 6>), + B10(BitCircuit<53, 6>), + B11(BitCircuit<52, 6>), + B12(BitCircuit<51, 6>), + B13(BitCircuit<50, 6>), + B14(BitCircuit<49, 6>), + B15(BitCircuit<48, 6>), + B16(BitCircuit<47, 6>), + B17(BitCircuit<45, 6>), + B18(BitCircuit<43, 6>), + B19(BitCircuit<41, 6>), + B20(BitCircuit<39, 6>), + B21(BitCircuit<37, 6>), + B22(BitCircuit<35, 6>), + B23(BitCircuit<33, 6>), + B24(BitCircuit<31, 6>), + B25(BitCircuit<28, 6>), + B26(BitCircuit<25, 6>), + B27(BitCircuit<22, 6>), + B28(BitCircuit<19, 6>), + B29(BitCircuit<15, 6>), + B30(BitCircuit<11, 6>), + B31(BitCircuit<1, 1>), +} +impl BitCircuitInfo for AnyBitCircuit { + fn info(&self) -> (&[Node], &[usize], usize) { + match self { + AnyBitCircuit::B0(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B1(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B2(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B3(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B4(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B5(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B6(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B7(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B8(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B9(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B10(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B11(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B12(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B13(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B14(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B15(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B16(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B17(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B18(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B19(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B20(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B21(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B22(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B23(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B24(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B25(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B26(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B27(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B28(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B29(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B30(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B31(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + } + } +} + +impl GetBitCircuitInfo<u32> for Circuit<AnyBitCircuit, 32usize> { + fn input_size(&self) -> usize { + 2 * u32::BITS as usize + } + fn output_size(&self) -> usize { + u32::BITS as usize + } + fn get_circuit(&self, bit: usize) -> (&[Node], &[usize], usize) { + self.0[bit].info() + } +} + +pub(crate) static OUTPUT_CIRCUITS: Circuit<AnyBitCircuit, 32usize> = Circuit([ + AnyBitCircuit::B0(BitCircuit::new( + [ + Node::new(13, 1, 0), + Node::new(11, 1, 0), + Node::new(8, 1, 0), + Node::new(14, 1, 0), + Node::new(21, 1, 0), + Node::new(23, 1, 0), + Node::new(24, 1, 0), + Node::new(17, 1, 0), + Node::new(6, 1, 0), + Node::new(3, 1, 0), + Node::new(29, 1, 0), + Node::new(1, 1, 0), + Node::new(20, 1, 0), + Node::new(28, 1, 0), + Node::new(10, 1, 0), + Node::new(18, 1, 0), + Node::new(19, 1, 0), + Node::new(15, 1, 0), + Node::new(7, 1, 0), + Node::new(0, 1, 0), + Node::new(30, 1, 0), + Node::new(5, 1, 0), + Node::new(27, 1, 0), + Node::new(9, 1, 0), + Node::new(2, 1, 0), + Node::new(25, 1, 0), + Node::new(12, 1, 0), + Node::new(31, 1, 0), + Node::new(16, 1, 0), + Node::new(22, 1, 0), + Node::new(26, 1, 0), + Node::new(4, 1, 0), + Node::new(36, 15, 24), + Node::new(36, 12, 31), + Node::new(36, 7, 11), + Node::new(36, 5, 18), + Node::new(36, 4, 21), + Node::new(36, 30, 14), + Node::new(36, 6, 2), + Node::new(36, 29, 8), + Node::new(36, 16, 9), + Node::new(36, 20, 3), + Node::new(36, 25, 23), + Node::new(36, 27, 17), + Node::new(36, 13, 26), + Node::new(36, 10, 0), + Node::new(36, 28, 19), + Node::new(36, 22, 1), + Node::new(35, 5, 0), + Node::new(35, 12, 1), + Node::new(35, 9, 7), + Node::new(35, 11, 3), + Node::new(35, 10, 2), + Node::new(35, 15, 8), + Node::new(35, 6, 14), + Node::new(35, 13, 4), + Node::new(34, 7, 4), + Node::new(34, 1, 6), + Node::new(34, 2, 0), + Node::new(34, 3, 5), + Node::new(33, 3, 0), + Node::new(33, 2, 1), + Node::new(32, 0, 1), + ], + [0, 32, 48, 56, 60, 62], + 32, + )), + AnyBitCircuit::B1(BitCircuit::new( + [ + Node::new(3, 1, 0), + Node::new(1, 1, 0), + Node::new(27, 1, 0), + Node::new(2, 1, 0), + Node::new(5, 1, 0), + Node::new(17, 1, 0), + Node::new(10, 1, 0), + Node::new(30, 1, 0), + Node::new(24, 1, 0), + Node::new(22, 1, 0), + Node::new(20, 1, 0), + Node::new(8, 1, 0), + Node::new(16, 1, 0), + Node::new(11, 1, 0), + Node::new(15, 1, 0), + Node::new(12, 1, 0), + Node::new(23, 1, 0), + Node::new(29, 1, 0), + Node::new(25, 1, 0), + Node::new(13, 1, 0), + Node::new(14, 1, 0), + Node::new(21, 1, 0), + Node::new(7, 1, 0), + Node::new(18, 1, 0), + Node::new(26, 1, 0), + Node::new(9, 1, 0), + Node::new(19, 1, 0), + Node::new(4, 1, 0), + Node::new(31, 1, 0), + Node::new(28, 1, 0), + Node::new(6, 1, 0), + Node::new(36, 26, 0), + Node::new(36, 8, 11), + Node::new(36, 23, 3), + Node::new(36, 2, 13), + Node::new(36, 29, 15), + Node::new(36, 28, 12), + Node::new(36, 9, 30), + Node::new(36, 5, 1), + Node::new(36, 21, 4), + Node::new(36, 10, 27), + Node::new(36, 18, 25), + Node::new(36, 28, 14), + Node::new(36, 7, 20), + Node::new(36, 16, 22), + Node::new(36, 17, 19), + Node::new(36, 24, 6), + Node::new(35, 14, 8), + Node::new(35, 12, 6), + Node::new(35, 11, 13), + Node::new(35, 3, 0), + Node::new(35, 10, 7), + Node::new(35, 4, 9), + Node::new(35, 5, 1), + Node::new(35, 15, 2), + Node::new(34, 1, 7), + Node::new(34, 6, 5), + Node::new(34, 0, 4), + Node::new(34, 2, 3), + Node::new(33, 3, 2), + Node::new(33, 1, 0), + Node::new(32, 1, 0), + ], + [0, 31, 47, 55, 59, 61], + 31, + )), + AnyBitCircuit::B2(BitCircuit::new( + [ + Node::new(8, 1, 0), + Node::new(28, 1, 0), + Node::new(4, 1, 0), + Node::new(20, 1, 0), + Node::new(27, 1, 0), + Node::new(7, 1, 0), + Node::new(23, 1, 0), + Node::new(26, 1, 0), + Node::new(17, 1, 0), + Node::new(6, 1, 0), + Node::new(29, 1, 0), + Node::new(2, 1, 0), + Node::new(9, 1, 0), + Node::new(21, 1, 0), + Node::new(25, 1, 0), + Node::new(31, 1, 0), + Node::new(15, 1, 0), + Node::new(18, 1, 0), + Node::new(10, 1, 0), + Node::new(30, 1, 0), + Node::new(5, 1, 0), + Node::new(13, 1, 0), + Node::new(24, 1, 0), + Node::new(12, 1, 0), + Node::new(19, 1, 0), + Node::new(22, 1, 0), + Node::new(16, 1, 0), + Node::new(3, 1, 0), + Node::new(11, 1, 0), + Node::new(14, 1, 0), + Node::new(36, 10, 21), + Node::new(36, 3, 2), + Node::new(36, 22, 0), + Node::new(36, 13, 20), + Node::new(36, 6, 5), + Node::new(36, 25, 9), + Node::new(36, 15, 16), + Node::new(36, 15, 8), + Node::new(36, 4, 28), + Node::new(36, 1, 23), + Node::new(36, 17, 11), + Node::new(36, 19, 29), + Node::new(36, 24, 27), + Node::new(36, 14, 12), + Node::new(36, 7, 18), + Node::new(36, 15, 26), + Node::new(35, 11, 5), + Node::new(35, 14, 10), + Node::new(35, 9, 1), + Node::new(35, 6, 4), + Node::new(35, 7, 13), + Node::new(35, 8, 12), + Node::new(35, 0, 3), + Node::new(35, 15, 2), + Node::new(34, 7, 2), + Node::new(34, 0, 1), + Node::new(34, 3, 5), + Node::new(34, 4, 6), + Node::new(33, 3, 2), + Node::new(33, 0, 1), + Node::new(32, 0, 1), + ], + [0, 30, 46, 54, 58, 60], + 30, + )), + AnyBitCircuit::B3(BitCircuit::new( + [ + Node::new(28, 1, 0), + Node::new(3, 1, 0), + Node::new(16, 1, 0), + Node::new(14, 1, 0), + Node::new(29, 1, 0), + Node::new(13, 1, 0), + Node::new(27, 1, 0), + Node::new(10, 1, 0), + Node::new(8, 1, 0), + Node::new(31, 1, 0), + Node::new(24, 1, 0), + Node::new(9, 1, 0), + Node::new(5, 1, 0), + Node::new(6, 1, 0), + Node::new(7, 1, 0), + Node::new(30, 1, 0), + Node::new(25, 1, 0), + Node::new(20, 1, 0), + Node::new(18, 1, 0), + Node::new(21, 1, 0), + Node::new(12, 1, 0), + Node::new(4, 1, 0), + Node::new(26, 1, 0), + Node::new(17, 1, 0), + Node::new(19, 1, 0), + Node::new(11, 1, 0), + Node::new(23, 1, 0), + Node::new(15, 1, 0), + Node::new(22, 1, 0), + Node::new(36, 4, 5), + Node::new(36, 19, 12), + Node::new(36, 26, 14), + Node::new(36, 6, 25), + Node::new(36, 9, 23), + Node::new(36, 16, 11), + Node::new(36, 15, 3), + Node::new(36, 10, 8), + Node::new(36, 0, 20), + Node::new(36, 9, 27), + Node::new(36, 9, 18), + Node::new(36, 9, 2), + Node::new(36, 28, 13), + Node::new(36, 24, 1), + Node::new(36, 17, 21), + Node::new(36, 22, 7), + Node::new(35, 8, 14), + Node::new(35, 3, 13), + Node::new(35, 11, 7), + Node::new(35, 10, 15), + Node::new(35, 0, 1), + Node::new(35, 4, 5), + Node::new(35, 6, 12), + Node::new(35, 9, 2), + Node::new(34, 5, 4), + Node::new(34, 3, 6), + Node::new(34, 2, 0), + Node::new(34, 7, 1), + Node::new(33, 1, 2), + Node::new(33, 0, 3), + Node::new(32, 0, 1), + ], + [0, 29, 45, 53, 57, 59], + 29, + )), + AnyBitCircuit::B4(BitCircuit::new( + [ + Node::new(27, 1, 0), + Node::new(8, 1, 0), + Node::new(9, 1, 0), + Node::new(11, 1, 0), + Node::new(29, 1, 0), + Node::new(16, 1, 0), + Node::new(10, 1, 0), + Node::new(30, 1, 0), + Node::new(21, 1, 0), + Node::new(25, 1, 0), + Node::new(14, 1, 0), + Node::new(5, 1, 0), + Node::new(15, 1, 0), + Node::new(23, 1, 0), + Node::new(24, 1, 0), + Node::new(26, 1, 0), + Node::new(17, 1, 0), + Node::new(20, 1, 0), + Node::new(13, 1, 0), + Node::new(4, 1, 0), + Node::new(28, 1, 0), + Node::new(18, 1, 0), + Node::new(6, 1, 0), + Node::new(7, 1, 0), + Node::new(22, 1, 0), + Node::new(19, 1, 0), + Node::new(12, 1, 0), + Node::new(31, 1, 0), + Node::new(36, 7, 10), + Node::new(36, 15, 6), + Node::new(36, 4, 18), + Node::new(36, 27, 21), + Node::new(36, 9, 2), + Node::new(36, 27, 12), + Node::new(36, 0, 3), + Node::new(36, 14, 1), + Node::new(36, 8, 11), + Node::new(36, 17, 19), + Node::new(36, 20, 26), + Node::new(36, 27, 25), + Node::new(36, 27, 16), + Node::new(36, 24, 22), + Node::new(36, 27, 5), + Node::new(36, 13, 23), + Node::new(35, 10, 9), + Node::new(35, 5, 15), + Node::new(35, 3, 1), + Node::new(35, 12, 4), + Node::new(35, 2, 8), + Node::new(35, 0, 13), + Node::new(35, 14, 7), + Node::new(35, 11, 6), + Node::new(34, 7, 1), + Node::new(34, 6, 0), + Node::new(34, 2, 5), + Node::new(34, 3, 4), + Node::new(33, 2, 1), + Node::new(33, 0, 3), + Node::new(32, 1, 0), + ], + [0, 28, 44, 52, 56, 58], + 28, + )), + AnyBitCircuit::B5(BitCircuit::new( + [ + Node::new(29, 1, 0), + Node::new(15, 1, 0), + Node::new(5, 1, 0), + Node::new(13, 1, 0), + Node::new(31, 1, 0), + Node::new(21, 1, 0), + Node::new(7, 1, 0), + Node::new(27, 1, 0), + Node::new(24, 1, 0), + Node::new(12, 1, 0), + Node::new(16, 1, 0), + Node::new(8, 1, 0), + Node::new(30, 1, 0), + Node::new(22, 1, 0), + Node::new(11, 1, 0), + Node::new(28, 1, 0), + Node::new(26, 1, 0), + Node::new(6, 1, 0), + Node::new(10, 1, 0), + Node::new(9, 1, 0), + Node::new(23, 1, 0), + Node::new(19, 1, 0), + Node::new(20, 1, 0), + Node::new(25, 1, 0), + Node::new(17, 1, 0), + Node::new(18, 1, 0), + Node::new(14, 1, 0), + Node::new(36, 20, 6), + Node::new(36, 4, 24), + Node::new(36, 4, 25), + Node::new(36, 16, 18), + Node::new(36, 4, 10), + Node::new(36, 8, 11), + Node::new(36, 7, 14), + Node::new(36, 15, 9), + Node::new(36, 0, 3), + Node::new(36, 4, 21), + Node::new(36, 5, 2), + Node::new(36, 23, 19), + Node::new(36, 13, 17), + Node::new(36, 4, 22), + Node::new(36, 12, 26), + Node::new(36, 4, 1), + Node::new(35, 8, 10), + Node::new(35, 15, 0), + Node::new(35, 13, 7), + Node::new(35, 9, 6), + Node::new(35, 1, 11), + Node::new(35, 4, 5), + Node::new(35, 2, 3), + Node::new(35, 14, 12), + Node::new(34, 4, 0), + Node::new(34, 2, 5), + Node::new(34, 3, 1), + Node::new(34, 6, 7), + Node::new(33, 1, 3), + Node::new(33, 2, 0), + Node::new(32, 0, 1), + ], + [0, 27, 43, 51, 55, 57], + 27, + )), + AnyBitCircuit::B6(BitCircuit::new( + [ + Node::new(24, 1, 0), + Node::new(18, 1, 0), + Node::new(17, 1, 0), + Node::new(29, 1, 0), + Node::new(16, 1, 0), + Node::new(7, 1, 0), + Node::new(30, 1, 0), + Node::new(13, 1, 0), + Node::new(6, 1, 0), + Node::new(28, 1, 0), + Node::new(26, 1, 0), + Node::new(12, 1, 0), + Node::new(19, 1, 0), + Node::new(9, 1, 0), + Node::new(20, 1, 0), + Node::new(21, 1, 0), + Node::new(14, 1, 0), + Node::new(8, 1, 0), + Node::new(10, 1, 0), + Node::new(22, 1, 0), + Node::new(25, 1, 0), + Node::new(15, 1, 0), + Node::new(11, 1, 0), + Node::new(23, 1, 0), + Node::new(31, 1, 0), + Node::new(27, 1, 0), + Node::new(36, 24, 14), + Node::new(36, 24, 12), + Node::new(36, 25, 22), + Node::new(36, 0, 17), + Node::new(36, 24, 4), + Node::new(36, 23, 5), + Node::new(36, 9, 11), + Node::new(36, 3, 7), + Node::new(36, 24, 2), + Node::new(36, 24, 15), + Node::new(36, 10, 18), + Node::new(36, 24, 1), + Node::new(36, 6, 16), + Node::new(36, 20, 13), + Node::new(36, 24, 21), + Node::new(36, 19, 8), + Node::new(35, 11, 10), + Node::new(35, 12, 15), + Node::new(35, 4, 3), + Node::new(35, 9, 7), + Node::new(35, 1, 2), + Node::new(35, 8, 13), + Node::new(35, 14, 5), + Node::new(35, 0, 6), + Node::new(34, 4, 6), + Node::new(34, 7, 2), + Node::new(34, 0, 1), + Node::new(34, 3, 5), + Node::new(33, 1, 2), + Node::new(33, 3, 0), + Node::new(32, 1, 0), + ], + [0, 26, 42, 50, 54, 56], + 26, + )), + AnyBitCircuit::B7(BitCircuit::new( + [ + Node::new(18, 1, 0), + Node::new(26, 1, 0), + Node::new(27, 1, 0), + Node::new(11, 1, 0), + Node::new(15, 1, 0), + Node::new(23, 1, 0), + Node::new(31, 1, 0), + Node::new(21, 1, 0), + Node::new(9, 1, 0), + Node::new(10, 1, 0), + Node::new(13, 1, 0), + Node::new(20, 1, 0), + Node::new(17, 1, 0), + Node::new(24, 1, 0), + Node::new(14, 1, 0), + Node::new(22, 1, 0), + Node::new(7, 1, 0), + Node::new(29, 1, 0), + Node::new(30, 1, 0), + Node::new(19, 1, 0), + Node::new(12, 1, 0), + Node::new(28, 1, 0), + Node::new(25, 1, 0), + Node::new(8, 1, 0), + Node::new(16, 1, 0), + Node::new(36, 6, 0), + Node::new(36, 6, 15), + Node::new(36, 22, 8), + Node::new(36, 6, 19), + Node::new(36, 13, 23), + Node::new(36, 21, 20), + Node::new(36, 6, 7), + Node::new(36, 2, 3), + Node::new(36, 6, 24), + Node::new(36, 6, 11), + Node::new(36, 6, 4), + Node::new(36, 5, 16), + Node::new(36, 1, 9), + Node::new(36, 18, 14), + Node::new(36, 6, 12), + Node::new(36, 17, 10), + Node::new(35, 6, 15), + Node::new(35, 9, 5), + Node::new(35, 10, 11), + Node::new(35, 8, 4), + Node::new(35, 14, 2), + Node::new(35, 0, 12), + Node::new(35, 1, 13), + Node::new(35, 3, 7), + Node::new(34, 7, 2), + Node::new(34, 1, 3), + Node::new(34, 0, 4), + Node::new(34, 6, 5), + Node::new(33, 3, 1), + Node::new(33, 2, 0), + Node::new(32, 0, 1), + ], + [0, 25, 41, 49, 53, 55], + 25, + )), + AnyBitCircuit::B8(BitCircuit::new( + [ + Node::new(21, 1, 0), + Node::new(22, 1, 0), + Node::new(15, 1, 0), + Node::new(20, 1, 0), + Node::new(11, 1, 0), + Node::new(24, 1, 0), + Node::new(18, 1, 0), + Node::new(13, 1, 0), + Node::new(9, 1, 0), + Node::new(10, 1, 0), + Node::new(26, 1, 0), + Node::new(27, 1, 0), + Node::new(19, 1, 0), + Node::new(23, 1, 0), + Node::new(12, 1, 0), + Node::new(29, 1, 0), + Node::new(8, 1, 0), + Node::new(17, 1, 0), + Node::new(14, 1, 0), + Node::new(25, 1, 0), + Node::new(28, 1, 0), + Node::new(31, 1, 0), + Node::new(16, 1, 0), + Node::new(30, 1, 0), + Node::new(36, 21, 13), + Node::new(36, 21, 22), + Node::new(36, 19, 8), + Node::new(36, 21, 12), + Node::new(36, 23, 18), + Node::new(36, 5, 16), + Node::new(36, 20, 14), + Node::new(36, 21, 3), + Node::new(36, 21, 0), + Node::new(36, 21, 17), + Node::new(36, 11, 4), + Node::new(36, 21, 2), + Node::new(36, 21, 1), + Node::new(36, 21, 6), + Node::new(36, 15, 7), + Node::new(36, 10, 9), + Node::new(35, 1, 5), + Node::new(35, 13, 15), + Node::new(35, 9, 2), + Node::new(35, 12, 4), + Node::new(35, 3, 10), + Node::new(35, 7, 6), + Node::new(35, 0, 11), + Node::new(35, 8, 14), + Node::new(34, 3, 1), + Node::new(34, 7, 2), + Node::new(34, 6, 4), + Node::new(34, 5, 0), + Node::new(33, 2, 1), + Node::new(33, 0, 3), + Node::new(32, 0, 1), + ], + [0, 24, 40, 48, 52, 54], + 24, + )), + AnyBitCircuit::B9(BitCircuit::new( + [ + Node::new(12, 1, 0), + Node::new(15, 1, 0), + Node::new(22, 1, 0), + Node::new(20, 1, 0), + Node::new(16, 1, 0), + Node::new(23, 1, 0), + Node::new(17, 1, 0), + Node::new(11, 1, 0), + Node::new(21, 1, 0), + Node::new(14, 1, 0), + Node::new(30, 1, 0), + Node::new(28, 1, 0), + Node::new(25, 1, 0), + Node::new(18, 1, 0), + Node::new(27, 1, 0), + Node::new(9, 1, 0), + Node::new(29, 1, 0), + Node::new(24, 1, 0), + Node::new(31, 1, 0), + Node::new(26, 1, 0), + Node::new(19, 1, 0), + Node::new(13, 1, 0), + Node::new(10, 1, 0), + Node::new(36, 12, 15), + Node::new(36, 16, 21), + Node::new(36, 18, 6), + Node::new(36, 19, 22), + Node::new(36, 18, 17), + Node::new(36, 18, 3), + Node::new(36, 14, 7), + Node::new(36, 18, 4), + Node::new(36, 18, 5), + Node::new(36, 18, 8), + Node::new(36, 18, 2), + Node::new(36, 18, 1), + Node::new(36, 10, 9), + Node::new(36, 11, 0), + Node::new(36, 18, 20), + Node::new(36, 18, 13), + Node::new(35, 5, 13), + Node::new(35, 2, 0), + Node::new(35, 9, 1), + Node::new(35, 8, 11), + Node::new(35, 14, 6), + Node::new(35, 10, 12), + Node::new(35, 4, 7), + Node::new(35, 15, 3), + Node::new(34, 6, 0), + Node::new(34, 3, 4), + Node::new(34, 5, 7), + Node::new(34, 2, 1), + Node::new(33, 1, 3), + Node::new(33, 0, 2), + Node::new(32, 1, 0), + ], + [0, 23, 39, 47, 51, 53], + 23, + )), + AnyBitCircuit::B10(BitCircuit::new( + [ + Node::new(26, 1, 0), + Node::new(23, 1, 0), + Node::new(31, 1, 0), + Node::new(10, 1, 0), + Node::new(18, 1, 0), + Node::new(17, 1, 0), + Node::new(30, 1, 0), + Node::new(29, 1, 0), + Node::new(22, 1, 0), + Node::new(12, 1, 0), + Node::new(19, 1, 0), + Node::new(15, 1, 0), + Node::new(11, 1, 0), + Node::new(16, 1, 0), + Node::new(13, 1, 0), + Node::new(24, 1, 0), + Node::new(25, 1, 0), + Node::new(14, 1, 0), + Node::new(28, 1, 0), + Node::new(21, 1, 0), + Node::new(27, 1, 0), + Node::new(20, 1, 0), + Node::new(36, 2, 11), + Node::new(36, 2, 16), + Node::new(36, 0, 3), + Node::new(36, 18, 9), + Node::new(36, 20, 12), + Node::new(36, 2, 4), + Node::new(36, 7, 14), + Node::new(36, 2, 10), + Node::new(36, 6, 17), + Node::new(36, 2, 13), + Node::new(36, 2, 1), + Node::new(36, 2, 15), + Node::new(36, 2, 8), + Node::new(36, 2, 21), + Node::new(36, 2, 19), + Node::new(36, 2, 5), + Node::new(35, 12, 8), + Node::new(35, 14, 6), + Node::new(35, 13, 3), + Node::new(35, 7, 4), + Node::new(35, 11, 9), + Node::new(35, 10, 0), + Node::new(35, 5, 2), + Node::new(35, 1, 15), + Node::new(34, 4, 2), + Node::new(34, 0, 6), + Node::new(34, 5, 3), + Node::new(34, 7, 1), + Node::new(33, 0, 1), + Node::new(33, 3, 2), + Node::new(32, 1, 0), + ], + [0, 22, 38, 46, 50, 52], + 22, + )), + AnyBitCircuit::B11(BitCircuit::new( + [ + Node::new(28, 1, 0), + Node::new(24, 1, 0), + Node::new(11, 1, 0), + Node::new(31, 1, 0), + Node::new(21, 1, 0), + Node::new(26, 1, 0), + Node::new(22, 1, 0), + Node::new(14, 1, 0), + Node::new(30, 1, 0), + Node::new(15, 1, 0), + Node::new(12, 1, 0), + Node::new(29, 1, 0), + Node::new(19, 1, 0), + Node::new(20, 1, 0), + Node::new(25, 1, 0), + Node::new(27, 1, 0), + Node::new(23, 1, 0), + Node::new(13, 1, 0), + Node::new(18, 1, 0), + Node::new(17, 1, 0), + Node::new(16, 1, 0), + Node::new(36, 3, 14), + Node::new(36, 3, 13), + Node::new(36, 3, 1), + Node::new(36, 8, 7), + Node::new(36, 3, 12), + Node::new(36, 11, 17), + Node::new(36, 3, 19), + Node::new(36, 3, 20), + Node::new(36, 3, 18), + Node::new(36, 3, 16), + Node::new(36, 3, 9), + Node::new(36, 15, 2), + Node::new(36, 0, 10), + Node::new(36, 3, 4), + Node::new(36, 3, 6), + Node::new(36, 3, 5), + Node::new(35, 0, 6), + Node::new(35, 9, 10), + Node::new(35, 13, 5), + Node::new(35, 2, 7), + Node::new(35, 4, 11), + Node::new(35, 15, 8), + Node::new(35, 1, 12), + Node::new(35, 14, 3), + Node::new(34, 0, 2), + Node::new(34, 1, 4), + Node::new(34, 3, 6), + Node::new(34, 5, 7), + Node::new(33, 3, 2), + Node::new(33, 0, 1), + Node::new(32, 0, 1), + ], + [0, 21, 37, 45, 49, 51], + 21, + )), + AnyBitCircuit::B12(BitCircuit::new( + [ + Node::new(23, 1, 0), + Node::new(22, 1, 0), + Node::new(13, 1, 0), + Node::new(12, 1, 0), + Node::new(26, 1, 0), + Node::new(25, 1, 0), + Node::new(15, 1, 0), + Node::new(31, 1, 0), + Node::new(24, 1, 0), + Node::new(29, 1, 0), + Node::new(18, 1, 0), + Node::new(21, 1, 0), + Node::new(14, 1, 0), + Node::new(20, 1, 0), + Node::new(27, 1, 0), + Node::new(19, 1, 0), + Node::new(16, 1, 0), + Node::new(28, 1, 0), + Node::new(17, 1, 0), + Node::new(30, 1, 0), + Node::new(36, 7, 6), + Node::new(36, 7, 0), + Node::new(36, 9, 2), + Node::new(36, 7, 5), + Node::new(36, 7, 15), + Node::new(36, 7, 18), + Node::new(36, 19, 12), + Node::new(36, 7, 8), + Node::new(36, 7, 1), + Node::new(36, 7, 11), + Node::new(36, 7, 16), + Node::new(36, 7, 10), + Node::new(36, 7, 4), + Node::new(36, 7, 14), + Node::new(36, 7, 13), + Node::new(36, 17, 3), + Node::new(35, 14, 15), + Node::new(35, 13, 4), + Node::new(35, 8, 6), + Node::new(35, 9, 2), + Node::new(35, 12, 11), + Node::new(35, 1, 0), + Node::new(35, 3, 5), + Node::new(35, 7, 10), + Node::new(34, 6, 3), + Node::new(34, 4, 2), + Node::new(34, 7, 0), + Node::new(34, 1, 5), + Node::new(33, 3, 0), + Node::new(33, 1, 2), + Node::new(32, 0, 1), + ], + [0, 20, 36, 44, 48, 50], + 20, + )), + AnyBitCircuit::B13(BitCircuit::new( + [ + Node::new(27, 1, 0), + Node::new(20, 1, 0), + Node::new(13, 1, 0), + Node::new(28, 1, 0), + Node::new(22, 1, 0), + Node::new(15, 1, 0), + Node::new(25, 1, 0), + Node::new(29, 1, 0), + Node::new(23, 1, 0), + Node::new(21, 1, 0), + Node::new(19, 1, 0), + Node::new(16, 1, 0), + Node::new(26, 1, 0), + Node::new(24, 1, 0), + Node::new(30, 1, 0), + Node::new(17, 1, 0), + Node::new(18, 1, 0), + Node::new(14, 1, 0), + Node::new(31, 1, 0), + Node::new(36, 18, 12), + Node::new(36, 18, 6), + Node::new(36, 18, 16), + Node::new(36, 18, 0), + Node::new(36, 18, 11), + Node::new(36, 18, 13), + Node::new(36, 18, 8), + Node::new(36, 14, 17), + Node::new(36, 7, 2), + Node::new(36, 18, 1), + Node::new(36, 18, 5), + Node::new(36, 18, 9), + Node::new(36, 18, 10), + Node::new(36, 18, 4), + Node::new(36, 18, 3), + Node::new(36, 18, 15), + Node::new(35, 3, 12), + Node::new(35, 14, 9), + Node::new(35, 11, 8), + Node::new(35, 13, 7), + Node::new(35, 5, 4), + Node::new(35, 6, 10), + Node::new(35, 0, 2), + Node::new(35, 1, 15), + Node::new(34, 6, 3), + Node::new(34, 7, 2), + Node::new(34, 0, 5), + Node::new(34, 1, 4), + Node::new(33, 2, 1), + Node::new(33, 3, 0), + Node::new(32, 1, 0), + ], + [0, 19, 35, 43, 47, 49], + 19, + )), + AnyBitCircuit::B14(BitCircuit::new( + [ + Node::new(26, 1, 0), + Node::new(21, 1, 0), + Node::new(20, 1, 0), + Node::new(29, 1, 0), + Node::new(31, 1, 0), + Node::new(22, 1, 0), + Node::new(19, 1, 0), + Node::new(23, 1, 0), + Node::new(16, 1, 0), + Node::new(15, 1, 0), + Node::new(14, 1, 0), + Node::new(18, 1, 0), + Node::new(17, 1, 0), + Node::new(28, 1, 0), + Node::new(24, 1, 0), + Node::new(30, 1, 0), + Node::new(25, 1, 0), + Node::new(27, 1, 0), + Node::new(36, 4, 8), + Node::new(36, 4, 6), + Node::new(36, 4, 13), + Node::new(36, 4, 12), + Node::new(36, 4, 1), + Node::new(36, 4, 14), + Node::new(36, 4, 0), + Node::new(36, 4, 11), + Node::new(36, 4, 9), + Node::new(36, 4, 3), + Node::new(36, 4, 17), + Node::new(36, 4, 2), + Node::new(36, 4, 16), + Node::new(36, 4, 7), + Node::new(36, 4, 5), + Node::new(36, 15, 10), + Node::new(35, 12, 3), + Node::new(35, 10, 1), + Node::new(35, 2, 11), + Node::new(35, 13, 8), + Node::new(35, 6, 7), + Node::new(35, 9, 4), + Node::new(35, 5, 0), + Node::new(35, 14, 15), + Node::new(34, 4, 7), + Node::new(34, 1, 3), + Node::new(34, 5, 0), + Node::new(34, 2, 6), + Node::new(33, 2, 1), + Node::new(33, 3, 0), + Node::new(32, 0, 1), + ], + [0, 18, 34, 42, 46, 48], + 18, + )), + AnyBitCircuit::B15(BitCircuit::new( + [ + Node::new(30, 1, 0), + Node::new(15, 1, 0), + Node::new(24, 1, 0), + Node::new(17, 1, 0), + Node::new(29, 1, 0), + Node::new(26, 1, 0), + Node::new(19, 1, 0), + Node::new(21, 1, 0), + Node::new(18, 1, 0), + Node::new(23, 1, 0), + Node::new(31, 1, 0), + Node::new(22, 1, 0), + Node::new(28, 1, 0), + Node::new(27, 1, 0), + Node::new(16, 1, 0), + Node::new(20, 1, 0), + Node::new(25, 1, 0), + Node::new(36, 10, 4), + Node::new(36, 10, 3), + Node::new(36, 10, 6), + Node::new(36, 10, 7), + Node::new(36, 10, 13), + Node::new(36, 10, 15), + Node::new(36, 10, 1), + Node::new(36, 10, 16), + Node::new(36, 10, 9), + Node::new(36, 10, 11), + Node::new(36, 10, 2), + Node::new(36, 10, 14), + Node::new(36, 10, 8), + Node::new(36, 10, 0), + Node::new(36, 10, 12), + Node::new(36, 10, 5), + Node::new(35, 10, 11), + Node::new(35, 15, 12), + Node::new(35, 8, 6), + Node::new(35, 4, 2), + Node::new(35, 0, 3), + Node::new(35, 13, 9), + Node::new(35, 7, 1), + Node::new(35, 14, 5), + Node::new(34, 3, 2), + Node::new(34, 4, 6), + Node::new(34, 5, 1), + Node::new(34, 7, 0), + Node::new(33, 2, 3), + Node::new(33, 1, 0), + Node::new(32, 0, 1), + ], + [0, 17, 33, 41, 45, 47], + 17, + )), + AnyBitCircuit::B16(BitCircuit::new( + [ + Node::new(31, 1, 0), + Node::new(24, 1, 0), + Node::new(21, 1, 0), + Node::new(29, 1, 0), + Node::new(26, 1, 0), + Node::new(17, 1, 0), + Node::new(18, 1, 0), + Node::new(28, 1, 0), + Node::new(19, 1, 0), + Node::new(22, 1, 0), + Node::new(25, 1, 0), + Node::new(23, 1, 0), + Node::new(20, 1, 0), + Node::new(16, 1, 0), + Node::new(27, 1, 0), + Node::new(30, 1, 0), + Node::new(31, 0, 0), + Node::new(36, 0, 10), + Node::new(36, 0, 3), + Node::new(36, 0, 8), + Node::new(36, 0, 1), + Node::new(36, 0, 7), + Node::new(36, 0, 2), + Node::new(36, 0, 12), + Node::new(36, 0, 6), + Node::new(36, 0, 13), + Node::new(36, 0, 5), + Node::new(36, 0, 14), + Node::new(36, 0, 11), + Node::new(36, 0, 4), + Node::new(36, 0, 9), + Node::new(36, 0, 15), + Node::new(35, 5, 7), + Node::new(35, 11, 3), + Node::new(35, 15, 14), + Node::new(35, 4, 9), + Node::new(35, 13, 8), + Node::new(35, 1, 10), + Node::new(35, 2, 6), + Node::new(35, 0, 12), + Node::new(34, 6, 5), + Node::new(34, 7, 1), + Node::new(34, 2, 4), + Node::new(34, 0, 3), + Node::new(33, 2, 3), + Node::new(33, 1, 0), + Node::new(32, 1, 0), + ], + [0, 16, 32, 40, 44, 46], + 16, + )), + AnyBitCircuit::B17(BitCircuit::new( + [ + Node::new(31, 1, 0), + Node::new(28, 1, 0), + Node::new(27, 1, 0), + Node::new(29, 1, 0), + Node::new(17, 1, 0), + Node::new(23, 1, 0), + Node::new(22, 1, 0), + Node::new(19, 1, 0), + Node::new(30, 1, 0), + Node::new(21, 1, 0), + Node::new(25, 1, 0), + Node::new(24, 1, 0), + Node::new(18, 1, 0), + Node::new(20, 1, 0), + Node::new(26, 1, 0), + Node::new(31, 0, 0), + Node::new(36, 0, 1), + Node::new(36, 0, 11), + Node::new(36, 0, 5), + Node::new(36, 0, 14), + Node::new(36, 0, 7), + Node::new(36, 0, 6), + Node::new(36, 0, 2), + Node::new(36, 0, 10), + Node::new(36, 0, 13), + Node::new(36, 0, 3), + Node::new(36, 0, 12), + Node::new(36, 0, 4), + Node::new(36, 0, 9), + Node::new(36, 0, 8), + Node::new(35, 1, 9), + Node::new(35, 0, 3), + Node::new(35, 8, 12), + Node::new(35, 4, 11), + Node::new(35, 0, 2), + Node::new(35, 10, 13), + Node::new(35, 14, 6), + Node::new(35, 7, 5), + Node::new(34, 6, 3), + Node::new(34, 4, 0), + Node::new(34, 5, 2), + Node::new(34, 1, 7), + Node::new(33, 3, 2), + Node::new(33, 1, 0), + Node::new(32, 1, 0), + ], + [0, 15, 30, 38, 42, 44], + 15, + )), + AnyBitCircuit::B18(BitCircuit::new( + [ + Node::new(31, 1, 0), + Node::new(22, 1, 0), + Node::new(20, 1, 0), + Node::new(23, 1, 0), + Node::new(25, 1, 0), + Node::new(19, 1, 0), + Node::new(21, 1, 0), + Node::new(18, 1, 0), + Node::new(29, 1, 0), + Node::new(27, 1, 0), + Node::new(26, 1, 0), + Node::new(30, 1, 0), + Node::new(28, 1, 0), + Node::new(24, 1, 0), + Node::new(31, 0, 0), + Node::new(36, 0, 1), + Node::new(36, 0, 5), + Node::new(36, 0, 7), + Node::new(36, 0, 13), + Node::new(36, 0, 9), + Node::new(36, 0, 6), + Node::new(36, 0, 3), + Node::new(36, 0, 10), + Node::new(36, 0, 2), + Node::new(36, 0, 12), + Node::new(36, 0, 11), + Node::new(36, 0, 8), + Node::new(36, 0, 4), + Node::new(35, 0, 4), + Node::new(35, 0, 7), + Node::new(35, 8, 3), + Node::new(35, 5, 2), + Node::new(35, 11, 1), + Node::new(35, 12, 6), + Node::new(35, 10, 9), + Node::new(35, 0, 13), + Node::new(34, 1, 3), + Node::new(34, 0, 6), + Node::new(34, 7, 5), + Node::new(34, 4, 2), + Node::new(33, 1, 3), + Node::new(33, 2, 0), + Node::new(32, 1, 0), + ], + [0, 14, 28, 36, 40, 42], + 14, + )), + AnyBitCircuit::B19(BitCircuit::new( + [ + Node::new(31, 1, 0), + Node::new(27, 1, 0), + Node::new(22, 1, 0), + Node::new(23, 1, 0), + Node::new(19, 1, 0), + Node::new(24, 1, 0), + Node::new(20, 1, 0), + Node::new(28, 1, 0), + Node::new(29, 1, 0), + Node::new(21, 1, 0), + Node::new(25, 1, 0), + Node::new(26, 1, 0), + Node::new(30, 1, 0), + Node::new(31, 0, 0), + Node::new(36, 0, 7), + Node::new(36, 0, 5), + Node::new(36, 0, 11), + Node::new(36, 0, 2), + Node::new(36, 0, 3), + Node::new(36, 0, 1), + Node::new(36, 0, 4), + Node::new(36, 0, 9), + Node::new(36, 0, 10), + Node::new(36, 0, 6), + Node::new(36, 0, 12), + Node::new(36, 0, 8), + Node::new(35, 0, 9), + Node::new(35, 12, 8), + Node::new(35, 6, 7), + Node::new(35, 0, 5), + Node::new(35, 11, 4), + Node::new(35, 0, 2), + Node::new(35, 1, 10), + Node::new(35, 0, 3), + Node::new(34, 7, 4), + Node::new(34, 5, 6), + Node::new(34, 3, 2), + Node::new(34, 0, 1), + Node::new(33, 0, 1), + Node::new(33, 3, 2), + Node::new(32, 0, 1), + ], + [0, 13, 26, 34, 38, 40], + 13, + )), + AnyBitCircuit::B20(BitCircuit::new( + [ + Node::new(31, 1, 0), + Node::new(30, 1, 0), + Node::new(29, 1, 0), + Node::new(20, 1, 0), + Node::new(27, 1, 0), + Node::new(25, 1, 0), + Node::new(26, 1, 0), + Node::new(24, 1, 0), + Node::new(28, 1, 0), + Node::new(21, 1, 0), + Node::new(23, 1, 0), + Node::new(22, 1, 0), + Node::new(31, 0, 0), + Node::new(36, 0, 7), + Node::new(36, 0, 8), + Node::new(36, 0, 10), + Node::new(36, 0, 11), + Node::new(36, 0, 2), + Node::new(36, 0, 3), + Node::new(36, 0, 9), + Node::new(36, 0, 1), + Node::new(36, 0, 4), + Node::new(36, 0, 6), + Node::new(36, 0, 5), + Node::new(35, 2, 6), + Node::new(35, 0, 11), + Node::new(35, 0, 10), + Node::new(35, 5, 7), + Node::new(35, 0, 1), + Node::new(35, 8, 4), + Node::new(35, 0, 3), + Node::new(35, 0, 9), + Node::new(34, 1, 3), + Node::new(34, 2, 5), + Node::new(34, 4, 0), + Node::new(34, 7, 6), + Node::new(33, 3, 0), + Node::new(33, 1, 2), + Node::new(32, 0, 1), + ], + [0, 12, 24, 32, 36, 38], + 12, + )), + AnyBitCircuit::B21(BitCircuit::new( + [ + Node::new(31, 1, 0), + Node::new(23, 1, 0), + Node::new(26, 1, 0), + Node::new(30, 1, 0), + Node::new(22, 1, 0), + Node::new(21, 1, 0), + Node::new(29, 1, 0), + Node::new(28, 1, 0), + Node::new(27, 1, 0), + Node::new(24, 1, 0), + Node::new(25, 1, 0), + Node::new(31, 0, 0), + Node::new(36, 0, 7), + Node::new(36, 0, 1), + Node::new(36, 0, 8), + Node::new(36, 0, 4), + Node::new(36, 0, 2), + Node::new(36, 0, 10), + Node::new(36, 0, 6), + Node::new(36, 0, 5), + Node::new(36, 0, 9), + Node::new(36, 0, 3), + Node::new(35, 0, 3), + Node::new(35, 0, 6), + Node::new(35, 10, 4), + Node::new(35, 0, 1), + Node::new(35, 0, 9), + Node::new(35, 0, 2), + Node::new(35, 0, 5), + Node::new(35, 7, 8), + Node::new(34, 6, 2), + Node::new(34, 0, 5), + Node::new(34, 1, 7), + Node::new(34, 3, 4), + Node::new(33, 3, 0), + Node::new(33, 1, 2), + Node::new(32, 0, 1), + ], + [0, 11, 22, 30, 34, 36], + 11, + )), + AnyBitCircuit::B22(BitCircuit::new( + [ + Node::new(31, 1, 0), + Node::new(25, 1, 0), + Node::new(23, 1, 0), + Node::new(28, 1, 0), + Node::new(27, 1, 0), + Node::new(22, 1, 0), + Node::new(24, 1, 0), + Node::new(30, 1, 0), + Node::new(29, 1, 0), + Node::new(26, 1, 0), + Node::new(31, 0, 0), + Node::new(36, 0, 9), + Node::new(36, 0, 5), + Node::new(36, 0, 4), + Node::new(36, 0, 1), + Node::new(36, 0, 2), + Node::new(36, 0, 8), + Node::new(36, 0, 3), + Node::new(36, 0, 6), + Node::new(36, 0, 7), + Node::new(35, 9, 2), + Node::new(35, 0, 5), + Node::new(35, 0, 3), + Node::new(35, 0, 1), + Node::new(35, 0, 8), + Node::new(35, 0, 7), + Node::new(35, 0, 4), + Node::new(35, 0, 6), + Node::new(34, 5, 4), + Node::new(34, 7, 6), + Node::new(34, 3, 0), + Node::new(34, 2, 1), + Node::new(33, 0, 2), + Node::new(33, 1, 3), + Node::new(32, 1, 0), + ], + [0, 10, 20, 28, 32, 34], + 10, + )), + AnyBitCircuit::B23(BitCircuit::new( + [ + Node::new(31, 1, 0), + Node::new(23, 1, 0), + Node::new(27, 1, 0), + Node::new(28, 1, 0), + Node::new(29, 1, 0), + Node::new(25, 1, 0), + Node::new(30, 1, 0), + Node::new(24, 1, 0), + Node::new(26, 1, 0), + Node::new(31, 0, 0), + Node::new(36, 0, 7), + Node::new(36, 0, 3), + Node::new(36, 0, 2), + Node::new(36, 0, 6), + Node::new(36, 0, 4), + Node::new(36, 0, 8), + Node::new(36, 0, 1), + Node::new(36, 0, 5), + Node::new(35, 0, 2), + Node::new(35, 0, 7), + Node::new(35, 0, 5), + Node::new(35, 0, 4), + Node::new(35, 0, 3), + Node::new(35, 0, 1), + Node::new(35, 0, 6), + Node::new(35, 0, 8), + Node::new(34, 0, 5), + Node::new(34, 3, 6), + Node::new(34, 4, 1), + Node::new(34, 2, 7), + Node::new(33, 1, 0), + Node::new(33, 3, 2), + Node::new(32, 0, 1), + ], + [0, 9, 18, 26, 30, 32], + 9, + )), + AnyBitCircuit::B24(BitCircuit::new( + [ + Node::new(31, 1, 0), + Node::new(29, 1, 0), + Node::new(30, 1, 0), + Node::new(24, 1, 0), + Node::new(28, 1, 0), + Node::new(25, 1, 0), + Node::new(26, 1, 0), + Node::new(27, 1, 0), + Node::new(31, 0, 0), + Node::new(36, 0, 6), + Node::new(36, 0, 2), + Node::new(36, 0, 5), + Node::new(36, 0, 1), + Node::new(36, 0, 4), + Node::new(36, 0, 3), + Node::new(36, 0, 7), + Node::new(31, 0, 0), + Node::new(35, 0, 1), + Node::new(35, 0, 5), + Node::new(35, 0, 2), + Node::new(35, 0, 7), + Node::new(35, 0, 6), + Node::new(35, 0, 3), + Node::new(35, 0, 4), + Node::new(34, 3, 1), + Node::new(34, 0, 4), + Node::new(34, 2, 5), + Node::new(34, 7, 6), + Node::new(33, 1, 3), + Node::new(33, 0, 2), + Node::new(32, 0, 1), + ], + [0, 8, 16, 24, 28, 30], + 8, + )), + AnyBitCircuit::B25(BitCircuit::new( + [ + Node::new(31, 1, 0), + Node::new(27, 1, 0), + Node::new(26, 1, 0), + Node::new(30, 1, 0), + Node::new(28, 1, 0), + Node::new(25, 1, 0), + Node::new(29, 1, 0), + Node::new(31, 0, 0), + Node::new(36, 0, 4), + Node::new(36, 0, 3), + Node::new(36, 0, 6), + Node::new(36, 0, 2), + Node::new(36, 0, 5), + Node::new(36, 0, 1), + Node::new(31, 0, 0), + Node::new(35, 0, 2), + Node::new(35, 0, 1), + Node::new(35, 0, 5), + Node::new(35, 0, 3), + Node::new(35, 0, 6), + Node::new(35, 0, 4), + Node::new(34, 4, 3), + Node::new(34, 1, 6), + Node::new(34, 0, 2), + Node::new(34, 0, 5), + Node::new(33, 3, 0), + Node::new(33, 2, 1), + Node::new(32, 1, 0), + ], + [0, 7, 14, 21, 25, 27], + 7, + )), + AnyBitCircuit::B26(BitCircuit::new( + [ + Node::new(31, 1, 0), + Node::new(26, 1, 0), + Node::new(27, 1, 0), + Node::new(29, 1, 0), + Node::new(30, 1, 0), + Node::new(28, 1, 0), + Node::new(31, 0, 0), + Node::new(36, 0, 2), + Node::new(36, 0, 1), + Node::new(36, 0, 4), + Node::new(36, 0, 5), + Node::new(36, 0, 3), + Node::new(31, 0, 0), + Node::new(35, 0, 3), + Node::new(35, 0, 1), + Node::new(35, 0, 4), + Node::new(35, 0, 5), + Node::new(35, 0, 2), + Node::new(34, 0, 2), + Node::new(34, 0, 3), + Node::new(34, 0, 4), + Node::new(34, 1, 5), + Node::new(33, 1, 3), + Node::new(33, 2, 0), + Node::new(32, 1, 0), + ], + [0, 6, 12, 18, 22, 24], + 6, + )), + AnyBitCircuit::B27(BitCircuit::new( + [ + Node::new(31, 1, 0), + Node::new(30, 1, 0), + Node::new(27, 1, 0), + Node::new(29, 1, 0), + Node::new(28, 1, 0), + Node::new(31, 0, 0), + Node::new(36, 0, 3), + Node::new(36, 0, 1), + Node::new(36, 0, 4), + Node::new(36, 0, 2), + Node::new(31, 0, 0), + Node::new(35, 0, 4), + Node::new(35, 0, 2), + Node::new(35, 0, 1), + Node::new(35, 0, 3), + Node::new(34, 0, 3), + Node::new(34, 0, 2), + Node::new(34, 0, 1), + Node::new(34, 0, 4), + Node::new(33, 0, 2), + Node::new(33, 1, 3), + Node::new(32, 1, 0), + ], + [0, 5, 10, 15, 19, 21], + 5, + )), + AnyBitCircuit::B28(BitCircuit::new( + [ + Node::new(31, 1, 0), + Node::new(28, 1, 0), + Node::new(30, 1, 0), + Node::new(29, 1, 0), + Node::new(31, 0, 0), + Node::new(36, 0, 2), + Node::new(36, 0, 1), + Node::new(36, 0, 3), + Node::new(31, 0, 0), + Node::new(35, 0, 2), + Node::new(35, 0, 3), + Node::new(35, 0, 1), + Node::new(31, 0, 0), + Node::new(34, 0, 3), + Node::new(34, 0, 2), + Node::new(34, 0, 1), + Node::new(33, 0, 2), + Node::new(33, 1, 3), + Node::new(32, 0, 1), + ], + [0, 4, 8, 12, 16, 18], + 4, + )), + AnyBitCircuit::B29(BitCircuit::new( + [ + Node::new(31, 1, 0), + Node::new(30, 1, 0), + Node::new(29, 1, 0), + Node::new(31, 0, 0), + Node::new(36, 0, 2), + Node::new(36, 0, 1), + Node::new(31, 0, 0), + Node::new(35, 0, 1), + Node::new(35, 0, 2), + Node::new(31, 0, 0), + Node::new(34, 0, 1), + Node::new(34, 0, 2), + Node::new(33, 0, 1), + Node::new(33, 0, 2), + Node::new(32, 1, 0), + ], + [0, 3, 6, 9, 12, 14], + 3, + )), + AnyBitCircuit::B30(BitCircuit::new( + [ + Node::new(31, 1, 0), + Node::new(30, 1, 0), + Node::new(31, 0, 0), + Node::new(36, 0, 1), + Node::new(31, 0, 0), + Node::new(35, 0, 1), + Node::new(31, 0, 0), + Node::new(34, 0, 1), + Node::new(31, 0, 0), + Node::new(33, 0, 1), + Node::new(32, 0, 1), + ], + [0, 2, 4, 6, 8, 10], + 2, + )), + AnyBitCircuit::B31(BitCircuit::new([Node::new(31, 1, 0)], [0], 2)), +]);
@@ -0,0 +1,1830 @@
+use crate::tfhe::bdd_arithmetic::{BitCircuit, BitCircuitInfo, Circuit, GetBitCircuitInfo, Node}; +pub(crate) enum AnyBitCircuit { + B0(BitCircuit<63, 6>), + B1(BitCircuit<63, 6>), + B2(BitCircuit<62, 6>), + B3(BitCircuit<61, 6>), + B4(BitCircuit<60, 6>), + B5(BitCircuit<59, 6>), + B6(BitCircuit<58, 6>), + B7(BitCircuit<57, 6>), + B8(BitCircuit<56, 6>), + B9(BitCircuit<55, 6>), + B10(BitCircuit<54, 6>), + B11(BitCircuit<53, 6>), + B12(BitCircuit<52, 6>), + B13(BitCircuit<51, 6>), + B14(BitCircuit<50, 6>), + B15(BitCircuit<49, 6>), + B16(BitCircuit<48, 6>), + B17(BitCircuit<47, 6>), + B18(BitCircuit<45, 6>), + B19(BitCircuit<43, 6>), + B20(BitCircuit<41, 6>), + B21(BitCircuit<39, 6>), + B22(BitCircuit<37, 6>), + B23(BitCircuit<35, 6>), + B24(BitCircuit<33, 6>), + B25(BitCircuit<31, 6>), + B26(BitCircuit<28, 6>), + B27(BitCircuit<25, 6>), + B28(BitCircuit<22, 6>), + B29(BitCircuit<19, 6>), + B30(BitCircuit<15, 6>), + B31(BitCircuit<11, 6>), +} +impl BitCircuitInfo for AnyBitCircuit { + fn info(&self) -> (&[Node], &[usize], usize) { + match self { + AnyBitCircuit::B0(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B1(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B2(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B3(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B4(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B5(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B6(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B7(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B8(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B9(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B10(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B11(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B12(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B13(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B14(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B15(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B16(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B17(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B18(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B19(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B20(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B21(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B22(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B23(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B24(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B25(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B26(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B27(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B28(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B29(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B30(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B31(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + } + } +} + +impl GetBitCircuitInfo<u32> for Circuit<AnyBitCircuit, 32usize> { + fn input_size(&self) -> usize { + 2 * u32::BITS as usize + } + fn output_size(&self) -> usize { + u32::BITS as usize + } + fn get_circuit(&self, bit: usize) -> (&[Node], &[usize], usize) { + self.0[bit].info() + } +} + +pub(crate) static OUTPUT_CIRCUITS: Circuit<AnyBitCircuit, 32usize> = Circuit([ + AnyBitCircuit::B0(BitCircuit::new( + [ + Node::new(0, 1, 0), + Node::new(29, 1, 0), + Node::new(3, 1, 0), + Node::new(9, 1, 0), + Node::new(13, 1, 0), + Node::new(27, 1, 0), + Node::new(18, 1, 0), + Node::new(25, 1, 0), + Node::new(28, 1, 0), + Node::new(26, 1, 0), + Node::new(20, 1, 0), + Node::new(22, 1, 0), + Node::new(11, 1, 0), + Node::new(10, 1, 0), + Node::new(2, 1, 0), + Node::new(15, 1, 0), + Node::new(1, 1, 0), + Node::new(12, 1, 0), + Node::new(14, 1, 0), + Node::new(4, 1, 0), + Node::new(19, 1, 0), + Node::new(17, 1, 0), + Node::new(30, 1, 0), + Node::new(24, 1, 0), + Node::new(31, 1, 0), + Node::new(16, 1, 0), + Node::new(5, 1, 0), + Node::new(23, 1, 0), + Node::new(8, 1, 0), + Node::new(21, 1, 0), + Node::new(6, 1, 0), + Node::new(7, 1, 0), + Node::new(36, 22, 18), + Node::new(36, 24, 15), + Node::new(36, 6, 14), + Node::new(36, 21, 16), + Node::new(36, 1, 4), + Node::new(36, 5, 12), + Node::new(36, 9, 13), + Node::new(36, 7, 3), + Node::new(36, 8, 17), + Node::new(36, 29, 26), + Node::new(36, 10, 19), + Node::new(36, 25, 0), + Node::new(36, 23, 28), + Node::new(36, 11, 30), + Node::new(36, 27, 31), + Node::new(36, 20, 2), + Node::new(35, 8, 10), + Node::new(35, 6, 2), + Node::new(35, 12, 11), + Node::new(35, 1, 14), + Node::new(35, 0, 13), + Node::new(35, 7, 3), + Node::new(35, 5, 15), + Node::new(35, 4, 9), + Node::new(34, 3, 6), + Node::new(34, 0, 2), + Node::new(34, 4, 1), + Node::new(34, 7, 5), + Node::new(33, 2, 1), + Node::new(33, 0, 3), + Node::new(32, 1, 0), + ], + [0, 32, 48, 56, 60, 62], + 32, + )), + AnyBitCircuit::B1(BitCircuit::new( + [ + Node::new(0, 0, 0), + Node::new(4, 1, 0), + Node::new(18, 1, 0), + Node::new(30, 1, 0), + Node::new(13, 1, 0), + Node::new(27, 1, 0), + Node::new(9, 1, 0), + Node::new(6, 1, 0), + Node::new(20, 1, 0), + Node::new(1, 1, 0), + Node::new(19, 1, 0), + Node::new(5, 1, 0), + Node::new(10, 1, 0), + Node::new(15, 1, 0), + Node::new(31, 1, 0), + Node::new(14, 1, 0), + Node::new(8, 1, 0), + Node::new(12, 1, 0), + Node::new(21, 1, 0), + Node::new(22, 1, 0), + Node::new(26, 1, 0), + Node::new(17, 1, 0), + Node::new(16, 1, 0), + Node::new(25, 1, 0), + Node::new(7, 1, 0), + Node::new(2, 1, 0), + Node::new(28, 1, 0), + Node::new(23, 1, 0), + Node::new(11, 1, 0), + Node::new(29, 1, 0), + Node::new(3, 1, 0), + Node::new(24, 1, 0), + Node::new(36, 18, 11), + Node::new(36, 23, 6), + Node::new(36, 0, 22), + Node::new(36, 21, 9), + Node::new(36, 27, 24), + Node::new(36, 8, 1), + Node::new(36, 14, 13), + Node::new(36, 5, 28), + Node::new(36, 19, 7), + Node::new(36, 29, 4), + Node::new(36, 20, 12), + Node::new(36, 26, 17), + Node::new(36, 3, 15), + Node::new(36, 10, 30), + Node::new(36, 31, 16), + Node::new(36, 2, 25), + Node::new(35, 12, 8), + Node::new(35, 2, 14), + Node::new(35, 7, 13), + Node::new(35, 10, 15), + Node::new(35, 1, 3), + Node::new(35, 11, 5), + Node::new(35, 6, 4), + Node::new(35, 9, 0), + Node::new(34, 1, 5), + Node::new(34, 6, 2), + Node::new(34, 7, 4), + Node::new(34, 0, 3), + Node::new(33, 1, 2), + Node::new(33, 0, 3), + Node::new(32, 1, 0), + ], + [0, 32, 48, 56, 60, 62], + 32, + )), + AnyBitCircuit::B2(BitCircuit::new( + [ + Node::new(0, 0, 0), + Node::new(19, 1, 0), + Node::new(13, 1, 0), + Node::new(21, 1, 0), + Node::new(8, 1, 0), + Node::new(22, 1, 0), + Node::new(18, 1, 0), + Node::new(4, 1, 0), + Node::new(11, 1, 0), + Node::new(16, 1, 0), + Node::new(3, 1, 0), + Node::new(31, 1, 0), + Node::new(17, 1, 0), + Node::new(14, 1, 0), + Node::new(24, 1, 0), + Node::new(20, 1, 0), + Node::new(7, 1, 0), + Node::new(23, 1, 0), + Node::new(6, 1, 0), + Node::new(29, 1, 0), + Node::new(10, 1, 0), + Node::new(12, 1, 0), + Node::new(28, 1, 0), + Node::new(25, 1, 0), + Node::new(27, 1, 0), + Node::new(30, 1, 0), + Node::new(9, 1, 0), + Node::new(15, 1, 0), + Node::new(2, 1, 0), + Node::new(26, 1, 0), + Node::new(5, 1, 0), + Node::new(36, 1, 10), + Node::new(36, 0, 12), + Node::new(36, 15, 7), + Node::new(36, 25, 13), + Node::new(36, 17, 16), + Node::new(36, 0, 9), + Node::new(36, 6, 28), + Node::new(36, 22, 21), + Node::new(36, 19, 2), + Node::new(36, 29, 20), + Node::new(36, 24, 8), + Node::new(36, 11, 27), + Node::new(36, 14, 4), + Node::new(36, 5, 18), + Node::new(36, 3, 30), + Node::new(36, 23, 26), + Node::new(35, 11, 4), + Node::new(35, 9, 6), + Node::new(35, 1, 15), + Node::new(35, 5, 12), + Node::new(35, 8, 14), + Node::new(35, 10, 0), + Node::new(35, 3, 13), + Node::new(35, 7, 2), + Node::new(34, 0, 5), + Node::new(34, 3, 7), + Node::new(34, 6, 1), + Node::new(34, 2, 4), + Node::new(33, 3, 0), + Node::new(33, 1, 2), + Node::new(32, 0, 1), + ], + [0, 31, 47, 55, 59, 61], + 31, + )), + AnyBitCircuit::B3(BitCircuit::new( + [ + Node::new(0, 0, 0), + Node::new(9, 1, 0), + Node::new(29, 1, 0), + Node::new(17, 1, 0), + Node::new(7, 1, 0), + Node::new(4, 1, 0), + Node::new(18, 1, 0), + Node::new(24, 1, 0), + Node::new(28, 1, 0), + Node::new(6, 1, 0), + Node::new(22, 1, 0), + Node::new(3, 1, 0), + Node::new(11, 1, 0), + Node::new(26, 1, 0), + Node::new(27, 1, 0), + Node::new(10, 1, 0), + Node::new(21, 1, 0), + Node::new(20, 1, 0), + Node::new(13, 1, 0), + Node::new(19, 1, 0), + Node::new(31, 1, 0), + Node::new(12, 1, 0), + Node::new(5, 1, 0), + Node::new(25, 1, 0), + Node::new(15, 1, 0), + Node::new(8, 1, 0), + Node::new(23, 1, 0), + Node::new(14, 1, 0), + Node::new(16, 1, 0), + Node::new(30, 1, 0), + Node::new(36, 14, 12), + Node::new(36, 0, 3), + Node::new(36, 29, 27), + Node::new(36, 23, 1), + Node::new(36, 0, 28), + Node::new(36, 8, 21), + Node::new(36, 0, 6), + Node::new(36, 2, 18), + Node::new(36, 20, 24), + Node::new(36, 26, 4), + Node::new(36, 10, 9), + Node::new(36, 17, 5), + Node::new(36, 19, 11), + Node::new(36, 7, 25), + Node::new(36, 13, 15), + Node::new(36, 16, 22), + Node::new(35, 8, 9), + Node::new(35, 5, 11), + Node::new(35, 0, 12), + Node::new(35, 4, 13), + Node::new(35, 6, 14), + Node::new(35, 2, 10), + Node::new(35, 7, 15), + Node::new(35, 1, 3), + Node::new(34, 0, 2), + Node::new(34, 3, 1), + Node::new(34, 4, 5), + Node::new(34, 7, 6), + Node::new(33, 3, 0), + Node::new(33, 2, 1), + Node::new(32, 1, 0), + ], + [0, 30, 46, 54, 58, 60], + 30, + )), + AnyBitCircuit::B4(BitCircuit::new( + [ + Node::new(0, 0, 0), + Node::new(28, 1, 0), + Node::new(10, 1, 0), + Node::new(27, 1, 0), + Node::new(14, 1, 0), + Node::new(11, 1, 0), + Node::new(16, 1, 0), + Node::new(13, 1, 0), + Node::new(18, 1, 0), + Node::new(22, 1, 0), + Node::new(26, 1, 0), + Node::new(20, 1, 0), + Node::new(8, 1, 0), + Node::new(17, 1, 0), + Node::new(5, 1, 0), + Node::new(24, 1, 0), + Node::new(23, 1, 0), + Node::new(15, 1, 0), + Node::new(4, 1, 0), + Node::new(25, 1, 0), + Node::new(31, 1, 0), + Node::new(30, 1, 0), + Node::new(6, 1, 0), + Node::new(29, 1, 0), + Node::new(9, 1, 0), + Node::new(12, 1, 0), + Node::new(19, 1, 0), + Node::new(21, 1, 0), + Node::new(7, 1, 0), + Node::new(36, 9, 22), + Node::new(36, 21, 4), + Node::new(36, 15, 12), + Node::new(36, 3, 5), + Node::new(36, 23, 7), + Node::new(36, 19, 24), + Node::new(36, 16, 28), + Node::new(36, 10, 2), + Node::new(36, 0, 6), + Node::new(36, 1, 25), + Node::new(36, 20, 17), + Node::new(36, 11, 18), + Node::new(36, 0, 13), + Node::new(36, 27, 14), + Node::new(36, 0, 8), + Node::new(36, 0, 26), + Node::new(35, 14, 7), + Node::new(35, 15, 3), + Node::new(35, 10, 6), + Node::new(35, 4, 13), + Node::new(35, 8, 2), + Node::new(35, 12, 5), + Node::new(35, 9, 11), + Node::new(35, 1, 0), + Node::new(34, 4, 6), + Node::new(34, 5, 3), + Node::new(34, 0, 7), + Node::new(34, 1, 2), + Node::new(33, 2, 0), + Node::new(33, 3, 1), + Node::new(32, 1, 0), + ], + [0, 29, 45, 53, 57, 59], + 29, + )), + AnyBitCircuit::B5(BitCircuit::new( + [ + Node::new(0, 0, 0), + Node::new(5, 1, 0), + Node::new(10, 1, 0), + Node::new(7, 1, 0), + Node::new(26, 1, 0), + Node::new(18, 1, 0), + Node::new(20, 1, 0), + Node::new(28, 1, 0), + Node::new(24, 1, 0), + Node::new(8, 1, 0), + Node::new(13, 1, 0), + Node::new(27, 1, 0), + Node::new(29, 1, 0), + Node::new(31, 1, 0), + Node::new(6, 1, 0), + Node::new(23, 1, 0), + Node::new(11, 1, 0), + Node::new(16, 1, 0), + Node::new(17, 1, 0), + Node::new(9, 1, 0), + Node::new(15, 1, 0), + Node::new(14, 1, 0), + Node::new(19, 1, 0), + Node::new(30, 1, 0), + Node::new(12, 1, 0), + Node::new(22, 1, 0), + Node::new(25, 1, 0), + Node::new(21, 1, 0), + Node::new(36, 23, 21), + Node::new(36, 7, 24), + Node::new(36, 12, 10), + Node::new(36, 13, 20), + Node::new(36, 0, 5), + Node::new(36, 26, 19), + Node::new(36, 8, 9), + Node::new(36, 25, 14), + Node::new(36, 0, 18), + Node::new(36, 0, 17), + Node::new(36, 4, 2), + Node::new(36, 0, 6), + Node::new(36, 15, 3), + Node::new(36, 27, 1), + Node::new(36, 0, 22), + Node::new(36, 11, 16), + Node::new(35, 4, 10), + Node::new(35, 14, 15), + Node::new(35, 8, 5), + Node::new(35, 3, 12), + Node::new(35, 11, 1), + Node::new(35, 2, 13), + Node::new(35, 0, 7), + Node::new(35, 9, 6), + Node::new(34, 2, 5), + Node::new(34, 4, 7), + Node::new(34, 1, 3), + Node::new(34, 0, 6), + Node::new(33, 2, 0), + Node::new(33, 1, 3), + Node::new(32, 1, 0), + ], + [0, 28, 44, 52, 56, 58], + 28, + )), + AnyBitCircuit::B6(BitCircuit::new( + [ + Node::new(0, 0, 0), + Node::new(21, 1, 0), + Node::new(20, 1, 0), + Node::new(23, 1, 0), + Node::new(29, 1, 0), + Node::new(7, 1, 0), + Node::new(10, 1, 0), + Node::new(13, 1, 0), + Node::new(14, 1, 0), + Node::new(22, 1, 0), + Node::new(31, 1, 0), + Node::new(27, 1, 0), + Node::new(11, 1, 0), + Node::new(19, 1, 0), + Node::new(9, 1, 0), + Node::new(24, 1, 0), + Node::new(16, 1, 0), + Node::new(17, 1, 0), + Node::new(28, 1, 0), + Node::new(6, 1, 0), + Node::new(26, 1, 0), + Node::new(18, 1, 0), + Node::new(8, 1, 0), + Node::new(12, 1, 0), + Node::new(15, 1, 0), + Node::new(30, 1, 0), + Node::new(25, 1, 0), + Node::new(36, 11, 12), + Node::new(36, 26, 14), + Node::new(36, 20, 6), + Node::new(36, 15, 22), + Node::new(36, 0, 16), + Node::new(36, 0, 2), + Node::new(36, 0, 17), + Node::new(36, 0, 21), + Node::new(36, 18, 23), + Node::new(36, 9, 19), + Node::new(36, 0, 13), + Node::new(36, 3, 5), + Node::new(36, 25, 8), + Node::new(36, 0, 1), + Node::new(36, 4, 7), + Node::new(36, 10, 24), + Node::new(35, 15, 11), + Node::new(35, 6, 1), + Node::new(35, 13, 14), + Node::new(35, 12, 9), + Node::new(35, 7, 2), + Node::new(35, 5, 8), + Node::new(35, 4, 3), + Node::new(35, 10, 0), + Node::new(34, 2, 1), + Node::new(34, 4, 3), + Node::new(34, 5, 6), + Node::new(34, 7, 0), + Node::new(33, 2, 1), + Node::new(33, 0, 3), + Node::new(32, 1, 0), + ], + [0, 27, 43, 51, 55, 57], + 27, + )), + AnyBitCircuit::B7(BitCircuit::new( + [ + Node::new(0, 0, 0), + Node::new(16, 1, 0), + Node::new(30, 1, 0), + Node::new(13, 1, 0), + Node::new(17, 1, 0), + Node::new(21, 1, 0), + Node::new(15, 1, 0), + Node::new(27, 1, 0), + Node::new(26, 1, 0), + Node::new(12, 1, 0), + Node::new(20, 1, 0), + Node::new(29, 1, 0), + Node::new(11, 1, 0), + Node::new(22, 1, 0), + Node::new(8, 1, 0), + Node::new(7, 1, 0), + Node::new(9, 1, 0), + Node::new(31, 1, 0), + Node::new(23, 1, 0), + Node::new(25, 1, 0), + Node::new(10, 1, 0), + Node::new(24, 1, 0), + Node::new(28, 1, 0), + Node::new(18, 1, 0), + Node::new(14, 1, 0), + Node::new(19, 1, 0), + Node::new(36, 0, 23), + Node::new(36, 2, 24), + Node::new(36, 7, 12), + Node::new(36, 22, 9), + Node::new(36, 0, 13), + Node::new(36, 8, 20), + Node::new(36, 0, 5), + Node::new(36, 0, 10), + Node::new(36, 21, 14), + Node::new(36, 17, 6), + Node::new(36, 0, 25), + Node::new(36, 19, 16), + Node::new(36, 11, 3), + Node::new(36, 0, 4), + Node::new(36, 18, 15), + Node::new(36, 0, 1), + Node::new(35, 9, 14), + Node::new(35, 7, 3), + Node::new(35, 10, 2), + Node::new(35, 15, 8), + Node::new(35, 6, 12), + Node::new(35, 4, 1), + Node::new(35, 0, 5), + Node::new(35, 13, 11), + Node::new(34, 4, 7), + Node::new(34, 1, 3), + Node::new(34, 5, 6), + Node::new(34, 2, 0), + Node::new(33, 0, 3), + Node::new(33, 2, 1), + Node::new(32, 1, 0), + ], + [0, 26, 42, 50, 54, 56], + 26, + )), + AnyBitCircuit::B8(BitCircuit::new( + [ + Node::new(0, 0, 0), + Node::new(19, 1, 0), + Node::new(29, 1, 0), + Node::new(12, 1, 0), + Node::new(8, 1, 0), + Node::new(26, 1, 0), + Node::new(21, 1, 0), + Node::new(20, 1, 0), + Node::new(17, 1, 0), + Node::new(14, 1, 0), + Node::new(22, 1, 0), + Node::new(13, 1, 0), + Node::new(18, 1, 0), + Node::new(11, 1, 0), + Node::new(24, 1, 0), + Node::new(28, 1, 0), + Node::new(16, 1, 0), + Node::new(25, 1, 0), + Node::new(30, 1, 0), + Node::new(10, 1, 0), + Node::new(9, 1, 0), + Node::new(31, 1, 0), + Node::new(27, 1, 0), + Node::new(15, 1, 0), + Node::new(23, 1, 0), + Node::new(36, 15, 3), + Node::new(36, 0, 10), + Node::new(36, 0, 24), + Node::new(36, 14, 4), + Node::new(36, 0, 1), + Node::new(36, 0, 6), + Node::new(36, 5, 19), + Node::new(36, 0, 7), + Node::new(36, 17, 20), + Node::new(36, 2, 11), + Node::new(36, 0, 8), + Node::new(36, 22, 13), + Node::new(36, 18, 9), + Node::new(36, 0, 12), + Node::new(36, 0, 16), + Node::new(36, 21, 23), + Node::new(35, 4, 11), + Node::new(35, 2, 15), + Node::new(35, 14, 3), + Node::new(35, 1, 12), + Node::new(35, 10, 8), + Node::new(35, 7, 0), + Node::new(35, 5, 9), + Node::new(35, 13, 6), + Node::new(34, 5, 2), + Node::new(34, 6, 4), + Node::new(34, 1, 0), + Node::new(34, 3, 7), + Node::new(33, 3, 0), + Node::new(33, 2, 1), + Node::new(32, 1, 0), + ], + [0, 25, 41, 49, 53, 55], + 25, + )), + AnyBitCircuit::B9(BitCircuit::new( + [ + Node::new(0, 0, 0), + Node::new(23, 1, 0), + Node::new(29, 1, 0), + Node::new(31, 1, 0), + Node::new(10, 1, 0), + Node::new(21, 1, 0), + Node::new(18, 1, 0), + Node::new(22, 1, 0), + Node::new(26, 1, 0), + Node::new(14, 1, 0), + Node::new(12, 1, 0), + Node::new(28, 1, 0), + Node::new(20, 1, 0), + Node::new(16, 1, 0), + Node::new(24, 1, 0), + Node::new(9, 1, 0), + Node::new(17, 1, 0), + Node::new(13, 1, 0), + Node::new(25, 1, 0), + Node::new(30, 1, 0), + Node::new(15, 1, 0), + Node::new(19, 1, 0), + Node::new(11, 1, 0), + Node::new(27, 1, 0), + Node::new(36, 0, 16), + Node::new(36, 8, 4), + Node::new(36, 0, 12), + Node::new(36, 0, 14), + Node::new(36, 19, 9), + Node::new(36, 0, 5), + Node::new(36, 2, 17), + Node::new(36, 18, 15), + Node::new(36, 0, 21), + Node::new(36, 11, 10), + Node::new(36, 0, 13), + Node::new(36, 3, 20), + Node::new(36, 0, 7), + Node::new(36, 0, 1), + Node::new(36, 0, 6), + Node::new(36, 23, 22), + Node::new(35, 2, 9), + Node::new(35, 3, 10), + Node::new(35, 0, 7), + Node::new(35, 8, 15), + Node::new(35, 14, 1), + Node::new(35, 5, 6), + Node::new(35, 12, 4), + Node::new(35, 13, 11), + Node::new(34, 5, 2), + Node::new(34, 7, 3), + Node::new(34, 1, 0), + Node::new(34, 6, 4), + Node::new(33, 1, 0), + Node::new(33, 2, 3), + Node::new(32, 1, 0), + ], + [0, 24, 40, 48, 52, 54], + 24, + )), + AnyBitCircuit::B10(BitCircuit::new( + [ + Node::new(0, 0, 0), + Node::new(21, 1, 0), + Node::new(10, 1, 0), + Node::new(25, 1, 0), + Node::new(18, 1, 0), + Node::new(24, 1, 0), + Node::new(28, 1, 0), + Node::new(26, 1, 0), + Node::new(19, 1, 0), + Node::new(27, 1, 0), + Node::new(14, 1, 0), + Node::new(20, 1, 0), + Node::new(13, 1, 0), + Node::new(22, 1, 0), + Node::new(23, 1, 0), + Node::new(12, 1, 0), + Node::new(15, 1, 0), + Node::new(16, 1, 0), + Node::new(31, 1, 0), + Node::new(29, 1, 0), + Node::new(17, 1, 0), + Node::new(30, 1, 0), + Node::new(11, 1, 0), + Node::new(36, 0, 11), + Node::new(36, 0, 5), + Node::new(36, 18, 16), + Node::new(36, 0, 4), + Node::new(36, 21, 10), + Node::new(36, 6, 15), + Node::new(36, 19, 12), + Node::new(36, 0, 1), + Node::new(36, 7, 2), + Node::new(36, 0, 20), + Node::new(36, 0, 13), + Node::new(36, 0, 14), + Node::new(36, 0, 3), + Node::new(36, 0, 17), + Node::new(36, 9, 22), + Node::new(36, 0, 8), + Node::new(35, 12, 9), + Node::new(35, 11, 2), + Node::new(35, 0, 5), + Node::new(35, 1, 13), + Node::new(35, 7, 6), + Node::new(35, 3, 8), + Node::new(35, 10, 4), + Node::new(35, 15, 14), + Node::new(34, 0, 4), + Node::new(34, 3, 2), + Node::new(34, 6, 5), + Node::new(34, 1, 7), + Node::new(33, 0, 3), + Node::new(33, 1, 2), + Node::new(32, 0, 1), + ], + [0, 23, 39, 47, 51, 53], + 23, + )), + AnyBitCircuit::B11(BitCircuit::new( + [ + Node::new(0, 0, 0), + Node::new(28, 1, 0), + Node::new(23, 1, 0), + Node::new(21, 1, 0), + Node::new(15, 1, 0), + Node::new(24, 1, 0), + Node::new(30, 1, 0), + Node::new(27, 1, 0), + Node::new(14, 1, 0), + Node::new(18, 1, 0), + Node::new(26, 1, 0), + Node::new(19, 1, 0), + Node::new(17, 1, 0), + Node::new(25, 1, 0), + Node::new(29, 1, 0), + Node::new(16, 1, 0), + Node::new(12, 1, 0), + Node::new(22, 1, 0), + Node::new(31, 1, 0), + Node::new(20, 1, 0), + Node::new(13, 1, 0), + Node::new(11, 1, 0), + Node::new(36, 0, 15), + Node::new(36, 0, 12), + Node::new(36, 0, 10), + Node::new(36, 0, 11), + Node::new(36, 0, 3), + Node::new(36, 0, 19), + Node::new(36, 0, 5), + Node::new(36, 6, 8), + Node::new(36, 0, 17), + Node::new(36, 14, 20), + Node::new(36, 18, 4), + Node::new(36, 7, 21), + Node::new(36, 0, 13), + Node::new(36, 0, 9), + Node::new(36, 1, 16), + Node::new(36, 0, 2), + Node::new(35, 5, 14), + Node::new(35, 12, 1), + Node::new(35, 15, 10), + Node::new(35, 3, 11), + Node::new(35, 6, 0), + Node::new(35, 8, 7), + Node::new(35, 4, 9), + Node::new(35, 2, 13), + Node::new(34, 4, 0), + Node::new(34, 1, 6), + Node::new(34, 2, 3), + Node::new(34, 7, 5), + Node::new(33, 3, 0), + Node::new(33, 1, 2), + Node::new(32, 0, 1), + ], + [0, 22, 38, 46, 50, 52], + 22, + )), + AnyBitCircuit::B12(BitCircuit::new( + [ + Node::new(0, 0, 0), + Node::new(19, 1, 0), + Node::new(23, 1, 0), + Node::new(12, 1, 0), + Node::new(13, 1, 0), + Node::new(26, 1, 0), + Node::new(29, 1, 0), + Node::new(17, 1, 0), + Node::new(28, 1, 0), + Node::new(25, 1, 0), + Node::new(21, 1, 0), + Node::new(30, 1, 0), + Node::new(18, 1, 0), + Node::new(31, 1, 0), + Node::new(24, 1, 0), + Node::new(20, 1, 0), + Node::new(16, 1, 0), + Node::new(15, 1, 0), + Node::new(14, 1, 0), + Node::new(27, 1, 0), + Node::new(22, 1, 0), + Node::new(36, 13, 17), + Node::new(36, 0, 20), + Node::new(36, 0, 10), + Node::new(36, 0, 7), + Node::new(36, 8, 3), + Node::new(36, 0, 14), + Node::new(36, 0, 15), + Node::new(36, 0, 12), + Node::new(36, 0, 2), + Node::new(36, 0, 19), + Node::new(36, 0, 9), + Node::new(36, 0, 16), + Node::new(36, 0, 5), + Node::new(36, 0, 1), + Node::new(36, 11, 18), + Node::new(36, 6, 4), + Node::new(35, 6, 4), + Node::new(35, 12, 7), + Node::new(35, 10, 3), + Node::new(35, 5, 11), + Node::new(35, 2, 15), + Node::new(35, 8, 0), + Node::new(35, 9, 13), + Node::new(35, 1, 14), + Node::new(34, 3, 0), + Node::new(34, 1, 7), + Node::new(34, 2, 4), + Node::new(34, 6, 5), + Node::new(33, 1, 0), + Node::new(33, 3, 2), + Node::new(32, 1, 0), + ], + [0, 21, 37, 45, 49, 51], + 21, + )), + AnyBitCircuit::B13(BitCircuit::new( + [ + Node::new(0, 0, 0), + Node::new(31, 1, 0), + Node::new(22, 1, 0), + Node::new(27, 1, 0), + Node::new(24, 1, 0), + Node::new(20, 1, 0), + Node::new(17, 1, 0), + Node::new(13, 1, 0), + Node::new(25, 1, 0), + Node::new(18, 1, 0), + Node::new(29, 1, 0), + Node::new(23, 1, 0), + Node::new(21, 1, 0), + Node::new(15, 1, 0), + Node::new(16, 1, 0), + Node::new(19, 1, 0), + Node::new(26, 1, 0), + Node::new(28, 1, 0), + Node::new(14, 1, 0), + Node::new(30, 1, 0), + Node::new(36, 19, 18), + Node::new(36, 0, 14), + Node::new(36, 0, 17), + Node::new(36, 0, 3), + Node::new(36, 1, 13), + Node::new(36, 0, 2), + Node::new(36, 0, 12), + Node::new(36, 0, 9), + Node::new(36, 0, 4), + Node::new(36, 0, 8), + Node::new(36, 0, 16), + Node::new(36, 0, 6), + Node::new(36, 0, 5), + Node::new(36, 0, 15), + Node::new(36, 10, 7), + Node::new(36, 0, 11), + Node::new(35, 6, 14), + Node::new(35, 8, 1), + Node::new(35, 5, 0), + Node::new(35, 2, 12), + Node::new(35, 9, 11), + Node::new(35, 3, 13), + Node::new(35, 10, 7), + Node::new(35, 15, 4), + Node::new(34, 6, 2), + Node::new(34, 5, 7), + Node::new(34, 4, 0), + Node::new(34, 3, 1), + Node::new(33, 1, 2), + Node::new(33, 3, 0), + Node::new(32, 1, 0), + ], + [0, 20, 36, 44, 48, 50], + 20, + )), + AnyBitCircuit::B14(BitCircuit::new( + [ + Node::new(0, 0, 0), + Node::new(19, 1, 0), + Node::new(15, 1, 0), + Node::new(25, 1, 0), + Node::new(30, 1, 0), + Node::new(16, 1, 0), + Node::new(22, 1, 0), + Node::new(28, 1, 0), + Node::new(27, 1, 0), + Node::new(24, 1, 0), + Node::new(26, 1, 0), + Node::new(20, 1, 0), + Node::new(31, 1, 0), + Node::new(21, 1, 0), + Node::new(17, 1, 0), + Node::new(29, 1, 0), + Node::new(14, 1, 0), + Node::new(23, 1, 0), + Node::new(18, 1, 0), + Node::new(36, 0, 5), + Node::new(36, 0, 11), + Node::new(36, 0, 14), + Node::new(36, 0, 1), + Node::new(36, 0, 6), + Node::new(36, 4, 16), + Node::new(36, 0, 10), + Node::new(36, 0, 8), + Node::new(36, 0, 17), + Node::new(36, 0, 9), + Node::new(36, 0, 18), + Node::new(36, 0, 3), + Node::new(36, 0, 7), + Node::new(36, 0, 15), + Node::new(36, 0, 13), + Node::new(36, 12, 2), + Node::new(35, 11, 2), + Node::new(35, 4, 5), + Node::new(35, 13, 14), + Node::new(35, 9, 0), + Node::new(35, 6, 10), + Node::new(35, 7, 3), + Node::new(35, 8, 15), + Node::new(35, 12, 1), + Node::new(34, 7, 3), + Node::new(34, 5, 6), + Node::new(34, 4, 1), + Node::new(34, 2, 0), + Node::new(33, 0, 2), + Node::new(33, 3, 1), + Node::new(32, 1, 0), + ], + [0, 19, 35, 43, 47, 49], + 19, + )), + AnyBitCircuit::B15(BitCircuit::new( + [ + Node::new(0, 0, 0), + Node::new(20, 1, 0), + Node::new(25, 1, 0), + Node::new(30, 1, 0), + Node::new(15, 1, 0), + Node::new(19, 1, 0), + Node::new(16, 1, 0), + Node::new(17, 1, 0), + Node::new(18, 1, 0), + Node::new(23, 1, 0), + Node::new(28, 1, 0), + Node::new(26, 1, 0), + Node::new(31, 1, 0), + Node::new(24, 1, 0), + Node::new(29, 1, 0), + Node::new(21, 1, 0), + Node::new(27, 1, 0), + Node::new(22, 1, 0), + Node::new(36, 12, 4), + Node::new(36, 0, 2), + Node::new(36, 0, 8), + Node::new(36, 0, 3), + Node::new(36, 0, 10), + Node::new(36, 0, 15), + Node::new(36, 0, 1), + Node::new(36, 0, 14), + Node::new(36, 0, 11), + Node::new(36, 0, 17), + Node::new(36, 0, 9), + Node::new(36, 0, 5), + Node::new(36, 0, 16), + Node::new(36, 0, 13), + Node::new(36, 0, 7), + Node::new(36, 0, 6), + Node::new(35, 8, 2), + Node::new(35, 4, 6), + Node::new(35, 1, 14), + Node::new(35, 10, 0), + Node::new(35, 3, 9), + Node::new(35, 13, 15), + Node::new(35, 12, 11), + Node::new(35, 7, 5), + Node::new(34, 1, 5), + Node::new(34, 4, 0), + Node::new(34, 6, 3), + Node::new(34, 7, 2), + Node::new(33, 1, 0), + Node::new(33, 3, 2), + Node::new(32, 0, 1), + ], + [0, 18, 34, 42, 46, 48], + 18, + )), + AnyBitCircuit::B16(BitCircuit::new( + [ + Node::new(0, 0, 0), + Node::new(17, 1, 0), + Node::new(28, 1, 0), + Node::new(30, 1, 0), + Node::new(18, 1, 0), + Node::new(22, 1, 0), + Node::new(27, 1, 0), + Node::new(16, 1, 0), + Node::new(20, 1, 0), + Node::new(25, 1, 0), + Node::new(24, 1, 0), + Node::new(26, 1, 0), + Node::new(21, 1, 0), + Node::new(23, 1, 0), + Node::new(31, 1, 0), + Node::new(29, 1, 0), + Node::new(19, 1, 0), + Node::new(36, 0, 8), + Node::new(36, 0, 11), + Node::new(36, 0, 13), + Node::new(36, 0, 3), + Node::new(36, 0, 15), + Node::new(36, 0, 16), + Node::new(36, 0, 12), + Node::new(36, 0, 6), + Node::new(36, 0, 2), + Node::new(36, 0, 7), + Node::new(36, 0, 4), + Node::new(36, 0, 5), + Node::new(36, 0, 10), + Node::new(36, 0, 9), + Node::new(36, 0, 14), + Node::new(36, 0, 1), + Node::new(35, 13, 15), + Node::new(35, 12, 9), + Node::new(35, 3, 11), + Node::new(35, 8, 0), + Node::new(35, 7, 5), + Node::new(35, 14, 2), + Node::new(35, 1, 10), + Node::new(35, 4, 6), + Node::new(34, 3, 1), + Node::new(34, 5, 4), + Node::new(34, 2, 6), + Node::new(34, 7, 0), + Node::new(33, 2, 0), + Node::new(33, 1, 3), + Node::new(32, 1, 0), + ], + [0, 17, 33, 41, 45, 47], + 17, + )), + AnyBitCircuit::B17(BitCircuit::new( + [ + Node::new(0, 0, 0), + Node::new(24, 1, 0), + Node::new(21, 1, 0), + Node::new(28, 1, 0), + Node::new(22, 1, 0), + Node::new(29, 1, 0), + Node::new(25, 1, 0), + Node::new(20, 1, 0), + Node::new(19, 1, 0), + Node::new(26, 1, 0), + Node::new(23, 1, 0), + Node::new(18, 1, 0), + Node::new(30, 1, 0), + Node::new(17, 1, 0), + Node::new(27, 1, 0), + Node::new(31, 1, 0), + Node::new(0, 0, 0), + Node::new(36, 0, 8), + Node::new(36, 0, 4), + Node::new(36, 0, 15), + Node::new(36, 0, 11), + Node::new(36, 0, 14), + Node::new(36, 0, 7), + Node::new(36, 0, 1), + Node::new(36, 0, 5), + Node::new(36, 0, 9), + Node::new(36, 0, 12), + Node::new(36, 0, 13), + Node::new(36, 0, 10), + Node::new(36, 0, 3), + Node::new(36, 0, 6), + Node::new(36, 0, 2), + Node::new(35, 13, 6), + Node::new(35, 0, 7), + Node::new(35, 10, 2), + Node::new(35, 9, 4), + Node::new(35, 5, 1), + Node::new(35, 3, 12), + Node::new(35, 8, 15), + Node::new(35, 14, 11), + Node::new(34, 2, 3), + Node::new(34, 6, 7), + Node::new(34, 5, 4), + Node::new(34, 1, 0), + Node::new(33, 3, 0), + Node::new(33, 2, 1), + Node::new(32, 0, 1), + ], + [0, 16, 32, 40, 44, 46], + 16, + )), + AnyBitCircuit::B18(BitCircuit::new( + [ + Node::new(0, 0, 0), + Node::new(23, 1, 0), + Node::new(24, 1, 0), + Node::new(18, 1, 0), + Node::new(22, 1, 0), + Node::new(30, 1, 0), + Node::new(27, 1, 0), + Node::new(25, 1, 0), + Node::new(31, 1, 0), + Node::new(21, 1, 0), + Node::new(26, 1, 0), + Node::new(19, 1, 0), + Node::new(28, 1, 0), + Node::new(29, 1, 0), + Node::new(20, 1, 0), + Node::new(0, 0, 0), + Node::new(36, 0, 9), + Node::new(36, 0, 8), + Node::new(36, 0, 13), + Node::new(36, 0, 4), + Node::new(36, 0, 1), + Node::new(36, 0, 3), + Node::new(36, 0, 5), + Node::new(36, 0, 6), + Node::new(36, 0, 14), + Node::new(36, 0, 11), + Node::new(36, 0, 10), + Node::new(36, 0, 7), + Node::new(36, 0, 2), + Node::new(36, 0, 12), + Node::new(35, 0, 12), + Node::new(35, 3, 1), + Node::new(35, 7, 4), + Node::new(35, 8, 10), + Node::new(35, 14, 9), + Node::new(35, 0, 13), + Node::new(35, 11, 6), + Node::new(35, 2, 5), + Node::new(34, 2, 6), + Node::new(34, 5, 4), + Node::new(34, 0, 1), + Node::new(34, 7, 3), + Node::new(33, 2, 3), + Node::new(33, 1, 0), + Node::new(32, 0, 1), + ], + [0, 15, 30, 38, 42, 44], + 15, + )), + AnyBitCircuit::B19(BitCircuit::new( + [ + Node::new(0, 0, 0), + Node::new(27, 1, 0), + Node::new(19, 1, 0), + Node::new(25, 1, 0), + Node::new(26, 1, 0), + Node::new(21, 1, 0), + Node::new(29, 1, 0), + Node::new(30, 1, 0), + Node::new(22, 1, 0), + Node::new(28, 1, 0), + Node::new(20, 1, 0), + Node::new(23, 1, 0), + Node::new(24, 1, 0), + Node::new(31, 1, 0), + Node::new(0, 0, 0), + Node::new(36, 0, 2), + Node::new(36, 0, 11), + Node::new(36, 0, 12), + Node::new(36, 0, 1), + Node::new(36, 0, 8), + Node::new(36, 0, 4), + Node::new(36, 0, 9), + Node::new(36, 0, 13), + Node::new(36, 0, 10), + Node::new(36, 0, 3), + Node::new(36, 0, 6), + Node::new(36, 0, 5), + Node::new(36, 0, 7), + Node::new(35, 4, 1), + Node::new(35, 0, 6), + Node::new(35, 0, 10), + Node::new(35, 11, 12), + Node::new(35, 8, 2), + Node::new(35, 7, 9), + Node::new(35, 0, 3), + Node::new(35, 13, 5), + Node::new(34, 6, 5), + Node::new(34, 1, 7), + Node::new(34, 4, 0), + Node::new(34, 2, 3), + Node::new(33, 1, 0), + Node::new(33, 3, 2), + Node::new(32, 0, 1), + ], + [0, 14, 28, 36, 40, 42], + 14, + )), + AnyBitCircuit::B20(BitCircuit::new( + [ + Node::new(0, 0, 0), + Node::new(24, 1, 0), + Node::new(23, 1, 0), + Node::new(27, 1, 0), + Node::new(31, 1, 0), + Node::new(22, 1, 0), + Node::new(28, 1, 0), + Node::new(20, 1, 0), + Node::new(29, 1, 0), + Node::new(21, 1, 0), + Node::new(30, 1, 0), + Node::new(25, 1, 0), + Node::new(26, 1, 0), + Node::new(0, 0, 0), + Node::new(36, 0, 6), + Node::new(36, 0, 10), + Node::new(36, 0, 7), + Node::new(36, 0, 2), + Node::new(36, 0, 5), + Node::new(36, 0, 12), + Node::new(36, 0, 8), + Node::new(36, 0, 11), + Node::new(36, 0, 9), + Node::new(36, 0, 3), + Node::new(36, 0, 4), + Node::new(36, 0, 1), + Node::new(35, 0, 12), + Node::new(35, 2, 5), + Node::new(35, 7, 9), + Node::new(35, 0, 10), + Node::new(35, 1, 3), + Node::new(35, 0, 8), + Node::new(35, 11, 4), + Node::new(35, 0, 6), + Node::new(34, 5, 2), + Node::new(34, 0, 4), + Node::new(34, 3, 6), + Node::new(34, 7, 1), + Node::new(33, 3, 1), + Node::new(33, 2, 0), + Node::new(32, 1, 0), + ], + [0, 13, 26, 34, 38, 40], + 13, + )), + AnyBitCircuit::B21(BitCircuit::new( + [ + Node::new(0, 0, 0), + Node::new(27, 1, 0), + Node::new(30, 1, 0), + Node::new(28, 1, 0), + Node::new(26, 1, 0), + Node::new(24, 1, 0), + Node::new(21, 1, 0), + Node::new(23, 1, 0), + Node::new(29, 1, 0), + Node::new(31, 1, 0), + Node::new(22, 1, 0), + Node::new(25, 1, 0), + Node::new(0, 0, 0), + Node::new(36, 0, 11), + Node::new(36, 0, 8), + Node::new(36, 0, 7), + Node::new(36, 0, 4), + Node::new(36, 0, 1), + Node::new(36, 0, 6), + Node::new(36, 0, 9), + Node::new(36, 0, 10), + Node::new(36, 0, 2), + Node::new(36, 0, 3), + Node::new(36, 0, 5), + Node::new(35, 2, 6), + Node::new(35, 7, 3), + Node::new(35, 0, 1), + Node::new(35, 0, 11), + Node::new(35, 0, 5), + Node::new(35, 9, 8), + Node::new(35, 0, 4), + Node::new(35, 0, 10), + Node::new(34, 7, 3), + Node::new(34, 2, 0), + Node::new(34, 4, 1), + Node::new(34, 6, 5), + Node::new(33, 0, 3), + Node::new(33, 2, 1), + Node::new(32, 0, 1), + ], + [0, 12, 24, 32, 36, 38], + 12, + )), + AnyBitCircuit::B22(BitCircuit::new( + [ + Node::new(0, 0, 0), + Node::new(30, 1, 0), + Node::new(31, 1, 0), + Node::new(27, 1, 0), + Node::new(23, 1, 0), + Node::new(29, 1, 0), + Node::new(22, 1, 0), + Node::new(26, 1, 0), + Node::new(25, 1, 0), + Node::new(24, 1, 0), + Node::new(28, 1, 0), + Node::new(0, 0, 0), + Node::new(36, 0, 3), + Node::new(36, 0, 1), + Node::new(36, 0, 10), + Node::new(36, 0, 5), + Node::new(36, 0, 2), + Node::new(36, 0, 9), + Node::new(36, 0, 4), + Node::new(36, 0, 7), + Node::new(36, 0, 6), + Node::new(36, 0, 8), + Node::new(35, 0, 1), + Node::new(35, 0, 10), + Node::new(35, 0, 6), + Node::new(35, 0, 3), + Node::new(35, 0, 8), + Node::new(35, 0, 4), + Node::new(35, 2, 9), + Node::new(35, 5, 7), + Node::new(34, 0, 7), + Node::new(34, 5, 1), + Node::new(34, 4, 6), + Node::new(34, 3, 2), + Node::new(33, 3, 2), + Node::new(33, 1, 0), + Node::new(32, 1, 0), + ], + [0, 11, 22, 30, 34, 36], + 11, + )), + AnyBitCircuit::B23(BitCircuit::new( + [ + Node::new(0, 0, 0), + Node::new(25, 1, 0), + Node::new(30, 1, 0), + Node::new(24, 1, 0), + Node::new(26, 1, 0), + Node::new(27, 1, 0), + Node::new(23, 1, 0), + Node::new(28, 1, 0), + Node::new(31, 1, 0), + Node::new(29, 1, 0), + Node::new(0, 0, 0), + Node::new(36, 0, 7), + Node::new(36, 0, 1), + Node::new(36, 0, 8), + Node::new(36, 0, 4), + Node::new(36, 0, 2), + Node::new(36, 0, 5), + Node::new(36, 0, 3), + Node::new(36, 0, 6), + Node::new(36, 0, 9), + Node::new(35, 0, 5), + Node::new(35, 0, 6), + Node::new(35, 0, 4), + Node::new(35, 0, 2), + Node::new(35, 3, 8), + Node::new(35, 0, 7), + Node::new(35, 0, 1), + Node::new(35, 0, 9), + Node::new(34, 1, 4), + Node::new(34, 6, 5), + Node::new(34, 7, 3), + Node::new(34, 0, 2), + Node::new(33, 3, 1), + Node::new(33, 2, 0), + Node::new(32, 0, 1), + ], + [0, 10, 20, 28, 32, 34], + 10, + )), + AnyBitCircuit::B24(BitCircuit::new( + [ + Node::new(0, 0, 0), + Node::new(29, 1, 0), + Node::new(24, 1, 0), + Node::new(25, 1, 0), + Node::new(26, 1, 0), + Node::new(30, 1, 0), + Node::new(27, 1, 0), + Node::new(28, 1, 0), + Node::new(31, 1, 0), + Node::new(0, 0, 0), + Node::new(36, 0, 5), + Node::new(36, 0, 3), + Node::new(36, 0, 1), + Node::new(36, 0, 7), + Node::new(36, 0, 2), + Node::new(36, 0, 4), + Node::new(36, 0, 6), + Node::new(36, 0, 8), + Node::new(35, 0, 7), + Node::new(35, 0, 6), + Node::new(35, 0, 1), + Node::new(35, 0, 2), + Node::new(35, 0, 8), + Node::new(35, 0, 5), + Node::new(35, 0, 4), + Node::new(35, 0, 3), + Node::new(34, 2, 1), + Node::new(34, 4, 0), + Node::new(34, 7, 3), + Node::new(34, 6, 5), + Node::new(33, 1, 2), + Node::new(33, 0, 3), + Node::new(32, 0, 1), + ], + [0, 9, 18, 26, 30, 32], + 9, + )), + AnyBitCircuit::B25(BitCircuit::new( + [ + Node::new(0, 0, 0), + Node::new(27, 1, 0), + Node::new(26, 1, 0), + Node::new(25, 1, 0), + Node::new(31, 1, 0), + Node::new(30, 1, 0), + Node::new(29, 1, 0), + Node::new(28, 1, 0), + Node::new(0, 0, 0), + Node::new(36, 0, 1), + Node::new(36, 0, 2), + Node::new(36, 0, 5), + Node::new(36, 0, 3), + Node::new(36, 0, 7), + Node::new(36, 0, 4), + Node::new(36, 0, 6), + Node::new(0, 0, 0), + Node::new(35, 0, 3), + Node::new(35, 0, 6), + Node::new(35, 0, 1), + Node::new(35, 0, 5), + Node::new(35, 0, 2), + Node::new(35, 0, 7), + Node::new(35, 0, 4), + Node::new(34, 2, 3), + Node::new(34, 0, 4), + Node::new(34, 1, 5), + Node::new(34, 6, 7), + Node::new(33, 0, 3), + Node::new(33, 1, 2), + Node::new(32, 1, 0), + ], + [0, 8, 16, 24, 28, 30], + 8, + )), + AnyBitCircuit::B26(BitCircuit::new( + [ + Node::new(0, 0, 0), + Node::new(30, 1, 0), + Node::new(27, 1, 0), + Node::new(26, 1, 0), + Node::new(28, 1, 0), + Node::new(31, 1, 0), + Node::new(29, 1, 0), + Node::new(0, 0, 0), + Node::new(36, 0, 3), + Node::new(36, 0, 4), + Node::new(36, 0, 5), + Node::new(36, 0, 1), + Node::new(36, 0, 2), + Node::new(36, 0, 6), + Node::new(0, 0, 0), + Node::new(35, 0, 2), + Node::new(35, 0, 4), + Node::new(35, 0, 3), + Node::new(35, 0, 6), + Node::new(35, 0, 5), + Node::new(35, 0, 1), + Node::new(34, 0, 4), + Node::new(34, 0, 1), + Node::new(34, 2, 6), + Node::new(34, 3, 5), + Node::new(33, 0, 3), + Node::new(33, 1, 2), + Node::new(32, 0, 1), + ], + [0, 7, 14, 21, 25, 27], + 7, + )), + AnyBitCircuit::B27(BitCircuit::new( + [ + Node::new(0, 0, 0), + Node::new(31, 1, 0), + Node::new(30, 1, 0), + Node::new(29, 1, 0), + Node::new(27, 1, 0), + Node::new(28, 1, 0), + Node::new(0, 0, 0), + Node::new(36, 0, 5), + Node::new(36, 0, 3), + Node::new(36, 0, 4), + Node::new(36, 0, 2), + Node::new(36, 0, 1), + Node::new(0, 0, 0), + Node::new(35, 0, 3), + Node::new(35, 0, 1), + Node::new(35, 0, 5), + Node::new(35, 0, 2), + Node::new(35, 0, 4), + Node::new(34, 0, 5), + Node::new(34, 3, 1), + Node::new(34, 0, 2), + Node::new(34, 0, 4), + Node::new(33, 3, 1), + Node::new(33, 0, 2), + Node::new(32, 1, 0), + ], + [0, 6, 12, 18, 22, 24], + 6, + )), + AnyBitCircuit::B28(BitCircuit::new( + [ + Node::new(0, 0, 0), + Node::new(29, 1, 0), + Node::new(31, 1, 0), + Node::new(30, 1, 0), + Node::new(28, 1, 0), + Node::new(0, 0, 0), + Node::new(36, 0, 2), + Node::new(36, 0, 4), + Node::new(36, 0, 1), + Node::new(36, 0, 3), + Node::new(0, 0, 0), + Node::new(35, 0, 2), + Node::new(35, 0, 3), + Node::new(35, 0, 1), + Node::new(35, 0, 4), + Node::new(34, 0, 3), + Node::new(34, 0, 1), + Node::new(34, 0, 2), + Node::new(34, 0, 4), + Node::new(33, 3, 1), + Node::new(33, 0, 2), + Node::new(32, 1, 0), + ], + [0, 5, 10, 15, 19, 21], + 5, + )), + AnyBitCircuit::B29(BitCircuit::new( + [ + Node::new(0, 0, 0), + Node::new(29, 1, 0), + Node::new(30, 1, 0), + Node::new(31, 1, 0), + Node::new(0, 0, 0), + Node::new(36, 0, 1), + Node::new(36, 0, 2), + Node::new(36, 0, 3), + Node::new(0, 0, 0), + Node::new(35, 0, 1), + Node::new(35, 0, 3), + Node::new(35, 0, 2), + Node::new(0, 0, 0), + Node::new(34, 0, 3), + Node::new(34, 0, 1), + Node::new(34, 0, 2), + Node::new(33, 3, 2), + Node::new(33, 0, 1), + Node::new(32, 1, 0), + ], + [0, 4, 8, 12, 16, 18], + 4, + )), + AnyBitCircuit::B30(BitCircuit::new( + [ + Node::new(0, 0, 0), + Node::new(31, 1, 0), + Node::new(30, 1, 0), + Node::new(0, 0, 0), + Node::new(36, 0, 2), + Node::new(36, 0, 1), + Node::new(0, 0, 0), + Node::new(35, 0, 2), + Node::new(35, 0, 1), + Node::new(0, 0, 0), + Node::new(34, 0, 1), + Node::new(34, 0, 2), + Node::new(33, 0, 1), + Node::new(33, 0, 2), + Node::new(32, 0, 1), + ], + [0, 3, 6, 9, 12, 14], + 3, + )), + AnyBitCircuit::B31(BitCircuit::new( + [ + Node::new(0, 0, 0), + Node::new(31, 1, 0), + Node::new(0, 0, 0), + Node::new(36, 0, 1), + Node::new(0, 0, 0), + Node::new(35, 0, 1), + Node::new(0, 0, 0), + Node::new(34, 0, 1), + Node::new(0, 0, 0), + Node::new(33, 0, 1), + Node::new(32, 0, 1), + ], + [0, 2, 4, 6, 8, 10], + 2, + )), +]);
@@ -0,0 +1,3019 @@
+use crate::tfhe::bdd_arithmetic::{BitCircuit, BitCircuitInfo, Circuit, GetBitCircuitInfo, Node}; +pub(crate) enum AnyBitCircuit { + B0(BitCircuit<3, 2>), + B1(BitCircuit<7, 4>), + B2(BitCircuit<12, 6>), + B3(BitCircuit<17, 8>), + B4(BitCircuit<22, 10>), + B5(BitCircuit<27, 12>), + B6(BitCircuit<32, 14>), + B7(BitCircuit<37, 16>), + B8(BitCircuit<42, 18>), + B9(BitCircuit<47, 20>), + B10(BitCircuit<52, 22>), + B11(BitCircuit<57, 24>), + B12(BitCircuit<62, 26>), + B13(BitCircuit<67, 28>), + B14(BitCircuit<72, 30>), + B15(BitCircuit<77, 32>), + B16(BitCircuit<82, 34>), + B17(BitCircuit<87, 36>), + B18(BitCircuit<92, 38>), + B19(BitCircuit<97, 40>), + B20(BitCircuit<102, 42>), + B21(BitCircuit<107, 44>), + B22(BitCircuit<112, 46>), + B23(BitCircuit<117, 48>), + B24(BitCircuit<122, 50>), + B25(BitCircuit<127, 52>), + B26(BitCircuit<132, 54>), + B27(BitCircuit<137, 56>), + B28(BitCircuit<142, 58>), + B29(BitCircuit<147, 60>), + B30(BitCircuit<152, 62>), + B31(BitCircuit<157, 64>), +} +impl BitCircuitInfo for AnyBitCircuit { + fn info(&self) -> (&[Node], &[usize], usize) { + match self { + AnyBitCircuit::B0(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B1(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B2(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B3(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B4(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B5(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B6(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B7(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B8(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B9(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B10(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B11(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B12(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B13(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B14(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B15(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B16(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B17(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B18(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B19(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B20(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B21(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B22(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B23(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B24(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B25(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B26(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B27(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B28(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B29(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B30(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + AnyBitCircuit::B31(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + } + } +} + +impl GetBitCircuitInfo<u32> for Circuit<AnyBitCircuit, 32usize> { + fn input_size(&self) -> usize { + 2 * u32::BITS as usize + } + fn output_size(&self) -> usize { + u32::BITS as usize + } + fn get_circuit(&self, bit: usize) -> (&[Node], &[usize], usize) { + self.0[bit].info() + } +} + +pub(crate) static OUTPUT_CIRCUITS: Circuit<AnyBitCircuit, 32usize> = Circuit([ + AnyBitCircuit::B0(BitCircuit::new( + [Node::new(32, 1, 0), Node::new(32, 0, 1), Node::new(0, 1, 0)], + [0, 2], + 2, + )), + AnyBitCircuit::B1(BitCircuit::new( + [ + Node::new(33, 1, 0), + Node::new(33, 0, 1), + Node::new(1, 1, 0), + Node::new(1, 0, 1), + Node::new(1, 0, 0), + Node::new(32, 1, 0), + Node::new(0, 0, 1), + ], + [0, 2, 4, 6], + 2, + )), + AnyBitCircuit::B2(BitCircuit::new( + [ + Node::new(34, 0, 1), + Node::new(34, 1, 0), + Node::new(2, 1, 0), + Node::new(2, 0, 1), + Node::new(2, 0, 0), + Node::new(2, 1, 1), + Node::new(33, 0, 1), + Node::new(1, 1, 2), + Node::new(1, 2, 0), + Node::new(1, 0, 0), + Node::new(32, 1, 0), + Node::new(0, 0, 1), + ], + [0, 2, 4, 7, 9, 11], + 3, + )), + AnyBitCircuit::B3(BitCircuit::new( + [ + Node::new(35, 0, 1), + Node::new(35, 1, 0), + Node::new(3, 1, 0), + Node::new(3, 0, 1), + Node::new(3, 0, 0), + Node::new(3, 1, 1), + Node::new(34, 0, 1), + Node::new(2, 2, 0), + Node::new(2, 1, 2), + Node::new(2, 0, 0), + Node::new(2, 1, 1), + Node::new(33, 0, 1), + Node::new(1, 1, 2), + Node::new(1, 2, 0), + Node::new(1, 0, 0), + Node::new(32, 1, 0), + Node::new(0, 0, 1), + ], + [0, 2, 4, 7, 9, 12, 14, 16], + 3, + )), + AnyBitCircuit::B4(BitCircuit::new( + [ + Node::new(36, 0, 1), + Node::new(36, 1, 0), + Node::new(4, 0, 1), + Node::new(4, 1, 0), + Node::new(4, 0, 0), + Node::new(4, 1, 1), + Node::new(35, 1, 0), + Node::new(3, 2, 1), + Node::new(3, 0, 2), + Node::new(3, 0, 0), + Node::new(3, 1, 1), + Node::new(34, 0, 1), + Node::new(2, 2, 0), + Node::new(2, 1, 2), + Node::new(2, 0, 0), + Node::new(2, 1, 1), + Node::new(33, 0, 1), + Node::new(1, 1, 2), + Node::new(1, 2, 0), + Node::new(1, 0, 0), + Node::new(32, 1, 0), + Node::new(0, 0, 1), + ], + [0, 2, 4, 7, 9, 12, 14, 17, 19, 21], + 3, + )), + AnyBitCircuit::B5(BitCircuit::new( + [ + Node::new(37, 0, 1), + Node::new(37, 1, 0), + Node::new(5, 1, 0), + Node::new(5, 0, 1), + Node::new(5, 0, 0), + Node::new(5, 1, 1), + Node::new(36, 0, 1), + Node::new(4, 2, 0), + Node::new(4, 1, 2), + Node::new(4, 0, 0), + Node::new(4, 1, 1), + Node::new(35, 0, 1), + Node::new(3, 1, 2), + Node::new(3, 2, 0), + Node::new(3, 0, 0), + Node::new(3, 1, 1), + Node::new(34, 1, 0), + Node::new(2, 2, 1), + Node::new(2, 0, 2), + Node::new(2, 0, 0), + Node::new(2, 1, 1), + Node::new(33, 0, 1), + Node::new(1, 1, 2), + Node::new(1, 2, 0), + Node::new(1, 0, 0), + Node::new(32, 1, 0), + Node::new(0, 0, 1), + ], + [0, 2, 4, 7, 9, 12, 14, 17, 19, 22, 24, 26], + 3, + )), + AnyBitCircuit::B6(BitCircuit::new( + [ + Node::new(38, 0, 1), + Node::new(38, 1, 0), + Node::new(6, 0, 1), + Node::new(6, 1, 0), + Node::new(6, 0, 0), + Node::new(6, 1, 1), + Node::new(37, 1, 0), + Node::new(5, 2, 1), + Node::new(5, 0, 2), + Node::new(5, 0, 0), + Node::new(5, 1, 1), + Node::new(36, 0, 1), + Node::new(4, 1, 2), + Node::new(4, 2, 0), + Node::new(4, 0, 0), + Node::new(4, 1, 1), + Node::new(35, 1, 0), + Node::new(3, 2, 1), + Node::new(3, 0, 2), + Node::new(3, 0, 0), + Node::new(3, 1, 1), + Node::new(34, 0, 1), + Node::new(2, 2, 0), + Node::new(2, 1, 2), + Node::new(2, 0, 0), + Node::new(2, 1, 1), + Node::new(33, 0, 1), + Node::new(1, 1, 2), + Node::new(1, 2, 0), + Node::new(1, 0, 0), + Node::new(32, 1, 0), + Node::new(0, 0, 1), + ], + [0, 2, 4, 7, 9, 12, 14, 17, 19, 22, 24, 27, 29, 31], + 3, + )), + AnyBitCircuit::B7(BitCircuit::new( + [ + Node::new(39, 1, 0), + Node::new(39, 0, 1), + Node::new(7, 0, 1), + Node::new(7, 1, 0), + Node::new(7, 0, 0), + Node::new(7, 1, 1), + Node::new(38, 0, 1), + Node::new(6, 1, 2), + Node::new(6, 2, 0), + Node::new(6, 0, 0), + Node::new(6, 1, 1), + Node::new(37, 1, 0), + Node::new(5, 2, 1), + Node::new(5, 0, 2), + Node::new(5, 0, 0), + Node::new(5, 1, 1), + Node::new(36, 0, 1), + Node::new(4, 2, 0), + Node::new(4, 1, 2), + Node::new(4, 0, 0), + Node::new(4, 1, 1), + Node::new(35, 0, 1), + Node::new(3, 2, 0), + Node::new(3, 1, 2), + Node::new(3, 0, 0), + Node::new(3, 1, 1), + Node::new(34, 0, 1), + Node::new(2, 1, 2), + Node::new(2, 2, 0), + Node::new(2, 0, 0), + Node::new(2, 1, 1), + Node::new(33, 1, 0), + Node::new(1, 0, 2), + Node::new(1, 2, 1), + Node::new(1, 0, 0), + Node::new(32, 1, 0), + Node::new(0, 0, 1), + ], + [0, 2, 4, 7, 9, 12, 14, 17, 19, 22, 24, 27, 29, 32, 34, 36], + 3, + )), + AnyBitCircuit::B8(BitCircuit::new( + [ + Node::new(40, 1, 0), + Node::new(40, 0, 1), + Node::new(8, 1, 0), + Node::new(8, 0, 1), + Node::new(8, 0, 0), + Node::new(8, 1, 1), + Node::new(39, 1, 0), + Node::new(7, 2, 1), + Node::new(7, 0, 2), + Node::new(7, 0, 0), + Node::new(7, 1, 1), + Node::new(38, 0, 1), + Node::new(6, 1, 2), + Node::new(6, 2, 0), + Node::new(6, 0, 0), + Node::new(6, 1, 1), + Node::new(37, 1, 0), + Node::new(5, 2, 1), + Node::new(5, 0, 2), + Node::new(5, 0, 0), + Node::new(5, 1, 1), + Node::new(36, 0, 1), + Node::new(4, 2, 0), + Node::new(4, 1, 2), + Node::new(4, 0, 0), + Node::new(4, 1, 1), + Node::new(35, 0, 1), + Node::new(3, 2, 0), + Node::new(3, 1, 2), + Node::new(3, 0, 0), + Node::new(3, 1, 1), + Node::new(34, 0, 1), + Node::new(2, 2, 0), + Node::new(2, 1, 2), + Node::new(2, 0, 0), + Node::new(2, 1, 1), + Node::new(33, 0, 1), + Node::new(1, 1, 2), + Node::new(1, 2, 0), + Node::new(1, 0, 0), + Node::new(32, 1, 0), + Node::new(0, 0, 1), + ], + [ + 0, 2, 4, 7, 9, 12, 14, 17, 19, 22, 24, 27, 29, 32, 34, 37, 39, 41, + ], + 3, + )), + AnyBitCircuit::B9(BitCircuit::new( + [ + Node::new(41, 1, 0), + Node::new(41, 0, 1), + Node::new(9, 0, 1), + Node::new(9, 1, 0), + Node::new(9, 0, 0), + Node::new(9, 1, 1), + Node::new(40, 0, 1), + Node::new(8, 1, 2), + Node::new(8, 2, 0), + Node::new(8, 0, 0), + Node::new(8, 1, 1), + Node::new(39, 1, 0), + Node::new(7, 2, 1), + Node::new(7, 0, 2), + Node::new(7, 0, 0), + Node::new(7, 1, 1), + Node::new(38, 0, 1), + Node::new(6, 1, 2), + Node::new(6, 2, 0), + Node::new(6, 0, 0), + Node::new(6, 1, 1), + Node::new(37, 1, 0), + Node::new(5, 2, 1), + Node::new(5, 0, 2), + Node::new(5, 0, 0), + Node::new(5, 1, 1), + Node::new(36, 0, 1), + Node::new(4, 2, 0), + Node::new(4, 1, 2), + Node::new(4, 0, 0), + Node::new(4, 1, 1), + Node::new(35, 0, 1), + Node::new(3, 1, 2), + Node::new(3, 2, 0), + Node::new(3, 0, 0), + Node::new(3, 1, 1), + Node::new(34, 1, 0), + Node::new(2, 0, 2), + Node::new(2, 2, 1), + Node::new(2, 0, 0), + Node::new(2, 1, 1), + Node::new(33, 1, 0), + Node::new(1, 0, 2), + Node::new(1, 2, 1), + Node::new(1, 0, 0), + Node::new(32, 1, 0), + Node::new(0, 0, 1), + ], + [ + 0, 2, 4, 7, 9, 12, 14, 17, 19, 22, 24, 27, 29, 32, 34, 37, 39, 42, 44, 46, + ], + 3, + )), + AnyBitCircuit::B10(BitCircuit::new( + [ + Node::new(42, 0, 1), + Node::new(42, 1, 0), + Node::new(10, 0, 1), + Node::new(10, 1, 0), + Node::new(10, 0, 0), + Node::new(10, 1, 1), + Node::new(41, 1, 0), + Node::new(9, 2, 1), + Node::new(9, 0, 2), + Node::new(9, 0, 0), + Node::new(9, 1, 1), + Node::new(40, 0, 1), + Node::new(8, 1, 2), + Node::new(8, 2, 0), + Node::new(8, 0, 0), + Node::new(8, 1, 1), + Node::new(39, 1, 0), + Node::new(7, 0, 2), + Node::new(7, 2, 1), + Node::new(7, 0, 0), + Node::new(7, 1, 1), + Node::new(38, 1, 0), + Node::new(6, 2, 1), + Node::new(6, 0, 2), + Node::new(6, 0, 0), + Node::new(6, 1, 1), + Node::new(37, 0, 1), + Node::new(5, 2, 0), + Node::new(5, 1, 2), + Node::new(5, 0, 0), + Node::new(5, 1, 1), + Node::new(36, 0, 1), + Node::new(4, 2, 0), + Node::new(4, 1, 2), + Node::new(4, 0, 0), + Node::new(4, 1, 1), + Node::new(35, 0, 1), + Node::new(3, 1, 2), + Node::new(3, 2, 0), + Node::new(3, 0, 0), + Node::new(3, 1, 1), + Node::new(34, 1, 0), + Node::new(2, 2, 1), + Node::new(2, 0, 2), + Node::new(2, 0, 0), + Node::new(2, 1, 1), + Node::new(33, 0, 1), + Node::new(1, 1, 2), + Node::new(1, 2, 0), + Node::new(1, 0, 0), + Node::new(32, 1, 0), + Node::new(0, 0, 1), + ], + [ + 0, 2, 4, 7, 9, 12, 14, 17, 19, 22, 24, 27, 29, 32, 34, 37, 39, 42, 44, 47, 49, 51, + ], + 3, + )), + AnyBitCircuit::B11(BitCircuit::new( + [ + Node::new(43, 0, 1), + Node::new(43, 1, 0), + Node::new(11, 1, 0), + Node::new(11, 0, 1), + Node::new(11, 0, 0), + Node::new(11, 1, 1), + Node::new(42, 0, 1), + Node::new(10, 1, 2), + Node::new(10, 2, 0), + Node::new(10, 0, 0), + Node::new(10, 1, 1), + Node::new(41, 1, 0), + Node::new(9, 0, 2), + Node::new(9, 2, 1), + Node::new(9, 0, 0), + Node::new(9, 1, 1), + Node::new(40, 1, 0), + Node::new(8, 0, 2), + Node::new(8, 2, 1), + Node::new(8, 0, 0), + Node::new(8, 1, 1), + Node::new(39, 1, 0), + Node::new(7, 0, 2), + Node::new(7, 2, 1), + Node::new(7, 0, 0), + Node::new(7, 1, 1), + Node::new(38, 1, 0), + Node::new(6, 2, 1), + Node::new(6, 0, 2), + Node::new(6, 0, 0), + Node::new(6, 1, 1), + Node::new(37, 0, 1), + Node::new(5, 1, 2), + Node::new(5, 2, 0), + Node::new(5, 0, 0), + Node::new(5, 1, 1), + Node::new(36, 1, 0), + Node::new(4, 0, 2), + Node::new(4, 2, 1), + Node::new(4, 0, 0), + Node::new(4, 1, 1), + Node::new(35, 1, 0), + Node::new(3, 2, 1), + Node::new(3, 0, 2), + Node::new(3, 0, 0), + Node::new(3, 1, 1), + Node::new(34, 0, 1), + Node::new(2, 2, 0), + Node::new(2, 1, 2), + Node::new(2, 0, 0), + Node::new(2, 1, 1), + Node::new(33, 0, 1), + Node::new(1, 1, 2), + Node::new(1, 2, 0), + Node::new(1, 0, 0), + Node::new(32, 1, 0), + Node::new(0, 0, 1), + ], + [ + 0, 2, 4, 7, 9, 12, 14, 17, 19, 22, 24, 27, 29, 32, 34, 37, 39, 42, 44, 47, 49, 52, 54, 56, + ], + 3, + )), + AnyBitCircuit::B12(BitCircuit::new( + [ + Node::new(44, 1, 0), + Node::new(44, 0, 1), + Node::new(12, 1, 0), + Node::new(12, 0, 1), + Node::new(12, 0, 0), + Node::new(12, 1, 1), + Node::new(43, 1, 0), + Node::new(11, 2, 1), + Node::new(11, 0, 2), + Node::new(11, 0, 0), + Node::new(11, 1, 1), + Node::new(42, 0, 1), + Node::new(10, 2, 0), + Node::new(10, 1, 2), + Node::new(10, 0, 0), + Node::new(10, 1, 1), + Node::new(41, 0, 1), + Node::new(9, 2, 0), + Node::new(9, 1, 2), + Node::new(9, 0, 0), + Node::new(9, 1, 1), + Node::new(40, 0, 1), + Node::new(8, 1, 2), + Node::new(8, 2, 0), + Node::new(8, 0, 0), + Node::new(8, 1, 1), + Node::new(39, 1, 0), + Node::new(7, 0, 2), + Node::new(7, 2, 1), + Node::new(7, 0, 0), + Node::new(7, 1, 1), + Node::new(38, 1, 0), + Node::new(6, 2, 1), + Node::new(6, 0, 2), + Node::new(6, 0, 0), + Node::new(6, 1, 1), + Node::new(37, 0, 1), + Node::new(5, 2, 0), + Node::new(5, 1, 2), + Node::new(5, 0, 0), + Node::new(5, 1, 1), + Node::new(36, 0, 1), + Node::new(4, 1, 2), + Node::new(4, 2, 0), + Node::new(4, 0, 0), + Node::new(4, 1, 1), + Node::new(35, 1, 0), + Node::new(3, 2, 1), + Node::new(3, 0, 2), + Node::new(3, 0, 0), + Node::new(3, 1, 1), + Node::new(34, 0, 1), + Node::new(2, 1, 2), + Node::new(2, 2, 0), + Node::new(2, 0, 0), + Node::new(2, 1, 1), + Node::new(33, 1, 0), + Node::new(1, 0, 2), + Node::new(1, 2, 1), + Node::new(1, 0, 0), + Node::new(32, 1, 0), + Node::new(0, 0, 1), + ], + [ + 0, 2, 4, 7, 9, 12, 14, 17, 19, 22, 24, 27, 29, 32, 34, 37, 39, 42, 44, 47, 49, 52, 54, 57, 59, 61, + ], + 3, + )), + AnyBitCircuit::B13(BitCircuit::new( + [ + Node::new(45, 0, 1), + Node::new(45, 1, 0), + Node::new(13, 1, 0), + Node::new(13, 0, 1), + Node::new(13, 0, 0), + Node::new(13, 1, 1), + Node::new(44, 0, 1), + Node::new(12, 1, 2), + Node::new(12, 2, 0), + Node::new(12, 0, 0), + Node::new(12, 1, 1), + Node::new(43, 1, 0), + Node::new(11, 0, 2), + Node::new(11, 2, 1), + Node::new(11, 0, 0), + Node::new(11, 1, 1), + Node::new(42, 1, 0), + Node::new(10, 0, 2), + Node::new(10, 2, 1), + Node::new(10, 0, 0), + Node::new(10, 1, 1), + Node::new(41, 1, 0), + Node::new(9, 2, 1), + Node::new(9, 0, 2), + Node::new(9, 0, 0), + Node::new(9, 1, 1), + Node::new(40, 0, 1), + Node::new(8, 2, 0), + Node::new(8, 1, 2), + Node::new(8, 0, 0), + Node::new(8, 1, 1), + Node::new(39, 0, 1), + Node::new(7, 2, 0), + Node::new(7, 1, 2), + Node::new(7, 0, 0), + Node::new(7, 1, 1), + Node::new(38, 0, 1), + Node::new(6, 1, 2), + Node::new(6, 2, 0), + Node::new(6, 0, 0), + Node::new(6, 1, 1), + Node::new(37, 1, 0), + Node::new(5, 2, 1), + Node::new(5, 0, 2), + Node::new(5, 0, 0), + Node::new(5, 1, 1), + Node::new(36, 0, 1), + Node::new(4, 2, 0), + Node::new(4, 1, 2), + Node::new(4, 0, 0), + Node::new(4, 1, 1), + Node::new(35, 0, 1), + Node::new(3, 1, 2), + Node::new(3, 2, 0), + Node::new(3, 0, 0), + Node::new(3, 1, 1), + Node::new(34, 1, 0), + Node::new(2, 2, 1), + Node::new(2, 0, 2), + Node::new(2, 0, 0), + Node::new(2, 1, 1), + Node::new(33, 0, 1), + Node::new(1, 1, 2), + Node::new(1, 2, 0), + Node::new(1, 0, 0), + Node::new(32, 1, 0), + Node::new(0, 0, 1), + ], + [ + 0, 2, 4, 7, 9, 12, 14, 17, 19, 22, 24, 27, 29, 32, 34, 37, 39, 42, 44, 47, 49, 52, 54, 57, 59, 62, 64, 66, + ], + 3, + )), + AnyBitCircuit::B14(BitCircuit::new( + [ + Node::new(46, 0, 1), + Node::new(46, 1, 0), + Node::new(14, 0, 1), + Node::new(14, 1, 0), + Node::new(14, 0, 0), + Node::new(14, 1, 1), + Node::new(45, 1, 0), + Node::new(13, 0, 2), + Node::new(13, 2, 1), + Node::new(13, 0, 0), + Node::new(13, 1, 1), + Node::new(44, 1, 0), + Node::new(12, 0, 2), + Node::new(12, 2, 1), + Node::new(12, 0, 0), + Node::new(12, 1, 1), + Node::new(43, 1, 0), + Node::new(11, 2, 1), + Node::new(11, 0, 2), + Node::new(11, 0, 0), + Node::new(11, 1, 1), + Node::new(42, 0, 1), + Node::new(10, 2, 0), + Node::new(10, 1, 2), + Node::new(10, 0, 0), + Node::new(10, 1, 1), + Node::new(41, 0, 1), + Node::new(9, 2, 0), + Node::new(9, 1, 2), + Node::new(9, 0, 0), + Node::new(9, 1, 1), + Node::new(40, 0, 1), + Node::new(8, 2, 0), + Node::new(8, 1, 2), + Node::new(8, 0, 0), + Node::new(8, 1, 1), + Node::new(39, 0, 1), + Node::new(7, 1, 2), + Node::new(7, 2, 0), + Node::new(7, 0, 0), + Node::new(7, 1, 1), + Node::new(38, 1, 0), + Node::new(6, 0, 2), + Node::new(6, 2, 1), + Node::new(6, 0, 0), + Node::new(6, 1, 1), + Node::new(37, 1, 0), + Node::new(5, 0, 2), + Node::new(5, 2, 1), + Node::new(5, 0, 0), + Node::new(5, 1, 1), + Node::new(36, 1, 0), + Node::new(4, 2, 1), + Node::new(4, 0, 2), + Node::new(4, 0, 0), + Node::new(4, 1, 1), + Node::new(35, 0, 1), + Node::new(3, 2, 0), + Node::new(3, 1, 2), + Node::new(3, 0, 0), + Node::new(3, 1, 1), + Node::new(34, 0, 1), + Node::new(2, 1, 2), + Node::new(2, 2, 0), + Node::new(2, 0, 0), + Node::new(2, 1, 1), + Node::new(33, 1, 0), + Node::new(1, 0, 2), + Node::new(1, 2, 1), + Node::new(1, 0, 0), + Node::new(32, 1, 0), + Node::new(0, 0, 1), + ], + [ + 0, 2, 4, 7, 9, 12, 14, 17, 19, 22, 24, 27, 29, 32, 34, 37, 39, 42, 44, 47, 49, 52, 54, 57, 59, 62, 64, 67, 69, 71, + ], + 3, + )), + AnyBitCircuit::B15(BitCircuit::new( + [ + Node::new(47, 0, 1), + Node::new(47, 1, 0), + Node::new(15, 0, 1), + Node::new(15, 1, 0), + Node::new(15, 0, 0), + Node::new(15, 1, 1), + Node::new(46, 1, 0), + Node::new(14, 2, 1), + Node::new(14, 0, 2), + Node::new(14, 0, 0), + Node::new(14, 1, 1), + Node::new(45, 0, 1), + Node::new(13, 2, 0), + Node::new(13, 1, 2), + Node::new(13, 0, 0), + Node::new(13, 1, 1), + Node::new(44, 0, 1), + Node::new(12, 1, 2), + Node::new(12, 2, 0), + Node::new(12, 0, 0), + Node::new(12, 1, 1), + Node::new(43, 1, 0), + Node::new(11, 0, 2), + Node::new(11, 2, 1), + Node::new(11, 0, 0), + Node::new(11, 1, 1), + Node::new(42, 1, 0), + Node::new(10, 2, 1), + Node::new(10, 0, 2), + Node::new(10, 0, 0), + Node::new(10, 1, 1), + Node::new(41, 0, 1), + Node::new(9, 1, 2), + Node::new(9, 2, 0), + Node::new(9, 0, 0), + Node::new(9, 1, 1), + Node::new(40, 1, 0), + Node::new(8, 2, 1), + Node::new(8, 0, 2), + Node::new(8, 0, 0), + Node::new(8, 1, 1), + Node::new(39, 0, 1), + Node::new(7, 2, 0), + Node::new(7, 1, 2), + Node::new(7, 0, 0), + Node::new(7, 1, 1), + Node::new(38, 0, 1), + Node::new(6, 2, 0), + Node::new(6, 1, 2), + Node::new(6, 0, 0), + Node::new(6, 1, 1), + Node::new(37, 0, 1), + Node::new(5, 1, 2), + Node::new(5, 2, 0), + Node::new(5, 0, 0), + Node::new(5, 1, 1), + Node::new(36, 1, 0), + Node::new(4, 0, 2), + Node::new(4, 2, 1), + Node::new(4, 0, 0), + Node::new(4, 1, 1), + Node::new(35, 1, 0), + Node::new(3, 2, 1), + Node::new(3, 0, 2), + Node::new(3, 0, 0), + Node::new(3, 1, 1), + Node::new(34, 0, 1), + Node::new(2, 1, 2), + Node::new(2, 2, 0), + Node::new(2, 0, 0), + Node::new(2, 1, 1), + Node::new(33, 1, 0), + Node::new(1, 0, 2), + Node::new(1, 2, 1), + Node::new(1, 0, 0), + Node::new(32, 1, 0), + Node::new(0, 0, 1), + ], + [ + 0, 2, 4, 7, 9, 12, 14, 17, 19, 22, 24, 27, 29, 32, 34, 37, 39, 42, 44, 47, 49, 52, 54, 57, 59, 62, 64, 67, 69, 72, + 74, 76, + ], + 3, + )), + AnyBitCircuit::B16(BitCircuit::new( + [ + Node::new(48, 1, 0), + Node::new(48, 0, 1), + Node::new(16, 1, 0), + Node::new(16, 0, 1), + Node::new(16, 0, 0), + Node::new(16, 1, 1), + Node::new(47, 1, 0), + Node::new(15, 2, 1), + Node::new(15, 0, 2), + Node::new(15, 0, 0), + Node::new(15, 1, 1), + Node::new(46, 0, 1), + Node::new(14, 1, 2), + Node::new(14, 2, 0), + Node::new(14, 0, 0), + Node::new(14, 1, 1), + Node::new(45, 1, 0), + Node::new(13, 0, 2), + Node::new(13, 2, 1), + Node::new(13, 0, 0), + Node::new(13, 1, 1), + Node::new(44, 1, 0), + Node::new(12, 2, 1), + Node::new(12, 0, 2), + Node::new(12, 0, 0), + Node::new(12, 1, 1), + Node::new(43, 0, 1), + Node::new(11, 2, 0), + Node::new(11, 1, 2), + Node::new(11, 0, 0), + Node::new(11, 1, 1), + Node::new(42, 0, 1), + Node::new(10, 1, 2), + Node::new(10, 2, 0), + Node::new(10, 0, 0), + Node::new(10, 1, 1), + Node::new(41, 1, 0), + Node::new(9, 2, 1), + Node::new(9, 0, 2), + Node::new(9, 0, 0), + Node::new(9, 1, 1), + Node::new(40, 0, 1), + Node::new(8, 2, 0), + Node::new(8, 1, 2), + Node::new(8, 0, 0), + Node::new(8, 1, 1), + Node::new(39, 0, 1), + Node::new(7, 2, 0), + Node::new(7, 1, 2), + Node::new(7, 0, 0), + Node::new(7, 1, 1), + Node::new(38, 0, 1), + Node::new(6, 1, 2), + Node::new(6, 2, 0), + Node::new(6, 0, 0), + Node::new(6, 1, 1), + Node::new(37, 1, 0), + Node::new(5, 2, 1), + Node::new(5, 0, 2), + Node::new(5, 0, 0), + Node::new(5, 1, 1), + Node::new(36, 0, 1), + Node::new(4, 2, 0), + Node::new(4, 1, 2), + Node::new(4, 0, 0), + Node::new(4, 1, 1), + Node::new(35, 0, 1), + Node::new(3, 1, 2), + Node::new(3, 2, 0), + Node::new(3, 0, 0), + Node::new(3, 1, 1), + Node::new(34, 1, 0), + Node::new(2, 2, 1), + Node::new(2, 0, 2), + Node::new(2, 0, 0), + Node::new(2, 1, 1), + Node::new(33, 0, 1), + Node::new(1, 1, 2), + Node::new(1, 2, 0), + Node::new(1, 0, 0), + Node::new(32, 1, 0), + Node::new(0, 0, 1), + ], + [ + 0, 2, 4, 7, 9, 12, 14, 17, 19, 22, 24, 27, 29, 32, 34, 37, 39, 42, 44, 47, 49, 52, 54, 57, 59, 62, 64, 67, 69, 72, + 74, 77, 79, 81, + ], + 3, + )), + AnyBitCircuit::B17(BitCircuit::new( + [ + Node::new(49, 1, 0), + Node::new(49, 0, 1), + Node::new(17, 1, 0), + Node::new(17, 0, 1), + Node::new(17, 0, 0), + Node::new(17, 1, 1), + Node::new(48, 1, 0), + Node::new(16, 0, 2), + Node::new(16, 2, 1), + Node::new(16, 0, 0), + Node::new(16, 1, 1), + Node::new(47, 1, 0), + Node::new(15, 2, 1), + Node::new(15, 0, 2), + Node::new(15, 0, 0), + Node::new(15, 1, 1), + Node::new(46, 0, 1), + Node::new(14, 2, 0), + Node::new(14, 1, 2), + Node::new(14, 0, 0), + Node::new(14, 1, 1), + Node::new(45, 0, 1), + Node::new(13, 1, 2), + Node::new(13, 2, 0), + Node::new(13, 0, 0), + Node::new(13, 1, 1), + Node::new(44, 1, 0), + Node::new(12, 2, 1), + Node::new(12, 0, 2), + Node::new(12, 0, 0), + Node::new(12, 1, 1), + Node::new(43, 0, 1), + Node::new(11, 1, 2), + Node::new(11, 2, 0), + Node::new(11, 0, 0), + Node::new(11, 1, 1), + Node::new(42, 1, 0), + Node::new(10, 2, 1), + Node::new(10, 0, 2), + Node::new(10, 0, 0), + Node::new(10, 1, 1), + Node::new(41, 0, 1), + Node::new(9, 2, 0), + Node::new(9, 1, 2), + Node::new(9, 0, 0), + Node::new(9, 1, 1), + Node::new(40, 0, 1), + Node::new(8, 2, 0), + Node::new(8, 1, 2), + Node::new(8, 0, 0), + Node::new(8, 1, 1), + Node::new(39, 0, 1), + Node::new(7, 1, 2), + Node::new(7, 2, 0), + Node::new(7, 0, 0), + Node::new(7, 1, 1), + Node::new(38, 1, 0), + Node::new(6, 0, 2), + Node::new(6, 2, 1), + Node::new(6, 0, 0), + Node::new(6, 1, 1), + Node::new(37, 1, 0), + Node::new(5, 0, 2), + Node::new(5, 2, 1), + Node::new(5, 0, 0), + Node::new(5, 1, 1), + Node::new(36, 1, 0), + Node::new(4, 2, 1), + Node::new(4, 0, 2), + Node::new(4, 0, 0), + Node::new(4, 1, 1), + Node::new(35, 0, 1), + Node::new(3, 2, 0), + Node::new(3, 1, 2), + Node::new(3, 0, 0), + Node::new(3, 1, 1), + Node::new(34, 0, 1), + Node::new(2, 1, 2), + Node::new(2, 2, 0), + Node::new(2, 0, 0), + Node::new(2, 1, 1), + Node::new(33, 1, 0), + Node::new(1, 0, 2), + Node::new(1, 2, 1), + Node::new(1, 0, 0), + Node::new(32, 1, 0), + Node::new(0, 0, 1), + ], + [ + 0, 2, 4, 7, 9, 12, 14, 17, 19, 22, 24, 27, 29, 32, 34, 37, 39, 42, 44, 47, 49, 52, 54, 57, 59, 62, 64, 67, 69, 72, + 74, 77, 79, 82, 84, 86, + ], + 3, + )), + AnyBitCircuit::B18(BitCircuit::new( + [ + Node::new(50, 0, 1), + Node::new(50, 1, 0), + Node::new(18, 0, 1), + Node::new(18, 1, 0), + Node::new(18, 0, 0), + Node::new(18, 1, 1), + Node::new(49, 1, 0), + Node::new(17, 0, 2), + Node::new(17, 2, 1), + Node::new(17, 0, 0), + Node::new(17, 1, 1), + Node::new(48, 1, 0), + Node::new(16, 2, 1), + Node::new(16, 0, 2), + Node::new(16, 0, 0), + Node::new(16, 1, 1), + Node::new(47, 0, 1), + Node::new(15, 2, 0), + Node::new(15, 1, 2), + Node::new(15, 0, 0), + Node::new(15, 1, 1), + Node::new(46, 0, 1), + Node::new(14, 2, 0), + Node::new(14, 1, 2), + Node::new(14, 0, 0), + Node::new(14, 1, 1), + Node::new(45, 0, 1), + Node::new(13, 2, 0), + Node::new(13, 1, 2), + Node::new(13, 0, 0), + Node::new(13, 1, 1), + Node::new(44, 0, 1), + Node::new(12, 2, 0), + Node::new(12, 1, 2), + Node::new(12, 0, 0), + Node::new(12, 1, 1), + Node::new(43, 0, 1), + Node::new(11, 2, 0), + Node::new(11, 1, 2), + Node::new(11, 0, 0), + Node::new(11, 1, 1), + Node::new(42, 0, 1), + Node::new(10, 1, 2), + Node::new(10, 2, 0), + Node::new(10, 0, 0), + Node::new(10, 1, 1), + Node::new(41, 1, 0), + Node::new(9, 2, 1), + Node::new(9, 0, 2), + Node::new(9, 0, 0), + Node::new(9, 1, 1), + Node::new(40, 0, 1), + Node::new(8, 2, 0), + Node::new(8, 1, 2), + Node::new(8, 0, 0), + Node::new(8, 1, 1), + Node::new(39, 0, 1), + Node::new(7, 1, 2), + Node::new(7, 2, 0), + Node::new(7, 0, 0), + Node::new(7, 1, 1), + Node::new(38, 1, 0), + Node::new(6, 0, 2), + Node::new(6, 2, 1), + Node::new(6, 0, 0), + Node::new(6, 1, 1), + Node::new(37, 1, 0), + Node::new(5, 0, 2), + Node::new(5, 2, 1), + Node::new(5, 0, 0), + Node::new(5, 1, 1), + Node::new(36, 1, 0), + Node::new(4, 0, 2), + Node::new(4, 2, 1), + Node::new(4, 0, 0), + Node::new(4, 1, 1), + Node::new(35, 1, 0), + Node::new(3, 0, 2), + Node::new(3, 2, 1), + Node::new(3, 0, 0), + Node::new(3, 1, 1), + Node::new(34, 1, 0), + Node::new(2, 2, 1), + Node::new(2, 0, 2), + Node::new(2, 0, 0), + Node::new(2, 1, 1), + Node::new(33, 0, 1), + Node::new(1, 1, 2), + Node::new(1, 2, 0), + Node::new(1, 0, 0), + Node::new(32, 1, 0), + Node::new(0, 0, 1), + ], + [ + 0, 2, 4, 7, 9, 12, 14, 17, 19, 22, 24, 27, 29, 32, 34, 37, 39, 42, 44, 47, 49, 52, 54, 57, 59, 62, 64, 67, 69, 72, + 74, 77, 79, 82, 84, 87, 89, 91, + ], + 3, + )), + AnyBitCircuit::B19(BitCircuit::new( + [ + Node::new(51, 0, 1), + Node::new(51, 1, 0), + Node::new(19, 0, 1), + Node::new(19, 1, 0), + Node::new(19, 0, 0), + Node::new(19, 1, 1), + Node::new(50, 1, 0), + Node::new(18, 0, 2), + Node::new(18, 2, 1), + Node::new(18, 0, 0), + Node::new(18, 1, 1), + Node::new(49, 1, 0), + Node::new(17, 0, 2), + Node::new(17, 2, 1), + Node::new(17, 0, 0), + Node::new(17, 1, 1), + Node::new(48, 1, 0), + Node::new(16, 0, 2), + Node::new(16, 2, 1), + Node::new(16, 0, 0), + Node::new(16, 1, 1), + Node::new(47, 1, 0), + Node::new(15, 2, 1), + Node::new(15, 0, 2), + Node::new(15, 0, 0), + Node::new(15, 1, 1), + Node::new(46, 0, 1), + Node::new(14, 1, 2), + Node::new(14, 2, 0), + Node::new(14, 0, 0), + Node::new(14, 1, 1), + Node::new(45, 1, 0), + Node::new(13, 2, 1), + Node::new(13, 0, 2), + Node::new(13, 0, 0), + Node::new(13, 1, 1), + Node::new(44, 0, 1), + Node::new(12, 1, 2), + Node::new(12, 2, 0), + Node::new(12, 0, 0), + Node::new(12, 1, 1), + Node::new(43, 1, 0), + Node::new(11, 0, 2), + Node::new(11, 2, 1), + Node::new(11, 0, 0), + Node::new(11, 1, 1), + Node::new(42, 1, 0), + Node::new(10, 2, 1), + Node::new(10, 0, 2), + Node::new(10, 0, 0), + Node::new(10, 1, 1), + Node::new(41, 0, 1), + Node::new(9, 2, 0), + Node::new(9, 1, 2), + Node::new(9, 0, 0), + Node::new(9, 1, 1), + Node::new(40, 0, 1), + Node::new(8, 1, 2), + Node::new(8, 2, 0), + Node::new(8, 0, 0), + Node::new(8, 1, 1), + Node::new(39, 1, 0), + Node::new(7, 2, 1), + Node::new(7, 0, 2), + Node::new(7, 0, 0), + Node::new(7, 1, 1), + Node::new(38, 0, 1), + Node::new(6, 2, 0), + Node::new(6, 1, 2), + Node::new(6, 0, 0), + Node::new(6, 1, 1), + Node::new(37, 0, 1), + Node::new(5, 1, 2), + Node::new(5, 2, 0), + Node::new(5, 0, 0), + Node::new(5, 1, 1), + Node::new(36, 1, 0), + Node::new(4, 0, 2), + Node::new(4, 2, 1), + Node::new(4, 0, 0), + Node::new(4, 1, 1), + Node::new(35, 1, 0), + Node::new(3, 2, 1), + Node::new(3, 0, 2), + Node::new(3, 0, 0), + Node::new(3, 1, 1), + Node::new(34, 0, 1), + Node::new(2, 1, 2), + Node::new(2, 2, 0), + Node::new(2, 0, 0), + Node::new(2, 1, 1), + Node::new(33, 1, 0), + Node::new(1, 0, 2), + Node::new(1, 2, 1), + Node::new(1, 0, 0), + Node::new(32, 1, 0), + Node::new(0, 0, 1), + ], + [ + 0, 2, 4, 7, 9, 12, 14, 17, 19, 22, 24, 27, 29, 32, 34, 37, 39, 42, 44, 47, 49, 52, 54, 57, 59, 62, 64, 67, 69, 72, + 74, 77, 79, 82, 84, 87, 89, 92, 94, 96, + ], + 3, + )), + AnyBitCircuit::B20(BitCircuit::new( + [ + Node::new(52, 1, 0), + Node::new(52, 0, 1), + Node::new(20, 0, 1), + Node::new(20, 1, 0), + Node::new(20, 0, 0), + Node::new(20, 1, 1), + Node::new(51, 0, 1), + Node::new(19, 2, 0), + Node::new(19, 1, 2), + Node::new(19, 0, 0), + Node::new(19, 1, 1), + Node::new(50, 0, 1), + Node::new(18, 2, 0), + Node::new(18, 1, 2), + Node::new(18, 0, 0), + Node::new(18, 1, 1), + Node::new(49, 0, 1), + Node::new(17, 2, 0), + Node::new(17, 1, 2), + Node::new(17, 0, 0), + Node::new(17, 1, 1), + Node::new(48, 0, 1), + Node::new(16, 2, 0), + Node::new(16, 1, 2), + Node::new(16, 0, 0), + Node::new(16, 1, 1), + Node::new(47, 0, 1), + Node::new(15, 1, 2), + Node::new(15, 2, 0), + Node::new(15, 0, 0), + Node::new(15, 1, 1), + Node::new(46, 1, 0), + Node::new(14, 0, 2), + Node::new(14, 2, 1), + Node::new(14, 0, 0), + Node::new(14, 1, 1), + Node::new(45, 1, 0), + Node::new(13, 2, 1), + Node::new(13, 0, 2), + Node::new(13, 0, 0), + Node::new(13, 1, 1), + Node::new(44, 0, 1), + Node::new(12, 1, 2), + Node::new(12, 2, 0), + Node::new(12, 0, 0), + Node::new(12, 1, 1), + Node::new(43, 1, 0), + Node::new(11, 0, 2), + Node::new(11, 2, 1), + Node::new(11, 0, 0), + Node::new(11, 1, 1), + Node::new(42, 1, 0), + Node::new(10, 0, 2), + Node::new(10, 2, 1), + Node::new(10, 0, 0), + Node::new(10, 1, 1), + Node::new(41, 1, 0), + Node::new(9, 2, 1), + Node::new(9, 0, 2), + Node::new(9, 0, 0), + Node::new(9, 1, 1), + Node::new(40, 0, 1), + Node::new(8, 2, 0), + Node::new(8, 1, 2), + Node::new(8, 0, 0), + Node::new(8, 1, 1), + Node::new(39, 0, 1), + Node::new(7, 2, 0), + Node::new(7, 1, 2), + Node::new(7, 0, 0), + Node::new(7, 1, 1), + Node::new(38, 0, 1), + Node::new(6, 2, 0), + Node::new(6, 1, 2), + Node::new(6, 0, 0), + Node::new(6, 1, 1), + Node::new(37, 0, 1), + Node::new(5, 1, 2), + Node::new(5, 2, 0), + Node::new(5, 0, 0), + Node::new(5, 1, 1), + Node::new(36, 1, 0), + Node::new(4, 2, 1), + Node::new(4, 0, 2), + Node::new(4, 0, 0), + Node::new(4, 1, 1), + Node::new(35, 0, 1), + Node::new(3, 1, 2), + Node::new(3, 2, 0), + Node::new(3, 0, 0), + Node::new(3, 1, 1), + Node::new(34, 1, 0), + Node::new(2, 2, 1), + Node::new(2, 0, 2), + Node::new(2, 0, 0), + Node::new(2, 1, 1), + Node::new(33, 0, 1), + Node::new(1, 1, 2), + Node::new(1, 2, 0), + Node::new(1, 0, 0), + Node::new(32, 1, 0), + Node::new(0, 0, 1), + ], + [ + 0, 2, 4, 7, 9, 12, 14, 17, 19, 22, 24, 27, 29, 32, 34, 37, 39, 42, 44, 47, 49, 52, 54, 57, 59, 62, 64, 67, 69, 72, + 74, 77, 79, 82, 84, 87, 89, 92, 94, 97, 99, 101, + ], + 3, + )), + AnyBitCircuit::B21(BitCircuit::new( + [ + Node::new(53, 1, 0), + Node::new(53, 0, 1), + Node::new(21, 1, 0), + Node::new(21, 0, 1), + Node::new(21, 0, 0), + Node::new(21, 1, 1), + Node::new(52, 1, 0), + Node::new(20, 2, 1), + Node::new(20, 0, 2), + Node::new(20, 0, 0), + Node::new(20, 1, 1), + Node::new(51, 0, 1), + Node::new(19, 2, 0), + Node::new(19, 1, 2), + Node::new(19, 0, 0), + Node::new(19, 1, 1), + Node::new(50, 0, 1), + Node::new(18, 1, 2), + Node::new(18, 2, 0), + Node::new(18, 0, 0), + Node::new(18, 1, 1), + Node::new(49, 1, 0), + Node::new(17, 2, 1), + Node::new(17, 0, 2), + Node::new(17, 0, 0), + Node::new(17, 1, 1), + Node::new(48, 0, 1), + Node::new(16, 1, 2), + Node::new(16, 2, 0), + Node::new(16, 0, 0), + Node::new(16, 1, 1), + Node::new(47, 1, 0), + Node::new(15, 0, 2), + Node::new(15, 2, 1), + Node::new(15, 0, 0), + Node::new(15, 1, 1), + Node::new(46, 1, 0), + Node::new(14, 2, 1), + Node::new(14, 0, 2), + Node::new(14, 0, 0), + Node::new(14, 1, 1), + Node::new(45, 0, 1), + Node::new(13, 2, 0), + Node::new(13, 1, 2), + Node::new(13, 0, 0), + Node::new(13, 1, 1), + Node::new(44, 0, 1), + Node::new(12, 1, 2), + Node::new(12, 2, 0), + Node::new(12, 0, 0), + Node::new(12, 1, 1), + Node::new(43, 1, 0), + Node::new(11, 2, 1), + Node::new(11, 0, 2), + Node::new(11, 0, 0), + Node::new(11, 1, 1), + Node::new(42, 0, 1), + Node::new(10, 2, 0), + Node::new(10, 1, 2), + Node::new(10, 0, 0), + Node::new(10, 1, 1), + Node::new(41, 0, 1), + Node::new(9, 2, 0), + Node::new(9, 1, 2), + Node::new(9, 0, 0), + Node::new(9, 1, 1), + Node::new(40, 0, 1), + Node::new(8, 1, 2), + Node::new(8, 2, 0), + Node::new(8, 0, 0), + Node::new(8, 1, 1), + Node::new(39, 1, 0), + Node::new(7, 0, 2), + Node::new(7, 2, 1), + Node::new(7, 0, 0), + Node::new(7, 1, 1), + Node::new(38, 1, 0), + Node::new(6, 0, 2), + Node::new(6, 2, 1), + Node::new(6, 0, 0), + Node::new(6, 1, 1), + Node::new(37, 1, 0), + Node::new(5, 2, 1), + Node::new(5, 0, 2), + Node::new(5, 0, 0), + Node::new(5, 1, 1), + Node::new(36, 0, 1), + Node::new(4, 1, 2), + Node::new(4, 2, 0), + Node::new(4, 0, 0), + Node::new(4, 1, 1), + Node::new(35, 1, 0), + Node::new(3, 0, 2), + Node::new(3, 2, 1), + Node::new(3, 0, 0), + Node::new(3, 1, 1), + Node::new(34, 1, 0), + Node::new(2, 0, 2), + Node::new(2, 2, 1), + Node::new(2, 0, 0), + Node::new(2, 1, 1), + Node::new(33, 1, 0), + Node::new(1, 0, 2), + Node::new(1, 2, 1), + Node::new(1, 0, 0), + Node::new(32, 1, 0), + Node::new(0, 0, 1), + ], + [ + 0, 2, 4, 7, 9, 12, 14, 17, 19, 22, 24, 27, 29, 32, 34, 37, 39, 42, 44, 47, 49, 52, 54, 57, 59, 62, 64, 67, 69, 72, + 74, 77, 79, 82, 84, 87, 89, 92, 94, 97, 99, 102, 104, 106, + ], + 3, + )), + AnyBitCircuit::B22(BitCircuit::new( + [ + Node::new(54, 0, 1), + Node::new(54, 1, 0), + Node::new(22, 0, 1), + Node::new(22, 1, 0), + Node::new(22, 0, 0), + Node::new(22, 1, 1), + Node::new(53, 1, 0), + Node::new(21, 2, 1), + Node::new(21, 0, 2), + Node::new(21, 0, 0), + Node::new(21, 1, 1), + Node::new(52, 0, 1), + Node::new(20, 2, 0), + Node::new(20, 1, 2), + Node::new(20, 0, 0), + Node::new(20, 1, 1), + Node::new(51, 0, 1), + Node::new(19, 1, 2), + Node::new(19, 2, 0), + Node::new(19, 0, 0), + Node::new(19, 1, 1), + Node::new(50, 1, 0), + Node::new(18, 0, 2), + Node::new(18, 2, 1), + Node::new(18, 0, 0), + Node::new(18, 1, 1), + Node::new(49, 1, 0), + Node::new(17, 2, 1), + Node::new(17, 0, 2), + Node::new(17, 0, 0), + Node::new(17, 1, 1), + Node::new(48, 0, 1), + Node::new(16, 1, 2), + Node::new(16, 2, 0), + Node::new(16, 0, 0), + Node::new(16, 1, 1), + Node::new(47, 1, 0), + Node::new(15, 0, 2), + Node::new(15, 2, 1), + Node::new(15, 0, 0), + Node::new(15, 1, 1), + Node::new(46, 1, 0), + Node::new(14, 0, 2), + Node::new(14, 2, 1), + Node::new(14, 0, 0), + Node::new(14, 1, 1), + Node::new(45, 1, 0), + Node::new(13, 0, 2), + Node::new(13, 2, 1), + Node::new(13, 0, 0), + Node::new(13, 1, 1), + Node::new(44, 1, 0), + Node::new(12, 0, 2), + Node::new(12, 2, 1), + Node::new(12, 0, 0), + Node::new(12, 1, 1), + Node::new(43, 1, 0), + Node::new(11, 0, 2), + Node::new(11, 2, 1), + Node::new(11, 0, 0), + Node::new(11, 1, 1), + Node::new(42, 1, 0), + Node::new(10, 2, 1), + Node::new(10, 0, 2), + Node::new(10, 0, 0), + Node::new(10, 1, 1), + Node::new(41, 0, 1), + Node::new(9, 1, 2), + Node::new(9, 2, 0), + Node::new(9, 0, 0), + Node::new(9, 1, 1), + Node::new(40, 1, 0), + Node::new(8, 2, 1), + Node::new(8, 0, 2), + Node::new(8, 0, 0), + Node::new(8, 1, 1), + Node::new(39, 0, 1), + Node::new(7, 2, 0), + Node::new(7, 1, 2), + Node::new(7, 0, 0), + Node::new(7, 1, 1), + Node::new(38, 0, 1), + Node::new(6, 1, 2), + Node::new(6, 2, 0), + Node::new(6, 0, 0), + Node::new(6, 1, 1), + Node::new(37, 1, 0), + Node::new(5, 0, 2), + Node::new(5, 2, 1), + Node::new(5, 0, 0), + Node::new(5, 1, 1), + Node::new(36, 1, 0), + Node::new(4, 2, 1), + Node::new(4, 0, 2), + Node::new(4, 0, 0), + Node::new(4, 1, 1), + Node::new(35, 0, 1), + Node::new(3, 1, 2), + Node::new(3, 2, 0), + Node::new(3, 0, 0), + Node::new(3, 1, 1), + Node::new(34, 1, 0), + Node::new(2, 2, 1), + Node::new(2, 0, 2), + Node::new(2, 0, 0), + Node::new(2, 1, 1), + Node::new(33, 0, 1), + Node::new(1, 1, 2), + Node::new(1, 2, 0), + Node::new(1, 0, 0), + Node::new(32, 1, 0), + Node::new(0, 0, 1), + ], + [ + 0, 2, 4, 7, 9, 12, 14, 17, 19, 22, 24, 27, 29, 32, 34, 37, 39, 42, 44, 47, 49, 52, 54, 57, 59, 62, 64, 67, 69, 72, + 74, 77, 79, 82, 84, 87, 89, 92, 94, 97, 99, 102, 104, 107, 109, 111, + ], + 3, + )), + AnyBitCircuit::B23(BitCircuit::new( + [ + Node::new(55, 0, 1), + Node::new(55, 1, 0), + Node::new(23, 1, 0), + Node::new(23, 0, 1), + Node::new(23, 0, 0), + Node::new(23, 1, 1), + Node::new(54, 0, 1), + Node::new(22, 2, 0), + Node::new(22, 1, 2), + Node::new(22, 0, 0), + Node::new(22, 1, 1), + Node::new(53, 0, 1), + Node::new(21, 1, 2), + Node::new(21, 2, 0), + Node::new(21, 0, 0), + Node::new(21, 1, 1), + Node::new(52, 1, 0), + Node::new(20, 0, 2), + Node::new(20, 2, 1), + Node::new(20, 0, 0), + Node::new(20, 1, 1), + Node::new(51, 1, 0), + Node::new(19, 0, 2), + Node::new(19, 2, 1), + Node::new(19, 0, 0), + Node::new(19, 1, 1), + Node::new(50, 1, 0), + Node::new(18, 0, 2), + Node::new(18, 2, 1), + Node::new(18, 0, 0), + Node::new(18, 1, 1), + Node::new(49, 1, 0), + Node::new(17, 2, 1), + Node::new(17, 0, 2), + Node::new(17, 0, 0), + Node::new(17, 1, 1), + Node::new(48, 0, 1), + Node::new(16, 2, 0), + Node::new(16, 1, 2), + Node::new(16, 0, 0), + Node::new(16, 1, 1), + Node::new(47, 0, 1), + Node::new(15, 1, 2), + Node::new(15, 2, 0), + Node::new(15, 0, 0), + Node::new(15, 1, 1), + Node::new(46, 1, 0), + Node::new(14, 0, 2), + Node::new(14, 2, 1), + Node::new(14, 0, 0), + Node::new(14, 1, 1), + Node::new(45, 1, 0), + Node::new(13, 0, 2), + Node::new(13, 2, 1), + Node::new(13, 0, 0), + Node::new(13, 1, 1), + Node::new(44, 1, 0), + Node::new(12, 2, 1), + Node::new(12, 0, 2), + Node::new(12, 0, 0), + Node::new(12, 1, 1), + Node::new(43, 0, 1), + Node::new(11, 1, 2), + Node::new(11, 2, 0), + Node::new(11, 0, 0), + Node::new(11, 1, 1), + Node::new(42, 1, 0), + Node::new(10, 2, 1), + Node::new(10, 0, 2), + Node::new(10, 0, 0), + Node::new(10, 1, 1), + Node::new(41, 0, 1), + Node::new(9, 2, 0), + Node::new(9, 1, 2), + Node::new(9, 0, 0), + Node::new(9, 1, 1), + Node::new(40, 0, 1), + Node::new(8, 1, 2), + Node::new(8, 2, 0), + Node::new(8, 0, 0), + Node::new(8, 1, 1), + Node::new(39, 1, 0), + Node::new(7, 2, 1), + Node::new(7, 0, 2), + Node::new(7, 0, 0), + Node::new(7, 1, 1), + Node::new(38, 0, 1), + Node::new(6, 1, 2), + Node::new(6, 2, 0), + Node::new(6, 0, 0), + Node::new(6, 1, 1), + Node::new(37, 1, 0), + Node::new(5, 0, 2), + Node::new(5, 2, 1), + Node::new(5, 0, 0), + Node::new(5, 1, 1), + Node::new(36, 1, 0), + Node::new(4, 0, 2), + Node::new(4, 2, 1), + Node::new(4, 0, 0), + Node::new(4, 1, 1), + Node::new(35, 1, 0), + Node::new(3, 2, 1), + Node::new(3, 0, 2), + Node::new(3, 0, 0), + Node::new(3, 1, 1), + Node::new(34, 0, 1), + Node::new(2, 1, 2), + Node::new(2, 2, 0), + Node::new(2, 0, 0), + Node::new(2, 1, 1), + Node::new(33, 1, 0), + Node::new(1, 0, 2), + Node::new(1, 2, 1), + Node::new(1, 0, 0), + Node::new(32, 1, 0), + Node::new(0, 0, 1), + ], + [ + 0, 2, 4, 7, 9, 12, 14, 17, 19, 22, 24, 27, 29, 32, 34, 37, 39, 42, 44, 47, 49, 52, 54, 57, 59, 62, 64, 67, 69, 72, + 74, 77, 79, 82, 84, 87, 89, 92, 94, 97, 99, 102, 104, 107, 109, 112, 114, 116, + ], + 3, + )), + AnyBitCircuit::B24(BitCircuit::new( + [ + Node::new(56, 1, 0), + Node::new(56, 0, 1), + Node::new(24, 1, 0), + Node::new(24, 0, 1), + Node::new(24, 0, 0), + Node::new(24, 1, 1), + Node::new(55, 1, 0), + Node::new(23, 0, 2), + Node::new(23, 2, 1), + Node::new(23, 0, 0), + Node::new(23, 1, 1), + Node::new(54, 1, 0), + Node::new(22, 2, 1), + Node::new(22, 0, 2), + Node::new(22, 0, 0), + Node::new(22, 1, 1), + Node::new(53, 0, 1), + Node::new(21, 2, 0), + Node::new(21, 1, 2), + Node::new(21, 0, 0), + Node::new(21, 1, 1), + Node::new(52, 0, 1), + Node::new(20, 2, 0), + Node::new(20, 1, 2), + Node::new(20, 0, 0), + Node::new(20, 1, 1), + Node::new(51, 0, 1), + Node::new(19, 2, 0), + Node::new(19, 1, 2), + Node::new(19, 0, 0), + Node::new(19, 1, 1), + Node::new(50, 0, 1), + Node::new(18, 2, 0), + Node::new(18, 1, 2), + Node::new(18, 0, 0), + Node::new(18, 1, 1), + Node::new(49, 0, 1), + Node::new(17, 1, 2), + Node::new(17, 2, 0), + Node::new(17, 0, 0), + Node::new(17, 1, 1), + Node::new(48, 1, 0), + Node::new(16, 2, 1), + Node::new(16, 0, 2), + Node::new(16, 0, 0), + Node::new(16, 1, 1), + Node::new(47, 0, 1), + Node::new(15, 1, 2), + Node::new(15, 2, 0), + Node::new(15, 0, 0), + Node::new(15, 1, 1), + Node::new(46, 1, 0), + Node::new(14, 2, 1), + Node::new(14, 0, 2), + Node::new(14, 0, 0), + Node::new(14, 1, 1), + Node::new(45, 0, 1), + Node::new(13, 1, 2), + Node::new(13, 2, 0), + Node::new(13, 0, 0), + Node::new(13, 1, 1), + Node::new(44, 1, 0), + Node::new(12, 2, 1), + Node::new(12, 0, 2), + Node::new(12, 0, 0), + Node::new(12, 1, 1), + Node::new(43, 0, 1), + Node::new(11, 2, 0), + Node::new(11, 1, 2), + Node::new(11, 0, 0), + Node::new(11, 1, 1), + Node::new(42, 0, 1), + Node::new(10, 1, 2), + Node::new(10, 2, 0), + Node::new(10, 0, 0), + Node::new(10, 1, 1), + Node::new(41, 1, 0), + Node::new(9, 2, 1), + Node::new(9, 0, 2), + Node::new(9, 0, 0), + Node::new(9, 1, 1), + Node::new(40, 0, 1), + Node::new(8, 2, 0), + Node::new(8, 1, 2), + Node::new(8, 0, 0), + Node::new(8, 1, 1), + Node::new(39, 0, 1), + Node::new(7, 2, 0), + Node::new(7, 1, 2), + Node::new(7, 0, 0), + Node::new(7, 1, 1), + Node::new(38, 0, 1), + Node::new(6, 2, 0), + Node::new(6, 1, 2), + Node::new(6, 0, 0), + Node::new(6, 1, 1), + Node::new(37, 0, 1), + Node::new(5, 1, 2), + Node::new(5, 2, 0), + Node::new(5, 0, 0), + Node::new(5, 1, 1), + Node::new(36, 1, 0), + Node::new(4, 2, 1), + Node::new(4, 0, 2), + Node::new(4, 0, 0), + Node::new(4, 1, 1), + Node::new(35, 0, 1), + Node::new(3, 2, 0), + Node::new(3, 1, 2), + Node::new(3, 0, 0), + Node::new(3, 1, 1), + Node::new(34, 0, 1), + Node::new(2, 1, 2), + Node::new(2, 2, 0), + Node::new(2, 0, 0), + Node::new(2, 1, 1), + Node::new(33, 1, 0), + Node::new(1, 0, 2), + Node::new(1, 2, 1), + Node::new(1, 0, 0), + Node::new(32, 1, 0), + Node::new(0, 0, 1), + ], + [ + 0, 2, 4, 7, 9, 12, 14, 17, 19, 22, 24, 27, 29, 32, 34, 37, 39, 42, 44, 47, 49, 52, 54, 57, 59, 62, 64, 67, 69, 72, + 74, 77, 79, 82, 84, 87, 89, 92, 94, 97, 99, 102, 104, 107, 109, 112, 114, 117, 119, 121, + ], + 3, + )), + AnyBitCircuit::B25(BitCircuit::new( + [ + Node::new(57, 1, 0), + Node::new(57, 0, 1), + Node::new(25, 0, 1), + Node::new(25, 1, 0), + Node::new(25, 0, 0), + Node::new(25, 1, 1), + Node::new(56, 0, 1), + Node::new(24, 1, 2), + Node::new(24, 2, 0), + Node::new(24, 0, 0), + Node::new(24, 1, 1), + Node::new(55, 1, 0), + Node::new(23, 0, 2), + Node::new(23, 2, 1), + Node::new(23, 0, 0), + Node::new(23, 1, 1), + Node::new(54, 1, 0), + Node::new(22, 0, 2), + Node::new(22, 2, 1), + Node::new(22, 0, 0), + Node::new(22, 1, 1), + Node::new(53, 1, 0), + Node::new(21, 2, 1), + Node::new(21, 0, 2), + Node::new(21, 0, 0), + Node::new(21, 1, 1), + Node::new(52, 0, 1), + Node::new(20, 1, 2), + Node::new(20, 2, 0), + Node::new(20, 0, 0), + Node::new(20, 1, 1), + Node::new(51, 1, 0), + Node::new(19, 0, 2), + Node::new(19, 2, 1), + Node::new(19, 0, 0), + Node::new(19, 1, 1), + Node::new(50, 1, 0), + Node::new(18, 2, 1), + Node::new(18, 0, 2), + Node::new(18, 0, 0), + Node::new(18, 1, 1), + Node::new(49, 0, 1), + Node::new(17, 2, 0), + Node::new(17, 1, 2), + Node::new(17, 0, 0), + Node::new(17, 1, 1), + Node::new(48, 0, 1), + Node::new(16, 1, 2), + Node::new(16, 2, 0), + Node::new(16, 0, 0), + Node::new(16, 1, 1), + Node::new(47, 1, 0), + Node::new(15, 2, 1), + Node::new(15, 0, 2), + Node::new(15, 0, 0), + Node::new(15, 1, 1), + Node::new(46, 0, 1), + Node::new(14, 2, 0), + Node::new(14, 1, 2), + Node::new(14, 0, 0), + Node::new(14, 1, 1), + Node::new(45, 0, 1), + Node::new(13, 1, 2), + Node::new(13, 2, 0), + Node::new(13, 0, 0), + Node::new(13, 1, 1), + Node::new(44, 1, 0), + Node::new(12, 2, 1), + Node::new(12, 0, 2), + Node::new(12, 0, 0), + Node::new(12, 1, 1), + Node::new(43, 0, 1), + Node::new(11, 2, 0), + Node::new(11, 1, 2), + Node::new(11, 0, 0), + Node::new(11, 1, 1), + Node::new(42, 0, 1), + Node::new(10, 2, 0), + Node::new(10, 1, 2), + Node::new(10, 0, 0), + Node::new(10, 1, 1), + Node::new(41, 0, 1), + Node::new(9, 1, 2), + Node::new(9, 2, 0), + Node::new(9, 0, 0), + Node::new(9, 1, 1), + Node::new(40, 1, 0), + Node::new(8, 2, 1), + Node::new(8, 0, 2), + Node::new(8, 0, 0), + Node::new(8, 1, 1), + Node::new(39, 0, 1), + Node::new(7, 1, 2), + Node::new(7, 2, 0), + Node::new(7, 0, 0), + Node::new(7, 1, 1), + Node::new(38, 1, 0), + Node::new(6, 2, 1), + Node::new(6, 0, 2), + Node::new(6, 0, 0), + Node::new(6, 1, 1), + Node::new(37, 0, 1), + Node::new(5, 2, 0), + Node::new(5, 1, 2), + Node::new(5, 0, 0), + Node::new(5, 1, 1), + Node::new(36, 0, 1), + Node::new(4, 1, 2), + Node::new(4, 2, 0), + Node::new(4, 0, 0), + Node::new(4, 1, 1), + Node::new(35, 1, 0), + Node::new(3, 2, 1), + Node::new(3, 0, 2), + Node::new(3, 0, 0), + Node::new(3, 1, 1), + Node::new(34, 0, 1), + Node::new(2, 1, 2), + Node::new(2, 2, 0), + Node::new(2, 0, 0), + Node::new(2, 1, 1), + Node::new(33, 1, 0), + Node::new(1, 0, 2), + Node::new(1, 2, 1), + Node::new(1, 0, 0), + Node::new(32, 1, 0), + Node::new(0, 0, 1), + ], + [ + 0, 2, 4, 7, 9, 12, 14, 17, 19, 22, 24, 27, 29, 32, 34, 37, 39, 42, 44, 47, 49, 52, 54, 57, 59, 62, 64, 67, 69, 72, + 74, 77, 79, 82, 84, 87, 89, 92, 94, 97, 99, 102, 104, 107, 109, 112, 114, 117, 119, 122, 124, 126, + ], + 3, + )), + AnyBitCircuit::B26(BitCircuit::new( + [ + Node::new(58, 0, 1), + Node::new(58, 1, 0), + Node::new(26, 0, 1), + Node::new(26, 1, 0), + Node::new(26, 0, 0), + Node::new(26, 1, 1), + Node::new(57, 1, 0), + Node::new(25, 0, 2), + Node::new(25, 2, 1), + Node::new(25, 0, 0), + Node::new(25, 1, 1), + Node::new(56, 1, 0), + Node::new(24, 2, 1), + Node::new(24, 0, 2), + Node::new(24, 0, 0), + Node::new(24, 1, 1), + Node::new(55, 0, 1), + Node::new(23, 1, 2), + Node::new(23, 2, 0), + Node::new(23, 0, 0), + Node::new(23, 1, 1), + Node::new(54, 1, 0), + Node::new(22, 2, 1), + Node::new(22, 0, 2), + Node::new(22, 0, 0), + Node::new(22, 1, 1), + Node::new(53, 0, 1), + Node::new(21, 2, 0), + Node::new(21, 1, 2), + Node::new(21, 0, 0), + Node::new(21, 1, 1), + Node::new(52, 0, 1), + Node::new(20, 1, 2), + Node::new(20, 2, 0), + Node::new(20, 0, 0), + Node::new(20, 1, 1), + Node::new(51, 1, 0), + Node::new(19, 0, 2), + Node::new(19, 2, 1), + Node::new(19, 0, 0), + Node::new(19, 1, 1), + Node::new(50, 1, 0), + Node::new(18, 0, 2), + Node::new(18, 2, 1), + Node::new(18, 0, 0), + Node::new(18, 1, 1), + Node::new(49, 1, 0), + Node::new(17, 2, 1), + Node::new(17, 0, 2), + Node::new(17, 0, 0), + Node::new(17, 1, 1), + Node::new(48, 0, 1), + Node::new(16, 1, 2), + Node::new(16, 2, 0), + Node::new(16, 0, 0), + Node::new(16, 1, 1), + Node::new(47, 1, 0), + Node::new(15, 2, 1), + Node::new(15, 0, 2), + Node::new(15, 0, 0), + Node::new(15, 1, 1), + Node::new(46, 0, 1), + Node::new(14, 2, 0), + Node::new(14, 1, 2), + Node::new(14, 0, 0), + Node::new(14, 1, 1), + Node::new(45, 0, 1), + Node::new(13, 2, 0), + Node::new(13, 1, 2), + Node::new(13, 0, 0), + Node::new(13, 1, 1), + Node::new(44, 0, 1), + Node::new(12, 2, 0), + Node::new(12, 1, 2), + Node::new(12, 0, 0), + Node::new(12, 1, 1), + Node::new(43, 0, 1), + Node::new(11, 1, 2), + Node::new(11, 2, 0), + Node::new(11, 0, 0), + Node::new(11, 1, 1), + Node::new(42, 1, 0), + Node::new(10, 0, 2), + Node::new(10, 2, 1), + Node::new(10, 0, 0), + Node::new(10, 1, 1), + Node::new(41, 1, 0), + Node::new(9, 0, 2), + Node::new(9, 2, 1), + Node::new(9, 0, 0), + Node::new(9, 1, 1), + Node::new(40, 1, 0), + Node::new(8, 0, 2), + Node::new(8, 2, 1), + Node::new(8, 0, 0), + Node::new(8, 1, 1), + Node::new(39, 1, 0), + Node::new(7, 0, 2), + Node::new(7, 2, 1), + Node::new(7, 0, 0), + Node::new(7, 1, 1), + Node::new(38, 1, 0), + Node::new(6, 2, 1), + Node::new(6, 0, 2), + Node::new(6, 0, 0), + Node::new(6, 1, 1), + Node::new(37, 0, 1), + Node::new(5, 1, 2), + Node::new(5, 2, 0), + Node::new(5, 0, 0), + Node::new(5, 1, 1), + Node::new(36, 1, 0), + Node::new(4, 2, 1), + Node::new(4, 0, 2), + Node::new(4, 0, 0), + Node::new(4, 1, 1), + Node::new(35, 0, 1), + Node::new(3, 1, 2), + Node::new(3, 2, 0), + Node::new(3, 0, 0), + Node::new(3, 1, 1), + Node::new(34, 1, 0), + Node::new(2, 2, 1), + Node::new(2, 0, 2), + Node::new(2, 0, 0), + Node::new(2, 1, 1), + Node::new(33, 0, 1), + Node::new(1, 1, 2), + Node::new(1, 2, 0), + Node::new(1, 0, 0), + Node::new(32, 1, 0), + Node::new(0, 0, 1), + ], + [ + 0, 2, 4, 7, 9, 12, 14, 17, 19, 22, 24, 27, 29, 32, 34, 37, 39, 42, 44, 47, 49, 52, 54, 57, 59, 62, 64, 67, 69, 72, + 74, 77, 79, 82, 84, 87, 89, 92, 94, 97, 99, 102, 104, 107, 109, 112, 114, 117, 119, 122, 124, 127, 129, 131, + ], + 3, + )), + AnyBitCircuit::B27(BitCircuit::new( + [ + Node::new(59, 1, 0), + Node::new(59, 0, 1), + Node::new(27, 0, 1), + Node::new(27, 1, 0), + Node::new(27, 0, 0), + Node::new(27, 1, 1), + Node::new(58, 0, 1), + Node::new(26, 1, 2), + Node::new(26, 2, 0), + Node::new(26, 0, 0), + Node::new(26, 1, 1), + Node::new(57, 1, 0), + Node::new(25, 0, 2), + Node::new(25, 2, 1), + Node::new(25, 0, 0), + Node::new(25, 1, 1), + Node::new(56, 1, 0), + Node::new(24, 2, 1), + Node::new(24, 0, 2), + Node::new(24, 0, 0), + Node::new(24, 1, 1), + Node::new(55, 0, 1), + Node::new(23, 2, 0), + Node::new(23, 1, 2), + Node::new(23, 0, 0), + Node::new(23, 1, 1), + Node::new(54, 0, 1), + Node::new(22, 1, 2), + Node::new(22, 2, 0), + Node::new(22, 0, 0), + Node::new(22, 1, 1), + Node::new(53, 1, 0), + Node::new(21, 0, 2), + Node::new(21, 2, 1), + Node::new(21, 0, 0), + Node::new(21, 1, 1), + Node::new(52, 1, 0), + Node::new(20, 2, 1), + Node::new(20, 0, 2), + Node::new(20, 0, 0), + Node::new(20, 1, 1), + Node::new(51, 0, 1), + Node::new(19, 2, 0), + Node::new(19, 1, 2), + Node::new(19, 0, 0), + Node::new(19, 1, 1), + Node::new(50, 0, 1), + Node::new(18, 2, 0), + Node::new(18, 1, 2), + Node::new(18, 0, 0), + Node::new(18, 1, 1), + Node::new(49, 0, 1), + Node::new(17, 1, 2), + Node::new(17, 2, 0), + Node::new(17, 0, 0), + Node::new(17, 1, 1), + Node::new(48, 1, 0), + Node::new(16, 2, 1), + Node::new(16, 0, 2), + Node::new(16, 0, 0), + Node::new(16, 1, 1), + Node::new(47, 0, 1), + Node::new(15, 1, 2), + Node::new(15, 2, 0), + Node::new(15, 0, 0), + Node::new(15, 1, 1), + Node::new(46, 1, 0), + Node::new(14, 2, 1), + Node::new(14, 0, 2), + Node::new(14, 0, 0), + Node::new(14, 1, 1), + Node::new(45, 0, 1), + Node::new(13, 1, 2), + Node::new(13, 2, 0), + Node::new(13, 0, 0), + Node::new(13, 1, 1), + Node::new(44, 1, 0), + Node::new(12, 0, 2), + Node::new(12, 2, 1), + Node::new(12, 0, 0), + Node::new(12, 1, 1), + Node::new(43, 1, 0), + Node::new(11, 0, 2), + Node::new(11, 2, 1), + Node::new(11, 0, 0), + Node::new(11, 1, 1), + Node::new(42, 1, 0), + Node::new(10, 0, 2), + Node::new(10, 2, 1), + Node::new(10, 0, 0), + Node::new(10, 1, 1), + Node::new(41, 1, 0), + Node::new(9, 2, 1), + Node::new(9, 0, 2), + Node::new(9, 0, 0), + Node::new(9, 1, 1), + Node::new(40, 0, 1), + Node::new(8, 2, 0), + Node::new(8, 1, 2), + Node::new(8, 0, 0), + Node::new(8, 1, 1), + Node::new(39, 0, 1), + Node::new(7, 1, 2), + Node::new(7, 2, 0), + Node::new(7, 0, 0), + Node::new(7, 1, 1), + Node::new(38, 1, 0), + Node::new(6, 2, 1), + Node::new(6, 0, 2), + Node::new(6, 0, 0), + Node::new(6, 1, 1), + Node::new(37, 0, 1), + Node::new(5, 1, 2), + Node::new(5, 2, 0), + Node::new(5, 0, 0), + Node::new(5, 1, 1), + Node::new(36, 1, 0), + Node::new(4, 2, 1), + Node::new(4, 0, 2), + Node::new(4, 0, 0), + Node::new(4, 1, 1), + Node::new(35, 0, 1), + Node::new(3, 1, 2), + Node::new(3, 2, 0), + Node::new(3, 0, 0), + Node::new(3, 1, 1), + Node::new(34, 1, 0), + Node::new(2, 2, 1), + Node::new(2, 0, 2), + Node::new(2, 0, 0), + Node::new(2, 1, 1), + Node::new(33, 0, 1), + Node::new(1, 1, 2), + Node::new(1, 2, 0), + Node::new(1, 0, 0), + Node::new(32, 1, 0), + Node::new(0, 0, 1), + ], + [ + 0, 2, 4, 7, 9, 12, 14, 17, 19, 22, 24, 27, 29, 32, 34, 37, 39, 42, 44, 47, 49, 52, 54, 57, 59, 62, 64, 67, 69, 72, + 74, 77, 79, 82, 84, 87, 89, 92, 94, 97, 99, 102, 104, 107, 109, 112, 114, 117, 119, 122, 124, 127, 129, 132, 134, + 136, + ], + 3, + )), + AnyBitCircuit::B28(BitCircuit::new( + [ + Node::new(60, 1, 0), + Node::new(60, 0, 1), + Node::new(28, 0, 1), + Node::new(28, 1, 0), + Node::new(28, 0, 0), + Node::new(28, 1, 1), + Node::new(59, 0, 1), + Node::new(27, 1, 2), + Node::new(27, 2, 0), + Node::new(27, 0, 0), + Node::new(27, 1, 1), + Node::new(58, 1, 0), + Node::new(26, 2, 1), + Node::new(26, 0, 2), + Node::new(26, 0, 0), + Node::new(26, 1, 1), + Node::new(57, 0, 1), + Node::new(25, 1, 2), + Node::new(25, 2, 0), + Node::new(25, 0, 0), + Node::new(25, 1, 1), + Node::new(56, 1, 0), + Node::new(24, 2, 1), + Node::new(24, 0, 2), + Node::new(24, 0, 0), + Node::new(24, 1, 1), + Node::new(55, 0, 1), + Node::new(23, 1, 2), + Node::new(23, 2, 0), + Node::new(23, 0, 0), + Node::new(23, 1, 1), + Node::new(54, 1, 0), + Node::new(22, 2, 1), + Node::new(22, 0, 2), + Node::new(22, 0, 0), + Node::new(22, 1, 1), + Node::new(53, 0, 1), + Node::new(21, 1, 2), + Node::new(21, 2, 0), + Node::new(21, 0, 0), + Node::new(21, 1, 1), + Node::new(52, 1, 0), + Node::new(20, 2, 1), + Node::new(20, 0, 2), + Node::new(20, 0, 0), + Node::new(20, 1, 1), + Node::new(51, 0, 1), + Node::new(19, 2, 0), + Node::new(19, 1, 2), + Node::new(19, 0, 0), + Node::new(19, 1, 1), + Node::new(50, 0, 1), + Node::new(18, 2, 0), + Node::new(18, 1, 2), + Node::new(18, 0, 0), + Node::new(18, 1, 1), + Node::new(49, 0, 1), + Node::new(17, 1, 2), + Node::new(17, 2, 0), + Node::new(17, 0, 0), + Node::new(17, 1, 1), + Node::new(48, 1, 0), + Node::new(16, 2, 1), + Node::new(16, 0, 2), + Node::new(16, 0, 0), + Node::new(16, 1, 1), + Node::new(47, 0, 1), + Node::new(15, 2, 0), + Node::new(15, 1, 2), + Node::new(15, 0, 0), + Node::new(15, 1, 1), + Node::new(46, 0, 1), + Node::new(14, 2, 0), + Node::new(14, 1, 2), + Node::new(14, 0, 0), + Node::new(14, 1, 1), + Node::new(45, 0, 1), + Node::new(13, 2, 0), + Node::new(13, 1, 2), + Node::new(13, 0, 0), + Node::new(13, 1, 1), + Node::new(44, 0, 1), + Node::new(12, 1, 2), + Node::new(12, 2, 0), + Node::new(12, 0, 0), + Node::new(12, 1, 1), + Node::new(43, 1, 0), + Node::new(11, 2, 1), + Node::new(11, 0, 2), + Node::new(11, 0, 0), + Node::new(11, 1, 1), + Node::new(42, 0, 1), + Node::new(10, 2, 0), + Node::new(10, 1, 2), + Node::new(10, 0, 0), + Node::new(10, 1, 1), + Node::new(41, 0, 1), + Node::new(9, 1, 2), + Node::new(9, 2, 0), + Node::new(9, 0, 0), + Node::new(9, 1, 1), + Node::new(40, 1, 0), + Node::new(8, 2, 1), + Node::new(8, 0, 2), + Node::new(8, 0, 0), + Node::new(8, 1, 1), + Node::new(39, 0, 1), + Node::new(7, 1, 2), + Node::new(7, 2, 0), + Node::new(7, 0, 0), + Node::new(7, 1, 1), + Node::new(38, 1, 0), + Node::new(6, 0, 2), + Node::new(6, 2, 1), + Node::new(6, 0, 0), + Node::new(6, 1, 1), + Node::new(37, 1, 0), + Node::new(5, 0, 2), + Node::new(5, 2, 1), + Node::new(5, 0, 0), + Node::new(5, 1, 1), + Node::new(36, 1, 0), + Node::new(4, 2, 1), + Node::new(4, 0, 2), + Node::new(4, 0, 0), + Node::new(4, 1, 1), + Node::new(35, 0, 1), + Node::new(3, 2, 0), + Node::new(3, 1, 2), + Node::new(3, 0, 0), + Node::new(3, 1, 1), + Node::new(34, 0, 1), + Node::new(2, 2, 0), + Node::new(2, 1, 2), + Node::new(2, 0, 0), + Node::new(2, 1, 1), + Node::new(33, 0, 1), + Node::new(1, 1, 2), + Node::new(1, 2, 0), + Node::new(1, 0, 0), + Node::new(32, 1, 0), + Node::new(0, 0, 1), + ], + [ + 0, 2, 4, 7, 9, 12, 14, 17, 19, 22, 24, 27, 29, 32, 34, 37, 39, 42, 44, 47, 49, 52, 54, 57, 59, 62, 64, 67, 69, 72, + 74, 77, 79, 82, 84, 87, 89, 92, 94, 97, 99, 102, 104, 107, 109, 112, 114, 117, 119, 122, 124, 127, 129, 132, 134, + 137, 139, 141, + ], + 3, + )), + AnyBitCircuit::B29(BitCircuit::new( + [ + Node::new(61, 1, 0), + Node::new(61, 0, 1), + Node::new(29, 0, 1), + Node::new(29, 1, 0), + Node::new(29, 0, 0), + Node::new(29, 1, 1), + Node::new(60, 0, 1), + Node::new(28, 2, 0), + Node::new(28, 1, 2), + Node::new(28, 0, 0), + Node::new(28, 1, 1), + Node::new(59, 0, 1), + Node::new(27, 1, 2), + Node::new(27, 2, 0), + Node::new(27, 0, 0), + Node::new(27, 1, 1), + Node::new(58, 1, 0), + Node::new(26, 0, 2), + Node::new(26, 2, 1), + Node::new(26, 0, 0), + Node::new(26, 1, 1), + Node::new(57, 1, 0), + Node::new(25, 2, 1), + Node::new(25, 0, 2), + Node::new(25, 0, 0), + Node::new(25, 1, 1), + Node::new(56, 0, 1), + Node::new(24, 1, 2), + Node::new(24, 2, 0), + Node::new(24, 0, 0), + Node::new(24, 1, 1), + Node::new(55, 1, 0), + Node::new(23, 2, 1), + Node::new(23, 0, 2), + Node::new(23, 0, 0), + Node::new(23, 1, 1), + Node::new(54, 0, 1), + Node::new(22, 1, 2), + Node::new(22, 2, 0), + Node::new(22, 0, 0), + Node::new(22, 1, 1), + Node::new(53, 1, 0), + Node::new(21, 0, 2), + Node::new(21, 2, 1), + Node::new(21, 0, 0), + Node::new(21, 1, 1), + Node::new(52, 1, 0), + Node::new(20, 0, 2), + Node::new(20, 2, 1), + Node::new(20, 0, 0), + Node::new(20, 1, 1), + Node::new(51, 1, 0), + Node::new(19, 0, 2), + Node::new(19, 2, 1), + Node::new(19, 0, 0), + Node::new(19, 1, 1), + Node::new(50, 1, 0), + Node::new(18, 0, 2), + Node::new(18, 2, 1), + Node::new(18, 0, 0), + Node::new(18, 1, 1), + Node::new(49, 1, 0), + Node::new(17, 2, 1), + Node::new(17, 0, 2), + Node::new(17, 0, 0), + Node::new(17, 1, 1), + Node::new(48, 0, 1), + Node::new(16, 1, 2), + Node::new(16, 2, 0), + Node::new(16, 0, 0), + Node::new(16, 1, 1), + Node::new(47, 1, 0), + Node::new(15, 2, 1), + Node::new(15, 0, 2), + Node::new(15, 0, 0), + Node::new(15, 1, 1), + Node::new(46, 0, 1), + Node::new(14, 2, 0), + Node::new(14, 1, 2), + Node::new(14, 0, 0), + Node::new(14, 1, 1), + Node::new(45, 0, 1), + Node::new(13, 1, 2), + Node::new(13, 2, 0), + Node::new(13, 0, 0), + Node::new(13, 1, 1), + Node::new(44, 1, 0), + Node::new(12, 2, 1), + Node::new(12, 0, 2), + Node::new(12, 0, 0), + Node::new(12, 1, 1), + Node::new(43, 0, 1), + Node::new(11, 1, 2), + Node::new(11, 2, 0), + Node::new(11, 0, 0), + Node::new(11, 1, 1), + Node::new(42, 1, 0), + Node::new(10, 0, 2), + Node::new(10, 2, 1), + Node::new(10, 0, 0), + Node::new(10, 1, 1), + Node::new(41, 1, 0), + Node::new(9, 0, 2), + Node::new(9, 2, 1), + Node::new(9, 0, 0), + Node::new(9, 1, 1), + Node::new(40, 1, 0), + Node::new(8, 2, 1), + Node::new(8, 0, 2), + Node::new(8, 0, 0), + Node::new(8, 1, 1), + Node::new(39, 0, 1), + Node::new(7, 2, 0), + Node::new(7, 1, 2), + Node::new(7, 0, 0), + Node::new(7, 1, 1), + Node::new(38, 0, 1), + Node::new(6, 1, 2), + Node::new(6, 2, 0), + Node::new(6, 0, 0), + Node::new(6, 1, 1), + Node::new(37, 1, 0), + Node::new(5, 2, 1), + Node::new(5, 0, 2), + Node::new(5, 0, 0), + Node::new(5, 1, 1), + Node::new(36, 0, 1), + Node::new(4, 1, 2), + Node::new(4, 2, 0), + Node::new(4, 0, 0), + Node::new(4, 1, 1), + Node::new(35, 1, 0), + Node::new(3, 2, 1), + Node::new(3, 0, 2), + Node::new(3, 0, 0), + Node::new(3, 1, 1), + Node::new(34, 0, 1), + Node::new(2, 2, 0), + Node::new(2, 1, 2), + Node::new(2, 0, 0), + Node::new(2, 1, 1), + Node::new(33, 0, 1), + Node::new(1, 1, 2), + Node::new(1, 2, 0), + Node::new(1, 0, 0), + Node::new(32, 1, 0), + Node::new(0, 0, 1), + ], + [ + 0, 2, 4, 7, 9, 12, 14, 17, 19, 22, 24, 27, 29, 32, 34, 37, 39, 42, 44, 47, 49, 52, 54, 57, 59, 62, 64, 67, 69, 72, + 74, 77, 79, 82, 84, 87, 89, 92, 94, 97, 99, 102, 104, 107, 109, 112, 114, 117, 119, 122, 124, 127, 129, 132, 134, + 137, 139, 142, 144, 146, + ], + 3, + )), + AnyBitCircuit::B30(BitCircuit::new( + [ + Node::new(62, 0, 1), + Node::new(62, 1, 0), + Node::new(30, 1, 0), + Node::new(30, 0, 1), + Node::new(30, 0, 0), + Node::new(30, 1, 1), + Node::new(61, 0, 1), + Node::new(29, 1, 2), + Node::new(29, 2, 0), + Node::new(29, 0, 0), + Node::new(29, 1, 1), + Node::new(60, 1, 0), + Node::new(28, 2, 1), + Node::new(28, 0, 2), + Node::new(28, 0, 0), + Node::new(28, 1, 1), + Node::new(59, 0, 1), + Node::new(27, 1, 2), + Node::new(27, 2, 0), + Node::new(27, 0, 0), + Node::new(27, 1, 1), + Node::new(58, 1, 0), + Node::new(26, 0, 2), + Node::new(26, 2, 1), + Node::new(26, 0, 0), + Node::new(26, 1, 1), + Node::new(57, 1, 0), + Node::new(25, 0, 2), + Node::new(25, 2, 1), + Node::new(25, 0, 0), + Node::new(25, 1, 1), + Node::new(56, 1, 0), + Node::new(24, 2, 1), + Node::new(24, 0, 2), + Node::new(24, 0, 0), + Node::new(24, 1, 1), + Node::new(55, 0, 1), + Node::new(23, 2, 0), + Node::new(23, 1, 2), + Node::new(23, 0, 0), + Node::new(23, 1, 1), + Node::new(54, 0, 1), + Node::new(22, 1, 2), + Node::new(22, 2, 0), + Node::new(22, 0, 0), + Node::new(22, 1, 1), + Node::new(53, 1, 0), + Node::new(21, 2, 1), + Node::new(21, 0, 2), + Node::new(21, 0, 0), + Node::new(21, 1, 1), + Node::new(52, 0, 1), + Node::new(20, 1, 2), + Node::new(20, 2, 0), + Node::new(20, 0, 0), + Node::new(20, 1, 1), + Node::new(51, 1, 0), + Node::new(19, 2, 1), + Node::new(19, 0, 2), + Node::new(19, 0, 0), + Node::new(19, 1, 1), + Node::new(50, 0, 1), + Node::new(18, 2, 0), + Node::new(18, 1, 2), + Node::new(18, 0, 0), + Node::new(18, 1, 1), + Node::new(49, 0, 1), + Node::new(17, 2, 0), + Node::new(17, 1, 2), + Node::new(17, 0, 0), + Node::new(17, 1, 1), + Node::new(48, 0, 1), + Node::new(16, 1, 2), + Node::new(16, 2, 0), + Node::new(16, 0, 0), + Node::new(16, 1, 1), + Node::new(47, 1, 0), + Node::new(15, 0, 2), + Node::new(15, 2, 1), + Node::new(15, 0, 0), + Node::new(15, 1, 1), + Node::new(46, 1, 0), + Node::new(14, 2, 1), + Node::new(14, 0, 2), + Node::new(14, 0, 0), + Node::new(14, 1, 1), + Node::new(45, 0, 1), + Node::new(13, 2, 0), + Node::new(13, 1, 2), + Node::new(13, 0, 0), + Node::new(13, 1, 1), + Node::new(44, 0, 1), + Node::new(12, 1, 2), + Node::new(12, 2, 0), + Node::new(12, 0, 0), + Node::new(12, 1, 1), + Node::new(43, 1, 0), + Node::new(11, 0, 2), + Node::new(11, 2, 1), + Node::new(11, 0, 0), + Node::new(11, 1, 1), + Node::new(42, 1, 0), + Node::new(10, 2, 1), + Node::new(10, 0, 2), + Node::new(10, 0, 0), + Node::new(10, 1, 1), + Node::new(41, 0, 1), + Node::new(9, 2, 0), + Node::new(9, 1, 2), + Node::new(9, 0, 0), + Node::new(9, 1, 1), + Node::new(40, 0, 1), + Node::new(8, 1, 2), + Node::new(8, 2, 0), + Node::new(8, 0, 0), + Node::new(8, 1, 1), + Node::new(39, 1, 0), + Node::new(7, 0, 2), + Node::new(7, 2, 1), + Node::new(7, 0, 0), + Node::new(7, 1, 1), + Node::new(38, 1, 0), + Node::new(6, 2, 1), + Node::new(6, 0, 2), + Node::new(6, 0, 0), + Node::new(6, 1, 1), + Node::new(37, 0, 1), + Node::new(5, 1, 2), + Node::new(5, 2, 0), + Node::new(5, 0, 0), + Node::new(5, 1, 1), + Node::new(36, 1, 0), + Node::new(4, 0, 2), + Node::new(4, 2, 1), + Node::new(4, 0, 0), + Node::new(4, 1, 1), + Node::new(35, 1, 0), + Node::new(3, 2, 1), + Node::new(3, 0, 2), + Node::new(3, 0, 0), + Node::new(3, 1, 1), + Node::new(34, 0, 1), + Node::new(2, 2, 0), + Node::new(2, 1, 2), + Node::new(2, 0, 0), + Node::new(2, 1, 1), + Node::new(33, 0, 1), + Node::new(1, 1, 2), + Node::new(1, 2, 0), + Node::new(1, 0, 0), + Node::new(32, 1, 0), + Node::new(0, 0, 1), + ], + [ + 0, 2, 4, 7, 9, 12, 14, 17, 19, 22, 24, 27, 29, 32, 34, 37, 39, 42, 44, 47, 49, 52, 54, 57, 59, 62, 64, 67, 69, 72, + 74, 77, 79, 82, 84, 87, 89, 92, 94, 97, 99, 102, 104, 107, 109, 112, 114, 117, 119, 122, 124, 127, 129, 132, 134, + 137, 139, 142, 144, 147, 149, 151, + ], + 3, + )), + AnyBitCircuit::B31(BitCircuit::new( + [ + Node::new(63, 0, 1), + Node::new(63, 1, 0), + Node::new(31, 1, 0), + Node::new(31, 0, 1), + Node::new(31, 0, 0), + Node::new(31, 1, 1), + Node::new(62, 0, 1), + Node::new(30, 1, 2), + Node::new(30, 2, 0), + Node::new(30, 0, 0), + Node::new(30, 1, 1), + Node::new(61, 1, 0), + Node::new(29, 0, 2), + Node::new(29, 2, 1), + Node::new(29, 0, 0), + Node::new(29, 1, 1), + Node::new(60, 1, 0), + Node::new(28, 0, 2), + Node::new(28, 2, 1), + Node::new(28, 0, 0), + Node::new(28, 1, 1), + Node::new(59, 1, 0), + Node::new(27, 0, 2), + Node::new(27, 2, 1), + Node::new(27, 0, 0), + Node::new(27, 1, 1), + Node::new(58, 1, 0), + Node::new(26, 2, 1), + Node::new(26, 0, 2), + Node::new(26, 0, 0), + Node::new(26, 1, 1), + Node::new(57, 0, 1), + Node::new(25, 2, 0), + Node::new(25, 1, 2), + Node::new(25, 0, 0), + Node::new(25, 1, 1), + Node::new(56, 0, 1), + Node::new(24, 2, 0), + Node::new(24, 1, 2), + Node::new(24, 0, 0), + Node::new(24, 1, 1), + Node::new(55, 0, 1), + Node::new(23, 1, 2), + Node::new(23, 2, 0), + Node::new(23, 0, 0), + Node::new(23, 1, 1), + Node::new(54, 1, 0), + Node::new(22, 2, 1), + Node::new(22, 0, 2), + Node::new(22, 0, 0), + Node::new(22, 1, 1), + Node::new(53, 0, 1), + Node::new(21, 1, 2), + Node::new(21, 2, 0), + Node::new(21, 0, 0), + Node::new(21, 1, 1), + Node::new(52, 1, 0), + Node::new(20, 2, 1), + Node::new(20, 0, 2), + Node::new(20, 0, 0), + Node::new(20, 1, 1), + Node::new(51, 0, 1), + Node::new(19, 1, 2), + Node::new(19, 2, 0), + Node::new(19, 0, 0), + Node::new(19, 1, 1), + Node::new(50, 1, 0), + Node::new(18, 2, 1), + Node::new(18, 0, 2), + Node::new(18, 0, 0), + Node::new(18, 1, 1), + Node::new(49, 0, 1), + Node::new(17, 1, 2), + Node::new(17, 2, 0), + Node::new(17, 0, 0), + Node::new(17, 1, 1), + Node::new(48, 1, 0), + Node::new(16, 0, 2), + Node::new(16, 2, 1), + Node::new(16, 0, 0), + Node::new(16, 1, 1), + Node::new(47, 1, 0), + Node::new(15, 0, 2), + Node::new(15, 2, 1), + Node::new(15, 0, 0), + Node::new(15, 1, 1), + Node::new(46, 1, 0), + Node::new(14, 2, 1), + Node::new(14, 0, 2), + Node::new(14, 0, 0), + Node::new(14, 1, 1), + Node::new(45, 0, 1), + Node::new(13, 2, 0), + Node::new(13, 1, 2), + Node::new(13, 0, 0), + Node::new(13, 1, 1), + Node::new(44, 0, 1), + Node::new(12, 2, 0), + Node::new(12, 1, 2), + Node::new(12, 0, 0), + Node::new(12, 1, 1), + Node::new(43, 0, 1), + Node::new(11, 1, 2), + Node::new(11, 2, 0), + Node::new(11, 0, 0), + Node::new(11, 1, 1), + Node::new(42, 1, 0), + Node::new(10, 0, 2), + Node::new(10, 2, 1), + Node::new(10, 0, 0), + Node::new(10, 1, 1), + Node::new(41, 1, 0), + Node::new(9, 0, 2), + Node::new(9, 2, 1), + Node::new(9, 0, 0), + Node::new(9, 1, 1), + Node::new(40, 1, 0), + Node::new(8, 2, 1), + Node::new(8, 0, 2), + Node::new(8, 0, 0), + Node::new(8, 1, 1), + Node::new(39, 0, 1), + Node::new(7, 2, 0), + Node::new(7, 1, 2), + Node::new(7, 0, 0), + Node::new(7, 1, 1), + Node::new(38, 0, 1), + Node::new(6, 2, 0), + Node::new(6, 1, 2), + Node::new(6, 0, 0), + Node::new(6, 1, 1), + Node::new(37, 0, 1), + Node::new(5, 2, 0), + Node::new(5, 1, 2), + Node::new(5, 0, 0), + Node::new(5, 1, 1), + Node::new(36, 0, 1), + Node::new(4, 1, 2), + Node::new(4, 2, 0), + Node::new(4, 0, 0), + Node::new(4, 1, 1), + Node::new(35, 1, 0), + Node::new(3, 0, 2), + Node::new(3, 2, 1), + Node::new(3, 0, 0), + Node::new(3, 1, 1), + Node::new(34, 1, 0), + Node::new(2, 0, 2), + Node::new(2, 2, 1), + Node::new(2, 0, 0), + Node::new(2, 1, 1), + Node::new(33, 1, 0), + Node::new(1, 0, 2), + Node::new(1, 2, 1), + Node::new(1, 0, 0), + Node::new(32, 1, 0), + Node::new(0, 0, 1), + ], + [ + 0, 2, 4, 7, 9, 12, 14, 17, 19, 22, 24, 27, 29, 32, 34, 37, 39, 42, 44, 47, 49, 52, 54, 57, 59, 62, 64, 67, 69, 72, + 74, 77, 79, 82, 84, 87, 89, 92, 94, 97, 99, 102, 104, 107, 109, 112, 114, 117, 119, 122, 124, 127, 129, 132, 134, + 137, 139, 142, 144, 147, 149, 152, 154, 156, + ], + 3, + )), +]);
@@ -0,0 +1,34 @@
+use crate::tfhe::bdd_arithmetic::{BitCircuit, BitCircuitInfo, Circuit, GetBitCircuitInfo, Node}; +pub(crate) enum AnyBitCircuit { + B0(BitCircuit<3, 2>), +} + +impl BitCircuitInfo for AnyBitCircuit { + fn info(&self) -> (&[Node], &[usize], usize) { + match self { + AnyBitCircuit::B0(bit_circuit) => ( + bit_circuit.nodes.as_ref(), + bit_circuit.levels.as_ref(), + bit_circuit.max_inter_state, + ), + } + } +} + +impl GetBitCircuitInfo<u32> for Circuit<AnyBitCircuit, 1usize> { + fn input_size(&self) -> usize { + 2 * u32::BITS as usize + } + fn output_size(&self) -> usize { + u32::BITS as usize + } + fn get_circuit(&self, _bit: usize) -> (&[Node], &[usize], usize) { + self.0[0].info() + } +} + +pub(crate) static OUTPUT_CIRCUITS: Circuit<AnyBitCircuit, 1usize> = Circuit([AnyBitCircuit::B0(BitCircuit::new( + [Node::new(1, 1, 0), Node::new(1, 0, 1), Node::new(0, 1, 0)], + [0, 2], + 2, +))]);
@@ -0,0 +1,198 @@
+use itertools::Itertools; +use poulpy_core::{ + GLWEExternalProductInplace, GLWEOperations, TakeGLWECtSlice, + layouts::{ + GLWECiphertext, GLWECiphertextToMut, LWEInfos, + prepared::{GGSWCiphertextPrepared, GGSWCiphertextPreparedToRef}, + }, +}; +use poulpy_hal::{ + api::{VecZnxAddInplace, VecZnxCopy, VecZnxNegateInplace, VecZnxSub}, + layouts::{Backend, DataMut, DataRef, Module, Scratch, ZnxZero}, +}; + +use crate::tfhe::bdd_arithmetic::UnsignedInteger; + +pub trait BitCircuitInfo { + fn info(&self) -> (&[Node], &[usize], usize); +} + +pub trait GetBitCircuitInfo<T: UnsignedInteger> { + fn input_size(&self) -> usize; + fn output_size(&self) -> usize; + fn get_circuit(&self, bit: usize) -> (&[Node], &[usize], usize); +} + +pub(crate) struct BitCircuit<const N: usize, const K: usize> { + pub(crate) nodes: [Node; N], + pub(crate) levels: [usize; K], + pub(crate) max_inter_state: usize, +} + +pub struct Circuit<C: BitCircuitInfo, const N: usize>(pub [C; N]); + +pub trait CircuitExecute<BE: Backend, T: UnsignedInteger> +where + Self: GetBitCircuitInfo<T>, +{ + fn execute<O>( + &self, + module: &Module<BE>, + out: &mut [GLWECiphertext<O>], + inputs: &[&dyn GGSWCiphertextPreparedToRef<BE>], + scratch: &mut Scratch<BE>, + ) where + O: DataMut; +} + +impl<C: BitCircuitInfo, const N: usize, T: UnsignedInteger, BE: Backend> CircuitExecute<BE, T> for Circuit<C, N> +where + Self: GetBitCircuitInfo<T>, + Module<BE>: Cmux<BE> + VecZnxCopy, + Scratch<BE>: TakeGLWECtSlice, +{ + fn execute<O>( + &self, + module: &Module<BE>, + out: &mut [GLWECiphertext<O>], + inputs: &[&dyn GGSWCiphertextPreparedToRef<BE>], + scratch: &mut Scratch<BE>, + ) where + O: DataMut, + { + #[cfg(debug_assertions)] + { + assert_eq!(inputs.len(), self.input_size()); + assert!(out.len() >= self.output_size()); + } + + for (i, out_i) in out.iter_mut().enumerate().take(self.output_size()) { + let (nodes, levels, max_inter_state) = self.get_circuit(i); + + let (mut level, scratch_1) = scratch.take_glwe_ct_slice(max_inter_state * 2, out_i); + + level.iter_mut().for_each(|ct| ct.data_mut().zero()); + + // TODO: implement API on GLWE + level[1] + .data_mut() + .encode_coeff_i64(out_i.base2k().into(), 0, 2, 0, 1); + + let mut level_ref = level.iter_mut().collect_vec(); + let (mut prev_level, mut next_level) = level_ref.split_at_mut(max_inter_state); + + for i in 0..levels.len() - 1 { + let start: usize = levels[i]; + let end: usize = levels[i + 1]; + + let nodes_lvl: &[Node] = &nodes[start..end]; + + for (j, node) in nodes_lvl.iter().enumerate() { + if node.low_index == node.high_index { + next_level[j].copy(module, prev_level[node.low_index]); + } else { + module.cmux( + next_level[j], + prev_level[node.high_index], + prev_level[node.low_index], + &inputs[node.input_index].to_ref(), + scratch_1, + ); + } + } + + (prev_level, next_level) = (next_level, prev_level); + } + + // handle last output + // there's always only 1 node at last level + let node: &Node = nodes.last().unwrap(); + module.cmux( + out_i, + prev_level[node.high_index], + prev_level[node.low_index], + &inputs[node.input_index].to_ref(), + scratch_1, + ); + } + + for out_i in out.iter_mut().skip(self.output_size()) { + out_i.data_mut().zero(); + } + } +} + +impl<const N: usize, const K: usize> BitCircuit<N, K> { + pub(crate) const fn new(nodes: [Node; N], levels: [usize; K], max_inter_state: usize) -> Self { + Self { + nodes, + levels, + max_inter_state, + } + } +} +impl<const N: usize, const K: usize> BitCircuitInfo for BitCircuit<N, K> { + fn info(&self) -> (&[Node], &[usize], usize) { + ( + self.nodes.as_ref(), + self.levels.as_ref(), + self.max_inter_state, + ) + } +} + +#[derive(Debug)] +pub struct Node { + input_index: usize, + high_index: usize, + low_index: usize, +} + +impl Node { + pub(crate) const fn new(input_index: usize, high_index: usize, low_index: usize) -> Self { + Self { + input_index, + high_index, + low_index, + } + } +} + +pub trait Cmux<BE: Backend> { + fn cmux<O, T, F, S>( + &self, + out: &mut GLWECiphertext<O>, + t: &GLWECiphertext<T>, + f: &GLWECiphertext<F>, + s: &GGSWCiphertextPrepared<S, BE>, + scratch: &mut Scratch<BE>, + ) where + O: DataMut, + T: DataRef, + F: DataRef, + S: DataRef; +} + +impl<BE: Backend> Cmux<BE> for Module<BE> +where + Module<BE>: GLWEExternalProductInplace<BE> + VecZnxSub + VecZnxCopy + VecZnxNegateInplace + VecZnxAddInplace, +{ + fn cmux<O, T, F, S>( + &self, + out: &mut GLWECiphertext<O>, + t: &GLWECiphertext<T>, + f: &GLWECiphertext<F>, + s: &GGSWCiphertextPrepared<S, BE>, + scratch: &mut Scratch<BE>, + ) where + O: DataMut, + T: DataRef, + F: DataRef, + S: DataRef, + { + // let mut out: GLWECiphertext<&mut [u8]> = out.to_mut(); + out.sub(self, t, f); + out.external_product_inplace(self, s, scratch); + out.to_mut().add_inplace(self, f); + } +}
@@ -0,0 +1,241 @@
+#[cfg(test)] +use crate::tfhe::bdd_arithmetic::FheUintBlocksPrepDebug; +use crate::tfhe::{ + bdd_arithmetic::{FheUintBlocks, FheUintBlocksPrep, UnsignedInteger}, + blind_rotation::{BlindRotationAlgo, BlindRotationKey, BlindRotationKeyAlloc, BlindRotationKeyEncryptSk}, + circuit_bootstrapping::{ + CircuitBootstrappingKey, CircuitBootstrappingKeyEncryptSk, CircuitBootstrappingKeyLayout, + CircuitBootstrappingKeyPrepared, CirtuitBootstrappingExecute, + }, +}; +use poulpy_core::{ + TakeGGSW, TakeGLWECt, + layouts::{ + GLWESecret, GLWEToLWEKey, GLWEToLWEKeyLayout, LWECiphertext, LWESecret, + prepared::{GLWEToLWESwitchingKeyPrepared, Prepare, PrepareAlloc}, + }, +}; +use poulpy_hal::{ + api::{ + ScratchAvailable, SvpApplyDftToDft, SvpApplyDftToDftInplace, SvpPPolAlloc, SvpPPolAllocBytes, SvpPrepare, TakeScalarZnx, + TakeSvpPPol, TakeVecZnx, TakeVecZnxBig, TakeVecZnxDft, VecZnxAddInplace, VecZnxAddNormal, VecZnxAddScalarInplace, + VecZnxAutomorphism, VecZnxAutomorphismInplace, VecZnxBigAddSmallInplace, VecZnxBigNormalize, VecZnxBigNormalizeTmpBytes, + VecZnxDftAllocBytes, VecZnxDftApply, VecZnxFillUniform, VecZnxIdftApplyConsume, VecZnxIdftApplyTmpA, VecZnxNormalize, + VecZnxNormalizeInplace, VecZnxNormalizeTmpBytes, VecZnxRotate, VecZnxSub, VecZnxSubInplace, VecZnxSwitchRing, + VmpApplyDftToDft, VmpApplyDftToDftAdd, VmpApplyDftToDftTmpBytes, VmpPrepare, + }, + layouts::{Backend, Data, DataMut, DataRef, Module, Scratch}, + source::Source, +}; + +pub trait BDDKeyInfos { + fn cbt_infos(&self) -> CircuitBootstrappingKeyLayout; + fn ks_infos(&self) -> GLWEToLWEKeyLayout; +} + +#[derive(Debug, Clone, Copy)] +pub struct BDDKeyLayout { + pub cbt: CircuitBootstrappingKeyLayout, + pub ks: GLWEToLWEKeyLayout, +} + +impl BDDKeyInfos for BDDKeyLayout { + fn cbt_infos(&self) -> CircuitBootstrappingKeyLayout { + self.cbt + } + + fn ks_infos(&self) -> GLWEToLWEKeyLayout { + self.ks + } +} + +pub struct BDDKey<CBT, LWE, BRA> +where + CBT: Data, + LWE: Data, + BRA: BlindRotationAlgo, +{ + cbt: CircuitBootstrappingKey<CBT, BRA>, + ks: GLWEToLWEKey<LWE>, +} + +impl<BRA: BlindRotationAlgo> BDDKey<Vec<u8>, Vec<u8>, BRA> { + pub fn encrypt_sk<DLwe, DGlwe, A, BE: Backend>( + module: &Module<BE>, + sk_lwe: &LWESecret<DLwe>, + sk_glwe: &GLWESecret<DGlwe>, + infos: &A, + source_xa: &mut Source, + source_xe: &mut Source, + scratch: &mut Scratch<BE>, + ) -> Self + where + A: BDDKeyInfos, + DLwe: DataRef, + DGlwe: DataRef, + BlindRotationKey<Vec<u8>, BRA>: BlindRotationKeyAlloc + BlindRotationKeyEncryptSk<BE>, + Module<BE>: SvpApplyDftToDft<BE> + + VecZnxIdftApplyTmpA<BE> + + VecZnxAddScalarInplace + + VecZnxDftAllocBytes + + VecZnxBigNormalize<BE> + + VecZnxDftApply<BE> + + SvpApplyDftToDftInplace<BE> + + VecZnxIdftApplyConsume<BE> + + VecZnxNormalizeTmpBytes + + VecZnxFillUniform + + VecZnxSubInplace + + VecZnxAddInplace + + VecZnxNormalizeInplace<BE> + + VecZnxAddNormal + + VecZnxNormalize<BE> + + VecZnxSub + + SvpPrepare<BE> + + VecZnxSwitchRing + + SvpPPolAllocBytes + + SvpPPolAlloc<BE> + + VecZnxAutomorphism + + VecZnxAutomorphismInplace<BE>, + Scratch<BE>: TakeVecZnxDft<BE> + ScratchAvailable + TakeVecZnx + TakeScalarZnx + TakeSvpPPol<BE> + TakeVecZnxBig<BE>, + { + let mut ks: GLWEToLWEKey<Vec<u8>> = GLWEToLWEKey::alloc(&infos.ks_infos()); + ks.encrypt_sk(module, sk_lwe, sk_glwe, source_xa, source_xe, scratch); + + Self { + cbt: CircuitBootstrappingKey::encrypt_sk( + module, + sk_lwe, + sk_glwe, + &infos.cbt_infos(), + source_xa, + source_xe, + scratch, + ), + ks, + } + } +} + +pub struct BDDKeyPrepared<CBT, LWE, BRA, BE> +where + CBT: Data, + LWE: Data, + BRA: BlindRotationAlgo, + BE: Backend, +{ + cbt: CircuitBootstrappingKeyPrepared<CBT, BRA, BE>, + ks: GLWEToLWESwitchingKeyPrepared<LWE, BE>, +} + +impl<CBT: DataMut, LWE: DataMut, BRA: BlindRotationAlgo, BE: Backend> PrepareAlloc<BE, BDDKeyPrepared<CBT, LWE, BRA, BE>> + for BDDKey<CBT, LWE, BRA> +where + CircuitBootstrappingKey<CBT, BRA>: PrepareAlloc<BE, CircuitBootstrappingKeyPrepared<CBT, BRA, BE>>, + GLWEToLWEKey<LWE>: PrepareAlloc<BE, GLWEToLWESwitchingKeyPrepared<LWE, BE>>, +{ + fn prepare_alloc(&self, module: &Module<BE>, scratch: &mut Scratch<BE>) -> BDDKeyPrepared<CBT, LWE, BRA, BE> { + BDDKeyPrepared { + cbt: self.cbt.prepare_alloc(module, scratch), + ks: self.ks.prepare_alloc(module, scratch), + } + } +} + +pub trait FheUintPrepare<BE: Backend, OUT, IN> { + fn prepare(&self, module: &Module<BE>, out: &mut OUT, bits: &IN, scratch: &mut Scratch<BE>); +} + +impl<CBT, OUT, IN, LWE, BRA, BE, T> FheUintPrepare<BE, FheUintBlocksPrep<OUT, BE, T>, FheUintBlocks<IN, T>> + for BDDKeyPrepared<CBT, LWE, BRA, BE> +where + T: UnsignedInteger, + CBT: DataRef, + OUT: DataMut, + IN: DataRef, + LWE: DataRef, + BRA: BlindRotationAlgo, + BE: Backend, + Module<BE>: VmpPrepare<BE> + + VecZnxRotate + + VecZnxDftAllocBytes + + VmpApplyDftToDftTmpBytes + + VecZnxBigNormalizeTmpBytes + + VmpApplyDftToDft<BE> + + VmpApplyDftToDftAdd<BE> + + VecZnxDftApply<BE> + + VecZnxIdftApplyConsume<BE> + + VecZnxBigAddSmallInplace<BE> + + VecZnxBigNormalize<BE> + + VecZnxNormalize<BE> + + VecZnxNormalizeTmpBytes, + Scratch<BE>: ScratchAvailable + TakeVecZnxDft<BE> + TakeGLWECt + TakeVecZnx + TakeGGSW, + CircuitBootstrappingKeyPrepared<CBT, BRA, BE>: CirtuitBootstrappingExecute<BE>, +{ + fn prepare( + &self, + module: &Module<BE>, + out: &mut FheUintBlocksPrep<OUT, BE, T>, + bits: &FheUintBlocks<IN, T>, + scratch: &mut Scratch<BE>, + ) { + #[cfg(debug_assertions)] + { + assert_eq!(out.blocks.len(), bits.blocks.len()); + } + let mut lwe: LWECiphertext<Vec<u8>> = LWECiphertext::alloc(&bits.blocks[0]); //TODO: add TakeLWE + let (mut tmp_ggsw, scratch_1) = scratch.take_ggsw(out); + for (dst, src) in out.blocks.iter_mut().zip(bits.blocks.iter()) { + lwe.from_glwe(module, src, &self.ks, scratch_1); + self.cbt + .execute_to_constant(module, &mut tmp_ggsw, &lwe, 1, 1, scratch_1); + dst.prepare(module, &tmp_ggsw, scratch_1); + } + } +} + +#[cfg(test)] +impl<CBT, OUT, IN, LWE, BRA, BE, T> FheUintPrepare<BE, FheUintBlocksPrepDebug<OUT, T>, FheUintBlocks<IN, T>> + for BDDKeyPrepared<CBT, LWE, BRA, BE> +where + T: UnsignedInteger, + CBT: DataRef, + OUT: DataMut, + IN: DataRef, + LWE: DataRef, + BRA: BlindRotationAlgo, + BE: Backend, + Module<BE>: VmpPrepare<BE> + + VecZnxRotate + + VecZnxDftAllocBytes + + VmpApplyDftToDftTmpBytes + + VecZnxBigNormalizeTmpBytes + + VmpApplyDftToDft<BE> + + VmpApplyDftToDftAdd<BE> + + VecZnxDftApply<BE> + + VecZnxIdftApplyConsume<BE> + + VecZnxBigAddSmallInplace<BE> + + VecZnxBigNormalize<BE> + + VecZnxNormalize<BE> + + VecZnxNormalizeTmpBytes, + Scratch<BE>: ScratchAvailable + TakeVecZnxDft<BE> + TakeGLWECt + TakeVecZnx + TakeGGSW, + CircuitBootstrappingKeyPrepared<CBT, BRA, BE>: CirtuitBootstrappingExecute<BE>, +{ + fn prepare( + &self, + module: &Module<BE>, + out: &mut FheUintBlocksPrepDebug<OUT, T>, + bits: &FheUintBlocks<IN, T>, + scratch: &mut Scratch<BE>, + ) { + #[cfg(debug_assertions)] + { + assert_eq!(out.blocks.len(), bits.blocks.len()); + } + let mut lwe: LWECiphertext<Vec<u8>> = LWECiphertext::alloc(&bits.blocks[0]); //TODO: add TakeLWE + for (dst, src) in out.blocks.iter_mut().zip(bits.blocks.iter()) { + lwe.from_glwe(module, src, &self.ks, scratch); + self.cbt + .execute_to_constant(module, dst, &lwe, 1, 1, scratch); + } + } +}
@@ -0,0 +1,86 @@
+mod bdd_2w_to_1w; +mod ciphertexts; +mod circuits; +mod eval; +mod key; +mod parameters; + +pub use bdd_2w_to_1w::*; +pub use ciphertexts::*; +pub(crate) use circuits::*; +pub(crate) use eval::*; +pub use key::*; + +#[cfg(test)] +pub(crate) use parameters::*; + +#[cfg(test)] +mod test; + +pub trait UnsignedInteger: Copy + 'static { + const WORD_SIZE: usize; +} + +impl UnsignedInteger for u8 { + const WORD_SIZE: usize = 8; +} +impl UnsignedInteger for u16 { + const WORD_SIZE: usize = 16; +} +impl UnsignedInteger for u32 { + const WORD_SIZE: usize = 32; +} +impl UnsignedInteger for u64 { + const WORD_SIZE: usize = 64; +} +impl UnsignedInteger for u128 { + const WORD_SIZE: usize = 128; +} + +pub trait ToBits { + fn bit(&self, i: usize) -> u8; +} + +macro_rules! impl_tobits { + ($($t:ty),*) => { + $( + impl ToBits for $t { + fn bit(&self, i: usize) -> u8 { + if i >= (std::mem::size_of::<$t>() * 8) { + panic!("bit index {} out of range for {}", i, stringify!($t)); + } + ((self >> i) & 1) as u8 + } + } + )* + }; +} + +impl_tobits!(u8, u16, u32, u64, u128); + +pub trait FromBits: Sized { + fn from_bits(bits: &[u8]) -> Self; +} + +macro_rules! impl_from_bits { + ($($t:ty),*) => { + $( + impl FromBits for $t { + fn from_bits(bits: &[u8]) -> Self { + let mut value: $t = 0; + let max_bits = std::mem::size_of::<$t>() * 8; + let n = bits.len().min(max_bits); + + for (i, &bit) in bits.iter().take(n).enumerate() { + if bit != 0 { + value |= 1 << i; + } + } + value + } + } + )* + }; +} + +impl_from_bits!(u8, u16, u32, u64, u128);
@@ -0,0 +1,80 @@
+#[cfg(test)] +use poulpy_core::layouts::{ + Base2K, Degree, Dnum, Dsize, GGLWEAutomorphismKeyLayout, GGLWETensorKeyLayout, GGSWCiphertextLayout, GLWECiphertextLayout, + GLWEToLWEKeyLayout, Rank, TorusPrecision, +}; + +#[cfg(test)] +use crate::tfhe::{ + bdd_arithmetic::BDDKeyLayout, blind_rotation::BlindRotationKeyLayout, circuit_bootstrapping::CircuitBootstrappingKeyLayout, +}; + +#[cfg(test)] +pub(crate) const TEST_N_GLWE: u32 = 512; +#[cfg(test)] +pub(crate) const TEST_N_LWE: u32 = 77; +#[cfg(test)] +pub(crate) const TEST_BASE2K: u32 = 13; +#[cfg(test)] +pub(crate) const TEST_K_GLWE: u32 = 26; +#[cfg(test)] +pub(crate) const TEST_K_GGSW: u32 = 39; +#[cfg(test)] +pub(crate) const TEST_BLOCK_SIZE: u32 = 7; +#[cfg(test)] +pub(crate) const TEST_RANK: u32 = 2; + +#[cfg(test)] +pub(crate) static TEST_GLWE_INFOS: GLWECiphertextLayout = GLWECiphertextLayout { + n: Degree(TEST_N_GLWE), + base2k: Base2K(TEST_BASE2K), + k: TorusPrecision(TEST_K_GLWE), + rank: Rank(TEST_RANK), +}; + +#[cfg(test)] +pub(crate) static TEST_GGSW_INFOS: GGSWCiphertextLayout = GGSWCiphertextLayout { + n: Degree(TEST_N_GLWE), + base2k: Base2K(TEST_BASE2K), + k: TorusPrecision(TEST_K_GGSW), + rank: Rank(TEST_RANK), + dnum: Dnum(2), + dsize: Dsize(1), +}; + +#[cfg(test)] +pub(crate) static TEST_BDD_KEY_LAYOUT: BDDKeyLayout = BDDKeyLayout { + cbt: CircuitBootstrappingKeyLayout { + layout_brk: BlindRotationKeyLayout { + n_glwe: Degree(TEST_N_GLWE), + n_lwe: Degree(TEST_N_LWE), + base2k: Base2K(TEST_BASE2K), + k: TorusPrecision(52), + dnum: Dnum(3), + rank: Rank(TEST_RANK), + }, + layout_atk: GGLWEAutomorphismKeyLayout { + n: Degree(TEST_N_GLWE), + base2k: Base2K(TEST_BASE2K), + k: TorusPrecision(52), + rank: Rank(TEST_RANK), + dnum: Dnum(3), + dsize: Dsize(1), + }, + layout_tsk: GGLWETensorKeyLayout { + n: Degree(TEST_N_GLWE), + base2k: Base2K(TEST_BASE2K), + k: TorusPrecision(52), + rank: Rank(TEST_RANK), + dnum: Dnum(3), + dsize: Dsize(1), + }, + }, + ks: GLWEToLWEKeyLayout { + n: Degree(TEST_N_GLWE), + base2k: Base2K(TEST_BASE2K), + k: TorusPrecision(39), + rank_in: Rank(TEST_RANK), + dnum: Dnum(2), + }, +};
@@ -0,0 +1,224 @@
+use std::time::Instant; + +use poulpy_backend::FFT64Ref; +use poulpy_core::{ + TakeGGSW, TakeGLWEPt, + layouts::{ + GGSWCiphertextLayout, GLWECiphertextLayout, GLWESecret, LWEInfos, LWESecret, + prepared::{GLWESecretPrepared, PrepareAlloc}, + }, +}; +use poulpy_hal::{ + api::{ + ModuleNew, ScratchAvailable, ScratchOwnedAlloc, ScratchOwnedBorrow, SvpApplyDftToDft, SvpApplyDftToDftInplace, + SvpPPolAlloc, SvpPPolAllocBytes, SvpPrepare, TakeScalarZnx, TakeSlice, TakeVecZnx, TakeVecZnxBig, TakeVecZnxDft, + VecZnxAddInplace, VecZnxAddNormal, VecZnxAddScalarInplace, VecZnxAutomorphism, VecZnxAutomorphismInplace, + VecZnxBigAddInplace, VecZnxBigAddSmallInplace, VecZnxBigAlloc, VecZnxBigAllocBytes, VecZnxBigAutomorphismInplace, + VecZnxBigNormalize, VecZnxBigNormalizeTmpBytes, VecZnxBigSubSmallNegateInplace, VecZnxCopy, VecZnxDftAddInplace, + VecZnxDftAlloc, VecZnxDftAllocBytes, VecZnxDftApply, VecZnxDftCopy, VecZnxFillUniform, VecZnxIdftApplyConsume, + VecZnxIdftApplyTmpA, VecZnxNegateInplace, VecZnxNormalize, VecZnxNormalizeInplace, VecZnxNormalizeTmpBytes, VecZnxRotate, + VecZnxRotateInplace, VecZnxRotateInplaceTmpBytes, VecZnxRshInplace, VecZnxSub, VecZnxSubInplace, VecZnxSwitchRing, + VmpApplyDftToDft, VmpApplyDftToDftAdd, VmpApplyDftToDftTmpBytes, VmpPMatAlloc, VmpPrepare, ZnAddNormal, ZnFillUniform, + ZnNormalizeInplace, + }, + layouts::{Backend, Module, Scratch, ScratchOwned}, + oep::{ + ScratchAvailableImpl, ScratchOwnedAllocImpl, ScratchOwnedBorrowImpl, TakeMatZnxImpl, TakeScalarZnxImpl, TakeSvpPPolImpl, + TakeVecZnxBigImpl, TakeVecZnxDftImpl, TakeVecZnxDftSliceImpl, TakeVecZnxImpl, TakeVecZnxSliceImpl, + }, + source::Source, +}; +use rand::RngCore; + +use crate::tfhe::{ + bdd_arithmetic::{ + Add, BDDKey, BDDKeyLayout, BDDKeyPrepared, FheUintBlocks, FheUintBlocksPrep, FheUintBlocksPrepDebug, Sub, + TEST_BDD_KEY_LAYOUT, TEST_BLOCK_SIZE, TEST_GGSW_INFOS, TEST_GLWE_INFOS, TEST_N_LWE, + }, + blind_rotation::{ + BlincRotationExecute, BlindRotationAlgo, BlindRotationKey, BlindRotationKeyAlloc, BlindRotationKeyEncryptSk, + BlindRotationKeyPrepared, CGGI, + }, +}; + +#[test] +fn test_bdd_2w_to_1w_fft64_ref() { + test_bdd_2w_to_1w::<FFT64Ref, CGGI>() +} + +fn test_bdd_2w_to_1w<BE: Backend, BRA: BlindRotationAlgo>() +where + Module<BE>: ModuleNew<BE> + SvpPPolAlloc<BE> + SvpPrepare<BE> + VmpPMatAlloc<BE>, + ScratchOwned<BE>: ScratchOwnedAlloc<BE> + ScratchOwnedBorrow<BE>, + Module<BE>: VecZnxAddScalarInplace + + VecZnxDftAllocBytes + + VecZnxBigNormalize<BE> + + VecZnxDftApply<BE> + + SvpApplyDftToDftInplace<BE> + + VecZnxIdftApplyConsume<BE> + + VecZnxNormalizeTmpBytes + + VecZnxFillUniform + + VecZnxSubInplace + + VecZnxAddInplace + + VecZnxNormalizeInplace<BE> + + VecZnxAddNormal + + VecZnxNormalize<BE> + + VecZnxSub + + VmpPrepare<BE>, + Scratch<BE>: TakeVecZnxDft<BE> + ScratchAvailable + TakeVecZnx + TakeGGSW + TakeScalarZnx + TakeSlice, + Module<BE>: VecZnxCopy + VecZnxNegateInplace + VmpApplyDftToDftTmpBytes + VmpApplyDftToDft<BE> + VmpApplyDftToDftAdd<BE>, + Module<BE>: VecZnxBigAddInplace<BE> + VecZnxBigAddSmallInplace<BE> + VecZnxBigNormalize<BE>, + Scratch<BE>: TakeVecZnxDft<BE> + TakeVecZnxBig<BE> + TakeGLWEPt<BE>, + Module<BE>: VecZnxAutomorphism + + VecZnxSwitchRing + + VecZnxBigAllocBytes + + VecZnxIdftApplyTmpA<BE> + + SvpApplyDftToDft<BE> + + VecZnxBigAlloc<BE> + + VecZnxDftAlloc<BE> + + VecZnxBigNormalizeTmpBytes + + SvpPPolAllocBytes + + VecZnxRotateInplace<BE> + + VecZnxBigAutomorphismInplace<BE> + + VecZnxRshInplace<BE> + + VecZnxDftCopy<BE> + + VecZnxAutomorphismInplace<BE> + + VecZnxBigSubSmallNegateInplace<BE> + + VecZnxRotateInplaceTmpBytes + + VecZnxBigAllocBytes + + VecZnxDftAddInplace<BE> + + VecZnxRotate + + ZnFillUniform + + ZnAddNormal + + ZnNormalizeInplace<BE>, + BE: Backend + + ScratchOwnedAllocImpl<BE> + + ScratchOwnedBorrowImpl<BE> + + TakeVecZnxDftImpl<BE> + + ScratchAvailableImpl<BE> + + TakeVecZnxImpl<BE> + + TakeScalarZnxImpl<BE> + + TakeSvpPPolImpl<BE> + + TakeVecZnxBigImpl<BE> + + TakeVecZnxDftSliceImpl<BE> + + TakeMatZnxImpl<BE> + + TakeVecZnxSliceImpl<BE>, + BlindRotationKey<Vec<u8>, BRA>: PrepareAlloc<BE, BlindRotationKeyPrepared<Vec<u8>, BRA, BE>>, + BlindRotationKeyPrepared<Vec<u8>, BRA, BE>: BlincRotationExecute<BE>, + BlindRotationKey<Vec<u8>, BRA>: BlindRotationKeyAlloc + BlindRotationKeyEncryptSk<BE>, +{ + let glwe_infos: GLWECiphertextLayout = TEST_GLWE_INFOS; + let ggsw_infos: GGSWCiphertextLayout = TEST_GGSW_INFOS; + + let n_glwe: usize = glwe_infos.n().into(); + + let module: Module<BE> = Module::<BE>::new(n_glwe as u64); + let mut source: Source = Source::new([6u8; 32]); + let mut source_xs: Source = Source::new([1u8; 32]); + let mut source_xa: Source = Source::new([2u8; 32]); + let mut source_xe: Source = Source::new([3u8; 32]); + + let mut scratch: ScratchOwned<BE> = ScratchOwned::alloc(1 << 22); + + let mut sk_glwe: GLWESecret<Vec<u8>> = GLWESecret::alloc(&glwe_infos); + sk_glwe.fill_ternary_prob(0.5, &mut source_xs); + let sk_glwe_prep: GLWESecretPrepared<Vec<u8>, BE> = sk_glwe.prepare_alloc(&module, scratch.borrow()); + + let a: u32 = source.next_u32(); + let b: u32 = source.next_u32(); + + println!("a: {a}"); + println!("b: {b}"); + + let mut a_enc_prep: FheUintBlocksPrep<Vec<u8>, BE, u32> = FheUintBlocksPrep::<Vec<u8>, BE, u32>::alloc(&module, &ggsw_infos); + let mut b_enc_prep: FheUintBlocksPrep<Vec<u8>, BE, u32> = FheUintBlocksPrep::<Vec<u8>, BE, u32>::alloc(&module, &ggsw_infos); + let mut c_enc: FheUintBlocks<Vec<u8>, u32> = FheUintBlocks::<Vec<u8>, u32>::alloc(&module, &glwe_infos); + let mut c_enc_prep_debug: FheUintBlocksPrepDebug<Vec<u8>, u32> = + FheUintBlocksPrepDebug::<Vec<u8>, u32>::alloc(&module, &ggsw_infos); + let mut c_enc_prep: FheUintBlocksPrep<Vec<u8>, BE, u32> = FheUintBlocksPrep::<Vec<u8>, BE, u32>::alloc(&module, &ggsw_infos); + + a_enc_prep.encrypt_sk( + &module, + a, + &sk_glwe_prep, + &mut source_xa, + &mut source_xe, + scratch.borrow(), + ); + b_enc_prep.encrypt_sk( + &module, + b, + &sk_glwe_prep, + &mut source_xa, + &mut source_xe, + scratch.borrow(), + ); + + let start: Instant = Instant::now(); + c_enc.sub(&module, &a_enc_prep, &b_enc_prep, scratch.borrow()); + + let duration: std::time::Duration = start.elapsed(); + println!("add: {} ms", duration.as_millis()); + + println!( + "have: {}", + c_enc.decrypt(&module, &sk_glwe_prep, scratch.borrow()) + ); + println!("want: {}", a.wrapping_sub(b)); + println!( + "noise: {:?}", + c_enc.noise(&module, &sk_glwe_prep, a.wrapping_sub(b), scratch.borrow()) + ); + + let n_lwe: u32 = TEST_N_LWE; + let block_size: u32 = TEST_BLOCK_SIZE; + + let mut sk_lwe: LWESecret<Vec<u8>> = LWESecret::alloc(n_lwe.into()); + sk_lwe.fill_binary_block(block_size as usize, &mut source_xs); + + let bdd_key_infos: BDDKeyLayout = TEST_BDD_KEY_LAYOUT; + + let now: Instant = Instant::now(); + let bdd_key: BDDKey<Vec<u8>, Vec<u8>, BRA> = BDDKey::encrypt_sk( + &module, + &sk_lwe, + &sk_glwe, + &bdd_key_infos, + &mut source_xa, + &mut source_xe, + scratch.borrow(), + ); + let bdd_key_prepared: BDDKeyPrepared<Vec<u8>, Vec<u8>, BRA, BE> = bdd_key.prepare_alloc(&module, scratch.borrow()); + println!("BDD-KGEN: {} ms", now.elapsed().as_millis()); + + let now: Instant = Instant::now(); + c_enc_prep_debug.prepare(&module, &c_enc, &bdd_key_prepared, scratch.borrow()); + println!("CBT: {} ms", now.elapsed().as_millis()); + + c_enc_prep_debug.noise(&module, &sk_glwe_prep, a.wrapping_sub(b)); + + let now: Instant = Instant::now(); + c_enc_prep.prepare(&module, &c_enc, &bdd_key_prepared, scratch.borrow()); + println!("CBT: {} ms", now.elapsed().as_millis()); + + let start: Instant = Instant::now(); + c_enc.add(&module, &c_enc_prep, &b_enc_prep, scratch.borrow()); + + let duration: std::time::Duration = start.elapsed(); + println!("add: {} ms", duration.as_millis()); + + println!( + "have: {}", + c_enc.decrypt(&module, &sk_glwe_prep, scratch.borrow()) + ); + println!("want: {}", b.wrapping_add(a.wrapping_sub(b))); + println!( + "noise: {:?}", + c_enc.noise( + &module, + &sk_glwe_prep, + b.wrapping_add(a.wrapping_sub(b)), + scratch.borrow() + ) + ); +}
@@ -42,13 +42,13 @@ let brk_size: usize = brk_infos.size();
if block_size > 1 { let cols: usize = (brk_infos.rank() + 1).into(); - let rows: usize = brk_infos.rows().into(); - let acc_dft: usize = module.vec_znx_dft_alloc_bytes(cols, rows) * extension_factor; + let dnum: usize = brk_infos.dnum().into(); + let acc_dft: usize = module.vec_znx_dft_alloc_bytes(cols, dnum) * extension_factor; let acc_big: usize = module.vec_znx_big_alloc_bytes(1, brk_size); let vmp_res: usize = module.vec_znx_dft_alloc_bytes(cols, brk_size) * extension_factor; let vmp_xai: usize = module.vec_znx_dft_alloc_bytes(1, brk_size); let acc_dft_add: usize = vmp_res; - let vmp: usize = module.vmp_apply_dft_to_dft_tmp_bytes(brk_size, rows, rows, 2, 2, brk_size); // GGSW product: (1 x 2) x (2 x 2) + let vmp: usize = module.vmp_apply_dft_to_dft_tmp_bytes(brk_size, dnum, dnum, 2, 2, brk_size); // GGSW product: (1 x 2) x (2 x 2) let acc: usize = if extension_factor > 1 { VecZnx::alloc_bytes(module.n(), cols, glwe_infos.size()) * extension_factor } else {@@ -158,11 +158,11 @@ {
let n_glwe: usize = brk.n_glwe().into(); let extension_factor: usize = lut.extension_factor(); let base2k: usize = res.base2k().into(); - let rows: usize = brk.rows().into(); + let dnum: usize = brk.dnum().into(); let cols: usize = (res.rank() + 1).into(); let (mut acc, scratch_1) = scratch.take_vec_znx_slice(extension_factor, n_glwe, cols, res.size()); - let (mut acc_dft, scratch_2) = scratch_1.take_vec_znx_dft_slice(extension_factor, n_glwe, cols, rows); + let (mut acc_dft, scratch_2) = scratch_1.take_vec_znx_dft_slice(extension_factor, n_glwe, cols, dnum); let (mut vmp_res, scratch_3) = scratch_2.take_vec_znx_dft_slice(extension_factor, n_glwe, cols, brk.size()); let (mut acc_add_dft, scratch_4) = scratch_3.take_vec_znx_dft_slice(extension_factor, n_glwe, cols, brk.size()); let (mut vmp_xai, scratch_5) = scratch_4.take_vec_znx_dft(n_glwe, 1, brk.size());@@ -328,7 +328,7 @@ let mut out_mut: GLWECiphertext<&mut [u8]> = res.to_mut();
let lwe_ref: LWECiphertext<&[u8]> = lwe.to_ref(); let two_n: usize = n_glwe << 1; let base2k: usize = brk.base2k().into(); - let rows: usize = brk.rows().into(); + let dnum: usize = brk.dnum().into(); let cols: usize = (out_mut.rank() + 1).into();@@ -351,7 +351,7 @@ let block_size: usize = brk.block_size();
// ACC + [sum DFT(X^ai -1) * (DFT(ACC) x BRKi)] - let (mut acc_dft, scratch_1) = scratch.take_vec_znx_dft(n_glwe, cols, rows); + let (mut acc_dft, scratch_1) = scratch.take_vec_znx_dft(n_glwe, cols, dnum); let (mut vmp_res, scratch_2) = scratch_1.take_vec_znx_dft(n_glwe, cols, brk.size()); let (mut acc_add_dft, scratch_3) = scratch_2.take_vec_znx_dft(n_glwe, cols, brk.size()); let (mut vmp_xai, scratch_4) = scratch_3.take_vec_znx_dft(n_glwe, 1, brk.size());
@@ -8,7 +8,7 @@
use poulpy_core::{ Distribution, layouts::{ - Base2K, Degree, Digits, GGSWCiphertext, GGSWInfos, GLWEInfos, LWEInfos, LWESecret, Rank, Rows, TorusPrecision, + Base2K, Degree, Dnum, Dsize, GGSWCiphertext, GGSWInfos, GLWEInfos, LWEInfos, LWESecret, Rank, TorusPrecision, prepared::GLWESecretPrepared, }, };@@ -23,7 +23,7 @@ pub n_glwe: Degree,
pub n_lwe: Degree, pub base2k: Base2K, pub k: TorusPrecision, - pub rows: Rows, + pub dnum: Dnum, pub rank: Rank, }@@ -38,12 +38,12 @@ }
} impl GGSWInfos for BlindRotationKeyLayout { - fn digits(&self) -> Digits { - Digits(1) + fn dsize(&self) -> Dsize { + Dsize(1) } - fn rows(&self) -> Rows { - self.rows + fn dnum(&self) -> Dnum { + self.dnum } }@@ -221,11 +221,11 @@ self.keys[0].rank()
} } impl<D: DataRef, BRT: BlindRotationAlgo> GGSWInfos for BlindRotationKey<D, BRT> { - fn digits(&self) -> poulpy_core::layouts::Digits { - Digits(1) + fn dsize(&self) -> poulpy_core::layouts::Dsize { + Dsize(1) } - fn rows(&self) -> Rows { - self.keys[0].rows() + fn dnum(&self) -> Dnum { + self.keys[0].dnum() } }
@@ -8,7 +8,7 @@
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; use poulpy_core::{ Distribution, - layouts::{Base2K, Degree, Digits, GGSWInfos, GLWEInfos, LWEInfos, TorusPrecision, compressed::GGSWCiphertextCompressed}, + layouts::{Base2K, Degree, Dsize, GGSWInfos, GLWEInfos, LWEInfos, TorusPrecision, compressed::GGSWCiphertextCompressed}, }; use crate::tfhe::blind_rotation::{BlindRotationAlgo, BlindRotationKeyInfos};@@ -128,12 +128,12 @@ }
} impl<D: DataRef, BRA: BlindRotationAlgo> GGSWInfos for BlindRotationKeyCompressed<D, BRA> { - fn rows(&self) -> poulpy_core::layouts::Rows { - self.keys[0].rows() + fn dnum(&self) -> poulpy_core::layouts::Dnum { + self.keys[0].dnum() } - fn digits(&self) -> poulpy_core::layouts::Digits { - Digits(1) + fn dsize(&self) -> poulpy_core::layouts::Dsize { + Dsize(1) } }
@@ -8,7 +8,7 @@
use poulpy_core::{ Distribution, layouts::{ - Base2K, Degree, Digits, GGSWInfos, GLWEInfos, LWEInfos, Rank, Rows, TorusPrecision, + Base2K, Degree, Dnum, Dsize, GGSWInfos, GLWEInfos, LWEInfos, Rank, TorusPrecision, prepared::{GGSWCiphertextPrepared, Prepare, PrepareAlloc}, }, };@@ -63,12 +63,12 @@ self.data[0].rank()
} } impl<D: Data, BRT: BlindRotationAlgo, B: Backend> GGSWInfos for BlindRotationKeyPrepared<D, BRT, B> { - fn digits(&self) -> poulpy_core::layouts::Digits { - Digits(1) + fn dsize(&self) -> poulpy_core::layouts::Dsize { + Dsize(1) } - fn rows(&self) -> Rows { - self.data[0].rows() + fn dnum(&self) -> Dnum { + self.data[0].dnum() } }
@@ -1,9 +1,10 @@
use poulpy_hal::{ api::{ - ScratchOwnedAlloc, ScratchOwnedBorrow, VecZnxCopy, VecZnxNormalizeInplace, VecZnxNormalizeTmpBytes, VecZnxRotateInplace, - VecZnxRotateInplaceTmpBytes, VecZnxSwitchRing, + ScratchOwnedAlloc, ScratchOwnedBorrow, TakeSlice, VecZnxCopy, VecZnxNormalizeInplace, VecZnxNormalizeTmpBytes, + VecZnxRotateInplace, VecZnxRotateInplaceTmpBytes, VecZnxSwitchRing, }, - layouts::{Backend, Module, ScratchOwned, VecZnx, ZnxInfos, ZnxViewMut}, + layouts::{Backend, Module, Scratch, ScratchOwned, VecZnx, ZnxInfos, ZnxViewMut}, + reference::{vec_znx::vec_znx_rotate_inplace, znx::ZnxRef}, }; #[derive(Debug, Clone, Copy)]@@ -76,12 +77,13 @@ + VecZnxSwitchRing
+ VecZnxCopy + VecZnxRotateInplaceTmpBytes, ScratchOwned<B>: ScratchOwnedAlloc<B> + ScratchOwnedBorrow<B>, + Scratch<B>: TakeSlice, { assert!(f.len() <= module.n()); let base2k: usize = self.base2k; - let mut scratch: ScratchOwned<B> = ScratchOwned::alloc(module.vec_znx_normalize_tmp_bytes()); + let mut scratch: ScratchOwned<B> = ScratchOwned::alloc(module.vec_znx_normalize_tmp_bytes() | (self.domain_size() << 3)); // Get the number minimum limb to store the message modulus let limbs: usize = k.div_ceil(base2k);@@ -128,19 +130,21 @@
// Rotates half the step to the left if self.extension_factor() > 1 { - (0..self.extension_factor()).for_each(|i| { + let (tmp, _) = scratch.borrow().take_slice(lut_full.n()); + + for i in 0..self.extension_factor() { module.vec_znx_switch_ring(&mut self.data[i], 0, &lut_full, 0); if i < self.extension_factor() { - module.vec_znx_rotate_inplace(-1, &mut lut_full, 0, scratch.borrow()); + vec_znx_rotate_inplace::<_, ZnxRef>(-1, &mut lut_full, 0, tmp); } - }); + } } else { module.vec_znx_copy(&mut self.data[0], 0, &lut_full, 0); } - self.data.iter_mut().for_each(|a| { + for a in self.data.iter_mut() { module.vec_znx_normalize_inplace(self.base2k, a, 0, scratch.borrow()); - }); + } self.rotate(module, -(drift as i64));
@@ -11,7 +11,7 @@ ZnFillUniform, ZnNormalizeInplace,
}, layouts::{Backend, Module, ScratchOwned, ZnxView}, oep::{ - ScratchAvailableImpl, ScratchOwnedAllocImpl, ScratchOwnedBorrowImpl, TakeVecZnxBigImpl, TakeVecZnxDftImpl, + ScratchAvailableImpl, ScratchOwnedAllocImpl, ScratchOwnedBorrowImpl, TakeSliceImpl, TakeVecZnxBigImpl, TakeVecZnxDftImpl, TakeVecZnxDftSliceImpl, TakeVecZnxImpl, TakeVecZnxSliceImpl, VecZnxBigAllocBytesImpl, VecZnxDftAllocBytesImpl, }, source::Source,@@ -82,7 +82,8 @@ + TakeVecZnxBigImpl<B>
+ TakeVecZnxDftSliceImpl<B> + ScratchAvailableImpl<B> + TakeVecZnxImpl<B> - + TakeVecZnxSliceImpl<B>, + + TakeVecZnxSliceImpl<B> + + TakeSliceImpl<B>, { let n_glwe: usize = module.n(); let base2k: usize = 19;@@ -106,7 +107,7 @@ n_glwe: n_glwe.into(),
n_lwe: n_lwe.into(), base2k: base2k.into(), k: k_brk.into(), - rows: rows_brk.into(), + dnum: rows_brk.into(), rank: rank.into(), };
@@ -6,7 +6,7 @@ VecZnxCopy, VecZnxNormalizeInplace, VecZnxNormalizeTmpBytes, VecZnxRotateInplace, VecZnxRotateInplaceTmpBytes,
VecZnxSwitchRing, }, layouts::{Backend, Module}, - oep::{ScratchOwnedAllocImpl, ScratchOwnedBorrowImpl}, + oep::{ScratchOwnedAllocImpl, ScratchOwnedBorrowImpl, TakeSliceImpl}, }; use crate::tfhe::blind_rotation::{DivRound, LookUpTable};@@ -19,7 +19,7 @@ + VecZnxNormalizeTmpBytes
+ VecZnxSwitchRing + VecZnxCopy + VecZnxRotateInplaceTmpBytes, - B: Backend + ScratchOwnedAllocImpl<B> + ScratchOwnedBorrowImpl<B>, + B: Backend + ScratchOwnedAllocImpl<B> + ScratchOwnedBorrowImpl<B> + TakeSliceImpl<B>, { let base2k: usize = 20; let k_lut: usize = 40;@@ -59,7 +59,7 @@ + VecZnxNormalizeTmpBytes
+ VecZnxSwitchRing + VecZnxCopy + VecZnxRotateInplaceTmpBytes, - B: Backend + ScratchOwnedAllocImpl<B> + ScratchOwnedBorrowImpl<B>, + B: Backend + ScratchOwnedAllocImpl<B> + ScratchOwnedBorrowImpl<B> + TakeSliceImpl<B>, { let base2k: usize = 20; let k_lut: usize = 40;
@@ -11,7 +11,7 @@ n_glwe: 256_u32.into(),
n_lwe: 64_usize.into(), base2k: 12_usize.into(), k: 54_usize.into(), - rows: 2_usize.into(), + dnum: 2_usize.into(), rank: 2_usize.into(), };@@ -26,7 +26,7 @@ n_glwe: 256_u32.into(),
n_lwe: 64_usize.into(), base2k: 12_usize.into(), k: 54_usize.into(), - rows: 2_usize.into(), + dnum: 2_usize.into(), rank: 2_usize.into(), };
@@ -2,7 +2,7 @@ use std::collections::HashMap;
use poulpy_hal::{ api::{ - ScratchAvailable, TakeMatZnx, TakeVecZnx, TakeVecZnxBig, TakeVecZnxDft, TakeVecZnxDftSlice, TakeVecZnxSlice, + ScratchAvailable, TakeMatZnx, TakeSlice, TakeVecZnx, TakeVecZnxBig, TakeVecZnxDft, TakeVecZnxDftSlice, TakeVecZnxSlice, VecZnxAddInplace, VecZnxAutomorphismInplace, VecZnxBigAddSmallInplace, VecZnxBigAllocBytes, VecZnxBigAutomorphismInplace, VecZnxBigNormalize, VecZnxBigNormalizeTmpBytes, VecZnxBigSubSmallNegateInplace, VecZnxCopy, VecZnxDftAddInplace, VecZnxDftAllocBytes, VecZnxDftApply, VecZnxDftCopy, VecZnxIdftApplyConsume, VecZnxIdftApplyTmpA, VecZnxNegateInplace,@@ -16,9 +16,10 @@ };
use poulpy_core::{ GLWEOperations, TakeGGLWE, TakeGLWECt, - layouts::{Digits, GGLWECiphertextLayout, GGSWInfos, GLWEInfos, LWEInfos}, + layouts::{Dsize, GGLWECiphertextLayout, GGSWInfos, GLWEInfos, LWEInfos}, }; +use poulpy_core::glwe_packing; use poulpy_core::layouts::{GGSWCiphertext, GLWECiphertext, LWECiphertext, prepared::GGLWEAutomorphismKeyPrepared}; use crate::tfhe::{@@ -66,7 +67,8 @@ + TakeVecZnxBig<B>
+ TakeVecZnxDft<B> + TakeMatZnx + ScratchAvailable - + TakeVecZnxSlice, + + TakeVecZnxSlice + + TakeSlice, BlindRotationKeyPrepared<D, BRA, B>: BlincRotationExecute<B>, { fn execute_to_constant<DM: DataMut, DR: DataRef>(@@ -166,7 +168,8 @@ + TakeVecZnxDft<B>
+ TakeVecZnx + ScratchAvailable + TakeVecZnxSlice - + TakeMatZnx, + + TakeMatZnx + + TakeSlice, BlindRotationKeyPrepared<DBrk, BRA, B>: BlincRotationExecute<B>, { #[cfg(debug_assertions)]@@ -180,29 +183,29 @@ }
let n: usize = res.n().into(); let base2k: usize = res.base2k().into(); - let rows: usize = res.rows().into(); + let dnum: usize = res.dnum().into(); let rank: usize = res.rank().into(); let k: usize = res.k().into(); - let alpha: usize = rows.next_power_of_two(); + let alpha: usize = dnum.next_power_of_two(); let mut f: Vec<i64> = vec![0i64; (1 << log_domain) * alpha]; if to_exponent { - (0..rows).for_each(|i| { - f[i] = 1 << (base2k * (rows - 1 - i)); + (0..dnum).for_each(|i| { + f[i] = 1 << (base2k * (dnum - 1 - i)); }); } else { (0..1 << log_domain).for_each(|j| { - (0..rows).for_each(|i| { - f[j * alpha + i] = j as i64 * (1 << (base2k * (rows - 1 - i))); + (0..dnum).for_each(|i| { + f[j * alpha + i] = j as i64 * (1 << (base2k * (dnum - 1 - i))); }); }); } // Lut precision, basically must be able to hold the decomposition power basis of the GGSW - let mut lut: LookUpTable = LookUpTable::alloc(module, base2k, base2k * rows, extension_factor); - lut.set(module, &f, base2k * rows); + let mut lut: LookUpTable = LookUpTable::alloc(module, base2k, base2k * dnum, extension_factor); + lut.set(module, &f, base2k * dnum); if to_exponent { lut.set_rotation_direction(LookUpTableRotationDirection::Right);@@ -215,8 +218,8 @@ let gglwe_infos: GGLWECiphertextLayout = GGLWECiphertextLayout {
n: n.into(), base2k: base2k.into(), k: k.into(), - rows: rows.into(), - digits: Digits(1), + dnum: dnum.into(), + dsize: Dsize(1), rank_in: rank.max(1).into(), rank_out: rank.into(), };@@ -229,7 +232,7 @@ let gap: usize = 2 * lut.drift / lut.extension_factor();
let log_gap_in: usize = (usize::BITS - (gap * alpha - 1).leading_zeros()) as _; - (0..rows).for_each(|i| { + (0..dnum).for_each(|i| { let mut tmp_glwe: GLWECiphertext<&mut [u8]> = tmp_gglwe.at_mut(i, 0); if to_exponent {@@ -248,7 +251,7 @@ } else {
tmp_glwe.trace(module, 0, module.log_n(), &res_glwe, &key.atk, scratch_2); } - if i < rows { + if i < dnum { res_glwe.rotate_inplace(module, -(gap as i64), scratch_2); } });@@ -300,7 +303,7 @@ Scratch<B>: TakeVecZnxDft<B> + ScratchAvailable + TakeVecZnx,
{ let log_n: usize = module.log_n(); - let mut cts: HashMap<usize, GLWECiphertext<Vec<u8>>> = HashMap::new(); + let mut cts: HashMap<usize, &mut GLWECiphertext<Vec<u8>>> = HashMap::new(); // First partial trace, vanishes all coefficients which are not multiples of gap_in // [1, 1, 1, 1, 0, 0, 0, ..., 0, 0, -1, -1, -1, -1] -> [1, 0, 0, 0, 0, 0, 0, ..., 0, 0, 0, 0, 0, 0]@@ -316,177 +319,31 @@
// TODO: optimize with packing and final partial trace // If gap_out < gap_in, then we need to repack, i.e. reduce the cap between coefficients. if log_gap_in != log_gap_out { - let steps: i32 = 1 << log_domain; - (0..steps).for_each(|i| { + let steps: usize = 1 << log_domain; + + // TODO: from Scratch + let mut cts_vec: Vec<GLWECiphertext<Vec<u8>>> = Vec::new(); + + for i in 0..steps { if i != 0 { res.rotate_inplace(module, -(1 << log_gap_in), scratch); } - cts.insert(i as usize * (1 << log_gap_out), res.to_owned_deep()); - }); - pack(module, &mut cts, log_gap_out, auto_keys, scratch); - let packed: GLWECiphertext<Vec<u8>> = cts.remove(&0).unwrap(); + cts_vec.push(res.to_owned_deep()); + } + + for (i, ct) in cts_vec.iter_mut().enumerate().take(steps) { + cts.insert(i * (1 << log_gap_out), ct); + } + + glwe_packing(module, &mut cts, log_gap_out, auto_keys, scratch); + let packed: &mut GLWECiphertext<Vec<u8>> = cts.remove(&0).unwrap(); res.trace( module, log_n - log_gap_out, log_n, - &packed, + packed, auto_keys, scratch, ); } } - -pub fn pack<D: DataMut, B: Backend>( - module: &Module<B>, - cts: &mut HashMap<usize, GLWECiphertext<D>>, - log_gap_out: usize, - auto_keys: &HashMap<i64, GGLWEAutomorphismKeyPrepared<Vec<u8>, B>>, - scratch: &mut Scratch<B>, -) where - Module<B>: VecZnxRotateInplace<B> - + VecZnxNormalizeInplace<B> - + VecZnxNormalizeTmpBytes - + VecZnxSwitchRing - + VecZnxBigAutomorphismInplace<B> - + VecZnxRshInplace<B> - + VecZnxDftCopy<B> - + VecZnxIdftApplyTmpA<B> - + VecZnxSub - + VecZnxAddInplace - + VecZnxNegateInplace - + VecZnxCopy - + VecZnxSubInplace - + VecZnxDftAllocBytes - + VmpApplyDftToDftTmpBytes - + VecZnxBigNormalizeTmpBytes - + VmpApplyDftToDft<B> - + VmpApplyDftToDftAdd<B> - + VecZnxDftApply<B> - + VecZnxIdftApplyConsume<B> - + VecZnxBigAddSmallInplace<B> - + VecZnxBigNormalize<B> - + VecZnxAutomorphismInplace<B> - + VecZnxBigSubSmallNegateInplace<B> - + VecZnxRotate - + VecZnxNormalize<B>, - Scratch<B>: TakeVecZnx + TakeVecZnxDft<B> + ScratchAvailable, -{ - let log_n: usize = module.log_n(); - - (0..log_n - log_gap_out).for_each(|i| { - let t: usize = 16.min(1 << (log_n - 1 - i)); - - let auto_key: &GGLWEAutomorphismKeyPrepared<Vec<u8>, B> = if i == 0 { - auto_keys.get(&-1).unwrap() - } else { - auto_keys.get(&module.galois_element(1 << (i - 1))).unwrap() - }; - - (0..t).for_each(|j| { - let mut a: Option<GLWECiphertext<D>> = cts.remove(&j); - let mut b: Option<GLWECiphertext<D>> = cts.remove(&(j + t)); - - combine(module, a.as_mut(), b.as_mut(), i, auto_key, scratch); - - if let Some(a) = a { - cts.insert(j, a); - } else if let Some(b) = b { - cts.insert(j, b); - } - }); - }); -} - -#[allow(clippy::too_many_arguments)] -fn combine<A: DataMut, D: DataMut, DataAK: DataRef, B: Backend>( - module: &Module<B>, - a: Option<&mut GLWECiphertext<A>>, - b: Option<&mut GLWECiphertext<D>>, - i: usize, - auto_key: &GGLWEAutomorphismKeyPrepared<DataAK, B>, - scratch: &mut Scratch<B>, -) where - Module<B>: VecZnxRotateInplace<B> - + VecZnxNormalizeInplace<B> - + VecZnxNormalizeTmpBytes - + VecZnxSwitchRing - + VecZnxBigAutomorphismInplace<B> - + VecZnxRshInplace<B> - + VecZnxDftCopy<B> - + VecZnxIdftApplyTmpA<B> - + VecZnxSub - + VecZnxAddInplace - + VecZnxNegateInplace - + VecZnxCopy - + VecZnxSubInplace - + VecZnxDftAllocBytes - + VmpApplyDftToDftTmpBytes - + VecZnxBigNormalizeTmpBytes - + VmpApplyDftToDft<B> - + VmpApplyDftToDftAdd<B> - + VecZnxDftApply<B> - + VecZnxIdftApplyConsume<B> - + VecZnxBigAddSmallInplace<B> - + VecZnxBigNormalize<B> - + VecZnxAutomorphismInplace<B> - + VecZnxBigSubSmallNegateInplace<B> - + VecZnxRotate - + VecZnxNormalize<B>, - Scratch<B>: TakeVecZnx + TakeVecZnxDft<B> + ScratchAvailable, -{ - // Goal is to evaluate: a = a + b*X^t + phi(a - b*X^t)) - // We also use the identity: AUTO(a * X^t, g) = -X^t * AUTO(a, g) - // where t = 2^(log_n - i - 1) and g = 5^{2^(i - 1)} - // Different cases for wether a and/or b are zero. - // - // Implicite RSH without modulus switch, introduces extra I(X) * Q/2 on decryption. - // Necessary so that the scaling of the plaintext remains constant. - // It however is ok to do so here because coefficients are eventually - // either mapped to garbage or twice their value which vanishes I(X) - // since 2*(I(X) * Q/2) = I(X) * Q = 0 mod Q. - if let Some(a) = a { - let t: i64 = 1 << (a.n().log2() - i - 1); - - if let Some(b) = b { - let (mut tmp_b, scratch_1) = scratch.take_glwe_ct(a); - - // a = a * X^-t - a.rotate_inplace(module, -t, scratch_1); - - // tmp_b = a * X^-t - b - tmp_b.sub(module, a, b); - tmp_b.rsh(module, 1, scratch_1); - - // a = a * X^-t + b - a.add_inplace(module, b); - a.rsh(module, 1, scratch_1); - - tmp_b.normalize_inplace(module, scratch_1); - - // tmp_b = phi(a * X^-t - b) - tmp_b.automorphism_inplace(module, auto_key, scratch_1); - - // a = a * X^-t + b - phi(a * X^-t - b) - a.sub_inplace_ab(module, &tmp_b); - a.normalize_inplace(module, scratch_1); - - // a = a + b * X^t - phi(a * X^-t - b) * X^t - // = a + b * X^t - phi(a * X^-t - b) * - phi(X^t) - // = a + b * X^t + phi(a - b * X^t) - a.rotate_inplace(module, t, scratch_1); - } else { - a.rsh(module, 1, scratch); - // a = a + phi(a) - a.automorphism_add_inplace(module, auto_key, scratch); - } - } else if let Some(b) = b { - let t: i64 = 1 << (b.n().log2() - i - 1); - - let (mut tmp_b, scratch_1) = scratch.take_glwe_ct(b); - tmp_b.rotate(module, t, b); - tmp_b.rsh(module, 1, scratch_1); - - // a = (b* X^t - phi(b* X^t)) - b.automorphism_sub_negate(module, &tmp_b, auto_key, scratch_1); - } -}
@@ -1,5 +1,5 @@
use poulpy_core::layouts::{ - GGLWEAutomorphismKey, GGLWEAutomorphismKeyLayout, GGLWELayoutInfos, GGLWETensorKey, GGLWETensorKeyLayout, GGSWInfos, + GGLWEAutomorphismKey, GGLWEAutomorphismKeyLayout, GGLWEInfos, GGLWETensorKey, GGLWETensorKeyLayout, GGSWInfos, GLWECiphertext, GLWEInfos, GLWESecret, LWEInfos, LWESecret, prepared::{GGLWEAutomorphismKeyPrepared, GGLWETensorKeyPrepared, GLWESecretPrepared, PrepareAlloc}, };@@ -23,11 +23,12 @@ BlindRotationKeyLayout, BlindRotationKeyPrepared,
}; pub trait CircuitBootstrappingKeyInfos { - fn layout_brk(&self) -> BlindRotationKeyLayout; - fn layout_atk(&self) -> GGLWEAutomorphismKeyLayout; - fn layout_tsk(&self) -> GGLWETensorKeyLayout; + fn brk_infos(&self) -> BlindRotationKeyLayout; + fn atk_infos(&self) -> GGLWEAutomorphismKeyLayout; + fn tsk_infos(&self) -> GGLWETensorKeyLayout; } +#[derive(Debug, Clone, Copy)] pub struct CircuitBootstrappingKeyLayout { pub layout_brk: BlindRotationKeyLayout, pub layout_atk: GGLWEAutomorphismKeyLayout,@@ -35,15 +36,15 @@ pub layout_tsk: GGLWETensorKeyLayout,
} impl CircuitBootstrappingKeyInfos for CircuitBootstrappingKeyLayout { - fn layout_atk(&self) -> GGLWEAutomorphismKeyLayout { + fn atk_infos(&self) -> GGLWEAutomorphismKeyLayout { self.layout_atk } - fn layout_brk(&self) -> BlindRotationKeyLayout { + fn brk_infos(&self) -> BlindRotationKeyLayout { self.layout_brk } - fn layout_tsk(&self) -> GGLWETensorKeyLayout { + fn tsk_infos(&self) -> GGLWETensorKeyLayout { self.layout_tsk } }@@ -110,16 +111,15 @@ where
INFOS: CircuitBootstrappingKeyInfos, DLwe: DataRef, DGlwe: DataRef, - Module<B>:, { - assert_eq!(sk_lwe.n(), cbt_infos.layout_brk().n_lwe()); - assert_eq!(sk_glwe.n(), cbt_infos.layout_brk().n_glwe()); - assert_eq!(sk_glwe.n(), cbt_infos.layout_atk().n()); - assert_eq!(sk_glwe.n(), cbt_infos.layout_tsk().n()); + assert_eq!(sk_lwe.n(), cbt_infos.brk_infos().n_lwe()); + assert_eq!(sk_glwe.n(), cbt_infos.brk_infos().n_glwe()); + assert_eq!(sk_glwe.n(), cbt_infos.atk_infos().n()); + assert_eq!(sk_glwe.n(), cbt_infos.tsk_infos().n()); - let atk_infos: GGLWEAutomorphismKeyLayout = cbt_infos.layout_atk(); - let brk_infos: BlindRotationKeyLayout = cbt_infos.layout_brk(); - let trk_infos: GGLWETensorKeyLayout = cbt_infos.layout_tsk(); + let atk_infos: GGLWEAutomorphismKeyLayout = cbt_infos.atk_infos(); + let brk_infos: BlindRotationKeyLayout = cbt_infos.brk_infos(); + let trk_infos: GGLWETensorKeyLayout = cbt_infos.tsk_infos(); let mut auto_keys: HashMap<i64, GGLWEAutomorphismKey<Vec<u8>>> = HashMap::new(); let gal_els: Vec<i64> = GLWECiphertext::trace_galois_elements(module);@@ -159,36 +159,36 @@ pub(crate) atk: HashMap<i64, GGLWEAutomorphismKeyPrepared<Vec<u8>, B>>,
} impl<D: DataRef, BRA: BlindRotationAlgo, B: Backend> CircuitBootstrappingKeyInfos for CircuitBootstrappingKeyPrepared<D, BRA, B> { - fn layout_atk(&self) -> GGLWEAutomorphismKeyLayout { + fn atk_infos(&self) -> GGLWEAutomorphismKeyLayout { let (_, atk) = self.atk.iter().next().expect("atk is empty"); GGLWEAutomorphismKeyLayout { n: atk.n(), base2k: atk.base2k(), k: atk.k(), - rows: atk.rows(), - digits: atk.digits(), + dnum: atk.dnum(), + dsize: atk.dsize(), rank: atk.rank(), } } - fn layout_brk(&self) -> BlindRotationKeyLayout { + fn brk_infos(&self) -> BlindRotationKeyLayout { BlindRotationKeyLayout { n_glwe: self.brk.n_glwe(), n_lwe: self.brk.n_lwe(), base2k: self.brk.base2k(), k: self.brk.k(), - rows: self.brk.rows(), + dnum: self.brk.dnum(), rank: self.brk.rank(), } } - fn layout_tsk(&self) -> GGLWETensorKeyLayout { + fn tsk_infos(&self) -> GGLWETensorKeyLayout { GGLWETensorKeyLayout { n: self.tsk.n(), base2k: self.tsk.base2k(), k: self.tsk.k(), - rows: self.tsk.rows(), - digits: self.tsk.digits(), + dnum: self.tsk.dnum(), + dsize: self.tsk.dsize(), rank: self.tsk.rank(), } }
@@ -14,8 +14,8 @@ ZnNormalizeInplace,
}, layouts::{Backend, Module, ScalarZnx, ScratchOwned, ZnxView, ZnxViewMut}, oep::{ - ScratchAvailableImpl, ScratchOwnedAllocImpl, ScratchOwnedBorrowImpl, TakeMatZnxImpl, TakeScalarZnxImpl, TakeSvpPPolImpl, - TakeVecZnxBigImpl, TakeVecZnxDftImpl, TakeVecZnxDftSliceImpl, TakeVecZnxImpl, TakeVecZnxSliceImpl, + ScratchAvailableImpl, ScratchOwnedAllocImpl, ScratchOwnedBorrowImpl, TakeMatZnxImpl, TakeScalarZnxImpl, TakeSliceImpl, + TakeSvpPPolImpl, TakeVecZnxBigImpl, TakeVecZnxDftImpl, TakeVecZnxDftSliceImpl, TakeVecZnxImpl, TakeVecZnxSliceImpl, }, source::Source, };@@ -32,7 +32,7 @@ },
}; use poulpy_core::layouts::{ - Digits, GGLWEAutomorphismKeyLayout, GGLWETensorKeyLayout, GGSWCiphertextLayout, LWECiphertextLayout, prepared::PrepareAlloc, + Dsize, GGLWEAutomorphismKeyLayout, GGLWETensorKeyLayout, GGSWCiphertextLayout, LWECiphertextLayout, prepared::PrepareAlloc, }; use poulpy_core::layouts::{@@ -100,7 +100,8 @@ + TakeSvpPPolImpl<B>
+ TakeVecZnxBigImpl<B> + TakeVecZnxDftSliceImpl<B> + TakeMatZnxImpl<B> - + TakeVecZnxSliceImpl<B>, + + TakeVecZnxSliceImpl<B> + + TakeSliceImpl<B>, BlindRotationKey<Vec<u8>, BRA>: PrepareAlloc<B, BlindRotationKeyPrepared<Vec<u8>, BRA, B>>, BlindRotationKeyPrepared<Vec<u8>, BRA, B>: BlincRotationExecute<B>, BlindRotationKey<Vec<u8>, BRA>: BlindRotationKeyAlloc + BlindRotationKeyEncryptSk<B>,@@ -139,23 +140,23 @@ n_glwe: n_glwe.into(),
n_lwe: n_lwe.into(), base2k: base2k.into(), k: k_brk.into(), - rows: rows_brk.into(), + dnum: rows_brk.into(), rank: rank.into(), }, layout_atk: GGLWEAutomorphismKeyLayout { n: n_glwe.into(), base2k: base2k.into(), k: k_atk.into(), - rows: rows_atk.into(), + dnum: rows_atk.into(), rank: rank.into(), - digits: Digits(1), + dsize: Dsize(1), }, layout_tsk: GGLWETensorKeyLayout { n: n_glwe.into(), base2k: base2k.into(), k: k_tsk.into(), - rows: rows_tsk.into(), - digits: Digits(1), + dnum: rows_tsk.into(), + dsize: Dsize(1), rank: rank.into(), }, };@@ -164,8 +165,8 @@ let ggsw_infos: GGSWCiphertextLayout = GGSWCiphertextLayout {
n: n_glwe.into(), base2k: base2k.into(), k: k_ggsw_res.into(), - rows: rows_ggsw_res.into(), - digits: Digits(1), + dnum: rows_ggsw_res.into(), + dsize: Dsize(1), rank: rank.into(), };@@ -321,7 +322,8 @@ + TakeSvpPPolImpl<B>
+ TakeVecZnxBigImpl<B> + TakeVecZnxDftSliceImpl<B> + TakeMatZnxImpl<B> - + TakeVecZnxSliceImpl<B>, + + TakeVecZnxSliceImpl<B> + + TakeSliceImpl<B>, BlindRotationKey<Vec<u8>, BRA>: PrepareAlloc<B, BlindRotationKeyPrepared<Vec<u8>, BRA, B>>, BlindRotationKeyPrepared<Vec<u8>, BRA, B>: BlincRotationExecute<B>, BlindRotationKey<Vec<u8>, BRA>: BlindRotationKeyAlloc + BlindRotationKeyEncryptSk<B>,@@ -360,23 +362,23 @@ n_glwe: n_glwe.into(),
n_lwe: n_lwe.into(), base2k: base2k.into(), k: k_brk.into(), - rows: rows_brk.into(), + dnum: rows_brk.into(), rank: rank.into(), }, layout_atk: GGLWEAutomorphismKeyLayout { n: n_glwe.into(), base2k: base2k.into(), k: k_atk.into(), - rows: rows_atk.into(), + dnum: rows_atk.into(), rank: rank.into(), - digits: Digits(1), + dsize: Dsize(1), }, layout_tsk: GGLWETensorKeyLayout { n: n_glwe.into(), base2k: base2k.into(), k: k_tsk.into(), - rows: rows_tsk.into(), - digits: Digits(1), + dnum: rows_tsk.into(), + dsize: Dsize(1), rank: rank.into(), }, };@@ -385,8 +387,8 @@ let ggsw_infos: GGSWCiphertextLayout = GGSWCiphertextLayout {
n: n_glwe.into(), base2k: base2k.into(), k: k_ggsw_res.into(), - rows: rows_ggsw_res.into(), - digits: Digits(1), + dnum: rows_ggsw_res.into(), + dsize: Dsize(1), rank: rank.into(), };
@@ -1,2 +1,3 @@
+pub mod bdd_arithmetic; pub mod blind_rotation; pub mod circuit_bootstrapping;