Skip to content
master
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
research/py_plonk/
research/py_plonk/

Latest commit

 

Git stats

Files

Permalink
Failed to load latest commit information.
Type
Name
Latest commit message
Commit time
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Py_plonk

Py_plonk is a simple python implementation of the PLONK protocol as described in https://eprint.iacr.org/2019/953.pdf (see also https://vitalik.ca/general/2019/09/22/plonk.html), targeted to be close to compatible with the implementation at https://zkrepl.dev. Py_plonk includes:

  • A simple programming language for describing circuits, which it can compile into the forms needed for a PLONK proof (QL, QR, QM, QO, QC, S1, S2, S3 polynomials)
  • A prover that can generate proofs for this language, given a list of variable assignments
  • A verifier that can verify these proofs

Full compatibility is achieved in some cases: for simple programs, py_plonk is capable of outputting verification keys that exactly match https://zkrepl.dev output. See the tests in test.py for some examples.

This implementation is intended for educational use, and to help reproduce and verify verification keys that are generated by other software. IT HAS NOT BEEN AUDITED AND PROBABLY HAS BUGS, DO NOT USE BY ITSELF IN PRODUCTION.

Many features are missing. The parts of PLONK that are responsible for ensuring strong privacy are left out (they are easy to add, they would simply increase complexity and reduce the educational value of this implementation).

Example

Here is a program that lets you prove that you know two small numbers that multiply to a given number (in our example we'll use 91) without revealing what those numbers are:

n public
pb0 === pb0 * pb0
pb1 === pb1 * pb1
pb2 === pb2 * pb2
pb3 === pb3 * pb3
qb0 === qb0 * qb0
qb1 === qb1 * qb1
qb2 === qb2 * qb2
qb3 === qb3 * qb3
pb01 <== pb0 + 2 * pb1
pb012 <== pb01 + 4 * pb2
p <== pb012 + 8 * pb3
qb01 <== qb0 + 2 * qb1
qb012 <== qb01 + 4 * qb2
q <== qb012 + 8 * qb3
n <== p * q

Generating the verification key:

setup = utils.Setup.from_file(SETUP_FILENAME)
vk = make_verification_key(setup, 16, string_containing_the_above_code)

A setup file is in this repo. The second argument is the group order; it should be a power of two, at least 8, and at least the number of lines of code in the program.

Proving:

assignments = compiler.fill_variable_assignments(eqs, {
    'pb3': 1, 'pb2': 1, 'pb1': 0, 'pb0': 1,
    'qb3': 0, 'qb2': 1, 'qb1': 1, 'qb0': 1,
})
proof = prover.prove_from_witness(setup, 16, eqs, assignments)

compiler.fill_variable_assignments is a convenience method that executes the program to fill in any variables that you do not specify yourself. In this case, you only specify the bits of the two factors (7 and 13), the program can compute all the other intermediate and final variables for you.

prove_from_witness generates a proof, passing in the full set of assignments as input.

Verifying:

assert verifier.verify_proof(setup, 16, vk, proof, [91], optimized=True)