diff --git a/circuits/benchmarks/config.json b/circuits/benchmarks/config.json index dfd1bb7a4a..51da1adbb4 100644 --- a/circuits/benchmarks/config.json +++ b/circuits/benchmarks/config.json @@ -3,10 +3,8 @@ "dkg/pk", "dkg/sk_share_computation", "dkg/e_sm_share_computation", - "dkg/sk_share_encryption", - "dkg/e_sm_share_encryption", - "dkg/sk_share_decryption", - "dkg/e_sm_share_decryption", + "dkg/share_encryption", + "dkg/share_decryption", "threshold/user_data_encryption", "threshold/pk_generation", "threshold/pk_aggregation", diff --git a/circuits/benchmarks/results_insecure/report.md b/circuits/benchmarks/results_insecure/report.md index 1ad630899c..3dc7ee236e 100644 --- a/circuits/benchmarks/results_insecure/report.md +++ b/circuits/benchmarks/results_insecure/report.md @@ -1,9 +1,9 @@ # Enclave ZK Circuit Benchmarks -**Generated:** 2026-02-11 17:03:46 UTC +**Generated:** 2026-02-12 16:42:19 UTC -**Git Branch:** `main` -**Git Commit:** `286813a7ec2d8a0edeb34ae723bb06c38049b7af` +**Git Branch:** `refactor/input-computation` +**Git Commit:** `2b72de5d2b119a672a6da46c355db03862614ac7` --- @@ -15,25 +15,21 @@ | Circuit | Compile | Execute | Prove | Verify | | ---------------------- | ------- | ------- | ------ | ------ | -| e_sm_share_computation | 0.32 s | 0.53 s | 1.64 s | 0.03 s | -| e_sm_share_decryption | 0.28 s | 0.30 s | 0.24 s | 0.02 s | -| e_sm_share_encryption | 2.73 s | 0.45 s | 0.62 s | 0.03 s | -| pk | 0.26 s | 0.27 s | 0.12 s | 0.02 s | -| sk_share_computation | 0.33 s | 0.53 s | 1.64 s | 0.02 s | -| sk_share_decryption | 0.28 s | 0.31 s | 0.24 s | 0.02 s | -| sk_share_encryption | 2.68 s | 0.45 s | 0.63 s | 0.03 s | +| e_sm_share_computation | 0.23 s | 0.42 s | 1.71 s | 0.03 s | +| pk | 0.19 s | 0.19 s | 0.12 s | 0.02 s | +| share_decryption | 0.61 s | 0.23 s | 0.30 s | 0.03 s | +| share_encryption | 0.22 s | 0.36 s | 0.65 s | 0.03 s | +| sk_share_computation | 0.23 s | 0.42 s | 1.71 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.90 KB | 3.59 KB | 15.88 KB | -| e_sm_share_decryption | 3093 | 28.72K | 158.28 KB | 148.87 KB | 3.59 KB | 15.88 KB | -| e_sm_share_encryption | 47758 | 127.69K | 798.23 KB | 512.41 KB | 3.59 KB | 15.88 KB | -| pk | 344 | 6.85K | 87.84 KB | 29.09 KB | 3.59 KB | 15.88 KB | -| sk_share_computation | 90827 | 326.14K | 1.38 MB | 463.59 KB | 3.59 KB | 15.88 KB | -| sk_share_decryption | 3093 | 28.72K | 158.27 KB | 148.89 KB | 3.59 KB | 15.88 KB | -| sk_share_encryption | 47758 | 127.69K | 798.23 KB | 512.31 KB | 3.59 KB | 15.88 KB | +| e_sm_share_computation | 90956 | 328.74K | 1.39 MB | 477.83 KB | 3.59 KB | 15.88 KB | +| pk | 344 | 6.85K | 87.81 KB | 29.06 KB | 3.59 KB | 15.88 KB | +| share_decryption | 3093 | 28.72K | 158.24 KB | 148.90 KB | 3.59 KB | 15.88 KB | +| share_encryption | 47758 | 127.69K | 798.18 KB | 512.13 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 @@ -41,21 +37,21 @@ | Circuit | Compile | Execute | Prove | Verify | | -------------------------------- | ------- | ------- | ------ | ------ | -| decrypted_shares_aggregation_mod | 0.29 s | 0.35 s | 0.48 s | 0.03 s | -| pk_aggregation | 0.30 s | 0.46 s | 0.98 s | 0.03 s | -| pk_generation | 0.29 s | 0.39 s | 0.50 s | 0.03 s | -| share_decryption | 0.30 s | 0.43 s | 0.56 s | 0.03 s | -| user_data_encryption | 0.31 s | 0.51 s | 0.60 s | 0.02 s | +| decrypted_shares_aggregation_mod | 0.21 s | 0.25 s | 0.51 s | 0.03 s | +| pk_aggregation | 0.22 s | 0.37 s | 0.95 s | 0.03 s | +| pk_generation | 0.21 s | 0.31 s | 0.55 s | 0.03 s | +| share_decryption | 0.21 s | 0.33 s | 0.58 s | 0.03 s | +| user_data_encryption | 0.23 s | 0.40 s | 0.64 s | 0.03 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.52 KB | 3.59 KB | 15.88 KB | -| pk_aggregation | 47817 | 169.89K | 884.11 KB | 360.83 KB | 3.59 KB | 15.88 KB | -| pk_generation | 30019 | 65.61K | 542.16 KB | 447.07 KB | 3.59 KB | 15.88 KB | -| share_decryption | 30570 | 85.48K | 541.56 KB | 522.91 KB | 3.59 KB | 15.88 KB | -| user_data_encryption | 56601 | 106.72K | 847.68 KB | 691.27 KB | 3.59 KB | 15.88 KB | +| decrypted_shares_aggregation_mod | 31544 | 80.74K | 509.82 KB | 77.42 KB | 3.59 KB | 15.88 KB | +| pk_aggregation | 47817 | 169.89K | 884.07 KB | 360.64 KB | 3.59 KB | 15.88 KB | +| pk_generation | 30019 | 65.61K | 542.13 KB | 446.90 KB | 3.59 KB | 15.88 KB | +| share_decryption | 30570 | 85.48K | 541.52 KB | 522.88 KB | 3.59 KB | 15.88 KB | +| user_data_encryption | 56601 | 106.72K | 847.64 KB | 690.54 KB | 3.59 KB | 15.88 KB | ## Circuit Details @@ -65,47 +61,15 @@ | Metric | Value | | -------------------- | --------- | -| **Compilation** | 0.32 s | -| **Execution** | 0.53 s | -| **VK Generation** | 0.61 s | -| **Proof Generation** | 1.64 s | +| **Compilation** | 0.23 s | +| **Execution** | 0.42 s | +| **VK Generation** | 0.59 s | +| **Proof Generation** | 1.71 s | | **Verification** | 0.03 s | | **ACIR Opcodes** | "90956" | | **Total Gates** | "328743" | | **Circuit Size** | 1.39 MB | -| **Witness Size** | 477.90 KB | -| **VK Size** | 3.59 KB | -| **Proof Size** | 15.88 KB | - -#### e_sm_share_decryption - -| Metric | Value | -| -------------------- | --------- | -| **Compilation** | 0.28 s | -| **Execution** | 0.30 s | -| **VK Generation** | 0.09 s | -| **Proof Generation** | 0.24 s | -| **Verification** | 0.02 s | -| **ACIR Opcodes** | "3093" | -| **Total Gates** | "28720" | -| **Circuit Size** | 158.28 KB | -| **Witness Size** | 148.87 KB | -| **VK Size** | 3.59 KB | -| **Proof Size** | 15.88 KB | - -#### e_sm_share_encryption - -| Metric | Value | -| -------------------- | --------- | -| **Compilation** | 2.73 s | -| **Execution** | 0.45 s | -| **VK Generation** | 0.26 s | -| **Proof Generation** | 0.62 s | -| **Verification** | 0.03 s | -| **ACIR Opcodes** | "47758" | -| **Total Gates** | "127691" | -| **Circuit Size** | 798.23 KB | -| **Witness Size** | 512.41 KB | +| **Witness Size** | 477.83 KB | | **VK Size** | 3.59 KB | | **Proof Size** | 15.88 KB | @@ -113,63 +77,63 @@ | Metric | Value | | -------------------- | -------- | -| **Compilation** | 0.26 s | -| **Execution** | 0.27 s | +| **Compilation** | 0.19 s | +| **Execution** | 0.19 s | | **VK Generation** | 0.05 s | | **Proof Generation** | 0.12 s | | **Verification** | 0.02 s | | **ACIR Opcodes** | "344" | | **Total Gates** | "6846" | -| **Circuit Size** | 87.84 KB | -| **Witness Size** | 29.09 KB | +| **Circuit Size** | 87.81 KB | +| **Witness Size** | 29.06 KB | | **VK Size** | 3.59 KB | | **Proof Size** | 15.88 KB | -#### sk_share_computation - -| Metric | Value | -| -------------------- | --------- | -| **Compilation** | 0.33 s | -| **Execution** | 0.53 s | -| **VK Generation** | 0.61 s | -| **Proof Generation** | 1.64 s | -| **Verification** | 0.02 s | -| **ACIR Opcodes** | "90827" | -| **Total Gates** | "326138" | -| **Circuit Size** | 1.38 MB | -| **Witness Size** | 463.59 KB | -| **VK Size** | 3.59 KB | -| **Proof Size** | 15.88 KB | - -#### sk_share_decryption +#### share_decryption | Metric | Value | | -------------------- | --------- | -| **Compilation** | 0.28 s | -| **Execution** | 0.31 s | +| **Compilation** | 0.61 s | +| **Execution** | 0.23 s | | **VK Generation** | 0.09 s | -| **Proof Generation** | 0.24 s | -| **Verification** | 0.02 s | +| **Proof Generation** | 0.30 s | +| **Verification** | 0.03 s | | **ACIR Opcodes** | "3093" | | **Total Gates** | "28720" | -| **Circuit Size** | 158.27 KB | -| **Witness Size** | 148.89 KB | +| **Circuit Size** | 158.24 KB | +| **Witness Size** | 148.90 KB | | **VK Size** | 3.59 KB | | **Proof Size** | 15.88 KB | -#### sk_share_encryption +#### share_encryption | Metric | Value | | -------------------- | --------- | -| **Compilation** | 2.68 s | -| **Execution** | 0.45 s | +| **Compilation** | 0.22 s | +| **Execution** | 0.36 s | | **VK Generation** | 0.26 s | -| **Proof Generation** | 0.63 s | +| **Proof Generation** | 0.65 s | | **Verification** | 0.03 s | | **ACIR Opcodes** | "47758" | | **Total Gates** | "127691" | -| **Circuit Size** | 798.23 KB | -| **Witness Size** | 512.31 KB | +| **Circuit Size** | 798.18 KB | +| **Witness Size** | 512.13 KB | +| **VK Size** | 3.59 KB | +| **Proof Size** | 15.88 KB | + +#### sk_share_computation + +| Metric | Value | +| -------------------- | --------- | +| **Compilation** | 0.23 s | +| **Execution** | 0.42 s | +| **VK Generation** | 0.62 s | +| **Proof Generation** | 1.71 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 | @@ -179,15 +143,15 @@ | Metric | Value | | -------------------- | --------- | -| **Compilation** | 0.29 s | -| **Execution** | 0.35 s | +| **Compilation** | 0.21 s | +| **Execution** | 0.25 s | | **VK Generation** | 0.19 s | -| **Proof Generation** | 0.48 s | +| **Proof Generation** | 0.51 s | | **Verification** | 0.03 s | | **ACIR Opcodes** | "31544" | | **Total Gates** | "80740" | -| **Circuit Size** | 509.84 KB | -| **Witness Size** | 77.52 KB | +| **Circuit Size** | 509.82 KB | +| **Witness Size** | 77.42 KB | | **VK Size** | 3.59 KB | | **Proof Size** | 15.88 KB | @@ -195,15 +159,15 @@ | Metric | Value | | -------------------- | --------- | -| **Compilation** | 0.30 s | -| **Execution** | 0.46 s | +| **Compilation** | 0.22 s | +| **Execution** | 0.37 s | | **VK Generation** | 0.36 s | -| **Proof Generation** | 0.98 s | +| **Proof Generation** | 0.95 s | | **Verification** | 0.03 s | | **ACIR Opcodes** | "47817" | | **Total Gates** | "169890" | -| **Circuit Size** | 884.11 KB | -| **Witness Size** | 360.83 KB | +| **Circuit Size** | 884.07 KB | +| **Witness Size** | 360.64 KB | | **VK Size** | 3.59 KB | | **Proof Size** | 15.88 KB | @@ -211,15 +175,15 @@ | Metric | Value | | -------------------- | --------- | -| **Compilation** | 0.29 s | -| **Execution** | 0.39 s | -| **VK Generation** | 0.17 s | -| **Proof Generation** | 0.50 s | +| **Compilation** | 0.21 s | +| **Execution** | 0.31 s | +| **VK Generation** | 0.18 s | +| **Proof Generation** | 0.55 s | | **Verification** | 0.03 s | | **ACIR Opcodes** | "30019" | | **Total Gates** | "65606" | -| **Circuit Size** | 542.16 KB | -| **Witness Size** | 447.07 KB | +| **Circuit Size** | 542.13 KB | +| **Witness Size** | 446.90 KB | | **VK Size** | 3.59 KB | | **Proof Size** | 15.88 KB | @@ -227,15 +191,15 @@ | Metric | Value | | -------------------- | --------- | -| **Compilation** | 0.30 s | -| **Execution** | 0.43 s | -| **VK Generation** | 0.20 s | -| **Proof Generation** | 0.56 s | +| **Compilation** | 0.21 s | +| **Execution** | 0.33 s | +| **VK Generation** | 0.19 s | +| **Proof Generation** | 0.58 s | | **Verification** | 0.03 s | | **ACIR Opcodes** | "30570" | | **Total Gates** | "85478" | -| **Circuit Size** | 541.56 KB | -| **Witness Size** | 522.91 KB | +| **Circuit Size** | 541.52 KB | +| **Witness Size** | 522.88 KB | | **VK Size** | 3.59 KB | | **Proof Size** | 15.88 KB | @@ -243,15 +207,15 @@ | Metric | Value | | -------------------- | --------- | -| **Compilation** | 0.31 s | -| **Execution** | 0.51 s | +| **Compilation** | 0.23 s | +| **Execution** | 0.40 s | | **VK Generation** | 0.24 s | -| **Proof Generation** | 0.60 s | -| **Verification** | 0.02 s | +| **Proof Generation** | 0.64 s | +| **Verification** | 0.03 s | | **ACIR Opcodes** | "56601" | | **Total Gates** | "106725" | -| **Circuit Size** | 847.68 KB | -| **Witness Size** | 691.27 KB | +| **Circuit Size** | 847.64 KB | +| **Witness Size** | 690.54 KB | | **VK Size** | 3.59 KB | | **Proof Size** | 15.88 KB | @@ -260,8 +224,8 @@ ### Hardware - **CPU:** Apple M4 Pro -- **CPU Cores:** 14 -- **RAM:** 48.00 GB +- **CPU Cores:** 12 +- **RAM:** 24.00 GB - **OS:** Darwin - **Architecture:** arm64 diff --git a/circuits/benchmarks/scripts/generate_prover_toml.sh b/circuits/benchmarks/scripts/generate_prover_toml.sh index e4d1ad0241..7e90ea5ca9 100755 --- a/circuits/benchmarks/scripts/generate_prover_toml.sh +++ b/circuits/benchmarks/scripts/generate_prover_toml.sh @@ -47,22 +47,14 @@ get_zk_args() { echo "share-computation smudging-noise" return ;; - dkg/sk_share_encryption) + dkg/share_encryption) echo "share-encryption secret-key" return ;; - dkg/e_sm_share_encryption) - echo "share-encryption smudging-noise" - return - ;; - dkg/sk_share_decryption) + dkg/share_decryption) echo "share-decryption secret-key" return ;; - dkg/e_sm_share_decryption) - echo "share-decryption smudging-noise" - return - ;; threshold/user_data_encryption) echo "user-data-encryption" return diff --git a/circuits/bin/dkg/Nargo.toml b/circuits/bin/dkg/Nargo.toml index 416708a4b8..a99b2343e7 100644 --- a/circuits/bin/dkg/Nargo.toml +++ b/circuits/bin/dkg/Nargo.toml @@ -2,9 +2,7 @@ members = [ "pk", "sk_share_computation", - "sk_share_encryption", - "sk_share_decryption", "e_sm_share_computation", - "e_sm_share_encryption", - "e_sm_share_decryption", + "share_encryption", + "share_decryption", ] \ No newline at end of file diff --git a/circuits/bin/dkg/e_sm_share_decryption/Nargo.toml b/circuits/bin/dkg/e_sm_share_decryption/Nargo.toml deleted file mode 100644 index c7089095bd..0000000000 --- a/circuits/bin/dkg/e_sm_share_decryption/Nargo.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "e_sm_share_decryption" -type = "bin" -authors = ["Gnosis Guild / Enclave"] -version = "1.0.0-beta.15" - - -[dependencies] -lib = { path = "../../../lib" } diff --git a/circuits/bin/dkg/e_sm_share_encryption/Nargo.toml b/circuits/bin/dkg/e_sm_share_encryption/Nargo.toml deleted file mode 100644 index e9a79e2a7e..0000000000 --- a/circuits/bin/dkg/e_sm_share_encryption/Nargo.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "e_sm_share_encryption" -type = "bin" -authors = ["Gnosis Guild / Enclave"] -version = "1.0.0-beta.15" - - -[dependencies] -lib = { path = "../../../lib" } diff --git a/circuits/bin/dkg/sk_share_decryption/Nargo.toml b/circuits/bin/dkg/share_decryption/Nargo.toml similarity index 82% rename from circuits/bin/dkg/sk_share_decryption/Nargo.toml rename to circuits/bin/dkg/share_decryption/Nargo.toml index 5b7e7af577..10c7fc9cd4 100644 --- a/circuits/bin/dkg/sk_share_decryption/Nargo.toml +++ b/circuits/bin/dkg/share_decryption/Nargo.toml @@ -1,5 +1,5 @@ [package] -name = "sk_share_decryption" +name = "share_decryption" type = "bin" authors = ["Gnosis Guild / Enclave"] version = "1.0.0-beta.15" diff --git a/circuits/bin/dkg/e_sm_share_decryption/README.md b/circuits/bin/dkg/share_decryption/README.md similarity index 100% rename from circuits/bin/dkg/e_sm_share_decryption/README.md rename to circuits/bin/dkg/share_decryption/README.md diff --git a/circuits/bin/dkg/e_sm_share_decryption/src/main.nr b/circuits/bin/dkg/share_decryption/src/main.nr similarity index 100% rename from circuits/bin/dkg/e_sm_share_decryption/src/main.nr rename to circuits/bin/dkg/share_decryption/src/main.nr diff --git a/circuits/bin/dkg/sk_share_encryption/Nargo.toml b/circuits/bin/dkg/share_encryption/Nargo.toml similarity index 82% rename from circuits/bin/dkg/sk_share_encryption/Nargo.toml rename to circuits/bin/dkg/share_encryption/Nargo.toml index 34e963b18d..d9da839762 100644 --- a/circuits/bin/dkg/sk_share_encryption/Nargo.toml +++ b/circuits/bin/dkg/share_encryption/Nargo.toml @@ -1,5 +1,5 @@ [package] -name = "sk_share_encryption" +name = "share_encryption" type = "bin" authors = ["Gnosis Guild / Enclave"] version = "1.0.0-beta.15" diff --git a/circuits/bin/dkg/e_sm_share_encryption/README.md b/circuits/bin/dkg/share_encryption/README.md similarity index 100% rename from circuits/bin/dkg/e_sm_share_encryption/README.md rename to circuits/bin/dkg/share_encryption/README.md diff --git a/circuits/bin/dkg/e_sm_share_encryption/src/main.nr b/circuits/bin/dkg/share_encryption/src/main.nr similarity index 100% rename from circuits/bin/dkg/e_sm_share_encryption/src/main.nr rename to circuits/bin/dkg/share_encryption/src/main.nr diff --git a/circuits/bin/dkg/sk_share_decryption/README.md b/circuits/bin/dkg/sk_share_decryption/README.md deleted file mode 100644 index c73566b882..0000000000 --- a/circuits/bin/dkg/sk_share_decryption/README.md +++ /dev/null @@ -1 +0,0 @@ -instantiation of correct Secret Key Share Decryption circuit (PVSS #4a) diff --git a/circuits/bin/dkg/sk_share_decryption/src/main.nr b/circuits/bin/dkg/sk_share_decryption/src/main.nr deleted file mode 100644 index dc09eb6365..0000000000 --- a/circuits/bin/dkg/sk_share_decryption/src/main.nr +++ /dev/null @@ -1,20 +0,0 @@ -// 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. - -use lib::configs::default::dkg::{L_THRESHOLD, N, SHARE_DECRYPTION_BIT_MSG}; -use lib::configs::default::H; -use lib::core::dkg::share_decryption::ShareDecryption; -use lib::math::polynomial::Polynomial; - -fn main( - expected_commitments: pub [[Field; L_THRESHOLD]; H], - decrypted_shares: [[Polynomial; L_THRESHOLD]; H], -) -> pub Field { - let share_decryption: ShareDecryption = - ShareDecryption::new(expected_commitments, decrypted_shares); - - share_decryption.execute() -} diff --git a/circuits/bin/dkg/sk_share_encryption/README.md b/circuits/bin/dkg/sk_share_encryption/README.md deleted file mode 100644 index 5dfe3aa553..0000000000 --- a/circuits/bin/dkg/sk_share_encryption/README.md +++ /dev/null @@ -1 +0,0 @@ -instantiation of Secret Key Share Encryption circuit (PVSS #3a) diff --git a/circuits/bin/dkg/sk_share_encryption/src/main.nr b/circuits/bin/dkg/sk_share_encryption/src/main.nr deleted file mode 100644 index 8885a32668..0000000000 --- a/circuits/bin/dkg/sk_share_encryption/src/main.nr +++ /dev/null @@ -1,54 +0,0 @@ -// 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. - -use lib::configs::default::dkg::{ - DKG_SHARE_ENCRYPTION_BIT_CT, DKG_SHARE_ENCRYPTION_BIT_E0, DKG_SHARE_ENCRYPTION_BIT_E1, - DKG_SHARE_ENCRYPTION_BIT_MSG, DKG_SHARE_ENCRYPTION_BIT_P1, DKG_SHARE_ENCRYPTION_BIT_P2, - DKG_SHARE_ENCRYPTION_BIT_PK, DKG_SHARE_ENCRYPTION_BIT_R1, DKG_SHARE_ENCRYPTION_BIT_R2, - DKG_SHARE_ENCRYPTION_BIT_U, DKG_SHARE_ENCRYPTION_CONFIGS, L, N, -}; -use lib::core::dkg::share_encryption::ShareEncryption; -use lib::math::polynomial::Polynomial; - -fn main( - expected_pk_commitment: pub Field, - expected_message_commitment: pub Field, - pk0is: [Polynomial; L], - pk1is: [Polynomial; L], - ct0is: pub [Polynomial; L], - ct1is: pub [Polynomial; L], - u: Polynomial, - e0: Polynomial, - e0is: [Polynomial; L], - e0_quotients: [Polynomial; L], - e1: Polynomial, - message: Polynomial, - r1is: [Polynomial<(2 * N) - 1>; L], - r2is: [Polynomial; L], - p1is: [Polynomial<(2 * N) - 1>; L], - p2is: [Polynomial; L], -) { - let share_encryption: ShareEncryption = ShareEncryption::new( - DKG_SHARE_ENCRYPTION_CONFIGS, - expected_pk_commitment, - expected_message_commitment, - pk0is, - pk1is, - ct0is, - ct1is, - u, - e0, - e0is, - e0_quotients, - e1, - message, - r1is, - r2is, - p1is, - p2is, - ); - share_encryption.execute(); -} diff --git a/crates/polynomial/src/polynomial.rs b/crates/polynomial/src/polynomial.rs index 26a5879e8b..883acecf99 100644 --- a/crates/polynomial/src/polynomial.rs +++ b/crates/polynomial/src/polynomial.rs @@ -7,7 +7,8 @@ //! Polynomial arithmetic implementation. use crate::utils::{center, reduce}; -use num_bigint::BigInt; +use fhe_math::rq::{Poly, Representation}; +use num_bigint::{BigInt, BigUint, ToBigInt}; use num_traits::{One, Zero}; use std::fmt; use thiserror::Error; @@ -130,6 +131,23 @@ impl Polynomial { Self { coefficients } } + /// Creates a new polynomial from a fhe-math `Poly` (CRT-reconstructed mod Q). + pub fn from_fhe_polynomial(p: &Poly) -> Self { + let mut p = p.clone(); + + if *p.representation() == Representation::Ntt { + p.change_representation(Representation::PowerBasis); + } + + let coefficients: Vec = Vec::::from(&p); + let bigints: Vec = coefficients + .iter() + .map(|c| c.to_bigint().unwrap()) + .collect(); + + Self::new(bigints) + } + /// Reverses coefficient order in-place. /// /// **Coefficient ordering:** Converts between **descending** (highest degree first, 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 fb3265baa3..d8ee71dabb 100644 --- a/crates/zk-helpers/src/circuits/dkg/share_encryption/computation.rs +++ b/crates/zk-helpers/src/circuits/dkg/share_encryption/computation.rs @@ -30,8 +30,6 @@ 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; @@ -348,318 +346,185 @@ impl Computation for Inputs { type Data = ShareEncryptionCircuitData; type Error = CircuitsErrors; - fn compute(preset: Self::Preset, data: &Self::Data) -> Result { + fn compute(_preset: Self::Preset, data: &Self::Data) -> Result { let (_, dkg_params) = - build_pair_for_preset(preset).map_err(|e| CircuitsErrors::Sample(e.to_string()))?; - let ctx = dkg_params.ctx_at_level(data.plaintext.level())?; - - let pk_bit = compute_modulus_bit(&dkg_params); - let msg_bit = compute_msg_bit(&dkg_params); + build_pair_for_preset(_preset).map_err(|e| CircuitsErrors::Sample(e.to_string()))?; let pk = data.public_key.clone(); let pt = data.plaintext.clone(); + let ct = &data.ciphertext; + let u = &data.u_rns; + let e0 = &data.e0_rns; + let e1 = &data.e1_rns; + + let ctx = dkg_params.ctx_at_level(pt.level())?; + let moduli = dkg_params.moduli(); + + #[allow(non_snake_case)] + let modulus_q = BigInt::from(ctx.modulus().clone()); + let t = dkg_params.plaintext(); + let n = dkg_params.degree() as u64; + let q_mod_t = (&modulus_q % t) + .to_u64() + .ok_or_else(|| CircuitsErrors::Other("Failed to convert q_mod_t to u64".into()))?; + let cyclo = cyclotomic_polynomial(n); - // Reconstruct e0 in mod Q so that e0_poly row i matches e0_rns row i (same ctx). - let mut e0_power = data.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 mut e0_mod_q = Polynomial::from_fhe_polynomial(e0); + e0_mod_q.reverse(); + e0_mod_q.center(&modulus_q); - 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 k1_u64 = pt.value.deref().to_vec(); + Modulus::new(t) + .map_err(|e| CircuitsErrors::Fhe(fhe::Error::from(e)))? + .scalar_mul_vec(&mut k1_u64, q_mod_t); + + let mut k1 = Polynomial::from_u64_vector(k1_u64); + k1.reverse(); + k1.center(&BigInt::from(t)); 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 u = CrtPolynomial::from_fhe_polynomial(u).limb(0).clone(); + let mut e1 = CrtPolynomial::from_fhe_polynomial(e1).limb(0).clone(); + + u.center(&BigInt::from(moduli[0])); + u.reverse(); + + e1.center(&BigInt::from(moduli[0])); + e1.reverse(); + + let mut ct0 = CrtPolynomial::from_fhe_polynomial(&ct.c[0]); + let mut ct1 = CrtPolynomial::from_fhe_polynomial(&ct.c[1]); + let mut pk0 = CrtPolynomial::from_fhe_polynomial(&pk.c.c[0]); + let mut pk1 = CrtPolynomial::from_fhe_polynomial(&pk.c.c[1]); + let mut e0_crt = CrtPolynomial::from_fhe_polynomial(e0); + + ct0.reverse(); + ct1.reverse(); + pk0.reverse(); + pk1.reverse(); + e0_crt.reverse(); + + ct0.reduce(moduli)?; + ct1.reduce(moduli)?; + pk0.reduce(moduli)?; + pk1.reduce(moduli)?; + + ct0.center(moduli)?; + ct1.center(moduli)?; + pk0.center(moduli)?; + pk1.center(moduli)?; + e0_crt.center(moduli)?; + + let CrtPolynomial { limbs: ct0_limbs } = ct0; + let CrtPolynomial { limbs: ct1_limbs } = ct1; + let CrtPolynomial { limbs: pk0_limbs } = pk0; + let CrtPolynomial { limbs: pk1_limbs } = pk1; + let CrtPolynomial { limbs: e0_limbs } = e0_crt; + + let mut results: Vec<_> = izip!( + ctx.moduli_operators(), + ct0_limbs, + ct1_limbs, + pk0_limbs, + pk1_limbs, + e0_limbs, + ) + .enumerate() + .par_bridge() + .map(|(i, (qi, ct0i, ct1i, pk0i, pk1i, e0i))| { + let qi_bigint = BigInt::from(qi.modulus()); - let mut k1 = Polynomial::from_u64_vector(k1_u64); - k1.center(&BigInt::from(t.modulus())); - - let mut u_rns_copy = data.u_rns.clone(); - let mut e0_rns_copy = data.e0_rns.clone(); - let mut e0_poly_copy = e0.clone(); - let mut e1_rns_copy = data.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 diff = e0_mod_q.sub(&e0i); + let qi_poly = Polynomial::constant(qi_bigint.clone()); + let (e0_quotient, remainder) = diff.div(&qi_poly).expect("CRT requires exact division"); - let mut e0_vec = Polynomial::new(e0_bigints.clone()); - e0_vec.reverse(); + assert!( + remainder.is_zero(), + "e0 - e0i must be divisible by qi (CRT consistency)" + ); - // Center the coefficients mod Q - let q_bigint = BigInt::from(ctx.modulus().clone()); + let k0qi = BigInt::from(qi.inv(qi.neg(t)).unwrap()); + let ki = k1.scalar_mul(&k0qi); - e0_vec.center(&q_bigint); + let ct0i_hat = { + let pk0i_u_times = pk0i.mul(&u); + let e0_plus_ki = e0i.add(&ki); - 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() + assert_eq!((pk0i_u_times.coefficients().len() as u64) - 1, 2 * (n - 1)); + assert_eq!((e0_plus_ki.coefficients().len() as u64) - 1, n - 1); + + pk0i_u_times.add(&e0_plus_ki) }; - // Extract and convert ciphertext and public key polynomials - let mut ct0 = data.ciphertext.c[0].clone(); // ct0 - let mut ct1 = data.ciphertext.c[1].clone(); // ct1 - ct0.change_representation(Representation::PowerBasis); - ct1.change_representation(Representation::PowerBasis); + assert_eq!((ct0i_hat.coefficients().len() as u64) - 1, 2 * (n - 1)); - 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); + let (r1i, r2i) = decompose_residue(&ct0i, &ct0i_hat, &qi_bigint, &cyclo, n); - let cyclo = cyclotomic_polynomial(n); + let ct1i_hat = { + let pk1i_u_times = pk1i.mul(&u); - 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( - |( + assert_eq!((pk1i_u_times.coefficients().len() as u64) - 1, 2 * (n - 1)); + + pk1i_u_times.add(&e1) + }; + assert_eq!((ct1i_hat.coefficients().len() as u64) - 1, 2 * (n - 1)); + + let (p1i, p2i) = decompose_residue(&ct1i, &ct1i_hat, &qi_bigint, &cyclo, n); + + ( 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)); - - let ct0i_hat_poly = Polynomial::new(ct0i_hat.clone()); - let (r1i_poly, r2i_poly) = - decompose_residue(&ct0i, &ct0i_hat_poly, &qi_bigint, &cyclo, n); - let r1i = r1i_poly.coefficients().to_vec(); - let r2i = r2i_poly.coefficients().to_vec(); - - // --------------------------------------------------- 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)); - - let ct1i_hat_poly = Polynomial::new(ct1i_hat.clone()); - let (p1i_poly, p2i_poly) = - decompose_residue(&ct1i, &ct1i_hat_poly, &qi_bigint, &cyclo, n); - let p1i = p1i_poly.coefficients().to_vec(); - let p2i = p2i_poly.coefficients().to_vec(); - - ( - i, - r2i, - r1i, - k0qi, - ct0i, - ct1i, - pk0i, - pk1i, - p1i, - p2i, - e0i, - e0_quotient, - ) - }, - ) + r2i, + r1i, + 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 mut pk0is = Vec::with_capacity(results.len()); + let mut pk1is = Vec::with_capacity(results.len()); + let mut ct0is = Vec::with_capacity(results.len()); + let mut ct1is = Vec::with_capacity(results.len()); + let mut r1is = Vec::with_capacity(results.len()); + let mut r2is = Vec::with_capacity(results.len()); + let mut p1is = Vec::with_capacity(results.len()); + let mut p2is = Vec::with_capacity(results.len()); + let mut e0is = Vec::with_capacity(results.len()); + let mut e0_quotients = Vec::with_capacity(results.len()); + + for (_, r2i, r1i, ct0i, ct1i, pk0i, pk1i, p1i, p2i, e0i, e0_quotient) in results { + pk0is.push(pk0i); + pk1is.push(pk1i); + ct0is.push(ct0i); + ct1is.push(ct1i); + r1is.push(r1i); + r2is.push(r2i); + p1is.push(p1i); + p2is.push(p2i); + e0is.push(e0i); + e0_quotients.push(e0_quotient); + } + + let mut pk0is = CrtPolynomial::new(pk0is); + let mut pk1is = CrtPolynomial::new(pk1is); + let mut ct0is = CrtPolynomial::new(ct0is); + let mut ct1is = CrtPolynomial::new(ct1is); + let mut r1is = CrtPolynomial::new(r1is); + let mut r2is = CrtPolynomial::new(r2is); + let mut p1is = CrtPolynomial::new(p1is); + let mut p2is = CrtPolynomial::new(p2is); + let mut e0is = CrtPolynomial::new(e0is); + let mut e0_quotients = CrtPolynomial::new(e0_quotients); let zkp_modulus = get_zkp_modulus(); @@ -675,9 +540,10 @@ impl Computation for Inputs { e0_quotients.reduce_uniform(&zkp_modulus); e1.reduce(&zkp_modulus); u.reduce(&zkp_modulus); - e0_vec.reduce(&zkp_modulus); - k1.reduce(&zkp_modulus); + e0_mod_q.reduce(&zkp_modulus); + let pk_bit = compute_modulus_bit(&dkg_params); + let msg_bit = compute_msg_bit(&dkg_params); let pk_commitment = compute_dkg_pk_commitment(&pk0is, &pk1is, pk_bit); let msg_commitment = compute_share_encryption_commitment_from_message(&message, msg_bit); @@ -692,7 +558,7 @@ impl Computation for Inputs { p2is, e0is, e0_quotients, - e0: e0_vec, + e0: e0_mod_q, e1, u, message, 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 26cba2ea26..2210549538 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 @@ -8,7 +8,7 @@ //! //! Uses [`crate::threshold::decrypted_shares_aggregation::utils`] for Q/delta, modular inverses, //! Lagrange-at-zero recovery, and scalar CRT reconstruction. Input coefficients are normalized -//! with [`e3_polynomial::reduce`] in [`Input::standard_form`], consistent with other circuits. +//! with [`e3_polynomial::reduce`] to [0, zkp_modulus) inside [`Inputs::compute`]. use crate::calculate_bit_width; use crate::get_zkp_modulus; @@ -80,7 +80,7 @@ pub struct Configs { } /// Input for decrypted shares aggregation (same shape as old DecSharesAggTrBfvVectors). -/// All coefficients reduced to [0, zkp_modulus) in standard_form. +/// All coefficients reduced to [0, zkp_modulus) by compute. #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Inputs { /// [party][modulus][coeff] @@ -292,59 +292,35 @@ impl Computation for Inputs { .map(|row| truncate(&row)) .collect(); - let inputs = Inputs { + let zkp_modulus = get_zkp_modulus(); + + let decryption_shares: Vec>> = decryption_shares + .iter() + .map(|party| { + party + .iter() + .map(|row| row.iter().map(|c| reduce(c, &zkp_modulus)).collect()) + .collect() + }) + .collect(); + let party_ids: Vec = party_ids.iter().map(|c| reduce(c, &zkp_modulus)).collect(); + let message: Vec = message.iter().map(|c| reduce(c, &zkp_modulus)).collect(); + let u_global: Vec = u_global.iter().map(|c| reduce(c, &zkp_modulus)).collect(); + let crt_quotients: Vec> = crt_quotients + .iter() + .map(|row| row.iter().map(|c| reduce(c, &zkp_modulus)).collect()) + .collect(); + + Ok(Inputs { decryption_shares, party_ids, message, u_global, crt_quotients, - }; - - Ok(inputs.standard_form()) - } -} - -impl Inputs { - /// Reduce all coefficients to [0, zkp_modulus). Uses `e3_polynomial::reduce` like other circuits. - pub fn standard_form(&self) -> Self { - let zkp_modulus = get_zkp_modulus(); - Inputs { - decryption_shares: self - .decryption_shares - .iter() - .map(|party| { - party - .iter() - .map(|row| row.iter().map(|c| reduce(c, &zkp_modulus)).collect()) - .collect() - }) - .collect(), - party_ids: self - .party_ids - .iter() - .map(|c| reduce(c, &zkp_modulus)) - .collect(), - message: self - .message - .iter() - .map(|c| reduce(c, &zkp_modulus)) - .collect(), - u_global: self - .u_global - .iter() - .map(|c| reduce(c, &zkp_modulus)) - .collect(), - crt_quotients: self - .crt_quotients - .iter() - .map(|row| row.iter().map(|c| reduce(c, &zkp_modulus)).collect()) - .collect(), - } + }) } - /// Serializes the input to JSON for Prover.toml. Each polynomial is emitted as - /// `{ "coefficients": [string, ...] }` to match Noir's `Polynomial` struct. - pub fn to_json(&self) -> serde_json::Result { + fn to_json(&self) -> serde_json::Result { use crate::bigint_1d_to_json_values; use crate::poly_coefficients_to_toml_json; diff --git a/crates/zk-helpers/src/circuits/threshold/decrypted_shares_aggregation/utils.rs b/crates/zk-helpers/src/circuits/threshold/decrypted_shares_aggregation/utils.rs index ab9d75763f..2b7e2423f5 100644 --- a/crates/zk-helpers/src/circuits/threshold/decrypted_shares_aggregation/utils.rs +++ b/crates/zk-helpers/src/circuits/threshold/decrypted_shares_aggregation/utils.rs @@ -9,7 +9,7 @@ //! **Generic BFV math** lives in [`crate::math`] and is re-exported here for convenience. //! **This module** adds only Shamir + scalar CRT helpers: [`lagrange_recover_at_zero`] and //! [`crt_reconstruct`]. Coefficient reduction uses [`e3_polynomial::reduce`] in -//! [`super::computation::Inputs::standard_form`]. +//! [`Inputs::compute`](super::computation::Inputs). use crate::math; use crate::CircuitsErrors; 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 708975cc73..d8dca6a969 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 @@ -29,8 +29,6 @@ use e3_polynomial::reduce; use e3_polynomial::CrtPolynomial; use e3_polynomial::Polynomial; use fhe::bfv::SecretKey; -use fhe_math::rq::Poly; -use fhe_math::rq::Representation; use fhe_math::zq::Modulus; use fhe_traits::Serialize as FheSerialize; use itertools::izip; @@ -361,317 +359,197 @@ impl Computation for Inputs { let (threshold_params, _) = build_pair_for_preset(preset).map_err(|e| CircuitsErrors::Sample(e.to_string()))?; - let pk_bit = compute_modulus_bit(&threshold_params); - let pk = data.public_key.clone(); let pt = data.plaintext.clone(); + // Context and plaintext modulus (use same ctx for e0 reconstruction and loop). + let ctx = threshold_params.ctx_at_level(0)?; + + #[allow(non_snake_case)] + let modulus_q = BigInt::from(ctx.modulus().clone()); + let moduli = threshold_params.moduli(); + + let t = threshold_params.plaintext(); + let n = threshold_params.degree() as u64; + let q_mod_t = (&modulus_q % t) + .to_u64() + .ok_or_else(|| CircuitsErrors::Other("Failed to convert q_mod_t to u64".into()))?; // [q]_t + let cyclo = cyclotomic_polynomial(n); + // Encrypt using the provided public key to ensure ciphertext matches the key. - let (ct, u_rns, e0_rns, e1_rns) = data + let (ct, u, e0, e1) = data .public_key .try_encrypt_extended(&data.plaintext, &mut thread_rng())?; - // Context and plaintext modulus (use same ctx for e0 reconstruction and loop). - let ctx = threshold_params.ctx_at_level(pt.level())?; - - // Reconstruct e0 in mod Q so that e0_poly row i matches e0_rns row i (same ctx). - let mut e0_power = 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(threshold_params.plaintext()) - .map_err(|e| CircuitsErrors::Fhe(fhe::Error::from(e)))?; - let n: u64 = ctx.degree as u64; - - // Calculate k1 (independent of qi), center and reverse - let q_mod_t = (ctx.modulus() % t.modulus()).to_u64().unwrap(); // [q]_t + // Reconstruct e0 coefficients mod Q (CRT) for e0_quotient computation. + let mut e0_mod_q = Polynomial::from_fhe_polynomial(&e0); + + e0_mod_q.reverse(); + e0_mod_q.center(&modulus_q); + + // Reconstruct k1 from plaintext polynomial. let mut k1_u64 = pt.value.deref().to_vec(); // m - t.scalar_mul_vec(&mut k1_u64, q_mod_t); // k1 = [q*m]_t + + Modulus::new(t) + .map_err(|e| CircuitsErrors::Fhe(fhe::Error::from(e)))? + .scalar_mul_vec(&mut k1_u64, q_mod_t); // k1 = [q*m]_t let mut k1 = Polynomial::from_u64_vector(k1_u64); k1.reverse(); - k1.center(&BigInt::from(t.modulus())); - - // Extract single vectors of u, e1, and e2 as Vec, center and reverse - let mut u_rns_copy = u_rns.clone(); - let mut e0_rns_copy = e0_rns.clone(); - let mut e0_poly_copy = e0.clone(); - let mut e1_rns_copy = 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() - }; + k1.center(&BigInt::from(t)); + + // Reconstruct u and e1 as polynomials (only the first limb is needed) + let mut u = CrtPolynomial::from_fhe_polynomial(&u).limb(0).clone(); + let mut e1 = CrtPolynomial::from_fhe_polynomial(&e1).limb(0).clone(); + + u.center(&BigInt::from(moduli[0])); + u.reverse(); + + e1.center(&BigInt::from(moduli[0])); + e1.reverse(); + + let mut ct0 = CrtPolynomial::from_fhe_polynomial(&ct.c[0]); + let mut ct1 = CrtPolynomial::from_fhe_polynomial(&ct.c[1]); + let mut pk0 = CrtPolynomial::from_fhe_polynomial(&pk.c.c[0]); + let mut pk1 = CrtPolynomial::from_fhe_polynomial(&pk.c.c[1]); + let mut e0 = CrtPolynomial::from_fhe_polynomial(&e0); + + ct0.reverse(); + ct1.reverse(); + pk0.reverse(); + pk1.reverse(); + e0.reverse(); + + ct0.reduce(&moduli)?; + ct1.reduce(&moduli)?; + pk0.reduce(&moduli)?; + pk1.reduce(&moduli)?; + + ct0.center(&moduli)?; + ct1.center(&moduli)?; + pk0.center(&moduli)?; + pk1.center(&moduli)?; + e0.center(&moduli)?; + + let CrtPolynomial { limbs: ct0_limbs } = ct0; + let CrtPolynomial { limbs: ct1_limbs } = ct1; + let CrtPolynomial { limbs: pk0_limbs } = pk0; + let CrtPolynomial { limbs: pk1_limbs } = pk1; + let CrtPolynomial { limbs: e0_limbs } = e0; + + // Perform the main computation logic + let mut results: Vec<_> = izip!( + ctx.moduli_operators(), + ct0_limbs, + ct1_limbs, + pk0_limbs, + pk1_limbs, + e0_limbs, + ) + .enumerate() + .par_bridge() + .map(|(i, (qi, ct0i, ct1i, pk0i, pk1i, e0i))| { + let qi_bigint = BigInt::from(qi.modulus()); + + // 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 + // Polynomial div by constant yields coefficient-wise division. + let diff = e0_mod_q.sub(&e0i); + let qi_poly = Polynomial::constant(qi_bigint.clone()); + let (e0_quotient, remainder) = diff.div(&qi_poly).expect("CRT requires exact division"); + + assert!( + remainder.is_zero(), + "e0 - e0i must be divisible by qi (CRT consistency)" + ); - let mut e0_vec = Polynomial::new(e0_bigints.clone()); + // k0qi = -t^{-1} mod qi + let k0qi = BigInt::from(qi.inv(qi.neg(t)).unwrap()); - e0_vec.reverse(); + // ki = k1 * k0qi + let ki = k1.scalar_mul(&k0qi); - // Center the coefficients mod Q - let q_bigint = BigInt::from(ctx.modulus().clone()); + // Calculate ct0i_hat = pk0 * ui + e0i + ki + let ct0i_hat = { + let pk0i_u_times = pk0i.mul(&u); + let e0_plus_ki = e0i.add(&ki); - e0_vec.center(&q_bigint); + assert_eq!((pk0i_u_times.coefficients().len() as u64) - 1, 2 * (n - 1)); + assert_eq!((e0_plus_ki.coefficients().len() as u64) - 1, n - 1); - 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() + pk0i_u_times.add(&e0_plus_ki) }; - // Extract and convert ciphertext and public key polynomials - let mut ct0 = ct.c[0].clone(); - let mut ct1 = ct.c[1].clone(); - ct0.change_representation(Representation::PowerBasis); - ct1.change_representation(Representation::PowerBasis); + assert_eq!((ct0i_hat.coefficients().len() as u64) - 1, 2 * (n - 1)); - 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); + let (r1i, r2i) = decompose_residue(&ct0i, &ct0i_hat, &qi_bigint, &cyclo, n); - let cyclo = cyclotomic_polynomial(n); + // Calculate ct1i_hat = pk1i * ui + e1 + let ct1i_hat = { + let pk1i_u_times = pk1i.mul(&u); - 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(); + assert_eq!((pk1i_u_times.coefficients().len() as u64) - 1, 2 * (n - 1)); - 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(); + pk1i_u_times.add(&e1) + }; + assert_eq!((ct1i_hat.coefficients().len() as u64) - 1, 2 * (n - 1)); - // 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( - |( + let (p1i, p2i) = decompose_residue(&ct1i, &ct1i_hat, &qi_bigint, &cyclo, n); + + ( 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)); - - let ct0i_hat_poly = Polynomial::new(ct0i_hat.clone()); - let (r1i_poly, r2i_poly) = - decompose_residue(&ct0i, &ct0i_hat_poly, &qi_bigint, &cyclo, n); - let r1i = r1i_poly.coefficients().to_vec(); - let r2i = r2i_poly.coefficients().to_vec(); - - // --------------------------------------------------- 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)); - - let ct1i_hat_poly = Polynomial::new(ct1i_hat.clone()); - let (p1i_poly, p2i_poly) = - decompose_residue(&ct1i, &ct1i_hat_poly, &qi_bigint, &cyclo, n); - let p1i = p1i_poly.coefficients().to_vec(); - let p2i = p2i_poly.coefficients().to_vec(); - - ( - i, - r2i, - r1i, - k0qi, - ct0i, - ct1i, - pk0i, - pk1i, - p1i, - p2i, - e0i, - e0_quotient, - ) - }, - ) + 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 mut pk0is = Vec::with_capacity(results.len()); + let mut pk1is = Vec::with_capacity(results.len()); + let mut ct0is = Vec::with_capacity(results.len()); + let mut ct1is = Vec::with_capacity(results.len()); + let mut r1is = Vec::with_capacity(results.len()); + let mut r2is = Vec::with_capacity(results.len()); + let mut p1is = Vec::with_capacity(results.len()); + let mut p2is = Vec::with_capacity(results.len()); + let mut e0is = Vec::with_capacity(results.len()); + let mut e0_quotients = Vec::with_capacity(results.len()); + + for (_, r2i, r1i, _, ct0i, ct1i, pk0i, pk1i, p1i, p2i, e0i, e0_quotient) in results { + pk0is.push(pk0i); + pk1is.push(pk1i); + ct0is.push(ct0i); + ct1is.push(ct1i); + r1is.push(r1i); + r2is.push(r2i); + p1is.push(p1i); + p2is.push(p2i); + e0is.push(e0i); + e0_quotients.push(e0_quotient); + } + + let mut pk0is = CrtPolynomial::new(pk0is); + let mut pk1is = CrtPolynomial::new(pk1is); + let mut ct0is = CrtPolynomial::new(ct0is); + let mut ct1is = CrtPolynomial::new(ct1is); + let mut r1is = CrtPolynomial::new(r1is); + let mut r2is = CrtPolynomial::new(r2is); + let mut p1is = CrtPolynomial::new(p1is); + let mut p2is = CrtPolynomial::new(p2is); + let mut e0is = CrtPolynomial::new(e0is); + let mut e0_quotients = CrtPolynomial::new(e0_quotients); let zkp_modulus = get_zkp_modulus(); @@ -687,9 +565,10 @@ impl Computation for Inputs { e0_quotients.reduce_uniform(&zkp_modulus); e1.reduce(&zkp_modulus); u.reduce(&zkp_modulus); - e0_vec.reduce(&zkp_modulus); + e0_mod_q.reduce(&zkp_modulus); k1.reduce(&zkp_modulus); + let pk_bit = compute_modulus_bit(&threshold_params); let pk_commitment = compute_pk_aggregation_commitment(&pk0is, &pk1is, pk_bit); let ct_commitment = compute_ciphertext_commitment(&ct0is, &ct1is, pk_bit); @@ -704,7 +583,7 @@ impl Computation for Inputs { p2is, e0is, e0_quotients, - e0: e0_vec, + e0: e0_mod_q, e1, u, k1: k1,