Skip to content

perf: GKR Levels#1735

Draft
Tabaie wants to merge 295 commits intomasterfrom
perf/gkr/levels
Draft

perf: GKR Levels#1735
Tabaie wants to merge 295 commits intomasterfrom
perf/gkr/levels

Conversation

@Tabaie
Copy link
Contributor

@Tabaie Tabaie commented Mar 16, 2026

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 on in_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.

Tabaie added 30 commits June 9, 2025 17:49
@Tabaie Tabaie requested a review from Copilot March 16, 2026 22:10
@Tabaie Tabaie changed the title GKR Levels perf: GKR Levels Mar 16, 2026
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.Compile skips all validation for input wires (IsInput()), so an input wire with a non-nil Gate (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 have Gate == nil (and possibly Exported semantics as expected) and return an error otherwise.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +361 to 377
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)
}
}

}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot apply changes based on this feedback
Compute every time

Comment on lines +76 to +85
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
}

Comment on lines +94 to +109
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),
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The entropy loss does indeed happen but I believe we generally consider it acceptable.

Copy link

Copilot AI commented Mar 16, 2026

@Tabaie I've opened a new pull request, #1736, to work on those changes. Once the pull request is ready, I'll request review from you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

perf: Skip Zero-Check on linear gates with only one claim perf: GKR layers

3 participants