{"id":16319186,"url":"https://github.com/controlcpluscontrolv/scribe","last_synced_at":"2025-03-20T22:31:00.381Z","repository":{"id":38158397,"uuid":"455240155","full_name":"ControlCplusControlV/Scribe","owner":"ControlCplusControlV","description":"Minimal Yul Transpilation to the Miden VM","archived":false,"fork":false,"pushed_at":"2023-01-27T07:28:58.000Z","size":546,"stargazers_count":52,"open_issues_count":14,"forks_count":4,"subscribers_count":2,"default_branch":"main","last_synced_at":"2024-10-11T22:26:10.017Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Rust","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/ControlCplusControlV.png","metadata":{"files":{"readme":"README.md","changelog":"history.txt","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-03T16:25:38.000Z","updated_at":"2024-09-26T00:04:03.000Z","dependencies_parsed_at":"2023-02-15T06:46:12.965Z","dependency_job_id":null,"html_url":"https://github.com/ControlCplusControlV/Scribe","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/ControlCplusControlV%2FScribe","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ControlCplusControlV%2FScribe/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ControlCplusControlV%2FScribe/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ControlCplusControlV%2FScribe/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ControlCplusControlV","download_url":"https://codeload.github.com/ControlCplusControlV/Scribe/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244085006,"owners_count":20395523,"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-10T22:26:07.464Z","updated_at":"2025-03-20T22:31:00.093Z","avatar_url":"https://github.com/ControlCplusControlV.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# 📜 Scribe 📜\n![Testing](https://github.com/ControlCplusControlV/Scribe/actions/workflows/rust.yml/badge.svg)\n\nScribe is a compact Yul transpiler written in Rust that targets the Polygon\nMiden VM. Scribe works by compiling Yul down to Miden opcodes, allowing\ndevelopers to write smart contracts in Yul and run them on Polygon Miden. Since\nYul is the intermediate language for Solidity, Vyper and Yul+ Scribe is a great\nfoundation for various smart contract languages to compile code to run on\nPolygon Miden.\n\n\n## Status\n\n**WARNING:** This project is in an alpha stage. It has not been audited and may contain bugs and security flaws. This implementation is NOT ready for production use.\n\n### Parsing\n\nAll yul syntax is parsed, including the new typed identifier list syntax.\n\nData blocks are not transpiled. Objects are naively transpiled as a series of statements.\n\n### Types\n\nBecause u256 operations are so expensive in miden, scribe will check whether\nvariables and parameters are typed, and if they're `u32` values, then we can\nuse the much cheaper miden u32 operations. Scribe will default to `u256`.\n\n\n### Supported yul functions\n\n| Function | u32 | u256 | notes |\n|----------|------|-----| ---- | \n| add      | ✅    | ✅ | |\n| mul      |  ✅    |  ✅  | |\n| sub      |   ✅   |  ✅   | |\n| div      |   ✅   |  ❌   | |\n| and      |   ✅   |  ✅   | |\n| or      |   ✅   |  ✅   | |\n| xor      |   ✅   |  ✅   | |\n| mstore      |   ✅   |  ✅  | address must be u32 |\n| mload      |   ✅   |  ✅  | address must be u32 |\n| iszero      |   ✅   |  ✅  | |\n| eq      |   ✅   |  ✅  | |\n| lt      |   ✅   |  ✅  | |\n| gt      |   ✅   |  ✅  | |\n| gte      |   ✅   |  ✅  | |\n| lte      |   ✅   |  ✅  | |\n| shl      |   ✅   |  ❌  | |\n| shr      |   ✅   |  ❌  | |\n\n\n## Miden Repl\n\nScribe features a REPL to write miden assembly. You can start the repl with:\n\n```\ncargo run -- repl\n```\n\nFrom within the repl, you can write any valid miden assembly, then check the\nstack with `stack`, or check your whole program with `program`. Anything that\nerrors out will not be added to the program. You can undo the last command with `undo`.\n\n```\n$ cargo run -- repl\n\n\u003e\u003e push.4\n\n\u003e\u003e push.5 push.7 mul\n\n\u003e\u003e stack\n\n  35 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n\n\u003e\u003e program\n\n  begin\n      push.4\n      push.5 push.7 mul\n  end\n\n\u003e\u003e undo\n  Undoing push.5 push.7 mul\n\n\u003e\u003e stack\n\n  4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n\n\u003e\u003e help\n\n  Available commands:\n\n  stack: display the stack\n  undo: remove the last instruction\n  program: display the program\n```\n\n## How Does it Work?\n\nScribe is built with Rust and uses the [Pest parser](https://github.com/pest-parser/pest) to be able to recognize Yul Grammar. Scribe then translates the Yul code to the Miden VM opcodes, enabling fully functional Miden assembly can be generated from Yul. Since languages like Solidity and Vyper compile to Yul before generating EVM opcodes, in future versions of Scribe, it will be possible to transpile code written in Solidity or Vyper, into Miden assembly!\n         \n \u003cbr/\u003e\n      \n**Lets take a closer look at how Scribe works under the hood.**\n      \n      \nFirst, Scribe reads in all of the Yul contracts in the `Scribe/contracts`\ndirectory. While Scribe can transpile entire Yul contracts, for this\nwalkthrough we will just use a simple snippet of Yul code. We'll use u32\nannotations so that the output is more readable, but this example will also\nwork with u256 values.\n      \n```js\n      \n object \"fib\" {\n  code {\n            let n:u32 := 10\n            let a:u32 := 0\n            let b:u32 := 1\n            let c:u32 := 0\n\n            for { let i:u32 := 0 } lt(i, n) { i := add(i, 1)}\n            {\n                c := add(a,b)\n                a := b\n                b := c\n            }\n            b\n  }\n}\n      \n ```\n       \nOnce the Yul code is read in, Scribe converts the code into a string and passes it into the `parse_yul_syntax` function. From there, Scribe parses the string, looking for Yul grammar and generates an `Expr` for each match.\n      \n ```rust \npub enum Expr {\n    Literal(ExprLiteral),\n    FunctionDefinition(ExprFunctionDefinition),\n    FunctionCall(ExprFunctionCall),\n    IfStatement(ExprIfStatement),\n    Assignment(ExprAssignment),\n    DeclareVariable(ExprDeclareVariable),\n    ForLoop(ExprForLoop),\n    Block(ExprBlock),\n    Switch(ExprSwitch),\n    Case(ExprCase),\n    Variable(ExprVariableReference),\n    Repeat(ExprRepeat),\n    Break,\n    Continue,\n    Leave,\n}\n```\n      \nEach `Expr` is pushed to a `Vec\u003cExpr\u003e`, which is then passed into the\n`miden_generator::transpile_program()` function. This function generates the\nMiden opcodes and keeps track of the variables as well as open memory\naddresses.\n      \nThe transpiled code from the fibonacci example looks like this:\n      \n```nasm\nbegin                                                                                                                                                                                                                                                                                 [30/1924]\n    # Assigning to n #\n        # u32 literal 10 #\n        push.10\n\n    # Assigning to a #\n        # u32 literal 0 #\n        push.0\n\n    # Assigning to b #\n        # u32 literal 1 #\n        push.1\n\n    # Assigning to c #\n        # u32 literal 0 #\n        push.0\n\n    # Assigning to i #\n        # u32 literal 0 #\n        push.0\n\n    # -- conditional -- #\n    # lt() #\n    # pushing i to the top #\n        dup.0\n    # pushing n to the top #\n        dup.5\n    lt\n    while.true\n        # -- interior block -- #\n            # Assigning to c #\n                # add() #\n                # pushing a to the top #\n                    dup.3\n                # pushing b to the top #\n                    dup.3\n                add\n            # Assigning to a #\n                # pushing b to the top #\n                    dup.3\n            # Assigning to b #\n                # pushing c to the top #\n                    dup.1\n\n        # -- after block -- #\n            # Assigning to i #\n                # add() #\n                # pushing i to the top #\n                    dup.3\n                # u32 literal 1 #\n                push.1\n\n                add\n\n            # cleaning up after branch #\n                # pushing n to the top #\n                    movup.8\n                # pushing a to the top #\n                    movup.3\n                # pushing b to the top #\n                    movup.3\n                # pushing c to the top #\n                    movup.4\n                # pushing i to the top #\n                    movup.4\n\n        # -- conditional -- #\n            # lt() #\n            # pushing i to the top #\n                dup.0\n            # pushing n to the top #\n                dup.5\n            lt\n\n    end\n\n    # pushing b to the top #\n        dup.2\nend\n   \n```\n      \nNow the generated Miden code is ready to run! Scribe can test your code on the Miden VM by starting the VM, passing in the Miden code and calling the executor. Here is what the process looks like from start to finish!\n      \n```rust\n//Parse the Yul code\nlet parsed_yul_code = parser::parse_yul_syntax(yul_code);\n\n//Generate Miden opcodes from the parsed Yul code\nlet miden_code = miden_generator::transpile_program(parsed);\n\n//Execute the Miden code on the Miden VM\nlet execution_value = executor::execute(miden_code, inputs).unwrap();\nlet stack = execution_value.last_stack_state();\nlet last_stack_value = stack.first().unwrap();\n\n//Print the output\nprintln!(\"Miden Output\");\nprintln!(\"{}\", last_stack_value);\n```\n      \nAnd here is the output!\n      \n```\nMiden Output\n89    \n```\n      \n      \n      \n## How to transpile your own contract.\n\nTo transpile and test your own contracts simple drop your own Yul Contracts inside the contracts folder then transpile then by running the transpiler crate with `cargo run`. Note that some Yul operations are still unsupported, but basic arithmatic, and control structures are supported, as well as variables.   \n\nScribe was meant to focus on real world applicability, and because of this uses Miden v0.2. Due to Miden v0.2 not being done yet certain crates of it like the zk prover are broken atm as the developers build away on the new release. So certain functionality like zk proof generation can't be done at the moment, but execution can still be tested in the zk VM environment.\n\nFirst clone this repo and download its submodule\n\n```\ngit clone https://github.com/ControlCplusControlV/Scribe\ncd Scribe\ngit submodule init\ngit submodule update\n```\n\nthen cd into the transpiler crate\n\n```\ncd transpiler\n```\n\nThen init the git submodule, and you should be good to go!\n      \n      \n## Contributing\n\n### Testing\n\nScribe has unit tests and integration tests that can be run with `cargo test`\n\nOur parsing tests use the [insta](https://github.com/mitsuhiko/insta)\nsnapshot-testing crate. After running a new test, run `cargo insta review`,\nverify that the generated AST looks right, then accept the output as correct.\nIn future tests the output will be compared to this snapshot.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcontrolcpluscontrolv%2Fscribe","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcontrolcpluscontrolv%2Fscribe","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcontrolcpluscontrolv%2Fscribe/lists"}