From 8b6363a2ff353cbdeb9b91dd2c7c040008a788ef Mon Sep 17 00:00:00 2001 From: nginnever Date: Tue, 13 Aug 2024 10:57:33 -0700 Subject: [PATCH 01/87] init swarm --- packages/ciphernode/p2p/Cargo.toml | 12 +++--- packages/ciphernode/p2p/src/main.rs | 57 ++++++++++++++++++++++++++++- 2 files changed, 62 insertions(+), 7 deletions(-) diff --git a/packages/ciphernode/p2p/Cargo.toml b/packages/ciphernode/p2p/Cargo.toml index 4340494c..5191fc99 100644 --- a/packages/ciphernode/p2p/Cargo.toml +++ b/packages/ciphernode/p2p/Cargo.toml @@ -8,15 +8,15 @@ repository = "https://github.com/gnosisguild/enclave/packages/ciphernode" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -async-std = "1.12.0" fhe = { git = "https://github.com/gnosisguild/fhe.rs", version = "0.1.0-beta.7" } fhe-traits = { git = "https://github.com/gnosisguild/fhe.rs", version = "0.1.0-beta.7" } fhe-util = { git = "https://github.com/gnosisguild/fhe.rs", version = "0.1.0-beta.7" } async-std = { version = "1.12", features = ["attributes"] } async-trait = "0.1" -futures = { workspace = true } -libp2p = { version = "0.53.2", features = [ "async-std", "identify", "macros", "noise", "ping", "rendezvous", "tcp", "tokio", "yamux"] } -tokio = { workspace = true, features = ["rt-multi-thread", "macros", "time"] } -tracing = { workspace = true } -tracing-subscriber = { workspace = true, features = ["env-filter"] } +futures = "0.3.30" +libp2p = { version = "0.53.2", features = [ "async-std", "identify", "macros", "noise", "ping", "rendezvous", "tcp", "tokio", "yamux", "mdns", "gossipsub", "quic"] } +tokio = { version = "1.38", features = ["rt-multi-thread", "macros", "time"] } +tracing = "0.1.37" +tracing-subscriber = { version = "0.3", features = ["env-filter"] } + diff --git a/packages/ciphernode/p2p/src/main.rs b/packages/ciphernode/p2p/src/main.rs index a0d9916c..abc025b2 100644 --- a/packages/ciphernode/p2p/src/main.rs +++ b/packages/ciphernode/p2p/src/main.rs @@ -1,3 +1,58 @@ -fn main() { +use futures::stream::StreamExt; +use libp2p::{gossipsub, mdns, noise, swarm::NetworkBehaviour, swarm::SwarmEvent, tcp, yamux}; +use std::collections::hash_map::DefaultHasher; +use std::error::Error; +use std::hash::{Hash, Hasher}; +use std::time::Duration; +use tokio::{io, io::AsyncBufReadExt, select}; +use tracing_subscriber::EnvFilter; + +#[derive(NetworkBehaviour)] +struct MyBehaviour { + gossipsub: gossipsub::Behaviour, + mdns: mdns::tokio::Behaviour, +} + +#[tokio::main] +async fn main() -> Result<(), Box> { + let _ = tracing_subscriber::fmt() + .with_env_filter(EnvFilter::from_default_env()) + .try_init(); + + let mut swarm = libp2p::SwarmBuilder::with_new_identity() + .with_tokio() + .with_tcp( + tcp::Config::default(), + noise::Config::new, + yamux::Config::default, + )? + .with_quic() + .with_behaviour(|key| { + let message_id_fn = |message: &gossipsub::Message| { + let mut s = DefaultHasher::new(); + message.data.hash(&mut s); + gossipsub::MessageId::from(s.finish().to_string()) + }; + + let gossipsub_config = gossipsub::ConfigBuilder::default() + .heartbeat_interval(Duration::from_secs(10)) + .validation_mode(gossipsub::ValidationMode::Strict) + .message_id_fn(message_id_fn) + .build() + .map_err(|msg| io::Error::new(io::ErrorKind::Other, msg))?; + + let gossipsub = gossipsub::Behaviour::new( + gossipsub::MessageAuthenticity::Signed(key.clone()), + gossipsub_config, + )?; + + let mdns = + mdns::tokio::Behaviour::new(mdns::Config::default(), key.public().to_peer_id())?; + Ok(MyBehaviour { gossipsub, mdns }) + })? + .with_swarm_config(|c| c.with_idle_connection_timeout(Duration::from_secs(60))) + .build(); + println!("Hello, cipher world!"); + Ok(()) } From 6406ff23639a4f17c66cb3e99424cb72cefaa9a9 Mon Sep 17 00:00:00 2001 From: nginnever Date: Tue, 13 Aug 2024 11:19:04 -0700 Subject: [PATCH 02/87] message input --- packages/ciphernode/p2p/Cargo.toml | 2 +- packages/ciphernode/p2p/src/main.rs | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/packages/ciphernode/p2p/Cargo.toml b/packages/ciphernode/p2p/Cargo.toml index 5191fc99..1c10900e 100644 --- a/packages/ciphernode/p2p/Cargo.toml +++ b/packages/ciphernode/p2p/Cargo.toml @@ -15,7 +15,7 @@ async-std = { version = "1.12", features = ["attributes"] } async-trait = "0.1" futures = "0.3.30" libp2p = { version = "0.53.2", features = [ "async-std", "identify", "macros", "noise", "ping", "rendezvous", "tcp", "tokio", "yamux", "mdns", "gossipsub", "quic"] } -tokio = { version = "1.38", features = ["rt-multi-thread", "macros", "time"] } +tokio = { version = "1.38", features = ["full"] } tracing = "0.1.37" tracing-subscriber = { version = "0.3", features = ["env-filter"] } diff --git a/packages/ciphernode/p2p/src/main.rs b/packages/ciphernode/p2p/src/main.rs index abc025b2..cd8a06b3 100644 --- a/packages/ciphernode/p2p/src/main.rs +++ b/packages/ciphernode/p2p/src/main.rs @@ -53,6 +53,18 @@ async fn main() -> Result<(), Box> { .with_swarm_config(|c| c.with_idle_connection_timeout(Duration::from_secs(60))) .build(); + let topic = gossipsub::IdentTopic::new("enclave-keygen-01"); + + swarm.behaviour_mut().gossipsub.subscribe(&topic)?; + + // Read full lines from stdin + let mut stdin = io::BufReader::new(io::stdin()).lines(); + + swarm.listen_on("/ip4/0.0.0.0/udp/0/quic-v1".parse()?)?; + swarm.listen_on("/ip4/0.0.0.0/tcp/0".parse()?)?; + + + println!("Hello, cipher world!"); Ok(()) } From ac60a53a3521f1da63ec3dfa18f38f4f81512377 Mon Sep 17 00:00:00 2001 From: nginnever Date: Tue, 13 Aug 2024 11:28:27 -0700 Subject: [PATCH 03/87] gossip stdin --- packages/ciphernode/p2p/src/main.rs | 38 ++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/packages/ciphernode/p2p/src/main.rs b/packages/ciphernode/p2p/src/main.rs index cd8a06b3..2257d584 100644 --- a/packages/ciphernode/p2p/src/main.rs +++ b/packages/ciphernode/p2p/src/main.rs @@ -63,7 +63,43 @@ async fn main() -> Result<(), Box> { swarm.listen_on("/ip4/0.0.0.0/udp/0/quic-v1".parse()?)?; swarm.listen_on("/ip4/0.0.0.0/tcp/0".parse()?)?; - + loop { + select! { + Ok(Some(line)) = stdin.next_line() => { + if let Err(e) = swarm + .behaviour_mut().gossipsub + .publish(topic.clone(), line.as_bytes()) { + println!("Publish error: {e:?}"); + } + } + event = swarm.select_next_some() => match event { + SwarmEvent::Behaviour(MyBehaviourEvent::Mdns(mdns::Event::Discovered(list))) => { + for (peer_id, _multiaddr) in list { + println!("mDNS discovered a new peer: {peer_id}"); + swarm.behaviour_mut().gossipsub.add_explicit_peer(&peer_id); + } + }, + SwarmEvent::Behaviour(MyBehaviourEvent::Mdns(mdns::Event::Expired(list))) => { + for (peer_id, _multiaddr) in list { + println!("mDNS discover peer has expired: {peer_id}"); + swarm.behaviour_mut().gossipsub.remove_explicit_peer(&peer_id); + } + }, + SwarmEvent::Behaviour(MyBehaviourEvent::Gossipsub(gossipsub::Event::Message { + propagation_source: peer_id, + message_id: id, + message, + })) => println!( + "Got message: '{}' with id: {id} from peer: {peer_id}", + String::from_utf8_lossy(&message.data), + ), + SwarmEvent::NewListenAddr { address, .. } => { + println!("Local node is listening on {address}"); + } + _ => {} + } + } + } println!("Hello, cipher world!"); Ok(()) From 6d93ff5898719c33ecb256f2438b43472587bec4 Mon Sep 17 00:00:00 2001 From: nginnever Date: Tue, 13 Aug 2024 12:55:21 -0700 Subject: [PATCH 04/87] bfv gen --- packages/ciphernode/p2p/Cargo.toml | 1 + packages/ciphernode/p2p/src/main.rs | 10 ++++++++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/packages/ciphernode/p2p/Cargo.toml b/packages/ciphernode/p2p/Cargo.toml index 1c10900e..487b5a53 100644 --- a/packages/ciphernode/p2p/Cargo.toml +++ b/packages/ciphernode/p2p/Cargo.toml @@ -8,6 +8,7 @@ repository = "https://github.com/gnosisguild/enclave/packages/ciphernode" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +bfv = { path = "../bfv" } fhe = { git = "https://github.com/gnosisguild/fhe.rs", version = "0.1.0-beta.7" } fhe-traits = { git = "https://github.com/gnosisguild/fhe.rs", version = "0.1.0-beta.7" } fhe-util = { git = "https://github.com/gnosisguild/fhe.rs", version = "0.1.0-beta.7" } diff --git a/packages/ciphernode/p2p/src/main.rs b/packages/ciphernode/p2p/src/main.rs index 2257d584..6d1d8f18 100644 --- a/packages/ciphernode/p2p/src/main.rs +++ b/packages/ciphernode/p2p/src/main.rs @@ -6,6 +6,7 @@ use std::hash::{Hash, Hasher}; use std::time::Duration; use tokio::{io, io::AsyncBufReadExt, select}; use tracing_subscriber::EnvFilter; +use bfv::EnclaveBFV; #[derive(NetworkBehaviour)] struct MyBehaviour { @@ -66,6 +67,8 @@ async fn main() -> Result<(), Box> { loop { select! { Ok(Some(line)) = stdin.next_line() => { + println!("Generating Public Key Share"); + let node_bfv = bfv::EnclaveBFV::new("test".to_string()); if let Err(e) = swarm .behaviour_mut().gossipsub .publish(topic.clone(), line.as_bytes()) { @@ -89,10 +92,13 @@ async fn main() -> Result<(), Box> { propagation_source: peer_id, message_id: id, message, - })) => println!( + })) => { + println!( "Got message: '{}' with id: {id} from peer: {peer_id}", String::from_utf8_lossy(&message.data), - ), + ); + let node_bfv = bfv::EnclaveBFV::new("test".to_string()); + }, SwarmEvent::NewListenAddr { address, .. } => { println!("Local node is listening on {address}"); } From 8b8e2125b8d33f62d1c222a5ee6c94b010a66ba2 Mon Sep 17 00:00:00 2001 From: nginnever Date: Wed, 14 Aug 2024 17:48:03 -0700 Subject: [PATCH 05/87] init p2p lib --- packages/ciphernode/p2p/src/main.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/packages/ciphernode/p2p/src/main.rs b/packages/ciphernode/p2p/src/main.rs index 6d1d8f18..6172016d 100644 --- a/packages/ciphernode/p2p/src/main.rs +++ b/packages/ciphernode/p2p/src/main.rs @@ -14,6 +14,18 @@ struct MyBehaviour { mdns: mdns::tokio::Behaviour, } +pub struct EnclaveRouter { + pub address: String, + behaviour: MyBehaviour, +} + +impl EnclaveRouter { + pub fn new(address: String) -> Self { + Self { address } + } +} + + #[tokio::main] async fn main() -> Result<(), Box> { let _ = tracing_subscriber::fmt() From 6b55b4613ca199ce61a7b33a26d729a9e9a11864 Mon Sep 17 00:00:00 2001 From: nginnever Date: Thu, 15 Aug 2024 16:50:44 -0700 Subject: [PATCH 06/87] connect and key --- packages/ciphernode/p2p/src/main.rs | 266 ++++++++++++++++++---------- 1 file changed, 170 insertions(+), 96 deletions(-) diff --git a/packages/ciphernode/p2p/src/main.rs b/packages/ciphernode/p2p/src/main.rs index 6172016d..e28a79ec 100644 --- a/packages/ciphernode/p2p/src/main.rs +++ b/packages/ciphernode/p2p/src/main.rs @@ -1,5 +1,5 @@ use futures::stream::StreamExt; -use libp2p::{gossipsub, mdns, noise, swarm::NetworkBehaviour, swarm::SwarmEvent, tcp, yamux}; +use libp2p::{gossipsub, mdns, noise, swarm::NetworkBehaviour, swarm::SwarmEvent, tcp, yamux, identity, Swarm}; use std::collections::hash_map::DefaultHasher; use std::error::Error; use std::hash::{Hash, Hasher}; @@ -8,6 +8,10 @@ use tokio::{io, io::AsyncBufReadExt, select}; use tracing_subscriber::EnvFilter; use bfv::EnclaveBFV; +fn print_type_of(_: &T) { + println!("{}", std::any::type_name::()); +} + #[derive(NetworkBehaviour)] struct MyBehaviour { gossipsub: gossipsub::Behaviour, @@ -15,109 +19,179 @@ struct MyBehaviour { } pub struct EnclaveRouter { - pub address: String, - behaviour: MyBehaviour, + pub identity: Option, + pub gossipsub_config: gossipsub::Config, + pub swarm: Option>, + //pub swarm: Swarm, + //behaviour: MyBehaviour, } impl EnclaveRouter { - pub fn new(address: String) -> Self { - Self { address } + pub fn new() -> Result> { + println!("new router"); + + let message_id_fn = |message: &gossipsub::Message| { + let mut s = DefaultHasher::new(); + message.data.hash(&mut s); + gossipsub::MessageId::from(s.finish().to_string()) + }; + + // TODO: Allow for config inputs to new() + let gossipsub_config = gossipsub::ConfigBuilder::default() + .heartbeat_interval(Duration::from_secs(10)) + .validation_mode(gossipsub::ValidationMode::Strict) + .message_id_fn(message_id_fn) + .build() + .map_err(|msg| io::Error::new(io::ErrorKind::Other, msg))?; + + Ok(Self { identity: None, gossipsub_config, swarm: None }) + } + + pub fn with_identiy(&mut self, keypair: identity::Keypair) { + self.identity = Some(keypair); + } + + pub fn connect_swarm(&mut self, discovery_type: String) -> Result<(), Box> { + match discovery_type.as_str() { + "mdns" => { + let _ = tracing_subscriber::fmt() + .with_env_filter(EnvFilter::from_default_env()) + .try_init(); + + // TODO: Use key if assigned already + let mut swarm = libp2p::SwarmBuilder::with_new_identity() + .with_tokio() + .with_tcp( + tcp::Config::default(), + noise::Config::new, + yamux::Config::default, + )? + .with_quic() + .with_behaviour(|key| { + let gossipsub = gossipsub::Behaviour::new( + gossipsub::MessageAuthenticity::Signed(key.clone()), + self.gossipsub_config.clone(), + )?; + + let mdns = + mdns::tokio::Behaviour::new(mdns::Config::default(), key.public().to_peer_id())?; + Ok(MyBehaviour { gossipsub, mdns }) + })? + .with_swarm_config(|c| c.with_idle_connection_timeout(Duration::from_secs(60))) + .build(); + self.swarm = Some(swarm); + }, + _ => { + println!("Defaulting to MDNS discovery") + }, + } + Ok(()) + } + + pub fn join_topic(topic: String) { + } -} + pub fn start() { + + } +} #[tokio::main] async fn main() -> Result<(), Box> { - let _ = tracing_subscriber::fmt() - .with_env_filter(EnvFilter::from_default_env()) - .try_init(); - - let mut swarm = libp2p::SwarmBuilder::with_new_identity() - .with_tokio() - .with_tcp( - tcp::Config::default(), - noise::Config::new, - yamux::Config::default, - )? - .with_quic() - .with_behaviour(|key| { - let message_id_fn = |message: &gossipsub::Message| { - let mut s = DefaultHasher::new(); - message.data.hash(&mut s); - gossipsub::MessageId::from(s.finish().to_string()) - }; - - let gossipsub_config = gossipsub::ConfigBuilder::default() - .heartbeat_interval(Duration::from_secs(10)) - .validation_mode(gossipsub::ValidationMode::Strict) - .message_id_fn(message_id_fn) - .build() - .map_err(|msg| io::Error::new(io::ErrorKind::Other, msg))?; - - let gossipsub = gossipsub::Behaviour::new( - gossipsub::MessageAuthenticity::Signed(key.clone()), - gossipsub_config, - )?; - - let mdns = - mdns::tokio::Behaviour::new(mdns::Config::default(), key.public().to_peer_id())?; - Ok(MyBehaviour { gossipsub, mdns }) - })? - .with_swarm_config(|c| c.with_idle_connection_timeout(Duration::from_secs(60))) - .build(); - - let topic = gossipsub::IdentTopic::new("enclave-keygen-01"); - - swarm.behaviour_mut().gossipsub.subscribe(&topic)?; - - // Read full lines from stdin - let mut stdin = io::BufReader::new(io::stdin()).lines(); - - swarm.listen_on("/ip4/0.0.0.0/udp/0/quic-v1".parse()?)?; - swarm.listen_on("/ip4/0.0.0.0/tcp/0".parse()?)?; - - loop { - select! { - Ok(Some(line)) = stdin.next_line() => { - println!("Generating Public Key Share"); - let node_bfv = bfv::EnclaveBFV::new("test".to_string()); - if let Err(e) = swarm - .behaviour_mut().gossipsub - .publish(topic.clone(), line.as_bytes()) { - println!("Publish error: {e:?}"); - } - } - event = swarm.select_next_some() => match event { - SwarmEvent::Behaviour(MyBehaviourEvent::Mdns(mdns::Event::Discovered(list))) => { - for (peer_id, _multiaddr) in list { - println!("mDNS discovered a new peer: {peer_id}"); - swarm.behaviour_mut().gossipsub.add_explicit_peer(&peer_id); - } - }, - SwarmEvent::Behaviour(MyBehaviourEvent::Mdns(mdns::Event::Expired(list))) => { - for (peer_id, _multiaddr) in list { - println!("mDNS discover peer has expired: {peer_id}"); - swarm.behaviour_mut().gossipsub.remove_explicit_peer(&peer_id); - } - }, - SwarmEvent::Behaviour(MyBehaviourEvent::Gossipsub(gossipsub::Event::Message { - propagation_source: peer_id, - message_id: id, - message, - })) => { - println!( - "Got message: '{}' with id: {id} from peer: {peer_id}", - String::from_utf8_lossy(&message.data), - ); - let node_bfv = bfv::EnclaveBFV::new("test".to_string()); - }, - SwarmEvent::NewListenAddr { address, .. } => { - println!("Local node is listening on {address}"); - } - _ => {} - } - } - } + // let _ = tracing_subscriber::fmt() + // .with_env_filter(EnvFilter::from_default_env()) + // .try_init(); + + // let mut swarm = libp2p::SwarmBuilder::with_new_identity() + // .with_tokio() + // .with_tcp( + // tcp::Config::default(), + // noise::Config::new, + // yamux::Config::default, + // )? + // .with_quic() + // .with_behaviour(|key| { + // let message_id_fn = |message: &gossipsub::Message| { + // let mut s = DefaultHasher::new(); + // message.data.hash(&mut s); + // gossipsub::MessageId::from(s.finish().to_string()) + // }; + + // let gossipsub_config = gossipsub::ConfigBuilder::default() + // .heartbeat_interval(Duration::from_secs(10)) + // .validation_mode(gossipsub::ValidationMode::Strict) + // .message_id_fn(message_id_fn) + // .build() + // .map_err(|msg| io::Error::new(io::ErrorKind::Other, msg))?; + + // let gossipsub = gossipsub::Behaviour::new( + // gossipsub::MessageAuthenticity::Signed(key.clone()), + // gossipsub_config, + // )?; + + // let mdns = + // mdns::tokio::Behaviour::new(mdns::Config::default(), key.public().to_peer_id())?; + // Ok(MyBehaviour { gossipsub, mdns }) + // })? + // .with_swarm_config(|c| c.with_idle_connection_timeout(Duration::from_secs(60))) + // .build(); + + // let topic = gossipsub::IdentTopic::new("enclave-keygen-01"); + + // swarm.behaviour_mut().gossipsub.subscribe(&topic)?; + + // // Read full lines from stdin + // let mut stdin = io::BufReader::new(io::stdin()).lines(); + + // swarm.listen_on("/ip4/0.0.0.0/udp/0/quic-v1".parse()?)?; + // swarm.listen_on("/ip4/0.0.0.0/tcp/0".parse()?)?; + + let mut p2p = EnclaveRouter::new()? + .connect_swarm("mdns".to_string())?; + + // loop { + // select! { + // Ok(Some(line)) = stdin.next_line() => { + // println!("Generating Public Key Share"); + // let node_bfv = bfv::EnclaveBFV::new("test".to_string()); + // if let Err(e) = swarm + // .behaviour_mut().gossipsub + // .publish(topic.clone(), line.as_bytes()) { + // println!("Publish error: {e:?}"); + // } + // } + // event = swarm.select_next_some() => match event { + // SwarmEvent::Behaviour(MyBehaviourEvent::Mdns(mdns::Event::Discovered(list))) => { + // for (peer_id, _multiaddr) in list { + // println!("mDNS discovered a new peer: {peer_id}"); + // swarm.behaviour_mut().gossipsub.add_explicit_peer(&peer_id); + // } + // }, + // SwarmEvent::Behaviour(MyBehaviourEvent::Mdns(mdns::Event::Expired(list))) => { + // for (peer_id, _multiaddr) in list { + // println!("mDNS discover peer has expired: {peer_id}"); + // swarm.behaviour_mut().gossipsub.remove_explicit_peer(&peer_id); + // } + // }, + // SwarmEvent::Behaviour(MyBehaviourEvent::Gossipsub(gossipsub::Event::Message { + // propagation_source: peer_id, + // message_id: id, + // message, + // })) => { + // println!( + // "Got message: '{}' with id: {id} from peer: {peer_id}", + // String::from_utf8_lossy(&message.data), + // ); + // let node_bfv = bfv::EnclaveBFV::new("test".to_string()); + // }, + // SwarmEvent::NewListenAddr { address, .. } => { + // println!("Local node is listening on {address}"); + // } + // _ => {} + // } + // } + // } println!("Hello, cipher world!"); Ok(()) From 4cda5c2383b503ab99ec40adf1d040121886f222 Mon Sep 17 00:00:00 2001 From: nginnever Date: Thu, 15 Aug 2024 18:44:57 -0700 Subject: [PATCH 07/87] initial structure --- packages/ciphernode/p2p/src/main.rs | 176 ++++++++++------------------ 1 file changed, 65 insertions(+), 111 deletions(-) diff --git a/packages/ciphernode/p2p/src/main.rs b/packages/ciphernode/p2p/src/main.rs index e28a79ec..f6fa9c42 100644 --- a/packages/ciphernode/p2p/src/main.rs +++ b/packages/ciphernode/p2p/src/main.rs @@ -8,10 +8,6 @@ use tokio::{io, io::AsyncBufReadExt, select}; use tracing_subscriber::EnvFilter; use bfv::EnclaveBFV; -fn print_type_of(_: &T) { - println!("{}", std::any::type_name::()); -} - #[derive(NetworkBehaviour)] struct MyBehaviour { gossipsub: gossipsub::Behaviour, @@ -22,14 +18,11 @@ pub struct EnclaveRouter { pub identity: Option, pub gossipsub_config: gossipsub::Config, pub swarm: Option>, - //pub swarm: Swarm, - //behaviour: MyBehaviour, + pub topic: Option, } impl EnclaveRouter { pub fn new() -> Result> { - println!("new router"); - let message_id_fn = |message: &gossipsub::Message| { let mut s = DefaultHasher::new(); message.data.hash(&mut s); @@ -44,14 +37,14 @@ impl EnclaveRouter { .build() .map_err(|msg| io::Error::new(io::ErrorKind::Other, msg))?; - Ok(Self { identity: None, gossipsub_config, swarm: None }) + Ok(Self { identity: None, gossipsub_config, swarm: None, topic: None }) } pub fn with_identiy(&mut self, keypair: identity::Keypair) { self.identity = Some(keypair); } - pub fn connect_swarm(&mut self, discovery_type: String) -> Result<(), Box> { + pub fn connect_swarm(&mut self, discovery_type: String) -> Result<(&Self), Box> { match discovery_type.as_str() { "mdns" => { let _ = tracing_subscriber::fmt() @@ -81,117 +74,78 @@ impl EnclaveRouter { .build(); self.swarm = Some(swarm); }, - _ => { - println!("Defaulting to MDNS discovery") - }, + _ => println!("Defaulting to MDNS discovery"), } - Ok(()) + Ok((self)) } - pub fn join_topic(topic: String) { - + pub fn join_topic(&mut self, topic_name: &str) -> Result<(&Self), Box> { + let topic = gossipsub::IdentTopic::new(topic_name); + self.topic = Some(topic.clone()); + self.swarm.as_mut().unwrap().behaviour_mut().gossipsub.subscribe(&topic)?; + Ok((self)) } - pub fn start() { - + pub async fn start(&mut self) -> Result<(), Box> { + // Read full lines from stdin + let mut stdin = io::BufReader::new(io::stdin()).lines(); + + self.swarm.as_mut().unwrap().listen_on("/ip4/0.0.0.0/udp/0/quic-v1".parse()?)?; + self.swarm.as_mut().unwrap().listen_on("/ip4/0.0.0.0/tcp/0".parse()?)?; + loop { + select! { + Ok(Some(line)) = stdin.next_line() => { + println!("Generating Public Key Share"); + let node_bfv = bfv::EnclaveBFV::new("test".to_string()); + if let Err(e) = self.swarm.as_mut().unwrap() + .behaviour_mut().gossipsub + .publish(self.topic.as_mut().unwrap().clone(), line.as_bytes()) { + println!("Publish error: {e:?}"); + } + } + event = self.swarm.as_mut().unwrap().select_next_some() => match event { + SwarmEvent::Behaviour(MyBehaviourEvent::Mdns(mdns::Event::Discovered(list))) => { + for (peer_id, _multiaddr) in list { + println!("mDNS discovered a new peer: {peer_id}"); + self.swarm.as_mut().unwrap().behaviour_mut().gossipsub.add_explicit_peer(&peer_id); + } + }, + SwarmEvent::Behaviour(MyBehaviourEvent::Mdns(mdns::Event::Expired(list))) => { + for (peer_id, _multiaddr) in list { + println!("mDNS discover peer has expired: {peer_id}"); + self.swarm.as_mut().unwrap().behaviour_mut().gossipsub.remove_explicit_peer(&peer_id); + } + }, + SwarmEvent::Behaviour(MyBehaviourEvent::Gossipsub(gossipsub::Event::Message { + propagation_source: peer_id, + message_id: id, + message, + })) => { + println!( + "Got message: '{}' with id: {id} from peer: {peer_id}", + String::from_utf8_lossy(&message.data), + ); + let node_bfv = bfv::EnclaveBFV::new("test".to_string()); + }, + SwarmEvent::NewListenAddr { address, .. } => { + println!("Local node is listening on {address}"); + } + _ => {} + } + } + } + + Ok(()) } } #[tokio::main] async fn main() -> Result<(), Box> { - // let _ = tracing_subscriber::fmt() - // .with_env_filter(EnvFilter::from_default_env()) - // .try_init(); - - // let mut swarm = libp2p::SwarmBuilder::with_new_identity() - // .with_tokio() - // .with_tcp( - // tcp::Config::default(), - // noise::Config::new, - // yamux::Config::default, - // )? - // .with_quic() - // .with_behaviour(|key| { - // let message_id_fn = |message: &gossipsub::Message| { - // let mut s = DefaultHasher::new(); - // message.data.hash(&mut s); - // gossipsub::MessageId::from(s.finish().to_string()) - // }; - - // let gossipsub_config = gossipsub::ConfigBuilder::default() - // .heartbeat_interval(Duration::from_secs(10)) - // .validation_mode(gossipsub::ValidationMode::Strict) - // .message_id_fn(message_id_fn) - // .build() - // .map_err(|msg| io::Error::new(io::ErrorKind::Other, msg))?; - - // let gossipsub = gossipsub::Behaviour::new( - // gossipsub::MessageAuthenticity::Signed(key.clone()), - // gossipsub_config, - // )?; - - // let mdns = - // mdns::tokio::Behaviour::new(mdns::Config::default(), key.public().to_peer_id())?; - // Ok(MyBehaviour { gossipsub, mdns }) - // })? - // .with_swarm_config(|c| c.with_idle_connection_timeout(Duration::from_secs(60))) - // .build(); - - // let topic = gossipsub::IdentTopic::new("enclave-keygen-01"); - - // swarm.behaviour_mut().gossipsub.subscribe(&topic)?; - - // // Read full lines from stdin - // let mut stdin = io::BufReader::new(io::stdin()).lines(); - - // swarm.listen_on("/ip4/0.0.0.0/udp/0/quic-v1".parse()?)?; - // swarm.listen_on("/ip4/0.0.0.0/tcp/0".parse()?)?; - - let mut p2p = EnclaveRouter::new()? - .connect_swarm("mdns".to_string())?; - - // loop { - // select! { - // Ok(Some(line)) = stdin.next_line() => { - // println!("Generating Public Key Share"); - // let node_bfv = bfv::EnclaveBFV::new("test".to_string()); - // if let Err(e) = swarm - // .behaviour_mut().gossipsub - // .publish(topic.clone(), line.as_bytes()) { - // println!("Publish error: {e:?}"); - // } - // } - // event = swarm.select_next_some() => match event { - // SwarmEvent::Behaviour(MyBehaviourEvent::Mdns(mdns::Event::Discovered(list))) => { - // for (peer_id, _multiaddr) in list { - // println!("mDNS discovered a new peer: {peer_id}"); - // swarm.behaviour_mut().gossipsub.add_explicit_peer(&peer_id); - // } - // }, - // SwarmEvent::Behaviour(MyBehaviourEvent::Mdns(mdns::Event::Expired(list))) => { - // for (peer_id, _multiaddr) in list { - // println!("mDNS discover peer has expired: {peer_id}"); - // swarm.behaviour_mut().gossipsub.remove_explicit_peer(&peer_id); - // } - // }, - // SwarmEvent::Behaviour(MyBehaviourEvent::Gossipsub(gossipsub::Event::Message { - // propagation_source: peer_id, - // message_id: id, - // message, - // })) => { - // println!( - // "Got message: '{}' with id: {id} from peer: {peer_id}", - // String::from_utf8_lossy(&message.data), - // ); - // let node_bfv = bfv::EnclaveBFV::new("test".to_string()); - // }, - // SwarmEvent::NewListenAddr { address, .. } => { - // println!("Local node is listening on {address}"); - // } - // _ => {} - // } - // } - // } + + let mut p2p = EnclaveRouter::new()?; + p2p.connect_swarm("mdns".to_string())?; + p2p.join_topic("enclave-keygen-01")?; + p2p.start().await?; println!("Hello, cipher world!"); Ok(()) From d408522a6b9eff8b43dd46550b2d407e6ea9a337 Mon Sep 17 00:00:00 2001 From: nginnever Date: Tue, 20 Aug 2024 11:31:53 -0700 Subject: [PATCH 08/87] lib --- packages/ciphernode/enclave_node/Cargo.toml | 2 ++ packages/ciphernode/enclave_node/src/main.rs | 31 ++++++++++++++++++-- 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/packages/ciphernode/enclave_node/Cargo.toml b/packages/ciphernode/enclave_node/Cargo.toml index 861bc2e7..fe310370 100644 --- a/packages/ciphernode/enclave_node/Cargo.toml +++ b/packages/ciphernode/enclave_node/Cargo.toml @@ -9,7 +9,9 @@ repository = "https://github.com/gnosisguild/enclave/packages/ciphernode" [dependencies] eth = { path = "../eth" } +p2p = { path = "../p2p" } async-std = "1.12.0" fhe = { git = "https://github.com/gnosisguild/fhe.rs", version = "0.1.0-beta.7" } fhe-traits = { git = "https://github.com/gnosisguild/fhe.rs", version = "0.1.0-beta.7" } fhe-util = { git = "https://github.com/gnosisguild/fhe.rs", version = "0.1.0-beta.7" } +tokio = { version = "1.38", features = ["full"] } \ No newline at end of file diff --git a/packages/ciphernode/enclave_node/src/main.rs b/packages/ciphernode/enclave_node/src/main.rs index 0074dc3c..d3b72aba 100644 --- a/packages/ciphernode/enclave_node/src/main.rs +++ b/packages/ciphernode/enclave_node/src/main.rs @@ -1,12 +1,39 @@ use eth::EtherClient; +use p2p::EnclaveRouter; +use std::error::Error; +use tokio; -fn main() { +const OWO: &str = r#" + ___ ___ ___ ___ ___ + /\__\ /\ \ /\__\ /\ \ ___ /\__\ + /:/ _/_ \:\ \ /:/ / /::\ \ /\ \ /:/ _/_ + /:/ /\__\ \:\ \ /:/ / /:/\:\ \ \:\ \ /:/ /\__\ + /:/ /:/ _/_ _____\:\ \ /:/ / ___ ___ ___ /:/ /::\ \ \:\ \ /:/ /:/ _/_ + /:/_/:/ /\__\ /::::::::\__\ /:/__/ /\__\ /\ \ /\__\ /:/_/:/\:\__\ ___ \:\__\ /:/_/:/ /\__\ + \:\/:/ /:/ / \:\~~\~~\/__/ \:\ \ /:/ / \:\ \ /:/ / \:\/:/ \/__/ /\ \ |:| | \:\/:/ /:/ / + \::/_/:/ / \:\ \ \:\ /:/ / \:\ /:/ / \::/__/ \:\ \|:| | \::/_/:/ / + \:\/:/ / \:\ \ \:\/:/ / \:\/:/ / \:\ \ \:\__|:|__| \:\/:/ / + \::/ / \:\__\ \::/ / \::/ / \:\__\ \::::/__/ \::/ / + \/__/ \/__/ \/__/ \/__/ \/__/ ~~~~ \/__/ + +"#; + +#[tokio::main] +async fn main() -> Result<(), Box> { // boot up p2p network // boot up ether client // start main loop - let ether = eth::EtherClient::new("test".to_string()); + //let ether = eth::EtherClient::new("test".to_string()); + println!("\n\n\n\n\n{}", OWO); + println!("\n\n\n\n"); + + let mut p2p = EnclaveRouter::new()?; + p2p.connect_swarm("mdns".to_string())?; + p2p.join_topic("enclave-keygen-01")?; + p2p.start().await?; println!("Hello, cipher world!"); + Ok(()) } \ No newline at end of file From 54fda0fd58b8ec7da44ff287818f52634238b7f4 Mon Sep 17 00:00:00 2001 From: nginnever Date: Wed, 21 Aug 2024 19:34:55 -0700 Subject: [PATCH 09/87] update --- packages/ciphernode/Cargo.lock | 2176 ++++++++++++++++- packages/ciphernode/Cargo.toml | 2 +- packages/ciphernode/bfv/Cargo.toml | 1 + packages/ciphernode/bfv/src/lib.rs | 46 + packages/ciphernode/bfv/src/main.rs | 3 - packages/ciphernode/bfv/src/util.rs | 129 + .../ciphernode/p2p/src/{main.rs => lib.rs} | 22 +- 7 files changed, 2299 insertions(+), 80 deletions(-) create mode 100644 packages/ciphernode/bfv/src/lib.rs delete mode 100644 packages/ciphernode/bfv/src/main.rs create mode 100644 packages/ciphernode/bfv/src/util.rs rename packages/ciphernode/p2p/src/{main.rs => lib.rs} (93%) diff --git a/packages/ciphernode/Cargo.lock b/packages/ciphernode/Cargo.lock index 39e6be0c..57495901 100644 --- a/packages/ciphernode/Cargo.lock +++ b/packages/ciphernode/Cargo.lock @@ -2,6 +2,56 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "addr2line" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "aead" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" +dependencies = [ + "crypto-common", + "generic-array", +] + +[[package]] +name = "aes" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", +] + +[[package]] +name = "aes-gcm" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "831010a0f742e1209b3bcea8fab6a8e149051ba6099432c8cb2cc117dec3ead1" +dependencies = [ + "aead", + "aes", + "cipher", + "ctr", + "ghash", + "subtle", +] + [[package]] name = "ahash" version = "0.8.11" @@ -41,6 +91,55 @@ version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d151e35f61089500b617991b791fc8bfd237ae50cd5950803758a179b41e67a" +[[package]] +name = "asn1-rs" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5493c3bedbacf7fd7382c6346bbd66687d12bbaad3a89a2d2c303ee6cf20b048" +dependencies = [ + "asn1-rs-derive", + "asn1-rs-impl", + "displaydoc", + "nom", + "num-traits", + "rusticata-macros", + "thiserror", + "time", +] + +[[package]] +name = "asn1-rs-derive" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "965c2d33e53cb6b267e148a4cb0760bc01f4904c1cd4bb4002a085bb016d1490" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.72", + "synstructure", +] + +[[package]] +name = "asn1-rs-impl" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b18050c2cd6fe86c3a76584ef5e0baf286d038cda203eb6223df2cc413565f7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.72", +] + +[[package]] +name = "async-attributes" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3203e79f4dd9bdda415ed03cf14dae5a2bf775c683a00f94e9cd1faf0f596e5" +dependencies = [ + "quote", + "syn 1.0.109", +] + [[package]] name = "async-channel" version = "1.9.0" @@ -77,6 +176,18 @@ dependencies = [ "slab", ] +[[package]] +name = "async-fs" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "279cf904654eeebfa37ac9bb1598880884924aab82e290aa65c9e77a0e142e06" +dependencies = [ + "async-lock 2.8.0", + "autocfg", + "blocking", + "futures-lite 1.13.0", +] + [[package]] name = "async-global-executor" version = "2.4.1" @@ -108,7 +219,7 @@ dependencies = [ "polling 2.8.0", "rustix 0.37.27", "slab", - "socket2", + "socket2 0.4.10", "waker-fn", ] @@ -151,16 +262,64 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "async-net" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0434b1ed18ce1cf5769b8ac540e33f01fa9471058b5e89da9e06f3c882a8c12f" +dependencies = [ + "async-io 1.13.0", + "blocking", + "futures-lite 1.13.0", +] + +[[package]] +name = "async-process" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea6438ba0a08d81529c69b36700fa2f95837bfe3e776ab39cde9c14d9149da88" +dependencies = [ + "async-io 1.13.0", + "async-lock 2.8.0", + "async-signal", + "blocking", + "cfg-if", + "event-listener 3.1.0", + "futures-lite 1.13.0", + "rustix 0.38.34", + "windows-sys 0.48.0", +] + +[[package]] +name = "async-signal" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "637e00349800c0bdf8bfc21ebbc0b6524abea702b0da4168ac00d070d0c0b9f3" +dependencies = [ + "async-io 2.3.3", + "async-lock 3.4.0", + "atomic-waker", + "cfg-if", + "futures-core", + "futures-io", + "rustix 0.38.34", + "signal-hook-registry", + "slab", + "windows-sys 0.59.0", +] + [[package]] name = "async-std" version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62565bb4402e926b29953c785397c6dc0391b7b446e45008b0049eb43cec6f5d" dependencies = [ + "async-attributes", "async-channel 1.9.0", "async-global-executor", "async-io 1.13.0", "async-lock 2.8.0", + "async-process", "crossbeam-utils", "futures-channel", "futures-core", @@ -177,36 +336,143 @@ dependencies = [ "wasm-bindgen-futures", ] +[[package]] +name = "async-std-resolver" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc3b454643291f9a4a3bbdb35fa62efa4ba7be5ea13fe243e3be4352182ff4b8" +dependencies = [ + "async-std", + "async-trait", + "futures-io", + "futures-util", + "hickory-resolver", + "pin-utils", + "socket2 0.5.7", +] + [[package]] name = "async-task" version = "4.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" +[[package]] +name = "async-trait" +version = "0.1.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e0c28dcc82d7c8ead5cb13beb15405b57b8546e93215673ff8ca0349a028107" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.72", +] + +[[package]] +name = "asynchronous-codec" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4057f2c32adbb2fc158e22fb38433c8e9bbf76b75a4732c7c0cbaf695fb65568" +dependencies = [ + "bytes", + "futures-sink", + "futures-util", + "memchr", + "pin-project-lite", +] + +[[package]] +name = "asynchronous-codec" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a860072022177f903e59730004fb5dc13db9275b79bb2aef7ba8ce831956c233" +dependencies = [ + "bytes", + "futures-sink", + "futures-util", + "memchr", + "pin-project-lite", +] + [[package]] name = "atomic-waker" version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" +[[package]] +name = "attohttpc" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d9a9bf8b79a749ee0b911b91b671cc2b6c670bdbc7e3dfd537576ddc94bb2a2" +dependencies = [ + "http", + "log", + "url", +] + [[package]] name = "autocfg" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" +[[package]] +name = "backtrace" +version = "0.3.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + [[package]] name = "base-x" version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4cbbc9d0964165b47557570cce6c952866c2678457aca742aafc9fb771d30270" +[[package]] +name = "base64" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + [[package]] name = "base64ct" version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" +[[package]] +name = "bfv" +version = "0.1.0" +dependencies = [ + "async-std", + "fhe", + "fhe-traits", + "fhe-util", + "rand", +] + +[[package]] +name = "bimap" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "230c5f1ca6a325a32553f8640d31ac9b49f2411e901e427570154868b46da4f7" + [[package]] name = "bitflags" version = "1.3.2" @@ -219,6 +485,15 @@ version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +[[package]] +name = "blake2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" +dependencies = [ + "digest", +] + [[package]] name = "block-buffer" version = "0.10.4" @@ -268,12 +543,53 @@ version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50" +[[package]] +name = "cc" +version = "1.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9e8aabfac534be767c909e0690571677d49f41bd8465ae876fe043d52ba5292" + [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "chacha20" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3613f74bd2eac03dad61bd53dbe620703d4371614fe0bc3b9f04dd36fe4e818" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", +] + +[[package]] +name = "chacha20poly1305" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10cd79432192d1c0f4e1a0fef9527696cc039165d729fb41b3f4f4f354c2dc35" +dependencies = [ + "aead", + "chacha20", + "cipher", + "poly1305", + "zeroize", +] + +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", + "zeroize", +] + [[package]] name = "concurrent-queue" version = "2.5.0" @@ -300,6 +616,22 @@ dependencies = [ "libp2p", ] +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + [[package]] name = "core2" version = "0.4.0" @@ -331,9 +663,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ "generic-array", + "rand_core", "typenum", ] +[[package]] +name = "ctr" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" +dependencies = [ + "cipher", +] + [[package]] name = "curve25519-dalek" version = "4.1.3" @@ -397,6 +739,29 @@ dependencies = [ "zeroize", ] +[[package]] +name = "der-parser" +version = "9.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cd0a5c643689626bec213c4d8bd4d96acc8ffdb4ad4bb6bc16abf27d5f4b553" +dependencies = [ + "asn1-rs", + "displaydoc", + "nom", + "num-bigint", + "num-traits", + "rusticata-macros", +] + +[[package]] +name = "deranged" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +dependencies = [ + "powerfmt", +] + [[package]] name = "digest" version = "0.10.7" @@ -408,12 +773,29 @@ dependencies = [ "subtle", ] +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.72", +] + [[package]] name = "doc-comment" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" +[[package]] +name = "dtoa" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcbb2bf8e87535c23f7a8a321e364ce21462d0ff10cb6407820e8e96dfff6653" + [[package]] name = "ed25519" version = "2.2.3" @@ -465,6 +847,20 @@ dependencies = [ "fhe", "fhe-traits", "fhe-util", + "p2p", + "tokio", +] + +[[package]] +name = "enum-as-inner" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ffccbb6966c05b32ef8fbac435df276c4ae4d3dc55a8cd0eb9745e6c12f546a" +dependencies = [ + "heck 0.4.1", + "proc-macro2", + "quote", + "syn 2.0.72", ] [[package]] @@ -507,9 +903,20 @@ checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" [[package]] name = "event-listener" -version = "5.3.1" +version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6032be9bd27023a771701cc49f9f053c751055f71efb2e0ae5c15809093675ba" +checksum = "d93877bcde0eb80ca09131a08d23f0a5c18a620b01db137dba666d18cd9b30c2" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener" +version = "5.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6032be9bd27023a771701cc49f9f053c751055f71efb2e0ae5c15809093675ba" dependencies = [ "concurrent-queue", "parking", @@ -647,6 +1054,16 @@ dependencies = [ "futures-util", ] +[[package]] +name = "futures-bounded" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91f328e7fb845fc832912fb6a34f40cf6d1888c92f974d1893a54e97b5ff542e" +dependencies = [ + "futures-timer", + "futures-util", +] + [[package]] name = "futures-channel" version = "0.3.30" @@ -720,6 +1137,17 @@ dependencies = [ "syn 2.0.72", ] +[[package]] +name = "futures-rustls" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f2f12607f92c69b12ed746fabf9ca4f5c482cba46679c1a75b874ed7c26adb" +dependencies = [ + "futures-io", + "rustls", + "rustls-pki-types", +] + [[package]] name = "futures-sink" version = "0.3.30" @@ -732,6 +1160,17 @@ version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" +[[package]] +name = "futures-ticker" +version = "0.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9763058047f713632a52e916cc7f6a4b3fc6e9fc1ff8c5b1dc49e5a89041682e" +dependencies = [ + "futures", + "futures-timer", + "instant", +] + [[package]] name = "futures-timer" version = "3.0.3" @@ -777,6 +1216,22 @@ dependencies = [ "wasi", ] +[[package]] +name = "ghash" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0d8a4362ccb29cb0b265253fb0a2728f592895ee6854fd9bc13f2ffda266ff1" +dependencies = [ + "opaque-debug", + "polyval", +] + +[[package]] +name = "gimli" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" + [[package]] name = "gloo-timers" version = "0.2.6" @@ -789,6 +1244,25 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "h2" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + [[package]] name = "hashbrown" version = "0.14.5" @@ -799,6 +1273,12 @@ dependencies = [ "allocator-api2", ] +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + [[package]] name = "heck" version = "0.5.0" @@ -817,6 +1297,58 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" +[[package]] +name = "hex_fmt" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b07f60793ff0a4d9cef0f18e63b5357e06209987153a64648c972c1e5aff336f" + +[[package]] +name = "hickory-proto" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07698b8420e2f0d6447a436ba999ec85d8fbf2a398bbd737b82cac4a2e96e512" +dependencies = [ + "async-trait", + "cfg-if", + "data-encoding", + "enum-as-inner", + "futures-channel", + "futures-io", + "futures-util", + "idna 0.4.0", + "ipnet", + "once_cell", + "rand", + "socket2 0.5.7", + "thiserror", + "tinyvec", + "tokio", + "tracing", + "url", +] + +[[package]] +name = "hickory-resolver" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28757f23aa75c98f254cf0405e6d8c25b831b32921b050a66692427679b1f243" +dependencies = [ + "cfg-if", + "futures-util", + "hickory-proto", + "ipconfig", + "lru-cache", + "once_cell", + "parking_lot", + "rand", + "resolv-conf", + "smallvec", + "thiserror", + "tokio", + "tracing", +] + [[package]] name = "hkdf" version = "0.12.4" @@ -835,6 +1367,85 @@ dependencies = [ "digest", ] +[[package]] +name = "hostname" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c731c3e10504cc8ed35cfe2f1db4c9274c3d35fa486e3b31df46f068ef3e867" +dependencies = [ + "libc", + "match_cfg", + "winapi", +] + +[[package]] +name = "http" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" +dependencies = [ + "bytes", + "http", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fcc0b4a115bf80b728eb8ea024ad5bd707b615bfed49e0665b6e0f86fd082d9" + +[[package]] +name = "httpdate" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" + +[[package]] +name = "hyper" +version = "0.14.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a152ddd61dfaec7273fe8419ab357f33aee0d914c5f4efbf0d96fa749eea5ec9" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2 0.5.7", + "tokio", + "tower-service", + "tracing", + "want", +] + +[[package]] +name = "idna" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + [[package]] name = "idna" version = "0.5.0" @@ -845,6 +1456,55 @@ dependencies = [ "unicode-normalization", ] +[[package]] +name = "if-addrs" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cabb0019d51a643781ff15c9c8a3e5dedc365c47211270f4e8f82812fedd8f0a" +dependencies = [ + "libc", + "windows-sys 0.48.0", +] + +[[package]] +name = "if-watch" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6b0422c86d7ce0e97169cc42e04ae643caf278874a7a3c87b8150a220dc7e1e" +dependencies = [ + "async-io 2.3.3", + "core-foundation", + "fnv", + "futures", + "if-addrs", + "ipnet", + "log", + "rtnetlink", + "smol", + "system-configuration", + "tokio", + "windows", +] + +[[package]] +name = "igd-next" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "064d90fec10d541084e7b39ead8875a5a80d9114a2b18791565253bae25f49e4" +dependencies = [ + "async-trait", + "attohttpc", + "bytes", + "futures", + "http", + "hyper", + "log", + "rand", + "tokio", + "url", + "xmltree", +] + [[package]] name = "indexmap" version = "2.3.0" @@ -855,6 +1515,15 @@ dependencies = [ "hashbrown", ] +[[package]] +name = "inout" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +dependencies = [ + "generic-array", +] + [[package]] name = "instant" version = "0.1.13" @@ -875,6 +1544,24 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "ipconfig" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b58db92f96b720de98181bbbe63c831e87005ab460c1bf306eb2622b4707997f" +dependencies = [ + "socket2 0.5.7", + "widestring", + "windows-sys 0.48.0", + "winreg", +] + +[[package]] +name = "ipnet" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" + [[package]] name = "itertools" version = "0.12.1" @@ -884,6 +1571,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" + [[package]] name = "js-sys" version = "0.3.69" @@ -908,7 +1601,7 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" dependencies = [ - "spin", + "spin 0.9.8", ] [[package]] @@ -937,9 +1630,21 @@ dependencies = [ "instant", "libp2p-allow-block-list", "libp2p-connection-limits", - "libp2p-core", + "libp2p-core 0.41.3", + "libp2p-dns", + "libp2p-gossipsub 0.46.1", + "libp2p-identify 0.44.2", "libp2p-identity", - "libp2p-swarm", + "libp2p-mdns", + "libp2p-metrics", + "libp2p-noise", + "libp2p-ping 0.44.1", + "libp2p-quic", + "libp2p-rendezvous", + "libp2p-swarm 0.44.2", + "libp2p-tcp", + "libp2p-upnp", + "libp2p-yamux", "multiaddr", "pin-project", "rw-stream-sink", @@ -952,9 +1657,9 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "107b238b794cb83ab53b74ad5dcf7cca3200899b72fe662840cfb52f5b0a32e6" dependencies = [ - "libp2p-core", + "libp2p-core 0.41.3", "libp2p-identity", - "libp2p-swarm", + "libp2p-swarm 0.44.2", "void", ] @@ -964,9 +1669,9 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c7cd50a78ccfada14de94cbacd3ce4b0138157f376870f13d3a8422cd075b4fd" dependencies = [ - "libp2p-core", + "libp2p-core 0.41.3", "libp2p-identity", - "libp2p-swarm", + "libp2p-swarm 0.44.2", "void", ] @@ -999,54 +1704,490 @@ dependencies = [ ] [[package]] -name = "libp2p-identity" -version = "0.2.9" +name = "libp2p-core" +version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55cca1eb2bc1fd29f099f3daaab7effd01e1a54b7c577d0ed082521034d912e8" +checksum = "a61f26c83ed111104cd820fe9bc3aaabbac5f1652a1d213ed6e900b7918a1298" dependencies = [ - "bs58", - "ed25519-dalek", - "hkdf", + "either", + "fnv", + "futures", + "futures-timer", + "libp2p-identity", + "multiaddr", "multihash", + "multistream-select", + "once_cell", + "parking_lot", + "pin-project", "quick-protobuf", "rand", - "sha2", + "rw-stream-sink", + "smallvec", "thiserror", "tracing", - "zeroize", + "unsigned-varint 0.8.0", + "void", + "web-time", ] [[package]] -name = "libp2p-swarm" -version = "0.44.2" +name = "libp2p-dns" +version = "0.41.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80cae6cb75f89dbca53862f9ebe0b9f463aa7b302762fcfaafb9e51dcc9b0f7e" +checksum = "d17cbcf7160ff35c3e8e560de4a068fe9d6cb777ea72840e48eb76ff9576c4b6" +dependencies = [ + "async-std-resolver", + "async-trait", + "futures", + "hickory-resolver", + "libp2p-core 0.41.3", + "libp2p-identity", + "parking_lot", + "smallvec", + "tracing", +] + +[[package]] +name = "libp2p-gossipsub" +version = "0.46.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d665144a616dadebdc5fff186b1233488cdcd8bfb1223218ff084b6d052c94f7" dependencies = [ + "asynchronous-codec 0.7.0", + "base64 0.21.7", + "byteorder", + "bytes", "either", "fnv", "futures", - "futures-timer", + "futures-ticker", + "getrandom", + "hex_fmt", "instant", - "libp2p-core", + "libp2p-core 0.41.3", "libp2p-identity", - "lru", - "multistream-select", - "once_cell", + "libp2p-swarm 0.44.2", + "prometheus-client", + "quick-protobuf", + "quick-protobuf-codec 0.3.1", "rand", + "regex", + "sha2", "smallvec", "tracing", "void", ] [[package]] -name = "linux-raw-sys" -version = "0.3.8" +name = "libp2p-gossipsub" +version = "0.47.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" +checksum = "b4e830fdf24ac8c444c12415903174d506e1e077fbe3875c404a78c5935a8543" +dependencies = [ + "asynchronous-codec 0.7.0", + "base64 0.22.1", + "byteorder", + "bytes", + "either", + "fnv", + "futures", + "futures-ticker", + "getrandom", + "hex_fmt", + "libp2p-core 0.42.0", + "libp2p-identity", + "libp2p-swarm 0.45.1", + "prometheus-client", + "quick-protobuf", + "quick-protobuf-codec 0.3.1", + "rand", + "regex", + "sha2", + "smallvec", + "tracing", + "void", + "web-time", +] [[package]] -name = "linux-raw-sys" -version = "0.4.14" +name = "libp2p-identify" +version = "0.44.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5d635ebea5ca0c3c3e77d414ae9b67eccf2a822be06091b9c1a0d13029a1e2f" +dependencies = [ + "asynchronous-codec 0.7.0", + "either", + "futures", + "futures-bounded", + "futures-timer", + "libp2p-core 0.41.3", + "libp2p-identity", + "libp2p-swarm 0.44.2", + "lru", + "quick-protobuf", + "quick-protobuf-codec 0.3.1", + "smallvec", + "thiserror", + "tracing", + "void", +] + +[[package]] +name = "libp2p-identify" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1711b004a273be4f30202778856368683bd9a83c4c7dcc8f848847606831a4e3" +dependencies = [ + "asynchronous-codec 0.7.0", + "either", + "futures", + "futures-bounded", + "futures-timer", + "libp2p-core 0.42.0", + "libp2p-identity", + "libp2p-swarm 0.45.1", + "lru", + "quick-protobuf", + "quick-protobuf-codec 0.3.1", + "smallvec", + "thiserror", + "tracing", + "void", +] + +[[package]] +name = "libp2p-identity" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55cca1eb2bc1fd29f099f3daaab7effd01e1a54b7c577d0ed082521034d912e8" +dependencies = [ + "bs58", + "ed25519-dalek", + "hkdf", + "multihash", + "quick-protobuf", + "rand", + "sha2", + "thiserror", + "tracing", + "zeroize", +] + +[[package]] +name = "libp2p-mdns" +version = "0.45.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49007d9a339b3e1d7eeebc4d67c05dbf23d300b7d091193ec2d3f26802d7faf2" +dependencies = [ + "async-io 2.3.3", + "async-std", + "data-encoding", + "futures", + "hickory-proto", + "if-watch", + "libp2p-core 0.41.3", + "libp2p-identity", + "libp2p-swarm 0.44.2", + "rand", + "smallvec", + "socket2 0.5.7", + "tokio", + "tracing", + "void", +] + +[[package]] +name = "libp2p-metrics" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a70afa7692c81ee03e89c40d1e8638d634f18baef6aeeea30fd245edfae4d3fd" +dependencies = [ + "futures", + "libp2p-core 0.42.0", + "libp2p-gossipsub 0.47.0", + "libp2p-identify 0.45.0", + "libp2p-identity", + "libp2p-ping 0.45.0", + "libp2p-swarm 0.45.1", + "pin-project", + "prometheus-client", + "web-time", +] + +[[package]] +name = "libp2p-noise" +version = "0.44.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecd0545ce077f6ea5434bcb76e8d0fe942693b4380aaad0d34a358c2bd05793" +dependencies = [ + "asynchronous-codec 0.7.0", + "bytes", + "curve25519-dalek", + "futures", + "libp2p-core 0.41.3", + "libp2p-identity", + "multiaddr", + "multihash", + "once_cell", + "quick-protobuf", + "rand", + "sha2", + "snow", + "static_assertions", + "thiserror", + "tracing", + "x25519-dalek", + "zeroize", +] + +[[package]] +name = "libp2p-ping" +version = "0.44.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1de5a6cf64fba7f7e8f2102711c9c6c043a8e56b86db8cd306492c517da3fb3" +dependencies = [ + "either", + "futures", + "futures-timer", + "instant", + "libp2p-core 0.41.3", + "libp2p-identity", + "libp2p-swarm 0.44.2", + "rand", + "tracing", + "void", +] + +[[package]] +name = "libp2p-ping" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "005a34420359223b974ee344457095f027e51346e992d1e0dcd35173f4cdd422" +dependencies = [ + "either", + "futures", + "futures-timer", + "libp2p-core 0.42.0", + "libp2p-identity", + "libp2p-swarm 0.45.1", + "rand", + "tracing", + "void", + "web-time", +] + +[[package]] +name = "libp2p-quic" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c67296ad4e092e23f92aea3d2bdb6f24eab79c0929ed816dfb460ea2f4567d2b" +dependencies = [ + "async-std", + "bytes", + "futures", + "futures-timer", + "if-watch", + "libp2p-core 0.41.3", + "libp2p-identity", + "libp2p-tls", + "parking_lot", + "quinn", + "rand", + "ring 0.17.8", + "rustls", + "socket2 0.5.7", + "thiserror", + "tokio", + "tracing", +] + +[[package]] +name = "libp2p-rendezvous" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "168a444a16f569771bcb48aa081a32724079156e64a730dd900276391ccb6385" +dependencies = [ + "async-trait", + "asynchronous-codec 0.6.2", + "bimap", + "futures", + "futures-timer", + "instant", + "libp2p-core 0.41.3", + "libp2p-identity", + "libp2p-request-response", + "libp2p-swarm 0.44.2", + "quick-protobuf", + "quick-protobuf-codec 0.2.0", + "rand", + "thiserror", + "tracing", + "void", +] + +[[package]] +name = "libp2p-request-response" +version = "0.26.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c314fe28368da5e3a262553fb0ad575c1c8934c461e10de10265551478163836" +dependencies = [ + "async-trait", + "futures", + "futures-bounded", + "futures-timer", + "instant", + "libp2p-core 0.41.3", + "libp2p-identity", + "libp2p-swarm 0.44.2", + "rand", + "smallvec", + "tracing", + "void", +] + +[[package]] +name = "libp2p-swarm" +version = "0.44.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80cae6cb75f89dbca53862f9ebe0b9f463aa7b302762fcfaafb9e51dcc9b0f7e" +dependencies = [ + "async-std", + "either", + "fnv", + "futures", + "futures-timer", + "instant", + "libp2p-core 0.41.3", + "libp2p-identity", + "libp2p-swarm-derive", + "lru", + "multistream-select", + "once_cell", + "rand", + "smallvec", + "tokio", + "tracing", + "void", +] + +[[package]] +name = "libp2p-swarm" +version = "0.45.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7dd6741793d2c1fb2088f67f82cf07261f25272ebe3c0b0c311e0c6b50e851a" +dependencies = [ + "either", + "fnv", + "futures", + "futures-timer", + "libp2p-core 0.42.0", + "libp2p-identity", + "lru", + "multistream-select", + "once_cell", + "rand", + "smallvec", + "tracing", + "void", + "web-time", +] + +[[package]] +name = "libp2p-swarm-derive" +version = "0.34.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5daceb9dd908417b6dfcfe8e94098bc4aac54500c282e78120b885dadc09b999" +dependencies = [ + "heck 0.5.0", + "proc-macro2", + "quote", + "syn 2.0.72", +] + +[[package]] +name = "libp2p-tcp" +version = "0.41.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b2460fc2748919adff99ecbc1aab296e4579e41f374fb164149bd2c9e529d4c" +dependencies = [ + "async-io 1.13.0", + "futures", + "futures-timer", + "if-watch", + "libc", + "libp2p-core 0.41.3", + "libp2p-identity", + "socket2 0.5.7", + "tokio", + "tracing", +] + +[[package]] +name = "libp2p-tls" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b7b831e55ce2aa6c354e6861a85fdd4dd0a2b97d5e276fabac0e4810a71776" +dependencies = [ + "futures", + "futures-rustls", + "libp2p-core 0.41.3", + "libp2p-identity", + "rcgen", + "ring 0.17.8", + "rustls", + "rustls-webpki 0.101.7", + "thiserror", + "x509-parser", + "yasna", +] + +[[package]] +name = "libp2p-upnp" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccf04b0e3ff3de52d07d5fd6c3b061d0e7f908ffc683c32d9638caedce86fc8" +dependencies = [ + "futures", + "futures-timer", + "igd-next", + "libp2p-core 0.41.3", + "libp2p-swarm 0.44.2", + "tokio", + "tracing", + "void", +] + +[[package]] +name = "libp2p-yamux" +version = "0.45.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddd5265f6b80f94d48a3963541aad183cc598a645755d2f1805a373e41e0716b" +dependencies = [ + "either", + "futures", + "libp2p-core 0.41.3", + "thiserror", + "tracing", + "yamux 0.12.1", + "yamux 0.13.3", +] + +[[package]] +name = "linked-hash-map" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" + +[[package]] +name = "linux-raw-sys" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" + +[[package]] +name = "linux-raw-sys" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" @@ -1078,6 +2219,30 @@ dependencies = [ "hashbrown", ] +[[package]] +name = "lru-cache" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31e24f1ad8321ca0e8a1e0ac13f23cb668e6f5466c2c57319f6a5cf1cc8e3b1c" +dependencies = [ + "linked-hash-map", +] + +[[package]] +name = "match_cfg" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4" + +[[package]] +name = "matchers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" +dependencies = [ + "regex-automata 0.1.10", +] + [[package]] name = "matrixmultiply" version = "0.3.9" @@ -1094,6 +2259,33 @@ version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "miniz_oxide" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" +dependencies = [ + "adler", +] + +[[package]] +name = "mio" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" +dependencies = [ + "hermit-abi 0.3.9", + "libc", + "wasi", + "windows-sys 0.52.0", +] + [[package]] name = "multiaddr" version = "0.18.1" @@ -1125,46 +2317,150 @@ dependencies = [ ] [[package]] -name = "multihash" -version = "0.19.1" +name = "multihash" +version = "0.19.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "076d548d76a0e2a0d4ab471d0b1c36c577786dfc4471242035d97a12a735c492" +dependencies = [ + "core2", + "unsigned-varint 0.7.2", +] + +[[package]] +name = "multimap" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "defc4c55412d89136f966bbb339008b474350e5e6e78d2714439c386b3137a03" + +[[package]] +name = "multistream-select" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea0df8e5eec2298a62b326ee4f0d7fe1a6b90a09dfcf9df37b38f947a8c42f19" +dependencies = [ + "bytes", + "futures", + "log", + "pin-project", + "smallvec", + "unsigned-varint 0.7.2", +] + +[[package]] +name = "ndarray" +version = "0.15.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adb12d4e967ec485a5f71c6311fe28158e9d6f4bc4a447b474184d0f91a8fa32" +dependencies = [ + "matrixmultiply", + "num-complex", + "num-integer", + "num-traits", + "rawpointer", +] + +[[package]] +name = "netlink-packet-core" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "345b8ab5bd4e71a2986663e88c56856699d060e78e152e6e9d7966fcd5491297" +dependencies = [ + "anyhow", + "byteorder", + "libc", + "netlink-packet-utils", +] + +[[package]] +name = "netlink-packet-route" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9ea4302b9759a7a88242299225ea3688e63c85ea136371bb6cf94fd674efaab" +dependencies = [ + "anyhow", + "bitflags 1.3.2", + "byteorder", + "libc", + "netlink-packet-core", + "netlink-packet-utils", +] + +[[package]] +name = "netlink-packet-utils" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ede8a08c71ad5a95cdd0e4e52facd37190977039a4704eb82a283f713747d34" +dependencies = [ + "anyhow", + "byteorder", + "paste", + "thiserror", +] + +[[package]] +name = "netlink-proto" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65b4b14489ab424703c092062176d52ba55485a89c076b4f9db05092b7223aa6" +dependencies = [ + "bytes", + "futures", + "log", + "netlink-packet-core", + "netlink-sys", + "thiserror", + "tokio", +] + +[[package]] +name = "netlink-sys" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "416060d346fbaf1f23f9512963e3e878f1a78e707cb699ba9215761754244307" +dependencies = [ + "async-io 1.13.0", + "bytes", + "futures", + "libc", + "log", + "tokio", +] + +[[package]] +name = "nix" +version = "0.24.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "076d548d76a0e2a0d4ab471d0b1c36c577786dfc4471242035d97a12a735c492" +checksum = "fa52e972a9a719cecb6864fb88568781eb706bac2cd1d4f04a648542dbf78069" dependencies = [ - "core2", - "unsigned-varint 0.7.2", + "bitflags 1.3.2", + "cfg-if", + "libc", ] [[package]] -name = "multimap" -version = "0.10.0" +name = "nohash-hasher" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "defc4c55412d89136f966bbb339008b474350e5e6e78d2714439c386b3137a03" +checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451" [[package]] -name = "multistream-select" -version = "0.13.0" +name = "nom" +version = "7.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea0df8e5eec2298a62b326ee4f0d7fe1a6b90a09dfcf9df37b38f947a8c42f19" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" dependencies = [ - "bytes", - "futures", - "log", - "pin-project", - "smallvec", - "unsigned-varint 0.7.2", + "memchr", + "minimal-lexical", ] [[package]] -name = "ndarray" -version = "0.15.6" +name = "nu-ansi-term" +version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adb12d4e967ec485a5f71c6311fe28158e9d6f4bc4a447b474184d0f91a8fa32" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" dependencies = [ - "matrixmultiply", - "num-complex", - "num-integer", - "num-traits", - "rawpointer", + "overload", + "winapi", ] [[package]] @@ -1203,6 +2499,12 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + [[package]] name = "num-integer" version = "0.1.46" @@ -1242,12 +2544,59 @@ dependencies = [ "libc", ] +[[package]] +name = "object" +version = "0.36.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27b64972346851a39438c60b341ebc01bba47464ae329e55cf343eb93964efd9" +dependencies = [ + "memchr", +] + +[[package]] +name = "oid-registry" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c958dd45046245b9c3c2547369bb634eb461670b2e7e0de552905801a648d1d" +dependencies = [ + "asn1-rs", +] + [[package]] name = "once_cell" version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +[[package]] +name = "opaque-debug" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" + +[[package]] +name = "overload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" + +[[package]] +name = "p2p" +version = "0.1.0" +dependencies = [ + "async-std", + "async-trait", + "bfv", + "fhe", + "fhe-traits", + "fhe-util", + "futures", + "libp2p", + "tokio", + "tracing", + "tracing-subscriber", +] + [[package]] name = "parking" version = "2.2.0" @@ -1277,6 +2626,22 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "pem" +version = "3.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e459365e590736a54c3fa561947c84837534b8e9af6fc5bf781307e82658fae" +dependencies = [ + "base64 0.22.1", + "serde", +] + [[package]] name = "percent-encoding" version = "2.3.1" @@ -1377,6 +2742,35 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "poly1305" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8159bd90725d2df49889a078b54f4f79e87f1f8a8444194cdca81d38f5393abf" +dependencies = [ + "cpufeatures", + "opaque-debug", + "universal-hash", +] + +[[package]] +name = "polyval" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25" +dependencies = [ + "cfg-if", + "cpufeatures", + "opaque-debug", + "universal-hash", +] + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + [[package]] name = "ppv-lite86" version = "0.2.20" @@ -1405,6 +2799,29 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "prometheus-client" +version = "0.22.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "504ee9ff529add891127c4827eb481bd69dc0ebc72e9a682e187db4caa60c3ca" +dependencies = [ + "dtoa", + "itoa", + "parking_lot", + "prometheus-client-derive-encode", +] + +[[package]] +name = "prometheus-client-derive-encode" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "440f724eba9f6996b75d63681b0a92b06947f1457076d503a4d2e2c8f56442b8" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.72", +] + [[package]] name = "prost" version = "0.12.6" @@ -1422,7 +2839,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22505a5c94da8e3b7c2996394d1c933236c4d743e81a410bcca4e6989fc066a4" dependencies = [ "bytes", - "heck", + "heck 0.5.0", "itertools", "log", "multimap", @@ -1458,6 +2875,12 @@ dependencies = [ "prost", ] +[[package]] +name = "quick-error" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" + [[package]] name = "quick-protobuf" version = "0.8.1" @@ -1467,6 +2890,83 @@ dependencies = [ "byteorder", ] +[[package]] +name = "quick-protobuf-codec" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8ededb1cd78531627244d51dd0c7139fbe736c7d57af0092a76f0ffb2f56e98" +dependencies = [ + "asynchronous-codec 0.6.2", + "bytes", + "quick-protobuf", + "thiserror", + "unsigned-varint 0.7.2", +] + +[[package]] +name = "quick-protobuf-codec" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15a0580ab32b169745d7a39db2ba969226ca16738931be152a3209b409de2474" +dependencies = [ + "asynchronous-codec 0.7.0", + "bytes", + "quick-protobuf", + "thiserror", + "unsigned-varint 0.8.0", +] + +[[package]] +name = "quinn" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b22d8e7369034b9a7132bc2008cac12f2013c8132b45e0554e6e20e2617f2156" +dependencies = [ + "async-io 2.3.3", + "async-std", + "bytes", + "futures-io", + "pin-project-lite", + "quinn-proto", + "quinn-udp", + "rustc-hash", + "rustls", + "socket2 0.5.7", + "thiserror", + "tokio", + "tracing", +] + +[[package]] +name = "quinn-proto" +version = "0.11.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba92fb39ec7ad06ca2582c0ca834dfeadcaf06ddfc8e635c80aa7e1c05315fdd" +dependencies = [ + "bytes", + "rand", + "ring 0.17.8", + "rustc-hash", + "rustls", + "slab", + "thiserror", + "tinyvec", + "tracing", +] + +[[package]] +name = "quinn-udp" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8bffec3605b73c6f1754535084a85229fa8a30f86014e6c81aeec4abb68b0285" +dependencies = [ + "libc", + "once_cell", + "socket2 0.5.7", + "tracing", + "windows-sys 0.52.0", +] + [[package]] name = "quote" version = "1.0.36" @@ -1512,6 +3012,18 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3" +[[package]] +name = "rcgen" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52c4f3084aa3bc7dfbba4eff4fab2a54db4324965d8872ab933565e6fbd83bc6" +dependencies = [ + "pem", + "ring 0.16.20", + "time", + "yasna", +] + [[package]] name = "redox_syscall" version = "0.5.3" @@ -1529,8 +3041,17 @@ checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" dependencies = [ "aho-corasick", "memchr", - "regex-automata", - "regex-syntax", + "regex-automata 0.4.7", + "regex-syntax 0.8.4", +] + +[[package]] +name = "regex-automata" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" +dependencies = [ + "regex-syntax 0.6.29", ] [[package]] @@ -1541,15 +3062,89 @@ checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" dependencies = [ "aho-corasick", "memchr", - "regex-syntax", + "regex-syntax 0.8.4", ] +[[package]] +name = "regex-syntax" +version = "0.6.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" + [[package]] name = "regex-syntax" version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" +[[package]] +name = "resolv-conf" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52e44394d2086d010551b14b53b1f24e31647570cd1deb0379e2c21b329aba00" +dependencies = [ + "hostname", + "quick-error", +] + +[[package]] +name = "ring" +version = "0.16.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" +dependencies = [ + "cc", + "libc", + "once_cell", + "spin 0.5.2", + "untrusted 0.7.1", + "web-sys", + "winapi", +] + +[[package]] +name = "ring" +version = "0.17.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" +dependencies = [ + "cc", + "cfg-if", + "getrandom", + "libc", + "spin 0.9.8", + "untrusted 0.9.0", + "windows-sys 0.52.0", +] + +[[package]] +name = "rtnetlink" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "322c53fd76a18698f1c27381d58091de3a043d356aa5bd0d510608b565f469a0" +dependencies = [ + "async-global-executor", + "futures", + "log", + "netlink-packet-route", + "netlink-proto", + "nix", + "thiserror", + "tokio", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" + +[[package]] +name = "rustc-hash" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152" + [[package]] name = "rustc_version" version = "0.4.0" @@ -1559,6 +3154,15 @@ dependencies = [ "semver", ] +[[package]] +name = "rusticata-macros" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "faf0c4a6ece9950b9abdb62b1cfcf2a68b3b67a10ba445b3bb85be2a293d0632" +dependencies = [ + "nom", +] + [[package]] name = "rustix" version = "0.37.27" @@ -1586,6 +3190,47 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "rustls" +version = "0.23.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c58f8c84392efc0a126acce10fa59ff7b3d2ac06ab451a33f2741989b806b044" +dependencies = [ + "once_cell", + "ring 0.17.8", + "rustls-pki-types", + "rustls-webpki 0.102.6", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-pki-types" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc0a2ce646f8655401bb81e7927b812614bd5d91dbc968696be50603510fcaf0" + +[[package]] +name = "rustls-webpki" +version = "0.101.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" +dependencies = [ + "ring 0.17.8", + "untrusted 0.9.0", +] + +[[package]] +name = "rustls-webpki" +version = "0.102.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e6b52d4fda176fd835fdc55a835d4a89b8499cad995885a21149d5ad62f852e" +dependencies = [ + "ring 0.17.8", + "rustls-pki-types", + "untrusted 0.9.0", +] + [[package]] name = "rw-stream-sink" version = "0.4.0" @@ -1630,14 +3275,32 @@ dependencies = [ ] [[package]] -name = "sha2" -version = "0.10.8" +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "signal-hook-registry" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" dependencies = [ - "cfg-if", - "cpufeatures", - "digest", + "libc", ] [[package]] @@ -1664,6 +3327,40 @@ version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" +[[package]] +name = "smol" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13f2b548cd8447f8de0fdf1c592929f70f4fc7039a05e47404b0d096ec6987a1" +dependencies = [ + "async-channel 1.9.0", + "async-executor", + "async-fs", + "async-io 1.13.0", + "async-lock 2.8.0", + "async-net", + "async-process", + "blocking", + "futures-lite 1.13.0", +] + +[[package]] +name = "snow" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "850948bee068e713b8ab860fe1adc4d109676ab4c3b621fd8147f06b261f2f85" +dependencies = [ + "aes-gcm", + "blake2", + "chacha20poly1305", + "curve25519-dalek", + "rand_core", + "ring 0.17.8", + "rustc_version", + "sha2", + "subtle", +] + [[package]] name = "socket2" version = "0.4.10" @@ -1674,6 +3371,22 @@ dependencies = [ "winapi", ] +[[package]] +name = "socket2" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "spin" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" + [[package]] name = "spin" version = "0.9.8" @@ -1724,6 +3437,38 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "synstructure" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.72", +] + +[[package]] +name = "system-configuration" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "system-configuration-sys", +] + +[[package]] +name = "system-configuration-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "tempfile" version = "3.11.0" @@ -1757,6 +3502,47 @@ dependencies = [ "syn 2.0.72", ] +[[package]] +name = "thread_local" +version = "1.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" +dependencies = [ + "cfg-if", + "once_cell", +] + +[[package]] +name = "time" +version = "0.3.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" +dependencies = [ + "deranged", + "itoa", + "num-conv", + "powerfmt", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" + +[[package]] +name = "time-macros" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" +dependencies = [ + "num-conv", + "time-core", +] + [[package]] name = "tinyvec" version = "1.8.0" @@ -1772,6 +3558,54 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" +[[package]] +name = "tokio" +version = "1.39.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daa4fb1bc778bd6f04cbfc4bb2d06a7396a8f299dc33ea1900cedaa316f467b1" +dependencies = [ + "backtrace", + "bytes", + "libc", + "mio", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "socket2 0.5.7", + "tokio-macros", + "windows-sys 0.52.0", +] + +[[package]] +name = "tokio-macros" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.72", +] + +[[package]] +name = "tokio-util" +version = "0.7.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tower-service" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" + [[package]] name = "tracing" version = "0.1.40" @@ -1801,8 +3635,44 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" dependencies = [ "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" +dependencies = [ + "matchers", + "nu-ansi-term", + "once_cell", + "regex", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", ] +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + [[package]] name = "typenum" version = "1.17.0" @@ -1830,11 +3700,25 @@ dependencies = [ "tinyvec", ] +[[package]] +name = "universal-hash" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" +dependencies = [ + "crypto-common", + "subtle", +] + [[package]] name = "unsigned-varint" version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6889a77d49f1f013504cec6bf97a2c730394adedaeb1deb5ea08949a50541105" +dependencies = [ + "asynchronous-codec 0.6.2", + "bytes", +] [[package]] name = "unsigned-varint" @@ -1842,6 +3726,18 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eb066959b24b5196ae73cb057f45598450d2c5f71460e98c49b738086eff9c06" +[[package]] +name = "untrusted" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + [[package]] name = "url" version = "2.5.2" @@ -1849,10 +3745,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" dependencies = [ "form_urlencoded", - "idna", + "idna 0.5.0", "percent-encoding", ] +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + [[package]] name = "value-bag" version = "1.9.0" @@ -1877,6 +3779,15 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "317211a0dc0ceedd78fb2ca9a44aed3d7b9b26f81870d485c07122b4350673b7" +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" @@ -1969,6 +3880,12 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "widestring" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7219d36b6eac893fa81e84ebe06485e7dcbb616177469b142df14f1f4deb1311" + [[package]] name = "winapi" version = "0.3.9" @@ -1991,6 +3908,25 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows" +version = "0.51.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca229916c5ee38c2f2bc1e9d8f04df975b4bd93f9955dc69fabb5d91270045c9" +dependencies = [ + "windows-core", + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-core" +version = "0.51.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1f8cf84f35d2db49a46868f947758c7a1138116f7fac3bc844f43ade1292e64" +dependencies = [ + "windows-targets 0.48.5", +] + [[package]] name = "windows-sys" version = "0.48.0" @@ -2009,6 +3945,15 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", +] + [[package]] name = "windows-targets" version = "0.48.5" @@ -2130,6 +4075,100 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +[[package]] +name = "winreg" +version = "0.50.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" +dependencies = [ + "cfg-if", + "windows-sys 0.48.0", +] + +[[package]] +name = "x25519-dalek" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7e468321c81fb07fa7f4c636c3972b9100f0346e5b6a9f2bd0603a52f7ed277" +dependencies = [ + "curve25519-dalek", + "rand_core", + "serde", + "zeroize", +] + +[[package]] +name = "x509-parser" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcbc162f30700d6f3f82a24bf7cc62ffe7caea42c0b2cba8bf7f3ae50cf51f69" +dependencies = [ + "asn1-rs", + "data-encoding", + "der-parser", + "lazy_static", + "nom", + "oid-registry", + "rusticata-macros", + "thiserror", + "time", +] + +[[package]] +name = "xml-rs" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "539a77ee7c0de333dcc6da69b177380a0b81e0dacfa4f7344c465a36871ee601" + +[[package]] +name = "xmltree" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7d8a75eaf6557bb84a65ace8609883db44a29951042ada9b393151532e41fcb" +dependencies = [ + "xml-rs", +] + +[[package]] +name = "yamux" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed0164ae619f2dc144909a9f082187ebb5893693d8c0196e8085283ccd4b776" +dependencies = [ + "futures", + "log", + "nohash-hasher", + "parking_lot", + "pin-project", + "rand", + "static_assertions", +] + +[[package]] +name = "yamux" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a31b5e376a8b012bee9c423acdbb835fc34d45001cfa3106236a624e4b738028" +dependencies = [ + "futures", + "log", + "nohash-hasher", + "parking_lot", + "pin-project", + "rand", + "static_assertions", + "web-time", +] + +[[package]] +name = "yasna" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e17bb3549cc1321ae1296b9cdc2698e2b6cb1992adfa19a8c72e5b7a738f44cd" +dependencies = [ + "time", +] + [[package]] name = "zerocopy" version = "0.7.35" @@ -2156,6 +4195,9 @@ name = "zeroize" version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" +dependencies = [ + "zeroize_derive", +] [[package]] name = "zeroize_derive" diff --git a/packages/ciphernode/Cargo.toml b/packages/ciphernode/Cargo.toml index e84fdc9c..ffd71233 100644 --- a/packages/ciphernode/Cargo.toml +++ b/packages/ciphernode/Cargo.toml @@ -1,2 +1,2 @@ [workspace] -members = ["core", "eth", "enclave", "enclave_node"] +members = ["core", "eth", "enclave", "enclave_node", "p2p"] diff --git a/packages/ciphernode/bfv/Cargo.toml b/packages/ciphernode/bfv/Cargo.toml index 2f53f5d2..2426bd01 100644 --- a/packages/ciphernode/bfv/Cargo.toml +++ b/packages/ciphernode/bfv/Cargo.toml @@ -12,3 +12,4 @@ async-std = "1.12.0" fhe = { git = "https://github.com/gnosisguild/fhe.rs", version = "0.1.0-beta.7" } fhe-traits = { git = "https://github.com/gnosisguild/fhe.rs", version = "0.1.0-beta.7" } fhe-util = { git = "https://github.com/gnosisguild/fhe.rs", version = "0.1.0-beta.7" } +rand = "0.8.5" diff --git a/packages/ciphernode/bfv/src/lib.rs b/packages/ciphernode/bfv/src/lib.rs new file mode 100644 index 00000000..af3a0447 --- /dev/null +++ b/packages/ciphernode/bfv/src/lib.rs @@ -0,0 +1,46 @@ +#![crate_name = "bfv"] +#![crate_type = "lib"] +#![warn(missing_docs, unused_imports)] + +mod util; + +use fhe::{ + bfv::{BfvParametersBuilder, Ciphertext, Encoding, Plaintext, SecretKey}, + mbfv::{AggregateIter, CommonRandomPoly, DecryptionShare, PublicKeyShare}, +}; +use fhe_traits::{FheDecoder, Serialize as FheSerialize, DeserializeParametrized}; +use rand::{Rng, rngs::OsRng, thread_rng}; +use util::timeit::{timeit}; + +pub struct EnclaveBFV { + pub address: String, + pub pk_share: Vec, +} + +impl EnclaveBFV { + pub fn new(address: String) -> Self { + let degree = 4096; + let plaintext_modulus: u64 = 4096; + let moduli = vec![0xffffee001, 0xffffc4001, 0x1ffffe0001]; + + // Generate the BFV parameters structure. + let params = timeit!( + "Parameters generation", + BfvParametersBuilder::new() + .set_degree(degree) + .set_plaintext_modulus(plaintext_modulus) + .set_moduli(&moduli) + .build_arc().unwrap() + ); + + let crp = CommonRandomPoly::new(¶ms, &mut thread_rng()).unwrap(); + //let crp_bytes = crp.to_bytes(); + let sk_share_1 = SecretKey::random(¶ms, &mut OsRng); + let pk_share_1 = PublicKeyShare::new(&sk_share_1, crp.clone(), &mut thread_rng()).unwrap(); + // serialize pk_share + let pk_share = pk_share_1.to_bytes(); + let sk_share = sk_share_1.coeffs.into_vec(); + + Self { address, pk_share } + } +} \ No newline at end of file diff --git a/packages/ciphernode/bfv/src/main.rs b/packages/ciphernode/bfv/src/main.rs deleted file mode 100644 index a0d9916c..00000000 --- a/packages/ciphernode/bfv/src/main.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn main() { - println!("Hello, cipher world!"); -} diff --git a/packages/ciphernode/bfv/src/util.rs b/packages/ciphernode/bfv/src/util.rs new file mode 100644 index 00000000..8e3d167f --- /dev/null +++ b/packages/ciphernode/bfv/src/util.rs @@ -0,0 +1,129 @@ +//! Utility functions + +use fhe::bfv; +use fhe_traits::FheEncoder; +use fhe_util::transcode_from_bytes; +use std::{cmp::min, fmt, sync::Arc, time::Duration}; + +/// Macros to time code and display a human-readable duration. +pub mod timeit { + #[allow(unused_macros)] + macro_rules! timeit_n { + ($name:expr, $loops:expr, $code:expr) => {{ + use util::DisplayDuration; + let start = std::time::Instant::now(); + let r = $code; + for _ in 1..$loops { + let _ = $code; + } + println!( + "⏱ {}: {}", + $name, + DisplayDuration(start.elapsed() / $loops) + ); + r + }}; + } + + #[allow(unused_macros)] + macro_rules! timeit { + ($name:expr, $code:expr) => {{ + use util::DisplayDuration; + let start = std::time::Instant::now(); + let r = $code; + println!("⏱ {}: {}", $name, DisplayDuration(start.elapsed())); + r + }}; + } + + #[allow(unused_imports)] + pub(crate) use timeit; + #[allow(unused_imports)] + pub(crate) use timeit_n; +} + +/// Utility struct for displaying human-readable duration of the form "10.5 ms", +/// "350 μs", or "27 ns". +pub struct DisplayDuration(pub Duration); + +impl fmt::Display for DisplayDuration { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let duration_ns = self.0.as_nanos(); + if duration_ns < 1_000_u128 { + write!(f, "{duration_ns} ns") + } else if duration_ns < 1_000_000_u128 { + write!(f, "{} μs", (duration_ns + 500) / 1_000) + } else { + let duration_ms_times_10 = (duration_ns + 50_000) / (100_000); + write!(f, "{} ms", (duration_ms_times_10 as f64) / 10.0) + } + } +} + +// Utility functions for Private Information Retrieval. + +/// Generate a database of elements of the form [i || 0...0] where i is the 4B +/// little endian encoding of the index. When the element size is less than 4B, +/// the encoding is truncated. +#[allow(dead_code)] +pub fn generate_database(database_size: usize, elements_size: usize) -> Vec> { + assert!(database_size > 0 && elements_size > 0); + let mut database = vec![vec![0u8; elements_size]; database_size]; + for (i, element) in database.iter_mut().enumerate() { + element[..min(4, elements_size)] + .copy_from_slice(&(i as u32).to_le_bytes()[..min(4, elements_size)]); + } + database +} + +#[allow(dead_code)] +pub fn number_elements_per_plaintext( + degree: usize, + plaintext_nbits: usize, + elements_size: usize, +) -> usize { + (plaintext_nbits * degree) / (elements_size * 8) +} + +#[allow(dead_code)] +pub fn encode_database( + database: &Vec>, + par: Arc, + level: usize, +) -> (Vec, (usize, usize)) { + assert!(!database.is_empty()); + + let elements_size = database[0].len(); + let plaintext_nbits = par.plaintext().ilog2() as usize; + let number_elements_per_plaintext = + number_elements_per_plaintext(par.degree(), plaintext_nbits, elements_size); + let number_rows = + (database.len() + number_elements_per_plaintext - 1) / number_elements_per_plaintext; + println!("number_rows = {number_rows}"); + println!("number_elements_per_plaintext = {number_elements_per_plaintext}"); + let dimension_1 = (number_rows as f64).sqrt().ceil() as usize; + let dimension_2 = (number_rows + dimension_1 - 1) / dimension_1; + println!("dimensions = {dimension_1} {dimension_2}"); + println!("dimension = {}", dimension_1 * dimension_2); + let mut preprocessed_database = + vec![ + bfv::Plaintext::zero(bfv::Encoding::poly_at_level(level), &par).unwrap(); + dimension_1 * dimension_2 + ]; + (0..number_rows).for_each(|i| { + let mut serialized_plaintext = vec![0u8; number_elements_per_plaintext * elements_size]; + for j in 0..number_elements_per_plaintext { + if let Some(pt) = database.get(j + i * number_elements_per_plaintext) { + serialized_plaintext[j * elements_size..(j + 1) * elements_size].copy_from_slice(pt) + } + } + let pt_values = transcode_from_bytes(&serialized_plaintext, plaintext_nbits); + preprocessed_database[i] = + bfv::Plaintext::try_encode(&pt_values, bfv::Encoding::poly_at_level(level), &par) + .unwrap(); + }); + (preprocessed_database, (dimension_1, dimension_2)) +} + +#[allow(dead_code)] +fn main() {} \ No newline at end of file diff --git a/packages/ciphernode/p2p/src/main.rs b/packages/ciphernode/p2p/src/lib.rs similarity index 93% rename from packages/ciphernode/p2p/src/main.rs rename to packages/ciphernode/p2p/src/lib.rs index f6fa9c42..47b75f70 100644 --- a/packages/ciphernode/p2p/src/main.rs +++ b/packages/ciphernode/p2p/src/lib.rs @@ -1,3 +1,7 @@ +#![crate_name = "p2p"] +#![crate_type = "lib"] +#![warn(missing_docs, unused_imports)] + use futures::stream::StreamExt; use libp2p::{gossipsub, mdns, noise, swarm::NetworkBehaviour, swarm::SwarmEvent, tcp, yamux, identity, Swarm}; use std::collections::hash_map::DefaultHasher; @@ -139,14 +143,14 @@ impl EnclaveRouter { } } -#[tokio::main] -async fn main() -> Result<(), Box> { +// #[tokio::main] +// async fn main() -> Result<(), Box> { - let mut p2p = EnclaveRouter::new()?; - p2p.connect_swarm("mdns".to_string())?; - p2p.join_topic("enclave-keygen-01")?; - p2p.start().await?; +// let mut p2p = EnclaveRouter::new()?; +// p2p.connect_swarm("mdns".to_string())?; +// p2p.join_topic("enclave-keygen-01")?; +// p2p.start().await?; - println!("Hello, cipher world!"); - Ok(()) -} +// println!("Hello, cipher world!"); +// Ok(()) +// } From db7064ee681f2d1a7683e2f22ac030986bebb8bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=B3=CE=BB?= Date: Thu, 22 Aug 2024 15:33:17 +1000 Subject: [PATCH 10/87] Get CI Working (#10) * fix linting * Fix lint errors * Add simple github actions file to run rust tests * Update toolchain * Rename tests --- .github/workflows/ci.yml | 2 +- .github/workflows/rust-ci.yml | 26 ++ .vscode/extensions.json | 5 +- LICENSE.md | 328 +++++++++--------- package.json | 3 +- packages/ciphernode/p2p/src/lib.rs | 11 +- .../contracts/test/MockCyphernodeRegistry.sol | 4 +- packages/evm/test/Enclave.spec.ts | 14 +- 8 files changed, 210 insertions(+), 183 deletions(-) create mode 100644 .github/workflows/rust-ci.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b5258e8e..08b7ae17 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,4 +1,4 @@ -name: "CI" +name: "EVM" env: HARDHAT_VAR_MNEMONIC: "test test test test test test test test test test test junk" diff --git a/.github/workflows/rust-ci.yml b/.github/workflows/rust-ci.yml new file mode 100644 index 00000000..b53b3fb3 --- /dev/null +++ b/.github/workflows/rust-ci.yml @@ -0,0 +1,26 @@ +name: Rust + +on: + workflow_dispatch: + pull_request: + push: + branches: + - main + +jobs: + ci: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + + - name: Install latest stable Rust + uses: actions-rs/toolchain@v1 + with: + toolchain: stable + override: true + + - name: Run tests + run: | + cd ./packages/ciphernode/ + cargo test diff --git a/.vscode/extensions.json b/.vscode/extensions.json index 9a51b727..1f6b36b6 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -1,3 +1,6 @@ { - "recommendations": ["esbenp.prettier-vscode", "NomicFoundation.hardhat-solidity"] + "recommendations": [ + "esbenp.prettier-vscode", + "NomicFoundation.hardhat-solidity" + ] } diff --git a/LICENSE.md b/LICENSE.md index f288702d..a5eae152 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,190 +1,190 @@ GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. +Copyright (C) 2007 Free Software Foundation, Inc. +Everyone is permitted to copy and distribute verbatim copies +of this license document, but changing it is not allowed. Preamble - The GNU General Public License is a free, copyleft license for +The GNU General Public License is a free, copyleft license for software and other kinds of works. - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, +The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the +software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to +any other work released this way by its authors. You can apply it to your programs, too. - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you +When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have +To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. - For example, if you distribute copies of such a program, whether +For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they know their rights. - Developers that use the GNU GPL protect your rights with two steps: +Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and +For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. - Some devices are designed to deny users access to install or run +Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we +use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we +products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. - Finally, every program is threatened constantly by software patents. +Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that +make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. - The precise terms and conditions for copying, distribution and +The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS - 0. Definitions. +0. Definitions. - "This License" refers to version 3 of the GNU General Public License. +"This License" refers to version 3 of the GNU General Public License. - "Copyright" also means copyright-like laws that apply to other kinds of +"Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and +"The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. - To "modify" a work means to copy from or adapt all or part of the work +To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the +exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. - A "covered work" means either the unmodified Program or a work based +A "covered work" means either the unmodified Program or a work based on the Program. - To "propagate" a work means to do anything with it that, without +To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, +computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through +To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. - An interactive user interface displays "Appropriate Legal Notices" +An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If +work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. - 1. Source Code. +1. Source Code. - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source +The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source form of a work. - A "Standard Interface" means an interface that either is an official +A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. - The "System Libraries" of an executable work include anything, other +The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A +implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. - The "Corresponding Source" for a work in object code form means all +The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's +control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source +which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. - The Corresponding Source need not include anything that users +The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. - The Corresponding Source for a work in source code form is that +The Corresponding Source for a work in source code form is that same work. - 2. Basic Permissions. +2. Basic Permissions. - All rights granted under this License are granted for the term of +All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your +content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. - You may make, run and propagate covered works that you do not +You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose +in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works +not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 +Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. +3. Protecting Users' Legal Rights From Anti-Circumvention Law. - No covered work shall be deemed part of an effective technological +No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. - When you convey a covered work, you waive any legal power to forbid +When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or @@ -192,9 +192,9 @@ modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. - 4. Conveying Verbatim Copies. +4. Conveying Verbatim Copies. - You may convey verbatim copies of the Program's source code as you +You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any @@ -202,12 +202,12 @@ non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. - You may charge any price or no price for each copy that you convey, +You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. - 5. Conveying Modified Source Versions. +5. Conveying Modified Source Versions. - You may convey a work based on the Program, or the modifications to +You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: @@ -232,19 +232,19 @@ terms of section 4, provided that you also meet all of these conditions: interfaces that do not display Appropriate Legal Notices, your work need not make them do so. - A compilation of a covered work with other separate and independent +A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work +beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. - 6. Conveying Non-Source Forms. +6. Conveying Non-Source Forms. - You may convey a covered work in object code form under the terms +You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: @@ -290,75 +290,75 @@ in one of these ways: Source of the work are being offered to the general public at no charge under subsection 6d. - A separable portion of the object code, whose source code is excluded +A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. - A "User Product" is either (1) a "consumer product", which means any +A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product +actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. - "Installation Information" for a User Product means any methods, +"Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must +a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. - If you convey an object code work under this section in, or with, or +If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply +by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). - The requirement to provide Installation Information does not include a +The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a +the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. - Corresponding Source conveyed, and Installation Information provided, +Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. - 7. Additional Terms. +7. Additional Terms. - "Additional permissions" are terms that supplement the terms of this +"Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions +that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. - When you convey a copy of a covered work, you may at your option +When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. - Notwithstanding any other provision of this License, for material you +Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: @@ -385,74 +385,74 @@ that material) supplement the terms of this License with terms: any liability that these contractual assumptions directly impose on those licensors and authors. - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you +All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains +restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. - If you add terms to a covered work in accord with this section, you +If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. - Additional terms, permissive or non-permissive, may be stated in the +Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. - 8. Termination. +8. Termination. - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or +You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). - However, if you cease all violation of this License, then your +However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. - Moreover, your license from a particular copyright holder is +Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. - Termination of your rights under this section does not terminate the +Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently +this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. - 9. Acceptance Not Required for Having Copies. +9. Acceptance Not Required for Having Copies. - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work +You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, +to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. - 10. Automatic Licensing of Downstream Recipients. +10. Automatic Licensing of Downstream Recipients. - Each time you convey a covered work, the recipient automatically +Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible +propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. - An "entity transaction" is a transaction transferring control of an +An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered +organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could @@ -460,43 +460,43 @@ give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may +You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. - 11. Patents. +11. Patents. - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The +A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". - A contributor's "essential patent claims" are all patent claims +A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For +consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. - Each contributor grants you a non-exclusive, worldwide, royalty-free +Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. - In the following three paragraphs, a "patent license" is any express +In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a +sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. - If you convey a covered work, knowingly relying on a patent license, +If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, @@ -504,13 +504,13 @@ then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have +license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. - If, pursuant to or in connection with a single transaction or +If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify @@ -518,10 +518,10 @@ or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. - A patent license is "discriminatory" if it does not include within +A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered +specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying @@ -533,73 +533,73 @@ for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. - Nothing in this License shall be construed as excluding or limiting +Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. - 12. No Surrender of Others' Freedom. +12. No Surrender of Others' Freedom. - If conditions are imposed on you (whether by court order, agreement or +If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a +excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you +not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. - 13. Use with the GNU Affero General Public License. +13. Use with the GNU Affero General Public License. - Notwithstanding any other provision of this License, you have +Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single -combined work, and to convey the resulting work. The terms of this +combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. - 14. Revised Versions of this License. +14. Revised Versions of this License. - The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will +The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. - Each version is given a distinguishing version number. If the +Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the +Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. - If the Program specifies that a proxy can decide which future +If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any +Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. - 15. Disclaimer of Warranty. +15. Disclaimer of Warranty. - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - 16. Limitation of Liability. +16. Limitation of Liability. - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE @@ -609,9 +609,9 @@ PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - 17. Interpretation of Sections 15 and 16. +17. Interpretation of Sections 15 and 16. - If the disclaimer of warranty and limitation of liability provided +If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the @@ -622,11 +622,11 @@ copy of the Program in return for a fee. How to Apply These Terms to Your New Programs - If you develop a new program, and you want it to be of the greatest +If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. - To do so, attach the following notices to the program. It is safest +To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. @@ -649,7 +649,7 @@ the "copyright" line and a pointer to where the full notice is found. Also add information on how to contact you by electronic and paper mail. - If the program does terminal interaction, make it output a short +If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) @@ -658,17 +658,17 @@ notice like this when it starts in an interactive mode: under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, your program's commands +parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". - You should also get your employer (if you work as a programmer) or school, +You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . - The GNU General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you +The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with -the library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. But first, please read +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read . diff --git a/package.json b/package.json index c5e4450c..c4257e37 100644 --- a/package.json +++ b/package.json @@ -21,5 +21,6 @@ "evm:test": "cd packages/evm && yarn test", "evm:coverage": "cd packages/evm && yarn coverage", "preinstall": "yarn evm:install" - } + }, + "dependencies": {} } diff --git a/packages/ciphernode/p2p/src/lib.rs b/packages/ciphernode/p2p/src/lib.rs index 47b75f70..4a6a4267 100644 --- a/packages/ciphernode/p2p/src/lib.rs +++ b/packages/ciphernode/p2p/src/lib.rs @@ -10,7 +10,6 @@ use std::hash::{Hash, Hasher}; use std::time::Duration; use tokio::{io, io::AsyncBufReadExt, select}; use tracing_subscriber::EnvFilter; -use bfv::EnclaveBFV; #[derive(NetworkBehaviour)] struct MyBehaviour { @@ -48,7 +47,7 @@ impl EnclaveRouter { self.identity = Some(keypair); } - pub fn connect_swarm(&mut self, discovery_type: String) -> Result<(&Self), Box> { + pub fn connect_swarm(&mut self, discovery_type: String) -> Result<&Self, Box> { match discovery_type.as_str() { "mdns" => { let _ = tracing_subscriber::fmt() @@ -80,14 +79,14 @@ impl EnclaveRouter { }, _ => println!("Defaulting to MDNS discovery"), } - Ok((self)) + Ok(self) } - pub fn join_topic(&mut self, topic_name: &str) -> Result<(&Self), Box> { + pub fn join_topic(&mut self, topic_name: &str) -> Result<&Self, Box> { let topic = gossipsub::IdentTopic::new(topic_name); self.topic = Some(topic.clone()); self.swarm.as_mut().unwrap().behaviour_mut().gossipsub.subscribe(&topic)?; - Ok((self)) + Ok(self) } pub async fn start(&mut self) -> Result<(), Box> { @@ -138,8 +137,6 @@ impl EnclaveRouter { } } } - - Ok(()) } } diff --git a/packages/evm/contracts/test/MockCyphernodeRegistry.sol b/packages/evm/contracts/test/MockCyphernodeRegistry.sol index de4e95f3..4f2469c9 100644 --- a/packages/evm/contracts/test/MockCyphernodeRegistry.sol +++ b/packages/evm/contracts/test/MockCyphernodeRegistry.sol @@ -20,7 +20,7 @@ contract MockCyphernodeRegistry is ICyphernodeRegistry { uint256, bytes calldata, bytes calldata - ) external {} + ) external {} // solhint-disable-line no-empty-blocks function committeePublicKey( uint256 e3Id @@ -54,7 +54,7 @@ contract MockCyphernodeRegistryEmptyKey is ICyphernodeRegistry { uint256, bytes calldata, bytes calldata - ) external {} + ) external {} // solhint-disable-line no-empty-blocks function committeePublicKey(uint256) external pure returns (bytes memory) { return hex""; diff --git a/packages/evm/test/Enclave.spec.ts b/packages/evm/test/Enclave.spec.ts index f23b8ddc..02b48d3b 100644 --- a/packages/evm/test/Enclave.spec.ts +++ b/packages/evm/test/Enclave.spec.ts @@ -696,7 +696,7 @@ describe("Enclave", function () { { value: 10 }, ); - mine(1, { interval: 1000 }); + const _ = mine(1, { interval: 1000 }); await expect(enclave.activate(0)).to.be.revertedWithCustomError( enclave, @@ -746,7 +746,7 @@ describe("Enclave", function () { { value: 10 }, ); - mine(1, { interval: 1000 }); + const _ = mine(1, { interval: 1000 }); await expect(enclave.activate(0)).to.be.revertedWithCustomError( enclave, @@ -954,10 +954,10 @@ describe("Enclave", function () { await enclave.activate(0); - expect(await enclave.publishInput(0, inputData)).to.not.be.reverted; + await expect(await enclave.publishInput(0, inputData)).to.not.be.reverted; let e3 = await enclave.getE3(0); expect(e3.inputs[0]).to.equal(inputData); - expect(await enclave.publishInput(0, inputData)).to.not.be.reverted; + await expect(await enclave.publishInput(0, inputData)).to.not.be.reverted; e3 = await enclave.getE3(0); expect(e3.inputs[1]).to.equal(inputData); }); @@ -1011,7 +1011,7 @@ describe("Enclave", function () { describe("publishCiphertextOutput()", function () { it("reverts if E3 does not exist", async function () { - const { enclave, request } = await loadFixture(setup); + const { enclave } = await loadFixture(setup); await expect(enclave.publishCiphertextOutput(0, "0x")) .to.be.revertedWithCustomError(enclave, "E3DoesNotExist") @@ -1173,7 +1173,7 @@ describe("Enclave", function () { describe("publishPlaintextOutput()", function () { it("reverts if E3 does not exist", async function () { - const { enclave, request } = await loadFixture(setup); + const { enclave } = await loadFixture(setup); const e3Id = 0; await expect(enclave.publishPlaintextOutput(e3Id, "0x")) @@ -1330,7 +1330,7 @@ describe("Enclave", function () { await enclave.activate(e3Id); await mine(2, { interval: request.duration }); await enclave.publishCiphertextOutput(e3Id, "0x1337"); - expect(await enclave.publishPlaintextOutput(e3Id, "0x1337")) + await expect(await enclave.publishPlaintextOutput(e3Id, "0x1337")) .to.emit(enclave, "PlaintextOutputPublished") .withArgs(e3Id, "0x1337"); }); From bf05f9d72af927c01dbe10e2d5cb176852c064e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=B3=CE=BB?= Date: Thu, 22 Aug 2024 15:55:15 +1000 Subject: [PATCH 11/87] Add ciphernode core unintegrated (#11) --- packages/ciphernode/Cargo.lock | 119 ++++++++-- packages/ciphernode/core/Cargo.toml | 11 +- packages/ciphernode/core/src/ciphernode.rs | 81 +++++++ packages/ciphernode/core/src/committee.rs | 65 ++++++ packages/ciphernode/core/src/committee_key.rs | 166 ++++++++++++++ packages/ciphernode/core/src/data.rs | 85 +++++++ packages/ciphernode/core/src/eventbus.rs | 99 +++++++++ packages/ciphernode/core/src/events.rs | 164 ++++++++++++++ packages/ciphernode/core/src/fhe.rs | 138 ++++++++++++ packages/ciphernode/core/src/lib.rs | 208 +++++++++++++++++- packages/ciphernode/core/src/ordered_set.rs | 194 ++++++++++++++++ packages/ciphernode/enclave_node/src/main.rs | 13 +- 12 files changed, 1313 insertions(+), 30 deletions(-) create mode 100644 packages/ciphernode/core/src/ciphernode.rs create mode 100644 packages/ciphernode/core/src/committee.rs create mode 100644 packages/ciphernode/core/src/committee_key.rs create mode 100644 packages/ciphernode/core/src/data.rs create mode 100644 packages/ciphernode/core/src/eventbus.rs create mode 100644 packages/ciphernode/core/src/events.rs create mode 100644 packages/ciphernode/core/src/fhe.rs create mode 100644 packages/ciphernode/core/src/ordered_set.rs diff --git a/packages/ciphernode/Cargo.lock b/packages/ciphernode/Cargo.lock index 57495901..f0ff4170 100644 --- a/packages/ciphernode/Cargo.lock +++ b/packages/ciphernode/Cargo.lock @@ -2,6 +2,63 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "actix" +version = "0.13.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de7fa236829ba0841304542f7614c42b80fca007455315c45c785ccfa873a85b" +dependencies = [ + "actix-macros", + "actix-rt", + "actix_derive", + "bitflags 2.6.0", + "bytes", + "crossbeam-channel", + "futures-core", + "futures-sink", + "futures-task", + "futures-util", + "log", + "once_cell", + "parking_lot", + "pin-project-lite", + "smallvec", + "tokio", + "tokio-util", +] + +[[package]] +name = "actix-macros" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e01ed3140b2f8d422c68afa1ed2e85d996ea619c988ac834d255db32138655cb" +dependencies = [ + "quote", + "syn 2.0.72", +] + +[[package]] +name = "actix-rt" +version = "2.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24eda4e2a6e042aa4e55ac438a2ae052d3b5da0ecf83d7411e1a368946925208" +dependencies = [ + "actix-macros", + "futures-core", + "tokio", +] + +[[package]] +name = "actix_derive" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c7db3d5a9718568e4cf4a537cfd7070e6e6ff7481510d0237fb529ac850f6d3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.72", +] + [[package]] name = "addr2line" version = "0.22.0" @@ -605,17 +662,6 @@ version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" -[[package]] -name = "core" -version = "0.1.0" -dependencies = [ - "async-std", - "fhe", - "fhe-traits", - "fhe-util", - "libp2p", -] - [[package]] name = "core-foundation" version = "0.9.4" @@ -650,6 +696,15 @@ dependencies = [ "libc", ] +[[package]] +name = "crossbeam-channel" +version = "0.5.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33480d6946193aa8033910124896ca395333cae7e2d1113d1fef6c3272217df2" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "crossbeam-utils" version = "0.8.20" @@ -838,6 +893,26 @@ dependencies = [ "fhe-util", ] +[[package]] +name = "enclave-core" +version = "0.1.0" +dependencies = [ + "actix", + "actix-rt", + "anyhow", + "async-std", + "bs58", + "fhe", + "fhe-traits", + "fhe-util", + "libp2p", + "rand", + "rand_chacha", + "secp256k1", + "sha2", + "tokio", +] + [[package]] name = "enclave_node" version = "0.1.0" @@ -3248,6 +3323,24 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "secp256k1" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e0cc0f1cf93f4969faf3ea1c7d8a9faed25918d96affa959720823dfe86d4f3" +dependencies = [ + "secp256k1-sys", +] + +[[package]] +name = "secp256k1-sys" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1433bd67156263443f14d603720b082dd3121779323fce20cba2aa07b874bc1b" +dependencies = [ + "cc", +] + [[package]] name = "semver" version = "1.0.23" @@ -3560,9 +3653,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.39.2" +version = "1.39.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daa4fb1bc778bd6f04cbfc4bb2d06a7396a8f299dc33ea1900cedaa316f467b1" +checksum = "9babc99b9923bfa4804bd74722ff02c0381021eafa4db9949217e3be8e84fff5" dependencies = [ "backtrace", "bytes", diff --git a/packages/ciphernode/core/Cargo.toml b/packages/ciphernode/core/Cargo.toml index 44c46514..e1f4ddfe 100644 --- a/packages/ciphernode/core/Cargo.toml +++ b/packages/ciphernode/core/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "core" +name = "enclave-core" version = "0.1.0" edition = "2021" description = ": coordinates the encryption and decryption of enclave computations" @@ -13,4 +13,13 @@ libp2p = "0.53.2" fhe = { git = "https://github.com/gnosisguild/fhe.rs", version = "0.1.0-beta.7" } fhe-traits = { git = "https://github.com/gnosisguild/fhe.rs", version = "0.1.0-beta.7" } fhe-util = { git = "https://github.com/gnosisguild/fhe.rs", version = "0.1.0-beta.7" } +actix = "0.13.5" +actix-rt = "2.10.0" +anyhow = "1.0.86" +rand = "0.8.5" +rand_chacha = "0.3.1" +secp256k1 = "0.29.0" +tokio = { version = "1.39.3", features = ["full"] } +sha2 = "0.10.8" +bs58 = "0.5.1" diff --git a/packages/ciphernode/core/src/ciphernode.rs b/packages/ciphernode/core/src/ciphernode.rs new file mode 100644 index 00000000..1b1a19dc --- /dev/null +++ b/packages/ciphernode/core/src/ciphernode.rs @@ -0,0 +1,81 @@ +use crate::{ + data::{Data, Insert}, + eventbus::EventBus, + events::{ComputationRequested, EnclaveEvent, KeyshareCreated}, + fhe::{Fhe, GenerateKeyshare}, +}; +use actix::prelude::*; +use anyhow::Result; + +pub struct Ciphernode { + fhe: Addr, + data: Addr, + bus: Addr, +} + +impl Actor for Ciphernode { + type Context = Context; +} + +impl Ciphernode { + pub fn new(bus: Addr, fhe: Addr, data: Addr) -> Self { + Self { bus, fhe, data } + } +} + +impl Handler for Ciphernode { + type Result = (); + + fn handle(&mut self, event: EnclaveEvent, ctx: &mut Context) -> Self::Result { + match event { + EnclaveEvent::ComputationRequested { data, .. } => ctx.address().do_send(data), + _ => (), + } + } +} + +impl Handler for Ciphernode { + type Result = ResponseFuture<()>; + + fn handle(&mut self, event: ComputationRequested, _: &mut Context) -> Self::Result { + let fhe = self.fhe.clone(); + let data = self.data.clone(); + let bus = self.bus.clone(); + Box::pin(async { + on_computation_requested(fhe, data, bus, event) + .await + .unwrap() + }) + } +} + +async fn on_computation_requested( + fhe: Addr, + data: Addr, + bus: Addr, + event: ComputationRequested, +) -> Result<()> { + let ComputationRequested { e3_id, .. } = event; + // generate keyshare + let (sk, pubkey) = fhe.send(GenerateKeyshare {}).await??; + + // TODO: decrypt from FHE actor + // save encrypted key against e3_id/sk + // reencrypt secretkey locally with env var - this is so we don't have to serialize a secret + // best practice would be as you boot up a node you enter in a configured password from + // which we derive a kdf which gets used to generate this key + data.do_send(Insert(format!("{}/sk", e3_id).into(), sk.unsafe_to_vec())); + + // save public key against e3_id/pk + data.do_send(Insert( + format!("{}/pk", e3_id).into(), + pubkey.clone().into(), + )); + + // broadcast the KeyshareCreated message + let event = EnclaveEvent::from(KeyshareCreated { pubkey, e3_id }); + + bus.do_send(event); + + Ok(()) +} diff --git a/packages/ciphernode/core/src/committee.rs b/packages/ciphernode/core/src/committee.rs new file mode 100644 index 00000000..16a88a72 --- /dev/null +++ b/packages/ciphernode/core/src/committee.rs @@ -0,0 +1,65 @@ +use std::collections::HashMap; + +use actix::{Actor, Addr, Context, Handler}; + +use crate::{ + committee_key::{CommitteeKey, Die}, + eventbus::EventBus, + events::{E3id, EnclaveEvent}, + fhe::Fhe, +}; + +pub struct Committee { + bus: Addr, + fhe: Addr, + aggregators: HashMap>, +} + +impl Actor for Committee { + type Context = Context; +} + +impl Committee { + pub fn new(bus: Addr, fhe: Addr) -> Self { + Self { + bus, + fhe, + aggregators: HashMap::new(), + } + } +} + +impl Handler for Committee { + type Result = (); + + fn handle(&mut self, event: EnclaveEvent, _ctx: &mut Self::Context) -> Self::Result { + match event { + EnclaveEvent::ComputationRequested { data, .. } => { + // start up a new aggregator + let aggregator = CommitteeKey::new( + self.fhe.clone(), + self.bus.clone(), + data.e3_id.clone(), + data.nodecount, + ) + .start(); + + self.aggregators.insert(data.e3_id, aggregator); + } + EnclaveEvent::KeyshareCreated { data, .. } => { + if let Some(aggregator) = self.aggregators.get(&data.e3_id) { + aggregator.do_send(data); + } + }, + EnclaveEvent::PublicKeyAggregated { data, .. } => { + let Some(aggregator) = self.aggregators.get(&data.e3_id) else { + return; + }; + + aggregator.do_send(Die); + self.aggregators.remove(&data.e3_id); + } + // _ => (), + } + } +} diff --git a/packages/ciphernode/core/src/committee_key.rs b/packages/ciphernode/core/src/committee_key.rs new file mode 100644 index 00000000..9d6e7aeb --- /dev/null +++ b/packages/ciphernode/core/src/committee_key.rs @@ -0,0 +1,166 @@ +use crate::{ + eventbus::EventBus, + events::{E3id, EnclaveEvent, KeyshareCreated, PublicKeyAggregated}, + fhe::{Fhe, GetAggregatePublicKey, WrappedPublicKey, WrappedPublicKeyShare}, ordered_set::OrderedSet, +}; +use actix::prelude::*; +use anyhow::{anyhow, Result}; + +#[derive(Debug, Clone)] +pub enum CommitteeKeyState { + Collecting { + nodecount: usize, + keyshares: OrderedSet, + }, + Computing { + keyshares: OrderedSet, + }, + Complete { + public_key: WrappedPublicKey, + keyshares: OrderedSet, + }, +} + +#[derive(Message)] +#[rtype(result = "anyhow::Result<()>")] +struct ComputeAggregate { + pub keyshares: OrderedSet, +} + +#[derive(Message)] +#[rtype(result = "()")] +pub struct Die; + +pub struct CommitteeKey { + fhe: Addr, + bus: Addr, + e3_id: E3id, + state: CommitteeKeyState, +} + +impl CommitteeKey { + pub fn new(fhe: Addr, bus: Addr, e3_id: E3id, nodecount: usize) -> Self { + CommitteeKey { + fhe, + bus, + e3_id, + state: CommitteeKeyState::Collecting { + nodecount, + keyshares: OrderedSet::new(), + }, + } + } + + pub fn add_keyshare(&mut self, keyshare: WrappedPublicKeyShare) -> Result { + let CommitteeKeyState::Collecting { + nodecount, + keyshares, + } = &mut self.state + else { + return Err(anyhow::anyhow!("Can only add keyshare in Collecting state")); + }; + + keyshares.insert(keyshare); + if keyshares.len() == *nodecount { + return Ok(CommitteeKeyState::Computing { + keyshares: keyshares.clone(), + }); + } + + Ok(self.state.clone()) + } + + pub fn set_pubkey(&mut self, pubkey: WrappedPublicKey) -> Result { + let CommitteeKeyState::Computing { keyshares } = &mut self.state else { + return Ok(self.state.clone()); + }; + + let keyshares = keyshares.to_owned(); + + Ok(CommitteeKeyState::Complete { + public_key: pubkey, + keyshares, + }) + } +} + +impl Actor for CommitteeKey { + type Context = Context; +} + +impl Handler for CommitteeKey { + type Result = Result<()>; + + fn handle(&mut self, event: KeyshareCreated, ctx: &mut Self::Context) -> Self::Result { + if event.e3_id != self.e3_id { + return Err(anyhow!( + "Wrong e3_id sent to aggregator. This should not happen." + )); + } + + let CommitteeKeyState::Collecting { .. } = self.state else { + return Err(anyhow!( + "Aggregator has been closed for collecting keyshares." + )); + }; + + // add the keyshare and + self.state = self.add_keyshare(event.pubkey)?; + + // Check the state and if it has changed to the computing + if let CommitteeKeyState::Computing { keyshares } = &self.state { + ctx.address().do_send(ComputeAggregate { + keyshares: keyshares.clone(), + }) + } + + Ok(()) + } +} + +impl Handler for CommitteeKey { + type Result = ResponseActFuture>; + + fn handle(&mut self, msg: ComputeAggregate, _: &mut Self::Context) -> Self::Result { + // Futures are awkward in Actix from what I can tell we should try and structure events so + // that futures that don't reuire access to self filre like the following... + Box::pin( + // Run the async future. + self.fhe + .send(GetAggregatePublicKey { + keyshares: msg.keyshares.clone(), + }) + // allow access to the actor + .into_actor(self) + // map into some sync stuff + .map(|res, act, _| { + // We have to double unwrap here. Suggestions? + // 1st - Mailbox error. + // 2nd - GetAggregatePublicKey Response. + let pubkey = res??; + + // Update the local state + act.state = act.set_pubkey(pubkey.clone())?; + + // Dispatch the PublicKeyAggregated event + let event = EnclaveEvent::from(PublicKeyAggregated { + pubkey, + e3_id: act.e3_id.clone(), + }); + + act.bus.do_send(event); + + // Return + Ok(()) + }), + ) + } +} + +impl Handler for CommitteeKey { + type Result = (); + + fn handle(&mut self, _msg: Die, ctx: &mut Context) { + ctx.stop(); + } +} diff --git a/packages/ciphernode/core/src/data.rs b/packages/ciphernode/core/src/data.rs new file mode 100644 index 00000000..40ba1a3e --- /dev/null +++ b/packages/ciphernode/core/src/data.rs @@ -0,0 +1,85 @@ +use std::collections::BTreeMap; + +use actix::{Actor, Context, Handler, Message}; + +// TODO: replace with sled version + +#[derive(Message, Clone, Debug, PartialEq, Eq, Hash)] +#[rtype(result = "()")] +pub struct Insert(pub Vec, pub Vec); +impl Insert { + fn key(&self) -> Vec { + self.0.clone() + } + + fn value(&self) -> Vec { + self.1.clone() + } +} + + +#[derive(Message, Clone, Debug, PartialEq, Eq, Hash)] +#[rtype(result = "Option>")] +pub struct Get(Vec); +impl Get { + fn key(&self) -> Vec { + self.0.clone() + } +} + +#[derive(Message, Clone, Debug, PartialEq, Eq, Hash)] +#[rtype(result = "Vec")] +pub struct GetLog; + +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub enum DataOp { + Insert(Insert), +} + +pub struct Data { + db: BTreeMap, Vec>, + log: Vec, + capture: bool, +} + +impl Actor for Data { + type Context = Context; +} + +impl Data { + pub fn new(capture: bool) -> Self { + Self { + db: BTreeMap::new(), + capture, + log: vec![], + } + } +} + +impl Handler for Data { + type Result = (); + fn handle(&mut self, event: Insert, _: &mut Self::Context) { + + // insert data into sled + self.db.insert(event.key(), event.value()); + + if self.capture { + self.log.push(DataOp::Insert(event)); + } + } +} + +impl Handler for Data { + type Result = Option>; + fn handle(&mut self, event: Get, _: &mut Self::Context) -> Option> { + let key = event.key(); + self.db.get(&key).map(|r| r.clone()) + } +} + +impl Handler for Data { + type Result = Vec; + fn handle(&mut self, _: GetLog, _: &mut Self::Context) -> Vec { + self.log.clone() + } +} diff --git a/packages/ciphernode/core/src/eventbus.rs b/packages/ciphernode/core/src/eventbus.rs new file mode 100644 index 00000000..d6b40cc9 --- /dev/null +++ b/packages/ciphernode/core/src/eventbus.rs @@ -0,0 +1,99 @@ +use crate::events::{EnclaveEvent, EventId}; +use actix::prelude::*; +use std::collections::{HashMap, HashSet}; + +#[derive(Message, Debug)] +#[rtype(result = "()")] +pub struct Subscribe { + pub event_type: String, + pub listener: Recipient, +} + +impl Subscribe { + pub fn new(event_type: impl Into, listener: Recipient) -> Self { + Self { + event_type: event_type.into(), + listener, + } + } +} + +#[derive(Message)] +#[rtype(result = "Vec")] +pub struct GetHistory; + +pub struct EventBus { + capture: bool, + history: Vec, + ids: HashSet, + listeners: HashMap>>, +} + +impl Actor for EventBus { + type Context = Context; +} + +impl EventBus { + pub fn new(capture: bool) -> Self { + EventBus { + capture, + listeners: HashMap::new(), + ids: HashSet::new(), + history: vec![], + } + } + + fn add_to_history(&mut self, event: EnclaveEvent) { + self.history.push(event.clone()); + self.ids.insert(event.into()); + } +} + +impl Handler for EventBus { + type Result = (); + + fn handle(&mut self, event: Subscribe, _: &mut Context) { + self.listeners + .entry(event.event_type) + .or_insert_with(Vec::new) + .push(event.listener); + } +} + +impl Handler for EventBus { + type Result = Vec; + + fn handle(&mut self, _: GetHistory, _: &mut Context) -> Vec { + self.history.clone() + } +} + +impl Handler for EventBus { + type Result = (); + + fn handle(&mut self, event: EnclaveEvent, _: &mut Context) { + // Deduplicate by id + if self.ids.contains(&event.clone().into()) { + // We have seen this before + println!("Duplicate {}", EventId::from(event)); + return; + } + + // TODO: How can we ensure the event we see is coming in in the correct order? + if let Some(listeners) = self.listeners.get("*") { + for listener in listeners { + listener.do_send(event.clone()) + } + } + + if let Some(listeners) = self.listeners.get(&event.event_type()) { + for listener in listeners { + listener.do_send(event.clone()) + } + } + + if self.capture { + self.add_to_history(event); + } + } +} diff --git a/packages/ciphernode/core/src/events.rs b/packages/ciphernode/core/src/events.rs new file mode 100644 index 00000000..2a1ebcde --- /dev/null +++ b/packages/ciphernode/core/src/events.rs @@ -0,0 +1,164 @@ +use actix::Message; +use sha2::{Digest, Sha256}; +use std::{ + fmt, + hash::{DefaultHasher, Hash, Hasher}, +}; + +use crate::fhe::{WrappedPublicKey, WrappedPublicKeyShare}; + +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub struct E3id(pub String); +impl fmt::Display for E3id { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(&self.0) + } +} + +impl E3id { + pub fn new(id: impl Into) -> Self { + Self(id.into()) + } +} + +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub struct EventId(pub [u8; 32]); + +impl EventId { + fn from(value: T) -> Self { + let mut hasher = Sha256::new(); + let mut std_hasher = DefaultHasher::new(); + value.hash(&mut std_hasher); + hasher.update(std_hasher.finish().to_le_bytes()); + let result = hasher.finalize(); + EventId(result.into()) + } +} + +impl fmt::Display for EventId { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let base58_string = bs58::encode(&self.0).into_string(); + write!(f, "eid_{}", base58_string) + } +} + + +#[derive(Message, Clone, Debug, PartialEq, Eq, Hash)] +#[rtype(result = "()")] +pub enum EnclaveEvent { + KeyshareCreated { + id: EventId, + data: KeyshareCreated, + }, + ComputationRequested { + id: EventId, + data: ComputationRequested, + }, + PublicKeyAggregated { + id: EventId, + data: PublicKeyAggregated, + }, + // CommitteeSelected, + // OutputDecrypted, + // CiphernodeRegistered, + // CiphernodeDeregistered, +} + +impl From for EventId { + fn from(value: EnclaveEvent) -> Self { + match value { + EnclaveEvent::KeyshareCreated { id, .. } => id, + EnclaveEvent::ComputationRequested { id, .. } => id, + EnclaveEvent::PublicKeyAggregated { id, .. } => id, + } + } +} + +impl From for EnclaveEvent { + fn from(data: KeyshareCreated) -> Self { + EnclaveEvent::KeyshareCreated { + id: EventId::from(data.clone()), + data: data.clone(), + } + } +} + +impl From for EnclaveEvent { + fn from(data:ComputationRequested) -> Self { + EnclaveEvent::ComputationRequested { + id: EventId::from(data.clone()), + data: data.clone(), + } + } +} + +impl From for EnclaveEvent{ + fn from(data:PublicKeyAggregated) -> Self { + EnclaveEvent::PublicKeyAggregated { + id: EventId::from(data.clone()), + data: data.clone(), + } + } +} + +#[derive(Message, Clone, Debug, PartialEq, Eq, Hash)] +#[rtype(result = "anyhow::Result<()>")] +pub struct KeyshareCreated { + pub pubkey: WrappedPublicKeyShare, + pub e3_id: E3id, +} + +#[derive(Message, Clone, Debug, PartialEq, Eq, Hash)] +#[rtype(result = "()")] +pub struct PublicKeyAggregated { + pub pubkey: WrappedPublicKey, + pub e3_id: E3id, +} + +#[derive(Message, Clone, Debug, PartialEq, Eq, Hash)] +#[rtype(result = "()")] +pub struct ComputationRequested { + pub e3_id: E3id, + pub nodecount: usize, + pub threshold: usize, + pub sortition_seed: u32, + // computation_type: ??, // TODO: + // execution_model_type: ??, // TODO: + // input_deadline: ??, // TODO: + // availability_duration: ??, // TODO: +} + +fn extract_enclave_event_name(s: &str) -> &str { + let bytes = s.as_bytes(); + for (i, &item) in bytes.iter().enumerate() { + if item == b' ' || item == b'(' { + return &s[..i]; + } + } + s +} + +impl EnclaveEvent { + pub fn event_type(&self) -> String { + let s = format!("{:?}", self); + extract_enclave_event_name(&s).to_string() + } +} + +#[cfg(test)] +mod tests { + + use crate::events::extract_enclave_event_name; + + #[test] + fn test_extract_enum_name() { + assert_eq!( + extract_enclave_event_name("KeyshareCreated(KeyshareCreated { pubkey: [] })"), + "KeyshareCreated" + ); + assert_eq!( + extract_enclave_event_name("CommitteeSelected(SomeStruct { t: 8 })"), + "CommitteeSelected" + ); + } +} diff --git a/packages/ciphernode/core/src/fhe.rs b/packages/ciphernode/core/src/fhe.rs new file mode 100644 index 00000000..c68edb24 --- /dev/null +++ b/packages/ciphernode/core/src/fhe.rs @@ -0,0 +1,138 @@ +use std::{cmp::Ordering, hash::Hash, mem, sync::Arc}; + +use actix::{Actor, Context, Handler, Message}; +use anyhow::*; +use fhe::{ + bfv::{BfvParameters, PublicKey, SecretKey}, + mbfv::{AggregateIter, CommonRandomPoly, PublicKeyShare}, +}; +use fhe_traits::Serialize; +use rand_chacha::ChaCha20Rng; + +use crate::ordered_set::OrderedSet; + +#[derive(Message, Clone, Debug, PartialEq, Eq, Hash)] +#[rtype(result = "Result<(WrappedSecretKey, WrappedPublicKeyShare)>")] +pub struct GenerateKeyshare { + // responder_pk: Vec, // TODO: use this to encrypt the secret data +} + +#[derive(Message, Clone, Debug, PartialEq, Eq)] +#[rtype(result = "Result<(WrappedPublicKey)>")] +pub struct GetAggregatePublicKey { + pub keyshares: OrderedSet, +} + +/// Wrapped PublicKeyShare. This is wrapped to provide an inflection point +/// as we use this library elsewhere we only implement traits as we need them +/// and avoid exposing underlying structures from fhe.rs +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct WrappedPublicKeyShare(pub PublicKeyShare); + +impl Ord for WrappedPublicKeyShare { + fn cmp(&self, other: &Self) -> Ordering { + self.0.to_bytes().cmp(&other.0.to_bytes()) + } +} + +impl PartialOrd for WrappedPublicKeyShare { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl From for Vec { + fn from(share: WrappedPublicKeyShare) -> Self { + share.0.to_bytes() + } +} + +impl Hash for WrappedPublicKeyShare { + fn hash(&self, state: &mut H) { + self.0.to_bytes().hash(state) + } +} + +impl WrappedPublicKeyShare { + fn clone_inner(&self) -> PublicKeyShare { + self.0.clone() + } +} + +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct WrappedPublicKey(pub PublicKey); + +impl Hash for WrappedPublicKey { + fn hash(&self, state: &mut H) { + self.0.to_bytes().hash(state) + } +} + +impl Ord for WrappedPublicKey { + fn cmp(&self, other: &Self) -> Ordering { + self.0.to_bytes().cmp(&other.0.to_bytes()) + } +} + +impl PartialOrd for WrappedPublicKey { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + + +#[derive(PartialEq)] +pub struct WrappedSecretKey(pub SecretKey); +impl WrappedSecretKey { + pub fn unsafe_to_vec(&self) -> Vec { + serialize_box_i64(self.0.coeffs.clone()) + } +} + +pub struct Fhe { + params: Arc, + crp: CommonRandomPoly, + rng: ChaCha20Rng, +} + +impl Actor for Fhe { + type Context = Context; +} + +impl Fhe { + pub fn new( + params: Arc, + crp: CommonRandomPoly, + rng: ChaCha20Rng, + ) -> Result { + Ok(Self { params, crp, rng }) + } +} + +impl Handler for Fhe { + type Result = Result<(WrappedSecretKey, WrappedPublicKeyShare)>; + fn handle(&mut self, _event: GenerateKeyshare, _: &mut Self::Context) -> Self::Result { + let sk_share = { SecretKey::random(&self.params, &mut self.rng) }; + let pk_share = { PublicKeyShare::new(&sk_share, self.crp.clone(), &mut self.rng)? }; + Ok((WrappedSecretKey(sk_share), WrappedPublicKeyShare(pk_share))) + } +} + +impl Handler for Fhe { + type Result = Result; + + fn handle(&mut self, msg: GetAggregatePublicKey, _: &mut Self::Context) -> Self::Result { + // Could implement Aggregate for Wrapped keys but that leaks traits + let public_key: PublicKey = msg.keyshares.iter().map(|k| k.clone_inner()).aggregate()?; + Ok(WrappedPublicKey(public_key)) + } +} + +fn serialize_box_i64(boxed: Box<[i64]>) -> Vec { + let vec = boxed.into_vec(); + let mut bytes = Vec::with_capacity(vec.len() * mem::size_of::()); + for &num in &vec { + bytes.extend_from_slice(&num.to_le_bytes()); + } + bytes +} diff --git a/packages/ciphernode/core/src/lib.rs b/packages/ciphernode/core/src/lib.rs index eecfcfeb..ca1f5c3e 100644 --- a/packages/ciphernode/core/src/lib.rs +++ b/packages/ciphernode/core/src/lib.rs @@ -1,13 +1,203 @@ -#![crate_name = "core"] +#![crate_name = "enclave_core"] #![crate_type = "lib"] -#![warn(missing_docs, unused_imports)] +// #![warn(missing_docs, unused_imports)] -pub struct Core { - pub name: String, -} +mod ciphernode; +mod committee; +mod committee_key; +mod data; +mod eventbus; +mod events; +mod fhe; +mod ordered_set; + +// pub struct Core { +// pub name: String, +// } +// +// impl Core { +// fn new(name: String) -> Self { +// Self { name } +// } +// +// fn run() { +// actix::run(async move { +// sleep(Duration::from_millis(100)).await; +// actix::System::current().stop(); +// }); +// } +// } + +#[cfg(test)] +mod tests { + use std::sync::Arc; + + use crate::{ + ciphernode::Ciphernode, + committee::Committee, + data::Data, + eventbus::{EventBus, GetHistory, Subscribe}, + events::{ComputationRequested, E3id, EnclaveEvent, KeyshareCreated, PublicKeyAggregated}, + fhe::{Fhe, WrappedPublicKey, WrappedPublicKeyShare}, + }; + use actix::prelude::*; + use anyhow::*; + use fhe::{ + bfv::{BfvParameters, BfvParametersBuilder, PublicKey, SecretKey}, + mbfv::{AggregateIter, CommonRandomPoly, PublicKeyShare}, + }; + use rand::SeedableRng; + use rand_chacha::ChaCha20Rng; + + // Simulating a local node + fn setup_local_ciphernode( + bus: Addr, + fhe: Addr, + logging: bool, + ) -> (Addr, Addr) { + // create data actor for saving data + let data = Data::new(logging).start(); // TODO: Use a sled backed Data Actor + + // create ciphernode actor for managing ciphernode flow + let node = Ciphernode::new(bus.clone(), fhe.clone(), data.clone()).start(); + + // subscribe for computation requested events from the event bus + bus.do_send(Subscribe::new("ComputationRequested", node.clone().into())); + + // setup the committee manager to generate the comittee public keys + setup_committee_manager(bus.clone(), fhe); + (node, data) + } + + fn setup_bfv_params( + moduli: &[u64], + degree: usize, + plaintext_modulus: u64, + mut rng: ChaCha20Rng, + ) -> Result<(Arc, CommonRandomPoly)> { + let params = BfvParametersBuilder::new() + .set_degree(degree) + .set_plaintext_modulus(plaintext_modulus) + .set_moduli(&moduli) + .build_arc()?; + let crp = CommonRandomPoly::new(¶ms, &mut rng)?; + Ok((params, crp)) + } + + fn generate_pk_share( + params: Arc, + crp: CommonRandomPoly, + mut rng: ChaCha20Rng, + ) -> Result<(WrappedPublicKeyShare, ChaCha20Rng)> { + let sk = SecretKey::random(¶ms, &mut rng); + let pk = WrappedPublicKeyShare(PublicKeyShare::new(&sk, crp.clone(), &mut rng)?); + Ok((pk, rng)) + } + + fn setup_committee_manager(bus: Addr, fhe: Addr) -> Addr { + let committee = Committee::new(bus.clone(), fhe.clone()).start(); -impl Core { - fn new(name: String) -> Self { - Self { name } + bus.do_send(Subscribe::new( + "ComputationRequested", + committee.clone().into(), + )); + bus.do_send(Subscribe::new("KeyshareCreated", committee.clone().into())); + + committee } -} \ No newline at end of file + + fn setup_global_fhe_actor( + moduli: &[u64], + degree: usize, + plaintext_modulus: u64, + rng1: ChaCha20Rng, + rng2: ChaCha20Rng, + ) -> Result> { + let (params, crp) = setup_bfv_params(&moduli, degree, plaintext_modulus, rng1)?; + Ok(Fhe::new(params, crp, rng2)?.start()) + } + + #[actix::test] + async fn test_ciphernode() -> Result<()> { + // Setup EventBus + let bus = EventBus::new(true).start(); + + // Setup global FHE actor + let fhe = setup_global_fhe_actor( + &vec![0x3FFFFFFF000001], + 2048, + 1032193, + ChaCha20Rng::seed_from_u64(42), + ChaCha20Rng::seed_from_u64(42), + )?; + setup_local_ciphernode(bus.clone(), fhe.clone(), true); + setup_local_ciphernode(bus.clone(), fhe.clone(), true); + setup_local_ciphernode(bus.clone(), fhe.clone(), true); + + let e3_id = E3id::new("1234"); + + let event = EnclaveEvent::from(ComputationRequested { + e3_id: e3_id.clone(), + nodecount: 3, + threshold: 123, + sortition_seed: 123, + }); + + // Send the computation requested event + bus.send(event.clone()).await?; + + // Test that we cannot send the same event twice + bus.send(event).await?; + + let history = bus.send(GetHistory).await?; + + let (params, crp) = setup_bfv_params( + &vec![0x3FFFFFFF000001], + 2048, + 1032193, + ChaCha20Rng::seed_from_u64(42), + )?; + + // Passing rng through function chain to ensure it matches usage in system above + let rng = ChaCha20Rng::seed_from_u64(42); + let (p1, rng) = generate_pk_share(params.clone(), crp.clone(), rng)?; + let (p2, rng) = generate_pk_share(params.clone(), crp.clone(), rng)?; + let (p3, _) = generate_pk_share(params.clone(), crp.clone(), rng)?; + + let aggregated: PublicKey = vec![p1.clone(), p2.clone(), p3.clone()] + .iter() + .map(|k| k.0.clone()) + .aggregate()?; + + assert_eq!(history.len(), 5); + assert_eq!( + history, + vec![ + EnclaveEvent::from(ComputationRequested { + e3_id: e3_id.clone(), + nodecount: 3, + threshold: 123, + sortition_seed: 123, + }), + EnclaveEvent::from(KeyshareCreated { + pubkey: p1.clone(), + e3_id: e3_id.clone(), + }), + EnclaveEvent::from(KeyshareCreated { + pubkey: p2.clone(), + e3_id: e3_id.clone(), + }), + EnclaveEvent::from(KeyshareCreated { + pubkey: p3.clone(), + e3_id: e3_id.clone() + }), + EnclaveEvent::from(PublicKeyAggregated { + pubkey: WrappedPublicKey(aggregated), + e3_id: e3_id.clone() + }) + ] + ); + + Ok(()) + } +} diff --git a/packages/ciphernode/core/src/ordered_set.rs b/packages/ciphernode/core/src/ordered_set.rs new file mode 100644 index 00000000..c263e30a --- /dev/null +++ b/packages/ciphernode/core/src/ordered_set.rs @@ -0,0 +1,194 @@ +use std::collections::BTreeSet; +use std::hash::{Hash, Hasher}; +use std::fmt; + +#[derive(Clone)] +pub struct OrderedSet(BTreeSet); + +impl OrderedSet { + pub fn new() -> Self { + OrderedSet(BTreeSet::new()) + } + + pub fn insert(&mut self, value: T) -> bool { + self.0.insert(value) + } + + pub fn contains(&self, value: &T) -> bool { + self.0.contains(value) + } + + pub fn len(&self) -> usize { + self.0.len() + } + + pub fn is_empty(&self) -> bool { + self.0.is_empty() + } + + pub fn iter(&self) -> impl Iterator { + self.0.iter() + } +} + +impl Hash for OrderedSet { + fn hash(&self, state: &mut H) { + self.0.len().hash(state); + for item in &self.0 { + item.hash(state); + } + } +} + +impl PartialEq for OrderedSet { + fn eq(&self, other: &Self) -> bool { + self.0 == other.0 + } +} + +impl Eq for OrderedSet {} + +impl fmt::Debug for OrderedSet { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_set().entries(self.0.iter()).finish() + } +} + +impl IntoIterator for OrderedSet { + type Item = T; + type IntoIter = std::collections::btree_set::IntoIter; + + fn into_iter(self) -> Self::IntoIter { + self.0.into_iter() + } +} + +impl<'a, T: Ord> IntoIterator for &'a OrderedSet { + type Item = &'a T; + type IntoIter = std::collections::btree_set::Iter<'a, T>; + + fn into_iter(self) -> Self::IntoIter { + self.0.iter() + } +} + +#[cfg(test)] +mod tests { + use super::*; + use std::collections::hash_map::DefaultHasher; + use std::hash::{Hash, Hasher}; + + #[test] + fn test_new() { + let set: OrderedSet = OrderedSet::new(); + assert!(set.is_empty()); + assert_eq!(set.len(), 0); + } + + #[test] + fn test_insert() { + let mut set = OrderedSet::new(); + assert!(set.insert(1)); + assert!(set.insert(2)); + assert!(!set.insert(1)); // Duplicate insertion + assert_eq!(set.len(), 2); + } + + #[test] + fn test_contains() { + let mut set = OrderedSet::new(); + set.insert(1); + set.insert(2); + assert!(set.contains(&1)); + assert!(set.contains(&2)); + assert!(!set.contains(&3)); + } + + #[test] + fn test_len_and_is_empty() { + let mut set = OrderedSet::new(); + assert!(set.is_empty()); + assert_eq!(set.len(), 0); + set.insert(1); + assert!(!set.is_empty()); + assert_eq!(set.len(), 1); + } + + #[test] + fn test_iter() { + let mut set = OrderedSet::new(); + set.insert(3); + set.insert(1); + set.insert(2); + let mut iter = set.iter(); + assert_eq!(iter.next(), Some(&1)); + assert_eq!(iter.next(), Some(&2)); + assert_eq!(iter.next(), Some(&3)); + assert_eq!(iter.next(), None); + } + + #[test] + fn test_hash() { + let mut set1 = OrderedSet::new(); + set1.insert(1); + set1.insert(2); + + let mut set2 = OrderedSet::new(); + set2.insert(2); + set2.insert(1); + + let mut hasher1 = DefaultHasher::new(); + let mut hasher2 = DefaultHasher::new(); + + set1.hash(&mut hasher1); + set2.hash(&mut hasher2); + + assert_eq!(hasher1.finish(), hasher2.finish()); + } + + #[test] + fn test_eq() { + let mut set1 = OrderedSet::new(); + set1.insert(1); + set1.insert(2); + + let mut set2 = OrderedSet::new(); + set2.insert(2); + set2.insert(1); + + let mut set3 = OrderedSet::new(); + set3.insert(1); + set3.insert(3); + + assert_eq!(set1, set2); + assert_ne!(set1, set3); + } + + #[test] + fn test_debug() { + let mut set = OrderedSet::new(); + set.insert(1); + set.insert(2); + assert_eq!(format!("{:?}", set), "{1, 2}"); + } + + #[test] + fn test_into_iter() { + let mut set = OrderedSet::new(); + set.insert(3); + set.insert(1); + set.insert(2); + let vec: Vec = set.into_iter().collect(); + assert_eq!(vec, vec![1, 2, 3]); + } + + #[test] + fn test_iter_ref() { + let mut set = OrderedSet::new(); + set.insert(3); + set.insert(1); + set.insert(2); + let vec: Vec<&i32> = (&set).into_iter().collect(); + assert_eq!(vec, vec![&1, &2, &3]); + } +} diff --git a/packages/ciphernode/enclave_node/src/main.rs b/packages/ciphernode/enclave_node/src/main.rs index d3b72aba..466d6e63 100644 --- a/packages/ciphernode/enclave_node/src/main.rs +++ b/packages/ciphernode/enclave_node/src/main.rs @@ -1,5 +1,4 @@ -use eth::EtherClient; -use p2p::EnclaveRouter; +// use p2p::EnclaveRouter; use std::error::Error; use tokio; @@ -30,10 +29,10 @@ async fn main() -> Result<(), Box> { println!("\n\n\n\n\n{}", OWO); println!("\n\n\n\n"); - let mut p2p = EnclaveRouter::new()?; - p2p.connect_swarm("mdns".to_string())?; - p2p.join_topic("enclave-keygen-01")?; - p2p.start().await?; + // let mut p2p = EnclaveRouter::new()?; + // p2p.connect_swarm("mdns".to_string())?; + // p2p.join_topic("enclave-keygen-01")?; + // p2p.start().await?; println!("Hello, cipher world!"); Ok(()) -} \ No newline at end of file +} From 925a853a69df75b40fcf78f5b53bc9c30d3b7c9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=B3=CE=BB?= Date: Thu, 22 Aug 2024 19:05:02 +1000 Subject: [PATCH 12/87] Setup p2p for events (#12) * Setup p2p for events * Change text * Tidy up --- packages/ciphernode/Cargo.lock | 1 + packages/ciphernode/core/Cargo.lock | 2137 ------------------ packages/ciphernode/core/Cargo.toml | 2 + packages/ciphernode/core/src/p2p.rs | 11 + packages/ciphernode/enclave_node/Cargo.toml | 2 +- packages/ciphernode/enclave_node/src/main.rs | 37 +- packages/ciphernode/p2p/src/lib.rs | 216 +- 7 files changed, 162 insertions(+), 2244 deletions(-) delete mode 100644 packages/ciphernode/core/Cargo.lock create mode 100644 packages/ciphernode/core/src/p2p.rs diff --git a/packages/ciphernode/Cargo.lock b/packages/ciphernode/Cargo.lock index f0ff4170..dc3ae782 100644 --- a/packages/ciphernode/Cargo.lock +++ b/packages/ciphernode/Cargo.lock @@ -906,6 +906,7 @@ dependencies = [ "fhe-traits", "fhe-util", "libp2p", + "p2p", "rand", "rand_chacha", "secp256k1", diff --git a/packages/ciphernode/core/Cargo.lock b/packages/ciphernode/core/Cargo.lock deleted file mode 100644 index 23e86c30..00000000 --- a/packages/ciphernode/core/Cargo.lock +++ /dev/null @@ -1,2137 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "ahash" -version = "0.8.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" -dependencies = [ - "cfg-if", - "once_cell", - "version_check", - "zerocopy", -] - -[[package]] -name = "aho-corasick" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" -dependencies = [ - "memchr", -] - -[[package]] -name = "allocator-api2" -version = "0.2.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" - -[[package]] -name = "anyhow" -version = "1.0.86" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" - -[[package]] -name = "arrayref" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d151e35f61089500b617991b791fc8bfd237ae50cd5950803758a179b41e67a" - -[[package]] -name = "async-channel" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35" -dependencies = [ - "concurrent-queue", - "event-listener 2.5.3", - "futures-core", -] - -[[package]] -name = "async-channel" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89b47800b0be77592da0afd425cc03468052844aff33b84e33cc696f64e77b6a" -dependencies = [ - "concurrent-queue", - "event-listener-strategy", - "futures-core", - "pin-project-lite", -] - -[[package]] -name = "async-executor" -version = "1.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7ebdfa2ebdab6b1760375fa7d6f382b9f486eac35fc994625a00e89280bdbb7" -dependencies = [ - "async-task", - "concurrent-queue", - "fastrand 2.1.0", - "futures-lite 2.3.0", - "slab", -] - -[[package]] -name = "async-global-executor" -version = "2.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05b1b633a2115cd122d73b955eadd9916c18c8f510ec9cd1686404c60ad1c29c" -dependencies = [ - "async-channel 2.3.1", - "async-executor", - "async-io 2.3.3", - "async-lock 3.4.0", - "blocking", - "futures-lite 2.3.0", - "once_cell", -] - -[[package]] -name = "async-io" -version = "1.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fc5b45d93ef0529756f812ca52e44c221b35341892d3dcc34132ac02f3dd2af" -dependencies = [ - "async-lock 2.8.0", - "autocfg", - "cfg-if", - "concurrent-queue", - "futures-lite 1.13.0", - "log", - "parking", - "polling 2.8.0", - "rustix 0.37.27", - "slab", - "socket2", - "waker-fn", -] - -[[package]] -name = "async-io" -version = "2.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d6baa8f0178795da0e71bc42c9e5d13261aac7ee549853162e66a241ba17964" -dependencies = [ - "async-lock 3.4.0", - "cfg-if", - "concurrent-queue", - "futures-io", - "futures-lite 2.3.0", - "parking", - "polling 3.7.2", - "rustix 0.38.34", - "slab", - "tracing", - "windows-sys 0.52.0", -] - -[[package]] -name = "async-lock" -version = "2.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "287272293e9d8c41773cec55e365490fe034813a2f172f502d6ddcf75b2f582b" -dependencies = [ - "event-listener 2.5.3", -] - -[[package]] -name = "async-lock" -version = "3.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18" -dependencies = [ - "event-listener 5.3.1", - "event-listener-strategy", - "pin-project-lite", -] - -[[package]] -name = "async-std" -version = "1.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62565bb4402e926b29953c785397c6dc0391b7b446e45008b0049eb43cec6f5d" -dependencies = [ - "async-channel 1.9.0", - "async-global-executor", - "async-io 1.13.0", - "async-lock 2.8.0", - "crossbeam-utils", - "futures-channel", - "futures-core", - "futures-io", - "futures-lite 1.13.0", - "gloo-timers", - "kv-log-macro", - "log", - "memchr", - "once_cell", - "pin-project-lite", - "pin-utils", - "slab", - "wasm-bindgen-futures", -] - -[[package]] -name = "async-task" -version = "4.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" - -[[package]] -name = "atomic-waker" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" - -[[package]] -name = "autocfg" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" - -[[package]] -name = "base-x" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cbbc9d0964165b47557570cce6c952866c2678457aca742aafc9fb771d30270" - -[[package]] -name = "base64ct" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "bitflags" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" - -[[package]] -name = "block-buffer" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" -dependencies = [ - "generic-array", -] - -[[package]] -name = "blocking" -version = "1.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "703f41c54fc768e63e091340b424302bb1c29ef4aa0c7f10fe849dfb114d29ea" -dependencies = [ - "async-channel 2.3.1", - "async-task", - "futures-io", - "futures-lite 2.3.0", - "piper", -] - -[[package]] -name = "bs58" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4" -dependencies = [ - "tinyvec", -] - -[[package]] -name = "bumpalo" -version = "3.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" - -[[package]] -name = "byteorder" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" - -[[package]] -name = "bytes" -version = "1.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50" - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "concurrent-queue" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" -dependencies = [ - "crossbeam-utils", -] - -[[package]] -name = "const-oid" -version = "0.9.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" - -[[package]] -name = "core2" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b49ba7ef1ad6107f8824dbe97de947cbaac53c44e7f9756a1fba0d37c1eec505" -dependencies = [ - "memchr", -] - -[[package]] -name = "cpufeatures" -version = "0.2.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" -dependencies = [ - "libc", -] - -[[package]] -name = "crossbeam-utils" -version = "0.8.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" - -[[package]] -name = "crypto-common" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" -dependencies = [ - "generic-array", - "typenum", -] - -[[package]] -name = "curve25519-dalek" -version = "4.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" -dependencies = [ - "cfg-if", - "cpufeatures", - "curve25519-dalek-derive", - "digest", - "fiat-crypto", - "rustc_version", - "subtle", - "zeroize", -] - -[[package]] -name = "curve25519-dalek-derive" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.72", -] - -[[package]] -name = "data-encoding" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" - -[[package]] -name = "data-encoding-macro" -version = "0.1.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1559b6cba622276d6d63706db152618eeb15b89b3e4041446b05876e352e639" -dependencies = [ - "data-encoding", - "data-encoding-macro-internal", -] - -[[package]] -name = "data-encoding-macro-internal" -version = "0.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "332d754c0af53bc87c108fed664d121ecf59207ec4196041f04d6ab9002ad33f" -dependencies = [ - "data-encoding", - "syn 1.0.109", -] - -[[package]] -name = "der" -version = "0.7.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" -dependencies = [ - "const-oid", - "zeroize", -] - -[[package]] -name = "digest" -version = "0.10.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" -dependencies = [ - "block-buffer", - "crypto-common", - "subtle", -] - -[[package]] -name = "doc-comment" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" - -[[package]] -name = "ed25519" -version = "2.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" -dependencies = [ - "pkcs8", - "signature", -] - -[[package]] -name = "ed25519-dalek" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a3daa8e81a3963a60642bcc1f90a670680bd4a77535faa384e9d1c79d620871" -dependencies = [ - "curve25519-dalek", - "ed25519", - "rand_core", - "serde", - "sha2", - "subtle", - "zeroize", -] - -[[package]] -name = "either" -version = "1.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" - -[[package]] -name = "enclave-core" -version = "0.1.0" -dependencies = [ - "async-std", - "fhe", - "fhe-traits", - "fhe-util", - "libp2p", -] - -[[package]] -name = "equivalent" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" - -[[package]] -name = "errno" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" -dependencies = [ - "libc", - "windows-sys 0.52.0", -] - -[[package]] -name = "ethnum" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b90ca2580b73ab6a1f724b76ca11ab632df820fd6040c336200d2c1df7b3c82c" - -[[package]] -name = "event-listener" -version = "2.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" - -[[package]] -name = "event-listener" -version = "5.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6032be9bd27023a771701cc49f9f053c751055f71efb2e0ae5c15809093675ba" -dependencies = [ - "concurrent-queue", - "parking", - "pin-project-lite", -] - -[[package]] -name = "event-listener-strategy" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f214dc438f977e6d4e3500aaa277f5ad94ca83fbbd9b1a15713ce2344ccc5a1" -dependencies = [ - "event-listener 5.3.1", - "pin-project-lite", -] - -[[package]] -name = "fastrand" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" -dependencies = [ - "instant", -] - -[[package]] -name = "fastrand" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" - -[[package]] -name = "fhe" -version = "0.1.0-beta.7" -source = "git+https://github.com/gnosisguild/fhe.rs#9624766dcfbb40ecfb01147f59c2f6292c447707" -dependencies = [ - "doc-comment", - "fhe-math", - "fhe-traits", - "fhe-util", - "itertools", - "ndarray", - "num-bigint", - "num-traits", - "prost", - "prost-build", - "rand", - "rand_chacha", - "serde", - "thiserror", - "zeroize", - "zeroize_derive", -] - -[[package]] -name = "fhe-math" -version = "0.1.0-beta.7" -source = "git+https://github.com/gnosisguild/fhe.rs#9624766dcfbb40ecfb01147f59c2f6292c447707" -dependencies = [ - "ethnum", - "fhe-traits", - "fhe-util", - "itertools", - "ndarray", - "num-bigint", - "num-bigint-dig", - "num-traits", - "prost", - "prost-build", - "rand", - "rand_chacha", - "sha2", - "thiserror", - "zeroize", -] - -[[package]] -name = "fhe-traits" -version = "0.1.0-beta.7" -source = "git+https://github.com/gnosisguild/fhe.rs#9624766dcfbb40ecfb01147f59c2f6292c447707" -dependencies = [ - "rand", -] - -[[package]] -name = "fhe-util" -version = "0.1.0-beta.7" -source = "git+https://github.com/gnosisguild/fhe.rs#9624766dcfbb40ecfb01147f59c2f6292c447707" -dependencies = [ - "itertools", - "num-bigint-dig", - "num-traits", - "rand", -] - -[[package]] -name = "fiat-crypto" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" - -[[package]] -name = "fixedbitset" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" - -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - -[[package]] -name = "form_urlencoded" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" -dependencies = [ - "percent-encoding", -] - -[[package]] -name = "futures" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" -dependencies = [ - "futures-channel", - "futures-core", - "futures-executor", - "futures-io", - "futures-sink", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-channel" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" -dependencies = [ - "futures-core", - "futures-sink", -] - -[[package]] -name = "futures-core" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" - -[[package]] -name = "futures-executor" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" -dependencies = [ - "futures-core", - "futures-task", - "futures-util", - "num_cpus", -] - -[[package]] -name = "futures-io" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" - -[[package]] -name = "futures-lite" -version = "1.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49a9d51ce47660b1e808d3c990b4709f2f415d928835a17dfd16991515c46bce" -dependencies = [ - "fastrand 1.9.0", - "futures-core", - "futures-io", - "memchr", - "parking", - "pin-project-lite", - "waker-fn", -] - -[[package]] -name = "futures-lite" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52527eb5074e35e9339c6b4e8d12600c7128b68fb25dcb9fa9dec18f7c25f3a5" -dependencies = [ - "fastrand 2.1.0", - "futures-core", - "futures-io", - "parking", - "pin-project-lite", -] - -[[package]] -name = "futures-macro" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.72", -] - -[[package]] -name = "futures-sink" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" - -[[package]] -name = "futures-task" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" - -[[package]] -name = "futures-timer" -version = "3.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24" - -[[package]] -name = "futures-util" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" -dependencies = [ - "futures-channel", - "futures-core", - "futures-io", - "futures-macro", - "futures-sink", - "futures-task", - "memchr", - "pin-project-lite", - "pin-utils", - "slab", -] - -[[package]] -name = "generic-array" -version = "0.14.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" -dependencies = [ - "typenum", - "version_check", -] - -[[package]] -name = "getrandom" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" -dependencies = [ - "cfg-if", - "libc", - "wasi", -] - -[[package]] -name = "gloo-timers" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b995a66bb87bebce9a0f4a95aed01daca4872c050bfcb21653361c03bc35e5c" -dependencies = [ - "futures-channel", - "futures-core", - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "hashbrown" -version = "0.14.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" -dependencies = [ - "ahash", - "allocator-api2", -] - -[[package]] -name = "heck" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" - -[[package]] -name = "hermit-abi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" - -[[package]] -name = "hermit-abi" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" - -[[package]] -name = "hkdf" -version = "0.12.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" -dependencies = [ - "hmac", -] - -[[package]] -name = "hmac" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" -dependencies = [ - "digest", -] - -[[package]] -name = "idna" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" -dependencies = [ - "unicode-bidi", - "unicode-normalization", -] - -[[package]] -name = "indexmap" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de3fc2e30ba82dd1b3911c8de1ffc143c74a914a14e99514d7637e3099df5ea0" -dependencies = [ - "equivalent", - "hashbrown", -] - -[[package]] -name = "instant" -version = "0.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "io-lifetimes" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" -dependencies = [ - "hermit-abi 0.3.9", - "libc", - "windows-sys 0.48.0", -] - -[[package]] -name = "itertools" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" -dependencies = [ - "either", -] - -[[package]] -name = "js-sys" -version = "0.3.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" -dependencies = [ - "wasm-bindgen", -] - -[[package]] -name = "kv-log-macro" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0de8b303297635ad57c9f5059fd9cee7a47f8e8daa09df0fcd07dd39fb22977f" -dependencies = [ - "log", -] - -[[package]] -name = "lazy_static" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" -dependencies = [ - "spin", -] - -[[package]] -name = "libc" -version = "0.2.155" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" - -[[package]] -name = "libm" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" - -[[package]] -name = "libp2p" -version = "0.53.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "681fb3f183edfbedd7a57d32ebe5dcdc0b9f94061185acf3c30249349cc6fc99" -dependencies = [ - "bytes", - "either", - "futures", - "futures-timer", - "getrandom", - "instant", - "libp2p-allow-block-list", - "libp2p-connection-limits", - "libp2p-core", - "libp2p-identity", - "libp2p-swarm", - "multiaddr", - "pin-project", - "rw-stream-sink", - "thiserror", -] - -[[package]] -name = "libp2p-allow-block-list" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "107b238b794cb83ab53b74ad5dcf7cca3200899b72fe662840cfb52f5b0a32e6" -dependencies = [ - "libp2p-core", - "libp2p-identity", - "libp2p-swarm", - "void", -] - -[[package]] -name = "libp2p-connection-limits" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7cd50a78ccfada14de94cbacd3ce4b0138157f376870f13d3a8422cd075b4fd" -dependencies = [ - "libp2p-core", - "libp2p-identity", - "libp2p-swarm", - "void", -] - -[[package]] -name = "libp2p-core" -version = "0.41.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5a8920cbd8540059a01950c1e5c96ea8d89eb50c51cd366fc18bdf540a6e48f" -dependencies = [ - "either", - "fnv", - "futures", - "futures-timer", - "libp2p-identity", - "multiaddr", - "multihash", - "multistream-select", - "once_cell", - "parking_lot", - "pin-project", - "quick-protobuf", - "rand", - "rw-stream-sink", - "smallvec", - "thiserror", - "tracing", - "unsigned-varint 0.8.0", - "void", - "web-time", -] - -[[package]] -name = "libp2p-identity" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55cca1eb2bc1fd29f099f3daaab7effd01e1a54b7c577d0ed082521034d912e8" -dependencies = [ - "bs58", - "ed25519-dalek", - "hkdf", - "multihash", - "quick-protobuf", - "rand", - "sha2", - "thiserror", - "tracing", - "zeroize", -] - -[[package]] -name = "libp2p-swarm" -version = "0.44.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80cae6cb75f89dbca53862f9ebe0b9f463aa7b302762fcfaafb9e51dcc9b0f7e" -dependencies = [ - "either", - "fnv", - "futures", - "futures-timer", - "instant", - "libp2p-core", - "libp2p-identity", - "lru", - "multistream-select", - "once_cell", - "rand", - "smallvec", - "tracing", - "void", -] - -[[package]] -name = "linux-raw-sys" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" - -[[package]] -name = "linux-raw-sys" -version = "0.4.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" - -[[package]] -name = "lock_api" -version = "0.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" -dependencies = [ - "autocfg", - "scopeguard", -] - -[[package]] -name = "log" -version = "0.4.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" -dependencies = [ - "value-bag", -] - -[[package]] -name = "lru" -version = "0.12.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37ee39891760e7d94734f6f63fedc29a2e4a152f836120753a72503f09fcf904" -dependencies = [ - "hashbrown", -] - -[[package]] -name = "matrixmultiply" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9380b911e3e96d10c1f415da0876389aaf1b56759054eeb0de7df940c456ba1a" -dependencies = [ - "autocfg", - "rawpointer", -] - -[[package]] -name = "memchr" -version = "2.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" - -[[package]] -name = "multiaddr" -version = "0.18.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b852bc02a2da5feed68cd14fa50d0774b92790a5bdbfa932a813926c8472070" -dependencies = [ - "arrayref", - "byteorder", - "data-encoding", - "libp2p-identity", - "multibase", - "multihash", - "percent-encoding", - "serde", - "static_assertions", - "unsigned-varint 0.7.2", - "url", -] - -[[package]] -name = "multibase" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b3539ec3c1f04ac9748a260728e855f261b4977f5c3406612c884564f329404" -dependencies = [ - "base-x", - "data-encoding", - "data-encoding-macro", -] - -[[package]] -name = "multihash" -version = "0.19.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "076d548d76a0e2a0d4ab471d0b1c36c577786dfc4471242035d97a12a735c492" -dependencies = [ - "core2", - "unsigned-varint 0.7.2", -] - -[[package]] -name = "multimap" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "defc4c55412d89136f966bbb339008b474350e5e6e78d2714439c386b3137a03" - -[[package]] -name = "multistream-select" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea0df8e5eec2298a62b326ee4f0d7fe1a6b90a09dfcf9df37b38f947a8c42f19" -dependencies = [ - "bytes", - "futures", - "log", - "pin-project", - "smallvec", - "unsigned-varint 0.7.2", -] - -[[package]] -name = "ndarray" -version = "0.15.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adb12d4e967ec485a5f71c6311fe28158e9d6f4bc4a447b474184d0f91a8fa32" -dependencies = [ - "matrixmultiply", - "num-complex", - "num-integer", - "num-traits", - "rawpointer", -] - -[[package]] -name = "num-bigint" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" -dependencies = [ - "num-integer", - "num-traits", -] - -[[package]] -name = "num-bigint-dig" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc84195820f291c7697304f3cbdadd1cb7199c0efc917ff5eafd71225c136151" -dependencies = [ - "byteorder", - "lazy_static", - "libm", - "num-integer", - "num-iter", - "num-traits", - "rand", - "serde", - "smallvec", -] - -[[package]] -name = "num-complex" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" -dependencies = [ - "num-traits", -] - -[[package]] -name = "num-integer" -version = "0.1.46" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" -dependencies = [ - "num-traits", -] - -[[package]] -name = "num-iter" -version = "0.1.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" -dependencies = [ - "autocfg", - "num-integer", - "num-traits", -] - -[[package]] -name = "num-traits" -version = "0.2.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" -dependencies = [ - "autocfg", -] - -[[package]] -name = "num_cpus" -version = "1.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" -dependencies = [ - "hermit-abi 0.3.9", - "libc", -] - -[[package]] -name = "once_cell" -version = "1.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" - -[[package]] -name = "parking" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae" - -[[package]] -name = "parking_lot" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" -dependencies = [ - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "smallvec", - "windows-targets 0.52.6", -] - -[[package]] -name = "percent-encoding" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" - -[[package]] -name = "petgraph" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" -dependencies = [ - "fixedbitset", - "indexmap", -] - -[[package]] -name = "pin-project" -version = "1.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" -dependencies = [ - "pin-project-internal", -] - -[[package]] -name = "pin-project-internal" -version = "1.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.72", -] - -[[package]] -name = "pin-project-lite" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" - -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - -[[package]] -name = "piper" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae1d5c74c9876f070d3e8fd503d748c7d974c3e48da8f41350fa5222ef9b4391" -dependencies = [ - "atomic-waker", - "fastrand 2.1.0", - "futures-io", -] - -[[package]] -name = "pkcs8" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" -dependencies = [ - "der", - "spki", -] - -[[package]] -name = "polling" -version = "2.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b2d323e8ca7996b3e23126511a523f7e62924d93ecd5ae73b333815b0eb3dce" -dependencies = [ - "autocfg", - "bitflags 1.3.2", - "cfg-if", - "concurrent-queue", - "libc", - "log", - "pin-project-lite", - "windows-sys 0.48.0", -] - -[[package]] -name = "polling" -version = "3.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3ed00ed3fbf728b5816498ecd316d1716eecaced9c0c8d2c5a6740ca214985b" -dependencies = [ - "cfg-if", - "concurrent-queue", - "hermit-abi 0.4.0", - "pin-project-lite", - "rustix 0.38.34", - "tracing", - "windows-sys 0.52.0", -] - -[[package]] -name = "ppv-lite86" -version = "0.2.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" -dependencies = [ - "zerocopy", -] - -[[package]] -name = "prettyplease" -version = "0.2.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f12335488a2f3b0a83b14edad48dca9879ce89b2edd10e80237e4e852dd645e" -dependencies = [ - "proc-macro2", - "syn 2.0.72", -] - -[[package]] -name = "proc-macro2" -version = "1.0.86" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "prost" -version = "0.12.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "deb1435c188b76130da55f17a466d252ff7b1418b2ad3e037d127b94e3411f29" -dependencies = [ - "bytes", - "prost-derive", -] - -[[package]] -name = "prost-build" -version = "0.12.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22505a5c94da8e3b7c2996394d1c933236c4d743e81a410bcca4e6989fc066a4" -dependencies = [ - "bytes", - "heck", - "itertools", - "log", - "multimap", - "once_cell", - "petgraph", - "prettyplease", - "prost", - "prost-types", - "regex", - "syn 2.0.72", - "tempfile", -] - -[[package]] -name = "prost-derive" -version = "0.12.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81bddcdb20abf9501610992b6759a4c888aef7d1a7247ef75e2404275ac24af1" -dependencies = [ - "anyhow", - "itertools", - "proc-macro2", - "quote", - "syn 2.0.72", -] - -[[package]] -name = "prost-types" -version = "0.12.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9091c90b0a32608e984ff2fa4091273cbdd755d54935c51d520887f4a1dbd5b0" -dependencies = [ - "prost", -] - -[[package]] -name = "quick-protobuf" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d6da84cc204722a989e01ba2f6e1e276e190f22263d0cb6ce8526fcdb0d2e1f" -dependencies = [ - "byteorder", -] - -[[package]] -name = "quote" -version = "1.0.36" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "rand" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "libc", - "rand_chacha", - "rand_core", -] - -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core", -] - -[[package]] -name = "rand_core" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "getrandom", -] - -[[package]] -name = "rawpointer" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3" - -[[package]] -name = "redox_syscall" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4" -dependencies = [ - "bitflags 2.6.0", -] - -[[package]] -name = "regex" -version = "1.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" -dependencies = [ - "aho-corasick", - "memchr", - "regex-automata", - "regex-syntax", -] - -[[package]] -name = "regex-automata" -version = "0.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" - -[[package]] -name = "rustc_version" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" -dependencies = [ - "semver", -] - -[[package]] -name = "rustix" -version = "0.37.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fea8ca367a3a01fe35e6943c400addf443c0f57670e6ec51196f71a4b8762dd2" -dependencies = [ - "bitflags 1.3.2", - "errno", - "io-lifetimes", - "libc", - "linux-raw-sys 0.3.8", - "windows-sys 0.48.0", -] - -[[package]] -name = "rustix" -version = "0.38.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" -dependencies = [ - "bitflags 2.6.0", - "errno", - "libc", - "linux-raw-sys 0.4.14", - "windows-sys 0.52.0", -] - -[[package]] -name = "rw-stream-sink" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8c9026ff5d2f23da5e45bbc283f156383001bfb09c4e44256d02c1a685fe9a1" -dependencies = [ - "futures", - "pin-project", - "static_assertions", -] - -[[package]] -name = "scopeguard" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" - -[[package]] -name = "semver" -version = "1.0.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" - -[[package]] -name = "serde" -version = "1.0.204" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.204" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.72", -] - -[[package]] -name = "sha2" -version = "0.10.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] - -[[package]] -name = "signature" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" -dependencies = [ - "rand_core", -] - -[[package]] -name = "slab" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" -dependencies = [ - "autocfg", -] - -[[package]] -name = "smallvec" -version = "1.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" - -[[package]] -name = "socket2" -version = "0.4.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d" -dependencies = [ - "libc", - "winapi", -] - -[[package]] -name = "spin" -version = "0.9.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" - -[[package]] -name = "spki" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" -dependencies = [ - "base64ct", - "der", -] - -[[package]] -name = "static_assertions" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" - -[[package]] -name = "subtle" -version = "2.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" - -[[package]] -name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syn" -version = "2.0.72" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc4b9b9bf2add8093d3f2c0204471e951b2285580335de42f9d2534f3ae7a8af" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "tempfile" -version = "3.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8fcd239983515c23a32fb82099f97d0b11b8c72f654ed659363a95c3dad7a53" -dependencies = [ - "cfg-if", - "fastrand 2.1.0", - "once_cell", - "rustix 0.38.34", - "windows-sys 0.52.0", -] - -[[package]] -name = "thiserror" -version = "1.0.63" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.63" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.72", -] - -[[package]] -name = "tinyvec" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" -dependencies = [ - "tinyvec_macros", -] - -[[package]] -name = "tinyvec_macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" - -[[package]] -name = "tracing" -version = "0.1.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" -dependencies = [ - "pin-project-lite", - "tracing-attributes", - "tracing-core", -] - -[[package]] -name = "tracing-attributes" -version = "0.1.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.72", -] - -[[package]] -name = "tracing-core" -version = "0.1.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" -dependencies = [ - "once_cell", -] - -[[package]] -name = "typenum" -version = "1.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" - -[[package]] -name = "unicode-bidi" -version = "0.3.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" - -[[package]] -name = "unicode-ident" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" - -[[package]] -name = "unicode-normalization" -version = "0.1.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" -dependencies = [ - "tinyvec", -] - -[[package]] -name = "unsigned-varint" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6889a77d49f1f013504cec6bf97a2c730394adedaeb1deb5ea08949a50541105" - -[[package]] -name = "unsigned-varint" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb066959b24b5196ae73cb057f45598450d2c5f71460e98c49b738086eff9c06" - -[[package]] -name = "url" -version = "2.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" -dependencies = [ - "form_urlencoded", - "idna", - "percent-encoding", -] - -[[package]] -name = "value-bag" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a84c137d37ab0142f0f2ddfe332651fdbf252e7b7dbb4e67b6c1f1b2e925101" - -[[package]] -name = "version_check" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" - -[[package]] -name = "void" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" - -[[package]] -name = "waker-fn" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "317211a0dc0ceedd78fb2ca9a44aed3d7b9b26f81870d485c07122b4350673b7" - -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - -[[package]] -name = "wasm-bindgen" -version = "0.2.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" -dependencies = [ - "cfg-if", - "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" -dependencies = [ - "bumpalo", - "log", - "once_cell", - "proc-macro2", - "quote", - "syn 2.0.72", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-futures" -version = "0.4.42" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" -dependencies = [ - "cfg-if", - "js-sys", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.72", - "wasm-bindgen-backend", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" - -[[package]] -name = "web-sys" -version = "0.3.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "web-time" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "windows-sys" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" -dependencies = [ - "windows-targets 0.48.5", -] - -[[package]] -name = "windows-sys" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" -dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-targets" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" -dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", -] - -[[package]] -name = "windows-targets" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" -dependencies = [ - "windows_aarch64_gnullvm 0.52.6", - "windows_aarch64_msvc 0.52.6", - "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm", - "windows_i686_msvc 0.52.6", - "windows_x86_64_gnu 0.52.6", - "windows_x86_64_gnullvm 0.52.6", - "windows_x86_64_msvc 0.52.6", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" - -[[package]] -name = "windows_i686_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" - -[[package]] -name = "windows_i686_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" - -[[package]] -name = "zerocopy" -version = "0.7.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" -dependencies = [ - "byteorder", - "zerocopy-derive", -] - -[[package]] -name = "zerocopy-derive" -version = "0.7.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.72", -] - -[[package]] -name = "zeroize" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" - -[[package]] -name = "zeroize_derive" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.72", -] diff --git a/packages/ciphernode/core/Cargo.toml b/packages/ciphernode/core/Cargo.toml index e1f4ddfe..5ef98a85 100644 --- a/packages/ciphernode/core/Cargo.toml +++ b/packages/ciphernode/core/Cargo.toml @@ -1,4 +1,5 @@ [package] +# we have to name this other than core for disambiguation name = "enclave-core" version = "0.1.0" edition = "2021" @@ -8,6 +9,7 @@ repository = "https://github.com/gnosisguild/enclave/packages/ciphernode" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +p2p = { path = "../p2p" } async-std = "1.12.0" libp2p = "0.53.2" fhe = { git = "https://github.com/gnosisguild/fhe.rs", version = "0.1.0-beta.7" } diff --git a/packages/ciphernode/core/src/p2p.rs b/packages/ciphernode/core/src/p2p.rs new file mode 100644 index 00000000..10e54ebb --- /dev/null +++ b/packages/ciphernode/core/src/p2p.rs @@ -0,0 +1,11 @@ +use actix::{Actor, Context}; + +use p2p::EnclaveRouter; +pub struct P2pActor; + + +impl Actor for P2pActor{ + type Context = Context; +} + + diff --git a/packages/ciphernode/enclave_node/Cargo.toml b/packages/ciphernode/enclave_node/Cargo.toml index fe310370..0a32f8bc 100644 --- a/packages/ciphernode/enclave_node/Cargo.toml +++ b/packages/ciphernode/enclave_node/Cargo.toml @@ -14,4 +14,4 @@ async-std = "1.12.0" fhe = { git = "https://github.com/gnosisguild/fhe.rs", version = "0.1.0-beta.7" } fhe-traits = { git = "https://github.com/gnosisguild/fhe.rs", version = "0.1.0-beta.7" } fhe-util = { git = "https://github.com/gnosisguild/fhe.rs", version = "0.1.0-beta.7" } -tokio = { version = "1.38", features = ["full"] } \ No newline at end of file +tokio = { version = "1.38", features = ["full"] } diff --git a/packages/ciphernode/enclave_node/src/main.rs b/packages/ciphernode/enclave_node/src/main.rs index 466d6e63..cbd75802 100644 --- a/packages/ciphernode/enclave_node/src/main.rs +++ b/packages/ciphernode/enclave_node/src/main.rs @@ -1,7 +1,10 @@ -// use p2p::EnclaveRouter; use std::error::Error; -use tokio; +use p2p::EnclaveRouter; +use tokio::{ + self, + io::{self, AsyncBufReadExt, BufReader}, +}; const OWO: &str = r#" ___ ___ ___ ___ ___ /\__\ /\ \ /\__\ /\ \ ___ /\__\ @@ -19,20 +22,30 @@ const OWO: &str = r#" #[tokio::main] async fn main() -> Result<(), Box> { - // boot up p2p network + // boot up p2p network - // boot up ether client + // boot up ether client - // start main loop + // start main loop - //let ether = eth::EtherClient::new("test".to_string()); + //let ether = eth::EtherClient::new("test".to_string()); println!("\n\n\n\n\n{}", OWO); println!("\n\n\n\n"); - - // let mut p2p = EnclaveRouter::new()?; - // p2p.connect_swarm("mdns".to_string())?; - // p2p.join_topic("enclave-keygen-01")?; - // p2p.start().await?; println!("Hello, cipher world!"); - Ok(()) + + let (mut p2p, tx, mut rx) = EnclaveRouter::new()?; + p2p.connect_swarm("mdns".to_string())?; + p2p.join_topic("enclave-keygen-01")?; + let mut stdin = BufReader::new(io::stdin()).lines(); + tokio::spawn(async move { p2p.start().await }); + tokio::spawn(async move { + while let Some(msg) = rx.recv().await { + println!("msg: {}", String::from_utf8(msg).unwrap()); + } + }); + loop { + if let Ok(Some(line)) = stdin.next_line().await { + tx.send(line.as_bytes().to_vec().clone()).await.unwrap(); + } + } } diff --git a/packages/ciphernode/p2p/src/lib.rs b/packages/ciphernode/p2p/src/lib.rs index 4a6a4267..d55ab000 100644 --- a/packages/ciphernode/p2p/src/lib.rs +++ b/packages/ciphernode/p2p/src/lib.rs @@ -3,29 +3,37 @@ #![warn(missing_docs, unused_imports)] use futures::stream::StreamExt; -use libp2p::{gossipsub, mdns, noise, swarm::NetworkBehaviour, swarm::SwarmEvent, tcp, yamux, identity, Swarm}; +use libp2p::{ + gossipsub, identity, mdns, noise, swarm::NetworkBehaviour, swarm::SwarmEvent, tcp, yamux, +}; use std::collections::hash_map::DefaultHasher; use std::error::Error; use std::hash::{Hash, Hasher}; use std::time::Duration; -use tokio::{io, io::AsyncBufReadExt, select}; +use tokio::sync::mpsc::{channel, Receiver, Sender}; +use tokio::{io, select}; use tracing_subscriber::EnvFilter; #[derive(NetworkBehaviour)] -struct MyBehaviour { +pub struct MyBehaviour { gossipsub: gossipsub::Behaviour, mdns: mdns::tokio::Behaviour, } + pub struct EnclaveRouter { - pub identity: Option, - pub gossipsub_config: gossipsub::Config, - pub swarm: Option>, - pub topic: Option, + pub identity: Option, + pub gossipsub_config: gossipsub::Config, + pub swarm: Option>, + pub topic: Option, + evt_tx: Sender>, + cmd_rx: Receiver> } impl EnclaveRouter { - pub fn new() -> Result> { + pub fn new() -> Result<(Self, Sender>, Receiver>), Box> { + let (evt_tx, evt_rx) = channel(100); // TODO : tune this param + let (cmd_tx, cmd_rx) = channel(100); // TODO : tune this param let message_id_fn = |message: &gossipsub::Message| { let mut s = DefaultHasher::new(); message.data.hash(&mut s); @@ -40,103 +48,123 @@ impl EnclaveRouter { .build() .map_err(|msg| io::Error::new(io::ErrorKind::Other, msg))?; - Ok(Self { identity: None, gossipsub_config, swarm: None, topic: None }) + Ok(( + Self { + identity: None, + gossipsub_config, + swarm: None, + topic: None, + evt_tx, + cmd_rx + }, + cmd_tx, + evt_rx, + )) } pub fn with_identiy(&mut self, keypair: identity::Keypair) { - self.identity = Some(keypair); + self.identity = Some(keypair); } pub fn connect_swarm(&mut self, discovery_type: String) -> Result<&Self, Box> { - match discovery_type.as_str() { - "mdns" => { - let _ = tracing_subscriber::fmt() - .with_env_filter(EnvFilter::from_default_env()) - .try_init(); - - // TODO: Use key if assigned already - let mut swarm = libp2p::SwarmBuilder::with_new_identity() - .with_tokio() - .with_tcp( - tcp::Config::default(), - noise::Config::new, - yamux::Config::default, - )? - .with_quic() - .with_behaviour(|key| { - let gossipsub = gossipsub::Behaviour::new( - gossipsub::MessageAuthenticity::Signed(key.clone()), - self.gossipsub_config.clone(), - )?; - - let mdns = - mdns::tokio::Behaviour::new(mdns::Config::default(), key.public().to_peer_id())?; - Ok(MyBehaviour { gossipsub, mdns }) - })? - .with_swarm_config(|c| c.with_idle_connection_timeout(Duration::from_secs(60))) - .build(); - self.swarm = Some(swarm); - }, - _ => println!("Defaulting to MDNS discovery"), - } - Ok(self) + match discovery_type.as_str() { + "mdns" => { + let _ = tracing_subscriber::fmt() + .with_env_filter(EnvFilter::from_default_env()) + .try_init(); + + // TODO: Use key if assigned already + let mut swarm = libp2p::SwarmBuilder::with_new_identity() + .with_tokio() + .with_tcp( + tcp::Config::default(), + noise::Config::new, + yamux::Config::default, + )? + .with_quic() + .with_behaviour(|key| { + let gossipsub = gossipsub::Behaviour::new( + gossipsub::MessageAuthenticity::Signed(key.clone()), + self.gossipsub_config.clone(), + )?; + + let mdns = mdns::tokio::Behaviour::new( + mdns::Config::default(), + key.public().to_peer_id(), + )?; + Ok(MyBehaviour { gossipsub, mdns }) + })? + .with_swarm_config(|c| c.with_idle_connection_timeout(Duration::from_secs(60))) + .build(); + self.swarm = Some(swarm); + } + _ => println!("Defaulting to MDNS discovery"), + } + Ok(self) } pub fn join_topic(&mut self, topic_name: &str) -> Result<&Self, Box> { - let topic = gossipsub::IdentTopic::new(topic_name); - self.topic = Some(topic.clone()); - self.swarm.as_mut().unwrap().behaviour_mut().gossipsub.subscribe(&topic)?; - Ok(self) + let topic = gossipsub::IdentTopic::new(topic_name); + self.topic = Some(topic.clone()); + self.swarm + .as_mut() + .unwrap() + .behaviour_mut() + .gossipsub + .subscribe(&topic)?; + Ok(self) } - pub async fn start(&mut self) -> Result<(), Box> { - // Read full lines from stdin - let mut stdin = io::BufReader::new(io::stdin()).lines(); - - self.swarm.as_mut().unwrap().listen_on("/ip4/0.0.0.0/udp/0/quic-v1".parse()?)?; - self.swarm.as_mut().unwrap().listen_on("/ip4/0.0.0.0/tcp/0".parse()?)?; - loop { - select! { - Ok(Some(line)) = stdin.next_line() => { - println!("Generating Public Key Share"); - let node_bfv = bfv::EnclaveBFV::new("test".to_string()); - if let Err(e) = self.swarm.as_mut().unwrap() - .behaviour_mut().gossipsub - .publish(self.topic.as_mut().unwrap().clone(), line.as_bytes()) { - println!("Publish error: {e:?}"); - } - } - event = self.swarm.as_mut().unwrap().select_next_some() => match event { - SwarmEvent::Behaviour(MyBehaviourEvent::Mdns(mdns::Event::Discovered(list))) => { - for (peer_id, _multiaddr) in list { - println!("mDNS discovered a new peer: {peer_id}"); - self.swarm.as_mut().unwrap().behaviour_mut().gossipsub.add_explicit_peer(&peer_id); - } - }, - SwarmEvent::Behaviour(MyBehaviourEvent::Mdns(mdns::Event::Expired(list))) => { - for (peer_id, _multiaddr) in list { - println!("mDNS discover peer has expired: {peer_id}"); - self.swarm.as_mut().unwrap().behaviour_mut().gossipsub.remove_explicit_peer(&peer_id); - } - }, - SwarmEvent::Behaviour(MyBehaviourEvent::Gossipsub(gossipsub::Event::Message { - propagation_source: peer_id, - message_id: id, - message, - })) => { - println!( - "Got message: '{}' with id: {id} from peer: {peer_id}", - String::from_utf8_lossy(&message.data), - ); - let node_bfv = bfv::EnclaveBFV::new("test".to_string()); - }, - SwarmEvent::NewListenAddr { address, .. } => { - println!("Local node is listening on {address}"); - } - _ => {} - } - } - } + pub async fn start(&mut self) -> Result<(), Box> { + self.swarm + .as_mut() + .unwrap() + .listen_on("/ip4/0.0.0.0/udp/0/quic-v1".parse()?)?; + self.swarm + .as_mut() + .unwrap() + .listen_on("/ip4/0.0.0.0/tcp/0".parse()?)?; + loop { + select! { + Some(line) = self.cmd_rx.recv() => { + println!("Receiving input"); + if let Err(e) = self.swarm.as_mut().unwrap() + .behaviour_mut().gossipsub + .publish(self.topic.as_mut().unwrap().clone(), line) { + println!("Publish error: {e:?}"); + } + } + event = self.swarm.as_mut().unwrap().select_next_some() => match event { + SwarmEvent::Behaviour(MyBehaviourEvent::Mdns(mdns::Event::Discovered(list))) => { + for (peer_id, _multiaddr) in list { + println!("mDNS discovered a new peer: {peer_id}"); + self.swarm.as_mut().unwrap().behaviour_mut().gossipsub.add_explicit_peer(&peer_id); + } + }, + SwarmEvent::Behaviour(MyBehaviourEvent::Mdns(mdns::Event::Expired(list))) => { + for (peer_id, _multiaddr) in list { + println!("mDNS discover peer has expired: {peer_id}"); + self.swarm.as_mut().unwrap().behaviour_mut().gossipsub.remove_explicit_peer(&peer_id); + } + }, + SwarmEvent::Behaviour(MyBehaviourEvent::Gossipsub(gossipsub::Event::Message { + propagation_source: peer_id, + message_id: id, + message, + })) => { + println!( + "Got message: '{}' with id: {id} from peer: {peer_id}", + String::from_utf8_lossy(&message.data), + ); + self.evt_tx.send(message.data).await?; + }, + SwarmEvent::NewListenAddr { address, .. } => { + println!("Local node is listening on {address}"); + } + _ => {} + } + } + } } } From e48b453558848ae94009d0a64d0f7db8032276ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=B3=CE=BB?= Date: Fri, 23 Aug 2024 10:29:16 +1000 Subject: [PATCH 13/87] Add some information about actors and their intent (#13) * Add some information about actors and their intent * Add comment --- packages/ciphernode/core/src/committee.rs | 8 +++---- packages/ciphernode/core/src/committee_key.rs | 6 ++++++ .../ciphernode/core/src/enclave_contract.rs | 16 ++++++++++++++ packages/ciphernode/core/src/eventbus.rs | 6 ++++++ packages/ciphernode/core/src/fhe.rs | 11 +++++++++- packages/ciphernode/core/src/lib.rs | 19 +++++++++++++---- packages/ciphernode/core/src/p2p.rs | 21 +++++++++++++++---- 7 files changed, 74 insertions(+), 13 deletions(-) create mode 100644 packages/ciphernode/core/src/enclave_contract.rs diff --git a/packages/ciphernode/core/src/committee.rs b/packages/ciphernode/core/src/committee.rs index 16a88a72..cae9920d 100644 --- a/packages/ciphernode/core/src/committee.rs +++ b/packages/ciphernode/core/src/committee.rs @@ -9,17 +9,17 @@ use crate::{ fhe::Fhe, }; -pub struct Committee { +pub struct CommitteeManager { bus: Addr, fhe: Addr, aggregators: HashMap>, } -impl Actor for Committee { +impl Actor for CommitteeManager { type Context = Context; } -impl Committee { +impl CommitteeManager { pub fn new(bus: Addr, fhe: Addr) -> Self { Self { bus, @@ -29,7 +29,7 @@ impl Committee { } } -impl Handler for Committee { +impl Handler for CommitteeManager { type Result = (); fn handle(&mut self, event: EnclaveEvent, _ctx: &mut Self::Context) -> Self::Result { diff --git a/packages/ciphernode/core/src/committee_key.rs b/packages/ciphernode/core/src/committee_key.rs index 9d6e7aeb..7004fa10 100644 --- a/packages/ciphernode/core/src/committee_key.rs +++ b/packages/ciphernode/core/src/committee_key.rs @@ -38,6 +38,12 @@ pub struct CommitteeKey { state: CommitteeKeyState, } +/// Aggregate PublicKey for a committee of nodes. This actor listens for KeyshareCreated events +/// around a particular e3_id and aggregates the public key based on this and once done broadcasts +/// a EnclaveEvent::PublicKeyAggregated event on the event bus. Note events are hashed and +/// identical events will not be triggered twice. +/// It is expected to change this mechanism as we work through adversarial scenarios and write tests +/// for them. impl CommitteeKey { pub fn new(fhe: Addr, bus: Addr, e3_id: E3id, nodecount: usize) -> Self { CommitteeKey { diff --git a/packages/ciphernode/core/src/enclave_contract.rs b/packages/ciphernode/core/src/enclave_contract.rs new file mode 100644 index 00000000..5639f562 --- /dev/null +++ b/packages/ciphernode/core/src/enclave_contract.rs @@ -0,0 +1,16 @@ + +use actix::{Actor, Context}; + +/// Manage an internal web3 instance and express protocol specific behaviour through the events it +/// accepts and emits to the EventBus +/// Monitor contract events using `contract.events().create_filter()` and rebroadcast to eventbus by +/// creating `EnclaveEvent` events +/// Delegate signing to a separate actor responsible for managing Eth keys +/// Accept eventbus events and forward as appropriate contract calls as required +pub struct EnclaveContract; + +impl Actor for EnclaveContract{ + type Context = Context; +} + + diff --git a/packages/ciphernode/core/src/eventbus.rs b/packages/ciphernode/core/src/eventbus.rs index d6b40cc9..9d63941f 100644 --- a/packages/ciphernode/core/src/eventbus.rs +++ b/packages/ciphernode/core/src/eventbus.rs @@ -22,6 +22,12 @@ impl Subscribe { #[rtype(result = "Vec")] pub struct GetHistory; + +/// Central EventBus for each node. Actors publish events to this bus by sending it EnclaveEvents. +/// All events sent to this bus are assumed to be published over the network via pubsub. +/// Other actors such as the P2p and Evm actor connect to outside services and control which events +/// actually get published as well as ensure that local events are not rebroadcast locally after +/// being published. pub struct EventBus { capture: bool, history: Vec, diff --git a/packages/ciphernode/core/src/fhe.rs b/packages/ciphernode/core/src/fhe.rs index c68edb24..73f8a93e 100644 --- a/packages/ciphernode/core/src/fhe.rs +++ b/packages/ciphernode/core/src/fhe.rs @@ -59,6 +59,9 @@ impl WrappedPublicKeyShare { } } +/// Wrapped PublicKey. This is wrapped to provide an inflection point +/// as we use this library elsewhere we only implement traits as we need them +/// and avoid exposing underlying structures from fhe.rs #[derive(Clone, Debug, PartialEq, Eq)] pub struct WrappedPublicKey(pub PublicKey); @@ -80,15 +83,21 @@ impl PartialOrd for WrappedPublicKey { } } - +/// Wrapped SecretKey. This is wrapped to provide an inflection point +/// as we use this library elsewhere we only implement traits as we need them +/// and avoid exposing underlying structures from fhe.rs +// We should favor consuming patterns and avoid cloning and copying this value around in memory. +// Underlying key Zeroizes on drop #[derive(PartialEq)] pub struct WrappedSecretKey(pub SecretKey); + impl WrappedSecretKey { pub fn unsafe_to_vec(&self) -> Vec { serialize_box_i64(self.0.coeffs.clone()) } } +/// Fhe library adaptor. All FHE computations should happen through this actor. pub struct Fhe { params: Arc, crp: CommonRandomPoly, diff --git a/packages/ciphernode/core/src/lib.rs b/packages/ciphernode/core/src/lib.rs index ca1f5c3e..9fc938ef 100644 --- a/packages/ciphernode/core/src/lib.rs +++ b/packages/ciphernode/core/src/lib.rs @@ -10,6 +10,8 @@ mod eventbus; mod events; mod fhe; mod ordered_set; +mod p2p; +mod enclave_contract; // pub struct Core { // pub name: String, @@ -34,7 +36,7 @@ mod tests { use crate::{ ciphernode::Ciphernode, - committee::Committee, + committee::CommitteeManager, data::Data, eventbus::{EventBus, GetHistory, Subscribe}, events::{ComputationRequested, E3id, EnclaveEvent, KeyshareCreated, PublicKeyAggregated}, @@ -94,8 +96,8 @@ mod tests { Ok((pk, rng)) } - fn setup_committee_manager(bus: Addr, fhe: Addr) -> Addr { - let committee = Committee::new(bus.clone(), fhe.clone()).start(); + fn setup_committee_manager(bus: Addr, fhe: Addr) -> Addr { + let committee = CommitteeManager::new(bus.clone(), fhe.clone()).start(); bus.do_send(Subscribe::new( "ComputationRequested", @@ -118,7 +120,7 @@ mod tests { } #[actix::test] - async fn test_ciphernode() -> Result<()> { + async fn test_public_key_aggregation() -> Result<()> { // Setup EventBus let bus = EventBus::new(true).start(); @@ -200,4 +202,13 @@ mod tests { Ok(()) } + + // TODO: Test p2p + fn test_p2p_event_broadcasting() { + // Setup two Vec channels to simulate libp2p + // 1. command channel + // 2. event channel + // Pass them to the p2p actor + // connect the p2p actor to the event bus actor and monitor which events are broadcast + } } diff --git a/packages/ciphernode/core/src/p2p.rs b/packages/ciphernode/core/src/p2p.rs index 10e54ebb..6a5e9bb2 100644 --- a/packages/ciphernode/core/src/p2p.rs +++ b/packages/ciphernode/core/src/p2p.rs @@ -1,11 +1,24 @@ +/// Actor for connecting to an libp2p client via it's mpsc channel interface +/// This Actor should be responsible for +/// 1. Sending and Recieving Vec messages with libp2p +/// 2. Converting between Vec and EnclaveEvents::Xxxxxxxxx() +/// 3. Broadcasting over the local eventbus +/// 4. Listening to the local eventbus for messages to be published to libp2p use actix::{Actor, Context}; - +use tokio::sync::mpsc::{Receiver, Sender}; use p2p::EnclaveRouter; -pub struct P2pActor; +pub struct P2p; -impl Actor for P2pActor{ +impl Actor for P2p{ type Context = Context; } - +impl P2p { + pub fn new() { + // Construct owning Libp2p module + } + pub fn from_channel(tx:Sender>, rx:Receiver>){ + // Construct from tx/rx + } +} From 66589edaf4ee4707efdd678eb61da9fbbc963fd1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=B3=CE=BB?= Date: Fri, 23 Aug 2024 12:05:20 +1000 Subject: [PATCH 14/87] Rename internals to make more sense (#14) --- packages/ciphernode/core/src/committee.rs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/packages/ciphernode/core/src/committee.rs b/packages/ciphernode/core/src/committee.rs index cae9920d..ee19f540 100644 --- a/packages/ciphernode/core/src/committee.rs +++ b/packages/ciphernode/core/src/committee.rs @@ -12,7 +12,7 @@ use crate::{ pub struct CommitteeManager { bus: Addr, fhe: Addr, - aggregators: HashMap>, + keys: HashMap>, } impl Actor for CommitteeManager { @@ -24,7 +24,7 @@ impl CommitteeManager { Self { bus, fhe, - aggregators: HashMap::new(), + keys: HashMap::new(), } } } @@ -35,8 +35,8 @@ impl Handler for CommitteeManager { fn handle(&mut self, event: EnclaveEvent, _ctx: &mut Self::Context) -> Self::Result { match event { EnclaveEvent::ComputationRequested { data, .. } => { - // start up a new aggregator - let aggregator = CommitteeKey::new( + // start up a new key + let key = CommitteeKey::new( self.fhe.clone(), self.bus.clone(), data.e3_id.clone(), @@ -44,20 +44,20 @@ impl Handler for CommitteeManager { ) .start(); - self.aggregators.insert(data.e3_id, aggregator); + self.keys.insert(data.e3_id, key); } EnclaveEvent::KeyshareCreated { data, .. } => { - if let Some(aggregator) = self.aggregators.get(&data.e3_id) { - aggregator.do_send(data); + if let Some(key) = self.keys.get(&data.e3_id) { + key.do_send(data); } }, EnclaveEvent::PublicKeyAggregated { data, .. } => { - let Some(aggregator) = self.aggregators.get(&data.e3_id) else { + let Some(key) = self.keys.get(&data.e3_id) else { return; }; - aggregator.do_send(Die); - self.aggregators.remove(&data.e3_id); + key.do_send(Die); + self.keys.remove(&data.e3_id); } // _ => (), } From 31d6872d3346f33dab414a055418166156866326 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=B3=CE=BB?= Date: Mon, 26 Aug 2024 11:25:26 +1000 Subject: [PATCH 15/87] Add serde serialization to events and wrapped FHE structures (#15) * Add serde serialization * Remove comment * Add comments * Tidy up --- packages/ciphernode/Cargo.lock | 9 +- packages/ciphernode/core/Cargo.toml | 1 + packages/ciphernode/core/src/events.rs | 30 ++--- packages/ciphernode/core/src/fhe.rs | 150 ++++++++++++++++++++++--- packages/ciphernode/core/src/lib.rs | 14 ++- 5 files changed, 166 insertions(+), 38 deletions(-) diff --git a/packages/ciphernode/Cargo.lock b/packages/ciphernode/Cargo.lock index dc3ae782..ff60f23a 100644 --- a/packages/ciphernode/Cargo.lock +++ b/packages/ciphernode/Cargo.lock @@ -910,6 +910,7 @@ dependencies = [ "rand", "rand_chacha", "secp256k1", + "serde", "sha2", "tokio", ] @@ -3350,18 +3351,18 @@ checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" [[package]] name = "serde" -version = "1.0.204" +version = "1.0.208" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12" +checksum = "cff085d2cb684faa248efb494c39b68e522822ac0de72ccf08109abde717cfb2" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.204" +version = "1.0.208" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" +checksum = "24008e81ff7613ed8e5ba0cfaf24e2c2f1e5b8a0495711e44fcd4882fca62bcf" dependencies = [ "proc-macro2", "quote", diff --git a/packages/ciphernode/core/Cargo.toml b/packages/ciphernode/core/Cargo.toml index 5ef98a85..8cc627e7 100644 --- a/packages/ciphernode/core/Cargo.toml +++ b/packages/ciphernode/core/Cargo.toml @@ -24,4 +24,5 @@ secp256k1 = "0.29.0" tokio = { version = "1.39.3", features = ["full"] } sha2 = "0.10.8" bs58 = "0.5.1" +serde = { version = "1.0.208", features = ["derive"] } diff --git a/packages/ciphernode/core/src/events.rs b/packages/ciphernode/core/src/events.rs index 2a1ebcde..1fe46f59 100644 --- a/packages/ciphernode/core/src/events.rs +++ b/packages/ciphernode/core/src/events.rs @@ -1,4 +1,5 @@ use actix::Message; +use serde::{Deserialize, Serialize}; use sha2::{Digest, Sha256}; use std::{ fmt, @@ -7,7 +8,7 @@ use std::{ use crate::fhe::{WrappedPublicKey, WrappedPublicKeyShare}; -#[derive(Clone, Debug, PartialEq, Eq, Hash)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] pub struct E3id(pub String); impl fmt::Display for E3id { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -21,7 +22,7 @@ impl E3id { } } -#[derive(Clone, Debug, PartialEq, Eq, Hash)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] pub struct EventId(pub [u8; 32]); impl EventId { @@ -42,8 +43,7 @@ impl fmt::Display for EventId { } } - -#[derive(Message, Clone, Debug, PartialEq, Eq, Hash)] +#[derive(Message, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[rtype(result = "()")] pub enum EnclaveEvent { KeyshareCreated { @@ -66,11 +66,11 @@ pub enum EnclaveEvent { impl From for EventId { fn from(value: EnclaveEvent) -> Self { - match value { - EnclaveEvent::KeyshareCreated { id, .. } => id, - EnclaveEvent::ComputationRequested { id, .. } => id, - EnclaveEvent::PublicKeyAggregated { id, .. } => id, - } + match value { + EnclaveEvent::KeyshareCreated { id, .. } => id, + EnclaveEvent::ComputationRequested { id, .. } => id, + EnclaveEvent::PublicKeyAggregated { id, .. } => id, + } } } @@ -84,7 +84,7 @@ impl From for EnclaveEvent { } impl From for EnclaveEvent { - fn from(data:ComputationRequested) -> Self { + fn from(data: ComputationRequested) -> Self { EnclaveEvent::ComputationRequested { id: EventId::from(data.clone()), data: data.clone(), @@ -92,8 +92,8 @@ impl From for EnclaveEvent { } } -impl From for EnclaveEvent{ - fn from(data:PublicKeyAggregated) -> Self { +impl From for EnclaveEvent { + fn from(data: PublicKeyAggregated) -> Self { EnclaveEvent::PublicKeyAggregated { id: EventId::from(data.clone()), data: data.clone(), @@ -101,21 +101,21 @@ impl From for EnclaveEvent{ } } -#[derive(Message, Clone, Debug, PartialEq, Eq, Hash)] +#[derive(Message, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[rtype(result = "anyhow::Result<()>")] pub struct KeyshareCreated { pub pubkey: WrappedPublicKeyShare, pub e3_id: E3id, } -#[derive(Message, Clone, Debug, PartialEq, Eq, Hash)] +#[derive(Message, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[rtype(result = "()")] pub struct PublicKeyAggregated { pub pubkey: WrappedPublicKey, pub e3_id: E3id, } -#[derive(Message, Clone, Debug, PartialEq, Eq, Hash)] +#[derive(Message, Clone, Debug, PartialEq, Eq, Hash, Serialize,Deserialize)] #[rtype(result = "()")] pub struct ComputationRequested { pub e3_id: E3id, diff --git a/packages/ciphernode/core/src/fhe.rs b/packages/ciphernode/core/src/fhe.rs index 73f8a93e..b643f788 100644 --- a/packages/ciphernode/core/src/fhe.rs +++ b/packages/ciphernode/core/src/fhe.rs @@ -6,8 +6,9 @@ use fhe::{ bfv::{BfvParameters, PublicKey, SecretKey}, mbfv::{AggregateIter, CommonRandomPoly, PublicKeyShare}, }; -use fhe_traits::Serialize; +use fhe_traits::{Deserialize, DeserializeParametrized, Serialize}; use rand_chacha::ChaCha20Rng; +use serde::Serializer; use crate::ordered_set::OrderedSet; @@ -27,11 +28,33 @@ pub struct GetAggregatePublicKey { /// as we use this library elsewhere we only implement traits as we need them /// and avoid exposing underlying structures from fhe.rs #[derive(Clone, Debug, PartialEq, Eq)] -pub struct WrappedPublicKeyShare(pub PublicKeyShare); +pub struct WrappedPublicKeyShare { + inner: PublicKeyShare, + // We need to hold copies of the params and crp in order to effectively serialize and + // deserialize the wrapped type + params: Arc, + crp: CommonRandomPoly, +} + +impl WrappedPublicKeyShare { + /// Public function to serialize specifically from the wrapped type including types that are + /// private from outside the crate + pub fn from_fhe_rs( + inner: PublicKeyShare, + params: Arc, + crp: CommonRandomPoly, + ) -> Self { + Self { inner, params, crp } + } + + pub fn clone_inner(&self) -> PublicKeyShare { + self.inner.clone() + } +} impl Ord for WrappedPublicKeyShare { fn cmp(&self, other: &Self) -> Ordering { - self.0.to_bytes().cmp(&other.0.to_bytes()) + self.inner.to_bytes().cmp(&other.inner.to_bytes()) } } @@ -43,37 +66,130 @@ impl PartialOrd for WrappedPublicKeyShare { impl From for Vec { fn from(share: WrappedPublicKeyShare) -> Self { - share.0.to_bytes() + share.inner.to_bytes() } } impl Hash for WrappedPublicKeyShare { fn hash(&self, state: &mut H) { - self.0.to_bytes().hash(state) + self.inner.to_bytes().hash(state) } } -impl WrappedPublicKeyShare { - fn clone_inner(&self) -> PublicKeyShare { - self.0.clone() - } +/// Deserialize from serde to WrappedPublicKeyShare +impl<'de> serde::Deserialize<'de> for WrappedPublicKeyShare { + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + // Intermediate struct of bytes for deserialization + #[derive(serde::Deserialize)] + struct PublicKeyShareBytes { + par_bytes: Vec, + crp_bytes: Vec, + bytes: Vec, + } + let PublicKeyShareBytes { + par_bytes, + crp_bytes, + bytes, + } = PublicKeyShareBytes::deserialize(deserializer)?; + let params = Arc::new(BfvParameters::try_deserialize(&par_bytes).unwrap()); + let crp = + CommonRandomPoly::deserialize(&crp_bytes, ¶ms).map_err(serde::de::Error::custom)?; + let inner = PublicKeyShare::deserialize(&bytes, ¶ms, crp.clone()) + .map_err(serde::de::Error::custom)?; + // TODO: how do we create an invariant that the deserialized params match the global params? + std::result::Result::Ok(WrappedPublicKeyShare::from_fhe_rs(inner, params, crp)) + } +} + +/// Serialize to serde bytes representation +impl serde::Serialize for WrappedPublicKeyShare { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + use serde::ser::SerializeStruct; + let bytes = self.inner.to_bytes(); + let par_bytes = self.params.to_bytes(); + let crp_bytes = self.params.to_bytes(); + // Intermediate struct of bytes + let mut state = serializer.serialize_struct("PublicKeyShare", 2)?; + state.serialize_field("par_bytes", &par_bytes)?; + state.serialize_field("crp_bytes", &crp_bytes)?; + state.serialize_field("bytes", &bytes)?; + state.end() + } } /// Wrapped PublicKey. This is wrapped to provide an inflection point /// as we use this library elsewhere we only implement traits as we need them /// and avoid exposing underlying structures from fhe.rs #[derive(Clone, Debug, PartialEq, Eq)] -pub struct WrappedPublicKey(pub PublicKey); +pub struct WrappedPublicKey { + inner: PublicKey, + params: Arc, +} + +impl WrappedPublicKey { + pub fn from_fhe_rs(inner: PublicKey, params: Arc) -> Self { + Self { inner, params } + } +} + +impl fhe_traits::Serialize for WrappedPublicKey { + fn to_bytes(&self) -> Vec { + self.inner.to_bytes() + } +} + +/// Deserialize from serde to WrappedPublicKey +impl<'de> serde::Deserialize<'de> for WrappedPublicKey { + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + // Intermediate struct of bytes for deserialization + #[derive(serde::Deserialize)] + struct PublicKeyBytes { + par: Vec, + bytes: Vec, + } + let PublicKeyBytes { par, bytes } = PublicKeyBytes::deserialize(deserializer)?; + let params = Arc::new(BfvParameters::try_deserialize(&par).unwrap()); + let inner = PublicKey::from_bytes(&bytes, ¶ms).map_err(serde::de::Error::custom)?; + // TODO: how do we create an invariant that the deserialized params match the global params? + std::result::Result::Ok(WrappedPublicKey::from_fhe_rs(inner, params)) + } +} + +/// Serialize to serde bytes representation +impl serde::Serialize for WrappedPublicKey { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + use serde::ser::SerializeStruct; + let bytes = self.inner.to_bytes(); + let par_bytes = self.params.to_bytes(); + // Intermediate struct of bytes + let mut state = serializer.serialize_struct("PublicKey", 2)?; + state.serialize_field("par_bytes", &par_bytes)?; + state.serialize_field("bytes", &bytes)?; + state.end() + } +} impl Hash for WrappedPublicKey { fn hash(&self, state: &mut H) { - self.0.to_bytes().hash(state) + self.inner.to_bytes().hash(state) } } impl Ord for WrappedPublicKey { fn cmp(&self, other: &Self) -> Ordering { - self.0.to_bytes().cmp(&other.0.to_bytes()) + self.inner.to_bytes().cmp(&other.inner.to_bytes()) } } @@ -123,7 +239,10 @@ impl Handler for Fhe { fn handle(&mut self, _event: GenerateKeyshare, _: &mut Self::Context) -> Self::Result { let sk_share = { SecretKey::random(&self.params, &mut self.rng) }; let pk_share = { PublicKeyShare::new(&sk_share, self.crp.clone(), &mut self.rng)? }; - Ok((WrappedSecretKey(sk_share), WrappedPublicKeyShare(pk_share))) + Ok(( + WrappedSecretKey(sk_share), + WrappedPublicKeyShare::from_fhe_rs(pk_share, self.params.clone(), self.crp.clone()), + )) } } @@ -133,7 +252,10 @@ impl Handler for Fhe { fn handle(&mut self, msg: GetAggregatePublicKey, _: &mut Self::Context) -> Self::Result { // Could implement Aggregate for Wrapped keys but that leaks traits let public_key: PublicKey = msg.keyshares.iter().map(|k| k.clone_inner()).aggregate()?; - Ok(WrappedPublicKey(public_key)) + Ok(WrappedPublicKey::from_fhe_rs( + public_key, + self.params.clone(), + )) } } diff --git a/packages/ciphernode/core/src/lib.rs b/packages/ciphernode/core/src/lib.rs index 9fc938ef..ff9dff94 100644 --- a/packages/ciphernode/core/src/lib.rs +++ b/packages/ciphernode/core/src/lib.rs @@ -6,12 +6,12 @@ mod ciphernode; mod committee; mod committee_key; mod data; +mod enclave_contract; mod eventbus; mod events; mod fhe; mod ordered_set; mod p2p; -mod enclave_contract; // pub struct Core { // pub name: String, @@ -92,7 +92,11 @@ mod tests { mut rng: ChaCha20Rng, ) -> Result<(WrappedPublicKeyShare, ChaCha20Rng)> { let sk = SecretKey::random(¶ms, &mut rng); - let pk = WrappedPublicKeyShare(PublicKeyShare::new(&sk, crp.clone(), &mut rng)?); + let pk = WrappedPublicKeyShare::from_fhe_rs( + PublicKeyShare::new(&sk, crp.clone(), &mut rng)?, + params.clone(), + crp, + ); Ok((pk, rng)) } @@ -168,7 +172,7 @@ mod tests { let aggregated: PublicKey = vec![p1.clone(), p2.clone(), p3.clone()] .iter() - .map(|k| k.0.clone()) + .map(|k| k.clone_inner()) .aggregate()?; assert_eq!(history.len(), 5); @@ -194,7 +198,7 @@ mod tests { e3_id: e3_id.clone() }), EnclaveEvent::from(PublicKeyAggregated { - pubkey: WrappedPublicKey(aggregated), + pubkey: WrappedPublicKey::from_fhe_rs(aggregated, params), e3_id: e3_id.clone() }) ] @@ -209,6 +213,6 @@ mod tests { // 1. command channel // 2. event channel // Pass them to the p2p actor - // connect the p2p actor to the event bus actor and monitor which events are broadcast + // connect the p2p actor to the event bus actor and monitor which events are broadcast } } From e277f4c93839eb348bef9c71496f2f8190e8d34b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=B3=CE=BB?= Date: Mon, 26 Aug 2024 11:44:14 +1000 Subject: [PATCH 16/87] Add binary encoding (#16) --- packages/ciphernode/Cargo.lock | 10 ++++++++++ packages/ciphernode/core/Cargo.toml | 1 + packages/ciphernode/core/src/events.rs | 13 ++++++++++++- 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/packages/ciphernode/Cargo.lock b/packages/ciphernode/Cargo.lock index ff60f23a..7d8ff2d1 100644 --- a/packages/ciphernode/Cargo.lock +++ b/packages/ciphernode/Cargo.lock @@ -530,6 +530,15 @@ version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "230c5f1ca6a325a32553f8640d31ac9b49f2411e901e427570154868b46da4f7" +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + [[package]] name = "bitflags" version = "1.3.2" @@ -901,6 +910,7 @@ dependencies = [ "actix-rt", "anyhow", "async-std", + "bincode", "bs58", "fhe", "fhe-traits", diff --git a/packages/ciphernode/core/Cargo.toml b/packages/ciphernode/core/Cargo.toml index 8cc627e7..44544994 100644 --- a/packages/ciphernode/core/Cargo.toml +++ b/packages/ciphernode/core/Cargo.toml @@ -25,4 +25,5 @@ tokio = { version = "1.39.3", features = ["full"] } sha2 = "0.10.8" bs58 = "0.5.1" serde = { version = "1.0.208", features = ["derive"] } +bincode = "1.3.3" diff --git a/packages/ciphernode/core/src/events.rs b/packages/ciphernode/core/src/events.rs index 1fe46f59..b638db4d 100644 --- a/packages/ciphernode/core/src/events.rs +++ b/packages/ciphernode/core/src/events.rs @@ -1,4 +1,5 @@ use actix::Message; +use bincode; use serde::{Deserialize, Serialize}; use sha2::{Digest, Sha256}; use std::{ @@ -64,6 +65,16 @@ pub enum EnclaveEvent { // CiphernodeDeregistered, } +impl EnclaveEvent { + pub fn to_bytes(&self) -> Result, bincode::Error> { + bincode::serialize(self) + } + + pub fn from_bytes(bytes: &[u8]) -> Result { + bincode::deserialize(bytes) + } +} + impl From for EventId { fn from(value: EnclaveEvent) -> Self { match value { @@ -115,7 +126,7 @@ pub struct PublicKeyAggregated { pub e3_id: E3id, } -#[derive(Message, Clone, Debug, PartialEq, Eq, Hash, Serialize,Deserialize)] +#[derive(Message, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[rtype(result = "()")] pub struct ComputationRequested { pub e3_id: E3id, From 1ed022cee3f0b5dd097be9f200efd620343638fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=B3=CE=BB?= Date: Mon, 26 Aug 2024 22:43:36 +1000 Subject: [PATCH 17/87] Test P2p actor forwarding and encoding events downstream (#17) --- packages/ciphernode/core/src/eventbus.rs | 3 +- packages/ciphernode/core/src/events.rs | 4 + packages/ciphernode/core/src/lib.rs | 51 ++++++++++-- packages/ciphernode/core/src/p2p.rs | 100 ++++++++++++++++++++--- 4 files changed, 138 insertions(+), 20 deletions(-) diff --git a/packages/ciphernode/core/src/eventbus.rs b/packages/ciphernode/core/src/eventbus.rs index 9d63941f..6a3c8cff 100644 --- a/packages/ciphernode/core/src/eventbus.rs +++ b/packages/ciphernode/core/src/eventbus.rs @@ -79,9 +79,8 @@ impl Handler for EventBus { fn handle(&mut self, event: EnclaveEvent, _: &mut Context) { // Deduplicate by id - if self.ids.contains(&event.clone().into()) { + if self.ids.contains(&event.get_id()) { // We have seen this before - println!("Duplicate {}", EventId::from(event)); return; } diff --git a/packages/ciphernode/core/src/events.rs b/packages/ciphernode/core/src/events.rs index b638db4d..051052e9 100644 --- a/packages/ciphernode/core/src/events.rs +++ b/packages/ciphernode/core/src/events.rs @@ -73,6 +73,10 @@ impl EnclaveEvent { pub fn from_bytes(bytes: &[u8]) -> Result { bincode::deserialize(bytes) } + + pub fn get_id(&self) -> EventId { + self.clone().into() + } } impl From for EventId { diff --git a/packages/ciphernode/core/src/lib.rs b/packages/ciphernode/core/src/lib.rs index ff9dff94..493d0667 100644 --- a/packages/ciphernode/core/src/lib.rs +++ b/packages/ciphernode/core/src/lib.rs @@ -32,7 +32,7 @@ mod p2p; #[cfg(test)] mod tests { - use std::sync::Arc; + use std::{sync::Arc, time::Duration}; use crate::{ ciphernode::Ciphernode, @@ -41,6 +41,7 @@ mod tests { eventbus::{EventBus, GetHistory, Subscribe}, events::{ComputationRequested, E3id, EnclaveEvent, KeyshareCreated, PublicKeyAggregated}, fhe::{Fhe, WrappedPublicKey, WrappedPublicKeyShare}, + p2p::P2p, }; use actix::prelude::*; use anyhow::*; @@ -50,6 +51,8 @@ mod tests { }; use rand::SeedableRng; use rand_chacha::ChaCha20Rng; + use tokio::sync::Mutex; + use tokio::{sync::mpsc::channel, time::sleep}; // Simulating a local node fn setup_local_ciphernode( @@ -207,12 +210,44 @@ mod tests { Ok(()) } - // TODO: Test p2p - fn test_p2p_event_broadcasting() { - // Setup two Vec channels to simulate libp2p - // 1. command channel - // 2. event channel - // Pass them to the p2p actor - // connect the p2p actor to the event bus actor and monitor which events are broadcast + #[actix::test] + async fn test_p2p_event_broadcasting() -> Result<()> { + let (tx, mut output) = channel(100); // Transmit byte events to the network + let (_, rx) = channel(100); // Receive byte events from the network + let bus = EventBus::new(true).start(); + let _ = P2p::spawn_and_listen(bus.clone(), tx.clone(), rx); + + // Capture messages from output on msgs vec + let msgs: Arc>>> = Arc::new(Mutex::new(Vec::new())); + let msgs_loop = msgs.clone(); + + tokio::spawn(async move { + while let Some(msg) = output.recv().await { + msgs_loop.lock().await.push(msg); + } + }); + + let evt_1 = EnclaveEvent::from(ComputationRequested { + e3_id: E3id::new("1234"), + nodecount: 3, + threshold: 123, + sortition_seed: 123, + }); + + let evt_2 = EnclaveEvent::from(ComputationRequested { + e3_id: E3id::new("1235"), + nodecount: 3, + threshold: 123, + sortition_seed: 123, + }); + + bus.do_send(evt_1.clone()); + bus.do_send(evt_2.clone()); + + sleep(Duration::from_millis(1)).await; // need to push to next tick + + assert_eq!(*msgs.lock().await, vec![evt_1.to_bytes()?, evt_2.to_bytes()?], "P2p did not transmit events to the network"); + + Ok(()) } } diff --git a/packages/ciphernode/core/src/p2p.rs b/packages/ciphernode/core/src/p2p.rs index 6a5e9bb2..3bcfa929 100644 --- a/packages/ciphernode/core/src/p2p.rs +++ b/packages/ciphernode/core/src/p2p.rs @@ -1,24 +1,104 @@ -/// Actor for connecting to an libp2p client via it's mpsc channel interface -/// This Actor should be responsible for +use std::collections::HashSet; + +/// Actor for connecting to an libp2p client via it's mpsc channel interface +/// This Actor should be responsible for /// 1. Sending and Recieving Vec messages with libp2p /// 2. Converting between Vec and EnclaveEvents::Xxxxxxxxx() /// 3. Broadcasting over the local eventbus /// 4. Listening to the local eventbus for messages to be published to libp2p -use actix::{Actor, Context}; +use actix::prelude::*; use tokio::sync::mpsc::{Receiver, Sender}; -use p2p::EnclaveRouter; -pub struct P2p; +use crate::{ + eventbus::{EventBus, Subscribe}, + events::{EnclaveEvent, EventId}, +}; + +pub struct P2p { + bus: Addr, + tx: Sender>, + sent_events: HashSet, +} -impl Actor for P2p{ +impl Actor for P2p { type Context = Context; } +#[derive(Message, Clone, Debug, PartialEq, Eq)] +#[rtype(result = "anyhow::Result<()>")] +struct LibP2pEvent(pub Vec); + impl P2p { - pub fn new() { - // Construct owning Libp2p module + pub fn new(bus: Addr, tx: Sender>) -> Self { + Self { + bus, + tx, + sent_events: HashSet::new(), + } } - pub fn from_channel(tx:Sender>, rx:Receiver>){ - // Construct from tx/rx + + /// Start a new P2p actor listening for libp2p messages on the given Receiver and forwarding + /// them to the actor + pub fn spawn_and_listen( + bus: Addr, + tx: Sender>, // Transmit byte events to the network + mut rx: Receiver>, // Receive byte events from the network + ) -> Addr { + // Create a new Actor + let p2p = P2p::new(bus.clone(), tx).start(); + + // Listen on all events + bus.do_send(Subscribe { + event_type: String::from("*"), + listener: p2p.clone().recipient(), + }); + + // Clone this to go in the spawned future + let p2p_addr = p2p.clone(); + tokio::spawn(async move { + while let Some(msg) = rx.recv().await { + p2p_addr.do_send(LibP2pEvent(msg)) + } + }); + + // Return the address + p2p + } +} + +impl Handler for P2p { + type Result = anyhow::Result<()>; + fn handle(&mut self, msg: LibP2pEvent, _: &mut Self::Context) -> Self::Result { + let LibP2pEvent(bytes) = msg; + match EnclaveEvent::from_bytes(&bytes) { + Ok(event) => { + self.bus.do_send(event.clone()); + self.sent_events.insert(event.into()); + } + Err(err) => println!("Error: {}", err), + } + Ok(()) + } +} + +impl Handler for P2p { + type Result = ResponseFuture<()>; + fn handle(&mut self, event: EnclaveEvent, _: &mut Self::Context) -> Self::Result { + let sent_events = self.sent_events.clone(); + let tx = self.tx.clone(); + let evt = event.clone(); + Box::pin(async move { + let id: EventId = evt.clone().into(); + if sent_events.contains(&id) { + return; + } + + match evt.to_bytes() { + Ok(bytes) => { + let _ = tx.send(bytes).await; + } + Err(error) => println!("Error: {}", error), + } + }) } } From baaa352e3145468622e15ba086514df883c097a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=B3=CE=BB?= Date: Tue, 27 Aug 2024 12:23:39 +1000 Subject: [PATCH 18/87] Add forward to bus from network test (#18) --- packages/ciphernode/core/src/lib.rs | 46 +++++++++++++++++++++++++---- 1 file changed, 40 insertions(+), 6 deletions(-) diff --git a/packages/ciphernode/core/src/lib.rs b/packages/ciphernode/core/src/lib.rs index 493d0667..99edea2a 100644 --- a/packages/ciphernode/core/src/lib.rs +++ b/packages/ciphernode/core/src/lib.rs @@ -37,7 +37,7 @@ mod tests { use crate::{ ciphernode::Ciphernode, committee::CommitteeManager, - data::Data, + data::{Data, GetLog}, eventbus::{EventBus, GetHistory, Subscribe}, events::{ComputationRequested, E3id, EnclaveEvent, KeyshareCreated, PublicKeyAggregated}, fhe::{Fhe, WrappedPublicKey, WrappedPublicKeyShare}, @@ -211,12 +211,13 @@ mod tests { } #[actix::test] - async fn test_p2p_event_broadcasting() -> Result<()> { + async fn test_p2p_actor_forwards_events_to_network() -> Result<()> { + // Setup elements in test let (tx, mut output) = channel(100); // Transmit byte events to the network let (_, rx) = channel(100); // Receive byte events from the network let bus = EventBus::new(true).start(); - let _ = P2p::spawn_and_listen(bus.clone(), tx.clone(), rx); - + P2p::spawn_and_listen(bus.clone(), tx.clone(), rx); + // Capture messages from output on msgs vec let msgs: Arc>>> = Arc::new(Mutex::new(Vec::new())); let msgs_loop = msgs.clone(); @@ -243,10 +244,43 @@ mod tests { bus.do_send(evt_1.clone()); bus.do_send(evt_2.clone()); - + + sleep(Duration::from_millis(1)).await; // need to push to next tick + + assert_eq!( + *msgs.lock().await, + vec![evt_1.to_bytes()?, evt_2.to_bytes()?], + "P2p did not transmit events to the network" + ); + + Ok(()) + } + + #[actix::test] + async fn test_p2p_actor_forwards_events_to_bus() -> Result<()> { + // Setup elements in test + let (tx, _) = channel(100); // Transmit byte events to the network + let (input, rx) = channel(100); // Receive byte events from the network + let bus = EventBus::new(true).start(); + P2p::spawn_and_listen(bus.clone(), tx.clone(), rx); + + // Capture messages from output on msgs vec + let event = EnclaveEvent::from(ComputationRequested { + e3_id: E3id::new("1235"), + nodecount: 3, + threshold: 123, + sortition_seed: 123, + }); + + // lets send an event from the network + let _ = input.send(event.to_bytes()?).await; + sleep(Duration::from_millis(1)).await; // need to push to next tick - assert_eq!(*msgs.lock().await, vec![evt_1.to_bytes()?, evt_2.to_bytes()?], "P2p did not transmit events to the network"); + // check the history of the event bus + let history = bus.send(GetHistory).await?; + + assert_eq!(history, vec![event]); Ok(()) } From 52a28f1e4856a47b7122daf1f1d8491876b1355b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=B3=CE=BB?= Date: Tue, 27 Aug 2024 13:01:00 +1000 Subject: [PATCH 19/87] Test rebroadcast does not bounce back to the eventbus (#19) --- packages/ciphernode/core/src/lib.rs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/packages/ciphernode/core/src/lib.rs b/packages/ciphernode/core/src/lib.rs index 99edea2a..ff81ad40 100644 --- a/packages/ciphernode/core/src/lib.rs +++ b/packages/ciphernode/core/src/lib.rs @@ -214,7 +214,7 @@ mod tests { async fn test_p2p_actor_forwards_events_to_network() -> Result<()> { // Setup elements in test let (tx, mut output) = channel(100); // Transmit byte events to the network - let (_, rx) = channel(100); // Receive byte events from the network + let (input, rx) = channel(100); // Receive byte events from the network let bus = EventBus::new(true).start(); P2p::spawn_and_listen(bus.clone(), tx.clone(), rx); @@ -224,7 +224,8 @@ mod tests { tokio::spawn(async move { while let Some(msg) = output.recv().await { - msgs_loop.lock().await.push(msg); + msgs_loop.lock().await.push(msg.clone()); + let _ = input.send(msg).await; // loopback to simulate a rebroadcast message } }); @@ -244,15 +245,20 @@ mod tests { bus.do_send(evt_1.clone()); bus.do_send(evt_2.clone()); - + sleep(Duration::from_millis(1)).await; // need to push to next tick + // check the history of the event bus + let history = bus.send(GetHistory).await?; + assert_eq!( *msgs.lock().await, vec![evt_1.to_bytes()?, evt_2.to_bytes()?], "P2p did not transmit events to the network" ); + assert_eq!(history, vec![evt_1, evt_2], "P2p must not retransmit forwarded event to event bus"); + Ok(()) } From 0054246db24bf52beb60c889ce2348342c78c4cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=B3=CE=BB?= Date: Tue, 27 Aug 2024 17:03:12 +1000 Subject: [PATCH 20/87] Start ciphernode binary example first commit (wip) (#20) * Create a ciphernode binary example * Logging was not accurate --- packages/ciphernode/Cargo.lock | 2 ++ packages/ciphernode/core/src/fhe.rs | 20 ++++++++++++++--- packages/ciphernode/core/src/lib.rs | 10 +++++++++ packages/ciphernode/core/src/p2p.rs | 22 ++++++++++++++++++- packages/ciphernode/enclave_node/Cargo.toml | 2 ++ .../enclave_node/src/bin/ciphernode.rs | 20 +++++++++++++++++ 6 files changed, 72 insertions(+), 4 deletions(-) create mode 100644 packages/ciphernode/enclave_node/src/bin/ciphernode.rs diff --git a/packages/ciphernode/Cargo.lock b/packages/ciphernode/Cargo.lock index 7d8ff2d1..efc9189b 100644 --- a/packages/ciphernode/Cargo.lock +++ b/packages/ciphernode/Cargo.lock @@ -929,7 +929,9 @@ dependencies = [ name = "enclave_node" version = "0.1.0" dependencies = [ + "actix-rt", "async-std", + "enclave-core", "eth", "fhe", "fhe-traits", diff --git a/packages/ciphernode/core/src/fhe.rs b/packages/ciphernode/core/src/fhe.rs index b643f788..d7c3070f 100644 --- a/packages/ciphernode/core/src/fhe.rs +++ b/packages/ciphernode/core/src/fhe.rs @@ -1,17 +1,17 @@ use std::{cmp::Ordering, hash::Hash, mem, sync::Arc}; +use crate::ordered_set::OrderedSet; use actix::{Actor, Context, Handler, Message}; use anyhow::*; use fhe::{ - bfv::{BfvParameters, PublicKey, SecretKey}, + bfv::{BfvParameters, BfvParametersBuilder, PublicKey, SecretKey}, mbfv::{AggregateIter, CommonRandomPoly, PublicKeyShare}, }; use fhe_traits::{Deserialize, DeserializeParametrized, Serialize}; +use rand::SeedableRng; use rand_chacha::ChaCha20Rng; use serde::Serializer; -use crate::ordered_set::OrderedSet; - #[derive(Message, Clone, Debug, PartialEq, Eq, Hash)] #[rtype(result = "Result<(WrappedSecretKey, WrappedPublicKeyShare)>")] pub struct GenerateKeyshare { @@ -232,6 +232,20 @@ impl Fhe { ) -> Result { Ok(Self { params, crp, rng }) } + pub fn try_default() -> Result { + let moduli = &vec![0x3FFFFFFF000001]; + let degree = 2048usize; + let plaintext_modulus = 1032193u64; + let mut rng = ChaCha20Rng::from_entropy(); + let params = BfvParametersBuilder::new() + .set_degree(degree) + .set_plaintext_modulus(plaintext_modulus) + .set_moduli(&moduli) + .build_arc()?; + let crp = CommonRandomPoly::new(¶ms, &mut rng)?; + + Ok(Fhe::new(params, crp, rng)?) + } } impl Handler for Fhe { diff --git a/packages/ciphernode/core/src/lib.rs b/packages/ciphernode/core/src/lib.rs index ff81ad40..68578d38 100644 --- a/packages/ciphernode/core/src/lib.rs +++ b/packages/ciphernode/core/src/lib.rs @@ -13,6 +13,16 @@ mod fhe; mod ordered_set; mod p2p; +pub use data::*; +pub use ciphernode::*; +pub use committee::*; +pub use committee_key::*; +pub use eventbus::*; +pub use events::*; +pub use fhe::*; +pub use p2p::*; +pub use actix::prelude::*; + // pub struct Core { // pub name: String, // } diff --git a/packages/ciphernode/core/src/p2p.rs b/packages/ciphernode/core/src/p2p.rs index 3bcfa929..f9c7ddfd 100644 --- a/packages/ciphernode/core/src/p2p.rs +++ b/packages/ciphernode/core/src/p2p.rs @@ -1,4 +1,4 @@ -use std::collections::HashSet; +use std::{collections::HashSet, error::Error}; /// Actor for connecting to an libp2p client via it's mpsc channel interface /// This Actor should be responsible for @@ -7,6 +7,8 @@ use std::collections::HashSet; /// 3. Broadcasting over the local eventbus /// 4. Listening to the local eventbus for messages to be published to libp2p use actix::prelude::*; +use anyhow::anyhow; +use p2p::EnclaveRouter; use tokio::sync::mpsc::{Receiver, Sender}; use crate::{ @@ -64,6 +66,24 @@ impl P2p { // Return the address p2p } + + pub fn spawn_libp2p( + bus: Addr, + ) -> Result< + ( + Addr, + tokio::task::JoinHandle<()>, + ), + Box, + > { + let (mut libp2p, tx, rx) = EnclaveRouter::new()?; + libp2p.connect_swarm("mdns".to_string())?; + libp2p.join_topic("enclave-keygen-01")?; + + let p2p_addr = Self::spawn_and_listen(bus, tx, rx); + let handle = tokio::spawn(async move { libp2p.start().await.unwrap() }); + Ok((p2p_addr, handle)) + } } impl Handler for P2p { diff --git a/packages/ciphernode/enclave_node/Cargo.toml b/packages/ciphernode/enclave_node/Cargo.toml index 0a32f8bc..4cb6a17d 100644 --- a/packages/ciphernode/enclave_node/Cargo.toml +++ b/packages/ciphernode/enclave_node/Cargo.toml @@ -10,8 +10,10 @@ repository = "https://github.com/gnosisguild/enclave/packages/ciphernode" [dependencies] eth = { path = "../eth" } p2p = { path = "../p2p" } +enclave-core = { path = "../core" } async-std = "1.12.0" fhe = { git = "https://github.com/gnosisguild/fhe.rs", version = "0.1.0-beta.7" } fhe-traits = { git = "https://github.com/gnosisguild/fhe.rs", version = "0.1.0-beta.7" } fhe-util = { git = "https://github.com/gnosisguild/fhe.rs", version = "0.1.0-beta.7" } tokio = { version = "1.38", features = ["full"] } +actix-rt = "2.10.0" diff --git a/packages/ciphernode/enclave_node/src/bin/ciphernode.rs b/packages/ciphernode/enclave_node/src/bin/ciphernode.rs new file mode 100644 index 00000000..d75e2490 --- /dev/null +++ b/packages/ciphernode/enclave_node/src/bin/ciphernode.rs @@ -0,0 +1,20 @@ +use std::error::Error; + +use enclave_core::Actor; +use enclave_core::Ciphernode; +use enclave_core::Data; +use enclave_core::EventBus; +use enclave_core::Fhe; +use enclave_core::P2p; + +#[actix_rt::main] +async fn main() -> Result<(), Box> { + let fhe = Fhe::try_default()?.start(); + let bus = EventBus::new(true).start(); + let data = Data::new(true).start(); // TODO: Use a sled backed Data Actor + let _node = Ciphernode::new(bus.clone(), fhe.clone(), data.clone()).start(); + let (_, h) = P2p::spawn_libp2p(bus.clone())?; + println!("Ciphernode"); + let _ = tokio::join!(h); + Ok(()) +} From 1deef8ab97f33c967f23b57e2f0a26e9c8b7b920 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=B3=CE=BB?= Date: Tue, 27 Aug 2024 21:33:48 +1000 Subject: [PATCH 21/87] Setup binary for testing full flow (#21) --- packages/ciphernode/core/src/ciphernode.rs | 8 ++- packages/ciphernode/core/src/committee.rs | 16 +++++- packages/ciphernode/core/src/eventbus.rs | 2 +- packages/ciphernode/core/src/events.rs | 55 +++++++++++++++++-- packages/ciphernode/core/src/fhe.rs | 3 +- packages/ciphernode/core/src/lib.rs | 13 +++++ packages/ciphernode/core/src/logger.rs | 27 +++++++++ packages/ciphernode/core/src/p2p.rs | 5 -- .../enclave_node/src/bin/ciphernode.rs | 9 ++- .../ciphernode/enclave_node/src/bin/cmd.rs | 39 +++++++++++++ packages/ciphernode/p2p/src/lib.rs | 5 +- 11 files changed, 161 insertions(+), 21 deletions(-) create mode 100644 packages/ciphernode/core/src/logger.rs create mode 100644 packages/ciphernode/enclave_node/src/bin/cmd.rs diff --git a/packages/ciphernode/core/src/ciphernode.rs b/packages/ciphernode/core/src/ciphernode.rs index 1b1a19dc..7f3bebe2 100644 --- a/packages/ciphernode/core/src/ciphernode.rs +++ b/packages/ciphernode/core/src/ciphernode.rs @@ -3,6 +3,7 @@ use crate::{ eventbus::EventBus, events::{ComputationRequested, EnclaveEvent, KeyshareCreated}, fhe::{Fhe, GenerateKeyshare}, + Subscribe, }; use actix::prelude::*; use anyhow::Result; @@ -21,6 +22,12 @@ impl Ciphernode { pub fn new(bus: Addr, fhe: Addr, data: Addr) -> Self { Self { bus, fhe, data } } + + pub fn attach(bus: Addr, fhe: Addr, data: Addr) -> Addr { + let node = Ciphernode::new(bus.clone(), fhe, data).start(); + bus.do_send(Subscribe::new("ComputationRequested", node.clone().into())); + node + } } impl Handler for Ciphernode { @@ -74,7 +81,6 @@ async fn on_computation_requested( // broadcast the KeyshareCreated message let event = EnclaveEvent::from(KeyshareCreated { pubkey, e3_id }); - bus.do_send(event); Ok(()) diff --git a/packages/ciphernode/core/src/committee.rs b/packages/ciphernode/core/src/committee.rs index ee19f540..836dc534 100644 --- a/packages/ciphernode/core/src/committee.rs +++ b/packages/ciphernode/core/src/committee.rs @@ -7,6 +7,7 @@ use crate::{ eventbus::EventBus, events::{E3id, EnclaveEvent}, fhe::Fhe, + Subscribe, }; pub struct CommitteeManager { @@ -27,6 +28,16 @@ impl CommitteeManager { keys: HashMap::new(), } } + + pub fn attach(bus: Addr, fhe: Addr) -> Addr { + let addr = CommitteeManager::new(bus.clone(), fhe).start(); + bus.do_send(Subscribe::new( + "ComputationRequested", + addr.clone().recipient(), + )); + bus.do_send(Subscribe::new("KeyshareCreated", addr.clone().into())); + addr + } } impl Handler for CommitteeManager { @@ -50,7 +61,7 @@ impl Handler for CommitteeManager { if let Some(key) = self.keys.get(&data.e3_id) { key.do_send(data); } - }, + } EnclaveEvent::PublicKeyAggregated { data, .. } => { let Some(key) = self.keys.get(&data.e3_id) else { return; @@ -58,8 +69,7 @@ impl Handler for CommitteeManager { key.do_send(Die); self.keys.remove(&data.e3_id); - } - // _ => (), + } // _ => (), } } } diff --git a/packages/ciphernode/core/src/eventbus.rs b/packages/ciphernode/core/src/eventbus.rs index 6a3c8cff..50cd14f8 100644 --- a/packages/ciphernode/core/src/eventbus.rs +++ b/packages/ciphernode/core/src/eventbus.rs @@ -83,7 +83,7 @@ impl Handler for EventBus { // We have seen this before return; } - + // TODO: How can we ensure the event we see is coming in in the correct order? if let Some(listeners) = self.listeners.get("*") { for listener in listeners { diff --git a/packages/ciphernode/core/src/events.rs b/packages/ciphernode/core/src/events.rs index 051052e9..ce062dae 100644 --- a/packages/ciphernode/core/src/events.rs +++ b/packages/ciphernode/core/src/events.rs @@ -1,3 +1,4 @@ +use crate::fhe::{WrappedPublicKey, WrappedPublicKeyShare}; use actix::Message; use bincode; use serde::{Deserialize, Serialize}; @@ -7,8 +8,6 @@ use std::{ hash::{DefaultHasher, Hash, Hasher}, }; -use crate::fhe::{WrappedPublicKey, WrappedPublicKeyShare}; - #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] pub struct E3id(pub String); impl fmt::Display for E3id { @@ -23,6 +22,12 @@ impl E3id { } } +impl From for E3id { + fn from(value: u32) -> Self { + E3id::new(value.to_string()) + } +} + #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] pub struct EventId(pub [u8; 32]); @@ -75,7 +80,7 @@ impl EnclaveEvent { } pub fn get_id(&self) -> EventId { - self.clone().into() + self.clone().into() } } @@ -116,6 +121,12 @@ impl From for EnclaveEvent { } } +impl fmt::Display for EnclaveEvent { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(&format!("{}({})", self.event_type(), self.get_id())) + } +} + #[derive(Message, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[rtype(result = "anyhow::Result<()>")] pub struct KeyshareCreated { @@ -163,7 +174,18 @@ impl EnclaveEvent { #[cfg(test)] mod tests { - use crate::events::extract_enclave_event_name; + use std::error::Error; + + use fhe::{ + bfv::{BfvParametersBuilder, SecretKey}, + mbfv::{CommonRandomPoly, PublicKeyShare}, + }; + use rand::SeedableRng; + use rand_chacha::ChaCha20Rng; + + use crate::{events::extract_enclave_event_name, E3id, KeyshareCreated, WrappedPublicKeyShare}; + + use super::EnclaveEvent; #[test] fn test_extract_enum_name() { @@ -176,4 +198,29 @@ mod tests { "CommitteeSelected" ); } + + #[test] + fn test_deserialization() -> Result<(), Box> { + let moduli = &vec![0x3FFFFFFF000001]; + let degree = 2048usize; + let plaintext_modulus = 1032193u64; + let mut rng = ChaCha20Rng::from_entropy(); + let params = BfvParametersBuilder::new() + .set_degree(degree) + .set_plaintext_modulus(plaintext_modulus) + .set_moduli(&moduli) + .build_arc()?; + let crp = CommonRandomPoly::new(¶ms, &mut rng)?; + let sk_share = { SecretKey::random(¶ms, &mut rng) }; + let pk_share = { PublicKeyShare::new(&sk_share, crp.clone(), &mut rng)? }; + let pubkey = WrappedPublicKeyShare::from_fhe_rs(pk_share, params.clone(), crp.clone()); + let kse = EnclaveEvent::from(KeyshareCreated { + e3_id: E3id::from(1001), + pubkey, + }); + let kse_bytes = kse.to_bytes()?; + let _ = EnclaveEvent::from_bytes(&kse_bytes.clone()); + // deserialization occurred without panic! + Ok(()) + } } diff --git a/packages/ciphernode/core/src/fhe.rs b/packages/ciphernode/core/src/fhe.rs index d7c3070f..7a5b59f7 100644 --- a/packages/ciphernode/core/src/fhe.rs +++ b/packages/ciphernode/core/src/fhe.rs @@ -113,7 +113,7 @@ impl serde::Serialize for WrappedPublicKeyShare { use serde::ser::SerializeStruct; let bytes = self.inner.to_bytes(); let par_bytes = self.params.to_bytes(); - let crp_bytes = self.params.to_bytes(); + let crp_bytes = self.crp.to_bytes(); // Intermediate struct of bytes let mut state = serializer.serialize_struct("PublicKeyShare", 2)?; state.serialize_field("par_bytes", &par_bytes)?; @@ -123,6 +123,7 @@ impl serde::Serialize for WrappedPublicKeyShare { } } + /// Wrapped PublicKey. This is wrapped to provide an inflection point /// as we use this library elsewhere we only implement traits as we need them /// and avoid exposing underlying structures from fhe.rs diff --git a/packages/ciphernode/core/src/lib.rs b/packages/ciphernode/core/src/lib.rs index 68578d38..772f0789 100644 --- a/packages/ciphernode/core/src/lib.rs +++ b/packages/ciphernode/core/src/lib.rs @@ -12,6 +12,19 @@ mod events; mod fhe; mod ordered_set; mod p2p; +mod logger; + +// TODO: this is too permissive +pub use data::*; +pub use ciphernode::*; +pub use committee::*; +pub use committee_key::*; +pub use eventbus::*; +pub use events::*; +pub use fhe::*; +pub use p2p::*; +pub use actix::prelude::*; +pub use logger::*; pub use data::*; pub use ciphernode::*; diff --git a/packages/ciphernode/core/src/logger.rs b/packages/ciphernode/core/src/logger.rs new file mode 100644 index 00000000..0ee12104 --- /dev/null +++ b/packages/ciphernode/core/src/logger.rs @@ -0,0 +1,27 @@ +use actix::{Actor, Addr, Context, Handler}; + +use crate::{EnclaveEvent, EventBus, Subscribe}; + +pub struct SimpleLogger; + +impl SimpleLogger { + pub fn attach(bus:Addr) -> Addr{ + let addr = Self.start(); + bus.do_send(Subscribe { + listener:addr.clone().recipient(), + event_type: "*".to_string() + }); + addr + } +} + +impl Actor for SimpleLogger { + type Context = Context; +} + +impl Handler for SimpleLogger { + type Result = (); + fn handle(&mut self, msg: EnclaveEvent, _: &mut Self::Context) -> Self::Result { + println!("{}", msg); + } +} diff --git a/packages/ciphernode/core/src/p2p.rs b/packages/ciphernode/core/src/p2p.rs index f9c7ddfd..6b4616b6 100644 --- a/packages/ciphernode/core/src/p2p.rs +++ b/packages/ciphernode/core/src/p2p.rs @@ -2,12 +2,7 @@ use std::{collections::HashSet, error::Error}; /// Actor for connecting to an libp2p client via it's mpsc channel interface /// This Actor should be responsible for -/// 1. Sending and Recieving Vec messages with libp2p -/// 2. Converting between Vec and EnclaveEvents::Xxxxxxxxx() -/// 3. Broadcasting over the local eventbus -/// 4. Listening to the local eventbus for messages to be published to libp2p use actix::prelude::*; -use anyhow::anyhow; use p2p::EnclaveRouter; use tokio::sync::mpsc::{Receiver, Sender}; diff --git a/packages/ciphernode/enclave_node/src/bin/ciphernode.rs b/packages/ciphernode/enclave_node/src/bin/ciphernode.rs index d75e2490..005496de 100644 --- a/packages/ciphernode/enclave_node/src/bin/ciphernode.rs +++ b/packages/ciphernode/enclave_node/src/bin/ciphernode.rs @@ -1,18 +1,21 @@ -use std::error::Error; - use enclave_core::Actor; use enclave_core::Ciphernode; +use enclave_core::CommitteeManager; use enclave_core::Data; use enclave_core::EventBus; use enclave_core::Fhe; use enclave_core::P2p; +use enclave_core::SimpleLogger; +use std::error::Error; #[actix_rt::main] async fn main() -> Result<(), Box> { let fhe = Fhe::try_default()?.start(); let bus = EventBus::new(true).start(); let data = Data::new(true).start(); // TODO: Use a sled backed Data Actor - let _node = Ciphernode::new(bus.clone(), fhe.clone(), data.clone()).start(); + SimpleLogger::attach(bus.clone()); + Ciphernode::attach(bus.clone(), fhe.clone(), data.clone()); + CommitteeManager::attach(bus.clone(), fhe.clone()); let (_, h) = P2p::spawn_libp2p(bus.clone())?; println!("Ciphernode"); let _ = tokio::join!(h); diff --git a/packages/ciphernode/enclave_node/src/bin/cmd.rs b/packages/ciphernode/enclave_node/src/bin/cmd.rs new file mode 100644 index 00000000..4ac97462 --- /dev/null +++ b/packages/ciphernode/enclave_node/src/bin/cmd.rs @@ -0,0 +1,39 @@ +use std::error::Error; + +use enclave_core::Actor; +use enclave_core::ComputationRequested; +use enclave_core::E3id; +use enclave_core::EnclaveEvent; +use enclave_core::EventBus; +use enclave_core::P2p; +use tokio::{ + self, + io::{self, AsyncBufReadExt, BufReader}, +}; + +#[actix_rt::main] +async fn main() -> Result<(), Box> { + let bus = EventBus::new(true).start(); + let (_, t1) = P2p::spawn_libp2p(bus.clone())?; + let mut stdin = BufReader::new(io::stdin()).lines(); + let t2 = tokio::spawn(async move { + let mut id: u32 = 1000; + while let Ok(Some(line)) = stdin.next_line().await { + match line.as_str() { + "test" => { + id += 1; + bus.do_send(EnclaveEvent::from(ComputationRequested { + e3_id: E3id::from(id), + nodecount: 3, + threshold: 3, + sortition_seed: 100, + })); + } + _ => println!("Unknown command"), + } + } + }); + + let _ = tokio::join!(t1, t2); + Ok(()) +} diff --git a/packages/ciphernode/p2p/src/lib.rs b/packages/ciphernode/p2p/src/lib.rs index d55ab000..7eff316e 100644 --- a/packages/ciphernode/p2p/src/lib.rs +++ b/packages/ciphernode/p2p/src/lib.rs @@ -127,7 +127,6 @@ impl EnclaveRouter { loop { select! { Some(line) = self.cmd_rx.recv() => { - println!("Receiving input"); if let Err(e) = self.swarm.as_mut().unwrap() .behaviour_mut().gossipsub .publish(self.topic.as_mut().unwrap().clone(), line) { @@ -153,9 +152,9 @@ impl EnclaveRouter { message, })) => { println!( - "Got message: '{}' with id: {id} from peer: {peer_id}", - String::from_utf8_lossy(&message.data), + "Got message with id: {id} from peer: {peer_id}", ); + println!("{:?}", message); self.evt_tx.send(message.data).await?; }, SwarmEvent::NewListenAddr { address, .. } => { From 9c92404e14b5e0f9255c32d43bdc40b3b66e29fa Mon Sep 17 00:00:00 2001 From: nginnever Date: Tue, 27 Aug 2024 13:03:07 -0700 Subject: [PATCH 22/87] bfv lib params --- packages/ciphernode/Cargo.lock | 1 + packages/ciphernode/Cargo.toml | 2 +- packages/ciphernode/bfv/src/lib.rs | 18 ++++++++++-------- packages/ciphernode/enclave_node/Cargo.toml | 1 + packages/ciphernode/enclave_node/src/main.rs | 3 +++ 5 files changed, 16 insertions(+), 9 deletions(-) diff --git a/packages/ciphernode/Cargo.lock b/packages/ciphernode/Cargo.lock index efc9189b..cf83b740 100644 --- a/packages/ciphernode/Cargo.lock +++ b/packages/ciphernode/Cargo.lock @@ -931,6 +931,7 @@ version = "0.1.0" dependencies = [ "actix-rt", "async-std", + "bfv", "enclave-core", "eth", "fhe", diff --git a/packages/ciphernode/Cargo.toml b/packages/ciphernode/Cargo.toml index ffd71233..9f243e52 100644 --- a/packages/ciphernode/Cargo.toml +++ b/packages/ciphernode/Cargo.toml @@ -1,2 +1,2 @@ [workspace] -members = ["core", "eth", "enclave", "enclave_node", "p2p"] +members = ["core", "eth", "enclave", "enclave_node", "p2p", "bfv"] diff --git a/packages/ciphernode/bfv/src/lib.rs b/packages/ciphernode/bfv/src/lib.rs index af3a0447..2a98d6d3 100644 --- a/packages/ciphernode/bfv/src/lib.rs +++ b/packages/ciphernode/bfv/src/lib.rs @@ -4,8 +4,9 @@ mod util; +use std::{sync::Arc}; use fhe::{ - bfv::{BfvParametersBuilder, Ciphertext, Encoding, Plaintext, SecretKey}, + bfv::{BfvParameters, BfvParametersBuilder, Ciphertext, Encoding, Plaintext, SecretKey}, mbfv::{AggregateIter, CommonRandomPoly, DecryptionShare, PublicKeyShare}, }; use fhe_traits::{FheDecoder, Serialize as FheSerialize, DeserializeParametrized}; @@ -13,15 +14,16 @@ use rand::{Rng, rngs::OsRng, thread_rng}; use util::timeit::{timeit}; pub struct EnclaveBFV { - pub address: String, - pub pk_share: Vec, + pk_share: PublicKeyShare, + params: Arc, + crp: CommonRandomPoly, } impl EnclaveBFV { - pub fn new(address: String) -> Self { - let degree = 4096; - let plaintext_modulus: u64 = 4096; - let moduli = vec![0xffffee001, 0xffffc4001, 0x1ffffe0001]; + pub fn new(degree: usize, plaintext_modulus: u64, moduli: Vec) -> Self { + // let degree = 4096; + // let plaintext_modulus: u64 = 4096; + // let moduli = vec![0xffffee001, 0xffffc4001, 0x1ffffe0001]; // Generate the BFV parameters structure. let params = timeit!( @@ -41,6 +43,6 @@ impl EnclaveBFV { let pk_share = pk_share_1.to_bytes(); let sk_share = sk_share_1.coeffs.into_vec(); - Self { address, pk_share } + Self { pk_share: pk_share_1, params, crp } } } \ No newline at end of file diff --git a/packages/ciphernode/enclave_node/Cargo.toml b/packages/ciphernode/enclave_node/Cargo.toml index 4cb6a17d..2f1698f0 100644 --- a/packages/ciphernode/enclave_node/Cargo.toml +++ b/packages/ciphernode/enclave_node/Cargo.toml @@ -10,6 +10,7 @@ repository = "https://github.com/gnosisguild/enclave/packages/ciphernode" [dependencies] eth = { path = "../eth" } p2p = { path = "../p2p" } +bfv = { path = "../bfv" } enclave-core = { path = "../core" } async-std = "1.12.0" fhe = { git = "https://github.com/gnosisguild/fhe.rs", version = "0.1.0-beta.7" } diff --git a/packages/ciphernode/enclave_node/src/main.rs b/packages/ciphernode/enclave_node/src/main.rs index cbd75802..85640d37 100644 --- a/packages/ciphernode/enclave_node/src/main.rs +++ b/packages/ciphernode/enclave_node/src/main.rs @@ -1,6 +1,7 @@ use std::error::Error; use p2p::EnclaveRouter; +use bfv::EnclaveBFV; use tokio::{ self, io::{self, AsyncBufReadExt, BufReader}, @@ -33,6 +34,8 @@ async fn main() -> Result<(), Box> { println!("\n\n\n\n"); println!("Hello, cipher world!"); + let new_bfv = EnclaveBFV::new(4096, 4096, vec![0xffffee001, 0xffffc4001, 0x1ffffe0001]); + let (mut p2p, tx, mut rx) = EnclaveRouter::new()?; p2p.connect_swarm("mdns".to_string())?; p2p.join_topic("enclave-keygen-01")?; From 487a3994b892f8108f50e67f9702c7ce91cca988 Mon Sep 17 00:00:00 2001 From: nginnever Date: Tue, 27 Aug 2024 13:25:39 -0700 Subject: [PATCH 23/87] serialize pk --- packages/ciphernode/bfv/src/lib.rs | 24 +++++++++++--------- packages/ciphernode/enclave_node/src/main.rs | 3 ++- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/packages/ciphernode/bfv/src/lib.rs b/packages/ciphernode/bfv/src/lib.rs index 2a98d6d3..c269e3fd 100644 --- a/packages/ciphernode/bfv/src/lib.rs +++ b/packages/ciphernode/bfv/src/lib.rs @@ -14,9 +14,10 @@ use rand::{Rng, rngs::OsRng, thread_rng}; use util::timeit::{timeit}; pub struct EnclaveBFV { - pk_share: PublicKeyShare, - params: Arc, - crp: CommonRandomPoly, + pub pk_share: PublicKeyShare, + sk_share: SecretKey, + pub params: Arc, + pub crp: CommonRandomPoly, } impl EnclaveBFV { @@ -36,13 +37,14 @@ impl EnclaveBFV { ); let crp = CommonRandomPoly::new(¶ms, &mut thread_rng()).unwrap(); - //let crp_bytes = crp.to_bytes(); - let sk_share_1 = SecretKey::random(¶ms, &mut OsRng); - let pk_share_1 = PublicKeyShare::new(&sk_share_1, crp.clone(), &mut thread_rng()).unwrap(); - // serialize pk_share - let pk_share = pk_share_1.to_bytes(); - let sk_share = sk_share_1.coeffs.into_vec(); - - Self { pk_share: pk_share_1, params, crp } + //TODO: save encrypted sk_share to disk? + let sk_share = SecretKey::random(¶ms, &mut OsRng); + let pk_share = PublicKeyShare::new(&sk_share, crp.clone(), &mut thread_rng()).unwrap(); + + Self { pk_share, sk_share, params, crp } + } + + pub fn get_pk_bytes(&mut self) -> Vec { + self.pk_share.to_bytes() } } \ No newline at end of file diff --git a/packages/ciphernode/enclave_node/src/main.rs b/packages/ciphernode/enclave_node/src/main.rs index 85640d37..3ab37ef3 100644 --- a/packages/ciphernode/enclave_node/src/main.rs +++ b/packages/ciphernode/enclave_node/src/main.rs @@ -34,7 +34,8 @@ async fn main() -> Result<(), Box> { println!("\n\n\n\n"); println!("Hello, cipher world!"); - let new_bfv = EnclaveBFV::new(4096, 4096, vec![0xffffee001, 0xffffc4001, 0x1ffffe0001]); + let mut new_bfv = EnclaveBFV::new(4096, 4096, vec![0xffffee001, 0xffffc4001, 0x1ffffe0001]); + let pk_bytes = new_bfv.get_pk_bytes(); let (mut p2p, tx, mut rx) = EnclaveRouter::new()?; p2p.connect_swarm("mdns".to_string())?; From bf992b8c421dc78bfc45b8206d84f42338ece8eb Mon Sep 17 00:00:00 2001 From: nginnever Date: Tue, 27 Aug 2024 13:57:02 -0700 Subject: [PATCH 24/87] serialization lib --- packages/ciphernode/bfv/src/lib.rs | 27 ++++++++++++++++++-- packages/ciphernode/enclave_node/src/main.rs | 5 +++- 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/packages/ciphernode/bfv/src/lib.rs b/packages/ciphernode/bfv/src/lib.rs index c269e3fd..d8e55781 100644 --- a/packages/ciphernode/bfv/src/lib.rs +++ b/packages/ciphernode/bfv/src/lib.rs @@ -9,7 +9,7 @@ use fhe::{ bfv::{BfvParameters, BfvParametersBuilder, Ciphertext, Encoding, Plaintext, SecretKey}, mbfv::{AggregateIter, CommonRandomPoly, DecryptionShare, PublicKeyShare}, }; -use fhe_traits::{FheDecoder, Serialize as FheSerialize, DeserializeParametrized}; +use fhe_traits::{FheDecoder, Serialize as FheSerialize, Deserialize, DeserializeParametrized}; use rand::{Rng, rngs::OsRng, thread_rng}; use util::timeit::{timeit}; @@ -44,7 +44,30 @@ impl EnclaveBFV { Self { pk_share, sk_share, params, crp } } - pub fn get_pk_bytes(&mut self) -> Vec { + pub fn serialize_pk(&mut self) -> Vec { self.pk_share.to_bytes() } + + pub fn deserialize_pk(&mut self, bytes: Vec, par_bytes: Vec, crp_bytes: Vec) -> PublicKeyShare { + let params = Arc::new(BfvParameters::try_deserialize(&par_bytes).unwrap()); + let crp = CommonRandomPoly::deserialize(&crp_bytes, ¶ms).unwrap(); + PublicKeyShare::deserialize(&bytes, ¶ms, crp.clone()).unwrap() + } + + pub fn serialize_crp(&mut self) -> Vec { + self.crp.to_bytes() + } + + pub fn deserialize_crp(&mut self, bytes: Vec, par_bytes: Vec) -> CommonRandomPoly { + let params = Arc::new(BfvParameters::try_deserialize(&par_bytes).unwrap()); + CommonRandomPoly::deserialize(&bytes, ¶ms).unwrap() + } + + pub fn serialize_params(&mut self) -> Vec { + self.params.to_bytes() + } + + pub fn deserialize_params(&mut self, par_bytes: Vec) -> Arc { + Arc::new(BfvParameters::try_deserialize(&par_bytes).unwrap()) + } } \ No newline at end of file diff --git a/packages/ciphernode/enclave_node/src/main.rs b/packages/ciphernode/enclave_node/src/main.rs index 3ab37ef3..9ad0668f 100644 --- a/packages/ciphernode/enclave_node/src/main.rs +++ b/packages/ciphernode/enclave_node/src/main.rs @@ -35,7 +35,10 @@ async fn main() -> Result<(), Box> { println!("Hello, cipher world!"); let mut new_bfv = EnclaveBFV::new(4096, 4096, vec![0xffffee001, 0xffffc4001, 0x1ffffe0001]); - let pk_bytes = new_bfv.get_pk_bytes(); + let pk_bytes = new_bfv.serialize_pk(); + let param_bytes = new_bfv.serialize_params(); + let crp_bytes = new_bfv.serialize_crp(); + let deserialized_pk = new_bfv.deserialize_pk(pk_bytes, param_bytes, crp_bytes); let (mut p2p, tx, mut rx) = EnclaveRouter::new()?; p2p.connect_swarm("mdns".to_string())?; From 64c50593bfdfefeb6ef563d5d07ef6b29de7ffda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=B3=CE=BB?= Date: Wed, 28 Aug 2024 09:30:04 +1000 Subject: [PATCH 25/87] Add binaries for demonstrating Actor model flexability (#23) --- .../enclave_node/src/bin/aggregator.rs | 19 +++++++++++++++++ .../enclave_node/src/bin/ciphernode-noag.rs | 21 +++++++++++++++++++ 2 files changed, 40 insertions(+) create mode 100644 packages/ciphernode/enclave_node/src/bin/aggregator.rs create mode 100644 packages/ciphernode/enclave_node/src/bin/ciphernode-noag.rs diff --git a/packages/ciphernode/enclave_node/src/bin/aggregator.rs b/packages/ciphernode/enclave_node/src/bin/aggregator.rs new file mode 100644 index 00000000..70d32a10 --- /dev/null +++ b/packages/ciphernode/enclave_node/src/bin/aggregator.rs @@ -0,0 +1,19 @@ +use enclave_core::Actor; +use enclave_core::CommitteeManager; +use enclave_core::EventBus; +use enclave_core::Fhe; +use enclave_core::P2p; +use enclave_core::SimpleLogger; +use std::error::Error; + +#[actix_rt::main] +async fn main() -> Result<(), Box> { + let fhe = Fhe::try_default()?.start(); + let bus = EventBus::new(true).start(); + SimpleLogger::attach(bus.clone()); + CommitteeManager::attach(bus.clone(), fhe.clone()); + let (_, h) = P2p::spawn_libp2p(bus.clone())?; + println!("Aggregator"); + let _ = tokio::join!(h); + Ok(()) +} diff --git a/packages/ciphernode/enclave_node/src/bin/ciphernode-noag.rs b/packages/ciphernode/enclave_node/src/bin/ciphernode-noag.rs new file mode 100644 index 00000000..627af0b3 --- /dev/null +++ b/packages/ciphernode/enclave_node/src/bin/ciphernode-noag.rs @@ -0,0 +1,21 @@ +use enclave_core::Actor; +use enclave_core::Ciphernode; +use enclave_core::Data; +use enclave_core::EventBus; +use enclave_core::Fhe; +use enclave_core::P2p; +use enclave_core::SimpleLogger; +use std::error::Error; + +#[actix_rt::main] +async fn main() -> Result<(), Box> { + let fhe = Fhe::try_default()?.start(); + let bus = EventBus::new(true).start(); + let data = Data::new(true).start(); // TODO: Use a sled backed Data Actor + SimpleLogger::attach(bus.clone()); + Ciphernode::attach(bus.clone(), fhe.clone(), data.clone()); + let (_, h) = P2p::spawn_libp2p(bus.clone())?; + println!("Ciphernode"); + let _ = tokio::join!(h); + Ok(()) +} From 4203446cdb8ba42344bcaea42c746e1fb49a6c12 Mon Sep 17 00:00:00 2001 From: Hamza Khalid Date: Wed, 28 Aug 2024 21:28:20 +0500 Subject: [PATCH 26/87] feat: Contract Listener --- packages/ciphernode/Cargo.lock | 2145 ++++++++++++++++++++++- packages/ciphernode/eth/Cargo.toml | 5 + packages/ciphernode/eth/src/lib.rs | 13 +- packages/ciphernode/eth/src/listener.rs | 81 + packages/ciphernode/eth/src/manager.rs | 30 + 5 files changed, 2225 insertions(+), 49 deletions(-) create mode 100644 packages/ciphernode/eth/src/listener.rs create mode 100644 packages/ciphernode/eth/src/manager.rs diff --git a/packages/ciphernode/Cargo.lock b/packages/ciphernode/Cargo.lock index cf83b740..d221500b 100644 --- a/packages/ciphernode/Cargo.lock +++ b/packages/ciphernode/Cargo.lock @@ -136,11 +136,730 @@ version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" +[[package]] +name = "alloy" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f4a4aaae80afd4be443a6aecd92a6b255dcdd000f97996928efb33d8a71e100" +dependencies = [ + "alloy-consensus", + "alloy-contract", + "alloy-core", + "alloy-eips", + "alloy-genesis", + "alloy-network", + "alloy-provider", + "alloy-pubsub", + "alloy-rpc-client", + "alloy-rpc-types", + "alloy-serde", + "alloy-signer", + "alloy-signer-local", + "alloy-transport", + "alloy-transport-http", + "alloy-transport-ipc", + "alloy-transport-ws", +] + +[[package]] +name = "alloy-chains" +version = "0.1.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb07629a5d0645d29f68d2fb6f4d0cf15c89ec0965be915f303967180929743f" +dependencies = [ + "num_enum", + "strum", +] + +[[package]] +name = "alloy-consensus" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04c309895995eaa4bfcc345f5515a39c7df9447798645cc8bf462b6c5bf1dc96" +dependencies = [ + "alloy-eips", + "alloy-primitives 0.7.7", + "alloy-rlp", + "alloy-serde", + "c-kzg", + "serde", +] + +[[package]] +name = "alloy-contract" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f4e0ef72b0876ae3068b2ed7dfae9ae1779ce13cfaec2ee1f08f5bd0348dc57" +dependencies = [ + "alloy-dyn-abi", + "alloy-json-abi", + "alloy-network", + "alloy-network-primitives", + "alloy-primitives 0.7.7", + "alloy-provider", + "alloy-pubsub", + "alloy-rpc-types-eth", + "alloy-sol-types 0.7.7", + "alloy-transport", + "futures", + "futures-util", + "thiserror", +] + +[[package]] +name = "alloy-core" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "529fc6310dc1126c8de51c376cbc59c79c7f662bd742be7dc67055d5421a81b4" +dependencies = [ + "alloy-dyn-abi", + "alloy-json-abi", + "alloy-primitives 0.7.7", + "alloy-sol-types 0.7.7", +] + +[[package]] +name = "alloy-dyn-abi" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413902aa18a97569e60f679c23f46a18db1656d87ab4d4e49d0e1e52042f66df" +dependencies = [ + "alloy-json-abi", + "alloy-primitives 0.7.7", + "alloy-sol-type-parser", + "alloy-sol-types 0.7.7", + "const-hex", + "itoa", + "serde", + "serde_json", + "winnow", +] + +[[package]] +name = "alloy-eips" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9431c99a3b3fe606ede4b3d4043bdfbcb780c45b8d8d226c3804e2b75cfbe68" +dependencies = [ + "alloy-primitives 0.7.7", + "alloy-rlp", + "alloy-serde", + "c-kzg", + "derive_more", + "k256", + "once_cell", + "serde", + "sha2", +] + +[[package]] +name = "alloy-genesis" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79614dfe86144328da11098edcc7bc1a3f25ad8d3134a9eb9e857e06f0d9840d" +dependencies = [ + "alloy-primitives 0.7.7", + "alloy-serde", + "serde", +] + +[[package]] +name = "alloy-json-abi" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc05b04ac331a9f07e3a4036ef7926e49a8bf84a99a1ccfc7e2ab55a5fcbb372" +dependencies = [ + "alloy-primitives 0.7.7", + "alloy-sol-type-parser", + "serde", + "serde_json", +] + +[[package]] +name = "alloy-json-rpc" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57e2865c4c3bb4cdad3f0d9ec1ab5c0c657ba69a375651bd35e32fb6c180ccc2" +dependencies = [ + "alloy-primitives 0.7.7", + "alloy-sol-types 0.7.7", + "serde", + "serde_json", + "thiserror", + "tracing", +] + +[[package]] +name = "alloy-network" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e701fc87ef9a3139154b0b4ccb935b565d27ffd9de020fe541bf2dec5ae4ede" +dependencies = [ + "alloy-consensus", + "alloy-eips", + "alloy-json-rpc", + "alloy-network-primitives", + "alloy-primitives 0.7.7", + "alloy-rpc-types-eth", + "alloy-serde", + "alloy-signer", + "alloy-sol-types 0.7.7", + "async-trait", + "auto_impl", + "futures-utils-wasm", + "thiserror", +] + +[[package]] +name = "alloy-network-primitives" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec9d5a0f9170b10988b6774498a022845e13eda94318440d17709d50687f67f9" +dependencies = [ + "alloy-primitives 0.7.7", + "alloy-serde", + "serde", +] + +[[package]] +name = "alloy-primitives" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "600d34d8de81e23b6d909c094e23b3d357e01ca36b78a8c5424c501eedbe86f0" +dependencies = [ + "alloy-rlp", + "bytes", + "cfg-if", + "const-hex", + "derive_more", + "hex-literal", + "itoa", + "k256", + "keccak-asm", + "proptest", + "rand", + "ruint", + "serde", + "tiny-keccak", +] + +[[package]] +name = "alloy-primitives" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccb3ead547f4532bc8af961649942f0b9c16ee9226e26caa3f38420651cc0bf4" +dependencies = [ + "alloy-rlp", + "bytes", + "cfg-if", + "const-hex", + "derive_more", + "hex-literal", + "itoa", + "k256", + "keccak-asm", + "proptest", + "rand", + "ruint", + "serde", + "tiny-keccak", +] + +[[package]] +name = "alloy-provider" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9c0ab10b93de601a6396fc7ff2ea10d3b28c46f079338fa562107ebf9857c8" +dependencies = [ + "alloy-chains", + "alloy-consensus", + "alloy-eips", + "alloy-json-rpc", + "alloy-network", + "alloy-network-primitives", + "alloy-primitives 0.7.7", + "alloy-pubsub", + "alloy-rpc-client", + "alloy-rpc-types-eth", + "alloy-transport", + "alloy-transport-http", + "alloy-transport-ipc", + "alloy-transport-ws", + "async-stream", + "async-trait", + "auto_impl", + "dashmap", + "futures", + "futures-utils-wasm", + "lru", + "pin-project", + "reqwest", + "serde", + "serde_json", + "tokio", + "tracing", + "url", +] + +[[package]] +name = "alloy-pubsub" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f5da2c55cbaf229bad3c5f8b00b5ab66c74ef093e5f3a753d874cfecf7d2281" +dependencies = [ + "alloy-json-rpc", + "alloy-primitives 0.7.7", + "alloy-transport", + "bimap", + "futures", + "serde", + "serde_json", + "tokio", + "tokio-stream", + "tower", + "tracing", +] + +[[package]] +name = "alloy-rlp" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26154390b1d205a4a7ac7352aa2eb4f81f391399d4e2f546fb81a2f8bb383f62" +dependencies = [ + "alloy-rlp-derive", + "arrayvec", + "bytes", +] + +[[package]] +name = "alloy-rlp-derive" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d0f2d905ebd295e7effec65e5f6868d153936130ae718352771de3e7d03c75c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.72", +] + +[[package]] +name = "alloy-rpc-client" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b38e3ffdb285df5d9f60cb988d336d9b8e3505acb78750c3bc60336a7af41d3" +dependencies = [ + "alloy-json-rpc", + "alloy-primitives 0.7.7", + "alloy-pubsub", + "alloy-transport", + "alloy-transport-http", + "alloy-transport-ipc", + "alloy-transport-ws", + "futures", + "pin-project", + "reqwest", + "serde", + "serde_json", + "tokio", + "tokio-stream", + "tower", + "tracing", + "url", +] + +[[package]] +name = "alloy-rpc-types" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c31a3750b8f5a350d17354e46a52b0f2f19ec5f2006d816935af599dedc521" +dependencies = [ + "alloy-rpc-types-engine", + "alloy-rpc-types-eth", + "alloy-serde", + "serde", +] + +[[package]] +name = "alloy-rpc-types-engine" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff63f51b2fb2f547df5218527fd0653afb1947bf7fead5b3ce58c75d170b30f7" +dependencies = [ + "alloy-consensus", + "alloy-eips", + "alloy-primitives 0.7.7", + "alloy-rlp", + "alloy-rpc-types-eth", + "alloy-serde", + "jsonwebtoken", + "rand", + "serde", + "thiserror", +] + +[[package]] +name = "alloy-rpc-types-eth" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81e18424d962d7700a882fe423714bd5b9dde74c7a7589d4255ea64068773aef" +dependencies = [ + "alloy-consensus", + "alloy-eips", + "alloy-network-primitives", + "alloy-primitives 0.7.7", + "alloy-rlp", + "alloy-serde", + "alloy-sol-types 0.7.7", + "itertools 0.13.0", + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "alloy-serde" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e33feda6a53e6079895aed1d08dcb98a1377b000d80d16370fbbdb8155d547ef" +dependencies = [ + "alloy-primitives 0.7.7", + "serde", + "serde_json", +] + +[[package]] +name = "alloy-signer" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "740a25b92e849ed7b0fa013951fe2f64be9af1ad5abe805037b44fb7770c5c47" +dependencies = [ + "alloy-primitives 0.7.7", + "async-trait", + "auto_impl", + "elliptic-curve", + "k256", + "thiserror", +] + +[[package]] +name = "alloy-signer-local" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b0707d4f63e4356a110b30ef3add8732ab6d181dd7be4607bf79b8777105cee" +dependencies = [ + "alloy-consensus", + "alloy-network", + "alloy-primitives 0.7.7", + "alloy-signer", + "async-trait", + "k256", + "rand", + "thiserror", +] + +[[package]] +name = "alloy-sol-macro" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e86ec0a47740b20bc5613b8712d0d321d031c4efc58e9645af96085d5cccfc27" +dependencies = [ + "const-hex", + "dunce", + "heck 0.4.1", + "indexmap", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 2.0.72", + "syn-solidity 0.6.4", + "tiny-keccak", +] + +[[package]] +name = "alloy-sol-macro" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b40397ddcdcc266f59f959770f601ce1280e699a91fc1862f29cef91707cd09" +dependencies = [ + "alloy-sol-macro-expander", + "alloy-sol-macro-input", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 2.0.72", +] + +[[package]] +name = "alloy-sol-macro-expander" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "867a5469d61480fea08c7333ffeca52d5b621f5ca2e44f271b117ec1fc9a0525" +dependencies = [ + "alloy-json-abi", + "alloy-sol-macro-input", + "const-hex", + "heck 0.5.0", + "indexmap", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 2.0.72", + "syn-solidity 0.7.7", + "tiny-keccak", +] + +[[package]] +name = "alloy-sol-macro-input" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e482dc33a32b6fadbc0f599adea520bd3aaa585c141a80b404d0a3e3fa72528" +dependencies = [ + "alloy-json-abi", + "const-hex", + "dunce", + "heck 0.5.0", + "proc-macro2", + "quote", + "serde_json", + "syn 2.0.72", + "syn-solidity 0.7.7", +] + +[[package]] +name = "alloy-sol-type-parser" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbcba3ca07cf7975f15d871b721fb18031eec8bce51103907f6dcce00b255d98" +dependencies = [ + "serde", + "winnow", +] + +[[package]] +name = "alloy-sol-types" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad09ec5853fa700d12d778ad224dcdec636af424d29fad84fb9a2f16a5b0ef09" +dependencies = [ + "alloy-primitives 0.6.4", + "alloy-sol-macro 0.6.4", + "const-hex", + "serde", +] + +[[package]] +name = "alloy-sol-types" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a91ca40fa20793ae9c3841b83e74569d1cc9af29a2f5237314fd3452d51e38c7" +dependencies = [ + "alloy-json-abi", + "alloy-primitives 0.7.7", + "alloy-sol-macro 0.7.7", + "const-hex", + "serde", +] + +[[package]] +name = "alloy-transport" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d0590afbdacf2f8cca49d025a2466f3b6584a016a8b28f532f29f8da1007bae" +dependencies = [ + "alloy-json-rpc", + "base64 0.22.1", + "futures-util", + "futures-utils-wasm", + "serde", + "serde_json", + "thiserror", + "tokio", + "tower", + "tracing", + "url", +] + +[[package]] +name = "alloy-transport-http" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2437d145d80ea1aecde8574d2058cceb8b3c9cba05f6aea8e67907c660d46698" +dependencies = [ + "alloy-json-rpc", + "alloy-transport", + "reqwest", + "serde_json", + "tower", + "tracing", + "url", +] + +[[package]] +name = "alloy-transport-ipc" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "804494366e20468776db4e18f9eb5db7db0fe14f1271eb6dbf155d867233405c" +dependencies = [ + "alloy-json-rpc", + "alloy-pubsub", + "alloy-transport", + "bytes", + "futures", + "interprocess", + "pin-project", + "serde_json", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "alloy-transport-ws" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af855163e7df008799941aa6dd324a43ef2bf264b08ba4b22d44aad6ced65300" +dependencies = [ + "alloy-pubsub", + "alloy-transport", + "futures", + "http 1.1.0", + "rustls", + "serde_json", + "tokio", + "tokio-tungstenite", + "tracing", + "ws_stream_wasm", +] + [[package]] name = "anyhow" version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" +checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" + +[[package]] +name = "ark-ff" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b3235cc41ee7a12aaaf2c575a2ad7b46713a8a50bda2fc3b003a04845c05dd6" +dependencies = [ + "ark-ff-asm 0.3.0", + "ark-ff-macros 0.3.0", + "ark-serialize 0.3.0", + "ark-std 0.3.0", + "derivative", + "num-bigint", + "num-traits", + "paste", + "rustc_version 0.3.3", + "zeroize", +] + +[[package]] +name = "ark-ff" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec847af850f44ad29048935519032c33da8aa03340876d351dfab5660d2966ba" +dependencies = [ + "ark-ff-asm 0.4.2", + "ark-ff-macros 0.4.2", + "ark-serialize 0.4.2", + "ark-std 0.4.0", + "derivative", + "digest 0.10.7", + "itertools 0.10.5", + "num-bigint", + "num-traits", + "paste", + "rustc_version 0.4.0", + "zeroize", +] + +[[package]] +name = "ark-ff-asm" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db02d390bf6643fb404d3d22d31aee1c4bc4459600aef9113833d17e786c6e44" +dependencies = [ + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-ff-asm" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ed4aa4fe255d0bc6d79373f7e31d2ea147bcf486cba1be5ba7ea85abdb92348" +dependencies = [ + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-ff-macros" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db2fd794a08ccb318058009eefdf15bcaaaaf6f8161eb3345f907222bac38b20" +dependencies = [ + "num-bigint", + "num-traits", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-ff-macros" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7abe79b0e4288889c4574159ab790824d0033b9fdcb2a112a3182fac2e514565" +dependencies = [ + "num-bigint", + "num-traits", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-serialize" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d6c2b318ee6e10f8c2853e73a83adc0ccb88995aa978d8a3408d492ab2ee671" +dependencies = [ + "ark-std 0.3.0", + "digest 0.9.0", +] + +[[package]] +name = "ark-serialize" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adb7b85a02b83d2f22f89bd5cac66c9c89474240cb6207cb1efc16d098e822a5" +dependencies = [ + "ark-std 0.4.0", + "digest 0.10.7", + "num-bigint", +] + +[[package]] +name = "ark-std" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1df2c09229cbc5a028b1d70e00fdb2acee28b1055dfb5ca73eea49c5a25c4e7c" +dependencies = [ + "num-traits", + "rand", +] + +[[package]] +name = "ark-std" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185" +dependencies = [ + "num-traits", + "rand", +] [[package]] name = "arrayref" @@ -148,6 +867,12 @@ version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d151e35f61089500b617991b791fc8bfd237ae50cd5950803758a179b41e67a" +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + [[package]] name = "asn1-rs" version = "0.6.2" @@ -408,6 +1133,28 @@ dependencies = [ "socket2 0.5.7", ] +[[package]] +name = "async-stream" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd56dd203fef61ac097dd65721a419ddccb106b2d2b70ba60a6b529f03961a51" +dependencies = [ + "async-stream-impl", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-stream-impl" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.72", +] + [[package]] name = "async-task" version = "4.7.1" @@ -425,6 +1172,17 @@ dependencies = [ "syn 2.0.72", ] +[[package]] +name = "async_io_stream" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6d7b9decdf35d8908a7e3ef02f64c5e9b1695e230154c0e8de3969142d9b94c" +dependencies = [ + "futures", + "pharos", + "rustc_version 0.4.0", +] + [[package]] name = "asynchronous-codec" version = "0.6.2" @@ -463,11 +1221,22 @@ version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d9a9bf8b79a749ee0b911b91b671cc2b6c670bdbc7e3dfd537576ddc94bb2a2" dependencies = [ - "http", + "http 0.2.12", "log", "url", ] +[[package]] +name = "auto_impl" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c87f3f15e7794432337fc718554eaa4dc8f04c9677a950ffe366f20a162ae42" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.72", +] + [[package]] name = "autocfg" version = "1.3.0" @@ -495,6 +1264,12 @@ version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4cbbc9d0964165b47557570cce6c952866c2678457aca742aafc9fb771d30270" +[[package]] +name = "base16ct" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" + [[package]] name = "base64" version = "0.21.7" @@ -539,6 +1314,21 @@ dependencies = [ "serde", ] +[[package]] +name = "bit-set" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" + [[package]] name = "bitflags" version = "1.3.2" @@ -551,13 +1341,25 @@ version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + [[package]] name = "blake2" version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" dependencies = [ - "digest", + "digest 0.10.7", ] [[package]] @@ -582,6 +1384,18 @@ dependencies = [ "piper", ] +[[package]] +name = "blst" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4378725facc195f1a538864863f6de233b500a8862747e7f165078a419d5e874" +dependencies = [ + "cc", + "glob", + "threadpool", + "zeroize", +] + [[package]] name = "bs58" version = "0.5.1" @@ -597,6 +1411,12 @@ version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" +[[package]] +name = "byte-slice-cast" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" + [[package]] name = "byteorder" version = "1.5.0" @@ -608,6 +1428,24 @@ name = "bytes" version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50" +dependencies = [ + "serde", +] + +[[package]] +name = "c-kzg" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0307f72feab3300336fb803a57134159f6e20139af1357f36c54cb90d8e8928" +dependencies = [ + "blst", + "cc", + "glob", + "hex", + "libc", + "once_cell", + "serde", +] [[package]] name = "cc" @@ -665,12 +1503,31 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "const-hex" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94fb8a24a26d37e1ffd45343323dc9fe6654ceea44c12f2fcb3d7ac29e610bc6" +dependencies = [ + "cfg-if", + "cpufeatures", + "hex", + "proptest", + "serde", +] + [[package]] name = "const-oid" version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" +[[package]] +name = "convert_case" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" + [[package]] name = "core-foundation" version = "0.9.4" @@ -720,6 +1577,24 @@ version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + +[[package]] +name = "crypto-bigint" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" +dependencies = [ + "generic-array", + "rand_core", + "subtle", + "zeroize", +] + [[package]] name = "crypto-common" version = "0.1.6" @@ -749,9 +1624,9 @@ dependencies = [ "cfg-if", "cpufeatures", "curve25519-dalek-derive", - "digest", + "digest 0.10.7", "fiat-crypto", - "rustc_version", + "rustc_version 0.4.0", "subtle", "zeroize", ] @@ -767,6 +1642,19 @@ dependencies = [ "syn 2.0.72", ] +[[package]] +name = "dashmap" +version = "5.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" +dependencies = [ + "cfg-if", + "hashbrown", + "lock_api", + "once_cell", + "parking_lot_core", +] + [[package]] name = "data-encoding" version = "2.6.0" @@ -826,6 +1714,39 @@ dependencies = [ "powerfmt", ] +[[package]] +name = "derivative" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "derive_more" +version = "0.99.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f33878137e4dafd7fa914ad4e259e18a4e8e532b9617a2d0150262bf53abfce" +dependencies = [ + "convert_case", + "proc-macro2", + "quote", + "rustc_version 0.4.0", + "syn 2.0.72", +] + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array", +] + [[package]] name = "digest" version = "0.10.7" @@ -833,6 +1754,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer", + "const-oid", "crypto-common", "subtle", ] @@ -854,12 +1776,38 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" +[[package]] +name = "doctest-file" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aac81fa3e28d21450aa4d2ac065992ba96a1d7303efbce51a95f4fd175b67562" + [[package]] name = "dtoa" version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dcbb2bf8e87535c23f7a8a321e364ce21462d0ff10cb6407820e8e96dfff6653" +[[package]] +name = "dunce" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" + +[[package]] +name = "ecdsa" +version = "0.16.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" +dependencies = [ + "der", + "digest 0.10.7", + "elliptic-curve", + "rfc6979", + "signature", + "spki", +] + [[package]] name = "ed25519" version = "2.2.3" @@ -891,6 +1839,25 @@ version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" +[[package]] +name = "elliptic-curve" +version = "0.13.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" +dependencies = [ + "base16ct", + "crypto-bigint", + "digest 0.10.7", + "ff", + "generic-array", + "group", + "pkcs8", + "rand_core", + "sec1", + "subtle", + "zeroize", +] + [[package]] name = "enclave" version = "0.1.0" @@ -973,10 +1940,15 @@ dependencies = [ name = "eth" version = "0.1.0" dependencies = [ + "alloy", + "alloy-primitives 0.6.4", + "alloy-sol-types 0.6.4", "async-std", + "eyre", "fhe", "fhe-traits", "fhe-util", + "futures-util", ] [[package]] @@ -1023,20 +1995,51 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "eyre" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cd915d99f24784cdc19fd37ef22b97e3ff0ae756c7e492e9fbfe897d61e2aec" +dependencies = [ + "indenter", + "once_cell", +] + [[package]] name = "fastrand" version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" +checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" +dependencies = [ + "instant", +] + +[[package]] +name = "fastrand" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" + +[[package]] +name = "fastrlp" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "139834ddba373bbdd213dffe02c8d110508dcf1726c2be27e8d1f7d7e1856418" dependencies = [ - "instant", + "arrayvec", + "auto_impl", + "bytes", ] [[package]] -name = "fastrand" -version = "2.1.0" +name = "ff" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" +checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" +dependencies = [ + "rand_core", + "subtle", +] [[package]] name = "fhe" @@ -1047,7 +2050,7 @@ dependencies = [ "fhe-math", "fhe-traits", "fhe-util", - "itertools", + "itertools 0.12.1", "ndarray", "num-bigint", "num-traits", @@ -1069,7 +2072,7 @@ dependencies = [ "ethnum", "fhe-traits", "fhe-util", - "itertools", + "itertools 0.12.1", "ndarray", "num-bigint", "num-bigint-dig", @@ -1096,7 +2099,7 @@ name = "fhe-util" version = "0.1.0-beta.7" source = "git+https://github.com/gnosisguild/fhe.rs#9624766dcfbb40ecfb01147f59c2f6292c447707" dependencies = [ - "itertools", + "itertools 0.12.1", "num-bigint-dig", "num-traits", "rand", @@ -1108,6 +2111,18 @@ version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" +[[package]] +name = "fixed-hash" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "835c052cb0c08c1acf6ffd71c022172e18723949c8282f2b9f27efbc51e64534" +dependencies = [ + "byteorder", + "rand", + "rustc-hex", + "static_assertions", +] + [[package]] name = "fixedbitset" version = "0.4.2" @@ -1120,6 +2135,21 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + [[package]] name = "form_urlencoded" version = "1.2.1" @@ -1129,6 +2159,12 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + [[package]] name = "futures" version = "0.3.30" @@ -1285,6 +2321,12 @@ dependencies = [ "slab", ] +[[package]] +name = "futures-utils-wasm" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42012b0f064e01aa58b545fe3727f90f7dd4020f4a3ea735b50344965f5a57e9" + [[package]] name = "generic-array" version = "0.14.7" @@ -1293,6 +2335,7 @@ checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ "typenum", "version_check", + "zeroize", ] [[package]] @@ -1302,8 +2345,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", + "js-sys", "libc", "wasi", + "wasm-bindgen", ] [[package]] @@ -1322,6 +2367,12 @@ version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + [[package]] name = "gloo-timers" version = "0.2.6" @@ -1334,6 +2385,17 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff", + "rand_core", + "subtle", +] + [[package]] name = "h2" version = "0.3.26" @@ -1345,7 +2407,7 @@ dependencies = [ "futures-core", "futures-sink", "futures-util", - "http", + "http 0.2.12", "indexmap", "slab", "tokio", @@ -1387,6 +2449,21 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +dependencies = [ + "serde", +] + +[[package]] +name = "hex-literal" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" + [[package]] name = "hex_fmt" version = "0.3.0" @@ -1454,7 +2531,7 @@ version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" dependencies = [ - "digest", + "digest 0.10.7", ] [[package]] @@ -1479,6 +2556,17 @@ dependencies = [ "itoa", ] +[[package]] +name = "http" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + [[package]] name = "http-body" version = "0.4.6" @@ -1486,7 +2574,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" dependencies = [ "bytes", - "http", + "http 0.2.12", + "pin-project-lite", +] + +[[package]] +name = "http-body" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +dependencies = [ + "bytes", + "http 1.1.0", +] + +[[package]] +name = "http-body-util" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" +dependencies = [ + "bytes", + "futures-util", + "http 1.1.0", + "http-body 1.0.1", "pin-project-lite", ] @@ -1513,8 +2624,8 @@ dependencies = [ "futures-core", "futures-util", "h2", - "http", - "http-body", + "http 0.2.12", + "http-body 0.4.6", "httparse", "httpdate", "itoa", @@ -1526,6 +2637,61 @@ dependencies = [ "want", ] +[[package]] +name = "hyper" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50dfd22e0e76d0f662d429a5f80fcaf3855009297eab6a0a9f8543834744ba05" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "http 1.1.0", + "http-body 1.0.1", + "httparse", + "itoa", + "pin-project-lite", + "smallvec", + "tokio", + "want", +] + +[[package]] +name = "hyper-tls" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" +dependencies = [ + "bytes", + "http-body-util", + "hyper 1.4.1", + "hyper-util", + "native-tls", + "tokio", + "tokio-native-tls", + "tower-service", +] + +[[package]] +name = "hyper-util" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cde7055719c54e36e95e8719f95883f22072a48ede39db7fc17a4e1d5281e9b9" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "http 1.1.0", + "http-body 1.0.1", + "hyper 1.4.1", + "pin-project-lite", + "socket2 0.5.7", + "tokio", + "tower", + "tower-service", + "tracing", +] + [[package]] name = "idna" version = "0.4.0" @@ -1586,8 +2752,8 @@ dependencies = [ "attohttpc", "bytes", "futures", - "http", - "hyper", + "http 0.2.12", + "hyper 0.14.30", "log", "rand", "tokio", @@ -1595,6 +2761,32 @@ dependencies = [ "xmltree", ] +[[package]] +name = "impl-codec" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba6a270039626615617f3f36d15fc827041df3b78c439da2cadfa47455a77f2f" +dependencies = [ + "parity-scale-codec", +] + +[[package]] +name = "impl-trait-for-tuples" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11d7a9f6330b71fea57921c9b61c47ee6e84f72d394754eff6163ae67e7395eb" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "indenter" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" + [[package]] name = "indexmap" version = "2.3.0" @@ -1623,6 +2815,21 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "interprocess" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2f4e4a06d42fab3e85ab1b419ad32b09eab58b901d40c57935ff92db3287a13" +dependencies = [ + "doctest-file", + "futures-core", + "libc", + "recvmsg", + "tokio", + "widestring", + "windows-sys 0.52.0", +] + [[package]] name = "io-lifetimes" version = "1.0.11" @@ -1652,6 +2859,15 @@ version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + [[package]] name = "itertools" version = "0.12.1" @@ -1661,6 +2877,15 @@ dependencies = [ "either", ] +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.11" @@ -1676,6 +2901,45 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "jsonwebtoken" +version = "9.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9ae10193d25051e74945f1ea2d0b42e03cc3b890f7e4cc5faa44997d808193f" +dependencies = [ + "base64 0.21.7", + "js-sys", + "pem", + "ring 0.17.8", + "serde", + "serde_json", + "simple_asn1", +] + +[[package]] +name = "k256" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "956ff9b67e26e1a6a866cb758f12c6f8746208489e3e4a4b5580802f2f0a587b" +dependencies = [ + "cfg-if", + "ecdsa", + "elliptic-curve", + "once_cell", + "sha2", + "signature", +] + +[[package]] +name = "keccak-asm" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "422fbc7ff2f2f5bdffeb07718e5a5324dca72b0c9293d50df4026652385e3314" +dependencies = [ + "digest 0.10.7", + "sha3-asm", +] + [[package]] name = "kv-log-macro" version = "1.0.7" @@ -2349,6 +3613,12 @@ version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + [[package]] name = "minimal-lexical" version = "0.2.1" @@ -2436,6 +3706,23 @@ dependencies = [ "unsigned-varint 0.7.2", ] +[[package]] +name = "native-tls" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8614eb2c83d59d1c8cc974dd3f920198647674a0a035e1af1fa58707e317466" +dependencies = [ + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + [[package]] name = "ndarray" version = "0.15.6" @@ -2622,6 +3909,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", + "libm", ] [[package]] @@ -2634,6 +3922,26 @@ dependencies = [ "libc", ] +[[package]] +name = "num_enum" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e613fc340b2220f734a8595782c551f1250e969d87d3be1ae0579e8d4065179" +dependencies = [ + "num_enum_derive", +] + +[[package]] +name = "num_enum_derive" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.72", +] + [[package]] name = "object" version = "0.36.3" @@ -2656,13 +3964,57 @@ dependencies = [ name = "once_cell" version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "opaque-debug" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" + +[[package]] +name = "openssl" +version = "0.10.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9529f4786b70a3e8c61e11179af17ab6188ad8d0ded78c5529441ed39d4bd9c1" +dependencies = [ + "bitflags 2.6.0", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.72", +] + +[[package]] +name = "openssl-probe" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] -name = "opaque-debug" -version = "0.3.1" +name = "openssl-sys" +version = "0.9.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" +checksum = "7f9e8deee91df40a943c71b917e5874b951d32a802526c85721ce3b776c929d6" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] [[package]] name = "overload" @@ -2687,6 +4039,32 @@ dependencies = [ "tracing-subscriber", ] +[[package]] +name = "parity-scale-codec" +version = "3.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "306800abfa29c7f16596b5970a588435e3d5b3149683d00c12b699cc19f895ee" +dependencies = [ + "arrayvec", + "bitvec", + "byte-slice-cast", + "impl-trait-for-tuples", + "parity-scale-codec-derive", + "serde", +] + +[[package]] +name = "parity-scale-codec-derive" +version = "3.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d830939c76d294956402033aee57a6da7b438f2294eb94864c37b0569053a42c" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "parking" version = "2.2.0" @@ -2738,6 +4116,17 @@ version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" +[[package]] +name = "pest" +version = "2.7.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd53dff83f26735fdc1ca837098ccf133605d794cdae66acfc2bfac3ec809d95" +dependencies = [ + "memchr", + "thiserror", + "ucd-trie", +] + [[package]] name = "petgraph" version = "0.6.5" @@ -2748,6 +4137,16 @@ dependencies = [ "indexmap", ] +[[package]] +name = "pharos" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9567389417feee6ce15dd6527a8a1ecac205ef62c2932bcf3d9f6fc5b78b414" +dependencies = [ + "futures", + "rustc_version 0.4.0", +] + [[package]] name = "pin-project" version = "1.1.5" @@ -2801,6 +4200,12 @@ dependencies = [ "spki", ] +[[package]] +name = "pkg-config" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" + [[package]] name = "polling" version = "2.8.0" @@ -2880,6 +4285,50 @@ dependencies = [ "syn 2.0.72", ] +[[package]] +name = "primitive-types" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b34d9fd68ae0b74a41b21c03c2f62847aa0ffea044eee893b4c140b37e244e2" +dependencies = [ + "fixed-hash", + "impl-codec", + "uint", +] + +[[package]] +name = "proc-macro-crate" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b" +dependencies = [ + "toml_edit", +] + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn 1.0.109", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + [[package]] name = "proc-macro2" version = "1.0.86" @@ -2912,6 +4361,26 @@ dependencies = [ "syn 2.0.72", ] +[[package]] +name = "proptest" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4c2511913b88df1637da85cc8d96ec8e43a3f8bb8ccb71ee1ac240d6f3df58d" +dependencies = [ + "bit-set", + "bit-vec", + "bitflags 2.6.0", + "lazy_static", + "num-traits", + "rand", + "rand_chacha", + "rand_xorshift", + "regex-syntax 0.8.4", + "rusty-fork", + "tempfile", + "unarray", +] + [[package]] name = "prost" version = "0.12.6" @@ -2930,7 +4399,7 @@ checksum = "22505a5c94da8e3b7c2996394d1c933236c4d743e81a410bcca4e6989fc066a4" dependencies = [ "bytes", "heck 0.5.0", - "itertools", + "itertools 0.12.1", "log", "multimap", "once_cell", @@ -2950,7 +4419,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "81bddcdb20abf9501610992b6759a4c888aef7d1a7247ef75e2404275ac24af1" dependencies = [ "anyhow", - "itertools", + "itertools 0.12.1", "proc-macro2", "quote", "syn 2.0.72", @@ -3066,6 +4535,12 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + [[package]] name = "rand" version = "0.8.5" @@ -3096,6 +4571,15 @@ dependencies = [ "getrandom", ] +[[package]] +name = "rand_xorshift" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f" +dependencies = [ + "rand_core", +] + [[package]] name = "rawpointer" version = "0.2.1" @@ -3114,6 +4598,12 @@ dependencies = [ "yasna", ] +[[package]] +name = "recvmsg" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3edd4d5d42c92f0a659926464d4cce56b562761267ecf0f469d85b7de384175" + [[package]] name = "redox_syscall" version = "0.5.3" @@ -3167,6 +4657,45 @@ version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" +[[package]] +name = "reqwest" +version = "0.12.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8f4955649ef5c38cc7f9e8aa41761d48fb9677197daea9984dc54f56aad5e63" +dependencies = [ + "base64 0.22.1", + "bytes", + "futures-core", + "futures-util", + "http 1.1.0", + "http-body 1.0.1", + "http-body-util", + "hyper 1.4.1", + "hyper-tls", + "hyper-util", + "ipnet", + "js-sys", + "log", + "mime", + "native-tls", + "once_cell", + "percent-encoding", + "pin-project-lite", + "rustls-pemfile", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper", + "tokio", + "tokio-native-tls", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "windows-registry", +] + [[package]] name = "resolv-conf" version = "0.7.0" @@ -3177,6 +4706,16 @@ dependencies = [ "quick-error", ] +[[package]] +name = "rfc6979" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +dependencies = [ + "hmac", + "subtle", +] + [[package]] name = "ring" version = "0.16.20" @@ -3207,6 +4746,16 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "rlp" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb919243f34364b6bd2fc10ef797edbfa75f33c252e7998527479c6d6b47e1ec" +dependencies = [ + "bytes", + "rustc-hex", +] + [[package]] name = "rtnetlink" version = "0.10.1" @@ -3223,6 +4772,36 @@ dependencies = [ "tokio", ] +[[package]] +name = "ruint" +version = "1.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c3cc4c2511671f327125da14133d0c5c5d137f006a1017a16f557bc85b16286" +dependencies = [ + "alloy-rlp", + "ark-ff 0.3.0", + "ark-ff 0.4.2", + "bytes", + "fastrlp", + "num-bigint", + "num-traits", + "parity-scale-codec", + "primitive-types", + "proptest", + "rand", + "rlp", + "ruint-macro", + "serde", + "valuable", + "zeroize", +] + +[[package]] +name = "ruint-macro" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48fd7bd8a6377e15ad9d42a8ec25371b94ddc67abe7c8b9127bec79bebaaae18" + [[package]] name = "rustc-demangle" version = "0.1.24" @@ -3235,13 +4814,28 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152" +[[package]] +name = "rustc-hex" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6" + +[[package]] +name = "rustc_version" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0dfe2087c51c460008730de8b57e6a320782fbfb312e1f4d520e6c6fae155ee" +dependencies = [ + "semver 0.11.0", +] + [[package]] name = "rustc_version" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" dependencies = [ - "semver", + "semver 1.0.23", ] [[package]] @@ -3294,6 +4888,16 @@ dependencies = [ "zeroize", ] +[[package]] +name = "rustls-pemfile" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "196fe16b00e106300d3e45ecfcb764fa292a535d7326a29a5875c579c7417425" +dependencies = [ + "base64 0.22.1", + "rustls-pki-types", +] + [[package]] name = "rustls-pki-types" version = "1.8.0" @@ -3321,6 +4925,24 @@ dependencies = [ "untrusted 0.9.0", ] +[[package]] +name = "rustversion" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" + +[[package]] +name = "rusty-fork" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb3dcc6e454c328bb824492db107ab7c0ae8fcffe4ad210136ef014458c1bc4f" +dependencies = [ + "fnv", + "quick-error", + "tempfile", + "wait-timeout", +] + [[package]] name = "rw-stream-sink" version = "0.4.0" @@ -3332,12 +4954,41 @@ dependencies = [ "static_assertions", ] +[[package]] +name = "ryu" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" + +[[package]] +name = "schannel" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" +dependencies = [ + "windows-sys 0.52.0", +] + [[package]] name = "scopeguard" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "sec1" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" +dependencies = [ + "base16ct", + "der", + "generic-array", + "pkcs8", + "subtle", + "zeroize", +] + [[package]] name = "secp256k1" version = "0.29.0" @@ -3356,30 +5007,112 @@ dependencies = [ "cc", ] +[[package]] +name = "security-framework" +version = "2.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" +dependencies = [ + "bitflags 2.6.0", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75da29fe9b9b08fe9d6b22b5b4bcbc75d8db3aa31e639aa56bb62e9d46bfceaf" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "semver" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" +dependencies = [ + "semver-parser", +] + [[package]] name = "semver" version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" +checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" + +[[package]] +name = "semver-parser" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7" +dependencies = [ + "pest", +] + +[[package]] +name = "send_wrapper" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73" + +[[package]] +name = "serde" +version = "1.0.208" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cff085d2cb684faa248efb494c39b68e522822ac0de72ccf08109abde717cfb2" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.208" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24008e81ff7613ed8e5ba0cfaf24e2c2f1e5b8a0495711e44fcd4882fca62bcf" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.72", +] + +[[package]] +name = "serde_json" +version = "1.0.127" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8043c06d9f82bd7271361ed64f415fe5e12a77fdb52e573e7f06a516dea329ad" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", +] [[package]] -name = "serde" -version = "1.0.208" +name = "serde_urlencoded" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cff085d2cb684faa248efb494c39b68e522822ac0de72ccf08109abde717cfb2" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" dependencies = [ - "serde_derive", + "form_urlencoded", + "itoa", + "ryu", + "serde", ] [[package]] -name = "serde_derive" -version = "1.0.208" +name = "sha1" +version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24008e81ff7613ed8e5ba0cfaf24e2c2f1e5b8a0495711e44fcd4882fca62bcf" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.72", + "cfg-if", + "cpufeatures", + "digest 0.10.7", ] [[package]] @@ -3390,7 +5123,17 @@ checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" dependencies = [ "cfg-if", "cpufeatures", - "digest", + "digest 0.10.7", +] + +[[package]] +name = "sha3-asm" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57d79b758b7cb2085612b11a235055e485605a5103faccdd633f35bd7aee69dd" +dependencies = [ + "cc", + "cfg-if", ] [[package]] @@ -3417,9 +5160,22 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" dependencies = [ + "digest 0.10.7", "rand_core", ] +[[package]] +name = "simple_asn1" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adc4e5204eb1910f40f9cfa375f6f05b68c3abac4b6fd879c8ff5e7ae8a0a085" +dependencies = [ + "num-bigint", + "num-traits", + "thiserror", + "time", +] + [[package]] name = "slab" version = "0.4.9" @@ -3464,7 +5220,7 @@ dependencies = [ "curve25519-dalek", "rand_core", "ring 0.17.8", - "rustc_version", + "rustc_version 0.4.0", "sha2", "subtle", ] @@ -3517,6 +5273,28 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" +[[package]] +name = "strum" +version = "0.26.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" +dependencies = [ + "strum_macros", +] + +[[package]] +name = "strum_macros" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" +dependencies = [ + "heck 0.5.0", + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.72", +] + [[package]] name = "subtle" version = "2.6.1" @@ -3545,6 +5323,39 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "syn-solidity" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb3d0961cd53c23ea94eeec56ba940f636f6394788976e9f16ca5ee0aca7464a" +dependencies = [ + "paste", + "proc-macro2", + "quote", + "syn 2.0.72", +] + +[[package]] +name = "syn-solidity" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c837dc8852cb7074e46b444afb81783140dab12c58867b49fb3898fbafedf7ea" +dependencies = [ + "paste", + "proc-macro2", + "quote", + "syn 2.0.72", +] + +[[package]] +name = "sync_wrapper" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394" +dependencies = [ + "futures-core", +] + [[package]] name = "synstructure" version = "0.13.1" @@ -3577,6 +5388,12 @@ dependencies = [ "libc", ] +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + [[package]] name = "tempfile" version = "3.11.0" @@ -3620,6 +5437,15 @@ dependencies = [ "once_cell", ] +[[package]] +name = "threadpool" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa" +dependencies = [ + "num_cpus", +] + [[package]] name = "time" version = "0.3.36" @@ -3651,6 +5477,15 @@ dependencies = [ "time-core", ] +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + [[package]] name = "tinyvec" version = "1.8.0" @@ -3695,6 +5530,55 @@ dependencies = [ "syn 2.0.72", ] +[[package]] +name = "tokio-native-tls" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" +dependencies = [ + "native-tls", + "tokio", +] + +[[package]] +name = "tokio-rustls" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" +dependencies = [ + "rustls", + "rustls-pki-types", + "tokio", +] + +[[package]] +name = "tokio-stream" +version = "0.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "267ac89e0bec6e691e5813911606935d77c476ff49024f98abcea3e7b15e37af" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", + "tokio-util", +] + +[[package]] +name = "tokio-tungstenite" +version = "0.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6989540ced10490aaf14e6bad2e3d33728a2813310a0c71d1574304c49631cd" +dependencies = [ + "futures-util", + "log", + "rustls", + "rustls-pki-types", + "tokio", + "tokio-rustls", + "tungstenite", + "webpki-roots", +] + [[package]] name = "tokio-util" version = "0.7.11" @@ -3708,6 +5592,45 @@ dependencies = [ "tokio", ] +[[package]] +name = "toml_datetime" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" + +[[package]] +name = "toml_edit" +version = "0.22.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "583c44c02ad26b0c3f3066fe629275e50627026c51ac2e595cca4c230ce1ce1d" +dependencies = [ + "indexmap", + "toml_datetime", + "winnow", +] + +[[package]] +name = "tower" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" +dependencies = [ + "futures-core", + "futures-util", + "pin-project", + "pin-project-lite", + "tokio", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-layer" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" + [[package]] name = "tower-service" version = "0.3.3" @@ -3720,6 +5643,7 @@ version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ + "log", "pin-project-lite", "tracing-attributes", "tracing-core", @@ -3781,12 +5705,56 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" +[[package]] +name = "tungstenite" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e2e2ce1e47ed2994fd43b04c8f618008d4cabdd5ee34027cf14f9d918edd9c8" +dependencies = [ + "byteorder", + "bytes", + "data-encoding", + "http 1.1.0", + "httparse", + "log", + "rand", + "rustls", + "rustls-pki-types", + "sha1", + "thiserror", + "utf-8", +] + [[package]] name = "typenum" version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" +[[package]] +name = "ucd-trie" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" + +[[package]] +name = "uint" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76f64bba2c53b04fcab63c01a7d7427eadc821e3bc48c34dc9ba29c501164b52" +dependencies = [ + "byteorder", + "crunchy", + "hex", + "static_assertions", +] + +[[package]] +name = "unarray" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" + [[package]] name = "unicode-bidi" version = "0.3.15" @@ -3857,6 +5825,12 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "utf-8" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" + [[package]] name = "valuable" version = "0.1.0" @@ -3869,6 +5843,12 @@ version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a84c137d37ab0142f0f2ddfe332651fdbf252e7b7dbb4e67b6c1f1b2e925101" +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + [[package]] name = "version_check" version = "0.9.5" @@ -3881,6 +5861,15 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" +[[package]] +name = "wait-timeout" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6" +dependencies = [ + "libc", +] + [[package]] name = "waker-fn" version = "1.2.0" @@ -3988,6 +5977,15 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "webpki-roots" +version = "0.26.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd7c23921eeb1713a4e851530e9b9756e4fb0e89978582942612524cf09f01cd" +dependencies = [ + "rustls-pki-types", +] + [[package]] name = "widestring" version = "1.1.0" @@ -4035,6 +6033,36 @@ dependencies = [ "windows-targets 0.48.5", ] +[[package]] +name = "windows-registry" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0" +dependencies = [ + "windows-result", + "windows-strings", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-result" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-strings" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" +dependencies = [ + "windows-result", + "windows-targets 0.52.6", +] + [[package]] name = "windows-sys" version = "0.48.0" @@ -4183,6 +6211,15 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +[[package]] +name = "winnow" +version = "0.6.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68a9bda4691f099d435ad181000724da8e5899daa10713c2d432552b9ccd3a6f" +dependencies = [ + "memchr", +] + [[package]] name = "winreg" version = "0.50.0" @@ -4193,6 +6230,34 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "ws_stream_wasm" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7999f5f4217fe3818726b66257a4475f71e74ffd190776ad053fa159e50737f5" +dependencies = [ + "async_io_stream", + "futures", + "js-sys", + "log", + "pharos", + "rustc_version 0.4.0", + "send_wrapper", + "thiserror", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] + [[package]] name = "x25519-dalek" version = "2.0.1" diff --git a/packages/ciphernode/eth/Cargo.toml b/packages/ciphernode/eth/Cargo.toml index 8e25c2d8..df17ea90 100644 --- a/packages/ciphernode/eth/Cargo.toml +++ b/packages/ciphernode/eth/Cargo.toml @@ -13,3 +13,8 @@ async-std = "1.12.0" fhe = { git = "https://github.com/gnosisguild/fhe.rs", version = "0.1.0-beta.7" } fhe-traits = { git = "https://github.com/gnosisguild/fhe.rs", version = "0.1.0-beta.7" } fhe-util = { git = "https://github.com/gnosisguild/fhe.rs", version = "0.1.0-beta.7" } +alloy = { version = "0.2.1", features = ["full"] } +alloy-primitives = { version = "0.6", default-features = false, features = ["rlp", "serde", "std"] } +alloy-sol-types = { version = "0.6" } +futures-util = "0.3" +eyre = "0.6" \ No newline at end of file diff --git a/packages/ciphernode/eth/src/lib.rs b/packages/ciphernode/eth/src/lib.rs index d59ebed4..a28cf1be 100644 --- a/packages/ciphernode/eth/src/lib.rs +++ b/packages/ciphernode/eth/src/lib.rs @@ -2,13 +2,8 @@ #![crate_type = "lib"] #![warn(missing_docs, unused_imports)] +mod listener; +mod manager; -pub struct EtherClient { - pub address: String, -} - -impl EtherClient { - pub fn new(address: String) -> Self { - Self { address } - } -} \ No newline at end of file +pub use listener::*; +pub use manager::*; \ No newline at end of file diff --git a/packages/ciphernode/eth/src/listener.rs b/packages/ciphernode/eth/src/listener.rs new file mode 100644 index 00000000..59197133 --- /dev/null +++ b/packages/ciphernode/eth/src/listener.rs @@ -0,0 +1,81 @@ +use alloy::{ + primitives::B256, + providers::{Provider, RootProvider}, + rpc::types::{Filter, Log}, + sol_types::SolEvent, transports::BoxTransport, +}; +use eyre::Result; +use futures_util::stream::StreamExt; +use std::collections::HashMap; +use std::sync::Arc; +use std::fmt::Debug; + +pub trait ContractEvent: Send + Sync + 'static { + fn process(&self) -> Result<()>; +} + +impl ContractEvent for T +where + T: SolEvent + Debug + Send + Sync + 'static, +{ + fn process(&self) -> Result<()> { + println!("Processing event: {:?}", self); + Ok(()) + } +} + +pub struct EventListener { + provider: Arc>, + filter: Filter, + handlers: HashMap Result> + Send + Sync>>, +} + +impl EventListener { + pub fn new(provider: Arc>, filter: Filter) -> Self { + Self { + provider, + filter, + handlers: HashMap::new(), + } + } + + pub fn add_event_handler(&mut self) + where + E: SolEvent + ContractEvent + 'static, + { + let signature = E::SIGNATURE_HASH; + let handler = Arc::new(move |log: Log| -> Result> { + let event = log.log_decode::()?.inner.data; + Ok(Box::new(event)) + }); + + self.handlers.insert(signature, handler); + } + + pub async fn listen(&self) -> Result<()> { + let sub = self.provider.subscribe_logs(&self.filter).await?; + let mut stream = sub.into_stream(); + + while let Some(log) = stream.next().await { + if let Some(topic) = log.topic0() { + if let Some(handler) = self.handlers.get(topic) { + match handler(log.clone()) { + Ok(event) => { + if let Err(err) = event.process() { + eprintln!("Error processing event: {:?}", err); + } + } + Err(err) => { + eprintln!("Error decoding log: {:?}", err); + } + } + } else { + eprintln!("No handler found for topic: {:?}", topic); + } + } + } + + Ok(()) + } +} + diff --git a/packages/ciphernode/eth/src/manager.rs b/packages/ciphernode/eth/src/manager.rs new file mode 100644 index 00000000..3f315fd8 --- /dev/null +++ b/packages/ciphernode/eth/src/manager.rs @@ -0,0 +1,30 @@ +use alloy::{ + primitives::Address, + providers::{ProviderBuilder, RootProvider}, + rpc::types::{BlockNumberOrTag, Filter}, + transports::BoxTransport, +}; +use eyre::Result; +use std::sync::Arc; +use crate::EventListener; + +pub struct ContractManager { + provider: Arc>, +} + +impl ContractManager { + pub async fn new(rpc_url: &str) -> Result { + let provider = ProviderBuilder::new().on_builtin(rpc_url).await?; + Ok(Self { + provider: Arc::new(provider), + }) + } + + pub fn add_listener(&self, contract_address: Address) -> EventListener { + let filter = Filter::new() + .address(contract_address) + .from_block(BlockNumberOrTag::Latest); + + EventListener::new(self.provider.clone(), filter) + } +} \ No newline at end of file From df50d1813a85f33befef65b35108d87aa6cbe803 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=B3=CE=BB?= Date: Thu, 29 Aug 2024 12:07:17 +1000 Subject: [PATCH 27/87] Prepare for decryption (#24) * Prepare for decryption * Add todo --- packages/ciphernode/core/src/ciphernode.rs | 17 ++++++- packages/ciphernode/core/src/committee.rs | 3 +- packages/ciphernode/core/src/eventbus.rs | 12 +++++ packages/ciphernode/core/src/events.rs | 29 ++++++++++- packages/ciphernode/core/src/fhe.rs | 59 ++++++++++++++++++++-- packages/ciphernode/core/src/lib.rs | 57 +++++++++++++++------ 6 files changed, 156 insertions(+), 21 deletions(-) diff --git a/packages/ciphernode/core/src/ciphernode.rs b/packages/ciphernode/core/src/ciphernode.rs index 7f3bebe2..e289c42a 100644 --- a/packages/ciphernode/core/src/ciphernode.rs +++ b/packages/ciphernode/core/src/ciphernode.rs @@ -3,7 +3,7 @@ use crate::{ eventbus::EventBus, events::{ComputationRequested, EnclaveEvent, KeyshareCreated}, fhe::{Fhe, GenerateKeyshare}, - Subscribe, + DecryptionRequested, Subscribe, }; use actix::prelude::*; use anyhow::Result; @@ -85,3 +85,18 @@ async fn on_computation_requested( Ok(()) } + +async fn on_decryption_requested( + fhe: Addr, + data: Addr, + bus: Addr, + event: DecryptionRequested, +) -> Result<()> { + let DecryptionRequested { e3_id, ciphertext } = event; + + // get secret key by id from data + + // TODO: Complete this + + Ok(()) +} diff --git a/packages/ciphernode/core/src/committee.rs b/packages/ciphernode/core/src/committee.rs index 836dc534..220bca21 100644 --- a/packages/ciphernode/core/src/committee.rs +++ b/packages/ciphernode/core/src/committee.rs @@ -69,7 +69,8 @@ impl Handler for CommitteeManager { key.do_send(Die); self.keys.remove(&data.e3_id); - } // _ => (), + }, + _ => (), } } } diff --git a/packages/ciphernode/core/src/eventbus.rs b/packages/ciphernode/core/src/eventbus.rs index 50cd14f8..fe908caf 100644 --- a/packages/ciphernode/core/src/eventbus.rs +++ b/packages/ciphernode/core/src/eventbus.rs @@ -22,6 +22,10 @@ impl Subscribe { #[rtype(result = "Vec")] pub struct GetHistory; +#[derive(Message)] +#[rtype(result = "()")] +pub struct ResetHistory; + /// Central EventBus for each node. Actors publish events to this bus by sending it EnclaveEvents. /// All events sent to this bus are assumed to be published over the network via pubsub. @@ -73,6 +77,14 @@ impl Handler for EventBus { self.history.clone() } } +impl Handler for EventBus { + type Result = (); + + fn handle(&mut self, _: ResetHistory, _: &mut Context) { + self.history.clear() + } +} + impl Handler for EventBus { type Result = (); diff --git a/packages/ciphernode/core/src/events.rs b/packages/ciphernode/core/src/events.rs index ce062dae..f0298264 100644 --- a/packages/ciphernode/core/src/events.rs +++ b/packages/ciphernode/core/src/events.rs @@ -1,4 +1,7 @@ -use crate::fhe::{WrappedPublicKey, WrappedPublicKeyShare}; +use crate::{ + fhe::{WrappedPublicKey, WrappedPublicKeyShare}, + WrappedCiphertext, +}; use actix::Message; use bincode; use serde::{Deserialize, Serialize}; @@ -64,6 +67,10 @@ pub enum EnclaveEvent { id: EventId, data: PublicKeyAggregated, }, + DecryptionRequested { + id: EventId, + data: DecryptionRequested + } // CommitteeSelected, // OutputDecrypted, // CiphernodeRegistered, @@ -90,6 +97,7 @@ impl From for EventId { EnclaveEvent::KeyshareCreated { id, .. } => id, EnclaveEvent::ComputationRequested { id, .. } => id, EnclaveEvent::PublicKeyAggregated { id, .. } => id, + EnclaveEvent::DecryptionRequested { id, .. } => id, } } } @@ -121,6 +129,18 @@ impl From for EnclaveEvent { } } + +impl From for EnclaveEvent { + fn from(data: DecryptionRequested) -> Self { + EnclaveEvent::DecryptionRequested { + id: EventId::from(data.clone()), + data: data.clone(), + } + } +} + + + impl fmt::Display for EnclaveEvent { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str(&format!("{}({})", self.event_type(), self.get_id())) @@ -154,6 +174,13 @@ pub struct ComputationRequested { // availability_duration: ??, // TODO: } +#[derive(Message, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[rtype(result = "()")] +pub struct DecryptionRequested { + pub e3_id: E3id, + pub ciphertext: WrappedCiphertext, +} + fn extract_enclave_event_name(s: &str) -> &str { let bytes = s.as_bytes(); for (i, &item) in bytes.iter().enumerate() { diff --git a/packages/ciphernode/core/src/fhe.rs b/packages/ciphernode/core/src/fhe.rs index 7a5b59f7..79904279 100644 --- a/packages/ciphernode/core/src/fhe.rs +++ b/packages/ciphernode/core/src/fhe.rs @@ -4,7 +4,7 @@ use crate::ordered_set::OrderedSet; use actix::{Actor, Context, Handler, Message}; use anyhow::*; use fhe::{ - bfv::{BfvParameters, BfvParametersBuilder, PublicKey, SecretKey}, + bfv::{BfvParameters, BfvParametersBuilder, Ciphertext, PublicKey, SecretKey}, mbfv::{AggregateIter, CommonRandomPoly, PublicKeyShare}, }; use fhe_traits::{Deserialize, DeserializeParametrized, Serialize}; @@ -123,7 +123,6 @@ impl serde::Serialize for WrappedPublicKeyShare { } } - /// Wrapped PublicKey. This is wrapped to provide an inflection point /// as we use this library elsewhere we only implement traits as we need them /// and avoid exposing underlying structures from fhe.rs @@ -214,6 +213,60 @@ impl WrappedSecretKey { } } +/// Wrapped Ciphertext. This is wrapped to provide an inflection point +/// as we use this library elsewhere we only implement traits as we need them +/// and avoid exposing underlying structures from fhe.rs +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct WrappedCiphertext { + inner: Ciphertext, + params: Arc, +} + +impl WrappedCiphertext { + pub fn from_fhe_rs(inner: Ciphertext, params: Arc) -> Self { + Self { inner, params } + } +} + +impl Hash for WrappedCiphertext { + fn hash(&self, state: &mut H) { + self.inner.to_bytes().hash(state) + } +} + +/// Deserialize from serde to WrappedPublicKey +impl<'de> serde::Deserialize<'de> for WrappedCiphertext { + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + // Intermediate struct of bytes for deserialization + #[derive(serde::Deserialize)] + struct DeserializedBytes { + par: Vec, + bytes: Vec, + } + let DeserializedBytes { par, bytes } = DeserializedBytes::deserialize(deserializer)?; + let params = Arc::new(BfvParameters::try_deserialize(&par).unwrap()); + let inner = Ciphertext::from_bytes(&bytes, ¶ms).map_err(serde::de::Error::custom)?; + std::result::Result::Ok(WrappedCiphertext::from_fhe_rs(inner, params)) + } +} +impl serde::Serialize for WrappedCiphertext { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + use serde::ser::SerializeStruct; + let bytes = self.inner.to_bytes(); + let par_bytes = self.params.to_bytes(); + // Intermediate struct of bytes + let mut state = serializer.serialize_struct("Ciphertext", 2)?; + state.serialize_field("par_bytes", &par_bytes)?; + state.serialize_field("bytes", &bytes)?; + state.end() + } +} /// Fhe library adaptor. All FHE computations should happen through this actor. pub struct Fhe { params: Arc, @@ -274,7 +327,7 @@ impl Handler for Fhe { } } -fn serialize_box_i64(boxed: Box<[i64]>) -> Vec { +pub fn serialize_box_i64(boxed: Box<[i64]>) -> Vec { let vec = boxed.into_vec(); let mut bytes = Vec::with_capacity(vec.len() * mem::size_of::()); for &num in &vec { diff --git a/packages/ciphernode/core/src/lib.rs b/packages/ciphernode/core/src/lib.rs index 772f0789..6e0c4562 100644 --- a/packages/ciphernode/core/src/lib.rs +++ b/packages/ciphernode/core/src/lib.rs @@ -10,31 +10,31 @@ mod enclave_contract; mod eventbus; mod events; mod fhe; +mod logger; mod ordered_set; mod p2p; -mod logger; // TODO: this is too permissive -pub use data::*; +pub use actix::prelude::*; pub use ciphernode::*; pub use committee::*; pub use committee_key::*; +pub use data::*; pub use eventbus::*; pub use events::*; pub use fhe::*; -pub use p2p::*; -pub use actix::prelude::*; pub use logger::*; +pub use p2p::*; -pub use data::*; +pub use actix::prelude::*; pub use ciphernode::*; pub use committee::*; pub use committee_key::*; +pub use data::*; pub use eventbus::*; pub use events::*; pub use fhe::*; pub use p2p::*; -pub use actix::prelude::*; // pub struct Core { // pub name: String, @@ -53,6 +53,7 @@ pub use actix::prelude::*; // } // } +// TODO: move these out to a test folder #[cfg(test)] mod tests { use std::{sync::Arc, time::Duration}; @@ -65,13 +66,15 @@ mod tests { events::{ComputationRequested, E3id, EnclaveEvent, KeyshareCreated, PublicKeyAggregated}, fhe::{Fhe, WrappedPublicKey, WrappedPublicKeyShare}, p2p::P2p, + DecryptionRequested, ResetHistory, WrappedCiphertext, }; use actix::prelude::*; use anyhow::*; use fhe::{ - bfv::{BfvParameters, BfvParametersBuilder, PublicKey, SecretKey}, + bfv::{BfvParameters, BfvParametersBuilder, Encoding, Plaintext, PublicKey, SecretKey}, mbfv::{AggregateIter, CommonRandomPoly, PublicKeyShare}, }; + use fhe_traits::{FheEncoder, FheEncrypter}; use rand::SeedableRng; use rand_chacha::ChaCha20Rng; use tokio::sync::Mutex; @@ -144,24 +147,29 @@ mod tests { plaintext_modulus: u64, rng1: ChaCha20Rng, rng2: ChaCha20Rng, - ) -> Result> { + ) -> Result<(Addr, Arc, CommonRandomPoly)> { let (params, crp) = setup_bfv_params(&moduli, degree, plaintext_modulus, rng1)?; - Ok(Fhe::new(params, crp, rng2)?.start()) + Ok(( + Fhe::new(params.clone(), crp.clone(), rng2)?.start(), + params, + crp, + )) } #[actix::test] - async fn test_public_key_aggregation() -> Result<()> { + async fn test_public_key_aggregation_and_decryption() -> Result<()> { // Setup EventBus let bus = EventBus::new(true).start(); // Setup global FHE actor - let fhe = setup_global_fhe_actor( + let (fhe, ..) = setup_global_fhe_actor( &vec![0x3FFFFFFF000001], 2048, 1032193, ChaCha20Rng::seed_from_u64(42), ChaCha20Rng::seed_from_u64(42), )?; + setup_local_ciphernode(bus.clone(), fhe.clone(), true); setup_local_ciphernode(bus.clone(), fhe.clone(), true); setup_local_ciphernode(bus.clone(), fhe.clone(), true); @@ -196,7 +204,7 @@ mod tests { let (p2, rng) = generate_pk_share(params.clone(), crp.clone(), rng)?; let (p3, _) = generate_pk_share(params.clone(), crp.clone(), rng)?; - let aggregated: PublicKey = vec![p1.clone(), p2.clone(), p3.clone()] + let pubkey: PublicKey = vec![p1.clone(), p2.clone(), p3.clone()] .iter() .map(|k| k.clone_inner()) .aggregate()?; @@ -224,12 +232,27 @@ mod tests { e3_id: e3_id.clone() }), EnclaveEvent::from(PublicKeyAggregated { - pubkey: WrappedPublicKey::from_fhe_rs(aggregated, params), + pubkey: WrappedPublicKey::from_fhe_rs(pubkey.clone(), params.clone()), e3_id: e3_id.clone() }) ] ); + // Aggregate decryption + bus.send(ResetHistory).await?; + + let yes = 12376213u64; + let no = 873827u64; + + let pt = Plaintext::try_encode(&vec![yes, no], Encoding::poly(), ¶ms)?; + + let ciphertext = pubkey.try_encrypt(&pt, &mut ChaCha20Rng::seed_from_u64(42))?; + + bus.do_send(EnclaveEvent::from(DecryptionRequested { + ciphertext: WrappedCiphertext::from_fhe_rs(ciphertext, params), + e3_id: e3_id.clone(), + })); + Ok(()) } @@ -268,7 +291,7 @@ mod tests { bus.do_send(evt_1.clone()); bus.do_send(evt_2.clone()); - + sleep(Duration::from_millis(1)).await; // need to push to next tick // check the history of the event bus @@ -280,7 +303,11 @@ mod tests { "P2p did not transmit events to the network" ); - assert_eq!(history, vec![evt_1, evt_2], "P2p must not retransmit forwarded event to event bus"); + assert_eq!( + history, + vec![evt_1, evt_2], + "P2p must not retransmit forwarded event to event bus" + ); Ok(()) } From d9690e68134b40aca8ec16d1b043ee1c23fe392e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=B3=CE=BB?= Date: Thu, 29 Aug 2024 18:50:51 +1000 Subject: [PATCH 28/87] DecryptionShareCreated events are firing (#26) --- packages/ciphernode/core/src/ciphernode.rs | 48 ++++++- packages/ciphernode/core/src/committee.rs | 5 +- packages/ciphernode/core/src/data.rs | 2 +- packages/ciphernode/core/src/eventbus.rs | 8 +- packages/ciphernode/core/src/events.rs | 24 +++- packages/ciphernode/core/src/fhe.rs | 142 ++++++++++++++++++--- packages/ciphernode/core/src/lib.rs | 91 ++++++++----- 7 files changed, 260 insertions(+), 60 deletions(-) diff --git a/packages/ciphernode/core/src/ciphernode.rs b/packages/ciphernode/core/src/ciphernode.rs index e289c42a..b424942f 100644 --- a/packages/ciphernode/core/src/ciphernode.rs +++ b/packages/ciphernode/core/src/ciphernode.rs @@ -3,7 +3,8 @@ use crate::{ eventbus::EventBus, events::{ComputationRequested, EnclaveEvent, KeyshareCreated}, fhe::{Fhe, GenerateKeyshare}, - DecryptionRequested, Subscribe, + DecryptCiphertext, DecryptionRequested, DecryptionshareCreated, Get, Subscribe, + WrappedSecretKey, }; use actix::prelude::*; use anyhow::Result; @@ -23,9 +24,10 @@ impl Ciphernode { Self { bus, fhe, data } } - pub fn attach(bus: Addr, fhe: Addr, data: Addr) -> Addr { + pub async fn attach(bus: Addr, fhe: Addr, data: Addr) -> Addr { let node = Ciphernode::new(bus.clone(), fhe, data).start(); - bus.do_send(Subscribe::new("ComputationRequested", node.clone().into())); + let _ = bus.send(Subscribe::new("ComputationRequested", node.clone().into())).await; + let _ = bus.send(Subscribe::new("DecryptionRequested", node.clone().into())).await; node } } @@ -36,6 +38,7 @@ impl Handler for Ciphernode { fn handle(&mut self, event: EnclaveEvent, ctx: &mut Context) -> Self::Result { match event { EnclaveEvent::ComputationRequested { data, .. } => ctx.address().do_send(data), + EnclaveEvent::DecryptionRequested { data, .. } => ctx.address().do_send(data), _ => (), } } @@ -56,6 +59,21 @@ impl Handler for Ciphernode { } } +impl Handler for Ciphernode { + type Result = ResponseFuture<()>; + + fn handle(&mut self, event: DecryptionRequested, _: &mut Context) -> Self::Result { + let fhe = self.fhe.clone(); + let data = self.data.clone(); + let bus = self.bus.clone(); + Box::pin(async { + on_decryption_requested(fhe, data, bus, event) + .await + .unwrap() + }) + } +} + async fn on_computation_requested( fhe: Addr, data: Addr, @@ -71,7 +89,10 @@ async fn on_computation_requested( // reencrypt secretkey locally with env var - this is so we don't have to serialize a secret // best practice would be as you boot up a node you enter in a configured password from // which we derive a kdf which gets used to generate this key - data.do_send(Insert(format!("{}/sk", e3_id).into(), sk.unsafe_to_vec())); + data.do_send(Insert( + format!("{}/sk", e3_id).into(), + sk.unsafe_serialize()?, + )); // save public key against e3_id/pk data.do_send(Insert( @@ -95,8 +116,25 @@ async fn on_decryption_requested( let DecryptionRequested { e3_id, ciphertext } = event; // get secret key by id from data + let Some(sk_bytes) = data.send(Get(format!("{}/sk", e3_id).into())).await? else { + return Err(anyhow::anyhow!("Secret key not stored for {}", e3_id)); + }; + + let unsafe_secret = WrappedSecretKey::deserialize(sk_bytes)?; - // TODO: Complete this + let decryption_share = fhe + .send(DecryptCiphertext { + ciphertext, + unsafe_secret, + }) + .await??; + + let event = EnclaveEvent::from(DecryptionshareCreated { + e3_id, + decryption_share, + }); + + bus.do_send(event); Ok(()) } diff --git a/packages/ciphernode/core/src/committee.rs b/packages/ciphernode/core/src/committee.rs index 220bca21..b2c51580 100644 --- a/packages/ciphernode/core/src/committee.rs +++ b/packages/ciphernode/core/src/committee.rs @@ -69,7 +69,10 @@ impl Handler for CommitteeManager { key.do_send(Die); self.keys.remove(&data.e3_id); - }, + } + EnclaveEvent::DecryptionRequested { .. } => { + // TODO: launch new plaintext aggregator + } _ => (), } } diff --git a/packages/ciphernode/core/src/data.rs b/packages/ciphernode/core/src/data.rs index 40ba1a3e..dd23c2eb 100644 --- a/packages/ciphernode/core/src/data.rs +++ b/packages/ciphernode/core/src/data.rs @@ -20,7 +20,7 @@ impl Insert { #[derive(Message, Clone, Debug, PartialEq, Eq, Hash)] #[rtype(result = "Option>")] -pub struct Get(Vec); +pub struct Get(pub Vec); impl Get { fn key(&self) -> Vec { self.0.clone() diff --git a/packages/ciphernode/core/src/eventbus.rs b/packages/ciphernode/core/src/eventbus.rs index fe908caf..c57ff2b5 100644 --- a/packages/ciphernode/core/src/eventbus.rs +++ b/packages/ciphernode/core/src/eventbus.rs @@ -26,11 +26,10 @@ pub struct GetHistory; #[rtype(result = "()")] pub struct ResetHistory; - /// Central EventBus for each node. Actors publish events to this bus by sending it EnclaveEvents. /// All events sent to this bus are assumed to be published over the network via pubsub. -/// Other actors such as the P2p and Evm actor connect to outside services and control which events -/// actually get published as well as ensure that local events are not rebroadcast locally after +/// Other actors such as the P2p and Evm actor connect to outside services and control which events +/// actually get published as well as ensure that local events are not rebroadcast locally after /// being published. pub struct EventBus { capture: bool, @@ -85,7 +84,6 @@ impl Handler for EventBus { } } - impl Handler for EventBus { type Result = (); @@ -95,7 +93,7 @@ impl Handler for EventBus { // We have seen this before return; } - + // TODO: How can we ensure the event we see is coming in in the correct order? if let Some(listeners) = self.listeners.get("*") { for listener in listeners { diff --git a/packages/ciphernode/core/src/events.rs b/packages/ciphernode/core/src/events.rs index f0298264..a5dcf6e4 100644 --- a/packages/ciphernode/core/src/events.rs +++ b/packages/ciphernode/core/src/events.rs @@ -1,6 +1,6 @@ use crate::{ fhe::{WrappedPublicKey, WrappedPublicKeyShare}, - WrappedCiphertext, + WrappedCiphertext, WrappedDecryptionShare, }; use actix::Message; use bincode; @@ -70,6 +70,10 @@ pub enum EnclaveEvent { DecryptionRequested { id: EventId, data: DecryptionRequested + }, + DecryptionshareCreated { + id: EventId, + data: DecryptionshareCreated } // CommitteeSelected, // OutputDecrypted, @@ -98,6 +102,7 @@ impl From for EventId { EnclaveEvent::ComputationRequested { id, .. } => id, EnclaveEvent::PublicKeyAggregated { id, .. } => id, EnclaveEvent::DecryptionRequested { id, .. } => id, + EnclaveEvent::DecryptionshareCreated { id, .. } => id } } } @@ -139,7 +144,14 @@ impl From for EnclaveEvent { } } - +impl From for EnclaveEvent { + fn from(data: DecryptionshareCreated) -> Self { + EnclaveEvent::DecryptionshareCreated { + id: EventId::from(data.clone()), + data: data.clone(), + } + } +} impl fmt::Display for EnclaveEvent { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -154,6 +166,14 @@ pub struct KeyshareCreated { pub e3_id: E3id, } + +#[derive(Message, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[rtype(result = "anyhow::Result<()>")] +pub struct DecryptionshareCreated { + pub decryption_share: WrappedDecryptionShare, + pub e3_id: E3id +} + #[derive(Message, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[rtype(result = "()")] pub struct PublicKeyAggregated { diff --git a/packages/ciphernode/core/src/fhe.rs b/packages/ciphernode/core/src/fhe.rs index 79904279..ec3f56d8 100644 --- a/packages/ciphernode/core/src/fhe.rs +++ b/packages/ciphernode/core/src/fhe.rs @@ -4,14 +4,16 @@ use crate::ordered_set::OrderedSet; use actix::{Actor, Context, Handler, Message}; use anyhow::*; use fhe::{ - bfv::{BfvParameters, BfvParametersBuilder, Ciphertext, PublicKey, SecretKey}, - mbfv::{AggregateIter, CommonRandomPoly, PublicKeyShare}, + bfv::{BfvParameters, BfvParametersBuilder, Ciphertext, Plaintext, PublicKey, SecretKey}, + mbfv::{AggregateIter, CommonRandomPoly, DecryptionShare, PublicKeyShare}, }; use fhe_traits::{Deserialize, DeserializeParametrized, Serialize}; use rand::SeedableRng; use rand_chacha::ChaCha20Rng; use serde::Serializer; +// TODO: remove all this wrapping and serialization/deserialization code by ensuring everything from fhe.rs has a to_bytes() and deserialize() -> T methods and return only Vec outside of this actor + #[derive(Message, Clone, Debug, PartialEq, Eq, Hash)] #[rtype(result = "Result<(WrappedSecretKey, WrappedPublicKeyShare)>")] pub struct GenerateKeyshare { @@ -24,6 +26,19 @@ pub struct GetAggregatePublicKey { pub keyshares: OrderedSet, } +#[derive(Message, Clone, Debug, PartialEq, Eq)] +#[rtype(result = "Result<(WrappedPlaintext)>")] +pub struct GetAggregatePlaintext { + pub decryptions: OrderedSet, +} + +#[derive(Message, Clone, Debug, PartialEq, Eq)] +#[rtype(result = "Result<(WrappedDecryptionShare)>")] +pub struct DecryptCiphertext { + pub unsafe_secret: WrappedSecretKey, + pub ciphertext: WrappedCiphertext, +} + /// Wrapped PublicKeyShare. This is wrapped to provide an inflection point /// as we use this library elsewhere we only implement traits as we need them /// and avoid exposing underlying structures from fhe.rs @@ -115,7 +130,7 @@ impl serde::Serialize for WrappedPublicKeyShare { let par_bytes = self.params.to_bytes(); let crp_bytes = self.crp.to_bytes(); // Intermediate struct of bytes - let mut state = serializer.serialize_struct("PublicKeyShare", 2)?; + let mut state = serializer.serialize_struct("PublicKeyShare", 3)?; state.serialize_field("par_bytes", &par_bytes)?; state.serialize_field("crp_bytes", &crp_bytes)?; state.serialize_field("bytes", &bytes)?; @@ -157,7 +172,7 @@ impl<'de> serde::Deserialize<'de> for WrappedPublicKey { bytes: Vec, } let PublicKeyBytes { par, bytes } = PublicKeyBytes::deserialize(deserializer)?; - let params = Arc::new(BfvParameters::try_deserialize(&par).unwrap()); + let params = Arc::new(BfvParameters::try_deserialize(&par).unwrap()); // TODO: fix errors let inner = PublicKey::from_bytes(&bytes, ¶ms).map_err(serde::de::Error::custom)?; // TODO: how do we create an invariant that the deserialized params match the global params? std::result::Result::Ok(WrappedPublicKey::from_fhe_rs(inner, params)) @@ -204,12 +219,39 @@ impl PartialOrd for WrappedPublicKey { /// and avoid exposing underlying structures from fhe.rs // We should favor consuming patterns and avoid cloning and copying this value around in memory. // Underlying key Zeroizes on drop -#[derive(PartialEq)] -pub struct WrappedSecretKey(pub SecretKey); +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct WrappedSecretKey { + inner: SecretKey, + params: Arc, +} impl WrappedSecretKey { - pub fn unsafe_to_vec(&self) -> Vec { - serialize_box_i64(self.0.coeffs.clone()) + pub fn from_fhe_rs(inner: SecretKey, params: Arc) -> Self { + Self { inner, params } + } +} + +#[derive(serde::Serialize, serde::Deserialize)] +struct SecretKeyData { + coeffs: Box<[i64]>, + par: Vec, +} + +impl WrappedSecretKey { + pub fn unsafe_serialize(&self) -> Result> { + Ok(bincode::serialize(&SecretKeyData { + coeffs: self.inner.coeffs.clone(), + par: self.params.clone().to_bytes(), + })?) + } + + pub fn deserialize(bytes: Vec) -> Result { + let SecretKeyData { coeffs, par } = bincode::deserialize(&bytes)?; + let params = Arc::new(BfvParameters::try_deserialize(&par).unwrap()); + Ok(WrappedSecretKey::from_fhe_rs( + SecretKey::new(coeffs.to_vec(), ¶ms), + params, + )) } } @@ -267,6 +309,51 @@ impl serde::Serialize for WrappedCiphertext { state.end() } } + +#[derive( + Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, serde::Serialize, serde::Deserialize, +)] +pub struct WrappedDecryptionShare { + inner: Vec, + params: Vec, + ct: Vec, +} + +impl WrappedDecryptionShare { + pub fn from_fhe_rs( + inner: DecryptionShare, + params: Arc, + ct: Arc, + ) -> Self { + // Have to serialize immediately in order to clone etc. + let inner_bytes = inner.to_bytes(); + let params_bytes = params.to_bytes(); + let ct_bytes = ct.to_bytes(); + Self { + inner: inner_bytes, + params: params_bytes, + ct: ct_bytes, + } + } + + pub fn try_inner(self) -> Result { + let params = Arc::new(BfvParameters::try_deserialize(&self.params)?); + let ct = Arc::new(Ciphertext::from_bytes(&self.ct, ¶ms)?); + Ok(DecryptionShare::deserialize(&self.inner, ¶ms, ct)?) + } +} + +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct WrappedPlaintext { + inner: Plaintext, +} + +impl WrappedPlaintext { + pub fn from_fhe_rs(inner: Plaintext /* params: Arc */) -> Self { + Self { inner } + } +} + /// Fhe library adaptor. All FHE computations should happen through this actor. pub struct Fhe { params: Arc, @@ -308,12 +395,31 @@ impl Handler for Fhe { let sk_share = { SecretKey::random(&self.params, &mut self.rng) }; let pk_share = { PublicKeyShare::new(&sk_share, self.crp.clone(), &mut self.rng)? }; Ok(( - WrappedSecretKey(sk_share), + WrappedSecretKey::from_fhe_rs(sk_share, self.params.clone()), WrappedPublicKeyShare::from_fhe_rs(pk_share, self.params.clone(), self.crp.clone()), )) } } +impl Handler for Fhe { + type Result = Result; + fn handle(&mut self, msg: DecryptCiphertext, _: &mut Self::Context) -> Self::Result { + let DecryptCiphertext { + unsafe_secret, // TODO: fix security issues with sending secrets between actors + ciphertext, + } = msg; + + let ct = Arc::new(ciphertext.inner); + let inner = DecryptionShare::new(&unsafe_secret.inner, &ct, &mut self.rng).unwrap(); + + Ok(WrappedDecryptionShare::from_fhe_rs( + inner, + ciphertext.params, + ct.clone(), + )) + } +} + impl Handler for Fhe { type Result = Result; @@ -327,11 +433,17 @@ impl Handler for Fhe { } } -pub fn serialize_box_i64(boxed: Box<[i64]>) -> Vec { - let vec = boxed.into_vec(); - let mut bytes = Vec::with_capacity(vec.len() * mem::size_of::()); - for &num in &vec { - bytes.extend_from_slice(&num.to_le_bytes()); +impl Handler for Fhe { + type Result = Result; + fn handle(&mut self, msg: GetAggregatePlaintext, _: &mut Self::Context) -> Self::Result { + let plaintext: Plaintext = msg + .decryptions + .iter() + .map(|k| k.clone().try_inner()) + .collect::>>()? // NOTE: not optimal + .into_iter() + .aggregate()?; + + Ok(WrappedPlaintext::from_fhe_rs(plaintext)) } - bytes } diff --git a/packages/ciphernode/core/src/lib.rs b/packages/ciphernode/core/src/lib.rs index 6e0c4562..f754d65d 100644 --- a/packages/ciphernode/core/src/lib.rs +++ b/packages/ciphernode/core/src/lib.rs @@ -66,13 +66,14 @@ mod tests { events::{ComputationRequested, E3id, EnclaveEvent, KeyshareCreated, PublicKeyAggregated}, fhe::{Fhe, WrappedPublicKey, WrappedPublicKeyShare}, p2p::P2p, - DecryptionRequested, ResetHistory, WrappedCiphertext, + DecryptionRequested, DecryptionshareCreated, ResetHistory, WrappedCiphertext, + WrappedDecryptionShare, }; use actix::prelude::*; use anyhow::*; use fhe::{ bfv::{BfvParameters, BfvParametersBuilder, Encoding, Plaintext, PublicKey, SecretKey}, - mbfv::{AggregateIter, CommonRandomPoly, PublicKeyShare}, + mbfv::{AggregateIter, CommonRandomPoly, DecryptionShare, PublicKeyShare}, }; use fhe_traits::{FheEncoder, FheEncrypter}; use rand::SeedableRng; @@ -81,7 +82,7 @@ mod tests { use tokio::{sync::mpsc::channel, time::sleep}; // Simulating a local node - fn setup_local_ciphernode( + async fn setup_local_ciphernode( bus: Addr, fhe: Addr, logging: bool, @@ -90,13 +91,10 @@ mod tests { let data = Data::new(logging).start(); // TODO: Use a sled backed Data Actor // create ciphernode actor for managing ciphernode flow - let node = Ciphernode::new(bus.clone(), fhe.clone(), data.clone()).start(); - - // subscribe for computation requested events from the event bus - bus.do_send(Subscribe::new("ComputationRequested", node.clone().into())); + let node = Ciphernode::attach(bus.clone(), fhe.clone(), data.clone()).await; // setup the committee manager to generate the comittee public keys - setup_committee_manager(bus.clone(), fhe); + CommitteeManager::attach(bus.clone(), fhe.clone()); (node, data) } @@ -119,26 +117,14 @@ mod tests { params: Arc, crp: CommonRandomPoly, mut rng: ChaCha20Rng, - ) -> Result<(WrappedPublicKeyShare, ChaCha20Rng)> { + ) -> Result<(WrappedPublicKeyShare, ChaCha20Rng, SecretKey)> { let sk = SecretKey::random(¶ms, &mut rng); let pk = WrappedPublicKeyShare::from_fhe_rs( PublicKeyShare::new(&sk, crp.clone(), &mut rng)?, params.clone(), crp, ); - Ok((pk, rng)) - } - - fn setup_committee_manager(bus: Addr, fhe: Addr) -> Addr { - let committee = CommitteeManager::new(bus.clone(), fhe.clone()).start(); - - bus.do_send(Subscribe::new( - "ComputationRequested", - committee.clone().into(), - )); - bus.do_send(Subscribe::new("KeyshareCreated", committee.clone().into())); - - committee + Ok((pk, rng, sk)) } fn setup_global_fhe_actor( @@ -170,9 +156,9 @@ mod tests { ChaCha20Rng::seed_from_u64(42), )?; - setup_local_ciphernode(bus.clone(), fhe.clone(), true); - setup_local_ciphernode(bus.clone(), fhe.clone(), true); - setup_local_ciphernode(bus.clone(), fhe.clone(), true); + setup_local_ciphernode(bus.clone(), fhe.clone(), true).await; + setup_local_ciphernode(bus.clone(), fhe.clone(), true).await; + setup_local_ciphernode(bus.clone(), fhe.clone(), true).await; let e3_id = E3id::new("1234"); @@ -200,9 +186,9 @@ mod tests { // Passing rng through function chain to ensure it matches usage in system above let rng = ChaCha20Rng::seed_from_u64(42); - let (p1, rng) = generate_pk_share(params.clone(), crp.clone(), rng)?; - let (p2, rng) = generate_pk_share(params.clone(), crp.clone(), rng)?; - let (p3, _) = generate_pk_share(params.clone(), crp.clone(), rng)?; + let (p1, rng, sk1) = generate_pk_share(params.clone(), crp.clone(), rng)?; + let (p2, rng, sk2) = generate_pk_share(params.clone(), crp.clone(), rng)?; + let (p3, mut rng, sk3) = generate_pk_share(params.clone(), crp.clone(), rng)?; let pubkey: PublicKey = vec![p1.clone(), p2.clone(), p3.clone()] .iter() @@ -248,10 +234,53 @@ mod tests { let ciphertext = pubkey.try_encrypt(&pt, &mut ChaCha20Rng::seed_from_u64(42))?; - bus.do_send(EnclaveEvent::from(DecryptionRequested { - ciphertext: WrappedCiphertext::from_fhe_rs(ciphertext, params), + let event = EnclaveEvent::from(DecryptionRequested { + ciphertext: WrappedCiphertext::from_fhe_rs(ciphertext.clone(), params.clone()), e3_id: e3_id.clone(), - })); + }); + + let arc_ct = Arc::new(ciphertext); + + let ds1 = WrappedDecryptionShare::from_fhe_rs( + DecryptionShare::new(&sk1, &arc_ct, &mut rng).unwrap(), + params.clone(), + arc_ct.clone(), + ); + let ds2 = WrappedDecryptionShare::from_fhe_rs( + DecryptionShare::new(&sk2, &arc_ct, &mut rng).unwrap(), + params.clone(), + arc_ct.clone(), + ); + let ds3 = WrappedDecryptionShare::from_fhe_rs( + DecryptionShare::new(&sk3, &arc_ct, &mut rng).unwrap(), + params.clone(), + arc_ct.clone(), + ); + + // let ds1 = sk1 + bus.send(event.clone()).await?; + + let history = bus.send(GetHistory).await?; + + assert_eq!( + history, + vec![ + event.clone(), + EnclaveEvent::from(DecryptionshareCreated { + decryption_share: ds1.clone(), + e3_id: e3_id.clone(), + }), + EnclaveEvent::from(DecryptionshareCreated { + decryption_share: ds2.clone(), + e3_id: e3_id.clone(), + }), + EnclaveEvent::from(DecryptionshareCreated { + decryption_share: ds3.clone(), + e3_id: e3_id.clone(), + }), + // TODO: aggregate plaintext + ] + ); Ok(()) } From 635b1e05b006da86e0e2e8ee27165668547843f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=B3=CE=BB?= Date: Thu, 29 Aug 2024 20:56:42 +1000 Subject: [PATCH 29/87] move all wrapped types out to module for deletion (#27) --- packages/ciphernode/core/src/ciphernode.rs | 7 +- packages/ciphernode/core/src/committee_key.rs | 2 +- packages/ciphernode/core/src/events.rs | 28 +- packages/ciphernode/core/src/fhe.rs | 335 +----------------- packages/ciphernode/core/src/lib.rs | 10 +- .../ciphernode/core/src/wrapped/ciphertext.rs | 59 +++ .../core/src/wrapped/decryption_share.rs | 40 +++ packages/ciphernode/core/src/wrapped/mod.rs | 13 + .../ciphernode/core/src/wrapped/plaintext.rs | 12 + .../ciphernode/core/src/wrapped/public_key.rs | 80 +++++ .../core/src/wrapped/public_key_share.rs | 106 ++++++ .../ciphernode/core/src/wrapped/secret_key.rs | 45 +++ 12 files changed, 385 insertions(+), 352 deletions(-) create mode 100644 packages/ciphernode/core/src/wrapped/ciphertext.rs create mode 100644 packages/ciphernode/core/src/wrapped/decryption_share.rs create mode 100644 packages/ciphernode/core/src/wrapped/mod.rs create mode 100644 packages/ciphernode/core/src/wrapped/plaintext.rs create mode 100644 packages/ciphernode/core/src/wrapped/public_key.rs create mode 100644 packages/ciphernode/core/src/wrapped/public_key_share.rs create mode 100644 packages/ciphernode/core/src/wrapped/secret_key.rs diff --git a/packages/ciphernode/core/src/ciphernode.rs b/packages/ciphernode/core/src/ciphernode.rs index b424942f..6b85268d 100644 --- a/packages/ciphernode/core/src/ciphernode.rs +++ b/packages/ciphernode/core/src/ciphernode.rs @@ -1,10 +1,5 @@ use crate::{ - data::{Data, Insert}, - eventbus::EventBus, - events::{ComputationRequested, EnclaveEvent, KeyshareCreated}, - fhe::{Fhe, GenerateKeyshare}, - DecryptCiphertext, DecryptionRequested, DecryptionshareCreated, Get, Subscribe, - WrappedSecretKey, + data::{Data, Insert}, eventbus::EventBus, events::{ComputationRequested, EnclaveEvent, KeyshareCreated}, fhe::{Fhe, GenerateKeyshare}, wrapped::WrappedSecretKey, DecryptCiphertext, DecryptionRequested, DecryptionshareCreated, Get, Subscribe }; use actix::prelude::*; use anyhow::Result; diff --git a/packages/ciphernode/core/src/committee_key.rs b/packages/ciphernode/core/src/committee_key.rs index 7004fa10..c4492b92 100644 --- a/packages/ciphernode/core/src/committee_key.rs +++ b/packages/ciphernode/core/src/committee_key.rs @@ -1,7 +1,7 @@ use crate::{ eventbus::EventBus, events::{E3id, EnclaveEvent, KeyshareCreated, PublicKeyAggregated}, - fhe::{Fhe, GetAggregatePublicKey, WrappedPublicKey, WrappedPublicKeyShare}, ordered_set::OrderedSet, + fhe::{Fhe, GetAggregatePublicKey}, ordered_set::OrderedSet, wrapped::{WrappedPublicKey, WrappedPublicKeyShare}, }; use actix::prelude::*; use anyhow::{anyhow, Result}; diff --git a/packages/ciphernode/core/src/events.rs b/packages/ciphernode/core/src/events.rs index a5dcf6e4..da121257 100644 --- a/packages/ciphernode/core/src/events.rs +++ b/packages/ciphernode/core/src/events.rs @@ -1,7 +1,4 @@ -use crate::{ - fhe::{WrappedPublicKey, WrappedPublicKeyShare}, - WrappedCiphertext, WrappedDecryptionShare, -}; +use crate::wrapped::{WrappedCiphertext, WrappedDecryptionShare, WrappedPublicKey, WrappedPublicKeyShare}; use actix::Message; use bincode; use serde::{Deserialize, Serialize}; @@ -69,16 +66,15 @@ pub enum EnclaveEvent { }, DecryptionRequested { id: EventId, - data: DecryptionRequested + data: DecryptionRequested, }, DecryptionshareCreated { id: EventId, - data: DecryptionshareCreated - } - // CommitteeSelected, - // OutputDecrypted, - // CiphernodeRegistered, - // CiphernodeDeregistered, + data: DecryptionshareCreated, + }, // CommitteeSelected, + // OutputDecrypted, + // CiphernodeRegistered, + // CiphernodeDeregistered, } impl EnclaveEvent { @@ -102,7 +98,7 @@ impl From for EventId { EnclaveEvent::ComputationRequested { id, .. } => id, EnclaveEvent::PublicKeyAggregated { id, .. } => id, EnclaveEvent::DecryptionRequested { id, .. } => id, - EnclaveEvent::DecryptionshareCreated { id, .. } => id + EnclaveEvent::DecryptionshareCreated { id, .. } => id, } } } @@ -134,7 +130,6 @@ impl From for EnclaveEvent { } } - impl From for EnclaveEvent { fn from(data: DecryptionRequested) -> Self { EnclaveEvent::DecryptionRequested { @@ -166,12 +161,11 @@ pub struct KeyshareCreated { pub e3_id: E3id, } - #[derive(Message, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[rtype(result = "anyhow::Result<()>")] -pub struct DecryptionshareCreated { +pub struct DecryptionshareCreated { pub decryption_share: WrappedDecryptionShare, - pub e3_id: E3id + pub e3_id: E3id, } #[derive(Message, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] @@ -230,7 +224,7 @@ mod tests { use rand::SeedableRng; use rand_chacha::ChaCha20Rng; - use crate::{events::extract_enclave_event_name, E3id, KeyshareCreated, WrappedPublicKeyShare}; + use crate::{events::extract_enclave_event_name, wrapped::WrappedPublicKeyShare, E3id, KeyshareCreated}; use super::EnclaveEvent; diff --git a/packages/ciphernode/core/src/fhe.rs b/packages/ciphernode/core/src/fhe.rs index ec3f56d8..ed87e2f8 100644 --- a/packages/ciphernode/core/src/fhe.rs +++ b/packages/ciphernode/core/src/fhe.rs @@ -1,359 +1,48 @@ -use std::{cmp::Ordering, hash::Hash, mem, sync::Arc}; - -use crate::ordered_set::OrderedSet; +use crate::{ + ordered_set::OrderedSet, + wrapped::{ + WrappedCiphertext, WrappedDecryptionShare, WrappedPlaintext, WrappedPublicKey, WrappedPublicKeyShare, WrappedSecretKey + }, +}; use actix::{Actor, Context, Handler, Message}; use anyhow::*; use fhe::{ - bfv::{BfvParameters, BfvParametersBuilder, Ciphertext, Plaintext, PublicKey, SecretKey}, + bfv::{BfvParameters, BfvParametersBuilder, Plaintext, PublicKey, SecretKey}, mbfv::{AggregateIter, CommonRandomPoly, DecryptionShare, PublicKeyShare}, }; -use fhe_traits::{Deserialize, DeserializeParametrized, Serialize}; use rand::SeedableRng; use rand_chacha::ChaCha20Rng; -use serde::Serializer; - -// TODO: remove all this wrapping and serialization/deserialization code by ensuring everything from fhe.rs has a to_bytes() and deserialize() -> T methods and return only Vec outside of this actor +use std::{hash::Hash, sync::Arc}; #[derive(Message, Clone, Debug, PartialEq, Eq, Hash)] #[rtype(result = "Result<(WrappedSecretKey, WrappedPublicKeyShare)>")] +// TODO: Result<(Vec,Vec)> pub struct GenerateKeyshare { // responder_pk: Vec, // TODO: use this to encrypt the secret data } #[derive(Message, Clone, Debug, PartialEq, Eq)] #[rtype(result = "Result<(WrappedPublicKey)>")] +// TODO: Result> pub struct GetAggregatePublicKey { pub keyshares: OrderedSet, } #[derive(Message, Clone, Debug, PartialEq, Eq)] #[rtype(result = "Result<(WrappedPlaintext)>")] +// TODO: Result> pub struct GetAggregatePlaintext { pub decryptions: OrderedSet, } #[derive(Message, Clone, Debug, PartialEq, Eq)] #[rtype(result = "Result<(WrappedDecryptionShare)>")] +// TODO: Result> pub struct DecryptCiphertext { pub unsafe_secret: WrappedSecretKey, pub ciphertext: WrappedCiphertext, } -/// Wrapped PublicKeyShare. This is wrapped to provide an inflection point -/// as we use this library elsewhere we only implement traits as we need them -/// and avoid exposing underlying structures from fhe.rs -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct WrappedPublicKeyShare { - inner: PublicKeyShare, - // We need to hold copies of the params and crp in order to effectively serialize and - // deserialize the wrapped type - params: Arc, - crp: CommonRandomPoly, -} - -impl WrappedPublicKeyShare { - /// Public function to serialize specifically from the wrapped type including types that are - /// private from outside the crate - pub fn from_fhe_rs( - inner: PublicKeyShare, - params: Arc, - crp: CommonRandomPoly, - ) -> Self { - Self { inner, params, crp } - } - - pub fn clone_inner(&self) -> PublicKeyShare { - self.inner.clone() - } -} - -impl Ord for WrappedPublicKeyShare { - fn cmp(&self, other: &Self) -> Ordering { - self.inner.to_bytes().cmp(&other.inner.to_bytes()) - } -} - -impl PartialOrd for WrappedPublicKeyShare { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - -impl From for Vec { - fn from(share: WrappedPublicKeyShare) -> Self { - share.inner.to_bytes() - } -} - -impl Hash for WrappedPublicKeyShare { - fn hash(&self, state: &mut H) { - self.inner.to_bytes().hash(state) - } -} - -/// Deserialize from serde to WrappedPublicKeyShare -impl<'de> serde::Deserialize<'de> for WrappedPublicKeyShare { - fn deserialize(deserializer: D) -> std::result::Result - where - D: serde::Deserializer<'de>, - { - // Intermediate struct of bytes for deserialization - #[derive(serde::Deserialize)] - struct PublicKeyShareBytes { - par_bytes: Vec, - crp_bytes: Vec, - bytes: Vec, - } - let PublicKeyShareBytes { - par_bytes, - crp_bytes, - bytes, - } = PublicKeyShareBytes::deserialize(deserializer)?; - let params = Arc::new(BfvParameters::try_deserialize(&par_bytes).unwrap()); - let crp = - CommonRandomPoly::deserialize(&crp_bytes, ¶ms).map_err(serde::de::Error::custom)?; - let inner = PublicKeyShare::deserialize(&bytes, ¶ms, crp.clone()) - .map_err(serde::de::Error::custom)?; - // TODO: how do we create an invariant that the deserialized params match the global params? - std::result::Result::Ok(WrappedPublicKeyShare::from_fhe_rs(inner, params, crp)) - } -} - -/// Serialize to serde bytes representation -impl serde::Serialize for WrappedPublicKeyShare { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - use serde::ser::SerializeStruct; - let bytes = self.inner.to_bytes(); - let par_bytes = self.params.to_bytes(); - let crp_bytes = self.crp.to_bytes(); - // Intermediate struct of bytes - let mut state = serializer.serialize_struct("PublicKeyShare", 3)?; - state.serialize_field("par_bytes", &par_bytes)?; - state.serialize_field("crp_bytes", &crp_bytes)?; - state.serialize_field("bytes", &bytes)?; - state.end() - } -} - -/// Wrapped PublicKey. This is wrapped to provide an inflection point -/// as we use this library elsewhere we only implement traits as we need them -/// and avoid exposing underlying structures from fhe.rs -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct WrappedPublicKey { - inner: PublicKey, - params: Arc, -} - -impl WrappedPublicKey { - pub fn from_fhe_rs(inner: PublicKey, params: Arc) -> Self { - Self { inner, params } - } -} - -impl fhe_traits::Serialize for WrappedPublicKey { - fn to_bytes(&self) -> Vec { - self.inner.to_bytes() - } -} - -/// Deserialize from serde to WrappedPublicKey -impl<'de> serde::Deserialize<'de> for WrappedPublicKey { - fn deserialize(deserializer: D) -> std::result::Result - where - D: serde::Deserializer<'de>, - { - // Intermediate struct of bytes for deserialization - #[derive(serde::Deserialize)] - struct PublicKeyBytes { - par: Vec, - bytes: Vec, - } - let PublicKeyBytes { par, bytes } = PublicKeyBytes::deserialize(deserializer)?; - let params = Arc::new(BfvParameters::try_deserialize(&par).unwrap()); // TODO: fix errors - let inner = PublicKey::from_bytes(&bytes, ¶ms).map_err(serde::de::Error::custom)?; - // TODO: how do we create an invariant that the deserialized params match the global params? - std::result::Result::Ok(WrappedPublicKey::from_fhe_rs(inner, params)) - } -} - -/// Serialize to serde bytes representation -impl serde::Serialize for WrappedPublicKey { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - use serde::ser::SerializeStruct; - let bytes = self.inner.to_bytes(); - let par_bytes = self.params.to_bytes(); - // Intermediate struct of bytes - let mut state = serializer.serialize_struct("PublicKey", 2)?; - state.serialize_field("par_bytes", &par_bytes)?; - state.serialize_field("bytes", &bytes)?; - state.end() - } -} - -impl Hash for WrappedPublicKey { - fn hash(&self, state: &mut H) { - self.inner.to_bytes().hash(state) - } -} - -impl Ord for WrappedPublicKey { - fn cmp(&self, other: &Self) -> Ordering { - self.inner.to_bytes().cmp(&other.inner.to_bytes()) - } -} - -impl PartialOrd for WrappedPublicKey { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - -/// Wrapped SecretKey. This is wrapped to provide an inflection point -/// as we use this library elsewhere we only implement traits as we need them -/// and avoid exposing underlying structures from fhe.rs -// We should favor consuming patterns and avoid cloning and copying this value around in memory. -// Underlying key Zeroizes on drop -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct WrappedSecretKey { - inner: SecretKey, - params: Arc, -} - -impl WrappedSecretKey { - pub fn from_fhe_rs(inner: SecretKey, params: Arc) -> Self { - Self { inner, params } - } -} - -#[derive(serde::Serialize, serde::Deserialize)] -struct SecretKeyData { - coeffs: Box<[i64]>, - par: Vec, -} - -impl WrappedSecretKey { - pub fn unsafe_serialize(&self) -> Result> { - Ok(bincode::serialize(&SecretKeyData { - coeffs: self.inner.coeffs.clone(), - par: self.params.clone().to_bytes(), - })?) - } - - pub fn deserialize(bytes: Vec) -> Result { - let SecretKeyData { coeffs, par } = bincode::deserialize(&bytes)?; - let params = Arc::new(BfvParameters::try_deserialize(&par).unwrap()); - Ok(WrappedSecretKey::from_fhe_rs( - SecretKey::new(coeffs.to_vec(), ¶ms), - params, - )) - } -} - -/// Wrapped Ciphertext. This is wrapped to provide an inflection point -/// as we use this library elsewhere we only implement traits as we need them -/// and avoid exposing underlying structures from fhe.rs -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct WrappedCiphertext { - inner: Ciphertext, - params: Arc, -} - -impl WrappedCiphertext { - pub fn from_fhe_rs(inner: Ciphertext, params: Arc) -> Self { - Self { inner, params } - } -} - -impl Hash for WrappedCiphertext { - fn hash(&self, state: &mut H) { - self.inner.to_bytes().hash(state) - } -} - -/// Deserialize from serde to WrappedPublicKey -impl<'de> serde::Deserialize<'de> for WrappedCiphertext { - fn deserialize(deserializer: D) -> std::result::Result - where - D: serde::Deserializer<'de>, - { - // Intermediate struct of bytes for deserialization - #[derive(serde::Deserialize)] - struct DeserializedBytes { - par: Vec, - bytes: Vec, - } - let DeserializedBytes { par, bytes } = DeserializedBytes::deserialize(deserializer)?; - let params = Arc::new(BfvParameters::try_deserialize(&par).unwrap()); - let inner = Ciphertext::from_bytes(&bytes, ¶ms).map_err(serde::de::Error::custom)?; - std::result::Result::Ok(WrappedCiphertext::from_fhe_rs(inner, params)) - } -} -impl serde::Serialize for WrappedCiphertext { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - use serde::ser::SerializeStruct; - let bytes = self.inner.to_bytes(); - let par_bytes = self.params.to_bytes(); - // Intermediate struct of bytes - let mut state = serializer.serialize_struct("Ciphertext", 2)?; - state.serialize_field("par_bytes", &par_bytes)?; - state.serialize_field("bytes", &bytes)?; - state.end() - } -} - -#[derive( - Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, serde::Serialize, serde::Deserialize, -)] -pub struct WrappedDecryptionShare { - inner: Vec, - params: Vec, - ct: Vec, -} - -impl WrappedDecryptionShare { - pub fn from_fhe_rs( - inner: DecryptionShare, - params: Arc, - ct: Arc, - ) -> Self { - // Have to serialize immediately in order to clone etc. - let inner_bytes = inner.to_bytes(); - let params_bytes = params.to_bytes(); - let ct_bytes = ct.to_bytes(); - Self { - inner: inner_bytes, - params: params_bytes, - ct: ct_bytes, - } - } - - pub fn try_inner(self) -> Result { - let params = Arc::new(BfvParameters::try_deserialize(&self.params)?); - let ct = Arc::new(Ciphertext::from_bytes(&self.ct, ¶ms)?); - Ok(DecryptionShare::deserialize(&self.inner, ¶ms, ct)?) - } -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct WrappedPlaintext { - inner: Plaintext, -} - -impl WrappedPlaintext { - pub fn from_fhe_rs(inner: Plaintext /* params: Arc */) -> Self { - Self { inner } - } -} - /// Fhe library adaptor. All FHE computations should happen through this actor. pub struct Fhe { params: Arc, diff --git a/packages/ciphernode/core/src/lib.rs b/packages/ciphernode/core/src/lib.rs index f754d65d..a75580e7 100644 --- a/packages/ciphernode/core/src/lib.rs +++ b/packages/ciphernode/core/src/lib.rs @@ -13,6 +13,7 @@ mod fhe; mod logger; mod ordered_set; mod p2p; +mod wrapped; // TODO: this is too permissive pub use actix::prelude::*; @@ -56,18 +57,16 @@ pub use p2p::*; // TODO: move these out to a test folder #[cfg(test)] mod tests { - use std::{sync::Arc, time::Duration}; - use crate::{ ciphernode::Ciphernode, committee::CommitteeManager, data::{Data, GetLog}, eventbus::{EventBus, GetHistory, Subscribe}, events::{ComputationRequested, E3id, EnclaveEvent, KeyshareCreated, PublicKeyAggregated}, - fhe::{Fhe, WrappedPublicKey, WrappedPublicKeyShare}, + fhe::Fhe, p2p::P2p, - DecryptionRequested, DecryptionshareCreated, ResetHistory, WrappedCiphertext, - WrappedDecryptionShare, + wrapped::{WrappedCiphertext, WrappedDecryptionShare, WrappedPublicKey, WrappedPublicKeyShare}, + DecryptionRequested, DecryptionshareCreated, ResetHistory, }; use actix::prelude::*; use anyhow::*; @@ -78,6 +77,7 @@ mod tests { use fhe_traits::{FheEncoder, FheEncrypter}; use rand::SeedableRng; use rand_chacha::ChaCha20Rng; + use std::{sync::Arc, time::Duration}; use tokio::sync::Mutex; use tokio::{sync::mpsc::channel, time::sleep}; diff --git a/packages/ciphernode/core/src/wrapped/ciphertext.rs b/packages/ciphernode/core/src/wrapped/ciphertext.rs new file mode 100644 index 00000000..34259f62 --- /dev/null +++ b/packages/ciphernode/core/src/wrapped/ciphertext.rs @@ -0,0 +1,59 @@ +use fhe::bfv::{BfvParameters, Ciphertext}; +use fhe_traits::{Deserialize, DeserializeParametrized, Serialize}; +use serde::Serializer; +use std::{hash::Hash, sync::Arc}; + +/// Wrapped Ciphertext. This is wrapped to provide an inflection point +/// as we use this library elsewhere we only implement traits as we need them +/// and avoid exposing underlying structures from fhe.rs +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct WrappedCiphertext { + pub inner: Ciphertext, + pub params: Arc, +} + +impl WrappedCiphertext { + pub fn from_fhe_rs(inner: Ciphertext, params: Arc) -> Self { + Self { inner, params } + } +} + +impl Hash for WrappedCiphertext { + fn hash(&self, state: &mut H) { + self.inner.to_bytes().hash(state) + } +} + +/// Deserialize from serde to WrappedPublicKey +impl<'de> serde::Deserialize<'de> for WrappedCiphertext { + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + // Intermediate struct of bytes for deserialization + #[derive(serde::Deserialize)] + struct DeserializedBytes { + par: Vec, + bytes: Vec, + } + let DeserializedBytes { par, bytes } = DeserializedBytes::deserialize(deserializer)?; + let params = Arc::new(BfvParameters::try_deserialize(&par).unwrap()); + let inner = Ciphertext::from_bytes(&bytes, ¶ms).map_err(serde::de::Error::custom)?; + std::result::Result::Ok(WrappedCiphertext::from_fhe_rs(inner, params)) + } +} +impl serde::Serialize for WrappedCiphertext { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + use serde::ser::SerializeStruct; + let bytes = self.inner.to_bytes(); + let par_bytes = self.params.to_bytes(); + // Intermediate struct of bytes + let mut state = serializer.serialize_struct("Ciphertext", 2)?; + state.serialize_field("par_bytes", &par_bytes)?; + state.serialize_field("bytes", &bytes)?; + state.end() + } +} diff --git a/packages/ciphernode/core/src/wrapped/decryption_share.rs b/packages/ciphernode/core/src/wrapped/decryption_share.rs new file mode 100644 index 00000000..f9d6721f --- /dev/null +++ b/packages/ciphernode/core/src/wrapped/decryption_share.rs @@ -0,0 +1,40 @@ +use anyhow::*; +use fhe::{ + bfv::{BfvParameters, Ciphertext}, + mbfv::DecryptionShare, +}; +use fhe_traits::{Deserialize, DeserializeParametrized, Serialize}; +use std::sync::Arc; + +#[derive( + Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, serde::Serialize, serde::Deserialize, +)] +pub struct WrappedDecryptionShare { + inner: Vec, + params: Vec, + ct: Vec, +} + +impl WrappedDecryptionShare { + pub fn from_fhe_rs( + inner: DecryptionShare, + params: Arc, + ct: Arc, + ) -> Self { + // Have to serialize immediately in order to clone etc. + let inner_bytes = inner.to_bytes(); + let params_bytes = params.to_bytes(); + let ct_bytes = ct.to_bytes(); + Self { + inner: inner_bytes, + params: params_bytes, + ct: ct_bytes, + } + } + + pub fn try_inner(self) -> Result { + let params = Arc::new(BfvParameters::try_deserialize(&self.params)?); + let ct = Arc::new(Ciphertext::from_bytes(&self.ct, ¶ms)?); + Ok(DecryptionShare::deserialize(&self.inner, ¶ms, ct)?) + } +} diff --git a/packages/ciphernode/core/src/wrapped/mod.rs b/packages/ciphernode/core/src/wrapped/mod.rs new file mode 100644 index 00000000..94757206 --- /dev/null +++ b/packages/ciphernode/core/src/wrapped/mod.rs @@ -0,0 +1,13 @@ +mod ciphertext; +mod decryption_share; +mod plaintext; +mod public_key; +mod public_key_share; +mod secret_key; + +pub use ciphertext::*; +pub use decryption_share::*; +pub use plaintext::*; +pub use public_key::*; +pub use public_key_share::*; +pub use secret_key::*; diff --git a/packages/ciphernode/core/src/wrapped/plaintext.rs b/packages/ciphernode/core/src/wrapped/plaintext.rs new file mode 100644 index 00000000..7a51da2d --- /dev/null +++ b/packages/ciphernode/core/src/wrapped/plaintext.rs @@ -0,0 +1,12 @@ +use fhe::bfv::Plaintext; + +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct WrappedPlaintext { + pub inner: Plaintext, +} + +impl WrappedPlaintext { + pub fn from_fhe_rs(inner: Plaintext /* params: Arc */) -> Self { + Self { inner } + } +} diff --git a/packages/ciphernode/core/src/wrapped/public_key.rs b/packages/ciphernode/core/src/wrapped/public_key.rs new file mode 100644 index 00000000..71f7113f --- /dev/null +++ b/packages/ciphernode/core/src/wrapped/public_key.rs @@ -0,0 +1,80 @@ +use fhe::bfv::{BfvParameters, PublicKey}; +use fhe_traits::{Deserialize, DeserializeParametrized, Serialize}; +use serde::Serializer; +use std::{cmp::Ordering, hash::Hash, sync::Arc}; + +/// Wrapped PublicKey. This is wrapped to provide an inflection point +/// as we use this library elsewhere we only implement traits as we need them +/// and avoid exposing underlying structures from fhe.rs +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct WrappedPublicKey { + inner: PublicKey, + params: Arc, +} + +impl WrappedPublicKey { + pub fn from_fhe_rs(inner: PublicKey, params: Arc) -> Self { + Self { inner, params } + } +} + +impl fhe_traits::Serialize for WrappedPublicKey { + fn to_bytes(&self) -> Vec { + self.inner.to_bytes() + } +} + +/// Deserialize from serde to WrappedPublicKey +impl<'de> serde::Deserialize<'de> for WrappedPublicKey { + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + // Intermediate struct of bytes for deserialization + #[derive(serde::Deserialize)] + struct PublicKeyBytes { + par: Vec, + bytes: Vec, + } + let PublicKeyBytes { par, bytes } = PublicKeyBytes::deserialize(deserializer)?; + let params = Arc::new(BfvParameters::try_deserialize(&par).unwrap()); // TODO: fix errors + let inner = PublicKey::from_bytes(&bytes, ¶ms).map_err(serde::de::Error::custom)?; + // TODO: how do we create an invariant that the deserialized params match the global params? + std::result::Result::Ok(WrappedPublicKey::from_fhe_rs(inner, params)) + } +} + +/// Serialize to serde bytes representation +impl serde::Serialize for WrappedPublicKey { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + use serde::ser::SerializeStruct; + let bytes = self.inner.to_bytes(); + let par_bytes = self.params.to_bytes(); + // Intermediate struct of bytes + let mut state = serializer.serialize_struct("PublicKey", 2)?; + state.serialize_field("par_bytes", &par_bytes)?; + state.serialize_field("bytes", &bytes)?; + state.end() + } +} + +impl Hash for WrappedPublicKey { + fn hash(&self, state: &mut H) { + self.inner.to_bytes().hash(state) + } +} + +impl Ord for WrappedPublicKey { + fn cmp(&self, other: &Self) -> Ordering { + self.inner.to_bytes().cmp(&other.inner.to_bytes()) + } +} + +impl PartialOrd for WrappedPublicKey { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} diff --git a/packages/ciphernode/core/src/wrapped/public_key_share.rs b/packages/ciphernode/core/src/wrapped/public_key_share.rs new file mode 100644 index 00000000..1e3983d3 --- /dev/null +++ b/packages/ciphernode/core/src/wrapped/public_key_share.rs @@ -0,0 +1,106 @@ +use std::{cmp::Ordering, hash::Hash, sync::Arc}; +use fhe_traits::{Deserialize, Serialize}; +use fhe::{ + bfv::BfvParameters, + mbfv::{CommonRandomPoly, PublicKeyShare}, +}; +use serde::Serializer; + +/// Wrapped PublicKeyShare. This is wrapped to provide an inflection point +/// as we use this library elsewhere we only implement traits as we need them +/// and avoid exposing underlying structures from fhe.rs +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct WrappedPublicKeyShare { + inner: PublicKeyShare, + // We need to hold copies of the params and crp in order to effectively serialize and + // deserialize the wrapped type + params: Arc, + crp: CommonRandomPoly, +} + +impl WrappedPublicKeyShare { + /// Public function to serialize specifically from the wrapped type including types that are + /// private from outside the crate + pub fn from_fhe_rs( + inner: PublicKeyShare, + params: Arc, + crp: CommonRandomPoly, + ) -> Self { + Self { inner, params, crp } + } + + pub fn clone_inner(&self) -> PublicKeyShare { + self.inner.clone() + } +} + +impl Ord for WrappedPublicKeyShare { + fn cmp(&self, other: &Self) -> Ordering { + self.inner.to_bytes().cmp(&other.inner.to_bytes()) + } +} + +impl PartialOrd for WrappedPublicKeyShare { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl From for Vec { + fn from(share: WrappedPublicKeyShare) -> Self { + share.inner.to_bytes() + } +} + +impl Hash for WrappedPublicKeyShare { + fn hash(&self, state: &mut H) { + self.inner.to_bytes().hash(state) + } +} + +/// Deserialize from serde to WrappedPublicKeyShare +impl<'de> serde::Deserialize<'de> for WrappedPublicKeyShare { + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + // Intermediate struct of bytes for deserialization + #[derive(serde::Deserialize)] + struct PublicKeyShareBytes { + par_bytes: Vec, + crp_bytes: Vec, + bytes: Vec, + } + let PublicKeyShareBytes { + par_bytes, + crp_bytes, + bytes, + } = PublicKeyShareBytes::deserialize(deserializer)?; + let params = Arc::new(BfvParameters::try_deserialize(&par_bytes).unwrap()); + let crp = + CommonRandomPoly::deserialize(&crp_bytes, ¶ms).map_err(serde::de::Error::custom)?; + let inner = PublicKeyShare::deserialize(&bytes, ¶ms, crp.clone()) + .map_err(serde::de::Error::custom)?; + // TODO: how do we create an invariant that the deserialized params match the global params? + std::result::Result::Ok(WrappedPublicKeyShare::from_fhe_rs(inner, params, crp)) + } +} + +/// Serialize to serde bytes representation +impl serde::Serialize for WrappedPublicKeyShare { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + use serde::ser::SerializeStruct; + let bytes = self.inner.to_bytes(); + let par_bytes = self.params.to_bytes(); + let crp_bytes = self.crp.to_bytes(); + // Intermediate struct of bytes + let mut state = serializer.serialize_struct("PublicKeyShare", 3)?; + state.serialize_field("par_bytes", &par_bytes)?; + state.serialize_field("crp_bytes", &crp_bytes)?; + state.serialize_field("bytes", &bytes)?; + state.end() + } +} diff --git a/packages/ciphernode/core/src/wrapped/secret_key.rs b/packages/ciphernode/core/src/wrapped/secret_key.rs new file mode 100644 index 00000000..2c662f1b --- /dev/null +++ b/packages/ciphernode/core/src/wrapped/secret_key.rs @@ -0,0 +1,45 @@ +use anyhow::*; +use fhe::bfv::{BfvParameters, SecretKey}; +use fhe_traits::{Deserialize, Serialize}; +use std::sync::Arc; + +/// Wrapped SecretKey. This is wrapped to provide an inflection point +/// as we use this library elsewhere we only implement traits as we need them +/// and avoid exposing underlying structures from fhe.rs +// We should favor consuming patterns and avoid cloning and copying this value around in memory. +// Underlying key Zeroizes on drop +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct WrappedSecretKey { + pub inner: SecretKey, + pub params: Arc, +} + +impl WrappedSecretKey { + pub fn from_fhe_rs(inner: SecretKey, params: Arc) -> Self { + Self { inner, params } + } +} + +#[derive(serde::Serialize, serde::Deserialize)] +struct SecretKeyData { + coeffs: Box<[i64]>, + par: Vec, +} + +impl WrappedSecretKey { + pub fn unsafe_serialize(&self) -> Result> { + Ok(bincode::serialize(&SecretKeyData { + coeffs: self.inner.coeffs.clone(), + par: self.params.clone().to_bytes(), + })?) + } + + pub fn deserialize(bytes: Vec) -> Result { + let SecretKeyData { coeffs, par } = bincode::deserialize(&bytes)?; + let params = Arc::new(BfvParameters::try_deserialize(&par).unwrap()); + Ok(WrappedSecretKey::from_fhe_rs( + SecretKey::new(coeffs.to_vec(), ¶ms), + params, + )) + } +} From f64ab1d4ba6f7e6c8b18486d91b4610e6fff607c Mon Sep 17 00:00:00 2001 From: Hamza Khalid Date: Thu, 29 Aug 2024 19:04:28 +0500 Subject: [PATCH 30/87] feat: eth actor --- packages/ciphernode/Cargo.lock | 6 +- packages/ciphernode/enclave_node/Cargo.toml | 2 + .../enclave_node/src/bin/eth-listener.rs | 33 ++++++ packages/ciphernode/eth/Cargo.toml | 16 ++- packages/ciphernode/eth/src/lib.rs | 2 +- packages/ciphernode/eth/src/listener.rs | 111 ++++++++++++++---- packages/ciphernode/eth/src/manager.rs | 50 +++++++- 7 files changed, 185 insertions(+), 35 deletions(-) create mode 100644 packages/ciphernode/enclave_node/src/bin/eth-listener.rs diff --git a/packages/ciphernode/Cargo.lock b/packages/ciphernode/Cargo.lock index d221500b..99c21fd2 100644 --- a/packages/ciphernode/Cargo.lock +++ b/packages/ciphernode/Cargo.lock @@ -1897,6 +1897,7 @@ name = "enclave_node" version = "0.1.0" dependencies = [ "actix-rt", + "alloy", "async-std", "bfv", "enclave-core", @@ -1940,14 +1941,13 @@ dependencies = [ name = "eth" version = "0.1.0" dependencies = [ + "actix", "alloy", "alloy-primitives 0.6.4", "alloy-sol-types 0.6.4", "async-std", + "enclave-core", "eyre", - "fhe", - "fhe-traits", - "fhe-util", "futures-util", ] diff --git a/packages/ciphernode/enclave_node/Cargo.toml b/packages/ciphernode/enclave_node/Cargo.toml index 2f1698f0..f062f405 100644 --- a/packages/ciphernode/enclave_node/Cargo.toml +++ b/packages/ciphernode/enclave_node/Cargo.toml @@ -18,3 +18,5 @@ fhe-traits = { git = "https://github.com/gnosisguild/fhe.rs", version = "0.1.0-b fhe-util = { git = "https://github.com/gnosisguild/fhe.rs", version = "0.1.0-beta.7" } tokio = { version = "1.38", features = ["full"] } actix-rt = "2.10.0" + +alloy = { version = "0.2.1", features = ["full"] } \ No newline at end of file diff --git a/packages/ciphernode/enclave_node/src/bin/eth-listener.rs b/packages/ciphernode/enclave_node/src/bin/eth-listener.rs new file mode 100644 index 00000000..fca5630c --- /dev/null +++ b/packages/ciphernode/enclave_node/src/bin/eth-listener.rs @@ -0,0 +1,33 @@ +use enclave_core::Actor; +use enclave_core::EventBus; + +use eth::StartListening; +use eth::{AddListener, ContractManager, AddEventHandler}; +use std::error::Error; +use tokio::signal; +use alloy::{primitives::address, sol}; + +sol! { + #[derive(Debug)] + event TestingEvent(uint256 e3Id, bytes input); +} + +#[actix_rt::main] +async fn main() -> Result<(), Box> { + let bus = EventBus::new(true).start(); + + let manager = ContractManager::attach(bus.clone(), "ws://127.0.0.1:8545").await; + let listener = manager + .send(AddListener { + contract_address: address!("e7f1725E7734CE288F8367e1Bb143E90bb3F0512"), + }) + .await + .unwrap(); + + listener.send(AddEventHandler::::new()).await.unwrap(); + listener.do_send(StartListening); // or manager.do_send(StartListening) if multiple listeners + + signal::ctrl_c().await.unwrap(); + + Ok(()) +} diff --git a/packages/ciphernode/eth/Cargo.toml b/packages/ciphernode/eth/Cargo.toml index df17ea90..19454d8c 100644 --- a/packages/ciphernode/eth/Cargo.toml +++ b/packages/ciphernode/eth/Cargo.toml @@ -9,12 +9,16 @@ path = "src/lib.rs" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +# Core +enclave-core = { path = "../core" } + +# Actix +actix = "0.13.5" async-std = "1.12.0" -fhe = { git = "https://github.com/gnosisguild/fhe.rs", version = "0.1.0-beta.7" } -fhe-traits = { git = "https://github.com/gnosisguild/fhe.rs", version = "0.1.0-beta.7" } -fhe-util = { git = "https://github.com/gnosisguild/fhe.rs", version = "0.1.0-beta.7" } + +# Ethereum +futures-util = "0.3" +eyre = "0.6" alloy = { version = "0.2.1", features = ["full"] } alloy-primitives = { version = "0.6", default-features = false, features = ["rlp", "serde", "std"] } -alloy-sol-types = { version = "0.6" } -futures-util = "0.3" -eyre = "0.6" \ No newline at end of file +alloy-sol-types = { version = "0.6" } \ No newline at end of file diff --git a/packages/ciphernode/eth/src/lib.rs b/packages/ciphernode/eth/src/lib.rs index a28cf1be..81ba5f41 100644 --- a/packages/ciphernode/eth/src/lib.rs +++ b/packages/ciphernode/eth/src/lib.rs @@ -1,6 +1,6 @@ #![crate_name = "eth"] #![crate_type = "lib"] -#![warn(missing_docs, unused_imports)] +// #![warn(missing_docs, unused_imports)] mod listener; mod manager; diff --git a/packages/ciphernode/eth/src/listener.rs b/packages/ciphernode/eth/src/listener.rs index 59197133..4f17a571 100644 --- a/packages/ciphernode/eth/src/listener.rs +++ b/packages/ciphernode/eth/src/listener.rs @@ -1,25 +1,30 @@ +use actix::{Actor, Addr, AsyncContext, Context, Handler, Message, WrapFuture}; use alloy::{ primitives::B256, providers::{Provider, RootProvider}, rpc::types::{Filter, Log}, - sol_types::SolEvent, transports::BoxTransport, + sol_types::SolEvent, + transports::BoxTransport, }; +use enclave_core::EventBus; use eyre::Result; use futures_util::stream::StreamExt; use std::collections::HashMap; -use std::sync::Arc; use std::fmt::Debug; +use std::sync::Arc; +use std::marker::PhantomData; pub trait ContractEvent: Send + Sync + 'static { - fn process(&self) -> Result<()>; + fn process(&self, bus: Addr) -> Result<()>; } impl ContractEvent for T where T: SolEvent + Debug + Send + Sync + 'static, { - fn process(&self) -> Result<()> { + fn process(&self, _bus: Addr) -> Result<()> { println!("Processing event: {:?}", self); + // bus.do_send(EnclaveEvent::from(self)); Ok(()) } } @@ -28,14 +33,20 @@ pub struct EventListener { provider: Arc>, filter: Filter, handlers: HashMap Result> + Send + Sync>>, + bus: Addr, } impl EventListener { - pub fn new(provider: Arc>, filter: Filter) -> Self { + pub fn new( + provider: Arc>, + filter: Filter, + bus: Addr, + ) -> Self { Self { provider, filter, handlers: HashMap::new(), + bus, } } @@ -53,24 +64,17 @@ impl EventListener { } pub async fn listen(&self) -> Result<()> { - let sub = self.provider.subscribe_logs(&self.filter).await?; - let mut stream = sub.into_stream(); - + let mut stream = self + .provider + .subscribe_logs(&self.filter) + .await? + .into_stream(); while let Some(log) = stream.next().await { - if let Some(topic) = log.topic0() { - if let Some(handler) = self.handlers.get(topic) { - match handler(log.clone()) { - Ok(event) => { - if let Err(err) = event.process() { - eprintln!("Error processing event: {:?}", err); - } - } - Err(err) => { - eprintln!("Error decoding log: {:?}", err); - } + if let Some(topic0) = log.topic0() { + if let Some(decoder) = self.handlers.get(topic0) { + if let Ok(event) = decoder(log.clone()) { + event.process(self.bus.clone())?; } - } else { - eprintln!("No handler found for topic: {:?}", topic); } } } @@ -79,3 +83,68 @@ impl EventListener { } } +impl Actor for EventListener { + type Context = Context; +} + +#[derive(Message)] +#[rtype(result = "()")] +pub struct AddEventHandler +where + E: SolEvent + ContractEvent + 'static, +{ + pub _marker: PhantomData, +} + +impl AddEventHandler +where + E: SolEvent + ContractEvent + 'static, +{ + pub fn new() -> Self { + Self { + _marker: PhantomData, + } + } +} + +impl Handler> for EventListener +where + E: SolEvent + ContractEvent + 'static, +{ + type Result = (); + + fn handle(&mut self, _: AddEventHandler, _: &mut Self::Context) -> Self::Result { + self.add_event_handler::(); + } +} + +#[derive(Message)] +#[rtype(result = "()")] +pub struct StartListening; + +impl Handler for EventListener { + type Result = (); + fn handle(&mut self, _: StartListening, ctx: &mut Self::Context) -> Self::Result { + let (provider, filter, handlers, bus) = ( + self.provider.clone(), + self.filter.clone(), + self.handlers.clone(), + self.bus.clone(), + ); + + ctx.spawn( + async move { + let listener = EventListener { + provider, + filter, + handlers, + bus, + }; + if let Err(err) = listener.listen().await { + eprintln!("Error listening for events: {:?}", err); + } + } + .into_actor(self), + ); + } +} diff --git a/packages/ciphernode/eth/src/manager.rs b/packages/ciphernode/eth/src/manager.rs index 3f315fd8..dd0e758f 100644 --- a/packages/ciphernode/eth/src/manager.rs +++ b/packages/ciphernode/eth/src/manager.rs @@ -1,30 +1,72 @@ +use crate::{EventListener, StartListening}; +use actix::{Actor, Addr, Context, Handler, Message}; use alloy::{ primitives::Address, providers::{ProviderBuilder, RootProvider}, rpc::types::{BlockNumberOrTag, Filter}, transports::BoxTransport, }; +use enclave_core::EventBus; use eyre::Result; use std::sync::Arc; -use crate::EventListener; pub struct ContractManager { + bus: Addr, provider: Arc>, + listeners: Vec>, } impl ContractManager { - pub async fn new(rpc_url: &str) -> Result { + async fn new(bus: Addr, rpc_url: &str) -> Result { let provider = ProviderBuilder::new().on_builtin(rpc_url).await?; Ok(Self { + bus, provider: Arc::new(provider), + listeners: vec![], }) } - pub fn add_listener(&self, contract_address: Address) -> EventListener { + pub async fn attach(bus: Addr, rpc_url: &str) -> Addr { + let addr = ContractManager::new(bus.clone(), rpc_url).await.unwrap().start(); + addr + } + + fn add_listener(&self, contract_address: Address) -> Addr { let filter = Filter::new() .address(contract_address) .from_block(BlockNumberOrTag::Latest); + let listener = EventListener::new(self.provider.clone(), filter, self.bus.clone()); + let addr = listener.start(); + addr + } +} + +impl Actor for ContractManager { + type Context = Context; +} + +#[derive(Message)] +#[rtype(result = "Addr")] +pub struct AddListener { + pub contract_address: Address, +} + +impl Handler for ContractManager { + type Result = Addr; + + fn handle(&mut self, msg: AddListener, _ctx: &mut Self::Context) -> Self::Result { + let listener = self.add_listener(msg.contract_address); + self.listeners.push(listener.clone()); + listener + } +} + +impl Handler for ContractManager { + type Result = (); - EventListener::new(self.provider.clone(), filter) + fn handle(&mut self, _: StartListening, _ctx: &mut Self::Context) -> Self::Result { + for listener in &self.listeners { + listener.do_send(StartListening); + } } } \ No newline at end of file From aa5c24cc930d0f7dbc3e201887ec175abb23dad2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=B3=CE=BB?= Date: Sat, 31 Aug 2024 07:19:49 +1000 Subject: [PATCH 31/87] Use Vec for FHE types (#34) * Use Vec * Tidy up and format * Rename to serializer --- packages/ciphernode/core/src/ciphernode.rs | 29 ++++--- packages/ciphernode/core/src/committee_key.rs | 21 ++--- packages/ciphernode/core/src/data.rs | 2 - .../ciphernode/core/src/enclave_contract.rs | 5 +- packages/ciphernode/core/src/events.rs | 23 +++-- packages/ciphernode/core/src/fhe.rs | 87 ++++++++++--------- packages/ciphernode/core/src/lib.rs | 32 +++---- .../ciphernode/core/src/wrapped/ciphertext.rs | 28 +++--- .../core/src/wrapped/decryption_share.rs | 25 ++---- .../ciphernode/core/src/wrapped/plaintext.rs | 8 +- .../ciphernode/core/src/wrapped/public_key.rs | 62 ++++++------- .../core/src/wrapped/public_key_share.rs | 54 ++++-------- .../ciphernode/core/src/wrapped/secret_key.rs | 24 ++--- 13 files changed, 188 insertions(+), 212 deletions(-) diff --git a/packages/ciphernode/core/src/ciphernode.rs b/packages/ciphernode/core/src/ciphernode.rs index 6b85268d..fc20fd8b 100644 --- a/packages/ciphernode/core/src/ciphernode.rs +++ b/packages/ciphernode/core/src/ciphernode.rs @@ -1,5 +1,10 @@ use crate::{ - data::{Data, Insert}, eventbus::EventBus, events::{ComputationRequested, EnclaveEvent, KeyshareCreated}, fhe::{Fhe, GenerateKeyshare}, wrapped::WrappedSecretKey, DecryptCiphertext, DecryptionRequested, DecryptionshareCreated, Get, Subscribe + data::{Data, Insert}, + eventbus::EventBus, + events::{ComputationRequested, EnclaveEvent, KeyshareCreated}, + fhe::{Fhe, GenerateKeyshare}, + wrapped::SecretKeySerializer, + DecryptCiphertext, DecryptionRequested, DecryptionshareCreated, Get, Subscribe, }; use actix::prelude::*; use anyhow::Result; @@ -21,8 +26,12 @@ impl Ciphernode { pub async fn attach(bus: Addr, fhe: Addr, data: Addr) -> Addr { let node = Ciphernode::new(bus.clone(), fhe, data).start(); - let _ = bus.send(Subscribe::new("ComputationRequested", node.clone().into())).await; - let _ = bus.send(Subscribe::new("DecryptionRequested", node.clone().into())).await; + let _ = bus + .send(Subscribe::new("ComputationRequested", node.clone().into())) + .await; + let _ = bus + .send(Subscribe::new("DecryptionRequested", node.clone().into())) + .await; node } } @@ -84,16 +93,10 @@ async fn on_computation_requested( // reencrypt secretkey locally with env var - this is so we don't have to serialize a secret // best practice would be as you boot up a node you enter in a configured password from // which we derive a kdf which gets used to generate this key - data.do_send(Insert( - format!("{}/sk", e3_id).into(), - sk.unsafe_serialize()?, - )); + data.do_send(Insert(format!("{}/sk", e3_id).into(), sk)); // save public key against e3_id/pk - data.do_send(Insert( - format!("{}/pk", e3_id).into(), - pubkey.clone().into(), - )); + data.do_send(Insert(format!("{}/pk", e3_id).into(), pubkey.clone())); // broadcast the KeyshareCreated message let event = EnclaveEvent::from(KeyshareCreated { pubkey, e3_id }); @@ -111,12 +114,10 @@ async fn on_decryption_requested( let DecryptionRequested { e3_id, ciphertext } = event; // get secret key by id from data - let Some(sk_bytes) = data.send(Get(format!("{}/sk", e3_id).into())).await? else { + let Some(unsafe_secret) = data.send(Get(format!("{}/sk", e3_id).into())).await? else { return Err(anyhow::anyhow!("Secret key not stored for {}", e3_id)); }; - let unsafe_secret = WrappedSecretKey::deserialize(sk_bytes)?; - let decryption_share = fhe .send(DecryptCiphertext { ciphertext, diff --git a/packages/ciphernode/core/src/committee_key.rs b/packages/ciphernode/core/src/committee_key.rs index c4492b92..b09b6c6e 100644 --- a/packages/ciphernode/core/src/committee_key.rs +++ b/packages/ciphernode/core/src/committee_key.rs @@ -1,7 +1,8 @@ use crate::{ eventbus::EventBus, events::{E3id, EnclaveEvent, KeyshareCreated, PublicKeyAggregated}, - fhe::{Fhe, GetAggregatePublicKey}, ordered_set::OrderedSet, wrapped::{WrappedPublicKey, WrappedPublicKeyShare}, + fhe::{Fhe, GetAggregatePublicKey}, + ordered_set::OrderedSet, }; use actix::prelude::*; use anyhow::{anyhow, Result}; @@ -10,21 +11,21 @@ use anyhow::{anyhow, Result}; pub enum CommitteeKeyState { Collecting { nodecount: usize, - keyshares: OrderedSet, + keyshares: OrderedSet>, }, Computing { - keyshares: OrderedSet, + keyshares: OrderedSet>, }, Complete { - public_key: WrappedPublicKey, - keyshares: OrderedSet, + public_key: Vec, + keyshares: OrderedSet>, }, } #[derive(Message)] #[rtype(result = "anyhow::Result<()>")] struct ComputeAggregate { - pub keyshares: OrderedSet, + pub keyshares: OrderedSet>, } #[derive(Message)] @@ -39,7 +40,7 @@ pub struct CommitteeKey { } /// Aggregate PublicKey for a committee of nodes. This actor listens for KeyshareCreated events -/// around a particular e3_id and aggregates the public key based on this and once done broadcasts +/// around a particular e3_id and aggregates the public key based on this and once done broadcasts /// a EnclaveEvent::PublicKeyAggregated event on the event bus. Note events are hashed and /// identical events will not be triggered twice. /// It is expected to change this mechanism as we work through adversarial scenarios and write tests @@ -57,7 +58,7 @@ impl CommitteeKey { } } - pub fn add_keyshare(&mut self, keyshare: WrappedPublicKeyShare) -> Result { + pub fn add_keyshare(&mut self, keyshare: Vec) -> Result { let CommitteeKeyState::Collecting { nodecount, keyshares, @@ -76,7 +77,7 @@ impl CommitteeKey { Ok(self.state.clone()) } - pub fn set_pubkey(&mut self, pubkey: WrappedPublicKey) -> Result { + pub fn set_pubkey(&mut self, pubkey: Vec) -> Result { let CommitteeKeyState::Computing { keyshares } = &mut self.state else { return Ok(self.state.clone()); }; @@ -129,7 +130,7 @@ impl Handler for CommitteeKey { fn handle(&mut self, msg: ComputeAggregate, _: &mut Self::Context) -> Self::Result { // Futures are awkward in Actix from what I can tell we should try and structure events so - // that futures that don't reuire access to self filre like the following... + // that futures that don't require access to self like the following... Box::pin( // Run the async future. self.fhe diff --git a/packages/ciphernode/core/src/data.rs b/packages/ciphernode/core/src/data.rs index dd23c2eb..7da55390 100644 --- a/packages/ciphernode/core/src/data.rs +++ b/packages/ciphernode/core/src/data.rs @@ -17,7 +17,6 @@ impl Insert { } } - #[derive(Message, Clone, Debug, PartialEq, Eq, Hash)] #[rtype(result = "Option>")] pub struct Get(pub Vec); @@ -59,7 +58,6 @@ impl Data { impl Handler for Data { type Result = (); fn handle(&mut self, event: Insert, _: &mut Self::Context) { - // insert data into sled self.db.insert(event.key(), event.value()); diff --git a/packages/ciphernode/core/src/enclave_contract.rs b/packages/ciphernode/core/src/enclave_contract.rs index 5639f562..ef607190 100644 --- a/packages/ciphernode/core/src/enclave_contract.rs +++ b/packages/ciphernode/core/src/enclave_contract.rs @@ -1,4 +1,3 @@ - use actix::{Actor, Context}; /// Manage an internal web3 instance and express protocol specific behaviour through the events it @@ -9,8 +8,6 @@ use actix::{Actor, Context}; /// Accept eventbus events and forward as appropriate contract calls as required pub struct EnclaveContract; -impl Actor for EnclaveContract{ +impl Actor for EnclaveContract { type Context = Context; } - - diff --git a/packages/ciphernode/core/src/events.rs b/packages/ciphernode/core/src/events.rs index da121257..5e5e8a3b 100644 --- a/packages/ciphernode/core/src/events.rs +++ b/packages/ciphernode/core/src/events.rs @@ -1,4 +1,3 @@ -use crate::wrapped::{WrappedCiphertext, WrappedDecryptionShare, WrappedPublicKey, WrappedPublicKeyShare}; use actix::Message; use bincode; use serde::{Deserialize, Serialize}; @@ -157,21 +156,21 @@ impl fmt::Display for EnclaveEvent { #[derive(Message, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[rtype(result = "anyhow::Result<()>")] pub struct KeyshareCreated { - pub pubkey: WrappedPublicKeyShare, + pub pubkey: Vec, pub e3_id: E3id, } #[derive(Message, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[rtype(result = "anyhow::Result<()>")] pub struct DecryptionshareCreated { - pub decryption_share: WrappedDecryptionShare, + pub decryption_share: Vec, pub e3_id: E3id, } #[derive(Message, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[rtype(result = "()")] pub struct PublicKeyAggregated { - pub pubkey: WrappedPublicKey, + pub pubkey: Vec, pub e3_id: E3id, } @@ -192,7 +191,7 @@ pub struct ComputationRequested { #[rtype(result = "()")] pub struct DecryptionRequested { pub e3_id: E3id, - pub ciphertext: WrappedCiphertext, + pub ciphertext: Vec, } fn extract_enclave_event_name(s: &str) -> &str { @@ -214,19 +213,17 @@ impl EnclaveEvent { #[cfg(test)] mod tests { - - use std::error::Error; - + use super::EnclaveEvent; + use crate::{ + events::extract_enclave_event_name, wrapped::PublicKeyShareSerializer, E3id, KeyshareCreated, + }; use fhe::{ bfv::{BfvParametersBuilder, SecretKey}, mbfv::{CommonRandomPoly, PublicKeyShare}, }; use rand::SeedableRng; use rand_chacha::ChaCha20Rng; - - use crate::{events::extract_enclave_event_name, wrapped::WrappedPublicKeyShare, E3id, KeyshareCreated}; - - use super::EnclaveEvent; + use std::error::Error; #[test] fn test_extract_enum_name() { @@ -254,7 +251,7 @@ mod tests { let crp = CommonRandomPoly::new(¶ms, &mut rng)?; let sk_share = { SecretKey::random(¶ms, &mut rng) }; let pk_share = { PublicKeyShare::new(&sk_share, crp.clone(), &mut rng)? }; - let pubkey = WrappedPublicKeyShare::from_fhe_rs(pk_share, params.clone(), crp.clone()); + let pubkey = PublicKeyShareSerializer::to_bytes(pk_share, params.clone(), crp.clone())?; let kse = EnclaveEvent::from(KeyshareCreated { e3_id: E3id::from(1001), pubkey, diff --git a/packages/ciphernode/core/src/fhe.rs b/packages/ciphernode/core/src/fhe.rs index ed87e2f8..17c4c3f0 100644 --- a/packages/ciphernode/core/src/fhe.rs +++ b/packages/ciphernode/core/src/fhe.rs @@ -1,13 +1,14 @@ use crate::{ ordered_set::OrderedSet, wrapped::{ - WrappedCiphertext, WrappedDecryptionShare, WrappedPlaintext, WrappedPublicKey, WrappedPublicKeyShare, WrappedSecretKey + CiphertextSerializer, DecryptionShareSerializer, PlaintextSerializer, PublicKeySerializer, + PublicKeyShareSerializer, SecretKeySerializer, }, }; use actix::{Actor, Context, Handler, Message}; use anyhow::*; use fhe::{ - bfv::{BfvParameters, BfvParametersBuilder, Plaintext, PublicKey, SecretKey}, + bfv::{BfvParameters, BfvParametersBuilder, Ciphertext, Plaintext, PublicKey, SecretKey}, mbfv::{AggregateIter, CommonRandomPoly, DecryptionShare, PublicKeyShare}, }; use rand::SeedableRng; @@ -15,32 +16,28 @@ use rand_chacha::ChaCha20Rng; use std::{hash::Hash, sync::Arc}; #[derive(Message, Clone, Debug, PartialEq, Eq, Hash)] -#[rtype(result = "Result<(WrappedSecretKey, WrappedPublicKeyShare)>")] -// TODO: Result<(Vec,Vec)> +#[rtype(result = "Result<(Vec, Vec)>")] pub struct GenerateKeyshare { // responder_pk: Vec, // TODO: use this to encrypt the secret data } #[derive(Message, Clone, Debug, PartialEq, Eq)] -#[rtype(result = "Result<(WrappedPublicKey)>")] -// TODO: Result> +#[rtype(result = "Result<(Vec)>")] pub struct GetAggregatePublicKey { - pub keyshares: OrderedSet, + pub keyshares: OrderedSet>, } #[derive(Message, Clone, Debug, PartialEq, Eq)] -#[rtype(result = "Result<(WrappedPlaintext)>")] -// TODO: Result> +#[rtype(result = "Result<(PlaintextSerializer)>")] pub struct GetAggregatePlaintext { - pub decryptions: OrderedSet, + pub decryptions: OrderedSet>, } #[derive(Message, Clone, Debug, PartialEq, Eq)] -#[rtype(result = "Result<(WrappedDecryptionShare)>")] -// TODO: Result> +#[rtype(result = "Result<(Vec)>")] pub struct DecryptCiphertext { - pub unsafe_secret: WrappedSecretKey, - pub ciphertext: WrappedCiphertext, + pub unsafe_secret: Vec, + pub ciphertext: Vec, } /// Fhe library adaptor. All FHE computations should happen through this actor. @@ -79,60 +76,68 @@ impl Fhe { } impl Handler for Fhe { - type Result = Result<(WrappedSecretKey, WrappedPublicKeyShare)>; + type Result = Result<(Vec, Vec)>; fn handle(&mut self, _event: GenerateKeyshare, _: &mut Self::Context) -> Self::Result { let sk_share = { SecretKey::random(&self.params, &mut self.rng) }; let pk_share = { PublicKeyShare::new(&sk_share, self.crp.clone(), &mut self.rng)? }; Ok(( - WrappedSecretKey::from_fhe_rs(sk_share, self.params.clone()), - WrappedPublicKeyShare::from_fhe_rs(pk_share, self.params.clone(), self.crp.clone()), + SecretKeySerializer::to_bytes(sk_share, self.params.clone())?, + PublicKeyShareSerializer::to_bytes(pk_share, self.params.clone(), self.crp.clone())?, )) } } impl Handler for Fhe { - type Result = Result; + type Result = Result>; fn handle(&mut self, msg: DecryptCiphertext, _: &mut Self::Context) -> Self::Result { let DecryptCiphertext { unsafe_secret, // TODO: fix security issues with sending secrets between actors ciphertext, } = msg; - let ct = Arc::new(ciphertext.inner); - let inner = DecryptionShare::new(&unsafe_secret.inner, &ct, &mut self.rng).unwrap(); + let secret_key = SecretKeySerializer::from_bytes(&unsafe_secret)?; + let ct = Arc::new(CiphertextSerializer::from_bytes(&ciphertext)?); + let inner = DecryptionShare::new(&secret_key, &ct, &mut self.rng).unwrap(); - Ok(WrappedDecryptionShare::from_fhe_rs( + Ok(DecryptionShareSerializer::to_bytes( inner, - ciphertext.params, + self.params.clone(), ct.clone(), - )) + )?) } } impl Handler for Fhe { - type Result = Result; + type Result = Result>; fn handle(&mut self, msg: GetAggregatePublicKey, _: &mut Self::Context) -> Self::Result { - // Could implement Aggregate for Wrapped keys but that leaks traits - let public_key: PublicKey = msg.keyshares.iter().map(|k| k.clone_inner()).aggregate()?; - Ok(WrappedPublicKey::from_fhe_rs( - public_key, - self.params.clone(), - )) - } -} - -impl Handler for Fhe { - type Result = Result; - fn handle(&mut self, msg: GetAggregatePlaintext, _: &mut Self::Context) -> Self::Result { - let plaintext: Plaintext = msg - .decryptions + let public_key: PublicKey = msg + .keyshares .iter() - .map(|k| k.clone().try_inner()) - .collect::>>()? // NOTE: not optimal + .map(|k| PublicKeyShareSerializer::from_bytes(k)) + .collect::>>()? .into_iter() .aggregate()?; - Ok(WrappedPlaintext::from_fhe_rs(plaintext)) + Ok(PublicKeySerializer::to_bytes( + public_key, + self.params.clone(), + )?) } } + +// TODO: add this once we have decryption aggregation ready +// impl Handler for Fhe { +// type Result = Result; +// fn handle(&mut self, msg: GetAggregatePlaintext, _: &mut Self::Context) -> Self::Result { +// let plaintext: Plaintext = msg +// .decryptions +// .iter() +// .map(|k| k.clone().try_inner()) +// .collect::>>()? // NOTE: not optimal +// .into_iter() +// .aggregate()?; +// +// Ok(PlaintextSerializer::to_bytes(plaintext)) +// } +// } diff --git a/packages/ciphernode/core/src/lib.rs b/packages/ciphernode/core/src/lib.rs index a75580e7..08e00fa5 100644 --- a/packages/ciphernode/core/src/lib.rs +++ b/packages/ciphernode/core/src/lib.rs @@ -60,12 +60,14 @@ mod tests { use crate::{ ciphernode::Ciphernode, committee::CommitteeManager, - data::{Data, GetLog}, - eventbus::{EventBus, GetHistory, Subscribe}, + data::Data, + eventbus::{EventBus, GetHistory}, events::{ComputationRequested, E3id, EnclaveEvent, KeyshareCreated, PublicKeyAggregated}, fhe::Fhe, p2p::P2p, - wrapped::{WrappedCiphertext, WrappedDecryptionShare, WrappedPublicKey, WrappedPublicKeyShare}, + wrapped::{ + CiphertextSerializer, DecryptionShareSerializer, PublicKeySerializer, PublicKeyShareSerializer, + }, DecryptionRequested, DecryptionshareCreated, ResetHistory, }; use actix::prelude::*; @@ -117,13 +119,13 @@ mod tests { params: Arc, crp: CommonRandomPoly, mut rng: ChaCha20Rng, - ) -> Result<(WrappedPublicKeyShare, ChaCha20Rng, SecretKey)> { + ) -> Result<(Vec, ChaCha20Rng, SecretKey)> { let sk = SecretKey::random(¶ms, &mut rng); - let pk = WrappedPublicKeyShare::from_fhe_rs( + let pk = PublicKeyShareSerializer::to_bytes( PublicKeyShare::new(&sk, crp.clone(), &mut rng)?, params.clone(), crp, - ); + )?; Ok((pk, rng, sk)) } @@ -192,7 +194,7 @@ mod tests { let pubkey: PublicKey = vec![p1.clone(), p2.clone(), p3.clone()] .iter() - .map(|k| k.clone_inner()) + .map(|k| PublicKeyShareSerializer::from_bytes(k).unwrap()) .aggregate()?; assert_eq!(history.len(), 5); @@ -218,7 +220,7 @@ mod tests { e3_id: e3_id.clone() }), EnclaveEvent::from(PublicKeyAggregated { - pubkey: WrappedPublicKey::from_fhe_rs(pubkey.clone(), params.clone()), + pubkey: PublicKeySerializer::to_bytes(pubkey.clone(), params.clone())?, e3_id: e3_id.clone() }) ] @@ -235,27 +237,27 @@ mod tests { let ciphertext = pubkey.try_encrypt(&pt, &mut ChaCha20Rng::seed_from_u64(42))?; let event = EnclaveEvent::from(DecryptionRequested { - ciphertext: WrappedCiphertext::from_fhe_rs(ciphertext.clone(), params.clone()), + ciphertext: CiphertextSerializer::to_bytes(ciphertext.clone(), params.clone())?, e3_id: e3_id.clone(), }); let arc_ct = Arc::new(ciphertext); - let ds1 = WrappedDecryptionShare::from_fhe_rs( + let ds1 = DecryptionShareSerializer::to_bytes( DecryptionShare::new(&sk1, &arc_ct, &mut rng).unwrap(), params.clone(), arc_ct.clone(), - ); - let ds2 = WrappedDecryptionShare::from_fhe_rs( + )?; + let ds2 = DecryptionShareSerializer::to_bytes( DecryptionShare::new(&sk2, &arc_ct, &mut rng).unwrap(), params.clone(), arc_ct.clone(), - ); - let ds3 = WrappedDecryptionShare::from_fhe_rs( + )?; + let ds3 = DecryptionShareSerializer::to_bytes( DecryptionShare::new(&sk3, &arc_ct, &mut rng).unwrap(), params.clone(), arc_ct.clone(), - ); + )?; // let ds1 = sk1 bus.send(event.clone()).await?; diff --git a/packages/ciphernode/core/src/wrapped/ciphertext.rs b/packages/ciphernode/core/src/wrapped/ciphertext.rs index 34259f62..0ad61ee3 100644 --- a/packages/ciphernode/core/src/wrapped/ciphertext.rs +++ b/packages/ciphernode/core/src/wrapped/ciphertext.rs @@ -1,31 +1,31 @@ +use anyhow::*; use fhe::bfv::{BfvParameters, Ciphertext}; use fhe_traits::{Deserialize, DeserializeParametrized, Serialize}; use serde::Serializer; -use std::{hash::Hash, sync::Arc}; +use std::sync::Arc; /// Wrapped Ciphertext. This is wrapped to provide an inflection point /// as we use this library elsewhere we only implement traits as we need them /// and avoid exposing underlying structures from fhe.rs -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct WrappedCiphertext { +pub struct CiphertextSerializer { pub inner: Ciphertext, pub params: Arc, } -impl WrappedCiphertext { - pub fn from_fhe_rs(inner: Ciphertext, params: Arc) -> Self { - Self { inner, params } +impl CiphertextSerializer { + pub fn to_bytes(inner: Ciphertext, params: Arc) -> Result> { + let value = Self { inner, params }; + Ok(bincode::serialize(&value)?) } -} -impl Hash for WrappedCiphertext { - fn hash(&self, state: &mut H) { - self.inner.to_bytes().hash(state) + pub fn from_bytes(bytes:&[u8]) -> Result{ + let wct: Self = bincode::deserialize(&bytes)?; + Ok(wct.inner) } } -/// Deserialize from serde to WrappedPublicKey -impl<'de> serde::Deserialize<'de> for WrappedCiphertext { +/// Deserialize from serde to PublicKeySerializer +impl<'de> serde::Deserialize<'de> for CiphertextSerializer { fn deserialize(deserializer: D) -> std::result::Result where D: serde::Deserializer<'de>, @@ -39,10 +39,10 @@ impl<'de> serde::Deserialize<'de> for WrappedCiphertext { let DeserializedBytes { par, bytes } = DeserializedBytes::deserialize(deserializer)?; let params = Arc::new(BfvParameters::try_deserialize(&par).unwrap()); let inner = Ciphertext::from_bytes(&bytes, ¶ms).map_err(serde::de::Error::custom)?; - std::result::Result::Ok(WrappedCiphertext::from_fhe_rs(inner, params)) + std::result::Result::Ok(Self { inner, params }) } } -impl serde::Serialize for WrappedCiphertext { +impl serde::Serialize for CiphertextSerializer { fn serialize(&self, serializer: S) -> Result where S: Serializer, diff --git a/packages/ciphernode/core/src/wrapped/decryption_share.rs b/packages/ciphernode/core/src/wrapped/decryption_share.rs index f9d6721f..9b384ddd 100644 --- a/packages/ciphernode/core/src/wrapped/decryption_share.rs +++ b/packages/ciphernode/core/src/wrapped/decryption_share.rs @@ -3,38 +3,31 @@ use fhe::{ bfv::{BfvParameters, Ciphertext}, mbfv::DecryptionShare, }; -use fhe_traits::{Deserialize, DeserializeParametrized, Serialize}; +use fhe_traits::Serialize; use std::sync::Arc; -#[derive( - Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, serde::Serialize, serde::Deserialize, -)] -pub struct WrappedDecryptionShare { +#[derive(serde::Serialize, serde::Deserialize)] +pub struct DecryptionShareSerializer { inner: Vec, params: Vec, ct: Vec, } -impl WrappedDecryptionShare { - pub fn from_fhe_rs( +impl DecryptionShareSerializer { + pub fn to_bytes( inner: DecryptionShare, params: Arc, ct: Arc, - ) -> Self { + ) -> Result> { // Have to serialize immediately in order to clone etc. let inner_bytes = inner.to_bytes(); let params_bytes = params.to_bytes(); let ct_bytes = ct.to_bytes(); - Self { + let value = Self { inner: inner_bytes, params: params_bytes, ct: ct_bytes, - } - } - - pub fn try_inner(self) -> Result { - let params = Arc::new(BfvParameters::try_deserialize(&self.params)?); - let ct = Arc::new(Ciphertext::from_bytes(&self.ct, ¶ms)?); - Ok(DecryptionShare::deserialize(&self.inner, ¶ms, ct)?) + }; + Ok(bincode::serialize(&value)?) } } diff --git a/packages/ciphernode/core/src/wrapped/plaintext.rs b/packages/ciphernode/core/src/wrapped/plaintext.rs index 7a51da2d..6e9ffbe6 100644 --- a/packages/ciphernode/core/src/wrapped/plaintext.rs +++ b/packages/ciphernode/core/src/wrapped/plaintext.rs @@ -1,12 +1,12 @@ use fhe::bfv::Plaintext; #[derive(Clone, Debug, PartialEq, Eq)] -pub struct WrappedPlaintext { +pub struct PlaintextSerializer { pub inner: Plaintext, } -impl WrappedPlaintext { - pub fn from_fhe_rs(inner: Plaintext /* params: Arc */) -> Self { - Self { inner } +impl PlaintextSerializer { + pub fn to_bytes(inner: Plaintext /* params: Arc */) -> Self { + Self { inner } } } diff --git a/packages/ciphernode/core/src/wrapped/public_key.rs b/packages/ciphernode/core/src/wrapped/public_key.rs index 71f7113f..528f2422 100644 --- a/packages/ciphernode/core/src/wrapped/public_key.rs +++ b/packages/ciphernode/core/src/wrapped/public_key.rs @@ -1,31 +1,31 @@ +use anyhow::*; use fhe::bfv::{BfvParameters, PublicKey}; use fhe_traits::{Deserialize, DeserializeParametrized, Serialize}; use serde::Serializer; -use std::{cmp::Ordering, hash::Hash, sync::Arc}; +use std::sync::Arc; /// Wrapped PublicKey. This is wrapped to provide an inflection point /// as we use this library elsewhere we only implement traits as we need them /// and avoid exposing underlying structures from fhe.rs -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct WrappedPublicKey { +pub struct PublicKeySerializer { inner: PublicKey, params: Arc, } -impl WrappedPublicKey { - pub fn from_fhe_rs(inner: PublicKey, params: Arc) -> Self { - Self { inner, params } +impl PublicKeySerializer { + pub fn to_bytes(inner: PublicKey, params: Arc) -> Result> { + let value = Self { inner, params }; + Ok(bincode::serialize(&value)?) } -} -impl fhe_traits::Serialize for WrappedPublicKey { - fn to_bytes(&self) -> Vec { - self.inner.to_bytes() + pub fn from_bytes(bytes: Vec) -> Result { + let wpk: PublicKeySerializer = bincode::deserialize(&bytes)?; + Ok(wpk.inner) } } -/// Deserialize from serde to WrappedPublicKey -impl<'de> serde::Deserialize<'de> for WrappedPublicKey { +/// Deserialize from serde to PublicKeySerializer +impl<'de> serde::Deserialize<'de> for PublicKeySerializer { fn deserialize(deserializer: D) -> std::result::Result where D: serde::Deserializer<'de>, @@ -40,12 +40,12 @@ impl<'de> serde::Deserialize<'de> for WrappedPublicKey { let params = Arc::new(BfvParameters::try_deserialize(&par).unwrap()); // TODO: fix errors let inner = PublicKey::from_bytes(&bytes, ¶ms).map_err(serde::de::Error::custom)?; // TODO: how do we create an invariant that the deserialized params match the global params? - std::result::Result::Ok(WrappedPublicKey::from_fhe_rs(inner, params)) + std::result::Result::Ok(Self { inner, params }) } } /// Serialize to serde bytes representation -impl serde::Serialize for WrappedPublicKey { +impl serde::Serialize for PublicKeySerializer { fn serialize(&self, serializer: S) -> Result where S: Serializer, @@ -61,20 +61,20 @@ impl serde::Serialize for WrappedPublicKey { } } -impl Hash for WrappedPublicKey { - fn hash(&self, state: &mut H) { - self.inner.to_bytes().hash(state) - } -} - -impl Ord for WrappedPublicKey { - fn cmp(&self, other: &Self) -> Ordering { - self.inner.to_bytes().cmp(&other.inner.to_bytes()) - } -} - -impl PartialOrd for WrappedPublicKey { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} +// impl Hash for PublicKeySerializer { +// fn hash(&self, state: &mut H) { +// self.inner.to_bytes().hash(state) +// } +// } +// +// impl Ord for PublicKeySerializer { +// fn cmp(&self, other: &Self) -> Ordering { +// self.inner.to_bytes().cmp(&other.inner.to_bytes()) +// } +// } +// +// impl PartialOrd for PublicKeySerializer { +// fn partial_cmp(&self, other: &Self) -> Option { +// Some(self.cmp(other)) +// } +// } diff --git a/packages/ciphernode/core/src/wrapped/public_key_share.rs b/packages/ciphernode/core/src/wrapped/public_key_share.rs index 1e3983d3..22f77cac 100644 --- a/packages/ciphernode/core/src/wrapped/public_key_share.rs +++ b/packages/ciphernode/core/src/wrapped/public_key_share.rs @@ -1,16 +1,16 @@ -use std::{cmp::Ordering, hash::Hash, sync::Arc}; -use fhe_traits::{Deserialize, Serialize}; +use anyhow::*; use fhe::{ bfv::BfvParameters, mbfv::{CommonRandomPoly, PublicKeyShare}, }; +use fhe_traits::{Deserialize, Serialize}; use serde::Serializer; +use std::sync::Arc; /// Wrapped PublicKeyShare. This is wrapped to provide an inflection point /// as we use this library elsewhere we only implement traits as we need them /// and avoid exposing underlying structures from fhe.rs -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct WrappedPublicKeyShare { +pub struct PublicKeyShareSerializer { inner: PublicKeyShare, // We need to hold copies of the params and crp in order to effectively serialize and // deserialize the wrapped type @@ -18,48 +18,26 @@ pub struct WrappedPublicKeyShare { crp: CommonRandomPoly, } -impl WrappedPublicKeyShare { +impl PublicKeyShareSerializer { /// Public function to serialize specifically from the wrapped type including types that are /// private from outside the crate - pub fn from_fhe_rs( + pub fn to_bytes( inner: PublicKeyShare, params: Arc, crp: CommonRandomPoly, - ) -> Self { - Self { inner, params, crp } - } - - pub fn clone_inner(&self) -> PublicKeyShare { - self.inner.clone() - } -} - -impl Ord for WrappedPublicKeyShare { - fn cmp(&self, other: &Self) -> Ordering { - self.inner.to_bytes().cmp(&other.inner.to_bytes()) + ) -> Result> { + let value = Self { inner, params, crp }; + Ok(bincode::serialize(&value)?) } -} - -impl PartialOrd for WrappedPublicKeyShare { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - -impl From for Vec { - fn from(share: WrappedPublicKeyShare) -> Self { - share.inner.to_bytes() - } -} -impl Hash for WrappedPublicKeyShare { - fn hash(&self, state: &mut H) { - self.inner.to_bytes().hash(state) + pub fn from_bytes(bytes: &[u8]) -> Result { + let wpk: Self = bincode::deserialize(&bytes)?; + Ok(wpk.inner) } } -/// Deserialize from serde to WrappedPublicKeyShare -impl<'de> serde::Deserialize<'de> for WrappedPublicKeyShare { +/// Deserialize from serde to PublicKeyShareSerializer +impl<'de> serde::Deserialize<'de> for PublicKeyShareSerializer { fn deserialize(deserializer: D) -> std::result::Result where D: serde::Deserializer<'de>, @@ -82,12 +60,12 @@ impl<'de> serde::Deserialize<'de> for WrappedPublicKeyShare { let inner = PublicKeyShare::deserialize(&bytes, ¶ms, crp.clone()) .map_err(serde::de::Error::custom)?; // TODO: how do we create an invariant that the deserialized params match the global params? - std::result::Result::Ok(WrappedPublicKeyShare::from_fhe_rs(inner, params, crp)) + std::result::Result::Ok(Self { inner, params, crp }) } } /// Serialize to serde bytes representation -impl serde::Serialize for WrappedPublicKeyShare { +impl serde::Serialize for PublicKeyShareSerializer { fn serialize(&self, serializer: S) -> Result where S: Serializer, diff --git a/packages/ciphernode/core/src/wrapped/secret_key.rs b/packages/ciphernode/core/src/wrapped/secret_key.rs index 2c662f1b..76c843fc 100644 --- a/packages/ciphernode/core/src/wrapped/secret_key.rs +++ b/packages/ciphernode/core/src/wrapped/secret_key.rs @@ -8,15 +8,19 @@ use std::sync::Arc; /// and avoid exposing underlying structures from fhe.rs // We should favor consuming patterns and avoid cloning and copying this value around in memory. // Underlying key Zeroizes on drop -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct WrappedSecretKey { +pub struct SecretKeySerializer { pub inner: SecretKey, pub params: Arc, } -impl WrappedSecretKey { - pub fn from_fhe_rs(inner: SecretKey, params: Arc) -> Self { - Self { inner, params } +impl SecretKeySerializer { + pub fn to_bytes(inner: SecretKey, params: Arc) -> Result> { + let value = Self { inner, params }; + Ok(value.unsafe_serialize()?) + } + + pub fn from_bytes(bytes: &[u8]) -> Result { + Ok(Self::deserialize(bytes)?.inner) } } @@ -26,7 +30,7 @@ struct SecretKeyData { par: Vec, } -impl WrappedSecretKey { +impl SecretKeySerializer { pub fn unsafe_serialize(&self) -> Result> { Ok(bincode::serialize(&SecretKeyData { coeffs: self.inner.coeffs.clone(), @@ -34,12 +38,12 @@ impl WrappedSecretKey { })?) } - pub fn deserialize(bytes: Vec) -> Result { + pub fn deserialize(bytes: &[u8]) -> Result { let SecretKeyData { coeffs, par } = bincode::deserialize(&bytes)?; let params = Arc::new(BfvParameters::try_deserialize(&par).unwrap()); - Ok(WrappedSecretKey::from_fhe_rs( - SecretKey::new(coeffs.to_vec(), ¶ms), + Ok(Self { + inner: SecretKey::new(coeffs.to_vec(), ¶ms), params, - )) + }) } } From be204e6becf5c841e53df91a6868e91e6fe82bef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=B3=CE=BB?= Date: Sat, 31 Aug 2024 07:27:01 +1000 Subject: [PATCH 32/87] Rename folder (#35) --- packages/ciphernode/core/src/ciphernode.rs | 2 +- packages/ciphernode/core/src/events.rs | 2 +- packages/ciphernode/core/src/fhe.rs | 2 +- packages/ciphernode/core/src/lib.rs | 4 ++-- .../core/src/{wrapped => serializers}/ciphertext.rs | 3 --- .../core/src/{wrapped => serializers}/decryption_share.rs | 0 packages/ciphernode/core/src/{wrapped => serializers}/mod.rs | 0 .../core/src/{wrapped => serializers}/plaintext.rs | 0 .../core/src/{wrapped => serializers}/public_key.rs | 3 --- .../core/src/{wrapped => serializers}/public_key_share.rs | 3 --- .../core/src/{wrapped => serializers}/secret_key.rs | 5 ----- 11 files changed, 5 insertions(+), 19 deletions(-) rename packages/ciphernode/core/src/{wrapped => serializers}/ciphertext.rs (90%) rename packages/ciphernode/core/src/{wrapped => serializers}/decryption_share.rs (100%) rename packages/ciphernode/core/src/{wrapped => serializers}/mod.rs (100%) rename packages/ciphernode/core/src/{wrapped => serializers}/plaintext.rs (100%) rename packages/ciphernode/core/src/{wrapped => serializers}/public_key.rs (92%) rename packages/ciphernode/core/src/{wrapped => serializers}/public_key_share.rs (93%) rename packages/ciphernode/core/src/{wrapped => serializers}/secret_key.rs (78%) diff --git a/packages/ciphernode/core/src/ciphernode.rs b/packages/ciphernode/core/src/ciphernode.rs index fc20fd8b..8481291e 100644 --- a/packages/ciphernode/core/src/ciphernode.rs +++ b/packages/ciphernode/core/src/ciphernode.rs @@ -3,7 +3,7 @@ use crate::{ eventbus::EventBus, events::{ComputationRequested, EnclaveEvent, KeyshareCreated}, fhe::{Fhe, GenerateKeyshare}, - wrapped::SecretKeySerializer, + serializers::SecretKeySerializer, DecryptCiphertext, DecryptionRequested, DecryptionshareCreated, Get, Subscribe, }; use actix::prelude::*; diff --git a/packages/ciphernode/core/src/events.rs b/packages/ciphernode/core/src/events.rs index 5e5e8a3b..6264a266 100644 --- a/packages/ciphernode/core/src/events.rs +++ b/packages/ciphernode/core/src/events.rs @@ -215,7 +215,7 @@ impl EnclaveEvent { mod tests { use super::EnclaveEvent; use crate::{ - events::extract_enclave_event_name, wrapped::PublicKeyShareSerializer, E3id, KeyshareCreated, + events::extract_enclave_event_name, serializers::PublicKeyShareSerializer, E3id, KeyshareCreated, }; use fhe::{ bfv::{BfvParametersBuilder, SecretKey}, diff --git a/packages/ciphernode/core/src/fhe.rs b/packages/ciphernode/core/src/fhe.rs index 17c4c3f0..622a21f2 100644 --- a/packages/ciphernode/core/src/fhe.rs +++ b/packages/ciphernode/core/src/fhe.rs @@ -1,6 +1,6 @@ use crate::{ ordered_set::OrderedSet, - wrapped::{ + serializers::{ CiphertextSerializer, DecryptionShareSerializer, PlaintextSerializer, PublicKeySerializer, PublicKeyShareSerializer, SecretKeySerializer, }, diff --git a/packages/ciphernode/core/src/lib.rs b/packages/ciphernode/core/src/lib.rs index 08e00fa5..a2612a9e 100644 --- a/packages/ciphernode/core/src/lib.rs +++ b/packages/ciphernode/core/src/lib.rs @@ -13,7 +13,7 @@ mod fhe; mod logger; mod ordered_set; mod p2p; -mod wrapped; +mod serializers; // TODO: this is too permissive pub use actix::prelude::*; @@ -65,7 +65,7 @@ mod tests { events::{ComputationRequested, E3id, EnclaveEvent, KeyshareCreated, PublicKeyAggregated}, fhe::Fhe, p2p::P2p, - wrapped::{ + serializers::{ CiphertextSerializer, DecryptionShareSerializer, PublicKeySerializer, PublicKeyShareSerializer, }, DecryptionRequested, DecryptionshareCreated, ResetHistory, diff --git a/packages/ciphernode/core/src/wrapped/ciphertext.rs b/packages/ciphernode/core/src/serializers/ciphertext.rs similarity index 90% rename from packages/ciphernode/core/src/wrapped/ciphertext.rs rename to packages/ciphernode/core/src/serializers/ciphertext.rs index 0ad61ee3..271fef7b 100644 --- a/packages/ciphernode/core/src/wrapped/ciphertext.rs +++ b/packages/ciphernode/core/src/serializers/ciphertext.rs @@ -4,9 +4,6 @@ use fhe_traits::{Deserialize, DeserializeParametrized, Serialize}; use serde::Serializer; use std::sync::Arc; -/// Wrapped Ciphertext. This is wrapped to provide an inflection point -/// as we use this library elsewhere we only implement traits as we need them -/// and avoid exposing underlying structures from fhe.rs pub struct CiphertextSerializer { pub inner: Ciphertext, pub params: Arc, diff --git a/packages/ciphernode/core/src/wrapped/decryption_share.rs b/packages/ciphernode/core/src/serializers/decryption_share.rs similarity index 100% rename from packages/ciphernode/core/src/wrapped/decryption_share.rs rename to packages/ciphernode/core/src/serializers/decryption_share.rs diff --git a/packages/ciphernode/core/src/wrapped/mod.rs b/packages/ciphernode/core/src/serializers/mod.rs similarity index 100% rename from packages/ciphernode/core/src/wrapped/mod.rs rename to packages/ciphernode/core/src/serializers/mod.rs diff --git a/packages/ciphernode/core/src/wrapped/plaintext.rs b/packages/ciphernode/core/src/serializers/plaintext.rs similarity index 100% rename from packages/ciphernode/core/src/wrapped/plaintext.rs rename to packages/ciphernode/core/src/serializers/plaintext.rs diff --git a/packages/ciphernode/core/src/wrapped/public_key.rs b/packages/ciphernode/core/src/serializers/public_key.rs similarity index 92% rename from packages/ciphernode/core/src/wrapped/public_key.rs rename to packages/ciphernode/core/src/serializers/public_key.rs index 528f2422..a485334b 100644 --- a/packages/ciphernode/core/src/wrapped/public_key.rs +++ b/packages/ciphernode/core/src/serializers/public_key.rs @@ -4,9 +4,6 @@ use fhe_traits::{Deserialize, DeserializeParametrized, Serialize}; use serde::Serializer; use std::sync::Arc; -/// Wrapped PublicKey. This is wrapped to provide an inflection point -/// as we use this library elsewhere we only implement traits as we need them -/// and avoid exposing underlying structures from fhe.rs pub struct PublicKeySerializer { inner: PublicKey, params: Arc, diff --git a/packages/ciphernode/core/src/wrapped/public_key_share.rs b/packages/ciphernode/core/src/serializers/public_key_share.rs similarity index 93% rename from packages/ciphernode/core/src/wrapped/public_key_share.rs rename to packages/ciphernode/core/src/serializers/public_key_share.rs index 22f77cac..cf7a6c6d 100644 --- a/packages/ciphernode/core/src/wrapped/public_key_share.rs +++ b/packages/ciphernode/core/src/serializers/public_key_share.rs @@ -7,9 +7,6 @@ use fhe_traits::{Deserialize, Serialize}; use serde::Serializer; use std::sync::Arc; -/// Wrapped PublicKeyShare. This is wrapped to provide an inflection point -/// as we use this library elsewhere we only implement traits as we need them -/// and avoid exposing underlying structures from fhe.rs pub struct PublicKeyShareSerializer { inner: PublicKeyShare, // We need to hold copies of the params and crp in order to effectively serialize and diff --git a/packages/ciphernode/core/src/wrapped/secret_key.rs b/packages/ciphernode/core/src/serializers/secret_key.rs similarity index 78% rename from packages/ciphernode/core/src/wrapped/secret_key.rs rename to packages/ciphernode/core/src/serializers/secret_key.rs index 76c843fc..95abca76 100644 --- a/packages/ciphernode/core/src/wrapped/secret_key.rs +++ b/packages/ciphernode/core/src/serializers/secret_key.rs @@ -3,11 +3,6 @@ use fhe::bfv::{BfvParameters, SecretKey}; use fhe_traits::{Deserialize, Serialize}; use std::sync::Arc; -/// Wrapped SecretKey. This is wrapped to provide an inflection point -/// as we use this library elsewhere we only implement traits as we need them -/// and avoid exposing underlying structures from fhe.rs -// We should favor consuming patterns and avoid cloning and copying this value around in memory. -// Underlying key Zeroizes on drop pub struct SecretKeySerializer { pub inner: SecretKey, pub params: Arc, From dc3fbca11fefb798466e2ebb0b8d8fe128ae1353 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=B3=CE=BB?= Date: Mon, 2 Sep 2024 14:35:30 +1000 Subject: [PATCH 33/87] Basic decryption is working (#36) --- packages/ciphernode/core/src/ciphernode.rs | 1 - packages/ciphernode/core/src/committee.rs | 58 +++++++- packages/ciphernode/core/src/committee_key.rs | 6 +- packages/ciphernode/core/src/decryption.rs | 140 ++++++++++++++++++ packages/ciphernode/core/src/events.rs | 26 +++- packages/ciphernode/core/src/fhe.rs | 43 +++--- packages/ciphernode/core/src/lib.rs | 20 ++- .../core/src/serializers/decryption_share.rs | 67 +++++++-- .../ciphernode/core/src/serializers/mod.rs | 2 - .../core/src/serializers/plaintext.rs | 12 -- 10 files changed, 311 insertions(+), 64 deletions(-) create mode 100644 packages/ciphernode/core/src/decryption.rs delete mode 100644 packages/ciphernode/core/src/serializers/plaintext.rs diff --git a/packages/ciphernode/core/src/ciphernode.rs b/packages/ciphernode/core/src/ciphernode.rs index 8481291e..78e6bc98 100644 --- a/packages/ciphernode/core/src/ciphernode.rs +++ b/packages/ciphernode/core/src/ciphernode.rs @@ -3,7 +3,6 @@ use crate::{ eventbus::EventBus, events::{ComputationRequested, EnclaveEvent, KeyshareCreated}, fhe::{Fhe, GenerateKeyshare}, - serializers::SecretKeySerializer, DecryptCiphertext, DecryptionRequested, DecryptionshareCreated, Get, Subscribe, }; use actix::prelude::*; diff --git a/packages/ciphernode/core/src/committee.rs b/packages/ciphernode/core/src/committee.rs index b2c51580..507cb7bb 100644 --- a/packages/ciphernode/core/src/committee.rs +++ b/packages/ciphernode/core/src/committee.rs @@ -1,19 +1,30 @@ use std::collections::HashMap; -use actix::{Actor, Addr, Context, Handler}; +use actix::{Actor, Addr, Context, Handler, Message}; use crate::{ - committee_key::{CommitteeKey, Die}, + committee_key::{CommitteeKey}, + decryption::Decryption, eventbus::EventBus, events::{E3id, EnclaveEvent}, fhe::Fhe, Subscribe, }; +#[derive(Message)] +#[rtype(result = "()")] +pub struct Die; + +struct CommitteeMeta { + nodecount: usize, +} pub struct CommitteeManager { bus: Addr, fhe: Addr, + keys: HashMap>, + decryptions: HashMap>, + meta: HashMap, } impl Actor for CommitteeManager { @@ -26,6 +37,8 @@ impl CommitteeManager { bus, fhe, keys: HashMap::new(), + decryptions: HashMap::new(), + meta: HashMap::new(), } } @@ -36,6 +49,9 @@ impl CommitteeManager { addr.clone().recipient(), )); bus.do_send(Subscribe::new("KeyshareCreated", addr.clone().into())); + bus.do_send(Subscribe::new("DecryptionRequested", addr.clone().into())); + bus.do_send(Subscribe::new("DecryptionshareCreated", addr.clone().into())); + bus.do_send(Subscribe::new("DecryptionOutputPublished", addr.clone().into())); addr } } @@ -55,6 +71,12 @@ impl Handler for CommitteeManager { ) .start(); + self.meta.insert( + data.e3_id.clone(), + CommitteeMeta { + nodecount: data.nodecount.clone(), + }, + ); self.keys.insert(data.e3_id, key); } EnclaveEvent::KeyshareCreated { data, .. } => { @@ -70,10 +92,36 @@ impl Handler for CommitteeManager { key.do_send(Die); self.keys.remove(&data.e3_id); } - EnclaveEvent::DecryptionRequested { .. } => { - // TODO: launch new plaintext aggregator + EnclaveEvent::DecryptionRequested { data, .. } => { + let Some(meta) = self.meta.get(&data.e3_id) else { + // TODO: setup proper logger / telemetry + println!("E3Id not found in committee"); + return; + }; + // start up a new key + let key = Decryption::new( + self.fhe.clone(), + self.bus.clone(), + data.e3_id.clone(), + meta.nodecount.clone(), + ) + .start(); + + self.decryptions.insert(data.e3_id, key); + } + EnclaveEvent::DecryptionshareCreated { data, .. } => { + if let Some(decryption) = self.decryptions.get(&data.e3_id) { + decryption.do_send(data); + } + } + EnclaveEvent::DecryptedOutputPublished { data, .. } => { + let Some(addr) = self.decryptions.get(&data.e3_id) else { + return; + }; + + addr.do_send(Die); + self.decryptions.remove(&data.e3_id); } - _ => (), } } } diff --git a/packages/ciphernode/core/src/committee_key.rs b/packages/ciphernode/core/src/committee_key.rs index b09b6c6e..aa31158d 100644 --- a/packages/ciphernode/core/src/committee_key.rs +++ b/packages/ciphernode/core/src/committee_key.rs @@ -2,7 +2,7 @@ use crate::{ eventbus::EventBus, events::{E3id, EnclaveEvent, KeyshareCreated, PublicKeyAggregated}, fhe::{Fhe, GetAggregatePublicKey}, - ordered_set::OrderedSet, + ordered_set::OrderedSet, Die, }; use actix::prelude::*; use anyhow::{anyhow, Result}; @@ -28,10 +28,6 @@ struct ComputeAggregate { pub keyshares: OrderedSet>, } -#[derive(Message)] -#[rtype(result = "()")] -pub struct Die; - pub struct CommitteeKey { fhe: Addr, bus: Addr, diff --git a/packages/ciphernode/core/src/decryption.rs b/packages/ciphernode/core/src/decryption.rs new file mode 100644 index 00000000..ac2fa3a1 --- /dev/null +++ b/packages/ciphernode/core/src/decryption.rs @@ -0,0 +1,140 @@ +use crate::{ + ordered_set::OrderedSet, DecryptedOutputPublished, DecryptionshareCreated, Die, E3id, EnclaveEvent, EventBus, Fhe, GetAggregatePlaintext +}; +use actix::prelude::*; +use anyhow::{anyhow, Result}; + +#[derive(Debug, Clone)] +pub enum DecryptionState { + Collecting { + nodecount: usize, + shares: OrderedSet>, + }, + Computing { + shares: OrderedSet>, + }, + Complete { + decrypted: Vec, + shares: OrderedSet>, + }, +} + +#[derive(Message)] +#[rtype(result = "anyhow::Result<()>")] +struct ComputeAggregate { + pub shares: OrderedSet>, +} + +pub struct Decryption { + fhe: Addr, + bus: Addr, + e3_id: E3id, + state: DecryptionState, +} + +impl Decryption { + pub fn new(fhe: Addr, bus: Addr, e3_id: E3id, nodecount: usize) -> Self { + Decryption { + fhe, + bus, + e3_id, + state: DecryptionState::Collecting { + nodecount, + shares: OrderedSet::new(), + }, + } + } + + pub fn add_share(&mut self, share: Vec) -> Result { + let DecryptionState::Collecting { nodecount, shares } = &mut self.state else { + return Err(anyhow::anyhow!("Can only add share in Collecting state")); + }; + + shares.insert(share); + if shares.len() == *nodecount { + return Ok(DecryptionState::Computing { + shares: shares.clone(), + }); + } + + Ok(self.state.clone()) + } + + pub fn set_decryption(&mut self, decrypted: Vec) -> Result { + let DecryptionState::Computing { shares } = &mut self.state else { + return Ok(self.state.clone()); + }; + + let shares = shares.to_owned(); + + Ok(DecryptionState::Complete { decrypted, shares }) + } +} + +impl Actor for Decryption { + type Context = Context; +} + +impl Handler for Decryption { + type Result = Result<()>; + fn handle(&mut self, event: DecryptionshareCreated, ctx: &mut Self::Context) -> Self::Result { + if event.e3_id != self.e3_id { + return Err(anyhow!( + "Wrong e3_id sent to aggregator. This should not happen." + )); + } + let DecryptionState::Collecting { .. } = self.state else { + return Err(anyhow!( + "Aggregator has been closed for collecting keyshares." + )); + }; + + // add the keyshare and + self.state = self.add_share(event.decryption_share)?; + + // Check the state and if it has changed to the computing + if let DecryptionState::Computing { shares } = &self.state { + ctx.address().do_send(ComputeAggregate { + shares: shares.clone(), + }) + } + + Ok(()) + } +} + +impl Handler for Decryption { + type Result = ResponseActFuture>; + fn handle(&mut self, msg: ComputeAggregate, ctx: &mut Self::Context) -> Self::Result { + Box::pin( + self.fhe + .send(GetAggregatePlaintext { + decryptions: msg.shares.clone(), + }) + .into_actor(self) + .map(|res, act, _| { + let decrypted_output = res??; + // Update the local state + act.state = act.set_decryption(decrypted_output.clone())?; + + // Dispatch the PublicKeyAggregated event + let event = EnclaveEvent::from(DecryptedOutputPublished { + decrypted_output, + e3_id: act.e3_id.clone(), + }); + + act.bus.do_send(event); + + Ok(()) + }), + ) + } +} + +impl Handler for Decryption { + type Result = (); + + fn handle(&mut self, _msg: Die, ctx: &mut Context) { + ctx.stop(); + } +} diff --git a/packages/ciphernode/core/src/events.rs b/packages/ciphernode/core/src/events.rs index 6264a266..600cd926 100644 --- a/packages/ciphernode/core/src/events.rs +++ b/packages/ciphernode/core/src/events.rs @@ -70,7 +70,13 @@ pub enum EnclaveEvent { DecryptionshareCreated { id: EventId, data: DecryptionshareCreated, - }, // CommitteeSelected, + }, +DecryptedOutputPublished { + id: EventId, + data: DecryptedOutputPublished + } + + // CommitteeSelected, // OutputDecrypted, // CiphernodeRegistered, // CiphernodeDeregistered, @@ -98,6 +104,7 @@ impl From for EventId { EnclaveEvent::PublicKeyAggregated { id, .. } => id, EnclaveEvent::DecryptionRequested { id, .. } => id, EnclaveEvent::DecryptionshareCreated { id, .. } => id, + EnclaveEvent::DecryptedOutputPublished { id, .. } => id, } } } @@ -147,6 +154,14 @@ impl From for EnclaveEvent { } } +impl From for EnclaveEvent { + fn from(data: DecryptedOutputPublished) -> Self { + EnclaveEvent::DecryptedOutputPublished { + id: EventId::from(data.clone()), + data: data.clone(), + } + } +} impl fmt::Display for EnclaveEvent { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str(&format!("{}({})", self.event_type(), self.get_id())) @@ -191,7 +206,14 @@ pub struct ComputationRequested { #[rtype(result = "()")] pub struct DecryptionRequested { pub e3_id: E3id, - pub ciphertext: Vec, + pub ciphertext: Vec +} + +#[derive(Message, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[rtype(result = "()")] +pub struct DecryptedOutputPublished { + pub e3_id: E3id, + pub decrypted_output: Vec } fn extract_enclave_event_name(s: &str) -> &str { diff --git a/packages/ciphernode/core/src/fhe.rs b/packages/ciphernode/core/src/fhe.rs index 622a21f2..18a526be 100644 --- a/packages/ciphernode/core/src/fhe.rs +++ b/packages/ciphernode/core/src/fhe.rs @@ -1,16 +1,17 @@ use crate::{ ordered_set::OrderedSet, serializers::{ - CiphertextSerializer, DecryptionShareSerializer, PlaintextSerializer, PublicKeySerializer, + CiphertextSerializer, DecryptionShareSerializer, PublicKeySerializer, PublicKeyShareSerializer, SecretKeySerializer, }, }; use actix::{Actor, Context, Handler, Message}; use anyhow::*; use fhe::{ - bfv::{BfvParameters, BfvParametersBuilder, Ciphertext, Plaintext, PublicKey, SecretKey}, + bfv::{BfvParameters, BfvParametersBuilder, Encoding, Plaintext, PublicKey, SecretKey}, mbfv::{AggregateIter, CommonRandomPoly, DecryptionShare, PublicKeyShare}, }; +use fhe_traits::FheDecoder; use rand::SeedableRng; use rand_chacha::ChaCha20Rng; use std::{hash::Hash, sync::Arc}; @@ -28,7 +29,7 @@ pub struct GetAggregatePublicKey { } #[derive(Message, Clone, Debug, PartialEq, Eq)] -#[rtype(result = "Result<(PlaintextSerializer)>")] +#[rtype(result = "Result<(Vec)>")] pub struct GetAggregatePlaintext { pub decryptions: OrderedSet>, } @@ -126,18 +127,24 @@ impl Handler for Fhe { } } -// TODO: add this once we have decryption aggregation ready -// impl Handler for Fhe { -// type Result = Result; -// fn handle(&mut self, msg: GetAggregatePlaintext, _: &mut Self::Context) -> Self::Result { -// let plaintext: Plaintext = msg -// .decryptions -// .iter() -// .map(|k| k.clone().try_inner()) -// .collect::>>()? // NOTE: not optimal -// .into_iter() -// .aggregate()?; -// -// Ok(PlaintextSerializer::to_bytes(plaintext)) -// } -// } +impl Handler for Fhe { + type Result = Result>; + fn handle(&mut self, msg: GetAggregatePlaintext, _: &mut Self::Context) -> Self::Result { + let plaintext: Plaintext = msg + .decryptions + .iter() + .map(|k| DecryptionShareSerializer::from_bytes(k)) + .collect::>>()? + .into_iter() + .aggregate()?; + + // XXX: how do we know what the expected output of the plaintext is in order to decrypt + // here for serialization? + // This would be dependent on the computation that is running. + // For now assuming testcase of Vec + // This could be determined based on the "program" config + let decoded = Vec::::try_decode(&plaintext, Encoding::poly())?; + let decoded = &decoded[0..2]; // TODO: this will be computation dependent + Ok(bincode::serialize(&decoded)?) + } +} diff --git a/packages/ciphernode/core/src/lib.rs b/packages/ciphernode/core/src/lib.rs index a2612a9e..1fe52611 100644 --- a/packages/ciphernode/core/src/lib.rs +++ b/packages/ciphernode/core/src/lib.rs @@ -6,6 +6,7 @@ mod ciphernode; mod committee; mod committee_key; mod data; +mod decryption; mod enclave_contract; mod eventbus; mod events; @@ -66,9 +67,10 @@ mod tests { fhe::Fhe, p2p::P2p, serializers::{ - CiphertextSerializer, DecryptionShareSerializer, PublicKeySerializer, PublicKeyShareSerializer, + CiphertextSerializer, DecryptionShareSerializer, PublicKeySerializer, + PublicKeyShareSerializer, }, - DecryptionRequested, DecryptionshareCreated, ResetHistory, + DecryptedOutputPublished, DecryptionRequested, DecryptionshareCreated, ResetHistory, }; use actix::prelude::*; use anyhow::*; @@ -229,10 +231,15 @@ mod tests { // Aggregate decryption bus.send(ResetHistory).await?; - let yes = 12376213u64; + // 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 yes = 1234u64; let no = 873827u64; - let pt = Plaintext::try_encode(&vec![yes, no], Encoding::poly(), ¶ms)?; + let raw_plaintext = vec![yes, no]; + let expected_raw_plaintext = bincode::serialize(&raw_plaintext)?; + let pt = Plaintext::try_encode(&raw_plaintext, Encoding::poly(), ¶ms)?; let ciphertext = pubkey.try_encrypt(&pt, &mut ChaCha20Rng::seed_from_u64(42))?; @@ -280,7 +287,10 @@ mod tests { decryption_share: ds3.clone(), e3_id: e3_id.clone(), }), - // TODO: aggregate plaintext + EnclaveEvent::from(DecryptedOutputPublished { + e3_id: e3_id.clone(), + decrypted_output: expected_raw_plaintext.clone() + }) ] ); diff --git a/packages/ciphernode/core/src/serializers/decryption_share.rs b/packages/ciphernode/core/src/serializers/decryption_share.rs index 9b384ddd..bc99d12e 100644 --- a/packages/ciphernode/core/src/serializers/decryption_share.rs +++ b/packages/ciphernode/core/src/serializers/decryption_share.rs @@ -3,14 +3,14 @@ use fhe::{ bfv::{BfvParameters, Ciphertext}, mbfv::DecryptionShare, }; -use fhe_traits::Serialize; +use fhe_traits::{Deserialize, DeserializeParametrized, Serialize}; +use serde::Serializer; use std::sync::Arc; -#[derive(serde::Serialize, serde::Deserialize)] pub struct DecryptionShareSerializer { - inner: Vec, - params: Vec, - ct: Vec, + inner: DecryptionShare, + params: Arc, + ct: Arc, } impl DecryptionShareSerializer { @@ -19,15 +19,54 @@ impl DecryptionShareSerializer { params: Arc, ct: Arc, ) -> Result> { - // Have to serialize immediately in order to clone etc. - let inner_bytes = inner.to_bytes(); - let params_bytes = params.to_bytes(); - let ct_bytes = ct.to_bytes(); - let value = Self { - inner: inner_bytes, - params: params_bytes, - ct: ct_bytes, - }; + let value = Self { inner, params, ct }; Ok(bincode::serialize(&value)?) } + + pub fn from_bytes(bytes: &[u8]) -> Result { + let ds: DecryptionShareSerializer = bincode::deserialize(&bytes)?; + Ok(ds.inner) + } +} + +/// Deserialize from serde to PublicKeySerializer +impl<'de> serde::Deserialize<'de> for DecryptionShareSerializer { + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + // Intermediate struct of bytes for deserialization + #[derive(serde::Deserialize)] + struct DecryptionShareBytes { + par: Vec, + bytes: Vec, + ct: Vec, + } + let DecryptionShareBytes { par, bytes, ct } = + DecryptionShareBytes::deserialize(deserializer)?; + let params = Arc::new(BfvParameters::try_deserialize(&par).unwrap()); // TODO: fix errors + let ct = Arc::new(Ciphertext::from_bytes(&ct, ¶ms).unwrap()); // TODO: fix errors + let inner = DecryptionShare::deserialize(&bytes, ¶ms, ct.clone()) + .map_err(serde::de::Error::custom)?; + // TODO: how do we create an invariant that the deserialized params match the global params? + std::result::Result::Ok(Self { inner, params, ct }) + } +} +/// Serialize to serde bytes representation +impl serde::Serialize for DecryptionShareSerializer { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + use serde::ser::SerializeStruct; + let bytes = self.inner.to_bytes(); + let par_bytes = self.params.to_bytes(); + let ct_bytes = self.ct.to_bytes(); + // Intermediate struct of bytes + let mut state = serializer.serialize_struct("DecryptionShareBytes", 2)?; + state.serialize_field("par", &par_bytes)?; + state.serialize_field("bytes", &bytes)?; + state.serialize_field("bytes", &ct_bytes)?; + state.end() + } } diff --git a/packages/ciphernode/core/src/serializers/mod.rs b/packages/ciphernode/core/src/serializers/mod.rs index 94757206..e5c15eeb 100644 --- a/packages/ciphernode/core/src/serializers/mod.rs +++ b/packages/ciphernode/core/src/serializers/mod.rs @@ -1,13 +1,11 @@ mod ciphertext; mod decryption_share; -mod plaintext; mod public_key; mod public_key_share; mod secret_key; pub use ciphertext::*; pub use decryption_share::*; -pub use plaintext::*; pub use public_key::*; pub use public_key_share::*; pub use secret_key::*; diff --git a/packages/ciphernode/core/src/serializers/plaintext.rs b/packages/ciphernode/core/src/serializers/plaintext.rs deleted file mode 100644 index 6e9ffbe6..00000000 --- a/packages/ciphernode/core/src/serializers/plaintext.rs +++ /dev/null @@ -1,12 +0,0 @@ -use fhe::bfv::Plaintext; - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct PlaintextSerializer { - pub inner: Plaintext, -} - -impl PlaintextSerializer { - pub fn to_bytes(inner: Plaintext /* params: Arc */) -> Self { - Self { inner } - } -} From 90627768f37bd210ea9d565a76a93efb83fa9103 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=B3=CE=BB?= Date: Tue, 3 Sep 2024 14:53:36 +1000 Subject: [PATCH 34/87] Rename events (#38) * ComputationRequested->CommitteeRequested * DecryptionRequested->CiphertextOutputPublished --- packages/ciphernode/core/src/ciphernode.rs | 44 ++++++++++--------- packages/ciphernode/core/src/committee.rs | 8 ++-- packages/ciphernode/core/src/events.rs | 30 ++++++------- packages/ciphernode/core/src/lib.rs | 18 ++++---- .../ciphernode/enclave_node/src/bin/cmd.rs | 4 +- 5 files changed, 53 insertions(+), 51 deletions(-) diff --git a/packages/ciphernode/core/src/ciphernode.rs b/packages/ciphernode/core/src/ciphernode.rs index 78e6bc98..4c09fb22 100644 --- a/packages/ciphernode/core/src/ciphernode.rs +++ b/packages/ciphernode/core/src/ciphernode.rs @@ -1,9 +1,9 @@ use crate::{ data::{Data, Insert}, eventbus::EventBus, - events::{ComputationRequested, EnclaveEvent, KeyshareCreated}, + events::{CommitteeRequested, EnclaveEvent, KeyshareCreated}, fhe::{Fhe, GenerateKeyshare}, - DecryptCiphertext, DecryptionRequested, DecryptionshareCreated, Get, Subscribe, + CiphertextOutputPublished, DecryptCiphertext, DecryptionshareCreated, Get, Subscribe, }; use actix::prelude::*; use anyhow::Result; @@ -26,10 +26,13 @@ impl Ciphernode { pub async fn attach(bus: Addr, fhe: Addr, data: Addr) -> Addr { let node = Ciphernode::new(bus.clone(), fhe, data).start(); let _ = bus - .send(Subscribe::new("ComputationRequested", node.clone().into())) + .send(Subscribe::new("CommitteeRequested", node.clone().into())) .await; let _ = bus - .send(Subscribe::new("DecryptionRequested", node.clone().into())) + .send(Subscribe::new( + "CiphertextOutputPublished", + node.clone().into(), + )) .await; node } @@ -40,32 +43,28 @@ impl Handler for Ciphernode { fn handle(&mut self, event: EnclaveEvent, ctx: &mut Context) -> Self::Result { match event { - EnclaveEvent::ComputationRequested { data, .. } => ctx.address().do_send(data), - EnclaveEvent::DecryptionRequested { data, .. } => ctx.address().do_send(data), + EnclaveEvent::CommitteeRequested { data, .. } => ctx.address().do_send(data), + EnclaveEvent::CiphertextOutputPublished { data, .. } => ctx.address().do_send(data), _ => (), } } } -impl Handler for Ciphernode { +impl Handler for Ciphernode { type Result = ResponseFuture<()>; - fn handle(&mut self, event: ComputationRequested, _: &mut Context) -> Self::Result { + fn handle(&mut self, event: CommitteeRequested, _: &mut Context) -> Self::Result { let fhe = self.fhe.clone(); let data = self.data.clone(); let bus = self.bus.clone(); - Box::pin(async { - on_computation_requested(fhe, data, bus, event) - .await - .unwrap() - }) + Box::pin(async { on_committee_requested(fhe, data, bus, event).await.unwrap() }) } } -impl Handler for Ciphernode { +impl Handler for Ciphernode { type Result = ResponseFuture<()>; - fn handle(&mut self, event: DecryptionRequested, _: &mut Context) -> Self::Result { + fn handle(&mut self, event: CiphertextOutputPublished, _: &mut Context) -> Self::Result { let fhe = self.fhe.clone(); let data = self.data.clone(); let bus = self.bus.clone(); @@ -77,13 +76,13 @@ impl Handler for Ciphernode { } } -async fn on_computation_requested( +async fn on_committee_requested( fhe: Addr, data: Addr, bus: Addr, - event: ComputationRequested, + event: CommitteeRequested, ) -> Result<()> { - let ComputationRequested { e3_id, .. } = event; + let CommitteeRequested { e3_id, .. } = event; // generate keyshare let (sk, pubkey) = fhe.send(GenerateKeyshare {}).await??; @@ -108,9 +107,12 @@ async fn on_decryption_requested( fhe: Addr, data: Addr, bus: Addr, - event: DecryptionRequested, + event: CiphertextOutputPublished, ) -> Result<()> { - let DecryptionRequested { e3_id, ciphertext } = event; + let CiphertextOutputPublished { + e3_id, + ciphertext_output, + } = event; // get secret key by id from data let Some(unsafe_secret) = data.send(Get(format!("{}/sk", e3_id).into())).await? else { @@ -119,7 +121,7 @@ async fn on_decryption_requested( let decryption_share = fhe .send(DecryptCiphertext { - ciphertext, + ciphertext: ciphertext_output, unsafe_secret, }) .await??; diff --git a/packages/ciphernode/core/src/committee.rs b/packages/ciphernode/core/src/committee.rs index 507cb7bb..807402ba 100644 --- a/packages/ciphernode/core/src/committee.rs +++ b/packages/ciphernode/core/src/committee.rs @@ -45,11 +45,11 @@ impl CommitteeManager { pub fn attach(bus: Addr, fhe: Addr) -> Addr { let addr = CommitteeManager::new(bus.clone(), fhe).start(); bus.do_send(Subscribe::new( - "ComputationRequested", + "CommitteeRequested", addr.clone().recipient(), )); bus.do_send(Subscribe::new("KeyshareCreated", addr.clone().into())); - bus.do_send(Subscribe::new("DecryptionRequested", addr.clone().into())); + bus.do_send(Subscribe::new("CiphertextOutputPublished", addr.clone().into())); bus.do_send(Subscribe::new("DecryptionshareCreated", addr.clone().into())); bus.do_send(Subscribe::new("DecryptionOutputPublished", addr.clone().into())); addr @@ -61,7 +61,7 @@ impl Handler for CommitteeManager { fn handle(&mut self, event: EnclaveEvent, _ctx: &mut Self::Context) -> Self::Result { match event { - EnclaveEvent::ComputationRequested { data, .. } => { + EnclaveEvent::CommitteeRequested { data, .. } => { // start up a new key let key = CommitteeKey::new( self.fhe.clone(), @@ -92,7 +92,7 @@ impl Handler for CommitteeManager { key.do_send(Die); self.keys.remove(&data.e3_id); } - EnclaveEvent::DecryptionRequested { data, .. } => { + EnclaveEvent::CiphertextOutputPublished { data, .. } => { let Some(meta) = self.meta.get(&data.e3_id) else { // TODO: setup proper logger / telemetry println!("E3Id not found in committee"); diff --git a/packages/ciphernode/core/src/events.rs b/packages/ciphernode/core/src/events.rs index 600cd926..d1949a37 100644 --- a/packages/ciphernode/core/src/events.rs +++ b/packages/ciphernode/core/src/events.rs @@ -55,17 +55,17 @@ pub enum EnclaveEvent { id: EventId, data: KeyshareCreated, }, - ComputationRequested { + CommitteeRequested { id: EventId, - data: ComputationRequested, + data: CommitteeRequested, }, PublicKeyAggregated { id: EventId, data: PublicKeyAggregated, }, - DecryptionRequested { + CiphertextOutputPublished { id: EventId, - data: DecryptionRequested, + data: CiphertextOutputPublished, }, DecryptionshareCreated { id: EventId, @@ -100,9 +100,9 @@ impl From for EventId { fn from(value: EnclaveEvent) -> Self { match value { EnclaveEvent::KeyshareCreated { id, .. } => id, - EnclaveEvent::ComputationRequested { id, .. } => id, + EnclaveEvent::CommitteeRequested { id, .. } => id, EnclaveEvent::PublicKeyAggregated { id, .. } => id, - EnclaveEvent::DecryptionRequested { id, .. } => id, + EnclaveEvent::CiphertextOutputPublished { id, .. } => id, EnclaveEvent::DecryptionshareCreated { id, .. } => id, EnclaveEvent::DecryptedOutputPublished { id, .. } => id, } @@ -118,9 +118,9 @@ impl From for EnclaveEvent { } } -impl From for EnclaveEvent { - fn from(data: ComputationRequested) -> Self { - EnclaveEvent::ComputationRequested { +impl From for EnclaveEvent { + fn from(data: CommitteeRequested) -> Self { + EnclaveEvent::CommitteeRequested { id: EventId::from(data.clone()), data: data.clone(), } @@ -136,9 +136,9 @@ impl From for EnclaveEvent { } } -impl From for EnclaveEvent { - fn from(data: DecryptionRequested) -> Self { - EnclaveEvent::DecryptionRequested { +impl From for EnclaveEvent { + fn from(data: CiphertextOutputPublished) -> Self { + EnclaveEvent::CiphertextOutputPublished { id: EventId::from(data.clone()), data: data.clone(), } @@ -191,7 +191,7 @@ pub struct PublicKeyAggregated { #[derive(Message, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[rtype(result = "()")] -pub struct ComputationRequested { +pub struct CommitteeRequested { pub e3_id: E3id, pub nodecount: usize, pub threshold: usize, @@ -204,9 +204,9 @@ pub struct ComputationRequested { #[derive(Message, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[rtype(result = "()")] -pub struct DecryptionRequested { +pub struct CiphertextOutputPublished { pub e3_id: E3id, - pub ciphertext: Vec + pub ciphertext_output: Vec } #[derive(Message, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] diff --git a/packages/ciphernode/core/src/lib.rs b/packages/ciphernode/core/src/lib.rs index 1fe52611..b24c285d 100644 --- a/packages/ciphernode/core/src/lib.rs +++ b/packages/ciphernode/core/src/lib.rs @@ -63,14 +63,14 @@ mod tests { committee::CommitteeManager, data::Data, eventbus::{EventBus, GetHistory}, - events::{ComputationRequested, E3id, EnclaveEvent, KeyshareCreated, PublicKeyAggregated}, + events::{CommitteeRequested, E3id, EnclaveEvent, KeyshareCreated, PublicKeyAggregated}, fhe::Fhe, p2p::P2p, serializers::{ CiphertextSerializer, DecryptionShareSerializer, PublicKeySerializer, PublicKeyShareSerializer, }, - DecryptedOutputPublished, DecryptionRequested, DecryptionshareCreated, ResetHistory, + DecryptedOutputPublished, CiphertextOutputPublished, DecryptionshareCreated, ResetHistory, }; use actix::prelude::*; use anyhow::*; @@ -166,7 +166,7 @@ mod tests { let e3_id = E3id::new("1234"); - let event = EnclaveEvent::from(ComputationRequested { + let event = EnclaveEvent::from(CommitteeRequested { e3_id: e3_id.clone(), nodecount: 3, threshold: 123, @@ -203,7 +203,7 @@ mod tests { assert_eq!( history, vec![ - EnclaveEvent::from(ComputationRequested { + EnclaveEvent::from(CommitteeRequested { e3_id: e3_id.clone(), nodecount: 3, threshold: 123, @@ -243,8 +243,8 @@ mod tests { let ciphertext = pubkey.try_encrypt(&pt, &mut ChaCha20Rng::seed_from_u64(42))?; - let event = EnclaveEvent::from(DecryptionRequested { - ciphertext: CiphertextSerializer::to_bytes(ciphertext.clone(), params.clone())?, + let event = EnclaveEvent::from(CiphertextOutputPublished { + ciphertext_output: CiphertextSerializer::to_bytes(ciphertext.clone(), params.clone())?, e3_id: e3_id.clone(), }); @@ -316,14 +316,14 @@ mod tests { } }); - let evt_1 = EnclaveEvent::from(ComputationRequested { + let evt_1 = EnclaveEvent::from(CommitteeRequested { e3_id: E3id::new("1234"), nodecount: 3, threshold: 123, sortition_seed: 123, }); - let evt_2 = EnclaveEvent::from(ComputationRequested { + let evt_2 = EnclaveEvent::from(CommitteeRequested { e3_id: E3id::new("1235"), nodecount: 3, threshold: 123, @@ -362,7 +362,7 @@ mod tests { P2p::spawn_and_listen(bus.clone(), tx.clone(), rx); // Capture messages from output on msgs vec - let event = EnclaveEvent::from(ComputationRequested { + let event = EnclaveEvent::from(CommitteeRequested { e3_id: E3id::new("1235"), nodecount: 3, threshold: 123, diff --git a/packages/ciphernode/enclave_node/src/bin/cmd.rs b/packages/ciphernode/enclave_node/src/bin/cmd.rs index 4ac97462..9984408f 100644 --- a/packages/ciphernode/enclave_node/src/bin/cmd.rs +++ b/packages/ciphernode/enclave_node/src/bin/cmd.rs @@ -1,7 +1,7 @@ use std::error::Error; use enclave_core::Actor; -use enclave_core::ComputationRequested; +use enclave_core::CommitteeRequested; use enclave_core::E3id; use enclave_core::EnclaveEvent; use enclave_core::EventBus; @@ -22,7 +22,7 @@ async fn main() -> Result<(), Box> { match line.as_str() { "test" => { id += 1; - bus.do_send(EnclaveEvent::from(ComputationRequested { + bus.do_send(EnclaveEvent::from(CommitteeRequested { e3_id: E3id::from(id), nodecount: 3, threshold: 3, From 1c4418ddfb2a74e6bd7bd61c0716593e51d53746 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=B3=CE=BB?= Date: Sun, 8 Sep 2024 11:49:31 +1000 Subject: [PATCH 35/87] Decryption -> PlaintextAggregator & CommitteeKey -> PublicKeyAggregator (#46) --- packages/ciphernode/core/src/committee.rs | 29 +++++++++----- packages/ciphernode/core/src/events.rs | 14 +++---- packages/ciphernode/core/src/lib.rs | 12 +++--- ...{decryption.rs => plaintext_aggregator.rs} | 40 +++++++++---------- ...mmittee_key.rs => publickey_aggregator.rs} | 36 ++++++++--------- 5 files changed, 70 insertions(+), 61 deletions(-) rename packages/ciphernode/core/src/{decryption.rs => plaintext_aggregator.rs} (70%) rename packages/ciphernode/core/src/{committee_key.rs => publickey_aggregator.rs} (82%) diff --git a/packages/ciphernode/core/src/committee.rs b/packages/ciphernode/core/src/committee.rs index 807402ba..db0a3e25 100644 --- a/packages/ciphernode/core/src/committee.rs +++ b/packages/ciphernode/core/src/committee.rs @@ -3,11 +3,11 @@ use std::collections::HashMap; use actix::{Actor, Addr, Context, Handler, Message}; use crate::{ - committee_key::{CommitteeKey}, - decryption::Decryption, + plaintext_aggregator::PlaintextAggregator, eventbus::EventBus, events::{E3id, EnclaveEvent}, fhe::Fhe, + publickey_aggregator::PublicKeyAggregator, Subscribe, }; @@ -22,8 +22,8 @@ pub struct CommitteeManager { bus: Addr, fhe: Addr, - keys: HashMap>, - decryptions: HashMap>, + keys: HashMap>, + decryptions: HashMap>, meta: HashMap, } @@ -49,9 +49,18 @@ impl CommitteeManager { addr.clone().recipient(), )); bus.do_send(Subscribe::new("KeyshareCreated", addr.clone().into())); - bus.do_send(Subscribe::new("CiphertextOutputPublished", addr.clone().into())); - bus.do_send(Subscribe::new("DecryptionshareCreated", addr.clone().into())); - bus.do_send(Subscribe::new("DecryptionOutputPublished", addr.clone().into())); + bus.do_send(Subscribe::new( + "CiphertextOutputPublished", + addr.clone().into(), + )); + bus.do_send(Subscribe::new( + "DecryptionshareCreated", + addr.clone().into(), + )); + bus.do_send(Subscribe::new( + "PlaintextAggregated", + addr.clone().into(), + )); addr } } @@ -63,7 +72,7 @@ impl Handler for CommitteeManager { match event { EnclaveEvent::CommitteeRequested { data, .. } => { // start up a new key - let key = CommitteeKey::new( + let key = PublicKeyAggregator::new( self.fhe.clone(), self.bus.clone(), data.e3_id.clone(), @@ -99,7 +108,7 @@ impl Handler for CommitteeManager { return; }; // start up a new key - let key = Decryption::new( + let key = PlaintextAggregator::new( self.fhe.clone(), self.bus.clone(), data.e3_id.clone(), @@ -114,7 +123,7 @@ impl Handler for CommitteeManager { decryption.do_send(data); } } - EnclaveEvent::DecryptedOutputPublished { data, .. } => { + EnclaveEvent::PlaintextAggregated { data, .. } => { let Some(addr) = self.decryptions.get(&data.e3_id) else { return; }; diff --git a/packages/ciphernode/core/src/events.rs b/packages/ciphernode/core/src/events.rs index d1949a37..9b95c310 100644 --- a/packages/ciphernode/core/src/events.rs +++ b/packages/ciphernode/core/src/events.rs @@ -71,9 +71,9 @@ pub enum EnclaveEvent { id: EventId, data: DecryptionshareCreated, }, -DecryptedOutputPublished { +PlaintextAggregated { id: EventId, - data: DecryptedOutputPublished + data: PlaintextAggregated } // CommitteeSelected, @@ -104,7 +104,7 @@ impl From for EventId { EnclaveEvent::PublicKeyAggregated { id, .. } => id, EnclaveEvent::CiphertextOutputPublished { id, .. } => id, EnclaveEvent::DecryptionshareCreated { id, .. } => id, - EnclaveEvent::DecryptedOutputPublished { id, .. } => id, + EnclaveEvent::PlaintextAggregated { id, .. } => id, } } } @@ -154,9 +154,9 @@ impl From for EnclaveEvent { } } -impl From for EnclaveEvent { - fn from(data: DecryptedOutputPublished) -> Self { - EnclaveEvent::DecryptedOutputPublished { +impl From for EnclaveEvent { + fn from(data: PlaintextAggregated) -> Self { + EnclaveEvent::PlaintextAggregated { id: EventId::from(data.clone()), data: data.clone(), } @@ -211,7 +211,7 @@ pub struct CiphertextOutputPublished { #[derive(Message, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[rtype(result = "()")] -pub struct DecryptedOutputPublished { +pub struct PlaintextAggregated { pub e3_id: E3id, pub decrypted_output: Vec } diff --git a/packages/ciphernode/core/src/lib.rs b/packages/ciphernode/core/src/lib.rs index b24c285d..2ded47ad 100644 --- a/packages/ciphernode/core/src/lib.rs +++ b/packages/ciphernode/core/src/lib.rs @@ -4,9 +4,9 @@ mod ciphernode; mod committee; -mod committee_key; +mod publickey_aggregator; mod data; -mod decryption; +mod plaintext_aggregator; mod enclave_contract; mod eventbus; mod events; @@ -20,7 +20,7 @@ mod serializers; pub use actix::prelude::*; pub use ciphernode::*; pub use committee::*; -pub use committee_key::*; +pub use publickey_aggregator::*; pub use data::*; pub use eventbus::*; pub use events::*; @@ -31,7 +31,7 @@ pub use p2p::*; pub use actix::prelude::*; pub use ciphernode::*; pub use committee::*; -pub use committee_key::*; +pub use publickey_aggregator::*; pub use data::*; pub use eventbus::*; pub use events::*; @@ -70,7 +70,7 @@ mod tests { CiphertextSerializer, DecryptionShareSerializer, PublicKeySerializer, PublicKeyShareSerializer, }, - DecryptedOutputPublished, CiphertextOutputPublished, DecryptionshareCreated, ResetHistory, + PlaintextAggregated, CiphertextOutputPublished, DecryptionshareCreated, ResetHistory, }; use actix::prelude::*; use anyhow::*; @@ -287,7 +287,7 @@ mod tests { decryption_share: ds3.clone(), e3_id: e3_id.clone(), }), - EnclaveEvent::from(DecryptedOutputPublished { + EnclaveEvent::from(PlaintextAggregated { e3_id: e3_id.clone(), decrypted_output: expected_raw_plaintext.clone() }) diff --git a/packages/ciphernode/core/src/decryption.rs b/packages/ciphernode/core/src/plaintext_aggregator.rs similarity index 70% rename from packages/ciphernode/core/src/decryption.rs rename to packages/ciphernode/core/src/plaintext_aggregator.rs index ac2fa3a1..fd142550 100644 --- a/packages/ciphernode/core/src/decryption.rs +++ b/packages/ciphernode/core/src/plaintext_aggregator.rs @@ -1,11 +1,11 @@ use crate::{ - ordered_set::OrderedSet, DecryptedOutputPublished, DecryptionshareCreated, Die, E3id, EnclaveEvent, EventBus, Fhe, GetAggregatePlaintext + ordered_set::OrderedSet, PlaintextAggregated, DecryptionshareCreated, Die, E3id, EnclaveEvent, EventBus, Fhe, GetAggregatePlaintext }; use actix::prelude::*; use anyhow::{anyhow, Result}; #[derive(Debug, Clone)] -pub enum DecryptionState { +pub enum PlaintextAggregatorState { Collecting { nodecount: usize, shares: OrderedSet>, @@ -25,34 +25,34 @@ struct ComputeAggregate { pub shares: OrderedSet>, } -pub struct Decryption { +pub struct PlaintextAggregator { fhe: Addr, bus: Addr, e3_id: E3id, - state: DecryptionState, + state: PlaintextAggregatorState, } -impl Decryption { +impl PlaintextAggregator { pub fn new(fhe: Addr, bus: Addr, e3_id: E3id, nodecount: usize) -> Self { - Decryption { + PlaintextAggregator { fhe, bus, e3_id, - state: DecryptionState::Collecting { + state: PlaintextAggregatorState::Collecting { nodecount, shares: OrderedSet::new(), }, } } - pub fn add_share(&mut self, share: Vec) -> Result { - let DecryptionState::Collecting { nodecount, shares } = &mut self.state else { + pub fn add_share(&mut self, share: Vec) -> Result { + let PlaintextAggregatorState::Collecting { nodecount, shares } = &mut self.state else { return Err(anyhow::anyhow!("Can only add share in Collecting state")); }; shares.insert(share); if shares.len() == *nodecount { - return Ok(DecryptionState::Computing { + return Ok(PlaintextAggregatorState::Computing { shares: shares.clone(), }); } @@ -60,22 +60,22 @@ impl Decryption { Ok(self.state.clone()) } - pub fn set_decryption(&mut self, decrypted: Vec) -> Result { - let DecryptionState::Computing { shares } = &mut self.state else { + pub fn set_decryption(&mut self, decrypted: Vec) -> Result { + let PlaintextAggregatorState::Computing { shares } = &mut self.state else { return Ok(self.state.clone()); }; let shares = shares.to_owned(); - Ok(DecryptionState::Complete { decrypted, shares }) + Ok(PlaintextAggregatorState::Complete { decrypted, shares }) } } -impl Actor for Decryption { +impl Actor for PlaintextAggregator { type Context = Context; } -impl Handler for Decryption { +impl Handler for PlaintextAggregator { type Result = Result<()>; fn handle(&mut self, event: DecryptionshareCreated, ctx: &mut Self::Context) -> Self::Result { if event.e3_id != self.e3_id { @@ -83,7 +83,7 @@ impl Handler for Decryption { "Wrong e3_id sent to aggregator. This should not happen." )); } - let DecryptionState::Collecting { .. } = self.state else { + let PlaintextAggregatorState::Collecting { .. } = self.state else { return Err(anyhow!( "Aggregator has been closed for collecting keyshares." )); @@ -93,7 +93,7 @@ impl Handler for Decryption { self.state = self.add_share(event.decryption_share)?; // Check the state and if it has changed to the computing - if let DecryptionState::Computing { shares } = &self.state { + if let PlaintextAggregatorState::Computing { shares } = &self.state { ctx.address().do_send(ComputeAggregate { shares: shares.clone(), }) @@ -103,7 +103,7 @@ impl Handler for Decryption { } } -impl Handler for Decryption { +impl Handler for PlaintextAggregator { type Result = ResponseActFuture>; fn handle(&mut self, msg: ComputeAggregate, ctx: &mut Self::Context) -> Self::Result { Box::pin( @@ -118,7 +118,7 @@ impl Handler for Decryption { act.state = act.set_decryption(decrypted_output.clone())?; // Dispatch the PublicKeyAggregated event - let event = EnclaveEvent::from(DecryptedOutputPublished { + let event = EnclaveEvent::from(PlaintextAggregated { decrypted_output, e3_id: act.e3_id.clone(), }); @@ -131,7 +131,7 @@ impl Handler for Decryption { } } -impl Handler for Decryption { +impl Handler for PlaintextAggregator { type Result = (); fn handle(&mut self, _msg: Die, ctx: &mut Context) { diff --git a/packages/ciphernode/core/src/committee_key.rs b/packages/ciphernode/core/src/publickey_aggregator.rs similarity index 82% rename from packages/ciphernode/core/src/committee_key.rs rename to packages/ciphernode/core/src/publickey_aggregator.rs index aa31158d..001ed2d8 100644 --- a/packages/ciphernode/core/src/committee_key.rs +++ b/packages/ciphernode/core/src/publickey_aggregator.rs @@ -8,7 +8,7 @@ use actix::prelude::*; use anyhow::{anyhow, Result}; #[derive(Debug, Clone)] -pub enum CommitteeKeyState { +pub enum PublicKeyAggregatorState { Collecting { nodecount: usize, keyshares: OrderedSet>, @@ -28,11 +28,11 @@ struct ComputeAggregate { pub keyshares: OrderedSet>, } -pub struct CommitteeKey { +pub struct PublicKeyAggregator { fhe: Addr, bus: Addr, e3_id: E3id, - state: CommitteeKeyState, + state: PublicKeyAggregatorState, } /// Aggregate PublicKey for a committee of nodes. This actor listens for KeyshareCreated events @@ -41,21 +41,21 @@ pub struct CommitteeKey { /// identical events will not be triggered twice. /// It is expected to change this mechanism as we work through adversarial scenarios and write tests /// for them. -impl CommitteeKey { +impl PublicKeyAggregator { pub fn new(fhe: Addr, bus: Addr, e3_id: E3id, nodecount: usize) -> Self { - CommitteeKey { + PublicKeyAggregator { fhe, bus, e3_id, - state: CommitteeKeyState::Collecting { + state: PublicKeyAggregatorState::Collecting { nodecount, keyshares: OrderedSet::new(), }, } } - pub fn add_keyshare(&mut self, keyshare: Vec) -> Result { - let CommitteeKeyState::Collecting { + pub fn add_keyshare(&mut self, keyshare: Vec) -> Result { + let PublicKeyAggregatorState::Collecting { nodecount, keyshares, } = &mut self.state @@ -65,7 +65,7 @@ impl CommitteeKey { keyshares.insert(keyshare); if keyshares.len() == *nodecount { - return Ok(CommitteeKeyState::Computing { + return Ok(PublicKeyAggregatorState::Computing { keyshares: keyshares.clone(), }); } @@ -73,25 +73,25 @@ impl CommitteeKey { Ok(self.state.clone()) } - pub fn set_pubkey(&mut self, pubkey: Vec) -> Result { - let CommitteeKeyState::Computing { keyshares } = &mut self.state else { + pub fn set_pubkey(&mut self, pubkey: Vec) -> Result { + let PublicKeyAggregatorState::Computing { keyshares } = &mut self.state else { return Ok(self.state.clone()); }; let keyshares = keyshares.to_owned(); - Ok(CommitteeKeyState::Complete { + Ok(PublicKeyAggregatorState::Complete { public_key: pubkey, keyshares, }) } } -impl Actor for CommitteeKey { +impl Actor for PublicKeyAggregator { type Context = Context; } -impl Handler for CommitteeKey { +impl Handler for PublicKeyAggregator { type Result = Result<()>; fn handle(&mut self, event: KeyshareCreated, ctx: &mut Self::Context) -> Self::Result { @@ -101,7 +101,7 @@ impl Handler for CommitteeKey { )); } - let CommitteeKeyState::Collecting { .. } = self.state else { + let PublicKeyAggregatorState::Collecting { .. } = self.state else { return Err(anyhow!( "Aggregator has been closed for collecting keyshares." )); @@ -111,7 +111,7 @@ impl Handler for CommitteeKey { self.state = self.add_keyshare(event.pubkey)?; // Check the state and if it has changed to the computing - if let CommitteeKeyState::Computing { keyshares } = &self.state { + if let PublicKeyAggregatorState::Computing { keyshares } = &self.state { ctx.address().do_send(ComputeAggregate { keyshares: keyshares.clone(), }) @@ -121,7 +121,7 @@ impl Handler for CommitteeKey { } } -impl Handler for CommitteeKey { +impl Handler for PublicKeyAggregator { type Result = ResponseActFuture>; fn handle(&mut self, msg: ComputeAggregate, _: &mut Self::Context) -> Self::Result { @@ -160,7 +160,7 @@ impl Handler for CommitteeKey { } } -impl Handler for CommitteeKey { +impl Handler for PublicKeyAggregator { type Result = (); fn handle(&mut self, _msg: Die, ctx: &mut Context) { From 7bf2e111c10b18828308aa7ba90ed9495356e9d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=B3=CE=BB?= Date: Sun, 8 Sep 2024 11:58:42 +1000 Subject: [PATCH 36/87] Committeemanager -> CiphernodeSupervisor (#47) --- .../src/{committee.rs => ciphernode_supervisor.rs} | 10 +++++----- packages/ciphernode/core/src/lib.rs | 10 +++++----- packages/ciphernode/enclave_node/src/bin/aggregator.rs | 4 ++-- packages/ciphernode/enclave_node/src/bin/ciphernode.rs | 4 ++-- 4 files changed, 14 insertions(+), 14 deletions(-) rename packages/ciphernode/core/src/{committee.rs => ciphernode_supervisor.rs} (94%) diff --git a/packages/ciphernode/core/src/committee.rs b/packages/ciphernode/core/src/ciphernode_supervisor.rs similarity index 94% rename from packages/ciphernode/core/src/committee.rs rename to packages/ciphernode/core/src/ciphernode_supervisor.rs index db0a3e25..7400459a 100644 --- a/packages/ciphernode/core/src/committee.rs +++ b/packages/ciphernode/core/src/ciphernode_supervisor.rs @@ -18,7 +18,7 @@ pub struct Die; struct CommitteeMeta { nodecount: usize, } -pub struct CommitteeManager { +pub struct CiphernodeSupervisor { bus: Addr, fhe: Addr, @@ -27,11 +27,11 @@ pub struct CommitteeManager { meta: HashMap, } -impl Actor for CommitteeManager { +impl Actor for CiphernodeSupervisor { type Context = Context; } -impl CommitteeManager { +impl CiphernodeSupervisor { pub fn new(bus: Addr, fhe: Addr) -> Self { Self { bus, @@ -43,7 +43,7 @@ impl CommitteeManager { } pub fn attach(bus: Addr, fhe: Addr) -> Addr { - let addr = CommitteeManager::new(bus.clone(), fhe).start(); + let addr = CiphernodeSupervisor::new(bus.clone(), fhe).start(); bus.do_send(Subscribe::new( "CommitteeRequested", addr.clone().recipient(), @@ -65,7 +65,7 @@ impl CommitteeManager { } } -impl Handler for CommitteeManager { +impl Handler for CiphernodeSupervisor { type Result = (); fn handle(&mut self, event: EnclaveEvent, _ctx: &mut Self::Context) -> Self::Result { diff --git a/packages/ciphernode/core/src/lib.rs b/packages/ciphernode/core/src/lib.rs index 2ded47ad..6dd1b4ac 100644 --- a/packages/ciphernode/core/src/lib.rs +++ b/packages/ciphernode/core/src/lib.rs @@ -3,7 +3,7 @@ // #![warn(missing_docs, unused_imports)] mod ciphernode; -mod committee; +mod ciphernode_supervisor; mod publickey_aggregator; mod data; mod plaintext_aggregator; @@ -19,7 +19,7 @@ mod serializers; // TODO: this is too permissive pub use actix::prelude::*; pub use ciphernode::*; -pub use committee::*; +pub use ciphernode_supervisor::*; pub use publickey_aggregator::*; pub use data::*; pub use eventbus::*; @@ -30,7 +30,7 @@ pub use p2p::*; pub use actix::prelude::*; pub use ciphernode::*; -pub use committee::*; +pub use ciphernode_supervisor::*; pub use publickey_aggregator::*; pub use data::*; pub use eventbus::*; @@ -60,7 +60,7 @@ pub use p2p::*; mod tests { use crate::{ ciphernode::Ciphernode, - committee::CommitteeManager, + ciphernode_supervisor::CiphernodeSupervisor, data::Data, eventbus::{EventBus, GetHistory}, events::{CommitteeRequested, E3id, EnclaveEvent, KeyshareCreated, PublicKeyAggregated}, @@ -98,7 +98,7 @@ mod tests { let node = Ciphernode::attach(bus.clone(), fhe.clone(), data.clone()).await; // setup the committee manager to generate the comittee public keys - CommitteeManager::attach(bus.clone(), fhe.clone()); + CiphernodeSupervisor::attach(bus.clone(), fhe.clone()); (node, data) } diff --git a/packages/ciphernode/enclave_node/src/bin/aggregator.rs b/packages/ciphernode/enclave_node/src/bin/aggregator.rs index 70d32a10..fa602555 100644 --- a/packages/ciphernode/enclave_node/src/bin/aggregator.rs +++ b/packages/ciphernode/enclave_node/src/bin/aggregator.rs @@ -1,5 +1,5 @@ use enclave_core::Actor; -use enclave_core::CommitteeManager; +use enclave_core::CiphernodeSupervisor; use enclave_core::EventBus; use enclave_core::Fhe; use enclave_core::P2p; @@ -11,7 +11,7 @@ async fn main() -> Result<(), Box> { let fhe = Fhe::try_default()?.start(); let bus = EventBus::new(true).start(); SimpleLogger::attach(bus.clone()); - CommitteeManager::attach(bus.clone(), fhe.clone()); + CiphernodeSupervisor::attach(bus.clone(), fhe.clone()); let (_, h) = P2p::spawn_libp2p(bus.clone())?; println!("Aggregator"); let _ = tokio::join!(h); diff --git a/packages/ciphernode/enclave_node/src/bin/ciphernode.rs b/packages/ciphernode/enclave_node/src/bin/ciphernode.rs index 005496de..a48a6ff1 100644 --- a/packages/ciphernode/enclave_node/src/bin/ciphernode.rs +++ b/packages/ciphernode/enclave_node/src/bin/ciphernode.rs @@ -1,6 +1,6 @@ use enclave_core::Actor; use enclave_core::Ciphernode; -use enclave_core::CommitteeManager; +use enclave_core::CiphernodeSupervisor; use enclave_core::Data; use enclave_core::EventBus; use enclave_core::Fhe; @@ -15,7 +15,7 @@ async fn main() -> Result<(), Box> { let data = Data::new(true).start(); // TODO: Use a sled backed Data Actor SimpleLogger::attach(bus.clone()); Ciphernode::attach(bus.clone(), fhe.clone(), data.clone()); - CommitteeManager::attach(bus.clone(), fhe.clone()); + CiphernodeSupervisor::attach(bus.clone(), fhe.clone()); let (_, h) = P2p::spawn_libp2p(bus.clone())?; println!("Ciphernode"); let _ = tokio::join!(h); From 1369c290f29b6cb4cc33ff149d7959f99ed3d755 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=B3=CE=BB?= Date: Sun, 8 Sep 2024 12:16:50 +1000 Subject: [PATCH 37/87] Tidy up supervisor (#48) --- .../core/src/ciphernode_supervisor.rs | 40 +++++++++---------- 1 file changed, 19 insertions(+), 21 deletions(-) diff --git a/packages/ciphernode/core/src/ciphernode_supervisor.rs b/packages/ciphernode/core/src/ciphernode_supervisor.rs index 7400459a..e71df8a2 100644 --- a/packages/ciphernode/core/src/ciphernode_supervisor.rs +++ b/packages/ciphernode/core/src/ciphernode_supervisor.rs @@ -3,27 +3,25 @@ use std::collections::HashMap; use actix::{Actor, Addr, Context, Handler, Message}; use crate::{ - plaintext_aggregator::PlaintextAggregator, - eventbus::EventBus, - events::{E3id, EnclaveEvent}, - fhe::Fhe, - publickey_aggregator::PublicKeyAggregator, - Subscribe, + eventbus::EventBus, events::{E3id, EnclaveEvent}, fhe::Fhe, plaintext_aggregator::PlaintextAggregator, publickey_aggregator::{self, PublicKeyAggregator}, Subscribe }; #[derive(Message)] #[rtype(result = "()")] pub struct Die; +// CommitteeMeta +// Storing metadata around the committee eg threshold / nodecount struct CommitteeMeta { nodecount: usize, } + pub struct CiphernodeSupervisor { bus: Addr, fhe: Addr, - keys: HashMap>, - decryptions: HashMap>, + publickey_aggregators: HashMap>, + plaintext_aggregators: HashMap>, meta: HashMap, } @@ -36,8 +34,8 @@ impl CiphernodeSupervisor { Self { bus, fhe, - keys: HashMap::new(), - decryptions: HashMap::new(), + publickey_aggregators: HashMap::new(), + plaintext_aggregators: HashMap::new(), meta: HashMap::new(), } } @@ -72,7 +70,7 @@ impl Handler for CiphernodeSupervisor { match event { EnclaveEvent::CommitteeRequested { data, .. } => { // start up a new key - let key = PublicKeyAggregator::new( + let publickey_aggregator = PublicKeyAggregator::new( self.fhe.clone(), self.bus.clone(), data.e3_id.clone(), @@ -86,20 +84,20 @@ impl Handler for CiphernodeSupervisor { nodecount: data.nodecount.clone(), }, ); - self.keys.insert(data.e3_id, key); + self.publickey_aggregators.insert(data.e3_id, publickey_aggregator); } EnclaveEvent::KeyshareCreated { data, .. } => { - if let Some(key) = self.keys.get(&data.e3_id) { + if let Some(key) = self.publickey_aggregators.get(&data.e3_id) { key.do_send(data); } } EnclaveEvent::PublicKeyAggregated { data, .. } => { - let Some(key) = self.keys.get(&data.e3_id) else { + let Some(publickey_aggregator) = self.publickey_aggregators.get(&data.e3_id) else { return; }; - key.do_send(Die); - self.keys.remove(&data.e3_id); + publickey_aggregator.do_send(Die); + self.publickey_aggregators.remove(&data.e3_id); } EnclaveEvent::CiphertextOutputPublished { data, .. } => { let Some(meta) = self.meta.get(&data.e3_id) else { @@ -108,7 +106,7 @@ impl Handler for CiphernodeSupervisor { return; }; // start up a new key - let key = PlaintextAggregator::new( + let plaintext_aggregator = PlaintextAggregator::new( self.fhe.clone(), self.bus.clone(), data.e3_id.clone(), @@ -116,20 +114,20 @@ impl Handler for CiphernodeSupervisor { ) .start(); - self.decryptions.insert(data.e3_id, key); + self.plaintext_aggregators.insert(data.e3_id, plaintext_aggregator); } EnclaveEvent::DecryptionshareCreated { data, .. } => { - if let Some(decryption) = self.decryptions.get(&data.e3_id) { + if let Some(decryption) = self.plaintext_aggregators.get(&data.e3_id) { decryption.do_send(data); } } EnclaveEvent::PlaintextAggregated { data, .. } => { - let Some(addr) = self.decryptions.get(&data.e3_id) else { + let Some(addr) = self.plaintext_aggregators.get(&data.e3_id) else { return; }; addr.do_send(Die); - self.decryptions.remove(&data.e3_id); + self.plaintext_aggregators.remove(&data.e3_id); } } } From afa57558426f333004551b72fa53bb40b2d8b5b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=B3=CE=BB?= Date: Sun, 8 Sep 2024 13:27:04 +1000 Subject: [PATCH 38/87] Added CiphernodeSelector Actor and connect Ciphernode to CiphernodeSelected event (#50) --- packages/ciphernode/core/src/ciphernode.rs | 22 ++++----- .../core/src/ciphernode_selector.rs | 46 ++++++++++++++++++ .../core/src/ciphernode_supervisor.rs | 27 ++++++----- packages/ciphernode/core/src/events.rs | 47 ++++++++++++++----- packages/ciphernode/core/src/lib.rs | 41 +++++----------- .../enclave_node/src/bin/aggregator.rs | 1 + .../enclave_node/src/bin/ciphernode-noag.rs | 3 ++ .../enclave_node/src/bin/ciphernode.rs | 3 ++ .../ciphernode/enclave_node/src/bin/cmd.rs | 1 + 9 files changed, 126 insertions(+), 65 deletions(-) create mode 100644 packages/ciphernode/core/src/ciphernode_selector.rs diff --git a/packages/ciphernode/core/src/ciphernode.rs b/packages/ciphernode/core/src/ciphernode.rs index 4c09fb22..e9f20b60 100644 --- a/packages/ciphernode/core/src/ciphernode.rs +++ b/packages/ciphernode/core/src/ciphernode.rs @@ -1,9 +1,5 @@ use crate::{ - data::{Data, Insert}, - eventbus::EventBus, - events::{CommitteeRequested, EnclaveEvent, KeyshareCreated}, - fhe::{Fhe, GenerateKeyshare}, - CiphertextOutputPublished, DecryptCiphertext, DecryptionshareCreated, Get, Subscribe, + data::{Data, Insert}, eventbus::EventBus, events::{CommitteeRequested, EnclaveEvent, KeyshareCreated}, fhe::{Fhe, GenerateKeyshare}, CiphernodeSelected, CiphertextOutputPublished, DecryptCiphertext, DecryptionshareCreated, Get, Subscribe }; use actix::prelude::*; use anyhow::Result; @@ -26,7 +22,7 @@ impl Ciphernode { pub async fn attach(bus: Addr, fhe: Addr, data: Addr) -> Addr { let node = Ciphernode::new(bus.clone(), fhe, data).start(); let _ = bus - .send(Subscribe::new("CommitteeRequested", node.clone().into())) + .send(Subscribe::new("CiphernodeSelected", node.clone().into())) .await; let _ = bus .send(Subscribe::new( @@ -43,21 +39,21 @@ impl Handler for Ciphernode { fn handle(&mut self, event: EnclaveEvent, ctx: &mut Context) -> Self::Result { match event { - EnclaveEvent::CommitteeRequested { data, .. } => ctx.address().do_send(data), + EnclaveEvent::CiphernodeSelected { data, .. } => ctx.address().do_send(data), EnclaveEvent::CiphertextOutputPublished { data, .. } => ctx.address().do_send(data), _ => (), } } } -impl Handler for Ciphernode { +impl Handler for Ciphernode { type Result = ResponseFuture<()>; - fn handle(&mut self, event: CommitteeRequested, _: &mut Context) -> Self::Result { + fn handle(&mut self, event: CiphernodeSelected, _: &mut Context) -> Self::Result { let fhe = self.fhe.clone(); let data = self.data.clone(); let bus = self.bus.clone(); - Box::pin(async { on_committee_requested(fhe, data, bus, event).await.unwrap() }) + Box::pin(async { on_ciphernode_selected(fhe, data, bus, event).await.unwrap() }) } } @@ -76,13 +72,13 @@ impl Handler for Ciphernode { } } -async fn on_committee_requested( +async fn on_ciphernode_selected( fhe: Addr, data: Addr, bus: Addr, - event: CommitteeRequested, + event: CiphernodeSelected, ) -> Result<()> { - let CommitteeRequested { e3_id, .. } = event; + let CiphernodeSelected { e3_id, .. } = event; // generate keyshare let (sk, pubkey) = fhe.send(GenerateKeyshare {}).await??; diff --git a/packages/ciphernode/core/src/ciphernode_selector.rs b/packages/ciphernode/core/src/ciphernode_selector.rs new file mode 100644 index 00000000..9d363953 --- /dev/null +++ b/packages/ciphernode/core/src/ciphernode_selector.rs @@ -0,0 +1,46 @@ +use actix::prelude::*; + +use crate::{CiphernodeSelected, CommitteeRequested, EnclaveEvent, EventBus, Subscribe}; + +pub struct CiphernodeSelector { + bus: Addr, +} + +impl Actor for CiphernodeSelector { + type Context = Context; +} + +impl CiphernodeSelector { + pub fn new(bus: Addr) -> Self { + Self { bus } + } + + pub fn attach(bus: Addr) -> Addr { + let addr = CiphernodeSelector::new(bus.clone()).start(); + + bus.do_send(Subscribe::new( + "CommitteeRequested", + addr.clone().recipient(), + )); + + addr + } +} + +impl Handler for CiphernodeSelector { + type Result = (); + + fn handle(&mut self, event: EnclaveEvent, ctx: &mut Self::Context) -> Self::Result { + match event { + EnclaveEvent::CommitteeRequested { data, .. } => { + // TODO: ask Sortition module whether registered node has been selected + self.bus.do_send(EnclaveEvent::from(CiphernodeSelected { + e3_id: data.e3_id, + nodecount: data.nodecount, + threshold: data.threshold, + })) + } + _ => (), + } + } +} diff --git a/packages/ciphernode/core/src/ciphernode_supervisor.rs b/packages/ciphernode/core/src/ciphernode_supervisor.rs index e71df8a2..ebe3d935 100644 --- a/packages/ciphernode/core/src/ciphernode_supervisor.rs +++ b/packages/ciphernode/core/src/ciphernode_supervisor.rs @@ -1,10 +1,13 @@ -use std::collections::HashMap; - -use actix::{Actor, Addr, Context, Handler, Message}; - use crate::{ - eventbus::EventBus, events::{E3id, EnclaveEvent}, fhe::Fhe, plaintext_aggregator::PlaintextAggregator, publickey_aggregator::{self, PublicKeyAggregator}, Subscribe + eventbus::EventBus, + events::{E3id, EnclaveEvent}, + fhe::Fhe, + plaintext_aggregator::PlaintextAggregator, + publickey_aggregator::PublicKeyAggregator, + Subscribe, }; +use actix::prelude::*; +use std::collections::HashMap; #[derive(Message)] #[rtype(result = "()")] @@ -55,10 +58,7 @@ impl CiphernodeSupervisor { "DecryptionshareCreated", addr.clone().into(), )); - bus.do_send(Subscribe::new( - "PlaintextAggregated", - addr.clone().into(), - )); + bus.do_send(Subscribe::new("PlaintextAggregated", addr.clone().into())); addr } } @@ -84,7 +84,8 @@ impl Handler for CiphernodeSupervisor { nodecount: data.nodecount.clone(), }, ); - self.publickey_aggregators.insert(data.e3_id, publickey_aggregator); + self.publickey_aggregators + .insert(data.e3_id, publickey_aggregator); } EnclaveEvent::KeyshareCreated { data, .. } => { if let Some(key) = self.publickey_aggregators.get(&data.e3_id) { @@ -114,7 +115,8 @@ impl Handler for CiphernodeSupervisor { ) .start(); - self.plaintext_aggregators.insert(data.e3_id, plaintext_aggregator); + self.plaintext_aggregators + .insert(data.e3_id, plaintext_aggregator); } EnclaveEvent::DecryptionshareCreated { data, .. } => { if let Some(decryption) = self.plaintext_aggregators.get(&data.e3_id) { @@ -128,7 +130,8 @@ impl Handler for CiphernodeSupervisor { addr.do_send(Die); self.plaintext_aggregators.remove(&data.e3_id); - } + }, + _ => () } } } diff --git a/packages/ciphernode/core/src/events.rs b/packages/ciphernode/core/src/events.rs index 9b95c310..7760ec98 100644 --- a/packages/ciphernode/core/src/events.rs +++ b/packages/ciphernode/core/src/events.rs @@ -70,16 +70,19 @@ pub enum EnclaveEvent { DecryptionshareCreated { id: EventId, data: DecryptionshareCreated, - }, -PlaintextAggregated { - id: EventId, - data: PlaintextAggregated - } - + }, + PlaintextAggregated { + id: EventId, + data: PlaintextAggregated, + }, + CiphernodeSelected { + id: EventId, + data: CiphernodeSelected, + }, // CommitteeSelected, - // OutputDecrypted, - // CiphernodeRegistered, - // CiphernodeDeregistered, + // OutputDecrypted, + // CiphernodeRegistered, + // CiphernodeDeregistered, } impl EnclaveEvent { @@ -105,6 +108,7 @@ impl From for EventId { EnclaveEvent::CiphertextOutputPublished { id, .. } => id, EnclaveEvent::DecryptionshareCreated { id, .. } => id, EnclaveEvent::PlaintextAggregated { id, .. } => id, + EnclaveEvent::CiphernodeSelected { id, .. } => id, } } } @@ -162,6 +166,16 @@ impl From for EnclaveEvent { } } } + +impl From for EnclaveEvent { + fn from(data: CiphernodeSelected) -> Self { + EnclaveEvent::CiphernodeSelected { + id: EventId::from(data.clone()), + data: data.clone(), + } + } +} + impl fmt::Display for EnclaveEvent { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str(&format!("{}({})", self.event_type(), self.get_id())) @@ -202,18 +216,26 @@ pub struct CommitteeRequested { // availability_duration: ??, // TODO: } +#[derive(Message, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[rtype(result = "()")] +pub struct CiphernodeSelected { + pub e3_id: E3id, + pub nodecount: usize, + pub threshold: usize, +} + #[derive(Message, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[rtype(result = "()")] pub struct CiphertextOutputPublished { pub e3_id: E3id, - pub ciphertext_output: Vec + pub ciphertext_output: Vec, } #[derive(Message, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[rtype(result = "()")] pub struct PlaintextAggregated { pub e3_id: E3id, - pub decrypted_output: Vec + pub decrypted_output: Vec, } fn extract_enclave_event_name(s: &str) -> &str { @@ -237,7 +259,8 @@ impl EnclaveEvent { mod tests { use super::EnclaveEvent; use crate::{ - events::extract_enclave_event_name, serializers::PublicKeyShareSerializer, E3id, KeyshareCreated, + events::extract_enclave_event_name, serializers::PublicKeyShareSerializer, E3id, + KeyshareCreated, }; use fhe::{ bfv::{BfvParametersBuilder, SecretKey}, diff --git a/packages/ciphernode/core/src/lib.rs b/packages/ciphernode/core/src/lib.rs index 6dd1b4ac..bd7139e9 100644 --- a/packages/ciphernode/core/src/lib.rs +++ b/packages/ciphernode/core/src/lib.rs @@ -15,6 +15,7 @@ mod logger; mod ordered_set; mod p2p; mod serializers; +mod ciphernode_selector; // TODO: this is too permissive pub use actix::prelude::*; @@ -31,6 +32,7 @@ pub use p2p::*; pub use actix::prelude::*; pub use ciphernode::*; pub use ciphernode_supervisor::*; +pub use ciphernode_selector::*; pub use publickey_aggregator::*; pub use data::*; pub use eventbus::*; @@ -38,39 +40,14 @@ pub use events::*; pub use fhe::*; pub use p2p::*; -// pub struct Core { -// pub name: String, -// } -// -// impl Core { -// fn new(name: String) -> Self { -// Self { name } -// } -// -// fn run() { -// actix::run(async move { -// sleep(Duration::from_millis(100)).await; -// actix::System::current().stop(); -// }); -// } -// } - // TODO: move these out to a test folder #[cfg(test)] mod tests { use crate::{ - ciphernode::Ciphernode, - ciphernode_supervisor::CiphernodeSupervisor, - data::Data, - eventbus::{EventBus, GetHistory}, - events::{CommitteeRequested, E3id, EnclaveEvent, KeyshareCreated, PublicKeyAggregated}, - fhe::Fhe, - p2p::P2p, - serializers::{ + ciphernode::Ciphernode, ciphernode_selector::CiphernodeSelector, ciphernode_supervisor::CiphernodeSupervisor, data::Data, eventbus::{EventBus, GetHistory}, events::{CommitteeRequested, E3id, EnclaveEvent, KeyshareCreated, PublicKeyAggregated}, fhe::Fhe, p2p::P2p, serializers::{ CiphertextSerializer, DecryptionShareSerializer, PublicKeySerializer, PublicKeyShareSerializer, - }, - PlaintextAggregated, CiphertextOutputPublished, DecryptionshareCreated, ResetHistory, + }, CiphernodeSelected, CiphertextOutputPublished, DecryptionshareCreated, PlaintextAggregated, ResetHistory }; use actix::prelude::*; use anyhow::*; @@ -91,10 +68,13 @@ mod tests { fhe: Addr, logging: bool, ) -> (Addr, Addr) { + // create data actor for saving data let data = Data::new(logging).start(); // TODO: Use a sled backed Data Actor // create ciphernode actor for managing ciphernode flow + CiphernodeSelector::attach(bus.clone()); + let node = Ciphernode::attach(bus.clone(), fhe.clone(), data.clone()).await; // setup the committee manager to generate the comittee public keys @@ -199,7 +179,7 @@ mod tests { .map(|k| PublicKeyShareSerializer::from_bytes(k).unwrap()) .aggregate()?; - assert_eq!(history.len(), 5); + assert_eq!(history.len(), 6); assert_eq!( history, vec![ @@ -209,6 +189,11 @@ mod tests { threshold: 123, sortition_seed: 123, }), + EnclaveEvent::from(CiphernodeSelected { + e3_id: e3_id.clone(), + nodecount: 3, + threshold: 123, + }), EnclaveEvent::from(KeyshareCreated { pubkey: p1.clone(), e3_id: e3_id.clone(), diff --git a/packages/ciphernode/enclave_node/src/bin/aggregator.rs b/packages/ciphernode/enclave_node/src/bin/aggregator.rs index fa602555..a46cf3f7 100644 --- a/packages/ciphernode/enclave_node/src/bin/aggregator.rs +++ b/packages/ciphernode/enclave_node/src/bin/aggregator.rs @@ -6,6 +6,7 @@ use enclave_core::P2p; use enclave_core::SimpleLogger; use std::error::Error; +/// Note this is untestable so it may break as we change our API #[actix_rt::main] async fn main() -> Result<(), Box> { let fhe = Fhe::try_default()?.start(); diff --git a/packages/ciphernode/enclave_node/src/bin/ciphernode-noag.rs b/packages/ciphernode/enclave_node/src/bin/ciphernode-noag.rs index 627af0b3..1aa3bea6 100644 --- a/packages/ciphernode/enclave_node/src/bin/ciphernode-noag.rs +++ b/packages/ciphernode/enclave_node/src/bin/ciphernode-noag.rs @@ -1,5 +1,6 @@ use enclave_core::Actor; use enclave_core::Ciphernode; +use enclave_core::CiphernodeSelector; use enclave_core::Data; use enclave_core::EventBus; use enclave_core::Fhe; @@ -7,11 +8,13 @@ use enclave_core::P2p; use enclave_core::SimpleLogger; use std::error::Error; +/// Note this is untestable so it may break as we change our API #[actix_rt::main] async fn main() -> Result<(), Box> { let fhe = Fhe::try_default()?.start(); let bus = EventBus::new(true).start(); let data = Data::new(true).start(); // TODO: Use a sled backed Data Actor + CiphernodeSelector::attach(bus.clone()); SimpleLogger::attach(bus.clone()); Ciphernode::attach(bus.clone(), fhe.clone(), data.clone()); let (_, h) = P2p::spawn_libp2p(bus.clone())?; diff --git a/packages/ciphernode/enclave_node/src/bin/ciphernode.rs b/packages/ciphernode/enclave_node/src/bin/ciphernode.rs index a48a6ff1..f24fff96 100644 --- a/packages/ciphernode/enclave_node/src/bin/ciphernode.rs +++ b/packages/ciphernode/enclave_node/src/bin/ciphernode.rs @@ -1,5 +1,6 @@ use enclave_core::Actor; use enclave_core::Ciphernode; +use enclave_core::CiphernodeSelector; use enclave_core::CiphernodeSupervisor; use enclave_core::Data; use enclave_core::EventBus; @@ -8,12 +9,14 @@ use enclave_core::P2p; use enclave_core::SimpleLogger; use std::error::Error; +/// Note this is untestable so it may break as we change our API #[actix_rt::main] async fn main() -> Result<(), Box> { let fhe = Fhe::try_default()?.start(); let bus = EventBus::new(true).start(); let data = Data::new(true).start(); // TODO: Use a sled backed Data Actor SimpleLogger::attach(bus.clone()); + CiphernodeSelector::attach(bus.clone()); Ciphernode::attach(bus.clone(), fhe.clone(), data.clone()); CiphernodeSupervisor::attach(bus.clone(), fhe.clone()); let (_, h) = P2p::spawn_libp2p(bus.clone())?; diff --git a/packages/ciphernode/enclave_node/src/bin/cmd.rs b/packages/ciphernode/enclave_node/src/bin/cmd.rs index 9984408f..238948e1 100644 --- a/packages/ciphernode/enclave_node/src/bin/cmd.rs +++ b/packages/ciphernode/enclave_node/src/bin/cmd.rs @@ -11,6 +11,7 @@ use tokio::{ io::{self, AsyncBufReadExt, BufReader}, }; +/// Note this is untestable so it may break as we change our API #[actix_rt::main] async fn main() -> Result<(), Box> { let bus = EventBus::new(true).start(); From 0aa04dc13dbd763be83f0773b5a11f783bfba4c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=B3=CE=BB?= Date: Sun, 8 Sep 2024 15:39:05 +1000 Subject: [PATCH 39/87] Filter local events (#51) * Filter local events * Add comments --- packages/ciphernode/core/src/events.rs | 7 ++++ packages/ciphernode/core/src/lib.rs | 48 ++++++++++++++++++-------- packages/ciphernode/core/src/p2p.rs | 15 ++++---- 3 files changed, 49 insertions(+), 21 deletions(-) diff --git a/packages/ciphernode/core/src/events.rs b/packages/ciphernode/core/src/events.rs index 7760ec98..95a8dcf2 100644 --- a/packages/ciphernode/core/src/events.rs +++ b/packages/ciphernode/core/src/events.rs @@ -97,6 +97,13 @@ impl EnclaveEvent { pub fn get_id(&self) -> EventId { self.clone().into() } + + pub fn is_local_only(&self) -> bool { + match self { + EnclaveEvent::CiphernodeSelected { .. } => true, + _ => false, + } + } } impl From for EventId { diff --git a/packages/ciphernode/core/src/lib.rs b/packages/ciphernode/core/src/lib.rs index bd7139e9..def9c502 100644 --- a/packages/ciphernode/core/src/lib.rs +++ b/packages/ciphernode/core/src/lib.rs @@ -3,10 +3,9 @@ // #![warn(missing_docs, unused_imports)] mod ciphernode; +mod ciphernode_selector; mod ciphernode_supervisor; -mod publickey_aggregator; mod data; -mod plaintext_aggregator; mod enclave_contract; mod eventbus; mod events; @@ -14,40 +13,51 @@ mod fhe; mod logger; mod ordered_set; mod p2p; +mod plaintext_aggregator; +mod publickey_aggregator; mod serializers; -mod ciphernode_selector; // TODO: this is too permissive pub use actix::prelude::*; pub use ciphernode::*; pub use ciphernode_supervisor::*; -pub use publickey_aggregator::*; pub use data::*; pub use eventbus::*; pub use events::*; pub use fhe::*; pub use logger::*; pub use p2p::*; +pub use publickey_aggregator::*; pub use actix::prelude::*; pub use ciphernode::*; -pub use ciphernode_supervisor::*; pub use ciphernode_selector::*; -pub use publickey_aggregator::*; +pub use ciphernode_supervisor::*; pub use data::*; pub use eventbus::*; pub use events::*; pub use fhe::*; pub use p2p::*; +pub use publickey_aggregator::*; // TODO: move these out to a test folder #[cfg(test)] mod tests { use crate::{ - ciphernode::Ciphernode, ciphernode_selector::CiphernodeSelector, ciphernode_supervisor::CiphernodeSupervisor, data::Data, eventbus::{EventBus, GetHistory}, events::{CommitteeRequested, E3id, EnclaveEvent, KeyshareCreated, PublicKeyAggregated}, fhe::Fhe, p2p::P2p, serializers::{ + ciphernode::Ciphernode, + ciphernode_selector::CiphernodeSelector, + ciphernode_supervisor::CiphernodeSupervisor, + data::Data, + eventbus::{EventBus, GetHistory}, + events::{CommitteeRequested, E3id, EnclaveEvent, KeyshareCreated, PublicKeyAggregated}, + fhe::Fhe, + p2p::P2p, + serializers::{ CiphertextSerializer, DecryptionShareSerializer, PublicKeySerializer, PublicKeyShareSerializer, - }, CiphernodeSelected, CiphertextOutputPublished, DecryptionshareCreated, PlaintextAggregated, ResetHistory + }, + CiphernodeSelected, CiphertextOutputPublished, DecryptionshareCreated, PlaintextAggregated, + ResetHistory, }; use actix::prelude::*; use anyhow::*; @@ -68,7 +78,6 @@ mod tests { fhe: Addr, logging: bool, ) -> (Addr, Addr) { - // create data actor for saving data let data = Data::new(logging).start(); // TODO: Use a sled backed Data Actor @@ -216,8 +225,8 @@ mod tests { // Aggregate decryption bus.send(ResetHistory).await?; - // TODO: - // Making these values large (especially the yes value) requires changing + // 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 yes = 1234u64; let no = 873827u64; @@ -298,6 +307,9 @@ mod tests { while let Some(msg) = output.recv().await { msgs_loop.lock().await.push(msg.clone()); let _ = input.send(msg).await; // loopback to simulate a rebroadcast message + // if this manages to broadcast an event to the + // event bus we will expect to see an extra event on + // the bus } }); @@ -315,8 +327,15 @@ mod tests { sortition_seed: 123, }); + let local_evt_3 = EnclaveEvent::from(CiphernodeSelected { + e3_id: E3id::new("1235"), + nodecount: 3, + threshold: 123, + }); + bus.do_send(evt_1.clone()); bus.do_send(evt_2.clone()); + bus.do_send(local_evt_3.clone()); // This is a local event which should not be broadcast to the network sleep(Duration::from_millis(1)).await; // need to push to next tick @@ -325,13 +344,14 @@ mod tests { assert_eq!( *msgs.lock().await, - vec![evt_1.to_bytes()?, evt_2.to_bytes()?], - "P2p did not transmit events to the network" + vec![evt_1.to_bytes()?, evt_2.to_bytes()?], // notice no local events + "P2p did not transmit correct events to the network" ); assert_eq!( history, - vec![evt_1, evt_2], + vec![evt_1, evt_2, local_evt_3], // all local events that have been broadcast but no + // events from the loopback "P2p must not retransmit forwarded event to event bus" ); diff --git a/packages/ciphernode/core/src/p2p.rs b/packages/ciphernode/core/src/p2p.rs index 6b4616b6..7c8cb9a8 100644 --- a/packages/ciphernode/core/src/p2p.rs +++ b/packages/ciphernode/core/src/p2p.rs @@ -64,13 +64,7 @@ impl P2p { pub fn spawn_libp2p( bus: Addr, - ) -> Result< - ( - Addr, - tokio::task::JoinHandle<()>, - ), - Box, - > { + ) -> Result<(Addr, tokio::task::JoinHandle<()>), Box> { let (mut libp2p, tx, rx) = EnclaveRouter::new()?; libp2p.connect_swarm("mdns".to_string())?; libp2p.join_topic("enclave-keygen-01")?; @@ -104,10 +98,17 @@ impl Handler for P2p { let evt = event.clone(); Box::pin(async move { let id: EventId = evt.clone().into(); + + // if we have seen this event before dont rebroadcast if sent_events.contains(&id) { return; } + // Ignore events that should be considered local + if evt.is_local_only() { + return; + } + match evt.to_bytes() { Ok(bytes) => { let _ = tx.send(bytes).await; From 1d65ad367c8f502e194fd18fc5ce481045dce239 Mon Sep 17 00:00:00 2001 From: nginnever Date: Tue, 10 Sep 2024 11:48:25 -0700 Subject: [PATCH 40/87] init sortition lib --- packages/ciphernode/enclave_node/Cargo.toml | 1 + packages/ciphernode/sortition/Cargo.toml | 24 +++++++++++++++++++++ 2 files changed, 25 insertions(+) create mode 100644 packages/ciphernode/sortition/Cargo.toml diff --git a/packages/ciphernode/enclave_node/Cargo.toml b/packages/ciphernode/enclave_node/Cargo.toml index f062f405..53dccba3 100644 --- a/packages/ciphernode/enclave_node/Cargo.toml +++ b/packages/ciphernode/enclave_node/Cargo.toml @@ -11,6 +11,7 @@ repository = "https://github.com/gnosisguild/enclave/packages/ciphernode" eth = { path = "../eth" } p2p = { path = "../p2p" } bfv = { path = "../bfv" } +sortition = { path = "../sortition" } enclave-core = { path = "../core" } async-std = "1.12.0" fhe = { git = "https://github.com/gnosisguild/fhe.rs", version = "0.1.0-beta.7" } diff --git a/packages/ciphernode/sortition/Cargo.toml b/packages/ciphernode/sortition/Cargo.toml new file mode 100644 index 00000000..68f60d4e --- /dev/null +++ b/packages/ciphernode/sortition/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "sortition" +version = "0.1.0" +edition = "2021" +description = ": coordinates the encryption and decryption of enclave computations" +repository = "https://github.com/gnosisguild/enclave/packages/ciphernode" +path = "src/lib.rs" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +# Core +enclave-core = { path = "../core" } + +# Actix +actix = "0.13.5" +async-std = "1.12.0" + +# Ethereum +futures-util = "0.3" +eyre = "0.6" +alloy = { version = "0.2.1", features = ["full"] } +alloy-primitives = { version = "0.6", default-features = false, features = ["rlp", "serde", "std"] } +alloy-sol-types = { version = "0.6" } \ No newline at end of file From a40c58091b808c30a1d2be1887df0f5d188ab94e Mon Sep 17 00:00:00 2001 From: nginnever Date: Tue, 10 Sep 2024 13:08:21 -0700 Subject: [PATCH 41/87] hasher --- packages/ciphernode/enclave_node/Cargo.toml | 1 + packages/ciphernode/enclave_node/src/main.rs | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/packages/ciphernode/enclave_node/Cargo.toml b/packages/ciphernode/enclave_node/Cargo.toml index 53dccba3..228541b9 100644 --- a/packages/ciphernode/enclave_node/Cargo.toml +++ b/packages/ciphernode/enclave_node/Cargo.toml @@ -19,5 +19,6 @@ fhe-traits = { git = "https://github.com/gnosisguild/fhe.rs", version = "0.1.0-b fhe-util = { git = "https://github.com/gnosisguild/fhe.rs", version = "0.1.0-beta.7" } tokio = { version = "1.38", features = ["full"] } actix-rt = "2.10.0" +alloy-primitives = { version = "0.6", default-features = false, features = ["rlp", "serde", "std"] } alloy = { version = "0.2.1", features = ["full"] } \ No newline at end of file diff --git a/packages/ciphernode/enclave_node/src/main.rs b/packages/ciphernode/enclave_node/src/main.rs index 9ad0668f..9e5aee83 100644 --- a/packages/ciphernode/enclave_node/src/main.rs +++ b/packages/ciphernode/enclave_node/src/main.rs @@ -2,10 +2,14 @@ use std::error::Error; use p2p::EnclaveRouter; use bfv::EnclaveBFV; +use sortition::DistanceSortition; use tokio::{ self, io::{self, AsyncBufReadExt, BufReader}, }; + +use alloy_primitives::{address}; + const OWO: &str = r#" ___ ___ ___ ___ ___ /\__\ /\ \ /\__\ /\ \ ___ /\__\ @@ -34,6 +38,9 @@ async fn main() -> Result<(), Box> { println!("\n\n\n\n"); println!("Hello, cipher world!"); + let mut committee = DistanceSortition::new(12, vec![address!("d8da6bf26964af9d7eed9e03e53415d37aa96045")], 10); + committee.get_committee(); + let mut new_bfv = EnclaveBFV::new(4096, 4096, vec![0xffffee001, 0xffffc4001, 0x1ffffe0001]); let pk_bytes = new_bfv.serialize_pk(); let param_bytes = new_bfv.serialize_params(); From 34eb638a4f8b330f2618d25a23c30010de75d3a9 Mon Sep 17 00:00:00 2001 From: nginnever Date: Tue, 10 Sep 2024 13:16:14 -0700 Subject: [PATCH 42/87] convert hash --- packages/ciphernode/sortition/Cargo.toml | 2 ++ packages/ciphernode/sortition/src/distance.rs | 36 +++++++++++++++++++ packages/ciphernode/sortition/src/index.rs | 0 packages/ciphernode/sortition/src/lib.rs | 9 +++++ 4 files changed, 47 insertions(+) create mode 100644 packages/ciphernode/sortition/src/distance.rs create mode 100644 packages/ciphernode/sortition/src/index.rs create mode 100644 packages/ciphernode/sortition/src/lib.rs diff --git a/packages/ciphernode/sortition/Cargo.toml b/packages/ciphernode/sortition/Cargo.toml index 68f60d4e..434fcb99 100644 --- a/packages/ciphernode/sortition/Cargo.toml +++ b/packages/ciphernode/sortition/Cargo.toml @@ -9,6 +9,8 @@ path = "src/lib.rs" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +num = "0.4.0" + # Core enclave-core = { path = "../core" } diff --git a/packages/ciphernode/sortition/src/distance.rs b/packages/ciphernode/sortition/src/distance.rs new file mode 100644 index 00000000..9c0611b7 --- /dev/null +++ b/packages/ciphernode/sortition/src/distance.rs @@ -0,0 +1,36 @@ +use alloy_primitives::{address, Address, keccak256}; +use num::{BigInt, Num}; + +pub struct DistanceSortition { + pub random_seed: u64, + pub registered_nodes: Vec
, + pub size: usize, +} + +impl DistanceSortition { + pub fn new(random_seed: u64, registered_nodes: Vec
, size: usize) -> Self { + Self { random_seed, registered_nodes, size } + } + + pub fn get_committee(&mut self) -> Vec
{ + let hashed = self.registered_nodes.iter() + .map(|address| + { + let concat = address.to_string() + &self.random_seed.to_string(); + let hash = keccak256(concat); + hash.to_string() + }) + .collect::>(); + + let numeric = hashed.iter() + .map(|hash| + { + let without_prefix = hash.trim_start_matches("0x"); + let z = BigInt::from_str_radix(without_prefix, 16); + println!("{:?}", z); + z.unwrap() + }) + .collect::>(); + self.registered_nodes.clone() + } +} \ No newline at end of file diff --git a/packages/ciphernode/sortition/src/index.rs b/packages/ciphernode/sortition/src/index.rs new file mode 100644 index 00000000..e69de29b diff --git a/packages/ciphernode/sortition/src/lib.rs b/packages/ciphernode/sortition/src/lib.rs new file mode 100644 index 00000000..6a99e9df --- /dev/null +++ b/packages/ciphernode/sortition/src/lib.rs @@ -0,0 +1,9 @@ +#![crate_name = "sortition"] +#![crate_type = "lib"] +// #![warn(missing_docs, unused_imports)] + +mod distance; +mod index; + +pub use distance::*; +pub use index::*; \ No newline at end of file From 85b174fa231b0904bf59e6c2986ba321daafb6bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=B3=CE=BB?= Date: Thu, 12 Sep 2024 00:27:38 +1000 Subject: [PATCH 43/87] Prepare for sequencers (#53) * Remove redundant imports * Add sequencers that do nothing but spawn children and send them messages * Setting up Registry * Fix up Fhe * Setup registry * Update registry * Modularize * Update registry to be more modular * Rename * Rename --- .../core/src/ciphernode_sequencer.rs | 40 ++++++ .../core/src/ciphernode_supervisor.rs | 4 +- packages/ciphernode/core/src/events.rs | 14 +++ packages/ciphernode/core/src/fhe.rs | 30 +++-- packages/ciphernode/core/src/lib.rs | 20 ++- .../core/src/plaintext_aggregator.rs | 12 +- .../core/src/plaintext_sequencer.rs | 43 +++++++ .../core/src/publickey_aggregator.rs | 12 +- .../core/src/publickey_sequencer.rs | 45 +++++++ packages/ciphernode/core/src/registry.rs | 115 ++++++++++++++++++ 10 files changed, 311 insertions(+), 24 deletions(-) create mode 100644 packages/ciphernode/core/src/ciphernode_sequencer.rs create mode 100644 packages/ciphernode/core/src/plaintext_sequencer.rs create mode 100644 packages/ciphernode/core/src/publickey_sequencer.rs create mode 100644 packages/ciphernode/core/src/registry.rs diff --git a/packages/ciphernode/core/src/ciphernode_sequencer.rs b/packages/ciphernode/core/src/ciphernode_sequencer.rs new file mode 100644 index 00000000..d67702d5 --- /dev/null +++ b/packages/ciphernode/core/src/ciphernode_sequencer.rs @@ -0,0 +1,40 @@ +// sequence and persist events for a single E3 request in the correct order +// TODO: spawn and store a ciphernode upon start and forward all events to it in order +// TODO: if the ciphernode fails restart the node by replaying all stored events back to it + +use actix::prelude::*; + +use crate::{Ciphernode, Data, EnclaveEvent, EventBus, Fhe}; + +pub struct CiphernodeSequencer { + fhe: Addr, + data: Addr, + bus: Addr, + child: Option>, +} +impl CiphernodeSequencer { + pub fn new(fhe: Addr, data: Addr, bus: Addr) -> Self { + Self { + fhe, + bus, + data, + child: None, + } + } +} +impl Actor for CiphernodeSequencer { + type Context = Context; +} + +impl Handler for CiphernodeSequencer { + type Result = (); + fn handle(&mut self, msg: EnclaveEvent, ctx: &mut Self::Context) -> Self::Result { + let bus = self.bus.clone(); + let fhe = self.fhe.clone(); + let data = self.data.clone(); + let sink = self + .child + .get_or_insert_with(|| Ciphernode::new(bus, fhe, data).start()); + sink.do_send(msg); + } +} diff --git a/packages/ciphernode/core/src/ciphernode_supervisor.rs b/packages/ciphernode/core/src/ciphernode_supervisor.rs index ebe3d935..7fea6c99 100644 --- a/packages/ciphernode/core/src/ciphernode_supervisor.rs +++ b/packages/ciphernode/core/src/ciphernode_supervisor.rs @@ -89,7 +89,7 @@ impl Handler for CiphernodeSupervisor { } EnclaveEvent::KeyshareCreated { data, .. } => { if let Some(key) = self.publickey_aggregators.get(&data.e3_id) { - key.do_send(data); + key.do_send(EnclaveEvent::from(data)); } } EnclaveEvent::PublicKeyAggregated { data, .. } => { @@ -120,7 +120,7 @@ impl Handler for CiphernodeSupervisor { } EnclaveEvent::DecryptionshareCreated { data, .. } => { if let Some(decryption) = self.plaintext_aggregators.get(&data.e3_id) { - decryption.do_send(data); + decryption.do_send(EnclaveEvent::from(data)); } } EnclaveEvent::PlaintextAggregated { data, .. } => { diff --git a/packages/ciphernode/core/src/events.rs b/packages/ciphernode/core/src/events.rs index 95a8dcf2..ff6300fd 100644 --- a/packages/ciphernode/core/src/events.rs +++ b/packages/ciphernode/core/src/events.rs @@ -120,6 +120,20 @@ impl From for EventId { } } +impl From for E3id { + fn from(value: EnclaveEvent) -> Self { + match value { + EnclaveEvent::KeyshareCreated { data, .. } => data.e3_id, + EnclaveEvent::CommitteeRequested { data, .. } => data.e3_id, + EnclaveEvent::PublicKeyAggregated { data, .. } => data.e3_id, + EnclaveEvent::CiphertextOutputPublished { data, .. } => data.e3_id, + EnclaveEvent::DecryptionshareCreated { data, .. } => data.e3_id, + EnclaveEvent::PlaintextAggregated { data, .. } => data.e3_id, + EnclaveEvent::CiphernodeSelected { data, .. } => data.e3_id, + } + } +} + impl From for EnclaveEvent { fn from(data: KeyshareCreated) -> Self { EnclaveEvent::KeyshareCreated { diff --git a/packages/ciphernode/core/src/fhe.rs b/packages/ciphernode/core/src/fhe.rs index 18a526be..f78cede0 100644 --- a/packages/ciphernode/core/src/fhe.rs +++ b/packages/ciphernode/core/src/fhe.rs @@ -53,18 +53,30 @@ impl Actor for Fhe { } impl Fhe { - pub fn new( - params: Arc, - crp: CommonRandomPoly, - rng: ChaCha20Rng, - ) -> Result { - Ok(Self { params, crp, rng }) + pub fn new(params: Arc, crp: CommonRandomPoly, rng: ChaCha20Rng) -> Self { + Self { params, crp, rng } } - pub fn try_default() -> Result { + + pub fn try_default() -> Result { let moduli = &vec![0x3FFFFFFF000001]; let degree = 2048usize; let plaintext_modulus = 1032193u64; - let mut rng = ChaCha20Rng::from_entropy(); + let rng = ChaCha20Rng::from_entropy(); + + Ok(Fhe::from_raw_params( + moduli, + degree, + plaintext_modulus, + rng, + )?) + } + + pub fn from_raw_params( + moduli: &[u64], + degree: usize, + plaintext_modulus: u64, + mut rng: ChaCha20Rng, + ) -> Result { let params = BfvParametersBuilder::new() .set_degree(degree) .set_plaintext_modulus(plaintext_modulus) @@ -72,7 +84,7 @@ impl Fhe { .build_arc()?; let crp = CommonRandomPoly::new(¶ms, &mut rng)?; - Ok(Fhe::new(params, crp, rng)?) + Ok(Fhe::new(params, crp, rng)) } } diff --git a/packages/ciphernode/core/src/lib.rs b/packages/ciphernode/core/src/lib.rs index def9c502..9cd3e63a 100644 --- a/packages/ciphernode/core/src/lib.rs +++ b/packages/ciphernode/core/src/lib.rs @@ -16,6 +16,10 @@ mod p2p; mod plaintext_aggregator; mod publickey_aggregator; mod serializers; +mod ciphernode_sequencer; +mod plaintext_sequencer; +mod publickey_sequencer; +mod registry; // TODO: this is too permissive pub use actix::prelude::*; @@ -28,17 +32,11 @@ pub use fhe::*; pub use logger::*; pub use p2p::*; pub use publickey_aggregator::*; - -pub use actix::prelude::*; -pub use ciphernode::*; +pub use publickey_sequencer::*; +pub use plaintext_sequencer::*; +pub use plaintext_aggregator::*; pub use ciphernode_selector::*; -pub use ciphernode_supervisor::*; -pub use data::*; -pub use eventbus::*; -pub use events::*; -pub use fhe::*; -pub use p2p::*; -pub use publickey_aggregator::*; +pub use ciphernode_sequencer::*; // TODO: move these out to a test folder #[cfg(test)] @@ -129,7 +127,7 @@ mod tests { ) -> Result<(Addr, Arc, CommonRandomPoly)> { let (params, crp) = setup_bfv_params(&moduli, degree, plaintext_modulus, rng1)?; Ok(( - Fhe::new(params.clone(), crp.clone(), rng2)?.start(), + Fhe::new(params.clone(), crp.clone(), rng2).start(), params, crp, )) diff --git a/packages/ciphernode/core/src/plaintext_aggregator.rs b/packages/ciphernode/core/src/plaintext_aggregator.rs index fd142550..9b5789c1 100644 --- a/packages/ciphernode/core/src/plaintext_aggregator.rs +++ b/packages/ciphernode/core/src/plaintext_aggregator.rs @@ -75,6 +75,16 @@ impl Actor for PlaintextAggregator { type Context = Context; } +impl Handler for PlaintextAggregator { + type Result = (); + fn handle(&mut self, msg: EnclaveEvent, ctx: &mut Self::Context) -> Self::Result { + match msg { + EnclaveEvent::DecryptionshareCreated { data, .. } => ctx.notify(data), + _ => () + } + } +} + impl Handler for PlaintextAggregator { type Result = Result<()>; fn handle(&mut self, event: DecryptionshareCreated, ctx: &mut Self::Context) -> Self::Result { @@ -94,7 +104,7 @@ impl Handler for PlaintextAggregator { // Check the state and if it has changed to the computing if let PlaintextAggregatorState::Computing { shares } = &self.state { - ctx.address().do_send(ComputeAggregate { + ctx.notify(ComputeAggregate { shares: shares.clone(), }) } diff --git a/packages/ciphernode/core/src/plaintext_sequencer.rs b/packages/ciphernode/core/src/plaintext_sequencer.rs new file mode 100644 index 00000000..87de9c5e --- /dev/null +++ b/packages/ciphernode/core/src/plaintext_sequencer.rs @@ -0,0 +1,43 @@ +// sequence and persist events for a single E3 request in the correct order +// TODO: spawn and store a ciphernode upon start and forward all events to it in order +// TODO: if the ciphernode fails restart the node by replaying all stored events back to it + +use actix::prelude::*; + +use crate::{E3id, EnclaveEvent, EventBus, Fhe, PlaintextAggregator}; + +pub struct PlaintextSequencer { + fhe: Addr, + e3_id: E3id, + bus: Addr, + nodecount: usize, + child: Option>, +} +impl PlaintextSequencer { + pub fn new(fhe: Addr, e3_id: E3id, bus: Addr, nodecount: usize) -> Self { + Self { + fhe, + e3_id, + bus, + nodecount, + child: None, + } + } +} +impl Actor for PlaintextSequencer { + type Context = Context; +} + +impl Handler for PlaintextSequencer { + type Result = (); + fn handle(&mut self, msg: EnclaveEvent, ctx: &mut Self::Context) -> Self::Result { + let fhe = self.fhe.clone(); + let bus = self.bus.clone(); + let nodecount = self.nodecount; + let e3_id = self.e3_id.clone(); + let sink = self + .child + .get_or_insert_with(|| PlaintextAggregator::new(fhe, bus, e3_id, nodecount).start()); + sink.do_send(msg); + } +} diff --git a/packages/ciphernode/core/src/publickey_aggregator.rs b/packages/ciphernode/core/src/publickey_aggregator.rs index 001ed2d8..c49339a9 100644 --- a/packages/ciphernode/core/src/publickey_aggregator.rs +++ b/packages/ciphernode/core/src/publickey_aggregator.rs @@ -91,6 +91,16 @@ impl Actor for PublicKeyAggregator { type Context = Context; } +impl Handler for PublicKeyAggregator { + type Result = (); + fn handle(&mut self, msg: EnclaveEvent, ctx: &mut Self::Context) -> Self::Result { + match msg { + EnclaveEvent::KeyshareCreated { data, .. } => ctx.notify(data), + _ => () + } + } +} + impl Handler for PublicKeyAggregator { type Result = Result<()>; @@ -112,7 +122,7 @@ impl Handler for PublicKeyAggregator { // Check the state and if it has changed to the computing if let PublicKeyAggregatorState::Computing { keyshares } = &self.state { - ctx.address().do_send(ComputeAggregate { + ctx.notify(ComputeAggregate { keyshares: keyshares.clone(), }) } diff --git a/packages/ciphernode/core/src/publickey_sequencer.rs b/packages/ciphernode/core/src/publickey_sequencer.rs new file mode 100644 index 00000000..8a2593c4 --- /dev/null +++ b/packages/ciphernode/core/src/publickey_sequencer.rs @@ -0,0 +1,45 @@ +// sequence and persist events for a single E3 request in the correct order +// TODO: spawn and store a ciphernode upon start and forward all events to it in order +// TODO: if the ciphernode fails restart the node by replaying all stored events back to it + +use actix::prelude::*; + +use crate::{E3id, EnclaveEvent, EventBus, Fhe, PublicKeyAggregator}; + +pub struct PublicKeySequencer { + fhe: Addr, + e3_id: E3id, + bus: Addr, + nodecount: usize, + child: Option>, +} + +impl PublicKeySequencer { + pub fn new(fhe: Addr, e3_id: E3id, bus: Addr, nodecount: usize) -> Self { + Self { + fhe, + e3_id, + bus, + nodecount, + child: None, + } + } +} + +impl Actor for PublicKeySequencer { + type Context = Context; +} + +impl Handler for PublicKeySequencer { + type Result = (); + fn handle(&mut self, msg: EnclaveEvent, ctx: &mut Self::Context) -> Self::Result { + let fhe = self.fhe.clone(); + let bus = self.bus.clone(); + let nodecount = self.nodecount; + let e3_id = self.e3_id.clone(); + let sink = self + .child + .get_or_insert_with(|| PublicKeyAggregator::new(fhe, bus, e3_id, nodecount).start()); + sink.do_send(msg); + } +} diff --git a/packages/ciphernode/core/src/registry.rs b/packages/ciphernode/core/src/registry.rs new file mode 100644 index 00000000..6a13120b --- /dev/null +++ b/packages/ciphernode/core/src/registry.rs @@ -0,0 +1,115 @@ +use crate::{ + CiphernodeSequencer, Data, E3id, EnclaveEvent, EventBus, Fhe, PlaintextSequencer, + PublicKeySequencer, +}; +use actix::prelude::*; +use rand_chacha::ChaCha20Rng; +use std::collections::HashMap; + +pub struct Registry { + bus: Addr, + ciphernodes: HashMap>, + data: Addr, + fhes: HashMap>, + nodecount: usize, + plaintexts: HashMap>, + public_keys: HashMap>, + rng: ChaCha20Rng, +} + +impl Actor for Registry { + type Context = Context; +} + +impl Handler for Registry { + type Result = (); + + fn handle(&mut self, msg: EnclaveEvent, _ctx: &mut Self::Context) -> Self::Result { + let e3_id = E3id::from(msg.clone()); + + match msg.clone() { + EnclaveEvent::CommitteeRequested { .. } => { + let fhe_factory = self.fhe_factory(); + let fhe = store(&e3_id, &mut self.fhes, fhe_factory); + + let public_key_sequencer_factory = self.public_key_sequencer_factory(e3_id.clone(), fhe.clone()); + store(&e3_id, &mut self.public_keys, public_key_sequencer_factory); + + let ciphernode_sequencer_factory = self.ciphernode_sequencer_factory(fhe.clone()); + store(&e3_id, &mut self.ciphernodes, ciphernode_sequencer_factory); + } + EnclaveEvent::CiphertextOutputPublished { .. } => { + let Some(fhe) = self.fhes.get(&e3_id) else { + return; + }; + let plaintext_sequencer_factory = self.plaintext_sequencer_factory(e3_id.clone(), fhe.clone()); + store(&e3_id, &mut self.plaintexts, plaintext_sequencer_factory); + } + _ => (), + }; + + self.forward_message(&e3_id, msg); + } +} + +impl Registry { + fn fhe_factory(&self) -> impl FnOnce() -> Addr { + let rng = self.rng.clone(); + move || { + let moduli = &vec![0x3FFFFFFF000001]; + let degree = 2048; + let plaintext_modulus = 1032193; + Fhe::from_raw_params(moduli, degree, plaintext_modulus, rng) + .unwrap() + .start() + } + } + + fn public_key_sequencer_factory( + &self, + e3_id: E3id, + fhe: Addr, + ) -> impl FnOnce() -> Addr { + let bus = self.bus.clone(); + let nodecount = self.nodecount; + move || PublicKeySequencer::new(fhe, e3_id, bus, nodecount).start() + } + + fn ciphernode_sequencer_factory(&self, fhe: Addr) -> impl FnOnce() -> Addr { + let data = self.data.clone(); + let bus = self.bus.clone(); + move || CiphernodeSequencer::new(fhe, data, bus).start() + } + + fn plaintext_sequencer_factory( + &self, + e3_id: E3id, + fhe: Addr, + ) -> impl FnOnce() -> Addr { + let bus = self.bus.clone(); + let nodecount = self.nodecount; + move || PlaintextSequencer::new(fhe, e3_id, bus, nodecount).start() + } + + fn forward_message(&self, e3_id: &E3id, msg: EnclaveEvent) { + if let Some(act) = self.public_keys.get(&e3_id) { + act.clone().recipient().do_send(msg.clone()); + } + + if let Some(act) = self.plaintexts.get(&e3_id) { + act.do_send(msg.clone()); + } + + if let Some(act) = self.ciphernodes.get(&e3_id) { + act.do_send(msg.clone()); + } + } +} + +fn store(e3_id: &E3id, map: &mut HashMap>, creator: F) -> Addr +where + T: Actor>, + F: FnOnce() -> Addr, +{ + map.entry(e3_id.clone()).or_insert_with(creator).clone() +} From 26011ce5569d30327d965c54e723de906d305136 Mon Sep 17 00:00:00 2001 From: nginnever Date: Wed, 11 Sep 2024 12:09:48 -0700 Subject: [PATCH 44/87] score address tuple --- packages/ciphernode/sortition/Cargo.toml | 2 +- packages/ciphernode/sortition/src/distance.rs | 22 ++++++++----------- 2 files changed, 10 insertions(+), 14 deletions(-) diff --git a/packages/ciphernode/sortition/Cargo.toml b/packages/ciphernode/sortition/Cargo.toml index 434fcb99..b4b794b2 100644 --- a/packages/ciphernode/sortition/Cargo.toml +++ b/packages/ciphernode/sortition/Cargo.toml @@ -9,7 +9,7 @@ path = "src/lib.rs" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -num = "0.4.0" +num = "0.4.3" # Core enclave-core = { path = "../core" } diff --git a/packages/ciphernode/sortition/src/distance.rs b/packages/ciphernode/sortition/src/distance.rs index 9c0611b7..ce9ad5ac 100644 --- a/packages/ciphernode/sortition/src/distance.rs +++ b/packages/ciphernode/sortition/src/distance.rs @@ -13,24 +13,20 @@ impl DistanceSortition { } pub fn get_committee(&mut self) -> Vec
{ - let hashed = self.registered_nodes.iter() + let scores = self.registered_nodes.iter() .map(|address| { let concat = address.to_string() + &self.random_seed.to_string(); - let hash = keccak256(concat); - hash.to_string() - }) - .collect::>(); - - let numeric = hashed.iter() - .map(|hash| - { + let hash = keccak256(concat).to_string(); let without_prefix = hash.trim_start_matches("0x"); - let z = BigInt::from_str_radix(without_prefix, 16); - println!("{:?}", z); - z.unwrap() + let z = BigInt::from_str_radix(without_prefix, 16).unwrap(); + let score = z - BigInt::from(self.random_seed); + (score, *address) }) - .collect::>(); + .collect::>(); + + println!("{:?}", scores); + self.registered_nodes.clone() } } \ No newline at end of file From 190d2463da52d90c9ec2db5ae1d92b41f0393772 Mon Sep 17 00:00:00 2001 From: nginnever Date: Wed, 11 Sep 2024 12:27:23 -0700 Subject: [PATCH 45/87] distance result --- packages/ciphernode/sortition/src/distance.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/ciphernode/sortition/src/distance.rs b/packages/ciphernode/sortition/src/distance.rs index ce9ad5ac..01b1e958 100644 --- a/packages/ciphernode/sortition/src/distance.rs +++ b/packages/ciphernode/sortition/src/distance.rs @@ -12,8 +12,8 @@ impl DistanceSortition { Self { random_seed, registered_nodes, size } } - pub fn get_committee(&mut self) -> Vec
{ - let scores = self.registered_nodes.iter() + pub fn get_committee(&mut self) -> Vec<(BigInt, Address)> { + let mut scores = self.registered_nodes.iter() .map(|address| { let concat = address.to_string() + &self.random_seed.to_string(); @@ -27,6 +27,8 @@ impl DistanceSortition { println!("{:?}", scores); - self.registered_nodes.clone() + scores.sort_by(|a, b| a.0.cmp(&b.0)); + let result = scores[0..self.size].to_vec(); + result } } \ No newline at end of file From c8b483c4cd826a3200e9165004ce355ca631ca2a Mon Sep 17 00:00:00 2001 From: nginnever Date: Wed, 11 Sep 2024 15:10:56 -0700 Subject: [PATCH 46/87] index sortition --- packages/ciphernode/sortition/Cargo.toml | 1 + packages/ciphernode/sortition/src/distance.rs | 4 +-- packages/ciphernode/sortition/src/index.rs | 36 +++++++++++++++++++ 3 files changed, 38 insertions(+), 3 deletions(-) diff --git a/packages/ciphernode/sortition/Cargo.toml b/packages/ciphernode/sortition/Cargo.toml index b4b794b2..c4f69dd2 100644 --- a/packages/ciphernode/sortition/Cargo.toml +++ b/packages/ciphernode/sortition/Cargo.toml @@ -10,6 +10,7 @@ path = "src/lib.rs" [dependencies] num = "0.4.3" +rand = "0.8.5" # Core enclave-core = { path = "../core" } diff --git a/packages/ciphernode/sortition/src/distance.rs b/packages/ciphernode/sortition/src/distance.rs index 01b1e958..79b6bb86 100644 --- a/packages/ciphernode/sortition/src/distance.rs +++ b/packages/ciphernode/sortition/src/distance.rs @@ -24,9 +24,7 @@ impl DistanceSortition { (score, *address) }) .collect::>(); - - println!("{:?}", scores); - + scores.sort_by(|a, b| a.0.cmp(&b.0)); let result = scores[0..self.size].to_vec(); result diff --git a/packages/ciphernode/sortition/src/index.rs b/packages/ciphernode/sortition/src/index.rs index e69de29b..da7162cc 100644 --- a/packages/ciphernode/sortition/src/index.rs +++ b/packages/ciphernode/sortition/src/index.rs @@ -0,0 +1,36 @@ +use rand::{rngs::StdRng, Rng, SeedableRng}; + +pub struct IndexSortition { + pub random_seed: u64, + pub num_nodes: usize, + pub size: usize, +} + +impl IndexSortition { + pub fn new(random_seed: u64, num_nodes: usize, size: usize) -> Self { + Self { random_seed, num_nodes, size } + } + + fn get_committee(&mut self) -> Vec { + // Initialize a vector with indices of nodes as elements + let mut leaf_indices: Vec = (0..self.num_nodes).collect(); + // Initialize an empty vector to store the committee + let mut committee: Vec = Vec::new(); + + // Initialize the random number generator with the given `seed` + let mut rng = StdRng::seed_from_u64(self.random_seed); + + // Partial shuffle for only the `committee_size` number of nodes + for _ in 0..self.size { + // Choose a random leaf index from the `leaf_indices` + let j = rng.gen_range(0..leaf_indices.len()); + // Push the chosen leaf index to the `committee` + committee.push(leaf_indices[j]); + // Remove the chosen leaf index from the `leaf_indices` + leaf_indices.remove(j); + } + + // Return the leaf indices of the selected committee + committee + } +} \ No newline at end of file From 3a298ee5f324ba1c503911f73a809ad9c52e9f1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=B3=CE=BB?= Date: Thu, 12 Sep 2024 11:40:54 +1000 Subject: [PATCH 47/87] Setup sequencers with events (#56) * Hook up registry and sequencer approach * Fix up cargo lock * Remove superfluous logging --- packages/ciphernode/Cargo.lock | 43 +++++ packages/ciphernode/core/src/ciphernode.rs | 7 +- .../core/src/ciphernode_sequencer.rs | 2 +- packages/ciphernode/core/src/events.rs | 5 + packages/ciphernode/core/src/fhe.rs | 51 ++++-- packages/ciphernode/core/src/lib.rs | 167 +++++++++++------- .../core/src/plaintext_aggregator.rs | 1 - .../core/src/publickey_aggregator.rs | 1 + .../core/src/publickey_sequencer.rs | 9 +- packages/ciphernode/core/src/registry.rs | 101 +++++++++-- .../ciphernode/enclave_node/src/bin/cmd.rs | 44 ++--- 11 files changed, 303 insertions(+), 128 deletions(-) diff --git a/packages/ciphernode/Cargo.lock b/packages/ciphernode/Cargo.lock index 99c21fd2..1d8ba935 100644 --- a/packages/ciphernode/Cargo.lock +++ b/packages/ciphernode/Cargo.lock @@ -1898,6 +1898,7 @@ version = "0.1.0" dependencies = [ "actix-rt", "alloy", + "alloy-primitives 0.6.4", "async-std", "bfv", "enclave-core", @@ -1906,6 +1907,7 @@ dependencies = [ "fhe-traits", "fhe-util", "p2p", + "sortition", "tokio", ] @@ -3840,6 +3842,20 @@ dependencies = [ "winapi", ] +[[package]] +name = "num" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" +dependencies = [ + "num-bigint", + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits", +] + [[package]] name = "num-bigint" version = "0.4.6" @@ -3902,6 +3918,17 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-rational" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" +dependencies = [ + "num-bigint", + "num-integer", + "num-traits", +] + [[package]] name = "num-traits" version = "0.2.19" @@ -5245,6 +5272,22 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "sortition" +version = "0.1.0" +dependencies = [ + "actix", + "alloy", + "alloy-primitives 0.6.4", + "alloy-sol-types 0.6.4", + "async-std", + "enclave-core", + "eyre", + "futures-util", + "num", + "rand", +] + [[package]] name = "spin" version = "0.5.2" diff --git a/packages/ciphernode/core/src/ciphernode.rs b/packages/ciphernode/core/src/ciphernode.rs index e9f20b60..99ebd6a3 100644 --- a/packages/ciphernode/core/src/ciphernode.rs +++ b/packages/ciphernode/core/src/ciphernode.rs @@ -1,5 +1,10 @@ use crate::{ - data::{Data, Insert}, eventbus::EventBus, events::{CommitteeRequested, EnclaveEvent, KeyshareCreated}, fhe::{Fhe, GenerateKeyshare}, CiphernodeSelected, CiphertextOutputPublished, DecryptCiphertext, DecryptionshareCreated, Get, Subscribe + data::{Data, Insert}, + eventbus::EventBus, + events::{EnclaveEvent, KeyshareCreated}, + fhe::{Fhe, GenerateKeyshare}, + CiphernodeSelected, CiphertextOutputPublished, DecryptCiphertext, DecryptionshareCreated, Get, + Subscribe, }; use actix::prelude::*; use anyhow::Result; diff --git a/packages/ciphernode/core/src/ciphernode_sequencer.rs b/packages/ciphernode/core/src/ciphernode_sequencer.rs index d67702d5..ae3b48c9 100644 --- a/packages/ciphernode/core/src/ciphernode_sequencer.rs +++ b/packages/ciphernode/core/src/ciphernode_sequencer.rs @@ -28,7 +28,7 @@ impl Actor for CiphernodeSequencer { impl Handler for CiphernodeSequencer { type Result = (); - fn handle(&mut self, msg: EnclaveEvent, ctx: &mut Self::Context) -> Self::Result { + fn handle(&mut self, msg: EnclaveEvent, _ctx: &mut Self::Context) -> Self::Result { let bus = self.bus.clone(); let fhe = self.fhe.clone(); let data = self.data.clone(); diff --git a/packages/ciphernode/core/src/events.rs b/packages/ciphernode/core/src/events.rs index ff6300fd..62a651dd 100644 --- a/packages/ciphernode/core/src/events.rs +++ b/packages/ciphernode/core/src/events.rs @@ -231,6 +231,11 @@ pub struct CommitteeRequested { pub nodecount: usize, pub threshold: usize, pub sortition_seed: u32, + // fhe params + pub moduli: Vec, + pub degree: usize, + pub plaintext_modulus: u64, + pub crp: Vec // computation_type: ??, // TODO: // execution_model_type: ??, // TODO: // input_deadline: ??, // TODO: diff --git a/packages/ciphernode/core/src/fhe.rs b/packages/ciphernode/core/src/fhe.rs index f78cede0..88d2fbb5 100644 --- a/packages/ciphernode/core/src/fhe.rs +++ b/packages/ciphernode/core/src/fhe.rs @@ -11,10 +11,13 @@ use fhe::{ bfv::{BfvParameters, BfvParametersBuilder, Encoding, Plaintext, PublicKey, SecretKey}, mbfv::{AggregateIter, CommonRandomPoly, DecryptionShare, PublicKeyShare}, }; -use fhe_traits::FheDecoder; +use fhe_traits::{FheDecoder, Serialize}; use rand::SeedableRng; -use rand_chacha::ChaCha20Rng; -use std::{hash::Hash, sync::Arc}; +use rand_chacha::{ChaCha20Rng, ChaCha8Rng}; +use std::{ + hash::Hash, + sync::{Arc, Mutex}, +}; #[derive(Message, Clone, Debug, PartialEq, Eq, Hash)] #[rtype(result = "Result<(Vec, Vec)>")] @@ -41,11 +44,13 @@ pub struct DecryptCiphertext { pub ciphertext: Vec, } +pub type SharedRng = Arc>; + /// Fhe library adaptor. All FHE computations should happen through this actor. pub struct Fhe { params: Arc, crp: CommonRandomPoly, - rng: ChaCha20Rng, + rng: SharedRng, } impl Actor for Fhe { @@ -53,20 +58,33 @@ impl Actor for Fhe { } impl Fhe { - pub fn new(params: Arc, crp: CommonRandomPoly, rng: ChaCha20Rng) -> Self { + pub fn new(params: Arc, crp: CommonRandomPoly, rng: SharedRng) -> Self { Self { params, crp, rng } } - pub fn try_default() -> Result { + // Deprecated + pub fn try_default() -> Result { + // TODO: The production bootstrapping of this will involve receiving a crp bytes and param + // input form the event let moduli = &vec![0x3FFFFFFF000001]; let degree = 2048usize; let plaintext_modulus = 1032193u64; - let rng = ChaCha20Rng::from_entropy(); + let rng = Arc::new(Mutex::new(ChaCha20Rng::from_entropy())); + let crp = CommonRandomPoly::new( + &BfvParametersBuilder::new() + .set_degree(degree) + .set_plaintext_modulus(plaintext_modulus) + .set_moduli(&moduli) + .build_arc()?, + &mut *rng.lock().unwrap(), + )? + .to_bytes(); Ok(Fhe::from_raw_params( moduli, degree, plaintext_modulus, + &crp, rng, )?) } @@ -75,24 +93,25 @@ impl Fhe { moduli: &[u64], degree: usize, plaintext_modulus: u64, - mut rng: ChaCha20Rng, + crp: &[u8], + rng: Arc>, ) -> Result { let params = BfvParametersBuilder::new() .set_degree(degree) .set_plaintext_modulus(plaintext_modulus) .set_moduli(&moduli) .build_arc()?; - let crp = CommonRandomPoly::new(¶ms, &mut rng)?; - Ok(Fhe::new(params, crp, rng)) + Ok(Fhe::new(params.clone(), CommonRandomPoly::deserialize(crp, ¶ms)?, rng)) } } impl Handler for Fhe { type Result = Result<(Vec, Vec)>; fn handle(&mut self, _event: GenerateKeyshare, _: &mut Self::Context) -> Self::Result { - let sk_share = { SecretKey::random(&self.params, &mut self.rng) }; - let pk_share = { PublicKeyShare::new(&sk_share, self.crp.clone(), &mut self.rng)? }; + let sk_share = { SecretKey::random(&self.params, &mut *self.rng.lock().unwrap()) }; + let pk_share = + { PublicKeyShare::new(&sk_share, self.crp.clone(), &mut *self.rng.lock().unwrap())? }; Ok(( SecretKeySerializer::to_bytes(sk_share, self.params.clone())?, PublicKeyShareSerializer::to_bytes(pk_share, self.params.clone(), self.crp.clone())?, @@ -110,7 +129,7 @@ impl Handler for Fhe { let secret_key = SecretKeySerializer::from_bytes(&unsafe_secret)?; let ct = Arc::new(CiphertextSerializer::from_bytes(&ciphertext)?); - let inner = DecryptionShare::new(&secret_key, &ct, &mut self.rng).unwrap(); + let inner = DecryptionShare::new(&secret_key, &ct, &mut *self.rng.lock().unwrap()).unwrap(); Ok(DecryptionShareSerializer::to_bytes( inner, @@ -153,8 +172,10 @@ impl Handler for Fhe { // XXX: how do we know what the expected output of the plaintext is in order to decrypt // here for serialization? // This would be dependent on the computation that is running. - // For now assuming testcase of Vec - // This could be determined based on the "program" config + // For now assuming testcase of Vec and currently represents a "HARDCODED" program + // output format of Vec + // This could be determined based on the "program" config events + let decoded = Vec::::try_decode(&plaintext, Encoding::poly())?; let decoded = &decoded[0..2]; // TODO: this will be computation dependent Ok(bincode::serialize(&decoded)?) diff --git a/packages/ciphernode/core/src/lib.rs b/packages/ciphernode/core/src/lib.rs index 9cd3e63a..b47b843c 100644 --- a/packages/ciphernode/core/src/lib.rs +++ b/packages/ciphernode/core/src/lib.rs @@ -4,6 +4,7 @@ mod ciphernode; mod ciphernode_selector; +mod ciphernode_sequencer; mod ciphernode_supervisor; mod data; mod enclave_contract; @@ -14,16 +15,17 @@ mod logger; mod ordered_set; mod p2p; mod plaintext_aggregator; -mod publickey_aggregator; -mod serializers; -mod ciphernode_sequencer; mod plaintext_sequencer; +mod publickey_aggregator; mod publickey_sequencer; mod registry; +mod serializers; // TODO: this is too permissive pub use actix::prelude::*; pub use ciphernode::*; +pub use ciphernode_selector::*; +pub use ciphernode_sequencer::*; pub use ciphernode_supervisor::*; pub use data::*; pub use eventbus::*; @@ -31,12 +33,11 @@ pub use events::*; pub use fhe::*; pub use logger::*; pub use p2p::*; +pub use plaintext_aggregator::*; +pub use plaintext_sequencer::*; pub use publickey_aggregator::*; pub use publickey_sequencer::*; -pub use plaintext_sequencer::*; -pub use plaintext_aggregator::*; -pub use ciphernode_selector::*; -pub use ciphernode_sequencer::*; +pub use registry::*; // TODO: move these out to a test folder #[cfg(test)] @@ -55,7 +56,7 @@ mod tests { PublicKeyShareSerializer, }, CiphernodeSelected, CiphertextOutputPublished, DecryptionshareCreated, PlaintextAggregated, - ResetHistory, + Registry, ResetHistory, SharedRng, }; use actix::prelude::*; use anyhow::*; @@ -63,7 +64,7 @@ mod tests { bfv::{BfvParameters, BfvParametersBuilder, Encoding, Plaintext, PublicKey, SecretKey}, mbfv::{AggregateIter, CommonRandomPoly, DecryptionShare, PublicKeyShare}, }; - use fhe_traits::{FheEncoder, FheEncrypter}; + use fhe_traits::{FheEncoder, FheEncrypter, Serialize}; use rand::SeedableRng; use rand_chacha::ChaCha20Rng; use std::{sync::Arc, time::Duration}; @@ -71,66 +72,82 @@ mod tests { use tokio::{sync::mpsc::channel, time::sleep}; // Simulating a local node - async fn setup_local_ciphernode( - bus: Addr, - fhe: Addr, - logging: bool, - ) -> (Addr, Addr) { + async fn setup_local_ciphernode(bus: Addr, rng: SharedRng, logging: bool) { // create data actor for saving data let data = Data::new(logging).start(); // TODO: Use a sled backed Data Actor // create ciphernode actor for managing ciphernode flow CiphernodeSelector::attach(bus.clone()); - - let node = Ciphernode::attach(bus.clone(), fhe.clone(), data.clone()).await; - - // setup the committee manager to generate the comittee public keys - CiphernodeSupervisor::attach(bus.clone(), fhe.clone()); - (node, data) + Registry::attach(bus.clone(), data.clone(), rng).await; } fn setup_bfv_params( moduli: &[u64], degree: usize, plaintext_modulus: u64, - mut rng: ChaCha20Rng, - ) -> Result<(Arc, CommonRandomPoly)> { - let params = BfvParametersBuilder::new() + ) -> Arc { + BfvParametersBuilder::new() .set_degree(degree) .set_plaintext_modulus(plaintext_modulus) .set_moduli(&moduli) - .build_arc()?; - let crp = CommonRandomPoly::new(¶ms, &mut rng)?; - Ok((params, crp)) + .build_arc() + .unwrap() + } + + fn set_up_crp(params: Arc, rng: SharedRng) -> CommonRandomPoly { + CommonRandomPoly::new(¶ms, &mut *rng.lock().unwrap()).unwrap() } fn generate_pk_share( params: Arc, crp: CommonRandomPoly, - mut rng: ChaCha20Rng, - ) -> Result<(Vec, ChaCha20Rng, SecretKey)> { - let sk = SecretKey::random(¶ms, &mut rng); + rng: SharedRng, + ) -> Result<(Vec, SecretKey)> { + let sk = SecretKey::random(¶ms, &mut *rng.lock().unwrap()); let pk = PublicKeyShareSerializer::to_bytes( - PublicKeyShare::new(&sk, crp.clone(), &mut rng)?, + PublicKeyShare::new(&sk, crp.clone(), &mut *rng.lock().unwrap())?, params.clone(), crp, )?; - Ok((pk, rng, sk)) + Ok((pk, sk)) } - fn setup_global_fhe_actor( + // fn setup_global_fhe_actor( + // moduli: &[u64], + // degree: usize, + // plaintext_modulus: u64, + // rng: SharedRng, + // ) -> Result<(Addr, Arc, CommonRandomPoly)> { + // let (params, crp) = setup_bfv_params(&moduli, degree, plaintext_modulus, rng.clone())?; + // Ok(( + // Fhe::new(params.clone(), crp.clone(), rng.clone()).start(), + // params, + // crp, + // )) + // } + // + struct NewParamsWithCrp { + pub moduli: Vec, + pub degree: usize, + pub plaintext_modulus: u64, + pub crp_bytes: Vec, + pub params: Arc, + } + fn setup_crp_params( moduli: &[u64], degree: usize, plaintext_modulus: u64, - rng1: ChaCha20Rng, - rng2: ChaCha20Rng, - ) -> Result<(Addr, Arc, CommonRandomPoly)> { - let (params, crp) = setup_bfv_params(&moduli, degree, plaintext_modulus, rng1)?; - Ok(( - Fhe::new(params.clone(), crp.clone(), rng2).start(), + rng: SharedRng, + ) -> NewParamsWithCrp { + let params = setup_bfv_params(moduli, degree, plaintext_modulus); + let crp = set_up_crp(params.clone(), rng); + NewParamsWithCrp { + moduli: moduli.to_vec(), + degree, + plaintext_modulus, + crp_bytes: crp.to_bytes(), params, - crp, - )) + } } #[actix::test] @@ -138,26 +155,30 @@ mod tests { // Setup EventBus let bus = EventBus::new(true).start(); - // Setup global FHE actor - let (fhe, ..) = setup_global_fhe_actor( - &vec![0x3FFFFFFF000001], - 2048, - 1032193, - ChaCha20Rng::seed_from_u64(42), - ChaCha20Rng::seed_from_u64(42), - )?; - - setup_local_ciphernode(bus.clone(), fhe.clone(), true).await; - setup_local_ciphernode(bus.clone(), fhe.clone(), true).await; - setup_local_ciphernode(bus.clone(), fhe.clone(), true).await; + let rng = Arc::new(std::sync::Mutex::new(ChaCha20Rng::seed_from_u64(42))); + setup_local_ciphernode(bus.clone(), rng.clone(), true).await; + setup_local_ciphernode(bus.clone(), rng.clone(), true).await; + setup_local_ciphernode(bus.clone(), rng.clone(), true).await; let e3_id = E3id::new("1234"); + let NewParamsWithCrp { + moduli, + degree, + plaintext_modulus, + crp_bytes, + params, + } = setup_crp_params(&vec![0x3FFFFFFF000001], 2048, 1032193, Arc::new(std::sync::Mutex::new(ChaCha20Rng::seed_from_u64(42)))); + let event = EnclaveEvent::from(CommitteeRequested { e3_id: e3_id.clone(), nodecount: 3, threshold: 123, sortition_seed: 123, + moduli: moduli.clone(), + degree, + plaintext_modulus, + crp: crp_bytes.clone(), }); // Send the computation requested event @@ -168,18 +189,14 @@ mod tests { let history = bus.send(GetHistory).await?; - let (params, crp) = setup_bfv_params( - &vec![0x3FFFFFFF000001], - 2048, - 1032193, - ChaCha20Rng::seed_from_u64(42), - )?; + let rng_test = Arc::new(std::sync::Mutex::new(ChaCha20Rng::seed_from_u64(42))); + + let crpoly = CommonRandomPoly::deserialize(&crp_bytes.clone(), ¶ms)?; // Passing rng through function chain to ensure it matches usage in system above - let rng = ChaCha20Rng::seed_from_u64(42); - let (p1, rng, sk1) = generate_pk_share(params.clone(), crp.clone(), rng)?; - let (p2, rng, sk2) = generate_pk_share(params.clone(), crp.clone(), rng)?; - let (p3, mut rng, sk3) = generate_pk_share(params.clone(), crp.clone(), rng)?; + let (p1, sk1) = generate_pk_share(params.clone(), crpoly.clone(), rng_test.clone())?; + let (p2, sk2) = generate_pk_share(params.clone(), crpoly.clone(), rng_test.clone())?; + let (p3, sk3) = generate_pk_share(params.clone(), crpoly.clone(), rng_test.clone())?; let pubkey: PublicKey = vec![p1.clone(), p2.clone(), p3.clone()] .iter() @@ -195,6 +212,10 @@ mod tests { nodecount: 3, threshold: 123, sortition_seed: 123, + moduli, + degree, + plaintext_modulus, + crp: crp_bytes, }), EnclaveEvent::from(CiphernodeSelected { e3_id: e3_id.clone(), @@ -243,17 +264,17 @@ mod tests { let arc_ct = Arc::new(ciphertext); let ds1 = DecryptionShareSerializer::to_bytes( - DecryptionShare::new(&sk1, &arc_ct, &mut rng).unwrap(), + DecryptionShare::new(&sk1, &arc_ct, &mut *rng_test.lock().unwrap()).unwrap(), params.clone(), arc_ct.clone(), )?; let ds2 = DecryptionShareSerializer::to_bytes( - DecryptionShare::new(&sk2, &arc_ct, &mut rng).unwrap(), + DecryptionShare::new(&sk2, &arc_ct, &mut *rng_test.lock().unwrap()).unwrap(), params.clone(), arc_ct.clone(), )?; let ds3 = DecryptionShareSerializer::to_bytes( - DecryptionShare::new(&sk3, &arc_ct, &mut rng).unwrap(), + DecryptionShare::new(&sk3, &arc_ct, &mut *rng_test.lock().unwrap()).unwrap(), params.clone(), arc_ct.clone(), )?; @@ -261,8 +282,10 @@ mod tests { // let ds1 = sk1 bus.send(event.clone()).await?; + sleep(Duration::from_millis(1)).await; // need to push to next tick let history = bus.send(GetHistory).await?; + assert_eq!(history.len(), 5); assert_eq!( history, vec![ @@ -316,6 +339,10 @@ mod tests { nodecount: 3, threshold: 123, sortition_seed: 123, + moduli: vec![0x3FFFFFFF000001], + degree: 2048, + plaintext_modulus: 1032193, + crp: vec![1, 2, 3, 4], }); let evt_2 = EnclaveEvent::from(CommitteeRequested { @@ -323,6 +350,10 @@ mod tests { nodecount: 3, threshold: 123, sortition_seed: 123, + moduli: vec![0x3FFFFFFF000001], + degree: 2048, + plaintext_modulus: 1032193, + crp: vec![1, 2, 3, 4], }); let local_evt_3 = EnclaveEvent::from(CiphernodeSelected { @@ -349,7 +380,7 @@ mod tests { assert_eq!( history, vec![evt_1, evt_2, local_evt_3], // all local events that have been broadcast but no - // events from the loopback + // events from the loopback "P2p must not retransmit forwarded event to event bus" ); @@ -370,6 +401,10 @@ mod tests { nodecount: 3, threshold: 123, sortition_seed: 123, + moduli: vec![0x3FFFFFFF000001], + degree: 2048, + plaintext_modulus: 1032193, + crp: vec![1, 2, 3, 4], }); // lets send an event from the network diff --git a/packages/ciphernode/core/src/plaintext_aggregator.rs b/packages/ciphernode/core/src/plaintext_aggregator.rs index 9b5789c1..3146ee8b 100644 --- a/packages/ciphernode/core/src/plaintext_aggregator.rs +++ b/packages/ciphernode/core/src/plaintext_aggregator.rs @@ -132,7 +132,6 @@ impl Handler for PlaintextAggregator { decrypted_output, e3_id: act.e3_id.clone(), }); - act.bus.do_send(event); Ok(()) diff --git a/packages/ciphernode/core/src/publickey_aggregator.rs b/packages/ciphernode/core/src/publickey_aggregator.rs index c49339a9..510fed03 100644 --- a/packages/ciphernode/core/src/publickey_aggregator.rs +++ b/packages/ciphernode/core/src/publickey_aggregator.rs @@ -105,6 +105,7 @@ impl Handler for PublicKeyAggregator { type Result = Result<()>; fn handle(&mut self, event: KeyshareCreated, ctx: &mut Self::Context) -> Self::Result { + if event.e3_id != self.e3_id { return Err(anyhow!( "Wrong e3_id sent to aggregator. This should not happen." diff --git a/packages/ciphernode/core/src/publickey_sequencer.rs b/packages/ciphernode/core/src/publickey_sequencer.rs index 8a2593c4..f5db6a47 100644 --- a/packages/ciphernode/core/src/publickey_sequencer.rs +++ b/packages/ciphernode/core/src/publickey_sequencer.rs @@ -1,6 +1,5 @@ // sequence and persist events for a single E3 request in the correct order -// TODO: spawn and store a ciphernode upon start and forward all events to it in order -// TODO: if the ciphernode fails restart the node by replaying all stored events back to it +// TODO: if the sequencer fails restart the node by replaying all stored events back to it use actix::prelude::*; @@ -32,14 +31,14 @@ impl Actor for PublicKeySequencer { impl Handler for PublicKeySequencer { type Result = (); - fn handle(&mut self, msg: EnclaveEvent, ctx: &mut Self::Context) -> Self::Result { + fn handle(&mut self, msg: EnclaveEvent, _ctx: &mut Self::Context) -> Self::Result { let fhe = self.fhe.clone(); let bus = self.bus.clone(); let nodecount = self.nodecount; let e3_id = self.e3_id.clone(); - let sink = self + let dest = self .child .get_or_insert_with(|| PublicKeyAggregator::new(fhe, bus, e3_id, nodecount).start()); - sink.do_send(msg); + dest.do_send(msg); } } diff --git a/packages/ciphernode/core/src/registry.rs b/packages/ciphernode/core/src/registry.rs index 6a13120b..683b6026 100644 --- a/packages/ciphernode/core/src/registry.rs +++ b/packages/ciphernode/core/src/registry.rs @@ -1,20 +1,58 @@ +// TODO: spawn and supervise child actors +// TODO: vertically modularize this so there is a registry for each function that get rolled up into one based +// on config use crate::{ - CiphernodeSequencer, Data, E3id, EnclaveEvent, EventBus, Fhe, PlaintextSequencer, - PublicKeySequencer, + CiphernodeSequencer, CommitteeRequested, Data, E3id, EnclaveEvent, EventBus, Fhe, + PlaintextSequencer, PublicKeySequencer, Subscribe, }; use actix::prelude::*; use rand_chacha::ChaCha20Rng; -use std::collections::HashMap; +use std::{ + collections::HashMap, + sync::{Arc, Mutex}, +}; + +#[derive(Clone)] +struct CommitteeMeta { + nodecount: usize, +} pub struct Registry { bus: Addr, ciphernodes: HashMap>, data: Addr, fhes: HashMap>, - nodecount: usize, plaintexts: HashMap>, + meta: HashMap, public_keys: HashMap>, - rng: ChaCha20Rng, + rng: Arc>, +} + +impl Registry { + pub fn new(bus: Addr, data: Addr, rng: Arc>) -> Self { + Self { + bus, + data, + rng, + ciphernodes: HashMap::new(), + plaintexts: HashMap::new(), + public_keys: HashMap::new(), + meta: HashMap::new(), + fhes: HashMap::new(), + } + } + + pub async fn attach( + bus: Addr, + data: Addr, + rng: Arc>, + ) -> Addr { + let addr = Registry::new(bus.clone(), data, rng).start(); + bus.send(Subscribe::new("*", addr.clone().into())) + .await + .unwrap(); + addr + } } impl Actor for Registry { @@ -28,11 +66,25 @@ impl Handler for Registry { let e3_id = E3id::from(msg.clone()); match msg.clone() { - EnclaveEvent::CommitteeRequested { .. } => { - let fhe_factory = self.fhe_factory(); + EnclaveEvent::CommitteeRequested { data, .. } => { + let CommitteeRequested { + degree, + moduli, + plaintext_modulus, + crp, + .. + } = data; + + let fhe_factory = self.fhe_factory(moduli, degree, plaintext_modulus, crp); let fhe = store(&e3_id, &mut self.fhes, fhe_factory); + let meta = CommitteeMeta { + nodecount: data.nodecount, + }; + + self.meta.entry(e3_id.clone()).or_insert(meta.clone()); - let public_key_sequencer_factory = self.public_key_sequencer_factory(e3_id.clone(), fhe.clone()); + let public_key_sequencer_factory = + self.public_key_sequencer_factory(e3_id.clone(), meta.clone(), fhe.clone()); store(&e3_id, &mut self.public_keys, public_key_sequencer_factory); let ciphernode_sequencer_factory = self.ciphernode_sequencer_factory(fhe.clone()); @@ -42,7 +94,13 @@ impl Handler for Registry { let Some(fhe) = self.fhes.get(&e3_id) else { return; }; - let plaintext_sequencer_factory = self.plaintext_sequencer_factory(e3_id.clone(), fhe.clone()); + + let Some(meta) = self.meta.get(&e3_id) else { + return; + }; + + let plaintext_sequencer_factory = + self.plaintext_sequencer_factory(e3_id.clone(), meta.clone(), fhe.clone()); store(&e3_id, &mut self.plaintexts, plaintext_sequencer_factory); } _ => (), @@ -53,13 +111,16 @@ impl Handler for Registry { } impl Registry { - fn fhe_factory(&self) -> impl FnOnce() -> Addr { + fn fhe_factory( + &self, + moduli: Vec, + degree: usize, + plaintext_modulus: u64, + crp: Vec, + ) -> impl FnOnce() -> Addr { let rng = self.rng.clone(); move || { - let moduli = &vec![0x3FFFFFFF000001]; - let degree = 2048; - let plaintext_modulus = 1032193; - Fhe::from_raw_params(moduli, degree, plaintext_modulus, rng) + Fhe::from_raw_params(&moduli, degree, plaintext_modulus, &crp, rng) .unwrap() .start() } @@ -68,14 +129,18 @@ impl Registry { fn public_key_sequencer_factory( &self, e3_id: E3id, + meta: CommitteeMeta, fhe: Addr, ) -> impl FnOnce() -> Addr { let bus = self.bus.clone(); - let nodecount = self.nodecount; + let nodecount = meta.nodecount; move || PublicKeySequencer::new(fhe, e3_id, bus, nodecount).start() } - fn ciphernode_sequencer_factory(&self, fhe: Addr) -> impl FnOnce() -> Addr { + fn ciphernode_sequencer_factory( + &self, + fhe: Addr, + ) -> impl FnOnce() -> Addr { let data = self.data.clone(); let bus = self.bus.clone(); move || CiphernodeSequencer::new(fhe, data, bus).start() @@ -84,10 +149,11 @@ impl Registry { fn plaintext_sequencer_factory( &self, e3_id: E3id, + meta: CommitteeMeta, fhe: Addr, ) -> impl FnOnce() -> Addr { let bus = self.bus.clone(); - let nodecount = self.nodecount; + let nodecount = meta.nodecount; move || PlaintextSequencer::new(fhe, e3_id, bus, nodecount).start() } @@ -106,6 +172,7 @@ impl Registry { } } +// Store on a hashmap a Addr from the factory F fn store(e3_id: &E3id, map: &mut HashMap>, creator: F) -> Addr where T: Actor>, diff --git a/packages/ciphernode/enclave_node/src/bin/cmd.rs b/packages/ciphernode/enclave_node/src/bin/cmd.rs index 238948e1..ed9385b6 100644 --- a/packages/ciphernode/enclave_node/src/bin/cmd.rs +++ b/packages/ciphernode/enclave_node/src/bin/cmd.rs @@ -14,27 +14,27 @@ use tokio::{ /// Note this is untestable so it may break as we change our API #[actix_rt::main] async fn main() -> Result<(), Box> { - let bus = EventBus::new(true).start(); - let (_, t1) = P2p::spawn_libp2p(bus.clone())?; - let mut stdin = BufReader::new(io::stdin()).lines(); - let t2 = tokio::spawn(async move { - let mut id: u32 = 1000; - while let Ok(Some(line)) = stdin.next_line().await { - match line.as_str() { - "test" => { - id += 1; - bus.do_send(EnclaveEvent::from(CommitteeRequested { - e3_id: E3id::from(id), - nodecount: 3, - threshold: 3, - sortition_seed: 100, - })); - } - _ => println!("Unknown command"), - } - } - }); - - let _ = tokio::join!(t1, t2); + // let bus = EventBus::new(true).start(); + // let (_, t1) = P2p::spawn_libp2p(bus.clone())?; + // let mut stdin = BufReader::new(io::stdin()).lines(); + // let t2 = tokio::spawn(async move { + // let mut id: u32 = 1000; + // while let Ok(Some(line)) = stdin.next_line().await { + // match line.as_str() { + // "test" => { + // id += 1; + // bus.do_send(EnclaveEvent::from(CommitteeRequested { + // e3_id: E3id::from(id), + // nodecount: 3, + // threshold: 3, + // sortition_seed: 100, + // })); + // } + // _ => println!("Unknown command"), + // } + // } + // }); + // + // let _ = tokio::join!(t1, t2); Ok(()) } From 3924477164a6c88502d7b35fce8bec164dc337bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=B3=CE=BB?= Date: Thu, 12 Sep 2024 13:43:04 +1000 Subject: [PATCH 48/87] Remove old code (#57) --- .../core/src/ciphernode_supervisor.rs | 137 ------------------ packages/ciphernode/core/src/lib.rs | 19 --- .../core/src/plaintext_aggregator.rs | 8 +- .../core/src/publickey_aggregator.rs | 8 +- .../enclave_node/src/bin/aggregator.rs | 20 --- .../enclave_node/src/bin/ciphernode-noag.rs | 24 --- .../enclave_node/src/bin/ciphernode.rs | 26 ---- .../ciphernode/enclave_node/src/bin/cmd.rs | 40 ----- 8 files changed, 2 insertions(+), 280 deletions(-) delete mode 100644 packages/ciphernode/core/src/ciphernode_supervisor.rs delete mode 100644 packages/ciphernode/enclave_node/src/bin/aggregator.rs delete mode 100644 packages/ciphernode/enclave_node/src/bin/ciphernode-noag.rs delete mode 100644 packages/ciphernode/enclave_node/src/bin/ciphernode.rs delete mode 100644 packages/ciphernode/enclave_node/src/bin/cmd.rs diff --git a/packages/ciphernode/core/src/ciphernode_supervisor.rs b/packages/ciphernode/core/src/ciphernode_supervisor.rs deleted file mode 100644 index 7fea6c99..00000000 --- a/packages/ciphernode/core/src/ciphernode_supervisor.rs +++ /dev/null @@ -1,137 +0,0 @@ -use crate::{ - eventbus::EventBus, - events::{E3id, EnclaveEvent}, - fhe::Fhe, - plaintext_aggregator::PlaintextAggregator, - publickey_aggregator::PublicKeyAggregator, - Subscribe, -}; -use actix::prelude::*; -use std::collections::HashMap; - -#[derive(Message)] -#[rtype(result = "()")] -pub struct Die; - -// CommitteeMeta -// Storing metadata around the committee eg threshold / nodecount -struct CommitteeMeta { - nodecount: usize, -} - -pub struct CiphernodeSupervisor { - bus: Addr, - fhe: Addr, - - publickey_aggregators: HashMap>, - plaintext_aggregators: HashMap>, - meta: HashMap, -} - -impl Actor for CiphernodeSupervisor { - type Context = Context; -} - -impl CiphernodeSupervisor { - pub fn new(bus: Addr, fhe: Addr) -> Self { - Self { - bus, - fhe, - publickey_aggregators: HashMap::new(), - plaintext_aggregators: HashMap::new(), - meta: HashMap::new(), - } - } - - pub fn attach(bus: Addr, fhe: Addr) -> Addr { - let addr = CiphernodeSupervisor::new(bus.clone(), fhe).start(); - bus.do_send(Subscribe::new( - "CommitteeRequested", - addr.clone().recipient(), - )); - bus.do_send(Subscribe::new("KeyshareCreated", addr.clone().into())); - bus.do_send(Subscribe::new( - "CiphertextOutputPublished", - addr.clone().into(), - )); - bus.do_send(Subscribe::new( - "DecryptionshareCreated", - addr.clone().into(), - )); - bus.do_send(Subscribe::new("PlaintextAggregated", addr.clone().into())); - addr - } -} - -impl Handler for CiphernodeSupervisor { - type Result = (); - - fn handle(&mut self, event: EnclaveEvent, _ctx: &mut Self::Context) -> Self::Result { - match event { - EnclaveEvent::CommitteeRequested { data, .. } => { - // start up a new key - let publickey_aggregator = PublicKeyAggregator::new( - self.fhe.clone(), - self.bus.clone(), - data.e3_id.clone(), - data.nodecount, - ) - .start(); - - self.meta.insert( - data.e3_id.clone(), - CommitteeMeta { - nodecount: data.nodecount.clone(), - }, - ); - self.publickey_aggregators - .insert(data.e3_id, publickey_aggregator); - } - EnclaveEvent::KeyshareCreated { data, .. } => { - if let Some(key) = self.publickey_aggregators.get(&data.e3_id) { - key.do_send(EnclaveEvent::from(data)); - } - } - EnclaveEvent::PublicKeyAggregated { data, .. } => { - let Some(publickey_aggregator) = self.publickey_aggregators.get(&data.e3_id) else { - return; - }; - - publickey_aggregator.do_send(Die); - self.publickey_aggregators.remove(&data.e3_id); - } - EnclaveEvent::CiphertextOutputPublished { data, .. } => { - let Some(meta) = self.meta.get(&data.e3_id) else { - // TODO: setup proper logger / telemetry - println!("E3Id not found in committee"); - return; - }; - // start up a new key - let plaintext_aggregator = PlaintextAggregator::new( - self.fhe.clone(), - self.bus.clone(), - data.e3_id.clone(), - meta.nodecount.clone(), - ) - .start(); - - self.plaintext_aggregators - .insert(data.e3_id, plaintext_aggregator); - } - EnclaveEvent::DecryptionshareCreated { data, .. } => { - if let Some(decryption) = self.plaintext_aggregators.get(&data.e3_id) { - decryption.do_send(EnclaveEvent::from(data)); - } - } - EnclaveEvent::PlaintextAggregated { data, .. } => { - let Some(addr) = self.plaintext_aggregators.get(&data.e3_id) else { - return; - }; - - addr.do_send(Die); - self.plaintext_aggregators.remove(&data.e3_id); - }, - _ => () - } - } -} diff --git a/packages/ciphernode/core/src/lib.rs b/packages/ciphernode/core/src/lib.rs index b47b843c..006ab118 100644 --- a/packages/ciphernode/core/src/lib.rs +++ b/packages/ciphernode/core/src/lib.rs @@ -5,7 +5,6 @@ mod ciphernode; mod ciphernode_selector; mod ciphernode_sequencer; -mod ciphernode_supervisor; mod data; mod enclave_contract; mod eventbus; @@ -26,7 +25,6 @@ pub use actix::prelude::*; pub use ciphernode::*; pub use ciphernode_selector::*; pub use ciphernode_sequencer::*; -pub use ciphernode_supervisor::*; pub use data::*; pub use eventbus::*; pub use events::*; @@ -43,13 +41,10 @@ pub use registry::*; #[cfg(test)] mod tests { use crate::{ - ciphernode::Ciphernode, ciphernode_selector::CiphernodeSelector, - ciphernode_supervisor::CiphernodeSupervisor, data::Data, eventbus::{EventBus, GetHistory}, events::{CommitteeRequested, E3id, EnclaveEvent, KeyshareCreated, PublicKeyAggregated}, - fhe::Fhe, p2p::P2p, serializers::{ CiphertextSerializer, DecryptionShareSerializer, PublicKeySerializer, @@ -112,20 +107,6 @@ mod tests { Ok((pk, sk)) } - // fn setup_global_fhe_actor( - // moduli: &[u64], - // degree: usize, - // plaintext_modulus: u64, - // rng: SharedRng, - // ) -> Result<(Addr, Arc, CommonRandomPoly)> { - // let (params, crp) = setup_bfv_params(&moduli, degree, plaintext_modulus, rng.clone())?; - // Ok(( - // Fhe::new(params.clone(), crp.clone(), rng.clone()).start(), - // params, - // crp, - // )) - // } - // struct NewParamsWithCrp { pub moduli: Vec, pub degree: usize, diff --git a/packages/ciphernode/core/src/plaintext_aggregator.rs b/packages/ciphernode/core/src/plaintext_aggregator.rs index 3146ee8b..29b88960 100644 --- a/packages/ciphernode/core/src/plaintext_aggregator.rs +++ b/packages/ciphernode/core/src/plaintext_aggregator.rs @@ -1,5 +1,5 @@ use crate::{ - ordered_set::OrderedSet, PlaintextAggregated, DecryptionshareCreated, Die, E3id, EnclaveEvent, EventBus, Fhe, GetAggregatePlaintext + ordered_set::OrderedSet, PlaintextAggregated, DecryptionshareCreated, E3id, EnclaveEvent, EventBus, Fhe, GetAggregatePlaintext }; use actix::prelude::*; use anyhow::{anyhow, Result}; @@ -140,10 +140,4 @@ impl Handler for PlaintextAggregator { } } -impl Handler for PlaintextAggregator { - type Result = (); - fn handle(&mut self, _msg: Die, ctx: &mut Context) { - ctx.stop(); - } -} diff --git a/packages/ciphernode/core/src/publickey_aggregator.rs b/packages/ciphernode/core/src/publickey_aggregator.rs index 510fed03..bc8733dd 100644 --- a/packages/ciphernode/core/src/publickey_aggregator.rs +++ b/packages/ciphernode/core/src/publickey_aggregator.rs @@ -2,7 +2,7 @@ use crate::{ eventbus::EventBus, events::{E3id, EnclaveEvent, KeyshareCreated, PublicKeyAggregated}, fhe::{Fhe, GetAggregatePublicKey}, - ordered_set::OrderedSet, Die, + ordered_set::OrderedSet, }; use actix::prelude::*; use anyhow::{anyhow, Result}; @@ -171,10 +171,4 @@ impl Handler for PublicKeyAggregator { } } -impl Handler for PublicKeyAggregator { - type Result = (); - fn handle(&mut self, _msg: Die, ctx: &mut Context) { - ctx.stop(); - } -} diff --git a/packages/ciphernode/enclave_node/src/bin/aggregator.rs b/packages/ciphernode/enclave_node/src/bin/aggregator.rs deleted file mode 100644 index a46cf3f7..00000000 --- a/packages/ciphernode/enclave_node/src/bin/aggregator.rs +++ /dev/null @@ -1,20 +0,0 @@ -use enclave_core::Actor; -use enclave_core::CiphernodeSupervisor; -use enclave_core::EventBus; -use enclave_core::Fhe; -use enclave_core::P2p; -use enclave_core::SimpleLogger; -use std::error::Error; - -/// Note this is untestable so it may break as we change our API -#[actix_rt::main] -async fn main() -> Result<(), Box> { - let fhe = Fhe::try_default()?.start(); - let bus = EventBus::new(true).start(); - SimpleLogger::attach(bus.clone()); - CiphernodeSupervisor::attach(bus.clone(), fhe.clone()); - let (_, h) = P2p::spawn_libp2p(bus.clone())?; - println!("Aggregator"); - let _ = tokio::join!(h); - Ok(()) -} diff --git a/packages/ciphernode/enclave_node/src/bin/ciphernode-noag.rs b/packages/ciphernode/enclave_node/src/bin/ciphernode-noag.rs deleted file mode 100644 index 1aa3bea6..00000000 --- a/packages/ciphernode/enclave_node/src/bin/ciphernode-noag.rs +++ /dev/null @@ -1,24 +0,0 @@ -use enclave_core::Actor; -use enclave_core::Ciphernode; -use enclave_core::CiphernodeSelector; -use enclave_core::Data; -use enclave_core::EventBus; -use enclave_core::Fhe; -use enclave_core::P2p; -use enclave_core::SimpleLogger; -use std::error::Error; - -/// Note this is untestable so it may break as we change our API -#[actix_rt::main] -async fn main() -> Result<(), Box> { - let fhe = Fhe::try_default()?.start(); - let bus = EventBus::new(true).start(); - let data = Data::new(true).start(); // TODO: Use a sled backed Data Actor - CiphernodeSelector::attach(bus.clone()); - SimpleLogger::attach(bus.clone()); - Ciphernode::attach(bus.clone(), fhe.clone(), data.clone()); - let (_, h) = P2p::spawn_libp2p(bus.clone())?; - println!("Ciphernode"); - let _ = tokio::join!(h); - Ok(()) -} diff --git a/packages/ciphernode/enclave_node/src/bin/ciphernode.rs b/packages/ciphernode/enclave_node/src/bin/ciphernode.rs deleted file mode 100644 index f24fff96..00000000 --- a/packages/ciphernode/enclave_node/src/bin/ciphernode.rs +++ /dev/null @@ -1,26 +0,0 @@ -use enclave_core::Actor; -use enclave_core::Ciphernode; -use enclave_core::CiphernodeSelector; -use enclave_core::CiphernodeSupervisor; -use enclave_core::Data; -use enclave_core::EventBus; -use enclave_core::Fhe; -use enclave_core::P2p; -use enclave_core::SimpleLogger; -use std::error::Error; - -/// Note this is untestable so it may break as we change our API -#[actix_rt::main] -async fn main() -> Result<(), Box> { - let fhe = Fhe::try_default()?.start(); - let bus = EventBus::new(true).start(); - let data = Data::new(true).start(); // TODO: Use a sled backed Data Actor - SimpleLogger::attach(bus.clone()); - CiphernodeSelector::attach(bus.clone()); - Ciphernode::attach(bus.clone(), fhe.clone(), data.clone()); - CiphernodeSupervisor::attach(bus.clone(), fhe.clone()); - let (_, h) = P2p::spawn_libp2p(bus.clone())?; - println!("Ciphernode"); - let _ = tokio::join!(h); - Ok(()) -} diff --git a/packages/ciphernode/enclave_node/src/bin/cmd.rs b/packages/ciphernode/enclave_node/src/bin/cmd.rs deleted file mode 100644 index ed9385b6..00000000 --- a/packages/ciphernode/enclave_node/src/bin/cmd.rs +++ /dev/null @@ -1,40 +0,0 @@ -use std::error::Error; - -use enclave_core::Actor; -use enclave_core::CommitteeRequested; -use enclave_core::E3id; -use enclave_core::EnclaveEvent; -use enclave_core::EventBus; -use enclave_core::P2p; -use tokio::{ - self, - io::{self, AsyncBufReadExt, BufReader}, -}; - -/// Note this is untestable so it may break as we change our API -#[actix_rt::main] -async fn main() -> Result<(), Box> { - // let bus = EventBus::new(true).start(); - // let (_, t1) = P2p::spawn_libp2p(bus.clone())?; - // let mut stdin = BufReader::new(io::stdin()).lines(); - // let t2 = tokio::spawn(async move { - // let mut id: u32 = 1000; - // while let Ok(Some(line)) = stdin.next_line().await { - // match line.as_str() { - // "test" => { - // id += 1; - // bus.do_send(EnclaveEvent::from(CommitteeRequested { - // e3_id: E3id::from(id), - // nodecount: 3, - // threshold: 3, - // sortition_seed: 100, - // })); - // } - // _ => println!("Unknown command"), - // } - // } - // }); - // - // let _ = tokio::join!(t1, t2); - Ok(()) -} From b1dba82c8e5e2d2a216ac258a9352968e05c2508 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=B3=CE=BB?= Date: Fri, 13 Sep 2024 19:01:45 +1000 Subject: [PATCH 49/87] Sortition actor (#58) * Sortition actor implemented * Fix up comments --- packages/ciphernode/Cargo.lock | 669 +++++++++++++++--- packages/ciphernode/core/Cargo.toml | 3 + .../core/src/ciphernode_selector.rs | 57 +- packages/ciphernode/core/src/events.rs | 81 ++- packages/ciphernode/core/src/lib.rs | 69 +- packages/ciphernode/core/src/registry.rs | 4 +- packages/ciphernode/core/src/sortition.rs | 120 ++++ packages/ciphernode/sortition/Cargo.toml | 9 +- 8 files changed, 875 insertions(+), 137 deletions(-) create mode 100644 packages/ciphernode/core/src/sortition.rs diff --git a/packages/ciphernode/Cargo.lock b/packages/ciphernode/Cargo.lock index 1d8ba935..bb298e9b 100644 --- a/packages/ciphernode/Cargo.lock +++ b/packages/ciphernode/Cargo.lock @@ -142,25 +142,41 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f4a4aaae80afd4be443a6aecd92a6b255dcdd000f97996928efb33d8a71e100" dependencies = [ - "alloy-consensus", + "alloy-consensus 0.2.1", "alloy-contract", - "alloy-core", - "alloy-eips", - "alloy-genesis", - "alloy-network", - "alloy-provider", + "alloy-core 0.7.7", + "alloy-eips 0.2.1", + "alloy-genesis 0.2.1", + "alloy-network 0.2.1", + "alloy-provider 0.2.1", "alloy-pubsub", - "alloy-rpc-client", + "alloy-rpc-client 0.2.1", "alloy-rpc-types", - "alloy-serde", - "alloy-signer", + "alloy-serde 0.2.1", + "alloy-signer 0.2.1", "alloy-signer-local", - "alloy-transport", - "alloy-transport-http", + "alloy-transport 0.2.1", + "alloy-transport-http 0.2.1", "alloy-transport-ipc", "alloy-transport-ws", ] +[[package]] +name = "alloy" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c37d89f69cb43901949ba29307ada8b9e3b170f94057ad4c04d6fd169d24d65f" +dependencies = [ + "alloy-consensus 0.3.3", + "alloy-core 0.8.3", + "alloy-eips 0.3.3", + "alloy-genesis 0.3.3", + "alloy-provider 0.3.3", + "alloy-rpc-client 0.3.3", + "alloy-serde 0.3.3", + "alloy-transport-http 0.3.3", +] + [[package]] name = "alloy-chains" version = "0.1.29" @@ -177,10 +193,24 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04c309895995eaa4bfcc345f5515a39c7df9447798645cc8bf462b6c5bf1dc96" dependencies = [ - "alloy-eips", + "alloy-eips 0.2.1", "alloy-primitives 0.7.7", "alloy-rlp", - "alloy-serde", + "alloy-serde 0.2.1", + "c-kzg", + "serde", +] + +[[package]] +name = "alloy-consensus" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1468e3128e07c7afe4ff13c17e8170c330d12c322f8924b8bf6986a27e0aad3d" +dependencies = [ + "alloy-eips 0.3.3", + "alloy-primitives 0.8.3", + "alloy-rlp", + "alloy-serde 0.3.3", "c-kzg", "serde", ] @@ -191,16 +221,16 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f4e0ef72b0876ae3068b2ed7dfae9ae1779ce13cfaec2ee1f08f5bd0348dc57" dependencies = [ - "alloy-dyn-abi", - "alloy-json-abi", - "alloy-network", - "alloy-network-primitives", + "alloy-dyn-abi 0.7.7", + "alloy-json-abi 0.7.7", + "alloy-network 0.2.1", + "alloy-network-primitives 0.2.1", "alloy-primitives 0.7.7", - "alloy-provider", + "alloy-provider 0.2.1", "alloy-pubsub", - "alloy-rpc-types-eth", + "alloy-rpc-types-eth 0.2.1", "alloy-sol-types 0.7.7", - "alloy-transport", + "alloy-transport 0.2.1", "futures", "futures-util", "thiserror", @@ -212,21 +242,33 @@ version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "529fc6310dc1126c8de51c376cbc59c79c7f662bd742be7dc67055d5421a81b4" dependencies = [ - "alloy-dyn-abi", - "alloy-json-abi", + "alloy-dyn-abi 0.7.7", + "alloy-json-abi 0.7.7", "alloy-primitives 0.7.7", "alloy-sol-types 0.7.7", ] +[[package]] +name = "alloy-core" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88b095eb0533144b4497e84a9cc3e44a5c2e3754a3983c0376a55a2f9183a53e" +dependencies = [ + "alloy-dyn-abi 0.8.3", + "alloy-json-abi 0.8.3", + "alloy-primitives 0.8.3", + "alloy-sol-types 0.8.3", +] + [[package]] name = "alloy-dyn-abi" version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "413902aa18a97569e60f679c23f46a18db1656d87ab4d4e49d0e1e52042f66df" dependencies = [ - "alloy-json-abi", + "alloy-json-abi 0.7.7", "alloy-primitives 0.7.7", - "alloy-sol-type-parser", + "alloy-sol-type-parser 0.7.7", "alloy-sol-types 0.7.7", "const-hex", "itoa", @@ -235,6 +277,45 @@ dependencies = [ "winnow", ] +[[package]] +name = "alloy-dyn-abi" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4004925bff5ba0a11739ae84dbb6601a981ea692f3bd45b626935ee90a6b8471" +dependencies = [ + "alloy-json-abi 0.8.3", + "alloy-primitives 0.8.3", + "alloy-sol-type-parser 0.8.3", + "alloy-sol-types 0.8.3", + "const-hex", + "itoa", + "serde", + "serde_json", + "winnow", +] + +[[package]] +name = "alloy-eip2930" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0069cf0642457f87a01a014f6dc29d5d893cd4fd8fddf0c3cdfad1bb3ebafc41" +dependencies = [ + "alloy-primitives 0.8.3", + "alloy-rlp", + "serde", +] + +[[package]] +name = "alloy-eip7702" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37d319bb544ca6caeab58c39cea8921c55d924d4f68f2c60f24f914673f9a74a" +dependencies = [ + "alloy-primitives 0.8.3", + "alloy-rlp", + "serde", +] + [[package]] name = "alloy-eips" version = "0.2.1" @@ -243,15 +324,33 @@ checksum = "d9431c99a3b3fe606ede4b3d4043bdfbcb780c45b8d8d226c3804e2b75cfbe68" dependencies = [ "alloy-primitives 0.7.7", "alloy-rlp", - "alloy-serde", + "alloy-serde 0.2.1", "c-kzg", - "derive_more", + "derive_more 0.99.18", "k256", "once_cell", "serde", "sha2", ] +[[package]] +name = "alloy-eips" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c35df7b972b06f1b2f4e8b7a53328522fa788054a9d3e556faf2411c5a51d5a" +dependencies = [ + "alloy-eip2930", + "alloy-eip7702", + "alloy-primitives 0.8.3", + "alloy-rlp", + "alloy-serde 0.3.3", + "c-kzg", + "derive_more 1.0.0", + "once_cell", + "serde", + "sha2", +] + [[package]] name = "alloy-genesis" version = "0.2.1" @@ -259,7 +358,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "79614dfe86144328da11098edcc7bc1a3f25ad8d3134a9eb9e857e06f0d9840d" dependencies = [ "alloy-primitives 0.7.7", - "alloy-serde", + "alloy-serde 0.2.1", + "serde", +] + +[[package]] +name = "alloy-genesis" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7210f9206c0fa2a83c824cf8cb6c962126bc9fdc4f41ade1932f14150ef5f6" +dependencies = [ + "alloy-primitives 0.8.3", + "alloy-serde 0.3.3", "serde", ] @@ -270,7 +380,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bc05b04ac331a9f07e3a4036ef7926e49a8bf84a99a1ccfc7e2ab55a5fcbb372" dependencies = [ "alloy-primitives 0.7.7", - "alloy-sol-type-parser", + "alloy-sol-type-parser 0.7.7", + "serde", + "serde_json", +] + +[[package]] +name = "alloy-json-abi" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9996daf962fd0a90d3c93b388033228865953b92de7bb1959b891d78750a4091" +dependencies = [ + "alloy-primitives 0.8.3", + "alloy-sol-type-parser 0.8.3", "serde", "serde_json", ] @@ -289,20 +411,34 @@ dependencies = [ "tracing", ] +[[package]] +name = "alloy-json-rpc" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8866562186d237f1dfeaf989ef941a24764f764bf5c33311e37ead3519c6a429" +dependencies = [ + "alloy-primitives 0.8.3", + "alloy-sol-types 0.8.3", + "serde", + "serde_json", + "thiserror", + "tracing", +] + [[package]] name = "alloy-network" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e701fc87ef9a3139154b0b4ccb935b565d27ffd9de020fe541bf2dec5ae4ede" dependencies = [ - "alloy-consensus", - "alloy-eips", - "alloy-json-rpc", - "alloy-network-primitives", + "alloy-consensus 0.2.1", + "alloy-eips 0.2.1", + "alloy-json-rpc 0.2.1", + "alloy-network-primitives 0.2.1", "alloy-primitives 0.7.7", - "alloy-rpc-types-eth", - "alloy-serde", - "alloy-signer", + "alloy-rpc-types-eth 0.2.1", + "alloy-serde 0.2.1", + "alloy-signer 0.2.1", "alloy-sol-types 0.7.7", "async-trait", "auto_impl", @@ -310,6 +446,27 @@ dependencies = [ "thiserror", ] +[[package]] +name = "alloy-network" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abe714e233f9eaf410de95a9af6bcd05d3a7f8c8de7a0817221e95a6b642a080" +dependencies = [ + "alloy-consensus 0.3.3", + "alloy-eips 0.3.3", + "alloy-json-rpc 0.3.3", + "alloy-network-primitives 0.3.3", + "alloy-primitives 0.8.3", + "alloy-rpc-types-eth 0.3.3", + "alloy-serde 0.3.3", + "alloy-signer 0.3.3", + "alloy-sol-types 0.8.3", + "async-trait", + "auto_impl", + "futures-utils-wasm", + "thiserror", +] + [[package]] name = "alloy-network-primitives" version = "0.2.1" @@ -317,7 +474,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec9d5a0f9170b10988b6774498a022845e13eda94318440d17709d50687f67f9" dependencies = [ "alloy-primitives 0.7.7", - "alloy-serde", + "alloy-serde 0.2.1", + "serde", +] + +[[package]] +name = "alloy-network-primitives" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c5a38117974c5776a45e140226745a0b664f79736aa900995d8e4121558e064" +dependencies = [ + "alloy-eips 0.3.3", + "alloy-primitives 0.8.3", + "alloy-serde 0.3.3", "serde", ] @@ -331,7 +500,7 @@ dependencies = [ "bytes", "cfg-if", "const-hex", - "derive_more", + "derive_more 0.99.18", "hex-literal", "itoa", "k256", @@ -353,7 +522,29 @@ dependencies = [ "bytes", "cfg-if", "const-hex", - "derive_more", + "derive_more 0.99.18", + "hex-literal", + "itoa", + "k256", + "keccak-asm", + "proptest", + "rand", + "ruint", + "serde", + "tiny-keccak", +] + +[[package]] +name = "alloy-primitives" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "411aff151f2a73124ee473708e82ed51b2535f68928b6a1caa8bc1246ae6f7cd" +dependencies = [ + "alloy-rlp", + "bytes", + "cfg-if", + "const-hex", + "derive_more 1.0.0", "hex-literal", "itoa", "k256", @@ -372,23 +563,23 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9c0ab10b93de601a6396fc7ff2ea10d3b28c46f079338fa562107ebf9857c8" dependencies = [ "alloy-chains", - "alloy-consensus", - "alloy-eips", - "alloy-json-rpc", - "alloy-network", - "alloy-network-primitives", + "alloy-consensus 0.2.1", + "alloy-eips 0.2.1", + "alloy-json-rpc 0.2.1", + "alloy-network 0.2.1", + "alloy-network-primitives 0.2.1", "alloy-primitives 0.7.7", "alloy-pubsub", - "alloy-rpc-client", - "alloy-rpc-types-eth", - "alloy-transport", - "alloy-transport-http", + "alloy-rpc-client 0.2.1", + "alloy-rpc-types-eth 0.2.1", + "alloy-transport 0.2.1", + "alloy-transport-http 0.2.1", "alloy-transport-ipc", "alloy-transport-ws", "async-stream", "async-trait", "auto_impl", - "dashmap", + "dashmap 5.5.3", "futures", "futures-utils-wasm", "lru", @@ -401,22 +592,56 @@ dependencies = [ "url", ] +[[package]] +name = "alloy-provider" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c65633d6ef83c3626913c004eaf166a6dd50406f724772ea8567135efd6dc5d3" +dependencies = [ + "alloy-chains", + "alloy-consensus 0.3.3", + "alloy-eips 0.3.3", + "alloy-json-rpc 0.3.3", + "alloy-network 0.3.3", + "alloy-network-primitives 0.3.3", + "alloy-primitives 0.8.3", + "alloy-rpc-client 0.3.3", + "alloy-rpc-types-eth 0.3.3", + "alloy-transport 0.3.3", + "alloy-transport-http 0.3.3", + "async-stream", + "async-trait", + "auto_impl", + "dashmap 6.1.0", + "futures", + "futures-utils-wasm", + "lru", + "pin-project", + "reqwest", + "serde", + "serde_json", + "thiserror", + "tokio", + "tracing", + "url", +] + [[package]] name = "alloy-pubsub" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f5da2c55cbaf229bad3c5f8b00b5ab66c74ef093e5f3a753d874cfecf7d2281" dependencies = [ - "alloy-json-rpc", + "alloy-json-rpc 0.2.1", "alloy-primitives 0.7.7", - "alloy-transport", + "alloy-transport 0.2.1", "bimap", "futures", "serde", "serde_json", "tokio", "tokio-stream", - "tower", + "tower 0.4.13", "tracing", ] @@ -448,11 +673,11 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b38e3ffdb285df5d9f60cb988d336d9b8e3505acb78750c3bc60336a7af41d3" dependencies = [ - "alloy-json-rpc", + "alloy-json-rpc 0.2.1", "alloy-primitives 0.7.7", "alloy-pubsub", - "alloy-transport", - "alloy-transport-http", + "alloy-transport 0.2.1", + "alloy-transport-http 0.2.1", "alloy-transport-ipc", "alloy-transport-ws", "futures", @@ -462,7 +687,28 @@ dependencies = [ "serde_json", "tokio", "tokio-stream", - "tower", + "tower 0.4.13", + "tracing", + "url", +] + +[[package]] +name = "alloy-rpc-client" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5fc328bb5d440599ba1b5aa44c0b9ab0625fbc3a403bb5ee94ed4a01ba23e07" +dependencies = [ + "alloy-json-rpc 0.3.3", + "alloy-transport 0.3.3", + "alloy-transport-http 0.3.3", + "futures", + "pin-project", + "reqwest", + "serde", + "serde_json", + "tokio", + "tokio-stream", + "tower 0.5.1", "tracing", "url", ] @@ -474,8 +720,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c31a3750b8f5a350d17354e46a52b0f2f19ec5f2006d816935af599dedc521" dependencies = [ "alloy-rpc-types-engine", - "alloy-rpc-types-eth", - "alloy-serde", + "alloy-rpc-types-eth 0.2.1", + "alloy-serde 0.2.1", "serde", ] @@ -485,12 +731,12 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff63f51b2fb2f547df5218527fd0653afb1947bf7fead5b3ce58c75d170b30f7" dependencies = [ - "alloy-consensus", - "alloy-eips", + "alloy-consensus 0.2.1", + "alloy-eips 0.2.1", "alloy-primitives 0.7.7", "alloy-rlp", - "alloy-rpc-types-eth", - "alloy-serde", + "alloy-rpc-types-eth 0.2.1", + "alloy-serde 0.2.1", "jsonwebtoken", "rand", "serde", @@ -503,12 +749,12 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "81e18424d962d7700a882fe423714bd5b9dde74c7a7589d4255ea64068773aef" dependencies = [ - "alloy-consensus", - "alloy-eips", - "alloy-network-primitives", + "alloy-consensus 0.2.1", + "alloy-eips 0.2.1", + "alloy-network-primitives 0.2.1", "alloy-primitives 0.7.7", "alloy-rlp", - "alloy-serde", + "alloy-serde 0.2.1", "alloy-sol-types 0.7.7", "itertools 0.13.0", "serde", @@ -516,6 +762,25 @@ dependencies = [ "thiserror", ] +[[package]] +name = "alloy-rpc-types-eth" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a59b1d7c86e0a653e7f3d29954f6de5a2878d8cfd1f010ff93be5c2c48cd3b1" +dependencies = [ + "alloy-consensus 0.3.3", + "alloy-eips 0.3.3", + "alloy-network-primitives 0.3.3", + "alloy-primitives 0.8.3", + "alloy-rlp", + "alloy-serde 0.3.3", + "alloy-sol-types 0.8.3", + "itertools 0.13.0", + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "alloy-serde" version = "0.2.1" @@ -527,6 +792,17 @@ dependencies = [ "serde_json", ] +[[package]] +name = "alloy-serde" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51db8a6428a2159e01b7a43ec7aac801edd0c4db1d4de06f310c288940f16fd3" +dependencies = [ + "alloy-primitives 0.8.3", + "serde", + "serde_json", +] + [[package]] name = "alloy-signer" version = "0.2.1" @@ -541,16 +817,30 @@ dependencies = [ "thiserror", ] +[[package]] +name = "alloy-signer" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bebc1760c13592b7ba3fcd964abba546b8d6a9f10d15e8d92a8263731be33f36" +dependencies = [ + "alloy-primitives 0.8.3", + "async-trait", + "auto_impl", + "elliptic-curve", + "k256", + "thiserror", +] + [[package]] name = "alloy-signer-local" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b0707d4f63e4356a110b30ef3add8732ab6d181dd7be4607bf79b8777105cee" dependencies = [ - "alloy-consensus", - "alloy-network", + "alloy-consensus 0.2.1", + "alloy-network 0.2.1", "alloy-primitives 0.7.7", - "alloy-signer", + "alloy-signer 0.2.1", "async-trait", "k256", "rand", @@ -581,22 +871,36 @@ version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b40397ddcdcc266f59f959770f601ce1280e699a91fc1862f29cef91707cd09" dependencies = [ - "alloy-sol-macro-expander", - "alloy-sol-macro-input", + "alloy-sol-macro-expander 0.7.7", + "alloy-sol-macro-input 0.7.7", "proc-macro-error", "proc-macro2", "quote", "syn 2.0.72", ] +[[package]] +name = "alloy-sol-macro" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0458ccb02a564228fcd76efb8eb5a520521a8347becde37b402afec9a1b83859" +dependencies = [ + "alloy-sol-macro-expander 0.8.3", + "alloy-sol-macro-input 0.8.3", + "proc-macro-error2", + "proc-macro2", + "quote", + "syn 2.0.72", +] + [[package]] name = "alloy-sol-macro-expander" version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "867a5469d61480fea08c7333ffeca52d5b621f5ca2e44f271b117ec1fc9a0525" dependencies = [ - "alloy-json-abi", - "alloy-sol-macro-input", + "alloy-json-abi 0.7.7", + "alloy-sol-macro-input 0.7.7", "const-hex", "heck 0.5.0", "indexmap", @@ -608,13 +912,31 @@ dependencies = [ "tiny-keccak", ] +[[package]] +name = "alloy-sol-macro-expander" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bc65475025fc1e84bf86fc840f04f63fcccdcf3cf12053c99918e4054dfbc69" +dependencies = [ + "alloy-sol-macro-input 0.8.3", + "const-hex", + "heck 0.5.0", + "indexmap", + "proc-macro-error2", + "proc-macro2", + "quote", + "syn 2.0.72", + "syn-solidity 0.8.3", + "tiny-keccak", +] + [[package]] name = "alloy-sol-macro-input" version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2e482dc33a32b6fadbc0f599adea520bd3aaa585c141a80b404d0a3e3fa72528" dependencies = [ - "alloy-json-abi", + "alloy-json-abi 0.7.7", "const-hex", "dunce", "heck 0.5.0", @@ -625,6 +947,21 @@ dependencies = [ "syn-solidity 0.7.7", ] +[[package]] +name = "alloy-sol-macro-input" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ed10f0715a0b69fde3236ff3b9ae5f6f7c97db5a387747100070d3016b9266b" +dependencies = [ + "const-hex", + "dunce", + "heck 0.5.0", + "proc-macro2", + "quote", + "syn 2.0.72", + "syn-solidity 0.8.3", +] + [[package]] name = "alloy-sol-type-parser" version = "0.7.7" @@ -635,6 +972,16 @@ dependencies = [ "winnow", ] +[[package]] +name = "alloy-sol-type-parser" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3edae8ea1de519ccba896b6834dec874230f72fe695ff3c9c118e90ec7cff783" +dependencies = [ + "serde", + "winnow", +] + [[package]] name = "alloy-sol-types" version = "0.6.4" @@ -653,20 +1000,52 @@ version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a91ca40fa20793ae9c3841b83e74569d1cc9af29a2f5237314fd3452d51e38c7" dependencies = [ - "alloy-json-abi", + "alloy-json-abi 0.7.7", "alloy-primitives 0.7.7", "alloy-sol-macro 0.7.7", "const-hex", "serde", ] +[[package]] +name = "alloy-sol-types" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1eb88e4da0a1b697ed6a9f811fdba223cf4d5c21410804fd1707836af73a462b" +dependencies = [ + "alloy-json-abi 0.8.3", + "alloy-primitives 0.8.3", + "alloy-sol-macro 0.8.3", + "const-hex", + "serde", +] + [[package]] name = "alloy-transport" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d0590afbdacf2f8cca49d025a2466f3b6584a016a8b28f532f29f8da1007bae" dependencies = [ - "alloy-json-rpc", + "alloy-json-rpc 0.2.1", + "base64 0.22.1", + "futures-util", + "futures-utils-wasm", + "serde", + "serde_json", + "thiserror", + "tokio", + "tower 0.4.13", + "tracing", + "url", +] + +[[package]] +name = "alloy-transport" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd5dc4e902f1860d54952446d246ac05386311ad61030a2b906ae865416d36e0" +dependencies = [ + "alloy-json-rpc 0.3.3", "base64 0.22.1", "futures-util", "futures-utils-wasm", @@ -674,7 +1053,7 @@ dependencies = [ "serde_json", "thiserror", "tokio", - "tower", + "tower 0.5.1", "tracing", "url", ] @@ -685,11 +1064,26 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2437d145d80ea1aecde8574d2058cceb8b3c9cba05f6aea8e67907c660d46698" dependencies = [ - "alloy-json-rpc", - "alloy-transport", + "alloy-json-rpc 0.2.1", + "alloy-transport 0.2.1", "reqwest", "serde_json", - "tower", + "tower 0.4.13", + "tracing", + "url", +] + +[[package]] +name = "alloy-transport-http" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1742b94bb814f1ca6b322a6f9dd38a0252ff45a3119e40e888fb7029afa500ce" +dependencies = [ + "alloy-json-rpc 0.3.3", + "alloy-transport 0.3.3", + "reqwest", + "serde_json", + "tower 0.5.1", "tracing", "url", ] @@ -700,9 +1094,9 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "804494366e20468776db4e18f9eb5db7db0fe14f1271eb6dbf155d867233405c" dependencies = [ - "alloy-json-rpc", + "alloy-json-rpc 0.2.1", "alloy-pubsub", - "alloy-transport", + "alloy-transport 0.2.1", "bytes", "futures", "interprocess", @@ -720,7 +1114,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af855163e7df008799941aa6dd324a43ef2bf264b08ba4b22d44aad6ced65300" dependencies = [ "alloy-pubsub", - "alloy-transport", + "alloy-transport 0.2.1", "futures", "http 1.1.0", "rustls", @@ -1655,6 +2049,20 @@ dependencies = [ "parking_lot_core", ] +[[package]] +name = "dashmap" +version = "6.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf" +dependencies = [ + "cfg-if", + "crossbeam-utils", + "hashbrown", + "lock_api", + "once_cell", + "parking_lot_core", +] + [[package]] name = "data-encoding" version = "2.6.0" @@ -1738,6 +2146,27 @@ dependencies = [ "syn 2.0.72", ] +[[package]] +name = "derive_more" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a9b99b9cbbe49445b21764dc0625032a89b145a2642e67603e1c936f5458d05" +dependencies = [ + "derive_more-impl", +] + +[[package]] +name = "derive_more-impl" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.72", + "unicode-xid", +] + [[package]] name = "digest" version = "0.9.0" @@ -1875,6 +2304,8 @@ version = "0.1.0" dependencies = [ "actix", "actix-rt", + "alloy 0.3.3", + "alloy-primitives 0.6.4", "anyhow", "async-std", "bincode", @@ -1889,6 +2320,7 @@ dependencies = [ "secp256k1", "serde", "sha2", + "sortition", "tokio", ] @@ -1897,7 +2329,7 @@ name = "enclave_node" version = "0.1.0" dependencies = [ "actix-rt", - "alloy", + "alloy 0.2.1", "alloy-primitives 0.6.4", "async-std", "bfv", @@ -1944,7 +2376,7 @@ name = "eth" version = "0.1.0" dependencies = [ "actix", - "alloy", + "alloy 0.2.1", "alloy-primitives 0.6.4", "alloy-sol-types 0.6.4", "async-std", @@ -2689,7 +3121,7 @@ dependencies = [ "pin-project-lite", "socket2 0.5.7", "tokio", - "tower", + "tower 0.4.13", "tower-service", "tracing", ] @@ -4356,6 +4788,28 @@ dependencies = [ "version_check", ] +[[package]] +name = "proc-macro-error-attr2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] +name = "proc-macro-error2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" +dependencies = [ + "proc-macro-error-attr2", + "proc-macro2", + "quote", + "syn 2.0.72", +] + [[package]] name = "proc-macro2" version = "1.0.86" @@ -4712,7 +5166,7 @@ dependencies = [ "serde", "serde_json", "serde_urlencoded", - "sync_wrapper", + "sync_wrapper 1.0.1", "tokio", "tokio-native-tls", "tower-service", @@ -5276,12 +5730,9 @@ dependencies = [ name = "sortition" version = "0.1.0" dependencies = [ - "actix", - "alloy", + "alloy 0.2.1", "alloy-primitives 0.6.4", "alloy-sol-types 0.6.4", - "async-std", - "enclave-core", "eyre", "futures-util", "num", @@ -5390,6 +5841,24 @@ dependencies = [ "syn 2.0.72", ] +[[package]] +name = "syn-solidity" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b95156f8b577cb59dc0b1df15c6f29a10afc5f8a7ac9786b0b5c68c19149278" +dependencies = [ + "paste", + "proc-macro2", + "quote", + "syn 2.0.72", +] + +[[package]] +name = "sync_wrapper" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" + [[package]] name = "sync_wrapper" version = "1.0.1" @@ -5668,6 +6137,20 @@ dependencies = [ "tracing", ] +[[package]] +name = "tower" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2873938d487c3cfb9aed7546dc9f2711d867c9f90c46b889989a2cb84eba6b4f" +dependencies = [ + "futures-core", + "futures-util", + "pin-project-lite", + "sync_wrapper 0.1.2", + "tower-layer", + "tower-service", +] + [[package]] name = "tower-layer" version = "0.3.3" @@ -5819,6 +6302,12 @@ dependencies = [ "tinyvec", ] +[[package]] +name = "unicode-xid" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "229730647fbc343e3a80e463c1db7f78f3855d3f3739bee0dda773c9a037c90a" + [[package]] name = "universal-hash" version = "0.5.1" diff --git a/packages/ciphernode/core/Cargo.toml b/packages/ciphernode/core/Cargo.toml index 44544994..ab995899 100644 --- a/packages/ciphernode/core/Cargo.toml +++ b/packages/ciphernode/core/Cargo.toml @@ -10,6 +10,7 @@ repository = "https://github.com/gnosisguild/enclave/packages/ciphernode" [dependencies] p2p = { path = "../p2p" } +sortition = { path = "../sortition" } async-std = "1.12.0" libp2p = "0.53.2" fhe = { git = "https://github.com/gnosisguild/fhe.rs", version = "0.1.0-beta.7" } @@ -26,4 +27,6 @@ sha2 = "0.10.8" bs58 = "0.5.1" serde = { version = "1.0.208", features = ["derive"] } bincode = "1.3.3" +alloy = "0.3.3" +alloy-primitives = { version = "0.6", default-features = false, features = ["rlp", "serde", "std"] } diff --git a/packages/ciphernode/core/src/ciphernode_selector.rs b/packages/ciphernode/core/src/ciphernode_selector.rs index 9d363953..43caad8b 100644 --- a/packages/ciphernode/core/src/ciphernode_selector.rs +++ b/packages/ciphernode/core/src/ciphernode_selector.rs @@ -1,9 +1,14 @@ use actix::prelude::*; +use alloy_primitives::Address; -use crate::{CiphernodeSelected, CommitteeRequested, EnclaveEvent, EventBus, Subscribe}; +use crate::{ + CiphernodeSelected, EnclaveEvent, EventBus, GetHasNode, Sortition, Subscribe, +}; pub struct CiphernodeSelector { bus: Addr, + sortition: Addr, + address: Address, } impl Actor for CiphernodeSelector { @@ -11,12 +16,16 @@ impl Actor for CiphernodeSelector { } impl CiphernodeSelector { - pub fn new(bus: Addr) -> Self { - Self { bus } + pub fn new(bus: Addr, sortition: Addr, address: Address) -> Self { + Self { + bus, + sortition, + address, + } } - pub fn attach(bus: Addr) -> Addr { - let addr = CiphernodeSelector::new(bus.clone()).start(); + pub fn attach(bus: Addr, sortition: Addr, address: Address) -> Addr { + let addr = CiphernodeSelector::new(bus.clone(), sortition, address).start(); bus.do_send(Subscribe::new( "CommitteeRequested", @@ -28,19 +37,39 @@ impl CiphernodeSelector { } impl Handler for CiphernodeSelector { - type Result = (); + type Result = ResponseFuture<()>; + + fn handle(&mut self, event: EnclaveEvent, _ctx: &mut Self::Context) -> Self::Result { + let address = self.address; + let sortition = self.sortition.clone(); + let bus = self.bus.clone(); + + Box::pin(async move { + let EnclaveEvent::CommitteeRequested { data, .. } = event else { + return; + }; - fn handle(&mut self, event: EnclaveEvent, ctx: &mut Self::Context) -> Self::Result { - match event { - EnclaveEvent::CommitteeRequested { data, .. } => { - // TODO: ask Sortition module whether registered node has been selected - self.bus.do_send(EnclaveEvent::from(CiphernodeSelected { + let seed = data.sortition_seed; + let size = data.nodecount; + + if let Ok(is_selected) = sortition + .send(GetHasNode { + seed, + address, + size, + }) + .await + { + if !is_selected { + return; + } + + bus.do_send(EnclaveEvent::from(CiphernodeSelected { e3_id: data.e3_id, nodecount: data.nodecount, threshold: data.threshold, - })) + })); } - _ => (), - } + }) } } diff --git a/packages/ciphernode/core/src/events.rs b/packages/ciphernode/core/src/events.rs index 62a651dd..09b66e35 100644 --- a/packages/ciphernode/core/src/events.rs +++ b/packages/ciphernode/core/src/events.rs @@ -1,5 +1,5 @@ use actix::Message; -use bincode; +use alloy_primitives::Address; use serde::{Deserialize, Serialize}; use sha2::{Digest, Sha256}; use std::{ @@ -7,6 +7,15 @@ use std::{ hash::{DefaultHasher, Hash, Hasher}, }; +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +pub struct EthAddr(pub Vec); + +impl From
for EthAddr { + fn from(value: Address) -> Self { + Self(value.to_vec()) + } +} + #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] pub struct E3id(pub String); impl fmt::Display for E3id { @@ -79,6 +88,14 @@ pub enum EnclaveEvent { id: EventId, data: CiphernodeSelected, }, + CiphernodeAdded { + id: EventId, + data: CiphernodeAdded, + }, + CiphernodeRemoved { + id: EventId, + data: CiphernodeRemoved, + }, // CommitteeSelected, // OutputDecrypted, // CiphernodeRegistered, @@ -99,6 +116,7 @@ impl EnclaveEvent { } pub fn is_local_only(&self) -> bool { + // Add a list of local events match self { EnclaveEvent::CiphernodeSelected { .. } => true, _ => false, @@ -116,20 +134,23 @@ impl From for EventId { EnclaveEvent::DecryptionshareCreated { id, .. } => id, EnclaveEvent::PlaintextAggregated { id, .. } => id, EnclaveEvent::CiphernodeSelected { id, .. } => id, + EnclaveEvent::CiphernodeAdded { id, .. } => id, + EnclaveEvent::CiphernodeRemoved { id, .. } => id, } } } -impl From for E3id { - fn from(value: EnclaveEvent) -> Self { - match value { - EnclaveEvent::KeyshareCreated { data, .. } => data.e3_id, - EnclaveEvent::CommitteeRequested { data, .. } => data.e3_id, - EnclaveEvent::PublicKeyAggregated { data, .. } => data.e3_id, - EnclaveEvent::CiphertextOutputPublished { data, .. } => data.e3_id, - EnclaveEvent::DecryptionshareCreated { data, .. } => data.e3_id, - EnclaveEvent::PlaintextAggregated { data, .. } => data.e3_id, - EnclaveEvent::CiphernodeSelected { data, .. } => data.e3_id, +impl EnclaveEvent { + pub fn get_e3_id(&self) -> Option { + match self.clone() { + EnclaveEvent::KeyshareCreated { data, .. } => Some(data.e3_id), + EnclaveEvent::CommitteeRequested { data, .. } => Some(data.e3_id), + EnclaveEvent::PublicKeyAggregated { data, .. } => Some(data.e3_id), + EnclaveEvent::CiphertextOutputPublished { data, .. } => Some(data.e3_id), + EnclaveEvent::DecryptionshareCreated { data, .. } => Some(data.e3_id), + EnclaveEvent::PlaintextAggregated { data, .. } => Some(data.e3_id), + EnclaveEvent::CiphernodeSelected { data, .. } => Some(data.e3_id), + _ => None, } } } @@ -197,6 +218,23 @@ impl From for EnclaveEvent { } } +impl From for EnclaveEvent { + fn from(data: CiphernodeAdded) -> Self { + EnclaveEvent::CiphernodeAdded { + id: EventId::from(data.clone()), + data: data.clone(), + } + } +} + +impl From for EnclaveEvent { + fn from(data: CiphernodeRemoved) -> Self { + EnclaveEvent::CiphernodeRemoved { + id: EventId::from(data.clone()), + data: data.clone(), + } + } +} impl fmt::Display for EnclaveEvent { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str(&format!("{}({})", self.event_type(), self.get_id())) @@ -230,12 +268,13 @@ pub struct CommitteeRequested { pub e3_id: E3id, pub nodecount: usize, pub threshold: usize, - pub sortition_seed: u32, + pub sortition_seed: u64, // Should actually be much larger eg [u8;32] + // fhe params pub moduli: Vec, pub degree: usize, pub plaintext_modulus: u64, - pub crp: Vec + pub crp: Vec, // computation_type: ??, // TODO: // execution_model_type: ??, // TODO: // input_deadline: ??, // TODO: @@ -264,6 +303,22 @@ pub struct PlaintextAggregated { pub decrypted_output: Vec, } +#[derive(Message, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[rtype(result = "()")] +pub struct CiphernodeAdded { + pub address: Address, + pub index: usize, + pub num_nodes: usize, +} + +#[derive(Message, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[rtype(result = "()")] +pub struct CiphernodeRemoved { + pub address: Address, + pub index: usize, + pub num_nodes: usize, +} + fn extract_enclave_event_name(s: &str) -> &str { let bytes = s.as_bytes(); for (i, &item) in bytes.iter().enumerate() { diff --git a/packages/ciphernode/core/src/lib.rs b/packages/ciphernode/core/src/lib.rs index 006ab118..bf603062 100644 --- a/packages/ciphernode/core/src/lib.rs +++ b/packages/ciphernode/core/src/lib.rs @@ -19,6 +19,7 @@ mod publickey_aggregator; mod publickey_sequencer; mod registry; mod serializers; +mod sortition; // TODO: this is too permissive pub use actix::prelude::*; @@ -36,6 +37,7 @@ pub use plaintext_sequencer::*; pub use publickey_aggregator::*; pub use publickey_sequencer::*; pub use registry::*; +pub use sortition::*; // TODO: move these out to a test folder #[cfg(test)] @@ -50,16 +52,18 @@ mod tests { CiphertextSerializer, DecryptionShareSerializer, PublicKeySerializer, PublicKeyShareSerializer, }, - CiphernodeSelected, CiphertextOutputPublished, DecryptionshareCreated, PlaintextAggregated, - Registry, ResetHistory, SharedRng, + CiphernodeAdded, CiphernodeSelected, CiphertextOutputPublished, DecryptionshareCreated, + PlaintextAggregated, Registry, ResetHistory, SharedRng, Sortition, }; use actix::prelude::*; + use alloy_primitives::Address; use anyhow::*; use fhe::{ bfv::{BfvParameters, BfvParametersBuilder, Encoding, Plaintext, PublicKey, SecretKey}, mbfv::{AggregateIter, CommonRandomPoly, DecryptionShare, PublicKeyShare}, }; use fhe_traits::{FheEncoder, FheEncrypter, Serialize}; + use rand::Rng; use rand::SeedableRng; use rand_chacha::ChaCha20Rng; use std::{sync::Arc, time::Duration}; @@ -67,12 +71,18 @@ mod tests { use tokio::{sync::mpsc::channel, time::sleep}; // Simulating a local node - async fn setup_local_ciphernode(bus: Addr, rng: SharedRng, logging: bool) { + async fn setup_local_ciphernode( + bus: Addr, + rng: SharedRng, + logging: bool, + addr: Address, + ) { // create data actor for saving data let data = Data::new(logging).start(); // TODO: Use a sled backed Data Actor // create ciphernode actor for managing ciphernode flow - CiphernodeSelector::attach(bus.clone()); + let sortition = Sortition::attach(bus.clone()); + CiphernodeSelector::attach(bus.clone(), sortition, addr); Registry::attach(bus.clone(), data.clone(), rng).await; } @@ -84,7 +94,7 @@ mod tests { BfvParametersBuilder::new() .set_degree(degree) .set_plaintext_modulus(plaintext_modulus) - .set_moduli(&moduli) + .set_moduli(moduli) .build_arc() .unwrap() } @@ -137,9 +147,14 @@ mod tests { let bus = EventBus::new(true).start(); let rng = Arc::new(std::sync::Mutex::new(ChaCha20Rng::seed_from_u64(42))); - setup_local_ciphernode(bus.clone(), rng.clone(), true).await; - setup_local_ciphernode(bus.clone(), rng.clone(), true).await; - setup_local_ciphernode(bus.clone(), rng.clone(), true).await; + + let eth_addrs: Vec
= (0..3) + .map(|_| Address::from_slice(&rand::thread_rng().gen::<[u8; 20]>())) + .collect(); + + setup_local_ciphernode(bus.clone(), rng.clone(), true, eth_addrs[0]).await; + setup_local_ciphernode(bus.clone(), rng.clone(), true, eth_addrs[1]).await; + setup_local_ciphernode(bus.clone(), rng.clone(), true, eth_addrs[2]).await; let e3_id = E3id::new("1234"); @@ -149,7 +164,36 @@ mod tests { plaintext_modulus, crp_bytes, params, - } = setup_crp_params(&vec![0x3FFFFFFF000001], 2048, 1032193, Arc::new(std::sync::Mutex::new(ChaCha20Rng::seed_from_u64(42)))); + } = setup_crp_params( + &[0x3FFFFFFF000001], + 2048, + 1032193, + Arc::new(std::sync::Mutex::new(ChaCha20Rng::seed_from_u64(42))), + ); + + let regevt_1 = EnclaveEvent::from(CiphernodeAdded { + address: eth_addrs[0], + index: 0, + num_nodes: 1, + }); + + bus.send(regevt_1.clone()).await?; + + let regevt_2 = EnclaveEvent::from(CiphernodeAdded { + address: eth_addrs[1], + index: 1, + num_nodes: 2, + }); + + bus.send(regevt_2.clone()).await?; + + let regevt_3 = EnclaveEvent::from(CiphernodeAdded { + address: eth_addrs[2], + index: 2, + num_nodes: 3, + }); + + bus.send(regevt_3.clone()).await?; let event = EnclaveEvent::from(CommitteeRequested { e3_id: e3_id.clone(), @@ -179,15 +223,18 @@ mod tests { let (p2, sk2) = generate_pk_share(params.clone(), crpoly.clone(), rng_test.clone())?; let (p3, sk3) = generate_pk_share(params.clone(), crpoly.clone(), rng_test.clone())?; - let pubkey: PublicKey = vec![p1.clone(), p2.clone(), p3.clone()] + let pubkey: PublicKey = [p1.clone(), p2.clone(), p3.clone()] .iter() .map(|k| PublicKeyShareSerializer::from_bytes(k).unwrap()) .aggregate()?; - assert_eq!(history.len(), 6); + assert_eq!(history.len(), 9); assert_eq!( history, vec![ + regevt_1, + regevt_2, + regevt_3, EnclaveEvent::from(CommitteeRequested { e3_id: e3_id.clone(), nodecount: 3, diff --git a/packages/ciphernode/core/src/registry.rs b/packages/ciphernode/core/src/registry.rs index 683b6026..26ec9b1a 100644 --- a/packages/ciphernode/core/src/registry.rs +++ b/packages/ciphernode/core/src/registry.rs @@ -63,7 +63,9 @@ impl Handler for Registry { type Result = (); fn handle(&mut self, msg: EnclaveEvent, _ctx: &mut Self::Context) -> Self::Result { - let e3_id = E3id::from(msg.clone()); + let Some(e3_id) = msg.get_e3_id() else { + return; + }; match msg.clone() { EnclaveEvent::CommitteeRequested { data, .. } => { diff --git a/packages/ciphernode/core/src/sortition.rs b/packages/ciphernode/core/src/sortition.rs new file mode 100644 index 00000000..f808be3d --- /dev/null +++ b/packages/ciphernode/core/src/sortition.rs @@ -0,0 +1,120 @@ +use std::collections::HashSet; + +use actix::prelude::*; +use alloy_primitives::Address; +use sortition::DistanceSortition; + +use crate::{CiphernodeAdded, CiphernodeRemoved, EnclaveEvent, EthAddr, EventBus, Subscribe}; + +#[derive(Message, Clone, Debug, PartialEq, Eq)] +#[rtype(result = "bool")] +pub struct GetHasNode { + pub seed: u64, + pub address: Address, + pub size: usize, +} + +pub trait SortitionList { + fn contains(&self, seed: u64, size: usize, address: T) -> bool; + fn add(&mut self, address: T); + fn remove(&mut self, address: T); +} + +pub struct SortitionModule { + nodes: HashSet
, +} + +impl SortitionModule { + pub fn new() -> Self { + Self { + nodes: HashSet::new(), + } + } +} + +impl Default for SortitionModule { + fn default() -> Self { + Self::new() + } +} + +impl SortitionList
for SortitionModule { + fn contains(&self, seed: u64, size: usize, address: Address) -> bool { + DistanceSortition::new( + seed, + self.nodes.clone().into_iter().collect(), + size, + ) + .get_committee() + .iter() + .any(|(_, addr)| *addr == address) + } + + fn add(&mut self, address: Address) { + self.nodes.insert(address); + } + + fn remove(&mut self, address: Address) { + self.nodes.remove(&address); + } +} + +pub struct Sortition { + list: SortitionModule, +} + +impl Sortition { + pub fn new() -> Self { + Self { + list: SortitionModule::new(), + } + } + + pub fn attach(bus: Addr) -> Addr { + let addr = Sortition::new().start(); + bus.do_send(Subscribe::new("CiphernodeAdded", addr.clone().into())); + addr + } +} + +impl Default for Sortition { + fn default() -> Self { + Self::new() + } +} + +impl Actor for Sortition { + type Context = Context; +} + +impl Handler for Sortition { + type Result = (); + fn handle(&mut self, msg: EnclaveEvent, ctx: &mut Self::Context) -> Self::Result { + match msg { + EnclaveEvent::CiphernodeAdded { data, .. } => ctx.notify(data.clone()), + EnclaveEvent::CiphernodeRemoved { data, .. } => ctx.notify(data.clone()), + _ => (), + } + } +} + +impl Handler for Sortition { + type Result = (); + fn handle(&mut self, msg: CiphernodeAdded, _ctx: &mut Self::Context) -> Self::Result { + self.list.add(msg.address); + } +} + +impl Handler for Sortition { + type Result = (); + fn handle(&mut self, msg: CiphernodeRemoved, _ctx: &mut Self::Context) -> Self::Result { + self.list.remove(msg.address); + } +} + +impl Handler for Sortition { + type Result = bool; + fn handle(&mut self, msg: GetHasNode, _ctx: &mut Self::Context) -> Self::Result { + self.list.contains(msg.seed, msg.size, msg.address) + } +} diff --git a/packages/ciphernode/sortition/Cargo.toml b/packages/ciphernode/sortition/Cargo.toml index c4f69dd2..54704919 100644 --- a/packages/ciphernode/sortition/Cargo.toml +++ b/packages/ciphernode/sortition/Cargo.toml @@ -12,16 +12,9 @@ path = "src/lib.rs" num = "0.4.3" rand = "0.8.5" -# Core -enclave-core = { path = "../core" } - -# Actix -actix = "0.13.5" -async-std = "1.12.0" - # Ethereum futures-util = "0.3" eyre = "0.6" alloy = { version = "0.2.1", features = ["full"] } alloy-primitives = { version = "0.6", default-features = false, features = ["rlp", "serde", "std"] } -alloy-sol-types = { version = "0.6" } \ No newline at end of file +alloy-sol-types = { version = "0.6" } From 01e021e72fbaff6fe33925383adfd55f42f67d3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=B3=CE=BB?= Date: Fri, 13 Sep 2024 21:48:43 +1000 Subject: [PATCH 50/87] setup sortition module against public key aggregator (#59) --- packages/ciphernode/core/src/ciphernode.rs | 23 +++-- .../core/src/ciphernode_sequencer.rs | 8 +- packages/ciphernode/core/src/events.rs | 4 + packages/ciphernode/core/src/lib.rs | 12 ++- .../core/src/publickey_aggregator.rs | 96 +++++++++++++------ .../core/src/publickey_sequencer.rs | 12 ++- packages/ciphernode/core/src/registry.rs | 35 +++++-- 7 files changed, 136 insertions(+), 54 deletions(-) diff --git a/packages/ciphernode/core/src/ciphernode.rs b/packages/ciphernode/core/src/ciphernode.rs index 99ebd6a3..2e7bc0bf 100644 --- a/packages/ciphernode/core/src/ciphernode.rs +++ b/packages/ciphernode/core/src/ciphernode.rs @@ -7,12 +7,14 @@ use crate::{ Subscribe, }; use actix::prelude::*; +use alloy_primitives::Address; use anyhow::Result; pub struct Ciphernode { fhe: Addr, data: Addr, bus: Addr, + address: Address } impl Actor for Ciphernode { @@ -20,12 +22,12 @@ impl Actor for Ciphernode { } impl Ciphernode { - pub fn new(bus: Addr, fhe: Addr, data: Addr) -> Self { - Self { bus, fhe, data } + pub fn new(bus: Addr, fhe: Addr, data: Addr, address: Address) -> Self { + Self { bus, fhe, data, address } } - pub async fn attach(bus: Addr, fhe: Addr, data: Addr) -> Addr { - let node = Ciphernode::new(bus.clone(), fhe, data).start(); + pub async fn attach(bus: Addr, fhe: Addr, data: Addr, address: Address) -> Addr { + let node = Ciphernode::new(bus.clone(), fhe, data, address).start(); let _ = bus .send(Subscribe::new("CiphernodeSelected", node.clone().into())) .await; @@ -58,7 +60,8 @@ impl Handler for Ciphernode { let fhe = self.fhe.clone(); let data = self.data.clone(); let bus = self.bus.clone(); - Box::pin(async { on_ciphernode_selected(fhe, data, bus, event).await.unwrap() }) + let address = self.address; + Box::pin(async move { on_ciphernode_selected(fhe, data, bus, event, address).await.unwrap() }) } } @@ -69,8 +72,9 @@ impl Handler for Ciphernode { let fhe = self.fhe.clone(); let data = self.data.clone(); let bus = self.bus.clone(); - Box::pin(async { - on_decryption_requested(fhe, data, bus, event) + let address = self.address; + Box::pin(async move { + on_decryption_requested(fhe, data, bus, event, address) .await .unwrap() }) @@ -82,6 +86,7 @@ async fn on_ciphernode_selected( data: Addr, bus: Addr, event: CiphernodeSelected, + address: Address ) -> Result<()> { let CiphernodeSelected { e3_id, .. } = event; // generate keyshare @@ -98,7 +103,7 @@ async fn on_ciphernode_selected( data.do_send(Insert(format!("{}/pk", e3_id).into(), pubkey.clone())); // broadcast the KeyshareCreated message - let event = EnclaveEvent::from(KeyshareCreated { pubkey, e3_id }); + let event = EnclaveEvent::from(KeyshareCreated { pubkey, e3_id, node: address }); bus.do_send(event); Ok(()) @@ -109,6 +114,7 @@ async fn on_decryption_requested( data: Addr, bus: Addr, event: CiphertextOutputPublished, + address: Address ) -> Result<()> { let CiphertextOutputPublished { e3_id, @@ -130,6 +136,7 @@ async fn on_decryption_requested( let event = EnclaveEvent::from(DecryptionshareCreated { e3_id, decryption_share, + node: address }); bus.do_send(event); diff --git a/packages/ciphernode/core/src/ciphernode_sequencer.rs b/packages/ciphernode/core/src/ciphernode_sequencer.rs index ae3b48c9..591e955d 100644 --- a/packages/ciphernode/core/src/ciphernode_sequencer.rs +++ b/packages/ciphernode/core/src/ciphernode_sequencer.rs @@ -3,6 +3,7 @@ // TODO: if the ciphernode fails restart the node by replaying all stored events back to it use actix::prelude::*; +use alloy_primitives::Address; use crate::{Ciphernode, Data, EnclaveEvent, EventBus, Fhe}; @@ -11,14 +12,16 @@ pub struct CiphernodeSequencer { data: Addr, bus: Addr, child: Option>, + address: Address, } impl CiphernodeSequencer { - pub fn new(fhe: Addr, data: Addr, bus: Addr) -> Self { + pub fn new(fhe: Addr, data: Addr, bus: Addr, address:Address) -> Self { Self { fhe, bus, data, child: None, + address } } } @@ -32,9 +35,10 @@ impl Handler for CiphernodeSequencer { let bus = self.bus.clone(); let fhe = self.fhe.clone(); let data = self.data.clone(); + let address = self.address; let sink = self .child - .get_or_insert_with(|| Ciphernode::new(bus, fhe, data).start()); + .get_or_insert_with(|| Ciphernode::new(bus, fhe, data, address).start()); sink.do_send(msg); } } diff --git a/packages/ciphernode/core/src/events.rs b/packages/ciphernode/core/src/events.rs index 09b66e35..eb6ef6bd 100644 --- a/packages/ciphernode/core/src/events.rs +++ b/packages/ciphernode/core/src/events.rs @@ -246,6 +246,7 @@ impl fmt::Display for EnclaveEvent { pub struct KeyshareCreated { pub pubkey: Vec, pub e3_id: E3id, + pub node: Address } #[derive(Message, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] @@ -253,6 +254,7 @@ pub struct KeyshareCreated { pub struct DecryptionshareCreated { pub decryption_share: Vec, pub e3_id: E3id, + pub node: Address } #[derive(Message, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] @@ -343,6 +345,7 @@ mod tests { events::extract_enclave_event_name, serializers::PublicKeyShareSerializer, E3id, KeyshareCreated, }; + use alloy_primitives::address; use fhe::{ bfv::{BfvParametersBuilder, SecretKey}, mbfv::{CommonRandomPoly, PublicKeyShare}, @@ -381,6 +384,7 @@ mod tests { let kse = EnclaveEvent::from(KeyshareCreated { e3_id: E3id::from(1001), pubkey, + node: address!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045") }); let kse_bytes = kse.to_bytes()?; let _ = EnclaveEvent::from_bytes(&kse_bytes.clone()); diff --git a/packages/ciphernode/core/src/lib.rs b/packages/ciphernode/core/src/lib.rs index bf603062..96d3e1f7 100644 --- a/packages/ciphernode/core/src/lib.rs +++ b/packages/ciphernode/core/src/lib.rs @@ -82,8 +82,8 @@ mod tests { // create ciphernode actor for managing ciphernode flow let sortition = Sortition::attach(bus.clone()); - CiphernodeSelector::attach(bus.clone(), sortition, addr); - Registry::attach(bus.clone(), data.clone(), rng).await; + CiphernodeSelector::attach(bus.clone(), sortition.clone(), addr); + Registry::attach(bus.clone(), data.clone(), sortition, rng, addr).await; } fn setup_bfv_params( @@ -253,14 +253,17 @@ mod tests { EnclaveEvent::from(KeyshareCreated { pubkey: p1.clone(), e3_id: e3_id.clone(), + node: eth_addrs[0] }), EnclaveEvent::from(KeyshareCreated { pubkey: p2.clone(), e3_id: e3_id.clone(), + node: eth_addrs[1] }), EnclaveEvent::from(KeyshareCreated { pubkey: p3.clone(), - e3_id: e3_id.clone() + e3_id: e3_id.clone(), + node: eth_addrs[2] }), EnclaveEvent::from(PublicKeyAggregated { pubkey: PublicKeySerializer::to_bytes(pubkey.clone(), params.clone())?, @@ -321,14 +324,17 @@ mod tests { EnclaveEvent::from(DecryptionshareCreated { decryption_share: ds1.clone(), e3_id: e3_id.clone(), + node: eth_addrs[0] }), EnclaveEvent::from(DecryptionshareCreated { decryption_share: ds2.clone(), e3_id: e3_id.clone(), + node: eth_addrs[1] }), EnclaveEvent::from(DecryptionshareCreated { decryption_share: ds3.clone(), e3_id: e3_id.clone(), + node: eth_addrs[2] }), EnclaveEvent::from(PlaintextAggregated { e3_id: e3_id.clone(), diff --git a/packages/ciphernode/core/src/publickey_aggregator.rs b/packages/ciphernode/core/src/publickey_aggregator.rs index bc8733dd..b287309c 100644 --- a/packages/ciphernode/core/src/publickey_aggregator.rs +++ b/packages/ciphernode/core/src/publickey_aggregator.rs @@ -3,15 +3,17 @@ use crate::{ events::{E3id, EnclaveEvent, KeyshareCreated, PublicKeyAggregated}, fhe::{Fhe, GetAggregatePublicKey}, ordered_set::OrderedSet, + GetHasNode, Sortition, }; use actix::prelude::*; -use anyhow::{anyhow, Result}; +use anyhow::Result; #[derive(Debug, Clone)] pub enum PublicKeyAggregatorState { Collecting { nodecount: usize, keyshares: OrderedSet>, + seed: u64, }, Computing { keyshares: OrderedSet>, @@ -31,6 +33,7 @@ struct ComputeAggregate { pub struct PublicKeyAggregator { fhe: Addr, bus: Addr, + sortition: Addr, e3_id: E3id, state: PublicKeyAggregatorState, } @@ -42,14 +45,23 @@ pub struct PublicKeyAggregator { /// It is expected to change this mechanism as we work through adversarial scenarios and write tests /// for them. impl PublicKeyAggregator { - pub fn new(fhe: Addr, bus: Addr, e3_id: E3id, nodecount: usize) -> Self { + pub fn new( + fhe: Addr, + bus: Addr, + sortition: Addr, + e3_id: E3id, + nodecount: usize, + seed: u64, + ) -> Self { PublicKeyAggregator { fhe, bus, e3_id, + sortition, state: PublicKeyAggregatorState::Collecting { nodecount, keyshares: OrderedSet::new(), + seed, }, } } @@ -58,6 +70,7 @@ impl PublicKeyAggregator { let PublicKeyAggregatorState::Collecting { nodecount, keyshares, + .. } = &mut self.state else { return Err(anyhow::anyhow!("Can only add keyshare in Collecting state")); @@ -94,41 +107,68 @@ impl Actor for PublicKeyAggregator { impl Handler for PublicKeyAggregator { type Result = (); fn handle(&mut self, msg: EnclaveEvent, ctx: &mut Self::Context) -> Self::Result { - match msg { - EnclaveEvent::KeyshareCreated { data, .. } => ctx.notify(data), - _ => () + if let EnclaveEvent::KeyshareCreated { data, .. } = msg { + ctx.notify(data) } } } impl Handler for PublicKeyAggregator { - type Result = Result<()>; - - fn handle(&mut self, event: KeyshareCreated, ctx: &mut Self::Context) -> Self::Result { - - if event.e3_id != self.e3_id { - return Err(anyhow!( - "Wrong e3_id sent to aggregator. This should not happen." - )); - } + type Result = ResponseActFuture>; - let PublicKeyAggregatorState::Collecting { .. } = self.state else { - return Err(anyhow!( - "Aggregator has been closed for collecting keyshares." - )); + fn handle(&mut self, event: KeyshareCreated, _: &mut Self::Context) -> Self::Result { + let PublicKeyAggregatorState::Collecting { + nodecount, seed, .. + } = self.state.clone() + else { + return Box::pin(fut::ready(Ok(()))); }; - // add the keyshare and - self.state = self.add_keyshare(event.pubkey)?; + let size = nodecount; + let address = event.node; + let e3_id = event.e3_id.clone(); + let pubkey = event.pubkey.clone(); - // Check the state and if it has changed to the computing - if let PublicKeyAggregatorState::Computing { keyshares } = &self.state { - ctx.notify(ComputeAggregate { - keyshares: keyshares.clone(), - }) - } + Box::pin( + self.sortition + .send(GetHasNode { + address, + size, + seed, + }) + .into_actor(self) + .map(move |res, act, ctx| { + // NOTE: Returning Ok(()) on errors as we probably dont need a result type here since + // we will not be doing a send + let has_node = res?; + if !has_node { + println!("Node not found in committee"); // TODO: log properly + return Ok(()); + } + + if e3_id != act.e3_id { + println!("Wrong e3_id sent to aggregator. This should not happen."); + return Ok(()); + } + + let PublicKeyAggregatorState::Collecting { .. } = act.state else { + println!("Aggregator has been closed for collecting keyshares."); // TODO: log properly + return Ok(()); + }; + + // add the keyshare and + act.state = act.add_keyshare(pubkey)?; + + // Check the state and if it has changed to the computing + if let PublicKeyAggregatorState::Computing { keyshares } = &act.state { + ctx.notify(ComputeAggregate { + keyshares: keyshares.clone(), + }) + } - Ok(()) + Ok(()) + }), + ) } } @@ -170,5 +210,3 @@ impl Handler for PublicKeyAggregator { ) } } - - diff --git a/packages/ciphernode/core/src/publickey_sequencer.rs b/packages/ciphernode/core/src/publickey_sequencer.rs index f5db6a47..e43aaf51 100644 --- a/packages/ciphernode/core/src/publickey_sequencer.rs +++ b/packages/ciphernode/core/src/publickey_sequencer.rs @@ -3,22 +3,26 @@ use actix::prelude::*; -use crate::{E3id, EnclaveEvent, EventBus, Fhe, PublicKeyAggregator}; +use crate::{E3id, EnclaveEvent, EventBus, Fhe, PublicKeyAggregator, Sortition}; pub struct PublicKeySequencer { fhe: Addr, e3_id: E3id, bus: Addr, + sortition:Addr, nodecount: usize, + seed: u64, child: Option>, } impl PublicKeySequencer { - pub fn new(fhe: Addr, e3_id: E3id, bus: Addr, nodecount: usize) -> Self { + pub fn new(fhe: Addr, e3_id: E3id, sortition:Addr,bus: Addr, nodecount: usize, seed:u64) -> Self { Self { fhe, e3_id, bus, + sortition, + seed, nodecount, child: None, } @@ -34,11 +38,13 @@ impl Handler for PublicKeySequencer { fn handle(&mut self, msg: EnclaveEvent, _ctx: &mut Self::Context) -> Self::Result { let fhe = self.fhe.clone(); let bus = self.bus.clone(); + let sortition = self.sortition.clone(); let nodecount = self.nodecount; let e3_id = self.e3_id.clone(); + let seed = self.seed; let dest = self .child - .get_or_insert_with(|| PublicKeyAggregator::new(fhe, bus, e3_id, nodecount).start()); + .get_or_insert_with(|| PublicKeyAggregator::new(fhe, bus, sortition, e3_id, nodecount, seed).start()); dest.do_send(msg); } } diff --git a/packages/ciphernode/core/src/registry.rs b/packages/ciphernode/core/src/registry.rs index 26ec9b1a..81ca54fb 100644 --- a/packages/ciphernode/core/src/registry.rs +++ b/packages/ciphernode/core/src/registry.rs @@ -3,9 +3,10 @@ // on config use crate::{ CiphernodeSequencer, CommitteeRequested, Data, E3id, EnclaveEvent, EventBus, Fhe, - PlaintextSequencer, PublicKeySequencer, Subscribe, + PlaintextSequencer, PublicKeySequencer, Sortition, Subscribe, }; use actix::prelude::*; +use alloy_primitives::Address; use rand_chacha::ChaCha20Rng; use std::{ collections::HashMap, @@ -21,6 +22,8 @@ pub struct Registry { bus: Addr, ciphernodes: HashMap>, data: Addr, + sortition: Addr, + address: Address, fhes: HashMap>, plaintexts: HashMap>, meta: HashMap, @@ -29,11 +32,19 @@ pub struct Registry { } impl Registry { - pub fn new(bus: Addr, data: Addr, rng: Arc>) -> Self { + pub fn new( + bus: Addr, + data: Addr, + sortition: Addr, + rng: Arc>, + address: Address, + ) -> Self { Self { bus, data, + sortition, rng, + address, ciphernodes: HashMap::new(), plaintexts: HashMap::new(), public_keys: HashMap::new(), @@ -45,9 +56,11 @@ impl Registry { pub async fn attach( bus: Addr, data: Addr, + sortition: Addr, rng: Arc>, + address: Address, ) -> Addr { - let addr = Registry::new(bus.clone(), data, rng).start(); + let addr = Registry::new(bus.clone(), data, sortition, rng, address).start(); bus.send(Subscribe::new("*", addr.clone().into())) .await .unwrap(); @@ -74,6 +87,7 @@ impl Handler for Registry { moduli, plaintext_modulus, crp, + sortition_seed, .. } = data; @@ -86,7 +100,7 @@ impl Handler for Registry { self.meta.entry(e3_id.clone()).or_insert(meta.clone()); let public_key_sequencer_factory = - self.public_key_sequencer_factory(e3_id.clone(), meta.clone(), fhe.clone()); + self.public_key_sequencer_factory(e3_id.clone(), meta.clone(), fhe.clone(), sortition_seed); store(&e3_id, &mut self.public_keys, public_key_sequencer_factory); let ciphernode_sequencer_factory = self.ciphernode_sequencer_factory(fhe.clone()); @@ -133,10 +147,12 @@ impl Registry { e3_id: E3id, meta: CommitteeMeta, fhe: Addr, + seed: u64, ) -> impl FnOnce() -> Addr { let bus = self.bus.clone(); let nodecount = meta.nodecount; - move || PublicKeySequencer::new(fhe, e3_id, bus, nodecount).start() + let sortition = self.sortition.clone(); + move || PublicKeySequencer::new(fhe, e3_id, sortition, bus, nodecount, seed).start() } fn ciphernode_sequencer_factory( @@ -145,7 +161,8 @@ impl Registry { ) -> impl FnOnce() -> Addr { let data = self.data.clone(); let bus = self.bus.clone(); - move || CiphernodeSequencer::new(fhe, data, bus).start() + let address = self.address; + move || CiphernodeSequencer::new(fhe, data, bus, address).start() } fn plaintext_sequencer_factory( @@ -160,15 +177,15 @@ impl Registry { } fn forward_message(&self, e3_id: &E3id, msg: EnclaveEvent) { - if let Some(act) = self.public_keys.get(&e3_id) { + if let Some(act) = self.public_keys.get(e3_id) { act.clone().recipient().do_send(msg.clone()); } - if let Some(act) = self.plaintexts.get(&e3_id) { + if let Some(act) = self.plaintexts.get(e3_id) { act.do_send(msg.clone()); } - if let Some(act) = self.ciphernodes.get(&e3_id) { + if let Some(act) = self.ciphernodes.get(e3_id) { act.do_send(msg.clone()); } } From d76aac6ce3031eeaa30ac76a44b018c91f46a681 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=B3=CE=BB?= Date: Fri, 13 Sep 2024 22:15:37 +1000 Subject: [PATCH 51/87] Add Sortition Module to Plaintext Aggregator (#60) --- .../core/src/plaintext_aggregator.rs | 95 +++++++++++++------ .../core/src/plaintext_sequencer.rs | 25 +++-- .../core/src/publickey_aggregator.rs | 7 +- packages/ciphernode/core/src/registry.rs | 14 ++- 4 files changed, 98 insertions(+), 43 deletions(-) diff --git a/packages/ciphernode/core/src/plaintext_aggregator.rs b/packages/ciphernode/core/src/plaintext_aggregator.rs index 29b88960..75c7c2ec 100644 --- a/packages/ciphernode/core/src/plaintext_aggregator.rs +++ b/packages/ciphernode/core/src/plaintext_aggregator.rs @@ -1,5 +1,6 @@ use crate::{ - ordered_set::OrderedSet, PlaintextAggregated, DecryptionshareCreated, E3id, EnclaveEvent, EventBus, Fhe, GetAggregatePlaintext + ordered_set::OrderedSet, DecryptionshareCreated, E3id, EnclaveEvent, EventBus, Fhe, + GetAggregatePlaintext, GetHasNode, PlaintextAggregated, Sortition, }; use actix::prelude::*; use anyhow::{anyhow, Result}; @@ -9,6 +10,7 @@ pub enum PlaintextAggregatorState { Collecting { nodecount: usize, shares: OrderedSet>, + seed: u64, }, Computing { shares: OrderedSet>, @@ -28,25 +30,38 @@ struct ComputeAggregate { pub struct PlaintextAggregator { fhe: Addr, bus: Addr, + sortition: Addr, e3_id: E3id, state: PlaintextAggregatorState, } impl PlaintextAggregator { - pub fn new(fhe: Addr, bus: Addr, e3_id: E3id, nodecount: usize) -> Self { + pub fn new( + fhe: Addr, + bus: Addr, + sortition: Addr, + e3_id: E3id, + nodecount: usize, + seed: u64, + ) -> Self { PlaintextAggregator { fhe, bus, + sortition, e3_id, state: PlaintextAggregatorState::Collecting { nodecount, shares: OrderedSet::new(), + seed, }, } } pub fn add_share(&mut self, share: Vec) -> Result { - let PlaintextAggregatorState::Collecting { nodecount, shares } = &mut self.state else { + let PlaintextAggregatorState::Collecting { + nodecount, shares, .. + } = &mut self.state + else { return Err(anyhow::anyhow!("Can only add share in Collecting state")); }; @@ -78,44 +93,68 @@ impl Actor for PlaintextAggregator { impl Handler for PlaintextAggregator { type Result = (); fn handle(&mut self, msg: EnclaveEvent, ctx: &mut Self::Context) -> Self::Result { - match msg { - EnclaveEvent::DecryptionshareCreated { data, .. } => ctx.notify(data), - _ => () + if let EnclaveEvent::DecryptionshareCreated { data, .. } = msg { + ctx.notify(data) } } } impl Handler for PlaintextAggregator { - type Result = Result<()>; - fn handle(&mut self, event: DecryptionshareCreated, ctx: &mut Self::Context) -> Self::Result { - if event.e3_id != self.e3_id { - return Err(anyhow!( - "Wrong e3_id sent to aggregator. This should not happen." - )); - } - let PlaintextAggregatorState::Collecting { .. } = self.state else { - return Err(anyhow!( - "Aggregator has been closed for collecting keyshares." - )); + type Result = ResponseActFuture>; + + fn handle(&mut self, event: DecryptionshareCreated, _: &mut Self::Context) -> Self::Result { + let PlaintextAggregatorState::Collecting { + nodecount, seed, .. + } = self.state + else { + println!("Aggregator has been closed for collecting."); + return Box::pin(fut::ready(Ok(()))); }; - // add the keyshare and - self.state = self.add_share(event.decryption_share)?; + let size = nodecount; + let address = event.node; + let e3_id = event.e3_id.clone(); + let decryption_share = event.decryption_share.clone(); - // Check the state and if it has changed to the computing - if let PlaintextAggregatorState::Computing { shares } = &self.state { - ctx.notify(ComputeAggregate { - shares: shares.clone(), - }) - } + Box::pin( + self.sortition + .send(GetHasNode { + address, + size, + seed, + }) + .into_actor(self) + .map(move |res, act, ctx| { + let has_node = res?; + if !has_node { + println!("Node not found in committee"); // TODO: log properly + return Ok(()); + } + + if e3_id != act.e3_id { + println!("Wrong e3_id sent to aggregator. This should not happen."); + return Ok(()); + } + + // add the keyshare and + act.state = act.add_share(decryption_share)?; + + // Check the state and if it has changed to the computing + if let PlaintextAggregatorState::Computing { shares } = &act.state { + ctx.notify(ComputeAggregate { + shares: shares.clone(), + }) + } - Ok(()) + Ok(()) + }), + ) } } impl Handler for PlaintextAggregator { type Result = ResponseActFuture>; - fn handle(&mut self, msg: ComputeAggregate, ctx: &mut Self::Context) -> Self::Result { + fn handle(&mut self, msg: ComputeAggregate, _: &mut Self::Context) -> Self::Result { Box::pin( self.fhe .send(GetAggregatePlaintext { @@ -139,5 +178,3 @@ impl Handler for PlaintextAggregator { ) } } - - diff --git a/packages/ciphernode/core/src/plaintext_sequencer.rs b/packages/ciphernode/core/src/plaintext_sequencer.rs index 87de9c5e..bf548e85 100644 --- a/packages/ciphernode/core/src/plaintext_sequencer.rs +++ b/packages/ciphernode/core/src/plaintext_sequencer.rs @@ -4,21 +4,32 @@ use actix::prelude::*; -use crate::{E3id, EnclaveEvent, EventBus, Fhe, PlaintextAggregator}; +use crate::{E3id, EnclaveEvent, EventBus, Fhe, PlaintextAggregator, Sortition}; pub struct PlaintextSequencer { fhe: Addr, e3_id: E3id, bus: Addr, + sortition: Addr, nodecount: usize, + seed: u64, child: Option>, } impl PlaintextSequencer { - pub fn new(fhe: Addr, e3_id: E3id, bus: Addr, nodecount: usize) -> Self { + pub fn new( + fhe: Addr, + e3_id: E3id, + bus: Addr, + sortition: Addr, + nodecount: usize, + seed: u64, + ) -> Self { Self { fhe, e3_id, bus, + sortition, + seed, nodecount, child: None, } @@ -30,14 +41,16 @@ impl Actor for PlaintextSequencer { impl Handler for PlaintextSequencer { type Result = (); - fn handle(&mut self, msg: EnclaveEvent, ctx: &mut Self::Context) -> Self::Result { + fn handle(&mut self, msg: EnclaveEvent, _: &mut Self::Context) -> Self::Result { let fhe = self.fhe.clone(); let bus = self.bus.clone(); + let sortition = self.sortition.clone(); let nodecount = self.nodecount; let e3_id = self.e3_id.clone(); - let sink = self - .child - .get_or_insert_with(|| PlaintextAggregator::new(fhe, bus, e3_id, nodecount).start()); + let seed = self.seed; + let sink = self.child.get_or_insert_with(|| { + PlaintextAggregator::new(fhe, bus, sortition, e3_id, nodecount, seed).start() + }); sink.do_send(msg); } } diff --git a/packages/ciphernode/core/src/publickey_aggregator.rs b/packages/ciphernode/core/src/publickey_aggregator.rs index b287309c..f6bc761c 100644 --- a/packages/ciphernode/core/src/publickey_aggregator.rs +++ b/packages/ciphernode/core/src/publickey_aggregator.rs @@ -121,6 +121,8 @@ impl Handler for PublicKeyAggregator { nodecount, seed, .. } = self.state.clone() else { + println!("Aggregator has been closed for collecting keyshares."); // TODO: log properly + return Box::pin(fut::ready(Ok(()))); }; @@ -151,11 +153,6 @@ impl Handler for PublicKeyAggregator { return Ok(()); } - let PublicKeyAggregatorState::Collecting { .. } = act.state else { - println!("Aggregator has been closed for collecting keyshares."); // TODO: log properly - return Ok(()); - }; - // add the keyshare and act.state = act.add_keyshare(pubkey)?; diff --git a/packages/ciphernode/core/src/registry.rs b/packages/ciphernode/core/src/registry.rs index 81ca54fb..440a1306 100644 --- a/packages/ciphernode/core/src/registry.rs +++ b/packages/ciphernode/core/src/registry.rs @@ -16,6 +16,7 @@ use std::{ #[derive(Clone)] struct CommitteeMeta { nodecount: usize, + seed: u64, } pub struct Registry { @@ -95,12 +96,17 @@ impl Handler for Registry { let fhe = store(&e3_id, &mut self.fhes, fhe_factory); let meta = CommitteeMeta { nodecount: data.nodecount, + seed: data.sortition_seed, }; self.meta.entry(e3_id.clone()).or_insert(meta.clone()); - let public_key_sequencer_factory = - self.public_key_sequencer_factory(e3_id.clone(), meta.clone(), fhe.clone(), sortition_seed); + let public_key_sequencer_factory = self.public_key_sequencer_factory( + e3_id.clone(), + meta.clone(), + fhe.clone(), + sortition_seed, + ); store(&e3_id, &mut self.public_keys, public_key_sequencer_factory); let ciphernode_sequencer_factory = self.ciphernode_sequencer_factory(fhe.clone()); @@ -172,8 +178,10 @@ impl Registry { fhe: Addr, ) -> impl FnOnce() -> Addr { let bus = self.bus.clone(); + let sortition = self.sortition.clone(); let nodecount = meta.nodecount; - move || PlaintextSequencer::new(fhe, e3_id, bus, nodecount).start() + let seed = meta.seed; + move || PlaintextSequencer::new(fhe, e3_id, bus, sortition, nodecount, seed).start() } fn forward_message(&self, e3_id: &E3id, msg: EnclaveEvent) { From f8d0e23f8ed663268d3383acd384c6ec81fb50e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=B3=CE=BB?= Date: Fri, 13 Sep 2024 23:56:51 +1000 Subject: [PATCH 52/87] Order events without sequencers (#65) * Order events without sequencers * Send initial events first followed by other early events * Ensure buffers are cleared once messages are taken --- .../core/src/ciphernode_sequencer.rs | 44 -------- packages/ciphernode/core/src/lib.rs | 6 -- .../core/src/plaintext_sequencer.rs | 56 ---------- .../core/src/publickey_sequencer.rs | 50 --------- packages/ciphernode/core/src/registry.rs | 100 ++++++++++++------ 5 files changed, 70 insertions(+), 186 deletions(-) delete mode 100644 packages/ciphernode/core/src/ciphernode_sequencer.rs delete mode 100644 packages/ciphernode/core/src/plaintext_sequencer.rs delete mode 100644 packages/ciphernode/core/src/publickey_sequencer.rs diff --git a/packages/ciphernode/core/src/ciphernode_sequencer.rs b/packages/ciphernode/core/src/ciphernode_sequencer.rs deleted file mode 100644 index 591e955d..00000000 --- a/packages/ciphernode/core/src/ciphernode_sequencer.rs +++ /dev/null @@ -1,44 +0,0 @@ -// sequence and persist events for a single E3 request in the correct order -// TODO: spawn and store a ciphernode upon start and forward all events to it in order -// TODO: if the ciphernode fails restart the node by replaying all stored events back to it - -use actix::prelude::*; -use alloy_primitives::Address; - -use crate::{Ciphernode, Data, EnclaveEvent, EventBus, Fhe}; - -pub struct CiphernodeSequencer { - fhe: Addr, - data: Addr, - bus: Addr, - child: Option>, - address: Address, -} -impl CiphernodeSequencer { - pub fn new(fhe: Addr, data: Addr, bus: Addr, address:Address) -> Self { - Self { - fhe, - bus, - data, - child: None, - address - } - } -} -impl Actor for CiphernodeSequencer { - type Context = Context; -} - -impl Handler for CiphernodeSequencer { - type Result = (); - fn handle(&mut self, msg: EnclaveEvent, _ctx: &mut Self::Context) -> Self::Result { - let bus = self.bus.clone(); - let fhe = self.fhe.clone(); - let data = self.data.clone(); - let address = self.address; - let sink = self - .child - .get_or_insert_with(|| Ciphernode::new(bus, fhe, data, address).start()); - sink.do_send(msg); - } -} diff --git a/packages/ciphernode/core/src/lib.rs b/packages/ciphernode/core/src/lib.rs index 96d3e1f7..556cde12 100644 --- a/packages/ciphernode/core/src/lib.rs +++ b/packages/ciphernode/core/src/lib.rs @@ -4,7 +4,6 @@ mod ciphernode; mod ciphernode_selector; -mod ciphernode_sequencer; mod data; mod enclave_contract; mod eventbus; @@ -14,9 +13,7 @@ mod logger; mod ordered_set; mod p2p; mod plaintext_aggregator; -mod plaintext_sequencer; mod publickey_aggregator; -mod publickey_sequencer; mod registry; mod serializers; mod sortition; @@ -25,7 +22,6 @@ mod sortition; pub use actix::prelude::*; pub use ciphernode::*; pub use ciphernode_selector::*; -pub use ciphernode_sequencer::*; pub use data::*; pub use eventbus::*; pub use events::*; @@ -33,9 +29,7 @@ pub use fhe::*; pub use logger::*; pub use p2p::*; pub use plaintext_aggregator::*; -pub use plaintext_sequencer::*; pub use publickey_aggregator::*; -pub use publickey_sequencer::*; pub use registry::*; pub use sortition::*; diff --git a/packages/ciphernode/core/src/plaintext_sequencer.rs b/packages/ciphernode/core/src/plaintext_sequencer.rs deleted file mode 100644 index bf548e85..00000000 --- a/packages/ciphernode/core/src/plaintext_sequencer.rs +++ /dev/null @@ -1,56 +0,0 @@ -// sequence and persist events for a single E3 request in the correct order -// TODO: spawn and store a ciphernode upon start and forward all events to it in order -// TODO: if the ciphernode fails restart the node by replaying all stored events back to it - -use actix::prelude::*; - -use crate::{E3id, EnclaveEvent, EventBus, Fhe, PlaintextAggregator, Sortition}; - -pub struct PlaintextSequencer { - fhe: Addr, - e3_id: E3id, - bus: Addr, - sortition: Addr, - nodecount: usize, - seed: u64, - child: Option>, -} -impl PlaintextSequencer { - pub fn new( - fhe: Addr, - e3_id: E3id, - bus: Addr, - sortition: Addr, - nodecount: usize, - seed: u64, - ) -> Self { - Self { - fhe, - e3_id, - bus, - sortition, - seed, - nodecount, - child: None, - } - } -} -impl Actor for PlaintextSequencer { - type Context = Context; -} - -impl Handler for PlaintextSequencer { - type Result = (); - fn handle(&mut self, msg: EnclaveEvent, _: &mut Self::Context) -> Self::Result { - let fhe = self.fhe.clone(); - let bus = self.bus.clone(); - let sortition = self.sortition.clone(); - let nodecount = self.nodecount; - let e3_id = self.e3_id.clone(); - let seed = self.seed; - let sink = self.child.get_or_insert_with(|| { - PlaintextAggregator::new(fhe, bus, sortition, e3_id, nodecount, seed).start() - }); - sink.do_send(msg); - } -} diff --git a/packages/ciphernode/core/src/publickey_sequencer.rs b/packages/ciphernode/core/src/publickey_sequencer.rs deleted file mode 100644 index e43aaf51..00000000 --- a/packages/ciphernode/core/src/publickey_sequencer.rs +++ /dev/null @@ -1,50 +0,0 @@ -// sequence and persist events for a single E3 request in the correct order -// TODO: if the sequencer fails restart the node by replaying all stored events back to it - -use actix::prelude::*; - -use crate::{E3id, EnclaveEvent, EventBus, Fhe, PublicKeyAggregator, Sortition}; - -pub struct PublicKeySequencer { - fhe: Addr, - e3_id: E3id, - bus: Addr, - sortition:Addr, - nodecount: usize, - seed: u64, - child: Option>, -} - -impl PublicKeySequencer { - pub fn new(fhe: Addr, e3_id: E3id, sortition:Addr,bus: Addr, nodecount: usize, seed:u64) -> Self { - Self { - fhe, - e3_id, - bus, - sortition, - seed, - nodecount, - child: None, - } - } -} - -impl Actor for PublicKeySequencer { - type Context = Context; -} - -impl Handler for PublicKeySequencer { - type Result = (); - fn handle(&mut self, msg: EnclaveEvent, _ctx: &mut Self::Context) -> Self::Result { - let fhe = self.fhe.clone(); - let bus = self.bus.clone(); - let sortition = self.sortition.clone(); - let nodecount = self.nodecount; - let e3_id = self.e3_id.clone(); - let seed = self.seed; - let dest = self - .child - .get_or_insert_with(|| PublicKeyAggregator::new(fhe, bus, sortition, e3_id, nodecount, seed).start()); - dest.do_send(msg); - } -} diff --git a/packages/ciphernode/core/src/registry.rs b/packages/ciphernode/core/src/registry.rs index 440a1306..817be879 100644 --- a/packages/ciphernode/core/src/registry.rs +++ b/packages/ciphernode/core/src/registry.rs @@ -2,8 +2,8 @@ // TODO: vertically modularize this so there is a registry for each function that get rolled up into one based // on config use crate::{ - CiphernodeSequencer, CommitteeRequested, Data, E3id, EnclaveEvent, EventBus, Fhe, - PlaintextSequencer, PublicKeySequencer, Sortition, Subscribe, + Ciphernode, CommitteeRequested, Data, E3id, EnclaveEvent, EventBus, Fhe, PlaintextAggregator, + PublicKeyAggregator, Sortition, Subscribe, }; use actix::prelude::*; use alloy_primitives::Address; @@ -21,14 +21,15 @@ struct CommitteeMeta { pub struct Registry { bus: Addr, - ciphernodes: HashMap>, + ciphernodes: HashMap>, data: Addr, sortition: Addr, address: Address, fhes: HashMap>, - plaintexts: HashMap>, + plaintexts: HashMap>, + buffers: HashMap>>, meta: HashMap, - public_keys: HashMap>, + public_keys: HashMap>, rng: Arc>, } @@ -49,6 +50,7 @@ impl Registry { ciphernodes: HashMap::new(), plaintexts: HashMap::new(), public_keys: HashMap::new(), + buffers: HashMap::new(), meta: HashMap::new(), fhes: HashMap::new(), } @@ -101,16 +103,16 @@ impl Handler for Registry { self.meta.entry(e3_id.clone()).or_insert(meta.clone()); - let public_key_sequencer_factory = self.public_key_sequencer_factory( + let public_key_factory = self.public_key_factory( e3_id.clone(), meta.clone(), fhe.clone(), sortition_seed, ); - store(&e3_id, &mut self.public_keys, public_key_sequencer_factory); + store(&e3_id, &mut self.public_keys, public_key_factory); - let ciphernode_sequencer_factory = self.ciphernode_sequencer_factory(fhe.clone()); - store(&e3_id, &mut self.ciphernodes, ciphernode_sequencer_factory); + let ciphernode_factory = self.ciphernode_factory(fhe.clone()); + store(&e3_id, &mut self.ciphernodes, ciphernode_factory); } EnclaveEvent::CiphertextOutputPublished { .. } => { let Some(fhe) = self.fhes.get(&e3_id) else { @@ -121,9 +123,9 @@ impl Handler for Registry { return; }; - let plaintext_sequencer_factory = - self.plaintext_sequencer_factory(e3_id.clone(), meta.clone(), fhe.clone()); - store(&e3_id, &mut self.plaintexts, plaintext_sequencer_factory); + let plaintext_factory = + self.plaintext_factory(e3_id.clone(), meta.clone(), fhe.clone()); + store(&e3_id, &mut self.plaintexts, plaintext_factory); } _ => (), }; @@ -148,53 +150,91 @@ impl Registry { } } - fn public_key_sequencer_factory( + fn public_key_factory( &self, e3_id: E3id, meta: CommitteeMeta, fhe: Addr, seed: u64, - ) -> impl FnOnce() -> Addr { + ) -> impl FnOnce() -> Addr { let bus = self.bus.clone(); let nodecount = meta.nodecount; let sortition = self.sortition.clone(); - move || PublicKeySequencer::new(fhe, e3_id, sortition, bus, nodecount, seed).start() + move || PublicKeyAggregator::new(fhe, bus, sortition, e3_id, nodecount, seed).start() } - fn ciphernode_sequencer_factory( - &self, - fhe: Addr, - ) -> impl FnOnce() -> Addr { + fn ciphernode_factory(&self, fhe: Addr) -> impl FnOnce() -> Addr { let data = self.data.clone(); let bus = self.bus.clone(); let address = self.address; - move || CiphernodeSequencer::new(fhe, data, bus, address).start() + move || Ciphernode::new(bus, fhe, data, address).start() } - fn plaintext_sequencer_factory( + fn plaintext_factory( &self, e3_id: E3id, meta: CommitteeMeta, fhe: Addr, - ) -> impl FnOnce() -> Addr { + ) -> impl FnOnce() -> Addr { let bus = self.bus.clone(); let sortition = self.sortition.clone(); let nodecount = meta.nodecount; let seed = meta.seed; - move || PlaintextSequencer::new(fhe, e3_id, bus, sortition, nodecount, seed).start() + move || PlaintextAggregator::new(fhe, bus, sortition, e3_id, nodecount, seed).start() } - fn forward_message(&self, e3_id: &E3id, msg: EnclaveEvent) { - if let Some(act) = self.public_keys.get(e3_id) { - act.clone().recipient().do_send(msg.clone()); + fn store_msg(&mut self, e3_id: E3id, msg: EnclaveEvent, key: &str) { + self.buffers + .entry(e3_id) + .or_default() + .entry(key.to_owned()) + .or_default() + .push(msg); + } + + fn take_msgs(&mut self, e3_id: E3id, key: &str) -> Vec { + self.buffers + .get_mut(&e3_id) + .and_then(|inner_map| inner_map.get_mut(key)) + .map(std::mem::take) + .unwrap_or_default() + } + + fn forward_message(&mut self, e3_id: &E3id, msg: EnclaveEvent) { + // Buffer events for each thing that has not been created + // TODO: Needs tidying up as this is verbose and repeats + // TODO: use an enum for the buffer keys + if let Some(act) = self.public_keys.clone().get(e3_id) { + let msgs = self.take_msgs(e3_id.clone(), "public_keys"); + let recipient = act.clone().recipient(); + recipient.do_send(msg.clone()); + for m in msgs { + recipient.do_send(m); + } + } else { + self.store_msg(e3_id.clone(), msg.clone(), "public_keys"); } - if let Some(act) = self.plaintexts.get(e3_id) { - act.do_send(msg.clone()); + if let Some(act) = self.plaintexts.clone().get(e3_id) { + let msgs = self.take_msgs(e3_id.clone(), "plaintexts"); + let recipient = act.clone().recipient(); + recipient.do_send(msg.clone()); + for m in msgs { + recipient.do_send(m); + } + } else { + self.store_msg(e3_id.clone(), msg.clone(), "plaintexts"); } - if let Some(act) = self.ciphernodes.get(e3_id) { - act.do_send(msg.clone()); + if let Some(act) = self.ciphernodes.clone().get(e3_id) { + let msgs = self.take_msgs(e3_id.clone(), "ciphernodes"); + let recipient = act.clone().recipient(); + recipient.do_send(msg.clone()); + for m in msgs { + recipient.do_send(m); + } + } else { + self.store_msg(e3_id.clone(), msg.clone(), "ciphernodes"); } } } From f5e52adaf8f8b1b79c4789d6b793538d26aec87c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=B3=CE=BB?= Date: Sat, 14 Sep 2024 23:25:32 +1000 Subject: [PATCH 53/87] Fix solidity tests and ensure tests are run and that we can merge in main (#67) This merges main into ciphernode_poc and fixes tests --- .gitignore | 4 +- README.md | 81 +- package.json | 6 +- packages/evm/.env.example | 4 + packages/evm/.gitignore | 1 - packages/evm/.prettierrc.yml | 2 +- packages/evm/.solhint.json | 2 +- packages/evm/README.md | 12 + packages/evm/contracts/Enclave.sol | 199 +- ...deRegistry.sol => ICiphernodeRegistry.sol} | 32 +- .../contracts/interfaces/IComputeProvider.sol | 14 + ...utVerifier.sol => IDecryptionVerifier.sol} | 9 +- packages/evm/contracts/interfaces/IE3.sol | 23 +- ...{IComputationModule.sol => IE3Program.sol} | 8 +- .../evm/contracts/interfaces/IEnclave.sol | 73 +- .../contracts/interfaces/IExecutionModule.sol | 12 - .../contracts/interfaces/IInputValidator.sol | 2 +- .../contracts/interfaces/IRegistryFilter.sol | 2 +- ...able.sol => CiphernodeRegistryOwnable.sol} | 74 +- .../registry/NaiveRegistryFilter.sol | 10 +- ...egistry.sol => MockCiphernodeRegistry.sol} | 14 +- .../contracts/test/MockComputeProvider.sol | 24 + ...erifier.sol => MockDecryptionVerifier.sol} | 6 +- ...omputationModule.sol => MockE3Program.sol} | 11 +- .../contracts/test/MockExecutionModule.sol | 22 - .../evm/contracts/test/MockInputValidator.sol | 2 +- .../evm/contracts/test/MockRegistryFilter.sol | 6 +- packages/evm/deploy/deploy.ts | 47 +- packages/evm/deployments/sepolia/.chainId | 1 + .../sepolia/CyphernodeRegistryOwnable.json | 726 +++++++ packages/evm/deployments/sepolia/Enclave.json | 1757 +++++++++++++++++ .../sepolia/NaiveRegistryFilter.json | 458 +++++ .../d0e6e4f19028714f394c36db62dff2be.json | 93 + packages/evm/hardhat.config.ts | 35 +- packages/evm/package.json | 12 +- packages/evm/tasks/enclave.ts | 21 - packages/evm/test/Enclave.spec.ts | 647 +++--- packages/evm/test/fixtures/Enclave.fixture.ts | 9 +- .../MockCiphernodeRegistry.fixture.ts | 15 + .../fixtures/MockComputationModule.fixture.ts | 11 - .../fixtures/MockComputeProvider.fixture.ts | 11 + .../MockCyphernodeRegistry.fixture.ts | 15 - .../MockDecryptionVerifier.fixture.ts | 10 + .../test/fixtures/MockE3Program.fixture.ts | 11 + .../fixtures/MockExecutionModule.fixture.ts | 11 - .../fixtures/MockOutputVerifier.fixture.ts | 10 - packages/evm/yarn.lock | 246 ++- 47 files changed, 4028 insertions(+), 773 deletions(-) create mode 100644 packages/evm/.env.example create mode 100644 packages/evm/README.md rename packages/evm/contracts/interfaces/{ICyphernodeRegistry.sol => ICiphernodeRegistry.sol} (73%) create mode 100644 packages/evm/contracts/interfaces/IComputeProvider.sol rename packages/evm/contracts/interfaces/{IOutputVerifier.sol => IDecryptionVerifier.sol} (63%) rename packages/evm/contracts/interfaces/{IComputationModule.sol => IE3Program.sol} (84%) delete mode 100644 packages/evm/contracts/interfaces/IExecutionModule.sol rename packages/evm/contracts/registry/{CyphernodeRegistryOwnable.sol => CiphernodeRegistryOwnable.sol} (70%) rename packages/evm/contracts/test/{MockCyphernodeRegistry.sol => MockCiphernodeRegistry.sol} (76%) create mode 100644 packages/evm/contracts/test/MockComputeProvider.sol rename packages/evm/contracts/test/{MockOutputVerifier.sol => MockDecryptionVerifier.sol} (61%) rename packages/evm/contracts/test/{MockComputationModule.sol => MockE3Program.sol} (76%) delete mode 100644 packages/evm/contracts/test/MockExecutionModule.sol create mode 100644 packages/evm/deployments/sepolia/.chainId create mode 100644 packages/evm/deployments/sepolia/CyphernodeRegistryOwnable.json create mode 100644 packages/evm/deployments/sepolia/Enclave.json create mode 100644 packages/evm/deployments/sepolia/NaiveRegistryFilter.json create mode 100644 packages/evm/deployments/sepolia/solcInputs/d0e6e4f19028714f394c36db62dff2be.json delete mode 100644 packages/evm/tasks/enclave.ts create mode 100644 packages/evm/test/fixtures/MockCiphernodeRegistry.fixture.ts delete mode 100644 packages/evm/test/fixtures/MockComputationModule.fixture.ts create mode 100644 packages/evm/test/fixtures/MockComputeProvider.fixture.ts delete mode 100644 packages/evm/test/fixtures/MockCyphernodeRegistry.fixture.ts create mode 100644 packages/evm/test/fixtures/MockDecryptionVerifier.fixture.ts create mode 100644 packages/evm/test/fixtures/MockE3Program.fixture.ts delete mode 100644 packages/evm/test/fixtures/MockExecutionModule.fixture.ts delete mode 100644 packages/evm/test/fixtures/MockOutputVerifier.fixture.ts diff --git a/.gitignore b/.gitignore index 150e1e47..91fcc861 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,6 @@ node_modules # ciphernode -target \ No newline at end of file +target + +*.DS_Store \ No newline at end of file diff --git a/README.md b/README.md index f5c23b79..79f4da0d 100644 --- a/README.md +++ b/README.md @@ -17,49 +17,46 @@ Enclave employs a modular architecture involving numerous actors and participant ```mermaid sequenceDiagram - actor Requester - actor Data Providers + participant Users participant Enclave - participant Ciphernode Registry - participant Ciphernodes - participant Computation Module - participant Execution Module - - loop Each computation request - Requester ->> Enclave: Request computation - activate Enclave - Enclave ->> Ciphernode Registry: Select Committee - activate Ciphernode Registry - Ciphernode Registry -->> Ciphernodes: Key Setup - activate Ciphernodes - Ciphernodes -->> Ciphernode Registry: Publish shared keys - deactivate Ciphernodes - Ciphernode Registry -->> Enclave: Publish Committee - deactivate Ciphernode Registry - - loop Each input - Data Providers ->> Enclave: Publish inputs - Enclave ->> Computation Module: Validate inputs - activate Computation Module - Computation Module -->> Enclave: 👌 - deactivate Computation Module - end - - Enclave ->> Execution Module: Request execution - activate Execution Module - Execution Module -->> Enclave: Publish ciphertext output - deactivate Execution Module - - Enclave -->> Ciphernodes: Request plaintext output - activate Ciphernodes - Ciphernodes ->> Enclave: Publish plaintext output - deactivate Ciphernodes - - Requester -->> Enclave: Get plaintext - Enclave -->> Requester: Returns plaintext - deactivate Enclave - end - + participant CiphernodeRegistry + participant E3Program + participant ComputeProvider + participant InputValidator + participant DecryptionVerifier + + Users->>Enclave: request(parameters) + Enclave->>E3Program: validate(e3ProgramParams) + E3Program-->>Enclave: inputValidator + Enclave->>ComputeProvider: validate(computeProviderParams) + ComputeProvider-->>Enclave: decryptionVerifier + Enclave->>CiphernodeRegistry: requestCommittee(e3Id, filter, threshold) + CiphernodeRegistry-->>Enclave: success + Enclave-->>Users: e3Id, E3 struct + + Users->>Enclave: activate(e3Id) + Enclave->>CiphernodeRegistry: committeePublicKey(e3Id) + CiphernodeRegistry-->>Enclave: publicKey + Enclave->>Enclave: Set expiration and committeePublicKey + Enclave-->>Users: success + + Users->>Enclave: publishInput(e3Id, data) + Enclave->>InputValidator: validate(msg.sender, data) + InputValidator-->>Enclave: input, success + Enclave->>Enclave: Store input + Enclave-->>Users: success + + Users->>Enclave: publishCiphertextOutput(e3Id, data) + Enclave->>DecryptionVerifier: verify(e3Id, data) + DecryptionVerifier-->>Enclave: output, success + Enclave->>Enclave: Store ciphertextOutput + Enclave-->>Users: success + + Users->>Enclave: publishPlaintextOutput(e3Id, data) + Enclave->>E3Program: verify(e3Id, data) + E3Program-->>Enclave: output, success + Enclave->>Enclave: Store plaintextOutput + Enclave-->>Users: success ``` ## Security and Liability diff --git a/package.json b/package.json index c4257e37..a37d2efb 100644 --- a/package.json +++ b/package.json @@ -9,11 +9,13 @@ }, "scripts": { "clean": "cd packages/evm && yarn clean", - "compile": "yarn evm:compile", + "compile": "yarn evm:compile && yarn ciphernode:build", "lint": "yarn evm:lint", "typechain": "yarn evm:typechain", - "test": "yarn evm:test", + "test": "yarn evm:test && yarn ciphernode:test", "coverage": "yarn evm:coverage", + "ciphernode:test": "cd packages/ciphernode && cargo test", + "ciphernode:build": "cd packages/ciphernode && cargo build --release", "evm:install": "cd packages/evm && yarn install", "evm:compile": "cd packages/evm && yarn compile", "evm:lint": "cd packages/evm && yarn lint", diff --git a/packages/evm/.env.example b/packages/evm/.env.example new file mode 100644 index 00000000..1009952f --- /dev/null +++ b/packages/evm/.env.example @@ -0,0 +1,4 @@ +MNEMONIC= +INFURA_KEY= + +ETHERSCAN_API_KEY= \ No newline at end of file diff --git a/packages/evm/.gitignore b/packages/evm/.gitignore index ec7522bb..e812c153 100644 --- a/packages/evm/.gitignore +++ b/packages/evm/.gitignore @@ -9,7 +9,6 @@ coverage dist node_modules types -deployments # files *.env diff --git a/packages/evm/.prettierrc.yml b/packages/evm/.prettierrc.yml index 17aefc74..b5da85f6 100644 --- a/packages/evm/.prettierrc.yml +++ b/packages/evm/.prettierrc.yml @@ -10,7 +10,7 @@ trailingComma: "all" overrides: - files: "*.sol" options: - compiler: "0.8.26" + compiler: "0.8.27" parser: "solidity-parse" tabWidth: 4 - files: "*.ts" diff --git a/packages/evm/.solhint.json b/packages/evm/.solhint.json index 78d8b176..876663a7 100644 --- a/packages/evm/.solhint.json +++ b/packages/evm/.solhint.json @@ -3,7 +3,7 @@ "plugins": ["prettier"], "rules": { "code-complexity": ["error", 8], - "compiler-version": ["error", ">=0.8.26"], + "compiler-version": ["error", ">=0.8.27"], "func-visibility": ["error", { "ignoreConstructors": true }], "max-line-length": ["error", 120], "named-parameters-mapping": "warn", diff --git a/packages/evm/README.md b/packages/evm/README.md new file mode 100644 index 00000000..86dbc875 --- /dev/null +++ b/packages/evm/README.md @@ -0,0 +1,12 @@ +# Enclave EVM + +## To deploy + +``` +yarn deploy --network [network] +``` + +This will add the deployment information to the `./deployments` directory. + +Be sure to configure your desired network in `hardhat.config.ts` before +deploying. diff --git a/packages/evm/contracts/Enclave.sol b/packages/evm/contracts/Enclave.sol index fe1e810b..609825a6 100644 --- a/packages/evm/contracts/Enclave.sol +++ b/packages/evm/contracts/Enclave.sol @@ -1,47 +1,59 @@ // SPDX-License-Identifier: LGPL-3.0-only -pragma solidity >=0.8.26; +pragma solidity >=0.8.27; import { IEnclave, E3, - IComputationModule, - IExecutionModule + IE3Program, + IComputeProvider } from "./interfaces/IEnclave.sol"; -import { ICyphernodeRegistry } from "./interfaces/ICyphernodeRegistry.sol"; +import { ICiphernodeRegistry } from "./interfaces/ICiphernodeRegistry.sol"; import { IInputValidator } from "./interfaces/IInputValidator.sol"; -import { IOutputVerifier } from "./interfaces/IOutputVerifier.sol"; +import { IDecryptionVerifier } from "./interfaces/IDecryptionVerifier.sol"; import { OwnableUpgradeable } from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; +import { + InternalLeanIMT, + LeanIMTData, + PoseidonT3 +} from "@zk-kit/lean-imt.sol/InternalLeanIMT.sol"; contract Enclave is IEnclave, OwnableUpgradeable { + using InternalLeanIMT for LeanIMTData; + //////////////////////////////////////////////////////////// // // // Storage Variables // // // //////////////////////////////////////////////////////////// - ICyphernodeRegistry public cyphernodeRegistry; // address of the Cyphernode registry. + ICiphernodeRegistry public ciphernodeRegistry; // address of the Ciphernode registry. uint256 public maxDuration; // maximum duration of a computation in seconds. uint256 public nexte3Id; // ID of the next E3. uint256 public requests; // total number of requests made to Enclave. - // TODO: should computation and execution modules be explicitly allowed? + // TODO: should computation and compute providers be explicitly allowed? // My intuition is that an allowlist is required since they impose slashing conditions. // But perhaps this is one place where node pools might be utilized, allowing nodes to // opt in to being selected for specific computations, along with the corresponding slashing conditions. // This would reduce the governance overhead for Enclave. - // Mapping of allowed computation modules. - mapping(IComputationModule computationModule => bool allowed) - public computationModules; + // Mapping of allowed E3 Programs. + mapping(IE3Program e3Program => bool allowed) public e3Programs; - // Mapping of allowed execution modules. - mapping(IExecutionModule executionModule => bool allowed) - public executionModules; + // Mapping of allowed compute providers. + mapping(IComputeProvider computeProvider => bool allowed) + public computeProviders; // Mapping of E3s. - mapping(uint256 id => E3 e3) public e3s; + mapping(uint256 e3Id => E3 e3) public e3s; + + // Mapping of input merkle trees + mapping(uint256 e3Id => LeanIMTData imt) public inputs; + + // Mapping counting the number of inputs for each E3. + mapping(uint256 e3Id => uint256 inputCount) public inputCounts; //////////////////////////////////////////////////////////// // // @@ -50,7 +62,7 @@ contract Enclave is IEnclave, OwnableUpgradeable { //////////////////////////////////////////////////////////// error CommitteeSelectionFailed(); - error ComputationModuleNotAllowed(IComputationModule computationModule); + error E3ProgramNotAllowed(IE3Program e3Program); error E3AlreadyActivated(uint256 e3Id); error E3Expired(); error E3NotActivated(uint256 e3Id); @@ -61,8 +73,8 @@ contract Enclave is IEnclave, OwnableUpgradeable { error InputDeadlinePassed(uint256 e3Id, uint256 expiration); error InputDeadlineNotPassed(uint256 e3Id, uint256 expiration); error InvalidComputation(); - error InvalidExecutionModuleSetup(); - error InvalidCyphernodeRegistry(ICyphernodeRegistry cyphernodeRegistry); + error InvalidComputeProviderSetup(); + error InvalidCiphernodeRegistry(ICiphernodeRegistry ciphernodeRegistry); error InvalidInput(); error InvalidDuration(uint256 duration); error InvalidOutput(bytes output); @@ -83,22 +95,22 @@ contract Enclave is IEnclave, OwnableUpgradeable { /// @param _maxDuration The maximum duration of a computation in seconds constructor( address _owner, - ICyphernodeRegistry _cyphernodeRegistry, + ICiphernodeRegistry _ciphernodeRegistry, uint256 _maxDuration ) { - initialize(_owner, _cyphernodeRegistry, _maxDuration); + initialize(_owner, _ciphernodeRegistry, _maxDuration); } /// @param _owner The owner of this contract /// @param _maxDuration The maximum duration of a computation in seconds function initialize( address _owner, - ICyphernodeRegistry _cyphernodeRegistry, + ICiphernodeRegistry _ciphernodeRegistry, uint256 _maxDuration ) public initializer { __Ownable_init(msg.sender); setMaxDuration(_maxDuration); - setCyphernodeRegistry(_cyphernodeRegistry); + setCiphernodeRegistry(_ciphernodeRegistry); if (_owner != owner()) transferOwnership(_owner); } @@ -113,13 +125,13 @@ contract Enclave is IEnclave, OwnableUpgradeable { uint32[2] calldata threshold, uint256[2] calldata startWindow, uint256 duration, - IComputationModule computationModule, - bytes memory computationParams, - IExecutionModule executionModule, - bytes memory emParams + IE3Program e3Program, + bytes memory e3ProgramParams, + IComputeProvider computeProvider, + bytes memory computeProviderParams ) external payable returns (uint256 e3Id, E3 memory e3) { // TODO: allow for other payment methods or only native tokens? - // TODO: should payment checks be somewhere else? Perhaps in the computation module or cyphernode registry? + // TODO: should payment checks be somewhere else? Perhaps in the E3 Program or ciphernode registry? require(msg.value > 0, PaymentRequired(msg.value)); require( threshold[1] >= threshold[0] && threshold[0] > 0, @@ -135,59 +147,59 @@ contract Enclave is IEnclave, OwnableUpgradeable { duration > 0 && duration <= maxDuration, InvalidDuration(duration) ); + require(e3Programs[e3Program], E3ProgramNotAllowed(e3Program)); require( - computationModules[computationModule], - ComputationModuleNotAllowed(computationModule) - ); - require( - executionModules[executionModule], - ModuleNotEnabled(address(executionModule)) + computeProviders[computeProvider], + ModuleNotEnabled(address(computeProvider)) ); // TODO: should IDs be incremental or produced deterministically? e3Id = nexte3Id; nexte3Id++; + uint256 seed = uint256(keccak256(abi.encode(block.prevrandao, e3Id))); - IInputValidator inputValidator = computationModule.validate( - computationParams + IInputValidator inputValidator = e3Program.validate( + e3Id, + seed, + e3ProgramParams ); require(address(inputValidator) != address(0), InvalidComputation()); - // TODO: validate that the requested computation can be performed by the given execution module. - IOutputVerifier outputVerifier = executionModule.validate(emParams); + // TODO: validate that the requested computation can be performed by the given compute provider. + // Perhaps the compute provider should be returned by the E3 Program? + IDecryptionVerifier decryptionVerifier = computeProvider.validate( + e3Id, + seed, + computeProviderParams + ); require( - address(outputVerifier) != address(0), - InvalidExecutionModuleSetup() + address(decryptionVerifier) != address(0), + InvalidComputeProviderSetup() ); e3 = E3({ + seed: seed, threshold: threshold, startWindow: startWindow, duration: duration, expiration: 0, - computationModule: computationModule, - executionModule: executionModule, + e3Program: e3Program, + e3ProgramParams: e3ProgramParams, inputValidator: inputValidator, - outputVerifier: outputVerifier, + computeProvider: computeProvider, + decryptionVerifier: decryptionVerifier, committeePublicKey: hex"", - inputs: new bytes[](0), ciphertextOutput: hex"", plaintextOutput: hex"" }); e3s[e3Id] = e3; require( - cyphernodeRegistry.requestCommittee(e3Id, filter, threshold), + ciphernodeRegistry.requestCommittee(e3Id, filter, threshold), CommitteeSelectionFailed() ); - emit E3Requested( - e3Id, - e3s[e3Id], - filter, - computationModule, - executionModule - ); + emit E3Requested(e3Id, e3s[e3Id], filter, e3Program, computeProvider); } function activate(uint256 e3Id) external returns (bool success) { @@ -199,7 +211,7 @@ contract Enclave is IEnclave, OwnableUpgradeable { // TODO: handle what happens to the payment if the start window has passed. require(e3.startWindow[1] >= block.timestamp, E3Expired()); - bytes memory publicKey = cyphernodeRegistry.committeePublicKey(e3Id); + bytes memory publicKey = ciphernodeRegistry.committeePublicKey(e3Id); // Note: This check feels weird require(publicKey.length > 0, CommitteeSelectionFailed()); @@ -227,9 +239,14 @@ contract Enclave is IEnclave, OwnableUpgradeable { bytes memory input; (input, success) = e3.inputValidator.validate(msg.sender, data); require(success, InvalidInput()); - // TODO: probably better to accumulate inputs, rather than just dumping them in storage. - e3s[e3Id].inputs.push(input); - emit InputPublished(e3Id, input); + uint256 inputHash = PoseidonT3.hash( + [uint256(keccak256(input)), inputCounts[e3Id]] + ); + + inputCounts[e3Id]++; + inputs[e3Id]._insert(inputHash); + + emit InputPublished(e3Id, input, inputHash, inputCounts[e3Id] - 1); } function publishCiphertextOutput( @@ -250,7 +267,7 @@ contract Enclave is IEnclave, OwnableUpgradeable { CiphertextOutputAlreadyPublished(e3Id) ); bytes memory output; - (output, success) = e3.outputVerifier.verify(e3Id, data); + (output, success) = e3.e3Program.verify(e3Id, data); require(success, InvalidOutput(output)); e3s[e3Id].ciphertextOutput = output; @@ -273,7 +290,7 @@ contract Enclave is IEnclave, OwnableUpgradeable { PlaintextOutputAlreadyPublished(e3Id) ); bytes memory output; - (output, success) = e3.computationModule.verify(e3Id, data); + (output, success) = e3.decryptionVerifier.verify(e3Id, data); require(success, InvalidOutput(output)); e3s[e3Id].plaintextOutput = output; @@ -294,65 +311,62 @@ contract Enclave is IEnclave, OwnableUpgradeable { emit MaxDurationSet(_maxDuration); } - function setCyphernodeRegistry( - ICyphernodeRegistry _cyphernodeRegistry + function setCiphernodeRegistry( + ICiphernodeRegistry _ciphernodeRegistry ) public onlyOwner returns (bool success) { require( - address(_cyphernodeRegistry) != address(0) && - _cyphernodeRegistry != cyphernodeRegistry, - InvalidCyphernodeRegistry(_cyphernodeRegistry) + address(_ciphernodeRegistry) != address(0) && + _ciphernodeRegistry != ciphernodeRegistry, + InvalidCiphernodeRegistry(_ciphernodeRegistry) ); - cyphernodeRegistry = _cyphernodeRegistry; + ciphernodeRegistry = _ciphernodeRegistry; success = true; - emit CyphernodeRegistrySet(address(_cyphernodeRegistry)); + emit CiphernodeRegistrySet(address(_ciphernodeRegistry)); } - function enableComputationModule( - IComputationModule computationModule + function enableE3Program( + IE3Program e3Program ) public onlyOwner returns (bool success) { require( - !computationModules[computationModule], - ModuleAlreadyEnabled(address(computationModule)) + !e3Programs[e3Program], + ModuleAlreadyEnabled(address(e3Program)) ); - computationModules[computationModule] = true; + e3Programs[e3Program] = true; success = true; - emit ComputationModuleEnabled(computationModule); + emit E3ProgramEnabled(e3Program); } - function enableExecutionModule( - IExecutionModule executionModule + function enableComputeProvider( + IComputeProvider computeProvider ) public onlyOwner returns (bool success) { require( - !executionModules[executionModule], - ModuleAlreadyEnabled(address(executionModule)) + !computeProviders[computeProvider], + ModuleAlreadyEnabled(address(computeProvider)) ); - executionModules[executionModule] = true; + computeProviders[computeProvider] = true; success = true; - emit ExecutionModuleEnabled(executionModule); + emit ComputeProviderEnabled(computeProvider); } - function disableComputationModule( - IComputationModule computationModule + function disableE3Program( + IE3Program e3Program ) public onlyOwner returns (bool success) { - require( - computationModules[computationModule], - ModuleNotEnabled(address(computationModule)) - ); - delete computationModules[computationModule]; + require(e3Programs[e3Program], ModuleNotEnabled(address(e3Program))); + delete e3Programs[e3Program]; success = true; - emit ComputationModuleDisabled(computationModule); + emit E3ProgramDisabled(e3Program); } - function disableExecutionModule( - IExecutionModule executionModule + function disableComputeProvider( + IComputeProvider computeProvider ) public onlyOwner returns (bool success) { require( - executionModules[executionModule], - ModuleNotEnabled(address(executionModule)) + computeProviders[computeProvider], + ModuleNotEnabled(address(computeProvider)) ); - delete executionModules[executionModule]; + delete computeProviders[computeProvider]; success = true; - emit ExecutionModuleDisabled(executionModule); + emit ComputeProviderDisabled(computeProvider); } //////////////////////////////////////////////////////////// @@ -363,9 +377,14 @@ contract Enclave is IEnclave, OwnableUpgradeable { function getE3(uint256 e3Id) public view returns (E3 memory e3) { e3 = e3s[e3Id]; + require(e3.e3Program != IE3Program(address(0)), E3DoesNotExist(e3Id)); + } + + function getInputRoot(uint256 e3Id) public view returns (uint256) { require( - e3.computationModule != IComputationModule(address(0)), + e3s[e3Id].e3Program != IE3Program(address(0)), E3DoesNotExist(e3Id) ); + return InternalLeanIMT._root(inputs[e3Id]); } } diff --git a/packages/evm/contracts/interfaces/ICyphernodeRegistry.sol b/packages/evm/contracts/interfaces/ICiphernodeRegistry.sol similarity index 73% rename from packages/evm/contracts/interfaces/ICyphernodeRegistry.sol rename to packages/evm/contracts/interfaces/ICiphernodeRegistry.sol index 444fff7c..6a48f70a 100644 --- a/packages/evm/contracts/interfaces/ICyphernodeRegistry.sol +++ b/packages/evm/contracts/interfaces/ICiphernodeRegistry.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: LGPL-3.0-only -pragma solidity >=0.8.26; +pragma solidity >=0.8.27; -interface ICyphernodeRegistry { +interface ICiphernodeRegistry { /// @notice This event MUST be emitted when a committee is selected for an E3. /// @param e3Id ID of the E3 for which the committee was selected. /// @param filter Address of the contract that will coordinate committee selection. @@ -21,13 +21,31 @@ interface ICyphernodeRegistry { /// @param enclave Address of the enclave contract. event EnclaveSet(address indexed enclave); - /// @notice This event MUST be emitted when a cyphernode is added to the registry. - event CyphernodeAdded(address indexed node); + /// @notice This event MUST be emitted when a ciphernode is added to the registry. + /// @param node Address of the ciphernode. + /// @param index Index of the ciphernode in the registry. + /// @param numNodes Number of ciphernodes in the registry. + /// @param size Size of the registry. + event CiphernodeAdded( + address indexed node, + uint256 index, + uint256 numNodes, + uint256 size + ); - /// @notice This event MUST be emitted when a cyphernode is removed from the registry. - event CyphernodeRemoved(address indexed node); + /// @notice This event MUST be emitted when a ciphernode is removed from the registry. + /// @param node Address of the ciphernode. + /// @param index Index of the ciphernode in the registry. + /// @param numNodes Number of ciphernodes in the registry. + /// @param size Size of the registry. + event CiphernodeRemoved( + address indexed node, + uint256 index, + uint256 numNodes, + uint256 size + ); - function isCyphernodeEligible(address cyphernode) external returns (bool); + function isCiphernodeEligible(address ciphernode) external returns (bool); /// @notice Initiates the committee selection process for a specified E3. /// @dev This function MUST revert when not called by the Enclave contract. diff --git a/packages/evm/contracts/interfaces/IComputeProvider.sol b/packages/evm/contracts/interfaces/IComputeProvider.sol new file mode 100644 index 00000000..e997b180 --- /dev/null +++ b/packages/evm/contracts/interfaces/IComputeProvider.sol @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: LGPL-3.0-only +pragma solidity >=0.8.27; + +import { IDecryptionVerifier } from "./IDecryptionVerifier.sol"; + +interface IComputeProvider { + /// @notice This function should be called by the Enclave contract to validate the compute provider parameters. + /// @param params ABI encoded compute provider parameters. + function validate( + uint256 e3Id, + uint256 seed, + bytes calldata params + ) external returns (IDecryptionVerifier decryptionVerifier); +} diff --git a/packages/evm/contracts/interfaces/IOutputVerifier.sol b/packages/evm/contracts/interfaces/IDecryptionVerifier.sol similarity index 63% rename from packages/evm/contracts/interfaces/IOutputVerifier.sol rename to packages/evm/contracts/interfaces/IDecryptionVerifier.sol index 53203715..9c71e9df 100644 --- a/packages/evm/contracts/interfaces/IOutputVerifier.sol +++ b/packages/evm/contracts/interfaces/IDecryptionVerifier.sol @@ -1,11 +1,12 @@ // SPDX-License-Identifier: LGPL-3.0-only -pragma solidity >=0.8.26; +pragma solidity >=0.8.27; -interface IOutputVerifier { - /// @notice This function should be called by the Enclave contract to verify the output of a computation. +interface IDecryptionVerifier { + /// @notice This function should be called by the Enclave contract to verify the + /// decryption of output of a computation. /// @param e3Id ID of the E3. /// @param data ABI encoded output data to be verified. - /// @return output Ciphertext output of the given computation. + /// @return output Plaintext output of the given computation. function verify( uint256 e3Id, bytes memory data diff --git a/packages/evm/contracts/interfaces/IE3.sol b/packages/evm/contracts/interfaces/IE3.sol index faa2cace..66a78385 100644 --- a/packages/evm/contracts/interfaces/IE3.sol +++ b/packages/evm/contracts/interfaces/IE3.sol @@ -1,10 +1,10 @@ // SPDX-License-Identifier: LGPL-3.0-only -pragma solidity >=0.8.26; +pragma solidity >=0.8.27; import { IInputValidator } from "./IInputValidator.sol"; -import { IExecutionModule } from "./IExecutionModule.sol"; -import { IComputationModule } from "./IComputationModule.sol"; -import { IOutputVerifier } from "./IOutputVerifier.sol"; +import { IComputeProvider } from "./IComputeProvider.sol"; +import { IE3Program } from "./IE3Program.sol"; +import { IDecryptionVerifier } from "./IDecryptionVerifier.sol"; /// @title E3 struct /// @notice This struct represents an E3 computation. @@ -12,24 +12,25 @@ import { IOutputVerifier } from "./IOutputVerifier.sol"; /// @param startWindow Start window for the computation: index zero is minimum, index 1 is the maxium. /// @param duration Duration of the E3. /// @param expiration Timestamp when committee duties expire. -/// @param computationModule Address of the computation module contract. -/// @param executionModule Address of the execution module contract. +/// @param e3Program Address of the E3 Program contract. +/// @param computeProvider Address of the compute provider contract. /// @param inputValidator Address of the input validator contract. -/// @param outputVerifier Address of the output verifier contract. +/// @param decryptionVerifier Address of the output verifier contract. /// @param committeeId ID of the selected committee. /// @param ciphertextOutput Encrypted output data. /// @param plaintextOutput Decrypted output data. struct E3 { + uint256 seed; uint32[2] threshold; uint256[2] startWindow; uint256 duration; uint256 expiration; - IComputationModule computationModule; - IExecutionModule executionModule; + IE3Program e3Program; + bytes e3ProgramParams; IInputValidator inputValidator; - IOutputVerifier outputVerifier; + IComputeProvider computeProvider; + IDecryptionVerifier decryptionVerifier; bytes committeePublicKey; - bytes[] inputs; bytes ciphertextOutput; bytes plaintextOutput; } diff --git a/packages/evm/contracts/interfaces/IComputationModule.sol b/packages/evm/contracts/interfaces/IE3Program.sol similarity index 84% rename from packages/evm/contracts/interfaces/IComputationModule.sol rename to packages/evm/contracts/interfaces/IE3Program.sol index 3a48423a..506e1e94 100644 --- a/packages/evm/contracts/interfaces/IComputationModule.sol +++ b/packages/evm/contracts/interfaces/IE3Program.sol @@ -1,13 +1,17 @@ // SPDX-License-Identifier: LGPL-3.0-only -pragma solidity >=0.8.26; +pragma solidity >=0.8.27; import { IInputValidator } from "./IInputValidator.sol"; -interface IComputationModule { +interface IE3Program { /// @notice This function should be called by the Enclave contract to validate the computation parameters. + /// @param e3Id ID of the E3. + /// @param seed Seed for the computation. /// @param params ABI encoded computation parameters. /// @return inputValidator The input validator to be used for the computation. function validate( + uint256 e3Id, + uint256 seed, bytes calldata params ) external returns (IInputValidator inputValidator); diff --git a/packages/evm/contracts/interfaces/IEnclave.sol b/packages/evm/contracts/interfaces/IEnclave.sol index fb2ec6f8..b22f03ed 100644 --- a/packages/evm/contracts/interfaces/IEnclave.sol +++ b/packages/evm/contracts/interfaces/IEnclave.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: LGPL-3.0-only -pragma solidity >=0.8.26; +pragma solidity >=0.8.27; -import { E3, IComputationModule, IExecutionModule } from "./IE3.sol"; +import { E3, IE3Program, IComputeProvider } from "./IE3.sol"; interface IEnclave { //////////////////////////////////////////////////////////// @@ -13,15 +13,15 @@ interface IEnclave { /// @notice This event MUST be emitted when an Encrypted Execution Environment (E3) is successfully requested. /// @param e3Id ID of the E3. /// @param e3 Details of the E3. - /// @param filter Address of the pool of nodes from which the Cypher Node committee was selected. - /// @param computationModule Address of the Computation module selected. - /// @param executionModule Address of the execution module selected. + /// @param filter Address of the pool of nodes from which the Cipher Node committee was selected. + /// @param e3Program Address of the Computation module selected. + /// @param computeProvider Address of the compute provider selected. event E3Requested( uint256 e3Id, E3 e3, address filter, - IComputationModule indexed computationModule, - IExecutionModule indexed executionModule + IE3Program indexed e3Program, + IComputeProvider indexed computeProvider ); /// @notice This event MUST be emitted when an Encrypted Execution Environment (E3) is successfully activated. @@ -38,7 +38,12 @@ interface IEnclave { /// successfully published. /// @param e3Id ID of the E3. /// @param data ABI encoded input data. - event InputPublished(uint256 indexed e3Id, bytes data); + event InputPublished( + uint256 indexed e3Id, + bytes data, + uint256 inputHash, + uint256 index + ); /// @notice This event MUST be emitted when the plaintext output of an Encrypted Execution Environment (E3) /// is successfully published. @@ -59,25 +64,25 @@ interface IEnclave { /// @param maxDuration The maximum duration of a computation in seconds. event MaxDurationSet(uint256 maxDuration); - /// @notice This event MUST be emitted any time the CyphernodeRegistry is set. - /// @param cyphernodeRegistry The address of the CyphernodeRegistry contract. - event CyphernodeRegistrySet(address cyphernodeRegistry); + /// @notice This event MUST be emitted any time the CiphernodeRegistry is set. + /// @param ciphernodeRegistry The address of the CiphernodeRegistry contract. + event CiphernodeRegistrySet(address ciphernodeRegistry); - /// @notice This event MUST be emitted any time a computation module is enabled. - /// @param computationModule The address of the computation module. - event ComputationModuleEnabled(IComputationModule computationModule); + /// @notice This event MUST be emitted any time a E3 Program is enabled. + /// @param e3Program The address of the E3 Program. + event E3ProgramEnabled(IE3Program e3Program); - /// @notice This event MUST be emitted any time a computation module is disabled. - /// @param computationModule The address of the computation module. - event ComputationModuleDisabled(IComputationModule computationModule); + /// @notice This event MUST be emitted any time a E3 Program is disabled. + /// @param e3Program The address of the E3 Program. + event E3ProgramDisabled(IE3Program e3Program); - /// @notice This event MUST be emitted any time an execution module is enabled. - /// @param executionModule The address of the execution module. - event ExecutionModuleEnabled(IExecutionModule executionModule); + /// @notice This event MUST be emitted any time an compute provider is enabled. + /// @param computeProvider The address of the compute provider. + event ComputeProviderEnabled(IComputeProvider computeProvider); - /// @notice This event MUST be emitted any time an execution module is disabled. - /// @param executionModule The address of the execution module. - event ExecutionModuleDisabled(IExecutionModule executionModule); + /// @notice This event MUST be emitted any time an compute provider is disabled. + /// @param computeProvider The address of the compute provider. + event ComputeProviderDisabled(IComputeProvider computeProvider); //////////////////////////////////////////////////////////// // // @@ -90,10 +95,10 @@ interface IEnclave { /// @param filter IDs of the pool of nodes from which to select the committee. /// @param threshold The M/N threshold for the committee. /// @param duration The duration of the computation in seconds. - /// @param computationModule Address of the computation module. - /// @param computationParams ABI encoded computation parameters. - /// @param executionModule Address of the execution module. - /// @param emParams ABI encoded execution module parameters. + /// @param e3Program Address of the E3 Program. + /// @param e3ProgramParams ABI encoded computation parameters. + /// @param computeProvider Address of the compute provider. + /// @param computeProviderParams ABI encoded compute provider parameters. /// @return e3Id ID of the E3. /// @return e3 The E3 struct. function request( @@ -101,10 +106,10 @@ interface IEnclave { uint32[2] calldata threshold, uint256[2] calldata startWindow, uint256 duration, - IComputationModule computationModule, - bytes memory computationParams, - IExecutionModule executionModule, - bytes memory emParams + IE3Program e3Program, + bytes memory e3ProgramParams, + IComputeProvider computeProvider, + bytes memory computeProviderParams ) external payable returns (uint256 e3Id, E3 memory e3); /// @notice This function should be called to activate an Encrypted Execution Environment (E3) once it has been @@ -171,4 +176,10 @@ interface IEnclave { /// @param e3Id ID of the E3. /// @return e3 The struct representing the requested E3. function getE3(uint256 e3Id) external view returns (E3 memory e3); + + /// @notice This function returns root of the input merkle tree for a given E3. + /// @dev This function MUST revert if the E3 does not exist. + /// @param e3Id ID of the E3. + /// @return root The root of the input merkle tree. + function getInputRoot(uint256 e3Id) external view returns (uint256 root); } diff --git a/packages/evm/contracts/interfaces/IExecutionModule.sol b/packages/evm/contracts/interfaces/IExecutionModule.sol deleted file mode 100644 index e6d6e9cf..00000000 --- a/packages/evm/contracts/interfaces/IExecutionModule.sol +++ /dev/null @@ -1,12 +0,0 @@ -// SPDX-License-Identifier: LGPL-3.0-only -pragma solidity >=0.8.26; - -import { IOutputVerifier } from "./IOutputVerifier.sol"; - -interface IExecutionModule { - /// @notice This function should be called by the Enclave contract to validate the execution module parameters. - /// @param params ABI encoded execution module parameters. - function validate( - bytes calldata params - ) external returns (IOutputVerifier outputVerifier); -} diff --git a/packages/evm/contracts/interfaces/IInputValidator.sol b/packages/evm/contracts/interfaces/IInputValidator.sol index 257af4da..1419472e 100644 --- a/packages/evm/contracts/interfaces/IInputValidator.sol +++ b/packages/evm/contracts/interfaces/IInputValidator.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: LGPL-3.0-only -pragma solidity >=0.8.26; +pragma solidity >=0.8.27; interface IInputValidator { /// @notice This function should be called by the Enclave contract to validate the input parameters. diff --git a/packages/evm/contracts/interfaces/IRegistryFilter.sol b/packages/evm/contracts/interfaces/IRegistryFilter.sol index c861d734..dbac5bf5 100644 --- a/packages/evm/contracts/interfaces/IRegistryFilter.sol +++ b/packages/evm/contracts/interfaces/IRegistryFilter.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: LGPL-3.0-only -pragma solidity >=0.8.26; +pragma solidity >=0.8.27; interface IRegistryFilter { function requestCommittee( diff --git a/packages/evm/contracts/registry/CyphernodeRegistryOwnable.sol b/packages/evm/contracts/registry/CiphernodeRegistryOwnable.sol similarity index 70% rename from packages/evm/contracts/registry/CyphernodeRegistryOwnable.sol rename to packages/evm/contracts/registry/CiphernodeRegistryOwnable.sol index c9c17ca5..e62682d7 100644 --- a/packages/evm/contracts/registry/CyphernodeRegistryOwnable.sol +++ b/packages/evm/contracts/registry/CiphernodeRegistryOwnable.sol @@ -1,13 +1,19 @@ // SPDX-License-Identifier: LGPL-3.0-only -pragma solidity >=0.8.26; +pragma solidity >=0.8.27; -import { ICyphernodeRegistry } from "../interfaces/ICyphernodeRegistry.sol"; +import { ICiphernodeRegistry } from "../interfaces/ICiphernodeRegistry.sol"; import { IRegistryFilter } from "../interfaces/IRegistryFilter.sol"; import { OwnableUpgradeable } from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; +import { + InternalLeanIMT, + LeanIMTData +} from "@zk-kit/lean-imt.sol/InternalLeanIMT.sol"; + +contract CiphernodeRegistryOwnable is ICiphernodeRegistry, OwnableUpgradeable { + using InternalLeanIMT for LeanIMTData; -contract CyphernodeRegistryOwnable is ICyphernodeRegistry, OwnableUpgradeable { //////////////////////////////////////////////////////////// // // // Storage Variables // @@ -15,10 +21,11 @@ contract CyphernodeRegistryOwnable is ICyphernodeRegistry, OwnableUpgradeable { //////////////////////////////////////////////////////////// address public enclave; - - mapping(address cyphernode => bool isEnabled) public isEnabled; + uint256 public numCiphernodes; + LeanIMTData public ciphernodes; mapping(uint256 e3Id => IRegistryFilter filter) public requests; + mapping(uint256 e3Id => uint256 root) public roots; mapping(uint256 e3Id => bytes publicKey) public publicKeys; //////////////////////////////////////////////////////////// @@ -31,7 +38,7 @@ contract CyphernodeRegistryOwnable is ICyphernodeRegistry, OwnableUpgradeable { error CommitteeAlreadyPublished(); error CommitteeDoesNotExist(); error CommitteeNotPublished(); - error CyphernodeNotEnabled(address node); + error CiphernodeNotEnabled(address node); error OnlyEnclave(); //////////////////////////////////////////////////////////// @@ -77,6 +84,7 @@ contract CyphernodeRegistryOwnable is ICyphernodeRegistry, OwnableUpgradeable { CommitteeAlreadyRequested() ); requests[e3Id] = IRegistryFilter(filter); + roots[e3Id] = root(); IRegistryFilter(filter).requestCommittee(e3Id, threshold); emit CommitteeRequested(e3Id, filter, threshold); @@ -91,13 +99,6 @@ contract CyphernodeRegistryOwnable is ICyphernodeRegistry, OwnableUpgradeable { // only to be published by the filter require(address(requests[e3Id]) == msg.sender, CommitteeDoesNotExist()); - // for (uint256 i = 0; i < cyphernodes.length; i++) { - // require( - // isEnabled[cyphernodes[i]] == true, - // CyphernodeNotEnabled(cyphernodes[i]) - // ); - // } - publicKeys[e3Id] = publicKey; emit CommitteePublished(e3Id, publicKey); } @@ -113,18 +114,37 @@ contract CyphernodeRegistryOwnable is ICyphernodeRegistry, OwnableUpgradeable { emit EnclaveSet(_enclave); } - function addCyphernode(address node) external onlyOwner { - isEnabled[node] = true; - emit CyphernodeAdded(node); + function addCiphernode(address node) external onlyOwner { + uint256 ciphernode = uint256(bytes32(bytes20(node))); + ciphernodes._insert(ciphernode); + numCiphernodes++; + emit CiphernodeAdded( + node, + ciphernodes._indexOf(ciphernode), + numCiphernodes, + ciphernodes.size + ); } - function removeCyphernode(address node) external onlyOwner { - isEnabled[node] = false; - emit CyphernodeRemoved(node); + function removeCiphernode( + address node, + uint256[] calldata siblingNodes + ) external onlyOwner { + uint256 ciphernode = uint256(bytes32(bytes20(node))); + ciphernodes._remove(ciphernode, siblingNodes); + uint256 index = ciphernodes._indexOf(ciphernode); + numCiphernodes--; + emit CiphernodeAdded( + node, + ciphernodes._indexOf(ciphernode), + numCiphernodes, + ciphernodes.size + ); + emit CiphernodeRemoved(node, index, numCiphernodes, ciphernodes.size); } - function isCyphernodeEligible(address node) external view returns (bool) { - return isEnabled[node]; + function isCiphernodeEligible(address node) external view returns (bool) { + return isEnabled(node); } //////////////////////////////////////////////////////////// @@ -139,4 +159,16 @@ contract CyphernodeRegistryOwnable is ICyphernodeRegistry, OwnableUpgradeable { publicKey = publicKeys[e3Id]; require(publicKey.length > 0, CommitteeNotPublished()); } + + function isEnabled(address node) public view returns (bool) { + return ciphernodes._has(uint256(bytes32(bytes20(node)))); + } + + function root() public view returns (uint256) { + return (ciphernodes._root()); + } + + function rootAt(uint256 e3Id) public view returns (uint256) { + return roots[e3Id]; + } } diff --git a/packages/evm/contracts/registry/NaiveRegistryFilter.sol b/packages/evm/contracts/registry/NaiveRegistryFilter.sol index 5966c8ea..7d122e9e 100644 --- a/packages/evm/contracts/registry/NaiveRegistryFilter.sol +++ b/packages/evm/contracts/registry/NaiveRegistryFilter.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: LGPL-3.0-only -pragma solidity >=0.8.26; +pragma solidity >=0.8.27; -import { ICyphernodeRegistry } from "../interfaces/ICyphernodeRegistry.sol"; +import { ICiphernodeRegistry } from "../interfaces/ICiphernodeRegistry.sol"; import { IRegistryFilter } from "../interfaces/IRegistryFilter.sol"; import { OwnableUpgradeable @@ -53,8 +53,8 @@ contract NaiveRegistryFilter is IRegistryFilter, OwnableUpgradeable { // // //////////////////////////////////////////////////////////// - constructor(address _owner, address _enclave) { - initialize(_owner, _enclave); + constructor(address _owner, address _registry) { + initialize(_owner, _registry); } function initialize(address _owner, address _registry) public initializer { @@ -91,7 +91,7 @@ contract NaiveRegistryFilter is IRegistryFilter, OwnableUpgradeable { ); committee.nodes = nodes; committee.publicKey = publicKey; - ICyphernodeRegistry(registry).publishCommittee( + ICiphernodeRegistry(registry).publishCommittee( e3Id, abi.encode(nodes), publicKey diff --git a/packages/evm/contracts/test/MockCyphernodeRegistry.sol b/packages/evm/contracts/test/MockCiphernodeRegistry.sol similarity index 76% rename from packages/evm/contracts/test/MockCyphernodeRegistry.sol rename to packages/evm/contracts/test/MockCiphernodeRegistry.sol index 4f2469c9..29625e39 100644 --- a/packages/evm/contracts/test/MockCyphernodeRegistry.sol +++ b/packages/evm/contracts/test/MockCiphernodeRegistry.sol @@ -1,9 +1,9 @@ // SPDX-License-Identifier: LGPL-3.0-only -pragma solidity >=0.8.26; +pragma solidity >=0.8.27; -import { ICyphernodeRegistry } from "../interfaces/ICyphernodeRegistry.sol"; +import { ICiphernodeRegistry } from "../interfaces/ICiphernodeRegistry.sol"; -contract MockCyphernodeRegistry is ICyphernodeRegistry { +contract MockCiphernodeRegistry is ICiphernodeRegistry { function requestCommittee( uint256, address filter, @@ -16,6 +16,7 @@ contract MockCyphernodeRegistry is ICyphernodeRegistry { } } + // solhint-disable no-empty-blocks function publishCommittee( uint256, bytes calldata, @@ -32,12 +33,12 @@ contract MockCyphernodeRegistry is ICyphernodeRegistry { } } - function isCyphernodeEligible(address) external pure returns (bool) { + function isCiphernodeEligible(address) external pure returns (bool) { return false; } } -contract MockCyphernodeRegistryEmptyKey is ICyphernodeRegistry { +contract MockCiphernodeRegistryEmptyKey is ICiphernodeRegistry { function requestCommittee( uint256, address filter, @@ -50,6 +51,7 @@ contract MockCyphernodeRegistryEmptyKey is ICyphernodeRegistry { } } + // solhint-disable no-empty-blocks function publishCommittee( uint256, bytes calldata, @@ -60,7 +62,7 @@ contract MockCyphernodeRegistryEmptyKey is ICyphernodeRegistry { return hex""; } - function isCyphernodeEligible(address) external pure returns (bool) { + function isCiphernodeEligible(address) external pure returns (bool) { return false; } } diff --git a/packages/evm/contracts/test/MockComputeProvider.sol b/packages/evm/contracts/test/MockComputeProvider.sol new file mode 100644 index 00000000..9ddd2fba --- /dev/null +++ b/packages/evm/contracts/test/MockComputeProvider.sol @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: LGPL-3.0-only +pragma solidity >=0.8.27; + +import { + IComputeProvider, + IDecryptionVerifier +} from "../interfaces/IComputeProvider.sol"; + +contract MockComputeProvider is IComputeProvider { + error invalidParams(); + + function validate( + uint256, + uint256, + bytes memory params + ) external pure returns (IDecryptionVerifier decryptionVerifier) { + require(params.length == 32, invalidParams()); + // solhint-disable no-inline-assembly + assembly { + decryptionVerifier := mload(add(params, 32)) + } + (decryptionVerifier) = abi.decode(params, (IDecryptionVerifier)); + } +} diff --git a/packages/evm/contracts/test/MockOutputVerifier.sol b/packages/evm/contracts/test/MockDecryptionVerifier.sol similarity index 61% rename from packages/evm/contracts/test/MockOutputVerifier.sol rename to packages/evm/contracts/test/MockDecryptionVerifier.sol index 1b5a00fd..d2977901 100644 --- a/packages/evm/contracts/test/MockOutputVerifier.sol +++ b/packages/evm/contracts/test/MockDecryptionVerifier.sol @@ -1,9 +1,9 @@ // SPDX-License-Identifier: LGPL-3.0-only -pragma solidity >=0.8.26; +pragma solidity >=0.8.27; -import { IOutputVerifier } from "../interfaces/IOutputVerifier.sol"; +import { IDecryptionVerifier } from "../interfaces/IDecryptionVerifier.sol"; -contract MockOutputVerifier is IOutputVerifier { +contract MockDecryptionVerifier is IDecryptionVerifier { function verify( uint256, bytes memory data diff --git a/packages/evm/contracts/test/MockComputationModule.sol b/packages/evm/contracts/test/MockE3Program.sol similarity index 76% rename from packages/evm/contracts/test/MockComputationModule.sol rename to packages/evm/contracts/test/MockE3Program.sol index a6492b1f..b92d6a84 100644 --- a/packages/evm/contracts/test/MockComputationModule.sol +++ b/packages/evm/contracts/test/MockE3Program.sol @@ -1,15 +1,14 @@ // SPDX-License-Identifier: LGPL-3.0-only -pragma solidity >=0.8.26; +pragma solidity >=0.8.27; -import { - IComputationModule, - IInputValidator -} from "../interfaces/IComputationModule.sol"; +import { IE3Program, IInputValidator } from "../interfaces/IE3Program.sol"; -contract MockComputationModule is IComputationModule { +contract MockE3Program is IE3Program { error invalidParams(bytes params); function validate( + uint256, + uint256, bytes memory params ) external pure returns (IInputValidator inputValidator) { require(params.length == 32, "invalid params"); diff --git a/packages/evm/contracts/test/MockExecutionModule.sol b/packages/evm/contracts/test/MockExecutionModule.sol deleted file mode 100644 index 87ce5c52..00000000 --- a/packages/evm/contracts/test/MockExecutionModule.sol +++ /dev/null @@ -1,22 +0,0 @@ -// SPDX-License-Identifier: LGPL-3.0-only -pragma solidity >=0.8.26; - -import { - IExecutionModule, - IOutputVerifier -} from "../interfaces/IExecutionModule.sol"; - -contract MockExecutionModule is IExecutionModule { - error invalidParams(); - - function validate( - bytes memory params - ) external pure returns (IOutputVerifier outputVerifier) { - require(params.length == 32, invalidParams()); - // solhint-disable no-inline-assembly - assembly { - outputVerifier := mload(add(params, 32)) - } - (outputVerifier) = abi.decode(params, (IOutputVerifier)); - } -} diff --git a/packages/evm/contracts/test/MockInputValidator.sol b/packages/evm/contracts/test/MockInputValidator.sol index 2dcb0c89..0c16adec 100644 --- a/packages/evm/contracts/test/MockInputValidator.sol +++ b/packages/evm/contracts/test/MockInputValidator.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: LGPL-3.0-only -pragma solidity >=0.8.26; +pragma solidity >=0.8.27; import { IInputValidator } from "../interfaces/IInputValidator.sol"; diff --git a/packages/evm/contracts/test/MockRegistryFilter.sol b/packages/evm/contracts/test/MockRegistryFilter.sol index d48bba7e..4899f574 100644 --- a/packages/evm/contracts/test/MockRegistryFilter.sol +++ b/packages/evm/contracts/test/MockRegistryFilter.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: LGPL-3.0-only -pragma solidity >=0.8.26; +pragma solidity >=0.8.27; import { IRegistryFilter } from "../interfaces/IRegistryFilter.sol"; import { @@ -9,12 +9,12 @@ import { interface IRegistry { function publishCommittee( uint256 e3Id, - address[] calldata cyphernodes, + address[] calldata ciphernodes, bytes calldata publicKey ) external; } -contract NaiveRegistryFilter is IRegistryFilter, OwnableUpgradeable { +contract MockNaiveRegistryFilter is IRegistryFilter, OwnableUpgradeable { struct Committee { address[] nodes; uint32[2] threshold; diff --git a/packages/evm/deploy/deploy.ts b/packages/evm/deploy/deploy.ts index 60c6f2bb..35b99935 100644 --- a/packages/evm/deploy/deploy.ts +++ b/packages/evm/deploy/deploy.ts @@ -2,18 +2,63 @@ import { DeployFunction } from "hardhat-deploy/types"; import { HardhatRuntimeEnvironment } from "hardhat/types"; const THIRTY_DAYS_IN_SECONDS = 60 * 60 * 24 * 30; +const addressOne = "0x0000000000000000000000000000000000000001"; const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { const { deployer } = await hre.getNamedAccounts(); const { deploy } = hre.deployments; + // Deploy Enclave contract + const enclave = await deploy("Enclave", { from: deployer, - args: [THIRTY_DAYS_IN_SECONDS], + args: [deployer, addressOne, THIRTY_DAYS_IN_SECONDS], log: true, }); console.log(`Enclave contract: `, enclave.address); + + // Deploy CyphernodeRegistryOwnable contract + + const cypherNodeRegistry = await deploy("CyphernodeRegistryOwnable", { + from: deployer, + args: [deployer, enclave.address], + log: true, + }); + + console.log( + `CyphernodeRegistryOwnable contract: `, + cypherNodeRegistry.address, + ); + + // Deploy NaiveRegistryFilter contract + + const naiveRegistryFilter = await deploy("NaiveRegistryFilter", { + from: deployer, + args: [deployer, cypherNodeRegistry.address], + log: true, + }); + + console.log(`NaiveRegistryFilter contract: `, naiveRegistryFilter.address); + + // set registry in enclave + const enclaveContract = await hre.ethers.getContractAt( + "Enclave", + enclave.address, + ); + + const registryAddress = await enclaveContract.cyphernodeRegistry(); + + if (registryAddress === cypherNodeRegistry.address) { + console.log(`Enclave contract already has registry`); + return; + } + + const result = await enclaveContract.setCyphernodeRegistry( + cypherNodeRegistry.address, + ); + await result.wait(); + console.log(`Enclave contract updated with registry`); }; export default func; func.id = "deploy_enclave"; // id required to prevent reexecution diff --git a/packages/evm/deployments/sepolia/.chainId b/packages/evm/deployments/sepolia/.chainId new file mode 100644 index 00000000..bd8d1cd4 --- /dev/null +++ b/packages/evm/deployments/sepolia/.chainId @@ -0,0 +1 @@ +11155111 \ No newline at end of file diff --git a/packages/evm/deployments/sepolia/CyphernodeRegistryOwnable.json b/packages/evm/deployments/sepolia/CyphernodeRegistryOwnable.json new file mode 100644 index 00000000..47ad8adb --- /dev/null +++ b/packages/evm/deployments/sepolia/CyphernodeRegistryOwnable.json @@ -0,0 +1,726 @@ +{ + "address": "0xF9E3aeB059D699Ac4541625DE81062d6D8ad7e85", + "abi": [ + { + "inputs": [ + { + "internalType": "address", + "name": "_owner", + "type": "address" + }, + { + "internalType": "address", + "name": "_enclave", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [], + "name": "CommitteeAlreadyPublished", + "type": "error" + }, + { + "inputs": [], + "name": "CommitteeAlreadyRequested", + "type": "error" + }, + { + "inputs": [], + "name": "CommitteeDoesNotExist", + "type": "error" + }, + { + "inputs": [], + "name": "CommitteeNotPublished", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "node", + "type": "address" + } + ], + "name": "CyphernodeNotEnabled", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidInitialization", + "type": "error" + }, + { + "inputs": [], + "name": "NotInitializing", + "type": "error" + }, + { + "inputs": [], + "name": "OnlyEnclave", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "OwnableInvalidOwner", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "OwnableUnauthorizedAccount", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "e3Id", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "publicKey", + "type": "bytes" + } + ], + "name": "CommitteePublished", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "e3Id", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "filter", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint32[2]", + "name": "threshold", + "type": "uint32[2]" + } + ], + "name": "CommitteeRequested", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "node", + "type": "address" + } + ], + "name": "CyphernodeAdded", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "node", + "type": "address" + } + ], + "name": "CyphernodeRemoved", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "enclave", + "type": "address" + } + ], + "name": "EnclaveSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint64", + "name": "version", + "type": "uint64" + } + ], + "name": "Initialized", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "node", + "type": "address" + } + ], + "name": "addCyphernode", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "e3Id", + "type": "uint256" + } + ], + "name": "committeePublicKey", + "outputs": [ + { + "internalType": "bytes", + "name": "publicKey", + "type": "bytes" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "enclave", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_owner", + "type": "address" + }, + { + "internalType": "address", + "name": "_enclave", + "type": "address" + } + ], + "name": "initialize", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "node", + "type": "address" + } + ], + "name": "isCyphernodeEligible", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "cyphernode", + "type": "address" + } + ], + "name": "isEnabled", + "outputs": [ + { + "internalType": "bool", + "name": "isEnabled", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "e3Id", + "type": "uint256" + } + ], + "name": "publicKeys", + "outputs": [ + { + "internalType": "bytes", + "name": "publicKey", + "type": "bytes" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "e3Id", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "publicKey", + "type": "bytes" + } + ], + "name": "publishCommittee", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "node", + "type": "address" + } + ], + "name": "removeCyphernode", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "renounceOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "e3Id", + "type": "uint256" + }, + { + "internalType": "address", + "name": "filter", + "type": "address" + }, + { + "internalType": "uint32[2]", + "name": "threshold", + "type": "uint32[2]" + } + ], + "name": "requestCommittee", + "outputs": [ + { + "internalType": "bool", + "name": "success", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "e3Id", + "type": "uint256" + } + ], + "name": "requests", + "outputs": [ + { + "internalType": "contract IRegistryFilter", + "name": "filter", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_enclave", + "type": "address" + } + ], + "name": "setEnclave", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } + ], + "transactionHash": "0x52c081e0009793b5db42f4b17258c27a2a11c40c46df6fad4d183de612d68b43", + "receipt": { + "to": null, + "from": "0x485E60C486671E932fd9C53d4110cdEab1E7F0eb", + "contractAddress": "0xF9E3aeB059D699Ac4541625DE81062d6D8ad7e85", + "transactionIndex": 9, + "gasUsed": "860580", + "logsBloom": "0x00000000000080000001000000000100000000000000000000800000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000001000000000000000000000000000000000000020000000000000000000800000000000000000000000000000000400000800000000000000800000000000000800000000080000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000002000000000004000000000000000020000000000000000000020000000000000000000000000000000001000000000000", + "blockHash": "0x8d6af7fa19913d7eb201f04a7307ee3844cdc4bda86b43ca3ab7e1522b577cab", + "transactionHash": "0x52c081e0009793b5db42f4b17258c27a2a11c40c46df6fad4d183de612d68b43", + "logs": [ + { + "transactionIndex": 9, + "blockNumber": 6668198, + "transactionHash": "0x52c081e0009793b5db42f4b17258c27a2a11c40c46df6fad4d183de612d68b43", + "address": "0xF9E3aeB059D699Ac4541625DE81062d6D8ad7e85", + "topics": [ + "0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x000000000000000000000000485e60c486671e932fd9c53d4110cdeab1e7f0eb" + ], + "data": "0x", + "logIndex": 16, + "blockHash": "0x8d6af7fa19913d7eb201f04a7307ee3844cdc4bda86b43ca3ab7e1522b577cab" + }, + { + "transactionIndex": 9, + "blockNumber": 6668198, + "transactionHash": "0x52c081e0009793b5db42f4b17258c27a2a11c40c46df6fad4d183de612d68b43", + "address": "0xF9E3aeB059D699Ac4541625DE81062d6D8ad7e85", + "topics": [ + "0x2c8267accd82e977550ed2349c73311183cd22e306347be4453c8d130995e3c9", + "0x000000000000000000000000083b0ae25fd41469fd8857027b40e3f49a169375" + ], + "data": "0x", + "logIndex": 17, + "blockHash": "0x8d6af7fa19913d7eb201f04a7307ee3844cdc4bda86b43ca3ab7e1522b577cab" + }, + { + "transactionIndex": 9, + "blockNumber": 6668198, + "transactionHash": "0x52c081e0009793b5db42f4b17258c27a2a11c40c46df6fad4d183de612d68b43", + "address": "0xF9E3aeB059D699Ac4541625DE81062d6D8ad7e85", + "topics": [ + "0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0", + "0x000000000000000000000000485e60c486671e932fd9c53d4110cdeab1e7f0eb", + "0x000000000000000000000000485e60c486671e932fd9c53d4110cdeab1e7f0eb" + ], + "data": "0x", + "logIndex": 18, + "blockHash": "0x8d6af7fa19913d7eb201f04a7307ee3844cdc4bda86b43ca3ab7e1522b577cab" + }, + { + "transactionIndex": 9, + "blockNumber": 6668198, + "transactionHash": "0x52c081e0009793b5db42f4b17258c27a2a11c40c46df6fad4d183de612d68b43", + "address": "0xF9E3aeB059D699Ac4541625DE81062d6D8ad7e85", + "topics": [ + "0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000000000001", + "logIndex": 19, + "blockHash": "0x8d6af7fa19913d7eb201f04a7307ee3844cdc4bda86b43ca3ab7e1522b577cab" + } + ], + "blockNumber": 6668198, + "cumulativeGasUsed": "2286050", + "status": 1, + "byzantium": true + }, + "args": [ + "0x485E60C486671E932fd9C53d4110cdEab1E7F0eb", + "0x083b0AE25fD41469Fd8857027B40e3f49A169375" + ], + "numDeployments": 1, + "solcInputHash": "d0e6e4f19028714f394c36db62dff2be", + "metadata": "{\"compiler\":{\"version\":\"0.8.26+commit.8a97fa7a\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_enclave\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"CommitteeAlreadyPublished\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CommitteeAlreadyRequested\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CommitteeDoesNotExist\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CommitteeNotPublished\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"node\",\"type\":\"address\"}],\"name\":\"CyphernodeNotEnabled\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidInitialization\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotInitializing\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyEnclave\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"OwnableInvalidOwner\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"OwnableUnauthorizedAccount\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"e3Id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"publicKey\",\"type\":\"bytes\"}],\"name\":\"CommitteePublished\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"e3Id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"filter\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint32[2]\",\"name\":\"threshold\",\"type\":\"uint32[2]\"}],\"name\":\"CommitteeRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"node\",\"type\":\"address\"}],\"name\":\"CyphernodeAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"node\",\"type\":\"address\"}],\"name\":\"CyphernodeRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"enclave\",\"type\":\"address\"}],\"name\":\"EnclaveSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"version\",\"type\":\"uint64\"}],\"name\":\"Initialized\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"node\",\"type\":\"address\"}],\"name\":\"addCyphernode\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"e3Id\",\"type\":\"uint256\"}],\"name\":\"committeePublicKey\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"publicKey\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"enclave\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_enclave\",\"type\":\"address\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"node\",\"type\":\"address\"}],\"name\":\"isCyphernodeEligible\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"cyphernode\",\"type\":\"address\"}],\"name\":\"isEnabled\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"e3Id\",\"type\":\"uint256\"}],\"name\":\"publicKeys\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"publicKey\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"e3Id\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"publicKey\",\"type\":\"bytes\"}],\"name\":\"publishCommittee\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"node\",\"type\":\"address\"}],\"name\":\"removeCyphernode\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"e3Id\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"filter\",\"type\":\"address\"},{\"internalType\":\"uint32[2]\",\"name\":\"threshold\",\"type\":\"uint32[2]\"}],\"name\":\"requestCommittee\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"e3Id\",\"type\":\"uint256\"}],\"name\":\"requests\",\"outputs\":[{\"internalType\":\"contract IRegistryFilter\",\"name\":\"filter\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_enclave\",\"type\":\"address\"}],\"name\":\"setEnclave\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"errors\":{\"InvalidInitialization()\":[{\"details\":\"The contract is already initialized.\"}],\"NotInitializing()\":[{\"details\":\"The contract is not initializing.\"}],\"OwnableInvalidOwner(address)\":[{\"details\":\"The owner is not a valid owner account. (eg. `address(0)`)\"}],\"OwnableUnauthorizedAccount(address)\":[{\"details\":\"The caller account is not authorized to perform an operation.\"}]},\"events\":{\"CommitteePublished(uint256,bytes)\":{\"params\":{\"e3Id\":\"ID of the E3 for which the committee was selected.\",\"publicKey\":\"Public key of the committee.\"}},\"CommitteeRequested(uint256,address,uint32[2])\":{\"params\":{\"e3Id\":\"ID of the E3 for which the committee was selected.\",\"filter\":\"Address of the contract that will coordinate committee selection.\",\"threshold\":\"The M/N threshold for the committee.\"}},\"EnclaveSet(address)\":{\"params\":{\"enclave\":\"Address of the enclave contract.\"}},\"Initialized(uint64)\":{\"details\":\"Triggered when the contract has been initialized or reinitialized.\"}},\"kind\":\"dev\",\"methods\":{\"committeePublicKey(uint256)\":{\"details\":\"This function MUST revert if no committee has been requested for the given E3.This function MUST revert if the committee has not yet published a public key.\",\"params\":{\"e3Id\":\"ID of the E3 for which to get the committee public key.\"},\"returns\":{\"publicKey\":\"The public key of the committee.\"}},\"owner()\":{\"details\":\"Returns the address of the current owner.\"},\"renounceOwnership()\":{\"details\":\"Leaves the contract without owner. It will not be possible to call `onlyOwner` functions. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby disabling any functionality that is only available to the owner.\"},\"requestCommittee(uint256,address,uint32[2])\":{\"details\":\"This function MUST revert when not called by the Enclave contract.\",\"params\":{\"e3Id\":\"ID of the E3 for which to select the committee.\",\"filter\":\"The address of the filter responsible for the committee selection process.\",\"threshold\":\"The M/N threshold for the committee.\"},\"returns\":{\"success\":\"True if committee selection was successfully initiated.\"}},\"transferOwnership(address)\":{\"details\":\"Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.\"}},\"version\":1},\"userdoc\":{\"events\":{\"CommitteePublished(uint256,bytes)\":{\"notice\":\"This event MUST be emitted when a committee is selected for an E3.\"},\"CommitteeRequested(uint256,address,uint32[2])\":{\"notice\":\"This event MUST be emitted when a committee is selected for an E3.\"},\"CyphernodeAdded(address)\":{\"notice\":\"This event MUST be emitted when a cyphernode is added to the registry.\"},\"CyphernodeRemoved(address)\":{\"notice\":\"This event MUST be emitted when a cyphernode is removed from the registry.\"},\"EnclaveSet(address)\":{\"notice\":\"This event MUST be emitted when `enclave` is set.\"}},\"kind\":\"user\",\"methods\":{\"committeePublicKey(uint256)\":{\"notice\":\"This function should be called by the Enclave contract to get the public key of a committee.\"},\"requestCommittee(uint256,address,uint32[2])\":{\"notice\":\"Initiates the committee selection process for a specified E3.\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/registry/CyphernodeRegistryOwnable.sol\":\"CyphernodeRegistryOwnable\"},\"evmVersion\":\"paris\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"none\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":800},\"remappings\":[],\"viaIR\":true},\"sources\":{\"@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)\\n\\npragma solidity ^0.8.20;\\n\\nimport {ContextUpgradeable} from \\\"../utils/ContextUpgradeable.sol\\\";\\nimport {Initializable} from \\\"../proxy/utils/Initializable.sol\\\";\\n\\n/**\\n * @dev Contract module which provides a basic access control mechanism, where\\n * there is an account (an owner) that can be granted exclusive access to\\n * specific functions.\\n *\\n * The initial owner is set to the address provided by the deployer. This can\\n * later be changed with {transferOwnership}.\\n *\\n * This module is used through inheritance. It will make available the modifier\\n * `onlyOwner`, which can be applied to your functions to restrict their use to\\n * the owner.\\n */\\nabstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {\\n /// @custom:storage-location erc7201:openzeppelin.storage.Ownable\\n struct OwnableStorage {\\n address _owner;\\n }\\n\\n // keccak256(abi.encode(uint256(keccak256(\\\"openzeppelin.storage.Ownable\\\")) - 1)) & ~bytes32(uint256(0xff))\\n bytes32 private constant OwnableStorageLocation = 0x9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300;\\n\\n function _getOwnableStorage() private pure returns (OwnableStorage storage $) {\\n assembly {\\n $.slot := OwnableStorageLocation\\n }\\n }\\n\\n /**\\n * @dev The caller account is not authorized to perform an operation.\\n */\\n error OwnableUnauthorizedAccount(address account);\\n\\n /**\\n * @dev The owner is not a valid owner account. (eg. `address(0)`)\\n */\\n error OwnableInvalidOwner(address owner);\\n\\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\\n\\n /**\\n * @dev Initializes the contract setting the address provided by the deployer as the initial owner.\\n */\\n function __Ownable_init(address initialOwner) internal onlyInitializing {\\n __Ownable_init_unchained(initialOwner);\\n }\\n\\n function __Ownable_init_unchained(address initialOwner) internal onlyInitializing {\\n if (initialOwner == address(0)) {\\n revert OwnableInvalidOwner(address(0));\\n }\\n _transferOwnership(initialOwner);\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the owner.\\n */\\n modifier onlyOwner() {\\n _checkOwner();\\n _;\\n }\\n\\n /**\\n * @dev Returns the address of the current owner.\\n */\\n function owner() public view virtual returns (address) {\\n OwnableStorage storage $ = _getOwnableStorage();\\n return $._owner;\\n }\\n\\n /**\\n * @dev Throws if the sender is not the owner.\\n */\\n function _checkOwner() internal view virtual {\\n if (owner() != _msgSender()) {\\n revert OwnableUnauthorizedAccount(_msgSender());\\n }\\n }\\n\\n /**\\n * @dev Leaves the contract without owner. It will not be possible to call\\n * `onlyOwner` functions. Can only be called by the current owner.\\n *\\n * NOTE: Renouncing ownership will leave the contract without an owner,\\n * thereby disabling any functionality that is only available to the owner.\\n */\\n function renounceOwnership() public virtual onlyOwner {\\n _transferOwnership(address(0));\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Can only be called by the current owner.\\n */\\n function transferOwnership(address newOwner) public virtual onlyOwner {\\n if (newOwner == address(0)) {\\n revert OwnableInvalidOwner(address(0));\\n }\\n _transferOwnership(newOwner);\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Internal function without access restriction.\\n */\\n function _transferOwnership(address newOwner) internal virtual {\\n OwnableStorage storage $ = _getOwnableStorage();\\n address oldOwner = $._owner;\\n $._owner = newOwner;\\n emit OwnershipTransferred(oldOwner, newOwner);\\n }\\n}\\n\",\"keccak256\":\"0xc163fcf9bb10138631a9ba5564df1fa25db9adff73bd9ee868a8ae1858fe093a\",\"license\":\"MIT\"},\"@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/Initializable.sol)\\n\\npragma solidity ^0.8.20;\\n\\n/**\\n * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed\\n * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an\\n * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer\\n * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.\\n *\\n * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be\\n * reused. This mechanism prevents re-execution of each \\\"step\\\" but allows the creation of new initialization steps in\\n * case an upgrade adds a module that needs to be initialized.\\n *\\n * For example:\\n *\\n * [.hljs-theme-light.nopadding]\\n * ```solidity\\n * contract MyToken is ERC20Upgradeable {\\n * function initialize() initializer public {\\n * __ERC20_init(\\\"MyToken\\\", \\\"MTK\\\");\\n * }\\n * }\\n *\\n * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {\\n * function initializeV2() reinitializer(2) public {\\n * __ERC20Permit_init(\\\"MyToken\\\");\\n * }\\n * }\\n * ```\\n *\\n * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as\\n * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.\\n *\\n * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure\\n * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.\\n *\\n * [CAUTION]\\n * ====\\n * Avoid leaving a contract uninitialized.\\n *\\n * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation\\n * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke\\n * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:\\n *\\n * [.hljs-theme-light.nopadding]\\n * ```\\n * /// @custom:oz-upgrades-unsafe-allow constructor\\n * constructor() {\\n * _disableInitializers();\\n * }\\n * ```\\n * ====\\n */\\nabstract contract Initializable {\\n /**\\n * @dev Storage of the initializable contract.\\n *\\n * It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions\\n * when using with upgradeable contracts.\\n *\\n * @custom:storage-location erc7201:openzeppelin.storage.Initializable\\n */\\n struct InitializableStorage {\\n /**\\n * @dev Indicates that the contract has been initialized.\\n */\\n uint64 _initialized;\\n /**\\n * @dev Indicates that the contract is in the process of being initialized.\\n */\\n bool _initializing;\\n }\\n\\n // keccak256(abi.encode(uint256(keccak256(\\\"openzeppelin.storage.Initializable\\\")) - 1)) & ~bytes32(uint256(0xff))\\n bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00;\\n\\n /**\\n * @dev The contract is already initialized.\\n */\\n error InvalidInitialization();\\n\\n /**\\n * @dev The contract is not initializing.\\n */\\n error NotInitializing();\\n\\n /**\\n * @dev Triggered when the contract has been initialized or reinitialized.\\n */\\n event Initialized(uint64 version);\\n\\n /**\\n * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,\\n * `onlyInitializing` functions can be used to initialize parent contracts.\\n *\\n * Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any\\n * number of times. This behavior in the constructor can be useful during testing and is not expected to be used in\\n * production.\\n *\\n * Emits an {Initialized} event.\\n */\\n modifier initializer() {\\n // solhint-disable-next-line var-name-mixedcase\\n InitializableStorage storage $ = _getInitializableStorage();\\n\\n // Cache values to avoid duplicated sloads\\n bool isTopLevelCall = !$._initializing;\\n uint64 initialized = $._initialized;\\n\\n // Allowed calls:\\n // - initialSetup: the contract is not in the initializing state and no previous version was\\n // initialized\\n // - construction: the contract is initialized at version 1 (no reininitialization) and the\\n // current contract is just being deployed\\n bool initialSetup = initialized == 0 && isTopLevelCall;\\n bool construction = initialized == 1 && address(this).code.length == 0;\\n\\n if (!initialSetup && !construction) {\\n revert InvalidInitialization();\\n }\\n $._initialized = 1;\\n if (isTopLevelCall) {\\n $._initializing = true;\\n }\\n _;\\n if (isTopLevelCall) {\\n $._initializing = false;\\n emit Initialized(1);\\n }\\n }\\n\\n /**\\n * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the\\n * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be\\n * used to initialize parent contracts.\\n *\\n * A reinitializer may be used after the original initialization step. This is essential to configure modules that\\n * are added through upgrades and that require initialization.\\n *\\n * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`\\n * cannot be nested. If one is invoked in the context of another, execution will revert.\\n *\\n * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in\\n * a contract, executing them in the right order is up to the developer or operator.\\n *\\n * WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization.\\n *\\n * Emits an {Initialized} event.\\n */\\n modifier reinitializer(uint64 version) {\\n // solhint-disable-next-line var-name-mixedcase\\n InitializableStorage storage $ = _getInitializableStorage();\\n\\n if ($._initializing || $._initialized >= version) {\\n revert InvalidInitialization();\\n }\\n $._initialized = version;\\n $._initializing = true;\\n _;\\n $._initializing = false;\\n emit Initialized(version);\\n }\\n\\n /**\\n * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the\\n * {initializer} and {reinitializer} modifiers, directly or indirectly.\\n */\\n modifier onlyInitializing() {\\n _checkInitializing();\\n _;\\n }\\n\\n /**\\n * @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}.\\n */\\n function _checkInitializing() internal view virtual {\\n if (!_isInitializing()) {\\n revert NotInitializing();\\n }\\n }\\n\\n /**\\n * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.\\n * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized\\n * to any version. It is recommended to use this to lock implementation contracts that are designed to be called\\n * through proxies.\\n *\\n * Emits an {Initialized} event the first time it is successfully executed.\\n */\\n function _disableInitializers() internal virtual {\\n // solhint-disable-next-line var-name-mixedcase\\n InitializableStorage storage $ = _getInitializableStorage();\\n\\n if ($._initializing) {\\n revert InvalidInitialization();\\n }\\n if ($._initialized != type(uint64).max) {\\n $._initialized = type(uint64).max;\\n emit Initialized(type(uint64).max);\\n }\\n }\\n\\n /**\\n * @dev Returns the highest version that has been initialized. See {reinitializer}.\\n */\\n function _getInitializedVersion() internal view returns (uint64) {\\n return _getInitializableStorage()._initialized;\\n }\\n\\n /**\\n * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.\\n */\\n function _isInitializing() internal view returns (bool) {\\n return _getInitializableStorage()._initializing;\\n }\\n\\n /**\\n * @dev Returns a pointer to the storage namespace.\\n */\\n // solhint-disable-next-line var-name-mixedcase\\n function _getInitializableStorage() private pure returns (InitializableStorage storage $) {\\n assembly {\\n $.slot := INITIALIZABLE_STORAGE\\n }\\n }\\n}\\n\",\"keccak256\":\"0x631188737069917d2f909d29ce62c4d48611d326686ba6683e26b72a23bfac0b\",\"license\":\"MIT\"},\"@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\\n\\npragma solidity ^0.8.20;\\nimport {Initializable} from \\\"../proxy/utils/Initializable.sol\\\";\\n\\n/**\\n * @dev Provides information about the current execution context, including the\\n * sender of the transaction and its data. While these are generally available\\n * via msg.sender and msg.data, they should not be accessed in such a direct\\n * manner, since when dealing with meta-transactions the account sending and\\n * paying for execution may not be the actual sender (as far as an application\\n * is concerned).\\n *\\n * This contract is only required for intermediate, library-like contracts.\\n */\\nabstract contract ContextUpgradeable is Initializable {\\n function __Context_init() internal onlyInitializing {\\n }\\n\\n function __Context_init_unchained() internal onlyInitializing {\\n }\\n function _msgSender() internal view virtual returns (address) {\\n return msg.sender;\\n }\\n\\n function _msgData() internal view virtual returns (bytes calldata) {\\n return msg.data;\\n }\\n\\n function _contextSuffixLength() internal view virtual returns (uint256) {\\n return 0;\\n }\\n}\\n\",\"keccak256\":\"0xdbef5f0c787055227243a7318ef74c8a5a1108ca3a07f2b3a00ef67769e1e397\",\"license\":\"MIT\"},\"contracts/interfaces/ICyphernodeRegistry.sol\":{\"content\":\"// SPDX-License-Identifier: LGPL-3.0-only\\npragma solidity >=0.8.26;\\n\\ninterface ICyphernodeRegistry {\\n /// @notice This event MUST be emitted when a committee is selected for an E3.\\n /// @param e3Id ID of the E3 for which the committee was selected.\\n /// @param filter Address of the contract that will coordinate committee selection.\\n /// @param threshold The M/N threshold for the committee.\\n event CommitteeRequested(\\n uint256 indexed e3Id,\\n address filter,\\n uint32[2] threshold\\n );\\n\\n /// @notice This event MUST be emitted when a committee is selected for an E3.\\n /// @param e3Id ID of the E3 for which the committee was selected.\\n /// @param publicKey Public key of the committee.\\n event CommitteePublished(uint256 indexed e3Id, bytes publicKey);\\n\\n /// @notice This event MUST be emitted when `enclave` is set.\\n /// @param enclave Address of the enclave contract.\\n event EnclaveSet(address indexed enclave);\\n\\n /// @notice This event MUST be emitted when a cyphernode is added to the registry.\\n event CyphernodeAdded(address indexed node);\\n\\n /// @notice This event MUST be emitted when a cyphernode is removed from the registry.\\n event CyphernodeRemoved(address indexed node);\\n\\n function isCyphernodeEligible(address cyphernode) external returns (bool);\\n\\n /// @notice Initiates the committee selection process for a specified E3.\\n /// @dev This function MUST revert when not called by the Enclave contract.\\n /// @param e3Id ID of the E3 for which to select the committee.\\n /// @param filter The address of the filter responsible for the committee selection process.\\n /// @param threshold The M/N threshold for the committee.\\n /// @return success True if committee selection was successfully initiated.\\n function requestCommittee(\\n uint256 e3Id,\\n address filter,\\n uint32[2] calldata threshold\\n ) external returns (bool success);\\n\\n /// @notice Publishes the public key resulting from the committee selection process.\\n /// @dev This function MUST revert if not called by the previously selected filter.\\n /// @param e3Id ID of the E3 for which to select the committee.\\n /// @param publicKey The public key generated by the selected committee.\\n function publishCommittee(\\n uint256 e3Id,\\n bytes calldata proof,\\n bytes calldata publicKey\\n ) external;\\n\\n /// @notice This function should be called by the Enclave contract to get the public key of a committee.\\n /// @dev This function MUST revert if no committee has been requested for the given E3.\\n /// @dev This function MUST revert if the committee has not yet published a public key.\\n /// @param e3Id ID of the E3 for which to get the committee public key.\\n /// @return publicKey The public key of the committee.\\n function committeePublicKey(\\n uint256 e3Id\\n ) external view returns (bytes memory);\\n}\\n\",\"keccak256\":\"0x60af5d66db32528f5032fe083218f180ab83f3199bcf090bed7249c28bc18104\",\"license\":\"LGPL-3.0-only\"},\"contracts/interfaces/IRegistryFilter.sol\":{\"content\":\"// SPDX-License-Identifier: LGPL-3.0-only\\npragma solidity >=0.8.26;\\n\\ninterface IRegistryFilter {\\n function requestCommittee(\\n uint256 e3Id,\\n uint32[2] calldata threshold\\n ) external returns (bool success);\\n}\\n\",\"keccak256\":\"0xec67f88f2cbf46e28d4835669ef3dd2320afe5b0324423944037c16fc3f42195\",\"license\":\"LGPL-3.0-only\"},\"contracts/registry/CyphernodeRegistryOwnable.sol\":{\"content\":\"// SPDX-License-Identifier: LGPL-3.0-only\\npragma solidity >=0.8.26;\\n\\nimport { ICyphernodeRegistry } from \\\"../interfaces/ICyphernodeRegistry.sol\\\";\\nimport { IRegistryFilter } from \\\"../interfaces/IRegistryFilter.sol\\\";\\nimport {\\n OwnableUpgradeable\\n} from \\\"@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol\\\";\\n\\ncontract CyphernodeRegistryOwnable is ICyphernodeRegistry, OwnableUpgradeable {\\n ////////////////////////////////////////////////////////////\\n // //\\n // Storage Variables //\\n // //\\n ////////////////////////////////////////////////////////////\\n\\n address public enclave;\\n\\n mapping(address cyphernode => bool isEnabled) public isEnabled;\\n\\n mapping(uint256 e3Id => IRegistryFilter filter) public requests;\\n mapping(uint256 e3Id => bytes publicKey) public publicKeys;\\n\\n ////////////////////////////////////////////////////////////\\n // //\\n // Errors //\\n // //\\n ////////////////////////////////////////////////////////////\\n\\n error CommitteeAlreadyRequested();\\n error CommitteeAlreadyPublished();\\n error CommitteeDoesNotExist();\\n error CommitteeNotPublished();\\n error CyphernodeNotEnabled(address node);\\n error OnlyEnclave();\\n\\n ////////////////////////////////////////////////////////////\\n // //\\n // Modifiers //\\n // //\\n ////////////////////////////////////////////////////////////\\n\\n modifier onlyEnclave() {\\n require(msg.sender == enclave, OnlyEnclave());\\n _;\\n }\\n\\n ////////////////////////////////////////////////////////////\\n // //\\n // Initialization //\\n // //\\n ////////////////////////////////////////////////////////////\\n\\n constructor(address _owner, address _enclave) {\\n initialize(_owner, _enclave);\\n }\\n\\n function initialize(address _owner, address _enclave) public initializer {\\n __Ownable_init(msg.sender);\\n setEnclave(_enclave);\\n transferOwnership(_owner);\\n }\\n\\n ////////////////////////////////////////////////////////////\\n // //\\n // Core Entrypoints //\\n // //\\n ////////////////////////////////////////////////////////////\\n\\n function requestCommittee(\\n uint256 e3Id,\\n address filter,\\n uint32[2] calldata threshold\\n ) external onlyEnclave returns (bool success) {\\n require(\\n requests[e3Id] == IRegistryFilter(address(0)),\\n CommitteeAlreadyRequested()\\n );\\n requests[e3Id] = IRegistryFilter(filter);\\n\\n IRegistryFilter(filter).requestCommittee(e3Id, threshold);\\n emit CommitteeRequested(e3Id, filter, threshold);\\n success = true;\\n }\\n\\n function publishCommittee(\\n uint256 e3Id,\\n bytes calldata,\\n bytes calldata publicKey\\n ) external {\\n // only to be published by the filter\\n require(address(requests[e3Id]) == msg.sender, CommitteeDoesNotExist());\\n\\n // for (uint256 i = 0; i < cyphernodes.length; i++) {\\n // require(\\n // isEnabled[cyphernodes[i]] == true,\\n // CyphernodeNotEnabled(cyphernodes[i])\\n // );\\n // }\\n\\n publicKeys[e3Id] = publicKey;\\n emit CommitteePublished(e3Id, publicKey);\\n }\\n\\n ////////////////////////////////////////////////////////////\\n // //\\n // Set Functions //\\n // //\\n ////////////////////////////////////////////////////////////\\n\\n function setEnclave(address _enclave) public onlyOwner {\\n enclave = _enclave;\\n emit EnclaveSet(_enclave);\\n }\\n\\n function addCyphernode(address node) external onlyOwner {\\n isEnabled[node] = true;\\n emit CyphernodeAdded(node);\\n }\\n\\n function removeCyphernode(address node) external onlyOwner {\\n isEnabled[node] = false;\\n emit CyphernodeRemoved(node);\\n }\\n\\n function isCyphernodeEligible(address node) external view returns (bool) {\\n return isEnabled[node];\\n }\\n\\n ////////////////////////////////////////////////////////////\\n // //\\n // Get Functions //\\n // //\\n ////////////////////////////////////////////////////////////\\n\\n function committeePublicKey(\\n uint256 e3Id\\n ) external view returns (bytes memory publicKey) {\\n publicKey = publicKeys[e3Id];\\n require(publicKey.length > 0, CommitteeNotPublished());\\n }\\n}\\n\",\"keccak256\":\"0x4cfad952b8b65dba77a5adf39dba5d1f7ff8d0a3661793bf155fea39f9d3f8e6\",\"license\":\"LGPL-3.0-only\"}},\"version\":1}", + "bytecode": "0x6080346101f957601f61105238819003918201601f19168301916001600160401b038311848410176101fe5780849260409485528339810103126101f957610052602061004b83610214565b9201610214565b60008051602061103283398151915254604081901c60ff16159290916001600160401b038316801590816101f1575b60011490816101e7575b1590816101de575b506101cd576001600160401b031983166001176000805160206110328339815191525561013292846101a2575b506100c96102b0565b6100d16102b0565b6100da33610228565b6100e26102de565b600080546001600160a01b0319166001600160a01b039290921691821781557f2c8267accd82e977550ed2349c73311183cd22e306347be4453c8d130995e3c99080a261012d6102de565b610228565b610146575b604051610d0b90816103278239f35b68ff0000000000000000196000805160206110328339815191525416600080516020611032833981519152557fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2602060405160018152a1610137565b6001600160481b031916680100000000000000011760008051602061103283398151915255386100c0565b63f92ee8a960e01b60005260046000fd5b90501538610093565b303b15915061008b565b859150610081565b600080fd5b634e487b7160e01b600052604160045260246000fd5b51906001600160a01b03821682036101f957565b6001600160a01b0316801561029a577f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c19930080546001600160a01b0319811683179091556001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a3565b631e4fbdf760e01b600052600060045260246000fd5b60ff6000805160206110328339815191525460401c16156102cd57565b631afcd79f60e31b60005260046000fd5b7f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300546001600160a01b0316330361031157565b63118cdaa760e01b6000523360045260246000fdfe608080604052600436101561001357600080fd5b60003560e01c9081632a8dc588146109b957508063476422f814610952578063485cc9551461074657806370e36bbe146106e3578063715018a61461064a578063770ad208146105e057806381d12c58146105ab5780638da5cb5b146105655780639015d371146105265780639ccb58d5146103cc578063c680f41014610394578063d9bbec9514610170578063dbb06c9314610149578063e82f3b70146100f45763f2fde38b146100c457600080fd5b346100ef5760203660031901126100ef576100ed6100e06109f4565b6100e8610c76565b610bd0565b005b600080fd5b346100ef5760203660031901126100ef57600435600052600360205261011d6040600020610a7c565b805115610138576101349060405191829182610b20565b0390f35b6322e679e360e11b60005260046000fd5b346100ef5760003660031901126100ef5760206001600160a01b0360005416604051908152f35b346100ef5760603660031901126100ef5760043560243567ffffffffffffffff81116100ef576101a4903690600401610b69565b505060443567ffffffffffffffff81116100ef576101c6903690600401610b69565b908260005260026020526001600160a01b0360406000205416330361038357826000526003602052604060002067ffffffffffffffff831161036d5761020c8154610a20565b601f8111610325575b506000601f841160011461029d5791604091847f8d0ca30515bbff1268ae5868080463444e5002373f7bc7d8d8869dca0a5ffc019594600091610292575b508460011b906000198660031b1c19161790555b82825193849260208452816020850152848401376000828201840152601f01601f19168101030190a2005b905082013587610253565b8181526020812090601f198516815b81811061030d57509160409391867f8d0ca30515bbff1268ae5868080463444e5002373f7bc7d8d8869dca0a5ffc01979694106102f3575b5050600184811b019055610267565b830135600019600387901b60f8161c1916905586806102e4565b919260206001819286890135815501940192016102ac565b816000526020600020601f850160051c81019160208610610363575b601f0160051c01905b8181106103575750610215565b6000815560010161034a565b9091508190610341565b634e487b7160e01b600052604160045260246000fd5b632a17a1f360e01b60005260046000fd5b346100ef5760203660031901126100ef5760043560005260036020526101346103c06040600020610a7c565b60405191829182610b20565b346100ef5760803660031901126100ef576004356103e8610a0a565b366084116100ef576001600160a01b03600054163303610515578160005260026020526001600160a01b0360406000205416610504576001600160a01b03168160005260026020526040600020816001600160a01b0319825416179055604051631590527b60e11b815282600482015261046460248201610b97565b6020816064816000865af180156104f8576104bd575b5060607fa17377d4a5c0ff5c67888a6b08d9bf3a8505b47e922b6186b259471ebf12738e916040519081526104b160208201610b97565ba2602060405160018152f35b6020813d6020116104f0575b816104d660209383610a5a565b810103126100ef575180151581036100ef5750606061047a565b3d91506104c9565b6040513d6000823e3d90fd5b6374ff462560e11b60005260046000fd5b63e4c2a7eb60e01b60005260046000fd5b346100ef5760203660031901126100ef576001600160a01b036105476109f4565b166000526001602052602060ff604060002054166040519015158152f35b346100ef5760003660031901126100ef5760206001600160a01b037f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c1993005416604051908152f35b346100ef5760203660031901126100ef57600435600052600260205260206001600160a01b0360406000205416604051908152f35b346100ef5760203660031901126100ef576001600160a01b036106016109f4565b610609610c76565b168060005260016020526040600020600160ff198254161790557f0fdc359cb937ddbe7734e324351ff282307ad333751a9e90f17e7330157ea579600080a2005b346100ef5760003660031901126100ef57610663610c76565b60006001600160a01b037f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300546001600160a01b031981167f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c19930055167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a3005b346100ef5760203660031901126100ef576001600160a01b036107046109f4565b61070c610c76565b16806001600160a01b031960005416176000557f2c8267accd82e977550ed2349c73311183cd22e306347be4453c8d130995e3c9600080a2005b346100ef5760403660031901126100ef5761075f6109f4565b610767610a0a565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00549160ff8360401c16159267ffffffffffffffff81168015908161094a575b6001149081610940575b159081610937575b506109265767ffffffffffffffff1981166001177ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0055610864926001600160a01b0391856108e7575b5061080b610cbe565b610813610cbe565b61081c33610bd0565b610824610c76565b16806001600160a01b031960005416176000557f2c8267accd82e977550ed2349c73311183cd22e306347be4453c8d130995e3c9600080a26100e8610c76565b61086a57005b68ff0000000000000000197ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0054167ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00557fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2602060405160018152a1005b68ffffffffffffffffff191668010000000000000001177ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005585610802565b63f92ee8a960e01b60005260046000fd5b905015856107b9565b303b1591506107b1565b8591506107a7565b346100ef5760203660031901126100ef576001600160a01b036109736109f4565b61097b610c76565b16806000526001602052604060002060ff1981541690557f07f3f62f2502752da9299b12b0a9966cb97ace5e3ce476d04649d5f588ec4491600080a2005b346100ef5760203660031901126100ef576020906001600160a01b036109dd6109f4565b166000526001825260ff6040600020541615158152f35b600435906001600160a01b03821682036100ef57565b602435906001600160a01b03821682036100ef57565b90600182811c92168015610a50575b6020831014610a3a57565b634e487b7160e01b600052602260045260246000fd5b91607f1691610a2f565b90601f8019910116810190811067ffffffffffffffff82111761036d57604052565b9060405191826000825492610a9084610a20565b8084529360018116908115610afe5750600114610ab7575b50610ab592500383610a5a565b565b90506000929192526020600020906000915b818310610ae2575050906020610ab59282010138610aa8565b6020919350806001915483858901015201910190918492610ac9565b905060209250610ab594915060ff191682840152151560051b82010138610aa8565b91909160208152825180602083015260005b818110610b53575060409293506000838284010152601f8019910116010190565b8060208092870101516040828601015201610b32565b9181601f840112156100ef5782359167ffffffffffffffff83116100ef57602083818601950101116100ef57565b60446000915b60028310610baa57505050565b81359063ffffffff82168092036100ef5760208160019382935201920192019190610b9d565b6001600160a01b03168015610c60576001600160a01b037f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c19930054826001600160a01b03198216177f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c19930055167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a3565b631e4fbdf760e01b600052600060045260246000fd5b6001600160a01b037f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c19930054163303610ca957565b63118cdaa760e01b6000523360045260246000fd5b60ff7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005460401c1615610ced57565b631afcd79f60e31b60005260046000fdfea164736f6c634300081a000af0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00", + "deployedBytecode": "0x608080604052600436101561001357600080fd5b60003560e01c9081632a8dc588146109b957508063476422f814610952578063485cc9551461074657806370e36bbe146106e3578063715018a61461064a578063770ad208146105e057806381d12c58146105ab5780638da5cb5b146105655780639015d371146105265780639ccb58d5146103cc578063c680f41014610394578063d9bbec9514610170578063dbb06c9314610149578063e82f3b70146100f45763f2fde38b146100c457600080fd5b346100ef5760203660031901126100ef576100ed6100e06109f4565b6100e8610c76565b610bd0565b005b600080fd5b346100ef5760203660031901126100ef57600435600052600360205261011d6040600020610a7c565b805115610138576101349060405191829182610b20565b0390f35b6322e679e360e11b60005260046000fd5b346100ef5760003660031901126100ef5760206001600160a01b0360005416604051908152f35b346100ef5760603660031901126100ef5760043560243567ffffffffffffffff81116100ef576101a4903690600401610b69565b505060443567ffffffffffffffff81116100ef576101c6903690600401610b69565b908260005260026020526001600160a01b0360406000205416330361038357826000526003602052604060002067ffffffffffffffff831161036d5761020c8154610a20565b601f8111610325575b506000601f841160011461029d5791604091847f8d0ca30515bbff1268ae5868080463444e5002373f7bc7d8d8869dca0a5ffc019594600091610292575b508460011b906000198660031b1c19161790555b82825193849260208452816020850152848401376000828201840152601f01601f19168101030190a2005b905082013587610253565b8181526020812090601f198516815b81811061030d57509160409391867f8d0ca30515bbff1268ae5868080463444e5002373f7bc7d8d8869dca0a5ffc01979694106102f3575b5050600184811b019055610267565b830135600019600387901b60f8161c1916905586806102e4565b919260206001819286890135815501940192016102ac565b816000526020600020601f850160051c81019160208610610363575b601f0160051c01905b8181106103575750610215565b6000815560010161034a565b9091508190610341565b634e487b7160e01b600052604160045260246000fd5b632a17a1f360e01b60005260046000fd5b346100ef5760203660031901126100ef5760043560005260036020526101346103c06040600020610a7c565b60405191829182610b20565b346100ef5760803660031901126100ef576004356103e8610a0a565b366084116100ef576001600160a01b03600054163303610515578160005260026020526001600160a01b0360406000205416610504576001600160a01b03168160005260026020526040600020816001600160a01b0319825416179055604051631590527b60e11b815282600482015261046460248201610b97565b6020816064816000865af180156104f8576104bd575b5060607fa17377d4a5c0ff5c67888a6b08d9bf3a8505b47e922b6186b259471ebf12738e916040519081526104b160208201610b97565ba2602060405160018152f35b6020813d6020116104f0575b816104d660209383610a5a565b810103126100ef575180151581036100ef5750606061047a565b3d91506104c9565b6040513d6000823e3d90fd5b6374ff462560e11b60005260046000fd5b63e4c2a7eb60e01b60005260046000fd5b346100ef5760203660031901126100ef576001600160a01b036105476109f4565b166000526001602052602060ff604060002054166040519015158152f35b346100ef5760003660031901126100ef5760206001600160a01b037f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c1993005416604051908152f35b346100ef5760203660031901126100ef57600435600052600260205260206001600160a01b0360406000205416604051908152f35b346100ef5760203660031901126100ef576001600160a01b036106016109f4565b610609610c76565b168060005260016020526040600020600160ff198254161790557f0fdc359cb937ddbe7734e324351ff282307ad333751a9e90f17e7330157ea579600080a2005b346100ef5760003660031901126100ef57610663610c76565b60006001600160a01b037f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300546001600160a01b031981167f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c19930055167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a3005b346100ef5760203660031901126100ef576001600160a01b036107046109f4565b61070c610c76565b16806001600160a01b031960005416176000557f2c8267accd82e977550ed2349c73311183cd22e306347be4453c8d130995e3c9600080a2005b346100ef5760403660031901126100ef5761075f6109f4565b610767610a0a565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00549160ff8360401c16159267ffffffffffffffff81168015908161094a575b6001149081610940575b159081610937575b506109265767ffffffffffffffff1981166001177ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0055610864926001600160a01b0391856108e7575b5061080b610cbe565b610813610cbe565b61081c33610bd0565b610824610c76565b16806001600160a01b031960005416176000557f2c8267accd82e977550ed2349c73311183cd22e306347be4453c8d130995e3c9600080a26100e8610c76565b61086a57005b68ff0000000000000000197ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0054167ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00557fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2602060405160018152a1005b68ffffffffffffffffff191668010000000000000001177ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005585610802565b63f92ee8a960e01b60005260046000fd5b905015856107b9565b303b1591506107b1565b8591506107a7565b346100ef5760203660031901126100ef576001600160a01b036109736109f4565b61097b610c76565b16806000526001602052604060002060ff1981541690557f07f3f62f2502752da9299b12b0a9966cb97ace5e3ce476d04649d5f588ec4491600080a2005b346100ef5760203660031901126100ef576020906001600160a01b036109dd6109f4565b166000526001825260ff6040600020541615158152f35b600435906001600160a01b03821682036100ef57565b602435906001600160a01b03821682036100ef57565b90600182811c92168015610a50575b6020831014610a3a57565b634e487b7160e01b600052602260045260246000fd5b91607f1691610a2f565b90601f8019910116810190811067ffffffffffffffff82111761036d57604052565b9060405191826000825492610a9084610a20565b8084529360018116908115610afe5750600114610ab7575b50610ab592500383610a5a565b565b90506000929192526020600020906000915b818310610ae2575050906020610ab59282010138610aa8565b6020919350806001915483858901015201910190918492610ac9565b905060209250610ab594915060ff191682840152151560051b82010138610aa8565b91909160208152825180602083015260005b818110610b53575060409293506000838284010152601f8019910116010190565b8060208092870101516040828601015201610b32565b9181601f840112156100ef5782359167ffffffffffffffff83116100ef57602083818601950101116100ef57565b60446000915b60028310610baa57505050565b81359063ffffffff82168092036100ef5760208160019382935201920192019190610b9d565b6001600160a01b03168015610c60576001600160a01b037f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c19930054826001600160a01b03198216177f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c19930055167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a3565b631e4fbdf760e01b600052600060045260246000fd5b6001600160a01b037f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c19930054163303610ca957565b63118cdaa760e01b6000523360045260246000fd5b60ff7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005460401c1615610ced57565b631afcd79f60e31b60005260046000fdfea164736f6c634300081a000a", + "devdoc": { + "errors": { + "InvalidInitialization()": [ + { + "details": "The contract is already initialized." + } + ], + "NotInitializing()": [ + { + "details": "The contract is not initializing." + } + ], + "OwnableInvalidOwner(address)": [ + { + "details": "The owner is not a valid owner account. (eg. `address(0)`)" + } + ], + "OwnableUnauthorizedAccount(address)": [ + { + "details": "The caller account is not authorized to perform an operation." + } + ] + }, + "events": { + "CommitteePublished(uint256,bytes)": { + "params": { + "e3Id": "ID of the E3 for which the committee was selected.", + "publicKey": "Public key of the committee." + } + }, + "CommitteeRequested(uint256,address,uint32[2])": { + "params": { + "e3Id": "ID of the E3 for which the committee was selected.", + "filter": "Address of the contract that will coordinate committee selection.", + "threshold": "The M/N threshold for the committee." + } + }, + "EnclaveSet(address)": { + "params": { + "enclave": "Address of the enclave contract." + } + }, + "Initialized(uint64)": { + "details": "Triggered when the contract has been initialized or reinitialized." + } + }, + "kind": "dev", + "methods": { + "committeePublicKey(uint256)": { + "details": "This function MUST revert if no committee has been requested for the given E3.This function MUST revert if the committee has not yet published a public key.", + "params": { + "e3Id": "ID of the E3 for which to get the committee public key." + }, + "returns": { + "publicKey": "The public key of the committee." + } + }, + "owner()": { + "details": "Returns the address of the current owner." + }, + "renounceOwnership()": { + "details": "Leaves the contract without owner. It will not be possible to call `onlyOwner` functions. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby disabling any functionality that is only available to the owner." + }, + "requestCommittee(uint256,address,uint32[2])": { + "details": "This function MUST revert when not called by the Enclave contract.", + "params": { + "e3Id": "ID of the E3 for which to select the committee.", + "filter": "The address of the filter responsible for the committee selection process.", + "threshold": "The M/N threshold for the committee." + }, + "returns": { + "success": "True if committee selection was successfully initiated." + } + }, + "transferOwnership(address)": { + "details": "Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner." + } + }, + "version": 1 + }, + "userdoc": { + "events": { + "CommitteePublished(uint256,bytes)": { + "notice": "This event MUST be emitted when a committee is selected for an E3." + }, + "CommitteeRequested(uint256,address,uint32[2])": { + "notice": "This event MUST be emitted when a committee is selected for an E3." + }, + "CyphernodeAdded(address)": { + "notice": "This event MUST be emitted when a cyphernode is added to the registry." + }, + "CyphernodeRemoved(address)": { + "notice": "This event MUST be emitted when a cyphernode is removed from the registry." + }, + "EnclaveSet(address)": { + "notice": "This event MUST be emitted when `enclave` is set." + } + }, + "kind": "user", + "methods": { + "committeePublicKey(uint256)": { + "notice": "This function should be called by the Enclave contract to get the public key of a committee." + }, + "requestCommittee(uint256,address,uint32[2])": { + "notice": "Initiates the committee selection process for a specified E3." + } + }, + "version": 1 + }, + "storageLayout": { + "storage": [ + { + "astId": 1860, + "contract": "contracts/registry/CyphernodeRegistryOwnable.sol:CyphernodeRegistryOwnable", + "label": "enclave", + "offset": 0, + "slot": "0", + "type": "t_address" + }, + { + "astId": 1864, + "contract": "contracts/registry/CyphernodeRegistryOwnable.sol:CyphernodeRegistryOwnable", + "label": "isEnabled", + "offset": 0, + "slot": "1", + "type": "t_mapping(t_address,t_bool)" + }, + { + "astId": 1869, + "contract": "contracts/registry/CyphernodeRegistryOwnable.sol:CyphernodeRegistryOwnable", + "label": "requests", + "offset": 0, + "slot": "2", + "type": "t_mapping(t_uint256,t_contract(IRegistryFilter)1846)" + }, + { + "astId": 1873, + "contract": "contracts/registry/CyphernodeRegistryOwnable.sol:CyphernodeRegistryOwnable", + "label": "publicKeys", + "offset": 0, + "slot": "3", + "type": "t_mapping(t_uint256,t_bytes_storage)" + } + ], + "types": { + "t_address": { + "encoding": "inplace", + "label": "address", + "numberOfBytes": "20" + }, + "t_bool": { + "encoding": "inplace", + "label": "bool", + "numberOfBytes": "1" + }, + "t_bytes_storage": { + "encoding": "bytes", + "label": "bytes", + "numberOfBytes": "32" + }, + "t_contract(IRegistryFilter)1846": { + "encoding": "inplace", + "label": "contract IRegistryFilter", + "numberOfBytes": "20" + }, + "t_mapping(t_address,t_bool)": { + "encoding": "mapping", + "key": "t_address", + "label": "mapping(address => bool)", + "numberOfBytes": "32", + "value": "t_bool" + }, + "t_mapping(t_uint256,t_bytes_storage)": { + "encoding": "mapping", + "key": "t_uint256", + "label": "mapping(uint256 => bytes)", + "numberOfBytes": "32", + "value": "t_bytes_storage" + }, + "t_mapping(t_uint256,t_contract(IRegistryFilter)1846)": { + "encoding": "mapping", + "key": "t_uint256", + "label": "mapping(uint256 => contract IRegistryFilter)", + "numberOfBytes": "32", + "value": "t_contract(IRegistryFilter)1846" + }, + "t_uint256": { + "encoding": "inplace", + "label": "uint256", + "numberOfBytes": "32" + } + } + } +} diff --git a/packages/evm/deployments/sepolia/Enclave.json b/packages/evm/deployments/sepolia/Enclave.json new file mode 100644 index 00000000..389e0b3f --- /dev/null +++ b/packages/evm/deployments/sepolia/Enclave.json @@ -0,0 +1,1757 @@ +{ + "address": "0x083b0AE25fD41469Fd8857027B40e3f49A169375", + "abi": [ + { + "inputs": [ + { + "internalType": "address", + "name": "_owner", + "type": "address" + }, + { + "internalType": "contract ICyphernodeRegistry", + "name": "_cyphernodeRegistry", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_maxDuration", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "e3Id", + "type": "uint256" + } + ], + "name": "CiphertextOutputAlreadyPublished", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "e3Id", + "type": "uint256" + } + ], + "name": "CiphertextOutputNotPublished", + "type": "error" + }, + { + "inputs": [], + "name": "CommitteeSelectionFailed", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "contract IComputationModule", + "name": "computationModule", + "type": "address" + } + ], + "name": "ComputationModuleNotAllowed", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "e3Id", + "type": "uint256" + } + ], + "name": "E3AlreadyActivated", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "e3Id", + "type": "uint256" + } + ], + "name": "E3DoesNotExist", + "type": "error" + }, + { + "inputs": [], + "name": "E3Expired", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "e3Id", + "type": "uint256" + } + ], + "name": "E3NotActivated", + "type": "error" + }, + { + "inputs": [], + "name": "E3NotReady", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "e3Id", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "expiration", + "type": "uint256" + } + ], + "name": "InputDeadlineNotPassed", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "e3Id", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "expiration", + "type": "uint256" + } + ], + "name": "InputDeadlinePassed", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidComputation", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "contract ICyphernodeRegistry", + "name": "cyphernodeRegistry", + "type": "address" + } + ], + "name": "InvalidCyphernodeRegistry", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "duration", + "type": "uint256" + } + ], + "name": "InvalidDuration", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidExecutionModuleSetup", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidInitialization", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidInput", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "output", + "type": "bytes" + } + ], + "name": "InvalidOutput", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidStartWindow", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint32[2]", + "name": "threshold", + "type": "uint32[2]" + } + ], + "name": "InvalidThreshold", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "module", + "type": "address" + } + ], + "name": "ModuleAlreadyEnabled", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "module", + "type": "address" + } + ], + "name": "ModuleNotEnabled", + "type": "error" + }, + { + "inputs": [], + "name": "NotInitializing", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "OwnableInvalidOwner", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "OwnableUnauthorizedAccount", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "PaymentRequired", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "e3Id", + "type": "uint256" + } + ], + "name": "PlaintextOutputAlreadyPublished", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "e3Id", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "ciphertextOutput", + "type": "bytes" + } + ], + "name": "CiphertextOutputPublished", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "contract IComputationModule", + "name": "computationModule", + "type": "address" + } + ], + "name": "ComputationModuleDisabled", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "contract IComputationModule", + "name": "computationModule", + "type": "address" + } + ], + "name": "ComputationModuleEnabled", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "cyphernodeRegistry", + "type": "address" + } + ], + "name": "CyphernodeRegistrySet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "e3Id", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "expiration", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "committeePublicKey", + "type": "bytes" + } + ], + "name": "E3Activated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "e3Id", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "uint32[2]", + "name": "threshold", + "type": "uint32[2]" + }, + { + "internalType": "uint256[2]", + "name": "startWindow", + "type": "uint256[2]" + }, + { + "internalType": "uint256", + "name": "duration", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "expiration", + "type": "uint256" + }, + { + "internalType": "contract IComputationModule", + "name": "computationModule", + "type": "address" + }, + { + "internalType": "contract IExecutionModule", + "name": "executionModule", + "type": "address" + }, + { + "internalType": "contract IInputValidator", + "name": "inputValidator", + "type": "address" + }, + { + "internalType": "contract IOutputVerifier", + "name": "outputVerifier", + "type": "address" + }, + { + "internalType": "bytes", + "name": "committeePublicKey", + "type": "bytes" + }, + { + "internalType": "bytes[]", + "name": "inputs", + "type": "bytes[]" + }, + { + "internalType": "bytes", + "name": "ciphertextOutput", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "plaintextOutput", + "type": "bytes" + } + ], + "indexed": false, + "internalType": "struct E3", + "name": "e3", + "type": "tuple" + }, + { + "indexed": false, + "internalType": "address", + "name": "filter", + "type": "address" + }, + { + "indexed": true, + "internalType": "contract IComputationModule", + "name": "computationModule", + "type": "address" + }, + { + "indexed": true, + "internalType": "contract IExecutionModule", + "name": "executionModule", + "type": "address" + } + ], + "name": "E3Requested", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "contract IExecutionModule", + "name": "executionModule", + "type": "address" + } + ], + "name": "ExecutionModuleDisabled", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "contract IExecutionModule", + "name": "executionModule", + "type": "address" + } + ], + "name": "ExecutionModuleEnabled", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint64", + "name": "version", + "type": "uint64" + } + ], + "name": "Initialized", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "e3Id", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "InputPublished", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "maxDuration", + "type": "uint256" + } + ], + "name": "MaxDurationSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "e3Id", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "plaintextOutput", + "type": "bytes" + } + ], + "name": "PlaintextOutputPublished", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "e3Id", + "type": "uint256" + } + ], + "name": "activate", + "outputs": [ + { + "internalType": "bool", + "name": "success", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IComputationModule", + "name": "computationModule", + "type": "address" + } + ], + "name": "computationModules", + "outputs": [ + { + "internalType": "bool", + "name": "allowed", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "cyphernodeRegistry", + "outputs": [ + { + "internalType": "contract ICyphernodeRegistry", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IComputationModule", + "name": "computationModule", + "type": "address" + } + ], + "name": "disableComputationModule", + "outputs": [ + { + "internalType": "bool", + "name": "success", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IExecutionModule", + "name": "executionModule", + "type": "address" + } + ], + "name": "disableExecutionModule", + "outputs": [ + { + "internalType": "bool", + "name": "success", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "id", + "type": "uint256" + } + ], + "name": "e3s", + "outputs": [ + { + "internalType": "uint256", + "name": "duration", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "expiration", + "type": "uint256" + }, + { + "internalType": "contract IComputationModule", + "name": "computationModule", + "type": "address" + }, + { + "internalType": "contract IExecutionModule", + "name": "executionModule", + "type": "address" + }, + { + "internalType": "contract IInputValidator", + "name": "inputValidator", + "type": "address" + }, + { + "internalType": "contract IOutputVerifier", + "name": "outputVerifier", + "type": "address" + }, + { + "internalType": "bytes", + "name": "committeePublicKey", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "ciphertextOutput", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "plaintextOutput", + "type": "bytes" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IComputationModule", + "name": "computationModule", + "type": "address" + } + ], + "name": "enableComputationModule", + "outputs": [ + { + "internalType": "bool", + "name": "success", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IExecutionModule", + "name": "executionModule", + "type": "address" + } + ], + "name": "enableExecutionModule", + "outputs": [ + { + "internalType": "bool", + "name": "success", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IExecutionModule", + "name": "executionModule", + "type": "address" + } + ], + "name": "executionModules", + "outputs": [ + { + "internalType": "bool", + "name": "allowed", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "e3Id", + "type": "uint256" + } + ], + "name": "getE3", + "outputs": [ + { + "components": [ + { + "internalType": "uint32[2]", + "name": "threshold", + "type": "uint32[2]" + }, + { + "internalType": "uint256[2]", + "name": "startWindow", + "type": "uint256[2]" + }, + { + "internalType": "uint256", + "name": "duration", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "expiration", + "type": "uint256" + }, + { + "internalType": "contract IComputationModule", + "name": "computationModule", + "type": "address" + }, + { + "internalType": "contract IExecutionModule", + "name": "executionModule", + "type": "address" + }, + { + "internalType": "contract IInputValidator", + "name": "inputValidator", + "type": "address" + }, + { + "internalType": "contract IOutputVerifier", + "name": "outputVerifier", + "type": "address" + }, + { + "internalType": "bytes", + "name": "committeePublicKey", + "type": "bytes" + }, + { + "internalType": "bytes[]", + "name": "inputs", + "type": "bytes[]" + }, + { + "internalType": "bytes", + "name": "ciphertextOutput", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "plaintextOutput", + "type": "bytes" + } + ], + "internalType": "struct E3", + "name": "e3", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_owner", + "type": "address" + }, + { + "internalType": "contract ICyphernodeRegistry", + "name": "_cyphernodeRegistry", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_maxDuration", + "type": "uint256" + } + ], + "name": "initialize", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "maxDuration", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "nexte3Id", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "e3Id", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "publishCiphertextOutput", + "outputs": [ + { + "internalType": "bool", + "name": "success", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "e3Id", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "publishInput", + "outputs": [ + { + "internalType": "bool", + "name": "success", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "e3Id", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "publishPlaintextOutput", + "outputs": [ + { + "internalType": "bool", + "name": "success", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "renounceOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "filter", + "type": "address" + }, + { + "internalType": "uint32[2]", + "name": "threshold", + "type": "uint32[2]" + }, + { + "internalType": "uint256[2]", + "name": "startWindow", + "type": "uint256[2]" + }, + { + "internalType": "uint256", + "name": "duration", + "type": "uint256" + }, + { + "internalType": "contract IComputationModule", + "name": "computationModule", + "type": "address" + }, + { + "internalType": "bytes", + "name": "computationParams", + "type": "bytes" + }, + { + "internalType": "contract IExecutionModule", + "name": "executionModule", + "type": "address" + }, + { + "internalType": "bytes", + "name": "emParams", + "type": "bytes" + } + ], + "name": "request", + "outputs": [ + { + "internalType": "uint256", + "name": "e3Id", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "uint32[2]", + "name": "threshold", + "type": "uint32[2]" + }, + { + "internalType": "uint256[2]", + "name": "startWindow", + "type": "uint256[2]" + }, + { + "internalType": "uint256", + "name": "duration", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "expiration", + "type": "uint256" + }, + { + "internalType": "contract IComputationModule", + "name": "computationModule", + "type": "address" + }, + { + "internalType": "contract IExecutionModule", + "name": "executionModule", + "type": "address" + }, + { + "internalType": "contract IInputValidator", + "name": "inputValidator", + "type": "address" + }, + { + "internalType": "contract IOutputVerifier", + "name": "outputVerifier", + "type": "address" + }, + { + "internalType": "bytes", + "name": "committeePublicKey", + "type": "bytes" + }, + { + "internalType": "bytes[]", + "name": "inputs", + "type": "bytes[]" + }, + { + "internalType": "bytes", + "name": "ciphertextOutput", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "plaintextOutput", + "type": "bytes" + } + ], + "internalType": "struct E3", + "name": "e3", + "type": "tuple" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [], + "name": "requests", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract ICyphernodeRegistry", + "name": "_cyphernodeRegistry", + "type": "address" + } + ], + "name": "setCyphernodeRegistry", + "outputs": [ + { + "internalType": "bool", + "name": "success", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_maxDuration", + "type": "uint256" + } + ], + "name": "setMaxDuration", + "outputs": [ + { + "internalType": "bool", + "name": "success", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } + ], + "transactionHash": "0x2e2dae8a05e34e82484cfaec005240ec707a4c0c6b6a4f6bcf8fb0f45c0c5b6f", + "receipt": { + "to": null, + "from": "0x485E60C486671E932fd9C53d4110cdEab1E7F0eb", + "contractAddress": "0x083b0AE25fD41469Fd8857027B40e3f49A169375", + "transactionIndex": 286, + "gasUsed": "2071049", + "logsBloom": "0x00000000000000000000000000000100000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000100000000000000000020000000000000000000800000000000000200000000800000000400000000008000000000800000000000000000000000880000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002004000000000000000020000000000000000000020000000001200000000800000000000000000000000000", + "blockHash": "0x516557b80e512cc5ad78bd83f7668e4d4f1dc08eb95582806d98fb0569c0517b", + "transactionHash": "0x2e2dae8a05e34e82484cfaec005240ec707a4c0c6b6a4f6bcf8fb0f45c0c5b6f", + "logs": [ + { + "transactionIndex": 286, + "blockNumber": 6662691, + "transactionHash": "0x2e2dae8a05e34e82484cfaec005240ec707a4c0c6b6a4f6bcf8fb0f45c0c5b6f", + "address": "0x083b0AE25fD41469Fd8857027B40e3f49A169375", + "topics": [ + "0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x000000000000000000000000485e60c486671e932fd9c53d4110cdeab1e7f0eb" + ], + "data": "0x", + "logIndex": 369, + "blockHash": "0x516557b80e512cc5ad78bd83f7668e4d4f1dc08eb95582806d98fb0569c0517b" + }, + { + "transactionIndex": 286, + "blockNumber": 6662691, + "transactionHash": "0x2e2dae8a05e34e82484cfaec005240ec707a4c0c6b6a4f6bcf8fb0f45c0c5b6f", + "address": "0x083b0AE25fD41469Fd8857027B40e3f49A169375", + "topics": [ + "0xba0716ba1ee2ea8ecc4c64119b4537cdb42a99d82acf92af5b87607b8b523552" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000000278d00", + "logIndex": 370, + "blockHash": "0x516557b80e512cc5ad78bd83f7668e4d4f1dc08eb95582806d98fb0569c0517b" + }, + { + "transactionIndex": 286, + "blockNumber": 6662691, + "transactionHash": "0x2e2dae8a05e34e82484cfaec005240ec707a4c0c6b6a4f6bcf8fb0f45c0c5b6f", + "address": "0x083b0AE25fD41469Fd8857027B40e3f49A169375", + "topics": [ + "0x016ea868599173c3163f65dea5e4677b2be5f0ececb4ec15d1166a27de35a533" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000000000001", + "logIndex": 371, + "blockHash": "0x516557b80e512cc5ad78bd83f7668e4d4f1dc08eb95582806d98fb0569c0517b" + }, + { + "transactionIndex": 286, + "blockNumber": 6662691, + "transactionHash": "0x2e2dae8a05e34e82484cfaec005240ec707a4c0c6b6a4f6bcf8fb0f45c0c5b6f", + "address": "0x083b0AE25fD41469Fd8857027B40e3f49A169375", + "topics": [ + "0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000000000001", + "logIndex": 372, + "blockHash": "0x516557b80e512cc5ad78bd83f7668e4d4f1dc08eb95582806d98fb0569c0517b" + } + ], + "blockNumber": 6662691, + "cumulativeGasUsed": "25038564", + "status": 1, + "byzantium": true + }, + "args": [ + "0x485E60C486671E932fd9C53d4110cdEab1E7F0eb", + "0x0000000000000000000000000000000000000001", + 2592000 + ], + "numDeployments": 1, + "solcInputHash": "d0e6e4f19028714f394c36db62dff2be", + "metadata": "{\"compiler\":{\"version\":\"0.8.26+commit.8a97fa7a\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"},{\"internalType\":\"contract ICyphernodeRegistry\",\"name\":\"_cyphernodeRegistry\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_maxDuration\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"e3Id\",\"type\":\"uint256\"}],\"name\":\"CiphertextOutputAlreadyPublished\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"e3Id\",\"type\":\"uint256\"}],\"name\":\"CiphertextOutputNotPublished\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CommitteeSelectionFailed\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"contract IComputationModule\",\"name\":\"computationModule\",\"type\":\"address\"}],\"name\":\"ComputationModuleNotAllowed\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"e3Id\",\"type\":\"uint256\"}],\"name\":\"E3AlreadyActivated\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"e3Id\",\"type\":\"uint256\"}],\"name\":\"E3DoesNotExist\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"E3Expired\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"e3Id\",\"type\":\"uint256\"}],\"name\":\"E3NotActivated\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"E3NotReady\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"e3Id\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"expiration\",\"type\":\"uint256\"}],\"name\":\"InputDeadlineNotPassed\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"e3Id\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"expiration\",\"type\":\"uint256\"}],\"name\":\"InputDeadlinePassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidComputation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"contract ICyphernodeRegistry\",\"name\":\"cyphernodeRegistry\",\"type\":\"address\"}],\"name\":\"InvalidCyphernodeRegistry\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"duration\",\"type\":\"uint256\"}],\"name\":\"InvalidDuration\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidExecutionModuleSetup\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidInitialization\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidInput\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"output\",\"type\":\"bytes\"}],\"name\":\"InvalidOutput\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidStartWindow\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint32[2]\",\"name\":\"threshold\",\"type\":\"uint32[2]\"}],\"name\":\"InvalidThreshold\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"module\",\"type\":\"address\"}],\"name\":\"ModuleAlreadyEnabled\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"module\",\"type\":\"address\"}],\"name\":\"ModuleNotEnabled\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotInitializing\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"OwnableInvalidOwner\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"OwnableUnauthorizedAccount\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"PaymentRequired\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"e3Id\",\"type\":\"uint256\"}],\"name\":\"PlaintextOutputAlreadyPublished\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"e3Id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"ciphertextOutput\",\"type\":\"bytes\"}],\"name\":\"CiphertextOutputPublished\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"contract IComputationModule\",\"name\":\"computationModule\",\"type\":\"address\"}],\"name\":\"ComputationModuleDisabled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"contract IComputationModule\",\"name\":\"computationModule\",\"type\":\"address\"}],\"name\":\"ComputationModuleEnabled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"cyphernodeRegistry\",\"type\":\"address\"}],\"name\":\"CyphernodeRegistrySet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"e3Id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"expiration\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"committeePublicKey\",\"type\":\"bytes\"}],\"name\":\"E3Activated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"e3Id\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"uint32[2]\",\"name\":\"threshold\",\"type\":\"uint32[2]\"},{\"internalType\":\"uint256[2]\",\"name\":\"startWindow\",\"type\":\"uint256[2]\"},{\"internalType\":\"uint256\",\"name\":\"duration\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"expiration\",\"type\":\"uint256\"},{\"internalType\":\"contract IComputationModule\",\"name\":\"computationModule\",\"type\":\"address\"},{\"internalType\":\"contract IExecutionModule\",\"name\":\"executionModule\",\"type\":\"address\"},{\"internalType\":\"contract IInputValidator\",\"name\":\"inputValidator\",\"type\":\"address\"},{\"internalType\":\"contract IOutputVerifier\",\"name\":\"outputVerifier\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"committeePublicKey\",\"type\":\"bytes\"},{\"internalType\":\"bytes[]\",\"name\":\"inputs\",\"type\":\"bytes[]\"},{\"internalType\":\"bytes\",\"name\":\"ciphertextOutput\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"plaintextOutput\",\"type\":\"bytes\"}],\"indexed\":false,\"internalType\":\"struct E3\",\"name\":\"e3\",\"type\":\"tuple\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"filter\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"contract IComputationModule\",\"name\":\"computationModule\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"contract IExecutionModule\",\"name\":\"executionModule\",\"type\":\"address\"}],\"name\":\"E3Requested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"contract IExecutionModule\",\"name\":\"executionModule\",\"type\":\"address\"}],\"name\":\"ExecutionModuleDisabled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"contract IExecutionModule\",\"name\":\"executionModule\",\"type\":\"address\"}],\"name\":\"ExecutionModuleEnabled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"version\",\"type\":\"uint64\"}],\"name\":\"Initialized\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"e3Id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"InputPublished\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"maxDuration\",\"type\":\"uint256\"}],\"name\":\"MaxDurationSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"e3Id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"plaintextOutput\",\"type\":\"bytes\"}],\"name\":\"PlaintextOutputPublished\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"e3Id\",\"type\":\"uint256\"}],\"name\":\"activate\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract IComputationModule\",\"name\":\"computationModule\",\"type\":\"address\"}],\"name\":\"computationModules\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"allowed\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"cyphernodeRegistry\",\"outputs\":[{\"internalType\":\"contract ICyphernodeRegistry\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract IComputationModule\",\"name\":\"computationModule\",\"type\":\"address\"}],\"name\":\"disableComputationModule\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract IExecutionModule\",\"name\":\"executionModule\",\"type\":\"address\"}],\"name\":\"disableExecutionModule\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"e3s\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"duration\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"expiration\",\"type\":\"uint256\"},{\"internalType\":\"contract IComputationModule\",\"name\":\"computationModule\",\"type\":\"address\"},{\"internalType\":\"contract IExecutionModule\",\"name\":\"executionModule\",\"type\":\"address\"},{\"internalType\":\"contract IInputValidator\",\"name\":\"inputValidator\",\"type\":\"address\"},{\"internalType\":\"contract IOutputVerifier\",\"name\":\"outputVerifier\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"committeePublicKey\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"ciphertextOutput\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"plaintextOutput\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract IComputationModule\",\"name\":\"computationModule\",\"type\":\"address\"}],\"name\":\"enableComputationModule\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract IExecutionModule\",\"name\":\"executionModule\",\"type\":\"address\"}],\"name\":\"enableExecutionModule\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract IExecutionModule\",\"name\":\"executionModule\",\"type\":\"address\"}],\"name\":\"executionModules\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"allowed\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"e3Id\",\"type\":\"uint256\"}],\"name\":\"getE3\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32[2]\",\"name\":\"threshold\",\"type\":\"uint32[2]\"},{\"internalType\":\"uint256[2]\",\"name\":\"startWindow\",\"type\":\"uint256[2]\"},{\"internalType\":\"uint256\",\"name\":\"duration\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"expiration\",\"type\":\"uint256\"},{\"internalType\":\"contract IComputationModule\",\"name\":\"computationModule\",\"type\":\"address\"},{\"internalType\":\"contract IExecutionModule\",\"name\":\"executionModule\",\"type\":\"address\"},{\"internalType\":\"contract IInputValidator\",\"name\":\"inputValidator\",\"type\":\"address\"},{\"internalType\":\"contract IOutputVerifier\",\"name\":\"outputVerifier\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"committeePublicKey\",\"type\":\"bytes\"},{\"internalType\":\"bytes[]\",\"name\":\"inputs\",\"type\":\"bytes[]\"},{\"internalType\":\"bytes\",\"name\":\"ciphertextOutput\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"plaintextOutput\",\"type\":\"bytes\"}],\"internalType\":\"struct E3\",\"name\":\"e3\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"},{\"internalType\":\"contract ICyphernodeRegistry\",\"name\":\"_cyphernodeRegistry\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_maxDuration\",\"type\":\"uint256\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"maxDuration\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"nexte3Id\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"e3Id\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"publishCiphertextOutput\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"e3Id\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"publishInput\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"e3Id\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"publishPlaintextOutput\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"filter\",\"type\":\"address\"},{\"internalType\":\"uint32[2]\",\"name\":\"threshold\",\"type\":\"uint32[2]\"},{\"internalType\":\"uint256[2]\",\"name\":\"startWindow\",\"type\":\"uint256[2]\"},{\"internalType\":\"uint256\",\"name\":\"duration\",\"type\":\"uint256\"},{\"internalType\":\"contract IComputationModule\",\"name\":\"computationModule\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"computationParams\",\"type\":\"bytes\"},{\"internalType\":\"contract IExecutionModule\",\"name\":\"executionModule\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"emParams\",\"type\":\"bytes\"}],\"name\":\"request\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"e3Id\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"uint32[2]\",\"name\":\"threshold\",\"type\":\"uint32[2]\"},{\"internalType\":\"uint256[2]\",\"name\":\"startWindow\",\"type\":\"uint256[2]\"},{\"internalType\":\"uint256\",\"name\":\"duration\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"expiration\",\"type\":\"uint256\"},{\"internalType\":\"contract IComputationModule\",\"name\":\"computationModule\",\"type\":\"address\"},{\"internalType\":\"contract IExecutionModule\",\"name\":\"executionModule\",\"type\":\"address\"},{\"internalType\":\"contract IInputValidator\",\"name\":\"inputValidator\",\"type\":\"address\"},{\"internalType\":\"contract IOutputVerifier\",\"name\":\"outputVerifier\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"committeePublicKey\",\"type\":\"bytes\"},{\"internalType\":\"bytes[]\",\"name\":\"inputs\",\"type\":\"bytes[]\"},{\"internalType\":\"bytes\",\"name\":\"ciphertextOutput\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"plaintextOutput\",\"type\":\"bytes\"}],\"internalType\":\"struct E3\",\"name\":\"e3\",\"type\":\"tuple\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"requests\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract ICyphernodeRegistry\",\"name\":\"_cyphernodeRegistry\",\"type\":\"address\"}],\"name\":\"setCyphernodeRegistry\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_maxDuration\",\"type\":\"uint256\"}],\"name\":\"setMaxDuration\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"errors\":{\"InvalidInitialization()\":[{\"details\":\"The contract is already initialized.\"}],\"NotInitializing()\":[{\"details\":\"The contract is not initializing.\"}],\"OwnableInvalidOwner(address)\":[{\"details\":\"The owner is not a valid owner account. (eg. `address(0)`)\"}],\"OwnableUnauthorizedAccount(address)\":[{\"details\":\"The caller account is not authorized to perform an operation.\"}]},\"events\":{\"CiphertextOutputPublished(uint256,bytes)\":{\"params\":{\"ciphertextOutput\":\"ABI encoded ciphertext output.\",\"e3Id\":\"ID of the E3.\"}},\"ComputationModuleDisabled(address)\":{\"params\":{\"computationModule\":\"The address of the computation module.\"}},\"ComputationModuleEnabled(address)\":{\"params\":{\"computationModule\":\"The address of the computation module.\"}},\"CyphernodeRegistrySet(address)\":{\"params\":{\"cyphernodeRegistry\":\"The address of the CyphernodeRegistry contract.\"}},\"E3Activated(uint256,uint256,bytes)\":{\"params\":{\"committeePublicKey\":\"Public key of the committee.\",\"e3Id\":\"ID of the E3.\",\"expiration\":\"Timestamp when committee duties expire.\"}},\"E3Requested(uint256,(uint32[2],uint256[2],uint256,uint256,address,address,address,address,bytes,bytes[],bytes,bytes),address,address,address)\":{\"params\":{\"computationModule\":\"Address of the Computation module selected.\",\"e3\":\"Details of the E3.\",\"e3Id\":\"ID of the E3.\",\"executionModule\":\"Address of the execution module selected.\",\"filter\":\"Address of the pool of nodes from which the Cypher Node committee was selected.\"}},\"ExecutionModuleDisabled(address)\":{\"params\":{\"executionModule\":\"The address of the execution module.\"}},\"ExecutionModuleEnabled(address)\":{\"params\":{\"executionModule\":\"The address of the execution module.\"}},\"Initialized(uint64)\":{\"details\":\"Triggered when the contract has been initialized or reinitialized.\"},\"InputPublished(uint256,bytes)\":{\"params\":{\"data\":\"ABI encoded input data.\",\"e3Id\":\"ID of the E3.\"}},\"MaxDurationSet(uint256)\":{\"params\":{\"maxDuration\":\"The maximum duration of a computation in seconds.\"}},\"PlaintextOutputPublished(uint256,bytes)\":{\"params\":{\"e3Id\":\"ID of the E3.\",\"plaintextOutput\":\"ABI encoded plaintext output.\"}}},\"kind\":\"dev\",\"methods\":{\"activate(uint256)\":{\"details\":\"This function MUST emit the E3Activated event.This function MUST revert if the given E3 has not yet been requested.This function MUST revert if the selected node committee has not yet published a public key.\",\"params\":{\"e3Id\":\"ID of the E3.\"}},\"constructor\":{\"params\":{\"_maxDuration\":\"The maximum duration of a computation in seconds\",\"_owner\":\"The owner of this contract\"}},\"getE3(uint256)\":{\"details\":\"This function MUST revert if the E3 does not exist.\",\"params\":{\"e3Id\":\"ID of the E3.\"},\"returns\":{\"e3\":\"The struct representing the requested E3.\"}},\"initialize(address,address,uint256)\":{\"params\":{\"_maxDuration\":\"The maximum duration of a computation in seconds\",\"_owner\":\"The owner of this contract\"}},\"owner()\":{\"details\":\"Returns the address of the current owner.\"},\"publishCiphertextOutput(uint256,bytes)\":{\"details\":\"This function MUST emit the CiphertextOutputPublished event.\",\"params\":{\"data\":\"ABI encoded output data to verify.\",\"e3Id\":\"ID of the E3.\"},\"returns\":{\"success\":\"True if the output was successfully published.\"}},\"publishInput(uint256,bytes)\":{\"details\":\"This function MUST revert if the E3 is not yet activated.This function MUST emit the InputPublished event.\",\"params\":{\"data\":\"ABI encoded input data to publish.\",\"e3Id\":\"ID of the E3.\"},\"returns\":{\"success\":\"True if the input was successfully published.\"}},\"publishPlaintextOutput(uint256,bytes)\":{\"details\":\"This function MUST revert if the output has not been published.This function MUST emit the PlaintextOutputPublished event.\",\"params\":{\"data\":\"ABI encoded output data to decrypt.\",\"e3Id\":\"ID of the E3.\"},\"returns\":{\"success\":\"True if the output was successfully decrypted.\"}},\"renounceOwnership()\":{\"details\":\"Leaves the contract without owner. It will not be possible to call `onlyOwner` functions. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby disabling any functionality that is only available to the owner.\"},\"request(address,uint32[2],uint256[2],uint256,address,bytes,address,bytes)\":{\"details\":\"This function MUST emit the E3Requested event.\",\"params\":{\"computationModule\":\"Address of the computation module.\",\"computationParams\":\"ABI encoded computation parameters.\",\"duration\":\"The duration of the computation in seconds.\",\"emParams\":\"ABI encoded execution module parameters.\",\"executionModule\":\"Address of the execution module.\",\"filter\":\"IDs of the pool of nodes from which to select the committee.\",\"threshold\":\"The M/N threshold for the committee.\"},\"returns\":{\"e3\":\"The E3 struct.\",\"e3Id\":\"ID of the E3.\"}},\"setMaxDuration(uint256)\":{\"params\":{\"_maxDuration\":\"The maximum duration of a computation in seconds.\"},\"returns\":{\"success\":\"True if the max duration was successfully set.\"}},\"transferOwnership(address)\":{\"details\":\"Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.\"}},\"version\":1},\"userdoc\":{\"events\":{\"CiphertextOutputPublished(uint256,bytes)\":{\"notice\":\"This event MUST be emitted when the ciphertext output of an Encrypted Execution Environment (E3) is successfully published.\"},\"ComputationModuleDisabled(address)\":{\"notice\":\"This event MUST be emitted any time a computation module is disabled.\"},\"ComputationModuleEnabled(address)\":{\"notice\":\"This event MUST be emitted any time a computation module is enabled.\"},\"CyphernodeRegistrySet(address)\":{\"notice\":\"This event MUST be emitted any time the CyphernodeRegistry is set.\"},\"E3Activated(uint256,uint256,bytes)\":{\"notice\":\"This event MUST be emitted when an Encrypted Execution Environment (E3) is successfully activated.\"},\"E3Requested(uint256,(uint32[2],uint256[2],uint256,uint256,address,address,address,address,bytes,bytes[],bytes,bytes),address,address,address)\":{\"notice\":\"This event MUST be emitted when an Encrypted Execution Environment (E3) is successfully requested.\"},\"ExecutionModuleDisabled(address)\":{\"notice\":\"This event MUST be emitted any time an execution module is disabled.\"},\"ExecutionModuleEnabled(address)\":{\"notice\":\"This event MUST be emitted any time an execution module is enabled.\"},\"InputPublished(uint256,bytes)\":{\"notice\":\"This event MUST be emitted when an input to an Encrypted Execution Environment (E3) is successfully published.\"},\"MaxDurationSet(uint256)\":{\"notice\":\"This event MUST be emitted any time the `maxDuration` is set.\"},\"PlaintextOutputPublished(uint256,bytes)\":{\"notice\":\"This event MUST be emitted when the plaintext output of an Encrypted Execution Environment (E3) is successfully published.\"}},\"kind\":\"user\",\"methods\":{\"activate(uint256)\":{\"notice\":\"This function should be called to activate an Encrypted Execution Environment (E3) once it has been initialized and is ready for input.\"},\"getE3(uint256)\":{\"notice\":\"This function should be called to retrieve the details of an Encrypted Execution Environment (E3).\"},\"publishCiphertextOutput(uint256,bytes)\":{\"notice\":\"This function should be called to publish output data for an Encrypted Execution Environment (E3).\"},\"publishInput(uint256,bytes)\":{\"notice\":\"This function should be called to publish input data for Encrypted Execution Environment (E3).\"},\"publishPlaintextOutput(uint256,bytes)\":{\"notice\":\"This function publishes the plaintext output of an Encrypted Execution Environment (E3).\"},\"request(address,uint32[2],uint256[2],uint256,address,bytes,address,bytes)\":{\"notice\":\"This function should be called to request a computation within an Encrypted Execution Environment (E3).\"},\"setMaxDuration(uint256)\":{\"notice\":\"This function should be called to set the maximum duration of requested computations.\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/Enclave.sol\":\"Enclave\"},\"evmVersion\":\"paris\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"none\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":800},\"remappings\":[],\"viaIR\":true},\"sources\":{\"@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)\\n\\npragma solidity ^0.8.20;\\n\\nimport {ContextUpgradeable} from \\\"../utils/ContextUpgradeable.sol\\\";\\nimport {Initializable} from \\\"../proxy/utils/Initializable.sol\\\";\\n\\n/**\\n * @dev Contract module which provides a basic access control mechanism, where\\n * there is an account (an owner) that can be granted exclusive access to\\n * specific functions.\\n *\\n * The initial owner is set to the address provided by the deployer. This can\\n * later be changed with {transferOwnership}.\\n *\\n * This module is used through inheritance. It will make available the modifier\\n * `onlyOwner`, which can be applied to your functions to restrict their use to\\n * the owner.\\n */\\nabstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {\\n /// @custom:storage-location erc7201:openzeppelin.storage.Ownable\\n struct OwnableStorage {\\n address _owner;\\n }\\n\\n // keccak256(abi.encode(uint256(keccak256(\\\"openzeppelin.storage.Ownable\\\")) - 1)) & ~bytes32(uint256(0xff))\\n bytes32 private constant OwnableStorageLocation = 0x9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300;\\n\\n function _getOwnableStorage() private pure returns (OwnableStorage storage $) {\\n assembly {\\n $.slot := OwnableStorageLocation\\n }\\n }\\n\\n /**\\n * @dev The caller account is not authorized to perform an operation.\\n */\\n error OwnableUnauthorizedAccount(address account);\\n\\n /**\\n * @dev The owner is not a valid owner account. (eg. `address(0)`)\\n */\\n error OwnableInvalidOwner(address owner);\\n\\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\\n\\n /**\\n * @dev Initializes the contract setting the address provided by the deployer as the initial owner.\\n */\\n function __Ownable_init(address initialOwner) internal onlyInitializing {\\n __Ownable_init_unchained(initialOwner);\\n }\\n\\n function __Ownable_init_unchained(address initialOwner) internal onlyInitializing {\\n if (initialOwner == address(0)) {\\n revert OwnableInvalidOwner(address(0));\\n }\\n _transferOwnership(initialOwner);\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the owner.\\n */\\n modifier onlyOwner() {\\n _checkOwner();\\n _;\\n }\\n\\n /**\\n * @dev Returns the address of the current owner.\\n */\\n function owner() public view virtual returns (address) {\\n OwnableStorage storage $ = _getOwnableStorage();\\n return $._owner;\\n }\\n\\n /**\\n * @dev Throws if the sender is not the owner.\\n */\\n function _checkOwner() internal view virtual {\\n if (owner() != _msgSender()) {\\n revert OwnableUnauthorizedAccount(_msgSender());\\n }\\n }\\n\\n /**\\n * @dev Leaves the contract without owner. It will not be possible to call\\n * `onlyOwner` functions. Can only be called by the current owner.\\n *\\n * NOTE: Renouncing ownership will leave the contract without an owner,\\n * thereby disabling any functionality that is only available to the owner.\\n */\\n function renounceOwnership() public virtual onlyOwner {\\n _transferOwnership(address(0));\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Can only be called by the current owner.\\n */\\n function transferOwnership(address newOwner) public virtual onlyOwner {\\n if (newOwner == address(0)) {\\n revert OwnableInvalidOwner(address(0));\\n }\\n _transferOwnership(newOwner);\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Internal function without access restriction.\\n */\\n function _transferOwnership(address newOwner) internal virtual {\\n OwnableStorage storage $ = _getOwnableStorage();\\n address oldOwner = $._owner;\\n $._owner = newOwner;\\n emit OwnershipTransferred(oldOwner, newOwner);\\n }\\n}\\n\",\"keccak256\":\"0xc163fcf9bb10138631a9ba5564df1fa25db9adff73bd9ee868a8ae1858fe093a\",\"license\":\"MIT\"},\"@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/Initializable.sol)\\n\\npragma solidity ^0.8.20;\\n\\n/**\\n * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed\\n * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an\\n * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer\\n * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.\\n *\\n * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be\\n * reused. This mechanism prevents re-execution of each \\\"step\\\" but allows the creation of new initialization steps in\\n * case an upgrade adds a module that needs to be initialized.\\n *\\n * For example:\\n *\\n * [.hljs-theme-light.nopadding]\\n * ```solidity\\n * contract MyToken is ERC20Upgradeable {\\n * function initialize() initializer public {\\n * __ERC20_init(\\\"MyToken\\\", \\\"MTK\\\");\\n * }\\n * }\\n *\\n * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {\\n * function initializeV2() reinitializer(2) public {\\n * __ERC20Permit_init(\\\"MyToken\\\");\\n * }\\n * }\\n * ```\\n *\\n * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as\\n * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.\\n *\\n * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure\\n * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.\\n *\\n * [CAUTION]\\n * ====\\n * Avoid leaving a contract uninitialized.\\n *\\n * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation\\n * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke\\n * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:\\n *\\n * [.hljs-theme-light.nopadding]\\n * ```\\n * /// @custom:oz-upgrades-unsafe-allow constructor\\n * constructor() {\\n * _disableInitializers();\\n * }\\n * ```\\n * ====\\n */\\nabstract contract Initializable {\\n /**\\n * @dev Storage of the initializable contract.\\n *\\n * It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions\\n * when using with upgradeable contracts.\\n *\\n * @custom:storage-location erc7201:openzeppelin.storage.Initializable\\n */\\n struct InitializableStorage {\\n /**\\n * @dev Indicates that the contract has been initialized.\\n */\\n uint64 _initialized;\\n /**\\n * @dev Indicates that the contract is in the process of being initialized.\\n */\\n bool _initializing;\\n }\\n\\n // keccak256(abi.encode(uint256(keccak256(\\\"openzeppelin.storage.Initializable\\\")) - 1)) & ~bytes32(uint256(0xff))\\n bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00;\\n\\n /**\\n * @dev The contract is already initialized.\\n */\\n error InvalidInitialization();\\n\\n /**\\n * @dev The contract is not initializing.\\n */\\n error NotInitializing();\\n\\n /**\\n * @dev Triggered when the contract has been initialized or reinitialized.\\n */\\n event Initialized(uint64 version);\\n\\n /**\\n * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,\\n * `onlyInitializing` functions can be used to initialize parent contracts.\\n *\\n * Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any\\n * number of times. This behavior in the constructor can be useful during testing and is not expected to be used in\\n * production.\\n *\\n * Emits an {Initialized} event.\\n */\\n modifier initializer() {\\n // solhint-disable-next-line var-name-mixedcase\\n InitializableStorage storage $ = _getInitializableStorage();\\n\\n // Cache values to avoid duplicated sloads\\n bool isTopLevelCall = !$._initializing;\\n uint64 initialized = $._initialized;\\n\\n // Allowed calls:\\n // - initialSetup: the contract is not in the initializing state and no previous version was\\n // initialized\\n // - construction: the contract is initialized at version 1 (no reininitialization) and the\\n // current contract is just being deployed\\n bool initialSetup = initialized == 0 && isTopLevelCall;\\n bool construction = initialized == 1 && address(this).code.length == 0;\\n\\n if (!initialSetup && !construction) {\\n revert InvalidInitialization();\\n }\\n $._initialized = 1;\\n if (isTopLevelCall) {\\n $._initializing = true;\\n }\\n _;\\n if (isTopLevelCall) {\\n $._initializing = false;\\n emit Initialized(1);\\n }\\n }\\n\\n /**\\n * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the\\n * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be\\n * used to initialize parent contracts.\\n *\\n * A reinitializer may be used after the original initialization step. This is essential to configure modules that\\n * are added through upgrades and that require initialization.\\n *\\n * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`\\n * cannot be nested. If one is invoked in the context of another, execution will revert.\\n *\\n * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in\\n * a contract, executing them in the right order is up to the developer or operator.\\n *\\n * WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization.\\n *\\n * Emits an {Initialized} event.\\n */\\n modifier reinitializer(uint64 version) {\\n // solhint-disable-next-line var-name-mixedcase\\n InitializableStorage storage $ = _getInitializableStorage();\\n\\n if ($._initializing || $._initialized >= version) {\\n revert InvalidInitialization();\\n }\\n $._initialized = version;\\n $._initializing = true;\\n _;\\n $._initializing = false;\\n emit Initialized(version);\\n }\\n\\n /**\\n * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the\\n * {initializer} and {reinitializer} modifiers, directly or indirectly.\\n */\\n modifier onlyInitializing() {\\n _checkInitializing();\\n _;\\n }\\n\\n /**\\n * @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}.\\n */\\n function _checkInitializing() internal view virtual {\\n if (!_isInitializing()) {\\n revert NotInitializing();\\n }\\n }\\n\\n /**\\n * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.\\n * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized\\n * to any version. It is recommended to use this to lock implementation contracts that are designed to be called\\n * through proxies.\\n *\\n * Emits an {Initialized} event the first time it is successfully executed.\\n */\\n function _disableInitializers() internal virtual {\\n // solhint-disable-next-line var-name-mixedcase\\n InitializableStorage storage $ = _getInitializableStorage();\\n\\n if ($._initializing) {\\n revert InvalidInitialization();\\n }\\n if ($._initialized != type(uint64).max) {\\n $._initialized = type(uint64).max;\\n emit Initialized(type(uint64).max);\\n }\\n }\\n\\n /**\\n * @dev Returns the highest version that has been initialized. See {reinitializer}.\\n */\\n function _getInitializedVersion() internal view returns (uint64) {\\n return _getInitializableStorage()._initialized;\\n }\\n\\n /**\\n * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.\\n */\\n function _isInitializing() internal view returns (bool) {\\n return _getInitializableStorage()._initializing;\\n }\\n\\n /**\\n * @dev Returns a pointer to the storage namespace.\\n */\\n // solhint-disable-next-line var-name-mixedcase\\n function _getInitializableStorage() private pure returns (InitializableStorage storage $) {\\n assembly {\\n $.slot := INITIALIZABLE_STORAGE\\n }\\n }\\n}\\n\",\"keccak256\":\"0x631188737069917d2f909d29ce62c4d48611d326686ba6683e26b72a23bfac0b\",\"license\":\"MIT\"},\"@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\\n\\npragma solidity ^0.8.20;\\nimport {Initializable} from \\\"../proxy/utils/Initializable.sol\\\";\\n\\n/**\\n * @dev Provides information about the current execution context, including the\\n * sender of the transaction and its data. While these are generally available\\n * via msg.sender and msg.data, they should not be accessed in such a direct\\n * manner, since when dealing with meta-transactions the account sending and\\n * paying for execution may not be the actual sender (as far as an application\\n * is concerned).\\n *\\n * This contract is only required for intermediate, library-like contracts.\\n */\\nabstract contract ContextUpgradeable is Initializable {\\n function __Context_init() internal onlyInitializing {\\n }\\n\\n function __Context_init_unchained() internal onlyInitializing {\\n }\\n function _msgSender() internal view virtual returns (address) {\\n return msg.sender;\\n }\\n\\n function _msgData() internal view virtual returns (bytes calldata) {\\n return msg.data;\\n }\\n\\n function _contextSuffixLength() internal view virtual returns (uint256) {\\n return 0;\\n }\\n}\\n\",\"keccak256\":\"0xdbef5f0c787055227243a7318ef74c8a5a1108ca3a07f2b3a00ef67769e1e397\",\"license\":\"MIT\"},\"contracts/Enclave.sol\":{\"content\":\"// SPDX-License-Identifier: LGPL-3.0-only\\npragma solidity >=0.8.26;\\n\\nimport {\\n IEnclave,\\n E3,\\n IComputationModule,\\n IExecutionModule\\n} from \\\"./interfaces/IEnclave.sol\\\";\\nimport { ICyphernodeRegistry } from \\\"./interfaces/ICyphernodeRegistry.sol\\\";\\nimport { IInputValidator } from \\\"./interfaces/IInputValidator.sol\\\";\\nimport { IOutputVerifier } from \\\"./interfaces/IOutputVerifier.sol\\\";\\nimport {\\n OwnableUpgradeable\\n} from \\\"@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol\\\";\\n\\ncontract Enclave is IEnclave, OwnableUpgradeable {\\n ////////////////////////////////////////////////////////////\\n // //\\n // Storage Variables //\\n // //\\n ////////////////////////////////////////////////////////////\\n\\n ICyphernodeRegistry public cyphernodeRegistry; // address of the Cyphernode registry.\\n uint256 public maxDuration; // maximum duration of a computation in seconds.\\n uint256 public nexte3Id; // ID of the next E3.\\n uint256 public requests; // total number of requests made to Enclave.\\n\\n // TODO: should computation and execution modules be explicitly allowed?\\n // My intuition is that an allowlist is required since they impose slashing conditions.\\n // But perhaps this is one place where node pools might be utilized, allowing nodes to\\n // opt in to being selected for specific computations, along with the corresponding slashing conditions.\\n // This would reduce the governance overhead for Enclave.\\n\\n // Mapping of allowed computation modules.\\n mapping(IComputationModule computationModule => bool allowed)\\n public computationModules;\\n\\n // Mapping of allowed execution modules.\\n mapping(IExecutionModule executionModule => bool allowed)\\n public executionModules;\\n\\n // Mapping of E3s.\\n mapping(uint256 id => E3 e3) public e3s;\\n\\n ////////////////////////////////////////////////////////////\\n // //\\n // Errors //\\n // //\\n ////////////////////////////////////////////////////////////\\n\\n error CommitteeSelectionFailed();\\n error ComputationModuleNotAllowed(IComputationModule computationModule);\\n error E3AlreadyActivated(uint256 e3Id);\\n error E3Expired();\\n error E3NotActivated(uint256 e3Id);\\n error E3NotReady();\\n error E3DoesNotExist(uint256 e3Id);\\n error ModuleAlreadyEnabled(address module);\\n error ModuleNotEnabled(address module);\\n error InputDeadlinePassed(uint256 e3Id, uint256 expiration);\\n error InputDeadlineNotPassed(uint256 e3Id, uint256 expiration);\\n error InvalidComputation();\\n error InvalidExecutionModuleSetup();\\n error InvalidCyphernodeRegistry(ICyphernodeRegistry cyphernodeRegistry);\\n error InvalidInput();\\n error InvalidDuration(uint256 duration);\\n error InvalidOutput(bytes output);\\n error InvalidStartWindow();\\n error InvalidThreshold(uint32[2] threshold);\\n error CiphertextOutputAlreadyPublished(uint256 e3Id);\\n error CiphertextOutputNotPublished(uint256 e3Id);\\n error PaymentRequired(uint256 value);\\n error PlaintextOutputAlreadyPublished(uint256 e3Id);\\n\\n ////////////////////////////////////////////////////////////\\n // //\\n // Initialization //\\n // //\\n ////////////////////////////////////////////////////////////\\n\\n /// @param _owner The owner of this contract\\n /// @param _maxDuration The maximum duration of a computation in seconds\\n constructor(\\n address _owner,\\n ICyphernodeRegistry _cyphernodeRegistry,\\n uint256 _maxDuration\\n ) {\\n initialize(_owner, _cyphernodeRegistry, _maxDuration);\\n }\\n\\n /// @param _owner The owner of this contract\\n /// @param _maxDuration The maximum duration of a computation in seconds\\n function initialize(\\n address _owner,\\n ICyphernodeRegistry _cyphernodeRegistry,\\n uint256 _maxDuration\\n ) public initializer {\\n __Ownable_init(msg.sender);\\n setMaxDuration(_maxDuration);\\n setCyphernodeRegistry(_cyphernodeRegistry);\\n if (_owner != owner()) transferOwnership(_owner);\\n }\\n\\n ////////////////////////////////////////////////////////////\\n // //\\n // Core Entrypoints //\\n // //\\n ////////////////////////////////////////////////////////////\\n\\n function request(\\n address filter,\\n uint32[2] calldata threshold,\\n uint256[2] calldata startWindow,\\n uint256 duration,\\n IComputationModule computationModule,\\n bytes memory computationParams,\\n IExecutionModule executionModule,\\n bytes memory emParams\\n ) external payable returns (uint256 e3Id, E3 memory e3) {\\n // TODO: allow for other payment methods or only native tokens?\\n // TODO: should payment checks be somewhere else? Perhaps in the computation module or cyphernode registry?\\n require(msg.value > 0, PaymentRequired(msg.value));\\n require(\\n threshold[1] >= threshold[0] && threshold[0] > 0,\\n InvalidThreshold(threshold)\\n );\\n require(\\n // TODO: do we need a minimum start window to allow time for committee selection?\\n startWindow[1] >= startWindow[0] &&\\n startWindow[1] >= block.timestamp,\\n InvalidStartWindow()\\n );\\n require(\\n duration > 0 && duration <= maxDuration,\\n InvalidDuration(duration)\\n );\\n require(\\n computationModules[computationModule],\\n ComputationModuleNotAllowed(computationModule)\\n );\\n require(\\n executionModules[executionModule],\\n ModuleNotEnabled(address(executionModule))\\n );\\n\\n // TODO: should IDs be incremental or produced deterministically?\\n e3Id = nexte3Id;\\n nexte3Id++;\\n\\n IInputValidator inputValidator = computationModule.validate(\\n computationParams\\n );\\n require(address(inputValidator) != address(0), InvalidComputation());\\n\\n // TODO: validate that the requested computation can be performed by the given execution module.\\n IOutputVerifier outputVerifier = executionModule.validate(emParams);\\n require(\\n address(outputVerifier) != address(0),\\n InvalidExecutionModuleSetup()\\n );\\n\\n e3 = E3({\\n threshold: threshold,\\n startWindow: startWindow,\\n duration: duration,\\n expiration: 0,\\n computationModule: computationModule,\\n executionModule: executionModule,\\n inputValidator: inputValidator,\\n outputVerifier: outputVerifier,\\n committeePublicKey: hex\\\"\\\",\\n inputs: new bytes[](0),\\n ciphertextOutput: hex\\\"\\\",\\n plaintextOutput: hex\\\"\\\"\\n });\\n e3s[e3Id] = e3;\\n\\n require(\\n cyphernodeRegistry.requestCommittee(e3Id, filter, threshold),\\n CommitteeSelectionFailed()\\n );\\n\\n emit E3Requested(\\n e3Id,\\n e3s[e3Id],\\n filter,\\n computationModule,\\n executionModule\\n );\\n }\\n\\n function activate(uint256 e3Id) external returns (bool success) {\\n // Note: we could load this into a storage pointer, and do the sets there\\n // Requires a mew internal _getter that returns storage\\n E3 memory e3 = getE3(e3Id);\\n require(e3.expiration == 0, E3AlreadyActivated(e3Id));\\n require(e3.startWindow[0] <= block.timestamp, E3NotReady());\\n // TODO: handle what happens to the payment if the start window has passed.\\n require(e3.startWindow[1] >= block.timestamp, E3Expired());\\n\\n bytes memory publicKey = cyphernodeRegistry.committeePublicKey(e3Id);\\n // Note: This check feels weird\\n require(publicKey.length > 0, CommitteeSelectionFailed());\\n\\n e3s[e3Id].expiration = block.timestamp + e3.duration;\\n e3s[e3Id].committeePublicKey = publicKey;\\n\\n emit E3Activated(e3Id, e3.expiration, e3.committeePublicKey);\\n\\n return true;\\n }\\n\\n function publishInput(\\n uint256 e3Id,\\n bytes memory data\\n ) external returns (bool success) {\\n E3 memory e3 = getE3(e3Id);\\n\\n // Note: if we make 0 a no expiration, this has to be refactored\\n require(e3.expiration > 0, E3NotActivated(e3Id));\\n // TODO: should we have an input window, including both a start and end timestamp?\\n require(\\n e3.expiration > block.timestamp,\\n InputDeadlinePassed(e3Id, e3.expiration)\\n );\\n bytes memory input;\\n (input, success) = e3.inputValidator.validate(msg.sender, data);\\n require(success, InvalidInput());\\n // TODO: probably better to accumulate inputs, rather than just dumping them in storage.\\n e3s[e3Id].inputs.push(input);\\n emit InputPublished(e3Id, input);\\n }\\n\\n function publishCiphertextOutput(\\n uint256 e3Id,\\n bytes memory data\\n ) external returns (bool success) {\\n E3 memory e3 = getE3(e3Id);\\n // Note: if we make 0 a no expiration, this has to be refactored\\n require(e3.expiration > 0, E3NotActivated(e3Id));\\n require(\\n e3.expiration <= block.timestamp,\\n InputDeadlineNotPassed(e3Id, e3.expiration)\\n );\\n // TODO: should the output verifier be able to change its mind?\\n //i.e. should we be able to call this multiple times?\\n require(\\n e3.ciphertextOutput.length == 0,\\n CiphertextOutputAlreadyPublished(e3Id)\\n );\\n bytes memory output;\\n (output, success) = e3.outputVerifier.verify(e3Id, data);\\n require(success, InvalidOutput(output));\\n e3s[e3Id].ciphertextOutput = output;\\n\\n emit CiphertextOutputPublished(e3Id, output);\\n }\\n\\n function publishPlaintextOutput(\\n uint256 e3Id,\\n bytes memory data\\n ) external returns (bool success) {\\n E3 memory e3 = getE3(e3Id);\\n // Note: if we make 0 a no expiration, this has to be refactored\\n require(e3.expiration > 0, E3NotActivated(e3Id));\\n require(\\n e3.ciphertextOutput.length > 0,\\n CiphertextOutputNotPublished(e3Id)\\n );\\n require(\\n e3.plaintextOutput.length == 0,\\n PlaintextOutputAlreadyPublished(e3Id)\\n );\\n bytes memory output;\\n (output, success) = e3.computationModule.verify(e3Id, data);\\n require(success, InvalidOutput(output));\\n e3s[e3Id].plaintextOutput = output;\\n\\n emit PlaintextOutputPublished(e3Id, output);\\n }\\n\\n ////////////////////////////////////////////////////////////\\n // //\\n // Set Functions //\\n // //\\n ////////////////////////////////////////////////////////////\\n\\n function setMaxDuration(\\n uint256 _maxDuration\\n ) public onlyOwner returns (bool success) {\\n maxDuration = _maxDuration;\\n success = true;\\n emit MaxDurationSet(_maxDuration);\\n }\\n\\n function setCyphernodeRegistry(\\n ICyphernodeRegistry _cyphernodeRegistry\\n ) public onlyOwner returns (bool success) {\\n require(\\n address(_cyphernodeRegistry) != address(0) &&\\n _cyphernodeRegistry != cyphernodeRegistry,\\n InvalidCyphernodeRegistry(_cyphernodeRegistry)\\n );\\n cyphernodeRegistry = _cyphernodeRegistry;\\n success = true;\\n emit CyphernodeRegistrySet(address(_cyphernodeRegistry));\\n }\\n\\n function enableComputationModule(\\n IComputationModule computationModule\\n ) public onlyOwner returns (bool success) {\\n require(\\n !computationModules[computationModule],\\n ModuleAlreadyEnabled(address(computationModule))\\n );\\n computationModules[computationModule] = true;\\n success = true;\\n emit ComputationModuleEnabled(computationModule);\\n }\\n\\n function enableExecutionModule(\\n IExecutionModule executionModule\\n ) public onlyOwner returns (bool success) {\\n require(\\n !executionModules[executionModule],\\n ModuleAlreadyEnabled(address(executionModule))\\n );\\n executionModules[executionModule] = true;\\n success = true;\\n emit ExecutionModuleEnabled(executionModule);\\n }\\n\\n function disableComputationModule(\\n IComputationModule computationModule\\n ) public onlyOwner returns (bool success) {\\n require(\\n computationModules[computationModule],\\n ModuleNotEnabled(address(computationModule))\\n );\\n delete computationModules[computationModule];\\n success = true;\\n emit ComputationModuleDisabled(computationModule);\\n }\\n\\n function disableExecutionModule(\\n IExecutionModule executionModule\\n ) public onlyOwner returns (bool success) {\\n require(\\n executionModules[executionModule],\\n ModuleNotEnabled(address(executionModule))\\n );\\n delete executionModules[executionModule];\\n success = true;\\n emit ExecutionModuleDisabled(executionModule);\\n }\\n\\n ////////////////////////////////////////////////////////////\\n // //\\n // Get Functions //\\n // //\\n ////////////////////////////////////////////////////////////\\n\\n function getE3(uint256 e3Id) public view returns (E3 memory e3) {\\n e3 = e3s[e3Id];\\n require(\\n e3.computationModule != IComputationModule(address(0)),\\n E3DoesNotExist(e3Id)\\n );\\n }\\n}\\n\",\"keccak256\":\"0xc37015e312c621b75b924d32d19b43682ffb94ef3319326b75ca1a4e36454700\",\"license\":\"LGPL-3.0-only\"},\"contracts/interfaces/IComputationModule.sol\":{\"content\":\"// SPDX-License-Identifier: LGPL-3.0-only\\npragma solidity >=0.8.26;\\n\\nimport { IInputValidator } from \\\"./IInputValidator.sol\\\";\\n\\ninterface IComputationModule {\\n /// @notice This function should be called by the Enclave contract to validate the computation parameters.\\n /// @param params ABI encoded computation parameters.\\n /// @return inputValidator The input validator to be used for the computation.\\n function validate(\\n bytes calldata params\\n ) external returns (IInputValidator inputValidator);\\n\\n /// @notice This function should be called by the Enclave contract to verify the decrypted output of an E3.\\n /// @param e3Id ID of the E3.\\n /// @param outputData ABI encoded output data to be verified.\\n /// @return output The output data to be published.\\n /// @return success Whether the output data is valid.\\n function verify(\\n uint256 e3Id,\\n bytes memory outputData\\n ) external returns (bytes memory output, bool success);\\n}\\n\",\"keccak256\":\"0x9e65874df81985a203a0f3bea12996cb66f9e57663beed3e93f849414a5c4d0d\",\"license\":\"LGPL-3.0-only\"},\"contracts/interfaces/ICyphernodeRegistry.sol\":{\"content\":\"// SPDX-License-Identifier: LGPL-3.0-only\\npragma solidity >=0.8.26;\\n\\ninterface ICyphernodeRegistry {\\n /// @notice This event MUST be emitted when a committee is selected for an E3.\\n /// @param e3Id ID of the E3 for which the committee was selected.\\n /// @param filter Address of the contract that will coordinate committee selection.\\n /// @param threshold The M/N threshold for the committee.\\n event CommitteeRequested(\\n uint256 indexed e3Id,\\n address filter,\\n uint32[2] threshold\\n );\\n\\n /// @notice This event MUST be emitted when a committee is selected for an E3.\\n /// @param e3Id ID of the E3 for which the committee was selected.\\n /// @param publicKey Public key of the committee.\\n event CommitteePublished(uint256 indexed e3Id, bytes publicKey);\\n\\n /// @notice This event MUST be emitted when `enclave` is set.\\n /// @param enclave Address of the enclave contract.\\n event EnclaveSet(address indexed enclave);\\n\\n /// @notice This event MUST be emitted when a cyphernode is added to the registry.\\n event CyphernodeAdded(address indexed node);\\n\\n /// @notice This event MUST be emitted when a cyphernode is removed from the registry.\\n event CyphernodeRemoved(address indexed node);\\n\\n function isCyphernodeEligible(address cyphernode) external returns (bool);\\n\\n /// @notice Initiates the committee selection process for a specified E3.\\n /// @dev This function MUST revert when not called by the Enclave contract.\\n /// @param e3Id ID of the E3 for which to select the committee.\\n /// @param filter The address of the filter responsible for the committee selection process.\\n /// @param threshold The M/N threshold for the committee.\\n /// @return success True if committee selection was successfully initiated.\\n function requestCommittee(\\n uint256 e3Id,\\n address filter,\\n uint32[2] calldata threshold\\n ) external returns (bool success);\\n\\n /// @notice Publishes the public key resulting from the committee selection process.\\n /// @dev This function MUST revert if not called by the previously selected filter.\\n /// @param e3Id ID of the E3 for which to select the committee.\\n /// @param publicKey The public key generated by the selected committee.\\n function publishCommittee(\\n uint256 e3Id,\\n bytes calldata proof,\\n bytes calldata publicKey\\n ) external;\\n\\n /// @notice This function should be called by the Enclave contract to get the public key of a committee.\\n /// @dev This function MUST revert if no committee has been requested for the given E3.\\n /// @dev This function MUST revert if the committee has not yet published a public key.\\n /// @param e3Id ID of the E3 for which to get the committee public key.\\n /// @return publicKey The public key of the committee.\\n function committeePublicKey(\\n uint256 e3Id\\n ) external view returns (bytes memory);\\n}\\n\",\"keccak256\":\"0x60af5d66db32528f5032fe083218f180ab83f3199bcf090bed7249c28bc18104\",\"license\":\"LGPL-3.0-only\"},\"contracts/interfaces/IE3.sol\":{\"content\":\"// SPDX-License-Identifier: LGPL-3.0-only\\npragma solidity >=0.8.26;\\n\\nimport { IInputValidator } from \\\"./IInputValidator.sol\\\";\\nimport { IExecutionModule } from \\\"./IExecutionModule.sol\\\";\\nimport { IComputationModule } from \\\"./IComputationModule.sol\\\";\\nimport { IOutputVerifier } from \\\"./IOutputVerifier.sol\\\";\\n\\n/// @title E3 struct\\n/// @notice This struct represents an E3 computation.\\n/// @param threshold M/N threshold for the committee.\\n/// @param startWindow Start window for the computation: index zero is minimum, index 1 is the maxium.\\n/// @param duration Duration of the E3.\\n/// @param expiration Timestamp when committee duties expire.\\n/// @param computationModule Address of the computation module contract.\\n/// @param executionModule Address of the execution module contract.\\n/// @param inputValidator Address of the input validator contract.\\n/// @param outputVerifier Address of the output verifier contract.\\n/// @param committeeId ID of the selected committee.\\n/// @param ciphertextOutput Encrypted output data.\\n/// @param plaintextOutput Decrypted output data.\\nstruct E3 {\\n uint32[2] threshold;\\n uint256[2] startWindow;\\n uint256 duration;\\n uint256 expiration;\\n IComputationModule computationModule;\\n IExecutionModule executionModule;\\n IInputValidator inputValidator;\\n IOutputVerifier outputVerifier;\\n bytes committeePublicKey;\\n bytes[] inputs;\\n bytes ciphertextOutput;\\n bytes plaintextOutput;\\n}\\n\",\"keccak256\":\"0x6013398b086073328305a2f33edd3027ed82b3fb7e802627f88ac7781a2c1125\",\"license\":\"LGPL-3.0-only\"},\"contracts/interfaces/IEnclave.sol\":{\"content\":\"// SPDX-License-Identifier: LGPL-3.0-only\\npragma solidity >=0.8.26;\\n\\nimport { E3, IComputationModule, IExecutionModule } from \\\"./IE3.sol\\\";\\n\\ninterface IEnclave {\\n ////////////////////////////////////////////////////////////\\n // //\\n // Events //\\n // //\\n ////////////////////////////////////////////////////////////\\n\\n /// @notice This event MUST be emitted when an Encrypted Execution Environment (E3) is successfully requested.\\n /// @param e3Id ID of the E3.\\n /// @param e3 Details of the E3.\\n /// @param filter Address of the pool of nodes from which the Cypher Node committee was selected.\\n /// @param computationModule Address of the Computation module selected.\\n /// @param executionModule Address of the execution module selected.\\n event E3Requested(\\n uint256 e3Id,\\n E3 e3,\\n address filter,\\n IComputationModule indexed computationModule,\\n IExecutionModule indexed executionModule\\n );\\n\\n /// @notice This event MUST be emitted when an Encrypted Execution Environment (E3) is successfully activated.\\n /// @param e3Id ID of the E3.\\n /// @param expiration Timestamp when committee duties expire.\\n /// @param committeePublicKey Public key of the committee.\\n event E3Activated(\\n uint256 e3Id,\\n uint256 expiration,\\n bytes committeePublicKey\\n );\\n\\n /// @notice This event MUST be emitted when an input to an Encrypted Execution Environment (E3) is\\n /// successfully published.\\n /// @param e3Id ID of the E3.\\n /// @param data ABI encoded input data.\\n event InputPublished(uint256 indexed e3Id, bytes data);\\n\\n /// @notice This event MUST be emitted when the plaintext output of an Encrypted Execution Environment (E3)\\n /// is successfully published.\\n /// @param e3Id ID of the E3.\\n /// @param plaintextOutput ABI encoded plaintext output.\\n event PlaintextOutputPublished(uint256 indexed e3Id, bytes plaintextOutput);\\n\\n /// @notice This event MUST be emitted when the ciphertext output of an Encrypted Execution Environment (E3)\\n /// is successfully published.\\n /// @param e3Id ID of the E3.\\n /// @param ciphertextOutput ABI encoded ciphertext output.\\n event CiphertextOutputPublished(\\n uint256 indexed e3Id,\\n bytes ciphertextOutput\\n );\\n\\n /// @notice This event MUST be emitted any time the `maxDuration` is set.\\n /// @param maxDuration The maximum duration of a computation in seconds.\\n event MaxDurationSet(uint256 maxDuration);\\n\\n /// @notice This event MUST be emitted any time the CyphernodeRegistry is set.\\n /// @param cyphernodeRegistry The address of the CyphernodeRegistry contract.\\n event CyphernodeRegistrySet(address cyphernodeRegistry);\\n\\n /// @notice This event MUST be emitted any time a computation module is enabled.\\n /// @param computationModule The address of the computation module.\\n event ComputationModuleEnabled(IComputationModule computationModule);\\n\\n /// @notice This event MUST be emitted any time a computation module is disabled.\\n /// @param computationModule The address of the computation module.\\n event ComputationModuleDisabled(IComputationModule computationModule);\\n\\n /// @notice This event MUST be emitted any time an execution module is enabled.\\n /// @param executionModule The address of the execution module.\\n event ExecutionModuleEnabled(IExecutionModule executionModule);\\n\\n /// @notice This event MUST be emitted any time an execution module is disabled.\\n /// @param executionModule The address of the execution module.\\n event ExecutionModuleDisabled(IExecutionModule executionModule);\\n\\n ////////////////////////////////////////////////////////////\\n // //\\n // Core Entrypoints //\\n // //\\n ////////////////////////////////////////////////////////////\\n\\n /// @notice This function should be called to request a computation within an Encrypted Execution Environment (E3).\\n /// @dev This function MUST emit the E3Requested event.\\n /// @param filter IDs of the pool of nodes from which to select the committee.\\n /// @param threshold The M/N threshold for the committee.\\n /// @param duration The duration of the computation in seconds.\\n /// @param computationModule Address of the computation module.\\n /// @param computationParams ABI encoded computation parameters.\\n /// @param executionModule Address of the execution module.\\n /// @param emParams ABI encoded execution module parameters.\\n /// @return e3Id ID of the E3.\\n /// @return e3 The E3 struct.\\n function request(\\n address filter,\\n uint32[2] calldata threshold,\\n uint256[2] calldata startWindow,\\n uint256 duration,\\n IComputationModule computationModule,\\n bytes memory computationParams,\\n IExecutionModule executionModule,\\n bytes memory emParams\\n ) external payable returns (uint256 e3Id, E3 memory e3);\\n\\n /// @notice This function should be called to activate an Encrypted Execution Environment (E3) once it has been\\n /// initialized and is ready for input.\\n /// @dev This function MUST emit the E3Activated event.\\n /// @dev This function MUST revert if the given E3 has not yet been requested.\\n /// @dev This function MUST revert if the selected node committee has not yet published a public key.\\n /// @param e3Id ID of the E3.\\n function activate(uint256 e3Id) external returns (bool success);\\n\\n /// @notice This function should be called to publish input data for Encrypted Execution Environment (E3).\\n /// @dev This function MUST revert if the E3 is not yet activated.\\n /// @dev This function MUST emit the InputPublished event.\\n /// @param e3Id ID of the E3.\\n /// @param data ABI encoded input data to publish.\\n /// @return success True if the input was successfully published.\\n function publishInput(\\n uint256 e3Id,\\n bytes calldata data\\n ) external returns (bool success);\\n\\n /// @notice This function should be called to publish output data for an Encrypted Execution Environment (E3).\\n /// @dev This function MUST emit the CiphertextOutputPublished event.\\n /// @param e3Id ID of the E3.\\n /// @param data ABI encoded output data to verify.\\n /// @return success True if the output was successfully published.\\n function publishCiphertextOutput(\\n uint256 e3Id,\\n bytes memory data\\n ) external returns (bool success);\\n\\n /// @notice This function publishes the plaintext output of an Encrypted Execution Environment (E3).\\n /// @dev This function MUST revert if the output has not been published.\\n /// @dev This function MUST emit the PlaintextOutputPublished event.\\n /// @param e3Id ID of the E3.\\n /// @param data ABI encoded output data to decrypt.\\n /// @return success True if the output was successfully decrypted.\\n function publishPlaintextOutput(\\n uint256 e3Id,\\n bytes memory data\\n ) external returns (bool success);\\n\\n ////////////////////////////////////////////////////////////\\n // //\\n // Set Functions //\\n // //\\n ////////////////////////////////////////////////////////////\\n\\n /// @notice This function should be called to set the maximum duration of requested computations.\\n /// @param _maxDuration The maximum duration of a computation in seconds.\\n /// @return success True if the max duration was successfully set.\\n function setMaxDuration(\\n uint256 _maxDuration\\n ) external returns (bool success);\\n\\n ////////////////////////////////////////////////////////////\\n // //\\n // Get Functions //\\n // //\\n ////////////////////////////////////////////////////////////\\n\\n /// @notice This function should be called to retrieve the details of an Encrypted Execution Environment (E3).\\n /// @dev This function MUST revert if the E3 does not exist.\\n /// @param e3Id ID of the E3.\\n /// @return e3 The struct representing the requested E3.\\n function getE3(uint256 e3Id) external view returns (E3 memory e3);\\n}\\n\",\"keccak256\":\"0x706e77d517e9d275fa68844f902ac74ae5c508443732da519423018e75426bb4\",\"license\":\"LGPL-3.0-only\"},\"contracts/interfaces/IExecutionModule.sol\":{\"content\":\"// SPDX-License-Identifier: LGPL-3.0-only\\npragma solidity >=0.8.26;\\n\\nimport { IOutputVerifier } from \\\"./IOutputVerifier.sol\\\";\\n\\ninterface IExecutionModule {\\n /// @notice This function should be called by the Enclave contract to validate the execution module parameters.\\n /// @param params ABI encoded execution module parameters.\\n function validate(\\n bytes calldata params\\n ) external returns (IOutputVerifier outputVerifier);\\n}\\n\",\"keccak256\":\"0x6cd6024b4459f94dde07b70e4f784078cbd4ab71d28c3b41316d3590d7c9bcf8\",\"license\":\"LGPL-3.0-only\"},\"contracts/interfaces/IInputValidator.sol\":{\"content\":\"// SPDX-License-Identifier: LGPL-3.0-only\\npragma solidity >=0.8.26;\\n\\ninterface IInputValidator {\\n /// @notice This function should be called by the Enclave contract to validate the input parameters.\\n /// @param params ABI encoded input parameters.\\n /// @return input The input data to be published.\\n /// @return success Whether the input parameters are valid.\\n function validate(\\n address sender,\\n bytes memory params\\n ) external returns (bytes memory input, bool success);\\n}\\n\",\"keccak256\":\"0x8faeb82309f9a353636ef4ad1ca34a181a8161ccd287dd7c3150c0d6251cd656\",\"license\":\"LGPL-3.0-only\"},\"contracts/interfaces/IOutputVerifier.sol\":{\"content\":\"// SPDX-License-Identifier: LGPL-3.0-only\\npragma solidity >=0.8.26;\\n\\ninterface IOutputVerifier {\\n /// @notice This function should be called by the Enclave contract to verify the output of a computation.\\n /// @param e3Id ID of the E3.\\n /// @param data ABI encoded output data to be verified.\\n /// @return output Ciphertext output of the given computation.\\n function verify(\\n uint256 e3Id,\\n bytes memory data\\n ) external view returns (bytes memory output, bool success);\\n}\\n\",\"keccak256\":\"0x09648c77f96c17a0d4143a11feb5c6aec15c70029cb483335a0bd9d6224769e8\",\"license\":\"LGPL-3.0-only\"}},\"version\":1}", + "bytecode": "0x6080346102a457601f61265838819003918201601f19168301916001600160401b038311848410176102a9578084926060946040528339810103126102a45780516001600160a01b0381168082036102a45760208301516001600160a01b03811693908490036102a457604090810151600080516020612638833981519152549182901c60ff161594916001600160401b0381168015908161029c575b6001149081610292575b159081610289575b50610278576001600160401b03198116600117600080516020612638833981519152557fba0716ba1ee2ea8ecc4c64119b4537cdb42a99d82acf92af5b87607b8b523552916020918761024d575b50610105610335565b61010d610335565b610116336102bf565b61011e610363565b80600155604051908152a1610131610363565b80151580610238575b1561022457600080546001600160a01b031916821790556040519081527f016ea868599173c3163f65dea5e4677b2be5f0ececb4ec15d1166a27de35a53390602090a1600080516020612618833981519152546001600160a01b03160361020d575b506101b1575b60405161227e908161039a8239f35b68ff0000000000000000196000805160206126388339815191525416600080516020612638833981519152557fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2602060405160018152a16101a2565b61021e90610219610363565b6102bf565b3861019c565b63157970a560e21b60005260045260246000fd5b506000546001600160a01b031681141561013a565b6001600160481b031916680100000000000000011760008051602061263883398151915255386100fc565b63f92ee8a960e01b60005260046000fd5b905015386100ae565b303b1591506100a6565b87915061009c565b600080fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b0316801561031f5760008051602061261883398151915280546001600160a01b0319811683179091556001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a3565b631e4fbdf760e01b600052600060045260246000fd5b60ff6000805160206126388339815191525460401c161561035257565b631afcd79f60e31b60005260046000fd5b600080516020612618833981519152546001600160a01b0316330361038457565b63118cdaa760e01b6000523360045260246000fdfe6080604052600436101561001257600080fd5b60003560e01c806309e098de146116c6578063115dfcbb146116875780631794bb3c146114615780632c27e1371461143a5780634017daf01461132e578063406ed35c146112fb578063594dfe61146109f95780636db5c8fd146109db578063715018a61461094257806376c932d514610903578063784b2830146107a657806378b41acd146107835780638da5cb5b1461073d578063a8873c6b146106ab578063af378f1014610619578063b260c42a14610469578063b74cb2db1461044b578063cb6496171461042d578063cf0f34c414610405578063d016b08d14610265578063d3c59355146101d7578063f14ea7b8146101495763f2fde38b1461011957600080fd5b34610144576020366003190112610144576101426101356118db565b61013d6121e9565b612143565b005b600080fd5b34610144576020366003190112610144577f39a3e67e141e4afa4c0f050632f57cfa9ccab94319143265fb278752551b0ca860206001600160a01b0361018d6118db565b6101956121e9565b1680600052600482526101b08160ff60406000205416612030565b8060005260048252604060002060ff198154169055604051908152a1602060405160018152f35b34610144576020366003190112610144577fe48e78a7419c5652baf40c86a4d7548a04ec3f569d4e6204e5a1e1890acbfaf460206001600160a01b0361021b6118db565b6102236121e9565b16806000526005825261023e8160ff60406000205416612030565b8060005260058252604060002060ff198154169055604051908152a1602060405160018152f35b3461014457610273366118a8565b61027c82611e0e565b6060810161028d8482511515611b69565b51428111156103ed57506102d76000926001600160a01b0360c085940151169060405194858094819363caf9278560e01b83523360048401526040602484015260448301906119d1565b03925af180156103e1576000916000916103bc575b50156103ab57816000526006602052600a60406000200180549168010000000000000000831015610395576001830180835583101561037f5761035d817fabf12c38379be7b560558cae3ceec83b3762653f7dd74e875af2ea6aeac7eaa89461037194600052602060002001611c69565b6040519182916020835260208301906119d1565b0390a2602060405160018152f35b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b63b4fa3fb360e01b60005260046000fd5b90506103db91503d806000833e6103d38183611823565b810190611bd4565b836102ec565b6040513d6000823e3d90fd5b8363142c294360e31b60005260045260245260446000fd5b34610144576020366003190112610144576020610423600435612107565b6040519015158152f35b34610144576000366003190112610144576020600254604051908152f35b34610144576000366003190112610144576020600354604051908152f35b346101445760203660031901126101445760043561048681611e0e565b60608101918251610605576020820180515142106105f45760204291510151106105e357602460006001600160a01b0381541660405192838092630e82f3b760e41b82528660048301525afa9081156103e15760009161059b575b5080511561058a57604083015142019081421161057457600083815260066020526040902060048101929092557f50df9e2c9fc5a7f4a07e403fa0300b88fcc8c6943bdff4b8ae71f55b7fd95f8994610566926101009261054491600901611c69565b51930151604051938493845260208401526060604084015260608301906119d1565b0390a1602060405160018152f35b634e487b7160e01b600052601160045260246000fd5b630d8dbe2560e01b60005260046000fd5b903d8082843e6105ab8184611823565b8201916020818403126105df5780519167ffffffffffffffff83116105dc57506105d6929101611b85565b846104e1565b80fd5b5080fd5b633d82a7cd60e11b60005260046000fd5b63a0750b5160e01b60005260046000fd5b633e26347b60e21b60005260045260246000fd5b34610144576020366003190112610144577fe5df1e46acc6e102c34b0f812f6557dba66de2e5fed10b64103b5d744083ee3160206001600160a01b0361065d6118db565b6106656121e9565b1680600052600482526106818160ff60406000205416156120e1565b80600052600482526040600020600160ff19825416179055604051908152a1602060405160018152f35b34610144576020366003190112610144577fcf75d44d74f911d2ec243ed8b390c2e4c69f2f2f372a197c0665e72843d49c0d60206001600160a01b036106ef6118db565b6106f76121e9565b1680600052600582526107138160ff60406000205416156120e1565b80600052600582526040600020600160ff19825416179055604051908152a1602060405160018152f35b346101445760003660031901126101445760206001600160a01b037f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c1993005416604051908152f35b346101445760203660031901126101445760206104236107a16118db565b612056565b34610144576107b4366118a8565b6107bd82611e0e565b606081016107ce8482511515611b69565b514281116108eb5750610140810151516108d65761081392916001600160a01b0360e060009301511660405180809681946321614b3960e21b83528760048401611c0a565b03915afa9081156103e1576020926000908193610893575b506108868161085b7f7cc27e4a5626cbc4f8ba1a927b0448de55e6a114bc87660331270c5109ade0719386611c21565b836000526006865261087481600b604060002001611c69565b604051918291878352878301906119d1565b0390a26040519015158152f35b61088693506108cd907f7cc27e4a5626cbc4f8ba1a927b0448de55e6a114bc87660331270c5109ade071923d8091833e6103d38183611823565b9390915061082b565b82637eb9cea960e11b60005260045260246000fd5b836370c05fb960e11b60005260045260245260446000fd5b34610144576020366003190112610144576001600160a01b036109246118db565b166000526004602052602060ff604060002054166040519015158152f35b346101445760003660031901126101445761095b6121e9565b60006001600160a01b037f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300546001600160a01b031981167f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c19930055167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a3005b34610144576000366003190112610144576020600154604051908152f35b61014036600319011261014457610a0e6118db565b36606411610144573660a4116101445760a4359060c4356001600160a01b03811681036101445760e43567ffffffffffffffff811161014457610a55903690600401611861565b9061010435936001600160a01b0385168503610144576101243567ffffffffffffffff811161014457610a8c903690600401611861565b91610a95611d6a565b5034156112e65760443563ffffffff811690818103610144575063ffffffff610abc611fd5565b161115806112d0575b156112b25760843560643581101590816112a7575b5015611296578115158061128a575b15611275576001600160a01b038116600052600460205260ff6040600020541615611257576001600160a01b0386166000526005602052610b3b6001600160a01b03871660ff60406000205416612030565b600254936000198514610574576020610b7691600187016002556040518093819263c16e50ef60e01b835284600484015260248301906119d1565b038160006001600160a01b0387165af19081156103e15760009161120e575b506001600160a01b03169283156111fd576020610bcd916040518093819263c16e50ef60e01b835284600484015260248301906119d1565b038160006001600160a01b038c165af19081156103e1576000916111b4575b506001600160a01b03169485156111a357604051602096610c0d8883611823565b6000825260405195610c1e87611806565b6040958651610c2d8882611823565b60248b825b6064831061118b5750505088528651610c4b8882611823565b60648b825b60a4831061117b5750905089015286880152600060608801526001600160a01b03851660808801526001600160a01b038a1660a088015260c087015260e08601528351610c9d8882611823565b600081526101008601526101208501528251610cb98782611823565b600081526101408501528251610ccf8782611823565b60008152610160850152846000526006865282600020845160009060005b89600282106111535750505081558685015160005b6002811061113e575050838501516003820155606085015160048201556001600160a01b036080860151166001600160a01b036005830191166001600160a01b03198254161790556001600160a01b0360a0860151166001600160a01b036006830191166001600160a01b03198254161790556001600160a01b0360c0860151166001600160a01b036007830191166001600160a01b03198254161790556001600160a01b0360e0860151166001600160a01b036008830191166001600160a01b0319825416179055610ddd61010086015160098301611c69565b610120850151805190680100000000000000008211610395578890600a84015483600a8601558084106110b5575b5001600a830160005288600020896000925b848410611097575050505050610e4e90610e3f610140870151600b8301611c69565b600c6101608701519101611c69565b6000866001600160a01b036084818454169487519485938492639ccb58d560e01b84528c60048501521696876024840152610e8b60448401611ff9565b5af190811561108c57600091611057575b501561058a57846000526006865282600020835190868252606088830152610ed8606083018263ffffffff602091548181168452821c16910152565b610ee860a0830160018301611de6565b600381015460e083015260048101546101008301526001600160a01b036005820154166101208301526001600160a01b036006820154166101408301526001600160a01b036007820154166101608301526001600160a01b036008820154166101808301526101c06101a0830152610f6761022083016009830161192b565b600a820190605f19848203016101c085015281548082528a8201918b8260051b820101936000528b600020926000915b83831061102c575050505050916001600160a01b0380611028999a9b6110098495600c610ff57fdb6ad92217850c3c041086cc44cbec591badf6afe93d864e7f4ea4ba1bcf604199605f19898203016101e08a0152600b840161192b565b878103605f1901610200890152910161192b565b9689850152169516930390a380805195869586528501528301906119f6565b0390f35b90919293948d60016110488193601f198682030187528961192b565b97019301930191939290610f97565b90508681813d8311611085575b61106e8183611823565b810103126101445761107f90611bc7565b88610e9c565b503d611064565b84513d6000823e3d90fd5b600191816110a784935186611c69565b019201920191908a90610e1d565b600a850160005282600020908482015b81830181106110d5575050610e0b565b6001919293946110e582546118f1565b806110f8575b505001908b9392916110c5565b601f81118414611110575050600081555b8c8f6110eb565b83601f61112c9385600052600020920160051c82019101611c52565b8060005260008d812081835555611109565b60019089835193019282828601015501610d02565b829363ffffffff6001939451169063ffffffff8560051b92831b921b19161793019101610ced565b82358152918101918d9101610c50565b819061119684611fe8565b8152019101908c90610c32565b63f72c404960e01b60005260046000fd5b6020813d6020116111f5575b816111cd60209383611823565b810103126105df5751906001600160a01b03821682036105dc57506001600160a01b03610bec565b3d91506111c0565b630fdfa71f60e31b60005260046000fd5b6020813d60201161124f575b8161122760209383611823565b810103126105df5751906001600160a01b03821682036105dc57506001600160a01b03610b95565b3d915061121a565b6001600160a01b0390631e505a8160e01b6000521660045260246000fd5b506313b783af60e21b60005260045260246000fd5b50600154821115610ae9565b6308594fb760e01b60005260046000fd5b905042111587610ada565b604051633744092160e21b81526044906112ce60048201611ff9565bfd5b5063ffffffff6112de611fd5565b161515610ac5565b638c4fcd9360e01b6000523460045260246000fd5b346101445760203660031901126101445761102861131a600435611e0e565b6040519182916020835260208301906119f6565b3461014457602036600319011261014457600435600052600660205260406000206003810154611028600c61142b60048501549461141d6001600160a01b036005830154166001600160a01b036006840154166001600160a01b036007850154166001600160a01b0360088601541691604051936113ba856113b38160098b0161192b565b0386611823565b6113e9604051976113d9896113d281600b850161192b565b038a611823565b6113d2604051809c81930161192b565b6040519b8c9b8c5260208c015260408b015260608a0152608089015260a088015261012060c08801526101208701906119d1565b9085820360e08701526119d1565b908382036101008501526119d1565b346101445760003660031901126101445760206001600160a01b0360005416604051908152f35b346101445760603660031901126101445761147a6118db565b602435906001600160a01b0382168203610144577ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005460ff8160401c16159267ffffffffffffffff82168015908161167f575b6001149081611675575b15908161166c575b5061165b5767ffffffffffffffff1982166001177ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005561154a918461161c575b50611528612231565b611530612231565b61153933612143565b611544604435612107565b50612056565b506001600160a01b037f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c19930054166001600160a01b0382160361160a575b5061158d57005b68ff0000000000000000197ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0054167ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00557fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2602060405160018152a1005b6116169061013d6121e9565b81611586565b68ffffffffffffffffff191668010000000000000001177ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00558461151f565b63f92ee8a960e01b60005260046000fd5b905015856114df565b303b1591506114d7565b8591506114cd565b34610144576020366003190112610144576001600160a01b036116a86118db565b166000526005602052602060ff604060002054166040519015158152f35b34610144576116d4366118a8565b6116dd82611e0e565b6116ed8360608301511515611b69565b61014081015151156117f157610160810151516117dc57611738600093926001600160a01b0360808694015116906040519586809481936321614b3960e21b83528860048401611c0a565b03925af19081156103e1576020926000908193611799575b50610886816117807f02a24c3402076671e129905ba4579d884b1f94ded1c07fc03d26d11b60bca1699386611c21565b836000526006865261087481600c604060002001611c69565b61088693506117d3907f02a24c3402076671e129905ba4579d884b1f94ded1c07fc03d26d11b60bca169923d8091833e6103d38183611823565b93909150611750565b826360ec327960e01b60005260045260246000fd5b8263032c20ef60e21b60005260045260246000fd5b610180810190811067ffffffffffffffff82111761039557604052565b90601f8019910116810190811067ffffffffffffffff82111761039557604052565b67ffffffffffffffff811161039557601f01601f191660200190565b81601f820112156101445780359061187882611845565b926118866040519485611823565b8284526020838301011161014457816000926020809301838601378301015290565b90604060031983011261014457600435916024359067ffffffffffffffff8211610144576118d891600401611861565b90565b600435906001600160a01b038216820361014457565b90600182811c92168015611921575b602083101461190b57565b634e487b7160e01b600052602260045260246000fd5b91607f1691611900565b6000929181549161193b836118f1565b8083529260018116908115611991575060011461195757505050565b60009081526020812093945091925b838310611977575060209250010190565b600181602092949394548385870101520191019190611966565b915050602093945060ff929192191683830152151560051b010190565b60005b8381106119c15750506000910152565b81810151838201526020016119b1565b906020916119ea815180928185528580860191016119ae565b601f01601f1916010190565b80519192916000845b60028210611b4d5750505060208101516000604085015b60028210611b375750505060408101516080840152606081015160a08401526001600160a01b0360808201511660c08401526001600160a01b0360a08201511660e08401526001600160a01b0360c0820151166101008401526001600160a01b0360e082015116610120840152611aa06101008201516101c06101408601526101c08501906119d1565b9261012082015193818103610160830152845180825260208201906020808260051b8501019701916000905b828210611b09575050505050610160611af76118d894956101408501518482036101808601526119d1565b920151906101a08184039101526119d1565b9091929397602080611b27600193601f198d820301865288516119d1565b9a96019493919091019101611acc565b6020806001928551815201930191019091611a16565b60208060019263ffffffff8651168152019301910190916119ff565b15611b715750565b63166b4d0360e01b60005260045260246000fd5b81601f82011215610144578051611b9b81611845565b92611ba96040519485611823565b81845260208284010111610144576118d891602080850191016119ae565b5190811515820361014457565b91906040838203126101445782519067ffffffffffffffff821161014457611c036020916118d8938601611b85565b9301611bc7565b6040906118d89392815281602082015201906119d1565b15611c295750565b604051632f9f8ab960e01b815260206004820152908190611c4e9060248301906119d1565b0390fd5b818110611c5d575050565b60008155600101611c52565b919091825167ffffffffffffffff811161039557611c8782546118f1565b601f8111611d2d575b506020601f8211600114611ccb5781929394600092611cc0575b50508160011b916000199060031b1c1916179055565b015190503880611caa565b601f1982169083600052806000209160005b818110611d1557509583600195969710611cfc575b505050811b019055565b015160001960f88460031b161c19169055388080611cf2565b9192602060018192868b015181550194019201611cdd565b611d5a90836000526020600020601f840160051c81019160208510611d60575b601f0160051c0190611c52565b38611c90565b9091508190611d4d565b60405190611d7782611806565b606061016083600060408051611d8d8282611823565b8136823783528051611d9f8282611823565b81368237602084015282015260008382015260006080820152600060a0820152600060c0820152600060e08201528261010082015282610120820152826101408201520152565b906000905b60028210611df857505050565b6001602081928554815201930191019091611deb565b90611e17611d6a565b50816000526006602052604060002091604051611e3381611806565b604051611e51818663ffffffff602091548181168452821c16910152565b611e5c604082611823565b8152604051611e6e8160018701611de6565b611e79604082611823565b602082015260038401546040820152600484015460608201526001600160a01b0360058501541693608082019485526001600160a01b0360068201541660a08301526001600160a01b0360078201541660c08301526001600160a01b0360088201541660e0830152604051611efc81611ef5816009860161192b565b0382611823565b610100830152600a8101805467ffffffffffffffff81116103955760208160051b0191611f2c6040519384611823565b818352602083019060005260206000206000915b838310611fb05750505050611f8b8392600c926101206001600160a01b03960152604051611f7581611ef581600b860161192b565b610140850152611ef5604051809481930161192b565b61016082015293511615611f9c5750565b63cd6f4a4f60e01b60005260045260246000fd5b600160208192604051611fc781611ef5818961192b565b815201920192019190611f40565b60243563ffffffff811681036101445790565b359063ffffffff8216820361014457565b6024906000905b6002821061200d57505050565b60208060019263ffffffff61202187611fe8565b16815201930191019091612000565b156120385750565b6001600160a01b03906321ac7c5f60e01b6000521660045260246000fd5b6001600160a01b03906120676121e9565b16801515806120cc575b156120b8576020817f016ea868599173c3163f65dea5e4677b2be5f0ececb4ec15d1166a27de35a533926001600160a01b03196000541617600055604051908152a1600190565b63157970a560e21b60005260045260246000fd5b506001600160a01b0360005416811415612071565b156120e95750565b6001600160a01b039063b29d459560e01b6000521660045260246000fd5b60207fba0716ba1ee2ea8ecc4c64119b4537cdb42a99d82acf92af5b87607b8b523552916121336121e9565b80600155604051908152a1600190565b6001600160a01b031680156121d3576001600160a01b037f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c19930054826001600160a01b03198216177f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c19930055167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a3565b631e4fbdf760e01b600052600060045260246000fd5b6001600160a01b037f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c1993005416330361221c57565b63118cdaa760e01b6000523360045260246000fd5b60ff7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005460401c161561226057565b631afcd79f60e31b60005260046000fdfea164736f6c634300081a000a9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300f0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00", + "deployedBytecode": "0x6080604052600436101561001257600080fd5b60003560e01c806309e098de146116c6578063115dfcbb146116875780631794bb3c146114615780632c27e1371461143a5780634017daf01461132e578063406ed35c146112fb578063594dfe61146109f95780636db5c8fd146109db578063715018a61461094257806376c932d514610903578063784b2830146107a657806378b41acd146107835780638da5cb5b1461073d578063a8873c6b146106ab578063af378f1014610619578063b260c42a14610469578063b74cb2db1461044b578063cb6496171461042d578063cf0f34c414610405578063d016b08d14610265578063d3c59355146101d7578063f14ea7b8146101495763f2fde38b1461011957600080fd5b34610144576020366003190112610144576101426101356118db565b61013d6121e9565b612143565b005b600080fd5b34610144576020366003190112610144577f39a3e67e141e4afa4c0f050632f57cfa9ccab94319143265fb278752551b0ca860206001600160a01b0361018d6118db565b6101956121e9565b1680600052600482526101b08160ff60406000205416612030565b8060005260048252604060002060ff198154169055604051908152a1602060405160018152f35b34610144576020366003190112610144577fe48e78a7419c5652baf40c86a4d7548a04ec3f569d4e6204e5a1e1890acbfaf460206001600160a01b0361021b6118db565b6102236121e9565b16806000526005825261023e8160ff60406000205416612030565b8060005260058252604060002060ff198154169055604051908152a1602060405160018152f35b3461014457610273366118a8565b61027c82611e0e565b6060810161028d8482511515611b69565b51428111156103ed57506102d76000926001600160a01b0360c085940151169060405194858094819363caf9278560e01b83523360048401526040602484015260448301906119d1565b03925af180156103e1576000916000916103bc575b50156103ab57816000526006602052600a60406000200180549168010000000000000000831015610395576001830180835583101561037f5761035d817fabf12c38379be7b560558cae3ceec83b3762653f7dd74e875af2ea6aeac7eaa89461037194600052602060002001611c69565b6040519182916020835260208301906119d1565b0390a2602060405160018152f35b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b63b4fa3fb360e01b60005260046000fd5b90506103db91503d806000833e6103d38183611823565b810190611bd4565b836102ec565b6040513d6000823e3d90fd5b8363142c294360e31b60005260045260245260446000fd5b34610144576020366003190112610144576020610423600435612107565b6040519015158152f35b34610144576000366003190112610144576020600254604051908152f35b34610144576000366003190112610144576020600354604051908152f35b346101445760203660031901126101445760043561048681611e0e565b60608101918251610605576020820180515142106105f45760204291510151106105e357602460006001600160a01b0381541660405192838092630e82f3b760e41b82528660048301525afa9081156103e15760009161059b575b5080511561058a57604083015142019081421161057457600083815260066020526040902060048101929092557f50df9e2c9fc5a7f4a07e403fa0300b88fcc8c6943bdff4b8ae71f55b7fd95f8994610566926101009261054491600901611c69565b51930151604051938493845260208401526060604084015260608301906119d1565b0390a1602060405160018152f35b634e487b7160e01b600052601160045260246000fd5b630d8dbe2560e01b60005260046000fd5b903d8082843e6105ab8184611823565b8201916020818403126105df5780519167ffffffffffffffff83116105dc57506105d6929101611b85565b846104e1565b80fd5b5080fd5b633d82a7cd60e11b60005260046000fd5b63a0750b5160e01b60005260046000fd5b633e26347b60e21b60005260045260246000fd5b34610144576020366003190112610144577fe5df1e46acc6e102c34b0f812f6557dba66de2e5fed10b64103b5d744083ee3160206001600160a01b0361065d6118db565b6106656121e9565b1680600052600482526106818160ff60406000205416156120e1565b80600052600482526040600020600160ff19825416179055604051908152a1602060405160018152f35b34610144576020366003190112610144577fcf75d44d74f911d2ec243ed8b390c2e4c69f2f2f372a197c0665e72843d49c0d60206001600160a01b036106ef6118db565b6106f76121e9565b1680600052600582526107138160ff60406000205416156120e1565b80600052600582526040600020600160ff19825416179055604051908152a1602060405160018152f35b346101445760003660031901126101445760206001600160a01b037f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c1993005416604051908152f35b346101445760203660031901126101445760206104236107a16118db565b612056565b34610144576107b4366118a8565b6107bd82611e0e565b606081016107ce8482511515611b69565b514281116108eb5750610140810151516108d65761081392916001600160a01b0360e060009301511660405180809681946321614b3960e21b83528760048401611c0a565b03915afa9081156103e1576020926000908193610893575b506108868161085b7f7cc27e4a5626cbc4f8ba1a927b0448de55e6a114bc87660331270c5109ade0719386611c21565b836000526006865261087481600b604060002001611c69565b604051918291878352878301906119d1565b0390a26040519015158152f35b61088693506108cd907f7cc27e4a5626cbc4f8ba1a927b0448de55e6a114bc87660331270c5109ade071923d8091833e6103d38183611823565b9390915061082b565b82637eb9cea960e11b60005260045260246000fd5b836370c05fb960e11b60005260045260245260446000fd5b34610144576020366003190112610144576001600160a01b036109246118db565b166000526004602052602060ff604060002054166040519015158152f35b346101445760003660031901126101445761095b6121e9565b60006001600160a01b037f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300546001600160a01b031981167f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c19930055167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a3005b34610144576000366003190112610144576020600154604051908152f35b61014036600319011261014457610a0e6118db565b36606411610144573660a4116101445760a4359060c4356001600160a01b03811681036101445760e43567ffffffffffffffff811161014457610a55903690600401611861565b9061010435936001600160a01b0385168503610144576101243567ffffffffffffffff811161014457610a8c903690600401611861565b91610a95611d6a565b5034156112e65760443563ffffffff811690818103610144575063ffffffff610abc611fd5565b161115806112d0575b156112b25760843560643581101590816112a7575b5015611296578115158061128a575b15611275576001600160a01b038116600052600460205260ff6040600020541615611257576001600160a01b0386166000526005602052610b3b6001600160a01b03871660ff60406000205416612030565b600254936000198514610574576020610b7691600187016002556040518093819263c16e50ef60e01b835284600484015260248301906119d1565b038160006001600160a01b0387165af19081156103e15760009161120e575b506001600160a01b03169283156111fd576020610bcd916040518093819263c16e50ef60e01b835284600484015260248301906119d1565b038160006001600160a01b038c165af19081156103e1576000916111b4575b506001600160a01b03169485156111a357604051602096610c0d8883611823565b6000825260405195610c1e87611806565b6040958651610c2d8882611823565b60248b825b6064831061118b5750505088528651610c4b8882611823565b60648b825b60a4831061117b5750905089015286880152600060608801526001600160a01b03851660808801526001600160a01b038a1660a088015260c087015260e08601528351610c9d8882611823565b600081526101008601526101208501528251610cb98782611823565b600081526101408501528251610ccf8782611823565b60008152610160850152846000526006865282600020845160009060005b89600282106111535750505081558685015160005b6002811061113e575050838501516003820155606085015160048201556001600160a01b036080860151166001600160a01b036005830191166001600160a01b03198254161790556001600160a01b0360a0860151166001600160a01b036006830191166001600160a01b03198254161790556001600160a01b0360c0860151166001600160a01b036007830191166001600160a01b03198254161790556001600160a01b0360e0860151166001600160a01b036008830191166001600160a01b0319825416179055610ddd61010086015160098301611c69565b610120850151805190680100000000000000008211610395578890600a84015483600a8601558084106110b5575b5001600a830160005288600020896000925b848410611097575050505050610e4e90610e3f610140870151600b8301611c69565b600c6101608701519101611c69565b6000866001600160a01b036084818454169487519485938492639ccb58d560e01b84528c60048501521696876024840152610e8b60448401611ff9565b5af190811561108c57600091611057575b501561058a57846000526006865282600020835190868252606088830152610ed8606083018263ffffffff602091548181168452821c16910152565b610ee860a0830160018301611de6565b600381015460e083015260048101546101008301526001600160a01b036005820154166101208301526001600160a01b036006820154166101408301526001600160a01b036007820154166101608301526001600160a01b036008820154166101808301526101c06101a0830152610f6761022083016009830161192b565b600a820190605f19848203016101c085015281548082528a8201918b8260051b820101936000528b600020926000915b83831061102c575050505050916001600160a01b0380611028999a9b6110098495600c610ff57fdb6ad92217850c3c041086cc44cbec591badf6afe93d864e7f4ea4ba1bcf604199605f19898203016101e08a0152600b840161192b565b878103605f1901610200890152910161192b565b9689850152169516930390a380805195869586528501528301906119f6565b0390f35b90919293948d60016110488193601f198682030187528961192b565b97019301930191939290610f97565b90508681813d8311611085575b61106e8183611823565b810103126101445761107f90611bc7565b88610e9c565b503d611064565b84513d6000823e3d90fd5b600191816110a784935186611c69565b019201920191908a90610e1d565b600a850160005282600020908482015b81830181106110d5575050610e0b565b6001919293946110e582546118f1565b806110f8575b505001908b9392916110c5565b601f81118414611110575050600081555b8c8f6110eb565b83601f61112c9385600052600020920160051c82019101611c52565b8060005260008d812081835555611109565b60019089835193019282828601015501610d02565b829363ffffffff6001939451169063ffffffff8560051b92831b921b19161793019101610ced565b82358152918101918d9101610c50565b819061119684611fe8565b8152019101908c90610c32565b63f72c404960e01b60005260046000fd5b6020813d6020116111f5575b816111cd60209383611823565b810103126105df5751906001600160a01b03821682036105dc57506001600160a01b03610bec565b3d91506111c0565b630fdfa71f60e31b60005260046000fd5b6020813d60201161124f575b8161122760209383611823565b810103126105df5751906001600160a01b03821682036105dc57506001600160a01b03610b95565b3d915061121a565b6001600160a01b0390631e505a8160e01b6000521660045260246000fd5b506313b783af60e21b60005260045260246000fd5b50600154821115610ae9565b6308594fb760e01b60005260046000fd5b905042111587610ada565b604051633744092160e21b81526044906112ce60048201611ff9565bfd5b5063ffffffff6112de611fd5565b161515610ac5565b638c4fcd9360e01b6000523460045260246000fd5b346101445760203660031901126101445761102861131a600435611e0e565b6040519182916020835260208301906119f6565b3461014457602036600319011261014457600435600052600660205260406000206003810154611028600c61142b60048501549461141d6001600160a01b036005830154166001600160a01b036006840154166001600160a01b036007850154166001600160a01b0360088601541691604051936113ba856113b38160098b0161192b565b0386611823565b6113e9604051976113d9896113d281600b850161192b565b038a611823565b6113d2604051809c81930161192b565b6040519b8c9b8c5260208c015260408b015260608a0152608089015260a088015261012060c08801526101208701906119d1565b9085820360e08701526119d1565b908382036101008501526119d1565b346101445760003660031901126101445760206001600160a01b0360005416604051908152f35b346101445760603660031901126101445761147a6118db565b602435906001600160a01b0382168203610144577ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005460ff8160401c16159267ffffffffffffffff82168015908161167f575b6001149081611675575b15908161166c575b5061165b5767ffffffffffffffff1982166001177ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005561154a918461161c575b50611528612231565b611530612231565b61153933612143565b611544604435612107565b50612056565b506001600160a01b037f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c19930054166001600160a01b0382160361160a575b5061158d57005b68ff0000000000000000197ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0054167ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00557fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2602060405160018152a1005b6116169061013d6121e9565b81611586565b68ffffffffffffffffff191668010000000000000001177ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00558461151f565b63f92ee8a960e01b60005260046000fd5b905015856114df565b303b1591506114d7565b8591506114cd565b34610144576020366003190112610144576001600160a01b036116a86118db565b166000526005602052602060ff604060002054166040519015158152f35b34610144576116d4366118a8565b6116dd82611e0e565b6116ed8360608301511515611b69565b61014081015151156117f157610160810151516117dc57611738600093926001600160a01b0360808694015116906040519586809481936321614b3960e21b83528860048401611c0a565b03925af19081156103e1576020926000908193611799575b50610886816117807f02a24c3402076671e129905ba4579d884b1f94ded1c07fc03d26d11b60bca1699386611c21565b836000526006865261087481600c604060002001611c69565b61088693506117d3907f02a24c3402076671e129905ba4579d884b1f94ded1c07fc03d26d11b60bca169923d8091833e6103d38183611823565b93909150611750565b826360ec327960e01b60005260045260246000fd5b8263032c20ef60e21b60005260045260246000fd5b610180810190811067ffffffffffffffff82111761039557604052565b90601f8019910116810190811067ffffffffffffffff82111761039557604052565b67ffffffffffffffff811161039557601f01601f191660200190565b81601f820112156101445780359061187882611845565b926118866040519485611823565b8284526020838301011161014457816000926020809301838601378301015290565b90604060031983011261014457600435916024359067ffffffffffffffff8211610144576118d891600401611861565b90565b600435906001600160a01b038216820361014457565b90600182811c92168015611921575b602083101461190b57565b634e487b7160e01b600052602260045260246000fd5b91607f1691611900565b6000929181549161193b836118f1565b8083529260018116908115611991575060011461195757505050565b60009081526020812093945091925b838310611977575060209250010190565b600181602092949394548385870101520191019190611966565b915050602093945060ff929192191683830152151560051b010190565b60005b8381106119c15750506000910152565b81810151838201526020016119b1565b906020916119ea815180928185528580860191016119ae565b601f01601f1916010190565b80519192916000845b60028210611b4d5750505060208101516000604085015b60028210611b375750505060408101516080840152606081015160a08401526001600160a01b0360808201511660c08401526001600160a01b0360a08201511660e08401526001600160a01b0360c0820151166101008401526001600160a01b0360e082015116610120840152611aa06101008201516101c06101408601526101c08501906119d1565b9261012082015193818103610160830152845180825260208201906020808260051b8501019701916000905b828210611b09575050505050610160611af76118d894956101408501518482036101808601526119d1565b920151906101a08184039101526119d1565b9091929397602080611b27600193601f198d820301865288516119d1565b9a96019493919091019101611acc565b6020806001928551815201930191019091611a16565b60208060019263ffffffff8651168152019301910190916119ff565b15611b715750565b63166b4d0360e01b60005260045260246000fd5b81601f82011215610144578051611b9b81611845565b92611ba96040519485611823565b81845260208284010111610144576118d891602080850191016119ae565b5190811515820361014457565b91906040838203126101445782519067ffffffffffffffff821161014457611c036020916118d8938601611b85565b9301611bc7565b6040906118d89392815281602082015201906119d1565b15611c295750565b604051632f9f8ab960e01b815260206004820152908190611c4e9060248301906119d1565b0390fd5b818110611c5d575050565b60008155600101611c52565b919091825167ffffffffffffffff811161039557611c8782546118f1565b601f8111611d2d575b506020601f8211600114611ccb5781929394600092611cc0575b50508160011b916000199060031b1c1916179055565b015190503880611caa565b601f1982169083600052806000209160005b818110611d1557509583600195969710611cfc575b505050811b019055565b015160001960f88460031b161c19169055388080611cf2565b9192602060018192868b015181550194019201611cdd565b611d5a90836000526020600020601f840160051c81019160208510611d60575b601f0160051c0190611c52565b38611c90565b9091508190611d4d565b60405190611d7782611806565b606061016083600060408051611d8d8282611823565b8136823783528051611d9f8282611823565b81368237602084015282015260008382015260006080820152600060a0820152600060c0820152600060e08201528261010082015282610120820152826101408201520152565b906000905b60028210611df857505050565b6001602081928554815201930191019091611deb565b90611e17611d6a565b50816000526006602052604060002091604051611e3381611806565b604051611e51818663ffffffff602091548181168452821c16910152565b611e5c604082611823565b8152604051611e6e8160018701611de6565b611e79604082611823565b602082015260038401546040820152600484015460608201526001600160a01b0360058501541693608082019485526001600160a01b0360068201541660a08301526001600160a01b0360078201541660c08301526001600160a01b0360088201541660e0830152604051611efc81611ef5816009860161192b565b0382611823565b610100830152600a8101805467ffffffffffffffff81116103955760208160051b0191611f2c6040519384611823565b818352602083019060005260206000206000915b838310611fb05750505050611f8b8392600c926101206001600160a01b03960152604051611f7581611ef581600b860161192b565b610140850152611ef5604051809481930161192b565b61016082015293511615611f9c5750565b63cd6f4a4f60e01b60005260045260246000fd5b600160208192604051611fc781611ef5818961192b565b815201920192019190611f40565b60243563ffffffff811681036101445790565b359063ffffffff8216820361014457565b6024906000905b6002821061200d57505050565b60208060019263ffffffff61202187611fe8565b16815201930191019091612000565b156120385750565b6001600160a01b03906321ac7c5f60e01b6000521660045260246000fd5b6001600160a01b03906120676121e9565b16801515806120cc575b156120b8576020817f016ea868599173c3163f65dea5e4677b2be5f0ececb4ec15d1166a27de35a533926001600160a01b03196000541617600055604051908152a1600190565b63157970a560e21b60005260045260246000fd5b506001600160a01b0360005416811415612071565b156120e95750565b6001600160a01b039063b29d459560e01b6000521660045260246000fd5b60207fba0716ba1ee2ea8ecc4c64119b4537cdb42a99d82acf92af5b87607b8b523552916121336121e9565b80600155604051908152a1600190565b6001600160a01b031680156121d3576001600160a01b037f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c19930054826001600160a01b03198216177f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c19930055167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a3565b631e4fbdf760e01b600052600060045260246000fd5b6001600160a01b037f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c1993005416330361221c57565b63118cdaa760e01b6000523360045260246000fd5b60ff7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005460401c161561226057565b631afcd79f60e31b60005260046000fdfea164736f6c634300081a000a", + "devdoc": { + "errors": { + "InvalidInitialization()": [ + { + "details": "The contract is already initialized." + } + ], + "NotInitializing()": [ + { + "details": "The contract is not initializing." + } + ], + "OwnableInvalidOwner(address)": [ + { + "details": "The owner is not a valid owner account. (eg. `address(0)`)" + } + ], + "OwnableUnauthorizedAccount(address)": [ + { + "details": "The caller account is not authorized to perform an operation." + } + ] + }, + "events": { + "CiphertextOutputPublished(uint256,bytes)": { + "params": { + "ciphertextOutput": "ABI encoded ciphertext output.", + "e3Id": "ID of the E3." + } + }, + "ComputationModuleDisabled(address)": { + "params": { + "computationModule": "The address of the computation module." + } + }, + "ComputationModuleEnabled(address)": { + "params": { + "computationModule": "The address of the computation module." + } + }, + "CyphernodeRegistrySet(address)": { + "params": { + "cyphernodeRegistry": "The address of the CyphernodeRegistry contract." + } + }, + "E3Activated(uint256,uint256,bytes)": { + "params": { + "committeePublicKey": "Public key of the committee.", + "e3Id": "ID of the E3.", + "expiration": "Timestamp when committee duties expire." + } + }, + "E3Requested(uint256,(uint32[2],uint256[2],uint256,uint256,address,address,address,address,bytes,bytes[],bytes,bytes),address,address,address)": { + "params": { + "computationModule": "Address of the Computation module selected.", + "e3": "Details of the E3.", + "e3Id": "ID of the E3.", + "executionModule": "Address of the execution module selected.", + "filter": "Address of the pool of nodes from which the Cypher Node committee was selected." + } + }, + "ExecutionModuleDisabled(address)": { + "params": { + "executionModule": "The address of the execution module." + } + }, + "ExecutionModuleEnabled(address)": { + "params": { + "executionModule": "The address of the execution module." + } + }, + "Initialized(uint64)": { + "details": "Triggered when the contract has been initialized or reinitialized." + }, + "InputPublished(uint256,bytes)": { + "params": { + "data": "ABI encoded input data.", + "e3Id": "ID of the E3." + } + }, + "MaxDurationSet(uint256)": { + "params": { + "maxDuration": "The maximum duration of a computation in seconds." + } + }, + "PlaintextOutputPublished(uint256,bytes)": { + "params": { + "e3Id": "ID of the E3.", + "plaintextOutput": "ABI encoded plaintext output." + } + } + }, + "kind": "dev", + "methods": { + "activate(uint256)": { + "details": "This function MUST emit the E3Activated event.This function MUST revert if the given E3 has not yet been requested.This function MUST revert if the selected node committee has not yet published a public key.", + "params": { + "e3Id": "ID of the E3." + } + }, + "constructor": { + "params": { + "_maxDuration": "The maximum duration of a computation in seconds", + "_owner": "The owner of this contract" + } + }, + "getE3(uint256)": { + "details": "This function MUST revert if the E3 does not exist.", + "params": { + "e3Id": "ID of the E3." + }, + "returns": { + "e3": "The struct representing the requested E3." + } + }, + "initialize(address,address,uint256)": { + "params": { + "_maxDuration": "The maximum duration of a computation in seconds", + "_owner": "The owner of this contract" + } + }, + "owner()": { + "details": "Returns the address of the current owner." + }, + "publishCiphertextOutput(uint256,bytes)": { + "details": "This function MUST emit the CiphertextOutputPublished event.", + "params": { + "data": "ABI encoded output data to verify.", + "e3Id": "ID of the E3." + }, + "returns": { + "success": "True if the output was successfully published." + } + }, + "publishInput(uint256,bytes)": { + "details": "This function MUST revert if the E3 is not yet activated.This function MUST emit the InputPublished event.", + "params": { + "data": "ABI encoded input data to publish.", + "e3Id": "ID of the E3." + }, + "returns": { + "success": "True if the input was successfully published." + } + }, + "publishPlaintextOutput(uint256,bytes)": { + "details": "This function MUST revert if the output has not been published.This function MUST emit the PlaintextOutputPublished event.", + "params": { + "data": "ABI encoded output data to decrypt.", + "e3Id": "ID of the E3." + }, + "returns": { + "success": "True if the output was successfully decrypted." + } + }, + "renounceOwnership()": { + "details": "Leaves the contract without owner. It will not be possible to call `onlyOwner` functions. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby disabling any functionality that is only available to the owner." + }, + "request(address,uint32[2],uint256[2],uint256,address,bytes,address,bytes)": { + "details": "This function MUST emit the E3Requested event.", + "params": { + "computationModule": "Address of the computation module.", + "computationParams": "ABI encoded computation parameters.", + "duration": "The duration of the computation in seconds.", + "emParams": "ABI encoded execution module parameters.", + "executionModule": "Address of the execution module.", + "filter": "IDs of the pool of nodes from which to select the committee.", + "threshold": "The M/N threshold for the committee." + }, + "returns": { + "e3": "The E3 struct.", + "e3Id": "ID of the E3." + } + }, + "setMaxDuration(uint256)": { + "params": { + "_maxDuration": "The maximum duration of a computation in seconds." + }, + "returns": { + "success": "True if the max duration was successfully set." + } + }, + "transferOwnership(address)": { + "details": "Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner." + } + }, + "version": 1 + }, + "userdoc": { + "events": { + "CiphertextOutputPublished(uint256,bytes)": { + "notice": "This event MUST be emitted when the ciphertext output of an Encrypted Execution Environment (E3) is successfully published." + }, + "ComputationModuleDisabled(address)": { + "notice": "This event MUST be emitted any time a computation module is disabled." + }, + "ComputationModuleEnabled(address)": { + "notice": "This event MUST be emitted any time a computation module is enabled." + }, + "CyphernodeRegistrySet(address)": { + "notice": "This event MUST be emitted any time the CyphernodeRegistry is set." + }, + "E3Activated(uint256,uint256,bytes)": { + "notice": "This event MUST be emitted when an Encrypted Execution Environment (E3) is successfully activated." + }, + "E3Requested(uint256,(uint32[2],uint256[2],uint256,uint256,address,address,address,address,bytes,bytes[],bytes,bytes),address,address,address)": { + "notice": "This event MUST be emitted when an Encrypted Execution Environment (E3) is successfully requested." + }, + "ExecutionModuleDisabled(address)": { + "notice": "This event MUST be emitted any time an execution module is disabled." + }, + "ExecutionModuleEnabled(address)": { + "notice": "This event MUST be emitted any time an execution module is enabled." + }, + "InputPublished(uint256,bytes)": { + "notice": "This event MUST be emitted when an input to an Encrypted Execution Environment (E3) is successfully published." + }, + "MaxDurationSet(uint256)": { + "notice": "This event MUST be emitted any time the `maxDuration` is set." + }, + "PlaintextOutputPublished(uint256,bytes)": { + "notice": "This event MUST be emitted when the plaintext output of an Encrypted Execution Environment (E3) is successfully published." + } + }, + "kind": "user", + "methods": { + "activate(uint256)": { + "notice": "This function should be called to activate an Encrypted Execution Environment (E3) once it has been initialized and is ready for input." + }, + "getE3(uint256)": { + "notice": "This function should be called to retrieve the details of an Encrypted Execution Environment (E3)." + }, + "publishCiphertextOutput(uint256,bytes)": { + "notice": "This function should be called to publish output data for an Encrypted Execution Environment (E3)." + }, + "publishInput(uint256,bytes)": { + "notice": "This function should be called to publish input data for Encrypted Execution Environment (E3)." + }, + "publishPlaintextOutput(uint256,bytes)": { + "notice": "This function publishes the plaintext output of an Encrypted Execution Environment (E3)." + }, + "request(address,uint32[2],uint256[2],uint256,address,bytes,address,bytes)": { + "notice": "This function should be called to request a computation within an Encrypted Execution Environment (E3)." + }, + "setMaxDuration(uint256)": { + "notice": "This function should be called to set the maximum duration of requested computations." + } + }, + "version": 1 + }, + "storageLayout": { + "storage": [ + { + "astId": 516, + "contract": "contracts/Enclave.sol:Enclave", + "label": "cyphernodeRegistry", + "offset": 0, + "slot": "0", + "type": "t_contract(ICyphernodeRegistry)1570" + }, + { + "astId": 518, + "contract": "contracts/Enclave.sol:Enclave", + "label": "maxDuration", + "offset": 0, + "slot": "1", + "type": "t_uint256" + }, + { + "astId": 520, + "contract": "contracts/Enclave.sol:Enclave", + "label": "nexte3Id", + "offset": 0, + "slot": "2", + "type": "t_uint256" + }, + { + "astId": 522, + "contract": "contracts/Enclave.sol:Enclave", + "label": "requests", + "offset": 0, + "slot": "3", + "type": "t_uint256" + }, + { + "astId": 527, + "contract": "contracts/Enclave.sol:Enclave", + "label": "computationModules", + "offset": 0, + "slot": "4", + "type": "t_mapping(t_contract(IComputationModule)1495,t_bool)" + }, + { + "astId": 532, + "contract": "contracts/Enclave.sol:Enclave", + "label": "executionModules", + "offset": 0, + "slot": "5", + "type": "t_mapping(t_contract(IExecutionModule)1802,t_bool)" + }, + { + "astId": 537, + "contract": "contracts/Enclave.sol:Enclave", + "label": "e3s", + "offset": 0, + "slot": "6", + "type": "t_mapping(t_uint256,t_struct(E3)1615_storage)" + } + ], + "types": { + "t_array(t_bytes_storage)dyn_storage": { + "base": "t_bytes_storage", + "encoding": "dynamic_array", + "label": "bytes[]", + "numberOfBytes": "32" + }, + "t_array(t_uint256)2_storage": { + "base": "t_uint256", + "encoding": "inplace", + "label": "uint256[2]", + "numberOfBytes": "64" + }, + "t_array(t_uint32)2_storage": { + "base": "t_uint32", + "encoding": "inplace", + "label": "uint32[2]", + "numberOfBytes": "32" + }, + "t_bool": { + "encoding": "inplace", + "label": "bool", + "numberOfBytes": "1" + }, + "t_bytes_storage": { + "encoding": "bytes", + "label": "bytes", + "numberOfBytes": "32" + }, + "t_contract(IComputationModule)1495": { + "encoding": "inplace", + "label": "contract IComputationModule", + "numberOfBytes": "20" + }, + "t_contract(ICyphernodeRegistry)1570": { + "encoding": "inplace", + "label": "contract ICyphernodeRegistry", + "numberOfBytes": "20" + }, + "t_contract(IExecutionModule)1802": { + "encoding": "inplace", + "label": "contract IExecutionModule", + "numberOfBytes": "20" + }, + "t_contract(IInputValidator)1817": { + "encoding": "inplace", + "label": "contract IInputValidator", + "numberOfBytes": "20" + }, + "t_contract(IOutputVerifier)1832": { + "encoding": "inplace", + "label": "contract IOutputVerifier", + "numberOfBytes": "20" + }, + "t_mapping(t_contract(IComputationModule)1495,t_bool)": { + "encoding": "mapping", + "key": "t_contract(IComputationModule)1495", + "label": "mapping(contract IComputationModule => bool)", + "numberOfBytes": "32", + "value": "t_bool" + }, + "t_mapping(t_contract(IExecutionModule)1802,t_bool)": { + "encoding": "mapping", + "key": "t_contract(IExecutionModule)1802", + "label": "mapping(contract IExecutionModule => bool)", + "numberOfBytes": "32", + "value": "t_bool" + }, + "t_mapping(t_uint256,t_struct(E3)1615_storage)": { + "encoding": "mapping", + "key": "t_uint256", + "label": "mapping(uint256 => struct E3)", + "numberOfBytes": "32", + "value": "t_struct(E3)1615_storage" + }, + "t_struct(E3)1615_storage": { + "encoding": "inplace", + "label": "struct E3", + "members": [ + { + "astId": 1585, + "contract": "contracts/Enclave.sol:Enclave", + "label": "threshold", + "offset": 0, + "slot": "0", + "type": "t_array(t_uint32)2_storage" + }, + { + "astId": 1589, + "contract": "contracts/Enclave.sol:Enclave", + "label": "startWindow", + "offset": 0, + "slot": "1", + "type": "t_array(t_uint256)2_storage" + }, + { + "astId": 1591, + "contract": "contracts/Enclave.sol:Enclave", + "label": "duration", + "offset": 0, + "slot": "3", + "type": "t_uint256" + }, + { + "astId": 1593, + "contract": "contracts/Enclave.sol:Enclave", + "label": "expiration", + "offset": 0, + "slot": "4", + "type": "t_uint256" + }, + { + "astId": 1596, + "contract": "contracts/Enclave.sol:Enclave", + "label": "computationModule", + "offset": 0, + "slot": "5", + "type": "t_contract(IComputationModule)1495" + }, + { + "astId": 1599, + "contract": "contracts/Enclave.sol:Enclave", + "label": "executionModule", + "offset": 0, + "slot": "6", + "type": "t_contract(IExecutionModule)1802" + }, + { + "astId": 1602, + "contract": "contracts/Enclave.sol:Enclave", + "label": "inputValidator", + "offset": 0, + "slot": "7", + "type": "t_contract(IInputValidator)1817" + }, + { + "astId": 1605, + "contract": "contracts/Enclave.sol:Enclave", + "label": "outputVerifier", + "offset": 0, + "slot": "8", + "type": "t_contract(IOutputVerifier)1832" + }, + { + "astId": 1607, + "contract": "contracts/Enclave.sol:Enclave", + "label": "committeePublicKey", + "offset": 0, + "slot": "9", + "type": "t_bytes_storage" + }, + { + "astId": 1610, + "contract": "contracts/Enclave.sol:Enclave", + "label": "inputs", + "offset": 0, + "slot": "10", + "type": "t_array(t_bytes_storage)dyn_storage" + }, + { + "astId": 1612, + "contract": "contracts/Enclave.sol:Enclave", + "label": "ciphertextOutput", + "offset": 0, + "slot": "11", + "type": "t_bytes_storage" + }, + { + "astId": 1614, + "contract": "contracts/Enclave.sol:Enclave", + "label": "plaintextOutput", + "offset": 0, + "slot": "12", + "type": "t_bytes_storage" + } + ], + "numberOfBytes": "416" + }, + "t_uint256": { + "encoding": "inplace", + "label": "uint256", + "numberOfBytes": "32" + }, + "t_uint32": { + "encoding": "inplace", + "label": "uint32", + "numberOfBytes": "4" + } + } + } +} diff --git a/packages/evm/deployments/sepolia/NaiveRegistryFilter.json b/packages/evm/deployments/sepolia/NaiveRegistryFilter.json new file mode 100644 index 00000000..61400ff2 --- /dev/null +++ b/packages/evm/deployments/sepolia/NaiveRegistryFilter.json @@ -0,0 +1,458 @@ +{ + "address": "0x4c19b2b2cE63129B494Cb0b0eCa4a2f761C649D6", + "abi": [ + { + "inputs": [ + { + "internalType": "address", + "name": "_owner", + "type": "address" + }, + { + "internalType": "address", + "name": "_enclave", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [], + "name": "CommitteeAlreadyExists", + "type": "error" + }, + { + "inputs": [], + "name": "CommitteeAlreadyPublished", + "type": "error" + }, + { + "inputs": [], + "name": "CommitteeDoesNotExist", + "type": "error" + }, + { + "inputs": [], + "name": "CommitteeNotPublished", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidInitialization", + "type": "error" + }, + { + "inputs": [], + "name": "NotInitializing", + "type": "error" + }, + { + "inputs": [], + "name": "OnlyRegistry", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "OwnableInvalidOwner", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "OwnableUnauthorizedAccount", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint64", + "name": "version", + "type": "uint64" + } + ], + "name": "Initialized", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "e3", + "type": "uint256" + } + ], + "name": "committees", + "outputs": [ + { + "internalType": "bytes", + "name": "publicKey", + "type": "bytes" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_owner", + "type": "address" + }, + { + "internalType": "address", + "name": "_registry", + "type": "address" + } + ], + "name": "initialize", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "e3Id", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "nodes", + "type": "address[]" + }, + { + "internalType": "bytes", + "name": "publicKey", + "type": "bytes" + } + ], + "name": "publishCommittee", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "registry", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "renounceOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "e3Id", + "type": "uint256" + }, + { + "internalType": "uint32[2]", + "name": "threshold", + "type": "uint32[2]" + } + ], + "name": "requestCommittee", + "outputs": [ + { + "internalType": "bool", + "name": "success", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_registry", + "type": "address" + } + ], + "name": "setRegistry", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } + ], + "transactionHash": "0x3e1cd2b9beba7d5ca0540a7dc817b897998eed25f69128ab8c18e72213a607bb", + "receipt": { + "to": null, + "from": "0x485E60C486671E932fd9C53d4110cdEab1E7F0eb", + "contractAddress": "0x4c19b2b2cE63129B494Cb0b0eCa4a2f761C649D6", + "transactionIndex": 103, + "gasUsed": "765625", + "logsBloom": "0x00000000000000000000000000000100000000000000000000800000000080000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000101000000000000000000000000000000000000020000000000000000000800000000000000000000000000000000400000000000000000000800000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000020000000000000000000020000000000000000000000000000000000000000000000", + "blockHash": "0x5f2631ec7ee97ddbc4d178d3d10e876979fcefde8efcb1e7be33f21c66013da9", + "transactionHash": "0x3e1cd2b9beba7d5ca0540a7dc817b897998eed25f69128ab8c18e72213a607bb", + "logs": [ + { + "transactionIndex": 103, + "blockNumber": 6668292, + "transactionHash": "0x3e1cd2b9beba7d5ca0540a7dc817b897998eed25f69128ab8c18e72213a607bb", + "address": "0x4c19b2b2cE63129B494Cb0b0eCa4a2f761C649D6", + "topics": [ + "0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x000000000000000000000000485e60c486671e932fd9c53d4110cdeab1e7f0eb" + ], + "data": "0x", + "logIndex": 154, + "blockHash": "0x5f2631ec7ee97ddbc4d178d3d10e876979fcefde8efcb1e7be33f21c66013da9" + }, + { + "transactionIndex": 103, + "blockNumber": 6668292, + "transactionHash": "0x3e1cd2b9beba7d5ca0540a7dc817b897998eed25f69128ab8c18e72213a607bb", + "address": "0x4c19b2b2cE63129B494Cb0b0eCa4a2f761C649D6", + "topics": [ + "0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0", + "0x000000000000000000000000485e60c486671e932fd9c53d4110cdeab1e7f0eb", + "0x000000000000000000000000485e60c486671e932fd9c53d4110cdeab1e7f0eb" + ], + "data": "0x", + "logIndex": 155, + "blockHash": "0x5f2631ec7ee97ddbc4d178d3d10e876979fcefde8efcb1e7be33f21c66013da9" + }, + { + "transactionIndex": 103, + "blockNumber": 6668292, + "transactionHash": "0x3e1cd2b9beba7d5ca0540a7dc817b897998eed25f69128ab8c18e72213a607bb", + "address": "0x4c19b2b2cE63129B494Cb0b0eCa4a2f761C649D6", + "topics": [ + "0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000000000001", + "logIndex": 156, + "blockHash": "0x5f2631ec7ee97ddbc4d178d3d10e876979fcefde8efcb1e7be33f21c66013da9" + } + ], + "blockNumber": 6668292, + "cumulativeGasUsed": "14723279", + "status": 1, + "byzantium": true + }, + "args": [ + "0x485E60C486671E932fd9C53d4110cdEab1E7F0eb", + "0xF9E3aeB059D699Ac4541625DE81062d6D8ad7e85" + ], + "numDeployments": 1, + "solcInputHash": "d0e6e4f19028714f394c36db62dff2be", + "metadata": "{\"compiler\":{\"version\":\"0.8.26+commit.8a97fa7a\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_enclave\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"CommitteeAlreadyExists\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CommitteeAlreadyPublished\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CommitteeDoesNotExist\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CommitteeNotPublished\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidInitialization\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotInitializing\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyRegistry\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"OwnableInvalidOwner\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"OwnableUnauthorizedAccount\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"version\",\"type\":\"uint64\"}],\"name\":\"Initialized\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"e3\",\"type\":\"uint256\"}],\"name\":\"committees\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"publicKey\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_registry\",\"type\":\"address\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"e3Id\",\"type\":\"uint256\"},{\"internalType\":\"address[]\",\"name\":\"nodes\",\"type\":\"address[]\"},{\"internalType\":\"bytes\",\"name\":\"publicKey\",\"type\":\"bytes\"}],\"name\":\"publishCommittee\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"registry\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"e3Id\",\"type\":\"uint256\"},{\"internalType\":\"uint32[2]\",\"name\":\"threshold\",\"type\":\"uint32[2]\"}],\"name\":\"requestCommittee\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_registry\",\"type\":\"address\"}],\"name\":\"setRegistry\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"errors\":{\"InvalidInitialization()\":[{\"details\":\"The contract is already initialized.\"}],\"NotInitializing()\":[{\"details\":\"The contract is not initializing.\"}],\"OwnableInvalidOwner(address)\":[{\"details\":\"The owner is not a valid owner account. (eg. `address(0)`)\"}],\"OwnableUnauthorizedAccount(address)\":[{\"details\":\"The caller account is not authorized to perform an operation.\"}]},\"events\":{\"Initialized(uint64)\":{\"details\":\"Triggered when the contract has been initialized or reinitialized.\"}},\"kind\":\"dev\",\"methods\":{\"owner()\":{\"details\":\"Returns the address of the current owner.\"},\"renounceOwnership()\":{\"details\":\"Leaves the contract without owner. It will not be possible to call `onlyOwner` functions. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby disabling any functionality that is only available to the owner.\"},\"transferOwnership(address)\":{\"details\":\"Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/registry/NaiveRegistryFilter.sol\":\"NaiveRegistryFilter\"},\"evmVersion\":\"paris\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"none\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":800},\"remappings\":[],\"viaIR\":true},\"sources\":{\"@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)\\n\\npragma solidity ^0.8.20;\\n\\nimport {ContextUpgradeable} from \\\"../utils/ContextUpgradeable.sol\\\";\\nimport {Initializable} from \\\"../proxy/utils/Initializable.sol\\\";\\n\\n/**\\n * @dev Contract module which provides a basic access control mechanism, where\\n * there is an account (an owner) that can be granted exclusive access to\\n * specific functions.\\n *\\n * The initial owner is set to the address provided by the deployer. This can\\n * later be changed with {transferOwnership}.\\n *\\n * This module is used through inheritance. It will make available the modifier\\n * `onlyOwner`, which can be applied to your functions to restrict their use to\\n * the owner.\\n */\\nabstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {\\n /// @custom:storage-location erc7201:openzeppelin.storage.Ownable\\n struct OwnableStorage {\\n address _owner;\\n }\\n\\n // keccak256(abi.encode(uint256(keccak256(\\\"openzeppelin.storage.Ownable\\\")) - 1)) & ~bytes32(uint256(0xff))\\n bytes32 private constant OwnableStorageLocation = 0x9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300;\\n\\n function _getOwnableStorage() private pure returns (OwnableStorage storage $) {\\n assembly {\\n $.slot := OwnableStorageLocation\\n }\\n }\\n\\n /**\\n * @dev The caller account is not authorized to perform an operation.\\n */\\n error OwnableUnauthorizedAccount(address account);\\n\\n /**\\n * @dev The owner is not a valid owner account. (eg. `address(0)`)\\n */\\n error OwnableInvalidOwner(address owner);\\n\\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\\n\\n /**\\n * @dev Initializes the contract setting the address provided by the deployer as the initial owner.\\n */\\n function __Ownable_init(address initialOwner) internal onlyInitializing {\\n __Ownable_init_unchained(initialOwner);\\n }\\n\\n function __Ownable_init_unchained(address initialOwner) internal onlyInitializing {\\n if (initialOwner == address(0)) {\\n revert OwnableInvalidOwner(address(0));\\n }\\n _transferOwnership(initialOwner);\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the owner.\\n */\\n modifier onlyOwner() {\\n _checkOwner();\\n _;\\n }\\n\\n /**\\n * @dev Returns the address of the current owner.\\n */\\n function owner() public view virtual returns (address) {\\n OwnableStorage storage $ = _getOwnableStorage();\\n return $._owner;\\n }\\n\\n /**\\n * @dev Throws if the sender is not the owner.\\n */\\n function _checkOwner() internal view virtual {\\n if (owner() != _msgSender()) {\\n revert OwnableUnauthorizedAccount(_msgSender());\\n }\\n }\\n\\n /**\\n * @dev Leaves the contract without owner. It will not be possible to call\\n * `onlyOwner` functions. Can only be called by the current owner.\\n *\\n * NOTE: Renouncing ownership will leave the contract without an owner,\\n * thereby disabling any functionality that is only available to the owner.\\n */\\n function renounceOwnership() public virtual onlyOwner {\\n _transferOwnership(address(0));\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Can only be called by the current owner.\\n */\\n function transferOwnership(address newOwner) public virtual onlyOwner {\\n if (newOwner == address(0)) {\\n revert OwnableInvalidOwner(address(0));\\n }\\n _transferOwnership(newOwner);\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Internal function without access restriction.\\n */\\n function _transferOwnership(address newOwner) internal virtual {\\n OwnableStorage storage $ = _getOwnableStorage();\\n address oldOwner = $._owner;\\n $._owner = newOwner;\\n emit OwnershipTransferred(oldOwner, newOwner);\\n }\\n}\\n\",\"keccak256\":\"0xc163fcf9bb10138631a9ba5564df1fa25db9adff73bd9ee868a8ae1858fe093a\",\"license\":\"MIT\"},\"@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/Initializable.sol)\\n\\npragma solidity ^0.8.20;\\n\\n/**\\n * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed\\n * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an\\n * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer\\n * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.\\n *\\n * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be\\n * reused. This mechanism prevents re-execution of each \\\"step\\\" but allows the creation of new initialization steps in\\n * case an upgrade adds a module that needs to be initialized.\\n *\\n * For example:\\n *\\n * [.hljs-theme-light.nopadding]\\n * ```solidity\\n * contract MyToken is ERC20Upgradeable {\\n * function initialize() initializer public {\\n * __ERC20_init(\\\"MyToken\\\", \\\"MTK\\\");\\n * }\\n * }\\n *\\n * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {\\n * function initializeV2() reinitializer(2) public {\\n * __ERC20Permit_init(\\\"MyToken\\\");\\n * }\\n * }\\n * ```\\n *\\n * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as\\n * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.\\n *\\n * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure\\n * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.\\n *\\n * [CAUTION]\\n * ====\\n * Avoid leaving a contract uninitialized.\\n *\\n * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation\\n * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke\\n * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:\\n *\\n * [.hljs-theme-light.nopadding]\\n * ```\\n * /// @custom:oz-upgrades-unsafe-allow constructor\\n * constructor() {\\n * _disableInitializers();\\n * }\\n * ```\\n * ====\\n */\\nabstract contract Initializable {\\n /**\\n * @dev Storage of the initializable contract.\\n *\\n * It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions\\n * when using with upgradeable contracts.\\n *\\n * @custom:storage-location erc7201:openzeppelin.storage.Initializable\\n */\\n struct InitializableStorage {\\n /**\\n * @dev Indicates that the contract has been initialized.\\n */\\n uint64 _initialized;\\n /**\\n * @dev Indicates that the contract is in the process of being initialized.\\n */\\n bool _initializing;\\n }\\n\\n // keccak256(abi.encode(uint256(keccak256(\\\"openzeppelin.storage.Initializable\\\")) - 1)) & ~bytes32(uint256(0xff))\\n bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00;\\n\\n /**\\n * @dev The contract is already initialized.\\n */\\n error InvalidInitialization();\\n\\n /**\\n * @dev The contract is not initializing.\\n */\\n error NotInitializing();\\n\\n /**\\n * @dev Triggered when the contract has been initialized or reinitialized.\\n */\\n event Initialized(uint64 version);\\n\\n /**\\n * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,\\n * `onlyInitializing` functions can be used to initialize parent contracts.\\n *\\n * Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any\\n * number of times. This behavior in the constructor can be useful during testing and is not expected to be used in\\n * production.\\n *\\n * Emits an {Initialized} event.\\n */\\n modifier initializer() {\\n // solhint-disable-next-line var-name-mixedcase\\n InitializableStorage storage $ = _getInitializableStorage();\\n\\n // Cache values to avoid duplicated sloads\\n bool isTopLevelCall = !$._initializing;\\n uint64 initialized = $._initialized;\\n\\n // Allowed calls:\\n // - initialSetup: the contract is not in the initializing state and no previous version was\\n // initialized\\n // - construction: the contract is initialized at version 1 (no reininitialization) and the\\n // current contract is just being deployed\\n bool initialSetup = initialized == 0 && isTopLevelCall;\\n bool construction = initialized == 1 && address(this).code.length == 0;\\n\\n if (!initialSetup && !construction) {\\n revert InvalidInitialization();\\n }\\n $._initialized = 1;\\n if (isTopLevelCall) {\\n $._initializing = true;\\n }\\n _;\\n if (isTopLevelCall) {\\n $._initializing = false;\\n emit Initialized(1);\\n }\\n }\\n\\n /**\\n * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the\\n * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be\\n * used to initialize parent contracts.\\n *\\n * A reinitializer may be used after the original initialization step. This is essential to configure modules that\\n * are added through upgrades and that require initialization.\\n *\\n * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`\\n * cannot be nested. If one is invoked in the context of another, execution will revert.\\n *\\n * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in\\n * a contract, executing them in the right order is up to the developer or operator.\\n *\\n * WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization.\\n *\\n * Emits an {Initialized} event.\\n */\\n modifier reinitializer(uint64 version) {\\n // solhint-disable-next-line var-name-mixedcase\\n InitializableStorage storage $ = _getInitializableStorage();\\n\\n if ($._initializing || $._initialized >= version) {\\n revert InvalidInitialization();\\n }\\n $._initialized = version;\\n $._initializing = true;\\n _;\\n $._initializing = false;\\n emit Initialized(version);\\n }\\n\\n /**\\n * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the\\n * {initializer} and {reinitializer} modifiers, directly or indirectly.\\n */\\n modifier onlyInitializing() {\\n _checkInitializing();\\n _;\\n }\\n\\n /**\\n * @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}.\\n */\\n function _checkInitializing() internal view virtual {\\n if (!_isInitializing()) {\\n revert NotInitializing();\\n }\\n }\\n\\n /**\\n * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.\\n * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized\\n * to any version. It is recommended to use this to lock implementation contracts that are designed to be called\\n * through proxies.\\n *\\n * Emits an {Initialized} event the first time it is successfully executed.\\n */\\n function _disableInitializers() internal virtual {\\n // solhint-disable-next-line var-name-mixedcase\\n InitializableStorage storage $ = _getInitializableStorage();\\n\\n if ($._initializing) {\\n revert InvalidInitialization();\\n }\\n if ($._initialized != type(uint64).max) {\\n $._initialized = type(uint64).max;\\n emit Initialized(type(uint64).max);\\n }\\n }\\n\\n /**\\n * @dev Returns the highest version that has been initialized. See {reinitializer}.\\n */\\n function _getInitializedVersion() internal view returns (uint64) {\\n return _getInitializableStorage()._initialized;\\n }\\n\\n /**\\n * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.\\n */\\n function _isInitializing() internal view returns (bool) {\\n return _getInitializableStorage()._initializing;\\n }\\n\\n /**\\n * @dev Returns a pointer to the storage namespace.\\n */\\n // solhint-disable-next-line var-name-mixedcase\\n function _getInitializableStorage() private pure returns (InitializableStorage storage $) {\\n assembly {\\n $.slot := INITIALIZABLE_STORAGE\\n }\\n }\\n}\\n\",\"keccak256\":\"0x631188737069917d2f909d29ce62c4d48611d326686ba6683e26b72a23bfac0b\",\"license\":\"MIT\"},\"@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\\n\\npragma solidity ^0.8.20;\\nimport {Initializable} from \\\"../proxy/utils/Initializable.sol\\\";\\n\\n/**\\n * @dev Provides information about the current execution context, including the\\n * sender of the transaction and its data. While these are generally available\\n * via msg.sender and msg.data, they should not be accessed in such a direct\\n * manner, since when dealing with meta-transactions the account sending and\\n * paying for execution may not be the actual sender (as far as an application\\n * is concerned).\\n *\\n * This contract is only required for intermediate, library-like contracts.\\n */\\nabstract contract ContextUpgradeable is Initializable {\\n function __Context_init() internal onlyInitializing {\\n }\\n\\n function __Context_init_unchained() internal onlyInitializing {\\n }\\n function _msgSender() internal view virtual returns (address) {\\n return msg.sender;\\n }\\n\\n function _msgData() internal view virtual returns (bytes calldata) {\\n return msg.data;\\n }\\n\\n function _contextSuffixLength() internal view virtual returns (uint256) {\\n return 0;\\n }\\n}\\n\",\"keccak256\":\"0xdbef5f0c787055227243a7318ef74c8a5a1108ca3a07f2b3a00ef67769e1e397\",\"license\":\"MIT\"},\"contracts/interfaces/ICyphernodeRegistry.sol\":{\"content\":\"// SPDX-License-Identifier: LGPL-3.0-only\\npragma solidity >=0.8.26;\\n\\ninterface ICyphernodeRegistry {\\n /// @notice This event MUST be emitted when a committee is selected for an E3.\\n /// @param e3Id ID of the E3 for which the committee was selected.\\n /// @param filter Address of the contract that will coordinate committee selection.\\n /// @param threshold The M/N threshold for the committee.\\n event CommitteeRequested(\\n uint256 indexed e3Id,\\n address filter,\\n uint32[2] threshold\\n );\\n\\n /// @notice This event MUST be emitted when a committee is selected for an E3.\\n /// @param e3Id ID of the E3 for which the committee was selected.\\n /// @param publicKey Public key of the committee.\\n event CommitteePublished(uint256 indexed e3Id, bytes publicKey);\\n\\n /// @notice This event MUST be emitted when `enclave` is set.\\n /// @param enclave Address of the enclave contract.\\n event EnclaveSet(address indexed enclave);\\n\\n /// @notice This event MUST be emitted when a cyphernode is added to the registry.\\n event CyphernodeAdded(address indexed node);\\n\\n /// @notice This event MUST be emitted when a cyphernode is removed from the registry.\\n event CyphernodeRemoved(address indexed node);\\n\\n function isCyphernodeEligible(address cyphernode) external returns (bool);\\n\\n /// @notice Initiates the committee selection process for a specified E3.\\n /// @dev This function MUST revert when not called by the Enclave contract.\\n /// @param e3Id ID of the E3 for which to select the committee.\\n /// @param filter The address of the filter responsible for the committee selection process.\\n /// @param threshold The M/N threshold for the committee.\\n /// @return success True if committee selection was successfully initiated.\\n function requestCommittee(\\n uint256 e3Id,\\n address filter,\\n uint32[2] calldata threshold\\n ) external returns (bool success);\\n\\n /// @notice Publishes the public key resulting from the committee selection process.\\n /// @dev This function MUST revert if not called by the previously selected filter.\\n /// @param e3Id ID of the E3 for which to select the committee.\\n /// @param publicKey The public key generated by the selected committee.\\n function publishCommittee(\\n uint256 e3Id,\\n bytes calldata proof,\\n bytes calldata publicKey\\n ) external;\\n\\n /// @notice This function should be called by the Enclave contract to get the public key of a committee.\\n /// @dev This function MUST revert if no committee has been requested for the given E3.\\n /// @dev This function MUST revert if the committee has not yet published a public key.\\n /// @param e3Id ID of the E3 for which to get the committee public key.\\n /// @return publicKey The public key of the committee.\\n function committeePublicKey(\\n uint256 e3Id\\n ) external view returns (bytes memory);\\n}\\n\",\"keccak256\":\"0x60af5d66db32528f5032fe083218f180ab83f3199bcf090bed7249c28bc18104\",\"license\":\"LGPL-3.0-only\"},\"contracts/interfaces/IRegistryFilter.sol\":{\"content\":\"// SPDX-License-Identifier: LGPL-3.0-only\\npragma solidity >=0.8.26;\\n\\ninterface IRegistryFilter {\\n function requestCommittee(\\n uint256 e3Id,\\n uint32[2] calldata threshold\\n ) external returns (bool success);\\n}\\n\",\"keccak256\":\"0xec67f88f2cbf46e28d4835669ef3dd2320afe5b0324423944037c16fc3f42195\",\"license\":\"LGPL-3.0-only\"},\"contracts/registry/NaiveRegistryFilter.sol\":{\"content\":\"// SPDX-License-Identifier: LGPL-3.0-only\\npragma solidity >=0.8.26;\\n\\nimport { ICyphernodeRegistry } from \\\"../interfaces/ICyphernodeRegistry.sol\\\";\\nimport { IRegistryFilter } from \\\"../interfaces/IRegistryFilter.sol\\\";\\nimport {\\n OwnableUpgradeable\\n} from \\\"@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol\\\";\\n\\ncontract NaiveRegistryFilter is IRegistryFilter, OwnableUpgradeable {\\n struct Committee {\\n address[] nodes;\\n uint32[2] threshold;\\n bytes publicKey;\\n }\\n\\n ////////////////////////////////////////////////////////////\\n // //\\n // Storage Variables //\\n // //\\n ////////////////////////////////////////////////////////////\\n\\n address public registry;\\n\\n mapping(uint256 e3 => Committee committee) public committees;\\n\\n ////////////////////////////////////////////////////////////\\n // //\\n // Errors //\\n // //\\n ////////////////////////////////////////////////////////////\\n\\n error CommitteeAlreadyExists();\\n error CommitteeAlreadyPublished();\\n error CommitteeDoesNotExist();\\n error CommitteeNotPublished();\\n error OnlyRegistry();\\n\\n ////////////////////////////////////////////////////////////\\n // //\\n // Modifiers //\\n // //\\n ////////////////////////////////////////////////////////////\\n\\n modifier onlyRegistry() {\\n require(msg.sender == registry, OnlyRegistry());\\n _;\\n }\\n\\n ////////////////////////////////////////////////////////////\\n // //\\n // Initialization //\\n // //\\n ////////////////////////////////////////////////////////////\\n\\n constructor(address _owner, address _enclave) {\\n initialize(_owner, _enclave);\\n }\\n\\n function initialize(address _owner, address _registry) public initializer {\\n __Ownable_init(msg.sender);\\n setRegistry(_registry);\\n transferOwnership(_owner);\\n }\\n\\n ////////////////////////////////////////////////////////////\\n // //\\n // Core Entrypoints //\\n // //\\n ////////////////////////////////////////////////////////////\\n\\n function requestCommittee(\\n uint256 e3Id,\\n uint32[2] calldata threshold\\n ) external onlyRegistry returns (bool success) {\\n Committee storage committee = committees[e3Id];\\n require(committee.threshold.length == 0, CommitteeAlreadyExists());\\n committee.threshold = threshold;\\n success = true;\\n }\\n\\n function publishCommittee(\\n uint256 e3Id,\\n address[] memory nodes,\\n bytes memory publicKey\\n ) external onlyOwner {\\n Committee storage committee = committees[e3Id];\\n require(\\n keccak256(committee.publicKey) == keccak256(hex\\\"\\\"),\\n CommitteeAlreadyPublished()\\n );\\n committee.nodes = nodes;\\n committee.publicKey = publicKey;\\n ICyphernodeRegistry(registry).publishCommittee(\\n e3Id,\\n abi.encode(nodes),\\n publicKey\\n );\\n }\\n\\n ////////////////////////////////////////////////////////////\\n // //\\n // Set Functions //\\n // //\\n ////////////////////////////////////////////////////////////\\n\\n function setRegistry(address _registry) public onlyOwner {\\n registry = _registry;\\n }\\n}\\n\",\"keccak256\":\"0x1f961c7313a6d24f0c1bfc4455a461eb25d329f85fea57e08a6fc159f9960a5a\",\"license\":\"LGPL-3.0-only\"}},\"version\":1}", + "bytecode": "0x6080346101d657601f610e7c38819003918201601f19168301916001600160401b038311848410176101db5780849260409485528339810103126101d657610052602061004b836101f1565b92016101f1565b600080516020610e5c83398151915254604081901c60ff16159290916001600160401b038316801590816101ce575b60011490816101c4575b1590816101bb575b506101aa576001600160401b03198316600117600080516020610e5c8339815191525561010f928461017f575b506100c961028d565b6100d161028d565b6100da33610205565b6100e26102bb565b600080546001600160a01b0319166001600160a01b039290921691909117905561010a6102bb565b610205565b610123575b604051610b5890816103048239f35b68ff000000000000000019600080516020610e5c8339815191525416600080516020610e5c833981519152557fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2602060405160018152a1610114565b6001600160481b0319166801000000000000000117600080516020610e5c83398151915255386100c0565b63f92ee8a960e01b60005260046000fd5b90501538610093565b303b15915061008b565b859150610081565b600080fd5b634e487b7160e01b600052604160045260246000fd5b51906001600160a01b03821682036101d657565b6001600160a01b03168015610277577f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c19930080546001600160a01b0319811683179091556001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a3565b631e4fbdf760e01b600052600060045260246000fd5b60ff600080516020610e5c8339815191525460401c16156102aa57565b631afcd79f60e31b60005260046000fd5b7f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300546001600160a01b031633036102ee57565b63118cdaa760e01b6000523360045260246000fdfe608080604052600436101561001357600080fd5b600090813560e01c90816329f73b9c14610480575080632b20a4f614610435578063485cc9551461023d578063715018a6146101a45780637b1039991461017e5780638da5cb5b14610138578063a91ee0dc146100f9578063f2fde38b146100cc5763f5e820fd1461008457600080fd5b346100c95760203660031901126100c9576100b1600260406100c593600435815260016020522001610921565b6040519182916020835260208301906109c5565b0390f35b80fd5b50346100c95760203660031901126100c9576100f66100e96108cc565b6100f1610ac3565b610a1d565b80f35b50346100c95760203660031901126100c9576001600160a01b0361011b6108cc565b610123610ac3565b166001600160a01b0319600054161760005580f35b50346100c957806003193601126100c95760206001600160a01b037f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c1993005416604051908152f35b50346100c957806003193601126100c9576001600160a01b036020915416604051908152f35b50346100c957806003193601126100c9576101bd610ac3565b806001600160a01b037f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300546001600160a01b031981167f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c19930055167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b50346100c95760403660031901126100c9576102576108cc565b602435906001600160a01b0382168203610431577ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00549160ff8360401c16159267ffffffffffffffff811680159081610429575b600114908161041f575b159081610416575b506104075767ffffffffffffffff1981166001177ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005561034392916001600160a01b0391856103c8575b50610310610b0b565b610318610b0b565b61032133610a1d565b610329610ac3565b166001600160a01b031960005416176000556100f1610ac3565b61034a5780f35b68ff0000000000000000197ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0054167ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00557fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2602060405160018152a180f35b68ffffffffffffffffff191668010000000000000001177ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005538610307565b63f92ee8a960e01b8552600485fd5b905015386102bd565b303b1591506102b5565b8591506102ab565b8280fd5b50346100c95760603660031901126100c957366064116100c957806001600160a01b03600492541633036104745760016020526334c2a65d60e11b8152fd5b6310f5403960e31b8152fd5b82346100c95760603660031901126100c9576004356024359267ffffffffffffffff841161043157366023850112156104315783600401359367ffffffffffffffff8511610880578460051b946104da6020870184610894565b82526020820190602482968201019036821161084457602401915b81831061085c575050506044359167ffffffffffffffff831161070b573660238401121561070b57826004013567ffffffffffffffff81116108485760405193610549601f8301601f191660200186610894565b8185523660248383010111610844578186926024602093018388013785010152610571610ac3565b80845260016020526040842060028101907fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a4706105ac83610921565b60208151910120036108355783519067ffffffffffffffff821161082157680100000000000000008211610821578054828255808310610806575b508790875260208720875b8381106107e95750505050835167ffffffffffffffff81116107d55761061882546108e7565b601f811161079a575b50806020601f821160011461073957879161072e575b508160011b916000199060031b1c19161790555b6001600160a01b0384541660405192604084019060208086015251809152606084019690865b81811061070f5750505061069283869796959603601f198101855284610894565b803b1561070b578392836106cd936106df6040519889968795869463d9bbec9560e01b865260048601526060602486015260648501906109c5565b838103600319016044850152906109c5565b03925af180156106fe576106f05780f35b6106f991610894565b818180f35b50604051903d90823e3d90fd5b8380fd5b82516001600160a01b0316895260209889019890920191600101610671565b905085015188610637565b8388528088209150601f198316885b81811061078257509083600194939210610769575b5050811b01905561064b565b87015160001960f88460031b161c19169055888061075d565b9192602060018192868c015181550194019201610748565b6107c59083885260208820601f840160051c810191602085106107cb575b601f0160051c0190610a06565b87610621565b90915081906107b8565b634e487b7160e01b86526041600452602486fd5b60019060206001600160a01b0385511694019381840155016105f2565b8188526020882061081b918101908401610a06565b886105e7565b634e487b7160e01b87526041600452602487fd5b63632a22bb60e01b8652600486fd5b8580fd5b634e487b7160e01b85526041600452602485fd5b82356001600160a01b038116810361087c578152602092830192016104f5565b8680fd5b634e487b7160e01b84526041600452602484fd5b90601f8019910116810190811067ffffffffffffffff8211176108b657604052565b634e487b7160e01b600052604160045260246000fd5b600435906001600160a01b03821682036108e257565b600080fd5b90600182811c92168015610917575b602083101461090157565b634e487b7160e01b600052602260045260246000fd5b91607f16916108f6565b9060405191826000825492610935846108e7565b80845293600181169081156109a3575060011461095c575b5061095a92500383610894565b565b90506000929192526020600020906000915b81831061098757505090602061095a928201013861094d565b602091935080600191548385890101520191019091849261096e565b90506020925061095a94915060ff191682840152151560051b8201013861094d565b919082519283825260005b8481106109f1575050826000602080949584010152601f8019910116010190565b806020809284010151828286010152016109d0565b818110610a11575050565b60008155600101610a06565b6001600160a01b03168015610aad576001600160a01b037f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c19930054826001600160a01b03198216177f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c19930055167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a3565b631e4fbdf760e01b600052600060045260246000fd5b6001600160a01b037f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c19930054163303610af657565b63118cdaa760e01b6000523360045260246000fd5b60ff7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005460401c1615610b3a57565b631afcd79f60e31b60005260046000fdfea164736f6c634300081a000af0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00", + "deployedBytecode": "0x608080604052600436101561001357600080fd5b600090813560e01c90816329f73b9c14610480575080632b20a4f614610435578063485cc9551461023d578063715018a6146101a45780637b1039991461017e5780638da5cb5b14610138578063a91ee0dc146100f9578063f2fde38b146100cc5763f5e820fd1461008457600080fd5b346100c95760203660031901126100c9576100b1600260406100c593600435815260016020522001610921565b6040519182916020835260208301906109c5565b0390f35b80fd5b50346100c95760203660031901126100c9576100f66100e96108cc565b6100f1610ac3565b610a1d565b80f35b50346100c95760203660031901126100c9576001600160a01b0361011b6108cc565b610123610ac3565b166001600160a01b0319600054161760005580f35b50346100c957806003193601126100c95760206001600160a01b037f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c1993005416604051908152f35b50346100c957806003193601126100c9576001600160a01b036020915416604051908152f35b50346100c957806003193601126100c9576101bd610ac3565b806001600160a01b037f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300546001600160a01b031981167f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c19930055167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b50346100c95760403660031901126100c9576102576108cc565b602435906001600160a01b0382168203610431577ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00549160ff8360401c16159267ffffffffffffffff811680159081610429575b600114908161041f575b159081610416575b506104075767ffffffffffffffff1981166001177ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005561034392916001600160a01b0391856103c8575b50610310610b0b565b610318610b0b565b61032133610a1d565b610329610ac3565b166001600160a01b031960005416176000556100f1610ac3565b61034a5780f35b68ff0000000000000000197ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0054167ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00557fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2602060405160018152a180f35b68ffffffffffffffffff191668010000000000000001177ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005538610307565b63f92ee8a960e01b8552600485fd5b905015386102bd565b303b1591506102b5565b8591506102ab565b8280fd5b50346100c95760603660031901126100c957366064116100c957806001600160a01b03600492541633036104745760016020526334c2a65d60e11b8152fd5b6310f5403960e31b8152fd5b82346100c95760603660031901126100c9576004356024359267ffffffffffffffff841161043157366023850112156104315783600401359367ffffffffffffffff8511610880578460051b946104da6020870184610894565b82526020820190602482968201019036821161084457602401915b81831061085c575050506044359167ffffffffffffffff831161070b573660238401121561070b57826004013567ffffffffffffffff81116108485760405193610549601f8301601f191660200186610894565b8185523660248383010111610844578186926024602093018388013785010152610571610ac3565b80845260016020526040842060028101907fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a4706105ac83610921565b60208151910120036108355783519067ffffffffffffffff821161082157680100000000000000008211610821578054828255808310610806575b508790875260208720875b8381106107e95750505050835167ffffffffffffffff81116107d55761061882546108e7565b601f811161079a575b50806020601f821160011461073957879161072e575b508160011b916000199060031b1c19161790555b6001600160a01b0384541660405192604084019060208086015251809152606084019690865b81811061070f5750505061069283869796959603601f198101855284610894565b803b1561070b578392836106cd936106df6040519889968795869463d9bbec9560e01b865260048601526060602486015260648501906109c5565b838103600319016044850152906109c5565b03925af180156106fe576106f05780f35b6106f991610894565b818180f35b50604051903d90823e3d90fd5b8380fd5b82516001600160a01b0316895260209889019890920191600101610671565b905085015188610637565b8388528088209150601f198316885b81811061078257509083600194939210610769575b5050811b01905561064b565b87015160001960f88460031b161c19169055888061075d565b9192602060018192868c015181550194019201610748565b6107c59083885260208820601f840160051c810191602085106107cb575b601f0160051c0190610a06565b87610621565b90915081906107b8565b634e487b7160e01b86526041600452602486fd5b60019060206001600160a01b0385511694019381840155016105f2565b8188526020882061081b918101908401610a06565b886105e7565b634e487b7160e01b87526041600452602487fd5b63632a22bb60e01b8652600486fd5b8580fd5b634e487b7160e01b85526041600452602485fd5b82356001600160a01b038116810361087c578152602092830192016104f5565b8680fd5b634e487b7160e01b84526041600452602484fd5b90601f8019910116810190811067ffffffffffffffff8211176108b657604052565b634e487b7160e01b600052604160045260246000fd5b600435906001600160a01b03821682036108e257565b600080fd5b90600182811c92168015610917575b602083101461090157565b634e487b7160e01b600052602260045260246000fd5b91607f16916108f6565b9060405191826000825492610935846108e7565b80845293600181169081156109a3575060011461095c575b5061095a92500383610894565b565b90506000929192526020600020906000915b81831061098757505090602061095a928201013861094d565b602091935080600191548385890101520191019091849261096e565b90506020925061095a94915060ff191682840152151560051b8201013861094d565b919082519283825260005b8481106109f1575050826000602080949584010152601f8019910116010190565b806020809284010151828286010152016109d0565b818110610a11575050565b60008155600101610a06565b6001600160a01b03168015610aad576001600160a01b037f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c19930054826001600160a01b03198216177f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c19930055167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a3565b631e4fbdf760e01b600052600060045260246000fd5b6001600160a01b037f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c19930054163303610af657565b63118cdaa760e01b6000523360045260246000fd5b60ff7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005460401c1615610b3a57565b631afcd79f60e31b60005260046000fdfea164736f6c634300081a000a", + "devdoc": { + "errors": { + "InvalidInitialization()": [ + { + "details": "The contract is already initialized." + } + ], + "NotInitializing()": [ + { + "details": "The contract is not initializing." + } + ], + "OwnableInvalidOwner(address)": [ + { + "details": "The owner is not a valid owner account. (eg. `address(0)`)" + } + ], + "OwnableUnauthorizedAccount(address)": [ + { + "details": "The caller account is not authorized to perform an operation." + } + ] + }, + "events": { + "Initialized(uint64)": { + "details": "Triggered when the contract has been initialized or reinitialized." + } + }, + "kind": "dev", + "methods": { + "owner()": { + "details": "Returns the address of the current owner." + }, + "renounceOwnership()": { + "details": "Leaves the contract without owner. It will not be possible to call `onlyOwner` functions. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby disabling any functionality that is only available to the owner." + }, + "transferOwnership(address)": { + "details": "Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner." + } + }, + "version": 1 + }, + "userdoc": { + "kind": "user", + "methods": {}, + "version": 1 + }, + "storageLayout": { + "storage": [ + { + "astId": 2140, + "contract": "contracts/registry/NaiveRegistryFilter.sol:NaiveRegistryFilter", + "label": "registry", + "offset": 0, + "slot": "0", + "type": "t_address" + }, + { + "astId": 2145, + "contract": "contracts/registry/NaiveRegistryFilter.sol:NaiveRegistryFilter", + "label": "committees", + "offset": 0, + "slot": "1", + "type": "t_mapping(t_uint256,t_struct(Committee)2138_storage)" + } + ], + "types": { + "t_address": { + "encoding": "inplace", + "label": "address", + "numberOfBytes": "20" + }, + "t_array(t_address)dyn_storage": { + "base": "t_address", + "encoding": "dynamic_array", + "label": "address[]", + "numberOfBytes": "32" + }, + "t_array(t_uint32)2_storage": { + "base": "t_uint32", + "encoding": "inplace", + "label": "uint32[2]", + "numberOfBytes": "32" + }, + "t_bytes_storage": { + "encoding": "bytes", + "label": "bytes", + "numberOfBytes": "32" + }, + "t_mapping(t_uint256,t_struct(Committee)2138_storage)": { + "encoding": "mapping", + "key": "t_uint256", + "label": "mapping(uint256 => struct NaiveRegistryFilter.Committee)", + "numberOfBytes": "32", + "value": "t_struct(Committee)2138_storage" + }, + "t_struct(Committee)2138_storage": { + "encoding": "inplace", + "label": "struct NaiveRegistryFilter.Committee", + "members": [ + { + "astId": 2131, + "contract": "contracts/registry/NaiveRegistryFilter.sol:NaiveRegistryFilter", + "label": "nodes", + "offset": 0, + "slot": "0", + "type": "t_array(t_address)dyn_storage" + }, + { + "astId": 2135, + "contract": "contracts/registry/NaiveRegistryFilter.sol:NaiveRegistryFilter", + "label": "threshold", + "offset": 0, + "slot": "1", + "type": "t_array(t_uint32)2_storage" + }, + { + "astId": 2137, + "contract": "contracts/registry/NaiveRegistryFilter.sol:NaiveRegistryFilter", + "label": "publicKey", + "offset": 0, + "slot": "2", + "type": "t_bytes_storage" + } + ], + "numberOfBytes": "96" + }, + "t_uint256": { + "encoding": "inplace", + "label": "uint256", + "numberOfBytes": "32" + }, + "t_uint32": { + "encoding": "inplace", + "label": "uint32", + "numberOfBytes": "4" + } + } + } +} diff --git a/packages/evm/deployments/sepolia/solcInputs/d0e6e4f19028714f394c36db62dff2be.json b/packages/evm/deployments/sepolia/solcInputs/d0e6e4f19028714f394c36db62dff2be.json new file mode 100644 index 00000000..eaf4c996 --- /dev/null +++ b/packages/evm/deployments/sepolia/solcInputs/d0e6e4f19028714f394c36db62dff2be.json @@ -0,0 +1,93 @@ +{ + "language": "Solidity", + "sources": { + "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)\n\npragma solidity ^0.8.20;\n\nimport {ContextUpgradeable} from \"../utils/ContextUpgradeable.sol\";\nimport {Initializable} from \"../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * The initial owner is set to the address provided by the deployer. This can\n * later be changed with {transferOwnership}.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\nabstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {\n /// @custom:storage-location erc7201:openzeppelin.storage.Ownable\n struct OwnableStorage {\n address _owner;\n }\n\n // keccak256(abi.encode(uint256(keccak256(\"openzeppelin.storage.Ownable\")) - 1)) & ~bytes32(uint256(0xff))\n bytes32 private constant OwnableStorageLocation = 0x9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300;\n\n function _getOwnableStorage() private pure returns (OwnableStorage storage $) {\n assembly {\n $.slot := OwnableStorageLocation\n }\n }\n\n /**\n * @dev The caller account is not authorized to perform an operation.\n */\n error OwnableUnauthorizedAccount(address account);\n\n /**\n * @dev The owner is not a valid owner account. (eg. `address(0)`)\n */\n error OwnableInvalidOwner(address owner);\n\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n /**\n * @dev Initializes the contract setting the address provided by the deployer as the initial owner.\n */\n function __Ownable_init(address initialOwner) internal onlyInitializing {\n __Ownable_init_unchained(initialOwner);\n }\n\n function __Ownable_init_unchained(address initialOwner) internal onlyInitializing {\n if (initialOwner == address(0)) {\n revert OwnableInvalidOwner(address(0));\n }\n _transferOwnership(initialOwner);\n }\n\n /**\n * @dev Throws if called by any account other than the owner.\n */\n modifier onlyOwner() {\n _checkOwner();\n _;\n }\n\n /**\n * @dev Returns the address of the current owner.\n */\n function owner() public view virtual returns (address) {\n OwnableStorage storage $ = _getOwnableStorage();\n return $._owner;\n }\n\n /**\n * @dev Throws if the sender is not the owner.\n */\n function _checkOwner() internal view virtual {\n if (owner() != _msgSender()) {\n revert OwnableUnauthorizedAccount(_msgSender());\n }\n }\n\n /**\n * @dev Leaves the contract without owner. It will not be possible to call\n * `onlyOwner` functions. Can only be called by the current owner.\n *\n * NOTE: Renouncing ownership will leave the contract without an owner,\n * thereby disabling any functionality that is only available to the owner.\n */\n function renounceOwnership() public virtual onlyOwner {\n _transferOwnership(address(0));\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Can only be called by the current owner.\n */\n function transferOwnership(address newOwner) public virtual onlyOwner {\n if (newOwner == address(0)) {\n revert OwnableInvalidOwner(address(0));\n }\n _transferOwnership(newOwner);\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Internal function without access restriction.\n */\n function _transferOwnership(address newOwner) internal virtual {\n OwnableStorage storage $ = _getOwnableStorage();\n address oldOwner = $._owner;\n $._owner = newOwner;\n emit OwnershipTransferred(oldOwner, newOwner);\n }\n}\n" + }, + "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/Initializable.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed\n * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an\n * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer\n * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.\n *\n * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be\n * reused. This mechanism prevents re-execution of each \"step\" but allows the creation of new initialization steps in\n * case an upgrade adds a module that needs to be initialized.\n *\n * For example:\n *\n * [.hljs-theme-light.nopadding]\n * ```solidity\n * contract MyToken is ERC20Upgradeable {\n * function initialize() initializer public {\n * __ERC20_init(\"MyToken\", \"MTK\");\n * }\n * }\n *\n * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {\n * function initializeV2() reinitializer(2) public {\n * __ERC20Permit_init(\"MyToken\");\n * }\n * }\n * ```\n *\n * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as\n * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.\n *\n * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure\n * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.\n *\n * [CAUTION]\n * ====\n * Avoid leaving a contract uninitialized.\n *\n * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation\n * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke\n * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:\n *\n * [.hljs-theme-light.nopadding]\n * ```\n * /// @custom:oz-upgrades-unsafe-allow constructor\n * constructor() {\n * _disableInitializers();\n * }\n * ```\n * ====\n */\nabstract contract Initializable {\n /**\n * @dev Storage of the initializable contract.\n *\n * It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions\n * when using with upgradeable contracts.\n *\n * @custom:storage-location erc7201:openzeppelin.storage.Initializable\n */\n struct InitializableStorage {\n /**\n * @dev Indicates that the contract has been initialized.\n */\n uint64 _initialized;\n /**\n * @dev Indicates that the contract is in the process of being initialized.\n */\n bool _initializing;\n }\n\n // keccak256(abi.encode(uint256(keccak256(\"openzeppelin.storage.Initializable\")) - 1)) & ~bytes32(uint256(0xff))\n bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00;\n\n /**\n * @dev The contract is already initialized.\n */\n error InvalidInitialization();\n\n /**\n * @dev The contract is not initializing.\n */\n error NotInitializing();\n\n /**\n * @dev Triggered when the contract has been initialized or reinitialized.\n */\n event Initialized(uint64 version);\n\n /**\n * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,\n * `onlyInitializing` functions can be used to initialize parent contracts.\n *\n * Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any\n * number of times. This behavior in the constructor can be useful during testing and is not expected to be used in\n * production.\n *\n * Emits an {Initialized} event.\n */\n modifier initializer() {\n // solhint-disable-next-line var-name-mixedcase\n InitializableStorage storage $ = _getInitializableStorage();\n\n // Cache values to avoid duplicated sloads\n bool isTopLevelCall = !$._initializing;\n uint64 initialized = $._initialized;\n\n // Allowed calls:\n // - initialSetup: the contract is not in the initializing state and no previous version was\n // initialized\n // - construction: the contract is initialized at version 1 (no reininitialization) and the\n // current contract is just being deployed\n bool initialSetup = initialized == 0 && isTopLevelCall;\n bool construction = initialized == 1 && address(this).code.length == 0;\n\n if (!initialSetup && !construction) {\n revert InvalidInitialization();\n }\n $._initialized = 1;\n if (isTopLevelCall) {\n $._initializing = true;\n }\n _;\n if (isTopLevelCall) {\n $._initializing = false;\n emit Initialized(1);\n }\n }\n\n /**\n * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the\n * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be\n * used to initialize parent contracts.\n *\n * A reinitializer may be used after the original initialization step. This is essential to configure modules that\n * are added through upgrades and that require initialization.\n *\n * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`\n * cannot be nested. If one is invoked in the context of another, execution will revert.\n *\n * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in\n * a contract, executing them in the right order is up to the developer or operator.\n *\n * WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization.\n *\n * Emits an {Initialized} event.\n */\n modifier reinitializer(uint64 version) {\n // solhint-disable-next-line var-name-mixedcase\n InitializableStorage storage $ = _getInitializableStorage();\n\n if ($._initializing || $._initialized >= version) {\n revert InvalidInitialization();\n }\n $._initialized = version;\n $._initializing = true;\n _;\n $._initializing = false;\n emit Initialized(version);\n }\n\n /**\n * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the\n * {initializer} and {reinitializer} modifiers, directly or indirectly.\n */\n modifier onlyInitializing() {\n _checkInitializing();\n _;\n }\n\n /**\n * @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}.\n */\n function _checkInitializing() internal view virtual {\n if (!_isInitializing()) {\n revert NotInitializing();\n }\n }\n\n /**\n * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.\n * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized\n * to any version. It is recommended to use this to lock implementation contracts that are designed to be called\n * through proxies.\n *\n * Emits an {Initialized} event the first time it is successfully executed.\n */\n function _disableInitializers() internal virtual {\n // solhint-disable-next-line var-name-mixedcase\n InitializableStorage storage $ = _getInitializableStorage();\n\n if ($._initializing) {\n revert InvalidInitialization();\n }\n if ($._initialized != type(uint64).max) {\n $._initialized = type(uint64).max;\n emit Initialized(type(uint64).max);\n }\n }\n\n /**\n * @dev Returns the highest version that has been initialized. See {reinitializer}.\n */\n function _getInitializedVersion() internal view returns (uint64) {\n return _getInitializableStorage()._initialized;\n }\n\n /**\n * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.\n */\n function _isInitializing() internal view returns (bool) {\n return _getInitializableStorage()._initializing;\n }\n\n /**\n * @dev Returns a pointer to the storage namespace.\n */\n // solhint-disable-next-line var-name-mixedcase\n function _getInitializableStorage() private pure returns (InitializableStorage storage $) {\n assembly {\n $.slot := INITIALIZABLE_STORAGE\n }\n }\n}\n" + }, + "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\npragma solidity ^0.8.20;\nimport {Initializable} from \"../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract ContextUpgradeable is Initializable {\n function __Context_init() internal onlyInitializing {\n }\n\n function __Context_init_unchained() internal onlyInitializing {\n }\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n" + }, + "contracts/Enclave.sol": { + "content": "// SPDX-License-Identifier: LGPL-3.0-only\npragma solidity >=0.8.26;\n\nimport {\n IEnclave,\n E3,\n IComputationModule,\n IExecutionModule\n} from \"./interfaces/IEnclave.sol\";\nimport { ICyphernodeRegistry } from \"./interfaces/ICyphernodeRegistry.sol\";\nimport { IInputValidator } from \"./interfaces/IInputValidator.sol\";\nimport { IOutputVerifier } from \"./interfaces/IOutputVerifier.sol\";\nimport {\n OwnableUpgradeable\n} from \"@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol\";\n\ncontract Enclave is IEnclave, OwnableUpgradeable {\n ////////////////////////////////////////////////////////////\n // //\n // Storage Variables //\n // //\n ////////////////////////////////////////////////////////////\n\n ICyphernodeRegistry public cyphernodeRegistry; // address of the Cyphernode registry.\n uint256 public maxDuration; // maximum duration of a computation in seconds.\n uint256 public nexte3Id; // ID of the next E3.\n uint256 public requests; // total number of requests made to Enclave.\n\n // TODO: should computation and execution modules be explicitly allowed?\n // My intuition is that an allowlist is required since they impose slashing conditions.\n // But perhaps this is one place where node pools might be utilized, allowing nodes to\n // opt in to being selected for specific computations, along with the corresponding slashing conditions.\n // This would reduce the governance overhead for Enclave.\n\n // Mapping of allowed computation modules.\n mapping(IComputationModule computationModule => bool allowed)\n public computationModules;\n\n // Mapping of allowed execution modules.\n mapping(IExecutionModule executionModule => bool allowed)\n public executionModules;\n\n // Mapping of E3s.\n mapping(uint256 id => E3 e3) public e3s;\n\n ////////////////////////////////////////////////////////////\n // //\n // Errors //\n // //\n ////////////////////////////////////////////////////////////\n\n error CommitteeSelectionFailed();\n error ComputationModuleNotAllowed(IComputationModule computationModule);\n error E3AlreadyActivated(uint256 e3Id);\n error E3Expired();\n error E3NotActivated(uint256 e3Id);\n error E3NotReady();\n error E3DoesNotExist(uint256 e3Id);\n error ModuleAlreadyEnabled(address module);\n error ModuleNotEnabled(address module);\n error InputDeadlinePassed(uint256 e3Id, uint256 expiration);\n error InputDeadlineNotPassed(uint256 e3Id, uint256 expiration);\n error InvalidComputation();\n error InvalidExecutionModuleSetup();\n error InvalidCyphernodeRegistry(ICyphernodeRegistry cyphernodeRegistry);\n error InvalidInput();\n error InvalidDuration(uint256 duration);\n error InvalidOutput(bytes output);\n error InvalidStartWindow();\n error InvalidThreshold(uint32[2] threshold);\n error CiphertextOutputAlreadyPublished(uint256 e3Id);\n error CiphertextOutputNotPublished(uint256 e3Id);\n error PaymentRequired(uint256 value);\n error PlaintextOutputAlreadyPublished(uint256 e3Id);\n\n ////////////////////////////////////////////////////////////\n // //\n // Initialization //\n // //\n ////////////////////////////////////////////////////////////\n\n /// @param _owner The owner of this contract\n /// @param _maxDuration The maximum duration of a computation in seconds\n constructor(\n address _owner,\n ICyphernodeRegistry _cyphernodeRegistry,\n uint256 _maxDuration\n ) {\n initialize(_owner, _cyphernodeRegistry, _maxDuration);\n }\n\n /// @param _owner The owner of this contract\n /// @param _maxDuration The maximum duration of a computation in seconds\n function initialize(\n address _owner,\n ICyphernodeRegistry _cyphernodeRegistry,\n uint256 _maxDuration\n ) public initializer {\n __Ownable_init(msg.sender);\n setMaxDuration(_maxDuration);\n setCyphernodeRegistry(_cyphernodeRegistry);\n if (_owner != owner()) transferOwnership(_owner);\n }\n\n ////////////////////////////////////////////////////////////\n // //\n // Core Entrypoints //\n // //\n ////////////////////////////////////////////////////////////\n\n function request(\n address filter,\n uint32[2] calldata threshold,\n uint256[2] calldata startWindow,\n uint256 duration,\n IComputationModule computationModule,\n bytes memory computationParams,\n IExecutionModule executionModule,\n bytes memory emParams\n ) external payable returns (uint256 e3Id, E3 memory e3) {\n // TODO: allow for other payment methods or only native tokens?\n // TODO: should payment checks be somewhere else? Perhaps in the computation module or cyphernode registry?\n require(msg.value > 0, PaymentRequired(msg.value));\n require(\n threshold[1] >= threshold[0] && threshold[0] > 0,\n InvalidThreshold(threshold)\n );\n require(\n // TODO: do we need a minimum start window to allow time for committee selection?\n startWindow[1] >= startWindow[0] &&\n startWindow[1] >= block.timestamp,\n InvalidStartWindow()\n );\n require(\n duration > 0 && duration <= maxDuration,\n InvalidDuration(duration)\n );\n require(\n computationModules[computationModule],\n ComputationModuleNotAllowed(computationModule)\n );\n require(\n executionModules[executionModule],\n ModuleNotEnabled(address(executionModule))\n );\n\n // TODO: should IDs be incremental or produced deterministically?\n e3Id = nexte3Id;\n nexte3Id++;\n\n IInputValidator inputValidator = computationModule.validate(\n computationParams\n );\n require(address(inputValidator) != address(0), InvalidComputation());\n\n // TODO: validate that the requested computation can be performed by the given execution module.\n IOutputVerifier outputVerifier = executionModule.validate(emParams);\n require(\n address(outputVerifier) != address(0),\n InvalidExecutionModuleSetup()\n );\n\n e3 = E3({\n threshold: threshold,\n startWindow: startWindow,\n duration: duration,\n expiration: 0,\n computationModule: computationModule,\n executionModule: executionModule,\n inputValidator: inputValidator,\n outputVerifier: outputVerifier,\n committeePublicKey: hex\"\",\n inputs: new bytes[](0),\n ciphertextOutput: hex\"\",\n plaintextOutput: hex\"\"\n });\n e3s[e3Id] = e3;\n\n require(\n cyphernodeRegistry.requestCommittee(e3Id, filter, threshold),\n CommitteeSelectionFailed()\n );\n\n emit E3Requested(\n e3Id,\n e3s[e3Id],\n filter,\n computationModule,\n executionModule\n );\n }\n\n function activate(uint256 e3Id) external returns (bool success) {\n // Note: we could load this into a storage pointer, and do the sets there\n // Requires a mew internal _getter that returns storage\n E3 memory e3 = getE3(e3Id);\n require(e3.expiration == 0, E3AlreadyActivated(e3Id));\n require(e3.startWindow[0] <= block.timestamp, E3NotReady());\n // TODO: handle what happens to the payment if the start window has passed.\n require(e3.startWindow[1] >= block.timestamp, E3Expired());\n\n bytes memory publicKey = cyphernodeRegistry.committeePublicKey(e3Id);\n // Note: This check feels weird\n require(publicKey.length > 0, CommitteeSelectionFailed());\n\n e3s[e3Id].expiration = block.timestamp + e3.duration;\n e3s[e3Id].committeePublicKey = publicKey;\n\n emit E3Activated(e3Id, e3.expiration, e3.committeePublicKey);\n\n return true;\n }\n\n function publishInput(\n uint256 e3Id,\n bytes memory data\n ) external returns (bool success) {\n E3 memory e3 = getE3(e3Id);\n\n // Note: if we make 0 a no expiration, this has to be refactored\n require(e3.expiration > 0, E3NotActivated(e3Id));\n // TODO: should we have an input window, including both a start and end timestamp?\n require(\n e3.expiration > block.timestamp,\n InputDeadlinePassed(e3Id, e3.expiration)\n );\n bytes memory input;\n (input, success) = e3.inputValidator.validate(msg.sender, data);\n require(success, InvalidInput());\n // TODO: probably better to accumulate inputs, rather than just dumping them in storage.\n e3s[e3Id].inputs.push(input);\n emit InputPublished(e3Id, input);\n }\n\n function publishCiphertextOutput(\n uint256 e3Id,\n bytes memory data\n ) external returns (bool success) {\n E3 memory e3 = getE3(e3Id);\n // Note: if we make 0 a no expiration, this has to be refactored\n require(e3.expiration > 0, E3NotActivated(e3Id));\n require(\n e3.expiration <= block.timestamp,\n InputDeadlineNotPassed(e3Id, e3.expiration)\n );\n // TODO: should the output verifier be able to change its mind?\n //i.e. should we be able to call this multiple times?\n require(\n e3.ciphertextOutput.length == 0,\n CiphertextOutputAlreadyPublished(e3Id)\n );\n bytes memory output;\n (output, success) = e3.outputVerifier.verify(e3Id, data);\n require(success, InvalidOutput(output));\n e3s[e3Id].ciphertextOutput = output;\n\n emit CiphertextOutputPublished(e3Id, output);\n }\n\n function publishPlaintextOutput(\n uint256 e3Id,\n bytes memory data\n ) external returns (bool success) {\n E3 memory e3 = getE3(e3Id);\n // Note: if we make 0 a no expiration, this has to be refactored\n require(e3.expiration > 0, E3NotActivated(e3Id));\n require(\n e3.ciphertextOutput.length > 0,\n CiphertextOutputNotPublished(e3Id)\n );\n require(\n e3.plaintextOutput.length == 0,\n PlaintextOutputAlreadyPublished(e3Id)\n );\n bytes memory output;\n (output, success) = e3.computationModule.verify(e3Id, data);\n require(success, InvalidOutput(output));\n e3s[e3Id].plaintextOutput = output;\n\n emit PlaintextOutputPublished(e3Id, output);\n }\n\n ////////////////////////////////////////////////////////////\n // //\n // Set Functions //\n // //\n ////////////////////////////////////////////////////////////\n\n function setMaxDuration(\n uint256 _maxDuration\n ) public onlyOwner returns (bool success) {\n maxDuration = _maxDuration;\n success = true;\n emit MaxDurationSet(_maxDuration);\n }\n\n function setCyphernodeRegistry(\n ICyphernodeRegistry _cyphernodeRegistry\n ) public onlyOwner returns (bool success) {\n require(\n address(_cyphernodeRegistry) != address(0) &&\n _cyphernodeRegistry != cyphernodeRegistry,\n InvalidCyphernodeRegistry(_cyphernodeRegistry)\n );\n cyphernodeRegistry = _cyphernodeRegistry;\n success = true;\n emit CyphernodeRegistrySet(address(_cyphernodeRegistry));\n }\n\n function enableComputationModule(\n IComputationModule computationModule\n ) public onlyOwner returns (bool success) {\n require(\n !computationModules[computationModule],\n ModuleAlreadyEnabled(address(computationModule))\n );\n computationModules[computationModule] = true;\n success = true;\n emit ComputationModuleEnabled(computationModule);\n }\n\n function enableExecutionModule(\n IExecutionModule executionModule\n ) public onlyOwner returns (bool success) {\n require(\n !executionModules[executionModule],\n ModuleAlreadyEnabled(address(executionModule))\n );\n executionModules[executionModule] = true;\n success = true;\n emit ExecutionModuleEnabled(executionModule);\n }\n\n function disableComputationModule(\n IComputationModule computationModule\n ) public onlyOwner returns (bool success) {\n require(\n computationModules[computationModule],\n ModuleNotEnabled(address(computationModule))\n );\n delete computationModules[computationModule];\n success = true;\n emit ComputationModuleDisabled(computationModule);\n }\n\n function disableExecutionModule(\n IExecutionModule executionModule\n ) public onlyOwner returns (bool success) {\n require(\n executionModules[executionModule],\n ModuleNotEnabled(address(executionModule))\n );\n delete executionModules[executionModule];\n success = true;\n emit ExecutionModuleDisabled(executionModule);\n }\n\n ////////////////////////////////////////////////////////////\n // //\n // Get Functions //\n // //\n ////////////////////////////////////////////////////////////\n\n function getE3(uint256 e3Id) public view returns (E3 memory e3) {\n e3 = e3s[e3Id];\n require(\n e3.computationModule != IComputationModule(address(0)),\n E3DoesNotExist(e3Id)\n );\n }\n}\n" + }, + "contracts/interfaces/IComputationModule.sol": { + "content": "// SPDX-License-Identifier: LGPL-3.0-only\npragma solidity >=0.8.26;\n\nimport { IInputValidator } from \"./IInputValidator.sol\";\n\ninterface IComputationModule {\n /// @notice This function should be called by the Enclave contract to validate the computation parameters.\n /// @param params ABI encoded computation parameters.\n /// @return inputValidator The input validator to be used for the computation.\n function validate(\n bytes calldata params\n ) external returns (IInputValidator inputValidator);\n\n /// @notice This function should be called by the Enclave contract to verify the decrypted output of an E3.\n /// @param e3Id ID of the E3.\n /// @param outputData ABI encoded output data to be verified.\n /// @return output The output data to be published.\n /// @return success Whether the output data is valid.\n function verify(\n uint256 e3Id,\n bytes memory outputData\n ) external returns (bytes memory output, bool success);\n}\n" + }, + "contracts/interfaces/ICyphernodeRegistry.sol": { + "content": "// SPDX-License-Identifier: LGPL-3.0-only\npragma solidity >=0.8.26;\n\ninterface ICyphernodeRegistry {\n /// @notice This event MUST be emitted when a committee is selected for an E3.\n /// @param e3Id ID of the E3 for which the committee was selected.\n /// @param filter Address of the contract that will coordinate committee selection.\n /// @param threshold The M/N threshold for the committee.\n event CommitteeRequested(\n uint256 indexed e3Id,\n address filter,\n uint32[2] threshold\n );\n\n /// @notice This event MUST be emitted when a committee is selected for an E3.\n /// @param e3Id ID of the E3 for which the committee was selected.\n /// @param publicKey Public key of the committee.\n event CommitteePublished(uint256 indexed e3Id, bytes publicKey);\n\n /// @notice This event MUST be emitted when `enclave` is set.\n /// @param enclave Address of the enclave contract.\n event EnclaveSet(address indexed enclave);\n\n /// @notice This event MUST be emitted when a cyphernode is added to the registry.\n event CyphernodeAdded(address indexed node);\n\n /// @notice This event MUST be emitted when a cyphernode is removed from the registry.\n event CyphernodeRemoved(address indexed node);\n\n function isCyphernodeEligible(address cyphernode) external returns (bool);\n\n /// @notice Initiates the committee selection process for a specified E3.\n /// @dev This function MUST revert when not called by the Enclave contract.\n /// @param e3Id ID of the E3 for which to select the committee.\n /// @param filter The address of the filter responsible for the committee selection process.\n /// @param threshold The M/N threshold for the committee.\n /// @return success True if committee selection was successfully initiated.\n function requestCommittee(\n uint256 e3Id,\n address filter,\n uint32[2] calldata threshold\n ) external returns (bool success);\n\n /// @notice Publishes the public key resulting from the committee selection process.\n /// @dev This function MUST revert if not called by the previously selected filter.\n /// @param e3Id ID of the E3 for which to select the committee.\n /// @param publicKey The public key generated by the selected committee.\n function publishCommittee(\n uint256 e3Id,\n bytes calldata proof,\n bytes calldata publicKey\n ) external;\n\n /// @notice This function should be called by the Enclave contract to get the public key of a committee.\n /// @dev This function MUST revert if no committee has been requested for the given E3.\n /// @dev This function MUST revert if the committee has not yet published a public key.\n /// @param e3Id ID of the E3 for which to get the committee public key.\n /// @return publicKey The public key of the committee.\n function committeePublicKey(\n uint256 e3Id\n ) external view returns (bytes memory);\n}\n" + }, + "contracts/interfaces/IE3.sol": { + "content": "// SPDX-License-Identifier: LGPL-3.0-only\npragma solidity >=0.8.26;\n\nimport { IInputValidator } from \"./IInputValidator.sol\";\nimport { IExecutionModule } from \"./IExecutionModule.sol\";\nimport { IComputationModule } from \"./IComputationModule.sol\";\nimport { IOutputVerifier } from \"./IOutputVerifier.sol\";\n\n/// @title E3 struct\n/// @notice This struct represents an E3 computation.\n/// @param threshold M/N threshold for the committee.\n/// @param startWindow Start window for the computation: index zero is minimum, index 1 is the maxium.\n/// @param duration Duration of the E3.\n/// @param expiration Timestamp when committee duties expire.\n/// @param computationModule Address of the computation module contract.\n/// @param executionModule Address of the execution module contract.\n/// @param inputValidator Address of the input validator contract.\n/// @param outputVerifier Address of the output verifier contract.\n/// @param committeeId ID of the selected committee.\n/// @param ciphertextOutput Encrypted output data.\n/// @param plaintextOutput Decrypted output data.\nstruct E3 {\n uint32[2] threshold;\n uint256[2] startWindow;\n uint256 duration;\n uint256 expiration;\n IComputationModule computationModule;\n IExecutionModule executionModule;\n IInputValidator inputValidator;\n IOutputVerifier outputVerifier;\n bytes committeePublicKey;\n bytes[] inputs;\n bytes ciphertextOutput;\n bytes plaintextOutput;\n}\n" + }, + "contracts/interfaces/IEnclave.sol": { + "content": "// SPDX-License-Identifier: LGPL-3.0-only\npragma solidity >=0.8.26;\n\nimport { E3, IComputationModule, IExecutionModule } from \"./IE3.sol\";\n\ninterface IEnclave {\n ////////////////////////////////////////////////////////////\n // //\n // Events //\n // //\n ////////////////////////////////////////////////////////////\n\n /// @notice This event MUST be emitted when an Encrypted Execution Environment (E3) is successfully requested.\n /// @param e3Id ID of the E3.\n /// @param e3 Details of the E3.\n /// @param filter Address of the pool of nodes from which the Cypher Node committee was selected.\n /// @param computationModule Address of the Computation module selected.\n /// @param executionModule Address of the execution module selected.\n event E3Requested(\n uint256 e3Id,\n E3 e3,\n address filter,\n IComputationModule indexed computationModule,\n IExecutionModule indexed executionModule\n );\n\n /// @notice This event MUST be emitted when an Encrypted Execution Environment (E3) is successfully activated.\n /// @param e3Id ID of the E3.\n /// @param expiration Timestamp when committee duties expire.\n /// @param committeePublicKey Public key of the committee.\n event E3Activated(\n uint256 e3Id,\n uint256 expiration,\n bytes committeePublicKey\n );\n\n /// @notice This event MUST be emitted when an input to an Encrypted Execution Environment (E3) is\n /// successfully published.\n /// @param e3Id ID of the E3.\n /// @param data ABI encoded input data.\n event InputPublished(uint256 indexed e3Id, bytes data);\n\n /// @notice This event MUST be emitted when the plaintext output of an Encrypted Execution Environment (E3)\n /// is successfully published.\n /// @param e3Id ID of the E3.\n /// @param plaintextOutput ABI encoded plaintext output.\n event PlaintextOutputPublished(uint256 indexed e3Id, bytes plaintextOutput);\n\n /// @notice This event MUST be emitted when the ciphertext output of an Encrypted Execution Environment (E3)\n /// is successfully published.\n /// @param e3Id ID of the E3.\n /// @param ciphertextOutput ABI encoded ciphertext output.\n event CiphertextOutputPublished(\n uint256 indexed e3Id,\n bytes ciphertextOutput\n );\n\n /// @notice This event MUST be emitted any time the `maxDuration` is set.\n /// @param maxDuration The maximum duration of a computation in seconds.\n event MaxDurationSet(uint256 maxDuration);\n\n /// @notice This event MUST be emitted any time the CyphernodeRegistry is set.\n /// @param cyphernodeRegistry The address of the CyphernodeRegistry contract.\n event CyphernodeRegistrySet(address cyphernodeRegistry);\n\n /// @notice This event MUST be emitted any time a computation module is enabled.\n /// @param computationModule The address of the computation module.\n event ComputationModuleEnabled(IComputationModule computationModule);\n\n /// @notice This event MUST be emitted any time a computation module is disabled.\n /// @param computationModule The address of the computation module.\n event ComputationModuleDisabled(IComputationModule computationModule);\n\n /// @notice This event MUST be emitted any time an execution module is enabled.\n /// @param executionModule The address of the execution module.\n event ExecutionModuleEnabled(IExecutionModule executionModule);\n\n /// @notice This event MUST be emitted any time an execution module is disabled.\n /// @param executionModule The address of the execution module.\n event ExecutionModuleDisabled(IExecutionModule executionModule);\n\n ////////////////////////////////////////////////////////////\n // //\n // Core Entrypoints //\n // //\n ////////////////////////////////////////////////////////////\n\n /// @notice This function should be called to request a computation within an Encrypted Execution Environment (E3).\n /// @dev This function MUST emit the E3Requested event.\n /// @param filter IDs of the pool of nodes from which to select the committee.\n /// @param threshold The M/N threshold for the committee.\n /// @param duration The duration of the computation in seconds.\n /// @param computationModule Address of the computation module.\n /// @param computationParams ABI encoded computation parameters.\n /// @param executionModule Address of the execution module.\n /// @param emParams ABI encoded execution module parameters.\n /// @return e3Id ID of the E3.\n /// @return e3 The E3 struct.\n function request(\n address filter,\n uint32[2] calldata threshold,\n uint256[2] calldata startWindow,\n uint256 duration,\n IComputationModule computationModule,\n bytes memory computationParams,\n IExecutionModule executionModule,\n bytes memory emParams\n ) external payable returns (uint256 e3Id, E3 memory e3);\n\n /// @notice This function should be called to activate an Encrypted Execution Environment (E3) once it has been\n /// initialized and is ready for input.\n /// @dev This function MUST emit the E3Activated event.\n /// @dev This function MUST revert if the given E3 has not yet been requested.\n /// @dev This function MUST revert if the selected node committee has not yet published a public key.\n /// @param e3Id ID of the E3.\n function activate(uint256 e3Id) external returns (bool success);\n\n /// @notice This function should be called to publish input data for Encrypted Execution Environment (E3).\n /// @dev This function MUST revert if the E3 is not yet activated.\n /// @dev This function MUST emit the InputPublished event.\n /// @param e3Id ID of the E3.\n /// @param data ABI encoded input data to publish.\n /// @return success True if the input was successfully published.\n function publishInput(\n uint256 e3Id,\n bytes calldata data\n ) external returns (bool success);\n\n /// @notice This function should be called to publish output data for an Encrypted Execution Environment (E3).\n /// @dev This function MUST emit the CiphertextOutputPublished event.\n /// @param e3Id ID of the E3.\n /// @param data ABI encoded output data to verify.\n /// @return success True if the output was successfully published.\n function publishCiphertextOutput(\n uint256 e3Id,\n bytes memory data\n ) external returns (bool success);\n\n /// @notice This function publishes the plaintext output of an Encrypted Execution Environment (E3).\n /// @dev This function MUST revert if the output has not been published.\n /// @dev This function MUST emit the PlaintextOutputPublished event.\n /// @param e3Id ID of the E3.\n /// @param data ABI encoded output data to decrypt.\n /// @return success True if the output was successfully decrypted.\n function publishPlaintextOutput(\n uint256 e3Id,\n bytes memory data\n ) external returns (bool success);\n\n ////////////////////////////////////////////////////////////\n // //\n // Set Functions //\n // //\n ////////////////////////////////////////////////////////////\n\n /// @notice This function should be called to set the maximum duration of requested computations.\n /// @param _maxDuration The maximum duration of a computation in seconds.\n /// @return success True if the max duration was successfully set.\n function setMaxDuration(\n uint256 _maxDuration\n ) external returns (bool success);\n\n ////////////////////////////////////////////////////////////\n // //\n // Get Functions //\n // //\n ////////////////////////////////////////////////////////////\n\n /// @notice This function should be called to retrieve the details of an Encrypted Execution Environment (E3).\n /// @dev This function MUST revert if the E3 does not exist.\n /// @param e3Id ID of the E3.\n /// @return e3 The struct representing the requested E3.\n function getE3(uint256 e3Id) external view returns (E3 memory e3);\n}\n" + }, + "contracts/interfaces/IExecutionModule.sol": { + "content": "// SPDX-License-Identifier: LGPL-3.0-only\npragma solidity >=0.8.26;\n\nimport { IOutputVerifier } from \"./IOutputVerifier.sol\";\n\ninterface IExecutionModule {\n /// @notice This function should be called by the Enclave contract to validate the execution module parameters.\n /// @param params ABI encoded execution module parameters.\n function validate(\n bytes calldata params\n ) external returns (IOutputVerifier outputVerifier);\n}\n" + }, + "contracts/interfaces/IInputValidator.sol": { + "content": "// SPDX-License-Identifier: LGPL-3.0-only\npragma solidity >=0.8.26;\n\ninterface IInputValidator {\n /// @notice This function should be called by the Enclave contract to validate the input parameters.\n /// @param params ABI encoded input parameters.\n /// @return input The input data to be published.\n /// @return success Whether the input parameters are valid.\n function validate(\n address sender,\n bytes memory params\n ) external returns (bytes memory input, bool success);\n}\n" + }, + "contracts/interfaces/IOutputVerifier.sol": { + "content": "// SPDX-License-Identifier: LGPL-3.0-only\npragma solidity >=0.8.26;\n\ninterface IOutputVerifier {\n /// @notice This function should be called by the Enclave contract to verify the output of a computation.\n /// @param e3Id ID of the E3.\n /// @param data ABI encoded output data to be verified.\n /// @return output Ciphertext output of the given computation.\n function verify(\n uint256 e3Id,\n bytes memory data\n ) external view returns (bytes memory output, bool success);\n}\n" + }, + "contracts/interfaces/IRegistryFilter.sol": { + "content": "// SPDX-License-Identifier: LGPL-3.0-only\npragma solidity >=0.8.26;\n\ninterface IRegistryFilter {\n function requestCommittee(\n uint256 e3Id,\n uint32[2] calldata threshold\n ) external returns (bool success);\n}\n" + }, + "contracts/registry/CyphernodeRegistryOwnable.sol": { + "content": "// SPDX-License-Identifier: LGPL-3.0-only\npragma solidity >=0.8.26;\n\nimport { ICyphernodeRegistry } from \"../interfaces/ICyphernodeRegistry.sol\";\nimport { IRegistryFilter } from \"../interfaces/IRegistryFilter.sol\";\nimport {\n OwnableUpgradeable\n} from \"@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol\";\n\ncontract CyphernodeRegistryOwnable is ICyphernodeRegistry, OwnableUpgradeable {\n ////////////////////////////////////////////////////////////\n // //\n // Storage Variables //\n // //\n ////////////////////////////////////////////////////////////\n\n address public enclave;\n\n mapping(address cyphernode => bool isEnabled) public isEnabled;\n\n mapping(uint256 e3Id => IRegistryFilter filter) public requests;\n mapping(uint256 e3Id => bytes publicKey) public publicKeys;\n\n ////////////////////////////////////////////////////////////\n // //\n // Errors //\n // //\n ////////////////////////////////////////////////////////////\n\n error CommitteeAlreadyRequested();\n error CommitteeAlreadyPublished();\n error CommitteeDoesNotExist();\n error CommitteeNotPublished();\n error CyphernodeNotEnabled(address node);\n error OnlyEnclave();\n\n ////////////////////////////////////////////////////////////\n // //\n // Modifiers //\n // //\n ////////////////////////////////////////////////////////////\n\n modifier onlyEnclave() {\n require(msg.sender == enclave, OnlyEnclave());\n _;\n }\n\n ////////////////////////////////////////////////////////////\n // //\n // Initialization //\n // //\n ////////////////////////////////////////////////////////////\n\n constructor(address _owner, address _enclave) {\n initialize(_owner, _enclave);\n }\n\n function initialize(address _owner, address _enclave) public initializer {\n __Ownable_init(msg.sender);\n setEnclave(_enclave);\n transferOwnership(_owner);\n }\n\n ////////////////////////////////////////////////////////////\n // //\n // Core Entrypoints //\n // //\n ////////////////////////////////////////////////////////////\n\n function requestCommittee(\n uint256 e3Id,\n address filter,\n uint32[2] calldata threshold\n ) external onlyEnclave returns (bool success) {\n require(\n requests[e3Id] == IRegistryFilter(address(0)),\n CommitteeAlreadyRequested()\n );\n requests[e3Id] = IRegistryFilter(filter);\n\n IRegistryFilter(filter).requestCommittee(e3Id, threshold);\n emit CommitteeRequested(e3Id, filter, threshold);\n success = true;\n }\n\n function publishCommittee(\n uint256 e3Id,\n bytes calldata,\n bytes calldata publicKey\n ) external {\n // only to be published by the filter\n require(address(requests[e3Id]) == msg.sender, CommitteeDoesNotExist());\n\n // for (uint256 i = 0; i < cyphernodes.length; i++) {\n // require(\n // isEnabled[cyphernodes[i]] == true,\n // CyphernodeNotEnabled(cyphernodes[i])\n // );\n // }\n\n publicKeys[e3Id] = publicKey;\n emit CommitteePublished(e3Id, publicKey);\n }\n\n ////////////////////////////////////////////////////////////\n // //\n // Set Functions //\n // //\n ////////////////////////////////////////////////////////////\n\n function setEnclave(address _enclave) public onlyOwner {\n enclave = _enclave;\n emit EnclaveSet(_enclave);\n }\n\n function addCyphernode(address node) external onlyOwner {\n isEnabled[node] = true;\n emit CyphernodeAdded(node);\n }\n\n function removeCyphernode(address node) external onlyOwner {\n isEnabled[node] = false;\n emit CyphernodeRemoved(node);\n }\n\n function isCyphernodeEligible(address node) external view returns (bool) {\n return isEnabled[node];\n }\n\n ////////////////////////////////////////////////////////////\n // //\n // Get Functions //\n // //\n ////////////////////////////////////////////////////////////\n\n function committeePublicKey(\n uint256 e3Id\n ) external view returns (bytes memory publicKey) {\n publicKey = publicKeys[e3Id];\n require(publicKey.length > 0, CommitteeNotPublished());\n }\n}\n" + }, + "contracts/registry/NaiveRegistryFilter.sol": { + "content": "// SPDX-License-Identifier: LGPL-3.0-only\npragma solidity >=0.8.26;\n\nimport { ICyphernodeRegistry } from \"../interfaces/ICyphernodeRegistry.sol\";\nimport { IRegistryFilter } from \"../interfaces/IRegistryFilter.sol\";\nimport {\n OwnableUpgradeable\n} from \"@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol\";\n\ncontract NaiveRegistryFilter is IRegistryFilter, OwnableUpgradeable {\n struct Committee {\n address[] nodes;\n uint32[2] threshold;\n bytes publicKey;\n }\n\n ////////////////////////////////////////////////////////////\n // //\n // Storage Variables //\n // //\n ////////////////////////////////////////////////////////////\n\n address public registry;\n\n mapping(uint256 e3 => Committee committee) public committees;\n\n ////////////////////////////////////////////////////////////\n // //\n // Errors //\n // //\n ////////////////////////////////////////////////////////////\n\n error CommitteeAlreadyExists();\n error CommitteeAlreadyPublished();\n error CommitteeDoesNotExist();\n error CommitteeNotPublished();\n error OnlyRegistry();\n\n ////////////////////////////////////////////////////////////\n // //\n // Modifiers //\n // //\n ////////////////////////////////////////////////////////////\n\n modifier onlyRegistry() {\n require(msg.sender == registry, OnlyRegistry());\n _;\n }\n\n ////////////////////////////////////////////////////////////\n // //\n // Initialization //\n // //\n ////////////////////////////////////////////////////////////\n\n constructor(address _owner, address _enclave) {\n initialize(_owner, _enclave);\n }\n\n function initialize(address _owner, address _registry) public initializer {\n __Ownable_init(msg.sender);\n setRegistry(_registry);\n transferOwnership(_owner);\n }\n\n ////////////////////////////////////////////////////////////\n // //\n // Core Entrypoints //\n // //\n ////////////////////////////////////////////////////////////\n\n function requestCommittee(\n uint256 e3Id,\n uint32[2] calldata threshold\n ) external onlyRegistry returns (bool success) {\n Committee storage committee = committees[e3Id];\n require(committee.threshold.length == 0, CommitteeAlreadyExists());\n committee.threshold = threshold;\n success = true;\n }\n\n function publishCommittee(\n uint256 e3Id,\n address[] memory nodes,\n bytes memory publicKey\n ) external onlyOwner {\n Committee storage committee = committees[e3Id];\n require(\n keccak256(committee.publicKey) == keccak256(hex\"\"),\n CommitteeAlreadyPublished()\n );\n committee.nodes = nodes;\n committee.publicKey = publicKey;\n ICyphernodeRegistry(registry).publishCommittee(\n e3Id,\n abi.encode(nodes),\n publicKey\n );\n }\n\n ////////////////////////////////////////////////////////////\n // //\n // Set Functions //\n // //\n ////////////////////////////////////////////////////////////\n\n function setRegistry(address _registry) public onlyOwner {\n registry = _registry;\n }\n}\n" + }, + "contracts/test/MockComputationModule.sol": { + "content": "// SPDX-License-Identifier: LGPL-3.0-only\npragma solidity >=0.8.26;\n\nimport {\n IComputationModule,\n IInputValidator\n} from \"../interfaces/IComputationModule.sol\";\n\ncontract MockComputationModule is IComputationModule {\n error invalidParams(bytes params);\n\n function validate(\n bytes memory params\n ) external pure returns (IInputValidator inputValidator) {\n require(params.length == 32, \"invalid params\");\n // solhint-disable no-inline-assembly\n assembly {\n inputValidator := mload(add(params, 32))\n }\n }\n\n function verify(\n uint256,\n bytes memory data\n ) external pure returns (bytes memory output, bool success) {\n output = data;\n if (output.length > 0) success = true;\n }\n}\n" + }, + "contracts/test/MockCyphernodeRegistry.sol": { + "content": "// SPDX-License-Identifier: LGPL-3.0-only\npragma solidity >=0.8.26;\n\nimport { ICyphernodeRegistry } from \"../interfaces/ICyphernodeRegistry.sol\";\n\ncontract MockCyphernodeRegistry is ICyphernodeRegistry {\n function requestCommittee(\n uint256,\n address filter,\n uint32[2] calldata\n ) external pure returns (bool success) {\n if (filter == address(2)) {\n success = false;\n } else {\n success = true;\n }\n }\n\n function publishCommittee(\n uint256,\n bytes calldata,\n bytes calldata\n ) external {} // solhint-disable-line no-empty-blocks\n\n function committeePublicKey(\n uint256 e3Id\n ) external pure returns (bytes memory) {\n if (e3Id == type(uint256).max) {\n return hex\"\";\n } else {\n return abi.encodePacked(keccak256(abi.encode(e3Id)));\n }\n }\n\n function isCyphernodeEligible(address) external pure returns (bool) {\n return false;\n }\n}\n\ncontract MockCyphernodeRegistryEmptyKey is ICyphernodeRegistry {\n function requestCommittee(\n uint256,\n address filter,\n uint32[2] calldata\n ) external pure returns (bool success) {\n if (filter == address(2)) {\n success = false;\n } else {\n success = true;\n }\n }\n\n function publishCommittee(\n uint256,\n bytes calldata,\n bytes calldata\n ) external {} // solhint-disable-line no-empty-blocks\n\n function committeePublicKey(uint256) external pure returns (bytes memory) {\n return hex\"\";\n }\n\n function isCyphernodeEligible(address) external pure returns (bool) {\n return false;\n }\n}\n" + }, + "contracts/test/MockExecutionModule.sol": { + "content": "// SPDX-License-Identifier: LGPL-3.0-only\npragma solidity >=0.8.26;\n\nimport {\n IExecutionModule,\n IOutputVerifier\n} from \"../interfaces/IExecutionModule.sol\";\n\ncontract MockExecutionModule is IExecutionModule {\n error invalidParams();\n\n function validate(\n bytes memory params\n ) external pure returns (IOutputVerifier outputVerifier) {\n require(params.length == 32, invalidParams());\n // solhint-disable no-inline-assembly\n assembly {\n outputVerifier := mload(add(params, 32))\n }\n (outputVerifier) = abi.decode(params, (IOutputVerifier));\n }\n}\n" + }, + "contracts/test/MockInputValidator.sol": { + "content": "// SPDX-License-Identifier: LGPL-3.0-only\npragma solidity >=0.8.26;\n\nimport { IInputValidator } from \"../interfaces/IInputValidator.sol\";\n\ncontract MockInputValidator is IInputValidator {\n function validate(\n address,\n bytes memory params\n ) external pure returns (bytes memory input, bool success) {\n input = params;\n\n if (input.length == 3) {\n success = false;\n } else {\n success = true;\n }\n }\n}\n" + }, + "contracts/test/MockOutputVerifier.sol": { + "content": "// SPDX-License-Identifier: LGPL-3.0-only\npragma solidity >=0.8.26;\n\nimport { IOutputVerifier } from \"../interfaces/IOutputVerifier.sol\";\n\ncontract MockOutputVerifier is IOutputVerifier {\n function verify(\n uint256,\n bytes memory data\n ) external pure returns (bytes memory output, bool success) {\n output = data;\n\n if (output.length > 0) success = true;\n }\n}\n" + }, + "contracts/test/MockRegistryFilter.sol": { + "content": "// SPDX-License-Identifier: LGPL-3.0-only\npragma solidity >=0.8.26;\n\nimport { IRegistryFilter } from \"../interfaces/IRegistryFilter.sol\";\nimport {\n OwnableUpgradeable\n} from \"@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol\";\n\ninterface IRegistry {\n function publishCommittee(\n uint256 e3Id,\n address[] calldata cyphernodes,\n bytes calldata publicKey\n ) external;\n}\n\ncontract NaiveRegistryFilter is IRegistryFilter, OwnableUpgradeable {\n struct Committee {\n address[] nodes;\n uint32[2] threshold;\n bytes publicKey;\n }\n\n ////////////////////////////////////////////////////////////\n // //\n // Storage Variables //\n // //\n ////////////////////////////////////////////////////////////\n\n address public registry;\n\n mapping(uint256 e3 => Committee committee) public committees;\n\n ////////////////////////////////////////////////////////////\n // //\n // Errors //\n // //\n ////////////////////////////////////////////////////////////\n\n error CommitteeAlreadyExists();\n error CommitteeAlreadyPublished();\n error CommitteeDoesNotExist();\n error CommitteeNotPublished();\n error OnlyRegistry();\n\n ////////////////////////////////////////////////////////////\n // //\n // Modifiers //\n // //\n ////////////////////////////////////////////////////////////\n\n modifier onlyRegistry() {\n require(msg.sender == registry, OnlyRegistry());\n _;\n }\n\n ////////////////////////////////////////////////////////////\n // //\n // Initialization //\n // //\n ////////////////////////////////////////////////////////////\n\n constructor(address _owner, address _enclave) {\n initialize(_owner, _enclave);\n }\n\n function initialize(address _owner, address _registry) public initializer {\n __Ownable_init(msg.sender);\n setRegistry(_registry);\n transferOwnership(_owner);\n }\n\n ////////////////////////////////////////////////////////////\n // //\n // Core Entrypoints //\n // //\n ////////////////////////////////////////////////////////////\n\n function requestCommittee(\n uint256 e3Id,\n uint32[2] calldata threshold\n ) external onlyRegistry returns (bool success) {\n Committee storage committee = committees[e3Id];\n require(committee.threshold.length == 0, CommitteeAlreadyExists());\n committee.threshold = threshold;\n success = true;\n }\n\n function publishCommittee(\n uint256 e3Id,\n address[] memory nodes,\n bytes memory publicKey\n ) external onlyOwner {\n Committee storage committee = committees[e3Id];\n require(\n keccak256(committee.publicKey) == keccak256(hex\"\"),\n CommitteeAlreadyPublished()\n );\n committee.nodes = nodes;\n committee.publicKey = publicKey;\n IRegistry(registry).publishCommittee(e3Id, nodes, publicKey);\n }\n\n ////////////////////////////////////////////////////////////\n // //\n // Set Functions //\n // //\n ////////////////////////////////////////////////////////////\n\n function setRegistry(address _registry) public onlyOwner {\n registry = _registry;\n }\n}\n" + } + }, + "settings": { + "metadata": { + "bytecodeHash": "none", + "useLiteralContent": true + }, + "optimizer": { + "enabled": true, + "runs": 800 + }, + "viaIR": true, + "evmVersion": "paris", + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata", + "devdoc", + "userdoc", + "storageLayout", + "evm.gasEstimates" + ], + "": ["ast"] + } + } + } +} diff --git a/packages/evm/hardhat.config.ts b/packages/evm/hardhat.config.ts index e07861b9..822d257c 100644 --- a/packages/evm/hardhat.config.ts +++ b/packages/evm/hardhat.config.ts @@ -1,16 +1,26 @@ import "@nomicfoundation/hardhat-toolbox"; +import dotenv from "dotenv"; import "hardhat-deploy"; import type { HardhatUserConfig } from "hardhat/config"; import { vars } from "hardhat/config"; import type { NetworkUserConfig } from "hardhat/types"; import "./tasks/accounts"; -import "./tasks/enclave"; -// Run 'npx hardhat vars setup' to see the list of variables that need to be set +dotenv.config(); -const mnemonic: string = vars.get("MNEMONIC"); -const infuraApiKey: string = vars.get("INFURA_API_KEY"); +const { INFURA_KEY, MNEMONIC, ETHERSCAN_API_KEY } = process.env; + +if (!INFURA_KEY || !MNEMONIC || !ETHERSCAN_API_KEY) { + console.error( + "Please set the INFURA_KEY, MNEMONIC, and ETHERSCAN_API_KEY environment variables", + ); +} + +// Setting defaults so that tests will run +const mnemonic = + MNEMONIC || "test test test test test test test test test test test junk"; +const infuraApiKey = INFURA_KEY || "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz"; const chainIds = { "arbitrum-mainnet": 42161, @@ -58,11 +68,11 @@ const config: HardhatUserConfig = { arbitrumOne: vars.get("ARBISCAN_API_KEY", ""), avalanche: vars.get("SNOWTRACE_API_KEY", ""), bsc: vars.get("BSCSCAN_API_KEY", ""), - mainnet: vars.get("ETHERSCAN_API_KEY", ""), + mainnet: ETHERSCAN_API_KEY, optimisticEthereum: vars.get("OPTIMISM_API_KEY", ""), polygon: vars.get("POLYGONSCAN_API_KEY", ""), polygonMumbai: vars.get("POLYGONSCAN_API_KEY", ""), - sepolia: vars.get("ETHERSCAN_API_KEY", ""), + sepolia: ETHERSCAN_API_KEY, }, }, gasReporter: { @@ -77,6 +87,7 @@ const config: HardhatUserConfig = { mnemonic, }, chainId: chainIds.hardhat, + allowUnlimitedContractSize: true, }, ganache: { accounts: { @@ -101,7 +112,7 @@ const config: HardhatUserConfig = { tests: "./test", }, solidity: { - version: "0.8.26", + version: "0.8.27", settings: { metadata: { // Not including the metadata hash @@ -116,6 +127,16 @@ const config: HardhatUserConfig = { }, viaIR: true, }, + overrides: { + "node_modules/poseidon-solidity/PoseidonT3.sol": { + settings: { + optimizer: { + enabled: true, + runs: 2 ** 32 - 1, + }, + }, + }, + }, }, typechain: { outDir: "types", diff --git a/packages/evm/package.json b/packages/evm/package.json index f6b4db13..d568a1ec 100644 --- a/packages/evm/package.json +++ b/packages/evm/package.json @@ -13,6 +13,7 @@ "@nomicfoundation/hardhat-network-helpers": "^1.0.10", "@nomicfoundation/hardhat-toolbox": "^4.0.0", "@nomicfoundation/hardhat-verify": "^2.0.2", + "@openzeppelin/contracts": "^5.0.2", "@openzeppelin/contracts-upgradeable": "^5.0.2", "@trivago/prettier-plugin-sort-imports": "^4.3.0", "@typechain/ethers-v6": "^0.5.1", @@ -23,21 +24,26 @@ "@types/node": "^20.10.4", "@typescript-eslint/eslint-plugin": "^7.11.0", "@typescript-eslint/parser": "^7.11.0", + "@zk-kit/lean-imt": "^2.1.0", + "@zk-kit/lean-imt.sol": "2.0.0", "chai": "^4.3.10", "cross-env": "^7.0.3", + "dotenv": "^16.4.5", "eslint": "^8.56.0", "eslint-config-prettier": "^9.1.0", "ethers": "^6.9.0", "fs-extra": "^11.2.0", - "hardhat": "^2.19.2", + "hardhat": "^2.22.0", "hardhat-deploy": "^0.12.1", "hardhat-gas-reporter": "^2.2.0", "lodash": "^4.17.21", "mocha": "^10.2.0", + "poseidon-lite": "^0.3.0", + "poseidon-solidity": "^0.0.5", "prettier": "^3.1.1", "prettier-plugin-solidity": "^1.2.0", "rimraf": "^5.0.5", - "solhint": "^5.0.1", + "solhint": "^5.0.3", "solhint-plugin-prettier": "^0.1.0", "solidity-coverage": "^0.8.5", "ts-generator": "^0.1.1", @@ -66,7 +72,7 @@ "clean": "rimraf ./artifacts ./cache ./coverage ./types ./coverage.json && yarn typechain", "compile": "cross-env TS_NODE_TRANSPILE_ONLY=true hardhat compile", "coverage": "hardhat coverage --solcoverjs ./.solcover.js --temp artifacts --testfiles \"test/**/*.ts\" && yarn typechain", - "deploy:contracts": "hardhat deploy", + "deploy": "hardhat deploy", "lint": "yarn lint:sol && yarn lint:ts && yarn prettier:check", "lint:sol": "solhint --max-warnings 0 \"contracts/**/*.sol\"", "lint:ts": "eslint --ignore-path ./.eslintignore --ext .js,.ts .", diff --git a/packages/evm/tasks/enclave.ts b/packages/evm/tasks/enclave.ts deleted file mode 100644 index c0d2c62a..00000000 --- a/packages/evm/tasks/enclave.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { task } from "hardhat/config"; -import type { TaskArguments } from "hardhat/types"; - -task("task:deployEnclave", "Deploys Enclave contract") - .addParam("owner", "Account that will own this contract") - .addParam("registry", "Address of the cyphernode registry") - .addParam("maxDuration", "The maximum duration of a computation in seconds") - .setAction(async function (taskArguments: TaskArguments, { ethers }) { - const signers = await ethers.getSigners(); - const enclaveFactory = await ethers.getContractFactory("Enclave"); - console.log(`Deploying Enclave...`); - const enclave = await enclaveFactory - .connect(signers[0]) - .deploy( - taskArguments.owner, - taskArguments.registry, - taskArguments.maxDuration, - ); - await enclave.waitForDeployment(); - console.log("Enclave deployed to: ", await enclave.getAddress()); - }); diff --git a/packages/evm/test/Enclave.spec.ts b/packages/evm/test/Enclave.spec.ts index 02b48d3b..45bef681 100644 --- a/packages/evm/test/Enclave.spec.ts +++ b/packages/evm/test/Enclave.spec.ts @@ -3,16 +3,18 @@ import { mine, time, } from "@nomicfoundation/hardhat-network-helpers"; +import { LeanIMT } from "@zk-kit/lean-imt"; import { expect } from "chai"; import { ZeroHash } from "ethers"; import { ethers } from "hardhat"; +import { poseidon2 } from "poseidon-lite"; import { deployEnclaveFixture } from "./fixtures/Enclave.fixture"; -import { deployComputationModuleFixture } from "./fixtures/MockComputationModule.fixture"; -import { deployCyphernodeRegistryFixture } from "./fixtures/MockCyphernodeRegistry.fixture"; -import { deployExecutionModuleFixture } from "./fixtures/MockExecutionModule.fixture"; +import { deployCiphernodeRegistryFixture } from "./fixtures/MockCiphernodeRegistry.fixture"; +import { deployComputeProviderFixture } from "./fixtures/MockComputeProvider.fixture"; +import { deployDecryptionVerifierFixture } from "./fixtures/MockDecryptionVerifier.fixture"; +import { deployE3ProgramFixture } from "./fixtures/MockE3Program.fixture"; import { deployInputValidatorFixture } from "./fixtures/MockInputValidator.fixture"; -import { deployOutputVerifierFixture } from "./fixtures/MockOutputVerifier.fixture"; const abiCoder = ethers.AbiCoder.defaultAbiCoder(); const AddressTwo = "0x0000000000000000000000000000000000000002"; @@ -21,14 +23,17 @@ const AddressSix = "0x0000000000000000000000000000000000000006"; const FilterFail = AddressTwo; const FilterOkay = AddressSix; +// Hash function used to compute the tree nodes. +const hash = (a: bigint, b: bigint) => poseidon2([a, b]); + describe("Enclave", function () { async function setup() { const [owner, notTheOwner] = await ethers.getSigners(); - const registry = await deployCyphernodeRegistryFixture(); - const computationModule = await deployComputationModuleFixture(); - const outputVerifier = await deployOutputVerifierFixture(); - const executionModule = await deployExecutionModuleFixture(); + const registry = await deployCiphernodeRegistryFixture(); + const e3Program = await deployE3ProgramFixture(); + const decryptionVerifier = await deployDecryptionVerifierFixture(); + const computeProvider = await deployComputeProviderFixture(); const inputValidator = await deployInputValidatorFixture(); const enclave = await deployEnclaveFixture({ @@ -36,17 +41,17 @@ describe("Enclave", function () { registry: await registry.getAddress(), }); - await enclave.enableComputationModule(await computationModule.getAddress()); - await enclave.enableExecutionModule(await executionModule.getAddress()); + await enclave.enableE3Program(await e3Program.getAddress()); + await enclave.enableComputeProvider(await computeProvider.getAddress()); return { owner, notTheOwner, enclave, mocks: { - computationModule, - outputVerifier, - executionModule, + e3Program, + decryptionVerifier, + computeProvider, inputValidator, registry, }, @@ -58,15 +63,15 @@ describe("Enclave", function () { number, ], duration: time.duration.days(30), - computationModule: await computationModule.getAddress(), - cMParams: abiCoder.encode( + e3Program: await e3Program.getAddress(), + e3ProgramParams: abiCoder.encode( ["address"], [await inputValidator.getAddress()], ), - executionModule: await executionModule.getAddress(), - eMParams: abiCoder.encode( + computeProvider: await computeProvider.getAddress(), + computeProviderParams: abiCoder.encode( ["address"], - [await outputVerifier.getAddress()], + [await decryptionVerifier.getAddress()], ), }, }; @@ -79,16 +84,16 @@ describe("Enclave", function () { owner: someSigner, registry: AddressTwo, }); - expect(await enclave.cyphernodeRegistry()).to.equal(AddressTwo); + expect(await enclave.ciphernodeRegistry()).to.equal(AddressTwo); }); - it("correctly sets cyphernodeRegistry address", async function () { + it("correctly sets ciphernodeRegistry address", async function () { const [aSigner] = await ethers.getSigners(); const enclave = await deployEnclaveFixture({ owner: aSigner, registry: AddressTwo, }); - expect(await enclave.cyphernodeRegistry()).to.equal(AddressTwo); + expect(await enclave.ciphernodeRegistry()).to.equal(AddressTwo); }); it("correctly sets max duration", async function () { @@ -127,49 +132,49 @@ describe("Enclave", function () { }); }); - describe("setCyphernodeRegistry()", function () { + describe("setCiphernodeRegistry()", function () { it("reverts if not called by owner", async function () { const { enclave, notTheOwner } = await loadFixture(setup); await expect( - enclave.connect(notTheOwner).setCyphernodeRegistry(AddressTwo), + enclave.connect(notTheOwner).setCiphernodeRegistry(AddressTwo), ) .to.be.revertedWithCustomError(enclave, "OwnableUnauthorizedAccount") .withArgs(notTheOwner); }); it("reverts if given address(0)", async function () { const { enclave } = await loadFixture(setup); - await expect(enclave.setCyphernodeRegistry(ethers.ZeroAddress)) - .to.be.revertedWithCustomError(enclave, "InvalidCyphernodeRegistry") + await expect(enclave.setCiphernodeRegistry(ethers.ZeroAddress)) + .to.be.revertedWithCustomError(enclave, "InvalidCiphernodeRegistry") .withArgs(ethers.ZeroAddress); }); - it("reverts if given address is the same as the current cyphernodeRegistry", async function () { + it("reverts if given address is the same as the current ciphernodeRegistry", async function () { const { enclave, mocks: { registry }, } = await loadFixture(setup); - await expect(enclave.setCyphernodeRegistry(registry)) - .to.be.revertedWithCustomError(enclave, "InvalidCyphernodeRegistry") + await expect(enclave.setCiphernodeRegistry(registry)) + .to.be.revertedWithCustomError(enclave, "InvalidCiphernodeRegistry") .withArgs(registry); }); - it("sets cyphernodeRegistry correctly", async function () { + it("sets ciphernodeRegistry correctly", async function () { const { enclave } = await loadFixture(setup); - expect(await enclave.cyphernodeRegistry()).to.not.equal(AddressTwo); - await enclave.setCyphernodeRegistry(AddressTwo); - expect(await enclave.cyphernodeRegistry()).to.equal(AddressTwo); + expect(await enclave.ciphernodeRegistry()).to.not.equal(AddressTwo); + await enclave.setCiphernodeRegistry(AddressTwo); + expect(await enclave.ciphernodeRegistry()).to.equal(AddressTwo); }); - it("returns true if cyphernodeRegistry is set successfully", async function () { + it("returns true if ciphernodeRegistry is set successfully", async function () { const { enclave } = await loadFixture(setup); - const result = await enclave.setCyphernodeRegistry.staticCall(AddressTwo); + const result = await enclave.setCiphernodeRegistry.staticCall(AddressTwo); expect(result).to.be.true; }); - it("emits CyphernodeRegistrySet event", async function () { + it("emits CiphernodeRegistrySet event", async function () { const { enclave } = await loadFixture(setup); - await expect(enclave.setCyphernodeRegistry(AddressTwo)) - .to.emit(enclave, "CyphernodeRegistrySet") + await expect(enclave.setCiphernodeRegistry(AddressTwo)) + .to.emit(enclave, "CiphernodeRegistrySet") .withArgs(AddressTwo); }); }); @@ -189,23 +194,24 @@ describe("Enclave", function () { request.threshold, request.startTime, request.duration, - request.computationModule, - request.cMParams, - request.executionModule, - request.eMParams, + request.e3Program, + request.e3ProgramParams, + request.computeProvider, + request.computeProviderParams, { value: 10 }, ); const e3 = await enclave.getE3(0); expect(e3.threshold).to.deep.equal(request.threshold); expect(e3.expiration).to.equal(0n); - expect(e3.computationModule).to.equal(request.computationModule); + expect(e3.e3Program).to.equal(request.e3Program); + expect(e3.e3ProgramParams).to.equal(request.e3ProgramParams); expect(e3.inputValidator).to.equal( - abiCoder.decode(["address"], request.cMParams)[0], + abiCoder.decode(["address"], request.e3ProgramParams)[0], ); - expect(e3.executionModule).to.equal(request.executionModule); - expect(e3.outputVerifier).to.equal( - abiCoder.decode(["address"], request.eMParams)[0], + expect(e3.computeProvider).to.equal(request.computeProvider); + expect(e3.decryptionVerifier).to.equal( + abiCoder.decode(["address"], request.computeProviderParams)[0], ); expect(e3.committeePublicKey).to.equal("0x"); expect(e3.ciphertextOutput).to.equal("0x"); @@ -213,193 +219,185 @@ describe("Enclave", function () { }); }); - describe("enableComputationModule()", function () { + describe("enableE3Program()", function () { it("reverts if not called by owner", async function () { const { notTheOwner, enclave, - mocks: { computationModule }, + mocks: { e3Program }, } = await loadFixture(setup); - await expect( - enclave.connect(notTheOwner).enableComputationModule(computationModule), - ) + await expect(enclave.connect(notTheOwner).enableE3Program(e3Program)) .to.be.revertedWithCustomError(enclave, "OwnableUnauthorizedAccount") .withArgs(notTheOwner); }); - it("reverts if computation module is already enabled", async function () { + it("reverts if E3 Program is already enabled", async function () { const { enclave, - mocks: { computationModule }, + mocks: { e3Program }, } = await loadFixture(setup); - await expect(enclave.enableComputationModule(computationModule)) + await expect(enclave.enableE3Program(e3Program)) .to.be.revertedWithCustomError(enclave, "ModuleAlreadyEnabled") - .withArgs(computationModule); + .withArgs(e3Program); }); - it("enables computation module correctly", async function () { + it("enables E3 Program correctly", async function () { const { enclave, - mocks: { computationModule }, + mocks: { e3Program }, } = await loadFixture(setup); - const enabled = await enclave.computationModules(computationModule); + const enabled = await enclave.e3Programs(e3Program); expect(enabled).to.be.true; }); - it("returns true if computation module is enabled successfully", async function () { + it("returns true if E3 Program is enabled successfully", async function () { const { enclave } = await loadFixture(setup); - const result = - await enclave.enableComputationModule.staticCall(AddressTwo); + const result = await enclave.enableE3Program.staticCall(AddressTwo); expect(result).to.be.true; }); - it("emits ComputationModuleEnabled event", async function () { + it("emits E3ProgramEnabled event", async function () { const { enclave } = await loadFixture(setup); - await expect(enclave.enableComputationModule(AddressTwo)) - .to.emit(enclave, "ComputationModuleEnabled") + await expect(enclave.enableE3Program(AddressTwo)) + .to.emit(enclave, "E3ProgramEnabled") .withArgs(AddressTwo); }); }); - describe("disableComputationModule()", function () { + describe("disableE3Program()", function () { it("reverts if not called by owner", async function () { const { notTheOwner, enclave, - mocks: { computationModule }, + mocks: { e3Program }, } = await loadFixture(setup); - await expect( - enclave - .connect(notTheOwner) - .disableComputationModule(computationModule), - ) + await expect(enclave.connect(notTheOwner).disableE3Program(e3Program)) .to.be.revertedWithCustomError(enclave, "OwnableUnauthorizedAccount") .withArgs(notTheOwner); }); - it("reverts if computation module is not enabled", async function () { + it("reverts if E3 Program is not enabled", async function () { const { enclave } = await loadFixture(setup); - await expect(enclave.disableComputationModule(AddressTwo)) + await expect(enclave.disableE3Program(AddressTwo)) .to.be.revertedWithCustomError(enclave, "ModuleNotEnabled") .withArgs(AddressTwo); }); - it("disables computation module correctly", async function () { + it("disables E3 Program correctly", async function () { const { enclave, - mocks: { computationModule }, + mocks: { e3Program }, } = await loadFixture(setup); - await enclave.disableComputationModule(computationModule); + await enclave.disableE3Program(e3Program); - const enabled = await enclave.computationModules(computationModule); + const enabled = await enclave.e3Programs(e3Program); expect(enabled).to.be.false; }); - it("returns true if computation module is disabled successfully", async function () { + it("returns true if E3 Program is disabled successfully", async function () { const { enclave, - mocks: { computationModule }, + mocks: { e3Program }, } = await loadFixture(setup); - const result = - await enclave.disableComputationModule.staticCall(computationModule); + const result = await enclave.disableE3Program.staticCall(e3Program); expect(result).to.be.true; }); - it("emits ComputationModuleDisabled event", async function () { + it("emits E3ProgramDisabled event", async function () { const { enclave, - mocks: { computationModule }, + mocks: { e3Program }, } = await loadFixture(setup); - await expect(enclave.disableComputationModule(computationModule)) - .to.emit(enclave, "ComputationModuleDisabled") - .withArgs(computationModule); + await expect(enclave.disableE3Program(e3Program)) + .to.emit(enclave, "E3ProgramDisabled") + .withArgs(e3Program); }); }); - describe("enableExecutionModule()", function () { + describe("enableComputeProvider()", function () { it("reverts if not called by owner", async function () { const { notTheOwner, enclave } = await loadFixture(setup); await expect( - enclave.connect(notTheOwner).enableExecutionModule(AddressTwo), + enclave.connect(notTheOwner).enableComputeProvider(AddressTwo), ) .to.be.revertedWithCustomError(enclave, "OwnableUnauthorizedAccount") .withArgs(notTheOwner.address); }); - it("reverts if execution module is already enabled", async function () { + it("reverts if compute provider is already enabled", async function () { const { enclave, - mocks: { executionModule }, + mocks: { computeProvider }, } = await loadFixture(setup); - await expect(enclave.enableExecutionModule(executionModule)) + await expect(enclave.enableComputeProvider(computeProvider)) .to.be.revertedWithCustomError(enclave, "ModuleAlreadyEnabled") - .withArgs(executionModule); + .withArgs(computeProvider); }); - it("enables execution module correctly", async function () { + it("enables compute provider correctly", async function () { const { enclave, - mocks: { executionModule }, + mocks: { computeProvider }, } = await loadFixture(setup); - const enabled = await enclave.executionModules(executionModule); + const enabled = await enclave.computeProviders(computeProvider); expect(enabled).to.be.true; }); - it("returns true if execution module is enabled successfully", async function () { + it("returns true if compute provider is enabled successfully", async function () { const { enclave } = await loadFixture(setup); - const result = await enclave.enableExecutionModule.staticCall(AddressTwo); + const result = await enclave.enableComputeProvider.staticCall(AddressTwo); expect(result).to.be.true; }); - it("emits ExecutionModuleEnabled event", async function () { + it("emits ComputeProviderEnabled event", async function () { const { enclave } = await loadFixture(setup); - await expect(enclave.enableExecutionModule(AddressTwo)) - .to.emit(enclave, "ExecutionModuleEnabled") + await expect(enclave.enableComputeProvider(AddressTwo)) + .to.emit(enclave, "ComputeProviderEnabled") .withArgs(AddressTwo); }); }); - describe("disableExecutionModule()", function () { + describe("disableComputeProvider()", function () { it("reverts if not called by owner", async function () { const { notTheOwner, enclave, - mocks: { executionModule }, + mocks: { computeProvider }, } = await loadFixture(setup); await expect( - enclave.connect(notTheOwner).disableExecutionModule(executionModule), + enclave.connect(notTheOwner).disableComputeProvider(computeProvider), ) .to.be.revertedWithCustomError(enclave, "OwnableUnauthorizedAccount") .withArgs(notTheOwner); }); - it("reverts if execution module is not enabled", async function () { + it("reverts if compute provider is not enabled", async function () { const { enclave } = await loadFixture(setup); - await expect(enclave.disableExecutionModule(AddressTwo)) + await expect(enclave.disableComputeProvider(AddressTwo)) .to.be.revertedWithCustomError(enclave, "ModuleNotEnabled") .withArgs(AddressTwo); }); - it("disables execution module correctly", async function () { + it("disables compute provider correctly", async function () { const { enclave, - mocks: { executionModule }, + mocks: { computeProvider }, } = await loadFixture(setup); - expect(await enclave.executionModules(executionModule)).to.be.true; - await enclave.disableExecutionModule(executionModule); - expect(await enclave.executionModules(executionModule)).to.be.false; + expect(await enclave.computeProviders(computeProvider)).to.be.true; + await enclave.disableComputeProvider(computeProvider); + expect(await enclave.computeProviders(computeProvider)).to.be.false; }); - it("returns true if execution module is disabled successfully", async function () { + it("returns true if compute provider is disabled successfully", async function () { const { enclave, - mocks: { executionModule }, + mocks: { computeProvider }, } = await loadFixture(setup); const result = - await enclave.disableExecutionModule.staticCall(executionModule); + await enclave.disableComputeProvider.staticCall(computeProvider); expect(result).to.be.true; }); - it("emits ExecutionModuleDisabled event", async function () { + it("emits ComputeProviderDisabled event", async function () { const { enclave, - mocks: { executionModule }, + mocks: { computeProvider }, } = await loadFixture(setup); - await expect(enclave.disableExecutionModule(executionModule)) - .to.emit(enclave, "ExecutionModuleDisabled") - .withArgs(executionModule); + await expect(enclave.disableComputeProvider(computeProvider)) + .to.emit(enclave, "ComputeProviderDisabled") + .withArgs(computeProvider); }); }); @@ -412,10 +410,10 @@ describe("Enclave", function () { request.threshold, request.startTime, request.duration, - request.computationModule, - request.cMParams, - request.executionModule, - request.eMParams, + request.e3Program, + request.e3ProgramParams, + request.computeProvider, + request.computeProviderParams, ), ).to.be.revertedWithCustomError(enclave, "PaymentRequired"); }); @@ -427,10 +425,10 @@ describe("Enclave", function () { [0, 2], request.startTime, request.duration, - request.computationModule, - request.cMParams, - request.executionModule, - request.eMParams, + request.e3Program, + request.e3ProgramParams, + request.computeProvider, + request.computeProviderParams, { value: 10 }, ), ).to.be.revertedWithCustomError(enclave, "InvalidThreshold"); @@ -443,10 +441,10 @@ describe("Enclave", function () { [3, 2], request.startTime, request.duration, - request.computationModule, - request.cMParams, - request.executionModule, - request.eMParams, + request.e3Program, + request.e3ProgramParams, + request.computeProvider, + request.computeProviderParams, { value: 10 }, ), ).to.be.revertedWithCustomError(enclave, "InvalidThreshold"); @@ -459,10 +457,10 @@ describe("Enclave", function () { request.threshold, request.startTime, 0, - request.computationModule, - request.cMParams, - request.executionModule, - request.eMParams, + request.e3Program, + request.e3ProgramParams, + request.computeProvider, + request.computeProviderParams, { value: 10 }, ), ).to.be.revertedWithCustomError(enclave, "InvalidDuration"); @@ -475,15 +473,15 @@ describe("Enclave", function () { request.threshold, request.startTime, time.duration.days(31), - request.computationModule, - request.cMParams, - request.executionModule, - request.eMParams, + request.e3Program, + request.e3ProgramParams, + request.computeProvider, + request.computeProviderParams, { value: 10 }, ), ).to.be.revertedWithCustomError(enclave, "InvalidDuration"); }); - it("reverts if computation module is not enabled", async function () { + it("reverts if E3 Program is not enabled", async function () { const { enclave, request } = await loadFixture(setup); await expect( enclave.request( @@ -492,16 +490,16 @@ describe("Enclave", function () { request.startTime, request.duration, ethers.ZeroAddress, - request.cMParams, - request.executionModule, - request.eMParams, + request.e3ProgramParams, + request.computeProvider, + request.computeProviderParams, { value: 10 }, ), ) - .to.be.revertedWithCustomError(enclave, "ComputationModuleNotAllowed") + .to.be.revertedWithCustomError(enclave, "E3ProgramNotAllowed") .withArgs(ethers.ZeroAddress); }); - it("reverts if execution module is not enabled", async function () { + it("reverts if compute provider is not enabled", async function () { const { enclave, request } = await loadFixture(setup); await expect( enclave.request( @@ -509,17 +507,17 @@ describe("Enclave", function () { request.threshold, request.startTime, request.duration, - request.computationModule, - request.cMParams, + request.e3Program, + request.e3ProgramParams, ethers.ZeroAddress, - request.eMParams, + request.computeProviderParams, { value: 10 }, ), ) .to.be.revertedWithCustomError(enclave, "ModuleNotEnabled") .withArgs(ethers.ZeroAddress); }); - it("reverts if input computation module does not return input validator address", async function () { + it("reverts if input E3 Program does not return input validator address", async function () { const { enclave, request } = await loadFixture(setup); await expect( @@ -528,15 +526,15 @@ describe("Enclave", function () { request.threshold, request.startTime, request.duration, - request.computationModule, + request.e3Program, ZeroHash, - request.executionModule, - request.eMParams, + request.computeProvider, + request.computeProviderParams, { value: 10 }, ), ).to.be.revertedWithCustomError(enclave, "InvalidComputation"); }); - it("reverts if input execution module does not return output verifier address", async function () { + it("reverts if input compute provider does not return output verifier address", async function () { const { enclave, request } = await loadFixture(setup); await expect( enclave.request( @@ -544,13 +542,13 @@ describe("Enclave", function () { request.threshold, request.startTime, request.duration, - request.computationModule, - request.cMParams, - request.executionModule, + request.e3Program, + request.e3ProgramParams, + request.computeProvider, ZeroHash, { value: 10 }, ), - ).to.be.revertedWithCustomError(enclave, "InvalidExecutionModuleSetup"); + ).to.be.revertedWithCustomError(enclave, "InvalidComputeProviderSetup"); }); it("reverts if committee selection fails", async function () { const { enclave, request } = await loadFixture(setup); @@ -560,10 +558,10 @@ describe("Enclave", function () { request.threshold, request.startTime, request.duration, - request.computationModule, - request.cMParams, - request.executionModule, - request.eMParams, + request.e3Program, + request.e3ProgramParams, + request.computeProvider, + request.computeProviderParams, { value: 10 }, ), ).to.be.revertedWithCustomError(enclave, "CommitteeSelectionFailed"); @@ -575,23 +573,23 @@ describe("Enclave", function () { request.threshold, request.startTime, request.duration, - request.computationModule, - request.cMParams, - request.executionModule, - request.eMParams, + request.e3Program, + request.e3ProgramParams, + request.computeProvider, + request.computeProviderParams, { value: 10 }, ); const e3 = await enclave.getE3(0); expect(e3.threshold).to.deep.equal(request.threshold); expect(e3.expiration).to.equal(0n); - expect(e3.computationModule).to.equal(request.computationModule); + expect(e3.e3Program).to.equal(request.e3Program); expect(e3.inputValidator).to.equal( - abiCoder.decode(["address"], request.cMParams)[0], + abiCoder.decode(["address"], request.e3ProgramParams)[0], ); - expect(e3.executionModule).to.equal(request.executionModule); - expect(e3.outputVerifier).to.equal( - abiCoder.decode(["address"], request.eMParams)[0], + expect(e3.computeProvider).to.equal(request.computeProvider); + expect(e3.decryptionVerifier).to.equal( + abiCoder.decode(["address"], request.computeProviderParams)[0], ); expect(e3.committeePublicKey).to.equal("0x"); expect(e3.ciphertextOutput).to.equal("0x"); @@ -604,10 +602,10 @@ describe("Enclave", function () { request.threshold, request.startTime, request.duration, - request.computationModule, - request.cMParams, - request.executionModule, - request.eMParams, + request.e3Program, + request.e3ProgramParams, + request.computeProvider, + request.computeProviderParams, { value: 10 }, ); const e3 = await enclave.getE3(0); @@ -618,8 +616,8 @@ describe("Enclave", function () { 0, e3, request.filter, - request.computationModule, - request.executionModule, + request.e3Program, + request.computeProvider, ); }); }); @@ -640,10 +638,10 @@ describe("Enclave", function () { request.threshold, request.startTime, request.duration, - request.computationModule, - request.cMParams, - request.executionModule, - request.eMParams, + request.e3Program, + request.e3ProgramParams, + request.computeProvider, + request.computeProviderParams, { value: 10 }, ); @@ -665,10 +663,10 @@ describe("Enclave", function () { request.threshold, startTime, request.duration, - request.computationModule, - request.cMParams, - request.executionModule, - request.eMParams, + request.e3Program, + request.e3ProgramParams, + request.computeProvider, + request.computeProviderParams, { value: 10 }, ); @@ -679,31 +677,31 @@ describe("Enclave", function () { }); it("reverts if E3 start has expired", async function () { const { enclave, request } = await loadFixture(setup); - const startTime = [await time.latest(), (await time.latest()) + 1] as [ - number, - number, - ]; + const startTime = [ + (await time.latest()) + 1, + (await time.latest()) + 1000, + ] as [number, number]; await enclave.request( request.filter, request.threshold, startTime, request.duration, - request.computationModule, - request.cMParams, - request.executionModule, - request.eMParams, + request.e3Program, + request.e3ProgramParams, + request.computeProvider, + request.computeProviderParams, { value: 10 }, ); - const _ = mine(1, { interval: 1000 }); + await mine(2, { interval: 2000 }); await expect(enclave.activate(0)).to.be.revertedWithCustomError( enclave, "E3Expired", ); }); - it("reverts if cyphernodeRegistry does not return a public key", async function () { + it("reverts if ciphernodeRegistry does not return a public key", async function () { const { enclave, request } = await loadFixture(setup); const startTime = [ (await time.latest()) + 1000, @@ -715,10 +713,10 @@ describe("Enclave", function () { request.threshold, startTime, request.duration, - request.computationModule, - request.cMParams, - request.executionModule, - request.eMParams, + request.e3Program, + request.e3ProgramParams, + request.computeProvider, + request.computeProviderParams, { value: 10 }, ); @@ -739,21 +737,21 @@ describe("Enclave", function () { request.threshold, startTime, request.duration, - request.computationModule, - request.cMParams, - request.executionModule, - request.eMParams, + request.e3Program, + request.e3ProgramParams, + request.computeProvider, + request.computeProviderParams, { value: 10 }, ); - const _ = mine(1, { interval: 1000 }); + await mine(1, { interval: 1000 }); await expect(enclave.activate(0)).to.be.revertedWithCustomError( enclave, "E3Expired", ); }); - it("reverts if cyphernodeRegistry does not return a public key", async function () { + it("reverts if ciphernodeRegistry does not return a public key", async function () { const { enclave, request } = await loadFixture(setup); await enclave.request( @@ -761,25 +759,25 @@ describe("Enclave", function () { request.threshold, request.startTime, request.duration, - request.computationModule, - request.cMParams, - request.executionModule, - request.eMParams, + request.e3Program, + request.e3ProgramParams, + request.computeProvider, + request.computeProviderParams, { value: 10 }, ); - const prevRegistry = await enclave.cyphernodeRegistry(); - const nextRegistry = await deployCyphernodeRegistryFixture( - "MockCyphernodeRegistryEmptyKey", + const prevRegistry = await enclave.ciphernodeRegistry(); + const nextRegistry = await deployCiphernodeRegistryFixture( + "MockCiphernodeRegistryEmptyKey", ); - await enclave.setCyphernodeRegistry(nextRegistry); + await enclave.setCiphernodeRegistry(nextRegistry); await expect(enclave.activate(0)).to.be.revertedWithCustomError( enclave, "CommitteeSelectionFailed", ); - await enclave.setCyphernodeRegistry(prevRegistry); + await enclave.setCiphernodeRegistry(prevRegistry); await expect(enclave.activate(0)).to.not.be.reverted; }); it("sets committeePublicKey correctly", async () => { @@ -794,10 +792,10 @@ describe("Enclave", function () { request.threshold, request.startTime, request.duration, - request.computationModule, - request.cMParams, - request.executionModule, - request.eMParams, + request.e3Program, + request.e3ProgramParams, + request.computeProvider, + request.computeProviderParams, { value: 10 }, ); @@ -820,10 +818,10 @@ describe("Enclave", function () { request.threshold, request.startTime, request.duration, - request.computationModule, - request.cMParams, - request.executionModule, - request.eMParams, + request.e3Program, + request.e3ProgramParams, + request.computeProvider, + request.computeProviderParams, { value: 10 }, ); @@ -839,10 +837,10 @@ describe("Enclave", function () { request.threshold, request.startTime, request.duration, - request.computationModule, - request.cMParams, - request.executionModule, - request.eMParams, + request.e3Program, + request.e3ProgramParams, + request.computeProvider, + request.computeProviderParams, { value: 10 }, ); @@ -872,10 +870,10 @@ describe("Enclave", function () { request.threshold, request.startTime, request.duration, - request.computationModule, - request.cMParams, - request.executionModule, - request.eMParams, + request.e3Program, + request.e3ProgramParams, + request.computeProvider, + request.computeProviderParams, { value: 10 }, ); @@ -887,8 +885,6 @@ describe("Enclave", function () { .withArgs(0); await enclave.activate(0); - - await expect(enclave.publishInput(0, inputData)).to.not.be.reverted; }); it("reverts if input is not valid", async function () { @@ -899,10 +895,10 @@ describe("Enclave", function () { request.threshold, request.startTime, request.duration, - request.computationModule, - request.cMParams, - request.executionModule, - request.eMParams, + request.e3Program, + request.e3ProgramParams, + request.computeProvider, + request.computeProviderParams, { value: 10 }, ); @@ -920,15 +916,14 @@ describe("Enclave", function () { request.threshold, request.startTime, request.duration, - request.computationModule, - request.cMParams, - request.executionModule, - request.eMParams, + request.e3Program, + request.e3ProgramParams, + request.computeProvider, + request.computeProviderParams, { value: 10 }, ); await enclave.activate(0); - await expect(enclave.publishInput(0, ZeroHash)).to.not.be.reverted; await mine(2, { interval: request.duration }); @@ -936,7 +931,7 @@ describe("Enclave", function () { enclave.publishInput(0, ZeroHash), ).to.be.revertedWithCustomError(enclave, "InputDeadlinePassed"); }); - it("sets ciphertextInput correctly", async function () { + it("returns true if input is published successfully", async function () { const { enclave, request } = await loadFixture(setup); const inputData = "0x12345678"; @@ -945,43 +940,52 @@ describe("Enclave", function () { request.threshold, request.startTime, request.duration, - request.computationModule, - request.cMParams, - request.executionModule, - request.eMParams, + request.e3Program, + request.e3ProgramParams, + request.computeProvider, + request.computeProviderParams, { value: 10 }, ); await enclave.activate(0); - await expect(await enclave.publishInput(0, inputData)).to.not.be.reverted; - let e3 = await enclave.getE3(0); - expect(e3.inputs[0]).to.equal(inputData); - await expect(await enclave.publishInput(0, inputData)).to.not.be.reverted; - e3 = await enclave.getE3(0); - expect(e3.inputs[1]).to.equal(inputData); + expect(await enclave.publishInput.staticCall(0, inputData)).to.equal( + true, + ); }); - it("returns true if input is published successfully", async function () { + + it("adds inputHash to merkle tree", async function () { const { enclave, request } = await loadFixture(setup); - const inputData = "0x12345678"; + const inputData = abiCoder.encode(["bytes"], ["0xaabbccddeeff"]); + + // To create an instance of a LeanIMT, you must provide the hash function. + const tree = new LeanIMT(hash); await enclave.request( request.filter, request.threshold, request.startTime, request.duration, - request.computationModule, - request.cMParams, - request.executionModule, - request.eMParams, + request.e3Program, + request.e3ProgramParams, + request.computeProvider, + request.computeProviderParams, { value: 10 }, ); - await enclave.activate(0); + const e3Id = 0; - expect(await enclave.publishInput.staticCall(0, inputData)).to.equal( - true, - ); + await enclave.activate(e3Id); + + tree.insert(hash(BigInt(ethers.keccak256(inputData)), BigInt(0))); + + await enclave.publishInput(e3Id, inputData); + expect(await enclave.getInputRoot(e3Id)).to.equal(tree.root); + + const secondInputData = abiCoder.encode(["bytes"], ["0x112233445566"]); + tree.insert(hash(BigInt(ethers.keccak256(secondInputData)), BigInt(1))); + await enclave.publishInput(e3Id, secondInputData); + expect(await enclave.getInputRoot(e3Id)).to.equal(tree.root); }); it("emits InputPublished event", async function () { const { enclave, request } = await loadFixture(setup); @@ -991,10 +995,10 @@ describe("Enclave", function () { request.threshold, request.startTime, request.duration, - request.computationModule, - request.cMParams, - request.executionModule, - request.eMParams, + request.e3Program, + request.e3ProgramParams, + request.computeProvider, + request.computeProviderParams, { value: 10 }, ); @@ -1002,10 +1006,11 @@ describe("Enclave", function () { const inputData = abiCoder.encode(["bytes"], ["0xaabbccddeeff"]); await enclave.activate(e3Id); + const expectedHash = hash(BigInt(ethers.keccak256(inputData)), BigInt(0)); await expect(enclave.publishInput(e3Id, inputData)) .to.emit(enclave, "InputPublished") - .withArgs(e3Id, inputData); + .withArgs(e3Id, inputData, expectedHash, 0); }); }); @@ -1026,10 +1031,10 @@ describe("Enclave", function () { request.threshold, request.startTime, request.duration, - request.computationModule, - request.cMParams, - request.executionModule, - request.eMParams, + request.e3Program, + request.e3ProgramParams, + request.computeProvider, + request.computeProviderParams, { value: 10 }, ); await expect(enclave.publishCiphertextOutput(e3Id, "0x")) @@ -1043,10 +1048,10 @@ describe("Enclave", function () { request.threshold, [await time.latest(), (await time.latest()) + 100], request.duration, - request.computationModule, - request.cMParams, - request.executionModule, - request.eMParams, + request.e3Program, + request.e3ProgramParams, + request.computeProvider, + request.computeProviderParams, { value: 10 }, ); const block = await tx.getBlock(); @@ -1069,10 +1074,10 @@ describe("Enclave", function () { request.threshold, [await time.latest(), (await time.latest()) + 100], request.duration, - request.computationModule, - request.cMParams, - request.executionModule, - request.eMParams, + request.e3Program, + request.e3ProgramParams, + request.computeProvider, + request.computeProviderParams, { value: 10 }, ); await enclave.activate(e3Id); @@ -1094,10 +1099,10 @@ describe("Enclave", function () { request.threshold, [await time.latest(), (await time.latest()) + 100], request.duration, - request.computationModule, - request.cMParams, - request.executionModule, - request.eMParams, + request.e3Program, + request.e3ProgramParams, + request.computeProvider, + request.computeProviderParams, { value: 10 }, ); await enclave.activate(e3Id); @@ -1115,10 +1120,10 @@ describe("Enclave", function () { request.threshold, [await time.latest(), (await time.latest()) + 100], request.duration, - request.computationModule, - request.cMParams, - request.executionModule, - request.eMParams, + request.e3Program, + request.e3ProgramParams, + request.computeProvider, + request.computeProviderParams, { value: 10 }, ); await enclave.activate(e3Id); @@ -1136,10 +1141,10 @@ describe("Enclave", function () { request.threshold, [await time.latest(), (await time.latest()) + 100], request.duration, - request.computationModule, - request.cMParams, - request.executionModule, - request.eMParams, + request.e3Program, + request.e3ProgramParams, + request.computeProvider, + request.computeProviderParams, { value: 10 }, ); await enclave.activate(e3Id); @@ -1157,10 +1162,10 @@ describe("Enclave", function () { request.threshold, [await time.latest(), (await time.latest()) + 100], request.duration, - request.computationModule, - request.cMParams, - request.executionModule, - request.eMParams, + request.e3Program, + request.e3ProgramParams, + request.computeProvider, + request.computeProviderParams, { value: 10 }, ); await enclave.activate(e3Id); @@ -1189,10 +1194,10 @@ describe("Enclave", function () { request.threshold, [await time.latest(), (await time.latest()) + 100], request.duration, - request.computationModule, - request.cMParams, - request.executionModule, - request.eMParams, + request.e3Program, + request.e3ProgramParams, + request.computeProvider, + request.computeProviderParams, { value: 10 }, ); await expect(enclave.publishPlaintextOutput(e3Id, "0x")) @@ -1208,10 +1213,10 @@ describe("Enclave", function () { request.threshold, [await time.latest(), (await time.latest()) + 100], request.duration, - request.computationModule, - request.cMParams, - request.executionModule, - request.eMParams, + request.e3Program, + request.e3ProgramParams, + request.computeProvider, + request.computeProviderParams, { value: 10 }, ); await enclave.activate(e3Id); @@ -1228,10 +1233,10 @@ describe("Enclave", function () { request.threshold, [await time.latest(), (await time.latest()) + 100], request.duration, - request.computationModule, - request.cMParams, - request.executionModule, - request.eMParams, + request.e3Program, + request.e3ProgramParams, + request.computeProvider, + request.computeProviderParams, { value: 10 }, ); await enclave.activate(e3Id); @@ -1254,10 +1259,10 @@ describe("Enclave", function () { request.threshold, [await time.latest(), (await time.latest()) + 100], request.duration, - request.computationModule, - request.cMParams, - request.executionModule, - request.eMParams, + request.e3Program, + request.e3ProgramParams, + request.computeProvider, + request.computeProviderParams, { value: 10 }, ); await enclave.activate(e3Id); @@ -1276,10 +1281,10 @@ describe("Enclave", function () { request.threshold, [await time.latest(), (await time.latest()) + 100], request.duration, - request.computationModule, - request.cMParams, - request.executionModule, - request.eMParams, + request.e3Program, + request.e3ProgramParams, + request.computeProvider, + request.computeProviderParams, { value: 10 }, ); await enclave.activate(e3Id); @@ -1299,10 +1304,10 @@ describe("Enclave", function () { request.threshold, [await time.latest(), (await time.latest()) + 100], request.duration, - request.computationModule, - request.cMParams, - request.executionModule, - request.eMParams, + request.e3Program, + request.e3ProgramParams, + request.computeProvider, + request.computeProviderParams, { value: 10 }, ); await enclave.activate(e3Id); @@ -1321,10 +1326,10 @@ describe("Enclave", function () { request.threshold, [await time.latest(), (await time.latest()) + 100], request.duration, - request.computationModule, - request.cMParams, - request.executionModule, - request.eMParams, + request.e3Program, + request.e3ProgramParams, + request.computeProvider, + request.computeProviderParams, { value: 10 }, ); await enclave.activate(e3Id); diff --git a/packages/evm/test/fixtures/Enclave.fixture.ts b/packages/evm/test/fixtures/Enclave.fixture.ts index 539e7cc9..aee379e0 100644 --- a/packages/evm/test/fixtures/Enclave.fixture.ts +++ b/packages/evm/test/fixtures/Enclave.fixture.ts @@ -12,8 +12,15 @@ export async function deployEnclaveFixture({ registry: string; maxDuration?: number; }) { + const poseidonFactory = await ethers.getContractFactory("PoseidonT3"); + const poseidonDeployment = await poseidonFactory.deploy(); + const deployment = await ( - await ethers.getContractFactory("Enclave") + await ethers.getContractFactory("Enclave", { + libraries: { + PoseidonT3: await poseidonDeployment.getAddress(), + }, + }) ).deploy(owner, registry, maxDuration); return Enclave__factory.connect(await deployment.getAddress(), owner); diff --git a/packages/evm/test/fixtures/MockCiphernodeRegistry.fixture.ts b/packages/evm/test/fixtures/MockCiphernodeRegistry.fixture.ts new file mode 100644 index 00000000..4e960cbc --- /dev/null +++ b/packages/evm/test/fixtures/MockCiphernodeRegistry.fixture.ts @@ -0,0 +1,15 @@ +import { ethers } from "hardhat"; + +import { MockCiphernodeRegistry__factory } from "../../types"; + +export async function deployCiphernodeRegistryFixture(name?: string) { + const [signer] = await ethers.getSigners(); + const deployment = await ( + await ethers.getContractFactory(name || "MockCiphernodeRegistry") + ).deploy(); + + return MockCiphernodeRegistry__factory.connect( + await deployment.getAddress(), + signer.provider, + ); +} diff --git a/packages/evm/test/fixtures/MockComputationModule.fixture.ts b/packages/evm/test/fixtures/MockComputationModule.fixture.ts deleted file mode 100644 index 9eba3fb9..00000000 --- a/packages/evm/test/fixtures/MockComputationModule.fixture.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { ethers } from "hardhat"; - -import { MockComputationModule__factory } from "../../types/factories/contracts/test/MockComputationModule__factory"; - -export async function deployComputationModuleFixture() { - const deployment = await ( - await ethers.getContractFactory("MockComputationModule") - ).deploy(); - - return MockComputationModule__factory.connect(await deployment.getAddress()); -} diff --git a/packages/evm/test/fixtures/MockComputeProvider.fixture.ts b/packages/evm/test/fixtures/MockComputeProvider.fixture.ts new file mode 100644 index 00000000..bcb2f0ce --- /dev/null +++ b/packages/evm/test/fixtures/MockComputeProvider.fixture.ts @@ -0,0 +1,11 @@ +import { ethers } from "hardhat"; + +import { MockComputeProvider__factory } from "../../types/factories/contracts/test/MockComputeProvider__factory"; + +export async function deployComputeProviderFixture() { + const deployment = await ( + await ethers.getContractFactory("MockComputeProvider") + ).deploy(); + + return MockComputeProvider__factory.connect(await deployment.getAddress()); +} diff --git a/packages/evm/test/fixtures/MockCyphernodeRegistry.fixture.ts b/packages/evm/test/fixtures/MockCyphernodeRegistry.fixture.ts deleted file mode 100644 index eecc554c..00000000 --- a/packages/evm/test/fixtures/MockCyphernodeRegistry.fixture.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { ethers } from "hardhat"; - -import { MockCyphernodeRegistry__factory } from "../../types"; - -export async function deployCyphernodeRegistryFixture(name?: string) { - const [signer] = await ethers.getSigners(); - const deployment = await ( - await ethers.getContractFactory(name || "MockCyphernodeRegistry") - ).deploy(); - - return MockCyphernodeRegistry__factory.connect( - await deployment.getAddress(), - signer.provider, - ); -} diff --git a/packages/evm/test/fixtures/MockDecryptionVerifier.fixture.ts b/packages/evm/test/fixtures/MockDecryptionVerifier.fixture.ts new file mode 100644 index 00000000..415771be --- /dev/null +++ b/packages/evm/test/fixtures/MockDecryptionVerifier.fixture.ts @@ -0,0 +1,10 @@ +import { ethers } from "hardhat"; + +import { MockDecryptionVerifier__factory } from "../../types/factories/contracts/test/MockDecryptionVerifier__factory"; + +export async function deployDecryptionVerifierFixture() { + const deployment = await ( + await ethers.getContractFactory("MockDecryptionVerifier") + ).deploy(); + return MockDecryptionVerifier__factory.connect(await deployment.getAddress()); +} diff --git a/packages/evm/test/fixtures/MockE3Program.fixture.ts b/packages/evm/test/fixtures/MockE3Program.fixture.ts new file mode 100644 index 00000000..353525b3 --- /dev/null +++ b/packages/evm/test/fixtures/MockE3Program.fixture.ts @@ -0,0 +1,11 @@ +import { ethers } from "hardhat"; + +import { MockE3Program__factory } from "../../types/factories/contracts/test/MockE3Program__factory"; + +export async function deployE3ProgramFixture() { + const deployment = await ( + await ethers.getContractFactory("MockE3Program") + ).deploy(); + + return MockE3Program__factory.connect(await deployment.getAddress()); +} diff --git a/packages/evm/test/fixtures/MockExecutionModule.fixture.ts b/packages/evm/test/fixtures/MockExecutionModule.fixture.ts deleted file mode 100644 index 0b8d6582..00000000 --- a/packages/evm/test/fixtures/MockExecutionModule.fixture.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { ethers } from "hardhat"; - -import { MockExecutionModule__factory } from "../../types/factories/contracts/test/MockExecutionModule__factory"; - -export async function deployExecutionModuleFixture() { - const deployment = await ( - await ethers.getContractFactory("MockExecutionModule") - ).deploy(); - - return MockExecutionModule__factory.connect(await deployment.getAddress()); -} diff --git a/packages/evm/test/fixtures/MockOutputVerifier.fixture.ts b/packages/evm/test/fixtures/MockOutputVerifier.fixture.ts deleted file mode 100644 index b7a9c28a..00000000 --- a/packages/evm/test/fixtures/MockOutputVerifier.fixture.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { ethers } from "hardhat"; - -import { MockOutputVerifier__factory } from "../../types/factories/contracts/test/MockOutputVerifier__factory"; - -export async function deployOutputVerifierFixture() { - const deployment = await ( - await ethers.getContractFactory("MockOutputVerifier") - ).deploy(); - return MockOutputVerifier__factory.connect(await deployment.getAddress()); -} diff --git a/packages/evm/yarn.lock b/packages/evm/yarn.lock index c287ce52..709ecbf8 100644 --- a/packages/evm/yarn.lock +++ b/packages/evm/yarn.lock @@ -680,53 +680,53 @@ "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" -"@nomicfoundation/edr-darwin-arm64@0.4.0": - version "0.4.0" - resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-darwin-arm64/-/edr-darwin-arm64-0.4.0.tgz#bbb43f0e01f40839b0bd38c2c443cb6910ae955f" - integrity sha512-7+rraFk9tCqvfemv9Ita5vTlSBAeO/S5aDKOgGRgYt0JEKZlrX161nDW6UfzMPxWl9GOLEDUzCEaYuNmXseUlg== +"@nomicfoundation/edr-darwin-arm64@0.5.2": + version "0.5.2" + resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-darwin-arm64/-/edr-darwin-arm64-0.5.2.tgz#72f7a826c9f0f2c91308edca562de3b9484ac079" + integrity sha512-Gm4wOPKhbDjGTIRyFA2QUAPfCXA1AHxYOKt3yLSGJkQkdy9a5WW+qtqKeEKHc/+4wpJSLtsGQfpzyIzggFfo/A== -"@nomicfoundation/edr-darwin-x64@0.4.0": - version "0.4.0" - resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-darwin-x64/-/edr-darwin-x64-0.4.0.tgz#b1ffcd9142418fd8498de34a7336b3f977907c86" - integrity sha512-+Hrc0mP9L6vhICJSfyGo/2taOToy1AIzVZawO3lU8Lf7oDQXfhQ4UkZnkWAs9SVu1eUwHUGGGE0qB8644piYgg== +"@nomicfoundation/edr-darwin-x64@0.5.2": + version "0.5.2" + resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-darwin-x64/-/edr-darwin-x64-0.5.2.tgz#6d0fedb219d664631c6feddc596ab8c3bbc36fa8" + integrity sha512-ClyABq2dFCsrYEED3/UIO0c7p4H1/4vvlswFlqUyBpOkJccr75qIYvahOSJRM62WgUFRhbSS0OJXFRwc/PwmVg== -"@nomicfoundation/edr-linux-arm64-gnu@0.4.0": - version "0.4.0" - resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-linux-arm64-gnu/-/edr-linux-arm64-gnu-0.4.0.tgz#8173d16d4f6f2b3e82ba7096d2a1ea3619d8bfa7" - integrity sha512-4HUDMchNClQrVRfVTqBeSX92hM/3khCgpZkXP52qrnJPqgbdCxosOehlQYZ65wu0b/kaaZSyvACgvCLSQ5oSzQ== +"@nomicfoundation/edr-linux-arm64-gnu@0.5.2": + version "0.5.2" + resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-linux-arm64-gnu/-/edr-linux-arm64-gnu-0.5.2.tgz#60e4d52d963141bc2bb4a02639dc590a7fbdda2f" + integrity sha512-HWMTVk1iOabfvU2RvrKLDgtFjJZTC42CpHiw2h6rfpsgRqMahvIlx2jdjWYzFNy1jZKPTN1AStQ/91MRrg5KnA== -"@nomicfoundation/edr-linux-arm64-musl@0.4.0": - version "0.4.0" - resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-linux-arm64-musl/-/edr-linux-arm64-musl-0.4.0.tgz#b1ce293a7c3e0d9f70391e1aef1a82b83b997567" - integrity sha512-D4J935ZRL8xfnP3zIFlCI9jXInJ0loDUkCTLeCEbOf2uuDumWDghKNQlF1itUS+EHaR1pFVBbuwqq8hVK0dASg== +"@nomicfoundation/edr-linux-arm64-musl@0.5.2": + version "0.5.2" + resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-linux-arm64-musl/-/edr-linux-arm64-musl-0.5.2.tgz#6676a09eab57c435a16ffc144658c896acca9baa" + integrity sha512-CwsQ10xFx/QAD5y3/g5alm9+jFVuhc7uYMhrZAu9UVF+KtVjeCvafj0PaVsZ8qyijjqVuVsJ8hD1x5ob7SMcGg== -"@nomicfoundation/edr-linux-x64-gnu@0.4.0": - version "0.4.0" - resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-linux-x64-gnu/-/edr-linux-x64-gnu-0.4.0.tgz#4c12c4e4bfd3d837f5663ad7cbf7cb6d5634ef83" - integrity sha512-6x7HPy+uN5Cb9N77e2XMmT6+QSJ+7mRbHnhkGJ8jm4cZvWuj2Io7npOaeHQ3YHK+TiQpTnlbkjoOIpEwpY3XZA== +"@nomicfoundation/edr-linux-x64-gnu@0.5.2": + version "0.5.2" + resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-linux-x64-gnu/-/edr-linux-x64-gnu-0.5.2.tgz#f558d9697ce961410e7a7468f9ab8c8a601b9df6" + integrity sha512-CWVCEdhWJ3fmUpzWHCRnC0/VLBDbqtqTGTR6yyY1Ep3S3BOrHEAvt7h5gx85r2vLcztisu2vlDq51auie4IU1A== -"@nomicfoundation/edr-linux-x64-musl@0.4.0": - version "0.4.0" - resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-linux-x64-musl/-/edr-linux-x64-musl-0.4.0.tgz#8842004aa1a47c504f10863687da28b65dca7baa" - integrity sha512-3HFIJSXgyubOiaN4MWGXx2xhTnhwlJk0PiSYNf9+L/fjBtcRkb2nM910ZJHTvqCb6OT98cUnaKuAYdXIW2amgw== +"@nomicfoundation/edr-linux-x64-musl@0.5.2": + version "0.5.2" + resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-linux-x64-musl/-/edr-linux-x64-musl-0.5.2.tgz#c9c9cbb2997499f75c1d022be724b0551d44569f" + integrity sha512-+aJDfwhkddy2pP5u1ISg3IZVAm0dO836tRlDTFWtvvSMQ5hRGqPcWwlsbobhDQsIxhPJyT7phL0orCg5W3WMeA== -"@nomicfoundation/edr-win32-x64-msvc@0.4.0": - version "0.4.0" - resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-win32-x64-msvc/-/edr-win32-x64-msvc-0.4.0.tgz#29d8bbb2edf9912a95f5453855cf17cdcb269957" - integrity sha512-CP4GsllEfXEz+lidcGYxKe5rDJ60TM5/blB5z/04ELVvw6/CK9eLcYeku7HV0jvV7VE6dADYKSdQyUkvd0El+A== +"@nomicfoundation/edr-win32-x64-msvc@0.5.2": + version "0.5.2" + resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-win32-x64-msvc/-/edr-win32-x64-msvc-0.5.2.tgz#f16db88bf4fe09a996af0a25096e09deecb72bfa" + integrity sha512-CcvvuA3sAv7liFNPsIR/68YlH6rrybKzYttLlMr80d4GKJjwJ5OKb3YgE6FdZZnOfP19HEHhsLcE0DPLtY3r0w== -"@nomicfoundation/edr@^0.4.0": - version "0.4.0" - resolved "https://registry.yarnpkg.com/@nomicfoundation/edr/-/edr-0.4.0.tgz#4895ecb6ef321136db837458949c37cce4a29459" - integrity sha512-T96DMSogO8TCdbKKctvxfsDljbhFOUKWc9fHJhSeUh71EEho2qR4951LKQF7t7UWEzguVYh/idQr5L/E3QeaMw== +"@nomicfoundation/edr@^0.5.2": + version "0.5.2" + resolved "https://registry.yarnpkg.com/@nomicfoundation/edr/-/edr-0.5.2.tgz#e8c7b3d3dd4a312432ab3930dec60f76dc5c4926" + integrity sha512-hW/iLvUQZNTVjFyX/I40rtKvvDOqUEyIi96T28YaLfmPL+3LW2lxmYLUXEJ6MI14HzqxDqrLyhf6IbjAa2r3Dw== dependencies: - "@nomicfoundation/edr-darwin-arm64" "0.4.0" - "@nomicfoundation/edr-darwin-x64" "0.4.0" - "@nomicfoundation/edr-linux-arm64-gnu" "0.4.0" - "@nomicfoundation/edr-linux-arm64-musl" "0.4.0" - "@nomicfoundation/edr-linux-x64-gnu" "0.4.0" - "@nomicfoundation/edr-linux-x64-musl" "0.4.0" - "@nomicfoundation/edr-win32-x64-msvc" "0.4.0" + "@nomicfoundation/edr-darwin-arm64" "0.5.2" + "@nomicfoundation/edr-darwin-x64" "0.5.2" + "@nomicfoundation/edr-linux-arm64-gnu" "0.5.2" + "@nomicfoundation/edr-linux-arm64-musl" "0.5.2" + "@nomicfoundation/edr-linux-x64-gnu" "0.5.2" + "@nomicfoundation/edr-linux-x64-musl" "0.5.2" + "@nomicfoundation/edr-win32-x64-msvc" "0.5.2" "@nomicfoundation/ethereumjs-common@4.0.4": version "4.0.4" @@ -874,6 +874,11 @@ resolved "https://registry.yarnpkg.com/@openzeppelin/contracts-upgradeable/-/contracts-upgradeable-5.0.2.tgz#3e5321a2ecdd0b206064356798c21225b6ec7105" integrity sha512-0MmkHSHiW2NRFiT9/r5Lu4eJq5UJ4/tzlOgYXNAIj/ONkQTVnz22pLxDvp4C4uZ9he7ZFvGn3Driptn1/iU7tQ== +"@openzeppelin/contracts@^5.0.2": + version "5.0.2" + resolved "https://registry.yarnpkg.com/@openzeppelin/contracts/-/contracts-5.0.2.tgz#b1d03075e49290d06570b2fd42154d76c2a5d210" + integrity sha512-ytPc6eLGcHHnapAZ9S+5qsdomhjo6QBHTDRRBFfTxXIpsicMhVPouPgmUPebZZZGX7vt9USA+Z+0M0dSVtSUEA== + "@pkgjs/parseargs@^0.11.0": version "0.11.0" resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33" @@ -1303,6 +1308,27 @@ resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.2.0.tgz#756641adb587851b5ccb3e095daf27ae581c8406" integrity sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ== +"@zk-kit/lean-imt.sol@2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@zk-kit/lean-imt.sol/-/lean-imt.sol-2.0.0.tgz#4b0aee47854b5844455f9361396062139416e12b" + integrity sha512-e9pAm+IXveLPy7b1h05ipIo6U44vp8g/2E+Ocx3PIloMu7lgTXFkIeZj/qZ/iLgEMsF74T0dsg7aVIT0B0nsDA== + dependencies: + poseidon-solidity "0.0.5" + +"@zk-kit/lean-imt@^2.1.0": + version "2.1.0" + resolved "https://registry.yarnpkg.com/@zk-kit/lean-imt/-/lean-imt-2.1.0.tgz#ca876463a0249fc3de76b2f8821c7af31f94998a" + integrity sha512-RbG6QmTrurken7HzrJQouKiXKyGTpcoD+czQ1jvExRIA83k9w+SEsRdB7anPE8WoMKWAandDe09BzDCk6AirSw== + dependencies: + "@zk-kit/utils" "1.2.0" + +"@zk-kit/utils@1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@zk-kit/utils/-/utils-1.2.0.tgz#7f5dfadb9512f1a090639c912395a6684b560ba2" + integrity sha512-Ut9zfnlBVpopZG/s600Ds/FPSWXiPhO4q8949kmXTzwDXytjnvFbDZIFdWqE/lA7/NZjvykiTnnVwmanMxv2+w== + dependencies: + buffer "^6.0.3" + abbrev@1: version "1.1.1" resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" @@ -1544,6 +1570,11 @@ base-x@^3.0.2: dependencies: safe-buffer "^5.0.1" +base64-js@^1.3.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" + integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== + bech32@1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/bech32/-/bech32-1.1.4.tgz#e38c9f37bf179b8eb16ae3a772b40c356d4832e9" @@ -1663,6 +1694,14 @@ buffer-xor@^1.0.3: resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9" integrity sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ== +buffer@^6.0.3: + version "6.0.3" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-6.0.3.tgz#2ace578459cc8fbe2a70aaa8f52ee63b6a74c6c6" + integrity sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA== + dependencies: + base64-js "^1.3.1" + ieee754 "^1.2.1" + bytes@3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5" @@ -1890,16 +1929,16 @@ command-line-usage@^6.1.0: table-layout "^1.0.2" typical "^5.2.0" -commander@3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/commander/-/commander-3.0.2.tgz#6837c3fb677ad9933d1cfba42dd14d5117d6b39e" - integrity sha512-Gar0ASD4BDyKC4hl4DwHqDrmvjoxWKZigVnAbn5H1owvm4CxCPdb0HQDehwNYMJpla5+M2tPmPARzhtYuwpHow== - commander@^10.0.0: version "10.0.1" resolved "https://registry.yarnpkg.com/commander/-/commander-10.0.1.tgz#881ee46b4f77d1c1dccc5823433aa39b022cbe06" integrity sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug== +commander@^8.1.0: + version "8.3.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-8.3.0.tgz#4837ea1b2da67b9c616a67afbb0fafee567bca66" + integrity sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww== + concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" @@ -2080,6 +2119,11 @@ doctrine@^3.0.0: dependencies: esutils "^2.0.2" +dotenv@^16.4.5: + version "16.4.5" + resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.4.5.tgz#cdd3b3b604cb327e286b4762e13502f717cb099f" + integrity sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg== + eastasianwidth@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb" @@ -2585,17 +2629,6 @@ fp-ts@^1.0.0: resolved "https://registry.yarnpkg.com/fp-ts/-/fp-ts-1.19.5.tgz#3da865e585dfa1fdfd51785417357ac50afc520a" integrity sha512-wDNqTimnzs8QqpldiId9OavWK2NptormjXnRJTQecNjzwfyp6P/8s/zG8e4h3ja3oqkKaY72UlTjQYt/1yXf9A== -fs-extra@^0.30.0: - version "0.30.0" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-0.30.0.tgz#f233ffcc08d4da7d432daa449776989db1df93f0" - integrity sha512-UvSPKyhMn6LEd/WpUaV9C9t3zATuqoqfWc3QdPhPLb58prN9tqYPlPWi8Krxi44loBoUzlobqZ3+8tGpxxSzwA== - dependencies: - graceful-fs "^4.1.2" - jsonfile "^2.1.0" - klaw "^1.0.0" - path-is-absolute "^1.0.0" - rimraf "^2.2.8" - fs-extra@^10.0.0: version "10.1.0" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-10.1.0.tgz#02873cfbc4084dde127eaa5f9905eef2325d1abf" @@ -2857,7 +2890,7 @@ graceful-fs@4.2.10: resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c" integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA== -graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.1.9, graceful-fs@^4.2.0: +graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0: version "4.2.11" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== @@ -2930,14 +2963,14 @@ hardhat-gas-reporter@^2.2.0: sha1 "^1.1.1" viem "2.7.14" -hardhat@^2.19.2: - version "2.22.5" - resolved "https://registry.yarnpkg.com/hardhat/-/hardhat-2.22.5.tgz#7e1a4311fa9e34a1cfe337784eae06706f6469a5" - integrity sha512-9Zq+HonbXCSy6/a13GY1cgHglQRfh4qkzmj1tpPlhxJDwNVnhxlReV6K7hCWFKlOrV13EQwsdcD0rjcaQKWRZw== +hardhat@^2.22.0: + version "2.22.9" + resolved "https://registry.yarnpkg.com/hardhat/-/hardhat-2.22.9.tgz#d8f2720561dc60f5cc0ee80c82f9b1907fd61c88" + integrity sha512-sWiuI/yRdFUPfndIvL+2H18Vs2Gav0XacCFYY5msT5dHOWkhLxESJySIk9j83mXL31aXL8+UMA9OgViFLexklg== dependencies: "@ethersproject/abi" "^5.1.2" "@metamask/eth-sig-util" "^4.0.0" - "@nomicfoundation/edr" "^0.4.0" + "@nomicfoundation/edr" "^0.5.2" "@nomicfoundation/ethereumjs-common" "4.0.4" "@nomicfoundation/ethereumjs-tx" "5.0.4" "@nomicfoundation/ethereumjs-util" "9.0.4" @@ -2971,7 +3004,7 @@ hardhat@^2.19.2: raw-body "^2.4.1" resolve "1.17.0" semver "^6.3.0" - solc "0.7.3" + solc "0.8.26" source-map-support "^0.5.13" stacktrace-parser "^0.1.10" tsort "0.0.1" @@ -3093,6 +3126,11 @@ iconv-lite@0.4.24: dependencies: safer-buffer ">= 2.1.2 < 3" +ieee754@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" + integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== + ignore@^5.1.1, ignore@^5.2.0, ignore@^5.2.4, ignore@^5.3.1: version "5.3.1" resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.1.tgz#5073e554cd42c5b33b394375f538b8593e34d4ef" @@ -3296,13 +3334,6 @@ json-stable-stringify-without-jsonify@^1.0.1: resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== -jsonfile@^2.1.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-2.4.0.tgz#3736a2b428b87bbda0cc83b53fa3d633a35c2ae8" - integrity sha512-PKllAqbgLgxHaj8TElYymKCAgrASebJrWpTnEkOaTowt23VKXXN0sUeriJ+eh7y6ufb/CC5ap11pz71/cM0hUw== - optionalDependencies: - graceful-fs "^4.1.6" - jsonfile@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" @@ -3345,13 +3376,6 @@ kind-of@^6.0.2: resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== -klaw@^1.0.0: - version "1.3.1" - resolved "https://registry.yarnpkg.com/klaw/-/klaw-1.3.1.tgz#4088433b46b3b1ba259d78785d8e96f73ba02439" - integrity sha512-TED5xi9gGQjGpNnvRWknrwAB1eL5GciPfVFOt3Vk1OJCVDQbzuSfrF3hkUQKlsgKrG1F+0t5W0m+Fje1jIt8rw== - optionalDependencies: - graceful-fs "^4.1.9" - latest-version@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/latest-version/-/latest-version-7.0.0.tgz#843201591ea81a4d404932eeb61240fe04e9e5da" @@ -3892,6 +3916,16 @@ pluralize@^8.0.0: resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-8.0.0.tgz#1a6fa16a38d12a1901e0320fa017051c539ce3b1" integrity sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA== +poseidon-lite@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/poseidon-lite/-/poseidon-lite-0.3.0.tgz#93c42f6f9b870f154f2722dfd686b909c4285765" + integrity sha512-ilJj4MIve4uBEG7SrtPqUUNkvpJ/pLVbndxa0WvebcQqeIhe+h72JR4g0EvwchUzm9sOQDlOjiDNmRAgxNZl4A== + +poseidon-solidity@0.0.5, poseidon-solidity@^0.0.5: + version "0.0.5" + resolved "https://registry.yarnpkg.com/poseidon-solidity/-/poseidon-solidity-0.0.5.tgz#3f93e01cfe25f6d2f2fac49734fbb00961b84655" + integrity sha512-NzrvSwHzvZgT4hvg2GyGqeR+UOU/eLSEt4wAoXEua+VaR7NTKKwx1X9bPlh1VMBEVEno+IWvkRBbidFGzTeAqQ== + prelude-ls@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" @@ -4046,7 +4080,7 @@ require-directory@^2.1.1: resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== -require-from-string@^2.0.0, require-from-string@^2.0.2: +require-from-string@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== @@ -4094,13 +4128,6 @@ reusify@^1.0.4: resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== -rimraf@^2.2.8: - version "2.7.1" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" - integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== - dependencies: - glob "^7.1.3" - rimraf@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" @@ -4291,18 +4318,16 @@ slice-ansi@^4.0.0: astral-regex "^2.0.0" is-fullwidth-code-point "^3.0.0" -solc@0.7.3: - version "0.7.3" - resolved "https://registry.yarnpkg.com/solc/-/solc-0.7.3.tgz#04646961bd867a744f63d2b4e3c0701ffdc7d78a" - integrity sha512-GAsWNAjGzIDg7VxzP6mPjdurby3IkGCjQcM8GFYZT6RyaoUZKmMU6Y7YwG+tFGhv7dwZ8rmR4iwFDrrD99JwqA== +solc@0.8.26: + version "0.8.26" + resolved "https://registry.yarnpkg.com/solc/-/solc-0.8.26.tgz#afc78078953f6ab3e727c338a2fefcd80dd5b01a" + integrity sha512-yiPQNVf5rBFHwN6SIf3TUUvVAFKcQqmSUFeq+fb6pNRCo0ZCgpYOZDi3BVoezCPIAcKrVYd/qXlBLUP9wVrZ9g== dependencies: command-exists "^1.2.8" - commander "3.0.2" + commander "^8.1.0" follow-redirects "^1.12.1" - fs-extra "^0.30.0" js-sha3 "0.8.0" memorystream "^0.3.1" - require-from-string "^2.0.0" semver "^5.5.0" tmp "0.0.33" @@ -4314,10 +4339,10 @@ solhint-plugin-prettier@^0.1.0: "@prettier/sync" "^0.3.0" prettier-linter-helpers "^1.0.0" -solhint@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/solhint/-/solhint-5.0.1.tgz#f0f783bd9d945e5a27b102295a3f28edba241d6c" - integrity sha512-QeQLS9HGCnIiibt+xiOa/+MuP7BWz9N7C5+Mj9pLHshdkNhuo3AzCpWmjfWVZBUuwIUO3YyCRVIcYLR3YOKGfg== +solhint@^5.0.3: + version "5.0.3" + resolved "https://registry.yarnpkg.com/solhint/-/solhint-5.0.3.tgz#b57f6d2534fe09a60f9db1b92e834363edd1cbde" + integrity sha512-OLCH6qm/mZTCpplTXzXTJGId1zrtNuDYP5c2e6snIv/hdRVxPfBBz/bAlL91bY/Accavkayp2Zp2BaDSrLVXTQ== dependencies: "@solidity-parser/parser" "^0.18.0" ajv "^6.12.6" @@ -4417,7 +4442,16 @@ string-format@^2.0.0: resolved "https://registry.yarnpkg.com/string-format/-/string-format-2.0.0.tgz#f2df2e7097440d3b65de31b6d40d54c96eaffb9b" integrity sha512-bbEs3scLeYNXLecRRuk6uJxdXUSj6le/8rNPHChIJTn2V79aXVTR1EH2OH5zLKKoz0V02fOUKZZcw01pLUShZA== -"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.2, string-width@^4.2.3: +"string-width-cjs@npm:string-width@^4.2.0": + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.2, string-width@^4.2.3: version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -4442,7 +4476,14 @@ string_decoder@^1.1.1: dependencies: safe-buffer "~5.2.0" -"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1: +"strip-ansi-cjs@npm:strip-ansi@^6.0.1": + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== @@ -4836,7 +4877,16 @@ workerpool@6.2.1: resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.2.1.tgz#46fc150c17d826b86a008e5a4508656777e9c343" integrity sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw== -"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0: +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrap-ansi@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== From 73bfbbcfeaf2fdaaa8fa87f39ff5a2c5c32bc618 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=B3=CE=BB?= Date: Sat, 14 Sep 2024 23:37:10 +1000 Subject: [PATCH 54/87] Merge main after changes (#68) From 9201374e69da62e8edc6eb6903792489b7303eb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=B3=CE=BB?= Date: Mon, 16 Sep 2024 10:10:27 +1000 Subject: [PATCH 55/87] add tasks for adding/removing ciphernodes (#66) (#70) Co-authored-by: samepant --- packages/evm/README.md | 14 ++++++++++++ packages/evm/hardhat.config.ts | 1 + packages/evm/package.json | 2 ++ packages/evm/tasks/ciphernode.ts | 38 ++++++++++++++++++++++++++++++++ 4 files changed, 55 insertions(+) create mode 100644 packages/evm/tasks/ciphernode.ts diff --git a/packages/evm/README.md b/packages/evm/README.md index 86dbc875..3f0bbb0b 100644 --- a/packages/evm/README.md +++ b/packages/evm/README.md @@ -10,3 +10,17 @@ This will add the deployment information to the `./deployments` directory. Be sure to configure your desired network in `hardhat.config.ts` before deploying. + +## Registering a Ciphernode + +To add a ciphernode to the registry, run + +``` +yarn ciphernode:add --network [network] --ciphernode-address [address] +``` + +To remove a ciphernode, run + +``` +yarn ciphernode:remove --network [network] --ciphernode-address [address] +``` diff --git a/packages/evm/hardhat.config.ts b/packages/evm/hardhat.config.ts index 822d257c..7cfa0ea3 100644 --- a/packages/evm/hardhat.config.ts +++ b/packages/evm/hardhat.config.ts @@ -6,6 +6,7 @@ import { vars } from "hardhat/config"; import type { NetworkUserConfig } from "hardhat/types"; import "./tasks/accounts"; +import "./tasks/ciphernode"; dotenv.config(); diff --git a/packages/evm/package.json b/packages/evm/package.json index d568a1ec..6dae0e66 100644 --- a/packages/evm/package.json +++ b/packages/evm/package.json @@ -73,6 +73,8 @@ "compile": "cross-env TS_NODE_TRANSPILE_ONLY=true hardhat compile", "coverage": "hardhat coverage --solcoverjs ./.solcover.js --temp artifacts --testfiles \"test/**/*.ts\" && yarn typechain", "deploy": "hardhat deploy", + "ciphernode:add": "hardhat ciphernode:add", + "ciphernode:remove": "hardhat ciphernode:remove", "lint": "yarn lint:sol && yarn lint:ts && yarn prettier:check", "lint:sol": "solhint --max-warnings 0 \"contracts/**/*.sol\"", "lint:ts": "eslint --ignore-path ./.eslintignore --ext .js,.ts .", diff --git a/packages/evm/tasks/ciphernode.ts b/packages/evm/tasks/ciphernode.ts new file mode 100644 index 00000000..af706bfa --- /dev/null +++ b/packages/evm/tasks/ciphernode.ts @@ -0,0 +1,38 @@ +import { task } from "hardhat/config"; +import type { TaskArguments } from "hardhat/types"; + +task("ciphernode:add", "Register a ciphernode to the registry") + .addParam("ciphernodeAddress", "address of ciphernode to register") + .setAction(async function (taskArguments: TaskArguments, hre) { + const registry = await hre.deployments.get("CyphernodeRegistryOwnable"); + + const registryContract = await hre.ethers.getContractAt( + "CyphernodeRegistryOwnable", + registry.address, + ); + + const tx = await registryContract.addCyphernode( + taskArguments.ciphernodeAddress, + ); + await tx.wait(); + + console.log(`Ciphernode ${taskArguments.ciphernodeAddress} registered`); + }); + +task("ciphernode:remove", "Remove a ciphernode from the registry") + .addParam("ciphernodeAddress", "address of ciphernode to remove") + .setAction(async function (taskArguments: TaskArguments, hre) { + const registry = await hre.deployments.get("CyphernodeRegistryOwnable"); + + const registryContract = await hre.ethers.getContractAt( + "CyphernodeRegistryOwnable", + registry.address, + ); + + const tx = await registryContract.removeCyphernode( + taskArguments.ciphernodeAddress, + ); + await tx.wait(); + + console.log(`Ciphernode ${taskArguments.ciphernodeAddress} removed`); + }); From 9e7d7345b70cdebb2ff99e04ee3d31d2b3813dd2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=B3=CE=BB?= Date: Tue, 17 Sep 2024 00:35:28 +1000 Subject: [PATCH 56/87] Refactor registries to be more modular (#78) * Refactor registries to be more modular * Tidy up ciphernode registry * Tidy up registry --- packages/ciphernode/Cargo.lock | 116 ++++++++++ .../core/src/ciphernode_registry.rs | 92 ++++++++ packages/ciphernode/core/src/lib.rs | 24 +- .../ciphernode/core/src/main_aggregator.rs | 57 +++++ .../ciphernode/core/src/main_ciphernode.rs | 71 ++++++ .../ciphernode/core/src/plaintext_registry.rs | 101 +++++++++ .../ciphernode/core/src/publickey_registry.rs | 102 +++++++++ packages/ciphernode/core/src/registry.rs | 213 ++++++------------ packages/ciphernode/enclave_node/Cargo.toml | 5 +- .../enclave_node/src/bin/aggregator.rs | 17 ++ .../enclave_node/src/bin/event-node.rs | 0 .../ciphernode/enclave_node/src/bin/node.rs | 19 ++ 12 files changed, 670 insertions(+), 147 deletions(-) create mode 100644 packages/ciphernode/core/src/ciphernode_registry.rs create mode 100644 packages/ciphernode/core/src/main_aggregator.rs create mode 100644 packages/ciphernode/core/src/main_ciphernode.rs create mode 100644 packages/ciphernode/core/src/plaintext_registry.rs create mode 100644 packages/ciphernode/core/src/publickey_registry.rs create mode 100644 packages/ciphernode/enclave_node/src/bin/aggregator.rs create mode 100644 packages/ciphernode/enclave_node/src/bin/event-node.rs create mode 100644 packages/ciphernode/enclave_node/src/bin/node.rs diff --git a/packages/ciphernode/Cargo.lock b/packages/ciphernode/Cargo.lock index bb298e9b..c46f11e4 100644 --- a/packages/ciphernode/Cargo.lock +++ b/packages/ciphernode/Cargo.lock @@ -1125,6 +1125,55 @@ dependencies = [ "ws_stream_wasm", ] +[[package]] +name = "anstream" +version = "0.6.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" + +[[package]] +name = "anstyle-parse" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" +dependencies = [ + "anstyle", + "windows-sys 0.52.0", +] + [[package]] name = "anyhow" version = "1.0.86" @@ -1888,6 +1937,52 @@ dependencies = [ "zeroize", ] +[[package]] +name = "clap" +version = "4.5.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e5a21b8495e732f1b3c364c9949b201ca7bae518c502c80256c96ad79eaf6ac" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8cf2dd12af7a047ad9d6da2b6b249759a22a7abc0f474c1dae1777afa4b21a73" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.5.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "501d359d5f3dcaf6ecdeee48833ae73ec6e42723a1e52419c79abf9507eec0a0" +dependencies = [ + "heck 0.5.0", + "proc-macro2", + "quote", + "syn 2.0.72", +] + +[[package]] +name = "clap_lex" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" + +[[package]] +name = "colorchoice" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" + [[package]] name = "concurrent-queue" version = "2.5.0" @@ -2333,12 +2428,15 @@ dependencies = [ "alloy-primitives 0.6.4", "async-std", "bfv", + "clap", "enclave-core", "eth", "fhe", "fhe-traits", "fhe-util", "p2p", + "rand", + "rand_chacha", "sortition", "tokio", ] @@ -3293,6 +3391,12 @@ version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" +[[package]] +name = "is_terminal_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" + [[package]] name = "itertools" version = "0.10.5" @@ -5767,6 +5871,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + [[package]] name = "strum" version = "0.26.3" @@ -6363,6 +6473,12 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + [[package]] name = "valuable" version = "0.1.0" diff --git a/packages/ciphernode/core/src/ciphernode_registry.rs b/packages/ciphernode/core/src/ciphernode_registry.rs new file mode 100644 index 00000000..2fd8341d --- /dev/null +++ b/packages/ciphernode/core/src/ciphernode_registry.rs @@ -0,0 +1,92 @@ +// TODO: spawn and supervise child actors +use crate::{Ciphernode, Data, E3id, EnclaveEvent, EventBus, Fhe, InitializeWithEnclaveEvent}; +use actix::prelude::*; +use alloy_primitives::Address; +use std::collections::HashMap; + +pub struct CiphernodeRegistry { + bus: Addr, + data: Addr, + address: Address, + ciphernodes: HashMap>, + buffers: HashMap>, +} + +impl CiphernodeRegistry { + pub fn new(bus: Addr, data: Addr, address: Address) -> Self { + Self { + bus, + data, + address, + ciphernodes: HashMap::new(), + buffers: HashMap::new(), + } + } + + pub fn attach(bus: Addr, data: Addr, address: Address) -> Addr { + CiphernodeRegistry::new(bus, data, address).start() + } +} + +impl Actor for CiphernodeRegistry { + type Context = Context; +} + +impl Handler for CiphernodeRegistry { + type Result = (); + fn handle(&mut self, msg: InitializeWithEnclaveEvent, _: &mut Self::Context) -> Self::Result { + let InitializeWithEnclaveEvent { fhe, event, .. } = msg; + let EnclaveEvent::CommitteeRequested { data, .. } = event else { + return; + }; + let ciphernode_factory = self.ciphernode_factory(fhe.clone()); + self.ciphernodes + .entry(data.e3_id.clone()) + .or_insert_with(ciphernode_factory); + } +} + +impl Handler for CiphernodeRegistry { + type Result = (); + + fn handle(&mut self, msg: EnclaveEvent, _ctx: &mut Self::Context) -> Self::Result { + let Some(e3_id) = msg.get_e3_id() else { + return; + }; + self.forward_message(&e3_id, msg); + } +} + +impl CiphernodeRegistry { + fn ciphernode_factory(&self, fhe: Addr) -> impl FnOnce() -> Addr { + let data = self.data.clone(); + let bus = self.bus.clone(); + let address = self.address; + move || Ciphernode::new(bus, fhe, data, address).start() + } + + fn store_msg(&mut self, e3_id: E3id, msg: EnclaveEvent) { + self.buffers.entry(e3_id).or_default().push(msg); + } + + fn take_msgs(&mut self, e3_id: E3id) -> Vec { + self.buffers + .get_mut(&e3_id) + .map(std::mem::take) + .unwrap_or_default() + } + + fn forward_message(&mut self, e3_id: &E3id, msg: EnclaveEvent) { + // Buffer events for each thing that has not been created + if let Some(act) = self.ciphernodes.clone().get(e3_id) { + let msgs = self.take_msgs(e3_id.clone()); + let recipient = act.clone().recipient(); + recipient.do_send(msg.clone()); + for m in msgs { + recipient.do_send(m); + } + } else { + self.store_msg(e3_id.clone(), msg.clone()); + } + } +} diff --git a/packages/ciphernode/core/src/lib.rs b/packages/ciphernode/core/src/lib.rs index 556cde12..1fd31bf9 100644 --- a/packages/ciphernode/core/src/lib.rs +++ b/packages/ciphernode/core/src/lib.rs @@ -3,6 +3,7 @@ // #![warn(missing_docs, unused_imports)] mod ciphernode; +mod ciphernode_registry; mod ciphernode_selector; mod data; mod enclave_contract; @@ -10,10 +11,14 @@ mod eventbus; mod events; mod fhe; mod logger; +mod main_aggregator; +mod main_ciphernode; mod ordered_set; mod p2p; mod plaintext_aggregator; +mod plaintext_registry; mod publickey_aggregator; +mod publickey_registry; mod registry; mod serializers; mod sortition; @@ -21,15 +26,20 @@ mod sortition; // TODO: this is too permissive pub use actix::prelude::*; pub use ciphernode::*; +pub use ciphernode_registry::*; pub use ciphernode_selector::*; pub use data::*; pub use eventbus::*; pub use events::*; pub use fhe::*; pub use logger::*; +pub use main_aggregator::*; +pub use main_ciphernode::*; pub use p2p::*; pub use plaintext_aggregator::*; +pub use plaintext_registry::*; pub use publickey_aggregator::*; +pub use publickey_registry::*; pub use registry::*; pub use sortition::*; @@ -46,8 +56,9 @@ mod tests { CiphertextSerializer, DecryptionShareSerializer, PublicKeySerializer, PublicKeyShareSerializer, }, - CiphernodeAdded, CiphernodeSelected, CiphertextOutputPublished, DecryptionshareCreated, - PlaintextAggregated, Registry, ResetHistory, SharedRng, Sortition, + CiphernodeAdded, CiphernodeRegistry, CiphernodeSelected, CiphertextOutputPublished, + DecryptionshareCreated, PlaintextAggregated, PlaintextRegistry, PublicKeyRegistry, + Registry, ResetHistory, SharedRng, Sortition, }; use actix::prelude::*; use alloy_primitives::Address; @@ -77,7 +88,14 @@ mod tests { // create ciphernode actor for managing ciphernode flow let sortition = Sortition::attach(bus.clone()); CiphernodeSelector::attach(bus.clone(), sortition.clone(), addr); - Registry::attach(bus.clone(), data.clone(), sortition, rng, addr).await; + Registry::attach( + bus.clone(), + rng, + Some(PublicKeyRegistry::attach(bus.clone(), sortition.clone())), + Some(PlaintextRegistry::attach(bus.clone(), sortition.clone())), + Some(CiphernodeRegistry::attach(bus.clone(), data, addr)), + ) + .await; } fn setup_bfv_params( diff --git a/packages/ciphernode/core/src/main_aggregator.rs b/packages/ciphernode/core/src/main_aggregator.rs new file mode 100644 index 00000000..ada40df7 --- /dev/null +++ b/packages/ciphernode/core/src/main_aggregator.rs @@ -0,0 +1,57 @@ +use std::sync::{Arc, Mutex}; + +use crate::{EventBus, P2p, PlaintextRegistry, PublicKeyRegistry, Registry, Sortition}; +use actix::{Actor, Addr, Context}; +use rand::SeedableRng; +use rand_chacha::rand_core::OsRng; +use tokio::task::JoinHandle; + +/// Main Ciphernode Actor +/// Suprvises all children +// TODO: add supervision logic +pub struct MainAggregator { + bus: Addr, + sortition: Addr, + registry: Addr, + p2p: Addr, +} + +impl MainAggregator { + pub fn new( + bus: Addr, + sortition: Addr, + registry: Addr, + p2p: Addr, + ) -> Self { + Self { + bus, + sortition, + registry, + p2p, + } + } + + pub async fn attach() -> (Addr, JoinHandle<()>) { + let rng = Arc::new(Mutex::new( + rand_chacha::ChaCha20Rng::from_rng(OsRng).expect("Failed to create RNG"), + )); + let bus = EventBus::new(true).start(); + let sortition = Sortition::attach(bus.clone()); + let registry = Registry::attach( + bus.clone(), + rng, + Some(PublicKeyRegistry::attach(bus.clone(), sortition.clone())), + Some(PlaintextRegistry::attach(bus.clone(), sortition.clone())), + None, + ) + .await; + let (p2p_addr, join_handle) = + P2p::spawn_libp2p(bus.clone()).expect("Failed to setup libp2p"); + let main_addr = MainAggregator::new(bus, sortition, registry, p2p_addr).start(); + (main_addr, join_handle) + } +} + +impl Actor for MainAggregator { + type Context = Context; +} diff --git a/packages/ciphernode/core/src/main_ciphernode.rs b/packages/ciphernode/core/src/main_ciphernode.rs new file mode 100644 index 00000000..66ed3681 --- /dev/null +++ b/packages/ciphernode/core/src/main_ciphernode.rs @@ -0,0 +1,71 @@ +use std::sync::{Arc, Mutex}; + +use crate::{CiphernodeRegistry, CiphernodeSelector, Data, EventBus, P2p, Registry, Sortition}; +use actix::{Actor, Addr, Context}; +use alloy_primitives::Address; +use rand::SeedableRng; +use rand_chacha::rand_core::OsRng; +use tokio::task::JoinHandle; + +/// Main Ciphernode Actor +/// Suprvises all children +// TODO: add supervision logic +pub struct MainCiphernode { + addr: Address, + bus: Addr, + data: Addr, + sortition: Addr, + selector: Addr, + registry: Addr, + p2p: Addr, +} + +impl MainCiphernode { + pub fn new( + addr: Address, + bus: Addr, + data: Addr, + sortition: Addr, + selector: Addr, + registry: Addr, + p2p: Addr, + ) -> Self { + Self { + addr, + bus, + data, + sortition, + selector, + registry, + p2p, + } + } + + pub async fn attach(address: Address) -> (Addr, JoinHandle<()>) { + let rng = Arc::new(Mutex::new( + rand_chacha::ChaCha20Rng::from_rng(OsRng).expect("Failed to create RNG"), + )); + let bus = EventBus::new(true).start(); + let data = Data::new(true).start(); // TODO: Use a sled backed Data Actor + let sortition = Sortition::attach(bus.clone()); + let selector = CiphernodeSelector::attach(bus.clone(), sortition.clone(), address); + let registry = Registry::attach( + bus.clone(), + rng, + None, + None, + Some(CiphernodeRegistry::attach(bus.clone(), data.clone(), address)), + ) + .await; + let (p2p_addr, join_handle) = + P2p::spawn_libp2p(bus.clone()).expect("Failed to setup libp2p"); + let main_addr = + MainCiphernode::new(address, bus, data, sortition, selector, registry, p2p_addr) + .start(); + (main_addr, join_handle) + } +} + +impl Actor for MainCiphernode { + type Context = Context; +} diff --git a/packages/ciphernode/core/src/plaintext_registry.rs b/packages/ciphernode/core/src/plaintext_registry.rs new file mode 100644 index 00000000..60127d5a --- /dev/null +++ b/packages/ciphernode/core/src/plaintext_registry.rs @@ -0,0 +1,101 @@ +// TODO: spawn and supervise child actors +use crate::{ + CommitteeMeta, E3id, EnclaveEvent, EventBus, Fhe, InitializeWithEnclaveEvent, + PlaintextAggregator, Sortition, +}; +use actix::prelude::*; +use std::collections::HashMap; + +pub struct PlaintextRegistry { + bus: Addr, + sortition: Addr, + buffers: HashMap>, + plaintexts: HashMap>, +} + +impl PlaintextRegistry { + pub fn new(bus: Addr, sortition: Addr) -> Self { + Self { + bus, + sortition, + plaintexts: HashMap::new(), + buffers: HashMap::new(), + } + } + + pub fn attach(bus: Addr, sortition: Addr) -> Addr { + PlaintextRegistry::new(bus.clone(), sortition).start() + } +} + +impl Actor for PlaintextRegistry { + type Context = Context; +} + +impl Handler for PlaintextRegistry { + type Result = (); + fn handle(&mut self, msg: InitializeWithEnclaveEvent, _: &mut Self::Context) -> Self::Result { + let InitializeWithEnclaveEvent { fhe, meta, event } = msg; + let EnclaveEvent::CiphertextOutputPublished { data, .. } = event else { + return; + }; + + let plaintext_factory = + self.plaintext_factory(data.e3_id.clone(), meta.clone(), fhe.clone()); + + self.plaintexts + .entry(data.e3_id) + .or_insert_with(plaintext_factory); + } +} + +impl Handler for PlaintextRegistry { + type Result = (); + + fn handle(&mut self, msg: EnclaveEvent, _ctx: &mut Self::Context) -> Self::Result { + let Some(e3_id) = msg.get_e3_id() else { + return; + }; + self.forward_message(&e3_id, msg); + } +} + +impl PlaintextRegistry { + fn plaintext_factory( + &self, + e3_id: E3id, + meta: CommitteeMeta, + fhe: Addr, + ) -> impl FnOnce() -> Addr { + let bus = self.bus.clone(); + let sortition = self.sortition.clone(); + let nodecount = meta.nodecount; + let seed = meta.seed; + move || PlaintextAggregator::new(fhe, bus, sortition, e3_id, nodecount, seed).start() + } + + fn store_msg(&mut self, e3_id: E3id, msg: EnclaveEvent) { + self.buffers.entry(e3_id).or_default().push(msg); + } + + fn take_msgs(&mut self, e3_id: E3id) -> Vec { + self.buffers + .get_mut(&e3_id) + .map(std::mem::take) + .unwrap_or_default() + } + + fn forward_message(&mut self, e3_id: &E3id, msg: EnclaveEvent) { + // Buffer events for each thing that has not been created + if let Some(act) = self.plaintexts.clone().get(e3_id) { + let msgs = self.take_msgs(e3_id.clone()); + let recipient = act.clone().recipient(); + recipient.do_send(msg.clone()); + for m in msgs { + recipient.do_send(m); + } + } else { + self.store_msg(e3_id.clone(), msg.clone()); + } + } +} diff --git a/packages/ciphernode/core/src/publickey_registry.rs b/packages/ciphernode/core/src/publickey_registry.rs new file mode 100644 index 00000000..51b7b3c6 --- /dev/null +++ b/packages/ciphernode/core/src/publickey_registry.rs @@ -0,0 +1,102 @@ +// TODO: spawn and supervise child actors +use crate::{ + E3id, EnclaveEvent, EventBus, Fhe, InitializeWithEnclaveEvent, PublicKeyAggregator, Sortition, +}; +use actix::prelude::*; +use std::collections::HashMap; + +pub struct PublicKeyRegistry { + bus: Addr, + sortition: Addr, + buffers: HashMap>, + public_keys: HashMap>, +} + +impl PublicKeyRegistry { + pub fn new(bus: Addr, sortition: Addr) -> Self { + Self { + bus, + sortition, + public_keys: HashMap::new(), + buffers: HashMap::new(), + } + } + + pub fn attach(bus: Addr, sortition: Addr) -> Addr { + PublicKeyRegistry::new(bus.clone(), sortition).start() + } +} + +impl Actor for PublicKeyRegistry { + type Context = Context; +} + +impl Handler for PublicKeyRegistry { + type Result = (); + fn handle(&mut self, msg: InitializeWithEnclaveEvent, _: &mut Self::Context) -> Self::Result { + let InitializeWithEnclaveEvent { fhe, event, .. } = msg; + let EnclaveEvent::CommitteeRequested { data, .. } = event else { + return; + }; + + let public_key_factory = self.public_key_factory( + fhe.clone(), + data.e3_id.clone(), + data.nodecount, + data.sortition_seed, + ); + self.public_keys + .entry(data.e3_id) + .or_insert_with(public_key_factory); + } +} + +impl Handler for PublicKeyRegistry { + type Result = (); + + fn handle(&mut self, msg: EnclaveEvent, _ctx: &mut Self::Context) -> Self::Result { + let Some(e3_id) = msg.get_e3_id() else { + return; + }; + self.forward_message(&e3_id, msg); + } +} + +impl PublicKeyRegistry { + fn public_key_factory( + &self, + fhe: Addr, + e3_id: E3id, + nodecount: usize, + seed: u64, + ) -> impl FnOnce() -> Addr { + let bus = self.bus.clone(); + let sortition = self.sortition.clone(); + move || PublicKeyAggregator::new(fhe, bus, sortition, e3_id, nodecount, seed).start() + } + + fn store_msg(&mut self, e3_id: E3id, msg: EnclaveEvent) { + self.buffers.entry(e3_id).or_default().push(msg); + } + + fn take_msgs(&mut self, e3_id: E3id) -> Vec { + self.buffers + .get_mut(&e3_id) + .map(std::mem::take) + .unwrap_or_default() + } + + fn forward_message(&mut self, e3_id: &E3id, msg: EnclaveEvent) { + // Buffer events for each thing that has not been created + if let Some(act) = self.public_keys.clone().get(e3_id) { + let msgs = self.take_msgs(e3_id.clone()); + let recipient = act.clone().recipient(); + recipient.do_send(msg.clone()); + for m in msgs { + recipient.do_send(m); + } + } else { + self.store_msg(e3_id.clone(), msg.clone()); + } + } +} diff --git a/packages/ciphernode/core/src/registry.rs b/packages/ciphernode/core/src/registry.rs index 817be879..6f7eedd5 100644 --- a/packages/ciphernode/core/src/registry.rs +++ b/packages/ciphernode/core/src/registry.rs @@ -1,69 +1,70 @@ // TODO: spawn and supervise child actors -// TODO: vertically modularize this so there is a registry for each function that get rolled up into one based -// on config use crate::{ - Ciphernode, CommitteeRequested, Data, E3id, EnclaveEvent, EventBus, Fhe, PlaintextAggregator, - PublicKeyAggregator, Sortition, Subscribe, + CiphernodeRegistry, CommitteeRequested, E3id, EnclaveEvent, EventBus, Fhe, PlaintextRegistry, + PublicKeyRegistry, Subscribe, }; use actix::prelude::*; -use alloy_primitives::Address; use rand_chacha::ChaCha20Rng; use std::{ collections::HashMap, sync::{Arc, Mutex}, }; -#[derive(Clone)] -struct CommitteeMeta { - nodecount: usize, - seed: u64, +#[derive(Message, Clone, Debug, PartialEq, Eq)] +#[rtype(result = "()")] +pub struct InitializeWithEnclaveEvent { + pub fhe: Addr, + pub meta: CommitteeMeta, + pub event: EnclaveEvent, +} + +impl InitializeWithEnclaveEvent { + pub fn new(fhe: Addr, meta: CommitteeMeta, event: EnclaveEvent) -> Self { + Self { fhe, meta, event } + } +} + +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct CommitteeMeta { + pub nodecount: usize, + pub seed: u64, } pub struct Registry { - bus: Addr, - ciphernodes: HashMap>, - data: Addr, - sortition: Addr, - address: Address, fhes: HashMap>, - plaintexts: HashMap>, - buffers: HashMap>>, meta: HashMap, - public_keys: HashMap>, + public_key: Option>, + plaintext: Option>, + ciphernode: Option>, rng: Arc>, } impl Registry { pub fn new( - bus: Addr, - data: Addr, - sortition: Addr, rng: Arc>, - address: Address, + public_key: Option>, + plaintext: Option>, + ciphernode: Option>, ) -> Self { Self { - bus, - data, - sortition, rng, - address, - ciphernodes: HashMap::new(), - plaintexts: HashMap::new(), - public_keys: HashMap::new(), - buffers: HashMap::new(), + public_key, + plaintext, + ciphernode, meta: HashMap::new(), fhes: HashMap::new(), } } + // TODO: use a builder pattern to manage the Option pub async fn attach( bus: Addr, - data: Addr, - sortition: Addr, rng: Arc>, - address: Address, + public_key: Option>, + plaintext: Option>, + ciphernode: Option>, ) -> Addr { - let addr = Registry::new(bus.clone(), data, sortition, rng, address).start(); + let addr = Registry::new(rng, public_key, plaintext, ciphernode).start(); bus.send(Subscribe::new("*", addr.clone().into())) .await .unwrap(); @@ -90,47 +91,56 @@ impl Handler for Registry { moduli, plaintext_modulus, crp, - sortition_seed, .. } = data; let fhe_factory = self.fhe_factory(moduli, degree, plaintext_modulus, crp); - let fhe = store(&e3_id, &mut self.fhes, fhe_factory); + let fhe = self.fhes.entry(e3_id.clone()).or_insert_with(fhe_factory); let meta = CommitteeMeta { nodecount: data.nodecount, seed: data.sortition_seed, }; - self.meta.entry(e3_id.clone()).or_insert(meta.clone()); - let public_key_factory = self.public_key_factory( - e3_id.clone(), - meta.clone(), - fhe.clone(), - sortition_seed, - ); - store(&e3_id, &mut self.public_keys, public_key_factory); - - let ciphernode_factory = self.ciphernode_factory(fhe.clone()); - store(&e3_id, &mut self.ciphernodes, ciphernode_factory); + if let Some(addr) = self.public_key.clone() { + addr.do_send(InitializeWithEnclaveEvent { + event: msg.clone(), + fhe: fhe.clone(), + meta: meta.clone(), + }) + } + + if let Some(addr) = self.ciphernode.clone() { + addr.do_send(InitializeWithEnclaveEvent { + event: msg.clone(), + fhe: fhe.clone(), + meta: meta.clone(), + }) + } } - EnclaveEvent::CiphertextOutputPublished { .. } => { - let Some(fhe) = self.fhes.get(&e3_id) else { + EnclaveEvent::CiphertextOutputPublished { data, .. } => { + let Some(plaintext) = self.plaintext.clone() else { + return; + }; + + let Some(fhe) = self.fhes.get(&data.e3_id) else { return; }; - let Some(meta) = self.meta.get(&e3_id) else { + let Some(meta) = self.meta.get(&data.e3_id) else { return; }; - let plaintext_factory = - self.plaintext_factory(e3_id.clone(), meta.clone(), fhe.clone()); - store(&e3_id, &mut self.plaintexts, plaintext_factory); + plaintext.do_send(InitializeWithEnclaveEvent { + event: msg.clone(), + fhe: fhe.clone(), + meta: meta.clone(), + }) } _ => (), }; - self.forward_message(&e3_id, msg); + self.forward_message(msg); } } @@ -150,100 +160,17 @@ impl Registry { } } - fn public_key_factory( - &self, - e3_id: E3id, - meta: CommitteeMeta, - fhe: Addr, - seed: u64, - ) -> impl FnOnce() -> Addr { - let bus = self.bus.clone(); - let nodecount = meta.nodecount; - let sortition = self.sortition.clone(); - move || PublicKeyAggregator::new(fhe, bus, sortition, e3_id, nodecount, seed).start() - } - - fn ciphernode_factory(&self, fhe: Addr) -> impl FnOnce() -> Addr { - let data = self.data.clone(); - let bus = self.bus.clone(); - let address = self.address; - move || Ciphernode::new(bus, fhe, data, address).start() - } - - fn plaintext_factory( - &self, - e3_id: E3id, - meta: CommitteeMeta, - fhe: Addr, - ) -> impl FnOnce() -> Addr { - let bus = self.bus.clone(); - let sortition = self.sortition.clone(); - let nodecount = meta.nodecount; - let seed = meta.seed; - move || PlaintextAggregator::new(fhe, bus, sortition, e3_id, nodecount, seed).start() - } - - fn store_msg(&mut self, e3_id: E3id, msg: EnclaveEvent, key: &str) { - self.buffers - .entry(e3_id) - .or_default() - .entry(key.to_owned()) - .or_default() - .push(msg); - } - - fn take_msgs(&mut self, e3_id: E3id, key: &str) -> Vec { - self.buffers - .get_mut(&e3_id) - .and_then(|inner_map| inner_map.get_mut(key)) - .map(std::mem::take) - .unwrap_or_default() - } - - fn forward_message(&mut self, e3_id: &E3id, msg: EnclaveEvent) { - // Buffer events for each thing that has not been created - // TODO: Needs tidying up as this is verbose and repeats - // TODO: use an enum for the buffer keys - if let Some(act) = self.public_keys.clone().get(e3_id) { - let msgs = self.take_msgs(e3_id.clone(), "public_keys"); - let recipient = act.clone().recipient(); - recipient.do_send(msg.clone()); - for m in msgs { - recipient.do_send(m); - } - } else { - self.store_msg(e3_id.clone(), msg.clone(), "public_keys"); + fn forward_message(&mut self, msg: EnclaveEvent) { + if let Some(addr) = self.ciphernode.clone() { + addr.do_send(msg.clone()) } - if let Some(act) = self.plaintexts.clone().get(e3_id) { - let msgs = self.take_msgs(e3_id.clone(), "plaintexts"); - let recipient = act.clone().recipient(); - recipient.do_send(msg.clone()); - for m in msgs { - recipient.do_send(m); - } - } else { - self.store_msg(e3_id.clone(), msg.clone(), "plaintexts"); + if let Some(addr) = self.public_key.clone() { + addr.do_send(msg.clone()) } - if let Some(act) = self.ciphernodes.clone().get(e3_id) { - let msgs = self.take_msgs(e3_id.clone(), "ciphernodes"); - let recipient = act.clone().recipient(); - recipient.do_send(msg.clone()); - for m in msgs { - recipient.do_send(m); - } - } else { - self.store_msg(e3_id.clone(), msg.clone(), "ciphernodes"); + if let Some(addr) = self.plaintext.clone() { + addr.do_send(msg.clone()) } } } - -// Store on a hashmap a Addr from the factory F -fn store(e3_id: &E3id, map: &mut HashMap>, creator: F) -> Addr -where - T: Actor>, - F: FnOnce() -> Addr, -{ - map.entry(e3_id.clone()).or_insert_with(creator).clone() -} diff --git a/packages/ciphernode/enclave_node/Cargo.toml b/packages/ciphernode/enclave_node/Cargo.toml index 228541b9..8e4d0db9 100644 --- a/packages/ciphernode/enclave_node/Cargo.toml +++ b/packages/ciphernode/enclave_node/Cargo.toml @@ -21,4 +21,7 @@ tokio = { version = "1.38", features = ["full"] } actix-rt = "2.10.0" alloy-primitives = { version = "0.6", default-features = false, features = ["rlp", "serde", "std"] } -alloy = { version = "0.2.1", features = ["full"] } \ No newline at end of file +alloy = { version = "0.2.1", features = ["full"] } +clap = { version = "4.5.17", features = ["derive"] } +rand_chacha = "0.3.1" +rand = "0.8.5" diff --git a/packages/ciphernode/enclave_node/src/bin/aggregator.rs b/packages/ciphernode/enclave_node/src/bin/aggregator.rs new file mode 100644 index 00000000..7378dc69 --- /dev/null +++ b/packages/ciphernode/enclave_node/src/bin/aggregator.rs @@ -0,0 +1,17 @@ +use alloy_primitives::Address; +use clap::Parser; +use enclave_core::MainAggregator; + +#[derive(Parser, Debug)] +#[command(author, version, about, long_about = None)] +struct Args { + #[arg(short, long)] + address: String, +} + +#[actix_rt::main] +async fn main() -> Result<(), Box> { + let (_, handle) = MainAggregator::attach().await; + let _ = tokio::join!(handle); + Ok(()) +} diff --git a/packages/ciphernode/enclave_node/src/bin/event-node.rs b/packages/ciphernode/enclave_node/src/bin/event-node.rs new file mode 100644 index 00000000..e69de29b diff --git a/packages/ciphernode/enclave_node/src/bin/node.rs b/packages/ciphernode/enclave_node/src/bin/node.rs new file mode 100644 index 00000000..001d6829 --- /dev/null +++ b/packages/ciphernode/enclave_node/src/bin/node.rs @@ -0,0 +1,19 @@ +use alloy_primitives::Address; +use clap::Parser; +use enclave_core::MainCiphernode; + +#[derive(Parser, Debug)] +#[command(author, version, about, long_about = None)] +struct Args { + #[arg(short, long)] + address: String, +} + +#[actix_rt::main] +async fn main() -> Result<(), Box> { + let args = Args::parse(); + let address = Address::parse_checksummed(&args.address, None).expect("Invalid address"); + let (_, handle) = MainCiphernode::attach(address).await; + let _ = tokio::join!(handle); + Ok(()) +} From 4d853a28c78e2f2b9f6e4c527da20222b12a31fa Mon Sep 17 00:00:00 2001 From: samepant Date: Mon, 16 Sep 2024 14:59:49 -0400 Subject: [PATCH 57/87] deploy public libraries if they don't exist on network --- packages/evm/deploy/deploy.ts | 43 ++++++++++++++++++++++++++++++---- packages/evm/hardhat.config.ts | 6 ++--- 2 files changed, 41 insertions(+), 8 deletions(-) diff --git a/packages/evm/deploy/deploy.ts b/packages/evm/deploy/deploy.ts index 35b99935..bde42ba0 100644 --- a/packages/evm/deploy/deploy.ts +++ b/packages/evm/deploy/deploy.ts @@ -1,5 +1,6 @@ import { DeployFunction } from "hardhat-deploy/types"; import { HardhatRuntimeEnvironment } from "hardhat/types"; +import { PoseidonT3, proxy } from "poseidon-solidity"; const THIRTY_DAYS_IN_SECONDS = 60 * 60 * 24 * 30; const addressOne = "0x0000000000000000000000000000000000000001"; @@ -8,26 +9,58 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { const { deployer } = await hre.getNamedAccounts(); const { deploy } = hre.deployments; + // First check if the proxy exists + if ((await hre.ethers.provider.getCode(proxy.address)) === "0x") { + // probably on the hardhat network + // fund the keyless account + const [sender] = await hre.ethers.getSigners(); + await sender.sendTransaction({ + to: proxy.from, + value: proxy.gas, + }); + + // then send the presigned transaction deploying the proxy + await hre.ethers.provider.broadcastTransaction(proxy.tx); + console.log(`Proxy deployed to: ${proxy.address}`); + } + + // Then deploy the hasher, if needed + if ((await hre.ethers.provider.getCode(PoseidonT3.address)) === "0x") { + const [sender] = await hre.ethers.getSigners(); + await sender.sendTransaction({ + to: proxy.address, + data: PoseidonT3.data, + }); + + console.log(`PoseidonT3 deployed to: ${PoseidonT3.address}`); + } + // Deploy Enclave contract const enclave = await deploy("Enclave", { from: deployer, args: [deployer, addressOne, THIRTY_DAYS_IN_SECONDS], log: true, + libraries: { + PoseidonT3: PoseidonT3.address, + }, }); console.log(`Enclave contract: `, enclave.address); - // Deploy CyphernodeRegistryOwnable contract + // Deploy CiphernodeRegistryOwnable contract - const cypherNodeRegistry = await deploy("CyphernodeRegistryOwnable", { + const cypherNodeRegistry = await deploy("CiphernodeRegistryOwnable", { from: deployer, args: [deployer, enclave.address], log: true, + libraries: { + PoseidonT3: PoseidonT3.address, + }, }); console.log( - `CyphernodeRegistryOwnable contract: `, + `CiphernodeRegistryOwnable contract: `, cypherNodeRegistry.address, ); @@ -47,14 +80,14 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { enclave.address, ); - const registryAddress = await enclaveContract.cyphernodeRegistry(); + const registryAddress = await enclaveContract.ciphernodeRegistry(); if (registryAddress === cypherNodeRegistry.address) { console.log(`Enclave contract already has registry`); return; } - const result = await enclaveContract.setCyphernodeRegistry( + const result = await enclaveContract.setCiphernodeRegistry( cypherNodeRegistry.address, ); await result.wait(); diff --git a/packages/evm/hardhat.config.ts b/packages/evm/hardhat.config.ts index 7cfa0ea3..4777a1d1 100644 --- a/packages/evm/hardhat.config.ts +++ b/packages/evm/hardhat.config.ts @@ -69,18 +69,17 @@ const config: HardhatUserConfig = { arbitrumOne: vars.get("ARBISCAN_API_KEY", ""), avalanche: vars.get("SNOWTRACE_API_KEY", ""), bsc: vars.get("BSCSCAN_API_KEY", ""), - mainnet: ETHERSCAN_API_KEY, + mainnet: ETHERSCAN_API_KEY || "", optimisticEthereum: vars.get("OPTIMISM_API_KEY", ""), polygon: vars.get("POLYGONSCAN_API_KEY", ""), polygonMumbai: vars.get("POLYGONSCAN_API_KEY", ""), - sepolia: ETHERSCAN_API_KEY, + sepolia: ETHERSCAN_API_KEY || "", }, }, gasReporter: { currency: "USD", enabled: process.env.REPORT_GAS ? true : false, excludeContracts: [], - src: "./contracts", }, networks: { hardhat: { @@ -130,6 +129,7 @@ const config: HardhatUserConfig = { }, overrides: { "node_modules/poseidon-solidity/PoseidonT3.sol": { + version: "0.8.27", settings: { optimizer: { enabled: true, From 4a3458fc11066141a98db0b86503c4056e64eb1b Mon Sep 17 00:00:00 2001 From: samepant Date: Mon, 16 Sep 2024 15:02:14 -0400 Subject: [PATCH 58/87] use correct version for poseidon contract --- packages/evm/hardhat.config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/evm/hardhat.config.ts b/packages/evm/hardhat.config.ts index 4777a1d1..6dd7c4e4 100644 --- a/packages/evm/hardhat.config.ts +++ b/packages/evm/hardhat.config.ts @@ -129,7 +129,7 @@ const config: HardhatUserConfig = { }, overrides: { "node_modules/poseidon-solidity/PoseidonT3.sol": { - version: "0.8.27", + version: "0.7.0", settings: { optimizer: { enabled: true, From beb231a339953a0380036fe3ee85cecda069edfd Mon Sep 17 00:00:00 2001 From: samepant Date: Mon, 16 Sep 2024 16:36:13 -0400 Subject: [PATCH 59/87] fix ciphernode references --- packages/evm/tasks/ciphernode.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/evm/tasks/ciphernode.ts b/packages/evm/tasks/ciphernode.ts index af706bfa..c6b919bf 100644 --- a/packages/evm/tasks/ciphernode.ts +++ b/packages/evm/tasks/ciphernode.ts @@ -4,14 +4,14 @@ import type { TaskArguments } from "hardhat/types"; task("ciphernode:add", "Register a ciphernode to the registry") .addParam("ciphernodeAddress", "address of ciphernode to register") .setAction(async function (taskArguments: TaskArguments, hre) { - const registry = await hre.deployments.get("CyphernodeRegistryOwnable"); + const registry = await hre.deployments.get("CiphernodeRegistryOwnable"); const registryContract = await hre.ethers.getContractAt( - "CyphernodeRegistryOwnable", + "CiphernodeRegistryOwnable", registry.address, ); - const tx = await registryContract.addCyphernode( + const tx = await registryContract.addCiphernode( taskArguments.ciphernodeAddress, ); await tx.wait(); @@ -22,14 +22,14 @@ task("ciphernode:add", "Register a ciphernode to the registry") task("ciphernode:remove", "Remove a ciphernode from the registry") .addParam("ciphernodeAddress", "address of ciphernode to remove") .setAction(async function (taskArguments: TaskArguments, hre) { - const registry = await hre.deployments.get("CyphernodeRegistryOwnable"); + const registry = await hre.deployments.get("CiphernodeRegistryOwnable"); const registryContract = await hre.ethers.getContractAt( - "CyphernodeRegistryOwnable", + "CiphernodeRegistryOwnable", registry.address, ); - const tx = await registryContract.removeCyphernode( + const tx = await registryContract.removeCiphernode( taskArguments.ciphernodeAddress, ); await tx.wait(); From cf930b142b7d848ff917986e1d4c1b746b9b4145 Mon Sep 17 00:00:00 2001 From: samepant Date: Mon, 16 Sep 2024 16:40:04 -0400 Subject: [PATCH 60/87] fix unused import lint warning --- packages/evm/contracts/interfaces/IE3.sol | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/evm/contracts/interfaces/IE3.sol b/packages/evm/contracts/interfaces/IE3.sol index 2a4e6e5e..51a9daab 100644 --- a/packages/evm/contracts/interfaces/IE3.sol +++ b/packages/evm/contracts/interfaces/IE3.sol @@ -2,7 +2,6 @@ pragma solidity >=0.8.27; import { IInputValidator } from "./IInputValidator.sol"; -import { IComputeProvider } from "./IComputeProvider.sol"; import { IE3Program } from "./IE3Program.sol"; import { IDecryptionVerifier } from "./IDecryptionVerifier.sol"; From d041744f36a96cf66bba62f9563dec8a776765d5 Mon Sep 17 00:00:00 2001 From: samepant Date: Mon, 16 Sep 2024 18:29:10 -0400 Subject: [PATCH 61/87] fix add ciphernode function --- packages/evm/contracts/registry/CiphernodeRegistryOwnable.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/evm/contracts/registry/CiphernodeRegistryOwnable.sol b/packages/evm/contracts/registry/CiphernodeRegistryOwnable.sol index e62682d7..2f897758 100644 --- a/packages/evm/contracts/registry/CiphernodeRegistryOwnable.sol +++ b/packages/evm/contracts/registry/CiphernodeRegistryOwnable.sol @@ -115,7 +115,7 @@ contract CiphernodeRegistryOwnable is ICiphernodeRegistry, OwnableUpgradeable { } function addCiphernode(address node) external onlyOwner { - uint256 ciphernode = uint256(bytes32(bytes20(node))); + uint160 ciphernode = uint160(node); ciphernodes._insert(ciphernode); numCiphernodes++; emit CiphernodeAdded( From c745073f21a22859d2f873568902e31f3d6dcabe Mon Sep 17 00:00:00 2001 From: samepant Date: Mon, 16 Sep 2024 21:25:17 -0400 Subject: [PATCH 62/87] Request committee hardhat task (#81) * adds task for requesting committee * remove unused import --- packages/evm/hardhat.config.ts | 1 + packages/evm/tasks/committee.ts | 105 ++++++++++++++++++++++++++++++++ 2 files changed, 106 insertions(+) create mode 100644 packages/evm/tasks/committee.ts diff --git a/packages/evm/hardhat.config.ts b/packages/evm/hardhat.config.ts index 6dd7c4e4..14821bc4 100644 --- a/packages/evm/hardhat.config.ts +++ b/packages/evm/hardhat.config.ts @@ -7,6 +7,7 @@ import type { NetworkUserConfig } from "hardhat/types"; import "./tasks/accounts"; import "./tasks/ciphernode"; +import "./tasks/committee"; dotenv.config(); diff --git a/packages/evm/tasks/committee.ts b/packages/evm/tasks/committee.ts new file mode 100644 index 00000000..f4f8eaad --- /dev/null +++ b/packages/evm/tasks/committee.ts @@ -0,0 +1,105 @@ +import { task, types } from "hardhat/config"; +import type { TaskArguments } from "hardhat/types"; + +task("committee:new", "Request a new ciphernode committee") + .addOptionalParam( + "filter", + "address of filter contract to use", + "0x0000000000000000000000000000000000000006", + types.string, + ) + .addOptionalParam( + "thresholdQuorum", + "threshold quorum for committee", + 2, + types.int, + ) + .addOptionalParam( + "thresholdTotal", + "threshold total for committee", + 2, + types.int, + ) + .addOptionalParam( + "windowStart", + "timestamp start of window for the E3 (default: now)", + Math.floor(Date.now() / 1000), + types.int, + ) + .addOptionalParam( + "windowEnd", + "timestamp end of window for the E3 (default: now + 1 day)", + Math.floor(Date.now() / 1000) + 86400, + types.int, + ) + .addOptionalParam( + "duration", + "duration in seconds of the E3 (default: 1 day)", + 86400, + types.int, + ) + .addOptionalParam( + "e3Address", + "address of the E3 program", + "0x95E366f13c16976A26339aBe7992a1AB523388f5", + types.string, + ) + .addOptionalParam( + "e3Params", + "parameters for the E3 program", + "0x0000000000000000000000009f3ebc4f6be495901a29bba2ae5a45fb870cdc14", + types.string, + ) + .addOptionalParam( + "computeParams", + "parameters for the compute provider", + "0x000000000000000000000000404af1c0780a9269e4d3308a0812fb87bf5fc490", + types.string, + ) + .setAction(async function (taskArguments: TaskArguments, hre) { + const enclave = await hre.deployments.get("Enclave"); + + const enclaveContract = await hre.ethers.getContractAt( + "Enclave", + enclave.address, + ); + + try { + const enableE3Tx = await enclaveContract.enableE3Program( + taskArguments.e3Address, + ); + await enableE3Tx.wait(); + } catch (e: unknown) { + console.log( + "E3 program enabling failed, probably already enabled: ", + e.message, + ); + } + + console.log( + "requesting committee...", + taskArguments.filter, + [taskArguments.thresholdQuorum, taskArguments.thresholdTotal], + [taskArguments.windowStart, taskArguments.windowEnd], + taskArguments.duration, + taskArguments.e3Address, + taskArguments.e3Params, + taskArguments.computeParams, + ); + const tx = await enclaveContract.request( + taskArguments.filter, + [taskArguments.thresholdQuorum, taskArguments.thresholdTotal], + [taskArguments.windowStart, taskArguments.windowEnd], + taskArguments.duration, + taskArguments.e3Address, + taskArguments.e3Params, + taskArguments.computeParams, + // 1 ETH + { value: "1000000000000000000" }, + ); + + console.log("Reequesting committee... ", tx.hash); + await tx.wait(); + + console.log(`Committee requested`); + }); From a9c2ff8ceb49fdb0e8618b8afa369d940971e90b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=B3=CE=BB?= Date: Tue, 17 Sep 2024 11:27:04 +1000 Subject: [PATCH 63/87] Rename registry to orchestrator (#83) * Rename to orchestrator * Rename to orchestrator * Add builder --- ...registry.rs => ciphernode_orchestrator.rs} | 14 +-- packages/ciphernode/core/src/lib.rs | 42 +++++---- .../ciphernode/core/src/main_aggregator.rs | 29 +++--- .../ciphernode/core/src/main_ciphernode.rs | 40 +++++--- .../core/src/{registry.rs => orchestrator.rs} | 93 +++++++++++++------ ..._registry.rs => plaintext_orchestrator.rs} | 14 +-- ..._registry.rs => publickey_orchestrator.rs} | 14 +-- 7 files changed, 151 insertions(+), 95 deletions(-) rename packages/ciphernode/core/src/{ciphernode_registry.rs => ciphernode_orchestrator.rs} (88%) rename packages/ciphernode/core/src/{registry.rs => orchestrator.rs} (66%) rename packages/ciphernode/core/src/{plaintext_registry.rs => plaintext_orchestrator.rs} (89%) rename packages/ciphernode/core/src/{publickey_registry.rs => publickey_orchestrator.rs} (89%) diff --git a/packages/ciphernode/core/src/ciphernode_registry.rs b/packages/ciphernode/core/src/ciphernode_orchestrator.rs similarity index 88% rename from packages/ciphernode/core/src/ciphernode_registry.rs rename to packages/ciphernode/core/src/ciphernode_orchestrator.rs index 2fd8341d..5e409593 100644 --- a/packages/ciphernode/core/src/ciphernode_registry.rs +++ b/packages/ciphernode/core/src/ciphernode_orchestrator.rs @@ -4,7 +4,7 @@ use actix::prelude::*; use alloy_primitives::Address; use std::collections::HashMap; -pub struct CiphernodeRegistry { +pub struct CiphernodeOrchestrator { bus: Addr, data: Addr, address: Address, @@ -12,7 +12,7 @@ pub struct CiphernodeRegistry { buffers: HashMap>, } -impl CiphernodeRegistry { +impl CiphernodeOrchestrator { pub fn new(bus: Addr, data: Addr, address: Address) -> Self { Self { bus, @@ -24,15 +24,15 @@ impl CiphernodeRegistry { } pub fn attach(bus: Addr, data: Addr, address: Address) -> Addr { - CiphernodeRegistry::new(bus, data, address).start() + CiphernodeOrchestrator::new(bus, data, address).start() } } -impl Actor for CiphernodeRegistry { +impl Actor for CiphernodeOrchestrator { type Context = Context; } -impl Handler for CiphernodeRegistry { +impl Handler for CiphernodeOrchestrator { type Result = (); fn handle(&mut self, msg: InitializeWithEnclaveEvent, _: &mut Self::Context) -> Self::Result { let InitializeWithEnclaveEvent { fhe, event, .. } = msg; @@ -46,7 +46,7 @@ impl Handler for CiphernodeRegistry { } } -impl Handler for CiphernodeRegistry { +impl Handler for CiphernodeOrchestrator { type Result = (); fn handle(&mut self, msg: EnclaveEvent, _ctx: &mut Self::Context) -> Self::Result { @@ -57,7 +57,7 @@ impl Handler for CiphernodeRegistry { } } -impl CiphernodeRegistry { +impl CiphernodeOrchestrator { fn ciphernode_factory(&self, fhe: Addr) -> impl FnOnce() -> Addr { let data = self.data.clone(); let bus = self.bus.clone(); diff --git a/packages/ciphernode/core/src/lib.rs b/packages/ciphernode/core/src/lib.rs index 1fd31bf9..7187714a 100644 --- a/packages/ciphernode/core/src/lib.rs +++ b/packages/ciphernode/core/src/lib.rs @@ -3,7 +3,7 @@ // #![warn(missing_docs, unused_imports)] mod ciphernode; -mod ciphernode_registry; +mod ciphernode_orchestrator; mod ciphernode_selector; mod data; mod enclave_contract; @@ -13,20 +13,20 @@ mod fhe; mod logger; mod main_aggregator; mod main_ciphernode; +mod orchestrator; mod ordered_set; mod p2p; mod plaintext_aggregator; -mod plaintext_registry; +mod plaintext_orchestrator; mod publickey_aggregator; -mod publickey_registry; -mod registry; +mod publickey_orchestrator; mod serializers; mod sortition; // TODO: this is too permissive pub use actix::prelude::*; pub use ciphernode::*; -pub use ciphernode_registry::*; +pub use ciphernode_orchestrator::*; pub use ciphernode_selector::*; pub use data::*; pub use eventbus::*; @@ -35,12 +35,12 @@ pub use fhe::*; pub use logger::*; pub use main_aggregator::*; pub use main_ciphernode::*; +pub use orchestrator::*; pub use p2p::*; pub use plaintext_aggregator::*; -pub use plaintext_registry::*; +pub use plaintext_orchestrator::*; pub use publickey_aggregator::*; -pub use publickey_registry::*; -pub use registry::*; +pub use publickey_orchestrator::*; pub use sortition::*; // TODO: move these out to a test folder @@ -56,9 +56,9 @@ mod tests { CiphertextSerializer, DecryptionShareSerializer, PublicKeySerializer, PublicKeyShareSerializer, }, - CiphernodeAdded, CiphernodeRegistry, CiphernodeSelected, CiphertextOutputPublished, - DecryptionshareCreated, PlaintextAggregated, PlaintextRegistry, PublicKeyRegistry, - Registry, ResetHistory, SharedRng, Sortition, + CiphernodeAdded, CiphernodeOrchestrator, CiphernodeSelected, CiphertextOutputPublished, + DecryptionshareCreated, Orchestrator, PlaintextAggregated, PlaintextOrchestrator, + PublicKeyOrchestrator, ResetHistory, SharedRng, Sortition, }; use actix::prelude::*; use alloy_primitives::Address; @@ -88,14 +88,18 @@ mod tests { // create ciphernode actor for managing ciphernode flow let sortition = Sortition::attach(bus.clone()); CiphernodeSelector::attach(bus.clone(), sortition.clone(), addr); - Registry::attach( - bus.clone(), - rng, - Some(PublicKeyRegistry::attach(bus.clone(), sortition.clone())), - Some(PlaintextRegistry::attach(bus.clone(), sortition.clone())), - Some(CiphernodeRegistry::attach(bus.clone(), data, addr)), - ) - .await; + Orchestrator::builder(bus.clone(), rng) + .public_key(PublicKeyOrchestrator::attach( + bus.clone(), + sortition.clone(), + )) + .plaintext(PlaintextOrchestrator::attach( + bus.clone(), + sortition.clone(), + )) + .ciphernode(CiphernodeOrchestrator::attach(bus.clone(), data, addr)) + .build() + .await; } fn setup_bfv_params( diff --git a/packages/ciphernode/core/src/main_aggregator.rs b/packages/ciphernode/core/src/main_aggregator.rs index ada40df7..00e48e66 100644 --- a/packages/ciphernode/core/src/main_aggregator.rs +++ b/packages/ciphernode/core/src/main_aggregator.rs @@ -1,6 +1,6 @@ use std::sync::{Arc, Mutex}; -use crate::{EventBus, P2p, PlaintextRegistry, PublicKeyRegistry, Registry, Sortition}; +use crate::{EventBus, Orchestrator, P2p, PlaintextOrchestrator, PublicKeyOrchestrator, Sortition}; use actix::{Actor, Addr, Context}; use rand::SeedableRng; use rand_chacha::rand_core::OsRng; @@ -12,7 +12,7 @@ use tokio::task::JoinHandle; pub struct MainAggregator { bus: Addr, sortition: Addr, - registry: Addr, + orchestrator: Addr, p2p: Addr, } @@ -20,13 +20,13 @@ impl MainAggregator { pub fn new( bus: Addr, sortition: Addr, - registry: Addr, + orchestrator: Addr, p2p: Addr, ) -> Self { Self { bus, sortition, - registry, + orchestrator, p2p, } } @@ -37,17 +37,20 @@ impl MainAggregator { )); let bus = EventBus::new(true).start(); let sortition = Sortition::attach(bus.clone()); - let registry = Registry::attach( - bus.clone(), - rng, - Some(PublicKeyRegistry::attach(bus.clone(), sortition.clone())), - Some(PlaintextRegistry::attach(bus.clone(), sortition.clone())), - None, - ) - .await; + let orchestrator = Orchestrator::builder(bus.clone(), rng) + .public_key(PublicKeyOrchestrator::attach( + bus.clone(), + sortition.clone(), + )) + .plaintext(PlaintextOrchestrator::attach( + bus.clone(), + sortition.clone(), + )) + .build() + .await; let (p2p_addr, join_handle) = P2p::spawn_libp2p(bus.clone()).expect("Failed to setup libp2p"); - let main_addr = MainAggregator::new(bus, sortition, registry, p2p_addr).start(); + let main_addr = MainAggregator::new(bus, sortition, orchestrator, p2p_addr).start(); (main_addr, join_handle) } } diff --git a/packages/ciphernode/core/src/main_ciphernode.rs b/packages/ciphernode/core/src/main_ciphernode.rs index 66ed3681..a91c0739 100644 --- a/packages/ciphernode/core/src/main_ciphernode.rs +++ b/packages/ciphernode/core/src/main_ciphernode.rs @@ -1,6 +1,8 @@ use std::sync::{Arc, Mutex}; -use crate::{CiphernodeRegistry, CiphernodeSelector, Data, EventBus, P2p, Registry, Sortition}; +use crate::{ + CiphernodeOrchestrator, CiphernodeSelector, Data, EventBus, Orchestrator, P2p, Sortition, +}; use actix::{Actor, Addr, Context}; use alloy_primitives::Address; use rand::SeedableRng; @@ -16,7 +18,7 @@ pub struct MainCiphernode { data: Addr, sortition: Addr, selector: Addr, - registry: Addr, + orchestrator: Addr, p2p: Addr, } @@ -27,7 +29,7 @@ impl MainCiphernode { data: Addr, sortition: Addr, selector: Addr, - registry: Addr, + orchestrator: Addr, p2p: Addr, ) -> Self { Self { @@ -36,7 +38,7 @@ impl MainCiphernode { data, sortition, selector, - registry, + orchestrator, p2p, } } @@ -49,19 +51,27 @@ impl MainCiphernode { let data = Data::new(true).start(); // TODO: Use a sled backed Data Actor let sortition = Sortition::attach(bus.clone()); let selector = CiphernodeSelector::attach(bus.clone(), sortition.clone(), address); - let registry = Registry::attach( - bus.clone(), - rng, - None, - None, - Some(CiphernodeRegistry::attach(bus.clone(), data.clone(), address)), - ) - .await; + let orchestrator = Orchestrator::builder(bus.clone(), rng) + .ciphernode(CiphernodeOrchestrator::attach( + bus.clone(), + data.clone(), + address, + )) + .build() + .await; + let (p2p_addr, join_handle) = P2p::spawn_libp2p(bus.clone()).expect("Failed to setup libp2p"); - let main_addr = - MainCiphernode::new(address, bus, data, sortition, selector, registry, p2p_addr) - .start(); + let main_addr = MainCiphernode::new( + address, + bus, + data, + sortition, + selector, + orchestrator, + p2p_addr, + ) + .start(); (main_addr, join_handle) } } diff --git a/packages/ciphernode/core/src/registry.rs b/packages/ciphernode/core/src/orchestrator.rs similarity index 66% rename from packages/ciphernode/core/src/registry.rs rename to packages/ciphernode/core/src/orchestrator.rs index 6f7eedd5..ae846a3d 100644 --- a/packages/ciphernode/core/src/registry.rs +++ b/packages/ciphernode/core/src/orchestrator.rs @@ -1,7 +1,7 @@ // TODO: spawn and supervise child actors use crate::{ - CiphernodeRegistry, CommitteeRequested, E3id, EnclaveEvent, EventBus, Fhe, PlaintextRegistry, - PublicKeyRegistry, Subscribe, + CiphernodeOrchestrator, CommitteeRequested, E3id, EnclaveEvent, EventBus, Fhe, + PlaintextOrchestrator, PublicKeyOrchestrator, Subscribe, }; use actix::prelude::*; use rand_chacha::ChaCha20Rng; @@ -30,23 +30,72 @@ pub struct CommitteeMeta { pub seed: u64, } -pub struct Registry { +pub struct OrchestratorBuilder { + bus: Addr, + rng: Arc>, + public_key: Option>, + plaintext: Option>, + ciphernode: Option>, +} + +impl OrchestratorBuilder { + pub fn new(bus: Addr, rng: Arc>) -> Self { + Self { + bus, + rng, + public_key: None, + plaintext: None, + ciphernode: None, + } + } + + pub fn public_key(mut self, value: Addr) -> Self { + self.public_key = Some(value); + self + } + + pub fn plaintext(mut self, value: Addr) -> Self { + self.plaintext = Some(value); + self + } + + pub fn ciphernode(mut self, value: Addr) -> Self { + self.ciphernode = Some(value); + self + } + + pub async fn build(self) -> Addr { + let bus = self.bus; + let rng = self.rng; + let public_key = self.public_key; + let plaintext = self.plaintext; + let ciphernode = self.ciphernode; + Orchestrator::attach(bus, rng, public_key, plaintext, ciphernode).await + } +} + +pub struct Orchestrator { fhes: HashMap>, meta: HashMap, - public_key: Option>, - plaintext: Option>, - ciphernode: Option>, + public_key: Option>, + plaintext: Option>, + ciphernode: Option>, rng: Arc>, } -impl Registry { - pub fn new( +impl Orchestrator { + pub fn builder(bus: Addr, rng: Arc>) -> OrchestratorBuilder { + OrchestratorBuilder::new(bus, rng) + } + + async fn attach( + bus: Addr, rng: Arc>, - public_key: Option>, - plaintext: Option>, - ciphernode: Option>, - ) -> Self { - Self { + public_key: Option>, + plaintext: Option>, + ciphernode: Option>, + ) -> Addr { + let addr = Orchestrator { rng, public_key, plaintext, @@ -54,17 +103,7 @@ impl Registry { meta: HashMap::new(), fhes: HashMap::new(), } - } - - // TODO: use a builder pattern to manage the Option - pub async fn attach( - bus: Addr, - rng: Arc>, - public_key: Option>, - plaintext: Option>, - ciphernode: Option>, - ) -> Addr { - let addr = Registry::new(rng, public_key, plaintext, ciphernode).start(); + .start(); bus.send(Subscribe::new("*", addr.clone().into())) .await .unwrap(); @@ -72,11 +111,11 @@ impl Registry { } } -impl Actor for Registry { +impl Actor for Orchestrator { type Context = Context; } -impl Handler for Registry { +impl Handler for Orchestrator { type Result = (); fn handle(&mut self, msg: EnclaveEvent, _ctx: &mut Self::Context) -> Self::Result { @@ -144,7 +183,7 @@ impl Handler for Registry { } } -impl Registry { +impl Orchestrator { fn fhe_factory( &self, moduli: Vec, diff --git a/packages/ciphernode/core/src/plaintext_registry.rs b/packages/ciphernode/core/src/plaintext_orchestrator.rs similarity index 89% rename from packages/ciphernode/core/src/plaintext_registry.rs rename to packages/ciphernode/core/src/plaintext_orchestrator.rs index 60127d5a..db8d48a5 100644 --- a/packages/ciphernode/core/src/plaintext_registry.rs +++ b/packages/ciphernode/core/src/plaintext_orchestrator.rs @@ -6,14 +6,14 @@ use crate::{ use actix::prelude::*; use std::collections::HashMap; -pub struct PlaintextRegistry { +pub struct PlaintextOrchestrator { bus: Addr, sortition: Addr, buffers: HashMap>, plaintexts: HashMap>, } -impl PlaintextRegistry { +impl PlaintextOrchestrator { pub fn new(bus: Addr, sortition: Addr) -> Self { Self { bus, @@ -24,15 +24,15 @@ impl PlaintextRegistry { } pub fn attach(bus: Addr, sortition: Addr) -> Addr { - PlaintextRegistry::new(bus.clone(), sortition).start() + PlaintextOrchestrator::new(bus.clone(), sortition).start() } } -impl Actor for PlaintextRegistry { +impl Actor for PlaintextOrchestrator { type Context = Context; } -impl Handler for PlaintextRegistry { +impl Handler for PlaintextOrchestrator { type Result = (); fn handle(&mut self, msg: InitializeWithEnclaveEvent, _: &mut Self::Context) -> Self::Result { let InitializeWithEnclaveEvent { fhe, meta, event } = msg; @@ -49,7 +49,7 @@ impl Handler for PlaintextRegistry { } } -impl Handler for PlaintextRegistry { +impl Handler for PlaintextOrchestrator { type Result = (); fn handle(&mut self, msg: EnclaveEvent, _ctx: &mut Self::Context) -> Self::Result { @@ -60,7 +60,7 @@ impl Handler for PlaintextRegistry { } } -impl PlaintextRegistry { +impl PlaintextOrchestrator { fn plaintext_factory( &self, e3_id: E3id, diff --git a/packages/ciphernode/core/src/publickey_registry.rs b/packages/ciphernode/core/src/publickey_orchestrator.rs similarity index 89% rename from packages/ciphernode/core/src/publickey_registry.rs rename to packages/ciphernode/core/src/publickey_orchestrator.rs index 51b7b3c6..c6930467 100644 --- a/packages/ciphernode/core/src/publickey_registry.rs +++ b/packages/ciphernode/core/src/publickey_orchestrator.rs @@ -5,14 +5,14 @@ use crate::{ use actix::prelude::*; use std::collections::HashMap; -pub struct PublicKeyRegistry { +pub struct PublicKeyOrchestrator { bus: Addr, sortition: Addr, buffers: HashMap>, public_keys: HashMap>, } -impl PublicKeyRegistry { +impl PublicKeyOrchestrator { pub fn new(bus: Addr, sortition: Addr) -> Self { Self { bus, @@ -23,15 +23,15 @@ impl PublicKeyRegistry { } pub fn attach(bus: Addr, sortition: Addr) -> Addr { - PublicKeyRegistry::new(bus.clone(), sortition).start() + PublicKeyOrchestrator::new(bus.clone(), sortition).start() } } -impl Actor for PublicKeyRegistry { +impl Actor for PublicKeyOrchestrator { type Context = Context; } -impl Handler for PublicKeyRegistry { +impl Handler for PublicKeyOrchestrator { type Result = (); fn handle(&mut self, msg: InitializeWithEnclaveEvent, _: &mut Self::Context) -> Self::Result { let InitializeWithEnclaveEvent { fhe, event, .. } = msg; @@ -51,7 +51,7 @@ impl Handler for PublicKeyRegistry { } } -impl Handler for PublicKeyRegistry { +impl Handler for PublicKeyOrchestrator { type Result = (); fn handle(&mut self, msg: EnclaveEvent, _ctx: &mut Self::Context) -> Self::Result { @@ -62,7 +62,7 @@ impl Handler for PublicKeyRegistry { } } -impl PublicKeyRegistry { +impl PublicKeyOrchestrator { fn public_key_factory( &self, fhe: Addr, From 6c02e3efe6b663aff0b3e0f8905626529486d065 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=B3=CE=BB?= Date: Tue, 17 Sep 2024 13:23:48 +1000 Subject: [PATCH 64/87] Move eth into core to solve dependency issues (#84) --- packages/ciphernode/Cargo.lock | 188 +++++++++++++++--- packages/ciphernode/Cargo.toml | 2 +- packages/ciphernode/core/Cargo.toml | 5 +- .../listener.rs => core/src/evm_listener.rs} | 17 +- .../manager.rs => core/src/evm_manager.rs} | 35 ++-- .../ciphernode/core/src/main_ciphernode.rs | 2 +- packages/ciphernode/enclave/Cargo.toml | 1 - packages/ciphernode/enclave_node/Cargo.toml | 1 - .../enclave_node/src/bin/eth-listener.rs | 33 --- .../ciphernode/enclave_node/src/bin/node.rs | 4 +- packages/ciphernode/eth/Cargo.toml | 24 --- packages/ciphernode/eth/src/lib.rs | 9 - 12 files changed, 193 insertions(+), 128 deletions(-) rename packages/ciphernode/{eth/src/listener.rs => core/src/evm_listener.rs} (92%) rename packages/ciphernode/{eth/src/manager.rs => core/src/evm_manager.rs} (69%) delete mode 100644 packages/ciphernode/enclave_node/src/bin/eth-listener.rs delete mode 100644 packages/ciphernode/eth/Cargo.toml delete mode 100644 packages/ciphernode/eth/src/lib.rs diff --git a/packages/ciphernode/Cargo.lock b/packages/ciphernode/Cargo.lock index c46f11e4..02bbe346 100644 --- a/packages/ciphernode/Cargo.lock +++ b/packages/ciphernode/Cargo.lock @@ -143,22 +143,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f4a4aaae80afd4be443a6aecd92a6b255dcdd000f97996928efb33d8a71e100" dependencies = [ "alloy-consensus 0.2.1", - "alloy-contract", + "alloy-contract 0.2.1", "alloy-core 0.7.7", "alloy-eips 0.2.1", "alloy-genesis 0.2.1", "alloy-network 0.2.1", "alloy-provider 0.2.1", - "alloy-pubsub", + "alloy-pubsub 0.2.1", "alloy-rpc-client 0.2.1", - "alloy-rpc-types", + "alloy-rpc-types 0.2.1", "alloy-serde 0.2.1", "alloy-signer 0.2.1", - "alloy-signer-local", + "alloy-signer-local 0.2.1", "alloy-transport 0.2.1", "alloy-transport-http 0.2.1", - "alloy-transport-ipc", - "alloy-transport-ws", + "alloy-transport-ipc 0.2.1", + "alloy-transport-ws 0.2.1", ] [[package]] @@ -168,13 +168,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c37d89f69cb43901949ba29307ada8b9e3b170f94057ad4c04d6fd169d24d65f" dependencies = [ "alloy-consensus 0.3.3", + "alloy-contract 0.3.3", "alloy-core 0.8.3", "alloy-eips 0.3.3", "alloy-genesis 0.3.3", + "alloy-network 0.3.3", "alloy-provider 0.3.3", + "alloy-pubsub 0.3.5", "alloy-rpc-client 0.3.3", + "alloy-rpc-types 0.3.5", "alloy-serde 0.3.3", + "alloy-signer 0.3.3", + "alloy-signer-local 0.3.5", + "alloy-transport 0.3.3", "alloy-transport-http 0.3.3", + "alloy-transport-ipc 0.3.5", + "alloy-transport-ws 0.3.5", ] [[package]] @@ -227,7 +236,7 @@ dependencies = [ "alloy-network-primitives 0.2.1", "alloy-primitives 0.7.7", "alloy-provider 0.2.1", - "alloy-pubsub", + "alloy-pubsub 0.2.1", "alloy-rpc-types-eth 0.2.1", "alloy-sol-types 0.7.7", "alloy-transport 0.2.1", @@ -236,6 +245,27 @@ dependencies = [ "thiserror", ] +[[package]] +name = "alloy-contract" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "335d62de1a887f1b780441f8a3037f39c9fb26839cc9acd891c9b80396145cd5" +dependencies = [ + "alloy-dyn-abi 0.8.3", + "alloy-json-abi 0.8.3", + "alloy-network 0.3.3", + "alloy-network-primitives 0.3.3", + "alloy-primitives 0.8.3", + "alloy-provider 0.3.3", + "alloy-pubsub 0.3.5", + "alloy-rpc-types-eth 0.3.3", + "alloy-sol-types 0.8.3", + "alloy-transport 0.3.3", + "futures", + "futures-util", + "thiserror", +] + [[package]] name = "alloy-core" version = "0.7.7" @@ -313,6 +343,7 @@ checksum = "37d319bb544ca6caeab58c39cea8921c55d924d4f68f2c60f24f914673f9a74a" dependencies = [ "alloy-primitives 0.8.3", "alloy-rlp", + "k256", "serde", ] @@ -569,13 +600,13 @@ dependencies = [ "alloy-network 0.2.1", "alloy-network-primitives 0.2.1", "alloy-primitives 0.7.7", - "alloy-pubsub", + "alloy-pubsub 0.2.1", "alloy-rpc-client 0.2.1", "alloy-rpc-types-eth 0.2.1", "alloy-transport 0.2.1", "alloy-transport-http 0.2.1", - "alloy-transport-ipc", - "alloy-transport-ws", + "alloy-transport-ipc 0.2.1", + "alloy-transport-ws 0.2.1", "async-stream", "async-trait", "auto_impl", @@ -605,10 +636,13 @@ dependencies = [ "alloy-network 0.3.3", "alloy-network-primitives 0.3.3", "alloy-primitives 0.8.3", + "alloy-pubsub 0.3.5", "alloy-rpc-client 0.3.3", "alloy-rpc-types-eth 0.3.3", "alloy-transport 0.3.3", "alloy-transport-http 0.3.3", + "alloy-transport-ipc 0.3.5", + "alloy-transport-ws 0.3.5", "async-stream", "async-trait", "auto_impl", @@ -645,6 +679,25 @@ dependencies = [ "tracing", ] +[[package]] +name = "alloy-pubsub" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34b9f5e85120aab30b8da23354592f7bd2b208d33d3204ffa1d44ac2e3dd5691" +dependencies = [ + "alloy-json-rpc 0.3.3", + "alloy-primitives 0.8.3", + "alloy-transport 0.3.3", + "bimap", + "futures", + "serde", + "serde_json", + "tokio", + "tokio-stream", + "tower 0.5.1", + "tracing", +] + [[package]] name = "alloy-rlp" version = "0.3.8" @@ -675,11 +728,11 @@ checksum = "5b38e3ffdb285df5d9f60cb988d336d9b8e3505acb78750c3bc60336a7af41d3" dependencies = [ "alloy-json-rpc 0.2.1", "alloy-primitives 0.7.7", - "alloy-pubsub", + "alloy-pubsub 0.2.1", "alloy-transport 0.2.1", "alloy-transport-http 0.2.1", - "alloy-transport-ipc", - "alloy-transport-ws", + "alloy-transport-ipc 0.2.1", + "alloy-transport-ws 0.2.1", "futures", "pin-project", "reqwest", @@ -699,8 +752,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d5fc328bb5d440599ba1b5aa44c0b9ab0625fbc3a403bb5ee94ed4a01ba23e07" dependencies = [ "alloy-json-rpc 0.3.3", + "alloy-primitives 0.8.3", + "alloy-pubsub 0.3.5", "alloy-transport 0.3.3", "alloy-transport-http 0.3.3", + "alloy-transport-ipc 0.3.5", + "alloy-transport-ws 0.3.5", "futures", "pin-project", "reqwest", @@ -719,12 +776,24 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c31a3750b8f5a350d17354e46a52b0f2f19ec5f2006d816935af599dedc521" dependencies = [ - "alloy-rpc-types-engine", + "alloy-rpc-types-engine 0.2.1", "alloy-rpc-types-eth 0.2.1", "alloy-serde 0.2.1", "serde", ] +[[package]] +name = "alloy-rpc-types" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22045187a5ebf5b2af3f8b6831b66735b6556c5750ec5790aeeb45935260c1c2" +dependencies = [ + "alloy-rpc-types-engine 0.3.5", + "alloy-rpc-types-eth 0.3.3", + "alloy-serde 0.3.3", + "serde", +] + [[package]] name = "alloy-rpc-types-engine" version = "0.2.1" @@ -743,6 +812,19 @@ dependencies = [ "thiserror", ] +[[package]] +name = "alloy-rpc-types-engine" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c031a91e94a39f928244bc837c953817be5b8cc61759e1a9123b3abd17560dd" +dependencies = [ + "alloy-consensus 0.3.3", + "alloy-eips 0.3.3", + "alloy-primitives 0.8.3", + "alloy-rlp", + "derive_more 1.0.0", +] + [[package]] name = "alloy-rpc-types-eth" version = "0.2.1" @@ -847,6 +929,22 @@ dependencies = [ "thiserror", ] +[[package]] +name = "alloy-signer-local" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99e250010dce0e3caf6a6033e809718e5921391d937d1cbbcffe52653b37cc63" +dependencies = [ + "alloy-consensus 0.3.3", + "alloy-network 0.3.3", + "alloy-primitives 0.8.3", + "alloy-signer 0.3.3", + "async-trait", + "k256", + "rand", + "thiserror", +] + [[package]] name = "alloy-sol-macro" version = "0.6.4" @@ -918,6 +1016,7 @@ version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2bc65475025fc1e84bf86fc840f04f63fcccdcf3cf12053c99918e4054dfbc69" dependencies = [ + "alloy-json-abi 0.8.3", "alloy-sol-macro-input 0.8.3", "const-hex", "heck 0.5.0", @@ -953,11 +1052,13 @@ version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ed10f0715a0b69fde3236ff3b9ae5f6f7c97db5a387747100070d3016b9266b" dependencies = [ + "alloy-json-abi 0.8.3", "const-hex", "dunce", "heck 0.5.0", "proc-macro2", "quote", + "serde_json", "syn 2.0.72", "syn-solidity 0.8.3", ] @@ -1095,7 +1196,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "804494366e20468776db4e18f9eb5db7db0fe14f1271eb6dbf155d867233405c" dependencies = [ "alloy-json-rpc 0.2.1", - "alloy-pubsub", + "alloy-pubsub 0.2.1", "alloy-transport 0.2.1", "bytes", "futures", @@ -1107,13 +1208,32 @@ dependencies = [ "tracing", ] +[[package]] +name = "alloy-transport-ipc" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aa02db8751f9c0c37caf8c38ad3eb7aa1cfb09cfea3451a13aacaf06846c7a5" +dependencies = [ + "alloy-json-rpc 0.3.3", + "alloy-pubsub 0.3.5", + "alloy-transport 0.3.3", + "bytes", + "futures", + "interprocess", + "pin-project", + "serde_json", + "tokio", + "tokio-util", + "tracing", +] + [[package]] name = "alloy-transport-ws" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af855163e7df008799941aa6dd324a43ef2bf264b08ba4b22d44aad6ced65300" dependencies = [ - "alloy-pubsub", + "alloy-pubsub 0.2.1", "alloy-transport 0.2.1", "futures", "http 1.1.0", @@ -1125,6 +1245,24 @@ dependencies = [ "ws_stream_wasm", ] +[[package]] +name = "alloy-transport-ws" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0a5c4a0929479bcb85a2df628c01173618a71c807b2f499939a236dbde5d008" +dependencies = [ + "alloy-pubsub 0.3.5", + "alloy-transport 0.3.3", + "futures", + "http 1.1.0", + "rustls", + "serde_json", + "tokio", + "tokio-tungstenite", + "tracing", + "ws_stream_wasm", +] + [[package]] name = "anstream" version = "0.6.15" @@ -2387,7 +2525,6 @@ name = "enclave" version = "0.1.0" dependencies = [ "async-std", - "eth", "fhe", "fhe-traits", "fhe-util", @@ -2401,6 +2538,7 @@ dependencies = [ "actix-rt", "alloy 0.3.3", "alloy-primitives 0.6.4", + "alloy-sol-types 0.6.4", "anyhow", "async-std", "bincode", @@ -2408,6 +2546,7 @@ dependencies = [ "fhe", "fhe-traits", "fhe-util", + "futures-util", "libp2p", "p2p", "rand", @@ -2430,7 +2569,6 @@ dependencies = [ "bfv", "clap", "enclave-core", - "eth", "fhe", "fhe-traits", "fhe-util", @@ -2469,20 +2607,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "eth" -version = "0.1.0" -dependencies = [ - "actix", - "alloy 0.2.1", - "alloy-primitives 0.6.4", - "alloy-sol-types 0.6.4", - "async-std", - "enclave-core", - "eyre", - "futures-util", -] - [[package]] name = "ethnum" version = "1.5.0" diff --git a/packages/ciphernode/Cargo.toml b/packages/ciphernode/Cargo.toml index 9f243e52..5a82643f 100644 --- a/packages/ciphernode/Cargo.toml +++ b/packages/ciphernode/Cargo.toml @@ -1,2 +1,2 @@ [workspace] -members = ["core", "eth", "enclave", "enclave_node", "p2p", "bfv"] +members = ["core", "enclave", "enclave_node", "p2p", "bfv"] diff --git a/packages/ciphernode/core/Cargo.toml b/packages/ciphernode/core/Cargo.toml index ab995899..5022d29e 100644 --- a/packages/ciphernode/core/Cargo.toml +++ b/packages/ciphernode/core/Cargo.toml @@ -27,6 +27,7 @@ sha2 = "0.10.8" bs58 = "0.5.1" serde = { version = "1.0.208", features = ["derive"] } bincode = "1.3.3" -alloy = "0.3.3" +futures-util = "0.3" +alloy = { version = "0.3.3", features = ["full"] } alloy-primitives = { version = "0.6", default-features = false, features = ["rlp", "serde", "std"] } - +alloy-sol-types = { version = "0.6" } diff --git a/packages/ciphernode/eth/src/listener.rs b/packages/ciphernode/core/src/evm_listener.rs similarity index 92% rename from packages/ciphernode/eth/src/listener.rs rename to packages/ciphernode/core/src/evm_listener.rs index 4f17a571..e6a04349 100644 --- a/packages/ciphernode/eth/src/listener.rs +++ b/packages/ciphernode/core/src/evm_listener.rs @@ -6,14 +6,15 @@ use alloy::{ sol_types::SolEvent, transports::BoxTransport, }; -use enclave_core::EventBus; -use eyre::Result; +use anyhow::Result; use futures_util::stream::StreamExt; use std::collections::HashMap; use std::fmt::Debug; use std::sync::Arc; use std::marker::PhantomData; +use crate::EventBus; + pub trait ContractEvent: Send + Sync + 'static { fn process(&self, bus: Addr) -> Result<()>; } @@ -29,14 +30,14 @@ where } } -pub struct EventListener { +pub struct EvmEventListener { provider: Arc>, filter: Filter, handlers: HashMap Result> + Send + Sync>>, bus: Addr, } -impl EventListener { +impl EvmEventListener { pub fn new( provider: Arc>, filter: Filter, @@ -83,7 +84,7 @@ impl EventListener { } } -impl Actor for EventListener { +impl Actor for EvmEventListener { type Context = Context; } @@ -107,7 +108,7 @@ where } } -impl Handler> for EventListener +impl Handler> for EvmEventListener where E: SolEvent + ContractEvent + 'static, { @@ -122,7 +123,7 @@ where #[rtype(result = "()")] pub struct StartListening; -impl Handler for EventListener { +impl Handler for EvmEventListener { type Result = (); fn handle(&mut self, _: StartListening, ctx: &mut Self::Context) -> Self::Result { let (provider, filter, handlers, bus) = ( @@ -134,7 +135,7 @@ impl Handler for EventListener { ctx.spawn( async move { - let listener = EventListener { + let listener = EvmEventListener { provider, filter, handlers, diff --git a/packages/ciphernode/eth/src/manager.rs b/packages/ciphernode/core/src/evm_manager.rs similarity index 69% rename from packages/ciphernode/eth/src/manager.rs rename to packages/ciphernode/core/src/evm_manager.rs index dd0e758f..262d0eed 100644 --- a/packages/ciphernode/eth/src/manager.rs +++ b/packages/ciphernode/core/src/evm_manager.rs @@ -1,4 +1,7 @@ -use crate::{EventListener, StartListening}; +use crate::{ + evm_listener::{EvmEventListener, StartListening}, + EventBus, +}; use actix::{Actor, Addr, Context, Handler, Message}; use alloy::{ primitives::Address, @@ -6,17 +9,15 @@ use alloy::{ rpc::types::{BlockNumberOrTag, Filter}, transports::BoxTransport, }; -use enclave_core::EventBus; -use eyre::Result; use std::sync::Arc; -pub struct ContractManager { +pub struct EvmContractManager { bus: Addr, provider: Arc>, - listeners: Vec>, + listeners: Vec>, } -impl ContractManager { +impl EvmContractManager { async fn new(bus: Addr, rpc_url: &str) -> Result { let provider = ProviderBuilder::new().on_builtin(rpc_url).await?; Ok(Self { @@ -27,32 +28,35 @@ impl ContractManager { } pub async fn attach(bus: Addr, rpc_url: &str) -> Addr { - let addr = ContractManager::new(bus.clone(), rpc_url).await.unwrap().start(); + let addr = EvmContractManager::new(bus.clone(), rpc_url) + .await + .unwrap() + .start(); addr } - fn add_listener(&self, contract_address: Address) -> Addr { + fn add_listener(&self, contract_address: Address) -> Addr { let filter = Filter::new() .address(contract_address) .from_block(BlockNumberOrTag::Latest); - let listener = EventListener::new(self.provider.clone(), filter, self.bus.clone()); + let listener = EvmEventListener::new(self.provider.clone(), filter, self.bus.clone()); let addr = listener.start(); addr } } -impl Actor for ContractManager { +impl Actor for EvmContractManager { type Context = Context; } #[derive(Message)] -#[rtype(result = "Addr")] +#[rtype(result = "Addr")] pub struct AddListener { pub contract_address: Address, } -impl Handler for ContractManager { - type Result = Addr; +impl Handler for EvmContractManager { + type Result = Addr; fn handle(&mut self, msg: AddListener, _ctx: &mut Self::Context) -> Self::Result { let listener = self.add_listener(msg.contract_address); @@ -61,7 +65,7 @@ impl Handler for ContractManager { } } -impl Handler for ContractManager { +impl Handler for EvmContractManager { type Result = (); fn handle(&mut self, _: StartListening, _ctx: &mut Self::Context) -> Self::Result { @@ -69,4 +73,5 @@ impl Handler for ContractManager { listener.do_send(StartListening); } } -} \ No newline at end of file +} + diff --git a/packages/ciphernode/core/src/main_ciphernode.rs b/packages/ciphernode/core/src/main_ciphernode.rs index a91c0739..1b5478ad 100644 --- a/packages/ciphernode/core/src/main_ciphernode.rs +++ b/packages/ciphernode/core/src/main_ciphernode.rs @@ -43,7 +43,7 @@ impl MainCiphernode { } } - pub async fn attach(address: Address) -> (Addr, JoinHandle<()>) { + pub async fn attach(address: Address, rpc_url:String) -> (Addr, JoinHandle<()>) { let rng = Arc::new(Mutex::new( rand_chacha::ChaCha20Rng::from_rng(OsRng).expect("Failed to create RNG"), )); diff --git a/packages/ciphernode/enclave/Cargo.toml b/packages/ciphernode/enclave/Cargo.toml index 3e2824bd..dba66d24 100644 --- a/packages/ciphernode/enclave/Cargo.toml +++ b/packages/ciphernode/enclave/Cargo.toml @@ -8,7 +8,6 @@ repository = "https://github.com/gnosisguild/enclave/packages/ciphernode" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -eth = { path = "../eth" } async-std = "1.12.0" fhe = { git = "https://github.com/gnosisguild/fhe.rs", version = "0.1.0-beta.7" } fhe-traits = { git = "https://github.com/gnosisguild/fhe.rs", version = "0.1.0-beta.7" } diff --git a/packages/ciphernode/enclave_node/Cargo.toml b/packages/ciphernode/enclave_node/Cargo.toml index 8e4d0db9..7f19fab2 100644 --- a/packages/ciphernode/enclave_node/Cargo.toml +++ b/packages/ciphernode/enclave_node/Cargo.toml @@ -8,7 +8,6 @@ repository = "https://github.com/gnosisguild/enclave/packages/ciphernode" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -eth = { path = "../eth" } p2p = { path = "../p2p" } bfv = { path = "../bfv" } sortition = { path = "../sortition" } diff --git a/packages/ciphernode/enclave_node/src/bin/eth-listener.rs b/packages/ciphernode/enclave_node/src/bin/eth-listener.rs deleted file mode 100644 index fca5630c..00000000 --- a/packages/ciphernode/enclave_node/src/bin/eth-listener.rs +++ /dev/null @@ -1,33 +0,0 @@ -use enclave_core::Actor; -use enclave_core::EventBus; - -use eth::StartListening; -use eth::{AddListener, ContractManager, AddEventHandler}; -use std::error::Error; -use tokio::signal; -use alloy::{primitives::address, sol}; - -sol! { - #[derive(Debug)] - event TestingEvent(uint256 e3Id, bytes input); -} - -#[actix_rt::main] -async fn main() -> Result<(), Box> { - let bus = EventBus::new(true).start(); - - let manager = ContractManager::attach(bus.clone(), "ws://127.0.0.1:8545").await; - let listener = manager - .send(AddListener { - contract_address: address!("e7f1725E7734CE288F8367e1Bb143E90bb3F0512"), - }) - .await - .unwrap(); - - listener.send(AddEventHandler::::new()).await.unwrap(); - listener.do_send(StartListening); // or manager.do_send(StartListening) if multiple listeners - - signal::ctrl_c().await.unwrap(); - - Ok(()) -} diff --git a/packages/ciphernode/enclave_node/src/bin/node.rs b/packages/ciphernode/enclave_node/src/bin/node.rs index 001d6829..e6f0c07c 100644 --- a/packages/ciphernode/enclave_node/src/bin/node.rs +++ b/packages/ciphernode/enclave_node/src/bin/node.rs @@ -7,13 +7,15 @@ use enclave_core::MainCiphernode; struct Args { #[arg(short, long)] address: String, + #[arg(short, long)] + rpc: String, } #[actix_rt::main] async fn main() -> Result<(), Box> { let args = Args::parse(); let address = Address::parse_checksummed(&args.address, None).expect("Invalid address"); - let (_, handle) = MainCiphernode::attach(address).await; + let (_, handle) = MainCiphernode::attach(address, args.rpc).await; let _ = tokio::join!(handle); Ok(()) } diff --git a/packages/ciphernode/eth/Cargo.toml b/packages/ciphernode/eth/Cargo.toml deleted file mode 100644 index 19454d8c..00000000 --- a/packages/ciphernode/eth/Cargo.toml +++ /dev/null @@ -1,24 +0,0 @@ -[package] -name = "eth" -version = "0.1.0" -edition = "2021" -description = ": coordinates the encryption and decryption of enclave computations" -repository = "https://github.com/gnosisguild/enclave/packages/ciphernode" -path = "src/lib.rs" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -# Core -enclave-core = { path = "../core" } - -# Actix -actix = "0.13.5" -async-std = "1.12.0" - -# Ethereum -futures-util = "0.3" -eyre = "0.6" -alloy = { version = "0.2.1", features = ["full"] } -alloy-primitives = { version = "0.6", default-features = false, features = ["rlp", "serde", "std"] } -alloy-sol-types = { version = "0.6" } \ No newline at end of file diff --git a/packages/ciphernode/eth/src/lib.rs b/packages/ciphernode/eth/src/lib.rs deleted file mode 100644 index 81ba5f41..00000000 --- a/packages/ciphernode/eth/src/lib.rs +++ /dev/null @@ -1,9 +0,0 @@ -#![crate_name = "eth"] -#![crate_type = "lib"] -// #![warn(missing_docs, unused_imports)] - -mod listener; -mod manager; - -pub use listener::*; -pub use manager::*; \ No newline at end of file From d3c0ac9143a1187fe6c564f48a78f26fae941029 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=B3=CE=BB?= Date: Tue, 17 Sep 2024 17:40:21 +1000 Subject: [PATCH 65/87] EVM integration Part 2 (#85) * Create Evm actor * Get it compiling and tidy up * Remove comment --- .../core/src/ciphernode_selector.rs | 1 - packages/ciphernode/core/src/events.rs | 9 +- packages/ciphernode/core/src/evm.rs | 90 +++++++++++++++++++ packages/ciphernode/core/src/evm_listener.rs | 4 +- packages/ciphernode/core/src/evm_manager.rs | 9 +- packages/ciphernode/core/src/lib.rs | 61 ++----------- .../ciphernode/core/src/main_ciphernode.rs | 7 +- packages/ciphernode/core/src/utils.rs | 45 ++++++++++ .../enclave_node/src/bin/aggregator.rs | 1 - .../enclave_node/src/bin/event-node.rs | 0 .../ciphernode/enclave_node/src/bin/node.rs | 6 +- 11 files changed, 165 insertions(+), 68 deletions(-) create mode 100644 packages/ciphernode/core/src/evm.rs create mode 100644 packages/ciphernode/core/src/utils.rs delete mode 100644 packages/ciphernode/enclave_node/src/bin/event-node.rs diff --git a/packages/ciphernode/core/src/ciphernode_selector.rs b/packages/ciphernode/core/src/ciphernode_selector.rs index 43caad8b..5502d947 100644 --- a/packages/ciphernode/core/src/ciphernode_selector.rs +++ b/packages/ciphernode/core/src/ciphernode_selector.rs @@ -67,7 +67,6 @@ impl Handler for CiphernodeSelector { bus.do_send(EnclaveEvent::from(CiphernodeSelected { e3_id: data.e3_id, nodecount: data.nodecount, - threshold: data.threshold, })); } }) diff --git a/packages/ciphernode/core/src/events.rs b/packages/ciphernode/core/src/events.rs index eb6ef6bd..43a42fff 100644 --- a/packages/ciphernode/core/src/events.rs +++ b/packages/ciphernode/core/src/events.rs @@ -246,7 +246,7 @@ impl fmt::Display for EnclaveEvent { pub struct KeyshareCreated { pub pubkey: Vec, pub e3_id: E3id, - pub node: Address + pub node: Address, } #[derive(Message, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] @@ -254,7 +254,7 @@ pub struct KeyshareCreated { pub struct DecryptionshareCreated { pub decryption_share: Vec, pub e3_id: E3id, - pub node: Address + pub node: Address, } #[derive(Message, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] @@ -269,7 +269,6 @@ pub struct PublicKeyAggregated { pub struct CommitteeRequested { pub e3_id: E3id, pub nodecount: usize, - pub threshold: usize, pub sortition_seed: u64, // Should actually be much larger eg [u8;32] // fhe params @@ -277,6 +276,7 @@ pub struct CommitteeRequested { pub degree: usize, pub plaintext_modulus: u64, pub crp: Vec, + // threshold: usize, // TODO: // computation_type: ??, // TODO: // execution_model_type: ??, // TODO: // input_deadline: ??, // TODO: @@ -288,7 +288,6 @@ pub struct CommitteeRequested { pub struct CiphernodeSelected { pub e3_id: E3id, pub nodecount: usize, - pub threshold: usize, } #[derive(Message, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] @@ -384,7 +383,7 @@ mod tests { let kse = EnclaveEvent::from(KeyshareCreated { e3_id: E3id::from(1001), pubkey, - node: address!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045") + node: address!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045"), }); let kse_bytes = kse.to_bytes()?; let _ = EnclaveEvent::from_bytes(&kse_bytes.clone()); diff --git a/packages/ciphernode/core/src/evm.rs b/packages/ciphernode/core/src/evm.rs new file mode 100644 index 00000000..2984ac41 --- /dev/null +++ b/packages/ciphernode/core/src/evm.rs @@ -0,0 +1,90 @@ +use actix::{Actor, Addr, Context}; +use alloy::{primitives::Address, sol, sol_types::SolEvent}; +use rand::{thread_rng, RngCore}; + +use crate::{ + evm_listener::{AddEventHandler, EvmEventListener, StartListening}, + evm_manager::{AddListener, EvmContractManager}, + E3id, EnclaveEvent, EventBus, SharedRng, +}; + +sol! { + #[derive(Debug)] + event CommitteeRequested( + uint256 indexed e3Id, + address filter, + uint32[2] threshold + ); + + #[derive(Debug)] + event CiphernodeAdded( + address indexed node, + uint256 index, + uint256 numNodes, + uint256 size + ); + + #[derive(Debug)] + event CiphernodeRemoved( + address indexed node, + uint256 index, + uint256 numNodes, + uint256 size + ); + + #[derive(Debug)] + event CiphertextOutputPublished( + uint256 indexed e3Id, + bytes ciphertextOutput + ); +} + +struct Evm { + evm_manager: Addr, + evm_listener: Addr, +} + +impl Evm { + pub async fn attach( + bus: Addr, + rpc_url: &str, + contract_address: Address, + ) -> Addr { + let evm_manager = EvmContractManager::attach(bus.clone(), rpc_url).await; + let evm_listener = evm_manager + .send(AddListener { contract_address }) + .await + .unwrap(); + + evm_listener + .send(AddEventHandler::::new()) + .await + .unwrap(); + + evm_listener + .send(AddEventHandler::::new()) + .await + .unwrap(); + + evm_listener + .send(AddEventHandler::::new()) + .await + .unwrap(); + + evm_listener + .send(AddEventHandler::::new()) + .await + .unwrap(); + evm_listener.do_send(StartListening); + + Evm { + evm_listener, + evm_manager, + } + .start() + } +} + +impl Actor for Evm { + type Context = Context; +} diff --git a/packages/ciphernode/core/src/evm_listener.rs b/packages/ciphernode/core/src/evm_listener.rs index e6a04349..042c6a1c 100644 --- a/packages/ciphernode/core/src/evm_listener.rs +++ b/packages/ciphernode/core/src/evm_listener.rs @@ -13,7 +13,7 @@ use std::fmt::Debug; use std::sync::Arc; use std::marker::PhantomData; -use crate::EventBus; +use crate::{EnclaveEvent, EventBus}; pub trait ContractEvent: Send + Sync + 'static { fn process(&self, bus: Addr) -> Result<()>; @@ -23,7 +23,7 @@ impl ContractEvent for T where T: SolEvent + Debug + Send + Sync + 'static, { - fn process(&self, _bus: Addr) -> Result<()> { + fn process(&self, bus: Addr) -> Result<()> { println!("Processing event: {:?}", self); // bus.do_send(EnclaveEvent::from(self)); Ok(()) diff --git a/packages/ciphernode/core/src/evm_manager.rs b/packages/ciphernode/core/src/evm_manager.rs index 262d0eed..e00d659a 100644 --- a/packages/ciphernode/core/src/evm_manager.rs +++ b/packages/ciphernode/core/src/evm_manager.rs @@ -9,6 +9,7 @@ use alloy::{ rpc::types::{BlockNumberOrTag, Filter}, transports::BoxTransport, }; +use anyhow::Result; use std::sync::Arc; pub struct EvmContractManager { @@ -28,11 +29,10 @@ impl EvmContractManager { } pub async fn attach(bus: Addr, rpc_url: &str) -> Addr { - let addr = EvmContractManager::new(bus.clone(), rpc_url) + EvmContractManager::new(bus.clone(), rpc_url) .await .unwrap() - .start(); - addr + .start() } fn add_listener(&self, contract_address: Address) -> Addr { @@ -40,8 +40,7 @@ impl EvmContractManager { .address(contract_address) .from_block(BlockNumberOrTag::Latest); let listener = EvmEventListener::new(self.provider.clone(), filter, self.bus.clone()); - let addr = listener.start(); - addr + listener.start() } } diff --git a/packages/ciphernode/core/src/lib.rs b/packages/ciphernode/core/src/lib.rs index 7187714a..b38e7f93 100644 --- a/packages/ciphernode/core/src/lib.rs +++ b/packages/ciphernode/core/src/lib.rs @@ -8,7 +8,10 @@ mod ciphernode_selector; mod data; mod enclave_contract; mod eventbus; -mod events; +pub mod events; +mod evm; +mod evm_listener; +mod evm_manager; mod fhe; mod logger; mod main_aggregator; @@ -22,6 +25,7 @@ mod publickey_aggregator; mod publickey_orchestrator; mod serializers; mod sortition; +mod utils; // TODO: this is too permissive pub use actix::prelude::*; @@ -56,6 +60,7 @@ mod tests { CiphertextSerializer, DecryptionShareSerializer, PublicKeySerializer, PublicKeyShareSerializer, }, + utils::{setup_crp_params, ParamsWithCrp}, CiphernodeAdded, CiphernodeOrchestrator, CiphernodeSelected, CiphertextOutputPublished, DecryptionshareCreated, Orchestrator, PlaintextAggregated, PlaintextOrchestrator, PublicKeyOrchestrator, ResetHistory, SharedRng, Sortition, @@ -64,10 +69,10 @@ mod tests { use alloy_primitives::Address; use anyhow::*; use fhe::{ - bfv::{BfvParameters, BfvParametersBuilder, Encoding, Plaintext, PublicKey, SecretKey}, + bfv::{BfvParameters, Encoding, Plaintext, PublicKey, SecretKey}, mbfv::{AggregateIter, CommonRandomPoly, DecryptionShare, PublicKeyShare}, }; - use fhe_traits::{FheEncoder, FheEncrypter, Serialize}; + use fhe_traits::{FheEncoder, FheEncrypter}; use rand::Rng; use rand::SeedableRng; use rand_chacha::ChaCha20Rng; @@ -102,23 +107,6 @@ mod tests { .await; } - fn setup_bfv_params( - moduli: &[u64], - degree: usize, - plaintext_modulus: u64, - ) -> Arc { - BfvParametersBuilder::new() - .set_degree(degree) - .set_plaintext_modulus(plaintext_modulus) - .set_moduli(moduli) - .build_arc() - .unwrap() - } - - fn set_up_crp(params: Arc, rng: SharedRng) -> CommonRandomPoly { - CommonRandomPoly::new(¶ms, &mut *rng.lock().unwrap()).unwrap() - } - fn generate_pk_share( params: Arc, crp: CommonRandomPoly, @@ -133,30 +121,6 @@ mod tests { Ok((pk, sk)) } - struct NewParamsWithCrp { - pub moduli: Vec, - pub degree: usize, - pub plaintext_modulus: u64, - pub crp_bytes: Vec, - pub params: Arc, - } - fn setup_crp_params( - moduli: &[u64], - degree: usize, - plaintext_modulus: u64, - rng: SharedRng, - ) -> NewParamsWithCrp { - let params = setup_bfv_params(moduli, degree, plaintext_modulus); - let crp = set_up_crp(params.clone(), rng); - NewParamsWithCrp { - moduli: moduli.to_vec(), - degree, - plaintext_modulus, - crp_bytes: crp.to_bytes(), - params, - } - } - #[actix::test] async fn test_public_key_aggregation_and_decryption() -> Result<()> { // Setup EventBus @@ -174,7 +138,7 @@ mod tests { let e3_id = E3id::new("1234"); - let NewParamsWithCrp { + let ParamsWithCrp { moduli, degree, plaintext_modulus, @@ -214,7 +178,6 @@ mod tests { let event = EnclaveEvent::from(CommitteeRequested { e3_id: e3_id.clone(), nodecount: 3, - threshold: 123, sortition_seed: 123, moduli: moduli.clone(), degree, @@ -254,7 +217,6 @@ mod tests { EnclaveEvent::from(CommitteeRequested { e3_id: e3_id.clone(), nodecount: 3, - threshold: 123, sortition_seed: 123, moduli, degree, @@ -264,7 +226,6 @@ mod tests { EnclaveEvent::from(CiphernodeSelected { e3_id: e3_id.clone(), nodecount: 3, - threshold: 123, }), EnclaveEvent::from(KeyshareCreated { pubkey: p1.clone(), @@ -387,7 +348,6 @@ mod tests { let evt_1 = EnclaveEvent::from(CommitteeRequested { e3_id: E3id::new("1234"), nodecount: 3, - threshold: 123, sortition_seed: 123, moduli: vec![0x3FFFFFFF000001], degree: 2048, @@ -398,7 +358,6 @@ mod tests { let evt_2 = EnclaveEvent::from(CommitteeRequested { e3_id: E3id::new("1235"), nodecount: 3, - threshold: 123, sortition_seed: 123, moduli: vec![0x3FFFFFFF000001], degree: 2048, @@ -409,7 +368,6 @@ mod tests { let local_evt_3 = EnclaveEvent::from(CiphernodeSelected { e3_id: E3id::new("1235"), nodecount: 3, - threshold: 123, }); bus.do_send(evt_1.clone()); @@ -449,7 +407,6 @@ mod tests { let event = EnclaveEvent::from(CommitteeRequested { e3_id: E3id::new("1235"), nodecount: 3, - threshold: 123, sortition_seed: 123, moduli: vec![0x3FFFFFFF000001], degree: 2048, diff --git a/packages/ciphernode/core/src/main_ciphernode.rs b/packages/ciphernode/core/src/main_ciphernode.rs index 1b5478ad..77ea88da 100644 --- a/packages/ciphernode/core/src/main_ciphernode.rs +++ b/packages/ciphernode/core/src/main_ciphernode.rs @@ -43,7 +43,11 @@ impl MainCiphernode { } } - pub async fn attach(address: Address, rpc_url:String) -> (Addr, JoinHandle<()>) { + pub async fn attach( + address: Address, + rpc_url: String, + contract_address: Address, + ) -> (Addr, JoinHandle<()>) { let rng = Arc::new(Mutex::new( rand_chacha::ChaCha20Rng::from_rng(OsRng).expect("Failed to create RNG"), )); @@ -51,6 +55,7 @@ impl MainCiphernode { let data = Data::new(true).start(); // TODO: Use a sled backed Data Actor let sortition = Sortition::attach(bus.clone()); let selector = CiphernodeSelector::attach(bus.clone(), sortition.clone(), address); + let orchestrator = Orchestrator::builder(bus.clone(), rng) .ciphernode(CiphernodeOrchestrator::attach( bus.clone(), diff --git a/packages/ciphernode/core/src/utils.rs b/packages/ciphernode/core/src/utils.rs new file mode 100644 index 00000000..b46de396 --- /dev/null +++ b/packages/ciphernode/core/src/utils.rs @@ -0,0 +1,45 @@ +use crate::SharedRng; +use fhe::{ + bfv::{BfvParameters, BfvParametersBuilder}, + mbfv::CommonRandomPoly, +}; +use fhe_traits::Serialize; +use std::sync::Arc; + +pub struct ParamsWithCrp { + pub moduli: Vec, + pub degree: usize, + pub plaintext_modulus: u64, + pub crp_bytes: Vec, + pub params: Arc, +} + +pub fn setup_crp_params( + moduli: &[u64], + degree: usize, + plaintext_modulus: u64, + rng: SharedRng, +) -> ParamsWithCrp { + let params = setup_bfv_params(moduli, degree, plaintext_modulus); + let crp = set_up_crp(params.clone(), rng); + ParamsWithCrp { + moduli: moduli.to_vec(), + degree, + plaintext_modulus, + crp_bytes: crp.to_bytes(), + params, + } +} + +fn setup_bfv_params(moduli: &[u64], degree: usize, plaintext_modulus: u64) -> Arc { + BfvParametersBuilder::new() + .set_degree(degree) + .set_plaintext_modulus(plaintext_modulus) + .set_moduli(moduli) + .build_arc() + .unwrap() +} + +fn set_up_crp(params: Arc, rng: SharedRng) -> CommonRandomPoly { + CommonRandomPoly::new(¶ms, &mut *rng.lock().unwrap()).unwrap() +} diff --git a/packages/ciphernode/enclave_node/src/bin/aggregator.rs b/packages/ciphernode/enclave_node/src/bin/aggregator.rs index 7378dc69..8ae7e2a5 100644 --- a/packages/ciphernode/enclave_node/src/bin/aggregator.rs +++ b/packages/ciphernode/enclave_node/src/bin/aggregator.rs @@ -1,4 +1,3 @@ -use alloy_primitives::Address; use clap::Parser; use enclave_core::MainAggregator; diff --git a/packages/ciphernode/enclave_node/src/bin/event-node.rs b/packages/ciphernode/enclave_node/src/bin/event-node.rs deleted file mode 100644 index e69de29b..00000000 diff --git a/packages/ciphernode/enclave_node/src/bin/node.rs b/packages/ciphernode/enclave_node/src/bin/node.rs index e6f0c07c..f7f23531 100644 --- a/packages/ciphernode/enclave_node/src/bin/node.rs +++ b/packages/ciphernode/enclave_node/src/bin/node.rs @@ -9,13 +9,17 @@ struct Args { address: String, #[arg(short, long)] rpc: String, + #[arg(short, long)] + contract_address: String, } #[actix_rt::main] async fn main() -> Result<(), Box> { let args = Args::parse(); let address = Address::parse_checksummed(&args.address, None).expect("Invalid address"); - let (_, handle) = MainCiphernode::attach(address, args.rpc).await; + let contract_address = + Address::parse_checksummed(&args.contract_address, None).expect("Invalid address"); + let (_, handle) = MainCiphernode::attach(address, args.rpc, contract_address).await; let _ = tokio::join!(handle); Ok(()) } From 60cc057783376f5de5c2ade72a631ba87ad7f64b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=B3=CE=BB?= Date: Wed, 18 Sep 2024 00:15:00 +1000 Subject: [PATCH 66/87] Scripts and binaries to demonstrate event system (#93) * Demo working * Demo tidy up --- packages/ciphernode/Cargo.lock | 11 ++ packages/ciphernode/core/Cargo.toml | 2 + packages/ciphernode/core/src/ciphernode.rs | 40 ++++-- .../core/src/ciphernode_orchestrator.rs | 3 +- packages/ciphernode/core/src/eventbus.rs | 2 +- packages/ciphernode/core/src/fhe.rs | 13 +- packages/ciphernode/core/src/lib.rs | 7 +- packages/ciphernode/core/src/logger.rs | 49 ++++++-- .../ciphernode/core/src/main_aggregator.rs | 8 +- .../ciphernode/core/src/main_ciphernode.rs | 8 +- packages/ciphernode/core/src/orchestrator.rs | 105 ++++++++-------- packages/ciphernode/core/src/utils.rs | 4 +- packages/ciphernode/enclave_node/Cargo.toml | 3 + .../enclave_node/scripts/.gitignore | 1 + .../ciphernode/enclave_node/scripts/ag.sh | 3 + .../ciphernode/enclave_node/scripts/cmd.sh | 4 + .../enclave_node/scripts/encrypt.sh | 4 + .../ciphernode/enclave_node/scripts/node1.sh | 4 + .../ciphernode/enclave_node/scripts/node2.sh | 4 + .../ciphernode/enclave_node/scripts/node3.sh | 4 + .../ciphernode/enclave_node/scripts/node4.sh | 4 + .../ciphernode/enclave_node/src/bin/cmd.rs | 116 ++++++++++++++++++ .../enclave_node/src/bin/encrypt.rs | 34 +++++ .../ciphernode/enclave_node/src/bin/node.rs | 14 +-- packages/ciphernode/p2p/src/lib.rs | 14 +-- 25 files changed, 359 insertions(+), 102 deletions(-) create mode 100644 packages/ciphernode/enclave_node/scripts/.gitignore create mode 100755 packages/ciphernode/enclave_node/scripts/ag.sh create mode 100755 packages/ciphernode/enclave_node/scripts/cmd.sh create mode 100755 packages/ciphernode/enclave_node/scripts/encrypt.sh create mode 100755 packages/ciphernode/enclave_node/scripts/node1.sh create mode 100755 packages/ciphernode/enclave_node/scripts/node2.sh create mode 100755 packages/ciphernode/enclave_node/scripts/node3.sh create mode 100755 packages/ciphernode/enclave_node/scripts/node4.sh create mode 100644 packages/ciphernode/enclave_node/src/bin/cmd.rs create mode 100644 packages/ciphernode/enclave_node/src/bin/encrypt.rs diff --git a/packages/ciphernode/Cargo.lock b/packages/ciphernode/Cargo.lock index 02bbe346..ded3b907 100644 --- a/packages/ciphernode/Cargo.lock +++ b/packages/ciphernode/Cargo.lock @@ -1869,6 +1869,12 @@ version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" +[[package]] +name = "base91" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4eb5fbae7b5ee422f239444a3dca9bdf5ecb3abf3af1bf87c8097db3f7bc025" + [[package]] name = "bfv" version = "0.1.0" @@ -2541,6 +2547,8 @@ dependencies = [ "alloy-sol-types 0.6.4", "anyhow", "async-std", + "base64 0.22.1", + "base91", "bincode", "bs58", "fhe", @@ -2566,7 +2574,10 @@ dependencies = [ "alloy 0.2.1", "alloy-primitives 0.6.4", "async-std", + "base64 0.22.1", + "base91", "bfv", + "bincode", "clap", "enclave-core", "fhe", diff --git a/packages/ciphernode/core/Cargo.toml b/packages/ciphernode/core/Cargo.toml index 5022d29e..8a8836f4 100644 --- a/packages/ciphernode/core/Cargo.toml +++ b/packages/ciphernode/core/Cargo.toml @@ -31,3 +31,5 @@ futures-util = "0.3" alloy = { version = "0.3.3", features = ["full"] } alloy-primitives = { version = "0.6", default-features = false, features = ["rlp", "serde", "std"] } alloy-sol-types = { version = "0.6" } +base64 = "0.22.1" +base91 = "0.1.0" diff --git a/packages/ciphernode/core/src/ciphernode.rs b/packages/ciphernode/core/src/ciphernode.rs index 2e7bc0bf..7bd4f271 100644 --- a/packages/ciphernode/core/src/ciphernode.rs +++ b/packages/ciphernode/core/src/ciphernode.rs @@ -14,7 +14,7 @@ pub struct Ciphernode { fhe: Addr, data: Addr, bus: Addr, - address: Address + address: Address, } impl Actor for Ciphernode { @@ -23,10 +23,20 @@ impl Actor for Ciphernode { impl Ciphernode { pub fn new(bus: Addr, fhe: Addr, data: Addr, address: Address) -> Self { - Self { bus, fhe, data, address } + Self { + bus, + fhe, + data, + address, + } } - pub async fn attach(bus: Addr, fhe: Addr, data: Addr, address: Address) -> Addr { + pub async fn attach( + bus: Addr, + fhe: Addr, + data: Addr, + address: Address, + ) -> Addr { let node = Ciphernode::new(bus.clone(), fhe, data, address).start(); let _ = bus .send(Subscribe::new("CiphernodeSelected", node.clone().into())) @@ -61,7 +71,11 @@ impl Handler for Ciphernode { let data = self.data.clone(); let bus = self.bus.clone(); let address = self.address; - Box::pin(async move { on_ciphernode_selected(fhe, data, bus, event, address).await.unwrap() }) + Box::pin(async move { + on_ciphernode_selected(fhe, data, bus, event, address) + .await + .unwrap() + }) } } @@ -69,6 +83,7 @@ impl Handler for Ciphernode { type Result = ResponseFuture<()>; fn handle(&mut self, event: CiphertextOutputPublished, _: &mut Context) -> Self::Result { + println!("Ciphernode::CiphertextOutputPublished"); let fhe = self.fhe.clone(); let data = self.data.clone(); let bus = self.bus.clone(); @@ -86,9 +101,12 @@ async fn on_ciphernode_selected( data: Addr, bus: Addr, event: CiphernodeSelected, - address: Address + address: Address, ) -> Result<()> { let CiphernodeSelected { e3_id, .. } = event; + + println!("\n\nGENERATING KEY!\n\n"); + // generate keyshare let (sk, pubkey) = fhe.send(GenerateKeyshare {}).await??; @@ -103,7 +121,11 @@ async fn on_ciphernode_selected( data.do_send(Insert(format!("{}/pk", e3_id).into(), pubkey.clone())); // broadcast the KeyshareCreated message - let event = EnclaveEvent::from(KeyshareCreated { pubkey, e3_id, node: address }); + let event = EnclaveEvent::from(KeyshareCreated { + pubkey, + e3_id, + node: address, + }); bus.do_send(event); Ok(()) @@ -114,7 +136,7 @@ async fn on_decryption_requested( data: Addr, bus: Addr, event: CiphertextOutputPublished, - address: Address + address: Address, ) -> Result<()> { let CiphertextOutputPublished { e3_id, @@ -126,6 +148,8 @@ async fn on_decryption_requested( return Err(anyhow::anyhow!("Secret key not stored for {}", e3_id)); }; + println!("\n\nDECRYPTING!\n\n"); + let decryption_share = fhe .send(DecryptCiphertext { ciphertext: ciphertext_output, @@ -136,7 +160,7 @@ async fn on_decryption_requested( let event = EnclaveEvent::from(DecryptionshareCreated { e3_id, decryption_share, - node: address + node: address, }); bus.do_send(event); diff --git a/packages/ciphernode/core/src/ciphernode_orchestrator.rs b/packages/ciphernode/core/src/ciphernode_orchestrator.rs index 5e409593..4fc80a99 100644 --- a/packages/ciphernode/core/src/ciphernode_orchestrator.rs +++ b/packages/ciphernode/core/src/ciphernode_orchestrator.rs @@ -36,7 +36,7 @@ impl Handler for CiphernodeOrchestrator { type Result = (); fn handle(&mut self, msg: InitializeWithEnclaveEvent, _: &mut Self::Context) -> Self::Result { let InitializeWithEnclaveEvent { fhe, event, .. } = msg; - let EnclaveEvent::CommitteeRequested { data, .. } = event else { + let EnclaveEvent::CiphernodeSelected { data, .. } = event else { return; }; let ciphernode_factory = self.ciphernode_factory(fhe.clone()); @@ -53,6 +53,7 @@ impl Handler for CiphernodeOrchestrator { let Some(e3_id) = msg.get_e3_id() else { return; }; + self.forward_message(&e3_id, msg); } } diff --git a/packages/ciphernode/core/src/eventbus.rs b/packages/ciphernode/core/src/eventbus.rs index c57ff2b5..6171fa07 100644 --- a/packages/ciphernode/core/src/eventbus.rs +++ b/packages/ciphernode/core/src/eventbus.rs @@ -64,7 +64,7 @@ impl Handler for EventBus { fn handle(&mut self, event: Subscribe, _: &mut Context) { self.listeners .entry(event.event_type) - .or_insert_with(Vec::new) + .or_default() .push(event.listener); } } diff --git a/packages/ciphernode/core/src/fhe.rs b/packages/ciphernode/core/src/fhe.rs index 88d2fbb5..544594de 100644 --- a/packages/ciphernode/core/src/fhe.rs +++ b/packages/ciphernode/core/src/fhe.rs @@ -99,10 +99,14 @@ impl Fhe { let params = BfvParametersBuilder::new() .set_degree(degree) .set_plaintext_modulus(plaintext_modulus) - .set_moduli(&moduli) + .set_moduli(moduli) .build_arc()?; - Ok(Fhe::new(params.clone(), CommonRandomPoly::deserialize(crp, ¶ms)?, rng)) + Ok(Fhe::new( + params.clone(), + CommonRandomPoly::deserialize(crp, ¶ms)?, + rng, + )) } } @@ -151,10 +155,7 @@ impl Handler for Fhe { .into_iter() .aggregate()?; - Ok(PublicKeySerializer::to_bytes( - public_key, - self.params.clone(), - )?) + Ok(public_key.to_bytes()) } } diff --git a/packages/ciphernode/core/src/lib.rs b/packages/ciphernode/core/src/lib.rs index b38e7f93..f437dec9 100644 --- a/packages/ciphernode/core/src/lib.rs +++ b/packages/ciphernode/core/src/lib.rs @@ -35,6 +35,7 @@ pub use ciphernode_selector::*; pub use data::*; pub use eventbus::*; pub use events::*; +pub use serializers::*; pub use fhe::*; pub use logger::*; pub use main_aggregator::*; @@ -46,7 +47,7 @@ pub use plaintext_orchestrator::*; pub use publickey_aggregator::*; pub use publickey_orchestrator::*; pub use sortition::*; - +pub use utils::*; // TODO: move these out to a test folder #[cfg(test)] mod tests { @@ -72,7 +73,7 @@ mod tests { bfv::{BfvParameters, Encoding, Plaintext, PublicKey, SecretKey}, mbfv::{AggregateIter, CommonRandomPoly, DecryptionShare, PublicKeyShare}, }; - use fhe_traits::{FheEncoder, FheEncrypter}; + use fhe_traits::{FheEncoder, FheEncrypter, Serialize}; use rand::Rng; use rand::SeedableRng; use rand_chacha::ChaCha20Rng; @@ -243,7 +244,7 @@ mod tests { node: eth_addrs[2] }), EnclaveEvent::from(PublicKeyAggregated { - pubkey: PublicKeySerializer::to_bytes(pubkey.clone(), params.clone())?, + pubkey: pubkey.to_bytes(), e3_id: e3_id.clone() }) ] diff --git a/packages/ciphernode/core/src/logger.rs b/packages/ciphernode/core/src/logger.rs index 0ee12104..8b3ef1cf 100644 --- a/packages/ciphernode/core/src/logger.rs +++ b/packages/ciphernode/core/src/logger.rs @@ -1,17 +1,24 @@ -use actix::{Actor, Addr, Context, Handler}; - use crate::{EnclaveEvent, EventBus, Subscribe}; +use actix::{Actor, Addr, Context, Handler}; +use base64::prelude::*; +use std::fs; -pub struct SimpleLogger; +pub struct SimpleLogger { + name: String, +} impl SimpleLogger { - pub fn attach(bus:Addr) -> Addr{ - let addr = Self.start(); - bus.do_send(Subscribe { - listener:addr.clone().recipient(), - event_type: "*".to_string() - }); - addr + pub fn attach(name: &str, bus: Addr) -> Addr { + let addr = Self { + name: name.to_owned(), + } + .start(); + bus.do_send(Subscribe { + listener: addr.clone().recipient(), + event_type: "*".to_string(), + }); + println!("[{}]: READY", name); + addr } } @@ -22,6 +29,26 @@ impl Actor for SimpleLogger { impl Handler for SimpleLogger { type Result = (); fn handle(&mut self, msg: EnclaveEvent, _: &mut Self::Context) -> Self::Result { - println!("{}", msg); + match msg.clone() { + EnclaveEvent::PublicKeyAggregated { data, .. } => { + let pubkey_str = BASE64_STANDARD.encode(&data.pubkey); + println!( + "\n\nPUBKEY:\n{}...{}\n\nSaved to scripts/pubkey.b64\n\n", + &pubkey_str[..20], + &pubkey_str[pubkey_str.len() - 20..] + ); + fs::write("scripts/pubkey.b64", &pubkey_str).unwrap(); + println!("[{}]: {}", self.name, msg); + } + EnclaveEvent::PlaintextAggregated { data, .. } => { + let output: Vec = bincode::deserialize(&data.decrypted_output).unwrap(); + println!("\n\nDECRYPTED:\n{:?}\n\n", output); + println!("[{}]: {}", self.name, msg); + } + EnclaveEvent::CiphernodeAdded { data, .. } => { + println!("[{}]: CiphernodeAdded({})", self.name, data.address); + } + _ => println!("[{}]: {}", self.name, msg), + } } } diff --git a/packages/ciphernode/core/src/main_aggregator.rs b/packages/ciphernode/core/src/main_aggregator.rs index 00e48e66..c6076f7b 100644 --- a/packages/ciphernode/core/src/main_aggregator.rs +++ b/packages/ciphernode/core/src/main_aggregator.rs @@ -1,6 +1,9 @@ use std::sync::{Arc, Mutex}; -use crate::{EventBus, Orchestrator, P2p, PlaintextOrchestrator, PublicKeyOrchestrator, Sortition}; +use crate::{ + EventBus, Orchestrator, P2p, PlaintextOrchestrator, PublicKeyOrchestrator, SimpleLogger, + Sortition, +}; use actix::{Actor, Addr, Context}; use rand::SeedableRng; use rand_chacha::rand_core::OsRng; @@ -50,6 +53,9 @@ impl MainAggregator { .await; let (p2p_addr, join_handle) = P2p::spawn_libp2p(bus.clone()).expect("Failed to setup libp2p"); + + SimpleLogger::attach("AGGREGATOR", bus.clone()); + let main_addr = MainAggregator::new(bus, sortition, orchestrator, p2p_addr).start(); (main_addr, join_handle) } diff --git a/packages/ciphernode/core/src/main_ciphernode.rs b/packages/ciphernode/core/src/main_ciphernode.rs index 77ea88da..a7241e62 100644 --- a/packages/ciphernode/core/src/main_ciphernode.rs +++ b/packages/ciphernode/core/src/main_ciphernode.rs @@ -1,7 +1,7 @@ use std::sync::{Arc, Mutex}; use crate::{ - CiphernodeOrchestrator, CiphernodeSelector, Data, EventBus, Orchestrator, P2p, Sortition, + CiphernodeOrchestrator, CiphernodeSelector, Data, EventBus, Orchestrator, P2p, SimpleLogger, Sortition }; use actix::{Actor, Addr, Context}; use alloy_primitives::Address; @@ -45,8 +45,8 @@ impl MainCiphernode { pub async fn attach( address: Address, - rpc_url: String, - contract_address: Address, + // rpc_url: String, + // contract_address: Address, ) -> (Addr, JoinHandle<()>) { let rng = Arc::new(Mutex::new( rand_chacha::ChaCha20Rng::from_rng(OsRng).expect("Failed to create RNG"), @@ -67,6 +67,8 @@ impl MainCiphernode { let (p2p_addr, join_handle) = P2p::spawn_libp2p(bus.clone()).expect("Failed to setup libp2p"); + + SimpleLogger::attach("CIPHERNODE",bus.clone()); let main_addr = MainCiphernode::new( address, bus, diff --git a/packages/ciphernode/core/src/orchestrator.rs b/packages/ciphernode/core/src/orchestrator.rs index ae846a3d..a542c527 100644 --- a/packages/ciphernode/core/src/orchestrator.rs +++ b/packages/ciphernode/core/src/orchestrator.rs @@ -123,60 +123,61 @@ impl Handler for Orchestrator { return; }; - match msg.clone() { - EnclaveEvent::CommitteeRequested { data, .. } => { - let CommitteeRequested { - degree, - moduli, - plaintext_modulus, - crp, - .. - } = data; - - let fhe_factory = self.fhe_factory(moduli, degree, plaintext_modulus, crp); - let fhe = self.fhes.entry(e3_id.clone()).or_insert_with(fhe_factory); - let meta = CommitteeMeta { - nodecount: data.nodecount, - seed: data.sortition_seed, - }; - self.meta.entry(e3_id.clone()).or_insert(meta.clone()); - - if let Some(addr) = self.public_key.clone() { - addr.do_send(InitializeWithEnclaveEvent { - event: msg.clone(), - fhe: fhe.clone(), - meta: meta.clone(), - }) + { + match msg.clone() { + EnclaveEvent::CommitteeRequested { data, .. } => { + let CommitteeRequested { + degree, + moduli, + plaintext_modulus, + crp, + .. + } = data; + + let fhe_factory = self.fhe_factory(moduli, degree, plaintext_modulus, crp); + let fhe = self.fhes.entry(e3_id.clone()).or_insert_with(fhe_factory); + let meta = CommitteeMeta { + nodecount: data.nodecount, + seed: data.sortition_seed, + }; + self.meta.entry(e3_id.clone()).or_insert(meta.clone()); + + if let Some(addr) = self.public_key.clone() { + addr.do_send(InitializeWithEnclaveEvent { + event: msg.clone(), + fhe: fhe.clone(), + meta: meta.clone(), + }); + } } - - if let Some(addr) = self.ciphernode.clone() { - addr.do_send(InitializeWithEnclaveEvent { - event: msg.clone(), - fhe: fhe.clone(), - meta: meta.clone(), - }) + EnclaveEvent::CiphernodeSelected { data, .. } => { + if let Some(addr) = self.ciphernode.clone() { + if let Some(fhe) = self.fhes.get(&data.e3_id) { + if let Some(meta) = self.meta.get(&data.e3_id) { + addr.do_send(InitializeWithEnclaveEvent { + event: msg.clone(), + fhe: fhe.clone(), + meta: meta.clone(), + }); + } + } + } + } + EnclaveEvent::CiphertextOutputPublished { data, .. } => { + if let Some(plaintext) = self.plaintext.clone() { + if let Some(fhe) = self.fhes.get(&data.e3_id) { + if let Some(meta) = self.meta.get(&data.e3_id) { + plaintext.do_send(InitializeWithEnclaveEvent { + event: msg.clone(), + fhe: fhe.clone(), + meta: meta.clone(), + }); + }; + }; + }; } - } - EnclaveEvent::CiphertextOutputPublished { data, .. } => { - let Some(plaintext) = self.plaintext.clone() else { - return; - }; - - let Some(fhe) = self.fhes.get(&data.e3_id) else { - return; - }; - - let Some(meta) = self.meta.get(&data.e3_id) else { - return; - }; - - plaintext.do_send(InitializeWithEnclaveEvent { - event: msg.clone(), - fhe: fhe.clone(), - meta: meta.clone(), - }) - } - _ => (), + _ => (), + }; }; self.forward_message(msg); diff --git a/packages/ciphernode/core/src/utils.rs b/packages/ciphernode/core/src/utils.rs index b46de396..1a51e8db 100644 --- a/packages/ciphernode/core/src/utils.rs +++ b/packages/ciphernode/core/src/utils.rs @@ -31,7 +31,7 @@ pub fn setup_crp_params( } } -fn setup_bfv_params(moduli: &[u64], degree: usize, plaintext_modulus: u64) -> Arc { +pub fn setup_bfv_params(moduli: &[u64], degree: usize, plaintext_modulus: u64) -> Arc { BfvParametersBuilder::new() .set_degree(degree) .set_plaintext_modulus(plaintext_modulus) @@ -40,6 +40,6 @@ fn setup_bfv_params(moduli: &[u64], degree: usize, plaintext_modulus: u64) -> Ar .unwrap() } -fn set_up_crp(params: Arc, rng: SharedRng) -> CommonRandomPoly { +pub fn set_up_crp(params: Arc, rng: SharedRng) -> CommonRandomPoly { CommonRandomPoly::new(¶ms, &mut *rng.lock().unwrap()).unwrap() } diff --git a/packages/ciphernode/enclave_node/Cargo.toml b/packages/ciphernode/enclave_node/Cargo.toml index 7f19fab2..7841aa31 100644 --- a/packages/ciphernode/enclave_node/Cargo.toml +++ b/packages/ciphernode/enclave_node/Cargo.toml @@ -24,3 +24,6 @@ alloy = { version = "0.2.1", features = ["full"] } clap = { version = "4.5.17", features = ["derive"] } rand_chacha = "0.3.1" rand = "0.8.5" +bincode = "1.3.3" +base91 = "0.1.0" +base64 = "0.22.1" diff --git a/packages/ciphernode/enclave_node/scripts/.gitignore b/packages/ciphernode/enclave_node/scripts/.gitignore new file mode 100644 index 00000000..3ba8733c --- /dev/null +++ b/packages/ciphernode/enclave_node/scripts/.gitignore @@ -0,0 +1 @@ +*.b64 diff --git a/packages/ciphernode/enclave_node/scripts/ag.sh b/packages/ciphernode/enclave_node/scripts/ag.sh new file mode 100755 index 00000000..d6e22791 --- /dev/null +++ b/packages/ciphernode/enclave_node/scripts/ag.sh @@ -0,0 +1,3 @@ +#!/bin/sh +echo "loading..." +RUSTFLAGS="-A warnings" cargo run --quiet --bin aggregator diff --git a/packages/ciphernode/enclave_node/scripts/cmd.sh b/packages/ciphernode/enclave_node/scripts/cmd.sh new file mode 100755 index 00000000..86e2106c --- /dev/null +++ b/packages/ciphernode/enclave_node/scripts/cmd.sh @@ -0,0 +1,4 @@ +#!/bin/sh + +echo "loading..." +RUSTFLAGS="-A warnings" cargo run --quiet --bin cmd diff --git a/packages/ciphernode/enclave_node/scripts/encrypt.sh b/packages/ciphernode/enclave_node/scripts/encrypt.sh new file mode 100755 index 00000000..45d3d6f8 --- /dev/null +++ b/packages/ciphernode/enclave_node/scripts/encrypt.sh @@ -0,0 +1,4 @@ +#!/bin/sh + +echo "loading..." +RUSTFLAGS="-A warnings" cargo run --quiet --bin encrypt diff --git a/packages/ciphernode/enclave_node/scripts/node1.sh b/packages/ciphernode/enclave_node/scripts/node1.sh new file mode 100755 index 00000000..97474c90 --- /dev/null +++ b/packages/ciphernode/enclave_node/scripts/node1.sh @@ -0,0 +1,4 @@ +#!/bin/sh + +echo "loading..." +RUSTFLAGS="-A warnings" cargo run --quiet --bin node -- --address 0xCc6c693FDB68f0DB58172639CDEa33FF488cf0a5 diff --git a/packages/ciphernode/enclave_node/scripts/node2.sh b/packages/ciphernode/enclave_node/scripts/node2.sh new file mode 100755 index 00000000..7568191c --- /dev/null +++ b/packages/ciphernode/enclave_node/scripts/node2.sh @@ -0,0 +1,4 @@ +#!/bin/sh + +echo "loading..." +RUSTFLAGS="-A warnings" cargo run --quiet --bin node -- --address 0x75437e59cAC691C0624e089554834619dc49B944 diff --git a/packages/ciphernode/enclave_node/scripts/node3.sh b/packages/ciphernode/enclave_node/scripts/node3.sh new file mode 100755 index 00000000..af6ca05c --- /dev/null +++ b/packages/ciphernode/enclave_node/scripts/node3.sh @@ -0,0 +1,4 @@ +#!/bin/sh + +echo "loading..." +RUSTFLAGS="-A warnings" cargo run --quiet --bin node -- --address 0xe3092f4A2B59234a557aa2dE5D97314D4E969764 diff --git a/packages/ciphernode/enclave_node/scripts/node4.sh b/packages/ciphernode/enclave_node/scripts/node4.sh new file mode 100755 index 00000000..0569550e --- /dev/null +++ b/packages/ciphernode/enclave_node/scripts/node4.sh @@ -0,0 +1,4 @@ +#!/bin/sh + +echo "loading..." +RUSTFLAGS="-A warnings" cargo run --quiet --bin node -- --address 0x25c693E1188b9E4455E07DC4f6a49142eFbF2C61 diff --git a/packages/ciphernode/enclave_node/src/bin/cmd.rs b/packages/ciphernode/enclave_node/src/bin/cmd.rs new file mode 100644 index 00000000..aca81e00 --- /dev/null +++ b/packages/ciphernode/enclave_node/src/bin/cmd.rs @@ -0,0 +1,116 @@ +use std::sync::Arc; + +use alloy_primitives::{address, Address}; +use base64::{engine::general_purpose, Engine as _}; +use enclave_core::{ + setup_crp_params, Actor, CommitteeRequested, E3id, EnclaveEvent, EventBus, P2p, ParamsWithCrp, + SimpleLogger, +}; +use enclave_core::{CiphernodeAdded, CiphertextOutputPublished}; +use fhe::bfv::{Encoding, Plaintext, PublicKey}; +use fhe_traits::{DeserializeParametrized, FheEncoder}; +use rand::{thread_rng, RngCore, SeedableRng}; +use rand_chacha::rand_core::OsRng; +use std::fs; +use tokio::{ + self, + io::{self, AsyncBufReadExt, BufReader}, +}; + +const ADDRS: [Address; 4] = [ + address!("Cc6c693FDB68f0DB58172639CDEa33FF488cf0a5"), + address!("75437e59cAC691C0624e089554834619dc49B944"), + address!("e3092f4A2B59234a557aa2dE5D97314D4E969764"), + address!("25c693E1188b9E4455E07DC4f6a49142eFbF2C61"), +]; + +#[actix_rt::main] +async fn main() -> Result<(), Box> { + let rng = Arc::new(std::sync::Mutex::new( + rand_chacha::ChaCha20Rng::from_rng(OsRng).expect("Failed to create RNG"), + )); + + let bus = EventBus::new(true).start(); + + SimpleLogger::attach("CMD", bus.clone()); + let (_, t1) = P2p::spawn_libp2p(bus.clone())?; + let mut stdin = BufReader::new(io::stdin()).lines(); + let ParamsWithCrp { + moduli, + degree, + plaintext_modulus, + crp_bytes, + .. + } = setup_crp_params(&[0x3FFFFFFF000001], 2048, 1032193, rng.clone()); + let t2 = tokio::spawn(async move { + let mut id: u32 = 1000; + while let Ok(Some(line)) = stdin.next_line().await { + let parts: Vec<&str> = line.split_whitespace().collect(); + match parts.as_slice() { + ["reg", "1"] => { + println!("Registering Ciphernode {}", ADDRS[0]); + bus.do_send(EnclaveEvent::from(CiphernodeAdded { + address: ADDRS[0], + index: 0, + num_nodes: 1, + })); + } + ["reg", "2"] => { + println!("Registering Ciphernode {}", ADDRS[1]); + bus.do_send(EnclaveEvent::from(CiphernodeAdded { + address: ADDRS[1], + index: 1, + num_nodes: 2, + })) + } + ["reg", "3"] => { + println!("Registering Ciphernode {}", ADDRS[2]); + bus.do_send(EnclaveEvent::from(CiphernodeAdded { + address: ADDRS[2], + index: 2, + num_nodes: 3, + })) + } + ["reg", "4"] => { + println!("Registering Ciphernode {}", ADDRS[3]); + bus.do_send(EnclaveEvent::from(CiphernodeAdded { + address: ADDRS[3], + index: 3, + num_nodes: 4, + })) + } + + ["com"] => { + id += 1; + println!("Requesting comittee: {}", id); + bus.do_send(EnclaveEvent::from(CommitteeRequested { + e3_id: E3id::from(id), + nodecount: 3, + sortition_seed: thread_rng().next_u64(), + moduli: moduli.clone(), + plaintext_modulus, + degree, + crp: crp_bytes.clone(), + })); + } + ["load"] => { + println!("Loading from ./scripts/encrypted.b64..."); + let encoded_string = fs::read_to_string("scripts/encrypted.b64").unwrap(); + + let decoded_bytes: Vec = general_purpose::STANDARD + .decode(encoded_string.trim()) + .unwrap(); + + bus.do_send(EnclaveEvent::from(CiphertextOutputPublished { + e3_id: E3id::from(id), + ciphertext_output: decoded_bytes, + })) + } + _ => println!("Unknown command"), + } + } + }); + + let _ = tokio::join!(t1, t2); + Ok(()) +} diff --git a/packages/ciphernode/enclave_node/src/bin/encrypt.rs b/packages/ciphernode/enclave_node/src/bin/encrypt.rs new file mode 100644 index 00000000..8777991a --- /dev/null +++ b/packages/ciphernode/enclave_node/src/bin/encrypt.rs @@ -0,0 +1,34 @@ +use base64::{engine::general_purpose, Engine as _}; +use enclave_core::{setup_bfv_params, setup_crp_params, CiphertextSerializer, ParamsWithCrp}; +use fhe::bfv::{Encoding, Plaintext, PublicKey}; +use fhe_traits::{DeserializeParametrized, FheEncoder, FheEncrypter, Serialize}; +use rand::SeedableRng; +use rand_chacha::{rand_core::OsRng, ChaCha20Rng}; +use std::{fs, sync::Arc}; + +fn main() -> Result<(), Box> { + // Read the base64 encoded string from a file + println!("Loading public key from ./scripts/pubkey.b64"); + let encoded_string = fs::read_to_string("scripts/pubkey.b64")?; + + // Decode the base64 string + let decoded_bytes: Vec = general_purpose::STANDARD.decode(encoded_string.trim())?; + let params = setup_bfv_params(&[0x3FFFFFFF000001], 2048, 1032193); + let pubkey = PublicKey::from_bytes(&decoded_bytes, ¶ms)?; + + let yes = 1234u64; + let no = 873827u64; + + let raw_plaintext = vec![yes, no]; + println!("Encrypting plaintext: {:?}", raw_plaintext); + + let pt = Plaintext::try_encode(&raw_plaintext, Encoding::poly(), ¶ms)?; + + let ciphertext = pubkey.try_encrypt(&pt, &mut ChaCha20Rng::seed_from_u64(42))?; + let ciphertext_bytes = CiphertextSerializer::to_bytes(ciphertext.clone(), params.clone())?; + + let encrypted = general_purpose::STANDARD.encode(ciphertext_bytes); + fs::write("scripts/encrypted.b64", &encrypted).unwrap(); + println!("Created ./scripts/encrypted.b64"); + Ok(()) +} diff --git a/packages/ciphernode/enclave_node/src/bin/node.rs b/packages/ciphernode/enclave_node/src/bin/node.rs index f7f23531..67908f96 100644 --- a/packages/ciphernode/enclave_node/src/bin/node.rs +++ b/packages/ciphernode/enclave_node/src/bin/node.rs @@ -7,19 +7,19 @@ use enclave_core::MainCiphernode; struct Args { #[arg(short, long)] address: String, - #[arg(short, long)] - rpc: String, - #[arg(short, long)] - contract_address: String, + // #[arg(short, long)] + // rpc: String, + // #[arg(short, long)] + // contract_address: String, } #[actix_rt::main] async fn main() -> Result<(), Box> { let args = Args::parse(); let address = Address::parse_checksummed(&args.address, None).expect("Invalid address"); - let contract_address = - Address::parse_checksummed(&args.contract_address, None).expect("Invalid address"); - let (_, handle) = MainCiphernode::attach(address, args.rpc, contract_address).await; + println!("LAUNCHING CIPHERNODE: ({})", address); + // let contract_address = Address::parse_checksummed(&args.contract_address, None).expect("Invalid address"); + let (_, handle) = MainCiphernode::attach(address /*args.rpc, contract_address*/).await; let _ = tokio::join!(handle); Ok(()) } diff --git a/packages/ciphernode/p2p/src/lib.rs b/packages/ciphernode/p2p/src/lib.rs index 7eff316e..9cf789cf 100644 --- a/packages/ciphernode/p2p/src/lib.rs +++ b/packages/ciphernode/p2p/src/lib.rs @@ -136,13 +136,13 @@ impl EnclaveRouter { event = self.swarm.as_mut().unwrap().select_next_some() => match event { SwarmEvent::Behaviour(MyBehaviourEvent::Mdns(mdns::Event::Discovered(list))) => { for (peer_id, _multiaddr) in list { - println!("mDNS discovered a new peer: {peer_id}"); + // println!("mDNS discovered a new peer: {peer_id}"); self.swarm.as_mut().unwrap().behaviour_mut().gossipsub.add_explicit_peer(&peer_id); } }, SwarmEvent::Behaviour(MyBehaviourEvent::Mdns(mdns::Event::Expired(list))) => { for (peer_id, _multiaddr) in list { - println!("mDNS discover peer has expired: {peer_id}"); + // println!("mDNS discover peer has expired: {peer_id}"); self.swarm.as_mut().unwrap().behaviour_mut().gossipsub.remove_explicit_peer(&peer_id); } }, @@ -151,14 +151,14 @@ impl EnclaveRouter { message_id: id, message, })) => { - println!( - "Got message with id: {id} from peer: {peer_id}", - ); - println!("{:?}", message); + // println!( + // "Got message with id: {id} from peer: {peer_id}", + // ); + // println!("{:?}", message); self.evt_tx.send(message.data).await?; }, SwarmEvent::NewListenAddr { address, .. } => { - println!("Local node is listening on {address}"); + // println!("Local node is listening on {address}"); } _ => {} } From 3cde5848d3eacba060c5eaa8aabd33b9a5b6d08c Mon Sep 17 00:00:00 2001 From: samepant Date: Tue, 17 Sep 2024 12:06:34 -0400 Subject: [PATCH 67/87] add mock deployment for testing --- packages/evm/deploy/{deploy.ts => enclave.ts} | 3 +- packages/evm/deploy/mocks.ts | 33 +++++++++++++ packages/evm/package.json | 3 +- packages/evm/tasks/committee.ts | 48 +++++++++++++------ 4 files changed, 69 insertions(+), 18 deletions(-) rename packages/evm/deploy/{deploy.ts => enclave.ts} (96%) create mode 100644 packages/evm/deploy/mocks.ts diff --git a/packages/evm/deploy/deploy.ts b/packages/evm/deploy/enclave.ts similarity index 96% rename from packages/evm/deploy/deploy.ts rename to packages/evm/deploy/enclave.ts index bde42ba0..207be341 100644 --- a/packages/evm/deploy/deploy.ts +++ b/packages/evm/deploy/enclave.ts @@ -94,5 +94,4 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { console.log(`Enclave contract updated with registry`); }; export default func; -func.id = "deploy_enclave"; // id required to prevent reexecution -func.tags = ["Enclave"]; +func.tags = ["enclave"]; diff --git a/packages/evm/deploy/mocks.ts b/packages/evm/deploy/mocks.ts new file mode 100644 index 00000000..623ebaf7 --- /dev/null +++ b/packages/evm/deploy/mocks.ts @@ -0,0 +1,33 @@ +import { DeployFunction } from "hardhat-deploy/types"; +import { HardhatRuntimeEnvironment } from "hardhat/types"; + +const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { + const { deployer } = await hre.getNamedAccounts(); + const { deploy } = hre.deployments; + + await deploy("MockE3Program", { + from: deployer, + args: [], + log: true, + }); + + await deploy("MockComputeProvider", { + from: deployer, + args: [], + log: true, + }); + + await deploy("MockDecryptionVerifier", { + from: deployer, + args: [], + log: true, + }); + + await deploy("MockInputValidator", { + from: deployer, + args: [], + log: true, + }); +}; +export default func; +func.tags = ["mocks"]; diff --git a/packages/evm/package.json b/packages/evm/package.json index 6dae0e66..698ba42c 100644 --- a/packages/evm/package.json +++ b/packages/evm/package.json @@ -72,7 +72,8 @@ "clean": "rimraf ./artifacts ./cache ./coverage ./types ./coverage.json && yarn typechain", "compile": "cross-env TS_NODE_TRANSPILE_ONLY=true hardhat compile", "coverage": "hardhat coverage --solcoverjs ./.solcover.js --temp artifacts --testfiles \"test/**/*.ts\" && yarn typechain", - "deploy": "hardhat deploy", + "deploy": "hardhat deploy --tags enclave", + "deploy:mocks": "hardhat deploy --tags enclave,mocks", "ciphernode:add": "hardhat ciphernode:add", "ciphernode:remove": "hardhat ciphernode:remove", "lint": "yarn lint:sol && yarn lint:ts && yarn prettier:check", diff --git a/packages/evm/tasks/committee.ts b/packages/evm/tasks/committee.ts index f4f8eaad..77004568 100644 --- a/packages/evm/tasks/committee.ts +++ b/packages/evm/tasks/committee.ts @@ -1,11 +1,14 @@ import { task, types } from "hardhat/config"; import type { TaskArguments } from "hardhat/types"; -task("committee:new", "Request a new ciphernode committee") +task( + "committee:new", + "Request a new ciphernode committee, will use E3 mock contracts by default", +) .addOptionalParam( "filter", "address of filter contract to use", - "0x0000000000000000000000000000000000000006", + undefined, types.string, ) .addOptionalParam( @@ -41,7 +44,7 @@ task("committee:new", "Request a new ciphernode committee") .addOptionalParam( "e3Address", "address of the E3 program", - "0x95E366f13c16976A26339aBe7992a1AB523388f5", + undefined, types.string, ) .addOptionalParam( @@ -64,34 +67,49 @@ task("committee:new", "Request a new ciphernode committee") enclave.address, ); - try { - const enableE3Tx = await enclaveContract.enableE3Program( - taskArguments.e3Address, + let e3Address = taskArguments.e3Address; + if (!e3Address) { + const mockE3Program = await hre.deployments.get("MockE3Program"); + if (!mockE3Program) { + throw new Error("MockE3Program not deployed"); + } + e3Address = mockE3Program.address; + } + + let filterAddress = taskArguments.filter; + if (!filterAddress) { + const naiveRegistryFilter = await hre.deployments.get( + "NaiveRegistryFilter", ); + if (!naiveRegistryFilter) { + throw new Error("NaiveRegistryFilter not deployed"); + } + filterAddress = naiveRegistryFilter.address; + } + + try { + const enableE3Tx = await enclaveContract.enableE3Program(e3Address); await enableE3Tx.wait(); - } catch (e: unknown) { - console.log( - "E3 program enabling failed, probably already enabled: ", - e.message, - ); + } catch (e) { + console.log("E3 program enabling failed, probably already enabled: ", e); } console.log( "requesting committee...", - taskArguments.filter, + filterAddress, [taskArguments.thresholdQuorum, taskArguments.thresholdTotal], [taskArguments.windowStart, taskArguments.windowEnd], taskArguments.duration, - taskArguments.e3Address, + e3Address, taskArguments.e3Params, taskArguments.computeParams, ); const tx = await enclaveContract.request( - taskArguments.filter, + filterAddress, [taskArguments.thresholdQuorum, taskArguments.thresholdTotal], [taskArguments.windowStart, taskArguments.windowEnd], taskArguments.duration, - taskArguments.e3Address, + e3Address, taskArguments.e3Params, taskArguments.computeParams, // 1 ETH From 238460787e25c7cba8e8d5dab00ec1ecae295fdf Mon Sep 17 00:00:00 2001 From: samepant Date: Tue, 17 Sep 2024 12:10:49 -0400 Subject: [PATCH 68/87] fix threshold initialization check --- packages/evm/contracts/registry/NaiveRegistryFilter.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/evm/contracts/registry/NaiveRegistryFilter.sol b/packages/evm/contracts/registry/NaiveRegistryFilter.sol index 7d122e9e..b8113378 100644 --- a/packages/evm/contracts/registry/NaiveRegistryFilter.sol +++ b/packages/evm/contracts/registry/NaiveRegistryFilter.sol @@ -74,7 +74,7 @@ contract NaiveRegistryFilter is IRegistryFilter, OwnableUpgradeable { uint32[2] calldata threshold ) external onlyRegistry returns (bool success) { Committee storage committee = committees[e3Id]; - require(committee.threshold.length == 0, CommitteeAlreadyExists()); + require(committee.threshold[1] == 0, CommitteeAlreadyExists()); committee.threshold = threshold; success = true; } From da694c29e15a460546a3c0927384001a7be1b7ce Mon Sep 17 00:00:00 2001 From: samepant Date: Tue, 17 Sep 2024 12:13:03 -0400 Subject: [PATCH 69/87] more efficient committee initialization --- packages/evm/contracts/registry/NaiveRegistryFilter.sol | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/evm/contracts/registry/NaiveRegistryFilter.sol b/packages/evm/contracts/registry/NaiveRegistryFilter.sol index b8113378..127b50e4 100644 --- a/packages/evm/contracts/registry/NaiveRegistryFilter.sol +++ b/packages/evm/contracts/registry/NaiveRegistryFilter.sol @@ -73,9 +73,8 @@ contract NaiveRegistryFilter is IRegistryFilter, OwnableUpgradeable { uint256 e3Id, uint32[2] calldata threshold ) external onlyRegistry returns (bool success) { - Committee storage committee = committees[e3Id]; - require(committee.threshold[1] == 0, CommitteeAlreadyExists()); - committee.threshold = threshold; + require(committees[e3Id].threshold[1] == 0, CommitteeAlreadyExists()); + committees[e3Id].threshold = threshold; success = true; } From 5af6ab5e4ef5f99614827132e75002a260a46584 Mon Sep 17 00:00:00 2001 From: samepant Date: Tue, 17 Sep 2024 12:13:29 -0400 Subject: [PATCH 70/87] remove broken task --- packages/evm/tasks/ciphernode.ts | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/packages/evm/tasks/ciphernode.ts b/packages/evm/tasks/ciphernode.ts index c6b919bf..a66bb264 100644 --- a/packages/evm/tasks/ciphernode.ts +++ b/packages/evm/tasks/ciphernode.ts @@ -18,21 +18,3 @@ task("ciphernode:add", "Register a ciphernode to the registry") console.log(`Ciphernode ${taskArguments.ciphernodeAddress} registered`); }); - -task("ciphernode:remove", "Remove a ciphernode from the registry") - .addParam("ciphernodeAddress", "address of ciphernode to remove") - .setAction(async function (taskArguments: TaskArguments, hre) { - const registry = await hre.deployments.get("CiphernodeRegistryOwnable"); - - const registryContract = await hre.ethers.getContractAt( - "CiphernodeRegistryOwnable", - registry.address, - ); - - const tx = await registryContract.removeCiphernode( - taskArguments.ciphernodeAddress, - ); - await tx.wait(); - - console.log(`Ciphernode ${taskArguments.ciphernodeAddress} removed`); - }); From 5aaadcb154084ca0d0dcc80d4e50bce9a3f53b27 Mon Sep 17 00:00:00 2001 From: samepant Date: Tue, 17 Sep 2024 12:14:43 -0400 Subject: [PATCH 71/87] ignore localhost deployment files --- packages/evm/.gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/evm/.gitignore b/packages/evm/.gitignore index e812c153..2b590893 100644 --- a/packages/evm/.gitignore +++ b/packages/evm/.gitignore @@ -9,6 +9,7 @@ coverage dist node_modules types +deployments/localhost # files *.env From 0fc763b820b91358a4479c1da3317c2e11b9c040 Mon Sep 17 00:00:00 2001 From: samepant Date: Tue, 17 Sep 2024 18:23:38 -0400 Subject: [PATCH 72/87] add e3 specific tasks, some file cleanup (#95) * add e3 specific tasks, some file cleanup * fix: publish input --------- Co-authored-by: Auryn Macmillan --- packages/evm/hardhat.config.ts | 9 +- packages/evm/tasks/committee.ts | 123 ---------------- packages/evm/tasks/enclave.ts | 245 ++++++++++++++++++++++++++++++++ 3 files changed, 246 insertions(+), 131 deletions(-) delete mode 100644 packages/evm/tasks/committee.ts create mode 100644 packages/evm/tasks/enclave.ts diff --git a/packages/evm/hardhat.config.ts b/packages/evm/hardhat.config.ts index 14821bc4..60c4cf88 100644 --- a/packages/evm/hardhat.config.ts +++ b/packages/evm/hardhat.config.ts @@ -7,7 +7,7 @@ import type { NetworkUserConfig } from "hardhat/types"; import "./tasks/accounts"; import "./tasks/ciphernode"; -import "./tasks/committee"; +import "./tasks/enclave"; dotenv.config(); @@ -90,13 +90,6 @@ const config: HardhatUserConfig = { chainId: chainIds.hardhat, allowUnlimitedContractSize: true, }, - ganache: { - accounts: { - mnemonic, - }, - chainId: chainIds.ganache, - url: "http://localhost:8545", - }, arbitrum: getChainConfig("arbitrum-mainnet"), avalanche: getChainConfig("avalanche"), bsc: getChainConfig("bsc"), diff --git a/packages/evm/tasks/committee.ts b/packages/evm/tasks/committee.ts deleted file mode 100644 index 77004568..00000000 --- a/packages/evm/tasks/committee.ts +++ /dev/null @@ -1,123 +0,0 @@ -import { task, types } from "hardhat/config"; -import type { TaskArguments } from "hardhat/types"; - -task( - "committee:new", - "Request a new ciphernode committee, will use E3 mock contracts by default", -) - .addOptionalParam( - "filter", - "address of filter contract to use", - undefined, - types.string, - ) - .addOptionalParam( - "thresholdQuorum", - "threshold quorum for committee", - 2, - types.int, - ) - .addOptionalParam( - "thresholdTotal", - "threshold total for committee", - 2, - types.int, - ) - .addOptionalParam( - "windowStart", - "timestamp start of window for the E3 (default: now)", - Math.floor(Date.now() / 1000), - types.int, - ) - .addOptionalParam( - "windowEnd", - "timestamp end of window for the E3 (default: now + 1 day)", - Math.floor(Date.now() / 1000) + 86400, - types.int, - ) - .addOptionalParam( - "duration", - "duration in seconds of the E3 (default: 1 day)", - 86400, - types.int, - ) - .addOptionalParam( - "e3Address", - "address of the E3 program", - undefined, - types.string, - ) - .addOptionalParam( - "e3Params", - "parameters for the E3 program", - "0x0000000000000000000000009f3ebc4f6be495901a29bba2ae5a45fb870cdc14", - types.string, - ) - .addOptionalParam( - "computeParams", - "parameters for the compute provider", - "0x000000000000000000000000404af1c0780a9269e4d3308a0812fb87bf5fc490", - types.string, - ) - .setAction(async function (taskArguments: TaskArguments, hre) { - const enclave = await hre.deployments.get("Enclave"); - - const enclaveContract = await hre.ethers.getContractAt( - "Enclave", - enclave.address, - ); - - let e3Address = taskArguments.e3Address; - if (!e3Address) { - const mockE3Program = await hre.deployments.get("MockE3Program"); - if (!mockE3Program) { - throw new Error("MockE3Program not deployed"); - } - e3Address = mockE3Program.address; - } - - let filterAddress = taskArguments.filter; - if (!filterAddress) { - const naiveRegistryFilter = await hre.deployments.get( - "NaiveRegistryFilter", - ); - if (!naiveRegistryFilter) { - throw new Error("NaiveRegistryFilter not deployed"); - } - filterAddress = naiveRegistryFilter.address; - } - - try { - const enableE3Tx = await enclaveContract.enableE3Program(e3Address); - await enableE3Tx.wait(); - } catch (e) { - console.log("E3 program enabling failed, probably already enabled: ", e); - } - - console.log( - "requesting committee...", - filterAddress, - [taskArguments.thresholdQuorum, taskArguments.thresholdTotal], - [taskArguments.windowStart, taskArguments.windowEnd], - taskArguments.duration, - e3Address, - taskArguments.e3Params, - taskArguments.computeParams, - ); - const tx = await enclaveContract.request( - filterAddress, - [taskArguments.thresholdQuorum, taskArguments.thresholdTotal], - [taskArguments.windowStart, taskArguments.windowEnd], - taskArguments.duration, - e3Address, - taskArguments.e3Params, - taskArguments.computeParams, - // 1 ETH - { value: "1000000000000000000" }, - ); - - console.log("Reequesting committee... ", tx.hash); - await tx.wait(); - - console.log(`Committee requested`); - }); diff --git a/packages/evm/tasks/enclave.ts b/packages/evm/tasks/enclave.ts new file mode 100644 index 00000000..7245d189 --- /dev/null +++ b/packages/evm/tasks/enclave.ts @@ -0,0 +1,245 @@ +import { task, types } from "hardhat/config"; +import type { TaskArguments } from "hardhat/types"; + +task( + "committee:new", + "Request a new ciphernode committee, will use E3 mock contracts by default", +) + .addOptionalParam( + "filter", + "address of filter contract to use", + undefined, + types.string, + ) + .addOptionalParam( + "thresholdQuorum", + "threshold quorum for committee", + 2, + types.int, + ) + .addOptionalParam( + "thresholdTotal", + "threshold total for committee", + 2, + types.int, + ) + .addOptionalParam( + "windowStart", + "timestamp start of window for the E3 (default: now)", + Math.floor(Date.now() / 1000), + types.int, + ) + .addOptionalParam( + "windowEnd", + "timestamp end of window for the E3 (default: now + 1 day)", + Math.floor(Date.now() / 1000) + 86400, + types.int, + ) + .addOptionalParam( + "duration", + "duration in seconds of the E3 (default: 1 day)", + 86400, + types.int, + ) + .addOptionalParam( + "e3Address", + "address of the E3 program", + undefined, + types.string, + ) + .addOptionalParam( + "e3Params", + "parameters for the E3 program", + "0x0000000000000000000000004965ceCe27422B8B9557f9b9C841581B8Da60B34", + types.string, + ) + .addOptionalParam( + "computeParams", + "parameters for the compute provider", + "0x000000000000000000000000404af1c0780a9269e4d3308a0812fb87bf5fc490", + types.string, + ) + .setAction(async function (taskArguments: TaskArguments, hre) { + const enclave = await hre.deployments.get("Enclave"); + + const enclaveContract = await hre.ethers.getContractAt( + "Enclave", + enclave.address, + ); + + let e3Address = taskArguments.e3Address; + if (!e3Address) { + const mockE3Program = await hre.deployments.get("MockE3Program"); + if (!mockE3Program) { + throw new Error("MockE3Program not deployed"); + } + e3Address = mockE3Program.address; + } + + let filterAddress = taskArguments.filter; + if (!filterAddress) { + const naiveRegistryFilter = await hre.deployments.get( + "NaiveRegistryFilter", + ); + if (!naiveRegistryFilter) { + throw new Error("NaiveRegistryFilter not deployed"); + } + filterAddress = naiveRegistryFilter.address; + } + + try { + const enableE3Tx = await enclaveContract.enableE3Program(e3Address); + await enableE3Tx.wait(); + } catch (e) { + console.log("E3 program enabling failed, probably already enabled: ", e); + } + + const tx = await enclaveContract.request( + filterAddress, + [taskArguments.thresholdQuorum, taskArguments.thresholdTotal], + [taskArguments.windowStart, taskArguments.windowEnd], + taskArguments.duration, + e3Address, + taskArguments.e3Params, + taskArguments.computeParams, + // 1 ETH + { value: "1000000000000000000" }, + ); + + console.log("Reequesting committee... ", tx.hash); + await tx.wait(); + + console.log(`Committee requested`); + }); + +task("committee:publish", "Publish the publickey of the committee") + .addOptionalParam( + "filter", + "address of filter contract to use (defaults to NaiveRegistryFilter)", + ) + .addParam("e3Id", "Id of the E3 program", undefined, types.int) + .addParam( + "nodes", + "list of node address in the committee, comma separated", + undefined, + types.string, + ) + .addParam("publicKey", "public key of the committee", undefined, types.string) + .setAction(async function (taskArguments: TaskArguments, hre) { + let filterAddress = taskArguments.filter; + if (!taskArguments.filter) { + filterAddress = (await hre.deployments.get("NaiveRegistryFilter")) + .address; + + if (!filterAddress) { + throw new Error("NaiveRegistryFilter not deployed"); + } + } + + const filterContract = await hre.ethers.getContractAt( + "NaiveRegistryFilter", + filterAddress, + ); + + const nodes = taskArguments.nodes.split(","); + + if (!Array.isArray(nodes)) { + throw new Error( + "Could not parse nodes: Nodes must be input as comma separated list", + ); + } + + const tx = await filterContract.publishCommittee( + taskArguments.e3Id, + nodes, + taskArguments.publicKey, + ); + + console.log("Publishing committee... ", tx.hash); + await tx.wait(); + console.log(`Committee public key published`); + }); + +task("e3:activate", "Activate an E3 program") + .addParam("e3Id", "Id of the E3 program") + .setAction(async function (taskArguments: TaskArguments, hre) { + const enclave = await hre.deployments.get("Enclave"); + + const enclaveContract = await hre.ethers.getContractAt( + "Enclave", + enclave.address, + ); + + const tx = await enclaveContract.activate(taskArguments.e3Id); + + console.log("Activating E3 program... ", tx.hash); + await tx.wait(); + + console.log(`E3 program activated`); + }); + +task("e3:publishInput", "Publish input for an E3 program") + .addParam("e3Id", "Id of the E3 program") + .addParam("data", "data to publish") + .setAction(async function (taskArguments: TaskArguments, hre) { + const enclave = await hre.deployments.get("Enclave"); + + const enclaveContract = await hre.ethers.getContractAt( + "Enclave", + enclave.address, + ); + + const tx = await enclaveContract.publishInput( + taskArguments.e3Id, + taskArguments.data, + ); + + console.log("Publishing input... ", tx.hash); + await tx.wait(); + + console.log(`Input published`); + }); + +task("e3:publishCiphertext", "Publish ciphertext output for an E3 program") + .addParam("e3Id", "Id of the E3 program") + .addParam("data", "data to publish") + .setAction(async function (taskArguments: TaskArguments, hre) { + const enclave = await hre.deployments.get("Enclave"); + + const enclaveContract = await hre.ethers.getContractAt( + "Enclave", + enclave.address, + ); + + const tx = await enclaveContract.publishCiphertextOutput( + taskArguments.e3Id, + taskArguments.data, + ); + + console.log("Publishing ciphertext... ", tx.hash); + await tx.wait(); + + console.log(`Ciphertext published`); + }); + +task("e3:publishPlaintext", "Publish plaintext output for an E3 program") + .addParam("e3Id", "Id of the E3 program") + .addParam("data", "data to publish") + .setAction(async function (taskArguments: TaskArguments, hre) { + const enclave = await hre.deployments.get("Enclave"); + + const enclaveContract = await hre.ethers.getContractAt( + "Enclave", + enclave.address, + ); + + const tx = await enclaveContract.publishPlaintextOutput( + taskArguments.e3Id, + taskArguments.data, + ); + + console.log("Publishing ciphertext... ", tx.hash); + await tx.wait(); + + console.log(`Ciphertext published`); + }); From 7749639fc70f8e111823156fefd543eee436bf08 Mon Sep 17 00:00:00 2001 From: Auryn Macmillan Date: Tue, 17 Sep 2024 23:26:08 -0400 Subject: [PATCH 73/87] feat: scaffold out new unit tests and fix fixtures --- .../registry/CiphernodeRegistryOwnable.sol | 30 ++-- .../CyphernodeRegistryOwnable.spec.ts | 150 ++++++++++++++++++ packages/evm/test/Enclave.spec.ts | 39 ++--- .../CiphernodeRegistryOwnable.fixture.ts | 24 +++ packages/evm/test/fixtures/Enclave.fixture.ts | 25 ++- .../fixtures/NaiveRegistryFilter.fixture.ts | 19 +++ .../evm/test/fixtures/PoseidonT3.fixture.ts | 15 ++ 7 files changed, 249 insertions(+), 53 deletions(-) create mode 100644 packages/evm/test/CyphernodeRegistry/CyphernodeRegistryOwnable.spec.ts create mode 100644 packages/evm/test/fixtures/CiphernodeRegistryOwnable.fixture.ts create mode 100644 packages/evm/test/fixtures/NaiveRegistryFilter.fixture.ts create mode 100644 packages/evm/test/fixtures/PoseidonT3.fixture.ts diff --git a/packages/evm/contracts/registry/CiphernodeRegistryOwnable.sol b/packages/evm/contracts/registry/CiphernodeRegistryOwnable.sol index 2f897758..c7e5dd62 100644 --- a/packages/evm/contracts/registry/CiphernodeRegistryOwnable.sol +++ b/packages/evm/contracts/registry/CiphernodeRegistryOwnable.sol @@ -103,17 +103,6 @@ contract CiphernodeRegistryOwnable is ICiphernodeRegistry, OwnableUpgradeable { emit CommitteePublished(e3Id, publicKey); } - //////////////////////////////////////////////////////////// - // // - // Set Functions // - // // - //////////////////////////////////////////////////////////// - - function setEnclave(address _enclave) public onlyOwner { - enclave = _enclave; - emit EnclaveSet(_enclave); - } - function addCiphernode(address node) external onlyOwner { uint160 ciphernode = uint160(node); ciphernodes._insert(ciphernode); @@ -130,7 +119,7 @@ contract CiphernodeRegistryOwnable is ICiphernodeRegistry, OwnableUpgradeable { address node, uint256[] calldata siblingNodes ) external onlyOwner { - uint256 ciphernode = uint256(bytes32(bytes20(node))); + uint160 ciphernode = uint160(node); ciphernodes._remove(ciphernode, siblingNodes); uint256 index = ciphernodes._indexOf(ciphernode); numCiphernodes--; @@ -143,8 +132,15 @@ contract CiphernodeRegistryOwnable is ICiphernodeRegistry, OwnableUpgradeable { emit CiphernodeRemoved(node, index, numCiphernodes, ciphernodes.size); } - function isCiphernodeEligible(address node) external view returns (bool) { - return isEnabled(node); + //////////////////////////////////////////////////////////// + // // + // Set Functions // + // // + //////////////////////////////////////////////////////////// + + function setEnclave(address _enclave) public onlyOwner { + enclave = _enclave; + emit EnclaveSet(_enclave); } //////////////////////////////////////////////////////////// @@ -160,8 +156,12 @@ contract CiphernodeRegistryOwnable is ICiphernodeRegistry, OwnableUpgradeable { require(publicKey.length > 0, CommitteeNotPublished()); } + function isCiphernodeEligible(address node) external view returns (bool) { + return isEnabled(node); + } + function isEnabled(address node) public view returns (bool) { - return ciphernodes._has(uint256(bytes32(bytes20(node)))); + return ciphernodes._has(uint160(node)); } function root() public view returns (uint256) { diff --git a/packages/evm/test/CyphernodeRegistry/CyphernodeRegistryOwnable.spec.ts b/packages/evm/test/CyphernodeRegistry/CyphernodeRegistryOwnable.spec.ts new file mode 100644 index 00000000..10d94af0 --- /dev/null +++ b/packages/evm/test/CyphernodeRegistry/CyphernodeRegistryOwnable.spec.ts @@ -0,0 +1,150 @@ +import { + loadFixture, + mine, + time, +} from "@nomicfoundation/hardhat-network-helpers"; +import { LeanIMT } from "@zk-kit/lean-imt"; +import { expect } from "chai"; +import { ZeroHash } from "ethers"; +import { ethers } from "hardhat"; +import { poseidon2 } from "poseidon-lite"; + +import { deployCiphernodeRegistryOwnableFixture } from "../fixtures/CiphernodeRegistryOwnable.fixture"; +import { naiveRegistryFilterFixture } from "../fixtures/NaiveRegistryFilter.fixture"; +import { PoseidonT3Fixture } from "../fixtures/PoseidonT3.fixture"; + +const abiCoder = ethers.AbiCoder.defaultAbiCoder(); +const AddressOne = "0x0000000000000000000000000000000000000001"; +const AddressTwo = "0x0000000000000000000000000000000000000002"; +const addressThree = "0x0000000000000000000000000000000000000003"; + +// Hash function used to compute the tree nodes. +const hash = (a: bigint, b: bigint) => poseidon2([a, b]); + +describe.only("CiphernodeRegistryOwnable", function () { + async function setup() { + const [owner, notTheOwner] = await ethers.getSigners(); + + const poseidon = await PoseidonT3Fixture(); + const registry = await deployCiphernodeRegistryOwnableFixture( + owner.address, + owner.address, + await poseidon.getAddress(), + ); + const filter = await naiveRegistryFilterFixture( + owner.address, + await registry.getAddress(), + ); + await registry.addCiphernode(AddressOne); + await registry.addCiphernode(AddressTwo); + + return { + owner, + notTheOwner, + registry, + filter, + request: { + e3Id: 1, + filter: await filter.getAddress(), + threshold: [2, 2] as [number, number], + }, + }; + } + + describe("constructor / initialize()", function () { + it("correctly sets `_owner` and `enclave` ", async function () { + const poseidonFactory = await ethers.getContractFactory("PoseidonT3"); + const poseidonDeployment = await poseidonFactory.deploy(); + const [deployer] = await ethers.getSigners(); + let ciphernodeRegistryFactory = await ethers.getContractFactory( + "CiphernodeRegistryOwnable", + { + libraries: { + PoseidonT3: await poseidonDeployment.getAddress(), + }, + }, + ); + let ciphernodeRegistry = await ciphernodeRegistryFactory.deploy( + deployer.address, + AddressTwo, + ); + expect(await ciphernodeRegistry.owner()).to.equal(deployer.address); + expect(await ciphernodeRegistry.enclave()).to.equal(AddressTwo); + }); + }); + + describe("requestCommittee()", function () { + it("reverts if committee has already been requested for given e3Id", async function () { + const { registry, request } = await loadFixture(setup); + await registry.requestCommittee( + request.e3Id, + request.filter, + request.threshold, + ); + await expect( + registry.requestCommittee( + request.e3Id, + request.filter, + request.threshold, + ), + ).to.be.revertedWithCustomError(registry, "CommitteeAlreadyRequested"); + }); + it("stores the registry filter for the given e3Id"); + it("stores the root of the ciphernode registry at the time of the request"); + it("requests a committee from the given filter"); + it("emits a CommitteeRequested event"); + it("reverts if filter.requestCommittee() fails"); + it("returns true if the request is successful"); + }); + + describe("publishCommittee()", function () { + it("reverts if the caller is not the filter for the given e3Id"); + it("stores the public key of the committee"); + it("emits a CommitteePublished event"); + }); + + describe("addCiphernode()", function () { + it("reverts if the caller is not the owner"); + it("adds the ciphernode to the registry"); + it("increments numCiphernodes"); + it("emits a CiphernodeAdded event"); + }); + + describe("removeCiphernode()", function () { + it("reverts if the caller is not the owner"); + it("removes the ciphernode from the registry"); + it("decrements numCiphernodes"); + it("emits a CiphernodeRemoved event"); + }); + + describe("setEnclave()", function () { + it("reverts if the caller is not the owner"); + it("sets the enclave address"); + it("emits an EnclaveSet event"); + }); + + describe("committeePublicKey()", function () { + it("returns the public key of the committee for the given e3Id"); + it("reverts if the committee has not been published"); + }); + + describe("isCiphernodeEligible()", function () { + it("returns true if the ciphernode is in the registry"); + it("returns false if the ciphernode is not in the registry"); + }); + + describe("isEnabled()", function () { + it("returns true if the ciphernode is currently enabled"); + it("returns false if the ciphernode is not currently enabled"); + }); + + describe("root()", function () { + it("returns the root of the ciphernode registry merkle tree"); + }); + + describe("rootAt()", function () { + it( + "returns the root of the ciphernode registry merkle tree at the given e3Id", + ); + }); +}); diff --git a/packages/evm/test/Enclave.spec.ts b/packages/evm/test/Enclave.spec.ts index 6432115f..22d53939 100644 --- a/packages/evm/test/Enclave.spec.ts +++ b/packages/evm/test/Enclave.spec.ts @@ -15,6 +15,7 @@ import { deployComputeProviderFixture } from "./fixtures/MockComputeProvider.fix import { deployDecryptionVerifierFixture } from "./fixtures/MockDecryptionVerifier.fixture"; import { deployE3ProgramFixture } from "./fixtures/MockE3Program.fixture"; import { deployInputValidatorFixture } from "./fixtures/MockInputValidator.fixture"; +import { PoseidonT3Fixture } from "./fixtures/PoseidonT3.fixture"; const abiCoder = ethers.AbiCoder.defaultAbiCoder(); const AddressTwo = "0x0000000000000000000000000000000000000002"; @@ -30,16 +31,18 @@ describe("Enclave", function () { async function setup() { const [owner, notTheOwner] = await ethers.getSigners(); + const poseidon = await PoseidonT3Fixture(); const registry = await deployCiphernodeRegistryFixture(); const e3Program = await deployE3ProgramFixture(); const decryptionVerifier = await deployDecryptionVerifierFixture(); const computeProvider = await deployComputeProviderFixture(); const inputValidator = await deployInputValidatorFixture(); - const enclave = await deployEnclaveFixture({ - owner, - registry: await registry.getAddress(), - }); + const enclave = await deployEnclaveFixture( + owner.address, + await registry.getAddress(), + await poseidon.getAddress(), + ); await enclave.enableE3Program(await e3Program.getAddress()); @@ -47,6 +50,7 @@ describe("Enclave", function () { owner, notTheOwner, enclave, + poseidon, mocks: { e3Program, decryptionVerifier, @@ -77,31 +81,20 @@ describe("Enclave", function () { describe("constructor / initialize()", function () { it("correctly sets owner", async function () { - const [, , , someSigner] = await ethers.getSigners(); - const enclave = await deployEnclaveFixture({ - owner: someSigner, - registry: AddressTwo, - }); - expect(await enclave.ciphernodeRegistry()).to.equal(AddressTwo); + const { owner, enclave } = await loadFixture(setup); + expect(await enclave.owner()).to.equal(owner.address); }); it("correctly sets ciphernodeRegistry address", async function () { - const [aSigner] = await ethers.getSigners(); - const enclave = await deployEnclaveFixture({ - owner: aSigner, - registry: AddressTwo, - }); - expect(await enclave.ciphernodeRegistry()).to.equal(AddressTwo); + const { mocks, enclave } = await loadFixture(setup); + expect(await enclave.ciphernodeRegistry()).to.equal( + await mocks.registry.getAddress(), + ); }); it("correctly sets max duration", async function () { - const [aSigner] = await ethers.getSigners(); - const enclave = await deployEnclaveFixture({ - owner: aSigner, - registry: AddressTwo, - maxDuration: 9876, - }); - expect(await enclave.maxDuration()).to.equal(9876); + const { enclave } = await loadFixture(setup); + expect(await enclave.maxDuration()).to.equal(60 * 60 * 24 * 30); }); }); diff --git a/packages/evm/test/fixtures/CiphernodeRegistryOwnable.fixture.ts b/packages/evm/test/fixtures/CiphernodeRegistryOwnable.fixture.ts new file mode 100644 index 00000000..3189186e --- /dev/null +++ b/packages/evm/test/fixtures/CiphernodeRegistryOwnable.fixture.ts @@ -0,0 +1,24 @@ +import { ethers } from "hardhat"; + +import { CiphernodeRegistryOwnable__factory } from "../../types"; + +export async function deployCiphernodeRegistryOwnableFixture( + owner: string, + enclave: string, + poseidonT3: string, + name?: string, +) { + const [signer] = await ethers.getSigners(); + const deployment = await ( + await ethers.getContractFactory(name || "CiphernodeRegistryOwnable", { + libraries: { + PoseidonT3: poseidonT3, + }, + }) + ).deploy(owner, enclave); + + return CiphernodeRegistryOwnable__factory.connect( + await deployment.getAddress(), + signer, + ); +} diff --git a/packages/evm/test/fixtures/Enclave.fixture.ts b/packages/evm/test/fixtures/Enclave.fixture.ts index aee379e0..9c847db7 100644 --- a/packages/evm/test/fixtures/Enclave.fixture.ts +++ b/packages/evm/test/fixtures/Enclave.fixture.ts @@ -3,25 +3,20 @@ import { ethers } from "hardhat"; import { Enclave__factory } from "../../types/factories/contracts/Enclave__factory"; -export async function deployEnclaveFixture({ - owner, - registry, - maxDuration = 60 * 60 * 24 * 30, -}: { - owner: SignerWithAddress; - registry: string; - maxDuration?: number; -}) { - const poseidonFactory = await ethers.getContractFactory("PoseidonT3"); - const poseidonDeployment = await poseidonFactory.deploy(); - +export async function deployEnclaveFixture( + owner: string, + registry: string, + poseidonT3: string, + maxDuration?: number, +) { + const [signer] = await ethers.getSigners(); const deployment = await ( await ethers.getContractFactory("Enclave", { libraries: { - PoseidonT3: await poseidonDeployment.getAddress(), + PoseidonT3: poseidonT3, }, }) - ).deploy(owner, registry, maxDuration); + ).deploy(owner, registry, maxDuration || 60 * 60 * 24 * 30); - return Enclave__factory.connect(await deployment.getAddress(), owner); + return Enclave__factory.connect(await deployment.getAddress(), signer); } diff --git a/packages/evm/test/fixtures/NaiveRegistryFilter.fixture.ts b/packages/evm/test/fixtures/NaiveRegistryFilter.fixture.ts new file mode 100644 index 00000000..e2004e39 --- /dev/null +++ b/packages/evm/test/fixtures/NaiveRegistryFilter.fixture.ts @@ -0,0 +1,19 @@ +import { ethers } from "hardhat"; + +import { NaiveRegistryFilter__factory } from "../../types"; + +export async function naiveRegistryFilterFixture( + owner: string, + registry: string, + name?: string, +) { + const [signer] = await ethers.getSigners(); + const deployment = await ( + await ethers.getContractFactory(name || "NaiveRegistryFilter") + ).deploy(owner, registry); + + return NaiveRegistryFilter__factory.connect( + await deployment.getAddress(), + signer.provider, + ); +} diff --git a/packages/evm/test/fixtures/PoseidonT3.fixture.ts b/packages/evm/test/fixtures/PoseidonT3.fixture.ts new file mode 100644 index 00000000..471339c9 --- /dev/null +++ b/packages/evm/test/fixtures/PoseidonT3.fixture.ts @@ -0,0 +1,15 @@ +import { ethers } from "hardhat"; + +import { PoseidonT3__factory } from "../../types"; + +export async function PoseidonT3Fixture(name?: string) { + const [signer] = await ethers.getSigners(); + const deployment = await ( + await ethers.getContractFactory(name || "PoseidonT3") + ).deploy(); + + return PoseidonT3__factory.connect( + await deployment.getAddress(), + signer.provider, + ); +} From 216cec16e80c9391091d69b3ee7a29f4ff691baa Mon Sep 17 00:00:00 2001 From: Auryn Macmillan Date: Wed, 18 Sep 2024 00:10:23 -0400 Subject: [PATCH 74/87] add: fill out some of the registry unit tests --- .../registry/CiphernodeRegistryOwnable.sol | 14 +- .../CyphernodeRegistryOwnable.spec.ts | 125 ++++++++++++++++-- .../fixtures/NaiveRegistryFilter.fixture.ts | 2 +- 3 files changed, 125 insertions(+), 16 deletions(-) diff --git a/packages/evm/contracts/registry/CiphernodeRegistryOwnable.sol b/packages/evm/contracts/registry/CiphernodeRegistryOwnable.sol index c7e5dd62..f01730f9 100644 --- a/packages/evm/contracts/registry/CiphernodeRegistryOwnable.sol +++ b/packages/evm/contracts/registry/CiphernodeRegistryOwnable.sol @@ -24,7 +24,7 @@ contract CiphernodeRegistryOwnable is ICiphernodeRegistry, OwnableUpgradeable { uint256 public numCiphernodes; LeanIMTData public ciphernodes; - mapping(uint256 e3Id => IRegistryFilter filter) public requests; + mapping(uint256 e3Id => IRegistryFilter filter) public filters; mapping(uint256 e3Id => uint256 root) public roots; mapping(uint256 e3Id => bytes publicKey) public publicKeys; @@ -36,7 +36,7 @@ contract CiphernodeRegistryOwnable is ICiphernodeRegistry, OwnableUpgradeable { error CommitteeAlreadyRequested(); error CommitteeAlreadyPublished(); - error CommitteeDoesNotExist(); + error OnlyFilter(); error CommitteeNotPublished(); error CiphernodeNotEnabled(address node); error OnlyEnclave(); @@ -80,10 +80,10 @@ contract CiphernodeRegistryOwnable is ICiphernodeRegistry, OwnableUpgradeable { uint32[2] calldata threshold ) external onlyEnclave returns (bool success) { require( - requests[e3Id] == IRegistryFilter(address(0)), + filters[e3Id] == IRegistryFilter(address(0)), CommitteeAlreadyRequested() ); - requests[e3Id] = IRegistryFilter(filter); + filters[e3Id] = IRegistryFilter(filter); roots[e3Id] = root(); IRegistryFilter(filter).requestCommittee(e3Id, threshold); @@ -97,7 +97,7 @@ contract CiphernodeRegistryOwnable is ICiphernodeRegistry, OwnableUpgradeable { bytes calldata publicKey ) external { // only to be published by the filter - require(address(requests[e3Id]) == msg.sender, CommitteeDoesNotExist()); + require(address(filters[e3Id]) == msg.sender, OnlyFilter()); publicKeys[e3Id] = publicKey; emit CommitteePublished(e3Id, publicKey); @@ -171,4 +171,8 @@ contract CiphernodeRegistryOwnable is ICiphernodeRegistry, OwnableUpgradeable { function rootAt(uint256 e3Id) public view returns (uint256) { return roots[e3Id]; } + + function getFilter(uint256 e3Id) public view returns (IRegistryFilter) { + return filters[e3Id]; + } } diff --git a/packages/evm/test/CyphernodeRegistry/CyphernodeRegistryOwnable.spec.ts b/packages/evm/test/CyphernodeRegistry/CyphernodeRegistryOwnable.spec.ts index 10d94af0..c4b149aa 100644 --- a/packages/evm/test/CyphernodeRegistry/CyphernodeRegistryOwnable.spec.ts +++ b/packages/evm/test/CyphernodeRegistry/CyphernodeRegistryOwnable.spec.ts @@ -6,7 +6,7 @@ import { import { LeanIMT } from "@zk-kit/lean-imt"; import { expect } from "chai"; import { ZeroHash } from "ethers"; -import { ethers } from "hardhat"; +import { ethers, network } from "hardhat"; import { poseidon2 } from "poseidon-lite"; import { deployCiphernodeRegistryOwnableFixture } from "../fixtures/CiphernodeRegistryOwnable.fixture"; @@ -89,18 +89,119 @@ describe.only("CiphernodeRegistryOwnable", function () { ), ).to.be.revertedWithCustomError(registry, "CommitteeAlreadyRequested"); }); - it("stores the registry filter for the given e3Id"); - it("stores the root of the ciphernode registry at the time of the request"); - it("requests a committee from the given filter"); - it("emits a CommitteeRequested event"); - it("reverts if filter.requestCommittee() fails"); - it("returns true if the request is successful"); + it("stores the registry filter for the given e3Id", async function () { + const { registry, request } = await loadFixture(setup); + await registry.requestCommittee( + request.e3Id, + request.filter, + request.threshold, + ); + expect(await registry.getFilter(request.e3Id)).to.equal(request.filter); + }); + it("stores the root of the ciphernode registry at the time of the request", async function () { + const { registry, request } = await loadFixture(setup); + await registry.requestCommittee( + request.e3Id, + request.filter, + request.threshold, + ); + expect(await registry.rootAt(request.e3Id)).to.equal( + await registry.root(), + ); + }); + it("requests a committee from the given filter", async function () { + const { registry, request } = await loadFixture(setup); + await registry.requestCommittee( + request.e3Id, + request.filter, + request.threshold, + ); + expect(await registry.getFilter(request.e3Id)).to.equal(request.filter); + }); + it("emits a CommitteeRequested event", async function () { + const { registry, request } = await loadFixture(setup); + await expect( + registry.requestCommittee( + request.e3Id, + request.filter, + request.threshold, + ), + ) + .to.emit(registry, "CommitteeRequested") + .withArgs(request.e3Id, request.filter, request.threshold); + }); + it("reverts if filter.requestCommittee() fails", async function () { + const { owner, registry, filter, request } = await loadFixture(setup); + + await filter.setRegistry(owner.address); + await filter.requestCommittee(request.e3Id, request.threshold); + await filter.setRegistry(await registry.getAddress()); + + await expect( + registry.requestCommittee( + request.e3Id, + request.filter, + request.threshold, + ), + ).to.be.revertedWithCustomError(filter, "CommitteeAlreadyExists"); + }); + it("returns true if the request is successful", async function () { + const { registry, request } = await loadFixture(setup); + expect( + await registry.requestCommittee.staticCall( + request.e3Id, + request.filter, + request.threshold, + ), + ).to.be.true; + }); }); describe("publishCommittee()", function () { - it("reverts if the caller is not the filter for the given e3Id"); - it("stores the public key of the committee"); - it("emits a CommitteePublished event"); + it("reverts if the caller is not the filter for the given e3Id", async function () { + const { registry, request } = await loadFixture(setup); + await registry.requestCommittee( + request.e3Id, + request.filter, + request.threshold, + ); + await expect( + registry.publishCommittee(request.e3Id, "0xc0de", "0xda7a"), + ).to.be.revertedWithCustomError(registry, "OnlyFilter"); + }); + it("stores the public key of the committee", async function () { + const { filter, registry, request } = await loadFixture(setup); + await registry.requestCommittee( + request.e3Id, + request.filter, + request.threshold, + ); + await filter.publishCommittee( + request.e3Id, + [AddressOne, AddressTwo], + "0xda7a", + ); + expect(await registry.committeePublicKey(request.e3Id)).to.equal( + "0xda7a", + ); + }); + it("emits a CommitteePublished event", async function () { + const { filter, registry, request } = await loadFixture(setup); + await registry.requestCommittee( + request.e3Id, + request.filter, + request.threshold, + ); + expect( + await filter.publishCommittee( + request.e3Id, + [AddressOne, AddressTwo], + "0xda7a", + ), + ) + .to.emit(registry, "CommitteePublished") + .withArgs(request.e3Id, "0xda7a"); + }); }); describe("addCiphernode()", function () { @@ -147,4 +248,8 @@ describe.only("CiphernodeRegistryOwnable", function () { "returns the root of the ciphernode registry merkle tree at the given e3Id", ); }); + + describe("getFilter()", function () { + it("returns the registry filter for the given e3Id"); + }); }); diff --git a/packages/evm/test/fixtures/NaiveRegistryFilter.fixture.ts b/packages/evm/test/fixtures/NaiveRegistryFilter.fixture.ts index e2004e39..64bc8c1c 100644 --- a/packages/evm/test/fixtures/NaiveRegistryFilter.fixture.ts +++ b/packages/evm/test/fixtures/NaiveRegistryFilter.fixture.ts @@ -14,6 +14,6 @@ export async function naiveRegistryFilterFixture( return NaiveRegistryFilter__factory.connect( await deployment.getAddress(), - signer.provider, + signer, ); } From 29fe84ea88fd941dacda210ec0ea98c4cbe9ac61 Mon Sep 17 00:00:00 2001 From: Auryn Macmillan Date: Wed, 18 Sep 2024 10:41:41 -0400 Subject: [PATCH 75/87] add: unit tests for `addCiphernode()` --- .../CyphernodeRegistryOwnable.spec.ts | 30 ++++++++++++++++--- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/packages/evm/test/CyphernodeRegistry/CyphernodeRegistryOwnable.spec.ts b/packages/evm/test/CyphernodeRegistry/CyphernodeRegistryOwnable.spec.ts index c4b149aa..4f629632 100644 --- a/packages/evm/test/CyphernodeRegistry/CyphernodeRegistryOwnable.spec.ts +++ b/packages/evm/test/CyphernodeRegistry/CyphernodeRegistryOwnable.spec.ts @@ -205,10 +205,32 @@ describe.only("CiphernodeRegistryOwnable", function () { }); describe("addCiphernode()", function () { - it("reverts if the caller is not the owner"); - it("adds the ciphernode to the registry"); - it("increments numCiphernodes"); - it("emits a CiphernodeAdded event"); + it("reverts if the caller is not the owner", async function () { + const { registry, notTheOwner } = await loadFixture(setup); + await expect(registry.connect(notTheOwner).addCiphernode(addressThree)) + .to.be.revertedWithCustomError(registry, "OwnableUnauthorizedAccount") + .withArgs(notTheOwner.address); + }); + it("adds the ciphernode to the registry", async function () { + const { registry } = await loadFixture(setup); + expect(await registry.addCiphernode(addressThree)); + expect(await registry.isCiphernodeEligible(addressThree)).to.be.true; + }); + it("increments numCiphernodes", async function () { + const { registry } = await loadFixture(setup); + const numCiphernodes = await registry.numCiphernodes(); + expect(await registry.addCiphernode(addressThree)); + expect(await registry.numCiphernodes()).to.equal( + numCiphernodes + BigInt(1), + ); + }); + it("emits a CiphernodeAdded event", async function () { + const { registry } = await loadFixture(setup); + const numCiphernodes = await registry.numCiphernodes(); + expect(await registry.addCiphernode(addressThree)) + .to.emit(registry, "CiphernodeAdded") + .withArgs(addressThree, numCiphernodes + BigInt(1)); + }); }); describe("removeCiphernode()", function () { From b45043c42f447cc862a6465caae0962874a45baf Mon Sep 17 00:00:00 2001 From: samepant Date: Wed, 18 Sep 2024 14:41:31 -0400 Subject: [PATCH 76/87] fix request script to use actual mock deployment addresses (#97) --- packages/evm/tasks/enclave.ts | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/packages/evm/tasks/enclave.ts b/packages/evm/tasks/enclave.ts index 7245d189..7e925614 100644 --- a/packages/evm/tasks/enclave.ts +++ b/packages/evm/tasks/enclave.ts @@ -50,13 +50,13 @@ task( .addOptionalParam( "e3Params", "parameters for the E3 program", - "0x0000000000000000000000004965ceCe27422B8B9557f9b9C841581B8Da60B34", + undefined, types.string, ) .addOptionalParam( "computeParams", "parameters for the compute provider", - "0x000000000000000000000000404af1c0780a9269e4d3308a0812fb87bf5fc490", + undefined, types.string, ) .setAction(async function (taskArguments: TaskArguments, hre) { @@ -87,6 +87,30 @@ task( filterAddress = naiveRegistryFilter.address; } + let e3Params = taskArguments.e3Params; + if (!e3Params) { + const MockInputValidator = + await hre.deployments.get("MockInputValidator"); + if (!MockInputValidator) { + throw new Error("MockInputValidator not deployed"); + } + e3Params = hre.ethers.zeroPadValue(MockInputValidator.address, 32); + } + + let computeParams = taskArguments.computeParams; + if (!computeParams) { + const MockDecryptionVerifier = await hre.deployments.get( + "MockDecryptionVerifier", + ); + if (!MockDecryptionVerifier) { + throw new Error("MockDecryptionVerifier not deployed"); + } + computeParams = hre.ethers.zeroPadValue( + MockDecryptionVerifier.address, + 32, + ); + } + try { const enableE3Tx = await enclaveContract.enableE3Program(e3Address); await enableE3Tx.wait(); @@ -100,8 +124,8 @@ task( [taskArguments.windowStart, taskArguments.windowEnd], taskArguments.duration, e3Address, - taskArguments.e3Params, - taskArguments.computeParams, + e3Params, + computeParams, // 1 ETH { value: "1000000000000000000" }, ); From d78b22abfa4636b8c8589643466b025219bd42c3 Mon Sep 17 00:00:00 2001 From: Auryn Macmillan Date: Wed, 18 Sep 2024 21:52:37 -0400 Subject: [PATCH 77/87] add: `removeCiphernode()` unit tests --- .../registry/CiphernodeRegistryOwnable.sol | 12 ++-- .../CyphernodeRegistryOwnable.spec.ts | 63 +++++++++++++++---- 2 files changed, 57 insertions(+), 18 deletions(-) diff --git a/packages/evm/contracts/registry/CiphernodeRegistryOwnable.sol b/packages/evm/contracts/registry/CiphernodeRegistryOwnable.sol index f01730f9..8997f690 100644 --- a/packages/evm/contracts/registry/CiphernodeRegistryOwnable.sol +++ b/packages/evm/contracts/registry/CiphernodeRegistryOwnable.sol @@ -120,15 +120,9 @@ contract CiphernodeRegistryOwnable is ICiphernodeRegistry, OwnableUpgradeable { uint256[] calldata siblingNodes ) external onlyOwner { uint160 ciphernode = uint160(node); - ciphernodes._remove(ciphernode, siblingNodes); uint256 index = ciphernodes._indexOf(ciphernode); + ciphernodes._remove(ciphernode, siblingNodes); numCiphernodes--; - emit CiphernodeAdded( - node, - ciphernodes._indexOf(ciphernode), - numCiphernodes, - ciphernodes.size - ); emit CiphernodeRemoved(node, index, numCiphernodes, ciphernodes.size); } @@ -175,4 +169,8 @@ contract CiphernodeRegistryOwnable is ICiphernodeRegistry, OwnableUpgradeable { function getFilter(uint256 e3Id) public view returns (IRegistryFilter) { return filters[e3Id]; } + + function treeSize() public view returns (uint256) { + return ciphernodes.size; + } } diff --git a/packages/evm/test/CyphernodeRegistry/CyphernodeRegistryOwnable.spec.ts b/packages/evm/test/CyphernodeRegistry/CyphernodeRegistryOwnable.spec.ts index 4f629632..38904e02 100644 --- a/packages/evm/test/CyphernodeRegistry/CyphernodeRegistryOwnable.spec.ts +++ b/packages/evm/test/CyphernodeRegistry/CyphernodeRegistryOwnable.spec.ts @@ -16,7 +16,7 @@ import { PoseidonT3Fixture } from "../fixtures/PoseidonT3.fixture"; const abiCoder = ethers.AbiCoder.defaultAbiCoder(); const AddressOne = "0x0000000000000000000000000000000000000001"; const AddressTwo = "0x0000000000000000000000000000000000000002"; -const addressThree = "0x0000000000000000000000000000000000000003"; +const AddressThree = "0x0000000000000000000000000000000000000003"; // Hash function used to compute the tree nodes. const hash = (a: bigint, b: bigint) => poseidon2([a, b]); @@ -35,14 +35,19 @@ describe.only("CiphernodeRegistryOwnable", function () { owner.address, await registry.getAddress(), ); + + const tree = new LeanIMT(hash); await registry.addCiphernode(AddressOne); + tree.insert(BigInt(AddressOne)); await registry.addCiphernode(AddressTwo); + tree.insert(BigInt(AddressTwo)); return { owner, notTheOwner, registry, filter, + tree, request: { e3Id: 1, filter: await filter.getAddress(), @@ -207,19 +212,19 @@ describe.only("CiphernodeRegistryOwnable", function () { describe("addCiphernode()", function () { it("reverts if the caller is not the owner", async function () { const { registry, notTheOwner } = await loadFixture(setup); - await expect(registry.connect(notTheOwner).addCiphernode(addressThree)) + await expect(registry.connect(notTheOwner).addCiphernode(AddressThree)) .to.be.revertedWithCustomError(registry, "OwnableUnauthorizedAccount") .withArgs(notTheOwner.address); }); it("adds the ciphernode to the registry", async function () { const { registry } = await loadFixture(setup); - expect(await registry.addCiphernode(addressThree)); - expect(await registry.isCiphernodeEligible(addressThree)).to.be.true; + expect(await registry.addCiphernode(AddressThree)); + expect(await registry.isCiphernodeEligible(AddressThree)).to.be.true; }); it("increments numCiphernodes", async function () { const { registry } = await loadFixture(setup); const numCiphernodes = await registry.numCiphernodes(); - expect(await registry.addCiphernode(addressThree)); + expect(await registry.addCiphernode(AddressThree)); expect(await registry.numCiphernodes()).to.equal( numCiphernodes + BigInt(1), ); @@ -227,17 +232,49 @@ describe.only("CiphernodeRegistryOwnable", function () { it("emits a CiphernodeAdded event", async function () { const { registry } = await loadFixture(setup); const numCiphernodes = await registry.numCiphernodes(); - expect(await registry.addCiphernode(addressThree)) + expect(await registry.addCiphernode(AddressThree)) .to.emit(registry, "CiphernodeAdded") - .withArgs(addressThree, numCiphernodes + BigInt(1)); + .withArgs(AddressThree, numCiphernodes + BigInt(1)); }); }); describe("removeCiphernode()", function () { - it("reverts if the caller is not the owner"); - it("removes the ciphernode from the registry"); - it("decrements numCiphernodes"); - it("emits a CiphernodeRemoved event"); + it("reverts if the caller is not the owner", async function () { + const { registry, notTheOwner } = await loadFixture(setup); + await expect( + registry.connect(notTheOwner).removeCiphernode(AddressOne, []), + ) + .to.be.revertedWithCustomError(registry, "OwnableUnauthorizedAccount") + .withArgs(notTheOwner.address); + }); + it("removes the ciphernode from the registry", async function () { + const { registry, tree } = await loadFixture(setup); + const index = tree.indexOf(BigInt(AddressOne)); + const proof = tree.generateProof(index); + expect(await registry.isEnabled(AddressOne)).to.be.true; + expect(await registry.removeCiphernode(AddressOne, proof.siblings)); + expect(await registry.isEnabled(AddressOne)).to.be.false; + }); + it("decrements numCiphernodes", async function () { + const { registry, tree } = await loadFixture(setup); + const numCiphernodes = await registry.numCiphernodes(); + const index = tree.indexOf(BigInt(AddressOne)); + const proof = tree.generateProof(index); + expect(await registry.removeCiphernode(AddressOne, proof.siblings)); + expect(await registry.numCiphernodes()).to.equal( + numCiphernodes - BigInt(1), + ); + }); + it("emits a CiphernodeRemoved event", async function () { + const { registry, tree } = await loadFixture(setup); + const numCiphernodes = await registry.numCiphernodes(); + const size = await registry.treeSize(); + const index = tree.indexOf(BigInt(AddressOne)); + const proof = tree.generateProof(index); + await expect(registry.removeCiphernode(AddressOne, proof.siblings)) + .to.emit(registry, "CiphernodeRemoved") + .withArgs(AddressOne, index, numCiphernodes - BigInt(1), size); + }); }); describe("setEnclave()", function () { @@ -274,4 +311,8 @@ describe.only("CiphernodeRegistryOwnable", function () { describe("getFilter()", function () { it("returns the registry filter for the given e3Id"); }); + + describe("treeSize()", function () { + it("returns the size of the ciphernode registry merkle tree"); + }); }); From 8365531079e9ef224d977727d1cdb4e724effc5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=B3=CE=BB?= Date: Thu, 19 Sep 2024 11:59:01 +1000 Subject: [PATCH 78/87] Remove Orchestrators (#98) --- packages/ciphernode/core/src/ciphernode.rs | 42 ++-- .../core/src/ciphernode_orchestrator.rs | 93 -------- .../ciphernode/core/src/committee_meta.rs | 26 +++ packages/ciphernode/core/src/e3_request.rs | 145 ++++++++++++ packages/ciphernode/core/src/fhe.rs | 27 +++ packages/ciphernode/core/src/lib.rs | 45 ++-- .../ciphernode/core/src/main_aggregator.rs | 25 +- .../ciphernode/core/src/main_ciphernode.rs | 29 ++- packages/ciphernode/core/src/orchestrator.rs | 216 ------------------ .../core/src/plaintext_aggregator.rs | 33 ++- .../core/src/plaintext_orchestrator.rs | 101 -------- .../core/src/publickey_aggregator.rs | 33 ++- .../core/src/publickey_orchestrator.rs | 102 --------- 13 files changed, 332 insertions(+), 585 deletions(-) delete mode 100644 packages/ciphernode/core/src/ciphernode_orchestrator.rs create mode 100644 packages/ciphernode/core/src/committee_meta.rs create mode 100644 packages/ciphernode/core/src/e3_request.rs delete mode 100644 packages/ciphernode/core/src/orchestrator.rs delete mode 100644 packages/ciphernode/core/src/plaintext_orchestrator.rs delete mode 100644 packages/ciphernode/core/src/publickey_orchestrator.rs diff --git a/packages/ciphernode/core/src/ciphernode.rs b/packages/ciphernode/core/src/ciphernode.rs index 7bd4f271..8bf0e9c5 100644 --- a/packages/ciphernode/core/src/ciphernode.rs +++ b/packages/ciphernode/core/src/ciphernode.rs @@ -3,8 +3,8 @@ use crate::{ eventbus::EventBus, events::{EnclaveEvent, KeyshareCreated}, fhe::{Fhe, GenerateKeyshare}, - CiphernodeSelected, CiphertextOutputPublished, DecryptCiphertext, DecryptionshareCreated, Get, - Subscribe, + ActorFactory, CiphernodeSelected, CiphertextOutputPublished, DecryptCiphertext, + DecryptionshareCreated, Get, }; use actix::prelude::*; use alloy_primitives::Address; @@ -30,25 +30,6 @@ impl Ciphernode { address, } } - - pub async fn attach( - bus: Addr, - fhe: Addr, - data: Addr, - address: Address, - ) -> Addr { - let node = Ciphernode::new(bus.clone(), fhe, data, address).start(); - let _ = bus - .send(Subscribe::new("CiphernodeSelected", node.clone().into())) - .await; - let _ = bus - .send(Subscribe::new( - "CiphertextOutputPublished", - node.clone().into(), - )) - .await; - node - } } impl Handler for Ciphernode { @@ -167,3 +148,22 @@ async fn on_decryption_requested( Ok(()) } + +pub struct CiphernodeFactory; +impl CiphernodeFactory { + pub fn create(bus: Addr, data: Addr, address: Address) -> ActorFactory { + Box::new(move |ctx, evt| { + // Save Ciphernode on CiphernodeSelected + let EnclaveEvent::CiphernodeSelected { .. } = evt else { + return; + }; + + let Some(ref fhe) = ctx.fhe else { + return; + }; + + ctx.ciphernode = + Some(Ciphernode::new(bus.clone(), fhe.clone(), data.clone(), address).start()) + }) + } +} diff --git a/packages/ciphernode/core/src/ciphernode_orchestrator.rs b/packages/ciphernode/core/src/ciphernode_orchestrator.rs deleted file mode 100644 index 4fc80a99..00000000 --- a/packages/ciphernode/core/src/ciphernode_orchestrator.rs +++ /dev/null @@ -1,93 +0,0 @@ -// TODO: spawn and supervise child actors -use crate::{Ciphernode, Data, E3id, EnclaveEvent, EventBus, Fhe, InitializeWithEnclaveEvent}; -use actix::prelude::*; -use alloy_primitives::Address; -use std::collections::HashMap; - -pub struct CiphernodeOrchestrator { - bus: Addr, - data: Addr, - address: Address, - ciphernodes: HashMap>, - buffers: HashMap>, -} - -impl CiphernodeOrchestrator { - pub fn new(bus: Addr, data: Addr, address: Address) -> Self { - Self { - bus, - data, - address, - ciphernodes: HashMap::new(), - buffers: HashMap::new(), - } - } - - pub fn attach(bus: Addr, data: Addr, address: Address) -> Addr { - CiphernodeOrchestrator::new(bus, data, address).start() - } -} - -impl Actor for CiphernodeOrchestrator { - type Context = Context; -} - -impl Handler for CiphernodeOrchestrator { - type Result = (); - fn handle(&mut self, msg: InitializeWithEnclaveEvent, _: &mut Self::Context) -> Self::Result { - let InitializeWithEnclaveEvent { fhe, event, .. } = msg; - let EnclaveEvent::CiphernodeSelected { data, .. } = event else { - return; - }; - let ciphernode_factory = self.ciphernode_factory(fhe.clone()); - self.ciphernodes - .entry(data.e3_id.clone()) - .or_insert_with(ciphernode_factory); - } -} - -impl Handler for CiphernodeOrchestrator { - type Result = (); - - fn handle(&mut self, msg: EnclaveEvent, _ctx: &mut Self::Context) -> Self::Result { - let Some(e3_id) = msg.get_e3_id() else { - return; - }; - - self.forward_message(&e3_id, msg); - } -} - -impl CiphernodeOrchestrator { - fn ciphernode_factory(&self, fhe: Addr) -> impl FnOnce() -> Addr { - let data = self.data.clone(); - let bus = self.bus.clone(); - let address = self.address; - move || Ciphernode::new(bus, fhe, data, address).start() - } - - fn store_msg(&mut self, e3_id: E3id, msg: EnclaveEvent) { - self.buffers.entry(e3_id).or_default().push(msg); - } - - fn take_msgs(&mut self, e3_id: E3id) -> Vec { - self.buffers - .get_mut(&e3_id) - .map(std::mem::take) - .unwrap_or_default() - } - - fn forward_message(&mut self, e3_id: &E3id, msg: EnclaveEvent) { - // Buffer events for each thing that has not been created - if let Some(act) = self.ciphernodes.clone().get(e3_id) { - let msgs = self.take_msgs(e3_id.clone()); - let recipient = act.clone().recipient(); - recipient.do_send(msg.clone()); - for m in msgs { - recipient.do_send(m); - } - } else { - self.store_msg(e3_id.clone(), msg.clone()); - } - } -} diff --git a/packages/ciphernode/core/src/committee_meta.rs b/packages/ciphernode/core/src/committee_meta.rs new file mode 100644 index 00000000..78be9141 --- /dev/null +++ b/packages/ciphernode/core/src/committee_meta.rs @@ -0,0 +1,26 @@ +use crate::{ActorFactory, CommitteeRequested, EnclaveEvent}; + +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct CommitteeMeta { + pub nodecount: usize, + pub seed: u64, +} + +pub struct CommitteeMetaFactory; + +impl CommitteeMetaFactory { + pub fn create() -> ActorFactory { + Box::new(move |ctx, evt| { + let EnclaveEvent::CommitteeRequested { data, .. }: crate::EnclaveEvent = evt else { + return; + }; + let CommitteeRequested { + nodecount, + sortition_seed: seed, + .. + } = data; + + ctx.meta = Some(CommitteeMeta { nodecount, seed }); + }) + } +} diff --git a/packages/ciphernode/core/src/e3_request.rs b/packages/ciphernode/core/src/e3_request.rs new file mode 100644 index 00000000..32de3914 --- /dev/null +++ b/packages/ciphernode/core/src/e3_request.rs @@ -0,0 +1,145 @@ +use std::collections::HashMap; + +use actix::{Actor, Addr, Context, Handler, Recipient}; + +use crate::{ + Ciphernode, CommitteeMeta, E3id, EnclaveEvent, EventBus, Fhe, PlaintextAggregator, + PublicKeyAggregator, Subscribe, +}; + +#[derive(Default)] +// TODO: Set this up with a Typestate pattern +pub struct E3RequestContext { + pub ciphernode: Option>, + pub fhe: Option>, + pub plaintext: Option>, + pub publickey: Option>, + pub meta: Option, +} + +struct EventBuffer { + buffer: HashMap>, +} + +impl Default for EventBuffer { + fn default() -> Self { + Self { + buffer: HashMap::new(), + } + } +} + +impl EventBuffer { + pub fn add(&mut self, key: &str, event: EnclaveEvent) { + self.buffer.entry(key.to_string()).or_default().push(event) + } + + pub fn take(&mut self, key: &str) -> Vec { + self.buffer + .get_mut(key) + .map(std::mem::take) + .unwrap_or_default() + } +} + +impl E3RequestContext { + fn recipients(&self) -> Vec<(String, Option>)> { + vec![ + ( + "ciphernode".to_owned(), + self.ciphernode.clone().map(|addr| addr.into()), + ), + ( + "plaintext".to_owned(), + self.plaintext.clone().map(|addr| addr.into()), + ), + ( + "publickey".to_owned(), + self.publickey.clone().map(|addr| addr.into()), + ), + ] + } + + fn forward_message(&self, msg: &EnclaveEvent, buffer: &mut EventBuffer) { + self.recipients().into_iter().for_each(|(key, recipient)| { + if let Some(act) = recipient { + act.do_send(msg.clone()); + for m in buffer.take(&key) { + act.do_send(m); + } + } else { + buffer.add(&key, msg.clone()); + } + }); + } +} + +struct E3RequestBuffers { + ciphernode: Vec, + publickey: Vec, + plaintext: Vec, +} + +pub type ActorFactory = Box; + +// TODO: setup typestate pattern so that we have to place factories within correct order of +// dependencies +pub struct E3RequestManager { + contexts: HashMap, + factories: Vec, + buffer: EventBuffer, +} + +impl E3RequestManager { + pub fn builder(bus: Addr) -> E3RequestManagerBuilder { + E3RequestManagerBuilder { + bus, + factories: vec![], + } + } +} + +pub struct E3RequestManagerBuilder { + pub bus: Addr, + pub factories: Vec, +} +impl E3RequestManagerBuilder { + pub fn add_hook(mut self, listener: ActorFactory) -> Self { + self.factories.push(listener); + self + } + + pub fn build(self) -> Addr { + let e3r = E3RequestManager { + contexts: HashMap::new(), + factories: self.factories, + buffer: EventBuffer::default(), + }; + + let addr = e3r.start(); + self.bus + .do_send(Subscribe::new("*", addr.clone().recipient())); + addr + } +} + +impl Actor for E3RequestManager { + type Context = Context; +} + +impl Handler for E3RequestManager { + type Result = (); + fn handle(&mut self, msg: EnclaveEvent, _: &mut Self::Context) -> Self::Result { + let Some(e3_id) = msg.get_e3_id() else { + return; + }; + + let context = self.contexts.entry(e3_id).or_default(); + + for factory in &mut self.factories { + factory(context, msg.clone()); + } + + context.forward_message(&msg, &mut self.buffer); + } +} diff --git a/packages/ciphernode/core/src/fhe.rs b/packages/ciphernode/core/src/fhe.rs index 544594de..f3394c18 100644 --- a/packages/ciphernode/core/src/fhe.rs +++ b/packages/ciphernode/core/src/fhe.rs @@ -4,6 +4,7 @@ use crate::{ CiphertextSerializer, DecryptionShareSerializer, PublicKeySerializer, PublicKeyShareSerializer, SecretKeySerializer, }, + ActorFactory, CommitteeRequested, EnclaveEvent, }; use actix::{Actor, Context, Handler, Message}; use anyhow::*; @@ -182,3 +183,29 @@ impl Handler for Fhe { Ok(bincode::serialize(&decoded)?) } } + +pub struct FheFactory; + +impl FheFactory { + pub fn create(rng: Arc>) -> ActorFactory { + Box::new(move |ctx, evt| { + // Saving the fhe on Committee Requested + let EnclaveEvent::CommitteeRequested { data, .. } = evt else { + return; + }; + let CommitteeRequested { + degree, + moduli, + plaintext_modulus, + crp, + .. + } = data; + + ctx.fhe = Some( + Fhe::from_raw_params(&moduli, degree, plaintext_modulus, &crp, rng.clone()) + .unwrap() + .start(), + ); + }) + } +} diff --git a/packages/ciphernode/core/src/lib.rs b/packages/ciphernode/core/src/lib.rs index f437dec9..3131e409 100644 --- a/packages/ciphernode/core/src/lib.rs +++ b/packages/ciphernode/core/src/lib.rs @@ -3,9 +3,10 @@ // #![warn(missing_docs, unused_imports)] mod ciphernode; -mod ciphernode_orchestrator; mod ciphernode_selector; +mod committee_meta; mod data; +mod e3_request; mod enclave_contract; mod eventbus; pub mod events; @@ -16,13 +17,10 @@ mod fhe; mod logger; mod main_aggregator; mod main_ciphernode; -mod orchestrator; mod ordered_set; mod p2p; mod plaintext_aggregator; -mod plaintext_orchestrator; mod publickey_aggregator; -mod publickey_orchestrator; mod serializers; mod sortition; mod utils; @@ -30,24 +28,23 @@ mod utils; // TODO: this is too permissive pub use actix::prelude::*; pub use ciphernode::*; -pub use ciphernode_orchestrator::*; pub use ciphernode_selector::*; +pub use committee_meta::*; pub use data::*; +pub use e3_request::*; pub use eventbus::*; pub use events::*; -pub use serializers::*; pub use fhe::*; pub use logger::*; pub use main_aggregator::*; pub use main_ciphernode::*; -pub use orchestrator::*; pub use p2p::*; pub use plaintext_aggregator::*; -pub use plaintext_orchestrator::*; pub use publickey_aggregator::*; -pub use publickey_orchestrator::*; +pub use serializers::*; pub use sortition::*; pub use utils::*; + // TODO: move these out to a test folder #[cfg(test)] mod tests { @@ -57,14 +54,12 @@ mod tests { eventbus::{EventBus, GetHistory}, events::{CommitteeRequested, E3id, EnclaveEvent, KeyshareCreated, PublicKeyAggregated}, p2p::P2p, - serializers::{ - CiphertextSerializer, DecryptionShareSerializer, PublicKeySerializer, - PublicKeyShareSerializer, - }, + serializers::{CiphertextSerializer, DecryptionShareSerializer, PublicKeyShareSerializer}, utils::{setup_crp_params, ParamsWithCrp}, - CiphernodeAdded, CiphernodeOrchestrator, CiphernodeSelected, CiphertextOutputPublished, - DecryptionshareCreated, Orchestrator, PlaintextAggregated, PlaintextOrchestrator, - PublicKeyOrchestrator, ResetHistory, SharedRng, Sortition, + CiphernodeAdded, CiphernodeFactory, CiphernodeSelected, CiphertextOutputPublished, + CommitteeMetaFactory, DecryptionshareCreated, E3RequestManager, FheFactory, + PlaintextAggregated, PlaintextAggregatorFactory, PublicKeyAggregatorFactory, ResetHistory, + SharedRng, Sortition, }; use actix::prelude::*; use alloy_primitives::Address; @@ -94,18 +89,24 @@ mod tests { // create ciphernode actor for managing ciphernode flow let sortition = Sortition::attach(bus.clone()); CiphernodeSelector::attach(bus.clone(), sortition.clone(), addr); - Orchestrator::builder(bus.clone(), rng) - .public_key(PublicKeyOrchestrator::attach( + + E3RequestManager::builder(bus.clone()) + .add_hook(CommitteeMetaFactory::create()) + .add_hook(FheFactory::create(rng.clone())) + .add_hook(PublicKeyAggregatorFactory::create( bus.clone(), sortition.clone(), )) - .plaintext(PlaintextOrchestrator::attach( + .add_hook(PlaintextAggregatorFactory::create( bus.clone(), sortition.clone(), )) - .ciphernode(CiphernodeOrchestrator::attach(bus.clone(), data, addr)) - .build() - .await; + .add_hook(CiphernodeFactory::create( + bus.clone(), + data.clone(), + addr, + )) + .build(); } fn generate_pk_share( diff --git a/packages/ciphernode/core/src/main_aggregator.rs b/packages/ciphernode/core/src/main_aggregator.rs index c6076f7b..faf4ecb8 100644 --- a/packages/ciphernode/core/src/main_aggregator.rs +++ b/packages/ciphernode/core/src/main_aggregator.rs @@ -1,8 +1,8 @@ use std::sync::{Arc, Mutex}; use crate::{ - EventBus, Orchestrator, P2p, PlaintextOrchestrator, PublicKeyOrchestrator, SimpleLogger, - Sortition, + committee_meta::CommitteeMetaFactory, E3RequestManager, EventBus, FheFactory, P2p, + PlaintextAggregatorFactory, PublicKeyAggregatorFactory, SimpleLogger, Sortition, }; use actix::{Actor, Addr, Context}; use rand::SeedableRng; @@ -13,9 +13,9 @@ use tokio::task::JoinHandle; /// Suprvises all children // TODO: add supervision logic pub struct MainAggregator { + e3_manager: Addr, bus: Addr, sortition: Addr, - orchestrator: Addr, p2p: Addr, } @@ -23,13 +23,13 @@ impl MainAggregator { pub fn new( bus: Addr, sortition: Addr, - orchestrator: Addr, p2p: Addr, + e3_manager: Addr, ) -> Self { Self { + e3_manager, bus, sortition, - orchestrator, p2p, } } @@ -40,23 +40,26 @@ impl MainAggregator { )); let bus = EventBus::new(true).start(); let sortition = Sortition::attach(bus.clone()); - let orchestrator = Orchestrator::builder(bus.clone(), rng) - .public_key(PublicKeyOrchestrator::attach( + + let e3_manager = E3RequestManager::builder(bus.clone()) + .add_hook(CommitteeMetaFactory::create()) + .add_hook(FheFactory::create(rng.clone())) + .add_hook(PublicKeyAggregatorFactory::create( bus.clone(), sortition.clone(), )) - .plaintext(PlaintextOrchestrator::attach( + .add_hook(PlaintextAggregatorFactory::create( bus.clone(), sortition.clone(), )) - .build() - .await; + .build(); + let (p2p_addr, join_handle) = P2p::spawn_libp2p(bus.clone()).expect("Failed to setup libp2p"); SimpleLogger::attach("AGGREGATOR", bus.clone()); - let main_addr = MainAggregator::new(bus, sortition, orchestrator, p2p_addr).start(); + let main_addr = MainAggregator::new(bus, sortition, p2p_addr, e3_manager).start(); (main_addr, join_handle) } } diff --git a/packages/ciphernode/core/src/main_ciphernode.rs b/packages/ciphernode/core/src/main_ciphernode.rs index a7241e62..94af2618 100644 --- a/packages/ciphernode/core/src/main_ciphernode.rs +++ b/packages/ciphernode/core/src/main_ciphernode.rs @@ -1,7 +1,9 @@ use std::sync::{Arc, Mutex}; use crate::{ - CiphernodeOrchestrator, CiphernodeSelector, Data, EventBus, Orchestrator, P2p, SimpleLogger, Sortition + CiphernodeFactory, CiphernodeSelector, CommitteeMetaFactory, Data, E3RequestManager, EventBus, + FheFactory, P2p, PlaintextAggregatorFactory, PublicKeyAggregatorFactory, SimpleLogger, + Sortition, }; use actix::{Actor, Addr, Context}; use alloy_primitives::Address; @@ -18,7 +20,7 @@ pub struct MainCiphernode { data: Addr, sortition: Addr, selector: Addr, - orchestrator: Addr, + e3_manager: Addr, p2p: Addr, } @@ -29,8 +31,8 @@ impl MainCiphernode { data: Addr, sortition: Addr, selector: Addr, - orchestrator: Addr, p2p: Addr, + e3_manager: Addr, ) -> Self { Self { addr, @@ -38,7 +40,7 @@ impl MainCiphernode { data, sortition, selector, - orchestrator, + e3_manager, p2p, } } @@ -56,27 +58,22 @@ impl MainCiphernode { let sortition = Sortition::attach(bus.clone()); let selector = CiphernodeSelector::attach(bus.clone(), sortition.clone(), address); - let orchestrator = Orchestrator::builder(bus.clone(), rng) - .ciphernode(CiphernodeOrchestrator::attach( + let e3_manager = E3RequestManager::builder(bus.clone()) + .add_hook(CommitteeMetaFactory::create()) + .add_hook(FheFactory::create(rng.clone())) + .add_hook(CiphernodeFactory::create( bus.clone(), data.clone(), address, )) - .build() - .await; + .build(); let (p2p_addr, join_handle) = P2p::spawn_libp2p(bus.clone()).expect("Failed to setup libp2p"); - SimpleLogger::attach("CIPHERNODE",bus.clone()); + SimpleLogger::attach("CIPHERNODE", bus.clone()); let main_addr = MainCiphernode::new( - address, - bus, - data, - sortition, - selector, - orchestrator, - p2p_addr, + address, bus, data, sortition, selector, p2p_addr, e3_manager, ) .start(); (main_addr, join_handle) diff --git a/packages/ciphernode/core/src/orchestrator.rs b/packages/ciphernode/core/src/orchestrator.rs deleted file mode 100644 index a542c527..00000000 --- a/packages/ciphernode/core/src/orchestrator.rs +++ /dev/null @@ -1,216 +0,0 @@ -// TODO: spawn and supervise child actors -use crate::{ - CiphernodeOrchestrator, CommitteeRequested, E3id, EnclaveEvent, EventBus, Fhe, - PlaintextOrchestrator, PublicKeyOrchestrator, Subscribe, -}; -use actix::prelude::*; -use rand_chacha::ChaCha20Rng; -use std::{ - collections::HashMap, - sync::{Arc, Mutex}, -}; - -#[derive(Message, Clone, Debug, PartialEq, Eq)] -#[rtype(result = "()")] -pub struct InitializeWithEnclaveEvent { - pub fhe: Addr, - pub meta: CommitteeMeta, - pub event: EnclaveEvent, -} - -impl InitializeWithEnclaveEvent { - pub fn new(fhe: Addr, meta: CommitteeMeta, event: EnclaveEvent) -> Self { - Self { fhe, meta, event } - } -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct CommitteeMeta { - pub nodecount: usize, - pub seed: u64, -} - -pub struct OrchestratorBuilder { - bus: Addr, - rng: Arc>, - public_key: Option>, - plaintext: Option>, - ciphernode: Option>, -} - -impl OrchestratorBuilder { - pub fn new(bus: Addr, rng: Arc>) -> Self { - Self { - bus, - rng, - public_key: None, - plaintext: None, - ciphernode: None, - } - } - - pub fn public_key(mut self, value: Addr) -> Self { - self.public_key = Some(value); - self - } - - pub fn plaintext(mut self, value: Addr) -> Self { - self.plaintext = Some(value); - self - } - - pub fn ciphernode(mut self, value: Addr) -> Self { - self.ciphernode = Some(value); - self - } - - pub async fn build(self) -> Addr { - let bus = self.bus; - let rng = self.rng; - let public_key = self.public_key; - let plaintext = self.plaintext; - let ciphernode = self.ciphernode; - Orchestrator::attach(bus, rng, public_key, plaintext, ciphernode).await - } -} - -pub struct Orchestrator { - fhes: HashMap>, - meta: HashMap, - public_key: Option>, - plaintext: Option>, - ciphernode: Option>, - rng: Arc>, -} - -impl Orchestrator { - pub fn builder(bus: Addr, rng: Arc>) -> OrchestratorBuilder { - OrchestratorBuilder::new(bus, rng) - } - - async fn attach( - bus: Addr, - rng: Arc>, - public_key: Option>, - plaintext: Option>, - ciphernode: Option>, - ) -> Addr { - let addr = Orchestrator { - rng, - public_key, - plaintext, - ciphernode, - meta: HashMap::new(), - fhes: HashMap::new(), - } - .start(); - bus.send(Subscribe::new("*", addr.clone().into())) - .await - .unwrap(); - addr - } -} - -impl Actor for Orchestrator { - type Context = Context; -} - -impl Handler for Orchestrator { - type Result = (); - - fn handle(&mut self, msg: EnclaveEvent, _ctx: &mut Self::Context) -> Self::Result { - let Some(e3_id) = msg.get_e3_id() else { - return; - }; - - { - match msg.clone() { - EnclaveEvent::CommitteeRequested { data, .. } => { - let CommitteeRequested { - degree, - moduli, - plaintext_modulus, - crp, - .. - } = data; - - let fhe_factory = self.fhe_factory(moduli, degree, plaintext_modulus, crp); - let fhe = self.fhes.entry(e3_id.clone()).or_insert_with(fhe_factory); - let meta = CommitteeMeta { - nodecount: data.nodecount, - seed: data.sortition_seed, - }; - self.meta.entry(e3_id.clone()).or_insert(meta.clone()); - - if let Some(addr) = self.public_key.clone() { - addr.do_send(InitializeWithEnclaveEvent { - event: msg.clone(), - fhe: fhe.clone(), - meta: meta.clone(), - }); - } - } - EnclaveEvent::CiphernodeSelected { data, .. } => { - if let Some(addr) = self.ciphernode.clone() { - if let Some(fhe) = self.fhes.get(&data.e3_id) { - if let Some(meta) = self.meta.get(&data.e3_id) { - addr.do_send(InitializeWithEnclaveEvent { - event: msg.clone(), - fhe: fhe.clone(), - meta: meta.clone(), - }); - } - } - } - } - EnclaveEvent::CiphertextOutputPublished { data, .. } => { - if let Some(plaintext) = self.plaintext.clone() { - if let Some(fhe) = self.fhes.get(&data.e3_id) { - if let Some(meta) = self.meta.get(&data.e3_id) { - plaintext.do_send(InitializeWithEnclaveEvent { - event: msg.clone(), - fhe: fhe.clone(), - meta: meta.clone(), - }); - }; - }; - }; - } - _ => (), - }; - }; - - self.forward_message(msg); - } -} - -impl Orchestrator { - fn fhe_factory( - &self, - moduli: Vec, - degree: usize, - plaintext_modulus: u64, - crp: Vec, - ) -> impl FnOnce() -> Addr { - let rng = self.rng.clone(); - move || { - Fhe::from_raw_params(&moduli, degree, plaintext_modulus, &crp, rng) - .unwrap() - .start() - } - } - - fn forward_message(&mut self, msg: EnclaveEvent) { - if let Some(addr) = self.ciphernode.clone() { - addr.do_send(msg.clone()) - } - - if let Some(addr) = self.public_key.clone() { - addr.do_send(msg.clone()) - } - - if let Some(addr) = self.plaintext.clone() { - addr.do_send(msg.clone()) - } - } -} diff --git a/packages/ciphernode/core/src/plaintext_aggregator.rs b/packages/ciphernode/core/src/plaintext_aggregator.rs index 75c7c2ec..618e2088 100644 --- a/packages/ciphernode/core/src/plaintext_aggregator.rs +++ b/packages/ciphernode/core/src/plaintext_aggregator.rs @@ -1,6 +1,6 @@ use crate::{ - ordered_set::OrderedSet, DecryptionshareCreated, E3id, EnclaveEvent, EventBus, Fhe, - GetAggregatePlaintext, GetHasNode, PlaintextAggregated, Sortition, + ordered_set::OrderedSet, ActorFactory, DecryptionshareCreated, E3id, EnclaveEvent, EventBus, + Fhe, GetAggregatePlaintext, GetHasNode, PlaintextAggregated, Sortition, }; use actix::prelude::*; use anyhow::{anyhow, Result}; @@ -178,3 +178,32 @@ impl Handler for PlaintextAggregator { ) } } + +pub struct PlaintextAggregatorFactory; +impl PlaintextAggregatorFactory { + pub fn create(bus: Addr, sortition: Addr) -> ActorFactory { + Box::new(move |ctx, evt| { + // Save plaintext aggregator + let EnclaveEvent::CiphertextOutputPublished { data, .. } = evt else { + return; + }; + let Some(ref fhe) = ctx.fhe else { + return; + }; + let Some(ref meta) = ctx.meta else { + return; + }; + ctx.plaintext = Some( + PlaintextAggregator::new( + fhe.clone(), + bus.clone(), + sortition.clone(), + data.e3_id, + meta.nodecount, + meta.seed, + ) + .start(), + ); + }) + } +} diff --git a/packages/ciphernode/core/src/plaintext_orchestrator.rs b/packages/ciphernode/core/src/plaintext_orchestrator.rs deleted file mode 100644 index db8d48a5..00000000 --- a/packages/ciphernode/core/src/plaintext_orchestrator.rs +++ /dev/null @@ -1,101 +0,0 @@ -// TODO: spawn and supervise child actors -use crate::{ - CommitteeMeta, E3id, EnclaveEvent, EventBus, Fhe, InitializeWithEnclaveEvent, - PlaintextAggregator, Sortition, -}; -use actix::prelude::*; -use std::collections::HashMap; - -pub struct PlaintextOrchestrator { - bus: Addr, - sortition: Addr, - buffers: HashMap>, - plaintexts: HashMap>, -} - -impl PlaintextOrchestrator { - pub fn new(bus: Addr, sortition: Addr) -> Self { - Self { - bus, - sortition, - plaintexts: HashMap::new(), - buffers: HashMap::new(), - } - } - - pub fn attach(bus: Addr, sortition: Addr) -> Addr { - PlaintextOrchestrator::new(bus.clone(), sortition).start() - } -} - -impl Actor for PlaintextOrchestrator { - type Context = Context; -} - -impl Handler for PlaintextOrchestrator { - type Result = (); - fn handle(&mut self, msg: InitializeWithEnclaveEvent, _: &mut Self::Context) -> Self::Result { - let InitializeWithEnclaveEvent { fhe, meta, event } = msg; - let EnclaveEvent::CiphertextOutputPublished { data, .. } = event else { - return; - }; - - let plaintext_factory = - self.plaintext_factory(data.e3_id.clone(), meta.clone(), fhe.clone()); - - self.plaintexts - .entry(data.e3_id) - .or_insert_with(plaintext_factory); - } -} - -impl Handler for PlaintextOrchestrator { - type Result = (); - - fn handle(&mut self, msg: EnclaveEvent, _ctx: &mut Self::Context) -> Self::Result { - let Some(e3_id) = msg.get_e3_id() else { - return; - }; - self.forward_message(&e3_id, msg); - } -} - -impl PlaintextOrchestrator { - fn plaintext_factory( - &self, - e3_id: E3id, - meta: CommitteeMeta, - fhe: Addr, - ) -> impl FnOnce() -> Addr { - let bus = self.bus.clone(); - let sortition = self.sortition.clone(); - let nodecount = meta.nodecount; - let seed = meta.seed; - move || PlaintextAggregator::new(fhe, bus, sortition, e3_id, nodecount, seed).start() - } - - fn store_msg(&mut self, e3_id: E3id, msg: EnclaveEvent) { - self.buffers.entry(e3_id).or_default().push(msg); - } - - fn take_msgs(&mut self, e3_id: E3id) -> Vec { - self.buffers - .get_mut(&e3_id) - .map(std::mem::take) - .unwrap_or_default() - } - - fn forward_message(&mut self, e3_id: &E3id, msg: EnclaveEvent) { - // Buffer events for each thing that has not been created - if let Some(act) = self.plaintexts.clone().get(e3_id) { - let msgs = self.take_msgs(e3_id.clone()); - let recipient = act.clone().recipient(); - recipient.do_send(msg.clone()); - for m in msgs { - recipient.do_send(m); - } - } else { - self.store_msg(e3_id.clone(), msg.clone()); - } - } -} diff --git a/packages/ciphernode/core/src/publickey_aggregator.rs b/packages/ciphernode/core/src/publickey_aggregator.rs index f6bc761c..2b09ae85 100644 --- a/packages/ciphernode/core/src/publickey_aggregator.rs +++ b/packages/ciphernode/core/src/publickey_aggregator.rs @@ -3,7 +3,7 @@ use crate::{ events::{E3id, EnclaveEvent, KeyshareCreated, PublicKeyAggregated}, fhe::{Fhe, GetAggregatePublicKey}, ordered_set::OrderedSet, - GetHasNode, Sortition, + ActorFactory, GetHasNode, Sortition, }; use actix::prelude::*; use anyhow::Result; @@ -207,3 +207,34 @@ impl Handler for PublicKeyAggregator { ) } } + +pub struct PublicKeyAggregatorFactory; +impl PublicKeyAggregatorFactory { + pub fn create(bus: Addr, sortition: Addr) -> ActorFactory { + Box::new(move |ctx, evt| { + // Saving the publickey aggregator with deps on CommitteeRequested + let EnclaveEvent::CommitteeRequested { data, .. } = evt else { + return; + }; + + let Some(ref fhe) = ctx.fhe else { + return; + }; + let Some(ref meta) = ctx.meta else { + return; + }; + + ctx.publickey = Some( + PublicKeyAggregator::new( + fhe.clone(), + bus.clone(), + sortition.clone(), + data.e3_id, + meta.nodecount, + meta.seed, + ) + .start(), + ); + }) + } +} diff --git a/packages/ciphernode/core/src/publickey_orchestrator.rs b/packages/ciphernode/core/src/publickey_orchestrator.rs deleted file mode 100644 index c6930467..00000000 --- a/packages/ciphernode/core/src/publickey_orchestrator.rs +++ /dev/null @@ -1,102 +0,0 @@ -// TODO: spawn and supervise child actors -use crate::{ - E3id, EnclaveEvent, EventBus, Fhe, InitializeWithEnclaveEvent, PublicKeyAggregator, Sortition, -}; -use actix::prelude::*; -use std::collections::HashMap; - -pub struct PublicKeyOrchestrator { - bus: Addr, - sortition: Addr, - buffers: HashMap>, - public_keys: HashMap>, -} - -impl PublicKeyOrchestrator { - pub fn new(bus: Addr, sortition: Addr) -> Self { - Self { - bus, - sortition, - public_keys: HashMap::new(), - buffers: HashMap::new(), - } - } - - pub fn attach(bus: Addr, sortition: Addr) -> Addr { - PublicKeyOrchestrator::new(bus.clone(), sortition).start() - } -} - -impl Actor for PublicKeyOrchestrator { - type Context = Context; -} - -impl Handler for PublicKeyOrchestrator { - type Result = (); - fn handle(&mut self, msg: InitializeWithEnclaveEvent, _: &mut Self::Context) -> Self::Result { - let InitializeWithEnclaveEvent { fhe, event, .. } = msg; - let EnclaveEvent::CommitteeRequested { data, .. } = event else { - return; - }; - - let public_key_factory = self.public_key_factory( - fhe.clone(), - data.e3_id.clone(), - data.nodecount, - data.sortition_seed, - ); - self.public_keys - .entry(data.e3_id) - .or_insert_with(public_key_factory); - } -} - -impl Handler for PublicKeyOrchestrator { - type Result = (); - - fn handle(&mut self, msg: EnclaveEvent, _ctx: &mut Self::Context) -> Self::Result { - let Some(e3_id) = msg.get_e3_id() else { - return; - }; - self.forward_message(&e3_id, msg); - } -} - -impl PublicKeyOrchestrator { - fn public_key_factory( - &self, - fhe: Addr, - e3_id: E3id, - nodecount: usize, - seed: u64, - ) -> impl FnOnce() -> Addr { - let bus = self.bus.clone(); - let sortition = self.sortition.clone(); - move || PublicKeyAggregator::new(fhe, bus, sortition, e3_id, nodecount, seed).start() - } - - fn store_msg(&mut self, e3_id: E3id, msg: EnclaveEvent) { - self.buffers.entry(e3_id).or_default().push(msg); - } - - fn take_msgs(&mut self, e3_id: E3id) -> Vec { - self.buffers - .get_mut(&e3_id) - .map(std::mem::take) - .unwrap_or_default() - } - - fn forward_message(&mut self, e3_id: &E3id, msg: EnclaveEvent) { - // Buffer events for each thing that has not been created - if let Some(act) = self.public_keys.clone().get(e3_id) { - let msgs = self.take_msgs(e3_id.clone()); - let recipient = act.clone().recipient(); - recipient.do_send(msg.clone()); - for m in msgs { - recipient.do_send(m); - } - } else { - self.store_msg(e3_id.clone(), msg.clone()); - } - } -} From d091597532f4ee96733c723ad59126904b78fc50 Mon Sep 17 00:00:00 2001 From: Auryn Macmillan Date: Wed, 18 Sep 2024 21:59:20 -0400 Subject: [PATCH 79/87] add: remaining unit tests for `CipherNodeRegistryOwnable.sol` --- .../CyphernodeRegistryOwnable.spec.ts | 101 +++++++++++++++--- 1 file changed, 86 insertions(+), 15 deletions(-) diff --git a/packages/evm/test/CyphernodeRegistry/CyphernodeRegistryOwnable.spec.ts b/packages/evm/test/CyphernodeRegistry/CyphernodeRegistryOwnable.spec.ts index 38904e02..2e08cec1 100644 --- a/packages/evm/test/CyphernodeRegistry/CyphernodeRegistryOwnable.spec.ts +++ b/packages/evm/test/CyphernodeRegistry/CyphernodeRegistryOwnable.spec.ts @@ -278,41 +278,112 @@ describe.only("CiphernodeRegistryOwnable", function () { }); describe("setEnclave()", function () { - it("reverts if the caller is not the owner"); - it("sets the enclave address"); - it("emits an EnclaveSet event"); + it("reverts if the caller is not the owner", async function () { + const { registry, notTheOwner } = await loadFixture(setup); + await expect( + registry.connect(notTheOwner).setEnclave(AddressThree), + ).to.be.revertedWithCustomError(registry, "OwnableUnauthorizedAccount"); + }); + it("sets the enclave address", async function () { + const { registry } = await loadFixture(setup); + expect(await registry.setEnclave(AddressThree)); + expect(await registry.enclave()).to.equal(AddressThree); + }); + it("emits an EnclaveSet event", async function () { + const { registry } = await loadFixture(setup); + expect(await registry.setEnclave(AddressThree)) + .to.emit(registry, "EnclaveSet") + .withArgs(AddressThree); + }); }); describe("committeePublicKey()", function () { - it("returns the public key of the committee for the given e3Id"); - it("reverts if the committee has not been published"); + it("returns the public key of the committee for the given e3Id", async function () { + const { filter, registry, request } = await loadFixture(setup); + await registry.requestCommittee( + request.e3Id, + request.filter, + request.threshold, + ); + await filter.publishCommittee( + request.e3Id, + [AddressOne, AddressTwo], + "0xda7a", + ); + expect(await registry.committeePublicKey(request.e3Id)).to.equal( + "0xda7a", + ); + }); + it("reverts if the committee has not been published", async function () { + const { registry, request } = await loadFixture(setup); + await registry.requestCommittee( + request.e3Id, + request.filter, + request.threshold, + ); + await expect( + registry.committeePublicKey(request.e3Id), + ).to.be.revertedWithCustomError(registry, "CommitteeNotPublished"); + }); }); describe("isCiphernodeEligible()", function () { - it("returns true if the ciphernode is in the registry"); - it("returns false if the ciphernode is not in the registry"); + it("returns true if the ciphernode is in the registry", async function () { + const { registry } = await loadFixture(setup); + expect(await registry.isCiphernodeEligible(AddressOne)).to.be.true; + }); + it("returns false if the ciphernode is not in the registry", async function () { + const { registry } = await loadFixture(setup); + expect(await registry.isCiphernodeEligible(AddressThree)).to.be.false; + }); }); describe("isEnabled()", function () { - it("returns true if the ciphernode is currently enabled"); - it("returns false if the ciphernode is not currently enabled"); + it("returns true if the ciphernode is currently enabled", async function () { + const { registry } = await loadFixture(setup); + expect(await registry.isEnabled(AddressOne)).to.be.true; + }); + it("returns false if the ciphernode is not currently enabled", async function () { + const { registry } = await loadFixture(setup); + expect(await registry.isEnabled(AddressThree)).to.be.false; + }); }); describe("root()", function () { - it("returns the root of the ciphernode registry merkle tree"); + it("returns the root of the ciphernode registry merkle tree", async function () { + const { registry, tree } = await loadFixture(setup); + expect(await registry.root()).to.equal(tree.root); + }); }); describe("rootAt()", function () { - it( - "returns the root of the ciphernode registry merkle tree at the given e3Id", - ); + it("returns the root of the ciphernode registry merkle tree at the given e3Id", async function () { + const { registry, tree, request } = await loadFixture(setup); + await registry.requestCommittee( + request.e3Id, + request.filter, + request.threshold, + ); + expect(await registry.rootAt(request.e3Id)).to.equal(tree.root); + }); }); describe("getFilter()", function () { - it("returns the registry filter for the given e3Id"); + it("returns the registry filter for the given e3Id", async function () { + const { registry, request } = await loadFixture(setup); + await registry.requestCommittee( + request.e3Id, + request.filter, + request.threshold, + ); + expect(await registry.getFilter(request.e3Id)).to.equal(request.filter); + }); }); describe("treeSize()", function () { - it("returns the size of the ciphernode registry merkle tree"); + it("returns the size of the ciphernode registry merkle tree", async function () { + const { registry, tree } = await loadFixture(setup); + expect(await registry.treeSize()).to.equal(tree.size); + }); }); }); From e893621f51ffba08e54e1cda890e0102955d67cf Mon Sep 17 00:00:00 2001 From: Auryn Macmillan Date: Wed, 18 Sep 2024 22:00:17 -0400 Subject: [PATCH 80/87] remove: unused imports --- .../CyphernodeRegistryOwnable.spec.ts | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/packages/evm/test/CyphernodeRegistry/CyphernodeRegistryOwnable.spec.ts b/packages/evm/test/CyphernodeRegistry/CyphernodeRegistryOwnable.spec.ts index 2e08cec1..728fe033 100644 --- a/packages/evm/test/CyphernodeRegistry/CyphernodeRegistryOwnable.spec.ts +++ b/packages/evm/test/CyphernodeRegistry/CyphernodeRegistryOwnable.spec.ts @@ -1,19 +1,13 @@ -import { - loadFixture, - mine, - time, -} from "@nomicfoundation/hardhat-network-helpers"; +import { loadFixture } from "@nomicfoundation/hardhat-network-helpers"; import { LeanIMT } from "@zk-kit/lean-imt"; import { expect } from "chai"; -import { ZeroHash } from "ethers"; -import { ethers, network } from "hardhat"; +import { ethers } from "hardhat"; import { poseidon2 } from "poseidon-lite"; import { deployCiphernodeRegistryOwnableFixture } from "../fixtures/CiphernodeRegistryOwnable.fixture"; import { naiveRegistryFilterFixture } from "../fixtures/NaiveRegistryFilter.fixture"; import { PoseidonT3Fixture } from "../fixtures/PoseidonT3.fixture"; -const abiCoder = ethers.AbiCoder.defaultAbiCoder(); const AddressOne = "0x0000000000000000000000000000000000000001"; const AddressTwo = "0x0000000000000000000000000000000000000002"; const AddressThree = "0x0000000000000000000000000000000000000003"; From 84f20c01c1d3a839109f7b5db5e4b429e07ee28a Mon Sep 17 00:00:00 2001 From: Auryn Macmillan Date: Thu, 19 Sep 2024 10:21:25 -0400 Subject: [PATCH 81/87] add: unit tests for NaiveRegistryFilter.sol --- packages/evm/contracts/Enclave.sol | 2 +- .../registry/NaiveRegistryFilter.sol | 12 + .../CyphernodeRegistryOwnable.spec.ts | 2 +- .../NaiveRegistryFilter.spec.ts | 241 ++++++++++++++++++ 4 files changed, 255 insertions(+), 2 deletions(-) create mode 100644 packages/evm/test/CyphernodeRegistry/NaiveRegistryFilter.spec.ts diff --git a/packages/evm/contracts/Enclave.sol b/packages/evm/contracts/Enclave.sol index f67943bf..f6649d05 100644 --- a/packages/evm/contracts/Enclave.sol +++ b/packages/evm/contracts/Enclave.sol @@ -176,7 +176,7 @@ contract Enclave is IEnclave, OwnableUpgradeable { CommitteeSelectionFailed() ); - emit E3Requested(e3Id, e3s[e3Id], filter, e3Program); + emit E3Requested(e3Id, e3, filter, e3Program); } function activate(uint256 e3Id) external returns (bool success) { diff --git a/packages/evm/contracts/registry/NaiveRegistryFilter.sol b/packages/evm/contracts/registry/NaiveRegistryFilter.sol index 127b50e4..ccc565a6 100644 --- a/packages/evm/contracts/registry/NaiveRegistryFilter.sol +++ b/packages/evm/contracts/registry/NaiveRegistryFilter.sol @@ -106,4 +106,16 @@ contract NaiveRegistryFilter is IRegistryFilter, OwnableUpgradeable { function setRegistry(address _registry) public onlyOwner { registry = _registry; } + + //////////////////////////////////////////////////////////// + // // + // Get Functions // + // // + //////////////////////////////////////////////////////////// + + function getCommittee( + uint256 e3Id + ) external view returns (Committee memory) { + return committees[e3Id]; + } } diff --git a/packages/evm/test/CyphernodeRegistry/CyphernodeRegistryOwnable.spec.ts b/packages/evm/test/CyphernodeRegistry/CyphernodeRegistryOwnable.spec.ts index 728fe033..9850c361 100644 --- a/packages/evm/test/CyphernodeRegistry/CyphernodeRegistryOwnable.spec.ts +++ b/packages/evm/test/CyphernodeRegistry/CyphernodeRegistryOwnable.spec.ts @@ -15,7 +15,7 @@ const AddressThree = "0x0000000000000000000000000000000000000003"; // Hash function used to compute the tree nodes. const hash = (a: bigint, b: bigint) => poseidon2([a, b]); -describe.only("CiphernodeRegistryOwnable", function () { +describe("CiphernodeRegistryOwnable", function () { async function setup() { const [owner, notTheOwner] = await ethers.getSigners(); diff --git a/packages/evm/test/CyphernodeRegistry/NaiveRegistryFilter.spec.ts b/packages/evm/test/CyphernodeRegistry/NaiveRegistryFilter.spec.ts new file mode 100644 index 00000000..46590165 --- /dev/null +++ b/packages/evm/test/CyphernodeRegistry/NaiveRegistryFilter.spec.ts @@ -0,0 +1,241 @@ +import { loadFixture } from "@nomicfoundation/hardhat-network-helpers"; +import { LeanIMT } from "@zk-kit/lean-imt"; +import { expect } from "chai"; +import { ethers } from "hardhat"; +import { poseidon2 } from "poseidon-lite"; + +import { deployCiphernodeRegistryOwnableFixture } from "../fixtures/CiphernodeRegistryOwnable.fixture"; +import { naiveRegistryFilterFixture } from "../fixtures/NaiveRegistryFilter.fixture"; +import { PoseidonT3Fixture } from "../fixtures/PoseidonT3.fixture"; + +const AddressOne = "0x0000000000000000000000000000000000000001"; +const AddressTwo = "0x0000000000000000000000000000000000000002"; +const AddressThree = "0x0000000000000000000000000000000000000003"; + +// Hash function used to compute the tree nodes. +const hash = (a: bigint, b: bigint) => poseidon2([a, b]); + +describe.only("NaiveRegistryFilter", function () { + async function setup() { + const [owner, notTheOwner] = await ethers.getSigners(); + + const poseidon = await PoseidonT3Fixture(); + const registry = await deployCiphernodeRegistryOwnableFixture( + owner.address, + owner.address, + await poseidon.getAddress(), + ); + const filter = await naiveRegistryFilterFixture( + owner.address, + await registry.getAddress(), + ); + + const tree = new LeanIMT(hash); + await registry.addCiphernode(AddressOne); + tree.insert(BigInt(AddressOne)); + await registry.addCiphernode(AddressTwo); + tree.insert(BigInt(AddressTwo)); + + return { + owner, + notTheOwner, + registry, + filter, + tree, + request: { + e3Id: 1, + filter: await filter.getAddress(), + threshold: [2, 2] as [number, number], + }, + }; + } + + describe("constructor / initialize()", function () { + it("should set the owner", async function () { + const { owner, filter } = await setup(); + expect(await filter.owner()).to.equal(owner.address); + }); + it("should set the registry", async function () { + const { registry, filter } = await setup(); + expect(await filter.registry()).to.equal(await registry.getAddress()); + }); + }); + + describe("requestCommittee()", function () { + it("should revert if the caller is not the registry", async function () { + const { notTheOwner, filter, request } = await setup(); + await expect( + filter + .connect(notTheOwner) + .requestCommittee(request.e3Id, request.threshold), + ).to.be.revertedWithCustomError(filter, "OnlyRegistry"); + }); + it("should revert if a committee has already been requested for the given e3Id", async function () { + const { filter, request, owner } = await setup(); + await filter.setRegistry(owner.address); + await filter.requestCommittee(request.e3Id, request.threshold); + await expect( + filter.requestCommittee(request.e3Id, request.threshold), + ).to.be.revertedWithCustomError(filter, "CommitteeAlreadyExists"); + }); + it("should set the threshold for the requested committee", async function () { + const { filter, owner, request } = await setup(); + await filter.setRegistry(owner.address); + await filter.requestCommittee(request.e3Id, request.threshold); + const committee = await filter.getCommittee(request.e3Id); + expect(committee.threshold).to.deep.equal(request.threshold); + }); + it("should return true when a committee is requested", async function () { + const { filter, owner, request } = await setup(); + await filter.setRegistry(owner.address); + const result = await filter.requestCommittee.staticCall( + request.e3Id, + request.threshold, + ); + expect(result).to.equal(true); + }); + }); + + describe("publishCommittee()", function () { + it("should revert if the caller is not owner", async function () { + const { filter, notTheOwner, request } = await setup(); + await expect( + filter + .connect(notTheOwner) + .publishCommittee( + request.e3Id, + [AddressOne, AddressTwo], + AddressThree, + ), + ).to.be.revertedWithCustomError(filter, "OwnableUnauthorizedAccount"); + }); + it("should revert if committee already published", async function () { + const { filter, registry, request } = await setup(); + expect( + await registry.requestCommittee( + request.e3Id, + request.filter, + request.threshold, + ), + ); + await filter.publishCommittee( + request.e3Id, + [AddressOne, AddressTwo], + AddressThree, + ); + await expect( + filter.publishCommittee( + request.e3Id, + [AddressOne, AddressTwo], + AddressThree, + ), + ).to.be.revertedWithCustomError(filter, "CommitteeAlreadyPublished"); + }); + it("should store the node addresses of the committee", async function () { + const { filter, registry, request } = await setup(); + expect( + await registry.requestCommittee( + request.e3Id, + request.filter, + request.threshold, + ), + ); + await filter.publishCommittee( + request.e3Id, + [AddressOne, AddressTwo], + AddressThree, + ); + const committee = await filter.getCommittee(request.e3Id); + expect(committee.nodes).to.deep.equal([AddressOne, AddressTwo]); + }); + it("should store the public key of the committee", async function () { + const { filter, registry, request } = await setup(); + expect( + await registry.requestCommittee( + request.e3Id, + request.filter, + request.threshold, + ), + ); + await filter.publishCommittee( + request.e3Id, + [AddressOne, AddressTwo], + AddressThree, + ); + const committee = await filter.getCommittee(request.e3Id); + expect(committee.publicKey).to.equal(AddressThree); + }); + it("should publish the correct node addresses of the committee for the given e3Id", async function () { + const { filter, registry, request } = await setup(); + expect( + await registry.requestCommittee( + request.e3Id, + request.filter, + request.threshold, + ), + ); + await filter.publishCommittee( + request.e3Id, + [AddressOne, AddressTwo], + AddressThree, + ); + const committee = await filter.getCommittee(request.e3Id); + expect(committee.nodes).to.deep.equal([AddressOne, AddressTwo]); + }); + it("should publish the public key of the committee for the given e3Id", async function () { + const { filter, registry, request } = await setup(); + expect( + await registry.requestCommittee( + request.e3Id, + request.filter, + request.threshold, + ), + ); + await filter.publishCommittee( + request.e3Id, + [AddressOne, AddressTwo], + AddressThree, + ); + const committee = await filter.getCommittee(request.e3Id); + expect(committee.publicKey).to.equal(AddressThree); + }); + }); + + describe("setRegistry()", function () { + it("should revert if the caller is not the owner", async function () { + const { filter, notTheOwner } = await setup(); + await expect(filter.connect(notTheOwner).setRegistry(notTheOwner.address)) + .to.be.revertedWithCustomError(filter, "OwnableUnauthorizedAccount") + .withArgs(notTheOwner.address); + }); + it("should set the registry", async function () { + const { filter, owner, registry } = await setup(); + await filter.setRegistry(owner.address); + expect(await filter.registry()).to.equal(owner.address); + }); + }); + + describe("getCommittee()", function () { + it("should return the committee for the given e3Id", async function () { + const { filter, owner, registry, request } = await setup(); + expect( + await registry.requestCommittee( + request.e3Id, + request.filter, + request.threshold, + ), + ); + expect( + await filter.publishCommittee( + request.e3Id, + [AddressOne, AddressTwo], + AddressThree, + ), + ); + const committee = await filter.getCommittee(request.e3Id); + expect(committee.threshold).to.deep.equal(request.threshold); + expect(committee.nodes).to.deep.equal([AddressOne, AddressTwo]); + expect(committee.publicKey).to.equal(AddressThree); + }); + }); +}); From 9e5f775100c1b60ac29ab4674a15d63604b6c548 Mon Sep 17 00:00:00 2001 From: Auryn Macmillan Date: Thu, 19 Sep 2024 10:33:27 -0400 Subject: [PATCH 82/87] fix: linter errors and a broken test they revealed --- ...c.ts => CiphernodeRegistryOwnable.spec.ts} | 18 +++++++---- .../NaiveRegistryFilter.spec.ts | 32 +++++++++---------- packages/evm/test/fixtures/Enclave.fixture.ts | 1 - 3 files changed, 28 insertions(+), 23 deletions(-) rename packages/evm/test/CyphernodeRegistry/{CyphernodeRegistryOwnable.spec.ts => CiphernodeRegistryOwnable.spec.ts} (96%) diff --git a/packages/evm/test/CyphernodeRegistry/CyphernodeRegistryOwnable.spec.ts b/packages/evm/test/CyphernodeRegistry/CiphernodeRegistryOwnable.spec.ts similarity index 96% rename from packages/evm/test/CyphernodeRegistry/CyphernodeRegistryOwnable.spec.ts rename to packages/evm/test/CyphernodeRegistry/CiphernodeRegistryOwnable.spec.ts index 9850c361..bf828e20 100644 --- a/packages/evm/test/CyphernodeRegistry/CyphernodeRegistryOwnable.spec.ts +++ b/packages/evm/test/CyphernodeRegistry/CiphernodeRegistryOwnable.spec.ts @@ -55,7 +55,7 @@ describe("CiphernodeRegistryOwnable", function () { const poseidonFactory = await ethers.getContractFactory("PoseidonT3"); const poseidonDeployment = await poseidonFactory.deploy(); const [deployer] = await ethers.getSigners(); - let ciphernodeRegistryFactory = await ethers.getContractFactory( + const ciphernodeRegistryFactory = await ethers.getContractFactory( "CiphernodeRegistryOwnable", { libraries: { @@ -63,7 +63,7 @@ describe("CiphernodeRegistryOwnable", function () { }, }, ); - let ciphernodeRegistry = await ciphernodeRegistryFactory.deploy( + const ciphernodeRegistry = await ciphernodeRegistryFactory.deploy( deployer.address, AddressTwo, ); @@ -191,7 +191,7 @@ describe("CiphernodeRegistryOwnable", function () { request.filter, request.threshold, ); - expect( + await expect( await filter.publishCommittee( request.e3Id, [AddressOne, AddressTwo], @@ -225,10 +225,16 @@ describe("CiphernodeRegistryOwnable", function () { }); it("emits a CiphernodeAdded event", async function () { const { registry } = await loadFixture(setup); + const treeSize = await registry.treeSize(); const numCiphernodes = await registry.numCiphernodes(); - expect(await registry.addCiphernode(AddressThree)) + await expect(await registry.addCiphernode(AddressThree)) .to.emit(registry, "CiphernodeAdded") - .withArgs(AddressThree, numCiphernodes + BigInt(1)); + .withArgs( + AddressThree, + treeSize, + numCiphernodes + BigInt(1), + treeSize + BigInt(1), + ); }); }); @@ -285,7 +291,7 @@ describe("CiphernodeRegistryOwnable", function () { }); it("emits an EnclaveSet event", async function () { const { registry } = await loadFixture(setup); - expect(await registry.setEnclave(AddressThree)) + await expect(await registry.setEnclave(AddressThree)) .to.emit(registry, "EnclaveSet") .withArgs(AddressThree); }); diff --git a/packages/evm/test/CyphernodeRegistry/NaiveRegistryFilter.spec.ts b/packages/evm/test/CyphernodeRegistry/NaiveRegistryFilter.spec.ts index 46590165..f2faa038 100644 --- a/packages/evm/test/CyphernodeRegistry/NaiveRegistryFilter.spec.ts +++ b/packages/evm/test/CyphernodeRegistry/NaiveRegistryFilter.spec.ts @@ -15,7 +15,7 @@ const AddressThree = "0x0000000000000000000000000000000000000003"; // Hash function used to compute the tree nodes. const hash = (a: bigint, b: bigint) => poseidon2([a, b]); -describe.only("NaiveRegistryFilter", function () { +describe("NaiveRegistryFilter", function () { async function setup() { const [owner, notTheOwner] = await ethers.getSigners(); @@ -52,18 +52,18 @@ describe.only("NaiveRegistryFilter", function () { describe("constructor / initialize()", function () { it("should set the owner", async function () { - const { owner, filter } = await setup(); + const { owner, filter } = await loadFixture(setup); expect(await filter.owner()).to.equal(owner.address); }); it("should set the registry", async function () { - const { registry, filter } = await setup(); + const { registry, filter } = await loadFixture(setup); expect(await filter.registry()).to.equal(await registry.getAddress()); }); }); describe("requestCommittee()", function () { it("should revert if the caller is not the registry", async function () { - const { notTheOwner, filter, request } = await setup(); + const { notTheOwner, filter, request } = await loadFixture(setup); await expect( filter .connect(notTheOwner) @@ -71,7 +71,7 @@ describe.only("NaiveRegistryFilter", function () { ).to.be.revertedWithCustomError(filter, "OnlyRegistry"); }); it("should revert if a committee has already been requested for the given e3Id", async function () { - const { filter, request, owner } = await setup(); + const { filter, request, owner } = await loadFixture(setup); await filter.setRegistry(owner.address); await filter.requestCommittee(request.e3Id, request.threshold); await expect( @@ -79,14 +79,14 @@ describe.only("NaiveRegistryFilter", function () { ).to.be.revertedWithCustomError(filter, "CommitteeAlreadyExists"); }); it("should set the threshold for the requested committee", async function () { - const { filter, owner, request } = await setup(); + const { filter, owner, request } = await loadFixture(setup); await filter.setRegistry(owner.address); await filter.requestCommittee(request.e3Id, request.threshold); const committee = await filter.getCommittee(request.e3Id); expect(committee.threshold).to.deep.equal(request.threshold); }); it("should return true when a committee is requested", async function () { - const { filter, owner, request } = await setup(); + const { filter, owner, request } = await loadFixture(setup); await filter.setRegistry(owner.address); const result = await filter.requestCommittee.staticCall( request.e3Id, @@ -98,7 +98,7 @@ describe.only("NaiveRegistryFilter", function () { describe("publishCommittee()", function () { it("should revert if the caller is not owner", async function () { - const { filter, notTheOwner, request } = await setup(); + const { filter, notTheOwner, request } = await loadFixture(setup); await expect( filter .connect(notTheOwner) @@ -110,7 +110,7 @@ describe.only("NaiveRegistryFilter", function () { ).to.be.revertedWithCustomError(filter, "OwnableUnauthorizedAccount"); }); it("should revert if committee already published", async function () { - const { filter, registry, request } = await setup(); + const { filter, registry, request } = await loadFixture(setup); expect( await registry.requestCommittee( request.e3Id, @@ -132,7 +132,7 @@ describe.only("NaiveRegistryFilter", function () { ).to.be.revertedWithCustomError(filter, "CommitteeAlreadyPublished"); }); it("should store the node addresses of the committee", async function () { - const { filter, registry, request } = await setup(); + const { filter, registry, request } = await loadFixture(setup); expect( await registry.requestCommittee( request.e3Id, @@ -149,7 +149,7 @@ describe.only("NaiveRegistryFilter", function () { expect(committee.nodes).to.deep.equal([AddressOne, AddressTwo]); }); it("should store the public key of the committee", async function () { - const { filter, registry, request } = await setup(); + const { filter, registry, request } = await loadFixture(setup); expect( await registry.requestCommittee( request.e3Id, @@ -166,7 +166,7 @@ describe.only("NaiveRegistryFilter", function () { expect(committee.publicKey).to.equal(AddressThree); }); it("should publish the correct node addresses of the committee for the given e3Id", async function () { - const { filter, registry, request } = await setup(); + const { filter, registry, request } = await loadFixture(setup); expect( await registry.requestCommittee( request.e3Id, @@ -183,7 +183,7 @@ describe.only("NaiveRegistryFilter", function () { expect(committee.nodes).to.deep.equal([AddressOne, AddressTwo]); }); it("should publish the public key of the committee for the given e3Id", async function () { - const { filter, registry, request } = await setup(); + const { filter, registry, request } = await loadFixture(setup); expect( await registry.requestCommittee( request.e3Id, @@ -203,13 +203,13 @@ describe.only("NaiveRegistryFilter", function () { describe("setRegistry()", function () { it("should revert if the caller is not the owner", async function () { - const { filter, notTheOwner } = await setup(); + const { filter, notTheOwner } = await loadFixture(setup); await expect(filter.connect(notTheOwner).setRegistry(notTheOwner.address)) .to.be.revertedWithCustomError(filter, "OwnableUnauthorizedAccount") .withArgs(notTheOwner.address); }); it("should set the registry", async function () { - const { filter, owner, registry } = await setup(); + const { filter, owner } = await loadFixture(setup); await filter.setRegistry(owner.address); expect(await filter.registry()).to.equal(owner.address); }); @@ -217,7 +217,7 @@ describe.only("NaiveRegistryFilter", function () { describe("getCommittee()", function () { it("should return the committee for the given e3Id", async function () { - const { filter, owner, registry, request } = await setup(); + const { filter, registry, request } = await loadFixture(setup); expect( await registry.requestCommittee( request.e3Id, diff --git a/packages/evm/test/fixtures/Enclave.fixture.ts b/packages/evm/test/fixtures/Enclave.fixture.ts index 9c847db7..b5d9087c 100644 --- a/packages/evm/test/fixtures/Enclave.fixture.ts +++ b/packages/evm/test/fixtures/Enclave.fixture.ts @@ -1,4 +1,3 @@ -import { SignerWithAddress } from "@nomicfoundation/hardhat-ethers/signers"; import { ethers } from "hardhat"; import { Enclave__factory } from "../../types/factories/contracts/Enclave__factory"; From 6dda71037ada6bb890308418f51b7530f6fadbd9 Mon Sep 17 00:00:00 2001 From: Auryn Macmillan Date: Thu, 19 Sep 2024 10:37:41 -0400 Subject: [PATCH 83/87] fix: rename an incorrectly named directory --- .../CiphernodeRegistryOwnable.spec.ts | 0 .../NaiveRegistryFilter.spec.ts | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename packages/evm/test/{CyphernodeRegistry => CiphernodeRegistry}/CiphernodeRegistryOwnable.spec.ts (100%) rename packages/evm/test/{CyphernodeRegistry => CiphernodeRegistry}/NaiveRegistryFilter.spec.ts (100%) diff --git a/packages/evm/test/CyphernodeRegistry/CiphernodeRegistryOwnable.spec.ts b/packages/evm/test/CiphernodeRegistry/CiphernodeRegistryOwnable.spec.ts similarity index 100% rename from packages/evm/test/CyphernodeRegistry/CiphernodeRegistryOwnable.spec.ts rename to packages/evm/test/CiphernodeRegistry/CiphernodeRegistryOwnable.spec.ts diff --git a/packages/evm/test/CyphernodeRegistry/NaiveRegistryFilter.spec.ts b/packages/evm/test/CiphernodeRegistry/NaiveRegistryFilter.spec.ts similarity index 100% rename from packages/evm/test/CyphernodeRegistry/NaiveRegistryFilter.spec.ts rename to packages/evm/test/CiphernodeRegistry/NaiveRegistryFilter.spec.ts From 6aac00cd6aa30d8bdf61cc87e264170054319683 Mon Sep 17 00:00:00 2001 From: Auryn Macmillan Date: Thu, 19 Sep 2024 12:22:13 -0400 Subject: [PATCH 84/87] add: `encryptionSchemeId` to `Enclave.sol` --- packages/evm/contracts/Enclave.sol | 43 ++++++- packages/evm/contracts/interfaces/IE3.sol | 1 + .../evm/contracts/interfaces/IE3Program.sol | 2 + .../evm/contracts/interfaces/IEnclave.sol | 8 ++ packages/evm/contracts/test/MockE3Program.sol | 2 + packages/evm/test/Enclave.spec.ts | 108 +++++++++++++++++- 6 files changed, 161 insertions(+), 3 deletions(-) diff --git a/packages/evm/contracts/Enclave.sol b/packages/evm/contracts/Enclave.sol index f6649d05..cf825c80 100644 --- a/packages/evm/contracts/Enclave.sol +++ b/packages/evm/contracts/Enclave.sol @@ -34,12 +34,16 @@ contract Enclave is IEnclave, OwnableUpgradeable { // Mapping of E3s. mapping(uint256 e3Id => E3 e3) public e3s; - // Mapping of input merkle trees + // Mapping of input merkle trees. mapping(uint256 e3Id => LeanIMTData imt) public inputs; // Mapping counting the number of inputs for each E3. mapping(uint256 e3Id => uint256 inputCount) public inputCounts; + // Mapping of enabled encryption schemes. + mapping(bytes32 encryptionSchemeId => bool enabled) + public encryptionSchemes; + //////////////////////////////////////////////////////////// // // // Errors // @@ -55,6 +59,7 @@ contract Enclave is IEnclave, OwnableUpgradeable { error E3DoesNotExist(uint256 e3Id); error ModuleAlreadyEnabled(address module); error ModuleNotEnabled(address module); + error InvalidEncryptionScheme(bytes32 encryptionSchemeId); error InputDeadlinePassed(uint256 e3Id, uint256 expiration); error InputDeadlineNotPassed(uint256 e3Id, uint256 expiration); error InvalidComputationRequest( @@ -141,6 +146,7 @@ contract Enclave is IEnclave, OwnableUpgradeable { uint256 seed = uint256(keccak256(abi.encode(block.prevrandao, e3Id))); ( + bytes32 encryptionSchemeId, IInputValidator inputValidator, IDecryptionVerifier decryptionVerifier ) = e3Program.validate( @@ -149,6 +155,10 @@ contract Enclave is IEnclave, OwnableUpgradeable { e3ProgramParams, computeProviderParams ); + require( + encryptionSchemes[encryptionSchemeId], + InvalidEncryptionScheme(encryptionSchemeId) + ); require( address(inputValidator) != address(0) && address(decryptionVerifier) != address(0), @@ -161,6 +171,7 @@ contract Enclave is IEnclave, OwnableUpgradeable { startWindow: startWindow, duration: duration, expiration: 0, + encryptionSchemeId: encryptionSchemeId, e3Program: e3Program, e3ProgramParams: e3ProgramParams, inputValidator: inputValidator, @@ -322,6 +333,30 @@ contract Enclave is IEnclave, OwnableUpgradeable { emit E3ProgramDisabled(e3Program); } + function enableEncryptionScheme( + bytes32 encryptionSchemeId + ) public onlyOwner returns (bool success) { + require( + !encryptionSchemes[encryptionSchemeId], + InvalidEncryptionScheme(encryptionSchemeId) + ); + encryptionSchemes[encryptionSchemeId] = true; + success = true; + emit EncryptionSchemeEnabled(encryptionSchemeId); + } + + function disableEncryptionScheme( + bytes32 encryptionSchemeId + ) public onlyOwner returns (bool success) { + require( + encryptionSchemes[encryptionSchemeId], + InvalidEncryptionScheme(encryptionSchemeId) + ); + encryptionSchemes[encryptionSchemeId] = false; + success = false; + emit EncryptionSchemeDisabled(encryptionSchemeId); + } + //////////////////////////////////////////////////////////// // // // Get Functions // @@ -340,4 +375,10 @@ contract Enclave is IEnclave, OwnableUpgradeable { ); return InternalLeanIMT._root(inputs[e3Id]); } + + function isEncryptionSchemeEnabled( + bytes32 encryptionSchemeId + ) public view returns (bool) { + return encryptionSchemes[encryptionSchemeId]; + } } diff --git a/packages/evm/contracts/interfaces/IE3.sol b/packages/evm/contracts/interfaces/IE3.sol index 51a9daab..258202ab 100644 --- a/packages/evm/contracts/interfaces/IE3.sol +++ b/packages/evm/contracts/interfaces/IE3.sol @@ -24,6 +24,7 @@ struct E3 { uint256[2] startWindow; uint256 duration; uint256 expiration; + bytes32 encryptionSchemeId; IE3Program e3Program; bytes e3ProgramParams; IInputValidator inputValidator; diff --git a/packages/evm/contracts/interfaces/IE3Program.sol b/packages/evm/contracts/interfaces/IE3Program.sol index 601dc4f4..67f7dbd8 100644 --- a/packages/evm/contracts/interfaces/IE3Program.sol +++ b/packages/evm/contracts/interfaces/IE3Program.sol @@ -10,6 +10,7 @@ interface IE3Program { /// @param seed Seed for the computation. /// @param e3ProgramParams ABI encoded computation parameters. /// @param computeProviderParams ABI encoded compute provider parameters. + /// @return encryptionSchemeId ID of the encryption scheme to be used for the computation. /// @return inputValidator The input validator to be used for the computation. /// @return decryptionVerifier The decryption verifier to be used for the computation. function validate( @@ -20,6 +21,7 @@ interface IE3Program { ) external returns ( + bytes32 encryptionSchemeId, IInputValidator inputValidator, IDecryptionVerifier decryptionVerifier ); diff --git a/packages/evm/contracts/interfaces/IEnclave.sol b/packages/evm/contracts/interfaces/IEnclave.sol index 246bc3d9..5d0b24d1 100644 --- a/packages/evm/contracts/interfaces/IEnclave.sol +++ b/packages/evm/contracts/interfaces/IEnclave.sol @@ -66,6 +66,14 @@ interface IEnclave { /// @param ciphernodeRegistry The address of the CiphernodeRegistry contract. event CiphernodeRegistrySet(address ciphernodeRegistry); + /// @notice The event MUST be emitted any time an encryption scheme is enabled. + /// @param encryptionSchemeId The ID of the encryption scheme that was enabled. + event EncryptionSchemeEnabled(bytes32 encryptionSchemeId); + + /// @notice This event MUST be emitted any time an encryption scheme is disabled. + /// @param encryptionSchemeId The ID of the encryption scheme that was disabled. + event EncryptionSchemeDisabled(bytes32 encryptionSchemeId); + /// @notice This event MUST be emitted any time a E3 Program is enabled. /// @param e3Program The address of the E3 Program. event E3ProgramEnabled(IE3Program e3Program); diff --git a/packages/evm/contracts/test/MockE3Program.sol b/packages/evm/contracts/test/MockE3Program.sol index d8ff026c..7121ff47 100644 --- a/packages/evm/contracts/test/MockE3Program.sol +++ b/packages/evm/contracts/test/MockE3Program.sol @@ -19,6 +19,7 @@ contract MockE3Program is IE3Program { external pure returns ( + bytes32 encryptionSchemeId, IInputValidator inputValidator, IDecryptionVerifier decryptionVerifier ) @@ -32,6 +33,7 @@ contract MockE3Program is IE3Program { inputValidator := mload(add(e3ProgramParams, 32)) decryptionVerifier := mload(add(computeProviderParams, 32)) } + encryptionSchemeId = 0x0000000000000000000000000000000000000000000000000000000000000001; } function verify( diff --git a/packages/evm/test/Enclave.spec.ts b/packages/evm/test/Enclave.spec.ts index 22d53939..382f9264 100644 --- a/packages/evm/test/Enclave.spec.ts +++ b/packages/evm/test/Enclave.spec.ts @@ -20,6 +20,10 @@ import { PoseidonT3Fixture } from "./fixtures/PoseidonT3.fixture"; const abiCoder = ethers.AbiCoder.defaultAbiCoder(); const AddressTwo = "0x0000000000000000000000000000000000000002"; const AddressSix = "0x0000000000000000000000000000000000000006"; +const encryptionSchemeId = + "0x0000000000000000000000000000000000000000000000000000000000000001"; +const newEncryptionSchemeId = + "0x0000000000000000000000000000000000000000000000000000000000000002"; const FilterFail = AddressTwo; const FilterOkay = AddressSix; @@ -44,6 +48,7 @@ describe("Enclave", function () { await poseidon.getAddress(), ); + await enclave.enableEncryptionScheme(encryptionSchemeId); await enclave.enableE3Program(await e3Program.getAddress()); return { @@ -208,6 +213,87 @@ describe("Enclave", function () { }); }); + describe("isEncryptionSchemeEnabled()", function () { + it("returns true if encryption scheme is enabled", async function () { + const { enclave } = await loadFixture(setup); + expect(await enclave.isEncryptionSchemeEnabled(encryptionSchemeId)).to.be + .true; + }); + it("returns false if encryption scheme is not enabled", async function () { + const { enclave } = await loadFixture(setup); + expect(await enclave.isEncryptionSchemeEnabled(newEncryptionSchemeId)).to + .be.false; + }); + }); + + describe("enableEncryptionScheme()", function () { + it("reverts if caller is not owner", async function () { + const { enclave, notTheOwner } = await loadFixture(setup); + + await expect( + enclave.connect(notTheOwner).enableEncryptionScheme(encryptionSchemeId), + ) + .to.be.revertedWithCustomError(enclave, "OwnableUnauthorizedAccount") + .withArgs(notTheOwner); + }); + it("reverts if encryption scheme is already enabled", async function () { + const { enclave } = await loadFixture(setup); + + await expect(enclave.enableEncryptionScheme(encryptionSchemeId)) + .to.be.revertedWithCustomError(enclave, "InvalidEncryptionScheme") + .withArgs(encryptionSchemeId); + }); + it("enabled encryption scheme", async function () { + const { enclave } = await loadFixture(setup); + + expect(await enclave.enableEncryptionScheme(newEncryptionSchemeId)); + expect(await enclave.isEncryptionSchemeEnabled(newEncryptionSchemeId)).to + .be.true; + }); + it("emits EncryptionSchemeEnabled", async function () { + const { enclave } = await loadFixture(setup); + + await expect(await enclave.enableEncryptionScheme(newEncryptionSchemeId)) + .to.emit(enclave, "EncryptionSchemeEnabled") + .withArgs(newEncryptionSchemeId); + }); + }); + + describe("disableEncryptionScheme()", function () { + it("reverts if caller is not owner", async function () { + const { enclave, notTheOwner } = await loadFixture(setup); + + await expect( + enclave + .connect(notTheOwner) + .disableEncryptionScheme(encryptionSchemeId), + ) + .to.be.revertedWithCustomError(enclave, "OwnableUnauthorizedAccount") + .withArgs(notTheOwner); + }); + it("reverts if encryption scheme is not already enabled", async function () { + const { enclave } = await loadFixture(setup); + + await expect(enclave.disableEncryptionScheme(newEncryptionSchemeId)) + .to.be.revertedWithCustomError(enclave, "InvalidEncryptionScheme") + .withArgs(newEncryptionSchemeId); + }); + it("disables encryption scheme", async function () { + const { enclave } = await loadFixture(setup); + + expect(await enclave.disableEncryptionScheme(encryptionSchemeId)); + expect(await enclave.isEncryptionSchemeEnabled(encryptionSchemeId)).to.be + .false; + }); + it("emits EncryptionSchemeDisabled", async function () { + const { enclave } = await loadFixture(setup); + + await expect(await enclave.disableEncryptionScheme(encryptionSchemeId)) + .to.emit(enclave, "EncryptionSchemeDisabled") + .withArgs(encryptionSchemeId); + }); + }); + describe("enableE3Program()", function () { it("reverts if not called by owner", async function () { const { @@ -390,7 +476,25 @@ describe("Enclave", function () { .to.be.revertedWithCustomError(enclave, "E3ProgramNotAllowed") .withArgs(ethers.ZeroAddress); }); - it("reverts if input E3 Program does not return input validator address", async function () { + it("reverts if given encryption scheme is not enabled", async function () { + const { enclave, request } = await loadFixture(setup); + await enclave.disableEncryptionScheme(encryptionSchemeId); + await expect( + enclave.request( + request.filter, + request.threshold, + request.startTime, + request.duration, + request.e3Program, + ZeroHash, + request.computeProviderParams, + { value: 10 }, + ), + ) + .to.be.revertedWithCustomError(enclave, "InvalidEncryptionScheme") + .withArgs(encryptionSchemeId); + }); + it("reverts if given E3 Program does not return input validator address", async function () { const { enclave, request } = await loadFixture(setup); await expect( @@ -406,7 +510,7 @@ describe("Enclave", function () { ), ).to.be.revertedWithCustomError(enclave, "InvalidComputationRequest"); }); - it("reverts if input compute provider does not return output verifier address", async function () { + it("reverts if given compute provider does not return output verifier address", async function () { const { enclave, request } = await loadFixture(setup); await expect( enclave.request( From 56a43527dfd89506dcf78f8615089cea82aeb55a Mon Sep 17 00:00:00 2001 From: Auryn Macmillan Date: Thu, 19 Sep 2024 14:10:38 -0400 Subject: [PATCH 85/87] fix: only call `transferOwnership()` if `_owner` and `owner()` do not match --- packages/evm/contracts/registry/CiphernodeRegistryOwnable.sol | 2 +- packages/evm/contracts/registry/NaiveRegistryFilter.sol | 2 +- packages/evm/contracts/test/MockRegistryFilter.sol | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/evm/contracts/registry/CiphernodeRegistryOwnable.sol b/packages/evm/contracts/registry/CiphernodeRegistryOwnable.sol index 8997f690..1c645307 100644 --- a/packages/evm/contracts/registry/CiphernodeRegistryOwnable.sol +++ b/packages/evm/contracts/registry/CiphernodeRegistryOwnable.sol @@ -65,7 +65,7 @@ contract CiphernodeRegistryOwnable is ICiphernodeRegistry, OwnableUpgradeable { function initialize(address _owner, address _enclave) public initializer { __Ownable_init(msg.sender); setEnclave(_enclave); - transferOwnership(_owner); + if (_owner != owner()) transferOwnership(_owner); } //////////////////////////////////////////////////////////// diff --git a/packages/evm/contracts/registry/NaiveRegistryFilter.sol b/packages/evm/contracts/registry/NaiveRegistryFilter.sol index ccc565a6..a8694196 100644 --- a/packages/evm/contracts/registry/NaiveRegistryFilter.sol +++ b/packages/evm/contracts/registry/NaiveRegistryFilter.sol @@ -60,7 +60,7 @@ contract NaiveRegistryFilter is IRegistryFilter, OwnableUpgradeable { function initialize(address _owner, address _registry) public initializer { __Ownable_init(msg.sender); setRegistry(_registry); - transferOwnership(_owner); + if (_owner != owner()) transferOwnership(_owner); } //////////////////////////////////////////////////////////// diff --git a/packages/evm/contracts/test/MockRegistryFilter.sol b/packages/evm/contracts/test/MockRegistryFilter.sol index 4899f574..f0abc7a3 100644 --- a/packages/evm/contracts/test/MockRegistryFilter.sol +++ b/packages/evm/contracts/test/MockRegistryFilter.sol @@ -67,7 +67,7 @@ contract MockNaiveRegistryFilter is IRegistryFilter, OwnableUpgradeable { function initialize(address _owner, address _registry) public initializer { __Ownable_init(msg.sender); setRegistry(_registry); - transferOwnership(_owner); + if (_owner != owner()) transferOwnership(_owner); } //////////////////////////////////////////////////////////// From 1cdfb336f62b586d8008ae01604f956b3575f24b Mon Sep 17 00:00:00 2001 From: samepant Date: Thu, 19 Sep 2024 15:30:48 -0400 Subject: [PATCH 86/87] add gh action for releasing evm package --- .github/workflows/publish-evm.yml | 23 +++++++++++++++++++++++ package.json | 3 ++- packages/evm/package.json | 8 +++++--- 3 files changed, 30 insertions(+), 4 deletions(-) create mode 100644 .github/workflows/publish-evm.yml diff --git a/.github/workflows/publish-evm.yml b/.github/workflows/publish-evm.yml new file mode 100644 index 00000000..9bd86220 --- /dev/null +++ b/.github/workflows/publish-evm.yml @@ -0,0 +1,23 @@ +name: EVM Version release + +on: + release: + types: [created] + +env: + HARDHAT_VAR_MNEMONIC: "test test test test test test test test test test test junk" + HARDHAT_VAR_INFURA_API_KEY: "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + +jobs: + publish-npm: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-node@v2 + with: + node-version: 20 + - run: yarn + - run: yarn evm:release + env: + NPM_AUTH_TOKEN: ${{secrets.PUBLISH_NPM_TOKEN}} + YARN_REGISTRY: https://registry.npmjs.org/ diff --git a/package.json b/package.json index a37d2efb..69448f37 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,8 @@ "evm:typechain": "cd packages/evm && yarn typechain", "evm:test": "cd packages/evm && yarn test", "evm:coverage": "cd packages/evm && yarn coverage", - "preinstall": "yarn evm:install" + "preinstall": "yarn evm:install", + "evm:release": "cd packages/evm && yarn release" }, "dependencies": {} } diff --git a/packages/evm/package.json b/packages/evm/package.json index 698ba42c..cc897ff5 100644 --- a/packages/evm/package.json +++ b/packages/evm/package.json @@ -1,7 +1,7 @@ { - "name": "@gnosisguild/enclave", + "name": "@gnosis-guild/enclave", "description": "Enclave is an open-source protocol for Encrypted Execution Environments (E3).", - "version": "0.0.0", + "version": "0.0.1", "license": "LGPL-3.0-only", "author": { "name": "gnosisguild", @@ -85,7 +85,9 @@ "task:deployLock": "hardhat task:deployLock", "task:withdraw": "hardhat task:withdraw", "test": "hardhat test", - "typechain": "cross-env TS_NODE_TRANSPILE_ONLY=true hardhat typechain" + "typechain": "cross-env TS_NODE_TRANSPILE_ONLY=true hardhat typechain", + "prerelease": "yarn clean && yarn compile && yarn typechain", + "release": "yarn publish --non-interactive" }, "dependencies": {} } From 10e48334dca45614467958cc0d9f9a844c5388c9 Mon Sep 17 00:00:00 2001 From: Auryn Macmillan Date: Thu, 19 Sep 2024 15:43:37 -0400 Subject: [PATCH 87/87] hash given outputs and pass output hash to corresponding verifiers --- packages/evm/contracts/Enclave.sol | 36 ++++++---- .../interfaces/IDecryptionVerifier.sol | 10 +-- packages/evm/contracts/interfaces/IE3.sol | 4 +- .../evm/contracts/interfaces/IE3Program.sol | 9 +-- .../evm/contracts/interfaces/IEnclave.sol | 13 ++-- .../contracts/test/MockDecryptionVerifier.sol | 7 +- packages/evm/contracts/test/MockE3Program.sol | 7 +- packages/evm/test/Enclave.spec.ts | 68 ++++++++++--------- 8 files changed, 86 insertions(+), 68 deletions(-) diff --git a/packages/evm/contracts/Enclave.sol b/packages/evm/contracts/Enclave.sol index f6649d05..88e27fa3 100644 --- a/packages/evm/contracts/Enclave.sol +++ b/packages/evm/contracts/Enclave.sol @@ -228,7 +228,8 @@ contract Enclave is IEnclave, OwnableUpgradeable { function publishCiphertextOutput( uint256 e3Id, - bytes memory data + bytes memory ciphertextOutput, + bytes memory proof ) external returns (bool success) { E3 memory e3 = getE3(e3Id); // Note: if we make 0 a no expiration, this has to be refactored @@ -240,38 +241,43 @@ contract Enclave is IEnclave, OwnableUpgradeable { // TODO: should the output verifier be able to change its mind? //i.e. should we be able to call this multiple times? require( - e3.ciphertextOutput.length == 0, + e3.ciphertextOutput == bytes32(0), CiphertextOutputAlreadyPublished(e3Id) ); - bytes memory output; - (output, success) = e3.e3Program.verify(e3Id, data); - require(success, InvalidOutput(output)); - e3s[e3Id].ciphertextOutput = output; + bytes32 ciphertextOutputHash = keccak256(ciphertextOutput); + (success) = e3.e3Program.verify(e3Id, ciphertextOutputHash, proof); + require(success, InvalidOutput(ciphertextOutput)); + e3s[e3Id].ciphertextOutput = ciphertextOutputHash; - emit CiphertextOutputPublished(e3Id, output); + emit CiphertextOutputPublished(e3Id, ciphertextOutput); } function publishPlaintextOutput( uint256 e3Id, - bytes memory data + bytes memory plaintextOutput, + bytes memory proof ) external returns (bool success) { E3 memory e3 = getE3(e3Id); // Note: if we make 0 a no expiration, this has to be refactored require(e3.expiration > 0, E3NotActivated(e3Id)); require( - e3.ciphertextOutput.length > 0, + e3.ciphertextOutput != bytes32(0), CiphertextOutputNotPublished(e3Id) ); require( - e3.plaintextOutput.length == 0, + e3.plaintextOutput == bytes32(0), PlaintextOutputAlreadyPublished(e3Id) ); - bytes memory output; - (output, success) = e3.decryptionVerifier.verify(e3Id, data); - require(success, InvalidOutput(output)); - e3s[e3Id].plaintextOutput = output; + bytes32 plaintextOutputHash = keccak256(plaintextOutput); + (success) = e3.decryptionVerifier.verify( + e3Id, + plaintextOutputHash, + proof + ); + require(success, InvalidOutput(plaintextOutput)); + e3s[e3Id].plaintextOutput = plaintextOutputHash; - emit PlaintextOutputPublished(e3Id, output); + emit PlaintextOutputPublished(e3Id, plaintextOutput); } //////////////////////////////////////////////////////////// diff --git a/packages/evm/contracts/interfaces/IDecryptionVerifier.sol b/packages/evm/contracts/interfaces/IDecryptionVerifier.sol index 9c71e9df..d5221a37 100644 --- a/packages/evm/contracts/interfaces/IDecryptionVerifier.sol +++ b/packages/evm/contracts/interfaces/IDecryptionVerifier.sol @@ -5,10 +5,12 @@ interface IDecryptionVerifier { /// @notice This function should be called by the Enclave contract to verify the /// decryption of output of a computation. /// @param e3Id ID of the E3. - /// @param data ABI encoded output data to be verified. - /// @return output Plaintext output of the given computation. + /// @param plaintextOutputHash The keccak256 hash of the plaintext output to be verified. + /// @param proof ABI encoded proof of the given output hash. + /// @return success Whether or not the plaintextOutputHash was successfully verified. function verify( uint256 e3Id, - bytes memory data - ) external view returns (bytes memory output, bool success); + bytes32 plaintextOutputHash, + bytes memory proof + ) external view returns (bool success); } diff --git a/packages/evm/contracts/interfaces/IE3.sol b/packages/evm/contracts/interfaces/IE3.sol index 51a9daab..f2fb94bd 100644 --- a/packages/evm/contracts/interfaces/IE3.sol +++ b/packages/evm/contracts/interfaces/IE3.sol @@ -29,6 +29,6 @@ struct E3 { IInputValidator inputValidator; IDecryptionVerifier decryptionVerifier; bytes committeePublicKey; - bytes ciphertextOutput; - bytes plaintextOutput; + bytes32 ciphertextOutput; + bytes32 plaintextOutput; } diff --git a/packages/evm/contracts/interfaces/IE3Program.sol b/packages/evm/contracts/interfaces/IE3Program.sol index 601dc4f4..a65224f4 100644 --- a/packages/evm/contracts/interfaces/IE3Program.sol +++ b/packages/evm/contracts/interfaces/IE3Program.sol @@ -26,11 +26,12 @@ interface IE3Program { /// @notice This function should be called by the Enclave contract to verify the decrypted output of an E3. /// @param e3Id ID of the E3. - /// @param outputData ABI encoded output data to be verified. - /// @return output The output data to be published. + /// @param ciphertextOutputHash The keccak256 hash of output data to be verified. + /// @param proof ABI encoded data to verify the ciphertextOutputHash. /// @return success Whether the output data is valid. function verify( uint256 e3Id, - bytes memory outputData - ) external returns (bytes memory output, bool success); + bytes32 ciphertextOutputHash, + bytes memory proof + ) external returns (bool success); } diff --git a/packages/evm/contracts/interfaces/IEnclave.sol b/packages/evm/contracts/interfaces/IEnclave.sol index 246bc3d9..ffb47391 100644 --- a/packages/evm/contracts/interfaces/IEnclave.sol +++ b/packages/evm/contracts/interfaces/IEnclave.sol @@ -122,22 +122,25 @@ interface IEnclave { /// @notice This function should be called to publish output data for an Encrypted Execution Environment (E3). /// @dev This function MUST emit the CiphertextOutputPublished event. /// @param e3Id ID of the E3. - /// @param data ABI encoded output data to verify. + /// @param ciphertextOutput ABI encoded output data to verify. + /// @param proof ABI encoded data to verify the ciphertextOutput. /// @return success True if the output was successfully published. function publishCiphertextOutput( uint256 e3Id, - bytes memory data + bytes memory ciphertextOutput, + bytes memory proof ) external returns (bool success); /// @notice This function publishes the plaintext output of an Encrypted Execution Environment (E3). /// @dev This function MUST revert if the output has not been published. /// @dev This function MUST emit the PlaintextOutputPublished event. /// @param e3Id ID of the E3. - /// @param data ABI encoded output data to decrypt. - /// @return success True if the output was successfully decrypted. + /// @param plaintextOutput ABI encoded plaintext output. + /// @param proof ABI encoded data to verify the plaintextOutput. function publishPlaintextOutput( uint256 e3Id, - bytes memory data + bytes memory plaintextOutput, + bytes memory proof ) external returns (bool success); //////////////////////////////////////////////////////////// diff --git a/packages/evm/contracts/test/MockDecryptionVerifier.sol b/packages/evm/contracts/test/MockDecryptionVerifier.sol index d2977901..7bbf68d3 100644 --- a/packages/evm/contracts/test/MockDecryptionVerifier.sol +++ b/packages/evm/contracts/test/MockDecryptionVerifier.sol @@ -6,10 +6,11 @@ import { IDecryptionVerifier } from "../interfaces/IDecryptionVerifier.sol"; contract MockDecryptionVerifier is IDecryptionVerifier { function verify( uint256, + bytes32, bytes memory data - ) external pure returns (bytes memory output, bool success) { - output = data; + ) external pure returns (bool success) { + data; - if (output.length > 0) success = true; + if (data.length > 0) success = true; } } diff --git a/packages/evm/contracts/test/MockE3Program.sol b/packages/evm/contracts/test/MockE3Program.sol index d8ff026c..7cc7112c 100644 --- a/packages/evm/contracts/test/MockE3Program.sol +++ b/packages/evm/contracts/test/MockE3Program.sol @@ -36,9 +36,10 @@ contract MockE3Program is IE3Program { function verify( uint256, + bytes32, bytes memory data - ) external pure returns (bytes memory output, bool success) { - output = data; - if (output.length > 0) success = true; + ) external pure returns (bool success) { + data; + if (data.length > 0) success = true; } } diff --git a/packages/evm/test/Enclave.spec.ts b/packages/evm/test/Enclave.spec.ts index 22d53939..ea9a64cc 100644 --- a/packages/evm/test/Enclave.spec.ts +++ b/packages/evm/test/Enclave.spec.ts @@ -24,6 +24,10 @@ const AddressSix = "0x0000000000000000000000000000000000000006"; const FilterFail = AddressTwo; const FilterOkay = AddressSix; +const data = "0xda7a"; +const dataHash = ethers.keccak256(data); +const proof = "0x1337"; + // Hash function used to compute the tree nodes. const hash = (a: bigint, b: bigint) => poseidon2([a, b]); @@ -203,8 +207,8 @@ describe("Enclave", function () { abiCoder.decode(["address"], request.computeProviderParams)[0], ); expect(e3.committeePublicKey).to.equal("0x"); - expect(e3.ciphertextOutput).to.equal("0x"); - expect(e3.plaintextOutput).to.equal("0x"); + expect(e3.ciphertextOutput).to.equal(ethers.ZeroHash); + expect(e3.plaintextOutput).to.equal(ethers.ZeroHash); }); }); @@ -460,8 +464,8 @@ describe("Enclave", function () { abiCoder.decode(["address"], request.computeProviderParams)[0], ); expect(e3.committeePublicKey).to.equal("0x"); - expect(e3.ciphertextOutput).to.equal("0x"); - expect(e3.plaintextOutput).to.equal("0x"); + expect(e3.ciphertextOutput).to.equal(ethers.ZeroHash); + expect(e3.plaintextOutput).to.equal(ethers.ZeroHash); }); it("emits E3Requested event", async function () { const { enclave, request } = await loadFixture(setup); @@ -864,7 +868,7 @@ describe("Enclave", function () { it("reverts if E3 does not exist", async function () { const { enclave } = await loadFixture(setup); - await expect(enclave.publishCiphertextOutput(0, "0x")) + await expect(enclave.publishCiphertextOutput(0, "0x", "0x")) .to.be.revertedWithCustomError(enclave, "E3DoesNotExist") .withArgs(0); }); @@ -882,7 +886,7 @@ describe("Enclave", function () { request.computeProviderParams, { value: 10 }, ); - await expect(enclave.publishCiphertextOutput(e3Id, "0x")) + await expect(enclave.publishCiphertextOutput(e3Id, "0x", "0x")) .to.be.revertedWithCustomError(enclave, "E3NotActivated") .withArgs(e3Id); }); @@ -905,7 +909,7 @@ describe("Enclave", function () { await enclave.activate(e3Id); - await expect(enclave.publishCiphertextOutput(e3Id, "0x")) + await expect(enclave.publishCiphertextOutput(e3Id, "0x", "0x")) .to.be.revertedWithCustomError(enclave, "InputDeadlineNotPassed") .withArgs(e3Id, expectedExpiration); }); @@ -925,8 +929,8 @@ describe("Enclave", function () { ); await enclave.activate(e3Id); await mine(2, { interval: request.duration }); - expect(await enclave.publishCiphertextOutput(e3Id, "0x1337")); - await expect(enclave.publishCiphertextOutput(e3Id, "0x1337")) + expect(await enclave.publishCiphertextOutput(e3Id, data, proof)); + await expect(enclave.publishCiphertextOutput(e3Id, data, proof)) .to.be.revertedWithCustomError( enclave, "CiphertextOutputAlreadyPublished", @@ -950,7 +954,7 @@ describe("Enclave", function () { await enclave.activate(e3Id); await mine(2, { interval: request.duration }); await expect( - enclave.publishCiphertextOutput(e3Id, "0x"), + enclave.publishCiphertextOutput(e3Id, "0x", "0x"), ).to.be.revertedWithCustomError(enclave, "InvalidOutput"); }); it("sets ciphertextOutput correctly", async function () { @@ -969,9 +973,9 @@ describe("Enclave", function () { ); await enclave.activate(e3Id); await mine(2, { interval: request.duration }); - expect(await enclave.publishCiphertextOutput(e3Id, "0x1337")); + expect(await enclave.publishCiphertextOutput(e3Id, data, proof)); const e3 = await enclave.getE3(e3Id); - expect(e3.ciphertextOutput).to.equal("0x1337"); + expect(e3.ciphertextOutput).to.equal(dataHash); }); it("returns true if output is published successfully", async function () { const { enclave, request } = await loadFixture(setup); @@ -990,7 +994,7 @@ describe("Enclave", function () { await enclave.activate(e3Id); await mine(2, { interval: request.duration }); expect( - await enclave.publishCiphertextOutput.staticCall(e3Id, "0x1337"), + await enclave.publishCiphertextOutput.staticCall(e3Id, data, proof), ).to.equal(true); }); it("emits CiphertextOutputPublished event", async function () { @@ -1009,9 +1013,9 @@ describe("Enclave", function () { ); await enclave.activate(e3Id); await mine(2, { interval: request.duration }); - await expect(enclave.publishCiphertextOutput(e3Id, "0x1337")) + await expect(enclave.publishCiphertextOutput(e3Id, data, proof)) .to.emit(enclave, "CiphertextOutputPublished") - .withArgs(e3Id, "0x1337"); + .withArgs(e3Id, data); }); }); @@ -1020,7 +1024,7 @@ describe("Enclave", function () { const { enclave } = await loadFixture(setup); const e3Id = 0; - await expect(enclave.publishPlaintextOutput(e3Id, "0x")) + await expect(enclave.publishPlaintextOutput(e3Id, data, "0x")) .to.be.revertedWithCustomError(enclave, "E3DoesNotExist") .withArgs(e3Id); }); @@ -1038,7 +1042,7 @@ describe("Enclave", function () { request.computeProviderParams, { value: 10 }, ); - await expect(enclave.publishPlaintextOutput(e3Id, "0x")) + await expect(enclave.publishPlaintextOutput(e3Id, data, "0x")) .to.be.revertedWithCustomError(enclave, "E3NotActivated") .withArgs(e3Id); }); @@ -1057,7 +1061,7 @@ describe("Enclave", function () { { value: 10 }, ); await enclave.activate(e3Id); - await expect(enclave.publishPlaintextOutput(e3Id, "0x")) + await expect(enclave.publishPlaintextOutput(e3Id, data, "0x")) .to.be.revertedWithCustomError(enclave, "CiphertextOutputNotPublished") .withArgs(e3Id); }); @@ -1077,9 +1081,9 @@ describe("Enclave", function () { ); await enclave.activate(e3Id); await mine(2, { interval: request.duration }); - await enclave.publishCiphertextOutput(e3Id, "0x1337"); - await enclave.publishPlaintextOutput(e3Id, "0x1337"); - await expect(enclave.publishPlaintextOutput(e3Id, "0x1337")) + await enclave.publishCiphertextOutput(e3Id, data, proof); + await enclave.publishPlaintextOutput(e3Id, data, proof); + await expect(enclave.publishPlaintextOutput(e3Id, data, proof)) .to.be.revertedWithCustomError( enclave, "PlaintextOutputAlreadyPublished", @@ -1102,10 +1106,10 @@ describe("Enclave", function () { ); await enclave.activate(e3Id); await mine(2, { interval: request.duration }); - await enclave.publishCiphertextOutput(e3Id, "0x1337"); - await expect(enclave.publishPlaintextOutput(e3Id, "0x")) + await enclave.publishCiphertextOutput(e3Id, data, proof); + await expect(enclave.publishPlaintextOutput(e3Id, data, "0x")) .to.be.revertedWithCustomError(enclave, "InvalidOutput") - .withArgs("0x"); + .withArgs(data); }); it("sets plaintextOutput correctly", async function () { const { enclave, request } = await loadFixture(setup); @@ -1123,11 +1127,11 @@ describe("Enclave", function () { ); await enclave.activate(e3Id); await mine(2, { interval: request.duration }); - await enclave.publishCiphertextOutput(e3Id, "0x1337"); - expect(await enclave.publishPlaintextOutput(e3Id, "0x1337")); + await enclave.publishCiphertextOutput(e3Id, data, proof); + expect(await enclave.publishPlaintextOutput(e3Id, data, proof)); const e3 = await enclave.getE3(e3Id); - expect(e3.plaintextOutput).to.equal("0x1337"); + expect(e3.plaintextOutput).to.equal(dataHash); }); it("returns true if output is published successfully", async function () { const { enclave, request } = await loadFixture(setup); @@ -1145,9 +1149,9 @@ describe("Enclave", function () { ); await enclave.activate(e3Id); await mine(2, { interval: request.duration }); - await enclave.publishCiphertextOutput(e3Id, "0x1337"); + await enclave.publishCiphertextOutput(e3Id, data, proof); expect( - await enclave.publishPlaintextOutput.staticCall(e3Id, "0x1337"), + await enclave.publishPlaintextOutput.staticCall(e3Id, data, proof), ).to.equal(true); }); it("emits PlaintextOutputPublished event", async function () { @@ -1166,10 +1170,10 @@ describe("Enclave", function () { ); await enclave.activate(e3Id); await mine(2, { interval: request.duration }); - await enclave.publishCiphertextOutput(e3Id, "0x1337"); - await expect(await enclave.publishPlaintextOutput(e3Id, "0x1337")) + await enclave.publishCiphertextOutput(e3Id, data, proof); + await expect(await enclave.publishPlaintextOutput(e3Id, data, proof)) .to.emit(enclave, "PlaintextOutputPublished") - .withArgs(e3Id, "0x1337"); + .withArgs(e3Id, data); }); }); });