Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Architecture fixes #114

Merged
merged 4 commits into from
Sep 26, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Remove serializers
  • Loading branch information
ryardley committed Sep 26, 2024
commit ce765cefdba74c4ea2cc8cf40cd15ce1e036de00
11 changes: 6 additions & 5 deletions packages/ciphernode/core/src/ciphernode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use crate::{
};
use actix::prelude::*;
use anyhow::Result;
use anyhow::Context;

pub struct Keyshare {
fhe: Arc<Fhe>,
Expand All @@ -19,7 +20,7 @@ pub struct Keyshare {
}

impl Actor for Keyshare {
type Context = Context<Self>;
type Context = actix::Context<Self>;
}

impl Keyshare {
Expand All @@ -36,7 +37,7 @@ impl Keyshare {
impl Handler<EnclaveEvent> for Keyshare {
type Result = ();

fn handle(&mut self, event: EnclaveEvent, ctx: &mut Context<Self>) -> Self::Result {
fn handle(&mut self, event: EnclaveEvent, ctx: &mut actix::Context<Self>) -> Self::Result {
match event {
EnclaveEvent::CiphernodeSelected { data, .. } => ctx.address().do_send(data),
EnclaveEvent::CiphertextOutputPublished { data, .. } => ctx.address().do_send(data),
Expand All @@ -48,7 +49,7 @@ impl Handler<EnclaveEvent> for Keyshare {
impl Handler<CiphernodeSelected> for Keyshare {
type Result = ResponseFuture<()>;

fn handle(&mut self, event: CiphernodeSelected, _: &mut Context<Self>) -> Self::Result {
fn handle(&mut self, event: CiphernodeSelected, _: &mut actix::Context<Self>) -> Self::Result {
let fhe = self.fhe.clone();
let data = self.data.clone();
let bus = self.bus.clone();
Expand All @@ -64,7 +65,7 @@ impl Handler<CiphernodeSelected> for Keyshare {
impl Handler<CiphertextOutputPublished> for Keyshare {
type Result = ResponseFuture<()>;

fn handle(&mut self, event: CiphertextOutputPublished, _: &mut Context<Self>) -> Self::Result {
fn handle(&mut self, event: CiphertextOutputPublished, _: &mut actix::Context<Self>) -> Self::Result {
println!("Ciphernode::CiphertextOutputPublished");
let fhe = self.fhe.clone();
let data = self.data.clone();
Expand Down Expand Up @@ -133,7 +134,7 @@ async fn on_decryption_requested(
let decryption_share = fhe.decrypt_ciphertext(DecryptCiphertext {
ciphertext: ciphertext_output,
unsafe_secret,
})?;
}).context("error decrypting ciphertext")?;

let event = EnclaveEvent::from(DecryptionshareCreated {
e3_id,
Expand Down
8 changes: 3 additions & 5 deletions packages/ciphernode/core/src/events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -384,7 +382,7 @@ mod tests {
let crp = CommonRandomPoly::new(&params, &mut rng)?;
let sk_share = { SecretKey::random(&params, &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,
Expand Down
117 changes: 60 additions & 57 deletions packages/ciphernode/core/src/fhe.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,12 @@
use crate::{
ordered_set::OrderedSet,
serializers::{
CiphertextSerializer, DecryptionShareSerializer, PublicKeyShareSerializer,
SecretKeySerializer,
},
ActorFactory, E3Requested, EnclaveEvent,
};
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 fhe_traits::{DeserializeParametrized, FheDecoder, Serialize};
use rand_chacha::ChaCha20Rng;
use std::sync::{Arc, Mutex};

Expand All @@ -22,6 +16,7 @@ pub struct GetAggregatePublicKey {

pub struct GetAggregatePlaintext {
pub decryptions: OrderedSet<Vec<u8>>,
pub ciphertext_output: Vec<u8>,
}

pub struct DecryptCiphertext {
Expand All @@ -44,33 +39,6 @@ impl Fhe {
Self { params, crp, rng }
}

// Deprecated
pub fn try_default() -> Result<Self> {
// 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,
Expand All @@ -96,49 +64,49 @@ impl Fhe {
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(),
))
}

pub fn decrypt_ciphertext(&self, msg: DecryptCiphertext) -> Result<Vec<u8>> {
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())
}

pub fn get_aggregate_public_key(&self, msg: GetAggregatePublicKey) -> Result<Vec<u8>> {
let public_key: PublicKey = msg
.keyshares
.iter()
.map(|k| PublicKeyShareSerializer::from_bytes(k))
.collect::<Result<Vec<_>>>()?
.into_iter()
.map(|k| PublicKeyShare::deserialize(k, &self.params, self.crp.clone()))
.aggregate()?;

Ok(public_key.to_bytes())
}

pub fn get_aggregate_plaintext(&self, msg: GetAggregatePlaintext) -> Result<Vec<u8>> {
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::<Result<Vec<_>>>()?
.into_iter()
.map(|k| DecryptionShare::deserialize(k, &self.params, arc_ct.clone()))
.aggregate()?;

let decoded = Vec::<u64>::try_decode(&plaintext, Encoding::poly())?;
let decoded = &decoded[0..2]; // TODO: remove this and leave it up to the caller
Ok(bincode::serialize(&decoded)?)
Expand Down Expand Up @@ -169,3 +137,38 @@ impl FheFactory {
})
}
}

struct SecretKeySerializer {
pub inner: SecretKey,
}

impl SecretKeySerializer {
pub fn to_bytes(inner: SecretKey) -> Result<Vec<u8>> {
let value = Self { inner };
Ok(value.unsafe_serialize()?)
}

pub fn from_bytes(bytes: &[u8], params: Arc<BfvParameters>) -> Result<SecretKey> {
Ok(Self::deserialize(bytes, params)?.inner)
}
}

#[derive(serde::Serialize, serde::Deserialize)]
struct SecretKeyData {
coeffs: Box<[i64]>,
}

impl SecretKeySerializer {
pub fn unsafe_serialize(&self) -> Result<Vec<u8>> {
Ok(bincode::serialize(&SecretKeyData {
coeffs: self.inner.coeffs.clone(),
})?)
}

pub fn deserialize(bytes: &[u8], params: Arc<BfvParameters>) -> Result<SecretKeySerializer> {
let SecretKeyData { coeffs } = bincode::deserialize(&bytes)?;
Ok(Self {
inner: SecretKey::new(coeffs.to_vec(), &params),
})
}
}
63 changes: 26 additions & 37 deletions packages/ciphernode/core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,11 @@ 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::*;
Expand All @@ -42,27 +41,34 @@ 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::*;

// TODO: move these out to a test folder
#[cfg(test)]
mod tests {
use crate::{
cipernode_selector::CiphernodeSelector, data::Data, eventbus::{EventBus, GetHistory}, events::{E3Requested, E3id, EnclaveEvent, KeyshareCreated, PublicKeyAggregated}, p2p::P2p, serializers::{CiphertextSerializer, DecryptionShareSerializer, PublicKeyShareSerializer}, utils::{setup_crp_params, ParamsWithCrp}, CiphernodeAdded, CiphernodeSelected, CiphertextOutputPublished, CommitteeMetaFactory, DecryptionshareCreated, E3RequestManager, FheFactory, KeyshareFactory, PlaintextAggregated, PlaintextAggregatorFactory, PublicKeyAggregatorFactory, ResetHistory, SharedRng, Sortition
cipernode_selector::CiphernodeSelector,
data::Data,
eventbus::{EventBus, GetHistory},
events::{E3Requested, E3id, EnclaveEvent, KeyshareCreated, PublicKeyAggregated},
p2p::P2p,
utils::{setup_crp_params, ParamsWithCrp},
CiphernodeAdded, CiphernodeSelected, CiphertextOutputPublished, CommitteeMetaFactory,
DecryptionshareCreated, E3RequestManager, FheFactory, KeyshareFactory, PlaintextAggregated,
PlaintextAggregatorFactory, PublicKeyAggregatorFactory, ResetHistory, SharedRng, Sortition,
};
use actix::prelude::*;
use alloy::primitives::Address;
use anyhow::*;
use fhe::{
bfv::{BfvParameters, Encoding, Plaintext, PublicKey, SecretKey},
mbfv::{AggregateIter, CommonRandomPoly, DecryptionShare, PublicKeyShare},
mbfv::{Aggregate, AggregateIter, CommonRandomPoly, DecryptionShare, PublicKeyShare},
};
use fhe_traits::{FheEncoder, FheEncrypter, Serialize};
use fhe_traits::{Deserialize, DeserializeParametrized, FheEncoder, FheEncrypter, Serialize};
use rand::Rng;
use rand::SeedableRng;
use rand_chacha::ChaCha20Rng;
Expand Down Expand Up @@ -103,13 +109,9 @@ mod tests {
params: Arc<BfvParameters>,
crp: CommonRandomPoly,
rng: SharedRng,
) -> Result<(Vec<u8>, SecretKey)> {
) -> Result<(PublicKeyShare, SecretKey)> {
let sk = SecretKey::random(&params, &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))
}

Expand Down Expand Up @@ -194,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);
Expand All @@ -220,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()
}),
Expand All @@ -257,27 +258,15 @@ mod tests {
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?;
Expand Down
Loading
Loading