forked from coinbase/kryptology
-
Notifications
You must be signed in to change notification settings - Fork 0
/
dkg_round1.go
148 lines (125 loc) · 4.09 KB
/
dkg_round1.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
//
// Copyright Coinbase, Inc. All Rights Reserved.
//
// SPDX-License-Identifier: Apache-2.0
//
package frost
import (
"bytes"
crand "crypto/rand"
"encoding/gob"
"fmt"
"reflect"
"github.com/pkg/errors"
"github.com/coinbase/kryptology/internal"
"github.com/coinbase/kryptology/pkg/core/curves"
"github.com/coinbase/kryptology/pkg/sharing"
)
// Round1Bcast are values that are broadcast to all other participants
// after round1 completes
type Round1Bcast struct {
Verifiers *sharing.FeldmanVerifier
Wi, Ci curves.Scalar
}
type Round1Result struct {
Broadcast *Round1Bcast
P2P *sharing.ShamirShare
}
func (result *Round1Result) Encode() ([]byte, error) {
gob.Register(result.Broadcast.Verifiers.Commitments[0]) // just the point for now
gob.Register(result.Broadcast.Ci)
buf := &bytes.Buffer{}
enc := gob.NewEncoder(buf)
if err := enc.Encode(result); err != nil {
return nil, errors.Wrap(err, "couldn't encode round 1 broadcast")
}
return buf.Bytes(), nil
}
func (result *Round1Result) Decode(input []byte) error {
buf := bytes.NewBuffer(input)
dec := gob.NewDecoder(buf)
if err := dec.Decode(result); err != nil {
return errors.Wrap(err, "couldn't encode round 1 broadcast")
}
return nil
}
// Round1P2PSend are values that are P2PSend to all other participants
// after round1 completes
type Round1P2PSend = map[uint32]*sharing.ShamirShare
// Round1 implements dkg round 1 of FROST
func (dp *DkgParticipant) Round1(secret []byte) (*Round1Bcast, Round1P2PSend, error) {
// Make sure dkg participant is not empty
if dp == nil || dp.Curve == nil {
return nil, nil, internal.ErrNilArguments
}
// Make sure round number is correct
if dp.round != 1 {
return nil, nil, internal.ErrInvalidRound
}
// Check number of participants
if uint32(len(dp.otherParticipantShares)+1) > dp.feldman.Limit || uint32(len(dp.otherParticipantShares)+1) < dp.feldman.Threshold {
return nil, nil, fmt.Errorf("length of dp.otherParticipantShares + 1 should be equal to feldman limit")
}
// If secret is nil, sample a new one
// If not, check secret is valid
var s curves.Scalar
var err error
if secret == nil {
s = dp.Curve.Scalar.Random(crand.Reader)
} else {
s, err = dp.Curve.Scalar.SetBytes(secret)
if err != nil {
return nil, nil, err
}
if s.IsZero() {
return nil, nil, internal.ErrZeroValue
}
}
// Step 1 - (Aj0,...Ajt), (xi1,...,xin) <- FeldmanShare(s)
// We should validate types of Feldman curve scalar and participant's curve scalar.
if reflect.TypeOf(dp.feldman.Curve.Scalar) != reflect.TypeOf(dp.Curve.Scalar) {
return nil, nil, fmt.Errorf("feldman scalar should have the same type as the dkg participant scalar")
}
verifiers, shares, err := dp.feldman.Split(s, crand.Reader)
if err != nil {
return nil, nil, err
}
// Store Verifiers and shares
dp.verifiers = verifiers
dp.secretShares = shares
// Step 2 - Sample ki <- Z_q
ki := dp.Curve.Scalar.Random(crand.Reader)
// Step 3 - Compute Ri = ki*G
Ri := dp.Curve.ScalarBaseMult(ki)
// Step 4 - Compute Ci = H(i, CTX, g^{a_(i,0)}, R_i), where CTX is fixed context string
var msg []byte
// Append participant id
msg = append(msg, byte(dp.Id))
// Append CTX
msg = append(msg, dp.ctx)
// Append a_{i,0}*G
msg = append(msg, verifiers.Commitments[0].ToAffineCompressed()...)
// Append Ri
msg = append(msg, Ri.ToAffineCompressed()...)
// Hash the message and get Ci
ci := dp.Curve.Scalar.Hash(msg)
// Step 5 - Compute Wi = ki+a_{i,0}*c_i mod q. Note that a_{i,0} is the secret.
// Note: We have to compute scalar in the following way when using ed25519 curve, rather than scalar := dp.Scalar.Mul(s, Ci)
// there is an invalid encoding error when we compute scalar as above.
wi := s.MulAdd(ci, ki)
// Step 6 - Broadcast (Ci, Wi, Ci) to other participants
round1Bcast := &Round1Bcast{
verifiers,
wi,
ci,
}
// Step 7 - P2PSend f_i(j) to each participant Pj and keep (i, f_j(i)) for himself
p2pSend := make(Round1P2PSend, len(dp.otherParticipantShares))
for id := range dp.otherParticipantShares {
p2pSend[id] = shares[id-1]
}
// Update internal state
dp.round = 2
// return
return round1Bcast, p2pSend, nil
}