Goal
Make EVMYulLean's native Yul runtime/interpreter the authoritative Layer 3 execution target for Verity-generated runtime Yul, instead of executing Verity's custom Yul statement interpreter with an EVMYulLean-backed builtin backend.
This follows up #1722, which was auto-closed by #1725. #1725 substantially improved the EVMYulLean builtin bridge, but it did not switch Verity to EvmYul.Yul.exec / EvmYul.Yul.callDispatcher as the runtime target.
Current status after #1725
- Verity has EVMYulLean-backed builtin coverage for the current safe fragment.
- The public Layer 3 retargeting path still runs Verity-shaped
YulStmt, YulState, and YulResult through interpretYulRuntimeWithBackend .evmYulLean.
- The EVMYulLean-native interpreter exists and builds:
EvmYul.Yul.eval
EvmYul.Yul.exec
EvmYul.Yul.execTopLevel
EvmYul.Yul.callDispatcher
- The existing adapter is structural, not a complete native-runtime bridge.
Required migration plan
Phase 1: Native runtime harness
Add a separate native execution path without disturbing the proven #1725 path yet.
- Implement primop-aware lowering from Verity Yul expressions to EVMYulLean expressions.
- Known builtins must lower to
.Call (.inl primOp) ... using lookupPrimOp or an explicit verified mapping.
- Unknown names should remain
.Call (.inr functionName) ... for user/helper Yul functions.
- Lower generated runtime code into an EVMYulLean
YulContract.
- Partition top-level function definitions into
YulContract.functions.
- Put non-function top-level runtime statements into the dispatcher.
- Build a native initial-state bridge from Verity transaction/state inputs into
EvmYul.Yul.State.Ok.
- Install the current contract code in the native account/code map.
- Populate calldata, callvalue, caller/source, address, storage, memory, returndata, block/env fields, and static-call permissions.
- Define native result projection back to Verity's observable
YulResult shape.
- Return/stop/revert status
- Return data/value projection
- Storage changes and revert rollback
- Logs/events
- Add executable smoke tests around
EvmYul.Yul.exec / EvmYul.Yul.callDispatcher for return, storage, dispatcher selection, mapping helpers, and event logs.
Backup option: keep this as a CI smoke-test runner first, while #1725's theorem remains the public target.
Phase 2: Bridge native execution to current observable semantics
- Prove syntactic lowering invariants:
- no top-level
funcDef remains in the dispatcher,
- helper functions are present in
YulContract.functions,
- builtin calls lower to native primops.
- Prove state bridge lemmas for calldata, selector, sender/source, callvalue, address, block fields, storage lookup, memory, and returndata.
- Prove result projection lemmas for return, stop, revert, storage, and logs.
Backup option: start with a read-only/no-storage fragment, then widen to storage and events.
Phase 3: Add a public native target theorem
Introduce a native target function, conceptually:
interpretYulRuntimeNativeEvmYulLean :
List Compiler.Yul.YulStmt →
YulTransaction →
(Nat → Nat) →
List (List Nat) →
YulResult
Internally this should lower to an EVMYulLean YulContract, build native state, run EvmYul.Yul.callDispatcher or EvmYul.Yul.exec, and project the result.
Then prove the Layer 3 preservation theorem against this native target for the same safe fragment covered by #1725.
Backup option: first prove equivalence between interpretYulRuntimeWithBackend .evmYulLean and the native target, then retarget Layer 3 directly later.
Phase 4: Flip the trusted path
- Make the native EVMYulLean theorem the canonical end-to-end target.
- Move Verity's custom Yul interpreter to reference-oracle/regression-test status.
- Update
TRUST_ASSUMPTIONS.md to document EVMYulLean as the semantic trust boundary.
- Keep the old interpreter for one release cycle as a cross-check.
Phase 5: Cleanup and upstream/fork work
- Delete or archive the old interpreter only after the proof imports no longer depend on it.
- Push any required EVMYulLean fork fixes upstream where appropriate.
- Add conformance/cross-check CI coverage for the native path.
Known blockers / design questions
- The current adapter lowers all calls as user functions, which fails native execution for builtins such as
add.
- Top-level function definitions are currently not preserved as EVMYulLean contract functions.
- Full native state construction and result projection are incomplete.
- Runtime Yul is the right first target. Deploy/object-code intrinsics such as
dataoffset, datasize, and datacopy should stay out of the initial migration.
- Review the EVMYulLean fork for missing primops/notations such as
log0, external-call failure semantics, nested static-call behavior, and whether execTopLevel erases too much information for proof use.
Success criteria
Related
Goal
Make EVMYulLean's native Yul runtime/interpreter the authoritative Layer 3 execution target for Verity-generated runtime Yul, instead of executing Verity's custom Yul statement interpreter with an EVMYulLean-backed builtin backend.
This follows up #1722, which was auto-closed by #1725. #1725 substantially improved the EVMYulLean builtin bridge, but it did not switch Verity to
EvmYul.Yul.exec/EvmYul.Yul.callDispatcheras the runtime target.Current status after #1725
YulStmt,YulState, andYulResultthroughinterpretYulRuntimeWithBackend .evmYulLean.EvmYul.Yul.evalEvmYul.Yul.execEvmYul.Yul.execTopLevelEvmYul.Yul.callDispatcherRequired migration plan
Phase 1: Native runtime harness
Add a separate native execution path without disturbing the proven #1725 path yet.
.Call (.inl primOp) ...usinglookupPrimOpor an explicit verified mapping..Call (.inr functionName) ...for user/helper Yul functions.YulContract.YulContract.functions.EvmYul.Yul.State.Ok.YulResultshape.EvmYul.Yul.exec/EvmYul.Yul.callDispatcherfor return, storage, dispatcher selection, mapping helpers, and event logs.Backup option: keep this as a CI smoke-test runner first, while #1725's theorem remains the public target.
Phase 2: Bridge native execution to current observable semantics
funcDefremains in the dispatcher,YulContract.functions,Backup option: start with a read-only/no-storage fragment, then widen to storage and events.
Phase 3: Add a public native target theorem
Introduce a native target function, conceptually:
Internally this should lower to an EVMYulLean
YulContract, build native state, runEvmYul.Yul.callDispatcherorEvmYul.Yul.exec, and project the result.Then prove the Layer 3 preservation theorem against this native target for the same safe fragment covered by #1725.
Backup option: first prove equivalence between
interpretYulRuntimeWithBackend .evmYulLeanand the native target, then retarget Layer 3 directly later.Phase 4: Flip the trusted path
TRUST_ASSUMPTIONS.mdto document EVMYulLean as the semantic trust boundary.Phase 5: Cleanup and upstream/fork work
Known blockers / design questions
add.dataoffset,datasize, anddatacopyshould stay out of the initial migration.log0, external-call failure semantics, nested static-call behavior, and whetherexecTopLevelerases too much information for proof use.Success criteria
EvmYul.Yul.exec/callDispatcher.YulContractwith dispatcher and functions.TRUST_ASSUMPTIONS.mdreflects the reduced trusted surface.Related