{"id":13803710,"url":"https://github.com/lambdaclass/cairo-vm_in_go","last_synced_at":"2026-03-08T11:32:09.641Z","repository":{"id":185863188,"uuid":"671982219","full_name":"lambdaclass/cairo-vm_in_go","owner":"lambdaclass","description":"cairo-vm_in_go is a Go implementation of the Cairo VM. Cairo (CPU Algebraic Intermediate Representation) is a programming language for writing provable programs, where one party can prove to another that a certain computation was executed correctly without the need for this party to re-execute the same program.","archived":false,"fork":false,"pushed_at":"2024-04-30T18:31:13.000Z","size":713,"stargazers_count":57,"open_issues_count":43,"forks_count":14,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-03-24T01:24:02.531Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/lambdaclass.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,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-07-28T15:50:08.000Z","updated_at":"2024-12-18T15:19:51.000Z","dependencies_parsed_at":"2023-09-11T14:43:31.872Z","dependency_job_id":"55119f66-a81f-4328-a28e-74e525030244","html_url":"https://github.com/lambdaclass/cairo-vm_in_go","commit_stats":null,"previous_names":["lambdaclass/cairo_vm.go","lambdaclass/cairo-vm_in_go"],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lambdaclass%2Fcairo-vm_in_go","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lambdaclass%2Fcairo-vm_in_go/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lambdaclass%2Fcairo-vm_in_go/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lambdaclass%2Fcairo-vm_in_go/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/lambdaclass","download_url":"https://codeload.github.com/lambdaclass/cairo-vm_in_go/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248130299,"owners_count":21052729,"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-08-04T01:00:37.132Z","updated_at":"2026-03-08T11:32:09.635Z","avatar_url":"https://github.com/lambdaclass.png","language":"Go","funding_links":[],"categories":["Additional developer resources"],"sub_categories":[],"readme":"# cairo-vm.go\n\nThis is a work in progress implementation of the [Cairo VM](https://github.com/lambdaclass/cairo-vm) in `Go`. The reasons for doing this include:\n\n- Having a diversity of implementations helps find bugs and make the whole ecosystem more resilient.\n- It's a good opportunity to extensively document the VM in general, as currently the documentation on its internals is very scarce and mostly lives on the minds of a few people.\n\n## Other docs\n\n- [Project layout](docs/layout.md)\n- [Rust/lambdaworks integration](docs/rust-integration.md)\n\n## Installation\n\nGo needs to be installed. For mac computers, run\n\n```shell\nbrew install go\n```\n\nWe also use [pyenv](https://github.com/pyenv/pyenv) to install testing-related dependencies\n\n## Compiling, running, testing\n\nFirst, install the testing dependencies:\n\n- On Linux, run\n\n```shell\nmake deps\n```\n\n- On MacOS, run\n\n```shell\nmake deps-macos\n```\n\nTo build the project, run:\n\n```shell\nmake build\n```\n\nTo run all tests, activate the venv created by make deps and run the test target:\n\n```shell\n. cairo-vm-env/bin/activate\nmake test\n```\n\n## Running the demo\n\nThis project currently has two demo targets, one for running a fibonacci programs and one for running a factorial program. Both of them output their corresponding trace files.\nThe demo uses cairo_lang to compile both cairo programs, you can install it by running `make deps` (or `make deps-macos` if you are on macos)\n\nTo run the fibonacci demo:\n\n```shell\nmake demo_fibonacci\n```\n\nTo run the factorial demo:\n\n```shell\nmake demo_factorial\n```\n\nThese demos compare the trace and memory files generated by the `Go` and `Rust` VM implementations to make sure they coincide. We have more general Makefile targets that do this comparison for every program we use for testing. You can check out a list of all these programs under the `cairo_programs` directory. The targets to run these comparisons are\n\n```\nmake compare_trace_memory\n```\n\nand\n\n```\nmake compare_proof_trace_memory\n```\n\nThe first one does the comparison for normal executions, while the second one does it with *proof mode* enabled.\n\n## Project Guidelines\n\n- PRs addressing performance are forbidden. We are currently concerned with making it work without bugs and nothing more.\n- All PRs must contain tests. Code coverage has to be above 98%.\n- To check for security and other types of bugs, the code will be fuzzed extensively.\n- PRs must be accompanied by its corresponding documentation. A book will be written documenting the entire inner workings of it, so anyone can dive in to a Cairo VM codebase and follow it along.\n\n## Milestones\n\n### First milestone: Fibonacci/Factorial\n\nThe first milestone for Cairo VM in Go is completed! 🎉\n\nThe milestone includes:\n\n- Parsing of `json` programs.\n- Decoding of instructions.\n- Memory relocation.\n- Instruction execution.\n- Writing of the trace into files with the correct format.\n- Make the fibonacci and factorial tests pass, comparing our own trace with the Rust VM one, making sure they match.\n- Writing of the memory into files with the correct format.\n- Make the fibonacci and factorial tests pass, comparing our own memory with the Rust VM one, making sure they match.\n\n### Second Milestone: Full VM implementation\n\nBelow is a list of requirements to have a full implementation along with their progress:\n\n- ✅ Builtins. Add the `BuiltinRunner` logic, then implement each builtin:\n  - ✅ `Range check (RC)`\n  - ✅ `Output`\n  - ✅ `Bitwise`\n  - ✅ `Ec_op`\n  - ✅ `Pedersen`\n  - ✅ `Keccak`\n  - ✅ `Poseidon`\n  - ✅ `Signature`\n- ✅ Memory layouts. (plain, small, all_cairo)\n- Hints. \n    - ✅ Add the `HintProcessor` logic\n    - ✅ [Parsing of references](https://github.com/lambdaclass/cairo-vm/tree/main/docs/references_parsing)\n    - Implement each hint. This is a long task which we divided into milestones. You can check out their progress [here](https://github.com/lambdaclass/cairo-vm_in_go/milestones).\n- ✅ Proof mode. It's important to explain in detail what this is when we do it. It's one of the most obscure parts of the VM in my experience.\n- ✅ Program tests from Cairo VM in Rust.\n- Support for Temporary Memory\n    - Handle temporary addresses in memory-related code\n    - Implement relocation process for temporary memory\n- Print debug information on failure (i.e. introduce the concept of a `VmException`)\n- Air Public inputs. (Tied to Proof mode)\n- Starknet integration:\n    - Running cairo contracts (i.e. implement `RunFromEntrypoint`)\n    - Tracking `ExecutionResources` and `RunResources`.\n- Cairo 1 support. This requires:\n    - Parsing Cairo 1 contracts. There is no `Json` representation of a Cairo 1 Program, so we can only run contracts. This means this depends on the `RunFromEntrypoint` feature above. \n    - Implementing Cairo 1 builtin (`Segment Arena`)\n    - Implementing Cairo 1 Hints\n- Support for `CairoPie` (Cairo Position Independent Code).\n\n\n### Other Stuff: Performance and Fuzzing\n\nThings that are out of the second milestone but we want to have:\n\n- Add benchmarks to track performance and compare against the Rust implementation.\n- Add Fuzzing and Differential fuzzing to catch errors that our regular tests don't and compare ourselves against the Rust VM.\n## Documentation\n\n### High Level Overview\n\nThe Cairo virtual machine is meant to be used in the context of STARK validity proofs. What this means is that the point of Cairo is not just to execute some code and get a result, but to *prove* to someone else that said execution was done correctly, without them having to re-execute the entire thing. The rough flow for it looks like this:\n\n- A user writes a Cairo program.\n- The program is compiled into Cairo's VM bytecode.\n- The VM executes said code and provides a *trace* of execution, i.e. a record of the state of the machine and its memory *at every step of the computation*.\n- This trace is passed on to a STARK prover, which creates a cryptographic proof from it, attesting to the correct execution of the program.\n- The proof is passed to a verifier, who checks that the proof is valid in a fraction of a second, without re-executing.\n\nThe main three components of this flow are:\n\n- A Cairo compiler to turn a program written in the [Cairo programming language](https://www.cairo-lang.org/) into bytecode.\n- A Cairo VM to then execute it and generate a trace.\n- [A STARK prover and verifier](https://github.com/lambdaclass/starknet_stack_prover_lambdaworks) so one party can prove correct execution, while another can verify it.\n\nWhile this repo is only concerned with the second component, it's important to keep in mind the other two; especially important are the prover and verifier that this VM feeds its trace to, as a lot of its design decisions come from them. This virtual machine is designed to make proving and verifying both feasible and fast, and that makes it quite different from most other VMs you are probably used to.\n\n### Basic VM flow\n\nOur virtual machine has a very simple flow:\n\n- Take a compiled cairo program as input. You can check out an example program [here](https://github.com/lambdaclass/cairo-vm.go/blob/main/cairo_programs/fibonacci.cairo).\n- Run the bytecode from the compiled program, doing the usual `fetch-\u003edecode-\u003eexecute` loop, running until program termination.\n- On every step of the execution, record the values of each register.\n- Take the register values and memory at every step and write them to a file, called the `execution trace`.\n\nBarring some simplifications we made, this is all the Cairo VM does. The two main things that stand out as radically different are the memory model and the use of `Field Elements` to perform arithmetic. Below we go into more detail on each step, and in the process explain the ommisions we made.\n\n### Architecture\n\nThe Cairo virtual machine uses a Von Neumann architecture with a Non-deterministic read-only memory. What this means, roughly, is that memory is immutable after you've written to it (i.e. you can only write to it once); this is to make the STARK proving easier, but we won't go into that here.\n\n#### Memory Segments and Relocation\n\nThe process of memory allocation in a contiguous write-once memory region can get pretty complicated. Imagine you want to have a regular call stack, with a stack pointer pointing to the top of it and allocation and deallocation of stack frames and local variables happening throughout execution. Because memory is immutable, this cannot be done the usual way; once you allocate a new stack frame that memory is set, it can't be reused for another one later on.\n\nBecause of this, memory in Cairo is divided into `segments`. This is just a way of organizing memory more conveniently for this write-once model. Each segment is nothing more than a contiguous memory region. Segments are identified by an `index`, an integer value that uniquely identifies them.\n\nMemory `cells` (i.e. values in memory) are identified by the index of the segment they belong to and an `offset` into said segment. Thus, the memory cell `{2,0}` is the first cell of segment number `2`.\n\nEven though this segment model is extremely convenient for the VM's execution, the STARK prover needs to have the memory as just one contiguous region. Because of this, once execution of a Cairo program finishes, all the memory segments are collapsed into one; this process is called `Relocation`. We will go into more detail on all of this below.\n\n#### Registers\n\nThere are only three registers in the Cairo VM:\n\n- The program counter `pc`, which points to the next instruction to be executed.\n- The allocation pointer `ap`, pointing to the next unused memory cell.\n- The frame pointer `fp`, pointing to the base of the current stack frame. When a new function is called, `fp` is set to the current `ap`. When the function returns, `fp` goes back to its previous value. The VM creates new segments whenever dynamic allocation is needed, so for example the cairo analog to a Rust `Vec` will have its own segment. Relocation at the end meshes everything together.\n\n#### Instruction Decoding/Execution\n\nTODO: explain the components of an instruction (`dst_reg`, `op0_reg`, etc), what each one is used for and how they're encoded/decoded.\n\n#### Felts\n\nFelts, or Field Elements, are cairo's basic integer type. Every variable in a cairo vm that is not a pointer is a felt. From our point of view we could say a felt in cairo is an unsigned integer in the range [0, CAIRO_PRIME). This means that all operations are done modulo CAIRO_PRIME. The CAIRO_PRIME is 0x800000000000011000000000000000000000000000000000000000000000001, which means felts can be quite big (up to 252 bits), luckily, we have the [Lambdaworks](https://github.com/lambdaclass/lambdaworks) library to help with handling these big integer values and providing fast and efficient modular arithmetic.\n\n#### Lambdaworks library wrapper\n\n[Lambdaworks](https://github.com/lambdaclass/lambdaworks) is a custom performance-focused library that aims to ease programming for developers. It provides essential mathematical and cryptographic methods required for this project, enabling arithmetic operations between `felts` and type conversions efficiently.\nWe've developed a C wrapper to expose the library's functions and enable easy usage from Go. This allows seamless integration of the library's features within Go projects, enhancing performance and functionality.\n\n#### More on memory\n\nThe cairo memory is made up of contiguous segments of variable length identified by their index. The first segment (index 0) is the program segment, which stores the instructions of a cairo program. The following segment (index 1) is the execution segment, which holds the values that are created along the execution of the vm, for example, when we call a function, a pointer to the next instruction after the call instruction will be stored in the execution segment which will then be used to find the next instruction after the function returns. The following group of segments are the builtin segments, one for each builtin used by the program, and which hold values used by the builtin runners. The last group of segments are the user segments, which represent data structures created by the user, for example, when creating an array on a cairo program, that array will be represented in memory as its own segment.\n\nAn address (or pointer) in cairo is represented as a `relocatable` value, which is made up of a `segment_index` and an `offset`, the `segment_index` tells us which segment the value is stored in and the `offset` tells us how many values exist between the start of the segment and the value.\n\nAs the cairo memory can hold both felts and pointers, the basic memory unit is a `maybe_relocatable`, a variable that can be either a `relocatable` or a `felt`.\n\nWhile memory is continous, some gaps may be present. These gaps can be created on purpose by the user, for example by running:\n\n```text\n[ap + 1] = 2;\n```\n\nWhere a gap is created at ap. But they may also be created indireclty by diverging branches, as for example one branch may declare a variable that the other branch doesn't, as memory needs to be allocated for both cases if the second case is ran then a gap is left where the variable should have been written.\n\n##### Memory API\n\nThe memory can perform the following basic operations:\n\n- `memory_add_segment`: Creates a new, empty segment in memory and returns a pointer to its start. Values cannot be inserted into a memory segment that hasn't been previously created.\n\n- `memory_insert`: Inserts a `maybe_relocatable` value at an address indicated by a `relocatable` pointer. For this operation to succeed, the pointer's segment_index must be an existing segment (created using `memory_add_segment`), and there mustn't be a value stored at that address, as the memory is immutable after its been written once. If there is a value already stored at that address but it is equal to the value to be inserted then the operation will be successful.\n\n- `memory_get`: Fetches a `maybe_relocatable` value from a memory address indicated by a `relocatable` pointer.\n\nOther operations:\n\n- `memory_load_data`: This is a convenience method, which takes an array of `maybe_relocatable` and inserts them contiguosuly in memory by calling `memory_insert` and advancing the pointer by one after each insertion. Returns a pointer to the next free memory slot after the inserted data.\n\n##### Memory Relocation\n\nDuring execution, the memory consists of segments of varying length, and they can be accessed by indicating their segment index, and the offset within that segment. When the run is finished, a relocation process takes place, which transforms this segmented memory into a contiguous list of values. The relocation process works as follows:\n\n1. The size of each segment is calculated (The size is equal to the highest offset within the segment + 1, and not the amount of `maybe_relocatable` values, as there can be gaps)\n2. A base is assigned to each segment by accumulating the size of the previous segment. The first segment's base is set to 1.\n3. All `relocatable` values are converted into a single integer by adding their `offset` value to their segment's base calculated in the previous step\n\nFor example, if we have this memory represented by address, value pairs:\n\n```text\n    0:0 -\u003e 1\n    0:1 -\u003e 4\n    0:2 -\u003e 7\n    1:0 -\u003e 8\n    1:1 -\u003e 0:2\n    1:4 -\u003e 0:1\n    2:0 -\u003e 1\n```\n\nStep 1: Calculate segment sizes:\n\n```text\n    0 --(has size)--\u003e 3\n    1 --(has size)--\u003e 5\n    2 --(has size)--\u003e 1\n```\n\nStep 2: Assign a base to each segment:\n\n```text\n    0 --(has base value)--\u003e 1\n    1 --(has base value)--\u003e 4 (that is: 1 + 3)\n    2 --(has base value)--\u003e 9 (that is: 4 + 5)\n```\n\nStep 3: Convert relocatables to integers\n\n```text\n    1 (base[0] + 0) -\u003e 1\n    2 (base[0] + 1) -\u003e 4\n    3 (base[0] + 2) -\u003e 7\n    4 (base[1] + 0) -\u003e 8\n    5 (base[1] + 1) -\u003e 3 (that is: base[0] + 2)\n    .... (memory gaps)\n    8 (base[1] + 4) -\u003e 2 (that is: base[0] + 1)\n    9 (base[2] + 0) -\u003e 1\n```\n\n#### Program parsing\n\nThe input of the Virtual Machine is a compiled Cairo program in Json format. The main part of the file are listed below:\n\n- **data:** List of hexadecimal values that represent the instructions and immediate values defined in the cairo program. Each hexadecimal value is stored as a maybe_relocatable element in memory, but they can only be felts because the decoder has to be able to get the instruction fields in its bit representation.\n- **debug_info:** This field provides information about the instructions defined in the data list. Each one is identified with its index inside the data list. For each one it contains information about the cairo variables in scope, the hints executed before that instruction if any, and its location inside the cairo program.\n- **hints:** All the hints used in the program, ordered by the pc offset at which they should be executed.\n- **identifiers:** User-defined symbols in the Cairo code representing variables, functions, classes, etc. with unique names. The expected offset, type and its corresponding information is provided for each identifier\n\n    For example, the identifier representing the main function (usually the entrypoint of the program) is of `function` type, and a list of decorators wrappers (if there are any) are provided as additional information.\n    Another example is a user defined struct, is of `struct` type, it provides its size, the members it contains (with its information) and more.\n\n- **main_scope:** Usually something like `__main__`. All the identifiers associated with main function will be identified as `__main__`.identifier_name. Useful to identify the entrypoint of the program.\n- **prime:** The cairo prime in hexadecimal format. As explained above, all arithmetic operations are done over a base field, modulo this primer number.\n- **reference_manager:** Contains information about cairo variables. This information is useful to access to variables when executing cairo hints.\n\n### Code walkthrough/Write your own Cairo VM\n\nLet's begin by creating the basic types and structures for our VM:\n\n#### Felt\n\nAs anyone who has ever written a cairo program will know, everything in cairo is a Felt. We can think of it as our unsigned integer. In this project, we use the `Lambdaworks` library to abstract ourselves from modular arithmetic.\n\nTODO: Instructions on how to use Lambdaworks felt from Go\n\n#### Relocatable\n\nThis is how cairo represents pointers, they are made up of `SegmentIndex`, which segment the variable is in, and `Offset`, how many values exist between the start of a segment and the variable. We represent them like this:\n\n```go\ntype Relocatable struct {\n    SegmentIndex int\n    Offset       uint\n}\n```\n\n#### MaybeRelocatable\n\nAs the cairo memory can hold both felts and relocatables, we need a data type that can represent both in order to represent a basic memory unit.\nWe would normally use enums or unions to represent this type, but as go lacks both, we will instead hold a non-typed inner value and rely on the api to make sure we can only create MaybeRelocatable values with either Felt or Relocatable as inner type.\n\n```go\ntype MaybeRelocatable struct {\n    inner any\n}\n\n// Creates a new MaybeRelocatable with an Int inner value\nfunc NewMaybeRelocatableInt(felt uint) *MaybeRelocatable {\n    return \u0026MaybeRelocatable{inner: Int{felt}}\n}\n\n// Creates a new MaybeRelocatable with a Relocatable inner value\nfunc NewMaybeRelocatableRelocatable(relocatable Relocatable) *MaybeRelocatable {\n    return \u0026MaybeRelocatable{inner: relocatable}\n}\n```\n\nWe will also add some methods that will allow us access `MaybeRelocatable` inner values:\n\n```go\n// If m is Int, returns the inner value + true, if not, returns zero + false\nfunc (m *MaybeRelocatable) GetInt() (Int, bool) {\n    int, is_type := m.inner.(Int)\n    return int, is_type\n}\n\n// If m is Relocatable, returns the inner value + true, if not, returns zero + false\nfunc (m *MaybeRelocatable) GetRelocatable() (Relocatable, bool) {\n    rel, is_type := m.inner.(Relocatable)\n    return rel, is_type\n}\n```\n\nThese will allow us to safely discern between `Felt` and `Relocatable` values later on.\n\n#### MaybeRelocatable Operations\n\nIntroducing the MaybeRelocatable type means we will have to handle various arithmetic operations between Relocatable, Felt and MaybeRelocatable types.\nWe will start by implementing Add and Sub operations for the `Relocatable` type:\n\n##### Relocatable.Add\n\nAddition between Relocatable values is not supported, so we don't implement it.\n\n##### Relocatable.AddFelt\n\nThis method adds a Felt value to the relocatable's offset by first converting the relocatable's offset to a Felt, performing felt addition between the offset and the felt value, and then converting the new offset to a uint value. This method returns an error if the new offset exceeds the size of a uint.\n\n```go\n// Adds a Felt value to a Relocatable\n// Fails if the new offset exceeds the size of a uint\nfunc (r *Relocatable) AddFelt(other lambdaworks.Felt) (Relocatable, error) {\n new_offset_felt := lambdaworks.FeltFromUint64(uint64(r.Offset)).Add(other)\n new_offset, err := new_offset_felt.ToU64()\n if err != nil {\n  return *r, err\n }\n return NewRelocatable(r.SegmentIndex, uint(new_offset)), nil\n}\n```\n\n##### Relocatable.Sub\n\nThis method returns the distance between two relocatable values. It can only be performed between to relocatables of the same segment (aka relocatables with the same segment index), and it returns the difference between their offsets as a uint value. It fails if the segment indexes differ or if the difference would yield a negative value\n\n```go\n// Returns the distance between two relocatable values (aka the difference between their offsets)\n// Fails if they have different segment indexes or if the difference is negative\nfunc (r *Relocatable) Sub(other Relocatable) (uint, error) {\n if r.SegmentIndex != other.SegmentIndex {\n  return 0, errors.New(\"Cant subtract two relocatables with different segment indexes\")\n }\n if r.Offset \u003c other.Offset {\n  return 0, errors.New(\"Relocatable subtraction yields relocatable with negative offset\")\n }\n return r.Offset - other.Offset, nil\n}\n```\n\n##### Relocatable.SubFelt\n\nThis method subtracts a Felt value to the relocatable's offset by first converting the relocatable's offset to a Felt, performing felt subtraction between the offset and the felt value, and then converting the new offset to a uint value. This method returns an error if the new offset is negative or exceeds the size of a uint.\n\n```go\n// Substracts a Felt value from a Relocatable\n// Performs the initial substraction considering the offset as a Felt\n// Fails if the new offset exceeds the size of a uint\nfunc (r *Relocatable) SubFelt(other lambdaworks.Felt) (Relocatable, error) {\n new_offset_felt := lambdaworks.FeltFromUint64(uint64(r.Offset)).Sub(other)\n new_offset, err := new_offset_felt.ToU64()\n if err != nil {\n  return *r, err\n }\n return NewRelocatable(r.SegmentIndex, uint(new_offset)), nil\n}\n```\n\nNow lets look at the operations between `MaybeRelocatable`s:\n\n##### MaybeRelocatable.Add\n\nThere are four different cases to consider when adding two `MaybeRelocatable` values:\n\n1. Both values are `Felt`: We perform felt addition\n2. Both values are `Relocatable`: This operation is not supported so we return an error\n3. First value is `Felt` and other in `Relocatable`: This operation is not supported so we return an error\n4. First value is `Relocatable` and other is `Felt`: We call `Relocatable.AddFelt`\n\n```go\nfunc (m MaybeRelocatable) Add(other MaybeRelocatable) (MaybeRelocatable, error) {\n // check if they are felt\n m_int, m_is_int := m.GetFelt()\n other_int, other_is_int := other.GetFelt()\n\n if m_is_int \u0026\u0026 other_is_int {\n  result := NewMaybeRelocatableFelt(m_int.Add(other_int))\n  return *result, nil\n }\n\n // check if one is relocatable and the other int\n m_rel, is_rel_m := m.GetRelocatable()\n other_rel, is_rel_other := other.GetRelocatable()\n\n if is_rel_m \u0026\u0026 !is_rel_other {\n  other_felt, _ := other.GetFelt()\n  relocatable, err := m_rel.AddFelt(other_felt)\n  if err != nil {\n   return *NewMaybeRelocatableFelt(lambdaworks.FeltZero()), err\n  }\n  return *NewMaybeRelocatableRelocatable(relocatable), nil\n\n } else if !is_rel_m \u0026\u0026 is_rel_other {\n\n  m_felt, _ := m.GetFelt()\n  relocatable, err := other_rel.AddFelt(m_felt)\n  if err != nil {\n   return *NewMaybeRelocatableFelt(lambdaworks.FeltZero()), err\n  }\n  return *NewMaybeRelocatableRelocatable(relocatable), nil\n } else {\n  return *NewMaybeRelocatableFelt(lambdaworks.FeltZero()), errors.New(\"RelocatableAdd\")\n }\n}\n```\n\n##### MaybeRelocatable.Sub\n\nThere are four different cases to consider when adding two `MaybeRelocatable` values:\n\n1. Both values are `Felt`: We perform felt subtraction\n2. Both values are `Relocatable`: We call `Relocatable.Sub`\n3. First value is `Felt` and other in `Relocatable`: This operation is not supported so we return an error\n4. First value is `Relocatable` and other is `Felt`: We call `Relocatable.SubFelt`\n\n```go\nfunc (m MaybeRelocatable) Sub(other MaybeRelocatable) (MaybeRelocatable, error) {\n // check if they are felt\n m_int, m_is_int := m.GetFelt()\n other_felt, other_is_felt := other.GetFelt()\n\n if m_is_int \u0026\u0026 other_is_felt {\n  result := NewMaybeRelocatableFelt(m_int.Sub(other_felt))\n  return *result, nil\n }\n\n // check if one is relocatable and the other int\n m_rel, is_rel_m := m.GetRelocatable()\n other_rel, is_rel_other := other.GetRelocatable()\n\n if is_rel_m \u0026\u0026 !is_rel_other {\n  relocatable, err := m_rel.SubFelt(other_felt)\n  if err != nil {\n   return *NewMaybeRelocatableFelt(lambdaworks.FeltZero()), err\n  }\n  return *NewMaybeRelocatableRelocatable(relocatable), nil\n\n } else if is_rel_m \u0026\u0026 is_rel_other {\n  offset_diff, err := m_rel.Sub(other_rel)\n  if err != nil {\n   return *NewMaybeRelocatableFelt(lambdaworks.FeltZero()), err\n  }\n  return *NewMaybeRelocatableFelt(lambdaworks.FeltFromUint64(uint64(offset_diff))), nil\n } else {\n  return *NewMaybeRelocatableFelt(lambdaworks.FeltZero()), errors.New(\"Cant sub Relocatable from Felt\")\n }\n}\n```\n\n#### Memory\n\nAs we previously described, the memory is made up of a series of segments of variable length, each containing a continuous sequence of `MaybeRelocatable` elements. Memory is also immutable, which means that once we have written a value into memory, it can't be changed.\nThere are multiple valid ways to represent this memory structure, but the simplest way to represent it is by using a map, maping a `Relocatable` address to a `MaybeRelocatable` value.\nAs we don't have an actual representation of segments, we have to keep track of the number of segments.\n\n```go\ntype Memory struct {\n    data         map[Relocatable]MaybeRelocatable\n    num_segments uint\n}\n```\n\nNow we can define the basic memory operations:\n\n##### Insert\n\nHere we need to make perform some checks to make sure that the memory remains consistent with its rules:\n\n- We must check that insertions are performed on previously-allocated segments, by checking that the address's segment_index is lower than our segment counter\n- We must check that we are not mutating memory we have previously written, by checking that the memory doesn't already contain a value at that address that is not equal to the one we are inserting\n\n```go\nfunc (m *Memory) Insert(addr Relocatable, val *MaybeRelocatable) error {\n    // Check that insertions are preformed within the memory bounds\n    if addr.segmentIndex \u003e= int(m.num_segments) {\n        return errors.New(\"Error: Inserting into a non allocated segment\")\n    }\n\n    // Check for possible overwrites\n    prev_elem, ok := m.data[addr]\n    if ok \u0026\u0026 prev_elem != *val {\n        return errors.New(\"Memory is write-once, cannot overwrite memory value\")\n    }\n\n    m.data[addr] = *val\n\n    return nil\n}\n```\n\n##### Get\n\nThis is the easiest operation, as we only need to fetch the value from our map:\n\n```go\n// Gets some value stored in the memory address `addr`.\nfunc (m *Memory) Get(addr Relocatable) (*MaybeRelocatable, error) {\n    value, ok := m.data[addr]\n\n    if !ok {\n        return nil, errors.New(\"Memory Get: Value not found\")\n    }\n\n    return \u0026value, nil\n}\n```\n\n#### MemorySegmentManager\n\nIn our `Memory` implementation, it looks like we need to have segments allocated before performing any valid memory operation, but we can't do so from the `Memory` api. To do so, we need to use the `MemorySegmentManager`.\nThe `MemorySegmentManager` is in charge of creating new segments and calculating their size during the relocation process, it has the following structure:\n\n```go\ntype MemorySegmentManager struct {\n    segmentSizes map[uint]uint\n    Memory       Memory\n}\n```\n\nAnd the following methods:\n\n##### Add Segment\n\nAs we are using a map, we dont have to allocate memory for the new segment, so we only have to raise our segment counter and return the first address of the new segment:\n\n```go\nfunc (m *MemorySegmentManager) AddSegment() Relocatable {\n    ptr := Relocatable{int(m.Memory.num_segments), 0}\n    m.Memory.num_segments += 1\n    return ptr\n}\n```\n\n##### Load Data\n\nThis method inserts a contiguous array of values starting from a certain addres in memory, and returns the next address after the inserted values. This is useful when inserting the program's instructions in memory.\nIn order to perform this operation, we only need to iterate over the array, inserting each value at the address indicated by `ptr` while advancing the ptr with each iteration and then return the final ptr.\n\n```go\nfunc (m *MemorySegmentManager) LoadData(ptr Relocatable, data *[]MaybeRelocatable) (Relocatable, error) {\n    for _, val := range *data {\n        err := m.Memory.Insert(ptr, \u0026val)\n        if err != nil {\n            return Relocatable{0, 0}, err\n        }\n        ptr.offset += 1\n    }\n    return ptr, nil\n}\n```\n\n#### RunContext\n\nThe RunContext keeps track of the vm's registers. Cairo VM only has 3 registers:\n\n- The program counter `Pc`, which points to the next instruction to be executed.\n- The allocation pointer `Ap`, pointing to the next unused memory cell.\n- The frame pointer `Fp`, pointing to the base of the current stack frame. When a new function is called, `Fp` is set to the current `Ap` value. When the function returns, `Fp` goes back to its previous value.\n\nWe can represent it like this:\n\n```go\ntype RunContext struct {\n    Pc memory.Relocatable\n    Ap memory.Relocatable\n    Fp memory.Relocatable\n}\n```\n\n#### VirtualMachine\n\nWith all of these types and structures defined, we can build our VM:\n\n```go\ntype VirtualMachine struct {\n    RunContext     RunContext\n    currentStep    uint\n    Segments       memory.MemorySegmentManager\n}\n```\n\nTo begin coding the basic execution functionality of our VM, we only need these basic fields, we will be adding more fields as we dive deeper into this guide.\n\n#### Instruction Decoding and Execution\n\nCairo program execution is divided into steps, and in turn each step is divided into:\n  1. Instruction decoding\n  2. Instruction execution\n\n##### Step \n\nThis method is the organizer of the execution of each instruction, it orchestrates them and handles the possible errors. \n\nThe first thing it does is to obtain the instruction we want to run, it does that by getting the value on memory where the current pc is pointing. We know that the instruction has to be a felt, if it is not, then there is an error with the encoding of the instruction. \nOnce we retrieve the felt we have the `encoded instruction`, we need to decode it to get the fields from its bits representation. Felt is not useful anymore so we will get its integer representation. \nNow it's time to decode the instruction and then run the `decoded instruction`.\n\n\n```go\nfunc (v *VirtualMachine) Step() error {\n\tencoded_instruction, err := v.Segments.Memory.Get(v.RunContext.Pc)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"Failed to fetch instruction at %+v\", v.RunContext.Pc)\n\t}\n\n\tencoded_instruction_felt, ok := encoded_instruction.GetFelt()\n\tif !ok {\n\t\treturn errors.New(\"Wrong instruction encoding\")\n\t}\n\n\tencoded_instruction_uint, err := encoded_instruction_felt.ToU64()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tinstruction, err := DecodeInstruction(encoded_instruction_uint)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn v.RunInstruction(\u0026instruction)\n}\n```\n\n##### Decode instruction \n\n```go\n//  Structure of the 63-bit that form the first word of each instruction.\n//  See Cairo whitepaper, page 32 - https://eprint.iacr.org/2021/1063.pdf.\n// ┌─────────────────────────────────────────────────────────────────────────┐\n// │                     off_dst (biased representation)                     │\n// ├─────────────────────────────────────────────────────────────────────────┤\n// │                     off_op0 (biased representation)                     │\n// ├─────────────────────────────────────────────────────────────────────────┤\n// │                     off_op1 (biased representation)                     │\n// ├─────┬─────┬───────┬───────┬───────────┬────────┬───────────────────┬────┤\n// │ dst │ op0 │  op1  │  res  │    pc     │   ap   │      opcode       │ 0  │\n// │ reg │ reg │  src  │ logic │  update   │ update │                   │    │\n// ├─────┼─────┼───┬───┼───┬───┼───┬───┬───┼───┬────┼────┬────┬────┬────┼────┤\n// │  0  │  1  │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │ 8 │ 9 │ 10 │ 11 │ 12 │ 13 │ 14 │ 15 │\n// └─────┴─────┴───┴───┴───┴───┴───┴───┴───┴───┴────┴────┴────┴────┴────┴────┘\n```\n\nAs we can see in the chart above, all the information we need is present on the bits representation of the instruction. The first thing to do is create a structure that stores it. \n\n```go \ntype Instruction struct {\n\tOff0     int\n\tOff1     int\n\tOff2     int\n\tDstReg   Register\n\tOp0Reg   Register\n\tOp1Addr  Op1Src\n\tResLogic ResLogic\n\tPcUpdate PcUpdate\n\tApUpdate ApUpdate\n\tFpUpdate FpUpdate\n\tOpcode   Opcode\n}\n```\n\nAnd the good thing about this is that every combination of bits for each field is known, so we can code all the possible flags to work with. These flags are represented below. \n\nThe off0, off1, and off2 values are used to compute the address of the dst, op0 and op1 respectively.\nFor example, if the DstReg is AP and Off0 is -1, then we can compute the dst address by substracting one from the current value of ap.\n\nThere's two possible registers, ap and fp. The ap register (address pointer register) keeps track of memory addresses for data access. The fp register (frame pointer register) manages function call stack frames, local variables and parameter access.\n\n```go \ntype Register uint\n\nconst (\n\tAP Register = 0\n\tFP Register = 1\n)\n```\n\nThe Op1Src constants define sources for an operation, including immediate values, registers (ap, fp), and an operation result.\n\n```go\ntype Op1Src uint\n\nconst (\n\tOp1SrcImm Op1Src = 0\n\tOp1SrcAP  Op1Src = 1\n\tOp1SrcFP  Op1Src = 2\n\tOp1SrcOp0 Op1Src = 4\n)\n```\nThe ResLogic constants represent different types of results in a program, including operation results, addition, multiplication, and unconstrained values.\n\n```go\ntype ResLogic uint\n\nconst (\n\tResOp1           ResLogic = 0\n\tResAdd           ResLogic = 1\n\tResMul           ResLogic = 2\n\tResUnconstrained ResLogic = 3\n)\n```\n\nThe PcUpdate constants define different ways to update the program counter, including regular updates, jumps, relative jumps, and conditional jumps (jump if not zero).\n\n```go\ntype PcUpdate uint\n\nconst (\n\tPcUpdateRegular PcUpdate = 0\n\tPcUpdateJump    PcUpdate = 1\n\tPcUpdateJumpRel PcUpdate = 2\n\tPcUpdateJnz     PcUpdate = 3\n)\n```\n\nThe ApUpdate constants represent various ways of updating an address pointer, including regular updates, and different addition types.\n\n```go\ntype ApUpdate uint\n\nconst (\n\tApUpdateRegular ApUpdate = 0\n\tApUpdateAdd     ApUpdate = 1\n\tApUpdateAdd1    ApUpdate = 2\n\tApUpdateAdd2    ApUpdate = 3\n)\n```\n\nThe FpUpdate constants define different ways of updating the frame pointer, including regular updates, addition with a specific offset, and destination updates.\n\n```go\ntype FpUpdate uint\n\nconst (\n\tFpUpdateRegular FpUpdate = 0\n\tFpUpdateAPPlus2 FpUpdate = 1\n\tFpUpdateDst     FpUpdate = 2\n)\n```\n\nThe Opcode constants represent different types of operations or instructions, including no operation, assertion checks, function calls, and returns.\n\n```go\ntype Opcode uint\n\nconst (\n\tNOp      Opcode = 0\n\tAssertEq Opcode = 1\n\tCall     Opcode = 2\n\tRet      Opcode = 4\n)\n```\n\nNow, once everything is set up, we only have to retrive each field by getting its representative bits. We do that, creating different bitmasks to just get the value. \n\n1. Constants and Masks:\n    The method starts by defining constants and masks for various fields and properties of the instruction. These constants are used to extract specific bits from the encoded instruction and decode them into meaningful values. For instance, the HighBit constant represents the highest bit (bit 63) of the instruction, and various other masks are defined to extract different fields like destination register, opcode, update types, etc.\n\n    ```go\n    func DecodeInstruction(encodedInstruction uint64) (Instruction, error) {\n        const HighBit uint64 = 1 \u003c\u003c 63\n        const DstRegMask uint64 = 0x0001\n        const DstRegOff uint64 = 0\n        const Op0RegMask uint64 = 0x0002\n        const Op0RegOff uint64 = 1\n        const Op1SrcMask uint64 = 0x001C\n        const Op1SrcOff uint64 = 2\n        const ResLogicMask uint64 = 0x0060\n        const ResLogicOff uint64 = 5\n        const PcUpdateMask uint64 = 0x0380\n        const PcUpdateOff uint64 = 7\n        const ApUpdateMask uint64 = 0x0C00\n        const ApUpdateOff uint64 = 10\n        const OpcodeMask uint64 = 0x7000\n        const OpcodeOff uint64 = 12\n    ```\n\n2. Checking High Bit:\n    The first check in the method is whether the highest bit (bit 63) of the encoded instruction is set to zero. If it's not zero, this indicates an error, and the function returns an ErrNonZeroHighBitError.\n\n    ```go\n    if encodedInstruction\u0026HighBit != 0 {\n\t\treturn Instruction{}, ErrNonZeroHighBitError\n\t}\n    ```\n\n3. Extracting Offsets:\n    The method extracts three offsets from the encoded instruction. These offsets represent memory addresses used in the instruction. They are extracted using bitwise operations and masks to get the lower 16 bits of three different sections of the instruction.\n\n    ```go\n    var offset0 = fromBiasedRepresentation((encodedInstruction) \u0026 0xFFFF)\n    var offset1 = fromBiasedRepresentation((encodedInstruction \u003e\u003e 16) \u0026 0xFFFF)\n    var offset2 = fromBiasedRepresentation((encodedInstruction \u003e\u003e 32) \u0026 0xFFFF)\n\n    -----------------------------------------------------------------------------------------\n    func fromBiasedRepresentation(offset uint64) int {\n        var bias uint16 = 1 \u003c\u003c 15\n        return int(int16(uint16(offset) - bias))    \n    }\n    ```\n\n4. Extracting Flags:\n    The next step is to extract the flag section of the encoded instruction, which holds information about registers, sources, updates, and opcodes. This flag section is extracted using a bit shift to the right by 48 positions (which discards the lower 48 bits).\n    \n    ```go\n    var flags = encodedInstruction \u003e\u003e 48\n    ```\n\n5. Decoding Fields:\n    Using the extracted flag section, the method decodes various fields like destination register, op0 register, op1 source, result logic, pc update, ap update, and opcode. These fields are decoded by extracting specific bits from the flag section and mapping them to their corresponding enum values.\n\n    ```go \n\tvar dstRegNum = (flags \u0026 DstRegMask) \u003e\u003e DstRegOff\n\tvar op0RegNum = (flags \u0026 Op0RegMask) \u003e\u003e Op0RegOff\n\tvar op1SrcNum = (flags \u0026 Op1SrcMask) \u003e\u003e Op1SrcOff\n\tvar resLogicNum = (flags \u0026 ResLogicMask) \u003e\u003e ResLogicOff\n\tvar pcUpdateNum = (flags \u0026 PcUpdateMask) \u003e\u003e PcUpdateOff\n\tvar apUpdateNum = (flags \u0026 ApUpdateMask) \u003e\u003e ApUpdateOff\n\tvar opCodeNum = (flags \u0026 OpcodeMask) \u003e\u003e OpcodeOff\n\n\tvar dstRegister Register\n\tvar op0Register Register\n\tvar op1Src Op1Src\n\tvar pcUpdate PcUpdate\n\tvar res ResLogic\n\tvar opcode Opcode\n\tvar apUpdate ApUpdate\n\tvar fpUpdate FpUpdate\n\n\tif dstRegNum == 1 {\n\t\tdstRegister = FP\n\t} else {\n\t\tdstRegister = AP\n\t}\n\n\tif op0RegNum == 1 {\n\t\top0Register = FP\n\t} else {\n\t\top0Register = AP\n\t}\n\n\tswitch op1SrcNum {\n        case 0:\n            op1Src = Op1SrcOp0\n        case 1:\n            op1Src = Op1SrcImm\n        case 2:\n            op1Src = Op1SrcFP\n        case 4:\n            op1Src = Op1SrcAP\n        default:\n            return Instruction{}, ErrInvalidOp1RegError\n\t}\n\n\tswitch pcUpdateNum {\n        case 0:\n            pcUpdate = PcUpdateRegular\n        case 1:\n            pcUpdate = PcUpdateJump\n        case 2:\n            pcUpdate = PcUpdateJumpRel\n        case 4:\n            pcUpdate = PcUpdateJnz\n        default:\n            return Instruction{}, ErrInvalidPcUpdateError\n\t}\n\n\tswitch resLogicNum {\n        case 0:\n            if pcUpdate == PcUpdateJnz {\n                res = ResUnconstrained\n            } else {\n                res = ResOp1\n            }\n        case 1:\n            res = ResAdd\n        case 2:\n            res = ResMul\n        default:\n            return Instruction{}, ErrInvalidResError\n\t}\n\n\tswitch opCodeNum {\n        case 0:\n            opcode = NOp\n        case 1:\n            opcode = Call\n        case 2:\n            opcode = Ret\n        case 4:\n            opcode = AssertEq\n        default:\n            return Instruction{}, ErrInvalidOpcodeError\n\t}\n\n\tswitch apUpdateNum {\n        case 0:\n            if opcode == Call {\n                apUpdate = ApUpdateAdd2\n            } else {\n                apUpdate = ApUpdateRegular\n            }\n        case 1:\n            apUpdate = ApUpdateAdd\n        case 2:\n            apUpdate = ApUpdateAdd1\n        default:\n            return Instruction{}, ErrInvalidApUpdateError\n\t}\n\n\tswitch opcode {\n        case Call:\n            fpUpdate = FpUpdateAPPlus2\n        case Ret:\n            fpUpdate = FpUpdateDst\n        default:\n            fpUpdate = FpUpdateRegular\n\t}\n    ```\n    \n6. Creating the Instruction and Returning the Result:\n    With all the necessary information extracted and decoded, the method constructs an Instruction object by assigning the decoded values to its fields and returns the created Instruction object along with a nil error if the decoding process is successful.\n\n    ```go \n    return Instruction{\n\t\tOff0:     offset0,\n\t\tOff1:     offset1,\n\t\tOff2:     offset2,\n\t\tDstReg:   dstRegister,\n\t\tOp0Reg:   op0Register,\n\t\tOp1Addr:  op1Src,\n\t\tResLogic: res,\n\t\tPcUpdate: pcUpdate,\n\t\tApUpdate: apUpdate,\n\t\tFpUpdate: fpUpdate,\n\t\tOpcode:   opcode,\n\t}, nil\n    ```\n\n7. Error Handling:\n    If at any point during the decoding process, an unexpected value is encountered or the input doesn't conform to the expected pattern, the method returns an appropriate error. These errors include cases like invalid op1 register, invalid pc update, invalid result logic, invalid opcode, etc.\n\n    ```go\n    var ErrNonZeroHighBitError = errors.New(\"Instruction high bit was not set to zero\")\n    var ErrInvalidOp1RegError = errors.New(\"Instruction had invalid Op1 Register\")\n    var ErrInvalidPcUpdateError = errors.New(\"Instruction had invalid Pc update\")\n    var ErrInvalidResError = errors.New(\"Instruction had an invalid res\")\n    var ErrInvalidOpcodeError = errors.New(\"Instruction had an invalid opcode\")\n    var ErrInvalidApUpdateError = errors.New(\"Instruction had an invalid Ap Update\")\n    ```\n\n##### Run instruction\n\nAt this point, we have all the information we need from the instruction. Let's run it! \n\nThere are 5 steps to run an instruction, they will be explained in detail later.\n\n    1. Compute the operands of the instruction\n    2. Assert the correctness of the operands\n    3. Add the context's register state to the trace \n    4. Update registers\n    5. Add one to the current step\n\n```go\nfunc (v *VirtualMachine) RunInstruction(instruction *Instruction) error {\n\toperands, err := v.ComputeOperands(*instruction)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\terr = v.OpcodeAssertions(*instruction, operands)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tv.Trace = append(v.Trace, TraceEntry{Pc: v.RunContext.Pc, Ap: v.RunContext.Ap, Fp: v.RunContext.Fp})\n\n\terr = v.UpdateRegisters(instruction, \u0026operands)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tv.CurrentStep++\n\treturn nil\n}\n```\n\n#### Compute operands\n\nOnce the instruction has been decoded, it is executed by `RunInstruction` whose first function is to compute operands. This function is in charge of\ncalculating the addresses of the operands and fetching them from memory. If the function could not fetch the operands then they are deduced from the other operands,\ntaking in consideration what kind of opcode is being executed.\n\n```go\nfunc (vm *VirtualMachine) ComputeOperands(instruction Instruction) (Operands, error) {\n    var res *memory.MaybeRelocatable\n\n    dst_addr, err := vm.RunContext.ComputeDstAddr(instruction)\n    if err != nil {\n        return Operands{}, errors.New(\"FailedToComputeDstAddr\")\n    }\n    dst, _ := vm.Segments.Memory.Get(dst_addr)\n\n    op0_addr, err := vm.RunContext.ComputeOp0Addr(instruction)\n    if err != nil {\n        return Operands{}, fmt.Errorf(\"FailedToComputeOp0Addr: %s\", err)\n    }\n    op0, _ := vm.Segments.Memory.Get(op0_addr)\n\n    op1_addr, err := vm.RunContext.ComputeOp1Addr(instruction, op0)\n    if err != nil {\n        return Operands{}, fmt.Errorf(\"FailedToComputeOp1Addr: %s\", err)\n    }\n    op1, _ := vm.Segments.Memory.Get(op1_addr)\n\n    if op0 == nil {\n        deducedOp0, deducedRes, err := vm.DeduceOp0(\u0026instruction, dst, op1)\n        if err != nil {\n            return Operands{}, err\n        }\n        op0 = deducedOp0\n        if op0 != nil {\n            vm.Segments.Memory.Insert(op0_addr, op0)\n        }\n        res = deducedRes\n    }\n\n    if op1 == nil {\n        deducedOp1, deducedRes, err := vm.DeduceOp1(instruction, dst, op0)\n        if err != nil {\n            return Operands{}, err\n        }\n        op1 = deducedOp1\n        if op1 != nil {\n            vm.Segments.Memory.Insert(op1_addr, op1)\n        }\n        if res == nil {\n            res = deducedRes\n        }\n    }\n\n    if res == nil {\n        res, err = vm.ComputeRes(instruction, *op0, *op1)\n\n        if err != nil {\n            return Operands{}, err\n        }\n    }\n\n    if dst == nil {\n        deducedDst := vm.DeduceDst(instruction, res)\n        dst = deducedDst\n        if dst != nil {\n            vm.Segments.Memory.Insert(dst_addr, dst)\n        }\n    }\n\n    operands := Operands{\n        Dst: *dst,\n        Op0: *op0,\n        Op1: *op1,\n        Res: res,\n    }\n    return operands, nil\n}\n```\n\n##### ComputeDstAddr\n\nThe method `ComputeDstAddr` computes the address of the value that will be stored in the Destination (dst) operand. It checks which register its is relative to (wether ap or fp) and gets the direction by adding the instruction's first offset(off0) to the corresponding register.\n\n```go\nfunc (run_context RunContext) ComputeDstAddr(instruction Instruction) (memory.Relocatable, error) {\n    var base_addr memory.Relocatable\n    switch instruction.DstReg {\n    case AP:\n        base_addr = run_context.Ap\n    case FP:\n        base_addr = run_context.Fp\n    }\n\n    if instruction.Off0 \u003c 0 {\n        return base_addr.SubUint(uint(math.Abs(float64(instruction.Off0))))\n    } else {\n        return base_addr.AddUint(uint(instruction.Off0))\n    }\n\n}\n```\n\n##### ComputeOp0Addr\n\nThis method is similar to `ComputeDstAddr` but it uses the instruction second offset (off1) to add to the selected register (ap or fp)\n\n```go\nfunc (run_context RunContext) ComputeOp0Addr(instruction Instruction) (memory.Relocatable, error) {\n    var base_addr memory.Relocatable\n    switch instruction.Op0Reg {\n    case AP:\n        base_addr = run_context.Ap\n    case FP:\n        base_addr = run_context.Fp\n    }\n\n    if instruction.Off1 \u003c 0 {\n        return base_addr.SubUint(uint(math.Abs(float64(instruction.Off1))))\n    } else {\n        return base_addr.AddUint(uint(instruction.Off1))\n    }\n}\n\n```\n\n##### ComputeOp1Addr\n\nIt computes the address of `Op1` based on the `Op0` operand and the kind of Address the instruction has for `Op1`.\n\n- If its address is `Op1SrcFp` it calculates the direction from Fp register.\n- if it is `Op1SrcAp` then if calculates it if from Ap register.\n- If it is an immediate then checks if the offset 2 is 1 and calculates it from the `Pc`.\n- If it is an `Op1SrcOp0` it checks the `Op0` and calculates the direction from it.\n\nThen it performs and addition or a substraction if the `Off2` is negative or positive.\n\n```go\nfunc (run_context RunContext) ComputeOp1Addr(instruction Instruction, op0 *memory.MaybeRelocatable) (memory.Relocatable, error) {\n    var base_addr memory.Relocatable\n\n    switch instruction.Op1Addr {\n    case Op1SrcFP:\n        base_addr = run_context.Fp\n    case Op1SrcAP:\n        base_addr = run_context.Ap\n    case Op1SrcImm:\n        if instruction.Off2 == 1 {\n            base_addr = run_context.Pc\n        } else {\n            base_addr = memory.NewRelocatable(0, 0)\n            return memory.Relocatable{}, \u0026VirtualMachineError{Msg: \"UnknownOp0\"}\n        }\n    case Op1SrcOp0:\n        if op0 == nil {\n            return memory.Relocatable{}, errors.New(\"Unknown Op0\")\n        }\n        rel, is_rel := op0.GetRelocatable()\n        if is_rel {\n            base_addr = rel\n        } else {\n            return memory.Relocatable{}, errors.New(\"AddressNotRelocatable\")\n        }\n    }\n\n    if instruction.Off2 \u003c 0 {\n        return base_addr.SubUint(uint(math.Abs(float64(instruction.Off2))))\n    } else {\n        return base_addr.AddUint(uint(instruction.Off2))\n    }\n}\n```\n\n##### DeduceOp0\n\nThe method deduces the value of `Op0` if possible (based on `dst` and `Op1`).\nIf Instruction's opcode is a `Call` `Op0` is deduced by adding the instruction size to the program counter.\n\n- If it is an `AssertEq` then a second switch case is used to check what `ResLogic` is.\n- If it is `ResAdd` `Op0` is deduced from the substraction of `Op1` from `Dst`,  if is is `Resmul` the `Op0` is deduced from the division of `Dst` and `Op1` (both felt values).\n- Otherwise op0 is nil.  \n\nThe method also deduces `res` by using the value of `dst`\n\n```go\nfunc (vm *VirtualMachine) DeduceOp0(instruction *Instruction, dst *memory.MaybeRelocatable, op1 *memory.MaybeRelocatable) (deduced_op0 *memory.MaybeRelocatable, deduced_res *memory.MaybeRelocatable, error error) {\n    switch instruction.Opcode {\n    case Call:\n        deduced_op0 := vm.RunContext.Pc\n        deduced_op0.Offset += instruction.Size()\n        return memory.NewMaybeRelocatableRelocatable(deduced_op0), nil, nil\n    case AssertEq:\n        switch instruction.ResLogic {\n        case ResAdd:\n            if dst != nil \u0026\u0026 op1 != nil {\n                deduced_op0, err := dst.Sub(*op1)\n                if err != nil {\n                    return nil, nil, err\n                }\n                return \u0026deduced_op0, dst, nil\n            }\n        case ResMul:\n            if dst != nil \u0026\u0026 op1 != nil {\n                dst_felt, dst_is_felt := dst.GetFelt()\n                op1_felt, op1_is_felt := op1.GetFelt()\n                if dst_is_felt \u0026\u0026 op1_is_felt \u0026\u0026 !op1_felt.IsZero() {\n                    return memory.NewMaybeRelocatableFelt(dst_felt.Div(op1_felt)), dst, nil\n\n                }\n            }\n        }\n    }\n    return nil, nil, nil\n}\n```\n\n##### DeduceOp1\n\nThe method deduces the value of `Op1` if possible (based on `dst` and `Op0`) it also deduces `res` if possible.\n\n- If the instruction opcode is `AssertEq` a switch case is used to check what the `ResLogic` is.\n- If it is a `ResOp1` then the value of op1 is equal to the dst operand.\n- If `ResLogic` is `ResAdd` op1 is deduced from the substraction of `op0` from `dst`.\n- If it is `ResMul` `op1` is deduced from the division of `dst` by `op0`,\n\nIn all the cases `res` is equal to `dst`. if none of the former cases apply then nil is returned.\n\n```go\nfunc (vm *VirtualMachine) DeduceOp1(instruction Instruction, dst *memory.MaybeRelocatable, op0 *memory.MaybeRelocatable) (*memory.MaybeRelocatable, *memory.MaybeRelocatable, error) {\n    if instruction.Opcode == AssertEq {\n        switch instruction.ResLogic {\n        case ResOp1:\n            return dst, dst, nil\n        case ResAdd:\n            if op0 != nil \u0026\u0026 dst != nil {\n                dst_rel, err := dst.Sub(*op0)\n                if err != nil {\n                    return nil, nil, err\n                }\n                return \u0026dst_rel, dst, nil\n            }\n        case ResMul:\n            dst_felt, dst_is_felt := dst.GetFelt()\n            op0_felt, op0_is_felt := op0.GetFelt()\n            if dst_is_felt \u0026\u0026 op0_is_felt \u0026\u0026 !op0_felt.IsZero() {\n                res := memory.NewMaybeRelocatableFelt(dst_felt.Div(op0_felt))\n                return res, dst, nil\n            }\n        }\n    }\n    return nil, nil, nil\n}\n\n```\n\n##### ComputeRes\n\nIf the Res value has not been deduced in the previous steps then it is computed based on the `Op0` and `Op1` values.\n\n- If `ResLogic` is `ResOp1` then `res` is equal to `op1`.\n- If it is `ResAdd` then `res` is deduced from the addition of `op0` and `op1`.\n- If it is `ResMul` `res` is deduced from the multiplication of `op0` and `op1`.\n- Otherwise `res` is nil.\n\n```go\nfunc (vm *VirtualMachine) ComputeRes(instruction Instruction, op0 memory.MaybeRelocatable, op1 memory.MaybeRelocatable) (*memory.MaybeRelocatable, error) {\n    switch instruction.ResLogic {\n    case ResOp1:\n        return \u0026op1, nil\n\n    case ResAdd:\n        maybe_rel, err := op0.Add(op1)\n        if err != nil {\n            return nil, err\n        }\n        return \u0026maybe_rel, nil\n\n    case ResMul:\n        num_op0, m_type := op0.GetFelt()\n        num_op1, other_type := op1.GetFelt()\n        if m_type \u0026\u0026 other_type {\n            result := memory.NewMaybeRelocatableFelt(num_op0.Mul(num_op1))\n            return result, nil\n        } else {\n            return nil, errors.New(\"ComputeResRelocatableMul\")\n        }\n\n    case ResUnconstrained:\n        return nil, nil\n    }\n    return nil, nil\n}\n```\n\n##### DeduceDst\n\nIf the destination value has not been calculated before then it is deduced based on the Res operand. If the opcode is an `AssertEq` then dst is equal res.\nIf it is a `Call` then its value is taken from the `Fp` register\n\n```go\nfunc (vm *VirtualMachine) DeduceDst(instruction Instruction, res *memory.MaybeRelocatable) *memory.MaybeRelocatable {\n    switch instruction.Opcode {\n    case AssertEq:\n        return res\n    case Call:\n        return memory.NewMaybeRelocatableRelocatable(vm.RunContext.Fp)\n\n    }\n    return nil\n}\n```\n\n#### Opcode assertions\n\nOnce we have the instruction's operands to work with, we have to ensure the correctness of them. The first thing we need to differentiate is which type of instruction are we running, we do this by looking at the instruction's opcode.\n\nThe posible opcodes we want to perform assertions on are:\n\n  1. AssertEq instruction\n  2. Call instruction\n\nIn the first option, we need to ensure the result operand is not null (nil in this case) and also that the result operand is equal to the dst operand. If any of those things fail, we throw an error.\n\nOn the other hand, the Call instruction, what we do first is define our return pc register, we do that adding the size of the instruction to the current pc. Then, we check our operand op0 is equal to the return pc and our dst operand is the same as the return fp register. If any of those things fail, we throw an error.\n\nIf this method returns a nil error, it means operands were computed correctly and we are good to go!\n\n```go\nfunc (vm *VirtualMachine) OpcodeAssertions(instruction Instruction, operands Operands) error {\n    switch instruction.Opcode {\n    case AssertEq:\n        if operands.Res == nil {\n            return \u0026VirtualMachineError{\"UnconstrainedResAssertEq\"}\n        }\n        if !operands.Res.IsEqual(\u0026operands.Dst) {\n            return \u0026VirtualMachineError{\"DiffAssertValues\"}\n        }\n    case Call:\n        new_rel, err := vm.RunContext.Pc.AddUint(instruction.Size())\n        if err != nil {\n            return err\n        }\n        returnPC := memory.NewMaybeRelocatableRelocatable(new_rel)\n\n        if !operands.Op0.IsEqual(returnPC) {\n            return \u0026VirtualMachineError{\"CantWriteReturnPc\"}\n        }\n\n        returnFP := vm.RunContext.Fp\n        dstRelocatable, _ := operands.Dst.GetRelocatable()\n        if !returnFP.IsEqual(\u0026dstRelocatable) {\n            return \u0026VirtualMachineError{\"CantWriteReturnFp\"}\n        }\n    }\n\n    return nil\n}\n```\n\n#### Updating Registers\n\nAfter we succesfully computed the value of the operands, it's now time to update the value of the registers, we will update each register according to the `PcUpdate`, `ApUpdate` and `FpUpdate` fields of the instruction respectively.\n\n##### UpdatePc\n\nAs we already know, the pc (program counter) points to the next instruction in memory. When no jumps take place, the pc is updated to point to the next instruction by adding the instruction size to it. The instruction size is 1 if there is no immediate value, and 2 if there is an immediate value following the instruction.\nCairo also supports 3 different types of jumps. The first one is a regular jump, in which the pc takes the value of the res operand. The next one is a relative jump, in which the pc advances by a number of positions set by the res operand. And the last one is a jump not zero, which performs a relative jump, advancing the number of positions given by op1, if the value of the dst operand is not zero, or performs a regular update if the value of the dst operand is zero. The operand will only be zero if it is a Felt value which is zero, relocatable values are never zero.\n\n```go\n// Updates the value of PC according to the executed instruction\nfunc (vm *VirtualMachine) UpdatePc(instruction *Instruction, operands *Operands) error {\n    switch instruction.PcUpdate {\n    case PcUpdateRegular:\n        vm.RunContext.Pc.Offset += instruction.Size()\n    case PcUpdateJump:\n        if operands.Res == nil {\n            return errors.New(\"Res.UNCONSTRAINED cannot be used with PcUpdate.JUMP\")\n        }\n        res, ok := operands.Res.GetRelocatable()\n        if !ok {\n            return errors.New(\"An integer value as Res cannot be used with PcUpdate.JUMP\")\n        }\n        vm.RunContext.Pc = res\n    case PcUpdateJumpRel:\n        if operands.Res == nil {\n            return errors.New(\"Res.UNCONSTRAINED cannot be used with PcUpdate.JUMP_REL\")\n        }\n        res, ok := operands.Res.GetFelt()\n        if !ok {\n            return errors.New(\"A relocatable value as Res cannot be used with PcUpdate.JUMP_REL\")\n        }\n        new_pc, err := vm.RunContext.Pc.AddFelt(res)\n        if err != nil {\n            return err\n        }\n        vm.RunContext.Pc = new_pc\n    case PcUpdateJnz:\n        if operands.Dst.IsZero() {\n            vm.RunContext.Pc.Offset += instruction.Size()\n        } else {\n            new_pc, err := vm.RunContext.Pc.AddMaybeRelocatable(operands.Op1)\n            if err != nil {\n                return err\n            }\n            vm.RunContext.Pc = new_pc\n        }\n\n    }\n    return nil\n}\n```\n\nSome auxiliary methods were added for this method:\n\n###### Instruction.Size\n\nReturns 1 if the instruction has no immediate value or 2 if it has. We can tell that an instruction has an immediate value if the op1 address is given by the immediate value.\n\n```go\nfunc (i *Instruction) Size() uint {\n    if i.Op1Addr == Op1SrcImm {\n        return 2\n    }\n    return 1\n}\n```\n\n###### MaybeRelocatable.IsZero()\n\nReturns true if the value is a Felt that is zero, returns false otherwise\n\n```go\n    func (m *MaybeRelocatable) IsZero() bool {\n    felt, is_int := m.GetFelt()\n    return is_int \u0026\u0026 felt.IsZero()\n}\n```\n\n##### UpdateFp\n\nAs we already know, the fp (frame pointer) points to the frame of the current function. It can be updated in 4 different ways. A regular fp update means no changes to the fp register. An ap plus 2 update consists on asigning the value of ap to fp and increasing it's offset by two (note: in the code below we only assign the offset, as fp and ap live on the execution segment and therefore have the same segment index). A dst fp update consists in performing either a direct or relative jump based on the value of the dst operand. If dst is a relocatable, fp will take the value of dst, if dst is a felt, fp's offset will be increased by the amount given by dst\n\n```go\n// Updates the value of FP according to the executed instruction\nfunc (vm *VirtualMachine) UpdateFp(instruction *Instruction, operands *Operands) error {\n    switch instruction.FpUpdate {\n    case FpUpdateAPPlus2:\n        vm.RunContext.Fp.Offset = vm.RunContext.Ap.Offset + 2\n    case FpUpdateDst:\n        rel, ok := operands.Dst.GetRelocatable()\n        if ok {\n            vm.RunContext.Fp = rel\n        } else {\n            felt, _ := operands.Dst.GetFelt()\n            new_fp, err := vm.RunContext.Fp.AddFelt(felt)\n            if err != nil {\n                return err\n            }\n            vm.RunContext.Fp = new_fp\n        }\n    }\n    return nil\n}\n```\n\n##### UpdateAp\n\nAnd lastly, the ap register points to the next unsused memory cell and has 4 types of update. A regular ap update means no changes to the ap register. An add update consists on advancing the ap register by the amount given by res. And the add1 and add2 updates consist on advancing the op register by 1 and 2 respectively.\n\n```go\n// Updates the value of AP according to the executed instruction\nfunc (vm *VirtualMachine) UpdateAp(instruction *Instruction, operands *Operands) error {\n    switch instruction.ApUpdate {\n    case ApUpdateAdd:\n        if operands.Res == nil {\n            return errors.New(\"Res.UNCONSTRAINED cannot be used with ApUpdate.ADD\")\n        }\n        new_ap, err := vm.RunContext.Ap.AddMaybeRelocatable(*operands.Res)\n        if err != nil {\n            return err\n        }\n        vm.RunContext.Ap = new_ap\n    case ApUpdateAdd1:\n        vm.RunContext.Ap.Offset += 1\n    case ApUpdateAdd2:\n        vm.RunContext.Ap.Offset += 2\n    }\n    return nil\n}\n```\n\n#### CairoRunner\n\nNow that can can execute cairo steps, lets look at the VM's initialization step.\nWe will begin by creating our `CairoRunner`:\n\n```go\ntype CairoRunner struct {\n    Program       vm.Program\n    Vm            vm.VirtualMachine\n    ProgramBase   memory.Relocatable\n    executionBase memory.Relocatable\n    initialPc     memory.Relocatable\n    initialAp     memory.Relocatable\n    initialFp     memory.Relocatable\n    finalPc       memory.Relocatable\n    mainOffset    uint\n}\n\nfunc NewCairoRunner(program vm.Program) *CairoRunner {\n    mainIdentifier, ok := (*program.Identifiers)[\"__main__.main\"]\n main_offset := uint(0)\n if ok {\n  main_offset = uint(mainIdentifier.PC)\n }\n    return \u0026CairoRunner{Program: program, Vm: *vm.NewVirtualMachine(), mainOffset: main_offset}\n\n}\n```\n\nNow we will create our `Initialize` method step by step:\n\n```go\n// Performs the initialization step, returns the end pointer (pc upon which execution should stop)\nfunc (r *CairoRunner) Initialize() (memory.Relocatable, error) {\n    r.initializeSegments()\n    end, err := r.initializeMainEntrypoint()\n    r.initializeVM()\n    return end, err\n}\n```\n\n##### InitializeSegments\n\nThis method will create our program and execution segments\n\n```go\nfunc (r *CairoRunner) initializeSegments() {\n    // Program Segment\n    r.ProgramBase = r.Vm.Segments.AddSegment()\n    // Execution Segment\n    r.executionBase = r.Vm.Segments.AddSegment()\n}\n```\n\n##### initializeMainEntrypoint\n\nThis method will initialize the memory and initial register values to begin execution from the main entrypoint, and return the final pc\n\n```go\nfunc (r *CairoRunner) initializeMainEntrypoint() (memory.Relocatable, error) {\n    stack := make([]memory.MaybeRelocatable, 0, 2)\n    return_fp := r.Vm.Segments.AddSegment()\n    return r.initializeFunctionEntrypoint(r.mainOffset, \u0026stack, return_fp)\n}\n```\n\n##### initializeFunctionEntrypoint\n\nThis method will initialize the memory and initial register values to execute a cairo function given its offset within the program segment (aka entrypoint) and return the final pc. In our case, this function will be the main entrypoint, but later on we will be able to use this method to run starknet contract entrypoints.\nThe stack will then be loaded into the execution segment in the next method. For now, the stack will be empty, but later on it will contain the builtin bases (which are the arguments for the main function), and the function arguments when running a function from a starknet contract.\n\n```go\nfunc (r *CairoRunner) initializeFunctionEntrypoint(entrypoint uint, stack *[]memory.MaybeRelocatable, return_fp memory.Relocatable) (memory.Relocatable, error) {\n    end := r.Vm.Segments.AddSegment()\n    *stack = append(*stack, *memory.NewMaybeRelocatableRelocatable(end), *memory.NewMaybeRelocatableRelocatable(return_fp))\n    r.initialFp = r.executionBase\n    r.initialFp.Offset += uint(len(*stack))\n    r.initialAp = r.initialFp\n    r.finalPc = end\n    return end, r.initializeState(entrypoint, stack)\n}\n```\n\n##### InitializeState\n\nThis method will be in charge of loading the program data into the program segment and the stack into the execution segment\n\n```go\nfunc (r *CairoRunner) initializeState(entrypoint uint, stack *[]memory.MaybeRelocatable) error {\n    r.initialPc = r.ProgramBase\n    r.initialPc.Offset += entrypoint\n    // Load program data\n    _, err := r.Vm.Segments.LoadData(r.ProgramBase, \u0026r.Program.Data)\n    if err == nil {\n        _, err = r.Vm.Segments.LoadData(r.executionBase, stack)\n    }\n    return err\n}\n```\n\n##### initializeVm\n\nThis method will set the values of the VM's `RunContext` with our `CairoRunner`'s initial values\n\n```go\nfunc (r *CairoRunner) initializeVM() {\n    r.Vm.RunContext.Ap = r.initialAp\n    r.Vm.RunContext.Fp = r.initialFp\n    r.Vm.RunContext.Pc = r.initialPc\n}\n```\n\nWith `CairoRunner.Initialize()` now complete we can move on to the execution step:\n\n##### RunUntilPc\n\nThis method will continuously execute cairo steps until the end pc, returned by 'CairoRunner.Initialize()' is reached\n\n```go\nfunc (r *CairoRunner) RunUntilPC(end memory.Relocatable) error {\n for r.Vm.RunContext.Pc != end {\n  err := r.Vm.Step()\n  if err != nil {\n   return err\n  }\n }\n return nil\n```\n\nOnce we are done executing, we can relocate our memory and trace and output them into files.\n\n#### Relocate\n\nThis method will relocate the memory and trace generated by the program execution. Relocating means that our VM transforms a two-dimensional memory (aka a memory divided by segments) to a continuous, one-dimensional memory.\nIn this section, we will refer to the two-dimensional memory as the original memory and the one-dimensional memory as the relocated memory.\nThe memory relocation process is explained at a high level [here](#memory-relocation).\n\nThe original memory is accessed using `Relocatable`s while the relocated memory is accessed using uints. Also, the original memory values can be either `Felt`s of `Relocatable`s while the relocated memory values are all `Felt`s.\n\nThe relocation process is divided into 4 steps:\n\n1. Compute the sizes of each memory segment.\n2. Build an array that contains the first relocated address of each segment.\n3. Creates the relocated memory transforming the original memory by using the array built in 2.\n4. Creates the relocated trace transforming the original trace by using the array built in 2.\n\nThe function that does the relocation process is shown below:\n\n```go\nfunc (v *VirtualMachine) Relocate() error {\n    v.Segments.ComputeEffectiveSizes()\n    if len(v.Trace) == 0 {\n        return nil\n    }\n\n    relocationTable, ok := v.Segments.RelocateSegments()\n    // This should be unreachable\n    if !ok {\n        return errors.New(\"ComputeEffectiveSizes called but RelocateSegments still returned error\")\n    }\n\n    relocatedMemory, err := v.Segments.RelocateMemory(\u0026relocationTable)\n    if err != nil {\n        return err\n    }\n\n    v.RelocateTrace(\u0026relocationTable)\n    v.RelocatedMemory = relocatedMemory\n    return nil\n}\n```\n\nNotice that each step is encapsulated into a function.\nWe need to add the relocated trace and relocated memory fields to the `VirtualMachine` struct:\n\n```go\ntype VirtualMachine struct {\n    RunContext     RunContext\n    currentStep    uint\n    Segments       memory.MemorySegmentManager\n    Trace           []TraceEntry\n    RelocatedTrace  []RelocatedTraceEntry\n    RelocatedMemory map[uint]lambdaworks.Felt\n}\n```\n\nAlso we need to add some methods to `MemorySegmentManager` and to `VirtualMachine`.\nWe will look into each one in the following subsections.\n\n#### ComputeEffectiveSizes\n\nTo relocate the memory segments, we first need to know the size of each segment of the memory.\nThis method computes those sizes by returning a map whose keys are segment indexes and its values are the segment sizes:\n\n```go\nfunc (m *MemorySegmentManager) ComputeEffectiveSizes() map[uint]uint {\n    if len(m.SegmentSizes) == 0 {\n\n        for ptr := range m.Memory.data {\n            segmentIndex := uint(ptr.SegmentIndex)\n            segmentMaxSize := m.SegmentSizes[segmentIndex]\n            segmentSize := ptr.Offset + 1\n            if segmentSize \u003e segmentMaxSize {\n                m.SegmentSizes[segmentIndex] = segmentSize\n            }\n        }\n    }\n\n    return m.SegmentSizes\n}\n```\n\nNotice that this method will only do something once: consecutive calls won't do anything.\nThis is because the relocation process will happen only after the program execution and never again.\nThe `Relocate` function shouldn't be called more than once.\n\n#### RelocateSegments\n\nOnce we have the segment sizes, we need to know where to relocate the segments.\nBecause we want the relocated memory to be continuous, the segments should be placed one after the other.\nThis means that the last address of the segment `i` is followed by the first address of the segment `i + 1`.\nTo know where to relocate the segments, we need to know the first address of each segment as if they were already relocated.\nWe also need to enforce that `RelocateSegments` is called after `ComputeEffectiveSizes`:\n\n```go\nfunc (m *MemorySegmentManager) RelocateSegments() ([]uint, bool) {\n    if m.SegmentSizes == nil {\n        return nil, false\n    }\n\n    first_addr := uint(1)\n    relocation_table := []uint{first_addr}\n\n    for i := uint(0); i \u003c m.Memory.NumSegments(); i++ {\n        new_addr := relocation_table[i] + m.SegmentSizes[i]\n        relocation_table = append(relocation_table, new_addr)\n    }\n    relocation_table = relocation_table[:len(relocation_table)-1]\n\n    return relocation_table, true\n}\n```\n\n#### RelocateMemory\n\nOnce we have where each segment should go in the relocated memory, we can relocate the memory segments.\n\n```go\nfunc (s *MemorySegmentManager) RelocateMemory(relocationTable *[]uint) (map[uint]lambdaworks.Felt, error) {\n    relocatedMemory := make(map[uint]lambdaworks.Felt, 0)\n\n    for i := uint(0); i \u003c s.Memory.NumSegments(); i++ {\n        for j := uint(0); j \u003c s.SegmentSizes[i]; j++ {\n            ptr := NewRelocatable(int(i), j)\n            cell, err := s.Memory.Get(ptr)\n            if err == nil {\n                relocatedAddr := ptr.RelocateAddress(relocationTable)\n                value, err := cell.RelocateValue(relocationTable)\n                if err != nil {\n                    return nil, err\n                }\n                relocatedMemory[relocatedAddr] = value\n            }\n        }\n    }\n\n    return relocatedMemory, nil\n}\n```\n\nThis method calls two new methods: `RelocateAddress` from `Relocatable` and `RelocateValue` from `MaybeRelocatable`.\nLet's implement them.\n\n##### RelocateAddress\n\nThis `Relocatable`'s method transforms an address of the original memory into an address of the relocated memory.\nBecause the relocated memory is one-dimensional and not divided into segments, the memory addresses are not of type `Relocatable` but\n`uint`.\n\n```go\nfunc (r *Relocatable) RelocateAddress(relocationTable *[]uint) uint {\n    return (*relocationTable)[r.SegmentIndex] + r.Offset\n}\n```\n\n##### RelocateValue\n\nThis `MaybeRelocatable`'s method transforms a value of the original memory into a value of the relocated memory.\n\n- If the value is a `Felt`, the method doesn't transform it and returns the value as is.\n- If the value is a `Relocatable`, the method transforms it to an address of the relocated memory.\n- If the value is any other type, the method returns an error.\n\n```go\nfunc (m *MaybeRelocatable) RelocateValue(relocationTable *[]uint) (lambdaworks.Felt, error) {\n    inner_felt, ok := m.GetFelt()\n    if ok {\n        return inner_felt, nil\n    }\n\n    inner_relocatable, ok := m.GetRelocatable()\n    if ok {\n        return lambdaworks.FeltFromUint64(uint64(inner_relocatable.RelocateAddress(relocationTable))), nil\n    }\n\n    return lambdaworks.FeltZero(), errors.New(fmt.Sprintf(\"Unexpected type %T\", m.inner))\n}\n```\n\n#### RelocateTrace\n\nAfter running `RelocateMemory` and returning the relocated memory without errors, the `Relocate` function calls `RelocateTrace`.\nThis method transforms the fields of each trace entry from `Relocatable`s to `Felt`s.\nThe fields of each entry are pc, ap and fp.\nBecause those fields are address, the trace relocation process involves relocating addresses.\nThat's why, this method also calls `RelocateAddress`:\n\n```go\nfunc (v *VirtualMachine) RelocateTrace(relocationTable *[]uint) error {\n    if len(*relocationTable) \u003c 2 {\n        return errors.New(\"no relocation found for execution segment\")\n    }\n\n    for _, entry := range v.Trace {\n        v.RelocatedTrace = append(v.RelocatedTrace, RelocatedTraceEntry{\n            Pc: lambdaworks.FeltFromUint64(uint64(entry.Pc.RelocateAddress(relocationTable))),\n            Ap: lambdaworks.FeltFromUint64(uint64(entry.Ap.RelocateAddress(relocationTable))),\n            Fp: lambdaworks.FeltFromUint64(uint64(entry.Fp.RelocateAddress(relocationTable))),\n        })\n    }\n\n    return nil\n}\n```\n\nLike in `RelocateMemory`, we need to check that the `RelocateSegments` function was called before.\n\nOnce the program was executed, the `VirtualMachine` will have generated a relocated trace and a relocated memory for that execution.\nBoth trace and memory should be outputs of the execution, so we will write two functions that respectively write the trace and memory\ninto a file.\nWe will create a package called `cairo_run` and create those functions there.\n\n#### Writing the trace into a file\n\nFirst, we will add a function in our new `cairo_run` package to write the relocated trace into a buffer.\nThis method converts the pc, fp and ap fields of each trace entry into a `uint64` and writes each integer into the buffer in little endian:\n\n```go\nfunc WriteEncodedTrace(relocatedTrace []vm.RelocatedTraceEntry, dest io.Writer) error {\n    for i, entry := range relocatedTrace {\n        ap_buffer := make([]byte, 8)\n        ap, err := entry.Ap.ToU64()\n        if err != nil {\n            return err\n        }\n        binary.LittleEndian.PutUint64(ap_buffer, ap)\n        _, err = dest.Write(ap_buffer)\n        if err != nil {\n            return encodeTraceError(i, err)\n        }\n\n        fp_buffer := make([]byte, 8)\n        fp, err := entry.Fp.ToU64()\n        if err != nil {\n            return err\n        }\n        binary.LittleEndian.PutUint64(fp_buffer, fp)\n        _, err = dest.Write(fp_buffer)\n        if err != nil {\n            return encodeTraceError(i, err)\n        }\n\n        pc_buffer := make([]byte, 8)\n        pc, err := entry.Pc.ToU64()\n        if err != nil {\n            return err\n        }\n        binary.LittleEndian.PutUint64(pc_buffer, pc)\n        _, err = dest.Write(pc_buffer)\n        if err != nil {\n            return encodeTraceError(i, err)\n        }\n    }\n\n    return nil\n}\n```\n\n#### Writing the memory into a file\n\nSecond, we will add a function in the `cairo_run` package to write the relocated memory into another buffer.\nWe want to write into the buffer the pairs of addresses and values by following a specific order.\nIn this case, we want those pairs to be incrementally ordered by address.\nBecause we implemented the relocated memory as a map and we store the addresses as keys, if we iterate over the relocated memory using\n`range`, we will end up storing the pairs of addresses and values without following any specific order.\nSo, first we sort the relocated memory addresses and then we iterate those addresses to write each pair into the buffer.\nBefore writing the relocated memory values into the buffer, we have to convert them to bytes in little endian by using the lambdaworks\nmethod `ToLeBytes`.\nThat method returns an array and `io.Writer.Write` expects a slice, so we convert the array that `ToLeBytes` returns to a slice.\n\n```go\nfunc WriteEncodedMemory(relocatedMemory map[uint]lambdaworks.Felt, dest io.Writer) error {\n    // create a slice to store keys of the relocatedMemory map\n    keysMap := make([]uint, 0, len(relocatedMemory))\n    for k := range relocatedMemory {\n        keysMap = append(keysMap, k)\n    }\n\n    // sort the keys\n    sort.Slice(keysMap, func(i, j int) bool { return keysMap[i] \u003c keysMap[j] })\n\n    // iterate over the `relocatedMemory` map in sorted key order\n    for _, k := range keysMap {\n        // write the key\n        keyArray := make([]byte, 8)\n        binary.LittleEndian.PutUint64(keyArray, uint64(k))\n        _, err := dest.Write(keyArray)\n        if err != nil {\n            return encodeMemoryError(k, err)\n        }\n\n        // write the value\n        valueArray := relocatedMemory[k].ToLeBytes()\n\n        _, err = dest.Write(valueArray[:])\n        if err != nil {\n            return encodeMemoryError(k, err)\n        }\n    }\n\n    return nil\n}\n```\n\n#### Putting it all together\n\nNow it's time to finally add our `main` function to the project!\nThe CLI will receive one argument: the program path.\nThis path will be passed as argument to a new function called `CairoRun`.\nThis new function will return the cairo runner and an error, if it exists one during the program execution.\nIf the program execution ends successfully, we write the relocated trace and memory in files respectively and print that the execution was ended with no errors.\nIf the program execution ends with an error, we don't write any file and print the corresponding error.\n\n```go\nfunc main() {\n    if len(os.Args) \u003c 2 {\n        fmt.Println(\"Wrong argument count: Use go run cmd/cli/main.go COMPILED_JSON\")\n        return\n    }\n    cli_args := os.Args[1:]\n    programPath := cli_args[0]\n    cairoRunner, err := cairo_run.CairoRun(programPath)\n    if err != nil {\n        fmt.Printf(\"Failed with error: %s\", err)\n        return\n    }\n    traceFilePath := strings.Replace(programPath, \".json\", \".go.trace\", 1)\n    traceFile, err := os.OpenFile(traceFilePath, os.O_RDWR|os.O_CREATE, 0644)\n    defer traceFile.Close()\n\n    memoryFilePath := strings.Replace(programPath, \".json\", \".go.memory\", 1)\n    memoryFile, err := os.OpenFile(memoryFilePath, os.O_RDWR|os.O_CREATE, 0644)\n    defer memoryFile.Close()\n\n    cairo_run.WriteEncodedTrace(cairoRunner.Vm.RelocatedTrace, traceFile)\n    cairo_run.WriteEncodedMemory(cairoRunner.Vm.RelocatedMemory, memoryFile)\n\n    println(\"Done!\")\n}\n```\n\nTo make our `main` function work, we still need to add another function to the `cairo_run` package.\nThe `CairoRun` function will be responsible of integrating the initialization, execution and relocation.\n\n```go\nfunc CairoRun(programPath string) (*runners.CairoRunner, error) {\n    compiledProgram := parser.Parse(programPath)\n    programJson := vm.DeserializeProgramJson(compiledProgram)\n\n    cairoRunner, err := runners.NewCairoRunner(programJson)\n    if err != nil {\n        return nil, err\n    }\n    end, err := cairoRunner.Initialize()\n    if err != nil {\n        return nil, err\n    }\n    err = cairoRunner.RunUntilPC(end)\n    if err != nil {\n        return nil, err\n    }\n    err = cairoRunner.Vm.Relocate()\n    return cairoRunner, err\n}\n```\n\nTODO: add parsing and deserializing\n\n#### Builtins\n\nNow that we are able to run a basic fibonacci program, lets step up our game by adding builtins to our VM. A builtin is a low level optimization integrated into the core loop of the VM that allows otherwise expensive computation to be performed more efficiently. Builtins have two ways to operate: via validation rules and via auto-deduction rules. Validation rules are applied to every element that is inserted into a builtin's segment. For example, if I want to verify an ecdsa signature, I can insert it into the ecdsa builtin's segment and let a validation rule take care of verifying the signature. Auto-deduction rules take over during instruction execution, when we can't compute the value of an operand who's address belongs to a builtin segment, we can use that builtin's auto-deduction rule to calculate the value of the operand. For example, If I want to calculate the pedersen hash of two values, I can write the values into the pedersen builtin's segment and then ask for the next memory cell, without builtins, this instruction would have failed, as there is no value stored in that cell, but now we can use auto-deduction rules to calculate the hash and fill in that memory cell.\n\nWe will define a basic interface to generalize all of our builtin's behaviour:\n\n```go\ntype BuiltinRunner interface {\n    // Returns the first address of the builtin's memory segment\n    Base() memory.Relocatable\n    // Returns the name of the builtin\n    Name() string\n    // Creates a memory segment for the builtin and initializes its base\n    InitializeSegments(*memory.MemorySegmentManager)\n    // Returns the builtin's initial stack\n    InitialStack() []memory.MaybeRelocatable\n    // Attempts to deduce the value of a memory cell given by its address. Can return either a nil pointer and an error, if an error arises during the deduction,\n    // a valid pointer and nil if the deduction was succesful, or a nil pointer and nil if there is no deduction for the memory cell\n    DeduceMemoryCell(memory.Relocatable, *memory.Memory) (*memory.MaybeRelocatable, error)\n    // Adds a validation rule to the memory\n    // Validation rules are applied when a value is inserted into the builtin's segment\n    AddValidationRule(*memory.Memory)\n}\n```\n\nAnd now lets integrate this into our existing codebase:\n\nFirst we will make some modifications to our basic structures:\n\nWe will add our builtin runners to the VM:\n\n```go\ntype VirtualMachine struct {\n    RunContext     RunContext\n    currentStep    uint\n    Segments       memory.MemorySegmentManager\n    Trace           []TraceEntry\n    RelocatedTrace  []RelocatedTraceEntry\n    RelocatedMemory map[uint]lambdaworks.Felt\n    BuiltinRunners []builtins.BuiltinRunner\n}\n```\n\nThen we will create two new types to handle validation rules in the `Memory`:\n\n##### ValidationRule\n\nThis will represent our builtin's validation rules, they take a memory address and a referenece to the memory, and return a list of validated addresses, for most builtins, this list will contain the address it received if the validation was succesful, but some builtins may return additional addresses.\n\n```go\n// A function that validates a memory address and returns a list of validated addresses\ntype ValidationRule func(*Memory, Relocatable) ([]Relocatable, error)\n```\n\n##### AddressSet\n\nAs go doesn't have a set type, we created our own really basic set for `Relocatable`s. This will hold the values returned by the validation rules, so that we don't have to run them more than once for each memory cell.\n\n```go\n// A Set to store Relocatable values\ntype AddressSet map[Relocatable]bool\n\nfunc NewAddressSet() AddressSet {\n    return make(map[Relocatable]bool)\n}\n\nfunc (set AddressSet) Add(element Relocatable) {\n    set[element] = true\n}\n\nfunc (set AddressSet) Contains(element Relocatable) bool {\n    return set[element]\n}\n```\n\nAnd we will add them to our `Memory` stuct:\n\n``` go\ntype Memory struct {\n    data                map[Relocatable]MaybeRelocatable\n    num_segments        uint\n    validation_rules    map[uint]ValidationRule\n    validated_addresses AddressSet\n}\n```\n\nNow we only need to add a way to create this validation rules:\n\n```go\n// Adds a validation rule for a given segment\nfunc (m *Memory) AddValidationRule(segment_index uint, rule ValidationRule) {\n    m.validation_rules[segment_index] = rule\n}\n```\n\nAnd a method that runs validations on a memory address:\n\n```go\n// Applies the validation rule for the addr's segment if any\n// Skips validation if the address is temporary or if it has been previously validated\nfunc (m *Memory) validateAddress(addr Relocatable) error {\n    if addr.SegmentIndex \u003c 0 || m.validated_addresses.Contains(addr) {\n        return nil\n    }\n    rule, ok := m.validation_rules[uint(addr.SegmentIndex)]\n    if !ok {\n        return nil\n    }\n    validated_addresses, error := rule(m, addr)\n    if error != nil {\n        return error\n    }\n    for _, validated_address := range validated_addresses {\n        m.validated_addresses.Add(validated_address)\n    }\n    return nil\n}\n```\n\nAnd we are all set to integrate this new logic into our `Memory`'s `Insert` operation:\n\n```go\n// Inserts a value in some memory address, given by a Relocatable value.\nfunc (m *Memory) Insert(addr Relocatable, val *MaybeRelocatable) error {\n    // Check that insertions are preformed within the memory bounds\n    if addr.SegmentIndex \u003e= int(m.num_segments) {\n        return errors.New(\"Error: Inserting into a non allocated segment\")\n    }\n    // Check for possible overwrites\n    prev_elem, ok := m.data[addr]\n    if ok \u0026\u0026 prev_elem != *val {\n        return errors.New(\"Memory is write-once, cannot overwrite memory value\")\n    }\n\n    m.data[addr] = *val\n\n    return m.validateAddress(addr)\n}\n```\n\nNow we will initialize the builtins from our `CairoRunner`:\n\n##### NewCairoRunner (Builtins)\n\nHere we will have to iterate over the `Builtins` field of the `Program`, and add the corresponding builtin to the `VirtualMachine`'s `BuiltinRunner` field. We don't have any builtins yet, so we wil add a comment as placeholder and just leave a default case. As we implement more builtins, we will add a case for each of them.\n\n```go\nfunc NewCairoRunner(program vm.Program) (*CairoRunner, error) {\n    mainIdentifier, ok := (*program.Identifiers)[\"__main__.main\"]\n main_offset := uint(0)\n if ok {\n  main_offset = uint(mainIdentifier.PC)\n }\n    runner := CairoRunner{Program: program, Vm: *vm.NewVirtualMachine(), mainOffset: main_offset}\n    for _, builtin_name := range program.Builtins {\n        switch builtin_name {\n        // Add a case for each builtin here, example:\n        // case \"range_check\":\n        //     runner.Vm.BuiltinRunners = append(runner.Vm.BuiltinRunners, RangeCheckBuiltin{})\n        default:\n            return nil, errors.New(\"Invalid builtin\")\n        }\n    }\n    return \u0026runner, nil\n}\n```\n\n##### InitializeSegments (Builtins)\n\nHere we will also initialize the builtin segments by calling each builtin's `InitializeSegments` method\n\n```go\nfunc (r *CairoRunner) initializeSegments() {\n    // Program Segment\n    r.ProgramBase = r.Vm.Segments.AddSegment()\n    // Execution Segment\n    r.executionBase = r.Vm.Segments.AddSegment()\n    // Builtin Segments\n    for i := range r.Vm.BuiltinRunners {\n        r.Vm.BuiltinRunners[i].InitializeSegments(\u0026r.Vm.Segments)\n    }\n}\n```\n\n##### InitializeMainEntryPoint(Builtins)\n\nHere we will add the builtin's initial_stack to our stack. The builtin's initial_stack is generally made up of the builtin's base, and is what allows the main function to write into the builtin's segment.\n\n```go\nfunc (r *CairoRunner) initializeMainEntrypoint() (memory.Relocatable, error) {\n    // When running from main entrypoint, only up to 11 values will be written (9 builtin bases + end + return_fp)\n    stack := make([]memory.MaybeRelocatable, 0, 11)\n    // Append builtins initial stack to stack\n    for i := range r.Vm.BuiltinRunners {\n        for _, val := range r.Vm.BuiltinRunners[i].InitialStack() {\n            stack = append(stack, val)\n        }\n    }\n    return_fp := r.Vm.Segments.AddSegment()\n    return r.initializeFunctionEntrypoint(r.mainOffset, \u0026stack, return_fp)\n}\n```\n\n##### initializeVm (Builtins)\n\nHere we will add our builtin's validation rules to the `Memory` and use them to validate the meory cells we loaded before\n\n```go\nfunc (r *CairoRunner) initializeVM() error {\n    r.Vm.RunContext.Ap = r.initialAp\n    r.Vm.RunContext.Fp = r.initialFp\n    r.Vm.RunContext.Pc = r.initialPc\n    // Add validation rules\n    for i := range r.Vm.BuiltinRunners {\n        r.Vm.BuiltinRunners[i].AddValidationRule(\u0026r.Vm.Segments.Memory)\n    }\n    // Apply validation rules to memory\n    return r.Vm.Segments.Memory.ValidateExistingMemory()\n}\n```\n\nFor this we will add the method `Memory.ValidateExistingMemory`:\n\n```go\nfunc (m *Memory) ValidateExistingMemory() error {\n    for addr := range m.data {\n        err := m.validateAddress(addr)\n        if err != nil {\n            return err\n        }\n    }\n    return nil\n}\n```\n\nNow we will dive deeper into how `auto-deduction` rules come into play during execution:\n\nBefore builtins, the basic flow for computing the value of an operand was to first compute its address, and then if we couldn't find it in memory, we would deduce its value based on the other operands.\nWith the introduction of builtins and their auto-deduction rules, this flow changes a bit. Now we compute the address, use it to fetch the value from memory, if we can't find it in memory we try to use the builtin's auto deduction rules, and if we can't deduce it via builtins we will then deduce it based on the other operands's.\nBut what does it mean to use the builtin's auto deduction rules to deduce the value of an operand?\n\n##### DeduceMemoryCell\n\nThis method will iterate over the builtin runners and try to find a builtin who's base's segment index matches the operand to be deduced's address. That is to say, it checks if the address belongs to a builtin's segment. If a match is found, it uses the builtin's `DeduceMemoryCell` method to run the builtin's auto-deduction rules and calculate the value of the operand\n\n```go\n// Applies the corresponding builtin's deduction rules if addr's segment index corresponds to a builtin segment\n// Returns nil if there is no deduction for the address\nfunc (vm *VirtualMachine) DeduceMemoryCell(addr memory.Relocatable) (*memory.MaybeRelocatable, error) {\n for i := range vm.BuiltinRunners {\n  if vm.BuiltinRunners[i].Base().SegmentIndex == addr.SegmentIndex {\n   return vm.BuiltinRunners[i].DeduceMemoryCell(addr, \u0026vm.Segments.Memory)\n  }\n }\n return nil, nil\n}\n```\n\nNow we have to integrate this new method into our `VirtualMachine.ComputeOperands` method:\n\nWe will add two helper methods to make our code easier to follow with these new additions:\nBoth of these methods will be ran fetching either op1 or op0 respectively yields a nil value, and will try to deduce them using both builtins and normal deductions, returning an error if both of these attempts fail\n\n##### ComputeOp0Deductions\n\n```go\n// Runs deductions for Op0, first runs builtin deductions, if this fails, attempts to deduce it based on dst and op1\n// Also returns res if it was also deduced in the process\n// Inserts the deduced operand\n// Fails if Op0 was not deduced or if an error arised in the process\nfunc (vm *VirtualMachine) ComputeOp0Deductions(op0_addr memory.Relocatable, instruction *Instruction, dst *memory.MaybeRelocatable, op1 *memory.MaybeRelocatable) (deduced_op0 memory.MaybeRelocatable, deduced_res *memory.MaybeRelocatable, err error) {\n op0, err := vm.DeduceMemoryCell(op0_addr)\n if err != nil {\n  return *memory.NewMaybeRelocatableFelt(lambdaworks.FeltZero()), nil, err\n }\n if op0 == nil {\n  op0, deduced_res, err = vm.DeduceOp0(instruction, dst, op1)\n  if err != nil {\n   return *memory.NewMaybeRelocatableFelt(lambdaworks.FeltZero()), nil, err\n  }\n }\n if op0 != nil {\n  vm.Segments.Memory.Insert(op0_addr, op0)\n } else {\n  return *memory.NewMaybeRelocatableFelt(lambdaworks.FeltZero()), nil, errors.New(\"Failed to compute or deduce op0\")\n }\n return *op0, deduced_res, nil\n}\n```\n\n##### ComputeOp1Deductions\n\n```go\n// Runs deductions for Op1, first runs builtin deductions, if this fails, attempts to deduce it based on dst and op0\n// Also updates res if it was also deduced in the process\n// Inserts the deduced operand\n// Fails if Op1 was not deduced or if an error arised in the process\nfunc (vm *VirtualMachine) ComputeOp1Deductions(op1_addr memory.Relocatable, instruction *Instruction, dst *memory.MaybeRelocatable, op0 *memory.MaybeRelocatable, res *memory.MaybeRelocatable) (memory.MaybeRelocatable, error) {\n op1, err := vm.DeduceMemoryCell(op1_addr)\n if err != nil {\n  return *memory.NewMaybeRelocatableFelt(lambdaworks.FeltZero()), err\n }\n if op1 == nil {\n  var deducedRes *memory.MaybeRelocatable\n  op1, deducedRes, err = vm.DeduceOp1(instruction, dst, op0)\n  if err != nil {\n   return *memory.NewMaybeRelocatableFelt(lambdaworks.FeltZero()), err\n  }\n  if res == nil {\n   res = deducedRes\n  }\n }\n if op1 != nil {\n  vm.Segments.Memory.Insert(op1_addr, op1)\n } else {\n  return *memory.NewMaybeRelocatableFelt(lambdaworks.FeltZero()), errors.New(\"Failed to compute or deduce op1\")\n }\n return *op1, nil\n}\n```\n\nNow we integrate these two new methods into our previous `ComputeOperands` method:\n\n```go\nfunc (vm *VirtualMachine) ComputeOperands(instruction Instruction) (Operands, error) {\n var res *memory.MaybeRelocatable\n\n dst_addr, err := vm.RunContext.ComputeDstAddr(instruction)\n if err != nil {\n  return Operands{}, errors.New(\"FailedToComputeDstAddr\")\n }\n dst, _ := vm.Segments.Memory.Get(dst_addr)\n\n op0_addr, err := vm.RunContext.ComputeOp0Addr(instruction)\n if err != nil {\n  return Operands{}, fmt.Errorf(\"FailedToComputeOp0Addr: %s\", err)\n }\n op0_op, _ := vm.Segments.Memory.Get(op0_addr)\n\n op1_addr, err := vm.RunContext.ComputeOp1Addr(instruction, op0_op)\n if err != nil {\n  return Operands{}, fmt.Errorf(\"FailedToComputeOp1Addr: %s\", err)\n }\n op1_op, _ := vm.Segments.Memory.Get(op1_addr)\n\n  var op0 memory.MaybeRelocatable\n if op0_op != nil {\n  op0 = *op0_op\n } else {\n  op0, res, err = vm.ComputeOp0Deductions(op0_addr, \u0026instruction, dst, op1_op)\n  if err != nil {\n   return Operands{}, err\n  }\n }\n\n var op1 memory.MaybeRelocatable\n if op1_op != nil {\n  op1 = *op1_op\n } else {\n  op1, err = vm.ComputeOp1Deductions(op1_addr, \u0026instruction, dst, op0_op, res)\n  if err != nil {\n   return Operands{}, err\n  }\n }\n    if res == nil {\n  res, err = vm.ComputeRes(instruction, op0, op1)\n\n  if err != nil {\n   return Operands{}, err\n  }\n }\n\n if dst == nil {\n  deducedDst := vm.DeduceDst(instruction, res)\n  dst = deducedDst\n  if dst != nil {\n   vm.Segments.Memory.Insert(dst_addr, dst)\n  }\n }\n\n operands := Operands{\n  Dst: *dst,\n  Op0: op0,\n  Op1: op1,\n  Res: res,\n }\n return operands, nil\n}\n```\n\nWith all of our builtin logic integrated into the codebase, we can implement any builtin and use it in our cairo programs while worrying only about implementing the `BuiltinRunner` interface and creating the builtin in the `NewCairoRunner` function.\n\n#### RangeCheck\n\nThe `RangeCheck` builtin does a very simple thing: it asserts that a given number is in the range $[0, 2^{128})$, i.e., that it's greater than zero and less than $2^{128}$. This might seem superficial but it is used for a lot of different things in Cairo, including comparing numbers. Whenever a program asserts that some number is less than other, the range check builtin is being called underneath. \n\nTODO: explain this better, it's not entirely clear why $2^{128}$ was chosen.\n\nLet's now talk about how to implement the `RangeCheckBuiltinRunner`.\n\nWe have getter functions just to obtain information about the builtin. The `Name` method is used when iterating through all the builtins of the program so we can switch to the correct execution. \n\n```go\nfunc (r *RangeCheckBuiltinRunner) Base() memory.Relocatable {\n\treturn r.base\n}\n\nfunc (r *RangeCheckBuiltinRunner) Name() string {\n\treturn \"range_check\"\n}\n```\n\nFor the `InitializeSegments` method we just add a segment to the memory and store the first address of the segment in the base attribute.\n\n```go\nfunc (r *RangeCheckBuiltinRunner) InitializeSegments(segments *memory.MemorySegmentManager) {\n\tr.base = segments.AddSegment()\n}\n```\n\nNext we have the `InitialStack` method, that just returns a stack with the base address appended. \n\n```go \nfunc (r *RangeCheckBuiltinRunner) InitialStack() []memory.MaybeRelocatable {\n\tif r.included {\n\t\tstack := []memory.MaybeRelocatable{*memory.NewMaybeRelocatableRelocatable(r.base)}\n\t\treturn stack\n\t}\n\treturn []memory.MaybeRelocatable{}\n}\n```\n\nIn this case, the `DeduceMemoryCell` is not used in this builtin, so we return nothing. \n\n```go\nfunc (r *RangeCheckBuiltinRunner) DeduceMemoryCell(addr memory.Relocatable, mem *memory.Memory) (*memory.MaybeRelocatable, error) {\n\treturn nil, nil\n}\n```\n\nAnd finally we have the `AddValidationRule` and the `ValidationRule` methods.\n\n###### AddValidationRule\n\nReceives the memory and adds a new validation rule to it for the builtin segment. \n\n###### ValidationRule\n\nReceives the memory and an address and it checks if the value in that address is a `felt` and then if it's inside the range. To do so, it checks that the necessary number of bits for representing the felt is not greater than the bits for representing the upper bound of the range. If it fits in this range, it returns an `Relocatable` array with the address appended. Otherwise returns error. \n\n```go \nfunc ValidationRule(mem *memory.Memory, address memory.Relocatable) ([]memory.Relocatable, error) {\n\tres_val, err := mem.Get(address)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tfelt, is_felt := res_val.GetFelt()\n\tif !is_felt {\n\t\treturn nil, errors.New(\"NotFeltElement\")\n\t}\n\tif felt.Bits() \u003c= N_PARTS*INNER_RC_BOUND_SHIFT {\n\t\treturn []memory.Relocatable{address}, nil\n\t}\n\treturn nil, errors.New(\"RangeCheckNumOutOfBounds\")\n}\n\nfunc (r *RangeCheckBuiltinRunner) AddValidationRule(mem *memory.Memory) {\n\tmem.AddValidationRule(uint(r.base.SegmentIndex), ValidationRule)\n}\n``````\n\n#### Output\n\nTODO\n\n#### Poseidon\n\nThe poseidon builtin is used to compute the poseidon hash function in an efficient way. The poseidon hash used by the builtin differs from a standard poseidon hash in two ways, it uses different constants (becoming its own stark poseidon hash), and it also uses the internal poseidon permutation function instead of calling a poseidon hash function. The reason for the second one is that it allows the builtin to hash more than one element at a time by permuting the three-element poseidon state.\n\nDue to this difference, the best solution is to use a poseidon implementation built specifically for cairo. In our case we are going to use the poseidon hash in the `starknet-crypto` crate of the [starknet-rs](https://github.com/xJonathanLEI/starknet-rs) repo.\nThe section below will explain how to create a C wrapper to use this crate from our go code, but you can skip it if you want to us","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flambdaclass%2Fcairo-vm_in_go","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flambdaclass%2Fcairo-vm_in_go","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flambdaclass%2Fcairo-vm_in_go/lists"}