github.com/consensys/gnark-crypto@v0.14.0/ecc/bls24-317/internal/fptower/e12.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  
    21  // E12 is a degree three finite field extension of fp4
    22  type E12 struct {
    23  	C0, C1, C2 E4
    24  }
    25  
    26  // Equal returns true if z equals x, false otherwise
    27  func (z *E12) Equal(x *E12) bool {
    28  	return z.C0.Equal(&x.C0) && z.C1.Equal(&x.C1) && z.C2.Equal(&x.C2)
    29  }
    30  
    31  // String puts E12 elmt in string form
    32  func (z *E12) String() string {
    33  	return (z.C0.String() + "+(" + z.C1.String() + ")*w+(" + z.C2.String() + ")*w**2")
    34  }
    35  
    36  // SetString sets a E12 elmt from stringf
    37  func (z *E12) SetString(s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11 string) *E12 {
    38  	z.C0.SetString(s0, s1, s2, s3)
    39  	z.C1.SetString(s4, s5, s6, s7)
    40  	z.C2.SetString(s8, s9, s10, s11)
    41  	return z
    42  }
    43  
    44  // Set Sets a E12 elmt form another E12 elmt
    45  func (z *E12) Set(x *E12) *E12 {
    46  	z.C0 = x.C0
    47  	z.C1 = x.C1
    48  	z.C2 = x.C2
    49  	return z
    50  }
    51  
    52  // SetOne sets z to 1 in Montgomery form and returns z
    53  func (z *E12) SetOne() *E12 {
    54  	*z = E12{}
    55  	z.C0.B0.A0.SetOne()
    56  	return z
    57  }
    58  
    59  // SetRandom sets z to a random elmt
    60  func (z *E12) SetRandom() (*E12, error) {
    61  	if _, err := z.C0.SetRandom(); err != nil {
    62  		return nil, err
    63  	}
    64  	if _, err := z.C1.SetRandom(); err != nil {
    65  		return nil, err
    66  	}
    67  	if _, err := z.C2.SetRandom(); err != nil {
    68  		return nil, err
    69  	}
    70  	return z, nil
    71  }
    72  
    73  // IsZero returns true if z is zero, false otherwise
    74  func (z *E12) IsZero() bool {
    75  	return z.C0.IsZero() && z.C1.IsZero() && z.C2.IsZero()
    76  }
    77  
    78  // IsOne returns true if z is one, false otherwise
    79  func (z *E12) IsOne() bool {
    80  	return z.C0.IsOne() && z.C1.IsZero() && z.C2.IsZero()
    81  }
    82  
    83  // Add adds two elements of E12
    84  func (z *E12) Add(x, y *E12) *E12 {
    85  	z.C0.Add(&x.C0, &y.C0)
    86  	z.C1.Add(&x.C1, &y.C1)
    87  	z.C2.Add(&x.C2, &y.C2)
    88  	return z
    89  }
    90  
    91  // Neg negates the E12 number
    92  func (z *E12) Neg(x *E12) *E12 {
    93  	z.C0.Neg(&x.C0)
    94  	z.C1.Neg(&x.C1)
    95  	z.C2.Neg(&x.C2)
    96  	return z
    97  }
    98  
    99  // Sub subtracts two elements of E12
   100  func (z *E12) Sub(x, y *E12) *E12 {
   101  	z.C0.Sub(&x.C0, &y.C0)
   102  	z.C1.Sub(&x.C1, &y.C1)
   103  	z.C2.Sub(&x.C2, &y.C2)
   104  	return z
   105  }
   106  
   107  // Double doubles an element in E12
   108  func (z *E12) Double(x *E12) *E12 {
   109  	z.C0.Double(&x.C0)
   110  	z.C1.Double(&x.C1)
   111  	z.C2.Double(&x.C2)
   112  	return z
   113  }
   114  
   115  // MulByNonResidue mul x by (0,1,0)
   116  func (z *E12) MulByNonResidue(x *E12) *E12 {
   117  	z.C2, z.C1, z.C0 = x.C1, x.C0, x.C2
   118  	z.C0.MulByNonResidue(&z.C0)
   119  	return z
   120  }
   121  
   122  // Mul sets z to the E12 product of x,y, returns z
   123  func (z *E12) Mul(x, y *E12) *E12 {
   124  	// Algorithm 13 from https://eprint.iacr.org/2010/354.pdf
   125  	var t0, t1, t2, c0, c1, c2, tmp E4
   126  	t0.Mul(&x.C0, &y.C0)
   127  	t1.Mul(&x.C1, &y.C1)
   128  	t2.Mul(&x.C2, &y.C2)
   129  
   130  	c0.Add(&x.C1, &x.C2)
   131  	tmp.Add(&y.C1, &y.C2)
   132  	c0.Mul(&c0, &tmp).Sub(&c0, &t1).Sub(&c0, &t2).MulByNonResidue(&c0).Add(&c0, &t0)
   133  
   134  	c1.Add(&x.C0, &x.C1)
   135  	tmp.Add(&y.C0, &y.C1)
   136  	c1.Mul(&c1, &tmp).Sub(&c1, &t0).Sub(&c1, &t1)
   137  	tmp.MulByNonResidue(&t2)
   138  	c1.Add(&c1, &tmp)
   139  
   140  	tmp.Add(&x.C0, &x.C2)
   141  	c2.Add(&y.C0, &y.C2).Mul(&c2, &tmp).Sub(&c2, &t0).Sub(&c2, &t2).Add(&c2, &t1)
   142  
   143  	z.C0.Set(&c0)
   144  	z.C1.Set(&c1)
   145  	z.C2.Set(&c2)
   146  
   147  	return z
   148  }
   149  
   150  // Square sets z to the E12 product of x,x, returns z
   151  func (z *E12) Square(x *E12) *E12 {
   152  
   153  	// Algorithm 16 from https://eprint.iacr.org/2010/354.pdf
   154  	var c4, c5, c1, c2, c3, c0 E4
   155  	c4.Mul(&x.C0, &x.C1).Double(&c4)
   156  	c5.Square(&x.C2)
   157  	c1.MulByNonResidue(&c5).Add(&c1, &c4)
   158  	c2.Sub(&c4, &c5)
   159  	c3.Square(&x.C0)
   160  	c4.Sub(&x.C0, &x.C1).Add(&c4, &x.C2)
   161  	c5.Mul(&x.C1, &x.C2).Double(&c5)
   162  	c4.Square(&c4)
   163  	c0.MulByNonResidue(&c5).Add(&c0, &c3)
   164  	z.C2.Add(&c2, &c4).Add(&z.C2, &c5).Sub(&z.C2, &c3)
   165  	z.C0.Set(&c0)
   166  	z.C1.Set(&c1)
   167  
   168  	return z
   169  }
   170  
   171  // Inverse an element in E12
   172  //
   173  // if x == 0, sets and returns z = x
   174  func (z *E12) Inverse(x *E12) *E12 {
   175  	// Algorithm 17 from https://eprint.iacr.org/2010/354.pdf
   176  	// step 9 is wrong in the paper it's t1-t4
   177  	var t0, t1, t2, t3, t4, t5, t6, c0, c1, c2, d1, d2 E4
   178  	t0.Square(&x.C0)
   179  	t1.Square(&x.C1)
   180  	t2.Square(&x.C2)
   181  	t3.Mul(&x.C0, &x.C1)
   182  	t4.Mul(&x.C0, &x.C2)
   183  	t5.Mul(&x.C1, &x.C2)
   184  	c0.MulByNonResidue(&t5).Sub(&t0, &c0)
   185  	c1.MulByNonResidue(&t2).Sub(&c1, &t3)
   186  	c2.Sub(&t1, &t4)
   187  	t6.Mul(&x.C0, &c0)
   188  	d1.Mul(&x.C2, &c1)
   189  	d2.Mul(&x.C1, &c2)
   190  	d1.Add(&d1, &d2).MulByNonResidue(&d1)
   191  	t6.Add(&t6, &d1)
   192  	t6.Inverse(&t6)
   193  	z.C0.Mul(&c0, &t6)
   194  	z.C1.Mul(&c1, &t6)
   195  	z.C2.Mul(&c2, &t6)
   196  
   197  	return z
   198  }
   199  
   200  // BatchInvertE12 returns a new slice with every element in a inverted.
   201  // It uses Montgomery batch inversion trick.
   202  //
   203  // if a[i] == 0, returns result[i] = a[i]
   204  func BatchInvertE12(a []E12) []E12 {
   205  	res := make([]E12, len(a))
   206  	if len(a) == 0 {
   207  		return res
   208  	}
   209  
   210  	zeroes := make([]bool, len(a))
   211  	var accumulator E12
   212  	accumulator.SetOne()
   213  
   214  	for i := 0; i < len(a); i++ {
   215  		if a[i].IsZero() {
   216  			zeroes[i] = true
   217  			continue
   218  		}
   219  		res[i].Set(&accumulator)
   220  		accumulator.Mul(&accumulator, &a[i])
   221  	}
   222  
   223  	accumulator.Inverse(&accumulator)
   224  
   225  	for i := len(a) - 1; i >= 0; i-- {
   226  		if zeroes[i] {
   227  			continue
   228  		}
   229  		res[i].Mul(&res[i], &accumulator)
   230  		accumulator.Mul(&accumulator, &a[i])
   231  	}
   232  
   233  	return res
   234  }
   235  
   236  // Exp sets z=xᵏ (mod q¹²) and returns it
   237  // uses 2-bits windowed method
   238  func (z *E12) Exp(x E12, k *big.Int) *E12 {
   239  	if k.IsUint64() && k.Uint64() == 0 {
   240  		return z.SetOne()
   241  	}
   242  
   243  	e := k
   244  	if k.Sign() == -1 {
   245  		// negative k, we invert
   246  		// if k < 0: xᵏ (mod q¹²) == (x⁻¹)ᵏ (mod q¹²)
   247  		x.Inverse(&x)
   248  
   249  		// we negate k in a temp big.Int since
   250  		// Int.Bit(_) of k and -k is different
   251  		e = bigIntPool.Get().(*big.Int)
   252  		defer bigIntPool.Put(e)
   253  		e.Neg(k)
   254  	}
   255  
   256  	var res E12
   257  	var ops [3]E12
   258  
   259  	res.SetOne()
   260  	ops[0].Set(&x)
   261  	ops[1].Square(&ops[0])
   262  	ops[2].Set(&ops[0]).Mul(&ops[2], &ops[1])
   263  
   264  	b := e.Bytes()
   265  	for i := range b {
   266  		w := b[i]
   267  		mask := byte(0xc0)
   268  		for j := 0; j < 4; j++ {
   269  			res.Square(&res).Square(&res)
   270  			c := (w & mask) >> (6 - 2*j)
   271  			if c != 0 {
   272  				res.Mul(&res, &ops[c-1])
   273  			}
   274  			mask = mask >> 2
   275  		}
   276  	}
   277  	z.Set(&res)
   278  
   279  	return z
   280  }
   281  
   282  // InverseUnitary inverse a unitary element
   283  func (z *E12) InverseUnitary(x *E12) *E12 {
   284  	return z.Conjugate(x)
   285  }
   286  
   287  // Conjugate sets z to x conjugated and returns z
   288  func (z *E12) Conjugate(x *E12) *E12 {
   289  	z.C0.Conjugate(&x.C0)
   290  	z.C1.Conjugate(&x.C1).Neg(&z.C1)
   291  	z.C2.Conjugate(&x.C2)
   292  	return z
   293  }
   294  
   295  // MulBy12 multiplication by sparse element (0,b1,b2)
   296  func (x *E12) MulBy12(b1, b2 *E4) *E12 {
   297  	var t1, t2, c0, tmp, c1, c2 E4
   298  	t1.Mul(&x.C1, b1)
   299  	t2.Mul(&x.C2, b2)
   300  	c0.Add(&x.C1, &x.C2)
   301  	tmp.Add(b1, b2)
   302  	c0.Mul(&c0, &tmp)
   303  	c0.Sub(&c0, &t1)
   304  	c0.Sub(&c0, &t2)
   305  	c0.MulByNonResidue(&c0)
   306  	c1.Add(&x.C0, &x.C1)
   307  	c1.Mul(&c1, b1)
   308  	c1.Sub(&c1, &t1)
   309  	tmp.MulByNonResidue(&t2)
   310  	c1.Add(&c1, &tmp)
   311  	tmp.Add(&x.C0, &x.C2)
   312  	c2.Mul(b2, &tmp)
   313  	c2.Sub(&c2, &t2)
   314  	c2.Add(&c2, &t1)
   315  
   316  	x.C0 = c0
   317  	x.C1 = c1
   318  	x.C2 = c2
   319  
   320  	return x
   321  }
   322  
   323  // MulBy01 multiplication by sparse element (c0,c1,0)
   324  func (z *E12) MulBy01(c0, c1 *E4) *E12 {
   325  
   326  	var a, b, tmp, t0, t1, t2 E4
   327  
   328  	a.Mul(&z.C0, c0)
   329  	b.Mul(&z.C1, c1)
   330  
   331  	tmp.Add(&z.C1, &z.C2)
   332  	t0.Mul(c1, &tmp)
   333  	t0.Sub(&t0, &b)
   334  	t0.MulByNonResidue(&t0)
   335  	t0.Add(&t0, &a)
   336  
   337  	tmp.Add(&z.C0, &z.C2)
   338  	t2.Mul(c0, &tmp)
   339  	t2.Sub(&t2, &a)
   340  	t2.Add(&t2, &b)
   341  
   342  	t1.Add(c0, c1)
   343  	tmp.Add(&z.C0, &z.C1)
   344  	t1.Mul(&t1, &tmp)
   345  	t1.Sub(&t1, &a)
   346  	t1.Sub(&t1, &b)
   347  
   348  	z.C0.Set(&t0)
   349  	z.C1.Set(&t1)
   350  	z.C2.Set(&t2)
   351  
   352  	return z
   353  }
   354  
   355  // MulByE2 multiplies an element in E12 by an element in E2
   356  func (z *E12) MulByE2(x *E12, y *E4) *E12 {
   357  	var yCopy E4
   358  	yCopy.Set(y)
   359  	z.C0.Mul(&x.C0, &yCopy)
   360  	z.C1.Mul(&x.C1, &yCopy)
   361  	z.C2.Mul(&x.C2, &yCopy)
   362  	return z
   363  }
   364  
   365  // MulBy1 multiplication of E12 by sparse element (0, c1, 0)
   366  func (z *E12) MulBy1(c1 *E4) *E12 {
   367  
   368  	var b, tmp, t0, t1 E4
   369  	b.Mul(&z.C1, c1)
   370  
   371  	tmp.Add(&z.C1, &z.C2)
   372  	t0.Mul(c1, &tmp)
   373  	t0.Sub(&t0, &b)
   374  	t0.MulByNonResidue(&t0)
   375  
   376  	tmp.Add(&z.C0, &z.C1)
   377  	t1.Mul(c1, &tmp)
   378  	t1.Sub(&t1, &b)
   379  
   380  	z.C0.Set(&t0)
   381  	z.C1.Set(&t1)
   382  	z.C2.Set(&b)
   383  
   384  	return z
   385  }