|
15 | 15 | @spec_test |
16 | 16 | @single_phase |
17 | 17 | def test_fft(spec): |
| 18 | + |
| 19 | + # in this test we sample a random polynomial in coefficient form |
| 20 | + # then we apply an FFT to get evaluations over the roots of unity |
| 21 | + # we then apply an inverse FFT to the evaluations to get coefficients |
| 22 | + |
| 23 | + # we check two things: |
| 24 | + # 1) the original coefficients and the resulting coefficients match |
| 25 | + # 2) the evaluations that we got are the same as if we would have evaluated individually |
| 26 | + |
18 | 27 | rng = random.Random(5566) |
19 | 28 |
|
20 | 29 | roots_of_unity = spec.compute_roots_of_unity(spec.FIELD_ELEMENTS_PER_BLOB) |
21 | 30 |
|
| 31 | + # sample a random polynomial |
22 | 32 | poly_coeff = [rng.randint(0, BLS_MODULUS - 1) for _ in range(spec.FIELD_ELEMENTS_PER_BLOB)] |
23 | 33 |
|
| 34 | + # do an FFT and then an inverse FFT |
24 | 35 | poly_eval = spec.fft_field(poly_coeff, roots_of_unity) |
25 | 36 | poly_coeff_inversed = spec.fft_field(poly_eval, roots_of_unity, inv=True) |
26 | 37 |
|
| 38 | + # first check: inverse FFT after FFT results in original coefficients |
27 | 39 | assert len(poly_eval) == len(poly_coeff) == len(poly_coeff_inversed) |
28 | 40 | assert poly_coeff_inversed == poly_coeff |
29 | 41 |
|
| 42 | + # second check: result of FFT are really the evaluations |
| 43 | + for i, w in enumerate(roots_of_unity): |
| 44 | + individual_evaluation = spec.evaluate_polynomialcoeff(poly_coeff, w) |
| 45 | + assert individual_evaluation == poly_eval[i] |
| 46 | + |
30 | 47 |
|
31 | 48 | @with_eip7594_and_later |
32 | 49 | @spec_test |
33 | 50 | @single_phase |
34 | 51 | def test_coset_fft(spec): |
| 52 | + |
| 53 | + # in this test we sample a random polynomial in coefficient form |
| 54 | + # then we apply a Coset FFT to get evaluations over the coset of the roots of unity |
| 55 | + # we then apply an inverse Coset FFT to the evaluations to get coefficients |
| 56 | + |
| 57 | + # we check two things: |
| 58 | + # 1) the original coefficients and the resulting coefficients match |
| 59 | + # 2) the evaluations that we got are the same as if we would have evaluated individually |
| 60 | + |
35 | 61 | rng = random.Random(5566) |
36 | 62 |
|
37 | 63 | roots_of_unity = spec.compute_roots_of_unity(spec.FIELD_ELEMENTS_PER_BLOB) |
38 | 64 |
|
| 65 | + # this is the shift that generates the coset |
| 66 | + coset_shift = spec.PRIMITIVE_ROOT_OF_UNITY |
| 67 | + |
| 68 | + # sample a random polynomial |
39 | 69 | poly_coeff = [rng.randint(0, BLS_MODULUS - 1) for _ in range(spec.FIELD_ELEMENTS_PER_BLOB)] |
40 | 70 |
|
| 71 | + # do a coset FFT and then an inverse coset FFT |
41 | 72 | poly_eval = spec.coset_fft_field(poly_coeff, roots_of_unity) |
42 | 73 | poly_coeff_inversed = spec.coset_fft_field(poly_eval, roots_of_unity, inv=True) |
43 | 74 |
|
| 75 | + # first check: inverse coset FFT after coset FFT results in original coefficients |
44 | 76 | assert len(poly_eval) == len(poly_coeff) == len(poly_coeff_inversed) |
45 | 77 | assert poly_coeff_inversed == poly_coeff |
46 | 78 |
|
| 79 | + # second check: result of FFT are really the evaluations over the coset |
| 80 | + for i, w in enumerate(roots_of_unity): |
| 81 | + # the element of the coset is coset_shift * w |
| 82 | + shifted_w = spec.BLSFieldElement((coset_shift * int(w)) % BLS_MODULUS) |
| 83 | + individual_evaluation = spec.evaluate_polynomialcoeff(poly_coeff, shifted_w) |
| 84 | + assert individual_evaluation == poly_eval[i] |
| 85 | + |
47 | 86 |
|
48 | 87 | @with_eip7594_and_later |
49 | 88 | @spec_test |
|
0 commit comments