-
Notifications
You must be signed in to change notification settings - Fork 6
Expand file tree
/
Copy pathbls12381.go
More file actions
183 lines (160 loc) · 5.93 KB
/
bls12381.go
File metadata and controls
183 lines (160 loc) · 5.93 KB
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
package crypto
import (
"crypto/subtle"
"encoding/hex"
"github.com/pkg/errors"
blst "github.com/supranational/blst/bindings/go"
)
const (
// BLSSecretKeyLength is the length of a BLS secret key in bytes
BLSSecretKeyLength = 32
// BLSPubkeyLength is the length of a BLS public key in bytes
BLSPubkeyLength = 48
// BLSAggregateSignatureLength is the length of a BLS aggregate signature in bytes
BLSAggregateSignatureLength = 96
)
var dst = []byte("BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_POP_")
type (
blstPublicKey = blst.P1Affine
blstSignature = blst.P2Affine
blstAggregateSignature = blst.P2Aggregate
blstAggregatePublicKey = blst.P1Aggregate
)
type (
// BLS12381PrivateKey represents a BLS12381 private key
BLS12381PrivateKey struct {
p *blst.SecretKey
}
// BLS12381PublicKey represents a BLS12381 public key
BLS12381PublicKey struct {
p *blstPublicKey
}
// BLSAggregateSignature represents an aggregated BLS signature
BLSAggregateSignature struct {
p *blstSignature
}
)
// GenerateBLS12381PrivateKey generates a new BLS12381 private key from the given input key material (ikm).
func GenerateBLS12381PrivateKey(ikm []byte) (*BLS12381PrivateKey, error) {
if len(ikm) < 32 {
return nil, errors.Wrapf(ErrPrivateKey, "input key material must be at least 32 bytes, got %d bytes", len(ikm))
}
priv := &BLS12381PrivateKey{
p: blst.KeyGen(ikm),
}
if IsZero(priv.p.Serialize()) {
return nil, errors.Wrapf(ErrPrivateKey, "private key generation failed, resulting key is zero")
}
return priv, nil
}
// BLS12381PrivateKeyFromBytes creates a BLS12381 private key from the given byte slice.
func BLS12381PrivateKeyFromBytes(b []byte) (*BLS12381PrivateKey, error) {
if len(b) != BLSSecretKeyLength {
return nil, errors.Wrapf(ErrPrivateKey, "invalid private key length: got %d, want %d", len(b), BLSSecretKeyLength)
}
if IsZero(b) {
return nil, errors.Wrapf(ErrPrivateKey, "private key is zero")
}
sk := new(blst.SecretKey).Deserialize(b)
if sk == nil {
return nil, errors.Wrapf(ErrPrivateKey, "invalid private key")
}
return &BLS12381PrivateKey{p: sk}, nil
}
// Bytes returns the byte representation of the BLS12381 private key.
func (k *BLS12381PrivateKey) Bytes() []byte {
return k.p.Serialize()
}
// HexString returns the hexadecimal string representation of the BLS12381 private key.
func (k *BLS12381PrivateKey) HexString() string {
return hex.EncodeToString(k.Bytes())
}
// Sign signs the given message using the BLS12381 private key.
func (k *BLS12381PrivateKey) Sign(msg []byte) ([]byte, error) {
signature := new(blstSignature).Sign(k.p, msg, dst)
return signature.Compress(), nil
}
// PublicKey returns the public key corresponding to the BLS12381 private key.
func (k *BLS12381PrivateKey) PublicKey() *BLS12381PublicKey {
return &BLS12381PublicKey{
p: new(blstPublicKey).From(k.p),
}
}
// Zero clears the BLS12381 private key, effectively zeroizing it.
func (k *BLS12381PrivateKey) Zero() {
k.p.Zeroize()
}
// BLS12381PublicKeyFromBytes creates a BLS12381 public key from the given byte slice.
func BLS12381PublicKeyFromBytes(b []byte) (*BLS12381PublicKey, error) {
if len(b) != BLSPubkeyLength {
return nil, errors.Wrapf(ErrPublicKey, "invalid public key length: got %d, want %d", len(b), BLSPubkeyLength)
}
pk := new(blstPublicKey).Uncompress(b)
if pk == nil {
return nil, errors.Wrapf(ErrPublicKey, "invalid public key")
}
if !pk.KeyValidate() {
return nil, errors.Wrapf(ErrPublicKey, "invalid public key, key validation failed")
}
return &BLS12381PublicKey{p: pk}, nil
}
// Bytes returns the byte representation of the BLS12381 public key.
func (k *BLS12381PublicKey) Bytes() []byte {
return k.p.Compress()
}
// HexString returns the hexadecimal string representation of the BLS12381 public key.
func (k *BLS12381PublicKey) HexString() string {
return hex.EncodeToString(k.Bytes())
}
// Verify verifies the given signature against the message using the BLS12381 public key.
func (k *BLS12381PublicKey) Verify(msg []byte, sig []byte) bool {
signature := new(blstSignature).Uncompress(sig)
if signature == nil {
return false
}
return signature.Verify(true, k.p, false, msg, dst)
}
// NewBLSAggregateSignature aggregates multiple BLS signatures into a single signature.
func NewBLSAggregateSignature(sigs [][]byte) (*BLSAggregateSignature, error) {
signature := new(blstAggregateSignature)
valid := signature.AggregateCompressed(sigs, true)
if !valid {
return nil, errors.Wrapf(ErrSignature, "provided signatures fail the group check and cannot be compressed")
}
return &BLSAggregateSignature{p: signature.ToAffine()}, nil
}
// BLSAggregateSignatureFromBytes creates a BLS aggregate signature from the given byte slice.
func BLSAggregateSignatureFromBytes(b []byte) (*BLSAggregateSignature, error) {
if len(b) != BLSAggregateSignatureLength {
return nil, errors.Wrapf(ErrSignature, "invalid aggregate signature length: got %d, want %d", len(b), BLSAggregateSignatureLength)
}
p := new(blstSignature).Uncompress(b)
if p == nil {
return nil, errors.Wrapf(ErrSignature, "invalid aggregate signature")
}
return &BLSAggregateSignature{p: p}, nil
}
// Bytes returns the byte representation of the BLS aggregate signature.
func (s *BLSAggregateSignature) Bytes() []byte {
return s.p.Compress()
}
// HexString returns the hexadecimal string representation of the BLS aggregate signature.
func (s *BLSAggregateSignature) HexString() string {
return hex.EncodeToString(s.Bytes())
}
// Verify verifies the aggregate signature against the given public keys and message.
func (s *BLSAggregateSignature) Verify(pubKeys []*BLS12381PublicKey, msg []byte) bool {
blstPubkeys := make([]*blstPublicKey, len(pubKeys))
for i, pubKey := range pubKeys {
blstPubkeys[i] = pubKey.p
}
return s.p.FastAggregateVerify(true, blstPubkeys, msg, dst)
}
// IsZero checks if the given byte slice is all zeros in constant time.
func IsZero(sKey []byte) bool {
b := byte(0)
for _, s := range sKey {
b |= s
}
return subtle.ConstantTimeByteEq(b, 0) == 1
}