Browse Source

correctly deserialize fri opening proofs

main
Kevin Jue 2 years ago
parent
commit
d6f73d101b
3 changed files with 88 additions and 13 deletions
  1. +64
    -5
      plonky2_verifier/deserialize.go
  2. +16
    -8
      plonky2_verifier/fri.go
  3. +8
    -0
      utils/utils.go

+ 64
- 5
plonky2_verifier/deserialize.go

@ -32,7 +32,7 @@ type ProofWithPublicInputsRaw 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"`
@ -45,6 +45,38 @@ type ProofWithPublicInputsRaw struct {
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 {
Config struct {
NumWires uint64 `json:"num_wires"`
@ -113,6 +145,17 @@ func DeserializeMerkleCap(merkleCapRaw []struct{ Elements []uint64 }) 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 {
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 @@ func DeserializeFriProof(openingProofRaw struct {
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 @@ func DeserializeProofWithPublicInputs(path string) ProofWithPublicInputs {
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 @@ func DeserializeCommonCircuitData(path string) CommonCircuitData {
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

+ 16
- 8
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 @@ func (f *FriChip) verifyQueryRound(
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 @@ func (f *FriChip) VerifyFriProof(
precomputedReducedEvals := f.fromOpeningsAndAlpha(&openings, friChallenges.FriAlpha)
// Size of the LDE domain.
n := uint64(math.Pow(2, float64(f.friParams.DegreeBits+f.friParams.Config.RateBits)))
if len(friChallenges.FriQueryIndicies) != len(precomputedReducedEvals) {
panic("Number of queryRoundProofs should equal number of precomputedReducedEvals")
nLog := f.friParams.DegreeBits + f.friParams.Config.RateBits
n := uint64(math.Pow(2, float64(nLog)))
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 @@ func (f *FriChip) VerifyFriProof(
friProof,
xIndex,
n,
nLog,
&roundProof,
)
}

+ 8
- 0
utils/utils.go

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

Loading…
Cancel
Save