From 6357a05509dcf77213779da8b128b29478a1147f Mon Sep 17 00:00:00 2001 From: Jean-Philippe Bossuat Date: Wed, 8 Oct 2025 17:52:03 +0200 Subject: [PATCH] Add BDD Arithmetic (#98) * Added some circuit, evaluation + some layouts * Refactor + memory reduction * Rows -> Dnum, Digits -> Dsize * fix #96 + glwe_packing (indirectly CBT) * clippy --- Cargo.lock | 17 +- .../cpu_fft64_avx/znx_avx/normalization.rs | 2 + .../benches/external_product_glwe_fft64.rs | 18 +- poulpy-core/benches/keyswitch_glwe_fft64.rs | 30 +- poulpy-core/src/automorphism/gglwe_atk.rs | 18 +- poulpy-core/src/automorphism/ggsw_ct.rs | 14 +- poulpy-core/src/automorphism/glwe_ct.rs | 6 +- poulpy-core/src/conversion/glwe_to_lwe.rs | 4 +- poulpy-core/src/conversion/lwe_to_glwe.rs | 4 +- .../src/encryption/compressed/gglwe_atk.rs | 4 +- .../src/encryption/compressed/gglwe_ct.rs | 32 +- .../src/encryption/compressed/gglwe_ksk.rs | 4 +- .../src/encryption/compressed/gglwe_tsk.rs | 4 +- .../src/encryption/compressed/ggsw_ct.rs | 8 +- poulpy-core/src/encryption/gglwe_atk.rs | 6 +- poulpy-core/src/encryption/gglwe_ct.rs | 30 +- poulpy-core/src/encryption/gglwe_ksk.rs | 7 +- poulpy-core/src/encryption/gglwe_tsk.rs | 4 +- poulpy-core/src/encryption/ggsw_ct.rs | 6 +- poulpy-core/src/encryption/glwe_to_lwe_ksk.rs | 11 +- poulpy-core/src/encryption/lwe_ksk.rs | 8 +- poulpy-core/src/encryption/lwe_to_glwe_ksk.rs | 4 +- poulpy-core/src/external_product/gglwe_atk.rs | 8 +- poulpy-core/src/external_product/gglwe_ksk.rs | 14 +- poulpy-core/src/external_product/ggsw_ct.rs | 8 +- poulpy-core/src/external_product/glwe_ct.rs | 367 +- poulpy-core/src/external_product/mod.rs | 19 + poulpy-core/src/glwe_packing.rs | 176 +- poulpy-core/src/glwe_trace.rs | 7 +- poulpy-core/src/keyswitching/gglwe_ct.rs | 46 +- poulpy-core/src/keyswitching/ggsw_ct.rs | 46 +- poulpy-core/src/keyswitching/glwe_ct.rs | 54 +- poulpy-core/src/keyswitching/lwe_ct.rs | 4 +- .../src/layouts/compressed/gglwe_atk.rs | 24 +- .../src/layouts/compressed/gglwe_ct.rs | 99 +- .../src/layouts/compressed/gglwe_ksk.rs | 34 +- .../src/layouts/compressed/gglwe_tsk.rs | 35 +- poulpy-core/src/layouts/compressed/ggsw_ct.rs | 70 +- .../src/layouts/compressed/glwe_to_lwe_ksk.rs | 35 +- poulpy-core/src/layouts/compressed/lwe_ksk.rs | 34 +- .../src/layouts/compressed/lwe_to_glwe_ksk.rs | 34 +- poulpy-core/src/layouts/gglwe_atk.rs | 38 +- poulpy-core/src/layouts/gglwe_ct.rs | 120 +- poulpy-core/src/layouts/gglwe_ksk.rs | 42 +- poulpy-core/src/layouts/gglwe_tsk.rs | 50 +- poulpy-core/src/layouts/ggsw_ct.rs | 118 +- poulpy-core/src/layouts/glwe_to_lwe_ksk.rs | 72 +- poulpy-core/src/layouts/lwe_ksk.rs | 48 +- poulpy-core/src/layouts/lwe_to_glwe_ksk.rs | 48 +- poulpy-core/src/layouts/mod.rs | 4 +- poulpy-core/src/layouts/prepared/gglwe_atk.rs | 31 +- poulpy-core/src/layouts/prepared/gglwe_ct.rs | 90 +- poulpy-core/src/layouts/prepared/gglwe_ksk.rs | 28 +- poulpy-core/src/layouts/prepared/gglwe_tsk.rs | 41 +- poulpy-core/src/layouts/prepared/ggsw_ct.rs | 117 +- .../src/layouts/prepared/glwe_to_lwe_ksk.rs | 40 +- poulpy-core/src/layouts/prepared/lwe_ksk.rs | 34 +- .../src/layouts/prepared/lwe_to_glwe_ksk.rs | 34 +- poulpy-core/src/lib.rs | 1 + poulpy-core/src/noise/gglwe_ct.rs | 14 +- poulpy-core/src/noise/ggsw_ct.rs | 14 +- poulpy-core/src/noise/glwe_ct.rs | 46 +- poulpy-core/src/scratch.rs | 52 +- poulpy-core/src/tests/serialization.rs | 40 +- .../test_suite/automorphism/gglwe_atk.rs | 56 +- .../tests/test_suite/automorphism/ggsw_ct.rs | 48 +- .../tests/test_suite/automorphism/glwe_ct.rs | 24 +- .../src/tests/test_suite/conversion.rs | 16 +- .../tests/test_suite/encryption/gglwe_atk.rs | 20 +- .../tests/test_suite/encryption/gglwe_ct.rs | 20 +- .../tests/test_suite/encryption/ggsw_ct.rs | 20 +- .../tests/test_suite/encryption/glwe_tsk.rs | 18 +- .../test_suite/external_product/gglwe_ksk.rs | 36 +- .../test_suite/external_product/ggsw_ct.rs | 40 +- .../test_suite/external_product/glwe_ct.rs | 24 +- .../tests/test_suite/keyswitch/gglwe_ct.rs | 38 +- .../src/tests/test_suite/keyswitch/ggsw_ct.rs | 44 +- .../src/tests/test_suite/keyswitch/glwe_ct.rs | 24 +- .../src/tests/test_suite/keyswitch/lwe_ct.rs | 4 +- poulpy-core/src/tests/test_suite/packing.rs | 10 +- poulpy-core/src/tests/test_suite/trace.rs | 8 +- .../src/reference/znx/arithmetic_ref.rs | 13 +- poulpy-schemes/Cargo.toml | 2 + .../benches/circuit_bootstrapping.rs | 26 +- .../examples/circuit_bootstrapping.rs | 22 +- .../src/tfhe/bdd_arithmetic/bdd_2w_to_1w.rs | 220 ++ .../tfhe/bdd_arithmetic/ciphertexts/block.rs | 215 ++ .../ciphertexts/block_prepared.rs | 282 ++ .../tfhe/bdd_arithmetic/ciphertexts/mod.rs | 7 + .../tfhe/bdd_arithmetic/ciphertexts/word.rs | 198 ++ .../src/tfhe/bdd_arithmetic/circuits/mod.rs | 1 + .../circuits/u32/add_codegen.rs | 3020 +++++++++++++++++ .../circuits/u32/and_codegen.rs | 465 +++ .../tfhe/bdd_arithmetic/circuits/u32/mod.rs | 10 + .../bdd_arithmetic/circuits/u32/or_codegen.rs | 34 + .../circuits/u32/sll_codegen.rs | 1830 ++++++++++ .../circuits/u32/slt_codegen.rs | 257 ++ .../circuits/u32/sltu_codegen.rs | 257 ++ .../circuits/u32/sra_codegen.rs | 1762 ++++++++++ .../circuits/u32/srl_codegen.rs | 1830 ++++++++++ .../circuits/u32/sub_codegen.rs | 3019 ++++++++++++++++ .../circuits/u32/xor_codegen.rs | 34 + .../src/tfhe/bdd_arithmetic/eval.rs | 198 ++ poulpy-schemes/src/tfhe/bdd_arithmetic/key.rs | 241 ++ poulpy-schemes/src/tfhe/bdd_arithmetic/mod.rs | 86 + .../src/tfhe/bdd_arithmetic/parameters.rs | 80 + .../src/tfhe/bdd_arithmetic/test.rs | 224 ++ .../src/tfhe/blind_rotation/cggi_algo.rs | 14 +- poulpy-schemes/src/tfhe/blind_rotation/key.rs | 20 +- .../src/tfhe/blind_rotation/key_compressed.rs | 10 +- .../src/tfhe/blind_rotation/key_prepared.rs | 10 +- poulpy-schemes/src/tfhe/blind_rotation/lut.rs | 22 +- .../tests/generic_blind_rotation.rs | 7 +- .../tfhe/blind_rotation/tests/generic_lut.rs | 6 +- .../tests/generic_serialization.rs | 4 +- .../src/tfhe/circuit_bootstrapping/circuit.rs | 215 +- .../src/tfhe/circuit_bootstrapping/key.rs | 46 +- .../tests/circuit_bootstrapping.rs | 40 +- poulpy-schemes/src/tfhe/mod.rs | 1 + 119 files changed, 15996 insertions(+), 1659 deletions(-) create mode 100644 poulpy-schemes/src/tfhe/bdd_arithmetic/bdd_2w_to_1w.rs create mode 100644 poulpy-schemes/src/tfhe/bdd_arithmetic/ciphertexts/block.rs create mode 100644 poulpy-schemes/src/tfhe/bdd_arithmetic/ciphertexts/block_prepared.rs create mode 100644 poulpy-schemes/src/tfhe/bdd_arithmetic/ciphertexts/mod.rs create mode 100644 poulpy-schemes/src/tfhe/bdd_arithmetic/ciphertexts/word.rs create mode 100644 poulpy-schemes/src/tfhe/bdd_arithmetic/circuits/mod.rs create mode 100644 poulpy-schemes/src/tfhe/bdd_arithmetic/circuits/u32/add_codegen.rs create mode 100644 poulpy-schemes/src/tfhe/bdd_arithmetic/circuits/u32/and_codegen.rs create mode 100644 poulpy-schemes/src/tfhe/bdd_arithmetic/circuits/u32/mod.rs create mode 100644 poulpy-schemes/src/tfhe/bdd_arithmetic/circuits/u32/or_codegen.rs create mode 100644 poulpy-schemes/src/tfhe/bdd_arithmetic/circuits/u32/sll_codegen.rs create mode 100644 poulpy-schemes/src/tfhe/bdd_arithmetic/circuits/u32/slt_codegen.rs create mode 100644 poulpy-schemes/src/tfhe/bdd_arithmetic/circuits/u32/sltu_codegen.rs create mode 100644 poulpy-schemes/src/tfhe/bdd_arithmetic/circuits/u32/sra_codegen.rs create mode 100644 poulpy-schemes/src/tfhe/bdd_arithmetic/circuits/u32/srl_codegen.rs create mode 100644 poulpy-schemes/src/tfhe/bdd_arithmetic/circuits/u32/sub_codegen.rs create mode 100644 poulpy-schemes/src/tfhe/bdd_arithmetic/circuits/u32/xor_codegen.rs create mode 100644 poulpy-schemes/src/tfhe/bdd_arithmetic/eval.rs create mode 100644 poulpy-schemes/src/tfhe/bdd_arithmetic/key.rs create mode 100644 poulpy-schemes/src/tfhe/bdd_arithmetic/mod.rs create mode 100644 poulpy-schemes/src/tfhe/bdd_arithmetic/parameters.rs create mode 100644 poulpy-schemes/src/tfhe/bdd_arithmetic/test.rs diff --git a/Cargo.lock b/Cargo.lock index 0db3387..3c3af8f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -408,6 +408,7 @@ dependencies = [ "poulpy-backend", "poulpy-core", "poulpy-hal", + "rand", ] [[package]] @@ -421,18 +422,18 @@ dependencies = [ [[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", diff --git a/poulpy-backend/src/cpu_fft64_avx/znx_avx/normalization.rs b/poulpy-backend/src/cpu_fft64_avx/znx_avx/normalization.rs index bcf8f7d..656fff2 100644 --- a/poulpy-backend/src/cpu_fft64_avx/znx_avx/normalization.rs +++ b/poulpy-backend/src/cpu_fft64_avx/znx_avx/normalization.rs @@ -1124,6 +1124,7 @@ mod tests { } } + #[allow(dead_code)] #[target_feature(enable = "avx2")] fn znx_extract_digit_addmul_internal() { let mut y0: [i64; 4] = [ @@ -1168,6 +1169,7 @@ mod tests { } } + #[allow(dead_code)] #[target_feature(enable = "avx2")] fn znx_normalize_digit_internal() { let mut y0: [i64; 4] = [ diff --git a/poulpy-core/benches/external_product_glwe_fft64.rs b/poulpy-core/benches/external_product_glwe_fft64.rs index 1d0ec94..360a9f4 100644 --- a/poulpy-core/benches/external_product_glwe_fft64.rs +++ b/poulpy-core/benches/external_product_glwe_fft64.rs @@ -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 @@ fn bench_external_product_glwe_fft64(c: &mut Criterion) { 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 @@ fn bench_external_product_glwe_inplace_fft64(c: &mut Criterion) { 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, }; diff --git a/poulpy-core/benches/keyswitch_glwe_fft64.rs b/poulpy-core/benches/keyswitch_glwe_fft64.rs index b2e3a3f..2da2032 100644 --- a/poulpy-core/benches/keyswitch_glwe_fft64.rs +++ b/poulpy-core/benches/keyswitch_glwe_fft64.rs @@ -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 @@ fn bench_keyswitch_glwe_fft64(c: &mut Criterion) { k_ct_in: TorusPrecision, k_ct_out: TorusPrecision, k_ksk: TorusPrecision, - digits: Digits, + dsize: Dsize, rank: Rank, } @@ -35,17 +35,17 @@ fn bench_keyswitch_glwe_fft64(c: &mut Criterion) { 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 @@ fn bench_keyswitch_glwe_fft64(c: &mut Criterion) { } let base2k: usize = 19; - let digits = 1; + let dsize = 1; let params_set: Vec = 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 @@ fn bench_keyswitch_glwe_inplace_fft64(c: &mut Criterion) { 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, }; diff --git a/poulpy-core/src/automorphism/gglwe_atk.rs b/poulpy-core/src/automorphism/gglwe_atk.rs index 72ee643..9b08e68 100644 --- a/poulpy-core/src/automorphism/gglwe_atk.rs +++ b/poulpy-core/src/automorphism/gglwe_atk.rs @@ -7,7 +7,7 @@ use poulpy_hal::{ 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> { pub fn automorphism_scratch_space( @@ -17,9 +17,9 @@ impl GGLWEAutomorphismKey> { key_infos: &KEY, ) -> usize where - OUT: GGLWELayoutInfos, - IN: GGLWELayoutInfos, - KEY: GGLWELayoutInfos, + OUT: GGLWEInfos, + IN: GGLWEInfos, + KEY: GGLWEInfos, Module: VecZnxDftAllocBytes + VmpApplyDftToDftTmpBytes + VecZnxBigNormalizeTmpBytes + VecZnxNormalizeTmpBytes, { GLWECiphertext::keyswitch_scratch_space( @@ -32,8 +32,8 @@ impl GGLWEAutomorphismKey> { pub fn automorphism_inplace_scratch_space(module: &Module, out_infos: &OUT, key_infos: &KEY) -> usize where - OUT: GGLWELayoutInfos, - KEY: GGLWELayoutInfos, + OUT: GGLWEInfos, + KEY: GGLWEInfos, Module: VecZnxDftAllocBytes + VmpApplyDftToDftTmpBytes + VecZnxBigNormalizeTmpBytes + VecZnxNormalizeTmpBytes, { GGLWEAutomorphismKey::automorphism_scratch_space(module, out_infos, out_infos, key_infos) @@ -102,7 +102,7 @@ impl GGLWEAutomorphismKey { 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 @@ impl GGLWEAutomorphismKey { }); }); - (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 @@ impl GGLWEAutomorphismKey { 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) diff --git a/poulpy-core/src/automorphism/ggsw_ct.rs b/poulpy-core/src/automorphism/ggsw_ct.rs index 8a7cb54..eef3082 100644 --- a/poulpy-core/src/automorphism/ggsw_ct.rs +++ b/poulpy-core/src/automorphism/ggsw_ct.rs @@ -9,7 +9,7 @@ use poulpy_hal::{ }; use crate::layouts::{ - GGLWELayoutInfos, GGSWCiphertext, GGSWInfos, GLWECiphertext, + GGLWEInfos, GGSWCiphertext, GGSWInfos, GLWECiphertext, prepared::{GGLWEAutomorphismKeyPrepared, GGLWETensorKeyPrepared}, }; @@ -24,8 +24,8 @@ impl GGSWCiphertext> { where OUT: GGSWInfos, IN: GGSWInfos, - KEY: GGLWELayoutInfos, - TSK: GGLWELayoutInfos, + KEY: GGLWEInfos, + TSK: GGLWEInfos, Module: VecZnxDftAllocBytes + VmpApplyDftToDftTmpBytes + VecZnxBigAllocBytes @@ -52,8 +52,8 @@ impl GGSWCiphertext> { ) -> usize where OUT: GGSWInfos, - KEY: GGLWELayoutInfos, - TSK: GGLWELayoutInfos, + KEY: GGLWEInfos, + TSK: GGLWEInfos, Module: VecZnxDftAllocBytes + VmpApplyDftToDftTmpBytes + VecZnxBigAllocBytes @@ -125,7 +125,7 @@ impl GGSWCiphertext { }; // 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 @@ impl GGSWCiphertext { Scratch: TakeVecZnxDft + ScratchAvailable + TakeVecZnxBig + 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) diff --git a/poulpy-core/src/automorphism/glwe_ct.rs b/poulpy-core/src/automorphism/glwe_ct.rs index f58d46e..79fcb12 100644 --- a/poulpy-core/src/automorphism/glwe_ct.rs +++ b/poulpy-core/src/automorphism/glwe_ct.rs @@ -8,7 +8,7 @@ use poulpy_hal::{ 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> { pub fn automorphism_scratch_space( @@ -20,7 +20,7 @@ impl GLWECiphertext> { where OUT: GLWEInfos, IN: GLWEInfos, - KEY: GGLWELayoutInfos, + KEY: GGLWEInfos, Module: VecZnxDftAllocBytes + VmpApplyDftToDftTmpBytes + VecZnxBigNormalizeTmpBytes + VecZnxNormalizeTmpBytes, { Self::keyswitch_scratch_space(module, out_infos, in_infos, key_infos) @@ -29,7 +29,7 @@ impl GLWECiphertext> { pub fn automorphism_inplace_scratch_space(module: &Module, out_infos: &OUT, key_infos: &KEY) -> usize where OUT: GLWEInfos, - KEY: GGLWELayoutInfos, + KEY: GGLWEInfos, Module: VecZnxDftAllocBytes + VmpApplyDftToDftTmpBytes + VecZnxBigNormalizeTmpBytes + VecZnxNormalizeTmpBytes, { Self::keyswitch_inplace_scratch_space(module, out_infos, key_infos) diff --git a/poulpy-core/src/conversion/glwe_to_lwe.rs b/poulpy-core/src/conversion/glwe_to_lwe.rs index c38a155..517da90 100644 --- a/poulpy-core/src/conversion/glwe_to_lwe.rs +++ b/poulpy-core/src/conversion/glwe_to_lwe.rs @@ -10,7 +10,7 @@ use poulpy_hal::{ use crate::{ TakeGLWECt, layouts::{ - GGLWELayoutInfos, GLWECiphertext, GLWECiphertextLayout, GLWEInfos, LWECiphertext, LWEInfos, Rank, + GGLWEInfos, GLWECiphertext, GLWECiphertextLayout, GLWEInfos, LWECiphertext, LWEInfos, Rank, prepared::GLWEToLWESwitchingKeyPrepared, }, }; @@ -25,7 +25,7 @@ impl LWECiphertext> { where OUT: LWEInfos, IN: GLWEInfos, - KEY: GGLWELayoutInfos, + KEY: GGLWEInfos, Module: VecZnxDftAllocBytes + VmpApplyDftToDftTmpBytes + VecZnxBigNormalizeTmpBytes + VecZnxNormalizeTmpBytes, { let glwe_layout: GLWECiphertextLayout = GLWECiphertextLayout { diff --git a/poulpy-core/src/conversion/lwe_to_glwe.rs b/poulpy-core/src/conversion/lwe_to_glwe.rs index a94c574..d3ae616 100644 --- a/poulpy-core/src/conversion/lwe_to_glwe.rs +++ b/poulpy-core/src/conversion/lwe_to_glwe.rs @@ -10,7 +10,7 @@ use poulpy_hal::{ use crate::{ TakeGLWECt, layouts::{ - GGLWELayoutInfos, GLWECiphertext, GLWECiphertextLayout, GLWEInfos, LWECiphertext, LWEInfos, + GGLWEInfos, GLWECiphertext, GLWECiphertextLayout, GLWEInfos, LWECiphertext, LWEInfos, prepared::LWEToGLWESwitchingKeyPrepared, }, }; @@ -25,7 +25,7 @@ impl GLWECiphertext> { where OUT: GLWEInfos, IN: LWEInfos, - KEY: GGLWELayoutInfos, + KEY: GGLWEInfos, Module: VecZnxDftAllocBytes + VmpApplyDftToDftTmpBytes + VecZnxBigNormalizeTmpBytes + VecZnxNormalizeTmpBytes, { let ct: usize = GLWECiphertext::alloc_bytes_with( diff --git a/poulpy-core/src/encryption/compressed/gglwe_atk.rs b/poulpy-core/src/encryption/compressed/gglwe_atk.rs index cd0da39..95dcf20 100644 --- a/poulpy-core/src/encryption/compressed/gglwe_atk.rs +++ b/poulpy-core/src/encryption/compressed/gglwe_atk.rs @@ -12,7 +12,7 @@ use poulpy_hal::{ use crate::{ TakeGLWESecret, TakeGLWESecretPrepared, layouts::{ - GGLWELayoutInfos, GLWEInfos, GLWESecret, LWEInfos, + GGLWEInfos, GLWEInfos, GLWESecret, LWEInfos, compressed::{GGLWEAutomorphismKeyCompressed, GGLWESwitchingKeyCompressed}, }, }; @@ -20,7 +20,7 @@ use crate::{ impl GGLWEAutomorphismKeyCompressed> { pub fn encrypt_sk_scratch_space(module: &Module, infos: &A) -> usize where - A: GGLWELayoutInfos, + A: GGLWEInfos, Module: VecZnxNormalizeTmpBytes + VecZnxDftAllocBytes + VecZnxNormalizeTmpBytes + SvpPPolAllocBytes, { assert_eq!(module.n() as u32, infos.n()); diff --git a/poulpy-core/src/encryption/compressed/gglwe_ct.rs b/poulpy-core/src/encryption/compressed/gglwe_ct.rs index ef58698..76871da 100644 --- a/poulpy-core/src/encryption/compressed/gglwe_ct.rs +++ b/poulpy-core/src/encryption/compressed/gglwe_ct.rs @@ -11,13 +11,13 @@ use poulpy_hal::{ 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> { pub fn encrypt_sk_scratch_space(module: &Module, infos: &A) -> usize where - A: GGLWELayoutInfos, + A: GGLWEInfos, Module: VecZnxNormalizeTmpBytes + VecZnxDftAllocBytes + VecZnxNormalizeTmpBytes, { GGLWECiphertext::encrypt_sk_scratch_space(module, infos) @@ -78,18 +78,18 @@ impl GGLWECiphertextCompressed { 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 @@ impl GGLWECiphertextCompressed { 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)), diff --git a/poulpy-core/src/encryption/compressed/gglwe_ksk.rs b/poulpy-core/src/encryption/compressed/gglwe_ksk.rs index b2d12a3..8dd177f 100644 --- a/poulpy-core/src/encryption/compressed/gglwe_ksk.rs +++ b/poulpy-core/src/encryption/compressed/gglwe_ksk.rs @@ -12,7 +12,7 @@ use poulpy_hal::{ 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 @@ use crate::{ impl GGLWESwitchingKeyCompressed> { pub fn encrypt_sk_scratch_space(module: &Module, infos: &A) -> usize where - A: GGLWELayoutInfos, + A: GGLWEInfos, Module: VecZnxNormalizeTmpBytes + VecZnxDftAllocBytes + VecZnxNormalizeTmpBytes + SvpPPolAllocBytes, { (GGLWECiphertext::encrypt_sk_scratch_space(module, infos) | ScalarZnx::alloc_bytes(module.n(), 1)) diff --git a/poulpy-core/src/encryption/compressed/gglwe_tsk.rs b/poulpy-core/src/encryption/compressed/gglwe_tsk.rs index 8bedeb4..6a75a57 100644 --- a/poulpy-core/src/encryption/compressed/gglwe_tsk.rs +++ b/poulpy-core/src/encryption/compressed/gglwe_tsk.rs @@ -12,7 +12,7 @@ use poulpy_hal::{ 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 @@ use crate::{ impl GGLWETensorKeyCompressed> { pub fn encrypt_sk_scratch_space(module: &Module, infos: &A) -> usize where - A: GGLWELayoutInfos, + A: GGLWEInfos, Module: SvpPPolAllocBytes + VecZnxNormalizeTmpBytes + VecZnxDftAllocBytes + VecZnxNormalizeTmpBytes + VecZnxBigAllocBytes, { diff --git a/poulpy-core/src/encryption/compressed/ggsw_ct.rs b/poulpy-core/src/encryption/compressed/ggsw_ct.rs index 59d669f..e49f246 100644 --- a/poulpy-core/src/encryption/compressed/ggsw_ct.rs +++ b/poulpy-core/src/encryption/compressed/ggsw_ct.rs @@ -65,19 +65,19 @@ impl GGSWCiphertextCompressed { 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| { diff --git a/poulpy-core/src/encryption/gglwe_atk.rs b/poulpy-core/src/encryption/gglwe_atk.rs index 308038c..6d45b37 100644 --- a/poulpy-core/src/encryption/gglwe_atk.rs +++ b/poulpy-core/src/encryption/gglwe_atk.rs @@ -11,13 +11,13 @@ use poulpy_hal::{ use crate::{ TakeGLWESecret, TakeGLWESecretPrepared, - layouts::{GGLWEAutomorphismKey, GGLWELayoutInfos, GGLWESwitchingKey, GLWEInfos, GLWESecret, LWEInfos}, + layouts::{GGLWEAutomorphismKey, GGLWEInfos, GGLWESwitchingKey, GLWEInfos, GLWESecret, LWEInfos}, }; impl GGLWEAutomorphismKey> { pub fn encrypt_sk_scratch_space(module: &Module, infos: &A) -> usize where - A: GGLWELayoutInfos, + A: GGLWEInfos, Module: SvpPPolAllocBytes + VecZnxNormalizeTmpBytes + VecZnxDftAllocBytes + VecZnxNormalizeTmpBytes, { assert_eq!( @@ -30,7 +30,7 @@ impl GGLWEAutomorphismKey> { pub fn encrypt_pk_scratch_space(module: &Module, _infos: &A) -> usize where - A: GGLWELayoutInfos, + A: GGLWEInfos, { assert_eq!( _infos.rank_in(), diff --git a/poulpy-core/src/encryption/gglwe_ct.rs b/poulpy-core/src/encryption/gglwe_ct.rs index c368892..51054cb 100644 --- a/poulpy-core/src/encryption/gglwe_ct.rs +++ b/poulpy-core/src/encryption/gglwe_ct.rs @@ -10,13 +10,13 @@ use poulpy_hal::{ use crate::{ TakeGLWEPt, - layouts::{GGLWECiphertext, GGLWELayoutInfos, GLWECiphertext, GLWEPlaintext, LWEInfos, prepared::GLWESecretPrepared}, + layouts::{GGLWECiphertext, GGLWEInfos, GLWECiphertext, GLWEPlaintext, LWEInfos, prepared::GLWESecretPrepared}, }; impl GGLWECiphertext> { pub fn encrypt_sk_scratch_space(module: &Module, infos: &A) -> usize where - A: GGLWELayoutInfos, + A: GGLWEInfos, Module: VecZnxNormalizeTmpBytes + VecZnxDftAllocBytes + VecZnxNormalizeTmpBytes, { GLWECiphertext::encrypt_sk_scratch_space(module, &infos.glwe_layout()) @@ -25,7 +25,7 @@ impl GGLWECiphertext> { pub fn encrypt_pk_scratch_space(_module: &Module, _infos: &A) -> usize where - A: GGLWELayoutInfos, + A: GGLWEInfos, { unimplemented!() } @@ -87,18 +87,18 @@ impl GGLWECiphertext { 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 @@ impl GGLWECiphertext { // (-(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 diff --git a/poulpy-core/src/encryption/gglwe_ksk.rs b/poulpy-core/src/encryption/gglwe_ksk.rs index 25daa00..0629bec 100644 --- a/poulpy-core/src/encryption/gglwe_ksk.rs +++ b/poulpy-core/src/encryption/gglwe_ksk.rs @@ -12,15 +12,14 @@ use poulpy_hal::{ use crate::{ TakeGLWESecretPrepared, layouts::{ - Degree, GGLWECiphertext, GGLWELayoutInfos, GGLWESwitchingKey, GLWEInfos, GLWESecret, LWEInfos, - prepared::GLWESecretPrepared, + Degree, GGLWECiphertext, GGLWEInfos, GGLWESwitchingKey, GLWEInfos, GLWESecret, LWEInfos, prepared::GLWESecretPrepared, }, }; impl GGLWESwitchingKey> { pub fn encrypt_sk_scratch_space(module: &Module, infos: &A) -> usize where - A: GGLWELayoutInfos, + A: GGLWEInfos, Module: SvpPPolAllocBytes + VecZnxNormalizeTmpBytes + VecZnxDftAllocBytes + VecZnxNormalizeTmpBytes, { (GGLWECiphertext::encrypt_sk_scratch_space(module, infos) | ScalarZnx::alloc_bytes(module.n(), 1)) @@ -30,7 +29,7 @@ impl GGLWESwitchingKey> { pub fn encrypt_pk_scratch_space(module: &Module, _infos: &A) -> usize where - A: GGLWELayoutInfos, + A: GGLWEInfos, { GGLWECiphertext::encrypt_pk_scratch_space(module, _infos) } diff --git a/poulpy-core/src/encryption/gglwe_tsk.rs b/poulpy-core/src/encryption/gglwe_tsk.rs index 04ac9cc..1946929 100644 --- a/poulpy-core/src/encryption/gglwe_tsk.rs +++ b/poulpy-core/src/encryption/gglwe_tsk.rs @@ -12,7 +12,7 @@ use poulpy_hal::{ 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 @@ use crate::{ impl GGLWETensorKey> { pub fn encrypt_sk_scratch_space(module: &Module, infos: &A) -> usize where - A: GGLWELayoutInfos, + A: GGLWEInfos, Module: SvpPPolAllocBytes + VecZnxNormalizeTmpBytes + VecZnxDftAllocBytes + VecZnxNormalizeTmpBytes + VecZnxBigAllocBytes, { diff --git a/poulpy-core/src/encryption/ggsw_ct.rs b/poulpy-core/src/encryption/ggsw_ct.rs index 4f0614f..6195458 100644 --- a/poulpy-core/src/encryption/ggsw_ct.rs +++ b/poulpy-core/src/encryption/ggsw_ct.rs @@ -65,15 +65,15 @@ impl GGSWCiphertext { 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| { diff --git a/poulpy-core/src/encryption/glwe_to_lwe_ksk.rs b/poulpy-core/src/encryption/glwe_to_lwe_ksk.rs index 01e2ca9..b65ce4e 100644 --- a/poulpy-core/src/encryption/glwe_to_lwe_ksk.rs +++ b/poulpy-core/src/encryption/glwe_to_lwe_ksk.rs @@ -11,16 +11,13 @@ use poulpy_hal::{ 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> { +impl GLWEToLWEKey> { pub fn encrypt_sk_scratch_space(module: &Module, infos: &A) -> usize where - A: GGLWELayoutInfos, + A: GGLWEInfos, Module: SvpPPolAllocBytes + VecZnxNormalizeTmpBytes + VecZnxDftAllocBytes + VecZnxNormalizeTmpBytes, { GLWESecretPrepared::alloc_bytes_with(module, infos.rank_in()) @@ -29,7 +26,7 @@ impl GLWEToLWESwitchingKey> { } } -impl GLWEToLWESwitchingKey { +impl GLWEToLWEKey { #[allow(clippy::too_many_arguments)] pub fn encrypt_sk( &mut self, diff --git a/poulpy-core/src/encryption/lwe_ksk.rs b/poulpy-core/src/encryption/lwe_ksk.rs index c7bac02..66ae685 100644 --- a/poulpy-core/src/encryption/lwe_ksk.rs +++ b/poulpy-core/src/encryption/lwe_ksk.rs @@ -12,7 +12,7 @@ use poulpy_hal::{ 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 @@ use crate::{ impl LWESwitchingKey> { pub fn encrypt_sk_scratch_space(module: &Module, infos: &A) -> usize where - A: GGLWELayoutInfos, + A: GGLWEInfos, Module: 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, diff --git a/poulpy-core/src/encryption/lwe_to_glwe_ksk.rs b/poulpy-core/src/encryption/lwe_to_glwe_ksk.rs index c97046a..204e84b 100644 --- a/poulpy-core/src/encryption/lwe_to_glwe_ksk.rs +++ b/poulpy-core/src/encryption/lwe_to_glwe_ksk.rs @@ -11,13 +11,13 @@ use poulpy_hal::{ use crate::{ TakeGLWESecret, TakeGLWESecretPrepared, - layouts::{Degree, GGLWELayoutInfos, GGLWESwitchingKey, GLWESecret, LWEInfos, LWESecret, LWEToGLWESwitchingKey, Rank}, + layouts::{Degree, GGLWEInfos, GGLWESwitchingKey, GLWESecret, LWEInfos, LWESecret, LWEToGLWESwitchingKey, Rank}, }; impl LWEToGLWESwitchingKey> { pub fn encrypt_sk_scratch_space(module: &Module, infos: &A) -> usize where - A: GGLWELayoutInfos, + A: GGLWEInfos, Module: SvpPPolAllocBytes + VecZnxNormalizeTmpBytes + VecZnxDftAllocBytes + VecZnxNormalizeTmpBytes, { debug_assert_eq!( diff --git a/poulpy-core/src/external_product/gglwe_atk.rs b/poulpy-core/src/external_product/gglwe_atk.rs index 611f755..cb35a4c 100644 --- a/poulpy-core/src/external_product/gglwe_atk.rs +++ b/poulpy-core/src/external_product/gglwe_atk.rs @@ -7,7 +7,7 @@ use poulpy_hal::{ 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> { pub fn external_product_scratch_space( @@ -17,8 +17,8 @@ impl GGLWEAutomorphismKey> { ggsw_infos: &GGSW, ) -> usize where - OUT: GGLWELayoutInfos, - IN: GGLWELayoutInfos, + OUT: GGLWEInfos, + IN: GGLWEInfos, GGSW: GGSWInfos, Module: VecZnxDftAllocBytes + VmpApplyDftToDftTmpBytes + VecZnxNormalizeTmpBytes, { @@ -31,7 +31,7 @@ impl GGLWEAutomorphismKey> { ggsw_infos: &GGSW, ) -> usize where - OUT: GGLWELayoutInfos, + OUT: GGLWEInfos, GGSW: GGSWInfos, Module: VecZnxDftAllocBytes + VmpApplyDftToDftTmpBytes + VecZnxNormalizeTmpBytes, { diff --git a/poulpy-core/src/external_product/gglwe_ksk.rs b/poulpy-core/src/external_product/gglwe_ksk.rs index 8e49640..2eff45c 100644 --- a/poulpy-core/src/external_product/gglwe_ksk.rs +++ b/poulpy-core/src/external_product/gglwe_ksk.rs @@ -7,7 +7,7 @@ use poulpy_hal::{ 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> { pub fn external_product_scratch_space( @@ -17,8 +17,8 @@ impl GGLWESwitchingKey> { ggsw_infos: &GGSW, ) -> usize where - OUT: GGLWELayoutInfos, - IN: GGLWELayoutInfos, + OUT: GGLWEInfos, + IN: GGLWEInfos, GGSW: GGSWInfos, Module: VecZnxDftAllocBytes + VmpApplyDftToDftTmpBytes + VecZnxNormalizeTmpBytes, { @@ -36,7 +36,7 @@ impl GGLWESwitchingKey> { ggsw_infos: &GGSW, ) -> usize where - OUT: GGLWELayoutInfos, + OUT: GGLWEInfos, GGSW: GGSWInfos, Module: VecZnxDftAllocBytes + VmpApplyDftToDftTmpBytes + VecZnxNormalizeTmpBytes, { @@ -91,13 +91,13 @@ impl GGLWESwitchingKey { } (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 @@ impl GGLWESwitchingKey { } (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); }); diff --git a/poulpy-core/src/external_product/ggsw_ct.rs b/poulpy-core/src/external_product/ggsw_ct.rs index a327058..a458de1 100644 --- a/poulpy-core/src/external_product/ggsw_ct.rs +++ b/poulpy-core/src/external_product/ggsw_ct.rs @@ -89,14 +89,14 @@ impl GGSWCiphertext { 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 @@ impl GGSWCiphertext { } (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); }); diff --git a/poulpy-core/src/external_product/glwe_ct.rs b/poulpy-core/src/external_product/glwe_ct.rs index a225976..d764507 100644 --- a/poulpy-core/src/external_product/glwe_ct.rs +++ b/poulpy-core/src/external_product/glwe_ct.rs @@ -7,7 +7,13 @@ use poulpy_hal::{ 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> { #[allow(clippy::too_many_arguments)] @@ -26,7 +32,7 @@ impl GLWECiphertext> { 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,70 +77,221 @@ impl GLWECiphertext { rhs: &GGSWCiphertextPrepared, scratch: &mut Scratch, ) where - Module: VecZnxDftAllocBytes - + VmpApplyDftToDftTmpBytes - + VecZnxNormalizeTmpBytes - + VecZnxDftApply - + VmpApplyDftToDft - + VmpApplyDftToDftAdd - + VecZnxIdftApplyConsume - + VecZnxBigNormalize - + VecZnxNormalize, - Scratch: TakeVecZnxDft + ScratchAvailable + TakeVecZnx, + Module: GLWEExternalProduct, { + module.external_product(self, lhs, rhs, scratch); + } + + pub fn external_product_inplace( + &mut self, + module: &Module, + rhs: &GGSWCiphertextPrepared, + scratch: &mut Scratch, + ) where + Module: GLWEExternalProductInplace, + { + module.external_product_inplace(self, rhs, scratch); + } +} + +impl GLWEExternalProductInplace for Module +where + Module: VecZnxDftAllocBytes + + VmpApplyDftToDftTmpBytes + + VecZnxNormalizeTmpBytes + + VecZnxDftApply + + VmpApplyDftToDft + + VmpApplyDftToDftAdd + + VecZnxIdftApplyConsume + + VecZnxBigNormalize + + VecZnxNormalize, + Scratch: TakeVecZnxDft + ScratchAvailable + TakeVecZnx, +{ + fn external_product_inplace(&self, res: &mut R, ggsw: &D, scratch: &mut Scratch) + where + R: GLWECiphertextToMut, + D: GGSWCiphertextPreparedToRef, + { + 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(); + + #[cfg(debug_assertions)] + { + use poulpy_hal::api::ScratchAvailable; + + 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 dsize: usize = rhs.dsize().into(); + let a_size: usize = (res.size() * basek_in).div_ceil(basek_ggsw); + + 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..dsize { + // (lhs.size() + di) / dsize = (a - (digit - di - 1)).div_ceil(dsize) + a_dft.set_size((res.size() + di) / dsize); + + // 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^{(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() - ((dsize - di) as isize - 2).max(0) as usize); + + for j in 0..cols { + self.vec_znx_dft_apply(dsize, dsize - 1 - di, &mut a_dft, j, &res.data, j); + } + + if di == 0 { + self.vmp_apply_dft_to_dft(&mut res_dft, &a_dft, &rhs.data, scratch_2); + } else { + 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(self.n(), cols, a_size); + + for j in 0..cols { + self.vec_znx_normalize( + basek_ggsw, + &mut a_conv, + j, + basek_in, + &res.data, + j, + scratch_3, + ); + } + + 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 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^{(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() - ((dsize - di) as isize - 2).max(0) as usize); + + for j in 0..cols { + self.vec_znx_dft_apply(dsize, dsize - 1 - di, &mut a_dft, j, &res.data, j); + } + + if di == 0 { + self.vmp_apply_dft_to_dft(&mut res_dft, &a_dft, &rhs.data, scratch_2); + } else { + self.vmp_apply_dft_to_dft_add(&mut res_dft, &a_dft, &rhs.data, di, scratch_2); + } + } + } + + let res_big: VecZnxBig<&mut [u8], BE> = self.vec_znx_idft_apply_consume(res_dft); + + for j in 0..cols { + self.vec_znx_big_normalize( + basek_in, + &mut res.data, + j, + basek_ggsw, + &res_big, + j, + scratch_1, + ); + } + } +} + +impl GLWEExternalProduct for Module +where + Module: VecZnxDftAllocBytes + + VmpApplyDftToDftTmpBytes + + VecZnxNormalizeTmpBytes + + VecZnxDftApply + + VmpApplyDftToDft + + VmpApplyDftToDftAdd + + VecZnxIdftApplyConsume + + VecZnxBigNormalize + + VecZnxNormalize, + Scratch: TakeVecZnxDft + ScratchAvailable + TakeVecZnx, +{ + fn external_product(&self, res: &mut R, lhs: &A, rhs: &D, scratch: &mut Scratch) + where + R: GLWECiphertextToMut, + A: GLWECiphertextToRef, + D: GGSWCiphertextPreparedToRef, + { + 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 = self.base2k().into(); + let basek_out: usize = res.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_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 dsize: usize = rhs.dsize().into(); 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(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((lhs.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, &lhs.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, @@ -145,37 +302,37 @@ impl GLWECiphertext { ); } - 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((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, &a_conv, 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_3); + 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_3); + 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); (0..cols).for_each(|i| { - module.vec_znx_big_normalize( + self.vec_znx_big_normalize( basek_out, - &mut self.data, + res.data_mut(), i, basek_ggsw, &res_big, @@ -184,120 +341,4 @@ impl GLWECiphertext { ); }); } - - pub fn external_product_inplace( - &mut self, - module: &Module, - rhs: &GGSWCiphertextPrepared, - scratch: &mut Scratch, - ) where - Module: VecZnxDftAllocBytes - + VmpApplyDftToDftTmpBytes - + VecZnxNormalizeTmpBytes - + VecZnxDftApply - + VmpApplyDftToDft - + VmpApplyDftToDftAdd - + VecZnxIdftApplyConsume - + VecZnxBigNormalize - + VecZnxNormalize, - Scratch: TakeVecZnxDft + ScratchAvailable + TakeVecZnx, - { - let basek_in: usize = self.base2k().into(); - let basek_ggsw: usize = rhs.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,)); - } - - 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 (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)); - 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); - - // Small optimization for digits > 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 - // ~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); - - for j in 0..cols { - module.vec_znx_dft_apply(digits, digits - 1 - di, &mut a_dft, j, &self.data, j); - } - - if di == 0 { - module.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); - } - } - } else { - let (mut a_conv, scratch_3) = scratch_2.take_vec_znx(module.n(), cols, a_size); - - for j in 0..cols { - module.vec_znx_normalize( - basek_ggsw, - &mut a_conv, - j, - basek_in, - &self.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); - - // Small optimization for digits > 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 - // ~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); - - for j in 0..cols { - module.vec_znx_dft_apply(digits, digits - 1 - di, &mut a_dft, j, &self.data, j); - } - - if di == 0 { - module.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); - } - } - } - - let res_big: VecZnxBig<&mut [u8], B> = module.vec_znx_idft_apply_consume(res_dft); - - for j in 0..cols { - module.vec_znx_big_normalize( - basek_in, - &mut self.data, - j, - basek_ggsw, - &res_big, - j, - scratch_1, - ); - } - } } diff --git a/poulpy-core/src/external_product/mod.rs b/poulpy-core/src/external_product/mod.rs index 0779074..f46b82c 100644 --- a/poulpy-core/src/external_product/mod.rs +++ b/poulpy-core/src/external_product/mod.rs @@ -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 { + fn external_product(&self, res: &mut R, a: &A, ggsw: &D, scratch: &mut Scratch) + where + R: GLWECiphertextToMut, + A: GLWECiphertextToRef, + D: GGSWCiphertextPreparedToRef; +} + +pub trait GLWEExternalProductInplace { + fn external_product_inplace(&self, res: &mut R, ggsw: &D, scratch: &mut Scratch) + where + R: GLWECiphertextToMut, + D: GGSWCiphertextPreparedToRef; +} diff --git a/poulpy-core/src/glwe_packing.rs b/poulpy-core/src/glwe_packing.rs index 93f84aa..3da962a 100644 --- a/poulpy-core/src/glwe_packing.rs +++ b/poulpy-core/src/glwe_packing.rs @@ -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 @@ impl GLWEPacker { pub fn scratch_space(module: &Module, out_infos: &OUT, key_infos: &KEY) -> usize where OUT: GLWEInfos, - KEY: GGLWELayoutInfos, + KEY: GGLWEInfos, Module: VecZnxDftAllocBytes + VmpApplyDftToDftTmpBytes + VecZnxBigNormalizeTmpBytes + VecZnxNormalizeTmpBytes, { pack_core_scratch_space(module, out_infos, key_infos) @@ -180,7 +180,7 @@ impl GLWEPacker { fn pack_core_scratch_space(module: &Module, out_infos: &OUT, key_infos: &KEY) -> usize where OUT: GLWEInfos, - KEY: GGLWELayoutInfos, + KEY: GGLWEInfos, Module: VecZnxDftAllocBytes + VmpApplyDftToDftTmpBytes + VecZnxBigNormalizeTmpBytes + VecZnxNormalizeTmpBytes, { combine_scratch_space(module, out_infos, key_infos) @@ -271,7 +271,7 @@ fn pack_core( fn combine_scratch_space(module: &Module, out_infos: &OUT, key_infos: &KEY) -> usize where OUT: GLWEInfos, - KEY: GGLWELayoutInfos, + KEY: GGLWEInfos, Module: VecZnxDftAllocBytes + VmpApplyDftToDftTmpBytes + VecZnxBigNormalizeTmpBytes + VecZnxNormalizeTmpBytes, { GLWECiphertext::alloc_bytes(out_infos) @@ -390,3 +390,165 @@ fn combine( 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( + module: &Module, + cts: &mut HashMap>, + log_gap_out: usize, + auto_keys: &HashMap>, + scratch: &mut Scratch, +) where + ATK: DataRef, + Module: VecZnxRotateInplace + + VecZnxNormalizeInplace + + VecZnxNormalizeTmpBytes + + VecZnxSwitchRing + + VecZnxBigAutomorphismInplace + + VecZnxRshInplace + + VecZnxDftCopy + + VecZnxIdftApplyTmpA + + VecZnxSub + + VecZnxAddInplace + + VecZnxNegateInplace + + VecZnxCopy + + VecZnxSubInplace + + VecZnxDftAllocBytes + + VmpApplyDftToDftTmpBytes + + VecZnxBigNormalizeTmpBytes + + VmpApplyDftToDft + + VmpApplyDftToDftAdd + + VecZnxDftApply + + VecZnxIdftApplyConsume + + VecZnxBigAddSmallInplace + + VecZnxBigNormalize + + VecZnxAutomorphismInplace + + VecZnxBigSubSmallNegateInplace + + VecZnxRotate + + VecZnxNormalize, + Scratch: TakeVecZnx + TakeVecZnxDft + 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 = 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> = cts.remove(&j); + let mut b: Option<&mut GLWECiphertext> = 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( + module: &Module, + a: &mut Option<&mut GLWECiphertext>, + b: &mut Option<&mut GLWECiphertext>, + i: usize, + auto_key: &GGLWEAutomorphismKeyPrepared, + scratch: &mut Scratch, +) where + Module: VecZnxRotateInplace + + VecZnxNormalizeInplace + + VecZnxNormalizeTmpBytes + + VecZnxBigAutomorphismInplace + + VecZnxRshInplace + + VecZnxDftCopy + + VecZnxIdftApplyTmpA + + VecZnxSub + + VecZnxAddInplace + + VecZnxNegateInplace + + VecZnxCopy + + VecZnxSubInplace + + VecZnxDftAllocBytes + + VmpApplyDftToDftTmpBytes + + VecZnxBigNormalizeTmpBytes + + VmpApplyDftToDft + + VmpApplyDftToDftAdd + + VecZnxDftApply + + VecZnxIdftApplyConsume + + VecZnxBigAddSmallInplace + + VecZnxBigNormalize + + VecZnxAutomorphismInplace + + VecZnxBigSubSmallNegateInplace + + VecZnxRotate + + VecZnxNormalize, + Scratch: TakeVecZnx + TakeVecZnxDft + 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); + } +} diff --git a/poulpy-core/src/glwe_trace.rs b/poulpy-core/src/glwe_trace.rs index 48471ff..4e1769e 100644 --- a/poulpy-core/src/glwe_trace.rs +++ b/poulpy-core/src/glwe_trace.rs @@ -12,8 +12,7 @@ use poulpy_hal::{ 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 @@ impl GLWECiphertext> { where OUT: GLWEInfos, IN: GLWEInfos, - KEY: GGLWELayoutInfos, + KEY: GGLWEInfos, Module: VecZnxDftAllocBytes + VmpApplyDftToDftTmpBytes + VecZnxBigNormalizeTmpBytes + VecZnxNormalizeTmpBytes, { let trace: usize = Self::automorphism_inplace_scratch_space(module, out_infos, key_infos); @@ -59,7 +58,7 @@ impl GLWECiphertext> { pub fn trace_inplace_scratch_space(module: &Module, out_infos: &OUT, key_infos: &KEY) -> usize where OUT: GLWEInfos, - KEY: GGLWELayoutInfos, + KEY: GGLWEInfos, Module: VecZnxDftAllocBytes + VmpApplyDftToDftTmpBytes + VecZnxBigNormalizeTmpBytes + VecZnxNormalizeTmpBytes, { Self::trace_scratch_space(module, out_infos, out_infos, key_infos) diff --git a/poulpy-core/src/keyswitching/gglwe_ct.rs b/poulpy-core/src/keyswitching/gglwe_ct.rs index 346dbdf..9f6caa5 100644 --- a/poulpy-core/src/keyswitching/gglwe_ct.rs +++ b/poulpy-core/src/keyswitching/gglwe_ct.rs @@ -8,7 +8,7 @@ use poulpy_hal::{ }; use crate::layouts::{ - GGLWEAutomorphismKey, GGLWELayoutInfos, GGLWESwitchingKey, GLWECiphertext, GLWEInfos, + GGLWEAutomorphismKey, GGLWEInfos, GGLWESwitchingKey, GLWECiphertext, GLWEInfos, prepared::{GGLWEAutomorphismKeyPrepared, GGLWESwitchingKeyPrepared}, }; @@ -20,9 +20,9 @@ impl GGLWEAutomorphismKey> { key_infos: &KEY, ) -> usize where - OUT: GGLWELayoutInfos, - IN: GGLWELayoutInfos, - KEY: GGLWELayoutInfos, + OUT: GGLWEInfos, + IN: GGLWEInfos, + KEY: GGLWEInfos, Module: VecZnxDftAllocBytes + VmpApplyDftToDftTmpBytes + VecZnxBigNormalizeTmpBytes + VecZnxNormalizeTmpBytes, { GGLWESwitchingKey::keyswitch_scratch_space(module, out_infos, in_infos, key_infos) @@ -30,8 +30,8 @@ impl GGLWEAutomorphismKey> { pub fn keyswitch_inplace_scratch_space(module: &Module, out_infos: &OUT, key_infos: &KEY) -> usize where - OUT: GGLWELayoutInfos, - KEY: GGLWELayoutInfos, + OUT: GGLWEInfos, + KEY: GGLWEInfos, Module: VecZnxDftAllocBytes + VmpApplyDftToDftTmpBytes + VecZnxBigNormalizeTmpBytes + VecZnxNormalizeTmpBytes, { GGLWESwitchingKey::keyswitch_inplace_scratch_space(module, out_infos, key_infos) @@ -93,9 +93,9 @@ impl GGLWESwitchingKey> { key_apply: &KEY, ) -> usize where - OUT: GGLWELayoutInfos, - IN: GGLWELayoutInfos, - KEY: GGLWELayoutInfos, + OUT: GGLWEInfos, + IN: GGLWEInfos, + KEY: GGLWEInfos, Module: VecZnxDftAllocBytes + VmpApplyDftToDftTmpBytes + VecZnxBigNormalizeTmpBytes + VecZnxNormalizeTmpBytes, { GLWECiphertext::keyswitch_scratch_space(module, out_infos, in_infos, key_apply) @@ -103,8 +103,8 @@ impl GGLWESwitchingKey> { pub fn keyswitch_inplace_scratch_space(module: &Module, out_infos: &OUT, key_apply: &KEY) -> usize where - OUT: GGLWELayoutInfos + GLWEInfos, - KEY: GGLWELayoutInfos + GLWEInfos, + OUT: GGLWEInfos + GLWEInfos, + KEY: GGLWEInfos + GLWEInfos, Module: VecZnxDftAllocBytes + VmpApplyDftToDftTmpBytes + VecZnxBigNormalizeTmpBytes + VecZnxNormalizeTmpBytes, { GLWECiphertext::keyswitch_inplace_scratch_space(module, out_infos, key_apply) @@ -156,28 +156,28 @@ impl GGLWESwitchingKey { 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 @@ impl GGLWESwitchingKey { } (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) }); diff --git a/poulpy-core/src/keyswitching/ggsw_ct.rs b/poulpy-core/src/keyswitching/ggsw_ct.rs index 0f05fd1..d261f03 100644 --- a/poulpy-core/src/keyswitching/ggsw_ct.rs +++ b/poulpy-core/src/keyswitching/ggsw_ct.rs @@ -10,7 +10,7 @@ use poulpy_hal::{ 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> { pub(crate) fn expand_row_scratch_space(module: &Module, out_infos: &OUT, tsk_infos: &TSK) -> usize where OUT: GGSWInfos, - TSK: GGLWELayoutInfos, + TSK: GGLWEInfos, Module: 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 @@ impl GGSWCiphertext> { where OUT: GGSWInfos, IN: GGSWInfos, - KEY: GGLWELayoutInfos, - TSK: GGLWELayoutInfos, + KEY: GGLWEInfos, + TSK: GGLWEInfos, Module: VecZnxDftAllocBytes + VmpApplyDftToDftTmpBytes + VecZnxBigAllocBytes @@ -101,8 +101,8 @@ impl GGSWCiphertext> { ) -> usize where OUT: GGSWInfos, - KEY: GGLWELayoutInfos, - TSK: GGLWELayoutInfos, + KEY: GGLWEInfos, + TSK: GGLWEInfos, Module: VecZnxDftAllocBytes + VmpApplyDftToDftTmpBytes + VecZnxBigAllocBytes @@ -143,12 +143,12 @@ impl GGSWCiphertext { 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 @@ impl GGSWCiphertext { + VecZnxNormalize, Scratch: ScratchAvailable + TakeVecZnxDft + TakeVecZnxBig + 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 @@ impl GGSWCiphertext { + VecZnxNormalize, Scratch: ScratchAvailable + TakeVecZnxDft + TakeVecZnxBig + 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 @@ impl GGSWCiphertext { 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 @@ impl GGSWCiphertext { // 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 @@ impl GGSWCiphertext { // 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 @@ impl GGSWCiphertext { let pmat: &VmpPMat = &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 { diff --git a/poulpy-core/src/keyswitching/glwe_ct.rs b/poulpy-core/src/keyswitching/glwe_ct.rs index 9174f84..07d95e9 100644 --- a/poulpy-core/src/keyswitching/glwe_ct.rs +++ b/poulpy-core/src/keyswitching/glwe_ct.rs @@ -7,7 +7,7 @@ use poulpy_hal::{ 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> { pub fn keyswitch_scratch_space( @@ -19,13 +19,13 @@ impl GLWECiphertext> { where OUT: GLWEInfos, IN: GLWEInfos, - KEY: GGLWELayoutInfos, + KEY: GGLWEInfos, Module: 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 @@ impl GLWECiphertext> { 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 @@ impl GLWECiphertext> { pub fn keyswitch_inplace_scratch_space(module: &Module, out_infos: &OUT, key_apply: &KEY) -> usize where OUT: GLWEInfos, - KEY: GGLWELayoutInfos, + KEY: GGLWEInfos, Module: VecZnxDftAllocBytes + VmpApplyDftToDftTmpBytes + VecZnxBigNormalizeTmpBytes + VecZnxNormalizeTmpBytes, { Self::keyswitch_scratch_space(module, out_infos, out_infos, key_apply) @@ -105,7 +105,7 @@ impl GLWECiphertext { lhs.k(), rhs.base2k(), rhs.k(), - rhs.digits(), + rhs.dsize(), rhs.rank_in(), rhs.rank_out(), )={scrach_needed}", @@ -256,7 +256,7 @@ impl GLWECiphertext { + VecZnxNormalize, Scratch: TakeVecZnxDft + TakeVecZnx, { - if rhs.digits() == 1 { + if rhs.dsize() == 1 { return keyswitch_vmp_one_digit( module, self.base2k().into(), @@ -275,7 +275,7 @@ impl GLWECiphertext { res_dft, &self.data, &rhs.key.data, - rhs.digits().into(), + rhs.dsize().into(), scratch, ) } @@ -333,7 +333,7 @@ fn keyswitch_vmp_multiple_digits( mut res_dft: VecZnxDft, a: &VecZnx, mat: &VmpPMat, - digits: usize, + dsize: usize, scratch: &mut Scratch, ) -> VecZnxBig where @@ -351,24 +351,24 @@ where { 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 @@ where 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 { diff --git a/poulpy-core/src/keyswitching/lwe_ct.rs b/poulpy-core/src/keyswitching/lwe_ct.rs index 2dc9364..7d9e08e 100644 --- a/poulpy-core/src/keyswitching/lwe_ct.rs +++ b/poulpy-core/src/keyswitching/lwe_ct.rs @@ -10,7 +10,7 @@ use poulpy_hal::{ use crate::{ TakeGLWECt, layouts::{ - GGLWELayoutInfos, GLWECiphertext, GLWECiphertextLayout, LWECiphertext, LWEInfos, Rank, TorusPrecision, + GGLWEInfos, GLWECiphertext, GLWECiphertextLayout, LWECiphertext, LWEInfos, Rank, TorusPrecision, prepared::LWESwitchingKeyPrepared, }, }; @@ -25,7 +25,7 @@ impl LWECiphertext> { where OUT: LWEInfos, IN: LWEInfos, - KEY: GGLWELayoutInfos, + KEY: GGLWEInfos, Module: VecZnxDftAllocBytes + VmpApplyDftToDftTmpBytes + VecZnxBigNormalizeTmpBytes diff --git a/poulpy-core/src/layouts/compressed/gglwe_atk.rs b/poulpy-core/src/layouts/compressed/gglwe_atk.rs index 4ad55b5..2a10765 100644 --- a/poulpy-core/src/layouts/compressed/gglwe_atk.rs +++ b/poulpy-core/src/layouts/compressed/gglwe_atk.rs @@ -5,7 +5,7 @@ use poulpy_hal::{ }; 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 @@ impl GLWEInfos for GGLWEAutomorphismKeyCompressed { } } -impl GGLWELayoutInfos for GGLWEAutomorphismKeyCompressed { +impl GGLWEInfos for GGLWEAutomorphismKeyCompressed { fn rank_in(&self) -> Rank { self.key.rank_in() } @@ -49,12 +49,12 @@ impl GGLWELayoutInfos for GGLWEAutomorphismKeyCompressed { 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 fmt::Display for GGLWEAutomorphismKeyCompressed { impl GGLWEAutomorphismKeyCompressed> { pub fn alloc(infos: &A) -> Self where - A: GGLWELayoutInfos, + A: GGLWEInfos, { debug_assert_eq!(infos.rank_in(), infos.rank_out()); Self { @@ -88,23 +88,23 @@ impl GGLWEAutomorphismKeyCompressed> { } } - 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(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) } } diff --git a/poulpy-core/src/layouts/compressed/gglwe_ct.rs b/poulpy-core/src/layouts/compressed/gglwe_ct.rs index a3dd256..f7a4df9 100644 --- a/poulpy-core/src/layouts/compressed/gglwe_ct.rs +++ b/poulpy-core/src/layouts/compressed/gglwe_ct.rs @@ -5,7 +5,7 @@ use poulpy_hal::{ }; 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 struct GGLWECiphertextCompressed { 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 @@ impl GLWEInfos for GGLWECiphertextCompressed { } } -impl GGLWELayoutInfos for GGLWECiphertextCompressed { +impl GGLWEInfos for GGLWECiphertextCompressed { fn rank_in(&self) -> Rank { Rank(self.data.cols_in() as u32) } @@ -53,12 +53,12 @@ impl GGLWELayoutInfos for GGLWECiphertextCompressed { 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 fmt::Display for GGLWECiphertextCompressed { 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 fmt::Display for GGLWECiphertextCompressed { impl GGLWECiphertextCompressed> { pub fn alloc(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 @@ impl GGLWECiphertextCompressed> { 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(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 ReaderFrom for GGLWECiphertextCompressed { fn read_from(&mut self, reader: &mut R) -> std::io::Result<()> { self.k = TorusPrecision(reader.read_u32::()?); self.base2k = Base2K(reader.read_u32::()?); - self.digits = Digits(reader.read_u32::()?); + self.dsize = Dsize(reader.read_u32::()?); self.rank_out = Rank(reader.read_u32::()?); let seed_len: u32 = reader.read_u32::()?; self.seed = vec![[0u8; 32]; seed_len as usize]; @@ -232,7 +223,7 @@ impl WriterTo for GGLWECiphertextCompressed { fn write_to(&self, writer: &mut W) -> std::io::Result<()> { writer.write_u32::(self.k.into())?; writer.write_u32::(self.base2k.into())?; - writer.write_u32::(self.digits.into())?; + writer.write_u32::(self.dsize.into())?; writer.write_u32::(self.rank_out.into())?; writer.write_u32::(self.seed.len() as u32)?; for s in &self.seed { @@ -279,19 +270,19 @@ where ); 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)); }); diff --git a/poulpy-core/src/layouts/compressed/gglwe_ksk.rs b/poulpy-core/src/layouts/compressed/gglwe_ksk.rs index fd25dcd..60d9316 100644 --- a/poulpy-core/src/layouts/compressed/gglwe_ksk.rs +++ b/poulpy-core/src/layouts/compressed/gglwe_ksk.rs @@ -5,7 +5,7 @@ use poulpy_hal::{ }; 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 @@ impl GLWEInfos for GGLWESwitchingKeyCompressed { } } -impl GGLWELayoutInfos for GGLWESwitchingKeyCompressed { +impl GGLWEInfos for GGLWESwitchingKeyCompressed { fn rank_in(&self) -> Rank { self.key.rank_in() } @@ -50,12 +50,12 @@ impl GGLWELayoutInfos for GGLWESwitchingKeyCompressed { 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 fmt::Display for GGLWESwitchingKeyCompressed { impl GGLWESwitchingKeyCompressed> { pub fn alloc(infos: &A) -> Self where - A: GGLWELayoutInfos, + A: GGLWEInfos, { GGLWESwitchingKeyCompressed { key: GGLWECiphertextCompressed::alloc(infos), @@ -97,13 +97,13 @@ impl GGLWESwitchingKeyCompressed> { 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 @@ impl GGLWESwitchingKeyCompressed> { pub fn alloc_bytes(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) } } diff --git a/poulpy-core/src/layouts/compressed/gglwe_tsk.rs b/poulpy-core/src/layouts/compressed/gglwe_tsk.rs index 2c5e102..fef4647 100644 --- a/poulpy-core/src/layouts/compressed/gglwe_tsk.rs +++ b/poulpy-core/src/layouts/compressed/gglwe_tsk.rs @@ -5,7 +5,7 @@ use poulpy_hal::{ }; 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 @@ impl GLWEInfos for GGLWETensorKeyCompressed { } } -impl GGLWELayoutInfos for GGLWETensorKeyCompressed { +impl GGLWEInfos for GGLWETensorKeyCompressed { fn rank_in(&self) -> Rank { self.rank_out() } @@ -47,12 +47,12 @@ impl GGLWELayoutInfos for GGLWETensorKeyCompressed { 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 fmt::Display for GGLWETensorKeyCompressed { impl GGLWETensorKeyCompressed> { pub fn alloc(infos: &A) -> Self where - A: GGLWELayoutInfos, + A: GGLWEInfos, { assert_eq!( infos.rank_in(), @@ -94,13 +94,13 @@ impl GGLWETensorKeyCompressed> { 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>> = Vec::new(); let pairs: u32 = (((rank.0 + 1) * rank.0) >> 1).max(1); (0..pairs).for_each(|_| { @@ -108,10 +108,10 @@ impl GGLWETensorKeyCompressed> { n, base2k, k, - rows, - digits, Rank(1), rank, + dnum, + dsize, )); }); Self { keys } @@ -119,7 +119,7 @@ impl GGLWETensorKeyCompressed> { pub fn alloc_bytes(infos: &A) -> usize where - A: GGLWELayoutInfos, + A: GGLWEInfos, { assert_eq!( infos.rank_in(), @@ -133,16 +133,15 @@ impl GGLWETensorKeyCompressed> { 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) } } diff --git a/poulpy-core/src/layouts/compressed/ggsw_ct.rs b/poulpy-core/src/layouts/compressed/ggsw_ct.rs index 93443e4..f0a62cc 100644 --- a/poulpy-core/src/layouts/compressed/ggsw_ct.rs +++ b/poulpy-core/src/layouts/compressed/ggsw_ct.rs @@ -5,7 +5,7 @@ use poulpy_hal::{ }; 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 { pub(crate) data: MatZnx, 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 GLWEInfos for GGSWCiphertextCompressed { } impl GGSWInfos for GGSWCiphertextCompressed { - 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 fmt::Display for GGSWCiphertextCompressed { 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 @@ impl GGSWCiphertextCompressed> { 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 @@ impl GGSWCiphertextCompressed> { 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 ReaderFrom for GGSWCiphertextCompressed { fn read_from(&mut self, reader: &mut R) -> std::io::Result<()> { self.k = TorusPrecision(reader.read_u32::()?); self.base2k = Base2K(reader.read_u32::()?); - self.digits = Digits(reader.read_u32::()?); + self.dsize = Dsize(reader.read_u32::()?); self.rank = Rank(reader.read_u32::()?); let seed_len: usize = reader.read_u32::()? as usize; self.seed = vec![[0u8; 32]; seed_len]; @@ -205,7 +205,7 @@ impl WriterTo for GGSWCiphertextCompressed { fn write_to(&self, writer: &mut W) -> std::io::Result<()> { writer.write_u32::(self.k.into())?; writer.write_u32::(self.base2k.into())?; - writer.write_u32::(self.digits.into())?; + writer.write_u32::(self.dsize.into())?; writer.write_u32::(self.rank.into())?; writer.write_u32::(self.seed.len() as u32)?; for s in &self.seed { @@ -225,9 +225,9 @@ where 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)); diff --git a/poulpy-core/src/layouts/compressed/glwe_to_lwe_ksk.rs b/poulpy-core/src/layouts/compressed/glwe_to_lwe_ksk.rs index b69667f..63933e8 100644 --- a/poulpy-core/src/layouts/compressed/glwe_to_lwe_ksk.rs +++ b/poulpy-core/src/layouts/compressed/glwe_to_lwe_ksk.rs @@ -6,8 +6,7 @@ use poulpy_hal::{ }; 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 @@ impl GLWEInfos for GLWEToLWESwitchingKeyCompressed { } } -impl GGLWELayoutInfos for GLWEToLWESwitchingKeyCompressed { +impl GGLWEInfos for GLWEToLWESwitchingKeyCompressed { 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 WriterTo for GLWEToLWESwitchingKeyCompressed { impl GLWEToLWESwitchingKeyCompressed> { pub fn alloc(infos: &A) -> Self where - A: GGLWELayoutInfos, + A: GGLWEInfos, { debug_assert_eq!( infos.rank_out().0, @@ -95,28 +94,28 @@ impl GLWEToLWESwitchingKeyCompressed> { "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(infos: &A) -> usize where - A: GGLWELayoutInfos, + A: GGLWEInfos, { debug_assert_eq!( infos.rank_out().0, @@ -124,14 +123,14 @@ impl GLWEToLWESwitchingKeyCompressed> { "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)) } } diff --git a/poulpy-core/src/layouts/compressed/lwe_ksk.rs b/poulpy-core/src/layouts/compressed/lwe_ksk.rs index c37fbdd..480707b 100644 --- a/poulpy-core/src/layouts/compressed/lwe_ksk.rs +++ b/poulpy-core/src/layouts/compressed/lwe_ksk.rs @@ -5,7 +5,7 @@ use poulpy_hal::{ }; 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 @@ impl GLWEInfos for LWESwitchingKeyCompressed { } } -impl GGLWELayoutInfos for LWESwitchingKeyCompressed { - fn digits(&self) -> Digits { - self.0.digits() +impl GGLWEInfos for LWESwitchingKeyCompressed { + fn dsize(&self) -> Dsize { + self.0.dsize() } fn rank_in(&self) -> Rank { @@ -48,8 +48,8 @@ impl GGLWELayoutInfos for LWESwitchingKeyCompressed { self.0.rank_out() } - fn rows(&self) -> Rows { - self.0.rows() + fn dnum(&self) -> Dnum { + self.0.dnum() } } @@ -86,12 +86,12 @@ impl WriterTo for LWESwitchingKeyCompressed { impl LWESwitchingKeyCompressed> { pub fn alloc(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 @@ impl LWESwitchingKeyCompressed> { 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(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 @@ impl LWESwitchingKeyCompressed> { 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)) } } diff --git a/poulpy-core/src/layouts/compressed/lwe_to_glwe_ksk.rs b/poulpy-core/src/layouts/compressed/lwe_to_glwe_ksk.rs index 7b86fb0..86c353b 100644 --- a/poulpy-core/src/layouts/compressed/lwe_to_glwe_ksk.rs +++ b/poulpy-core/src/layouts/compressed/lwe_to_glwe_ksk.rs @@ -5,7 +5,7 @@ use poulpy_hal::{ }; 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 @@ impl GLWEInfos for LWEToGLWESwitchingKeyCompressed { } } -impl GGLWELayoutInfos for LWEToGLWESwitchingKeyCompressed { - fn digits(&self) -> Digits { - self.0.digits() +impl GGLWEInfos for LWEToGLWESwitchingKeyCompressed { + fn dsize(&self) -> Dsize { + self.0.dsize() } fn rank_in(&self) -> Rank { @@ -48,8 +48,8 @@ impl GGLWELayoutInfos for LWEToGLWESwitchingKeyCompressed { self.0.rank_out() } - fn rows(&self) -> Rows { - self.0.rows() + fn dnum(&self) -> Dnum { + self.0.dnum() } } @@ -86,12 +86,12 @@ impl WriterTo for LWEToGLWESwitchingKeyCompressed { impl LWEToGLWESwitchingKeyCompressed> { pub fn alloc(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 @@ impl LWEToGLWESwitchingKeyCompressed> { 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(infos: &A) -> usize where - A: GGLWELayoutInfos, + A: GGLWEInfos, { debug_assert_eq!( infos.rank_in().0, @@ -123,15 +123,15 @@ impl LWEToGLWESwitchingKeyCompressed> { "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)) } } diff --git a/poulpy-core/src/layouts/gglwe_atk.rs b/poulpy-core/src/layouts/gglwe_atk.rs index 2177bca..5c786d2 100644 --- a/poulpy-core/src/layouts/gglwe_atk.rs +++ b/poulpy-core/src/layouts/gglwe_atk.rs @@ -4,7 +4,7 @@ use poulpy_hal::{ }; 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 @@ impl GLWEInfos for GGLWEAutomorphismKey { } } -impl GGLWELayoutInfos for GGLWEAutomorphismKey { +impl GGLWEInfos for GGLWEAutomorphismKey { fn rank_in(&self) -> Rank { self.key.rank_in() } @@ -65,12 +65,12 @@ impl GGLWELayoutInfos for GGLWEAutomorphismKey { 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 @@ impl GLWEInfos for GGLWEAutomorphismKeyLayout { } } -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 fmt::Display for GGLWEAutomorphismKey { impl GGLWEAutomorphismKey> { pub fn alloc(infos: &A) -> Self where - A: GGLWELayoutInfos, + A: GGLWEInfos, { assert_eq!( infos.rank_in(), @@ -146,16 +146,16 @@ impl GGLWEAutomorphismKey> { } } - 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(infos: &A) -> usize where - A: GGLWELayoutInfos, + A: GGLWEInfos, { assert_eq!( infos.rank_in(), @@ -165,8 +165,8 @@ impl GGLWEAutomorphismKey> { 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) } } diff --git a/poulpy-core/src/layouts/gglwe_ct.rs b/poulpy-core/src/layouts/gglwe_ct.rs index 54efd4a..ca8236c 100644 --- a/poulpy-core/src/layouts/gglwe_ct.rs +++ b/poulpy-core/src/layouts/gglwe_ct.rs @@ -3,17 +3,17 @@ use poulpy_hal::{ 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 @@ where 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 @@ impl GLWEInfos for GGLWECiphertextLayout { } } -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 { pub(crate) data: MatZnx, pub(crate) k: TorusPrecision, pub(crate) base2k: Base2K, - pub(crate) digits: Digits, + pub(crate) dsize: Dsize, } impl LWEInfos for GGLWECiphertext { @@ -110,7 +110,7 @@ impl GLWEInfos for GGLWECiphertext { } } -impl GGLWELayoutInfos for GGLWECiphertext { +impl GGLWEInfos for GGLWECiphertext { fn rank_in(&self) -> Rank { Rank(self.data.cols_in() as u32) } @@ -119,12 +119,12 @@ impl GGLWELayoutInfos for GGLWECiphertext { 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 { data: Option>, base2k: Option, k: Option, - digits: Option, + dsize: Option, } impl GGLWECiphertext { @@ -142,7 +142,7 @@ impl GGLWECiphertext { data: None, base2k: None, k: None, - digits: None, + dsize: None, } } } @@ -151,18 +151,18 @@ impl GGLWECiphertextBuilder> { #[inline] pub fn layout(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 @@ impl GGLWECiphertextBuilder { } #[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 @@ impl GGLWECiphertextBuilder { let data: MatZnx = 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 @@ impl GGLWECiphertextBuilder { data, base2k, k, - digits, + dsize, }) } } @@ -257,10 +257,10 @@ impl fmt::Display for GGLWECiphertext { 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 { impl GGLWECiphertext> { pub fn alloc(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 @@ impl GGLWECiphertext> { 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(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 @@ impl GGLWECiphertext> { 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 ReaderFrom for GGLWECiphertext { fn read_from(&mut self, reader: &mut R) -> std::io::Result<()> { self.k = TorusPrecision(reader.read_u32::()?); self.base2k = Base2K(reader.read_u32::()?); - self.digits = Digits(reader.read_u32::()?); + self.dsize = Dsize(reader.read_u32::()?); self.data.read_from(reader) } } @@ -402,7 +402,7 @@ impl WriterTo for GGLWECiphertext { fn write_to(&self, writer: &mut W) -> std::io::Result<()> { writer.write_u32::(self.k.0)?; writer.write_u32::(self.base2k.0)?; - writer.write_u32::(self.digits.0)?; + writer.write_u32::(self.dsize.0)?; self.data.write_to(writer) } } diff --git a/poulpy-core/src/layouts/gglwe_ksk.rs b/poulpy-core/src/layouts/gglwe_ksk.rs index 3f3e8b0..31a483b 100644 --- a/poulpy-core/src/layouts/gglwe_ksk.rs +++ b/poulpy-core/src/layouts/gglwe_ksk.rs @@ -4,7 +4,7 @@ use poulpy_hal::{ }; 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 @@ impl GLWEInfos for GGLWESwitchingKeyLayout { } } -impl GGLWELayoutInfos for GGLWESwitchingKeyLayout { +impl GGLWEInfos for GGLWESwitchingKeyLayout { fn rank_in(&self) -> Rank { self.rank_in } @@ -50,12 +50,12 @@ impl GGLWELayoutInfos for GGLWESwitchingKeyLayout { 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 @@ impl GLWEInfos for GGLWESwitchingKey { } } -impl GGLWELayoutInfos for GGLWESwitchingKey { +impl GGLWEInfos for GGLWESwitchingKey { fn rank_in(&self) -> Rank { self.key.rank_in() } @@ -99,12 +99,12 @@ impl GGLWELayoutInfos for GGLWESwitchingKey { 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 FillUniform for GGLWESwitchingKey { impl GGLWESwitchingKey> { pub fn alloc(infos: &A) -> Self where - A: GGLWELayoutInfos, + A: GGLWEInfos, { GGLWESwitchingKey { key: GGLWECiphertext::alloc(infos), @@ -148,13 +148,13 @@ impl GGLWESwitchingKey> { 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 @@ impl GGLWESwitchingKey> { pub fn alloc_bytes(infos: &A) -> usize where - A: GGLWELayoutInfos, + A: GGLWEInfos, { GGLWECiphertext::alloc_bytes(infos) } @@ -171,12 +171,12 @@ impl GGLWESwitchingKey> { 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) } } diff --git a/poulpy-core/src/layouts/gglwe_tsk.rs b/poulpy-core/src/layouts/gglwe_tsk.rs index b6a7450..a949b7e 100644 --- a/poulpy-core/src/layouts/gglwe_tsk.rs +++ b/poulpy-core/src/layouts/gglwe_tsk.rs @@ -3,9 +3,7 @@ use poulpy_hal::{ 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 @@ impl GLWEInfos for GGLWETensorKey { } } -impl GGLWELayoutInfos for GGLWETensorKey { +impl GGLWEInfos for GGLWETensorKey { fn rank_in(&self) -> Rank { self.rank_out() } @@ -58,12 +56,12 @@ impl GGLWELayoutInfos for GGLWETensorKey { 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 @@ impl GLWEInfos for GGLWETensorKeyLayout { } } -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 fmt::Display for GGLWETensorKey { impl GGLWETensorKey> { pub fn alloc(infos: &A) -> Self where - A: GGLWELayoutInfos, + A: GGLWEInfos, { assert_eq!( infos.rank_in(), @@ -143,13 +141,13 @@ impl GGLWETensorKey> { 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>> = Vec::new(); let pairs: u32 = (((rank.0 + 1) * rank.0) >> 1).max(1); (0..pairs).for_each(|_| { @@ -157,10 +155,10 @@ impl GGLWETensorKey> { n, base2k, k, - rows, - digits, Rank(1), rank, + dnum, + dsize, )); }); Self { keys } @@ -168,7 +166,7 @@ impl GGLWETensorKey> { pub fn alloc_bytes(infos: &A) -> usize where - A: GGLWELayoutInfos, + A: GGLWEInfos, { assert_eq!( infos.rank_in(), @@ -182,16 +180,16 @@ impl GGLWETensorKey> { 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) } } diff --git a/poulpy-core/src/layouts/ggsw_ct.rs b/poulpy-core/src/layouts/ggsw_ct.rs index 7ccdc7d..dacec88 100644 --- a/poulpy-core/src/layouts/ggsw_ct.rs +++ b/poulpy-core/src/layouts/ggsw_ct.rs @@ -4,22 +4,22 @@ use poulpy_hal::{ }; 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 GLWEInfos for GGSWCiphertextLayout { } 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 { pub(crate) data: MatZnx, pub(crate) k: TorusPrecision, pub(crate) base2k: Base2K, - pub(crate) digits: Digits, + pub(crate) dsize: Dsize, } impl LWEInfos for GGSWCiphertext { @@ -96,12 +96,12 @@ impl GLWEInfos for GGSWCiphertext { } impl GGSWInfos for GGSWCiphertext { - 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 { data: Option>, base2k: Option, k: Option, - digits: Option, + dsize: Option, } impl GGSWCiphertext { @@ -119,7 +119,7 @@ impl GGSWCiphertext { data: None, base2k: None, k: None, - digits: None, + dsize: None, } } } @@ -131,30 +131,30 @@ impl GGSWCiphertextBuilder> { 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 @@ impl GGSWCiphertextBuilder { } #[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 @@ impl GGSWCiphertextBuilder { let data: MatZnx = 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 @@ impl GGSWCiphertextBuilder { data, base2k, k, - digits, + dsize, }) } } @@ -231,10 +231,10 @@ impl fmt::Display for GGSWCiphertext { 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 @@ impl GGSWCiphertext> { 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 @@ impl GGSWCiphertext> { 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 ReaderFrom for GGSWCiphertext { fn read_from(&mut self, reader: &mut R) -> std::io::Result<()> { self.k = TorusPrecision(reader.read_u32::()?); self.base2k = Base2K(reader.read_u32::()?); - self.digits = Digits(reader.read_u32::()?); + self.dsize = Dsize(reader.read_u32::()?); self.data.read_from(reader) } } @@ -366,7 +366,7 @@ impl WriterTo for GGSWCiphertext { fn write_to(&self, writer: &mut W) -> std::io::Result<()> { writer.write_u32::(self.k.into())?; writer.write_u32::(self.base2k.into())?; - writer.write_u32::(self.digits.into())?; + writer.write_u32::(self.dsize.into())?; self.data.write_to(writer) } } diff --git a/poulpy-core/src/layouts/glwe_to_lwe_ksk.rs b/poulpy-core/src/layouts/glwe_to_lwe_ksk.rs index 00d5115..f227c9c 100644 --- a/poulpy-core/src/layouts/glwe_to_lwe_ksk.rs +++ b/poulpy-core/src/layouts/glwe_to_lwe_ksk.rs @@ -3,22 +3,20 @@ use poulpy_hal::{ 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 @@ impl LWEInfos for GLWEToLWESwitchingKeyLayout { } } -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(pub(crate) GGLWESwitchingKey); +pub struct GLWEToLWEKey(pub(crate) GGLWESwitchingKey); -impl LWEInfos for GLWEToLWESwitchingKey { +impl LWEInfos for GLWEToLWEKey { fn base2k(&self) -> Base2K { self.0.base2k() } @@ -78,63 +76,63 @@ impl LWEInfos for GLWEToLWESwitchingKey { } } -impl GLWEInfos for GLWEToLWESwitchingKey { +impl GLWEInfos for GLWEToLWEKey { fn rank(&self) -> Rank { self.rank_out() } } -impl GGLWELayoutInfos for GLWEToLWESwitchingKey { +impl GGLWEInfos for GLWEToLWEKey { 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 fmt::Debug for GLWEToLWESwitchingKey { +impl fmt::Debug for GLWEToLWEKey { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{self}") } } -impl FillUniform for GLWEToLWESwitchingKey { +impl FillUniform for GLWEToLWEKey { fn fill_uniform(&mut self, log_bound: usize, source: &mut Source) { self.0.fill_uniform(log_bound, source); } } -impl fmt::Display for GLWEToLWESwitchingKey { +impl fmt::Display for GLWEToLWEKey { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "(GLWEToLWESwitchingKey) {}", self.0) } } -impl ReaderFrom for GLWEToLWESwitchingKey { +impl ReaderFrom for GLWEToLWEKey { fn read_from(&mut self, reader: &mut R) -> std::io::Result<()> { self.0.read_from(reader) } } -impl WriterTo for GLWEToLWESwitchingKey { +impl WriterTo for GLWEToLWEKey { fn write_to(&self, writer: &mut W) -> std::io::Result<()> { self.0.write_to(writer) } } -impl GLWEToLWESwitchingKey> { +impl GLWEToLWEKey> { pub fn alloc(infos: &A) -> Self where - A: GGLWELayoutInfos, + A: GGLWEInfos, { debug_assert_eq!( infos.rank_out().0, @@ -142,28 +140,28 @@ impl GLWEToLWESwitchingKey> { "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(infos: &A) -> usize where - A: GGLWELayoutInfos, + A: GGLWEInfos, { debug_assert_eq!( infos.rank_out().0, @@ -171,14 +169,14 @@ impl GLWEToLWESwitchingKey> { "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)) } } diff --git a/poulpy-core/src/layouts/lwe_ksk.rs b/poulpy-core/src/layouts/lwe_ksk.rs index abf36cb..314322c 100644 --- a/poulpy-core/src/layouts/lwe_ksk.rs +++ b/poulpy-core/src/layouts/lwe_ksk.rs @@ -5,16 +5,14 @@ use poulpy_hal::{ 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 @@ impl GLWEInfos for LWESwitchingKeyLayout { } } -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 @@ impl GLWEInfos for LWESwitchingKey { } } -impl GGLWELayoutInfos for LWESwitchingKey { - fn digits(&self) -> Digits { - self.0.digits() +impl GGLWEInfos for LWESwitchingKey { + fn dsize(&self) -> Dsize { + self.0.dsize() } fn rank_in(&self) -> Rank { @@ -95,20 +93,20 @@ impl GGLWELayoutInfos for LWESwitchingKey { self.0.rank_out() } - fn rows(&self) -> Rows { - self.0.rows() + fn dnum(&self) -> Dnum { + self.0.dnum() } } impl LWESwitchingKey> { pub fn alloc(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 @@ impl LWESwitchingKey> { 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(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 @@ impl LWESwitchingKey> { 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)) } } diff --git a/poulpy-core/src/layouts/lwe_to_glwe_ksk.rs b/poulpy-core/src/layouts/lwe_to_glwe_ksk.rs index 92bac13..b3ba74b 100644 --- a/poulpy-core/src/layouts/lwe_to_glwe_ksk.rs +++ b/poulpy-core/src/layouts/lwe_to_glwe_ksk.rs @@ -5,17 +5,15 @@ use poulpy_hal::{ 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 @@ impl GLWEInfos for LWEToGLWESwitchingKeyLayout { } } -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 @@ impl GLWEInfos for LWEToGLWESwitchingKey { self.rank_out() } } -impl GGLWELayoutInfos for LWEToGLWESwitchingKey { - fn digits(&self) -> Digits { - self.0.digits() +impl GGLWEInfos for LWEToGLWESwitchingKey { + fn dsize(&self) -> Dsize { + self.0.dsize() } fn rank_in(&self) -> Rank { @@ -95,8 +93,8 @@ impl GGLWELayoutInfos for LWEToGLWESwitchingKey { self.0.rank_out() } - fn rows(&self) -> Rows { - self.0.rows() + fn dnum(&self) -> Dnum { + self.0.dnum() } } @@ -133,7 +131,7 @@ impl WriterTo for LWEToGLWESwitchingKey { impl LWEToGLWESwitchingKey> { pub fn alloc(infos: &A) -> Self where - A: GGLWELayoutInfos, + A: GGLWEInfos, { debug_assert_eq!( infos.rank_in().0, @@ -141,28 +139,28 @@ impl LWEToGLWESwitchingKey> { "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(infos: &A) -> usize where - A: GGLWELayoutInfos, + A: GGLWEInfos, { debug_assert_eq!( infos.rank_in().0, @@ -170,14 +168,14 @@ impl LWEToGLWESwitchingKey> { "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)) } } diff --git a/poulpy-core/src/layouts/mod.rs b/poulpy-core/src/layouts/mod.rs index a286201..2b13751 100644 --- a/poulpy-core/src/layouts/mod.rs +++ b/poulpy-core/src/layouts/mod.rs @@ -209,9 +209,9 @@ macro_rules! newtype_u32 { 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 { diff --git a/poulpy-core/src/layouts/prepared/gglwe_atk.rs b/poulpy-core/src/layouts/prepared/gglwe_atk.rs index 2a0fb3c..e350aaf 100644 --- a/poulpy-core/src/layouts/prepared/gglwe_atk.rs +++ b/poulpy-core/src/layouts/prepared/gglwe_atk.rs @@ -4,7 +4,7 @@ use poulpy_hal::{ }; 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 @@ impl GLWEInfos for GGLWEAutomorphismKeyPrepared { } } -impl GGLWELayoutInfos for GGLWEAutomorphismKeyPrepared { +impl GGLWEInfos for GGLWEAutomorphismKeyPrepared { fn rank_in(&self) -> Rank { self.key.rank_in() } @@ -53,19 +53,19 @@ impl GGLWELayoutInfos for GGLWEAutomorphismKeyPrepared 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 GGLWEAutomorphismKeyPrepared, B> { pub fn alloc(module: &Module, infos: &A) -> Self where - A: GGLWELayoutInfos, + A: GGLWEInfos, Module: VmpPMatAlloc, { assert_eq!( @@ -79,19 +79,19 @@ impl GGLWEAutomorphismKeyPrepared, B> { } } - pub fn alloc_with(module: &Module, base2k: Base2K, k: TorusPrecision, rows: Rows, digits: Digits, rank: Rank) -> Self + pub fn alloc_with(module: &Module, base2k: Base2K, k: TorusPrecision, rank: Rank, dnum: Dnum, dsize: Dsize) -> Self where Module: VmpPMatAlloc, { 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(module: &Module, infos: &A) -> usize where - A: GGLWELayoutInfos, + A: GGLWEInfos, Module: VmpPMatAllocBytes, { assert_eq!( @@ -102,18 +102,11 @@ impl GGLWEAutomorphismKeyPrepared, B> { GGLWESwitchingKeyPrepared::alloc_bytes(module, infos) } - pub fn alloc_bytes_with( - module: &Module, - base2k: Base2K, - k: TorusPrecision, - rows: Rows, - digits: Digits, - rank: Rank, - ) -> usize + pub fn alloc_bytes_with(module: &Module, base2k: Base2K, k: TorusPrecision, rank: Rank, dnum: Dnum, dsize: Dsize) -> usize where Module: VmpPMatAllocBytes, { - GGLWESwitchingKeyPrepared::alloc_bytes_with(module, base2k, k, rows, digits, rank, rank) + GGLWESwitchingKeyPrepared::alloc_bytes_with(module, base2k, k, rank, rank, dnum, dsize) } } diff --git a/poulpy-core/src/layouts/prepared/gglwe_ct.rs b/poulpy-core/src/layouts/prepared/gglwe_ct.rs index 70e183d..eeea3e8 100644 --- a/poulpy-core/src/layouts/prepared/gglwe_ct.rs +++ b/poulpy-core/src/layouts/prepared/gglwe_ct.rs @@ -5,7 +5,7 @@ use poulpy_hal::{ }; 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 { pub(crate) data: VmpPMat, pub(crate) k: TorusPrecision, pub(crate) base2k: Base2K, - pub(crate) digits: Digits, + pub(crate) dsize: Dsize, } impl LWEInfos for GGLWECiphertextPrepared { @@ -41,7 +41,7 @@ impl GLWEInfos for GGLWECiphertextPrepared { } } -impl GGLWELayoutInfos for GGLWECiphertextPrepared { +impl GGLWEInfos for GGLWECiphertextPrepared { fn rank_in(&self) -> Rank { Rank(self.data.cols_in() as u32) } @@ -50,12 +50,12 @@ impl GGLWELayoutInfos for GGLWECiphertextPrepared { 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 { data: Option>, base2k: Option, k: Option, - digits: Option, + dsize: Option, } impl GGLWECiphertextPrepared { @@ -73,7 +73,7 @@ impl GGLWECiphertextPrepared { data: None, base2k: None, k: None, - digits: None, + dsize: None, } } } @@ -82,19 +82,19 @@ impl GGLWECiphertextPreparedBuilder, B> { #[inline] pub fn layout(mut self, infos: &A) -> Self where - A: GGLWELayoutInfos, + A: GGLWEInfos, B: VmpPMatAllocBytesImpl, { 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 @@ impl GGLWECiphertextPreparedBuilder { } #[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 @@ impl GGLWECiphertextPreparedBuilder { let data: VmpPMat = 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 @@ impl GGLWECiphertextPreparedBuilder { data, base2k, k, - digits, + dsize, }) } } @@ -164,7 +164,7 @@ impl GGLWECiphertextPreparedBuilder { impl GGLWECiphertextPrepared, B> { pub fn alloc(module: &Module, infos: &A) -> Self where - A: GGLWELayoutInfos, + A: GGLWEInfos, Module: VmpPMatAlloc, { debug_assert_eq!(module.n(), infos.n().0 as usize, "module.n() != infos.n()"); @@ -172,10 +172,10 @@ impl GGLWECiphertextPrepared, B> { module, infos.base2k(), infos.k(), - infos.rows(), - infos.digits(), infos.rank_in(), infos.rank_out(), + infos.dnum(), + infos.dsize(), ) } @@ -183,39 +183,39 @@ impl GGLWECiphertextPrepared, B> { module: &Module, base2k: Base2K, k: TorusPrecision, - rows: Rows, - digits: Digits, rank_in: Rank, rank_out: Rank, + dnum: Dnum, + dsize: Dsize, ) -> Self where Module: VmpPMatAlloc, { 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(module: &Module, infos: &A) -> usize where - A: GGLWELayoutInfos, + A: GGLWEInfos, Module: VmpPMatAllocBytes, { debug_assert_eq!(module.n(), infos.n().0 as usize, "module.n() != infos.n()"); @@ -223,10 +223,10 @@ impl GGLWECiphertextPrepared, B> { module, infos.base2k(), infos.k(), - infos.rows(), - infos.digits(), infos.rank_in(), infos.rank_out(), + infos.dnum(), + infos.dsize(), ) } @@ -234,29 +234,29 @@ impl GGLWECiphertextPrepared, B> { module: &Module, base2k: Base2K, k: TorusPrecision, - rows: Rows, - digits: Digits, rank_in: Rank, rank_out: Rank, + dnum: Dnum, + dsize: Dsize, ) -> usize where Module: 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 @@ where 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; } } diff --git a/poulpy-core/src/layouts/prepared/gglwe_ksk.rs b/poulpy-core/src/layouts/prepared/gglwe_ksk.rs index 66198a6..5445c88 100644 --- a/poulpy-core/src/layouts/prepared/gglwe_ksk.rs +++ b/poulpy-core/src/layouts/prepared/gglwe_ksk.rs @@ -4,7 +4,7 @@ use poulpy_hal::{ }; 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 @@ impl GLWEInfos for GGLWESwitchingKeyPrepared { } } -impl GGLWELayoutInfos for GGLWESwitchingKeyPrepared { +impl GGLWEInfos for GGLWESwitchingKeyPrepared { fn rank_in(&self) -> Rank { self.key.rank_in() } @@ -48,19 +48,19 @@ impl GGLWELayoutInfos for GGLWESwitchingKeyPrepared { 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 GGLWESwitchingKeyPrepared, B> { pub fn alloc(module: &Module, infos: &A) -> Self where - A: GGLWELayoutInfos, + A: GGLWEInfos, Module: VmpPMatAlloc, { debug_assert_eq!(module.n() as u32, infos.n(), "module.n() != infos.n()"); @@ -75,16 +75,16 @@ impl GGLWESwitchingKeyPrepared, B> { module: &Module, base2k: Base2K, k: TorusPrecision, - rows: Rows, - digits: Digits, rank_in: Rank, rank_out: Rank, + dnum: Dnum, + dsize: Dsize, ) -> Self where Module: VmpPMatAlloc, { GGLWESwitchingKeyPrepared::, 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 @@ impl GGLWESwitchingKeyPrepared, B> { pub fn alloc_bytes(module: &Module, infos: &A) -> usize where - A: GGLWELayoutInfos, + A: GGLWEInfos, Module: VmpPMatAllocBytes, { debug_assert_eq!(module.n() as u32, infos.n(), "module.n() != infos.n()"); @@ -103,15 +103,15 @@ impl GGLWESwitchingKeyPrepared, B> { module: &Module, base2k: Base2K, k: TorusPrecision, - rows: Rows, - digits: Digits, rank_in: Rank, rank_out: Rank, + dnum: Dnum, + dsize: Dsize, ) -> usize where Module: 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) } } diff --git a/poulpy-core/src/layouts/prepared/gglwe_tsk.rs b/poulpy-core/src/layouts/prepared/gglwe_tsk.rs index 1d376ba..2efaeff 100644 --- a/poulpy-core/src/layouts/prepared/gglwe_tsk.rs +++ b/poulpy-core/src/layouts/prepared/gglwe_tsk.rs @@ -4,7 +4,7 @@ use poulpy_hal::{ }; 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 @@ impl GLWEInfos for GGLWETensorKeyPrepared { } } -impl GGLWELayoutInfos for GGLWETensorKeyPrepared { +impl GGLWEInfos for GGLWETensorKeyPrepared { fn rank_in(&self) -> Rank { self.rank_out() } @@ -46,19 +46,19 @@ impl GGLWELayoutInfos for GGLWETensorKeyPrepared { 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 GGLWETensorKeyPrepared, B> { pub fn alloc(module: &Module, infos: &A) -> Self where - A: GGLWELayoutInfos, + A: GGLWEInfos, Module: VmpPMatAlloc, { assert_eq!( @@ -70,13 +70,13 @@ impl GGLWETensorKeyPrepared, B> { module, infos.base2k(), infos.k(), - infos.rows(), - infos.digits(), + infos.dnum(), + infos.dsize(), infos.rank_out(), ) } - pub fn alloc_with(module: &Module, base2k: Base2K, k: TorusPrecision, rows: Rows, digits: Digits, rank: Rank) -> Self + pub fn alloc_with(module: &Module, base2k: Base2K, k: TorusPrecision, dnum: Dnum, dsize: Dsize, rank: Rank) -> Self where Module: VmpPMatAlloc, { @@ -87,10 +87,10 @@ impl GGLWETensorKeyPrepared, B> { module, base2k, k, - rows, - digits, Rank(1), rank, + dnum, + dsize, )); }); Self { keys } @@ -98,7 +98,7 @@ impl GGLWETensorKeyPrepared, B> { pub fn alloc_bytes(module: &Module, infos: &A) -> usize where - A: GGLWELayoutInfos, + A: GGLWEInfos, Module: VmpPMatAllocBytes, { assert_eq!( @@ -113,26 +113,19 @@ impl GGLWETensorKeyPrepared, B> { 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, - base2k: Base2K, - k: TorusPrecision, - rows: Rows, - digits: Digits, - rank: Rank, - ) -> usize + pub fn alloc_bytes_with(module: &Module, base2k: Base2K, k: TorusPrecision, rank: Rank, dnum: Dnum, dsize: Dsize) -> usize where Module: 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) } } diff --git a/poulpy-core/src/layouts/prepared/ggsw_ct.rs b/poulpy-core/src/layouts/prepared/ggsw_ct.rs index 1199ec2..117ae1e 100644 --- a/poulpy-core/src/layouts/prepared/ggsw_ct.rs +++ b/poulpy-core/src/layouts/prepared/ggsw_ct.rs @@ -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 { pub(crate) data: VmpPMat, pub(crate) k: TorusPrecision, pub(crate) base2k: Base2K, - pub(crate) digits: Digits, + pub(crate) dsize: Dsize, } impl LWEInfos for GGSWCiphertextPrepared { @@ -42,12 +42,12 @@ impl GLWEInfos for GGSWCiphertextPrepared { } impl GGSWInfos for GGSWCiphertextPrepared { - 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 { data: Option>, base2k: Option, k: Option, - digits: Option, + dsize: Option, } impl GGSWCiphertextPrepared { @@ -65,7 +65,7 @@ impl GGSWCiphertextPrepared { data: None, base2k: None, k: None, - digits: None, + dsize: None, } } } @@ -78,30 +78,30 @@ impl GGSWCiphertextPreparedBuilder, B> { B: VmpPMatAllocBytesImpl, { 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 @@ impl GGSWCiphertextPreparedBuilder { } #[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 @@ impl GGSWCiphertextPreparedBuilder { let data: VmpPMat = 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 @@ impl GGSWCiphertextPreparedBuilder { data, base2k, k, - digits, + dsize, }) } } @@ -178,40 +178,40 @@ impl GGSWCiphertextPrepared, B> { module, infos.base2k(), infos.k(), - infos.rows(), - infos.digits(), + infos.dnum(), + infos.dsize(), infos.rank(), ) } - pub fn alloc_with(module: &Module, base2k: Base2K, k: TorusPrecision, rows: Rows, digits: Digits, rank: Rank) -> Self + pub fn alloc_with(module: &Module, base2k: Base2K, k: TorusPrecision, dnum: Dnum, dsize: Dsize, rank: Rank) -> Self where Module: VmpPMatAlloc, { 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 @@ impl GGSWCiphertextPrepared, B> { module, infos.base2k(), infos.k(), - infos.rows(), - infos.digits(), + infos.dnum(), + infos.dsize(), infos.rank(), ) } - pub fn alloc_bytes_with( - module: &Module, - base2k: Base2K, - k: TorusPrecision, - rows: Rows, - digits: Digits, - rank: Rank, - ) -> usize + pub fn alloc_bytes_with(module: &Module, base2k: Base2K, k: TorusPrecision, dnum: Dnum, dsize: Dsize, rank: Rank) -> usize where Module: 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 @@ where 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 @@ where ggsw_prepared } } + +pub trait GGSWCiphertextPreparedToRef { + fn to_ref(&self) -> GGSWCiphertextPrepared<&[u8], B>; +} + +impl GGSWCiphertextPreparedToRef for GGSWCiphertextPrepared { + 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() + } +} diff --git a/poulpy-core/src/layouts/prepared/glwe_to_lwe_ksk.rs b/poulpy-core/src/layouts/prepared/glwe_to_lwe_ksk.rs index 8fa19d6..1993878 100644 --- a/poulpy-core/src/layouts/prepared/glwe_to_lwe_ksk.rs +++ b/poulpy-core/src/layouts/prepared/glwe_to_lwe_ksk.rs @@ -4,7 +4,7 @@ use poulpy_hal::{ }; 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 @@ impl GLWEInfos for GLWEToLWESwitchingKeyPrepared { } } -impl GGLWELayoutInfos for GLWEToLWESwitchingKeyPrepared { +impl GGLWEInfos for GLWEToLWESwitchingKeyPrepared { 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 GLWEToLWESwitchingKeyPrepared, B> { pub fn alloc(module: &Module, infos: &A) -> Self where - A: GGLWELayoutInfos, + A: GGLWEInfos, Module: VmpPMatAlloc, { debug_assert_eq!( @@ -65,14 +65,14 @@ impl GLWEToLWESwitchingKeyPrepared, B> { "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, base2k: Base2K, k: TorusPrecision, rows: Rows, rank_in: Rank) -> Self + pub fn alloc_with(module: &Module, base2k: Base2K, k: TorusPrecision, rank_in: Rank, dnum: Dnum) -> Self where Module: VmpPMatAlloc, { @@ -80,16 +80,16 @@ impl GLWEToLWESwitchingKeyPrepared, B> { module, base2k, k, - rows, - Digits(1), rank_in, Rank(1), + dnum, + Dsize(1), )) } pub fn alloc_bytes(module: &Module, infos: &A) -> usize where - A: GGLWELayoutInfos, + A: GGLWEInfos, Module: VmpPMatAllocBytes, { debug_assert_eq!( @@ -98,22 +98,22 @@ impl GLWEToLWESwitchingKeyPrepared, B> { "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, base2k: Base2K, k: TorusPrecision, rows: Rows, rank_in: Rank) -> usize + pub fn alloc_bytes_with(module: &Module, base2k: Base2K, k: TorusPrecision, rank_in: Rank, dnum: Dnum) -> usize where Module: 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 PrepareAlloc, B>> for GLWEToLWESwitchingKey +impl PrepareAlloc, B>> for GLWEToLWEKey where Module: VmpPrepare + VmpPMatAlloc, { @@ -124,11 +124,11 @@ where } } -impl Prepare> for GLWEToLWESwitchingKeyPrepared +impl Prepare> for GLWEToLWESwitchingKeyPrepared where Module: VmpPrepare, { - fn prepare(&mut self, module: &Module, other: &GLWEToLWESwitchingKey, scratch: &mut Scratch) { + fn prepare(&mut self, module: &Module, other: &GLWEToLWEKey, scratch: &mut Scratch) { self.0.prepare(module, &other.0, scratch); } } diff --git a/poulpy-core/src/layouts/prepared/lwe_ksk.rs b/poulpy-core/src/layouts/prepared/lwe_ksk.rs index 32c4fc3..9110dfb 100644 --- a/poulpy-core/src/layouts/prepared/lwe_ksk.rs +++ b/poulpy-core/src/layouts/prepared/lwe_ksk.rs @@ -4,7 +4,7 @@ use poulpy_hal::{ }; 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 @@ impl GLWEInfos for LWESwitchingKeyPrepared { } } -impl GGLWELayoutInfos for LWESwitchingKeyPrepared { - fn digits(&self) -> Digits { - self.0.digits() +impl GGLWEInfos for LWESwitchingKeyPrepared { + fn dsize(&self) -> Dsize { + self.0.dsize() } fn rank_in(&self) -> Rank { @@ -47,21 +47,21 @@ impl GGLWELayoutInfos for LWESwitchingKeyPrepared { self.0.rank_out() } - fn rows(&self) -> Rows { - self.0.rows() + fn dnum(&self) -> Dnum { + self.0.dnum() } } impl LWESwitchingKeyPrepared, B> { pub fn alloc(module: &Module, infos: &A) -> Self where - A: GGLWELayoutInfos, + A: GGLWEInfos, Module: VmpPMatAlloc, { 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 @@ impl LWESwitchingKeyPrepared, B> { Self(GGLWESwitchingKeyPrepared::alloc(module, infos)) } - pub fn alloc_with(module: &Module, base2k: Base2K, k: TorusPrecision, rows: Rows) -> Self + pub fn alloc_with(module: &Module, base2k: Base2K, k: TorusPrecision, dnum: Dnum) -> Self where Module: VmpPMatAlloc, { @@ -84,22 +84,22 @@ impl LWESwitchingKeyPrepared, B> { module, base2k, k, - rows, - Digits(1), Rank(1), Rank(1), + dnum, + Dsize(1), )) } pub fn alloc_bytes(module: &Module, infos: &A) -> usize where - A: GGLWELayoutInfos, + A: GGLWEInfos, Module: 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 @@ impl LWESwitchingKeyPrepared, B> { GGLWESwitchingKeyPrepared::alloc_bytes(module, infos) } - pub fn alloc_bytes_with(module: &Module, base2k: Base2K, k: TorusPrecision, rows: Rows) -> usize + pub fn alloc_bytes_with(module: &Module, base2k: Base2K, k: TorusPrecision, dnum: Dnum) -> usize where Module: 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)) } } diff --git a/poulpy-core/src/layouts/prepared/lwe_to_glwe_ksk.rs b/poulpy-core/src/layouts/prepared/lwe_to_glwe_ksk.rs index 75c0e79..010ba6d 100644 --- a/poulpy-core/src/layouts/prepared/lwe_to_glwe_ksk.rs +++ b/poulpy-core/src/layouts/prepared/lwe_to_glwe_ksk.rs @@ -4,7 +4,7 @@ use poulpy_hal::{ }; 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 @@ impl GLWEInfos for LWEToGLWESwitchingKeyPrepared { } } -impl GGLWELayoutInfos for LWEToGLWESwitchingKeyPrepared { - fn digits(&self) -> Digits { - self.0.digits() +impl GGLWEInfos for LWEToGLWESwitchingKeyPrepared { + fn dsize(&self) -> Dsize { + self.0.dsize() } fn rank_in(&self) -> Rank { @@ -49,15 +49,15 @@ impl GGLWELayoutInfos for LWEToGLWESwitchingKeyPrepared Rows { - self.0.rows() + fn dnum(&self) -> Dnum { + self.0.dnum() } } impl LWEToGLWESwitchingKeyPrepared, B> { pub fn alloc(module: &Module, infos: &A) -> Self where - A: GGLWELayoutInfos, + A: GGLWEInfos, Module: VmpPMatAlloc, { debug_assert_eq!( @@ -66,14 +66,14 @@ impl LWEToGLWESwitchingKeyPrepared, B> { "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, base2k: Base2K, k: TorusPrecision, rows: Rows, rank_out: Rank) -> Self + pub fn alloc_with(module: &Module, base2k: Base2K, k: TorusPrecision, rank_out: Rank, dnum: Dnum) -> Self where Module: VmpPMatAlloc, { @@ -81,16 +81,16 @@ impl LWEToGLWESwitchingKeyPrepared, B> { module, base2k, k, - rows, - Digits(1), Rank(1), rank_out, + dnum, + Dsize(1), )) } pub fn alloc_bytes(module: &Module, infos: &A) -> usize where - A: GGLWELayoutInfos, + A: GGLWEInfos, Module: VmpPMatAllocBytes, { debug_assert_eq!( @@ -99,18 +99,18 @@ impl LWEToGLWESwitchingKeyPrepared, B> { "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, base2k: Base2K, k: TorusPrecision, rows: Rows, rank_out: Rank) -> usize + pub fn alloc_bytes_with(module: &Module, base2k: Base2K, k: TorusPrecision, dnum: Dnum, rank_out: Rank) -> usize where Module: 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)) } } diff --git a/poulpy-core/src/lib.rs b/poulpy-core/src/lib.rs index d490742..70035af 100644 --- a/poulpy-core/src/lib.rs +++ b/poulpy-core/src/lib.rs @@ -15,6 +15,7 @@ mod utils; pub use operations::*; pub mod layouts; pub use dist::*; +pub use external_product::*; pub use glwe_packing::*; pub use encryption::SIGMA; diff --git a/poulpy-core/src/noise/gglwe_ct.rs b/poulpy-core/src/noise/gglwe_ct.rs index dc0593e..0712b7f 100644 --- a/poulpy-core/src/noise/gglwe_ct.rs +++ b/poulpy-core/src/noise/gglwe_ct.rs @@ -8,7 +8,7 @@ use poulpy_hal::{ 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 GGLWECiphertext { pub fn assert_noise( @@ -32,24 +32,18 @@ impl GGLWECiphertext { + VecZnxSubScalarInplace, B: Backend + TakeVecZnxDftImpl + TakeVecZnxBigImpl + ScratchOwnedAllocImpl + ScratchOwnedBorrowImpl, { - let digits: usize = self.digits().into(); + let dsize: usize = self.dsize().into(); let base2k: usize = self.base2k().into(); let mut scratch: ScratchOwned = ScratchOwned::alloc(GLWECiphertext::decrypt_scratch_space(module, self)); let mut pt: GLWEPlaintext> = 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(); diff --git a/poulpy-core/src/noise/ggsw_ct.rs b/poulpy-core/src/noise/ggsw_ct.rs index dc156d2..03bb0c0 100644 --- a/poulpy-core/src/noise/ggsw_ct.rs +++ b/poulpy-core/src/noise/ggsw_ct.rs @@ -42,7 +42,7 @@ impl GGSWCiphertext { 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> = GLWEPlaintext::alloc(self); let mut pt_have: GLWEPlaintext> = GLWEPlaintext::alloc(self); @@ -53,8 +53,8 @@ impl GGSWCiphertext { 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 @@ impl GGSWCiphertext { B: Backend + TakeVecZnxDftImpl + TakeVecZnxBigImpl + ScratchOwnedAllocImpl + ScratchOwnedBorrowImpl, { let base2k: usize = self.base2k().into(); - let digits: usize = self.digits().into(); + let dsize: usize = self.dsize().into(); let mut pt: GLWEPlaintext> = GLWEPlaintext::alloc(self); let mut pt_have: GLWEPlaintext> = GLWEPlaintext::alloc(self); @@ -125,8 +125,8 @@ impl GGSWCiphertext { 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 @@ impl GGSWCiphertext { 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!(">>>>>>>>>>>>>>>>"); }); }); } diff --git a/poulpy-core/src/noise/glwe_ct.rs b/poulpy-core/src/noise/glwe_ct.rs index c1e4f3a..f7af2a1 100644 --- a/poulpy-core/src/noise/glwe_ct.rs +++ b/poulpy-core/src/noise/glwe_ct.rs @@ -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 GLWECiphertext { + pub fn noise( + &self, + module: &Module, + sk_prepared: &GLWESecretPrepared, + pt_want: &GLWEPlaintext, + scratch: &mut Scratch, + ) -> f64 + where + DataSk: DataRef, + DataPt: DataRef, + B: Backend, + Module: VecZnxDftApply + + VecZnxSubInplace + + VecZnxNormalizeInplace + + SvpApplyDftToDftInplace + + VecZnxIdftApplyConsume + + VecZnxBigAddInplace + + VecZnxBigAddSmallInplace + + VecZnxBigNormalize, + Scratch: TakeVecZnxDft + TakeVecZnxBig, + { + let mut pt_have: GLWEPlaintext> = 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( &self, module: &Module, @@ -33,16 +61,8 @@ impl GLWECiphertext { + VecZnxNormalizeInplace, B: Backend + TakeVecZnxDftImpl + TakeVecZnxBigImpl + ScratchOwnedAllocImpl + ScratchOwnedBorrowImpl, { - let mut pt_have: GLWEPlaintext> = GLWEPlaintext::alloc(self); - let mut scratch: ScratchOwned = 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}"); } } diff --git a/poulpy-core/src/scratch.rs b/poulpy-core/src/scratch.rs index a570e66..f1676d7 100644 --- a/poulpy-core/src/scratch.rs +++ b/poulpy-core/src/scratch.rs @@ -6,8 +6,8 @@ use poulpy_hal::{ 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 TakeGLWEPt { pub trait TakeGGLWE { fn take_gglwe(&mut self, infos: &A) -> (GGLWECiphertext<&mut [u8]>, &mut Self) where - A: GGLWELayoutInfos; + A: GGLWEInfos; } pub trait TakeGGLWEPrepared { fn take_gglwe_prepared(&mut self, infos: &A) -> (GGLWECiphertextPrepared<&mut [u8], B>, &mut Self) where - A: GGLWELayoutInfos; + A: GGLWEInfos; } pub trait TakeGGSW { @@ -80,37 +80,37 @@ pub trait TakeGLWEPkPrepared { pub trait TakeGLWESwitchingKey { fn take_glwe_switching_key(&mut self, infos: &A) -> (GGLWESwitchingKey<&mut [u8]>, &mut Self) where - A: GGLWELayoutInfos; + A: GGLWEInfos; } pub trait TakeGGLWESwitchingKeyPrepared { fn take_gglwe_switching_key_prepared(&mut self, infos: &A) -> (GGLWESwitchingKeyPrepared<&mut [u8], B>, &mut Self) where - A: GGLWELayoutInfos; + A: GGLWEInfos; } pub trait TakeTensorKey { fn take_tensor_key(&mut self, infos: &A) -> (GGLWETensorKey<&mut [u8]>, &mut Self) where - A: GGLWELayoutInfos; + A: GGLWEInfos; } pub trait TakeGGLWETensorKeyPrepared { fn take_gglwe_tensor_key_prepared(&mut self, infos: &A) -> (GGLWETensorKeyPrepared<&mut [u8], B>, &mut Self) where - A: GGLWELayoutInfos; + A: GGLWEInfos; } pub trait TakeGGLWEAutomorphismKey { fn take_gglwe_automorphism_key(&mut self, infos: &A) -> (GGLWEAutomorphismKey<&mut [u8]>, &mut Self) where - A: GGLWELayoutInfos; + A: GGLWEInfos; } pub trait TakeGGLWEAutomorphismKeyPrepared { fn take_gglwe_automorphism_key_prepared(&mut self, infos: &A) -> (GGLWEAutomorphismKeyPrepared<&mut [u8], B>, &mut Self) where - A: GGLWELayoutInfos; + A: GGLWEInfos; } impl TakeGLWECt for Scratch @@ -180,11 +180,11 @@ where { fn take_gglwe(&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 @@ where GGLWECiphertext::builder() .base2k(infos.base2k()) .k(infos.k()) - .digits(infos.digits()) + .dsize(infos.dsize()) .data(data) .build() .unwrap(), @@ -208,11 +208,11 @@ where { fn take_gglwe_prepared(&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 @@ where ( GGLWECiphertextPrepared::builder() .base2k(infos.base2k()) - .digits(infos.digits()) + .dsize(infos.dsize()) .k(infos.k()) .data(data) .build() @@ -240,7 +240,7 @@ where { 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 @@ where ( GGSWCiphertext::builder() .base2k(infos.base2k()) - .digits(infos.digits()) + .dsize(infos.dsize()) .k(infos.k()) .data(data) .build() @@ -268,7 +268,7 @@ where { 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 @@ where ( GGSWCiphertextPrepared::builder() .base2k(infos.base2k()) - .digits(infos.digits()) + .dsize(infos.dsize()) .k(infos.k()) .data(data) .build() @@ -367,7 +367,7 @@ where { fn take_glwe_switching_key(&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 @@ where { fn take_gglwe_switching_key_prepared(&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 @@ where { fn take_gglwe_automorphism_key(&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 @@ where { fn take_gglwe_automorphism_key_prepared(&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 @@ where { fn take_tensor_key(&mut self, infos: &A) -> (GGLWETensorKey<&mut [u8]>, &mut Self) where - A: GGLWELayoutInfos, + A: GGLWEInfos, { assert_eq!( infos.rank_in(), @@ -468,7 +468,7 @@ where { fn take_gglwe_tensor_key_prepared(&mut self, infos: &A) -> (GGLWETensorKeyPrepared<&mut [u8], B>, &mut Self) where - A: GGLWELayoutInfos, + A: GGLWEInfos, { assert_eq!( infos.rank_in(), diff --git a/poulpy-core/src/tests/serialization.rs b/poulpy-core/src/tests/serialization.rs index fc0ee7d..8fe477c 100644 --- a/poulpy-core/src/tests/serialization.rs +++ b/poulpy-core/src/tests/serialization.rs @@ -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 @@ fn lwe_compressed_serialization() { #[test] fn test_gglwe_serialization() { - let original: GGLWECiphertext> = GGLWECiphertext::alloc_with(N_GLWE, BASE2K, K, ROWS, DIGITS, RANK, RANK); + let original: GGLWECiphertext> = 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> = - 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> = GGLWESwitchingKey::alloc_with(N_GLWE, BASE2K, K, ROWS, DIGITS, RANK, RANK); + let original: GGLWESwitchingKey> = 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> = - 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> = GGLWEAutomorphismKey::alloc_with(N_GLWE, BASE2K, K, ROWS, DIGITS, RANK); + let original: GGLWEAutomorphismKey> = 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> = - 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> = GGLWETensorKey::alloc_with(N_GLWE, BASE2K, K, ROWS, DIGITS, RANK); + let original: GGLWETensorKey> = 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> = GGLWETensorKeyCompressed::alloc_with(N_GLWE, BASE2K, K, ROWS, DIGITS, RANK); + let original: GGLWETensorKeyCompressed> = 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> = GLWEToLWESwitchingKey::alloc_with(N_GLWE, BASE2K, K, ROWS, RANK); + let original: GLWEToLWEKey> = 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> = - 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> = LWEToGLWESwitchingKey::alloc_with(N_GLWE, BASE2K, K, ROWS, RANK); + let original: LWEToGLWESwitchingKey> = 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> = - 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> = LWESwitchingKey::alloc_with(N_GLWE, BASE2K, K, ROWS); + let original: LWESwitchingKey> = LWESwitchingKey::alloc_with(N_GLWE, BASE2K, K, DNUM); test_reader_writer_interface(original); } #[test] fn lwe_switching_key_compressed_serialization() { - let original: LWESwitchingKeyCompressed> = LWESwitchingKeyCompressed::alloc_with(N_GLWE, BASE2K, K, ROWS); + let original: LWESwitchingKeyCompressed> = LWESwitchingKeyCompressed::alloc_with(N_GLWE, BASE2K, K, DNUM); test_reader_writer_interface(original); } #[test] fn ggsw_serialization() { - let original: GGSWCiphertext> = GGSWCiphertext::alloc_with(N_GLWE, BASE2K, K, ROWS, DIGITS, RANK); + let original: GGSWCiphertext> = GGSWCiphertext::alloc_with(N_GLWE, BASE2K, K, RANK, DNUM, DSIZE); test_reader_writer_interface(original); } #[test] fn ggsw_compressed_serialization() { - let original: GGSWCiphertextCompressed> = GGSWCiphertextCompressed::alloc_with(N_GLWE, BASE2K, K, ROWS, DIGITS, RANK); + let original: GGSWCiphertextCompressed> = GGSWCiphertextCompressed::alloc_with(N_GLWE, BASE2K, K, RANK, DNUM, DSIZE); test_reader_writer_interface(original); } diff --git a/poulpy-core/src/tests/test_suite/automorphism/gglwe_atk.rs b/poulpy-core/src/tests/test_suite/automorphism/gglwe_atk.rs index 0da77c4..1dd3e58 100644 --- a/poulpy-core/src/tests/test_suite/automorphism/gglwe_atk.rs +++ b/poulpy-core/src/tests/test_suite/automorphism/gglwe_atk.rs @@ -18,7 +18,7 @@ use poulpy_hal::{ 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 @@ where 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 @@ where 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 @@ where 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 @@ where let sk_auto_dft: GLWESecretPrepared, 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 @@ where 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 @@ where { 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 @@ where 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 @@ where let sk_auto_dft: GLWESecretPrepared, 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, ); diff --git a/poulpy-core/src/tests/test_suite/automorphism/ggsw_ct.rs b/poulpy-core/src/tests/test_suite/automorphism/ggsw_ct.rs index 90c53d6..2fd7151 100644 --- a/poulpy-core/src/tests/test_suite/automorphism/ggsw_ct.rs +++ b/poulpy-core/src/tests/test_suite/automorphism/ggsw_ct.rs @@ -77,27 +77,27 @@ where { 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 @@ where 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 @@ where 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 @@ where 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 @@ where { 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 @@ where 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 @@ where 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(), }; diff --git a/poulpy-core/src/tests/test_suite/automorphism/glwe_ct.rs b/poulpy-core/src/tests/test_suite/automorphism/glwe_ct.rs index 1a52bdd..5828c48 100644 --- a/poulpy-core/src/tests/test_suite/automorphism/glwe_ct.rs +++ b/poulpy-core/src/tests/test_suite/automorphism/glwe_ct.rs @@ -67,15 +67,15 @@ where { 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 @@ where 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> = GGLWEAutomorphismKey::alloc(&autokey_infos); @@ -148,7 +148,7 @@ where 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 @@ where { 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 @@ where 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> = GGLWEAutomorphismKey::alloc(&autokey_infos); @@ -282,7 +282,7 @@ where let max_noise: f64 = log2_std_noise_gglwe_product( module.n() as f64, - base2k * digits, + base2k * dsize, 0.5, 0.5, 0f64, diff --git a/poulpy-core/src/tests/test_suite/conversion.rs b/poulpy-core/src/tests/test_suite/conversion.rs index 6e82cd7..c2c81dc 100644 --- a/poulpy-core/src/tests/test_suite/conversion.rs +++ b/poulpy-core/src/tests/test_suite/conversion.rs @@ -16,9 +16,9 @@ use poulpy_hal::{ }; 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 @@ where n: n_glwe, base2k: Base2K(17), k: TorusPrecision(51), - rows: Rows(2), + dnum: Dnum(2), rank_out: rank, }; @@ -188,11 +188,11 @@ where 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 @@ where let mut source_xe: Source = Source::new([0u8; 32]); let mut scratch: ScratchOwned = 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 @@ where scratch.borrow(), ); - let mut ksk: GLWEToLWESwitchingKey> = GLWEToLWESwitchingKey::alloc(&glwe_to_lwe_infos); + let mut ksk: GLWEToLWEKey> = GLWEToLWEKey::alloc(&glwe_to_lwe_infos); ksk.encrypt_sk( module, diff --git a/poulpy-core/src/tests/test_suite/encryption/gglwe_atk.rs b/poulpy-core/src/tests/test_suite/encryption/gglwe_atk.rs index 717a639..e9b7c93 100644 --- a/poulpy-core/src/tests/test_suite/encryption/gglwe_atk.rs +++ b/poulpy-core/src/tests/test_suite/encryption/gglwe_atk.rs @@ -69,18 +69,18 @@ where { 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 @@ where { 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(), }; diff --git a/poulpy-core/src/tests/test_suite/encryption/gglwe_ct.rs b/poulpy-core/src/tests/test_suite/encryption/gglwe_ct.rs index d8ba73a..60bb7e2 100644 --- a/poulpy-core/src/tests/test_suite/encryption/gglwe_ct.rs +++ b/poulpy-core/src/tests/test_suite/encryption/gglwe_ct.rs @@ -64,19 +64,19 @@ where { 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 @@ where { 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(), }; diff --git a/poulpy-core/src/tests/test_suite/encryption/ggsw_ct.rs b/poulpy-core/src/tests/test_suite/encryption/ggsw_ct.rs index 8c29bda..9eacf38 100644 --- a/poulpy-core/src/tests/test_suite/encryption/ggsw_ct.rs +++ b/poulpy-core/src/tests/test_suite/encryption/ggsw_ct.rs @@ -67,18 +67,18 @@ where { 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 @@ where { 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(), }; diff --git a/poulpy-core/src/tests/test_suite/encryption/glwe_tsk.rs b/poulpy-core/src/tests/test_suite/encryption/glwe_tsk.rs index d373278..8bb9730 100644 --- a/poulpy-core/src/tests/test_suite/encryption/glwe_tsk.rs +++ b/poulpy-core/src/tests/test_suite/encryption/glwe_tsk.rs @@ -17,7 +17,7 @@ use poulpy_hal::{ 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 @@ where 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 @@ where 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 @@ where 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 @@ where 0, scratch.borrow(), ); - for row_i in 0..rows { + for row_i in 0..dnum { tensor_key .at(i, j) .at(row_i, 0) diff --git a/poulpy-core/src/tests/test_suite/external_product/gglwe_ksk.rs b/poulpy-core/src/tests/test_suite/external_product/gglwe_ksk.rs index b2f8f91..2cfa618 100644 --- a/poulpy-core/src/tests/test_suite/external_product/gglwe_ksk.rs +++ b/poulpy-core/src/tests/test_suite/external_product/gglwe_ksk.rs @@ -70,23 +70,23 @@ where { 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 @@ where 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 @@ where 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 @@ where { 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 @@ where 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(), }; diff --git a/poulpy-core/src/tests/test_suite/external_product/ggsw_ct.rs b/poulpy-core/src/tests/test_suite/external_product/ggsw_ct.rs index bf5ceb5..464eac2 100644 --- a/poulpy-core/src/tests/test_suite/external_product/ggsw_ct.rs +++ b/poulpy-core/src/tests/test_suite/external_product/ggsw_ct.rs @@ -72,24 +72,24 @@ where { 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 @@ where 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 @@ where 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 @@ where { 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 @@ where 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(), }; diff --git a/poulpy-core/src/tests/test_suite/external_product/glwe_ct.rs b/poulpy-core/src/tests/test_suite/external_product/glwe_ct.rs index 62a3d7c..1a21a0c 100644 --- a/poulpy-core/src/tests/test_suite/external_product/glwe_ct.rs +++ b/poulpy-core/src/tests/test_suite/external_product/glwe_ct.rs @@ -64,14 +64,14 @@ where { 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 @@ where 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 @@ where 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 @@ where { 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 @@ where 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 @@ where let max_noise: f64 = noise_ggsw_product( n as f64, - base2k * digits, + base2k * dsize, 0.5, var_msg, var_a0_err, diff --git a/poulpy-core/src/tests/test_suite/keyswitch/gglwe_ct.rs b/poulpy-core/src/tests/test_suite/keyswitch/gglwe_ct.rs index 637c5a6..f131556 100644 --- a/poulpy-core/src/tests/test_suite/keyswitch/gglwe_ct.rs +++ b/poulpy-core/src/tests/test_suite/keyswitch/gglwe_ct.rs @@ -66,26 +66,26 @@ where { 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 @@ where 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 @@ where 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 @@ where { 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 @@ where 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(), }; diff --git a/poulpy-core/src/tests/test_suite/keyswitch/ggsw_ct.rs b/poulpy-core/src/tests/test_suite/keyswitch/ggsw_ct.rs index 21be8e7..c7e7c82 100644 --- a/poulpy-core/src/tests/test_suite/keyswitch/ggsw_ct.rs +++ b/poulpy-core/src/tests/test_suite/keyswitch/ggsw_ct.rs @@ -73,24 +73,24 @@ where { 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 @@ where 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 @@ where 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 @@ where 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 @@ where { 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 @@ where 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 @@ where 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(), }; diff --git a/poulpy-core/src/tests/test_suite/keyswitch/glwe_ct.rs b/poulpy-core/src/tests/test_suite/keyswitch/glwe_ct.rs index ca8c914..d745f1d 100644 --- a/poulpy-core/src/tests/test_suite/keyswitch/glwe_ct.rs +++ b/poulpy-core/src/tests/test_suite/keyswitch/glwe_ct.rs @@ -66,16 +66,16 @@ where { 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 @@ where 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 @@ where 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 @@ where { 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 @@ where 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 @@ where let max_noise: f64 = log2_std_noise_gglwe_product( module.n() as f64, - base2k * digits, + base2k * dsize, 0.5, 0.5, 0f64, diff --git a/poulpy-core/src/tests/test_suite/keyswitch/lwe_ct.rs b/poulpy-core/src/tests/test_suite/keyswitch/lwe_ct.rs index 0badc86..1c29c70 100644 --- a/poulpy-core/src/tests/test_suite/keyswitch/lwe_ct.rs +++ b/poulpy-core/src/tests/test_suite/keyswitch/lwe_ct.rs @@ -73,7 +73,7 @@ where 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 @@ where n: n.into(), base2k: base2k.into(), k: k_ksk.into(), - rows: rows.into(), + dnum: dnum.into(), }; let lwe_in_infos: LWECiphertextLayout = LWECiphertextLayout { diff --git a/poulpy-core/src/tests/test_suite/packing.rs b/poulpy-core/src/tests/test_suite/packing.rs index 248f95d..de7fc9d 100644 --- a/poulpy-core/src/tests/test_suite/packing.rs +++ b/poulpy-core/src/tests/test_suite/packing.rs @@ -83,10 +83,10 @@ where 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 @@ where 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 = ScratchOwned::alloc( diff --git a/poulpy-core/src/tests/test_suite/trace.rs b/poulpy-core/src/tests/test_suite/trace.rs index 20dc5e7..bf348ca 100644 --- a/poulpy-core/src/tests/test_suite/trace.rs +++ b/poulpy-core/src/tests/test_suite/trace.rs @@ -80,8 +80,8 @@ where 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 @@ where 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> = GLWECiphertext::alloc(&glwe_out_infos); diff --git a/poulpy-hal/src/reference/znx/arithmetic_ref.rs b/poulpy-hal/src/reference/znx/arithmetic_ref.rs index 9955b94..9e9731d 100644 --- a/poulpy-hal/src/reference/znx/arithmetic_ref.rs +++ b/poulpy-hal/src/reference/znx/arithmetic_ref.rs @@ -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 @@ use crate::reference::znx::{ 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 {} @@ -29,6 +29,13 @@ impl ZnxAdd for ZnxRef { } } +impl ZnxRotate for ZnxRef { + #[inline(always)] + fn znx_rotate(p: i64, res: &mut [i64], src: &[i64]) { + znx_rotate::(p, res, src); + } +} + impl ZnxAddInplace for ZnxRef { #[inline(always)] fn znx_add_inplace(res: &mut [i64], a: &[i64]) { diff --git a/poulpy-schemes/Cargo.toml b/poulpy-schemes/Cargo.toml index 9afa99e..d36e156 100644 --- a/poulpy-schemes/Cargo.toml +++ b/poulpy-schemes/Cargo.toml @@ -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" diff --git a/poulpy-schemes/benches/circuit_bootstrapping.rs b/poulpy-schemes/benches/circuit_bootstrapping.rs index d056938..47c848e 100644 --- a/poulpy-schemes/benches/circuit_bootstrapping.rs +++ b/poulpy-schemes/benches/circuit_bootstrapping.rs @@ -3,7 +3,7 @@ use std::hint::black_box; 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 @@ use poulpy_hal::{ }, 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 @@ where + TakeVecZnxBigImpl + TakeVecZnxDftSliceImpl + TakeMatZnxImpl - + TakeVecZnxSliceImpl, + + TakeVecZnxSliceImpl + + TakeSliceImpl, BlindRotationKey, BRA>: PrepareAlloc, BRA, B>>, BlindRotationKeyPrepared, BRA, B>: BlincRotationExecute, BlindRotationKey, BRA>: BlindRotationKeyAlloc + BlindRotationKeyEncryptSk, @@ -178,7 +179,8 @@ where + TakeVecZnxBigImpl + TakeVecZnxDftSliceImpl + TakeMatZnxImpl - + TakeVecZnxSliceImpl, + + TakeVecZnxSliceImpl + + TakeSliceImpl, BlindRotationKey, BRA>: PrepareAlloc, BRA, B>>, BlindRotationKeyPrepared, BRA, B>: BlincRotationExecute, BlindRotationKey, BRA>: BlindRotationKeyAlloc + BlindRotationKeyEncryptSk, @@ -246,8 +248,8 @@ where 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 @@ where 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(), }, }, diff --git a/poulpy-schemes/examples/circuit_bootstrapping.rs b/poulpy-schemes/examples/circuit_bootstrapping.rs index b208287..4fec699 100644 --- a/poulpy-schemes/examples/circuit_bootstrapping.rs +++ b/poulpy-schemes/examples/circuit_bootstrapping.rs @@ -56,25 +56,25 @@ fn main() { // 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 @@ fn main() { 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 @@ fn main() { 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(), }; diff --git a/poulpy-schemes/src/tfhe/bdd_arithmetic/bdd_2w_to_1w.rs b/poulpy-schemes/src/tfhe/bdd_arithmetic/bdd_2w_to_1w.rs new file mode 100644 index 0000000..3836067 --- /dev/null +++ b/poulpy-schemes/src/tfhe/bdd_arithmetic/bdd_2w_to_1w.rs @@ -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(pub &'static Circuit); + +pub trait EvalBDD2WTo1W { + fn eval_bdd_2w_to_1w( + &self, + module: &Module, + out: &mut FheUintBlocks, + a: &FheUintBlocksPrep, + b: &FheUintBlocksPrep, + scratch: &mut Scratch, + ) where + R: DataMut, + A: DataRef, + B: DataRef; +} + +impl EvalBDD2WTo1W + for Circuits2WTo1W +where + Circuit: CircuitExecute, +{ + fn eval_bdd_2w_to_1w( + &self, + module: &Module, + out: &mut FheUintBlocks, + a: &FheUintBlocksPrep, + b: &FheUintBlocksPrep, + scratch: &mut Scratch, + ) 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, BE: Backend>( + module: &Module, + circuit: &C, + out: &mut FheUintBlocks, + a: &FheUintBlocksPrep, + b: &FheUintBlocksPrep, + scratch: &mut Scratch, +) { + #[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> = a + .blocks + .iter() + .map(|x| x as &dyn GGSWCiphertextPreparedToRef) + .chain( + b.blocks + .iter() + .map(|x| x as &dyn GGSWCiphertextPreparedToRef), + ) + .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 { + fn $method_name( + &mut self, + module: &Module, + a: &FheUintBlocksPrep, + b: &FheUintBlocksPrep, + scratch: &mut Scratch, + ) 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 $trait_name<$ty, BE> for FheUintBlocks + where + Circuits2WTo1W<$circuit_ty, $n>: EvalBDD2WTo1W, + { + fn $method_name( + &mut self, + module: &Module, + a: &FheUintBlocksPrep, + b: &FheUintBlocksPrep, + scratch: &mut Scratch, + ) 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 +); diff --git a/poulpy-schemes/src/tfhe/bdd_arithmetic/ciphertexts/block.rs b/poulpy-schemes/src/tfhe/bdd_arithmetic/ciphertexts/block.rs new file mode 100644 index 0000000..145ce6b --- /dev/null +++ b/poulpy-schemes/src/tfhe/bdd_arithmetic/ciphertexts/block.rs @@ -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 { + pub(crate) blocks: Vec>, + pub(crate) _base: u8, + pub(crate) _phantom: PhantomData, +} + +impl LWEInfos for FheUintBlocks { + 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 GLWEInfos for FheUintBlocks { + fn rank(&self) -> poulpy_core::layouts::Rank { + self.blocks[0].rank() + } +} + +impl FheUintBlocks, T> { + #[allow(dead_code)] + pub(crate) fn alloc(module: &Module, infos: &A) -> Self + where + A: GLWEInfos, + { + Self::alloc_with(module, infos.base2k(), infos.k(), infos.rank()) + } + + #[allow(dead_code)] + pub(crate) fn alloc_with(module: &Module, 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 FheUintBlocks { + #[allow(dead_code)] + #[cfg(test)] + pub(crate) fn encrypt_sk( + &mut self, + module: &Module, + value: T, + sk: &GLWESecretPrepared, + source_xa: &mut Source, + source_xe: &mut Source, + scratch: &mut Scratch, + ) where + S: DataRef, + Module: VecZnxDftAllocBytes + + VecZnxBigNormalize + + VecZnxDftApply + + SvpApplyDftToDftInplace + + VecZnxIdftApplyConsume + + VecZnxNormalizeTmpBytes + + VecZnxFillUniform + + VecZnxSubInplace + + VecZnxAddInplace + + VecZnxNormalizeInplace + + VecZnxAddNormal + + VecZnxNormalize + + VecZnxSub, + Scratch: TakeVecZnxDft + ScratchAvailable + TakeVecZnx + TakeGLWEPt, + { + 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 FheUintBlocks { + pub fn decrypt( + &self, + module: &Module, + sk: &GLWESecretPrepared, + scratch: &mut Scratch, + ) -> T + where + Module: VecZnxDftApply + + SvpApplyDftToDftInplace + + VecZnxIdftApplyConsume + + VecZnxBigAddInplace + + VecZnxBigAddSmallInplace + + VecZnxBigNormalize, + Scratch: TakeVecZnxDft + TakeVecZnxBig + TakeGLWEPt, + { + #[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 = 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( + &self, + module: &Module, + sk: &GLWESecretPrepared, + want: T, + scratch: &mut Scratch, + ) -> Vec + where + Module: VecZnxDftAllocBytes + + VecZnxBigAllocBytes + + VecZnxDftApply + + SvpApplyDftToDftInplace + + VecZnxIdftApplyConsume + + VecZnxBigAddInplace + + VecZnxBigAddSmallInplace + + VecZnxBigNormalize + + VecZnxNormalizeTmpBytes + + VecZnxSubInplace + + VecZnxNormalizeInplace, + Scratch: TakeGLWEPt + TakeVecZnxDft + TakeVecZnxBig, + { + #[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 = 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 + } +} diff --git a/poulpy-schemes/src/tfhe/bdd_arithmetic/ciphertexts/block_prepared.rs b/poulpy-schemes/src/tfhe/bdd_arithmetic/ciphertexts/block_prepared.rs new file mode 100644 index 0000000..3cd50a6 --- /dev/null +++ b/poulpy-schemes/src/tfhe/bdd_arithmetic/ciphertexts/block_prepared.rs @@ -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 { + pub(crate) blocks: Vec>, + pub(crate) _base: u8, + pub(crate) _phantom: PhantomData, +} + +#[cfg(test)] +impl FheUintBlocksPrepDebug, T> { + #[allow(dead_code)] + pub(crate) fn alloc(module: &Module, 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, + 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 { + pub(crate) blocks: Vec>, + pub(crate) _base: u8, + pub(crate) _phantom: PhantomData, +} + +impl FheUintBlocksPrep, BE, T> +where + Module: VmpPMatAlloc, +{ + #[allow(dead_code)] + pub(crate) fn alloc(module: &Module, 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, base2k: Base2K, k: TorusPrecision, dnum: Dnum, dsize: Dsize, rank: Rank) -> Self + where + Module: VmpPMatAlloc, + { + Self { + blocks: (0..T::WORD_SIZE) + .map(|_| GGSWCiphertextPrepared::alloc_with(module, base2k, k, dnum, dsize, rank)) + .collect(), + _base: 1, + _phantom: PhantomData, + } + } +} + +impl FheUintBlocksPrep { + #[allow(dead_code)] + #[cfg(test)] + pub(crate) fn encrypt_sk( + &mut self, + module: &Module, + value: T, + sk: &GLWESecretPrepared, + source_xa: &mut Source, + source_xe: &mut Source, + scratch: &mut Scratch, + ) where + S: DataRef, + Module: VecZnxAddScalarInplace + + VecZnxDftAllocBytes + + VecZnxBigNormalize + + VecZnxDftApply + + SvpApplyDftToDftInplace + + VecZnxIdftApplyConsume + + VecZnxNormalizeTmpBytes + + VecZnxFillUniform + + VecZnxSubInplace + + VecZnxAddInplace + + VecZnxNormalizeInplace + + VecZnxAddNormal + + VecZnxNormalize + + VecZnxSub + + VmpPrepare, + Scratch: TakeVecZnxDft + 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(&mut self, module: &Module, bits: &FheUintBlocks, key: &KEY, scratch: &mut Scratch) + where + BIT: DataRef, + KEY: FheUintPrepare, FheUintBlocks>, + { + key.prepare(module, self, bits, scratch); + } +} + +#[cfg(test)] +impl FheUintBlocksPrepDebug { + pub(crate) fn prepare( + &mut self, + module: &Module, + bits: &FheUintBlocks, + key: &KEY, + scratch: &mut Scratch, + ) where + BIT: DataRef, + KEY: FheUintPrepare, FheUintBlocks>, + { + key.prepare(module, self, bits, scratch); + } +} + +#[cfg(test)] +impl FheUintBlocksPrepDebug { + #[allow(dead_code)] + pub(crate) fn noise(&self, module: &Module, sk: &GLWESecretPrepared, want: T) + where + Module: VecZnxDftAllocBytes + + VecZnxBigAllocBytes + + VecZnxDftApply + + SvpApplyDftToDftInplace + + VecZnxIdftApplyConsume + + VecZnxBigAddInplace + + VecZnxBigAddSmallInplace + + VecZnxBigNormalize + + VecZnxNormalizeTmpBytes + + VecZnxBigAlloc + + VecZnxDftAlloc + + VecZnxBigNormalizeTmpBytes + + VecZnxIdftApplyTmpA + + VecZnxAddScalarInplace + + VecZnxSubInplace, + BE: Backend + TakeVecZnxDftImpl + TakeVecZnxBigImpl + ScratchOwnedAllocImpl + ScratchOwnedBorrowImpl, + { + 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 LWEInfos for FheUintBlocksPrep { + 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 GLWEInfos for FheUintBlocksPrep { + fn rank(&self) -> poulpy_core::layouts::Rank { + self.blocks[0].rank() + } +} + +impl GGSWInfos for FheUintBlocksPrep { + 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 LWEInfos for FheUintBlocksPrepDebug { + 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 GLWEInfos for FheUintBlocksPrepDebug { + fn rank(&self) -> poulpy_core::layouts::Rank { + self.blocks[0].rank() + } +} + +#[cfg(test)] +impl GGSWInfos for FheUintBlocksPrepDebug { + fn dsize(&self) -> poulpy_core::layouts::Dsize { + self.blocks[0].dsize() + } + + fn dnum(&self) -> poulpy_core::layouts::Dnum { + self.blocks[0].dnum() + } +} diff --git a/poulpy-schemes/src/tfhe/bdd_arithmetic/ciphertexts/mod.rs b/poulpy-schemes/src/tfhe/bdd_arithmetic/ciphertexts/mod.rs new file mode 100644 index 0000000..8b51045 --- /dev/null +++ b/poulpy-schemes/src/tfhe/bdd_arithmetic/ciphertexts/mod.rs @@ -0,0 +1,7 @@ +mod block; +mod block_prepared; +mod word; + +pub use block::*; +pub use block_prepared::*; +pub use word::*; diff --git a/poulpy-schemes/src/tfhe/bdd_arithmetic/ciphertexts/word.rs b/poulpy-schemes/src/tfhe/bdd_arithmetic/ciphertexts/word.rs new file mode 100644 index 0000000..cc754bc --- /dev/null +++ b/poulpy-schemes/src/tfhe/bdd_arithmetic/ciphertexts/word.rs @@ -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(pub(crate) GLWECiphertext, pub(crate) PhantomData); + +impl FheUintWord { + #[allow(dead_code)] + fn post_process( + &mut self, + module: &Module, + mut tmp_res: Vec>, + auto_keys: &HashMap>, + scratch: &mut Scratch, + ) where + ATK: DataRef, + Module: VecZnxSub + + VecZnxCopy + + VecZnxNegateInplace + + VecZnxDftAllocBytes + + VecZnxAddInplace + + VmpApplyDftToDftTmpBytes + + VecZnxNormalizeTmpBytes + + VecZnxDftApply + + VmpApplyDftToDft + + VmpApplyDftToDftAdd + + VecZnxIdftApplyConsume + + VecZnxBigNormalize + + VecZnxNormalize + + VecZnxRotateInplace + + VecZnxNormalizeInplace + + VecZnxSwitchRing + + VecZnxBigAutomorphismInplace + + VecZnxRshInplace + + VecZnxDftCopy + + VecZnxIdftApplyTmpA + + VecZnxSubInplace + + VecZnxBigNormalizeTmpBytes + + VecZnxBigAddSmallInplace + + VecZnxAutomorphismInplace + + VecZnxBigSubSmallNegateInplace + + VecZnxRotate, + Scratch: TakeVecZnxDft + 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> = 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 LWEInfos for FheUintWord { + 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 GLWEInfos for FheUintWord { + fn rank(&self) -> poulpy_core::layouts::Rank { + self.0.rank() + } +} + +impl FheUintWord { + pub fn encrypt_sk( + &mut self, + module: &Module, + data: T, + sk: &GLWESecretPrepared, + source_xa: &mut Source, + source_xe: &mut Source, + scratch: &mut Scratch, + ) where + Module: VecZnxAddScalarInplace + + VecZnxDftAllocBytes + + VecZnxBigNormalize + + VecZnxDftApply + + SvpApplyDftToDftInplace + + VecZnxIdftApplyConsume + + VecZnxNormalizeTmpBytes + + VecZnxFillUniform + + VecZnxSubInplace + + VecZnxAddInplace + + VecZnxNormalizeInplace + + VecZnxAddNormal + + VecZnxNormalize + + VecZnxSub, + Scratch: TakeVecZnxDft + ScratchAvailable + TakeVecZnx + TakeGLWEPt, + { + #[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 = 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 FheUintWord { + pub fn decrypt( + &self, + module: &Module, + sk: &GLWESecretPrepared, + scratch: &mut Scratch, + ) -> T + where + Module: VecZnxDftApply + + SvpApplyDftToDftInplace + + VecZnxIdftApplyConsume + + VecZnxBigAddInplace + + VecZnxBigAddSmallInplace + + VecZnxBigNormalize, + Scratch: TakeVecZnxDft + TakeVecZnxBig + TakeGLWEPt, + { + #[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 = vec![0i64; module.n()]; + + pt.decode_vec_i64(&mut data, TorusPrecision(1)); + + let bits: Vec = data.iter().step_by(gap).map(|c| *c as u8).collect_vec(); + T::from_bits(&bits) + } +} diff --git a/poulpy-schemes/src/tfhe/bdd_arithmetic/circuits/mod.rs b/poulpy-schemes/src/tfhe/bdd_arithmetic/circuits/mod.rs new file mode 100644 index 0000000..7bfe014 --- /dev/null +++ b/poulpy-schemes/src/tfhe/bdd_arithmetic/circuits/mod.rs @@ -0,0 +1 @@ +pub mod u32; diff --git a/poulpy-schemes/src/tfhe/bdd_arithmetic/circuits/u32/add_codegen.rs b/poulpy-schemes/src/tfhe/bdd_arithmetic/circuits/u32/add_codegen.rs new file mode 100644 index 0000000..dc6860b --- /dev/null +++ b/poulpy-schemes/src/tfhe/bdd_arithmetic/circuits/u32/add_codegen.rs @@ -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 for Circuit { + 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 = 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, + )), +]); diff --git a/poulpy-schemes/src/tfhe/bdd_arithmetic/circuits/u32/and_codegen.rs b/poulpy-schemes/src/tfhe/bdd_arithmetic/circuits/u32/and_codegen.rs new file mode 100644 index 0000000..a37b5a6 --- /dev/null +++ b/poulpy-schemes/src/tfhe/bdd_arithmetic/circuits/u32/and_codegen.rs @@ -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 for Circuit { + 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 = 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, + )), +]); diff --git a/poulpy-schemes/src/tfhe/bdd_arithmetic/circuits/u32/mod.rs b/poulpy-schemes/src/tfhe/bdd_arithmetic/circuits/u32/mod.rs new file mode 100644 index 0000000..72deb2a --- /dev/null +++ b/poulpy-schemes/src/tfhe/bdd_arithmetic/circuits/u32/mod.rs @@ -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; diff --git a/poulpy-schemes/src/tfhe/bdd_arithmetic/circuits/u32/or_codegen.rs b/poulpy-schemes/src/tfhe/bdd_arithmetic/circuits/u32/or_codegen.rs new file mode 100644 index 0000000..52b73e1 --- /dev/null +++ b/poulpy-schemes/src/tfhe/bdd_arithmetic/circuits/u32/or_codegen.rs @@ -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 for Circuit { + 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 = Circuit([AnyBitCircuit::B0(BitCircuit::new( + [Node::new(0, 0, 0), Node::new(1, 1, 0), Node::new(0, 1, 1)], + [0, 2], + 2, +))]); diff --git a/poulpy-schemes/src/tfhe/bdd_arithmetic/circuits/u32/sll_codegen.rs b/poulpy-schemes/src/tfhe/bdd_arithmetic/circuits/u32/sll_codegen.rs new file mode 100644 index 0000000..bc5ee9a --- /dev/null +++ b/poulpy-schemes/src/tfhe/bdd_arithmetic/circuits/u32/sll_codegen.rs @@ -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 for Circuit { + 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 = 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, + )), +]); diff --git a/poulpy-schemes/src/tfhe/bdd_arithmetic/circuits/u32/slt_codegen.rs b/poulpy-schemes/src/tfhe/bdd_arithmetic/circuits/u32/slt_codegen.rs new file mode 100644 index 0000000..e7087aa --- /dev/null +++ b/poulpy-schemes/src/tfhe/bdd_arithmetic/circuits/u32/slt_codegen.rs @@ -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 for Circuit { + 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 = 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, +))]); diff --git a/poulpy-schemes/src/tfhe/bdd_arithmetic/circuits/u32/sltu_codegen.rs b/poulpy-schemes/src/tfhe/bdd_arithmetic/circuits/u32/sltu_codegen.rs new file mode 100644 index 0000000..ad4c1e5 --- /dev/null +++ b/poulpy-schemes/src/tfhe/bdd_arithmetic/circuits/u32/sltu_codegen.rs @@ -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 for Circuit { + 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 = 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, +))]); diff --git a/poulpy-schemes/src/tfhe/bdd_arithmetic/circuits/u32/sra_codegen.rs b/poulpy-schemes/src/tfhe/bdd_arithmetic/circuits/u32/sra_codegen.rs new file mode 100644 index 0000000..4916f33 --- /dev/null +++ b/poulpy-schemes/src/tfhe/bdd_arithmetic/circuits/u32/sra_codegen.rs @@ -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 for Circuit { + 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 = 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)), +]); diff --git a/poulpy-schemes/src/tfhe/bdd_arithmetic/circuits/u32/srl_codegen.rs b/poulpy-schemes/src/tfhe/bdd_arithmetic/circuits/u32/srl_codegen.rs new file mode 100644 index 0000000..520e1b2 --- /dev/null +++ b/poulpy-schemes/src/tfhe/bdd_arithmetic/circuits/u32/srl_codegen.rs @@ -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 for Circuit { + 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 = 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, + )), +]); diff --git a/poulpy-schemes/src/tfhe/bdd_arithmetic/circuits/u32/sub_codegen.rs b/poulpy-schemes/src/tfhe/bdd_arithmetic/circuits/u32/sub_codegen.rs new file mode 100644 index 0000000..ff845f7 --- /dev/null +++ b/poulpy-schemes/src/tfhe/bdd_arithmetic/circuits/u32/sub_codegen.rs @@ -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 for Circuit { + 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 = 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, + )), +]); diff --git a/poulpy-schemes/src/tfhe/bdd_arithmetic/circuits/u32/xor_codegen.rs b/poulpy-schemes/src/tfhe/bdd_arithmetic/circuits/u32/xor_codegen.rs new file mode 100644 index 0000000..2512c52 --- /dev/null +++ b/poulpy-schemes/src/tfhe/bdd_arithmetic/circuits/u32/xor_codegen.rs @@ -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 for Circuit { + 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 = Circuit([AnyBitCircuit::B0(BitCircuit::new( + [Node::new(1, 1, 0), Node::new(1, 0, 1), Node::new(0, 1, 0)], + [0, 2], + 2, +))]); diff --git a/poulpy-schemes/src/tfhe/bdd_arithmetic/eval.rs b/poulpy-schemes/src/tfhe/bdd_arithmetic/eval.rs new file mode 100644 index 0000000..98e1083 --- /dev/null +++ b/poulpy-schemes/src/tfhe/bdd_arithmetic/eval.rs @@ -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 { + fn input_size(&self) -> usize; + fn output_size(&self) -> usize; + fn get_circuit(&self, bit: usize) -> (&[Node], &[usize], usize); +} + +pub(crate) struct BitCircuit { + pub(crate) nodes: [Node; N], + pub(crate) levels: [usize; K], + pub(crate) max_inter_state: usize, +} + +pub struct Circuit(pub [C; N]); + +pub trait CircuitExecute +where + Self: GetBitCircuitInfo, +{ + fn execute( + &self, + module: &Module, + out: &mut [GLWECiphertext], + inputs: &[&dyn GGSWCiphertextPreparedToRef], + scratch: &mut Scratch, + ) where + O: DataMut; +} + +impl CircuitExecute for Circuit +where + Self: GetBitCircuitInfo, + Module: Cmux + VecZnxCopy, + Scratch: TakeGLWECtSlice, +{ + fn execute( + &self, + module: &Module, + out: &mut [GLWECiphertext], + inputs: &[&dyn GGSWCiphertextPreparedToRef], + scratch: &mut Scratch, + ) 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 BitCircuit { + pub(crate) const fn new(nodes: [Node; N], levels: [usize; K], max_inter_state: usize) -> Self { + Self { + nodes, + levels, + max_inter_state, + } + } +} +impl BitCircuitInfo for BitCircuit { + 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 { + fn cmux( + &self, + out: &mut GLWECiphertext, + t: &GLWECiphertext, + f: &GLWECiphertext, + s: &GGSWCiphertextPrepared, + scratch: &mut Scratch, + ) where + O: DataMut, + T: DataRef, + F: DataRef, + S: DataRef; +} + +impl Cmux for Module +where + Module: GLWEExternalProductInplace + VecZnxSub + VecZnxCopy + VecZnxNegateInplace + VecZnxAddInplace, +{ + fn cmux( + &self, + out: &mut GLWECiphertext, + t: &GLWECiphertext, + f: &GLWECiphertext, + s: &GGSWCiphertextPrepared, + scratch: &mut Scratch, + ) 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); + } +} diff --git a/poulpy-schemes/src/tfhe/bdd_arithmetic/key.rs b/poulpy-schemes/src/tfhe/bdd_arithmetic/key.rs new file mode 100644 index 0000000..febabed --- /dev/null +++ b/poulpy-schemes/src/tfhe/bdd_arithmetic/key.rs @@ -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 +where + CBT: Data, + LWE: Data, + BRA: BlindRotationAlgo, +{ + cbt: CircuitBootstrappingKey, + ks: GLWEToLWEKey, +} + +impl BDDKey, Vec, BRA> { + pub fn encrypt_sk( + module: &Module, + sk_lwe: &LWESecret, + sk_glwe: &GLWESecret, + infos: &A, + source_xa: &mut Source, + source_xe: &mut Source, + scratch: &mut Scratch, + ) -> Self + where + A: BDDKeyInfos, + DLwe: DataRef, + DGlwe: DataRef, + BlindRotationKey, BRA>: BlindRotationKeyAlloc + BlindRotationKeyEncryptSk, + Module: SvpApplyDftToDft + + VecZnxIdftApplyTmpA + + VecZnxAddScalarInplace + + VecZnxDftAllocBytes + + VecZnxBigNormalize + + VecZnxDftApply + + SvpApplyDftToDftInplace + + VecZnxIdftApplyConsume + + VecZnxNormalizeTmpBytes + + VecZnxFillUniform + + VecZnxSubInplace + + VecZnxAddInplace + + VecZnxNormalizeInplace + + VecZnxAddNormal + + VecZnxNormalize + + VecZnxSub + + SvpPrepare + + VecZnxSwitchRing + + SvpPPolAllocBytes + + SvpPPolAlloc + + VecZnxAutomorphism + + VecZnxAutomorphismInplace, + Scratch: TakeVecZnxDft + ScratchAvailable + TakeVecZnx + TakeScalarZnx + TakeSvpPPol + TakeVecZnxBig, + { + let mut ks: GLWEToLWEKey> = 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 +where + CBT: Data, + LWE: Data, + BRA: BlindRotationAlgo, + BE: Backend, +{ + cbt: CircuitBootstrappingKeyPrepared, + ks: GLWEToLWESwitchingKeyPrepared, +} + +impl PrepareAlloc> + for BDDKey +where + CircuitBootstrappingKey: PrepareAlloc>, + GLWEToLWEKey: PrepareAlloc>, +{ + fn prepare_alloc(&self, module: &Module, scratch: &mut Scratch) -> BDDKeyPrepared { + BDDKeyPrepared { + cbt: self.cbt.prepare_alloc(module, scratch), + ks: self.ks.prepare_alloc(module, scratch), + } + } +} + +pub trait FheUintPrepare { + fn prepare(&self, module: &Module, out: &mut OUT, bits: &IN, scratch: &mut Scratch); +} + +impl FheUintPrepare, FheUintBlocks> + for BDDKeyPrepared +where + T: UnsignedInteger, + CBT: DataRef, + OUT: DataMut, + IN: DataRef, + LWE: DataRef, + BRA: BlindRotationAlgo, + BE: Backend, + Module: VmpPrepare + + VecZnxRotate + + VecZnxDftAllocBytes + + VmpApplyDftToDftTmpBytes + + VecZnxBigNormalizeTmpBytes + + VmpApplyDftToDft + + VmpApplyDftToDftAdd + + VecZnxDftApply + + VecZnxIdftApplyConsume + + VecZnxBigAddSmallInplace + + VecZnxBigNormalize + + VecZnxNormalize + + VecZnxNormalizeTmpBytes, + Scratch: ScratchAvailable + TakeVecZnxDft + TakeGLWECt + TakeVecZnx + TakeGGSW, + CircuitBootstrappingKeyPrepared: CirtuitBootstrappingExecute, +{ + fn prepare( + &self, + module: &Module, + out: &mut FheUintBlocksPrep, + bits: &FheUintBlocks, + scratch: &mut Scratch, + ) { + #[cfg(debug_assertions)] + { + assert_eq!(out.blocks.len(), bits.blocks.len()); + } + let mut lwe: LWECiphertext> = 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 FheUintPrepare, FheUintBlocks> + for BDDKeyPrepared +where + T: UnsignedInteger, + CBT: DataRef, + OUT: DataMut, + IN: DataRef, + LWE: DataRef, + BRA: BlindRotationAlgo, + BE: Backend, + Module: VmpPrepare + + VecZnxRotate + + VecZnxDftAllocBytes + + VmpApplyDftToDftTmpBytes + + VecZnxBigNormalizeTmpBytes + + VmpApplyDftToDft + + VmpApplyDftToDftAdd + + VecZnxDftApply + + VecZnxIdftApplyConsume + + VecZnxBigAddSmallInplace + + VecZnxBigNormalize + + VecZnxNormalize + + VecZnxNormalizeTmpBytes, + Scratch: ScratchAvailable + TakeVecZnxDft + TakeGLWECt + TakeVecZnx + TakeGGSW, + CircuitBootstrappingKeyPrepared: CirtuitBootstrappingExecute, +{ + fn prepare( + &self, + module: &Module, + out: &mut FheUintBlocksPrepDebug, + bits: &FheUintBlocks, + scratch: &mut Scratch, + ) { + #[cfg(debug_assertions)] + { + assert_eq!(out.blocks.len(), bits.blocks.len()); + } + let mut lwe: LWECiphertext> = 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); + } + } +} diff --git a/poulpy-schemes/src/tfhe/bdd_arithmetic/mod.rs b/poulpy-schemes/src/tfhe/bdd_arithmetic/mod.rs new file mode 100644 index 0000000..d89348f --- /dev/null +++ b/poulpy-schemes/src/tfhe/bdd_arithmetic/mod.rs @@ -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); diff --git a/poulpy-schemes/src/tfhe/bdd_arithmetic/parameters.rs b/poulpy-schemes/src/tfhe/bdd_arithmetic/parameters.rs new file mode 100644 index 0000000..6b56f79 --- /dev/null +++ b/poulpy-schemes/src/tfhe/bdd_arithmetic/parameters.rs @@ -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), + }, +}; diff --git a/poulpy-schemes/src/tfhe/bdd_arithmetic/test.rs b/poulpy-schemes/src/tfhe/bdd_arithmetic/test.rs new file mode 100644 index 0000000..1889e02 --- /dev/null +++ b/poulpy-schemes/src/tfhe/bdd_arithmetic/test.rs @@ -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::() +} + +fn test_bdd_2w_to_1w() +where + Module: ModuleNew + SvpPPolAlloc + SvpPrepare + VmpPMatAlloc, + ScratchOwned: ScratchOwnedAlloc + ScratchOwnedBorrow, + Module: VecZnxAddScalarInplace + + VecZnxDftAllocBytes + + VecZnxBigNormalize + + VecZnxDftApply + + SvpApplyDftToDftInplace + + VecZnxIdftApplyConsume + + VecZnxNormalizeTmpBytes + + VecZnxFillUniform + + VecZnxSubInplace + + VecZnxAddInplace + + VecZnxNormalizeInplace + + VecZnxAddNormal + + VecZnxNormalize + + VecZnxSub + + VmpPrepare, + Scratch: TakeVecZnxDft + ScratchAvailable + TakeVecZnx + TakeGGSW + TakeScalarZnx + TakeSlice, + Module: VecZnxCopy + VecZnxNegateInplace + VmpApplyDftToDftTmpBytes + VmpApplyDftToDft + VmpApplyDftToDftAdd, + Module: VecZnxBigAddInplace + VecZnxBigAddSmallInplace + VecZnxBigNormalize, + Scratch: TakeVecZnxDft + TakeVecZnxBig + TakeGLWEPt, + Module: VecZnxAutomorphism + + VecZnxSwitchRing + + VecZnxBigAllocBytes + + VecZnxIdftApplyTmpA + + SvpApplyDftToDft + + VecZnxBigAlloc + + VecZnxDftAlloc + + VecZnxBigNormalizeTmpBytes + + SvpPPolAllocBytes + + VecZnxRotateInplace + + VecZnxBigAutomorphismInplace + + VecZnxRshInplace + + VecZnxDftCopy + + VecZnxAutomorphismInplace + + VecZnxBigSubSmallNegateInplace + + VecZnxRotateInplaceTmpBytes + + VecZnxBigAllocBytes + + VecZnxDftAddInplace + + VecZnxRotate + + ZnFillUniform + + ZnAddNormal + + ZnNormalizeInplace, + BE: Backend + + ScratchOwnedAllocImpl + + ScratchOwnedBorrowImpl + + TakeVecZnxDftImpl + + ScratchAvailableImpl + + TakeVecZnxImpl + + TakeScalarZnxImpl + + TakeSvpPPolImpl + + TakeVecZnxBigImpl + + TakeVecZnxDftSliceImpl + + TakeMatZnxImpl + + TakeVecZnxSliceImpl, + BlindRotationKey, BRA>: PrepareAlloc, BRA, BE>>, + BlindRotationKeyPrepared, BRA, BE>: BlincRotationExecute, + BlindRotationKey, BRA>: BlindRotationKeyAlloc + BlindRotationKeyEncryptSk, +{ + 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 = Module::::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 = ScratchOwned::alloc(1 << 22); + + let mut sk_glwe: GLWESecret> = GLWESecret::alloc(&glwe_infos); + sk_glwe.fill_ternary_prob(0.5, &mut source_xs); + let sk_glwe_prep: GLWESecretPrepared, 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, BE, u32> = FheUintBlocksPrep::, BE, u32>::alloc(&module, &ggsw_infos); + let mut b_enc_prep: FheUintBlocksPrep, BE, u32> = FheUintBlocksPrep::, BE, u32>::alloc(&module, &ggsw_infos); + let mut c_enc: FheUintBlocks, u32> = FheUintBlocks::, u32>::alloc(&module, &glwe_infos); + let mut c_enc_prep_debug: FheUintBlocksPrepDebug, u32> = + FheUintBlocksPrepDebug::, u32>::alloc(&module, &ggsw_infos); + let mut c_enc_prep: FheUintBlocksPrep, BE, u32> = FheUintBlocksPrep::, 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> = 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, 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, 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() + ) + ); +} diff --git a/poulpy-schemes/src/tfhe/blind_rotation/cggi_algo.rs b/poulpy-schemes/src/tfhe/blind_rotation/cggi_algo.rs index 3814b48..03f36e9 100644 --- a/poulpy-schemes/src/tfhe/blind_rotation/cggi_algo.rs +++ b/poulpy-schemes/src/tfhe/blind_rotation/cggi_algo.rs @@ -42,13 +42,13 @@ where 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 @@ fn execute_block_binary_extended( 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 @@ fn execute_block_binary( 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 @@ fn execute_block_binary( // 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()); diff --git a/poulpy-schemes/src/tfhe/blind_rotation/key.rs b/poulpy-schemes/src/tfhe/blind_rotation/key.rs index b4fbda8..86dbd21 100644 --- a/poulpy-schemes/src/tfhe/blind_rotation/key.rs +++ b/poulpy-schemes/src/tfhe/blind_rotation/key.rs @@ -8,7 +8,7 @@ use std::{fmt, marker::PhantomData}; 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 struct BlindRotationKeyLayout { pub n_lwe: Degree, pub base2k: Base2K, pub k: TorusPrecision, - pub rows: Rows, + pub dnum: Dnum, pub rank: Rank, } @@ -38,12 +38,12 @@ impl BlindRotationKeyInfos for BlindRotationKeyLayout { } 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 @@ impl GLWEInfos for BlindRotationKey } } impl GGSWInfos for BlindRotationKey { - 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() } } diff --git a/poulpy-schemes/src/tfhe/blind_rotation/key_compressed.rs b/poulpy-schemes/src/tfhe/blind_rotation/key_compressed.rs index 22a98da..51ff139 100644 --- a/poulpy-schemes/src/tfhe/blind_rotation/key_compressed.rs +++ b/poulpy-schemes/src/tfhe/blind_rotation/key_compressed.rs @@ -8,7 +8,7 @@ use std::{fmt, marker::PhantomData}; 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 GLWEInfos for BlindRotationKeyCompresse } impl GGSWInfos for BlindRotationKeyCompressed { - 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) } } diff --git a/poulpy-schemes/src/tfhe/blind_rotation/key_prepared.rs b/poulpy-schemes/src/tfhe/blind_rotation/key_prepared.rs index d7dad82..8719de4 100644 --- a/poulpy-schemes/src/tfhe/blind_rotation/key_prepared.rs +++ b/poulpy-schemes/src/tfhe/blind_rotation/key_prepared.rs @@ -8,7 +8,7 @@ use std::marker::PhantomData; 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 @@ impl GLWEInfos for BlindRotationKey } } impl GGSWInfos for BlindRotationKeyPrepared { - 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() } } diff --git a/poulpy-schemes/src/tfhe/blind_rotation/lut.rs b/poulpy-schemes/src/tfhe/blind_rotation/lut.rs index 106bcff..f8e9006 100644 --- a/poulpy-schemes/src/tfhe/blind_rotation/lut.rs +++ b/poulpy-schemes/src/tfhe/blind_rotation/lut.rs @@ -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 @@ impl LookUpTable { + VecZnxCopy + VecZnxRotateInplaceTmpBytes, ScratchOwned: ScratchOwnedAlloc + ScratchOwnedBorrow, + Scratch: TakeSlice, { assert!(f.len() <= module.n()); let base2k: usize = self.base2k; - let mut scratch: ScratchOwned = ScratchOwned::alloc(module.vec_znx_normalize_tmp_bytes()); + let mut scratch: ScratchOwned = 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 @@ impl LookUpTable { // 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)); diff --git a/poulpy-schemes/src/tfhe/blind_rotation/tests/generic_blind_rotation.rs b/poulpy-schemes/src/tfhe/blind_rotation/tests/generic_blind_rotation.rs index f2fc246..190adff 100644 --- a/poulpy-schemes/src/tfhe/blind_rotation/tests/generic_blind_rotation.rs +++ b/poulpy-schemes/src/tfhe/blind_rotation/tests/generic_blind_rotation.rs @@ -11,7 +11,7 @@ use poulpy_hal::{ }, 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 @@ where + TakeVecZnxDftSliceImpl + ScratchAvailableImpl + TakeVecZnxImpl - + TakeVecZnxSliceImpl, + + TakeVecZnxSliceImpl + + TakeSliceImpl, { let n_glwe: usize = module.n(); let base2k: usize = 19; @@ -106,7 +107,7 @@ where n_lwe: n_lwe.into(), base2k: base2k.into(), k: k_brk.into(), - rows: rows_brk.into(), + dnum: rows_brk.into(), rank: rank.into(), }; diff --git a/poulpy-schemes/src/tfhe/blind_rotation/tests/generic_lut.rs b/poulpy-schemes/src/tfhe/blind_rotation/tests/generic_lut.rs index 20adc6d..bb6492c 100644 --- a/poulpy-schemes/src/tfhe/blind_rotation/tests/generic_lut.rs +++ b/poulpy-schemes/src/tfhe/blind_rotation/tests/generic_lut.rs @@ -6,7 +6,7 @@ use poulpy_hal::{ VecZnxSwitchRing, }, layouts::{Backend, Module}, - oep::{ScratchOwnedAllocImpl, ScratchOwnedBorrowImpl}, + oep::{ScratchOwnedAllocImpl, ScratchOwnedBorrowImpl, TakeSliceImpl}, }; use crate::tfhe::blind_rotation::{DivRound, LookUpTable}; @@ -19,7 +19,7 @@ where + VecZnxSwitchRing + VecZnxCopy + VecZnxRotateInplaceTmpBytes, - B: Backend + ScratchOwnedAllocImpl + ScratchOwnedBorrowImpl, + B: Backend + ScratchOwnedAllocImpl + ScratchOwnedBorrowImpl + TakeSliceImpl, { let base2k: usize = 20; let k_lut: usize = 40; @@ -59,7 +59,7 @@ where + VecZnxSwitchRing + VecZnxCopy + VecZnxRotateInplaceTmpBytes, - B: Backend + ScratchOwnedAllocImpl + ScratchOwnedBorrowImpl, + B: Backend + ScratchOwnedAllocImpl + ScratchOwnedBorrowImpl + TakeSliceImpl, { let base2k: usize = 20; let k_lut: usize = 40; diff --git a/poulpy-schemes/src/tfhe/blind_rotation/tests/generic_serialization.rs b/poulpy-schemes/src/tfhe/blind_rotation/tests/generic_serialization.rs index b56042a..f25a236 100644 --- a/poulpy-schemes/src/tfhe/blind_rotation/tests/generic_serialization.rs +++ b/poulpy-schemes/src/tfhe/blind_rotation/tests/generic_serialization.rs @@ -11,7 +11,7 @@ fn test_cggi_blind_rotation_key_serialization() { 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 @@ fn test_cggi_blind_rotation_key_compressed_serialization() { 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(), }; diff --git a/poulpy-schemes/src/tfhe/circuit_bootstrapping/circuit.rs b/poulpy-schemes/src/tfhe/circuit_bootstrapping/circuit.rs index d462ff7..45b9717 100644 --- a/poulpy-schemes/src/tfhe/circuit_bootstrapping/circuit.rs +++ b/poulpy-schemes/src/tfhe/circuit_bootstrapping/circuit.rs @@ -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_hal::{ 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 @@ where + TakeVecZnxDft + TakeMatZnx + ScratchAvailable - + TakeVecZnxSlice, + + TakeVecZnxSlice + + TakeSlice, BlindRotationKeyPrepared: BlincRotationExecute, { fn execute_to_constant( @@ -166,7 +168,8 @@ pub fn circuit_bootstrap_core( + TakeVecZnx + ScratchAvailable + TakeVecZnxSlice - + TakeMatZnx, + + TakeMatZnx + + TakeSlice, BlindRotationKeyPrepared: BlincRotationExecute, { #[cfg(debug_assertions)] @@ -180,29 +183,29 @@ pub fn circuit_bootstrap_core( 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 = 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 @@ pub fn circuit_bootstrap_core( 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 @@ pub fn circuit_bootstrap_core( 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 @@ pub fn circuit_bootstrap_core( 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 @@ fn post_process( { let log_n: usize = module.log_n(); - let mut cts: HashMap>> = HashMap::new(); + let mut cts: HashMap>> = 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 @@ fn post_process( // 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>> = 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> = 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> = cts.remove(&0).unwrap(); res.trace( module, log_n - log_gap_out, log_n, - &packed, + packed, auto_keys, scratch, ); } } - -pub fn pack( - module: &Module, - cts: &mut HashMap>, - log_gap_out: usize, - auto_keys: &HashMap, B>>, - scratch: &mut Scratch, -) where - Module: VecZnxRotateInplace - + VecZnxNormalizeInplace - + VecZnxNormalizeTmpBytes - + VecZnxSwitchRing - + VecZnxBigAutomorphismInplace - + VecZnxRshInplace - + VecZnxDftCopy - + VecZnxIdftApplyTmpA - + VecZnxSub - + VecZnxAddInplace - + VecZnxNegateInplace - + VecZnxCopy - + VecZnxSubInplace - + VecZnxDftAllocBytes - + VmpApplyDftToDftTmpBytes - + VecZnxBigNormalizeTmpBytes - + VmpApplyDftToDft - + VmpApplyDftToDftAdd - + VecZnxDftApply - + VecZnxIdftApplyConsume - + VecZnxBigAddSmallInplace - + VecZnxBigNormalize - + VecZnxAutomorphismInplace - + VecZnxBigSubSmallNegateInplace - + VecZnxRotate - + VecZnxNormalize, - Scratch: TakeVecZnx + TakeVecZnxDft + 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, 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> = cts.remove(&j); - let mut b: Option> = 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( - module: &Module, - a: Option<&mut GLWECiphertext>, - b: Option<&mut GLWECiphertext>, - i: usize, - auto_key: &GGLWEAutomorphismKeyPrepared, - scratch: &mut Scratch, -) where - Module: VecZnxRotateInplace - + VecZnxNormalizeInplace - + VecZnxNormalizeTmpBytes - + VecZnxSwitchRing - + VecZnxBigAutomorphismInplace - + VecZnxRshInplace - + VecZnxDftCopy - + VecZnxIdftApplyTmpA - + VecZnxSub - + VecZnxAddInplace - + VecZnxNegateInplace - + VecZnxCopy - + VecZnxSubInplace - + VecZnxDftAllocBytes - + VmpApplyDftToDftTmpBytes - + VecZnxBigNormalizeTmpBytes - + VmpApplyDftToDft - + VmpApplyDftToDftAdd - + VecZnxDftApply - + VecZnxIdftApplyConsume - + VecZnxBigAddSmallInplace - + VecZnxBigNormalize - + VecZnxAutomorphismInplace - + VecZnxBigSubSmallNegateInplace - + VecZnxRotate - + VecZnxNormalize, - Scratch: TakeVecZnx + TakeVecZnxDft + 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); - } -} diff --git a/poulpy-schemes/src/tfhe/circuit_bootstrapping/key.rs b/poulpy-schemes/src/tfhe/circuit_bootstrapping/key.rs index b9ed6b9..427cf75 100644 --- a/poulpy-schemes/src/tfhe/circuit_bootstrapping/key.rs +++ b/poulpy-schemes/src/tfhe/circuit_bootstrapping/key.rs @@ -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 @@ use crate::tfhe::blind_rotation::{ }; 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 struct CircuitBootstrappingKeyLayout { } 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:, { - 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>> = HashMap::new(); let gal_els: Vec = GLWECiphertext::trace_galois_elements(module); @@ -159,36 +159,36 @@ pub struct CircuitBootstrappingKeyPrepared CircuitBootstrappingKeyInfos for CircuitBootstrappingKeyPrepared { - 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(), } } diff --git a/poulpy-schemes/src/tfhe/circuit_bootstrapping/tests/circuit_bootstrapping.rs b/poulpy-schemes/src/tfhe/circuit_bootstrapping/tests/circuit_bootstrapping.rs index 7094255..40f5448 100644 --- a/poulpy-schemes/src/tfhe/circuit_bootstrapping/tests/circuit_bootstrapping.rs +++ b/poulpy-schemes/src/tfhe/circuit_bootstrapping/tests/circuit_bootstrapping.rs @@ -14,8 +14,8 @@ use poulpy_hal::{ }, 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 crate::tfhe::{ }; 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 @@ where + TakeVecZnxBigImpl + TakeVecZnxDftSliceImpl + TakeMatZnxImpl - + TakeVecZnxSliceImpl, + + TakeVecZnxSliceImpl + + TakeSliceImpl, BlindRotationKey, BRA>: PrepareAlloc, BRA, B>>, BlindRotationKeyPrepared, BRA, B>: BlincRotationExecute, BlindRotationKey, BRA>: BlindRotationKeyAlloc + BlindRotationKeyEncryptSk, @@ -139,23 +140,23 @@ where 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 @@ where 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 @@ where + TakeVecZnxBigImpl + TakeVecZnxDftSliceImpl + TakeMatZnxImpl - + TakeVecZnxSliceImpl, + + TakeVecZnxSliceImpl + + TakeSliceImpl, BlindRotationKey, BRA>: PrepareAlloc, BRA, B>>, BlindRotationKeyPrepared, BRA, B>: BlincRotationExecute, BlindRotationKey, BRA>: BlindRotationKeyAlloc + BlindRotationKeyEncryptSk, @@ -360,23 +362,23 @@ where 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 @@ where 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(), }; diff --git a/poulpy-schemes/src/tfhe/mod.rs b/poulpy-schemes/src/tfhe/mod.rs index f00b53d..85c84d4 100644 --- a/poulpy-schemes/src/tfhe/mod.rs +++ b/poulpy-schemes/src/tfhe/mod.rs @@ -1,2 +1,3 @@ +pub mod bdd_arithmetic; pub mod blind_rotation; pub mod circuit_bootstrapping;