def fk20_single_data_availability_optimized(polynomial, setup): """ Special version of the FK20 for the situation of data availability checks: The upper half of the polynomial coefficients is always 0, so we do not need to extend to twice the size for Toeplitz matrix multiplication """ assert is_power_of_two(len(polynomial)) n = len(polynomial) // 2 assert all(x == 0 for x in polynomial[n:]) reduced_polynomial = polynomial[:n] # Preprocessing part -- this is independent from the polynomial coefficients and can be # done before the polynomial is known, it only needs to be computed once x = setup[0][n - 2::-1] + [b.Z1] xext_fft = toeplitz_part1(x) toeplitz_coefficients = reduced_polynomial[-1::] + [0] * ( n + 1) + reduced_polynomial[1:-1] # Compute the vector h from the paper using a Toeplitz matric multiplication h = toeplitz_part3(toeplitz_part2(toeplitz_coefficients, xext_fft)) h = h + [b.Z1] * n # The proofs are the DFT of the h vector return fft(h, MODULUS, get_root_of_unity(2 * n))
def fk20_multi_data_availability_optimized(polynomial, l, setup): """ FK20 multi-proof method, optimized for dava availability where the top half of polynomial coefficients == 0 """ assert is_power_of_two(len(polynomial)) n = len(polynomial) // 2 k = n // l assert is_power_of_two(n) assert is_power_of_two(l) assert k >= 1 assert all(x == 0 for x in polynomial[n:]) reduced_polynomial = polynomial[:n] # Preprocessing part -- this is independent from the polynomial coefficients and can be # done before the polynomial is known, it only needs to be computed once xext_fft = [] for i in range(l): x = setup[0][n - l - 1 - i::-l] + [b.Z1] xext_fft.append(toeplitz_part1(x)) add_instrumentation() hext_fft = [b.Z1] * 2 * k for i in range(l): toeplitz_coefficients = reduced_polynomial[- i - 1::l] + [0] * (k + 1) \ + reduced_polynomial[2 * l - i - 1: - l - i:l] # Compute the vector h from the paper using a Toeplitz matric multiplication hext_fft = [ b.add(v, w) for v, w in zip( hext_fft, toeplitz_part2(toeplitz_coefficients, xext_fft[i])) ] # Final FFT done after summing all h vectors h = toeplitz_part3(hext_fft) h = h + [b.Z1] * k # The proofs are the DFT of the h vector return fft(h, MODULUS, get_root_of_unity(2 * k))
def fk20_multi(polynomial, l, setup): """ For a polynomial of size n, let w be a n-th root of unity. Then this method will return k=n/l KZG proofs for the points proof[0]: w^(0*l + 0), w^(0*l + 1), ... w^(0*l + l - 1) proof[0]: w^(0*l + 0), w^(0*l + 1), ... w^(0*l + l - 1) ... proof[i]: w^(i*l + 0), w^(i*l + 1), ... w^(i*l + l - 1) ... """ n = len(polynomial) k = n // l assert is_power_of_two(n) assert is_power_of_two(l) assert k >= 1 # Preprocessing part -- this is independent from the polynomial coefficients and can be # done before the polynomial is known, it only needs to be computed once xext_fft = [] for i in range(l): x = setup[0][n - l - 1 - i::-l] + [b.Z1] xext_fft.append(toeplitz_part1(x)) hext_fft = [b.Z1] * 2 * k for i in range(l): toeplitz_coefficients = polynomial[-i - 1::l] + [0] * ( k + 1) + polynomial[2 * l - i - 1:-l - i:l] # Compute the vector h from the paper using a Toeplitz matric multiplication hext_fft = [ b.add(v, w) for v, w in zip( hext_fft, toeplitz_part2(toeplitz_coefficients, xext_fft[i])) ] h = toeplitz_part3(hext_fft) # The proofs are the DFT of the h vector return fft(h, MODULUS, get_root_of_unity(k))
def data_availabilty_using_fk20(polynomial, setup): """ Computes all the KZG proofs for data availability checks. This involves sampling on the double domain and reordering according to reverse bit order """ assert is_power_of_two(len(polynomial)) n = len(polynomial) extended_polynomial = polynomial + [0] * n all_proofs = fk20_single_data_availability_optimized( extended_polynomial, setup) return list_to_reverse_bit_order(all_proofs)
def toeplitz_part1(x): """ Performs the first part of the Toeplitz matrix multiplication algorithm, which is a Fourier transform of the vector x extended """ assert is_power_of_two(len(x)) root_of_unity = get_root_of_unity(len(x) * 2) # Extend x with zeros (neutral element of G1) xext = x + [b.Z1] * len(x) xext_fft = fft(xext, MODULUS, root_of_unity, inv=False) return xext_fft
def fk20_single(polynomial, setup): """ Compute all n (single) proofs according to FK20 method """ assert is_power_of_two(len(polynomial)) n = len(polynomial) x = setup[0][n - 2::-1] + [b.Z1] xext_fft = toeplitz_part1(x) toeplitz_coefficients = polynomial[-1::] + [0] * (n + 1) + polynomial[1:-1] # Compute the vector h from the paper using a Toeplitz matric multiplication h = toeplitz_part3(toeplitz_part2(toeplitz_coefficients, xext_fft)) # The proofs are the DFT of the h vector return fft(h, MODULUS, get_root_of_unity(n))
def toeplitz_part2(toeplitz_coefficients, xext_fft): """ Performs the second part of the Toeplitz matrix multiplication algorithm """ # Extend the toeplitz coefficients to get a circulant matrix into which the Toeplitz # matrix is embedded assert is_power_of_two(len(toeplitz_coefficients)) root_of_unity = get_root_of_unity(len(xext_fft)) toeplitz_coefficients_fft = fft(toeplitz_coefficients, MODULUS, root_of_unity, inv=False) hext_fft = [ b.multiply(v, w) for v, w in zip(xext_fft, toeplitz_coefficients_fft) ] return hext_fft