|
| 1 | +package bls12381 |
| 2 | + |
| 3 | +import ( |
| 4 | + "bytes" |
| 5 | + "crypto/cipher" |
| 6 | + "testing" |
| 7 | + |
| 8 | + "github.com/corestario/kyber" |
| 9 | + "github.com/corestario/kyber/util/random" |
| 10 | + "github.com/stretchr/testify/require" |
| 11 | +) |
| 12 | + |
| 13 | +// Code extracted from kyber/utils/test |
| 14 | +// TODO: expose API in forked drand/kyber |
| 15 | +// Apply a generic set of validation tests to a cryptographic Group, |
| 16 | +// using a given source of [pseudo-]randomness. |
| 17 | +// |
| 18 | +// Returns a log of the pseudorandom Points produced in the test, |
| 19 | +// for comparison across alternative implementations |
| 20 | +// that are supposed to be equivalent. |
| 21 | +func testGroup(t *testing.T, g kyber.Group, rand cipher.Stream) []kyber.Point { |
| 22 | + t.Logf("\nTesting group '%s': %d-byte Point, %d-byte Scalar\n", |
| 23 | + g.String(), g.PointLen(), g.ScalarLen()) |
| 24 | + |
| 25 | + points := make([]kyber.Point, 0) |
| 26 | + ptmp := g.Point() |
| 27 | + stmp := g.Scalar() |
| 28 | + pzero := g.Point().Null() |
| 29 | + szero := g.Scalar().Zero() |
| 30 | + sone := g.Scalar().One() |
| 31 | + |
| 32 | + // Do a simple Diffie-Hellman test |
| 33 | + s1 := g.Scalar().Pick(rand) |
| 34 | + s2 := g.Scalar().Pick(rand) |
| 35 | + if s1.Equal(szero) { |
| 36 | + t.Fatalf("first secret is scalar zero %v", s1) |
| 37 | + } |
| 38 | + if s2.Equal(szero) { |
| 39 | + t.Fatalf("second secret is scalar zero %v", s2) |
| 40 | + } |
| 41 | + if s1.Equal(s2) { |
| 42 | + t.Fatalf("not getting unique secrets: picked %s twice", s1) |
| 43 | + } |
| 44 | + |
| 45 | + gen := g.Point().Base() |
| 46 | + points = append(points, gen) |
| 47 | + |
| 48 | + // Sanity-check relationship between addition and multiplication |
| 49 | + p1 := g.Point().Add(gen, gen) |
| 50 | + p2 := g.Point().Mul(stmp.SetInt64(2), nil) |
| 51 | + if !p1.Equal(p2) { |
| 52 | + t.Fatalf("multiply by two doesn't work: %v == %v (+) %[2]v != %[2]v (x) 2 == %v", p1, gen, p2) |
| 53 | + } |
| 54 | + p1.Add(p1, p1) |
| 55 | + p2.Mul(stmp.SetInt64(4), nil) |
| 56 | + if !p1.Equal(p2) { |
| 57 | + t.Fatalf("multiply by four doesn't work: %v (+) %[1]v != %v (x) 4 == %v", |
| 58 | + g.Point().Add(gen, gen), gen, p2) |
| 59 | + } |
| 60 | + points = append(points, p1) |
| 61 | + |
| 62 | + // Find out if this curve has a prime order: |
| 63 | + // if the curve does not offer a method IsPrimeOrder, |
| 64 | + // then assume that it is. |
| 65 | + type canCheckPrimeOrder interface { |
| 66 | + IsPrimeOrder() bool |
| 67 | + } |
| 68 | + primeOrder := true |
| 69 | + if gpo, ok := g.(canCheckPrimeOrder); ok { |
| 70 | + primeOrder = gpo.IsPrimeOrder() |
| 71 | + } |
| 72 | + |
| 73 | + // Verify additive and multiplicative identities of the generator. |
| 74 | + ptmp.Mul(stmp.SetInt64(-1), nil).Add(ptmp, gen) |
| 75 | + if !ptmp.Equal(pzero) { |
| 76 | + t.Fatalf("generator additive identity doesn't work: (scalar -1 %v) %v (x) -1 (+) %v = %v != %v the group point identity", |
| 77 | + stmp.SetInt64(-1), ptmp.Mul(stmp.SetInt64(-1), nil), gen, ptmp.Mul(stmp.SetInt64(-1), nil).Add(ptmp, gen), pzero) |
| 78 | + } |
| 79 | + // secret.Inv works only in prime-order groups |
| 80 | + if primeOrder { |
| 81 | + ptmp.Mul(stmp.SetInt64(2), nil).Mul(stmp.Inv(stmp), ptmp) |
| 82 | + if !ptmp.Equal(gen) { |
| 83 | + t.Fatalf("generator multiplicative identity doesn't work:\n%v (x) %v = %v\n%[3]v (x) %v = %v", |
| 84 | + ptmp.Base().String(), stmp.SetInt64(2).String(), |
| 85 | + ptmp.Mul(stmp.SetInt64(2), nil).String(), |
| 86 | + stmp.Inv(stmp).String(), |
| 87 | + ptmp.Mul(stmp.SetInt64(2), nil).Mul(stmp.Inv(stmp), ptmp).String()) |
| 88 | + } |
| 89 | + } |
| 90 | + |
| 91 | + p1.Mul(s1, gen) |
| 92 | + p2.Mul(s2, gen) |
| 93 | + if p1.Equal(p2) { |
| 94 | + t.Fatalf("encryption isn't producing unique points: %v (x) %v == %v (x) %[2]v == %[4]v", s1, gen, s2, p1) |
| 95 | + } |
| 96 | + points = append(points, p1) |
| 97 | + |
| 98 | + dh1 := g.Point().Mul(s2, p1) |
| 99 | + dh2 := g.Point().Mul(s1, p2) |
| 100 | + if !dh1.Equal(dh2) { |
| 101 | + t.Fatalf("Diffie-Hellman didn't work: %v == %v (x) %v != %v (x) %v == %v", dh1, s2, p1, s1, p2, dh2) |
| 102 | + } |
| 103 | + points = append(points, dh1) |
| 104 | + |
| 105 | + // Test secret inverse to get from dh1 back to p1 |
| 106 | + if primeOrder { |
| 107 | + ptmp.Mul(g.Scalar().Inv(s2), dh1) |
| 108 | + if !ptmp.Equal(p1) { |
| 109 | + t.Fatalf("Scalar inverse didn't work: %v != (-)%v (x) %v == %v", p1, s2, dh1, ptmp) |
| 110 | + } |
| 111 | + } |
| 112 | + |
| 113 | + // Zero and One identity secrets |
| 114 | + if !ptmp.Mul(szero, dh1).Equal(pzero) { |
| 115 | + t.Fatalf("Encryption with secret=0 didn't work: %v (x) %v == %v != %v", szero, dh1, ptmp, pzero) |
| 116 | + } |
| 117 | + if !ptmp.Mul(sone, dh1).Equal(dh1) { |
| 118 | + t.Fatalf("Encryption with secret=1 didn't work: %v (x) %v == %v != %[2]v", sone, dh1, ptmp) |
| 119 | + } |
| 120 | + |
| 121 | + // Additive homomorphic identities |
| 122 | + ptmp.Add(p1, p2) |
| 123 | + stmp.Add(s1, s2) |
| 124 | + pt2 := g.Point().Mul(stmp, gen) |
| 125 | + if !pt2.Equal(ptmp) { |
| 126 | + t.Fatalf("Additive homomorphism doesn't work: %v + %v == %v, %[3]v (x) %v == %v != %v == %v (+) %v", |
| 127 | + s1, s2, stmp, gen, pt2, ptmp, p1, p2) |
| 128 | + } |
| 129 | + ptmp.Sub(p1, p2) |
| 130 | + stmp.Sub(s1, s2) |
| 131 | + pt2.Mul(stmp, gen) |
| 132 | + if !pt2.Equal(ptmp) { |
| 133 | + t.Fatalf("Additive homomorphism doesn't work: %v - %v == %v, %[3]v (x) %v == %v != %v == %v (-) %v", |
| 134 | + s1, s2, stmp, gen, pt2, ptmp, p1, p2) |
| 135 | + } |
| 136 | + st2 := g.Scalar().Neg(s2) |
| 137 | + st2.Add(s1, st2) |
| 138 | + if !stmp.Equal(st2) { |
| 139 | + t.Fatalf("Scalar.Neg doesn't work: -%v == %v, %[2]v + %v == %v != %v", |
| 140 | + s2, g.Scalar().Neg(s2), s1, st2, stmp) |
| 141 | + } |
| 142 | + pt2.Neg(p2).Add(pt2, p1) |
| 143 | + if !pt2.Equal(ptmp) { |
| 144 | + t.Fatalf("Point.Neg doesn't work: (-)%v == %v, %[2]v (+) %v == %v != %v", |
| 145 | + p2, g.Point().Neg(p2), p1, pt2, ptmp) |
| 146 | + } |
| 147 | + |
| 148 | + // Multiplicative homomorphic identities |
| 149 | + stmp.Mul(s1, s2) |
| 150 | + if !ptmp.Mul(stmp, gen).Equal(dh1) { |
| 151 | + t.Fatalf("Multiplicative homomorphism doesn't work: %v * %v == %v, %[2]v (x) %v == %v != %v", |
| 152 | + s1, s2, stmp, gen, ptmp, dh1) |
| 153 | + } |
| 154 | + if primeOrder { |
| 155 | + st2.Inv(s2) |
| 156 | + st2.Mul(st2, stmp) |
| 157 | + if !st2.Equal(s1) { |
| 158 | + t.Fatalf("Scalar division doesn't work: %v^-1 * %v == %v * %[2]v == %[4]v != %v", |
| 159 | + s2, stmp, g.Scalar().Inv(s2), st2, s1) |
| 160 | + } |
| 161 | + st2.Div(stmp, s2) |
| 162 | + if !st2.Equal(s1) { |
| 163 | + t.Fatalf("Scalar division doesn't work: %v / %v == %v != %v", |
| 164 | + stmp, s2, st2, s1) |
| 165 | + } |
| 166 | + } |
| 167 | + |
| 168 | + // Test randomly picked points |
| 169 | + last := gen |
| 170 | + for i := 0; i < 5; i++ { |
| 171 | + rgen := g.Point().Pick(rand) |
| 172 | + if rgen.Equal(last) { |
| 173 | + t.Fatalf("Pick() not producing unique points: got %v twice", rgen) |
| 174 | + } |
| 175 | + last = rgen |
| 176 | + |
| 177 | + ptmp.Mul(stmp.SetInt64(-1), rgen).Add(ptmp, rgen) |
| 178 | + if !ptmp.Equal(pzero) { |
| 179 | + t.Fatalf("random generator fails additive identity: %v (x) %v == %v, %v (+) %[3]v == %[5]v != %v", |
| 180 | + g.Scalar().SetInt64(-1), rgen, g.Point().Mul(g.Scalar().SetInt64(-1), rgen), |
| 181 | + rgen, g.Point().Mul(g.Scalar().SetInt64(-1), rgen), pzero) |
| 182 | + } |
| 183 | + if primeOrder { |
| 184 | + ptmp.Mul(stmp.SetInt64(2), rgen).Mul(stmp.Inv(stmp), ptmp) |
| 185 | + if !ptmp.Equal(rgen) { |
| 186 | + t.Fatalf("random generator fails multiplicative identity: %v (x) (2 (x) %v) == %v != %[2]v", |
| 187 | + stmp, rgen, ptmp) |
| 188 | + } |
| 189 | + } |
| 190 | + points = append(points, rgen) |
| 191 | + } |
| 192 | + |
| 193 | + // Test encoding and decoding |
| 194 | + buf := new(bytes.Buffer) |
| 195 | + for i := 0; i < 5; i++ { |
| 196 | + buf.Reset() |
| 197 | + s := g.Scalar().Pick(rand) |
| 198 | + if _, err := s.MarshalTo(buf); err != nil { |
| 199 | + t.Fatalf("encoding of secret fails: " + err.Error()) |
| 200 | + } |
| 201 | + if _, err := stmp.UnmarshalFrom(buf); err != nil { |
| 202 | + t.Fatalf("decoding of secret fails: " + err.Error()) |
| 203 | + } |
| 204 | + if !stmp.Equal(s) { |
| 205 | + t.Fatalf("decoding produces different secret than encoded") |
| 206 | + } |
| 207 | + |
| 208 | + buf.Reset() |
| 209 | + p := g.Point().Pick(rand) |
| 210 | + if _, err := p.MarshalTo(buf); err != nil { |
| 211 | + t.Fatalf("encoding of point fails: " + err.Error()) |
| 212 | + } |
| 213 | + if _, err := ptmp.UnmarshalFrom(buf); err != nil { |
| 214 | + t.Fatalf("decoding of point fails: " + err.Error()) |
| 215 | + } |
| 216 | + |
| 217 | + if !ptmp.Equal(p) { |
| 218 | + t.Fatalf("decoding produces different point than encoded") |
| 219 | + } |
| 220 | + } |
| 221 | + |
| 222 | + // Test that we can marshal/ unmarshal null point |
| 223 | + pzero = g.Point().Null() |
| 224 | + b, _ := pzero.MarshalBinary() |
| 225 | + repzero := g.Point() |
| 226 | + err := repzero.UnmarshalBinary(b) |
| 227 | + if err != nil { |
| 228 | + t.Fatalf("Could not unmarshall binary %v: %v", b, err) |
| 229 | + } |
| 230 | + |
| 231 | + return points |
| 232 | +} |
| 233 | + |
| 234 | +// GroupTest applies a generic set of validation tests to a cryptographic Group. |
| 235 | +func GroupTest(t *testing.T, g kyber.Group) { |
| 236 | + testGroup(t, g, random.New()) |
| 237 | +} |
| 238 | + |
| 239 | +func TestKyberG1(t *testing.T) { |
| 240 | + GroupTest(t, NewGroupG1()) |
| 241 | +} |
| 242 | + |
| 243 | +func TestKyberG2(t *testing.T) { |
| 244 | + GroupTest(t, NewGroupG2()) |
| 245 | +} |
| 246 | + |
| 247 | +func TestKyberGT(t *testing.T) { |
| 248 | + GroupTest(t, NewGroupGT()) |
| 249 | +} |
| 250 | + |
| 251 | +func TestKyberPairingG2(t *testing.T) { |
| 252 | + s := NewBLS12381Suite().(*Suite) |
| 253 | + a := s.G1().Scalar().Pick(s.RandomStream()) |
| 254 | + b := s.G2().Scalar().Pick(s.RandomStream()) |
| 255 | + aG := s.G1().Point().Mul(a, nil) |
| 256 | + bH := s.G2().Point().Mul(b, nil) |
| 257 | + ab := s.G1().Scalar().Mul(a, b) |
| 258 | + abG := s.G1().Point().Mul(ab, nil) |
| 259 | + // e(aG, bG) = e(G,H)^(ab) |
| 260 | + p1 := s.Pair(aG, bH) |
| 261 | + // e((ab)G,H) = e(G,H)^(ab) |
| 262 | + p2 := s.Pair(abG, s.G2().Point().Base()) |
| 263 | + require.True(t, p1.Equal(p2)) |
| 264 | + require.True(t, s.ValidatePairing(aG, bH, abG.Clone(), s.G2().Point().Base())) |
| 265 | + |
| 266 | + pRandom := s.Pair(aG, s.G2().Point().Pick(s.RandomStream())) |
| 267 | + require.False(t, p1.Equal(pRandom)) |
| 268 | + pRandom = s.Pair(s.G1().Point().Pick(s.RandomStream()), bH) |
| 269 | + require.False(t, p1.Equal(pRandom)) |
| 270 | +} |
| 271 | + |
| 272 | +func BenchmarkPairingSeparate(bb *testing.B) { |
| 273 | + s := NewBLS12381Suite().(*Suite) |
| 274 | + a := s.G1().Scalar().Pick(s.RandomStream()) |
| 275 | + b := s.G2().Scalar().Pick(s.RandomStream()) |
| 276 | + aG := s.G1().Point().Mul(a, nil) |
| 277 | + bH := s.G2().Point().Mul(b, nil) |
| 278 | + ab := s.G1().Scalar().Mul(a, b) |
| 279 | + abG := s.G1().Point().Mul(ab, nil) |
| 280 | + bb.ResetTimer() |
| 281 | + for i := 0; i < bb.N; i++ { |
| 282 | + |
| 283 | + // e(aG, bG) = e(G,H)^(ab) |
| 284 | + p1 := s.Pair(aG, bH) |
| 285 | + // e((ab)G,H) = e(G,H)^(ab) |
| 286 | + p2 := s.Pair(abG, s.G2().Point().Base()) |
| 287 | + if !p1.Equal(p2) { |
| 288 | + panic("aie") |
| 289 | + } |
| 290 | + } |
| 291 | +} |
| 292 | + |
| 293 | +func BenchmarkPairingInv(bb *testing.B) { |
| 294 | + s := NewBLS12381Suite().(*Suite) |
| 295 | + a := s.G1().Scalar().Pick(s.RandomStream()) |
| 296 | + b := s.G2().Scalar().Pick(s.RandomStream()) |
| 297 | + aG := s.G1().Point().Mul(a, nil) |
| 298 | + bH := s.G2().Point().Mul(b, nil) |
| 299 | + ab := s.G1().Scalar().Mul(a, b) |
| 300 | + abG := s.G1().Point().Mul(ab, nil) |
| 301 | + bb.ResetTimer() |
| 302 | + for i := 0; i < bb.N; i++ { |
| 303 | + if !s.ValidatePairing(aG, bH, abG.Clone(), s.G2().Point().Base()) { |
| 304 | + panic("aie") |
| 305 | + } |
| 306 | + } |
| 307 | +} |
| 308 | + |
| 309 | +func TestIsValidGroup(t *testing.T) { |
| 310 | + suite := NewBLS12381Suite() |
| 311 | + p1 := suite.G1().Point().Pick(random.New()) |
| 312 | + p2 := suite.G1().Point().Pick(random.New()) |
| 313 | + |
| 314 | + require.True(t, p1.(GroupChecker).IsInCorrectGroup()) |
| 315 | + require.True(t, p2.(GroupChecker).IsInCorrectGroup()) |
| 316 | +} |
0 commit comments