github.com/consensys/gnark-crypto@v0.14.0/ecc/bls12-377/fr/iop/polynomial_test.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 // Code generated by consensys/gnark-crypto DO NOT EDIT 16 17 package iop 18 19 import ( 20 "testing" 21 22 "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" 23 "github.com/consensys/gnark-crypto/ecc/bls12-377/fr/fft" 24 25 "github.com/stretchr/testify/require" 26 27 "bytes" 28 "reflect" 29 ) 30 31 func TestEvaluation(t *testing.T) { 32 33 size := 8 34 shift := 2 35 d := fft.NewDomain(uint64(size)) 36 c := randomVector(size) 37 wp := NewPolynomial(c, Form{Basis: Canonical, Layout: Regular}) 38 wps := wp.ShallowClone().Shift(shift) 39 ref := wp.Clone() 40 ref.ToLagrange(d).ToRegular() 41 42 // regular layout 43 a := wp.Evaluate(d.Generator) 44 b := wps.Evaluate(d.Generator) 45 if !a.Equal(&ref.Coefficients()[1]) { 46 t.Fatal("error evaluation") 47 } 48 if !b.Equal(&ref.Coefficients()[1+shift]) { 49 t.Fatal("error evaluation shifted") 50 } 51 52 // bit reversed layout 53 wp.ToBitReverse() 54 wps.ToBitReverse() 55 a = wp.Evaluate(d.Generator) 56 b = wps.Evaluate(d.Generator) 57 if !a.Equal(&ref.Coefficients()[1]) { 58 t.Fatal("error evaluation") 59 } 60 if !b.Equal(&ref.Coefficients()[1+shift]) { 61 t.Fatal("error evaluation shifted") 62 } 63 64 } 65 66 func randomVector(size int) *[]fr.Element { 67 68 r := make([]fr.Element, size) 69 for i := 0; i < size; i++ { 70 r[i].SetRandom() 71 } 72 return &r 73 } 74 75 func TestGetCoeff(t *testing.T) { 76 77 size := 8 78 v := make([]fr.Element, size) 79 for i := 0; i < size; i++ { 80 v[i].SetUint64(uint64(i)) 81 } 82 wp := NewPolynomial(&v, Form{Layout: Regular, Basis: Canonical}) 83 wsp := wp.ShallowClone().Shift(1) 84 85 var aa, bb fr.Element 86 87 // regular layout 88 for i := 0; i < size; i++ { 89 90 a := wp.GetCoeff(i) 91 b := wsp.GetCoeff(i) 92 aa.SetUint64(uint64(i)) 93 bb.SetUint64(uint64((i + 1) % size)) 94 if !a.Equal(&aa) { 95 t.Fatal("error GetCoeff") 96 } 97 if !b.Equal(&bb) { 98 t.Fatal("error GetCoeff") 99 } 100 } 101 102 // bit reverse + bitReverse and shifted 103 wp.ToBitReverse() 104 wsp.ToBitReverse() 105 for i := 0; i < size; i++ { 106 107 a := wp.GetCoeff(i) 108 b := wsp.GetCoeff(i) 109 aa.SetUint64(uint64(i)) 110 bb.SetUint64(uint64((i + 1) % size)) 111 if !a.Equal(&aa) { 112 t.Fatal("error GetCoeff") 113 } 114 if !b.Equal(&bb) { 115 t.Fatal("error GetCoeff") 116 } 117 } 118 119 } 120 121 func TestRoundTrip(t *testing.T) { 122 assert := require.New(t) 123 var buf bytes.Buffer 124 125 size := 8 126 d := fft.NewDomain(uint64(8)) 127 blindingOrder := 2 128 129 p := NewPolynomial(randomVector(size), Form{Basis: Lagrange, Layout: Regular}).ToCanonical(d).ToRegular() 130 p.Blind(blindingOrder) 131 132 // serialize 133 written, err := p.WriteTo(&buf) 134 assert.NoError(err) 135 136 // deserialize 137 var reconstructed Polynomial 138 read, err := reconstructed.ReadFrom(&buf) 139 assert.NoError(err) 140 141 assert.Equal(read, written, "number of bytes written != number of bytes read") 142 143 // compare 144 assert.Equal(p.Basis, reconstructed.Basis) 145 assert.Equal(p.Layout, reconstructed.Layout) 146 assert.Equal(p.shift, reconstructed.shift) 147 assert.Equal(p.size, reconstructed.size) 148 assert.Equal(p.blindedSize, reconstructed.blindedSize) 149 c1, c2 := p.Coefficients(), reconstructed.Coefficients() 150 assert.True(reflect.DeepEqual(c1, c2)) 151 } 152 153 func TestBlinding(t *testing.T) { 154 155 size := 8 156 d := fft.NewDomain(uint64(8)) 157 blindingOrder := 2 158 159 // generate a random polynomial in Lagrange form for the moment 160 // to check that an error is raised when the polynomial is not 161 // in canonical form. 162 wp := NewPolynomial(randomVector(size), Form{Basis: Lagrange, Layout: Regular}) 163 164 // checks the blinding is correct: the evaluation of the blinded polynomial 165 // should be the same as the original on d's domain 166 wp.Basis = Canonical 167 wt := wp.Clone() 168 wt.Blind(blindingOrder) 169 if wt.coefficients.Len() != blindingOrder+size+1 { 170 t.Fatal("size of blinded polynomial is incorrect") 171 } 172 if wt.blindedSize != size+blindingOrder+1 { 173 t.Fatal("Size field of blinded polynomial is incorrect") 174 } 175 if wt.size != size { 176 t.Fatal("the size should not have been modified") 177 } 178 x := make([]fr.Element, size) 179 x[0].SetOne() 180 for i := 1; i < size; i++ { 181 x[i].Mul(&x[i-1], &d.Generator) 182 } 183 var a, b fr.Element 184 for i := 0; i < size; i++ { 185 a = wt.Evaluate(x[i]) 186 b = wp.Evaluate(x[i]) 187 if a != b { 188 t.Fatal("polynomial and its blinded version should be equal on V(X^{n}-1)") 189 } 190 } 191 192 } 193 194 // list of functions to turn a polynomial in Lagrange-regular form 195 // to all different forms in ordered using this encoding: 196 // int(p.Basis)*4 + int(p.Layout)*2 + int(p.Status) 197 // p is in Lagrange/Regular here. This function is for testing purpose 198 // only. 199 type TransfoTest func(p polynomial, d *fft.Domain) polynomial 200 201 // CANONICAL REGULAR 202 func fromLagrange0(p *Polynomial, d *fft.Domain) *Polynomial { 203 r := p.Clone() 204 r.Basis = Canonical 205 r.Layout = Regular 206 d.FFTInverse(r.Coefficients(), fft.DIF) 207 fft.BitReverse(r.Coefficients()) 208 return r 209 } 210 211 // CANONICAL BITREVERSE 212 func fromLagrange1(p *Polynomial, d *fft.Domain) *Polynomial { 213 r := p.Clone() 214 r.Basis = Canonical 215 r.Layout = BitReverse 216 d.FFTInverse(r.Coefficients(), fft.DIF) 217 return r 218 } 219 220 // LAGRANGE REGULAR 221 func fromLagrange2(p *Polynomial, d *fft.Domain) *Polynomial { 222 r := p.Clone() 223 r.Basis = Lagrange 224 r.Layout = Regular 225 return r 226 } 227 228 // LAGRANGE BITREVERSE 229 func fromLagrange3(p *Polynomial, d *fft.Domain) *Polynomial { 230 r := p.Clone() 231 r.Basis = Lagrange 232 r.Layout = BitReverse 233 fft.BitReverse(r.Coefficients()) 234 return r 235 } 236 237 // LAGRANGE_COSET REGULAR 238 func fromLagrange4(p *Polynomial, d *fft.Domain) *Polynomial { 239 r := p.Clone() 240 r.Basis = LagrangeCoset 241 r.Layout = Regular 242 d.FFTInverse(r.Coefficients(), fft.DIF) 243 d.FFT(r.Coefficients(), fft.DIT, fft.OnCoset()) 244 return r 245 } 246 247 // LAGRANGE_COSET BITREVERSE 248 func fromLagrange5(p *Polynomial, d *fft.Domain) *Polynomial { 249 r := p.Clone() 250 r.Basis = LagrangeCoset 251 r.Layout = BitReverse 252 d.FFTInverse(r.Coefficients(), fft.DIF) 253 d.FFT(r.Coefficients(), fft.DIT, fft.OnCoset()) 254 fft.BitReverse(r.Coefficients()) 255 return r 256 } 257 258 func fromLagrange(p *Polynomial, d *fft.Domain) *Polynomial { 259 id := p.Form 260 switch id { 261 case canonicalRegular: 262 return fromLagrange0(p, d) 263 case canonicalBitReverse: 264 return fromLagrange1(p, d) 265 case lagrangeRegular: 266 return fromLagrange2(p, d) 267 case lagrangeBitReverse: 268 return fromLagrange3(p, d) 269 case lagrangeCosetRegular: 270 return fromLagrange4(p, d) 271 case lagrangeCosetBitReverse: 272 return fromLagrange5(p, d) 273 default: 274 panic("unknown id") 275 } 276 } 277 278 func cmpCoefficents(p, q *fr.Vector) bool { 279 if p.Len() != q.Len() { 280 return false 281 } 282 for i := 0; i < p.Len(); i++ { 283 if !((*p)[i].Equal(&(*q)[i])) { 284 return false 285 } 286 } 287 return true 288 } 289 290 func TestPutInLagrangeForm(t *testing.T) { 291 292 size := 64 293 domain := fft.NewDomain(uint64(size)) 294 295 // reference vector in Lagrange-regular form 296 c := randomVector(size) 297 p := NewPolynomial(c, Form{Basis: Canonical, Layout: Regular}) 298 299 // CANONICAL REGULAR 300 { 301 _p := fromLagrange(p, domain) 302 q := _p.Clone() 303 q.ToLagrange(domain) 304 if q.Basis != Lagrange { 305 t.Fatal("expected basis is Lagrange") 306 } 307 if q.Layout != BitReverse { 308 t.Fatal("expected layout is BitReverse") 309 } 310 fft.BitReverse(q.Coefficients()) 311 if !cmpCoefficents(q.coefficients, p.coefficients) { 312 t.Fatal("wrong coefficients") 313 } 314 } 315 316 // CANONICAL BITREVERSE 317 { 318 _p := fromLagrange1(p, domain) 319 q := _p.Clone() 320 q.ToLagrange(domain) 321 if q.Basis != Lagrange { 322 t.Fatal("expected basis is Lagrange") 323 } 324 if q.Layout != Regular { 325 t.Fatal("expected layout is Regular") 326 } 327 if !cmpCoefficents(q.coefficients, p.coefficients) { 328 t.Fatal("wrong coefficients") 329 } 330 } 331 332 // LAGRANGE REGULAR 333 { 334 _p := fromLagrange2(p, domain) 335 q := _p.Clone() 336 q.ToLagrange(domain) 337 338 if q.Basis != Lagrange { 339 t.Fatal("expected basis is Lagrange") 340 } 341 if q.Layout != Regular { 342 t.Fatal("expected layout is Regular") 343 } 344 if !cmpCoefficents(q.coefficients, p.coefficients) { 345 t.Fatal("wrong coefficients") 346 } 347 } 348 349 // LAGRANGE BITREVERSE 350 { 351 _p := fromLagrange3(p, domain) 352 q := _p.Clone() 353 q.ToLagrange(domain) 354 if q.Basis != Lagrange { 355 t.Fatal("expected basis is Lagrange") 356 } 357 if q.Layout != BitReverse { 358 t.Fatal("expected layout is BitReverse") 359 } 360 fft.BitReverse(q.Coefficients()) 361 if !cmpCoefficents(q.coefficients, p.coefficients) { 362 t.Fatal("wrong coefficients") 363 } 364 } 365 366 // LAGRANGE_COSET REGULAR 367 { 368 _p := fromLagrange4(p, domain) 369 q := _p.Clone() 370 q.ToLagrange(domain) 371 if q.Basis != Lagrange { 372 t.Fatal("expected basis is Lagrange") 373 } 374 if q.Layout != Regular { 375 t.Fatal("expected layout is Regular") 376 } 377 if !cmpCoefficents(q.coefficients, p.coefficients) { 378 t.Fatal("wrong coefficients") 379 } 380 } 381 382 // LAGRANGE_COSET BITREVERSE 383 { 384 _p := fromLagrange5(p, domain) 385 q := _p.Clone() 386 q.ToLagrange(domain) 387 if q.Basis != Lagrange { 388 t.Fatal("expected basis is Lagrange") 389 } 390 if q.Layout != BitReverse { 391 t.Fatal("expected layout is BitReverse") 392 } 393 fft.BitReverse(q.Coefficients()) 394 if !cmpCoefficents(q.coefficients, p.coefficients) { 395 t.Fatal("wrong coefficients") 396 } 397 } 398 399 } 400 401 // CANONICAL REGULAR 402 func fromCanonical0(p *Polynomial, d *fft.Domain) *Polynomial { 403 _p := p.Clone() 404 _p.Basis = Canonical 405 _p.Layout = Regular 406 return _p 407 } 408 409 // CANONICAL BITREVERSE 410 func fromCanonical1(p *Polynomial, d *fft.Domain) *Polynomial { 411 _p := p.Clone() 412 _p.Basis = Canonical 413 _p.Layout = BitReverse 414 return _p 415 } 416 417 // LAGRANGE REGULAR 418 func fromCanonical2(p *Polynomial, d *fft.Domain) *Polynomial { 419 _p := p.Clone() 420 _p.Basis = Lagrange 421 _p.Layout = Regular 422 d.FFT(_p.Coefficients(), fft.DIF) 423 fft.BitReverse(_p.Coefficients()) 424 return _p 425 } 426 427 // LAGRANGE BITREVERSE 428 func fromCanonical3(p *Polynomial, d *fft.Domain) *Polynomial { 429 _p := p.Clone() 430 _p.Basis = Lagrange 431 _p.Layout = BitReverse 432 d.FFT(_p.Coefficients(), fft.DIF) 433 return _p 434 } 435 436 // LAGRANGE_COSET REGULAR 437 func fromCanonical4(p *Polynomial, d *fft.Domain) *Polynomial { 438 _p := p.Clone() 439 _p.Basis = LagrangeCoset 440 _p.Layout = Regular 441 d.FFT(_p.Coefficients(), fft.DIF, fft.OnCoset()) 442 fft.BitReverse(_p.Coefficients()) 443 return _p 444 } 445 446 // LAGRANGE_COSET BITREVERSE 447 func fromCanonical5(p *Polynomial, d *fft.Domain) *Polynomial { 448 _p := p.Clone() 449 _p.Basis = LagrangeCoset 450 _p.Layout = BitReverse 451 d.FFT(_p.Coefficients(), fft.DIF, fft.OnCoset()) 452 return _p 453 } 454 455 func TestPutInCanonicalForm(t *testing.T) { 456 457 size := 64 458 domain := fft.NewDomain(uint64(size)) 459 460 // reference vector in canonical-regular form 461 c := randomVector(size) 462 p := NewPolynomial(c, Form{Basis: Canonical, Layout: Regular}) 463 464 // CANONICAL REGULAR 465 { 466 _p := fromCanonical0(p, domain) 467 q := _p.Clone() 468 q.ToCanonical(domain) 469 if q.Basis != Canonical { 470 t.Fatal("expected basis is canonical") 471 } 472 if q.Layout != Regular { 473 t.Fatal("expected layout is regular") 474 } 475 if !cmpCoefficents(q.coefficients, p.coefficients) { 476 t.Fatal("wrong coefficients") 477 } 478 } 479 480 // CANONICAL BITREVERSE 481 { 482 _p := fromCanonical1(p, domain) 483 q := _p.Clone() 484 q.ToCanonical(domain) 485 if q.Basis != Canonical { 486 t.Fatal("expected basis is canonical") 487 } 488 if q.Layout != BitReverse { 489 t.Fatal("expected layout is bitReverse") 490 } 491 if !cmpCoefficents(q.coefficients, p.coefficients) { 492 t.Fatal("wrong coefficients") 493 } 494 } 495 496 // LAGRANGE REGULAR 497 { 498 _p := fromCanonical2(p, domain) 499 q := _p.Clone() 500 q.ToCanonical(domain) 501 if q.Basis != Canonical { 502 t.Fatal("expected basis is canonical") 503 } 504 if q.Layout != BitReverse { 505 t.Fatal("expected layout is bitReverse") 506 } 507 fft.BitReverse(q.Coefficients()) 508 if !cmpCoefficents(p.coefficients, q.coefficients) { 509 t.Fatal("wrong coefficients") 510 } 511 } 512 513 // LAGRANGE BITREVERSE 514 { 515 _p := fromCanonical3(p, domain) 516 q := _p.Clone() 517 q.ToCanonical(domain) 518 if q.Basis != Canonical { 519 t.Fatal("expected basis is canonical") 520 } 521 if q.Layout != Regular { 522 t.Fatal("expected layout is regular") 523 } 524 if !cmpCoefficents(q.coefficients, p.coefficients) { 525 t.Fatal("wrong coefficients") 526 } 527 } 528 529 // LAGRANGE_COSET REGULAR 530 { 531 _p := fromCanonical4(p, domain) 532 q := _p.Clone() 533 q.ToCanonical(domain) 534 if q.Basis != Canonical { 535 t.Fatal("expected basis is canonical") 536 } 537 if q.Layout != BitReverse { 538 t.Fatal("expected layout is BitReverse") 539 } 540 fft.BitReverse(q.Coefficients()) 541 if !cmpCoefficents(q.coefficients, p.coefficients) { 542 t.Fatal("wrong coefficients") 543 } 544 } 545 546 // LAGRANGE_COSET BITREVERSE 547 { 548 _p := fromCanonical5(p, domain) 549 q := _p.Clone() 550 q.ToCanonical(domain) 551 if q.Basis != Canonical { 552 t.Fatal("expected basis is canonical") 553 } 554 if q.Layout != Regular { 555 t.Fatal("expected layout is regular") 556 } 557 if !cmpCoefficents(q.coefficients, p.coefficients) { 558 t.Fatal("wrong coefficients") 559 } 560 } 561 562 } 563 564 // CANONICAL REGULAR 565 func fromLagrangeCoset0(p *Polynomial, d *fft.Domain) *Polynomial { 566 _p := p.Clone() 567 _p.Basis = Canonical 568 _p.Layout = Regular 569 d.FFTInverse(_p.Coefficients(), fft.DIF, fft.OnCoset()) 570 fft.BitReverse(_p.Coefficients()) 571 return _p 572 } 573 574 // CANONICAL BITREVERSE 575 func fromLagrangeCoset1(p *Polynomial, d *fft.Domain) *Polynomial { 576 _p := p.Clone() 577 _p.Basis = Canonical 578 _p.Layout = BitReverse 579 d.FFTInverse(_p.Coefficients(), fft.DIF, fft.OnCoset()) 580 return _p 581 } 582 583 // LAGRANGE REGULAR 584 func fromLagrangeCoset2(p *Polynomial, d *fft.Domain) *Polynomial { 585 _p := p.Clone() 586 _p.Basis = Lagrange 587 _p.Layout = Regular 588 d.FFTInverse(_p.Coefficients(), fft.DIF, fft.OnCoset()) 589 d.FFT(_p.Coefficients(), fft.DIT) 590 return _p 591 } 592 593 // LAGRANGE BITREVERSE 594 func fromLagrangeCoset3(p *Polynomial, d *fft.Domain) *Polynomial { 595 _p := p.Clone() 596 _p.Basis = Lagrange 597 _p.Layout = BitReverse 598 d.FFTInverse(_p.Coefficients(), fft.DIF, fft.OnCoset()) 599 d.FFT(_p.Coefficients(), fft.DIT) 600 fft.BitReverse(_p.Coefficients()) 601 return _p 602 } 603 604 // LAGRANGE_COSET REGULAR 605 func fromLagrangeCoset4(p *Polynomial, d *fft.Domain) *Polynomial { 606 _p := p.Clone() 607 _p.Basis = LagrangeCoset 608 _p.Layout = Regular 609 return _p 610 } 611 612 // LAGRANGE_COSET BITREVERSE 613 func fromLagrangeCoset5(p *Polynomial, d *fft.Domain) *Polynomial { 614 _p := p.Clone() 615 _p.Basis = LagrangeCoset 616 _p.Layout = BitReverse 617 fft.BitReverse(p.Coefficients()) 618 return _p 619 } 620 621 func TestPutInLagrangeCosetForm(t *testing.T) { 622 623 size := 64 624 domain := fft.NewDomain(uint64(size)) 625 626 // reference vector in canonical-regular form 627 c := randomVector(size) 628 p := NewPolynomial(c, Form{Basis: LagrangeCoset, Layout: Regular}) 629 630 // CANONICAL REGULAR 631 { 632 _p := fromLagrangeCoset0(p, domain) 633 q := _p.Clone() 634 q.ToLagrangeCoset(domain) 635 if q.Basis != LagrangeCoset { 636 t.Fatal("expected basis is lagrange coset") 637 } 638 if q.Layout != BitReverse { 639 t.Fatal("expected layout is bit reverse") 640 } 641 fft.BitReverse(q.Coefficients()) 642 if !cmpCoefficents(q.coefficients, p.coefficients) { 643 t.Fatal("wrong coefficients") 644 } 645 } 646 647 // CANONICAL BITREVERSE 648 { 649 _p := fromLagrangeCoset1(p, domain) 650 q := _p.Clone() 651 q.ToLagrangeCoset(domain) 652 if q.Basis != LagrangeCoset { 653 t.Fatal("expected basis is lagrange coset") 654 } 655 if q.Layout != Regular { 656 t.Fatal("expected layout is regular") 657 } 658 if !cmpCoefficents(q.coefficients, p.coefficients) { 659 t.Fatal("wrong coefficients") 660 } 661 } 662 663 // LAGRANGE REGULAR 664 { 665 _p := fromLagrangeCoset2(p, domain) 666 q := _p.Clone() 667 q.ToLagrangeCoset(domain) 668 if q.Basis != LagrangeCoset { 669 t.Fatal("expected basis is lagrange coset") 670 } 671 if q.Layout != Regular { 672 t.Fatal("expected layout is regular") 673 } 674 if !cmpCoefficents(q.coefficients, p.coefficients) { 675 t.Fatal("wrong coefficients") 676 } 677 } 678 679 // LAGRANGE BITREVERSE 680 { 681 _p := fromLagrangeCoset3(p, domain) 682 q := _p.Clone() 683 q.ToLagrangeCoset(domain) 684 if q.Basis != LagrangeCoset { 685 t.Fatal("expected basis is lagrange coset") 686 } 687 if q.Layout != BitReverse { 688 t.Fatal("expected layout is bit reverse") 689 } 690 fft.BitReverse(q.Coefficients()) 691 if !cmpCoefficents(q.coefficients, p.coefficients) { 692 t.Fatal("wrong coefficients") 693 } 694 } 695 696 // LAGRANGE_COSET REGULAR 697 { 698 _p := fromLagrangeCoset4(p, domain) 699 q := _p.Clone() 700 q.ToLagrangeCoset(domain) 701 if q.Basis != LagrangeCoset { 702 t.Fatal("expected basis is lagrange coset") 703 } 704 if q.Layout != Regular { 705 t.Fatal("expected layout is regular") 706 } 707 if !cmpCoefficents(q.coefficients, p.coefficients) { 708 t.Fatal("wrong coefficients") 709 } 710 } 711 712 // LAGRANGE_COSET BITREVERSE 713 { 714 _p := fromLagrangeCoset5(p, domain) 715 q := _p.Clone() 716 q.ToLagrangeCoset(domain) 717 if q.Basis != LagrangeCoset { 718 t.Fatal("expected basis is lagrange coset") 719 } 720 if q.Layout != BitReverse { 721 t.Fatal("expected layout is bit reverse") 722 } 723 fft.BitReverse(q.Coefficients()) 724 if !cmpCoefficents(q.coefficients, p.coefficients) { 725 t.Fatal("wrong coefficients") 726 } 727 } 728 729 }