forked from dedis/kyber
-
Notifications
You must be signed in to change notification settings - Fork 10
/
Copy pathtbls.go
150 lines (137 loc) · 4.6 KB
/
tbls.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
// Package tbls implements the (t,n)-threshold Boneh-Lynn-Shacham signature
// scheme. During setup a group of n participants runs a distributed key
// generation algorithm (see kyber/share/dkg) to compute a joint public signing
// key X and one secret key share xi for each of the n signers. To compute a
// signature S on a message m, at least t ouf of n signers have to provide
// partial (BLS) signatures Si on m using their individual key shares xi which
// can then be used to recover the full (regular) BLS signature S via Lagrange
// interpolation. The signature S can be verified with the initially
// established group key X. Signatures are points on curve G1 and public keys
// are points on curve G2.
package tbls
import (
"bytes"
"encoding/binary"
"errors"
"github.com/drand/kyber"
"github.com/drand/kyber/pairing"
"github.com/drand/kyber/share"
"github.com/drand/kyber/sign"
"github.com/drand/kyber/sign/bls"
)
// SigShare encodes a threshold BLS signature share Si = i || v where the 2-byte
// big-endian value i corresponds to the share's index and v represents the
// share's value. The signature share Si is a point on curve G1 or G2.
type SigShare []byte
// Index returns the index i of the TBLS share Si.
func (s SigShare) Index() (int, error) {
var index uint16
buf := bytes.NewReader(s)
err := binary.Read(buf, binary.BigEndian, &index)
if err != nil {
return -1, err
}
return int(index), nil
}
// Value returns the value v of the TBLS share Si.
func (s *SigShare) Value() []byte {
return []byte(*s)[2:]
}
type scheme struct {
keyGroup kyber.Group
sigGroup kyber.Group
sign.Scheme
}
// NewThresholdSchemeOnG1 returns a treshold scheme that computes bls signatures
// on G1
func NewThresholdSchemeOnG1(suite pairing.Suite) sign.ThresholdScheme {
return &scheme{
keyGroup: suite.G2(),
sigGroup: suite.G1(),
Scheme: bls.NewSchemeOnG1(suite),
}
}
// NewThresholdSchemeOnG2 returns a treshold scheme that computes bls signatures
// on G2
func NewThresholdSchemeOnG2(suite pairing.Suite) sign.ThresholdScheme {
return &scheme{
keyGroup: suite.G1(),
sigGroup: suite.G2(),
Scheme: bls.NewSchemeOnG2(suite),
}
}
// Sign creates a threshold BLS signature Si = xi * H(m) on the given message m
// using the provided secret key share xi.
func (s *scheme) Sign(private *share.PriShare, msg []byte) ([]byte, error) {
buf := new(bytes.Buffer)
if err := binary.Write(buf, binary.BigEndian, uint16(private.I)); err != nil {
return nil, err
}
sig, err := s.Scheme.Sign(private.V, msg)
if err != nil {
return nil, err
}
if err := binary.Write(buf, binary.BigEndian, sig); err != nil {
return nil, err
}
return buf.Bytes(), nil
}
func (s *scheme) IndexOf(signature []byte) (int, error) {
if len(signature) != s.sigGroup.PointLen()+2 {
return -1, errors.New("invalid partial signature length")
}
return SigShare(signature).Index()
}
// VerifyPartial checks the given threshold BLS signature Si on the message m using
// the public key share Xi that is associated to the secret key share xi. This
// public key share Xi can be computed by evaluating the public sharing
// polynonmial at the share's index i.
func (s *scheme) VerifyPartial(public *share.PubPoly, msg, sig []byte) error {
sh := SigShare(sig)
i, err := sh.Index()
if err != nil {
return err
}
return s.Scheme.Verify(public.Eval(i).V, msg, sh.Value())
}
func (s *scheme) VerifyRecovered(public kyber.Point, msg, sig []byte) error {
return s.Scheme.Verify(public, msg, sig)
}
// Recover reconstructs the full BLS signature S = x * H(m) from a threshold t
// of signature shares Si using Lagrange interpolation. The full signature S
// can be verified through the regular BLS verification routine using the
// shared public key X. The shared public key can be computed by evaluating the
// public sharing polynomial at index 0.
func (s *scheme) Recover(public *share.PubPoly, msg []byte, sigs [][]byte, t, n int) ([]byte, error) {
var pubShares []*share.PubShare
for _, sig := range sigs {
sh := SigShare(sig)
i, err := sh.Index()
if err != nil {
continue
}
if err = s.Scheme.Verify(public.Eval(i).V, msg, sh.Value()); err != nil {
continue
}
point := s.sigGroup.Point()
if err := point.UnmarshalBinary(sh.Value()); err != nil {
continue
}
pubShares = append(pubShares, &share.PubShare{I: i, V: point})
if len(pubShares) >= t {
break
}
}
if len(pubShares) < t {
return nil, errors.New("not enough valid partial signatures")
}
commit, err := share.RecoverCommit(s.sigGroup, pubShares, t, n)
if err != nil {
return nil, err
}
sig, err := commit.MarshalBinary()
if err != nil {
return nil, err
}
return sig, nil
}