feat(ethvuln): add ethereum-vuln-dataset track c-1 formalization — 66 statements, proofs deferred (speca#146) - #24
Conversation
grandchildrice
left a comment
There was a problem hiding this comment.
SPECA 02c での実装/関数への紐づけはこの PR の範囲外として見ています。sorry も問題ありません。
ただし、01e に落としたときの obligation の意味付けは修正が必要です。must-establish に入力・初期状態の前提が混ざっており、算術系も wraparound を許す定義と overflow-safe な要求の区別がつきません。EthTotal のように、実装が保証すべき性質と precondition、さらに exact な監査 assertion を分けて出力できる形にしたいです。
| {Bytecode : Type} | ||
| (size : Nat) (base len : Bytecode → Nat) | ||
| (hWindowChecked : ∀ c, base c + len c ≤ size) : | ||
| ∀ c k, k < len c → InBounds size (base c + k) := sorry |
There was a problem hiding this comment.
ここで k < len c まで 01e の must-establish に分解されますが、これはアクセス時の入力/文脈条件で、実装全体が保証する性質とは別です。hWindowChecked のような実装 obligation と分離して出力してください。
There was a problem hiding this comment.
ご指摘のとおりで、exporter が型全体を forallTelescope で平坦化するため、結論の ∀/→ ガードが must-establish に漏れていました(この k < len c を含め 130 件中 29 件・約 22% が入力/文脈条件でした)。二段で修正しています。
- statement 側: 全定理の結論を Common の名前付き述語 1 適用に畳みました。この定理の結論は
AccessesInBounds size (fun c => (List.range (len c)).map (base c + ·))になり、must-establish は実装 obligation のhWindowCheckedだけです(ガードは述語の内側)。 - exporter 側(再発防止): A2 に rule 4 を追加 — 匿名(hygienic 名)の Prop 束縛子は
context-preconditionに分類し、B1 は property 化せず、audit packet の preconditions に載せます(contextualizeAnonymousGuardsによる opt-in で、有効なのは ethvuln のみ。gasper は該当 0 件、EthTotal は既存分類を維持)。
tests/test_ethvuln.py::test_obligations_are_named_and_guards_are_folded が「must-establish は名前付き obligation のみ・context-precondition の残留ゼロ」を回帰ピンします。現在の must-establish は 115 件・全件名前付きです。
| るすべての入力対について、数学的な演算 `spec` と一致するという | ||
| 形。すなわち「オーバーフローやラップアラウンドによって結果が壊 | ||
| れることはない」という性質を表す。 -/ | ||
| def ArithAgrees (n : Nat) (impl : Word n → Word n → Word n) |
There was a problem hiding this comment.
ArithAgrees は結果が 2^n 未満の場合だけ exact equality を要求し、各 theorem の仮定は % 2^n です。この形だと、overflow-safe な property のつもりでも通常の wrapping 実装が仮定を満たします。EVM の modulo semantics 用と、narrowing/overflow を禁止する用で predicate を分けてください。
There was a problem hiding this comment.
ご指摘のとおりです。特に overflow 系 3 件(gorilla/websocket・geth p2p・Juno)では、脆弱だった wrapping 実装自身が % 2^n の仮定と ArithAgrees の結論の両方を満たしてしまい、定理が対象のバグを排除できていませんでした。ArithAgrees(と未使用の SignedArithAgrees)は廃止し、提案どおり 2 系統に分離しました。
AgreesModWidth(modulo semantics 用): 全定義域での mod-2^n 厳密一致。仕様自体が modulo 意味論を定める consensus uint64 / EVM ガスワード用で、Lodestar の IEEE-754 経由や Besu の 32bit 縮小が反例になります。CheckedArith/AcceptedExact(overflow 禁止用):Option値の checked 演算で、オーバーフローは必ず検出(none)。wrapping 実装は常にsomeを返すため満たせません。結論AcceptedExactは下流の上限チェックが依存する「受理値の厳密性」です。
1点補足すると、AgreesModWidth 系は spec 側を自由パラメータにせず具体関数に固定しています(uint64 加算は Nat.+、Besu CALL ガス 2 件は Common の evmCallGas = EIP-150 63/64 ルールのモデル)。spec を自由にしたままだと、縮小実装が「spec を自分に合わせて選ぶ」インスタンス化で仮定・結論を両方満たせてしまうためです。
EVM のシフト / MULMOD は破られた仕様条項そのもの(ShiftSaturates / SarSaturates / MulModZeroTotal。シフト閾値は仕様どおり 256 以上の全域)を述べ、仕様モデル上で証明済みです。これら 3 件は must-establish を持たず、実装義務は emit されるプロパティの assertion として 02c で結び付ける整理です。
| theorem entry_26333a99f530c12b_availability_robustness | ||
| {UntrustedInput BeaconNodeState : Type} | ||
| (h : Handler UntrustedInput BeaconNodeState) | ||
| (hTotal : ∀ s i, ∃ s', h s i = .ok s' ∨ h s i = .reject s') : |
There was a problem hiding this comment.
Outcome が ok / reject / crash の3値なので、この hTotal は NeverCrashes h とほぼ同じ内容です。01e に出る availability property が定義の再掲になります。malformed input、resource exhaustion、state rollback など、実装が守る具体的な条件を conclusion 側に出せる形にしたいです。
There was a problem hiding this comment.
トートロジーでした(availability 15 件中 11 件が実質 P → P)。挙げていただいた malformed input / resource exhaustion / state rollback に沿って、実装が守る具体的な 2 条件に分解しました。
RejectsMalformed h wellFormed: 整形式でない入力は状態を変えずに正常拒否(パース/検証の全域性 + rollback)TotalOnWellFormed h wellFormed: 整形式入力の全域処理。resource exhaustion や内部エラーも、状態を保存する定義済みの reject に落ちる
結論 NeverCrashes は補題 neverCrashes_of_split で導出します(証明済み)。B2 の lowering ではこの 2 条件がそれぞれ独立の must-establish プロパティ = 01e の監査項目になるので、「具体的な条件を 01e に出す」要件はこの配置で満たしている認識です(結論側を conjunction にする形が好ましければ調整します)。
正直な注記を2点: (1) wellFormed は自由パラメータで、監査時に対象コンポーネント自身の検証述語で具体化される想定です。したがってこの分解が NeverCrashes に対して形式的に上乗せする正味の内容は「拒否は状態を変えない(rollback 規律)」であり、残りは監査を malformed 経路 / well-formed 経路に分けて誘導する構造です。(2) 詳細非公開のエントリでは、この段階分解が標準的なクラッシュベクタに基づくモデリング選択であって dataset の記載事実ではないことを各 docstring に明記しました。
|
追加で、01e の中身に関するレビュー観点として以下を確認したいです。
01e の生成物を fixture / |
… gates The first placement registered the 66 EthVulnFormalProps.* statements in theorem_map.json and changed nothing else; CI failed in two independent ways: * lean job — every target unresolved. `lake build` built the modules, but `lake exe speca-export` resolves targets against the environment lean/Main.lean loads at run time (importModules of GasperBeaconChain.* only), so the smoke gate saw resolved=false for all 66. * python job — 11 tests: theorem_map.json's contract (non-checklist entries proved; consensus-only labels/anchor rows; one anchor_map defs row per entry; projection_map classifies every theorem; 30..160-char assertions) cannot be met by sorry stubs that span both layers and carry 11 labels with no spec anchor. Do what the EthTotal track did: a track of its own. - theorem_map.json restored to its pre-PR content (gasper export unchanged, lean/Main.lean untouched); the 66 entries move to theorem_map_ethvuln.json (source/ref = this plugin, lean_exe = speca-export-ethvuln, x_layer = the actual placed path, three assertions lengthened into the benchmark band, no proof-status field by design; note names the unanchored labels). - lean/MainEthVuln.lean + `lean_exe speca-export-ethvuln` (lakefile) with `ethVulnConfig` (nsPrefix EthVulnFormalProps): imports SpecaExport.EthVuln at compile time and passes it to driverMain at run time, so all 66 resolve and referenced_constants / referenced_defs_expanded are the track's own. - cli._run_lean honors a map's `lean_exe` / `x_src_roots`, so `emit-01e --map theorem_map_ethvuln.json --run-lean` runs the right exe. - tests/fixtures/theorem_health.ethvuln.sample.json = real speca-export-ethvuln output (66 resolved, lean_status=unknown / sorry_free=false); bug_bounty_scope.ethvuln.sample.json (both layers). - tests/test_ethvuln.py pins the module wiring, map<->Lean 1:1, map integrity, and that lean_status is copied from the exporter (proved <=> sorry_free) — never asserted to a value, so a landed proof needs no edit. - ci.yml: lean job exports the track's health (gate: all resolved, honesty pairing, EthVulnFormalProps.* expansions) and emits its 01e; python job emits from the fixture; run-lean-e2e exercises the map-selected exe. - README (three targets), docs/ethvuln-track.md, docs/pipeline.md. Verified locally: pytest 196 passed; lake build; every new and existing CI step of the lean / run-lean-e2e jobs replayed green on this workspace. Refs NyxFoundation/speca#146 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…arithmetic predicates, proofs (speca#146) Review response (grandchildrice, CHANGES_REQUESTED): 1. Conclusion guards no longer leak into must-establish (was 29/130, now 0/115, all named): every conclusion is a single application of a named Common predicate (two disclosed closed-form exceptions), and the exporter's A2 heuristic gains an opt-in rule 4 — anonymous (hygienic) Prop binders classify as context-precondition, never must-establish, and B1 never lowers them (ProjectConfig.contextualizeAnonymousGuards, enabled only for ethVulnConfig; gasper has zero anonymous binders and EthTotal — 17 of them — keeps its historical classification byte-stable). 2. ArithAgrees — satisfiable by the vulnerable wrapping implementations it was meant to exclude — is replaced by AgreesModWidth (full-domain exact modulo-2^n semantics, spec side PINNED to a concrete function: Nat.+ for uint64, Common.evmCallGas = the EIP-150 63/64 model for the Besu CALL-gas entries, so a narrowing implementation cannot choose the spec to match itself) and CheckedArith/AcceptedExact (Option-valued checked arithmetic; overflow must be detected, wrapping cannot satisfy it). EVM shift/MULMOD entries state the spec clauses (ShiftSaturates/SarSaturates at the spec's full shift >= 256 domain, MulModZeroTotal) and are proved. 3. The tautological availability hTotal (11/15 theorems were P -> P) is decomposed into RejectsMalformed (malformed input rejected with state rollback) + TotalOnWellFormed (well-formed input processed totally; exhaustion lands in a defined, state-preserving reject); NeverCrashes is derived via Common.neverCrashes_of_split. The two undisclosed Grandine spec-equivalence identities are strengthened to AgreeOnObservation on the entry's divergence surface (registry view / head selection). Modeling choices are stated in docstrings. 4. Every map entry carries a per-entry x_spec_anchor (20 anchored to consensus-/execution-specs with x_spec_symbol, 46 explicit 'N/A — category: reason'; curation in data/ethvuln_spec_anchors.json) and a deterministic audit_packet (tools/ethvuln-build-packets.py, no LLM, idempotent): guarantee, typed class-tagged preconditions, and one exact supporting fact per obligation (FACT-OB*) plus the root fact. data/anchor_map.json gains a beacon-chain:execution-payload row; 10 map assertions are updated to the new predicates; CI gains a map staleness gate mirroring the EthTotal one. Consequence of 1-3: every implication became shallow, so all 66 theorems are now PROVED (sorry-free; choice_free honestly surfaced). The map still carries no proof-status field — status stays exporter-only, and CI/tests keep asserting the pairing, not values. Rebased onto main to pick up the audit_packet pass-through (27dc1d8). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
b50c393 to
c8b939a
Compare
…arithmetic predicates, proofs (speca#146) Review response (grandchildrice, CHANGES_REQUESTED): 1. Conclusion guards no longer leak into must-establish (was 29/130, now 0/115, all named): every conclusion is a single application of a named Common predicate (two disclosed closed-form exceptions), and the exporter's A2 heuristic gains an opt-in rule 4 — anonymous (hygienic) Prop binders classify as context-precondition, never must-establish, and B1 never lowers them (ProjectConfig.contextualizeAnonymousGuards, enabled only for ethVulnConfig; gasper has zero anonymous binders and EthTotal — 17 of them — keeps its historical classification byte-stable). 2. ArithAgrees — satisfiable by the vulnerable wrapping implementations it was meant to exclude — is replaced by AgreesModWidth (full-domain exact modulo-2^n semantics, spec side PINNED to a concrete function: Nat.+ for uint64, Common.evmCallGas = the EIP-150 63/64 model for the Besu CALL-gas entries, so a narrowing implementation cannot choose the spec to match itself) and CheckedArith/AcceptedExact (Option-valued checked arithmetic; overflow must be detected, wrapping cannot satisfy it). EVM shift/MULMOD entries state the spec clauses (ShiftSaturates/SarSaturates at the spec's full shift >= 256 domain, MulModZeroTotal) and are proved. 3. The tautological availability hTotal (11/15 theorems were P -> P) is decomposed into RejectsMalformed (malformed input rejected with state rollback) + TotalOnWellFormed (well-formed input processed totally; exhaustion lands in a defined, state-preserving reject); NeverCrashes is derived via Common.neverCrashes_of_split. The two undisclosed Grandine spec-equivalence identities are strengthened to AgreeOnObservation on the entry's divergence surface (registry view / head selection). Modeling choices are stated in docstrings. 4. Every map entry carries a per-entry x_spec_anchor (20 anchored to consensus-/execution-specs with x_spec_symbol, 46 explicit 'N/A — category: reason'; curation in data/ethvuln_spec_anchors.json) and a deterministic audit_packet (tools/ethvuln-build-packets.py, no LLM, idempotent): guarantee, an explicit obligations key (the named must-establish hypotheses, exact Lean types), class-tagged preconditions, and one exact supporting fact per obligation (FACT-OB*) plus the root fact. data/anchor_map.json gains a beacon-chain:execution-payload row; 10 map assertions are updated to the new predicates; CI gains a map staleness gate mirroring the EthTotal one. Consequence of 1-3: every implication became shallow, so all 66 theorems are now PROVED (sorry-free; choice_free honestly surfaced). The map still carries no proof-status field — status stays exporter-only, and CI/tests keep asserting the pairing, not values. Rebased onto main to pick up the audit_packet pass-through (27dc1d8). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
c8b939a to
9e2f102
Compare
…arithmetic predicates, proofs (speca#146) Review response (grandchildrice, CHANGES_REQUESTED): 1. Conclusion guards no longer leak into must-establish (was 29/130, now 0/115, all named): every conclusion is a single application of a named Common predicate (two disclosed closed-form exceptions), and the exporter's A2 heuristic gains an opt-in rule 4 — anonymous (hygienic) Prop binders classify as context-precondition, never must-establish, and B1 never lowers them (ProjectConfig.contextualizeAnonymousGuards, enabled only for ethVulnConfig; gasper has zero anonymous binders and EthTotal — 17 of them — keeps its historical classification byte-stable). 2. ArithAgrees — satisfiable by the vulnerable wrapping implementations it was meant to exclude — is replaced by AgreesModWidth (full-domain exact modulo-2^n semantics, spec side PINNED to a concrete function: Nat.+ for uint64, Common.evmCallGas = the EIP-150 63/64 model for the Besu CALL-gas entries, so a narrowing implementation cannot choose the spec to match itself) and CheckedArith/AcceptedExact (Option-valued checked arithmetic; overflow must be detected, wrapping cannot satisfy it). EVM shift/MULMOD entries state the spec clauses (ShiftSaturates/SarSaturates at the spec's full shift >= 256 domain, MulModZeroTotal) and are proved. 3. The tautological availability hTotal (11/15 theorems were P -> P) is decomposed into RejectsMalformed (malformed input rejected with state rollback) + TotalOnWellFormed (well-formed input processed totally; exhaustion lands in a defined, state-preserving reject); NeverCrashes is derived via Common.neverCrashes_of_split. The two undisclosed Grandine spec-equivalence identities are strengthened to AgreeOnObservation on the entry's divergence surface (registry view / head selection). Modeling choices are stated in docstrings. 4. Every map entry carries a per-entry x_spec_anchor (20 anchored to consensus-/execution-specs with x_spec_symbol, 46 explicit 'N/A — category: reason'; curation in data/ethvuln_spec_anchors.json) and a deterministic audit_packet (tools/ethvuln-build-packets.py, no LLM, idempotent): guarantee, an explicit obligations key (the named must-establish hypotheses, exact Lean types), class-tagged preconditions, and one exact supporting fact per obligation (FACT-OB*) plus the root fact. data/anchor_map.json gains a beacon-chain:execution-payload row; 10 map assertions are updated to the new predicates; CI gains a map staleness gate mirroring the EthTotal one. Consequence of 1-3: every implication became shallow, so all 66 theorems are now PROVED (sorry-free; choice_free honestly surfaced). The map still carries no proof-status field — status stays exporter-only, and CI/tests keep asserting the pairing, not values. Rebased onto main to pick up the audit_packet pass-through (27dc1d8). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Also: tests/test_frontier.py's three tests require the uncommitted lean-ethtotal/health.json export and have broken main's CI since 27dc1d8; they now skip with a reason where the artifact is absent (and still run wherever it exists).
9e2f102 to
f60dfad
Compare
…arithmetic predicates, proofs (speca#146) Review response (grandchildrice, CHANGES_REQUESTED): 1. Conclusion guards no longer leak into must-establish (was 29/130, now 0/115, all named): every conclusion is a single application of a named Common predicate (two disclosed closed-form exceptions), and the exporter's A2 heuristic gains an opt-in rule 4 — anonymous (hygienic) Prop binders classify as context-precondition, never must-establish, and B1 never lowers them (ProjectConfig.contextualizeAnonymousGuards, enabled only for ethVulnConfig; gasper has zero anonymous binders and EthTotal — 17 of them — keeps its historical classification byte-stable). 2. ArithAgrees — satisfiable by the vulnerable wrapping implementations it was meant to exclude — is replaced by AgreesModWidth (full-domain exact modulo-2^n semantics, spec side PINNED to a concrete function: Nat.+ for uint64, Common.evmCallGas = the EIP-150 63/64 model for the Besu CALL-gas entries, so a narrowing implementation cannot choose the spec to match itself) and CheckedArith/AcceptedExact (Option-valued checked arithmetic; overflow must be detected, wrapping cannot satisfy it). EVM shift/MULMOD entries state the spec clauses (ShiftSaturates/SarSaturates at the spec's full shift >= 256 domain, MulModZeroTotal) and are proved. 3. The tautological availability hTotal (11/15 theorems were P -> P) is decomposed into RejectsMalformed (malformed input rejected with state rollback) + TotalOnWellFormed (well-formed input processed totally; exhaustion lands in a defined, state-preserving reject); NeverCrashes is derived via Common.neverCrashes_of_split. The two undisclosed Grandine spec-equivalence identities are strengthened to AgreeOnObservation on the entry's divergence surface (registry view / head selection). Modeling choices are stated in docstrings. 4. Every map entry carries a per-entry x_spec_anchor (20 anchored to consensus-/execution-specs with x_spec_symbol, 46 explicit 'N/A — category: reason'; curation in data/ethvuln_spec_anchors.json) and a deterministic audit_packet (tools/ethvuln-build-packets.py, no LLM, idempotent): guarantee, an explicit obligations key (the named must-establish hypotheses, exact Lean types), class-tagged preconditions, and one exact supporting fact per obligation (FACT-OB*) plus the root fact. data/anchor_map.json gains a beacon-chain:execution-payload row; 10 map assertions are updated to the new predicates; CI gains a map staleness gate mirroring the EthTotal one. Consequence of 1-3: every implication became shallow, so all 66 theorems are now PROVED (sorry-free; choice_free honestly surfaced). The map still carries no proof-status field — status stays exporter-only, and CI/tests keep asserting the pairing, not values. Rebased onto main to pick up the audit_packet pass-through (27dc1d8). Also: tests/test_frontier.py's three tests require the uncommitted lean-ethtotal/health.json export and have broken main's CI since 27dc1d8; they now skip with a reason where the artifact is absent (and still run wherever it exists). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
f60dfad to
e57ded5
Compare
|
4つの指摘、すべてに対応しました。
以下、補足です:
この整理で問題ないか見ていただきたいです!確認お願いします。 |
|
仕様アンカー / dataset 忠実性の観点(#issuecomment-5312990851)への返信です。
|
speca#146(トラック c / フェーズ①)の成果。
NyxFoundation/ethereum-vuln-datasetの critical/high 全 66 エントリ(CRITICAL 3 / HIGH 63、dataset refc7c4ccbc46aaaeb8b4d3abf18a81f587d2ba017e)について、各バグが破っていた不変条件を Lean 4 の命題として形式化し、lean/SpecaExport/EthVuln/に配置して 専用 maptheorem_map_ethvuln.jsonに登録する(第 3 トラック。gasper のtheorem_map.jsonは無変更)。レビュー対応(改訂 2 の内容)
forallTelescopeで平坦化するため、∀ c k, k < len c → …形の結論からガードが漏れ、must-establish 130 件中 29 件(約 22%)が入力・文脈条件だった。全定理の結論を Common の名前付き述語 1 適用(AccessesInBounds/SpecEquivOn/AcceptanceCarriesOver/AcceptsOnlyValid/OnAccept/PreservesInvOnTrace/GrantedOnlyVerified…)に畳み、加えて exporter の A2 ヒューリスティックに rule 4: 匿名(hygienic 名)Prop 束縛子 →context-preconditionを追加した(ProjectConfig.contextualizeAnonymousGuardsによる opt-in、有効なのは ethvuln トラックのみ。gasper は該当 0 件、EthTotal は既存分類を維持 — 匿名ガード 17 件があるため、opt-in はメンテナ判断に委ねる)。結果: must-establish は 115 件・全件が名前付きの実装義務、context-precondition は 0 件(規約で畳み切ったため)。tests/test_ethvuln.pyが両方を回帰ピンする。ArithAgreesは「数学的結果が幅に収まる場合のみ一致」を要求するため、脆弱な wrapping 実装自身が仮定と結論の両方を満たしてしまっていた(websocket / geth p2p / Juno の 3 件で、定理が対象のバグを排除できていなかった)。廃止し 2 系統に分離:AgreesModWidth(全定義域での mod-2^n 厳密一致。仕様自体が modulo 意味論を定める consensus uint64 / EVM ガスワード用)とCheckedArith/AcceptedExact(Option値の checked 演算 — オーバーフローは必ず検出。wrapping 実装はsomeを返し続けるため満たせない)。重要な点として、AgreesModWidth 系の spec 側は自由パラメータにせず具体関数に固定した(uint64 加算はNat.+、Besu CALL ガス 2 件は Common のevmCallGas= EIP-150 の 63/64 ルール + min のモデル)— spec を自由にすると縮小実装が spec を自分に合わせて選べてしまい、排除にならないため。EVM のシフト / MULMOD は仕様条項そのもの(ShiftSaturates/SarSaturates/MulModZeroTotal。シフトの閾値は仕様どおり 256 以上の全域とし、ビット 31 の値はその部分域として docstring に記録)を述べ、仕様モデル上で証明した。hTotalはNeverCrashesの言い換えだった(15 件中 11 件が実質P → P)。実装が守る具体的な 2 条件 —RejectsMalformed(malformed 入力は状態を変えずに正常拒否 = パース/検証の全域性 + ロールバック)とTotalOnWellFormed(整形式入力の全域処理。リソース枯渇・内部エラーも状態を保存する定義済み拒否に落ちる)— に分解し、NeverCrashesは補題neverCrashes_of_splitで導出。詳細非公開エントリではこの段階分解がモデリング選択であり dataset の記載事実ではないことを各 docstring に明記した。x_spec_anchorを付与: protocol semantics に対応する 20 件は consensus-specs / execution-specs の section +x_spec_symbol(例: MULMOD →execution-specs:…/vm/instructions/arithmetic.py::mulmod、Lodestar AttesterSlashing →consensus-specs:specs/phase0/beacon-chain.md::process_attester_slashing)、仕様対象外の 46 件は 明示的なN/A — <category>: <reason>(dependency-library 19 / client-internal 9 / rpc-api 8 / networking-devp2p 6 / undisclosed 4)として実装安全性側に区分。キュレーションはdata/ethvuln_spec_anchors.jsonに収載。ラベルテーブルにもbeacon-chain:execution-payload行を追加(beacon-chain:sync-committeeは当該 1 件のラベル自体が dataset 側で誤りのため行を追加せず、per-entry アンカーでprocess_effective_balance_updatesを指す — upstream 再キュレーション候補)。汎用形で覆ったエントリの docstring には entry 固有条件と抽象化部分を明記した。audit_packet(tools/ethvuln-build-packets.py、LLM 不使用・冪等)。指摘の三分割をキーとして明示した:guarantee= Lean の結論そのもの、obligations= 実装が確立すべき性質(must-establish 仮説の名前と正確な型)、preconditions= A2 クラスタグ付きの全仮説リスト(EthTotal 互換の表現)、supporting_facts= ルート結論の exact fact + 実装義務 1 件ごとの exact fact(FACT-OB*)。emit-01e で全 118 プロパティに載る。packet は proof status を持たない(status は従来どおり exporter のみ)。CI の lean ジョブに staleness ゲート(export した health +data/ethvuln_spec_anchors.jsonから packet/アンカーを再生成してgit diff --exit-code theorem_map_ethvuln.json、EthTotal の gate と同形)を追加した。あわせて map のassertion文 10 件(算術 9 + memory-safety 1)を新述語に一致するよう更新した。正直な残余(先に自己申告しておく):
SpecEquivOn → SpecEquivOnの恒等になっていたため、エントリ固有の観測(2.0.5 = エポック遷移後のレジストリ観測、2.0.4 = ヘッド選択)での一致AgreeOnObservationを結論とする形に強化した。must-establish は仕様準拠hConformのまま。eff1234(jsonparser OOB read)は「読み取り前の境界チェック」という修正が破られた不変条件そのものなので、含意は定義の展開である(docstring に明記。監査内容は must-establish 側)。a528f48の定数不等式400 * 1024 ≤ implMaxProofSizeとGHSA-7pg2の連言ShiftSaturates ∧ SarSaturates(いずれもガードなしの閉形式、docs に記載)。変更内容
lean/SpecaExport/EthVuln/Common.leanAgreesModWidth/CheckedArith+AcceptedExact)、availability 分解(RejectsMalformed/TotalOnWellFormed)、resource 3 条件(UsageAccounted/AdmissionControlled/RejectFrees)、受理事後条件(OnAccept/AcceptsOnlyValid)、spec-equiv 系(Agree/AcceptanceCarriesOver/AgreeOnObservation/ProducesSpecValid/PreservesInvOn/PreservesInvOnTrace)、crypto 系(RejectsInvalid/GrantedOnlyVerified/EstablishedAreValid)と、それらの分解補題(証明付き)lean/SpecaExport/EthVuln/Props/*.leanlean/SpecaExport/Basic.leancontext-precondition、contextualizeAnonymousGuardsopt-in、ethvuln のみ有効)lean/MainEthVuln.lean+lean/lakefile.leanlake exe speca-export-ethvuln(前回どおり)theorem_map_ethvuln.jsonx_spec_anchor/x_spec_symbol+audit_packet。proof status 用フィールドは引き続き持たないdata/ethvuln_spec_anchors.jsondata/anchor_map.jsonbeacon-chain:execution-payload行を追加(+14 行のみ)tools/ethvuln-build-packets.pysrc/speca_lean4/cli.py_run_leanが map のlean_exe/x_src_rootsを尊重(前回どおり)src/speca_lean4/health.pycontext_preconditionsアクセサtests/test_ethvuln.pyほかREADME.md,docs/ethvuln-track.md,docs/pipeline.mdクラス別内訳(66 件、変更なし): availability-robustness 15 / resource-bounds 14 / spec-equivalence 13 / arithmetic-safety 9 / memory-safety 4 / input-validation 4 / crypto-auth-integrity 4 / state-integrity 2 / serialization-fidelity 1。
proof status
全 66 定理が証明済み(
sorryなし)になった。 ただし枠づけを正直に: この証明は設計上「浅い」。再定式化の目的が「監査内容を仮説側に、保証される不変条件を結論側に正しく配ること」であり、その帰結として含意が数行の補題適用になった、というのが実体である。provedが保証するのは (a) その含意、(b) Common の分解補題群(neverCrashes_of_split・boundedUsage_of_admission・リスト帰納法など、小さいが実内容のある部分)、(c) 命題群が整合的で空虚でないこと — であって、実クライアントが義務を満たすかどうかはまさに 02c の監査対象である(must-establish 分解された 115 プロパティがその作業項目)。**issue #146 の「proved」完了条件を字義上は満たすが、その実体は上記のとおりなので、完了判定は issue 側の判断に委ねたい。**map は引き続き proof status を一切持たず、status は exporter(health JSON)だけが決める。CI・テストは値ではなく pairing(proved⇔sorry_free)と「emit された status = exporter の status」を検証するので、sorryへの退行も今日のprovedと同じ正直さで報告される。なお一部の定理は分解補題経由でClassical.choiceに依存する(choice_free=false18 件、exporter が正直に表示)。検証
ci.yml の lean / python / run-lean-e2e 各ジョブの ethvuln ステップはローカルでそのまま再生して exit 0 を確認(
--run-lean経路含む)。レビューで見てほしい点(改訂 2)
context-precondition分類は opt-in にし、gasper / EthTotal の既存 export をバイト安定に保った。EthTotal には匿名ガードが 17 件あるため、opt-in するかは EthTotal 側の判断として分離した。この整理で良いかRejectsMalformed+TotalOnWellFormedは提示いただいた malformed input / resource exhaustion / state rollback を仮説側(= B2 で 01e の監査項目になる側)に置く設計。conclusion 側は導出されたNeverCrashes。この配置で意図に合っているか42783aef(Reth 1.0 リリースノート、脆弱性ではない)とGHSA-wm9c(ラベルbeacon-chain:sync-committeeだが実体は Electra effective-balance)は ethereum-vuln-dataset 側の再キュレーション候補として挙げたい補足
banr1/eth-vuln-formal-props(private)には本改訂の Lean ソースと map 生成の追随を別途同期するRefs NyxFoundation/speca#146