github.com/consensys/gnark-crypto@v0.14.0/ecc/bls24-315/internal/fptower/e2.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  // E2 is a degree two finite field extension of fp.Element
    24  type E2 struct {
    25  	A0, A1 fp.Element
    26  }
    27  
    28  // Equal returns true if z equals x, false otherwise
    29  func (z *E2) Equal(x *E2) bool {
    30  	return z.A0.Equal(&x.A0) && z.A1.Equal(&x.A1)
    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 *E2) Cmp(x *E2) int {
    39  	if a1 := z.A1.Cmp(&x.A1); a1 != 0 {
    40  		return a1
    41  	}
    42  	return z.A0.Cmp(&x.A0)
    43  }
    44  
    45  // LexicographicallyLargest returns true if this element is strictly lexicographically
    46  // larger than its negation, false otherwise
    47  func (z *E2) LexicographicallyLargest() bool {
    48  	// adapted from github.com/zkcrypto/bls12_381
    49  	if z.A1.IsZero() {
    50  		return z.A0.LexicographicallyLargest()
    51  	}
    52  	return z.A1.LexicographicallyLargest()
    53  }
    54  
    55  // SetString sets a E2 element from strings
    56  func (z *E2) SetString(s1, s2 string) *E2 {
    57  	z.A0.SetString(s1)
    58  	z.A1.SetString(s2)
    59  	return z
    60  }
    61  
    62  // SetZero sets an E2 elmt to zero
    63  func (z *E2) SetZero() *E2 {
    64  	z.A0.SetZero()
    65  	z.A1.SetZero()
    66  	return z
    67  }
    68  
    69  // Set sets an E2 from x
    70  func (z *E2) Set(x *E2) *E2 {
    71  	z.A0 = x.A0
    72  	z.A1 = x.A1
    73  	return z
    74  }
    75  
    76  // SetOne sets z to 1 in Montgomery form and returns z
    77  func (z *E2) SetOne() *E2 {
    78  	z.A0.SetOne()
    79  	z.A1.SetZero()
    80  	return z
    81  }
    82  
    83  // SetRandom sets a0 and a1 to random values
    84  func (z *E2) SetRandom() (*E2, error) {
    85  	if _, err := z.A0.SetRandom(); err != nil {
    86  		return nil, err
    87  	}
    88  	if _, err := z.A1.SetRandom(); err != nil {
    89  		return nil, err
    90  	}
    91  	return z, nil
    92  }
    93  
    94  // IsZero returns true if z is zero, false otherwise
    95  func (z *E2) IsZero() bool {
    96  	return z.A0.IsZero() && z.A1.IsZero()
    97  }
    98  
    99  // IsOne returns true if z is one, false otherwise
   100  func (z *E2) IsOne() bool {
   101  	return z.A0.IsOne() && z.A1.IsZero()
   102  }
   103  
   104  // Add adds two elements of E2
   105  func (z *E2) Add(x, y *E2) *E2 {
   106  	addE2(z, x, y)
   107  	return z
   108  }
   109  
   110  // Sub two elements of E2
   111  func (z *E2) Sub(x, y *E2) *E2 {
   112  	subE2(z, x, y)
   113  	return z
   114  }
   115  
   116  // Double doubles an E2 element
   117  func (z *E2) Double(x *E2) *E2 {
   118  	doubleE2(z, x)
   119  	return z
   120  }
   121  
   122  // Neg negates an E2 element
   123  func (z *E2) Neg(x *E2) *E2 {
   124  	negE2(z, x)
   125  	return z
   126  }
   127  
   128  // String implements Stringer interface for fancy printing
   129  func (z *E2) String() string {
   130  	return (z.A0.String() + "+" + z.A1.String() + "*u")
   131  }
   132  
   133  // MulByElement multiplies an element in E2 by an element in fp
   134  func (z *E2) MulByElement(x *E2, y *fp.Element) *E2 {
   135  	var yCopy fp.Element
   136  	yCopy.Set(y)
   137  	z.A0.Mul(&x.A0, &yCopy)
   138  	z.A1.Mul(&x.A1, &yCopy)
   139  	return z
   140  }
   141  
   142  // Conjugate conjugates an element in E2
   143  func (z *E2) Conjugate(x *E2) *E2 {
   144  	z.A0 = x.A0
   145  	z.A1.Neg(&x.A1)
   146  	return z
   147  }
   148  
   149  // Legendre returns the Legendre symbol of z
   150  func (z *E2) Legendre() int {
   151  	var n fp.Element
   152  	z.norm(&n)
   153  	return n.Legendre()
   154  }
   155  
   156  // Exp sets z=xᵏ (mod q²) and returns it
   157  func (z *E2) Exp(x E2, k *big.Int) *E2 {
   158  	if k.IsUint64() && k.Uint64() == 0 {
   159  		return z.SetOne()
   160  	}
   161  
   162  	e := k
   163  	if k.Sign() == -1 {
   164  		// negative k, we invert
   165  		// if k < 0: xᵏ (mod q²) == (x⁻¹)ᵏ (mod q²)
   166  		x.Inverse(&x)
   167  
   168  		// we negate k in a temp big.Int since
   169  		// Int.Bit(_) of k and -k is different
   170  		e = bigIntPool.Get().(*big.Int)
   171  		defer bigIntPool.Put(e)
   172  		e.Neg(k)
   173  	}
   174  
   175  	z.SetOne()
   176  	b := e.Bytes()
   177  	for i := 0; i < len(b); i++ {
   178  		w := b[i]
   179  		for j := 0; j < 8; j++ {
   180  			z.Square(z)
   181  			if (w & (0b10000000 >> j)) != 0 {
   182  				z.Mul(z, &x)
   183  			}
   184  		}
   185  	}
   186  
   187  	return z
   188  }
   189  
   190  // Sqrt sets z to the square root of and returns z
   191  // The function does not test whether the square root
   192  // exists or not, it's up to the caller to call
   193  // Legendre beforehand.
   194  // cf https://eprint.iacr.org/2012/685.pdf (algo 10)
   195  func (z *E2) Sqrt(x *E2) *E2 {
   196  
   197  	// precomputation
   198  	var b, c, d, e, f, x0 E2
   199  	var _b, o fp.Element
   200  
   201  	// c must be a non square (works for p=1 mod 12 hence 1 mod 4, only bls377 has such a p currently)
   202  	c.A1.SetOne()
   203  
   204  	q := fp.Modulus()
   205  	var exp, one big.Int
   206  	one.SetUint64(1)
   207  	exp.Set(q).Sub(&exp, &one).Rsh(&exp, 1)
   208  	d.Exp(c, &exp)
   209  	e.Mul(&d, &c).Inverse(&e)
   210  	f.Mul(&d, &c).Square(&f)
   211  
   212  	// computation
   213  	exp.Rsh(&exp, 1)
   214  	b.Exp(*x, &exp)
   215  	b.norm(&_b)
   216  	o.SetOne()
   217  	if _b.Equal(&o) {
   218  		x0.Square(&b).Mul(&x0, x)
   219  		_b.Set(&x0.A0).Sqrt(&_b)
   220  		z.Conjugate(&b).MulByElement(z, &_b)
   221  		return z
   222  	}
   223  	x0.Square(&b).Mul(&x0, x).Mul(&x0, &f)
   224  	_b.Set(&x0.A0).Sqrt(&_b)
   225  	z.Conjugate(&b).MulByElement(z, &_b).Mul(z, &e)
   226  
   227  	return z
   228  }
   229  
   230  func (z *E2) Div(x *E2, y *E2) *E2 {
   231  	var r E2
   232  	r.Inverse(y).Mul(x, &r)
   233  	return z.Set(&r)
   234  }