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