github.com/consensys/gnark-crypto@v0.14.0/internal/generator/tower/template/fq12over6over2/fq12.go.tmpl (about)

     1  import (
     2  	"math/big"
     3  	"errors"
     4      "sync"
     5  	"github.com/consensys/gnark-crypto/ecc"
     6  	"github.com/consensys/gnark-crypto/ecc/{{.Curve.Name}}/fp"
     7  	"github.com/consensys/gnark-crypto/ecc/{{.Curve.Name}}/fr"
     8  )
     9  
    10  var bigIntPool = sync.Pool{
    11  	New: func() interface{} {
    12  		return new(big.Int)
    13  	},
    14  }
    15  
    16  // E12 is a degree two finite field extension of fp6
    17  type E12 struct {
    18  	C0, C1 E6
    19  }
    20  
    21  // Equal returns true if z equals x, false otherwise
    22  func (z *E12) Equal(x *E12) bool {
    23  	return z.C0.Equal(&x.C0) && z.C1.Equal(&x.C1)
    24  }
    25  
    26  // String puts E12 in string form
    27  func (z *E12) String() string {
    28  	return (z.C0.String() + "+(" + z.C1.String() + ")*w")
    29  }
    30  
    31  // SetString sets a E12 from string
    32  func (z *E12) SetString(s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11 string) *E12 {
    33  	z.C0.SetString(s0, s1, s2, s3, s4, s5)
    34  	z.C1.SetString(s6, s7, s8, s9, s10, s11)
    35  	return z
    36  }
    37  
    38  // Set copies x into z and returns z
    39  func (z *E12) Set(x *E12) *E12 {
    40  	z.C0 = x.C0
    41  	z.C1 = x.C1
    42  	return z
    43  }
    44  
    45  // SetOne sets z to 1 in Montgomery form and returns z
    46  func (z *E12) SetOne() *E12 {
    47  	*z = E12{}
    48  	z.C0.B0.A0.SetOne()
    49  	return z
    50  }
    51  
    52  // Add sets z=x+y in E12 and returns z
    53  func (z *E12) Add(x, y *E12) *E12 {
    54  	z.C0.Add(&x.C0, &y.C0)
    55  	z.C1.Add(&x.C1, &y.C1)
    56  	return z
    57  }
    58  
    59  // Sub sets z to x-y and returns z
    60  func (z *E12) Sub(x, y *E12) *E12 {
    61  	z.C0.Sub(&x.C0, &y.C0)
    62  	z.C1.Sub(&x.C1, &y.C1)
    63  	return z
    64  }
    65  
    66  // Double sets z=2*x and returns z
    67  func (z *E12) Double(x *E12) *E12 {
    68  	z.C0.Double(&x.C0)
    69  	z.C1.Double(&x.C1)
    70  	return z
    71  }
    72  
    73  // SetRandom used only in tests
    74  func (z *E12) SetRandom() (*E12, error) {
    75  	if _, err := z.C0.SetRandom(); err != nil {
    76  		return nil, err
    77  	}
    78  	if _, err := z.C1.SetRandom(); err != nil {
    79  		return nil, err
    80  	}
    81  	return z, nil
    82  }
    83  
    84  // IsZero returns true if z is zero, false otherwise
    85  func (z *E12) IsZero() bool {
    86  	return z.C0.IsZero() && z.C1.IsZero()
    87  }
    88  
    89  // IsOne returns true if z is one, false otherwise
    90  func (z *E12) IsOne() bool {
    91  	return z.C0.IsOne() && z.C1.IsZero()
    92  }
    93  
    94  // Mul sets z=x*y in E12 and returns z
    95  func (z *E12) Mul(x, y *E12) *E12 {
    96  	var a, b, c E6
    97  	a.Add(&x.C0, &x.C1)
    98  	b.Add(&y.C0, &y.C1)
    99  	a.Mul(&a, &b)
   100  	b.Mul(&x.C0, &y.C0)
   101  	c.Mul(&x.C1, &y.C1)
   102  	z.C1.Sub(&a, &b).Sub(&z.C1, &c)
   103  	z.C0.MulByNonResidue(&c).Add(&z.C0, &b)
   104  	return z
   105  }
   106  
   107  // Square sets z=x*x in E12 and returns z
   108  func (z *E12) Square(x *E12) *E12 {
   109  
   110  	//Algorithm 22 from https://eprint.iacr.org/2010/354.pdf
   111  	var c0, c2, c3 E6
   112  	c0.Sub(&x.C0, &x.C1)
   113  	c3.MulByNonResidue(&x.C1).Neg(&c3).Add(&x.C0, &c3)
   114  	c2.Mul(&x.C0, &x.C1)
   115  	c0.Mul(&c0, &c3).Add(&c0, &c2)
   116  	z.C1.Double(&c2)
   117  	c2.MulByNonResidue(&c2)
   118  	z.C0.Add(&c0, &c2)
   119  
   120  	return z
   121  }
   122  
   123  // Karabina's compressed cyclotomic square
   124  // https://eprint.iacr.org/2010/542.pdf
   125  // Th. 3.2 with minor modifications to fit our tower
   126  func (z *E12) CyclotomicSquareCompressed(x *E12) *E12 {
   127  
   128  	var t [7]E2
   129  
   130      // t0 = g1^2
   131      t[0].Square(&x.C0.B1)
   132      // t1 = g5^2
   133      t[1].Square(&x.C1.B2)
   134      // t5 = g1 + g5
   135      t[5].Add(&x.C0.B1, &x.C1.B2)
   136      // t2 = (g1 + g5)^2
   137      t[2].Square(&t[5])
   138  
   139      // t3 = g1^2 + g5^2
   140      t[3].Add(&t[0], &t[1])
   141      // t5 = 2 * g1 * g5
   142      t[5].Sub(&t[2], &t[3])
   143  
   144      // t6 = g3 + g2
   145      t[6].Add(&x.C1.B0, &x.C0.B2)
   146      // t3 = (g3 + g2)^2
   147      t[3].Square(&t[6])
   148      // t2 = g3^2
   149      t[2].Square(&x.C1.B0)
   150  
   151      // t6 = 2 * nr * g1 * g5
   152      t[6].MulByNonResidue(&t[5])
   153      // t5 = 4 * nr * g1 * g5 + 2 * g3
   154      t[5].Add(&t[6], &x.C1.B0).
   155          Double(&t[5])
   156      // z3 = 6 * nr * g1 * g5 + 2 * g3
   157      z.C1.B0.Add(&t[5], &t[6])
   158  
   159      // t4 = nr * g5^2
   160      t[4].MulByNonResidue(&t[1])
   161      // t5 = nr * g5^2 + g1^2
   162      t[5].Add(&t[0], &t[4])
   163      // t6 = nr * g5^2 + g1^2 - g2
   164      t[6].Sub(&t[5], &x.C0.B2)
   165  
   166      // t1 = g2^2
   167      t[1].Square(&x.C0.B2)
   168  
   169      // t6 = 2 * nr * g5^2 + 2 * g1^2 - 2*g2
   170      t[6].Double(&t[6])
   171      // z2 = 3 * nr * g5^2 + 3 * g1^2 - 2*g2
   172      z.C0.B2.Add(&t[6], &t[5])
   173  
   174      // t4 = nr * g2^2
   175      t[4].MulByNonResidue(&t[1])
   176      // t5 = g3^2 + nr * g2^2
   177      t[5].Add(&t[2], &t[4])
   178      // t6 = g3^2 + nr * g2^2 - g1
   179      t[6].Sub(&t[5], &x.C0.B1)
   180      // t6 = 2 * g3^2 + 2 * nr * g2^2 - 2 * g1
   181      t[6].Double(&t[6])
   182      // z1 = 3 * g3^2 + 3 * nr * g2^2 - 2 * g1
   183      z.C0.B1.Add(&t[6], &t[5])
   184  
   185      // t0 = g2^2 + g3^2
   186      t[0].Add(&t[2], &t[1])
   187      // t5 = 2 * g3 * g2
   188      t[5].Sub(&t[3], &t[0])
   189      // t6 = 2 * g3 * g2 + g5
   190      t[6].Add(&t[5], &x.C1.B2)
   191      // t6 = 4 * g3 * g2 + 2 * g5
   192      t[6].Double(&t[6])
   193      // z5 = 6 * g3 * g2 + 2 * g5
   194      z.C1.B2.Add(&t[5], &t[6])
   195  
   196      return z
   197  }
   198  
   199  // DecompressKarabina Karabina's cyclotomic square result
   200  // if g3 != 0
   201  //   g4 = (E * g5^2 + 3 * g1^2 - 2 * g2)/4g3
   202  // if g3 == 0
   203  //   g4 = 2g1g5/g2
   204  //
   205  // if g3=g2=0 then g4=g5=g1=0 and g0=1 (x=1)
   206  // Theorem 3.1 is well-defined for all x in Gϕₙ\{1}
   207  func (z *E12) DecompressKarabina(x *E12) *E12 {
   208  
   209  	var t [3]E2
   210      var one E2
   211      one.SetOne()
   212  
   213  	if x.C1.B2.IsZero() /* g3 == 0 */ {
   214  		t[0].Mul(&x.C0.B1, &x.C1.B2).
   215  			Double(&t[0])
   216  		// t1 = g2
   217  		t[1].Set(&x.C0.B2)
   218  
   219  		if t[1].IsZero() /* g2 == g3 == 0 */ {
   220  			return z.SetOne()
   221  		}
   222  	} else /* g3 != 0 */ {
   223  
   224  		// t0 = g1^2
   225  		t[0].Square(&x.C0.B1)
   226  		// t1 = 3 * g1^2 - 2 * g2
   227  		t[1].Sub(&t[0], &x.C0.B2).
   228  			Double(&t[1]).
   229  			Add(&t[1], &t[0])
   230  			// t0 = E * g5^2 + t1
   231  		t[2].Square(&x.C1.B2)
   232  		t[0].MulByNonResidue(&t[2]).
   233  			Add(&t[0], &t[1])
   234  		// t1 = 4 * g3
   235  		t[1].Double(&x.C1.B0).
   236  			Double(&t[1])
   237  	}
   238  
   239  	// z4 = g4
   240  	z.C1.B1.Div(&t[0], &t[1]) // costly
   241  
   242  	// t1 = g2 * g1
   243  	t[1].Mul(&x.C0.B2, &x.C0.B1);
   244  	// t2 = 2 * g4^2 - 3 * g2 * g1
   245  	t[2].Square(&z.C1.B1).
   246          Sub(&t[2], &t[1]).
   247          Double(&t[2]).
   248          Sub(&t[2], &t[1])
   249  	// t1 = g3 * g5 (g3 can be 0)
   250  	t[1].Mul(&x.C1.B0, &x.C1.B2)
   251  	// c_0 = E * (2 * g4^2 + g3 * g5 - 3 * g2 * g1) + 1
   252  	t[2].Add(&t[2], &t[1])
   253  	z.C0.B0.MulByNonResidue(&t[2]).
   254          Add(&z.C0.B0, &one)
   255  
   256      z.C0.B1.Set(&x.C0.B1)
   257      z.C0.B2.Set(&x.C0.B2)
   258      z.C1.B0.Set(&x.C1.B0)
   259      z.C1.B2.Set(&x.C1.B2)
   260  
   261      return z
   262  }
   263  
   264  // BatchDecompressKarabina multiple Karabina's cyclotomic square results
   265  // if g3 != 0
   266  //   g4 = (E * g5^2 + 3 * g1^2 - 2 * g2)/4g3
   267  // if g3 == 0
   268  //   g4 = 2g1g5/g2
   269  //
   270  // if g3=g2=0 then g4=g5=g1=0 and g0=1 (x=1)
   271  // Theorem 3.1 is well-defined for all x in Gϕₙ\{1}
   272  //
   273  // Divisions by 4g3 or g2 is batched using Montgomery batch inverse
   274  func BatchDecompressKarabina(x []E12) []E12 {
   275  
   276  	n := len(x)
   277  	if n == 0 {
   278  		return x
   279  	}
   280  
   281  	t0 := make([]E2, n)
   282  	t1 := make([]E2, n)
   283  	t2 := make([]E2, n)
   284  	zeroes := make([]bool, n)
   285  
   286  	var one E2
   287  	one.SetOne()
   288  
   289  	for i := 0; i < n; i++ {
   290  		if x[i].C1.B2.IsZero() /* g3 == 0 */ {
   291  			t0[i].Mul(&x[i].C0.B1, &x[i].C1.B2).
   292  				Double(&t0[i])
   293  			// t1 = g2
   294  			t1[i].Set(&x[i].C0.B2)
   295  
   296  			if t1[i].IsZero() /* g3 == g2 == 0 */ {
   297  				x[i].SetOne()
   298  				zeroes[i] = true
   299  				continue
   300  			}
   301  		} else /* g3 != 0 */ {
   302  			// t0 = g1^2
   303  			t0[i].Square(&x[i].C0.B1)
   304  			// t1 = 3 * g1^2 - 2 * g2
   305  			t1[i].Sub(&t0[i], &x[i].C0.B2).
   306  				Double(&t1[i]).
   307  				Add(&t1[i], &t0[i])
   308  				// t0 = E * g5^2 + t1
   309  			t2[i].Square(&x[i].C1.B2)
   310  			t0[i].MulByNonResidue(&t2[i]).
   311  				Add(&t0[i], &t1[i])
   312  			// t1 = 4 * g3
   313  			t1[i].Double(&x[i].C1.B0).
   314  				Double(&t1[i])
   315  		}
   316  	}
   317  
   318  	t1 = BatchInvertE2(t1) // costs 1 inverse
   319  
   320  	for i := 0; i < n; i++ {
   321  		if zeroes[i] {
   322  			continue
   323  		}
   324  
   325  		// z4 = g4
   326  		x[i].C1.B1.Mul(&t0[i], &t1[i])
   327  
   328  		// t1 = g2 * g1
   329  		t1[i].Mul(&x[i].C0.B2, &x[i].C0.B1)
   330  		// t2 = 2 * g4^2 - 3 * g2 * g1
   331  		t2[i].Square(&x[i].C1.B1)
   332  		t2[i].Sub(&t2[i], &t1[i])
   333  		t2[i].Double(&t2[i])
   334  		t2[i].Sub(&t2[i], &t1[i])
   335  
   336  		// t1 = g3 * g5 (g3s can be 0s)
   337  		t1[i].Mul(&x[i].C1.B0, &x[i].C1.B2)
   338  		// z0 = E * (2 * g4^2 + g3 * g5 - 3 * g2 * g1) + 1
   339  		t2[i].Add(&t2[i], &t1[i])
   340  		x[i].C0.B0.MulByNonResidue(&t2[i]).
   341  			Add(&x[i].C0.B0, &one)
   342  	}
   343  
   344  	return x
   345  }
   346  
   347  // Granger-Scott's cyclotomic square
   348  // https://eprint.iacr.org/2009/565.pdf, 3.2
   349  func (z *E12) CyclotomicSquare(x *E12) *E12 {
   350  
   351  	// x=(x0,x1,x2,x3,x4,x5,x6,x7) in E2^6
   352  	// cyclosquare(x)=(3*x4^2*u + 3*x0^2 - 2*x0,
   353  	//					3*x2^2*u + 3*x3^2 - 2*x1,
   354  	//					3*x5^2*u + 3*x1^2 - 2*x2,
   355  	//					6*x1*x5*u + 2*x3,
   356  	//					6*x0*x4 + 2*x4,
   357  	//					6*x2*x3 + 2*x5)
   358  
   359  	var t [9]E2
   360  
   361  	t[0].Square(&x.C1.B1)
   362  	t[1].Square(&x.C0.B0)
   363  	t[6].Add(&x.C1.B1, &x.C0.B0).Square(&t[6]).Sub(&t[6], &t[0]).Sub(&t[6], &t[1]) // 2*x4*x0
   364  	t[2].Square(&x.C0.B2)
   365  	t[3].Square(&x.C1.B0)
   366  	t[7].Add(&x.C0.B2, &x.C1.B0).Square(&t[7]).Sub(&t[7], &t[2]).Sub(&t[7], &t[3]) // 2*x2*x3
   367  	t[4].Square(&x.C1.B2)
   368  	t[5].Square(&x.C0.B1)
   369  	t[8].Add(&x.C1.B2, &x.C0.B1).Square(&t[8]).Sub(&t[8], &t[4]).Sub(&t[8], &t[5]).MulByNonResidue(&t[8]) // 2*x5*x1*u
   370  
   371  	t[0].MulByNonResidue(&t[0]).Add(&t[0], &t[1]) // x4^2*u + x0^2
   372  	t[2].MulByNonResidue(&t[2]).Add(&t[2], &t[3]) // x2^2*u + x3^2
   373  	t[4].MulByNonResidue(&t[4]).Add(&t[4], &t[5]) // x5^2*u + x1^2
   374  
   375  	z.C0.B0.Sub(&t[0], &x.C0.B0).Double(&z.C0.B0).Add(&z.C0.B0, &t[0])
   376  	z.C0.B1.Sub(&t[2], &x.C0.B1).Double(&z.C0.B1).Add(&z.C0.B1, &t[2])
   377  	z.C0.B2.Sub(&t[4], &x.C0.B2).Double(&z.C0.B2).Add(&z.C0.B2, &t[4])
   378  
   379  	z.C1.B0.Add(&t[8], &x.C1.B0).Double(&z.C1.B0).Add(&z.C1.B0, &t[8])
   380  	z.C1.B1.Add(&t[6], &x.C1.B1).Double(&z.C1.B1).Add(&z.C1.B1, &t[6])
   381  	z.C1.B2.Add(&t[7], &x.C1.B2).Double(&z.C1.B2).Add(&z.C1.B2, &t[7])
   382  
   383  	return z
   384  }
   385  
   386  
   387  // Inverse sets z to the inverse of x in E12 and returns z
   388  //
   389  // if x == 0, sets and returns z = x
   390  func (z *E12) Inverse(x *E12) *E12 {
   391  	// Algorithm 23 from https://eprint.iacr.org/2010/354.pdf
   392  
   393  	var t0, t1, tmp E6
   394  	t0.Square(&x.C0)
   395  	t1.Square(&x.C1)
   396  	tmp.MulByNonResidue(&t1)
   397  	t0.Sub(&t0, &tmp)
   398  	t1.Inverse(&t0)
   399  	z.C0.Mul(&x.C0, &t1)
   400  	z.C1.Mul(&x.C1, &t1).Neg(&z.C1)
   401  
   402  	return z
   403  }
   404  
   405  // BatchInvertE12 returns a new slice with every element in a inverted.
   406  // It uses Montgomery batch inversion trick.
   407  //
   408  // if a[i] == 0, returns result[i] = a[i]
   409  func BatchInvertE12(a []E12) []E12 {
   410  	res := make([]E12, len(a))
   411  	if len(a) == 0 {
   412  		return res
   413  	}
   414  
   415  	zeroes := make([]bool, len(a))
   416  	var accumulator E12
   417  	accumulator.SetOne()
   418  
   419  	for i := 0; i < len(a); i++ {
   420  		if a[i].IsZero() {
   421  			zeroes[i] = true
   422  			continue
   423  		}
   424  		res[i].Set(&accumulator)
   425  		accumulator.Mul(&accumulator, &a[i])
   426  	}
   427  
   428  	accumulator.Inverse(&accumulator)
   429  
   430  	for i := len(a) - 1; i >= 0; i-- {
   431  		if zeroes[i] {
   432  			continue
   433  		}
   434  		res[i].Mul(&res[i], &accumulator)
   435  		accumulator.Mul(&accumulator, &a[i])
   436  	}
   437  
   438  	return res
   439  }
   440  
   441  // Exp sets z=xᵏ (mod q¹²) and returns it
   442  // uses 2-bits windowed method
   443  func (z *E12) Exp(x E12, k *big.Int) *E12 {
   444  	if k.IsUint64() && k.Uint64() == 0 {
   445  		return z.SetOne()
   446  	}
   447  
   448  	e := k
   449  	if k.Sign() == -1 {
   450  		// negative k, we invert
   451  		// if k < 0: xᵏ (mod q¹²) == (x⁻¹)ᵏ (mod q¹²)
   452  		x.Inverse(&x)
   453  
   454  		// we negate k in a temp big.Int since
   455  		// Int.Bit(_) of k and -k is different
   456  		e = bigIntPool.Get().(*big.Int)
   457  		defer bigIntPool.Put(e)
   458  		e.Neg(k)
   459  	}
   460  
   461  	var res E12
   462  	var ops [3]E12
   463  
   464  	res.SetOne()
   465  	ops[0].Set(&x)
   466  	ops[1].Square(&ops[0])
   467  	ops[2].Set(&ops[0]).Mul(&ops[2], &ops[1])
   468  
   469  	b := e.Bytes()
   470  	for i := range b {
   471  		w := b[i]
   472  		mask := byte(0xc0)
   473  		for j := 0; j < 4; j++ {
   474  			res.Square(&res).Square(&res)
   475  			c := (w & mask) >> (6 - 2*j)
   476  			if c != 0 {
   477  				res.Mul(&res, &ops[c-1])
   478  			}
   479  			mask = mask >> 2
   480  		}
   481  	}
   482  	z.Set(&res)
   483  
   484  	return z
   485  }
   486  
   487  // CyclotomicExp sets z=xᵏ (mod q¹²) and returns it
   488  // uses 2-NAF decomposition
   489  // x must be in the cyclotomic subgroup
   490  // TODO: use a windowed method
   491  func (z *E12) CyclotomicExp(x E12, k *big.Int) *E12 {
   492  	if k.IsUint64() && k.Uint64() == 0 {
   493  		return z.SetOne()
   494  	}
   495  
   496  	e := k
   497  	if k.Sign() == -1 {
   498  		// negative k, we invert (=conjugate)
   499  		// if k < 0: xᵏ (mod q¹²) == (x⁻¹)ᵏ (mod q¹²)
   500  		x.Conjugate(&x)
   501  
   502  		// we negate k in a temp big.Int since
   503  		// Int.Bit(_) of k and -k is different
   504  		e = bigIntPool.Get().(*big.Int)
   505  		defer bigIntPool.Put(e)
   506  		e.Neg(k)
   507  	}
   508  
   509  	var res, xInv E12
   510  	xInv.InverseUnitary(&x)
   511  	res.SetOne()
   512  	eNAF := make([]int8, e.BitLen()+3)
   513  	n := ecc.NafDecomposition(e, eNAF[:])
   514  	for i := n - 1; i >= 0; i-- {
   515  		res.CyclotomicSquare(&res)
   516  		if eNAF[i] == 1 {
   517  			res.Mul(&res, &x)
   518  		} else if eNAF[i] == -1 {
   519  			res.Mul(&res, &xInv)
   520  		}
   521  	}
   522  	z.Set(&res)
   523  	return z
   524  }
   525  
   526  // ExpGLV sets z=xᵏ (q¹²) and returns it
   527  // uses 2-dimensional GLV with 2-bits windowed method
   528  // x must be in GT
   529  // TODO: use 2-NAF
   530  // TODO: use higher dimensional decomposition
   531  func (z *E12) ExpGLV(x E12, k *big.Int) *E12 {
   532  	if k.IsUint64() && k.Uint64() == 0 {
   533  		return z.SetOne()
   534  	}
   535  
   536  	e := k
   537  	if k.Sign() == -1 {
   538  		// negative k, we invert (=conjugate)
   539  		// if k < 0: xᵏ (mod q¹²) == (x⁻¹)ᵏ (mod q¹²)
   540  		x.Conjugate(&x)
   541  
   542  		// we negate k in a temp big.Int since
   543  		// Int.Bit(_) of k and -k is different
   544  		e = bigIntPool.Get().(*big.Int)
   545  		defer bigIntPool.Put(e)
   546  		e.Neg(k)
   547  	}
   548  
   549  	var table [15]E12
   550  	var res E12
   551  	var s1, s2 fr.Element
   552  
   553  	res.SetOne()
   554  
   555  	// table[b3b2b1b0-1] = b3b2*Frobinius(x) + b1b0*x
   556  	table[0].Set(&x)
   557  	table[3].Frobenius(&x)
   558  
   559  	// split the scalar, modifies ±x, Frob(x) accordingly
   560  	s := ecc.SplitScalar(e, &glvBasis)
   561  
   562  	if s[0].Sign() == -1 {
   563  		s[0].Neg(&s[0])
   564  		table[0].InverseUnitary(&table[0])
   565  	}
   566  	if s[1].Sign() == -1 {
   567  		s[1].Neg(&s[1])
   568  		table[3].InverseUnitary(&table[3])
   569  	}
   570  
   571  	// precompute table (2 bits sliding window)
   572  	// table[b3b2b1b0-1] = b3b2*Frobenius(x) + b1b0*x if b3b2b1b0 != 0
   573  	table[1].CyclotomicSquare(&table[0])
   574  	table[2].Mul(&table[1], &table[0])
   575  	table[4].Mul(&table[3], &table[0])
   576  	table[5].Mul(&table[3], &table[1])
   577  	table[6].Mul(&table[3], &table[2])
   578  	table[7].CyclotomicSquare(&table[3])
   579  	table[8].Mul(&table[7], &table[0])
   580  	table[9].Mul(&table[7], &table[1])
   581  	table[10].Mul(&table[7], &table[2])
   582  	table[11].Mul(&table[7], &table[3])
   583  	table[12].Mul(&table[11], &table[0])
   584  	table[13].Mul(&table[11], &table[1])
   585  	table[14].Mul(&table[11], &table[2])
   586  
   587  	// bounds on the lattice base vectors guarantee that s1, s2 are len(r)/2 bits long max
   588  	s1 = s1.SetBigInt(&s[0]).Bits()
   589  	s2 = s2.SetBigInt(&s[1]).Bits()
   590  
   591  	maxBit := s1.BitLen()
   592  	if s2.BitLen() > maxBit {
   593  		maxBit = s2.BitLen()
   594  	}
   595  	hiWordIndex := (maxBit - 1) / 64
   596  
   597  	// loop starts from len(s1)/2 due to the bounds
   598  	for i := hiWordIndex ; i >= 0; i-- {
   599  		mask := uint64(3) << 62
   600  		for j := 0; j < 32; j++ {
   601  			res.CyclotomicSquare(&res).CyclotomicSquare(&res)
   602  			b1 := (s1[i] & mask) >> (62 - 2*j)
   603  			b2 := (s2[i] & mask) >> (62 - 2*j)
   604  			if b1|b2 != 0 {
   605  				s := (b2<<2 | b1)
   606  				res.Mul(&res, &table[s-1])
   607  			}
   608  			mask = mask >> 2
   609  		}
   610  	}
   611  
   612  	z.Set(&res)
   613  	return z
   614  }
   615  
   616  // InverseUnitary inverses a unitary element
   617  func (z *E12) InverseUnitary(x *E12) *E12 {
   618  	return z.Conjugate(x)
   619  }
   620  
   621  // Conjugate sets z to x conjugated and returns z
   622  func (z *E12) Conjugate(x *E12) *E12 {
   623  	*z = *x
   624  	z.C1.Neg(&z.C1)
   625  	return z
   626  }
   627  
   628  
   629  {{- $sizeOfFp := mul .Curve.Fp.NbWords 8}}
   630  
   631  // SizeOfGT represents the size in bytes that a GT element need in binary form
   632  const SizeOfGT = {{ $sizeOfFp }} * 12
   633  
   634  // Marshal converts z to a byte slice
   635  func (z *E12) Marshal() ([]byte) {
   636  	b := z.Bytes()
   637  	return b[:]
   638  }
   639  
   640  // Unmarshal is an alias to SetBytes()
   641  func (z *E12) Unmarshal(buf []byte) error {
   642  	return z.SetBytes(buf)
   643  }
   644  
   645  // Bytes returns the regular (non montgomery) value
   646  // of z as a big-endian byte array.
   647  // z.C1.B2.A1 | z.C1.B2.A0 | z.C1.B1.A1 | ...
   648  func (z *E12) Bytes() (r [SizeOfGT]byte) {
   649  	{{- $offset := mul $sizeOfFp 11}}
   650  	{{- template "putFp" dict "all" . "OffSet" $offset "From" "z.C0.B0.A0"}}
   651  
   652  	{{- $offset := mul $sizeOfFp 10}}
   653  	{{- template "putFp" dict "all" . "OffSet" $offset "From" "z.C0.B0.A1"}}
   654  
   655  	{{- $offset := mul $sizeOfFp 9}}
   656  	{{- template "putFp" dict "all" . "OffSet" $offset "From" "z.C0.B1.A0"}}
   657  
   658  	{{- $offset := mul $sizeOfFp 8}}
   659  	{{- template "putFp" dict "all" . "OffSet" $offset "From" "z.C0.B1.A1"}}
   660  
   661  	{{- $offset := mul $sizeOfFp 7}}
   662  	{{- template "putFp" dict "all" . "OffSet" $offset "From" "z.C0.B2.A0"}}
   663  
   664  	{{- $offset := mul $sizeOfFp 6}}
   665  	{{- template "putFp" dict "all" . "OffSet" $offset "From" "z.C0.B2.A1"}}
   666  
   667  	{{- $offset := mul $sizeOfFp 5}}
   668  	{{- template "putFp" dict "all" . "OffSet" $offset "From" "z.C1.B0.A0"}}
   669  
   670  	{{- $offset := mul $sizeOfFp 4}}
   671  	{{- template "putFp" dict "all" . "OffSet" $offset "From" "z.C1.B0.A1"}}
   672  
   673  	{{- $offset := mul $sizeOfFp 3}}
   674  	{{- template "putFp" dict "all" . "OffSet" $offset "From" "z.C1.B1.A0"}}
   675  
   676  	{{- $offset := mul $sizeOfFp 2}}
   677  	{{- template "putFp" dict "all" . "OffSet" $offset "From" "z.C1.B1.A1"}}
   678  
   679  	{{- $offset := mul $sizeOfFp 1}}
   680  	{{- template "putFp" dict "all" . "OffSet" $offset "From" "z.C1.B2.A0"}}
   681  
   682  	{{- $offset := mul $sizeOfFp 0}}
   683  	{{- template "putFp" dict "all" . "OffSet" $offset "From" "z.C1.B2.A1"}}
   684  
   685  	return
   686  }
   687  
   688  
   689  // SetBytes interprets e as the bytes of a big-endian GT
   690  // sets z to that value (in Montgomery form), and returns z.
   691  // size(e) == {{ $sizeOfFp }} * 12
   692  // z.C1.B2.A1 | z.C1.B2.A0 | z.C1.B1.A1 | ...
   693  func (z *E12) SetBytes(e []byte) error {
   694  	if len(e) != SizeOfGT {
   695  		return errors.New("invalid buffer size")
   696  	}
   697  
   698  	{{- $offset := mul $sizeOfFp 11}}
   699  	{{- template "readFp" dict "all" . "OffSet" $offset "To" "z.C0.B0.A0"}}
   700  
   701  	{{- $offset := mul $sizeOfFp 10}}
   702  	{{- template "readFp" dict "all" . "OffSet" $offset "To" "z.C0.B0.A1"}}
   703  
   704  	{{- $offset := mul $sizeOfFp 9}}
   705  	{{- template "readFp" dict "all" . "OffSet" $offset "To" "z.C0.B1.A0"}}
   706  
   707  	{{- $offset := mul $sizeOfFp 8}}
   708  	{{- template "readFp" dict "all" . "OffSet" $offset "To" "z.C0.B1.A1"}}
   709  
   710  	{{- $offset := mul $sizeOfFp 7}}
   711  	{{- template "readFp" dict "all" . "OffSet" $offset "To" "z.C0.B2.A0"}}
   712  
   713  	{{- $offset := mul $sizeOfFp 6}}
   714  	{{- template "readFp" dict "all" . "OffSet" $offset "To" "z.C0.B2.A1"}}
   715  
   716  	{{- $offset := mul $sizeOfFp 5}}
   717  	{{- template "readFp" dict "all" . "OffSet" $offset "To" "z.C1.B0.A0"}}
   718  
   719  	{{- $offset := mul $sizeOfFp 4}}
   720  	{{- template "readFp" dict "all" . "OffSet" $offset "To" "z.C1.B0.A1"}}
   721  
   722  	{{- $offset := mul $sizeOfFp 3}}
   723  	{{- template "readFp" dict "all" . "OffSet" $offset "To" "z.C1.B1.A0"}}
   724  
   725  	{{- $offset := mul $sizeOfFp 2}}
   726  	{{- template "readFp" dict "all" . "OffSet" $offset "To" "z.C1.B1.A1"}}
   727  
   728  	{{- $offset := mul $sizeOfFp 1}}
   729  	{{- template "readFp" dict "all" . "OffSet" $offset "To" "z.C1.B2.A0"}}
   730  
   731  	{{- $offset := mul $sizeOfFp 0}}
   732  	{{- template "readFp" dict "all" . "OffSet" $offset "To" "z.C1.B2.A1"}}
   733  
   734  	return nil
   735  }
   736  
   737  // IsInSubGroup ensures GT/E12 is in correct subgroup
   738  func (z *E12) IsInSubGroup() bool {
   739  {{- if eq .Curve.Name "bn254"}}
   740      var a, b, _b E12
   741  
   742      a.Frobenius(z)
   743      b.Expt(z).
   744          Expt(&b).
   745          CyclotomicSquare(&b)
   746      _b.CyclotomicSquare(&b)
   747      b.Mul(&b, &_b)
   748  {{ else }}
   749      var a, b E12
   750  
   751      // check z^(phi_k(p)) == 1
   752      a.FrobeniusSquare(z)
   753      b.FrobeniusSquare(&a).Mul(&b, z)
   754  
   755      if !a.Equal(&b) {
   756          return false
   757      }
   758  
   759      // check z^(p+1-t) == 1
   760      a.Frobenius(z)
   761      b.Expt(z)
   762  {{ end }}
   763  
   764      return a.Equal(&b)
   765  }
   766  
   767  {{- define "putFp"}}
   768  	fp.BigEndian.PutElement((*[fp.Bytes]byte)( r[{{$.OffSet}}:{{$.OffSet}} + fp.Bytes]), {{$.From}})
   769  {{- end}}
   770  
   771  {{- define "readFp"}}
   772  	if err := {{$.To}}.SetBytesCanonical(e[{{$.OffSet}}:{{$.OffSet}} + fp.Bytes]); err != nil {
   773  		return err
   774  	}
   775  {{- end}}
   776  
   777  // CompressTorus GT/E12 element to half its size
   778  // z must be in the cyclotomic subgroup
   779  // i.e. z^(p^4-p^2+1)=1
   780  // e.g. GT
   781  // "COMPRESSION IN FINITE FIELDS AND TORUS-BASED CRYPTOGRAPHY", K. RUBIN AND A. SILVERBERG
   782  // z.C1 == 0 only when z \in {-1,1}
   783  func (z *E12) CompressTorus() (E6, error) {
   784  
   785  	if z.C1.IsZero() {
   786  		return E6{}, errors.New("invalid input")
   787  	}
   788  
   789  	var res, tmp, one E6
   790  	one.SetOne()
   791  	tmp.Inverse(&z.C1)
   792  	res.Add(&z.C0, &one).
   793  		Mul(&res, &tmp)
   794  
   795  	return res, nil
   796  }
   797  
   798  // BatchCompressTorus GT/E12 elements to half their size using a batch inversion.
   799  //
   800  // if len(x) == 0 or if any of the x[i].C1 coordinate is 0, this function returns an error.
   801  func BatchCompressTorus(x []E12) ([]E6, error) {
   802  
   803  	n := len(x)
   804  	if n == 0 {
   805  		return nil, errors.New("invalid input size")
   806  	}
   807  
   808  	var one E6
   809  	one.SetOne()
   810  	res := make([]E6, n)
   811  
   812  	for i := 0; i < n; i++ {
   813  		res[i].Set(&x[i].C1)
   814  		//  throw an error if any of the x[i].C1 is 0
   815  		if res[i].IsZero() {
   816  			return nil, errors.New("invalid input; C1 is 0")
   817  		}
   818  	}
   819  
   820  	t := BatchInvertE6(res) // costs 1 inverse
   821  
   822  	for i := 0; i < n; i++ {
   823  		res[i].Add(&x[i].C0, &one).
   824  			Mul(&res[i], &t[i])
   825  	}
   826  
   827  	return res, nil
   828  }
   829  
   830  // DecompressTorus GT/E12 a compressed element
   831  // element must be in the cyclotomic subgroup
   832  // "COMPRESSION IN FINITE FIELDS AND TORUS-BASED CRYPTOGRAPHY", K. RUBIN AND A. SILVERBERG
   833  func (z *E6) DecompressTorus() E12 {
   834  
   835  	var res, num, denum E12
   836  	num.C0.Set(z)
   837  	num.C1.SetOne()
   838  	denum.C0.Set(z)
   839  	denum.C1.SetOne().Neg(&denum.C1)
   840  	res.Inverse(&denum).
   841  		Mul(&res, &num)
   842  
   843  	return res
   844  }
   845  
   846  // BatchDecompressTorus GT/E12 compressed elements
   847  // using a batch inversion
   848  func BatchDecompressTorus(x []E6) ([]E12, error) {
   849  
   850  	n := len(x)
   851  	if n == 0 {
   852  		return []E12{}, errors.New("invalid input size")
   853  	}
   854  
   855  	res := make([]E12, n)
   856  	num := make([]E12, n)
   857  	denum := make([]E12, n)
   858  
   859  	for i := 0; i < n; i++ {
   860  		num[i].C0.Set(&x[i])
   861  		num[i].C1.SetOne()
   862  		denum[i].C0.Set(&x[i])
   863  		denum[i].C1.SetOne().Neg(&denum[i].C1)
   864  	}
   865  
   866  	denum = BatchInvertE12(denum) // costs 1 inverse
   867  
   868  	for i := 0; i < n; i++ {
   869  		res[i].Mul(&num[i], &denum[i])
   870  	}
   871  
   872  	return res, nil
   873  }
   874  {{ template "base" .}}