Skip to content

Commit

Permalink
test: add spec test for keysign protocol
Browse files Browse the repository at this point in the history
  • Loading branch information
aayush-rockx committed Jun 22, 2023
1 parent 2c6200a commit 82b9d5e
Show file tree
Hide file tree
Showing 12 changed files with 358 additions and 53 deletions.
File renamed without changes.
30 changes: 10 additions & 20 deletions dkg/keysign/instance.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,35 +48,25 @@ func NewSignature(
operatorID types.OperatorID,
config dkg.IConfig,
init *dkg.KeySign,
) (dkg.Protocol, error) {

keygenOutput, err := config.GetStorage().GetKeyGenOutput(init.ValidatorPK)
if err != nil {
return nil, fmt.Errorf("failed to retrieve secret keyshare for given validator pk: %s", err.Error())
}

operators := make([]uint32, 0)
for operatorID, _ := range keygenOutput.OperatorPubKeys {
operators = append(operators, uint32(operatorID))
}
) dkg.Protocol {

instanceParams := InstanceParams{
identifier: requestID,
operatorID: operatorID,

validatorPK: init.ValidatorPK,
threshold: keygenOutput.Threshold,
operators: operators,

Key: keygenOutput.Share,
OperatorPublicKeyshares: keygenOutput.OperatorPubKeys,
validatorPK: init.ValidatorPK,
SigningRoot: init.SigningRoot,
threshold: init.Threshold,
operators: init.Operators,
Key: init.SecretShare,
OperatorPublicKeyshares: init.OperatorPublicKeyshares,
}

return &Instance{
config: config,
state: initState(),
instanceParams: instanceParams,
}, nil
}
}

// Start ...
Expand Down Expand Up @@ -135,9 +125,9 @@ func (instance *Instance) ProcessMsg(msg *dkg.SignedMessage) (finished bool, pro
func (instance *Instance) canProceedThisRound() bool {
switch instance.state.GetCurrentRound() {
case common.Preparation:
instance.state.msgContainer.AllMessagesReceivedUpto(instance.state.GetCurrentRound(), instance.instanceParams.operators, instance.instanceParams.threshold)
return instance.state.msgContainer.AllMessagesReceivedUpto(instance.state.GetCurrentRound(), instance.instanceParams.operators, instance.instanceParams.threshold)
case common.Round1:
instance.state.msgContainer.AllMessagesReceivedFor(instance.state.GetCurrentRound(), instance.instanceParams.operators)
return instance.state.msgContainer.AllMessagesReceivedFor(instance.state.GetCurrentRound(), instance.instanceParams.operators)
}
return false
}
Expand Down
3 changes: 3 additions & 0 deletions dkg/keysign/keysign_output.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ func (instance *Instance) processKeysignOutput() (bool, *dkg.ProtocolOutcome, er

output := &dkg.ProtocolOutcome{
KeySignOutput: &dkg.KeySignOutput{
RequestID: instance.instanceParams.identifier,
ValidatorPK: instance.instanceParams.validatorPK,
},
}
Expand Down Expand Up @@ -48,6 +49,8 @@ func (instance *Instance) processKeysignOutput() (bool, *dkg.ProtocolOutcome, er
if prevSignature != nil && !bytes.Equal(protocolMessage.Round1Message.ReconstructedSignature, prevSignature) {
return false, nil, fmt.Errorf("inconsistent signatures between operators")
}

prevSignature = protocolMessage.Round1Message.ReconstructedSignature
}

output.KeySignOutput.Signature = prevSignature
Expand Down
29 changes: 29 additions & 0 deletions dkg/keysign/testing_utils.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package keysign

import (
"github.com/bloxapp/ssv-spec/dkg/common"
"github.com/bloxapp/ssv-spec/types"
"github.com/bloxapp/ssv-spec/types/testingutils"
)

func Testing_PreparationMessageBytes(id types.OperatorID, ks *testingutils.TestKeySet, root []byte) []byte {
msg := &ProtocolMsg{
Round: common.Preparation,
PreparationMessage: &PreparationMessage{
PartialSignature: ks.Shares[id].SignByte(root).Serialize(),
},
}
byts, _ := msg.Encode()
return byts
}

func Testing_Round1MessageBytes(id types.OperatorID, ks *testingutils.TestKeySet, root []byte) []byte {
msg := ProtocolMsg{
Round: common.Round1,
Round1Message: &Round1Message{
ReconstructedSignature: ks.ValidatorSK.SignByte(root).Serialize(),
},
}
byts, _ := msg.Encode()
return byts
}
8 changes: 8 additions & 0 deletions dkg/messages.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/herumi/bls-eth-go-binary/bls"
"github.com/pkg/errors"
)

Expand Down Expand Up @@ -279,6 +280,8 @@ type SignedOutput struct {
BlameData *BlameData
// Data signed
Data *Output
// KeySign Output signed
KeySignData *KeySignOutput
// Signer Operator ID which signed
Signer types.OperatorID
// Signature over Data.GetRoot()
Expand Down Expand Up @@ -364,6 +367,11 @@ func (msg *PartialDepositData) Decode(data []byte) error {
type KeySign struct {
ValidatorPK types.ValidatorPK
SigningRoot []byte

Operators []uint32
Threshold uint64
SecretShare *bls.SecretKey
OperatorPublicKeyshares map[types.OperatorID]*bls.PublicKey
}

func (msg *KeySign) Validate() error {
Expand Down
15 changes: 15 additions & 0 deletions dkg/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package dkg

import (
"encoding/hex"
"fmt"

"github.com/bloxapp/ssv-spec/types"
"github.com/pkg/errors"
Expand Down Expand Up @@ -91,6 +92,20 @@ func (n *Node) newResharingRunner(id RequestID, reshareMsg *Reshare) (Runner, er
}

func (n *Node) newSignatureRunner(id RequestID, keySign *KeySign) (Runner, error) {
keygenOutput, err := n.config.GetStorage().GetKeyGenOutput(keySign.ValidatorPK)
if err != nil {
return nil, fmt.Errorf("failed to retrieve secret keyshare for given validator pk: %s", err.Error())
}

operators := make([]uint32, 0)
for operatorID := range keygenOutput.OperatorPubKeys {
operators = append(operators, uint32(operatorID))
}

keySign.Operators = operators
keySign.Threshold = keygenOutput.Threshold
keySign.SecretShare = keygenOutput.Share
keySign.OperatorPublicKeyshares = keygenOutput.OperatorPubKeys

r := &runner{
Operator: n.operator,
Expand Down
23 changes: 23 additions & 0 deletions dkg/protocol.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package dkg

import (
"github.com/bloxapp/ssv-spec/types"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/crypto"
"github.com/herumi/bls-eth-go-binary/bls"
"github.com/pkg/errors"
)
Expand Down Expand Up @@ -32,10 +34,31 @@ type KeyGenOutput struct {

// KeySignOutput is the output of signature protocol
type KeySignOutput struct {
RequestID RequestID
Signature []byte
ValidatorPK types.ValidatorPK
}

func (o *KeySignOutput) GetRoot() ([]byte, error) {
bytesSolidity, _ := abi.NewType("bytes", "", nil)
arguments := abi.Arguments{
{
Type: bytesSolidity,
},
{
Type: bytesSolidity,
},
}
bytes, err := arguments.Pack(
[]byte(o.ValidatorPK),
[]byte(o.Signature),
)
if err != nil {
return nil, err
}
return crypto.Keccak256(bytes), nil
}

// BlameOutput is the output of blame round
type BlameOutput struct {
Valid bool
Expand Down
60 changes: 54 additions & 6 deletions dkg/runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,15 @@ func (r *runner) ProcessMsg(msg *SignedMessage) (bool, error) {

if finished {
r.KeygenOutcome = o
}

if finished && o.KeySignOutput != nil {
if err := r.prepareAndBroadcastOutput(); err != nil {
return false, err
}
}

if finished && o.KeySignOutput == nil {
isBlame, err := r.KeygenOutcome.IsFailedWithBlame()
if err != nil {
return true, errors.Wrap(err, "invalid KeygenOutcome")
Expand All @@ -80,7 +89,6 @@ func (r *runner) ProcessMsg(msg *SignedMessage) (bool, error) {
return false, err
}
}

}
return false, nil
case DepositDataMsgType:
Expand Down Expand Up @@ -118,11 +126,14 @@ func (r *runner) ProcessMsg(msg *SignedMessage) (bool, error) {
r.OutputMsgs[msg.Signer] = output
// GLNOTE: Actually we need every operator to sign instead only the quorum!
finished := false
if !r.isResharing() {
if r.isKeySign() {
finished = len(r.OutputMsgs) == len(r.KeySign.Operators)
} else if !r.isResharing() {
finished = len(r.OutputMsgs) == len(r.InitMsg.OperatorIDs)
} else {
finished = len(r.OutputMsgs) == len(r.ReshareMsg.OperatorIDs)
}

if finished {
err := r.config.Network.StreamDKGOutput(r.OutputMsgs)
return true, errors.Wrap(err, "failed to stream dkg output")
Expand Down Expand Up @@ -164,7 +175,33 @@ func (r *runner) prepareAndBroadcastDepositData() error {
return nil
}

func (r *runner) prepareAndBroadcastKeySignOutput() error {
o := r.KeygenOutcome.KeySignOutput
sig, err := r.config.Signer.SignDKGOutput(o, r.Operator.ETHAddress)
if err != nil {
return errors.Wrap(err, "could not sign output")
}
signedOuput := &SignedOutput{
KeySignData: o,
Signer: r.Operator.OperatorID,
Signature: sig,
}
if err != nil {
return errors.Wrap(err, "could not generate dkg SignedOutput")
}

r.OutputMsgs[r.Operator.OperatorID] = signedOuput
if err := r.signAndBroadcastMsg(signedOuput, OutputMsgType); err != nil {
return errors.Wrap(err, "could not broadcast Signed Keysign Output")
}
return nil
}

func (r *runner) prepareAndBroadcastOutput() error {
if r.KeygenOutcome.KeySignOutput != nil {
return r.prepareAndBroadcastKeySignOutput()
}

var (
depositSig types.Signature
err error
Expand Down Expand Up @@ -252,17 +289,21 @@ func (r *runner) validateSignedOutput(msg *SignedOutput) error {
// TODO: Separate fields match and signature validation
output := r.ownOutput()
if output != nil {
if output.BlameData == nil {
if output.Data != nil {
if output.Data.RequestID != msg.Data.RequestID {
return errors.New("got mismatching RequestID")
}
if !bytes.Equal(output.Data.ValidatorPubKey, msg.Data.ValidatorPubKey) {
return errors.New("got mismatching ValidatorPubKey")
}
} else {
} else if output.BlameData != nil {
if output.BlameData.RequestID != msg.BlameData.RequestID {
return errors.New("got mismatching RequestID")
}
} else {
if output.KeySignData.RequestID != msg.KeySignData.RequestID {
return errors.New("got mismatching RequestID")
}
}
}

Expand All @@ -279,11 +320,14 @@ func (r *runner) validateSignedOutput(msg *SignedOutput) error {
data types.Root
)

if msg.BlameData == nil {
if msg.Data != nil {
data = msg.Data
} else {
} else if msg.BlameData != nil {
data = msg.BlameData
} else {
data = msg.KeySignData
}

root, err = types.ComputeSigningRoot(data, types.ComputeSignatureDomain(r.config.SignatureDomainType, types.DKGSignatureType))
if err != nil {
return errors.Wrap(err, "fail to get root")
Expand Down Expand Up @@ -352,3 +396,7 @@ func (r *runner) ownOutput() *SignedOutput {
func (r *runner) isResharing() bool {
return r.ReshareMsg != nil
}

func (r *runner) isKeySign() bool {
return r.KeySign != nil
}
27 changes: 13 additions & 14 deletions dkg/spectest/all_tests.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,7 @@ package spectest
import (
"testing"

"github.com/bloxapp/ssv-spec/dkg/spectest/tests/frost/blame"
"github.com/bloxapp/ssv-spec/dkg/spectest/tests/frost/keygen"
"github.com/bloxapp/ssv-spec/dkg/spectest/tests/frost/resharing"
"github.com/bloxapp/ssv-spec/dkg/spectest/tests/frost/timeout"
"github.com/bloxapp/ssv-spec/dkg/spectest/tests/frost/keysign"
)

type SpecTest interface {
Expand All @@ -18,15 +15,17 @@ var AllTests = []SpecTest{
// tests.HappyFlow(),
// tests.ResharingHappyFlow(),

keygen.HappyFlow(),
resharing.HappyFlow(),
blame.BlameTypeInvalidCommitment_HappyFlow(),
blame.BlameTypeInvalidScalar_HappyFlow(),
blame.BlameTypeInconsistentMessage_HappyFlow(),
blame.BlameTypeInvalidShare_HappyFlow(),
blame.BlameTypeInvalidShare_FailedDecrypt_HappyFlow(),
// keygen.HappyFlow(),
// resharing.HappyFlow(),
// blame.BlameTypeInvalidCommitment_HappyFlow(),
// blame.BlameTypeInvalidScalar_HappyFlow(),
// blame.BlameTypeInconsistentMessage_HappyFlow(),
// blame.BlameTypeInvalidShare_HappyFlow(),
// blame.BlameTypeInvalidShare_FailedDecrypt_HappyFlow(),

timeout.Timeout_Preparation(),
timeout.Timeout_Round1(),
timeout.Timeout_Round2(),
// timeout.Timeout_Preparation(),
// timeout.Timeout_Round1(),
// timeout.Timeout_Round2(),

keysign.HappyFlow(),
}
Loading

0 comments on commit 82b9d5e

Please sign in to comment.