Repository navigation
Check transcript binding of recursion circuits (stacked on #595) - #629
Draft
kevaundray wants to merge 148 commits into
Draft
kevaundray wants to merge 148 commits into
kevaundray wants to merge 148 commits into
Conversation
…an-circuits-shift-20261010
…' into kw/clean-hashrec-20261010
…ash circuit from it The Hash class's gate list is now flock::clean::blake2s, generated from the Clean circuit LeanVMCircuits.Blake2s.Compress. Compress.soundness proves every satisfying witness outputs RFC 7693's F for the two legal finalization words, Rfc7693.abc checks the specification against the RFC's test vector in the kernel, and Compress.lowered proves the exact lowered artifact, whose additions are proven calls of the exported 32- and 31-bit adders. The hand-written G loop is removed; the word witness and its pin to the gate walk are unchanged, as are the product slots.
… for the prover K is (ZMod 2)[X]/(x^64+x^4+x^3+x+1) with Rec.modulus_irreducible checked in the kernel from carry-less certificates, a Clean FiniteField whose value is the machine's coefficient word; E is K[y]/(y^3+y+1) with its limb formulas. Every slot of EMUL, EXK, HASH, SPLIT and CAST is Form data with its theorem (emul_spec, exk_spec, hash_mux, split_spec), the HASH and SPLIT identities a Clean assertion, and GenerateRec.lean prints them as rec/clean.rs, which Table::slot and Table::identities now read instead of the hand-written forms.
Rec.Rows proves, from the table theorems and the bus equalities a pattern holds its slots to: an EMUL row held to one makes its factor the unique inverse, add sums, a SPLIT row with zeroed high bits packs a number below 2^n, the CAST views, a hash row's challenge words, and a Merkle node's placement of its child by a Boolean bit.
…to the proven ones Rec.hash_row_compress proves a hash row's output columns are RFC 7693's compression of its input columns when its packed witness satisfies the exported BLAKE2s artifact and its ports are its columns' words. Tests check that inv, pack and node emit the row shapes Rec.inverse_row, Rec.pack_row, Rec.node_row and Rec.hash_row_compress assume.
…tement digest in rows against RFC 7693 Rec.Merkle: hash rows chained output to chaining value output BLAKE2s-256 of their message columns; node rows up a path output the Merkle root of the leaf and their bits and siblings; parent rows over a subtree's levels output its root. Rec.Statement: Builder::chain's rows output the hash of a word message, and a tree statement's digest rows the hash of its header and items. Drop the row-shape tests, which only restated the builder's wiring.
… row theorems use
Rec.Duplex models fiat_shamir::Duplex on whole words and rec::transcript::Transcript's rows, and proves the rows reach the native state and sample the native challenges (run_rows), with the seed, commitment and proof-of-work check in rows (seed_row, commit_rows, pow_rows).
checkdesign checks a circuit's first exposure, at statement position zero, is of the constant of its own kind Shape.code (its e_const, or the builder's cached zero or one for those codes). Model.kindConst_ev and Model.kind_exposed: in every satisfying assignment that statement word is the code, so a child satisfied at the words its parent's verifier reads has its own code as the kind word the parent's kind rows bind.
WHIR's batch rounds read rows the Merkle paths bind through the query positions, squeezed from the same chaining value as the batching challenge. The certificate now names the challenge's own squeezed words and binds a batch round's atoms with the other words of that chaining value as seeds at the challenge's time, so every WHIR sumcheck is certified from the opening's first claim; WhirAnswers asks answers to agree on those words. The table sumcheck's input claim reads hinted fixed-column evaluations. The certificate names them and binds the claim with their limbs as seeds; sumcheck_test_sound counts the challenge vectors at which the hints are their true values, through Sumcheck.sumcheck_sound_on, and SumcheckAnswers no longer assumes the claim is the same in every answer. checkbind fails a dump whose WHIR sumcheck is not certified from its first claim or whose hint is no claim the reduction takes.
tree_sound_certs_off takes hrec only off an event badRec per child, as a verifier's soundness holds, and tree_sound_certs_frac bounds the outcomes at which some node's statement or input claims fail by the sum of the nodes' bad and badRec fractions. sat_tree_at and hedge_at are sat_tree and hedge_of_certs at one outcome.
…oracle model A Run is an assignment at each oracle, the answers at its transcript's squeezes' output words: in the random-oracle view, its squeezes' outputs the oracle's answers, and what its first k blocks absorb a function of the answers drawn by k. The verdict now checks that every certified check's challenges are drawn in order from the oracle's words (Cert.chalsOk: each word a challenge seed one step after its challenge's time and at no other time, its place one of its digest's four, no word shared, times not decreasing and increasing for WHIR), and checkbind reports a failure. oracleAt puts a challenge vector's coordinates in place of the challenges' words; at any oracle the run's assignments at oracleAt are SumcheckAnswers, OddAnswers, TopAnswers and WhirAnswers on every accepted circuit. The substitution is a lens, so each round theorem becomes a fraction of the uniform oracles (sumcheck_run_sound, odd_run_sound, top_run_sound, whir_run_sound). Proof of work's oracle is the trial compression's answer: pow_sem and pow_test_sound now ask every replayed call but that compression (FactsBut), and pow_run_sound bounds a run whose trials are answered by uniform oracle words. RomExample.run_exists gives a run meeting every premise but acceptance; chalsOk_mutations shows the check rejecting a shared word, a late challenge, challenges out of order and a word past its digest's four.
…ks, PCS, collisions and the AIR link RecParts splits hrec: the parent's circuit holds a verifier of each child, certified checks reducing input claims to output claims. Where the parent's circuit is satisfied (which hrec now receives, as sat_tree_at's induction has it), a check lets a false input through with true outputs only on its event, and each check's outputs are later checks' inputs or openings of the child's committed witness, true off the PCS event (leanEthereum#551). RecParts.ins_ok: off those events every check's inputs are true; RecParts.least_ok: the least such events satisfy the premises for any claims. RecParts.hrec gives hrec off the checks' events, the PCS event and the collision event from the AIR link, the premise left: a child's AIR claims true on its committed witness give its circuit satisfied at the statement its parent's verifier reads. tree_sound_parts bounds the tree's failures by the sum of those fractions. A sumcheck is such a check: sumcheck_claim_agree (the input claim is bound before the first challenge with the hints as seeds) gives sumcheck_run_sound_at, which drops the premise that the input claim is false and bounds the oracles at which the test passes with a false input and true outputs (sumcheckFalse); sumcheck_part reads it as a check's event. The run's answer theorems take their instance premises at the vectors put in at one oracle.
…ut premise whir_run_sound_at, odd_run_sound_at and top_run_sound_at drop the premise that the input claim or some input value is false at every vector put in: the input is bound before the check's first challenge, so it is one value over those vectors (card_at with bound_agree), and the oracles at which the test passes with a false input and true outputs (whirFalse, oddFalse, topFalse) are within the round theorem's fraction. whir_part, odd_part and top_part read them as RecParts checks, as sumcheck_part does.
… an event and reduce the AIR link The design summaries now hold, per shape, the claims `Design::carried` takes from a statement of labeled words, the statement `Reduced::statement` exposes for labeled reduction outputs, each tier's `Design::fixed_claim` on labeled hints at zero and at differing heights, the edge layout, and once the scalars `bind_state` binds; `checkdesign` compares each with `Rec/DesignClaims.lean` on all 600 shapes, with kernel-checked mutations for every rule, and computes each fixed stack's variables instead of reading them. DesignClaims proves the exposed statement's claims are the reduction's outputs, the fixed stack's placement, that a fresh fixed term reads the child's own column, and the bound state and digest round trips. `Rec/Collision.lean` bounds an adaptive prover's compression collisions and near window collisions under a uniform oracle and derives `HashCRP`, `WindowCRP` and `RomAnswers` from them; `crEvent` bounds `crBad`, and `PcsBound` states leanEthereum#551's bound as the interface for `pcsBad`. `Rec/AirLink.lean` proves the AIR's row, public and bus claims on a committed witness give `Model.Sat`, the bus from its GKR products off a bounded draw event, leaving `ChecksGiveRows`; `Rec/TreeBound.lean` combines the bounds.
`DesignClaims.digestRows` is `Kind::digest_rows` as a builder program, and `digestRows_good` proves it computes the tree statement digest of its tag and items in every satisfying assignment; the summaries now hold Rust's node digest of labeled children's digests for every tree of outputs, which `checkdesign` compares with the model's own BLAKE2s (`nodeDigestOk`). `nodeScale_small` and `nodeScale_two` prove a child's scale is zero exactly at the first level and one at every node, for the small tier's and the two-kind tree's modes.
`Rec/AirBatch.lean` models the constraint batch as `TableArgument::verify` and `constraints::verify` check it at the bus's point and a challenge, and bounds by Schwartz-Zippel the draws at which a witness breaking an identity still passes; the AIR link's remaining premise becomes `ChecksGiveBatch`, and `tree_sound_batch` and `tree_sound_ideal_batch` instantiate the batch's bound. `DesignClaims.tierMode_scale` proves a child's scale in its tier's mode is zero exactly at the first level, and `checkedges` now checks each dump's children are scaled in their tier's mode.
Rec/DigestEdges.lean names the calls by which a wrap states its child's digest and a node of a tree of outputs its children's tree digest, exposed at statement positions 1 and 2 (DigestCert), proves them sound where every call holds (DigestCert.exposed, wrap_states, node_states) and checks mutations in the kernel (wrap_mutations, node_mutations). checkedges finds and checks the certificate for every wrap and output node among the dumps.
…he AIR's challenges from a run and match leanEthereum#551's bound to pcsBad Run.lean: the run theorems take the honest instance, hints and true children as functions of the oracle fixed before the check's challenges (CommittedBefore, Run.committed_at, Run.sumcheck_committed and the like, draws_not_fixed). AirRun.lean: the bus's and the constraint batch's draws as a run's challenges after the commitment, the prover adaptive (busRun_frac, batchRun_frac), and tree_sound_run with no lens premise. PcsMatch.lean: leanEthereum#551's current_knowledge conclusion in its own form with a fiber-uniform map to its outcomes and pcsBad inside its event gives PcsBound (Pcs551.frac, pcsBound_of_551), and compress_fiber discharges the fiber premise for the ideal compression model read through an injective node encoding.
…lision term stands DesignKind.kindRows_good now gives is_node zero at the first level and one at every node (prod_zero_or_one). CrScale.lean: run_frac_off charges a collision event once per execution, and epsCR_deployed shows one execution's epsCR below 2^-7 at 2^60 compression queries and at least one at 2^64. The README states that the capstone bound is vacuous until the collision premise is narrowed to collision-free answers sharing the pre-challenge prefix.
…ords The round theorems asked every two answers of a run's family not to collide, which only a query count covering all their executions gave, so the tree bound was vacuous. Collision resistance is now asked only between answers sharing the prefix before a check's challenge, on the rows that prefix binds: rule validity only for the rules a derivation fires (closure_agree_on), collision and window rules reading only rows live on the fired nodes (RowLive, HashCRP and WindowCRP on live rows, PairCR on a seed list), the answers good off the run's collision event (Run.cr, Run.cr_at), and the four run theorems bound their events off that event (offC), run_frac_off charging it once. Run.cr_of_prefix and Run.cr_of_queries derive Run.cr from a prover whose queries before a squeeze are shared by the executions agreeing by then and include the rows the prefix binds, the collision event being one execution's. tree_sound_exec restates the tree's bound over the transcripts' oracle and the compression oracle with epsCR of one execution's queries per child. The window rule now takes the two output blocks' other input words (counter, finalization, message, constants in an output block) as premises, so two windows of distinct chaining values agreeing are a four-word event: Collision.win_frac bounds it by 2Q(Q-1)(Q-2)/|K|^4 in place of the two-word near hit 3Q(Q-1)/(2|K|^2). With card_E (|E| = 2^192), exec_bound_deployed: per child the checks', bus's and batch's bounds up to 2^40/|E| plus epsCR K Q are below 2^-1 for Q up to 2^84, 2^-7 up to 2^82, 2^-32 up to 2^74 and 2^-64 up to 2^63; epsCR_cap: at 2^86 the window term is past one. RecParts.Ok.test now holds off crBad.
…-to-end tree bound and reduce the AIR link to the honest instances A run's cr is now asked between two executions both off their execution's event, which every round theorem has. Run.cr_of_extract derives it from a causal, normalized prover whose rows the prefix binds output words the prefix fixed: a row whose input is first queried after the squeeze is a collision when its output is an earlier answer and otherwise a late hit on a target (Collision.LateHit, at most Q B / |V|^4, Edges.lateEvent_frac), charged per execution beside epsCR in tree_sound_exec. A later query hitting a word the prefix fixed is a collision only when that word is an earlier answer. AirLink.tree_sound_end takes the PCS term from leanEthereum#551 and states the tree's bound per child as D/|E| + leanEthereum#551's finalBound sum + epsCR + epsLate; Edges.tree_bound_deployed evaluates it (below 2^-19 for 2^10 nodes at leanEthereum#551 budgets 2^20, below 2^-7 at 2^32) and Edges.pcs_dominates shows leanEthereum#551's query term dominates. AirLink.ChecksGiveInst states the table sumcheck's input claim as the committed witness's honest sum and the bus GKR's roots as its honest products; checksGiveBatch_of_inst gives ChecksGiveBatch from it.
… composition A one-query example meets LateHit without Coll, so the straight-line extraction charges it beside the collision term; the README states the per-execution epsCR as the collision and window term plus epsLate.
…nce, name it on the dumps and drop normalization and causality from the prover model TableSum.lean: Sumcheck.mvInst is the honest instance of a polynomial on the Boolean cube with no eq weight factored out; AirLink.tableInst is the Rust table sumcheck's, each table active in its own variables and sitting out the rest at their corner, with its sum the batch's honest sum at the forms' honest sums (tableInst_sum, corner_sum), its degree, its final value at the verifier's folded weights (foldWeight_eq) and no eq weight in any round. The committed witness is taken at a layout (committedAt, LayoutFits), the public columns the verifier's, and ChecksGiveTable gives ChecksGiveInst and ChecksGiveRows (checksGiveInst_of_table, checksGiveRows_of_table). checkbind names each residual sumcheck as a table sumcheck (Bind.TableCert: rounds with no eq weight, input claim the mul_add of the bus totals at xi, a GKR first layer reading one root for both trees before it) and fails a dump where one is missing or fails its check; TableCert.sem, answers_weight and claim_iff read the named check's input claim, with mutation tests of TableCert.okIn. CrScale.lean: Run.cr_of_normal drops hnorm by normalizing the prover to query every hash row's input after its own queries, asking instead that its output is a function of its first Q answers and its rows are consistent with the oracle; Run.cr_of_staged drops hcaus for a staged prover (Staged, stageN, hcaus_of_staged); cr_of_extract asks causality only along the prover's own answers.
…f its leaves GkrInst.lean: Sumcheck.eqInst is the honest instance of an eq-weighted sum with each round's eq weight factored out (eqInst_sum, eqInst_ok, eqInst_final, eqInst_weight). A product tree's levels (level_two, level_four, level_root) make the bus's honest roots its trees' roots (pullRoot_eq_level, pushRoot_eq_level). AirLink.layerInst is gkr::verify_products' radix-four layer's honest instance: its sum the claim at the honest level values, degree 4, round i weighted by the point's coordinate, its final value the children's honest products at lambda; next_claim and odd_next carry the honest values to the next layer's point.
…totals checkbind names each table sumcheck's bus GKR (Bind.GkrCert): its first layer reading the root for both trees, its radix-four layers past the top as certified sumchecks linked to the previous layer's next claims and point (Bind.LayerCert, LayerCert.chain), and the totals as the add of a framework share and the last layer's next claims; a dump where one is missing or fails GkrCert.ok is rejected. GkrCert.sem, LayerCert.link_sem and LayerCert.chain_cons read a passing certificate, with mutation tests of GkrCert.okIn and LayerCert.linkOk.
On a node verifying several children the latest first layer before a table sumcheck can be a later child's; checkbind now names as the table's root the first layer from which the GKR's layers reach the table's totals, so every table sumcheck's bus GKR is named.
LayerCert.layer_sem: where the calls hold, a linked layer's sumcheck has no residual and its eq weights are the previous point, its input claim is the previous next claims combined at lambda, its final side the children's products at lambda, and its next claims the lines through its children.
…to kw/clean-rec-soundness The builder's mark moves to rec/circuit.rs, the claims' edge lines to tree/reduce, and the union's marks onto PoolShape::rows and PoolWires::product; the design summaries test and the bus plan test take the new APIs; the docs name bus::verify_balance, Design::kind_bits, PoolShape::rows and RoundQuad.
…enteen dumps The round reader is the verifier's read_round, WHIR's quadratic RoundQuad, the flock circuits CircuitId, the hash rows' batch RecWitness::build; the dumps add the leanXMSS-100 2 to 1 tree over zero-knowledge leaves, whose node names its table sumchecks and bus GKRs as the others do.
…e Tree::converge built LeanVMCircuits.Rec.Heights: every circuit converge returns, its heights holding its rows, fits its tier's layout (layoutFits_converge, via Design.converge_fits), and every owned table's tau is at most the rounds constraints::verify runs (taus_le_rounds); checksGiveRows_of_converge is checksGiveRows_of_table with both hypotheses replaced by the tree's building facts. tableInst_sum asks tau <= n of the owned tables only, the public table being in no summand.
LeanVMCircuits.Rec.Named: checksGiveTable_of_named gives ChecksGiveTable, with the totals, the root and xi the named wires' values, from parts whose named table sumcheck's input is its honest instance's sum on the committed witness, whose bus GKR first layer's input is the named root being both trees' honest roots, and whose flock check's input is the hash rows' packed witnesses; the parent's satisfied circuit gives the certificate's facts and TableCert.claim_iff reads the named input claim. named_inputs: such parts meet the hypotheses.
…ights and make GKR layers RecParts checks Rec/Tries.lean: an outcome is an oracle per try with the compression oracle shared; an event at most an ε fraction of try i's oracle at every value of the other tries' oracles is at most ε of all outcomes (Bind.frac_fix_le), so whichever try the prover outputs fails on at most the sum of the tries' bounds (frac_pick_le, frac_pick_le_mul), and Edges.tries_bound_deployed folds it into the end-to-end bound: m / 2^7 at leanEthereum#551 budgets 2^32, m / 2^19 at 2^20. Rec/Heights.lean: Circuit::heights transcribed from Table::height_log (circuitHeights), proven to hold the rows (heightsHold_circuit), so checksGiveRows_of_tree drops HeightsHold. Rust tests compare height_log with the transcription and check, on a tree of one tier and one of two, that each circuit Tree::converge returns sits at its tier's heights holding its rows. Rec/GkrParts.lean: a radix-four GKR layer past the top meets RecParts.Ok.test off its sumcheck's event, a line event (at most 2|S| pairs) and a λ event (at most one λ) (Bind.layer_part, lineBad_card, lamBad_card).
checkbind asks each radix-four layer past the top to draw λ, low and high in order from its transcript, its children bound by low's time (LayerCert.boundOk) and its values by λ's time with the words squeezed with λ but its own as seeds (LayerCert.lamOk, firings named per layer as WHIR's batch rounds do). layer_run_sound_at bounds the λ and line events together by 3/|E| of the oracles off the run's collision event: the values are fixed across λ at each (low, high) (Run.sib_agree), the children across (low, high) at each λ. Mutation tests for both rules; all 17 dumps pass.
…al value at the column claims Bind.ResidCert names each of the five residual terms: the weight's calls from a one through each round's times_one_plus or mul (foldWeight at the named point and the rounds' challenges), the column claims, the push and pull forms at them (BusForm::at), their mul_add at ξ, and the table's identities in allIds' order (BusForm::at_constants with the model's words) at the powers TableResidual::batch makes. ResidCert.sem gives the residual terms as Σ_T foldWeight · summandAt at the named forms and claims; ResidCert.final_eq gives tableInst_final at the committed witness's heights, forms and columns' extensions at chi r. checkbind names one for every table sumcheck on all 17 dumps; mutation tests reject a weight with another τ, an identity with another word or table, identities out of order, a form reading another column and a wrong power of ξ.
…ms, framework shares and totals Rec/BusDecompose.lean: a side's leaf claim over blocks at their offsets is Σ_b sel_b Σ_z eq(ζ[..κ_b], z) leaf_b(z) plus the padding mass (leaf_decompose); a table block's leaf over its coordinates is its BusForm::accumulate form plus its virtual coordinates (blockQuad, blockKnown, block_sum); side_decompose gives the leaf claim as the framework part plus each table's form summed over its rows; totals_eq_formSums gives the derived totals framework + Ṽ(ζ) as formSums in characteristic two; tableClaim_of_leaves gives ChecksGiveTable's table conjunct from true leaf claims with no row breaking an identity.
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked on #595 (based on its head 793fbc1, which merges upstream riscv-exploration at dfb7570, #630: flock's reductions before the bus), with upstream riscv-exploration d0b0f82 (#631) merged in.
Adds
lake exe checkbind, a transcript binding check over the recursion builder dumps thatcheckrecalready replays, with a kernel-checked verdict, and proves the claim union's coverage check sound on the circuit. Also addslake exe checkdesign(a model ofrec::tree::designfor every tree shape, compared with Rust, now including the claims a node takes, exposes and binds) andlake exe checkedges(the tree's edges from the dumps), makes collision resistance an event of the ideal compression model, and reduces the AIR link to the checks' claims on the committed witness.Correction
As first stated in this PR,
sumcheck_test_soundandodd_test_soundwere vacuous. Their answersval rhad to hold every constraint, each squeeze's compression included (Holds), and to agree on what is absorbed before roundiwhenever their challenges beforeiagreed; the round's challenge is the compression of what was absorbed, so it agreed too, forcingr i = r' i, and no answers existed onceEhas two elements. They are now stated in the random-oracle view: each transcript seeds its challenges one step after the block they read (chalSeeds), each transcript carries a second rule set reading none of its own absorb blocks' or squeezes' rows (Transcript.rulesRO,dropOf,Cert.marksRO) which the round certificates bind with, and the answers areRomAnswers c s T(every constraint and replayed call but the tests and transcriptT's own rows,HoldsP/Facts; collision resistance away from them).RomExample.sumcheck_answers_exist,odd_answers_existandpow_answers_existexhibit answers meeting every premise but acceptance, at every challenge vector, on a circuit whose challenges are squeezes of its transcript's blocks.pow_test_soundnow reads the trial digest's first word as the oracle's answer. The tests' binding (tests_by,tests_determined, the union theorems) keeps the full rule set:checkbind's verdict and every test's binding time are unchanged on all 17 dumps and the fixture.The check
Bind.Just) naming a row, an equality or a public row: a slot limb is its table's form of the columns it reads, SPLIT word and bits give each other, a constant mux bit picks a message word, a compression at a constant final word gives its output,inv's product gives each factor from the other, equalities that are not tests hold both ways, collision resistance gives a compression's inputs from its output and a chaining value from four consecutive output-stream words, and a union product is a function of its pool's digests, begin and selection bits and its point.eq_e/eq_k/eq_e_const/eq_k_constwhose wires depend, through the calls that make wires, on a squeeze. Every test must be bound by one transcript.union.rsmarks each pool and product in the trace (Builder::mark, tracing only). The certificate names, call for call, where each pool, product and point is.Kernel-checked
Bind.Cert.acceptsis the verdict: every rule's justification checks against the circuit, each transcript is a chain of compressions from a constant, the unions' calls are where the certificate says, every field equality reading a challenge is a test, some transcript's replay of the recorded firings gives every test's limbs a binding time, each union's coverage entry holds, each named sumcheck's rounds, proof-of-work check, GKR odd layer, GKR radix-four top layer, claim split and WHIR sumcheck are where the certificate says (Cert.sumchecksOk,PowCert.ok,Cert.oddsOk,Cert.lateOk), and their challenges are drawn in order from the oracle's words (Cert.chalsOk). Premises are named where used:HashCR(two hash rows given the same output ports, one by each assignment, are given the same input ports) andWindowCR(an output window of one chaining value fixes it); the random-oracle rule set's validity needs them only away from the squeeze rows (HashCRP,WindowCRP).tests_by: each test's limbs, at their binding timek, are in the closure of what one transcript's firstkblocks absorb, and of the statement only oncekpasses its last block (certifyT_sound).checkbind_soundis its weaker form with the whole transcript.tests_determined(premisesHashCR,WindowCR): on two assignments holding every constraint but the tests (Holds, implied byModel.Sat) and agreeing on what a transcript's firstkblocks absorb (and the statement past its last block),kthe test's binding time, each test's wires agree. A test bound after its latest challenge (a round-by-round sumcheck check) is thus a function of the blocks before the next challenge.tests_cover: no field equality the circuit keeps as a constraint reads a wire the verified scan marks as reading a challenge (taintStep). The classification is not a premise of any theorem's soundness: each is stated for assignments satisfyingHolds, whichSat.holdsgives fromModel.Satwhatever the classification.unionsValid(premiseHashCR): each union product is a function of its digests, begin and selection bits and point. FromModel.replayR_sound(a replay with the tests' equalities relaxed builds the circuit without its tests, so every other call's contract holds underHolds),PoolParse.parse_unique(a run's chain followed back from its end to its start bit fixes its kind bits and blocks),PoolCert.pool_sem,PoolCert.pool_unique,prod_agree,claim_valid.union_cover(premiseHashCRbetween the assignments): if in one assignment holding every constraint but the tests the two pools' claims on are different multisets, the points(X, A)ofS^5at which some assignment with the same digests, begin and selection bits holds every constraint but the tests and the coverage test are at most a4N/|S|fraction. Frompoint_sem(the weights areeq(A, k)),prod_closed/prod_slotsAt(a product isUnionSound.slotsAtof its pool's slots, tuples(1, label, member)),slots_bits,slots_agree, andUnionSound.coverage_sound(Schwartz-Zippel;poly_injectiveislem:gpvia Clean'seq_of_fingerprintProduct_eq).union_sound(premisesHashCR,WindowCR, and the challenge uniform onS^5): the union's theorem on an accepted circuit. The certificate names each union's coverage test, its two products and its transcript (Bind.Cover);Cert.coversOkchecks the test's wires are the products' outputs at one point, every product has an entry, the transcript binds what both pools commit to (PoolCert.committed), the declared pool has one digest and does not select, and the children's pool's run one-hot closes at its last digest (PoolCert.endOk,union::PoolShape::rows's closingeq_e_constchecks). Fix what the transcript absorbs by an assignment in which the selected child claims and the declared claims differ; if at each outcome of the challenge the prover answers with an assignment holding every constraint but the tests and absorbing the same words, the outcomes at which its point is the challenge and the coverage test holds are at most a4N/|S|fraction.Rec/PoolClaims.lean, premisePoolClaims.ChainCR: no pool row's compression collides with the chain of a named set's blocks). A set's written form (ClaimSet.blocks,ClaimSet::items) and digest (ClaimSet.digest, underblakeF, the compression ablockrow computes).run_reads: a run whose expected digest is a set's reads that set's blocks item for item.reads_sum/readC_blocks: the pool's items read the sum of the claims of the sets its runs name.pool_claims: claims on are at most that sum, and that sum without selection.cur_runAt: the run one-hot of a chunk is at the number of begin bits set so far, so underendOkevery run is a distinct digest's.decl_claims: the declared pool's claims on are the declared set's;sel_claims: the children's pool's claims on are among the sum of the children's sets.union_sound_sets(viasets_differ):union_soundwith the premise that the declared set's claims are not among the children's.union_sound_queries,union_sound_sets_queries(Rec/Composition.lean): the union bound overQtranscripts a prover may try, each with its own uniform point, the prover answering with the one it picks: at most aQ · 4N/|S|fraction.Sumcheck.sumcheck_sound,Sumcheck.sumcheck_sound_frac(Rec/Sumcheck.lean): sumcheck's round-by-round soundness at the protocol level. For an instance whose honest round polynomials have degree at mostd, a prover whose round polynomials (degree at mostd) may depend on the challenges so far, and a false claim, the verifier accepts at at mostn · d · |S|^(n-1)challenge vectors ofS^n, ann · d / |S|fraction. The instance carries each round's eq weight when factored out (Sumcheck.lin);Sumcheck.sumcheck_sound_funis the bound for a prover given by its round polynomials at each challenge vector, roundi's reading only the challenges before it.Rec/Rounds.lean,Rec/RoundSound.lean). Every sumcheck reads its rounds withVerifier::read_round(the claim fixes one coefficient, so each round's check holds by construction) and its next claim withpoly_eval; its one test is the last claim against the verifier's value.checkbindfinds each such test's rounds back to the input claim and records aBind.SumcheckCert(aBind.RoundCertper round: the fold past the fixed coefficient, the fixed coefficient's call, Horner'smul_adds, the challenge'sk_to_eof three squeezed words and its time in the transcript). The verdict checks the calls, that the test is a test of the last claim, that each challenge is squeezed from the chaining value of the transcript's blocktime(RoundCert.chalOk), and that what the round's prover sends, its eq weight and the input claim are bound by those blocks (SumcheckCert.boundOk); a table sumcheck's input claim reads hinted fixed-column evaluations, which the certificate names (SumcheckCert.hints, each a claim the reduction takes, anedge termvalue) and binds the claim with as seeds.sumRound_sem: where the replayed calls hold, the round polynomialSumcheck.polyOfof the coefficients has degree at mostd, passes the round's check against the claim and is the next claim at the challenge.sumcheck_test_sound(premisesHashCR,WindowCRbetween answers; the honest instanceSumcheck.Instas an explicit interface, with the circuit's eq weights): for answers indexed by the challenge vectorsrofS^n, holding every constraint but the tests, with challengesr, agreeing on the blocks before roundi's challenge when their challenges before roundiagree, and an input claim that is not the instance's sum, the vectors at which the test holds with its other side the instance's final value, and the hints are their true values, are at mostn · d · |S|^(n-1)(Sumcheck.sumcheck_sound_on).RomExample.sumcheck_hinted_answers_existexhibits hinted answers.Bind.PowCertnamescheck_pow's trial compression, thed_to_kandsplitof its first word and theeq_k_consttests of its topbbits.pow_sem: where the tests hold the word is below2^(64-b).grinding_bound: a prover picking one ofQtrials, each first word uniform, passes at at most aQ / 2^bfraction of the outcomes;pow_test_soundis both on an accepted circuit.Bind.OddCertnames the values combined atλ, the children's products combined atλ, the test, and each value's line through its children at the next challenge;Cert.oddsOkchecks the calls, both challenges' squeezes, the values bound beforeλand the children before the next challenge.odd_semreads them;odd_test_sound(true children as the explicit honest instance): if some value is not its children's product, the pairs of challenges at which the test holds and every next claim is its value's true line are at most anm/|S|fraction.Rec/TreeSound.lean): a node's statement words are the next verifier's claims.TreeSound.tree_sound: over a tree (nodes, root at depth zero, parents one level up), if at each node off an eventbad va true statement makes its input claims true, a child's statement is true when its parent's input claims are, and the root's statement is true, then off every node's event every node's statement and input claims are true;tree_sound_frac/tree_sound_eps: the failures are at most the sum of the nodes' fractions. In every dump the test bound only with the statement is the reduction's last check, certified with the other sumchecks.Rec/WhirRounds.lean,Rec/LateSound.lean), each in the random-oracle view of its own transcript: GKR's radix-four top layer (TopCert,top_test_sound: an(m + 1)/|S|fraction,card_plane_zero), the table sumcheck's residual (resid_sem, withinsumcheck_test_sound, its hinted fixed-column claims bound as seeds and counted at their true values), a leaf's program claim split (SplitCert,split_test_sound: the split is exact), and WHIR's sumcheck read with fold and batch rounds (WhirCert,QuadCert,PExpr,whir_test_sound:n · d / |S|over all its rounds from the opening's first claim). A batch round reads rows the Merkle paths bind through the query positions, squeezed from the same chaining value as the batching challengeλ: the certificate namesλ's own squeezed words (own) and binds the round's atoms with the other words of that chaining value as seeds atλ's time (WhirRound.seeds,Cert.timesX,timesX_sound,whirBound_closure,ro_agree), andWhirAnswersasks answers to agree on those words.RomExample.top_answers_existandwhir_answers_exist(a batch and a fold round) exhibit their answers.Rec/Run.lean).Bind.Run: an assignment at each oracleρ(the answers at its transcript's squeezes' output words), in the random-oracle view, its squeezes' outputsρ's answers, what its firstkblocks absorb a function of the answers drawn byk, and, off a collision eventCof its execution, collision-free against any execution sharing its prefix on the rows that prefix binds (Run.cr,PairCR). Collision resistance is asked of nothing else: rule validity only for the rules a derivation fires (closure_agree_on), and collision and window rules fired from a prefix read only rows live on it (RowLive,HashCRP/WindowCRPon live rows,rules_valid). Each challenge'sk_to_ereads three squeezed words (ChalCert.read), and the verdict now checks every certified check's challenges are drawn in order from the oracle's words (Cert.chalsOk: each word a challenge seed one step after its challenge's time only, a place of its digest, none shared, times not decreasing, increasing for WHIR).oracleAt own ρ rputs a challenge vector's coordinates in place of those words; at any oracle the run's assignments there areSumcheckAnswers,OddAnswers,TopAnswersandWhirAnswerson every accepted circuit (Run.sumcheckAnswers, ...), good offCat the substituted oracle. The substitution is a lens (card_lens,run_frac), so each round theorem holds as a fraction of uniform oracles offC:sumcheck_run_sound_at,odd_run_sound_at,top_run_sound_at,whir_run_sound_at(the input claim bound before the first challenge,sumcheck_claim_agreewith its hints as seeds), andrun_frac_offchargesConce. Proof of work's oracle is the trial compression's answer:pow_sem/pow_test_soundask every call but that compression (FactsBut), andpow_run_soundbounds a run whoseQtrials are answered by uniform oracle words byQ / 2^b.RomExample.run_existsgives a run meeting every premise but acceptance;RomExample.chalsOk_mutationsshows the check rejecting a shared word, a late challenge, challenges out of order and a word past its digest's four, and on a dump a sumcheck challenge'sk_to_ereading one word twice is rejected.Rec/Design.lean,Rec/DesignKind.lean):Designfor every shapeTree::newaccepts (places, tiers, kinds and positions, unions, the statement's layout,convergeover an abstract heights oracle), with structural theorems for every accepted shape (tier_iff,position_code,code_position,children_tier,section_unique,converge_fits,converge_least, ...).Model.kindRowsisDesign::kind_bitsandModel.limbRowsthe child's limbs as builder programs;Model.nodeRows_good: for every accepted shape and node position, whatever the transcribed rows (if they keep the builder's invariant), every child's kind is a kind of its tier, itstopbits select that circuit's block of the fixed polynomial,is_nodeis zero exactly at the first level, and its verifier is given its words' limbs (ChildBound).checkdesigncompares the model with Rust on 600 shapes (rec::tree::design_tests,fixtures/design-summaries.txt) checks the kind rows and limbs of every child of the 17 dumps against the model, and checks each circuit exposes its own kind code first (kind_exposed,kindConst_ev: a child satisfied at the words its parent's verifier reads has its own code as the kind word the parent binds).Rec/Edges.lean,checkedges): the dumps mark each child's statement words, the layout and the claims the reduction takes.Edges.EdgeCert.edge: in every satisfying assignment, every claim a child's words make at its kind's scale (nodeScale, from the calls computing it,ScaleCert) is among the reduction's claims, and the digest read is the words' halves.Edges.InstCert.verifies: the child's verifier (RecShape::verify) absorbs the words as its transcript's instance before any challenge (the count, then each word's limbs, as the nativeinstance) and reads them into the public table's columns (statement_at,VerifiesAt).Edges.tree_sound_certs:tree_soundover certified circuits, a child's statement being the words its parent's verifier reads (treeStmt), with the recursive verifier's soundness at that statement (hrec) as the premise on a child;Edges.sat_treegives every node's circuit satisfied at itstreeStmt. A verifier's soundness holds off an event of its challenges:Edges.tree_sound_certs_offtakeshreconly off an eventbadRec vper child (sat_tree_at,hedge_at: the induction at one outcome), andEdges.tree_sound_certs_fracbounds the outcomes at which some node's statement or input claims fail by the sum over the nodes of theirbadandbadRecfractions.Rec/RecParts.lean).hrecnow also receives the parent's satisfied circuit. The parent's verifier of a child is a list of certified checks, each reducing input claims to output claims; where the parent's circuit is satisfied a check lets a false input through with true outputs only on its event (RecParts.Ok.test), and each check's outputs are later checks' inputs or openings of the child's committed witness, true off the PCS event (RecParts.Ok.flow, Add executable Lean WHIR and checked list-binding composition #551'sε_PCS).RecParts.ins_ok: off those events every check's inputs are true;RecParts.least_ok: the least such events satisfy the premises for any claims;RecParts.hrec:hrecoff the checks' events,pcsBadandcrBadfrom the AIR link (hair);Edges.tree_sound_parts: the tree's failures are at most the sum over the nodes of theirbad, checks' events,pcsBadandcrBadfractions. Each certified check is such a part (sumcheck_part,whir_part,odd_part,top_part), its event bounded at each oracle with no premise that its input is false (sumcheck_run_sound_at,whir_run_sound_at,odd_run_sound_at,top_run_sound_at: the input is bound before the check's first challenge,sumcheck_claim_agree,card_at). The AIR link is the premise left: where the parent's circuit is satisfied, every check's inputs true (the AIR's constraint and bus claims on the child's committed witness), no compression colliding and the parent's verifier reading statementst, the child's circuit is satisfied atst.Rec/BusBalance.lean):BusBlocks::newpulls each slot's key and limbs and pushes itsnextkey with the same limbs (a Rust test,rec::bus::tests::every_slot_pulls_its_key_and_pushes_its_next_with_its_limbs, checks the plan slot by slot), andbus::verify_balance's fingerprint weights are the union'seq(A, k)over four challenges.balanced_of_eq: equal sides, encoded injectively, areBalanced.bus_balance_sound: if they do not balance, the points(β, A)ofS^5at which the two products agree are at most a4n/|S|fraction (UnionSound.coverage_sound).bus_copy_sound: withnextthe classes' cycles, the points at which the products agree but two slots of one class differ are at most that fraction (copy_argument).Rec/DesignClaims.lean,checkdesign). The summaries now hold, per shape, the statement's edge layout,Design::carriedon a statement of labeled words,Reduced::statementon labeled reduction outputs (two round counts and presences), each tier'sDesign::fixed_claimon labeled hints of every fixed column at zero heights and at heights differing per table and tier, and onceNodeClaims::bind_stateof a labeled state;checkdesigncompares each with the model on all 600 shapes (carriedOk,exposedOk,fixedOk,bindOk, each with kernel-checked mutations it rejects), and computes each tier's fixed stack's variables from its columns' instead of reading them. Proven for every layout:stmtClaims_stmtOf(what a parent reads off a node's exposed statement is exactly the node's reduction outputs;reduced_dense_mem,reduced_matrix_mem,stmt_exposed: the tree's step at a node is the reduction's soundness on those outputs);offset_aligned,offset_disjoint,offset_fits,block_spec(the fixed stack's placement);term_readsandfresh_fixed_reads(a fresh fixed term, columncat its prefix, its block and the child's kind bits, reads the extension of columncof the child's own circuit, for any column values, the multilinear extension modeled lowest coordinate first);bindState_good,bindState_binds(the two bound scalars are the final digest's words and determine it);digestHalves_good,digest_roundtrip(a parent'shalves_to_dreads the digest the child'sdigest_halves_rowswrote, top limbs zero).digestRows_good(Kind::digest_rowscomputes the tree statement digest of its tag and items in every satisfying assignment; the summaries hold Rust's node digest of labeled children's digests for every tree of outputs, compared with the model's own BLAKE2s,nodeDigestOk).tierMode_scale(a child's scale, in its tier's mode, is zero exactly at the first level and one at every node), whichcheckedgesnow checks of each dump's children (modeOk). The edge marks' parser moved toRec/EdgeMarks.leanfor both checkers. Rust:design_testsemits the new lines;carried,fixed_claim,Reduced::statementandbind_statearepub(super)for it.Rec/Collision.lean). An adaptive prover against a uniform compression oracle:Collision.birthday_frac(two distinct queries of the firstQcollide on at most aQ(Q-1)/(2|Y|)fraction of oracles, by resampling the first fresh query of a colliding pair),Collision.win_frac(a window hit: two output blocks of each of two chaining values, alike off the chaining value, agreeing on four words straddling them,2Q(Q-1)(Q-2)/|K|^4, charged to the last first query of the four). The window rule now takes the two blocks' other input words (counter, finalization, message: constants in an output block) as premises, which is what makes the window a four-word event; it was bounded by a two-word near hit,3Q(Q-1)/(2|K|^2), which capped the proof near2^64queries. A mutation test rejects a window without them or of two chaining values. Off the eventsBind.pairCR_of_oraclegivesPairCRof assignments whose live non-squeeze hash rows are oracle queries (Bind.OracleRows).Edges.crEvent,Edges.crBad_frac(a child'scrBadoverΩ₀ × oracleis at mostepsCRof its query count),Edges.PcsBound(Add executable Lean WHIR and checked list-binding composition #551'sWhir.SpongefishCurrentKnowledgeFinal.current_knowledgeat 8198d0b as the stated interface forpcsBad),Edges.tree_sound_eps(tree_sound_partswithepsPCS v + epsCR v).Rec/AirLink.lean). A committed witness (heights and columns per table, the public value columns included) and the AIR's claims of it (AirLink.Claims: row counts within the heights and2^32, each circuit row satisfying its table, public columns carrying each public row's constant or statement word, the bus balanced withnextthe slots' class cycles).AirLink.sat_of_claims: they giveModel.Satat the statement, for the assignment reading each wire off its class's first slot;claims_of_satthe converse for an honest witness (non-vacuity), and three circuits no witness meets (mutations). The bus is derived from the GKR root's two products agreeing at a draw offbusDraws(bus_of_product,busDraws_card,busBad_frac:4 · slots / |E|).AirLink.hair_of_airderiveshairfromAirLink.ChecksGiveRows(true check inputs give the rows' claims and the products' agreement, offcrBadand the constraint batch's eventbatchBad), andAirLink.tree_sound_airistree_sound_partswith it.Rec/TreeBound.lean:AirLink.tree_sound_bound(each event's fraction replaced by its bound:epsPCS v + epsCR v + epsBus v + epsBatch vper child beside its reduction's and checks' events),tree_sound_crEvent(crBadthe ideal model'scrEvent, bounded byepsCRof the child's queries) andtree_sound_ideal(the bus also bounded,4 · slots / |E|);Rec/AirBatch.lean: the constraint batch asTableArgument::verifyandconstraints::verifycheck it (at the bus's pointζandξ, the bus forms' sums plusΣ_j ξ^(2+j) C_j(ζ)over the 66 HASH and SPLIT identities vanish,AirLink.BatchClaim); a broken identity leaves it holding on at most(n + 67)/|E|of the draws (batchDraws_card: Schwartz-Zippel inζ, roots inξ; mutationbadSplit_rejected), andtables_ofgives every row its table's identities off them. The remaining premise isAirLink.ChecksGiveBatch(true check inputs give row counts, public columns, the hash rows' flock witnesses, the batch claim and the products' agreement at their draws);tree_sound_batchandtree_sound_ideal_batchare the bounds withepsBatch v = (n v + 67)/|E|, the draws taken uniform after the commitment.epsPCSstays the Add executable Lean WHIR and checked list-binding composition #551 interface.Rec/DigestEdges.lean,checkedges).Edges.DigestCertnames the calls by which a wrap states its only child's digest (thehalves_to_dof the child's statement words 1 and 2) and a node of a tree of outputsKind::Node::digest_rowsof its children's digests, exposed asdigest_halves_rowswrites it at statement positions 1 and 2;DigestCert.exposed,wrap_statesandnode_statesprove them sound where every call holds, andwrap_mutations,node_mutationsare kernel-checked mutations.checkedgesfinds and checks the certificate on every wrap and output-node dump, and rejects a wrap's dump with its halves' exposures swapped and a node's dump with its children hashed out of order or its header's count replaced.Rec/Run.lean,Rec/AirRun.lean).Bind.CommittedBefore: a function of what the transcript absorbs before a time, as the committed witness is through its commitment;Bind.Run.committed_atmakes it fixed across the challenge vectors put in when every challenge is drawn after (Bind.draws_not_fixed: the draws are not). The run theoremssumcheck_run_sound_at,whir_run_sound_at,odd_run_sound_atandtop_run_sound_attake the honest instance, the hints' true values and the true children as such functions of the oracle (Run.sumcheck_committedand the like).AirLink.busRun_fracandAirLink.batchRun_fracbound the bus's and the batch's draw events by4N/|E|and(n + 66 + 1)/|E|with the draws a run's challenges after the commitment and the prover adaptive, andAirLink.tree_sound_runis the tree's bound over a uniform oracle with no lens premise.PcsBound's terms (Rec/PcsMatch.lean).Edges.Pcs551takesWhir.SpongefishCurrentKnowledgeFinal.current_knowledge's conclusion in its own form (the uniform average over a primitive oracle and coins of the indicator of native acceptance with extraction failure, at most∑ k : Fin 4, finalBound Q_k,finalBoundverbatim), a map from the recursion's outcomes with fibers of one size, andpcsBad vinside its event's preimage;Edges.pcsBound_of_551givesPcsBound.Edges.compress_fiberdischarges the fiber premise for the ideal compression model's outcomes read through an injective encoding of Add executable Lean WHIR and checked list-binding composition #551's 833-bit node into the 14-word compression input and an output bijection.Rec/DesignKind.lean).Model.kindRows_goodnow proves a child'sis_nodezero at the first level and one at every node for every accepted shape (Model.prod_zero_or_one), not only zero exactly at the first level.Rec/CrScale.lean). A run'scris now asked between two executions sharing a prefix both off their execution's event, which every round theorem has (its two answers are bothgood).Bind.Run.cr_of_extractderives it by straight-line extraction from a causal prover (its queries before a squeeze are shared by the executions agreeing by then), normalized (its rows are among its firstQcompression queries, consistent with the oracle), whose rows the prefix binds output words the prefix fixed (hout: an earlier answer, or one of at mostBtargets its answers by then fix).Bind.oracleRows_of_late: a row whose input is first queried after the squeeze answers a word fixed before it, a collision if that word is an earlier answer and otherwise a late hit on a target (Collision.LateHit, at mostQ · B / |V|^4of the oracles:Collision.late_card,Edges.lateEvent_frac). So a later query hitting a word the prefix fixed is a collision only when the word is an earlier answer; a word written without being computed is a preimage target, now its own termEdges.epsLate.Bind.out_of_prefix: the previous premise (every such row a prefix query) implieshout.AirLink.tree_sound_execcharges each child'sepsCR K (Q v) + epsLate K (Q v) (B v)once, its checks' round bounds holding at every compression oracle (frac_prod_le).AirLink.tree_sound_endis the end-to-end statement for one tree: per childD v / |E|(its reduction's, checks', bus's and batch's terms), Add executable Lean WHIR and checked list-binding composition #551'sΣ_k finalBound (Q_k)(pcsBound_of_551),epsCRandepsLate, summed over the nodes.Edges.tree_bound_deployed(|E| = 2^192,Edges.card_E): for at most2^10nodes withD ≤ 2^40,2^64compression queries and2^86targets per child, the bound is below2^-19at Add executable Lean WHIR and checked list-binding composition #551 budgets of2^20per binding shape and below2^-7at2^32;Edges.pcs_dominates: Add executable Lean WHIR and checked list-binding composition #551's query term, about2^-51.1per query and shape, dominates (at least2^-18per child at2^32, while the compression terms at2^64queries are below2^-62).Edges.exec_bound_deployedbounds the compression terms alone againstQ(below2^-7forQ ≤ 2^82) andEdges.epsCR_capputs the window term past one at2^86.Rec/AirBatch.lean).AirLink.ChecksGiveInststatesChecksGiveBatch's claims as the honest instances' values on the committed witness: the table sumcheck's input claim, the bus totals'σ_0 + ξ σ_1, isAirLink.tableSum(the bus forms' weighted sums and each identity'sξ^(2+j) C_j(ζ)), and the bus GKR's root claims areAirLink.pullRootandAirLink.pushRoot, held equal bybus::verify_balance.checksGiveBatch_of_instgivesChecksGiveBatchfrom it, the batch's bus parts the forms' sums less the totals (batchClaim_of_sum,productClaim_iff).Rec/TableSum.lean).Sumcheck.mvInstis the honest instance of a polynomial on the Boolean cube with no eq weight factored out (mvInst_sum,mvInst_ok,mvInst_final,mvInst_weight).AirLink.tableInstisconstraints::verify's:nrounds from the highest variable down, each table active in its own variables (eq(ζ_m, r) = 1 + ζ_m + r) and sitting out the rest at their corner (r), its summandTableSummand::batchon its columns' multilinear extensions.tableInst_sum: its sum isAirLink.tableSumat the forms' honest sums, each table summing its own rows (corner_sum);tableInst_ok(degree 3 and up),tableInst_final(the verifier's folded weights,foldWeight_eq, times the summands at the columns' extensions atchi),tableInst_weight(no eq weight). The committed witness is taken at a layout (committedAt: heights2^τ, the public columns the verifier's at the statement), andAirLink.ChecksGiveTablegivesChecksGiveInstandChecksGiveRowswhere the layout holds the rows (checksGiveInst_of_table,checksGiveRows_of_table).Bind.TableCert,checkbind). Each residual sumcheck is named as a table sumcheck: its rounds read no eq weight, its input claim is themul_addof the bus totals atξ, and a GKR first layer before it reads one root for both trees;checkbindfails a dump where one is missing or failsTableCert.ok, and all 17 dumps name every residual (0 to 4 per circuit).TableCert.sem,answers_weightandclaim_iffread the named check's input claim as the totals'σ_0 + ξ σ_1;TableCert.okIn's mutation tests reject swapped totals, another claim, an eq-weighted round and two roots.Rec/TableResid.lean,Bind.ResidCert,checkbind). Each of its five terms names its weight's calls (from aone, amul_add(w, add(ζ_m, r_j), w)per round where its table is active and amul(w, r_j)where it sits out), its column claims, its push and pull forms at them (BusForm::at), theirmul_add(ξ, pull, push)and its identities inallIds' order (BusForm::at_constants, the model's words) at the powersξ^(2 + j).ResidCert.sem: where the calls hold, the residual terms sum toΣ_T foldWeight ζ τ_T r · summandAt forms ξ T col_Tat the named point,τs, forms and column claims;ResidCert.final_eq: at the committed witness'sτs, the formsformsand column claims the columns' extensions atchi r, that istableInst_final.checkbindfails a dump where a table sumcheck's residual is not so named; all 17 dumps name every one. Mutation tests reject a weight with anotherτ, an identity with another word or read as another table's, identities out of order, a form reading another column and a wrong power ofξ.bus::verify_balance's decomposition modelled (Rec/BusDecompose.lean).AirLink.leaf_decompose: a side's leaf claimΣ_x eq(ζ, x) L(x)over blocks at their offsets isΣ_b sel_b Σ_z eq(ζ[..κ_b], z) leaf_b(z) + (1 - Σ_b sel_b). A table block's leafβ + Σ_i w_i c_iover its row's coordinates (DCoord) is its form (blockQuad,BusForm::accumulate) plus its virtual coordinates (blockKnown).side_decompose: the leaf claim is the framework part (framework) plus each table's form (sideForm) summed over its rows;totals_eq_formSums: the derived totalsframework + Ṽ(ζ)areformSumsin characteristic two;tableClaim_of_leaves: with both sides' totals so and no row breaking an identity, the totals'σ_0 + ξ σ_1istableInst's sum over the bus point's firstNcoordinates (formSums_restrict).Rec/CrScale.lean).Bind.Run.cr_of_normal: the prover normalized to query every hash row's input after its ownQqueries (Collision.normalize,extra_mem_queries) needs only its output a function of its firstQanswers and its rows consistent with the oracle, its events countingQ + |rows|queries.Bind.Run.cr_of_staged: a staged prover (Bind.Staged: its query and transcript time at its answers read only the challenges drawn by any time it has not passed) is causal (hcaus_of_staged, the queries before it passeskbeingstageN);cr_of_extractasks causality only along the prover's own answers.Rec/GkrInst.lean).Sumcheck.eqInstis the honest instance of an eq-weighted sum with each round's eq weight factored out (v.read_round(5, claim, Some(eq_point))). A product tree's levels (level_two,level_four,level_root) make the bus's honest roots its trees' roots (pullRoot_eq_level,pushRoot_eq_level).AirLink.layerInstis a radix-four layer's honest instance: its sum the claimΣ_t λ^t Ṽ_t(p)at the honest level values, degree 4, roundiweighted byp_i, its final value the children's honest products atλ;next_claim(andodd_nextfor the odd layer) makes the layer's next claim,interp(interp(a, b, low), interp(c, d, low), high), the level below's value at[low, high] ++ r, so the honest values carry from the root to the leaves.Bind.GkrCert,Bind.LayerCert,checkbind). Its first layer is a top or odd layer reading the root as both trees' value; each radix-four layer past it is a certified sumcheck with no residual whose input claim is the layer's claim over the previous layer's next claims, whose final side is its children's expected product, whose rounds' eq weights are the previous layer's point and whose next claims are a top layer's lines (LayerCert.chain); each total is theaddof a framework share and the last layer's next claim. A GKR is paired with its table sumcheck by the chain that reaches that sumcheck's totals, so circuits verifying several children name each one's own.checkbindfails a dump where a table sumcheck has no GKR or one failsGkrCert.ok; every node dump names one per child (10 to 40 layers past the first per circuit), and the first-level dumps, which verify leaf proofs, have none.LayerCert.layer_semreads a named layer's wires inAirLink.layerInst's form;GkrCert.semandLayerCert.link_semread the chain; mutation tests reject totals reading another wire, a first layer reading two roots, a layer round reading another eq weight and a layer whose values are not the previous next claims (GkrCert.okIn,LayerCert.linkOk).Tree::convergebuilt (Rec/Heights.lean).AirLink.layoutFits_converge: every circuitDesign.convergereturns, its heights holding its rows, fits its tier's layout withinMAX_TAU(LayoutFits, viaconverge_fits);taus_le_rounds: every owned table'sτis at most the roundsconstraints::verifyruns, the tallest owned table's (tableInst_sumnow asks it of the owned tables only, the public table being in no summand).AirLink.checksGiveRows_of_convergeischecksGiveRows_of_tablewith both hypotheses replaced by the tree's building facts (each child its position's circuit at the converged heights, read at its tier's heights,Circuit::heightsholding its rows). A one-tier example converges in the kernel.Rec/Named.lean).AirLink.checksGiveTable_of_named: where the parent accepts its certificate and names the table sumcheck,ChecksGiveTableholds with the totals, root andξthe named wires' values, given parts whose named table sumcheck's input is its honest instancetableInst's sum on the committed witness, whose bus GKR first layer's input is the named root being both trees' honest roots, and whose flock check's input isFlocked;TableCert.claim_iffreads the named input claim off the parent's facts.named_inputsis its non-vacuity.Circuit::heightstranscribed (Rec/Heights.lean).AirLink.circuitHeightsisTable::height_logof each table's rows (log2_ceil_usize, and for the hash tablemin_n_blocks_logat flock's floor) at least its floor;heightsHold_circuitproves it holds the rows, andchecksGiveRows_of_treeischecksGiveRows_of_convergeat those heights withHeightsHolddischarged. Rust tests compareheight_logwith the transcription (rec::table::tests::a_tables_height_is_the_proven_transcription_and_holds_its_rows) and check the remaining building facts on a tree of one tier and one of two: each circuitTree::convergereturns has its tier's heights, at which a node reads its children, and they hold its rows (rec::tree::tests::every_circuit_is_at_its_tiers_converged_heights_which_hold_its_rows).RecParts(Rec/GkrParts.lean).Bind.layer_part: where the parent's circuit holds a linked radix-four layer's calls and its sumcheck's test, its next claims true (each tree's level below at[low, high] ++ r) make its values, the previous layer's next claims, true (each tree's level at the previous point), off its sumcheck's event againstlayerInst(sumcheckFalse, bounded bysumcheck_run_sound_at), the line eventLineBad(at most2|S|of the pairs(low, high),lineBad_cardviacard_plane_zero) and theλeventLamBad(at most oneλ,lamBad_card).checkbindnow asks each layer to draw its challenges as a top layer's (LayerCert.chalOk,GkrCert.layersOk:λ,low,highin order from its transcript, its children bound bylow's time,LayerCert.boundOk, and its values byλ's time with the words squeezed withλbut its own as seeds,LayerCert.lamOk: the sibling-word argument of WHIR's batch rounds, as the values read the previous layer'shigh, squeezed from the chaining valueλis squeezed from; both with mutation tests), andBind.layer_run_sound_atbounds the line andλevents together over a run by3 / |E|off the run's collision event (the values fixed acrossλat each(low, high),Run.sib_agree, the children across(low, high)at eachλ);LayerCert.chal_evalmakes the challenge wireslayer_partreads the oracle's.Rec/Tries.lean). An outcome is an oracle per try on its transcript's words with the compression oracle they share; tryi's event may read every try's oracle.Bind.frac_fix_le: an event at most anεfraction of tryi's oracle and the compression oracle at every value of the other tries' oracles is at mostεof all outcomes (with the others fixed as whole functions, tryiis an oracle algorithm on its own oracle, the setting ofBind.Runandtree_sound_end).Bind.frac_pick_le: whichever try the prover outputs, its event is at most the sum of the tries' bounds (frac_pick_le_mul:m · ε;bitPick_fracan example).Edges.tries_bound_deployedfolds it into the end-to-end bound.Regression fixture
verification/circuits/fixtures/pre626-claimset-two-tier-circuit-1.txt.xzis a two-tier node circuit from #595 with b094d00 (#626) reverted. Its coverage test is unbound: the children's pool product reads begin bits no transcript absorbs. CI runscheckbindon every current dump andcheckbind --expect-unboundon the fixture.Status
All 17 dumps of the merged head (with the leanXMSS-100 2 to 1 tree over zero-knowledge leaves, first and node) are accepted with no unbound test and no uncertified
eq_etest (2 union products and one coverage entry per union circuit); the fixture is rejected.checkbindrejects a dump with a WHIR sumcheck not certified from the opening's first claim, or with a hint that is not a claim the reduction takes; on a node dump, a query'sk_to_ereadingλ's own words and zeroededge termvalues are each rejected. Per circuit, in the random-oracle rule set, 2 to 54 tests close a certified sumcheck (45 to 687 rounds, up to 4 by a residual, whose input claims read up to 408 hints), 85 to 340 are the bits of 5 to 20 proof-of-work checks, 0 to 4 close a certified GKR odd layer, 0 to 4 a radix-four top layer, 1 to 4 a WHIR sumcheck from the opening's first claim (29 to 124 rounds, 5 to 20 of them batch rounds) and 0 to 4 a claim split.checkdesignpasses on the 600 shapes and the 17 dumps,checkedgeson the 17 dumps. Audit lists onlypropext,Classical.choice,Quot.sound; leanchecker passes on every changed module.The capstone bound per execution. As first stated the run theorems'
Bind.Runasked every two answers of a run's family (one per challenge vector,|E|^nof them) not to collide, which only a query count covering every answer's compressions gave, so the bound was vacuous. Now collision resistance is asked only between answers sharing the prefix before a check's challenge, on the rows that prefix binds, both off their execution's event, charged once per execution (run_frac_off,tree_sound_exec), and the window term is a four-word event. The step from one execution's queries to the prefix rows is straight-line extraction (Run.cr_of_extract), which adds the late-hit termQ · B / |V|^4. End to end (tree_sound_end,tree_bound_deployed) the level is set by #551's PCS term, aboutQ_k · 2^-51.1per binding shape and child: below2^-7for2^10nodes at budgets2^32, the compression terms negligible beside it up to2^64queries. Overmtried transcripts, an oracle per try and the compression oracle shared, the output try fails on at mostm / 2^7(m / 2^19at budgets2^20),Qcounting every compression query the prover makes (tries_bound_deployed).Not proven: the rest of the AIR link's premise,
AirLink.ChecksGiveTable: that the named table sumcheck's and bus GKR's input claims are true on the committed witness (reduced bychecksGiveTable_of_namedto parts whose named checks' inputs are their honest instances' claims; what stays is that such parts meetRecParts.Okwith the round theorems' events, each check's outputs being the inputs of the checks after it down to the opening; each GKR layer past the top meetsRecParts.Ok.testoff its sumcheck's, line andλevents,layer_part, the last two bounded over a run bylayer_run_sound_at), that the circuit's forms and framework shares areAirLink.sideFormandAirLink.frameworkover the bus's blocks and the GKR's leaf layer is those blocks atBusBlocks::new's offsets (the decomposition is modelled,AirLink.side_decompose,totals_eq_formSums,tableClaim_of_leaves, but the circuit's selector, weight and accumulation calls are not certified), that the table sumcheck's named forms are those forms and its named column claims the columns' extensions atchi rthe opening checks (ResidCert.final_eq's premises; the residual itself is certified term by term,ResidCert.sem), and the hash rows' packed witnesses (Flocked, flock's reduction);LayoutFitsandτ ≤ nhold for a treeTree::convergebuilt (checksGiveRows_of_tree,HeightsHoldproven of the transcribedCircuit::heights), with its building facts as premises, checked by Rust tests; #551's theorem itself (Edges.Pcs551.knowledge, a separate Lean 4.34 project) andpcsBad's inclusion in its event (Edges.Pcs551.sub: the parent's rows as #551's native acceptance of the child's opening, its extracted witness the committed one); the prover model'shoutinRun.cr_of_staged(the rows a prefix binds output words fixed before the prover passes the prefix's time, at mostBtargets, true of a Merkle opening against an absorbed root and its paths' inner digests but not derived from the closure's rules), with the prover staged, its output a function of its firstQanswers and its rows consistent with the oracle (the ideal model's compression); the reductions'badevents, enteringtree_sound_endthroughD v; over several tried transcripts, that each try with the other tries' oracles fixed meetstree_sound_end's premises (tries_bound_deployed'shend); the design model's remaining transcribed rows (each child's verifier past its statement, with its statement weights and share wiring, the union's digest, the reduction's rows, the first level) and its heights oracle, beyond whatcheckrec,checkdesignandcheckedgescheck on the 17 dumps andcheckdesignon the 600 summaries; the GKR's own product claim beyond its certified radix-four layers (its odd layer), and the model's classes being the Rust classes beyond the seventeen dumpscheckreccompares. The README's "End-to-end composition" states the target theorem and which parts #551 (Whir.StackWHIRROM.rom_list_binding_numeric,Whir.CommitmentAnchor.selected_unique,Whir.CommitmentAnchor.joint_opening_probability_numeric), #600 (callers bind each opening to its commitment record) and this PR supply.