Blanc/implementations/ports
BeaconDeposit.
The port of the deposit contract at 0x0000…05Fa — immutable, permissionless, the contract every validator’s stake passes through: a 32-deep incremental Merkle accumulator whose root the consensus layer reads. Blanc’s port proves that accumulator from a hash-parametric model down to the exact compiled bytes — through twelve SHA-256 precompile calls, a storage-writing loop, and dynamic-bytes calldata — roots it in a derived deployment, and carries the exact count and mixed root to every admitted future.
A port never claims byte identity — PORTING.md governs what is claimed and what never is. What makes this port distinctive is that it is the first in the portfolio whose proofs cross a precompile, and that its assurance register gives every one of its eleven rows a differential channel — or says, in so many words, that the row is proof-only and has none.
Fig. 1 — two BeaconDeposit gates, verbatim (exact-candidate run 2026-09-03 UTC), ellipses marking elision: the differential matrix beside the vendored deployed runtime in a pinned Prague oracle, and the register verifier that fails if any cited declaration, axiom set, or non-claim phrase drifts from the tree. The differential line continues “… 6 comparison-channel falsifiers and 16 manifest ownership falsifiers live; gas recorded on every runtime path (0 positive Blanc deltas require registry evidence); constructor 31/31 SHA calls per side and Blanc-minus-reference total/execution gas -719572/-26172.”
What the port proves
The accumulator, from the model to every admitted future.
The deposit contract does one thing: append a leaf to an incremental Merkle tree, and expose the root. The port proves that in three layers that hand off to each other. A hash-parametric model — the accumulator over an arbitrary H — is proved to compute the mixed root of exactly the history it has absorbed. A storage abstraction, ArtifactInv, ties the concrete branch, count, and zero-hash words of the compiled artifact to that model with H instantiated at Jaune’s Bytes.sha256. And a deployment root plus an open-history theorem carry the abstraction from one derived Prague creation block to every admitted future — where the exact count and mixed root can simply be read off.
From a checkpoint holding the exact compiled runtime at ca and the storage abstraction for some history baseline, every state reachable along the Prague-only schedule — under the one admission below — still carries the abstraction, for the same baseline extended by some suffix.
theorem pragueOnly_history_extends (chainId : UInt64) {baseline : List B256} {checkpoint future : BlockChain} {ca : Adr} (reach : BlockChain.ReachUsing (ChainConfig.pragueOnly chainId) checkpoint future) (native : ReachNativeShaAdmitted reach ca) (installed : some (checkpoint.state.getCode ca).toList = Prog.compile runtime) (artifact : ArtifactInv (checkpoint.state.getStor ca) baseline) : ∃ suffix, ArtifactInv (future.state.getStor ca) (baseline ++ suffix)
Read the quantifiers — ReachUsing is Jaune’s configured-chain reachability: whole valid blocks, every transaction anyone sent, arbitrary contracts doing arbitrary things. native is the one admission, and it is entry evidence about actual frames, never a poststate or a result: a retained history trace whose frames at ca enter fresh and find native SHA-256 at address 0x2. From the deployment root, DeploymentRoot.future_history_extends supplies the installed code and the empty baseline, and DeploymentRoot.future_count_root reads the consequences off one suffix: the concrete count equals baseline.length + suffix.length, it grew strictly if and only if the suffix is nonempty, and the concrete root equals mixedRootOf Bytes.sha256 (baseline ++ suffix). The suffix is existential — not unique, not transaction-indexed — and nothing here says a deposit occurs.
root_correct -- model: the root of any invariant state is mixedRootOf H of its leaf list, for any H deposit_inv -- model: success appends exactly the reconstructed deposit-data node, and keeps the invariant deposit_ne_assert_false -- the source's terminal assert(false) is unreachable deposit_success_settled_effects -- compiled: model-linked storage, the byte-exact 576-byte event, clean message settlement deposit_error_runCompiledTo -- all eight guards, source-exact Error(string), no raw SSTORE on the way out ArtifactInv.root_eq_mixedRootOf -- concrete words project the model root canonicalDeploymentStep_ establishes_root -- one strict Prague CREATE block → DeploymentRoot, installed bytes, empty history historySpec_preserves -- open frame: the four-selector dispatcher preserves the baseline-relative witness DeploymentRoot.future_count_root -- exact count, strictness ⇔ nonempty suffix, mixed root
Every hash in the contract is a STATICCALL to address 0x2 with a 64-byte input and a 32-byte window — twelve source-shaped sites, all retained. The proofs take the frame’s fork to be a covered one — Prague, Osaka, BPO1, or BPO2, never Amsterdam — name its precompile selection and the absence of a delegation designator at 0x2, prove the 64-byte child input, and instantiate the answer as exactly Bytes.sha256 input: environment facts, not a hash axiom. A failed call bubbles the child’s returndata byte for byte; a short success empty-reverts — both arms as the pinned solc wrapper does. The SHA-256 named here is Jaune’s, itself proved equal to a FIPS 180-4 transcription in the sibling — a strengthening no beacon statement depends on.
Three bounded walks — the 32-step root fold, the at-most-32-step insertion, the constructor’s 31 zero-hash writes — compile to tail-recursive auxiliary slots at constant stack height. The alternative was measured before it could become architecture: 179 bytes for the first slice against 4,195 unrolled, at indistinguishable elaboration cost, so no unrolled carrier and no resource ceiling was admitted. Every same-frame SSTORE site is classified: a successful deposit commits the count first, then exactly one live branch cell, and construction performs exactly 31 writes.
The decoder is a separate phase before any source guard: the 132-byte head, then, for each of the three tails, an offset and a length below 232 and a padded tail that fits in calldata. Reordered and overlapping tails are allowed; padding contents and trailing calldata are ignored; every structural failure empty-reverts. Canonical encodings are proved decodable, and the eight guards run in source order — lengths 48/32/96, three value checks, the reconstructed root, the cap — each with the reference’s exact Error(string).
So this re-proves what Runtime Verification proved?
pushbackNo — and the register forbids that sentence. Runtime Verification’s KEVM campaign verified the r1 Solidity artifact in K; Blanc’s theorems are about Blanc’s own 2,891-byte artifact under Jaune’s semantics. These are different artifacts and independent proof developments. Blanc does not reproduce, audit, criticize, or supersede that campaign, and it does not verify the deployed r2 bytecode. What may be said is narrower and still worth saying: the same property family — the incremental-Merkle invariant, root correctness, count monotonicity — is now carried to compiled code, with a proof object a third party’s kernel re-checks under three axioms.
“Every admitted future” — what does the admission cost?
pushbackIt is the price of a true theorem. Unconditional preservation is false: a type-4 (EIP-7702) authorization can place delegated ordinary code at address 0x2, so a frame that “calls SHA-256” may be calling anything. Rather than assume the callee away, the theorem admits frames positively — fresh entry and native SHA at the actual admitted roots of the retained history — and the closure goal was re-priced to that boundary explicitly rather than silently weakened. The admission is entry evidence about the frames that actually ran; it is not a poststate premise, not a result-equivalent premise, and no blanket callback axiom is anywhere in the family. Nothing quantifies over delegated address-2 code.
Does the root say anything about inclusion, or about the beacon chain?
pushbackNo. The root equation is relative to Bytes.sha256 and the witnessed list: no collision resistance, no unique-history commitment, no inclusion proof, no consensus-layer claim of any kind. Strictness is an equivalence about the witnessed suffix, not liveness — nothing promises a deposit, or that the count ever increases. And the deployment root is one exact shape: a direct, zero-endowment, singleton type-2 Prague block, under the Prague-only schedule; no CREATE2, factory, or co-block path, and no claim about the historical mainnet creation.
The 11-row assurance register maps OPEN-1 and P1–P8 onto 30 fully qualified declarations in seven frozen fields — declarations, premises, axioms, owning gates, differential channel, non-claims, source. Its eight load-bearing non-claim phrases are pinned by the gate that verifies it, and that gate runs two mutants on every invocation — a misspelled declaration and a wrong axiom set must both be rejected — so a green run is never a run that checked nothing.
How we know it is the deposit contract
Two oracle lanes, one control, and a register that names its gaps.
The vendored deployed runtime is the reference, never the subject. Two finite lanes run it beside Blanc’s exact artifact — historical Prague for breadth, the current BPO2 mainnet target for the fork that is live — a separate control executes what the deployment theorem then quantifies, and every register row says which lane corroborates it, or that none does.
▸Differential evidence — the Prague lane44 rows · 69 runtime transactions · 463 oracle SHA calls · six channels
check-beacon-deposit-differential.sh executes the exact compiler-owned Blanc runtime and creation artifacts in a clean pinned EELS Prague interpreter beside the vendored deployed runtime, agreeing on success or revert, exact returndata, projected logical storage, ETH, ordered logs, and the retained SHA-256 STATICCALL traces. The rows cover every selector and the no-match route, all eight guards in source order and their precedence, the malformed-ABI families — reordered and overlapping tails, dirty padding, trailing data, truncation, out-of-bounds offsets — chained deposits one through eight, child failure and short-return responses, and bounded out-of-gas cases.
Gas is recorded on every path, and any positive Blanc delta is refused without explicit registry evidence — there is none to cite. A separate fresh-state creation measurement checks each side’s own returned and installed runtime, the exact logical constructor state, and the 31-call SHA chain, and decomposes direct-message gas into constructor execution and code deposit so that the smaller runtime cannot hide a worse constructor. Live falsifiers protect the artifact, comparison, manifest, warmth, trace, gas-decomposition, and dominance channels: 6 comparison-channel, 16 manifest-ownership, 4 static.
Beneath it sits the model oracle: check-beacon-deposit-model.sh compares the hash-parametric model against independently generated vectors, 360 compared lines, under both a Keccak and a SHA-256 instantiation, and its four falsifier mutants — swapped hash-argument order, a dropped count mix-in, a cap off-by-one, a regime substitution — are required to keep every proof elaborating and to be caught by the vectors anyway.
▸Current mainnet — the BPO2 lane2 fresh creations · 7 runtime rows · exact raw event bytes
check-beacon-deposit-current-mainnet.sh consumes the contract-neutral current-mainnet target at its literal BPO2 pin: two fresh top-level CREATE transactions and the same ordered seven-transition runtime state chain per side, each transition carrying the exact prior poststate forward. It checks strict runtime and creation size dominance, the EIP-170, EIP-3860, and EIP-7825 limits, exact side-owned installed runtime and storage, canonical receipt status and gas on every row, and the exact raw DepositEvent bytes on the deposit row.
Constructor gas is split into intrinsic, code deposit, and the receipt-charged remainder after any refund — the target does not expose a refund counter, so this lane makes no zero-refund claim — and both the total and the net deltas must be non-positive. Exact returndata and the broad malformed, precompile-response, and out-of-gas matrix stay in the Prague lane, deliberately; this one exists so that the current fork has executable evidence of its own.
▸The deployment control — feasibility, kept out of the proof15 projections · 31 reconstructed words · 3 mutants that must fail
check-beacon-deposit-deployment.sh keeps finite execution evidence separate from the Lean root. A Lean evaluator emits the production artifacts and constants but no theorem and no golden; Python independently pins both artifact digests, reconstructs all 31 zero-hash storage words with its own SHA-256, derives the sender and CREATE address, authors one exact-gas singleton zero-value type-2 Prague block, and executes it in clean pinned EELS. Fifteen projections check the strict envelope, successful receipt, nonces and balances, the installed runtime, complete constructor storage, empty logs and requests; Jaune replays the temporary block; and wrong-target, wrong-runtime, and wrong-storage mutants must each fail at their intended boundary before the unchanged projection returns green. Generated output is never committed and never admitted as a Lean premise.
▸Proven functional specifications — the quantified layerOPEN-1 · P1–P8 · 89 audited theorems
Where the lanes sample, the theorems quantify — always about the exact compiled bytes: code_compile and constructorInitPrefix_compile pin the 2,891-byte runtime and the 3,037-byte creation artifact, with the EIP-170 and EIP-3860 ceilings proved. Above them, P2 through P6 cover the compiled success path with its byte-exact event, the total decoded-error partition and structural-failure routes, the views and ERC-165, complete write-site classification, and the storage abstraction; P7 and P8 are the deployment root and open-history family stated in full in the results section.
The port’s 89 audited theorems sit in the repository-wide axiom audit, and check-claims.sh pins the exact statements of the compiled P1–P6 boundaries and the P7/P8 deployment, frame, history, and count-root headlines. Two register rows are deliberately proof-only — the open-frame theorem and the history extension — and the register says so in their channel field rather than inventing an observation that does not exist.
Deviations
Five rows, and no accepted behavioral deviation.
BEACON_DEPOSIT_DEVIATIONS.md holds five rows, and none of them accepts a difference on the canonical surface: two are implementation freedoms, two are rulings that agreement is required and then measured, and one is a proved-dead arm removed. Its interface agreements — nonpayable views and ERC-165, guard order and reason strings, event timing, SHA-response handling, the selector census — are recorded as agreements precisely so that none can later be mislabelled a low-level freedom.
Raw storage layout
BD-1 — orthogonalSolidity’s layout for branch[32], deposit_count, and zero_hashes[32] is replaced by three compact disjoint regions — 0x100 + h, 0x200, 0x300 + h — so logical deposits, roots, and counts agree while raw slots and storage proofs do not.
The argument: a proof-oriented, structurally disjoint layout is an implementation freedom under PORTING.md; no raw-layout compatibility is claimed, and the seeded cap-boundary row seeds each side through its own declared layout.
Canonical and malformed dynamic calldata
BD-2, BD-3 — agreement required, then measuredOn canonical decoded calls no difference is accepted: decoding, guard precedence, and revert reasons are caller-visible interface. For malformed and noncanonical shapes the two-phase decoder reproduces the pinned solc decoder on the declared matrix — reordered, overlapping, dirty-padded, trailing, truncated, out-of-bounds — as finite agreement.
The argument: the algorithmic ruling is frozen and every mandatory malformed row is green; it is evidence on those rows, not a universal decoder theorem, and any later measured mismatch is registry-bearing rather than excusable.
The terminal assert(false)
BD-4 — a proved-dead armThe source keeps a defensive unreachable panic after its insertion loop. Blanc’s loop omits it and exits by construction.
The argument: the omission is licensed only by deposit_ne_assert_false — under the cap guard the walk always finds a live slot — and by the compiled commit theorem that executes the complete concrete commit through the unique first-live slot. No informal cap argument substitutes for the theorem, and no equivalence is claimed outside its premises.
Exact gas identity is not claimed, but gas is observable, so the registry carries seven gas-row families over the committed matrix: deposit success and chained depths, rejection at each of the eight guards, the read-only selectors, dispatch and ABI rejection, precompile resource edges, construction, and the BPO2 lane. Every row is non-positive for Blanc, which is why no BD-GAS deviation row exists — the empty list is measured, not inferred from an aggregate.
Declared exclusions, load-bearing: no verification of the deployed reference, which is executed only as the finite oracle; no universal equivalence, gas parity, or liveness; no raw identity of source, dispatcher, bytes, code hash, slots, or storage root. The deployment root and open history are proved for one direct singleton shape and the Prague-only schedule, under the admission the results section states — nothing wider.
Deltas
Half the bytes, and cheaper on every measured path.
| quantity | value | status |
|---|---|---|
| runtime size | 2,891 B | vs 6,358 deployed — 54.5% smaller, compiler-derived, digest-pinned |
| creation artifact | 3,037 B | vs 6,633 — 54.2% smaller; 146-byte constructor prefix |
| Prague runtime matrix | 67 / 2 / 0 | strictly cheaper / equal (shared OOG thresholds) / dearer, over 69 transactions |
| canonical first deposit | 55,249 | vs 62,050; the matrix’s median delta is −1,131, its largest saving 18,090 |
| root read | 84,032 | vs 102,095 — 18,063 cheaper on the empty-state read |
| constructor, direct creation message | 1,274,272 | vs 1,993,844; execution alone 696,072 vs 722,244 |
| BPO2 creation transaction | 1,368,074 | vs 2,146,896 — measured against the current-mainnet target |
The constructor’s win is required to hold with the code deposit removed, so that a smaller deposited runtime cannot mask a dearer constructor — and it does, by 26,172 gas in both lanes. What is committed is the finite vector above, every boundary digest-pinned with falsifiers that must keep failing. Universal gas dominance is not claimed; exact parity with the deployed original is a declared freedom, not a goal.
These are measurements against the pinned Prague EELS and the pinned BPO2 target, and the page labels them as such rather than promoting them. Nothing here implies deployability or cost on any other fork, and nothing here is a statement about the artifact at 0x0000…05Fa.
Notes
What the build taught.
The port’s first decision was made with a stopwatch. Two prototypes of the root fold — one tail-recursive loop slot with a shared continuation, one 32-way source-generated unroll — were compiled by the real compiler under an exclusive host hold: 179 bytes against 4,195, at indistinguishable wall time and memory. An unrolled artifact would have needed a carrier abstraction from the very first proof so that concrete internals never rode through a 32-copy walk; the loop needed one invariant and one reusable SHA-call boundary. The record is committed as BEACON_DEPOSIT_COST.md, and later proof work may split invariants but may not quietly replace the loops.
The open-history theorem was contracted as unconditional preservation and turned out to be false in that form — type-4 delegation at address 0x2 is real EVM. The repair was not a quieter statement but a louder one: contract-neutral trace admission over actual executions and retained frames, with fresh entry and native SHA as positive evidence at the admitted roots, re-priced with the user rather than slipped in. The same machinery is now shared, and static-child storage preservation is proved generically. A premise a theorem cannot do without should be visible in its statement, its register row, and the page that quotes it.
Boundary, restated: nothing on this page verifies the Solidity artifact deployed at 0x0000…05Fa — its address is a provenance identifier only, and Runtime Verification’s campaign on the r1 artifact is neither reproduced nor judged. The count and root results are partial correctness for Blanc’s own compiled artifact under the stated admission, the Prague-only schedule, and Jaune reachability’s own world bound; the suffix is existential; and no collision resistance, historical inclusion, or liveness is claimed. The full boundary — eight pinned non-claim phrases — lives in the assurance register, in the honest register.