Full Code of maxgillett/giza for AI

master 5794cc93b6ec cached
47 files
143.3 KB
38.8k tokens
455 symbols
1 requests
Download .txt
Repository: maxgillett/giza
Branch: master
Commit: 5794cc93b6ec
Files: 47
Total size: 143.3 KB

Directory structure:
gitextract_qfi_vi0c/

├── .gitignore
├── Cargo.toml
├── LICENSE
├── README.md
├── air/
│   ├── Cargo.toml
│   └── src/
│       ├── constraints.rs
│       ├── frame.rs
│       ├── lib.rs
│       └── options.rs
├── cli/
│   ├── Cargo.toml
│   ├── README.md
│   └── src/
│       ├── cmd/
│       │   ├── mod.rs
│       │   ├── prove/
│       │   │   ├── args.rs
│       │   │   ├── mod.rs
│       │   │   └── prove.rs
│       │   └── verify.rs
│       ├── giza.rs
│       └── utils.rs
├── core/
│   ├── Cargo.toml
│   └── src/
│       ├── field/
│       │   ├── f252/
│       │   │   ├── mod.rs
│       │   │   └── tests.rs
│       │   └── mod.rs
│       ├── flags/
│       │   └── mod.rs
│       ├── inputs/
│       │   └── mod.rs
│       ├── lib.rs
│       └── word/
│           ├── helpers.rs
│           └── mod.rs
├── examples/
│   ├── Cargo.toml
│   └── src/
│       └── main.rs
├── program.json
├── prover/
│   ├── Cargo.toml
│   └── src/
│       └── lib.rs
├── runner/
│   ├── Cargo.toml
│   └── src/
│       ├── cairo_interop.rs
│       ├── errors.rs
│       ├── hints.rs
│       ├── lib.rs
│       ├── memory.rs
│       ├── runner.rs
│       └── trace.rs
├── rust-toolchain.toml
└── wasm/
    ├── .gitignore
    ├── Cargo.toml
    ├── index.js
    ├── package.json
    ├── src/
    │   └── lib.rs
    └── webpack.config.js

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
tmp/
target/
Cargo.lock
*.sw*
.DS_Store


================================================
FILE: Cargo.toml
================================================
[workspace]
members = [
  "air",
  "core",
  "prover",
  "runner",
  "examples",
  "cli",
  "wasm"
]


================================================
FILE: LICENSE
================================================
                              Apache License
                        Version 2.0, January 2004
                     http://www.apache.org/licenses/

TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

1. Definitions.

   "License" shall mean the terms and conditions for use, reproduction,
   and distribution as defined by Sections 1 through 9 of this document.

   "Licensor" shall mean the copyright owner or entity authorized by
   the copyright owner that is granting the License.

   "Legal Entity" shall mean the union of the acting entity and all
   other entities that control, are controlled by, or are under common
   control with that entity. For the purposes of this definition,
   "control" means (i) the power, direct or indirect, to cause the
   direction or management of such entity, whether by contract or
   otherwise, or (ii) ownership of fifty percent (50%) or more of the
   outstanding shares, or (iii) beneficial ownership of such entity.

   "You" (or "Your") shall mean an individual or Legal Entity
   exercising permissions granted by this License.

   "Source" form shall mean the preferred form for making modifications,
   including but not limited to software source code, documentation
   source, and configuration files.

   "Object" form shall mean any form resulting from mechanical
   transformation or translation of a Source form, including but
   not limited to compiled object code, generated documentation,
   and conversions to other media types.

   "Work" shall mean the work of authorship, whether in Source or
   Object form, made available under the License, as indicated by a
   copyright notice that is included in or attached to the work
   (an example is provided in the Appendix below).

   "Derivative Works" shall mean any work, whether in Source or Object
   form, that is based on (or derived from) the Work and for which the
   editorial revisions, annotations, elaborations, or other modifications
   represent, as a whole, an original work of authorship. For the purposes
   of this License, Derivative Works shall not include works that remain
   separable from, or merely link (or bind by name) to the interfaces of,
   the Work and Derivative Works thereof.

   "Contribution" shall mean any work of authorship, including
   the original version of the Work and any modifications or additions
   to that Work or Derivative Works thereof, that is intentionally
   submitted to Licensor for inclusion in the Work by the copyright owner
   or by an individual or Legal Entity authorized to submit on behalf of
   the copyright owner. For the purposes of this definition, "submitted"
   means any form of electronic, verbal, or written communication sent
   to the Licensor or its representatives, including but not limited to
   communication on electronic mailing lists, source code control systems,
   and issue tracking systems that are managed by, or on behalf of, the
   Licensor for the purpose of discussing and improving the Work, but
   excluding communication that is conspicuously marked or otherwise
   designated in writing by the copyright owner as "Not a Contribution."

   "Contributor" shall mean Licensor and any individual or Legal Entity
   on behalf of whom a Contribution has been received by Licensor and
   subsequently incorporated within the Work.

2. Grant of Copyright License. Subject to the terms and conditions of
   this License, each Contributor hereby grants to You a perpetual,
   worldwide, non-exclusive, no-charge, royalty-free, irrevocable
   copyright license to reproduce, prepare Derivative Works of,
   publicly display, publicly perform, sublicense, and distribute the
   Work and such Derivative Works in Source or Object form.

3. Grant of Patent License. Subject to the terms and conditions of
   this License, each Contributor hereby grants to You a perpetual,
   worldwide, non-exclusive, no-charge, royalty-free, irrevocable
   (except as stated in this section) patent license to make, have made,
   use, offer to sell, sell, import, and otherwise transfer the Work,
   where such license applies only to those patent claims licensable
   by such Contributor that are necessarily infringed by their
   Contribution(s) alone or by combination of their Contribution(s)
   with the Work to which such Contribution(s) was submitted. If You
   institute patent litigation against any entity (including a
   cross-claim or counterclaim in a lawsuit) alleging that the Work
   or a Contribution incorporated within the Work constitutes direct
   or contributory patent infringement, then any patent licenses
   granted to You under this License for that Work shall terminate
   as of the date such litigation is filed.

4. Redistribution. You may reproduce and distribute copies of the
   Work or Derivative Works thereof in any medium, with or without
   modifications, and in Source or Object form, provided that You
   meet the following conditions:

   (a) You must give any other recipients of the Work or
       Derivative Works a copy of this License; and

   (b) You must cause any modified files to carry prominent notices
       stating that You changed the files; and

   (c) You must retain, in the Source form of any Derivative Works
       that You distribute, all copyright, patent, trademark, and
       attribution notices from the Source form of the Work,
       excluding those notices that do not pertain to any part of
       the Derivative Works; and

   (d) If the Work includes a "NOTICE" text file as part of its
       distribution, then any Derivative Works that You distribute must
       include a readable copy of the attribution notices contained
       within such NOTICE file, excluding those notices that do not
       pertain to any part of the Derivative Works, in at least one
       of the following places: within a NOTICE text file distributed
       as part of the Derivative Works; within the Source form or
       documentation, if provided along with the Derivative Works; or,
       within a display generated by the Derivative Works, if and
       wherever such third-party notices normally appear. The contents
       of the NOTICE file are for informational purposes only and
       do not modify the License. You may add Your own attribution
       notices within Derivative Works that You distribute, alongside
       or as an addendum to the NOTICE text from the Work, provided
       that such additional attribution notices cannot be construed
       as modifying the License.

   You may add Your own copyright statement to Your modifications and
   may provide additional or different license terms and conditions
   for use, reproduction, or distribution of Your modifications, or
   for any such Derivative Works as a whole, provided Your use,
   reproduction, and distribution of the Work otherwise complies with
   the conditions stated in this License.

5. Submission of Contributions. Unless You explicitly state otherwise,
   any Contribution intentionally submitted for inclusion in the Work
   by You to the Licensor shall be under the terms and conditions of
   this License, without any additional terms or conditions.
   Notwithstanding the above, nothing herein shall supersede or modify
   the terms of any separate license agreement you may have executed
   with Licensor regarding such Contributions.

6. Trademarks. This License does not grant permission to use the trade
   names, trademarks, service marks, or product names of the Licensor,
   except as required for reasonable and customary use in describing the
   origin of the Work and reproducing the content of the NOTICE file.

7. Disclaimer of Warranty. Unless required by applicable law or
   agreed to in writing, Licensor provides the Work (and each
   Contributor provides its Contributions) on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
   implied, including, without limitation, any warranties or conditions
   of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
   PARTICULAR PURPOSE. You are solely responsible for determining the
   appropriateness of using or redistributing the Work and assume any
   risks associated with Your exercise of permissions under this License.

8. Limitation of Liability. In no event and under no legal theory,
   whether in tort (including negligence), contract, or otherwise,
   unless required by applicable law (such as deliberate and grossly
   negligent acts) or agreed to in writing, shall any Contributor be
   liable to You for damages, including any direct, indirect, special,
   incidental, or consequential damages of any character arising as a
   result of this License or out of the use or inability to use the
   Work (including but not limited to damages for loss of goodwill,
   work stoppage, computer failure or malfunction, or any and all
   other commercial damages or losses), even if such Contributor
   has been advised of the possibility of such damages.

9. Accepting Warranty or Additional Liability. While redistributing
   the Work or Derivative Works thereof, You may choose to offer,
   and charge a fee for, acceptance of support, warranty, indemnity,
   or other liability obligations and/or rights consistent with this
   License. However, in accepting such obligations, You may act only
   on Your own behalf and on Your sole responsibility, not on behalf
   of any other Contributor, and only if You agree to indemnify,
   defend, and hold each Contributor harmless for any liability
   incurred by, or claims asserted against, such Contributor by reason
   of your accepting any such warranty or additional liability.

END OF TERMS AND CONDITIONS

APPENDIX: How to apply the Apache License to your work.

   To apply the Apache License to your work, attach the following
   boilerplate notice, with the fields enclosed by brackets "[]"
   replaced with your own identifying information. (Don't include
   the brackets!)  The text should be enclosed in the appropriate
   comment syntax for the file format. We also recommend that a
   file or class name and description of purpose be included on the
   same "printed page" as the copyright notice for easier
   identification within third-party archives.

Copyright [yyyy] [name of copyright owner]

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

	http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.


================================================
FILE: README.md
================================================
## Overview

Giza leverages the Winterfell library to prove and verify the execution of programs running on the Cairo VM.

## Usage instructions

Giza offers two modes of usage. In the first mode, an execution trace created by an external Cairo runner is supplied to the CLI to output a proof. The provided trace consists of binary files containing the record of register and memory states visited during the run of a Cairo program. To prove execution, additional auxiliary trace values must be reconstructed, and the built-in Rust runner is used to re-execute the trace in order to compute these values.

The second usage mode accepts only a Cairo program and initial register state, and uses the runner to construct all necessary trace information (including trace and memory values). Unlike the first mode, Python hint support and program input are not yet fully supported. This is not the preferred mode of interacting with Giza, and is not currently exposed through the CLI.

### Mode 1: Supply a trace to the CLI

Assuming a compiled Cairo program `program.json`, the following steps can be taken to construct a proof:

1. Install the Giza CLI using nightly Rust: `cargo install --path cli`
2. Generate the partial trace using an external runner, for example: `cairo-run --program=program.json --layout=all --memory_file=memory.bin --trace_file=trace.bin`. Note that the Starkware runner may only be used for purposes that fall within its [license](https://github.com/starkware-libs/cairo-lang/blob/master/LICENSE.txt).
3. Construct the proof: `giza prove --trace=trace.bin --memory=memory.bin --program=program.json --output=output.bin`
4. Verify the proof: `giza verify --proof=output.bin`

### Mode 2: Supply a program

To prove and verify the execution of the program found in `examples/src/main.rs`, one can run the following after completing step 1 from the previous section.

`cargo run --release --bin giza-examples`

## Acknowledgments
- The Cairo virtual machine and programming language is developed by [Starkware](https://starkware.co/).
- The STARK prover and verifier is built using the [Winterfell](https://github.com/novifinancial/winterfell) project.
- The current Rust runner is a fork of the implementation written by Anaïs Querol of O(1) Labs.


================================================
FILE: air/Cargo.toml
================================================
[package]
name = "giza-air"
version = "0.1.0"
edition = "2018"

[dependencies]
winter-air = { package = "winter-air", git = "https://github.com/maxgillett/winterfell", rev = "0aad6a5", default-features = false }
winter-utils = { package = "winter-utils", git = "https://github.com/maxgillett/winterfell", rev = "0aad6a5", default-features = false }
giza_core = { package = "giza-core", path = "../core", version = "0.1", default-features = false }
serde = "1.0.137"


================================================
FILE: air/src/constraints.rs
================================================
use super::{AuxEvaluationFrame, AuxTraceRandElements, MainEvaluationFrame};
use giza_core::{
    range, ExtensionOf, Felt, FieldElement, FlagDecomposition, OffsetDecomposition, Range,
};

pub trait EvaluationResult<E: FieldElement> {
    fn evaluate_instr_constraints(&mut self, frame: &MainEvaluationFrame<E>);
    fn evaluate_operand_constraints(&mut self, frame: &MainEvaluationFrame<E>);
    fn evaluate_register_constraints(&mut self, frame: &MainEvaluationFrame<E>);
    fn evaluate_opcode_constraints(&mut self, frame: &MainEvaluationFrame<E>);
    fn enforce_selector(&mut self, frame: &MainEvaluationFrame<E>);
}

pub trait AuxEvaluationResult<E: FieldElement, F: FieldElement + ExtensionOf<E>> {
    fn evaluate_memory_constraints(
        &mut self,
        main_frame: &MainEvaluationFrame<E>,
        aux_frame: &AuxEvaluationFrame<F>,
        aux_rand_elements: &AuxTraceRandElements<F>,
    );
    fn evaluate_range_check_constraints(
        &mut self,
        main_frame: &MainEvaluationFrame<E>,
        aux_frame: &AuxEvaluationFrame<F>,
        aux_rand_elements: &AuxTraceRandElements<F>,
    );
}

/// Main constraint identifiers
const INST: usize = 16;
const DST_ADDR: usize = 17;
const OP0_ADDR: usize = 18;
const OP1_ADDR: usize = 19;
const NEXT_AP: usize = 20;
const NEXT_FP: usize = 21;
const NEXT_PC_1: usize = 22;
const NEXT_PC_2: usize = 23;
const T0: usize = 24;
const T1: usize = 25;
const MUL_1: usize = 26;
const MUL_2: usize = 27;
const CALL_1: usize = 28;
const CALL_2: usize = 29;
const ASSERT_EQ: usize = 30;

/// Aux constraint identifiers
const A_M_PRIME: Range<usize> = range(0, 4);
const V_M_PRIME: Range<usize> = range(4, 4);
const P_M: Range<usize> = range(8, 4);
const A_RC_PRIME: Range<usize> = range(12, 3);
const P_RC: Range<usize> = range(15, 3);

const TWO: Felt = Felt::TWO;

impl<E: FieldElement + From<Felt>> EvaluationResult<E> for [E] {
    fn evaluate_instr_constraints(&mut self, frame: &MainEvaluationFrame<E>) {
        let curr = frame.current();
        // Bit constraints
        for (n, flag) in curr.flags().into_iter().enumerate() {
            self[n] = match n {
                0..=14 => flag * (flag - Felt::ONE.into()),
                15 => flag,
                _ => panic!("Unknown flag offset"),
            };
        }
        // Instruction unpacking
        let b15: E = TWO.exp(15u32.into()).into();
        let b16: E = TWO.exp(16u32.into()).into();
        let b32: E = TWO.exp(32u32.into()).into();
        let b48: E = TWO.exp(48u32.into()).into();
        let a: E = curr
            .flags()
            .into_iter()
            .enumerate()
            .take(15)
            .fold(Felt::ZERO.into(), |acc, (n, flag)| {
                acc + E::from(2u128.pow(n as u32)) * flag
            });
        self[INST] = (curr.off_dst() + b15)
            + b16 * (curr.off_op0() + b15)
            + b32 * (curr.off_op1() + b15)
            + b48 * a
            - curr.inst();
    }

    fn evaluate_operand_constraints(&mut self, frame: &MainEvaluationFrame<E>) {
        let curr = frame.current();
        let ap = curr.ap();
        let fp = curr.fp();
        let pc = curr.pc();
        let one: E = Felt::ONE.into();

        self[DST_ADDR] =
            curr.f_dst_fp() * fp + (one - curr.f_dst_fp()) * ap + curr.off_dst() - curr.dst_addr();
        self[OP0_ADDR] =
            curr.f_op0_fp() * fp + (one - curr.f_op0_fp()) * ap + curr.off_op0() - curr.op0_addr();
        self[OP1_ADDR] = curr.f_op1_val() * pc
            + curr.f_op1_ap() * ap
            + curr.f_op1_fp() * fp
            + (one - curr.f_op1_val() - curr.f_op1_ap() - curr.f_op1_fp()) * curr.op0()
            + curr.off_op1()
            - curr.op1_addr();
    }

    fn evaluate_register_constraints(&mut self, frame: &MainEvaluationFrame<E>) {
        let curr = frame.current();
        let next = frame.next();
        let one: E = Felt::ONE.into();

        // ap and fp constraints
        self[NEXT_AP] = curr.ap()
            + curr.f_ap_add() * curr.res()
            + curr.f_ap_one()
            + curr.f_opc_call() * TWO.into()
            - next.ap();
        self[NEXT_FP] = curr.f_opc_ret() * curr.dst()
            + curr.f_opc_call() * (curr.ap() + TWO.into())
            + (one - curr.f_opc_ret() - curr.f_opc_call()) * curr.fp()
            - next.fp();

        // pc constraints
        self[NEXT_PC_1] =
            (curr.t1() - curr.f_pc_jnz()) * (next.pc() - (curr.pc() + curr.inst_size()));
        self[NEXT_PC_2] = curr.t0() * (next.pc() - (curr.pc() + curr.op1()))
           + (one - curr.f_pc_jnz()) * next.pc()
           - ((one - curr.f_pc_abs() - curr.f_pc_rel() - curr.f_pc_jnz())
                   * (curr.pc() + curr.inst_size())
               + curr.f_pc_abs() * curr.res()
               + curr.f_pc_rel() * (curr.pc() + curr.res()));
        self[T0] = curr.f_pc_jnz() * curr.dst() - curr.t0();
        self[T1] = curr.t0() * curr.res() - curr.t1();
    }

    fn evaluate_opcode_constraints(&mut self, frame: &MainEvaluationFrame<E>) {
        let curr = frame.current();
        let one: E = Felt::ONE.into();
        self[MUL_1] = curr.mul() - (curr.op0() * curr.op1());
        self[MUL_2] = curr.f_res_add() * (curr.op0() + curr.op1())
            + curr.f_res_mul() * curr.mul()
            + (one - curr.f_res_add() - curr.f_res_mul() - curr.f_pc_jnz()) * curr.op1()
            - (one - curr.f_pc_jnz()) * curr.res();
        self[CALL_1] = curr.f_opc_call() * (curr.dst() - curr.fp());
        self[CALL_2] = curr.f_opc_call() * (curr.op0() - (curr.pc() + curr.inst_size()));
        self[ASSERT_EQ] = curr.f_opc_aeq() * (curr.dst() - curr.res());
    }

    fn enforce_selector(&mut self, frame: &MainEvaluationFrame<E>) {
        let curr = frame.current();
        for n in INST..=ASSERT_EQ {
            self[n] *= curr.selector();
        }
    }
}

impl<E, F> AuxEvaluationResult<E, F> for [F]
where
    E: FieldElement + From<Felt>,
    F: FieldElement + From<Felt> + ExtensionOf<E>,
{
    fn evaluate_memory_constraints(
        &mut self,
        main_frame: &MainEvaluationFrame<E>,
        aux_frame: &AuxEvaluationFrame<F>,
        aux_rand_elements: &AuxTraceRandElements<F>,
    ) {
        let curr = main_frame.segment();
        let aux = aux_frame.segment();

        let random_elements = aux_rand_elements.get_segment_elements(0);
        let z = random_elements[0];
        let alpha = random_elements[1];

        // Continuity constraint
        for (i, n) in A_M_PRIME.enumerate() {
            self[n] = (aux.a_m_prime(i + 1) - aux.a_m_prime(i))
                * (aux.a_m_prime(i + 1) - aux.a_m_prime(i) - F::ONE);
        }
        // Single-valued constraint
        for (i, n) in V_M_PRIME.enumerate() {
            self[n] = (aux.v_m_prime(i + 1) - aux.v_m_prime(i))
                * (aux.a_m_prime(i + 1) - aux.a_m_prime(i) - F::ONE);
        }
        // Cumulative product step
        for (i, n) in P_M.enumerate() {
            let a_m: F = curr.a_m(i + 1).into();
            let v_m: F = curr.v_m(i + 1).into();
            self[n] = (z - (aux.a_m_prime(i + 1) + alpha * aux.v_m_prime(i + 1))) * aux.p_m(i + 1)
                - (z - (a_m + alpha * v_m)) * aux.p_m(i);
        }
    }

    fn evaluate_range_check_constraints(
        &mut self,
        main_frame: &MainEvaluationFrame<E>,
        aux_frame: &AuxEvaluationFrame<F>,
        aux_rand_elements: &AuxTraceRandElements<F>,
    ) {
        let curr = main_frame.segment();
        let aux = aux_frame.segment();

        let random_elements = aux_rand_elements.get_segment_elements(1);
        let z = random_elements[0];

        // Continuity constraint
        for (i, n) in A_RC_PRIME.enumerate() {
            self[n] = (aux.a_rc_prime(i + 1) - aux.a_rc_prime(i))
                * (aux.a_rc_prime(i + 1) - aux.a_rc_prime(i) - F::ONE);
        }
        // Cumulative product step
        for (i, n) in P_RC.enumerate() {
            self[n] = (z - aux.a_rc_prime(i + 1)) * aux.p_rc(i + 1)
                - (z - curr.a_rc(i + 1).into()) * aux.p_rc(i)
        }
    }
}


================================================
FILE: air/src/frame.rs
================================================
use super::FieldElement;
use giza_core::{flags::*, *};
use winter_air::{Air, EvaluationFrame, Table};
use winter_utils::TableReader;

// MAIN FRAME
// --------------------------------------------------------------------------------------------

#[derive(Debug, Clone)]
pub struct MainEvaluationFrame<E: FieldElement> {
    table: Table<E>, // row-major indexing
}

impl<E: FieldElement> EvaluationFrame<E> for MainEvaluationFrame<E> {
    // CONSTRUCTORS
    // --------------------------------------------------------------------------------------------

    fn new<A: Air>(air: &A) -> Self {
        let num_cols = air.trace_layout().main_trace_width();
        let num_rows = Self::num_rows();
        MainEvaluationFrame {
            table: Table::new(num_rows, num_cols),
        }
    }

    fn from_table(table: Table<E>) -> Self {
        Self { table }
    }

    // ROW MUTATORS
    // --------------------------------------------------------------------------------------------

    fn read_from<R: TableReader<E>>(
        &mut self,
        data: R,
        step: usize,
        _offset: usize,
        blowup: usize,
    ) {
        let trace_len = data.num_rows();
        for (row, row_idx) in self.table.rows_mut().zip(Self::offsets().into_iter()) {
            for col_idx in 0..data.num_cols() {
                row[col_idx] = data.get(col_idx, (step + row_idx * blowup) % trace_len);
            }
        }
    }

    // ROW ACCESSORS
    // --------------------------------------------------------------------------------------------

    fn row<'a>(&'a self, row_idx: usize) -> &'a [E] {
        &self.table.get_row(row_idx)
    }

    fn to_table(&self) -> Table<E> {
        self.table.clone()
    }

    fn offsets() -> &'static [usize] {
        &[0, 1]
    }
}

impl<'a, E: FieldElement> MainEvaluationFrame<E> {
    pub fn current(&'a self) -> MainFrameSegment<'a, E> {
        MainFrameSegment::new(&self.table, 0)
    }
    pub fn next(&'a self) -> MainFrameSegment<'a, E> {
        MainFrameSegment::new(&self.table, 1)
    }
    pub fn segment(&'a self) -> MainFrameSegment<'a, E> {
        MainFrameSegment::new(&self.table, 0)
    }
}

pub struct MainFrameSegment<'a, E: FieldElement> {
    table: &'a Table<E>,
    row_start: usize,
}

enum DataSegment {
    Flags,
    ResValue,
    TempMemoryPointer,
    MemoryAddress,
    MemoryValues,
    Offsets,
    TempValues,
    Selector,
}

impl<'a, E: FieldElement> MainFrameSegment<'a, E> {
    fn new(table: &'a Table<E>, row_start: usize) -> Self {
        Self { table, row_start }
    }

    fn get(&self, pos: usize, data_type: DataSegment) -> E {
        // Should this function be inlined?
        let offset = match data_type {
            DataSegment::Flags => FLAG_TRACE_OFFSET,
            DataSegment::ResValue => RES_TRACE_OFFSET,
            DataSegment::TempMemoryPointer => MEM_P_TRACE_OFFSET,
            DataSegment::MemoryAddress => MEM_A_TRACE_OFFSET,
            DataSegment::MemoryValues => MEM_V_TRACE_OFFSET,
            DataSegment::Offsets => OFF_X_TRACE_OFFSET,
            DataSegment::TempValues => DERIVED_TRACE_OFFSET,
            DataSegment::Selector => SELECTOR_TRACE_OFFSET,
        };
        self.table.get_row(self.row_start)[offset + pos]
    }

    fn get_virtual(&self, idx: usize, offset: usize, width: usize) -> E {
        if (0..width).contains(&idx) {
            self.table.get_row(0)[offset + idx]
        } else if (width..width * 2).contains(&idx) {
            self.table.get_row(1)[offset + idx - width]
        } else {
            panic!()
        }
    }
}

impl<'a, E: FieldElement + From<Felt>> MainFrameSegment<'a, E> {
    /// Result
    pub fn res(&self) -> E {
        self.get(0, DataSegment::ResValue)
    }
    /// Registers
    pub fn pc(&self) -> E {
        self.get(0, DataSegment::MemoryAddress)
    }
    pub fn ap(&self) -> E {
        self.get(0, DataSegment::TempMemoryPointer)
    }
    pub fn fp(&self) -> E {
        self.get(1, DataSegment::TempMemoryPointer)
    }
    /// Memory addresses
    pub fn dst_addr(&self) -> E {
        self.get(1, DataSegment::MemoryAddress)
    }
    pub fn op0_addr(&self) -> E {
        self.get(2, DataSegment::MemoryAddress)
    }
    pub fn op1_addr(&self) -> E {
        self.get(3, DataSegment::MemoryAddress)
    }
    /// Memory values
    pub fn inst(&self) -> E {
        self.get(0, DataSegment::MemoryValues)
    }
    pub fn dst(&self) -> E {
        self.get(1, DataSegment::MemoryValues)
    }
    pub fn op0(&self) -> E {
        self.get(2, DataSegment::MemoryValues)
    }
    pub fn op1(&self) -> E {
        self.get(3, DataSegment::MemoryValues)
    }
    /// Instruction size
    pub fn inst_size(&self) -> E {
        self.f_op1_val() + Felt::ONE.into()
    }
    /// Derived trace values
    pub fn t0(&self) -> E {
        self.get(0, DataSegment::TempValues)
    }
    pub fn t1(&self) -> E {
        self.get(1, DataSegment::TempValues)
    }
    pub fn mul(&self) -> E {
        self.get(2, DataSegment::TempValues)
    }
    /// Virtual columns of memory addreses and values
    pub fn a_m(&self, idx: usize) -> E {
        self.get_virtual(idx, MEM_A_TRACE_OFFSET, MEM_A_TRACE_WIDTH)
    }
    pub fn v_m(&self, idx: usize) -> E {
        self.get_virtual(idx, MEM_V_TRACE_OFFSET, MEM_V_TRACE_WIDTH)
    }
    /// Virtual columns of offsets
    pub fn a_rc(&self, idx: usize) -> E {
        self.get_virtual(idx, OFF_X_TRACE_OFFSET, OFF_X_TRACE_WIDTH)
    }
    /// Selector
    pub fn selector(&self) -> E {
        self.get(0, DataSegment::Selector)
    }
}

impl<'a, E: FieldElement + From<Felt>> OffsetDecomposition<E> for MainFrameSegment<'a, E> {
    fn off_dst(&self) -> E {
        bias(self.get(0, DataSegment::Offsets))
    }

    fn off_op0(&self) -> E {
        bias(self.get(1, DataSegment::Offsets))
    }

    fn off_op1(&self) -> E {
        bias(self.get(2, DataSegment::Offsets))
    }
}

impl<'a, E: FieldElement + From<Felt>> FlagDecomposition<E> for MainFrameSegment<'a, E> {
    fn flags(&self) -> Vec<E> {
        let mut flags = Vec::with_capacity(NUM_FLAGS);
        for i in 0..NUM_FLAGS {
            flags.push(self.flag_at(i));
        }
        flags
    }

    fn flag_at(&self, pos: usize) -> E {
        self.get(pos, DataSegment::Flags)
    }
}

// AUX FRAME
// --------------------------------------------------------------------------------------------

#[derive(Debug, Clone)]
pub struct AuxEvaluationFrame<E: FieldElement> {
    table: Table<E>, // row-major indexing
}

impl<E: FieldElement> EvaluationFrame<E> for AuxEvaluationFrame<E> {
    // CONSTRUCTORS
    // --------------------------------------------------------------------------------------------

    fn new<A: Air>(air: &A) -> Self {
        let num_rows = Self::num_rows();
        let num_cols = air.trace_layout().aux_trace_width();
        AuxEvaluationFrame {
            table: Table::new(num_rows, num_cols),
        }
    }

    fn from_table(table: Table<E>) -> Self {
        Self { table }
    }

    // ROW MUTATORS
    // --------------------------------------------------------------------------------------------

    fn read_from<R: TableReader<E>>(&mut self, data: R, step: usize, offset: usize, blowup: usize) {
        let trace_len = data.num_rows();
        for (row, row_idx) in self.table.rows_mut().zip(Self::offsets().into_iter()) {
            for col_idx in 0..data.num_cols() {
                row[col_idx + offset] = data.get(col_idx, (step + row_idx * blowup) % trace_len);
            }
        }
    }

    // ROW ACCESSORS
    // --------------------------------------------------------------------------------------------

    fn row<'a>(&'a self, row_idx: usize) -> &'a [E] {
        &self.table.get_row(row_idx)
    }

    fn to_table(&self) -> Table<E> {
        self.table.clone()
    }

    fn offsets() -> &'static [usize] {
        &[0, 1]
    }
}

impl<'a, E: FieldElement> AuxEvaluationFrame<E> {
    pub fn segment(&'a self) -> AuxFrameSegment<'a, E> {
        AuxFrameSegment::new(&self.table, 0)
    }
}

pub struct AuxFrameSegment<'a, E: FieldElement> {
    curr_row: &'a [E],
    next_row: &'a [E],
}

impl<'a, E: FieldElement> AuxFrameSegment<'a, E> {
    fn new(table: &'a Table<E>, row_idx: usize) -> Self {
        let curr_row = table.get_row(row_idx);
        let next_row = table.get_row(row_idx + 1);
        Self { curr_row, next_row }
    }

    fn get_virtual(&self, idx: usize, offset: usize, width: usize) -> E {
        if (0..width).contains(&idx) {
            self.curr_row[offset + idx]
        } else if (width..width * 2).contains(&idx) {
            self.next_row[offset + idx - width]
        } else {
            panic!()
        }
    }

    /// Memory
    pub fn a_m_prime(&self, idx: usize) -> E {
        self.get_virtual(idx, A_M_PRIME_OFFSET, A_M_PRIME_WIDTH)
    }
    pub fn v_m_prime(&self, idx: usize) -> E {
        self.get_virtual(idx, V_M_PRIME_OFFSET, V_M_PRIME_WIDTH)
    }
    pub fn p_m(&self, idx: usize) -> E {
        self.get_virtual(idx, P_M_OFFSET, P_M_WIDTH)
    }

    /// Permutation range check
    pub fn a_rc_prime(&self, idx: usize) -> E {
        self.get_virtual(idx, A_RC_PRIME_OFFSET, A_RC_PRIME_WIDTH)
    }
    pub fn p_rc(&self, idx: usize) -> E {
        self.get_virtual(idx, P_RC_OFFSET, P_RC_WIDTH)
    }
}


================================================
FILE: air/src/lib.rs
================================================
#![feature(generic_associated_types)]

use giza_core::{
    Builtin, ExtensionOf, Felt, FieldElement, RegisterState, Word, A_RC_PRIME_FIRST,
    A_RC_PRIME_LAST, MEM_A_TRACE_OFFSET, MEM_P_TRACE_OFFSET, P_M_LAST,
};
use winter_air::{
    Air, AirContext, Assertion, AuxTraceRandElements, ProofOptions as WinterProofOptions,
    TraceInfo, TransitionConstraintDegree,
};
use winter_utils::{ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable};

// EXPORTS
// ================================================================================================

pub use winter_air::{EvaluationFrame, FieldExtension, HashFunction};

mod options;
pub use options::ProofOptions;

mod constraints;
use constraints::{AuxEvaluationResult, EvaluationResult};

mod frame;
pub use frame::{AuxEvaluationFrame, MainEvaluationFrame};

// PROCESSOR AIR
// ================================================================================================

pub struct ProcessorAir {
    context: AirContext<Felt>,
    pub_inputs: PublicInputs,
}

impl Air for ProcessorAir {
    type BaseField = Felt;
    type PublicInputs = PublicInputs;
    type Frame<E: FieldElement> = MainEvaluationFrame<E>;
    type AuxFrame<E: FieldElement> = AuxEvaluationFrame<E>;

    fn new(trace_info: TraceInfo, pub_inputs: PublicInputs, options: WinterProofOptions) -> Self {
        let mut main_degrees = vec![];
        // Instruction constraints
        for _ in 0..=14 {
            main_degrees.push(TransitionConstraintDegree::new(2)); // F0-F14
        }
        main_degrees.push(TransitionConstraintDegree::new(1)); // F15

        // Operand constraints
        main_degrees.push(TransitionConstraintDegree::new(4)); // INST
        main_degrees.push(TransitionConstraintDegree::new(4)); // DST_ADDR
        main_degrees.push(TransitionConstraintDegree::new(4)); // OP0_ADDR
        main_degrees.push(TransitionConstraintDegree::new(4)); // OP1_ADDR

        // Register constraints
        main_degrees.push(TransitionConstraintDegree::new(4)); // NEXT_AP
        main_degrees.push(TransitionConstraintDegree::new(4)); // NEXT_FP
        main_degrees.push(TransitionConstraintDegree::new(4)); // NEXT_PC_1
        main_degrees.push(TransitionConstraintDegree::new(4)); // NEXT_PC_2
        main_degrees.push(TransitionConstraintDegree::new(4)); // T0
        main_degrees.push(TransitionConstraintDegree::new(4)); // T1

        // Opcode constraints
        main_degrees.push(TransitionConstraintDegree::new(4)); // MUL_1
        main_degrees.push(TransitionConstraintDegree::new(4)); // MUL_2
        main_degrees.push(TransitionConstraintDegree::new(4)); // CALL_1
        main_degrees.push(TransitionConstraintDegree::new(4)); // CALL_2
        main_degrees.push(TransitionConstraintDegree::new(4)); // ASSERT_EQ

        let aux_degrees = vec![
            // Memory constraints
            TransitionConstraintDegree::new(2), // A_M_PRIME 0
            TransitionConstraintDegree::new(2), //     "     1
            TransitionConstraintDegree::new(2), //     "     2
            TransitionConstraintDegree::new(2), //     "     3
            TransitionConstraintDegree::new(2), // V_M_PRIME 0
            TransitionConstraintDegree::new(2), //     "     1
            TransitionConstraintDegree::new(2), //     "     2
            TransitionConstraintDegree::new(2), //     "     3
            TransitionConstraintDegree::new(2), //    P_M    0
            TransitionConstraintDegree::new(2), //     "     1
            TransitionConstraintDegree::new(2), //     "     2
            TransitionConstraintDegree::new(2), //     "     3
            // Range check constraints
            TransitionConstraintDegree::new(2), // A_RC_PRIME 0
            TransitionConstraintDegree::new(2), //     "      1
            TransitionConstraintDegree::new(2), //     "      2
            TransitionConstraintDegree::new(2), //    P_RC    0
            TransitionConstraintDegree::new(2), //     "      1
            TransitionConstraintDegree::new(2), //     "      2
        ];

        let mut transition_exemptions = vec![];
        transition_exemptions.extend(vec![1; main_degrees.len()]);
        transition_exemptions.extend(vec![1; aux_degrees.len()]);

        let mut context =
            AirContext::new_multi_segment(trace_info, main_degrees, aux_degrees, 4, 3, options);
        context.set_transition_exemptions(transition_exemptions);

        Self {
            context,
            pub_inputs,
        }
    }

    fn get_assertions(&self) -> Vec<Assertion<Felt>> {
        let last_step = self.pub_inputs.num_steps - 1;
        vec![
            // Initial and final 'pc' register
            Assertion::single(MEM_A_TRACE_OFFSET, 0, self.pub_inputs.init.pc),
            Assertion::single(MEM_A_TRACE_OFFSET, last_step, self.pub_inputs.fin.pc),
            // Initial and final 'ap' register
            Assertion::single(MEM_P_TRACE_OFFSET, 0, self.pub_inputs.init.ap),
            Assertion::single(MEM_P_TRACE_OFFSET, last_step, self.pub_inputs.fin.ap),
        ]
    }

    fn get_aux_assertions<E: FieldElement + From<Self::BaseField>>(
        &self,
        aux_rand_elements: &AuxTraceRandElements<E>,
    ) -> Vec<Assertion<E>> {
        let last_step = self.trace_length() - 1;
        let random_elements = aux_rand_elements.get_segment_elements(0);
        let mem = &self.pub_inputs.mem;
        let z = random_elements[0];
        let alpha = random_elements[1];
        let num = z.exp((mem.0.len() as u64).into());

        let den = mem
            .0
            .iter()
            .zip(&mem.1)
            .map(|(a, v)| z - (E::from(*a as u64) + alpha * E::from(v.unwrap().word())))
            .reduce(|a, b| a * b)
            .unwrap();

        vec![
            // Public memory
            Assertion::single(P_M_LAST, last_step, num / den),
            // Minimum range check value
            Assertion::single(A_RC_PRIME_FIRST, 0, E::from(self.pub_inputs.rc_min)),
            // Maximum range check value
            Assertion::single(A_RC_PRIME_LAST, last_step, E::from(self.pub_inputs.rc_max)),
        ]
    }

    fn evaluate_transition<E: FieldElement + From<Felt>>(
        &self,
        frame: &MainEvaluationFrame<E>,
        _periodic_values: &[E],
        result: &mut [E],
    ) {
        result.evaluate_instr_constraints(frame);
        result.evaluate_operand_constraints(frame);
        result.evaluate_register_constraints(frame);
        result.evaluate_opcode_constraints(frame);
        result.enforce_selector(frame);
    }

    fn evaluate_aux_transition<
        E: FieldElement + From<Felt>,
        F: FieldElement + From<Felt> + ExtensionOf<E>,
    >(
        &self,
        main_frame: &MainEvaluationFrame<E>,
        aux_frame: &AuxEvaluationFrame<F>,
        _periodic_values: &[E],
        aux_rand_elements: &AuxTraceRandElements<F>,
        result: &mut [F],
    ) {
        result.evaluate_memory_constraints(main_frame, aux_frame, aux_rand_elements);
        result.evaluate_range_check_constraints(main_frame, aux_frame, aux_rand_elements);
    }

    fn context(&self) -> &AirContext<Felt> {
        &self.context
    }
}

// PUBLIC INPUTS
// ================================================================================================

pub struct PublicInputs {
    pub init: RegisterState,                // initial register state
    pub fin: RegisterState,                 // final register state
    pub rc_min: u16, // minimum range check value (0 < rc_min < rc_max < 2^16)
    pub rc_max: u16, // maximum range check value
    pub mem: (Vec<u64>, Vec<Option<Word>>), // public memory
    pub num_steps: usize, // number of execution steps
    pub builtins: Vec<Builtin>, // list of builtins
}

impl PublicInputs {
    pub fn new(
        init: RegisterState,
        fin: RegisterState,
        rc_min: u16,
        rc_max: u16,
        mem: (Vec<u64>, Vec<Option<Word>>),
        num_steps: usize,
        builtins: Vec<Builtin>,
    ) -> Self {
        Self {
            init,
            fin,
            rc_min,
            rc_max,
            mem,
            num_steps,
            builtins,
        }
    }
}

// TODO: Implement Serializable/Deserializable traits in RegisterState and Memory
// structs instead of manually managing it here
impl Serializable for PublicInputs {
    fn write_into<W: ByteWriter>(&self, target: &mut W) {
        target.write(self.init.pc);
        target.write(self.init.ap);
        target.write(self.init.fp);
        target.write(self.fin.pc);
        target.write(self.fin.ap);
        target.write(self.fin.fp);
        target.write_u16(self.rc_min);
        target.write_u16(self.rc_max);
        target.write_u64(self.mem.1.len() as u64);
        for i in 0..self.mem.1.len() as usize {
            target.write_u64(self.mem.0[i]);
        }
        target.write(
            self.mem
                .1
                .iter()
                .map(|x| x.unwrap().word())
                .collect::<Vec<_>>(),
        );
        target.write_u64(self.num_steps as u64);
        // TODO: Use bit representation once multiple builtins are supported
        for builtin in self.builtins.iter() {
            if let Builtin::Output(_) = builtin {
                target.write_u8(1);
            } else {
                target.write_u8(0);
            }
        }
    }
}

impl Deserializable for PublicInputs {
    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
        let init = RegisterState::new(
            Felt::read_from(source)?,
            Felt::read_from(source)?,
            Felt::read_from(source)?,
        );
        let fin = RegisterState::new(
            Felt::read_from(source)?,
            Felt::read_from(source)?,
            Felt::read_from(source)?,
        );
        let rc_min = source.read_u16()?;
        let rc_max = source.read_u16()?;
        let mem_len = source.read_u64()?;
        let mut mem_a = vec![0u64; mem_len as usize];
        for i in 0..mem_len as usize {
            mem_a[i] = source.read_u64()?;
        }
        let mem_v = Felt::read_batch_from(source, mem_len as usize)?
            .into_iter()
            .map(|x| Some(Word::new(x)))
            .collect::<Vec<_>>();
        let num_steps = source.read_u64()?;
        // TODO: Interpret as bits once multiple builtins are supported
        let builtins = match source.read_u8()? {
            1 => vec![Builtin::Output(0)],
            _ => vec![],
        };
        Ok(PublicInputs::new(
            init,
            fin,
            rc_min,
            rc_max,
            (mem_a, mem_v),
            num_steps as usize,
            builtins,
        ))
    }
}


================================================
FILE: air/src/options.rs
================================================
use core::ops::Deref;
use winter_air::{FieldExtension, HashFunction, ProofOptions as WinterProofOptions};

/// TODO: add docs
#[derive(Clone)]
pub struct ProofOptions(WinterProofOptions);

impl ProofOptions {
    pub fn new(
        num_queries: usize,
        blowup_factor: usize,
        grinding_factor: u32,
        hash_fn: HashFunction,
        field_extension: FieldExtension,
        fri_folding_factor: usize,
        fri_max_remainder_size: usize,
    ) -> Self {
        Self(WinterProofOptions::new(
            num_queries,
            blowup_factor,
            grinding_factor,
            hash_fn,
            field_extension,
            fri_folding_factor,
            fri_max_remainder_size,
        ))
    }

    pub fn with_proof_options(
        num_queries: Option<usize>,
        blowup_factor: Option<usize>,
        grinding_factor: Option<u32>,
        fri_folding_factor: Option<usize>,
        fri_max_remainder_size: Option<usize>,
    ) -> Self {
        Self(WinterProofOptions::new(
            num_queries.unwrap_or(54),  // 27
            blowup_factor.unwrap_or(4), //8,
            grinding_factor.unwrap_or(16),
            HashFunction::Blake3_192,
            FieldExtension::None,
            fri_folding_factor.unwrap_or(8),
            fri_max_remainder_size.unwrap_or(256),
        ))
    }

    pub fn into_inner(self) -> WinterProofOptions {
        self.0
    }
}

impl Default for ProofOptions {
    fn default() -> Self {
        Self::with_proof_options(None, None, None, None, None)
    }
}

impl Deref for ProofOptions {
    type Target = WinterProofOptions;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}


================================================
FILE: cli/Cargo.toml
================================================
[package]
name = "giza-cli"
version = "0.1.0"
edition = "2021"
rust-version = "1.57"

[dependencies]
clap = { version = "3.1.18", features = ["derive"] }
air = { package = "giza-air", path = "../air", version = "0.1", default-features = false }
prover = { package = "giza-prover", path = "../prover", version = "0.1", default-features = false }
runner = { package = "giza-runner", path = "../runner", version = "0.1", default-features = false }
winterfell = { package = "winter-verifier", git = "https://github.com/maxgillett/winterfell", rev = "0aad6a5", features = ["std"], default-features = false }
winter-utils = { package = "winter-utils", git = "https://github.com/maxgillett/winterfell", rev = "0aad6a5", default-features = false }
serde = "1.0.137"
bincode = "1.3.3"

[[bin]]
name = "giza"
path = "src/giza.rs"
doc = false


================================================
FILE: cli/README.md
================================================
giza-cli
========

## Commands

```
# Generate a proof
giza prove --trace ./trace.bin --output proof.bin
```

================================================
FILE: cli/src/cmd/mod.rs
================================================
use serde::{Deserialize, Serialize};

pub mod prove;
pub mod verify;

#[derive(Serialize, Deserialize)]
struct ProofData {
    input_bytes: Vec<u8>,
    proof_bytes: Vec<u8>,
}


================================================
FILE: cli/src/cmd/prove/args.rs
================================================
use clap::{Error, ErrorKind, Parser, ValueHint};
use std::path::PathBuf;

#[derive(Parser, Debug)]
#[clap(author, version, about, long_about = None)]
pub struct ProveArgs {
    #[clap(
        help = "Path to the compiled Cairo program JSON file",
        long,
        value_hint = ValueHint::FilePath
    )]
    pub program: PathBuf,

    #[clap(
        help = "Path to the execution trace output file",
        long,
        value_hint = ValueHint::FilePath
    )]
    pub trace: PathBuf,

    #[clap(
        help = "Path to the memory output file",
        long,
        value_hint = ValueHint::FilePath
    )]
    pub memory: PathBuf,

    #[clap(
        help = "Path to write the STARK proof",
        long,
        value_hint = ValueHint::FilePath
    )]
    pub output: PathBuf,

    #[clap(help = "Number of serialized outputs", long)]
    pub num_outputs: Option<u64>,

    #[clap(
        help = "Number of queries for a STARK proof",
        long,
        value_parser(clap::builder::ValueParser::new(parse_num_queries))
    )]
    pub num_queries: Option<usize>,

    #[clap(
        help = "Blowup factor for a STARK proof",
        long,
        value_parser(clap::builder::ValueParser::new(parse_blowup_factor))
    )]
    pub blowup_factor: Option<usize>,

    #[clap(
        help = "Query seed grinding factor for a STARK proof",
        long,
        value_parser(clap::value_parser!(u32).range(..33))
    )]
    pub grinding_factor: Option<u32>,

    #[clap(
        help = "Factor by which the degree of a polynomial is reduced with each FRI layer",
        long,
        value_parser(clap::builder::ValueParser::new(parse_fri_folding_factor))
    )]
    pub fri_folding_factor: Option<usize>,

    #[clap(
        help = "Maximum allowed remainder (last FRI layer) size",
        long,
        value_parser(clap::builder::ValueParser::new(parse_fri_max_remainder_size))
    )]
    pub fri_max_remainder_size: Option<usize>,
}

fn parse_num_queries(value: &str) -> Result<usize, Error> {
    let value = value
        .parse::<usize>()
        .map_err(|e| Error::raw(ErrorKind::InvalidValue, format!("{}", e)))?;

    match value {
        0 => Err(Error::raw(ErrorKind::ValueValidation, "cannot be 0")),
        129.. => Err(Error::raw(
            ErrorKind::ValueValidation,
            "cannot be more than 128",
        )),
        _ => Ok(value),
    }
}

fn parse_blowup_factor(value: &str) -> Result<usize, Error> {
    let value = value
        .parse::<usize>()
        .map_err(|e| Error::raw(ErrorKind::InvalidValue, format!("{}", e)))?;

    if !value.is_power_of_two() {
        return Err(Error::raw(
            ErrorKind::ValueValidation,
            "must be a power of two",
        ));
    }

    match value {
        0..=3 => Err(Error::raw(
            ErrorKind::ValueValidation,
            "cannot be smaller than 4",
        )),
        257.. => Err(Error::raw(
            ErrorKind::ValueValidation,
            "cannot be more than 256",
        )),
        _ => Ok(value),
    }
}

fn parse_fri_folding_factor(value: &str) -> Result<usize, Error> {
    let value = value
        .parse::<usize>()
        .map_err(|e| Error::raw(ErrorKind::InvalidValue, format!("{}", e)))?;

    if value != 4 && value != 8 && value != 16 {
        Err(Error::raw(ErrorKind::ValueValidation, "must be 4, 8 or 16"))
    } else {
        Ok(value)
    }
}

fn parse_fri_max_remainder_size(value: &str) -> Result<usize, Error> {
    let value = value
        .parse::<usize>()
        .map_err(|e| Error::raw(ErrorKind::InvalidValue, format!("{}", e)))?;

    if !value.is_power_of_two() {
        return Err(Error::raw(
            ErrorKind::ValueValidation,
            "must be a power of two",
        ));
    }

    match value {
        0..=31 => Err(Error::raw(
            ErrorKind::ValueValidation,
            "cannot be smaller than 32",
        )),
        1025.. => Err(Error::raw(
            ErrorKind::ValueValidation,
            "cannot be more than 1024",
        )),
        _ => Ok(value),
    }
}


================================================
FILE: cli/src/cmd/prove/mod.rs
================================================
mod args;
mod prove;

pub use args::ProveArgs;


================================================
FILE: cli/src/cmd/prove/prove.rs
================================================
use std::fs::File;
use std::io::Write;

use super::ProveArgs;
use crate::{cmd::ProofData, utils::Cmd};
use air::ProofOptions;
use runner::ExecutionTrace;
use winter_utils::Serializable;

pub struct ProveOutput {}

#[derive(Debug)]
pub enum Error {}

impl Cmd for ProveArgs {
    type Output = Result<ProveOutput, Error>;

    fn run(self) -> Self::Output {
        // Load trace from file
        let trace =
            ExecutionTrace::from_file(self.program, self.trace, self.memory, self.num_outputs);

        // Generate proof
        let proof_options = ProofOptions::with_proof_options(
            self.num_queries,
            self.blowup_factor,
            self.grinding_factor,
            self.fri_folding_factor,
            self.fri_max_remainder_size,
        );
        let (proof, pub_inputs) = prover::prove_trace(trace, &proof_options).unwrap();
        let input_bytes = pub_inputs.to_bytes();
        let proof_bytes = proof.to_bytes();
        println!("Proof size: {:.1} KB", proof_bytes.len() as f64 / 1024f64);

        // Write proof to disk
        let data = ProofData {
            input_bytes,
            proof_bytes,
        };
        let b = bincode::serialize(&data).unwrap();
        let mut f = File::create(self.output).unwrap();
        f.write_all(&b).unwrap();

        Ok(ProveOutput {})
    }
}


================================================
FILE: cli/src/cmd/verify.rs
================================================
use std::fs::File;
use std::io::Read;
use std::path::PathBuf;

use super::ProofData;
use crate::utils::Cmd;
use air::{ProcessorAir, PublicInputs};
use clap::{Parser, ValueHint};
use winter_utils::{Deserializable, SliceReader};
use winterfell::StarkProof;

pub struct VerifyOutput {}

#[derive(Parser, Debug)]
#[clap(author, version, about, long_about = None)]
pub struct VerifyArgs {
    #[clap(
        help = "Path to the STARK proof",
        long,
        value_hint = ValueHint::FilePath
    )]
    pub proof: PathBuf,
}

#[derive(Debug)]
pub enum Error {}

impl Cmd for VerifyArgs {
    type Output = Result<VerifyOutput, Error>;

    fn run(self) -> Self::Output {
        // Load proof and public inputs from file
        let mut b = Vec::new();
        let mut f = File::open(self.proof).unwrap();
        f.read_to_end(&mut b).unwrap();
        let data: ProofData = bincode::deserialize(&b).unwrap();
        let pub_inputs =
            PublicInputs::read_from(&mut SliceReader::new(&data.input_bytes[..])).unwrap();
        let proof = StarkProof::from_bytes(&data.proof_bytes).unwrap();

        // Verify execution
        match winterfell::verify::<ProcessorAir>(proof, pub_inputs) {
            Ok(_) => println!("Execution verified"),
            Err(err) => println!("Failed to verify execution: {}", err),
        }

        Ok(VerifyOutput {})
    }
}


================================================
FILE: cli/src/giza.rs
================================================
pub mod cmd;
mod utils;

use crate::utils::Cmd;
use clap::{Parser, Subcommand};
use cmd::{prove::ProveArgs, verify::VerifyArgs};

#[derive(Debug, Parser)]
#[clap(name = "giza")]
pub struct Opts {
    #[clap(subcommand)]
    pub sub: Subcommands,
}

#[derive(Debug, Subcommand)]
#[allow(clippy::large_enum_variant)]
pub enum Subcommands {
    Prove(ProveArgs),
    Verify(VerifyArgs),
}

fn main() {
    let opts = Opts::parse();
    match opts.sub {
        Subcommands::Prove(cmd) => {
            cmd.run().unwrap();
        }
        Subcommands::Verify(cmd) => {
            cmd.run().unwrap();
        }
    }

    // TODO: consider returning Result<T,E> for error codes.
    // Ok(())
}


================================================
FILE: cli/src/utils.rs
================================================
/// Common trait for all cli commands
pub trait Cmd: clap::Parser + Sized {
    type Output;

    fn run(self) -> Self::Output;
}


================================================
FILE: core/Cargo.toml
================================================
[package]
name = "giza-core"
version = "0.1.0"
edition = "2021"
rust-version = "1.57"

[dependencies]
math = { package = "winter-math", git = "https://github.com/maxgillett/winterfell", rev = "0aad6a5", version = "0.4", default-features = false }
winter-utils = { package = "winter-utils", git = "https://github.com/maxgillett/winterfell", rev = "0aad6a5", version = "0.4", default-features = false }
ff = { version = "0.12", features = ["derive"] }
hex = "0.4"



================================================
FILE: core/src/field/f252/mod.rs
================================================
//! An implementation of the 252-bit STARK-friendly prime field chosen by Starkware
//! with modulus $2^{251} + 17 \cdot 2^{192} + 1$.
//! TODO: Worth switching to Barrett reduction for efficiency?

use core::{
    convert::{TryFrom, TryInto},
    fmt::{Debug, Display, Formatter, LowerHex},
    ops::{
        Add, AddAssign, BitAnd, Div, DivAssign, Mul, MulAssign, Neg, Shl, Shr, ShrAssign, Sub,
        SubAssign,
    },
    slice,
};
pub use math::{ExtensibleField, FieldElement, StarkField};
use winter_utils::{
    collections::Vec, string::String, AsBytes, ByteReader, ByteWriter, Deserializable,
    DeserializationError, Randomizable, Serializable,
};

use ff::{Field, PrimeField};

#[cfg(test)]
mod tests;

// FIELD ELEMENT
// ================================================================================================

// Note that the internal representation of Fr is assumed to be in Montgomery form with R=2^256
#[derive(PrimeField)]
#[PrimeFieldModulus = "3618502788666131213697322783095070105623107215331596699973092056135872020481"]
#[PrimeFieldGenerator = "3"]
#[PrimeFieldReprEndianness = "little"]
struct Fr([u64; 4]);

// Number of bytes needed to represent field element
const ELEMENT_BYTES: usize = core::mem::size_of::<Fr>();

// A wrapper around the internal representation of Fr for non-finite field integer manipulation
#[derive(PartialOrd, Ord, PartialEq, Eq, Copy, Clone, Debug)]
pub struct BigInt(pub [u64; 4]);

// Represents a base field element, using Fr as the backing type.
#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
pub struct BaseElement(Fr);

impl FieldElement for BaseElement {
    type PositiveInteger = BigInt;
    type BaseField = Self;

    const ZERO: Self = BaseElement(Fr([0, 0, 0, 0]));
    const ONE: Self = BaseElement(Fr(R.0)); // equal to 2^256 mod M

    const ELEMENT_BYTES: usize = ELEMENT_BYTES;

    const IS_CANONICAL: bool = true;

    fn inv(self) -> Self {
        Self(self.0.invert().unwrap())
    }

    fn conjugate(&self) -> Self {
        Self(self.0)
    }

    fn elements_as_bytes(elements: &[Self]) -> &[u8] {
        let p = elements.as_ptr();
        let len = elements.len() * Self::ELEMENT_BYTES;
        unsafe { slice::from_raw_parts(p as *const u8, len) }
    }

    unsafe fn bytes_as_elements(_bytes: &[u8]) -> Result<&[Self], DeserializationError> {
        unimplemented!()
    }

    fn zeroed_vector(n: usize) -> Vec<Self> {
        // TODO: use more efficient initialization
        let result = vec![Self::ZERO.0; n];

        // translate a zero-filled vector of Fr into a vector of base field elements
        let mut v = core::mem::ManuallyDrop::new(result);
        let p = v.as_mut_ptr();
        let len = v.len();
        let cap = v.capacity();
        unsafe { Vec::from_raw_parts(p as *mut Self, len, cap) }
    }

    fn as_base_elements(elements: &[Self]) -> &[Self::BaseField] {
        elements
    }
}

impl BaseElement {
    // Equal to 2*2^256 mod M (R is derived from the macro)
    pub const TWO: Self = BaseElement(Fr([
        0xffff_ffff_ffff_ffc1,
        0xffff_ffff_ffff_ffff,
        0xffff_ffff_ffff_ffff,
        0x7fff_ffff_ffff_bd0,
    ]));

    pub fn from_raw(value: [u64; 4]) -> Self {
        BaseElement(Fr::from_raw(value))
    }

    pub fn to_raw(&self) -> BigInt {
        self.0.to_raw()
    }
}

impl StarkField for BaseElement {
    /// sage: MODULUS = 2^251 + 17 * 2^192 + 1 \
    /// sage: GF(MODULUS).is_prime_field() \
    /// True \
    /// sage: GF(MODULUS).order() \
    /// 3618502788666131213697322783095070105623107215331596699973092056135872020481
    const MODULUS: Self::PositiveInteger = BigInt([0x1, 0x0, 0x0, 0x8000_0000_0000_011]);
    const MODULUS_BITS: u32 = 252;

    /// sage: GF(MODULUS).primitive_element() \
    /// 3
    const GENERATOR: Self = BaseElement(GENERATOR);

    /// sage: is_odd((MODULUS - 1) / 2^192) \
    /// True
    const TWO_ADICITY: u32 = 192;

    /// sage: k = (MODULUS - 1) / 2^192 \
    /// sage: GF(MODULUS).primitive_element()^k \
    /// 145784604816374866144131285430889962727208297722245411306711449302875041684
    const TWO_ADIC_ROOT_OF_UNITY: Self = BaseElement(ROOT_OF_UNITY);

    fn get_modulus_le_bytes() -> Vec<u8> {
        Self::MODULUS.to_le_bytes()
    }

    /// Convert from Montgomery form
    #[inline]
    fn as_int(&self) -> Self::PositiveInteger {
        self.0.to_raw()
    }
}

impl Randomizable for BaseElement {
    const VALUE_SIZE: usize = Self::ELEMENT_BYTES;

    fn from_random_bytes(bytes: &[u8]) -> Option<Self> {
        Self::try_from(bytes).ok()
    }
}

impl Display for BaseElement {
    fn fmt(&self, f: &mut Formatter) -> core::fmt::Result {
        write!(f, "{}", self.to_raw())
    }
}

// OVERLOADED OPERATORS
// ================================================================================================

impl Add for BaseElement {
    type Output = Self;

    fn add(self, rhs: Self) -> Self {
        Self(self.0 + rhs.0)
    }
}

impl AddAssign for BaseElement {
    fn add_assign(&mut self, rhs: Self) {
        *self = *self + rhs
    }
}

impl Sub for BaseElement {
    type Output = Self;

    fn sub(self, rhs: Self) -> Self {
        Self(self.0 - rhs.0)
    }
}

impl SubAssign for BaseElement {
    fn sub_assign(&mut self, rhs: Self) {
        *self = *self - rhs;
    }
}

impl Mul for BaseElement {
    type Output = Self;

    fn mul(self, rhs: Self) -> Self {
        Self(self.0 * rhs.0)
    }
}

impl MulAssign for BaseElement {
    fn mul_assign(&mut self, rhs: Self) {
        *self = *self * rhs
    }
}

impl Div for BaseElement {
    type Output = Self;

    fn div(self, rhs: Self) -> Self {
        Self(self.0 * rhs.0.invert().unwrap())
    }
}

impl DivAssign for BaseElement {
    fn div_assign(&mut self, rhs: Self) {
        *self = *self / rhs
    }
}

impl Neg for BaseElement {
    type Output = Self;

    fn neg(self) -> Self {
        Self(-self.0)
    }
}

// QUADRATIC EXTENSION
// ================================================================================================

/// Defines a quadratic extension of the base field over an irreducible polynomial x<sup>2</sup> -
/// x - 1. Thus, an extension element is defined as α + β * φ, where φ is a root of this polynomial,
/// and α and β are base field elements.
impl ExtensibleField<2> for BaseElement {
    #[inline(always)]
    fn mul(a: [Self; 2], b: [Self; 2]) -> [Self; 2] {
        let z = a[0] * b[0];
        [z + a[1] * b[1], (a[0] + a[1]) * (b[0] + b[1]) - z]
    }

    #[inline(always)]
    fn mul_base(a: [Self; 2], b: Self) -> [Self; 2] {
        [a[0] * b, a[1] * b]
    }

    #[inline(always)]
    fn frobenius(x: [Self; 2]) -> [Self; 2] {
        [x[0] + x[1], Self::ZERO - x[1]]
    }
}

// CUBIC EXTENSION
// ================================================================================================

/// Cubic extension for this field is not implemented as quadratic extension already provides
/// sufficient security level.
impl ExtensibleField<3> for BaseElement {
    fn mul(_a: [Self; 3], _b: [Self; 3]) -> [Self; 3] {
        unimplemented!()
    }

    #[inline(always)]
    fn mul_base(_a: [Self; 3], _b: Self) -> [Self; 3] {
        unimplemented!()
    }

    #[inline(always)]
    fn frobenius(_x: [Self; 3]) -> [Self; 3] {
        unimplemented!()
    }

    fn is_supported() -> bool {
        false
    }
}

// TYPE CONVERSIONS
// ================================================================================================

impl From<u128> for BaseElement {
    /// Converts a 128-bit value into a field element.
    fn from(value: u128) -> Self {
        let hi: u64 = (value >> 64) as u64;
        let lo: u64 = value as u64;
        Self(Fr::from_raw([lo, hi, 0, 0]))
    }
}

impl From<u64> for BaseElement {
    /// Converts a 64-bit value into a field element.
    fn from(value: u64) -> Self {
        Self(Fr::from_raw([value, 0, 0, 0]))
    }
}

impl From<u32> for BaseElement {
    /// Converts a 32-bit value into a field element.
    fn from(value: u32) -> Self {
        Self(Fr::from_raw([value as u64, 0, 0, 0]))
    }
}

impl From<u16> for BaseElement {
    /// Converts a 16-bit value into a field element.
    fn from(value: u16) -> Self {
        Self(Fr::from_raw([value as u64, 0, 0, 0]))
    }
}

impl From<u8> for BaseElement {
    /// Converts an 8-bit value into a field element.
    fn from(value: u8) -> Self {
        Self(Fr::from_raw([value as u64, 0, 0, 0]))
    }
}

impl From<[u64; 4]> for BaseElement {
    /// Converts the value encoded in an array of 4 64-bit words into a field element. The bytes
    /// are assumed to be in little-endian byte order. If the value is greater than or equal
    /// to the field modulus, modular reduction is silently performed.
    fn from(bytes: [u64; 4]) -> Self {
        Self(Fr::from_raw(bytes))
    }
}

impl From<[u8; 32]> for BaseElement {
    /// Converts the value encoded in an array of 32 bytes into a field element. The bytes
    /// are assumed to be in little-endian byte order. If the value is greater than or equal
    /// to the field modulus, modular reduction is silently performed.
    fn from(bytes: [u8; 32]) -> Self {
        let value: [u64; 4] = bytes
            .array_chunks::<8>()
            .map(|c| u64::from_le_bytes(*c))
            .collect::<Vec<u64>>()
            .try_into()
            .unwrap();
        Self(Fr::from_raw(value))
    }
}

impl<'a> TryFrom<&'a [u8]> for BaseElement {
    type Error = String;

    /// Converts a slice of bytes into a field element. The bytes are assumed to be in
    /// little-endian byte order. If the value is greater than or equal to the field modulus,
    /// modular reduction is silently performed.
    fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
        let mut value: [u64; 4] = [0; 4];
        for (i, c) in bytes.chunks(8).enumerate() {
            value[i] = u64::from_le_bytes(TryInto::<[u8; 8]>::try_into(c).unwrap());
        }
        Ok(Self(Fr::from_raw(value)))
    }
}

// TODO: Why is this method not working? See commented lines in core/src/word/helpers.rs
impl AsBytes for BaseElement {
    fn as_bytes(&self) -> &[u8] {
        //let ptr: *const Vec<u8> = &self.as_int().to_le_bytes();
        //unsafe { slice::from_raw_parts(ptr as *const u8, ELEMENT_BYTES) }
        let ptr: *const BigInt = &self.to_raw();
        unsafe { slice::from_raw_parts(ptr as *const u8, ELEMENT_BYTES) }
    }
}

// SERIALIZATION / DESERIALIZATION
// ------------------------------------------------------------------------------------------------

impl Serializable for BaseElement {
    fn write_into<W: ByteWriter>(&self, target: &mut W) {
        target.write_u8_slice(&self.0.to_le_bytes());
    }
}

impl Deserializable for BaseElement {
    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
        let bytes: [u8; 32] = source.read_u8_array()?;
        let value: [u64; 4] = bytes
            .array_chunks::<8>()
            .map(|c| u64::from_le_bytes(*c))
            .collect::<Vec<u64>>()
            .try_into()
            .unwrap();
        Ok(BaseElement(Fr(value)))
    }
}

// OVERLOADED OPERATORS (BIGINT)
// ================================================================================================

impl Shr<u32> for BigInt {
    type Output = BigInt;
    fn shr(self, rhs: u32) -> BigInt {
        shr_vartime(&self, rhs as usize)
    }
}

impl Shr<u32> for &BigInt {
    type Output = BigInt;
    fn shr(self, rhs: u32) -> BigInt {
        shr_vartime(&self, rhs as usize)
    }
}

impl ShrAssign for BigInt {
    fn shr_assign(&mut self, rhs: BigInt) {
        let shift: u64 = rhs.try_into().unwrap();
        *self = shr_vartime(&self, shift as usize);
    }
}

impl Shl<u32> for BigInt {
    type Output = BigInt;
    fn shl(self, rhs: u32) -> BigInt {
        shl_vartime(&self, rhs as usize)
    }
}

impl Shl<u32> for &BigInt {
    type Output = BigInt;
    fn shl(self, rhs: u32) -> BigInt {
        shl_vartime(&self, rhs as usize)
    }
}

impl BitAnd for BigInt {
    type Output = Self;
    fn bitand(self, Self(rhs): Self) -> Self::Output {
        let mut limbs = [0u64; 4];
        for i in 0..4 {
            limbs[i] = self.0[i] & rhs[i];
        }
        Self(limbs)
    }
}

// Modified from https://github.com/RustCrypto/crypto-bigint/blob/master/src/uint/shr.rs
fn shr_vartime(value: &BigInt, shift: usize) -> BigInt {
    let full_shifts = shift / 64;
    let small_shift = shift & (64 - 1);
    let mut limbs = [0u64; 4];

    if shift > 64 * 4 {
        return BigInt(limbs);
    }

    let n = 4 - full_shifts;
    let mut i = 0;

    if small_shift == 0 {
        while i < n {
            limbs[i] = value.0[i + full_shifts];
            i += 1;
        }
    } else {
        while i < n {
            let mut lo = value.0[i + full_shifts] >> small_shift;

            if i < (4 - 1) - full_shifts {
                lo |= value.0[i + full_shifts + 1] << (64 - small_shift);
            }

            limbs[i] = lo;
            i += 1;
        }
    }
    BigInt(limbs)
}

// Modified from https://github.com/RustCrypto/crypto-bigint/blob/171f6745b98b6dccf05f7d25263981949967f398/src/uint/shl.rs
fn shl_vartime(value: &BigInt, n: usize) -> BigInt {
    let mut limbs = [0u64; 4];

    if n >= 64 * 4 {
        return BigInt(limbs);
    }

    let shift_num = n / 64;
    let lshift_rem = n % 64;
    let nz = lshift_rem == 0;
    let rshift_rem = if nz { 0 } else { 64 - lshift_rem };
    let mut i = 4 - 1;
    while i > shift_num {
        let mut limb = value.0[i - shift_num] << lshift_rem;
        let hi = value.0[i - shift_num - 1] >> rshift_rem;
        limb |= hi & nz as u64;
        limbs[i] = limb;
        i -= 1
    }
    limbs[shift_num] = value.0[0] << lshift_rem;
    BigInt(limbs)
}

// TYPE CONVERSIONS (BIGINT, FR)
// ------------------------------------------------------------------------------------------------

impl From<u128> for BigInt {
    /// Converts a 128-bit value into a field element.
    fn from(value: u128) -> Self {
        let hi: u64 = (value >> 64) as u64;
        let lo: u64 = value as u64;
        BigInt([lo, hi, 0, 0])
    }
}

impl From<u64> for BigInt {
    /// Converts a 64-bit value into a field element.
    fn from(value: u64) -> Self {
        BigInt([value, 0, 0, 0])
    }
}

impl From<u32> for BigInt {
    /// Converts a 32-bit value into a field element.
    fn from(value: u32) -> Self {
        BigInt([value as u64, 0, 0, 0])
    }
}

impl From<u16> for BigInt {
    /// Converts a 16-bit value into a field element.
    fn from(value: u16) -> Self {
        BigInt([value as u64, 0, 0, 0])
    }
}

impl From<u8> for BigInt {
    /// Converts an 8-bit value into a field element.
    fn from(value: u8) -> Self {
        BigInt([value as u64, 0, 0, 0])
    }
}

impl TryInto<u64> for BigInt {
    type Error = ();
    fn try_into(self) -> Result<u64, Self::Error> {
        Ok(self.0[0])
    }
}

impl TryInto<u16> for BigInt {
    type Error = ();
    fn try_into(self) -> Result<u16, Self::Error> {
        Ok(self.0[0] as u16)
    }
}

impl BigInt {
    pub fn to_le_bytes(&self) -> Vec<u8> {
        let mut result = [0u8; 32];
        write_le_bytes(self.0, &mut result);
        result.to_vec()
    }
}

impl Display for BigInt {
    fn fmt(&self, f: &mut Formatter) -> core::fmt::Result {
        for i in (0..4).rev() {
            LowerHex::fmt(&self.0[i], f)?;
        }
        Ok(())
    }
}

impl Fr {
    pub fn from_raw(value: [u64; 4]) -> Self {
        Fr(value).mul(&R2)
    }

    pub fn to_raw(&self) -> BigInt {
        let limbs = self.0;
        let mut val = self.clone();
        val.mont_reduce(limbs[0], limbs[1], limbs[2], limbs[3], 0, 0, 0, 0);
        BigInt(val.0)
    }

    pub fn to_le_bytes(&self) -> Vec<u8> {
        let mut result = [0u8; 32];
        write_le_bytes(self.0, &mut result);
        result.to_vec()
    }
}

// Modified from https://github.com/RustCrypto/crypto-bigint/blob/171f6745b98b6dccf05f7d25263981949967f398/src/uint/encoding.rs
fn write_le_bytes(value: [u64; 4], out: &mut [u8]) {
    for (src, dst) in value.iter().cloned().zip(out.chunks_exact_mut(8)) {
        dst.copy_from_slice(&src.to_le_bytes());
    }
}

#[test]
fn as_int() {
    let a = BaseElement::from_raw([3, 0, 0, 0]);
    let b: u64 = a.as_int().try_into().unwrap();
    assert_eq!(b, 3);
}


================================================
FILE: core/src/field/f252/tests.rs
================================================


================================================
FILE: core/src/field/mod.rs
================================================
pub mod f252;


================================================
FILE: core/src/flags/mod.rs
================================================
// Modified from https://github.com/o1-labs/proof-systems

//! Definition of some constants for easier readability of the steps.
//! When they refer to single bit flagsets, only one constant is needed.

/// Number of Cairo flags
pub const NUM_FLAGS: usize = 16;
/// Position of destination offset of 16 bits within instruction decomposition
pub const POS_DST: usize = 0;
/// Position of first operand offset of 16 bits within instruction decomposition
pub const POS_OP0: usize = 1;
/// Position of second operand offset of 16 bits within instruction decomposition
pub const POS_OP1: usize = 2;
/// Bit position of the beginning of the flags in a Cairo instruction
pub const POS_FLAGS: usize = 48;

/// Destination refers to ap register
pub const DST_AP: u8 = 0;

/// First operand refers to ap register
pub const OP0_AP: u8 = 0;

/// Second operand is double indexing
pub const OP1_DBL: u8 = 0;
/// Second operand is immediate value
pub const OP1_VAL: u8 = 1;
/// Second operand refers to fp register
pub const OP1_FP: u8 = 2;
/// Second operand refers to ap register
pub const OP1_AP: u8 = 4;

/// Result is a single operand
pub const RES_ONE: u8 = 0;
/// Result is an addition
pub const RES_ADD: u8 = 1;
/// Result is a multiplication
pub const RES_MUL: u8 = 2;

/// Default increase of pc by adding instruction size
pub const PC_SIZ: u8 = 0;
/// Update pc by an absolute jump
pub const PC_ABS: u8 = 1;
/// Update pc by a relative jump
pub const PC_REL: u8 = 2;
/// Update pc by a conditional relative jump
pub const PC_JNZ: u8 = 4;

/// Update by 2 in call instructions or zero behaviour for other instructions
pub const AP_Z2: u8 = 0;
/// Update ap by adding a number of positions
pub const AP_ADD: u8 = 1;
/// Update ap by self increment
pub const AP_ONE: u8 = 2;

/// Operation code is a jump or an increment
pub const OPC_JMP_INC: u8 = 0;
/// Operation code is a call
pub const OPC_CALL: u8 = 1;
/// Operation code is a return
pub const OPC_RET: u8 = 2;
/// Operation code is an assert-equal
pub const OPC_AEQ: u8 = 4;


================================================
FILE: core/src/inputs/mod.rs
================================================
#[derive(Default)]
pub struct ProgramInputs {}


================================================
FILE: core/src/lib.rs
================================================
#![feature(array_chunks)]

pub use core::ops::Range;

pub use math::{ExtensionOf, FieldElement, StarkField};

pub mod word;
pub use word::{
    bias, FieldHelpers, FlagDecomposition, FlagGroupDecomposition, OffsetDecomposition, Word,
};

// TODO: Make the field element configurable in the CLI
//pub use math::fields::f128::BaseElement as Felt;
pub mod field;
pub use field::f252::{BaseElement as Felt, BigInt};

pub mod inputs;
pub use inputs::ProgramInputs;

pub mod flags;

// MAIN TRACE LAYOUT
// -----------------------------------------------------------------------------------------
//  A.  flags   (16) : Decoded instruction flags
//  B.  res     (1)  : Res value
//  C.  mem_p   (2)  : Temporary memory pointers (ap and fp)
//  D.  mem_a   (4)  : Memory addresses (pc, dst_addr, op0_addr, op1_addr)
//  E.  mem_v   (4)  : Memory values (inst, dst, op0, op1)
//  F.  offsets (3)  : (off_dst, off_op0, off_op1)
//  G.  derived (3)  : (t0, t1, mul)
//
//  A                B C  D    E    F   G
// ├xxxxxxxxxxxxxxxx|x|xx|xxxx|xxxx|xxx|xxx┤
//

pub const FLAG_TRACE_OFFSET: usize = 0;
pub const FLAG_TRACE_WIDTH: usize = 16;
pub const FLAG_TRACE_RANGE: Range<usize> = range(FLAG_TRACE_OFFSET, FLAG_TRACE_WIDTH);

pub const RES_TRACE_OFFSET: usize = 16;
pub const RES_TRACE_WIDTH: usize = 1;
pub const RES_TRACE_RANGE: Range<usize> = range(RES_TRACE_OFFSET, RES_TRACE_WIDTH);

pub const MEM_P_TRACE_OFFSET: usize = 17;
pub const MEM_P_TRACE_WIDTH: usize = 2;
pub const MEM_P_TRACE_RANGE: Range<usize> = range(MEM_P_TRACE_OFFSET, MEM_P_TRACE_WIDTH);

pub const MEM_A_TRACE_OFFSET: usize = 19;
pub const MEM_A_TRACE_WIDTH: usize = 4;
pub const MEM_A_TRACE_RANGE: Range<usize> = range(MEM_A_TRACE_OFFSET, MEM_A_TRACE_WIDTH);

pub const MEM_V_TRACE_OFFSET: usize = 23;
pub const MEM_V_TRACE_WIDTH: usize = 4;
pub const MEM_V_TRACE_RANGE: Range<usize> = range(MEM_V_TRACE_OFFSET, MEM_V_TRACE_WIDTH);

pub const OFF_X_TRACE_OFFSET: usize = 27;
pub const OFF_X_TRACE_WIDTH: usize = 3;
pub const OFF_X_TRACE_RANGE: Range<usize> = range(OFF_X_TRACE_OFFSET, OFF_X_TRACE_WIDTH);

pub const DERIVED_TRACE_OFFSET: usize = 30;
pub const DERIVED_TRACE_WIDTH: usize = 3;
pub const DERIVED_TRACE_RANGE: Range<usize> = range(DERIVED_TRACE_OFFSET, DERIVED_TRACE_WIDTH);

pub const SELECTOR_TRACE_OFFSET: usize = 33;
pub const SELECTOR_TRACE_WIDTH: usize = 1;
pub const SELECTOR_TRACE_RANGE: Range<usize> = range(SELECTOR_TRACE_OFFSET, SELECTOR_TRACE_WIDTH);

pub const TRACE_WIDTH: usize = 34;

// AUX TRACE LAYOUT (Memory)
// -----------------------------------------------------------------------------------------
//  A.  a_m_prime  (4) : Sorted memory address
//  B.  v_m_prime  (4) : Sorted memory values
//  C.  p_m        (4) : Permutation product (memory)
//
//  A    B    C
// ├xxxx|xxxx|xxxx┤

pub const A_M_PRIME_OFFSET: usize = 0;
pub const A_M_PRIME_WIDTH: usize = 4;

pub const V_M_PRIME_OFFSET: usize = 4;
pub const V_M_PRIME_WIDTH: usize = 4;

pub const P_M_OFFSET: usize = 8;
pub const P_M_WIDTH: usize = 4;

// AUX TRACE LAYOUT (Range check)
// -----------------------------------------------------------------------------------------
//  D.  a_rc_prime (3) : Sorted offset values
//  E.  p_rc       (3) : Permutation product (range check)
//
//  D   E
// ├xxx|xxx┤
//

pub const A_RC_PRIME_OFFSET: usize = 12;
pub const A_RC_PRIME_WIDTH: usize = 3;

pub const P_RC_OFFSET: usize = 15;
pub const P_RC_WIDTH: usize = 3;

// Main column indices

pub const AP: usize = MEM_P_TRACE_OFFSET;

// Aux column indices

pub const P_M_LAST: usize = P_M_OFFSET + P_M_WIDTH - 1;
pub const A_RC_PRIME_FIRST: usize = A_RC_PRIME_OFFSET;
pub const A_RC_PRIME_LAST: usize = A_RC_PRIME_OFFSET + 2;

/// Returns a [Range] initialized with the specified `start` and with `end` set to `start` + `len`.
pub const fn range(start: usize, len: usize) -> Range<usize> {
    Range {
        start,
        end: start + len,
    }
}

/// A structure to store program counter, allocation pointer and frame pointer
#[derive(Clone, Copy, Debug)]
pub struct RegisterState {
    /// Program counter: points to address in memory
    pub pc: Felt,
    /// Allocation pointer: points to first free space in memory
    pub ap: Felt,
    /// Frame pointer: points to the beginning of the stack in memory (for arguments)
    pub fp: Felt,
}

pub struct InstructionState {
    /// Instruction
    pub inst: Word,
    pub inst_size: Felt,
    /// Addresses
    pub dst_addr: Felt,
    pub op0_addr: Felt,
    pub op1_addr: Felt,
    /// Values
    pub dst: Option<Felt>,
    pub op0: Option<Felt>,
    pub op1: Option<Felt>,
    /// Result
    pub res: Option<Felt>,
}

impl RegisterState {
    /// Creates a new triple of pointers
    pub fn new<T: Into<Felt>>(pc: T, ap: T, fp: T) -> Self {
        RegisterState {
            pc: pc.into(),
            ap: ap.into(),
            fp: fp.into(),
        }
    }
}

impl InstructionState {
    /// Creates a new set instruction word and operand state
    pub fn new(
        inst: Word,
        inst_size: Felt,
        dst: Option<Felt>,
        op0: Option<Felt>,
        op1: Option<Felt>,
        res: Option<Felt>,
        dst_addr: Felt,
        op0_addr: Felt,
        op1_addr: Felt,
    ) -> Self {
        InstructionState {
            inst,
            inst_size,
            dst,
            op0,
            op1,
            res,
            dst_addr,
            op0_addr,
            op1_addr,
        }
    }
}

#[derive(PartialEq, Eq, Copy, Clone, Debug)]
pub enum Builtin {
    Output(u64),
    RangeCheck,
}


================================================
FILE: core/src/word/helpers.rs
================================================
// Modified from https://github.com/o1-labs/proof-systems

use super::{super::StarkField, Felt};
//use winter_utils::AsBytes;

pub trait FieldHelpers {
    /// Return field element as byte, if it fits. Otherwise returns least significant byte
    fn lsb(self) -> u8;

    /// Return pos-th 16-bit chunk as another field element
    fn chunk_u16(self, pos: usize) -> Felt;

    /// Return first 64 bits of the field element
    fn to_u64(self) -> u64;

    /// Return a field element in hexadecimal in little endian
    fn to_hex_le(self) -> String;

    /// Return a vector of field elements from a vector of i128
    fn vec_to_field(vec: &[i128]) -> Vec<Felt>;

    /// Return a vector of bits
    fn to_bits(self) -> Vec<bool>;
}

impl FieldHelpers for Felt {
    fn lsb(self) -> u8 {
        //self.as_bytes()[0]
        self.as_int().to_le_bytes()[0]
    }

    fn chunk_u16(self, pos: usize) -> Felt {
        //let bytes = self.as_bytes();
        let bytes = self.as_int().to_le_bytes();
        let chunk = u16::from(bytes[2 * pos]) + u16::from(bytes[2 * pos + 1]) * 2u16.pow(8);
        Felt::from(chunk)
    }

    fn to_u64(self) -> u64 {
        //let bytes = self.as_bytes();
        let bytes = self.as_int().to_le_bytes();
        let mut acc: u64 = 0;
        for i in 0..8 {
            acc += 2u64.pow(i * 8) * (bytes[i as usize] as u64);
        }
        acc
    }

    fn to_hex_le(self) -> String {
        let mut bytes = self.as_int().to_le_bytes();
        bytes.reverse();
        hex::encode(bytes)
    }

    fn vec_to_field(vec: &[i128]) -> Vec<Felt> {
        vec.iter()
            .map(|i| {
                if *i < 0 {
                    -Felt::from((-(*i)) as u64)
                } else {
                    Felt::from((*i) as u64)
                }
            })
            .collect()
    }

    fn to_bits(self) -> Vec<bool> {
        //self.as_bytes().iter().fold(vec![], |mut bits, byte| {
        let bytes = self.as_int().to_le_bytes();
        bytes.iter().fold(vec![], |mut bits, byte| {
            let mut byte = *byte;
            for _ in 0..8 {
                bits.push(byte & 0x01 == 0x01);
                byte >>= 1;
            }
            bits
        })
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_field_to_bits() {
        let fe = Felt::from(256u32);
        let bits = fe.to_bits();
        println!("{:?}", &bits[0..16]);
    }

    #[test]
    fn test_field_to_chunks() {
        let fe = Felt::from(0x480680017fff8000u64);
        let chunk = fe.chunk_u16(1);
        println!("chunk {:?}", chunk);
        println!("chunk2 {:?}", Felt::from(0x7fffu64));
        assert_eq!(chunk, Felt::from(0x7fffu64));
    }
}


================================================
FILE: core/src/word/mod.rs
================================================
// Modified from https://github.com/o1-labs/proof-systems

use super::{Felt, FieldElement};
use crate::flags::*;

mod helpers;
pub use helpers::FieldHelpers;

/// A  word for the runner. Some words are instructions (which fit inside a `u64`). Others are immediate values (any `F` element).
#[derive(Clone, Copy, Debug)]
pub struct Word(Felt);

/// Returns an offset of 16 bits to its biased representation in the interval `[-2^15,2^15)` as a field element
pub fn bias<E: FieldElement>(offset: E) -> E {
    offset - E::from(2u16.pow(15u32)) // -2^15 + sum_(i=0..15) b_i * 2^i
}

impl Word {
    /// Creates a [Word] from a field element
    pub fn new(word: Felt) -> Word {
        Word(word)
    }

    /// Returns the content of the word as a field element
    pub fn word(&self) -> Felt {
        self.0
    }
}

pub trait OffsetDecomposition<F> {
    /// Returns the destination offset in biased representation
    fn off_dst(&self) -> F;

    /// Returns the first operand offset in biased representation
    fn off_op0(&self) -> F;

    /// Returns the second operand offset in biased representation
    fn off_op1(&self) -> F;
}

/// This trait contains methods that decompose a field element into [Word] components
pub trait FlagDecomposition<F> {
    /// Returns vector of 16 flags
    fn flags(&self) -> Vec<F>;

    /// Returns i-th bit-flag
    fn flag_at(&self, pos: usize) -> F;

    /// Returns bit-flag for destination register as `F`
    fn f_dst_fp(&self) -> F {
        self.flag_at(0)
    }

    /// Returns bit-flag for first operand register as `F`
    fn f_op0_fp(&self) -> F {
        self.flag_at(1)
    }

    /// Returns bit-flag for immediate value for second register as `F`
    fn f_op1_val(&self) -> F {
        self.flag_at(2)
    }

    /// Returns bit-flag for frame pointer for second register as `F`
    fn f_op1_fp(&self) -> F {
        self.flag_at(3)
    }

    /// Returns bit-flag for allocation pointer for second regsiter as `F`
    fn f_op1_ap(&self) -> F {
        self.flag_at(4)
    }

    /// Returns bit-flag for addition operation in right side as `F`
    fn f_res_add(&self) -> F {
        self.flag_at(5)
    }

    /// Returns bit-flag for multiplication operation in right side as `F`
    fn f_res_mul(&self) -> F {
        self.flag_at(6)
    }

    /// Returns bit-flag for program counter update being absolute jump as `F`
    fn f_pc_abs(&self) -> F {
        self.flag_at(7)
    }

    /// Returns bit-flag for program counter update being relative jump as `F`
    fn f_pc_rel(&self) -> F {
        self.flag_at(8)
    }

    /// Returns bit-flag for program counter update being conditional jump as `F`
    fn f_pc_jnz(&self) -> F {
        self.flag_at(9)
    }

    /// Returns bit-flag for allocation counter update being a manual addition as `F`
    fn f_ap_add(&self) -> F {
        self.flag_at(10)
    }

    /// Returns bit-flag for allocation counter update being a self increment as `F`
    fn f_ap_one(&self) -> F {
        self.flag_at(11)
    }

    /// Returns bit-flag for operation being a call as `F`
    fn f_opc_call(&self) -> F {
        self.flag_at(12)
    }

    /// Returns bit-flag for operation being a return as `F`
    fn f_opc_ret(&self) -> F {
        self.flag_at(13)
    }

    /// Returns bit-flag for operation being an assert-equal as `F`
    fn f_opc_aeq(&self) -> F {
        self.flag_at(14)
    }

    /// Returns bit-flag for 16th position
    fn f15(&self) -> F {
        self.flag_at(15)
    }
}

pub trait FlagGroupDecomposition<F> {
    /// Returns flagset for destination register
    fn dst_reg(&self) -> u8;

    /// Returns flagset for first operand register
    fn op0_reg(&self) -> u8;

    /// Returns flagset for second operand register
    fn op1_src(&self) -> u8;

    /// Returns flagset for result logics
    fn res_log(&self) -> u8;

    /// Returns flagset for program counter update
    fn pc_up(&self) -> u8;

    /// Returns flagset for allocation pointer update
    fn ap_up(&self) -> u8;

    /// Returns flagset for operation code
    fn opcode(&self) -> u8;
}

impl OffsetDecomposition<Felt> for Word {
    fn off_dst(&self) -> Felt {
        // The least significant 16 bits
        bias(self.word().chunk_u16(POS_DST))
    }

    fn off_op0(&self) -> Felt {
        // From the 32nd bit to the 17th
        bias(self.word().chunk_u16(POS_OP0))
    }

    fn off_op1(&self) -> Felt {
        // From the 48th bit to the 33rd
        bias(self.word().chunk_u16(POS_OP1))
    }
}

impl FlagDecomposition<Felt> for Word {
    fn flags(&self) -> Vec<Felt> {
        let mut flags = Vec::with_capacity(NUM_FLAGS);
        // The most significant 16 bits
        for i in 0..NUM_FLAGS {
            flags.push(self.flag_at(i));
        }
        flags
    }

    fn flag_at(&self, pos: usize) -> Felt {
        Felt::from(self.word().to_bits()[POS_FLAGS + pos] as u32)
    }
}

impl FlagGroupDecomposition<Felt> for Word {
    fn dst_reg(&self) -> u8 {
        // dst_reg = fDST_REG
        self.f_dst_fp().lsb()
    }

    fn op0_reg(&self) -> u8 {
        // op0_reg = fOP0_REG
        self.f_op0_fp().lsb()
    }

    fn op1_src(&self) -> u8 {
        // op1_src = 4*fOP1_AP + 2*fOP1_FP + fOP1_VAL
        2 * (2 * self.f_op1_ap().lsb() + self.f_op1_fp().lsb()) + self.f_op1_val().lsb()
    }

    fn res_log(&self) -> u8 {
        // res_log = 2*fRES_MUL + fRES_ADD
        2 * self.f_res_mul().lsb() + self.f_res_add().lsb()
    }

    fn pc_up(&self) -> u8 {
        // pc_up = 4*fPC_JNZ + 2*fPC_REL + fPC_ABS
        2 * (2 * self.f_pc_jnz().lsb() + self.f_pc_rel().lsb()) + self.f_pc_abs().lsb()
    }

    fn ap_up(&self) -> u8 {
        // ap_up = 2*fAP_ONE + fAP_ADD
        2 * self.f_ap_one().lsb() + self.f_ap_add().lsb()
    }

    fn opcode(&self) -> u8 {
        // opcode = 4*fOPC_AEQ + 2*fOPC_RET + fOPC_CALL
        2 * (2 * self.f_opc_aeq().lsb() + self.f_opc_ret().lsb()) + self.f_opc_call().lsb()
    }
}

#[cfg(test)]
mod tests {
    use super::Felt as F;

    #[test]
    fn test_biased() {
        assert_eq!(F::from(1u32), super::bias(F::from(0x8001u32)));
        assert_eq!(F::from(0u32), super::bias(F::from(0x8000u32)));
        println!("{:?} {:?}", -F::from(1u32), super::bias(F::from(0x7fffu32)));
        assert_eq!(-F::from(1u32), super::bias(F::from(0x7fffu32)));
    }
}


================================================
FILE: examples/Cargo.toml
================================================
[package]
name = "examples"
version = "0.1.0"
edition = "2021"
rust-version = "1.57"

[[bin]]
name = "giza-examples"
path = "src/main.rs"
bench = false
doctest = false

[dependencies]
air = { package = "giza-air", path = "../air", version = "0.1", default-features = false }
prover = { package = "giza-prover", path = "../prover", version = "0.1", default-features = false }
runner = { package = "giza-runner", path = "../runner", version = "0.1", default-features = false }
giza_core = { package = "giza-core", path = "../core", version = "0.1", default-features = false }
winterfell = { package = "winter-verifier", git = "https://github.com/maxgillett/winterfell", rev = "0aad6a5", features = ["std"], version = "0.4", default-features = false }


================================================
FILE: examples/src/main.rs
================================================
use air::{ProcessorAir, ProofOptions};
use giza_core::Felt;
use runner::{Memory, Program};

fn main() {
    //  %builtins output
    //  from starkware.cairo.common.serialize import serialize_word
    //  func main{output_ptr : felt*}():
    //      tempvar x = 10
    //      tempvar y = x + x
    //      tempvar z = y * y + x
    //      serialize_word(x)
    //      serialize_word(y)
    //      serialize_word(z)
    //      return ()
    //  end
    //  */
    let instrs: Vec<Felt> = vec![
        Felt::from(0x400380007ffc7ffdu64),
        Felt::from(0x482680017ffc8000u64),
        Felt::from(1u64),
        Felt::from(0x208b7fff7fff7ffeu64),
        Felt::from(0x480680017fff8000u64),
        Felt::from(10u64),
        Felt::from(0x48307fff7fff8000u64),
        Felt::from(0x48507fff7fff8000u64),
        Felt::from(0x48307ffd7fff8000u64),
        Felt::from(0x480a7ffd7fff8000u64),
        Felt::from(0x48127ffb7fff8000u64),
        Felt::from(0x1104800180018000u64),
        -Felt::from(11u64),
        Felt::from(0x48127ff87fff8000u64),
        Felt::from(0x1104800180018000u64),
        -Felt::from(14u64),
        Felt::from(0x48127ff67fff8000u64),
        Felt::from(0x1104800180018000u64),
        -Felt::from(17u64),
        //Felt::from(0x208b7fff7fff7ffeu64),
        Felt::from(0x10780017fff7fffu64), // infinite loop
    ];
    let mut mem = Memory::new(instrs);
    mem.write_pub(Felt::from(21u32), Felt::from(41u32)); // beginning of output
    mem.write_pub(Felt::from(22u32), Felt::from(44u32)); // end of output
    mem.write_pub(Felt::from(23u32), Felt::from(44u32)); // end of program

    // run the program to create an execution trace
    let mut program = Program::new(&mut mem, 5, 24);
    let trace = program.execute().unwrap();

    // generate the proof of execution
    let proof_options = ProofOptions::with_proof_options(None, None, None, None, None);
    let (proof, pub_inputs) = prover::prove_trace(trace, &proof_options).unwrap();
    let proof_bytes = proof.to_bytes();
    println!("Proof size: {:.1} KB", proof_bytes.len() as f64 / 1024f64);

    // verify correct program execution
    match winterfell::verify::<ProcessorAir>(proof, pub_inputs) {
        Ok(_) => println!("Execution verified"),
        Err(err) => println!("Failed to verify execution: {}", err),
    }
}


================================================
FILE: program.json
================================================


================================================
FILE: prover/Cargo.toml
================================================
[package]
name = "giza-prover"
version = "0.1.0"
edition = "2021"
rust-version = "1.57"

[dependencies]
air = { package = "giza-air", path = "../air", version = "0.1", default-features = false }
prover = { package = "winter-prover", git = "https://github.com/maxgillett/winterfell", rev = "0aad6a5", version = "0.4", features = ["concurrent"], default-features = false }
runner = { package = "giza-runner", path = "../runner", version = "0.1", default-features = false }
giza_core = { package = "giza-core", path = "../core", version = "0.1", default-features = false }


================================================
FILE: prover/src/lib.rs
================================================
use air::{ProcessorAir, PublicInputs};
use giza_core::{Felt, RegisterState, MEM_A_TRACE_OFFSET, MEM_P_TRACE_OFFSET};
use prover::{Prover, Trace};
use runner::{ExecutionError, ExecutionTrace};

// EXPORTS
// ================================================================================================

pub use air::{FieldExtension, HashFunction, ProofOptions};
pub use prover::StarkProof;

// EXECUTOR
// ================================================================================================

/// Proves an execution trace and returns the result together with a STARK-based proof
/// of execution.
pub fn prove_trace(
    trace: ExecutionTrace,
    options: &ProofOptions,
) -> Result<(StarkProof, PublicInputs), ExecutionError> {
    let prover = ExecutionProver::new(options.clone());
    let public_inputs = prover.get_pub_inputs(&trace);
    let proof = prover.prove(trace).map_err(ExecutionError::ProverError)?;
    Ok((proof, public_inputs))
}

// PROVER
// ================================================================================================

pub struct ExecutionProver {
    options: ProofOptions,
}

impl ExecutionProver {
    pub fn new(options: ProofOptions) -> Self {
        Self { options }
    }
}

impl Prover for ExecutionProver {
    type BaseField = Felt;
    type Air = ProcessorAir;
    type Trace = ExecutionTrace;

    fn options(&self) -> &prover::ProofOptions {
        &self.options
    }

    fn get_pub_inputs(&self, trace: &ExecutionTrace) -> PublicInputs {
        let last_step = trace.num_steps - 1;

        let pc_init = trace.main_segment().get(MEM_A_TRACE_OFFSET, 0);
        let ap_init = trace.main_segment().get(MEM_P_TRACE_OFFSET, 0);
        let init = RegisterState::new(pc_init, ap_init, ap_init);

        let pc_fin = trace.main_segment().get(MEM_A_TRACE_OFFSET, last_step);
        let ap_fin = trace.main_segment().get(MEM_P_TRACE_OFFSET, last_step);
        let fin = RegisterState::new(pc_fin, ap_fin, ap_fin);

        let rc_min = trace.rc_min;
        let rc_max = trace.rc_max;

        let mem = trace.get_public_mem();

        PublicInputs::new(
            init,
            fin,
            rc_min,
            rc_max,
            mem,
            trace.num_steps,
            trace.builtins.clone(),
        )
    }
}


================================================
FILE: runner/Cargo.toml
================================================
[package]
name = "giza-runner"
version = "0.1.0"
edition = "2021"
rust-version = "1.57"

[lib]
bench = false
doctest = false

[dependencies]
air = { package = "giza-air", path = "../air", version = "0.1", default-features = false }
giza_core = { package = "giza-core", path = "../core", version = "0.1", default-features = false }
winterfell = { package = "winter-prover", git = "https://github.com/maxgillett/winterfell", rev = "0aad6a5", version = "0.4", features = ["concurrent"], default-features = false }
serde = { version = "1.0.136", features = ["derive"] }
serde_json = "1.0.79"
itertools = "0.10.3"
hex = "0.4"
pyo3 = { package = "pyo3", version = "0.16.3", features = ["auto-initialize"], optional = true }
indicatif = {version = "*", features = ["rayon"]}
rayon = "1.5.3"

[features]
hints = ["dep:pyo3"]



================================================
FILE: runner/src/cairo_interop.rs
================================================
/// Code for parsing the outputs of Starkware's cairo-runner.
/// Note the following:
/// - Field elements are encoded in little-endian byte order.
/// - Cairo serializes field elements as 32 bytes (the program
///   prime is assumed to be equal to the 252-bit Starkware prime).
///
use crate::memory::Memory;
use giza_core::{Builtin, Felt, RegisterState, Word};
use serde::{Deserialize, Serialize};
use std::fs::{metadata, File};
use std::io::{BufReader, Read};
use std::path::PathBuf;

#[derive(Serialize, Deserialize)]
struct CompiledProgram {
    builtins: Vec<String>,
    data: Vec<String>,
    prime: String,
}

/// Parses an execution trace outputted by the cairo-runner.
/// e.g. cairo-runner --trace_file out/trace.bin
pub fn read_trace_bin(path: &PathBuf) -> Vec<RegisterState> {
    let mut f = File::open(&path).expect("no file found");
    let metadata = metadata(&path).expect("unable to read metadata");
    let length = metadata.len() as usize;

    // Buffer for register values
    let mut pc: [u8; 8] = Default::default();
    let mut ap: [u8; 8] = Default::default();
    let mut fp: [u8; 8] = Default::default();

    let mut ptrs: Vec<RegisterState> = vec![];
    let mut bytes_read = 0;
    while bytes_read < length {
        bytes_read += f.read(&mut ap).unwrap();
        bytes_read += f.read(&mut fp).unwrap();
        bytes_read += f.read(&mut pc).unwrap();
        let reg = RegisterState::new(
            u64::from_le_bytes(pc),
            u64::from_le_bytes(ap),
            u64::from_le_bytes(fp),
        );
        ptrs.push(reg);
    }

    //print_registers(&ptrs);

    ptrs
}

/// Parses a memory dump outputted by the cairo-runner.
/// e.g. cairo-runner --memory_file out/memory.bin
pub fn read_memory_bin(mem_path: &PathBuf, program_path: &PathBuf) -> Memory {
    // Read memory trace
    let mut f = File::open(&mem_path).expect("Memory trace file not found");
    let metadata = metadata(&mem_path).expect("Unable to read metadata");
    let length = metadata.len() as usize;

    // Buffer for memory accesses
    let mut address: [u8; 8] = Default::default();
    let mut value: [u8; 32] = Default::default();

    let mut mem = Memory::new(vec![]).clone();
    let mut bytes_read = 0;
    while bytes_read < length {
        bytes_read += f.read(&mut address).unwrap();
        bytes_read += f.read(&mut value).unwrap();
        mem.write(
            Felt::try_from(u64::from_le_bytes(address)).unwrap(),
            Felt::try_from(value).unwrap(),
        );
    }

    // Read compiled program and set memory codelen (the length of the public memory)
    let file = File::open(&program_path).expect("Compiled program file not found");
    let reader = BufReader::new(file);
    let p: CompiledProgram = serde_json::from_reader(reader).unwrap();
    mem.set_codelen(p.data.len());

    //print_memory(&mem);

    mem
}

pub fn read_builtins(program_path: &PathBuf, output_len: Option<u64>) -> Vec<Builtin> {
    // Read compiled program and set memory codelen (the length of the public memory)
    let file = File::open(&program_path).expect("Compiled program file not found");
    let reader = BufReader::new(file);
    let p: CompiledProgram = serde_json::from_reader(reader).unwrap();
    let builtins = p
        .builtins
        .iter()
        .filter_map(|b| match b.as_str() {
            "output" => Some(Builtin::Output(output_len.unwrap())),
            _ => None,
        })
        .collect::<Vec<_>>();
    builtins
}

fn print_registers(reg: &[RegisterState]) {
    for (n, r) in reg.iter().enumerate() {
        println!("{} {} {} {}", n, r.pc, r.ap, r.fp,);
    }
}

fn print_memory(mem: &Memory) {
    for n in 0..mem.size() as usize {
        println!(
            "{} {}",
            n,
            mem.data[n].unwrap_or(Word::new(Felt::from(0u8))).word()
        );
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_trace_bin() {
        let trace = read_trace_bin(&PathBuf::from("../tmp/trace.bin"));
        println!("{:?}", trace);
    }

    #[test]
    fn test_memory_bin() {
        let mem = read_memory_bin(
            &PathBuf::from("../tmp/memory.bin"),
            &PathBuf::from("../tmp/program.json"),
        );
        println!("{:?}", mem.data);
    }
}


================================================
FILE: runner/src/errors.rs
================================================
use winterfell::ProverError;

#[derive(Debug)]
pub enum ExecutionError {
    ProverError(ProverError),
}


================================================
FILE: runner/src/hints.rs
================================================
use crate::memory::Memory;
use crate::runner::Step;
use giza_core::{Felt, StarkField, Word};

use pyo3::conversion::{FromPyObject, ToPyObject};
use pyo3::prelude::*;
use pyo3::types::PyDict;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::convert::TryInto;

#[derive(Default)]
pub struct HintManager {
    pub hints: HashMap<u64, Vec<Hint>>,
}

impl HintManager {
    pub fn push_hint(&mut self, pc: u64, hint: Hint) {
        self.hints.entry(pc).or_default().push(hint);
    }
    pub fn get_hints(&self, pc: Felt) -> Option<&Vec<Hint>> {
        let pc: u64 = pc.as_int().try_into().unwrap();
        self.hints.get(&pc)
    }
}

#[derive(Serialize, Deserialize)]
pub struct Hint {
    code: String,
    accessible_scopes: Vec<String>,
    flow_tracking_data: Option<FlowTrackingData>,
}

impl Hint {
    pub fn new(
        code: String,
        accessible_scopes: Vec<String>,
        flow_tracking_data: Option<FlowTrackingData>,
    ) -> Self {
        Hint {
            code,
            accessible_scopes,
            flow_tracking_data,
        }
    }
}

#[derive(Serialize, Deserialize)]
pub struct FlowTrackingData {
    ap_tracking: ApTracking,
    reference_ids: HashMap<String, u64>,
}

#[derive(Serialize, Deserialize)]
pub struct ApTracking {
    group: u64,
    offset: u64,
}

#[derive(Default, Debug)]
pub struct MemoryUpdate(pub Vec<(u64, Word)>);

/// Data structure containing all register and memory updates effected by hint execution
#[derive(Default, Debug)]
pub struct ExecutionEffect {
    pub pc: Felt,
    pub ap: Felt,
    pub fp: Felt,
    pub mem_updates: Option<MemoryUpdate>,
}

impl Hint {
    /// Run hint code in a Python environment, and return the aggregated effect
    /// on program state
    pub fn exec(&self, step: &Step) -> PyResult<ExecutionEffect> {
        // TODO: Import Cairo toolchain and monkey patch methods
        // (e.g. reference manager setter method) to track memory updates
        Python::with_gil(|py| {
            let locals = PyDict::new(py);
            locals.set_item(
                "pc",
                TryInto::<u64>::try_into(step.curr.pc.as_int()).unwrap(),
            )?;
            locals.set_item(
                "ap",
                TryInto::<u64>::try_into(step.curr.ap.as_int()).unwrap(),
            )?;
            locals.set_item(
                "fp",
                TryInto::<u64>::try_into(step.curr.fp.as_int()).unwrap(),
            )?;
            locals.set_item("memory", &*step.mem)?;
            locals.set_item("memory_updates", PyDict::new(py))?;
            py.run(self.code.as_str(), None, Some(&locals))
                .expect("error executing hint code");
            ExecutionEffect::from_locals(locals)
        })
    }
}

impl ExecutionEffect {
    fn from_locals(locals: &PyDict) -> PyResult<ExecutionEffect> {
        let pc = locals.get_item("pc").unwrap().extract::<u64>()?;
        let ap = locals.get_item("ap").unwrap().extract::<u64>()?;
        let fp = locals.get_item("fp").unwrap().extract::<u64>()?;
        let mem_updates: Option<MemoryUpdate> = locals
            .get_item("memory_updates")
            .unwrap()
            .extract::<MemoryUpdate>()
            .ok();
        Ok(ExecutionEffect {
            pc: Felt::from(pc),
            ap: Felt::from(ap),
            fp: Felt::from(fp),
            mem_updates,
        })
    }
}

impl<'a> FromPyObject<'a> for MemoryUpdate {
    fn extract(dict: &PyAny) -> PyResult<Self> {
        let mut mem_update = MemoryUpdate::default();
        for (key, val) in dict.downcast::<PyDict>()?.iter() {
            mem_update.0.push((
                key.extract::<u64>()?,
                Word::new(Felt::from(val.extract::<u128>()?)),
            ));
        }
        Ok(mem_update)
    }
}

impl ToPyObject for Memory {
    fn to_object(&self, py: Python) -> PyObject {
        let dict = PyDict::new(py);
        dict.into()
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use giza_core::{Felt, RegisterState};

    #[test]
    fn test_hint_execution() {
        let mut memory = Memory::new(vec![]);
        memory.write(Felt::from(memory.size()), Felt::from(1u64));
        memory.write(Felt::from(memory.size()), Felt::from(2u64));
        println!("{}", memory);
        let step = Step::new(
            &mut memory,
            None,
            RegisterState::new(Felt::from(1u64), Felt::from(1u64), Felt::from(1u64)),
        );
        let hint = Hint::new(String::from("pc = 2; ap = 5; memory[1] = 10"), vec![], None);
        let res = hint.exec(&step);
        println!("res {:?}", res);
    }
}


================================================
FILE: runner/src/lib.rs
================================================
pub mod memory;
pub use memory::Memory;

pub mod runner;
pub use runner::Program;

#[cfg(feature = "hints")]
pub mod hints;

mod trace;
pub use trace::ExecutionTrace;

mod errors;
pub use errors::ExecutionError;

mod cairo_interop;


================================================
FILE: runner/src/memory.rs
================================================
// Modified from https://github.com/o1-labs/proof-systems

use std::convert::TryInto;
use std::fmt::{Display, Formatter, Result};
use std::ops::{Index, IndexMut};

use core::iter::repeat;
use giza_core::{Felt, FieldHelpers, StarkField, Word};

/// This data structure stores the memory of the program
#[derive(Clone)]
pub struct Memory {
    /// length of the public memory
    codelen: usize,
    /// full memory vector, None if non initialized
    pub data: Vec<Option<Word>>,
}

impl Index<Felt> for Memory {
    type Output = Option<Word>;
    fn index(&self, idx: Felt) -> &Self::Output {
        let addr: u64 = idx.to_u64();
        &self.data[addr as usize]
    }
}

impl IndexMut<Felt> for Memory {
    fn index_mut(&mut self, idx: Felt) -> &mut Self::Output {
        let addr: u64 = idx.to_u64();
        self.resize(addr);
        &mut self.data[addr as usize]
    }
}

impl Display for Memory {
    fn fmt(&self, f: &mut Formatter<'_>) -> Result {
        for i in 1..self.size() {
            // Visualize content of memory
            if let Some(elem) = self[Felt::from(i as u64)] {
                if writeln!(f, "{0:>6}: 0x{1:}", i, elem.word().to_hex_le()).is_err() {
                    println!("Error while writing")
                }
            } else if writeln!(f, "{0:>6}: None", i).is_err() {
                println!("Error while writing")
            }
        }
        Ok(())
    }
}

impl Memory {
    /// Create a new memory structure from a vector of field elements
    pub fn new(input: Vec<Felt>) -> Memory {
        // Initialized with the public memory (compiled instructions only)
        let mut aux = vec![Felt::from(0u8)];
        aux.extend(input);
        Memory {
            codelen: aux.len(),
            data: aux.into_iter().map(|i| Some(Word::new(i))).collect(),
        }
    }

    /// Get size of the public memory
    pub fn get_codelen(&self) -> usize {
        self.codelen
    }

    /// Set size of the public memory
    pub fn set_codelen(&mut self, len: usize) {
        self.codelen = len;
    }

    /// Get size of the full memory
    pub fn size(&self) -> u64 {
        self.data.len() as u64
    }

    /// Resizes memory with enough additional None slots if necessary before writing or reading
    fn resize(&mut self, addr: u64) {
        if let Some(additional) = addr.checked_sub(self.size() - 1) {
            self.data.extend(repeat(None).take(additional as usize));
        }
    }

    /// Write u64 element in memory address
    pub fn write(&mut self, addr: Felt, elem: Felt) {
        self[addr] = Some(Word::new(elem));
    }

    /// Write u64 element in memory address
    pub fn write_pub(&mut self, addr: Felt, elem: Felt) {
        self.write(addr, elem);
        self.codelen += 1;
    }

    /// Read element in memory address
    pub fn read(&self, addr: Felt) -> Option<Felt> {
        //self.resize(addr.to_u64()); // Resize if necessary
        self[addr].map(|x| x.word())
    }

    /// Returns a list of all memory holes (defined as missing private memory
    /// accesses from the provided trace vec)
    /// TODO: Memory should be stored as a BTreeMap in data, not a Vec.
    pub fn get_holes(&self, vec: Vec<Felt>) -> Vec<Felt> {
        let mut accesses = vec
            .iter()
            .map(|x| TryInto::<u64>::try_into(x.as_int()).unwrap())
            .collect::<Vec<_>>();
        accesses.sort_unstable();

        let mut holes = vec![];
        for s in accesses.windows(2) {
            match s[1] - s[0] {
                0 | 1 => {}
                _ => {
                    if s[0] > self.codelen as u64 {
                        holes.extend((s[0] + 1..s[1]).map(|x| Felt::from(x)).collect::<Vec<_>>());
                    }
                }
            }
        }
        holes
    }
}

#[cfg(test)]
mod tests {
    use super::Felt as F;
    use super::*;
    use giza_core::{Felt, FieldHelpers, Word};

    #[test]
    fn test_cairo_bytecode() {
        // This test starts with the public memory corresponding to a simple  program
        // func main{}():
        //    tempvar x = 10;
        //    return()
        // end
        // And checks that memory writing and reading works as expected by completing
        // the total memory of executing the program
        let instrs = vec![
            F::from(0x480680017fff8000u64),
            F::from(10u64),
            F::from(0x208b7fff7fff7ffeu64),
        ];
        let mut memory = Memory::new(instrs);
        memory.write(F::from(memory.size() as u64), F::from(7u64));
        memory.write(F::from(memory.size() as u64), F::from(7u64));
        memory.write(F::from(memory.size() as u64), F::from(10u64));
        println!("{}", memory);
        // Check content of an address
        assert_eq!(
            memory.read(F::from(1u32)).unwrap(),
            F::from(0x480680017fff8000u64)
        );
        // Check that the program contained 3 words
        assert_eq!(3, memory.get_codelen());
        // Check we have 6 words, excluding the dummy entry
        assert_eq!(6, memory.size() - 1);
        memory.read(F::from(10u32));
    }
}


================================================
FILE: runner/src/runner.rs
================================================
// Modified from https://github.com/o1-labs/proof-systems

use crate::errors::ExecutionError;
use crate::memory::Memory;
use crate::trace::ExecutionTrace;
use giza_core::{flags::*, *};

#[cfg(feature = "hints")]
use crate::hints::{ExecutionEffect as HintExecutionEffect, HintManager};

/// A data structure to store a current step of computation
pub struct Step<'a> {
    pub mem: &'a Memory,
    pub curr: RegisterState,
    pub next: Option<RegisterState>,
    #[cfg(feature = "hints")]
    hints: Option<&'a HintManager>,
}

impl<'a> Step<'a> {
    /// Creates a new execution step from a step index, a word, and current pointers
    pub fn new(mem: &'a Memory, ptrs: RegisterState) -> Step<'a> {
        Step {
            mem,
            curr: ptrs,
            next: None,
        }
    }

    /// Executes a step from the current registers and returns the instruction state
    pub fn execute(&mut self, write: bool) -> InstructionState {
        // Execute hints and apply changes
        #[cfg(feature = "hints")]
        self.execute_hints();

        // Execute instruction
        let (op0_addr, mut op0) = self.set_op0();
        let (op1_addr, mut op1, size) = self.set_op1(op0);
        let (dst_addr, mut dst) = self.set_dst();
        let mut res = self.set_res(op0, op1, dst);
        let next_pc = self.next_pc(size, res, dst, op1);
        let (next_ap, next_fp, op0_update, op1_update, res_update, dst_update) =
            self.next_apfp(size, res, dst, dst_addr, op1_addr, write);
        if op0_update.is_some() {
            op0 = op0_update;
        }
        if op1_update.is_some() {
            op1 = op1_update;
        }
        if res_update.is_some() {
            res = res_update;
        }
        if dst_update.is_some() {
            dst = dst_update;
        }
        self.next = Some(RegisterState::new(
            next_pc.expect("Empty next program counter"),
            next_ap.expect("Empty next allocation pointer"),
            next_fp.expect("Empty next frame pointer"),
        ));
        InstructionState::new(
            self.inst(),
            size,
            dst,
            op0,
            op1,
            res,
            dst_addr,
            op0_addr,
            op1_addr,
        )
    }

    #[cfg(feature = "hints")]
    fn set_hint_manager(&mut self, hints: &'a HintManager) {
        self.hints = hints;
    }

    #[cfg(feature = "hints")]
    fn execute_hints(&mut self) {
        if let Some(manager) = self.hints {
            for hint in manager.get_hints(self.curr.pc).into_iter().flatten() {
                let changes = hint.exec(&self).unwrap();
                self.apply_hint_effects(changes);
            }
        }
    }

    #[cfg(feature = "hints")]
    fn apply_hint_effects(&mut self, res: HintExecutionEffect) {
        self.curr.pc = res.pc;
        self.curr.ap = res.ap;
        self.curr.fp = res.fp;
        if let Some(updates) = res.mem_updates {
            for (addr, elem) in updates.0.iter() {
                self.mem.write(Felt::from(*addr), elem.word());
            }
        }
    }

    /// This function returns the current word instruction being executed
    fn inst(&mut self) -> Word {
        Word::new(self.mem.read(self.curr.pc).expect("pc points to None cell"))
    }

    /// This function computes the first operand address.
    /// Outputs: `(op0_addr, op0)`
    fn set_op0(&mut self) -> (Felt, Option<Felt>) {
        let reg = match self.inst().op0_reg() {
            /*0*/ OP0_AP => self.curr.ap, // reads first word from allocated memory
            /*1*/ _ => self.curr.fp, // reads first word from input stack
        };
        let op0_addr = reg + self.inst().off_op0();
        let op0 = self.mem.read(op0_addr);
        (op0_addr, op0)
    }

    /// This function computes the second operand address and content and the instruction size
    /// Panics if the flagset `OP1_SRC` has more than 1 nonzero bit
    /// Inputs: `op0`
    /// Outputs: `(op1_addr, op1, size)`
    fn set_op1(&mut self, op0: Option<Felt>) -> (Felt, Option<Felt>, Felt) {
        let (reg, size) = match self.inst().op1_src() {
            /*0*/
            OP1_DBL => (op0.expect("None op0 for OP1_DBL"), Felt::ONE), // double indexing, op0 should be positive for address
            /*1*/
            OP1_VAL => (self.curr.pc, Felt::TWO), // off_op1 will be 1 and then op1 contains an immediate value
            /*2*/ OP1_FP => (self.curr.fp, Felt::ONE),
            /*4*/ OP1_AP => (self.curr.ap, Felt::ONE),
            _ => panic!("Invalid op1_src flagset"),
        };
        let op1_addr = reg + self.inst().off_op1(); // apply second offset to corresponding register
        let op1 = self.mem.read(op1_addr);
        (op1_addr, op1, size)
    }

    /// This function computes the value of the result of the arithmetic operation
    /// Panics if a `jnz` instruction is used with an invalid format
    ///     or if the flagset `RES_LOG` has more than 1 nonzero bit
    /// Inputs: `op0`, `op1`
    /// Outputs: `res`
    fn set_res(&mut self, op0: Option<Felt>, op1: Option<Felt>, dst: Option<Felt>) -> Option<Felt> {
        let res;
        if self.inst().pc_up() == PC_JNZ {
            /*4*/
            // jnz instruction
            if self.inst().res_log() == RES_ONE /*0*/
                && self.inst().opcode() == OPC_JMP_INC /*0*/
                && self.inst().ap_up() != AP_ADD
            /* not 1*/
            {
                // in the context of a jnz instruction, the res register is unused, so we repurpose
                // it to hold the value v = dst^(-1), which is used in the pc update constraint
                let dst = dst.expect("None dst after JNZ");
                if dst == Felt::ZERO {
                    res = Some(dst)
                } else {
                    res = Some(dst.inv());
                }
            } else {
                panic!("Invalid JNZ instruction");
            }
        } else if self.inst().pc_up() == PC_SIZ /*0*/
            || self.inst().pc_up() == PC_ABS /*1*/
            || self.inst().pc_up() == PC_REL
        /*2*/
        {
            // rest of types of updates
            // common increase || absolute jump || relative jump
            res = {
                match self.inst().res_log() {
                    /*0*/
                    RES_ONE => op1, // right part is single operand
                    /*1*/
                    RES_ADD => Some(
                        op0.expect("None op0 after RES_ADD") + op1.expect("None op1 after RES_ADD"),
                    ), // right part is addition
                    /*2*/
                    RES_MUL => Some(
                        op0.expect("None op0 after RES_MUL") * op1.expect("None op1 after RES_MUL"),
                    ), // right part is multiplication
                    _ => panic!("Invalid res_log flagset"),
                }
            };
        } else {
            // multiple bits take value 1
            panic!("Invalid pc_up flagset");
        }
        res
    }

    /// This function computes the destination address
    /// Outputs: `(dst_addr, dst)`
    fn set_dst(&mut self) -> (Felt, Option<Felt>) {
        let reg = match self.inst().dst_reg() {
            /*0*/ DST_AP => self.curr.ap, // read from stack
            /*1*/ _ => self.curr.fp, // read from parameters
        };
        let dst_addr = reg + self.inst().off_dst();
        let dst = self.mem.read(dst_addr);
        (dst_addr, dst)
    }

    /// This function computes the next program counter
    /// Panics if the flagset `PC_UP` has more than 1 nonzero bit
    /// Inputs: `size`, `res`, `dst`, `op1`,
    /// Outputs: `next_pc`
    fn next_pc(
        &mut self,
        size: Felt,
        res: Option<Felt>,
        dst: Option<Felt>,
        op1: Option<Felt>,
    ) -> Option<Felt> {
        match self.inst().pc_up() {
            /*0*/
            PC_SIZ => Some(self.curr.pc + size), // common case, next instruction is right after the current one
            /*1*/
            PC_ABS => Some(res.expect("None res after PC_ABS")), // absolute jump, next instruction is in res,
            /*2*/
            PC_REL => Some(self.curr.pc + res.expect("None res after PC_REL")), // relative jump, go to some address relative to pc
            /*4*/
            PC_JNZ => {
                // conditional relative jump (jnz)
                if dst == Some(Felt::ZERO) {
                    // if condition false, common case
                    Some(self.curr.pc + size)
                } else {
                    // if condition true, relative jump with second operand
                    Some(self.curr.pc + op1.expect("None op1 after PC_JNZ"))
                }
            }
            _ => panic!("Invalid pc_up flagset"),
        }
    }

    /// This function computes the next values of the allocation and frame pointers
    /// Panics if in a `call` instruction the flagset [AP_UP] is incorrect
    ///     or if in any other instruction the flagset AP_UP has more than 1 nonzero bit
    ///     or if the flagset `OPCODE` has more than 1 nonzero bit
    /// Inputs: `size`, `res`, `dst`, `dst_addr`, `op1_addr`
    /// Outputs: `(next_ap, next_fp, op0_update, op1_update, res_update, dst_update)`
    fn next_apfp(
        &mut self,
        size: Felt,
        res: Option<Felt>,
        dst: Option<Felt>,
        dst_addr: Felt,
        op1_addr: Felt,
        write: bool,
    ) -> (
        Option<Felt>,
        Option<Felt>,
        Option<Felt>,
        Option<Felt>,
        Option<Felt>,
        Option<Felt>,
    ) {
        let (next_ap, next_fp);
        let mut op0_update = None;
        let mut op1_update = None;
        let mut res_update = None;
        let mut dst_update = None;
        if self.inst().opcode() == OPC_CALL {
            /*1*/
            // "call" instruction
            if write {
                //self.mem.write(self.curr.ap, self.curr.fp);
                //self.mem
                //    .write(self.curr.ap + Felt::ONE, self.curr.pc + size);
            } else {
                let expected_a = self.mem.read(self.curr.ap).unwrap();
                let expected_b = self.mem.read(self.curr.ap + Felt::ONE).unwrap();
                assert_eq!(expected_a, self.curr.fp);
                assert_eq!(expected_b, self.curr.pc + size);
            }

            dst_update = self.mem.read(self.curr.ap);
            op0_update = self.mem.read(self.curr.ap + Felt::ONE);

            // Update fp
            // pointer for next frame is after current fp and instruction after call
            next_fp = Some(self.curr.ap + Felt::TWO);

            // Update ap
            match self.inst().ap_up() {
                /*0*/
                AP_Z2 => next_ap = Some(self.curr.ap + Felt::TWO), // two words were written so advance 2 positions
                _ => panic!("ap increment in call instruction"),
            };
        } else if self.inst().opcode() == OPC_JMP_INC /*0*/
            || self.inst().opcode() == OPC_RET /*2*/
            || self.inst().opcode() == OPC_AEQ
        /*4*/
        {
            // rest of types of instruction
            // jumps and increments || return || assert equal
            match self.inst().ap_up() {
                /*0*/ AP_Z2 => next_ap = Some(self.curr.ap), // no modification on ap
                /*1*/
                AP_ADD => {
                    // ap += <op> should be larger than current ap
                    next_ap = Some(self.curr.ap + res.expect("None res after AP_ADD"))
                }
                /*2*/ AP_ONE => next_ap = Some(self.curr.ap + Felt::ONE), // ap++
                _ => panic!("Invalid ap_up flagset"),
            }

            match self.inst().opcode() {
                /*0*/
                OPC_JMP_INC => next_fp = Some(self.curr.fp), // no modification on fp
                /*2*/
                OPC_RET => next_fp = Some(dst.expect("None dst after OPC_RET")), // ret sets fp to previous fp that was in [ap-2]
                /*4*/
                OPC_AEQ => {
                    // The following conditional is a fix that is not explained in the whitepaper
                    // The goal is to distinguish two types of ASSERT_EQUAL where one checks that
                    // dst = res , but in order for this to be true, one sometimes needs to write
                    // the res in mem(dst_addr) and sometimes write dst in mem(res_dir). The only
                    // case where res can be None is when res = op1 and thus res_dir = op1_addr
                    if res.is_none() {
                        // res = dst
                        if write {
                            //self.mem
                            //    .write(op1_addr, dst.expect("None dst after OPC_AEQ"));
                        } else {
                            let expected_a = self.mem.read(op1_addr).unwrap();
                            assert_eq!(expected_a, dst.unwrap());
                        }
                        op1_update = self.mem.read(op1_addr);
                        res_update = self.mem.read(op1_addr);
                    } else {
                        // dst = res
                        if write {
                            //self.mem
                            //    .write(dst_addr, res.expect("None res after OPC_AEQ"));
                        } else {
                            let expected_a = self.mem.read(dst_addr).unwrap();
                            assert_eq!(expected_a, res.unwrap());
                        }
                        dst_update = self.mem.read(dst_addr);
                    }
                    next_fp = Some(self.curr.fp); // no modification on fp
                }
                _ => {
                    panic!("This case must never happen")
                }
            }
        } else {
            panic!("Invalid opcode flagset");
        }
        (
            next_ap, next_fp, op0_update, op1_update, res_update, dst_update,
        )
    }
}

/// Trace-friendly record of registers and instruction state across
/// all program execution steps
pub struct State {
    pub flags: [Vec<Felt>; FLAG_TRACE_WIDTH],
    pub res: [Vec<Felt>; RES_TRACE_WIDTH],
    pub mem_p: [Vec<Felt>; MEM_P_TRACE_WIDTH],
    pub mem_a: [Vec<Felt>; MEM_A_TRACE_WIDTH],
    pub mem_v: [Vec<Felt>; MEM_V_TRACE_WIDTH],
    pub offsets: [Vec<Felt>; OFF_X_TRACE_WIDTH],
}

impl State {
    pub fn new(init_trace_len: usize) -> Self {
        let mut flags: Vec<Vec<Felt>> = Vec::with_capacity(FLAG_TRACE_WIDTH);
        let mut res: Vec<Vec<Felt>> = Vec::with_capacity(RES_TRACE_WIDTH);
        let mut mem_p: Vec<Vec<Felt>> = Vec::with_capacity(MEM_P_TRACE_WIDTH);
        let mut mem_a: Vec<Vec<Felt>> = Vec::with_capacity(MEM_A_TRACE_WIDTH);
        let mut mem_v: Vec<Vec<Felt>> = Vec::with_capacity(MEM_V_TRACE_WIDTH);
        let mut offsets: Vec<Vec<Felt>> = Vec::with_capacity(OFF_X_TRACE_WIDTH);
        for _ in 0..FLAG_TRACE_WIDTH {
            let column = Felt::zeroed_vector(init_trace_len);
            flags.push(column);
        }
        for _ in 0..RES_TRACE_WIDTH {
            let column = Felt::zeroed_vector(init_trace_len);
            res.push(column);
        }
        for _ in 0..MEM_P_TRACE_WIDTH {
            let column = Felt::zeroed_vector(init_trace_len);
            mem_p.push(column);
        }
        for _ in 0..MEM_A_TRACE_WIDTH {
            let column = Felt::zeroed_vector(init_trace_len);
            mem_a.push(column);
        }
        for _ in 0..MEM_V_TRACE_WIDTH {
            let column = Felt::zeroed_vector(init_trace_len);
            mem_v.push(column);
        }
        for _ in 0..OFF_X_TRACE_WIDTH {
            let column = Felt::zeroed_vector(init_trace_len);
            offsets.push(column);
        }
        State {
            flags: flags.try_into().unwrap(),
            res: res.try_into().unwrap(),
            mem_p: mem_p.try_into().unwrap(),
            mem_a: mem_a.try_into().unwrap(),
            mem_v: mem_v.try_into().unwrap(),
            offsets: offsets.try_into().unwrap(),
        }
    }

    pub fn set_register_state(&mut self, step: usize, s: RegisterState) {
        self.mem_a[0][step] = s.pc;
        self.mem_p[0][step] = s.ap;
        self.mem_p[1][step] = s.fp;
    }

    pub fn set_instruction_state(&mut self, step: usize, s: InstructionState) {
        // Flags
        let flags = s.inst.flags();
        for i in 0..=15 {
            self.flags[i][step] = flags[i];
        }

        // Result
        self.res[0][step] = s.res.unwrap_or(Felt::ZERO);

        // Instruction
        self.mem_v[0][step] = s.inst.word();

        // Auxiliary values
        self.mem_v[1][step] = s.dst.unwrap_or(Felt::ZERO);
        self.mem_v[2][step] = s.op0.unwrap_or(Felt::ZERO);
        self.mem_v[3][step] = s.op1.unwrap_or(Felt::ZERO);

        // Operands
        self.mem_a[1][step] = s.dst_addr;
        self.mem_a[2][step] = s.op0_addr;
        self.mem_a[3][step] = s.op1_addr;

        // Offsets
        self.offsets[0][step] = s.inst.off_dst();
        self.offsets[1][step] = s.inst.off_op0();
        self.offsets[2][step] = s.inst.off_op1();
    }
}

/// Stores all information needed to run a program
pub struct Program<'a> {
    /// total number of steps
    steps: usize,
    /// full execution memory
    mem: &'a mut Memory,
    /// initial register state
    init: RegisterState,
    /// final register state
    fin: RegisterState,
    /// requested builtins
    builtins: Vec<Builtin>,
    /// hints
    #[cfg(feature = "hints")]
    hints: Option<HintManager>,
}

impl<'a> Program<'a> {
    /// Creates an execution from the public information (memory and initial pointers)
    #[cfg(feature = "hints")]
    pub fn new(mem: &mut Memory, pc: u64, ap: u64, hints: Option<HintManager>) -> Program {
        Program {
            steps: 0,
            mem,
            init: RegisterState::new(Felt::from(pc), Felt::from(ap), Felt::from(ap)),
            fin: RegisterState::new(Felt::ZERO, Felt::ZERO, Felt::ZERO),
            builtins: vec![],
            hints,
        }
    }

    #[cfg(not(feature = "hints"))]
    pub fn new(mem: &mut Memory, pc: u64, ap: u64) -> Program {
        Program {
            steps: 0,
            mem,
            init: RegisterState::new(Felt::from(pc), Felt::from(ap), Felt::from(ap)),
            fin: RegisterState::new(Felt::ZERO, Felt::ZERO, Felt::ZERO),
            builtins: vec![],
        }
    }

    /// Outputs the total number of steps of the execution carried out by the runner
    pub fn get_steps(&self) -> usize {
        self.steps
    }

    /// Outputs the final value of the pointers after the execution carried out by the runner
    pub fn get_final(&self) -> RegisterState {
        self.fin
    }

    /// This function simulates an execution of the program received as input
    /// and returns an execution trace
    pub fn execute(&mut self) -> Result<ExecutionTrace, ExecutionError> {
        let mut state = State::new(self.mem.size() as usize);
        let mut n: usize = 0;
        let mut end = false;
        let mut curr = self.init;
        let mut next = curr;

        // keep executing steps until the end is reached
        while !end {
            // create current step of computation
            let mut step = Step::new(self.mem, next);
            curr = step.curr;

            #[cfg(feature = "hints")]
            step.set_hint_manager(self.hints.as_ref());

            // execute current step and save state
            let inst_state = step.execute(true);
            state.set_register_state(n, curr);
            state.set_instruction_state(n, inst_state);

            n += 1;
            match step.next {
                None => end = true,
                _ => {
                    next = step.next.expect("Empty next pointers");
                    if curr.ap.as_int() <= next.pc.as_int() {
                        // if reading from unallocated memory, end
                        end = true;
                    }
                }
            }
        }
        self.fin = curr;
        self.steps = n;

        Ok(ExecutionTrace::new(
            n,
            &mut state,
            &self.mem,
            self.builtins.clone(),
        ))
    }
}


================================================
FILE: runner/src/trace.rs
================================================
use crate::cairo_interop::{read_builtins, read_memory_bin, read_trace_bin};
use crate::memory::Memory;
use crate::runner::{State, Step};
use giza_core::{
    Builtin, Felt, FieldElement, StarkField, Word, AP, A_M_PRIME_WIDTH, A_RC_PRIME_WIDTH,
    MEM_A_TRACE_RANGE, MEM_A_TRACE_WIDTH, MEM_V_TRACE_RANGE, OFF_X_TRACE_RANGE, OFF_X_TRACE_WIDTH,
    P_M_WIDTH, P_RC_WIDTH, TRACE_WIDTH, V_M_PRIME_WIDTH,
};
use winterfell::{Matrix, Trace, TraceLayout};

use indicatif::ParallelProgressIterator;
use indicatif::ProgressIterator;
use itertools::Itertools;
use rayon::prelude::*;
use std::path::PathBuf;

pub struct ExecutionTrace {
    layout: TraceLayout,
    meta: Vec<u8>,
    trace: Matrix<Felt>,
    pub memory: Memory,
    pub rc_min: u16,
    pub rc_max: u16,
    pub num_steps: usize,
    pub builtins: Vec<Builtin>,
}

/// A virtual column is composed of one or more subcolumns.
struct VirtualColumn<'a, E: FieldElement> {
    subcols: &'a [Vec<E>],
}

impl<'a, E: FieldElement> VirtualColumn<'a, E> {
    fn new(subcols: &'a [Vec<E>]) -> Self {
        Self { subcols }
    }

    /// Pack subcolumns into a single output column: cycle through each subcolumn, appending
    /// a single value to the output column for each iteration step until exhausted.
    fn to_column(&self) -> Vec<E> {
        let mut col: Vec<E> = vec![];
        for n in 0..self.subcols[0].len() {
            for subcol in self.subcols {
                col.push(subcol[n]);
            }
        }
        col
    }

    /// Split subcolumns into multiple output columns: for each subcolumn, output a single
    /// value to each output column, cycling through each output column until exhuasted.
    fn to_columns(&self, num_rows: &[usize]) -> Vec<Vec<E>> {
        let mut n = 0;
        let mut cols: Vec<Vec<E>> = vec![vec![]; num_rows.iter().sum()];
        for (subcol, width) in self.subcols.iter().zip(num_rows) {
            for (elem, idx) in subcol.iter().zip((0..*width).cycle()) {
                cols[idx + n].push(*elem);
            }
            n += width;
        }
        cols
    }
}

struct Layouter<'a, E: FieldElement> {
    columns: &'a mut Vec<Vec<E>>,
    frame_len: usize,
}

impl<'a, E: FieldElement> Layouter<'a, E> {
    fn new(columns: &'a mut Vec<Vec<E>>, frame_len: usize) -> Self {
        Self { columns, frame_len }
    }

    /// Add one or more columns to the trace. The chunk size determines the number
    /// of subcolumn elements to place within each frame chunk (defaults to 1)
    /// starting from the top most row of the chunk.
    fn add_columns(&mut self, subcols: &[Vec<E>], chunk_size: Option<usize>) {
        for subcol in subcols.iter() {
            let mut col = E::zeroed_vector(subcol.len());
            for (col_chunk, subcol_chunk) in col
                .chunks_mut(self.frame_len)
                .zip(subcol.chunks(chunk_size.unwrap_or(1)))
            {
                for (n, elem) in subcol_chunk.iter().enumerate() {
                    col_chunk[n] = *elem
                }
            }
            self.columns.push(col);
        }
    }

    /// Resize columns to next power of two
    fn resize_all(&mut self) {
        resize_to_pow2(&mut self.columns);
    }
}

impl ExecutionTrace {
    /// Builds an execution trace
    pub(super) fn new(
        num_steps: usize,
        state: &mut State,
        memory: &Memory,
        builtins: Vec<Builtin>,
    ) -> Self {
        // Compute the derived ("auxiliary") trace values: t0, t1, and mul.
        // Note that in a conditional jump instruction we substitute res with dst^{-1}
        // (see page 53 of the whitepaper).
        let mut t0 = vec![];
        let mut t1 = vec![];
        let mut mul = vec![];
        for step in 0..num_steps {
            // TODO: Don't hardcode index values
            let f_pc_jnz = state.flags[9][step];
            let dst = state.mem_v[1][step];
            let res = state.res[0][step];
            t0.push(f_pc_jnz * dst); // f_pc_jnz * dst
            t1.push(t0[step] * res); // t_0 * res
            mul.push(state.mem_v[2][step] * state.mem_v[3][step]); // op0 * op1
        }

        // 1. Append dummy artificial accesses to mem_a and mem_v to fill memory holes.
        //    These gaps are due to interaction with builtins, and they still need to be handled
        //    elsewhere in the code for soundness.
        // 2. Append dummy (0,0) public memory values to mem_a and mem_v.
        //    Note that we don't need to worry about precise placement (i.e. ensuring that they are
        //    the final n entries in the columns), because these dummy values will extend into the
        //    resized column cells.
        //    TODO: We should also append dummy output (not just program) public memory, in case the
        //    trace length is not already long enough to contain these values.
        let mut col_extension = memory.get_holes(VirtualColumn::new(&state.mem_a).to_column());
        col_extension.extend(vec![Felt::ZERO; memory.get_codelen()]);
        for (n, col) in VirtualColumn::new(&[col_extension])
            .to_columns(&[MEM_A_TRACE_WIDTH])
            .iter()
            .enumerate()
        {
            state.mem_a[n].extend(col);
            state.mem_v[n].extend(Felt::zeroed_vector(col.len()));
        }

        // 1. Convert offsets into an unbiased representation by adding 2^15, so that values are
        //    within [0, 2^16].
        // 2. Fill gaps between sorted offsets so that we can compute the proper permutation
        //    product column in the range check auxiliary segment (if we implemented Ord for Felt
        //    we could achieve a speedup here)
        let b15 = Felt::from(2u8).exp(15u32.into());
        let mut rc_column: Vec<Felt> = VirtualColumn::new(&state.offsets)
            .to_column()
            .into_iter()
            .map(|x| x + b15)
            .collect();
        let mut rc_sorted: Vec<u16> = rc_column
            .iter()
            .map(|x| x.as_int().try_into().unwrap())
            .collect();
        rc_sorted.sort_unstable();
        let rc_min = rc_sorted.first().unwrap().clone();
        let rc_max = rc_sorted.last().unwrap().clone();
        for s in rc_sorted.windows(2).progress() {
            match s[1] - s[0] {
                0 | 1 => {}
                _ => {
                    rc_column.extend((s[0] + 1..s[1]).map(|x| Felt::from(x)).collect::<Vec<_>>());
                }
            }
        }
        let offsets = VirtualColumn::new(&[rc_column]).to_columns(&[3]);

        // This is hacky... We're adding a selector to the main trace to disable the Cairo
        // transition constraints for public memory (and any extended trace cells that were added
        // to ensure that that length is a power of two). If we instead used transition
        // exemptions, then proving/verifying time would be too slow for programs with a large
        // number of instructions.
        //
        // There are two methods that can be combined to avoid selectors:
        // - Transform traces so that they end in an inifite loop (use the instruction
        //   0x10780017fff7fffu64).
        // - Use a short bootloader program so that the number of transition exemptions is small
        //   and doesn't harm performance. This bootloader will compute and expose a hash of the
        //   private memory containing the program instructions to be run.
        let mut selector = vec![Felt::ONE; num_steps];
        selector[num_steps - 1] = Felt::ZERO;

        // Layout the trace
        let mut columns: Vec<Vec<Felt>> = Vec::with_capacity(TRACE_WIDTH);
        let mut layouter = Layouter::new(&mut columns, 1);
        layouter.add_columns(&state.flags, None);
        layouter.add_columns(&state.res, None);
        layouter.add_columns(&state.mem_p, None);
        layouter.add_columns(&state.mem_a, None);
        layouter.add_columns(&state.mem_v, None);
        layouter.add_columns(&offsets, None);
        layouter.add_columns(&[t0, t1, mul], None);
        layouter.add_columns(&[selector], None);

        layouter.resize_all();

        Self {
            layout: TraceLayout::new(
                TRACE_WIDTH,
                &[12, 6], // aux_segment widths
                &[2, 1],  // aux_segment rands
            ),
            meta: Vec::new(),
            trace: Matrix::new(columns),
            memory: memory.clone(),
            rc_min,
            rc_max,
            num_steps,
            builtins,
        }
    }

    /// Reconstructs the execution trace from file
    pub fn from_file(
        program_path: PathBuf,
        trace_path: PathBuf,
        memory_path: PathBuf,
        output_len: Option<u64>,
    ) -> ExecutionTrace {
        let mem = read_memory_bin(&memory_path, &program_path);
        let registers = read_trace_bin(&trace_path);
        let builtins = read_builtins(&program_path, output_len);
        let num_steps = registers.len();

        let inst_states = registers
            .par_iter()
            .progress()
            .map(|ptrs| {
                let mut step = Step::new(&mem, *ptrs);
                step.execute(false)
            })
            .collect::<Vec<_>>();

        let mut state = State::new(registers.len() + 1);
        for (n, (reg_state, inst_state)) in registers.iter().zip(inst_states).enumerate() {
            state.set_register_state(n, *reg_state);
            state.set_instruction_state(n, inst_state);
        }

        Self::new(num_steps, &mut state, &mem, builtins)
    }

    /// Return the program public memory
    pub fn get_program_mem(&self) -> (Vec<u64>, Vec<Option<Word>>) {
        let addrs = (0..self.memory.get_codelen() as u64).collect::<Vec<_>>();
        let vals = self.memory.data[..self.memory.get_codelen()].to_vec();
        (addrs, vals)
    }

    /// Return the output public memory
    pub fn get_output_mem(&self) -> (Vec<u64>, Vec<Option<Word>>) {
        for builtin in self.builtins.iter() {
            if let Builtin::Output(len) = builtin {
                let ptr_start: u64 = self.main_segment().get_column(AP)[self.num_steps - 1]
                    .as_int()
                    .try_into()
                    .unwrap();
                let ptr_end = ptr_start + len;
                let addrs = (ptr_start..ptr_end).collect::<Vec<_>>();
                let vals = addrs
                    .iter()
                    .map(|i| self.memory.data[*i as usize])
                    .collect::<Vec<_>>();
                return (addrs, vals);
            }
        }
        return (vec![], vec![]);
    }

    /// Return the combined public memory
    pub fn get_public_mem(&self) -> (Vec<u64>, Vec<Option<Word>>) {
        let (mut a, mut v) = self.get_program_mem();
        let (out_a, out_v) = self.get_output_mem();
        a.extend(out_a);
        v.extend(out_v);
        (a, v)
    }
}

impl Trace for ExecutionTrace {
    type BaseField = Felt;

    fn layout(&self) -> &TraceLayout {
        &self.layout
    }

    fn length(&self) -> usize {
        self.trace.num_rows()
    }

    fn meta(&self) -> &[u8] {
        &self.meta
    }

    fn main_segment(&self) -> &Matrix<Felt> {
        &self.trace
    }

    fn build_aux_segment<E>(
        &mut self,
        aux_segments: &[Matrix<E>],
        rand_elements: &[E],
    ) -> Option<Matrix<E>>
    where
        E: FieldElement<BaseField = Self::BaseField>,
    {
        match aux_segments.len() {
            0 => build_aux_segment_mem(self, rand_elements),
            1 => build_aux_segment_rc(self, rand_elements),
            _ => None,
        }
    }
}

/// Write documentation
fn build_aux_segment_mem<E>(trace: &ExecutionTrace, rand_elements: &[E]) -> Option<Matrix<E>>
where
    E: FieldElement + From<Felt>,
{
    let z = rand_elements[0];
    let alpha = rand_elements[1];

    // Pack main memory access trace columns into two virtual columns
    let main = trace.main_segment();
    let (a, v) = [MEM_A_TRACE_RANGE, MEM_V_TRACE_RANGE]
        .iter()
        .map(|range| {
            VirtualColumn::new(
                &range
                    .clone()
                    .map(|i| main.get_column(i).to_vec())
                    .collect::<Vec<_>>()[..],
            )
            .to_column()
        })
        .collect_tuple()
        .unwrap();

    // Construct duplicate virtual columns sorted by memory access, with dummy public
    // memory addresses/values replaced by their true values
    let mut a_prime = vec![E::ZERO; a.len()];
    let mut v_prime = vec![E::ZERO; a.len()];
    let mut a_replaced = a.clone();
    let mut v_replaced = v.clone();
    let (pub_a, pub_v) = trace.get_public_mem();
    let l = a.len() - pub_a.len() - 1;
    for (i, (n, x)) in pub_a.iter().copied().zip(pub_v).enumerate() {
        a_replaced[l + i] = Felt::from(n);
        v_replaced[l + i] = x.unwrap().word().into();
    }
    let mut indices = (0..a.len()).collect::<Vec<_>>();
    indices.sort_by_key(|&i| a_replaced[i].as_int());
    for (i, j) in indices.iter().copied().enumerate() {
        a_prime[i] = a_replaced[j].into();
        v_prime[i] = v_replaced[j].into();
    }

    // Construct virtual column of computed permutation products
    let mut p = vec![E::ZERO; trace.length() * MEM_A_TRACE_WIDTH];
    let a_0: E = a[0].into();
    let v_0: E = v[0].into();
    p[0] = (z - (a_0 + alpha * v_0).into()) / (z - (a_prime[0] + alpha * v_prime[0]).into());
    for i in (1..p.len()).progress() {
        let a_i: E = a[i].into();
        let v_i: E = v[i].into();
        p[i] = (z - (a_i + alpha * v_i).into()) * p[i - 1]
            / (z - (a_prime[i] + alpha * v_prime[i]).into());
    }

    // Split virtual columns into separate auxiliary columns
    let mut aux_columns = VirtualColumn::new(&[a_prime, v_prime, p]).to_columns(&[
        A_M_PRIME_WIDTH,
        V_M_PRIME_WIDTH,
        P_M_WIDTH,
    ]);
    resize_to_pow2(&mut aux_columns);

    Some(Matrix::new(aux_columns))
}

/// Write documentation
fn build_aux_segment_rc<E>(trace: &ExecutionTrace, rand_elements: &[E]) -> Option<Matrix<E>>
where
    E: FieldElement + From<Felt>,
{
    let z = rand_elements[0];

    // Pack main offset trace columns into a single virtual column
    let main = trace.main_segment();
    let a = VirtualColumn::new(
        &OFF_X_TRACE_RANGE
            .map(|i| main.get_column(i).to_vec())
            .collect::<Vec<_>>()[..],
    )
    .to_column();

    // Construct duplicate virtual column sorted by offset value
    let mut indices = (0..a.len()).collect::<Vec<_>>();
    indices.sort_by_key(|&i| a[i].as_int());
    let a_prime = indices.iter().map(|x| a[*x].into()).collect::<Vec<E>>();

    // Construct virtual column of computed permutation products
    let mut p = vec![E::ZERO; trace.length() * OFF_X_TRACE_WIDTH];
    let a_0: E = a[0].into();
    p[0] = (z - a_0) / (z - a_prime[0]);
    for i in (1..p.len()).progress() {
        let a_i: E = a[i].into();
        p[i] = (z - a_i) * p[i - 1] / (z - a_prime[i]);
    }

    // Split virtual columns into separate auxiliary columns
    let mut aux_columns =
        VirtualColumn::new(&[a_prime, p]).to_columns(&[A_RC_PRIME_WIDTH, P_RC_WIDTH]);
    resize_to_pow2(&mut aux_columns);

    Some(Matrix::new(aux_columns))
}

/// Resize columns to next power of two
fn resize_to_pow2<E: FieldElement>(columns: &mut [Vec<E>]) {
    let trace_len_pow2 = columns
        .iter()
        .map(|x| x.len().next_power_of_two())
        .max()
        .unwrap();
    for column in columns.iter_mut() {
        let last_value = column.last().copied().unwrap();
        column.resize(trace_len_pow2, last_value);
    }
}


================================================
FILE: rust-toolchain.toml
================================================
[toolchain]
channel = "nightly"


================================================
FILE: wasm/.gitignore
================================================
node_modules/
pkg/
dist/
output.bin


================================================
FILE: wasm/Cargo.toml
================================================
[package]
name = "giza-wasm"
version = "0.1.0"
edition = "2021"
rust-version = "1.57"

[lib]
crate-type = ["cdylib"]

[dependencies]
wasm-bindgen = "0.2.74"
js-sys = "0.3.57"
air = { package = "giza-air", path = "../air", version = "0.1", default-features = false }
giza_core = { package = "giza-core", path = "../core", version = "0.1", default-features = false }
winterfell = { package = "winter-verifier", git = "https://github.com/maxgillett/winterfell", rev = "0aad6a5", version = "0.4", default-features = false }
winter-utils = { package = "winter-utils", git = "https://github.com/maxgillett/winterfell", rev = "0aad6a5", version = "0.4", default-features = false }
bincode = "1.3.3"
serde = { version = "1.0.136", features = ["derive"] }

[profile.release]
lto = true
opt-level = 's'

[package.metadata.wasm-pack.profile.release]
wasm-opt = false


================================================
FILE: wasm/index.js
================================================
// Note that a dynamic `import` statement here is required due to
// webpack/webpack#6615, but in theory `import { greet } from './pkg';`
// will work here one day as well!
const rust = import('./pkg');

// Load a Cairo proof
import data from './output.bin';

rust
  .then(m => m.verify(data.data))
  .catch(console.error);




================================================
FILE: wasm/package.json
================================================
{
  "scripts": {
    "build": "webpack",
    "serve": "webpack-dev-server"
  },
  "devDependencies": {
    "@wasm-tool/wasm-pack-plugin": "1.6.0",
    "html-webpack-plugin": "^5.5.0",
    "text-encoding": "^0.7.0",
    "webpack": "^5.73.0",
    "webpack-cli": "^4.9.2",
    "webpack-dev-server": "^4.9.1"
  }
}


================================================
FILE: wasm/src/lib.rs
================================================
use air::{ProcessorAir, PublicInputs};
use serde::{Deserialize, Serialize};
use winter_utils::{Deserializable, SliceReader};
use winterfell::StarkProof;

use js_sys::Uint8Array;
use wasm_bindgen::prelude::*;

#[wasm_bindgen]
extern "C" {
    #[wasm_bindgen(js_namespace = console)]
    fn log(s: &str);
}

#[wasm_bindgen]
pub fn verify(buffer: &Uint8Array) {
    // Load proof and public inputs
    let b = buffer.to_vec();
    let data: ProofData = bincode::deserialize(&b).unwrap();
    let pub_inputs = PublicInputs::read_from(&mut SliceReader::new(&data.input_bytes[..])).unwrap();
    let proof = StarkProof::from_bytes(&data.proof_bytes).unwrap();

    // Verify execution
    match winterfell::verify::<ProcessorAir>(proof, pub_inputs) {
        Ok(_) => log("Execution verified"),
        Err(err) => log(format!("Failed to verify execution: {}", err).as_str()),
    }
}

#[derive(Serialize, Deserialize)]
struct ProofData {
    input_bytes: Vec<u8>,
    proof_bytes: Vec<u8>,
}


================================================
FILE: wasm/webpack.config.js
================================================
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const webpack = require('webpack');
const WasmPackPlugin = require("@wasm-tool/wasm-pack-plugin");

module.exports = {
    entry: './index.js',
    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: 'index.js',
    },
    plugins: [
        new HtmlWebpackPlugin(),
        new WasmPackPlugin({
            crateDirectory: path.resolve(__dirname, ".")
        }),
        // Have this example work in Edge which doesn't ship `TextEncoder` or
        // `TextDecoder` at this time.
        new webpack.ProvidePlugin({
          TextDecoder: ['text-encoding', 'TextDecoder'],
          TextEncoder: ['text-encoding', 'TextEncoder']
        })
    ],
    experiments: {
      asyncWebAssembly: true,
    },
    module: {
        rules: [
          {
            test: /\.bin/,
            type: 'asset/inline',
            generator: {
              dataUrl: content => {
                return content;
              }
            }
          }
        ],
    },
    mode: 'production',
    performance: {
      maxEntrypointSize: 2000000,
      maxAssetSize: 2000000,
    }
};

Download .txt
gitextract_qfi_vi0c/

├── .gitignore
├── Cargo.toml
├── LICENSE
├── README.md
├── air/
│   ├── Cargo.toml
│   └── src/
│       ├── constraints.rs
│       ├── frame.rs
│       ├── lib.rs
│       └── options.rs
├── cli/
│   ├── Cargo.toml
│   ├── README.md
│   └── src/
│       ├── cmd/
│       │   ├── mod.rs
│       │   ├── prove/
│       │   │   ├── args.rs
│       │   │   ├── mod.rs
│       │   │   └── prove.rs
│       │   └── verify.rs
│       ├── giza.rs
│       └── utils.rs
├── core/
│   ├── Cargo.toml
│   └── src/
│       ├── field/
│       │   ├── f252/
│       │   │   ├── mod.rs
│       │   │   └── tests.rs
│       │   └── mod.rs
│       ├── flags/
│       │   └── mod.rs
│       ├── inputs/
│       │   └── mod.rs
│       ├── lib.rs
│       └── word/
│           ├── helpers.rs
│           └── mod.rs
├── examples/
│   ├── Cargo.toml
│   └── src/
│       └── main.rs
├── program.json
├── prover/
│   ├── Cargo.toml
│   └── src/
│       └── lib.rs
├── runner/
│   ├── Cargo.toml
│   └── src/
│       ├── cairo_interop.rs
│       ├── errors.rs
│       ├── hints.rs
│       ├── lib.rs
│       ├── memory.rs
│       ├── runner.rs
│       └── trace.rs
├── rust-toolchain.toml
└── wasm/
    ├── .gitignore
    ├── Cargo.toml
    ├── index.js
    ├── package.json
    ├── src/
    │   └── lib.rs
    └── webpack.config.js
Download .txt
SYMBOL INDEX (455 symbols across 25 files)

FILE: air/src/constraints.rs
  type EvaluationResult (line 6) | pub trait EvaluationResult<E: FieldElement> {
    method evaluate_instr_constraints (line 7) | fn evaluate_instr_constraints(&mut self, frame: &MainEvaluationFrame<E>);
    method evaluate_operand_constraints (line 8) | fn evaluate_operand_constraints(&mut self, frame: &MainEvaluationFrame...
    method evaluate_register_constraints (line 9) | fn evaluate_register_constraints(&mut self, frame: &MainEvaluationFram...
    method evaluate_opcode_constraints (line 10) | fn evaluate_opcode_constraints(&mut self, frame: &MainEvaluationFrame<...
    method enforce_selector (line 11) | fn enforce_selector(&mut self, frame: &MainEvaluationFrame<E>);
  type AuxEvaluationResult (line 14) | pub trait AuxEvaluationResult<E: FieldElement, F: FieldElement + Extensi...
    method evaluate_memory_constraints (line 15) | fn evaluate_memory_constraints(
    method evaluate_range_check_constraints (line 21) | fn evaluate_range_check_constraints(
  constant INST (line 30) | const INST: usize = 16;
  constant DST_ADDR (line 31) | const DST_ADDR: usize = 17;
  constant OP0_ADDR (line 32) | const OP0_ADDR: usize = 18;
  constant OP1_ADDR (line 33) | const OP1_ADDR: usize = 19;
  constant NEXT_AP (line 34) | const NEXT_AP: usize = 20;
  constant NEXT_FP (line 35) | const NEXT_FP: usize = 21;
  constant NEXT_PC_1 (line 36) | const NEXT_PC_1: usize = 22;
  constant NEXT_PC_2 (line 37) | const NEXT_PC_2: usize = 23;
  constant T0 (line 38) | const T0: usize = 24;
  constant T1 (line 39) | const T1: usize = 25;
  constant MUL_1 (line 40) | const MUL_1: usize = 26;
  constant MUL_2 (line 41) | const MUL_2: usize = 27;
  constant CALL_1 (line 42) | const CALL_1: usize = 28;
  constant CALL_2 (line 43) | const CALL_2: usize = 29;
  constant ASSERT_EQ (line 44) | const ASSERT_EQ: usize = 30;
  constant A_M_PRIME (line 47) | const A_M_PRIME: Range<usize> = range(0, 4);
  constant V_M_PRIME (line 48) | const V_M_PRIME: Range<usize> = range(4, 4);
  constant P_M (line 49) | const P_M: Range<usize> = range(8, 4);
  constant A_RC_PRIME (line 50) | const A_RC_PRIME: Range<usize> = range(12, 3);
  constant P_RC (line 51) | const P_RC: Range<usize> = range(15, 3);
  constant TWO (line 53) | const TWO: Felt = Felt::TWO;
  function evaluate_instr_constraints (line 56) | fn evaluate_instr_constraints(&mut self, frame: &MainEvaluationFrame<E>) {
  function evaluate_operand_constraints (line 86) | fn evaluate_operand_constraints(&mut self, frame: &MainEvaluationFrame<E...
  function evaluate_register_constraints (line 105) | fn evaluate_register_constraints(&mut self, frame: &MainEvaluationFrame<...
  function evaluate_opcode_constraints (line 134) | fn evaluate_opcode_constraints(&mut self, frame: &MainEvaluationFrame<E>) {
  function enforce_selector (line 147) | fn enforce_selector(&mut self, frame: &MainEvaluationFrame<E>) {
  function evaluate_memory_constraints (line 160) | fn evaluate_memory_constraints(
  function evaluate_range_check_constraints (line 192) | fn evaluate_range_check_constraints(

FILE: air/src/frame.rs
  type MainEvaluationFrame (line 10) | pub struct MainEvaluationFrame<E: FieldElement> {
  function new (line 18) | fn new<A: Air>(air: &A) -> Self {
  function from_table (line 26) | fn from_table(table: Table<E>) -> Self {
  function read_from (line 33) | fn read_from<R: TableReader<E>>(
  function row (line 51) | fn row<'a>(&'a self, row_idx: usize) -> &'a [E] {
  function to_table (line 55) | fn to_table(&self) -> Table<E> {
  function offsets (line 59) | fn offsets() -> &'static [usize] {
  function current (line 65) | pub fn current(&'a self) -> MainFrameSegment<'a, E> {
  function next (line 68) | pub fn next(&'a self) -> MainFrameSegment<'a, E> {
  function segment (line 71) | pub fn segment(&'a self) -> MainFrameSegment<'a, E> {
  type MainFrameSegment (line 76) | pub struct MainFrameSegment<'a, E: FieldElement> {
  type DataSegment (line 81) | enum DataSegment {
  function new (line 93) | fn new(table: &'a Table<E>, row_start: usize) -> Self {
  function get (line 97) | fn get(&self, pos: usize, data_type: DataSegment) -> E {
  function get_virtual (line 112) | fn get_virtual(&self, idx: usize, offset: usize, width: usize) -> E {
  function res (line 125) | pub fn res(&self) -> E {
  function pc (line 129) | pub fn pc(&self) -> E {
  function ap (line 132) | pub fn ap(&self) -> E {
  function fp (line 135) | pub fn fp(&self) -> E {
  function dst_addr (line 139) | pub fn dst_addr(&self) -> E {
  function op0_addr (line 142) | pub fn op0_addr(&self) -> E {
  function op1_addr (line 145) | pub fn op1_addr(&self) -> E {
  function inst (line 149) | pub fn inst(&self) -> E {
  function dst (line 152) | pub fn dst(&self) -> E {
  function op0 (line 155) | pub fn op0(&self) -> E {
  function op1 (line 158) | pub fn op1(&self) -> E {
  function inst_size (line 162) | pub fn inst_size(&self) -> E {
  function t0 (line 166) | pub fn t0(&self) -> E {
  function t1 (line 169) | pub fn t1(&self) -> E {
  function mul (line 172) | pub fn mul(&self) -> E {
  function a_m (line 176) | pub fn a_m(&self, idx: usize) -> E {
  function v_m (line 179) | pub fn v_m(&self, idx: usize) -> E {
  function a_rc (line 183) | pub fn a_rc(&self, idx: usize) -> E {
  function selector (line 187) | pub fn selector(&self) -> E {
  function off_dst (line 193) | fn off_dst(&self) -> E {
  function off_op0 (line 197) | fn off_op0(&self) -> E {
  function off_op1 (line 201) | fn off_op1(&self) -> E {
  function flags (line 207) | fn flags(&self) -> Vec<E> {
  function flag_at (line 215) | fn flag_at(&self, pos: usize) -> E {
  type AuxEvaluationFrame (line 224) | pub struct AuxEvaluationFrame<E: FieldElement> {
  function new (line 232) | fn new<A: Air>(air: &A) -> Self {
  function from_table (line 240) | fn from_table(table: Table<E>) -> Self {
  function read_from (line 247) | fn read_from<R: TableReader<E>>(&mut self, data: R, step: usize, offset:...
  function row (line 259) | fn row<'a>(&'a self, row_idx: usize) -> &'a [E] {
  function to_table (line 263) | fn to_table(&self) -> Table<E> {
  function offsets (line 267) | fn offsets() -> &'static [usize] {
  function segment (line 273) | pub fn segment(&'a self) -> AuxFrameSegment<'a, E> {
  type AuxFrameSegment (line 278) | pub struct AuxFrameSegment<'a, E: FieldElement> {
  function new (line 284) | fn new(table: &'a Table<E>, row_idx: usize) -> Self {
  function get_virtual (line 290) | fn get_virtual(&self, idx: usize, offset: usize, width: usize) -> E {
  function a_m_prime (line 301) | pub fn a_m_prime(&self, idx: usize) -> E {
  function v_m_prime (line 304) | pub fn v_m_prime(&self, idx: usize) -> E {
  function p_m (line 307) | pub fn p_m(&self, idx: usize) -> E {
  function a_rc_prime (line 312) | pub fn a_rc_prime(&self, idx: usize) -> E {
  function p_rc (line 315) | pub fn p_rc(&self, idx: usize) -> E {

FILE: air/src/lib.rs
  type ProcessorAir (line 30) | pub struct ProcessorAir {
  type BaseField (line 36) | type BaseField = Felt;
  type PublicInputs (line 37) | type PublicInputs = PublicInputs;
  type Frame (line 38) | type Frame<E: FieldElement> = MainEvaluationFrame<E>;
  type AuxFrame (line 39) | type AuxFrame<E: FieldElement> = AuxEvaluationFrame<E>;
  method new (line 41) | fn new(trace_info: TraceInfo, pub_inputs: PublicInputs, options: WinterP...
  method get_assertions (line 107) | fn get_assertions(&self) -> Vec<Assertion<Felt>> {
  method get_aux_assertions (line 119) | fn get_aux_assertions<E: FieldElement + From<Self::BaseField>>(
  method evaluate_transition (line 148) | fn evaluate_transition<E: FieldElement + From<Felt>>(
  method evaluate_aux_transition (line 161) | fn evaluate_aux_transition<
  method context (line 176) | fn context(&self) -> &AirContext<Felt> {
  type PublicInputs (line 184) | pub struct PublicInputs {
    method new (line 195) | pub fn new(
  method write_into (line 219) | fn write_into<W: ByteWriter>(&self, target: &mut W) {
  method read_from (line 252) | fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, Deserializat...

FILE: air/src/options.rs
  type ProofOptions (line 6) | pub struct ProofOptions(WinterProofOptions);
    method new (line 9) | pub fn new(
    method with_proof_options (line 29) | pub fn with_proof_options(
    method into_inner (line 47) | pub fn into_inner(self) -> WinterProofOptions {
  method default (line 53) | fn default() -> Self {
  type Target (line 59) | type Target = WinterProofOptions;
  method deref (line 61) | fn deref(&self) -> &Self::Target {

FILE: cli/src/cmd/mod.rs
  type ProofData (line 7) | struct ProofData {

FILE: cli/src/cmd/prove/args.rs
  type ProveArgs (line 6) | pub struct ProveArgs {
  function parse_num_queries (line 74) | fn parse_num_queries(value: &str) -> Result<usize, Error> {
  function parse_blowup_factor (line 89) | fn parse_blowup_factor(value: &str) -> Result<usize, Error> {
  function parse_fri_folding_factor (line 114) | fn parse_fri_folding_factor(value: &str) -> Result<usize, Error> {
  function parse_fri_max_remainder_size (line 126) | fn parse_fri_max_remainder_size(value: &str) -> Result<usize, Error> {

FILE: cli/src/cmd/prove/prove.rs
  type ProveOutput (line 10) | pub struct ProveOutput {}
  type Error (line 13) | pub enum Error {}
  type Output (line 16) | type Output = Result<ProveOutput, Error>;
  method run (line 18) | fn run(self) -> Self::Output {

FILE: cli/src/cmd/verify.rs
  type VerifyOutput (line 12) | pub struct VerifyOutput {}
  type VerifyArgs (line 16) | pub struct VerifyArgs {
  type Error (line 26) | pub enum Error {}
  type Output (line 29) | type Output = Result<VerifyOutput, Error>;
  method run (line 31) | fn run(self) -> Self::Output {

FILE: cli/src/giza.rs
  type Opts (line 10) | pub struct Opts {
  type Subcommands (line 17) | pub enum Subcommands {
  function main (line 22) | fn main() {

FILE: cli/src/utils.rs
  type Cmd (line 2) | pub trait Cmd: clap::Parser + Sized {
    method run (line 5) | fn run(self) -> Self::Output;

FILE: core/src/field/f252/mod.rs
  type Fr (line 33) | struct Fr([u64; 4]);
    method from_raw (line 562) | pub fn from_raw(value: [u64; 4]) -> Self {
    method to_raw (line 566) | pub fn to_raw(&self) -> BigInt {
    method to_le_bytes (line 573) | pub fn to_le_bytes(&self) -> Vec<u8> {
  constant ELEMENT_BYTES (line 36) | const ELEMENT_BYTES: usize = core::mem::size_of::<Fr>();
  type BigInt (line 40) | pub struct BigInt(pub [u64; 4]);
    type Output (line 388) | type Output = BigInt;
    method shr (line 389) | fn shr(self, rhs: u32) -> BigInt {
    type Output (line 409) | type Output = BigInt;
    method shl (line 410) | fn shl(self, rhs: u32) -> BigInt {
    method from (line 495) | fn from(value: u128) -> Self {
    method from (line 504) | fn from(value: u64) -> Self {
    method from (line 511) | fn from(value: u32) -> Self {
    method from (line 518) | fn from(value: u16) -> Self {
    method from (line 525) | fn from(value: u8) -> Self {
    type Error (line 531) | type Error = ();
    method try_into (line 532) | fn try_into(self) -> Result<u64, Self::Error> {
    type Error (line 538) | type Error = ();
    method try_into (line 539) | fn try_into(self) -> Result<u16, Self::Error> {
    method to_le_bytes (line 545) | pub fn to_le_bytes(&self) -> Vec<u8> {
  type BaseElement (line 44) | pub struct BaseElement(Fr);
    constant TWO (line 94) | pub const TWO: Self = BaseElement(Fr([
    method from_raw (line 101) | pub fn from_raw(value: [u64; 4]) -> Self {
    method to_raw (line 105) | pub fn to_raw(&self) -> BigInt {
    method mul (line 232) | fn mul(a: [Self; 2], b: [Self; 2]) -> [Self; 2] {
    method mul_base (line 238) | fn mul_base(a: [Self; 2], b: Self) -> [Self; 2] {
    method frobenius (line 243) | fn frobenius(x: [Self; 2]) -> [Self; 2] {
    method mul (line 254) | fn mul(_a: [Self; 3], _b: [Self; 3]) -> [Self; 3] {
    method mul_base (line 259) | fn mul_base(_a: [Self; 3], _b: Self) -> [Self; 3] {
    method frobenius (line 264) | fn frobenius(_x: [Self; 3]) -> [Self; 3] {
    method is_supported (line 268) | fn is_supported() -> bool {
    method from (line 278) | fn from(value: u128) -> Self {
    method from (line 287) | fn from(value: u64) -> Self {
    method from (line 294) | fn from(value: u32) -> Self {
    method from (line 301) | fn from(value: u16) -> Self {
    method from (line 308) | fn from(value: u8) -> Self {
    method from (line 317) | fn from(bytes: [u64; 4]) -> Self {
    method from (line 326) | fn from(bytes: [u8; 32]) -> Self {
    type Error (line 338) | type Error = String;
    method try_from (line 343) | fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
  type PositiveInteger (line 47) | type PositiveInteger = BigInt;
  type BaseField (line 48) | type BaseField = Self;
  constant ZERO (line 50) | const ZERO: Self = BaseElement(Fr([0, 0, 0, 0]));
  constant ONE (line 51) | const ONE: Self = BaseElement(Fr(R.0));
  constant ELEMENT_BYTES (line 53) | const ELEMENT_BYTES: usize = ELEMENT_BYTES;
  constant IS_CANONICAL (line 55) | const IS_CANONICAL: bool = true;
  method inv (line 57) | fn inv(self) -> Self {
  method conjugate (line 61) | fn conjugate(&self) -> Self {
  method elements_as_bytes (line 65) | fn elements_as_bytes(elements: &[Self]) -> &[u8] {
  method bytes_as_elements (line 71) | unsafe fn bytes_as_elements(_bytes: &[u8]) -> Result<&[Self], Deserializ...
  method zeroed_vector (line 75) | fn zeroed_vector(n: usize) -> Vec<Self> {
  method as_base_elements (line 87) | fn as_base_elements(elements: &[Self]) -> &[Self::BaseField] {
  constant MODULUS (line 116) | const MODULUS: Self::PositiveInteger = BigInt([0x1, 0x0, 0x0, 0x8000_000...
  constant MODULUS_BITS (line 117) | const MODULUS_BITS: u32 = 252;
  constant GENERATOR (line 121) | const GENERATOR: Self = BaseElement(GENERATOR);
  constant TWO_ADICITY (line 125) | const TWO_ADICITY: u32 = 192;
  constant TWO_ADIC_ROOT_OF_UNITY (line 130) | const TWO_ADIC_ROOT_OF_UNITY: Self = BaseElement(ROOT_OF_UNITY);
  method get_modulus_le_bytes (line 132) | fn get_modulus_le_bytes() -> Vec<u8> {
  method as_int (line 138) | fn as_int(&self) -> Self::PositiveInteger {
  constant VALUE_SIZE (line 144) | const VALUE_SIZE: usize = Self::ELEMENT_BYTES;
  method from_random_bytes (line 146) | fn from_random_bytes(bytes: &[u8]) -> Option<Self> {
  method fmt (line 152) | fn fmt(&self, f: &mut Formatter) -> core::fmt::Result {
  type Output (line 161) | type Output = Self;
  method add (line 163) | fn add(self, rhs: Self) -> Self {
  method add_assign (line 169) | fn add_assign(&mut self, rhs: Self) {
  type Output (line 175) | type Output = Self;
  method sub (line 177) | fn sub(self, rhs: Self) -> Self {
  method sub_assign (line 183) | fn sub_assign(&mut self, rhs: Self) {
  type Output (line 189) | type Output = Self;
  method mul (line 191) | fn mul(self, rhs: Self) -> Self {
  method mul_assign (line 197) | fn mul_assign(&mut self, rhs: Self) {
  type Output (line 203) | type Output = Self;
  method div (line 205) | fn div(self, rhs: Self) -> Self {
  method div_assign (line 211) | fn div_assign(&mut self, rhs: Self) {
  type Output (line 217) | type Output = Self;
  method neg (line 219) | fn neg(self) -> Self {
  method as_bytes (line 354) | fn as_bytes(&self) -> &[u8] {
  method write_into (line 366) | fn write_into<W: ByteWriter>(&self, target: &mut W) {
  method read_from (line 372) | fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, Deserializat...
  type Output (line 395) | type Output = BigInt;
  function shr (line 396) | fn shr(self, rhs: u32) -> BigInt {
  method shr_assign (line 402) | fn shr_assign(&mut self, rhs: BigInt) {
  type Output (line 416) | type Output = BigInt;
  function shl (line 417) | fn shl(self, rhs: u32) -> BigInt {
  type Output (line 423) | type Output = Self;
  method bitand (line 424) | fn bitand(self, Self(rhs): Self) -> Self::Output {
  function shr_vartime (line 434) | fn shr_vartime(value: &BigInt, shift: usize) -> BigInt {
  function shl_vartime (line 467) | fn shl_vartime(value: &BigInt, n: usize) -> BigInt {
  method fmt (line 553) | fn fmt(&self, f: &mut Formatter) -> core::fmt::Result {
  function write_le_bytes (line 581) | fn write_le_bytes(value: [u64; 4], out: &mut [u8]) {
  function as_int (line 588) | fn as_int() {

FILE: core/src/flags/mod.rs
  constant NUM_FLAGS (line 7) | pub const NUM_FLAGS: usize = 16;
  constant POS_DST (line 9) | pub const POS_DST: usize = 0;
  constant POS_OP0 (line 11) | pub const POS_OP0: usize = 1;
  constant POS_OP1 (line 13) | pub const POS_OP1: usize = 2;
  constant POS_FLAGS (line 15) | pub const POS_FLAGS: usize = 48;
  constant DST_AP (line 18) | pub const DST_AP: u8 = 0;
  constant OP0_AP (line 21) | pub const OP0_AP: u8 = 0;
  constant OP1_DBL (line 24) | pub const OP1_DBL: u8 = 0;
  constant OP1_VAL (line 26) | pub const OP1_VAL: u8 = 1;
  constant OP1_FP (line 28) | pub const OP1_FP: u8 = 2;
  constant OP1_AP (line 30) | pub const OP1_AP: u8 = 4;
  constant RES_ONE (line 33) | pub const RES_ONE: u8 = 0;
  constant RES_ADD (line 35) | pub const RES_ADD: u8 = 1;
  constant RES_MUL (line 37) | pub const RES_MUL: u8 = 2;
  constant PC_SIZ (line 40) | pub const PC_SIZ: u8 = 0;
  constant PC_ABS (line 42) | pub const PC_ABS: u8 = 1;
  constant PC_REL (line 44) | pub const PC_REL: u8 = 2;
  constant PC_JNZ (line 46) | pub const PC_JNZ: u8 = 4;
  constant AP_Z2 (line 49) | pub const AP_Z2: u8 = 0;
  constant AP_ADD (line 51) | pub const AP_ADD: u8 = 1;
  constant AP_ONE (line 53) | pub const AP_ONE: u8 = 2;
  constant OPC_JMP_INC (line 56) | pub const OPC_JMP_INC: u8 = 0;
  constant OPC_CALL (line 58) | pub const OPC_CALL: u8 = 1;
  constant OPC_RET (line 60) | pub const OPC_RET: u8 = 2;
  constant OPC_AEQ (line 62) | pub const OPC_AEQ: u8 = 4;

FILE: core/src/inputs/mod.rs
  type ProgramInputs (line 2) | pub struct ProgramInputs {}

FILE: core/src/lib.rs
  constant FLAG_TRACE_OFFSET (line 36) | pub const FLAG_TRACE_OFFSET: usize = 0;
  constant FLAG_TRACE_WIDTH (line 37) | pub const FLAG_TRACE_WIDTH: usize = 16;
  constant FLAG_TRACE_RANGE (line 38) | pub const FLAG_TRACE_RANGE: Range<usize> = range(FLAG_TRACE_OFFSET, FLAG...
  constant RES_TRACE_OFFSET (line 40) | pub const RES_TRACE_OFFSET: usize = 16;
  constant RES_TRACE_WIDTH (line 41) | pub const RES_TRACE_WIDTH: usize = 1;
  constant RES_TRACE_RANGE (line 42) | pub const RES_TRACE_RANGE: Range<usize> = range(RES_TRACE_OFFSET, RES_TR...
  constant MEM_P_TRACE_OFFSET (line 44) | pub const MEM_P_TRACE_OFFSET: usize = 17;
  constant MEM_P_TRACE_WIDTH (line 45) | pub const MEM_P_TRACE_WIDTH: usize = 2;
  constant MEM_P_TRACE_RANGE (line 46) | pub const MEM_P_TRACE_RANGE: Range<usize> = range(MEM_P_TRACE_OFFSET, ME...
  constant MEM_A_TRACE_OFFSET (line 48) | pub const MEM_A_TRACE_OFFSET: usize = 19;
  constant MEM_A_TRACE_WIDTH (line 49) | pub const MEM_A_TRACE_WIDTH: usize = 4;
  constant MEM_A_TRACE_RANGE (line 50) | pub const MEM_A_TRACE_RANGE: Range<usize> = range(MEM_A_TRACE_OFFSET, ME...
  constant MEM_V_TRACE_OFFSET (line 52) | pub const MEM_V_TRACE_OFFSET: usize = 23;
  constant MEM_V_TRACE_WIDTH (line 53) | pub const MEM_V_TRACE_WIDTH: usize = 4;
  constant MEM_V_TRACE_RANGE (line 54) | pub const MEM_V_TRACE_RANGE: Range<usize> = range(MEM_V_TRACE_OFFSET, ME...
  constant OFF_X_TRACE_OFFSET (line 56) | pub const OFF_X_TRACE_OFFSET: usize = 27;
  constant OFF_X_TRACE_WIDTH (line 57) | pub const OFF_X_TRACE_WIDTH: usize = 3;
  constant OFF_X_TRACE_RANGE (line 58) | pub const OFF_X_TRACE_RANGE: Range<usize> = range(OFF_X_TRACE_OFFSET, OF...
  constant DERIVED_TRACE_OFFSET (line 60) | pub const DERIVED_TRACE_OFFSET: usize = 30;
  constant DERIVED_TRACE_WIDTH (line 61) | pub const DERIVED_TRACE_WIDTH: usize = 3;
  constant DERIVED_TRACE_RANGE (line 62) | pub const DERIVED_TRACE_RANGE: Range<usize> = range(DERIVED_TRACE_OFFSET...
  constant SELECTOR_TRACE_OFFSET (line 64) | pub const SELECTOR_TRACE_OFFSET: usize = 33;
  constant SELECTOR_TRACE_WIDTH (line 65) | pub const SELECTOR_TRACE_WIDTH: usize = 1;
  constant SELECTOR_TRACE_RANGE (line 66) | pub const SELECTOR_TRACE_RANGE: Range<usize> = range(SELECTOR_TRACE_OFFS...
  constant TRACE_WIDTH (line 68) | pub const TRACE_WIDTH: usize = 34;
  constant A_M_PRIME_OFFSET (line 79) | pub const A_M_PRIME_OFFSET: usize = 0;
  constant A_M_PRIME_WIDTH (line 80) | pub const A_M_PRIME_WIDTH: usize = 4;
  constant V_M_PRIME_OFFSET (line 82) | pub const V_M_PRIME_OFFSET: usize = 4;
  constant V_M_PRIME_WIDTH (line 83) | pub const V_M_PRIME_WIDTH: usize = 4;
  constant P_M_OFFSET (line 85) | pub const P_M_OFFSET: usize = 8;
  constant P_M_WIDTH (line 86) | pub const P_M_WIDTH: usize = 4;
  constant A_RC_PRIME_OFFSET (line 97) | pub const A_RC_PRIME_OFFSET: usize = 12;
  constant A_RC_PRIME_WIDTH (line 98) | pub const A_RC_PRIME_WIDTH: usize = 3;
  constant P_RC_OFFSET (line 100) | pub const P_RC_OFFSET: usize = 15;
  constant P_RC_WIDTH (line 101) | pub const P_RC_WIDTH: usize = 3;
  constant AP (line 105) | pub const AP: usize = MEM_P_TRACE_OFFSET;
  constant P_M_LAST (line 109) | pub const P_M_LAST: usize = P_M_OFFSET + P_M_WIDTH - 1;
  constant A_RC_PRIME_FIRST (line 110) | pub const A_RC_PRIME_FIRST: usize = A_RC_PRIME_OFFSET;
  constant A_RC_PRIME_LAST (line 111) | pub const A_RC_PRIME_LAST: usize = A_RC_PRIME_OFFSET + 2;
  function range (line 114) | pub const fn range(start: usize, len: usize) -> Range<usize> {
  type RegisterState (line 123) | pub struct RegisterState {
    method new (line 150) | pub fn new<T: Into<Felt>>(pc: T, ap: T, fp: T) -> Self {
  type InstructionState (line 132) | pub struct InstructionState {
    method new (line 161) | pub fn new(
  type Builtin (line 187) | pub enum Builtin {

FILE: core/src/word/helpers.rs
  type FieldHelpers (line 6) | pub trait FieldHelpers {
    method lsb (line 8) | fn lsb(self) -> u8;
    method chunk_u16 (line 11) | fn chunk_u16(self, pos: usize) -> Felt;
    method to_u64 (line 14) | fn to_u64(self) -> u64;
    method to_hex_le (line 17) | fn to_hex_le(self) -> String;
    method vec_to_field (line 20) | fn vec_to_field(vec: &[i128]) -> Vec<Felt>;
    method to_bits (line 23) | fn to_bits(self) -> Vec<bool>;
    method lsb (line 27) | fn lsb(self) -> u8 {
    method chunk_u16 (line 32) | fn chunk_u16(self, pos: usize) -> Felt {
    method to_u64 (line 39) | fn to_u64(self) -> u64 {
    method to_hex_le (line 49) | fn to_hex_le(self) -> String {
    method vec_to_field (line 55) | fn vec_to_field(vec: &[i128]) -> Vec<Felt> {
    method to_bits (line 67) | fn to_bits(self) -> Vec<bool> {
  function test_field_to_bits (line 86) | fn test_field_to_bits() {
  function test_field_to_chunks (line 93) | fn test_field_to_chunks() {

FILE: core/src/word/mod.rs
  type Word (line 11) | pub struct Word(Felt);
    method new (line 20) | pub fn new(word: Felt) -> Word {
    method word (line 25) | pub fn word(&self) -> Felt {
    method off_dst (line 154) | fn off_dst(&self) -> Felt {
    method off_op0 (line 159) | fn off_op0(&self) -> Felt {
    method off_op1 (line 164) | fn off_op1(&self) -> Felt {
    method flags (line 171) | fn flags(&self) -> Vec<Felt> {
    method flag_at (line 180) | fn flag_at(&self, pos: usize) -> Felt {
    method dst_reg (line 186) | fn dst_reg(&self) -> u8 {
    method op0_reg (line 191) | fn op0_reg(&self) -> u8 {
    method op1_src (line 196) | fn op1_src(&self) -> u8 {
    method res_log (line 201) | fn res_log(&self) -> u8 {
    method pc_up (line 206) | fn pc_up(&self) -> u8 {
    method ap_up (line 211) | fn ap_up(&self) -> u8 {
    method opcode (line 216) | fn opcode(&self) -> u8 {
  function bias (line 14) | pub fn bias<E: FieldElement>(offset: E) -> E {
  type OffsetDecomposition (line 30) | pub trait OffsetDecomposition<F> {
    method off_dst (line 32) | fn off_dst(&self) -> F;
    method off_op0 (line 35) | fn off_op0(&self) -> F;
    method off_op1 (line 38) | fn off_op1(&self) -> F;
  type FlagDecomposition (line 42) | pub trait FlagDecomposition<F> {
    method flags (line 44) | fn flags(&self) -> Vec<F>;
    method flag_at (line 47) | fn flag_at(&self, pos: usize) -> F;
    method f_dst_fp (line 50) | fn f_dst_fp(&self) -> F {
    method f_op0_fp (line 55) | fn f_op0_fp(&self) -> F {
    method f_op1_val (line 60) | fn f_op1_val(&self) -> F {
    method f_op1_fp (line 65) | fn f_op1_fp(&self) -> F {
    method f_op1_ap (line 70) | fn f_op1_ap(&self) -> F {
    method f_res_add (line 75) | fn f_res_add(&self) -> F {
    method f_res_mul (line 80) | fn f_res_mul(&self) -> F {
    method f_pc_abs (line 85) | fn f_pc_abs(&self) -> F {
    method f_pc_rel (line 90) | fn f_pc_rel(&self) -> F {
    method f_pc_jnz (line 95) | fn f_pc_jnz(&self) -> F {
    method f_ap_add (line 100) | fn f_ap_add(&self) -> F {
    method f_ap_one (line 105) | fn f_ap_one(&self) -> F {
    method f_opc_call (line 110) | fn f_opc_call(&self) -> F {
    method f_opc_ret (line 115) | fn f_opc_ret(&self) -> F {
    method f_opc_aeq (line 120) | fn f_opc_aeq(&self) -> F {
    method f15 (line 125) | fn f15(&self) -> F {
  type FlagGroupDecomposition (line 130) | pub trait FlagGroupDecomposition<F> {
    method dst_reg (line 132) | fn dst_reg(&self) -> u8;
    method op0_reg (line 135) | fn op0_reg(&self) -> u8;
    method op1_src (line 138) | fn op1_src(&self) -> u8;
    method res_log (line 141) | fn res_log(&self) -> u8;
    method pc_up (line 144) | fn pc_up(&self) -> u8;
    method ap_up (line 147) | fn ap_up(&self) -> u8;
    method opcode (line 150) | fn opcode(&self) -> u8;
  function test_biased (line 227) | fn test_biased() {

FILE: examples/src/main.rs
  function main (line 5) | fn main() {

FILE: prover/src/lib.rs
  function prove_trace (line 17) | pub fn prove_trace(
  type ExecutionProver (line 30) | pub struct ExecutionProver {
    method new (line 35) | pub fn new(options: ProofOptions) -> Self {
  type BaseField (line 41) | type BaseField = Felt;
  type Air (line 42) | type Air = ProcessorAir;
  type Trace (line 43) | type Trace = ExecutionTrace;
  method options (line 45) | fn options(&self) -> &prover::ProofOptions {
  method get_pub_inputs (line 49) | fn get_pub_inputs(&self, trace: &ExecutionTrace) -> PublicInputs {

FILE: runner/src/cairo_interop.rs
  type CompiledProgram (line 15) | struct CompiledProgram {
  function read_trace_bin (line 23) | pub fn read_trace_bin(path: &PathBuf) -> Vec<RegisterState> {
  function read_memory_bin (line 54) | pub fn read_memory_bin(mem_path: &PathBuf, program_path: &PathBuf) -> Me...
  function read_builtins (line 86) | pub fn read_builtins(program_path: &PathBuf, output_len: Option<u64>) ->...
  function print_registers (line 102) | fn print_registers(reg: &[RegisterState]) {
  function print_memory (line 108) | fn print_memory(mem: &Memory) {
  function test_trace_bin (line 123) | fn test_trace_bin() {
  function test_memory_bin (line 129) | fn test_memory_bin() {

FILE: runner/src/errors.rs
  type ExecutionError (line 4) | pub enum ExecutionError {

FILE: runner/src/hints.rs
  type HintManager (line 13) | pub struct HintManager {
    method push_hint (line 18) | pub fn push_hint(&mut self, pc: u64, hint: Hint) {
    method get_hints (line 21) | pub fn get_hints(&self, pc: Felt) -> Option<&Vec<Hint>> {
  type Hint (line 28) | pub struct Hint {
    method new (line 35) | pub fn new(
    method exec (line 75) | pub fn exec(&self, step: &Step) -> PyResult<ExecutionEffect> {
  type FlowTrackingData (line 49) | pub struct FlowTrackingData {
  type ApTracking (line 55) | pub struct ApTracking {
  type MemoryUpdate (line 61) | pub struct MemoryUpdate(pub Vec<(u64, Word)>);
    method extract (line 121) | fn extract(dict: &PyAny) -> PyResult<Self> {
  type ExecutionEffect (line 65) | pub struct ExecutionEffect {
    method from_locals (line 102) | fn from_locals(locals: &PyDict) -> PyResult<ExecutionEffect> {
  method to_object (line 134) | fn to_object(&self, py: Python) -> PyObject {
  function test_hint_execution (line 146) | fn test_hint_execution() {

FILE: runner/src/memory.rs
  type Memory (line 12) | pub struct Memory {
    type Output (line 20) | type Output = Option<Word>;
    method index (line 21) | fn index(&self, idx: Felt) -> &Self::Output {
    method index_mut (line 28) | fn index_mut(&mut self, idx: Felt) -> &mut Self::Output {
    method new (line 53) | pub fn new(input: Vec<Felt>) -> Memory {
    method get_codelen (line 64) | pub fn get_codelen(&self) -> usize {
    method set_codelen (line 69) | pub fn set_codelen(&mut self, len: usize) {
    method size (line 74) | pub fn size(&self) -> u64 {
    method resize (line 79) | fn resize(&mut self, addr: u64) {
    method write (line 86) | pub fn write(&mut self, addr: Felt, elem: Felt) {
    method write_pub (line 91) | pub fn write_pub(&mut self, addr: Felt, elem: Felt) {
    method read (line 97) | pub fn read(&self, addr: Felt) -> Option<Felt> {
    method get_holes (line 105) | pub fn get_holes(&self, vec: Vec<Felt>) -> Vec<Felt> {
  method fmt (line 36) | fn fmt(&self, f: &mut Formatter<'_>) -> Result {
  function test_cairo_bytecode (line 134) | fn test_cairo_bytecode() {

FILE: runner/src/runner.rs
  type Step (line 12) | pub struct Step<'a> {
  function new (line 22) | pub fn new(mem: &'a Memory, ptrs: RegisterState) -> Step<'a> {
  function execute (line 31) | pub fn execute(&mut self, write: bool) -> InstructionState {
  function set_hint_manager (line 75) | fn set_hint_manager(&mut self, hints: &'a HintManager) {
  function execute_hints (line 80) | fn execute_hints(&mut self) {
  function apply_hint_effects (line 90) | fn apply_hint_effects(&mut self, res: HintExecutionEffect) {
  function inst (line 102) | fn inst(&mut self) -> Word {
  function set_op0 (line 108) | fn set_op0(&mut self) -> (Felt, Option<Felt>) {
  function set_op1 (line 122) | fn set_op1(&mut self, op0: Option<Felt>) -> (Felt, Option<Felt>, Felt) {
  function set_res (line 142) | fn set_res(&mut self, op0: Option<Felt>, op1: Option<Felt>, dst: Option<...
  function set_dst (line 194) | fn set_dst(&mut self) -> (Felt, Option<Felt>) {
  function next_pc (line 208) | fn next_pc(
  function next_apfp (line 243) | fn next_apfp(
  type State (line 360) | pub struct State {
    method new (line 370) | pub fn new(init_trace_len: usize) -> Self {
    method set_register_state (line 411) | pub fn set_register_state(&mut self, step: usize, s: RegisterState) {
    method set_instruction_state (line 417) | pub fn set_instruction_state(&mut self, step: usize, s: InstructionSta...
  type Program (line 448) | pub struct Program<'a> {
  function new (line 467) | pub fn new(mem: &mut Memory, pc: u64, ap: u64, hints: Option<HintManager...
  function new (line 479) | pub fn new(mem: &mut Memory, pc: u64, ap: u64) -> Program {
  function get_steps (line 490) | pub fn get_steps(&self) -> usize {
  function get_final (line 495) | pub fn get_final(&self) -> RegisterState {
  function execute (line 501) | pub fn execute(&mut self) -> Result<ExecutionTrace, ExecutionError> {

FILE: runner/src/trace.rs
  type ExecutionTrace (line 17) | pub struct ExecutionTrace {
    method new (line 101) | pub(super) fn new(
    method from_file (line 217) | pub fn from_file(
    method get_program_mem (line 247) | pub fn get_program_mem(&self) -> (Vec<u64>, Vec<Option<Word>>) {
    method get_output_mem (line 254) | pub fn get_output_mem(&self) -> (Vec<u64>, Vec<Option<Word>>) {
    method get_public_mem (line 274) | pub fn get_public_mem(&self) -> (Vec<u64>, Vec<Option<Word>>) {
  type VirtualColumn (line 29) | struct VirtualColumn<'a, E: FieldElement> {
  function new (line 34) | fn new(subcols: &'a [Vec<E>]) -> Self {
  function to_column (line 40) | fn to_column(&self) -> Vec<E> {
  function to_columns (line 52) | fn to_columns(&self, num_rows: &[usize]) -> Vec<Vec<E>> {
  type Layouter (line 65) | struct Layouter<'a, E: FieldElement> {
  function new (line 71) | fn new(columns: &'a mut Vec<Vec<E>>, frame_len: usize) -> Self {
  function add_columns (line 78) | fn add_columns(&mut self, subcols: &[Vec<E>], chunk_size: Option<usize>) {
  function resize_all (line 94) | fn resize_all(&mut self) {
  type BaseField (line 284) | type BaseField = Felt;
  method layout (line 286) | fn layout(&self) -> &TraceLayout {
  method length (line 290) | fn length(&self) -> usize {
  method meta (line 294) | fn meta(&self) -> &[u8] {
  method main_segment (line 298) | fn main_segment(&self) -> &Matrix<Felt> {
  method build_aux_segment (line 302) | fn build_aux_segment<E>(
  function build_aux_segment_mem (line 319) | fn build_aux_segment_mem<E>(trace: &ExecutionTrace, rand_elements: &[E])...
  function build_aux_segment_rc (line 385) | fn build_aux_segment_rc<E>(trace: &ExecutionTrace, rand_elements: &[E]) ...
  function resize_to_pow2 (line 423) | fn resize_to_pow2<E: FieldElement>(columns: &mut [Vec<E>]) {

FILE: wasm/src/lib.rs
  function log (line 12) | fn log(s: &str);
  function verify (line 16) | pub fn verify(buffer: &Uint8Array) {
  type ProofData (line 31) | struct ProofData {
Condensed preview — 47 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (154K chars).
[
  {
    "path": ".gitignore",
    "chars": 40,
    "preview": "tmp/\ntarget/\nCargo.lock\n*.sw*\n.DS_Store\n"
  },
  {
    "path": "Cargo.toml",
    "chars": 101,
    "preview": "[workspace]\nmembers = [\n  \"air\",\n  \"core\",\n  \"prover\",\n  \"runner\",\n  \"examples\",\n  \"cli\",\n  \"wasm\"\n]\n"
  },
  {
    "path": "LICENSE",
    "chars": 10847,
    "preview": "                              Apache License\n                        Version 2.0, January 2004\n                     http"
  },
  {
    "path": "README.md",
    "chars": 2270,
    "preview": "## Overview\n\nGiza leverages the Winterfell library to prove and verify the execution of programs running on the Cairo VM"
  },
  {
    "path": "air/Cargo.toml",
    "chars": 466,
    "preview": "[package]\nname = \"giza-air\"\nversion = \"0.1.0\"\nedition = \"2018\"\n\n[dependencies]\nwinter-air = { package = \"winter-air\", gi"
  },
  {
    "path": "air/src/constraints.rs",
    "chars": 8092,
    "preview": "use super::{AuxEvaluationFrame, AuxTraceRandElements, MainEvaluationFrame};\nuse giza_core::{\n    range, ExtensionOf, Fel"
  },
  {
    "path": "air/src/frame.rs",
    "chars": 9347,
    "preview": "use super::FieldElement;\nuse giza_core::{flags::*, *};\nuse winter_air::{Air, EvaluationFrame, Table};\nuse winter_utils::"
  },
  {
    "path": "air/src/lib.rs",
    "chars": 10744,
    "preview": "#![feature(generic_associated_types)]\n\nuse giza_core::{\n    Builtin, ExtensionOf, Felt, FieldElement, RegisterState, Wor"
  },
  {
    "path": "air/src/options.rs",
    "chars": 1676,
    "preview": "use core::ops::Deref;\nuse winter_air::{FieldExtension, HashFunction, ProofOptions as WinterProofOptions};\n\n/// TODO: add"
  },
  {
    "path": "cli/Cargo.toml",
    "chars": 832,
    "preview": "[package]\nname = \"giza-cli\"\nversion = \"0.1.0\"\nedition = \"2021\"\nrust-version = \"1.57\"\n\n[dependencies]\nclap = { version = "
  },
  {
    "path": "cli/README.md",
    "chars": 108,
    "preview": "giza-cli\n========\n\n## Commands\n\n```\n# Generate a proof\ngiza prove --trace ./trace.bin --output proof.bin\n```"
  },
  {
    "path": "cli/src/cmd/mod.rs",
    "chars": 177,
    "preview": "use serde::{Deserialize, Serialize};\n\npub mod prove;\npub mod verify;\n\n#[derive(Serialize, Deserialize)]\nstruct ProofData"
  },
  {
    "path": "cli/src/cmd/prove/args.rs",
    "chars": 4059,
    "preview": "use clap::{Error, ErrorKind, Parser, ValueHint};\nuse std::path::PathBuf;\n\n#[derive(Parser, Debug)]\n#[clap(author, versio"
  },
  {
    "path": "cli/src/cmd/prove/mod.rs",
    "chars": 47,
    "preview": "mod args;\nmod prove;\n\npub use args::ProveArgs;\n"
  },
  {
    "path": "cli/src/cmd/prove/prove.rs",
    "chars": 1339,
    "preview": "use std::fs::File;\nuse std::io::Write;\n\nuse super::ProveArgs;\nuse crate::{cmd::ProofData, utils::Cmd};\nuse air::ProofOpt"
  },
  {
    "path": "cli/src/cmd/verify.rs",
    "chars": 1373,
    "preview": "use std::fs::File;\nuse std::io::Read;\nuse std::path::PathBuf;\n\nuse super::ProofData;\nuse crate::utils::Cmd;\nuse air::{Pr"
  },
  {
    "path": "cli/src/giza.rs",
    "chars": 693,
    "preview": "pub mod cmd;\nmod utils;\n\nuse crate::utils::Cmd;\nuse clap::{Parser, Subcommand};\nuse cmd::{prove::ProveArgs, verify::Veri"
  },
  {
    "path": "cli/src/utils.rs",
    "chars": 130,
    "preview": "/// Common trait for all cli commands\npub trait Cmd: clap::Parser + Sized {\n    type Output;\n\n    fn run(self) -> Self::"
  },
  {
    "path": "core/Cargo.toml",
    "chars": 463,
    "preview": "[package]\nname = \"giza-core\"\nversion = \"0.1.0\"\nedition = \"2021\"\nrust-version = \"1.57\"\n\n[dependencies]\nmath = { package ="
  },
  {
    "path": "core/src/field/f252/mod.rs",
    "chars": 16427,
    "preview": "//! An implementation of the 252-bit STARK-friendly prime field chosen by Starkware\n//! with modulus $2^{251} + 17 \\cdot"
  },
  {
    "path": "core/src/field/f252/tests.rs",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "core/src/field/mod.rs",
    "chars": 14,
    "preview": "pub mod f252;\n"
  },
  {
    "path": "core/src/flags/mod.rs",
    "chars": 2026,
    "preview": "// Modified from https://github.com/o1-labs/proof-systems\n\n//! Definition of some constants for easier readability of th"
  },
  {
    "path": "core/src/inputs/mod.rs",
    "chars": 47,
    "preview": "#[derive(Default)]\npub struct ProgramInputs {}\n"
  },
  {
    "path": "core/src/lib.rs",
    "chars": 5540,
    "preview": "#![feature(array_chunks)]\n\npub use core::ops::Range;\n\npub use math::{ExtensionOf, FieldElement, StarkField};\n\npub mod wo"
  },
  {
    "path": "core/src/word/helpers.rs",
    "chars": 2713,
    "preview": "// Modified from https://github.com/o1-labs/proof-systems\n\nuse super::{super::StarkField, Felt};\n//use winter_utils::AsB"
  },
  {
    "path": "core/src/word/mod.rs",
    "chars": 6329,
    "preview": "// Modified from https://github.com/o1-labs/proof-systems\n\nuse super::{Felt, FieldElement};\nuse crate::flags::*;\n\nmod he"
  },
  {
    "path": "examples/Cargo.toml",
    "chars": 749,
    "preview": "[package]\nname = \"examples\"\nversion = \"0.1.0\"\nedition = \"2021\"\nrust-version = \"1.57\"\n\n[[bin]]\nname = \"giza-examples\"\npat"
  },
  {
    "path": "examples/src/main.rs",
    "chars": 2324,
    "preview": "use air::{ProcessorAir, ProofOptions};\nuse giza_core::Felt;\nuse runner::{Memory, Program};\n\nfn main() {\n    //  %builtin"
  },
  {
    "path": "program.json",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "prover/Cargo.toml",
    "chars": 570,
    "preview": "[package]\nname = \"giza-prover\"\nversion = \"0.1.0\"\nedition = \"2021\"\nrust-version = \"1.57\"\n\n[dependencies]\nair = { package "
  },
  {
    "path": "prover/src/lib.rs",
    "chars": 2302,
    "preview": "use air::{ProcessorAir, PublicInputs};\nuse giza_core::{Felt, RegisterState, MEM_A_TRACE_OFFSET, MEM_P_TRACE_OFFSET};\nuse"
  },
  {
    "path": "runner/Cargo.toml",
    "chars": 818,
    "preview": "[package]\nname = \"giza-runner\"\nversion = \"0.1.0\"\nedition = \"2021\"\nrust-version = \"1.57\"\n\n[lib]\nbench = false\ndoctest = f"
  },
  {
    "path": "runner/src/cairo_interop.rs",
    "chars": 4272,
    "preview": "/// Code for parsing the outputs of Starkware's cairo-runner.\n/// Note the following:\n/// - Field elements are encoded i"
  },
  {
    "path": "runner/src/errors.rs",
    "chars": 105,
    "preview": "use winterfell::ProverError;\n\n#[derive(Debug)]\npub enum ExecutionError {\n    ProverError(ProverError),\n}\n"
  },
  {
    "path": "runner/src/hints.rs",
    "chars": 4629,
    "preview": "use crate::memory::Memory;\nuse crate::runner::Step;\nuse giza_core::{Felt, StarkField, Word};\n\nuse pyo3::conversion::{Fro"
  },
  {
    "path": "runner/src/lib.rs",
    "chars": 232,
    "preview": "pub mod memory;\npub use memory::Memory;\n\npub mod runner;\npub use runner::Program;\n\n#[cfg(feature = \"hints\")]\npub mod hin"
  },
  {
    "path": "runner/src/memory.rs",
    "chars": 5128,
    "preview": "// Modified from https://github.com/o1-labs/proof-systems\n\nuse std::convert::TryInto;\nuse std::fmt::{Display, Formatter,"
  },
  {
    "path": "runner/src/runner.rs",
    "chars": 20325,
    "preview": "// Modified from https://github.com/o1-labs/proof-systems\n\nuse crate::errors::ExecutionError;\nuse crate::memory::Memory;"
  },
  {
    "path": "runner/src/trace.rs",
    "chars": 15687,
    "preview": "use crate::cairo_interop::{read_builtins, read_memory_bin, read_trace_bin};\nuse crate::memory::Memory;\nuse crate::runner"
  },
  {
    "path": "rust-toolchain.toml",
    "chars": 32,
    "preview": "[toolchain]\nchannel = \"nightly\"\n"
  },
  {
    "path": "wasm/.gitignore",
    "chars": 36,
    "preview": "node_modules/\npkg/\ndist/\noutput.bin\n"
  },
  {
    "path": "wasm/Cargo.toml",
    "chars": 856,
    "preview": "[package]\nname = \"giza-wasm\"\nversion = \"0.1.0\"\nedition = \"2021\"\nrust-version = \"1.57\"\n\n[lib]\ncrate-type = [\"cdylib\"]\n\n[d"
  },
  {
    "path": "wasm/index.js",
    "chars": 326,
    "preview": "// Note that a dynamic `import` statement here is required due to\n// webpack/webpack#6615, but in theory `import { greet"
  },
  {
    "path": "wasm/package.json",
    "chars": 311,
    "preview": "{\n  \"scripts\": {\n    \"build\": \"webpack\",\n    \"serve\": \"webpack-dev-server\"\n  },\n  \"devDependencies\": {\n    \"@wasm-tool/w"
  },
  {
    "path": "wasm/src/lib.rs",
    "chars": 987,
    "preview": "use air::{ProcessorAir, PublicInputs};\nuse serde::{Deserialize, Serialize};\nuse winter_utils::{Deserializable, SliceRead"
  },
  {
    "path": "wasm/webpack.config.js",
    "chars": 1189,
    "preview": "const path = require('path');\nconst HtmlWebpackPlugin = require('html-webpack-plugin');\nconst webpack = require('webpack"
  }
]

About this extraction

This page contains the full source code of the maxgillett/giza GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 47 files (143.3 KB), approximately 38.8k tokens, and a symbol index with 455 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!