diff --git a/packages/binary/drng/dispatcher.go b/packages/binary/drng/dispatcher.go index 15a7826f8530bef43c07ccfb45fddea774e850bb..4e79a85a2a1d229be302c6c8352b676a095792dd 100644 --- a/packages/binary/drng/dispatcher.go +++ b/packages/binary/drng/dispatcher.go @@ -13,9 +13,10 @@ import ( "github.com/iotaledger/hive.go/marshalutil" ) -func (drng *Instance) Dispatch(issuer ed25519.PublicKey, timestamp time.Time, payload *payload.Payload) error { - switch payload.SubType() { - case header.CollectiveBeaconType(): +// Dispatch parses a DRNG message and process it based on its subtype +func (drng *DRNG) Dispatch(issuer ed25519.PublicKey, timestamp time.Time, payload *payload.Payload) error { + switch payload.Header.PayloadType { + case header.TypeCollectiveBeacon: // parse as CollectiveBeaconType marshalUtil := marshalutil.New(payload.Bytes()) parsedPayload, err := cb.Parse(marshalUtil) @@ -26,11 +27,11 @@ func (drng *Instance) Dispatch(issuer ed25519.PublicKey, timestamp time.Time, pa cbEvent := &events.CollectiveBeaconEvent{ IssuerPublicKey: issuer, Timestamp: timestamp, - InstanceID: parsedPayload.Instance(), - Round: parsedPayload.Round(), - PrevSignature: parsedPayload.PrevSignature(), - Signature: parsedPayload.Signature(), - Dpk: parsedPayload.DistributedPK(), + InstanceID: parsedPayload.Header.InstanceID, + Round: parsedPayload.Round, + PrevSignature: parsedPayload.PrevSignature, + Signature: parsedPayload.Signature, + Dpk: parsedPayload.Dpk, } drng.Events.CollectiveBeacon.Trigger(cbEvent) @@ -45,7 +46,6 @@ func (drng *Instance) Dispatch(issuer ed25519.PublicKey, timestamp time.Time, pa return nil default: - //do other stuff return errors.New("subtype not implemented") } } diff --git a/packages/binary/drng/dispatcher_test.go b/packages/binary/drng/dispatcher_test.go index b9635cac9e9bafac615d529ef95437d12aa3771f..80ad29b61ec1dda6061839f49f7a1b077f57f78f 100644 --- a/packages/binary/drng/dispatcher_test.go +++ b/packages/binary/drng/dispatcher_test.go @@ -31,7 +31,7 @@ func init() { dpkTest, _ = hex.DecodeString("a02fcd15edd52c8e134027491a43b597505b466d1679e88f70f927e57c45a93ae0765ff02fc2d015e3a02fd8748e2103") timestampTest = time.Now() - rand, _ := collectiveBeacon.GetRandomness(signatureTest) + rand, _ := collectiveBeacon.ExtractRandomness(signatureTest) randomnessTest = &state.Randomness{ Round: 1, Randomness: rand, @@ -50,8 +50,8 @@ func init() { } func dummyPayload() *cbPayload.Payload { - header := header.New(header.CollectiveBeaconType(), 1) - return cbPayload.New(header.Instance(), + header := header.New(header.TypeCollectiveBeacon, 1) + return cbPayload.New(header.InstanceID, 1, prevSignatureTest, signatureTest, diff --git a/packages/binary/drng/drng.go b/packages/binary/drng/drng.go index a4bf5c7cf8d86ce396dbe89fcd32dba3a5b4a3c0..15f6eadad97bcb5c31c54556b846f9bb0997c12c 100644 --- a/packages/binary/drng/drng.go +++ b/packages/binary/drng/drng.go @@ -2,17 +2,23 @@ package drng import ( "github.com/iotaledger/goshimmer/packages/binary/drng/state" + cbEvents "github.com/iotaledger/goshimmer/packages/binary/drng/subtypes/collectiveBeacon/events" + "github.com/iotaledger/hive.go/events" ) -type Instance struct { - State *state.State - Events *Event +// DRNG holds the state and events of a drng instance. +type DRNG struct { + State *state.State // The state of the DRNG. + Events *Event // The events fired on the DRNG. } // New creates a new DRNG instance. -func New(setters ...state.Option) *Instance { - return &Instance{ - State: state.New(setters...), - Events: NewEvent(), +func New(setters ...state.Option) *DRNG { + return &DRNG{ + State: state.New(setters...), + Events: &Event{ + CollectiveBeacon: events.NewEvent(cbEvents.CollectiveBeaconReceived), + Randomness: events.NewEvent(randomnessReceived), + }, } } diff --git a/packages/binary/drng/events.go b/packages/binary/drng/events.go index 50124047ccfe45c2c3b7b0667fcfb96a858a32a9..a3420fcaca949bb995910044b0a3d74b42092151 100644 --- a/packages/binary/drng/events.go +++ b/packages/binary/drng/events.go @@ -2,20 +2,15 @@ package drng import ( "github.com/iotaledger/goshimmer/packages/binary/drng/state" - cbEvents "github.com/iotaledger/goshimmer/packages/binary/drng/subtypes/collectiveBeacon/events" "github.com/iotaledger/hive.go/events" ) +// Event holds the different events triggered by a DRNG instance. type Event struct { - CollectiveBeacon cbEvents.CollectiveBeacon - Randomness *events.Event -} - -func NewEvent() *Event { - return &Event{ - CollectiveBeacon: cbEvents.NewCollectiveBeaconEvent(), - Randomness: events.NewEvent(randomnessReceived), - } + // Collective Beacon is triggered each time we receive a new CollectiveBeacon message. + CollectiveBeacon *events.Event + // Randomness is triggered each time we receive a new and valid CollectiveBeacon message. + Randomness *events.Event } func randomnessReceived(handler interface{}, params ...interface{}) { diff --git a/packages/binary/drng/payload/header/header.go b/packages/binary/drng/payload/header/header.go index 7f49d986f30fb9d3ca79abc0c5cc800036c8612c..426c1ee769056337099731b0d5b1bee33e91faaf 100644 --- a/packages/binary/drng/payload/header/header.go +++ b/packages/binary/drng/payload/header/header.go @@ -4,49 +4,38 @@ import ( "github.com/iotaledger/hive.go/marshalutil" ) +// Type defines the data model of a DRNG payload type type Type = byte -type payloadType struct { - CollectiveBeacon Type -} - -var drngTypes = &payloadType{ - CollectiveBeacon: Type(1), -} +const ( + // TypeCollectiveBeacon defines a CollectiveBeacon payload type + TypeCollectiveBeacon Type = 1 +) +// Length defines the length of a DRNG header const Length = 5 -func CollectiveBeaconType() Type { - return drngTypes.CollectiveBeacon -} - +// Header defines defines a DRNG payload header type Header struct { - payloadType Type // message type - instanceID uint32 // identifier of the dRAND instance + PayloadType Type // message type + InstanceID uint32 // identifier of the DRNG instance } +// New creates a new DRNG payload header for the given type and instance id. func New(payloadType Type, instanceID uint32) Header { return Header{ - payloadType: payloadType, - instanceID: instanceID, + PayloadType: payloadType, + InstanceID: instanceID, } } -func (h Header) PayloadType() Type { - return h.payloadType -} - -func (h Header) Instance() uint32 { - return h.instanceID -} - // Parse is a wrapper for simplified unmarshaling in a byte stream using the marshalUtil package. func Parse(marshalUtil *marshalutil.MarshalUtil) (Header, error) { - if header, err := marshalUtil.Parse(func(data []byte) (interface{}, error, int) { return FromBytes(data) }); err != nil { + header, err := marshalUtil.Parse(func(data []byte) (interface{}, error, int) { return FromBytes(data) }) + if err != nil { return Header{}, err - } else { - return header.(Header), nil } + return header.(Header), nil } // FromBytes unmarshals a header from a sequence of bytes. @@ -67,12 +56,12 @@ func FromBytes(bytes []byte, optionalTargetObject ...*Header) (result Header, er marshalUtil := marshalutil.New(bytes) // read payload type from bytes - if targetObject.payloadType, err = marshalUtil.ReadByte(); err != nil { + if targetObject.PayloadType, err = marshalUtil.ReadByte(); err != nil { return } // read instance ID from bytes - if targetObject.instanceID, err = marshalUtil.ReadUint32(); err != nil { + if targetObject.InstanceID, err = marshalUtil.ReadUint32(); err != nil { return } @@ -85,13 +74,14 @@ func FromBytes(bytes []byte, optionalTargetObject ...*Header) (result Header, er return } +// Bytes returns the header in serialized bytes form. func (header *Header) Bytes() (bytes []byte) { // initialize helper marshalUtil := marshalutil.New() // marshal the payload specific information - marshalUtil.WriteByte(header.PayloadType()) - marshalUtil.WriteUint32(header.Instance()) + marshalUtil.WriteByte(header.PayloadType) + marshalUtil.WriteUint32(header.InstanceID) bytes = marshalUtil.Bytes() diff --git a/packages/binary/drng/payload/header/header_test.go b/packages/binary/drng/payload/header/header_test.go index 12b67104affd4b738af441e32292e92af3d07cf0..03edf75346b7a3c83ede3012f093dd881e002df6 100644 --- a/packages/binary/drng/payload/header/header_test.go +++ b/packages/binary/drng/payload/header/header_test.go @@ -8,7 +8,7 @@ import ( ) func TestParse(t *testing.T) { - header := New(CollectiveBeaconType(), 0) + header := New(TypeCollectiveBeacon, 0) bytes := header.Bytes() marshalUtil := marshalutil.New(bytes) diff --git a/packages/binary/drng/payload/payload.go b/packages/binary/drng/payload/payload.go index b61f0f23682456618b35dd8fc8319c2269814a3a..fc21d403520b03de1d4171f02e549fa503fd591e 100644 --- a/packages/binary/drng/payload/payload.go +++ b/packages/binary/drng/payload/payload.go @@ -9,33 +9,23 @@ import ( "github.com/iotaledger/hive.go/stringify" ) +// Payload defines a DRNG payload. type Payload struct { - header header.Header - data []byte + header.Header + Data []byte bytes []byte bytesMutex sync.RWMutex } +// New creates a new DRNG payload. func New(header header.Header, data []byte) *Payload { return &Payload{ - header: header, - data: data, + Header: header, + Data: data, } } -func (p *Payload) SubType() header.Type { - return p.header.PayloadType() -} - -func (payload *Payload) Instance() uint32 { - return payload.header.Instance() -} - -func (payload *Payload) Data() []byte { - return payload.data -} - // Parse is a wrapper for simplified unmarshaling in a byte stream using the marshalUtil package. func Parse(marshalUtil *marshalutil.MarshalUtil) (*Payload, error) { if payload, err := marshalUtil.Parse(func(data []byte) (interface{}, error, int) { return FromBytes(data) }); err != nil { @@ -72,12 +62,12 @@ func FromBytes(bytes []byte, optionalTargetObject ...*Payload) (result *Payload, } // parse header - if result.header, err = header.Parse(marshalUtil); err != nil { + if result.Header, err = header.Parse(marshalUtil); err != nil { return } // parse data - if result.data, err = marshalUtil.ReadBytes(int(len - header.Length)); err != nil { + if result.Data, err = marshalUtil.ReadBytes(int(len - header.Length)); err != nil { return } @@ -96,7 +86,7 @@ func (payload *Payload) Bytes() (bytes []byte) { // return if bytes have been determined already if bytes = payload.bytes; bytes != nil { - defer payload.bytesMutex.RUnlock() + payload.bytesMutex.RUnlock() return } @@ -114,9 +104,9 @@ func (payload *Payload) Bytes() (bytes []byte) { // marshal the payload specific information marshalUtil.WriteUint32(Type) - marshalUtil.WriteUint32(uint32(len(payload.data) + header.Length)) - marshalUtil.WriteBytes(payload.header.Bytes()) - marshalUtil.WriteBytes(payload.data[:]) + marshalUtil.WriteUint32(uint32(len(payload.Data) + header.Length)) + marshalUtil.WriteBytes(payload.Header.Bytes()) + marshalUtil.WriteBytes(payload.Data[:]) bytes = marshalUtil.Bytes() @@ -125,9 +115,9 @@ func (payload *Payload) Bytes() (bytes []byte) { func (payload *Payload) String() string { return stringify.Struct("Payload", - stringify.StructField("type", uint64(payload.SubType())), - stringify.StructField("instance", uint64(payload.Instance())), - stringify.StructField("data", payload.Data()), + stringify.StructField("type", uint64(payload.Header.PayloadType)), + stringify.StructField("instance", uint64(payload.Header.InstanceID)), + stringify.StructField("data", payload.Data), ) } @@ -158,7 +148,4 @@ func init() { }) } -// define contract (ensure that the struct fulfills the corresponding interface) -var _ payload.Payload = &Payload{} - // // endregion /////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/packages/binary/drng/payload/payload_test.go b/packages/binary/drng/payload/payload_test.go index 0d939d96221929bba4e6dde49b692ae7eedb2bc7..7a6ac612028ab923c61307fc725e4c6097dffe16 100644 --- a/packages/binary/drng/payload/payload_test.go +++ b/packages/binary/drng/payload/payload_test.go @@ -9,7 +9,7 @@ import ( ) func dummyPayload() *Payload { - header := header.New(header.CollectiveBeaconType(), 0) + header := header.New(header.TypeCollectiveBeacon, 0) data := []byte("test") return New(header, data) } @@ -22,9 +22,9 @@ func TestParse(t *testing.T) { parsedPayload, err := Parse(marshalUtil) require.NoError(t, err) - require.Equal(t, payload.SubType(), parsedPayload.SubType()) - require.Equal(t, payload.Instance(), parsedPayload.Instance()) - require.Equal(t, payload.Data(), parsedPayload.Data()) + require.Equal(t, payload.Header.PayloadType, parsedPayload.Header.PayloadType) + require.Equal(t, payload.Header.InstanceID, parsedPayload.Header.InstanceID) + require.Equal(t, payload.Data, parsedPayload.Data) } func TestString(t *testing.T) { diff --git a/packages/binary/drng/state/options.go b/packages/binary/drng/state/options.go index 357c2eb67ca2ecd8b35d08a296b3fdbd50be1b72..8ced6516f37939c64c382a3dd3d433f2c34fb54d 100644 --- a/packages/binary/drng/state/options.go +++ b/packages/binary/drng/state/options.go @@ -1,10 +1,14 @@ package state +// Options define state options of a DRNG. type Options struct { - Committee *Committee + // The initial committee of the DRNG. + Committee *Committee + // The initial randomness of the DRNG. Randomness *Randomness } +// Option is a function which sets the given option. type Option func(*Options) // SetCommittee sets the initial committee diff --git a/packages/binary/drng/state/state.go b/packages/binary/drng/state/state.go index 595fd91d1fd8390f619fb04c9d22002d08c57d95..95e45d37be3c34f2d252ab177ae62f0ee8fbecf3 100644 --- a/packages/binary/drng/state/state.go +++ b/packages/binary/drng/state/state.go @@ -8,23 +8,34 @@ import ( "github.com/iotaledger/hive.go/crypto/ed25519" ) +// Randomness defines the current randomness state of a DRNG instance. type Randomness struct { - Round uint64 + // Round holds the current DRNG round. + Round uint64 + // Randomness holds the current randomness as a slice of bytes. Randomness []byte - Timestamp time.Time + // Timestamp holds the timestamp when the current randomness was received. + Timestamp time.Time } -// Float64 returns a float64 [0.0,1.0) rapresentation of the randomness byte slice +// Float64 returns a float64 [0.0,1.0) representation of the randomness byte slice. func (r Randomness) Float64() float64 { return float64(binary.BigEndian.Uint64(r.Randomness[:8])>>11) / (1 << 53) } +// Committee defines the current committee state of a DRNG instance. type Committee struct { - InstanceID uint32 - Threshold uint8 - Identities []ed25519.PublicKey + // InstanceID holds the identifier of the dRAND instance. + InstanceID uint32 + // Threshold holds the threshold of the secret sharing protocol. + Threshold uint8 + // Identities holds the nodes' identities of the committee members. + Identities []ed25519.PublicKey + // DistributedPK holds the drand distributed public key. DistributedPK []byte } + +// The state of the DRNG. type State struct { randomness *Randomness committee *Committee @@ -32,6 +43,7 @@ type State struct { mutex sync.RWMutex } +// New creates a new State with the given optional options func New(setters ...Option) *State { args := &Options{} @@ -44,12 +56,14 @@ func New(setters ...Option) *State { } } -func (s *State) SetRandomness(r *Randomness) { +// UpdateRandomness updates the randomness of the DRNG state +func (s *State) UpdateRandomness(r *Randomness) { s.mutex.Lock() defer s.mutex.Unlock() s.randomness = r } +// Randomness returns the randomness of the DRNG state func (s *State) Randomness() Randomness { s.mutex.RLock() defer s.mutex.RUnlock() @@ -59,12 +73,14 @@ func (s *State) Randomness() Randomness { return *s.randomness } -func (s *State) SetCommittee(c *Committee) { +// Update committee updates the committee of the DRNG state +func (s *State) UpdateCommittee(c *Committee) { s.mutex.Lock() defer s.mutex.Unlock() s.committee = c } +// Committee returns the committee of the DRNG state func (s *State) Committee() Committee { s.mutex.RLock() defer s.mutex.RUnlock() diff --git a/packages/binary/drng/state/state_test.go b/packages/binary/drng/state/state_test.go index 64a7a8cd14de97c078b1471caebe3617776d8389..2dbd5490eef3c26928ce9e189b5f61bfa822bb0b 100644 --- a/packages/binary/drng/state/state_test.go +++ b/packages/binary/drng/state/state_test.go @@ -32,12 +32,12 @@ func TestState(t *testing.T) { // committee setters - getters newCommittee := &Committee{1, 1, []ed25519.PublicKey{}, []byte{11}} - stateTest.SetCommittee(newCommittee) + stateTest.UpdateCommittee(newCommittee) require.Equal(t, *newCommittee, stateTest.Committee()) // randomness setters - getters newRandomness := &Randomness{1, []byte{123}, time.Now()} - stateTest.SetRandomness(newRandomness) + stateTest.UpdateRandomness(newRandomness) require.Equal(t, *newRandomness, stateTest.Randomness()) } diff --git a/packages/binary/drng/subtypes/collectiveBeacon/collective_beacon.go b/packages/binary/drng/subtypes/collectiveBeacon/collective_beacon.go index d6734b7632c1bf4eda9d55841f9cb30b24d509d2..9090d5b39f7b66a025584f9e3c363af57fd411e7 100644 --- a/packages/binary/drng/subtypes/collectiveBeacon/collective_beacon.go +++ b/packages/binary/drng/subtypes/collectiveBeacon/collective_beacon.go @@ -12,7 +12,16 @@ import ( "github.com/iotaledger/hive.go/crypto/ed25519" ) -// ProcessTransaction performs the following tasks: +var ( + ErrDistributedPubKeyMismatch = errors.New("Distributed Public Key does not match") + ErrInvalidRound = errors.New("Invalid Round") + ErrInstanceIdMismatch = errors.New("InstanceID does not match") + ErrInvalidIssuer = errors.New("Invalid Issuer") + ErrNilState = errors.New("Nil state") + ErrNilData = errors.New("Nil data") +) + +// ProcessBeacon performs the following tasks: // - verify that we have a valid random // - update drng state func ProcessBeacon(drng *state.State, cb *events.CollectiveBeaconEvent) error { @@ -24,7 +33,7 @@ func ProcessBeacon(drng *state.State, cb *events.CollectiveBeaconEvent) error { } // update drng state - randomness, err := GetRandomness(cb.Signature) + randomness, err := ExtractRandomness(cb.Signature) if err != nil { //TODO: handle error return err @@ -35,29 +44,36 @@ func ProcessBeacon(drng *state.State, cb *events.CollectiveBeaconEvent) error { Timestamp: cb.Timestamp, } - drng.SetRandomness(newRandomness) + drng.UpdateRandomness(newRandomness) return nil } // VerifyCollectiveBeacon verifies against a given state that -// the given CollectiveBeaconEvent contains a valid beacon +// the given CollectiveBeaconEvent contains a valid beacon. func VerifyCollectiveBeacon(state *state.State, data *events.CollectiveBeaconEvent) error { + if state == nil { + return ErrNilState + } + + if data == nil { + return ErrNilData + } if err := verifyIssuer(state, data.IssuerPublicKey); err != nil { return err } if !bytes.Equal(data.Dpk, state.Committee().DistributedPK) { - return errors.New("Distributed Public Key does not match") + return ErrDistributedPubKeyMismatch } if data.Round <= state.Randomness().Round { - return errors.New("invalid Round") + return ErrInvalidRound } if data.InstanceID != state.Committee().InstanceID { - return errors.New("invalid instanceID") + return ErrInstanceIdMismatch } if err := verifySignature(data); err != nil { @@ -67,22 +83,18 @@ func VerifyCollectiveBeacon(state *state.State, data *events.CollectiveBeaconEve return nil } -// verifyIssuer checks the given issuer is a member of the committee +// verifyIssuer checks the given issuer is a member of the committee. func verifyIssuer(state *state.State, issuer ed25519.PublicKey) error { for _, member := range state.Committee().Identities { if member == issuer { return nil } } - return errors.New("Invalid Issuer") + return ErrInvalidIssuer } -// verifySignature checks the current signature against the distributed public key +// verifySignature checks the current signature against the distributed public key. func verifySignature(data *events.CollectiveBeaconEvent) error { - if data == nil { - return errors.New("nil data") - } - dpk := key.KeyGroup.Point() if err := dpk.UnmarshalBinary(data.Dpk); err != nil { return err @@ -97,8 +109,8 @@ func verifySignature(data *events.CollectiveBeaconEvent) error { return nil } -// GetRandomness returns the randomness from a given signature -func GetRandomness(signature []byte) ([]byte, error) { +// ExtractRandomness returns the randomness from a given signature. +func ExtractRandomness(signature []byte) ([]byte, error) { hash := sha512.New() if _, err := hash.Write(signature); err != nil { return nil, err diff --git a/packages/binary/drng/subtypes/collectiveBeacon/collective_beacon_test.go b/packages/binary/drng/subtypes/collectiveBeacon/collective_beacon_test.go index cb3d5e43c5cbe8966e9edc53998956bc45eeefd5..4aaae36f4fa6c4786f3284e9ae745f725b4834d0 100644 --- a/packages/binary/drng/subtypes/collectiveBeacon/collective_beacon_test.go +++ b/packages/binary/drng/subtypes/collectiveBeacon/collective_beacon_test.go @@ -45,14 +45,12 @@ func init() { } func TestVerifySignature(t *testing.T) { - //payload := dkgShares(t, 5, 3) err := verifySignature(eventTest) require.NoError(t, err) } func TestGetRandomness(t *testing.T) { - //payload := dkgShares(t, 5, 3) - _, err := GetRandomness(eventTest.Signature) + _, err := ExtractRandomness(eventTest.Signature) require.NoError(t, err) } @@ -60,69 +58,3 @@ func TestProcessBeacon(t *testing.T) { err := ProcessBeacon(stateTest, eventTest) require.NoError(t, err) } - -// func dkgShares(t *testing.T, n, threshold int) *collectiveBeacon.Payload { -// var priPoly *share.PriPoly -// var pubPoly *share.PubPoly -// var err error -// // create shares and commitments -// for i := 0; i < n; i++ { -// pri := share.NewPriPoly(key.KeyGroup, threshold, key.KeyGroup.Scalar().Pick(random.New()), random.New()) -// pub := pri.Commit(key.KeyGroup.Point().Base()) -// if priPoly == nil { -// priPoly = pri -// pubPoly = pub -// continue -// } -// priPoly, err = priPoly.Add(pri) -// require.NoError(t, err) - -// pubPoly, err = pubPoly.Add(pub) -// require.NoError(t, err) -// } -// shares := priPoly.Shares(n) -// secret, err := share.RecoverSecret(key.KeyGroup, shares, threshold, n) -// require.NoError(t, err) -// require.True(t, secret.Equal(priPoly.Secret())) - -// msg := []byte("first message") -// sigs := make([][]byte, n, n) -// _, commits := pubPoly.Info() -// dkgShares := make([]*key.Share, n, n) - -// // partial signatures -// for i := 0; i < n; i++ { -// sigs[i], err = key.Scheme.Sign(shares[i], msg) -// require.NoError(t, err) - -// dkgShares[i] = &key.Share{ -// Share: shares[i], -// Commits: commits, -// } -// } - -// // reconstruct collective signature -// sig, err := key.Scheme.Recover(pubPoly, msg, sigs, threshold, n) -// require.NoError(t, err) - -// // verify signature against distributed public key -// err = key.Scheme.VerifyRecovered(pubPoly.Commit(), msg, sig) -// require.NoError(t, err) - -// msg = beacon.Message(sig, 1) -// sigs = make([][]byte, n, n) -// // partial signatures -// for i := 0; i < n; i++ { -// sigs[i], err = key.Scheme.Sign(shares[i], msg) -// require.NoError(t, err) -// } - -// // reconstruct collective signature -// newSig, err := key.Scheme.Recover(pubPoly, msg, sigs, threshold, n) -// require.NoError(t, err) - -// dpk, err := pubPoly.Commit().MarshalBinary() -// require.NoError(t, err) - -// return collectiveBeacon.New(1, 1, sig, newSig, dpk) -// } diff --git a/packages/binary/drng/subtypes/collectiveBeacon/events/events.go b/packages/binary/drng/subtypes/collectiveBeacon/events/events.go index c14e637b9b6cb19c6eb0d651aff0f7fe0dadbbd6..8425e20c1fbc6593ab695ec0ad989d328bed00d7 100644 --- a/packages/binary/drng/subtypes/collectiveBeacon/events/events.go +++ b/packages/binary/drng/subtypes/collectiveBeacon/events/events.go @@ -4,25 +4,27 @@ import ( "time" "github.com/iotaledger/hive.go/crypto/ed25519" - "github.com/iotaledger/hive.go/events" ) -type CollectiveBeacon = *events.Event - -func NewCollectiveBeaconEvent() *events.Event { - return events.NewEvent(collectiveBeaconReceived) -} - +// CollectiveBeaconEvent holds data about a collective beacon event. type CollectiveBeaconEvent struct { - IssuerPublicKey ed25519.PublicKey // public key of the issuer - Timestamp time.Time // timestamp when the beacon was issued - InstanceID uint32 // instanceID of the beacon - Round uint64 // round of the current beacon - PrevSignature []byte // collective signature of the previous beacon - Signature []byte // collective signature of the current beacon - Dpk []byte // distributed public key + // Public key of the issuer. + IssuerPublicKey ed25519.PublicKey + // Timestamp when the beacon was issued. + Timestamp time.Time + // InstanceID of the beacon. + InstanceID uint32 + // Round of the current beacon. + Round uint64 + // Collective signature of the previous beacon. + PrevSignature []byte + // Collective signature of the current beacon. + Signature []byte + // The distributed public key. + Dpk []byte } -func collectiveBeaconReceived(handler interface{}, params ...interface{}) { +// CollectiveBeaconReceived returns the data of a collective beacon event. +func CollectiveBeaconReceived(handler interface{}, params ...interface{}) { handler.(func(*CollectiveBeaconEvent))(params[0].(*CollectiveBeaconEvent)) } diff --git a/packages/binary/drng/subtypes/collectiveBeacon/events/events_test.go b/packages/binary/drng/subtypes/collectiveBeacon/events/events_test.go index 101655a60097e79a267c633bf0d92e9b21954b74..3100a36097e4067d5fe90e12f1a043ff2a2f1812 100644 --- a/packages/binary/drng/subtypes/collectiveBeacon/events/events_test.go +++ b/packages/binary/drng/subtypes/collectiveBeacon/events/events_test.go @@ -11,7 +11,7 @@ import ( func TestCollectiveBeaconEvent(t *testing.T) { var cbReceived *CollectiveBeaconEvent - eventTest := NewCollectiveBeaconEvent() + eventTest := events.NewEvent(CollectiveBeaconReceived) eventTest.Attach(events.NewClosure(func(cb *CollectiveBeaconEvent) { cbReceived = cb diff --git a/packages/binary/drng/subtypes/collectiveBeacon/payload/common.go b/packages/binary/drng/subtypes/collectiveBeacon/payload/common.go index 8b3b876264244a54f76e23794da780491c73c28f..13d8225f467a223f5d514b2f7920c158b1a2f649 100644 --- a/packages/binary/drng/subtypes/collectiveBeacon/payload/common.go +++ b/packages/binary/drng/subtypes/collectiveBeacon/payload/common.go @@ -1,8 +1,8 @@ package payload const ( - // BLS Signature size in bytes + // BLS Signature size in bytes. SignatureSize = 96 - // BLS Public Key size in bytes + // BLS Public Key size in bytes. PublicKeySize = 48 ) diff --git a/packages/binary/drng/subtypes/collectiveBeacon/payload/payload.go b/packages/binary/drng/subtypes/collectiveBeacon/payload/payload.go index 97e1b45539415762cc37f014f42cc6910906ccfe..731ab0a30a703fdbab002c509069a2f518d88645 100644 --- a/packages/binary/drng/subtypes/collectiveBeacon/payload/payload.go +++ b/packages/binary/drng/subtypes/collectiveBeacon/payload/payload.go @@ -11,53 +11,34 @@ import ( "github.com/iotaledger/hive.go/marshalutil" ) +// Payload is a collective beacon payload. type Payload struct { - //objectstorage.StorableObjectFlags - - header header.Header - - round uint64 // round of the current beacon - prevSignature []byte // collective signature of the previous beacon - signature []byte // collective signature of the current beacon - dpk []byte // distributed public key - bytes []byte - bytesMutex sync.RWMutex + header.Header + + // Round of the current beacon + Round uint64 + // Collective signature of the previous beacon + PrevSignature []byte + // Collective signature of the current beacon + Signature []byte + // The distributed public key + Dpk []byte + + bytes []byte + bytesMutex sync.RWMutex } +// New creates a new collective beacon payload. func New(instanceID uint32, round uint64, prevSignature, signature, dpk []byte) *Payload { return &Payload{ - header: header.New(header.CollectiveBeaconType(), instanceID), - round: round, - prevSignature: prevSignature, - signature: signature, - dpk: dpk, + Header: header.New(header.TypeCollectiveBeacon, instanceID), + Round: round, + PrevSignature: prevSignature, + Signature: signature, + Dpk: dpk, } } -func (p *Payload) SubType() header.Type { - return p.header.PayloadType() -} - -func (payload *Payload) Instance() uint32 { - return payload.header.Instance() -} - -func (payload *Payload) Round() uint64 { - return payload.round -} - -func (payload *Payload) PrevSignature() []byte { - return payload.prevSignature -} - -func (payload *Payload) Signature() []byte { - return payload.signature -} - -func (payload *Payload) DistributedPK() []byte { - return payload.dpk -} - // Parse is a wrapper for simplified unmarshaling in a byte stream using the marshalUtil package. func Parse(marshalUtil *marshalutil.MarshalUtil) (*Payload, error) { if payload, err := marshalUtil.Parse(func(data []byte) (interface{}, error, int) { return FromBytes(data) }); err != nil { @@ -92,27 +73,27 @@ func FromBytes(bytes []byte, optionalTargetObject ...*Payload) (result *Payload, } // parse header - if result.header, err = header.Parse(marshalUtil); err != nil { + if result.Header, err = header.Parse(marshalUtil); err != nil { return } // parse round - if result.round, err = marshalUtil.ReadUint64(); err != nil { + if result.Round, err = marshalUtil.ReadUint64(); err != nil { return } // parse prevSignature - if result.prevSignature, err = marshalUtil.ReadBytes(SignatureSize); err != nil { + if result.PrevSignature, err = marshalUtil.ReadBytes(SignatureSize); err != nil { return } // parse current signature - if result.signature, err = marshalUtil.ReadBytes(SignatureSize); err != nil { + if result.Signature, err = marshalUtil.ReadBytes(SignatureSize); err != nil { return } // parse distributed public key - if result.dpk, err = marshalUtil.ReadBytes(PublicKeySize); err != nil { + if result.Dpk, err = marshalUtil.ReadBytes(PublicKeySize); err != nil { return } @@ -131,7 +112,7 @@ func (payload *Payload) Bytes() (bytes []byte) { // return if bytes have been determined already if bytes = payload.bytes; bytes != nil { - defer payload.bytesMutex.RUnlock() + payload.bytesMutex.RUnlock() return } @@ -150,11 +131,11 @@ func (payload *Payload) Bytes() (bytes []byte) { marshalUtil := marshalutil.New(marshalutil.UINT32_SIZE + marshalutil.UINT32_SIZE + payloadLength) marshalUtil.WriteUint32(drngPayload.Type) marshalUtil.WriteUint32(uint32(payloadLength)) - marshalUtil.WriteBytes(payload.header.Bytes()) - marshalUtil.WriteUint64(payload.Round()) - marshalUtil.WriteBytes(payload.PrevSignature()) - marshalUtil.WriteBytes(payload.Signature()) - marshalUtil.WriteBytes(payload.DistributedPK()) + marshalUtil.WriteBytes(payload.Header.Bytes()) + marshalUtil.WriteUint64(payload.Round) + marshalUtil.WriteBytes(payload.PrevSignature) + marshalUtil.WriteBytes(payload.Signature) + marshalUtil.WriteBytes(payload.Dpk) bytes = marshalUtil.Bytes() @@ -166,12 +147,12 @@ func (payload *Payload) Bytes() (bytes []byte) { func (payload *Payload) String() string { return stringify.Struct("Payload", - stringify.StructField("type", uint64(payload.SubType())), - stringify.StructField("instance", uint64(payload.Instance())), - stringify.StructField("round", payload.Round()), - stringify.StructField("prevSignature", payload.PrevSignature()), - stringify.StructField("signature", payload.Signature()), - stringify.StructField("distributedPK", payload.DistributedPK()), + stringify.StructField("type", uint64(payload.Header.PayloadType)), + stringify.StructField("instance", uint64(payload.Header.InstanceID)), + stringify.StructField("round", payload.Round), + stringify.StructField("prevSignature", payload.PrevSignature), + stringify.StructField("signature", payload.Signature), + stringify.StructField("distributedPK", payload.Dpk), ) } @@ -191,16 +172,4 @@ func (payload *Payload) Unmarshal(data []byte) (err error) { return } -// func init() { -// payload.RegisterType(drngPayload.Type, func(data []byte) (payload payload.Payload, err error) { -// payload = &Payload{} -// err = payload.UnmarshalBinary(data) - -// return -// }) -// } - -// define contract (ensure that the struct fulfills the corresponding interface) -var _ payload.Payload = &Payload{} - // // endregion /////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/packages/binary/drng/subtypes/collectiveBeacon/payload/payload_test.go b/packages/binary/drng/subtypes/collectiveBeacon/payload/payload_test.go index fc4067c24fb5742a0ebb914710eae9fd0b482a84..03a782468a2560dfd4572602f8a424c4a831e646 100644 --- a/packages/binary/drng/subtypes/collectiveBeacon/payload/payload_test.go +++ b/packages/binary/drng/subtypes/collectiveBeacon/payload/payload_test.go @@ -9,8 +9,8 @@ import ( ) func dummyPayload() *Payload { - header := header.New(header.CollectiveBeaconType(), 0) - return New(header.Instance(), + header := header.New(header.TypeCollectiveBeacon, 0) + return New(header.InstanceID, 0, []byte("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"), // prevSignature []byte("BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"), // signature @@ -25,12 +25,12 @@ func TestParse(t *testing.T) { parsedPayload, err := Parse(marshalUtil) require.NoError(t, err) - require.Equal(t, payload.SubType(), parsedPayload.SubType()) - require.Equal(t, payload.Instance(), parsedPayload.Instance()) - require.Equal(t, payload.Round(), parsedPayload.Round()) - require.Equal(t, payload.PrevSignature(), parsedPayload.PrevSignature()) - require.Equal(t, payload.Signature(), parsedPayload.Signature()) - require.Equal(t, payload.DistributedPK(), parsedPayload.DistributedPK()) + require.Equal(t, payload.Header.PayloadType, parsedPayload.Header.PayloadType) + require.Equal(t, payload.Header.InstanceID, parsedPayload.Header.InstanceID) + require.Equal(t, payload.Round, parsedPayload.Round) + require.Equal(t, payload.PrevSignature, parsedPayload.PrevSignature) + require.Equal(t, payload.Signature, parsedPayload.Signature) + require.Equal(t, payload.Dpk, parsedPayload.Dpk) } func TestString(t *testing.T) { diff --git a/plugins/drng/drng.go b/plugins/drng/drng.go index a1fb2c489b4b24ea7a6a1822057e5dbe3ce5f38a..1f4385d3f477ee9e8a714c1ab91478807cd32658 100644 --- a/plugins/drng/drng.go +++ b/plugins/drng/drng.go @@ -15,7 +15,7 @@ var ( ) func parseCommitteeMembers() (result []ed25519.PublicKey, err error) { - for _, committeeMember := range config.Node.GetStringSlice(CFG_COMMITTEE_MEMBERS) { + for _, committeeMember := range config.Node.GetStringSlice(CfgDRNGCommitteeMembers) { if committeeMember == "" { continue } diff --git a/plugins/drng/parameters.go b/plugins/drng/parameters.go index 310e21eeb077de1b1de5002fdb143021410f1d19..d0c1193de979f71ce5766c028e15c38d824a05cd 100644 --- a/plugins/drng/parameters.go +++ b/plugins/drng/parameters.go @@ -5,15 +5,15 @@ import ( ) const ( - CFG_INSTANCE_ID = "drng.instanceId" - CFG_THRESHOLD = "drng.threshold" - CFG_DISTRIBUTED_PUB_KEY = "drng.distributedPubKey" - CFG_COMMITTEE_MEMBERS = "drng.committeeMembers" + CfgDRNGInstanceID = "drng.instanceId" + CfgDRNGThreshold = "drng.threshold" + CfgDRNGDistributedPubKey = "drng.distributedPubKey" + CfgDRNGCommitteeMembers = "drng.committeeMembers" ) func init() { - flag.Uint32(CFG_INSTANCE_ID, 1, "instance ID of the drng instance") - flag.Uint32(CFG_THRESHOLD, 3, "BLS threshold of the drng") - flag.String(CFG_DISTRIBUTED_PUB_KEY, "", "distributed public key of the committee (hex encoded)") - flag.StringSlice(CFG_COMMITTEE_MEMBERS, []string{}, "list of committee members of the drng") + flag.Uint32(CfgDRNGInstanceID, 1, "instance ID of the drng instance") + flag.Uint32(CfgDRNGThreshold, 3, "BLS threshold of the drng") + flag.String(CfgDRNGDistributedPubKey, "", "distributed public key of the committee (hex encoded)") + flag.StringSlice(CfgDRNGCommitteeMembers, []string{}, "list of committee members of the drng") } diff --git a/plugins/drng/plugin.go b/plugins/drng/plugin.go index ad8ff7f823b54e51d228bb9f2536863d134b087b..5b43673e688f8d42daf7b997082917921bf31c78 100644 --- a/plugins/drng/plugin.go +++ b/plugins/drng/plugin.go @@ -22,7 +22,7 @@ const name = "DRNG" // name of the plugin var PLUGIN = node.NewPlugin(name, node.Enabled, configure, run) var ( - Instance *drng.Instance + Instance *drng.DRNG log *logger.Logger ) @@ -32,26 +32,26 @@ func configure(*node.Plugin) { // parse identities of the committee members committeeMembers, err := parseCommitteeMembers() if err != nil { - log.Warnf("Invalid %s: %s", CFG_COMMITTEE_MEMBERS, err) + log.Warnf("Invalid %s: %s", CfgDRNGCommitteeMembers, err) } // parse distributed public key of the committee var dpk []byte - if str := config.Node.GetString(CFG_DISTRIBUTED_PUB_KEY); str != "" { + if str := config.Node.GetString(CfgDRNGDistributedPubKey); str != "" { bytes, err := hex.DecodeString(str) if err != nil { - log.Warnf("Invalid %s: %s", CFG_DISTRIBUTED_PUB_KEY, err) + log.Warnf("Invalid %s: %s", CfgDRNGDistributedPubKey, err) } if l := len(bytes); l != cbPayload.PublicKeySize { - log.Warnf("Invalid %s length: %d, need %d", CFG_DISTRIBUTED_PUB_KEY, l, cbPayload.PublicKeySize) + log.Warnf("Invalid %s length: %d, need %d", CfgDRNGDistributedPubKey, l, cbPayload.PublicKeySize) } dpk = append(dpk, bytes...) } // configure committee committeeConf := &state.Committee{ - InstanceID: config.Node.GetUint32(CFG_INSTANCE_ID), - Threshold: uint8(config.Node.GetUint32(CFG_THRESHOLD)), + InstanceID: config.Node.GetUint32(CfgDRNGInstanceID), + Threshold: uint8(config.Node.GetUint32(CfgDRNGThreshold)), DistributedPK: dpk, Identities: committeeMembers, } diff --git a/plugins/spa/drng_livefeed.go b/plugins/spa/drng_livefeed.go index 178882468cc3a5d498e03d9a336ef5cc2dc2303b..5f4b087e101fe931c3db099e5653568cf65dac0a 100644 --- a/plugins/spa/drng_livefeed.go +++ b/plugins/spa/drng_livefeed.go @@ -20,7 +20,6 @@ var drngLiveFeedWorkerPool *workerpool.WorkerPool func configureDrngLiveFeed() { drngLiveFeedWorkerPool = workerpool.New(func(task workerpool.Task) { newRandomness := task.Param(0).(state.Randomness) - log.Info(newRandomness) sendToAllWSClient(&msg{MsgTypeDrng, &drngMsg{ Instance: drng.Instance.State.Committee().InstanceID, @@ -36,7 +35,6 @@ func configureDrngLiveFeed() { func runDrngLiveFeed() { newMsgRateLimiter := time.NewTicker(time.Second / 10) notifyNewRandomness := events.NewClosure(func(message state.Randomness) { - select { case <-newMsgRateLimiter.C: drngLiveFeedWorkerPool.TrySubmit(message) @@ -44,14 +42,14 @@ func runDrngLiveFeed() { } }) - daemon.BackgroundWorker("SPA[DrngUpdater]", func(shutdownSignal <-chan struct{}) { + daemon.BackgroundWorker("SPA[DRNGUpdater]", func(shutdownSignal <-chan struct{}) { drng.Instance.Events.Randomness.Attach(notifyNewRandomness) drngLiveFeedWorkerPool.Start() <-shutdownSignal - log.Info("Stopping SPA[DrngUpdater] ...") + log.Info("Stopping SPA[DRNGUpdater] ...") drng.Instance.Events.Randomness.Detach(notifyNewRandomness) newMsgRateLimiter.Stop() drngLiveFeedWorkerPool.Stop() - log.Info("Stopping SPA[DrngUpdater] ... done") + log.Info("Stopping SPA[DRNGUpdater] ... done") }, shutdown.ShutdownPrioritySPA) } diff --git a/plugins/webapi/drng/collectiveBeacon/handler.go b/plugins/webapi/drng/collectiveBeacon/handler.go index bdd3d8ef57eb42ea973e00a739a157323cf00894..cb157e9a7530fd797a1e528981b1772d520703d0 100644 --- a/plugins/webapi/drng/collectiveBeacon/handler.go +++ b/plugins/webapi/drng/collectiveBeacon/handler.go @@ -10,8 +10,7 @@ import ( "github.com/labstack/gommon/log" ) -// Handler creates a message of the given payload and -// broadcasts it to the node's neighbors. It returns the message ID if successful. +// Handler gets the current DRNG committee. func Handler(c echo.Context) error { var request Request if err := c.Bind(&request); err != nil { @@ -24,7 +23,7 @@ func Handler(c echo.Context) error { marshalUtil := marshalutil.New(request.Payload) parsedPayload, err := payload.Parse(marshalUtil) if err != nil { - return c.JSON(http.StatusBadRequest, Response{Error: "Not a valid Collective Beacon payload"}) + return c.JSON(http.StatusBadRequest, Response{Error: "not a valid Collective Beacon payload"}) } tx := messagelayer.MessageFactory.IssuePayload(parsedPayload) @@ -32,11 +31,13 @@ func Handler(c echo.Context) error { return c.JSON(http.StatusOK, Response{Id: tx.Id().String()}) } +// Response is the HTTP response from broadcasting a collective beacon message. type Response struct { Id string `json:"id,omitempty"` Error string `json:"error,omitempty"` } +// Request is a request containing a collective beacon response. type Request struct { Payload []byte `json:"payload"` } diff --git a/plugins/webapi/drng/info/committee/handler.go b/plugins/webapi/drng/info/committee/handler.go index 88b332f327f8878c67386d1f794f43967a88130a..9b3a7bf8ff8db02929e4d06f8e94ac3526f7e71a 100644 --- a/plugins/webapi/drng/info/committee/handler.go +++ b/plugins/webapi/drng/info/committee/handler.go @@ -8,8 +8,7 @@ import ( "github.com/labstack/echo" ) -// Handler creates a message of the given payload and -// broadcasts it to the node's neighbors. It returns the message ID if successful. +// Handler returns the current DRNG committee used. func Handler(c echo.Context) error { committee := drng.Instance.State.Committee() return c.JSON(http.StatusOK, Response{ @@ -20,6 +19,7 @@ func Handler(c echo.Context) error { }) } +// Response is the HTTP message containing the DRNG committee. type Response struct { InstanceID uint32 `json:"instanceID,omitempty"` Threshold uint8 `json:"threshold,omitempty"`