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)
12
13type VerifierChip struct {
14 api frontend.API `gnark:"-"`
15 glChip *gl.GoldilocksApi `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 types.CommonCircuitData) *VerifierChip {
23 glChip := gl.NewGoldilocksApi(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.GoldilocksVariable) poseidon.GoldilocksHashOut {
39 return c.poseidonGlChip.HashNoPad(publicInputs)
40}
41
42func (c *VerifierChip) GetChallenges(
43 proof types.Proof,
44 publicInputsHash poseidon.GoldilocksHashOut,
45 commonData types.CommonCircuitData,
46 verifierData types.VerifierOnlyCircuitData,
47) types.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 types.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
83/*
84func (c *VerifierChip) generateProofInput(commonData common.CommonCircuitData) common.ProofWithPublicInputs {
85 // Generate the parts of the witness that is for the plonky2 proof input
86
87 capHeight := commonData.Config.FriConfig.CapHeight
88
89 friCommitPhaseMerkleCaps := []common.MerkleCap{}
90 for i := 0; i < len(commonData.FriParams.ReductionArityBits); i++ {
91 friCommitPhaseMerkleCaps = append(friCommitPhaseMerkleCaps, common.NewMerkleCap(capHeight))
92 }
93
94 salt := commonData.SaltSize()
95 numLeavesPerOracle := []uint{
96 commonData.NumPreprocessedPolys(),
97 commonData.Config.NumWires + salt,
98 commonData.NumZsPartialProductsPolys() + salt,
99 commonData.NumQuotientPolys() + salt,
100 }
101 friQueryRoundProofs := []common.FriQueryRound{}
102 for i := uint64(0); i < commonData.FriParams.Config.NumQueryRounds; i++ {
103 evalProofs := []common.EvalProof{}
104 merkleProofLen := commonData.FriParams.LDEBits() - capHeight
105 for _, numLeaves := range numLeavesPerOracle {
106 leaves := make([]field.F, numLeaves)
107 merkleProof := common.NewMerkleProof(merkleProofLen)
108 evalProofs = append(evalProofs, common.NewEvalProof(leaves, merkleProof))
109 }
110
111 initialTreesProof := common.NewFriInitialTreeProof(evalProofs)
112 steps := []common.FriQueryStep{}
113 for _, arityBit := range commonData.FriParams.ReductionArityBits {
114 if merkleProofLen < arityBit {
115 panic("merkleProofLen < arityBits")
116 }
117
118 steps = append(steps, common.NewFriQueryStep(arityBit, merkleProofLen))
119 }
120
121 friQueryRoundProofs = append(friQueryRoundProofs, common.NewFriQueryRound(steps, initialTreesProof))
122 }
123
124 proofInput := common.ProofWithPublicInputs{
125 Proof: common.Proof{
126 WiresCap: common.NewMerkleCap(capHeight),
127 PlonkZsPartialProductsCap: common.NewMerkleCap(capHeight),
128 QuotientPolysCap: common.NewMerkleCap(capHeight),
129 Openings: common.NewOpeningSet(
130 commonData.Config.NumConstants,
131 commonData.Config.NumRoutedWires,
132 commonData.Config.NumWires,
133 commonData.Config.NumChallenges,
134 commonData.NumPartialProducts,
135 commonData.QuotientDegreeFactor,
136 ),
137 OpeningProof: common.FriProof{
138 CommitPhaseMerkleCaps: friCommitPhaseMerkleCaps,
139 QueryRoundProofs: friQueryRoundProofs,
140 FinalPoly: common.NewPolynomialCoeffs(commonData.FriParams.FinalPolyLen()),
141 },
142 },
143 PublicInputs: make([]field.F, commonData.NumPublicInputs),
144 }
145
146 return proofInput
147}
148*/
149
150func (c *VerifierChip) rangeCheckProof(proof types.Proof) {
151 // Need to verify the plonky2 proof's openings, openings proof (other than the sibling elements), fri's final poly, pow witness.
152
153 // 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,
154 // we will assume that caller is doing that check.
155
156 // Range check the proof's openings.
157 for _, constant := range proof.Openings.Constants {
158 c.glChip.RangeCheckQE(constant)
159 }
160
161 for _, plonkSigma := range proof.Openings.PlonkSigmas {
162 c.glChip.RangeCheckQE(plonkSigma)
163 }
164
165 for _, wire := range proof.Openings.Wires {
166 c.glChip.RangeCheckQE(wire)
167 }
168
169 for _, plonkZ := range proof.Openings.PlonkZs {
170 c.glChip.RangeCheckQE(plonkZ)
171 }
172
173 for _, plonkZNext := range proof.Openings.PlonkZsNext {
174 c.glChip.RangeCheckQE(plonkZNext)
175 }
176
177 for _, partialProduct := range proof.Openings.PartialProducts {
178 c.glChip.RangeCheckQE(partialProduct)
179 }
180
181 for _, quotientPoly := range proof.Openings.QuotientPolys {
182 c.glChip.RangeCheckQE(quotientPoly)
183 }
184
185 // Range check the openings proof.
186 for _, queryRound := range proof.OpeningProof.QueryRoundProofs {
187 for _, initialTreesElement := range queryRound.InitialTreesProof.EvalsProofs[0].Elements {
188 c.glChip.RangeCheck(initialTreesElement)
189 }
190
191 for _, queryStep := range queryRound.Steps {
192 for _, eval := range queryStep.Evals {
193 c.glChip.RangeCheckQE(eval)
194 }
195 }
196 }
197
198 // Range check the fri's final poly.
199 for _, coeff := range proof.OpeningProof.FinalPoly.Coeffs {
200 c.glChip.RangeCheckQE(coeff)
201 }
202
203 // Range check the pow witness.
204 c.glChip.RangeCheck(proof.OpeningProof.PowWitness)
205}
206
207func (c *VerifierChip) Verify(
208 proof types.Proof,
209 publicInputs []gl.GoldilocksVariable,
210 verifierData types.VerifierOnlyCircuitData,
211 commonData types.CommonCircuitData,
212) {
213 c.rangeCheckProof(proof)
214
215 // Generate the parts of the witness that is for the plonky2 proof input
216 publicInputsHash := c.GetPublicInputsHash(publicInputs)
217 proofChallenges := c.GetChallenges(proof, publicInputsHash, commonData, verifierData)
218
219 c.plonkChip.Verify(proofChallenges, proof.Openings, publicInputsHash)
220
221 initialMerkleCaps := []types.FriMerkleCap{
222 verifierData.ConstantSigmasCap,
223 proof.WiresCap,
224 proof.PlonkZsPartialProductsCap,
225 proof.QuotientPolysCap,
226 }
227
228 c.friChip.VerifyFriProof(
229 fri.GetInstance(&commonData, c.glChip, proofChallenges.PlonkZeta, commonData.DegreeBits),
230 fri.ToOpenings(proof.Openings),
231 &proofChallenges.FriChallenges,
232 initialMerkleCaps,
233 &proof.OpeningProof,
234 )
235}