Skip to content

Commit

Permalink
Merge pull request #151 from mlswg/branch
Browse files Browse the repository at this point in the history
Add logic for subgroup branching
  • Loading branch information
bifurcation authored Mar 23, 2023
2 parents bc8a1d2 + d4c0764 commit 7f3a6cb
Show file tree
Hide file tree
Showing 3 changed files with 162 additions and 0 deletions.
40 changes: 40 additions & 0 deletions interop/configs/branch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
{
"scripts": {
"base": [
{"action": "createGroup", "actor": "alice"},
{"action": "externalJoin", "actor": "alice", "joiner": "bob", "members": []},
{"action": "externalJoin", "actor": "alice", "joiner": "charlie", "members": ["bob"]},
{"action": "externalJoin", "actor": "alice", "joiner": "diana", "members": ["bob", "charlie"]},
{"action": "externalJoin", "actor": "alice", "joiner": "eliza", "members": ["bob", "charlie", "diana"]},
{"action": "branch", "actor": "alice", "members": ["bob", "charlie", "diana", "eliza"]}
],

"with_extensions": [
{"action": "createGroup", "actor": "alice"},
{"action": "externalJoin", "actor": "alice", "joiner": "bob", "members": []},
{"action": "externalJoin", "actor": "alice", "joiner": "charlie", "members": ["bob"]},
{"action": "externalJoin", "actor": "alice", "joiner": "diana", "members": ["bob", "charlie"]},
{"action": "externalJoin", "actor": "alice", "joiner": "eliza", "members": ["bob", "charlie", "diana"]},
{"action": "branch", "actor": "alice", "members": ["bob", "charlie", "diana", "eliza"],
"extensions": [{"extension_type": 3, "extension_data": "AAAA"}, {"extension_type": 5, "extension_data": "AA=="} ]}
],

"external_tree": [
{"action": "createGroup", "actor": "alice"},
{"action": "externalJoin", "actor": "alice", "joiner": "bob", "members": []},
{"action": "externalJoin", "actor": "alice", "joiner": "charlie", "members": ["bob"]},
{"action": "externalJoin", "actor": "alice", "joiner": "diana", "members": ["bob", "charlie"]},
{"action": "externalJoin", "actor": "alice", "joiner": "eliza", "members": ["bob", "charlie", "diana"]},
{"action": "branch", "actor": "alice", "members": ["bob", "charlie", "diana", "eliza"], "externalTree": true}
],

"force_path": [
{"action": "createGroup", "actor": "alice"},
{"action": "externalJoin", "actor": "alice", "joiner": "bob", "members": []},
{"action": "externalJoin", "actor": "alice", "joiner": "charlie", "members": ["bob"]},
{"action": "externalJoin", "actor": "alice", "joiner": "diana", "members": ["bob", "charlie"]},
{"action": "externalJoin", "actor": "alice", "joiner": "eliza", "members": ["bob", "charlie", "diana"]},
{"action": "branch", "actor": "alice", "members": ["bob", "charlie", "diana", "eliza"], "forcePath": true}
]
}
}
34 changes: 34 additions & 0 deletions interop/proto/mls_client.proto
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ service MLSClient {
rpc HandleReInitCommit(HandleCommitRequest) returns (HandleReInitCommitResponse) {}
rpc ReInitWelcome(ReInitWelcomeRequest) returns (ReInitWelcomeResponse) {}
rpc HandleReInitWelcome(HandleReInitWelcomeRequest) returns (JoinGroupResponse) {}

// Subgroup Branching
rpc CreateBranch(CreateBranchRequest) returns (CreateBranchResponse) {}
rpc HandleBranch(HandleBranchRequest) returns (HandleBranchResponse) {}
}

// rpc Name
Expand Down Expand Up @@ -313,3 +317,33 @@ message HandleReInitWelcomeRequest {
bytes ratchet_tree = 3;
}


// rpc CreateBranch
message CreateBranchRequest {
uint32 state_id = 1;
bytes group_id = 2;
repeated Extension extensions = 3;
repeated bytes key_packages = 4;
bool force_path = 5;
bool external_tree = 6;
}

message CreateBranchResponse {
uint32 state_id = 1;
bytes welcome = 2;
bytes ratchet_tree = 3;
bytes epoch_authenticator = 4;
}

// rpc CreateBranch
message HandleBranchRequest {
uint32 state_id = 1;
uint32 transaction_id = 2;
bytes welcome = 3;
bytes ratchet_tree = 4;
}

message HandleBranchResponse {
uint32 state_id = 1;
bytes epoch_authenticator = 2;
}
88 changes: 88 additions & 0 deletions interop/test-runner/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ const (
ActionProtect ScriptAction = "protect"
ActionUnprotect ScriptAction = "unprotect"
ActionReInit ScriptAction = "reinit"
ActionBranch ScriptAction = "branch"

TimeoutSeconds = 120
)
Expand Down Expand Up @@ -181,6 +182,13 @@ type ReInitStepParams struct {
ExternalTree bool `json:"externalTree"`
}

type BranchStepParams struct {
Members []string `json:"members"`
ForcePath bool `json:"force_path"`
ExternalTree bool `json:"external_tree"`
Extensions []*pb.Extension `json:"extensions"`
}

func (step *ScriptStep) UnmarshalJSON(data []byte) error {
var parsed map[string]interface{}
err := json.Unmarshal(data, &parsed)
Expand Down Expand Up @@ -1211,6 +1219,86 @@ func (config *ScriptActorConfig) RunStep(index int, step ScriptStep) error {
config.stateID[member] = resp.StateId
}

case ActionBranch:
// XXX(RLB): Note that after this step, the state IDs remembered by the test
// runner will be for the members' states in the *new* group. It would be
// nice to test that both the old and new groups now work. But it's not
// clear how to do that in the scripting language.
// XXX(RLB): Also, this step does not write any output to the transcript
// right now, for similar reasons to ActionReInit and previous XXX note.
var params BranchStepParams
err := json.Unmarshal(step.Raw, &params)
if err != nil {
return err
}

// Get KeyPackages from the members
transactionIDs := map[string]uint32{}
keyPackages := [][]byte{}
for _, member := range params.Members {
client := config.ActorClients[member]
req := &pb.CreateKeyPackageRequest{
CipherSuite: config.CipherSuite,
Identity: []byte(member),
}
resp, err := client.rpc.CreateKeyPackage(ctx(), req)
if err != nil {
return err
}

transactionIDs[member] = resp.TransactionId
keyPackages = append(keyPackages, resp.KeyPackage)
}

// Have the committer create a branch Welcome
var welcome []byte
var ratchetTree []byte
var epochAuthenticator []byte
{
client := config.ActorClients[step.Actor]
req := &pb.CreateBranchRequest{
StateId: config.stateID[step.Actor],
GroupId: []byte(uuid.New().String()),
Extensions: params.Extensions,
KeyPackages: keyPackages,
ForcePath: params.ForcePath,
ExternalTree: params.ExternalTree,
}
resp, err := client.rpc.CreateBranch(ctx(), req)
if err != nil {
return err
}

welcome = resp.Welcome
epochAuthenticator = resp.EpochAuthenticator
if params.ExternalTree {
ratchetTree = resp.RatchetTree
}

config.stateID[step.Actor] = resp.StateId
}

// Apply the Welcome at each other member
for _, member := range params.Members {
client := config.ActorClients[member]
req := &pb.HandleBranchRequest{
StateId: config.stateID[member],
TransactionId: transactionIDs[member],
Welcome: welcome,
RatchetTree: ratchetTree,
}
resp, err := client.rpc.HandleBranch(ctx(), req)
if err != nil {
return err
}

if !bytes.Equal(resp.EpochAuthenticator, epochAuthenticator) {
return fmt.Errorf("Member [%s] failed to agree on epoch authenticator", member)
}

config.stateID[member] = resp.StateId
}

default:
return fmt.Errorf("Unknown action: %s", step.Action)
}
Expand Down

0 comments on commit 7f3a6cb

Please sign in to comment.