Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
8 changes: 1 addition & 7 deletions beekem/src/cgka.rs
Original file line number Diff line number Diff line change
Expand Up @@ -446,25 +446,19 @@ impl<M: ImplicitRemovesProtocol> Cgka<M> {
id
);
}
let leaf_index = self.tree.next_leaf_index();
let op = CgkaOperation {
doc_id: self.doc_id,
predecessors: Predecessors::heads_of(&self.ops_graph),
change: CgkaChange::Add {
added_id: id,
pk,
leaf_index,
invitation: invitation.map(Box::new),
key_proof,
citations: citations.into_iter().collect(),
},
};
let signed_op = self.sign_and_record::<F, S>(op, signer).await?;
let placed_leaf_index = self.tree.add_leaf(id, pk, signed_op.digest());
debug_assert_eq!(
placed_leaf_index, leaf_index,
"the add's leaf is at the index it was signed with"
);
self.tree.add_leaf(id, pk, signed_op.digest());
self.handle_new_removals(signed_op.payload());
Ok(Some(signed_op))
}
Expand Down
88 changes: 36 additions & 52 deletions beekem/src/operation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,6 @@ pub enum CgkaChange {
Add {
added_id: MemberId,
pk: ShareKey,
leaf_index: u32,
/// Root secrets from before this add, encrypted to `pk`, so the new member
/// can read content written before it could derive anything from the tree.
/// `None` when the adder had no root secrets to wrap, or no key pair of
Expand Down Expand Up @@ -389,15 +388,13 @@ impl Encode for CgkaChange {
CgkaChange::Add {
added_id,
pk,
leaf_index,
invitation,
key_proof,
citations,
} => {
out.push(0);
added_id.encode_into(out);
pk.encode_into(out);
leaf_index.encode_into(out);
match invitation {
None => out.push(0),
Some(invitation) => {
Expand Down Expand Up @@ -444,7 +441,6 @@ impl StreamDecode for CgkaChange {
Some((0, rest)) => {
let (added_id, rest) = MemberId::decode_next(rest)?;
let (pk, rest) = ShareKey::decode_next(rest)?;
let (leaf_index, rest) = u32::decode_next(rest)?;
let (invitation, rest) = Option::<Invitation>::decode_next(rest)?;
let (key_proof, rest) = match rest.split_first() {
None => return Err(DecodeError::UnexpectedEnd),
Expand All @@ -460,7 +456,6 @@ impl StreamDecode for CgkaChange {
CgkaChange::Add {
added_id,
pk,
leaf_index,
invitation: invitation.map(Box::new),
key_proof,
citations,
Expand Down Expand Up @@ -924,37 +919,27 @@ mod causal_graph_tests {
async fn signed_add(
signer: &MemorySigner,
doc_id: TreeId,
leaf_index: u32,
predecessors: &[&Verified<CgkaOperation>],
) -> Verified<CgkaOperation> {
signed_add_from(
&mut rand::thread_rng(),
signer,
doc_id,
leaf_index,
predecessors,
)
.await
signed_add_from(&mut rand::thread_rng(), signer, doc_id, predecessors).await
}

/// An add of a new member, with its member and key drawn from `rng`.
async fn signed_add_from<R: rand::CryptoRng + rand::RngCore>(
rng: &mut R,
signer: &MemorySigner,
doc_id: TreeId,
leaf_index: u32,
predecessors: &[&Verified<CgkaOperation>],
) -> Verified<CgkaOperation> {
let added_id = member_id_from(rng);
signed_add_of(rng, signer, doc_id, added_id, leaf_index, predecessors).await
signed_add_of(rng, signer, doc_id, added_id, predecessors).await
}

async fn signed_add_of<R: rand::CryptoRng + rand::RngCore>(
rng: &mut R,
signer: &MemorySigner,
doc_id: TreeId,
added_id: MemberId,
leaf_index: u32,
predecessors: &[&Verified<CgkaOperation>],
) -> Verified<CgkaOperation> {
let op = CgkaOperation {
Expand All @@ -963,7 +948,6 @@ mod causal_graph_tests {
change: CgkaChange::Add {
added_id,
pk: ShareSecretKey::generate(rng).share_key(),
leaf_index,
invitation: None,
key_proof: None,
citations: BTreeSet::new(),
Expand All @@ -985,11 +969,11 @@ mod causal_graph_tests {
let signer = MemorySigner::generate(&mut rand::thread_rng());
let doc_id = TreeId::from(&signer.0);
let mut trunk = CgkaOperationGraph::new();
let root = signed_add(&signer, doc_id, 0, &[]).await;
let root = signed_add(&signer, doc_id, &[]).await;
trunk.add_op(&root).expect("a root has no predecessors");

let mut forked = trunk.fork();
let on_fork = signed_add(&signer, doc_id, 1, &[&root]).await;
let on_fork = signed_add(&signer, doc_id, &[&root]).await;
let on_fork_hash = on_fork.digest();
forked
.add_op(&on_fork)
Expand All @@ -1012,7 +996,7 @@ mod causal_graph_tests {
"the merged operation should be the only head"
);
trunk
.add_op(&signed_add(&signer, doc_id, 2, &[&on_fork]).await)
.add_op(&signed_add(&signer, doc_id, &[&on_fork]).await)
.expect("the merged operation's depth is in the graph");
}

Expand All @@ -1034,13 +1018,13 @@ mod causal_graph_tests {
let signer = MemorySigner::generate(&mut rand::thread_rng());
let doc_id = TreeId::from(&signer.0);
let mut one = CgkaOperationGraph::new();
let root = signed_add(&signer, doc_id, 0, &[]).await;
let root = signed_add(&signer, doc_id, &[]).await;
one.add_op(&root).expect("a root has no predecessors");
let mut two = one.fork();

assert_eq!(hash_of(&one), hash_of(&two), "equal graphs should agree");

two.add_op(&signed_add(&signer, doc_id, 1, &[&root]).await)
two.add_op(&signed_add(&signer, doc_id, &[&root]).await)
.expect("the predecessor is in the graph");

assert_ne!(
Expand All @@ -1066,9 +1050,9 @@ mod causal_graph_tests {
let doc_id = TreeId::from(&signer.0);
let mut graph = CgkaOperationGraph::new();
let mut signed = BTreeMap::new();
for (leaf_index, (name, preds)) in (0..).zip(ops) {
for (name, preds) in ops {
let preds: Vec<_> = preds.iter().map(|pred| &signed[pred]).collect();
let op = signed_add(&signer, doc_id, leaf_index, &preds).await;
let op = signed_add(&signer, doc_id, &preds).await;
graph.add_op(&op).expect("predecessors are listed first");
signed.insert(*name, op);
}
Expand Down Expand Up @@ -1100,10 +1084,10 @@ mod causal_graph_tests {
let signer = MemorySigner::generate(rng);
let doc_id = TreeId::from(&signer.0);
let mut ops: Vec<Verified<CgkaOperation>> = Vec::new();
for leaf_index in 0..24 {
for _ in 0..24 {
let count = rng.gen_range(1..=3).min(ops.len());
let preds: Vec<_> = ops.iter().choose_multiple(rng, count);
let op = signed_add_from(rng, &signer, doc_id, leaf_index, &preds).await;
let op = signed_add_from(rng, &signer, doc_id, &preds).await;
ops.push(op);
}
let mut graph = CgkaOperationGraph::new();
Expand Down Expand Up @@ -1293,9 +1277,9 @@ mod causal_graph_tests {
let signer = MemorySigner::generate(&mut rand::thread_rng());
let doc_id = TreeId::from(&signer.0);
let mut graph = CgkaOperationGraph::new();
let root = signed_add(&signer, doc_id, 0, &[]).await;
let child = signed_add(&signer, doc_id, 1, &[&root]).await;
let grandchild = signed_add(&signer, doc_id, 2, &[&child]).await;
let root = signed_add(&signer, doc_id, &[]).await;
let child = signed_add(&signer, doc_id, &[&root]).await;
let grandchild = signed_add(&signer, doc_id, &[&child]).await;
for op in [&root, &child, &grandchild] {
graph.add_op(op).expect("predecessors are added first");
}
Expand All @@ -1313,12 +1297,12 @@ mod causal_graph_tests {
let signer = MemorySigner::generate(&mut rand::thread_rng());
let doc_id = TreeId::from(&signer.0);
let mut graph = CgkaOperationGraph::new();
let root = signed_add(&signer, doc_id, 0, &[]).await;
let root = signed_add(&signer, doc_id, &[]).await;
graph.add_op(&root).expect("a root has no predecessors");
let unknown = signed_add(&signer, doc_id, 1, &[]).await;
let unknown = signed_add(&signer, doc_id, &[]).await;
let before = graph.clone();

let result = graph.add_op(&signed_add(&signer, doc_id, 2, &[&root, &unknown]).await);
let result = graph.add_op(&signed_add(&signer, doc_id, &[&root, &unknown]).await);

assert!(
matches!(result, Err(CgkaError::OutOfOrderOperation)),
Expand Down Expand Up @@ -1364,9 +1348,9 @@ mod causal_graph_tests {
let signer = MemorySigner::generate(&mut rand::thread_rng());
let doc_id = TreeId::from(&signer.0);
let mut graph = CgkaOperationGraph::new();
let first_add = signed_add(&signer, doc_id, 0, &[]).await;
let first_add = signed_add(&signer, doc_id, &[]).await;
let update = signed_update(&signer, doc_id, &[&first_add]).await;
let second_add = signed_add(&signer, doc_id, 1, &[]).await;
let second_add = signed_add(&signer, doc_id, &[]).await;
for op in [&first_add, &update, &second_add] {
graph.add_op(op).expect("predecessors are added first");
}
Expand All @@ -1387,7 +1371,7 @@ mod causal_graph_tests {
let signer = MemorySigner::generate(&mut rand::thread_rng());
let doc_id = TreeId::from(&signer.0);
let mut graph = CgkaOperationGraph::new();
let root = signed_add(&signer, doc_id, 0, &[]).await;
let root = signed_add(&signer, doc_id, &[]).await;
let update = signed_update(&signer, doc_id, &[&root]).await;
let other_signer = MemorySigner::generate(&mut rand::thread_rng());
let other_update = signed_update(&other_signer, doc_id, &[&root]).await;
Expand All @@ -1410,7 +1394,7 @@ mod causal_graph_tests {
let signer = MemorySigner::generate(&mut rand::thread_rng());
let doc_id = TreeId::from(&signer.0);
let graph = CgkaOperationGraph::new();
let unknown = signed_add(&signer, doc_id, 0, &[]).await;
let unknown = signed_add(&signer, doc_id, &[]).await;

assert!(
matches!(
Expand All @@ -1427,8 +1411,8 @@ mod causal_graph_tests {
let signer = MemorySigner::generate(&mut rand::thread_rng());
let doc_id = TreeId::from(&signer.0);
let mut graph = CgkaOperationGraph::new();
let first_root = signed_add(&signer, doc_id, 0, &[]).await;
let second_root = signed_add(&signer, doc_id, 1, &[]).await;
let first_root = signed_add(&signer, doc_id, &[]).await;
let second_root = signed_add(&signer, doc_id, &[]).await;
for op in [&first_root, &second_root] {
graph.add_op(op).expect("a root has no predecessors");
}
Expand All @@ -1447,7 +1431,7 @@ mod causal_graph_tests {
let doc_id = TreeId::from(&signer.0);
let mut graph = CgkaOperationGraph::new();
graph
.add_op(&signed_add(&signer, doc_id, 0, &[]).await)
.add_op(&signed_add(&signer, doc_id, &[]).await)
.expect("a root add is accepted");
let before = graph.clone();

Expand All @@ -1469,7 +1453,7 @@ mod causal_graph_tests {
let signer = MemorySigner::generate(&mut rand::thread_rng());
let doc_id = TreeId::from(&signer.0);
let mut graph = CgkaOperationGraph::new();
let root = signed_add(&signer, doc_id, 0, &[]).await;
let root = signed_add(&signer, doc_id, &[]).await;
let u1 = signed_update(&signer, doc_id, &[&root]).await;
let u2 = signed_update(&signer, doc_id, &[&u1]).await;
for op in [&root, &u1, &u2] {
Expand All @@ -1487,11 +1471,11 @@ mod causal_graph_tests {
let signer = MemorySigner::generate(&mut rand::thread_rng());
let doc_id = TreeId::from(&signer.0);
let mut graph = CgkaOperationGraph::new();
let root = signed_add(&signer, doc_id, 0, &[]).await;
let root = signed_add(&signer, doc_id, &[]).await;
let earlier = signed_update(&signer, doc_id, &[&root]).await;
let later = signed_update(&signer, doc_id, &[&earlier]).await;
let add = signed_add(&signer, doc_id, 1, &[&later]).await;
let later_add = signed_add(&signer, doc_id, 2, &[&add]).await;
let add = signed_add(&signer, doc_id, &[&later]).await;
let later_add = signed_add(&signer, doc_id, &[&add]).await;
for op in [&root, &earlier, &later, &add, &later_add] {
graph.add_op(op).expect("predecessors are added first");
}
Expand All @@ -1508,7 +1492,7 @@ mod causal_graph_tests {
let signer = MemorySigner::generate(&mut rand::thread_rng());
let doc_id = TreeId::from(&signer.0);
let mut graph = CgkaOperationGraph::new();
let root = signed_add(&signer, doc_id, 0, &[]).await;
let root = signed_add(&signer, doc_id, &[]).await;
let update = signed_update(&signer, doc_id, &[&root]).await;
for op in [&root, &update] {
graph.add_op(op).expect("predecessors are added first");
Expand All @@ -1523,8 +1507,8 @@ mod causal_graph_tests {
let signer = MemorySigner::generate(&mut rand::thread_rng());
let doc_id = TreeId::from(&signer.0);
let mut graph = CgkaOperationGraph::new();
let root = signed_add(&signer, doc_id, 0, &[]).await;
let add = signed_add(&signer, doc_id, 1, &[&root]).await;
let root = signed_add(&signer, doc_id, &[]).await;
let add = signed_add(&signer, doc_id, &[&root]).await;
for op in [&root, &add] {
graph.add_op(op).expect("predecessors are added first");
}
Expand All @@ -1540,9 +1524,9 @@ mod causal_graph_tests {
let mut rng = rand::thread_rng();
let founder = member_id();
let joiner = member_id();
let root = signed_add_of(&mut rng, &signer, doc_id, founder, 0, &[]).await;
let root = signed_add_of(&mut rng, &signer, doc_id, founder, &[]).await;
let before = signed_update(&signer, doc_id, &[&root]).await;
let join = signed_add_of(&mut rng, &signer, doc_id, joiner, 1, &[&before]).await;
let join = signed_add_of(&mut rng, &signer, doc_id, joiner, &[&before]).await;
let after = signed_update(&signer, doc_id, &[&join]).await;
for op in [&root, &before, &join, &after] {
graph.add_op(op).expect("predecessors are added first");
Expand All @@ -1567,15 +1551,15 @@ mod causal_graph_tests {
let signer = MemorySigner::generate(&mut rand::thread_rng());
let doc_id = TreeId::from(&signer.0);
let mut graph = CgkaOperationGraph::new();
let root = signed_add(&signer, doc_id, 0, &[]).await;
let root = signed_add(&signer, doc_id, &[]).await;
graph.add_op(&root).expect("a root add has no predecessors");

// Two concurrent branches, each an update followed by an add.
let mut expected = Set::new();
let mut heads = Set::new();
for leaf_index in 1..=2u32 {
for _ in 0..2 {
let update = signed_update(&signer, doc_id, &[&root]).await;
let add = signed_add(&signer, doc_id, leaf_index, &[&update]).await;
let add = signed_add(&signer, doc_id, &[&update]).await;
for op in [&update, &add] {
graph.add_op(op).expect("predecessors are added first");
}
Expand Down
7 changes: 3 additions & 4 deletions beekem/src/tests/codec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -180,8 +180,8 @@ mod layout {
}
}

/// `doc ‖ predecessors ‖ 0 ‖ added_id ‖ pk ‖ leaf_index ‖ invitation? ‖
/// key_proof? ‖ citations`, an absent invitation as tag `0` and a present
/// `doc ‖ predecessors ‖ 0 ‖ added_id ‖ pk ‖ invitation? ‖ key_proof? ‖
/// citations`, an absent invitation as tag `0` and a present
/// key proof as tag `1` and its length-prefixed bytes.
#[test]
fn an_add_encodes_in_its_documented_layout() {
Expand All @@ -192,7 +192,6 @@ fn an_add_encodes_in_its_documented_layout() {
change: CgkaChange::Add {
added_id: member(),
pk: share_key(3),
leaf_index: 3,
invitation: None,
key_proof: Some(alloc::vec![9, 9]),
citations: [CitationId([5; 32])].into(),
Expand All @@ -203,7 +202,7 @@ fn an_add_encodes_in_its_documented_layout() {
&[0, 0],
member().as_bytes(),
share_key(3).as_bytes(),
&[3, 0, 1, 2, 9, 9, 1],
&[0, 1, 2, 9, 9, 1],
&[5; 32],
]);
assert_eq!(op.encode().as_bytes(), expected);
Expand Down
1 change: 0 additions & 1 deletion beekem/src/tests/invitations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,6 @@ async fn an_invitation_cannot_pair_a_secret_with_an_update_that_did_not_produce_
change: CgkaChange::Add {
added_id: bob_id,
pk: bob_pk,
leaf_index: 1,
invitation: Some(Box::new(Invitation {
inviter_pk,
ancestor_secrets: vec![InvitationSecret {
Expand Down
5 changes: 0 additions & 5 deletions beekem/src/tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -324,11 +324,6 @@ impl BeeKem {
})
}

/// The index the next leaf added will have.
pub fn next_leaf_index(&self) -> u32 {
self.next_leaf_idx.u32()
}

/// Place `leaf` at the first available [`LeafNodeIndex`] on the right and
/// blank that leaf's path to the root. Returns the leaf's index.
fn push_leaf_node(&mut self, leaf: LeafNode) -> u32 {
Expand Down
1 change: 0 additions & 1 deletion keyhive_core/src/cgka.rs
Original file line number Diff line number Diff line change
Expand Up @@ -356,7 +356,6 @@ mod tests {
change: CgkaChange::Add {
added_id: MemberId::from(&SigningKey::generate(&mut csprng)),
pk: invitee_sk.share_key(),
leaf_index: 0,
invitation: None,
key_proof: None,
citations: BTreeSet::new(),
Expand Down
Loading
Loading