From c3c4d69920d39981f2ae1e6278ed9bcf70ee1d55 Mon Sep 17 00:00:00 2001 From: 0xjei Date: Tue, 27 Jan 2026 18:27:58 +0100 Subject: [PATCH 01/12] bootstrap circuit registry --- Cargo.lock | 21 ++++ Cargo.toml | 4 +- crates/fhe-params/src/lib.rs | 4 +- crates/fhe-params/src/presets.rs | 31 ++++- crates/pvss/Cargo.toml | 24 ++++ crates/pvss/src/circuits/mod.rs | 1 + crates/pvss/src/circuits/pk_bfv/mod.rs | 4 + crates/pvss/src/codegen/mod.rs | 3 + crates/pvss/src/computation/mod.rs | 4 + crates/pvss/src/lib.rs | 10 ++ crates/pvss/src/registry.rs | 160 +++++++++++++++++++++++++ 11 files changed, 262 insertions(+), 4 deletions(-) create mode 100644 crates/pvss/Cargo.toml create mode 100644 crates/pvss/src/circuits/mod.rs create mode 100644 crates/pvss/src/circuits/pk_bfv/mod.rs create mode 100644 crates/pvss/src/codegen/mod.rs create mode 100644 crates/pvss/src/computation/mod.rs create mode 100644 crates/pvss/src/lib.rs create mode 100644 crates/pvss/src/registry.rs diff --git a/Cargo.lock b/Cargo.lock index 95f47768f4..66d5252950 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3312,6 +3312,27 @@ dependencies = [ "tokio", ] +[[package]] +name = "e3-pvss" +version = "0.1.7" +dependencies = [ + "anyhow", + "e3-fhe-params", + "e3-polynomial", + "fhe", + "fhe-math", + "itertools 0.14.0", + "num-bigint", + "num-traits", + "rand 0.8.5", + "rayon", + "serde", + "serde_json", + "tempfile", + "thiserror 1.0.69", + "toml", +] + [[package]] name = "e3-request" version = "0.1.7" diff --git a/Cargo.toml b/Cargo.toml index d96e9db888..11610afeb8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -36,7 +36,8 @@ members = [ "crates/wasm", "crates/parity-matrix", "crates/polynomial", - "crates/zk-helpers" + "crates/zk-helpers", + "crates/pvss" ] exclude = [ "examples/CRISP", @@ -102,6 +103,7 @@ e3-trbfv = { version = "0.1.7", path = "./crates/trbfv" } e3-utils = { version = "0.1.7", path = "./crates/utils" } e3-safe = { version = "0.1.7", path = "./crates/safe" } e3-zk-helpers = { version = "0.1.7", path = "./crates/zk-helpers" } +e3-pvss = { version = "0.1.7", path = "./crates/pvss" } actix = "=0.13.5" actix-web = "=4.11.0" diff --git a/crates/fhe-params/src/lib.rs b/crates/fhe-params/src/lib.rs index 3f411e3566..e1fb4973aa 100644 --- a/crates/fhe-params/src/lib.rs +++ b/crates/fhe-params/src/lib.rs @@ -18,4 +18,6 @@ pub use builder::{ }; #[cfg(feature = "abi-encoding")] pub use encoding::{decode_bfv_params, decode_bfv_params_arc, encode_bfv_params, EncodingError}; -pub use presets::{BfvParamSet, BfvPreset, PresetError, PresetMetadata, PresetSearchDefaults}; +pub use presets::{ + BfvParamSet, BfvPreset, ParameterType, PresetError, PresetMetadata, PresetSearchDefaults, +}; diff --git a/crates/fhe-params/src/presets.rs b/crates/fhe-params/src/presets.rs index dfaed3e3a8..b76d8a1587 100644 --- a/crates/fhe-params/src/presets.rs +++ b/crates/fhe-params/src/presets.rs @@ -57,6 +57,15 @@ pub enum BfvPreset { SecureDkg8192, } +/// Parameter type for BFV presets +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum ParameterType { + /// Threshold BFV (TRBFV) parameters + THRESHOLD, + /// DKG parameters (BFV) + DKG, +} + /// Metadata describing a BFV preset configuration /// /// This struct contains high-level information about a preset, including @@ -80,6 +89,8 @@ pub struct PresetMetadata { /// Higher values provide stronger security guarantees but may require /// larger parameters. Typically 80 for secure presets, 2 for insecure. pub lambda: usize, + /// Parameter type (BFV / trBFV). + pub parameter_type: ParameterType, } /// Default search parameters for BFV parameter generation @@ -218,17 +229,33 @@ impl BfvPreset { pub fn metadata(&self) -> PresetMetadata { match self { - BfvPreset::InsecureThresholdBfv512 | BfvPreset::InsecureDkg512 => PresetMetadata { + BfvPreset::InsecureThresholdBfv512 => PresetMetadata { + name: self.name(), + degree: insecure_512::DEGREE, + num_parties: insecure_512::NUM_PARTIES, + lambda: DEFAULT_INSECURE_LAMBDA, + parameter_type: ParameterType::THRESHOLD, + }, + BfvPreset::InsecureDkg512 => PresetMetadata { name: self.name(), degree: insecure_512::DEGREE, num_parties: insecure_512::NUM_PARTIES, lambda: DEFAULT_INSECURE_LAMBDA, + parameter_type: ParameterType::DKG, + }, + BfvPreset::SecureThresholdBfv8192 => PresetMetadata { + name: self.name(), + degree: secure_8192::DEGREE, + num_parties: secure_8192::NUM_PARTIES, + lambda: DEFAULT_SECURE_LAMBDA, + parameter_type: ParameterType::THRESHOLD, }, - BfvPreset::SecureThresholdBfv8192 | BfvPreset::SecureDkg8192 => PresetMetadata { + BfvPreset::SecureDkg8192 => PresetMetadata { name: self.name(), degree: secure_8192::DEGREE, num_parties: secure_8192::NUM_PARTIES, lambda: DEFAULT_SECURE_LAMBDA, + parameter_type: ParameterType::DKG, }, } } diff --git a/crates/pvss/Cargo.toml b/crates/pvss/Cargo.toml new file mode 100644 index 0000000000..625b63a6dd --- /dev/null +++ b/crates/pvss/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "e3-pvss" +version.workspace = true +edition.workspace = true +license.workspace = true +description = "PVSS core codegen and computation crate" +repository = "https://github.com/gnosisguild/enclave/crates/pvss" + +[dependencies] +e3-polynomial = { workspace = true } +fhe = { workspace = true } +fhe-math = { workspace = true } +e3-fhe-params = { workspace = true } +num-bigint = { workspace = true } +num-traits = { workspace = true } +rand = { workspace = true } +rayon = { workspace = true } +itertools = "0.14.0" +serde = { workspace = true } +serde_json = { workspace = true } +toml = "0.8.23" +anyhow = { workspace = true } +tempfile = { workspace = true } +thiserror = { workspace = true } diff --git a/crates/pvss/src/circuits/mod.rs b/crates/pvss/src/circuits/mod.rs new file mode 100644 index 0000000000..320415b027 --- /dev/null +++ b/crates/pvss/src/circuits/mod.rs @@ -0,0 +1 @@ +pub mod pk_bfv; diff --git a/crates/pvss/src/circuits/pk_bfv/mod.rs b/crates/pvss/src/circuits/pk_bfv/mod.rs new file mode 100644 index 0000000000..9084077f50 --- /dev/null +++ b/crates/pvss/src/circuits/pk_bfv/mod.rs @@ -0,0 +1,4 @@ +/// Circuit metadata +pub const PK_BFV_CIRCUIT_NAME: &str = "pk-bfv"; +pub const PK_BFV_N_PROOFS: u32 = 1; +pub const PK_BFV_N_PUBLIC_INPUTS: u32 = 1; diff --git a/crates/pvss/src/codegen/mod.rs b/crates/pvss/src/codegen/mod.rs new file mode 100644 index 0000000000..db93b70922 --- /dev/null +++ b/crates/pvss/src/codegen/mod.rs @@ -0,0 +1,3 @@ +//! Codegen for PVSS circuits. +//! +//! This module hosts codegen (artifact, template, and TOML generation) for PVSS circuits. diff --git a/crates/pvss/src/computation/mod.rs b/crates/pvss/src/computation/mod.rs new file mode 100644 index 0000000000..6e35e673ee --- /dev/null +++ b/crates/pvss/src/computation/mod.rs @@ -0,0 +1,4 @@ +//! Computation APIs for PVSS circuits. +//! +//! This module will host runtime math utilities (bounds, witness inputs, and +//! example witness generation). diff --git a/crates/pvss/src/lib.rs b/crates/pvss/src/lib.rs new file mode 100644 index 0000000000..1e0acb74de --- /dev/null +++ b/crates/pvss/src/lib.rs @@ -0,0 +1,10 @@ +//! PVSS library for circuit computation and registry utilities. +//! +//! This crate exposes runtime-facing APIs for circuit selection and computation. + +pub mod circuits; +pub mod codegen; +pub mod computation; +pub mod registry; + +pub use registry::{CircuitRegistry, RegistryError}; diff --git a/crates/pvss/src/registry.rs b/crates/pvss/src/registry.rs new file mode 100644 index 0000000000..22cee03b73 --- /dev/null +++ b/crates/pvss/src/registry.rs @@ -0,0 +1,160 @@ +use crate::circuits::pk_bfv::{PK_BFV_CIRCUIT_NAME, PK_BFV_N_PROOFS, PK_BFV_N_PUBLIC_INPUTS}; +use e3_fhe_params::ParameterType; +use std::collections::HashMap; +use std::sync::Arc; +use thiserror::Error; + +type PublicInputsFn = Arc u32 + Send + Sync + 'static>; + +#[derive(Clone)] +pub struct ZKCircuit { + name: &'static str, + compute: CircuitComputeMetadata, + codegen: CircuitCodegenMetadata, +} + +#[derive(Clone)] +pub struct CircuitComputeMetadata { + supported_parameter: ParameterType, +} + +#[derive(Clone)] +pub struct CircuitCodegenMetadata { + n_proofs: u32, + n_public_inputs: PublicInputsFn, +} + +/// Errors produced by the circuit registry. +#[derive(Error, Debug)] +pub enum RegistryError { + #[error("Unknown circuit: {name}")] + UnknownCircuit { name: String }, +} + +/// Registry for PVSS circuits. +pub struct CircuitRegistry { + circuits: HashMap, +} + +impl CircuitRegistry { + /// Build a registry with all known circuits registered. + pub fn new() -> Self { + let mut registry = Self { + circuits: HashMap::new(), + }; + + registry.register( + PK_BFV_CIRCUIT_NAME, + CircuitComputeMetadata { + supported_parameter: ParameterType::DKG, + }, + CircuitCodegenMetadata { + n_proofs: PK_BFV_N_PROOFS, + n_public_inputs: Arc::new(|| PK_BFV_N_PUBLIC_INPUTS), + }, + ); + + registry + } + + /// Register a circuit descriptor under a name. + fn register( + &mut self, + name: &'static str, + compute: CircuitComputeMetadata, + codegen: CircuitCodegenMetadata, + ) { + self.circuits.insert( + name.to_lowercase(), + ZKCircuit { + name, + compute, + codegen, + }, + ); + } + + /// Get a circuit descriptor from the registry. + pub fn get(&self, name: &str) -> Result { + let key = name.to_lowercase(); + let ZKCircuit { + name, + compute, + codegen, + } = self + .circuits + .get(&key) + .ok_or_else(|| RegistryError::UnknownCircuit { + name: name.to_string(), + })?; + Ok(ZKCircuit { + name, + compute: compute.clone(), + codegen: codegen.clone(), + }) + } + + /// Return supported parameter types for a circuit. + pub fn supported_parameter_type(&self, name: &str) -> Result { + let ZKCircuit { compute, .. } = + self.circuits.get(&name.to_lowercase()).ok_or_else(|| { + RegistryError::UnknownCircuit { + name: name.to_string(), + } + })?; + Ok(compute.supported_parameter) + } + + /// Get number of proofs for a circuit. + /// This is used for determine the number of proofs required for aggregation. + pub fn n_proofs(&self, name: &str) -> Result { + let ZKCircuit { codegen, .. } = + self.circuits.get(&name.to_lowercase()).ok_or_else(|| { + RegistryError::UnknownCircuit { + name: name.to_string(), + } + })?; + Ok(codegen.n_proofs) + } + + /// Get number of public inputs for a circuit. + /// This is used for determine the number of public inputs required for aggregation. + pub fn n_public_inputs(&self, name: &str) -> Result { + let ZKCircuit { codegen, .. } = + self.circuits.get(&name.to_lowercase()).ok_or_else(|| { + RegistryError::UnknownCircuit { + name: name.to_string(), + } + })?; + Ok((codegen.n_public_inputs)()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn registry_rejects_unknown_circuit() { + let registry = CircuitRegistry::new(); + assert!(matches!( + registry.get("unknown"), + Err(RegistryError::UnknownCircuit { .. }) + )); + } + + #[test] + fn registry_reports_expected_metadata() { + let registry = CircuitRegistry::new(); + let ZKCircuit { + name, + compute, + codegen, + } = registry.get(PK_BFV_CIRCUIT_NAME).unwrap(); + + assert_eq!(name, PK_BFV_CIRCUIT_NAME); + assert_eq!(compute.supported_parameter, ParameterType::DKG); + assert_eq!(codegen.n_proofs, PK_BFV_N_PROOFS); + assert_eq!((codegen.n_public_inputs)(), PK_BFV_N_PUBLIC_INPUTS); + } +} From cc90827338b4cf06baa259ea21962cb230f7bdeb Mon Sep 17 00:00:00 2001 From: 0xjei Date: Tue, 27 Jan 2026 18:28:51 +0100 Subject: [PATCH 02/12] add licenses --- crates/pvss/src/circuits/mod.rs | 6 ++++++ crates/pvss/src/circuits/pk_bfv/mod.rs | 6 ++++++ crates/pvss/src/codegen/mod.rs | 6 ++++++ crates/pvss/src/computation/mod.rs | 6 ++++++ crates/pvss/src/lib.rs | 6 ++++++ crates/pvss/src/registry.rs | 6 ++++++ 6 files changed, 36 insertions(+) diff --git a/crates/pvss/src/circuits/mod.rs b/crates/pvss/src/circuits/mod.rs index 320415b027..78aa5fbb5d 100644 --- a/crates/pvss/src/circuits/mod.rs +++ b/crates/pvss/src/circuits/mod.rs @@ -1 +1,7 @@ +// 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. + pub mod pk_bfv; diff --git a/crates/pvss/src/circuits/pk_bfv/mod.rs b/crates/pvss/src/circuits/pk_bfv/mod.rs index 9084077f50..3089b68b63 100644 --- a/crates/pvss/src/circuits/pk_bfv/mod.rs +++ b/crates/pvss/src/circuits/pk_bfv/mod.rs @@ -1,3 +1,9 @@ +// SPDX-License-Identifier: LGPL-3.0-only +// +// This file is provided WITHOUT ANY WARRANTY; +// without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. + /// Circuit metadata pub const PK_BFV_CIRCUIT_NAME: &str = "pk-bfv"; pub const PK_BFV_N_PROOFS: u32 = 1; diff --git a/crates/pvss/src/codegen/mod.rs b/crates/pvss/src/codegen/mod.rs index db93b70922..208fc4df60 100644 --- a/crates/pvss/src/codegen/mod.rs +++ b/crates/pvss/src/codegen/mod.rs @@ -1,3 +1,9 @@ +// 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. + //! Codegen for PVSS circuits. //! //! This module hosts codegen (artifact, template, and TOML generation) for PVSS circuits. diff --git a/crates/pvss/src/computation/mod.rs b/crates/pvss/src/computation/mod.rs index 6e35e673ee..e94347ceb2 100644 --- a/crates/pvss/src/computation/mod.rs +++ b/crates/pvss/src/computation/mod.rs @@ -1,3 +1,9 @@ +// SPDX-License-Identifier: LGPL-3.0-only +// +// This file is provided WITHOUT ANY WARRANTY; +// without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. + //! Computation APIs for PVSS circuits. //! //! This module will host runtime math utilities (bounds, witness inputs, and diff --git a/crates/pvss/src/lib.rs b/crates/pvss/src/lib.rs index 1e0acb74de..829d2c9750 100644 --- a/crates/pvss/src/lib.rs +++ b/crates/pvss/src/lib.rs @@ -1,3 +1,9 @@ +// 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. + //! PVSS library for circuit computation and registry utilities. //! //! This crate exposes runtime-facing APIs for circuit selection and computation. diff --git a/crates/pvss/src/registry.rs b/crates/pvss/src/registry.rs index 22cee03b73..0f41c8e054 100644 --- a/crates/pvss/src/registry.rs +++ b/crates/pvss/src/registry.rs @@ -1,3 +1,9 @@ +// 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 crate::circuits::pk_bfv::{PK_BFV_CIRCUIT_NAME, PK_BFV_N_PROOFS, PK_BFV_N_PUBLIC_INPUTS}; use e3_fhe_params::ParameterType; use std::collections::HashMap; From 54cfb325546857f43b1343b6179918604ff2e64b Mon Sep 17 00:00:00 2001 From: 0xjei Date: Wed, 28 Jan 2026 11:32:24 +0100 Subject: [PATCH 03/12] add computation for c0 --- Cargo.lock | 1 + crates/Dockerfile | 1 + crates/pvss/Cargo.toml | 1 + crates/pvss/src/codegen/mod.rs | 9 -- crates/pvss/src/computation/mod.rs | 10 -- crates/pvss/src/lib.rs | 69 +++++++- .../{circuits/mod.rs => pk_bfv/codegen.rs} | 1 - crates/pvss/src/pk_bfv/computation.rs | 150 ++++++++++++++++++ crates/pvss/src/{circuits => }/pk_bfv/mod.rs | 2 + crates/pvss/src/registry.rs | 7 +- crates/pvss/src/sample.rs | 37 +++++ 11 files changed, 259 insertions(+), 29 deletions(-) delete mode 100644 crates/pvss/src/codegen/mod.rs delete mode 100644 crates/pvss/src/computation/mod.rs rename crates/pvss/src/{circuits/mod.rs => pk_bfv/codegen.rs} (92%) create mode 100644 crates/pvss/src/pk_bfv/computation.rs rename crates/pvss/src/{circuits => }/pk_bfv/mod.rs (93%) create mode 100644 crates/pvss/src/sample.rs diff --git a/Cargo.lock b/Cargo.lock index 66d5252950..4332178660 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3319,6 +3319,7 @@ dependencies = [ "anyhow", "e3-fhe-params", "e3-polynomial", + "e3-zk-helpers", "fhe", "fhe-math", "itertools 0.14.0", diff --git a/crates/Dockerfile b/crates/Dockerfile index f620dba64a..79b753e551 100644 --- a/crates/Dockerfile +++ b/crates/Dockerfile @@ -80,6 +80,7 @@ COPY crates/trbfv/Cargo.toml ./trbfv/Cargo.toml COPY crates/utils/Cargo.toml ./utils/Cargo.toml COPY crates/wasm/Cargo.toml ./wasm/Cargo.toml COPY crates/zk-helpers/Cargo.toml ./zk-helpers/Cargo.toml +COPY crates/pvss/Cargo.toml ./pvss/Cargo.toml RUN echo 'fn main() { println!("cargo:warning=dependency cache build"); }' > ./entrypoint/build.rs RUN echo 'fn main() { println!("cargo:warning=dependency cache build"); }' > ./cli/build.rs diff --git a/crates/pvss/Cargo.toml b/crates/pvss/Cargo.toml index 625b63a6dd..1246c23752 100644 --- a/crates/pvss/Cargo.toml +++ b/crates/pvss/Cargo.toml @@ -11,6 +11,7 @@ e3-polynomial = { workspace = true } fhe = { workspace = true } fhe-math = { workspace = true } e3-fhe-params = { workspace = true } +e3-zk-helpers = { workspace = true } num-bigint = { workspace = true } num-traits = { workspace = true } rand = { workspace = true } diff --git a/crates/pvss/src/codegen/mod.rs b/crates/pvss/src/codegen/mod.rs deleted file mode 100644 index 208fc4df60..0000000000 --- a/crates/pvss/src/codegen/mod.rs +++ /dev/null @@ -1,9 +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. - -//! Codegen for PVSS circuits. -//! -//! This module hosts codegen (artifact, template, and TOML generation) for PVSS circuits. diff --git a/crates/pvss/src/computation/mod.rs b/crates/pvss/src/computation/mod.rs deleted file mode 100644 index e94347ceb2..0000000000 --- a/crates/pvss/src/computation/mod.rs +++ /dev/null @@ -1,10 +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. - -//! Computation APIs for PVSS circuits. -//! -//! This module will host runtime math utilities (bounds, witness inputs, and -//! example witness generation). diff --git a/crates/pvss/src/lib.rs b/crates/pvss/src/lib.rs index 829d2c9750..eb774abe95 100644 --- a/crates/pvss/src/lib.rs +++ b/crates/pvss/src/lib.rs @@ -4,13 +4,66 @@ // without even the implied warranty of MERCHANTABILITY // or FITNESS FOR A PARTICULAR PURPOSE. -//! PVSS library for circuit computation and registry utilities. -//! -//! This crate exposes runtime-facing APIs for circuit selection and computation. - -pub mod circuits; -pub mod codegen; -pub mod computation; +pub mod pk_bfv; pub mod registry; +pub mod sample; + +/// Variant for input types for DKG. +/// +/// This variant is used to determine the type of input that is used for the DKG +/// circuits (C2, C3, C4) +#[derive(Clone)] +pub enum DkgInputType { + /// The input type that generates shares of a secret key using secret sharing. + SecretKey, + /// The input type that generates shares of smudging noise instead of secret key shares. + SmudgingNoise, +} + +/// @todo this must be integrated inside Ciphernodes & Smart Contract +/// instead of being a separate type in here. The pvss crate should import this and +/// the default values that must be used and shared among the whole enclave repository. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum CiphernodesCommitteeSize { + /// Small committee size (fast local/testing). + Small, + /// Medium committee size (default). + Medium, + /// Large committee size (higher assurance). + Large, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct CiphernodesCommittee { + /// Total number of parties (N_PARTIES). + n: usize, + /// Number of honest parties (H). + h: usize, + /// Threshold value (T). + threshold: usize, +} -pub use registry::{CircuitRegistry, RegistryError}; +impl CiphernodesCommitteeSize { + /// Returns `(num_parties, num_honest_parties, threshold)` for this size. + pub fn values(self) -> CiphernodesCommittee { + match self { + CiphernodesCommitteeSize::Small => CiphernodesCommittee { + n: 5, + h: 3, + threshold: 2, + }, + _ => unreachable!(), + } + // @todo add the other committee sizes + // CiphernodesCommitteeSize::Medium => CiphernodesCommittee { + // n: 5, + // h: 3, + // threshold: 2, + // }, + // CiphernodesCommitteeSize::Large => CiphernodesCommittee { + // n: 5, + // h: 3, + // threshold: 2, + // }, + } +} diff --git a/crates/pvss/src/circuits/mod.rs b/crates/pvss/src/pk_bfv/codegen.rs similarity index 92% rename from crates/pvss/src/circuits/mod.rs rename to crates/pvss/src/pk_bfv/codegen.rs index 78aa5fbb5d..f5242f4613 100644 --- a/crates/pvss/src/circuits/mod.rs +++ b/crates/pvss/src/pk_bfv/codegen.rs @@ -4,4 +4,3 @@ // without even the implied warranty of MERCHANTABILITY // or FITNESS FOR A PARTICULAR PURPOSE. -pub mod pk_bfv; diff --git a/crates/pvss/src/pk_bfv/computation.rs b/crates/pvss/src/pk_bfv/computation.rs new file mode 100644 index 0000000000..5399bf400e --- /dev/null +++ b/crates/pvss/src/pk_bfv/computation.rs @@ -0,0 +1,150 @@ +// 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 e3_polynomial::reduce_coefficients_2d; +use e3_polynomial::utils::reduce_and_center_coefficients_mut; +use e3_zk_helpers::utils::calculate_bit_width; +use e3_zk_helpers::utils::get_zkp_modulus; +use e3_zk_helpers::utils::Result as ZkUtilsResult; +use fhe::bfv::BfvParameters; +use fhe::bfv::PublicKey; +use fhe_math::rq::Representation; +use itertools::izip; +use num_bigint::BigInt; +use num_bigint::BigUint; +use rayon::prelude::*; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Clone)] +pub struct Bits { + pub pk_bit: u32, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct Bounds { + /// Bound for public key polynomials (pk0, pk1) + pub pk_bound: BigUint, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct Witness { + /// Public key polynomials (pk0, pk1) for each CRT basis. + pub pk0is: Vec>, + pub pk1is: Vec>, +} + +impl Bits { + pub fn compute(bfv_params: &BfvParameters) -> ZkUtilsResult { + let pk_bound = Bounds::compute(bfv_params); + + Ok(Bits { + pk_bit: calculate_bit_width(&pk_bound.pk_bound.to_string())?, + }) + } +} + +impl Bounds { + pub fn compute(bfv_params: &BfvParameters) -> Bounds { + let mut pk_bound_max = BigUint::from(0u32); + + for &qi in bfv_params.moduli() { + let qi_bound: BigUint = (&BigUint::from(qi) - 1u32) / 2u32; + + if qi_bound > pk_bound_max { + pk_bound_max = qi_bound; + } + } + + Bounds { + pk_bound: pk_bound_max, + } + } +} + +impl Witness { + pub fn compute( + bfv_params: &BfvParameters, + public_key: &PublicKey, + ) -> Result { + let moduli = bfv_params.moduli(); + + // Extract public key components (pk0, pk1) from the ciphertext structure + // and change representation to Power Basis. + let mut pk0 = public_key.c.c[0].clone(); + let mut pk1 = public_key.c.c[1].clone(); + pk0.change_representation(Representation::PowerBasis); + pk1.change_representation(Representation::PowerBasis); + + let pk0_coeffs = pk0.coefficients(); + let pk1_coeffs = pk1.coefficients(); + let pk0_rows = pk0_coeffs.rows(); + let pk1_rows = pk1_coeffs.rows(); + + // Extract and convert public key polynomials per modulus + let results: Vec<(Vec, Vec)> = izip!(moduli, pk0_rows, pk1_rows) + .par_bridge() + .map(|(qi, pk0_coeffs, pk1_coeffs)| { + let mut pk0i: Vec = + pk0_coeffs.iter().rev().map(|&x| BigInt::from(x)).collect(); + let mut pk1i: Vec = + pk1_coeffs.iter().rev().map(|&x| BigInt::from(x)).collect(); + + reduce_and_center_coefficients_mut(&mut pk0i, &BigInt::from(*qi)); + reduce_and_center_coefficients_mut(&mut pk1i, &BigInt::from(*qi)); + + (pk0i, pk1i) + }) + .collect(); + + let (pk0is, pk1is): (Vec<_>, Vec<_>) = results.into_iter().unzip(); + + Ok(Witness { pk0is, pk1is }) + } + + pub fn to_zkp_modulus(&self) -> Witness { + Witness { + pk0is: reduce_coefficients_2d(&self.pk0is, &get_zkp_modulus()), + pk1is: reduce_coefficients_2d(&self.pk1is, &get_zkp_modulus()), + } + } + + pub fn to_json(&self) -> serde_json::Result { + serde_json::to_value(self) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::sample::generate_sample; + use e3_fhe_params::{BfvParamSet, BfvPreset}; + + #[test] + fn test_bound_and_bits_computation() { + let bfv_params = BfvParamSet::from(BfvPreset::InsecureThresholdBfv512).build_arc(); + let bounds = Bounds::compute(&bfv_params); + let bits = Bits::compute(&bfv_params).unwrap(); + + assert_eq!(bounds.pk_bound, BigUint::from(34359701504u64)); + assert_eq!(bits.pk_bit, 35); + } + + #[test] + fn test_witness_computation_and_conversion() { + let bfv_params = BfvParamSet::from(BfvPreset::InsecureThresholdBfv512).build_arc(); + + let encryption_data = generate_sample(&bfv_params); + + let witness = Witness::compute(&bfv_params, &encryption_data.public_key).unwrap(); + + let zkp_reduced = witness.to_zkp_modulus(); + let json = zkp_reduced.to_json().unwrap(); + let decoded: Witness = serde_json::from_value(json.clone()).unwrap(); + + assert_eq!(decoded.pk0is, zkp_reduced.pk0is); + assert_eq!(decoded.pk1is, zkp_reduced.pk1is); + } +} diff --git a/crates/pvss/src/circuits/pk_bfv/mod.rs b/crates/pvss/src/pk_bfv/mod.rs similarity index 93% rename from crates/pvss/src/circuits/pk_bfv/mod.rs rename to crates/pvss/src/pk_bfv/mod.rs index 3089b68b63..f68aac05be 100644 --- a/crates/pvss/src/circuits/pk_bfv/mod.rs +++ b/crates/pvss/src/pk_bfv/mod.rs @@ -8,3 +8,5 @@ pub const PK_BFV_CIRCUIT_NAME: &str = "pk-bfv"; pub const PK_BFV_N_PROOFS: u32 = 1; pub const PK_BFV_N_PUBLIC_INPUTS: u32 = 1; + +pub mod computation; diff --git a/crates/pvss/src/registry.rs b/crates/pvss/src/registry.rs index 0f41c8e054..9d7fe3b83e 100644 --- a/crates/pvss/src/registry.rs +++ b/crates/pvss/src/registry.rs @@ -4,7 +4,8 @@ // without even the implied warranty of MERCHANTABILITY // or FITNESS FOR A PARTICULAR PURPOSE. -use crate::circuits::pk_bfv::{PK_BFV_CIRCUIT_NAME, PK_BFV_N_PROOFS, PK_BFV_N_PUBLIC_INPUTS}; +use crate::pk_bfv::{PK_BFV_CIRCUIT_NAME, PK_BFV_N_PROOFS, PK_BFV_N_PUBLIC_INPUTS}; +use crate::DkgInputType; use e3_fhe_params::ParameterType; use std::collections::HashMap; use std::sync::Arc; @@ -22,6 +23,8 @@ pub struct ZKCircuit { #[derive(Clone)] pub struct CircuitComputeMetadata { supported_parameter: ParameterType, + #[allow(dead_code)] + dkg_input_type: Option, } #[derive(Clone)] @@ -53,6 +56,7 @@ impl CircuitRegistry { PK_BFV_CIRCUIT_NAME, CircuitComputeMetadata { supported_parameter: ParameterType::DKG, + dkg_input_type: None, }, CircuitCodegenMetadata { n_proofs: PK_BFV_N_PROOFS, @@ -160,6 +164,7 @@ mod tests { assert_eq!(name, PK_BFV_CIRCUIT_NAME); assert_eq!(compute.supported_parameter, ParameterType::DKG); + assert_eq!(compute.dkg_input_type.is_none(), true); assert_eq!(codegen.n_proofs, PK_BFV_N_PROOFS); assert_eq!((codegen.n_public_inputs)(), PK_BFV_N_PUBLIC_INPUTS); } diff --git a/crates/pvss/src/sample.rs b/crates/pvss/src/sample.rs new file mode 100644 index 0000000000..70628d57c3 --- /dev/null +++ b/crates/pvss/src/sample.rs @@ -0,0 +1,37 @@ +// 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 fhe::bfv::{BfvParameters, PublicKey, SecretKey}; +use rand::thread_rng; +use std::sync::Arc; + +#[derive(Debug, Clone)] +pub struct Sample { + pub public_key: PublicKey, +} + +pub fn generate_sample(bfv_params: &Arc) -> Sample { + let mut rng = thread_rng(); + + let secret_key = SecretKey::random(bfv_params, &mut rng); + let public_key = PublicKey::new(&secret_key, &mut rng); + + Sample { public_key } +} + +#[cfg(test)] +mod tests { + use super::*; + use e3_fhe_params::{BfvParamSet, BfvPreset}; + + #[test] + fn test_generate_sample() { + let bfv_params = BfvParamSet::from(BfvPreset::InsecureThresholdBfv512).build_arc(); + let sample = generate_sample(&bfv_params); + + assert_eq!(sample.public_key.c.c.len(), 2); + } +} From 0ffcf907df5b111b432a59f64910c2280e455d86 Mon Sep 17 00:00:00 2001 From: 0xjei Date: Wed, 28 Jan 2026 11:49:34 +0100 Subject: [PATCH 04/12] add shared traits for computation --- crates/pvss/src/lib.rs | 1 + crates/pvss/src/pk_bfv/computation.rs | 92 +++++++++++++++------------ crates/pvss/src/traits.rs | 22 +++++++ 3 files changed, 75 insertions(+), 40 deletions(-) create mode 100644 crates/pvss/src/traits.rs diff --git a/crates/pvss/src/lib.rs b/crates/pvss/src/lib.rs index eb774abe95..dc9fa4087d 100644 --- a/crates/pvss/src/lib.rs +++ b/crates/pvss/src/lib.rs @@ -7,6 +7,7 @@ pub mod pk_bfv; pub mod registry; pub mod sample; +pub mod traits; /// Variant for input types for DKG. /// diff --git a/crates/pvss/src/pk_bfv/computation.rs b/crates/pvss/src/pk_bfv/computation.rs index 5399bf400e..2afbbf73a2 100644 --- a/crates/pvss/src/pk_bfv/computation.rs +++ b/crates/pvss/src/pk_bfv/computation.rs @@ -4,11 +4,12 @@ // without even the implied warranty of MERCHANTABILITY // or FITNESS FOR A PARTICULAR PURPOSE. +use crate::traits::Computation; +use crate::traits::Transform; use e3_polynomial::reduce_coefficients_2d; use e3_polynomial::utils::reduce_and_center_coefficients_mut; use e3_zk_helpers::utils::calculate_bit_width; use e3_zk_helpers::utils::get_zkp_modulus; -use e3_zk_helpers::utils::Result as ZkUtilsResult; use fhe::bfv::BfvParameters; use fhe::bfv::PublicKey; use fhe_math::rq::Representation; @@ -36,40 +37,13 @@ pub struct Witness { pub pk1is: Vec>, } -impl Bits { - pub fn compute(bfv_params: &BfvParameters) -> ZkUtilsResult { - let pk_bound = Bounds::compute(bfv_params); +impl Computation for Witness { + type Params = BfvParameters; + type Input = PublicKey; + type Error = fhe::Error; - Ok(Bits { - pk_bit: calculate_bit_width(&pk_bound.pk_bound.to_string())?, - }) - } -} - -impl Bounds { - pub fn compute(bfv_params: &BfvParameters) -> Bounds { - let mut pk_bound_max = BigUint::from(0u32); - - for &qi in bfv_params.moduli() { - let qi_bound: BigUint = (&BigUint::from(qi) - 1u32) / 2u32; - - if qi_bound > pk_bound_max { - pk_bound_max = qi_bound; - } - } - - Bounds { - pk_bound: pk_bound_max, - } - } -} - -impl Witness { - pub fn compute( - bfv_params: &BfvParameters, - public_key: &PublicKey, - ) -> Result { - let moduli = bfv_params.moduli(); + fn compute(params: &Self::Params, public_key: &Self::Input) -> Result { + let moduli = params.moduli(); // Extract public key components (pk0, pk1) from the ciphertext structure // and change representation to Power Basis. @@ -103,30 +77,68 @@ impl Witness { Ok(Witness { pk0is, pk1is }) } +} - pub fn to_zkp_modulus(&self) -> Witness { +impl Transform for Witness { + fn reduce_to_zkp_modulus(&self) -> Witness { Witness { pk0is: reduce_coefficients_2d(&self.pk0is, &get_zkp_modulus()), pk1is: reduce_coefficients_2d(&self.pk1is, &get_zkp_modulus()), } } - pub fn to_json(&self) -> serde_json::Result { + fn convert_to_json(&self) -> serde_json::Result { serde_json::to_value(self) } } +impl Computation for Bounds { + type Params = BfvParameters; + type Input = (); + type Error = std::convert::Infallible; + + fn compute(params: &Self::Params, _: &Self::Input) -> Result { + let mut pk_bound_max = BigUint::from(0u32); + + for &qi in params.moduli() { + let qi_bound: BigUint = (&BigUint::from(qi) - 1u32) / 2u32; + + if qi_bound > pk_bound_max { + pk_bound_max = qi_bound; + } + } + + Ok(Bounds { + pk_bound: pk_bound_max, + }) + } +} + +impl Computation for Bits { + type Params = BfvParameters; + type Input = Bounds; + type Error = e3_zk_helpers::utils::ZkHelpersUtilsError; + + fn compute(params: &Self::Params, input: &Self::Input) -> Result { + let _ = params; + Ok(Bits { + pk_bit: calculate_bit_width(&input.pk_bound.to_string())?, + }) + } +} + #[cfg(test)] mod tests { use super::*; use crate::sample::generate_sample; + use crate::traits::Transform; use e3_fhe_params::{BfvParamSet, BfvPreset}; #[test] fn test_bound_and_bits_computation() { let bfv_params = BfvParamSet::from(BfvPreset::InsecureThresholdBfv512).build_arc(); - let bounds = Bounds::compute(&bfv_params); - let bits = Bits::compute(&bfv_params).unwrap(); + let bounds = Bounds::compute(&bfv_params, &()).unwrap(); + let bits = Bits::compute(&bfv_params, &bounds).unwrap(); assert_eq!(bounds.pk_bound, BigUint::from(34359701504u64)); assert_eq!(bits.pk_bit, 35); @@ -140,8 +152,8 @@ mod tests { let witness = Witness::compute(&bfv_params, &encryption_data.public_key).unwrap(); - let zkp_reduced = witness.to_zkp_modulus(); - let json = zkp_reduced.to_json().unwrap(); + let zkp_reduced = witness.reduce_to_zkp_modulus(); + let json = zkp_reduced.convert_to_json().unwrap(); let decoded: Witness = serde_json::from_value(json.clone()).unwrap(); assert_eq!(decoded.pk0is, zkp_reduced.pk0is); diff --git a/crates/pvss/src/traits.rs b/crates/pvss/src/traits.rs new file mode 100644 index 0000000000..d380c345ee --- /dev/null +++ b/crates/pvss/src/traits.rs @@ -0,0 +1,22 @@ +// 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. + +//! Common computation behavior across circuits. + +use serde_json::Value; + +pub trait Computation: Sized { + type Params; + type Input; + type Error; + + fn compute(params: &Self::Params, input: &Self::Input) -> Result; +} + +pub trait Transform: Sized { + fn reduce_to_zkp_modulus(&self) -> Self; + fn convert_to_json(&self) -> serde_json::Result; +} From ed2e8193119bc1a7892b3f3ad60d8d632ebc3de2 Mon Sep 17 00:00:00 2001 From: 0xjei Date: Wed, 28 Jan 2026 11:59:21 +0100 Subject: [PATCH 05/12] complete computation and traits for c0 --- crates/pvss/src/pk_bfv/computation.rs | 136 ++++++++++++++++++-------- crates/pvss/src/traits.rs | 7 +- 2 files changed, 98 insertions(+), 45 deletions(-) diff --git a/crates/pvss/src/pk_bfv/computation.rs b/crates/pvss/src/pk_bfv/computation.rs index 2afbbf73a2..34fae170a4 100644 --- a/crates/pvss/src/pk_bfv/computation.rs +++ b/crates/pvss/src/pk_bfv/computation.rs @@ -5,7 +5,8 @@ // or FITNESS FOR A PARTICULAR PURPOSE. use crate::traits::Computation; -use crate::traits::Transform; +use crate::traits::ConvertToJson; +use crate::traits::ReduceToZkpModulus; use e3_polynomial::reduce_coefficients_2d; use e3_polynomial::utils::reduce_and_center_coefficients_mut; use e3_zk_helpers::utils::calculate_bit_width; @@ -19,6 +20,13 @@ use num_bigint::BigUint; use rayon::prelude::*; use serde::{Deserialize, Serialize}; +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct Configs { + pub n: usize, + pub l: usize, + pub moduli: Vec, +} + #[derive(Debug, Clone)] pub struct Bits { pub pk_bit: u32, @@ -37,6 +45,57 @@ pub struct Witness { pub pk1is: Vec>, } +impl Computation for Configs { + type Params = BfvParameters; + type Input = (); + type Error = std::convert::Infallible; + + fn compute(params: &Self::Params, _: &Self::Input) -> Result { + let moduli = params.moduli().to_vec(); + + Ok(Configs { + n: params.degree(), + l: moduli.len(), + moduli, + }) + } +} + +impl Computation for Bits { + type Params = BfvParameters; + type Input = Bounds; + type Error = e3_zk_helpers::utils::ZkHelpersUtilsError; + + fn compute(params: &Self::Params, input: &Self::Input) -> Result { + let _ = params; + Ok(Bits { + pk_bit: calculate_bit_width(&input.pk_bound.to_string())?, + }) + } +} + +impl Computation for Bounds { + type Params = BfvParameters; + type Input = (); + type Error = std::convert::Infallible; + + fn compute(params: &Self::Params, _: &Self::Input) -> Result { + let mut pk_bound_max = BigUint::from(0u32); + + for &qi in params.moduli() { + let qi_bound: BigUint = (&BigUint::from(qi) - 1u32) / 2u32; + + if qi_bound > pk_bound_max { + pk_bound_max = qi_bound; + } + } + + Ok(Bounds { + pk_bound: pk_bound_max, + }) + } +} + impl Computation for Witness { type Params = BfvParameters; type Input = PublicKey; @@ -79,51 +138,30 @@ impl Computation for Witness { } } -impl Transform for Witness { - fn reduce_to_zkp_modulus(&self) -> Witness { - Witness { - pk0is: reduce_coefficients_2d(&self.pk0is, &get_zkp_modulus()), - pk1is: reduce_coefficients_2d(&self.pk1is, &get_zkp_modulus()), - } +impl ConvertToJson for Configs { + fn convert_to_json(&self) -> serde_json::Result { + serde_json::to_value(self) } +} +impl ConvertToJson for Bounds { fn convert_to_json(&self) -> serde_json::Result { serde_json::to_value(self) } } -impl Computation for Bounds { - type Params = BfvParameters; - type Input = (); - type Error = std::convert::Infallible; - - fn compute(params: &Self::Params, _: &Self::Input) -> Result { - let mut pk_bound_max = BigUint::from(0u32); - - for &qi in params.moduli() { - let qi_bound: BigUint = (&BigUint::from(qi) - 1u32) / 2u32; - - if qi_bound > pk_bound_max { - pk_bound_max = qi_bound; - } - } - - Ok(Bounds { - pk_bound: pk_bound_max, - }) +impl ConvertToJson for Witness { + fn convert_to_json(&self) -> serde_json::Result { + serde_json::to_value(self) } } -impl Computation for Bits { - type Params = BfvParameters; - type Input = Bounds; - type Error = e3_zk_helpers::utils::ZkHelpersUtilsError; - - fn compute(params: &Self::Params, input: &Self::Input) -> Result { - let _ = params; - Ok(Bits { - pk_bit: calculate_bit_width(&input.pk_bound.to_string())?, - }) +impl ReduceToZkpModulus for Witness { + fn reduce_to_zkp_modulus(&self) -> Witness { + Witness { + pk0is: reduce_coefficients_2d(&self.pk0is, &get_zkp_modulus()), + pk1is: reduce_coefficients_2d(&self.pk1is, &get_zkp_modulus()), + } } } @@ -131,27 +169,26 @@ impl Computation for Bits { mod tests { use super::*; use crate::sample::generate_sample; - use crate::traits::Transform; + use crate::traits::ConvertToJson; + use crate::traits::ReduceToZkpModulus; use e3_fhe_params::{BfvParamSet, BfvPreset}; #[test] - fn test_bound_and_bits_computation() { + fn test_bound_and_bits_computation_consistency() { let bfv_params = BfvParamSet::from(BfvPreset::InsecureThresholdBfv512).build_arc(); let bounds = Bounds::compute(&bfv_params, &()).unwrap(); let bits = Bits::compute(&bfv_params, &bounds).unwrap(); + let expected_bits = calculate_bit_width(&bounds.pk_bound.to_string()).unwrap(); assert_eq!(bounds.pk_bound, BigUint::from(34359701504u64)); - assert_eq!(bits.pk_bit, 35); + assert_eq!(bits.pk_bit, expected_bits); } #[test] - fn test_witness_computation_and_conversion() { + fn test_witness_reduction_and_json_roundtrip() { let bfv_params = BfvParamSet::from(BfvPreset::InsecureThresholdBfv512).build_arc(); - let encryption_data = generate_sample(&bfv_params); - let witness = Witness::compute(&bfv_params, &encryption_data.public_key).unwrap(); - let zkp_reduced = witness.reduce_to_zkp_modulus(); let json = zkp_reduced.convert_to_json().unwrap(); let decoded: Witness = serde_json::from_value(json.clone()).unwrap(); @@ -159,4 +196,17 @@ mod tests { assert_eq!(decoded.pk0is, zkp_reduced.pk0is); assert_eq!(decoded.pk1is, zkp_reduced.pk1is); } + + #[test] + fn test_configs_json_roundtrip() { + let bfv_params = BfvParamSet::from(BfvPreset::InsecureThresholdBfv512).build_arc(); + let configs = Configs::compute(&bfv_params, &()).unwrap(); + + let json = configs.convert_to_json().unwrap(); + let decoded: Configs = serde_json::from_value(json).unwrap(); + + assert_eq!(decoded.n, configs.n); + assert_eq!(decoded.l, configs.l); + assert_eq!(decoded.moduli, configs.moduli); + } } diff --git a/crates/pvss/src/traits.rs b/crates/pvss/src/traits.rs index d380c345ee..d976d272ce 100644 --- a/crates/pvss/src/traits.rs +++ b/crates/pvss/src/traits.rs @@ -16,7 +16,10 @@ pub trait Computation: Sized { fn compute(params: &Self::Params, input: &Self::Input) -> Result; } -pub trait Transform: Sized { - fn reduce_to_zkp_modulus(&self) -> Self; +pub trait ConvertToJson { fn convert_to_json(&self) -> serde_json::Result; } + +pub trait ReduceToZkpModulus: Sized { + fn reduce_to_zkp_modulus(&self) -> Self; +} From 4a695a2e489c2fe8b74470471a331cbefe208595 Mon Sep 17 00:00:00 2001 From: 0xjei Date: Wed, 28 Jan 2026 12:55:21 +0100 Subject: [PATCH 06/12] initiate codegen for c0 --- crates/pvss/src/lib.rs | 1 + crates/pvss/src/pk_bfv/codegen.rs | 84 +++++++++++++++++++++++++++ crates/pvss/src/pk_bfv/computation.rs | 3 +- crates/pvss/src/pk_bfv/mod.rs | 1 + crates/pvss/src/utils.rs | 20 +++++++ 5 files changed, 108 insertions(+), 1 deletion(-) create mode 100644 crates/pvss/src/utils.rs diff --git a/crates/pvss/src/lib.rs b/crates/pvss/src/lib.rs index dc9fa4087d..93f94457f2 100644 --- a/crates/pvss/src/lib.rs +++ b/crates/pvss/src/lib.rs @@ -8,6 +8,7 @@ pub mod pk_bfv; pub mod registry; pub mod sample; pub mod traits; +pub mod utils; /// Variant for input types for DKG. /// diff --git a/crates/pvss/src/pk_bfv/codegen.rs b/crates/pvss/src/pk_bfv/codegen.rs index f5242f4613..b4fe1bb1e1 100644 --- a/crates/pvss/src/pk_bfv/codegen.rs +++ b/crates/pvss/src/pk_bfv/codegen.rs @@ -4,3 +4,87 @@ // without even the implied warranty of MERCHANTABILITY // or FITNESS FOR A PARTICULAR PURPOSE. +use crate::pk_bfv::computation::*; +use crate::traits::Computation; +use crate::traits::ReduceToZkpModulus; +use crate::utils::map_witness_2d_vector_to_json; +use crate::CiphernodesCommitteeSize; +use fhe::bfv::BfvParameters; +use fhe::bfv::PublicKey; +use serde::{Deserialize, Serialize}; +use serde_json; +use std::path::Path; +use std::sync::Arc; + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct Toml { + pub pk0is: Vec, + pub pk1is: Vec, +} + +pub fn generate_toml(witness: Witness) -> Toml { + let pk0is = map_witness_2d_vector_to_json(&witness.pk0is); + let pk1is = map_witness_2d_vector_to_json(&witness.pk1is); + + Toml { pk0is, pk1is } +} + +pub fn codegen( + committee: CiphernodesCommitteeSize, + params: Arc, + public_key: PublicKey, +) -> Toml { + // Compute. + let bounds = Bounds::compute(¶ms, &()).unwrap(); + let bits = Bits::compute(¶ms, &bounds).unwrap(); + let witness = Witness::compute(¶ms, &public_key).unwrap(); + let zkp_witness = witness.reduce_to_zkp_modulus(); + + // Generate Prover.toml + let toml = generate_toml(zkp_witness); + // Generate configs.nr + // Generate main.nr + // Generate wrapper.nr + + toml +} + +pub fn write_artifacts(toml: Toml, path: Option<&Path>) { + let toml_path = path.unwrap_or_else(|| Path::new(".")); + let toml_path = toml_path.join("Prover.toml"); + let toml_content = toml::to_string(&toml).unwrap(); + std::fs::write(toml_path, toml_content).unwrap(); +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::sample; + use e3_fhe_params::{BfvParamSet, BfvPreset}; + use tempfile::TempDir; + + #[test] + fn test_toml_generation_and_structure() { + let committee = CiphernodesCommitteeSize::Small; + let params = BfvParamSet::from(BfvPreset::InsecureThresholdBfv512).build_arc(); + let sample = sample::generate_sample(¶ms); + let toml = codegen(committee, params, sample.public_key); + + assert!(toml.pk0is.len() > 0); + assert!(toml.pk1is.len() > 0); + + let temp_dir = TempDir::new().unwrap(); + write_artifacts(toml.clone(), Some(temp_dir.path())); + + let output_path = temp_dir.path().join("Prover.toml"); + assert!(output_path.exists()); + + let content = std::fs::read_to_string(&output_path).unwrap(); + assert!(content.contains("pk0is")); + assert!(content.contains("pk1is")); + + let toml_string = toml::to_string(&toml).unwrap(); + assert!(toml_string.contains("[[pk0is]]")); + assert!(toml_string.contains("[[pk1is]]")); + } +} diff --git a/crates/pvss/src/pk_bfv/computation.rs b/crates/pvss/src/pk_bfv/computation.rs index 34fae170a4..9c1bbcca3b 100644 --- a/crates/pvss/src/pk_bfv/computation.rs +++ b/crates/pvss/src/pk_bfv/computation.rs @@ -19,6 +19,7 @@ use num_bigint::BigInt; use num_bigint::BigUint; use rayon::prelude::*; use serde::{Deserialize, Serialize}; +use std::sync::Arc; #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Configs { @@ -97,7 +98,7 @@ impl Computation for Bounds { } impl Computation for Witness { - type Params = BfvParameters; + type Params = Arc; type Input = PublicKey; type Error = fhe::Error; diff --git a/crates/pvss/src/pk_bfv/mod.rs b/crates/pvss/src/pk_bfv/mod.rs index f68aac05be..0ad8076831 100644 --- a/crates/pvss/src/pk_bfv/mod.rs +++ b/crates/pvss/src/pk_bfv/mod.rs @@ -9,4 +9,5 @@ pub const PK_BFV_CIRCUIT_NAME: &str = "pk-bfv"; pub const PK_BFV_N_PROOFS: u32 = 1; pub const PK_BFV_N_PUBLIC_INPUTS: u32 = 1; +pub mod codegen; pub mod computation; diff --git a/crates/pvss/src/utils.rs b/crates/pvss/src/utils.rs new file mode 100644 index 0000000000..d639fdeda8 --- /dev/null +++ b/crates/pvss/src/utils.rs @@ -0,0 +1,20 @@ +// 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 e3_zk_helpers::utils::to_string_1d_vec; +use num_bigint::BigInt; +use serde_json; + +pub fn map_witness_2d_vector_to_json(values: &Vec>) -> Vec { + values + .iter() + .map(|value| { + serde_json::json!({ + "coefficients": to_string_1d_vec(value) + }) + }) + .collect() +} From cbb1fadd6229854c58ac782a4b9e50752b64261c Mon Sep 17 00:00:00 2001 From: 0xjei Date: Wed, 28 Jan 2026 15:29:40 +0100 Subject: [PATCH 07/12] complete c0 and connect to registry --- crates/pvss/src/lib.rs | 61 +--------- crates/pvss/src/pk_bfv/codegen.rs | 162 ++++++++++++++++++++++---- crates/pvss/src/pk_bfv/computation.rs | 22 ++-- crates/pvss/src/pk_bfv/mod.rs | 20 +++- crates/pvss/src/registry.rs | 147 +++++++---------------- crates/pvss/src/sample.rs | 14 +-- crates/pvss/src/traits.rs | 65 +++++++++++ crates/pvss/src/types.rs | 101 ++++++++++++++++ crates/pvss/src/utils.rs | 44 +++++++ 9 files changed, 420 insertions(+), 216 deletions(-) create mode 100644 crates/pvss/src/types.rs diff --git a/crates/pvss/src/lib.rs b/crates/pvss/src/lib.rs index 93f94457f2..d1e7cbdb4d 100644 --- a/crates/pvss/src/lib.rs +++ b/crates/pvss/src/lib.rs @@ -8,64 +8,5 @@ pub mod pk_bfv; pub mod registry; pub mod sample; pub mod traits; +pub mod types; pub mod utils; - -/// Variant for input types for DKG. -/// -/// This variant is used to determine the type of input that is used for the DKG -/// circuits (C2, C3, C4) -#[derive(Clone)] -pub enum DkgInputType { - /// The input type that generates shares of a secret key using secret sharing. - SecretKey, - /// The input type that generates shares of smudging noise instead of secret key shares. - SmudgingNoise, -} - -/// @todo this must be integrated inside Ciphernodes & Smart Contract -/// instead of being a separate type in here. The pvss crate should import this and -/// the default values that must be used and shared among the whole enclave repository. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum CiphernodesCommitteeSize { - /// Small committee size (fast local/testing). - Small, - /// Medium committee size (default). - Medium, - /// Large committee size (higher assurance). - Large, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct CiphernodesCommittee { - /// Total number of parties (N_PARTIES). - n: usize, - /// Number of honest parties (H). - h: usize, - /// Threshold value (T). - threshold: usize, -} - -impl CiphernodesCommitteeSize { - /// Returns `(num_parties, num_honest_parties, threshold)` for this size. - pub fn values(self) -> CiphernodesCommittee { - match self { - CiphernodesCommitteeSize::Small => CiphernodesCommittee { - n: 5, - h: 3, - threshold: 2, - }, - _ => unreachable!(), - } - // @todo add the other committee sizes - // CiphernodesCommitteeSize::Medium => CiphernodesCommittee { - // n: 5, - // h: 3, - // threshold: 2, - // }, - // CiphernodesCommitteeSize::Large => CiphernodesCommittee { - // n: 5, - // h: 3, - // threshold: 2, - // }, - } -} diff --git a/crates/pvss/src/pk_bfv/codegen.rs b/crates/pvss/src/pk_bfv/codegen.rs index b4fe1bb1e1..51f00bcbe9 100644 --- a/crates/pvss/src/pk_bfv/codegen.rs +++ b/crates/pvss/src/pk_bfv/codegen.rs @@ -5,10 +5,19 @@ // or FITNESS FOR A PARTICULAR PURPOSE. use crate::pk_bfv::computation::*; +use crate::pk_bfv::PkBfvCircuit; +use crate::traits::Circuit; use crate::traits::Computation; use crate::traits::ReduceToZkpModulus; +use crate::types::Configs; +use crate::types::Template; +use crate::types::Toml; +use crate::types::Wrapper; +use crate::utils::generate_wrapper; +use crate::utils::get_security_level; use crate::utils::map_witness_2d_vector_to_json; -use crate::CiphernodesCommitteeSize; +use e3_fhe_params::BfvParamSet; +use e3_fhe_params::BfvPreset; use fhe::bfv::BfvParameters; use fhe::bfv::PublicKey; use serde::{Deserialize, Serialize}; @@ -17,7 +26,7 @@ use std::path::Path; use std::sync::Arc; #[derive(Debug, Clone, Serialize, Deserialize)] -pub struct Toml { +pub struct TomlJson { pub pk0is: Vec, pub pk1is: Vec, } @@ -26,34 +35,109 @@ pub fn generate_toml(witness: Witness) -> Toml { let pk0is = map_witness_2d_vector_to_json(&witness.pk0is); let pk1is = map_witness_2d_vector_to_json(&witness.pk1is); - Toml { pk0is, pk1is } + let toml_json = TomlJson { pk0is, pk1is }; + toml::to_string(&toml_json).unwrap() } -pub fn codegen( - committee: CiphernodesCommitteeSize, - params: Arc, - public_key: PublicKey, -) -> Toml { +pub fn codegen(preset: BfvPreset, public_key: PublicKey) -> (Toml, Configs, Template, Wrapper) { + let params = BfvParamSet::from(preset).build_arc(); // Compute. let bounds = Bounds::compute(¶ms, &()).unwrap(); let bits = Bits::compute(¶ms, &bounds).unwrap(); let witness = Witness::compute(¶ms, &public_key).unwrap(); let zkp_witness = witness.reduce_to_zkp_modulus(); - // Generate Prover.toml let toml = generate_toml(zkp_witness); - // Generate configs.nr - // Generate main.nr - // Generate wrapper.nr + let configs = generate_configs(¶ms, &bits); + let template = generate_template(preset.metadata().lambda); + let wrapper = generate_wrapper( + ::N_PROOFS, + ::N_PUBLIC_INPUTS, + ); - toml + (toml, configs, template, wrapper) } -pub fn write_artifacts(toml: Toml, path: Option<&Path>) { +pub fn generate_template(lambda: usize) -> Template { + format!( + r#"use lib::configs::{}::bfv::{{ +L, N, {}_BIT_PK, +}}; +use lib::core::bfv_pk::BfvPkCommit; +use lib::math::polynomial::Polynomial; + +fn main( +pk0is: [Polynomial; L], +pk1is: [Polynomial; L], +) -> pub Field {{ +let pk_bfv: BfvPkCommit = + BfvPkCommit::new(pk0is, pk1is); +pk_bfv.verify() +}} +"#, + get_security_level(lambda).as_str(), + ::PREFIX, + ::PREFIX, + ) +} + +pub fn generate_configs(params: &Arc, bits: &Bits) -> Configs { + format!( + r#"// Global configs for Public Key BFV circuit +pub global N: u32 = {}; +pub global L: u32 = {}; + +/************************************ +------------------------------------- +pk_bfv (CIRCUIT 0 - PUBLIC KEY BFV COMMITMENT) +------------------------------------- +************************************/ + +// pk_bfv - bit parameters +pub global {}_BIT_PK: u32 = {}; +å"#, + params.degree(), + params.moduli().len(), + ::PREFIX, + bits.pk_bit, + ) +} + +pub fn write_toml(toml: &Toml, path: Option<&Path>) { let toml_path = path.unwrap_or_else(|| Path::new(".")); let toml_path = toml_path.join("Prover.toml"); - let toml_content = toml::to_string(&toml).unwrap(); - std::fs::write(toml_path, toml_content).unwrap(); + std::fs::write(toml_path, toml).unwrap(); +} + +pub fn write_template(template: &Template, path: Option<&Path>) { + let template_path = path.unwrap_or_else(|| Path::new(".")); + let template_path = template_path.join("main.nr"); + std::fs::write(template_path, template).unwrap(); +} + +pub fn write_configs(configs: &Configs, path: Option<&Path>) { + let configs_path = path.unwrap_or_else(|| Path::new(".")); + let configs_path = configs_path.join("configs.nr"); + std::fs::write(configs_path, configs).unwrap(); +} + +pub fn write_wrapper(wrapper: &Wrapper, path: Option<&Path>) { + let wrapper_path = path.unwrap_or_else(|| Path::new(".")); + let wrapper_path = wrapper_path.join("wrapper.nr"); + std::fs::write(wrapper_path, wrapper).unwrap(); +} + +pub fn write_artifacts( + toml: &Toml, + template: &Template, + configs: &Configs, + wrapper: &Wrapper, + path: Option<&Path>, +) { + write_toml(&toml, path); + write_template(&template, path); + write_configs(&configs, path); + write_wrapper(&wrapper, path); } #[cfg(test)] @@ -65,16 +149,25 @@ mod tests { #[test] fn test_toml_generation_and_structure() { - let committee = CiphernodesCommitteeSize::Small; - let params = BfvParamSet::from(BfvPreset::InsecureThresholdBfv512).build_arc(); + let preset = BfvPreset::InsecureThresholdBfv512; + let params = BfvParamSet::from(preset).build_arc(); let sample = sample::generate_sample(¶ms); - let toml = codegen(committee, params, sample.public_key); + let (toml, configs, template, wrapper) = codegen(preset, sample.public_key); - assert!(toml.pk0is.len() > 0); - assert!(toml.pk1is.len() > 0); + let parsed: toml::Value = toml.parse().unwrap(); + let pk0is = parsed + .get("pk0is") + .and_then(|value| value.as_array()) + .unwrap(); + let pk1is = parsed + .get("pk1is") + .and_then(|value| value.as_array()) + .unwrap(); + assert!(!pk0is.is_empty()); + assert!(!pk1is.is_empty()); let temp_dir = TempDir::new().unwrap(); - write_artifacts(toml.clone(), Some(temp_dir.path())); + write_artifacts(&toml, &template, &configs, &wrapper, Some(temp_dir.path())); let output_path = temp_dir.path().join("Prover.toml"); assert!(output_path.exists()); @@ -83,8 +176,27 @@ mod tests { assert!(content.contains("pk0is")); assert!(content.contains("pk1is")); - let toml_string = toml::to_string(&toml).unwrap(); - assert!(toml_string.contains("[[pk0is]]")); - assert!(toml_string.contains("[[pk1is]]")); + assert!(toml.contains("[[pk0is]]")); + assert!(toml.contains("[[pk1is]]")); + + let template_path = temp_dir.path().join("main.nr"); + assert!(template_path.exists()); + + let template_content = std::fs::read_to_string(&template_path).unwrap(); + assert!(template_content.contains("pk0is: [Polynomial; L],")); + assert!(template_content.contains("pk1is: [Polynomial; L],")); + + let wrapper_path = temp_dir.path().join("wrapper.nr"); + assert!(wrapper_path.exists()); + + let configs_path = temp_dir.path().join("configs.nr"); + assert!(configs_path.exists()); + + let configs_content = std::fs::read_to_string(&configs_path).unwrap(); + let bounds = Bounds::compute(¶ms, &()).unwrap(); + let bits = Bits::compute(¶ms, &bounds).unwrap(); + assert!(configs_content.contains(format!("N: u32 = {}", params.degree()).as_str())); + assert!(configs_content.contains(format!("L: u32 = {}", params.moduli().len()).as_str())); + assert!(configs_content.contains(format!("PK_BFV_BIT_PK: u32 = {}", bits.pk_bit).as_str())); } } diff --git a/crates/pvss/src/pk_bfv/computation.rs b/crates/pvss/src/pk_bfv/computation.rs index 9c1bbcca3b..bbfdcc376e 100644 --- a/crates/pvss/src/pk_bfv/computation.rs +++ b/crates/pvss/src/pk_bfv/computation.rs @@ -19,7 +19,6 @@ use num_bigint::BigInt; use num_bigint::BigUint; use rayon::prelude::*; use serde::{Deserialize, Serialize}; -use std::sync::Arc; #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Configs { @@ -67,8 +66,7 @@ impl Computation for Bits { type Input = Bounds; type Error = e3_zk_helpers::utils::ZkHelpersUtilsError; - fn compute(params: &Self::Params, input: &Self::Input) -> Result { - let _ = params; + fn compute(_: &Self::Params, input: &Self::Input) -> Result { Ok(Bits { pk_bit: calculate_bit_width(&input.pk_bound.to_string())?, }) @@ -98,7 +96,7 @@ impl Computation for Bounds { } impl Computation for Witness { - type Params = Arc; + type Params = BfvParameters; type Input = PublicKey; type Error = fhe::Error; @@ -176,9 +174,9 @@ mod tests { #[test] fn test_bound_and_bits_computation_consistency() { - let bfv_params = BfvParamSet::from(BfvPreset::InsecureThresholdBfv512).build_arc(); - let bounds = Bounds::compute(&bfv_params, &()).unwrap(); - let bits = Bits::compute(&bfv_params, &bounds).unwrap(); + let params = BfvParamSet::from(BfvPreset::InsecureThresholdBfv512).build_arc(); + let bounds = Bounds::compute(¶ms, &()).unwrap(); + let bits = Bits::compute(¶ms, &bounds).unwrap(); let expected_bits = calculate_bit_width(&bounds.pk_bound.to_string()).unwrap(); assert_eq!(bounds.pk_bound, BigUint::from(34359701504u64)); @@ -187,9 +185,9 @@ mod tests { #[test] fn test_witness_reduction_and_json_roundtrip() { - let bfv_params = BfvParamSet::from(BfvPreset::InsecureThresholdBfv512).build_arc(); - let encryption_data = generate_sample(&bfv_params); - let witness = Witness::compute(&bfv_params, &encryption_data.public_key).unwrap(); + let params = BfvParamSet::from(BfvPreset::InsecureThresholdBfv512).build_arc(); + let encryption_data = generate_sample(¶ms); + let witness = Witness::compute(¶ms, &encryption_data.public_key).unwrap(); let zkp_reduced = witness.reduce_to_zkp_modulus(); let json = zkp_reduced.convert_to_json().unwrap(); let decoded: Witness = serde_json::from_value(json.clone()).unwrap(); @@ -200,8 +198,8 @@ mod tests { #[test] fn test_configs_json_roundtrip() { - let bfv_params = BfvParamSet::from(BfvPreset::InsecureThresholdBfv512).build_arc(); - let configs = Configs::compute(&bfv_params, &()).unwrap(); + let params = BfvParamSet::from(BfvPreset::InsecureThresholdBfv512).build_arc(); + let configs = Configs::compute(¶ms, &()).unwrap(); let json = configs.convert_to_json().unwrap(); let decoded: Configs = serde_json::from_value(json).unwrap(); diff --git a/crates/pvss/src/pk_bfv/mod.rs b/crates/pvss/src/pk_bfv/mod.rs index 0ad8076831..106ea7fabd 100644 --- a/crates/pvss/src/pk_bfv/mod.rs +++ b/crates/pvss/src/pk_bfv/mod.rs @@ -4,10 +4,20 @@ // without even the implied warranty of MERCHANTABILITY // or FITNESS FOR A PARTICULAR PURPOSE. -/// Circuit metadata -pub const PK_BFV_CIRCUIT_NAME: &str = "pk-bfv"; -pub const PK_BFV_N_PROOFS: u32 = 1; -pub const PK_BFV_N_PUBLIC_INPUTS: u32 = 1; - pub mod codegen; pub mod computation; + +use crate::traits::Circuit; +use crate::types::DkgInputType; +use e3_fhe_params::ParameterType; + +pub struct PkBfvCircuit; + +impl Circuit for PkBfvCircuit { + const NAME: &'static str = "pk-bfv"; + const PREFIX: &'static str = "PK_BFV"; + const SUPPORTED_PARAMETER: ParameterType = ParameterType::DKG; + const DKG_INPUT_TYPE: Option = None; + const N_PROOFS: usize = 1; + const N_PUBLIC_INPUTS: usize = 1; +} diff --git a/crates/pvss/src/registry.rs b/crates/pvss/src/registry.rs index 9d7fe3b83e..ab11c6c995 100644 --- a/crates/pvss/src/registry.rs +++ b/crates/pvss/src/registry.rs @@ -4,145 +4,82 @@ // without even the implied warranty of MERCHANTABILITY // or FITNESS FOR A PARTICULAR PURPOSE. -use crate::pk_bfv::{PK_BFV_CIRCUIT_NAME, PK_BFV_N_PROOFS, PK_BFV_N_PUBLIC_INPUTS}; -use crate::DkgInputType; +use crate::traits::CircuitMeta; +use crate::types::DkgInputType; use e3_fhe_params::ParameterType; use std::collections::HashMap; use std::sync::Arc; use thiserror::Error; -type PublicInputsFn = Arc u32 + Send + Sync + 'static>; - -#[derive(Clone)] -pub struct ZKCircuit { - name: &'static str, - compute: CircuitComputeMetadata, - codegen: CircuitCodegenMetadata, -} - -#[derive(Clone)] -pub struct CircuitComputeMetadata { - supported_parameter: ParameterType, - #[allow(dead_code)] - dkg_input_type: Option, -} - -#[derive(Clone)] -pub struct CircuitCodegenMetadata { - n_proofs: u32, - n_public_inputs: PublicInputsFn, -} - /// Errors produced by the circuit registry. #[derive(Error, Debug)] pub enum RegistryError { #[error("Unknown circuit: {name}")] UnknownCircuit { name: String }, + #[error("Invalid input for circuit {name}: expected {expected}")] + InvalidInput { + name: String, + expected: &'static str, + }, } /// Registry for PVSS circuits. pub struct CircuitRegistry { - circuits: HashMap, + circuits: HashMap>, } impl CircuitRegistry { /// Build a registry with all known circuits registered. pub fn new() -> Self { - let mut registry = Self { + Self { circuits: HashMap::new(), - }; - - registry.register( - PK_BFV_CIRCUIT_NAME, - CircuitComputeMetadata { - supported_parameter: ParameterType::DKG, - dkg_input_type: None, - }, - CircuitCodegenMetadata { - n_proofs: PK_BFV_N_PROOFS, - n_public_inputs: Arc::new(|| PK_BFV_N_PUBLIC_INPUTS), - }, - ); - - registry + } } /// Register a circuit descriptor under a name. - fn register( - &mut self, - name: &'static str, - compute: CircuitComputeMetadata, - codegen: CircuitCodegenMetadata, - ) { - self.circuits.insert( - name.to_lowercase(), - ZKCircuit { - name, - compute, - codegen, - }, - ); + #[allow(dead_code)] + fn register(&mut self, circuit: Arc) { + self.circuits.insert(circuit.name().to_lowercase(), circuit); } /// Get a circuit descriptor from the registry. - pub fn get(&self, name: &str) -> Result { - let key = name.to_lowercase(); - let ZKCircuit { - name, - compute, - codegen, - } = self - .circuits - .get(&key) + pub fn get(&self, name: &str) -> Result, RegistryError> { + self.circuits + .get(&name.to_lowercase()) + .cloned() .ok_or_else(|| RegistryError::UnknownCircuit { name: name.to_string(), - })?; - Ok(ZKCircuit { - name, - compute: compute.clone(), - codegen: codegen.clone(), - }) + }) } /// Return supported parameter types for a circuit. pub fn supported_parameter_type(&self, name: &str) -> Result { - let ZKCircuit { compute, .. } = - self.circuits.get(&name.to_lowercase()).ok_or_else(|| { - RegistryError::UnknownCircuit { - name: name.to_string(), - } - })?; - Ok(compute.supported_parameter) + Ok(self.get(name)?.supported_parameter()) + } + + /// Return DKG input type for a circuit, if any. + pub fn dkg_input_type(&self, name: &str) -> Result, RegistryError> { + Ok(self.get(name)?.dkg_input_type()) } /// Get number of proofs for a circuit. /// This is used for determine the number of proofs required for aggregation. - pub fn n_proofs(&self, name: &str) -> Result { - let ZKCircuit { codegen, .. } = - self.circuits.get(&name.to_lowercase()).ok_or_else(|| { - RegistryError::UnknownCircuit { - name: name.to_string(), - } - })?; - Ok(codegen.n_proofs) + pub fn n_proofs(&self, name: &str) -> Result { + Ok(self.get(name)?.n_proofs()) } /// Get number of public inputs for a circuit. /// This is used for determine the number of public inputs required for aggregation. - pub fn n_public_inputs(&self, name: &str) -> Result { - let ZKCircuit { codegen, .. } = - self.circuits.get(&name.to_lowercase()).ok_or_else(|| { - RegistryError::UnknownCircuit { - name: name.to_string(), - } - })?; - Ok((codegen.n_public_inputs)()) + pub fn n_public_inputs(&self, name: &str) -> Result { + Ok(self.get(name)?.n_public_inputs()) } } #[cfg(test)] mod tests { use super::*; + use crate::pk_bfv::PkBfvCircuit; + use crate::traits::Circuit; #[test] fn registry_rejects_unknown_circuit() { @@ -155,17 +92,17 @@ mod tests { #[test] fn registry_reports_expected_metadata() { - let registry = CircuitRegistry::new(); - let ZKCircuit { - name, - compute, - codegen, - } = registry.get(PK_BFV_CIRCUIT_NAME).unwrap(); - - assert_eq!(name, PK_BFV_CIRCUIT_NAME); - assert_eq!(compute.supported_parameter, ParameterType::DKG); - assert_eq!(compute.dkg_input_type.is_none(), true); - assert_eq!(codegen.n_proofs, PK_BFV_N_PROOFS); - assert_eq!((codegen.n_public_inputs)(), PK_BFV_N_PUBLIC_INPUTS); + let mut registry = CircuitRegistry::new(); + registry.register(Arc::new(PkBfvCircuit)); + let circuit = registry.get(::NAME).unwrap(); + + assert_eq!(circuit.name(), ::NAME); + assert_eq!(circuit.supported_parameter(), ParameterType::DKG); + assert!(circuit.dkg_input_type().is_none()); + assert_eq!(circuit.n_proofs(), ::N_PROOFS); + assert_eq!( + circuit.n_public_inputs(), + ::N_PUBLIC_INPUTS + ); } } diff --git a/crates/pvss/src/sample.rs b/crates/pvss/src/sample.rs index 70628d57c3..6d89aa0fd9 100644 --- a/crates/pvss/src/sample.rs +++ b/crates/pvss/src/sample.rs @@ -4,19 +4,15 @@ // without even the implied warranty of MERCHANTABILITY // or FITNESS FOR A PARTICULAR PURPOSE. +use crate::types::Sample; use fhe::bfv::{BfvParameters, PublicKey, SecretKey}; use rand::thread_rng; use std::sync::Arc; -#[derive(Debug, Clone)] -pub struct Sample { - pub public_key: PublicKey, -} - -pub fn generate_sample(bfv_params: &Arc) -> Sample { +pub fn generate_sample(params: &Arc) -> Sample { let mut rng = thread_rng(); - let secret_key = SecretKey::random(bfv_params, &mut rng); + let secret_key = SecretKey::random(¶ms, &mut rng); let public_key = PublicKey::new(&secret_key, &mut rng); Sample { public_key } @@ -29,8 +25,8 @@ mod tests { #[test] fn test_generate_sample() { - let bfv_params = BfvParamSet::from(BfvPreset::InsecureThresholdBfv512).build_arc(); - let sample = generate_sample(&bfv_params); + let params = BfvParamSet::from(BfvPreset::InsecureThresholdBfv512).build_arc(); + let sample = generate_sample(¶ms); assert_eq!(sample.public_key.c.c.len(), 2); } diff --git a/crates/pvss/src/traits.rs b/crates/pvss/src/traits.rs index d976d272ce..1204a3b241 100644 --- a/crates/pvss/src/traits.rs +++ b/crates/pvss/src/traits.rs @@ -6,6 +6,8 @@ //! Common computation behavior across circuits. +use crate::types::DkgInputType; +use e3_fhe_params::ParameterType; use serde_json::Value; pub trait Computation: Sized { @@ -23,3 +25,66 @@ pub trait ConvertToJson { pub trait ReduceToZkpModulus: Sized { fn reduce_to_zkp_modulus(&self) -> Self; } + +pub trait Circuit: Send + Sync { + const NAME: &'static str; + const PREFIX: &'static str; + const SUPPORTED_PARAMETER: ParameterType; + const DKG_INPUT_TYPE: Option; + const N_PROOFS: usize; + const N_PUBLIC_INPUTS: usize; + + fn name(&self) -> &'static str { + Self::NAME + } + + fn prefix(&self) -> &'static str { + Self::PREFIX + } + + fn supported_parameter(&self) -> ParameterType { + Self::SUPPORTED_PARAMETER + } + + fn dkg_input_type(&self) -> Option { + Self::DKG_INPUT_TYPE + } + + fn n_proofs(&self) -> usize { + Self::N_PROOFS + } + + fn n_public_inputs(&self) -> usize { + Self::N_PUBLIC_INPUTS + } +} + +pub trait CircuitMeta: Send + Sync { + fn name(&self) -> &'static str; + fn supported_parameter(&self) -> ParameterType; + fn dkg_input_type(&self) -> Option; + fn n_proofs(&self) -> usize; + fn n_public_inputs(&self) -> usize; +} + +impl CircuitMeta for T { + fn name(&self) -> &'static str { + T::NAME + } + + fn supported_parameter(&self) -> ParameterType { + T::SUPPORTED_PARAMETER + } + + fn dkg_input_type(&self) -> Option { + T::DKG_INPUT_TYPE + } + + fn n_proofs(&self) -> usize { + T::N_PROOFS + } + + fn n_public_inputs(&self) -> usize { + T::N_PUBLIC_INPUTS + } +} diff --git a/crates/pvss/src/types.rs b/crates/pvss/src/types.rs new file mode 100644 index 0000000000..7d059ff45c --- /dev/null +++ b/crates/pvss/src/types.rs @@ -0,0 +1,101 @@ +// 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 fhe::bfv::PublicKey; + +pub type Toml = String; +pub type Template = String; +pub type Configs = String; +pub type Wrapper = String; + +/// Variant for input types for DKG. +/// +/// This variant is used to determine the type of input that is used for the DKG +/// circuits (C2, C3, C4) +#[derive(Clone)] +pub enum DkgInputType { + /// The input type that generates shares of a secret key using secret sharing. + SecretKey, + /// The input type that generates shares of smudging noise instead of secret key shares. + SmudgingNoise, +} + +/// @todo this must be integrated inside Ciphernodes & Smart Contract +/// instead of being a separate type in here. The pvss crate should import this and +/// the default values that must be used and shared among the whole enclave repository. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum CiphernodesCommitteeSize { + /// Small committee size (fast local/testing). + Small, + /// Medium committee size (default). + Medium, + /// Large committee size (higher assurance). + Large, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct CiphernodesCommittee { + /// Total number of parties (N_PARTIES). + n: usize, + /// Number of honest parties (H). + h: usize, + /// Threshold value (T). + threshold: usize, +} + +impl CiphernodesCommitteeSize { + /// Returns `(num_parties, num_honest_parties, threshold)` for this size. + pub fn values(self) -> CiphernodesCommittee { + match self { + CiphernodesCommitteeSize::Small => CiphernodesCommittee { + n: 5, + h: 3, + threshold: 2, + }, + _ => unreachable!(), + } + // @todo add the other committee sizes + // CiphernodesCommitteeSize::Medium => CiphernodesCommittee { + // n: 5, + // h: 3, + // threshold: 2, + // }, + // CiphernodesCommitteeSize::Large => CiphernodesCommittee { + // n: 5, + // h: 3, + // threshold: 2, + // }, + } +} + +#[derive(Debug, Clone, Copy)] +pub enum SecurityLevel { + INSECURE, + PRODUCTION, +} + +impl SecurityLevel { + pub fn as_str(self) -> &'static str { + match self { + SecurityLevel::INSECURE => "insecure", + SecurityLevel::PRODUCTION => "production", + } + } +} + +#[derive(Debug, Clone)] +pub struct Sample { + pub public_key: PublicKey, +} + +#[derive(Debug)] +pub enum CircuitArtifacts { + PkBfv { + toml: Toml, + configs: Configs, + template: Template, + wrapper: Wrapper, + }, +} diff --git a/crates/pvss/src/utils.rs b/crates/pvss/src/utils.rs index d639fdeda8..cab83c1f23 100644 --- a/crates/pvss/src/utils.rs +++ b/crates/pvss/src/utils.rs @@ -4,6 +4,7 @@ // without even the implied warranty of MERCHANTABILITY // or FITNESS FOR A PARTICULAR PURPOSE. +use crate::types::{SecurityLevel, Wrapper}; use e3_zk_helpers::utils::to_string_1d_vec; use num_bigint::BigInt; use serde_json; @@ -18,3 +19,46 @@ pub fn map_witness_2d_vector_to_json(values: &Vec>) -> Vec SecurityLevel { + if lambda < 80 { + SecurityLevel::INSECURE + } else { + SecurityLevel::PRODUCTION + } +} + +pub fn generate_wrapper(n_proofs: usize, n_public_inputs: usize) -> Wrapper { + format!( + r#"use bb_proof_verification::{{UltraHonkProof, UltraHonkVerificationKey, verify_ultrahonk_proof}}; +use lib::math::commitments::compute_aggregation_commitment; + +// Number of proofs. +pub global N_PROOFS: u32 = {}; +/// Number of public inputs/outputs per proof. +pub global N_PUBLIC_INPUTS: u32 = {}; + +fn main( + verification_key: UltraHonkVerificationKey, + proofs: [UltraHonkProof; N_PROOFS], + public_inputs: pub [[Field; N_PUBLIC_INPUTS]; N_PROOFS], + key_hash: Field, +) -> pub Field {{ + for i in 0..N_PROOFS {{ + verify_ultrahonk_proof(verification_key, proofs[i], public_inputs[i], key_hash); + }} + + let mut aggregated_public_inputs = Vec::new(); + + for i in 0..N_PROOFS {{ + for j in 0..N_PUBLIC_INPUTS {{ + aggregated_public_inputs.push(public_inputs[i][j]); + }} + }} + + compute_aggregation_commitment(aggregated_public_inputs) +}} +"#, + n_proofs, n_public_inputs + ) +} From e7e9654f2fa511248ad17ea0f68c3b69d5f04e3e Mon Sep 17 00:00:00 2001 From: 0xjei Date: Wed, 28 Jan 2026 15:58:29 +0100 Subject: [PATCH 08/12] simplify registry --- crates/pvss/src/errors.rs | 21 ++++++++ crates/pvss/src/lib.rs | 1 + crates/pvss/src/pk_bfv/circuit.rs | 70 +++++++++++++++++++++++++++ crates/pvss/src/pk_bfv/codegen.rs | 69 +++++++++++++++----------- crates/pvss/src/pk_bfv/computation.rs | 24 ++++----- crates/pvss/src/pk_bfv/mod.rs | 16 +----- crates/pvss/src/registry.rs | 11 +++-- crates/pvss/src/traits.rs | 26 +++++++++- crates/pvss/src/types.rs | 14 +++--- 9 files changed, 184 insertions(+), 68 deletions(-) create mode 100644 crates/pvss/src/errors.rs create mode 100644 crates/pvss/src/pk_bfv/circuit.rs diff --git a/crates/pvss/src/errors.rs b/crates/pvss/src/errors.rs new file mode 100644 index 0000000000..04ed43423a --- /dev/null +++ b/crates/pvss/src/errors.rs @@ -0,0 +1,21 @@ +// 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 thiserror::Error; + +#[derive(Error, Debug)] +pub enum CodegenError { + #[error("I/O error: {0}")] + Io(#[from] std::io::Error), + #[error("TOML serialization error: {0}")] + Toml(#[from] toml::ser::Error), + #[error("BFV error: {0}")] + Fhe(#[from] fhe::Error), + #[error("ZK helper error: {0}")] + ZkHelpers(#[from] e3_zk_helpers::utils::ZkHelpersUtilsError), + #[error("Unexpected error: {0}")] + Other(String), +} diff --git a/crates/pvss/src/lib.rs b/crates/pvss/src/lib.rs index d1e7cbdb4d..9266c37044 100644 --- a/crates/pvss/src/lib.rs +++ b/crates/pvss/src/lib.rs @@ -4,6 +4,7 @@ // without even the implied warranty of MERCHANTABILITY // or FITNESS FOR A PARTICULAR PURPOSE. +pub mod errors; pub mod pk_bfv; pub mod registry; pub mod sample; diff --git a/crates/pvss/src/pk_bfv/circuit.rs b/crates/pvss/src/pk_bfv/circuit.rs new file mode 100644 index 0000000000..2d837b6e35 --- /dev/null +++ b/crates/pvss/src/pk_bfv/circuit.rs @@ -0,0 +1,70 @@ +// 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 crate::errors::CodegenError; +use crate::pk_bfv; +use crate::pk_bfv::computation::{Bits, Bounds, Witness}; +use crate::traits::{Circuit, CircuitCodegen, CircuitComputation, Computation}; +use crate::types::{Artifacts, DkgInputType}; +use e3_fhe_params::{BfvPreset, ParameterType}; +use fhe::bfv::{BfvParameters, PublicKey}; + +#[derive(Debug)] +pub struct PkBfvCircuit; + +#[derive(Debug, Clone)] +pub struct PkBfvCodegenInput { + pub preset: BfvPreset, + pub public_key: PublicKey, +} + +#[derive(Debug, Clone)] +pub struct PkBfvComputationOutput { + pub bounds: Bounds, + pub bits: Bits, + pub witness: Witness, +} + +impl Circuit for PkBfvCircuit { + const NAME: &'static str = "pk-bfv"; + const PREFIX: &'static str = "PK_BFV"; + const SUPPORTED_PARAMETER: ParameterType = ParameterType::DKG; + const DKG_INPUT_TYPE: Option = None; + const N_PROOFS: usize = 1; + const N_PUBLIC_INPUTS: usize = 1; +} + +impl CircuitCodegen for PkBfvCircuit { + type Input = PkBfvCodegenInput; + type Error = CodegenError; + + fn codegen(&self, input: Self::Input) -> Result { + pk_bfv::codegen::codegen(input.preset, input.public_key) + } +} + +impl CircuitComputation for PkBfvCircuit { + type Params = BfvParameters; + type Input = PublicKey; + type Output = PkBfvComputationOutput; + type Error = CodegenError; + + fn compute( + &self, + params: &Self::Params, + input: &Self::Input, + ) -> Result { + let bounds = Bounds::compute(params, &())?; + let bits = Bits::compute(params, &bounds)?; + let witness = Witness::compute(params, input)?; + + Ok(PkBfvComputationOutput { + bounds, + bits, + witness, + }) + } +} diff --git a/crates/pvss/src/pk_bfv/codegen.rs b/crates/pvss/src/pk_bfv/codegen.rs index 51f00bcbe9..0023f3e49c 100644 --- a/crates/pvss/src/pk_bfv/codegen.rs +++ b/crates/pvss/src/pk_bfv/codegen.rs @@ -4,11 +4,13 @@ // without even the implied warranty of MERCHANTABILITY // or FITNESS FOR A PARTICULAR PURPOSE. +use crate::errors::CodegenError; use crate::pk_bfv::computation::*; use crate::pk_bfv::PkBfvCircuit; use crate::traits::Circuit; use crate::traits::Computation; use crate::traits::ReduceToZkpModulus; +use crate::types::Artifacts; use crate::types::Configs; use crate::types::Template; use crate::types::Toml; @@ -31,23 +33,23 @@ pub struct TomlJson { pub pk1is: Vec, } -pub fn generate_toml(witness: Witness) -> Toml { +pub fn generate_toml(witness: Witness) -> Result { let pk0is = map_witness_2d_vector_to_json(&witness.pk0is); let pk1is = map_witness_2d_vector_to_json(&witness.pk1is); let toml_json = TomlJson { pk0is, pk1is }; - toml::to_string(&toml_json).unwrap() + Ok(toml::to_string(&toml_json)?) } -pub fn codegen(preset: BfvPreset, public_key: PublicKey) -> (Toml, Configs, Template, Wrapper) { +pub fn codegen(preset: BfvPreset, public_key: PublicKey) -> Result { let params = BfvParamSet::from(preset).build_arc(); // Compute. - let bounds = Bounds::compute(¶ms, &()).unwrap(); - let bits = Bits::compute(¶ms, &bounds).unwrap(); - let witness = Witness::compute(¶ms, &public_key).unwrap(); + let bounds = Bounds::compute(¶ms, &())?; + let bits = Bits::compute(¶ms, &bounds)?; + let witness = Witness::compute(¶ms, &public_key)?; let zkp_witness = witness.reduce_to_zkp_modulus(); - let toml = generate_toml(zkp_witness); + let toml = generate_toml(zkp_witness)?; let configs = generate_configs(¶ms, &bits); let template = generate_template(preset.metadata().lambda); let wrapper = generate_wrapper( @@ -55,7 +57,12 @@ pub fn codegen(preset: BfvPreset, public_key: PublicKey) -> (Toml, Configs, Temp ::N_PUBLIC_INPUTS, ); - (toml, configs, template, wrapper) + Ok(Artifacts { + toml, + configs, + template, + wrapper, + }) } pub fn generate_template(lambda: usize) -> Template { @@ -95,7 +102,7 @@ pk_bfv (CIRCUIT 0 - PUBLIC KEY BFV COMMITMENT) // pk_bfv - bit parameters pub global {}_BIT_PK: u32 = {}; -å"#, +"#, params.degree(), params.moduli().len(), ::PREFIX, @@ -103,28 +110,28 @@ pub global {}_BIT_PK: u32 = {}; ) } -pub fn write_toml(toml: &Toml, path: Option<&Path>) { +pub fn write_toml(toml: &Toml, path: Option<&Path>) -> Result<(), CodegenError> { let toml_path = path.unwrap_or_else(|| Path::new(".")); let toml_path = toml_path.join("Prover.toml"); - std::fs::write(toml_path, toml).unwrap(); + Ok(std::fs::write(toml_path, toml)?) } -pub fn write_template(template: &Template, path: Option<&Path>) { +pub fn write_template(template: &Template, path: Option<&Path>) -> Result<(), CodegenError> { let template_path = path.unwrap_or_else(|| Path::new(".")); let template_path = template_path.join("main.nr"); - std::fs::write(template_path, template).unwrap(); + Ok(std::fs::write(template_path, template)?) } -pub fn write_configs(configs: &Configs, path: Option<&Path>) { +pub fn write_configs(configs: &Configs, path: Option<&Path>) -> Result<(), CodegenError> { let configs_path = path.unwrap_or_else(|| Path::new(".")); let configs_path = configs_path.join("configs.nr"); - std::fs::write(configs_path, configs).unwrap(); + Ok(std::fs::write(configs_path, configs)?) } -pub fn write_wrapper(wrapper: &Wrapper, path: Option<&Path>) { +pub fn write_wrapper(wrapper: &Wrapper, path: Option<&Path>) -> Result<(), CodegenError> { let wrapper_path = path.unwrap_or_else(|| Path::new(".")); let wrapper_path = wrapper_path.join("wrapper.nr"); - std::fs::write(wrapper_path, wrapper).unwrap(); + Ok(std::fs::write(wrapper_path, wrapper)?) } pub fn write_artifacts( @@ -133,11 +140,12 @@ pub fn write_artifacts( configs: &Configs, wrapper: &Wrapper, path: Option<&Path>, -) { - write_toml(&toml, path); - write_template(&template, path); - write_configs(&configs, path); - write_wrapper(&wrapper, path); +) -> Result<(), CodegenError> { + write_toml(&toml, path)?; + write_template(&template, path)?; + write_configs(&configs, path)?; + write_wrapper(&wrapper, path)?; + Ok(()) } #[cfg(test)] @@ -152,9 +160,9 @@ mod tests { let preset = BfvPreset::InsecureThresholdBfv512; let params = BfvParamSet::from(preset).build_arc(); let sample = sample::generate_sample(¶ms); - let (toml, configs, template, wrapper) = codegen(preset, sample.public_key); + let artifacts = codegen(preset, sample.public_key).unwrap(); - let parsed: toml::Value = toml.parse().unwrap(); + let parsed: toml::Value = artifacts.toml.parse().unwrap(); let pk0is = parsed .get("pk0is") .and_then(|value| value.as_array()) @@ -167,7 +175,14 @@ mod tests { assert!(!pk1is.is_empty()); let temp_dir = TempDir::new().unwrap(); - write_artifacts(&toml, &template, &configs, &wrapper, Some(temp_dir.path())); + write_artifacts( + &artifacts.toml, + &artifacts.template, + &artifacts.configs, + &artifacts.wrapper, + Some(temp_dir.path()), + ) + .unwrap(); let output_path = temp_dir.path().join("Prover.toml"); assert!(output_path.exists()); @@ -176,8 +191,8 @@ mod tests { assert!(content.contains("pk0is")); assert!(content.contains("pk1is")); - assert!(toml.contains("[[pk0is]]")); - assert!(toml.contains("[[pk1is]]")); + assert!(artifacts.toml.contains("[[pk0is]]")); + assert!(artifacts.toml.contains("[[pk1is]]")); let template_path = temp_dir.path().join("main.nr"); assert!(template_path.exists()); diff --git a/crates/pvss/src/pk_bfv/computation.rs b/crates/pvss/src/pk_bfv/computation.rs index bbfdcc376e..064bfd6b3f 100644 --- a/crates/pvss/src/pk_bfv/computation.rs +++ b/crates/pvss/src/pk_bfv/computation.rs @@ -21,7 +21,7 @@ use rayon::prelude::*; use serde::{Deserialize, Serialize}; #[derive(Debug, Clone, Serialize, Deserialize)] -pub struct Configs { +pub struct Constants { pub n: usize, pub l: usize, pub moduli: Vec, @@ -45,7 +45,7 @@ pub struct Witness { pub pk1is: Vec>, } -impl Computation for Configs { +impl Computation for Constants { type Params = BfvParameters; type Input = (); type Error = std::convert::Infallible; @@ -53,7 +53,7 @@ impl Computation for Configs { fn compute(params: &Self::Params, _: &Self::Input) -> Result { let moduli = params.moduli().to_vec(); - Ok(Configs { + Ok(Constants { n: params.degree(), l: moduli.len(), moduli, @@ -76,7 +76,7 @@ impl Computation for Bits { impl Computation for Bounds { type Params = BfvParameters; type Input = (); - type Error = std::convert::Infallible; + type Error = crate::errors::CodegenError; fn compute(params: &Self::Params, _: &Self::Input) -> Result { let mut pk_bound_max = BigUint::from(0u32); @@ -137,7 +137,7 @@ impl Computation for Witness { } } -impl ConvertToJson for Configs { +impl ConvertToJson for Constants { fn convert_to_json(&self) -> serde_json::Result { serde_json::to_value(self) } @@ -197,15 +197,15 @@ mod tests { } #[test] - fn test_configs_json_roundtrip() { + fn test_constants_json_roundtrip() { let params = BfvParamSet::from(BfvPreset::InsecureThresholdBfv512).build_arc(); - let configs = Configs::compute(¶ms, &()).unwrap(); + let constants = Constants::compute(¶ms, &()).unwrap(); - let json = configs.convert_to_json().unwrap(); - let decoded: Configs = serde_json::from_value(json).unwrap(); + let json = constants.convert_to_json().unwrap(); + let decoded: Constants = serde_json::from_value(json).unwrap(); - assert_eq!(decoded.n, configs.n); - assert_eq!(decoded.l, configs.l); - assert_eq!(decoded.moduli, configs.moduli); + assert_eq!(decoded.n, constants.n); + assert_eq!(decoded.l, constants.l); + assert_eq!(decoded.moduli, constants.moduli); } } diff --git a/crates/pvss/src/pk_bfv/mod.rs b/crates/pvss/src/pk_bfv/mod.rs index 106ea7fabd..3ab1c1b6af 100644 --- a/crates/pvss/src/pk_bfv/mod.rs +++ b/crates/pvss/src/pk_bfv/mod.rs @@ -4,20 +4,8 @@ // without even the implied warranty of MERCHANTABILITY // or FITNESS FOR A PARTICULAR PURPOSE. +pub mod circuit; pub mod codegen; pub mod computation; -use crate::traits::Circuit; -use crate::types::DkgInputType; -use e3_fhe_params::ParameterType; - -pub struct PkBfvCircuit; - -impl Circuit for PkBfvCircuit { - const NAME: &'static str = "pk-bfv"; - const PREFIX: &'static str = "PK_BFV"; - const SUPPORTED_PARAMETER: ParameterType = ParameterType::DKG; - const DKG_INPUT_TYPE: Option = None; - const N_PROOFS: usize = 1; - const N_PUBLIC_INPUTS: usize = 1; -} +pub use circuit::PkBfvCircuit; diff --git a/crates/pvss/src/registry.rs b/crates/pvss/src/registry.rs index ab11c6c995..6faf2af413 100644 --- a/crates/pvss/src/registry.rs +++ b/crates/pvss/src/registry.rs @@ -4,7 +4,7 @@ // without even the implied warranty of MERCHANTABILITY // or FITNESS FOR A PARTICULAR PURPOSE. -use crate::traits::CircuitMeta; +use crate::traits::CircuitMetadata; use crate::types::DkgInputType; use e3_fhe_params::ParameterType; use std::collections::HashMap; @@ -25,7 +25,7 @@ pub enum RegistryError { /// Registry for PVSS circuits. pub struct CircuitRegistry { - circuits: HashMap>, + circuits: HashMap>, } impl CircuitRegistry { @@ -37,13 +37,12 @@ impl CircuitRegistry { } /// Register a circuit descriptor under a name. - #[allow(dead_code)] - fn register(&mut self, circuit: Arc) { + pub fn register(&mut self, circuit: Arc) { self.circuits.insert(circuit.name().to_lowercase(), circuit); } /// Get a circuit descriptor from the registry. - pub fn get(&self, name: &str) -> Result, RegistryError> { + pub fn get(&self, name: &str) -> Result, RegistryError> { self.circuits .get(&name.to_lowercase()) .cloned() @@ -82,6 +81,7 @@ mod tests { use crate::traits::Circuit; #[test] + /// Unknown circuits should return an error. fn registry_rejects_unknown_circuit() { let registry = CircuitRegistry::new(); assert!(matches!( @@ -91,6 +91,7 @@ mod tests { } #[test] + /// Registry should expose metadata for registered circuits. fn registry_reports_expected_metadata() { let mut registry = CircuitRegistry::new(); registry.register(Arc::new(PkBfvCircuit)); diff --git a/crates/pvss/src/traits.rs b/crates/pvss/src/traits.rs index 1204a3b241..8af5adc51e 100644 --- a/crates/pvss/src/traits.rs +++ b/crates/pvss/src/traits.rs @@ -59,7 +59,7 @@ pub trait Circuit: Send + Sync { } } -pub trait CircuitMeta: Send + Sync { +pub trait CircuitMetadata: Send + Sync { fn name(&self) -> &'static str; fn supported_parameter(&self) -> ParameterType; fn dkg_input_type(&self) -> Option; @@ -67,7 +67,7 @@ pub trait CircuitMeta: Send + Sync { fn n_public_inputs(&self) -> usize; } -impl CircuitMeta for T { +impl CircuitMetadata for T { fn name(&self) -> &'static str { T::NAME } @@ -88,3 +88,25 @@ impl CircuitMeta for T { T::N_PUBLIC_INPUTS } } + +pub trait CircuitCodegen: Circuit { + type Input; + type Error; + + /// Generate artifacts for a circuit. + fn codegen(&self, input: Self::Input) -> Result; +} + +pub trait CircuitComputation: Circuit { + type Params; + type Input; + type Output; + type Error; + + /// Compute circuit-specific data. + fn compute( + &self, + params: &Self::Params, + input: &Self::Input, + ) -> Result; +} diff --git a/crates/pvss/src/types.rs b/crates/pvss/src/types.rs index 7d059ff45c..d244d8445a 100644 --- a/crates/pvss/src/types.rs +++ b/crates/pvss/src/types.rs @@ -90,12 +90,10 @@ pub struct Sample { pub public_key: PublicKey, } -#[derive(Debug)] -pub enum CircuitArtifacts { - PkBfv { - toml: Toml, - configs: Configs, - template: Template, - wrapper: Wrapper, - }, +#[derive(Debug, Clone)] +pub struct Artifacts { + pub toml: Toml, + pub configs: Configs, + pub template: Template, + pub wrapper: Wrapper, } From adc6d27b1d0fdac4a9c6ad6e0d64550954f8e122 Mon Sep 17 00:00:00 2001 From: 0xjei Date: Wed, 28 Jan 2026 16:19:08 +0100 Subject: [PATCH 09/12] add first version of pvss-cli --- Cargo.lock | 10 +++ Cargo.toml | 3 +- crates/Dockerfile | 1 + crates/pvss-cli/Cargo.toml | 13 ++++ crates/pvss-cli/src/main.rs | 120 ++++++++++++++++++++++++++++++ crates/pvss/src/pk_bfv/codegen.rs | 14 +--- crates/pvss/src/registry.rs | 5 ++ 7 files changed, 155 insertions(+), 11 deletions(-) create mode 100644 crates/pvss-cli/Cargo.toml create mode 100644 crates/pvss-cli/src/main.rs diff --git a/Cargo.lock b/Cargo.lock index 4332178660..42386baacb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3334,6 +3334,16 @@ dependencies = [ "toml", ] +[[package]] +name = "e3-pvss-cli" +version = "0.1.7" +dependencies = [ + "anyhow", + "clap", + "e3-fhe-params", + "e3-pvss", +] + [[package]] name = "e3-request" version = "0.1.7" diff --git a/Cargo.toml b/Cargo.toml index 11610afeb8..87908abada 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -37,7 +37,8 @@ members = [ "crates/parity-matrix", "crates/polynomial", "crates/zk-helpers", - "crates/pvss" + "crates/pvss", + "crates/pvss-cli" ] exclude = [ "examples/CRISP", diff --git a/crates/Dockerfile b/crates/Dockerfile index 79b753e551..581ac52a31 100644 --- a/crates/Dockerfile +++ b/crates/Dockerfile @@ -81,6 +81,7 @@ COPY crates/utils/Cargo.toml ./utils/Cargo.toml COPY crates/wasm/Cargo.toml ./wasm/Cargo.toml COPY crates/zk-helpers/Cargo.toml ./zk-helpers/Cargo.toml COPY crates/pvss/Cargo.toml ./pvss/Cargo.toml +COPY crates/pvss-cli/Cargo.toml ./pvss-cli/Cargo.toml RUN echo 'fn main() { println!("cargo:warning=dependency cache build"); }' > ./entrypoint/build.rs RUN echo 'fn main() { println!("cargo:warning=dependency cache build"); }' > ./cli/build.rs diff --git a/crates/pvss-cli/Cargo.toml b/crates/pvss-cli/Cargo.toml new file mode 100644 index 0000000000..46b892b552 --- /dev/null +++ b/crates/pvss-cli/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "e3-pvss-cli" +version.workspace = true +edition.workspace = true +license.workspace = true +description = "PVSS CLI for artifact generation" +repository = "https://github.com/gnosisguild/enclave/crates/pvss-cli" + +[dependencies] +e3-pvss = { workspace = true } +e3-fhe-params = { workspace = true } +clap = { workspace = true } +anyhow = { workspace = true } diff --git a/crates/pvss-cli/src/main.rs b/crates/pvss-cli/src/main.rs new file mode 100644 index 0000000000..5e50c602f5 --- /dev/null +++ b/crates/pvss-cli/src/main.rs @@ -0,0 +1,120 @@ +// 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 anyhow::{anyhow, Context, Result}; +use clap::Parser; +use e3_fhe_params::{BfvParamSet, BfvPreset}; +use e3_pvss::pk_bfv::circuit::{PkBfvCircuit, PkBfvCodegenInput}; +use e3_pvss::pk_bfv::codegen::write_artifacts; +use e3_pvss::registry::CircuitRegistry; +use e3_pvss::sample; +use e3_pvss::traits::Circuit; +use e3_pvss::traits::CircuitCodegen; +use std::path::PathBuf; +use std::sync::Arc; + +/// Minimal PVSS CLI for generating circuit artifacts. +#[derive(Debug, Parser)] +#[command(name = "pvss-cli")] +struct Cli { + /// List all available circuits and exit. + #[arg(long)] + list_circuits: bool, + /// Circuit name to generate artifacts for (e.g. pk-bfv). + #[arg(long, required_unless_present = "list_circuits")] + circuit: Option, + /// BFV preset name (must match circuit's parameter type). + #[arg(long, required_unless_present = "list_circuits")] + preset: Option, + /// Output directory for generated artifacts. + #[arg(long, default_value = "output")] + output: PathBuf, +} + +/// Parse a preset name into a BFV preset. +fn parse_preset(name: &str) -> Result { + BfvPreset::from_name(name).map_err(|_| { + let available = BfvPreset::list().join(", "); + anyhow!("unknown preset: {name}. Available: {available}") + }) +} + +fn main() -> Result<()> { + let args = Cli::parse(); + + // Register all circuits in the registry (metadata only). + let mut registry = CircuitRegistry::new(); + registry.register(Arc::new(PkBfvCircuit)); + + // Handle list circuits flag. + if args.list_circuits { + let circuits = registry.list_circuits(); + println!("Available circuits:"); + for circuit_name in circuits { + if let Ok(circuit_meta) = registry.get(&circuit_name) { + println!( + " {} - params_type: {:?}, n_proofs: {}, pub_inputs: {}", + circuit_name, + circuit_meta.supported_parameter(), + circuit_meta.n_proofs(), + circuit_meta.n_public_inputs() + ); + } + } + return Ok(()); + } + + // Unwrap required arguments (clap ensures they're present when list_circuits is false). + let circuit = args.circuit.unwrap(); + let preset = parse_preset(&args.preset.unwrap())?; + + std::fs::create_dir_all(&args.output) + .with_context(|| format!("failed to create output dir {}", args.output.display()))?; + + // Validate circuit exists in registry. + let circuit_meta = registry.get(&circuit).map_err(|_| { + let available = registry.list_circuits().join(", "); + anyhow!("unknown circuit: {}. Available: {}", circuit, available) + })?; + + // Validate preset parameter type matches circuit's supported parameter type. + let preset_param_type = preset.metadata().parameter_type; + let circuit_param_type = circuit_meta.supported_parameter(); + if preset_param_type != circuit_param_type { + return Err(anyhow!( + "preset has parameter type {:?}, but circuit {} requires {:?}", + preset_param_type, + circuit, + circuit_param_type + )); + } + + // Generate artifacts based on circuit name from registry. + let params = BfvParamSet::from(preset).build_arc(); + let sample = sample::generate_sample(¶ms); + let circuit_name = circuit_meta.name(); + let artifacts = match circuit_name { + name if name == ::NAME => { + let circuit = PkBfvCircuit; + circuit.codegen(PkBfvCodegenInput { + preset, + public_key: sample.public_key, + })? + } + name => return Err(anyhow!("circuit {} not yet implemented", name)), + }; + + write_artifacts( + &artifacts.toml, + &artifacts.template, + &artifacts.configs, + &artifacts.wrapper, + Some(args.output.as_path()), + )?; + + println!("Artifacts written to {}", args.output.display()); + Ok(()) +} diff --git a/crates/pvss/src/pk_bfv/codegen.rs b/crates/pvss/src/pk_bfv/codegen.rs index 0023f3e49c..3fe0b3934c 100644 --- a/crates/pvss/src/pk_bfv/codegen.rs +++ b/crates/pvss/src/pk_bfv/codegen.rs @@ -67,19 +67,13 @@ pub fn codegen(preset: BfvPreset, public_key: PublicKey) -> Result Template { format!( - r#"use lib::configs::{}::bfv::{{ -L, N, {}_BIT_PK, -}}; + r#"use lib::configs::{}::bfv::{{L, N, {}_BIT_PK}}; use lib::core::bfv_pk::BfvPkCommit; use lib::math::polynomial::Polynomial; -fn main( -pk0is: [Polynomial; L], -pk1is: [Polynomial; L], -) -> pub Field {{ -let pk_bfv: BfvPkCommit = - BfvPkCommit::new(pk0is, pk1is); -pk_bfv.verify() +fn main(pk0is: [Polynomial; L], pk1is: [Polynomial; L]) -> pub Field {{ + let pk_bfv: BfvPkCommit = BfvPkCommit::new(pk0is, pk1is); + pk_bfv.verify() }} "#, get_security_level(lambda).as_str(), diff --git a/crates/pvss/src/registry.rs b/crates/pvss/src/registry.rs index 6faf2af413..246b40787a 100644 --- a/crates/pvss/src/registry.rs +++ b/crates/pvss/src/registry.rs @@ -72,6 +72,11 @@ impl CircuitRegistry { pub fn n_public_inputs(&self, name: &str) -> Result { Ok(self.get(name)?.n_public_inputs()) } + + /// List all registered circuit names. + pub fn list_circuits(&self) -> Vec { + self.circuits.keys().cloned().collect() + } } #[cfg(test)] From 2ee1044f8124aa9a9e1132d626ca6cb430d82b8c Mon Sep 17 00:00:00 2001 From: 0xjei Date: Wed, 28 Jan 2026 16:33:43 +0100 Subject: [PATCH 10/12] fix test --- crates/pvss/src/pk_bfv/codegen.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/pvss/src/pk_bfv/codegen.rs b/crates/pvss/src/pk_bfv/codegen.rs index 3fe0b3934c..fe0b15ca79 100644 --- a/crates/pvss/src/pk_bfv/codegen.rs +++ b/crates/pvss/src/pk_bfv/codegen.rs @@ -193,7 +193,7 @@ mod tests { let template_content = std::fs::read_to_string(&template_path).unwrap(); assert!(template_content.contains("pk0is: [Polynomial; L],")); - assert!(template_content.contains("pk1is: [Polynomial; L],")); + assert!(template_content.contains("pk1is: [Polynomial; L]")); let wrapper_path = temp_dir.path().join("wrapper.nr"); assert!(wrapper_path.exists()); From 2b3c657f25b8560f644bc0bbb5703b84c282ea69 Mon Sep 17 00:00:00 2001 From: 0xjei Date: Wed, 28 Jan 2026 16:42:49 +0100 Subject: [PATCH 11/12] remove par_bridge in favour of par_iter --- crates/pvss/src/pk_bfv/computation.rs | 10 ++++++---- crates/pvss/src/registry.rs | 2 +- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/crates/pvss/src/pk_bfv/computation.rs b/crates/pvss/src/pk_bfv/computation.rs index 064bfd6b3f..5fc6b6d2e7 100644 --- a/crates/pvss/src/pk_bfv/computation.rs +++ b/crates/pvss/src/pk_bfv/computation.rs @@ -116,16 +116,18 @@ impl Computation for Witness { let pk1_rows = pk1_coeffs.rows(); // Extract and convert public key polynomials per modulus - let results: Vec<(Vec, Vec)> = izip!(moduli, pk0_rows, pk1_rows) - .par_bridge() + // Collect into Vec first to preserve moduli ordering with par_iter + let zipped: Vec<_> = izip!(moduli, pk0_rows, pk1_rows).collect(); + let results: Vec<(Vec, Vec)> = zipped + .par_iter() .map(|(qi, pk0_coeffs, pk1_coeffs)| { let mut pk0i: Vec = pk0_coeffs.iter().rev().map(|&x| BigInt::from(x)).collect(); let mut pk1i: Vec = pk1_coeffs.iter().rev().map(|&x| BigInt::from(x)).collect(); - reduce_and_center_coefficients_mut(&mut pk0i, &BigInt::from(*qi)); - reduce_and_center_coefficients_mut(&mut pk1i, &BigInt::from(*qi)); + reduce_and_center_coefficients_mut(&mut pk0i, &BigInt::from(**qi)); + reduce_and_center_coefficients_mut(&mut pk1i, &BigInt::from(**qi)); (pk0i, pk1i) }) diff --git a/crates/pvss/src/registry.rs b/crates/pvss/src/registry.rs index 246b40787a..853321df53 100644 --- a/crates/pvss/src/registry.rs +++ b/crates/pvss/src/registry.rs @@ -29,7 +29,7 @@ pub struct CircuitRegistry { } impl CircuitRegistry { - /// Build a registry with all known circuits registered. + /// Build an empty registry. pub fn new() -> Self { Self { circuits: HashMap::new(), From 97c10fecf96a822ec79fec4817e087c2799c38e0 Mon Sep 17 00:00:00 2001 From: 0xjei Date: Wed, 28 Jan 2026 18:05:59 +0100 Subject: [PATCH 12/12] modularize, update configs for c0, max reuse of writers --- circuits/lib/src/configs/insecure/bfv.nr | 2 +- circuits/lib/src/configs/production/bfv.nr | 2 +- crates/pvss-cli/src/main.rs | 8 ++-- crates/pvss/src/circuits/mod.rs | 7 ++++ .../pvss/src/{ => circuits}/pk_bfv/circuit.rs | 20 +++++----- .../pvss/src/{ => circuits}/pk_bfv/codegen.rs | 37 ++++--------------- .../src/{ => circuits}/pk_bfv/computation.rs | 0 crates/pvss/src/{ => circuits}/pk_bfv/mod.rs | 2 - crates/pvss/src/lib.rs | 2 +- crates/pvss/src/registry.rs | 18 ++++----- crates/pvss/src/traits.rs | 6 +-- crates/pvss/src/utils.rs | 32 ++++++++++++++-- 12 files changed, 71 insertions(+), 65 deletions(-) create mode 100644 crates/pvss/src/circuits/mod.rs rename crates/pvss/src/{ => circuits}/pk_bfv/circuit.rs (90%) rename crates/pvss/src/{ => circuits}/pk_bfv/codegen.rs (83%) rename crates/pvss/src/{ => circuits}/pk_bfv/computation.rs (100%) rename crates/pvss/src/{ => circuits}/pk_bfv/mod.rs (88%) diff --git a/circuits/lib/src/configs/insecure/bfv.nr b/circuits/lib/src/configs/insecure/bfv.nr index 782e54b246..cb9681e600 100644 --- a/circuits/lib/src/configs/insecure/bfv.nr +++ b/circuits/lib/src/configs/insecure/bfv.nr @@ -24,7 +24,7 @@ pk_bfv (CIRCUIT 0 - PUBLIC KEY BFV) ************************************/ // pk_bfv - bit parameters -pub global PK_BFV_BIT_PK: u32 = 51; +pub global PK_BFV_BIT_PK: u32 = 50; /************************************ ------------------------------------- diff --git a/circuits/lib/src/configs/production/bfv.nr b/circuits/lib/src/configs/production/bfv.nr index 031444d633..5f541fc32f 100644 --- a/circuits/lib/src/configs/production/bfv.nr +++ b/circuits/lib/src/configs/production/bfv.nr @@ -27,7 +27,7 @@ pk_bfv (CIRCUIT 0 - PUBLIC KEY BFV) // pk_bfv - bit parameters -pub global PK_BFV_BIT_PK: u32 = 57; +pub global PK_BFV_BIT_PK: u32 = 58; /************************************ ------------------------------------- diff --git a/crates/pvss-cli/src/main.rs b/crates/pvss-cli/src/main.rs index 5e50c602f5..6f1204e70d 100644 --- a/crates/pvss-cli/src/main.rs +++ b/crates/pvss-cli/src/main.rs @@ -7,8 +7,8 @@ use anyhow::{anyhow, Context, Result}; use clap::Parser; use e3_fhe_params::{BfvParamSet, BfvPreset}; -use e3_pvss::pk_bfv::circuit::{PkBfvCircuit, PkBfvCodegenInput}; -use e3_pvss::pk_bfv::codegen::write_artifacts; +use e3_pvss::circuits::pk_bfv::circuit::{PkBfvCircuit, PkBfvCodegenInput}; +use e3_pvss::circuits::pk_bfv::codegen::write_artifacts; use e3_pvss::registry::CircuitRegistry; use e3_pvss::sample; use e3_pvss::traits::Circuit; @@ -56,10 +56,10 @@ fn main() -> Result<()> { for circuit_name in circuits { if let Ok(circuit_meta) = registry.get(&circuit_name) { println!( - " {} - params_type: {:?}, n_proofs: {}, pub_inputs: {}", + " {} - params_type: {:?}, n_recursive_proofs: {}, pub_inputs: {}", circuit_name, circuit_meta.supported_parameter(), - circuit_meta.n_proofs(), + circuit_meta.n_recursive_proofs(), circuit_meta.n_public_inputs() ); } diff --git a/crates/pvss/src/circuits/mod.rs b/crates/pvss/src/circuits/mod.rs new file mode 100644 index 0000000000..78aa5fbb5d --- /dev/null +++ b/crates/pvss/src/circuits/mod.rs @@ -0,0 +1,7 @@ +// 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. + +pub mod pk_bfv; diff --git a/crates/pvss/src/pk_bfv/circuit.rs b/crates/pvss/src/circuits/pk_bfv/circuit.rs similarity index 90% rename from crates/pvss/src/pk_bfv/circuit.rs rename to crates/pvss/src/circuits/pk_bfv/circuit.rs index 2d837b6e35..8b6d7a4bac 100644 --- a/crates/pvss/src/pk_bfv/circuit.rs +++ b/crates/pvss/src/circuits/pk_bfv/circuit.rs @@ -4,9 +4,9 @@ // without even the implied warranty of MERCHANTABILITY // or FITNESS FOR A PARTICULAR PURPOSE. +use crate::circuits::pk_bfv::codegen; +use crate::circuits::pk_bfv::computation::{Bits, Bounds, Witness}; use crate::errors::CodegenError; -use crate::pk_bfv; -use crate::pk_bfv::computation::{Bits, Bounds, Witness}; use crate::traits::{Circuit, CircuitCodegen, CircuitComputation, Computation}; use crate::types::{Artifacts, DkgInputType}; use e3_fhe_params::{BfvPreset, ParameterType}; @@ -15,19 +15,19 @@ use fhe::bfv::{BfvParameters, PublicKey}; #[derive(Debug)] pub struct PkBfvCircuit; -#[derive(Debug, Clone)] -pub struct PkBfvCodegenInput { - pub preset: BfvPreset, - pub public_key: PublicKey, -} - -#[derive(Debug, Clone)] +#[derive(Debug)] pub struct PkBfvComputationOutput { pub bounds: Bounds, pub bits: Bits, pub witness: Witness, } +#[derive(Debug, Clone)] +pub struct PkBfvCodegenInput { + pub preset: BfvPreset, + pub public_key: PublicKey, +} + impl Circuit for PkBfvCircuit { const NAME: &'static str = "pk-bfv"; const PREFIX: &'static str = "PK_BFV"; @@ -42,7 +42,7 @@ impl CircuitCodegen for PkBfvCircuit { type Error = CodegenError; fn codegen(&self, input: Self::Input) -> Result { - pk_bfv::codegen::codegen(input.preset, input.public_key) + codegen::codegen(input.preset, input.public_key) } } diff --git a/crates/pvss/src/pk_bfv/codegen.rs b/crates/pvss/src/circuits/pk_bfv/codegen.rs similarity index 83% rename from crates/pvss/src/pk_bfv/codegen.rs rename to crates/pvss/src/circuits/pk_bfv/codegen.rs index fe0b15ca79..151403143e 100644 --- a/crates/pvss/src/pk_bfv/codegen.rs +++ b/crates/pvss/src/circuits/pk_bfv/codegen.rs @@ -4,20 +4,21 @@ // without even the implied warranty of MERCHANTABILITY // or FITNESS FOR A PARTICULAR PURPOSE. +use crate::circuits::pk_bfv::circuit::PkBfvCircuit; +use crate::circuits::pk_bfv::computation::{Bits, Bounds, Witness}; use crate::errors::CodegenError; -use crate::pk_bfv::computation::*; -use crate::pk_bfv::PkBfvCircuit; use crate::traits::Circuit; use crate::traits::Computation; use crate::traits::ReduceToZkpModulus; use crate::types::Artifacts; -use crate::types::Configs; -use crate::types::Template; -use crate::types::Toml; -use crate::types::Wrapper; +use crate::types::{Configs, Template, Toml, Wrapper}; use crate::utils::generate_wrapper; use crate::utils::get_security_level; use crate::utils::map_witness_2d_vector_to_json; +use crate::utils::write_configs; +use crate::utils::write_template; +use crate::utils::write_toml; +use crate::utils::write_wrapper; use e3_fhe_params::BfvParamSet; use e3_fhe_params::BfvPreset; use fhe::bfv::BfvParameters; @@ -104,30 +105,6 @@ pub global {}_BIT_PK: u32 = {}; ) } -pub fn write_toml(toml: &Toml, path: Option<&Path>) -> Result<(), CodegenError> { - let toml_path = path.unwrap_or_else(|| Path::new(".")); - let toml_path = toml_path.join("Prover.toml"); - Ok(std::fs::write(toml_path, toml)?) -} - -pub fn write_template(template: &Template, path: Option<&Path>) -> Result<(), CodegenError> { - let template_path = path.unwrap_or_else(|| Path::new(".")); - let template_path = template_path.join("main.nr"); - Ok(std::fs::write(template_path, template)?) -} - -pub fn write_configs(configs: &Configs, path: Option<&Path>) -> Result<(), CodegenError> { - let configs_path = path.unwrap_or_else(|| Path::new(".")); - let configs_path = configs_path.join("configs.nr"); - Ok(std::fs::write(configs_path, configs)?) -} - -pub fn write_wrapper(wrapper: &Wrapper, path: Option<&Path>) -> Result<(), CodegenError> { - let wrapper_path = path.unwrap_or_else(|| Path::new(".")); - let wrapper_path = wrapper_path.join("wrapper.nr"); - Ok(std::fs::write(wrapper_path, wrapper)?) -} - pub fn write_artifacts( toml: &Toml, template: &Template, diff --git a/crates/pvss/src/pk_bfv/computation.rs b/crates/pvss/src/circuits/pk_bfv/computation.rs similarity index 100% rename from crates/pvss/src/pk_bfv/computation.rs rename to crates/pvss/src/circuits/pk_bfv/computation.rs diff --git a/crates/pvss/src/pk_bfv/mod.rs b/crates/pvss/src/circuits/pk_bfv/mod.rs similarity index 88% rename from crates/pvss/src/pk_bfv/mod.rs rename to crates/pvss/src/circuits/pk_bfv/mod.rs index 3ab1c1b6af..63504b9145 100644 --- a/crates/pvss/src/pk_bfv/mod.rs +++ b/crates/pvss/src/circuits/pk_bfv/mod.rs @@ -7,5 +7,3 @@ pub mod circuit; pub mod codegen; pub mod computation; - -pub use circuit::PkBfvCircuit; diff --git a/crates/pvss/src/lib.rs b/crates/pvss/src/lib.rs index 9266c37044..9be7fb848e 100644 --- a/crates/pvss/src/lib.rs +++ b/crates/pvss/src/lib.rs @@ -4,8 +4,8 @@ // without even the implied warranty of MERCHANTABILITY // or FITNESS FOR A PARTICULAR PURPOSE. +pub mod circuits; pub mod errors; -pub mod pk_bfv; pub mod registry; pub mod sample; pub mod traits; diff --git a/crates/pvss/src/registry.rs b/crates/pvss/src/registry.rs index 853321df53..4229475fd1 100644 --- a/crates/pvss/src/registry.rs +++ b/crates/pvss/src/registry.rs @@ -16,11 +16,6 @@ use thiserror::Error; pub enum RegistryError { #[error("Unknown circuit: {name}")] UnknownCircuit { name: String }, - #[error("Invalid input for circuit {name}: expected {expected}")] - InvalidInput { - name: String, - expected: &'static str, - }, } /// Registry for PVSS circuits. @@ -61,10 +56,10 @@ impl CircuitRegistry { Ok(self.get(name)?.dkg_input_type()) } - /// Get number of proofs for a circuit. + /// Get number of recursive proofs for a circuit. /// This is used for determine the number of proofs required for aggregation. - pub fn n_proofs(&self, name: &str) -> Result { - Ok(self.get(name)?.n_proofs()) + pub fn n_recursive_proofs(&self, name: &str) -> Result { + Ok(self.get(name)?.n_recursive_proofs()) } /// Get number of public inputs for a circuit. @@ -82,7 +77,7 @@ impl CircuitRegistry { #[cfg(test)] mod tests { use super::*; - use crate::pk_bfv::PkBfvCircuit; + use crate::circuits::pk_bfv::circuit::PkBfvCircuit; use crate::traits::Circuit; #[test] @@ -105,7 +100,10 @@ mod tests { assert_eq!(circuit.name(), ::NAME); assert_eq!(circuit.supported_parameter(), ParameterType::DKG); assert!(circuit.dkg_input_type().is_none()); - assert_eq!(circuit.n_proofs(), ::N_PROOFS); + assert_eq!( + circuit.n_recursive_proofs(), + ::N_PROOFS + ); assert_eq!( circuit.n_public_inputs(), ::N_PUBLIC_INPUTS diff --git a/crates/pvss/src/traits.rs b/crates/pvss/src/traits.rs index 8af5adc51e..78fa9dfaf1 100644 --- a/crates/pvss/src/traits.rs +++ b/crates/pvss/src/traits.rs @@ -50,7 +50,7 @@ pub trait Circuit: Send + Sync { Self::DKG_INPUT_TYPE } - fn n_proofs(&self) -> usize { + fn n_recursive_proofs(&self) -> usize { Self::N_PROOFS } @@ -63,7 +63,7 @@ pub trait CircuitMetadata: Send + Sync { fn name(&self) -> &'static str; fn supported_parameter(&self) -> ParameterType; fn dkg_input_type(&self) -> Option; - fn n_proofs(&self) -> usize; + fn n_recursive_proofs(&self) -> usize; fn n_public_inputs(&self) -> usize; } @@ -80,7 +80,7 @@ impl CircuitMetadata for T { T::DKG_INPUT_TYPE } - fn n_proofs(&self) -> usize { + fn n_recursive_proofs(&self) -> usize { T::N_PROOFS } diff --git a/crates/pvss/src/utils.rs b/crates/pvss/src/utils.rs index cab83c1f23..df55859972 100644 --- a/crates/pvss/src/utils.rs +++ b/crates/pvss/src/utils.rs @@ -4,10 +4,12 @@ // without even the implied warranty of MERCHANTABILITY // or FITNESS FOR A PARTICULAR PURPOSE. -use crate::types::{SecurityLevel, Wrapper}; +use crate::errors::CodegenError; +use crate::types::{Configs, SecurityLevel, Template, Toml, Wrapper}; use e3_zk_helpers::utils::to_string_1d_vec; use num_bigint::BigInt; use serde_json; +use std::path::Path; pub fn map_witness_2d_vector_to_json(values: &Vec>) -> Vec { values @@ -28,7 +30,7 @@ pub fn get_security_level(lambda: usize) -> SecurityLevel { } } -pub fn generate_wrapper(n_proofs: usize, n_public_inputs: usize) -> Wrapper { +pub fn generate_wrapper(n_recursive_proofs: usize, n_public_inputs: usize) -> Wrapper { format!( r#"use bb_proof_verification::{{UltraHonkProof, UltraHonkVerificationKey, verify_ultrahonk_proof}}; use lib::math::commitments::compute_aggregation_commitment; @@ -59,6 +61,30 @@ fn main( compute_aggregation_commitment(aggregated_public_inputs) }} "#, - n_proofs, n_public_inputs + n_recursive_proofs, n_public_inputs ) } + +pub fn write_toml(toml: &Toml, path: Option<&Path>) -> Result<(), CodegenError> { + let toml_path = path.unwrap_or_else(|| Path::new(".")); + let toml_path = toml_path.join("Prover.toml"); + Ok(std::fs::write(toml_path, toml)?) +} + +pub fn write_template(template: &Template, path: Option<&Path>) -> Result<(), CodegenError> { + let template_path = path.unwrap_or_else(|| Path::new(".")); + let template_path = template_path.join("main.nr"); + Ok(std::fs::write(template_path, template)?) +} + +pub fn write_configs(configs: &Configs, path: Option<&Path>) -> Result<(), CodegenError> { + let configs_path = path.unwrap_or_else(|| Path::new(".")); + let configs_path = configs_path.join("configs.nr"); + Ok(std::fs::write(configs_path, configs)?) +} + +pub fn write_wrapper(wrapper: &Wrapper, path: Option<&Path>) -> Result<(), CodegenError> { + let wrapper_path = path.unwrap_or_else(|| Path::new(".")); + let wrapper_path = wrapper_path.join("wrapper.nr"); + Ok(std::fs::write(wrapper_path, wrapper)?) +}