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