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

Add support for Light MLS #436

Merged
merged 32 commits into from
Nov 5, 2024
Merged
Show file tree
Hide file tree
Changes from 23 commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
787d1cf
Move tree storage from vector to map.
bifurcation Apr 10, 2024
6ec8042
Add tree slice logic
bifurcation May 21, 2024
160d162
Add a flags extension
bifurcation May 21, 2024
eee9d1b
Add the ability for clients to join as light
bifurcation May 24, 2024
c3fe4ee
Implement LightCommit more or less along the lines in the draft
bifurcation May 29, 2024
9b3efa4
Fix build errors after rebase
bifurcation Aug 22, 2024
62efc72
Add the ability for a light client to upgrade to being a full client
bifurcation Aug 22, 2024
bb6372b
Add the ability to handle an AnnotatedCommit
bifurcation Aug 26, 2024
d79877b
Add the ability to generate annotated commits
bifurcation Aug 26, 2024
101a9de
Add an AnnotatedCommit test
bifurcation Aug 26, 2024
53f38b6
Handle GroupContextExtensions and PSKs via proposals, not annotations
bifurcation Aug 26, 2024
3ebb0df
Optionally run passive client tests as a light client
bifurcation Aug 26, 2024
4e741b1
Add DS utilities library
bifurcation Aug 27, 2024
37375c3
Use TreeFollower in light passive client tests
bifurcation Aug 27, 2024
29095b8
Update AnnotatedCommit to work with new commit structure
bifurcation Sep 27, 2024
e3d678b
Enable light clients to process external joins
bifurcation Sep 29, 2024
52a5829
Properly ignore sender membership proofs in the external commit case
bifurcation Sep 29, 2024
41929f9
Revert in-Welcome sending of membership proofs
bifurcation Oct 11, 2024
f1c6169
Add a test case that shows client fast-join behavior
bifurcation Oct 16, 2024
5245675
Fix external commit test
bifurcation Nov 1, 2024
1d9615a
Clean up AnnotatedWelcome API
bifurcation Nov 1, 2024
16cc29f
Allow light clients to validate parent hashes
bifurcation Nov 1, 2024
cd1f9a5
clang-tidy
bifurcation Nov 1, 2024
ae8c1db
clang-format
bifurcation Nov 4, 2024
62c422c
Revert changes to passive client test vector processing
bifurcation Nov 4, 2024
a4c99d3
Fix shadowing warnings on Windows
bifurcation Nov 4, 2024
c1018c7
clang-format
bifurcation Nov 4, 2024
d114d73
Add missing mls_ds dependency
bifurcation Nov 4, 2024
ccd9dd0
Fix windows build
bifurcation Nov 4, 2024
5059492
Remove unneeded flags extension
bifurcation Nov 5, 2024
8a8af8f
Don't replicate proposals in the AnnotatedCommit
bifurcation Nov 5, 2024
de22676
clang-format
bifurcation Nov 5, 2024
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
1 change: 1 addition & 0 deletions .clang-tidy
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ Checks: '*,
-google-runtime-references,
-hicpp-no-assembler,
-hicpp-special-member-functions,-warnings-as-errors,
-hicpp-signed-bitwise,
-llvm-include-order,
-llvmlibc-callee-namespace,
-llvmlibc-implementation-in-namespace,
Expand Down
31 changes: 24 additions & 7 deletions cmd/interop/src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,14 @@ using nlohmann::json;
using namespace mls_client;
using namespace mls_vectors;

#define NO_U64 0xffffffffffffffff
DEFINE_uint64(gen, NO_U64, "Generate test vectors of a given type");
DEFINE_uint64(ver, NO_U64, "Verify test vectors of a given type");
DEFINE_uint64(live,
NO_U64,
"Run a gRPC live-testing server on the specified port");
DEFINE_bool(light, false, "Run passive client tests as a light client");

// Values used on the command line to indicate the type of test vector to be
// generated / verified
enum struct TestVectorClass
Expand Down Expand Up @@ -191,6 +199,22 @@ verify_test_vector(const json& j)
return std::nullopt;
}

template<>
std::optional<std::string>
verify_test_vector<PassiveClientTestVector>(const json& j)
{
auto cases = j.get<std::vector<PassiveClientTestVector>>();
for (auto& tc : cases) {
tc.light_client = FLAGS_light;
auto result = tc.verify();
if (result) {
return result;
}
}

return std::nullopt;
}

static std::optional<std::string>
verify_test_vector(uint64_t type)
{
Expand Down Expand Up @@ -241,13 +265,6 @@ verify_test_vector(uint64_t type)
}
}

#define NO_U64 0xffffffffffffffff
DEFINE_uint64(gen, NO_U64, "Generate test vectors of a given type");
DEFINE_uint64(ver, NO_U64, "Verify test vectors of a given type");
DEFINE_uint64(live,
NO_U64,
"Run a gRPC live-testing server on the specified port");

int
main(int argc, char* argv[])
{
Expand Down
49 changes: 28 additions & 21 deletions cmd/interop/src/mls_client_impl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1062,14 +1062,16 @@ MLSClientImpl::commit(CachedState& entry,
by_value.emplace_back(std::move(proposal));
}

auto force_path = request->force_path();
auto inline_tree = !request->external_tree();
const auto force_path = request->force_path();
const auto inline_tree = !request->external_tree();
const auto include_membership_proof = false;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking at this, we haven't updated this code since we moved to AnnotatedWelcome. I'll update and request re-review.


auto leaf_secret =
MLS_NAMESPACE::random_bytes(entry.state.cipher_suite().secret_size());
auto [commit, welcome, next] = entry.state.commit(
leaf_secret,
MLS_NAMESPACE::CommitOpts{ by_value, inline_tree, force_path, {} },
MLS_NAMESPACE::CommitOpts{
by_value, inline_tree, force_path, include_membership_proof, {} },
entry.message_opts());

if (!inline_tree) {
Expand Down Expand Up @@ -1337,10 +1339,13 @@ MLSClientImpl::reinit_commit(CachedState& entry,
throw std::runtime_error("Commit included among proposals");
}

const auto include_membership_proof = false;

const auto leaf_secret =
MLS_NAMESPACE::random_bytes(entry.state.cipher_suite().secret_size());
const auto commit_opts =
MLS_NAMESPACE::CommitOpts{ {}, inline_tree, force_path, {} };
const auto commit_opts = MLS_NAMESPACE::CommitOpts{
{}, inline_tree, force_path, include_membership_proof, {}
};
auto [tombstone, commit] =
entry.state.reinit_commit(leaf_secret, commit_opts, entry.message_opts());

Expand Down Expand Up @@ -1450,16 +1455,17 @@ MLSClientImpl::reinit_welcome(const ReInitWelcomeRequest* request,
// Create the Welcome
const auto inline_tree = !request->external_tree();
const auto force_path = request->force_path();
const auto include_membership_proof = false;
const auto cipher_suite = reinit->tombstone.reinit.cipher_suite;
const auto leaf_secret =
MLS_NAMESPACE::random_bytes(cipher_suite.secret_size());
auto [state, welcome] =
reinit->tombstone.create_welcome(reinit->kp_priv.encryption_priv,
reinit->kp_priv.signature_priv,
reinit->kp_priv.key_package.leaf_node,
key_packages,
leaf_secret,
{ {}, inline_tree, force_path, {} });
auto [state, welcome] = reinit->tombstone.create_welcome(
reinit->kp_priv.encryption_priv,
reinit->kp_priv.signature_priv,
reinit->kp_priv.key_package.leaf_node,
key_packages,
leaf_secret,
{ {}, inline_tree, force_path, include_membership_proof, {} });

const auto welcome_data =
MLS_NAMESPACE::tls::marshal(MLS_NAMESPACE::MLSMessage{ welcome });
Expand Down Expand Up @@ -1552,20 +1558,21 @@ MLSClientImpl::create_branch(CachedState& entry,

const auto inline_tree = !request->external_tree();
const auto force_path = request->force_path();
const auto include_membership_proof = false;
const auto group_id = string_to_bytes(request->group_id());
const auto cipher_suite = entry.state.cipher_suite();
const auto kp_priv = new_key_package(cipher_suite, identity);
const auto leaf_secret =
MLS_NAMESPACE::random_bytes(cipher_suite.secret_size());
auto [next, welcome] =
entry.state.create_branch(group_id,
kp_priv.encryption_priv,
kp_priv.signature_priv,
kp_priv.key_package.leaf_node,
ext_list,
key_packages,
leaf_secret,
{ {}, inline_tree, force_path, {} });
auto [next, welcome] = entry.state.create_branch(
group_id,
kp_priv.encryption_priv,
kp_priv.signature_priv,
kp_priv.key_package.leaf_node,
ext_list,
key_packages,
leaf_secret,
{ {}, inline_tree, force_path, include_membership_proof, {} });

const auto epoch_authenticator = next.epoch_authenticator();

Expand Down
12 changes: 11 additions & 1 deletion include/mls/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -216,11 +216,21 @@ std::vector<Value>
transform(const Container& c, const UnaryOperation& op)
{
auto out = std::vector<Value>{};
auto ins = std::inserter(out, out.begin());
auto ins = std::back_inserter(out);
std::transform(c.begin(), c.end(), ins, op);
return out;
}

template<typename Value, typename Container, typename UnaryOperation>
std::vector<Value>
filter(const Container& c, const UnaryOperation& op)
{
auto out = std::vector<Value>{};
auto ins = std::back_inserter(out);
std::copy_if(c.begin(), c.end(), ins, op);
return out;
}

template<typename Container, typename UnaryPredicate>
bool
any_of(const Container& c, const UnaryPredicate& pred)
Expand Down
64 changes: 64 additions & 0 deletions include/mls/messages.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,20 @@ struct ExternalSendersExtension
TLS_SERIALIZABLE(senders);
};

struct FlagsExtension
{
std::vector<uint8_t> flag_data;

void set(size_t pos);
void unset(size_t pos);
bool get(size_t pos) const;

static const uint16_t type;

// XXX(RLB): This should check for extra zero bytes on deserialize.
TLS_SERIALIZABLE(flag_data);
};

struct SFrameParameters
{
uint16_t cipher_suite;
Expand Down Expand Up @@ -257,6 +271,8 @@ struct Welcome
const std::vector<PSKWithSecret>& psks);
};

struct MLSMessage;

///
/// Proposals & Commit
///
Expand Down Expand Up @@ -691,6 +707,54 @@ external_proposal(CipherSuite suite,
uint32_t signer_index,
const SignaturePrivateKey& sig_priv);

struct AnnotatedWelcome
{
Welcome welcome;

TreeSlice sender_membership_proof;
TreeSlice receiver_membership_proof;

static AnnotatedWelcome from(Welcome welcome,
const TreeKEMPublicKey& tree,
LeafIndex sender,
LeafIndex joiner);

TreeKEMPublicKey tree() const;

TLS_SERIALIZABLE(welcome,
sender_membership_proof,
receiver_membership_proof);
};

struct AnnotatedCommit
{
MLSMessage commit_message;
bytes tree_hash_after;

std::optional<TreeSlice> sender_membership_proof_before;
TreeSlice sender_membership_proof_after;
TreeSlice receiver_membership_proof_after;

std::optional<uint32_t> resolution_index;
std::optional<ExtensionList> extensions;
std::vector<PreSharedKeyID> psks;

static AnnotatedCommit from(LeafIndex receiver,
const std::vector<MLSMessage>& proposals,
const MLSMessage& commit_message,
const TreeKEMPublicKey& tree_before,
const TreeKEMPublicKey& tree_after);

TLS_SERIALIZABLE(commit_message,
tree_hash_after,
sender_membership_proof_before,
sender_membership_proof_after,
receiver_membership_proof_after,
resolution_index,
extensions,
psks);
};

} // namespace MLS_NAMESPACE

namespace MLS_NAMESPACE::tls {
Expand Down
20 changes: 18 additions & 2 deletions include/mls/state.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,16 @@ struct RosterIndex : public UInt32

struct CommitOpts
{
// Include these proposals in the commit by value
std::vector<Proposal> extra_proposals;
bool inline_tree;
bool force_path;

// Send a ratchet_tree extension in the Welcome
bool inline_tree = false;

// Send an UpdatePath even if none is required
bool force_path = false;

// Update the committer's LeafNode in the following way
LeafNodeOptions leaf_node_opts;
};

Expand Down Expand Up @@ -127,6 +134,14 @@ class State
std::optional<State> handle(const ValidatedContent& content_auth,
std::optional<State> cached_state);

///
/// Light MLS
///
void implant_tree_slice(const TreeSlice& slice);
State handle(const AnnotatedCommit& annotated_commit);
bool is_full_client() const { return _tree.is_complete(); }
void upgrade_to_full_client(TreeKEMPublicKey tree);

///
/// PSK management
///
Expand Down Expand Up @@ -327,6 +342,7 @@ class State
CommitMaterials prepare_commit(const bytes& leaf_secret,
const std::optional<CommitOpts>& opts,
const CommitParams& params) const;
GroupInfo group_info(bool external_pub, bool inline_tree) const;
Welcome welcome(bool inline_tree,
const std::vector<PSKWithSecret>& psks,
const std::vector<KeyPackage>& joiners,
Expand Down
4 changes: 2 additions & 2 deletions include/mls/tree_math.h
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,8 @@ struct NodeIndex : public UInt32
// of `ancestor` that is not in the direct path of this node.
NodeIndex sibling(NodeIndex ancestor) const;

std::vector<NodeIndex> dirpath(LeafCount n);
std::vector<NodeIndex> copath(LeafCount n);
std::vector<NodeIndex> dirpath(LeafCount n) const;
std::vector<NodeIndex> copath(LeafCount n) const;

uint32_t level() const;
};
Expand Down
Loading
Loading