gnark-plonky2-verifier/verifier/verifier.go
verifier/verifier.goRaw
1package verifier
2
3import (
4 "github.com/consensys/gnark/frontend"
5 "github.com/succinctlabs/gnark-plonky2-verifier/challenger"
6 "github.com/succinctlabs/gnark-plonky2-verifier/fri"
7 gl "github.com/succinctlabs/gnark-plonky2-verifier/goldilocks"
8 "github.com/succinctlabs/gnark-plonky2-verifier/plonk"
9 "github.com/succinctlabs/gnark-plonky2-verifier/poseidon"
10 "github.com/succinctlabs/gnark-plonky2-verifier/variables"
11)
12
13type VerifierChip struct {
14 api frontend.API `gnark:"-"`
15 glChip *gl.Chip `gnark:"-"`
16 poseidonGlChip *poseidon.GoldilocksChip `gnark:"-"`
17 poseidonBN254Chip *poseidon.BN254Chip `gnark:"-"`
18 plonkChip *plonk.PlonkChip `gnark:"-"`
19 friChip *fri.Chip `gnark:"-"`
20}
21
22func NewVerifierChip(api frontend.API, commonCircuitData variables.CommonCircuitData) *VerifierChip {
23 glChip := gl.New(api)
24 friChip := fri.NewChip(api, &commonCircuitData.FriParams)
25 plonkChip := plonk.NewPlonkChip(api, commonCircuitData)
26 poseidonGlChip := poseidon.NewGoldilocksChip(api)
27 poseidonBN254Chip := poseidon.NewBN254Chip(api)
28 return &VerifierChip{
29 api: api,
30 glChip: glChip,
31 poseidonGlChip: poseidonGlChip,
32 poseidonBN254Chip: poseidonBN254Chip,
33 plonkChip: plonkChip,
34 friChip: friChip,
35 }
36}
37
38func (c *VerifierChip) GetPublicInputsHash(publicInputs []gl.Variable) poseidon.GoldilocksHashOut {
39 return c.poseidonGlChip.HashNoPad(publicInputs)
40}
41
42func (c *VerifierChip) GetChallenges(
43 proof variables.Proof,
44 publicInputsHash poseidon.GoldilocksHashOut,
45 commonData variables.CommonCircuitData,
46 verifierData variables.VerifierOnlyCircuitData,
47) variables.ProofChallenges {
48 config := commonData.Config
49 numChallenges := config.NumChallenges
50 challenger := challenger.NewChip(c.api)
51
52 var circuitDigest = verifierData.CircuitDigest
53
54 challenger.ObserveBN254Hash(circuitDigest)
55 challenger.ObserveHash(publicInputsHash)
56 challenger.ObserveCap(proof.WiresCap)
57 plonkBetas := challenger.GetNChallenges(numChallenges)
58 plonkGammas := challenger.GetNChallenges(numChallenges)
59
60 challenger.ObserveCap(proof.PlonkZsPartialProductsCap)
61 plonkAlphas := challenger.GetNChallenges(numChallenges)
62
63 challenger.ObserveCap(proof.QuotientPolysCap)
64 plonkZeta := challenger.GetExtensionChallenge()
65
66 challenger.ObserveOpenings(fri.ToOpenings(proof.Openings))
67
68 return variables.ProofChallenges{
69 PlonkBetas: plonkBetas,
70 PlonkGammas: plonkGammas,
71 PlonkAlphas: plonkAlphas,
72 PlonkZeta: plonkZeta,
73 FriChallenges: challenger.GetFriChallenges(
74 proof.OpeningProof.CommitPhaseMerkleCaps,
75 proof.OpeningProof.FinalPoly,
76 proof.OpeningProof.PowWitness,
77 commonData.DegreeBits,
78 config.FriConfig,
79 ),
80 }
81}
82
83func (c *VerifierChip) rangeCheckProof(proof variables.Proof) {
84 // Need to verify the plonky2 proof's openings, openings proof (other than the sibling elements), fri's final poly, pow witness.
85
86 // Note that this is NOT range checking the public inputs (first 32 elements should be no more than 8 bits and the last 4 elements should be no more than 64 bits). Since this is currently being inputted via the smart contract,
87 // we will assume that caller is doing that check.
88
89 // Range check the proof's openings.
90 for _, constant := range proof.Openings.Constants {
91 c.glChip.RangeCheckQE(constant)
92 }
93
94 for _, plonkSigma := range proof.Openings.PlonkSigmas {
95 c.glChip.RangeCheckQE(plonkSigma)
96 }
97
98 for _, wire := range proof.Openings.Wires {
99 c.glChip.RangeCheckQE(wire)
100 }
101
102 for _, plonkZ := range proof.Openings.PlonkZs {
103 c.glChip.RangeCheckQE(plonkZ)
104 }
105
106 for _, plonkZNext := range proof.Openings.PlonkZsNext {
107 c.glChip.RangeCheckQE(plonkZNext)
108 }
109
110 for _, partialProduct := range proof.Openings.PartialProducts {
111 c.glChip.RangeCheckQE(partialProduct)
112 }
113
114 for _, quotientPoly := range proof.Openings.QuotientPolys {
115 c.glChip.RangeCheckQE(quotientPoly)
116 }
117
118 // Range check the openings proof.
119 for _, queryRound := range proof.OpeningProof.QueryRoundProofs {
120 for _, initialTreesElement := range queryRound.InitialTreesProof.EvalsProofs[0].Elements {
121 c.glChip.RangeCheck(initialTreesElement)
122 }
123
124 for _, queryStep := range queryRound.Steps {
125 for _, eval := range queryStep.Evals {
126 c.glChip.RangeCheckQE(eval)
127 }
128 }
129 }
130
131 // Range check the fri's final poly.
132 for _, coeff := range proof.OpeningProof.FinalPoly.Coeffs {
133 c.glChip.RangeCheckQE(coeff)
134 }
135
136 // Range check the pow witness.
137 c.glChip.RangeCheck(proof.OpeningProof.PowWitness)
138}
139
140func (c *VerifierChip) Verify(
141 proof variables.Proof,
142 publicInputs []gl.Variable,
143 verifierData variables.VerifierOnlyCircuitData,
144 commonData variables.CommonCircuitData,
145) {
146 c.rangeCheckProof(proof)
147
148 // Generate the parts of the witness that is for the plonky2 proof input
149 publicInputsHash := c.GetPublicInputsHash(publicInputs)
150 proofChallenges := c.GetChallenges(proof, publicInputsHash, commonData, verifierData)
151
152 c.plonkChip.Verify(proofChallenges, proof.Openings, publicInputsHash)
153
154 initialMerkleCaps := []variables.FriMerkleCap{
155 verifierData.ConstantSigmasCap,
156 proof.WiresCap,
157 proof.PlonkZsPartialProductsCap,
158 proof.QuotientPolysCap,
159 }
160
161 c.friChip.VerifyFriProof(
162 fri.GetInstance(&commonData, c.glChip, proofChallenges.PlonkZeta, commonData.DegreeBits),
163 fri.ToOpenings(proof.Openings),
164 &proofChallenges.FriChallenges,
165 initialMerkleCaps,
166 &proof.OpeningProof,
167 )
168}