github.com/consensys/gnark-crypto@v0.14.0/ecc/bls24-315/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-315/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 set 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 sub 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 set 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 set 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  // BatchDecompressKarabina multiple Karabina's cyclotomic square results
   283  // if g3 != 0
   284  //
   285  //	g4 = (E * g5^2 + 3 * g1^2 - 2 * g2)/4g3
   286  //
   287  // if g3 == 0
   288  //
   289  //	g4 = 2g1g5/g2
   290  //
   291  // if g3=g2=0 then g4=g5=g1=0 and g0=1 (x=1)
   292  // Theorem 3.1 is well-defined for all x in Gϕₙ\{1}
   293  //
   294  // Divisions by 4g3 or g2 is batched using Montgomery batch inverse
   295  func BatchDecompressKarabina(x []E24) []E24 {
   296  
   297  	n := len(x)
   298  	if n == 0 {
   299  		return x
   300  	}
   301  
   302  	t0 := make([]E4, n)
   303  	t1 := make([]E4, n)
   304  	t2 := make([]E4, n)
   305  
   306  	var one E4
   307  	one.SetOne()
   308  
   309  	for i := 0; i < n; i++ {
   310  		// g3 == 0
   311  		if x[i].D1.C0.IsZero() {
   312  			t0[i].Mul(&x[i].D0.C1, &x[i].D1.C2).
   313  				Double(&t0[i])
   314  			// t1 = g2
   315  			t1[i].Set(&x[i].D0.C2)
   316  
   317  			// g3 != 0
   318  		} else {
   319  			// t0 = g1^2
   320  			t0[i].Square(&x[i].D0.C1)
   321  			// t1 = 3 * g1^2 - 2 * g2
   322  			t1[i].Sub(&t0[i], &x[i].D0.C2).
   323  				Double(&t1[i]).
   324  				Add(&t1[i], &t0[i])
   325  			// t0 = E * g5^2 + t1
   326  			t2[i].Square(&x[i].D1.C2)
   327  			t0[i].MulByNonResidue(&t2[i]).
   328  				Add(&t0[i], &t1[i])
   329  			// t1 = 4 * g3
   330  			t1[i].Double(&x[i].D1.C0).
   331  				Double(&t1[i])
   332  		}
   333  	}
   334  
   335  	t1 = BatchInvertE4(t1) // costs 1 inverse
   336  
   337  	for i := 0; i < n; i++ {
   338  		// z4 = g4
   339  		x[i].D1.C1.Mul(&t0[i], &t1[i])
   340  
   341  		// t1 = g2 * g1
   342  		t1[i].Mul(&x[i].D0.C2, &x[i].D0.C1)
   343  		// t2 = 2 * g4² - 3 * g2 * g1
   344  		t2[i].Square(&x[i].D1.C1)
   345  		t2[i].Sub(&t2[i], &t1[i])
   346  		t2[i].Double(&t2[i])
   347  		t2[i].Sub(&t2[i], &t1[i])
   348  
   349  		// t1 = g3 * g5 (g3s can be 0s)
   350  		t1[i].Mul(&x[i].D1.C0, &x[i].D1.C2)
   351  		// z0 = E * (2 * g4² + g3 * g5 - 3 * g2 * g1) + 1
   352  		t2[i].Add(&t2[i], &t1[i])
   353  		x[i].D0.C0.MulByNonResidue(&t2[i]).
   354  			Add(&x[i].D0.C0, &one)
   355  	}
   356  
   357  	return x
   358  }
   359  
   360  // Granger-Scott's cyclotomic square
   361  // https://eprint.iacr.org/2009/565.pdf, 3.2
   362  func (z *E24) CyclotomicSquare(x *E24) *E24 {
   363  
   364  	// x=(x0,x1,x2,x3,x4,x5,x6,x7) in E4⁶
   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]E4
   373  
   374  	t[0].Square(&x.D1.C1)
   375  	t[1].Square(&x.D0.C0)
   376  	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
   377  	t[2].Square(&x.D0.C2)
   378  	t[3].Square(&x.D1.C0)
   379  	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
   380  	t[4].Square(&x.D1.C2)
   381  	t[5].Square(&x.D0.C1)
   382  	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
   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.D0.C0.Sub(&t[0], &x.D0.C0).Double(&z.D0.C0).Add(&z.D0.C0, &t[0])
   389  	z.D0.C1.Sub(&t[2], &x.D0.C1).Double(&z.D0.C1).Add(&z.D0.C1, &t[2])
   390  	z.D0.C2.Sub(&t[4], &x.D0.C2).Double(&z.D0.C2).Add(&z.D0.C2, &t[4])
   391  
   392  	z.D1.C0.Add(&t[8], &x.D1.C0).Double(&z.D1.C0).Add(&z.D1.C0, &t[8])
   393  	z.D1.C1.Add(&t[6], &x.D1.C1).Double(&z.D1.C1).Add(&z.D1.C1, &t[6])
   394  	z.D1.C2.Add(&t[7], &x.D1.C2).Double(&z.D1.C2).Add(&z.D1.C2, &t[7])
   395  
   396  	return z
   397  }
   398  
   399  // Inverse set z to the inverse of x in E24 and return z
   400  //
   401  // if x == 0, sets and returns z = x
   402  func (z *E24) Inverse(x *E24) *E24 {
   403  	// Algorithm 23 from https://eprint.iacr.org/2010/354.pdf
   404  
   405  	var t0, t1, tmp E12
   406  	t0.Square(&x.D0)
   407  	t1.Square(&x.D1)
   408  	tmp.MulByNonResidue(&t1)
   409  	t0.Sub(&t0, &tmp)
   410  	t1.Inverse(&t0)
   411  	z.D0.Mul(&x.D0, &t1)
   412  	z.D1.Mul(&x.D1, &t1).Neg(&z.D1)
   413  
   414  	return z
   415  }
   416  
   417  // BatchInvertE24 returns a new slice with every element inverted.
   418  // Uses Montgomery batch inversion trick
   419  //
   420  // if a[i] == 0, returns result[i] = a[i]
   421  func BatchInvertE24(a []E24) []E24 {
   422  	res := make([]E24, len(a))
   423  	if len(a) == 0 {
   424  		return res
   425  	}
   426  
   427  	zeroes := make([]bool, len(a))
   428  	var accumulator E24
   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 *E24) Exp(x E24, k *big.Int) *E24 {
   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 E24
   474  	var ops [3]E24
   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 *E24) CyclotomicExp(x E24, k *big.Int) *E24 {
   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 E24
   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 *E24) ExpGLV(x E24, k *big.Int) *E24 {
   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]E24
   562  	var res E24
   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 inverse a unitary element
   629  func (z *E24) InverseUnitary(x *E24) *E24 {
   630  	return z.Conjugate(x)
   631  }
   632  
   633  // Conjugate set z to x conjugated and return z
   634  func (z *E24) Conjugate(x *E24) *E24 {
   635  	*z = *x
   636  	z.D1.Neg(&z.D1)
   637  	return z
   638  }
   639  
   640  // SizeOfGT represents the size in bytes that a GT element need in binary form
   641  const sizeOfFp = 40
   642  const SizeOfGT = sizeOfFp * 24
   643  
   644  // Marshal converts z to a byte slice
   645  func (z *E24) Marshal() []byte {
   646  	b := z.Bytes()
   647  	return b[:]
   648  }
   649  
   650  // Unmarshal is an alias to SetBytes()
   651  func (z *E24) Unmarshal(buf []byte) error {
   652  	return z.SetBytes(buf)
   653  }
   654  
   655  func (z *E24) Bytes() (r [SizeOfGT]byte) {
   656  
   657  	offset := 0
   658  	var buf [sizeOfFp]byte
   659  
   660  	buf = z.D0.C0.B0.A0.Bytes()
   661  	copy(r[offset:offset+sizeOfFp], buf[:])
   662  	offset += sizeOfFp
   663  
   664  	buf = z.D0.C0.B0.A1.Bytes()
   665  	copy(r[offset:offset+sizeOfFp], buf[:])
   666  	offset += sizeOfFp
   667  
   668  	buf = z.D0.C0.B1.A0.Bytes()
   669  	copy(r[offset:offset+sizeOfFp], buf[:])
   670  	offset += sizeOfFp
   671  
   672  	buf = z.D0.C0.B1.A1.Bytes()
   673  	copy(r[offset:offset+sizeOfFp], buf[:])
   674  	offset += sizeOfFp
   675  
   676  	buf = z.D0.C1.B0.A0.Bytes()
   677  	copy(r[offset:offset+sizeOfFp], buf[:])
   678  	offset += sizeOfFp
   679  
   680  	buf = z.D0.C1.B0.A1.Bytes()
   681  	copy(r[offset:offset+sizeOfFp], buf[:])
   682  	offset += sizeOfFp
   683  
   684  	buf = z.D0.C1.B1.A0.Bytes()
   685  	copy(r[offset:offset+sizeOfFp], buf[:])
   686  	offset += sizeOfFp
   687  
   688  	buf = z.D0.C1.B1.A1.Bytes()
   689  	copy(r[offset:offset+sizeOfFp], buf[:])
   690  	offset += sizeOfFp
   691  
   692  	buf = z.D0.C2.B0.A0.Bytes()
   693  	copy(r[offset:offset+sizeOfFp], buf[:])
   694  	offset += sizeOfFp
   695  
   696  	buf = z.D0.C2.B0.A1.Bytes()
   697  	copy(r[offset:offset+sizeOfFp], buf[:])
   698  	offset += sizeOfFp
   699  
   700  	buf = z.D0.C2.B1.A0.Bytes()
   701  	copy(r[offset:offset+sizeOfFp], buf[:])
   702  	offset += sizeOfFp
   703  
   704  	buf = z.D0.C2.B1.A1.Bytes()
   705  	copy(r[offset:offset+sizeOfFp], buf[:])
   706  	offset += sizeOfFp
   707  
   708  	buf = z.D1.C0.B0.A0.Bytes()
   709  	copy(r[offset:offset+sizeOfFp], buf[:])
   710  	offset += sizeOfFp
   711  
   712  	buf = z.D1.C0.B0.A1.Bytes()
   713  	copy(r[offset:offset+sizeOfFp], buf[:])
   714  	offset += sizeOfFp
   715  
   716  	buf = z.D1.C0.B1.A0.Bytes()
   717  	copy(r[offset:offset+sizeOfFp], buf[:])
   718  	offset += sizeOfFp
   719  
   720  	buf = z.D1.C0.B1.A1.Bytes()
   721  	copy(r[offset:offset+sizeOfFp], buf[:])
   722  	offset += sizeOfFp
   723  
   724  	buf = z.D1.C1.B0.A0.Bytes()
   725  	copy(r[offset:offset+sizeOfFp], buf[:])
   726  	offset += sizeOfFp
   727  
   728  	buf = z.D1.C1.B0.A1.Bytes()
   729  	copy(r[offset:offset+sizeOfFp], buf[:])
   730  	offset += sizeOfFp
   731  
   732  	buf = z.D1.C1.B1.A0.Bytes()
   733  	copy(r[offset:offset+sizeOfFp], buf[:])
   734  	offset += sizeOfFp
   735  
   736  	buf = z.D1.C1.B1.A1.Bytes()
   737  	copy(r[offset:offset+sizeOfFp], buf[:])
   738  	offset += sizeOfFp
   739  
   740  	buf = z.D1.C2.B0.A0.Bytes()
   741  	copy(r[offset:offset+sizeOfFp], buf[:])
   742  	offset += sizeOfFp
   743  
   744  	buf = z.D1.C2.B0.A1.Bytes()
   745  	copy(r[offset:offset+sizeOfFp], buf[:])
   746  	offset += sizeOfFp
   747  
   748  	buf = z.D1.C2.B1.A0.Bytes()
   749  	copy(r[offset:offset+sizeOfFp], buf[:])
   750  	offset += sizeOfFp
   751  
   752  	buf = z.D1.C2.B1.A1.Bytes()
   753  	copy(r[offset:offset+sizeOfFp], buf[:])
   754  
   755  	return
   756  }
   757  
   758  // SetBytes interprets e as the bytes of a big-endian GT
   759  // sets z to that value (in Montgomery form), and returns z.
   760  func (z *E24) SetBytes(e []byte) error {
   761  	if len(e) != SizeOfGT {
   762  		return errors.New("invalid buffer size")
   763  	}
   764  	offset := 0
   765  	z.D0.C0.B0.A0.SetBytes(e[offset : offset+sizeOfFp])
   766  	offset += sizeOfFp
   767  	z.D0.C0.B0.A1.SetBytes(e[offset : offset+sizeOfFp])
   768  	offset += sizeOfFp
   769  	z.D0.C0.B1.A0.SetBytes(e[offset : offset+sizeOfFp])
   770  	offset += sizeOfFp
   771  	z.D0.C0.B1.A1.SetBytes(e[offset : offset+sizeOfFp])
   772  	offset += sizeOfFp
   773  	z.D0.C1.B0.A0.SetBytes(e[offset : offset+sizeOfFp])
   774  	offset += sizeOfFp
   775  	z.D0.C1.B0.A1.SetBytes(e[offset : offset+sizeOfFp])
   776  	offset += sizeOfFp
   777  	z.D0.C1.B1.A0.SetBytes(e[offset : offset+sizeOfFp])
   778  	offset += sizeOfFp
   779  	z.D0.C1.B1.A1.SetBytes(e[offset : offset+sizeOfFp])
   780  	offset += sizeOfFp
   781  	z.D0.C2.B0.A0.SetBytes(e[offset : offset+sizeOfFp])
   782  	offset += sizeOfFp
   783  	z.D0.C2.B0.A1.SetBytes(e[offset : offset+sizeOfFp])
   784  	offset += sizeOfFp
   785  	z.D0.C2.B1.A0.SetBytes(e[offset : offset+sizeOfFp])
   786  	offset += sizeOfFp
   787  	z.D0.C2.B1.A1.SetBytes(e[offset : offset+sizeOfFp])
   788  	offset += sizeOfFp
   789  	z.D1.C0.B0.A0.SetBytes(e[offset : offset+sizeOfFp])
   790  	offset += sizeOfFp
   791  	z.D1.C0.B0.A1.SetBytes(e[offset : offset+sizeOfFp])
   792  	offset += sizeOfFp
   793  	z.D1.C0.B1.A0.SetBytes(e[offset : offset+sizeOfFp])
   794  	offset += sizeOfFp
   795  	z.D1.C0.B1.A1.SetBytes(e[offset : offset+sizeOfFp])
   796  	offset += sizeOfFp
   797  	z.D1.C1.B0.A0.SetBytes(e[offset : offset+sizeOfFp])
   798  	offset += sizeOfFp
   799  	z.D1.C1.B0.A1.SetBytes(e[offset : offset+sizeOfFp])
   800  	offset += sizeOfFp
   801  	z.D1.C1.B1.A0.SetBytes(e[offset : offset+sizeOfFp])
   802  	offset += sizeOfFp
   803  	z.D1.C1.B1.A1.SetBytes(e[offset : offset+sizeOfFp])
   804  	offset += sizeOfFp
   805  	z.D1.C2.B0.A0.SetBytes(e[offset : offset+sizeOfFp])
   806  	offset += sizeOfFp
   807  	z.D1.C2.B0.A1.SetBytes(e[offset : offset+sizeOfFp])
   808  	offset += sizeOfFp
   809  	z.D1.C2.B1.A0.SetBytes(e[offset : offset+sizeOfFp])
   810  	offset += sizeOfFp
   811  	z.D1.C2.B1.A1.SetBytes(e[offset : offset+sizeOfFp])
   812  
   813  	return nil
   814  }
   815  
   816  // IsInSubGroup ensures GT/E24 is in correct subgroup
   817  func (z *E24) IsInSubGroup() bool {
   818  	var a, b E24
   819  
   820  	// check z^(phi_k(p)) == 1
   821  	a.FrobeniusQuad(z)
   822  	b.FrobeniusQuad(&a).Mul(&b, z)
   823  
   824  	if !a.Equal(&b) {
   825  		return false
   826  	}
   827  
   828  	// check z^(p+1-t) == 1
   829  	a.Frobenius(z)
   830  	b.Expt(z)
   831  
   832  	return a.Equal(&b)
   833  }
   834  
   835  // CompressTorus GT/E24 element to half its size
   836  // z must be in the cyclotomic subgroup
   837  // i.e. z^(p⁴-p²+1)=1
   838  // e.g. GT
   839  // "COMPRESSION IN FINITE FIELDS AND TORUS-BASED CRYPTOGRAPHY", K. RUBIN AND A. SILVERBERG
   840  // z.C1 == 0 only when z ∈ {-1,1}
   841  func (z *E24) CompressTorus() (E12, error) {
   842  
   843  	if z.D1.IsZero() {
   844  		return E12{}, errors.New("invalid input")
   845  	}
   846  
   847  	var res, tmp, one E12
   848  	one.SetOne()
   849  	tmp.Inverse(&z.D1)
   850  	res.Add(&z.D0, &one).
   851  		Mul(&res, &tmp)
   852  
   853  	return res, nil
   854  }
   855  
   856  // BatchCompressTorus GT/E24 elements to half their size
   857  // using a batch inversion
   858  func BatchCompressTorus(x []E24) ([]E12, error) {
   859  
   860  	n := len(x)
   861  	if n == 0 {
   862  		return []E12{}, errors.New("invalid input size")
   863  	}
   864  
   865  	var one E12
   866  	one.SetOne()
   867  	res := make([]E12, n)
   868  
   869  	for i := 0; i < n; i++ {
   870  		res[i].Set(&x[i].D1)
   871  		//  throw an error if any of the x[i].C1 is 0
   872  		if res[i].IsZero() {
   873  			return []E12{}, errors.New("invalid input")
   874  		}
   875  	}
   876  
   877  	t := BatchInvertE12(res) // costs 1 inverse
   878  
   879  	for i := 0; i < n; i++ {
   880  		res[i].Add(&x[i].D0, &one).
   881  			Mul(&res[i], &t[i])
   882  	}
   883  
   884  	return res, nil
   885  }
   886  
   887  // DecompressTorus GT/E24 a compressed element
   888  // element must be in the cyclotomic subgroup
   889  // "COMPRESSION IN FINITE FIELDS AND TORUS-BASED CRYPTOGRAPHY", K. RUBIN AND A. SILVERBERG
   890  func (z *E12) DecompressTorus() E24 {
   891  
   892  	var res, num, denum E24
   893  	num.D0.Set(z)
   894  	num.D1.SetOne()
   895  	denum.D0.Set(z)
   896  	denum.D1.SetOne().Neg(&denum.D1)
   897  	res.Inverse(&denum).
   898  		Mul(&res, &num)
   899  
   900  	return res
   901  }
   902  
   903  // BatchDecompressTorus GT/E24 compressed elements
   904  // using a batch inversion
   905  func BatchDecompressTorus(x []E12) ([]E24, error) {
   906  
   907  	n := len(x)
   908  	if n == 0 {
   909  		return []E24{}, errors.New("invalid input size")
   910  	}
   911  
   912  	res := make([]E24, n)
   913  	num := make([]E24, n)
   914  	denum := make([]E24, n)
   915  
   916  	for i := 0; i < n; i++ {
   917  		num[i].D0.Set(&x[i])
   918  		num[i].D1.SetOne()
   919  		denum[i].D0.Set(&x[i])
   920  		denum[i].D1.SetOne().Neg(&denum[i].D1)
   921  	}
   922  
   923  	denum = BatchInvertE24(denum) // costs 1 inverse
   924  
   925  	for i := 0; i < n; i++ {
   926  		res[i].Mul(&num[i], &denum[i])
   927  	}
   928  
   929  	return res, nil
   930  }