Skip to content

Commit d7dd6f7

Browse files
authored
Merge pull request #1603 from keep-network/minimal-number-of-supporting-signatures
Adding signature safety margin on DKG result We are increasing the DKG nofail signature threshold to 75%. It gives us a 25% safety margin for relay entry signing.
2 parents 5608f1a + a1a8568 commit d7dd6f7

9 files changed

Lines changed: 201 additions & 146 deletions

File tree

pkg/beacon/relay/dkg/result/integration_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import (
1414
func TestExecute_IA_members24_phase13(t *testing.T) {
1515
t.Parallel()
1616

17-
groupSize := 5
17+
groupSize := 6
1818
honestThreshold := 3
1919
seed := dkgtest.RandomSeed(t)
2020

@@ -39,5 +39,5 @@ func TestExecute_IA_members24_phase13(t *testing.T) {
3939
dkgtest.AssertSamePublicKey(t, result)
4040
dkgtest.AssertNoMisbehavingMembers(t, result)
4141
dkgtest.AssertValidGroupPublicKey(t, result)
42-
dkgtest.AssertResultSupportingMembers(t, result, []group.MemberIndex{1, 3, 5}...)
42+
dkgtest.AssertResultSupportingMembers(t, result, []group.MemberIndex{1, 3, 5, 6}...)
4343
}

pkg/beacon/relay/dkg/result/submission.go

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,11 +61,15 @@ func (sm *SubmittingMember) SubmitDKGResult(
6161
)
6262
}
6363

64-
if len(signatures) < config.HonestThreshold {
64+
// Chain rejects the result if it has less than 25% safety margin.
65+
// If there are not enough signatures to preserve the margin, it does not
66+
// make sense to submit the result.
67+
signatureThreshold := config.HonestThreshold + (config.GroupSize-config.HonestThreshold)/2
68+
if len(signatures) < signatureThreshold {
6569
return fmt.Errorf(
66-
"could not submit result with [%v] signatures for honest threshold [%v]",
70+
"could not submit result with [%v] signatures for signature threshold [%v]",
6771
len(signatures),
68-
config.HonestThreshold,
72+
signatureThreshold,
6973
)
7074
}
7175

pkg/beacon/relay/dkg/result/submission_test.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ func TestSubmitDKGResult(t *testing.T) {
3232
1: []byte{101},
3333
2: []byte{102},
3434
3: []byte{103},
35+
4: []byte{104},
3536
}
3637

3738
tStep := config.ResultPublicationBlockStep
@@ -130,6 +131,7 @@ func TestConcurrentPublishResult(t *testing.T) {
130131
1: []byte{101},
131132
2: []byte{102},
132133
3: []byte{103},
134+
4: []byte{104},
133135
}
134136

135137
var tests = map[string]struct {

pkg/beacon/relay/gjkr/integration_test.go

Lines changed: 27 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ func TestExecute_IA_member1_phase8(t *testing.T) {
205205
func TestExecute_IA_members35_phase10(t *testing.T) {
206206
t.Parallel()
207207

208-
groupSize := 5
208+
groupSize := 6
209209
honestThreshold := 3
210210
seed := dkgtest.RandomSeed(t)
211211

@@ -226,12 +226,12 @@ func TestExecute_IA_members35_phase10(t *testing.T) {
226226

227227
dkgtest.AssertDkgResultPublished(t, result)
228228
dkgtest.AssertSuccessfulSignersCount(t, result, groupSize-2)
229-
dkgtest.AssertSuccessfulSigners(t, result, []group.MemberIndex{1, 2, 4}...)
229+
dkgtest.AssertSuccessfulSigners(t, result, []group.MemberIndex{1, 2, 4, 6}...)
230230
dkgtest.AssertMemberFailuresCount(t, result, 2)
231231
dkgtest.AssertSamePublicKey(t, result)
232232
dkgtest.AssertMisbehavingMembers(t, result, group.MemberIndex(3), group.MemberIndex(5))
233233
dkgtest.AssertValidGroupPublicKey(t, result)
234-
dkgtest.AssertResultSupportingMembers(t, result, []group.MemberIndex{1, 2, 4}...)
234+
dkgtest.AssertResultSupportingMembers(t, result, []group.MemberIndex{1, 2, 4, 6}...)
235235
}
236236

237237
// Phase 2 test case - a member sends an invalid ephemeral public key message.
@@ -523,7 +523,7 @@ func TestExecute_DQ_member4_falseAccusation_phase5(t *testing.T) {
523523
func TestExecute_DQ_member2_accusesInactiveMember_phase5(t *testing.T) {
524524
t.Parallel()
525525

526-
groupSize := 5
526+
groupSize := 6
527527
honestThreshold := 3
528528
seed := dkgtest.RandomSeed(t)
529529

@@ -569,12 +569,12 @@ func TestExecute_DQ_member2_accusesInactiveMember_phase5(t *testing.T) {
569569

570570
dkgtest.AssertDkgResultPublished(t, result)
571571
dkgtest.AssertSuccessfulSignersCount(t, result, groupSize-2)
572-
dkgtest.AssertSuccessfulSigners(t, result, []group.MemberIndex{3, 4, 5}...)
572+
dkgtest.AssertSuccessfulSigners(t, result, []group.MemberIndex{3, 4, 5, 6}...)
573573
dkgtest.AssertMemberFailuresCount(t, result, 2)
574574
dkgtest.AssertSamePublicKey(t, result)
575575
dkgtest.AssertMisbehavingMembers(t, result, []group.MemberIndex{1, 2}...)
576576
dkgtest.AssertValidGroupPublicKey(t, result)
577-
dkgtest.AssertResultSupportingMembers(t, result, []group.MemberIndex{3, 4, 5}...)
577+
dkgtest.AssertResultSupportingMembers(t, result, []group.MemberIndex{3, 4, 5, 6}...)
578578
}
579579

580580
// Phase 8 test case - a member sends an invalid member public key share points
@@ -672,7 +672,7 @@ func TestExecute_DQ_members25_revealWrongPrivateKey_phase9(t *testing.T) {
672672
func TestExecute_DQ_members14_invalidPublicKeyShare_phase9(t *testing.T) {
673673
t.Parallel()
674674

675-
groupSize := 5
675+
groupSize := 6
676676
honestThreshold := 3
677677
seed := dkgtest.RandomSeed(t)
678678

@@ -704,12 +704,12 @@ func TestExecute_DQ_members14_invalidPublicKeyShare_phase9(t *testing.T) {
704704

705705
dkgtest.AssertDkgResultPublished(t, result)
706706
dkgtest.AssertSuccessfulSignersCount(t, result, groupSize-2)
707-
dkgtest.AssertSuccessfulSigners(t, result, []group.MemberIndex{2, 3, 5}...)
707+
dkgtest.AssertSuccessfulSigners(t, result, []group.MemberIndex{2, 3, 5, 6}...)
708708
dkgtest.AssertMemberFailuresCount(t, result, 2)
709709
dkgtest.AssertSamePublicKey(t, result)
710710
dkgtest.AssertMisbehavingMembers(t, result, []group.MemberIndex{1, 4}...)
711711
dkgtest.AssertValidGroupPublicKey(t, result)
712-
dkgtest.AssertResultSupportingMembers(t, result, []group.MemberIndex{2, 3, 5}...)
712+
dkgtest.AssertResultSupportingMembers(t, result, []group.MemberIndex{2, 3, 5, 6}...)
713713
}
714714

715715
// Phase 9 test case - a member misbehaved by performing a false accusation
@@ -771,7 +771,7 @@ func TestExecute_DQ_member4_falseAccusation_phase9(t *testing.T) {
771771
func TestExecute_DQ_member2_accusesInactiveMember_phase9(t *testing.T) {
772772
t.Parallel()
773773

774-
groupSize := 5
774+
groupSize := 6
775775
honestThreshold := 3
776776
seed := dkgtest.RandomSeed(t)
777777

@@ -816,12 +816,12 @@ func TestExecute_DQ_member2_accusesInactiveMember_phase9(t *testing.T) {
816816

817817
dkgtest.AssertDkgResultPublished(t, result)
818818
dkgtest.AssertSuccessfulSignersCount(t, result, groupSize-2)
819-
dkgtest.AssertSuccessfulSigners(t, result, []group.MemberIndex{3, 4, 5}...)
819+
dkgtest.AssertSuccessfulSigners(t, result, []group.MemberIndex{3, 4, 5, 6}...)
820820
dkgtest.AssertMemberFailuresCount(t, result, 2)
821821
dkgtest.AssertSamePublicKey(t, result)
822822
dkgtest.AssertMisbehavingMembers(t, result, []group.MemberIndex{1, 2}...)
823823
dkgtest.AssertValidGroupPublicKey(t, result)
824-
dkgtest.AssertResultSupportingMembers(t, result, []group.MemberIndex{3, 4, 5}...)
824+
dkgtest.AssertResultSupportingMembers(t, result, []group.MemberIndex{3, 4, 5, 6}...)
825825
}
826826

827827
// Phase 9 test case - a member misbehaved by sending shares which
@@ -832,7 +832,7 @@ func TestExecute_DQ_member2_accusesInactiveMember_phase9(t *testing.T) {
832832
func TestExecute_DQ_members12_cannotDecryptTheirShares_phase9(t *testing.T) {
833833
t.Parallel()
834834

835-
groupSize := 5
835+
groupSize := 6
836836
honestThreshold := 3
837837
seed := dkgtest.RandomSeed(t)
838838

@@ -883,12 +883,12 @@ func TestExecute_DQ_members12_cannotDecryptTheirShares_phase9(t *testing.T) {
883883

884884
dkgtest.AssertDkgResultPublished(t, result)
885885
dkgtest.AssertSuccessfulSignersCount(t, result, groupSize-2)
886-
dkgtest.AssertSuccessfulSigners(t, result, []group.MemberIndex{3, 4, 5}...)
886+
dkgtest.AssertSuccessfulSigners(t, result, []group.MemberIndex{3, 4, 5, 6}...)
887887
dkgtest.AssertMemberFailuresCount(t, result, 2)
888888
dkgtest.AssertSamePublicKey(t, result)
889889
dkgtest.AssertMisbehavingMembers(t, result, []group.MemberIndex{1, 2}...)
890890
dkgtest.AssertValidGroupPublicKey(t, result)
891-
dkgtest.AssertResultSupportingMembers(t, result, []group.MemberIndex{3, 4, 5}...)
891+
dkgtest.AssertResultSupportingMembers(t, result, []group.MemberIndex{3, 4, 5, 6}...)
892892
}
893893

894894
// Phase 11 test case - a member misbehaved by not revealing its private key
@@ -899,7 +899,7 @@ func TestExecute_DQ_members12_cannotDecryptTheirShares_phase9(t *testing.T) {
899899
func TestExecute_DQ_member2_notRevealsDisqualifiedQualMemberKey_phase11(t *testing.T) {
900900
t.Parallel()
901901

902-
groupSize := 5
902+
groupSize := 6
903903
honestThreshold := 3
904904
seed := dkgtest.RandomSeed(t)
905905

@@ -936,12 +936,12 @@ func TestExecute_DQ_member2_notRevealsDisqualifiedQualMemberKey_phase11(t *testi
936936

937937
dkgtest.AssertDkgResultPublished(t, result)
938938
dkgtest.AssertSuccessfulSignersCount(t, result, groupSize-2)
939-
dkgtest.AssertSuccessfulSigners(t, result, []group.MemberIndex{3, 4, 5}...)
939+
dkgtest.AssertSuccessfulSigners(t, result, []group.MemberIndex{3, 4, 5, 6}...)
940940
dkgtest.AssertMemberFailuresCount(t, result, 2)
941941
dkgtest.AssertSamePublicKey(t, result)
942942
dkgtest.AssertMisbehavingMembers(t, result, []group.MemberIndex{1, 2}...)
943943
dkgtest.AssertValidGroupPublicKey(t, result)
944-
dkgtest.AssertResultSupportingMembers(t, result, []group.MemberIndex{3, 4, 5}...)
944+
dkgtest.AssertResultSupportingMembers(t, result, []group.MemberIndex{3, 4, 5, 6}...)
945945
}
946946

947947
// Phase 11 test case - a member misbehaved by revealing key of an operating
@@ -993,7 +993,7 @@ func TestExecute_DQ_member2_revealedKeyOfOperatingMember_phase11(t *testing.T) {
993993
func TestExecute_DQ_member5_revealsWrongPrivateKey_phase11(t *testing.T) {
994994
t.Parallel()
995995

996-
groupSize := 5
996+
groupSize := 6
997997
honestThreshold := 3
998998
seed := dkgtest.RandomSeed(t)
999999

@@ -1034,12 +1034,12 @@ func TestExecute_DQ_member5_revealsWrongPrivateKey_phase11(t *testing.T) {
10341034

10351035
dkgtest.AssertDkgResultPublished(t, result)
10361036
dkgtest.AssertSuccessfulSignersCount(t, result, groupSize-2)
1037-
dkgtest.AssertSuccessfulSigners(t, result, []group.MemberIndex{1, 2, 3}...)
1037+
dkgtest.AssertSuccessfulSigners(t, result, []group.MemberIndex{1, 2, 3, 6}...)
10381038
dkgtest.AssertMemberFailuresCount(t, result, 2)
10391039
dkgtest.AssertSamePublicKey(t, result)
10401040
dkgtest.AssertMisbehavingMembers(t, result, []group.MemberIndex{4, 5}...)
10411041
dkgtest.AssertValidGroupPublicKey(t, result)
1042-
dkgtest.AssertResultSupportingMembers(t, result, []group.MemberIndex{1, 2, 3}...)
1042+
dkgtest.AssertResultSupportingMembers(t, result, []group.MemberIndex{1, 2, 3, 6}...)
10431043
}
10441044

10451045
// Phase 11 test case - a member misbehaved by revealing private key generated for
@@ -1049,7 +1049,7 @@ func TestExecute_DQ_member5_revealsWrongPrivateKey_phase11(t *testing.T) {
10491049
func TestExecute_DQ_member2_revealsInactiveNonQualMemberKey_phase11(t *testing.T) {
10501050
t.Parallel()
10511051

1052-
groupSize := 5
1052+
groupSize := 6
10531053
honestThreshold := 3
10541054
seed := dkgtest.RandomSeed(t)
10551055

@@ -1094,12 +1094,12 @@ func TestExecute_DQ_member2_revealsInactiveNonQualMemberKey_phase11(t *testing.T
10941094

10951095
dkgtest.AssertDkgResultPublished(t, result)
10961096
dkgtest.AssertSuccessfulSignersCount(t, result, groupSize-2)
1097-
dkgtest.AssertSuccessfulSigners(t, result, []group.MemberIndex{3, 4, 5}...)
1097+
dkgtest.AssertSuccessfulSigners(t, result, []group.MemberIndex{3, 4, 5, 6}...)
10981098
dkgtest.AssertMemberFailuresCount(t, result, 2)
10991099
dkgtest.AssertSamePublicKey(t, result)
11001100
dkgtest.AssertMisbehavingMembers(t, result, []group.MemberIndex{1, 2}...)
11011101
dkgtest.AssertValidGroupPublicKey(t, result)
1102-
dkgtest.AssertResultSupportingMembers(t, result, []group.MemberIndex{3, 4, 5}...)
1102+
dkgtest.AssertResultSupportingMembers(t, result, []group.MemberIndex{3, 4, 5, 6}...)
11031103
}
11041104

11051105
// Phase 11 test case - a member misbehaved by sending shares which
@@ -1113,7 +1113,7 @@ func TestExecute_DQ_member2_revealsInactiveNonQualMemberKey_phase11(t *testing.T
11131113
func TestExecute_DQ_member3_revealsDisqualifiedNonQualMemberKey_phase11(t *testing.T) {
11141114
t.Parallel()
11151115

1116-
groupSize := 5
1116+
groupSize := 6
11171117
honestThreshold := 3
11181118
seed := dkgtest.RandomSeed(t)
11191119

@@ -1174,12 +1174,12 @@ func TestExecute_DQ_member3_revealsDisqualifiedNonQualMemberKey_phase11(t *testi
11741174

11751175
dkgtest.AssertDkgResultPublished(t, result)
11761176
dkgtest.AssertSuccessfulSignersCount(t, result, groupSize-2)
1177-
dkgtest.AssertSuccessfulSigners(t, result, []group.MemberIndex{1, 2, 5}...)
1177+
dkgtest.AssertSuccessfulSigners(t, result, []group.MemberIndex{1, 2, 5, 6}...)
11781178
dkgtest.AssertMemberFailuresCount(t, result, 2)
11791179
dkgtest.AssertSamePublicKey(t, result)
11801180
dkgtest.AssertMisbehavingMembers(t, result, []group.MemberIndex{3, 4}...)
11811181
dkgtest.AssertValidGroupPublicKey(t, result)
1182-
dkgtest.AssertResultSupportingMembers(t, result, []group.MemberIndex{1, 2, 5}...)
1182+
dkgtest.AssertResultSupportingMembers(t, result, []group.MemberIndex{1, 2, 5, 6}...)
11831183
}
11841184

11851185
func TestExecute_InvalidMemberIndex(t *testing.T) {

solidity/contracts/KeepRandomBeaconOperator.sol

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -198,10 +198,7 @@ contract KeepRandomBeaconOperator is ReentrancyGuard {
198198
dkgResultVerification.timeDKG = 5*(1+5) + 2*(1+10) + 20;
199199
dkgResultVerification.resultPublicationBlockStep = resultPublicationBlockStep;
200200
dkgResultVerification.groupSize = groupSize;
201-
// TODO: For now, the required number of signatures is equal to group
202-
// threshold. This should be updated to keep a safety margin for
203-
// participants misbehaving during signing.
204-
dkgResultVerification.signatureThreshold = groupThreshold;
201+
dkgResultVerification.signatureThreshold = groupThreshold + (groupSize - groupThreshold) / 2;
205202
}
206203

207204
/**

solidity/contracts/libraries/operator/DKGResultVerification.sol

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,6 @@ library DKGResultVerification {
4545
* group selection protocol.
4646
* @param groupSelectionEndBlock Block height at which the group selection
4747
* protocol ended.
48-
*
49-
* @return true if submitter is eligible to submit and the result is valid;
50-
* Otherwise, transaction is reverted.
5148
*/
5249
function verify(
5350
Storage storage self,
@@ -58,7 +55,7 @@ library DKGResultVerification {
5855
uint256[] memory signingMemberIndices,
5956
address[] memory members,
6057
uint256 groupSelectionEndBlock
61-
) public view returns (bool) {
58+
) public view {
6259
require(submitterMemberIndex > 0, "Invalid submitter index");
6360
require(
6461
members[submitterMemberIndex - 1] == msg.sender,
@@ -97,7 +94,5 @@ library DKGResultVerification {
9794

9895
require(members[signingMemberIndices[i] - 1] == recoveredAddress, "Invalid signature");
9996
}
100-
101-
return true;
10297
}
10398
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
pragma solidity 0.5.17;
2+
3+
import "../KeepRandomBeaconOperator.sol";
4+
5+
6+
contract KeepRandomBeaconOperatorDKGResultStub is KeepRandomBeaconOperator {
7+
constructor(address _serviceContract, address _stakingContract)
8+
public
9+
KeepRandomBeaconOperator(_serviceContract, _stakingContract)
10+
{
11+
groupSelection.ticketSubmissionTimeout = 100;
12+
}
13+
14+
function setGroupSize(uint256 size) public {
15+
groupSize = size;
16+
groupSelection.groupSize = size;
17+
dkgResultVerification.groupSize = size;
18+
}
19+
20+
function setGroupThreshold(uint256 threshold) public {
21+
groupThreshold = threshold;
22+
dkgResultVerification.signatureThreshold = threshold;
23+
}
24+
25+
function setDKGResultSignatureThreshold(uint256 threshold) public {
26+
dkgResultVerification.signatureThreshold = threshold;
27+
}
28+
29+
function setResultPublicationBlockStep(uint256 step) public {
30+
resultPublicationBlockStep = step;
31+
}
32+
33+
function getGroupSelectionRelayEntry() public view returns (uint256) {
34+
return groupSelection.seed;
35+
}
36+
37+
function getTicketSubmissionStartBlock() public view returns (uint256) {
38+
return groupSelection.ticketSubmissionStartBlock;
39+
}
40+
41+
function isGroupSelectionInProgress() public view returns (bool) {
42+
return groupSelection.inProgress;
43+
}
44+
45+
function setGasPriceCeiling(uint256 _gasPriceCeiling) public {
46+
gasPriceCeiling = _gasPriceCeiling;
47+
}
48+
49+
function timeDKG() public view returns (uint256) {
50+
return dkgResultVerification.timeDKG;
51+
}
52+
}

0 commit comments

Comments
 (0)