Appearance
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)