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