-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Detect and mark inactive members after the ephemeral pubkey generation
The phase 2 of the GJKR protocol generating symmetric keys should find members inactive in phase 1 and mark them accordingly. I introduced this logic in a new file, message_filter.go and moved there the deduplication logic as well. The goal is to have all the message pre-processing for all phases in one place. For phase 2, the pre-processing includes deduplication, inactive member detection, and session ID handling (to be added in the next commits). For further phases, we will also have to filter out members marked as inactive or disqualified in previous phases of the protocol.
- Loading branch information
Showing
6 changed files
with
177 additions
and
20 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
package gjkr | ||
|
||
// findInactive goes through the messages passed as a parameter and finds all | ||
// inactive members for this set of messages. The function does not care if | ||
// the given member was already marked as inactive before. The function makes no | ||
// assumptions about the ordering of the list elements. | ||
func findInactive[T interface{ senderIdx() memberIndex }]( | ||
groupSize uint16, list []T, | ||
) []memberIndex { | ||
senders := make(map[memberIndex]bool) | ||
for _, item := range list { | ||
senders[item.senderIdx()] = true | ||
} | ||
|
||
inactive := make([]memberIndex, 0) | ||
for i := uint16(1); i <= groupSize; i++ { | ||
if !senders[memberIndex(i)] { | ||
inactive = append(inactive, memberIndex(i)) | ||
} | ||
} | ||
|
||
return inactive | ||
} | ||
|
||
// deduplicateBySender removes duplicated items for the given sender. It always | ||
// takes the first item that occurs for the given sender and ignores the | ||
// subsequent ones. | ||
func deduplicateBySender[T interface{ senderIdx() memberIndex }]( | ||
list []T, | ||
) []T { | ||
senders := make(map[memberIndex]bool) | ||
result := make([]T, 0) | ||
|
||
for _, item := range list { | ||
if _, exists := senders[item.senderIdx()]; !exists { | ||
senders[item.senderIdx()] = true | ||
result = append(result, item) | ||
} | ||
} | ||
|
||
return result | ||
} | ||
|
||
func (m *symmetricKeyGeneratingMember) preProcessMessages( | ||
ephemeralPubKeyMessages []*ephemeralPublicKeyMessage, | ||
) []*ephemeralPublicKeyMessage { | ||
inactiveMembers := findInactive(m.group.groupSize, ephemeralPubKeyMessages) | ||
for _, ia := range inactiveMembers { | ||
m.group.markMemberAsInactive(ia) | ||
} | ||
|
||
// TODO: validate session ID | ||
|
||
return deduplicateBySender(ephemeralPubKeyMessages) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
package gjkr | ||
|
||
import ( | ||
"testing" | ||
|
||
"threshold.network/roast/internal/testutils" | ||
) | ||
|
||
func TestFindInactive(t *testing.T) { | ||
var tests = map[string]struct { | ||
groupSize uint16 | ||
senders []memberIndex | ||
expectedIA []memberIndex | ||
}{ | ||
"with no inactive senders": { | ||
groupSize: 5, | ||
senders: []memberIndex{1, 4, 3, 2, 5}, | ||
expectedIA: []memberIndex{}, | ||
}, | ||
"with inactivity and senders ordered": { | ||
groupSize: 5, | ||
senders: []memberIndex{1, 3, 5}, | ||
expectedIA: []memberIndex{2, 4}, | ||
}, | ||
"with inactivity and senders not ordered": { | ||
groupSize: 5, | ||
senders: []memberIndex{5, 1, 3}, | ||
expectedIA: []memberIndex{2, 4}, | ||
}, | ||
"with all senders inactive": { | ||
groupSize: 5, | ||
senders: []memberIndex{}, | ||
expectedIA: []memberIndex{1, 2, 3, 4, 5}, | ||
}, | ||
} | ||
|
||
for testName, test := range tests { | ||
t.Run(testName, func(t *testing.T) { | ||
messages := make([]*ephemeralPublicKeyMessage, len(test.senders)) | ||
for i, senderIndex := range test.senders { | ||
messages[i] = &ephemeralPublicKeyMessage{senderIndex: senderIndex} | ||
} | ||
|
||
ia := findInactive(test.groupSize, messages) | ||
testutils.AssertUint16SlicesEqual( | ||
t, | ||
"inactive members", | ||
test.expectedIA, | ||
ia, | ||
) | ||
}) | ||
} | ||
} | ||
|
||
func TestDeduplicateBySender(t *testing.T) { | ||
var tests = map[string]struct { | ||
senders []memberIndex | ||
expectedDeduplicated []memberIndex | ||
}{ | ||
"with no duplicates": { | ||
senders: []memberIndex{1, 4, 3, 2, 5}, | ||
expectedDeduplicated: []memberIndex{1, 4, 3, 2, 5}, | ||
}, | ||
"with duplicates and senders ordered": { | ||
senders: []memberIndex{1, 1, 2, 3, 3, 4, 5, 5}, | ||
expectedDeduplicated: []memberIndex{1, 2, 3, 4, 5}, | ||
}, | ||
"with duplicates and senders not ordered": { | ||
senders: []memberIndex{5, 2, 5, 3, 1, 3, 3, 2, 5, 4, 5}, | ||
expectedDeduplicated: []memberIndex{5, 2, 3, 1, 4}, | ||
}, | ||
} | ||
|
||
for testName, test := range tests { | ||
t.Run(testName, func(t *testing.T) { | ||
messages := make([]*ephemeralPublicKeyMessage, len(test.senders)) | ||
for i, senderIndex := range test.senders { | ||
messages[i] = &ephemeralPublicKeyMessage{senderIndex: senderIndex} | ||
} | ||
|
||
deduplicatedSenders := make([]memberIndex, 0) | ||
for _, msg := range deduplicateBySender(messages) { | ||
deduplicatedSenders = append(deduplicatedSenders, msg.senderIdx()) | ||
} | ||
testutils.AssertUint16SlicesEqual( | ||
t, | ||
"deduplicated senders", | ||
test.expectedDeduplicated, | ||
deduplicatedSenders, | ||
) | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters