github.com/consensys/gnark-crypto@v0.14.0/ecc/bw6-633/internal/fptower/e3.go (about)

     1  // Copyright 2020 ConsenSys AG
     2  //
     3  // You may obtain a copy of the License at
     4  //
     5  //     http://www.apache.org/licenses/LICENSE-2.0
     6  //
     7  // Unless required by applicable law or agreed to in writing, software
     8  // distributed under the License is distributed on an "AS IS" BASIS,
     9  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    10  // See the License for the specific language governing permissions and
    11  // limitations under the License.
    12  
    13  package fptower
    14  
    15  import (
    16  	"github.com/consensys/gnark-crypto/ecc/bw6-633/fp"
    17  )
    18  
    19  // E3 is a degree-three finite field extension of fp2
    20  type E3 struct {
    21  	A0, A1, A2 fp.Element
    22  }
    23  
    24  // Equal returns true if z equals x, false otherwise
    25  // TODO can this be deleted?  Should be able to use == operator instead
    26  func (z *E3) Equal(x *E3) bool {
    27  	return z.A0.Equal(&x.A0) && z.A1.Equal(&x.A1) && z.A2.Equal(&x.A2)
    28  }
    29  
    30  // SetString sets a E3 elmt from stringf
    31  func (z *E3) SetString(s1, s2, s3 string) *E3 {
    32  	z.A0.SetString(s1)
    33  	z.A1.SetString(s2)
    34  	z.A2.SetString(s3)
    35  	return z
    36  }
    37  
    38  // SetZero sets an E3 elmt to zero
    39  func (z *E3) SetZero() *E3 {
    40  	z.A0.SetZero()
    41  	z.A1.SetZero()
    42  	z.A2.SetZero()
    43  	return z
    44  }
    45  
    46  // Clone returns a copy of self
    47  func (z *E3) Clone() *E3 {
    48  	return &E3{
    49  		A0: z.A0,
    50  		A1: z.A1,
    51  		A2: z.A2,
    52  	}
    53  }
    54  
    55  // Set Sets a E3 elmt form another E3 elmt
    56  func (z *E3) Set(x *E3) *E3 {
    57  	z.A0 = x.A0
    58  	z.A1 = x.A1
    59  	z.A2 = x.A2
    60  	return z
    61  }
    62  
    63  // SetOne sets z to 1 in Montgomery form and returns z
    64  func (z *E3) SetOne() *E3 {
    65  	z.A0.SetOne()
    66  	z.A1.SetZero()
    67  	z.A2.SetZero()
    68  	return z
    69  }
    70  
    71  // SetRandom sets z to a random elmt
    72  func (z *E3) SetRandom() (*E3, error) {
    73  	if _, err := z.A0.SetRandom(); err != nil {
    74  		return nil, err
    75  	}
    76  	if _, err := z.A1.SetRandom(); err != nil {
    77  		return nil, err
    78  	}
    79  	if _, err := z.A2.SetRandom(); err != nil {
    80  		return nil, err
    81  	}
    82  	return z, nil
    83  }
    84  
    85  // IsZero returns true if z is zero, false otherwise
    86  func (z *E3) IsZero() bool {
    87  	return z.A0.IsZero() && z.A1.IsZero() && z.A2.IsZero()
    88  }
    89  
    90  // IsOne returns true if z is one, false otherwise
    91  func (z *E3) IsOne() bool {
    92  	return z.A0.IsOne() && z.A1.IsZero() && z.A2.IsZero()
    93  }
    94  
    95  // Neg negates the E3 number
    96  func (z *E3) Neg(x *E3) *E3 {
    97  	z.A0.Neg(&x.A0)
    98  	z.A1.Neg(&x.A1)
    99  	z.A2.Neg(&x.A2)
   100  	return z
   101  }
   102  
   103  // Add adds two elements of E3
   104  func (z *E3) Add(x, y *E3) *E3 {
   105  	z.A0.Add(&x.A0, &y.A0)
   106  	z.A1.Add(&x.A1, &y.A1)
   107  	z.A2.Add(&x.A2, &y.A2)
   108  	return z
   109  }
   110  
   111  // Sub subtracts two elements of E3
   112  func (z *E3) Sub(x, y *E3) *E3 {
   113  	z.A0.Sub(&x.A0, &y.A0)
   114  	z.A1.Sub(&x.A1, &y.A1)
   115  	z.A2.Sub(&x.A2, &y.A2)
   116  	return z
   117  }
   118  
   119  // Double doubles an element in E3
   120  func (z *E3) Double(x *E3) *E3 {
   121  	z.A0.Double(&x.A0)
   122  	z.A1.Double(&x.A1)
   123  	z.A2.Double(&x.A2)
   124  	return z
   125  }
   126  
   127  // String puts E3 elmt in string form
   128  func (z *E3) String() string {
   129  	return (z.A0.String() + "+(" + z.A1.String() + ")*u+(" + z.A2.String() + ")*u**2")
   130  }
   131  
   132  // MulByElement multiplies an element in E3 by an element in fp
   133  func (z *E3) MulByElement(x *E3, y *fp.Element) *E3 {
   134  	var yCopy fp.Element
   135  	yCopy.Set(y)
   136  	z.A0.Mul(&x.A0, &yCopy)
   137  	z.A1.Mul(&x.A1, &yCopy)
   138  	z.A2.Mul(&x.A2, &yCopy)
   139  	return z
   140  }
   141  
   142  // MulBy12 multiplication by sparse element (0,b1,b2)
   143  func (x *E3) MulBy12(b1, b2 *fp.Element) *E3 {
   144  	var t1, t2, c0, tmp, c1, c2 fp.Element
   145  	t1.Mul(&x.A1, b1)
   146  	t2.Mul(&x.A2, b2)
   147  	c0.Add(&x.A1, &x.A2)
   148  	tmp.Add(b1, b2)
   149  	c0.Mul(&c0, &tmp)
   150  	c0.Sub(&c0, &t1)
   151  	c0.Sub(&c0, &t2)
   152  	c0.MulByNonResidue(&c0)
   153  	c1.Add(&x.A0, &x.A1)
   154  	c1.Mul(&c1, b1)
   155  	c1.Sub(&c1, &t1)
   156  	tmp.MulByNonResidue(&t2)
   157  	c1.Add(&c1, &tmp)
   158  	tmp.Add(&x.A0, &x.A2)
   159  	c2.Mul(b2, &tmp)
   160  	c2.Sub(&c2, &t2)
   161  	c2.Add(&c2, &t1)
   162  
   163  	x.A0 = c0
   164  	x.A1 = c1
   165  	x.A2 = c2
   166  
   167  	return x
   168  }
   169  
   170  // MulBy01 multiplication by sparse element (c0,c1,0)
   171  func (z *E3) MulBy01(c0, c1 *fp.Element) *E3 {
   172  
   173  	var a, b, tmp, t0, t1, t2 fp.Element
   174  
   175  	a.Mul(&z.A0, c0)
   176  	b.Mul(&z.A1, c1)
   177  
   178  	tmp.Add(&z.A1, &z.A2)
   179  	t0.Mul(c1, &tmp)
   180  	t0.Sub(&t0, &b)
   181  	t0.MulByNonResidue(&t0)
   182  	t0.Add(&t0, &a)
   183  
   184  	tmp.Add(&z.A0, &z.A2)
   185  	t2.Mul(c0, &tmp)
   186  	t2.Sub(&t2, &a)
   187  	t2.Add(&t2, &b)
   188  
   189  	t1.Add(c0, c1)
   190  	tmp.Add(&z.A0, &z.A1)
   191  	t1.Mul(&t1, &tmp)
   192  	t1.Sub(&t1, &a)
   193  	t1.Sub(&t1, &b)
   194  
   195  	z.A0.Set(&t0)
   196  	z.A1.Set(&t1)
   197  	z.A2.Set(&t2)
   198  
   199  	return z
   200  }
   201  
   202  // MulBy1 multiplication of E6 by sparse element (0, c1, 0)
   203  func (z *E3) MulBy1(c1 *fp.Element) *E3 {
   204  
   205  	var b, tmp, t0, t1 fp.Element
   206  	b.Mul(&z.A1, c1)
   207  
   208  	tmp.Add(&z.A1, &z.A2)
   209  	t0.Mul(c1, &tmp)
   210  	t0.Sub(&t0, &b)
   211  	t0.MulByNonResidue(&t0)
   212  
   213  	tmp.Add(&z.A0, &z.A1)
   214  	t1.Mul(c1, &tmp)
   215  	t1.Sub(&t1, &b)
   216  
   217  	z.A0.Set(&t0)
   218  	z.A1.Set(&t1)
   219  	z.A2.Set(&b)
   220  
   221  	return z
   222  }
   223  
   224  // Mul sets z to the E3-product of x,y, returns z
   225  func (z *E3) Mul(x, y *E3) *E3 {
   226  	// Karatsuba method for cubic extensions
   227  	// https://eprint.iacr.org/2006/471.pdf (section 4)
   228  	var t0, t1, t2, c0, c1, c2, tmp fp.Element
   229  	t0.Mul(&x.A0, &y.A0)
   230  	t1.Mul(&x.A1, &y.A1)
   231  	t2.Mul(&x.A2, &y.A2)
   232  
   233  	c0.Add(&x.A1, &x.A2)
   234  	tmp.Add(&y.A1, &y.A2)
   235  	c0.Mul(&c0, &tmp).Sub(&c0, &t1).Sub(&c0, &t2).MulByNonResidue(&c0).Add(&c0, &t0)
   236  
   237  	c1.Add(&x.A0, &x.A1)
   238  	tmp.Add(&y.A0, &y.A1)
   239  	c1.Mul(&c1, &tmp).Sub(&c1, &t0).Sub(&c1, &t1)
   240  	tmp.MulByNonResidue(&t2)
   241  	c1.Add(&c1, &tmp)
   242  
   243  	tmp.Add(&x.A0, &x.A2)
   244  	c2.Add(&y.A0, &y.A2).Mul(&c2, &tmp).Sub(&c2, &t0).Sub(&c2, &t2).Add(&c2, &t1)
   245  
   246  	z.A0.Set(&c0)
   247  	z.A1.Set(&c1)
   248  	z.A2.Set(&c2)
   249  
   250  	return z
   251  }
   252  
   253  // MulAssign sets z to the E3-product of z,y, returns z
   254  func (z *E3) MulAssign(x *E3) *E3 {
   255  	z.Mul(z, x)
   256  	return z
   257  }
   258  
   259  // Square sets z to the E3-product of x,x, returns z
   260  func (z *E3) Square(x *E3) *E3 {
   261  
   262  	// Algorithm 16 from https://eprint.iacr.org/2010/354.pdf
   263  	var c4, c5, c1, c2, c3, c0 fp.Element
   264  	c4.Mul(&x.A0, &x.A1).Double(&c4)
   265  	c5.Square(&x.A2)
   266  	c1.MulByNonResidue(&c5).Add(&c1, &c4)
   267  	c2.Sub(&c4, &c5)
   268  	c3.Square(&x.A0)
   269  	c4.Sub(&x.A0, &x.A1).Add(&c4, &x.A2)
   270  	c5.Mul(&x.A1, &x.A2).Double(&c5)
   271  	c4.Square(&c4)
   272  	c0.MulByNonResidue(&c5).Add(&c0, &c3)
   273  	z.A2.Add(&c2, &c4).Add(&z.A2, &c5).Sub(&z.A2, &c3)
   274  	z.A0.Set(&c0)
   275  	z.A1.Set(&c1)
   276  
   277  	return z
   278  }
   279  
   280  // MulByNonResidue mul x by (0,1,0)
   281  func (z *E3) MulByNonResidue(x *E3) *E3 {
   282  	z.A2, z.A1, z.A0 = x.A1, x.A0, x.A2
   283  	z.A0.MulByNonResidue(&z.A0)
   284  	return z
   285  }
   286  
   287  // Inverse an element in E3
   288  //
   289  // if x == 0, sets and returns z = x
   290  func (z *E3) Inverse(x *E3) *E3 {
   291  	// Algorithm 17 from https://eprint.iacr.org/2010/354.pdf
   292  	// step 9 is wrong in the paper it's t1-t4
   293  	var t0, t1, t2, t3, t4, t5, t6, c0, c1, c2, d1, d2 fp.Element
   294  	t0.Square(&x.A0)
   295  	t1.Square(&x.A1)
   296  	t2.Square(&x.A2)
   297  	t3.Mul(&x.A0, &x.A1)
   298  	t4.Mul(&x.A0, &x.A2)
   299  	t5.Mul(&x.A1, &x.A2)
   300  	c0.MulByNonResidue(&t5).Neg(&c0).Add(&c0, &t0)
   301  	c1.MulByNonResidue(&t2).Sub(&c1, &t3)
   302  	c2.Sub(&t1, &t4)
   303  	t6.Mul(&x.A0, &c0)
   304  	d1.Mul(&x.A2, &c1)
   305  	d2.Mul(&x.A1, &c2)
   306  	d1.Add(&d1, &d2).MulByNonResidue(&d1)
   307  	t6.Add(&t6, &d1)
   308  	t6.Inverse(&t6)
   309  	z.A0.Mul(&c0, &t6)
   310  	z.A1.Mul(&c1, &t6)
   311  	z.A2.Mul(&c2, &t6)
   312  
   313  	return z
   314  }
   315  
   316  // BatchInvertE3 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 BatchInvertE3(a []E3) []E3 {
   321  	res := make([]E3, len(a))
   322  	if len(a) == 0 {
   323  		return res
   324  	}
   325  
   326  	zeroes := make([]bool, len(a))
   327  	var accumulator E3
   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  }