Skip to content

Verifying a proof ​

Now all that is left for the verifier is to reconstruct step by step the transcript and check that everything passes! If you implemented the above exercises correctly, this check should pass.

python
def verify_plonk(proof_dictionary):
    # 0. Reconstruct transcript
    transcript = ""
    if (value_a != 0 or value_b != 1):
        return False, "Input values are not correct"
    # 1. Round 1: commitments to a, b, c
    for name in ('value_a','value_b','output'):
        transcript = push(proof_dictionary['evaluations'][name], transcript)    
    for name in ('c_a','c_b','c_c'):
        transcript = push(proof_dictionary['commitments'][name], transcript)
    
    # 2. Round 2: beta, gamma
    beta_v = generate_challenge(transcript)
    if beta_v != proof_dictionary['challenges']['beta']:
        print(beta_v, proof_dictionary['challenges']['beta'])
        return False, "beta mismatch"
    transcript = push(beta_v, transcript)
    

    gamma_v = generate_challenge(transcript)
    if gamma_v != proof_dictionary['challenges']['gamma']:
        return False, "gamma mismatch"
    transcript = push(gamma_v, transcript)
    
    # append z commitment
    transcript = push(proof_dictionary['commitments']['c_z'], transcript)
    
    # 3. Round 3: alpha
    alpha_v = generate_challenge(transcript)
    if alpha_v != proof_dictionary['challenges']['alpha']:
        return False, "alpha mismatch"
    transcript = push(alpha_v, transcript)
    
    # append t commitment
    transcript = push(proof_dictionary['commitments']['c_t'], transcript)
    
    # 4. Round 4: zeta
    zeta_v = generate_challenge(transcript)
    if zeta_v != proof_dictionary['challenges']['zeta']:
        return False, "zeta mismatch"
    transcript = push(zeta_v, transcript)
    
    
    # 5. Pairing checks for each opening
    checks = [
        # inputs and output openings
        ('c_a',          'proof_value_a',         'value_a', Ο‰),
        ('c_b',          'proof_value_b',         'value_b',Ο‰),
        ('c_c',          'proof_output',         'output',Ο‰^4),
        # witness openings
        ('c_a',          'proof_a',         'a_zeta', zeta_v),
        ('c_b',          'proof_b',         'b_zeta',zeta_v),
        ('c_c',          'proof_c',         'c_zeta',zeta_v),
        # z and t openings
        ('c_z',          'proof_z',         'z_zeta',zeta_v),
        ('c_t',          'proof_t',         't_zeta',zeta_v),
        # z(ΞΆΒ·Ο‰) for perm check
        ('c_z',          'proof_z_omega',   'z_zeta_omega',zeta_v* Ο‰ ),
    ]
    
    for (c_key, Ο€_key, b_key, challenge_point) in checks:
        C = proof_dictionary['commitments'][c_key]
        Ο€ = proof_dictionary['proofs'][Ο€_key]
        b = proof_dictionary['evaluations'][b_key]
    
        if not verification(C, Ο€, challenge_point, b):
            return False, f"Pairing check failed for {c_key}"

    qL_z = qL(zeta_v)
    qR_z = qR(zeta_v)
    qM_z = qM(zeta_v)
    N_z = N_poly(zeta_v)
    D_z = D_poly(zeta_v)

    # Check 1: Gate constraints
    
    t_gates_v = qM_z*a_zeta*b_zeta + qL_z*a_zeta+qR_z*b_zeta-c_zeta

    # Check 2: Permutation constraints
    L1_z = L1(zeta_v)
    t_perm_start_v = (z_zeta - 1) * L1_z
    t_perm_step_v = z_zeta * N_z - D_z * z_zeta_omega

    # Check 3: Quotient constraint
    # Reconstruct the value of the master polynomial at zeta
    master_poly_v = t_gates_v + alpha_v * t_perm_start_v + alpha_v**2 * t_perm_step_v

    # Reconstruct the value of the vanishing polynomial at zeta
    ZH_z = zeta_v**n - 1

    # The final check: Does the master polynomial identity hold?
    if master_poly_v == t_zeta * ZH_z:
        print("Quotient constraint holds.")
    else:
        return False, "Quotient constraint check failed!"    

    return True, "All checks passed!"

# --- Example invocation ---
ok, msg = verify_plonk(proof_dictionary)
print("Verifier result:", ok, msg)

𝒫𝔩𝔬𝔫𝒦 Tutorial by zkSecurity