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 }