Exemplo n.º 1
0
def SameRatioSeqSym(sequence, pair):
    left = G * Fp(0)
    right = G * Fp(0)
    l = len(sequence)
    blinds = [random_fp() for i in range(l-1)]
    for i in range(l-1):
        left += sequence[i+1] * blinds[i]
        right += sequence[i] * blinds[i]
    return Group.pair(pair[0],left) == Group.pair(pair[1], right)
Exemplo n.º 2
0
def vanishing_poly(S):
    """
    args: 
       S   (m vector)
    returns:
       p(X) = (X-S1)*(X-S2)*...*(X-Sm)
    """
    p = Poly([Fp(1)])
    for s in S:
        p *= Poly([-s, Fp(1)])
    return p
Exemplo n.º 3
0
def eval_poly(poly, domain, shift=Fp(1)):
    poly_coeff = poly.to_coeffs()
    eval = []
    for j in range(len(domain)):
        eval += [sum([(domain[j] * shift) ** i * poly_coeff.coefficients[i]
                 for i in range(poly_coeff.degree()+1)])]
    return eval
Exemplo n.º 4
0
def babysnarkopt_prover(U, n_stmt, CRS, precomp, a):
    (m, n) = U.shape
    assert n == len(a)
    assert len(CRS) == (m + 1) + 2 + (n - n_stmt)

    taus = CRS[: m + 1]
    bUis = CRS[-(n - n_stmt) :]

    Uis, T = precomp

    # Target is the vanishing polynomial
    mpow2 = m
    assert mpow2 & mpow2 - 1 == 0, "mpow2 must be a power of 2"
    omega = omega_base ** (2 ** 32 // mpow2)
    omega2 = omega_base ** (2 ** 32 // (2 * mpow2))
    PolyEvalRep = polynomialsEvalRep(Fp, omega, mpow2)
    t = vanishing_poly(omega, mpow2)

    # 1. Find the polynomial p(X)

    # First compute v
    v = PolyEvalRep((), ())
    for (i, k), y in U.items():
        x = ROOTS[i]
        v += PolyEvalRep([x], [y]) * a[k]

    # Now we need to convert between representations to multiply and divide
    PolyEvalRep2 = polynomialsEvalRep(Fp, omega2, 2 * mpow2)
    roots2 = [omega2 ** i for i in range(2 * mpow2)]
    ONE = PolyEvalRep2(roots2, [Fp(1) for _ in roots2])

    vv = v.to_coeffs()
    v2 = PolyEvalRep2.from_coeffs(v.to_coeffs())
    p2 = v2 * v2 - ONE
    p = p2.to_coeffs()

    # Find the polynomial h by dividing p / t
    h = PolyEvalRep2.divideWithCoset(p, t)
    # assert p == h * t

    # 2. Compute the H term
    H = evaluate_in_exponent(taus, h)

    # 3. Compute the Vw terms, using precomputed Uis
    Vw = sum([Uis[k] * a[k] for k in range(n_stmt, n)], G * 0)
    # assert G * vw(tau) == Vw

    # 4. Compute the Bw terms
    Bw = sum([bUis[k - n_stmt] * a[k] for k in range(n_stmt, n)], G * 0)
    # assert G * (beta * vw(tau)) == Bw

    # V = G * vv(tau)
    # assert H.pair(T) * GT == V.pair(V)

    # print('H:', H)
    # print('Bw:', Bw)
    # print('Vw:', Vw)
    return H, Bw, Vw
Exemplo n.º 5
0
def setup_algo(gates_matrix, permutation, L, p_i):
    print("Starting Setup Phase...")
    (m, n) = gates_matrix.shape

    assert n & n - 1 == 0, "n must be a power of 2"
    omega = omega_base ** (2 ** 32 // n)
    ROOTS = [omega ** i for i in range(n)]

    PolyEvalRep = polynomialsEvalRep(Fp, omega, n)

    # Generate polynomials from columns of gates_matrix
    q_L = PolyEvalRep(ROOTS, [Fp(i) for i in gates_matrix[0]])
    q_R = PolyEvalRep(ROOTS, [Fp(i) for i in gates_matrix[1]])
    q_M = PolyEvalRep(ROOTS, [Fp(i) for i in gates_matrix[2]])
    q_O = PolyEvalRep(ROOTS, [Fp(i) for i in gates_matrix[3]])
    q_C = PolyEvalRep(ROOTS, [Fp(i) for i in gates_matrix[4]])
    Qs = [q_L, q_R, q_M, q_O, q_C]

    # The public input poly vanishes everywhere except for the position of the
    # public input gate where it evaluates to -(public_input)
    public_input = [Fp(0) for i in range(len(ROOTS))]
    for i in L:
        public_input[i] = Fp(-p_i)
    p_i_poly = PolyEvalRep(ROOTS, public_input)

    # We generate domains on which we can evaluate the witness polynomials
    k = random_fp()
    id_domain_a = ROOTS
    id_domain_b = [k * root for root in ROOTS]
    id_domain_c = [k**2 * root for root in ROOTS]
    id_domain = id_domain_a + id_domain_b + id_domain_c

    # We permute the positions of the domain generated above
    perm_domain = [id_domain[i - 1] for i in permutation]
    perm_domain_a = perm_domain[:n]
    perm_domain_b = perm_domain[n: 2*n]
    perm_domain_c = perm_domain[2*n:3*n]

    # Generate polynomials that return the permuted index when evaluated on the
    # domain
    S_sigma_1 = PolyEvalRep(ROOTS, perm_domain_a)
    S_sigma_2 = PolyEvalRep(ROOTS, perm_domain_b)
    S_sigma_3 = PolyEvalRep(ROOTS, perm_domain_c)
    Ss = [S_sigma_1, S_sigma_2, S_sigma_3]

    perm_precomp = [id_domain, perm_domain, k, Ss]

    # We perform the trusted setup
    tau = random_fp()
    CRS = [G * (tau ** i) for i in range(n + 3)]

    # We take some work off the shoulders of the verifier
    print("Starting Verifier Preprocessing...")
    q_exp = [evaluate_in_exponent(CRS, q.to_coeffs()) for q in Qs]
    s_exp = [evaluate_in_exponent(CRS, s.to_coeffs()) for s in Ss]
    x_exp = G2 * tau
    verifier_preprocessing = [q_exp, s_exp, x_exp]
    print("Setup Phase Finished!")

    return CRS, Qs, p_i_poly, perm_precomp, verifier_preprocessing
Exemplo n.º 6
0
def _sparse_poly_demo():
    PolyEvalRep = polynomialsEvalRep(Fp, omega, mpow2)

    # Example polynomial that has roots at most of the powers of omega
    xs = [omega ** 1, omega ** 4, omega ** 5]
    ys = [Fp(3), Fp(5), Fp(1)]
    f_rep = PolyEvalRep(xs, ys)

    for i in [0, 2, 3, 6, 7]:
        assert f_rep(omega ** i) == Fp(0)
    for i, x in enumerate(xs):
        assert f_rep(x) == ys[i]

    # Convert to coeffs and back
    f = f_rep.to_coeffs()
    assert f_rep.to_coeffs() == PolyEvalRep.from_coeffs(f).to_coeffs()

    # Check f and f_rep are consistent
    tau = random_fp()
    assert f(tau) == f_rep(tau)
Exemplo n.º 7
0
def random_sparse_matrix(m, n, avgPerN=2):
    U = RowDictSparseMatrix(m, n, Fp(0))

    # First fill the first column
    for row in range(m):
        U[row, 0] = random_fp()

    # Then pick randomly for the rest
    for _ in range(avgPerN * n - 1):
        row = random.randrange(m)
        col = random.randrange(n)
        U[row, col] = random_fp()

    return U
Exemplo n.º 8
0
def accumulator_factor(n, i, witness, beta, id_domain, perm_domain, gamma):
    # This function is used in round 2
    # i am doing permutation[j-1] below because the list starts at 0 and the
    # paper at 1
    res = Fp(1)
    for j in range(i+1):
        nom_1 =   witness[j]         + beta * id_domain[j]     + gamma
        denom_1 = witness[j]         + beta * perm_domain[j]     + gamma

        nom_2 =   witness[n + j]     + beta * id_domain[n+j]   + gamma
        denom_2 = witness[n + j]     + beta * perm_domain[n+j]   + gamma

        nom_3 =   witness[2 * n + j] + beta * id_domain[2*n+j] + gamma
        denom_3 = witness[2 * n + j] + beta * perm_domain[2*n+j] + gamma
        res *= (nom_1 / denom_1) * (nom_2 / denom_2) * (nom_3 / denom_3)
    return res
Exemplo n.º 9
0
def vanishing_poly(omega, n):
    # For the special case of evaluating at all n powers of omega,
    # the vanishing poly has a special form.
    #  t(X) = (X-1)(X-omega)....(X-omega^(n-1)) = X^n - 1
    return Poly([Fp(-1)] + [Fp(0)] * (n - 1) + [Fp(1)])
Exemplo n.º 10
0
def hash_to_fp(bytestr):
    assert type(bytestr) is bytes
    return Fp(int(sha256(bytestr).hexdigest(), 16)%Fp.p)
Exemplo n.º 11
0
def random_fp():
    return Fp(random.randint(0, Fp.p-1))
Exemplo n.º 12
0
def verifier_algo(proof_SNARK, n, p_i_poly, verifier_preprocessing, k):
    print("Starting Verification...")
    omega = omega_base**(2**32 // n)

    first_output, second_output, third_output, fifth_output, fourth_output = proof_SNARK
    a_eval_exp, b_eval_exp, c_eval_exp = first_output
    z_eval_exp = second_output
    t_lo_eval_exp, t_mid_eval_exp, t_hi_eval_exp = third_output
    a_zeta, b_zeta, c_zeta, S_1_zeta, S_2_zeta, accumulator_shift_zeta, t_zeta, r_zeta = fourth_output
    W_zeta_eval_exp, W_zeta_omega_eval_exp = fifth_output

    q_exp, s_exp, x_exp = verifier_preprocessing
    q_L_exp, q_R_exp, q_M_exp, q_O_exp, q_C_exp = q_exp
    s_1_exp, s_2_exp, s_3_exp = s_exp

    print("Check1: Elements in group?")
    assert type(a_eval_exp) is SS_BLS12_381
    assert type(b_eval_exp) is SS_BLS12_381
    assert type(c_eval_exp) is SS_BLS12_381
    assert type(z_eval_exp) is SS_BLS12_381
    assert type(t_lo_eval_exp) is SS_BLS12_381
    assert type(t_mid_eval_exp) is SS_BLS12_381
    assert type(t_hi_eval_exp) is SS_BLS12_381
    assert type(W_zeta_eval_exp) is SS_BLS12_381
    assert type(W_zeta_omega_eval_exp) is SS_BLS12_381

    print("Check2: Elements in field?")
    assert type(a_zeta) is Fp
    assert type(b_zeta) is Fp
    assert type(c_zeta) is Fp
    assert type(S_1_zeta) is Fp
    assert type(S_2_zeta) is Fp
    assert type(r_zeta) is Fp
    assert type(accumulator_shift_zeta) is Fp

    print("Check3: Public input in field?")
    assert type(p_i_poly) == polynomialsEvalRep(Fp, omega, n)
    print(type(p_i_poly))

    print("Step4: Recompute challenges from transcript")
    beta = random_fp_seeded(str(first_output) + "0")
    gamma = random_fp_seeded(str(first_output) + "1")
    alpha = random_fp_seeded(str(first_output) + str(second_output))
    zeta = random_fp_seeded(
        str(first_output) + str(second_output) + str(third_output))
    nu = random_fp_seeded(
        str(first_output) + str(second_output) + str(third_output) +
        str(fourth_output))
    u = random_fp_seeded(str(proof_SNARK))

    print("Step5: Evaluate vanishing polynomial at zeta")
    vanishing_poly_eval = zeta**n - Fp(1)

    print("Step6: Evaluate lagrange polynomial at zeta")
    L_1_zeta = (zeta**n - Fp(1)) / (n * (zeta - Fp(1)))

    print("Step7: Evaluate public input polynomial at zeta")
    p_i_poly_zeta = eval_poly(p_i_poly, [zeta])[0]

    print("Step8: Compute quotient polynomial evaluation")
    t_zeta = (r_zeta + p_i_poly_zeta - (a_zeta + beta * S_1_zeta + gamma) *
              (b_zeta + beta * S_2_zeta + gamma) *
              (c_zeta + gamma) * accumulator_shift_zeta * alpha -
              L_1_zeta * alpha**2) / vanishing_poly_eval

    print("Step9: Comupte first part of batched polynomial commitment")
    D_1_exp = (q_M_exp * a_zeta * b_zeta * nu + q_L_exp * a_zeta * nu +
               q_R_exp * b_zeta * nu + q_O_exp * c_zeta * nu + q_C_exp * nu)
    D_1_exp += (z_eval_exp * ((a_zeta + beta * zeta + gamma) *
                              (b_zeta + beta * k * zeta + gamma) *
                              (c_zeta + beta *
                               (k**2) * zeta + gamma) * alpha * nu + L_1_zeta *
                              (alpha**2) * nu + u))
    D_1_exp += (s_3_exp * (a_zeta + beta * S_1_zeta + gamma) *
                (b_zeta + beta * S_2_zeta + gamma) * alpha * beta *
                accumulator_shift_zeta * nu) * Fp(-1)

    print("Step10: Compute full batched polynomial commitment")
    F_1_exp = (t_lo_eval_exp + t_mid_eval_exp * zeta**(n + 2) +
               t_hi_eval_exp * zeta**(2 * (n + 2)) + D_1_exp +
               a_eval_exp * nu**2 + b_eval_exp * nu**3 + c_eval_exp * nu**4 +
               s_1_exp * nu**5 + s_2_exp * nu**6)

    print("Step 11: Compute group encoded batch evaluation")
    E_1_exp = G * (t_zeta + nu * r_zeta + nu**2 * a_zeta + nu**3 * b_zeta +
                   nu**4 * c_zeta + nu**5 * S_1_zeta + nu**6 * S_2_zeta +
                   u * accumulator_shift_zeta)

    print("Check12: Batch validate all evaluations via pairing")
    e11 = W_zeta_eval_exp + W_zeta_omega_eval_exp * u
    e21 = (W_zeta_eval_exp * zeta + W_zeta_omega_eval_exp * u * zeta * omega +
           F_1_exp + (E_1_exp * Fp(-1)))
    assert e11.pair(x_exp) == e21.pair(G2)
    print("Verification Successful!")
Exemplo n.º 13
0
def random_fp_seeded(seeded):
    random.seed(seeded)
    return Fp(random.randint(0, Fp.p - 1))
Exemplo n.º 14
0
#| we write an adaptor for it. See `py_ecc/` and `ssbls12.py` for details.
from ssbls12 import Fp, Poly, Group
G = Group.G
GT = Group.GT

#| ## Choosing the evaluation domain
#| Define some canonical roots $r_1,...,r_m$. These are public parameters
#| and can be set arbitrarily, and in particular they don't depend on the
#| circuit (though there must be enough of them to represent the problem
#| instance).
# This is a global value.
# Initializing it to 1,2,...,128 is enough for small examples in this file.
# We'll overwrite it in `babysnark_setup` when a larger constraint system
# is needed. And in `babysnark_opt.py` we'll define a different policy for
# choosing roots that leads to FFT optimization.
ROOTS = [Fp(i) for i in range(128)]


#| Here we define the vanishing polynomial, which is a degree-$m$ polynomial
#| that roots at the $m$ distinct locations given.
def vanishing_poly(S):
    """
    args: 
       S   (m vector)
    returns:
       p(X) = (X-S1)*(X-S2)*...*(X-Sm)
    """
    p = Poly([Fp(1)])
    for s in S:
        p *= Poly([-s, Fp(1)])
    return p
Exemplo n.º 15
0
def prover_algo(witness, CRS, Qs, p_i_poly, perm_precomp):
    print("Starting the Prover Algorithm")
    n = int(len(witness) / 3)
    assert n & n - 1 == 0, "n must be a power of 2"
    id_domain, perm_domain, k, Ss = perm_precomp

    # We need to convert between representations to multiply and divide more
    # efficiently. In round 3 we have to divide a polynomial of degree 4*n+6
    # Not sure if there is a big benefit in keeping the lower order
    # representations or if it makes sense to do everything in the highest
    # order 8*n right away...

    # polys represented with n points
    omega = omega_base ** (2 ** 32 // n)
    ROOTS = [omega ** i for i in range(n)]
    PolyEvalRep = polynomialsEvalRep(Fp, omega, n)
    witness = [Fp(i) for i in witness]
    witness_poly_a = PolyEvalRep(ROOTS, witness[:n])
    witness_poly_b = PolyEvalRep(ROOTS, witness[n:n*2])
    witness_poly_c = PolyEvalRep(ROOTS, witness[2*n:])
    vanishing_pol_coeff = vanishing_poly(omega, n)

    # polys represented with 2*n points
    omega2 = omega_base ** (2 ** 32 // (2 * n))
    PolyEvalRep2 = polynomialsEvalRep(Fp, omega2, 2 * n)
    vanishing_poly_ext = PolyEvalRep2.from_coeffs(vanishing_pol_coeff)
    witness_poly_a_ext = PolyEvalRep2.from_coeffs(witness_poly_a.to_coeffs())
    witness_poly_b_ext = PolyEvalRep2.from_coeffs(witness_poly_b.to_coeffs())
    witness_poly_c_ext = PolyEvalRep2.from_coeffs(witness_poly_c.to_coeffs())

    # polys represented with 8*n points
    omega3 = omega_base ** (2 ** 32 // (8 * n))
    PolyEvalRep3 = polynomialsEvalRep(Fp, omega3, 8 * n)
    roots3 = [omega3 ** i for i in range(8 * n)]
    S1, S2, S3 = Ss
    S1_ext3 = PolyEvalRep3.from_coeffs(S1.to_coeffs())
    S2_ext3 = PolyEvalRep3.from_coeffs(S2.to_coeffs())
    S3_ext3 = PolyEvalRep3.from_coeffs(S3.to_coeffs())
    p_i_poly_ext3 = PolyEvalRep3.from_coeffs(p_i_poly.to_coeffs())
    qs_ext3 = [PolyEvalRep3.from_coeffs(q.to_coeffs()) for q in Qs]
    q_L_ext3, q_R_ext3, q_M_ext3, q_O_ext3, q_C_ext3 = qs_ext3

    # Following the paper, we are using the Fiat Shamir Heuristic. We are
    # Simulating 5 rounds of communication with the verifier using a
    # random oracle for verifier answers
    print("Starting Round 1...")

    # Generate "random" blinding scalars
    rand_scalars = [random_fp_seeded("1234") for i in range(9)]

    # Generate polys with the random scalars as coefficients and convert to
    # evaluation representation. These are needed for zero knowledge to
    # obfuscate the witness.
    a_blind_poly_ext = Poly([rand_scalars[1], rand_scalars[0]])
    b_blind_poly_ext = Poly([rand_scalars[3], rand_scalars[2]])
    c_blind_poly_ext = Poly([rand_scalars[5], rand_scalars[4]])
    a_blind_poly_ext = PolyEvalRep2.from_coeffs(a_blind_poly_ext)
    b_blind_poly_ext = PolyEvalRep2.from_coeffs(b_blind_poly_ext)
    c_blind_poly_ext = PolyEvalRep2.from_coeffs(c_blind_poly_ext)

    # These polynomals have random evaluations at all points except ROOTS where
    # they evaluate to the witness
    a_poly_ext = a_blind_poly_ext * vanishing_poly_ext + witness_poly_a_ext
    b_poly_ext = b_blind_poly_ext * vanishing_poly_ext + witness_poly_b_ext
    c_poly_ext = c_blind_poly_ext * vanishing_poly_ext + witness_poly_c_ext

    # Evaluate the witness polynomials in the exponent using the CRS
    a_eval_exp = evaluate_in_exponent(CRS, a_poly_ext.to_coeffs())
    b_eval_exp = evaluate_in_exponent(CRS, b_poly_ext.to_coeffs())
    c_eval_exp = evaluate_in_exponent(CRS, c_poly_ext.to_coeffs())

    first_output = [a_eval_exp, b_eval_exp, c_eval_exp]
    print("Round 1 Finished with output: ", first_output)

    print("Starting Round 2...")
    # Compute permutation challenges from imaginary verifier
    beta = random_fp_seeded(str(first_output) + "0")
    gamma = random_fp_seeded(str(first_output) + "1")

    # Compute permutation polynomial. z_1 is the blinding summand needed for ZK
    z_1 = Poly([rand_scalars[8], rand_scalars[7], rand_scalars[6]])
    z_1 = PolyEvalRep2.from_coeffs(z_1)
    z_1 = z_1 * vanishing_poly_ext
    accumulator_poly_eval = [Fp(1)]
    accumulator_poly_eval += [accumulator_factor(n,
                                                 i,
                                                 witness, beta,
                                                 id_domain,
                                                 perm_domain,
                                                 gamma)
                              for i in range(n-1)]
    accumulator_poly = PolyEvalRep(ROOTS, accumulator_poly_eval)
    accumulator_poly = z_1 + PolyEvalRep2.from_coeffs(accumulator_poly.to_coeffs())

    second_output = evaluate_in_exponent(CRS, accumulator_poly.to_coeffs())
    print("Round 2 Finished with output: ", second_output)

    print("Starting Round 3...")
    alpha = random_fp_seeded(str(first_output) + str(second_output))

    accumulator_poly_ext3 = PolyEvalRep3.from_coeffs(accumulator_poly.to_coeffs())

    # The third summand of t has the accumulator poly evaluated at a shift
    accumulator_poly_shift_evaluations = eval_poly(accumulator_poly,
                                                   roots3,
                                                   ROOTS[1])
    accumulator_poly_ext3_shift = PolyEvalRep3(roots3,
                                               accumulator_poly_shift_evaluations)

    a_poly_ext3 = PolyEvalRep3.from_coeffs(a_poly_ext.to_coeffs())
    b_poly_ext3 = PolyEvalRep3.from_coeffs(b_poly_ext.to_coeffs())
    c_poly_ext3 = PolyEvalRep3.from_coeffs(c_poly_ext.to_coeffs())

    id_poly_1_ext3 = PolyEvalRep3.from_coeffs(Poly([gamma, beta]))
    id_poly_2_ext3 = PolyEvalRep3.from_coeffs(Poly([gamma, beta * k]))
    id_poly_3_ext3 = PolyEvalRep3.from_coeffs(Poly([gamma, beta * k**2]))

    gamma_poly = PolyEvalRep3.from_coeffs(Poly([gamma]))
    L_1 = PolyEvalRep(ROOTS, [Fp(1)] + [Fp(0) for i in range(len(ROOTS)-1)])

    # Compute quotient polynomial: we are dividing by the vanishing poly which
    # has zeros at n roots so we need to do division by swapping to a coset
    # first summand should have degree 3n+1, second and third should have
    # degree 4n + 5
    t = ((a_poly_ext3 * b_poly_ext3 * q_M_ext3) +
         (a_poly_ext3 * q_L_ext3) +
         (b_poly_ext3 * q_R_ext3) +
         (c_poly_ext3 * q_O_ext3) +
         q_C_ext3 + p_i_poly_ext3)

    t += ((a_poly_ext3 + id_poly_1_ext3) *
          (b_poly_ext3 + id_poly_2_ext3) *
          (c_poly_ext3 + id_poly_3_ext3) * accumulator_poly_ext3 * alpha)

    t -= ((a_poly_ext3 + S1_ext3 * beta + gamma_poly) *
          (b_poly_ext3 + S2_ext3 * beta + gamma_poly) *
          (c_poly_ext3 + S3_ext3 * beta + gamma_poly) *
          accumulator_poly_ext3_shift * alpha)

    t += ((accumulator_poly_ext3 - PolyEvalRep3.from_coeffs(Poly([Fp(1)]))) *
          PolyEvalRep3.from_coeffs(L_1.to_coeffs()) * alpha ** 2)

    t = PolyEvalRep3.divideWithCoset(t.to_coeffs(), vanishing_pol_coeff)

    t_coeff = t.coefficients

    # We split up the polynomial t in three polynomials so that:
    # t= t_lo + x^n*t_mid + t^2n*t_hi
    # I found that n has actually to be (n+2) to accomodate the CRS because
    # t can be of degree 4n+5
    t_lo = Poly(t_coeff[:n+2])
    t_mid = Poly(t_coeff[n+2:2*(n+2)])
    t_hi = Poly(t_coeff[2*(n+2):])

    t_lo_eval_exp = evaluate_in_exponent(CRS, t_lo)
    t_mid_eval_exp = evaluate_in_exponent(CRS, t_mid)
    t_hi_eval_exp = evaluate_in_exponent(CRS, t_hi)

    third_output = [t_lo_eval_exp, t_mid_eval_exp, t_hi_eval_exp]
    print("Round 3 Finished with output: ", third_output)

    print("Starting Round 4...")
    # Compute the evaluation challenge
    zeta = random_fp_seeded(str(first_output) +
                            str(second_output) +
                            str(third_output))

    # Compute the opening evaluations
    a_zeta = eval_poly(a_poly_ext, [zeta])[0]
    b_zeta = eval_poly(b_poly_ext, [zeta])[0]
    c_zeta = eval_poly(c_poly_ext, [zeta])[0]
    S_1_zeta = eval_poly(S1, [zeta])[0]
    S_2_zeta = eval_poly(S2, [zeta])[0]
    t_zeta = eval_poly(PolyEvalRep3.from_coeffs(t), [zeta])[0]
    accumulator_shift_zeta = eval_poly(accumulator_poly_ext3,
                                       [zeta * ROOTS[1]])[0]

    # Compute linerisation polynomial
    r = (q_M_ext3 * a_zeta * b_zeta +
         q_L_ext3 * a_zeta +
         q_R_ext3 * b_zeta +
         q_O_ext3 * c_zeta +
         q_C_ext3)
    r += (accumulator_poly_ext3 *
          (a_zeta + beta * zeta + gamma) *
          (b_zeta + beta * k * zeta + gamma) *
          (c_zeta + beta * (k ** 2) * zeta + gamma) * alpha)
    r -= (S3_ext3 *
          (a_zeta + beta * S_1_zeta + gamma) *
          (b_zeta + beta * S_2_zeta + gamma) *
          alpha * beta * accumulator_shift_zeta)
    r += accumulator_poly_ext3 * eval_poly(L_1, [zeta])[0] * alpha ** 2

    # Evaluate r at zeta
    r_zeta = eval_poly(r, [zeta])[0]

    fourth_output = [a_zeta, b_zeta, c_zeta, S_1_zeta, S_2_zeta,
                     accumulator_shift_zeta, t_zeta, r_zeta]
    print("Round 4 Finished with output: ", fourth_output)

    print("Starting Round 5...")
    # Compute opening challeng
    nu = random_fp_seeded(str(first_output) +
                          str(second_output) +
                          str(third_output) +
                          str(fourth_output))

    # Compute opening proof polynomial
    W_zeta = (PolyEvalRep3.from_coeffs(t_lo) +
              PolyEvalRep3.from_coeffs(t_mid) * zeta ** (n+2) +
              PolyEvalRep3.from_coeffs(t_hi) * zeta ** (2*(n+2)) -
              PolyEvalRep3.from_coeffs(Poly([t_zeta])) +
              (r - PolyEvalRep3.from_coeffs(Poly([r_zeta]))) * nu +
              (a_poly_ext3 - PolyEvalRep3.from_coeffs(Poly([a_zeta]))) * nu ** 2 +
              (b_poly_ext3 - PolyEvalRep3.from_coeffs(Poly([b_zeta]))) * nu ** 3 +
              (c_poly_ext3 - PolyEvalRep3.from_coeffs(Poly([c_zeta]))) * nu ** 4 +
              (S1_ext3 - PolyEvalRep3.from_coeffs(Poly([S_1_zeta]))) * nu ** 5 +
              (S2_ext3 - PolyEvalRep3.from_coeffs(Poly([S_2_zeta]))) * nu ** 6)
    W_zeta = W_zeta / PolyEvalRep3.from_coeffs(Poly([-zeta, Fp(1)]))

    # Compute the opening proof polynomial
    W_zeta_omega = accumulator_poly_ext3 - PolyEvalRep3.from_coeffs(Poly([accumulator_shift_zeta]))
    W_zeta_omega = W_zeta_omega / PolyEvalRep3.from_coeffs(Poly([-zeta*ROOTS[1], Fp(1)]))

    W_zeta_eval_exp = evaluate_in_exponent(CRS, W_zeta.to_coeffs())
    W_zeta_omega_eval_exp = evaluate_in_exponent(CRS, W_zeta_omega.to_coeffs())

    fifth_output = [W_zeta_eval_exp, W_zeta_omega_eval_exp]
    proof_SNARK = [first_output, second_output, third_output, fifth_output, fourth_output]
    print("Round 5 Finished with output: ", fifth_output)

    u = random_fp_seeded(str(proof_SNARK))
    return proof_SNARK, u
Exemplo n.º 16
0
    def compile_to_solved_ssp(self, inp):

        # Evaluate the circuit to process the values of all gates
        # from the inputs
        self.evaluate(inp)

        # Preprocess the wires into the list of the desired form
        # We want all the wires for which we have inputs to be first
        # Recall a_vec = [1 a_stmt a_witness]
        a_vec = self.convert_wires_to_a_vec()

        # Store U in sparse form
        m = len(a_vec) - 1 + len(self.sorted_gates)
        m = nearestPowerOfTwo(m)
        n = len(a_vec)
        U = RowDictSparseMatrix(m, n)

        constraint_index = 0

        for wire_index in range(1, len(a_vec)):
            wire_label = a_vec[wire_index]
            if wire_label not in self.statements_wires:
                # Put 0,1 constaint as a column
                # number of rows per column is len(wires) + 1
                U[constraint_index, wire_index] = Fp(2)
                U[constraint_index, 0] = Fp(-1)
            else:
                # The wire must have some fixed value
                U[constraint_index, wire_index] = Fp(1)
                # force w_i to the correct value
                U[constraint_index, 0] = Fp(1 - self.wire_values[wire_label])
            constraint_index = constraint_index + 1

        # Now add constraints per type of gate
        for gid in self.sorted_gates:
            gate = self.gates[gid]

            inp1 = gate["inp"][0]
            ind_inp1 = self.get_index(inp1)
            out = gate["out"][0]
            ind_out = self.get_index(out)
            """
            a + b - 2 + 2c in {0,1}

            2a + 2b - 4 + 4c in {0,2}

            2a + 2b + 4c - 5 in {-1,1}
            """
            if gate["type"] == "NAND":
                inp2 = gate["inp"][1]
                ind_inp2 = self.get_index(inp2)
                U[constraint_index, ind_inp1] = Fp(2)
                U[constraint_index, ind_inp2] = Fp(2)
                U[constraint_index, ind_out] = Fp(4)
                U[constraint_index, 0] = Fp(-5)
            if gate["type"] == "INV":
                U[constraint_index, ind_inp1] = Fp(1)
                U[constraint_index, ind_out] = Fp(1)
            elif gate["type"] == "AND":
                inp2 = gate["inp"][1]
                ind_inp2 = self.get_index(inp2)
                U[constraint_index, ind_inp1] = Fp(2)
                U[constraint_index, ind_inp2] = Fp(2)
                U[constraint_index, ind_out] = Fp(-4)
                U[constraint_index, 0] = Fp(-1)
            elif gate["type"] == "OR":
                inp2 = gate["inp"][1]
                ind_inp2 = self.get_index(inp2)
                U[constraint_index, ind_inp1] = Fp(-2)
                U[constraint_index, ind_inp2] = Fp(-2)
                U[constraint_index, ind_out] = Fp(4)
                U[constraint_index, 0] = Fp(-1)
            elif gate["type"] == "XOR":
                inp2 = gate["inp"][1]
                ind_inp2 = self.get_index(inp2)
                U[constraint_index, ind_inp1] = Fp(1)
                U[constraint_index, ind_inp2] = Fp(1)
                U[constraint_index, ind_out] = Fp(1)
                U[constraint_index, 0] = Fp(-1)
            else:
                raise Exception(
                    "We don't support any other gate than NAND/OR/AND/XOR/INV for now"
                )
            constraint_index += 1

        # Finally fill up the remaining spaces with dummy constraitns
        # of 1 = 1
        while constraint_index < U.m:
            U[constraint_index, 0] = Fp(1)
            constraint_index += 1
        # create the final witness with values in it
        # The first value is 1, others are according to the evaluated circuit
        a_final = [1] + [
            self.wire_values[a_vec[i]] for i in range(1, len(a_vec))
        ]
        assert len(a_final) == 1 + len(self.wire_values)
        # Returns a tuple with number of public inputs, a_vec and U
        return (1 + len(self.statements_wires), a_final, U)