arnaucube
arnaucube/gnark-plonky2-verifierPublic Self-hosted repository
correctly deserialize fri opening proofs
Kevin Jue kjue235@gmail.com
Tue, 08 Nov 2022 14:52:22 -0800
commit

d6f73d101b2a8548d9dffad47b6686ef9db23759

parent

da80afaac465ef3fae149282d6b82a62b351f5ac

3 files changed, 87 insertions(+), 12 deletions(-)

jump to
M plonky2_verifier/deserialize.go → plonky2_verifier/deserialize.go

@@ -32,7 +32,7 @@ OpeningProof struct {

CommitPhaseMerkleCaps []interface{} `json:"commit_phase_merkle_caps"` QueryRoundProofs []struct { InitialTreesProof struct { - EvalsProofs [][]interface{} `json:"evals_proofs"` + EvalsProofs []EvalProofRaw `json:"evals_proofs"` } `json:"initial_trees_proof"` Steps []interface{} `json:"steps"` } `json:"query_round_proofs"`

@@ -43,6 +43,38 @@ PowWitness uint64 `json:"pow_witness"`

} `json:"opening_proof"` } `json:"proof"` PublicInputs []uint64 `json:"public_inputs"` +} + +type EvalProofRaw struct { + leafElements []uint64 + merkleProof MerkleProofRaw +} + +func (e *EvalProofRaw) UnmarshalJSON(data []byte) error { + return json.Unmarshal(data, &[]interface{}{&e.leafElements, &e.merkleProof}) +} + +type MerkleProofRaw struct { + hash [][]uint64 +} + +func (m *MerkleProofRaw) UnmarshalJSON(data []byte) error { + var siblingDict map[string]interface{} + if err := json.Unmarshal(data, &siblingDict); err != nil { + panic(err) + } + + siblings := siblingDict["siblings"].([]interface{}) + m.hash = make([][]uint64, len(siblings)) + for siblingIdx, sibling := range siblings { + siblingHash := sibling.(map[string]interface{})["elements"].([]interface{}) + m.hash[siblingIdx] = make([]uint64, 4) + for siblingElementIdx, siblingElement := range siblingHash { + m.hash[siblingIdx][siblingElementIdx] = uint64(siblingElement.(float64)) + } + } + + return nil } type CommonCircuitDataRaw struct {

@@ -113,6 +145,17 @@ }

return merkleCap } +func DeserializeMerkleProof(merkleProofRaw struct{ Siblings []interface{} }) MerkleProof { + n := len(merkleProofRaw.Siblings) + var mp MerkleProof + mp.Siblings = make([]Hash, n) + for i := 0; i < n; i++ { + element := merkleProofRaw.Siblings[i].(struct{ Elements []uint64 }) + copy(mp.Siblings[i][:], utils.Uint64ArrayToFArray(element.Elements)) + } + return mp +} + func DeserializeOpeningSet(openingSetRaw struct { Constants [][]uint64 PlonkSigmas [][]uint64

@@ -137,7 +180,7 @@ func DeserializeFriProof(openingProofRaw struct {

CommitPhaseMerkleCaps []interface{} QueryRoundProofs []struct { InitialTreesProof struct { - EvalsProofs [][]interface{} + EvalsProofs []EvalProofRaw } Steps []interface{} }

@@ -149,6 +192,19 @@ }) FriProof {

var openingProof FriProof openingProof.PowWitness = NewFieldElement(openingProofRaw.PowWitness) openingProof.FinalPoly.Coeffs = utils.Uint64ArrayToQuadraticExtensionArray(openingProofRaw.FinalPoly.Coeffs) + + numQueryRoundProofs := len(openingProofRaw.QueryRoundProofs) + openingProof.QueryRoundProofs = make([]FriQueryRound, numQueryRoundProofs) + + for i := 0; i < numQueryRoundProofs; i++ { + numEvalProofs := len(openingProofRaw.QueryRoundProofs[i].InitialTreesProof.EvalsProofs) + openingProof.QueryRoundProofs[i].InitialTreesProof.EvalsProofs = make([]EvalProof, numEvalProofs) + for j := 0; j < numEvalProofs; j++ { + openingProof.QueryRoundProofs[i].InitialTreesProof.EvalsProofs[j].Elements = utils.Uint64ArrayToFArray(openingProofRaw.QueryRoundProofs[i].InitialTreesProof.EvalsProofs[j].leafElements) + openingProof.QueryRoundProofs[i].InitialTreesProof.EvalsProofs[j].MerkleProof.Siblings = utils.Uint64ArrayToHashArray(openingProofRaw.QueryRoundProofs[i].InitialTreesProof.EvalsProofs[j].merkleProof.hash) + } + } + return openingProof }

@@ -183,8 +239,10 @@ }(raw.Proof.Openings))

proofWithPis.Proof.OpeningProof = DeserializeFriProof(struct { CommitPhaseMerkleCaps []interface{} QueryRoundProofs []struct { - InitialTreesProof struct{ EvalsProofs [][]interface{} } - Steps []interface{} + InitialTreesProof struct { + EvalsProofs []EvalProofRaw + } + Steps []interface{} } FinalPoly struct{ Coeffs [][]uint64 } PowWitness uint64

@@ -224,7 +282,8 @@ commonCircuitData.Config.FriConfig.CapHeight = raw.Config.FriConfig.CapHeight

commonCircuitData.Config.FriConfig.ProofOfWorkBits = raw.Config.FriConfig.ProofOfWorkBits commonCircuitData.Config.FriConfig.NumQueryRounds = raw.Config.FriConfig.NumQueryRounds - commonCircuitData.FriParams.Config.CapHeight = raw.FriParams.Config.CapHeight + commonCircuitData.FriParams.DegreeBits = raw.FriParams.DegreeBits + commonCircuitData.FriParams.Config.RateBits = raw.FriParams.Config.RateBits commonCircuitData.FriParams.Config.CapHeight = raw.FriParams.Config.CapHeight commonCircuitData.FriParams.Config.ProofOfWorkBits = raw.FriParams.Config.ProofOfWorkBits commonCircuitData.FriParams.Config.NumQueryRounds = raw.FriParams.Config.NumQueryRounds
M plonky2_verifier/fri.go → plonky2_verifier/fri.go

@@ -1,6 +1,7 @@

package plonky2_verifier import ( + "fmt" "gnark-ed25519/field" . "gnark-ed25519/field" "gnark-ed25519/poseidon"

@@ -155,7 +156,9 @@ func (f *FriChip) assertNoncanonicalIndicesOK() {

numAmbiguousElems := uint64(math.MaxUint64) - EmulatedFieldModulus().Uint64() + 1 queryError := f.friParams.Config.rate() pAmbiguous := float64(numAmbiguousElems) / float64(EmulatedFieldModulus().Uint64()) - if pAmbiguous < queryError*1e-5 { + + // TODO: Check that pAmbiguous value is the same as the one in plonky2 verifier + if pAmbiguous >= queryError*1e-5 { panic("A non-negligible portion of field elements are in the range that permits non-canonical encodings. Need to do more analysis or enforce canonical encodings.") } }

@@ -167,12 +170,11 @@ initialMerkleCaps []MerkleCap,

proof *FriProof, xIndex F, n uint64, + nLog uint64, roundProof *FriQueryRound, ) { - nLog := log2Strict(uint(n)) - f.assertNoncanonicalIndicesOK() - xIndexBits := f.qe.field.ToBinary(xIndex, nLog) + xIndexBits := f.qe.field.ToBinary(xIndex, int(nLog)) capIndex := f.qe.field.FromBinary(xIndexBits[len(xIndexBits)-int(f.friParams.Config.CapHeight):]...).(F) f.verifyInitialProof(xIndexBits, &roundProof.InitialTreesProof, initialMerkleCaps, capIndex)

@@ -201,10 +203,15 @@

precomputedReducedEvals := f.fromOpeningsAndAlpha(&openings, friChallenges.FriAlpha) // Size of the LDE domain. - n := uint64(math.Pow(2, float64(f.friParams.DegreeBits+f.friParams.Config.RateBits))) + nLog := f.friParams.DegreeBits + f.friParams.Config.RateBits + n := uint64(math.Pow(2, float64(nLog))) - if len(friChallenges.FriQueryIndicies) != len(precomputedReducedEvals) { - panic("Number of queryRoundProofs should equal number of precomputedReducedEvals") + if len(friChallenges.FriQueryIndicies) != len(friProof.QueryRoundProofs) { + panic(fmt.Sprintf( + "Number of query indices (%d) should equal number of query round proofs (%d)", + len(friChallenges.FriQueryIndicies), + len(friProof.QueryRoundProofs), + )) } for idx, xIndex := range friChallenges.FriQueryIndicies {

@@ -217,6 +224,7 @@ initialMerkleCaps,

friProof, xIndex, n, + nLog, &roundProof, ) }
M utils/utils.go → utils/utils.go

@@ -40,3 +40,11 @@ output = append(output, [2]F{NewFieldElement(input[i][0]), NewFieldElement(input[i][1])})

} return output } + +func Uint64ArrayToHashArray(input [][]uint64) []Hash { + var output []Hash + for i := 0; i < len(input); i++ { + output = append(output, [4]F{NewFieldElement(input[i][0]), NewFieldElement(input[i][1]), NewFieldElement(input[i][2]), NewFieldElement(input[i][3])}) + } + return output +}