From 84c2cedcc12835c1f2b0f81525cef0cd2d581022 Mon Sep 17 00:00:00 2001 From: 0xjei Date: Thu, 5 Feb 2026 16:19:04 +0100 Subject: [PATCH 1/4] add share-encryption circuit gen --- circuits/lib/src/configs/insecure/dkg.nr | 25 +- circuits/lib/src/configs/secure/dkg.nr | 27 +- crates/zk-helpers/src/bin/zk_cli.rs | 33 +- crates/zk-helpers/src/circuits/dkg/mod.rs | 1 + .../circuits/dkg/share_encryption/circuit.rs | 46 + .../circuits/dkg/share_encryption/codegen.rs | 297 ++++++ .../dkg/share_encryption/computation.rs | 996 ++++++++++++++++++ .../src/circuits/dkg/share_encryption/mod.rs | 15 + .../circuits/dkg/share_encryption/sample.rs | 186 ++++ crates/zk-helpers/src/utils.rs | 13 + 10 files changed, 1609 insertions(+), 30 deletions(-) create mode 100644 crates/zk-helpers/src/circuits/dkg/share_encryption/circuit.rs create mode 100644 crates/zk-helpers/src/circuits/dkg/share_encryption/codegen.rs create mode 100644 crates/zk-helpers/src/circuits/dkg/share_encryption/computation.rs create mode 100644 crates/zk-helpers/src/circuits/dkg/share_encryption/mod.rs create mode 100644 crates/zk-helpers/src/circuits/dkg/share_encryption/sample.rs diff --git a/circuits/lib/src/configs/insecure/dkg.nr b/circuits/lib/src/configs/insecure/dkg.nr index 3797eb9a2b..06f8218579 100644 --- a/circuits/lib/src/configs/insecure/dkg.nr +++ b/circuits/lib/src/configs/insecure/dkg.nr @@ -74,19 +74,17 @@ share_encryption_sk (CIRCUIT 3a) ------------------------------------- ************************************/ -// share_encryption_sk - bit parameters -pub global SHARE_ENCRYPTION_BIT_PK: u32 = 51; -pub global SHARE_ENCRYPTION_BIT_CT: u32 = 51; -pub global SHARE_ENCRYPTION_BIT_U: u32 = 2; -pub global SHARE_ENCRYPTION_BIT_E0: u32 = 4; -pub global SHARE_ENCRYPTION_BIT_E1: u32 = 4; -pub global SHARE_ENCRYPTION_BIT_MSG: u32 = 37; -pub global SHARE_ENCRYPTION_BIT_R1: u32 = 36; -pub global SHARE_ENCRYPTION_BIT_R2: u32 = 51; -pub global SHARE_ENCRYPTION_BIT_P1: u32 = 10; -pub global SHARE_ENCRYPTION_BIT_P2: u32 = 51; - -// share_encryption_sk - bounds +pub global SHARE_ENCRYPTION_BIT_PK: u32 = 50; +pub global SHARE_ENCRYPTION_BIT_CT: u32 = 50; +pub global SHARE_ENCRYPTION_BIT_U: u32 = 1; +pub global SHARE_ENCRYPTION_BIT_E0: u32 = 3; +pub global SHARE_ENCRYPTION_BIT_E1: u32 = 3; +pub global SHARE_ENCRYPTION_BIT_MSG: u32 = 36; +pub global SHARE_ENCRYPTION_BIT_R1: u32 = 35; +pub global SHARE_ENCRYPTION_BIT_R2: u32 = 50; +pub global SHARE_ENCRYPTION_BIT_P1: u32 = 9; +pub global SHARE_ENCRYPTION_BIT_P2: u32 = 50; + pub global SHARE_ENCRYPTION_T: Field = 68719403009; pub global SHARE_ENCRYPTION_Q_MOD_T: Field = 2415755265; pub global SHARE_ENCRYPTION_K0IS: [Field; L] = [1284838520228573]; @@ -101,7 +99,6 @@ pub global SHARE_ENCRYPTION_P1_BOUNDS: [Field; L] = [256]; pub global SHARE_ENCRYPTION_P2_BOUNDS: [Field; L] = [1125899906777088]; pub global SHARE_ENCRYPTION_MSG_BOUND: Field = 68719403008; -// share_encryption_sk - configs pub global SHARE_ENCRYPTION_CONFIGS_SK: ShareEncryptionConfigs = ShareEncryptionConfigs::new( SHARE_ENCRYPTION_T, SHARE_ENCRYPTION_Q_MOD_T, diff --git a/circuits/lib/src/configs/secure/dkg.nr b/circuits/lib/src/configs/secure/dkg.nr index 27e544b637..2a8f97f23f 100644 --- a/circuits/lib/src/configs/secure/dkg.nr +++ b/circuits/lib/src/configs/secure/dkg.nr @@ -86,19 +86,17 @@ share_encryption_sk (CIRCUIT 3a) ------------------------------------- ************************************/ -// share_encryption_sk - bit parameters -pub global SHARE_ENCRYPTION_BIT_PK: u32 = 57; -pub global SHARE_ENCRYPTION_BIT_CT: u32 = 57; -pub global SHARE_ENCRYPTION_BIT_U: u32 = 2; -pub global SHARE_ENCRYPTION_BIT_E0: u32 = 6; -pub global SHARE_ENCRYPTION_BIT_E1: u32 = 6; -pub global SHARE_ENCRYPTION_BIT_MSG: u32 = 55; -pub global SHARE_ENCRYPTION_BIT_R1: u32 = 54; -pub global SHARE_ENCRYPTION_BIT_R2: u32 = 57; -pub global SHARE_ENCRYPTION_BIT_P1: u32 = 14; -pub global SHARE_ENCRYPTION_BIT_P2: u32 = 57; - -// share_encryption_sk - bounds +pub global SHARE_ENCRYPTION_BIT_PK: u32 = 56; +pub global SHARE_ENCRYPTION_BIT_CT: u32 = 56; +pub global SHARE_ENCRYPTION_BIT_U: u32 = 1; +pub global SHARE_ENCRYPTION_BIT_E0: u32 = 5; +pub global SHARE_ENCRYPTION_BIT_E1: u32 = 5; +pub global SHARE_ENCRYPTION_BIT_MSG: u32 = 54; +pub global SHARE_ENCRYPTION_BIT_R1: u32 = 53; +pub global SHARE_ENCRYPTION_BIT_R2: u32 = 56; +pub global SHARE_ENCRYPTION_BIT_P1: u32 = 13; +pub global SHARE_ENCRYPTION_BIT_P2: u32 = 56; + pub global SHARE_ENCRYPTION_T: Field = 18014398509481984; pub global SHARE_ENCRYPTION_Q_MOD_T: Field = 1082658244788225; pub global SHARE_ENCRYPTION_K0IS: [Field; L] = [70854796903366627, 47439047573780733]; @@ -113,7 +111,6 @@ pub global SHARE_ENCRYPTION_P1_BOUNDS: [Field; L] = [4096, 4096]; pub global SHARE_ENCRYPTION_P2_BOUNDS: [Field; L] = [36028797041049600, 36028797031219200]; pub global SHARE_ENCRYPTION_MSG_BOUND: Field = 18014398509481983; -// share_encryption_sk - configs pub global SHARE_ENCRYPTION_CONFIGS_SK: ShareEncryptionConfigs = ShareEncryptionConfigs::new( SHARE_ENCRYPTION_T, SHARE_ENCRYPTION_Q_MOD_T, @@ -137,7 +134,7 @@ share_encryption_e_sm (CIRCUIT 3b) ------------------------------------- ************************************/ -// share_encryption_e_sm uses the same bit parameters and bounds as SK +// share_encryption_e_sm uses the same bit parameters and bounds as share_encryption_sk pub global SHARE_ENCRYPTION_CONFIGS_E_SM: ShareEncryptionConfigs = ShareEncryptionConfigs::new( SHARE_ENCRYPTION_T, SHARE_ENCRYPTION_Q_MOD_T, diff --git a/crates/zk-helpers/src/bin/zk_cli.rs b/crates/zk-helpers/src/bin/zk_cli.rs index d29475d8bb..947de61b98 100644 --- a/crates/zk-helpers/src/bin/zk_cli.rs +++ b/crates/zk-helpers/src/bin/zk_cli.rs @@ -20,6 +20,9 @@ use e3_zk_helpers::circuits::dkg::share_computation::circuit::{ }; use e3_zk_helpers::codegen::{write_artifacts, CircuitCodegen}; use e3_zk_helpers::computation::DkgInputType; +use e3_zk_helpers::dkg::share_encryption::{ + ShareEncryptionCircuit, ShareEncryptionCircuitInput, ShareEncryptionSample, +}; use e3_zk_helpers::registry::{Circuit, CircuitRegistry}; use e3_zk_helpers::threshold::{ UserDataEncryptionCircuit, UserDataEncryptionCircuitInput, UserDataEncryptionSample, @@ -153,6 +156,7 @@ fn main() -> Result<()> { registry.register(Arc::new(PkCircuit)); registry.register(Arc::new(ShareComputationCircuit)); registry.register(Arc::new(UserDataEncryptionCircuit)); + registry.register(Arc::new(ShareEncryptionCircuit)); // Handle list circuits flag. if args.list_circuits { @@ -201,7 +205,8 @@ fn main() -> Result<()> { let write_prover_toml = args.toml; // Only share-computation has a witness-type choice (secret-key vs smudging-noise). pk always uses secret key. - let has_witness_type = circuit_meta.name() == ShareComputationCircuit::NAME; + let has_witness_type = circuit_meta.name() == ShareComputationCircuit::NAME + || circuit_meta.name() == ShareEncryptionCircuit::NAME; let dkg_input_type = if has_witness_type { // Share-computation: require --witness when generating Prover.toml; default secret-key for configs-only. @@ -273,6 +278,32 @@ fn main() -> Result<()> { }, )? } + name if name == ::NAME => { + let sd = preset + .search_defaults() + .ok_or_else(|| anyhow!("missing search_defaults for preset"))?; + let sample = ShareEncryptionSample::generate( + preset, + CiphernodesCommitteeSize::Small, + dkg_input_type, + sd.z, + sd.lambda, + ); + let circuit = ShareEncryptionCircuit; + + circuit.codegen( + preset, + &ShareEncryptionCircuitInput { + plaintext: sample.plaintext, + ciphertext: sample.ciphertext, + public_key: sample.public_key, + secret_key: sample.secret_key, + u_rns: sample.u_rns, + e0_rns: sample.e0_rns, + e1_rns: sample.e1_rns, + }, + )? + } name if name == ::NAME => { let sample = UserDataEncryptionSample::generate(preset); let circuit = UserDataEncryptionCircuit; diff --git a/crates/zk-helpers/src/circuits/dkg/mod.rs b/crates/zk-helpers/src/circuits/dkg/mod.rs index 905b80d19e..deb387206b 100644 --- a/crates/zk-helpers/src/circuits/dkg/mod.rs +++ b/crates/zk-helpers/src/circuits/dkg/mod.rs @@ -6,3 +6,4 @@ pub mod pk; pub mod share_computation; +pub mod share_encryption; diff --git a/crates/zk-helpers/src/circuits/dkg/share_encryption/circuit.rs b/crates/zk-helpers/src/circuits/dkg/share_encryption/circuit.rs new file mode 100644 index 0000000000..93bc22c389 --- /dev/null +++ b/crates/zk-helpers/src/circuits/dkg/share_encryption/circuit.rs @@ -0,0 +1,46 @@ +// SPDX-License-Identifier: LGPL-3.0-only +// +// This file is provided WITHOUT ANY WARRANTY; +// without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. + +//! Circuit definition and input type for the share-encryption ZK circuit (CIRCUIT 3a/3b). + +use crate::computation::DkgInputType; +use crate::registry::Circuit; +use e3_fhe_params::ParameterType; +use fhe::bfv::Ciphertext; +use fhe::bfv::Plaintext; +use fhe::bfv::PublicKey; +use fhe::bfv::SecretKey; +use fhe_math::rq::Poly; + +/// Share-encryption circuit: proves correct encryption of a (secret or smudging) share under the DKG public key. +#[derive(Debug)] +pub struct ShareEncryptionCircuit; + +impl Circuit for ShareEncryptionCircuit { + const NAME: &'static str = "share-encryption"; + const PREFIX: &'static str = "SHARE_ENCRYPTION"; + const SUPPORTED_PARAMETER: ParameterType = ParameterType::THRESHOLD; + /// None: circuit accepts runtime-varying input type (SecretKey or SmudgingNoise). + const DKG_INPUT_TYPE: Option = None; +} + +/// Input to the share-encryption circuit: plaintext, ciphertext, keys, and encryption randomness. +pub struct ShareEncryptionCircuitInput { + /// Plaintext (encoded share row). + pub plaintext: Plaintext, + /// Ciphertext (encryption under public_key). + pub ciphertext: Ciphertext, + /// DKG public key used to encrypt. + pub public_key: PublicKey, + /// Secret key (for witness; not revealed in proof). + pub secret_key: SecretKey, + /// Encryption randomness u in RNS form (from try_encrypt_extended). + pub u_rns: Poly, + /// Encryption error e0 in RNS form. + pub e0_rns: Poly, + /// Encryption error e1 in RNS form. + pub e1_rns: Poly, +} diff --git a/crates/zk-helpers/src/circuits/dkg/share_encryption/codegen.rs b/crates/zk-helpers/src/circuits/dkg/share_encryption/codegen.rs new file mode 100644 index 0000000000..3b1127bc67 --- /dev/null +++ b/crates/zk-helpers/src/circuits/dkg/share_encryption/codegen.rs @@ -0,0 +1,297 @@ +// SPDX-License-Identifier: LGPL-3.0-only +// +// This file is provided WITHOUT ANY WARRANTY; +// without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. + +//! Code generation for the share-encryption BFV circuit: Prover.toml and configs.nr. + +use crate::circuits::computation::CircuitComputation; +use crate::circuits::dkg::share_encryption::Configs; +use crate::circuits::dkg::share_encryption::ShareEncryptionCircuit; +use crate::circuits::dkg::share_encryption::ShareEncryptionCircuitInput; +use crate::circuits::dkg::share_encryption::ShareEncryptionOutput; +use crate::circuits::dkg::share_encryption::Witness; +use crate::circuits::{Artifacts, CircuitCodegen, CircuitsErrors, CodegenToml}; +use crate::codegen::CodegenConfigs; +use crate::computation::Computation; +use crate::registry::Circuit; +use crate::utils::join_display; +use e3_fhe_params::BfvPreset; + +/// Implementation of [`CircuitCodegen`] for [`ShareEncryptionCircuit`]. +impl CircuitCodegen for ShareEncryptionCircuit { + type Preset = BfvPreset; + type Input = ShareEncryptionCircuitInput; + type Error = CircuitsErrors; + + fn codegen(&self, preset: Self::Preset, input: &Self::Input) -> Result { + let ShareEncryptionOutput { witness, .. } = ShareEncryptionCircuit::compute(preset, input)?; + + let toml = generate_toml(&witness)?; + let configs = Configs::compute(preset, input)?; + let configs_str = generate_configs(preset, &configs); + + Ok(Artifacts { + toml, + configs: configs_str, + }) + } +} + +/// Serializes the witness to TOML string for the Noir prover (Prover.toml). +pub fn generate_toml(witness: &Witness) -> Result { + let json = witness + .to_json() + .map_err(|e| CircuitsErrors::SerdeJson(e))?; + + Ok(toml::to_string(&json)?) +} + +/// Builds the configs.nr string (N, L, bit parameters, bounds, and ShareEncryptionConfigs) for the Noir prover. +pub fn generate_configs(preset: BfvPreset, configs: &Configs) -> CodegenConfigs { + let prefix = ::PREFIX; + + let qis_str = join_display(&configs.moduli, ", "); + let k0is_str = join_display(&configs.k0is, ", "); + let pk_bounds_str = join_display(&configs.bounds.pk_bounds, ", "); + let r1_low_bounds_str = join_display(&configs.bounds.r1_low_bounds, ", "); + let r1_up_bounds_str = join_display(&configs.bounds.r1_up_bounds, ", "); + let r2_bounds_str = join_display(&configs.bounds.r2_bounds, ", "); + let p1_bounds_str = join_display(&configs.bounds.p1_bounds, ", "); + let p2_bounds_str = join_display(&configs.bounds.p2_bounds, ", "); + + format!( + r#"use crate::core::dkg::share_encryption::Configs as ShareEncryptionConfigs; + +pub global N: u32 = {}; +pub global L: u32 = {}; +pub global QIS: [Field; L] = [{}]; + +/************************************ +------------------------------------- +share_encryption_sk (CIRCUIT 3a) +------------------------------------- +************************************/ + +pub global {}_BIT_PK: u32 = {}; +pub global {}_BIT_CT: u32 = {}; +pub global {}_BIT_U: u32 = {}; +pub global {}_BIT_E0: u32 = {}; +pub global {}_BIT_E1: u32 = {}; +pub global {}_BIT_MSG: u32 = {}; +pub global {}_BIT_R1: u32 = {}; +pub global {}_BIT_R2: u32 = {}; +pub global {}_BIT_P1: u32 = {}; +pub global {}_BIT_P2: u32 = {}; + +pub global {}_T: Field = {}; +pub global {}_Q_MOD_T: Field = {}; +pub global {}_K0IS: [Field; L] = [{}]; +pub global {}_PK_BOUNDS: [Field; L] = [{}]; +pub global {}_E0_BOUND: Field = {}; +pub global {}_E1_BOUND: Field = {}; +pub global {}_U_BOUND: Field = {}; +pub global {}_R1_LOW_BOUNDS: [Field; L] = [{}]; +pub global {}_R1_UP_BOUNDS: [Field; L] = [{}]; +pub global {}_R2_BOUNDS: [Field; L] = [{}]; +pub global {}_P1_BOUNDS: [Field; L] = [{}]; +pub global {}_P2_BOUNDS: [Field; L] = [{}]; +pub global {}_MSG_BOUND: Field = {}; + +pub global {}_CONFIGS_SK: ShareEncryptionConfigs = ShareEncryptionConfigs::new( + {}_T, + {}_Q_MOD_T, + QIS, + {}_K0IS, + {}_PK_BOUNDS, + {}_E0_BOUND, + {}_E1_BOUND, + {}_U_BOUND, + {}_R1_LOW_BOUNDS, + {}_R1_UP_BOUNDS, + {}_R2_BOUNDS, + {}_P1_BOUNDS, + {}_P2_BOUNDS, + {}_MSG_BOUND, +); + +/************************************ +------------------------------------- +share_encryption_e_sm (CIRCUIT 3b) +------------------------------------- +************************************/ + +// share_encryption_e_sm uses the same bit parameters and bounds as share_encryption_sk +pub global SHARE_ENCRYPTION_CONFIGS_E_SM: ShareEncryptionConfigs = ShareEncryptionConfigs::new( + {}_T, + {}_Q_MOD_T, + QIS, + {}_K0IS, + {}_PK_BOUNDS, + {}_E0_BOUND, + {}_E1_BOUND, + {}_U_BOUND, + {}_R1_LOW_BOUNDS, + {}_R1_UP_BOUNDS, + {}_R2_BOUNDS, + {}_P1_BOUNDS, + {}_P2_BOUNDS, + {}_MSG_BOUND,); +"#, + preset.dkg_counterpart().unwrap().metadata().degree, + preset.dkg_counterpart().unwrap().metadata().num_moduli, + qis_str, + prefix, + configs.bits.pk_bit, + prefix, + configs.bits.ct_bit, + prefix, + configs.bits.u_bit, + prefix, + configs.bits.e0_bit, + prefix, + configs.bits.e1_bit, + prefix, + configs.bits.msg_bit, + prefix, + configs.bits.r1_bit, + prefix, + configs.bits.r2_bit, + prefix, + configs.bits.p1_bit, + prefix, + configs.bits.p2_bit, + prefix, + configs.t, + prefix, + configs.q_mod_t, + prefix, + k0is_str, + prefix, + pk_bounds_str, + prefix, + configs.bounds.e0_bound, + prefix, + configs.bounds.e1_bound, + prefix, + configs.bounds.u_bound, + prefix, + r1_low_bounds_str, + prefix, + r1_up_bounds_str, + prefix, + r2_bounds_str, + prefix, + p1_bounds_str, + prefix, + p2_bounds_str, + prefix, + configs.bounds.msg_bound, + prefix, + prefix, + prefix, + prefix, + prefix, + prefix, + prefix, + prefix, + prefix, + prefix, + prefix, + prefix, + prefix, + prefix, + prefix, + prefix, + prefix, + prefix, + prefix, + prefix, + prefix, + prefix, + prefix, + prefix, + prefix, + prefix, + prefix, + ) +} + +#[cfg(test)] +mod tests { + use super::*; + + use crate::ciphernodes_committee::CiphernodesCommitteeSize; + use crate::circuits::dkg::share_encryption::{Bounds, ShareEncryptionCircuitInput}; + use crate::computation::Computation; + use crate::computation::DkgInputType; + use crate::dkg::share_encryption::sample::prepare_share_encryption_sample_for_test; + use crate::dkg::share_encryption::ShareEncryptionSample; + use crate::Circuit; + use e3_fhe_params::BfvPreset; + use e3_fhe_params::DEFAULT_BFV_PRESET; + + fn share_encryption_input_from_sample( + sample: &ShareEncryptionSample, + ) -> ShareEncryptionCircuitInput { + ShareEncryptionCircuitInput { + plaintext: sample.plaintext.clone(), + ciphertext: sample.ciphertext.clone(), + public_key: sample.public_key.clone(), + secret_key: sample.secret_key.clone(), + u_rns: sample.u_rns.clone(), + e0_rns: sample.e0_rns.clone(), + e1_rns: sample.e1_rns.clone(), + } + } + + #[test] + fn test_toml_generation_and_structure() { + let sample = prepare_share_encryption_sample_for_test( + BfvPreset::InsecureThreshold512, + CiphernodesCommitteeSize::Small, + DkgInputType::SecretKey, + ); + let input = share_encryption_input_from_sample(&sample); + + let artifacts = ShareEncryptionCircuit + .codegen(DEFAULT_BFV_PRESET, &input) + .unwrap(); + + let parsed: toml::Value = artifacts.toml.parse().unwrap(); + assert!(parsed.get("message").is_some()); + assert!(parsed.get("pk0is").is_some()); + assert!(parsed.get("expected_pk_commitment").is_some()); + assert!(parsed.get("expected_message_commitment").is_some()); + } + + #[test] + fn test_configs_generation_contains_expected() { + let sample = prepare_share_encryption_sample_for_test( + BfvPreset::InsecureThreshold512, + CiphernodesCommitteeSize::Small, + DkgInputType::SecretKey, + ); + let input = share_encryption_input_from_sample(&sample); + + let artifacts = ShareEncryptionCircuit + .codegen(DEFAULT_BFV_PRESET, &input) + .unwrap(); + + let bounds = Bounds::compute(DEFAULT_BFV_PRESET, &input).unwrap(); + let bits = + crate::circuits::dkg::share_encryption::Bits::compute(DEFAULT_BFV_PRESET, &bounds) + .unwrap(); + let prefix = ::PREFIX; + + assert!(artifacts.configs.contains("ShareEncryptionConfigs")); + assert!(artifacts + .configs + .contains(format!("{}_BIT_PK: u32 = {}", prefix, bits.pk_bit).as_str())); + assert!(artifacts + .configs + .contains(format!("{}_BIT_MSG: u32 = {}", prefix, bits.msg_bit).as_str())); + assert!(artifacts.configs.contains("SHARE_ENCRYPTION_CONFIGS_E_SM")); + } +} diff --git a/crates/zk-helpers/src/circuits/dkg/share_encryption/computation.rs b/crates/zk-helpers/src/circuits/dkg/share_encryption/computation.rs new file mode 100644 index 0000000000..802a209409 --- /dev/null +++ b/crates/zk-helpers/src/circuits/dkg/share_encryption/computation.rs @@ -0,0 +1,996 @@ +// SPDX-License-Identifier: LGPL-3.0-only +// +// This file is provided WITHOUT ANY WARRANTY; +// without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. + +//! Computation types for the share-encryption circuit: configs, bounds, bit widths, and witness. +//! +//! [`Configs`], [`Bounds`], [`Bits`], and [`Witness`] are produced from BFV parameters +//! and (for witness) plaintext, ciphertext, and encryption randomness. Witness values are +//! normalized for the ZKP field so the Noir circuit's range checks and commitment checks succeed. + +use crate::circuits::commitments::{ + compute_dkg_pk_commitment, compute_share_encryption_commitment_from_message, +}; +use std::ops::Deref; + +use crate::dkg::share_encryption::ShareEncryptionCircuit; +use crate::dkg::share_encryption::ShareEncryptionCircuitInput; +use crate::get_zkp_modulus; +use crate::polynomial_to_toml_json; +use crate::utils::{compute_msg_bit, compute_pk_bit}; +use crate::CircuitsErrors; +use crate::{calculate_bit_width, crt_polynomial_to_toml_json}; +use crate::{CircuitComputation, Computation}; +use e3_fhe_params::build_pair_for_preset; +use e3_fhe_params::BfvPreset; +use e3_polynomial::Polynomial; +use e3_polynomial::{center, reduce, CrtPolynomial}; +use fhe::bfv::SecretKey; +use fhe_math::rq::Poly; +use fhe_math::rq::Representation; +use fhe_math::zq::Modulus; +use itertools::izip; +use num_bigint::ToBigInt; +use num_bigint::{BigInt, BigUint}; +use num_traits::Zero; +use num_traits::{Signed, ToPrimitive}; +use rayon::iter::ParallelIterator; +use rayon::prelude::ParallelBridge; +use serde::{Deserialize, Serialize}; + +/// Output of [`CircuitComputation::compute`] for [`ShareEncryptionCircuit`]: bounds, bit widths, and witness. +#[derive(Debug)] +pub struct ShareEncryptionOutput { + /// Coefficient bounds used to derive bit widths. + pub bounds: Bounds, + /// Bit widths used by the Noir prover for packing. + pub bits: Bits, + /// Witness data for the share-encryption circuit. + pub witness: Witness, +} + +/// Implementation of [`CircuitComputation`] for [`ShareEncryptionCircuit`]. +impl CircuitComputation for ShareEncryptionCircuit { + type Preset = BfvPreset; + type Input = ShareEncryptionCircuitInput; + type Output = ShareEncryptionOutput; + type Error = CircuitsErrors; + + fn compute(preset: Self::Preset, input: &Self::Input) -> Result { + let bounds = Bounds::compute(preset, input)?; + let bits = Bits::compute(preset, &bounds)?; + let witness = Witness::compute(preset, input)?; + + Ok(ShareEncryptionOutput { + bounds, + bits, + witness, + }) + } +} + +/// Global configs for the share-encryption circuit: plaintext modulus, [q]_t, moduli, k0is, bits, and bounds. +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct Configs { + /// Plaintext modulus (as usize). + pub t: usize, + /// [q]_t reduced to ZKP field modulus. + pub q_mod_t: BigInt, + /// CRT moduli (one per limb). + pub moduli: Vec, + /// k0_i = [1/q_i]_t per modulus, for scaling in the circuit. + pub k0is: Vec, + pub bits: Bits, + pub bounds: Bounds, +} + +/// Bit widths used by the Noir prover (e.g. for packing coefficients). +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct Bits { + pub pk_bit: u32, + pub ct_bit: u32, + pub u_bit: u32, + pub e0_bit: u32, + pub e1_bit: u32, + pub msg_bit: u32, + pub r1_bit: u32, + pub r2_bit: u32, + pub p1_bit: u32, + pub p2_bit: u32, +} + +/// Coefficient bounds for polynomials (used to derive bit widths). +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct Bounds { + pub u_bound: BigUint, + pub e0_bound: BigUint, + pub e1_bound: BigUint, + pub msg_bound: BigUint, + pub pk_bounds: Vec, + pub r1_low_bounds: Vec, + pub r1_up_bounds: Vec, + pub r2_bounds: Vec, + pub p1_bounds: Vec, + pub p2_bounds: Vec, +} + +/// Witness data for the share-encryption circuit: CRT limbs for pk, ct, randomness, and message. +/// +/// Coefficients are reduced to the ZKP field modulus for serialization. The circuit verifies +/// that the ciphertext and commitments match the public inputs. +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct Witness { + /// Public key and ciphertext polynomials in CRT form (per modulus). + pub pk0is: CrtPolynomial, + pub pk1is: CrtPolynomial, + pub ct0is: CrtPolynomial, + pub ct1is: CrtPolynomial, + pub r1is: CrtPolynomial, + pub r2is: CrtPolynomial, + pub p1is: CrtPolynomial, + pub p2is: CrtPolynomial, + pub e0is: CrtPolynomial, + pub e0_quotients: CrtPolynomial, + pub e0: Polynomial, + pub e1: Polynomial, + pub u: Polynomial, + pub message: Polynomial, + pub pk_commitment: BigInt, + pub msg_commitment: BigInt, +} + +impl Computation for Configs { + type Preset = BfvPreset; + type Input = ShareEncryptionCircuitInput; + type Error = CircuitsErrors; + + fn compute(preset: Self::Preset, input: &Self::Input) -> Result { + let (_, dkg_params) = + build_pair_for_preset(preset).map_err(|e| CircuitsErrors::Sample(e.to_string()))?; + + let moduli = dkg_params.moduli().to_vec(); + let ctx = dkg_params.ctx_at_level(0)?; + let modulus = BigInt::from(ctx.modulus().clone()); + let t = BigInt::from(dkg_params.plaintext()); + let p = get_zkp_modulus(); + + let q_mod_t = center(&reduce(&modulus, &t), &t); + let q_mod_t_mod_p = reduce(&q_mod_t, &p); + + let mut k0is: Vec = Vec::new(); + + for qi in ctx.moduli_operators() { + let k0qi = BigInt::from(qi.inv(qi.neg(dkg_params.plaintext())).ok_or_else(|| { + CircuitsErrors::Fhe(fhe::Error::MathError(fhe_math::Error::Default( + "Failed to calculate modulus inverse for k0qi".into(), + ))) + })?); + + k0is.push(k0qi.to_u64().unwrap_or(0)); + } + + let bounds = Bounds::compute(preset, input)?; + let bits = Bits::compute(preset, &bounds)?; + + Ok(Configs { + t: dkg_params.plaintext() as usize, + q_mod_t: q_mod_t_mod_p, + moduli, + k0is, + bits, + bounds, + }) + } +} + +impl Computation for Bits { + type Preset = BfvPreset; + type Input = Bounds; + type Error = crate::utils::ZkHelpersUtilsError; + + fn compute(_: Self::Preset, input: &Self::Input) -> Result { + let max_pk_bound = input.pk_bounds.iter().max().unwrap(); + let max_r2_bound = input.r2_bounds.iter().max().unwrap(); + let max_p1_bound = input.p1_bounds.iter().max().unwrap(); + let max_p2_bound = input.p2_bounds.iter().max().unwrap(); + + let pk_bit = calculate_bit_width(BigInt::from(max_pk_bound.clone())); + let ct_bit = calculate_bit_width(BigInt::from(max_pk_bound.clone())); + let u_bit = calculate_bit_width(BigInt::from(input.u_bound.clone())); + let e0_bit = calculate_bit_width(BigInt::from(input.e0_bound.clone())); + let e1_bit = calculate_bit_width(BigInt::from(input.e1_bound.clone())); + let msg_bit = calculate_bit_width(BigInt::from(input.msg_bound.clone())); + let r1_bit = calculate_bit_width(BigInt::from( + input + .r1_low_bounds + .iter() + .chain(input.r1_up_bounds.iter()) + .max() + .unwrap() + .clone(), + )); + let r2_bit = calculate_bit_width(BigInt::from(max_r2_bound.clone())); + let p1_bit = calculate_bit_width(BigInt::from(max_p1_bound.clone())); + let p2_bit = calculate_bit_width(BigInt::from(max_p2_bound.clone())); + + Ok(Bits { + pk_bit, + ct_bit, + u_bit, + e0_bit, + e1_bit, + msg_bit, + r1_bit, + r2_bit, + p1_bit, + p2_bit, + }) + } +} + +impl Computation for Bounds { + type Preset = BfvPreset; + type Input = ShareEncryptionCircuitInput; + type Error = CircuitsErrors; + + fn compute(preset: Self::Preset, _: &Self::Input) -> Result { + let (_, dkg_params) = + build_pair_for_preset(preset).map_err(|e| CircuitsErrors::Sample(e.to_string()))?; + + let n = BigInt::from(dkg_params.degree()); + let ctx = dkg_params.ctx_at_level(0)?; + + let t = BigInt::from(dkg_params.plaintext()); + + // CBD bound + let cbd_bound = (dkg_params.variance() * 2) as u64; + // Uniform bound + let uniform_bound = (dkg_params.get_error1_variance() * BigUint::from(3u32)) + .sqrt() + .to_bigint() + .ok_or_else(|| { + CircuitsErrors::Other("Failed to convert uniform bound to BigInt".into()) + })?; + + let u_bound = SecretKey::sk_bound() as u128; // u_bound is the same as sk_bound + + // e0 = e1 in the fhe.rs + let e0_bound: u128 = if dkg_params.get_error1_variance() <= &BigUint::from(16u32) { + cbd_bound as u128 + } else { + uniform_bound.to_u128().unwrap() + }; + let e1_bound = cbd_bound; // e1 = e2 in the fhe.rs + + // Message bound: message is in [0, t), so bound is t - 1 + let msg_bound = t.clone() - BigInt::from(1); + + let ptxt_up_bound = (t.clone() - BigInt::from(1)) / BigInt::from(2); + let ptxt_low_bound: BigInt = if (t.clone() % BigInt::from(2)) == BigInt::from(1) { + -1 * ptxt_up_bound.clone() + } else { + -1 * ptxt_up_bound.clone() - BigInt::from(1) + }; + + // Calculate bounds for each CRT basis + let _num_moduli = ctx.moduli().len(); + let mut pk_bounds: Vec = Vec::new(); + let mut r1_low_bounds: Vec = Vec::new(); + let mut r1_up_bounds: Vec = Vec::new(); + let mut r2_bounds: Vec = Vec::new(); + let mut p1_bounds: Vec = Vec::new(); + let mut p2_bounds: Vec = Vec::new(); + let mut moduli: Vec = Vec::new(); + let mut k0is: Vec = Vec::new(); + + for qi in ctx.moduli_operators() { + let qi_bigint = BigInt::from(qi.modulus()); + let qi_bound = (&qi_bigint - BigInt::from(1)) / BigInt::from(2); + + moduli.push(qi.modulus()); + + // Calculate k0qi for bounds + let k0qi = BigInt::from(qi.inv(qi.neg(dkg_params.plaintext())).ok_or_else(|| { + CircuitsErrors::Fhe(fhe::Error::MathError(fhe_math::Error::Default( + "Failed to calculate modulus inverse for k0qi".into(), + ))) + })?); + k0is.push(k0qi.to_u64().unwrap_or(0)); + + // PK and R2 bounds (same as qi_bound) + pk_bounds.push(qi_bound.clone()); + r2_bounds.push(qi_bound.clone()); + + let e0_bound_i = e0_bound % qi_bigint.clone(); + + // R1 bounds (more complex calculation) + let r1_low: BigInt = (&ptxt_low_bound * k0qi.abs() + - &((&n * u_bound + BigInt::from(2)) * &qi_bound + e0_bound_i.clone())) + / &qi_bigint; + let r1_up: BigInt = (&ptxt_up_bound * k0qi.abs() + + ((&n * u_bound + BigInt::from(2)) * &qi_bound + e0_bound_i.clone())) + / &qi_bigint; + + r1_low_bounds.push(BigInt::from(-1) * r1_low.clone()); + r1_up_bounds.push(r1_up.clone()); + + // P1 and P2 bounds + let p1_bound: BigInt = + ((&n * u_bound + BigInt::from(2)) * &qi_bound + e1_bound) / &qi_bigint; + p1_bounds.push(p1_bound.clone()); + p2_bounds.push(qi_bound.clone()); + } + + Ok(Bounds { + pk_bounds: pk_bounds + .iter() + .map(|b| BigUint::from(b.to_u128().unwrap())) + .collect(), + u_bound: BigUint::from(u_bound as u64), + e0_bound: BigUint::from(e0_bound), + e1_bound: BigUint::from(e1_bound), + msg_bound: BigUint::from(msg_bound.to_u128().unwrap()), + r1_low_bounds: r1_low_bounds + .iter() + .map(|b| BigUint::from(b.to_u128().unwrap())) + .collect(), + r1_up_bounds: r1_up_bounds + .iter() + .map(|b| BigUint::from(b.to_u128().unwrap())) + .collect(), + r2_bounds: r2_bounds + .iter() + .map(|b| BigUint::from(b.to_u128().unwrap())) + .collect(), + p1_bounds: p1_bounds + .iter() + .map(|b| BigUint::from(b.to_u128().unwrap())) + .collect(), + p2_bounds: p2_bounds + .iter() + .map(|b| BigUint::from(b.to_u128().unwrap())) + .collect(), + }) + } +} + +impl Computation for Witness { + type Preset = BfvPreset; + type Input = ShareEncryptionCircuitInput; + type Error = CircuitsErrors; + + fn compute(preset: Self::Preset, input: &Self::Input) -> Result { + let (_, dkg_params) = + build_pair_for_preset(preset).map_err(|e| CircuitsErrors::Sample(e.to_string()))?; + let ctx = dkg_params.ctx_at_level(input.plaintext.level())?; + + let pk_bit = compute_pk_bit(&dkg_params); + let msg_bit = compute_msg_bit(&dkg_params); + + let pk = input.public_key.clone(); + let pt = input.plaintext.clone(); + + // Reconstruct e0 in mod Q so that e0_poly row i matches e0_rns row i (same ctx). + let mut e0_power = input.e0_rns.clone(); + e0_power.change_representation(Representation::PowerBasis); + let e0_mod_q: Vec = Vec::::from(&e0_power); + let e0_bigints: Vec = e0_mod_q.iter().map(|c| c.to_bigint().unwrap()).collect(); + let e0 = (*Poly::from_bigints(&e0_bigints, &ctx) + .map_err(|e| CircuitsErrors::Other(e.to_string()))?) + .clone(); + + let t = Modulus::new(dkg_params.plaintext()) + .map_err(|e| CircuitsErrors::Fhe(fhe::Error::from(e)))?; + let n: u64 = ctx.degree as u64; + + let mut message = Polynomial::from_u64_vector(pt.value.deref().to_vec()); + message.reverse(); + + // k1[i] = (q_mod_t * message[i]) mod t, centered to [-t/2, t/2) + let q_mod_t = (ctx.modulus() % t.modulus()).to_u64().unwrap(); + let mut k1_u64: Vec = message + .coefficients() + .iter() + .map(|c| c.to_u64().unwrap()) + .collect(); + t.scalar_mul_vec(&mut k1_u64, q_mod_t); + + let mut k1 = Polynomial::from_u64_vector(k1_u64); + k1.center(&BigInt::from(t.modulus())); + + let mut u_rns_copy = input.u_rns.clone(); + let mut e0_rns_copy = input.e0_rns.clone(); + let mut e0_poly_copy = e0.clone(); + let mut e1_rns_copy = input.e1_rns.clone(); + + u_rns_copy.change_representation(Representation::PowerBasis); + e0_rns_copy.change_representation(Representation::PowerBasis); + e0_poly_copy.change_representation(Representation::PowerBasis); + e1_rns_copy.change_representation(Representation::PowerBasis); + + // Extract coefficients using the current API + let u: Vec = + unsafe { + ctx.moduli_operators()[0] + .center_vec_vt(u_rns_copy.coefficients().row(0).as_slice().ok_or_else( + || CircuitsErrors::Other("Cannot center coefficients.".into()), + )?) + .iter() + .rev() + .map(|&x| BigInt::from(x)) + .collect() + }; + + let mut e0_vec = Polynomial::new(e0_bigints.clone()); + e0_vec.reverse(); + + // Center the coefficients mod Q + let q_bigint = BigInt::from(ctx.modulus().clone()); + + e0_vec.center(&q_bigint); + + let e1: Vec = + unsafe { + ctx.moduli_operators()[0] + .center_vec_vt(e1_rns_copy.coefficients().row(0).as_slice().ok_or_else( + || CircuitsErrors::Other("Cannot center coefficients.".into()), + )?) + .iter() + .rev() + .map(|&x| BigInt::from(x)) + .collect() + }; + + // Extract and convert ciphertext and public key polynomials + let mut ct0 = input.ciphertext.c[0].clone(); // ct0 + let mut ct1 = input.ciphertext.c[1].clone(); // ct1 + ct0.change_representation(Representation::PowerBasis); + ct1.change_representation(Representation::PowerBasis); + + let mut pk0: Poly = pk.c.c[0].clone(); + let mut pk1: Poly = pk.c.c[1].clone(); + pk0.change_representation(Representation::PowerBasis); + pk1.change_representation(Representation::PowerBasis); + + // Create cyclotomic polynomial x^N + 1 + let mut cyclo = vec![BigInt::from(0u64); (n + 1) as usize]; + + cyclo[0] = BigInt::from(1u64); // x^N term + cyclo[n as usize] = BigInt::from(1u64); // x^0 term + + let ct0_coeffs = ct0.coefficients(); + let ct1_coeffs = ct1.coefficients(); + let pk0_coeffs = pk0.coefficients(); + let pk1_coeffs = pk1.coefficients(); + let e0_coeffs = e0_rns_copy.coefficients(); + let e0_poly_coeffs = e0_poly_copy.coefficients(); + + let ct0_coeffs_rows = ct0_coeffs.rows(); + let ct1_coeffs_rows = ct1_coeffs.rows(); + let pk0_coeffs_rows = pk0_coeffs.rows(); + let pk1_coeffs_rows = pk1_coeffs.rows(); + let e0_coeffs_rows = e0_coeffs.rows(); + let e0_poly_coeffs_rows = e0_poly_coeffs.rows(); + + // Perform the main computation logic + let results: Vec<_> = izip!( + ctx.moduli_operators(), + ct0_coeffs_rows, + ct1_coeffs_rows, + pk0_coeffs_rows, + pk1_coeffs_rows, + e0_coeffs_rows, + e0_poly_coeffs_rows, + ) + .enumerate() + .par_bridge() + .map( + |( + i, + (qi, ct0_coeffs, ct1_coeffs, pk0_coeffs, pk1_coeffs, e0_coeffs, e0_poly_coeffs), + )| { + // --------------------------------------------------- ct0i --------------------------------------------------- + + // Convert to vectors of bigint, center, and reverse order. + let mut ct0i = Polynomial::from_u64_vector(ct0_coeffs.to_vec()); + let mut ct1i = Polynomial::from_u64_vector(ct1_coeffs.to_vec()); + let mut pk0i = Polynomial::from_u64_vector(pk0_coeffs.to_vec()); + let mut pk1i = Polynomial::from_u64_vector(pk1_coeffs.to_vec()); + + ct0i.reverse(); + ct1i.reverse(); + pk0i.reverse(); + pk1i.reverse(); + + let qi_bigint = BigInt::from(qi.modulus()); + + ct0i.reduce(&qi_bigint); + ct0i.center(&qi_bigint); + ct1i.reduce(&qi_bigint); + ct1i.center(&qi_bigint); + pk0i.reduce(&qi_bigint); + pk0i.center(&qi_bigint); + pk1i.reduce(&qi_bigint); + pk1i.center(&qi_bigint); + + let e0i: Vec = unsafe { + qi.center_vec_vt( + e0_coeffs + .as_slice() + .ok_or_else(|| "Cannot center coefficients.".to_string()) + .unwrap(), + ) + .iter() + .rev() + .map(|&x| BigInt::from(x)) + .collect() + }; + + // Explicitly check e1is[i] == e1 mod qi (after centering and reversal) + let e0i_from_poly: Vec = unsafe { + qi.center_vec_vt( + e0_poly_coeffs + .as_slice() + .ok_or_else(|| "Cannot center coefficients.".to_string()) + .unwrap(), + ) + .iter() + .rev() + .map(|&x| BigInt::from(x)) + .collect() + }; + + // Check that e0i equals e0 reduced modulo q_i (from e0_poly) + assert_eq!(e0i, e0i_from_poly); + + // Compute e0_quotients[i] = (e0 - e0i) / qi for each coefficient + // This is used for CRT consistency check: e0[j] = e0i[j] + e0_quotients[i][j] * qi + let e0_quotient: Vec = e0_vec + .coefficients() + .iter() + .zip(e0i.iter()) + .map(|(e0_coeff, e0i_coeff)| { + let diff = e0_coeff - e0i_coeff; + // Division should be exact since e0 = e0i (mod qi) + let quotient = &diff / &qi_bigint; + // Verify the CRT relationship + assert_eq!(e0_coeff, &(e0i_coeff + "ient * &qi_bigint)); + quotient + }) + .collect(); + + // k0qi = -t^{-1} mod qi + let koqi_u64 = qi.inv(qi.neg(t.modulus())).unwrap(); + let k0qi = BigInt::from(koqi_u64); // Do not need to center this + + // ki = k1 * k0qi + let ki_poly = Polynomial::new(k1.coefficients().to_vec()).scalar_mul(&k0qi); + let ki = ki_poly.coefficients().to_vec(); + + // Calculate ct0i_hat = pk0 * ui + e0i + ki + let ct0i_hat = { + let pk0i_poly = pk0i.clone(); + let u_poly = Polynomial::new(u.clone()); + let pk0i_times_u = pk0i_poly.mul(&u_poly); + assert_eq!((pk0i_times_u.coefficients().len() as u64) - 1, 2 * (n - 1)); + + let e0i_poly = Polynomial::new(e0i.clone()); + let ki_poly = Polynomial::new(ki.clone()); + let e0_plus_ki = e0i_poly.add(&ki_poly); + assert_eq!((e0_plus_ki.coefficients().len() as u64) - 1, n - 1); + + pk0i_times_u.add(&e0_plus_ki).coefficients().to_vec() + }; + assert_eq!((ct0i_hat.len() as u64) - 1, 2 * (n - 1)); + + // Check whether ct0i_hat mod R_qi (the ring) is equal to ct0i + let mut ct0i_hat_mod_rqi = Polynomial::new(ct0i_hat.clone()); + + ct0i_hat_mod_rqi = ct0i_hat_mod_rqi.reduce_by_cyclotomic(&cyclo).unwrap(); + + ct0i_hat_mod_rqi.reduce(&qi_bigint); + ct0i_hat_mod_rqi.center(&qi_bigint); + + assert_eq!(&ct0i, &ct0i_hat_mod_rqi); + + // Compute r2i numerator = ct0i - ct0i_hat and reduce/center the polynomial + let ct0i_poly = ct0i.clone(); + let ct0i_hat_poly = Polynomial::new(ct0i_hat.clone()); + let ct0i_minus_ct0i_hat = ct0i_poly.sub(&ct0i_hat_poly).coefficients().to_vec(); + assert_eq!((ct0i_minus_ct0i_hat.len() as u64) - 1, 2 * (n - 1)); + + let mut ct0i_minus_ct0i_hat_mod_zqi = Polynomial::new(ct0i_minus_ct0i_hat.clone()); + + ct0i_minus_ct0i_hat_mod_zqi.reduce(&qi_bigint); + ct0i_minus_ct0i_hat_mod_zqi.center(&qi_bigint); + + // Compute r2i as the quotient of numerator divided by the cyclotomic polynomial + // to produce: (ct0i - ct0i_hat) / (x^N + 1) mod Z_qi. Remainder should be empty. + let ct0i_minus_ct0i_hat_poly = ct0i_minus_ct0i_hat_mod_zqi.clone(); + let cyclo_poly = Polynomial::new(cyclo.clone()); + let (r2i_poly, r2i_rem_poly) = ct0i_minus_ct0i_hat_poly.div(&cyclo_poly).unwrap(); + let r2i = r2i_poly.coefficients().to_vec(); + let r2i_rem = r2i_rem_poly.coefficients().to_vec(); + assert!(r2i_rem.iter().all(|x| x.is_zero())); + assert_eq!((r2i.len() as u64) - 1, n - 2); // Order(r2i) = N - 2 + + // Assert that (ct0i - ct0i_hat) = (r2i * cyclo) mod Z_qi + let r2i_poly = Polynomial::new(r2i.clone()); + let r2i_times_cyclo = r2i_poly.mul(&cyclo_poly).coefficients().to_vec(); + + let mut r2i_times_cyclo_mod_zqi = Polynomial::new(r2i_times_cyclo.clone()); + + r2i_times_cyclo_mod_zqi.reduce(&qi_bigint); + r2i_times_cyclo_mod_zqi.center(&qi_bigint); + + assert_eq!(&ct0i_minus_ct0i_hat_mod_zqi, &r2i_times_cyclo_mod_zqi); + assert_eq!((r2i_times_cyclo.len() as u64) - 1, 2 * (n - 1)); + + // Calculate r1i = (ct0i - ct0i_hat - r2i * cyclo) / qi mod Z_p. Remainder should be empty. + let ct0i_minus_ct0i_hat_poly = Polynomial::new(ct0i_minus_ct0i_hat.clone()); + let r2i_times_cyclo_poly = Polynomial::new(r2i_times_cyclo.clone()); + let r1i_num = ct0i_minus_ct0i_hat_poly + .sub(&r2i_times_cyclo_poly) + .coefficients() + .to_vec(); + assert_eq!((r1i_num.len() as u64) - 1, 2 * (n - 1)); + + let r1i_num_poly = Polynomial::new(r1i_num.clone()); + let qi_poly = Polynomial::new(vec![qi_bigint.clone()]); + let (r1i_poly, r1i_rem_poly) = r1i_num_poly.div(&qi_poly).unwrap(); + let r1i = r1i_poly.coefficients().to_vec(); + let r1i_rem = r1i_rem_poly.coefficients().to_vec(); + assert!(r1i_rem.iter().all(|x| x.is_zero())); + assert_eq!((r1i.len() as u64) - 1, 2 * (n - 1)); // Order(r1i) = 2*(N-1) + let r1i_poly_check = Polynomial::new(r1i.clone()); + assert_eq!( + &r1i_num, + &r1i_poly_check.mul(&qi_poly).coefficients().to_vec() + ); + + // Assert that ct0i = ct0i_hat + r1i * qi + r2i * cyclo mod Z_p + let r1i_poly = Polynomial::new(r1i.clone()); + let r1i_times_qi = r1i_poly.scalar_mul(&qi_bigint).coefficients().to_vec(); + let ct0i_hat_poly = Polynomial::new(ct0i_hat.clone()); + let r1i_times_qi_poly = Polynomial::new(r1i_times_qi.clone()); + let r2i_times_cyclo_poly = Polynomial::new(r2i_times_cyclo.clone()); + let mut ct0i_calculated = ct0i_hat_poly + .add(&r1i_times_qi_poly) + .add(&r2i_times_cyclo_poly) + .coefficients() + .to_vec(); + + while !ct0i_calculated.is_empty() && ct0i_calculated[0].is_zero() { + ct0i_calculated.remove(0); + } + + assert_eq!(&ct0i, &Polynomial::new(ct0i_calculated.clone())); + + // --------------------------------------------------- ct1i --------------------------------------------------- + + // Calculate ct1i_hat = pk1i * ui + e1 + let ct1i_hat = { + let pk1i_poly = pk1i.clone(); + let u_poly = Polynomial::new(u.clone()); + let pk1i_times_u = pk1i_poly.mul(&u_poly); + assert_eq!((pk1i_times_u.coefficients().len() as u64) - 1, 2 * (n - 1)); + + let e1_poly = Polynomial::new(e1.clone()); + pk1i_times_u.add(&e1_poly).coefficients().to_vec() + }; + assert_eq!((ct1i_hat.len() as u64) - 1, 2 * (n - 1)); + + // Check whether ct1i_hat mod R_qi (the ring) is equal to ct1i + let mut ct1i_hat_mod_rqi = Polynomial::new(ct1i_hat.clone()); + + ct1i_hat_mod_rqi = ct1i_hat_mod_rqi.reduce_by_cyclotomic(&cyclo).unwrap(); + ct1i_hat_mod_rqi.reduce(&qi_bigint); + ct1i_hat_mod_rqi.center(&qi_bigint); + + assert_eq!(&ct1i, &ct1i_hat_mod_rqi); + + // Compute p2i numerator = ct1i - ct1i_hat + let ct1i_poly = ct1i.clone(); + let ct1i_hat_poly = Polynomial::new(ct1i_hat.clone()); + let ct1i_minus_ct1i_hat = ct1i_poly.sub(&ct1i_hat_poly).coefficients().to_vec(); + assert_eq!((ct1i_minus_ct1i_hat.len() as u64) - 1, 2 * (n - 1)); + let mut ct1i_minus_ct1i_hat_mod_zqi = Polynomial::new(ct1i_minus_ct1i_hat.clone()); + + ct1i_minus_ct1i_hat_mod_zqi.reduce(&qi_bigint); + ct1i_minus_ct1i_hat_mod_zqi.center(&qi_bigint); + + // Compute p2i as the quotient of numerator divided by the cyclotomic polynomial, + // and reduce/center the resulting coefficients to produce: + // (ct1i - ct1i_hat) / (x^N + 1) mod Z_qi. Remainder should be empty. + let ct1i_minus_ct1i_hat_poly = ct1i_minus_ct1i_hat_mod_zqi.clone(); + let (p2i_poly, p2i_rem_poly) = + ct1i_minus_ct1i_hat_poly.div(&cyclo_poly.clone()).unwrap(); + let p2i = p2i_poly.coefficients().to_vec(); + let p2i_rem = p2i_rem_poly.coefficients().to_vec(); + assert!(p2i_rem.iter().all(|x| x.is_zero())); + assert_eq!((p2i.len() as u64) - 1, n - 2); // Order(p2i) = N - 2 + + // Assert that (ct1i - ct1i_hat) = (p2i * cyclo) mod Z_qi + let p2i_poly = Polynomial::new(p2i.clone()); + let p2i_times_cyclo: Vec = + p2i_poly.mul(&cyclo_poly).coefficients().to_vec(); + let mut p2i_times_cyclo_mod_zqi = Polynomial::new(p2i_times_cyclo.clone()); + + p2i_times_cyclo_mod_zqi.reduce(&qi_bigint); + p2i_times_cyclo_mod_zqi.center(&qi_bigint); + + assert_eq!(&ct1i_minus_ct1i_hat_mod_zqi, &p2i_times_cyclo_mod_zqi); + assert_eq!((p2i_times_cyclo.len() as u64) - 1, 2 * (n - 1)); + + // Calculate p1i = (ct1i - ct1i_hat - p2i * cyclo) / qi mod Z_p. Remainder should be empty. + let ct1i_minus_ct1i_hat_poly = Polynomial::new(ct1i_minus_ct1i_hat.clone()); + let p2i_times_cyclo_poly = Polynomial::new(p2i_times_cyclo.clone()); + let p1i_num = ct1i_minus_ct1i_hat_poly + .sub(&p2i_times_cyclo_poly) + .coefficients() + .to_vec(); + assert_eq!((p1i_num.len() as u64) - 1, 2 * (n - 1)); + + let p1i_num_poly = Polynomial::new(p1i_num.clone()); + let qi_poly = Polynomial::new(vec![BigInt::from(qi.modulus())]); + let (p1i_poly, p1i_rem_poly) = p1i_num_poly.div(&qi_poly).unwrap(); + let p1i = p1i_poly.coefficients().to_vec(); + let p1i_rem = p1i_rem_poly.coefficients().to_vec(); + assert!(p1i_rem.iter().all(|x| x.is_zero())); + assert_eq!((p1i.len() as u64) - 1, 2 * (n - 1)); // Order(p1i) = 2*(N-1) + let p1i_poly_check = Polynomial::new(p1i.clone()); + assert_eq!( + &p1i_num, + &p1i_poly_check.mul(&qi_poly).coefficients().to_vec() + ); + + // Assert that ct1i = ct1i_hat + p1i * qi + p2i * cyclo mod Z_p + let p1i_poly = Polynomial::new(p1i.clone()); + let p1i_times_qi = p1i_poly.scalar_mul(&qi_bigint).coefficients().to_vec(); + let ct1i_hat_poly = Polynomial::new(ct1i_hat.clone()); + let p1i_times_qi_poly = Polynomial::new(p1i_times_qi.clone()); + let p2i_times_cyclo_poly = Polynomial::new(p2i_times_cyclo.clone()); + let mut ct1i_calculated = ct1i_hat_poly + .add(&p1i_times_qi_poly) + .add(&p2i_times_cyclo_poly) + .coefficients() + .to_vec(); + + while !ct1i_calculated.is_empty() && ct1i_calculated[0].is_zero() { + ct1i_calculated.remove(0); + } + + assert_eq!(&ct1i, &Polynomial::new(ct1i_calculated.clone())); + ( + i, + r2i, + r1i, + k0qi, + ct0i, + ct1i, + pk0i, + pk1i, + p1i, + p2i, + e0i, + e0_quotient, + ) + }, + ) + .collect(); + + // Sort by modulus index so CRT limbs are in order + let mut results = results.clone(); + results.sort_by_key(|(i, ..)| *i); + + // results elements: (i, r2i, r1i, k0qi, ct0i, ct1i, pk0i, pk1i, p1i, p2i, e0i, e0_quotient) + let mut pk0is = CrtPolynomial::from_bigint_vectors( + results + .iter() + .map(|row| row.6.clone()) + .map(|pk0i| pk0i.coefficients().to_vec()) + .collect(), + ); + let mut pk1is = CrtPolynomial::from_bigint_vectors( + results + .iter() + .map(|row| row.7.clone()) + .map(|pk1i| pk1i.coefficients().to_vec()) + .collect(), + ); + let mut ct0is = CrtPolynomial::from_bigint_vectors( + results + .iter() + .map(|row| row.4.clone()) + .map(|ct0i| ct0i.coefficients().to_vec()) + .collect(), + ); + let mut ct1is = CrtPolynomial::from_bigint_vectors( + results + .iter() + .map(|row| row.5.clone()) + .map(|ct1i| ct1i.coefficients().to_vec()) + .collect(), + ); + let mut r1is = + CrtPolynomial::from_bigint_vectors(results.iter().map(|row| row.2.clone()).collect()); + let mut r2is = + CrtPolynomial::from_bigint_vectors(results.iter().map(|row| row.1.clone()).collect()); + let mut p1is = + CrtPolynomial::from_bigint_vectors(results.iter().map(|row| row.8.clone()).collect()); + let mut p2is = + CrtPolynomial::from_bigint_vectors(results.iter().map(|row| row.9.clone()).collect()); + let mut e0is = + CrtPolynomial::from_bigint_vectors(results.iter().map(|row| row.10.clone()).collect()); + let mut e0_quotients = + CrtPolynomial::from_bigint_vectors(results.iter().map(|row| row.11.clone()).collect()); + + let mut e1 = Polynomial::new(e1); + let mut u = Polynomial::new(u); + + let zkp_modulus = get_zkp_modulus(); + + pk0is.reduce_uniform(&zkp_modulus); + pk1is.reduce_uniform(&zkp_modulus); + ct0is.reduce_uniform(&zkp_modulus); + ct1is.reduce_uniform(&zkp_modulus); + r1is.reduce_uniform(&zkp_modulus); + r2is.reduce_uniform(&zkp_modulus); + p1is.reduce_uniform(&zkp_modulus); + p2is.reduce_uniform(&zkp_modulus); + e0is.reduce_uniform(&zkp_modulus); + e0_quotients.reduce_uniform(&zkp_modulus); + e1.reduce(&zkp_modulus); + u.reduce(&zkp_modulus); + e0_vec.reduce(&zkp_modulus); + k1.reduce(&zkp_modulus); + + let pk_commitment = compute_dkg_pk_commitment(&pk0is, &pk1is, pk_bit); + let msg_commitment = compute_share_encryption_commitment_from_message(&message, msg_bit); + + Ok(Witness { + pk0is, + pk1is, + ct0is, + ct1is, + r1is, + r2is, + p1is, + p2is, + e0is, + e0_quotients, + e0: e0_vec, + e1, + u, + message, + pk_commitment, + msg_commitment, + }) + } + + // Used as witness for Nargo execution. + fn to_json(&self) -> serde_json::Result { + let pk0is = crt_polynomial_to_toml_json(&self.pk0is); + let pk1is = crt_polynomial_to_toml_json(&self.pk1is); + let ct0is = crt_polynomial_to_toml_json(&self.ct0is); + let ct1is = crt_polynomial_to_toml_json(&self.ct1is); + let u = polynomial_to_toml_json(&self.u); + let e0 = polynomial_to_toml_json(&self.e0); + let e0is = crt_polynomial_to_toml_json(&self.e0is); + let e0_quotients = crt_polynomial_to_toml_json(&self.e0_quotients); + let e1 = polynomial_to_toml_json(&self.e1); + let message = polynomial_to_toml_json(&self.message); + let r1is = crt_polynomial_to_toml_json(&self.r1is); + let r2is = crt_polynomial_to_toml_json(&self.r2is); + let p1is = crt_polynomial_to_toml_json(&self.p1is); + let p2is = crt_polynomial_to_toml_json(&self.p2is); + let pk_commitment = self.pk_commitment.to_string(); + let msg_commitment = self.msg_commitment.to_string(); + + let json = serde_json::json!({ + "pk0is": pk0is, + "pk1is": pk1is, + "ct0is": ct0is, + "ct1is": ct1is, + "u": u, + "e0": e0, + "e0is": e0is, + "e0_quotients": e0_quotients, + "e1": e1, + "message": message, + "r1is": r1is, + "r2is": r2is, + "p1is": p1is, + "p2is": p2is, + "expected_pk_commitment": pk_commitment, + "expected_message_commitment": msg_commitment, + }); + + Ok(json) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + use crate::ciphernodes_committee::CiphernodesCommitteeSize; + use crate::computation::DkgInputType; + use crate::dkg::share_encryption::sample::prepare_share_encryption_sample_for_test; + use crate::dkg::share_encryption::ShareEncryptionSample; + use e3_fhe_params::BfvPreset; + use e3_fhe_params::DEFAULT_BFV_PRESET; + + fn share_encryption_input_from_sample( + sample: &ShareEncryptionSample, + ) -> ShareEncryptionCircuitInput { + ShareEncryptionCircuitInput { + plaintext: sample.plaintext.clone(), + ciphertext: sample.ciphertext.clone(), + public_key: sample.public_key.clone(), + secret_key: sample.secret_key.clone(), + u_rns: sample.u_rns.clone(), + e0_rns: sample.e0_rns.clone(), + e1_rns: sample.e1_rns.clone(), + } + } + + #[test] + fn test_bound_and_bits_computation_consistency() { + let sample = prepare_share_encryption_sample_for_test( + BfvPreset::InsecureThreshold512, + CiphernodesCommitteeSize::Small, + DkgInputType::SecretKey, + ); + let input = share_encryption_input_from_sample(&sample); + let bounds = Bounds::compute(DEFAULT_BFV_PRESET, &input).unwrap(); + let bits = Bits::compute(DEFAULT_BFV_PRESET, &bounds).unwrap(); + + let max_pk_bound = bounds.pk_bounds.iter().max().unwrap(); + let expected_bits = calculate_bit_width(BigInt::from(max_pk_bound.clone())); + + assert_eq!(max_pk_bound.clone(), BigUint::from(1125899906777088u128)); + assert_eq!(bits.pk_bit, expected_bits); + } + + #[test] + fn test_constants_json_roundtrip() { + let sample = prepare_share_encryption_sample_for_test( + BfvPreset::InsecureThreshold512, + CiphernodesCommitteeSize::Small, + DkgInputType::SecretKey, + ); + let input = share_encryption_input_from_sample(&sample); + let constants = Configs::compute(DEFAULT_BFV_PRESET, &input).unwrap(); + + let json = constants.to_json().unwrap(); + let decoded: Configs = serde_json::from_value(json).unwrap(); + + assert_eq!(decoded.t, constants.t); + assert_eq!(decoded.q_mod_t, constants.q_mod_t); + assert_eq!(decoded.moduli, constants.moduli); + assert_eq!(decoded.k0is, constants.k0is); + assert_eq!(decoded.bits, constants.bits); + assert_eq!(decoded.bounds, constants.bounds); + } + + #[test] + fn test_witness_message_consistency() { + let sample = prepare_share_encryption_sample_for_test( + BfvPreset::InsecureThreshold512, + CiphernodesCommitteeSize::Small, + DkgInputType::SecretKey, + ); + let input = share_encryption_input_from_sample(&sample); + let witness = Witness::compute(DEFAULT_BFV_PRESET, &input).unwrap(); + + // witness.message is plaintext coefficients (reversed, as used in circuit) + let expected_message = Polynomial::from_u64_vector(sample.plaintext.value.deref().to_vec()); + let mut expected = expected_message; + expected.reverse(); + + assert_eq!(witness.message.coefficients(), expected.coefficients()); + } +} diff --git a/crates/zk-helpers/src/circuits/dkg/share_encryption/mod.rs b/crates/zk-helpers/src/circuits/dkg/share_encryption/mod.rs new file mode 100644 index 0000000000..3446225c16 --- /dev/null +++ b/crates/zk-helpers/src/circuits/dkg/share_encryption/mod.rs @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: LGPL-3.0-only +// +// This file is provided WITHOUT ANY WARRANTY; +// without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. + +//! Share-encryption circuit: proves correct encryption of a share under the DKG public key (CIRCUIT 3a/3b). + +pub mod circuit; +pub mod codegen; +pub mod computation; +pub mod sample; +pub use circuit::{ShareEncryptionCircuit, ShareEncryptionCircuitInput}; +pub use computation::{Bits, Bounds, Configs, ShareEncryptionOutput, Witness}; +pub use sample::{prepare_share_encryption_sample_for_test, ShareEncryptionSample}; diff --git a/crates/zk-helpers/src/circuits/dkg/share_encryption/sample.rs b/crates/zk-helpers/src/circuits/dkg/share_encryption/sample.rs new file mode 100644 index 0000000000..2d6c639fe7 --- /dev/null +++ b/crates/zk-helpers/src/circuits/dkg/share_encryption/sample.rs @@ -0,0 +1,186 @@ +// SPDX-License-Identifier: LGPL-3.0-only +// +// This file is provided WITHOUT ANY WARRANTY; +// without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. + +//! Sample data generation for the share-encryption circuit: DKG public key, plaintext, +//! ciphertext, and encryption randomness (u_rns, e0_rns, e1_rns) for testing and codegen. + +use crate::ciphernodes_committee::CiphernodesCommitteeSize; +use crate::computation::DkgInputType; +use crate::CircuitsErrors; +use e3_fhe_params::build_pair_for_preset; +use e3_fhe_params::BfvPreset; +use fhe::bfv::Ciphertext; +use fhe::bfv::Encoding; +use fhe::bfv::Plaintext; +use fhe::bfv::{PublicKey, SecretKey}; +use fhe::trbfv::{ShareManager, TRBFV}; +use fhe_math::rq::Poly; +use fhe_traits::FheEncoder; +use rand::thread_rng; + +/// Sample data for the share-encryption circuit: plaintext, ciphertext, keys, and RNS randomness. +#[derive(Debug, Clone)] +pub struct ShareEncryptionSample { + pub plaintext: Plaintext, + pub ciphertext: Ciphertext, + pub public_key: PublicKey, + pub secret_key: SecretKey, + pub u_rns: Poly, + pub e0_rns: Poly, + pub e1_rns: Poly, +} + +impl ShareEncryptionSample { + /// Generates sample data for the share-encryption circuit (encrypts a share row under DKG pk). + pub fn generate( + preset: BfvPreset, + committee_size: CiphernodesCommitteeSize, + dkg_input_type: DkgInputType, + num_ciphertexts: u128, // z in the search defaults + lambda: u32, + ) -> Self { + let (threshold_params, dkg_params) = build_pair_for_preset(preset).unwrap(); + + let mut rng = thread_rng(); + let committee = committee_size.values(); + + let dkg_secret_key = SecretKey::random(&dkg_params, &mut rng); + let dkg_public_key = PublicKey::new(&dkg_secret_key, &mut rng); + + let trbfv = TRBFV::new(committee.n, committee.threshold, threshold_params.clone()) + .unwrap_or_else(|e| panic!("Failed to create TRBFV: {:?}", e)); + let mut share_manager = + ShareManager::new(committee.n, committee.threshold, threshold_params.clone()); + + let share_row = match dkg_input_type { + DkgInputType::SecretKey => { + let threshold_secret_key = SecretKey::random(&threshold_params, &mut rng); + + let sk_poly = share_manager + .coeffs_to_poly_level0(threshold_secret_key.coeffs.clone().as_ref()) + .unwrap(); + + let sk_sss_u64 = share_manager + .generate_secret_shares_from_poly(sk_poly.clone(), &mut rng) + .unwrap(); + + sk_sss_u64[0].row(0).to_vec() + } + DkgInputType::SmudgingNoise => { + let esi_coeffs = trbfv + .generate_smudging_error(num_ciphertexts as usize, lambda as usize, &mut rng) + .map_err(|e| { + CircuitsErrors::Sample(format!( + "Failed to generate smudging error: {:?}", + e + )) + }) + .unwrap(); + let esi_poly = share_manager.bigints_to_poly(&esi_coeffs).unwrap(); + let esi_sss_u64 = share_manager + .generate_secret_shares_from_poly(esi_poly.clone(), &mut rng.clone()) + .map_err(|e| { + CircuitsErrors::Sample(format!("Failed to generate error shares: {:?}", e)) + }) + .unwrap(); + + esi_sss_u64[0].row(0).to_vec() + } + }; + + let pt = Plaintext::try_encode(&share_row, Encoding::poly(), &dkg_params).unwrap(); + + let (_ct, u_rns, e0_rns, e1_rns) = + dkg_public_key.try_encrypt_extended(&pt, &mut rng).unwrap(); + + ShareEncryptionSample { + plaintext: pt, + ciphertext: _ct, + public_key: dkg_public_key, + secret_key: dkg_secret_key, + u_rns, + e0_rns, + e1_rns, + } + } +} + +/// Prepares a share-encryption sample for testing using a threshold preset. +pub fn prepare_share_encryption_sample_for_test( + preset: BfvPreset, + committee: CiphernodesCommitteeSize, + dkg_input_type: DkgInputType, +) -> ShareEncryptionSample { + let defaults = preset.search_defaults().unwrap(); + + ShareEncryptionSample::generate( + preset, + committee, + dkg_input_type, + defaults.z, + defaults.lambda, + ) +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::ciphernodes_committee::CiphernodesCommitteeSize; + use crate::computation::DkgInputType; + use e3_fhe_params::{BfvPreset, DEFAULT_BFV_PRESET}; + + #[test] + fn test_generate_secret_key_sample() { + let sample = prepare_share_encryption_sample_for_test( + BfvPreset::InsecureThreshold512, + CiphernodesCommitteeSize::Small, + DkgInputType::SecretKey, + ); + + assert_eq!(sample.public_key.c.c.len(), 2); + assert_eq!( + sample.plaintext.value.len(), + DEFAULT_BFV_PRESET.metadata().degree + ); + assert_eq!(sample.ciphertext.c.len(), 2); + assert_eq!( + sample.u_rns.coefficients().len(), + DEFAULT_BFV_PRESET.metadata().degree + ); + assert_eq!( + sample.e0_rns.coefficients().len(), + DEFAULT_BFV_PRESET.metadata().degree + ); + assert_eq!( + sample.e1_rns.coefficients().len(), + DEFAULT_BFV_PRESET.metadata().degree + ); + } + + #[test] + fn test_generate_smudging_noise_sample() { + let sample = prepare_share_encryption_sample_for_test( + BfvPreset::InsecureThreshold512, + CiphernodesCommitteeSize::Small, + DkgInputType::SmudgingNoise, + ); + + assert_eq!(sample.public_key.c.c.len(), 2); + assert_eq!(sample.ciphertext.c.len(), 2); + assert_eq!( + sample.u_rns.coefficients().len(), + DEFAULT_BFV_PRESET.metadata().degree + ); + assert_eq!( + sample.e0_rns.coefficients().len(), + DEFAULT_BFV_PRESET.metadata().degree + ); + assert_eq!( + sample.e1_rns.coefficients().len(), + DEFAULT_BFV_PRESET.metadata().degree + ); + } +} diff --git a/crates/zk-helpers/src/utils.rs b/crates/zk-helpers/src/utils.rs index ba3e085af8..3c27b4cf43 100644 --- a/crates/zk-helpers/src/utils.rs +++ b/crates/zk-helpers/src/utils.rs @@ -166,6 +166,19 @@ pub fn compute_pk_bit(params: &BfvParameters) -> u32 { calculate_bit_width(bound) } +/// Computes the bit width of the message. +/// +/// # Arguments +/// * `params` - BFV parameters +/// +/// # Returns +/// The bit width of the message +pub fn compute_msg_bit(params: &BfvParameters) -> u32 { + let t = BigInt::from(params.plaintext()); + let bound = t.clone() - BigInt::from(1); + calculate_bit_width(bound) +} + /// Get the ZKP modulus as a BigInt. /// /// The ZKP modulus is the BN254 scalar field modulus: From 74dba12f883f9d19bdd5e8a84c7a9219d53fdd8a Mon Sep 17 00:00:00 2001 From: 0xjei Date: Thu, 5 Feb 2026 17:27:25 +0100 Subject: [PATCH 2/4] default to insecure preset for testing --- .../zk-helpers/src/circuits/dkg/pk/codegen.rs | 30 +++++++++++++------ .../src/circuits/dkg/pk/computation.rs | 10 +++---- .../circuits/dkg/share_computation/codegen.rs | 16 ++++++---- .../dkg/share_computation/computation.rs | 9 +++--- .../circuits/dkg/share_encryption/circuit.rs | 2 +- .../circuits/dkg/share_encryption/codegen.rs | 15 +++++----- .../dkg/share_encryption/computation.rs | 9 +++--- .../circuits/dkg/share_encryption/sample.rs | 16 +++++----- .../threshold/user_data_encryption/codegen.rs | 28 +++++++++++------ .../user_data_encryption/computation.rs | 8 ++--- .../threshold/user_data_encryption/sample.rs | 6 ++-- .../threshold/user_data_encryption/utils.rs | 14 ++++----- 12 files changed, 94 insertions(+), 69 deletions(-) diff --git a/crates/zk-helpers/src/circuits/dkg/pk/codegen.rs b/crates/zk-helpers/src/circuits/dkg/pk/codegen.rs index 8c3d99b025..152601e60e 100644 --- a/crates/zk-helpers/src/circuits/dkg/pk/codegen.rs +++ b/crates/zk-helpers/src/circuits/dkg/pk/codegen.rs @@ -76,18 +76,20 @@ mod tests { use crate::prepare_pk_sample_for_test; use crate::utils::compute_pk_bit; - use e3_fhe_params::{build_pair_for_preset, DEFAULT_BFV_PRESET}; + use e3_fhe_params::{build_pair_for_preset, BfvPreset}; use tempfile::TempDir; #[test] fn test_toml_generation_and_structure() { - let (_, dkg_params) = build_pair_for_preset(DEFAULT_BFV_PRESET).unwrap(); - let sample = - prepare_pk_sample_for_test(DEFAULT_BFV_PRESET, CiphernodesCommitteeSize::Small); + let (_, dkg_params) = build_pair_for_preset(BfvPreset::InsecureThreshold512).unwrap(); + let sample = prepare_pk_sample_for_test( + BfvPreset::InsecureThreshold512, + CiphernodesCommitteeSize::Small, + ); let artifacts = PkCircuit .codegen( - DEFAULT_BFV_PRESET, + BfvPreset::InsecureThreshold512, &PkCircuitInput { public_key: sample.dkg_public_key, }, @@ -130,10 +132,20 @@ mod tests { let configs_content = std::fs::read_to_string(&configs_path).unwrap(); let pk_bit = compute_pk_bit(&dkg_params); - assert!(configs_content - .contains(format!("N: u32 = {}", DEFAULT_BFV_PRESET.metadata().degree).as_str())); - assert!(configs_content - .contains(format!("L: u32 = {}", DEFAULT_BFV_PRESET.metadata().num_moduli).as_str())); + assert!(configs_content.contains( + format!( + "N: u32 = {}", + BfvPreset::InsecureThreshold512.metadata().degree + ) + .as_str() + )); + assert!(configs_content.contains( + format!( + "L: u32 = {}", + BfvPreset::InsecureThreshold512.metadata().num_moduli + ) + .as_str() + )); assert!(configs_content.contains( format!( "{}_BIT_PK: u32 = {}", diff --git a/crates/zk-helpers/src/circuits/dkg/pk/computation.rs b/crates/zk-helpers/src/circuits/dkg/pk/computation.rs index 2f4ebe3e5f..9f9a5a50c2 100644 --- a/crates/zk-helpers/src/circuits/dkg/pk/computation.rs +++ b/crates/zk-helpers/src/circuits/dkg/pk/computation.rs @@ -188,14 +188,14 @@ impl Computation for Witness { mod tests { use super::*; - use e3_fhe_params::DEFAULT_BFV_PRESET; + use e3_fhe_params::BfvPreset; #[test] fn test_bound_and_bits_computation_consistency() { - let (_, dkg_params) = build_pair_for_preset(DEFAULT_BFV_PRESET).unwrap(); + let (_, dkg_params) = build_pair_for_preset(BfvPreset::InsecureThreshold512).unwrap(); - let bounds = Bounds::compute(DEFAULT_BFV_PRESET, &()).unwrap(); - let bits = Bits::compute(DEFAULT_BFV_PRESET, &()).unwrap(); + let bounds = Bounds::compute(BfvPreset::InsecureThreshold512, &()).unwrap(); + let bits = Bits::compute(BfvPreset::InsecureThreshold512, &()).unwrap(); let expected_bits = compute_pk_bit(&dkg_params); assert_eq!(bounds.pk_bound, BigUint::from(1125899906777088u128)); @@ -204,7 +204,7 @@ mod tests { #[test] fn test_constants_json_roundtrip() { - let constants = Configs::compute(DEFAULT_BFV_PRESET, &()).unwrap(); + let constants = Configs::compute(BfvPreset::InsecureThreshold512, &()).unwrap(); let json = constants.to_json().unwrap(); let decoded: Configs = serde_json::from_value(json).unwrap(); diff --git a/crates/zk-helpers/src/circuits/dkg/share_computation/codegen.rs b/crates/zk-helpers/src/circuits/dkg/share_computation/codegen.rs index 33f892d0f4..c16fc73fbb 100644 --- a/crates/zk-helpers/src/circuits/dkg/share_computation/codegen.rs +++ b/crates/zk-helpers/src/circuits/dkg/share_computation/codegen.rs @@ -197,7 +197,6 @@ mod tests { use crate::Circuit; use crate::{prepare_share_computation_sample_for_test, ShareComputationSample}; use e3_fhe_params::BfvPreset; - use e3_fhe_params::DEFAULT_BFV_PRESET; use tempfile::TempDir; fn share_computation_input_from_sample( @@ -225,7 +224,7 @@ mod tests { let input = share_computation_input_from_sample(&sample, DkgInputType::SecretKey); let artifacts = ShareComputationCircuit - .codegen(DEFAULT_BFV_PRESET, &input) + .codegen(BfvPreset::InsecureThreshold512, &input) .unwrap(); let parsed: toml::Value = artifacts.toml.parse().unwrap(); @@ -258,12 +257,17 @@ mod tests { assert!(configs_path.exists()); let configs_content = std::fs::read_to_string(&configs_path).unwrap(); - let bounds = Bounds::compute(DEFAULT_BFV_PRESET, &input).unwrap(); - let bits = Bits::compute(DEFAULT_BFV_PRESET, &bounds).unwrap(); + let bounds = Bounds::compute(BfvPreset::InsecureThreshold512, &input).unwrap(); + let bits = Bits::compute(BfvPreset::InsecureThreshold512, &bounds).unwrap(); let prefix = ::PREFIX; - assert!(configs_content - .contains(format!("N: u32 = {}", DEFAULT_BFV_PRESET.metadata().degree).as_str())); + assert!(configs_content.contains( + format!( + "N: u32 = {}", + BfvPreset::InsecureThreshold512.metadata().degree + ) + .as_str() + )); assert!(configs_content .contains(format!("{}_BIT_SHARE: u32 = {}", prefix, bits.bit_share).as_str())); assert!(configs_content diff --git a/crates/zk-helpers/src/circuits/dkg/share_computation/computation.rs b/crates/zk-helpers/src/circuits/dkg/share_computation/computation.rs index ed4159ee32..304e193f6d 100644 --- a/crates/zk-helpers/src/circuits/dkg/share_computation/computation.rs +++ b/crates/zk-helpers/src/circuits/dkg/share_computation/computation.rs @@ -269,7 +269,6 @@ mod tests { use crate::dkg::share_computation::ShareComputationCircuitInput; use crate::{prepare_share_computation_sample_for_test, ShareComputationSample}; use e3_fhe_params::BfvPreset; - use e3_fhe_params::DEFAULT_BFV_PRESET; fn share_computation_input_from_sample( sample: &ShareComputationSample, @@ -294,8 +293,8 @@ mod tests { ); let input = share_computation_input_from_sample(&sample, DkgInputType::SecretKey); - let bounds = Bounds::compute(DEFAULT_BFV_PRESET, &input).unwrap(); - let bits = Bits::compute(DEFAULT_BFV_PRESET, &bounds).unwrap(); + let bounds = Bounds::compute(BfvPreset::InsecureThreshold512, &input).unwrap(); + let bits = Bits::compute(BfvPreset::InsecureThreshold512, &bounds).unwrap(); let expected_sk_bits = calculate_bit_width(BigInt::from(bounds.sk_bound.clone())); assert_eq!(bits.bit_sk_secret, expected_sk_bits); @@ -310,7 +309,7 @@ mod tests { ); let input = share_computation_input_from_sample(&sample, DkgInputType::SmudgingNoise); - let witness = Witness::compute(DEFAULT_BFV_PRESET, &input).unwrap(); + let witness = Witness::compute(BfvPreset::InsecureThreshold512, &input).unwrap(); let degree = witness.secret_crt.limb(0).coefficients().len(); let num_moduli = witness.secret_crt.limbs.len(); for coeff_idx in 0..degree { @@ -335,7 +334,7 @@ mod tests { ); let input = share_computation_input_from_sample(&sample, DkgInputType::SecretKey); - let constants = Configs::compute(DEFAULT_BFV_PRESET, &input).unwrap(); + let constants = Configs::compute(BfvPreset::InsecureThreshold512, &input).unwrap(); let json = constants.to_json().unwrap(); let decoded: Configs = serde_json::from_value(json).unwrap(); diff --git a/crates/zk-helpers/src/circuits/dkg/share_encryption/circuit.rs b/crates/zk-helpers/src/circuits/dkg/share_encryption/circuit.rs index 93bc22c389..ec3bcd3bf5 100644 --- a/crates/zk-helpers/src/circuits/dkg/share_encryption/circuit.rs +++ b/crates/zk-helpers/src/circuits/dkg/share_encryption/circuit.rs @@ -22,7 +22,7 @@ pub struct ShareEncryptionCircuit; impl Circuit for ShareEncryptionCircuit { const NAME: &'static str = "share-encryption"; const PREFIX: &'static str = "SHARE_ENCRYPTION"; - const SUPPORTED_PARAMETER: ParameterType = ParameterType::THRESHOLD; + const SUPPORTED_PARAMETER: ParameterType = ParameterType::DKG; /// None: circuit accepts runtime-varying input type (SecretKey or SmudgingNoise). const DKG_INPUT_TYPE: Option = None; } diff --git a/crates/zk-helpers/src/circuits/dkg/share_encryption/codegen.rs b/crates/zk-helpers/src/circuits/dkg/share_encryption/codegen.rs index 3b1127bc67..7e7813557c 100644 --- a/crates/zk-helpers/src/circuits/dkg/share_encryption/codegen.rs +++ b/crates/zk-helpers/src/circuits/dkg/share_encryption/codegen.rs @@ -230,7 +230,6 @@ mod tests { use crate::dkg::share_encryption::ShareEncryptionSample; use crate::Circuit; use e3_fhe_params::BfvPreset; - use e3_fhe_params::DEFAULT_BFV_PRESET; fn share_encryption_input_from_sample( sample: &ShareEncryptionSample, @@ -256,7 +255,7 @@ mod tests { let input = share_encryption_input_from_sample(&sample); let artifacts = ShareEncryptionCircuit - .codegen(DEFAULT_BFV_PRESET, &input) + .codegen(BfvPreset::InsecureThreshold512, &input) .unwrap(); let parsed: toml::Value = artifacts.toml.parse().unwrap(); @@ -276,13 +275,15 @@ mod tests { let input = share_encryption_input_from_sample(&sample); let artifacts = ShareEncryptionCircuit - .codegen(DEFAULT_BFV_PRESET, &input) + .codegen(BfvPreset::InsecureThreshold512, &input) .unwrap(); - let bounds = Bounds::compute(DEFAULT_BFV_PRESET, &input).unwrap(); - let bits = - crate::circuits::dkg::share_encryption::Bits::compute(DEFAULT_BFV_PRESET, &bounds) - .unwrap(); + let bounds = Bounds::compute(BfvPreset::InsecureThreshold512, &input).unwrap(); + let bits = crate::circuits::dkg::share_encryption::Bits::compute( + BfvPreset::InsecureThreshold512, + &bounds, + ) + .unwrap(); let prefix = ::PREFIX; assert!(artifacts.configs.contains("ShareEncryptionConfigs")); diff --git a/crates/zk-helpers/src/circuits/dkg/share_encryption/computation.rs b/crates/zk-helpers/src/circuits/dkg/share_encryption/computation.rs index 802a209409..8576487235 100644 --- a/crates/zk-helpers/src/circuits/dkg/share_encryption/computation.rs +++ b/crates/zk-helpers/src/circuits/dkg/share_encryption/computation.rs @@ -921,7 +921,6 @@ mod tests { use crate::dkg::share_encryption::sample::prepare_share_encryption_sample_for_test; use crate::dkg::share_encryption::ShareEncryptionSample; use e3_fhe_params::BfvPreset; - use e3_fhe_params::DEFAULT_BFV_PRESET; fn share_encryption_input_from_sample( sample: &ShareEncryptionSample, @@ -945,8 +944,8 @@ mod tests { DkgInputType::SecretKey, ); let input = share_encryption_input_from_sample(&sample); - let bounds = Bounds::compute(DEFAULT_BFV_PRESET, &input).unwrap(); - let bits = Bits::compute(DEFAULT_BFV_PRESET, &bounds).unwrap(); + let bounds = Bounds::compute(BfvPreset::InsecureThreshold512, &input).unwrap(); + let bits = Bits::compute(BfvPreset::InsecureThreshold512, &bounds).unwrap(); let max_pk_bound = bounds.pk_bounds.iter().max().unwrap(); let expected_bits = calculate_bit_width(BigInt::from(max_pk_bound.clone())); @@ -963,7 +962,7 @@ mod tests { DkgInputType::SecretKey, ); let input = share_encryption_input_from_sample(&sample); - let constants = Configs::compute(DEFAULT_BFV_PRESET, &input).unwrap(); + let constants = Configs::compute(BfvPreset::InsecureThreshold512, &input).unwrap(); let json = constants.to_json().unwrap(); let decoded: Configs = serde_json::from_value(json).unwrap(); @@ -984,7 +983,7 @@ mod tests { DkgInputType::SecretKey, ); let input = share_encryption_input_from_sample(&sample); - let witness = Witness::compute(DEFAULT_BFV_PRESET, &input).unwrap(); + let witness = Witness::compute(BfvPreset::InsecureThreshold512, &input).unwrap(); // witness.message is plaintext coefficients (reversed, as used in circuit) let expected_message = Polynomial::from_u64_vector(sample.plaintext.value.deref().to_vec()); diff --git a/crates/zk-helpers/src/circuits/dkg/share_encryption/sample.rs b/crates/zk-helpers/src/circuits/dkg/share_encryption/sample.rs index 2d6c639fe7..888f8d140a 100644 --- a/crates/zk-helpers/src/circuits/dkg/share_encryption/sample.rs +++ b/crates/zk-helpers/src/circuits/dkg/share_encryption/sample.rs @@ -130,7 +130,7 @@ mod tests { use super::*; use crate::ciphernodes_committee::CiphernodesCommitteeSize; use crate::computation::DkgInputType; - use e3_fhe_params::{BfvPreset, DEFAULT_BFV_PRESET}; + use e3_fhe_params::BfvPreset; #[test] fn test_generate_secret_key_sample() { @@ -143,20 +143,20 @@ mod tests { assert_eq!(sample.public_key.c.c.len(), 2); assert_eq!( sample.plaintext.value.len(), - DEFAULT_BFV_PRESET.metadata().degree + BfvPreset::InsecureThreshold512.metadata().degree ); assert_eq!(sample.ciphertext.c.len(), 2); assert_eq!( sample.u_rns.coefficients().len(), - DEFAULT_BFV_PRESET.metadata().degree + BfvPreset::InsecureThreshold512.metadata().degree ); assert_eq!( sample.e0_rns.coefficients().len(), - DEFAULT_BFV_PRESET.metadata().degree + BfvPreset::InsecureThreshold512.metadata().degree ); assert_eq!( sample.e1_rns.coefficients().len(), - DEFAULT_BFV_PRESET.metadata().degree + BfvPreset::InsecureThreshold512.metadata().degree ); } @@ -172,15 +172,15 @@ mod tests { assert_eq!(sample.ciphertext.c.len(), 2); assert_eq!( sample.u_rns.coefficients().len(), - DEFAULT_BFV_PRESET.metadata().degree + BfvPreset::InsecureThreshold512.metadata().degree ); assert_eq!( sample.e0_rns.coefficients().len(), - DEFAULT_BFV_PRESET.metadata().degree + BfvPreset::InsecureThreshold512.metadata().degree ); assert_eq!( sample.e1_rns.coefficients().len(), - DEFAULT_BFV_PRESET.metadata().degree + BfvPreset::InsecureThreshold512.metadata().degree ); } } diff --git a/crates/zk-helpers/src/circuits/threshold/user_data_encryption/codegen.rs b/crates/zk-helpers/src/circuits/threshold/user_data_encryption/codegen.rs index 369a565f95..f0c17cc22c 100644 --- a/crates/zk-helpers/src/circuits/threshold/user_data_encryption/codegen.rs +++ b/crates/zk-helpers/src/circuits/threshold/user_data_encryption/codegen.rs @@ -206,15 +206,15 @@ mod tests { use crate::threshold::user_data_encryption::computation::{Bits, Bounds}; use crate::threshold::user_data_encryption::sample::UserDataEncryptionSample; - use e3_fhe_params::DEFAULT_BFV_PRESET; + use e3_fhe_params::BfvPreset; use tempfile::TempDir; #[test] fn test_toml_generation_and_structure() { - let sample = UserDataEncryptionSample::generate(DEFAULT_BFV_PRESET); + let sample = UserDataEncryptionSample::generate(BfvPreset::InsecureThreshold512); let artifacts = UserDataEncryptionCircuit .codegen( - DEFAULT_BFV_PRESET, + BfvPreset::InsecureThreshold512, &UserDataEncryptionCircuitInput { public_key: sample.public_key, plaintext: sample.plaintext, @@ -256,13 +256,23 @@ mod tests { assert!(configs_path.exists()); let configs_content = std::fs::read_to_string(&configs_path).unwrap(); - let bounds = Bounds::compute(DEFAULT_BFV_PRESET, &()).unwrap(); - let bits = Bits::compute(DEFAULT_BFV_PRESET, &bounds).unwrap(); + let bounds = Bounds::compute(BfvPreset::InsecureThreshold512, &()).unwrap(); + let bits = Bits::compute(BfvPreset::InsecureThreshold512, &bounds).unwrap(); - assert!(configs_content - .contains(format!("N: u32 = {}", DEFAULT_BFV_PRESET.metadata().degree).as_str())); - assert!(configs_content - .contains(format!("L: u32 = {}", DEFAULT_BFV_PRESET.metadata().num_moduli).as_str())); + assert!(configs_content.contains( + format!( + "N: u32 = {}", + BfvPreset::InsecureThreshold512.metadata().degree + ) + .as_str() + )); + assert!(configs_content.contains( + format!( + "L: u32 = {}", + BfvPreset::InsecureThreshold512.metadata().num_moduli + ) + .as_str() + )); assert!(configs_content.contains( format!( "{}_BIT_PK: u32 = {}", diff --git a/crates/zk-helpers/src/circuits/threshold/user_data_encryption/computation.rs b/crates/zk-helpers/src/circuits/threshold/user_data_encryption/computation.rs index a94daddd90..64f3a327ac 100644 --- a/crates/zk-helpers/src/circuits/threshold/user_data_encryption/computation.rs +++ b/crates/zk-helpers/src/circuits/threshold/user_data_encryption/computation.rs @@ -930,12 +930,12 @@ impl Computation for Witness { mod tests { use super::*; - use e3_fhe_params::DEFAULT_BFV_PRESET; + use e3_fhe_params::BfvPreset; #[test] fn test_bound_and_bits_computation_consistency() { - let bounds = Bounds::compute(DEFAULT_BFV_PRESET, &()).unwrap(); - let bits = Bits::compute(DEFAULT_BFV_PRESET, &bounds).unwrap(); + let bounds = Bounds::compute(BfvPreset::InsecureThreshold512, &()).unwrap(); + let bits = Bits::compute(BfvPreset::InsecureThreshold512, &bounds).unwrap(); let max_pk_bound = bounds.pk_bounds.iter().max().unwrap(); let expected_bits = calculate_bit_width(BigInt::from(max_pk_bound.clone())); @@ -946,7 +946,7 @@ mod tests { #[test] fn test_constants_json_roundtrip() { - let constants = Configs::compute(DEFAULT_BFV_PRESET, &()).unwrap(); + let constants = Configs::compute(BfvPreset::InsecureThreshold512, &()).unwrap(); let json = constants.to_json().unwrap(); let decoded: Configs = serde_json::from_value(json).unwrap(); diff --git a/crates/zk-helpers/src/circuits/threshold/user_data_encryption/sample.rs b/crates/zk-helpers/src/circuits/threshold/user_data_encryption/sample.rs index 827adfa293..f77b310e4c 100644 --- a/crates/zk-helpers/src/circuits/threshold/user_data_encryption/sample.rs +++ b/crates/zk-helpers/src/circuits/threshold/user_data_encryption/sample.rs @@ -44,16 +44,16 @@ impl UserDataEncryptionSample { #[cfg(test)] mod tests { use super::*; - use e3_fhe_params::DEFAULT_BFV_PRESET; + use e3_fhe_params::BfvPreset; #[test] fn test_generate_sample() { - let sample = UserDataEncryptionSample::generate(DEFAULT_BFV_PRESET); + let sample = UserDataEncryptionSample::generate(BfvPreset::InsecureThreshold512); assert_eq!(sample.public_key.c.c.len(), 2); assert_eq!( sample.plaintext.value.len(), - DEFAULT_BFV_PRESET.metadata().degree + BfvPreset::InsecureThreshold512.metadata().degree ); } } diff --git a/crates/zk-helpers/src/circuits/threshold/user_data_encryption/utils.rs b/crates/zk-helpers/src/circuits/threshold/user_data_encryption/utils.rs index 8b192bbbdc..37190a8a2d 100644 --- a/crates/zk-helpers/src/circuits/threshold/user_data_encryption/utils.rs +++ b/crates/zk-helpers/src/circuits/threshold/user_data_encryption/utils.rs @@ -177,16 +177,16 @@ mod tests { use crate::threshold::user_data_encryption::computation::Witness; use crate::threshold::user_data_encryption::sample::UserDataEncryptionSample; use crate::threshold::UserDataEncryptionCircuitInput; - use e3_fhe_params::{build_pair_for_preset, DEFAULT_BFV_PRESET}; + use e3_fhe_params::{build_pair_for_preset, BfvPreset}; use fhe_traits::DeserializeParametrized; #[test] fn test_bfv_public_key_to_greco() { - let (threshold_params, _) = build_pair_for_preset(DEFAULT_BFV_PRESET).unwrap(); - let sample = UserDataEncryptionSample::generate(DEFAULT_BFV_PRESET); + let (threshold_params, _) = build_pair_for_preset(BfvPreset::InsecureThreshold512).unwrap(); + let sample = UserDataEncryptionSample::generate(BfvPreset::InsecureThreshold512); let witness = Witness::compute( - DEFAULT_BFV_PRESET, + BfvPreset::InsecureThreshold512, &UserDataEncryptionCircuitInput { public_key: sample.public_key.clone(), plaintext: sample.plaintext, @@ -205,12 +205,12 @@ mod tests { #[test] fn test_bfv_ciphertext_to_greco() { - let (threshold_params, _) = build_pair_for_preset(DEFAULT_BFV_PRESET).unwrap(); + let (threshold_params, _) = build_pair_for_preset(BfvPreset::InsecureThreshold512).unwrap(); - let sample = UserDataEncryptionSample::generate(DEFAULT_BFV_PRESET); + let sample = UserDataEncryptionSample::generate(BfvPreset::InsecureThreshold512); let witness = Witness::compute( - DEFAULT_BFV_PRESET, + BfvPreset::InsecureThreshold512, &UserDataEncryptionCircuitInput { public_key: sample.public_key.clone(), plaintext: sample.plaintext, From 631a6196b02bb0efb94d8e75ed9facb2f87af695 Mon Sep 17 00:00:00 2001 From: 0xjei Date: Thu, 5 Feb 2026 17:49:10 +0100 Subject: [PATCH 3/4] avoid repetitive configs --- .../bin/dkg/e_sm_share_encryption/src/main.nr | 4 +- .../bin/dkg/sk_share_encryption/src/main.nr | 4 +- circuits/lib/src/configs/insecure/dkg.nr | 10 +---- circuits/lib/src/configs/secure/dkg.nr | 26 +------------ .../circuits/dkg/share_encryption/codegen.rs | 39 +------------------ 5 files changed, 10 insertions(+), 73 deletions(-) diff --git a/circuits/bin/dkg/e_sm_share_encryption/src/main.nr b/circuits/bin/dkg/e_sm_share_encryption/src/main.nr index dc093b2d7f..ad96bbb1f2 100644 --- a/circuits/bin/dkg/e_sm_share_encryption/src/main.nr +++ b/circuits/bin/dkg/e_sm_share_encryption/src/main.nr @@ -8,7 +8,7 @@ use lib::configs::default::dkg::{ L, N, SHARE_ENCRYPTION_BIT_CT, SHARE_ENCRYPTION_BIT_E0, SHARE_ENCRYPTION_BIT_E1, SHARE_ENCRYPTION_BIT_MSG, SHARE_ENCRYPTION_BIT_P1, SHARE_ENCRYPTION_BIT_P2, SHARE_ENCRYPTION_BIT_PK, SHARE_ENCRYPTION_BIT_R1, SHARE_ENCRYPTION_BIT_R2, - SHARE_ENCRYPTION_BIT_U, SHARE_ENCRYPTION_CONFIGS_E_SM, + SHARE_ENCRYPTION_BIT_U, SHARE_ENCRYPTION_CONFIGS, }; use lib::core::dkg::share_encryption::ShareEncryption; use lib::math::polynomial::Polynomial; @@ -32,7 +32,7 @@ fn main( p2is: [Polynomial; L], ) { let share_encryption: ShareEncryption = ShareEncryption::new( - SHARE_ENCRYPTION_CONFIGS_E_SM, + SHARE_ENCRYPTION_CONFIGS, expected_pk_commitment, expected_message_commitment, pk0is, diff --git a/circuits/bin/dkg/sk_share_encryption/src/main.nr b/circuits/bin/dkg/sk_share_encryption/src/main.nr index 68a3f7085d..ad96bbb1f2 100644 --- a/circuits/bin/dkg/sk_share_encryption/src/main.nr +++ b/circuits/bin/dkg/sk_share_encryption/src/main.nr @@ -8,7 +8,7 @@ use lib::configs::default::dkg::{ L, N, SHARE_ENCRYPTION_BIT_CT, SHARE_ENCRYPTION_BIT_E0, SHARE_ENCRYPTION_BIT_E1, SHARE_ENCRYPTION_BIT_MSG, SHARE_ENCRYPTION_BIT_P1, SHARE_ENCRYPTION_BIT_P2, SHARE_ENCRYPTION_BIT_PK, SHARE_ENCRYPTION_BIT_R1, SHARE_ENCRYPTION_BIT_R2, - SHARE_ENCRYPTION_BIT_U, SHARE_ENCRYPTION_CONFIGS_SK, + SHARE_ENCRYPTION_BIT_U, SHARE_ENCRYPTION_CONFIGS, }; use lib::core::dkg::share_encryption::ShareEncryption; use lib::math::polynomial::Polynomial; @@ -32,7 +32,7 @@ fn main( p2is: [Polynomial; L], ) { let share_encryption: ShareEncryption = ShareEncryption::new( - SHARE_ENCRYPTION_CONFIGS_SK, + SHARE_ENCRYPTION_CONFIGS, expected_pk_commitment, expected_message_commitment, pk0is, diff --git a/circuits/lib/src/configs/insecure/dkg.nr b/circuits/lib/src/configs/insecure/dkg.nr index 06f8218579..5775be709e 100644 --- a/circuits/lib/src/configs/insecure/dkg.nr +++ b/circuits/lib/src/configs/insecure/dkg.nr @@ -71,6 +71,7 @@ pub global SHARE_COMPUTATION_E_SM_CONFIGS: ShareComputationConfigs /************************************ ------------------------------------- share_encryption_sk (CIRCUIT 3a) +share_encryption_e_sm (CIRCUIT 3b) ------------------------------------- ************************************/ @@ -116,14 +117,7 @@ pub global SHARE_ENCRYPTION_CONFIGS_SK: ShareEncryptionConfigs = ShareEncrypt SHARE_ENCRYPTION_MSG_BOUND, ); -/************************************ -------------------------------------- -share_encryption_e_sm (CIRCUIT 3b) -------------------------------------- -************************************/ - -// share_encryption_e_sm uses the same bit parameters and bounds as share_encryption_sk -pub global SHARE_ENCRYPTION_CONFIGS_E_SM: ShareEncryptionConfigs = ShareEncryptionConfigs::new( +pub global SHARE_ENCRYPTION_CONFIGS: ShareEncryptionConfigs = ShareEncryptionConfigs::new( SHARE_ENCRYPTION_T, SHARE_ENCRYPTION_Q_MOD_T, QIS, diff --git a/circuits/lib/src/configs/secure/dkg.nr b/circuits/lib/src/configs/secure/dkg.nr index 2a8f97f23f..11190a7251 100644 --- a/circuits/lib/src/configs/secure/dkg.nr +++ b/circuits/lib/src/configs/secure/dkg.nr @@ -83,6 +83,7 @@ pub global SHARE_COMPUTATION_E_SM_CONFIGS: ShareComputationConfigs /************************************ ------------------------------------- share_encryption_sk (CIRCUIT 3a) +share_encryption_e_sm (CIRCUIT 3b) ------------------------------------- ************************************/ @@ -111,31 +112,8 @@ pub global SHARE_ENCRYPTION_P1_BOUNDS: [Field; L] = [4096, 4096]; pub global SHARE_ENCRYPTION_P2_BOUNDS: [Field; L] = [36028797041049600, 36028797031219200]; pub global SHARE_ENCRYPTION_MSG_BOUND: Field = 18014398509481983; -pub global SHARE_ENCRYPTION_CONFIGS_SK: ShareEncryptionConfigs = ShareEncryptionConfigs::new( - SHARE_ENCRYPTION_T, - SHARE_ENCRYPTION_Q_MOD_T, - QIS, - SHARE_ENCRYPTION_K0IS, - SHARE_ENCRYPTION_PK_BOUNDS, - SHARE_ENCRYPTION_E0_BOUND, - SHARE_ENCRYPTION_E1_BOUND, - SHARE_ENCRYPTION_U_BOUND, - SHARE_ENCRYPTION_R1_LOW_BOUNDS, - SHARE_ENCRYPTION_R1_UP_BOUNDS, - SHARE_ENCRYPTION_R2_BOUNDS, - SHARE_ENCRYPTION_P1_BOUNDS, - SHARE_ENCRYPTION_P2_BOUNDS, - SHARE_ENCRYPTION_MSG_BOUND, -); - -/************************************ -------------------------------------- -share_encryption_e_sm (CIRCUIT 3b) -------------------------------------- -************************************/ - // share_encryption_e_sm uses the same bit parameters and bounds as share_encryption_sk -pub global SHARE_ENCRYPTION_CONFIGS_E_SM: ShareEncryptionConfigs = ShareEncryptionConfigs::new( +pub global SHARE_ENCRYPTION_CONFIGS: ShareEncryptionConfigs = ShareEncryptionConfigs::new( SHARE_ENCRYPTION_T, SHARE_ENCRYPTION_Q_MOD_T, QIS, diff --git a/crates/zk-helpers/src/circuits/dkg/share_encryption/codegen.rs b/crates/zk-helpers/src/circuits/dkg/share_encryption/codegen.rs index 7e7813557c..5b9ad7ced5 100644 --- a/crates/zk-helpers/src/circuits/dkg/share_encryption/codegen.rs +++ b/crates/zk-helpers/src/circuits/dkg/share_encryption/codegen.rs @@ -71,6 +71,7 @@ pub global QIS: [Field; L] = [{}]; /************************************ ------------------------------------- share_encryption_sk (CIRCUIT 3a) +share_encryption_e_sm (CIRCUIT 3b) ------------------------------------- ************************************/ @@ -99,7 +100,7 @@ pub global {}_P1_BOUNDS: [Field; L] = [{}]; pub global {}_P2_BOUNDS: [Field; L] = [{}]; pub global {}_MSG_BOUND: Field = {}; -pub global {}_CONFIGS_SK: ShareEncryptionConfigs = ShareEncryptionConfigs::new( +pub global {}_CONFIGS: ShareEncryptionConfigs = ShareEncryptionConfigs::new( {}_T, {}_Q_MOD_T, QIS, @@ -115,29 +116,6 @@ pub global {}_CONFIGS_SK: ShareEncryptionConfigs = ShareEncryptionConfigs::ne {}_P2_BOUNDS, {}_MSG_BOUND, ); - -/************************************ -------------------------------------- -share_encryption_e_sm (CIRCUIT 3b) -------------------------------------- -************************************/ - -// share_encryption_e_sm uses the same bit parameters and bounds as share_encryption_sk -pub global SHARE_ENCRYPTION_CONFIGS_E_SM: ShareEncryptionConfigs = ShareEncryptionConfigs::new( - {}_T, - {}_Q_MOD_T, - QIS, - {}_K0IS, - {}_PK_BOUNDS, - {}_E0_BOUND, - {}_E1_BOUND, - {}_U_BOUND, - {}_R1_LOW_BOUNDS, - {}_R1_UP_BOUNDS, - {}_R2_BOUNDS, - {}_P1_BOUNDS, - {}_P2_BOUNDS, - {}_MSG_BOUND,); "#, preset.dkg_counterpart().unwrap().metadata().degree, preset.dkg_counterpart().unwrap().metadata().num_moduli, @@ -202,19 +180,6 @@ pub global SHARE_ENCRYPTION_CONFIGS_E_SM: ShareEncryptionConfigs = ShareEncry prefix, prefix, prefix, - prefix, - prefix, - prefix, - prefix, - prefix, - prefix, - prefix, - prefix, - prefix, - prefix, - prefix, - prefix, - prefix, ) } From 11d1f50e5ac18f03f46f99d603af1fda20184fb9 Mon Sep 17 00:00:00 2001 From: 0xjei Date: Thu, 5 Feb 2026 17:56:57 +0100 Subject: [PATCH 4/4] fix test --- crates/zk-helpers/src/circuits/dkg/share_encryption/codegen.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/zk-helpers/src/circuits/dkg/share_encryption/codegen.rs b/crates/zk-helpers/src/circuits/dkg/share_encryption/codegen.rs index 5b9ad7ced5..33aacc1a9c 100644 --- a/crates/zk-helpers/src/circuits/dkg/share_encryption/codegen.rs +++ b/crates/zk-helpers/src/circuits/dkg/share_encryption/codegen.rs @@ -258,6 +258,6 @@ mod tests { assert!(artifacts .configs .contains(format!("{}_BIT_MSG: u32 = {}", prefix, bits.msg_bit).as_str())); - assert!(artifacts.configs.contains("SHARE_ENCRYPTION_CONFIGS_E_SM")); + assert!(artifacts.configs.contains("SHARE_ENCRYPTION_CONFIGS")); } }