Browse Source

All tests pass

main
Uma Roy 2 years ago
parent
commit
3aef7954ed
32 changed files with 839 additions and 946 deletions
  1. +1
    -0
      .gitignore
  2. +2
    -2
      README.md
  3. +154
    -61
      benchmark.go
  4. +0
    -187
      benchmark_plonk.go
  5. +38
    -0
      fri/fri.go
  6. +25
    -17
      fri/fri_test.go
  7. +13
    -67
      fri/fri_utils.go
  8. +21
    -0
      fri/vars.go
  9. +2
    -2
      plonk/gates/gates_test.go
  10. +15
    -4
      plonk/plonk.go
  11. +25
    -11
      plonk/plonk_test.go
  12. +0
    -0
      testdata/.DS_Store
  13. +0
    -0
      testdata/decode_block/common_circuit_data.json
  14. +0
    -0
      testdata/decode_block/proof_with_public_inputs.json
  15. +0
    -0
      testdata/decode_block/verifier_only_circuit_data.json
  16. +0
    -0
      testdata/step/common_circuit_data.json
  17. +0
    -0
      testdata/step/proof_with_public_inputs.json
  18. +0
    -0
      testdata/step/verifier_only_circuit_data.json
  19. +122
    -0
      types/common_data.go
  20. +9
    -0
      types/common_data_test.go
  21. +126
    -0
      types/deserialize.go
  22. +13
    -0
      types/deserialize_test.go
  23. +28
    -0
      types/types.go
  24. +21
    -0
      types/utils.go
  25. +0
    -28
      variables/circuit.go
  26. +156
    -0
      variables/deserialize.go
  27. +17
    -0
      variables/deserialize_test.go
  28. +0
    -436
      verifier/deserialize.go
  29. +0
    -24
      verifier/deserialize_test.go
  30. +24
    -0
      verifier/util.go
  31. +11
    -10
      verifier/verifier.go
  32. +16
    -97
      verifier/verifier_test.go

+ 1
- 0
.gitignore

@ -15,3 +15,4 @@
# vendor/
gnark-ed25519
gnark.pprof

+ 2
- 2
README.md

@ -1,6 +1,6 @@
# gnark-plonky2-verifier
# Gnark Plonky2 Verifier
This is an in-progress implementation of a [Plonky2](https://github.com/mir-protocol/plonky2) verifier in Gnark (supports Groth16 and PLONK). It currently is able to verify some dummy circuits, but not much more as many of the custom gates used in Plonky2 are currently not implemented.
This is an implementation of a [Plonky2](https://github.com/mir-protocol/plonky2) verifier in Gnark (supports Groth16 and PLONK).
Besides the verifier, there are some Gnark implementation of circuits in this repo that may be useful for other projects:

+ 154
- 61
benchmark.go

@ -8,51 +8,50 @@ import (
"os"
"time"
gl "github.com/succinctlabs/gnark-plonky2-verifier/goldilocks"
"github.com/succinctlabs/gnark-plonky2-verifier/types"
"github.com/succinctlabs/gnark-plonky2-verifier/variables"
"github.com/succinctlabs/gnark-plonky2-verifier/verifier"
"github.com/consensys/gnark-crypto/ecc"
"github.com/consensys/gnark/backend/groth16"
"github.com/consensys/gnark/backend/plonk"
"github.com/consensys/gnark/constraint"
"github.com/consensys/gnark/frontend"
"github.com/consensys/gnark/frontend/cs/r1cs"
"github.com/consensys/gnark/frontend/cs/scs"
"github.com/consensys/gnark/profile"
"github.com/consensys/gnark/test"
)
type BenchmarkPlonky2VerifierCircuit struct {
Proof variables.Proof
PublicInputs []gl.Variable `gnark:",public"`
func runBenchmark(plonky2Circuit string, proofSystem string, profileCircuit bool, dummy bool, saveArtifacts bool) {
commonCircuitData := types.DeserializeCommonCircuitData("testdata/" + plonky2Circuit + "/common_circuit_data.json")
verifierChip *verifier.VerifierChip `gnark:"-"`
plonky2CircuitName string `gnark:"-"`
}
func (circuit *BenchmarkPlonky2VerifierCircuit) Define(api frontend.API) error {
circuitDirname := "./verifier/data/" + circuit.plonky2CircuitName + "/"
commonCircuitData := verifier.DeserializeCommonCircuitData(circuitDirname + "common_circuit_data.json")
verifierOnlyCircuitData := verifier.DeserializeVerifierOnlyCircuitData(circuitDirname + "verifier_only_circuit_data.json")
circuit.verifierChip = verifier.NewVerifierChip(api, commonCircuitData)
circuit.verifierChip.Verify(circuit.Proof, circuit.PublicInputs, verifierOnlyCircuitData, commonCircuitData)
return nil
}
proofWithPis := variables.DeserializeProofWithPublicInputs(types.ReadProofWithPublicInputs("testdata/" + plonky2Circuit + "/proof_with_public_inputs.json"))
verifierOnlyCircuitData := variables.DeserializeVerifierOnlyCircuitData(types.ReadVerifierOnlyCircuitData("testdata/" + plonky2Circuit + "/verifier_only_circuit_data.json"))
func compileCircuit(plonky2Circuit string, profileCircuit bool, serialize bool, outputSolidity bool, dummy bool) (constraint.ConstraintSystem, groth16.ProvingKey, groth16.VerifyingKey) {
circuit := BenchmarkPlonky2VerifierCircuit{
plonky2CircuitName: plonky2Circuit,
circuit := verifier.ExampleVerifierCircuit{
Proof: proofWithPis.Proof,
PublicInputs: proofWithPis.PublicInputs,
VerifierOnlyCircuitData: verifierOnlyCircuitData,
CommonCircuitData: commonCircuitData,
}
proofWithPis := verifier.DeserializeProofWithPublicInputs("./verifier/data/" + plonky2Circuit + "/proof_with_public_inputs.json")
circuit.Proof = proofWithPis.Proof
circuit.PublicInputs = proofWithPis.PublicInputs
var p *profile.Profile
if profileCircuit {
p = profile.Start()
}
r1cs, err := frontend.Compile(ecc.BN254.ScalarField(), r1cs.NewBuilder, &circuit)
var builder frontend.NewBuilder
if proofSystem == "plonk" {
builder = scs.NewBuilder
} else if proofSystem == "groth16" {
builder = r1cs.NewBuilder
} else {
fmt.Println("Please provide a valid proof system to benchmark, we only support plonk and groth16")
os.Exit(1)
}
r1cs, err := frontend.Compile(ecc.BN254.ScalarField(), builder, &circuit)
if err != nil {
fmt.Println("error in building circuit", err)
os.Exit(1)
@ -68,16 +67,116 @@ func compileCircuit(plonky2Circuit string, profileCircuit bool, serialize bool,
println("r1cs.GetNbInternalVariables(): ", r1cs.GetNbInternalVariables())
}
witness := verifier.ExampleVerifierCircuit{
Proof: proofWithPis.Proof,
PublicInputs: proofWithPis.PublicInputs,
VerifierOnlyCircuitData: verifierOnlyCircuitData,
CommonCircuitData: commonCircuitData,
}
if proofSystem == "plonk" {
plonkProof(r1cs, witness, dummy, saveArtifacts)
} else if proofSystem == "groth16" {
groth16Proof(r1cs, witness, dummy, saveArtifacts)
} else {
panic("Please provide a valid proof system to benchmark, we only support plonk and groth16")
}
}
func plonkProof(r1cs constraint.ConstraintSystem, assignment verifier.ExampleVerifierCircuit, dummy bool, saveArtifacts bool) {
var pk plonk.ProvingKey
var vk plonk.VerifyingKey
var err error
// Don't serialize the circuit for now, since it takes up too much memory
/*
if serialize {
fR1CS, _ := os.Create("circuit")
r1cs.WriteTo(fR1CS)
fR1CS.Close()
// if saveArtifacts {
// fR1CS, _ := os.Create("circuit")
// r1cs.WriteTo(fR1CS)
// fR1CS.Close()
// }
fmt.Println("Running circuit setup", time.Now())
if dummy {
panic("dummy setup not supported for plonk")
} else {
fmt.Println("Using real setup")
srs, err := test.NewKZGSRS(r1cs)
if err != nil {
panic(err)
}
*/
pk, vk, err = plonk.Setup(r1cs, srs)
}
if err != nil {
fmt.Println(err)
os.Exit(1)
}
if saveArtifacts {
fPK, _ := os.Create("proving.key")
pk.WriteTo(fPK)
fPK.Close()
if vk != nil {
fVK, _ := os.Create("verifying.key")
vk.WriteTo(fVK)
fVK.Close()
}
fSolidity, _ := os.Create("proof.sol")
err = vk.ExportSolidity(fSolidity)
}
fmt.Println("Generating witness", time.Now())
witness, _ := frontend.NewWitness(&assignment, ecc.BN254.ScalarField())
publicWitness, _ := witness.Public()
if saveArtifacts {
fWitness, _ := os.Create("witness")
witness.WriteTo(fWitness)
fWitness.Close()
}
fmt.Println("Creating proof", time.Now())
proof, err := plonk.Prove(r1cs, pk, witness)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
if saveArtifacts {
fProof, _ := os.Create("proof.proof")
proof.WriteTo(fProof)
fProof.Close()
}
if vk == nil {
fmt.Println("vk is nil, means you're using dummy setup and we skip verification of proof")
return
}
fmt.Println("Verifying proof", time.Now())
err = plonk.Verify(proof, vk, publicWitness)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
const fpSize = 4 * 8
var buf bytes.Buffer
proof.WriteRawTo(&buf)
proofBytes := buf.Bytes()
fmt.Printf("proofBytes: %v\n", proofBytes)
}
func groth16Proof(r1cs constraint.ConstraintSystem, assignment verifier.ExampleVerifierCircuit, dummy bool, saveArtifacts bool) {
var pk groth16.ProvingKey
var vk groth16.VerifyingKey
var err error
// Don't serialize the circuit for now, since it takes up too much memory
// if saveArtifacts {
// fR1CS, _ := os.Create("circuit")
// r1cs.WriteTo(fR1CS)
// fR1CS.Close()
// }
fmt.Println("Running circuit setup", time.Now())
if dummy {
@ -92,37 +191,25 @@ func compileCircuit(plonky2Circuit string, profileCircuit bool, serialize bool,
os.Exit(1)
}
if serialize {
if saveArtifacts {
fPK, _ := os.Create("proving.key")
pk.WriteTo(fPK)
fPK.Close()
fVK, _ := os.Create("verifying.key")
vk.WriteTo(fVK)
fVK.Close()
}
if vk != nil {
fVK, _ := os.Create("verifying.key")
vk.WriteTo(fVK)
fVK.Close()
}
if outputSolidity {
fSolidity, _ := os.Create("proof.sol")
err = vk.ExportSolidity(fSolidity)
}
return r1cs, pk, vk
}
func createProof(plonky2Circuit string, r1cs constraint.ConstraintSystem, pk groth16.ProvingKey, vk groth16.VerifyingKey, serialize bool) groth16.Proof {
proofWithPis := verifier.DeserializeProofWithPublicInputs("./verifier/data/" + plonky2Circuit + "/proof_with_public_inputs.json")
// Witness
assignment := &BenchmarkPlonky2VerifierCircuit{
Proof: proofWithPis.Proof,
PublicInputs: proofWithPis.PublicInputs,
}
fmt.Println("Generating witness", time.Now())
witness, _ := frontend.NewWitness(assignment, ecc.BN254.ScalarField())
witness, _ := frontend.NewWitness(&assignment, ecc.BN254.ScalarField())
publicWitness, _ := witness.Public()
if serialize {
if saveArtifacts {
fWitness, _ := os.Create("witness")
witness.WriteTo(fWitness)
fWitness.Close()
@ -134,15 +221,15 @@ func createProof(plonky2Circuit string, r1cs constraint.ConstraintSystem, pk gro
fmt.Println(err)
os.Exit(1)
}
if serialize {
if saveArtifacts {
fProof, _ := os.Create("proof.proof")
proof.WriteTo(fProof)
fProof.Close()
}
if vk == nil {
fmt.Println("vk is nil, means you're using dummy setup and we skip verification step")
return proof
fmt.Println("vk is nil, means you're using dummy setup and we skip verification of proof")
return
}
fmt.Println("Verifying proof", time.Now())
@ -184,14 +271,14 @@ func createProof(plonky2Circuit string, r1cs constraint.ConstraintSystem, pk gro
println("c[0] is ", c[0].String())
println("c[1] is ", c[1].String())
return proof
}
func main() {
plonky2Circuit := flag.String("plonky2-circuit", "", "plonky2 circuit to benchmark")
profileCircuit := flag.Bool("profile", false, "profile the circuit")
serialize := flag.Bool("serialize", false, "serialize the circuit")
outputSolidity := flag.Bool("solidity", false, "output solidity code for the circuit")
proofSystem := flag.String("proof-system", "groth16", "proof system to benchmark")
profileCircuit := flag.Bool("profile", true, "profile the circuit")
dummySetup := flag.Bool("dummy", true, "use dummy setup")
saveArtifacts := flag.Bool("save", false, "save circuit artifacts")
flag.Parse()
@ -200,6 +287,12 @@ func main() {
os.Exit(1)
}
r1cs, pk, vk := compileCircuit(*plonky2Circuit, *profileCircuit, *serialize, *outputSolidity, true)
createProof(*plonky2Circuit, r1cs, pk, vk, *serialize)
if *proofSystem == "plonk" {
*dummySetup = false
}
fmt.Printf("Running benchmark for %s circuit with proof system %s\n", *plonky2Circuit, *proofSystem)
fmt.Printf("Profiling: %t, DummySetup: %t, SaveArtifacts: %t\n", *profileCircuit, *dummySetup, *saveArtifacts)
runBenchmark(*plonky2Circuit, *proofSystem, *profileCircuit, *dummySetup, *saveArtifacts)
}

+ 0
- 187
benchmark_plonk.go

@ -1,187 +0,0 @@
package main
import (
"bytes"
"flag"
"fmt"
"math/big"
"os"
"time"
gl "github.com/succinctlabs/gnark-plonky2-verifier/goldilocks"
"github.com/succinctlabs/gnark-plonky2-verifier/variables"
"github.com/succinctlabs/gnark-plonky2-verifier/verifier"
"github.com/consensys/gnark-crypto/ecc"
"github.com/consensys/gnark/backend/plonk"
"github.com/consensys/gnark/constraint"
"github.com/consensys/gnark/frontend"
"github.com/consensys/gnark/frontend/cs/scs"
"github.com/consensys/gnark/profile"
"github.com/consensys/gnark/test"
)
type BenchmarkPlonky2VerifierCircuitPlonk struct {
Proof variables.Proof
PublicInputs []gl.Variable `gnark:",public"`
verifierChip *verifier.VerifierChip `gnark:"-"`
plonky2CircuitName string `gnark:"-"`
}
func (circuit *BenchmarkPlonky2VerifierCircuitPlonk) Define(api frontend.API) error {
circuitDirname := "./verifier/data/" + circuit.plonky2CircuitName + "/"
commonCircuitData := verifier.DeserializeCommonCircuitData(circuitDirname + "common_circuit_data.json")
verifierOnlyCircuitData := verifier.DeserializeVerifierOnlyCircuitData(circuitDirname + "verifier_only_circuit_data.json")
circuit.verifierChip = verifier.NewVerifierChip(api, commonCircuitData)
circuit.verifierChip.Verify(circuit.Proof, circuit.PublicInputs, verifierOnlyCircuitData, commonCircuitData)
return nil
}
func compileCircuitPlonk(plonky2Circuit string, profileCircuit bool, serialize bool, outputSolidity bool) (constraint.ConstraintSystem, plonk.ProvingKey, plonk.VerifyingKey) {
circuit := BenchmarkPlonky2VerifierCircuitPlonk{
plonky2CircuitName: plonky2Circuit,
}
proofWithPis := verifier.DeserializeProofWithPublicInputs("./verifier/data/" + plonky2Circuit + "/proof_with_public_inputs.json")
circuit.Proof = proofWithPis.Proof
circuit.PublicInputs = proofWithPis.PublicInputs
var p *profile.Profile
if profileCircuit {
p = profile.Start()
}
r1cs, err := frontend.Compile(ecc.BN254.ScalarField(), scs.NewBuilder, &circuit)
if err != nil {
fmt.Println("error in building circuit", err)
os.Exit(1)
}
if profileCircuit {
p.Stop()
p.Top()
println("r1cs.GetNbCoefficients(): ", r1cs.GetNbCoefficients())
println("r1cs.GetNbConstraints(): ", r1cs.GetNbConstraints())
println("r1cs.GetNbSecretVariables(): ", r1cs.GetNbSecretVariables())
println("r1cs.GetNbPublicVariables(): ", r1cs.GetNbPublicVariables())
println("r1cs.GetNbInternalVariables(): ", r1cs.GetNbInternalVariables())
}
// Don't serialize the circuit for now, since it takes up too much memory
/*
if serialize {
fR1CS, _ := os.Create("circuit")
r1cs.WriteTo(fR1CS)
fR1CS.Close()
}
*/
srs, err := test.NewKZGSRS(r1cs)
if err != nil {
panic(err)
}
fmt.Println("Running circuit setup", time.Now())
pk, vk, err := plonk.Setup(r1cs, srs)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
if serialize {
fPK, _ := os.Create("proving.key")
pk.WriteTo(fPK)
fPK.Close()
fVK, _ := os.Create("verifying.key")
vk.WriteTo(fVK)
fVK.Close()
}
if outputSolidity {
fSolidity, _ := os.Create("proof.sol")
err = vk.ExportSolidity(fSolidity)
}
return r1cs, pk, vk
}
func createProofPlonk(plonky2Circuit string, r1cs constraint.ConstraintSystem, pk plonk.ProvingKey, vk plonk.VerifyingKey, serialize bool) plonk.Proof {
proofWithPis := verifier.DeserializeProofWithPublicInputs("./verifier/data/" + plonky2Circuit + "/proof_with_public_inputs.json")
// Witness
assignment := &BenchmarkPlonky2VerifierCircuitPlonk{
Proof: proofWithPis.Proof,
PublicInputs: proofWithPis.PublicInputs,
}
fmt.Println("Generating witness", time.Now())
witness, _ := frontend.NewWitness(assignment, ecc.BN254.ScalarField())
publicWitness, _ := witness.Public()
fmt.Println("Creating proof", time.Now())
proof, err := plonk.Prove(r1cs, pk, witness)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
fmt.Println("Verifying proof", time.Now())
err = plonk.Verify(proof, vk, publicWitness)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
const fpSize = 4 * 8
var buf bytes.Buffer
proof.WriteRawTo(&buf)
proofBytes := buf.Bytes()
var (
a [2]*big.Int
b [2][2]*big.Int
c [2]*big.Int
)
// proof.Ar, proof.Bs, proof.Krs
a[0] = new(big.Int).SetBytes(proofBytes[fpSize*0 : fpSize*1])
a[1] = new(big.Int).SetBytes(proofBytes[fpSize*1 : fpSize*2])
b[0][0] = new(big.Int).SetBytes(proofBytes[fpSize*2 : fpSize*3])
b[0][1] = new(big.Int).SetBytes(proofBytes[fpSize*3 : fpSize*4])
b[1][0] = new(big.Int).SetBytes(proofBytes[fpSize*4 : fpSize*5])
b[1][1] = new(big.Int).SetBytes(proofBytes[fpSize*5 : fpSize*6])
c[0] = new(big.Int).SetBytes(proofBytes[fpSize*6 : fpSize*7])
c[1] = new(big.Int).SetBytes(proofBytes[fpSize*7 : fpSize*8])
println("a[0] is ", a[0].String())
println("a[1] is ", a[1].String())
println("b[0][0] is ", b[0][0].String())
println("b[0][1] is ", b[0][1].String())
println("b[1][0] is ", b[1][0].String())
println("b[1][1] is ", b[1][1].String())
println("c[0] is ", c[0].String())
println("c[1] is ", c[1].String())
return proof
}
func main() {
plonky2Circuit := flag.String("plonky2-circuit", "", "plonky2 circuit to benchmark")
profileCircuit := flag.Bool("profile", false, "profile the circuit")
serialize := flag.Bool("serialize", false, "serialize the circuit")
outputSolidity := flag.Bool("solidity", false, "output solidity code for the circuit")
flag.Parse()
if plonky2Circuit == nil || *plonky2Circuit == "" {
fmt.Println("Please provide a plonky2 circuit to benchmark")
os.Exit(1)
}
r1cs, pk, vk := compileCircuitPlonk(*plonky2Circuit, *profileCircuit, *serialize, *outputSolidity)
createProofPlonk(*plonky2Circuit, r1cs, pk, vk, *serialize)
}

+ 38
- 0
fri/fri.go

@ -18,22 +18,60 @@ type Chip struct {
api frontend.API `gnark:"-"`
gl gl.Chip `gnark:"-"`
poseidonBN254Chip *poseidon.BN254Chip
commonData *types.CommonCircuitData
friParams *types.FriParams `gnark:"-"`
}
func NewChip(
api frontend.API,
commonData *types.CommonCircuitData,
friParams *types.FriParams,
) *Chip {
poseidonBN254Chip := poseidon.NewBN254Chip(api)
return &Chip{
api: api,
poseidonBN254Chip: poseidonBN254Chip,
commonData: commonData,
friParams: friParams,
gl: *gl.New(api),
}
}
func (f *Chip) GetInstance(zeta gl.QuadraticExtensionVariable) InstanceInfo {
zetaBatch := BatchInfo{
Point: zeta,
Polynomials: friAllPolys(f.commonData),
}
g := gl.PrimitiveRootOfUnity(f.commonData.DegreeBits)
zetaNext := f.gl.MulExtension(
gl.NewVariable(g.Uint64()).ToQuadraticExtension(),
zeta,
)
zetaNextBath := BatchInfo{
Point: zetaNext,
Polynomials: friZSPolys(f.commonData),
}
return InstanceInfo{
Oracles: friOracles(f.commonData),
Batches: []BatchInfo{zetaBatch, zetaNextBath},
}
}
func (f *Chip) ToOpenings(c variables.OpeningSet) Openings {
values := c.Constants // num_constants + 1
values = append(values, c.PlonkSigmas...) // num_routed_wires
values = append(values, c.Wires...) // num_wires
values = append(values, c.PlonkZs...) // num_challenges
values = append(values, c.PartialProducts...) // num_challenges * num_partial_products
values = append(values, c.QuotientPolys...) // num_challenges * quotient_degree_factor
zetaBatch := OpeningBatch{Values: values}
zetaNextBatch := OpeningBatch{Values: c.PlonkZsNext}
return Openings{Batches: []OpeningBatch{zetaBatch, zetaNextBatch}}
}
func (f *Chip) assertLeadingZeros(powWitness gl.Variable, friConfig types.FriConfig) {
// Asserts that powWitness'es big-endian bit representation has at least `leading_zeros` leading zeros.
// Note that this is assuming that the Goldilocks field is being used. Specfically that the

+ 25
- 17
fri/fri_test.go

@ -10,24 +10,24 @@ import (
"github.com/succinctlabs/gnark-plonky2-verifier/fri"
gl "github.com/succinctlabs/gnark-plonky2-verifier/goldilocks"
"github.com/succinctlabs/gnark-plonky2-verifier/poseidon"
"github.com/succinctlabs/gnark-plonky2-verifier/types"
"github.com/succinctlabs/gnark-plonky2-verifier/variables"
"github.com/succinctlabs/gnark-plonky2-verifier/verifier"
)
type TestFriCircuit struct {
proofWithPIsFilename string `gnark:"-"`
commonCircuitDataFilename string `gnark:"-"`
verifierOnlyCircuitDataFilename string `gnark:"-"`
ProofWithPis variables.ProofWithPublicInputs
VerifierOnlyCircuitData variables.VerifierOnlyCircuitData
CommonCircuitData types.CommonCircuitData
}
func (circuit *TestFriCircuit) Define(api frontend.API) error {
proofWithPis := verifier.DeserializeProofWithPublicInputs(circuit.proofWithPIsFilename)
commonCircuitData := verifier.DeserializeCommonCircuitData(circuit.commonCircuitDataFilename)
verifierOnlyCircuitData := verifier.DeserializeVerifierOnlyCircuitData(circuit.verifierOnlyCircuitDataFilename)
commonCircuitData := circuit.CommonCircuitData
verifierOnlyCircuitData := circuit.VerifierOnlyCircuitData
proofWithPis := circuit.ProofWithPis
glApi := gl.New(api)
poseidonChip := poseidon.NewGoldilocksChip(api)
friChip := fri.NewChip(api, &commonCircuitData.FriParams)
friChip := fri.NewChip(api, &commonCircuitData, &commonCircuitData.FriParams)
challengerChip := challenger.NewChip(api)
challengerChip.ObserveBN254Hash(verifierOnlyCircuitData.CircuitDigest)
@ -46,7 +46,7 @@ func (circuit *TestFriCircuit) Define(api frontend.API) error {
plonkZeta := challengerChip.GetExtensionChallenge()
glApi.AssertIsEqual(plonkZeta[0], gl.NewVariable("3892795992421241388"))
challengerChip.ObserveOpenings(fri.ToOpenings(proofWithPis.Proof.Openings))
challengerChip.ObserveOpenings(friChip.ToOpenings(proofWithPis.Proof.Openings))
friChallenges := challengerChip.GetFriChallenges(
proofWithPis.Proof.OpeningProof.CommitPhaseMerkleCaps,
@ -94,8 +94,8 @@ func (circuit *TestFriCircuit) Define(api frontend.API) error {
}
friChip.VerifyFriProof(
fri.GetInstance(&commonCircuitData, glApi, plonkZeta, commonCircuitData.DegreeBits),
fri.ToOpenings(proofWithPis.Proof.Openings),
friChip.GetInstance(plonkZeta),
friChip.ToOpenings(proofWithPis.Proof.Openings),
&friChallenges,
initialMerkleCaps,
&proofWithPis.Proof.OpeningProof,
@ -107,16 +107,24 @@ func (circuit *TestFriCircuit) Define(api frontend.API) error {
func TestDecodeBlockFriVerification(t *testing.T) {
assert := test.NewAssert(t)
proofWithPIsFilename := "../testdata/decode_block/proof_with_public_inputs.json"
commonCircuitDataFilename := "../testdata/decode_block/common_circuit_data.json"
verifierOnlyCircuitDataFilename := "../testdata/decode_block/verifier_only_circuit_data.json"
proofWithPis := variables.DeserializeProofWithPublicInputs(types.ReadProofWithPublicInputs(proofWithPIsFilename))
commonCircuitData := types.DeserializeCommonCircuitData(commonCircuitDataFilename)
verifierOnlyCircuitData := variables.DeserializeVerifierOnlyCircuitData(types.ReadVerifierOnlyCircuitData(verifierOnlyCircuitDataFilename))
testCase := func() {
circuit := TestFriCircuit{
proofWithPIsFilename: "../../data/decode_block/proof_with_public_inputs.json",
commonCircuitDataFilename: "../../data/decode_block//common_circuit_data.json",
verifierOnlyCircuitDataFilename: "../../data/decode_block//verifier_only_circuit_data.json",
proofWithPis,
verifierOnlyCircuitData,
commonCircuitData,
}
witness := TestFriCircuit{
proofWithPIsFilename: "../../data/dummy_2^14_gates/proof_with_public_inputs.json",
commonCircuitDataFilename: "../../data/dummy_2^14_gates/common_circuit_data.json",
verifierOnlyCircuitDataFilename: ".../../data/dummy_2^14_gates/verifier_only_circuit_data.json",
proofWithPis,
verifierOnlyCircuitData,
commonCircuitData,
}
err := test.IsSolved(&circuit, &witness, ecc.BN254.ScalarField())
assert.NoError(err)

+ 13
- 67
fri/fri_utils.go

@ -1,30 +1,9 @@
package fri
import (
gl "github.com/succinctlabs/gnark-plonky2-verifier/goldilocks"
"github.com/succinctlabs/gnark-plonky2-verifier/variables"
"github.com/succinctlabs/gnark-plonky2-verifier/types"
)
type OpeningBatch struct {
Values []gl.QuadraticExtensionVariable
}
type Openings struct {
Batches []OpeningBatch
}
func ToOpenings(c variables.OpeningSet) Openings {
values := c.Constants // num_constants + 1
values = append(values, c.PlonkSigmas...) // num_routed_wires
values = append(values, c.Wires...) // num_wires
values = append(values, c.PlonkZs...) // num_challenges
values = append(values, c.PartialProducts...) // num_challenges * num_partial_products
values = append(values, c.QuotientPolys...) // num_challenges * quotient_degree_factor
zetaBatch := OpeningBatch{Values: values}
zetaNextBatch := OpeningBatch{Values: c.PlonkZsNext}
return Openings{Batches: []OpeningBatch{zetaBatch, zetaNextBatch}}
}
type PolynomialInfo struct {
OracleIndex uint64
PolynomialInfo uint64
@ -35,16 +14,6 @@ type OracleInfo struct {
Blinding bool
}
type BatchInfo struct {
Point gl.QuadraticExtensionVariable
Polynomials []PolynomialInfo
}
type InstanceInfo struct {
Oracles []OracleInfo
Batches []BatchInfo
}
type PlonkOracle struct {
index uint64
blinding bool
@ -70,7 +39,7 @@ var QUOTIENT = PlonkOracle{
blinding: true,
}
func polynomialInfoFromRange(c *variables.CommonCircuitData, oracleIdx uint64, startPolyIdx uint64, endPolyIdx uint64) []PolynomialInfo {
func polynomialInfoFromRange(c *types.CommonCircuitData, oracleIdx uint64, startPolyIdx uint64, endPolyIdx uint64) []PolynomialInfo {
returnArr := make([]PolynomialInfo, 0)
for i := startPolyIdx; i < endPolyIdx; i++ {
returnArr = append(returnArr,
@ -84,7 +53,7 @@ func polynomialInfoFromRange(c *variables.CommonCircuitData, oracleIdx uint64, s
}
// Range of the sigma polynomials in the `constants_sigmas_commitment`.
func sigmasRange(c *variables.CommonCircuitData) []uint64 {
func sigmasRange(c *types.CommonCircuitData) []uint64 {
returnArr := make([]uint64, 0)
for i := c.NumConstants; i <= c.NumConstants+c.Config.NumRoutedWires; i++ {
returnArr = append(returnArr, i)
@ -93,20 +62,20 @@ func sigmasRange(c *variables.CommonCircuitData) []uint64 {
return returnArr
}
func numPreprocessedPolys(c *variables.CommonCircuitData) uint64 {
func numPreprocessedPolys(c *types.CommonCircuitData) uint64 {
sigmasRange := sigmasRange(c)
return sigmasRange[len(sigmasRange)-1]
}
func numZSPartialProductsPolys(c *variables.CommonCircuitData) uint64 {
func numZSPartialProductsPolys(c *types.CommonCircuitData) uint64 {
return c.Config.NumChallenges * (1 + c.NumPartialProducts)
}
func numQuotientPolys(c *variables.CommonCircuitData) uint64 {
func numQuotientPolys(c *types.CommonCircuitData) uint64 {
return c.Config.NumChallenges * c.QuotientDegreeFactor
}
func friPreprocessedPolys(c *variables.CommonCircuitData) []PolynomialInfo {
func friPreprocessedPolys(c *types.CommonCircuitData) []PolynomialInfo {
return polynomialInfoFromRange(
c,
CONSTANTS_SIGMAS.index,
@ -115,12 +84,12 @@ func friPreprocessedPolys(c *variables.CommonCircuitData) []PolynomialInfo {
)
}
func friWirePolys(c *variables.CommonCircuitData) []PolynomialInfo {
func friWirePolys(c *types.CommonCircuitData) []PolynomialInfo {
numWirePolys := c.Config.NumWires
return polynomialInfoFromRange(c, WIRES.index, 0, numWirePolys)
}
func friZSPartialProductsPolys(c *variables.CommonCircuitData) []PolynomialInfo {
func friZSPartialProductsPolys(c *types.CommonCircuitData) []PolynomialInfo {
return polynomialInfoFromRange(
c,
ZS_PARTIAL_PRODUCTS.index,
@ -129,7 +98,7 @@ func friZSPartialProductsPolys(c *variables.CommonCircuitData) []PolynomialInfo
)
}
func friQuotientPolys(c *variables.CommonCircuitData) []PolynomialInfo {
func friQuotientPolys(c *types.CommonCircuitData) []PolynomialInfo {
return polynomialInfoFromRange(
c,
QUOTIENT.index,
@ -138,7 +107,7 @@ func friQuotientPolys(c *variables.CommonCircuitData) []PolynomialInfo {
)
}
func friZSPolys(c *variables.CommonCircuitData) []PolynomialInfo {
func friZSPolys(c *types.CommonCircuitData) []PolynomialInfo {
return polynomialInfoFromRange(
c,
ZS_PARTIAL_PRODUCTS.index,
@ -147,7 +116,7 @@ func friZSPolys(c *variables.CommonCircuitData) []PolynomialInfo {
)
}
func friOracles(c *variables.CommonCircuitData) []OracleInfo {
func friOracles(c *types.CommonCircuitData) []OracleInfo {
return []OracleInfo{
{
NumPolys: numPreprocessedPolys(c),
@ -168,7 +137,7 @@ func friOracles(c *variables.CommonCircuitData) []OracleInfo {
}
}
func friAllPolys(c *variables.CommonCircuitData) []PolynomialInfo {
func friAllPolys(c *types.CommonCircuitData) []PolynomialInfo {
returnArr := make([]PolynomialInfo, 0)
returnArr = append(returnArr, friPreprocessedPolys(c)...)
returnArr = append(returnArr, friWirePolys(c)...)
@ -177,26 +146,3 @@ func friAllPolys(c *variables.CommonCircuitData) []PolynomialInfo {
return returnArr
}
func GetInstance(c *variables.CommonCircuitData, glApi *gl.Chip, zeta gl.QuadraticExtensionVariable, degreeBits uint64) InstanceInfo {
zetaBatch := BatchInfo{
Point: zeta,
Polynomials: friAllPolys(c),
}
g := gl.PrimitiveRootOfUnity(degreeBits)
zetaNext := glApi.MulExtension(
gl.NewVariable(g.Uint64()).ToQuadraticExtension(),
zeta,
)
zetaNextBath := BatchInfo{
Point: zetaNext,
Polynomials: friZSPolys(c),
}
return InstanceInfo{
Oracles: friOracles(c),
Batches: []BatchInfo{zetaBatch, zetaNextBath},
}
}

+ 21
- 0
fri/vars.go

@ -0,0 +1,21 @@
package fri
import gl "github.com/succinctlabs/gnark-plonky2-verifier/goldilocks"
type BatchInfo struct {
Point gl.QuadraticExtensionVariable
Polynomials []PolynomialInfo
}
type InstanceInfo struct {
Oracles []OracleInfo
Batches []BatchInfo
}
type OpeningBatch struct {
Values []gl.QuadraticExtensionVariable
}
type Openings struct {
Batches []OpeningBatch
}

+ 2
- 2
plonk/gates/gates_test.go

@ -11,7 +11,7 @@ import (
gl "github.com/succinctlabs/gnark-plonky2-verifier/goldilocks"
"github.com/succinctlabs/gnark-plonky2-verifier/plonk/gates"
"github.com/succinctlabs/gnark-plonky2-verifier/poseidon"
"github.com/succinctlabs/gnark-plonky2-verifier/verifier"
"github.com/succinctlabs/gnark-plonky2-verifier/types"
)
// From recursive_step circuit
@ -690,7 +690,7 @@ type TestGateCircuit struct {
}
func (circuit *TestGateCircuit) Define(api frontend.API) error {
commonCircuitData := verifier.DeserializeCommonCircuitData("../../data/decode_block/common_circuit_data.json")
commonCircuitData := types.DeserializeCommonCircuitData("../../testdata/decode_block/common_circuit_data.json")
numSelectors := commonCircuitData.SelectorsInfo.NumSelectors()
glApi := gl.New(api)

+ 15
- 4
plonk/plonk.go

@ -5,27 +5,37 @@ import (
gl "github.com/succinctlabs/gnark-plonky2-verifier/goldilocks"
"github.com/succinctlabs/gnark-plonky2-verifier/plonk/gates"
"github.com/succinctlabs/gnark-plonky2-verifier/poseidon"
"github.com/succinctlabs/gnark-plonky2-verifier/types"
"github.com/succinctlabs/gnark-plonky2-verifier/variables"
)
type PlonkChip struct {
api frontend.API `gnark:"-"`
commonData variables.CommonCircuitData `gnark:"-"`
commonData types.CommonCircuitData `gnark:"-"`
// These are global constant variables that we use in this Chip that we save here.
// This avoids having to recreate them every time we use them.
DEGREE gl.Variable `gnark:"-"`
DEGREE_BITS_F gl.Variable `gnark:"-"`
DEGREE_QE gl.QuadraticExtensionVariable `gnark:"-"`
commonDataKIs []gl.Variable `gnark:"-"`
evaluateGatesChip *gates.EvaluateGatesChip
}
func NewPlonkChip(api frontend.API, commonData variables.CommonCircuitData) *PlonkChip {
func NewPlonkChip(api frontend.API, commonData types.CommonCircuitData) *PlonkChip {
// TODO: Should degreeBits be verified that it fits within the field and that degree is within uint64?
// Create the gates based on commonData GateIds
createdGates := []gates.Gate{}
for _, gateId := range commonData.GateIds {
createdGates = append(createdGates, gates.GateInstanceFromId(gateId))
}
evaluateGatesChip := gates.NewEvaluateGatesChip(
api,
commonData.Gates,
createdGates,
commonData.NumGateConstraints,
commonData.SelectorsInfo,
)
@ -38,6 +48,7 @@ func NewPlonkChip(api frontend.API, commonData variables.CommonCircuitData) *Plo
DEGREE: gl.NewVariable(1 << commonData.DegreeBits),
DEGREE_BITS_F: gl.NewVariable(commonData.DegreeBits),
DEGREE_QE: gl.NewVariable(1 << commonData.DegreeBits).ToQuadraticExtension(),
commonDataKIs: gl.Uint64ArrayToVariableArray(commonData.KIs),
evaluateGatesChip: evaluateGatesChip,
}
@ -117,7 +128,7 @@ func (p *PlonkChip) evalVanishingPoly(
sIDs := make([]gl.QuadraticExtensionVariable, p.commonData.Config.NumRoutedWires)
for i := uint64(0); i < p.commonData.Config.NumRoutedWires; i++ {
sIDs[i] = glApi.ScalarMulExtension(proofChallenges.PlonkZeta, p.commonData.KIs[i])
sIDs[i] = glApi.ScalarMulExtension(proofChallenges.PlonkZeta, p.commonDataKIs[i])
}
// Calculate L_0(zeta)

+ 25
- 11
plonk/plonk_test.go

@ -7,23 +7,25 @@ import (
"github.com/consensys/gnark/frontend"
"github.com/consensys/gnark/test"
"github.com/succinctlabs/gnark-plonky2-verifier/plonk"
"github.com/succinctlabs/gnark-plonky2-verifier/types"
"github.com/succinctlabs/gnark-plonky2-verifier/variables"
"github.com/succinctlabs/gnark-plonky2-verifier/verifier"
)
type TestPlonkCircuit struct {
proofWithPIsFilename string `gnark:"-"`
commonCircuitDataFilename string `gnark:"-"`
verifierOnlyCircuitDataFilename string `gnark:"-"`
ProofWithPis variables.ProofWithPublicInputs `gnark:",public"`
VerifierOnlyCircuitData variables.VerifierOnlyCircuitData `gnark:",public"`
CommonCircuitData types.CommonCircuitData
}
func (circuit *TestPlonkCircuit) Define(api frontend.API) error {
proofWithPis := verifier.DeserializeProofWithPublicInputs(circuit.proofWithPIsFilename)
commonCircuitData := verifier.DeserializeCommonCircuitData(circuit.commonCircuitDataFilename)
verifierOnlyCircuitData := verifier.DeserializeVerifierOnlyCircuitData(circuit.verifierOnlyCircuitDataFilename)
commonCircuitData := circuit.CommonCircuitData
verifierOnlyCircuitData := circuit.VerifierOnlyCircuitData
proofWithPis := circuit.ProofWithPis
verifierChip := verifier.NewVerifierChip(api, commonCircuitData)
publicInputsHash := verifierChip.GetPublicInputsHash(proofWithPis.PublicInputs)
proofChallenges := verifierChip.GetChallenges(proofWithPis.Proof, publicInputsHash, commonCircuitData, verifierOnlyCircuitData)
proofChallenges := verifierChip.GetChallenges(proofWithPis.Proof, publicInputsHash, verifierOnlyCircuitData)
plonkChip := plonk.NewPlonkChip(
api,
@ -37,13 +39,25 @@ func (circuit *TestPlonkCircuit) Define(api frontend.API) error {
func TestPlonkDecodeBlock(t *testing.T) {
assert := test.NewAssert(t)
proofWithPIsFilename := "../testdata/decode_block/proof_with_public_inputs.json"
commonCircuitDataFilename := "../testdata/decode_block/common_circuit_data.json"
verifierOnlyCircuitDataFilename := "../testdata/decode_block/verifier_only_circuit_data.json"
proofWithPis := variables.DeserializeProofWithPublicInputs(types.ReadProofWithPublicInputs(proofWithPIsFilename))
commonCircuitData := types.DeserializeCommonCircuitData(commonCircuitDataFilename)
verifierOnlyCircuitData := variables.DeserializeVerifierOnlyCircuitData(types.ReadVerifierOnlyCircuitData(verifierOnlyCircuitDataFilename))
testCase := func() {
circuit := TestPlonkCircuit{
proofWithPIsFilename: "../../data/decode_block/proof_with_public_inputs.json",
commonCircuitDataFilename: "../../data/decode_block/common_circuit_data.json",
verifierOnlyCircuitDataFilename: "../../data/decode_block/verifier_only_circuit_data.json",
proofWithPis,
verifierOnlyCircuitData,
commonCircuitData,
}
witness := TestPlonkCircuit{
proofWithPis,
verifierOnlyCircuitData,
commonCircuitData,
}
witness := TestPlonkCircuit{}
err := test.IsSolved(&circuit, &witness, ecc.BN254.ScalarField())
assert.NoError(err)
}

verifier/data/.DS_Store → testdata/.DS_Store


verifier/data/decode_block/common_circuit_data.json → testdata/decode_block/common_circuit_data.json


verifier/data/decode_block/proof_with_public_inputs.json → testdata/decode_block/proof_with_public_inputs.json


verifier/data/decode_block/verifier_only_circuit_data.json → testdata/decode_block/verifier_only_circuit_data.json


verifier/data/step/common_circuit_data.json → testdata/step/common_circuit_data.json


verifier/data/step/proof_with_public_inputs.json → testdata/step/proof_with_public_inputs.json


verifier/data/step/verifier_only_circuit_data.json → testdata/step/verifier_only_circuit_data.json


+ 122
- 0
types/common_data.go

@ -0,0 +1,122 @@
package types
import (
"encoding/json"
"io"
"os"
"github.com/succinctlabs/gnark-plonky2-verifier/plonk/gates"
)
type CommonCircuitDataRaw struct {
Config struct {
NumWires uint64 `json:"num_wires"`
NumRoutedWires uint64 `json:"num_routed_wires"`
NumConstants uint64 `json:"num_constants"`
UseBaseArithmeticGate bool `json:"use_base_arithmetic_gate"`
SecurityBits uint64 `json:"security_bits"`
NumChallenges uint64 `json:"num_challenges"`
ZeroKnowledge bool `json:"zero_knowledge"`
MaxQuotientDegreeFactor uint64 `json:"max_quotient_degree_factor"`
FriConfig struct {
RateBits uint64 `json:"rate_bits"`
CapHeight uint64 `json:"cap_height"`
ProofOfWorkBits uint64 `json:"proof_of_work_bits"`
ReductionStrategy struct {
ConstantArityBits []uint64 `json:"ConstantArityBits"`
} `json:"reduction_strategy"`
NumQueryRounds uint64 `json:"num_query_rounds"`
} `json:"fri_config"`
} `json:"config"`
FriParams struct {
Config struct {
RateBits uint64 `json:"rate_bits"`
CapHeight uint64 `json:"cap_height"`
ProofOfWorkBits uint64 `json:"proof_of_work_bits"`
ReductionStrategy struct {
ConstantArityBits []uint64 `json:"ConstantArityBits"`
} `json:"reduction_strategy"`
NumQueryRounds uint64 `json:"num_query_rounds"`
} `json:"config"`
Hiding bool `json:"hiding"`
DegreeBits uint64 `json:"degree_bits"`
ReductionArityBits []uint64 `json:"reduction_arity_bits"`
} `json:"fri_params"`
Gates []string `json:"gates"`
SelectorsInfo struct {
SelectorIndices []uint64 `json:"selector_indices"`
Groups []struct {
Start uint64 `json:"start"`
End uint64 `json:"end"`
} `json:"groups"`
} `json:"selectors_info"`
QuotientDegreeFactor uint64 `json:"quotient_degree_factor"`
NumGateConstraints uint64 `json:"num_gate_constraints"`
NumConstants uint64 `json:"num_constants"`
NumPublicInputs uint64 `json:"num_public_inputs"`
KIs []uint64 `json:"k_is"`
NumPartialProducts uint64 `json:"num_partial_products"`
}
func DeserializeCommonCircuitData(path string) CommonCircuitData {
jsonFile, err := os.Open(path)
if err != nil {
panic(err)
}
defer jsonFile.Close()
rawBytes, _ := io.ReadAll(jsonFile)
var raw CommonCircuitDataRaw
err = json.Unmarshal(rawBytes, &raw)
if err != nil {
panic(err)
}
var commonCircuitData CommonCircuitData
commonCircuitData.Config.NumWires = raw.Config.NumWires
commonCircuitData.Config.NumRoutedWires = raw.Config.NumRoutedWires
commonCircuitData.Config.NumConstants = raw.Config.NumConstants
commonCircuitData.Config.UseBaseArithmeticGate = raw.Config.UseBaseArithmeticGate
commonCircuitData.Config.SecurityBits = raw.Config.SecurityBits
commonCircuitData.Config.NumChallenges = raw.Config.NumChallenges
commonCircuitData.Config.ZeroKnowledge = raw.Config.ZeroKnowledge
commonCircuitData.Config.MaxQuotientDegreeFactor = raw.Config.MaxQuotientDegreeFactor
commonCircuitData.Config.FriConfig.RateBits = raw.Config.FriConfig.RateBits
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.DegreeBits = raw.FriParams.DegreeBits
commonCircuitData.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
commonCircuitData.FriParams.ReductionArityBits = raw.FriParams.ReductionArityBits
commonCircuitData.GateIds = raw.Gates
selectorGroupStart := []uint64{}
selectorGroupEnd := []uint64{}
for _, group := range raw.SelectorsInfo.Groups {
selectorGroupStart = append(selectorGroupStart, group.Start)
selectorGroupEnd = append(selectorGroupEnd, group.End)
}
commonCircuitData.SelectorsInfo = *gates.NewSelectorsInfo(
raw.SelectorsInfo.SelectorIndices,
selectorGroupStart,
selectorGroupEnd,
)
commonCircuitData.QuotientDegreeFactor = raw.QuotientDegreeFactor
commonCircuitData.NumGateConstraints = raw.NumGateConstraints
commonCircuitData.NumConstants = raw.NumConstants
commonCircuitData.NumPublicInputs = raw.NumPublicInputs
commonCircuitData.KIs = raw.KIs
commonCircuitData.NumPartialProducts = raw.NumPartialProducts
return commonCircuitData
}

+ 9
- 0
types/common_data_test.go

@ -0,0 +1,9 @@
package types
import (
"testing"
)
func TestDeserializeCommonCircuitData(t *testing.T) {
DeserializeCommonCircuitData("../testdata/decode_block/common_circuit_data.json")
}

+ 126
- 0
types/deserialize.go

@ -0,0 +1,126 @@
package types
import (
"encoding/json"
"io"
"os"
)
type ProofWithPublicInputsRaw struct {
Proof struct {
WiresCap []string `json:"wires_cap"`
PlonkZsPartialProductsCap []string `json:"plonk_zs_partial_products_cap"`
QuotientPolysCap []string `json:"quotient_polys_cap"`
Openings struct {
Constants [][]uint64 `json:"constants"`
PlonkSigmas [][]uint64 `json:"plonk_sigmas"`
Wires [][]uint64 `json:"wires"`
PlonkZs [][]uint64 `json:"plonk_zs"`
PlonkZsNext [][]uint64 `json:"plonk_zs_next"`
PartialProducts [][]uint64 `json:"partial_products"`
QuotientPolys [][]uint64 `json:"quotient_polys"`
} `json:"openings"`
OpeningProof struct {
CommitPhaseMerkleCaps [][]string `json:"commit_phase_merkle_caps"`
QueryRoundProofs []struct {
InitialTreesProof struct {
EvalsProofs []EvalProofRaw `json:"evals_proofs"`
} `json:"initial_trees_proof"`
Steps []struct {
Evals [][]uint64 `json:"evals"`
MerkleProof struct {
Siblings []string `json:"siblings"`
} `json:"merkle_proof"`
} `json:"steps"`
} `json:"query_round_proofs"`
FinalPoly struct {
Coeffs [][]uint64 `json:"coeffs"`
} `json:"final_poly"`
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 []string
}
func (m *MerkleProofRaw) UnmarshalJSON(data []byte) error {
type SiblingObject struct {
Siblings []string // "siblings"
}
var siblings SiblingObject
if err := json.Unmarshal(data, &siblings); err != nil {
panic(err)
}
m.Hash = make([]string, len(siblings.Siblings))
copy(m.Hash[:], siblings.Siblings)
return nil
}
type ProofChallengesRaw struct {
PlonkBetas []uint64 `json:"plonk_betas"`
PlonkGammas []uint64 `json:"plonk_gammas"`
PlonkAlphas []uint64 `json:"plonk_alphas"`
PlonkZeta []uint64 `json:"plonk_zeta"`
FriChallenges struct {
FriAlpha []uint64 `json:"fri_alpha"`
FriBetas [][]uint64 `json:"fri_betas"`
FriPowResponse uint64 `json:"fri_pow_response"`
FriQueryIndices []uint64 `json:"fri_query_indices"`
} `json:"fri_challenges"`
}
type VerifierOnlyCircuitDataRaw struct {
ConstantsSigmasCap []string `json:"constants_sigmas_cap"`
CircuitDigest string `json:"circuit_digest"`
}
func ReadProofWithPublicInputs(path string) ProofWithPublicInputsRaw {
jsonFile, err := os.Open(path)
if err != nil {
panic(err)
}
defer jsonFile.Close()
rawBytes, _ := io.ReadAll(jsonFile)
var raw ProofWithPublicInputsRaw
err = json.Unmarshal(rawBytes, &raw)
if err != nil {
panic(err)
}
return raw
}
func ReadVerifierOnlyCircuitData(path string) VerifierOnlyCircuitDataRaw {
jsonFile, err := os.Open(path)
if err != nil {
panic(err)
}
defer jsonFile.Close()
rawBytes, _ := io.ReadAll(jsonFile)
var raw VerifierOnlyCircuitDataRaw
err = json.Unmarshal(rawBytes, &raw)
if err != nil {
panic(err)
}
return raw
}

+ 13
- 0
types/deserialize_test.go

@ -0,0 +1,13 @@
package types
import (
"testing"
)
func TestReadProofWithPublicInputs(t *testing.T) {
ReadProofWithPublicInputs("../testdata/decode_block/proof_with_public_inputs.json")
}
func TestReadVerifierOnlyCircuitData(t *testing.T) {
ReadVerifierOnlyCircuitData("../testdata/decode_block/verifier_only_circuit_data.json")
}

+ 28
- 0
types/types.go

@ -1,5 +1,7 @@
package types
import "github.com/succinctlabs/gnark-plonky2-verifier/plonk/gates"
type FriConfig struct {
RateBits uint64
CapHeight uint64
@ -18,3 +20,29 @@ type FriParams struct {
DegreeBits uint64
ReductionArityBits []uint64
}
type CircuitConfig struct {
NumWires uint64
NumRoutedWires uint64
NumConstants uint64
UseBaseArithmeticGate bool
SecurityBits uint64
NumChallenges uint64
ZeroKnowledge bool
MaxQuotientDegreeFactor uint64
FriConfig FriConfig
}
type CommonCircuitData struct {
Config CircuitConfig
FriParams
GateIds []string
SelectorsInfo gates.SelectorsInfo
DegreeBits uint64
QuotientDegreeFactor uint64
NumGateConstraints uint64
NumConstants uint64
NumPublicInputs uint64
KIs []uint64
NumPartialProducts uint64
}

+ 21
- 0
types/utils.go

@ -0,0 +1,21 @@
package types
func ReductionArityBits(
arityBits uint64,
finalPolyBits uint64,
degreeBits uint64,
rateBits uint64,
capHeight uint64,
) []uint64 {
returnArr := make([]uint64, 0)
for degreeBits > finalPolyBits && degreeBits+rateBits-arityBits >= capHeight {
returnArr = append(returnArr, arityBits)
if degreeBits < arityBits {
panic("degreeBits < arityBits")
}
degreeBits -= arityBits
}
return returnArr
}

+ 0
- 28
variables/circuit.go

@ -2,9 +2,7 @@ package variables
import (
gl "github.com/succinctlabs/gnark-plonky2-verifier/goldilocks"
"github.com/succinctlabs/gnark-plonky2-verifier/plonk/gates"
"github.com/succinctlabs/gnark-plonky2-verifier/poseidon"
"github.com/succinctlabs/gnark-plonky2-verifier/types"
)
type Proof struct {
@ -24,29 +22,3 @@ type VerifierOnlyCircuitData struct {
ConstantSigmasCap FriMerkleCap
CircuitDigest poseidon.BN254HashOut
}
type CircuitConfig struct {
NumWires uint64
NumRoutedWires uint64
NumConstants uint64
UseBaseArithmeticGate bool
SecurityBits uint64
NumChallenges uint64
ZeroKnowledge bool
MaxQuotientDegreeFactor uint64
FriConfig types.FriConfig
}
type CommonCircuitData struct {
Config CircuitConfig
FriParams types.FriParams
Gates []gates.Gate
SelectorsInfo gates.SelectorsInfo
DegreeBits uint64
QuotientDegreeFactor uint64
NumGateConstraints uint64
NumConstants uint64
NumPublicInputs uint64
KIs []gl.Variable
NumPartialProducts uint64
}

+ 156
- 0
variables/deserialize.go

@ -0,0 +1,156 @@
package variables
import (
"math/big"
"github.com/consensys/gnark/frontend"
gl "github.com/succinctlabs/gnark-plonky2-verifier/goldilocks"
"github.com/succinctlabs/gnark-plonky2-verifier/poseidon"
"github.com/succinctlabs/gnark-plonky2-verifier/types"
)
func DeserializeMerkleCap(merkleCapRaw []string) FriMerkleCap {
n := len(merkleCapRaw)
merkleCap := make([]poseidon.BN254HashOut, n)
for i := 0; i < n; i++ {
capBigInt, _ := new(big.Int).SetString(merkleCapRaw[i], 10)
merkleCap[i] = frontend.Variable(capBigInt)
}
return merkleCap
}
func DeserializeMerkleProof(merkleProofRaw struct{ Siblings []interface{} }) FriMerkleProof {
n := len(merkleProofRaw.Siblings)
var mp FriMerkleProof
mp.Siblings = make([]poseidon.BN254HashOut, n)
for i := 0; i < n; i++ {
element := merkleProofRaw.Siblings[i].(struct{ Elements []uint64 })
mp.Siblings[i] = gl.Uint64ArrayToVariableArray(element.Elements)
}
return mp
}
func DeserializeOpeningSet(openingSetRaw struct {
Constants [][]uint64
PlonkSigmas [][]uint64
Wires [][]uint64
PlonkZs [][]uint64
PlonkZsNext [][]uint64
PartialProducts [][]uint64
QuotientPolys [][]uint64
}) OpeningSet {
return OpeningSet{
Constants: gl.Uint64ArrayToQuadraticExtensionArray(openingSetRaw.Constants),
PlonkSigmas: gl.Uint64ArrayToQuadraticExtensionArray(openingSetRaw.PlonkSigmas),
Wires: gl.Uint64ArrayToQuadraticExtensionArray(openingSetRaw.Wires),
PlonkZs: gl.Uint64ArrayToQuadraticExtensionArray(openingSetRaw.PlonkZs),
PlonkZsNext: gl.Uint64ArrayToQuadraticExtensionArray(openingSetRaw.PlonkZsNext),
PartialProducts: gl.Uint64ArrayToQuadraticExtensionArray(openingSetRaw.PartialProducts),
QuotientPolys: gl.Uint64ArrayToQuadraticExtensionArray(openingSetRaw.QuotientPolys),
}
}
func StringArrayToHashBN254Array(rawHashes []string) []poseidon.BN254HashOut {
hashes := []poseidon.BN254HashOut{}
for i := 0; i < len(rawHashes); i++ {
hashBigInt, _ := new(big.Int).SetString(rawHashes[i], 10)
hashVar := frontend.Variable(hashBigInt)
hashes = append(hashes, poseidon.BN254HashOut(hashVar))
}
return hashes
}
func DeserializeFriProof(openingProofRaw struct {
CommitPhaseMerkleCaps [][]string
QueryRoundProofs []struct {
InitialTreesProof struct {
EvalsProofs []types.EvalProofRaw
}
Steps []struct {
Evals [][]uint64
MerkleProof struct {
Siblings []string
}
}
}
FinalPoly struct {
Coeffs [][]uint64
}
PowWitness uint64
}) FriProof {
var openingProof FriProof
openingProof.PowWitness = gl.NewVariable(openingProofRaw.PowWitness)
openingProof.FinalPoly.Coeffs = gl.Uint64ArrayToQuadraticExtensionArray(openingProofRaw.FinalPoly.Coeffs)
openingProof.CommitPhaseMerkleCaps = make([]FriMerkleCap, len(openingProofRaw.CommitPhaseMerkleCaps))
for i := 0; i < len(openingProofRaw.CommitPhaseMerkleCaps); i++ {
openingProof.CommitPhaseMerkleCaps[i] = StringArrayToHashBN254Array(openingProofRaw.CommitPhaseMerkleCaps[i])
}
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([]FriEvalProof, numEvalProofs)
for j := 0; j < numEvalProofs; j++ {
openingProof.QueryRoundProofs[i].InitialTreesProof.EvalsProofs[j].Elements = gl.Uint64ArrayToVariableArray(openingProofRaw.QueryRoundProofs[i].InitialTreesProof.EvalsProofs[j].LeafElements)
openingProof.QueryRoundProofs[i].InitialTreesProof.EvalsProofs[j].MerkleProof.Siblings = StringArrayToHashBN254Array(openingProofRaw.QueryRoundProofs[i].InitialTreesProof.EvalsProofs[j].MerkleProof.Hash)
}
numSteps := len(openingProofRaw.QueryRoundProofs[i].Steps)
openingProof.QueryRoundProofs[i].Steps = make([]FriQueryStep, numSteps)
for j := 0; j < numSteps; j++ {
openingProof.QueryRoundProofs[i].Steps[j].Evals = gl.Uint64ArrayToQuadraticExtensionArray(openingProofRaw.QueryRoundProofs[i].Steps[j].Evals)
openingProof.QueryRoundProofs[i].Steps[j].MerkleProof.Siblings = StringArrayToHashBN254Array(openingProofRaw.QueryRoundProofs[i].Steps[j].MerkleProof.Siblings)
}
}
return openingProof
}
func DeserializeProofWithPublicInputs(raw types.ProofWithPublicInputsRaw) ProofWithPublicInputs {
var proofWithPis ProofWithPublicInputs
proofWithPis.Proof.WiresCap = DeserializeMerkleCap(raw.Proof.WiresCap)
proofWithPis.Proof.PlonkZsPartialProductsCap = DeserializeMerkleCap(raw.Proof.PlonkZsPartialProductsCap)
proofWithPis.Proof.QuotientPolysCap = DeserializeMerkleCap(raw.Proof.QuotientPolysCap)
proofWithPis.Proof.Openings = DeserializeOpeningSet(struct {
Constants [][]uint64
PlonkSigmas [][]uint64
Wires [][]uint64
PlonkZs [][]uint64
PlonkZsNext [][]uint64
PartialProducts [][]uint64
QuotientPolys [][]uint64
}(raw.Proof.Openings))
proofWithPis.Proof.OpeningProof = DeserializeFriProof(struct {
CommitPhaseMerkleCaps [][]string
QueryRoundProofs []struct {
InitialTreesProof struct {
EvalsProofs []types.EvalProofRaw
}
Steps []struct {
Evals [][]uint64
MerkleProof struct {
Siblings []string
}
}
}
FinalPoly struct{ Coeffs [][]uint64 }
PowWitness uint64
}(raw.Proof.OpeningProof))
proofWithPis.PublicInputs = gl.Uint64ArrayToVariableArray(raw.PublicInputs)
return proofWithPis
}
func DeserializeVerifierOnlyCircuitData(raw types.VerifierOnlyCircuitDataRaw) VerifierOnlyCircuitData {
var verifierOnlyCircuitData VerifierOnlyCircuitData
verifierOnlyCircuitData.ConstantSigmasCap = DeserializeMerkleCap(raw.ConstantsSigmasCap)
circuitDigestBigInt, _ := new(big.Int).SetString(raw.CircuitDigest, 10)
circuitDigestVar := frontend.Variable(circuitDigestBigInt)
verifierOnlyCircuitData.CircuitDigest = poseidon.BN254HashOut(circuitDigestVar)
return verifierOnlyCircuitData
}

+ 17
- 0
variables/deserialize_test.go

@ -0,0 +1,17 @@
package variables
import (
"testing"
"github.com/succinctlabs/gnark-plonky2-verifier/types"
)
func TestDeserializeProofWithPublicInputs(t *testing.T) {
proofWithPis := DeserializeProofWithPublicInputs(types.ReadProofWithPublicInputs("../testdata/decode_block/proof_with_public_inputs.json"))
t.Logf("%+v\n", proofWithPis)
}
func TestDeserializeVerifierOnlyCircuitData(t *testing.T) {
verifierOnlyCircuitData := DeserializeVerifierOnlyCircuitData(types.ReadVerifierOnlyCircuitData("../testdata/decode_block/verifier_only_circuit_data.json"))
t.Logf("%+v\n", verifierOnlyCircuitData)
}

+ 0
- 436
verifier/deserialize.go

@ -1,436 +0,0 @@
package verifier
import (
"encoding/json"
"io"
"math/big"
"os"
"github.com/consensys/gnark/frontend"
gl "github.com/succinctlabs/gnark-plonky2-verifier/goldilocks"
"github.com/succinctlabs/gnark-plonky2-verifier/plonk/gates"
"github.com/succinctlabs/gnark-plonky2-verifier/poseidon"
"github.com/succinctlabs/gnark-plonky2-verifier/variables"
)
type ProofWithPublicInputsRaw struct {
Proof struct {
WiresCap []string `json:"wires_cap"`
PlonkZsPartialProductsCap []string `json:"plonk_zs_partial_products_cap"`
QuotientPolysCap []string `json:"quotient_polys_cap"`
Openings struct {
Constants [][]uint64 `json:"constants"`
PlonkSigmas [][]uint64 `json:"plonk_sigmas"`
Wires [][]uint64 `json:"wires"`
PlonkZs [][]uint64 `json:"plonk_zs"`
PlonkZsNext [][]uint64 `json:"plonk_zs_next"`
PartialProducts [][]uint64 `json:"partial_products"`
QuotientPolys [][]uint64 `json:"quotient_polys"`
} `json:"openings"`
OpeningProof struct {
CommitPhaseMerkleCaps [][]string `json:"commit_phase_merkle_caps"`
QueryRoundProofs []struct {
InitialTreesProof struct {
EvalsProofs []EvalProofRaw `json:"evals_proofs"`
} `json:"initial_trees_proof"`
Steps []struct {
Evals [][]uint64 `json:"evals"`
MerkleProof struct {
Siblings []string `json:"siblings"`
} `json:"merkle_proof"`
} `json:"steps"`
} `json:"query_round_proofs"`
FinalPoly struct {
Coeffs [][]uint64 `json:"coeffs"`
} `json:"final_poly"`
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 []string
}
func (m *MerkleProofRaw) UnmarshalJSON(data []byte) error {
type SiblingObject struct {
Siblings []string // "siblings"
}
var siblings SiblingObject
if err := json.Unmarshal(data, &siblings); err != nil {
panic(err)
}
m.Hash = make([]string, len(siblings.Siblings))
copy(m.Hash[:], siblings.Siblings)
return nil
}
type CommonCircuitDataRaw struct {
Config struct {
NumWires uint64 `json:"num_wires"`
NumRoutedWires uint64 `json:"num_routed_wires"`
NumConstants uint64 `json:"num_constants"`
UseBaseArithmeticGate bool `json:"use_base_arithmetic_gate"`
SecurityBits uint64 `json:"security_bits"`
NumChallenges uint64 `json:"num_challenges"`
ZeroKnowledge bool `json:"zero_knowledge"`
MaxQuotientDegreeFactor uint64 `json:"max_quotient_degree_factor"`
FriConfig struct {
RateBits uint64 `json:"rate_bits"`
CapHeight uint64 `json:"cap_height"`
ProofOfWorkBits uint64 `json:"proof_of_work_bits"`
ReductionStrategy struct {
ConstantArityBits []uint64 `json:"ConstantArityBits"`
} `json:"reduction_strategy"`
NumQueryRounds uint64 `json:"num_query_rounds"`
} `json:"fri_config"`
} `json:"config"`
FriParams struct {
Config struct {
RateBits uint64 `json:"rate_bits"`
CapHeight uint64 `json:"cap_height"`
ProofOfWorkBits uint64 `json:"proof_of_work_bits"`
ReductionStrategy struct {
ConstantArityBits []uint64 `json:"ConstantArityBits"`
} `json:"reduction_strategy"`
NumQueryRounds uint64 `json:"num_query_rounds"`
} `json:"config"`
Hiding bool `json:"hiding"`
DegreeBits uint64 `json:"degree_bits"`
ReductionArityBits []uint64 `json:"reduction_arity_bits"`
} `json:"fri_params"`
Gates []string `json:"gates"`
SelectorsInfo struct {
SelectorIndices []uint64 `json:"selector_indices"`
Groups []struct {
Start uint64 `json:"start"`
End uint64 `json:"end"`
} `json:"groups"`
} `json:"selectors_info"`
QuotientDegreeFactor uint64 `json:"quotient_degree_factor"`
NumGateConstraints uint64 `json:"num_gate_constraints"`
NumConstants uint64 `json:"num_constants"`
NumPublicInputs uint64 `json:"num_public_inputs"`
KIs []uint64 `json:"k_is"`
NumPartialProducts uint64 `json:"num_partial_products"`
}
type ProofChallengesRaw struct {
PlonkBetas []uint64 `json:"plonk_betas"`
PlonkGammas []uint64 `json:"plonk_gammas"`
PlonkAlphas []uint64 `json:"plonk_alphas"`
PlonkZeta []uint64 `json:"plonk_zeta"`
FriChallenges struct {
FriAlpha []uint64 `json:"fri_alpha"`
FriBetas [][]uint64 `json:"fri_betas"`
FriPowResponse uint64 `json:"fri_pow_response"`
FriQueryIndices []uint64 `json:"fri_query_indices"`
} `json:"fri_challenges"`
}
type VerifierOnlyCircuitDataRaw struct {
ConstantsSigmasCap []string `json:"constants_sigmas_cap"`
CircuitDigest string `json:"circuit_digest"`
}
func DeserializeMerkleCap(merkleCapRaw []string) variables.FriMerkleCap {
n := len(merkleCapRaw)
merkleCap := make([]poseidon.BN254HashOut, n)
for i := 0; i < n; i++ {
capBigInt, _ := new(big.Int).SetString(merkleCapRaw[i], 10)
merkleCap[i] = frontend.Variable(capBigInt)
}
return merkleCap
}
func DeserializeMerkleProof(merkleProofRaw struct{ Siblings []interface{} }) variables.FriMerkleProof {
n := len(merkleProofRaw.Siblings)
var mp variables.FriMerkleProof
mp.Siblings = make([]poseidon.BN254HashOut, n)
for i := 0; i < n; i++ {
element := merkleProofRaw.Siblings[i].(struct{ Elements []uint64 })
mp.Siblings[i] = gl.Uint64ArrayToVariableArray(element.Elements)
}
return mp
}
func DeserializeOpeningSet(openingSetRaw struct {
Constants [][]uint64
PlonkSigmas [][]uint64
Wires [][]uint64
PlonkZs [][]uint64
PlonkZsNext [][]uint64
PartialProducts [][]uint64
QuotientPolys [][]uint64
}) variables.OpeningSet {
return variables.OpeningSet{
Constants: gl.Uint64ArrayToQuadraticExtensionArray(openingSetRaw.Constants),
PlonkSigmas: gl.Uint64ArrayToQuadraticExtensionArray(openingSetRaw.PlonkSigmas),
Wires: gl.Uint64ArrayToQuadraticExtensionArray(openingSetRaw.Wires),
PlonkZs: gl.Uint64ArrayToQuadraticExtensionArray(openingSetRaw.PlonkZs),
PlonkZsNext: gl.Uint64ArrayToQuadraticExtensionArray(openingSetRaw.PlonkZsNext),
PartialProducts: gl.Uint64ArrayToQuadraticExtensionArray(openingSetRaw.PartialProducts),
QuotientPolys: gl.Uint64ArrayToQuadraticExtensionArray(openingSetRaw.QuotientPolys),
}
}
func StringArrayToHashBN254Array(rawHashes []string) []poseidon.BN254HashOut {
hashes := []poseidon.BN254HashOut{}
for i := 0; i < len(rawHashes); i++ {
hashBigInt, _ := new(big.Int).SetString(rawHashes[i], 10)
hashVar := frontend.Variable(hashBigInt)
hashes = append(hashes, poseidon.BN254HashOut(hashVar))
}
return hashes
}
func DeserializeFriProof(openingProofRaw struct {
CommitPhaseMerkleCaps [][]string
QueryRoundProofs []struct {
InitialTreesProof struct {
EvalsProofs []EvalProofRaw
}
Steps []struct {
Evals [][]uint64
MerkleProof struct {
Siblings []string
}
}
}
FinalPoly struct {
Coeffs [][]uint64
}
PowWitness uint64
}) variables.FriProof {
var openingProof variables.FriProof
openingProof.PowWitness = gl.NewVariable(openingProofRaw.PowWitness)
openingProof.FinalPoly.Coeffs = gl.Uint64ArrayToQuadraticExtensionArray(openingProofRaw.FinalPoly.Coeffs)
openingProof.CommitPhaseMerkleCaps = make([]variables.FriMerkleCap, len(openingProofRaw.CommitPhaseMerkleCaps))
for i := 0; i < len(openingProofRaw.CommitPhaseMerkleCaps); i++ {
openingProof.CommitPhaseMerkleCaps[i] = StringArrayToHashBN254Array(openingProofRaw.CommitPhaseMerkleCaps[i])
}
numQueryRoundProofs := len(openingProofRaw.QueryRoundProofs)
openingProof.QueryRoundProofs = make([]variables.FriQueryRound, numQueryRoundProofs)
for i := 0; i < numQueryRoundProofs; i++ {
numEvalProofs := len(openingProofRaw.QueryRoundProofs[i].InitialTreesProof.EvalsProofs)
openingProof.QueryRoundProofs[i].InitialTreesProof.EvalsProofs = make([]variables.FriEvalProof, numEvalProofs)
for j := 0; j < numEvalProofs; j++ {
openingProof.QueryRoundProofs[i].InitialTreesProof.EvalsProofs[j].Elements = gl.Uint64ArrayToVariableArray(openingProofRaw.QueryRoundProofs[i].InitialTreesProof.EvalsProofs[j].LeafElements)
openingProof.QueryRoundProofs[i].InitialTreesProof.EvalsProofs[j].MerkleProof.Siblings = StringArrayToHashBN254Array(openingProofRaw.QueryRoundProofs[i].InitialTreesProof.EvalsProofs[j].MerkleProof.Hash)
}
numSteps := len(openingProofRaw.QueryRoundProofs[i].Steps)
openingProof.QueryRoundProofs[i].Steps = make([]variables.FriQueryStep, numSteps)
for j := 0; j < numSteps; j++ {
openingProof.QueryRoundProofs[i].Steps[j].Evals = gl.Uint64ArrayToQuadraticExtensionArray(openingProofRaw.QueryRoundProofs[i].Steps[j].Evals)
openingProof.QueryRoundProofs[i].Steps[j].MerkleProof.Siblings = StringArrayToHashBN254Array(openingProofRaw.QueryRoundProofs[i].Steps[j].MerkleProof.Siblings)
}
}
return openingProof
}
func DeserializeProofWithPublicInputs(path string) variables.ProofWithPublicInputs {
jsonFile, err := os.Open(path)
if err != nil {
panic(err)
}
defer jsonFile.Close()
rawBytes, _ := io.ReadAll(jsonFile)
var raw ProofWithPublicInputsRaw
err = json.Unmarshal(rawBytes, &raw)
if err != nil {
panic(err)
}
var proofWithPis variables.ProofWithPublicInputs
proofWithPis.Proof.WiresCap = DeserializeMerkleCap(raw.Proof.WiresCap)
proofWithPis.Proof.PlonkZsPartialProductsCap = DeserializeMerkleCap(raw.Proof.PlonkZsPartialProductsCap)
proofWithPis.Proof.QuotientPolysCap = DeserializeMerkleCap(raw.Proof.QuotientPolysCap)
proofWithPis.Proof.Openings = DeserializeOpeningSet(struct {
Constants [][]uint64
PlonkSigmas [][]uint64
Wires [][]uint64
PlonkZs [][]uint64
PlonkZsNext [][]uint64
PartialProducts [][]uint64
QuotientPolys [][]uint64
}(raw.Proof.Openings))
proofWithPis.Proof.OpeningProof = DeserializeFriProof(struct {
CommitPhaseMerkleCaps [][]string
QueryRoundProofs []struct {
InitialTreesProof struct {
EvalsProofs []EvalProofRaw
}
Steps []struct {
Evals [][]uint64
MerkleProof struct {
Siblings []string
}
}
}
FinalPoly struct{ Coeffs [][]uint64 }
PowWitness uint64
}(raw.Proof.OpeningProof))
proofWithPis.PublicInputs = gl.Uint64ArrayToVariableArray(raw.PublicInputs)
return proofWithPis
}
// TODO: this seemed unused?
// func DeserializeProofChallenges(path string) variables.ProofChallenges {
// jsonFile, err := os.Open(path)
// if err != nil {
// panic(err)
// }
// defer jsonFile.Close()
// rawBytes, _ := io.ReadAll(jsonFile)
// var raw ProofChallengesRaw
// err = json.Unmarshal(rawBytes, &raw)
// if err != nil {
// panic(err)
// }
// var proofChallenges variables.ProofChallenges
// proofChallenges.PlonkBetas = gl.Uint64ArrayToVariableArray(raw.PlonkBetas)
// proofChallenges.PlonkGammas = gl.Uint64ArrayToVariableArray(raw.PlonkGammas)
// proofChallenges.PlonkAlphas = gl.Uint64ArrayToVariableArray(raw.PlonkAlphas)
// proofChallenges.PlonkZeta = gl.Uint64ArrayToQuadraticExtension(raw.PlonkZeta)
// proofChallenges.FriChallenges.FriAlpha = gl.Uint64ArrayToQuadraticExtension(raw.FriChallenges.FriAlpha)
// proofChallenges.FriChallenges.FriBetas = gl.Uint64ArrayToQuadraticExtensionArray(raw.FriChallenges.FriBetas)
// proofChallenges.FriChallenges.FriPowResponse = gl.NewVariable(raw.FriChallenges.FriPowResponse)
// proofChallenges.FriChallenges.FriQueryIndices = gl.Uint64ArrayToVariableArray(raw.FriChallenges.FriQueryIndices)
// return proofChallenges
// }
func ReductionArityBits(
arityBits uint64,
finalPolyBits uint64,
degreeBits uint64,
rateBits uint64,
capHeight uint64,
) []uint64 {
returnArr := make([]uint64, 0)
for degreeBits > finalPolyBits && degreeBits+rateBits-arityBits >= capHeight {
returnArr = append(returnArr, arityBits)
if degreeBits < arityBits {
panic("degreeBits < arityBits")
}
degreeBits -= arityBits
}
return returnArr
}
func DeserializeCommonCircuitData(path string) variables.CommonCircuitData {
jsonFile, err := os.Open(path)
if err != nil {
panic(err)
}
defer jsonFile.Close()
rawBytes, _ := io.ReadAll(jsonFile)
var raw CommonCircuitDataRaw
err = json.Unmarshal(rawBytes, &raw)
if err != nil {
panic(err)
}
var commonCircuitData variables.CommonCircuitData
commonCircuitData.Config.NumWires = raw.Config.NumWires
commonCircuitData.Config.NumRoutedWires = raw.Config.NumRoutedWires
commonCircuitData.Config.NumConstants = raw.Config.NumConstants
commonCircuitData.Config.UseBaseArithmeticGate = raw.Config.UseBaseArithmeticGate
commonCircuitData.Config.SecurityBits = raw.Config.SecurityBits
commonCircuitData.Config.NumChallenges = raw.Config.NumChallenges
commonCircuitData.Config.ZeroKnowledge = raw.Config.ZeroKnowledge
commonCircuitData.Config.MaxQuotientDegreeFactor = raw.Config.MaxQuotientDegreeFactor
commonCircuitData.Config.FriConfig.RateBits = raw.Config.FriConfig.RateBits
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.DegreeBits = raw.FriParams.DegreeBits
commonCircuitData.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
commonCircuitData.FriParams.ReductionArityBits = raw.FriParams.ReductionArityBits
commonCircuitData.Gates = []gates.Gate{}
for _, gate := range raw.Gates {
commonCircuitData.Gates = append(commonCircuitData.Gates, gates.GateInstanceFromId(gate))
}
selectorGroupStart := []uint64{}
selectorGroupEnd := []uint64{}
for _, group := range raw.SelectorsInfo.Groups {
selectorGroupStart = append(selectorGroupStart, group.Start)
selectorGroupEnd = append(selectorGroupEnd, group.End)
}
commonCircuitData.SelectorsInfo = *gates.NewSelectorsInfo(
raw.SelectorsInfo.SelectorIndices,
selectorGroupStart,
selectorGroupEnd,
)
commonCircuitData.QuotientDegreeFactor = raw.QuotientDegreeFactor
commonCircuitData.NumGateConstraints = raw.NumGateConstraints
commonCircuitData.NumConstants = raw.NumConstants
commonCircuitData.NumPublicInputs = raw.NumPublicInputs
commonCircuitData.KIs = gl.Uint64ArrayToVariableArray(raw.KIs)
commonCircuitData.NumPartialProducts = raw.NumPartialProducts
return commonCircuitData
}
func DeserializeVerifierOnlyCircuitData(path string) variables.VerifierOnlyCircuitData {
jsonFile, err := os.Open(path)
if err != nil {
panic(err)
}
defer jsonFile.Close()
rawBytes, _ := io.ReadAll(jsonFile)
var raw VerifierOnlyCircuitDataRaw
err = json.Unmarshal(rawBytes, &raw)
if err != nil {
panic(err)
}
var verifierOnlyCircuitData variables.VerifierOnlyCircuitData
verifierOnlyCircuitData.ConstantSigmasCap = DeserializeMerkleCap(raw.ConstantsSigmasCap)
circuitDigestBigInt, _ := new(big.Int).SetString(raw.CircuitDigest, 10)
circuitDigestVar := frontend.Variable(circuitDigestBigInt)
verifierOnlyCircuitData.CircuitDigest = poseidon.BN254HashOut(circuitDigestVar)
return verifierOnlyCircuitData
}

+ 0
- 24
verifier/deserialize_test.go

@ -1,24 +0,0 @@
package verifier
import (
"fmt"
"testing"
)
func TestDeserializeProofWithPublicInputs(t *testing.T) {
proofWithPis := DeserializeProofWithPublicInputs("../data/decode_block/proof_with_public_inputs.json")
fmt.Printf("%+v\n", proofWithPis)
panic("look at stdout")
}
func TestDeserializeCommonCircuitData(t *testing.T) {
commonCircuitData := DeserializeCommonCircuitData("../data/decode_block/common_circuit_data.json")
fmt.Printf("%+v\n", commonCircuitData)
panic("look at stdout")
}
func TestDeserializeVerifierOnlyCircuitData(t *testing.T) {
verifierOnlyCircuitData := DeserializeVerifierOnlyCircuitData("../data/decode_block/verifier_only_circuit_data.json")
fmt.Printf("%+v\n", verifierOnlyCircuitData)
panic("look at stdout")
}

+ 24
- 0
verifier/util.go

@ -0,0 +1,24 @@
package verifier
import (
"github.com/consensys/gnark/frontend"
gl "github.com/succinctlabs/gnark-plonky2-verifier/goldilocks"
"github.com/succinctlabs/gnark-plonky2-verifier/types"
"github.com/succinctlabs/gnark-plonky2-verifier/variables"
)
type ExampleVerifierCircuit struct {
PublicInputs []gl.Variable `gnark:",public"`
Proof variables.Proof
VerifierOnlyCircuitData variables.VerifierOnlyCircuitData
// This is configuration for the circuit, it is a constant not a variable
CommonCircuitData types.CommonCircuitData
}
func (c *ExampleVerifierCircuit) Define(api frontend.API) error {
verifierChip := NewVerifierChip(api, c.CommonCircuitData)
verifierChip.Verify(c.Proof, c.PublicInputs, c.VerifierOnlyCircuitData)
return nil
}

+ 11
- 10
verifier/verifier.go

@ -7,6 +7,7 @@ import (
gl "github.com/succinctlabs/gnark-plonky2-verifier/goldilocks"
"github.com/succinctlabs/gnark-plonky2-verifier/plonk"
"github.com/succinctlabs/gnark-plonky2-verifier/poseidon"
"github.com/succinctlabs/gnark-plonky2-verifier/types"
"github.com/succinctlabs/gnark-plonky2-verifier/variables"
)
@ -17,11 +18,12 @@ type VerifierChip struct {
poseidonBN254Chip *poseidon.BN254Chip `gnark:"-"`
plonkChip *plonk.PlonkChip `gnark:"-"`
friChip *fri.Chip `gnark:"-"`
commonData types.CommonCircuitData `gnark:"-"`
}
func NewVerifierChip(api frontend.API, commonCircuitData variables.CommonCircuitData) *VerifierChip {
func NewVerifierChip(api frontend.API, commonCircuitData types.CommonCircuitData) *VerifierChip {
glChip := gl.New(api)
friChip := fri.NewChip(api, &commonCircuitData.FriParams)
friChip := fri.NewChip(api, &commonCircuitData, &commonCircuitData.FriParams)
plonkChip := plonk.NewPlonkChip(api, commonCircuitData)
poseidonGlChip := poseidon.NewGoldilocksChip(api)
poseidonBN254Chip := poseidon.NewBN254Chip(api)
@ -32,6 +34,7 @@ func NewVerifierChip(api frontend.API, commonCircuitData variables.CommonCircuit
poseidonBN254Chip: poseidonBN254Chip,
plonkChip: plonkChip,
friChip: friChip,
commonData: commonCircuitData,
}
}
@ -42,10 +45,9 @@ func (c *VerifierChip) GetPublicInputsHash(publicInputs []gl.Variable) poseidon.
func (c *VerifierChip) GetChallenges(
proof variables.Proof,
publicInputsHash poseidon.GoldilocksHashOut,
commonData variables.CommonCircuitData,
verifierData variables.VerifierOnlyCircuitData,
) variables.ProofChallenges {
config := commonData.Config
config := c.commonData.Config
numChallenges := config.NumChallenges
challenger := challenger.NewChip(c.api)
@ -63,7 +65,7 @@ func (c *VerifierChip) GetChallenges(
challenger.ObserveCap(proof.QuotientPolysCap)
plonkZeta := challenger.GetExtensionChallenge()
challenger.ObserveOpenings(fri.ToOpenings(proof.Openings))
challenger.ObserveOpenings(c.friChip.ToOpenings(proof.Openings))
return variables.ProofChallenges{
PlonkBetas: plonkBetas,
@ -74,7 +76,7 @@ func (c *VerifierChip) GetChallenges(
proof.OpeningProof.CommitPhaseMerkleCaps,
proof.OpeningProof.FinalPoly,
proof.OpeningProof.PowWitness,
commonData.DegreeBits,
c.commonData.DegreeBits,
config.FriConfig,
),
}
@ -141,13 +143,12 @@ func (c *VerifierChip) Verify(
proof variables.Proof,
publicInputs []gl.Variable,
verifierData variables.VerifierOnlyCircuitData,
commonData variables.CommonCircuitData,
) {
c.rangeCheckProof(proof)
// Generate the parts of the witness that is for the plonky2 proof input
publicInputsHash := c.GetPublicInputsHash(publicInputs)
proofChallenges := c.GetChallenges(proof, publicInputsHash, commonData, verifierData)
proofChallenges := c.GetChallenges(proof, publicInputsHash, verifierData)
c.plonkChip.Verify(proofChallenges, proof.Openings, publicInputsHash)
@ -159,8 +160,8 @@ func (c *VerifierChip) Verify(
}
c.friChip.VerifyFriProof(
fri.GetInstance(&commonData, c.glChip, proofChallenges.PlonkZeta, commonData.DegreeBits),
fri.ToOpenings(proof.Openings),
c.friChip.GetInstance(proofChallenges.PlonkZeta),
c.friChip.ToOpenings(proof.Openings),
&proofChallenges.FriChallenges,
initialMerkleCaps,
&proof.OpeningProof,

+ 16
- 97
verifier/verifier_test.go

@ -4,52 +4,34 @@ import (
"testing"
"github.com/consensys/gnark-crypto/ecc"
"github.com/consensys/gnark/backend"
"github.com/consensys/gnark/frontend"
"github.com/consensys/gnark/std/math/emulated"
"github.com/consensys/gnark/test"
gl "github.com/succinctlabs/gnark-plonky2-verifier/goldilocks"
"github.com/succinctlabs/gnark-plonky2-verifier/types"
"github.com/succinctlabs/gnark-plonky2-verifier/variables"
"github.com/succinctlabs/gnark-plonky2-verifier/verifier"
)
type TestVerifierCircuit struct {
Proof variables.Proof
PublicInputs []gl.Variable `gnark:",public"`
verifierChip *verifier.VerifierChip `gnark:"-"`
plonky2CircuitName string `gnark:"-"`
}
func (c *TestVerifierCircuit) Define(api frontend.API) error {
circuitDirname := "./data/" + c.plonky2CircuitName + "/"
commonCircuitData := verifier.DeserializeCommonCircuitData(circuitDirname + "common_circuit_data.json")
verifierOnlyCircuitData := verifier.DeserializeVerifierOnlyCircuitData(circuitDirname + "verifier_only_circuit_data.json")
c.verifierChip = verifier.NewVerifierChip(api, commonCircuitData)
c.verifierChip.Verify(c.Proof, c.PublicInputs, verifierOnlyCircuitData, commonCircuitData)
return nil
}
func TestStepVerifier(t *testing.T) {
assert := test.NewAssert(t)
testCase := func() {
plonky2Circuit := "step"
proofWithPis := verifier.DeserializeProofWithPublicInputs("./data/" + plonky2Circuit + "/proof_with_public_inputs.json")
circuit := TestVerifierCircuit{
plonky2CircuitName: plonky2Circuit,
Proof: proofWithPis.Proof,
PublicInputs: proofWithPis.PublicInputs,
commonCircuitData := types.DeserializeCommonCircuitData("../testdata/" + plonky2Circuit + "/common_circuit_data.json")
proofWithPis := variables.DeserializeProofWithPublicInputs(types.ReadProofWithPublicInputs("../testdata/" + plonky2Circuit + "/proof_with_public_inputs.json"))
verifierOnlyCircuitData := variables.DeserializeVerifierOnlyCircuitData(types.ReadVerifierOnlyCircuitData("../testdata/" + plonky2Circuit + "/verifier_only_circuit_data.json"))
circuit := verifier.ExampleVerifierCircuit{
Proof: proofWithPis.Proof,
PublicInputs: proofWithPis.PublicInputs,
VerifierOnlyCircuitData: verifierOnlyCircuitData,
CommonCircuitData: commonCircuitData,
}
proofWithPis2 := verifier.DeserializeProofWithPublicInputs("./data/" + plonky2Circuit + "/proof_with_public_inputs.json")
witness := TestVerifierCircuit{
plonky2CircuitName: plonky2Circuit,
Proof: proofWithPis2.Proof,
PublicInputs: proofWithPis2.PublicInputs,
witness := verifier.ExampleVerifierCircuit{
Proof: proofWithPis.Proof,
PublicInputs: proofWithPis.PublicInputs,
VerifierOnlyCircuitData: verifierOnlyCircuitData,
CommonCircuitData: commonCircuitData,
}
err := test.IsSolved(&circuit, &witness, ecc.BN254.ScalarField())
@ -57,66 +39,3 @@ func TestStepVerifier(t *testing.T) {
}
testCase()
}
func TestStepVerifier2(t *testing.T) {
assert := test.NewAssert(t)
plonky2Circuit := "step"
proofWithPis := verifier.DeserializeProofWithPublicInputs("./data/" + plonky2Circuit + "/proof_with_public_inputs.json")
circuit := TestVerifierCircuit{
plonky2CircuitName: plonky2Circuit,
Proof: proofWithPis.Proof,
PublicInputs: proofWithPis.PublicInputs,
}
proofWithPis2 := verifier.DeserializeProofWithPublicInputs("./data/" + plonky2Circuit + "/proof_with_public_inputs.json")
witness := TestVerifierCircuit{
plonky2CircuitName: plonky2Circuit,
Proof: proofWithPis2.Proof,
PublicInputs: proofWithPis2.PublicInputs,
}
assert.ProverSucceeded(
&circuit,
&witness,
test.WithBackends(backend.GROTH16),
test.WithCurves(ecc.BN254),
test.NoFuzzing(),
test.NoSerializationChecks(),
)
}
type testCircuit struct {
Arr [2]emulated.Element[emulated.Secp256k1Fp]
Expected emulated.Element[emulated.Secp256k1Fp]
}
func (circuit *testCircuit) Define(api frontend.API) error {
field, _ := emulated.NewField[emulated.Secp256k1Fp](api)
mulRes := field.Mul(&circuit.Arr[0], &circuit.Arr[1])
field.AssertIsEqual(mulRes, &circuit.Expected)
return nil
}
func TestMain(t *testing.T) {
assert := test.NewAssert(t)
var circuit testCircuit
assert.ProverSucceeded(
&circuit,
&testCircuit{
Arr: [2]emulated.Element[emulated.Secp256k1Fp]{
emulated.ValueOf[emulated.Secp256k1Fp](42),
emulated.ValueOf[emulated.Secp256k1Fp](24),
},
Expected: emulated.ValueOf[emulated.Secp256k1Fp](1008),
},
test.WithBackends(backend.GROTH16),
test.WithCurves(ecc.BN254),
test.NoFuzzing(),
test.NoSerializationChecks(),
)
}

Loading…
Cancel
Save