Merge pull request #346 from harmony-one/rj_branch

Add message signature checking; Leader sign multi-sig too; Other cosmetic fix.
pull/348/head
Rongjian Lan 6 years ago committed by GitHub
commit bd83cfe56a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 24
      consensus/consensus.go
  2. 48
      consensus/consensus_leader.go
  3. 53
      consensus/consensus_leader_test.go
  4. 48
      consensus/consensus_validator.go
  5. 4
      consensus/consensus_validator_msg.go

@ -5,6 +5,7 @@ import (
"crypto/sha256" "crypto/sha256"
"encoding/binary" "encoding/binary"
"encoding/hex" "encoding/hex"
"errors"
"fmt" "fmt"
"reflect" "reflect"
"strconv" "strconv"
@ -13,7 +14,9 @@ import (
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rlp"
protobuf "github.com/golang/protobuf/proto"
"github.com/harmony-one/bls/ffi/go/bls" "github.com/harmony-one/bls/ffi/go/bls"
consensus_proto "github.com/harmony-one/harmony/api/consensus"
"github.com/harmony-one/harmony/core/state" "github.com/harmony-one/harmony/core/state"
"github.com/harmony-one/harmony/core/types" "github.com/harmony-one/harmony/core/types"
bls_cosi "github.com/harmony-one/harmony/crypto/bls" bls_cosi "github.com/harmony-one/harmony/crypto/bls"
@ -192,6 +195,27 @@ func New(host p2p.Host, ShardID string, peers []p2p.Peer, leader p2p.Peer) *Cons
return &consensus return &consensus
} }
// Verify the signature of the message are valid from the signer's public key.
func verifyMessageSig(signerPubKey *bls.PublicKey, message consensus_proto.Message) error {
signature := message.Signature
message.Signature = nil
messageBytes, err := protobuf.Marshal(&message)
if err != nil {
return err
}
msgSig := bls.Sign{}
err = msgSig.Deserialize(signature)
if err != nil {
return err
}
msgHash := sha256.Sum256(messageBytes)
if !msgSig.VerifyHash(signerPubKey, msgHash[:]) {
return errors.New("failed to verify the signature")
}
return nil
}
// Author returns the author of the block header. // Author returns the author of the block header.
func (consensus *Consensus) Author(header *types.Header) (common.Address, error) { func (consensus *Consensus) Author(header *types.Header) (common.Address, error) {
// TODO: implement this // TODO: implement this

@ -57,7 +57,7 @@ func (consensus *Consensus) WaitForNewBlock(blockChannel chan *types.Block) {
// ProcessMessageLeader dispatches consensus message for the leader. // ProcessMessageLeader dispatches consensus message for the leader.
func (consensus *Consensus) ProcessMessageLeader(payload []byte) { func (consensus *Consensus) ProcessMessageLeader(payload []byte) {
message := consensus_proto.Message{} message := consensus_proto.Message{}
err := message.XXX_Unmarshal(payload) err := protobuf.Unmarshal(payload, &message)
if err != nil { if err != nil {
utils.GetLogInstance().Error("Failed to unmarshal message payload.", "err", err, "consensus", consensus) utils.GetLogInstance().Error("Failed to unmarshal message payload.", "err", err, "consensus", consensus)
@ -93,7 +93,10 @@ func (consensus *Consensus) startConsensus(newBlock *types.Block) {
// Set state to AnnounceDone // Set state to AnnounceDone
consensus.state = AnnounceDone consensus.state = AnnounceDone
// TODO: sign for leader itself
// Leader sign the multi-sig itself
(*consensus.prepareSigs)[consensus.nodeID] = consensus.priKey.SignHash(consensus.blockHash[:])
host.BroadcastMessageFromLeader(consensus.host, consensus.GetValidatorPeers(), msgToSend, consensus.OfflinePeers) host.BroadcastMessageFromLeader(consensus.host, consensus.GetValidatorPeers(), msgToSend, consensus.OfflinePeers)
} }
@ -103,7 +106,6 @@ func (consensus *Consensus) processPrepareMessage(message consensus_proto.Messag
blockHash := message.BlockHash blockHash := message.BlockHash
validatorID := message.SenderId validatorID := message.SenderId
prepareSig := message.Payload prepareSig := message.Payload
signature := message.Signature
// Verify signature // Verify signature
v, ok := consensus.validators.Load(validatorID) v, ok := consensus.validators.Load(validatorID)
@ -117,18 +119,12 @@ func (consensus *Consensus) processPrepareMessage(message consensus_proto.Messag
return return
} }
message.Signature = nil // Verify message signature
messageBytes, err := protobuf.Marshal(&message) err := verifyMessageSig(value.PubKey, message)
if err != nil { if err != nil {
utils.GetLogInstance().Warn("Failed to marshal the prepare message", "error", err) utils.GetLogInstance().Warn("Failed to verify the message signature", "Error", err, "validatorID", validatorID)
return
} }
_ = messageBytes
_ = signature
// TODO: verify message signature
//if schnorr.Verify(crypto.Ed25519Curve, value.PubKey, messageBytes, signature) != nil {
// consensus.Log.Warn("Received message with invalid signature", "validatorKey", consensus.leader.PubKey, "consensus", consensus)
// return
//}
// check consensus Id // check consensus Id
consensus.mutex.Lock() consensus.mutex.Lock()
@ -180,6 +176,10 @@ func (consensus *Consensus) processPrepareMessage(message consensus_proto.Messag
msgToSend, aggSig := consensus.constructPreparedMessage() msgToSend, aggSig := consensus.constructPreparedMessage()
consensus.aggregatedPrepareSig = aggSig consensus.aggregatedPrepareSig = aggSig
// Leader sign the multi-sig itself
// TODO: sign on the prepared multi-sig, rather than the block hash
(*consensus.commitSigs)[consensus.nodeID] = consensus.priKey.SignHash(consensus.blockHash[:])
// Broadcast prepared message // Broadcast prepared message
host.BroadcastMessageFromLeader(consensus.host, consensus.GetValidatorPeers(), msgToSend, consensus.OfflinePeers) host.BroadcastMessageFromLeader(consensus.host, consensus.GetValidatorPeers(), msgToSend, consensus.OfflinePeers)
@ -194,7 +194,6 @@ func (consensus *Consensus) processCommitMessage(message consensus_proto.Message
blockHash := message.BlockHash blockHash := message.BlockHash
validatorID := message.SenderId validatorID := message.SenderId
commitSig := message.Payload commitSig := message.Payload
signature := message.Signature
shouldProcess := true shouldProcess := true
consensus.mutex.Lock() consensus.mutex.Lock()
@ -203,11 +202,11 @@ func (consensus *Consensus) processCommitMessage(message consensus_proto.Message
// check consensus Id // check consensus Id
if consensusID != consensus.consensusID { if consensusID != consensus.consensusID {
shouldProcess = false shouldProcess = false
utils.GetLogInstance().Warn("Received Response with wrong consensus Id", "myConsensusId", consensus.consensusID, "theirConsensusId", consensusID, "consensus", consensus) utils.GetLogInstance().Warn("Received Commit with wrong consensus Id", "myConsensusId", consensus.consensusID, "theirConsensusId", consensusID, "consensus", consensus)
} }
if !bytes.Equal(blockHash, consensus.blockHash[:]) { if !bytes.Equal(blockHash, consensus.blockHash[:]) {
utils.GetLogInstance().Warn("Received Response with wrong blockHash", "myConsensusId", consensus.consensusID, "theirConsensusId", consensusID, "consensus", consensus) utils.GetLogInstance().Warn("Received Commit with wrong blockHash", "myConsensusId", consensus.consensusID, "theirConsensusId", consensusID, "consensus", consensus)
return return
} }
@ -222,18 +221,13 @@ func (consensus *Consensus) processCommitMessage(message consensus_proto.Message
utils.GetLogInstance().Warn("Invalid validator", "validatorID", validatorID, "consensus", consensus) utils.GetLogInstance().Warn("Invalid validator", "validatorID", validatorID, "consensus", consensus)
return return
} }
message.Signature = nil
messageBytes, err := protobuf.Marshal(&message) // Verify message signature
err := verifyMessageSig(value.PubKey, message)
if err != nil { if err != nil {
utils.GetLogInstance().Warn("Failed to marshal the commit message", "error", err) utils.GetLogInstance().Warn("Failed to verify the message signature", "Error", err, "validatorID", validatorID)
return
} }
_ = messageBytes
_ = signature
// TODO: verify message signature
//if schnorr.Verify(crypto.Ed25519Curve, value.PubKey, messageBytes, signature) != nil {
// consensus.Log.Warn("Received message with invalid signature", "validatorKey", consensus.leader.PubKey, "consensus", consensus)
// return
//}
commitSigs := consensus.commitSigs commitSigs := consensus.commitSigs
commitBitmap := consensus.commitBitmap commitBitmap := consensus.commitBitmap
@ -276,7 +270,7 @@ func (consensus *Consensus) processCommitMessage(message consensus_proto.Message
host.BroadcastMessageFromLeader(consensus.host, consensus.GetValidatorPeers(), msgToSend, consensus.OfflinePeers) host.BroadcastMessageFromLeader(consensus.host, consensus.GetValidatorPeers(), msgToSend, consensus.OfflinePeers)
var blockObj types.Block var blockObj types.Block
err = rlp.DecodeBytes(consensus.block, &blockObj) err := rlp.DecodeBytes(consensus.block, &blockObj)
if err != nil { if err != nil {
utils.GetLogInstance().Debug("failed to construct the new block after consensus") utils.GetLogInstance().Debug("failed to construct the new block after consensus")
} }

@ -10,6 +10,8 @@ import (
"github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rlp"
"github.com/golang/mock/gomock" "github.com/golang/mock/gomock"
protobuf "github.com/golang/protobuf/proto"
consensus_proto "github.com/harmony-one/harmony/api/consensus"
"github.com/harmony-one/harmony/core/types" "github.com/harmony-one/harmony/core/types"
"github.com/harmony-one/harmony/internal/utils" "github.com/harmony-one/harmony/internal/utils"
mock_host "github.com/harmony-one/harmony/p2p/host/mock" mock_host "github.com/harmony-one/harmony/p2p/host/mock"
@ -70,6 +72,57 @@ func TestProcessMessageLeaderPrepare(test *testing.T) {
time.Sleep(1 * time.Second) time.Sleep(1 * time.Second)
} }
func TestProcessMessageLeaderPrepareInvalidSignature(test *testing.T) {
ctrl := gomock.NewController(test)
defer ctrl.Finish()
leader := p2p.Peer{IP: ip, Port: "7777"}
_, leader.PubKey = utils.GenKeyBLS(leader.IP, leader.Port)
validators := make([]p2p.Peer, 3)
hosts := make([]p2p.Host, 3)
for i := 0; i < 3; i++ {
port := fmt.Sprintf("%d", 7788+i)
validators[i] = p2p.Peer{IP: ip, Port: port, ValidatorID: i + 1}
_, validators[i].PubKey = utils.GenKeyBLS(validators[i].IP, validators[i].Port)
}
m := mock_host.NewMockHost(ctrl)
// Asserts that the first and only call to Bar() is passed 99.
// Anything else will fail.
m.EXPECT().GetSelfPeer().Return(leader)
m.EXPECT().SendMessage(gomock.Any(), gomock.Any()).Times(0)
consensusLeader := New(m, "0", validators, leader)
consensusLeader.blockHash = blockHash
consensusValidators := make([]*Consensus, 3)
for i := 0; i < 3; i++ {
priKey, _, _ := utils.GenKeyP2P(validators[i].IP, validators[i].Port)
host, err := p2pimpl.NewHost(&validators[i], priKey)
if err != nil {
test.Fatalf("newhost error: %v", err)
}
hosts[i] = host
consensusValidators[i] = New(hosts[i], "0", validators, leader)
consensusValidators[i].blockHash = blockHash
msg := consensusValidators[i].constructPrepareMessage()
message := consensus_proto.Message{}
protobuf.Unmarshal(msg[1:], &message)
// Put invalid signature
message.Signature = consensusValidators[i].signMessage([]byte("random string"))
msg, _ = protobuf.Marshal(&message)
consensusLeader.ProcessMessageLeader(msg[1:])
}
assert.Equal(test, Finished, consensusLeader.state)
time.Sleep(1 * time.Second)
}
func TestProcessMessageLeaderCommit(test *testing.T) { func TestProcessMessageLeaderCommit(test *testing.T) {
ctrl := gomock.NewController(test) ctrl := gomock.NewController(test)
defer ctrl.Finish() defer ctrl.Finish()

@ -39,7 +39,6 @@ func (consensus *Consensus) processAnnounceMessage(message consensus_proto.Messa
blockHash := message.BlockHash blockHash := message.BlockHash
leaderID := message.SenderId leaderID := message.SenderId
block := message.Payload block := message.Payload
signature := message.Signature
copy(consensus.blockHash[:], blockHash[:]) copy(consensus.blockHash[:], blockHash[:])
@ -51,19 +50,12 @@ func (consensus *Consensus) processAnnounceMessage(message consensus_proto.Messa
return return
} }
// Verify signature // Verify message signature
message.Signature = nil err := verifyMessageSig(consensus.leader.PubKey, message)
messageBytes, err := protobuf.Marshal(&message)
if err != nil { if err != nil {
utils.GetLogInstance().Warn("Failed to marshal the announce message", "error", err) utils.GetLogInstance().Warn("Failed to verify the message signature", "Error", err, "leader ID", leaderID)
return
} }
_ = signature
_ = messageBytes
// TODO: verify message signature
//if schnorr.Verify(crypto.Ed25519Curve, consensus.leader.PubKey, messageBytes, signature) != nil {
// consensus.Log.Warn("Received message with invalid signature", "leaderKey", consensus.leader.PubKey, "consensus", consensus)
// return
//}
// check block header is valid // check block header is valid
var blockObj types.Block var blockObj types.Block
@ -117,7 +109,6 @@ func (consensus *Consensus) processPreparedMessage(message consensus_proto.Messa
blockHash := message.BlockHash blockHash := message.BlockHash
leaderID := message.SenderId leaderID := message.SenderId
messagePayload := message.Payload messagePayload := message.Payload
signature := message.Signature
//#### Read payload data //#### Read payload data
offset := 0 offset := 0
@ -139,19 +130,12 @@ func (consensus *Consensus) processPreparedMessage(message consensus_proto.Messa
return return
} }
// Verify signature // Verify message signature
message.Signature = nil err := verifyMessageSig(consensus.leader.PubKey, message)
messageBytes, err := protobuf.Marshal(&message)
if err != nil { if err != nil {
utils.GetLogInstance().Warn("Failed to marshal the announce message", "error", err) utils.GetLogInstance().Warn("Failed to verify the message signature", "Error", err, "leader ID", leaderID)
return
} }
_ = signature
_ = messageBytes
// TODO: verify message signature
//if schnorr.Verify(crypto.Ed25519Curve, consensus.leader.PubKey, messageBytes, signature) != nil {
// consensus.Log.Warn("Received message with invalid signature", "leaderKey", consensus.leader.PubKey, "consensus", consensus)
// return
//}
// Add attack model of IncorrectResponse. // Add attack model of IncorrectResponse.
if attack.GetInstance().IncorrectResponse() { if attack.GetInstance().IncorrectResponse() {
@ -188,7 +172,6 @@ func (consensus *Consensus) processCommittedMessage(message consensus_proto.Mess
blockHash := message.BlockHash blockHash := message.BlockHash
leaderID := message.SenderId leaderID := message.SenderId
messagePayload := message.Payload messagePayload := message.Payload
signature := message.Signature
//#### Read payload data //#### Read payload data
offset := 0 offset := 0
@ -210,19 +193,12 @@ func (consensus *Consensus) processCommittedMessage(message consensus_proto.Mess
return return
} }
// Verify signature // Verify message signature
message.Signature = nil err := verifyMessageSig(consensus.leader.PubKey, message)
messageBytes, err := protobuf.Marshal(&message)
if err != nil { if err != nil {
utils.GetLogInstance().Warn("Failed to marshal the announce message", "error", err) utils.GetLogInstance().Warn("Failed to verify the message signature", "Error", err, "leader ID", leaderID)
return
} }
_ = signature
_ = messageBytes
// TODO: verify message signature
//if schnorr.Verify(crypto.Ed25519Curve, consensus.leader.PubKey, messageBytes, signature) != nil {
// consensus.Log.Warn("Received message with invalid signature", "leaderKey", consensus.leader.PubKey, "consensus", consensus)
// return
//}
// Add attack model of IncorrectResponse. // Add attack model of IncorrectResponse.
if attack.GetInstance().IncorrectResponse() { if attack.GetInstance().IncorrectResponse() {

@ -24,7 +24,7 @@ func (consensus *Consensus) constructPrepareMessage() []byte {
// 48 byte of bls signature // 48 byte of bls signature
sign := consensus.priKey.SignHash(message.BlockHash) sign := consensus.priKey.SignHash(message.BlockHash)
if sign != nil { if sign != nil {
message.Payload = consensus.priKey.SignHash(message.BlockHash).Serialize() message.Payload = sign.Serialize()
} }
marshaledMessage, err := protobuf.Marshal(&message) marshaledMessage, err := protobuf.Marshal(&message)
@ -61,7 +61,7 @@ func (consensus *Consensus) constructCommitMessage() []byte {
// TODO: sign on the prepared message hash, rather than the block hash // TODO: sign on the prepared message hash, rather than the block hash
sign := consensus.priKey.SignHash(message.BlockHash) sign := consensus.priKey.SignHash(message.BlockHash)
if sign != nil { if sign != nil {
message.Payload = consensus.priKey.SignHash(message.BlockHash).Serialize() message.Payload = sign.Serialize()
} }
marshaledMessage, err := protobuf.Marshal(&message) marshaledMessage, err := protobuf.Marshal(&message)

Loading…
Cancel
Save