-
Notifications
You must be signed in to change notification settings - Fork 6
/
kyber_g2.go
171 lines (143 loc) · 4.1 KB
/
kyber_g2.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
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
package bls
import (
"bytes"
"crypto/cipher"
"encoding/hex"
"io"
"github.com/drand/kyber"
"github.com/drand/kyber/group/mod"
bls12381 "github.com/kilic/bls12-381"
)
// domainG2 is the DST used for hash to curve on G2, this is the default from the RFC.
// This is compatible with the paired library > v18
var domainG2 = []byte("BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_NUL_")
func DefaultDomainG2() []byte {
return domainG2
}
// KyberG2 is a kyber.Point holding a G2 point on BLS12-381 curve
type KyberG2 struct {
p *bls12381.PointG2
// domain separation tag. We treat a 0 len dst as the default value as per the RFC "Tags MUST have nonzero length"
dst []byte
}
func NullKyberG2(dst ...byte) *KyberG2 {
var p bls12381.PointG2
return newKyberG2(&p, dst)
}
func newKyberG2(p *bls12381.PointG2, dst []byte) *KyberG2 {
domain := dst
if bytes.Equal(dst, domainG2) {
domain = nil
}
return &KyberG2{p: p, dst: domain}
}
func (k *KyberG2) Equal(k2 kyber.Point) bool {
k2g2, ok := k2.(*KyberG2)
if !ok {
return false
}
return bls12381.NewG2().Equal(k.p, k2g2.p) && bytes.Equal(k.dst, k2g2.dst)
}
func (k *KyberG2) Null() kyber.Point {
return newKyberG2(bls12381.NewG2().Zero(), k.dst)
}
func (k *KyberG2) Base() kyber.Point {
return newKyberG2(bls12381.NewG2().One(), k.dst)
}
func (k *KyberG2) Pick(rand cipher.Stream) kyber.Point {
var dst, src [32]byte
rand.XORKeyStream(dst[:], src[:])
return k.Hash(dst[:])
}
func (k *KyberG2) Set(q kyber.Point) kyber.Point {
k.p.Set(q.(*KyberG2).p)
return k
}
func (k *KyberG2) Clone() kyber.Point {
var p bls12381.PointG2
p.Set(k.p)
return newKyberG2(&p, k.dst)
}
func (k *KyberG2) EmbedLen() int {
panic("bls12-381: unsupported operation")
}
func (k *KyberG2) Embed(data []byte, rand cipher.Stream) kyber.Point {
panic("bls12-381: unsupported operation")
}
func (k *KyberG2) Data() ([]byte, error) {
panic("bls12-381: unsupported operation")
}
func (k *KyberG2) Add(a, b kyber.Point) kyber.Point {
aa := a.(*KyberG2)
bb := b.(*KyberG2)
bls12381.NewG2().Add(k.p, aa.p, bb.p)
return k
}
func (k *KyberG2) Sub(a, b kyber.Point) kyber.Point {
aa := a.(*KyberG2)
bb := b.(*KyberG2)
bls12381.NewG2().Sub(k.p, aa.p, bb.p)
return k
}
func (k *KyberG2) Neg(a kyber.Point) kyber.Point {
aa := a.(*KyberG2)
bls12381.NewG2().Neg(k.p, aa.p)
return k
}
func (k *KyberG2) Mul(s kyber.Scalar, q kyber.Point) kyber.Point {
if q == nil {
q = NullKyberG2(k.dst...).Base()
}
bls12381.NewG2().MulScalarBig(k.p, q.(*KyberG2).p, &s.(*mod.Int).V)
return k
}
// MarshalBinary returns a compressed point, without any domain separation tag information
func (k *KyberG2) MarshalBinary() ([]byte, error) {
// we need to clone the point because of https://github.com/kilic/bls12-381/issues/37
// in order to avoid risks of race conditions.
t := new(bls12381.PointG2).Set(k.p)
return bls12381.NewG2().ToCompressed(t), nil
}
// UnmarshalBinary populates the point from a compressed point representation.
func (k *KyberG2) UnmarshalBinary(buff []byte) error {
var err error
k.p, err = bls12381.NewG2().FromCompressed(buff)
return err
}
// MarshalTo writes a compressed point to the Writer, without any domain separation tag information
func (k *KyberG2) MarshalTo(w io.Writer) (int, error) {
buf, err := k.MarshalBinary()
if err != nil {
return 0, err
}
return w.Write(buf)
}
// UnmarshalFrom populates the point from a compressed point representation read from the Reader.
func (k *KyberG2) UnmarshalFrom(r io.Reader) (int, error) {
buf := make([]byte, k.MarshalSize())
n, err := io.ReadFull(r, buf)
if err != nil {
return n, err
}
return n, k.UnmarshalBinary(buf)
}
func (k *KyberG2) MarshalSize() int {
return 96
}
func (k *KyberG2) String() string {
b, _ := k.MarshalBinary()
return "bls12-381.G2: " + hex.EncodeToString(b)
}
func (k *KyberG2) Hash(m []byte) kyber.Point {
domain := domainG2
// We treat a 0 len dst as the default value as per the RFC "Tags MUST have nonzero length"
if len(k.dst) != 0 {
domain = k.dst
}
pg2, _ := bls12381.NewG2().HashToCurve(m, domain)
k.p = pg2
return k
}
func (k *KyberG2) IsInCorrectGroup() bool {
return bls12381.NewG2().InCorrectSubgroup(k.p)
}