forked from taurusgroup/multi-party-sig
-
Notifications
You must be signed in to change notification settings - Fork 0
/
round3.go
198 lines (167 loc) · 5.93 KB
/
round3.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
189
190
191
192
193
194
195
196
197
198
package keygen
import (
"fmt"
"github.com/MixinNetwork/multi-party-sig/common/round"
"github.com/MixinNetwork/multi-party-sig/common/types"
"github.com/MixinNetwork/multi-party-sig/pkg/hash"
"github.com/MixinNetwork/multi-party-sig/pkg/math/curve"
"github.com/MixinNetwork/multi-party-sig/pkg/math/polynomial"
"github.com/MixinNetwork/multi-party-sig/pkg/party"
)
// This round corresponds with steps 2-4 of Round 2, Figure 1 in the Frost paper:
//
// https://eprint.iacr.org/2020/852.pdf
type round3 struct {
*round2
// shareFrom is the secret share sent to us by a given party, including ourselves.
//
// shareFrom[l] corresponds to fₗ(i) in the Frost paper, with i our own ID.
shareFrom map[party.ID]curve.Scalar
}
type message3 struct {
// F_li is the secret share sent from party l to this party.
F_li curve.Scalar
}
type broadcast3 struct {
round.NormalBroadcastContent
// C_l is contribution to the chaining key for this party.
C_l types.RID
// Decommitment = uᵢ decommitment bytes
Decommitment hash.Decommitment
}
// StoreBroadcastMessage implements round.BroadcastRound.
func (r *round3) StoreBroadcastMessage(msg round.Message) error {
from := msg.From
body, ok := msg.Content.(*broadcast3)
if !ok || body == nil {
return round.ErrInvalidContent
}
if err := body.C_l.Validate(); err != nil {
return err
}
// Verify that the commitment to the chain key contribution matches, and then xor
// it into the accumulated chain key so far.
if !r.HashForID(from).Decommit(r.ChainKeyCommitments[from], body.Decommitment, body.C_l) {
return fmt.Errorf("failed to verify chain key commitment")
}
r.ChainKeys[from] = body.C_l
return nil
}
// VerifyMessage implements round.Round.
func (r *round3) VerifyMessage(msg round.Message) error {
body, ok := msg.Content.(*message3)
if !ok || body == nil {
return round.ErrInvalidContent
}
// check nil
if body.F_li == nil {
return round.ErrNilFields
}
return nil
}
// StoreMessage implements round.Round.
//
// Verify the VSS condition here since we will not be sending this message to other parties for verification.
func (r *round3) StoreMessage(msg round.Message) error {
from, body := msg.From, msg.Content.(*message3)
// These steps come from Figure 1, Round 2 of the Frost paper
// 2. "Each Pᵢ verifies their shares by calculating
//
// fₗ(i) * G =? ∑ₖ₌₀ᵗ (iᵏ mod q) * ϕₗₖ
//
// aborting if the check fails."
expected := body.F_li.ActOnBase()
actual := r.Phi[from].Evaluate(r.SelfID().Scalar(r.Group()))
if !expected.Equal(actual) {
return fmt.Errorf("VSS failed to validate")
}
r.shareFrom[from] = body.F_li
return nil
}
// Finalize implements round.Round.
func (r *round3) Finalize(chan<- *round.Message) (round.Session, error) {
chainKey := types.EmptyRID()
for _, j := range r.PartyIDs() {
chainKey.XOR(r.ChainKeys[j])
}
// These steps come from Figure 1, Round 2 of the Frost paper
// 3. "Each P_i calculates their long-lived private signing share by computing
// sᵢ = ∑ₗ₌₁ⁿ fₗ(i), stores s_i securely, and deletes each fₗ(i)"
for l, f_li := range r.shareFrom {
r.privateShare.Add(f_li)
// TODO: Maybe actually clear this in a better way
delete(r.shareFrom, l)
}
// 4. "Each Pᵢ calculates their public verification share Yᵢ = sᵢ • G,
// and the group's public key Y = ∑ⱼ₌₁ⁿ ϕⱼ₀. Any participant
// can compute the verification share of any other participant by calculating
//
// Yᵢ = ∑ⱼ₌₁ⁿ ∑ₖ₌₀ᵗ (iᵏ mod q) * ϕⱼₖ."
for _, phi_j := range r.Phi {
r.publicKey = r.publicKey.Add(phi_j.Constant())
}
// This accomplishes the same sum as in the paper, by first summing
// together the exponent coefficients, and then evaluating.
exponents := make([]*polynomial.Exponent, 0, r.PartyIDs().Len())
for _, phi_j := range r.Phi {
exponents = append(exponents, phi_j)
}
verificationExponent, err := polynomial.Sum(exponents)
if err != nil {
panic(err)
}
for k, v := range r.verificationShares {
r.verificationShares[k] = v.Add(verificationExponent.Evaluate(k.Scalar(r.Group())))
}
if r.taproot {
// BIP-340 adjustment: If our public key is odd, then the underlying secret
// needs to be negated. Since this secret is ∑ᵢ aᵢ₀, we can negated each
// of these. Had we generated the polynomials -fᵢ instead, we would have
// ended up with the correct sharing of the secret. So, this means that
// we can correct by simply negating our share.
//
// We assume that everyone else does the same, so we negate all the verification
// shares.
YSecp := r.publicKey
if !YSecp.HasEvenY() {
r.privateShare.Negate()
for i, y_i := range r.verificationShares {
r.verificationShares[i] = y_i.Negate()
}
}
secpVerificationShares := make(map[party.ID]curve.Point)
for k, v := range r.verificationShares {
secpVerificationShares[k] = v
}
return r.ResultRound(&TaprootConfig{
ID: r.SelfID(),
Threshold: r.threshold,
PrivateShare: r.privateShare,
PublicKey: YSecp.XScalar().Bytes(),
ChainKey: chainKey,
VerificationShares: secpVerificationShares,
}), nil
}
return r.ResultRound(&Config{
ID: r.SelfID(),
Threshold: r.threshold,
PrivateShare: r.privateShare,
PublicKey: r.publicKey,
ChainKey: chainKey,
VerificationShares: party.NewPointMap(r.verificationShares),
}), nil
}
// RoundNumber implements round.Content.
func (message3) RoundNumber() round.Number { return 3 }
// MessageContent implements round.Round.
func (r *round3) MessageContent() round.Content {
return &message3{
F_li: r.Group().NewScalar(),
}
}
// RoundNumber implements round.Content.
func (broadcast3) RoundNumber() round.Number { return 3 }
// BroadcastContent implements round.BroadcastRound.
func (r *round3) BroadcastContent() round.BroadcastContent { return &broadcast3{} }
// Number implements round.Round.
func (round3) Number() round.Number { return 3 }