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 config.FriConfig,
80 ),
81 }
82}
83
84func (c *VerifierChip) rangeCheckProof(proof variables.Proof) {
85 // Need to verify the plonky2 proof's openings, openings proof (other than the sibling elements), fri's final poly, pow witness.
86
87 // 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,
88 // we will assume that caller is doing that check.
89
90 // Range check the proof's openings.
91 for _, constant := range proof.Openings.Constants {
92 c.glChip.RangeCheckQE(constant)
93 }
94
95 for _, plonkSigma := range proof.Openings.PlonkSigmas {
96 c.glChip.RangeCheckQE(plonkSigma)
97 }
98
99 for _, wire := range proof.Openings.Wires {
100 c.glChip.RangeCheckQE(wire)
101 }
102
103 for _, plonkZ := range proof.Openings.PlonkZs {
104 c.glChip.RangeCheckQE(plonkZ)
105 }
106
107 for _, plonkZNext := range proof.Openings.PlonkZsNext {
108 c.glChip.RangeCheckQE(plonkZNext)
109 }
110
111 for _, partialProduct := range proof.Openings.PartialProducts {
112 c.glChip.RangeCheckQE(partialProduct)
113 }
114
115 for _, quotientPoly := range proof.Openings.QuotientPolys {
116 c.glChip.RangeCheckQE(quotientPoly)
117 }
118
119 // Range check the openings proof.
120 for _, queryRound := range proof.OpeningProof.QueryRoundProofs {
121 for _, evalsProof := range queryRound.InitialTreesProof.EvalsProofs {
122 for _, evalsProofElement := range evalsProof.Elements {
123 c.glChip.RangeCheck(evalsProofElement)
124 }
125 }
126
127 for _, queryStep := range queryRound.Steps {
128 for _, eval := range queryStep.Evals {
129 c.glChip.RangeCheckQE(eval)
130 }
131 }
132 }
133
134 // Range check the fri's final poly.
135 for _, coeff := range proof.OpeningProof.FinalPoly.Coeffs {
136 c.glChip.RangeCheckQE(coeff)
137 }
138
139 // Range check the pow witness.
140 c.glChip.RangeCheck(proof.OpeningProof.PowWitness)
141}
142
143func (c *VerifierChip) Verify(
144 proof variables.Proof,
145 publicInputs []gl.Variable,
146 verifierData variables.VerifierOnlyCircuitData,
147) {
148 c.rangeCheckProof(proof)
149
150 // Generate the parts of the witness that is for the plonky2 proof input
151 publicInputsHash := c.GetPublicInputsHash(publicInputs)
152 proofChallenges := c.GetChallenges(proof, publicInputsHash, verifierData)
153
154 c.plonkChip.Verify(proofChallenges, proof.Openings, publicInputsHash)
155
156 initialMerkleCaps := []variables.FriMerkleCap{
157 verifierData.ConstantSigmasCap,
158 proof.WiresCap,
159 proof.PlonkZsPartialProductsCap,
160 proof.QuotientPolysCap,
161 }
162
163 c.friChip.VerifyFriProof(
164 c.friChip.GetInstance(proofChallenges.PlonkZeta),
165 c.friChip.ToOpenings(proof.Openings),
166 &proofChallenges.FriChallenges,
167 initialMerkleCaps,
168 &proof.OpeningProof,
169 )
170}