github.com/consensys/gnark-crypto@v0.14.0/ecc/bls24-315/internal/fptower/e4.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  	"math/big"
    19  
    20  	"github.com/consensys/gnark-crypto/ecc/bls24-315/fp"
    21  )
    22  
    23  // E4 is a degree two finite field extension of fp2
    24  type E4 struct {
    25  	B0, B1 E2
    26  }
    27  
    28  // Equal returns true if z equals x, false otherwise
    29  func (z *E4) Equal(x *E4) bool {
    30  	return z.B0.Equal(&x.B0) && z.B1.Equal(&x.B1)
    31  }
    32  
    33  // Cmp compares (lexicographic order) z and x and returns:
    34  //
    35  //	-1 if z <  x
    36  //	 0 if z == x
    37  //	+1 if z >  x
    38  func (z *E4) Cmp(x *E4) int {
    39  	if a1 := z.B1.Cmp(&x.B1); a1 != 0 {
    40  		return a1
    41  	}
    42  	return z.B0.Cmp(&x.B0)
    43  }
    44  
    45  // LexicographicallyLargest returns true if this element is strictly lexicographically
    46  // larger than its negation, false otherwise
    47  func (z *E4) LexicographicallyLargest() bool {
    48  	// adapted from github.com/zkcrypto/bls12_381
    49  	if z.B1.IsZero() {
    50  		return z.B0.LexicographicallyLargest()
    51  	}
    52  	return z.B1.LexicographicallyLargest()
    53  }
    54  
    55  // String puts E4 in string form
    56  func (z *E4) String() string {
    57  	return (z.B0.String() + "+(" + z.B1.String() + ")*v")
    58  }
    59  
    60  // SetString sets a E4 from string
    61  func (z *E4) SetString(s0, s1, s2, s3 string) *E4 {
    62  	z.B0.SetString(s0, s1)
    63  	z.B1.SetString(s2, s3)
    64  	return z
    65  }
    66  
    67  // Set copies x into z and returns z
    68  func (z *E4) Set(x *E4) *E4 {
    69  	z.B0 = x.B0
    70  	z.B1 = x.B1
    71  	return z
    72  }
    73  
    74  // SetZero sets an E4 elmt to zero
    75  func (z *E4) SetZero() *E4 {
    76  	z.B0.SetZero()
    77  	z.B1.SetZero()
    78  	return z
    79  }
    80  
    81  // SetOne sets z to 1 in Montgomery form and returns z
    82  func (z *E4) SetOne() *E4 {
    83  	*z = E4{}
    84  	z.B0.A0.SetOne()
    85  	return z
    86  }
    87  
    88  // MulByElement multiplies an element in E4 by an element in fp
    89  func (z *E4) MulByElement(x *E4, y *fp.Element) *E4 {
    90  	var yCopy fp.Element
    91  	yCopy.Set(y)
    92  	z.B0.MulByElement(&x.B0, &yCopy)
    93  	z.B1.MulByElement(&x.B1, &yCopy)
    94  	return z
    95  }
    96  
    97  // Add set z=x+y in E4 and return z
    98  func (z *E4) Add(x, y *E4) *E4 {
    99  	z.B0.Add(&x.B0, &y.B0)
   100  	z.B1.Add(&x.B1, &y.B1)
   101  	return z
   102  }
   103  
   104  // Sub sets z to x sub y and return z
   105  func (z *E4) Sub(x, y *E4) *E4 {
   106  	z.B0.Sub(&x.B0, &y.B0)
   107  	z.B1.Sub(&x.B1, &y.B1)
   108  	return z
   109  }
   110  
   111  // Double sets z=2*x and returns z
   112  func (z *E4) Double(x *E4) *E4 {
   113  	z.B0.Double(&x.B0)
   114  	z.B1.Double(&x.B1)
   115  	return z
   116  }
   117  
   118  // Neg negates an E4 element
   119  func (z *E4) Neg(x *E4) *E4 {
   120  	z.B0.Neg(&x.B0)
   121  	z.B1.Neg(&x.B1)
   122  	return z
   123  }
   124  
   125  // SetRandom used only in tests
   126  func (z *E4) SetRandom() (*E4, error) {
   127  	if _, err := z.B0.SetRandom(); err != nil {
   128  		return nil, err
   129  	}
   130  	if _, err := z.B1.SetRandom(); err != nil {
   131  		return nil, err
   132  	}
   133  	return z, nil
   134  }
   135  
   136  // IsZero returns true if z is zero, false otherwise
   137  func (z *E4) IsZero() bool {
   138  	return z.B0.IsZero() && z.B1.IsZero()
   139  }
   140  
   141  // IsOne returns true if z is one, false otherwise
   142  func (z *E4) IsOne() bool {
   143  	return z.B0.IsOne() && z.B1.IsZero()
   144  }
   145  
   146  // MulByNonResidue mul x by (0,1)
   147  func (z *E4) MulByNonResidue(x *E4) *E4 {
   148  	z.B1, z.B0 = x.B0, x.B1
   149  	z.B0.MulByNonResidue(&z.B0)
   150  	return z
   151  }
   152  
   153  // MulByNonResidueInv mul x by (0,1)^{-1}
   154  func (z *E4) MulByNonResidueInv(x *E4) *E4 {
   155  	a := x.B1
   156  	var uInv E2
   157  	uInv.A1.SetString("6108483493771298205388567675447533806912846525679192205394505462405828322019437284165171866703")
   158  	z.B1.Mul(&x.B0, &uInv)
   159  	z.B0 = a
   160  	return z
   161  }
   162  
   163  // Mul set z=x*y in E4 and return z
   164  func (z *E4) Mul(x, y *E4) *E4 {
   165  	var a, b, c E2
   166  	a.Add(&x.B0, &x.B1)
   167  	b.Add(&y.B0, &y.B1)
   168  	a.Mul(&a, &b)
   169  	b.Mul(&x.B0, &y.B0)
   170  	c.Mul(&x.B1, &y.B1)
   171  	z.B1.Sub(&a, &b).Sub(&z.B1, &c)
   172  	z.B0.MulByNonResidue(&c).Add(&z.B0, &b)
   173  	return z
   174  }
   175  
   176  // Square set z=x*x in E4 and return z
   177  func (z *E4) Square(x *E4) *E4 {
   178  
   179  	//Algorithm 22 from https://eprint.iacr.org/2010/354.pdf
   180  	var c0, c2, c3 E2
   181  	c0.Sub(&x.B0, &x.B1)
   182  	c3.MulByNonResidue(&x.B1).Sub(&x.B0, &c3)
   183  	c2.Mul(&x.B0, &x.B1)
   184  	c0.Mul(&c0, &c3).Add(&c0, &c2)
   185  	z.B1.Double(&c2)
   186  	c2.MulByNonResidue(&c2)
   187  	z.B0.Add(&c0, &c2)
   188  
   189  	return z
   190  }
   191  
   192  // Inverse set z to the inverse of x in E4 and return z
   193  //
   194  // if x == 0, sets and returns z = x
   195  func (z *E4) Inverse(x *E4) *E4 {
   196  	// Algorithm 23 from https://eprint.iacr.org/2010/354.pdf
   197  
   198  	var t0, t1, tmp E2
   199  	t0.Square(&x.B0)
   200  	t1.Square(&x.B1)
   201  	tmp.MulByNonResidue(&t1)
   202  	t0.Sub(&t0, &tmp)
   203  	t1.Inverse(&t0)
   204  	z.B0.Mul(&x.B0, &t1)
   205  	z.B1.Mul(&x.B1, &t1).Neg(&z.B1)
   206  
   207  	return z
   208  }
   209  
   210  // Exp sets z=xᵏ (mod q⁴) and returns it
   211  func (z *E4) Exp(x E4, k *big.Int) *E4 {
   212  	if k.IsUint64() && k.Uint64() == 0 {
   213  		return z.SetOne()
   214  	}
   215  
   216  	e := k
   217  	if k.Sign() == -1 {
   218  		// negative k, we invert
   219  		// if k < 0: xᵏ (mod q⁴) == (x⁻¹)ᵏ (mod q⁴)
   220  		x.Inverse(&x)
   221  
   222  		// we negate k in a temp big.Int since
   223  		// Int.Bit(_) of k and -k is different
   224  		e = bigIntPool.Get().(*big.Int)
   225  		defer bigIntPool.Put(e)
   226  		e.Neg(k)
   227  	}
   228  
   229  	z.SetOne()
   230  	b := e.Bytes()
   231  	for i := 0; i < len(b); i++ {
   232  		w := b[i]
   233  		for j := 0; j < 8; j++ {
   234  			z.Square(z)
   235  			if (w & (0b10000000 >> j)) != 0 {
   236  				z.Mul(z, &x)
   237  			}
   238  		}
   239  	}
   240  
   241  	return z
   242  }
   243  
   244  // Conjugate set z to x conjugated and return z
   245  func (z *E4) Conjugate(x *E4) *E4 {
   246  	z.B0 = x.B0
   247  	z.B1.Neg(&x.B1)
   248  	return z
   249  }
   250  
   251  func (z *E4) Halve() {
   252  
   253  	z.B0.A0.Halve()
   254  	z.B0.A1.Halve()
   255  	z.B1.A0.Halve()
   256  	z.B1.A1.Halve()
   257  }
   258  
   259  // norm sets x to the norm of z
   260  func (z *E4) norm(x *E2) {
   261  	var tmp E2
   262  	tmp.Square(&z.B1).MulByNonResidue(&tmp)
   263  	x.Square(&z.B0).Sub(x, &tmp)
   264  }
   265  
   266  // Legendre returns the Legendre symbol of z
   267  func (z *E4) Legendre() int {
   268  	var n E2
   269  	z.norm(&n)
   270  	return n.Legendre()
   271  }
   272  
   273  // Sqrt sets z to the square root of and returns z
   274  // The function does not test whether the square root
   275  // exists or not, it's up to the caller to call
   276  // Legendre beforehand.
   277  // cf https://eprint.iacr.org/2012/685.pdf (algo 10)
   278  func (z *E4) Sqrt(x *E4) *E4 {
   279  
   280  	// precomputation
   281  	var b, c, d, e, f, x0, _g E4
   282  	var _b, o E2
   283  
   284  	// c must be a non square (works for p=1 mod 12 hence 1 mod 4, only bls377 has such a p currently)
   285  	c.B1.SetOne()
   286  
   287  	q := fp.Modulus()
   288  	var exp, one big.Int
   289  	one.SetUint64(1)
   290  	exp.Mul(q, q).Sub(&exp, &one).Rsh(&exp, 1)
   291  	d.Exp(c, &exp)
   292  	e.Mul(&d, &c).Inverse(&e)
   293  	f.Mul(&d, &c).Square(&f)
   294  
   295  	// computation
   296  	exp.Rsh(&exp, 1)
   297  	b.Exp(*x, &exp)
   298  	b.norm(&_b)
   299  	o.SetOne()
   300  	if _b.Equal(&o) {
   301  		x0.Square(&b).Mul(&x0, x)
   302  		_b.Set(&x0.B0).Sqrt(&_b)
   303  		_g.B0.Set(&_b)
   304  		z.Conjugate(&b).Mul(z, &_g)
   305  		return z
   306  	}
   307  	x0.Square(&b).Mul(&x0, x).Mul(&x0, &f)
   308  	_b.Set(&x0.B0).Sqrt(&_b)
   309  	_g.B0.Set(&_b)
   310  	z.Conjugate(&b).Mul(z, &_g).Mul(z, &e)
   311  
   312  	return z
   313  }
   314  
   315  // BatchInvertE4 returns a new slice with every element inverted.
   316  // Uses Montgomery batch inversion trick
   317  //
   318  // if a[i] == 0, returns result[i] = a[i]
   319  func BatchInvertE4(a []E4) []E4 {
   320  	res := make([]E4, len(a))
   321  	if len(a) == 0 {
   322  		return res
   323  	}
   324  
   325  	zeroes := make([]bool, len(a))
   326  	var accumulator E4
   327  	accumulator.SetOne()
   328  
   329  	for i := 0; i < len(a); i++ {
   330  		if a[i].IsZero() {
   331  			zeroes[i] = true
   332  			continue
   333  		}
   334  		res[i].Set(&accumulator)
   335  		accumulator.Mul(&accumulator, &a[i])
   336  	}
   337  
   338  	accumulator.Inverse(&accumulator)
   339  
   340  	for i := len(a) - 1; i >= 0; i-- {
   341  		if zeroes[i] {
   342  			continue
   343  		}
   344  		res[i].Mul(&res[i], &accumulator)
   345  		accumulator.Mul(&accumulator, &a[i])
   346  	}
   347  
   348  	return res
   349  }
   350  
   351  func (z *E4) Div(x *E4, y *E4) *E4 {
   352  	var r E4
   353  	r.Inverse(y).Mul(x, &r)
   354  	return z.Set(&r)
   355  }