{"id":15638694,"url":"https://github.com/leonardoalt/dl_symb_exec_sol","last_synced_at":"2025-04-19T12:15:12.688Z","repository":{"id":38321428,"uuid":"456494665","full_name":"leonardoalt/dl_symb_exec_sol","owner":"leonardoalt","description":"Symbolic execution engine written in Solidity, based on Difference Logic.","archived":false,"fork":false,"pushed_at":"2022-10-06T14:59:04.000Z","size":38,"stargazers_count":111,"open_issues_count":0,"forks_count":6,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-03-12T18:04:11.863Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Solidity","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/leonardoalt.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2022-02-07T12:23:33.000Z","updated_at":"2025-01-14T14:10:30.000Z","dependencies_parsed_at":"2022-08-17T16:05:41.540Z","dependency_job_id":null,"html_url":"https://github.com/leonardoalt/dl_symb_exec_sol","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/leonardoalt%2Fdl_symb_exec_sol","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/leonardoalt%2Fdl_symb_exec_sol/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/leonardoalt%2Fdl_symb_exec_sol/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/leonardoalt%2Fdl_symb_exec_sol/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/leonardoalt","download_url":"https://codeload.github.com/leonardoalt/dl_symb_exec_sol/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246156025,"owners_count":20732357,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-03T11:22:30.708Z","updated_at":"2025-03-30T21:31:52.490Z","avatar_url":"https://github.com/leonardoalt.png","language":"Solidity","funding_links":[],"categories":[],"sub_categories":[],"readme":"**This code base is not meant to be used seriously, it's only a study.**\n========================================================================\n\nEVM Symbolic Execution in Solidity\n==================================\n\nThis repo contains an experimental symbolic execution engine implemented in\nSolidity.\nIf you write smart contracts in Solidity and write your tests also in Solidity,\nthe analysis runs simply as part of the test suite, itself being a test\nlibrary.\nTherefore, any framework that allows tests in Solidity should be able to run\nthis symbolic execution, without any extra tooling.\nSince that code is not going to be deployed anyway we don't care about gas.\n\nThe VM opcode handling part was inspired by\nhttps://github.com/Ohalo-Ltd/solevm.\n\nAnalysis\n--------\n\nDuring the symbolic run, path constraints are collected and for every `JUMPI`\nopcode the analysis asks a Difference Logic solver (`DLSolver.sol`) whether the\ncondition can ever be true.\nIf the condition can never be true, the event `UnreachableBranch(pc)` is\nemitted, giving the program counter of that branch.\nIf the condition can be true, the generated constraints are added into the list\nof constraints, and the new `true` branch is executed.\nThe negation of the generated constraints is added into the constraint list for\nthe `false` branch.\n\nUsage\n-----\n\nThis repo uses `forge` from [Foundry](https://github.com/gakonst/foundry/).\nTo run all the tests:\n\n```\n$ forge test\n```\n\nThe tests in this repo include unit tests for the DL solver, and examples of\nhow to use the symbolic engine.\nTo run the latter:\n\n```\n$ forge test --match symb_run -vvvv\n```\n\nThe first test, `SymbExecTest::test_symb_run_simple`, shows us that the branch\nstarting at program counter 0x14 is unreachable! It can therefore be removed.\nThat branch is `tag_2`, which represents the inner `if` in the sample Yul code.\nSee the test for a detailed explanation.\n\nIn the last test, you should see\n\n```\n[PASS] test_symb_run_unreachable() (gas: 687208634)\nTraces:\n\n  [687208634] SymbExecTest::test_symb_run_unreachable()\n    ├─ emit UnreachableBranch(pc: 382)\n    ├─ emit UnreachableBranch(pc: 425)\n    ├─ emit UnreachableBranch(pc: 468)\n    ├─ emit UnreachableBranch(pc: 550)\n    └─ ← ()\n```\n\nThis shows that the analysis found 4 useless branches in the bytecode!\nCheck `src/test/SymbExec.t.sol` to understand why/where.\n\nThe analysis for a contract Analyzed can be invoked by calling\n`symb_run(type(Analyzed).runtimeCode)`, as seen in the tests.\n\nNote that the settings in this repo are **not** using the Solidity compiler's\noptimizer on purpose.\nThe optimizer itself already removes some of these branches from the bytecode.\nIt is likely that many of the cases that this engine could optimize are already\ncovered by the compiler.\nYou will likely notice test result differences if you enable/disable the\noptimizer settings in`foundry.toml`.\nNeed to run more tests.\n\nDifference Logic (DL)\n---------------------\n\nDL is a nice little logic that accepts expressions of the form `a - b \u003c= k`,\nwhere `a` and `b` are variables, and `k` is a constant.\nThe domain may be the Integers or the Reals.\nA DL solver is similar to an LP solver, but a lot simpler.\nIt takes a set of constraints in the form above (instead of more general linear\nconstraints), and answers whether it is feasible for all the constraints to be\ntrue at the same time.\n\nThe algorithm for solving sets of DL constraints is to represent the\nconstraints as a weighted graph, such that every constraint `a - b \u003c= k` is an\nedge `a -\u003e b` with weight `k`, and check whether the graph has a negative\ncycle.\nThe latter can be solved, for example, with the Bellman-Ford single source\nshortest path algorithm with the negative cycle detection extension.\n\nThe proofs of the statements above are left as exercises to the reader.\n\nEncoding\n--------\n\nFor every `JUMPI` we collect constraints from the condition and convert them to\nDL expressions.\nFor example, if the `JUMPI` condition is `stack_slot_1 \u003c 2`, this becomes\n`stack_slot_1 - zero \u003c= 1`, where `zero` is a symbolic variable that always\nrepresents the constant 0 in the DL graph.\nThe encoding for `GT` is similar.\nThe encoding for `ISZERO` simply negates the encoding of its argument.\nEqualities (`EQ`) `x = y` become two constraints: `x - y \u003c= 0` and `y - x \u003c=\n0`.\nIn the case of disequalities, that is, the `iszero(eq(...))` constraint for the\ntrue branch of a `JUMPI`, or the negation of an `eq(...)` for the false branch,\nwe actually do not generate new constraints.\nThis is because the encoding of a disequality is actually a disjunction: `a !=\nb \u003c=\u003e !(a \u003c= b \u0026\u0026 b \u003c= a) \u003c=\u003e a \u003e b || b \u003e a`.\nIf the domain is the Integers (which it is in our case), the DL satisfiability\nproblem becomes NP-hard.\n\nCode base issues\n----------------\n\nAll the VM data structures, such as stack, path and constraints, are memory arrays.\nThere is a lot of copying of those arrays.\nSome of them are intended, since we need to make a new VM when starting a new\n`JUMPI` branch, and continue the other branch with the current VM.\nHowever, at times we simply want to extend an array without copying it\nentirely.\nSince we can't extend memory arrays natively, we just create a new larger array\nfrom scratch with the previous content copied, plus the desired extension.\nThe code base would definitely benefit from a memory vector, either natively\nor from a library.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fleonardoalt%2Fdl_symb_exec_sol","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fleonardoalt%2Fdl_symb_exec_sol","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fleonardoalt%2Fdl_symb_exec_sol/lists"}