Add real vrf into drand with validator generating vrf and leader verifying them

pull/449/head
Rongjian Lan 6 years ago
parent 84ced41d6d
commit c55d2ef04a
  1. 13
      crypto/vrf/p256/p256.go
  2. 4
      crypto/vrf/vrf.go
  3. 19
      drand/drand.go
  4. 22
      drand/drand_leader.go
  5. 4
      drand/drand_validator_msg.go
  6. 2
      drand/drand_validator_msg_test.go

@ -37,8 +37,8 @@ import (
"fmt"
"math/big"
"github.com/google/keytransparency/core/crypto/vrf"
"github.com/google/trillian/crypto/keys"
"github.com/harmony-one/harmony/crypto/vrf"
"github.com/golang/protobuf/proto"
)
@ -67,6 +67,17 @@ type PrivateKey struct {
*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
func GenerateKey() (vrf.PrivateKey, vrf.PublicKey) {
key, err := ecdsa.GenerateKey(curve, rand.Reader)

@ -37,4 +37,8 @@ type PrivateKey interface {
type PublicKey interface {
// ProofToHash verifies the NP-proof supplied by Proof and outputs Index.
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"
"sync"
"github.com/harmony-one/harmony/crypto/vrf"
"github.com/harmony-one/harmony/crypto/vrf/p256"
"github.com/harmony-one/harmony/core/types"
protobuf "github.com/golang/protobuf/proto"
@ -26,6 +29,9 @@ type DRand struct {
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.
// global consensus mutex
mutex sync.Mutex
// map of nodeID to validator Peer object
// FIXME: should use PubKey of p2p.Peer as the hashkey
validators sync.Map // key is uint16, value is p2p.Peer
@ -40,6 +46,10 @@ type DRand struct {
// private/public keys of current node
priKey *bls.SecretKey
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
IsLeader bool
@ -109,6 +119,11 @@ func New(host p2p.Host, ShardID string, peers []p2p.Peer, leader p2p.Peer, confi
dRand.priKey = &privateKey
dRand.pubKey = privateKey.GetPublicKey()
// VRF keys
priKey, pubKey := p256.GenerateKey()
dRand.vrfPriKey = &priKey
dRand.vrfPubKey = &pubKey
myShardID, err := strconv.Atoi(ShardID)
if err != nil {
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) {
// TODO: implement vrf
return [32]byte{}, []byte{}
rand, proof = (*dRand.vrfPriKey).Evaluate(blockHash[:])
return
}
// GetValidatorPeers returns list of validator peers.

@ -1,10 +1,13 @@
package drand
import (
"bytes"
protobuf "github.com/golang/protobuf/proto"
drand_proto "github.com/harmony-one/harmony/api/drand"
"github.com/harmony-one/harmony/core"
"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/p2p/host"
)
@ -69,6 +72,9 @@ func (dRand *DRand) processCommitMessage(message drand_proto.Message) {
return
}
dRand.mutex.Lock()
defer dRand.mutex.Unlock()
validatorID := message.SenderId
validatorPeer := dRand.getValidatorPeerByID(validatorID)
vrfs := dRand.vrfs
@ -85,10 +91,17 @@ func (dRand *DRand) processCommitMessage(message drand_proto.Message) {
}
rand := message.Payload[:32]
proof := message.Payload[32:]
_ = rand
_ = proof
// TODO: check the validity of the vrf commit
proof := message.Payload[32 : len(message.Payload)-64]
pubKeyBytes := message.Payload[len(message.Payload)-64:]
_, pubKey := p256.GenerateKey()
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))
@ -98,7 +111,6 @@ func (dRand *DRand) processCommitMessage(message drand_proto.Message) {
if len((*vrfs)) >= ((len(dRand.PublicKeys))/3 + 1) {
// Construct pRand and initiate consensus on it
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{}
// 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.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)
if err != nil {
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{}
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))
}
}

Loading…
Cancel
Save