forked from dedis/kyber
/
tbls.go
107 lines (99 loc) · 3.53 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
// 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"
"go.dedis.ch/kyber/v3/pairing"
"go.dedis.ch/kyber/v3/share"
"go.dedis.ch/kyber/v3/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.
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:]
}
// Sign creates a threshold BLS signature Si = xi * H(m) on the given message m
// using the provided secret key share xi.
func Sign(suite pairing.Suite, 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
}
s, err := bls.Sign(suite, private.V, msg)
if err != nil {
return nil, err
}
if err := binary.Write(buf, binary.BigEndian, s); err != nil {
return nil, err
}
return buf.Bytes(), nil
}
// Verify 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 Verify(suite pairing.Suite, public *share.PubPoly, msg, sig []byte) error {
s := SigShare(sig)
i, err := s.Index()
if err != nil {
return err
}
return bls.Verify(suite, public.Eval(i).V, msg, s.Value())
}
// 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 Recover(suite pairing.Suite, public *share.PubPoly, msg []byte, sigs [][]byte, t, n int) ([]byte, error) {
pubShares := make([]*share.PubShare, 0)
for _, sig := range sigs {
s := SigShare(sig)
i, err := s.Index()
if err != nil {
return nil, err
}
if err = bls.Verify(suite, public.Eval(i).V, msg, s.Value()); err != nil {
return nil, err
}
point := suite.G1().Point()
if err := point.UnmarshalBinary(s.Value()); err != nil {
return nil, err
}
pubShares = append(pubShares, &share.PubShare{I: i, V: point})
if len(pubShares) >= t {
break
}
}
commit, err := share.RecoverCommit(suite.G1(), pubShares, t, n)
if err != nil {
return nil, err
}
sig, err := commit.MarshalBinary()
if err != nil {
return nil, err
}
return sig, nil
}