1 package bls12381
2
3 import (
4 "crypto/rand"
5 "fmt"
6 "testing"
7
8 "github.com/cloudflare/circl/ecc/bls12381/ff"
9 "github.com/cloudflare/circl/internal/test"
10 )
11
12 func randomScalar(t testing.TB) *Scalar {
13 s := &Scalar{}
14 err := s.Random(rand.Reader)
15 test.CheckNoErr(t, err, "random scalar")
16 return s
17 }
18
19 func randomG1(t testing.TB) *G1 {
20 P := &G1{}
21 u := &ff.Fp{}
22 r := &isogG1Point{}
23
24 err := u.Random(rand.Reader)
25 test.CheckNoErr(t, err, "random fp")
26
27 r.sswu(u)
28 P.evalIsogG1(r)
29 P.clearCofactor()
30 got := P.IsOnG1()
31 want := true
32
33 if got != want {
34 test.ReportError(t, got, want, "point not in G1", u)
35 }
36 return P
37 }
38
39 func TestG1Add(t *testing.T) {
40 const testTimes = 1 << 6
41 var Q, R G1
42 for i := 0; i < testTimes; i++ {
43 P := randomG1(t)
44 Q = *P
45 R = *P
46 R.Add(&R, &R)
47 R.Neg()
48 Q.Double()
49 Q.Neg()
50 got := R
51 want := Q
52 if !got.IsEqual(&want) {
53 test.ReportError(t, got, want, P)
54 }
55 }
56 }
57
58 func TestG1ScalarMult(t *testing.T) {
59 const testTimes = 1 << 6
60 var Q G1
61 for i := 0; i < testTimes; i++ {
62 P := randomG1(t)
63 k := randomScalar(t)
64 Q.ScalarMult(k, P)
65 Q.toAffine()
66 got := Q.IsOnG1()
67 want := true
68 if got != want {
69 test.ReportError(t, got, want, P, k)
70 }
71 }
72 }
73
74 func TestG1Hash(t *testing.T) {
75 const testTimes = 1 << 8
76
77 for _, e := range [...]struct {
78 Name string
79 Enc func(p *G1, input, dst []byte)
80 }{
81 {"Encode", func(p *G1, input, dst []byte) { p.Encode(input, dst) }},
82 {"Hash", func(p *G1, input, dst []byte) { p.Hash(input, dst) }},
83 } {
84 var msg, dst [4]byte
85 var p G1
86 t.Run(e.Name, func(t *testing.T) {
87 for i := 0; i < testTimes; i++ {
88 _, _ = rand.Read(msg[:])
89 _, _ = rand.Read(dst[:])
90 e.Enc(&p, msg[:], dst[:])
91
92 got := p.isRTorsion()
93 want := true
94 if got != want {
95 test.ReportError(t, got, want, e.Name, msg, dst)
96 }
97 }
98 })
99 }
100 }
101
102 func BenchmarkG1(b *testing.B) {
103 P := randomG1(b)
104 Q := randomG1(b)
105 k := randomScalar(b)
106 var msg, dst [4]byte
107 _, _ = rand.Read(msg[:])
108 _, _ = rand.Read(dst[:])
109
110 b.Run("Add", func(b *testing.B) {
111 for i := 0; i < b.N; i++ {
112 P.Add(P, Q)
113 }
114 })
115 b.Run("Mul", func(b *testing.B) {
116 for i := 0; i < b.N; i++ {
117 P.ScalarMult(k, P)
118 }
119 })
120 b.Run("Hash", func(b *testing.B) {
121 for i := 0; i < b.N; i++ {
122 P.Hash(msg[:], dst[:])
123 }
124 })
125 }
126
127 func TestG1Serial(t *testing.T) {
128 mustOk := "must be ok"
129 mustErr := "must be an error"
130 t.Run("valid", func(t *testing.T) {
131 testTimes := 1 << 6
132 var got, want G1
133 want.SetIdentity()
134 for i := 0; i < testTimes; i++ {
135 for _, b := range [][]byte{want.Bytes(), want.BytesCompressed()} {
136 err := got.SetBytes(b)
137 test.CheckNoErr(t, err, fmt.Sprintf("failure to deserialize: (P:%v b:%x)", want, b))
138
139 if !got.IsEqual(&want) {
140 test.ReportError(t, got, want, b)
141 }
142 }
143 want = *randomG1(t)
144 }
145 })
146 t.Run("badLength", func(t *testing.T) {
147 q := new(G1)
148 p := randomG1(t)
149 b := p.Bytes()
150 test.CheckIsErr(t, q.SetBytes(b[:0]), mustErr)
151 test.CheckIsErr(t, q.SetBytes(b[:1]), mustErr)
152 test.CheckIsErr(t, q.SetBytes(b[:G1Size-1]), mustErr)
153 test.CheckIsErr(t, q.SetBytes(b[:G1SizeCompressed]), mustErr)
154 test.CheckNoErr(t, q.SetBytes(b), mustOk)
155 test.CheckNoErr(t, q.SetBytes(append(b, 0)), mustOk)
156 b = p.BytesCompressed()
157 test.CheckIsErr(t, q.SetBytes(b[:0]), mustErr)
158 test.CheckIsErr(t, q.SetBytes(b[:1]), mustErr)
159 test.CheckIsErr(t, q.SetBytes(b[:G1SizeCompressed-1]), mustErr)
160 test.CheckNoErr(t, q.SetBytes(b), mustOk)
161 test.CheckNoErr(t, q.SetBytes(append(b, 0)), mustOk)
162 })
163 t.Run("badInfinity", func(t *testing.T) {
164 var badInf, p G1
165 badInf.SetIdentity()
166 b := badInf.Bytes()
167 b[0] |= 0x1F
168 err := p.SetBytes(b)
169 test.CheckIsErr(t, err, mustErr)
170 b[0] &= 0xE0
171 b[1] = 0xFF
172 err = p.SetBytes(b)
173 test.CheckIsErr(t, err, mustErr)
174 })
175 t.Run("badCoords", func(t *testing.T) {
176 bad := (&[ff.FpSize]byte{})[:]
177 for i := range bad {
178 bad[i] = 0xFF
179 }
180 var e ff.Fp
181 _ = e.Random(rand.Reader)
182 good, err := e.MarshalBinary()
183 test.CheckNoErr(t, err, mustOk)
184
185
186 b := append(bad, good...)
187 b[0] = b[0]&0x1F | headerEncoding(0, 0, 0)
188 test.CheckIsErr(t, new(G1).SetBytes(b), mustErr)
189
190
191 b = append(good, bad...)
192 b[0] = b[0]&0x1F | headerEncoding(0, 0, 0)
193 test.CheckIsErr(t, new(G1).SetBytes(b), mustErr)
194 })
195 t.Run("noQR", func(t *testing.T) {
196 var x ff.Fp
197 x.SetUint64(1)
198 b, err := x.MarshalBinary()
199 test.CheckNoErr(t, err, mustOk)
200 b[0] = b[0]&0x1F | headerEncoding(1, 0, 0)
201 test.CheckIsErr(t, new(G1).SetBytes(b), mustErr)
202 })
203 t.Run("notInG1", func(t *testing.T) {
204
205 var x, y ff.Fp
206 y.SetUint64(1)
207 bx, err := x.MarshalBinary()
208 test.CheckNoErr(t, err, mustOk)
209 by, err := y.MarshalBinary()
210 test.CheckNoErr(t, err, mustOk)
211 b := append(bx, by...)
212 b[0] = b[0]&0x1F | headerEncoding(0, 0, 0)
213 test.CheckIsErr(t, new(G1).SetBytes(b), mustErr)
214 })
215 }
216
217 func TestG1Affinize(t *testing.T) {
218 N := 20
219 testTimes := 1 << 6
220 g1 := make([]*G1, N)
221 g2 := make([]*G1, N)
222 for i := 0; i < testTimes; i++ {
223 for j := 0; j < N; j++ {
224 g1[j] = randomG1(t)
225 g2[j] = &G1{}
226 *g2[j] = *g1[j]
227 }
228 affinize(g2)
229 for j := 0; j < N; j++ {
230 g1[j].toAffine()
231 if !g1[j].IsEqual(g2[j]) {
232 t.Fatal("failure to preserve points")
233 }
234 if g2[j].z.IsEqual(&g1[j].z) != 1 {
235 t.Fatal("failure to make affine")
236 }
237 }
238 }
239 }
240
241 func TestG1Torsion(t *testing.T) {
242 if !G1Generator().isRTorsion() {
243 t.Fatalf("G1 generator is not r-torsion")
244 }
245 }
246
247 func TestG1Bytes(t *testing.T) {
248 got := new(G1)
249 id := new(G1)
250 id.SetIdentity()
251 g := G1Generator()
252 minusG := G1Generator()
253 minusG.Neg()
254
255 type testCase struct {
256 header byte
257 length int
258 point *G1
259 toBytes func(G1) []byte
260 }
261
262 for i, v := range []testCase{
263 {headerEncoding(0, 0, 0), G1Size, randomG1(t), (G1).Bytes},
264 {headerEncoding(0, 0, 0), G1Size, g, (G1).Bytes},
265 {headerEncoding(1, 0, 0), G1SizeCompressed, g, (G1).BytesCompressed},
266 {headerEncoding(1, 0, 1), G1SizeCompressed, minusG, (G1).BytesCompressed},
267 {headerEncoding(0, 1, 0), G1Size, id, (G1).Bytes},
268 {headerEncoding(1, 1, 0), G1SizeCompressed, id, (G1).BytesCompressed},
269 } {
270 b := v.toBytes(*v.point)
271 test.CheckOk(len(b) == v.length, fmt.Sprintf("bad encoding size (case:%v point:%v b:%x)", i, v.point, b), t)
272 test.CheckOk(b[0]&0xE0 == v.header, fmt.Sprintf("bad encoding header (case:%v point:%v b:%x)", i, v.point, b), t)
273
274 err := got.SetBytes(b)
275 want := v.point
276 if err != nil || !got.IsEqual(want) {
277 test.ReportError(t, got, want, i, b)
278 }
279 }
280 }
281
View as plain text