Conversation
There was a problem hiding this comment.
Pull request overview
This PR adds a proving-schedule (“GKR levels”) abstraction to batch independent gates (and introduce “skip” levels for degree-1 gates), reducing proof size and Fiat–Shamir hashing, and it extends Fiat–Shamir bootstrapping to bind the circuit + schedule into the initial challenges.
Changes:
- Introduces
constraint.GkrProvingSchedule/GkrSumcheckLevel/GkrSkipLevel, plus default schedule generation and deterministic serialization for hashing. - Refactors GKR proving/verifying paths (including curve-specific blueprints) to consume an explicit schedule and a running-hash Fiat–Shamir transcript model.
- Updates tests and test vectors (including Poseidon2-like test circuits) to validate the new schedule/level behavior and updated proof encoding.
Reviewed changes
Copilot reviewed 62 out of 63 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| std/permutation/gkr-mimc/gkr-mimc.go | Removes implicit hash registration import. |
| std/hash/poseidon2/gkr-poseidon2/gkr-poseidon2.go | Removes implicit hash registration import. |
| std/gkrapi/api.go | Switches API circuit representation to gkrcore.RawCircuit. |
| std/gkrapi/compile.go | Adds schedule computation + statement hash binding; updates verification to use schedule/hasher directly. |
| std/gkrapi/api_test.go | Adds a Poseidon2-like gadget circuit test for new scheduling/batching. |
| internal/utils/slices.go | Removes unused References helper. |
| internal/gkr/test_vectors/two_inputs_select-input-3_gate_two_instances.json | Updates expected proof layout for new levels/schedule semantics. |
| internal/gkr/test_vectors/two_identity_gates_composed_single_input_two_instances.json | Updates expected proof layout for new levels/schedule semantics. |
| internal/gkr/test_vectors/single_mul_gate_two_instances.json | Updates expected proof layout for new levels/schedule semantics. |
| internal/gkr/test_vectors/single_mimc_gate_two_instances.json | Updates expected proof layout for new levels/schedule semantics. |
| internal/gkr/test_vectors/single_mimc_gate_four_instances.json | Updates expected proof layout for new levels/schedule semantics. |
| internal/gkr/test_vectors/single_input_two_outs_two_instances.json | Updates expected proof layout for new levels/schedule semantics. |
| internal/gkr/test_vectors/single_input_two_identity_gates_two_instances.json | Updates expected proof layout for new levels/schedule semantics. |
| internal/gkr/test_vectors/single_identity_gate_two_instances.json | Updates expected proof layout for new levels/schedule semantics. |
| internal/gkr/test_vectors/generate.go | Refactors test vector generation task list. |
| internal/gkr/sumcheck.go | Replaces fiat-shamir transcript usage with running hash.FieldHasher transcript. |
| internal/gkr/small_rational/test_vector_gen.go | Plumbs schedule + updated transcript model into small-rational vectors. |
| internal/gkr/small_rational/sumcheck_test_vector_gen.go | Updates sumcheck vector gen to new transcript + APIs. |
| internal/gkr/small_rational/sumcheck_test.go | Updates tests to new transcript + APIs. |
| internal/gkr/small_rational/sumcheck.go | Replaces fiat-shamir transcript with running-hash transcript; removes folding-coeff path. |
| internal/gkr/gkrtesting/gkrtesting.go | Adds schedule JSON support + Poseidon2 test circuit builder + shared log-instances helper. |
| internal/gkr/gkrcore/types.go | Renames package and introduces RawCircuit/RawWire + new compile path. |
| internal/gkr/gkrcore/gate.go | Renames package; adds IdentityBytecode. |
| internal/gkr/gkrcore/gate_test.go | Package rename for tests. |
| internal/gkr/gkrcore/serialize.go | New: deterministic serialization of circuit + schedule (for hashing/binding). |
| internal/gkr/gkrcore/schedule.go | New: default proving schedule builder with batching + skip levels. |
| internal/gkr/gkrcore/schedule_test.go | New: tests for default schedule (incl. Poseidon2 layout). |
| internal/gkr/gkr_test.go | Updates deserialization/verify paths to include schedule; updates logNbInstances calc signature. |
| internal/gkr/bn254/sumcheck.go | Updates transcript model; sumcheck API now takes claimedSum/degree + transcript. |
| internal/gkr/bn254/sumcheck_test.go | Updates tests for new transcript/sumcheck APIs. |
| internal/gkr/bn254/gkr_test.go | Adds schedule-aware tests for sumcheck/skip levels and explicit schedules. |
| internal/gkr/bn254/blueprint.go | Plumbs schedule and new transcript seeding into blueprint proving; proof size uses schedule. |
| internal/gkr/bls12-377/sumcheck.go | Same transcript/sumcheck API updates. |
| internal/gkr/bls12-377/sumcheck_test.go | Same test updates. |
| internal/gkr/bls12-377/blueprint.go | Plumbs schedule and new transcript seeding into blueprint proving; proof size uses schedule. |
| internal/gkr/bls12-381/sumcheck.go | Same transcript/sumcheck API updates. |
| internal/gkr/bls12-381/sumcheck_test.go | Same test updates. |
| internal/gkr/bls12-381/gkr_test.go | Adds schedule-aware tests for sumcheck/skip levels and explicit schedules. |
| internal/gkr/bls12-381/blueprint.go | Plumbs schedule and new transcript seeding into blueprint proving; proof size uses schedule. |
| internal/gkr/bw6-761/sumcheck.go | Same transcript/sumcheck API updates. |
| internal/gkr/bw6-761/sumcheck_test.go | Same test updates. |
| internal/gkr/bw6-761/gkr_test.go | Adds schedule-aware tests for sumcheck/skip levels and explicit schedules. |
| internal/gkr/bw6-761/blueprint.go | Plumbs schedule and new transcript seeding into blueprint proving; proof size uses schedule. |
| internal/generator/backend/template/gkr/sumcheck.go.tmpl | Updates generated sumcheck to new transcript model + APIs. |
| internal/generator/backend/template/gkr/sumcheck.test.go.tmpl | Updates generated tests for new transcript model + APIs. |
| internal/generator/backend/template/gkr/sumcheck.test.defs.go.tmpl | Updates generated test claim structs for new sumcheck interfaces. |
| internal/generator/backend/template/gkr/sumcheck.test.vectors.gen.go.tmpl | Updates generated vector code for new transcript model + APIs. |
| internal/generator/backend/template/gkr/gkr.test.go.tmpl | Updates generated GKR tests for schedules + new Prove/Verify signatures. |
| internal/generator/backend/template/gkr/gkr.test.vectors.go.tmpl | Updates generated vector loader to parse schedule and compute outputs via Outputs(). |
| internal/generator/backend/template/gkr/gkr.test.vectors.gen.go.tmpl | Updates generated vector generator to include schedule + new Prove/Verify signatures. |
| internal/generator/backend/template/gkr/blueprint.go.tmpl | Updates generated blueprints for schedule + transcript seeding changes. |
| constraint/solver/gkrgates/registry.go | Switches compilation dependency to gkrcore. |
| constraint/marshal.go | Registers CBOR tags for schedule level types. |
| constraint/gkr.go | New: schedule/level/claim-source data model + transcript binding helper. |
Comments suppressed due to low confidence (1)
internal/gkr/gkrcore/types.go:218
RawCircuit.Compileskips all validation for input wires (IsInput()), so an input wire with a non-nilGate(or other unexpected metadata) would be silently accepted and the gate ignored. This can mask circuit-construction bugs and make the circuit hash/schedule binding surprising. It would be safer to enforce that input wires haveGate == nil(and possiblyExportedsemantics as expected) and return an error otherwise.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| var testManyInstancesLogMaxInstances = -1 | ||
|
|
||
| func GetLogMaxInstances(t *testing.T) int { | ||
| if testManyInstancesLogMaxInstances == -1 { | ||
|
|
||
| s := os.Getenv("GKR_LOG_INSTANCES") | ||
| if s == "" { | ||
| testManyInstancesLogMaxInstances = 5 | ||
| } else { | ||
| var err error | ||
| testManyInstancesLogMaxInstances, err = strconv.Atoi(s) | ||
| if err != nil { | ||
| t.Error(err) | ||
| } | ||
| } | ||
|
|
||
| } |
There was a problem hiding this comment.
@copilot apply changes based on this feedback
Compute every time
| func SerializeCircuit(w io.Writer, c SerializableCircuit) error { | ||
| if len(c) >= 1<<32 { | ||
| return fmt.Errorf("circuit length too large: %d", len(c)) | ||
| } | ||
|
|
||
| // Write the number of wires | ||
| if err := writeUint16(w, len(c)); err != nil { | ||
| return err | ||
| } | ||
|
|
| hsh := sha256.New() | ||
| if err = gkrcore.SerializeCircuit(hsh, serializableCircuit); err != nil { | ||
| return nil, fmt.Errorf("failed to serialize circuit: %w", err) | ||
| } | ||
| if err = gkrcore.SerializeSchedule(hsh, schedule); err != nil { | ||
| return nil, fmt.Errorf("failed to serialize schedule: %w", err) | ||
| } | ||
|
|
||
| res := Circuit{ | ||
| circuit: gadgetCircuit, | ||
| schedule: schedule, | ||
| assignments: make(gadget.WireAssignment, len(api.circuit)), | ||
| api: api.parentApi, | ||
| hashName: fiatshamirHashName, | ||
| statementHash: hsh.Sum(nil), | ||
| } |
There was a problem hiding this comment.
The entropy loss does indeed happen but I believe we generally consider it acceptable.
This PR introduces batched levels, whereby the Zero-Check protocol on groups of independent gates of the same degree can be batched together, thereby reducing the size of GKR proofs and saving Fiat-Shamir hashing costs.
The gains are most manifest where the number of instances are low. With 5000 gkr-poseidon2 permutations, the verifier cost goes from 3672233 constraints to 2919423 (a 26% improvement) and for 50,000 (ballpark for the Linea Data Availability circuit) it goes from 4962791 to 4044948 (a 23% improvement).
"Skip" levels are also introduced for degree-1 gates. For a gate of degree 1, an interpolation claim on
G(in_1(-), in_2(-), ..., in_n(-))can be directly translated to interpolation claims onin_1(-), ...,in_n(-)at almost no cost. This however means that if the skip level had multiple claims on it, the levels below will inherit all those claims rather than just one, as a sum-check level would have. Therefore the scheduler cautiously refrains from creating skip levels with more than one incoming claim.Furthermore, to enhance protocol soundness, now a hash of the circuit and proving schedule (level structure) is also added to the initial proof challenges.