diff --git a/packages/ciphernode/core/src/e3_request.rs b/packages/ciphernode/core/src/e3_request.rs index c59f3a16..0df4c472 100644 --- a/packages/ciphernode/core/src/e3_request.rs +++ b/packages/ciphernode/core/src/e3_request.rs @@ -1,17 +1,17 @@ -use std::collections::HashMap; +use std::{collections::HashMap, sync::Arc}; use actix::{Actor, Addr, Context, Handler, Recipient}; use crate::{ - Ciphernode, CommitteeMeta, E3id, EnclaveEvent, EventBus, Fhe, PlaintextAggregator, + Keyshare, 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 keyshare: Option>, + pub fhe: Option>, pub plaintext: Option>, pub publickey: Option>, pub meta: Option, @@ -38,8 +38,8 @@ impl E3RequestContext { fn recipients(&self) -> Vec<(String, Option>)> { vec![ ( - "ciphernode".to_owned(), - self.ciphernode.clone().map(|addr| addr.into()), + "keyshare".to_owned(), + self.keyshare.clone().map(|addr| addr.into()), ), ( "plaintext".to_owned(), @@ -66,12 +66,6 @@ impl E3RequestContext { } } -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 diff --git a/packages/ciphernode/core/src/events.rs b/packages/ciphernode/core/src/events.rs index d61ee000..01dcbd95 100644 --- a/packages/ciphernode/core/src/events.rs +++ b/packages/ciphernode/core/src/events.rs @@ -345,15 +345,13 @@ impl EnclaveEvent { #[cfg(test)] mod tests { use super::EnclaveEvent; - use crate::{ - events::extract_enclave_event_name, serializers::PublicKeyShareSerializer, E3id, - KeyshareCreated, - }; + use crate::{events::extract_enclave_event_name, E3id, KeyshareCreated}; use alloy_primitives::address; use fhe::{ bfv::{BfvParametersBuilder, SecretKey}, mbfv::{CommonRandomPoly, PublicKeyShare}, }; + use fhe_traits::Serialize; use rand::SeedableRng; use rand_chacha::ChaCha20Rng; use std::error::Error; @@ -384,7 +382,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 = PublicKeyShareSerializer::to_bytes(pk_share, params.clone(), crp.clone())?; + let pubkey = pk_share.to_bytes(); 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 7085f7a1..be3189b7 100644 --- a/packages/ciphernode/core/src/fhe.rs +++ b/packages/ciphernode/core/src/fhe.rs @@ -1,45 +1,24 @@ -use crate::{ - ordered_set::OrderedSet, - serializers::{ - CiphertextSerializer, DecryptionShareSerializer, PublicKeySerializer, - PublicKeyShareSerializer, SecretKeySerializer, - }, - ActorFactory, E3Requested, EnclaveEvent, -}; -use actix::{Actor, Context, Handler, Message}; +use crate::{ordered_set::OrderedSet, ActorFactory, E3Requested, EnclaveEvent}; use anyhow::*; use fhe::{ - bfv::{BfvParameters, BfvParametersBuilder, Encoding, Plaintext, PublicKey, SecretKey}, + bfv::{ + BfvParameters, BfvParametersBuilder, Ciphertext, Encoding, Plaintext, PublicKey, SecretKey, + }, mbfv::{AggregateIter, CommonRandomPoly, DecryptionShare, PublicKeyShare}, }; -use fhe_traits::{FheDecoder, Serialize}; -use rand::SeedableRng; -use rand_chacha::{ChaCha20Rng, ChaCha8Rng}; -use std::{ - hash::Hash, - sync::{Arc, Mutex}, -}; +use fhe_traits::{DeserializeParametrized, FheDecoder, Serialize}; +use rand_chacha::ChaCha20Rng; +use std::sync::{Arc, Mutex}; -#[derive(Message, Clone, Debug, PartialEq, Eq, Hash)] -#[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<(Vec)>")] pub struct GetAggregatePublicKey { pub keyshares: OrderedSet>, } -#[derive(Message, Clone, Debug, PartialEq, Eq)] -#[rtype(result = "Result<(Vec)>")] pub struct GetAggregatePlaintext { pub decryptions: OrderedSet>, + pub ciphertext_output: Vec, } -#[derive(Message, Clone, Debug, PartialEq, Eq)] -#[rtype(result = "Result<(Vec)>")] pub struct DecryptCiphertext { pub unsafe_secret: Vec, pub ciphertext: Vec, @@ -47,49 +26,19 @@ pub struct DecryptCiphertext { pub type SharedRng = Arc>; -/// Fhe library adaptor. All FHE computations should happen through this actor. +/// Fhe library adaptor. +#[derive(Clone)] pub struct Fhe { params: Arc, crp: CommonRandomPoly, rng: SharedRng, } -impl Actor for Fhe { - type Context = Context; -} - impl Fhe { pub fn new(params: Arc, crp: CommonRandomPoly, rng: SharedRng) -> Self { Self { params, crp, rng } } - // 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 = 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, - )?) - } - pub fn from_raw_params( moduli: &[u64], degree: usize, @@ -109,77 +58,56 @@ impl Fhe { rng, )) } -} -impl Handler for Fhe { - type Result = Result<(Vec, Vec)>; - fn handle(&mut self, _event: GenerateKeyshare, _: &mut Self::Context) -> Self::Result { + pub fn generate_keyshare(&self) -> Result<(Vec, Vec)> { 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())?, + SecretKeySerializer::to_bytes(sk_share)?, + pk_share.to_bytes(), )) } -} -impl Handler for Fhe { - type Result = Result>; - fn handle(&mut self, msg: DecryptCiphertext, _: &mut Self::Context) -> Self::Result { + pub fn decrypt_ciphertext(&self, msg: DecryptCiphertext) -> Result> { let DecryptCiphertext { - unsafe_secret, // TODO: fix security issues with sending secrets between actors + unsafe_secret, ciphertext, } = msg; - 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.lock().unwrap()).unwrap(); - - Ok(DecryptionShareSerializer::to_bytes( - inner, - self.params.clone(), - ct.clone(), - )?) + let secret_key = SecretKeySerializer::from_bytes(&unsafe_secret, self.params.clone())?; + let ct = Arc::new( + Ciphertext::from_bytes(&ciphertext, &self.params) + .context("Error deserializing ciphertext")?, + ); + let decryption_share = + DecryptionShare::new(&secret_key, &ct, &mut *self.rng.lock().unwrap()).unwrap(); + Ok(decryption_share.to_bytes()) } -} -impl Handler for Fhe { - type Result = Result>; - - fn handle(&mut self, msg: GetAggregatePublicKey, _: &mut Self::Context) -> Self::Result { + pub fn get_aggregate_public_key(&self, msg: GetAggregatePublicKey) -> Result> { let public_key: PublicKey = msg .keyshares .iter() - .map(|k| PublicKeyShareSerializer::from_bytes(k)) - .collect::>>()? - .into_iter() + .map(|k| PublicKeyShare::deserialize(k, &self.params, self.crp.clone())) .aggregate()?; Ok(public_key.to_bytes()) } -} -impl Handler for Fhe { - type Result = Result>; - fn handle(&mut self, msg: GetAggregatePlaintext, _: &mut Self::Context) -> Self::Result { + pub fn get_aggregate_plaintext(&self, msg: GetAggregatePlaintext) -> Result> { + let arc_ct = Arc::new(Ciphertext::from_bytes( + &msg.ciphertext_output, + &self.params, + )?); + let plaintext: Plaintext = msg .decryptions .iter() - .map(|k| DecryptionShareSerializer::from_bytes(k)) - .collect::>>()? - .into_iter() + .map(|k| DecryptionShare::deserialize(k, &self.params, arc_ct.clone())) .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 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)?) } } @@ -201,11 +129,45 @@ impl FheFactory { .. } = data; - ctx.fhe = Some( + ctx.fhe = Some(Arc::new( Fhe::from_raw_params(&moduli, degree, plaintext_modulus, &crp, rng.clone()) - .unwrap() - .start(), - ); + .unwrap(), + )); + }) + } +} + +struct SecretKeySerializer { + pub inner: SecretKey, +} + +impl SecretKeySerializer { + pub fn to_bytes(inner: SecretKey) -> Result> { + let value = Self { inner }; + Ok(value.unsafe_serialize()?) + } + + pub fn from_bytes(bytes: &[u8], params: Arc) -> Result { + Ok(Self::deserialize(bytes, params)?.inner) + } +} + +#[derive(serde::Serialize, serde::Deserialize)] +struct SecretKeyData { + coeffs: Box<[i64]>, +} + +impl SecretKeySerializer { + pub fn unsafe_serialize(&self) -> Result> { + Ok(bincode::serialize(&SecretKeyData { + coeffs: self.inner.coeffs.clone(), + })?) + } + + pub fn deserialize(bytes: &[u8], params: Arc) -> Result { + let SecretKeyData { coeffs } = bincode::deserialize(&bytes)?; + Ok(Self { + inner: SecretKey::new(coeffs.to_vec(), ¶ms), }) } } diff --git a/packages/ciphernode/core/src/ciphernode.rs b/packages/ciphernode/core/src/keyshare.rs similarity index 75% rename from packages/ciphernode/core/src/ciphernode.rs rename to packages/ciphernode/core/src/keyshare.rs index 002bb3df..69f6aba6 100644 --- a/packages/ciphernode/core/src/ciphernode.rs +++ b/packages/ciphernode/core/src/keyshare.rs @@ -1,40 +1,43 @@ +use std::sync::Arc; + use crate::{ data::{Data, Insert}, eventbus::EventBus, events::{EnclaveEvent, KeyshareCreated}, - fhe::{Fhe, GenerateKeyshare}, + fhe::Fhe, ActorFactory, CiphernodeSelected, CiphertextOutputPublished, DecryptCiphertext, DecryptionshareCreated, Get, }; use actix::prelude::*; use anyhow::Result; +use anyhow::Context; -pub struct Ciphernode { - fhe: Addr, +pub struct Keyshare { + fhe: Arc, data: Addr, bus: Addr, address: String, } -impl Actor for Ciphernode { - type Context = Context; +impl Actor for Keyshare { + type Context = actix::Context; } -impl Ciphernode { - pub fn new(bus: Addr, fhe: Addr, data: Addr, address: &str) -> Self { +impl Keyshare { + pub fn new(bus: Addr, data: Addr, fhe: Arc, address: &str) -> Self { Self { bus, fhe, data, - address:address.to_string(), + address: address.to_string(), } } } -impl Handler for Ciphernode { +impl Handler for Keyshare { type Result = (); - fn handle(&mut self, event: EnclaveEvent, ctx: &mut Context) -> Self::Result { + fn handle(&mut self, event: EnclaveEvent, ctx: &mut actix::Context) -> Self::Result { match event { EnclaveEvent::CiphernodeSelected { data, .. } => ctx.address().do_send(data), EnclaveEvent::CiphertextOutputPublished { data, .. } => ctx.address().do_send(data), @@ -43,10 +46,10 @@ impl Handler for Ciphernode { } } -impl Handler for Ciphernode { +impl Handler for Keyshare { type Result = ResponseFuture<()>; - fn handle(&mut self, event: CiphernodeSelected, _: &mut Context) -> Self::Result { + fn handle(&mut self, event: CiphernodeSelected, _: &mut actix::Context) -> Self::Result { let fhe = self.fhe.clone(); let data = self.data.clone(); let bus = self.bus.clone(); @@ -59,10 +62,10 @@ impl Handler for Ciphernode { } } -impl Handler for Ciphernode { +impl Handler for Keyshare { type Result = ResponseFuture<()>; - fn handle(&mut self, event: CiphertextOutputPublished, _: &mut Context) -> Self::Result { + fn handle(&mut self, event: CiphertextOutputPublished, _: &mut actix::Context) -> Self::Result { println!("Ciphernode::CiphertextOutputPublished"); let fhe = self.fhe.clone(); let data = self.data.clone(); @@ -77,7 +80,7 @@ impl Handler for Ciphernode { } async fn on_ciphernode_selected( - fhe: Addr, + fhe: Arc, data: Addr, bus: Addr, event: CiphernodeSelected, @@ -86,7 +89,7 @@ async fn on_ciphernode_selected( let CiphernodeSelected { e3_id, .. } = event; // generate keyshare - let (sk, pubkey) = fhe.send(GenerateKeyshare {}).await??; + let (sk, pubkey) = fhe.generate_keyshare()?; // TODO: decrypt from FHE actor // save encrypted key against e3_id/sk @@ -110,7 +113,7 @@ async fn on_ciphernode_selected( } async fn on_decryption_requested( - fhe: Addr, + fhe: Arc, data: Addr, bus: Addr, event: CiphertextOutputPublished, @@ -128,12 +131,10 @@ async fn on_decryption_requested( println!("\n\nDECRYPTING!\n\n"); - let decryption_share = fhe - .send(DecryptCiphertext { - ciphertext: ciphertext_output, - unsafe_secret, - }) - .await??; + let decryption_share = fhe.decrypt_ciphertext(DecryptCiphertext { + ciphertext: ciphertext_output, + unsafe_secret, + }).context("error decrypting ciphertext")?; let event = EnclaveEvent::from(DecryptionshareCreated { e3_id, @@ -146,8 +147,8 @@ async fn on_decryption_requested( Ok(()) } -pub struct CiphernodeFactory; -impl CiphernodeFactory { +pub struct KeyshareFactory; +impl KeyshareFactory { pub fn create(bus: Addr, data: Addr, address: &str) -> ActorFactory { let address = address.to_string(); Box::new(move |ctx, evt| { @@ -160,8 +161,8 @@ impl CiphernodeFactory { return; }; - ctx.ciphernode = - Some(Ciphernode::new(bus.clone(), fhe.clone(), data.clone(), &address).start()) + ctx.keyshare = + Some(Keyshare::new(bus.clone(), data.clone(), fhe.clone(), &address).start()) }) } } diff --git a/packages/ciphernode/core/src/lib.rs b/packages/ciphernode/core/src/lib.rs index 5d9635c9..e2d4ac42 100644 --- a/packages/ciphernode/core/src/lib.rs +++ b/packages/ciphernode/core/src/lib.rs @@ -3,7 +3,6 @@ // #![warn(missing_docs, unused_imports)] mod cipernode_selector; -mod ciphernode; mod committee_meta; mod data; mod e3_request; @@ -14,38 +13,37 @@ mod evm_enclave; mod evm_listener; mod evm_manager; mod fhe; +mod keyshare; mod logger; mod main_aggregator; mod main_ciphernode; mod ordered_set; mod p2p; mod plaintext_aggregator; +mod plaintext_writer; +mod public_key_writer; mod publickey_aggregator; -mod serializers; mod sortition; mod utils; -mod public_key_writer; -mod plaintext_writer; // TODO: this is too permissive pub use actix::prelude::*; pub use cipernode_selector::*; -pub use ciphernode::*; pub use committee_meta::*; pub use data::*; pub use e3_request::*; pub use eventbus::*; pub use events::*; pub use fhe::*; +pub use keyshare::*; pub use logger::*; pub use main_aggregator::*; pub use main_ciphernode::*; pub use p2p::*; pub use plaintext_aggregator::*; -pub use publickey_aggregator::*; -pub use public_key_writer::*; pub use plaintext_writer::*; -pub use serializers::*; +pub use public_key_writer::*; +pub use publickey_aggregator::*; pub use sortition::*; pub use utils::*; @@ -58,12 +56,10 @@ mod tests { eventbus::{EventBus, GetHistory}, events::{E3Requested, E3id, EnclaveEvent, KeyshareCreated, PublicKeyAggregated}, p2p::P2p, - serializers::{CiphertextSerializer, DecryptionShareSerializer, PublicKeyShareSerializer}, utils::{setup_crp_params, ParamsWithCrp}, - CiphernodeAdded, CiphernodeFactory, CiphernodeSelected, CiphertextOutputPublished, - CommitteeMetaFactory, DecryptionshareCreated, E3RequestManager, FheFactory, - PlaintextAggregated, PlaintextAggregatorFactory, PublicKeyAggregatorFactory, ResetHistory, - SharedRng, Sortition, + CiphernodeAdded, CiphernodeSelected, CiphertextOutputPublished, CommitteeMetaFactory, + DecryptionshareCreated, E3RequestManager, FheFactory, KeyshareFactory, PlaintextAggregated, + PlaintextAggregatorFactory, PublicKeyAggregatorFactory, ResetHistory, SharedRng, Sortition, }; use actix::prelude::*; use alloy::primitives::Address; @@ -105,7 +101,7 @@ mod tests { bus.clone(), sortition.clone(), )) - .add_hook(CiphernodeFactory::create(bus.clone(), data.clone(), addr)) + .add_hook(KeyshareFactory::create(bus.clone(), data.clone(), addr)) .build(); } @@ -113,13 +109,9 @@ mod tests { params: Arc, crp: CommonRandomPoly, rng: SharedRng, - ) -> Result<(Vec, SecretKey)> { + ) -> Result<(PublicKeyShare, SecretKey)> { let sk = SecretKey::random(¶ms, &mut *rng.lock().unwrap()); - let pk = PublicKeyShareSerializer::to_bytes( - PublicKeyShare::new(&sk, crp.clone(), &mut *rng.lock().unwrap())?, - params.clone(), - crp, - )?; + let pk = PublicKeyShare::new(&sk, crp.clone(), &mut *rng.lock().unwrap())?; Ok((pk, sk)) } @@ -204,9 +196,8 @@ 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 = [p1.clone(), p2.clone(), p3.clone()] - .iter() - .map(|k| PublicKeyShareSerializer::from_bytes(k).unwrap()) + let pubkey: PublicKey = vec![p1.clone(), p2.clone(), p3.clone()] + .into_iter() .aggregate()?; assert_eq!(history.len(), 9); @@ -230,17 +221,17 @@ mod tests { threshold_m: 3, }), EnclaveEvent::from(KeyshareCreated { - pubkey: p1.clone(), + pubkey: p1.to_bytes(), e3_id: e3_id.clone(), node: eth_addrs[0].clone() }), EnclaveEvent::from(KeyshareCreated { - pubkey: p2.clone(), + pubkey: p2.to_bytes(), e3_id: e3_id.clone(), node: eth_addrs[1].clone() }), EnclaveEvent::from(KeyshareCreated { - pubkey: p3.clone(), + pubkey: p3.to_bytes(), e3_id: e3_id.clone(), node: eth_addrs[2].clone() }), @@ -253,7 +244,12 @@ mod tests { // Aggregate decryption bus.send(ResetHistory).await?; - + fn pad_end(input: &[u64], pad: u64, total: usize) -> Vec { + let len = input.len(); + let mut cop = input.to_vec(); + cop.extend(std::iter::repeat(pad).take(total - len)); + cop + } // 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 @@ -261,33 +257,22 @@ mod tests { let no = 873827u64; let raw_plaintext = vec![yes, no]; - let expected_raw_plaintext = bincode::serialize(&raw_plaintext)?; + let padded = &pad_end(&raw_plaintext, 0, 2048); + let expected_raw_plaintext = bincode::serialize(&padded)?; let pt = Plaintext::try_encode(&raw_plaintext, Encoding::poly(), ¶ms)?; let ciphertext = pubkey.try_encrypt(&pt, &mut ChaCha20Rng::seed_from_u64(42))?; let event = EnclaveEvent::from(CiphertextOutputPublished { - ciphertext_output: CiphertextSerializer::to_bytes(ciphertext.clone(), params.clone())?, + ciphertext_output: ciphertext.to_bytes(), e3_id: e3_id.clone(), }); let arc_ct = Arc::new(ciphertext); - let ds1 = DecryptionShareSerializer::to_bytes( - 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_test.lock().unwrap()).unwrap(), - params.clone(), - arc_ct.clone(), - )?; - let ds3 = DecryptionShareSerializer::to_bytes( - DecryptionShare::new(&sk3, &arc_ct, &mut *rng_test.lock().unwrap()).unwrap(), - params.clone(), - arc_ct.clone(), - )?; + let ds1 = DecryptionShare::new(&sk1, &arc_ct, &mut *rng_test.lock().unwrap())?.to_bytes(); + let ds2 = DecryptionShare::new(&sk2, &arc_ct, &mut *rng_test.lock().unwrap())?.to_bytes(); + let ds3 = DecryptionShare::new(&sk3, &arc_ct, &mut *rng_test.lock().unwrap())?.to_bytes(); // let ds1 = sk1 bus.send(event.clone()).await?; @@ -296,6 +281,7 @@ mod tests { let history = bus.send(GetHistory).await?; assert_eq!(history.len(), 5); + assert_eq!( history, vec![ diff --git a/packages/ciphernode/core/src/logger.rs b/packages/ciphernode/core/src/logger.rs index 43f68984..6cb5c104 100644 --- a/packages/ciphernode/core/src/logger.rs +++ b/packages/ciphernode/core/src/logger.rs @@ -39,11 +39,6 @@ impl Handler for SimpleLogger { ); println!("[{}]: {}", self.name, msg); } - EnclaveEvent::PlaintextAggregated { data, .. } => { - let output: Vec = bincode::deserialize(&data.decrypted_output).unwrap(); - println!("[{}]: DECRYPTED: \n{:?}\n\n", self.name,output); - println!("[{}]: {}", self.name, msg); - } EnclaveEvent::CiphernodeAdded { data, .. } => { println!("[{}]: CiphernodeAdded({})", self.name, data.address); }, diff --git a/packages/ciphernode/core/src/main_aggregator.rs b/packages/ciphernode/core/src/main_aggregator.rs index 5a17f9fc..a7ab5a15 100644 --- a/packages/ciphernode/core/src/main_aggregator.rs +++ b/packages/ciphernode/core/src/main_aggregator.rs @@ -1,15 +1,14 @@ -use std::{ - env, - sync::{Arc, Mutex}, -}; - use crate::{ - committee_meta::CommitteeMetaFactory, evm_ciphernode_registry::connect_evm_ciphernode_registry, evm_enclave::connect_evm_enclave, public_key_writer::PublicKeyWriter, E3RequestManager, EventBus, FheFactory, P2p, PlaintextAggregatorFactory, PlaintextWriter, PublicKeyAggregatorFactory, SimpleLogger, Sortition + committee_meta::CommitteeMetaFactory, evm_ciphernode_registry::connect_evm_ciphernode_registry, + evm_enclave::connect_evm_enclave, public_key_writer::PublicKeyWriter, E3RequestManager, + EventBus, FheFactory, P2p, PlaintextAggregatorFactory, PlaintextWriter, + PublicKeyAggregatorFactory, SimpleLogger, Sortition, }; use actix::{Actor, Addr, Context}; use alloy::primitives::Address; use rand::SeedableRng; use rand_chacha::rand_core::OsRng; +use std::sync::{Arc, Mutex}; use tokio::task::JoinHandle; /// Main Ciphernode Actor @@ -42,7 +41,7 @@ impl MainAggregator { enclave_contract: Address, registry_contract: Address, pubkey_write_path: Option<&str>, - plaintext_write_path: Option<&str> + plaintext_write_path: Option<&str>, ) -> (Addr, JoinHandle<()>) { let rng = Arc::new(Mutex::new( rand_chacha::ChaCha20Rng::from_rng(OsRng).expect("Failed to create RNG"), diff --git a/packages/ciphernode/core/src/main_ciphernode.rs b/packages/ciphernode/core/src/main_ciphernode.rs index b6c0e8ec..027f5c7f 100644 --- a/packages/ciphernode/core/src/main_ciphernode.rs +++ b/packages/ciphernode/core/src/main_ciphernode.rs @@ -2,7 +2,7 @@ use std::sync::{Arc, Mutex}; use crate::{ evm_ciphernode_registry::connect_evm_ciphernode_registry, evm_enclave::connect_evm_enclave, - CiphernodeFactory, CiphernodeSelector, CommitteeMetaFactory, Data, E3RequestManager, EventBus, + KeyshareFactory, CiphernodeSelector, CommitteeMetaFactory, Data, E3RequestManager, EventBus, FheFactory, P2p, SimpleLogger, Sortition, }; use actix::{Actor, Addr, Context}; @@ -66,7 +66,7 @@ impl MainCiphernode { let e3_manager = E3RequestManager::builder(bus.clone()) .add_hook(CommitteeMetaFactory::create()) .add_hook(FheFactory::create(rng.clone())) - .add_hook(CiphernodeFactory::create( + .add_hook(KeyshareFactory::create( bus.clone(), data.clone(), &address.to_string(), diff --git a/packages/ciphernode/core/src/plaintext_aggregator.rs b/packages/ciphernode/core/src/plaintext_aggregator.rs index 9ad82e96..14d37000 100644 --- a/packages/ciphernode/core/src/plaintext_aggregator.rs +++ b/packages/ciphernode/core/src/plaintext_aggregator.rs @@ -1,9 +1,11 @@ +use std::sync::Arc; + use crate::{ ordered_set::OrderedSet, ActorFactory, DecryptionshareCreated, E3id, EnclaveEvent, EventBus, Fhe, GetAggregatePlaintext, GetHasNode, PlaintextAggregated, Sortition, }; use actix::prelude::*; -use anyhow::{anyhow, Result}; +use anyhow::Result; #[derive(Debug, Clone)] pub enum PlaintextAggregatorState { @@ -11,9 +13,11 @@ pub enum PlaintextAggregatorState { threshold_m: usize, shares: OrderedSet>, seed: u64, + ciphertext_output: Vec, }, Computing { shares: OrderedSet>, + ciphertext_output: Vec, }, Complete { decrypted: Vec, @@ -25,10 +29,11 @@ pub enum PlaintextAggregatorState { #[rtype(result = "anyhow::Result<()>")] struct ComputeAggregate { pub shares: OrderedSet>, + pub ciphertext_output: Vec, } pub struct PlaintextAggregator { - fhe: Addr, + fhe: Arc, bus: Addr, sortition: Addr, e3_id: E3id, @@ -37,12 +42,13 @@ pub struct PlaintextAggregator { impl PlaintextAggregator { pub fn new( - fhe: Addr, + fhe: Arc, bus: Addr, sortition: Addr, e3_id: E3id, threshold_m: usize, seed: u64, + ciphertext_output: Vec, ) -> Self { PlaintextAggregator { fhe, @@ -53,6 +59,7 @@ impl PlaintextAggregator { threshold_m, shares: OrderedSet::new(), seed, + ciphertext_output, }, } } @@ -61,6 +68,7 @@ impl PlaintextAggregator { let PlaintextAggregatorState::Collecting { threshold_m, shares, + ciphertext_output, .. } = &mut self.state else { @@ -71,6 +79,7 @@ impl PlaintextAggregator { if shares.len() == *threshold_m { return Ok(PlaintextAggregatorState::Computing { shares: shares.clone(), + ciphertext_output: ciphertext_output.to_vec(), }); } @@ -78,7 +87,7 @@ impl PlaintextAggregator { } pub fn set_decryption(&mut self, decrypted: Vec) -> Result { - let PlaintextAggregatorState::Computing { shares } = &mut self.state else { + let PlaintextAggregatorState::Computing { shares, .. } = &mut self.state else { return Ok(self.state.clone()); }; @@ -142,9 +151,14 @@ impl Handler for PlaintextAggregator { 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 { + if let PlaintextAggregatorState::Computing { + shares, + ciphertext_output, + } = &act.state + { ctx.notify(ComputeAggregate { shares: shares.clone(), + ciphertext_output: ciphertext_output.to_vec(), }) } @@ -155,29 +169,25 @@ impl Handler for PlaintextAggregator { } impl Handler for PlaintextAggregator { - type Result = ResponseActFuture>; + type Result = Result<()>; fn handle(&mut self, msg: ComputeAggregate, _: &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(PlaintextAggregated { - decrypted_output, - e3_id: act.e3_id.clone(), - }); - act.bus.do_send(event); + let decrypted_output = self.fhe.get_aggregate_plaintext(GetAggregatePlaintext { + decryptions: msg.shares.clone(), + ciphertext_output: msg.ciphertext_output + })?; - Ok(()) - }), - ) + // Update the local state + self.state = self.set_decryption(decrypted_output.clone())?; + + // Dispatch the PlaintextAggregated event + let event = EnclaveEvent::from(PlaintextAggregated { + decrypted_output, + e3_id: self.e3_id.clone(), + }); + + self.bus.do_send(event); + + Ok(()) } } @@ -195,6 +205,7 @@ impl PlaintextAggregatorFactory { let Some(ref meta) = ctx.meta else { return; }; + ctx.plaintext = Some( PlaintextAggregator::new( fhe.clone(), @@ -203,6 +214,7 @@ impl PlaintextAggregatorFactory { data.e3_id, meta.threshold_m, meta.seed, + data.ciphertext_output, ) .start(), ); diff --git a/packages/ciphernode/core/src/publickey_aggregator.rs b/packages/ciphernode/core/src/publickey_aggregator.rs index 4bf14426..6222057c 100644 --- a/packages/ciphernode/core/src/publickey_aggregator.rs +++ b/packages/ciphernode/core/src/publickey_aggregator.rs @@ -1,3 +1,5 @@ +use std::sync::Arc; + use crate::{ eventbus::EventBus, events::{E3id, EnclaveEvent, KeyshareCreated, PublicKeyAggregated}, @@ -31,7 +33,7 @@ struct ComputeAggregate { } pub struct PublicKeyAggregator { - fhe: Addr, + fhe: Arc, bus: Addr, sortition: Addr, e3_id: E3id, @@ -46,7 +48,7 @@ pub struct PublicKeyAggregator { /// for them. impl PublicKeyAggregator { pub fn new( - fhe: Addr, + fhe: Arc, bus: Addr, sortition: Addr, e3_id: E3id, @@ -169,43 +171,28 @@ impl Handler for PublicKeyAggregator { } impl Handler for PublicKeyAggregator { - type Result = ResponseActFuture>; + type Result = Result<()>; 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 require access to self 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??; + let pubkey = self.fhe.get_aggregate_public_key(GetAggregatePublicKey { + keyshares: msg.keyshares.clone(), + })?; - // Update the local state - act.state = act.set_pubkey(pubkey.clone())?; + // Update the local state + self.state = self.set_pubkey(pubkey.clone())?; - // Dispatch the PublicKeyAggregated event - let event = EnclaveEvent::from(PublicKeyAggregated { - pubkey, - e3_id: act.e3_id.clone(), - }); + // Dispatch the PublicKeyAggregated event + let event = EnclaveEvent::from(PublicKeyAggregated { + pubkey, + e3_id: self.e3_id.clone(), + }); - act.bus.do_send(event); + self.bus.do_send(event); - // Return - Ok(()) - }), - ) + // Return + Ok(()) } -} +} pub struct PublicKeyAggregatorFactory; impl PublicKeyAggregatorFactory { diff --git a/packages/ciphernode/core/src/serializers/ciphertext.rs b/packages/ciphernode/core/src/serializers/ciphertext.rs deleted file mode 100644 index 271fef7b..00000000 --- a/packages/ciphernode/core/src/serializers/ciphertext.rs +++ /dev/null @@ -1,56 +0,0 @@ -use anyhow::*; -use fhe::bfv::{BfvParameters, Ciphertext}; -use fhe_traits::{Deserialize, DeserializeParametrized, Serialize}; -use serde::Serializer; -use std::sync::Arc; - -pub struct CiphertextSerializer { - pub inner: Ciphertext, - pub params: Arc, -} - -impl CiphertextSerializer { - pub fn to_bytes(inner: Ciphertext, params: Arc) -> Result> { - let value = Self { inner, params }; - Ok(bincode::serialize(&value)?) - } - - pub fn from_bytes(bytes:&[u8]) -> Result{ - let wct: Self = bincode::deserialize(&bytes)?; - Ok(wct.inner) - } -} - -/// Deserialize from serde to PublicKeySerializer -impl<'de> serde::Deserialize<'de> for CiphertextSerializer { - 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(Self { inner, params }) - } -} -impl serde::Serialize for CiphertextSerializer { - 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/serializers/decryption_share.rs b/packages/ciphernode/core/src/serializers/decryption_share.rs deleted file mode 100644 index bc99d12e..00000000 --- a/packages/ciphernode/core/src/serializers/decryption_share.rs +++ /dev/null @@ -1,72 +0,0 @@ -use anyhow::*; -use fhe::{ - bfv::{BfvParameters, Ciphertext}, - mbfv::DecryptionShare, -}; -use fhe_traits::{Deserialize, DeserializeParametrized, Serialize}; -use serde::Serializer; -use std::sync::Arc; - -pub struct DecryptionShareSerializer { - inner: DecryptionShare, - params: Arc, - ct: Arc, -} - -impl DecryptionShareSerializer { - pub fn to_bytes( - inner: DecryptionShare, - params: Arc, - ct: Arc, - ) -> Result> { - 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 deleted file mode 100644 index e5c15eeb..00000000 --- a/packages/ciphernode/core/src/serializers/mod.rs +++ /dev/null @@ -1,11 +0,0 @@ -mod ciphertext; -mod decryption_share; -mod public_key; -mod public_key_share; -mod secret_key; - -pub use ciphertext::*; -pub use decryption_share::*; -pub use public_key::*; -pub use public_key_share::*; -pub use secret_key::*; diff --git a/packages/ciphernode/core/src/serializers/public_key.rs b/packages/ciphernode/core/src/serializers/public_key.rs deleted file mode 100644 index a485334b..00000000 --- a/packages/ciphernode/core/src/serializers/public_key.rs +++ /dev/null @@ -1,77 +0,0 @@ -use anyhow::*; -use fhe::bfv::{BfvParameters, PublicKey}; -use fhe_traits::{Deserialize, DeserializeParametrized, Serialize}; -use serde::Serializer; -use std::sync::Arc; - -pub struct PublicKeySerializer { - inner: PublicKey, - params: Arc, -} - -impl PublicKeySerializer { - pub fn to_bytes(inner: PublicKey, params: Arc) -> Result> { - let value = Self { inner, params }; - Ok(bincode::serialize(&value)?) - } - - pub fn from_bytes(bytes: Vec) -> Result { - let wpk: PublicKeySerializer = bincode::deserialize(&bytes)?; - Ok(wpk.inner) - } -} - -/// Deserialize from serde to PublicKeySerializer -impl<'de> serde::Deserialize<'de> for PublicKeySerializer { - 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(Self { inner, params }) - } -} - -/// Serialize to serde bytes representation -impl serde::Serialize for PublicKeySerializer { - 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 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/serializers/public_key_share.rs b/packages/ciphernode/core/src/serializers/public_key_share.rs deleted file mode 100644 index cf7a6c6d..00000000 --- a/packages/ciphernode/core/src/serializers/public_key_share.rs +++ /dev/null @@ -1,81 +0,0 @@ -use anyhow::*; -use fhe::{ - bfv::BfvParameters, - mbfv::{CommonRandomPoly, PublicKeyShare}, -}; -use fhe_traits::{Deserialize, Serialize}; -use serde::Serializer; -use std::sync::Arc; - -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 - params: Arc, - crp: CommonRandomPoly, -} - -impl PublicKeyShareSerializer { - /// Public function to serialize specifically from the wrapped type including types that are - /// private from outside the crate - pub fn to_bytes( - inner: PublicKeyShare, - params: Arc, - crp: CommonRandomPoly, - ) -> Result> { - let value = Self { inner, params, crp }; - Ok(bincode::serialize(&value)?) - } - - pub fn from_bytes(bytes: &[u8]) -> Result { - let wpk: Self = bincode::deserialize(&bytes)?; - Ok(wpk.inner) - } -} - -/// Deserialize from serde to PublicKeyShareSerializer -impl<'de> serde::Deserialize<'de> for PublicKeyShareSerializer { - 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(Self { inner, params, crp }) - } -} - -/// Serialize to serde bytes representation -impl serde::Serialize for PublicKeyShareSerializer { - 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/serializers/secret_key.rs b/packages/ciphernode/core/src/serializers/secret_key.rs deleted file mode 100644 index 95abca76..00000000 --- a/packages/ciphernode/core/src/serializers/secret_key.rs +++ /dev/null @@ -1,44 +0,0 @@ -use anyhow::*; -use fhe::bfv::{BfvParameters, SecretKey}; -use fhe_traits::{Deserialize, Serialize}; -use std::sync::Arc; - -pub struct SecretKeySerializer { - pub inner: SecretKey, - pub params: Arc, -} - -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) - } -} - -#[derive(serde::Serialize, serde::Deserialize)] -struct SecretKeyData { - coeffs: Box<[i64]>, - par: Vec, -} - -impl SecretKeySerializer { - 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: &[u8]) -> Result { - let SecretKeyData { coeffs, par } = bincode::deserialize(&bytes)?; - let params = Arc::new(BfvParameters::try_deserialize(&par).unwrap()); - Ok(Self { - inner: SecretKey::new(coeffs.to_vec(), ¶ms), - params, - }) - } -} diff --git a/packages/ciphernode/enclave_node/src/bin/test_encryptor.rs b/packages/ciphernode/enclave_node/src/bin/test_encryptor.rs index 4cc74a08..9a1531f2 100644 --- a/packages/ciphernode/enclave_node/src/bin/test_encryptor.rs +++ b/packages/ciphernode/enclave_node/src/bin/test_encryptor.rs @@ -1,8 +1,8 @@ // This is a test script designed to encrypt some fixed data to a fhe public key use clap::Parser; -use enclave_core::{setup_bfv_params, CiphertextSerializer}; +use enclave_core::setup_bfv_params; use fhe::bfv::{Encoding, Plaintext, PublicKey}; -use fhe_traits::{DeserializeParametrized, FheEncoder, FheEncrypter}; +use fhe_traits::{DeserializeParametrized, FheEncoder, FheEncrypter, Serialize}; use rand::SeedableRng; use rand_chacha::ChaCha20Rng; use std::fs; @@ -36,7 +36,7 @@ fn main() -> Result<(), Box> { 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 ciphertext_bytes = ciphertext.clone().to_bytes(); fs::write(&args.output, &ciphertext_bytes)?; println!("Created {}", args.output); diff --git a/tests/basic_integration/test.sh b/tests/basic_integration/test.sh index 47fffa87..8080e6e0 100755 --- a/tests/basic_integration/test.sh +++ b/tests/basic_integration/test.sh @@ -150,13 +150,17 @@ yarn e3:publishCiphertext --e3-id 0 --network localhost --data-file "$SCRIPT_DIR waiton "$SCRIPT_DIR/output/plaintext.txt" ACTUAL=$(cat $SCRIPT_DIR/output/plaintext.txt) + -if [[ "$ACTUAL" != "$PLAINTEXT" ]]; then +# Assume plaintext is shorter + +if [[ "$ACTUAL" != "$PLAINTEXT"* ]]; then echo "Invalid plaintext decrypted: actual='$ACTUAL' expected='$PLAINTEXT'" + echo "Test FAILED" exit 1 fi -echo "Test PASSED" +heading "Test PASSED !" cleanup 0