Merge pull request #449 from harmony-one/rj_branch

Add real vrf into drand with validator generating vrf and leader verifying them; Also reduce manager_test.go's delay
pull/461/head v1.0-1902
Rongjian Lan 6 years ago committed by GitHub
commit f6ce924bdf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      api/service/manager_test.go
  2. 13
      crypto/vrf/p256/p256.go
  3. 4
      crypto/vrf/vrf.go
  4. 19
      drand/drand.go
  5. 22
      drand/drand_leader.go
  6. 4
      drand/drand_validator_msg.go
  7. 2
      drand/drand_validator_msg_test.go

@ -24,7 +24,7 @@ func TestTakeAction(t *testing.T) {
for i := 0; i < 2; i++ { for i := 0; i < 2; i++ {
select { select {
case <-time.After(WaitForStatusUpdate): case <-time.After(100 * time.Millisecond):
m.SendAction(&Action{Action: Start, ServiceType: SupportSyncing}) m.SendAction(&Action{Action: Start, ServiceType: SupportSyncing})
} }
} }

@ -37,8 +37,8 @@ import (
"fmt" "fmt"
"math/big" "math/big"
"github.com/google/keytransparency/core/crypto/vrf"
"github.com/google/trillian/crypto/keys" "github.com/google/trillian/crypto/keys"
"github.com/harmony-one/harmony/crypto/vrf"
"github.com/golang/protobuf/proto" "github.com/golang/protobuf/proto"
) )
@ -67,6 +67,17 @@ type PrivateKey struct {
*ecdsa.PrivateKey *ecdsa.PrivateKey
} }
// Serialize serialize the public key into bytes
func (pk *PublicKey) Serialize() []byte {
return append(pk.PublicKey.X.Bytes(), pk.PublicKey.Y.Bytes()...)
}
// Deserialize de-serialize bytes into public key
func (pk *PublicKey) Deserialize(data []byte) {
pk.X.SetBytes(data[:len(data)/2])
pk.Y.SetBytes(data[len(data)/2:])
}
// GenerateKey generates a fresh keypair for this VRF // GenerateKey generates a fresh keypair for this VRF
func GenerateKey() (vrf.PrivateKey, vrf.PublicKey) { func GenerateKey() (vrf.PrivateKey, vrf.PublicKey) {
key, err := ecdsa.GenerateKey(curve, rand.Reader) key, err := ecdsa.GenerateKey(curve, rand.Reader)

@ -37,4 +37,8 @@ type PrivateKey interface {
type PublicKey interface { type PublicKey interface {
// ProofToHash verifies the NP-proof supplied by Proof and outputs Index. // ProofToHash verifies the NP-proof supplied by Proof and outputs Index.
ProofToHash(m, proof []byte) (index [32]byte, err error) ProofToHash(m, proof []byte) (index [32]byte, err error)
// Serialize serialize the public key into bytes
Serialize() []byte
// Deserialize de-serialize bytes into public key
Deserialize([]byte)
} }

@ -7,6 +7,9 @@ import (
"strconv" "strconv"
"sync" "sync"
"github.com/harmony-one/harmony/crypto/vrf"
"github.com/harmony-one/harmony/crypto/vrf/p256"
"github.com/harmony-one/harmony/core/types" "github.com/harmony-one/harmony/core/types"
protobuf "github.com/golang/protobuf/proto" protobuf "github.com/golang/protobuf/proto"
@ -26,6 +29,9 @@ type DRand struct {
ConfirmedBlockChannel chan *types.Block // Channel to receive confirmed blocks ConfirmedBlockChannel chan *types.Block // Channel to receive confirmed blocks
PRndChannel chan []byte // Channel to send pRnd (preimage of randomness resulting from combined vrf randomnesses) to consensus. The first 32 bytes are randomness, the rest is for bitmap. PRndChannel chan []byte // Channel to send pRnd (preimage of randomness resulting from combined vrf randomnesses) to consensus. The first 32 bytes are randomness, the rest is for bitmap.
// global consensus mutex
mutex sync.Mutex
// map of nodeID to validator Peer object // map of nodeID to validator Peer object
// FIXME: should use PubKey of p2p.Peer as the hashkey // FIXME: should use PubKey of p2p.Peer as the hashkey
validators sync.Map // key is uint16, value is p2p.Peer validators sync.Map // key is uint16, value is p2p.Peer
@ -40,6 +46,10 @@ type DRand struct {
// private/public keys of current node // private/public keys of current node
priKey *bls.SecretKey priKey *bls.SecretKey
pubKey *bls.PublicKey pubKey *bls.PublicKey
// VRF private and public key
// TODO: directly use signature signing key (BLS) for vrf
vrfPriKey *vrf.PrivateKey
vrfPubKey *vrf.PublicKey
// Whether I am leader. False means I am validator // Whether I am leader. False means I am validator
IsLeader bool IsLeader bool
@ -109,6 +119,11 @@ func New(host p2p.Host, ShardID string, peers []p2p.Peer, leader p2p.Peer, confi
dRand.priKey = &privateKey dRand.priKey = &privateKey
dRand.pubKey = privateKey.GetPublicKey() dRand.pubKey = privateKey.GetPublicKey()
// VRF keys
priKey, pubKey := p256.GenerateKey()
dRand.vrfPriKey = &priKey
dRand.vrfPubKey = &pubKey
myShardID, err := strconv.Atoi(ShardID) myShardID, err := strconv.Atoi(ShardID)
if err != nil { if err != nil {
panic("Unparseable shard Id" + ShardID) panic("Unparseable shard Id" + ShardID)
@ -167,8 +182,8 @@ func (dRand *DRand) signAndMarshalDRandMessage(message *drand_proto.Message) ([]
} }
func (dRand *DRand) vrf(blockHash [32]byte) (rand [32]byte, proof []byte) { func (dRand *DRand) vrf(blockHash [32]byte) (rand [32]byte, proof []byte) {
// TODO: implement vrf rand, proof = (*dRand.vrfPriKey).Evaluate(blockHash[:])
return [32]byte{}, []byte{} return
} }
// GetValidatorPeers returns list of validator peers. // GetValidatorPeers returns list of validator peers.

@ -1,10 +1,13 @@
package drand package drand
import ( import (
"bytes"
protobuf "github.com/golang/protobuf/proto" protobuf "github.com/golang/protobuf/proto"
drand_proto "github.com/harmony-one/harmony/api/drand" drand_proto "github.com/harmony-one/harmony/api/drand"
"github.com/harmony-one/harmony/core" "github.com/harmony-one/harmony/core"
"github.com/harmony-one/harmony/core/types" "github.com/harmony-one/harmony/core/types"
"github.com/harmony-one/harmony/crypto/vrf/p256"
"github.com/harmony-one/harmony/internal/utils" "github.com/harmony-one/harmony/internal/utils"
"github.com/harmony-one/harmony/p2p/host" "github.com/harmony-one/harmony/p2p/host"
) )
@ -69,6 +72,9 @@ func (dRand *DRand) processCommitMessage(message drand_proto.Message) {
return return
} }
dRand.mutex.Lock()
defer dRand.mutex.Unlock()
validatorID := message.SenderId validatorID := message.SenderId
validatorPeer := dRand.getValidatorPeerByID(validatorID) validatorPeer := dRand.getValidatorPeerByID(validatorID)
vrfs := dRand.vrfs vrfs := dRand.vrfs
@ -85,10 +91,17 @@ func (dRand *DRand) processCommitMessage(message drand_proto.Message) {
} }
rand := message.Payload[:32] rand := message.Payload[:32]
proof := message.Payload[32:] proof := message.Payload[32 : len(message.Payload)-64]
_ = rand pubKeyBytes := message.Payload[len(message.Payload)-64:]
_ = proof _, pubKey := p256.GenerateKey()
// TODO: check the validity of the vrf commit pubKey.Deserialize(pubKeyBytes)
expectedRand, err := pubKey.ProofToHash(dRand.blockHash[:], proof)
if err != nil || !bytes.Equal(expectedRand[:], rand) {
utils.GetLogInstance().Error("Failed to verify the VRF", "error", err, "validatorID", validatorID, "expectedRand", expectedRand, "receivedRand", rand)
return
}
utils.GetLogInstance().Debug("Received new commit", "numReceivedSoFar", len((*vrfs)), "validatorID", validatorID, "PublicKeys", len(dRand.PublicKeys)) utils.GetLogInstance().Debug("Received new commit", "numReceivedSoFar", len((*vrfs)), "validatorID", validatorID, "PublicKeys", len(dRand.PublicKeys))
@ -98,7 +111,6 @@ func (dRand *DRand) processCommitMessage(message drand_proto.Message) {
if len((*vrfs)) >= ((len(dRand.PublicKeys))/3 + 1) { if len((*vrfs)) >= ((len(dRand.PublicKeys))/3 + 1) {
// Construct pRand and initiate consensus on it // Construct pRand and initiate consensus on it
utils.GetLogInstance().Debug("Received enough randomness commit", "numReceivedSoFar", len((*vrfs)), "validatorID", validatorID, "PublicKeys", len(dRand.PublicKeys)) utils.GetLogInstance().Debug("Received enough randomness commit", "numReceivedSoFar", len((*vrfs)), "validatorID", validatorID, "PublicKeys", len(dRand.PublicKeys))
// TODO: communicate the pRand to consensus
pRnd := [32]byte{} pRnd := [32]byte{}
// Bitwise XOR on all the submitted vrfs // Bitwise XOR on all the submitted vrfs

@ -14,7 +14,9 @@ func (dRand *DRand) constructCommitMessage(vrf [32]byte, proof []byte) []byte {
message.BlockHash = dRand.blockHash[:] message.BlockHash = dRand.blockHash[:]
message.Payload = append(vrf[:], proof...) message.Payload = append(vrf[:], proof...)
// Adding the public key into payload so leader can verify the vrf
// TODO: change the curve to follow the same curve with consensus, so the public key doesn't need to be attached.
message.Payload = append(message.Payload, (*dRand.vrfPubKey).Serialize()...)
marshaledMessage, err := dRand.signAndMarshalDRandMessage(&message) marshaledMessage, err := dRand.signAndMarshalDRandMessage(&message)
if err != nil { if err != nil {
utils.GetLogInstance().Error("Failed to sign and marshal the commit message", "error", err) utils.GetLogInstance().Error("Failed to sign and marshal the commit message", "error", err)

@ -20,7 +20,7 @@ func TestConstructCommitMessage(test *testing.T) {
dRand.blockHash = [32]byte{} dRand.blockHash = [32]byte{}
msg := dRand.constructCommitMessage([32]byte{}, []byte{}) msg := dRand.constructCommitMessage([32]byte{}, []byte{})
if len(msg) != 127 { if len(msg) != 191 {
test.Errorf("Commit message is not constructed in the correct size: %d", len(msg)) test.Errorf("Commit message is not constructed in the correct size: %d", len(msg))
} }
} }

Loading…
Cancel
Save