Skip to content

Commit c8d23eb

Browse files
committed
Applying changes after Thibault's review.
1 parent 04ebacc commit c8d23eb

File tree

2 files changed

+131
-23
lines changed

2 files changed

+131
-23
lines changed

sign/bls/bls.go

+100-23
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,30 @@
1-
// Package bls provides BLS signatures instantiated with the BLS12-381 pairing curve.
1+
// Package bls provides BLS signatures using the BLS12-381 pairing curve.
2+
//
3+
// This packages implements the IETF/CFRG draft for BLS signatures [1].
4+
// Currently only the BASIC mode (one of the three modes specified
5+
// in the draft) is supported. The pairing function is instantiated
6+
// with the BLS12-381 curve.
7+
//
8+
// # Groups
9+
//
10+
// The BLS signature scheme can be instantiated with keys in one of the
11+
// two groups: G1 or G2, which correspond to the input domain of a pairing
12+
// function e(G1,G2) -> Gt.
13+
// Thus, choosing keys in G1 implies that signature values are internally
14+
// represented in G2; or viceversa. Use the types KeyG1SigG2 or KeyG2SigG1
15+
// to express this preference.
16+
//
17+
// # Serialization
18+
//
19+
// The serialization of elements in G1 and G2 follows the recommendation
20+
// given in [2], in order to be compatible with other implementations of
21+
// BLS12-381 curve.
22+
//
23+
// # References
24+
//
25+
// [1] https://datatracker.ietf.org/doc/draft-irtf-cfrg-bls-signature/
26+
//
27+
// [2] https://github.com/zkcrypto/bls12_381/blob/0.7.0/src/notes/serialization.rs
228
package bls
329

430
import (
@@ -12,6 +38,19 @@ import (
1238
"golang.org/x/crypto/hkdf"
1339
)
1440

41+
var (
42+
ErrInvalid = errors.New("bls: invalid BLS instance")
43+
ErrInvalidKey = errors.New("bls: invalid key")
44+
ErrKeyGen = errors.New("bls: too many unsuccessful key generation tries")
45+
ErrShortIKM = errors.New("bls: IKM material shorter than 32 bytes")
46+
ErrAggregate = errors.New("bls: error while aggregating signatures")
47+
)
48+
49+
const (
50+
dstG1 = "BLS_SIG_BLS12381G1_XMD:SHA-256_SSWU_RO_NUL_"
51+
dstG2 = "BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_NUL_"
52+
)
53+
1554
type Signature = []byte
1655

1756
type (
@@ -44,6 +83,8 @@ type PublicKey[K KeyGroup] struct{ key K }
4483

4584
func (k *PrivateKey[K]) Public() crypto.PublicKey { return k.PublicKey() }
4685

86+
// PublicKey computes the corresponding public key. The key is cached
87+
// for further invocations to this function.
4788
func (k *PrivateKey[K]) PublicKey() *PublicKey[K] {
4889
if k.pub == nil {
4990
k.pub = new(PublicKey[K])
@@ -64,14 +105,30 @@ func (k *PrivateKey[K]) PublicKey() *PublicKey[K] {
64105

65106
func (k *PrivateKey[K]) Equal(x crypto.PrivateKey) bool {
66107
xx, ok := x.(*PrivateKey[K])
108+
if !ok {
109+
return false
110+
}
111+
112+
switch (interface{})(k).(type) {
113+
case *PrivateKey[G1], *PrivateKey[G2]:
114+
return k.key.IsEqual(&xx.key) == 1
115+
default:
116+
panic(ErrInvalid)
117+
}
118+
}
119+
120+
// Validate explicitly determines if a private key is valid.
121+
func (k *PrivateKey[K]) Validate() bool {
67122
switch (interface{})(k).(type) {
68123
case *PrivateKey[G1], *PrivateKey[G2]:
69-
return ok && k.key.IsEqual(&xx.key) == 1
124+
return k.key.IsZero() == 0
70125
default:
71126
panic(ErrInvalid)
72127
}
73128
}
74129

130+
// MarshalBinary returns a slice with the representation of
131+
// the underlying PrivateKey scalar (in big-endian order).
75132
func (k *PrivateKey[K]) MarshalBinary() ([]byte, error) {
76133
switch (interface{})(k).(type) {
77134
case *PrivateKey[G1], *PrivateKey[G2]:
@@ -84,12 +141,20 @@ func (k *PrivateKey[K]) MarshalBinary() ([]byte, error) {
84141
func (k *PrivateKey[K]) UnmarshalBinary(data []byte) error {
85142
switch (interface{})(k).(type) {
86143
case *PrivateKey[G1], *PrivateKey[G2]:
87-
return k.key.UnmarshalBinary(data)
144+
if err := k.key.UnmarshalBinary(data); err != nil {
145+
return err
146+
}
147+
if !k.Validate() {
148+
return ErrInvalidKey
149+
}
150+
k.pub = nil
151+
return nil
88152
default:
89153
panic(ErrInvalid)
90154
}
91155
}
92156

157+
// Validate explicitly determines if a public key is valid.
93158
func (k *PublicKey[K]) Validate() bool {
94159
switch (interface{})(k).(type) {
95160
case *PublicKey[G1]:
@@ -105,20 +170,26 @@ func (k *PublicKey[K]) Validate() bool {
105170

106171
func (k *PublicKey[K]) Equal(x crypto.PublicKey) bool {
107172
xx, ok := x.(*PublicKey[K])
173+
if !ok {
174+
return false
175+
}
176+
108177
switch (interface{})(k).(type) {
109178
case *PublicKey[G1]:
110179
xxx := (interface{})(xx.key).(G1)
111180
kk := (interface{})(k.key).(G1)
112-
return ok && kk.g.IsEqual(&xxx.g)
181+
return kk.g.IsEqual(&xxx.g)
113182
case *PublicKey[G2]:
114183
xxx := (interface{})(xx.key).(G2)
115184
kk := (interface{})(k.key).(G2)
116-
return ok && kk.g.IsEqual(&xxx.g)
185+
return kk.g.IsEqual(&xxx.g)
117186
default:
118187
panic(ErrInvalid)
119188
}
120189
}
121190

191+
// MarshalBinary returns a slice with the compressed
192+
// representation of the underlying element in G1 or G2.
122193
func (k *PublicKey[K]) MarshalBinary() ([]byte, error) {
123194
switch (interface{})(k).(type) {
124195
case *PublicKey[G1]:
@@ -145,7 +216,13 @@ func (k *PublicKey[K]) UnmarshalBinary(data []byte) error {
145216
}
146217
}
147218

219+
// KeyGen derives a private key for the specified group (G1 or G2).
220+
// The length of ikm material should be at least 32 bytes length.
221+
// The salt value should be either empty or a uniformly random
222+
// bytes whose length equals the output length of SHA-256.
148223
func KeyGen[K KeyGroup](ikm, salt, keyInfo []byte) (*PrivateKey[K], error) {
224+
// Implements recommended method at:
225+
// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-bls-signature-05#name-keygen
149226
if len(ikm) < 32 {
150227
return nil, ErrShortIKM
151228
}
@@ -179,7 +256,13 @@ func KeyGen[K KeyGroup](ikm, salt, keyInfo []byte) (*PrivateKey[K], error) {
179256
return nil, ErrKeyGen
180257
}
181258

259+
// Sign computes a signature of a message using a key (defined in
260+
// G1 or G1).
182261
func Sign[K KeyGroup](k *PrivateKey[K], msg []byte) Signature {
262+
if !k.Validate() {
263+
panic(ErrInvalidKey)
264+
}
265+
183266
switch (interface{})(k).(type) {
184267
case *PrivateKey[G1]:
185268
var Q GG.G2
@@ -196,6 +279,8 @@ func Sign[K KeyGroup](k *PrivateKey[K], msg []byte) Signature {
196279
}
197280
}
198281

282+
// Verify returns true if the signature of a message is valid for the
283+
// corresponding public key.
199284
func Verify[K KeyGroup](pub *PublicKey[K], msg []byte, sig Signature) bool {
200285
var (
201286
a, b interface {
@@ -236,6 +321,9 @@ func Verify[K KeyGroup](pub *PublicKey[K], msg []byte, sig Signature) bool {
236321
return res.IsIdentity()
237322
}
238323

324+
// Aggregate produces a unified signature given a list of signatures.
325+
// To specify the group of keys pass either G1{} or G2{} as the first
326+
// parameter.
239327
func Aggregate[K KeyGroup](k K, sigs []Signature) (Signature, error) {
240328
if len(sigs) == 0 {
241329
return nil, ErrAggregate
@@ -269,6 +357,9 @@ func Aggregate[K KeyGroup](k K, sigs []Signature) (Signature, error) {
269357
}
270358
}
271359

360+
// VerifyAggregate returns true if the aggregated signature is valid for
361+
// the list of messages and public keys provided. The slices must have
362+
// equal size and have at least one element.
272363
func VerifyAggregate[K KeyGroup](pubs []*PublicKey[K], msgs [][]byte, aggSig Signature) bool {
273364
if len(pubs) != len(msgs) || len(pubs) == 0 || len(msgs) == 0 {
274365
return false
@@ -279,6 +370,10 @@ func VerifyAggregate[K KeyGroup](pubs []*PublicKey[K], msgs [][]byte, aggSig Sig
279370
listG2 := make([]*GG.G2, n+1)
280371
listExp := make([]int, n+1)
281372

373+
listG1[n] = GG.G1Generator()
374+
listG2[n] = GG.G2Generator()
375+
listExp[n] = -1
376+
282377
switch (interface{})(pubs).(type) {
283378
case []*PublicKey[G1]:
284379
for i := range msgs {
@@ -290,13 +385,10 @@ func VerifyAggregate[K KeyGroup](pubs []*PublicKey[K], msgs [][]byte, aggSig Sig
290385
listExp[i] = 1
291386
}
292387

293-
listG2[n] = new(GG.G2)
294388
err := listG2[n].SetBytes(aggSig)
295389
if err != nil {
296390
return false
297391
}
298-
listG1[n] = GG.G1Generator()
299-
listExp[n] = -1
300392

301393
case []*PublicKey[G2]:
302394
for i := range msgs {
@@ -308,13 +400,10 @@ func VerifyAggregate[K KeyGroup](pubs []*PublicKey[K], msgs [][]byte, aggSig Sig
308400
listExp[i] = 1
309401
}
310402

311-
listG1[n] = new(GG.G1)
312403
err := listG1[n].SetBytes(aggSig)
313404
if err != nil {
314405
return false
315406
}
316-
listG2[n] = GG.G2Generator()
317-
listExp[n] = -1
318407

319408
default:
320409
panic(ErrInvalid)
@@ -323,15 +412,3 @@ func VerifyAggregate[K KeyGroup](pubs []*PublicKey[K], msgs [][]byte, aggSig Sig
323412
C := GG.ProdPairFrac(listG1, listG2, listExp)
324413
return C.IsIdentity()
325414
}
326-
327-
var (
328-
ErrInvalid = errors.New("bls: invalid BLS instance")
329-
ErrKeyGen = errors.New("bls: too many unsuccessful key generation tries")
330-
ErrShortIKM = errors.New("bls: IKM material shorter than 32 bytes")
331-
ErrAggregate = errors.New("bls: error while aggregating signatures")
332-
)
333-
334-
const (
335-
dstG1 = "BLS_SIG_BLS12381G1_XMD:SHA-256_SSWU_RO_NUL_"
336-
dstG2 = "BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_NUL_"
337-
)

sign/bls/bls_test.go

+31
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package bls_test
33
import (
44
"bytes"
55
"crypto/rand"
6+
"crypto/rsa"
67
"encoding"
78
"fmt"
89
"testing"
@@ -80,6 +81,9 @@ func testMarshal[K bls.KeyGroup](
8081
if !bytes.Equal(got, want) {
8182
test.ReportError(t, got, want)
8283
}
84+
85+
err = right.UnmarshalBinary(nil)
86+
test.CheckIsErr(t, err, "should fail: empty input")
8387
}
8488

8589
func testErrors[K bls.KeyGroup](t *testing.T) {
@@ -93,6 +97,33 @@ func testErrors[K bls.KeyGroup](t *testing.T) {
9397
test.CheckNoErr(t, err, "failed to keygen")
9498
pub := priv.PublicKey()
9599
test.CheckOk(bls.Verify(pub, nil, nil) == false, "should fail: bad signature", t)
100+
101+
// Bad public key
102+
msg := []byte("hello")
103+
sig := bls.Sign[K](priv, msg)
104+
pub = new(bls.PublicKey[K])
105+
test.CheckOk(pub.Validate() == false, "should fail: bad public key", t)
106+
test.CheckOk(bls.Verify(pub, msg, sig) == false, "should fail: bad signature", t)
107+
108+
// Bad private key
109+
priv = new(bls.PrivateKey[K])
110+
test.CheckOk(priv.Validate() == false, "should fail: bad private key", t)
111+
err = test.CheckPanic(func() { bls.Sign(priv, msg) })
112+
test.CheckNoErr(t, err, "sign should panic")
113+
114+
// Wrong comparisons
115+
test.CheckOk(priv.Equal(new(rsa.PrivateKey)) == false, "should fail: bad private key types", t)
116+
test.CheckOk(pub.Equal(new(rsa.PublicKey)) == false, "should fail: bad public key types", t)
117+
118+
// Aggregate nil
119+
_, err = bls.Aggregate[K](*new(K), nil)
120+
test.CheckIsErr(t, err, "should fail: empty signatures")
121+
122+
// VerifyAggregate nil
123+
test.CheckOk(bls.VerifyAggregate([]*bls.PublicKey[K]{}, nil, nil) == false, "should fail: empty keys", t)
124+
125+
// VerifyAggregate empty signature
126+
test.CheckOk(bls.VerifyAggregate([]*bls.PublicKey[K]{pub}, [][]byte{msg}, nil) == false, "should fail: empty signature", t)
96127
}
97128

98129
func testAggregation[K bls.KeyGroup](t *testing.T) {

0 commit comments

Comments
 (0)