github.com/consensys/gnark-crypto@v0.14.0/ecc/bw6-633/internal/fptower/e6.go (about)

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