correctly deserialize fri opening proofs

This commit is contained in:
Kevin Jue
2022-11-08 14:52:22 -08:00
parent da80afaac4
commit d6f73d101b
3 changed files with 87 additions and 12 deletions

View File

@@ -32,7 +32,7 @@ type ProofWithPublicInputsRaw struct {
CommitPhaseMerkleCaps []interface{} `json:"commit_phase_merkle_caps"` CommitPhaseMerkleCaps []interface{} `json:"commit_phase_merkle_caps"`
QueryRoundProofs []struct { QueryRoundProofs []struct {
InitialTreesProof struct { InitialTreesProof struct {
EvalsProofs [][]interface{} `json:"evals_proofs"` EvalsProofs []EvalProofRaw `json:"evals_proofs"`
} `json:"initial_trees_proof"` } `json:"initial_trees_proof"`
Steps []interface{} `json:"steps"` Steps []interface{} `json:"steps"`
} `json:"query_round_proofs"` } `json:"query_round_proofs"`
@@ -45,6 +45,38 @@ type ProofWithPublicInputsRaw struct {
PublicInputs []uint64 `json:"public_inputs"` 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 { type CommonCircuitDataRaw struct {
Config struct { Config struct {
NumWires uint64 `json:"num_wires"` NumWires uint64 `json:"num_wires"`
@@ -113,6 +145,17 @@ func DeserializeMerkleCap(merkleCapRaw []struct{ Elements []uint64 }) MerkleCap
return merkleCap 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 { func DeserializeOpeningSet(openingSetRaw struct {
Constants [][]uint64 Constants [][]uint64
PlonkSigmas [][]uint64 PlonkSigmas [][]uint64
@@ -137,7 +180,7 @@ func DeserializeFriProof(openingProofRaw struct {
CommitPhaseMerkleCaps []interface{} CommitPhaseMerkleCaps []interface{}
QueryRoundProofs []struct { QueryRoundProofs []struct {
InitialTreesProof struct { InitialTreesProof struct {
EvalsProofs [][]interface{} EvalsProofs []EvalProofRaw
} }
Steps []interface{} Steps []interface{}
} }
@@ -149,6 +192,19 @@ func DeserializeFriProof(openingProofRaw struct {
var openingProof FriProof var openingProof FriProof
openingProof.PowWitness = NewFieldElement(openingProofRaw.PowWitness) openingProof.PowWitness = NewFieldElement(openingProofRaw.PowWitness)
openingProof.FinalPoly.Coeffs = utils.Uint64ArrayToQuadraticExtensionArray(openingProofRaw.FinalPoly.Coeffs) 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 return openingProof
} }
@@ -183,7 +239,9 @@ func DeserializeProofWithPublicInputs(path string) ProofWithPublicInputs {
proofWithPis.Proof.OpeningProof = DeserializeFriProof(struct { proofWithPis.Proof.OpeningProof = DeserializeFriProof(struct {
CommitPhaseMerkleCaps []interface{} CommitPhaseMerkleCaps []interface{}
QueryRoundProofs []struct { QueryRoundProofs []struct {
InitialTreesProof struct{ EvalsProofs [][]interface{} } InitialTreesProof struct {
EvalsProofs []EvalProofRaw
}
Steps []interface{} Steps []interface{}
} }
FinalPoly struct{ Coeffs [][]uint64 } FinalPoly struct{ Coeffs [][]uint64 }
@@ -224,7 +282,8 @@ func DeserializeCommonCircuitData(path string) CommonCircuitData {
commonCircuitData.Config.FriConfig.ProofOfWorkBits = raw.Config.FriConfig.ProofOfWorkBits commonCircuitData.Config.FriConfig.ProofOfWorkBits = raw.Config.FriConfig.ProofOfWorkBits
commonCircuitData.Config.FriConfig.NumQueryRounds = raw.Config.FriConfig.NumQueryRounds 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.CapHeight = raw.FriParams.Config.CapHeight
commonCircuitData.FriParams.Config.ProofOfWorkBits = raw.FriParams.Config.ProofOfWorkBits commonCircuitData.FriParams.Config.ProofOfWorkBits = raw.FriParams.Config.ProofOfWorkBits
commonCircuitData.FriParams.Config.NumQueryRounds = raw.FriParams.Config.NumQueryRounds commonCircuitData.FriParams.Config.NumQueryRounds = raw.FriParams.Config.NumQueryRounds

View File

@@ -1,6 +1,7 @@
package plonky2_verifier package plonky2_verifier
import ( import (
"fmt"
"gnark-ed25519/field" "gnark-ed25519/field"
. "gnark-ed25519/field" . "gnark-ed25519/field"
"gnark-ed25519/poseidon" "gnark-ed25519/poseidon"
@@ -155,7 +156,9 @@ func (f *FriChip) assertNoncanonicalIndicesOK() {
numAmbiguousElems := uint64(math.MaxUint64) - EmulatedFieldModulus().Uint64() + 1 numAmbiguousElems := uint64(math.MaxUint64) - EmulatedFieldModulus().Uint64() + 1
queryError := f.friParams.Config.rate() queryError := f.friParams.Config.rate()
pAmbiguous := float64(numAmbiguousElems) / float64(EmulatedFieldModulus().Uint64()) 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.") 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 @@ func (f *FriChip) verifyQueryRound(
proof *FriProof, proof *FriProof,
xIndex F, xIndex F,
n uint64, n uint64,
nLog uint64,
roundProof *FriQueryRound, roundProof *FriQueryRound,
) { ) {
nLog := log2Strict(uint(n))
f.assertNoncanonicalIndicesOK() 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) capIndex := f.qe.field.FromBinary(xIndexBits[len(xIndexBits)-int(f.friParams.Config.CapHeight):]...).(F)
f.verifyInitialProof(xIndexBits, &roundProof.InitialTreesProof, initialMerkleCaps, capIndex) f.verifyInitialProof(xIndexBits, &roundProof.InitialTreesProof, initialMerkleCaps, capIndex)
@@ -201,10 +203,15 @@ func (f *FriChip) VerifyFriProof(
precomputedReducedEvals := f.fromOpeningsAndAlpha(&openings, friChallenges.FriAlpha) precomputedReducedEvals := f.fromOpeningsAndAlpha(&openings, friChallenges.FriAlpha)
// Size of the LDE domain. // 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) { if len(friChallenges.FriQueryIndicies) != len(friProof.QueryRoundProofs) {
panic("Number of queryRoundProofs should equal number of precomputedReducedEvals") 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 { for idx, xIndex := range friChallenges.FriQueryIndicies {
@@ -217,6 +224,7 @@ func (f *FriChip) VerifyFriProof(
friProof, friProof,
xIndex, xIndex,
n, n,
nLog,
&roundProof, &roundProof,
) )
} }

View File

@@ -40,3 +40,11 @@ func Uint64ArrayToQuadraticExtensionArray(input [][]uint64) []QuadraticExtension
} }
return output 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
}