From c0447811f4b07d84e18ccf0b1348e60d1d9108b5 Mon Sep 17 00:00:00 2001 From: ryardley Date: Wed, 5 Nov 2025 22:15:26 +0000 Subject: [PATCH 01/61] first pass at integration test --- Cargo.lock | 3 + .../src/threshold_plaintext_aggregator.rs | 8 +- crates/cli/src/cli.rs | 11 +- crates/cli/src/nodes.rs | 22 ++- crates/cli/src/nodes_daemon.rs | 11 +- crates/cli/src/nodes_up.rs | 12 +- crates/cli/src/start.rs | 11 +- crates/entrypoint/src/nodes/daemon.rs | 15 +- crates/entrypoint/src/nodes/up.rs | 11 +- .../entrypoint/src/start/aggregator_start.rs | 19 ++- crates/entrypoint/src/start/start.rs | 19 ++- .../src/enclave_event/publish_document/mod.rs | 28 ++- .../enclave_event/threshold_share_created.rs | 1 + crates/evm/src/enclave_sol_reader.rs | 8 +- crates/keyshare/src/threshold_keyshare.rs | 1 + crates/net/src/dialer.rs | 6 +- crates/net/src/document_publisher.rs | 160 +++++++++++++++--- crates/net/src/events.rs | 8 +- crates/net/src/lib.rs | 1 - crates/net/src/net_event_translator.rs | 40 ++++- crates/net/src/net_interface.rs | 35 +++- crates/test-helpers/Cargo.toml | 1 + crates/test-helpers/src/bin/fake_encrypt.rs | 34 +++- crates/test-helpers/src/lib.rs | 31 ++-- crates/tests/tests/integration_legacy.rs | 15 +- crates/utils/Cargo.toml | 8 +- crates/utils/src/lib.rs | 2 + crates/{net => utils}/src/retry.rs | 0 crates/utils/src/utility_types.rs | 4 + .../scripts/deployEnclave.ts | 2 +- packages/enclave-contracts/tasks/enclave.ts | 15 +- tests/integration/base.sh | 34 +++- tests/integration/enclave.config.yaml | 12 +- tests/integration/fns.sh | 24 +-- tests/integration/persist.sh | 34 +++- 35 files changed, 517 insertions(+), 129 deletions(-) rename crates/{net => utils}/src/retry.rs (100%) diff --git a/Cargo.lock b/Cargo.lock index eaa6cb98e0..eec9f0fcd1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3149,6 +3149,7 @@ dependencies = [ "e3-utils", "fhe", "fhe-traits", + "hex", "rand 0.8.5", "rand_chacha 0.3.1", "tokio", @@ -3236,6 +3237,8 @@ dependencies = [ "rand 0.8.5", "rand_chacha 0.3.1", "serde", + "tokio", + "tracing", ] [[package]] diff --git a/crates/aggregator/src/threshold_plaintext_aggregator.rs b/crates/aggregator/src/threshold_plaintext_aggregator.rs index 9beb053e77..092b438b84 100644 --- a/crates/aggregator/src/threshold_plaintext_aggregator.rs +++ b/crates/aggregator/src/threshold_plaintext_aggregator.rs @@ -22,7 +22,7 @@ use e3_trbfv::{ TrBFVConfig, TrBFVRequest, }; use e3_utils::utility_types::ArcBytes; -use tracing::{error, info, trace}; +use tracing::{debug, error, info, trace}; #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] pub struct Collecting { @@ -247,6 +247,12 @@ impl Handler for ThresholdPlaintextAggregator { type Result = ResponseActFuture>; fn handle(&mut self, event: DecryptionshareCreated, _: &mut Self::Context) -> Self::Result { + let Some(ThresholdPlaintextAggregatorState::Collecting(Collecting { .. })) = + self.state.get() + else { + debug!(state=?self.state, "Aggregator has been closed for collecting so ignoring this event."); + return Box::pin(fut::ready(Ok(()))); + }; info!(event=?event, "Processing DecryptionShareCreated..."); let address = event.node.clone(); let party_id = event.party_id; diff --git a/crates/cli/src/cli.rs b/crates/cli/src/cli.rs index c37fadebd7..f0ce77d13d 100644 --- a/crates/cli/src/cli.rs +++ b/crates/cli/src/cli.rs @@ -61,9 +61,9 @@ pub struct Cli { #[arg(long = "otel", global = true)] pub otel: Option, - // TODO: expose this as a feature once we have this hooked up to the bin integration test - #[arg(long, hide = true)] - pub experimental_trbfv: Option, + /// Enable the experimental TrBFV threshold feature. + #[arg(long, global = true)] + pub experimental_trbfv: bool, } impl Cli { @@ -158,7 +158,9 @@ impl Cli { } match self.command { - Commands::Start { peers } => start::execute(config, peers).await?, + Commands::Start { peers } => { + start::execute(config, peers, self.experimental_trbfv).await? + } Commands::Init { .. } => { bail!("Cannot run `enclave init` when a configuration exists."); } @@ -180,6 +182,7 @@ impl Cli { self.verbose, self.config, self.otel.clone().map(Into::into), + self.experimental_trbfv, ) .await? } diff --git a/crates/cli/src/nodes.rs b/crates/cli/src/nodes.rs index bcd4f0866b..15a2075dc1 100644 --- a/crates/cli/src/nodes.rs +++ b/crates/cli/src/nodes.rs @@ -78,15 +78,33 @@ pub async fn execute( verbose: u8, config_string: Option, otel: Option, + experimental_trbfv: bool, ) -> Result<()> { match command { NodeCommands::Up { detach, exclude } => { - nodes_up::execute(config, detach, exclude, verbose, config_string, otel).await? + nodes_up::execute( + config, + detach, + exclude, + verbose, + config_string, + otel, + experimental_trbfv, + ) + .await? } NodeCommands::Down => nodes_down::execute().await?, NodeCommands::Ps => nodes_ps::execute().await?, NodeCommands::Daemon { exclude } => { - nodes_daemon::execute(config, exclude, verbose, config_string, otel).await? + nodes_daemon::execute( + config, + exclude, + verbose, + config_string, + otel, + experimental_trbfv, + ) + .await? } NodeCommands::Start { id } => nodes_start::execute(&id).await?, NodeCommands::Status { id } => nodes_status::execute(&id).await?, diff --git a/crates/cli/src/nodes_daemon.rs b/crates/cli/src/nodes_daemon.rs index 2909c46456..cbdb44c107 100644 --- a/crates/cli/src/nodes_daemon.rs +++ b/crates/cli/src/nodes_daemon.rs @@ -14,6 +14,15 @@ pub async fn execute( verbose: u8, config_string: Option, otel: Option, + experimental_trbfv: bool, ) -> Result<()> { - daemon::execute(config, exclude, verbose, config_string, otel).await + daemon::execute( + config, + exclude, + verbose, + config_string, + otel, + experimental_trbfv, + ) + .await } diff --git a/crates/cli/src/nodes_up.rs b/crates/cli/src/nodes_up.rs index e894371e9c..198381f1bc 100644 --- a/crates/cli/src/nodes_up.rs +++ b/crates/cli/src/nodes_up.rs @@ -15,6 +15,16 @@ pub async fn execute( verbose: u8, config_string: Option, otel: Option, + experimental_trbfv: bool, ) -> Result<()> { - up::execute(config, detach, exclude, verbose, config_string, otel).await + up::execute( + config, + detach, + exclude, + verbose, + config_string, + otel, + experimental_trbfv, + ) + .await } diff --git a/crates/cli/src/start.rs b/crates/cli/src/start.rs index 91ca8c614e..df3897e6f3 100644 --- a/crates/cli/src/start.rs +++ b/crates/cli/src/start.rs @@ -11,7 +11,11 @@ use e3_entrypoint::helpers::listen_for_shutdown; use tracing::{info, instrument}; #[instrument(skip_all)] -pub async fn execute(mut config: AppConfig, peers: Vec) -> Result<()> { +pub async fn execute( + mut config: AppConfig, + peers: Vec, + experimental_trbfv: bool, +) -> Result<()> { owo(); let Some(address) = config.address() else { @@ -31,12 +35,15 @@ pub async fn execute(mut config: AppConfig, peers: Vec) -> Result<()> { &config, pubkey_write_path, plaintext_write_path, + experimental_trbfv, ) .await? } // Launch in ciphernode configuration - NodeRole::Ciphernode => e3_entrypoint::start::start::execute(&config, address).await?, + NodeRole::Ciphernode => { + e3_entrypoint::start::start::execute(&config, address, experimental_trbfv).await? + } }; info!( diff --git a/crates/entrypoint/src/nodes/daemon.rs b/crates/entrypoint/src/nodes/daemon.rs index 7359b1f511..7d528ae7e4 100644 --- a/crates/entrypoint/src/nodes/daemon.rs +++ b/crates/entrypoint/src/nodes/daemon.rs @@ -53,6 +53,7 @@ impl LaunchCommand { verbose: u8, maybe_config_string: &Option, maybe_otel: &Option, + experimental_trbfv: bool, ) -> Result { let enclave_bin = env::current_exe()?.display().to_string(); let mut args = vec![]; @@ -80,6 +81,10 @@ impl LaunchCommand { args.push(peer.to_string()); } + if experimental_trbfv { + args.push("--experimental-trbfv".to_string()); + } + Ok((enclave_bin, args)) } } @@ -91,6 +96,7 @@ fn extract_commands( verbose: u8, maybe_config_string: Option, maybe_otel: Option, + experimental_trbfv: bool, ) -> Result { let mut exclude_list = exclude.clone(); @@ -111,7 +117,12 @@ fn extract_commands( let mut cmds = HashMap::new(); for item in filtered.iter() { - let params = item.to_params(verbose, &maybe_config_string, &maybe_otel)?; + let params = item.to_params( + verbose, + &maybe_config_string, + &maybe_otel, + experimental_trbfv, + )?; cmds.insert(item.name.clone(), params); } @@ -125,6 +136,7 @@ pub async fn execute( verbose: u8, maybe_config_string: Option, maybe_otel: Option, + experimental_trbfv: bool, ) -> Result<()> { let command_map = extract_commands( config.nodes(), @@ -133,6 +145,7 @@ pub async fn execute( verbose, maybe_config_string, maybe_otel, + experimental_trbfv, )?; let process_manager = Arc::new(Mutex::new(ProcessManager::from(command_map))); diff --git a/crates/entrypoint/src/nodes/up.rs b/crates/entrypoint/src/nodes/up.rs index 8344afce91..062e46d371 100644 --- a/crates/entrypoint/src/nodes/up.rs +++ b/crates/entrypoint/src/nodes/up.rs @@ -19,6 +19,7 @@ pub async fn execute( verbose: u8, maybe_config_string: Option, maybe_otel: Option, + experimental_trbfv: bool, ) -> Result<()> { if client::is_ready().await? { bail!("Swarm is already running!"); @@ -30,7 +31,15 @@ pub async fn execute( } // run the swarm_daemon process locally forwarding args - daemon::execute(config, exclude, verbose, maybe_config_string, maybe_otel).await?; + daemon::execute( + config, + exclude, + verbose, + maybe_config_string, + maybe_otel, + experimental_trbfv, + ) + .await?; Ok(()) } diff --git a/crates/entrypoint/src/start/aggregator_start.rs b/crates/entrypoint/src/start/aggregator_start.rs index d0cfd37d1e..de31b563e3 100644 --- a/crates/entrypoint/src/start/aggregator_start.rs +++ b/crates/entrypoint/src/start/aggregator_start.rs @@ -27,6 +27,7 @@ pub async fn execute( config: &AppConfig, pubkey_write_path: Option, plaintext_write_path: Option, + experimental_trbfv: bool, ) -> Result<(Addr>, JoinHandle>, String)> { let bus = get_enclave_event_bus(); let rng = Arc::new(Mutex::new(ChaCha20Rng::from_rng(OsRng)?)); @@ -34,7 +35,7 @@ pub async fn execute( let repositories = store.repositories(); let cipher = Arc::new(Cipher::from_file(config.key_file()).await?); - CiphernodeBuilder::new(rng.clone(), cipher.clone()) + let mut builder = CiphernodeBuilder::new(rng.clone(), cipher.clone()) .with_source_bus(&bus) .with_datastore(store) .with_chains(&config.chains()) @@ -42,17 +43,23 @@ pub async fn execute( .with_contract_enclave_full() .with_contract_bonding_registry() .with_contract_ciphernode_registry() - .with_plaintext_aggregation() - .with_pubkey_aggregation() - .build() - .await?; + .with_pubkey_aggregation(); - let (_, join_handle, peer_id) = NetEventTranslator::setup_with_interface( + if experimental_trbfv { + builder = builder.with_threshold_plaintext_aggregation(); + } else { + builder = builder.with_plaintext_aggregation() + } + + builder.build().await?; + + let (_, _, join_handle, peer_id) = NetEventTranslator::setup_with_interface( bus.clone(), config.peers(), &cipher, config.quic_port(), repositories.libp2p_keypair(), + experimental_trbfv, ) .await?; diff --git a/crates/entrypoint/src/start/start.rs b/crates/entrypoint/src/start/start.rs index 1fa874a5d6..6f227c94e8 100644 --- a/crates/entrypoint/src/start/start.rs +++ b/crates/entrypoint/src/start/start.rs @@ -26,6 +26,7 @@ use crate::helpers::datastore::setup_datastore; pub async fn execute( config: &AppConfig, address: Address, + experimental_trbfv: bool, ) -> Result<(Addr>, JoinHandle>, String)> { let rng = Arc::new(Mutex::new(rand_chacha::ChaCha20Rng::from_rng(OsRng)?)); @@ -34,25 +35,31 @@ pub async fn execute( let store = setup_datastore(&config, &bus)?; let repositories = store.repositories(); - CiphernodeBuilder::new(rng.clone(), cipher.clone()) + let mut builder = CiphernodeBuilder::new(rng.clone(), cipher.clone()) .with_address(&address.to_string()) - .with_keyshare() .with_source_bus(&bus) .with_datastore(store) .with_sortition_score() .with_chains(&config.chains()) .with_contract_enclave_reader() .with_contract_bonding_registry() - .with_contract_ciphernode_registry() - .build() - .await?; + .with_contract_ciphernode_registry(); - let (_, join_handle, peer_id) = NetEventTranslator::setup_with_interface( + if experimental_trbfv { + builder = builder.with_trbfv(); + } else { + builder = builder.with_keyshare(); + } + + builder.build().await?; + + let (_, _, join_handle, peer_id) = NetEventTranslator::setup_with_interface( bus.clone(), config.peers(), &cipher, config.quic_port(), repositories.libp2p_keypair(), + experimental_trbfv, ) .await?; diff --git a/crates/events/src/enclave_event/publish_document/mod.rs b/crates/events/src/enclave_event/publish_document/mod.rs index 336fdcdce9..e0e3135f03 100644 --- a/crates/events/src/enclave_event/publish_document/mod.rs +++ b/crates/events/src/enclave_event/publish_document/mod.rs @@ -9,15 +9,18 @@ mod filter; use std::fmt::{self, Display}; use actix::Message; -use chrono::{serde::ts_seconds, DateTime, Utc}; +use chrono::{serde::ts_seconds, DateTime, Duration, Utc}; use e3_utils::ArcBytes; use filter::Filter; use serde::{Deserialize, Serialize}; +use tracing::warn; use crate::E3id; pub type PartyId = u64; +const DEFAULT_KADEMLIA_EXPIRY_DAYS: i64 = 30; + /// Diambiguates the kind of document we are looking for #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] pub enum DocumentKind { @@ -44,8 +47,11 @@ impl DocumentMeta { e3_id: E3id, kind: DocumentKind, filter: Vec>, - expires_at: DateTime, + expires_at: Option>, ) -> DocumentMeta { + let expires_at = + expires_at.unwrap_or_else(|| Utc::now() + Duration::days(DEFAULT_KADEMLIA_EXPIRY_DAYS)); + Self { e3_id, expires_at, @@ -76,9 +82,16 @@ pub struct PublishDocumentRequested { pub value: ArcBytes, } +impl PublishDocumentRequested { + pub fn new(meta: DocumentMeta, value: ArcBytes) -> Self { + warn!("Publishing document that is {}", value.size()); + Self { meta, value } + } +} + impl Display for PublishDocumentRequested { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", self.meta) // XXX:: apply ArcBytes and rely on debug once trbfv is merged + write!(f, "{:?}", self) } } @@ -101,7 +114,7 @@ mod tests { E3id::new("1", 1), DocumentKind::TrBFV, vec![Filter::Range(Some(100), Some(200)), Filter::Item(77)], - Utc::now(), + Some(Utc::now()), ); assert_eq!(meta.matches(&21), false); assert_eq!(meta.matches(&77), true); @@ -111,7 +124,12 @@ mod tests { } #[test] fn test_meta_no_filters() { - let meta = DocumentMeta::new(E3id::new("1", 1), DocumentKind::TrBFV, vec![], Utc::now()); + let meta = DocumentMeta::new( + E3id::new("1", 1), + DocumentKind::TrBFV, + vec![], + Some(Utc::now()), + ); assert_eq!(meta.matches(&21), true); assert_eq!(meta.matches(&77), true); assert_eq!(meta.matches(&90), true); diff --git a/crates/events/src/enclave_event/threshold_share_created.rs b/crates/events/src/enclave_event/threshold_share_created.rs index 4514ae2f1c..d07fbd84b1 100644 --- a/crates/events/src/enclave_event/threshold_share_created.rs +++ b/crates/events/src/enclave_event/threshold_share_created.rs @@ -38,6 +38,7 @@ pub struct ThresholdShare { pub struct ThresholdShareCreated { pub e3_id: E3id, pub share: Arc, + pub external: bool, } impl Display for ThresholdShareCreated { diff --git a/crates/evm/src/enclave_sol_reader.rs b/crates/evm/src/enclave_sol_reader.rs index 2549f852db..97871e1129 100644 --- a/crates/evm/src/enclave_sol_reader.rs +++ b/crates/evm/src/enclave_sol_reader.rs @@ -33,10 +33,12 @@ impl From for e3_events::E3Requested { threshold_m: value.0.e3.threshold[0] as usize, threshold_n: value.0.e3.threshold[1] as usize, seed: value.0.e3.seed.into(), + // TODO: this should be delivered from the e3_program. Here we provide a sensible + // default that passes our tests error_size: ArcBytes::from_bytes( - BigUint::from(10000000000000000000000000u128).to_bytes_be(), - ), // XXX: what should be here? - esi_per_ct: 3, // XXX: HARD CODING FOR NOW + BigUint::from(36128399948547143872891754381312u128).to_bytes_be(), + ), + esi_per_ct: 3, // TODO: this should be delivered from the e3_program e3_id: E3id::new(value.0.e3Id.to_string(), value.1), } } diff --git a/crates/keyshare/src/threshold_keyshare.rs b/crates/keyshare/src/threshold_keyshare.rs index 401363b278..1c7572e8ea 100644 --- a/crates/keyshare/src/threshold_keyshare.rs +++ b/crates/keyshare/src/threshold_keyshare.rs @@ -534,6 +534,7 @@ impl ThresholdKeyshare { pk_share, sk_sss, }), + external: false, })); Ok(()) diff --git a/crates/net/src/dialer.rs b/crates/net/src/dialer.rs index dee49daa78..8681bad81d 100644 --- a/crates/net/src/dialer.rs +++ b/crates/net/src/dialer.rs @@ -21,10 +21,8 @@ use tracing::info; use tracing::trace; use tracing::warn; -use crate::{ - events::{NetCommand, NetEvent}, - retry::{retry_with_backoff, to_retry, RetryError, BACKOFF_DELAY, BACKOFF_MAX_RETRIES}, -}; +use crate::events::{NetCommand, NetEvent}; +use e3_utils::{retry_with_backoff, to_retry, RetryError, BACKOFF_DELAY, BACKOFF_MAX_RETRIES}; /// Dial a single Multiaddr with retries and return an error should those retries not work async fn dial_multiaddr( diff --git a/crates/net/src/document_publisher.rs b/crates/net/src/document_publisher.rs index 61187b3727..71762481c7 100644 --- a/crates/net/src/document_publisher.rs +++ b/crates/net/src/document_publisher.rs @@ -8,25 +8,31 @@ use crate::{ events::{ call_and_await_response, DocumentPublishedNotification, GossipData, NetCommand, NetEvent, }, - retry::{retry_with_backoff, to_retry}, Cid, }; use actix::prelude::*; use anyhow::Result; use chrono::{DateTime, Utc}; use e3_events::{ - BusError, CiphernodeSelected, CorrelationId, DocumentReceived, E3RequestComplete, E3id, - EnclaveErrorType, EnclaveEvent, EventBus, PartyId, PublishDocumentRequested, Subscribe, + BusError, CiphernodeSelected, CorrelationId, DocumentKind, DocumentMeta, DocumentReceived, + E3RequestComplete, E3id, EnclaveErrorType, EnclaveEvent, EventBus, PartyId, + PublishDocumentRequested, Subscribe, ThresholdShareCreated, }; +use e3_utils::retry::{retry_with_backoff, to_retry}; use e3_utils::ArcBytes; use futures::TryFutureExt; +use serde::{Deserialize, Serialize}; use std::{ collections::HashMap, sync::Arc, time::{Duration, Instant}, }; use tokio::sync::{broadcast, mpsc}; -use tracing::{debug, error}; +use tracing::{debug, error, info, warn}; + +const KADEMLIA_PUT_TIMEOUT: Duration = Duration::from_secs(30); +const KADEMLIA_GET_TIMEOUT: Duration = Duration::from_secs(30); +const KADEMLIA_BROADCAST_TIMEOUT: Duration = Duration::from_secs(30); /// DocumentPublisher is an actor that monitors events from both the NetInterface and the Enclave /// EventBus in order to manage document publishing interactions. In particular this involves the @@ -69,6 +75,7 @@ impl DocumentPublisher { // Add a list of events with paylods for the DHT match event { EnclaveEvent::PublishDocumentRequested { .. } => true, + EnclaveEvent::ThresholdShareCreated { .. } => true, _ => false, } } @@ -82,6 +89,10 @@ impl DocumentPublisher { ) -> Addr { let mut events = rx.resubscribe(); let addr = Self::new(bus, tx, rx, topic).start(); + + // Convert events + EventConverter::setup(bus); + // Listen on all events bus.do_send(Subscribe::new("*", addr.clone().recipient())); @@ -237,18 +248,8 @@ pub async fn handle_publish_document_requested( 1000, ) .await?; - - broadcast_document_published_notification( - tx, - rx, - DocumentPublishedNotification { - meta: event.meta, - key, - }, - topic, - ) - .await?; - + let notification = DocumentPublishedNotification::new(event.meta, key); + broadcast_document_published_notification(tx, rx, notification, topic).await?; Ok(()) } @@ -316,7 +317,7 @@ async fn put_record( } _ => None, }, - Duration::from_secs(3), + KADEMLIA_PUT_TIMEOUT, ) .await } @@ -342,7 +343,7 @@ async fn get_record( } _ => None, }, - Duration::from_secs(3), + KADEMLIA_GET_TIMEOUT, ) .await } @@ -370,11 +371,122 @@ async fn broadcast_document_published_notification( } _ => None, }, - Duration::from_secs(3), + KADEMLIA_BROADCAST_TIMEOUT, ) .await } +/// Convert between ThresholdShareCreated and DocumentPublished events +pub struct EventConverter { + bus: Addr>, +} + +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +enum ReceivableDocument { + ThresholdShareCreated(ThresholdShareCreated), +} + +impl ReceivableDocument { + pub fn get_e3_id(&self) -> &E3id { + match self { + ReceivableDocument::ThresholdShareCreated(d) => &d.e3_id, + } + } + + pub fn to_bytes(&self) -> Result, bincode::Error> { + bincode::serialize(self) + } + + pub fn from_bytes(bytes: &[u8]) -> Result { + bincode::deserialize(bytes) + } +} + +impl EventConverter { + pub fn new(bus: &Addr>) -> Self { + Self { bus: bus.clone() } + } + + pub fn setup(bus: &Addr>) -> Addr { + let addr = Self::new(bus).start(); + bus.do_send(Subscribe::new("ThresholdShareCreated", addr.clone().into())); + bus.do_send(Subscribe::new("DocumentReceived", addr.clone().into())); + addr + } + + /// Local node created a threshold share. Send it as a published document + pub fn handle_threshold_share_created(&self, msg: ThresholdShareCreated) -> Result<()> { + // If this is received from elsewhere + if msg.external { + return Ok(()); + } + let receivable = ReceivableDocument::ThresholdShareCreated(msg); + let value = ArcBytes::from_bytes(receivable.to_bytes()?); + let meta = DocumentMeta::new( + receivable.get_e3_id().clone(), + DocumentKind::TrBFV, + vec![], + None, + ); + + self.bus + .do_send(EnclaveEvent::from(PublishDocumentRequested::new( + meta, value, + ))); + Ok(()) + } + /// Received document externally + pub fn handle_document_received(&self, msg: DocumentReceived) -> Result<()> { + warn!("Converting DocumentReceived..."); + let receivable = ReceivableDocument::from_bytes(&msg.value.extract_bytes())?; + let event = EnclaveEvent::from(match receivable { + ReceivableDocument::ThresholdShareCreated(evt) => ThresholdShareCreated { + external: true, + e3_id: evt.e3_id, + share: evt.share, + }, + }); + + self.bus.do_send(event); + Ok(()) + } +} + +impl Actor for EventConverter { + type Context = actix::Context; +} + +impl Handler for EventConverter { + type Result = (); + fn handle(&mut self, msg: EnclaveEvent, ctx: &mut Self::Context) -> Self::Result { + match msg { + EnclaveEvent::ThresholdShareCreated { data, .. } => ctx.notify(data), + EnclaveEvent::DocumentReceived { data, .. } => ctx.notify(data), + _ => (), + } + } +} + +impl Handler for EventConverter { + type Result = (); + fn handle(&mut self, msg: ThresholdShareCreated, ctx: &mut Self::Context) -> Self::Result { + match self.handle_threshold_share_created(msg) { + Ok(_) => (), + Err(err) => error!("{err}"), + } + } +} + +impl Handler for EventConverter { + type Result = (); + fn handle(&mut self, msg: DocumentReceived, ctx: &mut Self::Context) -> Self::Result { + match self.handle_document_received(msg) { + Ok(_) => (), + Err(err) => error!("{err}"), + } + } +} + #[cfg(test)] mod tests { use std::{collections::HashMap, num::NonZero, time::Duration}; @@ -435,7 +547,7 @@ mod tests { let (_guard, bus, _net_cmd_tx, mut net_cmd_rx, net_evt_tx, _net_evt_rx, _, _, _) = setup_test(); let value = ArcBytes::from_bytes(b"I am a special document".to_vec()); - let expires_at = Utc::now() + chrono::Duration::days(1); + let expires_at = Some(Utc::now() + chrono::Duration::days(1)); let e3_id = E3id::new("1243", 1); // 1. Send a request to publish @@ -508,7 +620,7 @@ mod tests { setup_test(); let value = b"I am a special document".to_vec(); - let expires_at = Utc::now() + chrono::Duration::days(1); + let expires_at = Some(Utc::now() + chrono::Duration::days(1)); let e3_id = E3id::new("1243", 1); let cid = Cid::from_content(&value); @@ -571,7 +683,7 @@ mod tests { _, ) = setup_test(); let value = ArcBytes::from_bytes(b"I am a special document".to_vec()); - let expires_at = Utc::now() + chrono::Duration::days(1); + let expires_at = Some(Utc::now() + chrono::Duration::days(1)); let e3_id = E3id::new("1243", 1); // Send a request to publish @@ -640,7 +752,7 @@ mod tests { E3id::new("1111", 1), DocumentKind::TrBFV, vec![], - expires_at, + Some(expires_at), ), }), ))?; @@ -654,7 +766,7 @@ mod tests { net_evt_tx.send(NetEvent::GossipData( GossipData::DocumentPublishedNotification(DocumentPublishedNotification { key: cid.clone(), - meta: DocumentMeta::new(e3_id, DocumentKind::TrBFV, vec![], expires_at), + meta: DocumentMeta::new(e3_id, DocumentKind::TrBFV, vec![], Some(expires_at)), }), ))?; diff --git a/crates/net/src/events.rs b/crates/net/src/events.rs index 00307cb822..0dedd10769 100644 --- a/crates/net/src/events.rs +++ b/crates/net/src/events.rs @@ -21,6 +21,7 @@ use std::{ time::{Duration, Instant}, }; use tokio::sync::{broadcast, mpsc}; +use tracing::{info, warn}; /// Incoming/Outgoing GossipData. We disambiguate on concerns relative to the net package. #[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize)] @@ -138,6 +139,8 @@ impl NetEvent { pub fn correlation_id(&self) -> Option { use NetEvent as N; match self { + N::GossipPublished { correlation_id, .. } => Some(*correlation_id), + N::GossipPublishError { correlation_id, .. } => Some(*correlation_id), N::DhtGetRecordError { correlation_id, .. } => Some(*correlation_id), N::DhtGetRecordSucceeded { correlation_id, .. } => Some(*correlation_id), N::DhtPutRecordError { correlation_id, .. } => Some(*correlation_id), @@ -157,6 +160,10 @@ pub struct DocumentPublishedNotification { } impl DocumentPublishedNotification { + pub fn new(meta: DocumentMeta, key: Cid) -> Self { + Self { meta, key } + } + pub fn to_bytes(&self) -> Result> { bincode::serialize(self).context("Could not serialize DocumentPublishedNotification") } @@ -212,6 +219,5 @@ where }) .await .map_err(|_| anyhow::anyhow!(format!("Timed out waiting for response from {}", debug_cmd)))?; - result } diff --git a/crates/net/src/lib.rs b/crates/net/src/lib.rs index 51b3af5e4a..0b9868cd08 100644 --- a/crates/net/src/lib.rs +++ b/crates/net/src/lib.rs @@ -11,7 +11,6 @@ pub mod events; mod net_event_translator; mod net_interface; mod repo; -mod retry; pub use cid::Cid; pub use document_publisher::*; diff --git a/crates/net/src/net_event_translator.rs b/crates/net/src/net_event_translator.rs index df16a44116..b56803c4c9 100644 --- a/crates/net/src/net_event_translator.rs +++ b/crates/net/src/net_event_translator.rs @@ -7,6 +7,7 @@ use crate::events::GossipData; use crate::events::NetCommand; use crate::events::NetEvent; +use crate::DocumentPublisher; use crate::NetInterface; /// Actor for connecting to an libp2p client via it's mpsc channel interface /// This Actor should be responsible for @@ -20,6 +21,7 @@ use std::collections::HashSet; use std::sync::Arc; use tokio::sync::broadcast; use tokio::sync::mpsc; +use tracing::warn; use tracing::{error, info, instrument, trace}; // TODO: store event filtering here on this actor instead of is_local_only() on the event. We @@ -59,11 +61,12 @@ impl NetEventTranslator { } pub fn setup( - bus: Addr>, + bus: &Addr>, tx: &mpsc::Sender, - mut rx: broadcast::Receiver, + rx: &Arc>, topic: &str, ) -> Addr { + let mut rx = rx.resubscribe(); let addr = NetEventTranslator::new(bus.clone(), tx, topic).start(); // Listen on all events @@ -101,7 +104,6 @@ impl NetEventTranslator { EnclaveEvent::KeyshareCreated { .. } => true, EnclaveEvent::PlaintextAggregated { .. } => true, EnclaveEvent::PublicKeyAggregated { .. } => true, - EnclaveEvent::ThresholdShareCreated { .. } => true, _ => false, } } @@ -114,7 +116,13 @@ impl NetEventTranslator { cipher: &Arc, quic_port: u16, repository: Repository>, - ) -> Result<(Addr, tokio::task::JoinHandle>, String)> { + experimental_trbfv: bool, + ) -> Result<( + Addr, + Option>, + tokio::task::JoinHandle>, + String, + )> { let topic = "tmp-enclave-gossip-topic"; // Get existing keypair or generate a new one let mut bytes = match repository.read().await? { @@ -131,11 +139,27 @@ impl NetEventTranslator { let mut interface = NetInterface::new(&keypair, peers, Some(quic_port), topic)?; // Setup and start net event translator - let rx = interface.rx(); - let addr = NetEventTranslator::setup(bus, &interface.tx(), rx, topic); + let rx = &Arc::new(interface.rx()); + let addr = NetEventTranslator::setup(&bus, &interface.tx(), rx, topic); + + // NOTE: + // This is a little rough but having the trbfv switch is short term + // Once we setup permenantly we should refactor to + // We should separate NetInterface from NetEventTranslator + let maybe_publisher = if experimental_trbfv { + Some(DocumentPublisher::setup(&bus, &interface.tx(), rx, topic)) + } else { + None + }; + let handle = tokio::spawn(async move { Ok(interface.start().await?) }); - Ok((addr, handle, keypair.public().to_peer_id().to_string())) + Ok(( + addr, + maybe_publisher, + handle, + keypair.public().to_peer_id().to_string(), + )) } } @@ -175,7 +199,7 @@ impl Handler for NetEventTranslator { trace!(evt_id=%id,"Have seen event before not rebroadcasting!"); return; } - + warn!("GossipPublish event: {}", event.event_type()); match evt.to_bytes() { Ok(data) => { if let Err(e) = tx diff --git a/crates/net/src/net_interface.rs b/crates/net/src/net_interface.rs index 4cf21d3cc0..7949634493 100644 --- a/crates/net/src/net_interface.rs +++ b/crates/net/src/net_interface.rs @@ -14,11 +14,13 @@ use libp2p::{ identify::{self, Behaviour as IdentifyBehaviour}, identity::Keypair, kad::{ - self, store::MemoryStore, Behaviour as KademliaBehaviour, GetRecordOk, QueryId, + self, + store::{MemoryStore, MemoryStoreConfig}, + Behaviour as KademliaBehaviour, Config as KademliaConfig, GetRecordOk, QueryId, QueryResult, Quorum, Record, RecordKey, }, swarm::{dial_opts::DialOpts, NetworkBehaviour, SwarmEvent}, - Swarm, + StreamProtocol, Swarm, }; use std::sync::atomic::AtomicBool; use std::{ @@ -166,6 +168,7 @@ fn create_behaviour( let gossipsub_config = gossipsub::ConfigBuilder::default() .heartbeat_interval(Duration::from_secs(10)) + .max_transmit_size(700 * 1024) .validation_mode(gossipsub::ValidationMode::Strict) .build() .map_err(|msg| Error::new(std::io::ErrorKind::Other, msg))?; @@ -175,8 +178,24 @@ fn create_behaviour( gossipsub_config, )?; + const PROTOCOL_NAME: StreamProtocol = StreamProtocol::new("/ipfs/kad/1.0.0"); + let payload_mb = 10; + let mut config = KademliaConfig::new(PROTOCOL_NAME); + + config + .set_max_packet_size(payload_mb * 1024 * 1024) + .set_query_timeout(Duration::from_secs(30)); + + let store_config = MemoryStoreConfig { + max_records: 1024, + max_value_bytes: payload_mb * 1024 * 1024, + max_providers_per_key: usize::MAX, + max_provided_keys: 1024, + }; + let store = MemoryStore::with_config(peer_id, store_config); + // Setup Kademlia as server so that it responds to events correctly - let mut kademlia = KademliaBehaviour::new(peer_id, MemoryStore::new(peer_id)); + let mut kademlia = KademliaBehaviour::with_config(peer_id, store, config); kademlia.set_mode(Some(kad::Mode::Server)); Ok(NodeBehaviour { @@ -323,7 +342,9 @@ async fn process_swarm_event( let count = swarm.behaviour().gossipsub.mesh_peers(&topic).count(); event_tx.send(NetEvent::GossipSubscribed { count, topic })?; } - _ => {} + unknown => { + trace!("Unknown event: {:?}", unknown); + } }; Ok(()) } @@ -376,8 +397,10 @@ fn handle_gossip_publish( topic: String, correlation_id: CorrelationId, ) -> Result<()> { + let bytes = data.to_bytes()?; + warn!("About to try to Gossip {} bytes", bytes.len()); let gossipsub_behaviour = &mut swarm.behaviour_mut().gossipsub; - match gossipsub_behaviour.publish(gossipsub::IdentTopic::new(topic), data.to_bytes()?) { + match gossipsub_behaviour.publish(gossipsub::IdentTopic::new(topic), bytes) { Ok(message_id) => { event_tx.send(NetEvent::GossipPublished { correlation_id, @@ -385,7 +408,7 @@ fn handle_gossip_publish( })?; } Err(e) => { - warn!(error=?e, "Could not publish to swarm. Retrying..."); + error!(error=?e, "Could not GossipPublish."); event_tx.send(NetEvent::GossipPublishError { correlation_id, error: Arc::new(e), diff --git a/crates/test-helpers/Cargo.toml b/crates/test-helpers/Cargo.toml index ce77f5d76c..518da04118 100644 --- a/crates/test-helpers/Cargo.toml +++ b/crates/test-helpers/Cargo.toml @@ -28,6 +28,7 @@ e3-utils = { workspace = true } e3-sortition = { workspace = true } fhe = { workspace = true } fhe-traits = { workspace = true } +hex = { workspace = true } rand = { workspace = true } rand_chacha = { workspace = true } tokio = { workspace = true } diff --git a/crates/test-helpers/src/bin/fake_encrypt.rs b/crates/test-helpers/src/bin/fake_encrypt.rs index ace5bb1f14..ff5e5e7005 100644 --- a/crates/test-helpers/src/bin/fake_encrypt.rs +++ b/crates/test-helpers/src/bin/fake_encrypt.rs @@ -6,12 +6,27 @@ // This is a test script designed to encrypt some fixed data to a fhe public key use clap::Parser; -use e3_sdk::bfv_helpers::{build_bfv_params_arc, params::SET_2048_1032193_1}; +use e3_sdk::bfv_helpers::{build_bfv_params_arc, decode_bfv_params, params::SET_2048_1032193_1}; use fhe::bfv::{Encoding, Plaintext, PublicKey}; use fhe_traits::{DeserializeParametrized, FheEncoder, FheEncrypter, Serialize}; use rand::SeedableRng; use rand_chacha::ChaCha20Rng; -use std::fs; +use std::{fs, sync::Arc}; + +#[derive(Debug, Clone)] +struct HexBytes(pub Vec); + +fn parse_hex(s: &str) -> Result { + // Remove "0x" or "0X" prefix if present + let s = s + .strip_prefix("0x") + .or_else(|| s.strip_prefix("0X")) + .unwrap_or(s); + // Decode hex string to bytes + hex::decode(s) + .map(HexBytes) + .map_err(|e| format!("Invalid hex string: {}", e)) +} #[derive(Parser, Debug)] #[command(author, version, about, long_about = None)] @@ -24,6 +39,9 @@ struct Args { #[arg(short, long, value_delimiter = ',')] plaintext: Vec, + + #[arg(long, value_parser = parse_hex)] + params: Option, } fn main() -> Result<(), Box> { @@ -32,13 +50,15 @@ fn main() -> Result<(), Box> { // Read the base64 encoded string from the input file println!("Loading public key from {}", args.input); let bytes = fs::read(&args.input)?; - - // Decode the base64 string - let (degree, plaintext_modulus, moduli) = SET_2048_1032193_1; - let params = build_bfv_params_arc(degree, plaintext_modulus, &moduli); + let params = if let Some(params_bytes) = args.params { + Arc::new(decode_bfv_params(¶ms_bytes.0)) + } else { + let (degree, plaintext_modulus, moduli) = SET_2048_1032193_1; + build_bfv_params_arc(degree, plaintext_modulus, &moduli) + }; let pubkey = PublicKey::from_bytes(&bytes, ¶ms)?; - let raw_plaintext = args.plaintext; + println!("Encrypting plaintext: {:?}", raw_plaintext); let pt = Plaintext::try_encode(&raw_plaintext, Encoding::poly(), ¶ms)?; diff --git a/crates/test-helpers/src/lib.rs b/crates/test-helpers/src/lib.rs index b1bfe093b3..46ba9fea7f 100644 --- a/crates/test-helpers/src/lib.rs +++ b/crates/test-helpers/src/lib.rs @@ -18,7 +18,7 @@ use e3_events::{ CiphernodeAdded, EnclaveEvent, EventBus, EventBusConfig, HistoryCollector, Seed, Subscribe, }; use e3_fhe::{create_crp, setup_crp_params, ParamsWithCrp}; -use e3_net::NetEventTranslator; +use e3_net::{DocumentPublisher, NetEventTranslator}; use e3_sdk::bfv_helpers::params::SET_2048_1032193_1; use e3_utils::SharedRng; use fhe::bfv::{BfvParameters, Ciphertext, Encoding, Plaintext, PublicKey}; @@ -137,6 +137,7 @@ pub fn simulate_libp2p_net(nodes: &[CiphernodeHandle]) { // converted to DocumentReceived events NetEventTranslator::is_forwardable_event(e) + || DocumentPublisher::is_document_publisher_event(e) }, dest, ) @@ -190,17 +191,23 @@ impl AddToCommittee { pub fn encrypt_ciphertext( params: &Arc, pubkey: PublicKey, - raw_plaintext: Vec, -) -> Result<(Arc, Vec)> { - let padded = &pad_end(&raw_plaintext, 0, 2048); - let mut bytes = Vec::with_capacity(padded.len() * 8); - for value in padded { - bytes.extend_from_slice(&value.to_le_bytes()); - } - let expected = bytes; - let pt = Plaintext::try_encode(&raw_plaintext, Encoding::poly(), ¶ms)?; - let ciphertext = pubkey.try_encrypt(&pt, &mut ChaCha20Rng::seed_from_u64(42))?; - Ok((Arc::new(ciphertext), expected)) + raw_plaintext: Vec>, +) -> Result<(Vec, Vec)> { + let mut rng = ChaCha20Rng::seed_from_u64(42); + let plaintext = raw_plaintext + .into_iter() + .map(|raw| Ok(Plaintext::try_encode(&raw, Encoding::poly(), &params)?)) + .collect::<Result<Vec<Plaintext>>>()?; + + let ciphertext = plaintext + .iter() + .map(|pt| { + pubkey + .try_encrypt(&pt, &mut rng) + .map_err(|e| anyhow!("{e}")) + }) + .collect::<Result<Vec<Ciphertext>>>()?; + Ok((ciphertext, plaintext)) } fn pad_end(input: &[u64], pad: u64, total: usize) -> Vec<u64> { diff --git a/crates/tests/tests/integration_legacy.rs b/crates/tests/tests/integration_legacy.rs index b961682435..fe7438880c 100644 --- a/crates/tests/tests/integration_legacy.rs +++ b/crates/tests/tests/integration_legacy.rs @@ -165,6 +165,15 @@ fn aggregate_public_key(shares: &Vec<PkSkShareTuple>) -> Result<PublicKey> { #[actix::test] async fn test_public_key_aggregation_and_decryption() -> Result<()> { + use tracing_subscriber::{fmt, EnvFilter}; + + let subscriber = fmt() + .with_env_filter(EnvFilter::new("info")) + .with_test_writer() + .finish(); + + let _guard = tracing::subscriber::set_default(subscriber); + // Setup let (bus, rng, seed, params, crpoly, _, _) = get_common_setup(None)?; let e3_id = E3id::new("1234", 1); @@ -415,9 +424,9 @@ async fn test_p2p_actor_forwards_events_to_network() -> Result<()> { let bus = EventBus::<EnclaveEvent>::new(EventBusConfig { deduplicate: true }).start(); let history_collector = HistoryCollector::<EnclaveEvent>::new().start(); bus.do_send(Subscribe::new("*", history_collector.clone().recipient())); - let event_rx = event_tx.subscribe(); + let event_rx = Arc::new(event_tx.subscribe()); // Pas cmd and event channels to NetEventTranslator - NetEventTranslator::setup(bus.clone(), &cmd_tx, event_rx, "my-topic"); + NetEventTranslator::setup(&bus, &cmd_tx, &event_rx, "my-topic"); // Capture messages from output on msgs vec let msgs: Arc<Mutex<Vec<GossipData>>> = Arc::new(Mutex::new(Vec::new())); @@ -588,7 +597,7 @@ async fn test_p2p_actor_forwards_events_to_bus() -> Result<()> { let history_collector = HistoryCollector::<EnclaveEvent>::new().start(); bus.do_send(Subscribe::new("*", history_collector.clone().recipient())); - NetEventTranslator::setup(bus.clone(), &cmd_tx, event_rx, "mytopic"); + NetEventTranslator::setup(&bus, &cmd_tx, &Arc::new(event_rx), "mytopic"); // Capture messages from output on msgs vec let event = EnclaveEvent::from(E3Requested { diff --git a/crates/utils/Cargo.toml b/crates/utils/Cargo.toml index 458fd315ee..bc2563d2eb 100644 --- a/crates/utils/Cargo.toml +++ b/crates/utils/Cargo.toml @@ -7,10 +7,12 @@ description.workspace = true repository.workspace = true [dependencies] -alloy.workspace = true -derivative.workspace = true -serde.workspace = true actix.workspace = true +alloy.workspace = true anyhow.workspace = true +derivative.workspace = true rand.workspace = true rand_chacha.workspace = true +serde.workspace = true +tokio.workspace = true +tracing.workspace = true diff --git a/crates/utils/src/lib.rs b/crates/utils/src/lib.rs index 19c2ebd0dc..761c59c4f4 100644 --- a/crates/utils/src/lib.rs +++ b/crates/utils/src/lib.rs @@ -8,9 +8,11 @@ pub mod actix; pub mod alloy; pub mod formatters; pub mod helpers; +pub mod retry; pub mod utility_types; pub use actix::*; pub use alloy::*; pub use formatters::*; pub use helpers::*; +pub use retry::*; pub use utility_types::*; diff --git a/crates/net/src/retry.rs b/crates/utils/src/retry.rs similarity index 100% rename from crates/net/src/retry.rs rename to crates/utils/src/retry.rs diff --git a/crates/utils/src/utility_types.rs b/crates/utils/src/utility_types.rs index e92e88350b..539ca35f9c 100644 --- a/crates/utils/src/utility_types.rs +++ b/crates/utils/src/utility_types.rs @@ -29,6 +29,10 @@ impl ArcBytes { pub fn extract_bytes(&self) -> Vec<u8> { (*self.0).clone() } + + pub fn size(&self) -> usize { + self.0.len() + } } impl Deref for ArcBytes { diff --git a/packages/enclave-contracts/scripts/deployEnclave.ts b/packages/enclave-contracts/scripts/deployEnclave.ts index 9951fb8744..3dcb4623f4 100644 --- a/packages/enclave-contracts/scripts/deployEnclave.ts +++ b/packages/enclave-contracts/scripts/deployEnclave.ts @@ -40,7 +40,7 @@ export const deployEnclave = async (withMocks?: boolean) => { ); const THIRTY_DAYS_IN_SECONDS = 60 * 60 * 24 * 30; - const SORTITION_SUBMISSION_WINDOW = 5; + const SORTITION_SUBMISSION_WINDOW = 15; const addressOne = "0x0000000000000000000000000000000000000001"; const poseidonT3 = await deployAndSavePoseidonT3({ hre }); diff --git a/packages/enclave-contracts/tasks/enclave.ts b/packages/enclave-contracts/tasks/enclave.ts index 6cd029d075..6bb3d8ae78 100644 --- a/packages/enclave-contracts/tasks/enclave.ts +++ b/packages/enclave-contracts/tasks/enclave.ts @@ -321,8 +321,21 @@ export const activateE3 = task("e3:activate", "Activate an E3 program") defaultValue: "", type: ArgumentType.STRING, }) + .addOption({ + name: "publicKeyFile", + description: "path to file containing the public key", + defaultValue: "", + type: ArgumentType.STRING, + }) .setAction(async () => ({ - default: async ({ e3Id, publicKey }, hre) => { + default: async ({ e3Id, publicKey: publicKeyArg, publicKeyFile }, hre) => { + const publicKey = + publicKeyArg || + (publicKeyFile ? fs.readFileSync(publicKeyFile, "utf8").trim() : "") || + process.env.PUBLIC_KEY; + + if (!publicKey) throw new Error("No public key provided!"); + const { deployAndSaveEnclave } = await import( "../scripts/deployAndSave/enclave" ); diff --git a/tests/integration/base.sh b/tests/integration/base.sh index 7bc1e979c8..b82472c838 100755 --- a/tests/integration/base.sh +++ b/tests/integration/base.sh @@ -24,6 +24,8 @@ enclave_wallet_set ag "$PRIVATE_KEY_AG" enclave_wallet_set cn1 "$PRIVATE_KEY_CN1" enclave_wallet_set cn2 "$PRIVATE_KEY_CN2" enclave_wallet_set cn3 "$PRIVATE_KEY_CN3" +enclave_wallet_set cn4 "$PRIVATE_KEY_CN4" +enclave_wallet_set cn5 "$PRIVATE_KEY_CN5" # start swarm enclave_nodes_up @@ -43,23 +45,42 @@ pnpm ciphernode:add --ciphernode-address $CIPHERNODE_ADDRESS_2 --network localho heading "Add ciphernode $CIPHERNODE_ADDRESS_3" pnpm ciphernode:add --ciphernode-address $CIPHERNODE_ADDRESS_3 --network localhost +heading "Add ciphernode $CIPHERNODE_ADDRESS_4" +pnpm ciphernode:add --ciphernode-address $CIPHERNODE_ADDRESS_4 --network localhost + +heading "Add ciphernode $CIPHERNODE_ADDRESS_5" +pnpm ciphernode:add --ciphernode-address $CIPHERNODE_ADDRESS_5 --network localhost + heading "Request Committee" -ENCODED_PARAMS=0x$($SCRIPT_DIR/lib/pack_e3_params.sh --moduli 0x3FFFFFFF000001 --degree 2048 --plaintext-modulus 1032193) +ENCODED_PARAMS=0x$($SCRIPT_DIR/lib/pack_e3_params.sh \ + --moduli 0x800000022a0001 \ + --moduli 0x800000021a0001 \ + --moduli 0x80000002120001 \ + --moduli 0x80000001f60001 \ + --degree 8192 \ + --plaintext-modulus 1032193) sleep 4 -pnpm committee:new --network localhost --duration 4 --e3-params "$ENCODED_PARAMS" +pnpm committee:new \ + --network localhost \ + --duration 4 \ + --e3-params "$ENCODED_PARAMS" \ + --threshold-quorum 2 \ + --threshold-total 5 waiton "$SCRIPT_DIR/output/pubkey.bin" + PUBLIC_KEY=$(xxd -p -c 10000000 "$SCRIPT_DIR/output/pubkey.bin") heading "Mock encrypted plaintext" -$SCRIPT_DIR/lib/fake_encrypt.sh --input "$SCRIPT_DIR/output/pubkey.bin" --output "$SCRIPT_DIR/output/output.bin" --plaintext $PLAINTEXT +$SCRIPT_DIR/lib/fake_encrypt.sh --input "$SCRIPT_DIR/output/pubkey.bin" --output "$SCRIPT_DIR/output/output.bin" --plaintext $PLAINTEXT --params "$ENCODED_PARAMS" heading "Mock activate e3-id" -# NOTE: using -s to avoid key spamming output -pnpm -s e3:activate --e3-id 0 --public-key "0x$PUBLIC_KEY" --network localhost +PUBLIC_KEY_FILE=/tmp/enclave-public-key.txt +echo "0x${PUBLIC_KEY}" > $PUBLIC_KEY_FILE +pnpm -s e3:activate --e3-id 0 --network localhost --public-key-file $PUBLIC_KEY_FILE heading "Mock publish input e3-id" pnpm e3:publishInput --network localhost --e3-id 0 --data 0x12345678 @@ -77,6 +98,8 @@ ACTUAL=$(cat $SCRIPT_DIR/output/plaintext.txt) # Assume plaintext is shorter +echo "ACTUAL:" +echo $ACTUAL if [[ "$ACTUAL" != "$PLAINTEXT"* ]]; then echo "Invalid plaintext decrypted: actual='$ACTUAL' expected='$PLAINTEXT'" @@ -103,4 +126,3 @@ echo -e "\033[32m \033[0m" gracefull_shutdown - diff --git a/tests/integration/enclave.config.yaml b/tests/integration/enclave.config.yaml index fcb16eae42..08ce539970 100644 --- a/tests/integration/enclave.config.yaml +++ b/tests/integration/enclave.config.yaml @@ -41,11 +41,21 @@ nodes: quic_port: 9203 autonetkey: true autopassword: true - ag: + cn4: address: "0x15d34AAf54267DB7D7c367839AAf71A00a2C6A65" quic_port: 9204 autonetkey: true autopassword: true + cn5: + address: "0x9965507D1a55bcC2695C58ba16FB37d819B0A4dc" + quic_port: 9205 + autonetkey: true + autopassword: true + ag: + address: "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" + quic_port: 9096 + autonetkey: true + autopassword: true role: type: aggregator pubkey_write_path: "./output/pubkey.bin" diff --git a/tests/integration/fns.sh b/tests/integration/fns.sh index 2251c9f200..a34448772d 100644 --- a/tests/integration/fns.sh +++ b/tests/integration/fns.sh @@ -19,18 +19,17 @@ PRIVATE_KEY_AG="0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff PRIVATE_KEY_CN1="0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d" PRIVATE_KEY_CN2="0x5de4111afa1a4b94908f83103eb1f1706367c2e68ca870fc3fb9a804cdab365a" PRIVATE_KEY_CN3="0x7c852118294e51e653712a81e05800f419141751be58f605c371e15141b007a6" -NETWORK_PRIVATE_KEY_AG="0x51a1e500a548b70d88184a1e042900c0ed6c57f8710bcc35dc8c85fa33d3f580" +PRIVATE_KEY_CN4="0x47e179ec197488593b187f80a00eb0da91f1b9d0b13f8733639f19c30a34926a" +PRIVATE_KEY_CN5="0x8b3a350cf5c34c9194ca85829a2df0ec3153be0318b5e2d3348e872092edffba" CIPHERNODE_SECRET="We are the music makers and we are the dreamers of the dreams." # These are random addresses for now -CIPHERNODE_ADDRESS_1="0x90F79bf6EB2c4f870365E785982E1f101E93b906" -CIPHERNODE_ADDRESS_2="0x70997970C51812dc3A010C7d01b50e0d17dc79C8" -CIPHERNODE_ADDRESS_3="0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC" +CIPHERNODE_ADDRESS_1="0x70997970C51812dc3A010C7d01b50e0d17dc79C8" +CIPHERNODE_ADDRESS_2="0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC" +CIPHERNODE_ADDRESS_3="0x90F79bf6EB2c4f870365E785982E1f101E93b906" +CIPHERNODE_ADDRESS_4="0x15d34AAf54267DB7D7c367839AAf71A00a2C6A65" +CIPHERNODE_ADDRESS_5="0x9965507D1a55bcC2695C58ba16FB37d819B0A4dc" -# These are the network private keys for the ciphernodes -NETWORK_PRIVATE_KEY_1="0x11a1e500a548b70d88184a1e042900c0ed6c57f8710bcc35dc8c85fa33d3f580" -NETWORK_PRIVATE_KEY_2="0x21a1e500a548b70d88184a1e042900c0ed6c57f8710bcc35dc8c85fa33d3f580" -NETWORK_PRIVATE_KEY_3="0x31a1e500a548b70d88184a1e042900c0ed6c57f8710bcc35dc8c85fa33d3f580" if command -v enclave >/dev/null 2>&1; then ENCLAVE_BIN="enclave" @@ -119,9 +118,14 @@ enclave_start() { enclave_nodes_up() { $ENCLAVE_BIN nodes up -v \ - --config "$SCRIPT_DIR/enclave.config.yaml" & + --config "$SCRIPT_DIR/enclave.config.yaml" --experimental-trbfv & } +# enclave_nodes_up() { +# $ENCLAVE_BIN nodes up -v \ +# --config "$SCRIPT_DIR/enclave.config.yaml" & +# } + enclave_nodes_down() { $ENCLAVE_BIN nodes down } @@ -205,5 +209,3 @@ kill_em_all trap 'cleanup $?' ERR INT TERM $SCRIPT_DIR/lib/clean_folders.sh "$SCRIPT_DIR" - - diff --git a/tests/integration/persist.sh b/tests/integration/persist.sh index 480805f3f8..498eb98d2b 100755 --- a/tests/integration/persist.sh +++ b/tests/integration/persist.sh @@ -24,6 +24,8 @@ enclave_wallet_set ag "$PRIVATE_KEY_AG" enclave_wallet_set cn1 "$PRIVATE_KEY_CN1" enclave_wallet_set cn2 "$PRIVATE_KEY_CN2" enclave_wallet_set cn3 "$PRIVATE_KEY_CN3" +enclave_wallet_set cn4 "$PRIVATE_KEY_CN4" +enclave_wallet_set cn5 "$PRIVATE_KEY_CN5" # start swarm enclave_nodes_up @@ -39,11 +41,28 @@ pnpm ciphernode:add --ciphernode-address $CIPHERNODE_ADDRESS_2 --network localho heading "Add ciphernode $CIPHERNODE_ADDRESS_3" pnpm ciphernode:add --ciphernode-address $CIPHERNODE_ADDRESS_3 --network localhost -heading "Request Committee" +heading "Add ciphernode $CIPHERNODE_ADDRESS_4" +pnpm ciphernode:add --ciphernode-address $CIPHERNODE_ADDRESS_4 --network localhost + +heading "Add ciphernode $CIPHERNODE_ADDRESS_5" +pnpm ciphernode:add --ciphernode-address $CIPHERNODE_ADDRESS_5 --network localhost -ENCODED_PARAMS=0x$($SCRIPT_DIR/lib/pack_e3_params.sh --moduli 0x3FFFFFFF000001 --degree 2048 --plaintext-modulus 1032193) +heading "Request Committee" -pnpm committee:new --network localhost --duration 4 --e3-params "$ENCODED_PARAMS" +ENCODED_PARAMS=0x$($SCRIPT_DIR/lib/pack_e3_params.sh \ + --moduli 0x800000022a0001 \ + --moduli 0x800000021a0001 \ + --moduli 0x80000002120001 \ + --moduli 0x80000001f60001 \ + --degree 8192 \ + --plaintext-modulus 1032193) + +pnpm committee:new \ + --network localhost \ + --duration 4 \ + --e3-params "$ENCODED_PARAMS" \ + --threshold-quorum 2 \ + --threshold-total 5 waiton "$SCRIPT_DIR/output/pubkey.bin" PUBLIC_KEY=$(xxd -p -c 10000000 "$SCRIPT_DIR/output/pubkey.bin") @@ -60,11 +79,13 @@ enclave_nodes_start ag sleep 2 heading "Mock encrypted plaintext" -$SCRIPT_DIR/lib/fake_encrypt.sh --input "$SCRIPT_DIR/output/pubkey.bin" --output "$SCRIPT_DIR/output/output.bin" --plaintext $PLAINTEXT +$SCRIPT_DIR/lib/fake_encrypt.sh --input "$SCRIPT_DIR/output/pubkey.bin" --output "$SCRIPT_DIR/output/output.bin" --plaintext $PLAINTEXT --params "$ENCODED_PARAMS" heading "Mock activate e3-id" -# NOTE using -s to avoid key spaming the output -pnpm -s e3:activate --e3-id 0 --public-key "0x$PUBLIC_KEY" --network localhost + +PUBLIC_KEY_FILE=/tmp/enclave-public-key.txt +echo "0x${PUBLIC_KEY}" > $PUBLIC_KEY_FILE +pnpm -s e3:activate --e3-id 0 --network localhost --public-key-file $PUBLIC_KEY_FILE heading "Mock publish input e3-id" pnpm e3:publishInput --network localhost --e3-id 0 --data 0x12345678 @@ -109,4 +130,3 @@ echo -e "\033[32m gracefull_shutdown - From bc79dc13c2ff6c46f89ca7e2f1b5a25c87db6439 Mon Sep 17 00:00:00 2001 From: ryardley <r@blockhackers.io> Date: Wed, 5 Nov 2025 22:38:11 +0000 Subject: [PATCH 02/61] update tests --- crates/tests/tests/integration_legacy.rs | 65 ++++++++++++++++-------- 1 file changed, 44 insertions(+), 21 deletions(-) diff --git a/crates/tests/tests/integration_legacy.rs b/crates/tests/tests/integration_legacy.rs index fe7438880c..16f172a9a5 100644 --- a/crates/tests/tests/integration_legacy.rs +++ b/crates/tests/tests/integration_legacy.rs @@ -246,37 +246,43 @@ async fn test_public_key_aggregation_and_decryption() -> Result<()> { println!("Aggregating decryption..."); // Aggregate decryption - // TODO: - // Making these values large (especially the yes value) requires changing - // the params we use here - as we tune the FHE we need to take care - let raw_plaintext = vec![1234u64, 873827u64]; - let (ciphertext, expected) = encrypt_ciphertext(&params, test_pubkey, raw_plaintext)?; + let raw_plaintext = vec![vec![1234, 567890]]; + let (ciphertext, _) = encrypt_ciphertext(&params, test_pubkey, raw_plaintext.clone())?; // Setup Ciphertext Published Event let ciphertext_published_event = EnclaveEvent::from(CiphertextOutputPublished { - ciphertext_output: vec![ArcBytes::from_bytes(ciphertext.to_bytes())], + ciphertext_output: ciphertext + .iter() + .map(|ct| ArcBytes::from_bytes(ct.to_bytes())) + .collect(), e3_id: e3_id.clone(), }); bus.send(ciphertext_published_event.clone()).await?; - let expected_plaintext_agg_event = PlaintextAggregated { - e3_id: e3_id.clone(), - decrypted_output: vec![ArcBytes::from_bytes(expected.clone())], - }; let history = history_collector .send(TakeEvents::<EnclaveEvent>::new(6)) .await?; - let aggregated_event = history + let event = history .into_iter() .filter_map(|e| match e { EnclaveEvent::PlaintextAggregated { data, .. } => Some(data), _ => None, }) - .collect::<Vec<_>>(); + .collect::<Vec<_>>() + .first() + .unwrap() + .clone(); - assert_eq!(aggregated_event, vec![expected_plaintext_agg_event]); + assert_eq!( + event + .decrypted_output + .iter() + .map(|b| bincode::deserialize::<Vec<u64>>(b).map_err(|e| anyhow!("{e}"))) + .collect::<Result<Vec<Vec<u64>>>>()?, + raw_plaintext + ); Ok(()) } @@ -392,11 +398,14 @@ async fn test_stopped_keyshares_retain_state() -> Result<()> { .aggregate()?; // Publish the ciphertext - let raw_plaintext = vec![1234u64, 873827u64]; - let (ciphertext, expected) = encrypt_ciphertext(&params, pubkey, raw_plaintext)?; + let raw_plaintext = vec![vec![1234u64, 873827u64]]; + let (ciphertext, _) = encrypt_ciphertext(&params, pubkey, raw_plaintext.clone())?; bus.send( EnclaveEvent::from(CiphertextOutputPublished { - ciphertext_output: vec![ArcBytes::from_bytes(ciphertext.to_bytes())], + ciphertext_output: ciphertext + .iter() + .map(|ct| ArcBytes::from_bytes(ct.to_bytes())) + .collect(), e3_id: e3_id.clone(), }) .clone(), @@ -407,11 +416,25 @@ async fn test_stopped_keyshares_retain_state() -> Result<()> { .send(TakeEvents::<EnclaveEvent>::new(5)) .await?; - let actual = history.iter().find_map(|evt| match evt { - EnclaveEvent::PlaintextAggregated { data, .. } => Some(data.decrypted_output.clone()), - _ => None, - }); - assert_eq!(actual, Some(vec![ArcBytes::from_bytes(expected)])); + let event = history + .into_iter() + .filter_map(|e| match e { + EnclaveEvent::PlaintextAggregated { data, .. } => Some(data), + _ => None, + }) + .collect::<Vec<_>>() + .first() + .unwrap() + .clone(); + + assert_eq!( + event + .decrypted_output + .iter() + .map(|b| bincode::deserialize::<Vec<u64>>(b).map_err(|e| anyhow!("{e}"))) + .collect::<Result<Vec<Vec<u64>>>>()?, + raw_plaintext + ); Ok(()) } From 37c56e771d9d7389fdc3e05cf6e4c2f4c248d1ba Mon Sep 17 00:00:00 2001 From: ryardley <r@blockhackers.io> Date: Wed, 5 Nov 2025 22:44:21 +0000 Subject: [PATCH 03/61] remove lines --- crates/entrypoint/src/start/start.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/crates/entrypoint/src/start/start.rs b/crates/entrypoint/src/start/start.rs index 6f227c94e8..6ad6930cb6 100644 --- a/crates/entrypoint/src/start/start.rs +++ b/crates/entrypoint/src/start/start.rs @@ -50,9 +50,7 @@ pub async fn execute( } else { builder = builder.with_keyshare(); } - builder.build().await?; - let (_, _, join_handle, peer_id) = NetEventTranslator::setup_with_interface( bus.clone(), config.peers(), From 06a09ac950b3b26642b118654aa5cd2fdbdc7b08 Mon Sep 17 00:00:00 2001 From: ryardley <r@blockhackers.io> Date: Wed, 5 Nov 2025 22:44:58 +0000 Subject: [PATCH 04/61] remove lines --- crates/events/src/enclave_event/publish_document/mod.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/crates/events/src/enclave_event/publish_document/mod.rs b/crates/events/src/enclave_event/publish_document/mod.rs index e0e3135f03..80c11c5519 100644 --- a/crates/events/src/enclave_event/publish_document/mod.rs +++ b/crates/events/src/enclave_event/publish_document/mod.rs @@ -51,7 +51,6 @@ impl DocumentMeta { ) -> DocumentMeta { let expires_at = expires_at.unwrap_or_else(|| Utc::now() + Duration::days(DEFAULT_KADEMLIA_EXPIRY_DAYS)); - Self { e3_id, expires_at, From e1d554ebe71d8f5d51992650256a6d6ca98bb677 Mon Sep 17 00:00:00 2001 From: ryardley <r@blockhackers.io> Date: Wed, 5 Nov 2025 22:47:32 +0000 Subject: [PATCH 05/61] remove lines --- crates/net/src/document_publisher.rs | 8 +------- crates/net/src/net_event_translator.rs | 5 +---- 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/crates/net/src/document_publisher.rs b/crates/net/src/document_publisher.rs index 71762481c7..989a4d84a7 100644 --- a/crates/net/src/document_publisher.rs +++ b/crates/net/src/document_publisher.rs @@ -28,7 +28,7 @@ use std::{ time::{Duration, Instant}, }; use tokio::sync::{broadcast, mpsc}; -use tracing::{debug, error, info, warn}; +use tracing::{debug, error, warn}; const KADEMLIA_PUT_TIMEOUT: Duration = Duration::from_secs(30); const KADEMLIA_GET_TIMEOUT: Duration = Duration::from_secs(30); @@ -89,10 +89,7 @@ impl DocumentPublisher { ) -> Addr<Self> { let mut events = rx.resubscribe(); let addr = Self::new(bus, tx, rx, topic).start(); - - // Convert events EventConverter::setup(bus); - // Listen on all events bus.do_send(Subscribe::new("*", addr.clone().recipient())); @@ -406,14 +403,12 @@ impl EventConverter { pub fn new(bus: &Addr<EventBus<EnclaveEvent>>) -> Self { Self { bus: bus.clone() } } - pub fn setup(bus: &Addr<EventBus<EnclaveEvent>>) -> Addr<Self> { let addr = Self::new(bus).start(); bus.do_send(Subscribe::new("ThresholdShareCreated", addr.clone().into())); bus.do_send(Subscribe::new("DocumentReceived", addr.clone().into())); addr } - /// Local node created a threshold share. Send it as a published document pub fn handle_threshold_share_created(&self, msg: ThresholdShareCreated) -> Result<()> { // If this is received from elsewhere @@ -428,7 +423,6 @@ impl EventConverter { vec![], None, ); - self.bus .do_send(EnclaveEvent::from(PublishDocumentRequested::new( meta, value, diff --git a/crates/net/src/net_event_translator.rs b/crates/net/src/net_event_translator.rs index b56803c4c9..32f8493f0d 100644 --- a/crates/net/src/net_event_translator.rs +++ b/crates/net/src/net_event_translator.rs @@ -142,10 +142,7 @@ impl NetEventTranslator { let rx = &Arc::new(interface.rx()); let addr = NetEventTranslator::setup(&bus, &interface.tx(), rx, topic); - // NOTE: - // This is a little rough but having the trbfv switch is short term - // Once we setup permenantly we should refactor to - // We should separate NetInterface from NetEventTranslator + // TODO: We should separate NetInterface from NetEventTranslator let maybe_publisher = if experimental_trbfv { Some(DocumentPublisher::setup(&bus, &interface.tx(), rx, topic)) } else { From 298d4866b257dd181d6d68812a37ec6c54b138a4 Mon Sep 17 00:00:00 2001 From: ryardley <r@blockhackers.io> Date: Thu, 6 Nov 2025 01:31:23 +0000 Subject: [PATCH 06/61] fix tests --- crates/fhe/src/fhe.rs | 6 +--- crates/test-helpers/src/lib.rs | 4 +-- crates/tests/tests/integration_legacy.rs | 35 ++++++++++++++---------- 3 files changed, 24 insertions(+), 21 deletions(-) diff --git a/crates/fhe/src/fhe.rs b/crates/fhe/src/fhe.rs index ca5f16942d..1c3728990a 100644 --- a/crates/fhe/src/fhe.rs +++ b/crates/fhe/src/fhe.rs @@ -122,11 +122,7 @@ impl Fhe { .map(|k| DecryptionShare::deserialize(k, &self.params, arc_ct.clone())) .aggregate()?; let decoded = Vec::<u64>::try_decode(&plaintext, Encoding::poly())?; - let mut bytes = Vec::with_capacity(decoded.len() * 8); - for value in decoded { - bytes.extend_from_slice(&value.to_le_bytes()); - } - + let bytes = bincode::serialize(&decoded)?; Ok(bytes) } } diff --git a/crates/test-helpers/src/lib.rs b/crates/test-helpers/src/lib.rs index 46ba9fea7f..3099be4f6b 100644 --- a/crates/test-helpers/src/lib.rs +++ b/crates/test-helpers/src/lib.rs @@ -194,10 +194,10 @@ pub fn encrypt_ciphertext( raw_plaintext: Vec<Vec<u64>>, ) -> Result<(Vec<Ciphertext>, Vec<Plaintext>)> { let mut rng = ChaCha20Rng::seed_from_u64(42); - let plaintext = raw_plaintext + let plaintext: Vec<_> = raw_plaintext .into_iter() .map(|raw| Ok(Plaintext::try_encode(&raw, Encoding::poly(), &params)?)) - .collect::<Result<Vec<Plaintext>>>()?; + .collect::<Result<_>>()?; let ciphertext = plaintext .iter() diff --git a/crates/tests/tests/integration_legacy.rs b/crates/tests/tests/integration_legacy.rs index 16f172a9a5..67ce2c4b90 100644 --- a/crates/tests/tests/integration_legacy.rs +++ b/crates/tests/tests/integration_legacy.rs @@ -30,11 +30,12 @@ use e3_test_helpers::{ }; use e3_utils::utility_types::ArcBytes; use e3_utils::SharedRng; +use fhe::bfv::Encoding; use fhe::{ bfv::{BfvParameters, PublicKey, SecretKey}, mbfv::{AggregateIter, CommonRandomPoly, PublicKeyShare}, }; -use fhe_traits::Serialize; +use fhe_traits::{FheDecoder, Serialize}; use rand::SeedableRng; use rand_chacha::ChaCha20Rng; use std::{sync::Arc, time::Duration}; @@ -247,7 +248,7 @@ async fn test_public_key_aggregation_and_decryption() -> Result<()> { // Aggregate decryption let raw_plaintext = vec![vec![1234, 567890]]; - let (ciphertext, _) = encrypt_ciphertext(&params, test_pubkey, raw_plaintext.clone())?; + let (ciphertext, expected) = encrypt_ciphertext(&params, test_pubkey, raw_plaintext)?; // Setup Ciphertext Published Event let ciphertext_published_event = EnclaveEvent::from(CiphertextOutputPublished { @@ -264,7 +265,7 @@ async fn test_public_key_aggregation_and_decryption() -> Result<()> { .send(TakeEvents::<EnclaveEvent>::new(6)) .await?; - let event = history + let actual = history .into_iter() .filter_map(|e| match e { EnclaveEvent::PlaintextAggregated { data, .. } => Some(data), @@ -276,12 +277,15 @@ async fn test_public_key_aggregation_and_decryption() -> Result<()> { .clone(); assert_eq!( - event + actual .decrypted_output .iter() - .map(|b| bincode::deserialize::<Vec<u64>>(b).map_err(|e| anyhow!("{e}"))) - .collect::<Result<Vec<Vec<u64>>>>()?, - raw_plaintext + .map(|b| bincode::deserialize::<Vec<u64>>(b).unwrap()) + .collect::<Vec<Vec<u64>>>(), + expected + .iter() + .map(|p| Vec::<u64>::try_decode(&p, Encoding::poly()).unwrap()) + .collect::<Vec<Vec<u64>>>() ); Ok(()) @@ -398,8 +402,8 @@ async fn test_stopped_keyshares_retain_state() -> Result<()> { .aggregate()?; // Publish the ciphertext - let raw_plaintext = vec![vec![1234u64, 873827u64]]; - let (ciphertext, _) = encrypt_ciphertext(&params, pubkey, raw_plaintext.clone())?; + let raw_plaintext = vec![vec![1234, 567890]]; + let (ciphertext, expected) = encrypt_ciphertext(&params, pubkey, raw_plaintext)?; bus.send( EnclaveEvent::from(CiphertextOutputPublished { ciphertext_output: ciphertext @@ -416,7 +420,7 @@ async fn test_stopped_keyshares_retain_state() -> Result<()> { .send(TakeEvents::<EnclaveEvent>::new(5)) .await?; - let event = history + let actual = history .into_iter() .filter_map(|e| match e { EnclaveEvent::PlaintextAggregated { data, .. } => Some(data), @@ -428,12 +432,15 @@ async fn test_stopped_keyshares_retain_state() -> Result<()> { .clone(); assert_eq!( - event + actual .decrypted_output .iter() - .map(|b| bincode::deserialize::<Vec<u64>>(b).map_err(|e| anyhow!("{e}"))) - .collect::<Result<Vec<Vec<u64>>>>()?, - raw_plaintext + .map(|b| bincode::deserialize::<Vec<u64>>(b).unwrap()) + .collect::<Vec<Vec<u64>>>(), + expected + .iter() + .map(|p| Vec::<u64>::try_decode(&p, Encoding::poly()).unwrap()) + .collect::<Vec<Vec<u64>>>() ); Ok(()) From 52db4d960d979b7dbb0e6f5da4d40cda08094d23 Mon Sep 17 00:00:00 2001 From: ryardley <r@blockhackers.io> Date: Thu, 6 Nov 2025 01:43:49 +0000 Subject: [PATCH 07/61] fix linting --- crates/test-helpers/src/bin/fake_encrypt.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/test-helpers/src/bin/fake_encrypt.rs b/crates/test-helpers/src/bin/fake_encrypt.rs index bd8a794716..8f59f72c5d 100644 --- a/crates/test-helpers/src/bin/fake_encrypt.rs +++ b/crates/test-helpers/src/bin/fake_encrypt.rs @@ -6,7 +6,7 @@ // This is a test script designed to encrypt some fixed data to a fhe public key use clap::Parser; -use e3_sdk::bfv_helpers::{decode_bfv_params}; +use e3_sdk::bfv_helpers::decode_bfv_params; use e3_sdk::bfv_helpers::{build_bfv_params_from_set_arc, params::SET_2048_1032193_1}; use fhe::bfv::{Encoding, Plaintext, PublicKey}; use fhe_traits::{DeserializeParametrized, FheEncoder, FheEncrypter, Serialize}; From 4eb3747d05b76dbfb10c66667c8b0f6a9bc4a60f Mon Sep 17 00:00:00 2001 From: ryardley <r@blockhackers.io> Date: Thu, 6 Nov 2025 01:47:39 +0000 Subject: [PATCH 08/61] lines --- crates/entrypoint/src/start/aggregator_start.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/crates/entrypoint/src/start/aggregator_start.rs b/crates/entrypoint/src/start/aggregator_start.rs index de31b563e3..8260ddf199 100644 --- a/crates/entrypoint/src/start/aggregator_start.rs +++ b/crates/entrypoint/src/start/aggregator_start.rs @@ -50,9 +50,7 @@ pub async fn execute( } else { builder = builder.with_plaintext_aggregation() } - builder.build().await?; - let (_, _, join_handle, peer_id) = NetEventTranslator::setup_with_interface( bus.clone(), config.peers(), From 63fde17cfe609ae3968ed4f1ad47d4bcfbdec331 Mon Sep 17 00:00:00 2001 From: ryardley <r@blockhackers.io> Date: Thu, 6 Nov 2025 01:48:35 +0000 Subject: [PATCH 09/61] lines --- crates/events/src/enclave_event/publish_document/mod.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/crates/events/src/enclave_event/publish_document/mod.rs b/crates/events/src/enclave_event/publish_document/mod.rs index 80c11c5519..91b476a885 100644 --- a/crates/events/src/enclave_event/publish_document/mod.rs +++ b/crates/events/src/enclave_event/publish_document/mod.rs @@ -18,7 +18,6 @@ use tracing::warn; use crate::E3id; pub type PartyId = u64; - const DEFAULT_KADEMLIA_EXPIRY_DAYS: i64 = 30; /// Diambiguates the kind of document we are looking for From bd515643fe139de967258aefd4fa8859962bcb96 Mon Sep 17 00:00:00 2001 From: ryardley <r@blockhackers.io> Date: Thu, 6 Nov 2025 01:49:14 +0000 Subject: [PATCH 10/61] lines --- crates/net/src/document_publisher.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/crates/net/src/document_publisher.rs b/crates/net/src/document_publisher.rs index 989a4d84a7..c8e946724b 100644 --- a/crates/net/src/document_publisher.rs +++ b/crates/net/src/document_publisher.rs @@ -33,7 +33,6 @@ use tracing::{debug, error, warn}; const KADEMLIA_PUT_TIMEOUT: Duration = Duration::from_secs(30); const KADEMLIA_GET_TIMEOUT: Duration = Duration::from_secs(30); const KADEMLIA_BROADCAST_TIMEOUT: Duration = Duration::from_secs(30); - /// DocumentPublisher is an actor that monitors events from both the NetInterface and the Enclave /// EventBus in order to manage document publishing interactions. In particular this involves the /// interactions of publishing a document and listening for notifications, determining if the node From acf870770f6db5ca9d93bc7968bbcf84a3213158 Mon Sep 17 00:00:00 2001 From: ryardley <r@blockhackers.io> Date: Thu, 6 Nov 2025 01:50:42 +0000 Subject: [PATCH 11/61] lines --- crates/net/src/net_event_translator.rs | 3 +-- crates/net/src/net_interface.rs | 3 --- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/crates/net/src/net_event_translator.rs b/crates/net/src/net_event_translator.rs index 32f8493f0d..18aa0cbb4a 100644 --- a/crates/net/src/net_event_translator.rs +++ b/crates/net/src/net_event_translator.rs @@ -123,6 +123,7 @@ impl NetEventTranslator { tokio::task::JoinHandle<Result<()>>, String, )> { + // TODO: We should separate NetInterface from NetEventTranslator let topic = "tmp-enclave-gossip-topic"; // Get existing keypair or generate a new one let mut bytes = match repository.read().await? { @@ -141,8 +142,6 @@ impl NetEventTranslator { // Setup and start net event translator let rx = &Arc::new(interface.rx()); let addr = NetEventTranslator::setup(&bus, &interface.tx(), rx, topic); - - // TODO: We should separate NetInterface from NetEventTranslator let maybe_publisher = if experimental_trbfv { Some(DocumentPublisher::setup(&bus, &interface.tx(), rx, topic)) } else { diff --git a/crates/net/src/net_interface.rs b/crates/net/src/net_interface.rs index 7949634493..29db0ed335 100644 --- a/crates/net/src/net_interface.rs +++ b/crates/net/src/net_interface.rs @@ -181,11 +181,9 @@ fn create_behaviour( const PROTOCOL_NAME: StreamProtocol = StreamProtocol::new("/ipfs/kad/1.0.0"); let payload_mb = 10; let mut config = KademliaConfig::new(PROTOCOL_NAME); - config .set_max_packet_size(payload_mb * 1024 * 1024) .set_query_timeout(Duration::from_secs(30)); - let store_config = MemoryStoreConfig { max_records: 1024, max_value_bytes: payload_mb * 1024 * 1024, @@ -193,7 +191,6 @@ fn create_behaviour( max_provided_keys: 1024, }; let store = MemoryStore::with_config(peer_id, store_config); - // Setup Kademlia as server so that it responds to events correctly let mut kademlia = KademliaBehaviour::with_config(peer_id, store, config); kademlia.set_mode(Some(kad::Mode::Server)); From 243091b1146e517ec148f28a1d90f3f258e44761 Mon Sep 17 00:00:00 2001 From: ryardley <r@blockhackers.io> Date: Thu, 6 Nov 2025 02:35:23 +0000 Subject: [PATCH 12/61] get integration tests working --- crates/test-helpers/src/plaintext_writer.rs | 7 +-- .../enclave-contracts/deployed_contracts.json | 44 ++++++++++++++++++- tests/integration/base.sh | 3 +- tests/integration/persist.sh | 3 +- 4 files changed, 46 insertions(+), 11 deletions(-) diff --git a/crates/test-helpers/src/plaintext_writer.rs b/crates/test-helpers/src/plaintext_writer.rs index a0267d0aaa..5c157a2875 100644 --- a/crates/test-helpers/src/plaintext_writer.rs +++ b/crates/test-helpers/src/plaintext_writer.rs @@ -37,16 +37,11 @@ impl Handler<EnclaveEvent> for PlaintextWriter { type Result = (); fn handle(&mut self, msg: EnclaveEvent, _: &mut Self::Context) -> Self::Result { if let EnclaveEvent::PlaintextAggregated { data, .. } = msg.clone() { - // HACK: decrypted output will be an array of ArcBytes and we will use this moving forward. For now - // only having the plaintext writer compatible with legacy tests and extracting the first value let Some(decrypted) = data.decrypted_output.first() else { error!("Decrypted output must not be empty!"); return; }; - let output: Vec<u64> = decrypted - .chunks_exact(8) - .map(|chunk| u64::from_le_bytes(chunk.try_into().unwrap())) - .collect(); + let output: Vec<u64> = bincode::deserialize(decrypted).unwrap(); info!(path = ?&self.path, "Writing Plaintext To Path"); let contents: Vec<String> = output.iter().map(|&num| num.to_string()).collect(); diff --git a/packages/enclave-contracts/deployed_contracts.json b/packages/enclave-contracts/deployed_contracts.json index cf2ffe77d8..ada5eef523 100644 --- a/packages/enclave-contracts/deployed_contracts.json +++ b/packages/enclave-contracts/deployed_contracts.json @@ -116,7 +116,7 @@ }, "localhost": { "PoseidonT3": { - "blockNumber": 3, + "blockNumber": 86, "address": "0x3333333C0A88F9BE4fd23ed0536F9B6c427e3B93" }, "MockUSDC": { @@ -164,6 +164,48 @@ }, "blockNumber": 9, "address": "0xa513E6E4b8f2a923D98304ec87F64353C4D5C853" + }, + "CiphernodeRegistryOwnable": { + "constructorArgs": { + "owner": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", + "enclaveAddress": "0x0000000000000000000000000000000000000001", + "submissionWindow": "15" + }, + "blockNumber": 10, + "address": "0x2279B7A0a67DB372996a5FaB50D91eAA73d2eBe6" + }, + "Enclave": { + "constructorArgs": { + "owner": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", + "registry": "0x2279B7A0a67DB372996a5FaB50D91eAA73d2eBe6", + "bondingRegistry": "0xa513E6E4b8f2a923D98304ec87F64353C4D5C853", + "feeToken": "0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0", + "maxDuration": "2592000", + "params": [ + "0x000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000fc00100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000003fffffff000001" + ] + }, + "blockNumber": 11, + "address": "0x8A791620dd6260079BF849Dc5567aDC3F2FdC318" + }, + "MockComputeProvider": { + "blockNumber": 20, + "address": "0x68B1D87F95878fE05B998F19b66F4baba5De1aed" + }, + "MockDecryptionVerifier": { + "blockNumber": 21, + "address": "0x3Aa5ebB10DC797CAC828524e59A333d0A371443c" + }, + "MockInputValidator": { + "blockNumber": 22, + "address": "0xc6e7DF5E7b4f2A278906862b61205850344D4e7d" + }, + "MockE3Program": { + "constructorArgs": { + "mockInputValidator": "0xc6e7DF5E7b4f2A278906862b61205850344D4e7d" + }, + "blockNumber": 23, + "address": "0x59b670e9fA9D0A427751Af201D676719a970857b" } } } \ No newline at end of file diff --git a/tests/integration/base.sh b/tests/integration/base.sh index b82472c838..1a9fb9bcd9 100755 --- a/tests/integration/base.sh +++ b/tests/integration/base.sh @@ -94,8 +94,7 @@ pnpm e3:publishCiphertext --e3-id 0 --network localhost --data-file "$SCRIPT_DIR waiton "$SCRIPT_DIR/output/plaintext.txt" -ACTUAL=$(cat $SCRIPT_DIR/output/plaintext.txt) - +ACTUAL=$(cut -d',' -f1,2 $SCRIPT_DIR/output/plaintext.txt) # Assume plaintext is shorter echo "ACTUAL:" diff --git a/tests/integration/persist.sh b/tests/integration/persist.sh index 498eb98d2b..16187d3fc6 100755 --- a/tests/integration/persist.sh +++ b/tests/integration/persist.sh @@ -99,8 +99,7 @@ pnpm e3:publishCiphertext --e3-id 0 --network localhost --data-file "$SCRIPT_DIR waiton "$SCRIPT_DIR/output/plaintext.txt" -ACTUAL=$(cat $SCRIPT_DIR/output/plaintext.txt) - +ACTUAL=$(cut -d',' -f1,2 $SCRIPT_DIR/output/plaintext.txt) # Assume plaintext is shorter From eea703304116bd37d1bebdbfdbaf7fd3bd32e246 Mon Sep 17 00:00:00 2001 From: ryardley <r@blockhackers.io> Date: Thu, 6 Nov 2025 02:41:49 +0000 Subject: [PATCH 13/61] split the diff on submission window --- packages/enclave-contracts/scripts/deployEnclave.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/enclave-contracts/scripts/deployEnclave.ts b/packages/enclave-contracts/scripts/deployEnclave.ts index 3dcb4623f4..e6779b5f83 100644 --- a/packages/enclave-contracts/scripts/deployEnclave.ts +++ b/packages/enclave-contracts/scripts/deployEnclave.ts @@ -40,7 +40,7 @@ export const deployEnclave = async (withMocks?: boolean) => { ); const THIRTY_DAYS_IN_SECONDS = 60 * 60 * 24 * 30; - const SORTITION_SUBMISSION_WINDOW = 15; + const SORTITION_SUBMISSION_WINDOW = 10; const addressOne = "0x0000000000000000000000000000000000000001"; const poseidonT3 = await deployAndSavePoseidonT3({ hre }); From aa3f491418bb56c12a30bfdc9ba5fb50ec69966e Mon Sep 17 00:00:00 2001 From: ryardley <r@blockhackers.io> Date: Thu, 6 Nov 2025 02:51:26 +0000 Subject: [PATCH 14/61] extract constants --- crates/net/src/net_interface.rs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/crates/net/src/net_interface.rs b/crates/net/src/net_interface.rs index 29db0ed335..dd517fe871 100644 --- a/crates/net/src/net_interface.rs +++ b/crates/net/src/net_interface.rs @@ -32,6 +32,10 @@ use std::{io::Error, time::Duration}; use tokio::{select, sync::broadcast, sync::mpsc}; use tracing::{debug, error, info, trace, warn}; +const PROTOCOL_NAME: StreamProtocol = StreamProtocol::new("/ipfs/kad/1.0.0"); +const MAX_KADEMLIA_PAYLOAD_MB: usize = 10; +const MAX_GOSSIP_MSG_SIZE_KB: usize = 700; + use crate::events::{GossipData, NetCommand}; use crate::events::{NetEvent, PutOrStoreError}; use crate::{dialer::dial_peers, Cid}; @@ -168,7 +172,7 @@ fn create_behaviour( let gossipsub_config = gossipsub::ConfigBuilder::default() .heartbeat_interval(Duration::from_secs(10)) - .max_transmit_size(700 * 1024) + .max_transmit_size(MAX_GOSSIP_MSG_SIZE_KB * 1024) .validation_mode(gossipsub::ValidationMode::Strict) .build() .map_err(|msg| Error::new(std::io::ErrorKind::Other, msg))?; @@ -178,15 +182,13 @@ fn create_behaviour( gossipsub_config, )?; - const PROTOCOL_NAME: StreamProtocol = StreamProtocol::new("/ipfs/kad/1.0.0"); - let payload_mb = 10; let mut config = KademliaConfig::new(PROTOCOL_NAME); config - .set_max_packet_size(payload_mb * 1024 * 1024) + .set_max_packet_size(MAX_KADEMLIA_PAYLOAD_MB * 1024 * 1024) .set_query_timeout(Duration::from_secs(30)); let store_config = MemoryStoreConfig { max_records: 1024, - max_value_bytes: payload_mb * 1024 * 1024, + max_value_bytes: MAX_KADEMLIA_PAYLOAD_MB * 1024 * 1024, max_providers_per_key: usize::MAX, max_provided_keys: 1024, }; From ac22ab6dfec5998157412dae2fd5fbc8d74bb7e0 Mon Sep 17 00:00:00 2001 From: ryardley <r@blockhackers.io> Date: Thu, 6 Nov 2025 03:54:58 +0000 Subject: [PATCH 15/61] use more nodes --- examples/CRISP/enclave.config.yaml | 12 +++++++++++- examples/CRISP/scripts/dev_cipher.sh | 8 ++++++++ examples/CRISP/server/.env.example | 4 ++-- tests/integration/enclave.config.yaml | 2 +- 4 files changed, 22 insertions(+), 4 deletions(-) diff --git a/examples/CRISP/enclave.config.yaml b/examples/CRISP/enclave.config.yaml index 6119452800..45bd0d7664 100644 --- a/examples/CRISP/enclave.config.yaml +++ b/examples/CRISP/enclave.config.yaml @@ -41,10 +41,20 @@ nodes: quic_port: 9203 autonetkey: true autopassword: true - ag: + cn4: address: "0x15d34AAf54267DB7D7c367839AAf71A00a2C6A65" quic_port: 9204 autonetkey: true autopassword: true + cn5: + address: "0x9965507D1a55bcC2695C58ba16FB37d819B0A4dc" + quic_port: 9205 + autonetkey: true + autopassword: true + ag: + address: "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" + quic_port: 9206 + autonetkey: true + autopassword: true role: type: aggregator diff --git a/examples/CRISP/scripts/dev_cipher.sh b/examples/CRISP/scripts/dev_cipher.sh index 2ca9dbb6c2..809cba8152 100755 --- a/examples/CRISP/scripts/dev_cipher.sh +++ b/examples/CRISP/scripts/dev_cipher.sh @@ -10,11 +10,15 @@ PRIVATE_KEY_AG="0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff PRIVATE_KEY_CN1="0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d" PRIVATE_KEY_CN2="0x5de4111afa1a4b94908f83103eb1f1706367c2e68ca870fc3fb9a804cdab365a" PRIVATE_KEY_CN3="0x7c852118294e51e653712a81e05800f419141751be58f605c371e15141b007a6" +PRIVATE_KEY_CN4="0x47e179ec197488593b187f80a00eb0da91f1b9d0b13f8733639f19c30a34926a" +PRIVATE_KEY_CN5="0x8b3a350cf5c34c9194ca85829a2df0ec3153be0318b5e2d3348e872092edffba" enclave wallet set --name ag --private-key "$PRIVATE_KEY_AG" enclave wallet set --name cn1 --private-key "$PRIVATE_KEY_CN1" enclave wallet set --name cn2 --private-key "$PRIVATE_KEY_CN2" enclave wallet set --name cn3 --private-key "$PRIVATE_KEY_CN3" +enclave wallet set --name cn4 --private-key "$PRIVATE_KEY_CN4" +enclave wallet set --name cn5 --private-key "$PRIVATE_KEY_CN5" # using & instead of -d so that wait works below enclave nodes up -v & @@ -24,10 +28,14 @@ sleep 2 CN1=$(cat ./enclave.config.yaml | yq -r '.nodes.cn1.address') CN2=$(cat ./enclave.config.yaml | yq -r '.nodes.cn2.address') CN3=$(cat ./enclave.config.yaml | yq -r '.nodes.cn3.address') +CN4=$(cat ./enclave.config.yaml | yq -r '.nodes.cn4.address') +CN5=$(cat ./enclave.config.yaml | yq -r '.nodes.cn5.address') # Add ciphernodes using variables from config.sh pnpm ciphernode:add --ciphernode-address "$CN1" --network "localhost" pnpm ciphernode:add --ciphernode-address "$CN2" --network "localhost" pnpm ciphernode:add --ciphernode-address "$CN3" --network "localhost" +pnpm ciphernode:add --ciphernode-address "$CN4" --network "localhost" +pnpm ciphernode:add --ciphernode-address "$CN5" --network "localhost" wait diff --git a/examples/CRISP/server/.env.example b/examples/CRISP/server/.env.example index 8599e48c51..cf83c576ad 100644 --- a/examples/CRISP/server/.env.example +++ b/examples/CRISP/server/.env.example @@ -20,8 +20,8 @@ FEE_TOKEN_ADDRESS="0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0" # E3 Config E3_WINDOW_SIZE=40 -E3_THRESHOLD_MIN=1 -E3_THRESHOLD_MAX=2 +E3_THRESHOLD_MIN=2 +E3_THRESHOLD_MAX=5 E3_DURATION=160 # E3 Compute Provider Config diff --git a/tests/integration/enclave.config.yaml b/tests/integration/enclave.config.yaml index 08ce539970..81daff0ca0 100644 --- a/tests/integration/enclave.config.yaml +++ b/tests/integration/enclave.config.yaml @@ -53,7 +53,7 @@ nodes: autopassword: true ag: address: "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" - quic_port: 9096 + quic_port: 9206 autonetkey: true autopassword: true role: From 7e8af15c1ba2f41b6c157d65802abd5f3973878e Mon Sep 17 00:00:00 2001 From: ryardley <r@blockhackers.io> Date: Thu, 6 Nov 2025 03:56:12 +0000 Subject: [PATCH 16/61] add trbfv to crisp --- examples/CRISP/scripts/dev_cipher.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/CRISP/scripts/dev_cipher.sh b/examples/CRISP/scripts/dev_cipher.sh index 809cba8152..3a22a62424 100755 --- a/examples/CRISP/scripts/dev_cipher.sh +++ b/examples/CRISP/scripts/dev_cipher.sh @@ -21,7 +21,7 @@ enclave wallet set --name cn4 --private-key "$PRIVATE_KEY_CN4" enclave wallet set --name cn5 --private-key "$PRIVATE_KEY_CN5" # using & instead of -d so that wait works below -enclave nodes up -v & +enclave nodes up -v --experimental-trbfv & sleep 2 From 40453b7c52e3594268e2cc8541f3eec18ddcbafe Mon Sep 17 00:00:00 2001 From: ryardley <r@blockhackers.io> Date: Thu, 6 Nov 2025 04:35:58 +0000 Subject: [PATCH 17/61] wait for ciphernodes to be ready --- examples/CRISP/scripts/dev_cipher.sh | 10 ++++++++-- examples/CRISP/scripts/dev_services.sh | 4 ++-- examples/CRISP/server/src/server/indexer.rs | 6 +----- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/examples/CRISP/scripts/dev_cipher.sh b/examples/CRISP/scripts/dev_cipher.sh index 3a22a62424..948c601261 100755 --- a/examples/CRISP/scripts/dev_cipher.sh +++ b/examples/CRISP/scripts/dev_cipher.sh @@ -1,10 +1,12 @@ #!/usr/bin/env bash set -euo pipefail +READYFILE=$1 # nuke past installations as we are adding these nodes to the contract -rm -rf ./enclave/data -rm -rf ./enclave/config +rm -rf ./.enclave/data +rm -rf ./.enclave/config +rm -rf $READYFILE PRIVATE_KEY_AG="0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80" PRIVATE_KEY_CN1="0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d" @@ -38,4 +40,8 @@ pnpm ciphernode:add --ciphernode-address "$CN3" --network "localhost" pnpm ciphernode:add --ciphernode-address "$CN4" --network "localhost" pnpm ciphernode:add --ciphernode-address "$CN5" --network "localhost" +echo 1 > $READYFILE + +echo "CIPHERNODES HAVE BEEN ADDED." + wait diff --git a/examples/CRISP/scripts/dev_services.sh b/examples/CRISP/scripts/dev_services.sh index fb876a98df..1d8d851be4 100755 --- a/examples/CRISP/scripts/dev_services.sh +++ b/examples/CRISP/scripts/dev_services.sh @@ -3,7 +3,7 @@ set -euo pipefail concurrently -kr \ - "./scripts/dev_cipher.sh" \ + "./scripts/dev_cipher.sh ./.enclave/ciphernodes_ready" \ "./scripts/dev_program.sh" \ "wait-on tcp:13151 && ./scripts/dev_server.sh" \ - "wait-on tcp:4000 && ./scripts/dev_client.sh" + "wait-on tcp:4000 && wait-on file:$CIPHERNODES_READY && ./scripts/dev_client.sh" diff --git a/examples/CRISP/server/src/server/indexer.rs b/examples/CRISP/server/src/server/indexer.rs index dd29635c6b..55bbc67379 100644 --- a/examples/CRISP/server/src/server/indexer.rs +++ b/examples/CRISP/server/src/server/indexer.rs @@ -253,11 +253,7 @@ pub async fn register_plaintext_output_published( // The computation sums the encrypted votes: '0' for Option 1, '1' for Option 2. // Thus, the decrypted sum directly represents the number of votes for Option 2. // The output is expected to be a Vec<u8> in little endian format of u64s. - let decoded: Vec<u64> = event - .plaintextOutput - .chunks_exact(8) - .map(|chunk| u64::from_le_bytes(chunk.try_into().unwrap())) - .collect(); + let decoded: Vec<u64> = bincode::deserialize(&event.plaintextOutput)?; // decoded[0] is the sum of all encrypted votes (0s and 1s). // Since Option 1 votes are encrypted as '0' and Option 2 votes as '1', From 1cffb884e415b385831ef3c16ee7ada9653a43be Mon Sep 17 00:00:00 2001 From: ryardley <r@blockhackers.io> Date: Thu, 6 Nov 2025 04:47:04 +0000 Subject: [PATCH 18/61] use file for ready --- examples/CRISP/scripts/dev_services.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/CRISP/scripts/dev_services.sh b/examples/CRISP/scripts/dev_services.sh index 1d8d851be4..f95d198c7c 100755 --- a/examples/CRISP/scripts/dev_services.sh +++ b/examples/CRISP/scripts/dev_services.sh @@ -3,7 +3,7 @@ set -euo pipefail concurrently -kr \ - "./scripts/dev_cipher.sh ./.enclave/ciphernodes_ready" \ + "./scripts/dev_cipher.sh ./.enclave/ready" \ "./scripts/dev_program.sh" \ "wait-on tcp:13151 && ./scripts/dev_server.sh" \ - "wait-on tcp:4000 && wait-on file:$CIPHERNODES_READY && ./scripts/dev_client.sh" + "wait-on tcp:4000 && wait-on file:./.enclave/ready && ./scripts/dev_client.sh" From 85ee3777e5a3cc257e52af53666fdcadc808947c Mon Sep 17 00:00:00 2001 From: Hamza Khalid <Hamzakhalid829@gmail.com> Date: Thu, 6 Nov 2025 18:58:21 +0500 Subject: [PATCH 19/61] chore: add logs for e3id --- examples/CRISP/server/src/server/indexer.rs | 68 +++++++++++++-------- 1 file changed, 42 insertions(+), 26 deletions(-) diff --git a/examples/CRISP/server/src/server/indexer.rs b/examples/CRISP/server/src/server/indexer.rs index 55bbc67379..7890bf8418 100644 --- a/examples/CRISP/server/src/server/indexer.rs +++ b/examples/CRISP/server/src/server/indexer.rs @@ -46,7 +46,7 @@ pub async fn register_e3_requested( let e3_id = event.e3Id.to::<u64>(); let mut repo = CrispE3Repository::new(store.clone(), e3_id); - info!("E3Requested: {:?}", event); + info!("[e3_id={}] E3Requested: {:?}", e3_id, event); async move { // Convert custom params bytes back to token address and balance threshold. @@ -77,15 +77,15 @@ pub async fn register_e3_requested( // Get token holders from Etherscan API or mocked data. let token_holders = if matches!(CONFIG.chain_id, 31337 | 1337) { info!( - "Using mocked token holders for local network (chain_id: {})", - CONFIG.chain_id + "[e3_id={}] Using mocked token holders for local network (chain_id: {})", + e3_id, CONFIG.chain_id ); get_mock_token_holders() } else { info!( - "Using Etherscan API for network (chain_id: {})", - CONFIG.chain_id + "[e3_id={}] Using Etherscan API for network (chain_id: {})", + e3_id, CONFIG.chain_id ); let etherscan_client = @@ -98,7 +98,8 @@ pub async fn register_e3_requested( U256::from_str_radix(&balance_threshold.to_string(), 10).map_err( |e| { eyre::eyre!( - "Failed to convert balance threshold to U256: {}", + "[e3_id={}] Failed to convert balance threshold to U256: {}", + e3_id, e ) }, @@ -110,7 +111,8 @@ pub async fn register_e3_requested( if token_holders.is_empty() { return Err(eyre::eyre!( - "No eligible token holders found for token address {}.", + "[e3_id={}] No eligible token holders found for token address {}.", + e3_id, token_address ) .into()); @@ -129,7 +131,7 @@ pub async fn register_e3_requested( .root() .ok_or_else(|| eyre::eyre!("Failed to get merkle root from tree"))?; - info!("Merkle root: {}", merkle_root); + info!("[e3_id={}] Merkle root: {}", e3_id, merkle_root); // TODO: Publish merkle root on-chain (inputValidator contract). @@ -151,7 +153,7 @@ pub async fn register_e3_activated( let mut current_round_repo = CurrentRoundRepository::new(store); let expiration = event.expiration.to::<u64>(); - info!("Handling E3 request with id {}", e3_id); + info!("[e3_id={}] Handling E3 request", e3_id); async move { repo.start_round().await?; @@ -161,12 +163,16 @@ pub async fn register_e3_activated( // Calculate expiration time to sleep until let now = get_current_timestamp_rpc().await?; + info!("[e3_id={}] Current time before sleep: {}", e3_id, now); let wait_duration = if expiration > now { let secs = expiration - now; - info!("Need to wait {} seconds until expiration", secs); + info!( + "[e3_id={}] Need to wait {} seconds until expiration", + e3_id, secs + ); Duration::from_secs(secs) } else { - info!("Expired E3"); + info!("[e3_id={}] Expired E3", e3_id); Duration::ZERO }; if !wait_duration.is_zero() { @@ -176,7 +182,7 @@ pub async fn register_e3_activated( repo.update_status("Expired").await?; if repo.get_vote_count().await? > 0 { - info!("Starting computation for E3: {}", e3_id); + info!("[e3_id={}] Starting computation for E3", e3_id); repo.update_status("Computing").await?; let (id, status) = run_compute( @@ -205,14 +211,17 @@ pub async fn register_e3_activated( .into()); } - info!("Request Computation for E3: {}", e3_id); + info!("[e3_id={}] Request Computation for E3", e3_id); repo.update_status("PublishingCiphertext").await?; } else { - info!("E3 has no votes to decrypt. Setting status to Finished."); + info!( + "[e3_id={}] E3 has no votes to decrypt. Setting status to Finished.", + e3_id + ); repo.update_status("Finished").await?; } - info!("E3 request handled successfully."); + info!("[e3_id={}] E3 request handled successfully.", e3_id); Ok(()) } @@ -230,6 +239,7 @@ pub async fn register_ciphertext_output_published( let e3_id = event.e3Id.to::<u64>(); let mut repo = CrispE3Repository::new(store, e3_id); async move { + info!("[e3_id={}] Handling CiphertextOutputPublished", e3_id); repo.update_status("CiphertextPublished").await?; Ok(()) } @@ -247,7 +257,7 @@ pub async fn register_plaintext_output_published( let e3_id = event.e3Id.to::<u64>(); let mut repo = CrispE3Repository::new(store, e3_id); async move { - info!("CRISP: handling 'PlaintextOutputPublished'"); + info!("[e3_id={}] Handling PlaintextOutputPublished", e3_id); // The plaintextOutput from the event contains the result of the FHE computation. // The computation sums the encrypted votes: '0' for Option 1, '1' for Option 2. @@ -267,9 +277,9 @@ pub async fn register_plaintext_output_published( // the Option 2 votes (the sum from the FHE output) from the total votes. let option_1 = total_votes - option_2; - info!("Vote Count: {:?}", total_votes); - info!("Votes Option 1: {:?}", option_1); - info!("Votes Option 2: {:?}", option_2); + info!("[e3_id={}] Vote Count: {:?}", e3_id, total_votes); + info!("[e3_id={}] Votes Option 1: {:?}", e3_id, option_1); + info!("[e3_id={}] Votes Option 2: {:?}", e3_id, option_2); repo.set_votes(option_1, option_2).await?; repo.update_status("Finished").await?; @@ -294,28 +304,31 @@ pub async fn register_committee_published( // making two calls to contract let e3 = contract.get_e3(event.e3Id).await?; if u64::try_from(e3.expiration)? > 0 { - info!("E3 already activated '{}'", event.e3Id); + info!("[e3_id={}] E3 already activated", event.e3Id); return Ok(()); } // Read Start time in Seconds let start_time = e3.startWindow[0].to::<u64>(); - info!("Start time: {}", start_time); + info!("[e3_id={}] Start time: {}", event.e3Id, start_time); // Get current time let now = get_current_timestamp_rpc().await?; - info!("Current time: {}", now); + info!("[e3_id={}] Current time: {}", event.e3Id, now); // Calculate wait duration let wait_duration = if start_time > now { let secs = start_time - now; - info!("Need to wait {} seconds until activation", secs); + info!( + "[e3_id={}] Need to wait {} seconds until activation", + event.e3Id, secs + ); Duration::from_secs(secs) } else { - info!("Activating E3"); + info!("[e3_id={}] Activating E3", event.e3Id); Duration::ZERO }; - info!("Wait duration: {:?}", wait_duration); + info!("[e3_id={}] Wait duration: {:?}", event.e3Id, wait_duration); // Sleep until start time if !wait_duration.is_zero() { @@ -324,7 +337,10 @@ pub async fn register_committee_published( // If not activated activate let tx = contract.activate(event.e3Id, event.publicKey).await?; - info!("E3 activated with tx: {:?}", tx.transaction_hash); + info!( + "[e3_id={}] E3 activated with tx: {:?}", + event.e3Id, tx.transaction_hash + ); Ok(()) } }) From 8684fdc903a0f2107f45361b8e66bc081b7df5b3 Mon Sep 17 00:00:00 2001 From: Hamza Khalid <Hamzakhalid829@gmail.com> Date: Thu, 6 Nov 2025 19:19:14 +0500 Subject: [PATCH 20/61] chore: add logs for e3id --- .../CRISP/server/src/server/routes/voting.rs | 31 +++++++++++++------ 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/examples/CRISP/server/src/server/routes/voting.rs b/examples/CRISP/server/src/server/routes/voting.rs index 0f571b0241..5121f9fb3a 100644 --- a/examples/CRISP/server/src/server/routes/voting.rs +++ b/examples/CRISP/server/src/server/routes/voting.rs @@ -40,7 +40,7 @@ async fn broadcast_encrypted_vote( store: web::Data<AppData>, ) -> impl Responder { let vote = data.into_inner(); - + error!("[e3_id={}] Broadcasting encrypted vote", vote.round_id); // Validate and update vote status let has_voted = match store .e3(vote.round_id) @@ -49,12 +49,16 @@ async fn broadcast_encrypted_vote( { Ok(voted) => voted, Err(e) => { - log::error!("Database error checking vote status: {:?}", e); + error!( + "[e3_id={}] Database error checking vote status: {:?}", + vote.round_id, e + ); return HttpResponse::InternalServerError().json("Internal server error"); } }; if has_voted { + info!("[e3_id={}] User has already voted", vote.round_id); return HttpResponse::Ok().json(VoteResponse { status: VoteResponseStatus::UserAlreadyVoted, tx_hash: None, @@ -65,7 +69,10 @@ async fn broadcast_encrypted_vote( let mut repo = store.e3(vote.round_id); if let Err(e) = repo.insert_voter_address(vote.address.clone()).await { - log::error!("Database error inserting voter: {:?}", e); + error!( + "[e3_id={}] Database error inserting voter: {:?}", + vote.round_id, e + ); return HttpResponse::InternalServerError().json("Internal server error"); } @@ -103,17 +110,23 @@ async fn broadcast_encrypted_vote( { Ok(c) => c, Err(e) => { - log::error!("Database error checking vote status: {:?}", e); + error!( + "[e3_id={}] Database error checking vote status: {:?}", + vote.round_id, e + ); return HttpResponse::InternalServerError().json("Internal server error"); } }; match contract.publish_input(e3_id, encoded_params).await { - Ok(hash) => HttpResponse::Ok().json(VoteResponse { - status: VoteResponseStatus::Success, - tx_hash: Some(hash.transaction_hash.to_string()), - message: Some("Vote Successful".to_string()), - }), + Ok(hash) => { + info!("[e3_id={}] Vote broadcasted successfully", vote.round_id); + HttpResponse::Ok().json(VoteResponse { + status: VoteResponseStatus::Success, + tx_hash: Some(hash.transaction_hash.to_string()), + message: Some("Vote Successful".to_string()), + }) + } Err(e) => handle_vote_error(e, repo, &vote.address).await, } } From 04177a576b14a26a8e2a9cfad6f6490310b82f86 Mon Sep 17 00:00:00 2001 From: Hamza Khalid <Hamzakhalid829@gmail.com> Date: Thu, 6 Nov 2025 20:12:57 +0500 Subject: [PATCH 21/61] chore: increase e3 duration --- examples/CRISP/server/.env.example | 2 +- examples/CRISP/test/crisp.spec.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/CRISP/server/.env.example b/examples/CRISP/server/.env.example index cf83c576ad..2f531e938f 100644 --- a/examples/CRISP/server/.env.example +++ b/examples/CRISP/server/.env.example @@ -22,7 +22,7 @@ FEE_TOKEN_ADDRESS="0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0" E3_WINDOW_SIZE=40 E3_THRESHOLD_MIN=2 E3_THRESHOLD_MAX=5 -E3_DURATION=160 +E3_DURATION=220 # E3 Compute Provider Config E3_COMPUTE_PROVIDER_NAME="RISC0" diff --git a/examples/CRISP/test/crisp.spec.ts b/examples/CRISP/test/crisp.spec.ts index 0854877ebf..a10fa0b733 100644 --- a/examples/CRISP/test/crisp.spec.ts +++ b/examples/CRISP/test/crisp.spec.ts @@ -60,7 +60,7 @@ test("CRISP smoke test", async ({ .locator("[data-test-id='poll-button-0'] > [data-test-id='card']") .click(); await page.locator('button:has-text("Cast Vote")').click(); - await page.waitForTimeout(220_000); + await page.waitForTimeout(280_000); await page.locator('a:has-text("Historic polls")').click(); await expect(page.locator("h1")).toHaveText("Historic polls"); await expect( From f66d41f9a4ad72ae0561509be709cc0c4260b43d Mon Sep 17 00:00:00 2001 From: Hamza Khalid <Hamzakhalid829@gmail.com> Date: Thu, 6 Nov 2025 20:50:49 +0500 Subject: [PATCH 22/61] chore: increase e3 duration --- examples/CRISP/test/crisp.spec.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/CRISP/test/crisp.spec.ts b/examples/CRISP/test/crisp.spec.ts index a10fa0b733..215908767e 100644 --- a/examples/CRISP/test/crisp.spec.ts +++ b/examples/CRISP/test/crisp.spec.ts @@ -48,8 +48,8 @@ test("CRISP smoke test", async ({ ); await runCliInit(); - // Wait 6 seconds for committee to be published - await page.waitForTimeout(6_000); + // Wait 10 seconds for committee to be published + await page.waitForTimeout(10_000); await page.goto("/"); await ensureHomePageLoaded(page); await page.locator('button:has-text("Connect Wallet")').click(); @@ -60,7 +60,7 @@ test("CRISP smoke test", async ({ .locator("[data-test-id='poll-button-0'] > [data-test-id='card']") .click(); await page.locator('button:has-text("Cast Vote")').click(); - await page.waitForTimeout(280_000); + await page.waitForTimeout(220_000); await page.locator('a:has-text("Historic polls")').click(); await expect(page.locator("h1")).toHaveText("Historic polls"); await expect( From 9d460c24a6a15682d5c414f7c465ed36a4bf5d37 Mon Sep 17 00:00:00 2001 From: Hamza Khalid <Hamzakhalid829@gmail.com> Date: Thu, 6 Nov 2025 20:51:03 +0500 Subject: [PATCH 23/61] chore: derease e3 duration --- examples/CRISP/server/.env.example | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/CRISP/server/.env.example b/examples/CRISP/server/.env.example index 2f531e938f..cf83c576ad 100644 --- a/examples/CRISP/server/.env.example +++ b/examples/CRISP/server/.env.example @@ -22,7 +22,7 @@ FEE_TOKEN_ADDRESS="0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0" E3_WINDOW_SIZE=40 E3_THRESHOLD_MIN=2 E3_THRESHOLD_MAX=5 -E3_DURATION=220 +E3_DURATION=160 # E3 Compute Provider Config E3_COMPUTE_PROVIDER_NAME="RISC0" From dc82125f967ced2f81738543eb6c441249a76594 Mon Sep 17 00:00:00 2001 From: Hamza Khalid <Hamzakhalid829@gmail.com> Date: Thu, 6 Nov 2025 21:27:53 +0500 Subject: [PATCH 24/61] chore: testing with 0 retries --- examples/CRISP/playwright.config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/CRISP/playwright.config.ts b/examples/CRISP/playwright.config.ts index ae724033bc..b5770d4ec8 100644 --- a/examples/CRISP/playwright.config.ts +++ b/examples/CRISP/playwright.config.ts @@ -13,7 +13,7 @@ export default defineConfig({ baseURL: "http://localhost:3000", actionTimeout: 75 * 1000, }, - retries: process.env.CI ? 2 : 0, + retries: 0, fullyParallel: true, forbidOnly: !!process.env.CI, workers: process.env.CI ? 1 : undefined, From 236f9c1426a2b94853e3835ba81d10b0e1ad8ae1 Mon Sep 17 00:00:00 2001 From: ryardley <r@blockhackers.io> Date: Thu, 6 Nov 2025 16:52:09 +0000 Subject: [PATCH 25/61] fix bad merge --- crates/tests/tests/integration_legacy.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/crates/tests/tests/integration_legacy.rs b/crates/tests/tests/integration_legacy.rs index fd3c3e8170..46ca464e9e 100644 --- a/crates/tests/tests/integration_legacy.rs +++ b/crates/tests/tests/integration_legacy.rs @@ -420,7 +420,6 @@ async fn test_stopped_keyshares_retain_state() -> Result<()> { .send(TakeEvents::<EnclaveEvent>::new(5)) .await?; -<<<<<<< HEAD let actual = history .into_iter() .filter_map(|e| match e { From 26193a8abd9f138844df0a8e3ca48167be0b87af Mon Sep 17 00:00:00 2001 From: Hamza Khalid <Hamzakhalid829@gmail.com> Date: Thu, 6 Nov 2025 21:55:40 +0500 Subject: [PATCH 26/61] chore: increase timeout value --- examples/CRISP/test/crisp.spec.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/CRISP/test/crisp.spec.ts b/examples/CRISP/test/crisp.spec.ts index 215908767e..774abb62f6 100644 --- a/examples/CRISP/test/crisp.spec.ts +++ b/examples/CRISP/test/crisp.spec.ts @@ -48,8 +48,8 @@ test("CRISP smoke test", async ({ ); await runCliInit(); - // Wait 10 seconds for committee to be published - await page.waitForTimeout(10_000); + // Wait 15 seconds for committee to be published + await page.waitForTimeout(15_000); await page.goto("/"); await ensureHomePageLoaded(page); await page.locator('button:has-text("Connect Wallet")').click(); From bb40f3bbc73b6cb9bf61b2ae5add9cd5b2d8f32f Mon Sep 17 00:00:00 2001 From: Hamza Khalid <Hamzakhalid829@gmail.com> Date: Thu, 6 Nov 2025 22:00:29 +0500 Subject: [PATCH 27/61] fix: lint error --- crates/net/src/document_publisher.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/net/src/document_publisher.rs b/crates/net/src/document_publisher.rs index ac4d6c739c..9f03994b72 100644 --- a/crates/net/src/document_publisher.rs +++ b/crates/net/src/document_publisher.rs @@ -415,7 +415,7 @@ impl EventConverter { return Ok(()); } let receivable = ReceivableDocument::ThresholdShareCreated(msg); - let value = ArcBytes::from_bytes(receivable.to_bytes()?); + let value = ArcBytes::from_bytes(&receivable.to_bytes()?); let meta = DocumentMeta::new( receivable.get_e3_id().clone(), DocumentKind::TrBFV, From e51feaa23a1abbc27343a57a347d11870ee81a61 Mon Sep 17 00:00:00 2001 From: Hamza Khalid <Hamzakhalid829@gmail.com> Date: Thu, 6 Nov 2025 22:48:26 +0500 Subject: [PATCH 28/61] feat: remove timeouts from crisp test for evm calls --- crates/evm-helpers/src/contracts.rs | 10 ++-- examples/CRISP/.gitignore | 1 + examples/CRISP/server/src/cli/commands.rs | 20 ++++++-- examples/CRISP/server/src/cli/main.rs | 16 ++++-- .../CRISP/server/src/server/routes/rounds.rs | 7 ++- examples/CRISP/test/crisp.spec.ts | 50 +++++++++++++++++-- 6 files changed, 85 insertions(+), 19 deletions(-) diff --git a/crates/evm-helpers/src/contracts.rs b/crates/evm-helpers/src/contracts.rs index db56937b86..db4b576879 100644 --- a/crates/evm-helpers/src/contracts.rs +++ b/crates/evm-helpers/src/contracts.rs @@ -136,7 +136,7 @@ pub trait EnclaveWrite { e3_params: Bytes, compute_provider_params: Bytes, custom_params: Bytes, - ) -> Result<TransactionReceipt>; + ) -> Result<(TransactionReceipt, U256)>; /// Activate an E3 with a public key async fn activate(&self, e3_id: U256, pub_key: Bytes) -> Result<TransactionReceipt>; @@ -382,13 +382,16 @@ impl EnclaveWrite for EnclaveContract<ReadWrite> { e3_params: Bytes, compute_provider_params: Bytes, custom_params: Bytes, - ) -> Result<TransactionReceipt> { + ) -> Result<(TransactionReceipt, U256)> { let _guard = NONCE_LOCK.lock().await; let wallet_addr = self .wallet_address .ok_or_else(|| eyre::eyre!("No wallet address configured"))?; let nonce = get_next_nonce(&*self.provider, wallet_addr).await?; + let contract = Enclave::new(self.contract_address, &self.provider); + let e3_id = contract.nexte3Id().call().await?; + let e3_request = E3RequestParams { threshold, startWindow: start_window, @@ -399,11 +402,10 @@ impl EnclaveWrite for EnclaveContract<ReadWrite> { customParams: custom_params.clone(), }; - let contract = Enclave::new(self.contract_address, &self.provider); let builder = contract.request(e3_request).nonce(nonce); let receipt = builder.send().await?.get_receipt().await?; - Ok(receipt) + Ok((receipt, e3_id)) } async fn activate(&self, e3_id: U256, pub_key: Bytes) -> Result<TransactionReceipt> { diff --git a/examples/CRISP/.gitignore b/examples/CRISP/.gitignore index 99c0e6ea24..384bd03867 100644 --- a/examples/CRISP/.gitignore +++ b/examples/CRISP/.gitignore @@ -47,4 +47,5 @@ playwright-report/ .enclave/data/ .enclave/config/ .enclave/caches/ +.enclave/ready cache_hardhat/ diff --git a/examples/CRISP/server/src/cli/commands.rs b/examples/CRISP/server/src/cli/commands.rs index fcfa271eb4..a1767899f6 100644 --- a/examples/CRISP/server/src/cli/commands.rs +++ b/examples/CRISP/server/src/cli/commands.rs @@ -4,7 +4,6 @@ // without even the implied warranty of MERCHANTABILITY // or FITNESS FOR A PARTICULAR PURPOSE. -use chrono::Utc; use dialoguer::{theme::ColorfulTheme, FuzzySelect, Input}; use log::info; use num_bigint::BigUint; @@ -19,7 +18,7 @@ use crisp::config::CONFIG; use e3_sdk::bfv_helpers::{ build_bfv_params_from_set_arc, encode_bfv_params, params::SET_2048_1032193_1, }; -use e3_sdk::evm_helpers::contracts::{EnclaveContract, EnclaveRead, EnclaveWrite}; +use e3_sdk::evm_helpers::contracts::{EnclaveContract, EnclaveRead, EnclaveWrite, E3}; use fhe::bfv::{BfvParameters, Ciphertext, Encoding, Plaintext, PublicKey, SecretKey}; use fhe_traits::{ DeserializeParametrized, FheDecoder, FheDecrypter, FheEncoder, FheEncrypter, @@ -74,7 +73,7 @@ pub async fn get_current_timestamp() -> Result<u64, Box<dyn std::error::Error + pub async fn initialize_crisp_round( token_address: &str, balance_threshold: &str, -) -> Result<(), Box<dyn std::error::Error + Send + Sync>> { +) -> Result<u64, Box<dyn std::error::Error + Send + Sync>> { info!( "Starting new CRISP round with token address: {} and balance threshold: {}", token_address, balance_threshold @@ -178,7 +177,7 @@ pub async fn initialize_crisp_round( CONFIG.ciphernode_registry_address ); - let res = contract + let (res, e3_id) = contract .request_e3( threshold, start_window, @@ -190,8 +189,19 @@ pub async fn initialize_crisp_round( ) .await?; info!("E3 request sent. TxHash: {:?}", res.transaction_hash); + let e3_id_u64 = u64::try_from(e3_id)?; + info!("E3 ID: {}", e3_id_u64); - Ok(()) + Ok(e3_id_u64) +} + +pub async fn check_e3_activated( + e3_id: u64, +) -> Result<bool, Box<dyn std::error::Error + Send + Sync>> { + let contract = + EnclaveContract::read_only(&CONFIG.http_rpc_url, &CONFIG.enclave_address).await?; + let e3: E3 = contract.get_e3(U256::from(e3_id)).await?; + Ok(u64::try_from(e3.expiration)? > 0) } pub async fn activate_e3_round() -> Result<(), Box<dyn std::error::Error + Send + Sync>> { diff --git a/examples/CRISP/server/src/cli/main.rs b/examples/CRISP/server/src/cli/main.rs index 7a10be5e15..2f68e62293 100644 --- a/examples/CRISP/server/src/cli/main.rs +++ b/examples/CRISP/server/src/cli/main.rs @@ -10,7 +10,7 @@ mod commands; use dialoguer::{theme::ColorfulTheme, FuzzySelect, Input}; use reqwest::Client; -use commands::initialize_crisp_round; +use commands::{check_e3_activated, initialize_crisp_round}; use crisp::logger::init_logger; use log::info; @@ -49,6 +49,10 @@ enum Commands { #[arg(short, long, default_value = "1000000000000000000")] balance_threshold: String, }, + CheckActivate { + #[arg(short, long)] + e3id: u64, + }, } #[tokio::main] @@ -68,7 +72,12 @@ pub async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> { token_address, balance_threshold, }) => { - initialize_crisp_round(&token_address, &balance_threshold).await?; + let e3_id = initialize_crisp_round(&token_address, &balance_threshold).await?; + println!("{}", e3_id); + } + Some(Commands::CheckActivate { e3id }) => { + let is_activated = check_e3_activated(e3id).await?; + println!("{}", is_activated); } None => { // Fall back to interactive mode if no command was specified @@ -77,7 +86,8 @@ pub async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> { 0 => { let token_address = get_token_address()?; let balance_threshold = get_balance_threshold()?; - initialize_crisp_round(&token_address, &balance_threshold).await?; + let e3_id = initialize_crisp_round(&token_address, &balance_threshold).await?; + println!("E3 ID: {}", e3_id); } _ => unreachable!(), } diff --git a/examples/CRISP/server/src/server/routes/rounds.rs b/examples/CRISP/server/src/server/routes/rounds.rs index 1ac3d49873..83a7746940 100644 --- a/examples/CRISP/server/src/server/routes/rounds.rs +++ b/examples/CRISP/server/src/server/routes/rounds.rs @@ -209,7 +209,7 @@ pub async fn initialize_crisp_round( batch_size: CONFIG.e3_compute_provider_batch_size, }; let compute_provider_params = Bytes::from(bincode::serialize(&compute_provider_params)?); - let res = contract + let (receipt, e3_id) = contract .request_e3( threshold, start_window, @@ -220,7 +220,10 @@ pub async fn initialize_crisp_round( custom_params_bytes, ) .await?; - info!("E3 request sent. TxHash: {:?}", res.transaction_hash); + info!( + "E3 request sent. TxHash: {:?}, E3 ID: {}", + receipt.transaction_hash, e3_id + ); Ok(()) } diff --git a/examples/CRISP/test/crisp.spec.ts b/examples/CRISP/test/crisp.spec.ts index 774abb62f6..3a5ba63e87 100644 --- a/examples/CRISP/test/crisp.spec.ts +++ b/examples/CRISP/test/crisp.spec.ts @@ -10,7 +10,7 @@ import { MetaMask, metaMaskFixtures } from "@synthetixio/synpress/playwright"; import basicSetup from "./wallet-setup/basic.setup"; import { execSync } from "child_process"; -async function runCliInit() { +async function runCliInit(): Promise<number> { try { // Execute the command and wait for it to complete const output = execSync( @@ -18,13 +18,49 @@ async function runCliInit() { { encoding: "utf-8" } ); console.log("Command output:", output); - return output; + const lines = output.trim().split("\n"); + const lastLine = lines[lines.length - 1].trim(); + const e3Id = parseInt(lastLine, 10); + if (isNaN(e3Id)) { + throw new Error(`Failed to parse e3Id from CLI output: ${lastLine}`); + } + return e3Id; } catch (error) { console.error("Error executing command:", error); throw error; } } +async function checkE3Activated(e3id: number): Promise<boolean> { + try { + const output = execSync(`pnpm cli check-activate --e3id ${e3id}`, { + encoding: "utf-8", + }); + const lines = output.trim().split("\n"); + const lastLine = lines[lines.length - 1].trim(); + return lastLine === "true"; + } catch (error) { + console.error("Error checking e3 activation:", error); + return false; + } +} + +async function waitForE3Activation( + e3id: number, + maxWaitMs: number = 300000 +): Promise<void> { + const startTime = Date.now(); + while (Date.now() - startTime < maxWaitMs) { + const isActivated = await checkE3Activated(e3id); + if (isActivated) { + console.log(`E3 ${e3id} is activated`); + return; + } + await new Promise((resolve) => setTimeout(resolve, 2000)); + } + throw new Error(`E3 ${e3id} was not activated within ${maxWaitMs}ms`); +} + const test = testWithSynpress(metaMaskFixtures(basicSetup)); const { expect } = test; @@ -47,15 +83,19 @@ test("CRISP smoke test", async ({ extensionId ); - await runCliInit(); - // Wait 15 seconds for committee to be published - await page.waitForTimeout(15_000); + const e3id = await runCliInit(); + console.log(`Got e3 id: ${e3id}`); + await page.goto("/"); await ensureHomePageLoaded(page); await page.locator('button:has-text("Connect Wallet")').click(); await page.locator('button:has-text("MetaMask")').click(); await metamask.connectToDapp(); await page.locator('button:has-text("Try Demo")').click(); + + await waitForE3Activation(e3id); + await page.reload(); + await page .locator("[data-test-id='poll-button-0'] > [data-test-id='card']") .click(); From 20964f32f42dc747a6888d0a40f9d568e355bb4f Mon Sep 17 00:00:00 2001 From: ryardley <contact@rudiyardley.com> Date: Thu, 6 Nov 2025 16:45:34 -0300 Subject: [PATCH 29/61] debug --- .../CRISP/packages/crisp-contracts/deployed_contracts.json | 4 ++-- examples/CRISP/server/src/server/indexer.rs | 2 +- .../interfaces/IBondingRegistry.sol/IBondingRegistry.json | 2 +- .../ICiphernodeRegistry.sol/ICiphernodeRegistry.json | 2 +- .../artifacts/contracts/interfaces/IEnclave.sol/IEnclave.json | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/examples/CRISP/packages/crisp-contracts/deployed_contracts.json b/examples/CRISP/packages/crisp-contracts/deployed_contracts.json index 22c64fe348..87609307eb 100644 --- a/examples/CRISP/packages/crisp-contracts/deployed_contracts.json +++ b/examples/CRISP/packages/crisp-contracts/deployed_contracts.json @@ -165,7 +165,7 @@ "constructorArgs": { "owner": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", "enclaveAddress": "0x0000000000000000000000000000000000000001", - "submissionWindow": "3" + "submissionWindow": "10" }, "blockNumber": 10, "address": "0x2279B7A0a67DB372996a5FaB50D91eAA73d2eBe6" @@ -203,7 +203,7 @@ "blockNumber": 23, "address": "0x59b670e9fA9D0A427751Af201D676719a970857b" }, - "RiscZeroGroth16Verifier": { + "MockRISC0Verifier": { "address": "0xa85233C63b9Ee964Add6F2cffe00Fd84eb32338f" }, "CRISPInputValidator": { diff --git a/examples/CRISP/server/src/server/indexer.rs b/examples/CRISP/server/src/server/indexer.rs index 7890bf8418..d6a4b53479 100644 --- a/examples/CRISP/server/src/server/indexer.rs +++ b/examples/CRISP/server/src/server/indexer.rs @@ -264,7 +264,7 @@ pub async fn register_plaintext_output_published( // Thus, the decrypted sum directly represents the number of votes for Option 2. // The output is expected to be a Vec<u8> in little endian format of u64s. let decoded: Vec<u64> = bincode::deserialize(&event.plaintextOutput)?; - + println!("RECEIVED: {:?}", decoded); // decoded[0] is the sum of all encrypted votes (0s and 1s). // Since Option 1 votes are encrypted as '0' and Option 2 votes as '1', // this sum is equivalent to the count of votes for Option 2. diff --git a/packages/enclave-contracts/artifacts/contracts/interfaces/IBondingRegistry.sol/IBondingRegistry.json b/packages/enclave-contracts/artifacts/contracts/interfaces/IBondingRegistry.sol/IBondingRegistry.json index da0ed3208f..2fd0b2b467 100644 --- a/packages/enclave-contracts/artifacts/contracts/interfaces/IBondingRegistry.sol/IBondingRegistry.json +++ b/packages/enclave-contracts/artifacts/contracts/interfaces/IBondingRegistry.sol/IBondingRegistry.json @@ -851,5 +851,5 @@ "deployedLinkReferences": {}, "immutableReferences": {}, "inputSourceName": "project/contracts/interfaces/IBondingRegistry.sol", - "buildInfoId": "solc-0_8_28-a2f64967aeae699bd499cc90bbcf76e2314a0651" + "buildInfoId": "solc-0_8_28-c084532c59ac53ee00b443bea013584d95d4e870" } \ No newline at end of file diff --git a/packages/enclave-contracts/artifacts/contracts/interfaces/ICiphernodeRegistry.sol/ICiphernodeRegistry.json b/packages/enclave-contracts/artifacts/contracts/interfaces/ICiphernodeRegistry.sol/ICiphernodeRegistry.json index b4749a16db..ffdaa8d9d4 100644 --- a/packages/enclave-contracts/artifacts/contracts/interfaces/ICiphernodeRegistry.sol/ICiphernodeRegistry.json +++ b/packages/enclave-contracts/artifacts/contracts/interfaces/ICiphernodeRegistry.sol/ICiphernodeRegistry.json @@ -535,5 +535,5 @@ "deployedLinkReferences": {}, "immutableReferences": {}, "inputSourceName": "project/contracts/interfaces/ICiphernodeRegistry.sol", - "buildInfoId": "solc-0_8_28-a2f64967aeae699bd499cc90bbcf76e2314a0651" + "buildInfoId": "solc-0_8_28-c084532c59ac53ee00b443bea013584d95d4e870" } \ No newline at end of file diff --git a/packages/enclave-contracts/artifacts/contracts/interfaces/IEnclave.sol/IEnclave.json b/packages/enclave-contracts/artifacts/contracts/interfaces/IEnclave.sol/IEnclave.json index b7d1d76a68..adf68d7704 100644 --- a/packages/enclave-contracts/artifacts/contracts/interfaces/IEnclave.sol/IEnclave.json +++ b/packages/enclave-contracts/artifacts/contracts/interfaces/IEnclave.sol/IEnclave.json @@ -977,5 +977,5 @@ "deployedLinkReferences": {}, "immutableReferences": {}, "inputSourceName": "project/contracts/interfaces/IEnclave.sol", - "buildInfoId": "solc-0_8_28-c5db5579375d04ced938f4f4a02b4414441687bc" + "buildInfoId": "solc-0_8_28-c084532c59ac53ee00b443bea013584d95d4e870" } \ No newline at end of file From ba0c5062d028855e1b5b0b418503c31891a5a13b Mon Sep 17 00:00:00 2001 From: ryardley <contact@rudiyardley.com> Date: Thu, 6 Nov 2025 17:01:01 -0300 Subject: [PATCH 30/61] more debug --- crates/trbfv/src/calculate_threshold_decryption.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/trbfv/src/calculate_threshold_decryption.rs b/crates/trbfv/src/calculate_threshold_decryption.rs index 0138158576..3f52fdfc76 100644 --- a/crates/trbfv/src/calculate_threshold_decryption.rs +++ b/crates/trbfv/src/calculate_threshold_decryption.rs @@ -116,6 +116,7 @@ impl TryFrom<InnerResponse> for CalculateThresholdDecryptionResponse { .map(|open_result| -> Result<_> { let vec_64 = Vec::<u64>::try_decode(&open_result, Encoding::poly()) .context("could not decode plaintext")?; + println!("FINISHED AGGREGATING: {:?}", vec_64); let bytes = bincode::serialize(&vec_64)?; Ok(ArcBytes::from_bytes(&bytes)) }) From a4c1ec7fde0a02537e7fea0fb12e873df6c2ee67 Mon Sep 17 00:00:00 2001 From: ryardley <contact@rudiyardley.com> Date: Thu, 6 Nov 2025 17:12:27 -0300 Subject: [PATCH 31/61] more debug --- crates/trbfv/src/calculate_threshold_decryption.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/trbfv/src/calculate_threshold_decryption.rs b/crates/trbfv/src/calculate_threshold_decryption.rs index 3f52fdfc76..bff213a299 100644 --- a/crates/trbfv/src/calculate_threshold_decryption.rs +++ b/crates/trbfv/src/calculate_threshold_decryption.rs @@ -116,7 +116,7 @@ impl TryFrom<InnerResponse> for CalculateThresholdDecryptionResponse { .map(|open_result| -> Result<_> { let vec_64 = Vec::<u64>::try_decode(&open_result, Encoding::poly()) .context("could not decode plaintext")?; - println!("FINISHED AGGREGATING: {:?}", vec_64); + info!("FINISHED AGGREGATING: {:?}", vec_64); let bytes = bincode::serialize(&vec_64)?; Ok(ArcBytes::from_bytes(&bytes)) }) From f4c41c0bf2a69372adab5de4f0f69521073ca708 Mon Sep 17 00:00:00 2001 From: Hamza Khalid <Hamzakhalid829@gmail.com> Date: Fri, 7 Nov 2025 19:23:42 +0500 Subject: [PATCH 32/61] chore: add trbfv params and test changes --- crates/bfv-helpers/src/client.rs | 28 ++++++--- crates/wasm/src/lib.rs | 16 ++--- .../client/libs/wasm/pkg/crisp_worker.js | 3 +- examples/CRISP/client/package.json | 2 +- examples/CRISP/scripts/dev_cipher.sh | 2 +- packages/enclave-sdk/src/enclave-sdk.ts | 10 ++-- packages/enclave-sdk/src/types.ts | 21 ++++++- pnpm-lock.yaml | 59 +------------------ 8 files changed, 58 insertions(+), 83 deletions(-) diff --git a/crates/bfv-helpers/src/client.rs b/crates/bfv-helpers/src/client.rs index 26701211d5..17ea343d24 100644 --- a/crates/bfv-helpers/src/client.rs +++ b/crates/bfv-helpers/src/client.rs @@ -35,7 +35,7 @@ pub fn bfv_encrypt<T>( public_key: Vec<u8>, degree: usize, plaintext_modulus: u64, - moduli: [u64; 1], + moduli: Vec<u64>, ) -> Result<Vec<u8>> where Plaintext: for<'a> FheEncoder<&'a T, Error = FheError>, @@ -86,7 +86,7 @@ pub fn bfv_verifiable_encrypt<T>( public_key: Vec<u8>, degree: usize, plaintext_modulus: u64, - moduli: [u64; 1], + moduli: Vec<u64>, ) -> Result<VerifiableEncryptionResult> where Plaintext: for<'a> FheEncoder<&'a T, Error = FheError>, @@ -145,8 +145,14 @@ mod tests { let pk = PublicKey::new(&sk, &mut rng); let num = [1u64]; - let encrypted_data = - bfv_encrypt(num, pk.to_bytes(), degree, plaintext_modulus, moduli).unwrap(); + let encrypted_data = bfv_encrypt( + num, + pk.to_bytes(), + degree, + plaintext_modulus, + moduli.to_vec(), + ) + .unwrap(); let ct = Ciphertext::from_bytes(&encrypted_data, &params).unwrap(); let pt = sk.try_decrypt(&ct).unwrap(); @@ -175,7 +181,7 @@ mod tests { pk.to_bytes(), degree, plaintext_modulus, - moduli, + moduli.to_vec(), ) .unwrap(); @@ -202,8 +208,14 @@ mod tests { let pk = PublicKey::new(&sk, &mut rng); let num = [1u64]; - let encrypted_data = - bfv_verifiable_encrypt(num, pk.to_bytes(), degree, plaintext_modulus, moduli).unwrap(); + let encrypted_data = bfv_verifiable_encrypt( + num, + pk.to_bytes(), + degree, + plaintext_modulus, + moduli.to_vec(), + ) + .unwrap(); let ct = Ciphertext::from_bytes(&encrypted_data.encrypted_data, &params).unwrap(); let pt = sk.try_decrypt(&ct).unwrap(); @@ -232,7 +244,7 @@ mod tests { pk.to_bytes(), degree, plaintext_modulus, - moduli, + moduli.to_vec(), ) .unwrap(); diff --git a/crates/wasm/src/lib.rs b/crates/wasm/src/lib.rs index b235b01406..8916a2956a 100644 --- a/crates/wasm/src/lib.rs +++ b/crates/wasm/src/lib.rs @@ -30,9 +30,9 @@ pub fn bfv_encrypt_number( public_key: Vec<u8>, degree: usize, plaintext_modulus: u64, - moduli: u64, + moduli: Vec<u64>, ) -> Result<Vec<u8>, JsValue> { - let encrypted_data = bfv_encrypt([data], public_key, degree, plaintext_modulus, [moduli]) + let encrypted_data = bfv_encrypt([data], public_key, degree, plaintext_modulus, moduli) .map_err(|e| JsValue::from_str(&format!("{}", e)))?; Ok(encrypted_data) } @@ -60,9 +60,9 @@ pub fn bfv_encrypt_vector( public_key: Vec<u8>, degree: usize, plaintext_modulus: u64, - moduli: u64, + moduli: Vec<u64>, ) -> Result<Vec<u8>, JsValue> { - let encrypted_data = bfv_encrypt(data, public_key, degree, plaintext_modulus, [moduli]) + let encrypted_data = bfv_encrypt(data, public_key, degree, plaintext_modulus, moduli) .map_err(|e| JsValue::from_str(&format!("{}", e)))?; Ok(encrypted_data) } @@ -91,9 +91,9 @@ pub fn bfv_verifiable_encrypt_number( public_key: Vec<u8>, degree: usize, plaintext_modulus: u64, - moduli: u64, + moduli: Vec<u64>, ) -> Result<Vec<JsValue>, JsValue> { - let result = bfv_verifiable_encrypt([data], public_key, degree, plaintext_modulus, [moduli]) + let result = bfv_verifiable_encrypt([data], public_key, degree, plaintext_modulus, moduli) .map_err(|e| JsValue::from_str(&format!("{}", e)))?; // Return as a vector of JsValues @@ -127,9 +127,9 @@ pub fn bfv_verifiable_encrypt_vector( public_key: Vec<u8>, degree: usize, plaintext_modulus: u64, - moduli: u64, + moduli: Vec<u64>, ) -> Result<Vec<JsValue>, JsValue> { - let result = bfv_verifiable_encrypt(data, public_key, degree, plaintext_modulus, [moduli]) + let result = bfv_verifiable_encrypt(data, public_key, degree, plaintext_modulus, moduli) .map_err(|e| JsValue::from_str(&format!("{}", e)))?; // Return as a vector of JsValues diff --git a/examples/CRISP/client/libs/wasm/pkg/crisp_worker.js b/examples/CRISP/client/libs/wasm/pkg/crisp_worker.js index 35a7aa5656..ca7e32587b 100755 --- a/examples/CRISP/client/libs/wasm/pkg/crisp_worker.js +++ b/examples/CRISP/client/libs/wasm/pkg/crisp_worker.js @@ -20,6 +20,7 @@ self.onmessage = async function (event) { contracts: { enclave: '0xc6e7DF5E7b4f2A278906862b61205850344D4e7d', ciphernodeRegistry: '0xc6e7DF5E7b4f2A278906862b61205850344D4e7d', + feeToken: '0xc6e7DF5E7b4f2A278906862b61205850344D4e7d', }, // local node rpcUrl: 'http://localhost:8545', @@ -34,7 +35,7 @@ self.onmessage = async function (event) { type: 'encrypt_vote', success: true, encryptedVote: { - vote: result.encryptedVote, + vote: result.encryptedData, proofData: result.proof, }, }) diff --git a/examples/CRISP/client/package.json b/examples/CRISP/client/package.json index ee0b5c94dc..4e56b1544e 100644 --- a/examples/CRISP/client/package.json +++ b/examples/CRISP/client/package.json @@ -22,7 +22,7 @@ "@aztec/bb.js": "^0.82.2", "@emotion/babel-plugin": "^11.11.0", "@emotion/react": "^11.11.4", - "@enclave-e3/sdk": "^0.1.5", + "@enclave-e3/sdk": "workspace:*", "@noir-lang/acvm_js": "1.0.0-beta.3", "@noir-lang/noir_js": "1.0.0-beta.3", "@noir-lang/noirc_abi": "1.0.0-beta.3", diff --git a/examples/CRISP/scripts/dev_cipher.sh b/examples/CRISP/scripts/dev_cipher.sh index 948c601261..d582073653 100755 --- a/examples/CRISP/scripts/dev_cipher.sh +++ b/examples/CRISP/scripts/dev_cipher.sh @@ -23,7 +23,7 @@ enclave wallet set --name cn4 --private-key "$PRIVATE_KEY_CN4" enclave wallet set --name cn5 --private-key "$PRIVATE_KEY_CN5" # using & instead of -d so that wait works below -enclave nodes up -v --experimental-trbfv & +enclave nodes up -v & sleep 2 diff --git a/packages/enclave-sdk/src/enclave-sdk.ts b/packages/enclave-sdk/src/enclave-sdk.ts index 9401a8ebb3..f21c7bfff5 100644 --- a/packages/enclave-sdk/src/enclave-sdk.ts +++ b/packages/enclave-sdk/src/enclave-sdk.ts @@ -42,7 +42,7 @@ import { bfv_verifiable_encrypt_number, bfv_verifiable_encrypt_vector, } from "@enclave-e3/wasm"; -import { CircuitInputs, generateProof } from "./greco"; +import { generateProof } from "./greco"; import { CompiledCircuit } from "@noir-lang/noir_js"; export class EnclaveSDK { @@ -140,7 +140,7 @@ export class EnclaveSDK { publicKey, this.protocolParams.degree, this.protocolParams.plaintextModulus, - this.protocolParams.moduli + new BigUint64Array(this.protocolParams.moduli) ); default: throw new Error("Protocol not supported"); @@ -165,7 +165,7 @@ export class EnclaveSDK { publicKey, this.protocolParams.degree, this.protocolParams.plaintextModulus, - this.protocolParams.moduli + new BigUint64Array(this.protocolParams.moduli) ); default: throw new Error("Protocol not supported"); @@ -191,7 +191,7 @@ export class EnclaveSDK { publicKey, this.protocolParams.degree, this.protocolParams.plaintextModulus, - this.protocolParams.moduli + new BigUint64Array(this.protocolParams.moduli) ); const publicInputs = JSON.parse(circuitInputs); @@ -244,7 +244,7 @@ export class EnclaveSDK { publicKey, this.protocolParams.degree, this.protocolParams.plaintextModulus, - this.protocolParams.moduli + new BigUint64Array(this.protocolParams.moduli) ); const publicInputs = JSON.parse(circuitInputs); diff --git a/packages/enclave-sdk/src/types.ts b/packages/enclave-sdk/src/types.ts index 0f21717cef..627b06a1fe 100644 --- a/packages/enclave-sdk/src/types.ts +++ b/packages/enclave-sdk/src/types.ts @@ -312,7 +312,7 @@ export interface ProtocolParams { /** * The moduli */ - moduli: bigint; + moduli: bigint[]; } /** @@ -328,7 +328,24 @@ export const BfvProtocolParams = { BFV_NORMAL: { degree: 2048, plaintextModulus: 1032193n, - moduli: 0x3fffffff000001n, + moduli: [0x3fffffff000001n], + } as const satisfies ProtocolParams, + + /** + * Recommended parameters for TrBFV protocol + * - Degree: 8192 + * - Plaintext modulus: 1000 + * - Moduli: [0x00800000022a0001, 0x00800000021a0001, 0x0080000002120001, 0x0080000001f60001] + */ + BFV_THRESHOLD: { + degree: 8192, + plaintextModulus: 1032193n, + moduli: [ + 0x00800000022a0001n, + 0x00800000021a0001n, + 0x0080000002120001n, + 0x0080000001f60001n, + ], } as const satisfies ProtocolParams, }; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0bd915214b..5498c333a2 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -128,8 +128,8 @@ importers: specifier: ^11.11.4 version: 11.14.0(@types/react@18.3.26)(react@18.3.1) '@enclave-e3/sdk': - specifier: ^0.1.5 - version: 0.1.5(@openzeppelin/contracts@5.3.0)(@swc/helpers@0.5.17)(@types/node@22.7.5)(bufferutil@4.0.9)(rollup@4.52.5)(typescript@5.8.3)(utf-8-validate@5.0.10)(vite@5.4.21(@types/node@22.7.5))(zod@4.1.12) + specifier: workspace:* + version: link:../../../packages/enclave-sdk '@noir-lang/acvm_js': specifier: 1.0.0-beta.3 version: 1.0.0-beta.3 @@ -1562,15 +1562,6 @@ packages: '@emotion/weak-memoize@0.4.0': resolution: {integrity: sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==} - '@enclave-e3/contracts@0.1.5': - resolution: {integrity: sha512-C1Mo9z2JG6netDhpOsk0kZV8DBjVd4ftE5oqhpXDDbK+HHD4XHozjKMqmlUYTooSzzT3INGYNS/IEDUHxYOqTA==} - - '@enclave-e3/sdk@0.1.5': - resolution: {integrity: sha512-AZGIYrlJZ6FeK6DIQWqNKZDwvDpw+l1zCd7hc97giFX2LrNbSAzf/UJmNewAXFfaGtlnOePSVsuixk/ZQd1TVw==} - - '@enclave-e3/wasm@0.1.5': - resolution: {integrity: sha512-PZ/TpABK/PAAzO0d2+q17i3plzCs/E3chihc4yOi9DqCxdGFhm76hTueY/lDXusDnM+LUrEuaD11YR/2kBRvTg==} - '@esbuild/aix-ppc64@0.20.0': resolution: {integrity: sha512-fGFDEctNh0CcSwsiRPxiaqX0P5rq+AqE0SRhYGZ4PX46Lg1FNR6oCxJghf8YgY0WQEgQuh3lErUFE4KxLeRmmw==} engines: {node: '>=12'} @@ -11066,52 +11057,6 @@ snapshots: '@emotion/weak-memoize@0.4.0': {} - '@enclave-e3/contracts@0.1.5(@openzeppelin/contracts@5.3.0)': - dependencies: - '@openzeppelin/contracts-upgradeable': 5.4.0(@openzeppelin/contracts@5.3.0) - '@zk-kit/lean-imt.sol': 2.0.1 - poseidon-solidity: 0.0.5 - transitivePeerDependencies: - - '@openzeppelin/contracts' - - '@enclave-e3/sdk@0.1.5(@openzeppelin/contracts@5.3.0)(@swc/helpers@0.5.17)(@types/node@22.7.5)(bufferutil@4.0.9)(rollup@4.52.5)(typescript@5.8.3)(utf-8-validate@5.0.10)(vite@5.4.21(@types/node@22.7.5))(zod@4.1.12)': - dependencies: - '@aztec/bb.js': 0.82.3 - '@enclave-e3/contracts': 0.1.5(@openzeppelin/contracts@5.3.0) - '@enclave-e3/wasm': 0.1.5 - '@noir-lang/noir_js': 1.0.0-beta.3 - comlink: 4.4.2 - viem: 2.38.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12) - vite-plugin-top-level-await: 1.6.0(@swc/helpers@0.5.17)(rollup@4.52.5)(vite@5.4.21(@types/node@22.7.5)) - vite-plugin-wasm: 3.5.0(vite@5.4.21(@types/node@22.7.5)) - vitest: 1.6.1(@types/node@22.7.5) - web-worker: 1.5.0 - transitivePeerDependencies: - - '@edge-runtime/vm' - - '@openzeppelin/contracts' - - '@swc/helpers' - - '@types/node' - - '@vitest/browser' - - '@vitest/ui' - - bufferutil - - happy-dom - - jsdom - - less - - lightningcss - - rollup - - sass - - sass-embedded - - stylus - - sugarss - - supports-color - - terser - - typescript - - utf-8-validate - - vite - - zod - - '@enclave-e3/wasm@0.1.5': {} - '@esbuild/aix-ppc64@0.20.0': optional: true From 4249dfd501bc6cc3623409cbef4022710fb53ef6 Mon Sep 17 00:00:00 2001 From: ryardley <contact@rudiyardley.com> Date: Fri, 7 Nov 2025 11:37:33 -0300 Subject: [PATCH 33/61] add logging --- examples/CRISP/test/crisp.spec.ts | 17 ++++--- packages/enclave-sdk/src/enclave-sdk.ts | 68 +++++++++++++------------ 2 files changed, 46 insertions(+), 39 deletions(-) diff --git a/examples/CRISP/test/crisp.spec.ts b/examples/CRISP/test/crisp.spec.ts index 3a5ba63e87..56b894b808 100644 --- a/examples/CRISP/test/crisp.spec.ts +++ b/examples/CRISP/test/crisp.spec.ts @@ -15,7 +15,7 @@ async function runCliInit(): Promise<number> { // Execute the command and wait for it to complete const output = execSync( "pnpm cli init --token-address 0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512 --balance-threshold 1000", - { encoding: "utf-8" } + { encoding: "utf-8" }, ); console.log("Command output:", output); const lines = output.trim().split("\n"); @@ -47,7 +47,7 @@ async function checkE3Activated(e3id: number): Promise<boolean> { async function waitForE3Activation( e3id: number, - maxWaitMs: number = 300000 + maxWaitMs: number = 300000, ): Promise<void> { const startTime = Date.now(); while (Date.now() - startTime < maxWaitMs) { @@ -66,7 +66,7 @@ const { expect } = test; async function ensureHomePageLoaded(page: Page) { return await expect(page.locator("h4")).toHaveText( - "Coercion-Resistant Impartial Selection Protocol" + "Coercion-Resistant Impartial Selection Protocol", ); } @@ -80,13 +80,18 @@ test("CRISP smoke test", async ({ context, metamaskPage, basicSetup.walletPassword, - extensionId + extensionId, ); const e3id = await runCliInit(); console.log(`Got e3 id: ${e3id}`); await page.goto("/"); + + page.on("console", (...msg: any[]) => { + console.log(...msg); + }); + await ensureHomePageLoaded(page); await page.locator('button:has-text("Connect Wallet")').click(); await page.locator('button:has-text("MetaMask")').click(); @@ -104,9 +109,9 @@ test("CRISP smoke test", async ({ await page.locator('a:has-text("Historic polls")').click(); await expect(page.locator("h1")).toHaveText("Historic polls"); await expect( - page.locator("[data-test-id='poll-0-0'] [data-test-id='poll-result-0'] h3") + page.locator("[data-test-id='poll-0-0'] [data-test-id='poll-result-0'] h3"), ).toHaveText("100%"); await expect( - page.locator("[data-test-id='poll-0-0'] [data-test-id='poll-result-1'] h3") + page.locator("[data-test-id='poll-0-0'] [data-test-id='poll-result-1'] h3"), ).toHaveText("0%"); }); diff --git a/packages/enclave-sdk/src/enclave-sdk.ts b/packages/enclave-sdk/src/enclave-sdk.ts index f21c7bfff5..25cc792c29 100644 --- a/packages/enclave-sdk/src/enclave-sdk.ts +++ b/packages/enclave-sdk/src/enclave-sdk.ts @@ -71,14 +71,14 @@ export class EnclaveSDK { if (!isValidAddress(config.contracts.ciphernodeRegistry)) { throw new SDKError( "Invalid CiphernodeRegistry contract address", - "INVALID_ADDRESS" + "INVALID_ADDRESS", ); } if (!isValidAddress(config.contracts.feeToken)) { throw new SDKError( "Invalid FeeToken contract address", - "INVALID_ADDRESS" + "INVALID_ADDRESS", ); } @@ -86,7 +86,7 @@ export class EnclaveSDK { this.contractClient = new ContractClient( config.publicClient, config.walletClient, - config.contracts + config.contracts, ); this.protocol = config.protocol; @@ -117,7 +117,7 @@ export class EnclaveSDK { } catch (error) { throw new SDKError( `Failed to initialize SDK: ${error}`, - "SDK_INITIALIZATION_FAILED" + "SDK_INITIALIZATION_FAILED", ); } } @@ -130,7 +130,7 @@ export class EnclaveSDK { */ public async encryptNumber( data: bigint, - publicKey: Uint8Array + publicKey: Uint8Array, ): Promise<Uint8Array> { await initializeWasm(); switch (this.protocol) { @@ -140,7 +140,7 @@ export class EnclaveSDK { publicKey, this.protocolParams.degree, this.protocolParams.plaintextModulus, - new BigUint64Array(this.protocolParams.moduli) + this.protocolParams.moduli, ); default: throw new Error("Protocol not supported"); @@ -155,7 +155,7 @@ export class EnclaveSDK { */ public async encryptVector( data: BigUint64Array, - publicKey: Uint8Array + publicKey: Uint8Array, ): Promise<Uint8Array> { await initializeWasm(); switch (this.protocol) { @@ -165,7 +165,7 @@ export class EnclaveSDK { publicKey, this.protocolParams.degree, this.protocolParams.plaintextModulus, - new BigUint64Array(this.protocolParams.moduli) + this.protocolParams.moduli, ); default: throw new Error("Protocol not supported"); @@ -181,8 +181,10 @@ export class EnclaveSDK { */ public async encryptNumberAndGenInputs( data: bigint, - publicKey: Uint8Array + publicKey: Uint8Array, ): Promise<EncryptedValueAndPublicInputs> { + console.log("encrypting number:" + data); + console.log("encrypting with public key:" + publicKey); await initializeWasm(); switch (this.protocol) { case FheProtocol.BFV: @@ -191,7 +193,7 @@ export class EnclaveSDK { publicKey, this.protocolParams.degree, this.protocolParams.plaintextModulus, - new BigUint64Array(this.protocolParams.moduli) + this.protocolParams.moduli, ); const publicInputs = JSON.parse(circuitInputs); @@ -214,7 +216,7 @@ export class EnclaveSDK { public async encryptNumberAndGenProof( data: bigint, publicKey: Uint8Array, - circuit: CompiledCircuit + circuit: CompiledCircuit, ): Promise<VerifiableEncryptionResult> { const { publicInputs, encryptedData } = await this.encryptNumberAndGenInputs(data, publicKey); @@ -234,7 +236,7 @@ export class EnclaveSDK { */ public async encryptVectorAndGenInputs( data: BigUint64Array, - publicKey: Uint8Array + publicKey: Uint8Array, ): Promise<EncryptedValueAndPublicInputs> { await initializeWasm(); switch (this.protocol) { @@ -244,7 +246,7 @@ export class EnclaveSDK { publicKey, this.protocolParams.degree, this.protocolParams.plaintextModulus, - new BigUint64Array(this.protocolParams.moduli) + this.protocolParams.moduli, ); const publicInputs = JSON.parse(circuitInputs); @@ -267,7 +269,7 @@ export class EnclaveSDK { public async encryptVectorAndGenProof( data: BigUint64Array, publicKey: Uint8Array, - circuit: CompiledCircuit + circuit: CompiledCircuit, ): Promise<VerifiableEncryptionResult> { const { publicInputs, encryptedData } = await this.encryptVectorAndGenInputs(data, publicKey); @@ -322,7 +324,7 @@ export class EnclaveSDK { params.e3ProgramParams, params.computeProviderParams, params.customParams, - params.gasLimit + params.gasLimit, ); } @@ -345,7 +347,7 @@ export class EnclaveSDK { public async activateE3( e3Id: bigint, publicKey: `0x${string}`, - gasLimit?: bigint + gasLimit?: bigint, ): Promise<Hash> { if (!this.initialized) { await this.initialize(); @@ -360,7 +362,7 @@ export class EnclaveSDK { public async publishInput( e3Id: bigint, data: `0x${string}`, - gasLimit?: bigint + gasLimit?: bigint, ): Promise<Hash> { if (!this.initialized) { await this.initialize(); @@ -376,7 +378,7 @@ export class EnclaveSDK { e3Id: bigint, ciphertextOutput: `0x${string}`, proof: `0x${string}`, - gasLimit?: bigint + gasLimit?: bigint, ): Promise<Hash> { if (!this.initialized) { await this.initialize(); @@ -386,7 +388,7 @@ export class EnclaveSDK { e3Id, ciphertextOutput, proof, - gasLimit + gasLimit, ); } @@ -406,11 +408,11 @@ export class EnclaveSDK { */ public onEnclaveEvent<T extends AllEventTypes>( eventType: T, - callback: EventCallback<T> + callback: EventCallback<T>, ): void { // Determine which contract to listen to based on event type const isEnclaveEvent = Object.values(EnclaveEventType).includes( - eventType as EnclaveEventType + eventType as EnclaveEventType, ); const contractAddress = isEnclaveEvent ? this.config.contracts.enclave @@ -423,7 +425,7 @@ export class EnclaveSDK { contractAddress, eventType, abi, - callback + callback, ); } @@ -432,7 +434,7 @@ export class EnclaveSDK { */ public off<T extends AllEventTypes>( eventType: T, - callback: EventCallback<T> + callback: EventCallback<T>, ): void { this.eventListener.off(eventType, callback); } @@ -442,7 +444,7 @@ export class EnclaveSDK { */ public once<T extends AllEventTypes>( type: T, - callback: EventCallback<T> + callback: EventCallback<T>, ): void { const handler: EventCallback<T> = (event) => { this.off(type, handler); @@ -460,10 +462,10 @@ export class EnclaveSDK { public async getHistoricalEvents( eventType: AllEventTypes, fromBlock?: bigint, - toBlock?: bigint + toBlock?: bigint, ): Promise<Log[]> { const isEnclaveEvent = Object.values(EnclaveEventType).includes( - eventType as EnclaveEventType + eventType as EnclaveEventType, ); const contractAddress = isEnclaveEvent ? this.config.contracts.enclave @@ -477,7 +479,7 @@ export class EnclaveSDK { eventType, abi, fromBlock, - toBlock + toBlock, ); } @@ -507,14 +509,14 @@ export class EnclaveSDK { args: readonly unknown[], contractAddress: `0x${string}`, abi: Abi, - value?: bigint + value?: bigint, ): Promise<bigint> { return this.contractClient.estimateGas( functionName, args, contractAddress, abi, - value + value, ); } @@ -560,7 +562,7 @@ export class EnclaveSDK { this.contractClient = new ContractClient( this.config.publicClient, this.config.walletClient, - this.config.contracts + this.config.contracts, ); this.initialized = false; @@ -584,9 +586,9 @@ export class EnclaveSDK { options.rpcUrl.startsWith("ws://") || options.rpcUrl.startsWith("wss://"); const transport = isWebSocket ? webSocket(options.rpcUrl, { - keepAlive: { interval: 30_000 }, - reconnect: { attempts: 5, delay: 2_000 }, - }) + keepAlive: { interval: 30_000 }, + reconnect: { attempts: 5, delay: 2_000 }, + }) : http(options.rpcUrl); const publicClient = createPublicClient({ chain, From 887d26c89c507d06407a0511826ad275684b2634 Mon Sep 17 00:00:00 2001 From: ryardley <contact@rudiyardley.com> Date: Fri, 7 Nov 2025 11:47:02 -0300 Subject: [PATCH 34/61] ensure building --- scripts/run-crisp-test.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/run-crisp-test.sh b/scripts/run-crisp-test.sh index f13c1cccc1..402e542c85 100755 --- a/scripts/run-crisp-test.sh +++ b/scripts/run-crisp-test.sh @@ -6,4 +6,4 @@ echo "Press any key to continue or Ctrl+C to cancel..." read -rm -rf * && git reset --hard HEAD && git submodule update --init --recursive && pnpm install && cd examples/CRISP && pnpm test:e2e "$@" +rm -rf * && git reset --hard HEAD && git submodule update --init --recursive && pnpm install && pnpm build && cd examples/CRISP && pnpm test:e2e "$@" From 7c83ffb0d8742a85bf51634d10ba20e9bff33b05 Mon Sep 17 00:00:00 2001 From: ryardley <contact@rudiyardley.com> Date: Fri, 7 Nov 2025 11:58:09 -0300 Subject: [PATCH 35/61] dont compile nargo stuff when nargo is not installed --- scripts/compile-circuits.sh | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/scripts/compile-circuits.sh b/scripts/compile-circuits.sh index 70355883d1..7c14d6e781 100755 --- a/scripts/compile-circuits.sh +++ b/scripts/compile-circuits.sh @@ -5,6 +5,12 @@ set -euo pipefail # Ensure we're in the right directory cd circuits +if ! command -v nargo >/dev/null 2>&1 +then + echo "nargo could not be found" + exit 0 # exiting 0 so that other scripts are not affected +fi + # Checking circuit format echo "Checking circuit format..." if ! (nargo fmt --check); then @@ -19,4 +25,4 @@ if ! (nargo compile --workspace); then exit 1 fi -echo "Noir circuits compiled successfully" \ No newline at end of file +echo "Noir circuits compiled successfully" From 3ee4d10c8b10ed2bcd970d39525ad127c7de4796 Mon Sep 17 00:00:00 2001 From: ryardley <contact@rudiyardley.com> Date: Fri, 7 Nov 2025 13:07:30 -0300 Subject: [PATCH 36/61] add more logging --- examples/CRISP/playwright.config.ts | 4 ++- examples/CRISP/test/crisp.spec.ts | 41 ++++++++++++++++++++++++----- 2 files changed, 38 insertions(+), 7 deletions(-) diff --git a/examples/CRISP/playwright.config.ts b/examples/CRISP/playwright.config.ts index b5770d4ec8..20788b4627 100644 --- a/examples/CRISP/playwright.config.ts +++ b/examples/CRISP/playwright.config.ts @@ -17,7 +17,9 @@ export default defineConfig({ fullyParallel: true, forbidOnly: !!process.env.CI, workers: process.env.CI ? 1 : undefined, - reporter: "html", + // reporter: "html", + reporter: [["html"], ["list"]], // Add list reporter + // Add support for ES modules projects: [ { diff --git a/examples/CRISP/test/crisp.spec.ts b/examples/CRISP/test/crisp.spec.ts index 56b894b808..a066a3dce0 100644 --- a/examples/CRISP/test/crisp.spec.ts +++ b/examples/CRISP/test/crisp.spec.ts @@ -4,7 +4,7 @@ // without even the implied warranty of MERCHANTABILITY // or FITNESS FOR A PARTICULAR PURPOSE. -import { Page } from "@playwright/test"; +import { ConsoleMessage, Page } from "@playwright/test"; import { testWithSynpress } from "@synthetixio/synpress"; import { MetaMask, metaMaskFixtures } from "@synthetixio/synpress/playwright"; import basicSetup from "./wallet-setup/basic.setup"; @@ -70,12 +70,25 @@ async function ensureHomePageLoaded(page: Page) { ); } +function log(msg: string) { + console.log(`[playwright] ${msg}`); +} + test("CRISP smoke test", async ({ context, page, metamaskPage, extensionId, }) => { + page.on("console", (msg: ConsoleMessage) => { + console.log(msg.text()); + }); + + log("============================================"); + log(" STARTING YOUR PLAYWRIGHT TEST! "); + log("============================================"); + + log("Creating new Metamask..."); const metamask = new MetaMask( context, metamaskPage, @@ -83,35 +96,51 @@ test("CRISP smoke test", async ({ extensionId, ); + log("runCliInit()..."); const e3id = await runCliInit(); - console.log(`Got e3 id: ${e3id}`); + log(`Got e3 id: ${e3id}`); await page.goto("/"); - page.on("console", (...msg: any[]) => { - console.log(...msg); - }); - + log(`ensureHomePageLoaded...`); await ensureHomePageLoaded(page); + + log(`searching for connect button...`); await page.locator('button:has-text("Connect Wallet")').click(); + log(`searching for MetaMask button...`); await page.locator('button:has-text("MetaMask")').click(); + log(`connecting to dapp...`); await metamask.connectToDapp(); + log(`clicking try demo...`); await page.locator('button:has-text("Try Demo")').click(); + log(`waiting for E3 activation...`); await waitForE3Activation(e3id); + log(`forcing page reload...`); await page.reload(); + log(`clicking first vote card...`); await page .locator("[data-test-id='poll-button-0'] > [data-test-id='card']") .click(); + log(`clicking Cast Vote...`); await page.locator('button:has-text("Cast Vote")').click(); + log(`waiting for 220_000...`); await page.waitForTimeout(220_000); + log(`clicking historic polls button...`); await page.locator('a:has-text("Historic polls")').click(); + log(`asserting that Historic polls exists...`); await expect(page.locator("h1")).toHaveText("Historic polls"); + log(`asserting that result has 100% on the vote we clicked on...`); await expect( page.locator("[data-test-id='poll-0-0'] [data-test-id='poll-result-0'] h3"), ).toHaveText("100%"); + log(`asserting that result has 0% on the vote we did not click on...`); await expect( page.locator("[data-test-id='poll-0-0'] [data-test-id='poll-result-1'] h3"), ).toHaveText("0%"); + + log("============================================"); + log(" PLAYWRIGHT TEST IS COMPLETE "); + log("============================================"); }); From 08d82750ef0a2dde606aca7476e1d8daf3c7349c Mon Sep 17 00:00:00 2001 From: ryardley <contact@rudiyardley.com> Date: Fri, 7 Nov 2025 14:25:27 -0300 Subject: [PATCH 37/61] update parameter set --- .../CRISP/server/src/server/routes/rounds.rs | 2 +- packages/enclave-sdk/src/utils.ts | 42 ++++++++++++++----- 2 files changed, 32 insertions(+), 12 deletions(-) diff --git a/examples/CRISP/server/src/server/routes/rounds.rs b/examples/CRISP/server/src/server/routes/rounds.rs index 83a7746940..45000056f4 100644 --- a/examples/CRISP/server/src/server/routes/rounds.rs +++ b/examples/CRISP/server/src/server/routes/rounds.rs @@ -181,7 +181,7 @@ pub async fn initialize_crisp_round( } info!("Generating parameters..."); - let params = encode_bfv_params(&build_bfv_params_from_set_arc(SET_2048_1032193_1)); + let params = encode_bfv_params(&build_bfv_params_from_set_arc(SET_8192_1000_4)); let token_address: Address = token_address.parse()?; let balance_threshold = BigUint::parse_bytes(balance_threshold.as_bytes(), 10) diff --git a/packages/enclave-sdk/src/utils.ts b/packages/enclave-sdk/src/utils.ts index ece09846f0..78ec9c4f3e 100644 --- a/packages/enclave-sdk/src/utils.ts +++ b/packages/enclave-sdk/src/utils.ts @@ -7,7 +7,10 @@ import { type Address, type Hash, type Log, encodeAbiParameters } from "viem"; export class SDKError extends Error { - constructor(message: string, public readonly code?: string) { + constructor( + message: string, + public readonly code?: string, + ) { super(message); this.name = "SDKError"; } @@ -23,7 +26,7 @@ export function isValidHash(hash: string): hash is Hash { export function formatEventName( contractName: string, - eventName: string + eventName: string, ): string { return `${contractName}.${eventName}`; } @@ -59,13 +62,30 @@ export function getCurrentTimestamp(): number { } // BFV parameter set matching the Rust SET_2048_1032193_1 configuration -export const BFV_PARAMS_SET = { +export const SET_2048_1032193_1 = { degree: 2048, plaintext_modulus: 1032193, moduli: [0x3fffffff000001n], // BigInt for the modulus error2_variance: "10", } as const; +// BFV parameter set matching the Rust SET_8192_1000_4 configuration +export const SET_8192_1000_4 = { + degree: 8192, + plaintext_modulus: 1000, + moduli: [ + 0x00800000022a0001n, + 0x00800000021a0001n, + 0x0080000002120001n, + 0x0080000001f60001n, + ], + error2_variance: + "52309181128222339698631578526730685514457152477762943514050560000", +}; + +// Set default parameter set +export const BFV_PARAMS_SET = SET_8192_1000_4; + // Compute provider parameters structure export interface ComputeProviderParams { name: string; @@ -97,7 +117,7 @@ export function encodeBfvParams( degree: number = BFV_PARAMS_SET.degree, plaintext_modulus: number = BFV_PARAMS_SET.plaintext_modulus, moduli: readonly bigint[] = BFV_PARAMS_SET.moduli, - error2_variance: string = BFV_PARAMS_SET.error2_variance + error2_variance: string = BFV_PARAMS_SET.error2_variance, ): `0x${string}` { return encodeAbiParameters( [ @@ -119,7 +139,7 @@ export function encodeBfvParams( moduli: [...moduli], error2_variance, }, - ] + ], ); } @@ -129,7 +149,7 @@ export function encodeBfvParams( */ export function encodeComputeProviderParams( params: ComputeProviderParams, - mock: boolean = false + mock: boolean = false, ): `0x${string}` { if (mock) { return `0x${"0".repeat(32)}` as `0x${string}`; @@ -140,7 +160,7 @@ export function encodeComputeProviderParams( const bytes = encoder.encode(jsonString); return `0x${Array.from(bytes, (byte) => - byte.toString(16).padStart(2, "0") + byte.toString(16).padStart(2, "0"), ).join("")}`; } @@ -148,14 +168,14 @@ export function encodeComputeProviderParams( * Encode custom parameters for the smart contract. */ export function encodeCustomParams( - params: Record<string, unknown> + params: Record<string, unknown>, ): `0x${string}` { const jsonString = JSON.stringify(params); const encoder = new TextEncoder(); const bytes = encoder.encode(jsonString); return `0x${Array.from(bytes, (byte) => - byte.toString(16).padStart(2, "0") + byte.toString(16).padStart(2, "0"), ).join("")}`; } @@ -163,7 +183,7 @@ export function encodeCustomParams( * Calculate start window for E3 request */ export function calculateStartWindow( - windowSize: number = DEFAULT_E3_CONFIG.window_size + windowSize: number = DEFAULT_E3_CONFIG.window_size, ): [bigint, bigint] { const now = getCurrentTimestamp(); return [BigInt(now), BigInt(now + windowSize)]; @@ -181,7 +201,7 @@ export function decodePlaintextOutput(plaintextOutput: string): number | null { // Convert hex to bytes const bytes = new Uint8Array( - hex.match(/.{1,2}/g)?.map((byte) => parseInt(byte, 16)) || [] + hex.match(/.{1,2}/g)?.map((byte) => parseInt(byte, 16)) || [], ); if (bytes.length < 8) { From 2359b4c88f5ac877871900de10b007c86de8740e Mon Sep 17 00:00:00 2001 From: ryardley <contact@rudiyardley.com> Date: Fri, 7 Nov 2025 14:32:04 -0300 Subject: [PATCH 38/61] fix ts errors --- packages/enclave-sdk/src/enclave-sdk.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/enclave-sdk/src/enclave-sdk.ts b/packages/enclave-sdk/src/enclave-sdk.ts index 25cc792c29..97e5922d55 100644 --- a/packages/enclave-sdk/src/enclave-sdk.ts +++ b/packages/enclave-sdk/src/enclave-sdk.ts @@ -140,7 +140,7 @@ export class EnclaveSDK { publicKey, this.protocolParams.degree, this.protocolParams.plaintextModulus, - this.protocolParams.moduli, + BigUint64Array.from(this.protocolParams.moduli), ); default: throw new Error("Protocol not supported"); @@ -165,7 +165,7 @@ export class EnclaveSDK { publicKey, this.protocolParams.degree, this.protocolParams.plaintextModulus, - this.protocolParams.moduli, + BigUint64Array.from(this.protocolParams.moduli), ); default: throw new Error("Protocol not supported"); @@ -193,7 +193,7 @@ export class EnclaveSDK { publicKey, this.protocolParams.degree, this.protocolParams.plaintextModulus, - this.protocolParams.moduli, + BigUint64Array.from(this.protocolParams.moduli), ); const publicInputs = JSON.parse(circuitInputs); @@ -246,7 +246,7 @@ export class EnclaveSDK { publicKey, this.protocolParams.degree, this.protocolParams.plaintextModulus, - this.protocolParams.moduli, + BigUint64Array.from(this.protocolParams.moduli), ); const publicInputs = JSON.parse(circuitInputs); From 51d0732728931ee8562de2c18fe149415c932c24 Mon Sep 17 00:00:00 2001 From: ryardley <contact@rudiyardley.com> Date: Fri, 7 Nov 2025 14:38:43 -0300 Subject: [PATCH 39/61] revert trbfv --- examples/CRISP/scripts/dev_cipher.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/CRISP/scripts/dev_cipher.sh b/examples/CRISP/scripts/dev_cipher.sh index d582073653..948c601261 100755 --- a/examples/CRISP/scripts/dev_cipher.sh +++ b/examples/CRISP/scripts/dev_cipher.sh @@ -23,7 +23,7 @@ enclave wallet set --name cn4 --private-key "$PRIVATE_KEY_CN4" enclave wallet set --name cn5 --private-key "$PRIVATE_KEY_CN5" # using & instead of -d so that wait works below -enclave nodes up -v & +enclave nodes up -v --experimental-trbfv & sleep 2 From bd852b890a0be69a47a45e52c27920ebd39c397a Mon Sep 17 00:00:00 2001 From: ryardley <contact@rudiyardley.com> Date: Fri, 7 Nov 2025 14:39:39 -0300 Subject: [PATCH 40/61] use trbfv on template --- templates/default/scripts/dev_ciphernodes.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/default/scripts/dev_ciphernodes.sh b/templates/default/scripts/dev_ciphernodes.sh index e6f982b859..425d8e291a 100755 --- a/templates/default/scripts/dev_ciphernodes.sh +++ b/templates/default/scripts/dev_ciphernodes.sh @@ -35,7 +35,7 @@ enclave wallet set --name cn2 --private-key "$PRIVATE_KEY_CN2" enclave wallet set --name cn3 --private-key "$PRIVATE_KEY_CN3" # using & instead of -d so that wait works below -enclave nodes up -v & +enclave nodes up -v --experimental-trbfv & sleep 2 From ddee19f8ac19be7542a7cc78168e92a07ff696a4 Mon Sep 17 00:00:00 2001 From: ryardley <contact@rudiyardley.com> Date: Fri, 7 Nov 2025 14:44:31 -0300 Subject: [PATCH 41/61] use 5 nodes --- templates/default/enclave.config.yaml | 12 +++++++++++- templates/default/scripts/dev_ciphernodes.sh | 14 ++++++++++---- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/templates/default/enclave.config.yaml b/templates/default/enclave.config.yaml index 8df8049404..24274110bf 100644 --- a/templates/default/enclave.config.yaml +++ b/templates/default/enclave.config.yaml @@ -41,10 +41,20 @@ nodes: quic_port: 9203 autonetkey: true autopassword: true - ag: + cn4: address: "0x15d34AAf54267DB7D7c367839AAf71A00a2C6A65" quic_port: 9204 autonetkey: true autopassword: true + cn5: + address: "0x9965507D1a55bcC2695C58ba16FB37d819B0A4dc" + quic_port: 9205 + autonetkey: true + autopassword: true + ag: + address: "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" + quic_port: 9206 + autonetkey: true + autopassword: true role: type: aggregator diff --git a/templates/default/scripts/dev_ciphernodes.sh b/templates/default/scripts/dev_ciphernodes.sh index 425d8e291a..a51214c5ef 100755 --- a/templates/default/scripts/dev_ciphernodes.sh +++ b/templates/default/scripts/dev_ciphernodes.sh @@ -28,11 +28,15 @@ PRIVATE_KEY_AG="0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff PRIVATE_KEY_CN1="0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d" PRIVATE_KEY_CN2="0x5de4111afa1a4b94908f83103eb1f1706367c2e68ca870fc3fb9a804cdab365a" PRIVATE_KEY_CN3="0x7c852118294e51e653712a81e05800f419141751be58f605c371e15141b007a6" +PRIVATE_KEY_CN4="0x47e179ec197488593b187f80a00eb0da91f1b9d0b13f8733639f19c30a34926a" +PRIVATE_KEY_CN5="0x8b3a350cf5c34c9194ca85829a2df0ec3153be0318b5e2d3348e872092edffba" -enclave wallet set --name ag --private-key "$PRIVATE_KEY_AG" -enclave wallet set --name cn1 --private-key "$PRIVATE_KEY_CN1" -enclave wallet set --name cn2 --private-key "$PRIVATE_KEY_CN2" -enclave wallet set --name cn3 --private-key "$PRIVATE_KEY_CN3" +enclave wallet set --name ag --private-key "$PRIVATE_KEY_AG" +enclave wallet set --name cn1 --private-key "$PRIVATE_KEY_CN1" +enclave wallet set --name cn2 --private-key "$PRIVATE_KEY_CN2" +enclave wallet set --name cn3 --private-key "$PRIVATE_KEY_CN3" +enclave wallet set --name cn4 --private-key "$PRIVATE_KEY_CN4" +enclave wallet set --name cn5 --private-key "$PRIVATE_KEY_CN5" # using & instead of -d so that wait works below enclave nodes up -v --experimental-trbfv & @@ -48,6 +52,8 @@ pnpm run deploy && sleep 2 pnpm hardhat ciphernode:admin-add --ciphernode-address $CN1 --network localhost pnpm hardhat ciphernode:admin-add --ciphernode-address $CN2 --network localhost pnpm hardhat ciphernode:admin-add --ciphernode-address $CN3 --network localhost +pnpm hardhat ciphernode:admin-add --ciphernode-address $CN4 --network localhost +pnpm hardhat ciphernode:admin-add --ciphernode-address $CN5 --network localhost # Function to send RPC request. send_rpc() { From f2bc2f13d916380f9423b60568e15770da266e83 Mon Sep 17 00:00:00 2001 From: ryardley <contact@rudiyardley.com> Date: Fri, 7 Nov 2025 14:59:07 -0300 Subject: [PATCH 42/61] fix broken import --- examples/CRISP/server/src/server/routes/rounds.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/CRISP/server/src/server/routes/rounds.rs b/examples/CRISP/server/src/server/routes/rounds.rs index 45000056f4..6197fdde30 100644 --- a/examples/CRISP/server/src/server/routes/rounds.rs +++ b/examples/CRISP/server/src/server/routes/rounds.rs @@ -13,6 +13,7 @@ use crate::server::models::{ use actix_web::{web, HttpResponse, Responder}; use alloy::primitives::{Address, Bytes, U256}; use chrono::Utc; +use e3_sdk::bfv_helpers::params::SET_8192_1000_4; use e3_sdk::bfv_helpers::{ build_bfv_params_from_set_arc, encode_bfv_params, params::SET_2048_1032193_1, }; From fbe59813c08aef57f286bef7a30ee2d238988451 Mon Sep 17 00:00:00 2001 From: Hamza Khalid <Hamzakhalid829@gmail.com> Date: Sat, 8 Nov 2025 00:36:48 +0500 Subject: [PATCH 43/61] chore: switch to trbfv params --- .../client/libs/wasm/pkg/crisp_worker.js | 2 +- examples/CRISP/server/src/cli/commands.rs | 4 +- .../CRISP/server/src/server/routes/rounds.rs | 2 +- .../enclave-contracts/deployed_contracts.json | 64 +++++++++---------- .../scripts/deployEnclave.ts | 11 +++- packages/enclave-sdk/src/enclave-sdk.ts | 3 + packages/enclave-sdk/src/types.ts | 6 +- 7 files changed, 52 insertions(+), 40 deletions(-) diff --git a/examples/CRISP/client/libs/wasm/pkg/crisp_worker.js b/examples/CRISP/client/libs/wasm/pkg/crisp_worker.js index ca7e32587b..f9a42d856e 100755 --- a/examples/CRISP/client/libs/wasm/pkg/crisp_worker.js +++ b/examples/CRISP/client/libs/wasm/pkg/crisp_worker.js @@ -26,7 +26,7 @@ self.onmessage = async function (event) { rpcUrl: 'http://localhost:8545', // default Anvil private key privateKey: '0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80', - protocol: FheProtocol.BFV, + protocol: FheProtocol.TRBFV, }) const result = await sdk.encryptNumberAndGenProof(voteId, publicKey, circuit) diff --git a/examples/CRISP/server/src/cli/commands.rs b/examples/CRISP/server/src/cli/commands.rs index a1767899f6..f442d60e08 100644 --- a/examples/CRISP/server/src/cli/commands.rs +++ b/examples/CRISP/server/src/cli/commands.rs @@ -16,7 +16,7 @@ use alloy::primitives::{Address, Bytes, U256}; use alloy::providers::{Provider, ProviderBuilder}; use crisp::config::CONFIG; use e3_sdk::bfv_helpers::{ - build_bfv_params_from_set_arc, encode_bfv_params, params::SET_2048_1032193_1, + build_bfv_params_from_set_arc, encode_bfv_params, params::SET_8192_1000_4, }; use e3_sdk::evm_helpers::contracts::{EnclaveContract, EnclaveRead, EnclaveWrite, E3}; use fhe::bfv::{BfvParameters, Ciphertext, Encoding, Plaintext, PublicKey, SecretKey}; @@ -329,7 +329,7 @@ pub async fn decrypt_and_publish_result( } fn generate_bfv_parameters() -> Arc<BfvParameters> { - build_bfv_params_from_set_arc(SET_2048_1032193_1) + build_bfv_params_from_set_arc(SET_8192_1000_4) } fn generate_keys(params: &Arc<BfvParameters>) -> (SecretKey, PublicKey) { diff --git a/examples/CRISP/server/src/server/routes/rounds.rs b/examples/CRISP/server/src/server/routes/rounds.rs index 6197fdde30..c541b21770 100644 --- a/examples/CRISP/server/src/server/routes/rounds.rs +++ b/examples/CRISP/server/src/server/routes/rounds.rs @@ -15,7 +15,7 @@ use alloy::primitives::{Address, Bytes, U256}; use chrono::Utc; use e3_sdk::bfv_helpers::params::SET_8192_1000_4; use e3_sdk::bfv_helpers::{ - build_bfv_params_from_set_arc, encode_bfv_params, params::SET_2048_1032193_1, + build_bfv_params_from_set_arc, encode_bfv_params, params::SET_8192_1000_4, }; use e3_sdk::evm_helpers::contracts::{EnclaveContract, EnclaveRead, EnclaveWrite}; use log::{error, info}; diff --git a/packages/enclave-contracts/deployed_contracts.json b/packages/enclave-contracts/deployed_contracts.json index ada5eef523..d7b83debd8 100644 --- a/packages/enclave-contracts/deployed_contracts.json +++ b/packages/enclave-contracts/deployed_contracts.json @@ -116,45 +116,45 @@ }, "localhost": { "PoseidonT3": { - "blockNumber": 86, + "blockNumber": 1, "address": "0x3333333C0A88F9BE4fd23ed0536F9B6c427e3B93" }, "MockUSDC": { "constructorArgs": { "initialSupply": "1000000" }, - "blockNumber": 4, - "address": "0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0" + "blockNumber": 2, + "address": "0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512" }, "EnclaveToken": { "constructorArgs": { "owner": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" }, - "blockNumber": 5, - "address": "0xCf7Ed3AccA5a467e9e704C703E8D87F634fB0Fc9" + "blockNumber": 3, + "address": "0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0" }, "EnclaveTicketToken": { "constructorArgs": { - "baseToken": "0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0", + "baseToken": "0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512", "registry": "0x0000000000000000000000000000000000000001", "owner": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" }, - "blockNumber": 7, - "address": "0x5FC8d32690cc91D4c39d9d3abcBD16989F875707" + "blockNumber": 5, + "address": "0xDc64a140Aa3E981100a9becA4E685f962f0cF6C9" }, "SlashingManager": { "constructorArgs": { "admin": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", "bondingRegistry": "0x0000000000000000000000000000000000000001" }, - "blockNumber": 8, - "address": "0x0165878A594ca255338adfa4d48449f69242Eb8F" + "blockNumber": 6, + "address": "0x5FC8d32690cc91D4c39d9d3abcBD16989F875707" }, "BondingRegistry": { "constructorArgs": { "owner": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", - "ticketToken": "0x5FC8d32690cc91D4c39d9d3abcBD16989F875707", - "licenseToken": "0xCf7Ed3AccA5a467e9e704C703E8D87F634fB0Fc9", + "ticketToken": "0xDc64a140Aa3E981100a9becA4E685f962f0cF6C9", + "licenseToken": "0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0", "registry": "0x0000000000000000000000000000000000000001", "slashedFundsTreasury": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", "ticketPrice": "10000000", @@ -162,50 +162,50 @@ "minTicketBalance": "1", "exitDelay": "604800" }, - "blockNumber": 9, - "address": "0xa513E6E4b8f2a923D98304ec87F64353C4D5C853" + "blockNumber": 7, + "address": "0x0165878A594ca255338adfa4d48449f69242Eb8F" }, "CiphernodeRegistryOwnable": { "constructorArgs": { "owner": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", "enclaveAddress": "0x0000000000000000000000000000000000000001", - "submissionWindow": "15" + "submissionWindow": "10" }, - "blockNumber": 10, - "address": "0x2279B7A0a67DB372996a5FaB50D91eAA73d2eBe6" + "blockNumber": 8, + "address": "0xa513E6E4b8f2a923D98304ec87F64353C4D5C853" }, "Enclave": { "constructorArgs": { "owner": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", - "registry": "0x2279B7A0a67DB372996a5FaB50D91eAA73d2eBe6", - "bondingRegistry": "0xa513E6E4b8f2a923D98304ec87F64353C4D5C853", - "feeToken": "0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0", + "registry": "0xa513E6E4b8f2a923D98304ec87F64353C4D5C853", + "bondingRegistry": "0x0165878A594ca255338adfa4d48449f69242Eb8F", + "feeToken": "0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512", "maxDuration": "2592000", "params": [ - "0x000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000fc00100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000003fffffff000001" + "0x000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000fc0010000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000800000022a000100000000000000000000000000000000000000000000000000800000021a000100000000000000000000000000000000000000000000000000800000021200010000000000000000000000000000000000000000000000000080000001f60001" ] }, - "blockNumber": 11, - "address": "0x8A791620dd6260079BF849Dc5567aDC3F2FdC318" + "blockNumber": 9, + "address": "0x2279B7A0a67DB372996a5FaB50D91eAA73d2eBe6" }, "MockComputeProvider": { - "blockNumber": 20, - "address": "0x68B1D87F95878fE05B998F19b66F4baba5De1aed" + "blockNumber": 18, + "address": "0x9A9f2CCfdE556A7E9Ff0848998Aa4a0CFD8863AE" }, "MockDecryptionVerifier": { - "blockNumber": 21, - "address": "0x3Aa5ebB10DC797CAC828524e59A333d0A371443c" + "blockNumber": 19, + "address": "0x68B1D87F95878fE05B998F19b66F4baba5De1aed" }, "MockInputValidator": { - "blockNumber": 22, - "address": "0xc6e7DF5E7b4f2A278906862b61205850344D4e7d" + "blockNumber": 20, + "address": "0x3Aa5ebB10DC797CAC828524e59A333d0A371443c" }, "MockE3Program": { "constructorArgs": { - "mockInputValidator": "0xc6e7DF5E7b4f2A278906862b61205850344D4e7d" + "mockInputValidator": "0x3Aa5ebB10DC797CAC828524e59A333d0A371443c" }, - "blockNumber": 23, - "address": "0x59b670e9fA9D0A427751Af201D676719a970857b" + "blockNumber": 21, + "address": "0xc6e7DF5E7b4f2A278906862b61205850344D4e7d" } } } \ No newline at end of file diff --git a/packages/enclave-contracts/scripts/deployEnclave.ts b/packages/enclave-contracts/scripts/deployEnclave.ts index e6779b5f83..5e4a2def74 100644 --- a/packages/enclave-contracts/scripts/deployEnclave.ts +++ b/packages/enclave-contracts/scripts/deployEnclave.ts @@ -30,9 +30,14 @@ export const deployEnclave = async (withMocks?: boolean) => { const ownerAddress = await owner.getAddress(); - const polynomial_degree = ethers.toBigInt(2048); - const plaintext_modulus = ethers.toBigInt(1032193); - const moduli = [ethers.toBigInt("18014398492704769")]; + const polynomial_degree = ethers.toBigInt(8192); + const plaintext_modulus = ethers.toBigInt(1000); + const moduli = [ + ethers.toBigInt("36028797055270913"), + ethers.toBigInt("36028797054222337"), + ethers.toBigInt("36028797053698049"), + ethers.toBigInt("36028797051863041"), + ]; const encoded = ethers.AbiCoder.defaultAbiCoder().encode( ["uint256", "uint256", "uint256[]"], diff --git a/packages/enclave-sdk/src/enclave-sdk.ts b/packages/enclave-sdk/src/enclave-sdk.ts index 97e5922d55..7ce9fdd283 100644 --- a/packages/enclave-sdk/src/enclave-sdk.ts +++ b/packages/enclave-sdk/src/enclave-sdk.ts @@ -98,6 +98,9 @@ export class EnclaveSDK { case FheProtocol.BFV: this.protocolParams = BfvProtocolParams.BFV_NORMAL; break; + case FheProtocol.TRBFV: + this.protocolParams = BfvProtocolParams.BFV_THRESHOLD; + break; default: throw new Error("Protocol not supported"); } diff --git a/packages/enclave-sdk/src/types.ts b/packages/enclave-sdk/src/types.ts index 627b06a1fe..a07901a4f7 100644 --- a/packages/enclave-sdk/src/types.ts +++ b/packages/enclave-sdk/src/types.ts @@ -291,6 +291,10 @@ export enum FheProtocol { * The BFV protocol */ BFV = "BFV", + /** + * The TrBFV protocol + */ + TRBFV = "TRBFV", } /** @@ -339,7 +343,7 @@ export const BfvProtocolParams = { */ BFV_THRESHOLD: { degree: 8192, - plaintextModulus: 1032193n, + plaintextModulus: 1000n, moduli: [ 0x00800000022a0001n, 0x00800000021a0001n, From 586c16c2b391d30c7eda9aec9f5efd891b9fa193 Mon Sep 17 00:00:00 2001 From: Hamza Khalid <Hamzakhalid829@gmail.com> Date: Sat, 8 Nov 2025 00:44:43 +0500 Subject: [PATCH 44/61] fix: revert trbfv for e2e --- .../client/libs/wasm/pkg/crisp_worker.js | 5 +- examples/CRISP/client/package.json | 2 +- examples/CRISP/scripts/dev_cipher.sh | 2 +- examples/CRISP/server/src/cli/commands.rs | 4 +- .../CRISP/server/src/server/routes/rounds.rs | 5 +- .../scripts/deployEnclave.ts | 11 +--- pnpm-lock.yaml | 59 ++++++++++++++++++- 7 files changed, 68 insertions(+), 20 deletions(-) diff --git a/examples/CRISP/client/libs/wasm/pkg/crisp_worker.js b/examples/CRISP/client/libs/wasm/pkg/crisp_worker.js index f9a42d856e..35a7aa5656 100755 --- a/examples/CRISP/client/libs/wasm/pkg/crisp_worker.js +++ b/examples/CRISP/client/libs/wasm/pkg/crisp_worker.js @@ -20,13 +20,12 @@ self.onmessage = async function (event) { contracts: { enclave: '0xc6e7DF5E7b4f2A278906862b61205850344D4e7d', ciphernodeRegistry: '0xc6e7DF5E7b4f2A278906862b61205850344D4e7d', - feeToken: '0xc6e7DF5E7b4f2A278906862b61205850344D4e7d', }, // local node rpcUrl: 'http://localhost:8545', // default Anvil private key privateKey: '0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80', - protocol: FheProtocol.TRBFV, + protocol: FheProtocol.BFV, }) const result = await sdk.encryptNumberAndGenProof(voteId, publicKey, circuit) @@ -35,7 +34,7 @@ self.onmessage = async function (event) { type: 'encrypt_vote', success: true, encryptedVote: { - vote: result.encryptedData, + vote: result.encryptedVote, proofData: result.proof, }, }) diff --git a/examples/CRISP/client/package.json b/examples/CRISP/client/package.json index 4e56b1544e..ee0b5c94dc 100644 --- a/examples/CRISP/client/package.json +++ b/examples/CRISP/client/package.json @@ -22,7 +22,7 @@ "@aztec/bb.js": "^0.82.2", "@emotion/babel-plugin": "^11.11.0", "@emotion/react": "^11.11.4", - "@enclave-e3/sdk": "workspace:*", + "@enclave-e3/sdk": "^0.1.5", "@noir-lang/acvm_js": "1.0.0-beta.3", "@noir-lang/noir_js": "1.0.0-beta.3", "@noir-lang/noirc_abi": "1.0.0-beta.3", diff --git a/examples/CRISP/scripts/dev_cipher.sh b/examples/CRISP/scripts/dev_cipher.sh index 948c601261..2df14bc3ff 100755 --- a/examples/CRISP/scripts/dev_cipher.sh +++ b/examples/CRISP/scripts/dev_cipher.sh @@ -23,7 +23,7 @@ enclave wallet set --name cn4 --private-key "$PRIVATE_KEY_CN4" enclave wallet set --name cn5 --private-key "$PRIVATE_KEY_CN5" # using & instead of -d so that wait works below -enclave nodes up -v --experimental-trbfv & +enclave nodes up -v & sleep 2 diff --git a/examples/CRISP/server/src/cli/commands.rs b/examples/CRISP/server/src/cli/commands.rs index f442d60e08..a1767899f6 100644 --- a/examples/CRISP/server/src/cli/commands.rs +++ b/examples/CRISP/server/src/cli/commands.rs @@ -16,7 +16,7 @@ use alloy::primitives::{Address, Bytes, U256}; use alloy::providers::{Provider, ProviderBuilder}; use crisp::config::CONFIG; use e3_sdk::bfv_helpers::{ - build_bfv_params_from_set_arc, encode_bfv_params, params::SET_8192_1000_4, + build_bfv_params_from_set_arc, encode_bfv_params, params::SET_2048_1032193_1, }; use e3_sdk::evm_helpers::contracts::{EnclaveContract, EnclaveRead, EnclaveWrite, E3}; use fhe::bfv::{BfvParameters, Ciphertext, Encoding, Plaintext, PublicKey, SecretKey}; @@ -329,7 +329,7 @@ pub async fn decrypt_and_publish_result( } fn generate_bfv_parameters() -> Arc<BfvParameters> { - build_bfv_params_from_set_arc(SET_8192_1000_4) + build_bfv_params_from_set_arc(SET_2048_1032193_1) } fn generate_keys(params: &Arc<BfvParameters>) -> (SecretKey, PublicKey) { diff --git a/examples/CRISP/server/src/server/routes/rounds.rs b/examples/CRISP/server/src/server/routes/rounds.rs index c541b21770..83a7746940 100644 --- a/examples/CRISP/server/src/server/routes/rounds.rs +++ b/examples/CRISP/server/src/server/routes/rounds.rs @@ -13,9 +13,8 @@ use crate::server::models::{ use actix_web::{web, HttpResponse, Responder}; use alloy::primitives::{Address, Bytes, U256}; use chrono::Utc; -use e3_sdk::bfv_helpers::params::SET_8192_1000_4; use e3_sdk::bfv_helpers::{ - build_bfv_params_from_set_arc, encode_bfv_params, params::SET_8192_1000_4, + build_bfv_params_from_set_arc, encode_bfv_params, params::SET_2048_1032193_1, }; use e3_sdk::evm_helpers::contracts::{EnclaveContract, EnclaveRead, EnclaveWrite}; use log::{error, info}; @@ -182,7 +181,7 @@ pub async fn initialize_crisp_round( } info!("Generating parameters..."); - let params = encode_bfv_params(&build_bfv_params_from_set_arc(SET_8192_1000_4)); + let params = encode_bfv_params(&build_bfv_params_from_set_arc(SET_2048_1032193_1)); let token_address: Address = token_address.parse()?; let balance_threshold = BigUint::parse_bytes(balance_threshold.as_bytes(), 10) diff --git a/packages/enclave-contracts/scripts/deployEnclave.ts b/packages/enclave-contracts/scripts/deployEnclave.ts index 5e4a2def74..e6779b5f83 100644 --- a/packages/enclave-contracts/scripts/deployEnclave.ts +++ b/packages/enclave-contracts/scripts/deployEnclave.ts @@ -30,14 +30,9 @@ export const deployEnclave = async (withMocks?: boolean) => { const ownerAddress = await owner.getAddress(); - const polynomial_degree = ethers.toBigInt(8192); - const plaintext_modulus = ethers.toBigInt(1000); - const moduli = [ - ethers.toBigInt("36028797055270913"), - ethers.toBigInt("36028797054222337"), - ethers.toBigInt("36028797053698049"), - ethers.toBigInt("36028797051863041"), - ]; + const polynomial_degree = ethers.toBigInt(2048); + const plaintext_modulus = ethers.toBigInt(1032193); + const moduli = [ethers.toBigInt("18014398492704769")]; const encoded = ethers.AbiCoder.defaultAbiCoder().encode( ["uint256", "uint256", "uint256[]"], diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5498c333a2..0bd915214b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -128,8 +128,8 @@ importers: specifier: ^11.11.4 version: 11.14.0(@types/react@18.3.26)(react@18.3.1) '@enclave-e3/sdk': - specifier: workspace:* - version: link:../../../packages/enclave-sdk + specifier: ^0.1.5 + version: 0.1.5(@openzeppelin/contracts@5.3.0)(@swc/helpers@0.5.17)(@types/node@22.7.5)(bufferutil@4.0.9)(rollup@4.52.5)(typescript@5.8.3)(utf-8-validate@5.0.10)(vite@5.4.21(@types/node@22.7.5))(zod@4.1.12) '@noir-lang/acvm_js': specifier: 1.0.0-beta.3 version: 1.0.0-beta.3 @@ -1562,6 +1562,15 @@ packages: '@emotion/weak-memoize@0.4.0': resolution: {integrity: sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==} + '@enclave-e3/contracts@0.1.5': + resolution: {integrity: sha512-C1Mo9z2JG6netDhpOsk0kZV8DBjVd4ftE5oqhpXDDbK+HHD4XHozjKMqmlUYTooSzzT3INGYNS/IEDUHxYOqTA==} + + '@enclave-e3/sdk@0.1.5': + resolution: {integrity: sha512-AZGIYrlJZ6FeK6DIQWqNKZDwvDpw+l1zCd7hc97giFX2LrNbSAzf/UJmNewAXFfaGtlnOePSVsuixk/ZQd1TVw==} + + '@enclave-e3/wasm@0.1.5': + resolution: {integrity: sha512-PZ/TpABK/PAAzO0d2+q17i3plzCs/E3chihc4yOi9DqCxdGFhm76hTueY/lDXusDnM+LUrEuaD11YR/2kBRvTg==} + '@esbuild/aix-ppc64@0.20.0': resolution: {integrity: sha512-fGFDEctNh0CcSwsiRPxiaqX0P5rq+AqE0SRhYGZ4PX46Lg1FNR6oCxJghf8YgY0WQEgQuh3lErUFE4KxLeRmmw==} engines: {node: '>=12'} @@ -11057,6 +11066,52 @@ snapshots: '@emotion/weak-memoize@0.4.0': {} + '@enclave-e3/contracts@0.1.5(@openzeppelin/contracts@5.3.0)': + dependencies: + '@openzeppelin/contracts-upgradeable': 5.4.0(@openzeppelin/contracts@5.3.0) + '@zk-kit/lean-imt.sol': 2.0.1 + poseidon-solidity: 0.0.5 + transitivePeerDependencies: + - '@openzeppelin/contracts' + + '@enclave-e3/sdk@0.1.5(@openzeppelin/contracts@5.3.0)(@swc/helpers@0.5.17)(@types/node@22.7.5)(bufferutil@4.0.9)(rollup@4.52.5)(typescript@5.8.3)(utf-8-validate@5.0.10)(vite@5.4.21(@types/node@22.7.5))(zod@4.1.12)': + dependencies: + '@aztec/bb.js': 0.82.3 + '@enclave-e3/contracts': 0.1.5(@openzeppelin/contracts@5.3.0) + '@enclave-e3/wasm': 0.1.5 + '@noir-lang/noir_js': 1.0.0-beta.3 + comlink: 4.4.2 + viem: 2.38.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12) + vite-plugin-top-level-await: 1.6.0(@swc/helpers@0.5.17)(rollup@4.52.5)(vite@5.4.21(@types/node@22.7.5)) + vite-plugin-wasm: 3.5.0(vite@5.4.21(@types/node@22.7.5)) + vitest: 1.6.1(@types/node@22.7.5) + web-worker: 1.5.0 + transitivePeerDependencies: + - '@edge-runtime/vm' + - '@openzeppelin/contracts' + - '@swc/helpers' + - '@types/node' + - '@vitest/browser' + - '@vitest/ui' + - bufferutil + - happy-dom + - jsdom + - less + - lightningcss + - rollup + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + - typescript + - utf-8-validate + - vite + - zod + + '@enclave-e3/wasm@0.1.5': {} + '@esbuild/aix-ppc64@0.20.0': optional: true From bfff1d926df963d2d8530159bad8664c0d3185ad Mon Sep 17 00:00:00 2001 From: Hamza Khalid <Hamzakhalid829@gmail.com> Date: Sat, 8 Nov 2025 00:49:04 +0500 Subject: [PATCH 45/61] fix: remove trbfv from integratin --- examples/CRISP/scripts/dev_cipher.sh | 1 + templates/default/scripts/dev_ciphernodes.sh | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/examples/CRISP/scripts/dev_cipher.sh b/examples/CRISP/scripts/dev_cipher.sh index 2df14bc3ff..d9971a1f75 100755 --- a/examples/CRISP/scripts/dev_cipher.sh +++ b/examples/CRISP/scripts/dev_cipher.sh @@ -23,6 +23,7 @@ enclave wallet set --name cn4 --private-key "$PRIVATE_KEY_CN4" enclave wallet set --name cn5 --private-key "$PRIVATE_KEY_CN5" # using & instead of -d so that wait works below +# TODO: add --experimental-trbfv after testing enclave nodes up -v & sleep 2 diff --git a/templates/default/scripts/dev_ciphernodes.sh b/templates/default/scripts/dev_ciphernodes.sh index a51214c5ef..6b0b709460 100755 --- a/templates/default/scripts/dev_ciphernodes.sh +++ b/templates/default/scripts/dev_ciphernodes.sh @@ -39,7 +39,8 @@ enclave wallet set --name cn4 --private-key "$PRIVATE_KEY_CN4" enclave wallet set --name cn5 --private-key "$PRIVATE_KEY_CN5" # using & instead of -d so that wait works below -enclave nodes up -v --experimental-trbfv & +# TODO: add --experimental-trbfv after testing +enclave nodes up -v & sleep 2 From fd731686a9c8db24bd0ece1683612fe779edd289 Mon Sep 17 00:00:00 2001 From: ryardley <contact@rudiyardley.com> Date: Fri, 7 Nov 2025 17:32:20 -0300 Subject: [PATCH 46/61] fix template default test --- templates/default/scripts/dev_ciphernodes.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/templates/default/scripts/dev_ciphernodes.sh b/templates/default/scripts/dev_ciphernodes.sh index 6b0b709460..b5db725889 100755 --- a/templates/default/scripts/dev_ciphernodes.sh +++ b/templates/default/scripts/dev_ciphernodes.sh @@ -47,6 +47,8 @@ sleep 2 CN1=$(grep -A 1 'cn1:' enclave.config.yaml | grep 'address:' | sed 's/.*address: *"\([^"]*\)".*/\1/') CN2=$(grep -A 1 'cn2:' enclave.config.yaml | grep 'address:' | sed 's/.*address: *"\([^"]*\)".*/\1/') CN3=$(grep -A 1 'cn3:' enclave.config.yaml | grep 'address:' | sed 's/.*address: *"\([^"]*\)".*/\1/') +CN4=$(grep -A 1 'cn4:' enclave.config.yaml | grep 'address:' | sed 's/.*address: *"\([^"]*\)".*/\1/') +CN5=$(grep -A 1 'cn5:' enclave.config.yaml | grep 'address:' | sed 's/.*address: *"\([^"]*\)".*/\1/') # Add ciphernodes using variables from config.sh pnpm run deploy && sleep 2 From d5cfc9c309a4317381b14432aeed2c5c895d35b1 Mon Sep 17 00:00:00 2001 From: ryardley <contact@rudiyardley.com> Date: Fri, 7 Nov 2025 18:06:02 -0300 Subject: [PATCH 47/61] test failures --- templates/default/program/src/lib.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/templates/default/program/src/lib.rs b/templates/default/program/src/lib.rs index 7ebf0c9bfd..58a2cdbd1c 100644 --- a/templates/default/program/src/lib.rs +++ b/templates/default/program/src/lib.rs @@ -26,9 +26,7 @@ pub fn fhe_processor(fhe_inputs: &FHEInputs) -> Vec<u8> { mod tests { use super::*; use anyhow::Result; - use e3_bfv_helpers::{ - build_bfv_params_from_set_arc, encode_bfv_params, params::SET_2048_1032193_1, - }; + use e3_bfv_helpers::{build_bfv_params_arc, encode_bfv_params, params::SET_2048_1032193_1}; use fhe::bfv::{Encoding, Plaintext, PublicKey, SecretKey}; use fhe_traits::FheEncoder; use fhe_traits::FheEncrypter; @@ -39,7 +37,8 @@ mod tests { fn test() -> Result<()> { let mut rng = thread_rng(); - let params = build_bfv_params_from_set_arc(SET_2048_1032193_1); + let (degree, plaintext, moduli) = SET_2048_1032193_1; + let params = build_bfv_params_arc(degree, plaintext, &moduli); let secret_key = SecretKey::random(&params, &mut OsRng); let public_key = PublicKey::new(&secret_key, &mut rng); From cc7920c9704b9242dfededf660eebd1414eba5fd Mon Sep 17 00:00:00 2001 From: ryardley <contact@rudiyardley.com> Date: Fri, 7 Nov 2025 18:09:51 -0300 Subject: [PATCH 48/61] Add debuging for publicKey --- templates/default/tests/integration.spec.ts | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/templates/default/tests/integration.spec.ts b/templates/default/tests/integration.spec.ts index 6d18d74be1..4222dd1b42 100644 --- a/templates/default/tests/integration.spec.ts +++ b/templates/default/tests/integration.spec.ts @@ -73,11 +73,11 @@ type E3State = async function setupEventListeners( sdk: EnclaveSDK, - store: Map<bigint, E3State> + store: Map<bigint, E3State>, ) { async function waitForEvent<T extends AllEventTypes>( type: T, - trigger?: () => Promise<void> + trigger?: () => Promise<void>, ): Promise<EnclaveEvent<T>> { return new Promise((resolve) => { sdk.once(type, resolve); @@ -191,7 +191,7 @@ describe("Integration", () => { const e3ProgramParams = encodeBfvParams(); const computeProviderParams = encodeComputeProviderParams( DEFAULT_COMPUTE_PROVIDER_PARAMS, - true // Mock the compute provider parameters, return 32 bytes of 0x00 + true, // Mock the compute provider parameters, return 32 bytes of 0x00 ); let state; @@ -245,6 +245,7 @@ describe("Integration", () => { const num1 = 12n; const num2 = 21n; const publicKeyBytes = hexToBytes(state.publicKey); + console.log(`publicKeyBytes: ${publicKeyBytes}`); const enc1 = await sdk.encryptNumber(num1, publicKeyBytes); const enc2 = await sdk.encryptNumber(num2, publicKeyBytes); @@ -252,21 +253,21 @@ describe("Integration", () => { await sdk.publishInput( e3Id, `0x${Array.from(enc1, (b) => b.toString(16).padStart(2, "0")).join( - "" - )}` as `0x${string}` + "", + )}` as `0x${string}`, ); }); await waitForEvent(EnclaveEventType.INPUT_PUBLISHED, async () => { await sdk.publishInput( e3Id, `0x${Array.from(enc2, (b) => b.toString(16).padStart(2, "0")).join( - "" - )}` as `0x${string}` + "", + )}` as `0x${string}`, ); }); const plaintextEvent = await waitForEvent( - EnclaveEventType.PLAINTEXT_OUTPUT_PUBLISHED + EnclaveEventType.PLAINTEXT_OUTPUT_PUBLISHED, ); const parsed = hexToUint8Array(plaintextEvent.data.plaintextOutput); From 0206bd8aeb0153e1db7e41be1dedd513e9c92e1f Mon Sep 17 00:00:00 2001 From: ryardley <contact@rudiyardley.com> Date: Fri, 7 Nov 2025 18:14:05 -0300 Subject: [PATCH 49/61] update threshold --- packages/enclave-sdk/src/utils.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/enclave-sdk/src/utils.ts b/packages/enclave-sdk/src/utils.ts index 78ec9c4f3e..cd0c7d25b6 100644 --- a/packages/enclave-sdk/src/utils.ts +++ b/packages/enclave-sdk/src/utils.ts @@ -102,8 +102,8 @@ export const DEFAULT_COMPUTE_PROVIDER_PARAMS: ComputeProviderParams = { // Default E3 configuration export const DEFAULT_E3_CONFIG = { - threshold_min: 1, - threshold_max: 2, + threshold_min: 2, + threshold_max: 5, window_size: 120, // 2 minutes in seconds duration: 1800, // 30 minutes in seconds payment_amount: "0", // 0 ETH in wei From 7ea15542fb120b08e3f921db17decd3f6edc9068 Mon Sep 17 00:00:00 2001 From: ryardley <contact@rudiyardley.com> Date: Fri, 7 Nov 2025 19:35:03 -0300 Subject: [PATCH 50/61] tidy up types --- Cargo.lock | 191 +++++++++++++++---------------- crates/bfv-helpers/Cargo.toml | 2 +- crates/bfv-helpers/src/client.rs | 16 +-- crates/wasm/src/lib.rs | 4 +- 4 files changed, 103 insertions(+), 110 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2f55d9f13f..01e371f408 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -90,7 +90,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e01ed3140b2f8d422c68afa1ed2e85d996ea619c988ac834d255db32138655cb" dependencies = [ "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -207,7 +207,7 @@ dependencies = [ "actix-router", "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -218,7 +218,7 @@ checksum = "b6ac1e58cded18cb28ddc17143c4dea5345b3ad575e14f32f66e4054a56eb271" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -731,7 +731,7 @@ checksum = "64b728d511962dda67c1bc7ea7c03736ec275ed2cf4c35d9585298ac9ccf3b73" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -929,7 +929,7 @@ dependencies = [ "proc-macro-error2", "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -946,7 +946,7 @@ dependencies = [ "proc-macro-error2", "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", "syn-solidity", "tiny-keccak", ] @@ -965,7 +965,7 @@ dependencies = [ "proc-macro2", "quote", "serde_json", - "syn 2.0.108", + "syn 2.0.109", "syn-solidity", ] @@ -1093,7 +1093,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -1292,7 +1292,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62945a2f7e6de02a31fe400aa489f0e0f5b2502e69f95f853adb82a96c7a6b60" dependencies = [ "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -1330,7 +1330,7 @@ dependencies = [ "num-traits", "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -1460,7 +1460,7 @@ checksum = "965c2d33e53cb6b267e148a4cb0760bc01f4904c1cd4bb4002a085bb016d1490" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", "synstructure", ] @@ -1472,7 +1472,7 @@ checksum = "7b18050c2cd6fe86c3a76584ef5e0baf286d038cda203eb6223df2cc413565f7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -1574,7 +1574,7 @@ checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -1623,7 +1623,7 @@ checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -1640,7 +1640,7 @@ checksum = "e539d3fca749fcee5236ab05e93a52867dd549cc157c8cb7f99595f3cedffdb5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -1701,7 +1701,7 @@ checksum = "ffdcb70bdbc4d478427380519163274ac86e52916e10f0a8889adf0f96d3fee7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -2000,9 +2000,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.44" +version = "1.2.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37521ac7aabe3d13122dc382493e20c9416f299d2ccd5b3a5340a2570cdeb0f3" +checksum = "35900b6c8d709fb1d854671ae27aeaa9eec2f8b01b364e1619a40da3e6fe2afe" dependencies = [ "find-msvc-tools", "jobserver", @@ -2078,7 +2078,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -2357,7 +2357,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -2382,7 +2382,7 @@ dependencies = [ "quote", "serde", "strsim", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -2393,7 +2393,7 @@ checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81" dependencies = [ "darling_core", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -2433,7 +2433,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d162beedaa69905488a8da94f5ac3edb4dd4788b732fadb7bd120b2625c1976" dependencies = [ "data-encoding", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -2498,7 +2498,7 @@ checksum = "bda628edc44c4bb645fbe0f758797143e4e07926f7ebf4e9bdfbd3d2ce621df3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", "unicode-xid", ] @@ -2595,7 +2595,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -3298,7 +3298,7 @@ dependencies = [ "enum-ordinalize", "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -3371,7 +3371,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -3391,7 +3391,7 @@ checksum = "8ca9601fb2d62598ee17836250842873a413586e5d7ed88b356e38ddbb0ec631" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -3494,7 +3494,7 @@ dependencies = [ [[package]] name = "fhe" version = "0.1.0-beta.7" -source = "git+https://github.com/gnosisguild/fhe.rs#c4f01896ac4c017e68ae986ba1237f27be353863" +source = "git+https://github.com/gnosisguild/fhe.rs#837be950a453ffce5bbf35823344f08a65edb0ce" dependencies = [ "doc-comment", "fhe-math", @@ -3519,7 +3519,7 @@ dependencies = [ [[package]] name = "fhe-math" version = "0.1.0-beta.7" -source = "git+https://github.com/gnosisguild/fhe.rs#c4f01896ac4c017e68ae986ba1237f27be353863" +source = "git+https://github.com/gnosisguild/fhe.rs#837be950a453ffce5bbf35823344f08a65edb0ce" dependencies = [ "ethnum", "fhe-traits", @@ -3541,7 +3541,7 @@ dependencies = [ [[package]] name = "fhe-traits" version = "0.1.0-beta.7" -source = "git+https://github.com/gnosisguild/fhe.rs#c4f01896ac4c017e68ae986ba1237f27be353863" +source = "git+https://github.com/gnosisguild/fhe.rs#837be950a453ffce5bbf35823344f08a65edb0ce" dependencies = [ "rand 0.8.5", ] @@ -3549,7 +3549,7 @@ dependencies = [ [[package]] name = "fhe-util" version = "0.1.0-beta.7" -source = "git+https://github.com/gnosisguild/fhe.rs#c4f01896ac4c017e68ae986ba1237f27be353863" +source = "git+https://github.com/gnosisguild/fhe.rs#837be950a453ffce5bbf35823344f08a65edb0ce" dependencies = [ "itertools 0.12.1", "num-bigint-dig", @@ -3759,7 +3759,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -4235,7 +4235,7 @@ dependencies = [ "tokio", "tokio-rustls", "tower-service", - "webpki-roots 1.0.3", + "webpki-roots 1.0.4", ] [[package]] @@ -4500,7 +4500,7 @@ checksum = "a0eb5a3343abf848c0984fe4604b2b105da9539376e24fc0a3b0007411ae4fd9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -4593,9 +4593,9 @@ dependencies = [ [[package]] name = "io-uring" -version = "0.7.10" +version = "0.7.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "046fa2d4d00aea763528b4950358d0ead425372445dc8ff86312b3c69ff7727b" +checksum = "fdd7bddefd0a8833b88a4b68f90dae22c7450d11b354198baee3874fd811b344" dependencies = [ "bitflags 2.10.0", "cfg-if", @@ -4622,9 +4622,9 @@ checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" [[package]] name = "iri-string" -version = "0.7.8" +version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbc5ebe9c3a1a7a5127f920a418f7585e9e758e911d0466ed004f393b0e380b2" +checksum = "4f867b9d1d896b67beb18518eda36fdb77a32ea590de864f1325b294a6d14397" dependencies = [ "memchr", "serde", @@ -5106,7 +5106,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -5304,7 +5304,7 @@ checksum = "1b27834086c65ec3f9387b096d66e99f221cf081c2b738042aa252bcd41204e3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -5592,11 +5592,10 @@ dependencies = [ [[package]] name = "num-bigint-dig" -version = "0.8.4" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc84195820f291c7697304f3cbdadd1cb7199c0efc917ff5eafd71225c136151" +checksum = "82c79c15c05d4bf82b6f5ef163104cc81a760d8e874d38ac50ab67c8877b647b" dependencies = [ - "byteorder", "lazy_static", "libm", "num-integer", @@ -5691,7 +5690,7 @@ checksum = "ff32365de1b6743cb203b710788263c44a03de03802daf96092f2da4fe6ba4d7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -5752,9 +5751,9 @@ checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" [[package]] name = "openssl" -version = "0.10.74" +version = "0.10.75" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24ad14dd45412269e1a30f52ad8f0664f0f4f4a89ee8fe28c3b3527021ebb654" +checksum = "08838db121398ad17ab8531ce9de97b244589089e290a384c900cb9ff7434328" dependencies = [ "bitflags 2.10.0", "cfg-if", @@ -5773,7 +5772,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -5784,9 +5783,9 @@ checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" [[package]] name = "openssl-sys" -version = "0.9.110" +version = "0.9.111" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a9f0075ba3c21b09f8e8b2026584b1d18d49388648f2fbbf3c97ea8deced8e2" +checksum = "82cab2d520aa75e3c58898289429321eb788c3106963d0dc886ec7a5f4adc321" dependencies = [ "cc", "libc", @@ -5931,7 +5930,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -6101,7 +6100,7 @@ dependencies = [ "phf_shared", "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -6130,7 +6129,7 @@ checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -6235,7 +6234,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" dependencies = [ "proc-macro2", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -6288,7 +6287,7 @@ dependencies = [ "proc-macro-error-attr2", "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -6320,7 +6319,7 @@ checksum = "440f724eba9f6996b75d63681b0a92b06947f1457076d503a4d2e2c8f56442b8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -6379,7 +6378,7 @@ dependencies = [ "prost 0.12.6", "prost-types", "regex", - "syn 2.0.108", + "syn 2.0.109", "tempfile", ] @@ -6393,7 +6392,7 @@ dependencies = [ "itertools 0.12.1", "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -6406,7 +6405,7 @@ dependencies = [ "itertools 0.14.0", "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -6504,9 +6503,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.41" +version = "1.0.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1" +checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f" dependencies = [ "proc-macro2", ] @@ -6705,7 +6704,7 @@ checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -6801,7 +6800,7 @@ dependencies = [ "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "webpki-roots 1.0.3", + "webpki-roots 1.0.4", ] [[package]] @@ -6971,9 +6970,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.34" +version = "0.23.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a9586e9ee2b4f8fab52a0048ca7334d7024eef48e2cb9407e3497bb7cab7fa7" +checksum = "533f54bc6a7d4f647e46ad909549eda97bf5afc1585190ef692b4286b198bd8f" dependencies = [ "once_cell", "ring 0.17.14", @@ -7081,9 +7080,9 @@ dependencies = [ [[package]] name = "schemars" -version = "1.0.4" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82d20c4491bc164fa2f6c5d44565947a52ad80b9505d8e36f8d54c27c739fcd0" +checksum = "9558e172d4e8533736ba97870c4b2cd63f84b382a3d6eb063da41b91cce17289" dependencies = [ "dyn-clone", "ref-cast", @@ -7219,7 +7218,7 @@ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -7267,7 +7266,7 @@ dependencies = [ "indexmap 1.9.3", "indexmap 2.12.0", "schemars 0.9.0", - "schemars 1.0.4", + "schemars 1.1.0", "serde", "serde_derive", "serde_json", @@ -7284,7 +7283,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -7332,7 +7331,7 @@ checksum = "5d69265a08751de7844521fd15003ae0a888e035773ba05695c5c759a6f89eef" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -7585,7 +7584,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -7607,9 +7606,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.108" +version = "2.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da58917d35242480a05c2897064da0a80589a2a0476c9a3f2fdc83b53502e917" +checksum = "2f17c7e013e88258aa9543dcbe81aca68a667a9ac37cd69c9fbc07858bfe0e2f" dependencies = [ "proc-macro2", "quote", @@ -7625,7 +7624,7 @@ dependencies = [ "paste", "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -7645,7 +7644,7 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -7725,7 +7724,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -7736,7 +7735,7 @@ checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -7850,7 +7849,7 @@ checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -7903,9 +7902,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.16" +version = "0.7.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14307c986784f72ef81c89db7d9e28d6ac26d16213b109ea501696195e6e3ce5" +checksum = "2efa149fe76073d6e8fd97ef4f4eca7b67f599660115591483572e406e165594" dependencies = [ "bytes", "futures-core", @@ -8096,7 +8095,7 @@ checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -8175,7 +8174,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04659ddb06c87d233c566112c1c9c5b9e98256d9af50ec3bc9c8327f873a7568" dependencies = [ "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -8456,7 +8455,7 @@ dependencies = [ "bumpalo", "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", "wasm-bindgen-shared", ] @@ -8509,14 +8508,14 @@ version = "0.26.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9" dependencies = [ - "webpki-roots 1.0.3", + "webpki-roots 1.0.4", ] [[package]] name = "webpki-roots" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32b130c0d2d49f8b6889abc456e795e82525204f27c42cf767cf0d7734e089b8" +checksum = "b2878ef029c47c6e8cf779119f20fcf52bde7ad42a731b2a304bc221df17571e" dependencies = [ "rustls-pki-types", ] @@ -8590,7 +8589,7 @@ checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -8601,7 +8600,7 @@ checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -9032,7 +9031,7 @@ checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", "synstructure", ] @@ -9053,7 +9052,7 @@ checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -9073,7 +9072,7 @@ checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", "synstructure", ] @@ -9094,7 +9093,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -9127,13 +9126,13 @@ checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] name = "zkfhe-greco" version = "0.1.0" -source = "git+https://github.com/gnosisguild/zkfhe-generator#82f27e955599ff88f552e43594bc52859fb51681" +source = "git+https://github.com/gnosisguild/zkfhe-generator#1bb8019b8d9944ebf2fd293ec15d6cabc4e37da0" dependencies = [ "anyhow", "bigint-poly", @@ -9156,7 +9155,7 @@ dependencies = [ [[package]] name = "zkfhe-shared" version = "0.1.0" -source = "git+https://github.com/gnosisguild/zkfhe-generator#82f27e955599ff88f552e43594bc52859fb51681" +source = "git+https://github.com/gnosisguild/zkfhe-generator#1bb8019b8d9944ebf2fd293ec15d6cabc4e37da0" dependencies = [ "anyhow", "bigint-poly", diff --git a/crates/bfv-helpers/Cargo.toml b/crates/bfv-helpers/Cargo.toml index d34e2dfc0e..fdade751c7 100644 --- a/crates/bfv-helpers/Cargo.toml +++ b/crates/bfv-helpers/Cargo.toml @@ -14,7 +14,7 @@ fhe.workspace = true rand.workspace = true anyhow.workspace = true fhe-util = { git = "https://github.com/gnosisguild/fhe.rs" } -greco = { package = "zkfhe-greco", git = "https://github.com/gnosisguild/zkfhe-generator", version = "0.1.0"} +greco = { package = "zkfhe-greco", git = "https://github.com/gnosisguild/zkfhe-generator" } num-bigint = { workspace = true } [dev-dependencies] diff --git a/crates/bfv-helpers/src/client.rs b/crates/bfv-helpers/src/client.rs index 17ea343d24..1aede0675b 100644 --- a/crates/bfv-helpers/src/client.rs +++ b/crates/bfv-helpers/src/client.rs @@ -35,12 +35,12 @@ pub fn bfv_encrypt<T>( public_key: Vec<u8>, degree: usize, plaintext_modulus: u64, - moduli: Vec<u64>, + moduli: &[u64], ) -> Result<Vec<u8>> where Plaintext: for<'a> FheEncoder<&'a T, Error = FheError>, { - let params = build_bfv_params_arc(degree, plaintext_modulus, &moduli, None); + let params = build_bfv_params_arc(degree, plaintext_modulus, moduli, None); let pk = PublicKey::from_bytes(&public_key, &params) .map_err(|e| anyhow!("Error deserializing public key:{e}"))?; @@ -145,14 +145,8 @@ mod tests { let pk = PublicKey::new(&sk, &mut rng); let num = [1u64]; - let encrypted_data = bfv_encrypt( - num, - pk.to_bytes(), - degree, - plaintext_modulus, - moduli.to_vec(), - ) - .unwrap(); + let encrypted_data = + bfv_encrypt(num, pk.to_bytes(), degree, plaintext_modulus, &moduli).unwrap(); let ct = Ciphertext::from_bytes(&encrypted_data, &params).unwrap(); let pt = sk.try_decrypt(&ct).unwrap(); @@ -181,7 +175,7 @@ mod tests { pk.to_bytes(), degree, plaintext_modulus, - moduli.to_vec(), + &moduli, ) .unwrap(); diff --git a/crates/wasm/src/lib.rs b/crates/wasm/src/lib.rs index 8916a2956a..9111aca25a 100644 --- a/crates/wasm/src/lib.rs +++ b/crates/wasm/src/lib.rs @@ -32,7 +32,7 @@ pub fn bfv_encrypt_number( plaintext_modulus: u64, moduli: Vec<u64>, ) -> Result<Vec<u8>, JsValue> { - let encrypted_data = bfv_encrypt([data], public_key, degree, plaintext_modulus, moduli) + let encrypted_data = bfv_encrypt([data], public_key, degree, plaintext_modulus, &moduli) .map_err(|e| JsValue::from_str(&format!("{}", e)))?; Ok(encrypted_data) } @@ -62,7 +62,7 @@ pub fn bfv_encrypt_vector( plaintext_modulus: u64, moduli: Vec<u64>, ) -> Result<Vec<u8>, JsValue> { - let encrypted_data = bfv_encrypt(data, public_key, degree, plaintext_modulus, moduli) + let encrypted_data = bfv_encrypt(data, public_key, degree, plaintext_modulus, &moduli) .map_err(|e| JsValue::from_str(&format!("{}", e)))?; Ok(encrypted_data) } From 1ca334f1c87029c4c95c74a2397a68fb2e1feadd Mon Sep 17 00:00:00 2001 From: ryardley <contact@rudiyardley.com> Date: Fri, 7 Nov 2025 21:09:31 -0300 Subject: [PATCH 51/61] tidy up encoding and decoding --- Cargo.lock | 1 + crates/bfv-helpers/Cargo.toml | 1 + crates/bfv-helpers/src/lib.rs | 39 ++++++++++++++++++- crates/fhe/src/fhe.rs | 10 +++-- crates/test-helpers/src/plaintext_writer.rs | 4 +- crates/tests/tests/integration.rs | 8 ++-- crates/tests/tests/integration_legacy.rs | 10 +++-- .../src/calculate_threshold_decryption.rs | 7 ++-- crates/trbfv/tests/integration.rs | 10 ++--- examples/CRISP/Cargo.lock | 1 + examples/CRISP/server/src/server/indexer.rs | 3 +- 11 files changed, 70 insertions(+), 24 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4a07a2ba4d..f5b507e713 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2676,6 +2676,7 @@ dependencies = [ "hex", "num-bigint", "rand 0.8.5", + "thiserror 1.0.69", "zkfhe-greco", ] diff --git a/crates/bfv-helpers/Cargo.toml b/crates/bfv-helpers/Cargo.toml index ff71742135..ca0e40a0df 100644 --- a/crates/bfv-helpers/Cargo.toml +++ b/crates/bfv-helpers/Cargo.toml @@ -17,6 +17,7 @@ fhe-util = { git = "https://github.com/gnosisguild/fhe.rs" } fhe-math = { git = "https://github.com/gnosisguild/fhe.rs" } greco = { package = "zkfhe-greco", git = "https://github.com/gnosisguild/zkfhe-generator" } num-bigint = { workspace = true } +thiserror = { workspace = true } [dev-dependencies] hex.workspace = true diff --git a/crates/bfv-helpers/src/lib.rs b/crates/bfv-helpers/src/lib.rs index ff85e72f8a..413bb93a20 100644 --- a/crates/bfv-helpers/src/lib.rs +++ b/crates/bfv-helpers/src/lib.rs @@ -9,8 +9,20 @@ mod util; use alloy_dyn_abi::{DynSolType, DynSolValue}; use alloy_primitives::U256; -use fhe::bfv::{BfvParameters, BfvParametersBuilder}; +use fhe::bfv::{BfvParameters, BfvParametersBuilder, Encoding, Plaintext}; +use fhe_traits::FheDecoder; use std::sync::Arc; +use thiserror::Error as ThisError; + +#[derive(ThisError, Debug)] +pub enum Error { + #[error("Plaintext decoding failed")] + PlaintextDecodeFailed, + // TODO: add errors from client.rs +} + +/// Result that returns a type T or a BfvHelpersError +type Result<T> = std::result::Result<T, Error>; /// Predefined BFV parameters for common use cases pub mod params { @@ -337,6 +349,31 @@ pub fn decode_bfv_params_arc(bytes: &[u8]) -> Arc<BfvParameters> { Arc::new(decode_bfv_params(bytes)) } +/// Decode Plaintext to a Vec<u64> +pub fn decode_plaintext_to_vec_u64(value: &Plaintext) -> Result<Vec<u64>> { + let decoded = Vec::<u64>::try_decode(&value, Encoding::poly()) + .map_err(|_| Error::PlaintextDecodeFailed)?; + + Ok(decoded) +} + +/// Convert from a Vec<u64> to Vec<u8> +pub fn encode_vec_u64_to_bytes(value: &[u64]) -> Vec<u8> { + let mut bytes = Vec::new(); + for num in &value.to_vec() { + bytes.extend_from_slice(&num.to_le_bytes()); + } + bytes +} + +/// Decode bytes to Vec<u64> +pub fn decode_bytes_to_vec_u64(bytes: &[u8]) -> Vec<u64> { + bytes + .chunks_exact(8) + .map(|chunk| u64::from_le_bytes(chunk.try_into().unwrap())) + .collect() +} + #[cfg(test)] mod tests { use super::*; diff --git a/crates/fhe/src/fhe.rs b/crates/fhe/src/fhe.rs index d70f685084..8e6171d8a1 100644 --- a/crates/fhe/src/fhe.rs +++ b/crates/fhe/src/fhe.rs @@ -7,7 +7,10 @@ use super::create_crp; use anyhow::*; use async_trait::async_trait; -use e3_bfv_helpers::{build_bfv_params_arc, decode_bfv_params_arc}; +use e3_bfv_helpers::{ + build_bfv_params_arc, decode_bfv_params_arc, decode_plaintext_to_vec_u64, + encode_vec_u64_to_bytes, +}; use e3_data::{FromSnapshotWithParams, Snapshot}; use e3_events::{OrderedSet, Seed}; use e3_utils::{ArcBytes, SharedRng}; @@ -121,8 +124,9 @@ impl Fhe { .iter() .map(|k| DecryptionShare::deserialize(k, &self.params, arc_ct.clone())) .aggregate()?; - let decoded = Vec::<u64>::try_decode(&plaintext, Encoding::poly())?; - let bytes = bincode::serialize(&decoded)?; + let decoded = + decode_plaintext_to_vec_u64(&plaintext).context("Could not decode plaintext")?; + let bytes = encode_vec_u64_to_bytes(&decoded); Ok(bytes) } } diff --git a/crates/test-helpers/src/plaintext_writer.rs b/crates/test-helpers/src/plaintext_writer.rs index 5c157a2875..4934ddf536 100644 --- a/crates/test-helpers/src/plaintext_writer.rs +++ b/crates/test-helpers/src/plaintext_writer.rs @@ -9,6 +9,7 @@ use std::path::PathBuf; use super::write_file_with_dirs; use actix::{Actor, Addr, Context, Handler}; use e3_events::{EnclaveEvent, EventBus, Subscribe}; +use e3_sdk::bfv_helpers::decode_bytes_to_vec_u64; use tracing::{error, info}; pub struct PlaintextWriter { @@ -41,7 +42,8 @@ impl Handler<EnclaveEvent> for PlaintextWriter { error!("Decrypted output must not be empty!"); return; }; - let output: Vec<u64> = bincode::deserialize(decrypted).unwrap(); + + let output = decode_bytes_to_vec_u64(&decrypted); info!(path = ?&self.path, "Writing Plaintext To Path"); let contents: Vec<String> = output.iter().map(|&num| num.to_string()).collect(); diff --git a/crates/tests/tests/integration.rs b/crates/tests/tests/integration.rs index 13b71844c3..c8fa24e468 100644 --- a/crates/tests/tests/integration.rs +++ b/crates/tests/tests/integration.rs @@ -15,7 +15,7 @@ use e3_events::{ TicketBalanceUpdated, }; use e3_multithread::Multithread; -use e3_sdk::bfv_helpers::{build_bfv_params_arc, encode_bfv_params}; +use e3_sdk::bfv_helpers::{build_bfv_params_arc, decode_bytes_to_vec_u64, encode_bfv_params}; use e3_test_helpers::ciphernode_system::CiphernodeSystemBuilder; use e3_test_helpers::{create_seed_from_u64, create_shared_rng_from_u64, AddToCommittee}; use e3_trbfv::helpers::calculate_error_size; @@ -340,10 +340,8 @@ async fn test_trbfv_actor() -> Result<()> { let results = plaintext .into_iter() - .map(|a| { - bincode::deserialize(&a.extract_bytes()).context("Could not deserialize plaintext") - }) - .collect::<Result<Vec<Vec<u64>>>>()?; + .map(|a| decode_bytes_to_vec_u64(&a.extract_bytes())) + .collect::<Vec<Vec<u64>>>(); let results: Vec<u64> = results .into_iter() diff --git a/crates/tests/tests/integration_legacy.rs b/crates/tests/tests/integration_legacy.rs index 46ca464e9e..9faa7e945f 100644 --- a/crates/tests/tests/integration_legacy.rs +++ b/crates/tests/tests/integration_legacy.rs @@ -22,6 +22,8 @@ use e3_events::{ }; use e3_net::events::GossipData; use e3_net::{events::NetEvent, NetEventTranslator}; +use e3_sdk::bfv_helpers::decode_bytes_to_vec_u64; +use e3_sdk::bfv_helpers::decode_plaintext_to_vec_u64; use e3_sdk::bfv_helpers::encode_bfv_params; use e3_test_helpers::encrypt_ciphertext; use e3_test_helpers::{ @@ -280,11 +282,11 @@ async fn test_public_key_aggregation_and_decryption() -> Result<()> { actual .decrypted_output .iter() - .map(|b| bincode::deserialize::<Vec<u64>>(b).unwrap()) + .map(|b| decode_bytes_to_vec_u64(b)) .collect::<Vec<Vec<u64>>>(), expected .iter() - .map(|p| Vec::<u64>::try_decode(&p, Encoding::poly()).unwrap()) + .map(|p| decode_plaintext_to_vec_u64(p).unwrap()) .collect::<Vec<Vec<u64>>>() ); @@ -435,11 +437,11 @@ async fn test_stopped_keyshares_retain_state() -> Result<()> { actual .decrypted_output .iter() - .map(|b| bincode::deserialize::<Vec<u64>>(b).unwrap()) + .map(|b| decode_bytes_to_vec_u64(b)) .collect::<Vec<Vec<u64>>>(), expected .iter() - .map(|p| Vec::<u64>::try_decode(&p, Encoding::poly()).unwrap()) + .map(|p| decode_plaintext_to_vec_u64(p).unwrap()) .collect::<Vec<Vec<u64>>>() ); diff --git a/crates/trbfv/src/calculate_threshold_decryption.rs b/crates/trbfv/src/calculate_threshold_decryption.rs index bff213a299..31ed8355ad 100644 --- a/crates/trbfv/src/calculate_threshold_decryption.rs +++ b/crates/trbfv/src/calculate_threshold_decryption.rs @@ -9,6 +9,7 @@ use std::sync::Arc; /// This module defines event payloads that will dcrypt a ciphertext with a threshold quorum of decryption shares use crate::{helpers::try_poly_from_bytes, PartyId, TrBFVConfig}; use anyhow::*; +use e3_bfv_helpers::{decode_plaintext_to_vec_u64, encode_vec_u64_to_bytes}; use e3_utils::utility_types::ArcBytes; use fhe::bfv::{Encoding, Plaintext}; use fhe::{bfv::Ciphertext, trbfv::ShareManager}; @@ -114,10 +115,8 @@ impl TryFrom<InnerResponse> for CalculateThresholdDecryptionResponse { .plaintext .into_iter() .map(|open_result| -> Result<_> { - let vec_64 = Vec::<u64>::try_decode(&open_result, Encoding::poly()) - .context("could not decode plaintext")?; - info!("FINISHED AGGREGATING: {:?}", vec_64); - let bytes = bincode::serialize(&vec_64)?; + let decoded = decode_plaintext_to_vec_u64(&open_result)?; + let bytes = encode_vec_u64_to_bytes(&decoded); Ok(ArcBytes::from_bytes(&bytes)) }) .collect::<Result<_>>()?, diff --git a/crates/trbfv/tests/integration.rs b/crates/trbfv/tests/integration.rs index 10c51386a3..4db4eb3dfa 100644 --- a/crates/trbfv/tests/integration.rs +++ b/crates/trbfv/tests/integration.rs @@ -9,7 +9,9 @@ use std::{ }; use anyhow::{Context, Result}; -use e3_bfv_helpers::{build_bfv_params_arc, encode_bfv_params}; +use e3_bfv_helpers::{ + build_bfv_params_arc, decode_bytes_to_vec_u64, decode_plaintext_to_vec_u64, encode_bfv_params, +}; use e3_crypto::Cipher; use e3_fhe::create_crp; use e3_test_helpers::{create_seed_from_u64, create_shared_rng_from_u64, usecase_helpers}; @@ -142,10 +144,8 @@ async fn test_trbfv_isolation() -> Result<()> { let results = plaintext .into_iter() - .map(|a| { - bincode::deserialize(&a.extract_bytes()).context("Could not deserialize plaintext") - }) - .collect::<Result<Vec<Vec<u64>>>>()?; + .map(|a| decode_bytes_to_vec_u64(&a.extract_bytes())) + .collect::<Vec<Vec<u64>>>(); let results: Vec<u64> = results .into_iter() diff --git a/examples/CRISP/Cargo.lock b/examples/CRISP/Cargo.lock index 7abae24b74..63b33914ad 100644 --- a/examples/CRISP/Cargo.lock +++ b/examples/CRISP/Cargo.lock @@ -2257,6 +2257,7 @@ dependencies = [ "fhe-util", "num-bigint", "rand 0.8.5", + "thiserror 1.0.69", "zkfhe-greco", ] diff --git a/examples/CRISP/server/src/server/indexer.rs b/examples/CRISP/server/src/server/indexer.rs index d6a4b53479..fd0cbe41b1 100644 --- a/examples/CRISP/server/src/server/indexer.rs +++ b/examples/CRISP/server/src/server/indexer.rs @@ -16,6 +16,7 @@ use alloy::providers::{Provider, ProviderBuilder}; use alloy::sol_types::{sol_data, SolType}; use alloy_primitives::{Address, U256}; use e3_sdk::{ + bfv_helpers::decode_bytes_to_vec_u64, evm_helpers::{ contracts::{ EnclaveContract, EnclaveContractFactory, EnclaveRead, EnclaveWrite, ReadWrite, @@ -263,7 +264,7 @@ pub async fn register_plaintext_output_published( // The computation sums the encrypted votes: '0' for Option 1, '1' for Option 2. // Thus, the decrypted sum directly represents the number of votes for Option 2. // The output is expected to be a Vec<u8> in little endian format of u64s. - let decoded: Vec<u64> = bincode::deserialize(&event.plaintextOutput)?; + let decoded = decode_bytes_to_vec_u64(&event.plaintextOutput); println!("RECEIVED: {:?}", decoded); // decoded[0] is the sum of all encrypted votes (0s and 1s). // Since Option 1 votes are encrypted as '0' and Option 2 votes as '1', From ce220a2f2b2c58429376d11e50f6209fa7705409 Mon Sep 17 00:00:00 2001 From: ryardley <contact@rudiyardley.com> Date: Fri, 7 Nov 2025 21:16:52 -0300 Subject: [PATCH 52/61] remove debugging --- templates/default/tests/integration.spec.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/templates/default/tests/integration.spec.ts b/templates/default/tests/integration.spec.ts index 4222dd1b42..5524302378 100644 --- a/templates/default/tests/integration.spec.ts +++ b/templates/default/tests/integration.spec.ts @@ -245,7 +245,6 @@ describe("Integration", () => { const num1 = 12n; const num2 = 21n; const publicKeyBytes = hexToBytes(state.publicKey); - console.log(`publicKeyBytes: ${publicKeyBytes}`); const enc1 = await sdk.encryptNumber(num1, publicKeyBytes); const enc2 = await sdk.encryptNumber(num2, publicKeyBytes); From 505dd2ef62605d34639f211e6f1bff4cb54e208f Mon Sep 17 00:00:00 2001 From: ryardley <contact@rudiyardley.com> Date: Fri, 7 Nov 2025 21:49:04 -0300 Subject: [PATCH 53/61] found it --- packages/enclave-sdk/src/utils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/enclave-sdk/src/utils.ts b/packages/enclave-sdk/src/utils.ts index cd0c7d25b6..ead9dce144 100644 --- a/packages/enclave-sdk/src/utils.ts +++ b/packages/enclave-sdk/src/utils.ts @@ -84,7 +84,7 @@ export const SET_8192_1000_4 = { }; // Set default parameter set -export const BFV_PARAMS_SET = SET_8192_1000_4; +export const BFV_PARAMS_SET = SET_2048_1032193_1; // Compute provider parameters structure export interface ComputeProviderParams { From 1b787cd91220af0de360d3236ff00dff7bed9534 Mon Sep 17 00:00:00 2001 From: ryardley <contact@rudiyardley.com> Date: Fri, 7 Nov 2025 22:14:06 -0300 Subject: [PATCH 54/61] try adding a wait --- examples/CRISP/test/crisp.spec.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/CRISP/test/crisp.spec.ts b/examples/CRISP/test/crisp.spec.ts index a066a3dce0..fe21c67e3c 100644 --- a/examples/CRISP/test/crisp.spec.ts +++ b/examples/CRISP/test/crisp.spec.ts @@ -132,6 +132,7 @@ test("CRISP smoke test", async ({ log(`asserting that Historic polls exists...`); await expect(page.locator("h1")).toHaveText("Historic polls"); log(`asserting that result has 100% on the vote we clicked on...`); + await page.waitForSelector("[data-test-id^='poll-']", { timeout: 15000 }); await expect( page.locator("[data-test-id='poll-0-0'] [data-test-id='poll-result-0'] h3"), ).toHaveText("100%"); From 8f3c8d6301af4f2f87320f83194030d78de86104 Mon Sep 17 00:00:00 2001 From: ryardley <contact@rudiyardley.com> Date: Fri, 7 Nov 2025 22:18:50 -0300 Subject: [PATCH 55/61] try waiting more --- examples/CRISP/test/crisp.spec.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/CRISP/test/crisp.spec.ts b/examples/CRISP/test/crisp.spec.ts index fe21c67e3c..7848adb66a 100644 --- a/examples/CRISP/test/crisp.spec.ts +++ b/examples/CRISP/test/crisp.spec.ts @@ -125,14 +125,14 @@ test("CRISP smoke test", async ({ .click(); log(`clicking Cast Vote...`); await page.locator('button:has-text("Cast Vote")').click(); - log(`waiting for 220_000...`); - await page.waitForTimeout(220_000); + const WAIT = 300_000; + log(`waiting for ${WAIT}ms...`); + await page.waitForTimeout(WAIT); log(`clicking historic polls button...`); await page.locator('a:has-text("Historic polls")').click(); log(`asserting that Historic polls exists...`); await expect(page.locator("h1")).toHaveText("Historic polls"); log(`asserting that result has 100% on the vote we clicked on...`); - await page.waitForSelector("[data-test-id^='poll-']", { timeout: 15000 }); await expect( page.locator("[data-test-id='poll-0-0'] [data-test-id='poll-result-0'] h3"), ).toHaveText("100%"); From 391470137d72389acc2fbfa2bed34102218338fc Mon Sep 17 00:00:00 2001 From: ryardley <contact@rudiyardley.com> Date: Fri, 7 Nov 2025 22:26:00 -0300 Subject: [PATCH 56/61] remove logging --- packages/enclave-sdk/src/enclave-sdk.ts | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/packages/enclave-sdk/src/enclave-sdk.ts b/packages/enclave-sdk/src/enclave-sdk.ts index 7ce9fdd283..98f36bebf5 100644 --- a/packages/enclave-sdk/src/enclave-sdk.ts +++ b/packages/enclave-sdk/src/enclave-sdk.ts @@ -186,8 +186,6 @@ export class EnclaveSDK { data: bigint, publicKey: Uint8Array, ): Promise<EncryptedValueAndPublicInputs> { - console.log("encrypting number:" + data); - console.log("encrypting with public key:" + publicKey); await initializeWasm(); switch (this.protocol) { case FheProtocol.BFV: @@ -589,9 +587,9 @@ export class EnclaveSDK { options.rpcUrl.startsWith("ws://") || options.rpcUrl.startsWith("wss://"); const transport = isWebSocket ? webSocket(options.rpcUrl, { - keepAlive: { interval: 30_000 }, - reconnect: { attempts: 5, delay: 2_000 }, - }) + keepAlive: { interval: 30_000 }, + reconnect: { attempts: 5, delay: 2_000 }, + }) : http(options.rpcUrl); const publicClient = createPublicClient({ chain, From 9b4ffb010eb1e9c432c37743311dd8c539f65f26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=B3=CE=BB?= <contact@rudiyardley.com> Date: Sat, 8 Nov 2025 01:32:37 +0000 Subject: [PATCH 57/61] Update examples/CRISP/server/src/server/routes/voting.rs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- examples/CRISP/server/src/server/routes/voting.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/CRISP/server/src/server/routes/voting.rs b/examples/CRISP/server/src/server/routes/voting.rs index 5121f9fb3a..59b448b7d2 100644 --- a/examples/CRISP/server/src/server/routes/voting.rs +++ b/examples/CRISP/server/src/server/routes/voting.rs @@ -40,7 +40,7 @@ async fn broadcast_encrypted_vote( store: web::Data<AppData>, ) -> impl Responder { let vote = data.into_inner(); - error!("[e3_id={}] Broadcasting encrypted vote", vote.round_id); + info!("[e3_id={}] Broadcasting encrypted vote", vote.round_id); // Validate and update vote status let has_voted = match store .e3(vote.round_id) From 9ce4387d40db43d0f7ceef81cdb933164e11257f Mon Sep 17 00:00:00 2001 From: ryardley <contact@rudiyardley.com> Date: Fri, 7 Nov 2025 22:39:14 -0300 Subject: [PATCH 58/61] remove import --- crates/trbfv/tests/integration.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/crates/trbfv/tests/integration.rs b/crates/trbfv/tests/integration.rs index 4db4eb3dfa..324d89fc5c 100644 --- a/crates/trbfv/tests/integration.rs +++ b/crates/trbfv/tests/integration.rs @@ -8,10 +8,8 @@ use std::{ sync::{Arc, Mutex}, }; -use anyhow::{Context, Result}; -use e3_bfv_helpers::{ - build_bfv_params_arc, decode_bytes_to_vec_u64, decode_plaintext_to_vec_u64, encode_bfv_params, -}; +use anyhow::Result; +use e3_bfv_helpers::{build_bfv_params_arc, decode_bytes_to_vec_u64, encode_bfv_params}; use e3_crypto::Cipher; use e3_fhe::create_crp; use e3_test_helpers::{create_seed_from_u64, create_shared_rng_from_u64, usecase_helpers}; From aebbd07856ea5d75222d6a496bad2182124b874e Mon Sep 17 00:00:00 2001 From: ryardley <contact@rudiyardley.com> Date: Fri, 7 Nov 2025 22:47:59 -0300 Subject: [PATCH 59/61] ensure input is formed correctly --- crates/bfv-helpers/src/lib.rs | 12 +++++++++--- crates/test-helpers/src/plaintext_writer.rs | 2 +- crates/tests/tests/integration.rs | 4 ++-- crates/tests/tests/integration_legacy.rs | 4 ++-- crates/trbfv/tests/integration.rs | 2 +- 5 files changed, 15 insertions(+), 9 deletions(-) diff --git a/crates/bfv-helpers/src/lib.rs b/crates/bfv-helpers/src/lib.rs index 413bb93a20..2727135442 100644 --- a/crates/bfv-helpers/src/lib.rs +++ b/crates/bfv-helpers/src/lib.rs @@ -19,6 +19,8 @@ pub enum Error { #[error("Plaintext decoding failed")] PlaintextDecodeFailed, // TODO: add errors from client.rs + #[error("Input was not encoded correctly")] + BadEncoding, } /// Result that returns a type T or a BfvHelpersError @@ -367,11 +369,15 @@ pub fn encode_vec_u64_to_bytes(value: &[u64]) -> Vec<u8> { } /// Decode bytes to Vec<u64> -pub fn decode_bytes_to_vec_u64(bytes: &[u8]) -> Vec<u64> { - bytes +pub fn decode_bytes_to_vec_u64(bytes: &[u8]) -> Result<Vec<u64>> { + if bytes.len() % 8 != 0 { + return Err(Error::BadEncoding); + } + + Ok(bytes .chunks_exact(8) .map(|chunk| u64::from_le_bytes(chunk.try_into().unwrap())) - .collect() + .collect()) } #[cfg(test)] diff --git a/crates/test-helpers/src/plaintext_writer.rs b/crates/test-helpers/src/plaintext_writer.rs index 4934ddf536..b2a5911bbb 100644 --- a/crates/test-helpers/src/plaintext_writer.rs +++ b/crates/test-helpers/src/plaintext_writer.rs @@ -43,7 +43,7 @@ impl Handler<EnclaveEvent> for PlaintextWriter { return; }; - let output = decode_bytes_to_vec_u64(&decrypted); + let output = decode_bytes_to_vec_u64(&decrypted).unwrap(); info!(path = ?&self.path, "Writing Plaintext To Path"); let contents: Vec<String> = output.iter().map(|&num| num.to_string()).collect(); diff --git a/crates/tests/tests/integration.rs b/crates/tests/tests/integration.rs index c8fa24e468..2035e5abd7 100644 --- a/crates/tests/tests/integration.rs +++ b/crates/tests/tests/integration.rs @@ -6,7 +6,7 @@ use actix::Actor; use alloy::primitives::{FixedBytes, I256, U256}; -use anyhow::{bail, Context, Result}; +use anyhow::{bail, Result}; use e3_ciphernode_builder::CiphernodeBuilder; use e3_crypto::Cipher; use e3_events::{ @@ -340,7 +340,7 @@ async fn test_trbfv_actor() -> Result<()> { let results = plaintext .into_iter() - .map(|a| decode_bytes_to_vec_u64(&a.extract_bytes())) + .map(|a| decode_bytes_to_vec_u64(&a.extract_bytes()).expect("error decoding bytes")) .collect::<Vec<Vec<u64>>>(); let results: Vec<u64> = results diff --git a/crates/tests/tests/integration_legacy.rs b/crates/tests/tests/integration_legacy.rs index 9faa7e945f..e07dcb2de2 100644 --- a/crates/tests/tests/integration_legacy.rs +++ b/crates/tests/tests/integration_legacy.rs @@ -282,7 +282,7 @@ async fn test_public_key_aggregation_and_decryption() -> Result<()> { actual .decrypted_output .iter() - .map(|b| decode_bytes_to_vec_u64(b)) + .map(|b| decode_bytes_to_vec_u64(b).unwrap()) .collect::<Vec<Vec<u64>>>(), expected .iter() @@ -437,7 +437,7 @@ async fn test_stopped_keyshares_retain_state() -> Result<()> { actual .decrypted_output .iter() - .map(|b| decode_bytes_to_vec_u64(b)) + .map(|b| decode_bytes_to_vec_u64(b).unwrap()) .collect::<Vec<Vec<u64>>>(), expected .iter() diff --git a/crates/trbfv/tests/integration.rs b/crates/trbfv/tests/integration.rs index 324d89fc5c..66b42dfe6b 100644 --- a/crates/trbfv/tests/integration.rs +++ b/crates/trbfv/tests/integration.rs @@ -142,7 +142,7 @@ async fn test_trbfv_isolation() -> Result<()> { let results = plaintext .into_iter() - .map(|a| decode_bytes_to_vec_u64(&a.extract_bytes())) + .map(|a| decode_bytes_to_vec_u64(&a.extract_bytes()).unwrap()) .collect::<Vec<Vec<u64>>>(); let results: Vec<u64> = results From 3feceaa66bff0cd1d8ccc04a6f30fd2f6f75a268 Mon Sep 17 00:00:00 2001 From: ryardley <contact@rudiyardley.com> Date: Fri, 7 Nov 2025 22:49:21 -0300 Subject: [PATCH 60/61] remove excessive logging --- examples/CRISP/server/src/server/indexer.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/CRISP/server/src/server/indexer.rs b/examples/CRISP/server/src/server/indexer.rs index fd0cbe41b1..5788893f38 100644 --- a/examples/CRISP/server/src/server/indexer.rs +++ b/examples/CRISP/server/src/server/indexer.rs @@ -265,7 +265,7 @@ pub async fn register_plaintext_output_published( // Thus, the decrypted sum directly represents the number of votes for Option 2. // The output is expected to be a Vec<u8> in little endian format of u64s. let decoded = decode_bytes_to_vec_u64(&event.plaintextOutput); - println!("RECEIVED: {:?}", decoded); + // decoded[0] is the sum of all encrypted votes (0s and 1s). // Since Option 1 votes are encrypted as '0' and Option 2 votes as '1', // this sum is equivalent to the count of votes for Option 2. From d33885d47af14f8e2649025a05cbae186f09761e Mon Sep 17 00:00:00 2001 From: ryardley <contact@rudiyardley.com> Date: Fri, 7 Nov 2025 23:18:34 -0300 Subject: [PATCH 61/61] fix compilation error --- examples/CRISP/server/src/server/indexer.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/CRISP/server/src/server/indexer.rs b/examples/CRISP/server/src/server/indexer.rs index 5788893f38..1a30097aab 100644 --- a/examples/CRISP/server/src/server/indexer.rs +++ b/examples/CRISP/server/src/server/indexer.rs @@ -264,7 +264,7 @@ pub async fn register_plaintext_output_published( // The computation sums the encrypted votes: '0' for Option 1, '1' for Option 2. // Thus, the decrypted sum directly represents the number of votes for Option 2. // The output is expected to be a Vec<u8> in little endian format of u64s. - let decoded = decode_bytes_to_vec_u64(&event.plaintextOutput); + let decoded = decode_bytes_to_vec_u64(&event.plaintextOutput)?; // decoded[0] is the sum of all encrypted votes (0s and 1s). // Since Option 1 votes are encrypted as '0' and Option 2 votes as '1',