github.com/cloudflare/circl@v1.5.0/ecc/bls12381/pair.go (about)

     1  package bls12381
     2  
     3  import "github.com/cloudflare/circl/ecc/bls12381/ff"
     4  
     5  // Pair calculates the ate-pairing of P and Q.
     6  func Pair(P *G1, Q *G2) *Gt {
     7  	affP := *P
     8  	affP.toAffine()
     9  	mi := &ff.Fp12{}
    10  	miller(mi, &affP, Q)
    11  	e := &Gt{}
    12  	finalExp(e, mi)
    13  	return e
    14  }
    15  
    16  func miller(f *ff.Fp12, P *G1, Q *G2) {
    17  	g := &ff.LineValue{}
    18  	acc := &ff.Fp12Cubic{}
    19  	acc.SetOne()
    20  	T := &G2{}
    21  	*T = *Q
    22  	l := &line{}
    23  	const lenX = 64
    24  	for i := lenX - 2; i >= 0; i-- {
    25  		acc.Sqr(acc)
    26  		doubleAndLine(T, l)
    27  		evalLine(g, l, P)
    28  		acc.MulLine(acc, g)
    29  		// paramX is -2 ^ 63 - 2 ^ 62 - 2 ^ 60 - 2 ^ 57 - 2 ^ 48 - 2 ^ 16
    30  		if (i == 62) || (i == 60) || (i == 57) || (i == 48) || (i == 16) {
    31  			addAndLine(T, T, Q, l)
    32  			evalLine(g, l, P)
    33  			acc.MulLine(acc, g)
    34  		}
    35  	}
    36  	f.FromFp12Cubic(acc)
    37  	f.Cjg() // inverts f as paramX is negative.
    38  }
    39  
    40  // line contains the coefficients of a sparse element of Fp12.
    41  // Evaluating the line on P' = (xP',yP') results in
    42  //
    43  //	f = evalLine(P') = l[0]*xP' + l[1]*yP' + l[2] \in Fp12.
    44  type line [3]ff.Fp2
    45  
    46  // evalLine updates f = f * line(P'), where f lives in Fp12 = Fp6[w]/(w^2-v)
    47  // and P' is the image of P on the twist curve.
    48  func evalLine(f *ff.LineValue, l *line, P *G1) {
    49  	// Send P \in E to the twist
    50  	//     E    -->        E'
    51  	//  (xP,yP) |-> (xP*w^2,yP*w^3) = (xP',yP')
    52  	//
    53  	// f = line(P') = l[0]*xP' + l[1]*yP' + l[2] \in Fp12.
    54  	//              = l[0]*xP*w^2 + l[1]*yP*w^3 + l[2] \in Fp12.
    55  
    56  	// First perform the products: l[0]*xP and l[1]*yP \in Fp2.
    57  	var xP, yP ff.Fp2
    58  	xP[0] = P.x
    59  	yP[0] = P.y
    60  	f[1].Mul(&l[0], &xP)
    61  	f[2].Mul(&l[1], &yP)
    62  	f[0] = l[2]
    63  
    64  	if f.IsZero() == 1 {
    65  		f.SetOne()
    66  	}
    67  }
    68  
    69  func finalExp(g *Gt, f *ff.Fp12) {
    70  	c := &ff.Cyclo6{}
    71  	ff.EasyExponentiation(c, f)
    72  	ff.HardExponentiation(&g.i, c)
    73  }
    74  
    75  // ProdPair calculates the product of pairings, i.e., \Prod_i pair(Pi,Qi)^ni.
    76  func ProdPair(P []*G1, Q []*G2, n []*Scalar) *Gt {
    77  	if len(P) != len(Q) || len(P) != len(n) {
    78  		panic("mismatch length of inputs")
    79  	}
    80  
    81  	ei := new(ff.Fp12)
    82  	mi := new(ff.Fp12)
    83  	out := new(ff.Fp12)
    84  	out.SetOne()
    85  
    86  	affineP := affinize(P)
    87  	for i := range affineP {
    88  		miller(mi, &affineP[i], Q[i])
    89  		nb, _ := n[i].MarshalBinary()
    90  		ei.Exp(mi, nb)
    91  		out.Mul(out, ei)
    92  	}
    93  
    94  	e := &Gt{}
    95  	finalExp(e, out)
    96  	return e
    97  }
    98  
    99  // ProdPairFrac computes the product e(P, Q)^sign where sign is 1 or -1
   100  func ProdPairFrac(P []*G1, Q []*G2, signs []int) *Gt {
   101  	if len(P) != len(Q) || len(P) != len(signs) {
   102  		panic("mismatch length of inputs")
   103  	}
   104  
   105  	mi := new(ff.Fp12)
   106  	out := new(ff.Fp12)
   107  	out.SetOne()
   108  
   109  	affineP := affinize(P)
   110  	for i := range affineP {
   111  		if signs[i] == -1 {
   112  			affineP[i].Neg()
   113  		}
   114  		miller(mi, &affineP[i], Q[i])
   115  		out.Mul(mi, out)
   116  	}
   117  
   118  	e := &Gt{}
   119  	finalExp(e, out)
   120  	return e
   121  }