use tls_codec::{Deserialize, Serialize};
use crate::{
framing::{MlsMessageIn, Sender},
group::{
tests_and_kats::utils::generate_credential_with_key, MlsGroup, MlsGroupCreateConfig,
PURE_PLAINTEXT_WIRE_FORMAT_POLICY,
},
prelude::ProcessedMessageContent,
};
#[openmls_test::openmls_test]
fn test_external_commit() {
let alice_provider = &Provider::default();
let bob_provider = &Provider::default();
let charlie_provider = &Provider::default();
let alice_credential = generate_credential_with_key(
"Alice".into(),
ciphersuite.signature_algorithm(),
alice_provider,
);
let bob_credential = generate_credential_with_key(
"Bob".into(),
ciphersuite.signature_algorithm(),
bob_provider,
);
let charlie_credential = generate_credential_with_key(
"Charlie".into(),
ciphersuite.signature_algorithm(),
charlie_provider,
);
let mls_group_create_config = MlsGroupCreateConfig::builder()
.wire_format_policy(PURE_PLAINTEXT_WIRE_FORMAT_POLICY)
.ciphersuite(ciphersuite)
.build();
let mut alice_group = MlsGroup::new(
alice_provider,
&alice_credential.signer,
&mls_group_create_config,
alice_credential.credential_with_key.clone(),
)
.unwrap();
let verifiable_group_info = alice_group
.export_group_info(alice_provider.crypto(), &alice_credential.signer, false)
.unwrap()
.into_verifiable_group_info()
.unwrap();
let tree_option = alice_group.export_ratchet_tree();
let (mut bob_group, public_message_commit) = MlsGroup::external_commit_builder()
.with_config(alice_group.configuration().clone())
.with_ratchet_tree(tree_option.into())
.build_group(
bob_provider,
verifiable_group_info,
bob_credential.credential_with_key.clone(),
)
.unwrap()
.load_psks(bob_provider.storage())
.unwrap()
.build(
bob_provider.rand(),
bob_provider.crypto(),
&bob_credential.signer,
|_| true,
)
.unwrap()
.finalize(bob_provider)
.unwrap();
let public_message_commit = {
let serialized_message = public_message_commit
.into_commit()
.tls_serialize_detached()
.unwrap();
MlsMessageIn::tls_deserialize(&mut serialized_message.as_slice())
.unwrap()
.into_plaintext()
.unwrap()
};
assert!(matches!(
public_message_commit.sender(),
Sender::NewMemberCommit
));
let processed_message = alice_group
.process_message(alice_provider, public_message_commit)
.unwrap();
match processed_message.into_content() {
ProcessedMessageContent::StagedCommitMessage(staged_commit) => {
alice_group
.merge_staged_commit(alice_provider, *staged_commit)
.unwrap();
}
_ => panic!("Expected Commit message"),
}
assert_eq!(
alice_group.export_secret(alice_provider.crypto(), "label", b"context", 32),
bob_group.export_secret(bob_provider.crypto(), "label", b"context", 32)
);
assert_eq!(
alice_group.export_ratchet_tree(),
bob_group.export_ratchet_tree()
);
let verifiable_group_info = alice_group
.export_group_info(alice_provider.crypto(), &alice_credential.signer, false)
.unwrap()
.into_verifiable_group_info()
.unwrap();
let tree_option = alice_group.export_ratchet_tree();
let (mut charlie_group, public_message_commit) = MlsGroup::external_commit_builder()
.with_config(alice_group.configuration().clone())
.with_ratchet_tree(tree_option.into())
.build_group(
charlie_provider,
verifiable_group_info,
charlie_credential.credential_with_key.clone(),
)
.unwrap()
.load_psks(charlie_provider.storage())
.unwrap()
.build(
charlie_provider.rand(),
charlie_provider.crypto(),
&charlie_credential.signer,
|_| true,
)
.unwrap()
.finalize(charlie_provider)
.unwrap();
let charlie_commit = MlsMessageIn::from(public_message_commit.into_commit())
.into_plaintext()
.unwrap();
let alice_processed_message = alice_group
.process_message(alice_provider, charlie_commit.clone())
.unwrap();
match alice_processed_message.into_content() {
ProcessedMessageContent::StagedCommitMessage(staged_commit) => {
alice_group
.merge_staged_commit(alice_provider, *staged_commit)
.unwrap();
}
_ => panic!("Expected Commit message"),
}
let bob_processed_message = bob_group
.process_message(bob_provider, charlie_commit)
.unwrap();
match bob_processed_message.into_content() {
ProcessedMessageContent::StagedCommitMessage(staged_commit) => {
bob_group
.merge_staged_commit(bob_provider, *staged_commit)
.unwrap();
}
_ => panic!("Expected Commit message"),
}
assert_eq!(
alice_group.export_secret(alice_provider.crypto(), "label", b"context", 32),
bob_group.export_secret(bob_provider.crypto(), "label", b"context", 32)
);
assert_eq!(
alice_group.export_secret(alice_provider.crypto(), "label", b"context", 32),
charlie_group.export_secret(charlie_provider.crypto(), "label", b"context", 32)
);
assert_eq!(
alice_group.export_ratchet_tree(),
bob_group.export_ratchet_tree()
);
assert_eq!(
alice_group.export_ratchet_tree(),
charlie_group.export_ratchet_tree()
);
let verifiable_group_info = bob_group
.export_group_info(bob_provider.crypto(), &bob_credential.signer, false)
.unwrap()
.into_verifiable_group_info()
.unwrap();
let tree_option = bob_group.export_ratchet_tree();
let (alice_group, public_message_commit) = MlsGroup::external_commit_builder()
.with_config(bob_group.configuration().clone())
.with_ratchet_tree(tree_option.into())
.build_group(
alice_provider,
verifiable_group_info,
alice_credential.credential_with_key.clone(),
)
.unwrap()
.load_psks(alice_provider.storage())
.unwrap()
.build(
alice_provider.rand(),
alice_provider.crypto(),
&alice_credential.signer,
|_| true,
)
.unwrap()
.finalize(alice_provider)
.unwrap();
let alice_commit = MlsMessageIn::from(public_message_commit.into_commit())
.into_plaintext()
.unwrap();
let bob_processed_message = bob_group
.process_message(bob_provider, alice_commit.clone())
.unwrap();
match bob_processed_message.into_content() {
ProcessedMessageContent::StagedCommitMessage(staged_commit) => {
let remove_proposals = staged_commit.remove_proposals().collect::<Vec<_>>();
assert_eq!(remove_proposals.len(), 1);
let remove_proposal = &remove_proposals[0];
assert_eq!(remove_proposal.remove_proposal().removed().u32(), 0);
bob_group
.merge_staged_commit(bob_provider, *staged_commit)
.unwrap();
}
_ => panic!("Expected Commit message"),
}
let charlie_processed_message = charlie_group
.process_message(charlie_provider, alice_commit)
.unwrap();
match charlie_processed_message.into_content() {
ProcessedMessageContent::StagedCommitMessage(staged_commit) => {
charlie_group
.merge_staged_commit(charlie_provider, *staged_commit)
.unwrap();
}
_ => panic!("Expected Commit message"),
}
assert_eq!(
alice_group.export_secret(alice_provider.crypto(), "label", b"context", 32),
bob_group.export_secret(bob_provider.crypto(), "label", b"context", 32)
);
assert_eq!(
alice_group.export_secret(alice_provider.crypto(), "label", b"context", 32),
charlie_group.export_secret(charlie_provider.crypto(), "label", b"context", 32)
);
assert_eq!(
alice_group.export_ratchet_tree(),
bob_group.export_ratchet_tree()
);
assert_eq!(
alice_group.export_ratchet_tree(),
charlie_group.export_ratchet_tree()
);
}