github.com/hellobchain/third_party@v0.0.0-20230331131523-deb0478a2e52/hyperledger/fabric-amcl/amcl/FP256BN/FP4.go (about)

     1  /*
     2  Licensed to the Apache Software Foundation (ASF) under one
     3  or more contributor license agreements.  See the NOTICE file
     4  distributed with this work for additional information
     5  regarding copyright ownership.  The ASF licenses this file
     6  to you under the Apache License, Version 2.0 (the
     7  "License"); you may not use this file except in compliance
     8  with the License.  You may obtain a copy of the License at
     9  
    10    http://www.apache.org/licenses/LICENSE-2.0
    11  
    12  Unless required by applicable law or agreed to in writing,
    13  software distributed under the License is distributed on an
    14  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    15  KIND, either express or implied.  See the License for the
    16  specific language governing permissions and limitations
    17  under the License.
    18  */
    19  
    20  /* Finite Field arithmetic  Fp^4 functions */
    21  
    22  /* FP4 elements are of the form a+ib, where i is sqrt(-1+sqrt(-1)) */
    23  
    24  package FP256BN
    25  
    26  
    27  
    28  type FP4 struct {
    29  	a *FP2
    30  	b *FP2
    31  }
    32  
    33  /* Constructors */
    34  func NewFP4int(a int) *FP4 {
    35  	F:=new(FP4)
    36  	F.a=NewFP2int(a)
    37  	F.b=NewFP2int(0)
    38  	return F
    39  }
    40  
    41  func NewFP4copy(x *FP4) *FP4 {
    42  	F:=new(FP4)
    43  	F.a=NewFP2copy(x.a)
    44  	F.b=NewFP2copy(x.b)
    45  	return F
    46  }
    47  
    48  func NewFP4fp2s(c *FP2,d *FP2) *FP4 {
    49  	F:=new(FP4)
    50  	F.a=NewFP2copy(c)
    51  	F.b=NewFP2copy(d)
    52  	return F
    53  }
    54  
    55  func NewFP4fp2(c *FP2) *FP4 {
    56  	F:=new(FP4)
    57  	F.a=NewFP2copy(c)
    58  	F.b=NewFP2int(0)
    59  	return F
    60  }
    61  
    62  /* reduce all components of this mod Modulus */
    63  func (F *FP4) reduce() {
    64  	F.a.reduce()
    65  	F.b.reduce()
    66  }
    67  
    68  /* normalise all components of this mod Modulus */
    69  func (F *FP4) norm() {
    70  	F.a.norm()
    71  	F.b.norm()
    72  }
    73  
    74  /* test this==0 ? */
    75  func (F *FP4) iszilch() bool {
    76  	//F.reduce()
    77  	return F.a.iszilch() && F.b.iszilch()
    78  }
    79  
    80  /* Conditional move */
    81  func (F *FP4) cmove(g *FP4,d int) {
    82  	F.a.cmove(g.a,d)
    83  	F.b.cmove(g.b,d)
    84  }
    85  
    86  /* test this==1 ? */
    87  func (F *FP4) isunity() bool {
    88  	one:=NewFP2int(1)
    89  	return F.a.Equals(one) && F.b.iszilch()
    90  }
    91  
    92  /* test is w real? That is in a+ib test b is zero */
    93  func (F *FP4) isreal() bool {
    94  	return F.b.iszilch()
    95  }
    96  /* extract real part a */
    97  func (F *FP4) real() *FP2 {
    98  	return F.a
    99  }
   100  
   101  func (F *FP4) geta() *FP2 {
   102  	return F.a
   103  }
   104  /* extract imaginary part b */
   105  func (F *FP4) getb() *FP2 {
   106  	return F.b
   107  }
   108  /* test this=x? */
   109  func (F *FP4) Equals(x *FP4) bool {
   110  	return (F.a.Equals(x.a) && F.b.Equals(x.b))
   111  }
   112  
   113  /* copy this=x */
   114  func (F *FP4) copy(x *FP4) {
   115  	F.a.copy(x.a)
   116  	F.b.copy(x.b)
   117  }
   118  /* set this=0 */
   119  func (F *FP4) zero() {
   120  	F.a.zero()
   121  	F.b.zero()
   122  	}
   123  /* set this=1 */
   124  func (F *FP4) one() {
   125  	F.a.one()
   126  	F.b.zero()
   127  }
   128  
   129  /* set this=-this */
   130  func (F *FP4) neg() {
   131  	F.norm()
   132  	m:=NewFP2copy(F.a);
   133  	t:=NewFP2int(0)
   134  	m.add(F.b)
   135  	m.neg()
   136  	//m.norm()
   137  	t.copy(m); t.add(F.b)
   138  	F.b.copy(m)
   139  	F.b.add(F.a)
   140  	F.a.copy(t)
   141  	F.norm()
   142  }
   143  
   144  /* this=conjugate(this) */
   145  func (F *FP4) conj() {
   146  	F.b.neg(); F.norm()
   147  }
   148  
   149  /* this=-conjugate(this) */
   150  func (F *FP4) nconj() {
   151  	F.a.neg(); F.norm()
   152  }
   153  
   154  /* this+=x */
   155  func (F *FP4) add(x *FP4) {
   156  	F.a.add(x.a)
   157  	F.b.add(x.b)
   158  }
   159  /* this-=x */
   160  func (F *FP4) sub(x *FP4) {
   161  	m:=NewFP4copy(x)
   162  	m.neg()
   163  	F.add(m)
   164  }
   165  
   166  /* this-=x */
   167  func (F *FP4) rsub(x *FP4) {
   168  	F.neg()
   169  	F.add(x)
   170  }
   171  
   172  /* this*=s where s is FP2 */
   173  func (F *FP4) pmul(s *FP2) {
   174  	F.a.mul(s)
   175  	F.b.mul(s)
   176  }
   177  
   178  /* this*=s where s is FP2 */
   179  func (F *FP4) qmul(s *FP) {
   180  	F.a.pmul(s)
   181  	F.b.pmul(s)
   182  }
   183  
   184  /* this*=c where c is int */
   185  func (F *FP4) imul(c int) {
   186  	F.a.imul(c)
   187  	F.b.imul(c)
   188  }
   189  
   190  /* this*=this */	
   191  func (F *FP4) sqr() {
   192  //	F.norm()
   193  
   194  	t1:=NewFP2copy(F.a)
   195  	t2:=NewFP2copy(F.b)
   196  	t3:=NewFP2copy(F.a)
   197  
   198  	t3.mul(F.b)
   199  	t1.add(F.b)
   200  	t2.mul_ip()
   201  
   202  	t2.add(F.a)
   203  
   204  	t1.norm(); t2.norm()
   205  
   206  	F.a.copy(t1)
   207  
   208  	F.a.mul(t2)
   209  
   210  	t2.copy(t3)
   211  	t2.mul_ip()
   212  	t2.add(t3); t2.norm()
   213  	t2.neg()
   214  	F.a.add(t2)
   215  
   216  	F.b.copy(t3)
   217  	F.b.add(t3)
   218  
   219  	F.norm()
   220  }
   221  
   222  /* this*=y */
   223  func (F *FP4) mul(y *FP4) {
   224  //	F.norm()
   225  
   226  	t1:=NewFP2copy(F.a)
   227  	t2:=NewFP2copy(F.b)
   228  	t3:=NewFP2int(0)
   229  	t4:=NewFP2copy(F.b)
   230  
   231  	t1.mul(y.a)
   232  	t2.mul(y.b)
   233  	t3.copy(y.b)
   234  	t3.add(y.a)
   235  	t4.add(F.a)
   236  
   237  	t3.norm(); t4.norm();
   238  
   239  	t4.mul(t3)
   240  
   241  	t3.copy(t1)
   242  	t3.neg()
   243  	t4.add(t3)
   244  	t4.norm()
   245  
   246  	t3.copy(t2);
   247  	t3.neg()
   248  	F.b.copy(t4)
   249  	F.b.add(t3)
   250  
   251  	t2.mul_ip()
   252  	F.a.copy(t2)
   253  	F.a.add(t1)
   254  
   255  	F.norm()
   256  }
   257  
   258  /* convert this to hex string */
   259  func (F *FP4) toString() string {
   260  	return ("["+F.a.toString()+","+F.b.toString()+"]")
   261  }
   262  
   263  /* this=1/this */
   264  func (F *FP4) inverse() {
   265  //	F.norm()
   266  
   267  	t1:=NewFP2copy(F.a)
   268  	t2:=NewFP2copy(F.b)
   269  
   270  	t1.sqr()
   271  	t2.sqr()
   272  	t2.mul_ip(); t2.norm()
   273  	t1.sub(t2)
   274  	t1.inverse()
   275  	F.a.mul(t1)
   276  	t1.neg(); t1.norm()
   277  	F.b.mul(t1)
   278  }
   279  
   280  /* this*=i where i = sqrt(-1+sqrt(-1)) */
   281  func (F *FP4) times_i() {
   282  //	F.norm()
   283  	s:=NewFP2copy(F.b)
   284  	t:=NewFP2copy(F.b)
   285  	s.times_i()
   286  	t.add(s)
   287  //	t.norm();
   288  	F.b.copy(F.a)
   289  	F.a.copy(t)
   290  	F.norm()
   291  }
   292  
   293  /* this=this^p using Frobenius */
   294  func (F *FP4) frob(f *FP2) {
   295  	F.a.conj()
   296  	F.b.conj()
   297  	F.b.mul(f)
   298  }
   299  
   300  /* this=this^e */
   301  func (F *FP4) pow(e *BIG) *FP4 {
   302  	F.norm()
   303  	e.norm()
   304  	w:=NewFP4copy(F)
   305  	z:=NewBIGcopy(e)
   306  	r:=NewFP4int(1)
   307  	for true {
   308  		bt:=z.parity()
   309  		z.fshr(1)
   310  		if bt==1 {r.mul(w)}
   311  		if z.iszilch() {break}
   312  		w.sqr()
   313  	}
   314  	r.reduce()
   315  	return r
   316  }
   317  
   318  /* XTR xtr_a function */
   319  func (F *FP4) xtr_A(w *FP4,y *FP4,z *FP4) {
   320  	r:=NewFP4copy(w)
   321  	t:=NewFP4copy(w)
   322  	//y.norm()
   323  	r.sub(y); r.norm()
   324  	r.pmul(F.a)
   325  	t.add(y); t.norm()
   326  	t.pmul(F.b)
   327  	t.times_i()
   328  
   329  	F.copy(r)
   330  	F.add(t)
   331  	F.add(z)
   332  
   333  	F.norm()
   334  }
   335  
   336  /* XTR xtr_d function */
   337  func (F *FP4) xtr_D() {
   338  	w:=NewFP4copy(F)
   339  	F.sqr(); w.conj()
   340  	w.add(w); w.norm()
   341  	F.sub(w)
   342  	F.reduce()
   343  }
   344  
   345  /* r=x^n using XTR method on traces of FP12s */
   346  func (F *FP4) xtr_pow(n *BIG) *FP4 {
   347  	a:=NewFP4int(3)
   348  	b:=NewFP4copy(F)
   349  	c:=NewFP4copy(b)
   350  	c.xtr_D()
   351  	t:=NewFP4int(0)
   352  	r:=NewFP4int(0)
   353  
   354  	n.norm()
   355  	par:=n.parity()
   356  	v:=NewBIGcopy(n); v.fshr(1)
   357  	if (par==0) {v.dec(1); v.norm()}
   358  
   359  	nb:=v.nbits();
   360  	for i:=nb-1;i>=0;i-- {
   361  		if v.bit(i)!=1 {
   362  			t.copy(b)
   363  			F.conj()
   364  			c.conj()
   365  			b.xtr_A(a,F,c)
   366  			F.conj()
   367  			c.copy(t)
   368  			c.xtr_D()
   369  			a.xtr_D()
   370  		} else {
   371  			t.copy(a); t.conj()
   372  			a.copy(b)
   373  			a.xtr_D()
   374  			b.xtr_A(c,F,t)
   375  			c.xtr_D()
   376  		}
   377  	}
   378  	if par==0 {
   379  		r.copy(c)
   380  	} else {r.copy(b)}
   381  	r.reduce()
   382  	return r
   383  }
   384  
   385  /* r=ck^a.cl^n using XTR double exponentiation method on traces of FP12s. See Stam thesis. */
   386  func (F *FP4) xtr_pow2(ck *FP4,ckml *FP4,ckm2l *FP4,a *BIG,b *BIG) *FP4 {
   387  	a.norm(); b.norm()
   388  	e:=NewBIGcopy(a)
   389  	d:=NewBIGcopy(b)
   390  	w:=NewBIGint(0)
   391  
   392  	cu:=NewFP4copy(ck)  // can probably be passed in w/o copying
   393  	cv:=NewFP4copy(F);
   394  	cumv:=NewFP4copy(ckml)
   395  	cum2v:=NewFP4copy(ckm2l)
   396  	r:=NewFP4int(0)
   397  	t:=NewFP4int(0)
   398  
   399  	f2:=0
   400  	for (d.parity()==0 && e.parity()==0) {
   401  		d.fshr(1)
   402  		e.fshr(1)
   403  		f2++
   404  	}
   405  
   406  	for comp(d,e)!=0 {
   407  		if comp(d,e)>0 {
   408  			w.copy(e); w.imul(4); w.norm()
   409  			if comp(d,w)<=0 {
   410  				w.copy(d); d.copy(e)
   411  				e.rsub(w); e.norm()
   412  
   413  				t.copy(cv);
   414  				t.xtr_A(cu,cumv,cum2v)
   415  				cum2v.copy(cumv);
   416  				cum2v.conj()
   417  				cumv.copy(cv)
   418  				cv.copy(cu)
   419  				cu.copy(t)
   420  			} else {
   421  					if (d.parity()==0) {
   422  					d.fshr(1)
   423  					r.copy(cum2v); r.conj()
   424  					t.copy(cumv)
   425  					t.xtr_A(cu,cv,r)
   426  					cum2v.copy(cumv)
   427  					cum2v.xtr_D()
   428  					cumv.copy(t)
   429  					cu.xtr_D()
   430  				} else {
   431  					if (e.parity()==1) {
   432  						d.sub(e); d.norm()
   433  						d.fshr(1)
   434  						t.copy(cv)
   435  						t.xtr_A(cu,cumv,cum2v)
   436  						cu.xtr_D()
   437  						cum2v.copy(cv)
   438  						cum2v.xtr_D()
   439  						cum2v.conj()
   440  						cv.copy(t)
   441  					} else {
   442  						w.copy(d)
   443  						d.copy(e); d.fshr(1)
   444  						e.copy(w)
   445  						t.copy(cumv)
   446  						t.xtr_D()
   447  						cumv.copy(cum2v); cumv.conj()
   448  						cum2v.copy(t); cum2v.conj()
   449  						t.copy(cv)
   450  						t.xtr_D()
   451  						cv.copy(cu)
   452  						cu.copy(t)
   453  					}
   454  				}
   455  			}
   456  		}
   457  		if comp(d,e)<0 {
   458  			w.copy(d); w.imul(4); w.norm()
   459  			if comp(e,w)<=0 {
   460  				e.sub(d); e.norm()
   461  				t.copy(cv)
   462  				t.xtr_A(cu,cumv,cum2v)
   463  				cum2v.copy(cumv)
   464  				cumv.copy(cu)
   465  				cu.copy(t)
   466  			} else {
   467  				if (e.parity()==0) {
   468  					w.copy(d)
   469  					d.copy(e); d.fshr(1)
   470  					e.copy(w)
   471  					t.copy(cumv)
   472  					t.xtr_D()
   473  					cumv.copy(cum2v); cumv.conj()
   474  					cum2v.copy(t); cum2v.conj()
   475  					t.copy(cv)
   476  					t.xtr_D()
   477  					cv.copy(cu)
   478  					cu.copy(t)
   479  				} else {
   480  					if (d.parity()==1) {
   481  						w.copy(e)
   482  						e.copy(d)
   483  						w.sub(d); w.norm()
   484  						d.copy(w); d.fshr(1)
   485  						t.copy(cv)
   486  						t.xtr_A(cu,cumv,cum2v)
   487  						cumv.conj()
   488  						cum2v.copy(cu)
   489  						cum2v.xtr_D()
   490  						cum2v.conj()
   491  						cu.copy(cv)
   492  						cu.xtr_D()
   493  						cv.copy(t)
   494  					} else {
   495  						d.fshr(1)
   496  						r.copy(cum2v); r.conj()
   497  						t.copy(cumv)
   498  						t.xtr_A(cu,cv,r)
   499  						cum2v.copy(cumv)
   500  						cum2v.xtr_D()
   501  						cumv.copy(t)
   502  						cu.xtr_D()
   503  					}
   504  				}
   505  			}
   506  		}
   507  	}
   508  	r.copy(cv)
   509  	r.xtr_A(cu,cumv,cum2v)
   510  	for i:=0;i<f2;i++ {r.xtr_D()}
   511  	r=r.xtr_pow(d)
   512  	return r
   513  }
   514  
   515  /* this/=2 */
   516  func (F *FP4) div2() {
   517  	F.a.div2()
   518  	F.b.div2()
   519  }
   520  
   521  func (F *FP4) div_i() {
   522  	u:=NewFP2copy(F.a)
   523  	v:=NewFP2copy(F.b)
   524  	u.div_ip()
   525  	F.a.copy(v)
   526  	F.b.copy(u)
   527  }	
   528  
   529  func (F *FP4) div_2i() {
   530  	u:=NewFP2copy(F.a)
   531  	v:=NewFP2copy(F.b)
   532  	u.div_ip2()
   533  	v.add(v); v.norm()
   534  	F.a.copy(v)
   535  	F.b.copy(u)
   536  }
   537  
   538  /* sqrt(a+ib) = sqrt(a+sqrt(a*a-n*b*b)/2)+ib/(2*sqrt(a+sqrt(a*a-n*b*b)/2)) */
   539  /* returns true if this is QR */
   540  func (F *FP4) sqrt() bool {
   541  	if F.iszilch() {return true}
   542  
   543  	a:=NewFP2copy(F.a)
   544  	s:=NewFP2copy(F.b)
   545  	t:=NewFP2copy(F.a)
   546  
   547  	if s.iszilch() {
   548  		if t.sqrt() {
   549  			F.a.copy(t)
   550  			F.b.zero()
   551  		} else {
   552  			t.div_ip()
   553  			t.sqrt()
   554  			F.b.copy(t)
   555  			F.a.zero()
   556  		}
   557  		return true
   558  	}
   559  	s.sqr()
   560  	a.sqr()
   561  	s.mul_ip()
   562  	s.norm()
   563  	a.sub(s)
   564  
   565  	s.copy(a)
   566  	if !s.sqrt() {
   567  		return false
   568  	}
   569  
   570  	a.copy(t); a.add(s); a.norm(); a.div2()
   571  
   572  	if !a.sqrt() {
   573  		a.copy(t); a.sub(s); a.norm(); a.div2()
   574  		if !a.sqrt() {
   575  			return false
   576  		}
   577  	}
   578  	t.copy(F.b)
   579  	s.copy(a); s.add(a)
   580  	s.inverse()
   581  
   582  	t.mul(s)
   583  	F.a.copy(a)
   584  	F.b.copy(t)
   585  
   586  	return true
   587  }