diff --git a/da/kzg_rs/fft.py b/da/kzg_rs/fft.py new file mode 100644 index 0000000..bf93412 --- /dev/null +++ b/da/kzg_rs/fft.py @@ -0,0 +1,37 @@ + +def _simple_ft(vals, modulus, roots_of_unity): + L = len(roots_of_unity) + o = [] + for i in range(L): + last = 0 + for j in range(L): + last += vals[j] * roots_of_unity[(i*j)%L] + o.append(last % modulus) + return o + + +def _fft(vals, modulus, roots_of_unity): + if len(vals) == 4: + return _simple_ft(vals, modulus, roots_of_unity) + if len(vals) == 1: + return vals + L = _fft(vals[::2], modulus, roots_of_unity[::2]) + R = _fft(vals[1::2], modulus, roots_of_unity[::2]) + o = [0 for _ in vals] + for i, (x, y) in enumerate(zip(L, R)): + y_times_root = (y*roots_of_unity[i]) % modulus + o[i] = (x+y_times_root) % modulus + o[i+len(L)] = (x-y_times_root+modulus) % modulus + return o + + +def fft(vals, modulus, root_of_unity): + assert len(vals) == len(root_of_unity) + return _fft(vals, modulus, root_of_unity) + + +def ifft(vals, modulus, root_of_unity): + assert len(vals) == len(root_of_unity) + # modular inverse + invlen = pow(len(vals), -1, modulus) + return [(x * invlen) % modulus for x in _fft(vals, modulus, list(reversed(root_of_unity)))] diff --git a/da/kzg_rs/fk20.py b/da/kzg_rs/fk20.py new file mode 100644 index 0000000..c252b86 --- /dev/null +++ b/da/kzg_rs/fk20.py @@ -0,0 +1,36 @@ +from typing import List, Sequence + +from eth2spec.deneb.mainnet import KZGProof as Proof + +from da.kzg_rs.common import G1, BLS_MODULUS +from da.kzg_rs.fft import fft +from da.kzg_rs.poly import Polynomial +from da.kzg_rs.utils import is_power_of_two + + +def toeplitz1(global_parameters: List[G1], roots_of_unity: Sequence[int], polynomial_degree: int) -> List[G1]: + """ + This part can be precomputed for different global_parameters lengths depending on polynomial degree of powers of two. + :param global_parameters: + :param roots_of_unity: + :param polynomial_degree: + :return: + """ + assert len(roots_of_unity) >= 2 * polynomial_degree + assert len(global_parameters) >= polynomial_degree + global_parameters = global_parameters[:polynomial_degree] + # algorithm only works on powers of 2 for dft computations + assert is_power_of_two(len(global_parameters)) + roots_of_unity = roots_of_unity[:2*polynomial_degree] + vector_x_extended = global_parameters + [G1(0) for _ in range(len(global_parameters))] + vector_x_extended_fft = fft(vector_x_extended, BLS_MODULUS, roots_of_unity) + return vector_x_extended_fft + +def fk20_generate_proofs(polynomial: Polynomial) -> List[Proof]: + # 1 - Build toeplitz matrix for h values + # 1.1 y = dft([s^d-1, s^d-2, ..., s, 1, *[0 for _ in len(polynomial)]]) + # 1.2 z = dft([*[0 for _ in len(polynomial)], f1, f2, ..., fd]) + # 1.3 u = y * v * roots_of_unity(len(polynomial)*2) + # 2 - Build circulant matrix with the polynomial coefficients (reversed N..n, and padded) + # 3 - Perform fft and nub the tail half as it is padding + pass \ No newline at end of file diff --git a/da/kzg_rs/test_fft.py b/da/kzg_rs/test_fft.py new file mode 100644 index 0000000..bb7b263 --- /dev/null +++ b/da/kzg_rs/test_fft.py @@ -0,0 +1,13 @@ +from unittest import TestCase + +from da.kzg_rs.common import BLS_MODULUS +from fft import fft, ifft +from eth2spec.eip7594.mainnet import fft_field, BLSFieldElement + + +class TestFFT(TestCase): + def test_fft_ifft(self): + roots_of_unity = [pow(2, i, BLS_MODULUS) for i in range(8)] + vals = list(BLSFieldElement(x) for x in range(8)) + vals_fft = fft_field(vals, roots_of_unity) + self.assertEqual(vals, fft_field(vals_fft, roots_of_unity, inv=True)) diff --git a/da/kzg_rs/test_fk20.py b/da/kzg_rs/test_fk20.py new file mode 100644 index 0000000..cda74bf --- /dev/null +++ b/da/kzg_rs/test_fk20.py @@ -0,0 +1,5 @@ +from unittest import TestCase +import random + +class TestFK20(TestCase): + def test_toeplizt1(self): diff --git a/da/kzg_rs/utils.py b/da/kzg_rs/utils.py new file mode 100644 index 0000000..190ac22 --- /dev/null +++ b/da/kzg_rs/utils.py @@ -0,0 +1,6 @@ + +POWERS_OF_2 = {2**i for i in range(1, 8)} + + +def is_power_of_two(n) -> bool: + return n in POWERS_OF_2 diff --git a/requirements.txt b/requirements.txt index bb86124..5e802ca 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -blspy==2.0.2 +blspy==2.0.3 cffi==1.16.0 cryptography==41.0.7 numpy==1.26.3