This file is the authoritative registry of axioms used by Verity proof code.
Axioms are exceptional. When an axiom exists, it must have:
- Explicit documentation in this file.
- Source comment marking it as an axiom and linking to this file.
- CI checks that validate usage assumptions.
- A clear elimination path, when practical.
None. Verity has zero project-level Lean axioms.
- Active axioms: 0
The last remaining axiom (solidityMappingSlot_lt_evmModulus) was eliminated
by replacing the opaque FFI-based keccak256 call with the kernel-computable
Keccak engine (Compiler/Keccak/Sponge.lean), which exposes the 32-byte
output-length guarantee to Lean's proof system.
Former location: Compiler/Proofs/MappingSlot.lean:125
Former statement:
axiom solidityMappingSlot_lt_evmModulus (baseSlot key : Nat) :
solidityMappingSlot baseSlot key < Compiler.Constants.evmModulusHow it was eliminated:
solidityMappingSlotwas redefined to useKeccakEngine.keccak256(kernel-computable) instead offfi.KEC(opaque FFI).squeeze256_sizeproves the output is always exactly 32 bytes.fromByteArrayBigEndian_lt_of_sizeproves a ≤32-byte big-endian value is < 2^256.- The axiom became a theorem:
solidityMappingSlot_lt_evmModulusis now proved, not assumed.
Runtime performance: An @[implemented_by] annotation optionally redirects to
the FFI version at runtime for speed, without affecting proof soundness.
Verity currently has zero project-level Lean axioms, but some proofs and tests intentionally rely on Lean mechanisms that sit outside ordinary kernel elaboration:
native_decideproofs depend on Lean's native code generation and the builtinLean.ofReduceBoolaxiom. They are acceptable for executable smoke tests, concrete bridge checks, and explicitly documented reduction witnesses, but they are tracked as trusted reduction surface rather than counted as project-level axioms.@[implemented_by ...]may redirect runtime execution to a faster implementation. The proof term still sees the kernel-computable definition, so this is a runtime/codegen trust boundary rather than a Lean axiom.partial defmarks recursive executable helpers whose termination is not kernel-proved. These helpers are allowed in macro, codegen, reporting, and native-test infrastructure, and their presence is registry-gated.
CI runs scripts/check_trust_surface_registry.py to ensure these mechanisms and
all explicit ECM assumptions (axioms := [...]) remain documented when their
source footprint changes.
Function selector derivation (bytes4(keccak256(signature))) was previously
axiomatic. It is now kernel-computable via the vendored unrolled Keccak engine
in Compiler/Keccak/ and Compiler/Selectors.lean.
The generic body-simulation axiom in Layer 2 was eliminated through explicit
proof work (issue #1618). supported_function_correct is now a real theorem.
The dispatch bridge in Layer 3 was converted from a Lean axiom to an explicit
theorem hypothesis in Compiler/Proofs/YulGeneration/Preservation.lean.
Location: Compiler/Selectors.lean, Compiler/Keccak/*.lean
Role:
Computes function selectors (bytes4(keccak256(signature))) inside Lean's
kernel using a vendored unrolled Keccak-256 engine. This is now a definitional
computation, not a Lean axiom.
Soundness controls:
- Fixed selector examples in
Compiler/Selectors.lean. - CI cross-checks selectors against
solc --hashes. - Selector fixture checks still run as defense in depth.
Location: Compiler/Proofs/MappingSlot.lean, Compiler/Keccak/*.lean
Role:
Computes mapping storage slots as keccak256(abi.encode(key, baseSlot)) using
the same kernel-computable Keccak engine. The output-length bound is proved
structurally via Compiler/Keccak/SpongeProperties.lean.
What we trust:
- The kernel Keccak implementation matches the EVM's keccak256 (CI cross-checked).
- Two different inputs won't hash to the same slot (standard cryptographic assumption — Solidity makes the same one).
Soundness controls:
- Mapping-slot abstraction boundary checks in CI.
- End-to-end regression suites that exercise mapping reads/writes.
- CI cross-checks kernel Keccak output against FFI Keccak output.
Location: Compiler/Proofs/IRGeneration/SourceSemantics.lean
(keccakMemorySlice, memorySliceBytesBE, and the .keccak256 arms of
evalExpr / evalExprWithHelpers).
Role:
The executable source semantics evaluates Expr.keccak256 offset size by reading
the RuntimeState memory as 256-bit words at offset, offset+32, …,
concatenating them big-endian, truncating the result to size bytes, and hashing
with the in-tree KeccakEngine.keccak256. Previously this expression evaluated to
none (modeled as a revert), so any contract performing a native keccak256 fell
outside the modeled fragment; it is now executably modeled.
What we trust (keccak256_memory_slice_matches_evm):
Verity's compiled output writes scratch memory in whole 32-byte words (mstore),
so reading whole words and truncating the big-endian concatenation to size bytes
reproduces the EVM's byte-addressed keccak256(offset, size) preimage exactly. The
RuntimeState memory is word-keyed, so sub-word / byte-granular aliasing is not
modeled; this is faithful for the word-aligned access shape Verity emits and is the
same assumption already surfaced in --trust-report for Expr.keccak256.
Soundness controls:
- Reuses the same kernel-computable
KeccakEngine.keccak256that CI cross-checks against FFI/EVM keccak; no new hash implementation is introduced. keccakMemorySliceis an ordinary computable definition, not an axiom: it adds noaxiom/sorryto the trust surface.
Location:
Compiler/Proofs/YulGeneration/Backends/EvmYulLean*.lean,
lake-manifest.json, artifacts/evmyullean_fork_audit.json
Role: EVMYulLean is the authoritative Yul runtime target for the safe-body EndToEnd retargeting path. This is not a Lean axiom: Verity proves the adapter, builtin bridge, recursive target equality, safe-body closure, and public EndToEnd wrappers in Lean, then trusts that the pinned EVMYulLean execution model matches the EVM.
What we trust:
- The pinned
lfglabs-dev/EVMYulLeanfork matches the intended EVM/Yul semantics inherited from upstreamNethermindEth/EVMYulLean. - The audited fork delta remains non-semantic unless explicitly reviewed.
Soundness controls:
make checkvalidates the fork-audit artifact againstlake-manifest.json.make test-evmyullean-forkrechecks the fork audit, checks the adapter report, rebuilds the native transition harness, the public EndToEnd EVMYulLean target, and the concretenative_decidebridge-equivalence tests..github/workflows/evmyullean-fork-conformance.ymlruns the conformance probe weekly; scheduled or manual failures fail the workflow and open or update a GitHub issue for drift triage.
When your contract calls an external contract (like an ERC-20 token), Verity can't prove that the other contract works correctly. Instead, it documents the assumption: "we assume this address implements the expected interface."
These are not proof-system axioms — they are interface assumptions scoped
to contracts that use the module. The compiler lists all of them at compile
time in --verbose output. Use --deny-unchecked-dependencies to make
compilation fail if any assumption hasn't been reviewed.
Independently of the ECM interface assumptions above, the EVM frame
condition that an external CALL cannot mutate the caller's storage,
transient storage, or memory outside the declared output buffer is now a
theorem of Verity.EVM.Frame, no longer an assumption. The relevant
results are:
Verity.EVM.Frame.external_call_preserves_caller_storageVerity.EVM.Frame.external_call_preserves_caller_transient_storageVerity.EVM.Frame.external_call_preserves_caller_memory_outside_output_bufferVerity.EVM.Frame.external_call_preserves_caller_memory(disjoint-region form)- their iterated-CALL variants
Verity.EVM.Frame.external_calls_preserve_*
The theorems quantify universally over Verity.EVM.Frame.CalleeResult,
which is the observational interface of any EVM callee program. Downstream
contract proofs can consume these theorems directly to discharge the EVM
frame condition without re-stating it.
The abstract memory model on which these theorems compose lives at
Verity.EVM.MemoryModel; the standard solc memory-layout schema and the
call-buffer-disjoint-from-heap theorem live at Verity.EVM.Layout.
| Module | Assumption | Meaning |
|---|---|---|
ERC20.safeTransfer |
erc20_transfer_interface |
Target implements ERC-20 transfer(address,uint256) |
ERC20.safeTransferFrom |
erc20_transferFrom_interface |
Target implements ERC-20 transferFrom(address,address,uint256) |
ERC20.safeApprove |
erc20_approve_interface |
Target implements ERC-20 approve(address,uint256) |
ERC20.solmateSafeTransfer |
erc20_solmate_safe_transfer_interface |
Target implements ERC-20 transfer(address,uint256); optional-return acceptance follows Solmate SafeTransferLib |
ERC20.solmateSafeTransferFrom |
erc20_solmate_safe_transferFrom_interface |
Target implements ERC-20 transferFrom(address,address,uint256); optional-return acceptance follows Solmate SafeTransferLib |
ERC20.legacyStringSafeTransfer |
erc20_legacy_string_safe_transfer_interface |
Target implements ERC-20 transfer(address,uint256); uses legacy string Error("...") reverts + extcodesize check (Morpho-style) |
ERC20.legacyStringSafeTransferFrom |
erc20_legacy_string_safe_transferFrom_interface |
Target implements ERC-20 transferFrom(address,address,uint256); uses legacy string Error("...") reverts + extcodesize check (Morpho-style) |
ERC20.balanceOf |
erc20_balanceOf_interface |
Target implements balanceOf(address) and returns a uint256 |
ERC20.allowance |
erc20_allowance_interface |
Target implements allowance(address,address) and returns a uint256 |
ERC20.totalSupply |
erc20_totalSupply_interface |
Target implements totalSupply() and returns a uint256 |
ERC4626.previewDeposit |
erc4626_previewDeposit_interface |
Target implements previewDeposit(uint256) and returns a uint256 |
ERC4626.previewMint |
erc4626_previewMint_interface |
Target implements previewMint(uint256) and returns a uint256 |
ERC4626.previewWithdraw |
erc4626_previewWithdraw_interface |
Target implements previewWithdraw(uint256) and returns a uint256 |
ERC4626.previewRedeem |
erc4626_previewRedeem_interface |
Target implements previewRedeem(uint256) and returns a uint256 |
ERC4626.convertToAssets |
erc4626_convertToAssets_interface |
Target implements convertToAssets(uint256) and returns a uint256 |
ERC4626.convertToShares |
erc4626_convertToShares_interface |
Target implements convertToShares(uint256) and returns a uint256 |
ERC4626.totalAssets |
erc4626_totalAssets_interface |
Target implements totalAssets() and returns a uint256 |
ERC4626.asset |
erc4626_asset_interface |
Target implements asset() and returns an address |
ERC4626.maxDeposit |
erc4626_maxDeposit_interface |
Target implements maxDeposit(address) and returns a uint256 |
ERC4626.maxMint |
erc4626_maxMint_interface |
Target implements maxMint(address) and returns a uint256 |
ERC4626.maxWithdraw |
erc4626_maxWithdraw_interface |
Target implements maxWithdraw(address) and returns a uint256 |
ERC4626.maxRedeem |
erc4626_maxRedeem_interface |
Target implements maxRedeem(address) and returns a uint256 |
ERC4626.deposit |
erc4626_deposit_interface |
Target implements deposit(uint256,address) and returns a uint256 |
Oracle.oracleReadUint256 |
oracle_read_uint256_interface |
Target implements the selected oracle read interface and returns a uint256 |
Precompiles.ecrecover |
evm_ecrecover_precompile |
EVM precompile at address 0x01 behaves per Yellow Paper |
Precompiles.sha256Memory / Precompiles.sha256 |
evm_sha256_precompile |
EVM precompile at address 0x02 behaves per Yellow Paper |
Precompiles.bn256Add |
evm_bn256_add_precompile |
EVM precompile at address 0x06 behaves per EIP-196 (BN254 point addition) |
Precompiles.bn256ScalarMul |
evm_bn256_scalar_mul_precompile |
EVM precompile at address 0x07 behaves per EIP-196 (BN254 scalar multiplication) |
Precompiles.bn256Pairing |
evm_bn256_pairing_precompile |
EVM precompile at address 0x08 behaves per EIP-197 (BN254 optimal-Ate pairing) |
Callbacks.callback |
callback_target_interface |
Callback target processes ABI-encoded arguments correctly |
Calls.withReturn |
external_call_abi_interface |
Target contract function matches declared selector and ABI |
Calls.callWithValue / Calls.callWithValueBytes |
generic_call_with_value_interface |
Target accepts caller-provided calldata and ETH value; failures bubble returndata |
Calls.bubblingValueCall / Calls.bubblingValueCallNoOutput |
generic_low_level_value_call_interface |
Generic low-level call mechanics are emitted; calldata and successful returndata meaning remain package assumptions |
Hashing.abiEncodeStaticWords |
keccak256_memory_slice_matches_evm, abi_standard_static_word_layout |
Static ABI words are laid out contiguously before Keccak |
Hashing.abiEncodePackedWords / Hashing.abiEncodePacked |
keccak256_memory_slice_matches_evm, abi_packed_static_word_layout |
Static packed words are laid out contiguously before Keccak |
Hashing.abiEncodeStaticArray |
keccak256_memory_slice_matches_evm, abi_standard_dynamic_array_static_element_layout |
Single dynamic-array ABI encoding with static-width elements is laid out before Keccak |
Hashing.abiEncodePackedStaticSegments |
keccak256_memory_slice_matches_evm, abi_packed_static_segment_layout |
Static packed byte-width segments are laid out before Keccak |
Hashing.eip712Digest |
keccak256_memory_slice_matches_evm, eip712_digest_layout |
Final EIP-712 typed-data preimage is laid out as `0x1901 |
Hashing.sha256PackedWords / Hashing.sha256Packed |
evm_sha256_precompile, abi_packed_static_word_layout |
Static packed words are laid out before SHA-256 precompile call |
Hashing.sha256PackedStaticSegments |
evm_sha256_precompile, abi_packed_static_segment_layout |
Static packed byte-width segments are laid out before SHA-256 precompile call |
| Fixture | Assumption | Meaning |
|---|---|---|
Compiler.CompileDriverTest |
test_call_interface |
Synthetic compile-driver fixture for ECM trust reporting |
Compiler.CompileDriverTest |
ctor_hook_interface |
Synthetic constructor fixture for ECM trust reporting |
Third-party ECMs (external Lean packages) document their assumptions in their own
AXIOMS.md. All assumptions — standard and third-party — are listed at compile
time. See docs/EXTERNAL_CALL_MODULES.md for details.
Risk: Low. These are interface assumptions (not proof-system extensions) scoped to contracts that use the module.
All 25 pure EVM arithmetic builtins have universal bridge equivalence lemmas
(all 25 fully proven).
The proofs show that Verity's arithmetic matches EVM arithmetic (wrapping at
2^256) for all possible inputs, not just test cases. The EVMYulLean bridge
currently has universal equivalence lemmas for 25 of them (add, sub, mul,
div, mod, addmod, mulmod, exp, sdiv, smod, lt, gt, slt, sgt, eq, iszero, and, or,
xor, not, shl, shr, sar, signextend, byte),
with no remaining pure builtins relying only on concrete bridge checks.
Additionally, 8 higher-level expression operators have proven compilation
correctness in the ExprCompileCore fragment: min, max, ceilDiv, ite
(conditional), wMulDown, wDivUp, mulDivDown, and mulDivUp. See
docs/ARITHMETIC_PROFILE.md for the full
specification.
Intrinsics do not add project-level Verity axioms. Each verity_intrinsic
declaration names a consumer-owned obligation in its obligation [...] clause
and records that obligation next to the generated consumer semantic wrapper.
While that obligation is assumed, the consumer repository must document it in
its own AXIOMS.md or equivalent trust-boundary document.
For example, a Tamago CLZ intrinsic should document the consumer-side
clz_matches_eip7939 assumption: the Lean semantics function used by Tamago
proofs matches the EIP-7939 opcode emitted as verbatim_1i_1o(hex"1e", x) on
chains that support Osaka-or-later execution semantics.
These obligations are outside this registry because they are not axioms in the
Verity project. Future consumer trust reports should surface them
machine-readably; until that integration exists, review them by grepping
consumer code for verity_intrinsic.
The Verity-side proof module Compiler.Proofs.IRGeneration.IntrinsicProofs
proves only compiler-owned plumbing around the generic intrinsic path:
argument scope accounting, verbatim/builtin lowering shape, fork-order facts,
arity rejection, and the fail-closed min_fork predicate used by the compiler
fork gate. It adds no axiom asserting that any emitted opcode implements the
declared consumer semantics. The current end-to-end proven fragment remains
fail-closed over intrinsics: SupportedSpec and helper-aware source semantics
classify Expr.intrinsic as unsupported/unmodeled until an opcode semantics
proof exists.
- Active project-level axioms: 0
- Production blockers from project-level axioms: 0
- Consumer intrinsic obligations: owned and documented by consumer packages
- Enforcement:
scripts/check_axioms.pyensures this file tracks exact source locations. - All internal compiler functions are proven to terminate (no axioms involved).
- The macro front-end and typed-IR pipeline do not use any
axioms. The typed-IR compiler has zero
sorry.
Any commit that adds, removes, renames, or moves a project-level axiom must update this file in the same commit. Any commit that changes intrinsic trust semantics must update this file, TRUST_ASSUMPTIONS.md, and AUDIT.md.
If this file is stale, trust analysis is stale.
Last Updated: 2026-05 (intrinsics addition)