forked from drand/drand
/
group.go
188 lines (167 loc) · 4.76 KB
/
group.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
// Group is a list of Public keys providing helper methods to search and
package key
import (
"encoding/binary"
"encoding/hex"
"errors"
"fmt"
"time"
"github.com/dchest/blake2b"
kyber "github.com/dedis/kyber"
vss "github.com/dedis/kyber/share/vss/pedersen"
)
// Group holds all information about a group of drand nodes.
type Group struct {
// List of identities forming this group
Nodes []*Identity
// The distributed public key of this group. It is nil if the group has not
// ran a DKG protocol yet.
PublicKey *DistPublic
// Threshold to setup during the DKG or resharing protocol.
Threshold int
// Period to use for the beacon randomness generation
Period time.Duration
}
func (g *Group) Identities() []*Identity {
return g.Nodes
}
// Contains returns true if the public key is contained in the list or not.
func (g *Group) Contains(pub *Identity) bool {
for _, pu := range g.Nodes {
if pu.Equal(pub) {
return true
}
}
return false
}
// Index returns the index of the given public key with a boolean indicating
// whether the public has been found or not.
func (g *Group) Index(pub *Identity) (int, bool) {
for i, pu := range g.Nodes {
if pu.Equal(pub) {
return i, true
}
}
return -1, false
}
// Public returns the public associated to that index
// or panic otherwise. XXX Change that to return error
func (g *Group) Public(i int) *Identity {
if i >= g.Len() {
panic("out of bounds access for Group")
}
return g.Nodes[i]
}
// Hash returns an unique short representation of this group.
// NOTE: It currently does NOT take into account the distributed public key when
// set for simplicity (we want old nodes and new nodes to easily refer to the
// same group for example). This may cause trouble in the future and may require
// more thoughts.
func (g *Group) Hash() (string, error) {
h := blake2b.New256()
// all nodes public keys and positions
for i, n := range g.Nodes {
binary.Write(h, binary.LittleEndian, uint32(i))
b, err := n.Key.MarshalBinary()
if err != nil {
return "", err
}
h.Write(b)
}
binary.Write(h, binary.LittleEndian, uint32(g.Threshold))
return hex.EncodeToString(h.Sum(nil)), nil
}
// Points returns itself under the form of a list of kyber.Point
func (g *Group) Points() []kyber.Point {
pts := make([]kyber.Point, g.Len())
for i, pu := range g.Nodes {
pts[i] = pu.Key
}
return pts
}
// Len returns the number of participants in the group
func (g *Group) Len() int {
return len(g.Nodes)
}
// GroupTOML is the representation of a Group TOML compatible
type GroupTOML struct {
Nodes []*PublicTOML
PublicKey *DistPublicTOML
Threshold int
Period string
}
// FromTOML decodes the group from the toml struct
func (g *Group) FromTOML(i interface{}) (err error) {
gt, ok := i.(*GroupTOML)
if !ok {
return fmt.Errorf("grouptoml unknown")
}
g.Threshold = gt.Threshold
g.Nodes = make([]*Identity, len(gt.Nodes))
for i, ptoml := range gt.Nodes {
g.Nodes[i] = new(Identity)
if err := g.Nodes[i].FromTOML(ptoml); err != nil {
return err
}
}
if g.Threshold < vss.MinimumT(len(gt.Nodes)) {
return errors.New("group file have threshold 0")
} else if g.Threshold > g.Len() {
return errors.New("group file threshold greater than number of participants")
}
if gt.PublicKey != nil {
// dist key only if dkg ran
g.PublicKey = &DistPublic{}
if err = g.PublicKey.FromTOML(gt.PublicKey); err != nil {
return err
}
}
g.Period, err = time.ParseDuration(gt.Period)
return err
}
// TOML returns a TOML-encodable version of the Group
func (g *Group) TOML() interface{} {
gtoml := &GroupTOML{Threshold: g.Threshold}
gtoml.Nodes = make([]*PublicTOML, g.Len())
for i, p := range g.Nodes {
gtoml.Nodes[i] = p.TOML().(*PublicTOML)
}
if g.PublicKey != nil {
gtoml.PublicKey = g.PublicKey.TOML().(*DistPublicTOML)
}
gtoml.Period = g.Period.String()
return gtoml
}
// TOMLValue returns an empty TOML-compatible value of the group
func (g *Group) TOMLValue() interface{} {
return &GroupTOML{}
}
// MergeGroup returns a NEW group with both list of identities combined,
// the maximum between the default threshold and the group's threshold,
// and with the same period as the group.
func (g *Group) MergeGroup(list []*Identity) *Group {
thr := DefaultThreshold(len(list) + g.Len())
if thr < g.Threshold {
thr = g.Threshold
}
return &Group{
Nodes: append(g.Identities(), list...),
Threshold: thr,
Period: g.Period,
}
}
// NewGroup returns a list of identities as a Group.
func NewGroup(list []*Identity, threshold int) *Group {
return &Group{
Nodes: list,
Threshold: threshold,
}
}
// LoadGroup returns a group associated with a given public key
func LoadGroup(list []*Identity, public *DistPublic, threshold int) *Group {
return &Group{
Nodes: list,
Threshold: threshold,
PublicKey: public,
}
}