use crate::crypto::Rng;
use crate::message_scheme::dcgka::{Dcgka, DirectMessageType, ProcessInput};
use crate::message_scheme::test_utils::dcgka::{
ExpectedMembers, assert_direct_message, assert_members_view, init_dcgka_state,
};
use crate::test_utils::MessageId;
#[test]
fn concurrent_operation() {
let rng = Rng::from_seed([1; 32]);
let alice = 0;
let bob = 1;
let charlie = 2;
let dahlia = 3;
let emil = 4;
let [
alice_dcgka,
bob_dcgka,
charlie_dcgka,
dahlia_dcgka,
_emil_dcgka,
] = init_dcgka_state([alice, bob, charlie, dahlia, emil], &rng);
let (alice_dcgka, alice_output) = {
let (alice_dcgka_pre, alice_pre) =
Dcgka::create(alice_dcgka, vec![alice, bob, charlie], &rng).unwrap();
Dcgka::process_local(
alice_dcgka_pre,
MessageId {
sender: alice,
seq: 0,
},
alice_pre,
&rng,
)
.unwrap()
};
let (bob_dcgka, _bob_output) = Dcgka::process_remote(
bob_dcgka,
ProcessInput {
seq: MessageId {
sender: alice,
seq: 0,
},
sender: alice,
direct_message: Some(assert_direct_message(&alice_output.direct_messages, bob)),
control_message: alice_output.control_message.clone(),
},
&rng,
)
.unwrap();
let (charlie_dcgka, _charlie_output) = Dcgka::process_remote(
charlie_dcgka,
ProcessInput {
seq: MessageId {
sender: alice,
seq: 0,
},
sender: alice,
direct_message: Some(assert_direct_message(
&alice_output.direct_messages,
charlie,
)),
control_message: alice_output.control_message,
},
&rng,
)
.unwrap();
for dcgka in [&alice_dcgka, &bob_dcgka, &charlie_dcgka] {
assert_members_view(
dcgka,
&[ExpectedMembers {
viewer: &[alice, bob, charlie],
expected: &[alice, bob, charlie],
}],
);
}
let (charlie_dcgka, charlie_output) = {
let (charlie_dcgka_pre, charlie_pre) = Dcgka::add(charlie_dcgka, dahlia, &rng).unwrap();
Dcgka::process_local(
charlie_dcgka_pre,
MessageId {
sender: charlie,
seq: 1,
},
charlie_pre,
&rng,
)
.unwrap()
};
for dcgka in [&alice_dcgka, &bob_dcgka] {
assert_members_view(
dcgka,
&[ExpectedMembers {
viewer: &[alice, bob, charlie],
expected: &[alice, bob, charlie],
}],
);
}
assert_members_view(
&charlie_dcgka,
&[ExpectedMembers {
viewer: &[charlie, dahlia],
expected: &[alice, bob, charlie, dahlia],
}],
);
let (bob_dcgka, bob_output) = Dcgka::process_remote(
bob_dcgka,
ProcessInput {
seq: MessageId {
sender: charlie,
seq: 1,
},
sender: charlie,
direct_message: None,
control_message: charlie_output.control_message.clone(),
},
&rng,
)
.unwrap();
assert_eq!(bob_output.direct_messages.len(), 1);
assert_eq!(
bob_output.direct_messages.first().unwrap().recipient,
dahlia
);
assert_members_view(
&bob_dcgka,
&[
ExpectedMembers {
viewer: &[bob, charlie, dahlia],
expected: &[alice, bob, charlie, dahlia],
},
ExpectedMembers {
viewer: &[alice],
expected: &[alice, bob, charlie],
},
],
);
let (dahlia_dcgka, _dahlia_output) = Dcgka::process_remote(
dahlia_dcgka,
ProcessInput {
seq: MessageId {
sender: charlie,
seq: 1,
},
sender: charlie,
direct_message: Some(assert_direct_message(
&charlie_output.direct_messages,
dahlia,
)),
control_message: charlie_output.control_message,
},
&rng,
)
.unwrap();
assert_members_view(
&dahlia_dcgka,
&[
ExpectedMembers {
viewer: &[charlie, dahlia],
expected: &[alice, bob, charlie, dahlia],
},
ExpectedMembers {
viewer: &[alice, bob],
expected: &[alice, bob, charlie],
},
],
);
let (dahlia_dcgka, _dahlia_output) = Dcgka::process_remote(
dahlia_dcgka,
ProcessInput {
seq: MessageId {
sender: bob,
seq: 1,
},
sender: bob,
direct_message: Some(assert_direct_message(&bob_output.direct_messages, dahlia)),
control_message: bob_output.control_message.as_ref().unwrap().clone(),
},
&rng,
)
.unwrap();
for action in ["update", "remove", "another_add"] {
let (_alice_dcgka, alice_output) = {
let (alice_dcgka_pre, alice_pre) = match action {
"update" => Dcgka::update(alice_dcgka.clone(), &rng).unwrap(),
"remove" => Dcgka::remove(alice_dcgka.clone(), charlie, &rng).unwrap(),
"another_add" => Dcgka::add(alice_dcgka.clone(), emil, &rng).unwrap(),
_ => unreachable!(),
};
Dcgka::process_local(
alice_dcgka_pre,
MessageId {
sender: alice,
seq: 1,
},
alice_pre,
&rng,
)
.unwrap()
};
let (_bob_dcgka, bob_output) = Dcgka::process_remote(
bob_dcgka.clone(),
ProcessInput {
seq: MessageId {
sender: alice,
seq: 1,
},
sender: alice,
control_message: alice_output.control_message.clone(),
direct_message: {
if action == "another_add" {
None
} else if action == "update" || action == "remove" {
Some(assert_direct_message(&alice_output.direct_messages, bob))
} else {
unreachable!()
}
},
},
&rng,
)
.unwrap();
if action == "remove" {
assert_eq!(bob_output.direct_messages.len(), 0);
} else if action == "another_add" {
assert_eq!(bob_output.direct_messages.len(), 1);
assert_eq!(bob_output.direct_messages.first().unwrap().recipient, emil);
assert_eq!(
bob_output.direct_messages.first().unwrap().message_type(),
DirectMessageType::Forward
);
} else if action == "update" {
assert_eq!(bob_output.direct_messages.len(), 1);
assert_eq!(
bob_output.direct_messages.first().unwrap().recipient,
dahlia
);
assert_eq!(
bob_output.direct_messages.first().unwrap().message_type(),
DirectMessageType::Forward
);
}
let (dahlia_dcgka, dahlia_output) = Dcgka::process_remote(
dahlia_dcgka.clone(),
ProcessInput {
seq: MessageId {
sender: alice,
seq: 1,
},
sender: alice,
control_message: alice_output.control_message,
direct_message: None,
},
&rng,
)
.unwrap();
if action == "another_add" {
assert!(dahlia_output.me_update_secret.is_some());
} else {
assert!(dahlia_output.me_update_secret.is_none());
}
assert!(dahlia_output.sender_update_secret.is_none());
if action == "update" {
let (_dahlia_dcgka, dahlia_output) = Dcgka::process_remote(
dahlia_dcgka,
ProcessInput {
seq: MessageId {
sender: bob,
seq: 2,
},
sender: bob,
direct_message: Some(assert_direct_message(
&bob_output.direct_messages,
dahlia,
)),
control_message: bob_output.control_message.as_ref().unwrap().clone(),
},
&rng,
)
.unwrap();
assert_eq!(
dahlia_output.sender_update_secret.unwrap(),
bob_output.me_update_secret.unwrap()
);
}
}
}
#[test]
fn concurrent_adds() {
let rng = Rng::from_seed([1; 32]);
let alice = 0;
let bob = 1;
let charlie = 2;
let dahlia = 3;
let [alice_dcgka, bob_dcgka, charlie_dcgka, dahlia_dcgka] =
init_dcgka_state([alice, bob, charlie, dahlia], &rng);
let (alice_dcgka, alice_output) = {
let (alice_dcgka_pre, alice_pre) =
Dcgka::create(alice_dcgka, vec![alice, bob], &rng).unwrap();
Dcgka::process_local(
alice_dcgka_pre,
MessageId {
sender: alice,
seq: 0,
},
alice_pre,
&rng,
)
.unwrap()
};
let (bob_dcgka, bob_output) = Dcgka::process_remote(
bob_dcgka,
ProcessInput {
seq: MessageId {
sender: alice,
seq: 0,
},
sender: alice,
direct_message: Some(assert_direct_message(&alice_output.direct_messages, bob)),
control_message: alice_output.control_message,
},
&rng,
)
.unwrap();
assert_eq!(
&alice_output.me_update_secret.unwrap(),
bob_output.sender_update_secret.as_ref().unwrap()
);
let (alice_dcgka, alice_output) = Dcgka::process_remote(
alice_dcgka,
ProcessInput {
seq: MessageId {
sender: bob,
seq: 0,
},
sender: bob,
direct_message: None,
control_message: bob_output.control_message.unwrap(),
},
&rng,
)
.unwrap();
assert_eq!(
alice_output.sender_update_secret.unwrap(),
bob_output.me_update_secret.unwrap()
);
for dcgka in [&alice_dcgka, &bob_dcgka] {
assert_members_view(
dcgka,
&[ExpectedMembers {
viewer: &[alice, bob],
expected: &[alice, bob],
}],
);
}
let (_alice_dcgka, alice_output) = {
let (alice_dcgka_pre, alice_pre) = Dcgka::add(alice_dcgka, charlie, &rng).unwrap();
Dcgka::process_local(
alice_dcgka_pre,
MessageId {
sender: alice,
seq: 1,
},
alice_pre,
&rng,
)
.unwrap()
};
let (bob_dcgka, bob_output) = {
let (bob_dcgka_pre, bob_pre) = Dcgka::add(bob_dcgka, dahlia, &rng).unwrap();
Dcgka::process_local(
bob_dcgka_pre,
MessageId {
sender: bob,
seq: 1,
},
bob_pre,
&rng,
)
.unwrap()
};
let (charlie_dcgka, _charlie_output) = Dcgka::process_remote(
charlie_dcgka,
ProcessInput {
seq: MessageId {
sender: alice,
seq: 1,
},
sender: alice,
direct_message: Some(assert_direct_message(
&alice_output.direct_messages,
charlie,
)),
control_message: alice_output.control_message.clone(),
},
&rng,
)
.unwrap();
let (dahlia_dcgka, _dahlia_output) = Dcgka::process_remote(
dahlia_dcgka,
ProcessInput {
seq: MessageId {
sender: bob,
seq: 1,
},
sender: bob,
direct_message: Some(assert_direct_message(&bob_output.direct_messages, dahlia)),
control_message: bob_output.control_message,
},
&rng,
)
.unwrap();
let (dahlia_dcgka, _dahlia_output) = Dcgka::process_remote(
dahlia_dcgka,
ProcessInput {
seq: MessageId {
sender: alice,
seq: 1,
},
sender: alice,
direct_message: None,
control_message: alice_output.control_message.clone(),
},
&rng,
)
.unwrap();
assert_members_view(
&dahlia_dcgka,
&[ExpectedMembers {
viewer: &[dahlia],
expected: &[alice, bob, charlie, dahlia],
}],
);
let (bob_dcgka, bob_output) = Dcgka::process_remote(
bob_dcgka,
ProcessInput {
seq: MessageId {
sender: alice,
seq: 1,
},
sender: alice,
direct_message: None,
control_message: alice_output.control_message,
},
&rng,
)
.unwrap();
assert_members_view(
&bob_dcgka,
&[
ExpectedMembers {
viewer: &[bob],
expected: &[alice, bob, charlie, dahlia],
},
ExpectedMembers {
viewer: &[charlie],
expected: &[alice, bob, charlie],
},
],
);
assert_eq!(bob_output.direct_messages.len(), 1);
assert_eq!(
bob_output.direct_messages.first().unwrap().recipient,
charlie
);
assert_eq!(
bob_output.direct_messages.first().unwrap().message_type(),
DirectMessageType::Forward
);
let (_charlie_dcgka, charlie_output) = Dcgka::process_remote(
charlie_dcgka,
ProcessInput {
seq: MessageId {
sender: bob,
seq: 1,
},
sender: bob,
direct_message: Some(assert_direct_message(&bob_output.direct_messages, charlie)),
control_message: bob_output.control_message.unwrap(),
},
&rng,
)
.unwrap();
assert_eq!(
bob_output.me_update_secret.unwrap(),
charlie_output.sender_update_secret.unwrap()
);
}