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  }