There is a main verifier class that contains the core logic for verifying a PLONK proof.
Various significant functionalities have been broken out into their own modular blocks, to make testing easier and the code easier to follow. To this end, there is a Transcript class to calculate the challenges and a polynomialEval set of functions to perform the polynomial evaluation calculations.
C++ Barretenberg
A test circuit has been added to the prover code in the C++ Barretenberg module. It uses standard PLONK, to construct a test proof against which the verifier can be tested.
Verifier - /src/verifier/index.ts
There is a main Verifier class which performs the key PLONK methods. It inherits from BaseVerifier.ts
The constructor sets things up, decoding the proof, the verification key, extracting the preprocessed input etc.
There are three key methods:
computeChallenges() - calculatet the init, beta, gamma, alpha, `
computePolynomialEvaluations() - evaluate the various required polynomials
verifyProof() - validate the proof, using the preprocessed input, challenges and polynomial evaluations
BaseVerifier - 'src/verifier/BaseVerifier.ts`
Provides non-PLONK version specific utility like methods that are needed during the proof verification process, such as proof decoding.
Transcript - src/transcript/index.ts
Used to calculate the challenges created by the PLONK prover, and required for the verifier. The challenge calculation follows the methods used in the C++ verifier code, rather than the paper.
Challenge generation tested against an example proof generated by Barretenberg
polynomialEval - src/polynomialEval/index.ts
This section is the heaviest work in progress section of the verifier. It aims to evaluate the various polynomials according to the original PLONK paper.
Testing instructions
barretenberg.js uses Jest for it's testing framework. To run the appropriate tests use:
jest 'src/transcript/index.test.tsjest 'src/polynomialEval/index.test.tsjest 'src/verifier/index.test.ts
TODOs
There are various aspects of the verifier still to be completed - these are marked by TODOs throughout the code. The main ones are:
extractPreProcessed() function needs implementing. Necessary to extract the selector polynomails, k1, k2 and sigmas
decodeVerificationKey() needs refactoring, to correctly extract numPublicInputs and circuitSize from the verification key; once the C++ prover has added support to export it
polynomialEvals - these have been naively implemented according to the original paper and not yet tested
verifyProof() function does not actually perform the pairing check - would need to use the mcl-wasm library. I don't plan on implementing this. The verifier will be complete when the output of the polynomial evaluations match those generated by the C++ verifier.
Feedback
Interested primarily in feedback on:
1) Code structure/how I've broken the Verifier down into discrete modular chunks
2) General guidance on whether the Verifier is broadly doing things correctly, any glaring misunderstandings etc
3) Ideas as to how I can manage the large numbers of inputs to various functions better - several functions are requiring 15, maybe 20 inputs which doesn't look great + clutters things
Summary
This PR adds a WIP TypeScript implementation of the PLONK verifier as described in the original paper: https://eprint.iacr.org/2019/953.pdf
Description
There is a main verifier class that contains the core logic for verifying a PLONK proof.
Various significant functionalities have been broken out into their own modular blocks, to make testing easier and the code easier to follow. To this end, there is a
Transcript
class to calculate the challenges and apolynomialEval
set of functions to perform the polynomial evaluation calculations.C++ Barretenberg
A test circuit has been added to the prover code in the C++ Barretenberg module. It uses standard PLONK, to construct a test proof against which the verifier can be tested.
Verifier -
/src/verifier/index.ts
There is a main
Verifier
class which performs the key PLONK methods. It inherits fromBaseVerifier.ts
The constructor sets things up, decoding the proof, the verification key, extracting the preprocessed input etc.
There are three key methods:
computeChallenges()
- calculatet theinit
,beta
,gamma
,alpha
, `computePolynomialEvaluations()
- evaluate the various required polynomialsverifyProof()
- validate the proof, using the preprocessed input, challenges and polynomial evaluationsBaseVerifier - 'src/verifier/BaseVerifier.ts`
Provides non-PLONK version specific utility like methods that are needed during the proof verification process, such as proof decoding.
Transcript -
src/transcript/index.ts
Used to calculate the challenges created by the PLONK prover, and required for the verifier. The challenge calculation follows the methods used in the C++ verifier code, rather than the paper.
Challenge generation tested against an example proof generated by
Barretenberg
polynomialEval -
src/polynomialEval/index.ts
This section is the heaviest work in progress section of the verifier. It aims to evaluate the various polynomials according to the original PLONK paper.
Testing instructions
barretenberg.js
usesJest
for it's testing framework. To run the appropriate tests use:jest 'src/transcript/index.test.ts
jest 'src/polynomialEval/index.test.ts
jest 'src/verifier/index.test.ts
TODOs
There are various aspects of the verifier still to be completed - these are marked by
TODO
s throughout the code. The main ones are:extractPreProcessed()
function needs implementing. Necessary to extract the selector polynomails,k1
,k2
and sigmasdecodeVerificationKey()
needs refactoring, to correctly extractnumPublicInputs
andcircuitSize
from the verification key; once the C++ prover has added support to export itpolynomialEvals
- these have been naively implemented according to the original paper and not yet testedverifyProof()
function does not actually perform the pairing check - would need to use themcl-wasm
library. I don't plan on implementing this. The verifier will be complete when the output of the polynomial evaluations match those generated by the C++ verifier.Feedback
Interested primarily in feedback on: 1) Code structure/how I've broken the Verifier down into discrete modular chunks 2) General guidance on whether the Verifier is broadly doing things correctly, any glaring misunderstandings etc 3) Ideas as to how I can manage the large numbers of inputs to various functions better - several functions are requiring 15, maybe 20 inputs which doesn't look great + clutters things