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 }