From ce819aec0aa1779d09542317ef8f55afd0839ff3 Mon Sep 17 00:00:00 2001 From: pavelkrolevets Date: Fri, 8 Nov 2024 18:34:08 +0300 Subject: [PATCH 1/3] add broadcast for response and justification phases --- pkgs/board/board.go | 34 ++++- pkgs/initiator/initiator.go | 53 ++++++- pkgs/initiator/initiator_test.go | 230 +++++++++++++++++++++++++++++++ pkgs/wire/types_json.go | 16 +++ 4 files changed, 325 insertions(+), 8 deletions(-) diff --git a/pkgs/board/board.go b/pkgs/board/board.go index 41c244ff..17d4bdd1 100644 --- a/pkgs/board/board.go +++ b/pkgs/board/board.go @@ -36,7 +36,7 @@ func NewBoard( // PushDeals implements a kyber DKG Board interface to broadcast deal bundle func (b *Board) PushDeals(bundle *dkg.DealBundle) { - b.logger.Debug("Pushing deal bundle: ", zap.Int("num of deals", len(bundle.Deals))) + b.logger.Info("Pushing deal bundle: ", zap.Int("num of deals", len(bundle.Deals))) byts, err := wire2.EncodeDealBundle(bundle) if err != nil { @@ -61,7 +61,21 @@ func (b *Board) IncomingDeal() <-chan dkg.DealBundle { // PushResponses implements a kyber DKG Board interface to broadcast responses func (b *Board) PushResponses(bundle *dkg.ResponseBundle) { - // dont push responses to nodes, allowing them to finish with error + b.logger.Info("Pushing response bundle: ", zap.Int("num of responses", len(bundle.Responses))) + byts, err := wire2.EncodeResponseBundle(bundle) + if err != nil { + b.logger.Error("error encoding response bundle", zap.Error(err)) + return + } + msg := &wire2.KyberMessage{ + Type: wire2.KyberResponseBundleMessageType, + Data: byts, + } + + if err := b.broadcastF(msg); err != nil { + b.logger.Error("error broadcasting response bundle", zap.Error(err)) + return + } } // IncomingResponse implements a kyber DKG Board interface function @@ -71,7 +85,21 @@ func (b *Board) IncomingResponse() <-chan dkg.ResponseBundle { // PushJustifications implements a kyber DKG interface to broadcast justifications func (b *Board) PushJustifications(bundle *dkg.JustificationBundle) { - // dont push justifications to nodes, allowing them to finish with error + b.logger.Info("Pushing justifications bundle: ", zap.Int("num of justifications", len(bundle.Justifications))) + byts, err := wire2.EncodeJustificationBundle(bundle) + if err != nil { + b.logger.Error("error encoding justifications bundle", zap.Error(err)) + return + } + msg := &wire2.KyberMessage{ + Type: wire2.KyberJustificationBundleMessageType, + Data: byts, + } + + if err := b.broadcastF(msg); err != nil { + b.logger.Error("error broadcasting justifications bundle", zap.Error(err)) + return + } } // IncomingJustification implements a kyber DKG Board interface function diff --git a/pkgs/initiator/initiator.go b/pkgs/initiator/initiator.go index 7d072d05..958ef801 100644 --- a/pkgs/initiator/initiator.go +++ b/pkgs/initiator/initiator.go @@ -14,10 +14,11 @@ import ( "github.com/attestantio/go-eth2-client/spec/phase0" eth2_key_manager_core "github.com/bloxapp/eth2-key-manager/core" + kyber_bls12381 "github.com/drand/kyber-bls12381" + kyber_dkg "github.com/drand/kyber/share/dkg" "github.com/ethereum/go-ethereum/common" "github.com/herumi/bls-eth-go-binary/bls" "github.com/imroc/req/v3" - "go.uber.org/zap" spec "github.com/ssvlabs/dkg-spec" spec_crypto "github.com/ssvlabs/dkg-spec/crypto" @@ -25,6 +26,7 @@ import ( "github.com/ssvlabs/ssv-dkg/pkgs/crypto" "github.com/ssvlabs/ssv-dkg/pkgs/utils" "github.com/ssvlabs/ssv-dkg/pkgs/wire" + "go.uber.org/zap" ) type VerifyMessageSignatureFunc func(pub *rsa.PublicKey, msg, sig []byte) error @@ -442,7 +444,7 @@ func (c *Initiator) CreateCeremonyResults( nonce uint64, amount phase0.Gwei, ) (*wire.DepositDataCLI, *wire.KeySharesCLI, []*wire.SignedProof, error) { - dkgResults, err := parseDKGResultsFromBytes(resultsBytes) + dkgResults, err := c.parseDKGResultsFromBytes(resultsBytes) if err != nil { return nil, nil, nil, err } @@ -580,7 +582,7 @@ func (c *Initiator) processDKGResultResponse(dkgResults []*spec.Result, return depositDataJson, keyshares, nil } -func parseDKGResultsFromBytes(responseResult [][]byte) (dkgResults []*spec.Result, finalErr error) { +func (c *Initiator) parseDKGResultsFromBytes(responseResult [][]byte) (dkgResults []*spec.Result, finalErr error) { for i := 0; i < len(responseResult); i++ { msg := responseResult[i] tsp := &wire.SignedTransport{} @@ -588,12 +590,53 @@ func parseDKGResultsFromBytes(responseResult [][]byte) (dkgResults []*spec.Resul finalErr = errors.Join(finalErr, err) continue } + ops, err := c.Operators.ToSpecOperators() + if err != nil { + finalErr = errors.Join(finalErr, err) + continue + } + from, err := spec.OperatorIDByPubKey(ops, tsp.Signer) + if err != nil { + finalErr = errors.Join(finalErr, fmt.Errorf("cant find operator ID message from operator ID %d: %w", from, err)) + continue + } if tsp.Message.Type == wire.ErrorMessageType { finalErr = errors.Join(finalErr, fmt.Errorf("%s", string(tsp.Message.Data))) continue } if tsp.Message.Type != wire.OutputMessageType { - finalErr = errors.Join(finalErr, fmt.Errorf("wrong DKG result message type: exp %s, got %s ", wire.OutputMessageType.String(), tsp.Message.Type.String())) + // check if response/justification bundle received + if tsp.Message.Type == wire.KyberMessageType { + kyberMsg := &wire.KyberMessage{} + if err := kyberMsg.UnmarshalSSZ(tsp.Message.Data); err != nil { + finalErr = errors.Join(finalErr, err) + continue + } + switch kyberMsg.Type { + case wire.KyberResponseBundleMessageType: + response, err := wire.DecodeResponseBundle(kyberMsg.Data) + if err != nil { + finalErr = errors.Join(finalErr, err) + continue + } else { + finalErr = errors.Join(finalErr, fmt.Errorf("received response message: from %d, %v", from, response)) + continue + } + case wire.KyberJustificationBundleMessageType: + justification, err := wire.DecodeJustificationBundle(kyberMsg.Data, kyber_bls12381.NewBLS12381Suite().G1().(kyber_dkg.Suite)) + if err != nil { + finalErr = errors.Join(finalErr, err) + continue + } else { + finalErr = errors.Join(finalErr, fmt.Errorf("received justification message: from %d, %v", from, justification)) + continue + } + default: + finalErr = errors.Join(finalErr, fmt.Errorf("received message: from %d, but wrong type %s ", from, kyberMsg.Type)) + continue + } + } + finalErr = errors.Join(finalErr, fmt.Errorf("wrong DKG result message type from oprator ID %d: exp %s, got %s ", from, wire.OutputMessageType.String(), tsp.Message.Type.String())) continue } result := &spec.Result{} @@ -931,7 +974,7 @@ func (c *Initiator) createBulkResults(resultsBytes [][][]byte, signedMsg, msgIDM bulkKeyShares := []*wire.KeySharesCLI{} bulkProofs := [][]*wire.SignedProof{} for _, ceremonyResult := range resultsBytes { - dkgResults, err := parseDKGResultsFromBytes(ceremonyResult) + dkgResults, err := c.parseDKGResultsFromBytes(ceremonyResult) if err != nil { return nil, nil, nil, err } diff --git a/pkgs/initiator/initiator_test.go b/pkgs/initiator/initiator_test.go index 8d766863..a8238631 100644 --- a/pkgs/initiator/initiator_test.go +++ b/pkgs/initiator/initiator_test.go @@ -11,17 +11,22 @@ import ( "github.com/attestantio/go-eth2-client/spec/phase0" "github.com/bloxapp/eth2-key-manager/core" "github.com/bloxapp/ssv/logging" + kyber_bls12381 "github.com/drand/kyber-bls12381" + "github.com/drand/kyber/share/dkg" + kyber_dkg "github.com/drand/kyber/share/dkg" "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/common" "github.com/herumi/bls-eth-go-binary/bls" "github.com/stretchr/testify/require" "go.uber.org/zap" + e2m_core "github.com/bloxapp/eth2-key-manager/core" spec "github.com/ssvlabs/dkg-spec" spec_crypto "github.com/ssvlabs/dkg-spec/crypto" "github.com/ssvlabs/dkg-spec/testing/stubs" "github.com/ssvlabs/ssv-dkg/pkgs/crypto" "github.com/ssvlabs/ssv-dkg/pkgs/initiator" + "github.com/ssvlabs/ssv-dkg/pkgs/utils" "github.com/ssvlabs/ssv-dkg/pkgs/utils/test_utils" "github.com/ssvlabs/ssv-dkg/pkgs/validator" "github.com/ssvlabs/ssv-dkg/pkgs/wire" @@ -418,3 +423,228 @@ func must[T any](v T, err error) T { } return v } + +func TestDKGFailWithOperatorsMisbehave(t *testing.T) { + err := logging.SetGlobalLogger("debug", "capital", "console", nil) + require.NoError(t, err) + logger := zap.L().Named("operator-tests") + ops := wire.OperatorsCLI{} + version := "test.version" + stubClient := &stubs.Client{ + CallContractF: func(call ethereum.CallMsg) ([]byte, error) { + return nil, nil + }, + } + srv1 := test_utils.CreateTestOperatorFromFile(t, 1, "../../examples/operator1", version, operatorCert, operatorKey, stubClient) + srv2 := test_utils.CreateTestOperatorFromFile(t, 2, "../../examples/operator2", version, operatorCert, operatorKey, stubClient) + srv3 := test_utils.CreateTestOperatorFromFile(t, 3, "../../examples/operator3", version, operatorCert, operatorKey, stubClient) + srv4 := test_utils.CreateTestOperatorFromFile(t, 4, "../../examples/operator4", version, operatorCert, operatorKey, stubClient) + srvs := map[uint64]*test_utils.TestOperator{1: srv1, 2: srv2, 3: srv3, 4: srv4} + + ops = append( + ops, + wire.OperatorCLI{Addr: srv1.HttpSrv.URL, ID: 1, PubKey: &srv1.PrivKey.PublicKey}, + wire.OperatorCLI{Addr: srv2.HttpSrv.URL, ID: 2, PubKey: &srv2.PrivKey.PublicKey}, + wire.OperatorCLI{Addr: srv3.HttpSrv.URL, ID: 3, PubKey: &srv3.PrivKey.PublicKey}, + wire.OperatorCLI{Addr: srv4.HttpSrv.URL, ID: 4, PubKey: &srv4.PrivKey.PublicKey}, + ) + withdraw := common.HexToAddress("0x0000000000000000000000000000000000000009") + owner := common.HexToAddress("0x0000000000000000000000000000000000000007") + ids := []uint64{1, 2, 3, 4} + t.Run("operator cheat with deal bundle", func(t *testing.T) { + intr, err := initiator.New(ops, logger, "test.version", rootCert, false) + require.NoError(t, err) + id := spec.NewID() + + ops, err := initiator.ValidatedOperatorData(ids, intr.Operators) + require.NoError(t, err) + threshold := utils.GetThreshold(ids) + init := &spec.Init{ + Operators: ops, + T: uint64(threshold), + WithdrawalCredentials: withdraw.Bytes(), + Fork: e2m_core.NetworkFromString("mainnet").GenesisForkVersion(), + Owner: owner, + Nonce: 0, + Amount: uint64(spec_crypto.MIN_ACTIVATION_BALANCE), + } + + exchangeMsgs, _, err := intr.SendInitMsg(id, init, ops) + require.NoError(t, err) + kyberMsgs, _, err := intr.SendExchangeMsgs(id, exchangeMsgs, ops) + require.NoError(t, err) + + tsp := &wire.SignedTransport{} + err = tsp.UnmarshalSSZ(kyberMsgs[1]) + require.NoError(t, err) + + kyberMsg := &wire.KyberMessage{} + err = kyberMsg.UnmarshalSSZ(tsp.Message.Data) + require.NoError(t, err) + + // decode deal bundle + d, err := wire.DecodeDealBundle(kyberMsg.Data, kyber_bls12381.NewBLS12381Suite().G1().(kyber_dkg.Suite)) + require.NoError(t, err) + + // try to cheat + cheatDealShare, err := hex.DecodeString("a262a2a96d170658f68cf2450106949e92b9c415c3add2dbb8ce1a09886cf24f12f4f2ff1043b372090b06ce9a328a6f64b4279125902a244a22aa4ae30e16249186b1ae3a2c2c6a29634215a84e86fae66862013d8db1cdc930a8b1502750d8") + require.NoError(t, err) + d.Deals[0].EncryptedShare = cheatDealShare + bundle := &dkg.DealBundle{ + DealerIndex: d.DealerIndex, + Deals: d.Deals, + Public: d.Public, + SessionID: d.SessionID, + Signature: d.Signature, + } + + byts, err := wire.EncodeDealBundle(bundle) + require.NoError(t, err) + + // send corrupted kyber message to get justification error from protocol + msg := &wire.KyberMessage{ + Type: wire.KyberDealBundleMessageType, + Data: byts, + } + byts, err = msg.MarshalSSZ() + require.NoError(t, err) + + trsp := &wire.Transport{ + Type: wire.KyberMessageType, + Identifier: id, + Data: byts, + Version: intr.Version, + } + bts, err := trsp.MarshalSSZ() + require.NoError(t, err) + + // Sign message with RSA private key + sign, err := srv1.Srv.State.Sign(bts) + require.NoError(t, err) + + pub, err := spec_crypto.EncodeRSAPublicKey(&srv1.Srv.State.PrivateKey.PublicKey) + require.NoError(t, err) + + signed := &wire.SignedTransport{ + Message: trsp, + Signer: pub, + Signature: sign, + } + final, err := signed.MarshalSSZ() + kyberMsgs[srv1.ID] = final + require.NoError(t, err) + + dkgResult, errs, err := intr.SendKyberMsgs(id, kyberMsgs, ops) + require.NoError(t, err) + + for _, err := range errs { + require.NoError(t, err) + } + var finalResults [][]byte + for _, res := range dkgResult { + finalResults = append(finalResults, res) + } + + _, _, _, err = intr.CreateCeremonyResults(finalResults, id, init.Operators, init.WithdrawalCredentials, nil, init.Fork, init.Owner, init.Nonce, phase0.Gwei(init.Amount)) + require.ErrorContains(t, err, "received response message") + }) + + t.Run("operator send empty bundle", func(t *testing.T) { + intr, err := initiator.New(ops, logger, "test.version", rootCert, false) + require.NoError(t, err) + id := spec.NewID() + + ops, err := initiator.ValidatedOperatorData(ids, intr.Operators) + require.NoError(t, err) + threshold := utils.GetThreshold(ids) + init := &spec.Init{ + Operators: ops, + T: uint64(threshold), + WithdrawalCredentials: withdraw.Bytes(), + Fork: e2m_core.NetworkFromString("mainnet").GenesisForkVersion(), + Owner: owner, + Nonce: 0, + Amount: uint64(spec_crypto.MIN_ACTIVATION_BALANCE), + } + + exchangeMsgs, _, err := intr.SendInitMsg(id, init, ops) + require.NoError(t, err) + kyberMsgs, _, err := intr.SendExchangeMsgs(id, exchangeMsgs, ops) + require.NoError(t, err) + + for i, msg := range kyberMsgs { + tsp := &wire.SignedTransport{} + err = tsp.UnmarshalSSZ(msg) + require.NoError(t, err) + + kyberMsg := &wire.KyberMessage{} + err = kyberMsg.UnmarshalSSZ(tsp.Message.Data) + require.NoError(t, err) + // decode deal bundle + d, err := wire.DecodeDealBundle(kyberMsg.Data, kyber_bls12381.NewBLS12381Suite().G1().(kyber_dkg.Suite)) + require.NoError(t, err) + bundle := &dkg.DealBundle{ + DealerIndex: d.DealerIndex, + Deals: []kyber_dkg.Deal{}, + Public: d.Public, + SessionID: d.SessionID, + Signature: d.Signature, + } + + byts, err := wire.EncodeDealBundle(bundle) + require.NoError(t, err) + + // send corrupted kyber message to get justification error from protocol + msg := &wire.KyberMessage{ + Type: wire.KyberDealBundleMessageType, + Data: byts, + } + byts, err = msg.MarshalSSZ() + require.NoError(t, err) + + trsp := &wire.Transport{ + Type: wire.KyberMessageType, + Identifier: id, + Data: byts, + Version: intr.Version, + } + bts, err := trsp.MarshalSSZ() + require.NoError(t, err) + + // Sign message with RSA private key + sign, err := srvs[i].Srv.State.Sign(bts) + require.NoError(t, err) + + pub, err := spec_crypto.EncodeRSAPublicKey(&srvs[i].Srv.State.PrivateKey.PublicKey) + require.NoError(t, err) + + signed := &wire.SignedTransport{ + Message: trsp, + Signer: pub, + Signature: sign, + } + final, err := signed.MarshalSSZ() + require.NoError(t, err) + kyberMsgs[i] = final + } + + dkgResult, errs, err := intr.SendKyberMsgs(id, kyberMsgs, ops) + require.NoError(t, err) + + for _, err := range errs { + require.NoError(t, err) + } + var finalResults [][]byte + for _, res := range dkgResult { + finalResults = append(finalResults, res) + } + + _, _, _, err = intr.CreateCeremonyResults(finalResults, id, init.Operators, init.WithdrawalCredentials, nil, init.Fork, init.Owner, init.Nonce, phase0.Gwei(init.Amount)) + require.ErrorContains(t, err, "received response message") + }) + + srv1.HttpSrv.Close() + srv2.HttpSrv.Close() + srv3.HttpSrv.Close() + srv4.HttpSrv.Close() +} diff --git a/pkgs/wire/types_json.go b/pkgs/wire/types_json.go index 22506a51..ff07c970 100644 --- a/pkgs/wire/types_json.go +++ b/pkgs/wire/types_json.go @@ -16,6 +16,7 @@ import ( "strings" spec "github.com/ssvlabs/dkg-spec" + spec_crypto "github.com/ssvlabs/dkg-spec/crypto" ) // Proof for a DKG ceremony @@ -191,6 +192,21 @@ func (o OperatorsCLI) Clone() OperatorsCLI { return clone } +func (o OperatorsCLI) ToSpecOperators() ([]*spec.Operator, error) { + specOps := make([]*spec.Operator, 0) + for _, op := range o { + pub, err := spec_crypto.EncodeRSAPublicKey(op.PubKey) + if err != nil { + return nil, err + } + specOps = append(specOps, &spec.Operator{ + ID: op.ID, + PubKey: pub, + }) + } + return specOps, nil +} + type operatorCLIJSON struct { Addr string `json:"ip"` ID uint64 `json:"id"` From e9847b0ffe8a445c1547548f92bbf1f98287b3ce Mon Sep 17 00:00:00 2001 From: pavelkrolevets Date: Mon, 11 Nov 2024 16:59:30 +0300 Subject: [PATCH 2/3] update message + refactor --- pkgs/board/board.go | 3 + pkgs/initiator/initiator.go | 83 ++++++++++++--------------- pkgs/initiator/initiator_test.go | 97 +------------------------------- 3 files changed, 39 insertions(+), 144 deletions(-) diff --git a/pkgs/board/board.go b/pkgs/board/board.go index 17d4bdd1..76598447 100644 --- a/pkgs/board/board.go +++ b/pkgs/board/board.go @@ -60,6 +60,9 @@ func (b *Board) IncomingDeal() <-chan dkg.DealBundle { } // PushResponses implements a kyber DKG Board interface to broadcast responses + +// A response bundle is returned if there is any invalid or +// missing deals. func (b *Board) PushResponses(bundle *dkg.ResponseBundle) { b.logger.Info("Pushing response bundle: ", zap.Int("num of responses", len(bundle.Responses))) byts, err := wire2.EncodeResponseBundle(bundle) diff --git a/pkgs/initiator/initiator.go b/pkgs/initiator/initiator.go index 958ef801..9b5d1e96 100644 --- a/pkgs/initiator/initiator.go +++ b/pkgs/initiator/initiator.go @@ -590,55 +590,10 @@ func (c *Initiator) parseDKGResultsFromBytes(responseResult [][]byte) (dkgResult finalErr = errors.Join(finalErr, err) continue } - ops, err := c.Operators.ToSpecOperators() - if err != nil { + if err := verifyMessageType(tsp, wire.OutputMessageType); err != nil { finalErr = errors.Join(finalErr, err) continue } - from, err := spec.OperatorIDByPubKey(ops, tsp.Signer) - if err != nil { - finalErr = errors.Join(finalErr, fmt.Errorf("cant find operator ID message from operator ID %d: %w", from, err)) - continue - } - if tsp.Message.Type == wire.ErrorMessageType { - finalErr = errors.Join(finalErr, fmt.Errorf("%s", string(tsp.Message.Data))) - continue - } - if tsp.Message.Type != wire.OutputMessageType { - // check if response/justification bundle received - if tsp.Message.Type == wire.KyberMessageType { - kyberMsg := &wire.KyberMessage{} - if err := kyberMsg.UnmarshalSSZ(tsp.Message.Data); err != nil { - finalErr = errors.Join(finalErr, err) - continue - } - switch kyberMsg.Type { - case wire.KyberResponseBundleMessageType: - response, err := wire.DecodeResponseBundle(kyberMsg.Data) - if err != nil { - finalErr = errors.Join(finalErr, err) - continue - } else { - finalErr = errors.Join(finalErr, fmt.Errorf("received response message: from %d, %v", from, response)) - continue - } - case wire.KyberJustificationBundleMessageType: - justification, err := wire.DecodeJustificationBundle(kyberMsg.Data, kyber_bls12381.NewBLS12381Suite().G1().(kyber_dkg.Suite)) - if err != nil { - finalErr = errors.Join(finalErr, err) - continue - } else { - finalErr = errors.Join(finalErr, fmt.Errorf("received justification message: from %d, %v", from, justification)) - continue - } - default: - finalErr = errors.Join(finalErr, fmt.Errorf("received message: from %d, but wrong type %s ", from, kyberMsg.Type)) - continue - } - } - finalErr = errors.Join(finalErr, fmt.Errorf("wrong DKG result message type from oprator ID %d: exp %s, got %s ", from, wire.OutputMessageType.String(), tsp.Message.Type.String())) - continue - } result := &spec.Result{} if err := result.UnmarshalSSZ(tsp.Message.Data); err != nil { finalErr = errors.Join(finalErr, err) @@ -829,8 +784,8 @@ func (c *Initiator) processPongMessage(res wire.PongResult) error { return fmt.Errorf("operator returned error: %s", errString) } // Validate that incoming message is an pong message - if signedPongMsg.Message.Type != wire.PongMessageType { - return fmt.Errorf("wrong incoming message type from operator") + if err := verifyMessageType(signedPongMsg, wire.PongMessageType); err != nil { + return err } pong := &wire.Pong{} if err := pong.UnmarshalSSZ(signedPongMsg.Message.Data); err != nil { @@ -1013,3 +968,35 @@ func (c *Initiator) createBulkResults(resultsBytes [][][]byte, signedMsg, msgIDM } return bulkDepositData, bulkKeyShares, bulkProofs, nil } + +func verifyMessageType(tsp *wire.SignedTransport, expectedType wire.TransportType) error { + if tsp.Message.Type != expectedType { + if tsp.Message.Type == wire.ErrorMessageType { + return fmt.Errorf("dkg protocol failed with %s", string(tsp.Message.Data)) + } + if tsp.Message.Type == wire.KyberMessageType { + kyberMsg := &wire.KyberMessage{} + if err := kyberMsg.UnmarshalSSZ(tsp.Message.Data); err != nil { + return err + } + switch kyberMsg.Type { + // if we are not in fastsync, we expect only complaints + case wire.KyberResponseBundleMessageType: + bundle, err := wire.DecodeResponseBundle(kyberMsg.Data) + if err != nil { + return err + } + return fmt.Errorf("dkg protocol failed with response complaints: %v", bundle) + case wire.KyberJustificationBundleMessageType: + bundle, err := wire.DecodeJustificationBundle(kyberMsg.Data, kyber_bls12381.NewBLS12381Suite().G1().(kyber_dkg.Suite)) + if err != nil { + return err + } + return fmt.Errorf("dkg protocol failed with justification message, which is unexpected: %v", bundle) + default: + return fmt.Errorf("received message with wrong type %s ", kyberMsg.Type) + } + } + } + return nil +} diff --git a/pkgs/initiator/initiator_test.go b/pkgs/initiator/initiator_test.go index a8238631..db0bbd63 100644 --- a/pkgs/initiator/initiator_test.go +++ b/pkgs/initiator/initiator_test.go @@ -439,7 +439,6 @@ func TestDKGFailWithOperatorsMisbehave(t *testing.T) { srv2 := test_utils.CreateTestOperatorFromFile(t, 2, "../../examples/operator2", version, operatorCert, operatorKey, stubClient) srv3 := test_utils.CreateTestOperatorFromFile(t, 3, "../../examples/operator3", version, operatorCert, operatorKey, stubClient) srv4 := test_utils.CreateTestOperatorFromFile(t, 4, "../../examples/operator4", version, operatorCert, operatorKey, stubClient) - srvs := map[uint64]*test_utils.TestOperator{1: srv1, 2: srv2, 3: srv3, 4: srv4} ops = append( ops, @@ -546,101 +545,7 @@ func TestDKGFailWithOperatorsMisbehave(t *testing.T) { } _, _, _, err = intr.CreateCeremonyResults(finalResults, id, init.Operators, init.WithdrawalCredentials, nil, init.Fork, init.Owner, init.Nonce, phase0.Gwei(init.Amount)) - require.ErrorContains(t, err, "received response message") - }) - - t.Run("operator send empty bundle", func(t *testing.T) { - intr, err := initiator.New(ops, logger, "test.version", rootCert, false) - require.NoError(t, err) - id := spec.NewID() - - ops, err := initiator.ValidatedOperatorData(ids, intr.Operators) - require.NoError(t, err) - threshold := utils.GetThreshold(ids) - init := &spec.Init{ - Operators: ops, - T: uint64(threshold), - WithdrawalCredentials: withdraw.Bytes(), - Fork: e2m_core.NetworkFromString("mainnet").GenesisForkVersion(), - Owner: owner, - Nonce: 0, - Amount: uint64(spec_crypto.MIN_ACTIVATION_BALANCE), - } - - exchangeMsgs, _, err := intr.SendInitMsg(id, init, ops) - require.NoError(t, err) - kyberMsgs, _, err := intr.SendExchangeMsgs(id, exchangeMsgs, ops) - require.NoError(t, err) - - for i, msg := range kyberMsgs { - tsp := &wire.SignedTransport{} - err = tsp.UnmarshalSSZ(msg) - require.NoError(t, err) - - kyberMsg := &wire.KyberMessage{} - err = kyberMsg.UnmarshalSSZ(tsp.Message.Data) - require.NoError(t, err) - // decode deal bundle - d, err := wire.DecodeDealBundle(kyberMsg.Data, kyber_bls12381.NewBLS12381Suite().G1().(kyber_dkg.Suite)) - require.NoError(t, err) - bundle := &dkg.DealBundle{ - DealerIndex: d.DealerIndex, - Deals: []kyber_dkg.Deal{}, - Public: d.Public, - SessionID: d.SessionID, - Signature: d.Signature, - } - - byts, err := wire.EncodeDealBundle(bundle) - require.NoError(t, err) - - // send corrupted kyber message to get justification error from protocol - msg := &wire.KyberMessage{ - Type: wire.KyberDealBundleMessageType, - Data: byts, - } - byts, err = msg.MarshalSSZ() - require.NoError(t, err) - - trsp := &wire.Transport{ - Type: wire.KyberMessageType, - Identifier: id, - Data: byts, - Version: intr.Version, - } - bts, err := trsp.MarshalSSZ() - require.NoError(t, err) - - // Sign message with RSA private key - sign, err := srvs[i].Srv.State.Sign(bts) - require.NoError(t, err) - - pub, err := spec_crypto.EncodeRSAPublicKey(&srvs[i].Srv.State.PrivateKey.PublicKey) - require.NoError(t, err) - - signed := &wire.SignedTransport{ - Message: trsp, - Signer: pub, - Signature: sign, - } - final, err := signed.MarshalSSZ() - require.NoError(t, err) - kyberMsgs[i] = final - } - - dkgResult, errs, err := intr.SendKyberMsgs(id, kyberMsgs, ops) - require.NoError(t, err) - - for _, err := range errs { - require.NoError(t, err) - } - var finalResults [][]byte - for _, res := range dkgResult { - finalResults = append(finalResults, res) - } - - _, _, _, err = intr.CreateCeremonyResults(finalResults, id, init.Operators, init.WithdrawalCredentials, nil, init.Fork, init.Owner, init.Nonce, phase0.Gwei(init.Amount)) - require.ErrorContains(t, err, "received response message") + require.ErrorContains(t, err, "protocol failed with response complaints") }) srv1.HttpSrv.Close() From 42d6f91bab63c334ef5417e31db4d5d8153e71d8 Mon Sep 17 00:00:00 2001 From: pavelkrolevets Date: Mon, 11 Nov 2024 18:24:17 +0300 Subject: [PATCH 3/3] lint --- pkgs/wire/types_json.go | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/pkgs/wire/types_json.go b/pkgs/wire/types_json.go index ff07c970..22506a51 100644 --- a/pkgs/wire/types_json.go +++ b/pkgs/wire/types_json.go @@ -16,7 +16,6 @@ import ( "strings" spec "github.com/ssvlabs/dkg-spec" - spec_crypto "github.com/ssvlabs/dkg-spec/crypto" ) // Proof for a DKG ceremony @@ -192,21 +191,6 @@ func (o OperatorsCLI) Clone() OperatorsCLI { return clone } -func (o OperatorsCLI) ToSpecOperators() ([]*spec.Operator, error) { - specOps := make([]*spec.Operator, 0) - for _, op := range o { - pub, err := spec_crypto.EncodeRSAPublicKey(op.PubKey) - if err != nil { - return nil, err - } - specOps = append(specOps, &spec.Operator{ - ID: op.ID, - PubKey: pub, - }) - } - return specOps, nil -} - type operatorCLIJSON struct { Addr string `json:"ip"` ID uint64 `json:"id"`