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/field"
6 "github.com/succinctlabs/gnark-plonky2-verifier/poseidon"
7 "github.com/succinctlabs/gnark-plonky2-verifier/verifier/common"
8 "github.com/succinctlabs/gnark-plonky2-verifier/verifier/internal/fri"
9 "github.com/succinctlabs/gnark-plonky2-verifier/verifier/internal/plonk"
10)
11
12type VerifierChip struct {
13 api frontend.API `gnark:"-"`
14 fieldAPI field.FieldAPI `gnark:"-"`
15 qeAPI *field.QuadraticExtensionAPI `gnark:"-"`
16 poseidonChip *poseidon.PoseidonChip
17 poseidonBN128Chip *poseidon.PoseidonBN128Chip
18 plonkChip *plonk.PlonkChip
19 friChip *fri.FriChip
20}
21
22func NewVerifierChip(api frontend.API, commonCircuitData common.CommonCircuitData) *VerifierChip {
23
24 fieldAPI := field.NewFieldAPI(api)
25 qeAPI := field.NewQuadraticExtensionAPI(api, fieldAPI)
26 poseidonBN128Chip := poseidon.NewPoseidonBN128Chip(api, fieldAPI)
27
28 friChip := fri.NewFriChip(api, fieldAPI, qeAPI, poseidonBN128Chip, &commonCircuitData.FriParams)
29 plonkChip := plonk.NewPlonkChip(api, qeAPI, commonCircuitData)
30
31 // We are using goldilocks poseidon for the challenge computation
32 poseidonChip := poseidon.NewPoseidonChip(api, fieldAPI, qeAPI)
33
34 return &VerifierChip{
35 api: api,
36 fieldAPI: fieldAPI,
37 qeAPI: qeAPI,
38 poseidonChip: poseidonChip,
39 poseidonBN128Chip: poseidonBN128Chip,
40 plonkChip: plonkChip,
41 friChip: friChip,
42 }
43}
44
45func (c *VerifierChip) GetPublicInputsHash(publicInputs []field.F) poseidon.PoseidonHashOut {
46 return c.poseidonChip.HashNoPad(publicInputs)
47}
48
49func (c *VerifierChip) GetChallenges(
50 proof common.Proof,
51 publicInputsHash poseidon.PoseidonHashOut,
52 commonData common.CommonCircuitData,
53 verifierData common.VerifierOnlyCircuitData,
54) common.ProofChallenges {
55 config := commonData.Config
56 numChallenges := config.NumChallenges
57 challenger := plonk.NewChallengerChip(c.api, c.fieldAPI, c.poseidonChip, c.poseidonBN128Chip)
58
59 var circuitDigest = verifierData.CircuitDigest
60
61 challenger.ObserveBN128Hash(circuitDigest)
62 challenger.ObserveHash(publicInputsHash)
63 challenger.ObserveCap(proof.WiresCap)
64 plonkBetas := challenger.GetNChallenges(numChallenges)
65 plonkGammas := challenger.GetNChallenges(numChallenges)
66
67 challenger.ObserveCap(proof.PlonkZsPartialProductsCap)
68 plonkAlphas := challenger.GetNChallenges(numChallenges)
69
70 challenger.ObserveCap(proof.QuotientPolysCap)
71 plonkZeta := challenger.GetExtensionChallenge()
72
73 challenger.ObserveOpenings(fri.ToFriOpenings(proof.Openings))
74
75 return common.ProofChallenges{
76 PlonkBetas: plonkBetas,
77 PlonkGammas: plonkGammas,
78 PlonkAlphas: plonkAlphas,
79 PlonkZeta: plonkZeta,
80 FriChallenges: challenger.GetFriChallenges(
81 proof.OpeningProof.CommitPhaseMerkleCaps,
82 proof.OpeningProof.FinalPoly,
83 proof.OpeningProof.PowWitness,
84 commonData.DegreeBits,
85 config.FriConfig,
86 ),
87 }
88}
89
90/*
91func (c *VerifierChip) generateProofInput(commonData common.CommonCircuitData) common.ProofWithPublicInputs {
92 // Generate the parts of the witness that is for the plonky2 proof input
93
94 capHeight := commonData.Config.FriConfig.CapHeight
95
96 friCommitPhaseMerkleCaps := []common.MerkleCap{}
97 for i := 0; i < len(commonData.FriParams.ReductionArityBits); i++ {
98 friCommitPhaseMerkleCaps = append(friCommitPhaseMerkleCaps, common.NewMerkleCap(capHeight))
99 }
100
101 salt := commonData.SaltSize()
102 numLeavesPerOracle := []uint{
103 commonData.NumPreprocessedPolys(),
104 commonData.Config.NumWires + salt,
105 commonData.NumZsPartialProductsPolys() + salt,
106 commonData.NumQuotientPolys() + salt,
107 }
108 friQueryRoundProofs := []common.FriQueryRound{}
109 for i := uint64(0); i < commonData.FriParams.Config.NumQueryRounds; i++ {
110 evalProofs := []common.EvalProof{}
111 merkleProofLen := commonData.FriParams.LDEBits() - capHeight
112 for _, numLeaves := range numLeavesPerOracle {
113 leaves := make([]field.F, numLeaves)
114 merkleProof := common.NewMerkleProof(merkleProofLen)
115 evalProofs = append(evalProofs, common.NewEvalProof(leaves, merkleProof))
116 }
117
118 initialTreesProof := common.NewFriInitialTreeProof(evalProofs)
119 steps := []common.FriQueryStep{}
120 for _, arityBit := range commonData.FriParams.ReductionArityBits {
121 if merkleProofLen < arityBit {
122 panic("merkleProofLen < arityBits")
123 }
124
125 steps = append(steps, common.NewFriQueryStep(arityBit, merkleProofLen))
126 }
127
128 friQueryRoundProofs = append(friQueryRoundProofs, common.NewFriQueryRound(steps, initialTreesProof))
129 }
130
131 proofInput := common.ProofWithPublicInputs{
132 Proof: common.Proof{
133 WiresCap: common.NewMerkleCap(capHeight),
134 PlonkZsPartialProductsCap: common.NewMerkleCap(capHeight),
135 QuotientPolysCap: common.NewMerkleCap(capHeight),
136 Openings: common.NewOpeningSet(
137 commonData.Config.NumConstants,
138 commonData.Config.NumRoutedWires,
139 commonData.Config.NumWires,
140 commonData.Config.NumChallenges,
141 commonData.NumPartialProducts,
142 commonData.QuotientDegreeFactor,
143 ),
144 OpeningProof: common.FriProof{
145 CommitPhaseMerkleCaps: friCommitPhaseMerkleCaps,
146 QueryRoundProofs: friQueryRoundProofs,
147 FinalPoly: common.NewPolynomialCoeffs(commonData.FriParams.FinalPolyLen()),
148 },
149 },
150 PublicInputs: make([]field.F, commonData.NumPublicInputs),
151 }
152
153 return proofInput
154}
155*/
156
157func (c *VerifierChip) Verify(proof common.Proof, publicInputs []field.F, verifierData common.VerifierOnlyCircuitData, commonData common.CommonCircuitData) {
158 // TODO: Need to range check all the proof and public input elements to make sure they are within goldilocks field
159
160 // Generate the parts of the witness that is for the plonky2 proof input
161 publicInputsHash := c.GetPublicInputsHash(publicInputs)
162 proofChallenges := c.GetChallenges(proof, publicInputsHash, commonData, verifierData)
163
164 c.plonkChip.Verify(proofChallenges, proof.Openings, publicInputsHash)
165
166 initialMerkleCaps := []common.MerkleCap{
167 verifierData.ConstantSigmasCap,
168 proof.WiresCap,
169 proof.PlonkZsPartialProductsCap,
170 proof.QuotientPolysCap,
171 }
172
173 // Seems like there is a bug in the emulated field code.
174 // Add ZERO to all of the fri challenges values to reduce them.
175 proofChallenges.PlonkZeta[0] = c.fieldAPI.Add(proofChallenges.PlonkZeta[0], field.ZERO_F)
176 proofChallenges.PlonkZeta[1] = c.fieldAPI.Add(proofChallenges.PlonkZeta[1], field.ZERO_F)
177
178 proofChallenges.FriChallenges.FriAlpha[0] = c.fieldAPI.Add(proofChallenges.FriChallenges.FriAlpha[0], field.ZERO_F)
179 proofChallenges.FriChallenges.FriAlpha[1] = c.fieldAPI.Add(proofChallenges.FriChallenges.FriAlpha[1], field.ZERO_F)
180
181 for i := 0; i < len(proofChallenges.FriChallenges.FriBetas); i++ {
182 proofChallenges.FriChallenges.FriBetas[i][0] = c.fieldAPI.Add(proofChallenges.FriChallenges.FriBetas[i][0], field.ZERO_F)
183 proofChallenges.FriChallenges.FriBetas[i][1] = c.fieldAPI.Add(proofChallenges.FriChallenges.FriBetas[i][1], field.ZERO_F)
184 }
185
186 proofChallenges.FriChallenges.FriPowResponse = c.fieldAPI.Add(proofChallenges.FriChallenges.FriPowResponse, field.ZERO_F)
187
188 for i := 0; i < len(proofChallenges.FriChallenges.FriQueryIndices); i++ {
189 proofChallenges.FriChallenges.FriQueryIndices[i] = c.fieldAPI.Add(proofChallenges.FriChallenges.FriQueryIndices[i], field.ZERO_F)
190 }
191
192 c.friChip.VerifyFriProof(
193 fri.GetFriInstance(&commonData, c.qeAPI, proofChallenges.PlonkZeta, commonData.DegreeBits),
194 fri.ToFriOpenings(proof.Openings),
195 &proofChallenges.FriChallenges,
196 initialMerkleCaps,
197 &proof.OpeningProof,
198 )
199}