diff --git a/circuits/benchmarks/results_insecure/report.md b/circuits/benchmarks/results_insecure/report.md index 3b7e19d687..a0b18a30cb 100644 --- a/circuits/benchmarks/results_insecure/report.md +++ b/circuits/benchmarks/results_insecure/report.md @@ -13,45 +13,45 @@ #### Timing Metrics -| Circuit | Compile | Execute | Prove | Verify | -|---------|---------|---------|-------|--------| -| e_sm_share_computation | 0.31 s | 0.52 s | 1.55 s | 0.02 s | -| pk | 0.25 s | 0.27 s | 0.12 s | 0.03 s | -| share_decryption | 0.25 s | 0.29 s | 0.23 s | 0.02 s | -| share_encryption | 0.29 s | 0.44 s | 0.61 s | 0.03 s | -| sk_share_computation | 0.30 s | 0.51 s | 1.54 s | 0.03 s | +| Circuit | Compile | Execute | Prove | Verify | +| ---------------------- | ------- | ------- | ------ | ------ | +| e_sm_share_computation | 0.31 s | 0.52 s | 1.55 s | 0.02 s | +| pk | 0.25 s | 0.27 s | 0.12 s | 0.03 s | +| share_decryption | 0.25 s | 0.29 s | 0.23 s | 0.02 s | +| share_encryption | 0.29 s | 0.44 s | 0.61 s | 0.03 s | +| sk_share_computation | 0.30 s | 0.51 s | 1.54 s | 0.03 s | #### Size & Circuit Metrics -| Circuit | Opcodes | Gates | Circuit Size | Witness | VK Size | Proof Size | -|---------|---------|-------|--------------|---------|---------|------------| -| e_sm_share_computation | 90956 | 328.74K | 1.39 MB | 477.72 KB | 3.59 KB | 15.88 KB | -| pk | 344 | 6.85K | 87.84 KB | 29.07 KB | 3.59 KB | 15.88 KB | -| share_decryption | 3093 | 28.72K | 158.27 KB | 148.91 KB | 3.59 KB | 15.88 KB | -| share_encryption | 47758 | 127.69K | 798.14 KB | 512.11 KB | 3.59 KB | 15.88 KB | -| sk_share_computation | 90827 | 326.14K | 1.38 MB | 463.68 KB | 3.59 KB | 15.88 KB | +| Circuit | Opcodes | Gates | Circuit Size | Witness | VK Size | Proof Size | +| ---------------------- | ------- | ------- | ------------ | --------- | ------- | ---------- | +| e_sm_share_computation | 90956 | 328.74K | 1.39 MB | 477.72 KB | 3.59 KB | 15.88 KB | +| pk | 344 | 6.85K | 87.84 KB | 29.07 KB | 3.59 KB | 15.88 KB | +| share_decryption | 3093 | 28.72K | 158.27 KB | 148.91 KB | 3.59 KB | 15.88 KB | +| share_encryption | 47758 | 127.69K | 798.14 KB | 512.11 KB | 3.59 KB | 15.88 KB | +| sk_share_computation | 90827 | 326.14K | 1.38 MB | 463.68 KB | 3.59 KB | 15.88 KB | ### Threshold #### Timing Metrics -| Circuit | Compile | Execute | Prove | Verify | -|---------|---------|---------|-------|--------| -| decrypted_shares_aggregation_mod | 0.27 s | 0.33 s | 0.46 s | 0.02 s | -| pk_aggregation | 0.29 s | 0.45 s | 0.87 s | 0.02 s | -| pk_generation | 0.28 s | 0.38 s | 0.48 s | 0.03 s | -| share_decryption | 0.28 s | 0.40 s | 0.53 s | 0.03 s | -| user_data_encryption | 0.30 s | 0.47 s | 0.58 s | 0.02 s | +| Circuit | Compile | Execute | Prove | Verify | +| -------------------------------- | ------- | ------- | ------ | ------ | +| decrypted_shares_aggregation_mod | 0.27 s | 0.33 s | 0.46 s | 0.02 s | +| pk_aggregation | 0.29 s | 0.45 s | 0.87 s | 0.02 s | +| pk_generation | 0.28 s | 0.38 s | 0.48 s | 0.03 s | +| share_decryption | 0.28 s | 0.40 s | 0.53 s | 0.03 s | +| user_data_encryption | 0.30 s | 0.47 s | 0.58 s | 0.02 s | #### Size & Circuit Metrics -| Circuit | Opcodes | Gates | Circuit Size | Witness | VK Size | Proof Size | -|---------|---------|-------|--------------|---------|---------|------------| -| decrypted_shares_aggregation_mod | 31544 | 80.74K | 509.84 KB | 77.56 KB | 3.59 KB | 15.88 KB | -| pk_aggregation | 47817 | 169.89K | 884.11 KB | 360.86 KB | 3.59 KB | 15.88 KB | -| pk_generation | 30019 | 65.61K | 542.16 KB | 447.05 KB | 3.59 KB | 15.88 KB | -| share_decryption | 30570 | 85.48K | 541.56 KB | 522.86 KB | 3.59 KB | 15.88 KB | -| user_data_encryption | 56601 | 106.72K | 847.64 KB | 691.13 KB | 3.59 KB | 15.88 KB | +| Circuit | Opcodes | Gates | Circuit Size | Witness | VK Size | Proof Size | +| -------------------------------- | ------- | ------- | ------------ | --------- | ------- | ---------- | +| decrypted_shares_aggregation_mod | 31544 | 80.74K | 509.84 KB | 77.56 KB | 3.59 KB | 15.88 KB | +| pk_aggregation | 47817 | 169.89K | 884.11 KB | 360.86 KB | 3.59 KB | 15.88 KB | +| pk_generation | 30019 | 65.61K | 542.16 KB | 447.05 KB | 3.59 KB | 15.88 KB | +| share_decryption | 30570 | 85.48K | 541.56 KB | 522.86 KB | 3.59 KB | 15.88 KB | +| user_data_encryption | 56601 | 106.72K | 847.64 KB | 691.13 KB | 3.59 KB | 15.88 KB | ## Circuit Details @@ -59,167 +59,165 @@ #### e_sm_share_computation -| Metric | Value | -|--------|-------| -| **Compilation** | 0.31 s | -| **Execution** | 0.52 s | -| **VK Generation** | 0.59 s | -| **Proof Generation** | 1.55 s | -| **Verification** | 0.02 s | -| **ACIR Opcodes** | "90956" | -| **Total Gates** | "328743" | -| **Circuit Size** | 1.39 MB | -| **Witness Size** | 477.72 KB | -| **VK Size** | 3.59 KB | -| **Proof Size** | 15.88 KB | +| Metric | Value | +| -------------------- | --------- | +| **Compilation** | 0.31 s | +| **Execution** | 0.52 s | +| **VK Generation** | 0.59 s | +| **Proof Generation** | 1.55 s | +| **Verification** | 0.02 s | +| **ACIR Opcodes** | "90956" | +| **Total Gates** | "328743" | +| **Circuit Size** | 1.39 MB | +| **Witness Size** | 477.72 KB | +| **VK Size** | 3.59 KB | +| **Proof Size** | 15.88 KB | #### pk -| Metric | Value | -|--------|-------| -| **Compilation** | 0.25 s | -| **Execution** | 0.27 s | -| **VK Generation** | 0.05 s | -| **Proof Generation** | 0.12 s | -| **Verification** | 0.03 s | -| **ACIR Opcodes** | "344" | -| **Total Gates** | "6846" | -| **Circuit Size** | 87.84 KB | -| **Witness Size** | 29.07 KB | -| **VK Size** | 3.59 KB | -| **Proof Size** | 15.88 KB | +| Metric | Value | +| -------------------- | -------- | +| **Compilation** | 0.25 s | +| **Execution** | 0.27 s | +| **VK Generation** | 0.05 s | +| **Proof Generation** | 0.12 s | +| **Verification** | 0.03 s | +| **ACIR Opcodes** | "344" | +| **Total Gates** | "6846" | +| **Circuit Size** | 87.84 KB | +| **Witness Size** | 29.07 KB | +| **VK Size** | 3.59 KB | +| **Proof Size** | 15.88 KB | #### share_decryption -| Metric | Value | -|--------|-------| -| **Compilation** | 0.25 s | -| **Execution** | 0.29 s | -| **VK Generation** | 0.09 s | -| **Proof Generation** | 0.23 s | -| **Verification** | 0.02 s | -| **ACIR Opcodes** | "3093" | -| **Total Gates** | "28720" | -| **Circuit Size** | 158.27 KB | -| **Witness Size** | 148.91 KB | -| **VK Size** | 3.59 KB | -| **Proof Size** | 15.88 KB | +| Metric | Value | +| -------------------- | --------- | +| **Compilation** | 0.25 s | +| **Execution** | 0.29 s | +| **VK Generation** | 0.09 s | +| **Proof Generation** | 0.23 s | +| **Verification** | 0.02 s | +| **ACIR Opcodes** | "3093" | +| **Total Gates** | "28720" | +| **Circuit Size** | 158.27 KB | +| **Witness Size** | 148.91 KB | +| **VK Size** | 3.59 KB | +| **Proof Size** | 15.88 KB | #### share_encryption -| Metric | Value | -|--------|-------| -| **Compilation** | 0.29 s | -| **Execution** | 0.44 s | -| **VK Generation** | 0.26 s | -| **Proof Generation** | 0.61 s | -| **Verification** | 0.03 s | -| **ACIR Opcodes** | "47758" | -| **Total Gates** | "127691" | -| **Circuit Size** | 798.14 KB | -| **Witness Size** | 512.11 KB | -| **VK Size** | 3.59 KB | -| **Proof Size** | 15.88 KB | +| Metric | Value | +| -------------------- | --------- | +| **Compilation** | 0.29 s | +| **Execution** | 0.44 s | +| **VK Generation** | 0.26 s | +| **Proof Generation** | 0.61 s | +| **Verification** | 0.03 s | +| **ACIR Opcodes** | "47758" | +| **Total Gates** | "127691" | +| **Circuit Size** | 798.14 KB | +| **Witness Size** | 512.11 KB | +| **VK Size** | 3.59 KB | +| **Proof Size** | 15.88 KB | #### sk_share_computation -| Metric | Value | -|--------|-------| -| **Compilation** | 0.30 s | -| **Execution** | 0.51 s | -| **VK Generation** | 0.66 s | -| **Proof Generation** | 1.54 s | -| **Verification** | 0.03 s | -| **ACIR Opcodes** | "90827" | -| **Total Gates** | "326138" | -| **Circuit Size** | 1.38 MB | -| **Witness Size** | 463.68 KB | -| **VK Size** | 3.59 KB | -| **Proof Size** | 15.88 KB | - +| Metric | Value | +| -------------------- | --------- | +| **Compilation** | 0.30 s | +| **Execution** | 0.51 s | +| **VK Generation** | 0.66 s | +| **Proof Generation** | 1.54 s | +| **Verification** | 0.03 s | +| **ACIR Opcodes** | "90827" | +| **Total Gates** | "326138" | +| **Circuit Size** | 1.38 MB | +| **Witness Size** | 463.68 KB | +| **VK Size** | 3.59 KB | +| **Proof Size** | 15.88 KB | ### Threshold #### decrypted_shares_aggregation_mod -| Metric | Value | -|--------|-------| -| **Compilation** | 0.27 s | -| **Execution** | 0.33 s | -| **VK Generation** | 0.18 s | -| **Proof Generation** | 0.46 s | -| **Verification** | 0.02 s | -| **ACIR Opcodes** | "31544" | -| **Total Gates** | "80740" | -| **Circuit Size** | 509.84 KB | -| **Witness Size** | 77.56 KB | -| **VK Size** | 3.59 KB | -| **Proof Size** | 15.88 KB | +| Metric | Value | +| -------------------- | --------- | +| **Compilation** | 0.27 s | +| **Execution** | 0.33 s | +| **VK Generation** | 0.18 s | +| **Proof Generation** | 0.46 s | +| **Verification** | 0.02 s | +| **ACIR Opcodes** | "31544" | +| **Total Gates** | "80740" | +| **Circuit Size** | 509.84 KB | +| **Witness Size** | 77.56 KB | +| **VK Size** | 3.59 KB | +| **Proof Size** | 15.88 KB | #### pk_aggregation -| Metric | Value | -|--------|-------| -| **Compilation** | 0.29 s | -| **Execution** | 0.45 s | -| **VK Generation** | 0.35 s | -| **Proof Generation** | 0.87 s | -| **Verification** | 0.02 s | -| **ACIR Opcodes** | "47817" | -| **Total Gates** | "169890" | -| **Circuit Size** | 884.11 KB | -| **Witness Size** | 360.86 KB | -| **VK Size** | 3.59 KB | -| **Proof Size** | 15.88 KB | +| Metric | Value | +| -------------------- | --------- | +| **Compilation** | 0.29 s | +| **Execution** | 0.45 s | +| **VK Generation** | 0.35 s | +| **Proof Generation** | 0.87 s | +| **Verification** | 0.02 s | +| **ACIR Opcodes** | "47817" | +| **Total Gates** | "169890" | +| **Circuit Size** | 884.11 KB | +| **Witness Size** | 360.86 KB | +| **VK Size** | 3.59 KB | +| **Proof Size** | 15.88 KB | #### pk_generation -| Metric | Value | -|--------|-------| -| **Compilation** | 0.28 s | -| **Execution** | 0.38 s | -| **VK Generation** | 0.16 s | -| **Proof Generation** | 0.48 s | -| **Verification** | 0.03 s | -| **ACIR Opcodes** | "30019" | -| **Total Gates** | "65606" | -| **Circuit Size** | 542.16 KB | -| **Witness Size** | 447.05 KB | -| **VK Size** | 3.59 KB | -| **Proof Size** | 15.88 KB | +| Metric | Value | +| -------------------- | --------- | +| **Compilation** | 0.28 s | +| **Execution** | 0.38 s | +| **VK Generation** | 0.16 s | +| **Proof Generation** | 0.48 s | +| **Verification** | 0.03 s | +| **ACIR Opcodes** | "30019" | +| **Total Gates** | "65606" | +| **Circuit Size** | 542.16 KB | +| **Witness Size** | 447.05 KB | +| **VK Size** | 3.59 KB | +| **Proof Size** | 15.88 KB | #### share_decryption -| Metric | Value | -|--------|-------| -| **Compilation** | 0.28 s | -| **Execution** | 0.40 s | -| **VK Generation** | 0.19 s | -| **Proof Generation** | 0.53 s | -| **Verification** | 0.03 s | -| **ACIR Opcodes** | "30570" | -| **Total Gates** | "85478" | -| **Circuit Size** | 541.56 KB | -| **Witness Size** | 522.86 KB | -| **VK Size** | 3.59 KB | -| **Proof Size** | 15.88 KB | +| Metric | Value | +| -------------------- | --------- | +| **Compilation** | 0.28 s | +| **Execution** | 0.40 s | +| **VK Generation** | 0.19 s | +| **Proof Generation** | 0.53 s | +| **Verification** | 0.03 s | +| **ACIR Opcodes** | "30570" | +| **Total Gates** | "85478" | +| **Circuit Size** | 541.56 KB | +| **Witness Size** | 522.86 KB | +| **VK Size** | 3.59 KB | +| **Proof Size** | 15.88 KB | #### user_data_encryption -| Metric | Value | -|--------|-------| -| **Compilation** | 0.30 s | -| **Execution** | 0.47 s | -| **VK Generation** | 0.23 s | -| **Proof Generation** | 0.58 s | -| **Verification** | 0.02 s | -| **ACIR Opcodes** | "56601" | -| **Total Gates** | "106725" | -| **Circuit Size** | 847.64 KB | -| **Witness Size** | 691.13 KB | -| **VK Size** | 3.59 KB | -| **Proof Size** | 15.88 KB | - +| Metric | Value | +| -------------------- | --------- | +| **Compilation** | 0.30 s | +| **Execution** | 0.47 s | +| **VK Generation** | 0.23 s | +| **Proof Generation** | 0.58 s | +| **Verification** | 0.02 s | +| **ACIR Opcodes** | "56601" | +| **Total Gates** | "106725" | +| **Circuit Size** | 847.64 KB | +| **Witness Size** | 691.13 KB | +| **VK Size** | 3.59 KB | +| **Proof Size** | 15.88 KB | ## System Information @@ -233,6 +231,7 @@ ### Software -- **Nargo Version:** nargo version = 1.0.0-beta.15 noirc version = 1.0.0-beta.15+83245db91dcf63420ef4bcbbd85b98f397fee663 (git version hash: 83245db91dcf63420ef4bcbbd85b98f397fee663, is dirty: false) -- **Barretenberg Version:** 3.0.0-nightly.20251104 - +- **Nargo Version:** nargo version = 1.0.0-beta.15 noirc version = + 1.0.0-beta.15+83245db91dcf63420ef4bcbbd85b98f397fee663 (git version hash: + 83245db91dcf63420ef4bcbbd85b98f397fee663, is dirty: false) +- **Barretenberg Version:** 3.0.0-nightly.20251104 diff --git a/circuits/bin/config/Nargo.toml b/circuits/bin/config/Nargo.toml new file mode 100644 index 0000000000..03a041845f --- /dev/null +++ b/circuits/bin/config/Nargo.toml @@ -0,0 +1,8 @@ +[package] +name = "validate_secure_configs" +type = "bin" +authors = ["Gnosis Guild / Enclave"] +version = "1.0.0-beta.15" + +[dependencies] +lib = { path = "../../lib" } \ No newline at end of file diff --git a/circuits/bin/config/src/main.nr b/circuits/bin/config/src/main.nr new file mode 100644 index 0000000000..537dd8c928 --- /dev/null +++ b/circuits/bin/config/src/main.nr @@ -0,0 +1,407 @@ +// 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. + +// This circuit verifies all the configuration parameters used in the secure configs +// Only re-run if parameters change (new deployment) + +use lib::configs::secure::dkg::{ + // DKG structural parameters + N as DKG_N, L as DKG_L, + // DKG moduli + QIS as DKG_QIS, + // DKG derived values + PLAINTEXT_MODULUS as DKG_PLAINTEXT_MODULUS, Q_MOD_T as DKG_Q_MOD_T, + // Threshold moduli reference + L_THRESHOLD, QIS_THRESHOLD, + // Share encryption bounds + 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, +}; + +use lib::configs::secure::threshold::{ + // Structural parameters + N as THRESHOLD_N, L as THRESHOLD_L, PARAMS_SEARCH_N as N_PARTIES, + PARAMS_SEARCH_Z as N_CIPHERTEXTS, + // Moduli + QIS as THRESHOLD_QIS, + // Derived values + PLAINTEXT_MODULUS as THRESHOLD_PLAINTEXT_MODULUS, Q_MOD_T as THRESHOLD_Q_MOD_T, + Q_INVERSE_MOD_T as THRESHOLD_Q_INVERSE_MOD_T, + // pk_generation bounds + PK_GENERATION_EEK_BOUND, PK_GENERATION_SK_BOUND, PK_GENERATION_E_SM_BOUND, + PK_GENERATION_R1_BOUNDS, PK_GENERATION_R2_BOUNDS, PK_GENERATION_B_ENC, + // share_decryption bounds + THRESHOLD_SHARE_DECRYPTION_R1_BOUNDS, THRESHOLD_SHARE_DECRYPTION_R2_BOUNDS, + // user_data_encryption (Greco) bounds + USER_DATA_ENCRYPTION_K0IS, USER_DATA_ENCRYPTION_PK_BOUNDS, USER_DATA_ENCRYPTION_E0_BOUND, + USER_DATA_ENCRYPTION_E1_BOUND, USER_DATA_ENCRYPTION_U_BOUND, USER_DATA_ENCRYPTION_K1_LOW_BOUND, + USER_DATA_ENCRYPTION_K1_UP_BOUND, USER_DATA_ENCRYPTION_R1_LOW_BOUNDS, + USER_DATA_ENCRYPTION_R1_UP_BOUNDS, USER_DATA_ENCRYPTION_R2_BOUNDS, + USER_DATA_ENCRYPTION_P1_BOUNDS, USER_DATA_ENCRYPTION_P2_BOUNDS, +}; + +use lib::math::modulo::U128::ModU128; + +fn main() { + // DKG (BFV) Verification + verify_dkg_derived_values(); + verify_dkg_bounds(); + + // Threshold (TRBFV) Verification + verify_threshold_derived_values(); + verify_threshold_bounds(); + + // user_data_encryption Verification + verify_greco_bounds(); + + // Cross-Config Consistency + verify_cross_config_consistency(); +} + +//DKG Derived Values + +fn verify_dkg_derived_values() { + verify_dkg_q_mod_t(); +} + +// Verifies DKG: Q_MOD_T = (product of QIS) mod t +fn verify_dkg_q_mod_t() { + let t = DKG_PLAINTEXT_MODULUS; + let m = ModU128::new(t); + + let mut product: Field = 1; + for i in 0..DKG_L { + product = m.mul_mod(product, DKG_QIS[i]); + } + + assert(product == DKG_Q_MOD_T, "DKG Q_MOD_T verification failed"); +} + +//DKG Bounds + +// Verifies share_encryption bounds (Circuit 3) +fn verify_dkg_bounds() { + let n: u128 = DKG_N as u128; + let t: u128 = DKG_PLAINTEXT_MODULUS as u128; + let u_bound: u128 = SHARE_ENCRYPTION_U_BOUND as u128; + let e0_bound: u128 = SHARE_ENCRYPTION_E0_BOUND as u128; + let e1_bound: u128 = SHARE_ENCRYPTION_E1_BOUND as u128; + + // u_bound = 1 (ternary) + assert(SHARE_ENCRYPTION_U_BOUND == 1, "SHARE_ENCRYPTION_U_BOUND should be 1 for ternary"); + + // e0_bound = 20 + assert(SHARE_ENCRYPTION_E0_BOUND == 20, "SHARE_ENCRYPTION_E0_BOUND should be 20"); + + // e1_bound = 20 + assert(SHARE_ENCRYPTION_E1_BOUND == 20, "SHARE_ENCRYPTION_E1_BOUND should be 20"); + + // msg_bound = t - 1 + assert(SHARE_ENCRYPTION_MSG_BOUND as u128 == t - 1, "SHARE_ENCRYPTION_MSG_BOUND mismatch"); + + // ptxt bounds for r1 calculation + let ptxt_up_bound: u128 = (t - 1) / 2; + + // Check if t is even or odd for ptxt_low calculation + let t_is_even: bool = (t % 2) == 0; + + for i in 0..DKG_L { + let qi: u128 = DKG_QIS[i] as u128; + let qi_bound: u128 = (qi - 1) / 2; + let k0i: u128 = SHARE_ENCRYPTION_K0IS[i] as u128; + + // pk_bounds[i] = (q_i - 1) / 2 + assert( + SHARE_ENCRYPTION_PK_BOUNDS[i] as u128 == qi_bound, + "SHARE_ENCRYPTION_PK_BOUNDS mismatch", + ); + + // r2_bounds[i] = (q_i - 1) / 2 + assert( + SHARE_ENCRYPTION_R2_BOUNDS[i] as u128 == qi_bound, + "SHARE_ENCRYPTION_R2_BOUNDS mismatch", + ); + + // p2_bounds[i] = (q_i - 1) / 2 + assert( + SHARE_ENCRYPTION_P2_BOUNDS[i] as u128 == qi_bound, + "SHARE_ENCRYPTION_P2_BOUNDS mismatch", + ); + + // p1_bounds[i] = ((n * u_bound + 2) * qi_bound + e1_bound) / q_i + let expected_p1: u128 = ((n * u_bound + 2) * qi_bound + e1_bound) / qi; + assert( + SHARE_ENCRYPTION_P1_BOUNDS[i] as u128 == expected_p1, + "SHARE_ENCRYPTION_P1_BOUNDS mismatch", + ); + + // k0is[i] verification: k0i * t = -1 mod q_i + let m = ModU128::new(DKG_QIS[i]); + let product = m.mul_mod(SHARE_ENCRYPTION_K0IS[i], DKG_PLAINTEXT_MODULUS); + let neg_one = DKG_QIS[i] - 1; + assert(product == neg_one, "SHARE_ENCRYPTION_K0IS mismatch"); + + // e0_bound mod qi for r1 calculation + let e0_bound_i: u128 = e0_bound % qi; + + // r1_up_bounds[i] = (ptxt_up * k0i + ((n * u + 2) * qi_bound + e0_i)) / q_i + let expected_r1_up: u128 = + (ptxt_up_bound * k0i + ((n * u_bound + 2) * qi_bound + e0_bound_i)) / qi; + assert( + SHARE_ENCRYPTION_R1_UP_BOUNDS[i] as u128 == expected_r1_up, + "SHARE_ENCRYPTION_R1_UP_BOUNDS mismatch", + ); + + // r1_low_bounds[i] depends on whether t is even or odd + let expected_r1_low: u128 = if t_is_even { + ((ptxt_up_bound + 1) * k0i + ((n * u_bound + 2) * qi_bound + e0_bound_i)) / qi + } else { + expected_r1_up + }; + assert( + SHARE_ENCRYPTION_R1_LOW_BOUNDS[i] as u128 == expected_r1_low, + "SHARE_ENCRYPTION_R1_LOW_BOUNDS mismatch", + ); + } +} + +//Threshold Derived Values + +fn verify_threshold_derived_values() { + verify_threshold_q_mod_t(); + verify_threshold_q_inverse_mod_t(); +} + +// Verifies Threshold: Q_MOD_T = (product of QIS) mod t +fn verify_threshold_q_mod_t() { + let t = THRESHOLD_PLAINTEXT_MODULUS; + let m = ModU128::new(t); + + let mut product: Field = 1; + for i in 0..THRESHOLD_L { + product = m.mul_mod(product, THRESHOLD_QIS[i]); + } + + assert(product == THRESHOLD_Q_MOD_T, "Threshold Q_MOD_T verification failed"); +} + +// Verifies Threshold: Q * Q_INVERSE_MOD_T = 1 mod t +fn verify_threshold_q_inverse_mod_t() { + let t = THRESHOLD_PLAINTEXT_MODULUS; + let m = ModU128::new(t); + + let product = m.mul_mod(THRESHOLD_Q_MOD_T, THRESHOLD_Q_INVERSE_MOD_T); + + assert(product == 1, "Threshold Q_INVERSE_MOD_T verification failed"); +} + +//Threshold Bounds + +fn verify_threshold_bounds() { + verify_pk_generation_bounds(); + verify_share_decryption_bounds(); +} + +// Verifies pk_generation bounds (Circuit 1) +fn verify_pk_generation_bounds() { + let n: u128 = THRESHOLD_N as u128; + let eek: u128 = PK_GENERATION_EEK_BOUND as u128; + + // sk_bound = 1 (ternary) + assert(PK_GENERATION_SK_BOUND == 1, "PK_GENERATION_SK_BOUND should be 1 for ternary"); + + // eek_bound = 20 + assert(PK_GENERATION_EEK_BOUND == 20, "PK_GENERATION_EEK_BOUND should be 20"); + + // r2_bounds and r1_bounds for each modulus + for i in 0..THRESHOLD_L { + let qi: u128 = THRESHOLD_QIS[i] as u128; + let qi_bound: u128 = (qi - 1) / 2; + + // r2_bounds[i] = (q_i - 1) / 2 + assert(PK_GENERATION_R2_BOUNDS[i] as u128 == qi_bound, "PK_GENERATION_R2_BOUNDS mismatch"); + + // r1_bounds[i] = ((n * eek_bound + 2) * qi_bound + eek_bound) / q_i + let expected_r1: u128 = ((n * eek + 2) * qi_bound + eek) / qi; + assert( + PK_GENERATION_R1_BOUNDS[i] as u128 == expected_r1, + "PK_GENERATION_R1_BOUNDS mismatch", + ); + } + + verify_e_sm_bound(); +} + +// Verifies e_sm_bound (smudging noise bound) +fn verify_e_sm_bound() { + let n: Field = THRESHOLD_N as Field; + let e_norm: Field = 20; + let b_e: Field = 20; + let sk_norm: Field = N_PARTIES as Field; + let num_ciphertexts: Field = N_CIPHERTEXTS as Field; + + // b_fresh = N * e_norm + b_enc + N * b_e * sk_norm + let b_fresh = n * e_norm + PK_GENERATION_B_ENC + n * b_e * sk_norm; + + // b_c = N_CIPHERTEXTS * (b_fresh + Q_MOD_T) + let b_c = num_ciphertexts * (b_fresh + THRESHOLD_Q_MOD_T); + + // 2^80 + let two_pow_80: Field = 0x100000000000000000000; + + // e_sm_bound = 2^80 * b_c + let expected_e_sm_bound = two_pow_80 * b_c; + + assert(expected_e_sm_bound == PK_GENERATION_E_SM_BOUND, "PK_GENERATION_E_SM_BOUND mismatch"); +} + +// Verifies share_decryption bounds (Circuit 6) +fn verify_share_decryption_bounds() { + let n: u128 = THRESHOLD_N as u128; + + for i in 0..THRESHOLD_L { + let qi: u128 = THRESHOLD_QIS[i] as u128; + let qi_bound: u128 = (qi - 1) / 2; + + // r2_bounds[i] = (q_i - 1) / 2 + assert( + THRESHOLD_SHARE_DECRYPTION_R2_BOUNDS[i] as u128 == qi_bound, + "SHARE_DECRYPTION_R2_BOUNDS mismatch", + ); + + // r1_bounds[i] = (qi_bound * (qi_bound * n + 3) - qi_bound) / q_i + let expected_r1: u128 = (qi_bound * (qi_bound * n + 3) - qi_bound) / qi; + assert( + THRESHOLD_SHARE_DECRYPTION_R1_BOUNDS[i] as u128 == expected_r1, + "SHARE_DECRYPTION_R1_BOUNDS mismatch", + ); + } +} + +//user_data_encryption Bounds + +// Verifies user_data_encryption (Greco) bounds +// Uses THRESHOLD parameters +fn verify_greco_bounds() { + let n: u128 = THRESHOLD_N as u128; + let t: u128 = THRESHOLD_PLAINTEXT_MODULUS as u128; + let u_bound: u128 = USER_DATA_ENCRYPTION_U_BOUND as u128; + let e1_bound: u128 = USER_DATA_ENCRYPTION_E1_BOUND as u128; + + // u_bound = 1 (ternary) + assert(USER_DATA_ENCRYPTION_U_BOUND == 1, "USER_DATA_ENCRYPTION_U_BOUND should be 1"); + + // e1_bound = 20 (variance * 2) + assert(USER_DATA_ENCRYPTION_E1_BOUND == 20, "USER_DATA_ENCRYPTION_E1_BOUND should be 20"); + + // e0_bound = sqrt(3 * error1_variance) = PK_GENERATION_B_ENC (same parameter set) + assert( + USER_DATA_ENCRYPTION_E0_BOUND == PK_GENERATION_B_ENC, + "USER_DATA_ENCRYPTION_E0_BOUND should equal PK_GENERATION_B_ENC", + ); + + // k1_up_bound = (t - 1) / 2 = 49 + let expected_k1_up: u128 = (t - 1) / 2; + assert( + USER_DATA_ENCRYPTION_K1_UP_BOUND as u128 == expected_k1_up, + "USER_DATA_ENCRYPTION_K1_UP_BOUND mismatch", + ); + + // k1_low_bound = (t - 1) / 2 + 1 = 50 (for even t) + let t_is_even: bool = (t % 2) == 0; + let expected_k1_low: u128 = if t_is_even { + expected_k1_up + 1 + } else { + expected_k1_up + }; + assert( + USER_DATA_ENCRYPTION_K1_LOW_BOUND as u128 == expected_k1_low, + "USER_DATA_ENCRYPTION_K1_LOW_BOUND mismatch", + ); + + // ptxt_up_bound for r1 calculations + let ptxt_up_bound: u128 = (t - 1) / 2; + + for i in 0..THRESHOLD_L { + let qi: u128 = THRESHOLD_QIS[i] as u128; + let qi_bound: u128 = (qi - 1) / 2; + let k0i: u128 = USER_DATA_ENCRYPTION_K0IS[i] as u128; + + // pk_bounds[i] = (q_i - 1) / 2 + assert( + USER_DATA_ENCRYPTION_PK_BOUNDS[i] as u128 == qi_bound, + "USER_DATA_ENCRYPTION_PK_BOUNDS mismatch", + ); + + // r2_bounds[i] = (q_i - 1) / 2 + assert( + USER_DATA_ENCRYPTION_R2_BOUNDS[i] as u128 == qi_bound, + "USER_DATA_ENCRYPTION_R2_BOUNDS mismatch", + ); + + // p2_bounds[i] = (q_i - 1) / 2 + assert( + USER_DATA_ENCRYPTION_P2_BOUNDS[i] as u128 == qi_bound, + "USER_DATA_ENCRYPTION_P2_BOUNDS mismatch", + ); + + // p1_bounds[i] = ((n * u_bound + 2) * qi_bound + e1_bound) / q_i + let expected_p1: u128 = ((n * u_bound + 2) * qi_bound + e1_bound) / qi; + assert( + USER_DATA_ENCRYPTION_P1_BOUNDS[i] as u128 == expected_p1, + "USER_DATA_ENCRYPTION_P1_BOUNDS mismatch", + ); + + // k0is[i] verification: k0i * t = -1 mod q_i + let m = ModU128::new(THRESHOLD_QIS[i]); + let product = m.mul_mod(USER_DATA_ENCRYPTION_K0IS[i], THRESHOLD_PLAINTEXT_MODULUS); + let neg_one = THRESHOLD_QIS[i] - 1; + assert(product == neg_one, "USER_DATA_ENCRYPTION_K0IS mismatch"); + + // e0_bound mod qi for r1 calculation + // Use Field arithmetic since e0_bound is ~107 bits + let e0_bound_i: u128 = (USER_DATA_ENCRYPTION_E0_BOUND as u128) % qi; + + // r1_up_bounds[i] = (ptxt_up * k0i + ((n * u + 2) * qi_bound + e0_i)) / q_i + let expected_r1_up: u128 = + (ptxt_up_bound * k0i + ((n * u_bound + 2) * qi_bound + e0_bound_i)) / qi; + assert( + USER_DATA_ENCRYPTION_R1_UP_BOUNDS[i] as u128 == expected_r1_up, + "USER_DATA_ENCRYPTION_R1_UP_BOUNDS mismatch", + ); + + // r1_low_bounds[i] for even t + let expected_r1_low: u128 = if t_is_even { + ((ptxt_up_bound + 1) * k0i + ((n * u_bound + 2) * qi_bound + e0_bound_i)) / qi + } else { + expected_r1_up + }; + assert( + USER_DATA_ENCRYPTION_R1_LOW_BOUNDS[i] as u128 == expected_r1_low, + "USER_DATA_ENCRYPTION_R1_LOW_BOUNDS mismatch", + ); + } +} + +//Cross-Config Consistency + +fn verify_cross_config_consistency() { + // N is consistent + assert(DKG_N == THRESHOLD_N, "N mismatch between DKG and Threshold configs"); + + // L_THRESHOLD in dkg.nr matches L in threshold.nr + assert(L_THRESHOLD == THRESHOLD_L, "L_THRESHOLD mismatch between config files"); + + // QIS_THRESHOLD in dkg.nr matches QIS in threshold.nr + for i in 0..THRESHOLD_L { + assert( + QIS_THRESHOLD[i] == THRESHOLD_QIS[i], + "QIS_THRESHOLD mismatch between dkg.nr and threshold.nr", + ); + } +} diff --git a/circuits/lib/src/configs/insecure/threshold.nr b/circuits/lib/src/configs/insecure/threshold.nr index 5c3260b4ea..55e488edcf 100644 --- a/circuits/lib/src/configs/insecure/threshold.nr +++ b/circuits/lib/src/configs/insecure/threshold.nr @@ -37,6 +37,8 @@ pub global PK_GENERATION_E_SM_BOUND: Field = 12307200; pub global PK_GENERATION_R1_BOUNDS: [Field; L] = [5120, 5120]; pub global PK_GENERATION_R2_BOUNDS: [Field; L] = [34359701504, 34359615488]; +pub global PK_GENERATION_B_ENC: Field = 3; + pub global PK_GENERATION_CONFIGS: PkGenerationConfigs = PkGenerationConfigs::new( QIS, PK_GENERATION_EEK_BOUND, @@ -87,7 +89,6 @@ pub global USER_DATA_ENCRYPTION_P1_BOUNDS: [Field; L] = [256, 256]; pub global USER_DATA_ENCRYPTION_P2_BOUNDS: [Field; L] = [34359701504, 34359615488]; pub global USER_DATA_ENCRYPTION_CONFIGS: UserDataEncryptionConfigs = UserDataEncryptionConfigs::new( - Q_MOD_T, QIS, USER_DATA_ENCRYPTION_K0IS, USER_DATA_ENCRYPTION_PK_BOUNDS, diff --git a/circuits/lib/src/configs/secure/threshold.nr b/circuits/lib/src/configs/secure/threshold.nr index c08510d2a1..6c6e153b4e 100644 --- a/circuits/lib/src/configs/secure/threshold.nr +++ b/circuits/lib/src/configs/secure/threshold.nr @@ -10,6 +10,12 @@ use crate::core::threshold::pk_generation::Configs as PkGenerationConfigs; use crate::core::threshold::share_decryption::Configs as ShareDecryptionConfigs; use crate::core::threshold::user_data_encryption::Configs as UserDataEncryptionConfigs; +/// Threshold BFV parameter set search defaults configurations. +/// These are for the SecureThreshold8192 preset. +/// The InsecureThreshold512 preset has been generated manually. +pub global PARAMS_SEARCH_N: Field = 100; +pub global PARAMS_SEARCH_Z: Field = 100; + // Global configs for threshold secure preset pub global N: u32 = 8192; pub global L: u32 = 4; @@ -35,11 +41,13 @@ pub global PK_GENERATION_BIT_PK: u32 = 52; pub global PK_GENERATION_EEK_BOUND: Field = 20; pub global PK_GENERATION_SK_BOUND: Field = 1; pub global PK_GENERATION_E_SM_BOUND: Field = - 4789048565205902682369834578696752269343944643454802329600; + 4789048565205902682369836460365611983121962490123622809600; pub global PK_GENERATION_R1_BOUNDS: [Field; L] = [81920, 81920, 81920, 81920]; pub global PK_GENERATION_R2_BOUNDS: [Field; L] = [1125899911102464, 2251799813881856, 2251799815716864, 2251799817289728]; +pub global PK_GENERATION_B_ENC: Field = 39614081257132168796771975168000; + pub global PK_GENERATION_CONFIGS: PkGenerationConfigs = PkGenerationConfigs::new( QIS, PK_GENERATION_EEK_BOUND, @@ -56,7 +64,6 @@ pk_aggregation (CIRCUIT 5) ************************************/ pub global PK_AGGREGATION_BIT_PK: u32 = 52; - pub global PK_AGGREGATION_CONFIGS: PkAggregationConfigs = PkAggregationConfigs::new(QIS); /************************************ @@ -94,7 +101,6 @@ pub global USER_DATA_ENCRYPTION_P2_BOUNDS: [Field; L] = [1125899911102464, 2251799813881856, 2251799815716864, 2251799817289728]; pub global USER_DATA_ENCRYPTION_CONFIGS: UserDataEncryptionConfigs = UserDataEncryptionConfigs::new( - Q_MOD_T, QIS, USER_DATA_ENCRYPTION_K0IS, USER_DATA_ENCRYPTION_PK_BOUNDS, diff --git a/circuits/lib/src/core/threshold/share_decryption.nr b/circuits/lib/src/core/threshold/share_decryption.nr index 2f838f0ebc..74c579f672 100644 --- a/circuits/lib/src/core/threshold/share_decryption.nr +++ b/circuits/lib/src/core/threshold/share_decryption.nr @@ -31,7 +31,7 @@ impl Configs { /// Verifies: /// 1. Commitment to sk matches expected (from DKG decryption circuit) /// 2. Commitment to e_sm matches expected (from DKG decryption circuit) -/// 3. Correct computation: d = c_0 + c_1 * s + e + r_2 * (X^N + 1) + r_1 * q_i +/// 3. Correct computation: d_i = c_0i + c_1i * s_i + e_i + r_2i * (X^N + 1) + r_1i * q_i pub struct ShareDecryption { /// Circuit parameters including bounds and cryptographic constants configs: Configs, @@ -126,7 +126,7 @@ impl( - self.configs.r2_bounds[basis_idx], - self.configs.r2_bounds[basis_idx], - ); - self.e_sm[basis_idx].range_check_2bounds::( - self.configs.r2_bounds[basis_idx], - self.configs.r2_bounds[basis_idx], - ); - } - // Check quotient polynomials are within bounds for basis_idx in 0..L { // r_1 quotients can be negative (modulus quotients) @@ -220,7 +210,7 @@ impl { /// CRT moduli: [q_0, q_1, ..., q_{L-1}] pub qis: [Field; L], - /// Plaintext modulus: q mod t - pub q_mod_t: Field, /// Scaling factors for each basis: [k0_0, k0_1, ..., k0_{L-1}] pub k0is: [Field; L], /// Bounds for public key polynomials for each CRT basis @@ -42,7 +40,6 @@ pub struct Configs { impl Configs { pub fn new( - q_mod_t: Field, qis: [Field; L], k0is: [Field; L], pk_bounds: [Field; L], @@ -59,7 +56,6 @@ impl Configs { ) -> Self { Configs { qis, - q_mod_t, k0is, pk_bounds, e0_bound, diff --git a/crates/fhe-params/src/constants.rs b/crates/fhe-params/src/constants.rs index d072259df0..3671a039cb 100644 --- a/crates/fhe-params/src/constants.rs +++ b/crates/fhe-params/src/constants.rs @@ -12,7 +12,7 @@ /// Insecure preset constants (degree 512) - DO NOT USE IN PRODUCTION pub mod insecure_512 { pub const DEGREE: usize = 512; - pub const NUM_PARTIES: u128 = 5; + pub const NUM_PARTIES: u128 = 5; // fake - not used in the search default /// Threshold BFV parameters pub mod threshold { @@ -34,7 +34,7 @@ pub mod insecure_512 { /// Secure preset constants (degree 8192) - PRODUCTION READY pub mod secure_8192 { pub const DEGREE: usize = 8192; - pub const NUM_PARTIES: u128 = 100; + pub const NUM_PARTIES: u128 = 100; // real - used in the search default /// Threshold BFV parameters pub mod threshold { 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 503b8db454..b49ad195ba 100644 --- a/crates/zk-helpers/src/circuits/dkg/share_encryption/computation.rs +++ b/crates/zk-helpers/src/circuits/dkg/share_encryption/computation.rs @@ -17,8 +17,7 @@ use std::ops::Deref; use crate::dkg::share_encryption::ShareEncryptionCircuit; use crate::dkg::share_encryption::ShareEncryptionCircuitData; -use crate::get_zkp_modulus; -use crate::math::{compute_k0is, compute_q_mod_t, compute_q_product}; +use crate::math::{compute_k0is, compute_q_mod_t_centered}; use crate::math::{cyclotomic_polynomial, decompose_residue}; use crate::polynomial_to_toml_json; use crate::utils::{compute_modulus_bit, compute_msg_bit}; @@ -27,8 +26,8 @@ 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::CrtPolynomial; use e3_polynomial::Polynomial; -use e3_polynomial::{center, reduce, CrtPolynomial}; use fhe::bfv::SecretKey; use fhe_math::zq::Modulus; use itertools::izip; @@ -75,7 +74,7 @@ impl CircuitComputation for ShareEncryptionCircuit { pub struct Configs { /// Plaintext modulus (as usize). pub t: usize, - /// [q]_t reduced to ZKP field modulus. + /// centered [q]_t reduced to ZKP field modulus. pub q_mod_t: BigInt, /// CRT moduli (one per limb). pub moduli: Vec, @@ -150,23 +149,17 @@ impl Computation for Configs { build_pair_for_preset(preset).map_err(|e| CircuitsErrors::Sample(e.to_string()))?; let moduli = dkg_params.moduli().to_vec(); - let plaintext = dkg_params.plaintext(); - let q = compute_q_product(&moduli); - let q_mod_t_uint = compute_q_mod_t(&q, plaintext); - let t = BigInt::from(plaintext); - let p = get_zkp_modulus(); - - let q_mod_t = center(&BigInt::from(q_mod_t_uint), &t); - let q_mod_t_mod_p = reduce(&q_mod_t, &p); + let t = dkg_params.plaintext(); + let q_mod_t = compute_q_mod_t_centered(&moduli, t); - let k0is = compute_k0is(&moduli, plaintext)?; + let k0is = compute_k0is(&moduli, t)?; let bounds = Bounds::compute(preset, data)?; let bits = Bits::compute(preset, &bounds)?; Ok(Configs { - t: plaintext as usize, - q_mod_t: q_mod_t_mod_p, + t: t as usize, + q_mod_t, moduli, k0is, bits, diff --git a/crates/zk-helpers/src/circuits/threshold/decrypted_shares_aggregation/codegen.rs b/crates/zk-helpers/src/circuits/threshold/decrypted_shares_aggregation/codegen.rs index 6386fec5c2..b886f418b8 100644 --- a/crates/zk-helpers/src/circuits/threshold/decrypted_shares_aggregation/codegen.rs +++ b/crates/zk-helpers/src/circuits/threshold/decrypted_shares_aggregation/codegen.rs @@ -61,6 +61,7 @@ pub fn generate_configs(_preset: BfvPreset, configs: &Configs) -> CodegenConfigs pub global L: u32 = {}; pub global QIS: [Field; L] = [{}]; pub global PLAINTEXT_MODULUS: Field = {}; +pub global Q_MOD_T: Field = {}; pub global Q_INVERSE_MOD_T: Field = {}; /************************************ @@ -77,6 +78,7 @@ pub global {}_CONFIGS: DecryptedSharesAggregationConfigs = configs.l, qis_str, configs.plaintext_modulus, + configs.q_mod_t, configs.q_inverse_mod_t, prefix, configs.bits.noise_bit, diff --git a/crates/zk-helpers/src/circuits/threshold/decrypted_shares_aggregation/computation.rs b/crates/zk-helpers/src/circuits/threshold/decrypted_shares_aggregation/computation.rs index 22130f3802..35dc1d1dfa 100644 --- a/crates/zk-helpers/src/circuits/threshold/decrypted_shares_aggregation/computation.rs +++ b/crates/zk-helpers/src/circuits/threshold/decrypted_shares_aggregation/computation.rs @@ -12,6 +12,7 @@ //! [0, zkp_modulus) with [`e3_polynomial::reduce`] inside [`Inputs::compute`]. use crate::calculate_bit_width; +use crate::compute_q_mod_t_centered; use crate::get_zkp_modulus; use crate::threshold::decrypted_shares_aggregation::circuit::DecryptedSharesAggregationCircuit; use crate::threshold::decrypted_shares_aggregation::circuit::DecryptedSharesAggregationCircuitData; @@ -26,7 +27,6 @@ use fhe_math::rq::{Poly, Representation}; use num_bigint::{BigInt, BigUint}; use num_traits::Zero; use serde::{Deserialize, Serialize}; - /// Output of [`CircuitComputation::compute`] for [`DecryptedSharesAggregationCircuit`]. #[derive(Debug)] pub struct DecryptedSharesAggregationComputationOutput { @@ -74,6 +74,7 @@ pub struct Configs { pub threshold: usize, pub moduli: Vec, pub plaintext_modulus: u64, + pub q_mod_t: BigInt, pub q_inverse_mod_t: u64, pub bits: Bits, pub bounds: Bounds, @@ -136,6 +137,7 @@ impl Computation for Configs { build_pair_for_preset(preset).map_err(|e| CircuitsErrors::Other(e.to_string()))?; let moduli = threshold_params.moduli().to_vec(); let t = threshold_params.plaintext(); + let q_mod_t = compute_q_mod_t_centered(&moduli, t); let q = utils::compute_q_product(&moduli); let q_inverse_mod_t = utils::compute_q_inverse_mod_t(&q, t)?; let bounds = Bounds::compute(preset, &())?; @@ -145,6 +147,7 @@ impl Computation for Configs { l: moduli.len(), moduli, plaintext_modulus: t, + q_mod_t, q_inverse_mod_t, bits, bounds, diff --git a/crates/zk-helpers/src/circuits/threshold/pk_generation/codegen.rs b/crates/zk-helpers/src/circuits/threshold/pk_generation/codegen.rs index 4ab79196ca..3179a0e13d 100644 --- a/crates/zk-helpers/src/circuits/threshold/pk_generation/codegen.rs +++ b/crates/zk-helpers/src/circuits/threshold/pk_generation/codegen.rs @@ -17,6 +17,7 @@ use crate::CircuitCodegen; use crate::CircuitsErrors; use crate::{Artifacts, CodegenToml}; use crate::{Circuit, CodegenConfigs}; +use num_bigint::BigUint; /// Implementation of [`CircuitCodegen`] for [`PkGenerationCircuit`]. impl CircuitCodegen for PkGenerationCircuit { @@ -26,7 +27,7 @@ impl CircuitCodegen for PkGenerationCircuit { fn codegen(&self, preset: Self::Preset, data: &Self::Data) -> Result { let inputs = Inputs::compute(preset, data)?; - let configs = Configs::compute(preset, &data.committee)?; + let configs = Configs::compute(preset, &())?; let toml = generate_toml(inputs)?; let configs = generate_configs(preset, &configs); @@ -41,7 +42,7 @@ pub fn generate_toml(inputs: Inputs) -> Result { Ok(toml::to_string(&json)?) } -pub fn generate_configs(_preset: BfvPreset, configs: &Configs) -> CodegenConfigs { +pub fn generate_configs(preset: BfvPreset, configs: &Configs) -> CodegenConfigs { let prefix = ::PREFIX; let qis_str = join_display(&configs.moduli, ", "); @@ -49,6 +50,11 @@ pub fn generate_configs(_preset: BfvPreset, configs: &Configs) -> CodegenConfigs let r1_bounds_str = join_display(&configs.bounds.r1_bounds, ", "); let r2_bounds_str = join_display(&configs.bounds.r2_bounds, ", "); + let (threshold_params, _) = preset.build_pair().unwrap(); + + // B_enc ≈ sqrt(3 * error1_variance) + let b_enc = (BigUint::from(3u32) * threshold_params.get_error1_variance()).sqrt(); + format!( r#"use crate::core::threshold::pk_generation::Configs as PkGenerationConfigs; @@ -76,6 +82,8 @@ pub global {}_E_SM_BOUND: Field = {}; pub global {}_R1_BOUNDS: [Field; L] = [{}]; pub global {}_R2_BOUNDS: [Field; L] = [{}]; +pub global {}_B_ENC: Field = {}; + pub global {}_CONFIGS: PkGenerationConfigs = PkGenerationConfigs::new( QIS, {}_EEK_BOUND, @@ -111,6 +119,8 @@ QIS, prefix, r2_bounds_str, prefix, + b_enc, + prefix, prefix, prefix, prefix, @@ -175,7 +185,7 @@ mod tests { assert!(configs_path.exists()); let configs_content = std::fs::read_to_string(&configs_path).unwrap(); - let bounds = Bounds::compute(BfvPreset::InsecureThreshold512, &sample.committee).unwrap(); + let bounds = Bounds::compute(BfvPreset::InsecureThreshold512, &()).unwrap(); let bits = Bits::compute(BfvPreset::InsecureThreshold512, &bounds).unwrap(); assert!(configs_content.contains( diff --git a/crates/zk-helpers/src/circuits/threshold/pk_generation/computation.rs b/crates/zk-helpers/src/circuits/threshold/pk_generation/computation.rs index f9b4ccac3b..dd587ee475 100644 --- a/crates/zk-helpers/src/circuits/threshold/pk_generation/computation.rs +++ b/crates/zk-helpers/src/circuits/threshold/pk_generation/computation.rs @@ -15,7 +15,6 @@ use crate::math::{cyclotomic_polynomial, decompose_residue}; use crate::polynomial_to_toml_json; use crate::threshold::pk_generation::circuit::PkGenerationCircuit; use crate::threshold::pk_generation::circuit::PkGenerationCircuitData; -use crate::CiphernodesCommittee; use crate::CircuitsErrors; use crate::{CircuitComputation, Computation}; use e3_fhe_params::build_pair_for_preset; @@ -49,7 +48,7 @@ impl CircuitComputation for PkGenerationCircuit { type Error = CircuitsErrors; fn compute(preset: Self::Preset, data: &Self::Data) -> Result { - let bounds = Bounds::compute(preset, &data.committee)?; + let bounds = Bounds::compute(preset, &())?; let bits = Bits::compute(preset, &bounds)?; let inputs = Inputs::compute(preset, data)?; @@ -104,16 +103,16 @@ pub struct Inputs { impl Computation for Configs { type Preset = BfvPreset; - type Data = CiphernodesCommittee; + type Data = (); type Error = CircuitsErrors; - fn compute(preset: Self::Preset, data: &Self::Data) -> Result { + fn compute(preset: Self::Preset, _: &Self::Data) -> Result { let (threshold_params, _) = build_pair_for_preset(preset).map_err(|e| CircuitsErrors::Other(e.to_string()))?; let moduli = threshold_params.moduli().to_vec(); - let bounds = Bounds::compute(preset, data)?; + let bounds = Bounds::compute(preset, &())?; let bits = Bits::compute(preset, &bounds)?; Ok(Configs { @@ -163,10 +162,10 @@ impl Computation for Bits { impl Computation for Bounds { type Preset = BfvPreset; - type Data = CiphernodesCommittee; + type Data = (); type Error = CircuitsErrors; - fn compute(preset: Self::Preset, data: &Self::Data) -> Result { + fn compute(preset: Self::Preset, _: &Self::Data) -> Result { let (threshold_params, _) = build_pair_for_preset(preset).map_err(|e| CircuitsErrors::Other(e.to_string()))?; @@ -178,15 +177,14 @@ impl Computation for Bounds { let sk_bound = SecretKey::sk_bound(); let eek_bound = cbd_bound; - let defaults = preset + let sd = preset .search_defaults() .ok_or_else(|| CircuitsErrors::Other("missing search defaults".to_string()))?; - let num_ciphertexts = defaults.z; let smudging_config = SmudgingBoundCalculatorConfig::new( threshold_params.clone(), - data.n, - num_ciphertexts as usize, + sd.n as usize, + sd.z as usize, preset.metadata().lambda, ); let smudging_calculator = SmudgingBoundCalculator::new(smudging_config); @@ -373,16 +371,12 @@ impl Computation for Inputs { #[cfg(test)] mod tests { - use crate::CiphernodesCommitteeSize; - use super::*; - use e3_fhe_params::BfvPreset; #[test] fn test_bound_and_bits_computation_consistency() { - let committee = CiphernodesCommitteeSize::Small.values(); - let bounds = Bounds::compute(BfvPreset::InsecureThreshold512, &committee).unwrap(); + let bounds = Bounds::compute(BfvPreset::InsecureThreshold512, &()).unwrap(); let bits = Bits::compute(BfvPreset::InsecureThreshold512, &bounds).unwrap(); let expected_bit = calculate_bit_width(BigInt::from(bounds.pk_bound.clone())); @@ -392,8 +386,7 @@ mod tests { #[test] fn test_constants_json_roundtrip() { - let committee = CiphernodesCommitteeSize::Small.values(); - let constants = Configs::compute(BfvPreset::InsecureThreshold512, &committee).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/codegen.rs b/crates/zk-helpers/src/circuits/threshold/user_data_encryption/codegen.rs index 6e5ad0dd2d..dea7e3832b 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 @@ -62,7 +62,7 @@ pub fn generate_toml(inputs: Inputs) -> Result { Ok(toml::to_string(&json)?) } -pub fn generate_configs(_preset: BfvPreset, configs: &Configs) -> CodegenConfigs { +pub fn generate_configs(_: BfvPreset, configs: &Configs) -> CodegenConfigs { let prefix = ::PREFIX; let qis_str = join_display(&configs.moduli, ", "); @@ -81,7 +81,6 @@ pub fn generate_configs(_preset: BfvPreset, configs: &Configs) -> CodegenConfigs pub global N: u32 = {}; pub global L: u32 = {}; pub global QIS: [Field; L] = [{}]; -pub global Q_MOD_T: Field = {}; /************************************ ------------------------------------- @@ -114,7 +113,6 @@ pub global {}_P1_BOUNDS: [Field; L] = [{}]; pub global {}_P2_BOUNDS: [Field; L] = [{}]; pub global {}_CONFIGS: UserDataEncryptionConfigs = UserDataEncryptionConfigs::new( - Q_MOD_T, QIS, {}_K0IS, {}_PK_BOUNDS, @@ -130,10 +128,9 @@ pub global {}_CONFIGS: UserDataEncryptionConfigs = UserDataEncryptionConfi {}_K1_UP_BOUND ); "#, - configs.n, // N - configs.l, // L - qis_str, // QIS array - configs.q_mod_t, // Q_MOD_T + configs.n, // N + configs.l, // L + qis_str, // QIS array prefix, configs.bits.pk_bit, // BIT_PK prefix, 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 733cb66c2a..a1033bf78e 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 @@ -13,7 +13,7 @@ use crate::calculate_bit_width; use crate::commitments::compute_pk_aggregation_commitment; use crate::compute_ciphertext_commitment; use crate::get_zkp_modulus; -use crate::math::{compute_k0is, compute_q_mod_t, compute_q_product}; +use crate::math::compute_k0is; use crate::math::{cyclotomic_polynomial, decompose_residue}; use crate::threshold::user_data_encryption::circuit::UserDataEncryptionCircuit; use crate::threshold::user_data_encryption::circuit::UserDataEncryptionCircuitData; @@ -22,7 +22,6 @@ use crate::CircuitsErrors; use crate::{CircuitComputation, Computation}; use e3_fhe_params::build_pair_for_preset; use e3_fhe_params::BfvPreset; -use e3_polynomial::center; use e3_polynomial::CrtPolynomial; use e3_polynomial::Polynomial; use fhe::bfv::SecretKey; @@ -73,7 +72,6 @@ pub struct Configs { pub n: usize, pub l: usize, pub moduli: Vec, - pub q_mod_t: BigInt, pub k0is: Vec, pub bits: Bits, pub bounds: Bounds, @@ -139,13 +137,6 @@ impl Computation for Configs { build_pair_for_preset(preset).map_err(|e| CircuitsErrors::Sample(e.to_string()))?; let moduli = threshold_params.moduli().to_vec(); - let plaintext = threshold_params.plaintext(); - let q = compute_q_product(&moduli); - let q_mod_t_uint = compute_q_mod_t(&q, plaintext); - let t = BigInt::from(plaintext); - - let q_mod_t = center(&BigInt::from(q_mod_t_uint), &t); - let k0is = compute_k0is(threshold_params.moduli(), threshold_params.plaintext())?; let bounds = Bounds::compute(preset, &())?; @@ -154,7 +145,6 @@ impl Computation for Configs { Ok(Configs { n: threshold_params.degree(), l: moduli.len(), - q_mod_t, k0is, moduli, bits, diff --git a/crates/zk-helpers/src/math.rs b/crates/zk-helpers/src/math.rs index 31aa0f2471..c8741dd5d2 100644 --- a/crates/zk-helpers/src/math.rs +++ b/crates/zk-helpers/src/math.rs @@ -8,6 +8,7 @@ //! CRT operations (k0is, FHE poly to CRT), and polynomial ring (cyclotomic, residue decomposition). use crate::CircuitsErrors; +use e3_polynomial::center; use e3_polynomial::{CrtPolynomial, CrtPolynomialError, Polynomial}; use fhe_math::rq::Poly; use fhe_math::zq::Modulus; @@ -66,6 +67,15 @@ pub fn compute_q_mod_t(q: &BigUint, t: u64) -> BigUint { q % BigUint::from(t) } +/// Q mod t in centered form [-t/2, t/2], given CRT moduli and plaintext modulus t. +/// Use with threshold or DKG params via `params.moduli()` and `params.plaintext()`. +pub fn compute_q_mod_t_centered(moduli: &[u64], t: u64) -> BigInt { + let q = compute_q_product(moduli); + let q_mod_t_uint = compute_q_mod_t(&q, t); + let t_bn = BigInt::from(t); + center(&BigInt::from(q_mod_t_uint), &t_bn) +} + /// t^{-1} mod Q (for CRT / scaling). Fails if gcd(Q, t) != 1. pub fn compute_t_inv_mod_q(q: &BigUint, t: u64) -> Result { let q_bigint = BigInt::from(q.clone()); diff --git a/scripts/lint-circuits.sh b/scripts/lint-circuits.sh index 61f7ee455a..481128f50e 100755 --- a/scripts/lint-circuits.sh +++ b/scripts/lint-circuits.sh @@ -11,7 +11,7 @@ fi cd circuits # Directories to check -DIRS=("lib" "bin/recursive_aggregation/fold" "bin/recursive_aggregation/wrapper/dkg" "bin/recursive_aggregation/wrapper/threshold" "bin/dkg" "bin/threshold") +DIRS=("lib" "bin/config" "bin/recursive_aggregation/fold" "bin/recursive_aggregation/wrapper/dkg" "bin/recursive_aggregation/wrapper/threshold" "bin/dkg" "bin/threshold") for dir in "${DIRS[@]}"; do if [ ! -d "$dir" ]; then