diff --git a/compilers/concrete-optimizer/concrete-optimizer-cpp/src/concrete-optimizer.rs b/compilers/concrete-optimizer/concrete-optimizer-cpp/src/concrete-optimizer.rs index 00a997055..84293c98a 100644 --- a/compilers/concrete-optimizer/concrete-optimizer-cpp/src/concrete-optimizer.rs +++ b/compilers/concrete-optimizer/concrete-optimizer-cpp/src/concrete-optimizer.rs @@ -7,7 +7,6 @@ use concrete_optimizer::dag::operator::{ use concrete_optimizer::dag::unparametrized; use concrete_optimizer::optimization::config::{Config, SearchSpace}; use concrete_optimizer::optimization::dag::multi_parameters::keys_spec::{self, CircuitSolution}; -use concrete_optimizer::optimization::dag::multi_parameters::optimize::optimize_to_circuit_solution; use concrete_optimizer::optimization::dag::solo_key::optimize_generic::{ Encoding, Solution as DagSolution, }; @@ -198,10 +197,42 @@ fn convert_to_circuit_solution(sol: &ffi::DagSolution, dag: &OperationDag) -> ff }, description: "tlu bootstrap".into(), }; + let circuit_bootstrap_keys = if sol.use_wop_pbs { + vec![ffi::CircuitBoostrapKey { + identifier: 0, + representation_key: big_key.clone(), + br_decomposition_parameter: ffi::BrDecompositionParameters { + level: sol.cb_decomposition_level_count, + log2_base: sol.cb_decomposition_base_log, + }, + description: "circuit bootstrap for woppbs".into(), + }] + } else { + vec![] + }; + let private_functional_packing_keys = if sol.use_wop_pbs { + vec![ffi::PrivateFunctionalPackingBoostrapKey { + identifier: 0, + representation_key: big_key.clone(), + br_decomposition_parameter: ffi::BrDecompositionParameters { + level: sol.pp_decomposition_level_count, + log2_base: sol.pp_decomposition_base_log, + }, + description: "private functional packing for woppbs".into(), + }] + } else { + vec![] + }; let instruction_keys = ffi::InstructionKeys { input_key: big_key.identifier, tlu_keyswitch_key: keyswitch_key.identifier, tlu_bootstrap_key: bootstrap_key.identifier, + tlu_circuit_bootstrap_key: circuit_bootstrap_keys + .last() + .map_or(keys_spec::NO_KEY_ID, |v| v.identifier), + tlu_private_functional_packing_key: private_functional_packing_keys + .last() + .map_or(keys_spec::NO_KEY_ID, |v| v.identifier), output_key: big_key.identifier, extra_conversion_keys: vec![], }; @@ -211,6 +242,8 @@ fn convert_to_circuit_solution(sol: &ffi::DagSolution, dag: &OperationDag) -> ff keyswitch_keys: [keyswitch_key].into(), bootstrap_keys: [bootstrap_key].into(), conversion_keyswitch_keys: [].into(), + circuit_bootstrap_keys, + private_functional_packing_keys, }; let is_feasible = sol.p_error < 1.0; let error_msg = if is_feasible { @@ -222,6 +255,7 @@ fn convert_to_circuit_solution(sol: &ffi::DagSolution, dag: &OperationDag) -> ff ffi::CircuitSolution { circuit_keys, instructions_keys, + crt_decomposition: sol.crt_decomposition.clone(), complexity: sol.complexity, p_error: sol.p_error, global_p_error: sol.global_p_error, @@ -235,6 +269,7 @@ impl From for ffi::CircuitSolution { Self { circuit_keys: v.circuit_keys.into(), instructions_keys: vec_into(v.instructions_keys), + crt_decomposition: v.crt_decomposition, complexity: v.complexity, p_error: v.p_error, global_p_error: v.global_p_error, @@ -316,12 +351,38 @@ impl From for ffi::BootstrapKey { } } +impl From for ffi::CircuitBoostrapKey { + fn from(v: keys_spec::CircuitBoostrapKey) -> Self { + Self { + identifier: v.identifier, + representation_key: v.representation_key.into(), + br_decomposition_parameter: v.br_decomposition_parameter.into(), + description: v.description, + } + } +} + +impl From + for ffi::PrivateFunctionalPackingBoostrapKey +{ + fn from(v: keys_spec::PrivateFunctionalPackingBoostrapKey) -> Self { + Self { + identifier: v.identifier, + representation_key: v.representation_key.into(), + br_decomposition_parameter: v.br_decomposition_parameter.into(), + description: v.description, + } + } +} + impl From for ffi::InstructionKeys { fn from(v: keys_spec::InstructionKeys) -> Self { Self { input_key: v.input_key, tlu_keyswitch_key: v.tlu_keyswitch_key, tlu_bootstrap_key: v.tlu_bootstrap_key, + tlu_circuit_bootstrap_key: v.tlu_circuit_bootstrap_key, + tlu_private_functional_packing_key: v.tlu_private_functional_packing_key, output_key: v.output_key, extra_conversion_keys: v.extra_conversion_keys, } @@ -338,11 +399,18 @@ impl From for ffi::CircuitKeys { secret_keys: vec_into(v.secret_keys), keyswitch_keys: vec_into(v.keyswitch_keys), bootstrap_keys: vec_into(v.bootstrap_keys), + circuit_bootstrap_keys: vec_into(v.circuit_bootstrap_keys), + private_functional_packing_keys: vec_into(v.private_functional_packing_keys), conversion_keyswitch_keys: vec_into(v.conversion_keyswitch_keys), } } } +#[allow(non_snake_case)] +fn NO_KEY_ID() -> u64 { + keys_spec::NO_KEY_ID +} + pub struct OperationDag(unparametrized::OperationDag); fn empty() -> Box { @@ -474,13 +542,18 @@ impl OperationDag { complexity_model: &CpuComplexity::default(), }; let search_space = SearchSpace::default(processing_unit); - let circuit_sol = optimize_to_circuit_solution( - &self.0, - config, - &search_space, - &caches_from(options), - &None, - ); + + let encoding = options.encoding.into(); + let circuit_sol = + concrete_optimizer::optimization::dag::multi_parameters::optimize_generic::optimize( + &self.0, + config, + &search_space, + encoding, + options.default_log_norm2_woppbs, + &caches_from(options), + &None, + ); circuit_sol.into() } } @@ -590,6 +663,7 @@ mod ffi { fn optimize_multi(self: &OperationDag, _options: Options) -> CircuitSolution; + fn NO_KEY_ID() -> u64; } #[derive(Debug, Clone, Copy)] @@ -712,6 +786,22 @@ mod ffi { } #[namespace = "concrete_optimizer::dag"] + #[derive(Debug, Clone)] + pub struct CircuitBoostrapKey { + pub identifier: u64, + pub representation_key: SecretLweKey, + pub br_decomposition_parameter: BrDecompositionParameters, + pub description: String, + } + + #[derive(Debug, Clone)] + pub struct PrivateFunctionalPackingBoostrapKey { + pub identifier: u64, + pub representation_key: SecretLweKey, + pub br_decomposition_parameter: BrDecompositionParameters, + pub description: String, + } + #[derive(Debug, Clone)] pub struct CircuitKeys { /* All keys used in a circuit */ @@ -719,6 +809,8 @@ mod ffi { pub keyswitch_keys: Vec, pub bootstrap_keys: Vec, pub conversion_keyswitch_keys: Vec, + pub circuit_bootstrap_keys: Vec, + pub private_functional_packing_keys: Vec, } #[namespace = "concrete_optimizer::dag"] @@ -727,6 +819,8 @@ mod ffi { pub input_key: u64, pub tlu_keyswitch_key: u64, pub tlu_bootstrap_key: u64, + pub tlu_circuit_bootstrap_key: u64, + pub tlu_private_functional_packing_key: u64, pub output_key: u64, pub extra_conversion_keys: Vec, } @@ -736,6 +830,7 @@ mod ffi { pub struct CircuitSolution { pub circuit_keys: CircuitKeys, pub instructions_keys: Vec, + pub crt_decomposition: Vec, pub complexity: f64, pub p_error: f64, pub global_p_error: f64, diff --git a/compilers/concrete-optimizer/concrete-optimizer-cpp/src/cpp/concrete-optimizer.cpp b/compilers/concrete-optimizer/concrete-optimizer-cpp/src/cpp/concrete-optimizer.cpp index 24c69c22f..68d54595f 100644 --- a/compilers/concrete-optimizer/concrete-optimizer-cpp/src/cpp/concrete-optimizer.cpp +++ b/compilers/concrete-optimizer/concrete-optimizer-cpp/src/cpp/concrete-optimizer.cpp @@ -938,6 +938,8 @@ union MaybeUninit { } // namespace cxxbridge1 } // namespace rust +struct PrivateFunctionalPackingBoostrapKey; +struct CircuitKeys; namespace concrete_optimizer { struct OperationDag; struct Weights; @@ -952,7 +954,7 @@ namespace concrete_optimizer { struct BootstrapKey; struct KeySwitchKey; struct ConversionKeySwitchKey; - struct CircuitKeys; + struct CircuitBoostrapKey; struct InstructionKeys; struct CircuitSolution; } @@ -1155,24 +1157,56 @@ struct ConversionKeySwitchKey final { }; #endif // CXXBRIDGE1_STRUCT_concrete_optimizer$dag$ConversionKeySwitchKey -#ifndef CXXBRIDGE1_STRUCT_concrete_optimizer$dag$CircuitKeys -#define CXXBRIDGE1_STRUCT_concrete_optimizer$dag$CircuitKeys +#ifndef CXXBRIDGE1_STRUCT_concrete_optimizer$dag$CircuitBoostrapKey +#define CXXBRIDGE1_STRUCT_concrete_optimizer$dag$CircuitBoostrapKey +struct CircuitBoostrapKey final { + ::std::uint64_t identifier; + ::concrete_optimizer::dag::SecretLweKey representation_key; + ::concrete_optimizer::dag::BrDecompositionParameters br_decomposition_parameter; + ::rust::String description; + + using IsRelocatable = ::std::true_type; +}; +#endif // CXXBRIDGE1_STRUCT_concrete_optimizer$dag$CircuitBoostrapKey +} // namespace dag +} // namespace concrete_optimizer + +#ifndef CXXBRIDGE1_STRUCT_PrivateFunctionalPackingBoostrapKey +#define CXXBRIDGE1_STRUCT_PrivateFunctionalPackingBoostrapKey +struct PrivateFunctionalPackingBoostrapKey final { + ::std::uint64_t identifier; + ::concrete_optimizer::dag::SecretLweKey representation_key; + ::concrete_optimizer::dag::BrDecompositionParameters br_decomposition_parameter; + ::rust::String description; + + using IsRelocatable = ::std::true_type; +}; +#endif // CXXBRIDGE1_STRUCT_PrivateFunctionalPackingBoostrapKey + +#ifndef CXXBRIDGE1_STRUCT_CircuitKeys +#define CXXBRIDGE1_STRUCT_CircuitKeys struct CircuitKeys final { ::rust::Vec<::concrete_optimizer::dag::SecretLweKey> secret_keys; ::rust::Vec<::concrete_optimizer::dag::KeySwitchKey> keyswitch_keys; ::rust::Vec<::concrete_optimizer::dag::BootstrapKey> bootstrap_keys; ::rust::Vec<::concrete_optimizer::dag::ConversionKeySwitchKey> conversion_keyswitch_keys; + ::rust::Vec<::concrete_optimizer::dag::CircuitBoostrapKey> circuit_bootstrap_keys; + ::rust::Vec<::PrivateFunctionalPackingBoostrapKey> private_functional_packing_keys; using IsRelocatable = ::std::true_type; }; -#endif // CXXBRIDGE1_STRUCT_concrete_optimizer$dag$CircuitKeys +#endif // CXXBRIDGE1_STRUCT_CircuitKeys +namespace concrete_optimizer { +namespace dag { #ifndef CXXBRIDGE1_STRUCT_concrete_optimizer$dag$InstructionKeys #define CXXBRIDGE1_STRUCT_concrete_optimizer$dag$InstructionKeys struct InstructionKeys final { ::std::uint64_t input_key; ::std::uint64_t tlu_keyswitch_key; ::std::uint64_t tlu_bootstrap_key; + ::std::uint64_t tlu_circuit_bootstrap_key; + ::std::uint64_t tlu_private_functional_packing_key; ::std::uint64_t output_key; ::rust::Vec<::std::uint64_t> extra_conversion_keys; @@ -1183,8 +1217,9 @@ struct InstructionKeys final { #ifndef CXXBRIDGE1_STRUCT_concrete_optimizer$dag$CircuitSolution #define CXXBRIDGE1_STRUCT_concrete_optimizer$dag$CircuitSolution struct CircuitSolution final { - ::concrete_optimizer::dag::CircuitKeys circuit_keys; + ::CircuitKeys circuit_keys; ::rust::Vec<::concrete_optimizer::dag::InstructionKeys> instructions_keys; + ::rust::Vec<::std::uint64_t> crt_decomposition; double complexity; double p_error; double global_p_error; @@ -1259,6 +1294,8 @@ extern "C" { extern "C" { void concrete_optimizer$cxxbridge1$OperationDag$optimize_multi(::concrete_optimizer::OperationDag const &self, ::concrete_optimizer::Options _options, ::concrete_optimizer::dag::CircuitSolution *return$) noexcept; + +::std::uint64_t concrete_optimizer$cxxbridge1$NO_KEY_ID() noexcept; } // extern "C" namespace v0 { @@ -1358,6 +1395,10 @@ namespace weights { concrete_optimizer$cxxbridge1$OperationDag$optimize_multi(*this, _options, &return$.value); return ::std::move(return$.value); } + +::std::uint64_t NO_KEY_ID() noexcept { + return concrete_optimizer$cxxbridge1$NO_KEY_ID(); +} } // namespace concrete_optimizer extern "C" { @@ -1405,6 +1446,24 @@ void cxxbridge1$rust_vec$concrete_optimizer$dag$ConversionKeySwitchKey$reserve_t void cxxbridge1$rust_vec$concrete_optimizer$dag$ConversionKeySwitchKey$set_len(::rust::Vec<::concrete_optimizer::dag::ConversionKeySwitchKey> *ptr, ::std::size_t len) noexcept; void cxxbridge1$rust_vec$concrete_optimizer$dag$ConversionKeySwitchKey$truncate(::rust::Vec<::concrete_optimizer::dag::ConversionKeySwitchKey> *ptr, ::std::size_t len) noexcept; +void cxxbridge1$rust_vec$concrete_optimizer$dag$CircuitBoostrapKey$new(::rust::Vec<::concrete_optimizer::dag::CircuitBoostrapKey> const *ptr) noexcept; +void cxxbridge1$rust_vec$concrete_optimizer$dag$CircuitBoostrapKey$drop(::rust::Vec<::concrete_optimizer::dag::CircuitBoostrapKey> *ptr) noexcept; +::std::size_t cxxbridge1$rust_vec$concrete_optimizer$dag$CircuitBoostrapKey$len(::rust::Vec<::concrete_optimizer::dag::CircuitBoostrapKey> const *ptr) noexcept; +::std::size_t cxxbridge1$rust_vec$concrete_optimizer$dag$CircuitBoostrapKey$capacity(::rust::Vec<::concrete_optimizer::dag::CircuitBoostrapKey> const *ptr) noexcept; +::concrete_optimizer::dag::CircuitBoostrapKey const *cxxbridge1$rust_vec$concrete_optimizer$dag$CircuitBoostrapKey$data(::rust::Vec<::concrete_optimizer::dag::CircuitBoostrapKey> const *ptr) noexcept; +void cxxbridge1$rust_vec$concrete_optimizer$dag$CircuitBoostrapKey$reserve_total(::rust::Vec<::concrete_optimizer::dag::CircuitBoostrapKey> *ptr, ::std::size_t new_cap) noexcept; +void cxxbridge1$rust_vec$concrete_optimizer$dag$CircuitBoostrapKey$set_len(::rust::Vec<::concrete_optimizer::dag::CircuitBoostrapKey> *ptr, ::std::size_t len) noexcept; +void cxxbridge1$rust_vec$concrete_optimizer$dag$CircuitBoostrapKey$truncate(::rust::Vec<::concrete_optimizer::dag::CircuitBoostrapKey> *ptr, ::std::size_t len) noexcept; + +void cxxbridge1$rust_vec$PrivateFunctionalPackingBoostrapKey$new(::rust::Vec<::PrivateFunctionalPackingBoostrapKey> const *ptr) noexcept; +void cxxbridge1$rust_vec$PrivateFunctionalPackingBoostrapKey$drop(::rust::Vec<::PrivateFunctionalPackingBoostrapKey> *ptr) noexcept; +::std::size_t cxxbridge1$rust_vec$PrivateFunctionalPackingBoostrapKey$len(::rust::Vec<::PrivateFunctionalPackingBoostrapKey> const *ptr) noexcept; +::std::size_t cxxbridge1$rust_vec$PrivateFunctionalPackingBoostrapKey$capacity(::rust::Vec<::PrivateFunctionalPackingBoostrapKey> const *ptr) noexcept; +::PrivateFunctionalPackingBoostrapKey const *cxxbridge1$rust_vec$PrivateFunctionalPackingBoostrapKey$data(::rust::Vec<::PrivateFunctionalPackingBoostrapKey> const *ptr) noexcept; +void cxxbridge1$rust_vec$PrivateFunctionalPackingBoostrapKey$reserve_total(::rust::Vec<::PrivateFunctionalPackingBoostrapKey> *ptr, ::std::size_t new_cap) noexcept; +void cxxbridge1$rust_vec$PrivateFunctionalPackingBoostrapKey$set_len(::rust::Vec<::PrivateFunctionalPackingBoostrapKey> *ptr, ::std::size_t len) noexcept; +void cxxbridge1$rust_vec$PrivateFunctionalPackingBoostrapKey$truncate(::rust::Vec<::PrivateFunctionalPackingBoostrapKey> *ptr, ::std::size_t len) noexcept; + void cxxbridge1$rust_vec$concrete_optimizer$dag$InstructionKeys$new(::rust::Vec<::concrete_optimizer::dag::InstructionKeys> const *ptr) noexcept; void cxxbridge1$rust_vec$concrete_optimizer$dag$InstructionKeys$drop(::rust::Vec<::concrete_optimizer::dag::InstructionKeys> *ptr) noexcept; ::std::size_t cxxbridge1$rust_vec$concrete_optimizer$dag$InstructionKeys$len(::rust::Vec<::concrete_optimizer::dag::InstructionKeys> const *ptr) noexcept; @@ -1570,6 +1629,70 @@ void Vec<::concrete_optimizer::dag::ConversionKeySwitchKey>::truncate(::std::siz return cxxbridge1$rust_vec$concrete_optimizer$dag$ConversionKeySwitchKey$truncate(this, len); } template <> +Vec<::concrete_optimizer::dag::CircuitBoostrapKey>::Vec() noexcept { + cxxbridge1$rust_vec$concrete_optimizer$dag$CircuitBoostrapKey$new(this); +} +template <> +void Vec<::concrete_optimizer::dag::CircuitBoostrapKey>::drop() noexcept { + return cxxbridge1$rust_vec$concrete_optimizer$dag$CircuitBoostrapKey$drop(this); +} +template <> +::std::size_t Vec<::concrete_optimizer::dag::CircuitBoostrapKey>::size() const noexcept { + return cxxbridge1$rust_vec$concrete_optimizer$dag$CircuitBoostrapKey$len(this); +} +template <> +::std::size_t Vec<::concrete_optimizer::dag::CircuitBoostrapKey>::capacity() const noexcept { + return cxxbridge1$rust_vec$concrete_optimizer$dag$CircuitBoostrapKey$capacity(this); +} +template <> +::concrete_optimizer::dag::CircuitBoostrapKey const *Vec<::concrete_optimizer::dag::CircuitBoostrapKey>::data() const noexcept { + return cxxbridge1$rust_vec$concrete_optimizer$dag$CircuitBoostrapKey$data(this); +} +template <> +void Vec<::concrete_optimizer::dag::CircuitBoostrapKey>::reserve_total(::std::size_t new_cap) noexcept { + return cxxbridge1$rust_vec$concrete_optimizer$dag$CircuitBoostrapKey$reserve_total(this, new_cap); +} +template <> +void Vec<::concrete_optimizer::dag::CircuitBoostrapKey>::set_len(::std::size_t len) noexcept { + return cxxbridge1$rust_vec$concrete_optimizer$dag$CircuitBoostrapKey$set_len(this, len); +} +template <> +void Vec<::concrete_optimizer::dag::CircuitBoostrapKey>::truncate(::std::size_t len) { + return cxxbridge1$rust_vec$concrete_optimizer$dag$CircuitBoostrapKey$truncate(this, len); +} +template <> +Vec<::PrivateFunctionalPackingBoostrapKey>::Vec() noexcept { + cxxbridge1$rust_vec$PrivateFunctionalPackingBoostrapKey$new(this); +} +template <> +void Vec<::PrivateFunctionalPackingBoostrapKey>::drop() noexcept { + return cxxbridge1$rust_vec$PrivateFunctionalPackingBoostrapKey$drop(this); +} +template <> +::std::size_t Vec<::PrivateFunctionalPackingBoostrapKey>::size() const noexcept { + return cxxbridge1$rust_vec$PrivateFunctionalPackingBoostrapKey$len(this); +} +template <> +::std::size_t Vec<::PrivateFunctionalPackingBoostrapKey>::capacity() const noexcept { + return cxxbridge1$rust_vec$PrivateFunctionalPackingBoostrapKey$capacity(this); +} +template <> +::PrivateFunctionalPackingBoostrapKey const *Vec<::PrivateFunctionalPackingBoostrapKey>::data() const noexcept { + return cxxbridge1$rust_vec$PrivateFunctionalPackingBoostrapKey$data(this); +} +template <> +void Vec<::PrivateFunctionalPackingBoostrapKey>::reserve_total(::std::size_t new_cap) noexcept { + return cxxbridge1$rust_vec$PrivateFunctionalPackingBoostrapKey$reserve_total(this, new_cap); +} +template <> +void Vec<::PrivateFunctionalPackingBoostrapKey>::set_len(::std::size_t len) noexcept { + return cxxbridge1$rust_vec$PrivateFunctionalPackingBoostrapKey$set_len(this, len); +} +template <> +void Vec<::PrivateFunctionalPackingBoostrapKey>::truncate(::std::size_t len) { + return cxxbridge1$rust_vec$PrivateFunctionalPackingBoostrapKey$truncate(this, len); +} +template <> Vec<::concrete_optimizer::dag::InstructionKeys>::Vec() noexcept { cxxbridge1$rust_vec$concrete_optimizer$dag$InstructionKeys$new(this); } diff --git a/compilers/concrete-optimizer/concrete-optimizer-cpp/src/cpp/concrete-optimizer.hpp b/compilers/concrete-optimizer/concrete-optimizer-cpp/src/cpp/concrete-optimizer.hpp index ddc053baa..a54a4e5a5 100644 --- a/compilers/concrete-optimizer/concrete-optimizer-cpp/src/cpp/concrete-optimizer.hpp +++ b/compilers/concrete-optimizer/concrete-optimizer-cpp/src/cpp/concrete-optimizer.hpp @@ -919,6 +919,8 @@ std::size_t align_of() { } // namespace cxxbridge1 } // namespace rust +struct PrivateFunctionalPackingBoostrapKey; +struct CircuitKeys; namespace concrete_optimizer { struct OperationDag; struct Weights; @@ -933,7 +935,7 @@ namespace concrete_optimizer { struct BootstrapKey; struct KeySwitchKey; struct ConversionKeySwitchKey; - struct CircuitKeys; + struct CircuitBoostrapKey; struct InstructionKeys; struct CircuitSolution; } @@ -1136,24 +1138,56 @@ struct ConversionKeySwitchKey final { }; #endif // CXXBRIDGE1_STRUCT_concrete_optimizer$dag$ConversionKeySwitchKey -#ifndef CXXBRIDGE1_STRUCT_concrete_optimizer$dag$CircuitKeys -#define CXXBRIDGE1_STRUCT_concrete_optimizer$dag$CircuitKeys +#ifndef CXXBRIDGE1_STRUCT_concrete_optimizer$dag$CircuitBoostrapKey +#define CXXBRIDGE1_STRUCT_concrete_optimizer$dag$CircuitBoostrapKey +struct CircuitBoostrapKey final { + ::std::uint64_t identifier; + ::concrete_optimizer::dag::SecretLweKey representation_key; + ::concrete_optimizer::dag::BrDecompositionParameters br_decomposition_parameter; + ::rust::String description; + + using IsRelocatable = ::std::true_type; +}; +#endif // CXXBRIDGE1_STRUCT_concrete_optimizer$dag$CircuitBoostrapKey +} // namespace dag +} // namespace concrete_optimizer + +#ifndef CXXBRIDGE1_STRUCT_PrivateFunctionalPackingBoostrapKey +#define CXXBRIDGE1_STRUCT_PrivateFunctionalPackingBoostrapKey +struct PrivateFunctionalPackingBoostrapKey final { + ::std::uint64_t identifier; + ::concrete_optimizer::dag::SecretLweKey representation_key; + ::concrete_optimizer::dag::BrDecompositionParameters br_decomposition_parameter; + ::rust::String description; + + using IsRelocatable = ::std::true_type; +}; +#endif // CXXBRIDGE1_STRUCT_PrivateFunctionalPackingBoostrapKey + +#ifndef CXXBRIDGE1_STRUCT_CircuitKeys +#define CXXBRIDGE1_STRUCT_CircuitKeys struct CircuitKeys final { ::rust::Vec<::concrete_optimizer::dag::SecretLweKey> secret_keys; ::rust::Vec<::concrete_optimizer::dag::KeySwitchKey> keyswitch_keys; ::rust::Vec<::concrete_optimizer::dag::BootstrapKey> bootstrap_keys; ::rust::Vec<::concrete_optimizer::dag::ConversionKeySwitchKey> conversion_keyswitch_keys; + ::rust::Vec<::concrete_optimizer::dag::CircuitBoostrapKey> circuit_bootstrap_keys; + ::rust::Vec<::PrivateFunctionalPackingBoostrapKey> private_functional_packing_keys; using IsRelocatable = ::std::true_type; }; -#endif // CXXBRIDGE1_STRUCT_concrete_optimizer$dag$CircuitKeys +#endif // CXXBRIDGE1_STRUCT_CircuitKeys +namespace concrete_optimizer { +namespace dag { #ifndef CXXBRIDGE1_STRUCT_concrete_optimizer$dag$InstructionKeys #define CXXBRIDGE1_STRUCT_concrete_optimizer$dag$InstructionKeys struct InstructionKeys final { ::std::uint64_t input_key; ::std::uint64_t tlu_keyswitch_key; ::std::uint64_t tlu_bootstrap_key; + ::std::uint64_t tlu_circuit_bootstrap_key; + ::std::uint64_t tlu_private_functional_packing_key; ::std::uint64_t output_key; ::rust::Vec<::std::uint64_t> extra_conversion_keys; @@ -1164,8 +1198,9 @@ struct InstructionKeys final { #ifndef CXXBRIDGE1_STRUCT_concrete_optimizer$dag$CircuitSolution #define CXXBRIDGE1_STRUCT_concrete_optimizer$dag$CircuitSolution struct CircuitSolution final { - ::concrete_optimizer::dag::CircuitKeys circuit_keys; + ::CircuitKeys circuit_keys; ::rust::Vec<::concrete_optimizer::dag::InstructionKeys> instructions_keys; + ::rust::Vec<::std::uint64_t> crt_decomposition; double complexity; double p_error; double global_p_error; @@ -1195,4 +1230,6 @@ namespace dag { namespace weights { ::rust::Box<::concrete_optimizer::Weights> vector(::rust::Slice<::std::int64_t const> weights) noexcept; } // namespace weights + +::std::uint64_t NO_KEY_ID() noexcept; } // namespace concrete_optimizer diff --git a/compilers/concrete-optimizer/concrete-optimizer-cpp/tests/src/main.cpp b/compilers/concrete-optimizer/concrete-optimizer-cpp/tests/src/main.cpp index bffc73fba..3483d8e06 100644 --- a/compilers/concrete-optimizer/concrete-optimizer-cpp/tests/src/main.cpp +++ b/compilers/concrete-optimizer/concrete-optimizer-cpp/tests/src/main.cpp @@ -171,6 +171,42 @@ void test_multi_parameters_2_precision() { assert(actual == expected); } +void test_multi_parameters_2_precision_crt() { + auto dag = concrete_optimizer::dag::empty(); + + std::vector shape = {3}; + + concrete_optimizer::dag::OperatorIndex input1 = + dag->add_input(PRECISION_8B, slice(shape)); + + concrete_optimizer::dag::OperatorIndex input2 = + dag->add_input(PRECISION_1B, slice(shape)); + + + std::vector table = {}; + auto lut1 = dag->add_lut(input1, slice(table), PRECISION_8B); + auto lut2 = dag->add_lut(input2, slice(table), PRECISION_8B); + + std::vector inputs = {lut1, lut2}; + + std::vector weight_vec = {1, 1}; + + rust::cxxbridge1::Box weights = + concrete_optimizer::weights::vector(slice(weight_vec)); + + dag->add_dot(slice(inputs), std::move(weights)); + + auto options = default_options(); + options.encoding = concrete_optimizer::Encoding::Crt; + auto circuit_solution = dag->optimize_multi(options); + assert(circuit_solution.is_feasible); + auto secret_keys = circuit_solution.circuit_keys.secret_keys; + assert(circuit_solution.circuit_keys.secret_keys.size() == 2); + assert(circuit_solution.circuit_keys.bootstrap_keys.size() == 1); + assert(circuit_solution.circuit_keys.keyswitch_keys.size() == 1); + assert(circuit_solution.circuit_keys.conversion_keyswitch_keys.size() == 0); +} + int main() { test_v0(); test_dag_no_lut(); @@ -179,6 +215,7 @@ int main() { test_dag_lut_force_wop(); test_multi_parameters_1_precision(); test_multi_parameters_2_precision(); + test_multi_parameters_2_precision_crt(); return 0; } diff --git a/compilers/concrete-optimizer/concrete-optimizer/src/optimization/dag/multi_parameters/analyze.rs b/compilers/concrete-optimizer/concrete-optimizer/src/optimization/dag/multi_parameters/analyze.rs index 5567d3f1e..2c9aa5617 100644 --- a/compilers/concrete-optimizer/concrete-optimizer/src/optimization/dag/multi_parameters/analyze.rs +++ b/compilers/concrete-optimizer/concrete-optimizer/src/optimization/dag/multi_parameters/analyze.rs @@ -152,6 +152,8 @@ pub fn original_instrs_partition( tlu_bootstrap_key: tlu_bootstrap_key.unwrap_or(unknown), output_key: big_keys[partition].identifier, extra_conversion_keys: conversion_key.iter().copied().collect(), + tlu_circuit_bootstrap_key: keys_spec::NO_KEY_ID, + tlu_private_functional_packing_key: keys_spec::NO_KEY_ID, }; result.push(merged); } diff --git a/compilers/concrete-optimizer/concrete-optimizer/src/optimization/dag/multi_parameters/keys_spec.rs b/compilers/concrete-optimizer/concrete-optimizer/src/optimization/dag/multi_parameters/keys_spec.rs index ea22e068e..34fbf4f25 100644 --- a/compilers/concrete-optimizer/concrete-optimizer/src/optimization/dag/multi_parameters/keys_spec.rs +++ b/compilers/concrete-optimizer/concrete-optimizer/src/optimization/dag/multi_parameters/keys_spec.rs @@ -1,3 +1,4 @@ +use crate::optimization::wop_atomic_pattern; use crate::parameters::{BrDecompositionParameters, KsDecompositionParameters}; use crate::optimization::dag::multi_parameters::optimize::MacroParameters; @@ -8,6 +9,9 @@ pub type SecretLweKeyId = Id; pub type BootstrapKeyId = Id; pub type KeySwitchKeyId = Id; pub type ConversionKeySwitchKeyId = Id; +pub type CircuitBoostrapKeyId = Id; +pub type PrivateFunctionalPackingBoostrapKeyId = Id; +pub const NO_KEY_ID: Id = Id::MAX; #[derive(Debug, Clone)] pub struct SecretLweKey { @@ -50,6 +54,22 @@ pub struct ConversionKeySwitchKey { pub description: String, } +#[derive(Debug, Clone)] +pub struct CircuitBoostrapKey { + pub identifier: ConversionKeySwitchKeyId, + pub representation_key: SecretLweKey, + pub br_decomposition_parameter: BrDecompositionParameters, + pub description: String, +} + +#[derive(Debug, Clone)] +pub struct PrivateFunctionalPackingBoostrapKey { + pub identifier: PrivateFunctionalPackingBoostrapKeyId, + pub representation_key: SecretLweKey, + pub br_decomposition_parameter: BrDecompositionParameters, + pub description: String, +} + #[derive(Debug, Default, Clone)] pub struct CircuitKeys { /* All keys used in a circuit, sorted by Id for each key type */ @@ -57,6 +77,8 @@ pub struct CircuitKeys { pub keyswitch_keys: Vec, pub bootstrap_keys: Vec, pub conversion_keyswitch_keys: Vec, + pub circuit_bootstrap_keys: Vec, + pub private_functional_packing_keys: Vec, } #[derive(Debug, Clone)] @@ -68,11 +90,13 @@ pub struct InstructionKeys { pub input_key: SecretLweKeyId, pub tlu_keyswitch_key: KeySwitchKeyId, pub tlu_bootstrap_key: BootstrapKeyId, + pub tlu_circuit_bootstrap_key: CircuitBoostrapKeyId, + pub tlu_private_functional_packing_key: PrivateFunctionalPackingBoostrapKeyId, pub output_key: SecretLweKeyId, pub extra_conversion_keys: Vec, } -#[derive(Debug, Clone)] +#[derive(Debug, Default, Clone)] pub struct CircuitSolution { pub circuit_keys: CircuitKeys, /* instructions keys ordered by instructions index of the original dag original (i.e. in same order): @@ -88,16 +112,120 @@ pub struct CircuitSolution { pub p_error: f64, /* result error rate, assuming any error will propagate to the result */ pub global_p_error: f64, + pub crt_decomposition: Vec, // empty in native case pub is_feasible: bool, pub error_msg: String, } +impl CircuitSolution { + pub fn no_solution(error_msg: impl Into) -> Self { + Self { + is_feasible: false, + complexity: f64::INFINITY, + p_error: 1.0, + global_p_error: 1.0, + error_msg: error_msg.into(), + ..Self::default() + } + } + + pub fn from_wop_solution(sol: wop_atomic_pattern::Solution, nb_instr: usize) -> Self { + let big_key = SecretLweKey { + identifier: 0, + polynomial_size: sol.glwe_polynomial_size, + glwe_dimension: sol.glwe_dimension, + description: "big-secret".into(), + }; + let small_key = SecretLweKey { + identifier: 1, + polynomial_size: sol.internal_ks_output_lwe_dimension, + glwe_dimension: 1, + description: "small-secret".into(), + }; + let keyswitch_key = KeySwitchKey { + identifier: 0, + input_key: big_key.clone(), + output_key: small_key.clone(), + ks_decomposition_parameter: KsDecompositionParameters { + level: sol.ks_decomposition_level_count, + log2_base: sol.ks_decomposition_base_log, + }, + description: "tlu keyswitch".into(), + }; + let bootstrap_key = BootstrapKey { + identifier: 0, + input_key: small_key.clone(), + output_key: big_key.clone(), + br_decomposition_parameter: BrDecompositionParameters { + level: sol.br_decomposition_level_count, + log2_base: sol.br_decomposition_base_log, + }, + description: "tlu bootstrap".into(), + }; + let circuit_bootstrap_key = CircuitBoostrapKey { + identifier: 0, + representation_key: big_key.clone(), + br_decomposition_parameter: BrDecompositionParameters { + level: sol.cb_decomposition_level_count, + log2_base: sol.cb_decomposition_base_log, + }, + description: "circuit bootstrap for woppbs".into(), + }; + let private_functional_packing_key = PrivateFunctionalPackingBoostrapKey { + identifier: 0, + representation_key: big_key.clone(), + br_decomposition_parameter: BrDecompositionParameters { + level: sol.pp_decomposition_level_count, + log2_base: sol.pp_decomposition_base_log, + }, + description: "private functional packing for woppbs".into(), + }; + let instruction_keys = InstructionKeys { + input_key: big_key.identifier, + tlu_keyswitch_key: keyswitch_key.identifier, + tlu_bootstrap_key: bootstrap_key.identifier, + output_key: big_key.identifier, + extra_conversion_keys: vec![], + tlu_circuit_bootstrap_key: circuit_bootstrap_key.identifier, + tlu_private_functional_packing_key: private_functional_packing_key.identifier, + }; + let instructions_keys = vec![instruction_keys; nb_instr]; + let circuit_keys = CircuitKeys { + secret_keys: [big_key, small_key].into(), + keyswitch_keys: [keyswitch_key].into(), + bootstrap_keys: [bootstrap_key].into(), + conversion_keyswitch_keys: [].into(), + circuit_bootstrap_keys: [circuit_bootstrap_key].into(), + private_functional_packing_keys: [private_functional_packing_key].into(), + }; + let is_feasible = sol.p_error < 1.0; + let error_msg = if is_feasible { + "" + } else { + "No crypto-parameters for the given constraints" + } + .into(); + Self { + circuit_keys, + instructions_keys, + complexity: sol.complexity, + p_error: sol.p_error, + global_p_error: sol.p_error, + crt_decomposition: sol.crt_decomposition, + is_feasible: true, + error_msg, + } + } +} + pub struct ExpandedCircuitKeys { pub big_secret_keys: Vec, pub small_secret_keys: Vec, pub keyswitch_keys: Vec>>, pub bootstrap_keys: Vec, pub conversion_keyswitch_keys: Vec>>, + pub circuit_bootstrap_keys: Vec, + pub private_functional_packing_keys: Vec, } impl ExpandedCircuitKeys { @@ -192,6 +320,9 @@ impl ExpandedCircuitKeys { keyswitch_keys, bootstrap_keys, conversion_keyswitch_keys, + // for now woppbs never get by that path + circuit_bootstrap_keys: vec![], + private_functional_packing_keys: vec![], } } @@ -211,6 +342,8 @@ impl ExpandedCircuitKeys { .flatten() .flatten() .collect(), + circuit_bootstrap_keys: self.circuit_bootstrap_keys, + private_functional_packing_keys: self.private_functional_packing_keys, } } } diff --git a/compilers/concrete-optimizer/concrete-optimizer/src/optimization/dag/multi_parameters/mod.rs b/compilers/concrete-optimizer/concrete-optimizer/src/optimization/dag/multi_parameters/mod.rs index 3d3ca3723..8c23b05a8 100644 --- a/compilers/concrete-optimizer/concrete-optimizer/src/optimization/dag/multi_parameters/mod.rs +++ b/compilers/concrete-optimizer/concrete-optimizer/src/optimization/dag/multi_parameters/mod.rs @@ -5,6 +5,7 @@ mod feasible; pub mod keys_spec; mod operations_value; pub mod optimize; +pub mod optimize_generic; mod partitionning; mod partitions; mod precision_cut; diff --git a/compilers/concrete-optimizer/concrete-optimizer/src/optimization/dag/multi_parameters/optimize.rs b/compilers/concrete-optimizer/concrete-optimizer/src/optimization/dag/multi_parameters/optimize.rs index 459436c0d..cc3f5e0bc 100644 --- a/compilers/concrete-optimizer/concrete-optimizer/src/optimization/dag/multi_parameters/optimize.rs +++ b/compilers/concrete-optimizer/concrete-optimizer/src/optimization/dag/multi_parameters/optimize.rs @@ -1028,6 +1028,7 @@ pub fn optimize_to_circuit_solution( keys_spec::CircuitSolution { circuit_keys, instructions_keys, + crt_decomposition: vec![], complexity: params.complexity, p_error: params.p_error, global_p_error: params.global_p_error, @@ -1038,6 +1039,7 @@ pub fn optimize_to_circuit_solution( keys_spec::CircuitSolution { circuit_keys: keys_spec::CircuitKeys::default(), instructions_keys: vec![], + crt_decomposition: vec![], complexity: f64::INFINITY, p_error: 1.0, global_p_error: 1.0, diff --git a/compilers/concrete-optimizer/concrete-optimizer/src/optimization/dag/multi_parameters/optimize_generic.rs b/compilers/concrete-optimizer/concrete-optimizer/src/optimization/dag/multi_parameters/optimize_generic.rs new file mode 100644 index 000000000..f6247a060 --- /dev/null +++ b/compilers/concrete-optimizer/concrete-optimizer/src/optimization/dag/multi_parameters/optimize_generic.rs @@ -0,0 +1,70 @@ +use crate::dag::unparametrized::OperationDag; +use crate::optimization::config::{Config, SearchSpace}; +use crate::optimization::dag::multi_parameters::keys_spec::CircuitSolution; +use crate::optimization::dag::multi_parameters::optimize::optimize_to_circuit_solution as native_optimize; +use crate::optimization::dag::solo_key::analyze; +use crate::optimization::dag::solo_key::optimize_generic::{max_precision, Encoding}; +use crate::optimization::decomposition::PersistDecompCaches; +use crate::optimization::wop_atomic_pattern::optimize::optimize_to_circuit_solution as crt_optimize_no_dag; + +use super::precision_cut::PrecisionCut; + +fn best_complexity_solution(native: CircuitSolution, crt: CircuitSolution) -> CircuitSolution { + match (&native.is_feasible, &crt.is_feasible) { + (true, true) => { + // crt has 0 complexity in no lut case + // so we always select native in this case + if native.complexity <= crt.complexity || crt.complexity == 0.0 { + native + } else { + crt + } + } + (false, true) => crt, + _ => native, + } +} + +fn crt_optimize( + dag: &OperationDag, + config: Config, + search_space: &SearchSpace, + default_log_norm2_woppbs: f64, + caches: &PersistDecompCaches, +) -> CircuitSolution { + if analyze::has_round(dag) { + return CircuitSolution::no_solution("Crt does not support round operator"); + } // TODO: dag to params + let max_precision = max_precision(dag); + let nb_luts = analyze::lut_count_from_dag(dag); + let worst_log_norm = analyze::worst_log_norm_for_wop(dag); + let log_norm = default_log_norm2_woppbs.min(worst_log_norm); + let nb_instr = dag.operators.len(); + crt_optimize_no_dag( + max_precision as u64, + nb_instr, + nb_luts, + config, + log_norm, + search_space, + caches, + ) +} + +pub fn optimize( + dag: &OperationDag, + config: Config, + search_space: &SearchSpace, + encoding: Encoding, + default_log_norm2_woppbs: f64, + caches: &PersistDecompCaches, + p_cut: &Option, +) -> CircuitSolution { + let native = || native_optimize(dag, config, search_space, caches, p_cut); + let crt = || crt_optimize(dag, config, search_space, default_log_norm2_woppbs, caches); + match encoding { + Encoding::Auto => best_complexity_solution(native(), crt()), + Encoding::Native => native(), + Encoding::Crt => crt(), + } +} diff --git a/compilers/concrete-optimizer/concrete-optimizer/src/optimization/dag/solo_key/optimize_generic.rs b/compilers/concrete-optimizer/concrete-optimizer/src/optimization/dag/solo_key/optimize_generic.rs index 3429794fd..3a7736ba2 100644 --- a/compilers/concrete-optimizer/concrete-optimizer/src/optimization/dag/solo_key/optimize_generic.rs +++ b/compilers/concrete-optimizer/concrete-optimizer/src/optimization/dag/solo_key/optimize_generic.rs @@ -31,11 +31,11 @@ pub enum Encoding { Crt, } -fn max_precision(dag: &OperationDag) -> Precision { +pub fn max_precision(dag: &OperationDag) -> Precision { dag.out_precisions.iter().copied().max().unwrap_or(0) } -fn updated_global_p_error_and_comlexity(nb_luts: u64, sol: WopSolution) -> WopSolution { +fn updated_global_p_error_and_complexity(nb_luts: u64, sol: WopSolution) -> WopSolution { let global_p_error = repeat_p_error(sol.p_error, nb_luts); let complexity = nb_luts as f64 * sol.complexity; WopSolution { @@ -78,7 +78,7 @@ fn optimize_with_wop_pbs( let log_norm = default_log_norm2_woppbs.min(worst_log_norm); wop_optimize(max_precision as u64, config, log_norm, search_space, caches) .best_solution - .map(|sol| updated_global_p_error_and_comlexity(nb_luts, sol)) + .map(|sol| updated_global_p_error_and_complexity(nb_luts, sol)) } pub fn optimize( diff --git a/compilers/concrete-optimizer/concrete-optimizer/src/optimization/wop_atomic_pattern/optimize.rs b/compilers/concrete-optimizer/concrete-optimizer/src/optimization/wop_atomic_pattern/optimize.rs index 267b4e9e3..35268267f 100644 --- a/compilers/concrete-optimizer/concrete-optimizer/src/optimization/wop_atomic_pattern/optimize.rs +++ b/compilers/concrete-optimizer/concrete-optimizer/src/optimization/wop_atomic_pattern/optimize.rs @@ -7,10 +7,12 @@ use crate::noise_estimator::error::{ error_probability_of_sigma_scale, safe_variance_bound_product_1padbit, sigma_scale_of_error_probability, }; +use crate::noise_estimator::p_error::repeat_p_error; use crate::optimization::atomic_pattern; use crate::optimization::atomic_pattern::OptimizationDecompositionsConsts; use crate::optimization::config::{Config, SearchSpace}; +use crate::optimization::dag::multi_parameters::keys_spec; use crate::optimization::decomposition::circuit_bootstrap::{CbComplexityNoise, CbPareto}; use crate::optimization::decomposition::cmux::CmuxComplexityNoise; use crate::optimization::decomposition::keyswitch::KsComplexityNoise; @@ -533,3 +535,39 @@ pub fn optimize_one_compat( best_solution: result.best_solution.map(Solution::into), } } + +pub fn optimize_to_circuit_solution( + precision: u64, + nb_instr: usize, + nb_luts: u64, + config: Config, + log_norm: f64, + search_space: &SearchSpace, + caches: &PersistDecompCaches, +) -> keys_spec::CircuitSolution { + let Ok(coprimes) = crt_decomposition::default_coprimes(precision as Precision) else { + return keys_spec::CircuitSolution::no_solution("Crt decomposition is not unknown for {precision}:bits") + }; + let n_functions = 1; + let state = optimize_raw( + log_norm, + config, + search_space, + n_functions, + &coprimes, + caches, + ); + if let Some(sol) = state.best_solution { + keys_spec::CircuitSolution { + crt_decomposition: coprimes, + global_p_error: repeat_p_error(sol.p_error, nb_luts), + complexity: nb_luts as f64 * sol.complexity, + ..keys_spec::CircuitSolution::from_wop_solution(sol, nb_instr) + } + } else { + keys_spec::CircuitSolution { + crt_decomposition: coprimes, + ..keys_spec::CircuitSolution::no_solution("No crypto parameters") + } + } +}