From 4e43d7c5e3be808922437c47cf7ff8ab23d00d0c Mon Sep 17 00:00:00 2001 From: John Mumm Date: Thu, 30 Jan 2025 15:40:28 +0100 Subject: [PATCH 1/4] WIP: end-to-end decrypt/encrypt testing --- keyhive_core/src/cgka.rs | 27 ++++ keyhive_core/src/cgka/beekem.rs | 3 + keyhive_core/src/cgka/operation.rs | 15 +++ keyhive_core/src/keyhive.rs | 179 ++++++++++++++++++++++--- keyhive_core/src/principal/document.rs | 13 +- keyhive_wasm/src/js/keyhive.rs | 6 + 6 files changed, 217 insertions(+), 26 deletions(-) diff --git a/keyhive_core/src/cgka.rs b/keyhive_core/src/cgka.rs index 714e398c..516d8d4e 100644 --- a/keyhive_core/src/cgka.rs +++ b/keyhive_core/src/cgka.rs @@ -132,6 +132,7 @@ impl Cgka { let current_pcs_key = if !self.has_pcs_key() { let new_share_secret_key = ShareSecretKey::generate(csprng); let new_share_key = new_share_secret_key.share_key(); + println!("!@ new_app_secret update op for {}", self.owner_id); let (pcs_key, update_op) = self.update(new_share_key, new_share_secret_key, csprng)?; self.insert_pcs_key(&pcs_key, Digest::hash(&update_op)); op = Some(update_op); @@ -163,17 +164,21 @@ impl Cgka { &mut self, encrypted: &EncryptedContent, ) -> Result { + println!("!@ decryption_key_for 0"); let pcs_key = self.pcs_key_from_hashes(&encrypted.pcs_key_hash, &encrypted.pcs_update_op_hash)?; + println!("!@ decryption_key_for 1"); if !self.pcs_keys.contains_key(&encrypted.pcs_key_hash) { self.insert_pcs_key(&pcs_key, encrypted.pcs_update_op_hash); } + println!("!@ decryption_key_for 2"); let app_secret = pcs_key.derive_application_secret( &encrypted.nonce, &encrypted.content_ref, &encrypted.pred_refs, &encrypted.pcs_update_op_hash, ); + println!("!@ decryption_key_for 3"); Ok(app_secret.key()) } @@ -192,6 +197,7 @@ impl Cgka { if self.tree.contains_id(&id) { return Ok(None); } + println!("!@ Calling Cgka::add()"); if self.should_replay() { self.replay_ops_graph()?; } @@ -227,6 +233,7 @@ impl Cgka { if !self.tree.contains_id(&id) { return Ok(None); } + println!("!@ Calling Cgka::remove()"); if self.should_replay() { self.replay_ops_graph()?; } @@ -254,6 +261,7 @@ impl Cgka { new_sk: ShareSecretKey, csprng: &mut R, ) -> Result<(PcsKey, CgkaOperation), CgkaError> { + println!("!@ Calling Cgka::update()"); if self.should_replay() { self.replay_ops_graph()?; } @@ -269,6 +277,7 @@ impl Cgka { predecessors, doc_id: self.doc_id, }; + println!("!@ -- Op Digest: {}", Digest::hash(&op)); self.ops_graph.add_local_op(&op); self.insert_pcs_key(&pcs_key, Digest::hash(&op)); Ok((pcs_key, op)) @@ -289,6 +298,7 @@ impl Cgka { /// membership changes and we receive a concurrent update, we can apply it /// immediately. pub fn merge_concurrent_operation(&mut self, op: Rc) -> Result<(), CgkaError> { + println!("\nMerging operation at {}: {:?}\n", self.owner_id, op.name()); if self.ops_graph.contains_op_hash(&Digest::hash(op.borrow())) { return Ok(()); } @@ -315,6 +325,10 @@ impl Cgka { Ok(()) } + pub fn ops(&self) -> Result, CgkaError> { + self.ops_graph.topsort_graph() + } + /// Apply a [`CgkaOperation`]. fn apply_operation(&mut self, op: Rc) -> Result<(), CgkaError> { if self.ops_graph.contains_op_hash(&Digest::hash(op.borrow())) { @@ -397,15 +411,20 @@ impl Cgka { pcs_key_hash: &Digest, update_op_hash: &Digest, ) -> Result { + println!("pcs_key_from_hashes 0"); if let Some(pcs_key) = self.pcs_keys.get(pcs_key_hash) { + println!("pcs_key_from_hashes DONE"); Ok(*pcs_key.clone()) } else { if self.has_pcs_key() { + println!("pcs_key_from_hashes tree root"); let pcs_key = self.pcs_key_from_tree_root()?; + println!("pcs_key_from_hashes tree root FOUND"); if &Digest::hash(&pcs_key) == pcs_key_hash { return Ok(pcs_key); } } + println!("pcs_key_from_hashes derive pcs key"); self.derive_pcs_key_for_op(update_op_hash) } } @@ -415,12 +434,15 @@ impl Cgka { &mut self, op_hash: &Digest, ) -> Result { + println!("!@ derive_pcs_key_for_op 0"); if !self.ops_graph.contains_op_hash(op_hash) { return Err(CgkaError::UnknownPcsKey); } + println!("!@ derive_pcs_key_for_op 1"); let mut heads = HashSet::new(); heads.insert(*op_hash); let ops = self.ops_graph.topsort_for_heads(&heads)?; + println!("!@ derive_pcs_key_for_op 2"); self.rebuild_pcs_key(ops) } @@ -459,12 +481,17 @@ impl Cgka { epochs.last()[0].borrow(), &CgkaOperation::Update { .. } )); + println!("rebuild_pcs_key 0"); let mut rebuilt_cgka = Cgka::new(self.doc_id, self.original_member.0, self.original_member.1)? .with_new_owner(self.owner_id, self.owner_sks.clone())?; + println!("rebuild_pcs_key 1"); rebuilt_cgka.apply_epochs(&epochs)?; + println!("rebuild_pcs_key 2"); let pcs_key = rebuilt_cgka.pcs_key_from_tree_root()?; + println!("rebuild_pcs_key 3"); self.insert_pcs_key(&pcs_key, Digest::hash(&epochs.last()[0])); + println!("rebuild_pcs_key 4"); Ok(pcs_key) } diff --git a/keyhive_core/src/cgka/beekem.rs b/keyhive_core/src/cgka/beekem.rs index ac0f8730..b5bb7a6e 100644 --- a/keyhive_core/src/cgka/beekem.rs +++ b/keyhive_core/src/cgka/beekem.rs @@ -279,6 +279,7 @@ impl BeeKem { sks: &mut ShareKeyMap, csprng: &mut R, ) -> Result, CgkaError> { + println!("!@ encrypt_path by {}: pk {}", id, pk); let leaf_idx = *self.leaf_index_for_id(id)?; debug_assert!(self.id_for_leaf(leaf_idx).unwrap() == id); let mut new_path = PathChange { @@ -330,6 +331,8 @@ impl BeeKem { /// Applies a [`PathChange`] representing new public and encrypted secret keys for each /// node on a path. pub(crate) fn apply_path(&mut self, new_path: &PathChange) { + println!("!@ apply_path received from {}", new_path.leaf_id); + // If this id has been concurrently removed, it might no longer be present // when we try to apply the concurrent update at that id. if !self.id_to_leaf_idx.contains_key(&new_path.leaf_id) { diff --git a/keyhive_core/src/cgka/operation.rs b/keyhive_core/src/cgka/operation.rs index ed6d06d6..2b76a87c 100644 --- a/keyhive_core/src/cgka/operation.rs +++ b/keyhive_core/src/cgka/operation.rs @@ -61,6 +61,15 @@ pub enum CgkaOperation { } impl CgkaOperation { + // FIXME: Remove + pub(crate) fn name(&self) -> String { + match self { + CgkaOperation::Add { .. } => String::from("Add"), + CgkaOperation::Remove { .. } => String::from("Remove"), + CgkaOperation::Update { .. } => String::from("Update"), + } + } + /// The zero or more immediate causal predecessors of this operation. pub(crate) fn predecessors(&self) -> HashSet> { match self { @@ -135,11 +144,13 @@ impl CgkaOperationGraph { /// Add an operation that was created locally to the graph. pub(crate) fn add_local_op(&mut self, op: &CgkaOperation) { + println!("!@ OpsGraph: adding local {}", Digest::hash(op)); self.add_op_and_update_heads(op, None); } /// Add an operation to the graph. pub(crate) fn add_op(&mut self, op: &CgkaOperation, heads: &HashSet>) { + println!("!@ OpsGraph: adding remote {}", Digest::hash(op)); self.add_op_and_update_heads(op, Some(heads)); } @@ -211,6 +222,7 @@ impl CgkaOperationGraph { &self, heads: &HashSet>, ) -> Result, CgkaError> { + println!("!@ topsort_for_heads 0"); debug_assert!(heads.iter().all(|head| self.cgka_ops.contains_key(head))); let mut op_hashes = Vec::new(); let mut dependencies = TopologicalSort::>::new(); @@ -225,9 +237,11 @@ impl CgkaOperationGraph { } // Populate dependencies and successors with all ancestors of the initial heads. while let Some(op_hash) = frontier.pop_front() { + println!("!@ topsort_for_heads loopy op_hash: {}", op_hash); let preds = self .predecessors_for(&op_hash) .ok_or(CgkaError::OperationNotFound)?; + println!("!@ -- preds: {:?}", preds); for update_pred in preds { dependencies.add_dependency(*update_pred, op_hash); successors.entry(*update_pred).or_default().insert(op_hash); @@ -304,6 +318,7 @@ impl CgkaOperationGraph { } } for hash in next_set { + println!("!@ topsort_for_heads pushy"); next_epoch.push( self.cgka_ops .get(&hash) diff --git a/keyhive_core/src/keyhive.rs b/keyhive_core/src/keyhive.rs index 5ea339d4..e76c0688 100644 --- a/keyhive_core/src/keyhive.rs +++ b/keyhive_core/src/keyhive.rs @@ -322,32 +322,43 @@ impl< ) } + // FIXME: I've temporarily changed this to return EncryptedContentWithUpdate + // to make progress on writing end-to-end decrypt/encrypt tests. pub fn try_encrypt_content( &mut self, doc: Rc>>, content_ref: &T, pred_refs: &Vec, content: &[u8], - ) -> Result, T>, EncryptContentError> { - let EncryptedContentWithUpdate { - encrypted_content, - update_op, - } = doc.borrow_mut().try_encrypt_content( - content_ref, - content, - pred_refs, - &mut self.csprng, - )?; - - if let Some(found_update_op) = update_op { - let signed_op = Rc::new( - self.try_sign(found_update_op) - .map_err(EncryptContentError::SignCgkaOpError)?, - ); - self.event_listener.on_cgka_op(&signed_op); - } - - Ok(encrypted_content) + ) -> Result, EncryptContentError> { +// ) -> Result, T>, EncryptContentError> { +// let EncryptedContentWithUpdate { +// encrypted_content, +// update_op, +// } = doc.borrow_mut().try_encrypt_content( +// content_ref, +// content, +// pred_refs, +// &mut self.csprng, +// )?; + +// if let Some(found_update_op) = update_op { +// let signed_op = Rc::new( +// self.try_sign(found_update_op) +// .map_err(EncryptContentError::SignCgkaOpError)?, +// ); +// self.event_listener.on_cgka_op(&signed_op); +// } + +// Ok(encrypted_content) +// } + let res = doc.borrow_mut().try_encrypt_content( + content_ref, + content, + pred_refs, + &mut self.csprng, + )?; + Ok(res) } pub fn try_decrypt_content( @@ -1327,6 +1338,7 @@ mod tests { use crate::{access::Access, principal::public::Public}; use nonempty::nonempty; use pretty_assertions::assert_eq; + use rand::RngCore; #[test] fn test_archival_round_trip() { @@ -1571,4 +1583,131 @@ mod tests { assert_eq!(dlg.delegation.subject_id(), doc.borrow().doc_id().into()); } + + // TODO: + // * Replace Public with real individuals + // * Break out helper functions + // * Concurrent combinations + // * Add group to doc + // * Add group to multiple docs, then add member to that group + + fn make_indie() -> Rc> { + let mut csprng = rand::thread_rng(); + let indie_sk = ed25519_dalek::SigningKey::generate(&mut csprng); + Rc::new(RefCell::new( + Individual::generate(&indie_sk.into(), &mut csprng).unwrap(), + )) + } + + fn initialize_keyhives_and_doc(count: usize) -> (Vec, DocumentId) { + let mut csprng = rand::thread_rng(); + let mut keyhives = Vec::new(); + let mut first = make_keyhive(); + keyhives.push(first); + let indie = make_indie(); + let doc = keyhives[0] + .generate_doc( + vec![indie.dupe().into()], + nonempty![[0u8; 32]], + ) + .unwrap(); + let cgka_epochs = doc.borrow().cgka_ops().unwrap(); + for _ in 0..count - 1 { + let mut next = make_keyhive(); + let ops = keyhives[0].membership_ops_for_agent(&indie.dupe().into()); + for (_h, op) in &ops { + next.receive_op(&op.clone().into()).unwrap(); + } + for epoch in &cgka_epochs { + for op in epoch.iter() { + next.receive_cgka_op((**op).clone()).unwrap(); + } + } + keyhives.push(next); + } + let doc_id = doc.borrow().doc_id(); + for keyhive in &mut keyhives { + keyhive.get_document(doc_id).unwrap(); + } + (keyhives, doc_id) + } + + fn share_delegation(delegation: Rc>>, keyhives: &mut Vec, sharer_idx: usize) { + let static_dlg = Signed { + issuer: delegation.issuer, + signature: delegation.signature, + payload: delegation.payload.clone().into() + }; + for idx in 0..keyhives.len() { + if idx == sharer_idx { + continue + } + keyhives[idx].receive_delegation(&static_dlg).unwrap(); + } + } + + fn share_ops_for_agent(agent: &Agent, keyhives: &mut Vec, sharer_idx: usize) { + for idx in 0..keyhives.len() { + if idx == sharer_idx { + continue + } + let ops = keyhives[sharer_idx].membership_ops_for_agent(agent); + for (_h, op) in &ops { + keyhives[idx].receive_op(&op.clone().into()).unwrap(); + } + } + } + + fn share_cgka_op(op: &CgkaOperation, keyhives: &mut Vec, sharer_idx: usize) { + for idx in 0..keyhives.len() { + if idx == sharer_idx { + continue + } + keyhives[idx].receive_cgka_op(op.clone()).unwrap(); + } + } + + #[test] + fn test_concurrent_cgka_operations() { + let (mut keyhives, doc_id) = initialize_keyhives_and_doc(2); + let a_idx = 0; + let b_idx = 1; + + let a_doc = keyhives[a_idx].get_document(doc_id).unwrap().dupe(); + let cgka_op = keyhives[a_idx].force_pcs_update(a_doc.dupe()).unwrap(); + share_cgka_op(&cgka_op, &mut keyhives, a_idx); + + let content = "Let's start!"; + let content_ref = generate_content_ref(); + let pred_refs = Vec::new(); + let encrypted_with_update = keyhives[a_idx].try_encrypt_content(a_doc.dupe(), &content_ref, &pred_refs, content.as_bytes()).unwrap(); + assert_eq!(content, &String::from_utf8(keyhives[a_idx].try_decrypt_content(a_doc, &encrypted_with_update.encrypted_content).unwrap()).unwrap()); + + if let Some(op) = encrypted_with_update.update_op { + keyhives[b_idx].receive_cgka_op(op.clone()).unwrap(); + } + let encrypted = encrypted_with_update.encrypted_content; + let b_doc = keyhives[b_idx].get_document(doc_id).unwrap().dupe(); + let b_content: String = String::from_utf8(keyhives[b_idx].try_decrypt_content(b_doc.dupe(), &encrypted).unwrap()).unwrap(); + assert_eq!(content, &b_content); + + + let b_doc = keyhives[b_idx].get_document(doc_id).unwrap().dupe(); + let second_group = keyhives[b_idx].generate_group(vec![]).unwrap(); + share_ops_for_agent(&second_group.dupe().into(), &mut keyhives, 1); + let indie = make_indie(); + let add = keyhives[b_idx] + .add_member(indie.dupe().into(), &mut second_group.dupe().into(), Access::Read, &[]) + .unwrap(); + share_delegation(add.delegation.dupe(), &mut keyhives, b_idx); + share_ops_for_agent(&indie.dupe().into(), &mut keyhives, b_idx); + + } + + fn generate_content_ref() -> [u8; 32] { + let mut csprng = rand::thread_rng(); + let mut content_ref = [0u8; 32]; + csprng.fill_bytes(&mut content_ref); + content_ref + } } diff --git a/keyhive_core/src/principal/document.rs b/keyhive_core/src/principal/document.rs index a732726f..e10488c5 100644 --- a/keyhive_core/src/principal/document.rs +++ b/keyhive_core/src/principal/document.rs @@ -3,7 +3,7 @@ pub mod id; use super::{group::AddGroupMemberError, individual::id::IndividualId}; use crate::{ access::Access, - cgka::{error::CgkaError, keys::ShareKeyMap, operation::CgkaOperation, Cgka}, + cgka::{error::CgkaError, keys::ShareKeyMap, operation::{CgkaEpoch, CgkaOperation}, Cgka}, content::reference::ContentRef, crypto::{ digest::Digest, @@ -155,10 +155,6 @@ impl> Document { .cloned(), ); } - let (_pcs_key, update_op) = cgka.update(owner_share_key, owner_share_secret_key, csprng)?; - // FIXME: We don't currently do anything with these ops, but need to share them - // across the network. - ops.push(update_op); Ok(Document { group, reader_keys: HashMap::new(), // FIXME @@ -260,6 +256,10 @@ impl> Document { self.cgka.merge_concurrent_operation(Rc::new(op)) } + pub fn cgka_ops(&self) -> Result, CgkaError> { + self.cgka.ops() + } + pub fn pcs_update( &mut self, csprng: &mut R, @@ -430,7 +430,8 @@ pub enum GenerateDocError { #[derive(Debug, Clone, PartialEq, Eq)] pub struct EncryptedContentWithUpdate { - pub(crate) encrypted_content: EncryptedContent, T>, + // FIXME: Changed visibility to get tests running + pub encrypted_content: EncryptedContent, T>, pub(crate) update_op: Option, } diff --git a/keyhive_wasm/src/js/keyhive.rs b/keyhive_wasm/src/js/keyhive.rs index 55f252b8..e3c6ddc0 100644 --- a/keyhive_wasm/src/js/keyhive.rs +++ b/keyhive_wasm/src/js/keyhive.rs @@ -118,6 +118,9 @@ impl JsKeyhive { Ok(self .0 .try_encrypt_content(doc.0, &content_ref, &pred_refs, content)? + // FIXME: This is based on temporary change to return type to get tests + // running. + .encrypted_content .into()) } @@ -133,6 +136,9 @@ impl JsKeyhive { Ok(self .0 .try_encrypt_content(doc.0, &content_ref, &pred_refs, content)? + // FIXME: This is based on temporary change to return type to get tests + // running. + .encrypted_content .into()) } From 43bace4ee6e0b607f574238a6fd8e8dba4437bd7 Mon Sep 17 00:00:00 2001 From: John Mumm Date: Thu, 30 Jan 2025 17:55:25 +0100 Subject: [PATCH 2/4] Debug version --- keyhive_core/src/cgka/operation.rs | 2 +- keyhive_core/src/keyhive.rs | 63 ++++++++++++++++++------------ 2 files changed, 40 insertions(+), 25 deletions(-) diff --git a/keyhive_core/src/cgka/operation.rs b/keyhive_core/src/cgka/operation.rs index 2b76a87c..6ebc8fba 100644 --- a/keyhive_core/src/cgka/operation.rs +++ b/keyhive_core/src/cgka/operation.rs @@ -19,7 +19,7 @@ use topological_sort::TopologicalSort; /// An ordered [`NonEmpty`] of concurrent [`CgkaOperation`]s. #[derive(Debug, Clone, Eq, PartialEq)] -pub(crate) struct CgkaEpoch(NonEmpty>); +pub struct CgkaEpoch(NonEmpty>); impl From>> for CgkaEpoch { fn from(item: NonEmpty>) -> Self { diff --git a/keyhive_core/src/keyhive.rs b/keyhive_core/src/keyhive.rs index e76c0688..40de8603 100644 --- a/keyhive_core/src/keyhive.rs +++ b/keyhive_core/src/keyhive.rs @@ -814,6 +814,7 @@ impl< .get(&subject_id.into()) .and_then(|content_heads| NonEmpty::collect(content_heads.iter().cloned())) { + println!("!@ Inserting doc into self.docs!"); let doc = Document::from_group(group, &self.active.borrow(), content_heads)?; self.docs.insert(doc.doc_id(), Rc::new(RefCell::new(doc))); } else { @@ -1668,30 +1669,10 @@ mod tests { } #[test] - fn test_concurrent_cgka_operations() { + fn test_sharing_ops_to_debug() { let (mut keyhives, doc_id) = initialize_keyhives_and_doc(2); - let a_idx = 0; + // let a_idx = 0; let b_idx = 1; - - let a_doc = keyhives[a_idx].get_document(doc_id).unwrap().dupe(); - let cgka_op = keyhives[a_idx].force_pcs_update(a_doc.dupe()).unwrap(); - share_cgka_op(&cgka_op, &mut keyhives, a_idx); - - let content = "Let's start!"; - let content_ref = generate_content_ref(); - let pred_refs = Vec::new(); - let encrypted_with_update = keyhives[a_idx].try_encrypt_content(a_doc.dupe(), &content_ref, &pred_refs, content.as_bytes()).unwrap(); - assert_eq!(content, &String::from_utf8(keyhives[a_idx].try_decrypt_content(a_doc, &encrypted_with_update.encrypted_content).unwrap()).unwrap()); - - if let Some(op) = encrypted_with_update.update_op { - keyhives[b_idx].receive_cgka_op(op.clone()).unwrap(); - } - let encrypted = encrypted_with_update.encrypted_content; - let b_doc = keyhives[b_idx].get_document(doc_id).unwrap().dupe(); - let b_content: String = String::from_utf8(keyhives[b_idx].try_decrypt_content(b_doc.dupe(), &encrypted).unwrap()).unwrap(); - assert_eq!(content, &b_content); - - let b_doc = keyhives[b_idx].get_document(doc_id).unwrap().dupe(); let second_group = keyhives[b_idx].generate_group(vec![]).unwrap(); share_ops_for_agent(&second_group.dupe().into(), &mut keyhives, 1); @@ -1699,11 +1680,45 @@ mod tests { let add = keyhives[b_idx] .add_member(indie.dupe().into(), &mut second_group.dupe().into(), Access::Read, &[]) .unwrap(); - share_delegation(add.delegation.dupe(), &mut keyhives, b_idx); + // share_delegation(add.delegation.dupe(), &mut keyhives, b_idx); share_ops_for_agent(&indie.dupe().into(), &mut keyhives, b_idx); - } + // #[test] + // fn test_concurrent_cgka_operations() { + // let (mut keyhives, doc_id) = initialize_keyhives_and_doc(2); + // let a_idx = 0; + // let b_idx = 1; + + // let a_doc = keyhives[a_idx].get_document(doc_id).unwrap().dupe(); + // let cgka_op = keyhives[a_idx].force_pcs_update(a_doc.dupe()).unwrap(); + // share_cgka_op(&cgka_op, &mut keyhives, a_idx); + + // let content = "Let's start!"; + // let content_ref = generate_content_ref(); + // let pred_refs = Vec::new(); + // let encrypted_with_update = keyhives[a_idx].try_encrypt_content(a_doc.dupe(), &content_ref, &pred_refs, content.as_bytes()).unwrap(); + // assert_eq!(content, &String::from_utf8(keyhives[a_idx].try_decrypt_content(a_doc, &encrypted_with_update.encrypted_content).unwrap()).unwrap()); + + // if let Some(op) = encrypted_with_update.update_op { + // keyhives[b_idx].receive_cgka_op(op.clone()).unwrap(); + // } + // let encrypted = encrypted_with_update.encrypted_content; + // let b_doc = keyhives[b_idx].get_document(doc_id).unwrap().dupe(); + // let b_content: String = String::from_utf8(keyhives[b_idx].try_decrypt_content(b_doc.dupe(), &encrypted).unwrap()).unwrap(); + // assert_eq!(content, &b_content); + + + // let second_group = keyhives[b_idx].generate_group(vec![]).unwrap(); + // share_ops_for_agent(&second_group.dupe().into(), &mut keyhives, 1); + // let indie = make_indie(); + // let add = keyhives[b_idx] + // .add_member(indie.dupe().into(), &mut second_group.dupe().into(), Access::Read, &[]) + // .unwrap(); + // // share_delegation(add.delegation.dupe(), &mut keyhives, b_idx); + // share_ops_for_agent(&indie.dupe().into(), &mut keyhives, b_idx); + // } + fn generate_content_ref() -> [u8; 32] { let mut csprng = rand::thread_rng(); let mut content_ref = [0u8; 32]; From 3beefa5da36aee48b5caa9a41062eddc52ee6b11 Mon Sep 17 00:00:00 2001 From: John Mumm Date: Thu, 30 Jan 2025 19:30:38 +0100 Subject: [PATCH 3/4] .. --- keyhive_core/benches/bench_cgka.rs | 2 +- keyhive_core/src/cgka.rs | 6 +- keyhive_core/src/keyhive.rs | 79 ++++++++++++++------------ keyhive_core/src/listener.rs | 2 +- keyhive_core/src/principal/document.rs | 7 ++- 5 files changed, 55 insertions(+), 41 deletions(-) diff --git a/keyhive_core/benches/bench_cgka.rs b/keyhive_core/benches/bench_cgka.rs index dd35c020..1d2e3513 100644 --- a/keyhive_core/benches/bench_cgka.rs +++ b/keyhive_core/benches/bench_cgka.rs @@ -1,5 +1,5 @@ -use keyhive_core::{ use divan::Bencher; +use keyhive_core::{ cgka::{ error::CgkaError, test_utils::{ diff --git a/keyhive_core/src/cgka.rs b/keyhive_core/src/cgka.rs index 516d8d4e..f6659ca4 100644 --- a/keyhive_core/src/cgka.rs +++ b/keyhive_core/src/cgka.rs @@ -298,7 +298,11 @@ impl Cgka { /// membership changes and we receive a concurrent update, we can apply it /// immediately. pub fn merge_concurrent_operation(&mut self, op: Rc) -> Result<(), CgkaError> { - println!("\nMerging operation at {}: {:?}\n", self.owner_id, op.name()); + println!( + "\nMerging operation at {}: {:?}\n", + self.owner_id, + op.name() + ); if self.ops_graph.contains_op_hash(&Digest::hash(op.borrow())) { return Ok(()); } diff --git a/keyhive_core/src/keyhive.rs b/keyhive_core/src/keyhive.rs index 40de8603..497f6d6d 100644 --- a/keyhive_core/src/keyhive.rs +++ b/keyhive_core/src/keyhive.rs @@ -331,33 +331,33 @@ impl< pred_refs: &Vec, content: &[u8], ) -> Result, EncryptContentError> { -// ) -> Result, T>, EncryptContentError> { -// let EncryptedContentWithUpdate { -// encrypted_content, -// update_op, -// } = doc.borrow_mut().try_encrypt_content( -// content_ref, -// content, -// pred_refs, -// &mut self.csprng, -// )?; - -// if let Some(found_update_op) = update_op { -// let signed_op = Rc::new( -// self.try_sign(found_update_op) -// .map_err(EncryptContentError::SignCgkaOpError)?, -// ); -// self.event_listener.on_cgka_op(&signed_op); -// } - -// Ok(encrypted_content) -// } + // ) -> Result, T>, EncryptContentError> { + // let EncryptedContentWithUpdate { + // encrypted_content, + // update_op, + // } = doc.borrow_mut().try_encrypt_content( + // content_ref, + // content, + // pred_refs, + // &mut self.csprng, + // )?; + + // if let Some(found_update_op) = update_op { + // let signed_op = Rc::new( + // self.try_sign(found_update_op) + // .map_err(EncryptContentError::SignCgkaOpError)?, + // ); + // self.event_listener.on_cgka_op(&signed_op); + // } + + // Ok(encrypted_content) + // } let res = doc.borrow_mut().try_encrypt_content( - content_ref, - content, - pred_refs, - &mut self.csprng, - )?; + content_ref, + content, + pred_refs, + &mut self.csprng, + )?; Ok(res) } @@ -1607,10 +1607,7 @@ mod tests { keyhives.push(first); let indie = make_indie(); let doc = keyhives[0] - .generate_doc( - vec![indie.dupe().into()], - nonempty![[0u8; 32]], - ) + .generate_doc(vec![indie.dupe().into()], nonempty![[0u8; 32]]) .unwrap(); let cgka_epochs = doc.borrow().cgka_ops().unwrap(); for _ in 0..count - 1 { @@ -1633,15 +1630,19 @@ mod tests { (keyhives, doc_id) } - fn share_delegation(delegation: Rc>>, keyhives: &mut Vec, sharer_idx: usize) { + fn share_delegation( + delegation: Rc>>, + keyhives: &mut Vec, + sharer_idx: usize, + ) { let static_dlg = Signed { issuer: delegation.issuer, signature: delegation.signature, - payload: delegation.payload.clone().into() + payload: delegation.payload.clone().into(), }; for idx in 0..keyhives.len() { if idx == sharer_idx { - continue + continue; } keyhives[idx].receive_delegation(&static_dlg).unwrap(); } @@ -1650,7 +1651,7 @@ mod tests { fn share_ops_for_agent(agent: &Agent, keyhives: &mut Vec, sharer_idx: usize) { for idx in 0..keyhives.len() { if idx == sharer_idx { - continue + continue; } let ops = keyhives[sharer_idx].membership_ops_for_agent(agent); for (_h, op) in &ops { @@ -1662,7 +1663,7 @@ mod tests { fn share_cgka_op(op: &CgkaOperation, keyhives: &mut Vec, sharer_idx: usize) { for idx in 0..keyhives.len() { if idx == sharer_idx { - continue + continue; } keyhives[idx].receive_cgka_op(op.clone()).unwrap(); } @@ -1678,7 +1679,12 @@ mod tests { share_ops_for_agent(&second_group.dupe().into(), &mut keyhives, 1); let indie = make_indie(); let add = keyhives[b_idx] - .add_member(indie.dupe().into(), &mut second_group.dupe().into(), Access::Read, &[]) + .add_member( + indie.dupe().into(), + &mut second_group.dupe().into(), + Access::Read, + &[], + ) .unwrap(); // share_delegation(add.delegation.dupe(), &mut keyhives, b_idx); share_ops_for_agent(&indie.dupe().into(), &mut keyhives, b_idx); @@ -1708,7 +1714,6 @@ mod tests { // let b_content: String = String::from_utf8(keyhives[b_idx].try_decrypt_content(b_doc.dupe(), &encrypted).unwrap()).unwrap(); // assert_eq!(content, &b_content); - // let second_group = keyhives[b_idx].generate_group(vec![]).unwrap(); // share_ops_for_agent(&second_group.dupe().into(), &mut keyhives, 1); // let indie = make_indie(); diff --git a/keyhive_core/src/listener.rs b/keyhive_core/src/listener.rs index cf6716af..86b7ab8a 100644 --- a/keyhive_core/src/listener.rs +++ b/keyhive_core/src/listener.rs @@ -1,5 +1,5 @@ -pub mod deque; pub mod cgka; +pub mod deque; pub mod membership; pub mod no_listener; pub mod prekey; diff --git a/keyhive_core/src/principal/document.rs b/keyhive_core/src/principal/document.rs index e10488c5..31042c0e 100644 --- a/keyhive_core/src/principal/document.rs +++ b/keyhive_core/src/principal/document.rs @@ -3,7 +3,12 @@ pub mod id; use super::{group::AddGroupMemberError, individual::id::IndividualId}; use crate::{ access::Access, - cgka::{error::CgkaError, keys::ShareKeyMap, operation::{CgkaEpoch, CgkaOperation}, Cgka}, + cgka::{ + error::CgkaError, + keys::ShareKeyMap, + operation::{CgkaEpoch, CgkaOperation}, + Cgka, + }, content::reference::ContentRef, crypto::{ digest::Digest, From 8e7cf7d3ee8aeefe11ae5f45328a627c312cbb95 Mon Sep 17 00:00:00 2001 From: Brooklyn Zelenka Date: Wed, 19 Feb 2025 20:45:00 -0800 Subject: [PATCH 4/4] Fix test! (#76) --- keyhive_core/src/keyhive.rs | 34 ++++++++++++++++++++-------- keyhive_core/src/store/delegation.rs | 4 ++++ 2 files changed, 28 insertions(+), 10 deletions(-) diff --git a/keyhive_core/src/keyhive.rs b/keyhive_core/src/keyhive.rs index 497f6d6d..ebba7649 100644 --- a/keyhive_core/src/keyhive.rs +++ b/keyhive_core/src/keyhive.rs @@ -1648,16 +1648,21 @@ mod tests { } } - fn share_ops_for_agent(agent: &Agent, keyhives: &mut Vec, sharer_idx: usize) { + fn share_ops_for_agent(agent: Agent, keyhives: &mut Vec, sharer_idx: usize) -> usize { + let mut share_count = 0; for idx in 0..keyhives.len() { if idx == sharer_idx { continue; } - let ops = keyhives[sharer_idx].membership_ops_for_agent(agent); - for (_h, op) in &ops { + let op_store = keyhives[sharer_idx].membership_ops_for_agent(&agent); + + for (_h, op) in op_store.iter() { + share_count += 1; keyhives[idx].receive_op(&op.clone().into()).unwrap(); } } + + share_count } fn share_cgka_op(op: &CgkaOperation, keyhives: &mut Vec, sharer_idx: usize) { @@ -1671,12 +1676,20 @@ mod tests { #[test] fn test_sharing_ops_to_debug() { - let (mut keyhives, doc_id) = initialize_keyhives_and_doc(2); - // let a_idx = 0; + let (mut keyhives, _doc_id) = initialize_keyhives_and_doc(2); + let a_idx = 0; let b_idx = 1; - let b_doc = keyhives[b_idx].get_document(doc_id).unwrap().dupe(); - let second_group = keyhives[b_idx].generate_group(vec![]).unwrap(); - share_ops_for_agent(&second_group.dupe().into(), &mut keyhives, 1); + + let a_peer: Peer = Rc::new(RefCell::new( + keyhives[a_idx].active.borrow().individual.clone(), + )) + .into(); + + let second_group = keyhives[b_idx].generate_group(vec![a_peer]).unwrap(); + let share_count = + share_ops_for_agent(keyhives[a_idx].active.dupe().into(), &mut keyhives, 1); + assert!(share_count > 0); + let indie = make_indie(); let add = keyhives[b_idx] .add_member( @@ -1686,8 +1699,9 @@ mod tests { &[], ) .unwrap(); - // share_delegation(add.delegation.dupe(), &mut keyhives, b_idx); - share_ops_for_agent(&indie.dupe().into(), &mut keyhives, b_idx); + share_delegation(add.delegation.dupe(), &mut keyhives, 1); + let indie_op_count = share_ops_for_agent(indie.dupe().into(), &mut keyhives, 1); + assert!(indie_op_count > 0); } // #[test] diff --git a/keyhive_core/src/store/delegation.rs b/keyhive_core/src/store/delegation.rs index 814b50cc..64634015 100644 --- a/keyhive_core/src/store/delegation.rs +++ b/keyhive_core/src/store/delegation.rs @@ -30,6 +30,10 @@ impl> DelegationStore { borrowed.get(key).cloned() } + pub fn len(&self) -> usize { + self.0.borrow().len() + } + pub fn contains_key(&self, key: &Digest>>) -> bool { let rc = self.0.dupe(); let borrowed = RefCell::borrow(&rc);