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 randomG2(t testing.TB) *G2 {
13 var P G2
14 k := randomScalar(t)
15 P.ScalarMult(k, G2Generator())
16 if !P.isOnCurve() {
17 t.Helper()
18 t.Fatal("not on curve")
19 }
20 return &P
21 }
22
23 func TestG2Add(t *testing.T) {
24 const testTimes = 1 << 6
25 var Q, R G2
26 for i := 0; i < testTimes; i++ {
27 P := randomG2(t)
28 Q = *P
29 R = *P
30 R.Add(&R, &R)
31 R.Neg()
32 Q.Double()
33 Q.Neg()
34 got := R
35 want := Q
36 if !got.IsEqual(&want) {
37 test.ReportError(t, got, want, P)
38 }
39 }
40 }
41
42 func TestG2ScalarMult(t *testing.T) {
43 const testTimes = 1 << 6
44 var Q G2
45 for i := 0; i < testTimes; i++ {
46 P := randomG2(t)
47 k := randomScalar(t)
48 Q.ScalarMult(k, P)
49 Q.toAffine()
50 got := Q.IsOnG2()
51 want := true
52 if got != want {
53 test.ReportError(t, got, want, P)
54 }
55 }
56 }
57
58 func TestG2Hash(t *testing.T) {
59 const testTimes = 1 << 8
60
61 for _, e := range [...]struct {
62 Name string
63 Enc func(p *G2, input, dst []byte)
64 }{
65 {"Encode", func(p *G2, input, dst []byte) { p.Encode(input, dst) }},
66 {"Hash", func(p *G2, input, dst []byte) { p.Hash(input, dst) }},
67 } {
68 var msg, dst [4]byte
69 var p G2
70 t.Run(e.Name, func(t *testing.T) {
71 for i := 0; i < testTimes; i++ {
72 _, _ = rand.Read(msg[:])
73 _, _ = rand.Read(dst[:])
74 e.Enc(&p, msg[:], dst[:])
75
76 got := p.isRTorsion()
77 want := true
78 if got != want {
79 test.ReportError(t, got, want, e.Name, msg, dst)
80 }
81 }
82 })
83 }
84 }
85
86 func TestG2Serial(t *testing.T) {
87 mustOk := "must be ok"
88 mustErr := "must be an error"
89 t.Run("valid", func(t *testing.T) {
90 testTimes := 1 << 6
91 var got, want G2
92 want.SetIdentity()
93 for i := 0; i < testTimes; i++ {
94 for _, b := range [][]byte{want.Bytes(), want.BytesCompressed()} {
95 err := got.SetBytes(b)
96 test.CheckNoErr(t, err, fmt.Sprintf("failure to deserialize: (P:%v b:%x)", want, b))
97
98 if !got.IsEqual(&want) {
99 test.ReportError(t, got, want, b)
100 }
101 }
102 want = *randomG2(t)
103 }
104 })
105 t.Run("badLength", func(t *testing.T) {
106 q := new(G2)
107 p := randomG2(t)
108 b := p.Bytes()
109 test.CheckIsErr(t, q.SetBytes(b[:0]), mustErr)
110 test.CheckIsErr(t, q.SetBytes(b[:1]), mustErr)
111 test.CheckIsErr(t, q.SetBytes(b[:G2Size-1]), mustErr)
112 test.CheckIsErr(t, q.SetBytes(b[:G2SizeCompressed]), mustErr)
113 test.CheckNoErr(t, q.SetBytes(b), mustOk)
114 test.CheckNoErr(t, q.SetBytes(append(b, 0)), mustOk)
115 b = p.BytesCompressed()
116 test.CheckIsErr(t, q.SetBytes(b[:0]), mustErr)
117 test.CheckIsErr(t, q.SetBytes(b[:1]), mustErr)
118 test.CheckIsErr(t, q.SetBytes(b[:G2SizeCompressed-1]), mustErr)
119 test.CheckNoErr(t, q.SetBytes(b), mustOk)
120 test.CheckNoErr(t, q.SetBytes(append(b, 0)), mustOk)
121 })
122 t.Run("badInfinity", func(t *testing.T) {
123 var badInf, p G2
124 badInf.SetIdentity()
125 b := badInf.Bytes()
126 b[0] |= 0x1F
127 err := p.SetBytes(b)
128 test.CheckIsErr(t, err, mustErr)
129 b[0] &= 0xE0
130 b[1] = 0xFF
131 err = p.SetBytes(b)
132 test.CheckIsErr(t, err, mustErr)
133 })
134 t.Run("badCoords", func(t *testing.T) {
135 bad := (&[ff.Fp2Size]byte{})[:]
136 for i := range bad {
137 bad[i] = 0xFF
138 }
139 var e ff.Fp2
140 _ = e[0].Random(rand.Reader)
141 _ = e[1].Random(rand.Reader)
142 good, err := e.MarshalBinary()
143 test.CheckNoErr(t, err, mustOk)
144
145
146 b := append(bad, good...)
147 b[0] = b[0]&0x1F | headerEncoding(0, 0, 0)
148 test.CheckIsErr(t, new(G2).SetBytes(b), mustErr)
149
150
151 b = append(good, bad...)
152 b[0] = b[0]&0x1F | headerEncoding(0, 0, 0)
153 test.CheckIsErr(t, new(G2).SetBytes(b), mustErr)
154 })
155 t.Run("noQR", func(t *testing.T) {
156 var x ff.Fp2
157
158 b, err := x.MarshalBinary()
159 test.CheckNoErr(t, err, mustOk)
160 b[0] = b[0]&0x1F | headerEncoding(1, 0, 0)
161 test.CheckIsErr(t, new(G2).SetBytes(b), mustErr)
162 })
163 t.Run("notInG2", func(t *testing.T) {
164
165 var x, y ff.Fp2
166 y[0].SetUint64(1)
167 bx, err := x.MarshalBinary()
168 test.CheckNoErr(t, err, mustOk)
169 by, err := y.MarshalBinary()
170 test.CheckNoErr(t, err, mustOk)
171 b := append(bx, by...)
172 b[0] = b[0]&0x1F | headerEncoding(0, 0, 0)
173 test.CheckIsErr(t, new(G2).SetBytes(b), mustErr)
174 })
175 }
176
177 func BenchmarkG2(b *testing.B) {
178 P := randomG2(b)
179 Q := randomG2(b)
180 k := randomScalar(b)
181 var msg, dst [4]byte
182 _, _ = rand.Read(msg[:])
183 _, _ = rand.Read(dst[:])
184
185 b.Run("Add", func(b *testing.B) {
186 for i := 0; i < b.N; i++ {
187 P.Add(P, Q)
188 }
189 })
190 b.Run("Mul", func(b *testing.B) {
191 for i := 0; i < b.N; i++ {
192 P.ScalarMult(k, P)
193 }
194 })
195 b.Run("Hash", func(b *testing.B) {
196 for i := 0; i < b.N; i++ {
197 P.Hash(msg[:], dst[:])
198 }
199 })
200 }
201
202 func TestG2Torsion(t *testing.T) {
203 if !G2Generator().isRTorsion() {
204 t.Fatalf("G2 generator is not r-torsion")
205 }
206 }
207
208 func TestG2Bytes(t *testing.T) {
209 got := new(G2)
210 id := new(G2)
211 id.SetIdentity()
212 g := G2Generator()
213 minusG := G2Generator()
214 minusG.Neg()
215
216 type testCase struct {
217 header byte
218 length int
219 point *G2
220 toBytes func(G2) []byte
221 }
222
223 for i, v := range []testCase{
224 {headerEncoding(0, 0, 0), G2Size, randomG2(t), (G2).Bytes},
225 {headerEncoding(0, 0, 0), G2Size, g, (G2).Bytes},
226 {headerEncoding(1, 0, 0), G2SizeCompressed, g, (G2).BytesCompressed},
227 {headerEncoding(1, 0, 1), G2SizeCompressed, minusG, (G2).BytesCompressed},
228 {headerEncoding(0, 1, 0), G2Size, id, (G2).Bytes},
229 {headerEncoding(1, 1, 0), G2SizeCompressed, id, (G2).BytesCompressed},
230 } {
231 b := v.toBytes(*v.point)
232 test.CheckOk(len(b) == v.length, fmt.Sprintf("bad encoding size (case:%v point:%v b:%x)", i, v.point, b), t)
233 test.CheckOk(b[0]&0xE0 == v.header, fmt.Sprintf("bad encoding header (case:%v point:%v b:%x)", i, v.point, b), t)
234
235 err := got.SetBytes(b)
236 want := v.point
237 if err != nil || !got.IsEqual(want) {
238 test.ReportError(t, got, want, i, b)
239 }
240 }
241 }
242
View as plain text