github.com/cloudflare/circl@v1.5.0/ecc/bls12381/g1.go (about) 1 package bls12381 2 3 import ( 4 "crypto" 5 _ "crypto/sha256" 6 "crypto/subtle" 7 "fmt" 8 "math/big" 9 10 "github.com/cloudflare/circl/ecc/bls12381/ff" 11 "github.com/cloudflare/circl/expander" 12 ) 13 14 // G1Size is the length in bytes of an element in G1 in uncompressed form.. 15 const G1Size = 2 * ff.FpSize 16 17 // G1SizeCompressed is the length in bytes of an element in G1 in compressed form. 18 const G1SizeCompressed = ff.FpSize 19 20 // G1 is a point in the BLS12 curve over Fp. 21 type G1 struct{ x, y, z ff.Fp } 22 23 func (g G1) String() string { return fmt.Sprintf("x: %v\ny: %v\nz: %v", g.x, g.y, g.z) } 24 25 // Bytes serializes a G1 element in uncompressed form. 26 func (g G1) Bytes() []byte { return g.encodeBytes(false) } 27 28 // Bytes serializes a G1 element in compressed form. 29 func (g G1) BytesCompressed() []byte { return g.encodeBytes(true) } 30 31 // SetBytes sets g to the value in bytes, and returns a non-nil error if not in G1. 32 func (g *G1) SetBytes(b []byte) error { 33 if len(b) < G1SizeCompressed { 34 return errInputLength 35 } 36 37 // Check for invalid prefixes 38 switch b[0] & 0xE0 { 39 case 0x20, 0x60, 0xE0: 40 return errEncoding 41 } 42 43 isCompressed := int((b[0] >> 7) & 0x1) 44 isInfinity := int((b[0] >> 6) & 0x1) 45 isBigYCoord := int((b[0] >> 5) & 0x1) 46 47 if isInfinity == 1 { 48 l := G1Size 49 if isCompressed == 1 { 50 l = G1SizeCompressed 51 } 52 zeros := make([]byte, l-1) 53 if (b[0]&0x1F) != 0 || subtle.ConstantTimeCompare(b[1:l], zeros) != 1 { 54 return errEncoding 55 } 56 g.SetIdentity() 57 return nil 58 } 59 60 x := (&[ff.FpSize]byte{})[:] 61 copy(x, b) 62 x[0] &= 0x1F 63 if err := g.x.UnmarshalBinary(x); err != nil { 64 return err 65 } 66 67 if isCompressed == 1 { 68 x3b := &ff.Fp{} 69 x3b.Sqr(&g.x) 70 x3b.Mul(x3b, &g.x) 71 x3b.Add(x3b, &g1Params.b) 72 if g.y.Sqrt(x3b) == 0 { 73 return errEncoding 74 } 75 if g.y.IsNegative() != isBigYCoord { 76 g.y.Neg() 77 } 78 } else { 79 if len(b) < G1Size { 80 return errInputLength 81 } 82 if err := g.y.UnmarshalBinary(b[ff.FpSize:G1Size]); err != nil { 83 return err 84 } 85 } 86 87 g.z.SetOne() 88 if !g.IsOnG1() { 89 return errEncoding 90 } 91 return nil 92 } 93 94 func (g G1) encodeBytes(compressed bool) []byte { 95 g.toAffine() 96 97 var isCompressed, isInfinity, isBigYCoord byte 98 if compressed { 99 isCompressed = 1 100 } 101 if g.z.IsZero() == 1 { 102 isInfinity = 1 103 } 104 if isCompressed == 1 && isInfinity == 0 { 105 isBigYCoord = byte(g.y.IsNegative()) 106 } 107 108 bytes, _ := g.x.MarshalBinary() 109 if isCompressed == 0 { 110 yBytes, _ := g.y.MarshalBinary() 111 bytes = append(bytes, yBytes...) 112 } 113 if isInfinity == 1 { 114 l := len(bytes) 115 for i := 0; i < l; i++ { 116 bytes[i] = 0 117 } 118 } 119 120 bytes[0] = bytes[0]&0x1F | headerEncoding(isCompressed, isInfinity, isBigYCoord) 121 122 return bytes 123 } 124 125 // Neg inverts g. 126 func (g *G1) Neg() { g.y.Neg() } 127 128 // SetIdentity assigns g to the identity element. 129 func (g *G1) SetIdentity() { g.x = ff.Fp{}; g.y.SetOne(); g.z = ff.Fp{} } 130 131 // isValidProjective returns true if the point is not a projective point. 132 func (g *G1) isValidProjective() bool { return (g.x.IsZero() & g.y.IsZero() & g.z.IsZero()) != 1 } 133 134 // IsOnG1 returns true if the point is in the group G1. 135 func (g *G1) IsOnG1() bool { return g.isValidProjective() && g.isOnCurve() && g.isRTorsion() } 136 137 // IsIdentity return true if the point is the identity of G1. 138 func (g *G1) IsIdentity() bool { return g.isValidProjective() && (g.z.IsZero() == 1) } 139 140 // cmov sets g to P if b == 1 141 func (g *G1) cmov(P *G1, b int) { 142 (&g.x).CMov(&g.x, &P.x, b) 143 (&g.y).CMov(&g.y, &P.y, b) 144 (&g.z).CMov(&g.z, &P.z, b) 145 } 146 147 // sigma is an edomorphism defined by (x, y) → (βx, y) for some β ∈ Fp of 148 // multiplicative order 3. 149 func (g *G1) sigma(P *G1) { *g = *P; g.x.Mul(&g.x, &g1Sigma.beta0) } 150 151 // sigma2 is sigma(sigma(P)). 152 func (g *G1) sigma2(P *G1) { *g = *P; g.x.Mul(&g.x, &g1Sigma.beta1) } 153 154 // isRTorsion returns true if point is in the r-torsion subgroup. 155 func (g *G1) isRTorsion() bool { 156 // Bowe, "Faster Subgroup Checks for BLS12-381" (https://eprint.iacr.org/2019/814) 157 Q, _2sP, ssP := &G1{}, &G1{}, &G1{} 158 coef := bls12381.g1Check[:] 159 160 _2sP.sigma(g) // s(P) 161 _2sP.Double() // 2*s(P) 162 ssP.sigma2(g) // s(s(P)) 163 Q.Add(g, ssP) // P + s(s(P)) 164 Q.Neg() // -P - s(s(P)) 165 Q.Add(Q, _2sP) // 2*s(P) - P - s(s(P)) 166 Q.scalarMultShort(coef, Q) // coef * [2*s(P) - P - s(s(P))] 167 ssP.Neg() // -s(s(P)) 168 Q.Add(Q, ssP) // coef * [2*s(P) - P - s(s(P))] - s(s(P)) 169 170 return Q.IsIdentity() 171 } 172 173 // clearCofactor maps g to a point in the r-torsion subgroup. 174 // 175 // This method multiplies g times (1-z) rather than (z-1)^2/3, where z is the 176 // BLS12 parameter. This is enough to remove points of order 177 // 178 // h \in {3, 11, 10177, 859267, 52437899}, 179 // 180 // and because there are no points of order h^2. See Section 5 of Wahby-Boneh 181 // "Fast and simple constant-time hashing to the BLS12-381 elliptic curve" at 182 // https://eprint.iacr.org/2019/403 183 func (g *G1) clearCofactor() { g.scalarMultShort(bls12381.oneMinusZ[:], g) } 184 185 // Double updates g = 2g. 186 func (g *G1) Double() { 187 // Reference: 188 // "Complete addition formulas for prime order elliptic curves" by 189 // Costello-Renes-Batina. [Alg.9] (eprint.iacr.org/2015/1060). 190 var R G1 191 X, Y, Z := &g.x, &g.y, &g.z 192 X3, Y3, Z3 := &R.x, &R.y, &R.z 193 var f0, f1, f2 ff.Fp 194 t0, t1, t2 := &f0, &f1, &f2 195 _3B := &g1Params._3b 196 t0.Sqr(Y) // 1. t0 = Y * Y 197 Z3.Add(t0, t0) // 2. Z3 = t0 + t0 198 Z3.Add(Z3, Z3) // 3. Z3 = Z3 + Z3 199 Z3.Add(Z3, Z3) // 4. Z3 = Z3 + Z3 200 t1.Mul(Y, Z) // 5. t1 = Y * Z 201 t2.Sqr(Z) // 6. t2 = Z * Z 202 t2.Mul(_3B, t2) // 7. t2 = b3 * t2 203 X3.Mul(t2, Z3) // 8. X3 = t2 * Z3 204 Y3.Add(t0, t2) // 9. Y3 = t0 + t2 205 Z3.Mul(t1, Z3) // 10. Z3 = t1 * Z3 206 t1.Add(t2, t2) // 11. t1 = t2 + t2 207 t2.Add(t1, t2) // 12. t2 = t1 + t2 208 t0.Sub(t0, t2) // 13. t0 = t0 - t2 209 Y3.Mul(t0, Y3) // 14. Y3 = t0 * Y3 210 Y3.Add(X3, Y3) // 15. Y3 = X3 + Y3 211 t1.Mul(X, Y) // 16. t1 = X * Y 212 X3.Mul(t0, t1) // 17. X3 = t0 * t1 213 X3.Add(X3, X3) // 18. X3 = X3 + X3 214 *g = R 215 } 216 217 // Add updates g=P+Q. 218 func (g *G1) Add(P, Q *G1) { 219 // Reference: 220 // "Complete addition formulas for prime order elliptic curves" by 221 // Costello-Renes-Batina. [Alg.7] (eprint.iacr.org/2015/1060). 222 var R G1 223 X1, Y1, Z1 := &P.x, &P.y, &P.z 224 X2, Y2, Z2 := &Q.x, &Q.y, &Q.z 225 X3, Y3, Z3 := &R.x, &R.y, &R.z 226 _3B := &g1Params._3b 227 var f0, f1, f2, f3, f4 ff.Fp 228 t0, t1, t2, t3, t4 := &f0, &f1, &f2, &f3, &f4 229 t0.Mul(X1, X2) // 1. t0 = X1 * X2 230 t1.Mul(Y1, Y2) // 2. t1 = Y1 * Y2 231 t2.Mul(Z1, Z2) // 3. t2 = Z1 * Z2 232 t3.Add(X1, Y1) // 4. t3 = X1 + Y1 233 t4.Add(X2, Y2) // 5. t4 = X2 + Y2 234 t3.Mul(t3, t4) // 6. t3 = t3 * t4 235 t4.Add(t0, t1) // 7. t4 = t0 + t1 236 t3.Sub(t3, t4) // 8. t3 = t3 - t4 237 t4.Add(Y1, Z1) // 9. t4 = Y1 + Z1 238 X3.Add(Y2, Z2) // 10. X3 = Y2 + Z2 239 t4.Mul(t4, X3) // 11. t4 = t4 * X3 240 X3.Add(t1, t2) // 12. X3 = t1 + t2 241 t4.Sub(t4, X3) // 13. t4 = t4 - X3 242 X3.Add(X1, Z1) // 14. X3 = X1 + Z1 243 Y3.Add(X2, Z2) // 15. Y3 = X2 + Z2 244 X3.Mul(X3, Y3) // 16. X3 = X3 * Y3 245 Y3.Add(t0, t2) // 17. Y3 = t0 + t2 246 Y3.Sub(X3, Y3) // 18. Y3 = X3 - Y3 247 X3.Add(t0, t0) // 19. X3 = t0 + t0 248 t0.Add(X3, t0) // 20. t0 = X3 + t0 249 t2.Mul(_3B, t2) // 21. t2 = b3 * t2 250 Z3.Add(t1, t2) // 22. Z3 = t1 + t2 251 t1.Sub(t1, t2) // 23. t1 = t1 - t2 252 Y3.Mul(_3B, Y3) // 24. Y3 = b3 * Y3 253 X3.Mul(t4, Y3) // 25. X3 = t4 * Y3 254 t2.Mul(t3, t1) // 26. t2 = t3 * t1 255 X3.Sub(t2, X3) // 27. X3 = t2 - X3 256 Y3.Mul(Y3, t0) // 28. Y3 = Y3 * t0 257 t1.Mul(t1, Z3) // 29. t1 = t1 * Z3 258 Y3.Add(t1, Y3) // 30. Y3 = t1 + Y3 259 t0.Mul(t0, t3) // 31. t0 = t0 * t3 260 Z3.Mul(Z3, t4) // 32. Z3 = Z3 * t4 261 Z3.Add(Z3, t0) // 33. Z3 = Z3 + t0 262 *g = R 263 } 264 265 // ScalarMult calculates g = kP. 266 func (g *G1) ScalarMult(k *Scalar, P *G1) { b, _ := k.MarshalBinary(); g.scalarMult(b, P) } 267 268 // scalarMult calculates g = kP, where k is the scalar in big-endian order. 269 func (g *G1) scalarMult(k []byte, P *G1) { 270 var Q G1 271 Q.SetIdentity() 272 T := &G1{} 273 var mults [16]G1 274 mults[0].SetIdentity() 275 mults[1] = *P 276 for i := 1; i < 8; i++ { 277 mults[2*i] = mults[i] 278 mults[2*i].Double() 279 mults[2*i+1].Add(&mults[2*i], P) 280 } 281 N := 8 * len(k) 282 for i := 0; i < N; i += 4 { 283 Q.Double() 284 Q.Double() 285 Q.Double() 286 Q.Double() 287 idx := 0xf & (k[i/8] >> uint(4-i%8)) 288 for j := 0; j < 16; j++ { 289 T.cmov(&mults[j], subtle.ConstantTimeByteEq(idx, uint8(j))) 290 } 291 Q.Add(&Q, T) 292 } 293 *g = Q 294 } 295 296 // scalarMultShort multiplies by a short, constant scalar k, where k is the 297 // scalar in big-endian order. Runtime depends on the scalar. 298 func (g *G1) scalarMultShort(k []byte, P *G1) { 299 // Since the scalar is short and low Hamming weight not much helps. 300 var Q G1 301 Q.SetIdentity() 302 N := 8 * len(k) 303 for i := 0; i < N; i++ { 304 Q.Double() 305 bit := 0x1 & (k[i/8] >> uint(7-i%8)) 306 if bit != 0 { 307 Q.Add(&Q, P) 308 } 309 } 310 *g = Q 311 } 312 313 // IsEqual returns true if g and p are equivalent. 314 func (g *G1) IsEqual(p *G1) bool { 315 var lx, rx, ly, ry ff.Fp 316 lx.Mul(&g.x, &p.z) // lx = x1*z2 317 rx.Mul(&p.x, &g.z) // rx = x2*z1 318 lx.Sub(&lx, &rx) // lx = lx-rx 319 ly.Mul(&g.y, &p.z) // ly = y1*z2 320 ry.Mul(&p.y, &g.z) // ry = y2*z1 321 ly.Sub(&ly, &ry) // ly = ly-ry 322 return g.isValidProjective() && p.isValidProjective() && lx.IsZero() == 1 && ly.IsZero() == 1 323 } 324 325 // isOnCurve returns true if g is a valid point on the curve. 326 func (g *G1) isOnCurve() bool { 327 var x3, z3, y2 ff.Fp 328 y2.Sqr(&g.y) // y2 = y^2 329 y2.Mul(&y2, &g.z) // y2 = y^2*z 330 x3.Sqr(&g.x) // x3 = x^2 331 x3.Mul(&x3, &g.x) // x3 = x^3 332 z3.Sqr(&g.z) // z3 = z^2 333 z3.Mul(&z3, &g.z) // z3 = z^3 334 z3.Mul(&z3, &g1Params.b) // z3 = 4*z^3 335 x3.Add(&x3, &z3) // x3 = x^3 + 4*z^3 336 y2.Sub(&y2, &x3) // y2 = y^2*z - (x^3 + 4*z^3) 337 return y2.IsZero() == 1 338 } 339 340 // toAffine updates g with its affine representation. 341 func (g *G1) toAffine() { 342 if g.z.IsZero() != 1 { 343 var invZ ff.Fp 344 invZ.Inv(&g.z) 345 g.x.Mul(&g.x, &invZ) 346 g.y.Mul(&g.y, &invZ) 347 g.z.SetOne() 348 } 349 } 350 351 // EncodeToCurve is a non-uniform encoding from an input byte string (and 352 // an optional domain separation tag) to elements in G1. This function must not 353 // be used as a hash function, otherwise use G1.Hash instead. 354 func (g *G1) Encode(input, dst []byte) { 355 const L = 64 356 pseudo := expander.NewExpanderMD(crypto.SHA256, dst).Expand(input, L) 357 358 bu := new(big.Int).SetBytes(pseudo) 359 bu.Mod(bu, new(big.Int).SetBytes(ff.FpOrder())) 360 361 var u ff.Fp 362 u.SetBytes(pseudo[:L]) 363 364 var q isogG1Point 365 q.sswu(&u) 366 g.evalIsogG1(&q) 367 g.clearCofactor() 368 } 369 370 // Hash produces an element of G1 from the hash of an input byte string and 371 // an optional domain separation tag. This function is safe to use when a 372 // random oracle returning points in G1 be required. 373 func (g *G1) Hash(input, dst []byte) { 374 const L = 64 375 pseudo := expander.NewExpanderMD(crypto.SHA256, dst).Expand(input, 2*L) 376 377 var u0, u1 ff.Fp 378 u0.SetBytes(pseudo[0*L : 1*L]) 379 u1.SetBytes(pseudo[1*L : 2*L]) 380 381 var q0, q1 isogG1Point 382 q0.sswu(&u0) 383 q1.sswu(&u1) 384 var p0, p1 G1 385 p0.evalIsogG1(&q0) 386 p1.evalIsogG1(&q1) 387 g.Add(&p0, &p1) 388 g.clearCofactor() 389 } 390 391 // G1Generator returns the generator point of G1. 392 func G1Generator() *G1 { 393 var G G1 394 G.x = g1Params.genX 395 G.y = g1Params.genY 396 G.z.SetOne() 397 return &G 398 } 399 400 // affinize converts an entire slice to affine at once 401 func affinize(points []*G1) (out []G1) { 402 out = make([]G1, len(points)) 403 if len(points) == 0 { 404 return 405 } 406 ws := make([]ff.Fp, len(points)+1) 407 ws[0].SetOne() 408 for i := 0; i < len(points); i++ { 409 ws[i+1].Mul(&ws[i], &points[i].z) 410 } 411 412 w := &ff.Fp{} 413 w.Inv(&ws[len(points)]) 414 415 zinv := &ff.Fp{} 416 for i := len(points) - 1; i >= 0; i-- { 417 zinv.Mul(w, &ws[i]) 418 w.Mul(w, &points[i].z) 419 420 out[i].x.Mul(&points[i].x, zinv) 421 out[i].y.Mul(&points[i].y, zinv) 422 out[i].z.SetOne() 423 } 424 return 425 }