github.com/consensys/gnark-crypto@v0.14.0/ecc/bls24-317/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-317/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 sets z=x+y in E4 and returns 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-y and returns 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)⁻¹
   154  func (z *E4) MulByNonResidueInv(x *E4) *E4 {
   155  	a := x.B1
   156  	var uInv E2
   157  	uInv.A0.SetString("68196535552147955757549882954137028530972556060709796988605069651952986598616012809013078365526")
   158  	uInv.A1.SetString("68196535552147955757549882954137028530972556060709796988605069651952986598616012809013078365525")
   159  	z.B1.Mul(&x.B0, &uInv)
   160  	z.B0 = a
   161  	return z
   162  }
   163  
   164  // Mul sets z=x*y in E4 and returns z
   165  func (z *E4) Mul(x, y *E4) *E4 {
   166  	var a, b, c E2
   167  	a.Add(&x.B0, &x.B1)
   168  	b.Add(&y.B0, &y.B1)
   169  	a.Mul(&a, &b)
   170  	b.Mul(&x.B0, &y.B0)
   171  	c.Mul(&x.B1, &y.B1)
   172  	z.B1.Sub(&a, &b).Sub(&z.B1, &c)
   173  	z.B0.MulByNonResidue(&c).Add(&z.B0, &b)
   174  	return z
   175  }
   176  
   177  // Square sets z=x*x in E4 and returns z
   178  func (z *E4) Square(x *E4) *E4 {
   179  
   180  	//Algorithm 22 from https://eprint.iacr.org/2010/354.pdf
   181  	var c0, c2, c3 E2
   182  	c0.Sub(&x.B0, &x.B1)
   183  	c3.MulByNonResidue(&x.B1).Sub(&x.B0, &c3)
   184  	c2.Mul(&x.B0, &x.B1)
   185  	c0.Mul(&c0, &c3).Add(&c0, &c2)
   186  	z.B1.Double(&c2)
   187  	c2.MulByNonResidue(&c2)
   188  	z.B0.Add(&c0, &c2)
   189  
   190  	return z
   191  }
   192  
   193  // Inverse sets z to the inverse of x in E4 and returns z
   194  //
   195  // if x == 0, sets and returns z = x
   196  func (z *E4) Inverse(x *E4) *E4 {
   197  	// Algorithm 23 from https://eprint.iacr.org/2010/354.pdf
   198  
   199  	var t0, t1, tmp E2
   200  	t0.Square(&x.B0)
   201  	t1.Square(&x.B1)
   202  	tmp.MulByNonResidue(&t1)
   203  	t0.Sub(&t0, &tmp)
   204  	t1.Inverse(&t0)
   205  	z.B0.Mul(&x.B0, &t1)
   206  	z.B1.Mul(&x.B1, &t1).Neg(&z.B1)
   207  
   208  	return z
   209  }
   210  
   211  // Exp sets z=xᵏ (mod q⁴) and returns it
   212  func (z *E4) Exp(x E4, k *big.Int) *E4 {
   213  	if k.IsUint64() && k.Uint64() == 0 {
   214  		return z.SetOne()
   215  	}
   216  
   217  	e := k
   218  	if k.Sign() == -1 {
   219  		// negative k, we invert
   220  		// if k < 0: xᵏ (mod q⁴) == (x⁻¹)ᵏ (mod q⁴)
   221  		x.Inverse(&x)
   222  
   223  		// we negate k in a temp big.Int since
   224  		// Int.Bit(_) of k and -k is different
   225  		e = bigIntPool.Get().(*big.Int)
   226  		defer bigIntPool.Put(e)
   227  		e.Neg(k)
   228  	}
   229  
   230  	z.SetOne()
   231  	b := e.Bytes()
   232  	for i := 0; i < len(b); i++ {
   233  		w := b[i]
   234  		for j := 0; j < 8; j++ {
   235  			z.Square(z)
   236  			if (w & (0b10000000 >> j)) != 0 {
   237  				z.Mul(z, &x)
   238  			}
   239  		}
   240  	}
   241  
   242  	return z
   243  }
   244  
   245  // Conjugate sets z to x conjugated and returns z
   246  func (z *E4) Conjugate(x *E4) *E4 {
   247  	z.B0 = x.B0
   248  	z.B1.Neg(&x.B1)
   249  	return z
   250  }
   251  
   252  func (z *E4) Halve() {
   253  
   254  	z.B0.A0.Halve()
   255  	z.B0.A1.Halve()
   256  	z.B1.A0.Halve()
   257  	z.B1.A1.Halve()
   258  }
   259  
   260  // norm sets x to the norm of z
   261  func (z *E4) norm(x *E2) {
   262  	var tmp E2
   263  	tmp.Square(&z.B1).MulByNonResidue(&tmp)
   264  	x.Square(&z.B0).Sub(x, &tmp)
   265  }
   266  
   267  // Legendre returns the Legendre symbol of z
   268  func (z *E4) Legendre() int {
   269  	var n E2
   270  	z.norm(&n)
   271  	return n.Legendre()
   272  }
   273  
   274  // Sqrt sets z to the square root of and returns z
   275  // The function does not test whether the square root
   276  // exists or not, it's up to the caller to call
   277  // Legendre beforehand.
   278  // cf https://eprint.iacr.org/2012/685.pdf (algo 10)
   279  func (z *E4) Sqrt(x *E4) *E4 {
   280  
   281  	// precomputation
   282  	var b, c, d, e, f, x0, _g E4
   283  	var _b, o E2
   284  
   285  	// c must be a non square (works for p=1 mod 12 hence 1 mod 4, only bls377 has such a p currently)
   286  	c.B1.SetOne()
   287  
   288  	q := fp.Modulus()
   289  	var exp, one big.Int
   290  	one.SetUint64(1)
   291  	exp.Mul(q, q).Sub(&exp, &one).Rsh(&exp, 1)
   292  	d.Exp(c, &exp)
   293  	e.Mul(&d, &c).Inverse(&e)
   294  	f.Mul(&d, &c).Square(&f)
   295  
   296  	// computation
   297  	exp.Rsh(&exp, 1)
   298  	b.Exp(*x, &exp)
   299  	b.norm(&_b)
   300  	o.SetOne()
   301  	if _b.Equal(&o) {
   302  		x0.Square(&b).Mul(&x0, x)
   303  		_b.Set(&x0.B0).Sqrt(&_b)
   304  		_g.B0.Set(&_b)
   305  		z.Conjugate(&b).Mul(z, &_g)
   306  		return z
   307  	}
   308  	x0.Square(&b).Mul(&x0, x).Mul(&x0, &f)
   309  	_b.Set(&x0.B0).Sqrt(&_b)
   310  	_g.B0.Set(&_b)
   311  	z.Conjugate(&b).Mul(z, &_g).Mul(z, &e)
   312  
   313  	return z
   314  }
   315  
   316  // BatchInvertE4 returns a new slice with every element in a inverted.
   317  // It uses Montgomery batch inversion trick.
   318  //
   319  // if a[i] == 0, returns result[i] = a[i]
   320  func BatchInvertE4(a []E4) []E4 {
   321  	res := make([]E4, len(a))
   322  	if len(a) == 0 {
   323  		return res
   324  	}
   325  
   326  	zeroes := make([]bool, len(a))
   327  	var accumulator E4
   328  	accumulator.SetOne()
   329  
   330  	for i := 0; i < len(a); i++ {
   331  		if a[i].IsZero() {
   332  			zeroes[i] = true
   333  			continue
   334  		}
   335  		res[i].Set(&accumulator)
   336  		accumulator.Mul(&accumulator, &a[i])
   337  	}
   338  
   339  	accumulator.Inverse(&accumulator)
   340  
   341  	for i := len(a) - 1; i >= 0; i-- {
   342  		if zeroes[i] {
   343  			continue
   344  		}
   345  		res[i].Mul(&res[i], &accumulator)
   346  		accumulator.Mul(&accumulator, &a[i])
   347  	}
   348  
   349  	return res
   350  }
   351  
   352  // Div divides an element in E4 by an element in E4
   353  func (z *E4) Div(x *E4, y *E4) *E4 {
   354  	var r E4
   355  	r.Inverse(y).Mul(x, &r)
   356  	return z.Set(&r)
   357  }