github.com/cloudflare/circl@v1.5.0/ecc/bls12381/g2_test.go (about) 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("badPrefix", func(t *testing.T) { 106 q := new(G2) 107 b := make([]byte, G2Size) 108 for _, b[0] = range []byte{0x20, 0x60, 0xE0} { 109 test.CheckIsErr(t, q.SetBytes(b), mustErr) 110 } 111 }) 112 t.Run("badLength", func(t *testing.T) { 113 q := new(G2) 114 p := randomG2(t) 115 b := p.Bytes() 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[:G2Size-1]), mustErr) 119 test.CheckIsErr(t, q.SetBytes(b[:G2SizeCompressed]), mustErr) 120 test.CheckNoErr(t, q.SetBytes(b), mustOk) 121 test.CheckNoErr(t, q.SetBytes(append(b, 0)), mustOk) 122 b = p.BytesCompressed() 123 test.CheckIsErr(t, q.SetBytes(b[:0]), mustErr) 124 test.CheckIsErr(t, q.SetBytes(b[:1]), mustErr) 125 test.CheckIsErr(t, q.SetBytes(b[:G2SizeCompressed-1]), mustErr) 126 test.CheckNoErr(t, q.SetBytes(b), mustOk) 127 test.CheckNoErr(t, q.SetBytes(append(b, 0)), mustOk) 128 }) 129 t.Run("badInfinity", func(t *testing.T) { 130 var badInf, p G2 131 badInf.SetIdentity() 132 b := badInf.Bytes() 133 b[0] |= 0x1F 134 err := p.SetBytes(b) 135 test.CheckIsErr(t, err, mustErr) 136 b[0] &= 0xE0 137 b[1] = 0xFF 138 err = p.SetBytes(b) 139 test.CheckIsErr(t, err, mustErr) 140 }) 141 t.Run("badCoords", func(t *testing.T) { 142 bad := (&[ff.Fp2Size]byte{})[:] 143 for i := range bad { 144 bad[i] = 0xFF 145 } 146 var e ff.Fp2 147 _ = e[0].Random(rand.Reader) 148 _ = e[1].Random(rand.Reader) 149 good, err := e.MarshalBinary() 150 test.CheckNoErr(t, err, mustOk) 151 152 // bad x, good y 153 b := append(bad, good...) 154 b[0] = b[0]&0x1F | headerEncoding(0, 0, 0) 155 test.CheckIsErr(t, new(G2).SetBytes(b), mustErr) 156 157 // good x, bad y 158 b = append(good, bad...) 159 b[0] = b[0]&0x1F | headerEncoding(0, 0, 0) 160 test.CheckIsErr(t, new(G2).SetBytes(b), mustErr) 161 }) 162 t.Run("noQR", func(t *testing.T) { 163 var x ff.Fp2 164 // Let x=0, so x^3+4*(u+1) = 4*(u+1), which is not QR because (u+1) is not. 165 b, err := x.MarshalBinary() 166 test.CheckNoErr(t, err, mustOk) 167 b[0] = b[0]&0x1F | headerEncoding(1, 0, 0) 168 test.CheckIsErr(t, new(G2).SetBytes(b), mustErr) 169 }) 170 t.Run("notInG2", func(t *testing.T) { 171 // p=(0,1) is not on curve. 172 var x, y ff.Fp2 173 y[0].SetUint64(1) 174 bx, err := x.MarshalBinary() 175 test.CheckNoErr(t, err, mustOk) 176 by, err := y.MarshalBinary() 177 test.CheckNoErr(t, err, mustOk) 178 b := append(bx, by...) 179 b[0] = b[0]&0x1F | headerEncoding(0, 0, 0) 180 test.CheckIsErr(t, new(G2).SetBytes(b), mustErr) 181 }) 182 } 183 184 func BenchmarkG2(b *testing.B) { 185 P := randomG2(b) 186 Q := randomG2(b) 187 k := randomScalar(b) 188 var msg, dst [4]byte 189 _, _ = rand.Read(msg[:]) 190 _, _ = rand.Read(dst[:]) 191 192 b.Run("Add", func(b *testing.B) { 193 for i := 0; i < b.N; i++ { 194 P.Add(P, Q) 195 } 196 }) 197 b.Run("Mul", func(b *testing.B) { 198 for i := 0; i < b.N; i++ { 199 P.ScalarMult(k, P) 200 } 201 }) 202 b.Run("Hash", func(b *testing.B) { 203 for i := 0; i < b.N; i++ { 204 P.Hash(msg[:], dst[:]) 205 } 206 }) 207 } 208 209 func TestG2Torsion(t *testing.T) { 210 if !G2Generator().isRTorsion() { 211 t.Fatalf("G2 generator is not r-torsion") 212 } 213 } 214 215 func TestG2Bytes(t *testing.T) { 216 got := new(G2) 217 id := new(G2) 218 id.SetIdentity() 219 g := G2Generator() 220 minusG := G2Generator() 221 minusG.Neg() 222 223 type testCase struct { 224 header byte 225 length int 226 point *G2 227 toBytes func(G2) []byte 228 } 229 230 for i, v := range []testCase{ 231 {headerEncoding(0, 0, 0), G2Size, randomG2(t), (G2).Bytes}, 232 {headerEncoding(0, 0, 0), G2Size, g, (G2).Bytes}, 233 {headerEncoding(1, 0, 0), G2SizeCompressed, g, (G2).BytesCompressed}, 234 {headerEncoding(1, 0, 1), G2SizeCompressed, minusG, (G2).BytesCompressed}, 235 {headerEncoding(0, 1, 0), G2Size, id, (G2).Bytes}, 236 {headerEncoding(1, 1, 0), G2SizeCompressed, id, (G2).BytesCompressed}, 237 } { 238 b := v.toBytes(*v.point) 239 test.CheckOk(len(b) == v.length, fmt.Sprintf("bad encoding size (case:%v point:%v b:%x)", i, v.point, b), t) 240 test.CheckOk(b[0]&0xE0 == v.header, fmt.Sprintf("bad encoding header (case:%v point:%v b:%x)", i, v.point, b), t) 241 242 err := got.SetBytes(b) 243 want := v.point 244 if err != nil || !got.IsEqual(want) { 245 test.ReportError(t, got, want, i, b) 246 } 247 } 248 }