gnark-plonky2-verifier/verifier/deserialize.go
verifier/deserialize.goRaw
1package verifier
2
3import (
4 "encoding/json"
5 "io"
6 "math/big"
7 "os"
8
9 "github.com/consensys/gnark/frontend"
10 gl "github.com/succinctlabs/gnark-plonky2-verifier/goldilocks"
11 "github.com/succinctlabs/gnark-plonky2-verifier/plonk/gates"
12 "github.com/succinctlabs/gnark-plonky2-verifier/poseidon"
13 "github.com/succinctlabs/gnark-plonky2-verifier/variables"
14)
15
16type ProofWithPublicInputsRaw struct {
17 Proof struct {
18 WiresCap []string `json:"wires_cap"`
19 PlonkZsPartialProductsCap []string `json:"plonk_zs_partial_products_cap"`
20 QuotientPolysCap []string `json:"quotient_polys_cap"`
21 Openings struct {
22 Constants [][]uint64 `json:"constants"`
23 PlonkSigmas [][]uint64 `json:"plonk_sigmas"`
24 Wires [][]uint64 `json:"wires"`
25 PlonkZs [][]uint64 `json:"plonk_zs"`
26 PlonkZsNext [][]uint64 `json:"plonk_zs_next"`
27 PartialProducts [][]uint64 `json:"partial_products"`
28 QuotientPolys [][]uint64 `json:"quotient_polys"`
29 } `json:"openings"`
30 OpeningProof struct {
31 CommitPhaseMerkleCaps [][]string `json:"commit_phase_merkle_caps"`
32 QueryRoundProofs []struct {
33 InitialTreesProof struct {
34 EvalsProofs []EvalProofRaw `json:"evals_proofs"`
35 } `json:"initial_trees_proof"`
36 Steps []struct {
37 Evals [][]uint64 `json:"evals"`
38 MerkleProof struct {
39 Siblings []string `json:"siblings"`
40 } `json:"merkle_proof"`
41 } `json:"steps"`
42 } `json:"query_round_proofs"`
43 FinalPoly struct {
44 Coeffs [][]uint64 `json:"coeffs"`
45 } `json:"final_poly"`
46 PowWitness uint64 `json:"pow_witness"`
47 } `json:"opening_proof"`
48 } `json:"proof"`
49 PublicInputs []uint64 `json:"public_inputs"`
50}
51
52type EvalProofRaw struct {
53 LeafElements []uint64
54 MerkleProof MerkleProofRaw
55}
56
57func (e *EvalProofRaw) UnmarshalJSON(data []byte) error {
58 return json.Unmarshal(data, &[]interface{}{&e.LeafElements, &e.MerkleProof})
59}
60
61type MerkleProofRaw struct {
62 Hash []string
63}
64
65func (m *MerkleProofRaw) UnmarshalJSON(data []byte) error {
66 type SiblingObject struct {
67 Siblings []string // "siblings"
68 }
69
70 var siblings SiblingObject
71 if err := json.Unmarshal(data, &siblings); err != nil {
72 panic(err)
73 }
74
75 m.Hash = make([]string, len(siblings.Siblings))
76 copy(m.Hash[:], siblings.Siblings)
77
78 return nil
79}
80
81type CommonCircuitDataRaw struct {
82 Config struct {
83 NumWires uint64 `json:"num_wires"`
84 NumRoutedWires uint64 `json:"num_routed_wires"`
85 NumConstants uint64 `json:"num_constants"`
86 UseBaseArithmeticGate bool `json:"use_base_arithmetic_gate"`
87 SecurityBits uint64 `json:"security_bits"`
88 NumChallenges uint64 `json:"num_challenges"`
89 ZeroKnowledge bool `json:"zero_knowledge"`
90 MaxQuotientDegreeFactor uint64 `json:"max_quotient_degree_factor"`
91 FriConfig struct {
92 RateBits uint64 `json:"rate_bits"`
93 CapHeight uint64 `json:"cap_height"`
94 ProofOfWorkBits uint64 `json:"proof_of_work_bits"`
95 ReductionStrategy struct {
96 ConstantArityBits []uint64 `json:"ConstantArityBits"`
97 } `json:"reduction_strategy"`
98 NumQueryRounds uint64 `json:"num_query_rounds"`
99 } `json:"fri_config"`
100 } `json:"config"`
101 FriParams struct {
102 Config struct {
103 RateBits uint64 `json:"rate_bits"`
104 CapHeight uint64 `json:"cap_height"`
105 ProofOfWorkBits uint64 `json:"proof_of_work_bits"`
106 ReductionStrategy struct {
107 ConstantArityBits []uint64 `json:"ConstantArityBits"`
108 } `json:"reduction_strategy"`
109 NumQueryRounds uint64 `json:"num_query_rounds"`
110 } `json:"config"`
111 Hiding bool `json:"hiding"`
112 DegreeBits uint64 `json:"degree_bits"`
113 ReductionArityBits []uint64 `json:"reduction_arity_bits"`
114 } `json:"fri_params"`
115 Gates []string `json:"gates"`
116 SelectorsInfo struct {
117 SelectorIndices []uint64 `json:"selector_indices"`
118 Groups []struct {
119 Start uint64 `json:"start"`
120 End uint64 `json:"end"`
121 } `json:"groups"`
122 } `json:"selectors_info"`
123 QuotientDegreeFactor uint64 `json:"quotient_degree_factor"`
124 NumGateConstraints uint64 `json:"num_gate_constraints"`
125 NumConstants uint64 `json:"num_constants"`
126 NumPublicInputs uint64 `json:"num_public_inputs"`
127 KIs []uint64 `json:"k_is"`
128 NumPartialProducts uint64 `json:"num_partial_products"`
129}
130
131type ProofChallengesRaw struct {
132 PlonkBetas []uint64 `json:"plonk_betas"`
133 PlonkGammas []uint64 `json:"plonk_gammas"`
134 PlonkAlphas []uint64 `json:"plonk_alphas"`
135 PlonkZeta []uint64 `json:"plonk_zeta"`
136 FriChallenges struct {
137 FriAlpha []uint64 `json:"fri_alpha"`
138 FriBetas [][]uint64 `json:"fri_betas"`
139 FriPowResponse uint64 `json:"fri_pow_response"`
140 FriQueryIndices []uint64 `json:"fri_query_indices"`
141 } `json:"fri_challenges"`
142}
143
144type VerifierOnlyCircuitDataRaw struct {
145 ConstantsSigmasCap []string `json:"constants_sigmas_cap"`
146 CircuitDigest string `json:"circuit_digest"`
147}
148
149func DeserializeMerkleCap(merkleCapRaw []string) variables.FriMerkleCap {
150 n := len(merkleCapRaw)
151 merkleCap := make([]poseidon.BN254HashOut, n)
152 for i := 0; i < n; i++ {
153 capBigInt, _ := new(big.Int).SetString(merkleCapRaw[i], 10)
154 merkleCap[i] = frontend.Variable(capBigInt)
155 }
156 return merkleCap
157}
158
159func DeserializeMerkleProof(merkleProofRaw struct{ Siblings []interface{} }) variables.FriMerkleProof {
160 n := len(merkleProofRaw.Siblings)
161 var mp variables.FriMerkleProof
162 mp.Siblings = make([]poseidon.BN254HashOut, n)
163 for i := 0; i < n; i++ {
164 element := merkleProofRaw.Siblings[i].(struct{ Elements []uint64 })
165 mp.Siblings[i] = gl.Uint64ArrayToVariableArray(element.Elements)
166 }
167 return mp
168}
169
170func DeserializeOpeningSet(openingSetRaw struct {
171 Constants [][]uint64
172 PlonkSigmas [][]uint64
173 Wires [][]uint64
174 PlonkZs [][]uint64
175 PlonkZsNext [][]uint64
176 PartialProducts [][]uint64
177 QuotientPolys [][]uint64
178}) variables.OpeningSet {
179 return variables.OpeningSet{
180 Constants: gl.Uint64ArrayToQuadraticExtensionArray(openingSetRaw.Constants),
181 PlonkSigmas: gl.Uint64ArrayToQuadraticExtensionArray(openingSetRaw.PlonkSigmas),
182 Wires: gl.Uint64ArrayToQuadraticExtensionArray(openingSetRaw.Wires),
183 PlonkZs: gl.Uint64ArrayToQuadraticExtensionArray(openingSetRaw.PlonkZs),
184 PlonkZsNext: gl.Uint64ArrayToQuadraticExtensionArray(openingSetRaw.PlonkZsNext),
185 PartialProducts: gl.Uint64ArrayToQuadraticExtensionArray(openingSetRaw.PartialProducts),
186 QuotientPolys: gl.Uint64ArrayToQuadraticExtensionArray(openingSetRaw.QuotientPolys),
187 }
188}
189
190func StringArrayToHashBN254Array(rawHashes []string) []poseidon.BN254HashOut {
191 hashes := []poseidon.BN254HashOut{}
192
193 for i := 0; i < len(rawHashes); i++ {
194 hashBigInt, _ := new(big.Int).SetString(rawHashes[i], 10)
195 hashVar := frontend.Variable(hashBigInt)
196 hashes = append(hashes, poseidon.BN254HashOut(hashVar))
197 }
198
199 return hashes
200}
201
202func DeserializeFriProof(openingProofRaw struct {
203 CommitPhaseMerkleCaps [][]string
204 QueryRoundProofs []struct {
205 InitialTreesProof struct {
206 EvalsProofs []EvalProofRaw
207 }
208 Steps []struct {
209 Evals [][]uint64
210 MerkleProof struct {
211 Siblings []string
212 }
213 }
214 }
215 FinalPoly struct {
216 Coeffs [][]uint64
217 }
218 PowWitness uint64
219}) variables.FriProof {
220 var openingProof variables.FriProof
221 openingProof.PowWitness = gl.NewVariable(openingProofRaw.PowWitness)
222 openingProof.FinalPoly.Coeffs = gl.Uint64ArrayToQuadraticExtensionArray(openingProofRaw.FinalPoly.Coeffs)
223
224 openingProof.CommitPhaseMerkleCaps = make([]variables.FriMerkleCap, len(openingProofRaw.CommitPhaseMerkleCaps))
225 for i := 0; i < len(openingProofRaw.CommitPhaseMerkleCaps); i++ {
226 openingProof.CommitPhaseMerkleCaps[i] = StringArrayToHashBN254Array(openingProofRaw.CommitPhaseMerkleCaps[i])
227 }
228
229 numQueryRoundProofs := len(openingProofRaw.QueryRoundProofs)
230 openingProof.QueryRoundProofs = make([]variables.FriQueryRound, numQueryRoundProofs)
231
232 for i := 0; i < numQueryRoundProofs; i++ {
233 numEvalProofs := len(openingProofRaw.QueryRoundProofs[i].InitialTreesProof.EvalsProofs)
234 openingProof.QueryRoundProofs[i].InitialTreesProof.EvalsProofs = make([]variables.FriEvalProof, numEvalProofs)
235 for j := 0; j < numEvalProofs; j++ {
236 openingProof.QueryRoundProofs[i].InitialTreesProof.EvalsProofs[j].Elements = gl.Uint64ArrayToVariableArray(openingProofRaw.QueryRoundProofs[i].InitialTreesProof.EvalsProofs[j].LeafElements)
237 openingProof.QueryRoundProofs[i].InitialTreesProof.EvalsProofs[j].MerkleProof.Siblings = StringArrayToHashBN254Array(openingProofRaw.QueryRoundProofs[i].InitialTreesProof.EvalsProofs[j].MerkleProof.Hash)
238 }
239
240 numSteps := len(openingProofRaw.QueryRoundProofs[i].Steps)
241 openingProof.QueryRoundProofs[i].Steps = make([]variables.FriQueryStep, numSteps)
242 for j := 0; j < numSteps; j++ {
243 openingProof.QueryRoundProofs[i].Steps[j].Evals = gl.Uint64ArrayToQuadraticExtensionArray(openingProofRaw.QueryRoundProofs[i].Steps[j].Evals)
244 openingProof.QueryRoundProofs[i].Steps[j].MerkleProof.Siblings = StringArrayToHashBN254Array(openingProofRaw.QueryRoundProofs[i].Steps[j].MerkleProof.Siblings)
245 }
246 }
247
248 return openingProof
249}
250
251func DeserializeProofWithPublicInputs(path string) variables.ProofWithPublicInputs {
252 jsonFile, err := os.Open(path)
253 if err != nil {
254 panic(err)
255 }
256
257 defer jsonFile.Close()
258 rawBytes, _ := io.ReadAll(jsonFile)
259
260 var raw ProofWithPublicInputsRaw
261 err = json.Unmarshal(rawBytes, &raw)
262 if err != nil {
263 panic(err)
264 }
265
266 var proofWithPis variables.ProofWithPublicInputs
267 proofWithPis.Proof.WiresCap = DeserializeMerkleCap(raw.Proof.WiresCap)
268 proofWithPis.Proof.PlonkZsPartialProductsCap = DeserializeMerkleCap(raw.Proof.PlonkZsPartialProductsCap)
269 proofWithPis.Proof.QuotientPolysCap = DeserializeMerkleCap(raw.Proof.QuotientPolysCap)
270 proofWithPis.Proof.Openings = DeserializeOpeningSet(struct {
271 Constants [][]uint64
272 PlonkSigmas [][]uint64
273 Wires [][]uint64
274 PlonkZs [][]uint64
275 PlonkZsNext [][]uint64
276 PartialProducts [][]uint64
277 QuotientPolys [][]uint64
278 }(raw.Proof.Openings))
279 proofWithPis.Proof.OpeningProof = DeserializeFriProof(struct {
280 CommitPhaseMerkleCaps [][]string
281 QueryRoundProofs []struct {
282 InitialTreesProof struct {
283 EvalsProofs []EvalProofRaw
284 }
285 Steps []struct {
286 Evals [][]uint64
287 MerkleProof struct {
288 Siblings []string
289 }
290 }
291 }
292 FinalPoly struct{ Coeffs [][]uint64 }
293 PowWitness uint64
294 }(raw.Proof.OpeningProof))
295 proofWithPis.PublicInputs = gl.Uint64ArrayToVariableArray(raw.PublicInputs)
296
297 return proofWithPis
298}
299
300// TODO: this seemed unused?
301// func DeserializeProofChallenges(path string) variables.ProofChallenges {
302// jsonFile, err := os.Open(path)
303// if err != nil {
304// panic(err)
305// }
306
307// defer jsonFile.Close()
308// rawBytes, _ := io.ReadAll(jsonFile)
309
310// var raw ProofChallengesRaw
311// err = json.Unmarshal(rawBytes, &raw)
312// if err != nil {
313// panic(err)
314// }
315
316// var proofChallenges variables.ProofChallenges
317// proofChallenges.PlonkBetas = gl.Uint64ArrayToVariableArray(raw.PlonkBetas)
318// proofChallenges.PlonkGammas = gl.Uint64ArrayToVariableArray(raw.PlonkGammas)
319// proofChallenges.PlonkAlphas = gl.Uint64ArrayToVariableArray(raw.PlonkAlphas)
320// proofChallenges.PlonkZeta = gl.Uint64ArrayToQuadraticExtension(raw.PlonkZeta)
321// proofChallenges.FriChallenges.FriAlpha = gl.Uint64ArrayToQuadraticExtension(raw.FriChallenges.FriAlpha)
322// proofChallenges.FriChallenges.FriBetas = gl.Uint64ArrayToQuadraticExtensionArray(raw.FriChallenges.FriBetas)
323// proofChallenges.FriChallenges.FriPowResponse = gl.NewVariable(raw.FriChallenges.FriPowResponse)
324// proofChallenges.FriChallenges.FriQueryIndices = gl.Uint64ArrayToVariableArray(raw.FriChallenges.FriQueryIndices)
325
326// return proofChallenges
327// }
328
329func ReductionArityBits(
330 arityBits uint64,
331 finalPolyBits uint64,
332 degreeBits uint64,
333 rateBits uint64,
334 capHeight uint64,
335) []uint64 {
336 returnArr := make([]uint64, 0)
337
338 for degreeBits > finalPolyBits && degreeBits+rateBits-arityBits >= capHeight {
339 returnArr = append(returnArr, arityBits)
340 if degreeBits < arityBits {
341 panic("degreeBits < arityBits")
342 }
343 degreeBits -= arityBits
344 }
345
346 return returnArr
347}
348
349func DeserializeCommonCircuitData(path string) variables.CommonCircuitData {
350 jsonFile, err := os.Open(path)
351 if err != nil {
352 panic(err)
353 }
354
355 defer jsonFile.Close()
356 rawBytes, _ := io.ReadAll(jsonFile)
357
358 var raw CommonCircuitDataRaw
359 err = json.Unmarshal(rawBytes, &raw)
360 if err != nil {
361 panic(err)
362 }
363
364 var commonCircuitData variables.CommonCircuitData
365 commonCircuitData.Config.NumWires = raw.Config.NumWires
366 commonCircuitData.Config.NumRoutedWires = raw.Config.NumRoutedWires
367 commonCircuitData.Config.NumConstants = raw.Config.NumConstants
368 commonCircuitData.Config.UseBaseArithmeticGate = raw.Config.UseBaseArithmeticGate
369 commonCircuitData.Config.SecurityBits = raw.Config.SecurityBits
370 commonCircuitData.Config.NumChallenges = raw.Config.NumChallenges
371 commonCircuitData.Config.ZeroKnowledge = raw.Config.ZeroKnowledge
372 commonCircuitData.Config.MaxQuotientDegreeFactor = raw.Config.MaxQuotientDegreeFactor
373
374 commonCircuitData.Config.FriConfig.RateBits = raw.Config.FriConfig.RateBits
375 commonCircuitData.Config.FriConfig.CapHeight = raw.Config.FriConfig.CapHeight
376 commonCircuitData.Config.FriConfig.ProofOfWorkBits = raw.Config.FriConfig.ProofOfWorkBits
377 commonCircuitData.Config.FriConfig.NumQueryRounds = raw.Config.FriConfig.NumQueryRounds
378
379 commonCircuitData.FriParams.DegreeBits = raw.FriParams.DegreeBits
380 commonCircuitData.DegreeBits = raw.FriParams.DegreeBits
381 commonCircuitData.FriParams.Config.RateBits = raw.FriParams.Config.RateBits
382 commonCircuitData.FriParams.Config.CapHeight = raw.FriParams.Config.CapHeight
383 commonCircuitData.FriParams.Config.ProofOfWorkBits = raw.FriParams.Config.ProofOfWorkBits
384 commonCircuitData.FriParams.Config.NumQueryRounds = raw.FriParams.Config.NumQueryRounds
385 commonCircuitData.FriParams.ReductionArityBits = raw.FriParams.ReductionArityBits
386
387 commonCircuitData.Gates = []gates.Gate{}
388 for _, gate := range raw.Gates {
389 commonCircuitData.Gates = append(commonCircuitData.Gates, gates.GateInstanceFromId(gate))
390 }
391
392 selectorGroupStart := []uint64{}
393 selectorGroupEnd := []uint64{}
394 for _, group := range raw.SelectorsInfo.Groups {
395 selectorGroupStart = append(selectorGroupStart, group.Start)
396 selectorGroupEnd = append(selectorGroupEnd, group.End)
397 }
398
399 commonCircuitData.SelectorsInfo = *gates.NewSelectorsInfo(
400 raw.SelectorsInfo.SelectorIndices,
401 selectorGroupStart,
402 selectorGroupEnd,
403 )
404
405 commonCircuitData.QuotientDegreeFactor = raw.QuotientDegreeFactor
406 commonCircuitData.NumGateConstraints = raw.NumGateConstraints
407 commonCircuitData.NumConstants = raw.NumConstants
408 commonCircuitData.NumPublicInputs = raw.NumPublicInputs
409 commonCircuitData.KIs = gl.Uint64ArrayToVariableArray(raw.KIs)
410 commonCircuitData.NumPartialProducts = raw.NumPartialProducts
411
412 return commonCircuitData
413}
414
415func DeserializeVerifierOnlyCircuitData(path string) variables.VerifierOnlyCircuitData {
416 jsonFile, err := os.Open(path)
417 if err != nil {
418 panic(err)
419 }
420
421 defer jsonFile.Close()
422 rawBytes, _ := io.ReadAll(jsonFile)
423
424 var raw VerifierOnlyCircuitDataRaw
425 err = json.Unmarshal(rawBytes, &raw)
426 if err != nil {
427 panic(err)
428 }
429
430 var verifierOnlyCircuitData variables.VerifierOnlyCircuitData
431 verifierOnlyCircuitData.ConstantSigmasCap = DeserializeMerkleCap(raw.ConstantsSigmasCap)
432 circuitDigestBigInt, _ := new(big.Int).SetString(raw.CircuitDigest, 10)
433 circuitDigestVar := frontend.Variable(circuitDigestBigInt)
434 verifierOnlyCircuitData.CircuitDigest = poseidon.BN254HashOut(circuitDigestVar)
435 return verifierOnlyCircuitData
436}