Exemple #1
0
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))
Exemple #2
0
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
Exemple #3
0
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))
Exemple #4
0
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))
Exemple #5
0
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
Exemple #6
0
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))
Exemple #7
0
def toeplitz_part3(hext_fft):
    root_of_unity = get_root_of_unity(len(hext_fft))

    # Transform back and return the first half of the vector
    # Only the top half is the Toeplitz product, the rest is padding
    return fft(hext_fft, MODULUS, root_of_unity, inv=True)[:len(hext_fft) // 2]
Exemple #8
0
    extended_polynomial = polynomial + [0] * n

    all_proofs = fk20_single_data_availability_optimized(
        extended_polynomial, setup)

    return list_to_reverse_bit_order(all_proofs)


if __name__ == "__main__":
    polynomial = [1, 2, 3, 4, 7, 7, 7, 7, 13, 13, 13, 13, 13, 13, 13, 13]
    n = len(polynomial)

    setup = generate_setup(1927409816240961209460912649124, n)

    commitment = commit_to_poly(polynomial, setup)

    # Computing the proofs on the double
    all_proofs = data_availabilty_using_fk20(polynomial, setup)
    print("All KZG proofs computed")

    # Now check a random position

    pos = 9
    root_of_unity = get_root_of_unity(n * 2)
    x = pow(root_of_unity, pos, MODULUS)
    y = eval_poly_at(polynomial, x)

    assert check_proof_single(commitment,
                              all_proofs[reverse_bit_order(pos, 2 * n)], x, y,
                              setup)
    print("Single point check passed")
Exemple #9
0
    setup = generate_setup(1927409816240961209460912649124, n)

    commitment = commit_to_poly(polynomial, setup)

    l = 16

    all_proofs = data_availabilty_using_fk20_multi(polynomial, l, setup)
    print(
        "All KZG proofs computed for data availability (supersampled by factor 2)"
    )
    print("Required {0} G1 multiplications".format(multiplication_count))
    print(n, l, multiplication_count)

    # Now check all positions
    extended_data = get_extended_data(polynomial)

    for pos in range(2 * n // l):
        root_of_unity = get_root_of_unity(n * 2)
        x = pow(root_of_unity, reverse_bit_order(pos, 2 * n // l), MODULUS)
        ys = extended_data[l * pos:l * (pos + 1)]

        subgroup_root_of_unity = get_root_of_unity(l)
        coset = [x * pow(subgroup_root_of_unity, i, MODULUS) for i in range(l)]
        ys2 = [eval_poly_at(polynomial, z) for z in coset]
        assert list_to_reverse_bit_order(ys) == ys2

        assert check_proof_multi(commitment, all_proofs[pos], x,
                                 list_to_reverse_bit_order(ys), setup)
        print("Data availability sample check {0} passed".format(pos))