-
Notifications
You must be signed in to change notification settings - Fork 136
/
frost.go
92 lines (76 loc) · 2.05 KB
/
frost.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
// Package frost provides the FROST threshold signature scheme for Schnorr signatures.
//
// References:
//
// FROST paper: https://eprint.iacr.org/2020/852
// draft-irtf-cfrg-frost: https://datatracker.ietf.org/doc/draft-irtf-cfrg-frost
package frost
import (
"io"
"github.com/cloudflare/circl/group"
"github.com/cloudflare/circl/secretsharing"
)
type PrivateKey struct {
Suite
key group.Scalar
pubKey *PublicKey
}
type PublicKey struct {
Suite
key group.Element
}
func GenerateKey(s Suite, rnd io.Reader) *PrivateKey {
return &PrivateKey{s, s.g.RandomNonZeroScalar(rnd), nil}
}
func (k *PrivateKey) Public() *PublicKey {
return &PublicKey{k.Suite, k.Suite.g.NewElement().MulGen(k.key)}
}
type SharesCommitment = []group.Element
func (k *PrivateKey) Split(rnd io.Reader, threshold, maxSigners uint) ([]PeerSigner, SharesCommitment, error) {
vss, err := secretsharing.NewFeldmanSecretSharing(k.Suite.g, threshold, maxSigners)
if err != nil {
return nil, nil, err
}
shares, sharesCom := vss.Shard(rnd, k.key)
peers := make([]PeerSigner, len(shares))
for i := range shares {
peers[i] = PeerSigner{
Suite: k.Suite,
ID: uint16(shares[i].ID),
threshold: uint16(threshold),
maxSigners: uint16(maxSigners),
keyShare: shares[i].Value,
myPubKey: nil,
}
}
return peers, sharesCom, nil
}
func Verify(s Suite, pubKey *PublicKey, msg, signature []byte) bool {
params := s.g.Params()
Ne, Ns := params.CompressedElementLength, params.ScalarLength
if len(signature) < int(Ne+Ns) {
return false
}
REnc := signature[:Ne]
R := s.g.NewElement()
err := R.UnmarshalBinary(REnc)
if err != nil {
return false
}
zEnc := signature[Ne : Ne+Ns]
z := s.g.NewScalar()
err = z.UnmarshalBinary(zEnc)
if err != nil {
return false
}
pubKeyEnc, err := pubKey.key.MarshalBinaryCompress()
if err != nil {
return false
}
chInput := append(append(append([]byte{}, REnc...), pubKeyEnc...), msg...)
c := s.hasher.h2(chInput)
l := s.g.NewElement().MulGen(z)
r := s.g.NewElement().Mul(pubKey.key, c)
r.Add(r, R)
return l.IsEqual(r)
}