diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9e25418ea2..8d846344d7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -34,7 +34,9 @@ permissions: jobs: rust_tests: - runs-on: ubuntu-latest + runs-on: + group: enclave-ci + labels: [enclave-ci-runner] steps: - uses: actions/checkout@v6 @@ -80,7 +82,9 @@ jobs: run: 'cargo test --test integration -- --nocapture' zk_prover_integration: - runs-on: ubuntu-latest + runs-on: + group: enclave-ci + labels: [enclave-ci-runner] steps: - uses: actions/checkout@v6 @@ -109,7 +113,9 @@ jobs: run: 'cargo test -p e3-zk-prover --features integration-tests --test integration_tests -- --nocapture' build_e3_support_risc0: - runs-on: ubuntu-latest + runs-on: + group: enclave-ci + labels: [enclave-ci-runner] steps: - uses: actions/checkout@v6 - name: Generate tags @@ -146,7 +152,9 @@ jobs: type=gha,mode=max,scope=e3-support build_ciphernode_image: - runs-on: ubuntu-latest + runs-on: + group: enclave-ci + labels: [enclave-ci-runner] steps: - uses: actions/checkout@v6 @@ -186,7 +194,9 @@ jobs: type=gha,mode=max,scope=ciphernode test_contracts: - runs-on: 'ubuntu-latest' + runs-on: + group: enclave-ci + labels: [enclave-ci-runner] steps: - name: 'Check out the repo' uses: 'actions/checkout@v6' @@ -221,7 +231,9 @@ jobs: echo "✅ Passed" >> $GITHUB_STEP_SUMMARY test_net: - runs-on: 'ubuntu-latest' + runs-on: + group: enclave-ci + labels: [enclave-ci-runner] steps: - name: 'Check out the repo' uses: 'actions/checkout@v6' @@ -234,7 +246,9 @@ jobs: echo "✅ Passed" >> $GITHUB_STEP_SUMMARY integration_prebuild: - runs-on: 'ubuntu-latest' + runs-on: + group: enclave-ci + labels: [enclave-ci-runner] steps: - name: 'Check out the repo' uses: 'actions/checkout@v6' @@ -291,7 +305,9 @@ jobs: ciphernode_integration_test: needs: [integration_prebuild, build_enclave_cli, build_sdk] - runs-on: 'ubuntu-latest' + runs-on: + group: enclave-ci + labels: [enclave-ci-runner] strategy: matrix: test-suite: [base, persist] @@ -353,7 +369,9 @@ jobs: echo "✅ Passed" >> $GITHUB_STEP_SUMMARY build_enclave_cli: - runs-on: ubuntu-latest + runs-on: + group: enclave-ci + labels: [enclave-ci-runner] steps: - uses: actions/checkout@v6 with: @@ -384,7 +402,9 @@ jobs: retention-days: 1 crisp_unit: - runs-on: ubuntu-latest + runs-on: + group: enclave-ci + labels: [enclave-ci-runner] needs: [build_crisp_sdk] steps: - uses: actions/checkout@v6 @@ -457,7 +477,9 @@ jobs: run: 'pnpm test:contracts' crisp_e2e: - runs-on: ubuntu-latest + runs-on: + group: enclave-ci + labels: [enclave-ci-runner] needs: [build_enclave_cli, build_crisp_sdk] steps: - uses: actions/checkout@v6 @@ -565,7 +587,9 @@ jobs: retention-days: 30 build_circuits: - runs-on: ubuntu-latest + runs-on: + group: enclave-ci + labels: [enclave-ci-runner] steps: - uses: actions/checkout@v6 with: @@ -618,7 +642,9 @@ jobs: if-no-files-found: error zk_prover_e2e: - runs-on: ubuntu-latest + runs-on: + group: enclave-ci + labels: [enclave-ci-runner] needs: [build_circuits] steps: - uses: actions/checkout@v6 @@ -657,7 +683,9 @@ jobs: run: cargo test -p e3-zk-prover --test local_e2e_tests -- --nocapture build_e3_support_dev: - runs-on: ubuntu-latest + runs-on: + group: enclave-ci + labels: [enclave-ci-runner] steps: - uses: actions/checkout@v6 with: @@ -686,7 +714,9 @@ jobs: if-no-files-found: error build_sdk: - runs-on: ubuntu-latest + runs-on: + group: enclave-ci + labels: [enclave-ci-runner] steps: - uses: actions/checkout@v6 with: @@ -735,7 +765,9 @@ jobs: if-no-files-found: warn build_crisp_sdk: - runs-on: ubuntu-latest + runs-on: + group: enclave-ci + labels: [enclave-ci-runner] steps: - uses: actions/checkout@v6 @@ -779,7 +811,9 @@ jobs: if-no-files-found: warn template_integration: - runs-on: ubuntu-latest + runs-on: + group: enclave-ci + labels: [enclave-ci-runner] needs: [build_enclave_cli, build_e3_support_dev, build_sdk] steps: - uses: actions/checkout@v6 @@ -839,7 +873,9 @@ jobs: pnpm test:integration test_enclave_init: - runs-on: ubuntu-latest + runs-on: + group: enclave-ci + labels: [enclave-ci-runner] needs: [build_enclave_cli, build_e3_support_dev] steps: - name: Install pnpm @@ -876,7 +912,9 @@ jobs: enclave init mycitest --verbose --template=${{ github.server_url }}/${{ github.repository }}.git#${BRANCH}:templates/default contrib-readme-job: - runs-on: ubuntu-latest + runs-on: + group: enclave-ci + labels: [enclave-ci-runner] name: Populate Contributors List # Only run on main branch to avoid branch conflicts if: github.ref == 'refs/heads/main' && !contains(github.event.head_commit.message, 'contrib-readme-action') diff --git a/Cargo.lock b/Cargo.lock index 95088c2a01..cb38cb9fa5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3499,6 +3499,7 @@ version = "0.1.15" dependencies = [ "actix", "anyhow", + "bincode 1.3.3", "e3-crypto", "e3-data", "e3-events", @@ -3510,6 +3511,8 @@ dependencies = [ "e3-zk-prover", "fhe", "fhe-traits", + "ndarray", + "num-bigint", "rand 0.8.5", "rayon", "thiserror 1.0.69", diff --git a/crates/events/src/enclave_event/compute_request/mod.rs b/crates/events/src/enclave_event/compute_request/mod.rs index e339ed9a14..00d31b8c9e 100644 --- a/crates/events/src/enclave_event/compute_request/mod.rs +++ b/crates/events/src/enclave_event/compute_request/mod.rs @@ -83,6 +83,7 @@ impl ToString for ComputeRequest { ComputeRequestKind::Zk(req) => match req { ZkRequest::PkBfv(_) => "ZkPkBfv", ZkRequest::PkGeneration(_) => "ZkPkGeneration", + ZkRequest::ShareComputation(_) => "ZkShareComputation", }, } .to_string() diff --git a/crates/events/src/enclave_event/compute_request/zk.rs b/crates/events/src/enclave_event/compute_request/zk.rs index a89bb530fc..9d5f88d570 100644 --- a/crates/events/src/enclave_event/compute_request/zk.rs +++ b/crates/events/src/enclave_event/compute_request/zk.rs @@ -9,19 +9,37 @@ use derivative::Derivative; use e3_crypto::SensitiveBytes; use e3_fhe_params::BfvPreset; use e3_utils::utility_types::ArcBytes; -use e3_zk_helpers::CiphernodesCommitteeSize; +use e3_zk_helpers::{computation::DkgInputType, CiphernodesCommitteeSize}; use serde::{Deserialize, Serialize}; /// ZK proof generation request variants. #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] pub enum ZkRequest { - /// Generate proof for BFV public key (T0). + /// Generate proof for BFV public key (C0). PkBfv(PkBfvProofRequest), - /// Generate proof for PK generation (T1a). + /// Generate proof for PK generation (C1). PkGeneration(PkGenerationProofRequest), + /// Generate proof for share and esm computation (C2a and C2b). + ShareComputation(ShareComputationProofRequest), } -/// Request to generate a proof for BFV public key generation (T0). +/// Request to generate a proof for share computation (C2a or C2b). +#[derive(Derivative, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[derivative(Debug)] +pub struct ShareComputationProofRequest { + /// Raw secret polynomial bytes (sk or e_sm — witness, encrypted at rest). + pub secret_raw: SensitiveBytes, + /// Bincode-serialized SharedSecret containing Shamir shares (witness, encrypted at rest). + pub secret_sss_raw: SensitiveBytes, + /// Which secret type (SecretKey or SmudgingNoise). + pub dkg_input_type: DkgInputType, + /// BFV preset for parameter resolution. + pub params_preset: BfvPreset, + /// The size of the committee. + pub committee_size: CiphernodesCommitteeSize, +} + +/// Request to generate a proof for BFV public key generation (C0). #[derive(Derivative, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derivative(Debug)] pub struct PkBfvProofRequest { @@ -31,7 +49,7 @@ pub struct PkBfvProofRequest { pub params_preset: BfvPreset, } -/// Request to generate a proof for PK share generation (T1a). +/// Request to generate a proof for PK share generation (C1). #[derive(Derivative, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derivative(Debug)] pub struct PkGenerationProofRequest { @@ -86,6 +104,15 @@ pub enum ZkResponse { PkBfv(PkBfvProofResponse), /// Proof for PK generation (T1a). PkGeneration(PkGenerationProofResponse), + /// Proof for share and esm computation (T2a and T2b). + ShareComputation(ShareComputationProofResponse), +} + +/// Response containing a generated share computation proof. +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +pub struct ShareComputationProofResponse { + pub proof: Proof, + pub dkg_input_type: DkgInputType, } /// Response containing a generated BFV public key proof. @@ -100,6 +127,15 @@ pub struct PkGenerationProofResponse { pub proof: Proof, } +impl ShareComputationProofResponse { + pub fn new(proof: Proof, dkg_input_type: DkgInputType) -> Self { + Self { + proof, + dkg_input_type, + } + } +} + impl PkBfvProofResponse { pub fn new(proof: Proof) -> Self { Self { proof } diff --git a/crates/events/src/enclave_event/mod.rs b/crates/events/src/enclave_event/mod.rs index fba6dce82c..004bfd1924 100644 --- a/crates/events/src/enclave_event/mod.rs +++ b/crates/events/src/enclave_event/mod.rs @@ -36,6 +36,7 @@ mod plaintext_output_published; mod proof; mod publickey_aggregated; mod publish_document; +mod share_computation_proof_signed; mod shutdown; mod signed_proof; mod sync_effect; @@ -83,6 +84,7 @@ pub use plaintext_output_published::*; pub use proof::*; pub use publickey_aggregated::*; pub use publish_document::*; +pub use share_computation_proof_signed::*; pub use shutdown::*; pub use signed_proof::*; use strum::IntoStaticStr; @@ -215,6 +217,7 @@ pub enum EnclaveEventData { TicketSubmitted(TicketSubmitted), PlaintextOutputPublished(PlaintextOutputPublished), PkGenerationProofSigned(PkGenerationProofSigned), + ShareComputationProofSigned(ShareComputationProofSigned), EnclaveError(EnclaveError), E3RequestComplete(E3RequestComplete), E3Failed(E3Failed), @@ -468,6 +471,7 @@ impl EnclaveEventData { EnclaveEventData::DecryptionshareCreated(ref data) => Some(data.e3_id.clone()), EnclaveEventData::PlaintextAggregated(ref data) => Some(data.e3_id.clone()), EnclaveEventData::PkGenerationProofSigned(ref data) => Some(data.e3_id.clone()), + EnclaveEventData::ShareComputationProofSigned(ref data) => Some(data.e3_id.clone()), EnclaveEventData::CiphernodeSelected(ref data) => Some(data.e3_id.clone()), EnclaveEventData::ThresholdShareCreated(ref data) => Some(data.e3_id.clone()), EnclaveEventData::ThresholdSharePending(ref data) => Some(data.e3_id.clone()), @@ -519,6 +523,7 @@ impl_event_types!( PlaintextAggregated, PublishDocumentRequested, PkGenerationProofSigned, + ShareComputationProofSigned, E3RequestComplete, E3Failed, E3StageChanged, diff --git a/crates/events/src/enclave_event/share_computation_proof_signed.rs b/crates/events/src/enclave_event/share_computation_proof_signed.rs new file mode 100644 index 0000000000..0f417ec797 --- /dev/null +++ b/crates/events/src/enclave_event/share_computation_proof_signed.rs @@ -0,0 +1,24 @@ +// 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::{E3id, SignedProofPayload}; +use actix::Message; +use serde::{Deserialize, Serialize}; +use std::fmt::{self, Display}; + +#[derive(Message, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[rtype(result = "()")] +pub struct ShareComputationProofSigned { + pub e3_id: E3id, + pub party_id: u64, + pub signed_proof: SignedProofPayload, +} + +impl Display for ShareComputationProofSigned { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{:?}", self) + } +} diff --git a/crates/events/src/enclave_event/threshold_share_pending.rs b/crates/events/src/enclave_event/threshold_share_pending.rs index be37599881..0f39aee7e0 100644 --- a/crates/events/src/enclave_event/threshold_share_pending.rs +++ b/crates/events/src/enclave_event/threshold_share_pending.rs @@ -4,7 +4,7 @@ // without even the implied warranty of MERCHANTABILITY // or FITNESS FOR A PARTICULAR PURPOSE. -use crate::{E3id, PkGenerationProofRequest, ThresholdShare}; +use crate::{E3id, PkGenerationProofRequest, ShareComputationProofRequest, ThresholdShare}; use actix::Message; use serde::{Deserialize, Serialize}; use std::fmt::{self, Display}; @@ -16,8 +16,12 @@ pub struct ThresholdSharePending { pub e3_id: E3id, /// Full threshold share containing all encrypted shares for all parties pub full_share: Arc, - /// The proof request data for the zk actor + /// The proof request data for C1 (PkGeneration) pub proof_request: PkGenerationProofRequest, + /// The proof request for C2a (SkShareComputation) + pub sk_share_computation_request: ShareComputationProofRequest, + /// The proof request for C2b (ESmShareComputation) + pub e_sm_share_computation_request: ShareComputationProofRequest, } impl Display for ThresholdSharePending { diff --git a/crates/keyshare/src/threshold_keyshare.rs b/crates/keyshare/src/threshold_keyshare.rs index b2a2e3a0f9..590f4599e2 100644 --- a/crates/keyshare/src/threshold_keyshare.rs +++ b/crates/keyshare/src/threshold_keyshare.rs @@ -13,9 +13,10 @@ use e3_events::{ ComputeResponse, ComputeResponseKind, CorrelationId, DecryptionshareCreated, Die, E3RequestComplete, E3id, EType, EnclaveEvent, EnclaveEventData, EncryptionKey, EncryptionKeyCollectionFailed, EncryptionKeyCreated, EncryptionKeyPending, EventContext, - KeyshareCreated, PartyId, PkGenerationProofRequest, PkGenerationProofSigned, Sequenced, - SignedProofPayload, ThresholdShare, ThresholdShareCollectionFailed, ThresholdShareCreated, - ThresholdSharePending, TypedEvent, + KeyshareCreated, PartyId, PkGenerationProofRequest, PkGenerationProofSigned, ProofType, + Sequenced, ShareComputationProofRequest, ShareComputationProofSigned, SignedProofPayload, + ThresholdShare, ThresholdShareCollectionFailed, ThresholdShareCreated, ThresholdSharePending, + TypedEvent, }; use e3_fhe_params::create_deterministic_crp_from_default_seed; use e3_fhe_params::{BfvParamSet, BfvPreset}; @@ -32,6 +33,7 @@ use e3_trbfv::{ }; use e3_utils::{to_ordered_vec, utility_types::ArcBytes}; use e3_utils::{NotifySync, MAILBOX_LIMIT}; +use e3_zk_helpers::computation::DkgInputType; use e3_zk_helpers::CiphernodesCommitteeSize; use fhe::bfv::{PublicKey, SecretKey}; use fhe_traits::{DeserializeParametrized, Serialize}; @@ -99,6 +101,8 @@ pub struct AggregatingDecryptionKey { pk_share: ArcBytes, sk_bfv: SensitiveBytes, signed_pk_generation_proof: Option, + signed_sk_share_computation_proof: Option, + signed_e_sm_share_computation_proof: Option, } #[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] @@ -107,6 +111,8 @@ pub struct ReadyForDecryption { sk_poly_sum: SensitiveBytes, es_poly_sum: Vec, signed_pk_generation_proof: Option, + signed_sk_share_computation_proof: Option, + signed_e_sm_share_computation_proof: Option, } #[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] @@ -115,6 +121,8 @@ pub struct Decrypting { sk_poly_sum: SensitiveBytes, es_poly_sum: Vec, signed_pk_generation_proof: Option, + signed_sk_share_computation_proof: Option, + signed_e_sm_share_computation_proof: Option, } #[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] @@ -445,6 +453,49 @@ impl ThresholdKeyshare { Ok(()) } + /// Handle ShareComputationProofSigned - stores the signed proof in state based on proof type (C1, C2a or C2b) + pub fn handle_share_computation_proof_signed( + &mut self, + msg: TypedEvent, + ) -> Result<()> { + let (msg, ec) = msg.into_components(); + let state = self.state.try_get()?; + + if msg.party_id != state.party_id { + return Ok(()); + } + + let proof_type = msg.signed_proof.payload.proof_type; + info!( + "Received ShareComputationProofSigned ({:?}) for party {} E3 {}", + proof_type, msg.party_id, msg.e3_id + ); + + self.state.try_mutate(&ec, |s| { + let current: AggregatingDecryptionKey = s.clone().try_into()?; + let updated = match proof_type { + ProofType::T1SkShareComputation => AggregatingDecryptionKey { + signed_sk_share_computation_proof: Some(msg.signed_proof), + ..current + }, + ProofType::T1ESmShareComputation => AggregatingDecryptionKey { + signed_e_sm_share_computation_proof: Some(msg.signed_proof), + ..current + }, + other => { + warn!( + "Unexpected proof type {:?} in ShareComputationProofSigned", + other + ); + current + } + }; + s.new_state(KeyshareState::AggregatingDecryptionKey(updated)) + })?; + + Ok(()) + } + pub fn handle_compute_response(&mut self, msg: TypedEvent) -> Result<()> { match &msg.response { ComputeResponseKind::TrBFV(trbfv) => match trbfv { @@ -654,9 +705,8 @@ impl ThresholdKeyshare { let (msg, ec) = msg.into_components(); info!("GenEsiSss on ThresholdKeyshare"); - let evt = msg.ciphernode_selected; - let e_sm_raw_decrypted = ArcBytes::from_bytes(&msg.e_sm_raw.access_raw(&self.cipher)?); - let CiphernodeSelected { e3_id, .. } = evt.clone(); + let e_sm_raw = msg.e_sm_raw; + let CiphernodeSelected { e3_id, .. } = msg.ciphernode_selected; let state = self .state @@ -666,13 +716,10 @@ impl ThresholdKeyshare { let trbfv_config = state.get_trbfv_config(); let event = ComputeRequest::trbfv( - TrBFVRequest::GenEsiSss( - GenEsiSssRequest { - trbfv_config, - e_sm_raw: e_sm_raw_decrypted, - } - .into(), - ), + TrBFVRequest::GenEsiSss(GenEsiSssRequest { + trbfv_config, + e_sm_raw, + }), CorrelationId::new(), e3_id, ); @@ -722,6 +769,8 @@ impl ThresholdKeyshare { pk_share: current.pk_share.expect("pk_share checked above"), sk_bfv: current.sk_bfv, signed_pk_generation_proof: None, + signed_sk_share_computation_proof: None, + signed_e_sm_share_computation_proof: None, }, )) })?; @@ -770,6 +819,21 @@ impl ThresholdKeyshare { .map(|s| s.decrypt(&self.cipher)) .collect::>()?; + // Serialize for T2a/T2b proof requests (encrypted at rest) + let sk_sss_raw = SensitiveBytes::new( + bincode::serialize(&decrypted_sk_sss) + .map_err(|e| anyhow!("Failed to serialize sk_sss: {}", e))?, + &self.cipher, + )?; + let esi_sss_raw: Vec = decrypted_esi_sss + .iter() + .map(|s| { + let bytes = bincode::serialize(s) + .map_err(|e| anyhow!("Failed to serialize esi_sss: {}", e))?; + SensitiveBytes::new(bytes, &self.cipher) + }) + .collect::>()?; + // Encrypt shares for all recipients using BFV let mut rng = OsRng; let encrypted_sk_sss = @@ -794,6 +858,7 @@ impl ThresholdKeyshare { .threshold_counterpart() .ok_or_else(|| anyhow!("No threshold counterpart for {:?}", self.share_enc_preset))?; + // Build T1 request (PkGenerationProof) let proof_request = PkGenerationProofRequest::new( proof_request_data.pk0_share_raw.clone(), proof_request_data.sk_raw.clone(), @@ -803,8 +868,29 @@ impl ThresholdKeyshare { CiphernodesCommitteeSize::Small, // TODO: derive from config ); + // Build T2a request (SkShareComputation) + let sk_share_computation_request = ShareComputationProofRequest { + secret_raw: proof_request_data.sk_raw.clone(), + secret_sss_raw: sk_sss_raw, + dkg_input_type: DkgInputType::SecretKey, + params_preset: threshold_preset, + committee_size: CiphernodesCommitteeSize::Small, + }; + + // Build T2b request (ESmShareComputation) + let e_sm_share_computation_request = ShareComputationProofRequest { + secret_raw: e_sm_raw.clone(), + secret_sss_raw: esi_sss_raw + .into_iter() + .next() + .ok_or_else(|| anyhow!("esi_sss_raw is empty — expected at least one entry"))?, + dkg_input_type: DkgInputType::SmudgingNoise, + params_preset: threshold_preset, + committee_size: CiphernodesCommitteeSize::Small, + }; + info!( - "Publishing ThresholdSharePending for E3 {} (proof will be generated and signed by ProofRequestActor)", + "Publishing ThresholdSharePending for E3 {} (3 proofs: T1, T2a, T2b)", e3_id ); @@ -814,6 +900,8 @@ impl ThresholdKeyshare { e3_id: e3_id.clone(), full_share: Arc::new(full_share), proof_request, + sk_share_computation_request, + e_sm_share_computation_request, }, ec.clone(), )?; @@ -821,8 +909,6 @@ impl ThresholdKeyshare { Ok(()) } - /// 5. AllThresholdSharesCollected. This is fired after the ThresholdShareCreated events are - /// aggregateed in the decryption_key_collector::ThresholdShareCollector /// 5. AllThresholdSharesCollected - Decrypt received shares using BFV and aggregate pub fn handle_all_threshold_shares_collected( &self, @@ -920,6 +1006,8 @@ impl ThresholdKeyshare { sk_poly_sum, es_poly_sum, signed_pk_generation_proof: current.signed_pk_generation_proof, + signed_sk_share_computation_proof: current.signed_sk_share_computation_proof, + signed_e_sm_share_computation_proof: current.signed_e_sm_share_computation_proof, }); s.new_state(next) @@ -960,6 +1048,8 @@ impl ThresholdKeyshare { sk_poly_sum: current.sk_poly_sum, es_poly_sum: current.es_poly_sum, signed_pk_generation_proof: current.signed_pk_generation_proof, + signed_sk_share_computation_proof: current.signed_sk_share_computation_proof, + signed_e_sm_share_computation_proof: current.signed_e_sm_share_computation_proof, }); s.new_state(next) @@ -1046,6 +1136,9 @@ impl Handler for ThresholdKeyshare { EnclaveEventData::PkGenerationProofSigned(data) => { let _ = self.handle_pk_generation_proof_signed(TypedEvent::new(data, ec)); } + EnclaveEventData::ShareComputationProofSigned(data) => { + let _ = self.handle_share_computation_proof_signed(TypedEvent::new(data, ec)); + } EnclaveEventData::E3RequestComplete(data) => self.notify_sync(ctx, data), EnclaveEventData::E3Failed(data) => { warn!( diff --git a/crates/multithread/Cargo.toml b/crates/multithread/Cargo.toml index a8a33b975e..9f414b2ab9 100644 --- a/crates/multithread/Cargo.toml +++ b/crates/multithread/Cargo.toml @@ -9,6 +9,7 @@ repository.workspace = true [dependencies] actix = { workspace = true } anyhow = { workspace = true } +bincode = { workspace = true } e3-data = { workspace = true } e3-fhe-params = { workspace = true } e3-trbfv = { workspace = true } @@ -20,6 +21,8 @@ e3-utils = { workspace = true } e3-zk-prover = { workspace = true } fhe = { workspace = true } fhe-traits = { workspace = true } +ndarray = { workspace = true } +num-bigint = { workspace = true } rand = { workspace = true } rayon = { workspace = true } tokio = { workspace = true } diff --git a/crates/multithread/src/multithread.rs b/crates/multithread/src/multithread.rs index b514980d55..319bbe2fb8 100644 --- a/crates/multithread/src/multithread.rs +++ b/crates/multithread/src/multithread.rs @@ -25,8 +25,10 @@ use e3_events::{ BusHandle, ComputeRequest, ComputeRequestError, ComputeRequestErrorKind, ComputeRequestKind, ComputeResponse, EnclaveEvent, EnclaveEventData, EventPublisher, EventSubscriber, EventType, PkBfvProofRequest, PkBfvProofResponse, PkGenerationProofRequest, PkGenerationProofResponse, - TypedEvent, ZkError as ZkEventError, ZkRequest, ZkResponse, + ShareComputationProofRequest, ShareComputationProofResponse, TypedEvent, + ZkError as ZkEventError, ZkRequest, ZkResponse, }; +use e3_fhe_params::build_pair_for_preset; use e3_fhe_params::{BfvParamSet, BfvPreset}; use e3_polynomial::CrtPolynomial; use e3_trbfv::calculate_decryption_key::calculate_decryption_key; @@ -35,16 +37,22 @@ use e3_trbfv::calculate_threshold_decryption::calculate_threshold_decryption; use e3_trbfv::gen_esi_sss::gen_esi_sss; use e3_trbfv::gen_pk_share_and_sk_sss::gen_pk_share_and_sk_sss; use e3_trbfv::helpers::try_poly_from_bytes; +use e3_trbfv::shares::SharedSecret; use e3_trbfv::{TrBFVError, TrBFVRequest, TrBFVResponse}; use e3_utils::SharedRng; use e3_utils::MAILBOX_LIMIT; use e3_zk_helpers::circuits::dkg::pk::circuit::{PkCircuit, PkCircuitData}; +use e3_zk_helpers::circuits::dkg::share_computation::utils::compute_parity_matrix; use e3_zk_helpers::circuits::threshold::pk_generation::circuit::{ PkGenerationCircuit, PkGenerationCircuitData, }; +use e3_zk_helpers::computation::DkgInputType; +use e3_zk_helpers::dkg::share_computation::{ShareComputationCircuit, ShareComputationCircuitData}; use e3_zk_prover::{Provable, ZkBackend, ZkProver}; use fhe::bfv::PublicKey; use fhe_traits::DeserializeParametrized; +use ndarray::Array2; +use num_bigint::BigInt; use rand::Rng; use tracing::{error, info}; @@ -398,6 +406,9 @@ fn handle_zk_request( ZkRequest::PkGeneration(req) => timefunc("zk_pk_generation", id, || { handle_pk_generation_proof(&prover, &cipher, req, request.clone()) }), + ZkRequest::ShareComputation(req) => timefunc("zk_share_computation", id, || { + handle_share_computation_proof(&prover, &cipher, req, request.clone()) + }), } } @@ -409,6 +420,87 @@ fn make_zk_error(request: &ComputeRequest, msg: String) -> ComputeRequestError { ) } +fn handle_share_computation_proof( + prover: &ZkProver, + cipher: &Cipher, + req: ShareComputationProofRequest, + request: ComputeRequest, +) -> Result { + // 1. Build BFV threshold parameters + let (threshold_params, _dkg_params) = build_pair_for_preset(req.params_preset.clone()) + .map_err(|e| make_zk_error(&request, format!("build_pair_for_preset: {}", e)))?; + + // 2. Decrypt sensitive witness fields + let secret_bytes = req + .secret_raw + .access_raw(cipher) + .map_err(|e| make_zk_error(&request, format!("secret_raw decrypt: {}", e)))?; + let secret_sss_bytes = req + .secret_sss_raw + .access_raw(cipher) + .map_err(|e| make_zk_error(&request, format!("secret_sss_raw decrypt: {}", e)))?; + + // 3. Deserialize secret polynomial + let secret_poly = try_poly_from_bytes(&secret_bytes, &threshold_params) + .map_err(|e| make_zk_error(&request, format!("secret_raw: {}", e)))?; + let mut secret = CrtPolynomial::from_fhe_polynomial(&secret_poly); + if req.dkg_input_type == DkgInputType::SecretKey { + secret + .center(threshold_params.moduli()) + .map_err(|e| make_zk_error(&request, format!("Failed to center polynomial: {}", e)))?; + } + + // 4. Deserialize Shamir shares (bincode-encoded SharedSecret) + let shared_secret: SharedSecret = bincode::deserialize(&secret_sss_bytes) + .map_err(|e| make_zk_error(&request, format!("secret_sss_raw deserialize: {}", e)))?; + + // Convert Vec> → Vec> + let secret_sss: Vec> = shared_secret + .moduli_data() + .iter() + .map(|arr| arr.mapv(|v| BigInt::from(v))) + .collect(); + + // 5. Compute parity matrix + let committee = req.committee_size.values(); + let parity_matrix = + compute_parity_matrix(threshold_params.moduli(), committee.n, committee.threshold) + .map_err(|e| make_zk_error(&request, format!("compute_parity_matrix: {}", e)))?; + + // 6. Build circuit data + let circuit_data = ShareComputationCircuitData { + dkg_input_type: req.dkg_input_type, + secret, + secret_sss, + parity_matrix, + n_parties: committee.n as u32, + threshold: committee.threshold as u32, + }; + + // 7. Generate proof + let circuit = ShareComputationCircuit; + let e3_id_str = request.e3_id.to_string(); + + let proof = circuit + .prove(prover, &req.params_preset, &circuit_data, &e3_id_str) + .map_err(|e| { + ComputeRequestError::new( + ComputeRequestErrorKind::Zk(ZkEventError::ProofGenerationFailed(e.to_string())), + request.clone(), + ) + })?; + + // 8. Return response + Ok(ComputeResponse::zk( + ZkResponse::ShareComputation(ShareComputationProofResponse { + proof, + dkg_input_type: req.dkg_input_type, + }), + request.correlation_id, + request.e3_id, + )) +} + fn handle_pk_generation_proof( prover: &ZkProver, cipher: &Cipher, diff --git a/crates/test-helpers/src/usecase_helpers.rs b/crates/test-helpers/src/usecase_helpers.rs index 54b3039311..3372e9ca60 100644 --- a/crates/test-helpers/src/usecase_helpers.rs +++ b/crates/test-helpers/src/usecase_helpers.rs @@ -81,7 +81,7 @@ pub fn generate_shares_hash_map( &cipher, GenEsiSssRequest { trbfv_config: trbfv_config.clone(), - e_sm_raw: ArcBytes::from_bytes(&e_sm_raw.access_raw(&cipher)?), + e_sm_raw: e_sm_raw.clone(), }, )?; diff --git a/crates/tests/tests/integration.rs b/crates/tests/tests/integration.rs index e4bd5291ac..ad27ea2a9e 100644 --- a/crates/tests/tests/integration.rs +++ b/crates/tests/tests/integration.rs @@ -132,6 +132,42 @@ async fn setup_test_zk_backend() -> (ZkBackend, tempfile::TempDir) { .await .unwrap(); + // Copy T2a (sk_share_computation) circuit + let sk_share_comp_circuit_dir = circuits_dir.join("dkg").join("sk_share_computation"); + tokio::fs::create_dir_all(&sk_share_comp_circuit_dir) + .await + .unwrap(); + tokio::fs::copy( + dkg_target.join("sk_share_computation.json"), + sk_share_comp_circuit_dir.join("sk_share_computation.json"), + ) + .await + .unwrap(); + tokio::fs::copy( + dkg_target.join("sk_share_computation.vk"), + sk_share_comp_circuit_dir.join("sk_share_computation.vk"), + ) + .await + .unwrap(); + + // Copy T2b (e_sm_share_computation) circuit + let e_sm_share_comp_circuit_dir = circuits_dir.join("dkg").join("e_sm_share_computation"); + tokio::fs::create_dir_all(&e_sm_share_comp_circuit_dir) + .await + .unwrap(); + tokio::fs::copy( + dkg_target.join("e_sm_share_computation.json"), + e_sm_share_comp_circuit_dir.join("e_sm_share_computation.json"), + ) + .await + .unwrap(); + tokio::fs::copy( + dkg_target.join("e_sm_share_computation.vk"), + e_sm_share_comp_circuit_dir.join("e_sm_share_computation.vk"), + ) + .await + .unwrap(); + let backend = ZkBackend::new( BBPath::Default(bb_binary), circuits_dir, diff --git a/crates/trbfv/src/gen_esi_sss.rs b/crates/trbfv/src/gen_esi_sss.rs index 7eb473f9f4..213d15e816 100644 --- a/crates/trbfv/src/gen_esi_sss.rs +++ b/crates/trbfv/src/gen_esi_sss.rs @@ -10,7 +10,7 @@ use crate::{ TrBFVConfig, }; use anyhow::{Context, Result}; -use e3_crypto::Cipher; +use e3_crypto::{Cipher, SensitiveBytes}; use e3_utils::{utility_types::ArcBytes, SharedRng}; use fhe::trbfv::ShareManager; use serde::{Deserialize, Serialize}; @@ -20,8 +20,8 @@ use tracing::info; pub struct GenEsiSssRequest { /// TrBFV configuration pub trbfv_config: TrBFVConfig, - /// This is pre-generated smudging noise. - pub e_sm_raw: ArcBytes, + /// Pre-generated smudging noise polynomial (private witness, encrypted at rest). + pub e_sm_raw: SensitiveBytes, } struct InnerRequest { @@ -29,12 +29,12 @@ struct InnerRequest { pub e_sm_raw: ArcBytes, } -impl TryFrom for InnerRequest { - type Error = anyhow::Error; - fn try_from(value: GenEsiSssRequest) -> std::result::Result { +impl GenEsiSssRequest { + fn into_inner(self, cipher: &Cipher) -> Result { + let e_sm_decrypted = self.e_sm_raw.access(cipher)?; Ok(InnerRequest { - trbfv_config: value.trbfv_config, - e_sm_raw: value.e_sm_raw, + trbfv_config: self.trbfv_config, + e_sm_raw: ArcBytes::from_bytes(&e_sm_decrypted), }) } } @@ -74,7 +74,7 @@ pub fn gen_esi_sss( req: GenEsiSssRequest, ) -> Result { info!("gen_esi_sss"); - let req: InnerRequest = req.try_into()?; + let req: InnerRequest = req.into_inner(cipher)?; let params = req.trbfv_config.params(); let threshold = req.trbfv_config.threshold() as usize; @@ -85,7 +85,7 @@ pub fn gen_esi_sss( let e_sm_poly = try_poly_from_bytes(&e_sm_raw, ¶ms)?; let mut share_manager = ShareManager::new(num_ciphernodes, threshold, params.clone()); - info!("gen_esi_sss:generate_smudging_error..."); + info!("gen_esi_sss:generate_secret_shares_from_poly..."); let esi_sss = vec![SharedSecret::from( share_manager diff --git a/crates/trbfv/src/shares/shares.rs b/crates/trbfv/src/shares/shares.rs index 03828616ce..0ddc1f400e 100644 --- a/crates/trbfv/src/shares/shares.rs +++ b/crates/trbfv/src/shares/shares.rs @@ -21,6 +21,10 @@ impl SharedSecret { Self { moduli_data } } + pub fn moduli_data(&self) -> &Vec> { + &self.moduli_data + } + /// Extract one party's complete share across all moduli. pub fn extract_party_share(&self, party_id: usize) -> Result { let Some(first) = self.moduli_data.get(0) else { diff --git a/crates/zk-helpers/src/circuits/computation.rs b/crates/zk-helpers/src/circuits/computation.rs index 0a2d933346..b56391036b 100644 --- a/crates/zk-helpers/src/circuits/computation.rs +++ b/crates/zk-helpers/src/circuits/computation.rs @@ -13,7 +13,7 @@ use serde::{Deserialize, Serialize}; /// Variant for input types for DKG. -#[derive(Clone, Copy, PartialEq, Eq, Debug, Deserialize, Serialize)] +#[derive(Clone, Copy, PartialEq, Eq, Debug, Deserialize, Serialize, Hash)] pub enum DkgInputType { /// The input type that generates shares of a secret key using secret sharing. SecretKey, diff --git a/crates/zk-prover/src/actors/proof_request.rs b/crates/zk-prover/src/actors/proof_request.rs index 170942d18b..c3c91fa453 100644 --- a/crates/zk-prover/src/actors/proof_request.rs +++ b/crates/zk-prover/src/actors/proof_request.rs @@ -14,12 +14,19 @@ use e3_events::{ ComputeResponseKind, CorrelationId, E3id, EnclaveEvent, EnclaveEventData, EncryptionKey, EncryptionKeyCreated, EncryptionKeyPending, EventContext, EventPublisher, EventSubscriber, EventType, PkBfvProofRequest, PkGenerationProofSigned, Proof, ProofPayload, ProofType, - Sequenced, SignedProofPayload, ThresholdShare, ThresholdShareCreated, ThresholdSharePending, - TypedEvent, ZkRequest, ZkResponse, + Sequenced, ShareComputationProofSigned, SignedProofPayload, ThresholdShare, + ThresholdShareCreated, ThresholdSharePending, TypedEvent, ZkRequest, ZkResponse, }; use e3_utils::NotifySync; use tracing::{error, info}; +#[derive(Clone, Debug)] +enum ThresholdProofKind { + PkGeneration, + SkShareComputation, + ESmShareComputation, +} + #[derive(Clone, Debug)] struct PendingProofRequest { e3_id: E3id, @@ -27,9 +34,42 @@ struct PendingProofRequest { } #[derive(Clone, Debug)] -struct PendingThresholdShareProof { +struct PendingThresholdProofs { e3_id: E3id, full_share: Arc, + ec: EventContext, + pk_generation_proof: Option, + sk_share_computation_proof: Option, + e_sm_share_computation_proof: Option, +} + +impl PendingThresholdProofs { + fn new(e3_id: E3id, full_share: Arc, ec: EventContext) -> Self { + Self { + e3_id, + full_share, + ec, + pk_generation_proof: None, + sk_share_computation_proof: None, + e_sm_share_computation_proof: None, + } + } + + fn is_complete(&self) -> bool { + self.pk_generation_proof.is_some() + && self.sk_share_computation_proof.is_some() + && self.e_sm_share_computation_proof.is_some() + } + + fn store_proof(&mut self, kind: &ThresholdProofKind, proof: Proof) { + match kind { + ThresholdProofKind::PkGeneration => self.pk_generation_proof = Some(proof), + ThresholdProofKind::SkShareComputation => self.sk_share_computation_proof = Some(proof), + ThresholdProofKind::ESmShareComputation => { + self.e_sm_share_computation_proof = Some(proof) + } + } + } } /// Core actor that handles encryption key proof requests. @@ -41,7 +81,8 @@ pub struct ProofRequestActor { bus: BusHandle, signer: PrivateKeySigner, pending: HashMap, - pending_threshold: HashMap, + threshold_correlation: HashMap, + pending_threshold: HashMap, } impl ProofRequestActor { @@ -51,6 +92,7 @@ impl ProofRequestActor { signer, pending: HashMap::new(), pending_threshold: HashMap::new(), + threshold_correlation: HashMap::new(), } } @@ -92,25 +134,73 @@ impl ProofRequestActor { fn handle_threshold_share_pending(&mut self, msg: TypedEvent) { let (msg, ec) = msg.into_components(); - let correlation_id = CorrelationId::new(); + let e3_id = msg.e3_id.clone(); + self.pending_threshold.insert( - correlation_id, - PendingThresholdShareProof { - e3_id: msg.e3_id.clone(), - full_share: msg.full_share.clone(), - }, + e3_id.clone(), + PendingThresholdProofs::new(e3_id.clone(), msg.full_share.clone(), ec.clone()), ); - let request = ComputeRequest::zk( - ZkRequest::PkGeneration(msg.proof_request), - correlation_id, - msg.e3_id, + // C1: PkGeneration + let t1_corr = CorrelationId::new(); + self.threshold_correlation + .insert(t1_corr, (e3_id.clone(), ThresholdProofKind::PkGeneration)); + info!("Requesting T1 PkGeneration proof"); + if let Err(err) = self.bus.publish( + ComputeRequest::zk( + ZkRequest::PkGeneration(msg.proof_request), + t1_corr, + e3_id.clone(), + ), + ec.clone(), + ) { + error!("Failed to publish T1 proof request: {err}"); + self.threshold_correlation.remove(&t1_corr); + self.pending_threshold.remove(&e3_id); + return; + } + + // C2a: SkShareComputation + let t2a_corr = CorrelationId::new(); + self.threshold_correlation.insert( + t2a_corr, + (e3_id.clone(), ThresholdProofKind::SkShareComputation), ); + info!("Requesting T2a SkShareComputation proof"); + if let Err(err) = self.bus.publish( + ComputeRequest::zk( + ZkRequest::ShareComputation(msg.sk_share_computation_request), + t2a_corr, + e3_id.clone(), + ), + ec.clone(), + ) { + error!("Failed to publish T2a proof request: {err}"); + self.threshold_correlation + .retain(|_, (eid, _)| *eid != e3_id); + self.pending_threshold.remove(&e3_id); + return; + } - info!("Requesting T1 PkGeneration proof generation"); - if let Err(err) = self.bus.publish(request, ec) { - error!("Failed to publish ZK proof request: {err}"); - self.pending_threshold.remove(&correlation_id); + // C2b: ESmShareComputation + let t2b_corr = CorrelationId::new(); + self.threshold_correlation.insert( + t2b_corr, + (e3_id.clone(), ThresholdProofKind::ESmShareComputation), + ); + info!("Requesting T2b ESmShareComputation proof"); + if let Err(err) = self.bus.publish( + ComputeRequest::zk( + ZkRequest::ShareComputation(msg.e_sm_share_computation_request), + t2b_corr, + e3_id.clone(), + ), + ec.clone(), + ) { + error!("Failed to publish T2b proof request: {err}"); + self.threshold_correlation + .retain(|_, (eid, _)| *eid != e3_id); + self.pending_threshold.remove(&e3_id); } } @@ -121,69 +211,133 @@ impl ProofRequestActor { self.handle_pk_bfv_response(&msg.correlation_id, resp.proof.clone(), &ec); } ComputeResponseKind::Zk(ZkResponse::PkGeneration(resp)) => { - self.handle_pk_generation_response(&msg.correlation_id, resp.proof.clone(), &ec); + self.handle_threshold_proof_response(&msg.correlation_id, resp.proof.clone()); + } + ComputeResponseKind::Zk(ZkResponse::ShareComputation(resp)) => { + self.handle_threshold_proof_response(&msg.correlation_id, resp.proof.clone()); } _ => {} } } - fn handle_pk_generation_response( - &mut self, - correlation_id: &CorrelationId, - proof: Proof, - ec: &EventContext, - ) { - let Some(pending) = self.pending_threshold.remove(correlation_id) else { + fn handle_threshold_proof_response(&mut self, correlation_id: &CorrelationId, proof: Proof) { + let Some((e3_id, kind)) = self.threshold_correlation.remove(correlation_id) else { + return; + }; + + let Some(pending) = self.pending_threshold.get_mut(&e3_id) else { error!( - "Received PkGeneration ComputeResponse with correlation_id {:?} but no matching pending request found.", - correlation_id + "No pending threshold proofs for E3 {} — orphan correlation", + e3_id ); return; }; + info!("Received {:?} proof for E3 {}", kind, e3_id); + pending.store_proof(&kind, proof); + + if pending.is_complete() { + info!("All 3 threshold proofs complete for E3 {}", e3_id); + let pending = self.pending_threshold.remove(&e3_id).unwrap(); + self.publish_threshold_share_with_proofs(pending); + } + } + + fn sign_proof( + &self, + e3_id: &E3id, + proof_type: ProofType, + proof: Proof, + ) -> Option { let payload = ProofPayload { - e3_id: pending.e3_id.clone(), - proof_type: ProofType::T1PkGeneration, - proof: proof.clone(), + e3_id: e3_id.clone(), + proof_type, + proof, }; - - let signed = match SignedProofPayload::sign(payload, &self.signer) { - Ok(s) => { - info!( - "Signed T1 PkGeneration proof for party {} (signer: {})", - pending.full_share.party_id, - self.signer.address() - ); - s - } + match SignedProofPayload::sign(payload, &self.signer) { + Ok(signed) => Some(signed), Err(err) => { - error!("Failed to sign T1 PkGeneration proof payload: {err} — shares will not be published"); - return; + error!("Failed to sign {:?} proof: {err}", proof_type); + None } - }; + } + } + fn publish_threshold_share_with_proofs(&mut self, pending: PendingThresholdProofs) { + let e3_id = &pending.e3_id; let party_id = pending.full_share.party_id; - let e3_id = pending.e3_id.clone(); + let ec = &pending.ec; + + let Some(signed_pk_gen) = self.sign_proof( + e3_id, + ProofType::T1PkGeneration, + pending.pk_generation_proof.expect("checked"), + ) else { + error!("Failed to sign C1 proof — shares will not be published"); + return; + }; + + let Some(signed_sk_share) = self.sign_proof( + e3_id, + ProofType::T1SkShareComputation, + pending.sk_share_computation_proof.expect("checked"), + ) else { + error!("Failed to sign C2a proof — shares will not be published"); + return; + }; + + let Some(signed_e_sm_share) = self.sign_proof( + e3_id, + ProofType::T1ESmShareComputation, + pending.e_sm_share_computation_proof.expect("checked"), + ) else { + error!("Failed to sign C2b proof — shares will not be published"); + return; + }; info!( - "Publishing PkGenerationProofSigned for E3 {} party {}", - pending.e3_id, party_id + "All proofs signed for E3 {} party {} (signer: {})", + e3_id, + party_id, + self.signer.address() ); + + let share = &pending.full_share; + let num_parties = share.num_parties(); + if let Err(err) = self.bus.publish( PkGenerationProofSigned { - e3_id: pending.e3_id, + e3_id: e3_id.clone(), party_id, - signed_proof: signed, + signed_proof: signed_pk_gen, }, ec.clone(), ) { error!("Failed to publish PkGenerationProofSigned: {err}"); } - let share = &pending.full_share; + if let Err(err) = self.bus.publish( + ShareComputationProofSigned { + e3_id: e3_id.clone(), + party_id, + signed_proof: signed_sk_share, + }, + ec.clone(), + ) { + error!("Failed to publish SkShareComputationProofSigned: {err}"); + } + + if let Err(err) = self.bus.publish( + ShareComputationProofSigned { + e3_id: e3_id.clone(), + party_id, + signed_proof: signed_e_sm_share, + }, + ec.clone(), + ) { + error!("Failed to publish ESmShareComputationProofSigned: {err}"); + } - // Publish per-party shares - let num_parties = share.num_parties(); info!( "Publishing ThresholdShareCreated for E3 {} to {} parties", e3_id, num_parties @@ -274,10 +428,14 @@ impl ProofRequestActor { ); } - if let Some(pending) = self.pending_threshold.remove(msg.correlation_id()) { + if let Some((e3_id, kind)) = self.threshold_correlation.remove(msg.correlation_id()) { error!( - "T1 PkShareGeneration proof request failed for E3 {}: {err} — threshold share will not be published without proof", pending.e3_id - ) + "T1 {:?} proof request failed for E3 {}: {err} — threshold share will not be published without proof", + kind, e3_id + ); + self.threshold_correlation + .retain(|_, (eid, _)| *eid != e3_id); + self.pending_threshold.remove(&e3_id); } } } diff --git a/examples/CRISP/server/.env.example b/examples/CRISP/server/.env.example index 0d81df449f..906f1bc646 100644 --- a/examples/CRISP/server/.env.example +++ b/examples/CRISP/server/.env.example @@ -23,7 +23,7 @@ FEE_TOKEN_ADDRESS="0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0" # After this interval, the computation phase starts automatically # After activation + this interval, ciphernodes are then not responsing to # any more decryption requests -E3_DURATION=130 +E3_DURATION=180 E3_THRESHOLD_MIN=2 E3_THRESHOLD_MAX=5 diff --git a/examples/CRISP/test/crisp.spec.ts b/examples/CRISP/test/crisp.spec.ts index 27758a508e..0f26a010dc 100644 --- a/examples/CRISP/test/crisp.spec.ts +++ b/examples/CRISP/test/crisp.spec.ts @@ -44,7 +44,7 @@ async function checkE3Ready(e3id: number): Promise { } } -async function waitForE3Ready(e3id: number, maxWaitMs: number = 30000): Promise { +async function waitForE3Ready(e3id: number, maxWaitMs: number = 80000): Promise { const startTime = Date.now() while (Date.now() - startTime < maxWaitMs) { const isActivated = await checkE3Ready(e3id) diff --git a/templates/default/tests/integration.spec.ts b/templates/default/tests/integration.spec.ts index 8459432531..01c27e423a 100644 --- a/templates/default/tests/integration.spec.ts +++ b/templates/default/tests/integration.spec.ts @@ -162,7 +162,7 @@ describe('Integration', () => { const { waitForEvent } = await setupEventListeners(sdk, store) const threshold: [number, number] = [DEFAULT_E3_CONFIG.threshold_min, DEFAULT_E3_CONFIG.threshold_max] - const duration = 30 + const duration = 70 const inputWindow = await calculateInputWindow(publicClient, duration) const thresholdBfvParams = await sdk.getThresholdBfvParamsSet() const e3ProgramParams = encodeBfvParams(thresholdBfvParams)