[
  {
    "path": ".gitignore",
    "content": "tmp/\ntarget/\nCargo.lock\n*.sw*\n.DS_Store\n"
  },
  {
    "path": "Cargo.toml",
    "content": "[workspace]\nmembers = [\n  \"air\",\n  \"core\",\n  \"prover\",\n  \"runner\",\n  \"examples\",\n  \"cli\",\n  \"wasm\"\n]\n"
  },
  {
    "path": "LICENSE",
    "content": "                              Apache License\n                        Version 2.0, January 2004\n                     http://www.apache.org/licenses/\n\nTERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n1. Definitions.\n\n   \"License\" shall mean the terms and conditions for use, reproduction,\n   and distribution as defined by Sections 1 through 9 of this document.\n\n   \"Licensor\" shall mean the copyright owner or entity authorized by\n   the copyright owner that is granting the License.\n\n   \"Legal Entity\" shall mean the union of the acting entity and all\n   other entities that control, are controlled by, or are under common\n   control with that entity. For the purposes of this definition,\n   \"control\" means (i) the power, direct or indirect, to cause the\n   direction or management of such entity, whether by contract or\n   otherwise, or (ii) ownership of fifty percent (50%) or more of the\n   outstanding shares, or (iii) beneficial ownership of such entity.\n\n   \"You\" (or \"Your\") shall mean an individual or Legal Entity\n   exercising permissions granted by this License.\n\n   \"Source\" form shall mean the preferred form for making modifications,\n   including but not limited to software source code, documentation\n   source, and configuration files.\n\n   \"Object\" form shall mean any form resulting from mechanical\n   transformation or translation of a Source form, including but\n   not limited to compiled object code, generated documentation,\n   and conversions to other media types.\n\n   \"Work\" shall mean the work of authorship, whether in Source or\n   Object form, made available under the License, as indicated by a\n   copyright notice that is included in or attached to the work\n   (an example is provided in the Appendix below).\n\n   \"Derivative Works\" shall mean any work, whether in Source or Object\n   form, that is based on (or derived from) the Work and for which the\n   editorial revisions, annotations, elaborations, or other modifications\n   represent, as a whole, an original work of authorship. For the purposes\n   of this License, Derivative Works shall not include works that remain\n   separable from, or merely link (or bind by name) to the interfaces of,\n   the Work and Derivative Works thereof.\n\n   \"Contribution\" shall mean any work of authorship, including\n   the original version of the Work and any modifications or additions\n   to that Work or Derivative Works thereof, that is intentionally\n   submitted to Licensor for inclusion in the Work by the copyright owner\n   or by an individual or Legal Entity authorized to submit on behalf of\n   the copyright owner. For the purposes of this definition, \"submitted\"\n   means any form of electronic, verbal, or written communication sent\n   to the Licensor or its representatives, including but not limited to\n   communication on electronic mailing lists, source code control systems,\n   and issue tracking systems that are managed by, or on behalf of, the\n   Licensor for the purpose of discussing and improving the Work, but\n   excluding communication that is conspicuously marked or otherwise\n   designated in writing by the copyright owner as \"Not a Contribution.\"\n\n   \"Contributor\" shall mean Licensor and any individual or Legal Entity\n   on behalf of whom a Contribution has been received by Licensor and\n   subsequently incorporated within the Work.\n\n2. Grant of Copyright License. Subject to the terms and conditions of\n   this License, each Contributor hereby grants to You a perpetual,\n   worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n   copyright license to reproduce, prepare Derivative Works of,\n   publicly display, publicly perform, sublicense, and distribute the\n   Work and such Derivative Works in Source or Object form.\n\n3. Grant of Patent License. Subject to the terms and conditions of\n   this License, each Contributor hereby grants to You a perpetual,\n   worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n   (except as stated in this section) patent license to make, have made,\n   use, offer to sell, sell, import, and otherwise transfer the Work,\n   where such license applies only to those patent claims licensable\n   by such Contributor that are necessarily infringed by their\n   Contribution(s) alone or by combination of their Contribution(s)\n   with the Work to which such Contribution(s) was submitted. If You\n   institute patent litigation against any entity (including a\n   cross-claim or counterclaim in a lawsuit) alleging that the Work\n   or a Contribution incorporated within the Work constitutes direct\n   or contributory patent infringement, then any patent licenses\n   granted to You under this License for that Work shall terminate\n   as of the date such litigation is filed.\n\n4. Redistribution. You may reproduce and distribute copies of the\n   Work or Derivative Works thereof in any medium, with or without\n   modifications, and in Source or Object form, provided that You\n   meet the following conditions:\n\n   (a) You must give any other recipients of the Work or\n       Derivative Works a copy of this License; and\n\n   (b) You must cause any modified files to carry prominent notices\n       stating that You changed the files; and\n\n   (c) You must retain, in the Source form of any Derivative Works\n       that You distribute, all copyright, patent, trademark, and\n       attribution notices from the Source form of the Work,\n       excluding those notices that do not pertain to any part of\n       the Derivative Works; and\n\n   (d) If the Work includes a \"NOTICE\" text file as part of its\n       distribution, then any Derivative Works that You distribute must\n       include a readable copy of the attribution notices contained\n       within such NOTICE file, excluding those notices that do not\n       pertain to any part of the Derivative Works, in at least one\n       of the following places: within a NOTICE text file distributed\n       as part of the Derivative Works; within the Source form or\n       documentation, if provided along with the Derivative Works; or,\n       within a display generated by the Derivative Works, if and\n       wherever such third-party notices normally appear. The contents\n       of the NOTICE file are for informational purposes only and\n       do not modify the License. You may add Your own attribution\n       notices within Derivative Works that You distribute, alongside\n       or as an addendum to the NOTICE text from the Work, provided\n       that such additional attribution notices cannot be construed\n       as modifying the License.\n\n   You may add Your own copyright statement to Your modifications and\n   may provide additional or different license terms and conditions\n   for use, reproduction, or distribution of Your modifications, or\n   for any such Derivative Works as a whole, provided Your use,\n   reproduction, and distribution of the Work otherwise complies with\n   the conditions stated in this License.\n\n5. Submission of Contributions. Unless You explicitly state otherwise,\n   any Contribution intentionally submitted for inclusion in the Work\n   by You to the Licensor shall be under the terms and conditions of\n   this License, without any additional terms or conditions.\n   Notwithstanding the above, nothing herein shall supersede or modify\n   the terms of any separate license agreement you may have executed\n   with Licensor regarding such Contributions.\n\n6. Trademarks. This License does not grant permission to use the trade\n   names, trademarks, service marks, or product names of the Licensor,\n   except as required for reasonable and customary use in describing the\n   origin of the Work and reproducing the content of the NOTICE file.\n\n7. Disclaimer of Warranty. Unless required by applicable law or\n   agreed to in writing, Licensor provides the Work (and each\n   Contributor provides its Contributions) on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n   implied, including, without limitation, any warranties or conditions\n   of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n   PARTICULAR PURPOSE. You are solely responsible for determining the\n   appropriateness of using or redistributing the Work and assume any\n   risks associated with Your exercise of permissions under this License.\n\n8. Limitation of Liability. In no event and under no legal theory,\n   whether in tort (including negligence), contract, or otherwise,\n   unless required by applicable law (such as deliberate and grossly\n   negligent acts) or agreed to in writing, shall any Contributor be\n   liable to You for damages, including any direct, indirect, special,\n   incidental, or consequential damages of any character arising as a\n   result of this License or out of the use or inability to use the\n   Work (including but not limited to damages for loss of goodwill,\n   work stoppage, computer failure or malfunction, or any and all\n   other commercial damages or losses), even if such Contributor\n   has been advised of the possibility of such damages.\n\n9. Accepting Warranty or Additional Liability. While redistributing\n   the Work or Derivative Works thereof, You may choose to offer,\n   and charge a fee for, acceptance of support, warranty, indemnity,\n   or other liability obligations and/or rights consistent with this\n   License. However, in accepting such obligations, You may act only\n   on Your own behalf and on Your sole responsibility, not on behalf\n   of any other Contributor, and only if You agree to indemnify,\n   defend, and hold each Contributor harmless for any liability\n   incurred by, or claims asserted against, such Contributor by reason\n   of your accepting any such warranty or additional liability.\n\nEND OF TERMS AND CONDITIONS\n\nAPPENDIX: How to apply the Apache License to your work.\n\n   To apply the Apache License to your work, attach the following\n   boilerplate notice, with the fields enclosed by brackets \"[]\"\n   replaced with your own identifying information. (Don't include\n   the brackets!)  The text should be enclosed in the appropriate\n   comment syntax for the file format. We also recommend that a\n   file or class name and description of purpose be included on the\n   same \"printed page\" as the copyright notice for easier\n   identification within third-party archives.\n\nCopyright [yyyy] [name of copyright owner]\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n\thttp://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n"
  },
  {
    "path": "README.md",
    "content": "## Overview\n\nGiza leverages the Winterfell library to prove and verify the execution of programs running on the Cairo VM.\n\n## Usage instructions\n\nGiza 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.\n\nThe 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.\n\n### Mode 1: Supply a trace to the CLI\n\nAssuming a compiled Cairo program `program.json`, the following steps can be taken to construct a proof:\n\n1. Install the Giza CLI using nightly Rust: `cargo install --path cli`\n2. 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).\n3. Construct the proof: `giza prove --trace=trace.bin --memory=memory.bin --program=program.json --output=output.bin`\n4. Verify the proof: `giza verify --proof=output.bin`\n\n### Mode 2: Supply a program\n\nTo 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.\n\n`cargo run --release --bin giza-examples`\n\n## Acknowledgments\n- The Cairo virtual machine and programming language is developed by [Starkware](https://starkware.co/).\n- The STARK prover and verifier is built using the [Winterfell](https://github.com/novifinancial/winterfell) project.\n- The current Rust runner is a fork of the implementation written by Anaïs Querol of O(1) Labs.\n"
  },
  {
    "path": "air/Cargo.toml",
    "content": "[package]\nname = \"giza-air\"\nversion = \"0.1.0\"\nedition = \"2018\"\n\n[dependencies]\nwinter-air = { package = \"winter-air\", git = \"https://github.com/maxgillett/winterfell\", rev = \"0aad6a5\", default-features = false }\nwinter-utils = { package = \"winter-utils\", git = \"https://github.com/maxgillett/winterfell\", rev = \"0aad6a5\", default-features = false }\ngiza_core = { package = \"giza-core\", path = \"../core\", version = \"0.1\", default-features = false }\nserde = \"1.0.137\"\n"
  },
  {
    "path": "air/src/constraints.rs",
    "content": "use super::{AuxEvaluationFrame, AuxTraceRandElements, MainEvaluationFrame};\nuse giza_core::{\n    range, ExtensionOf, Felt, FieldElement, FlagDecomposition, OffsetDecomposition, Range,\n};\n\npub trait EvaluationResult<E: FieldElement> {\n    fn evaluate_instr_constraints(&mut self, frame: &MainEvaluationFrame<E>);\n    fn evaluate_operand_constraints(&mut self, frame: &MainEvaluationFrame<E>);\n    fn evaluate_register_constraints(&mut self, frame: &MainEvaluationFrame<E>);\n    fn evaluate_opcode_constraints(&mut self, frame: &MainEvaluationFrame<E>);\n    fn enforce_selector(&mut self, frame: &MainEvaluationFrame<E>);\n}\n\npub trait AuxEvaluationResult<E: FieldElement, F: FieldElement + ExtensionOf<E>> {\n    fn evaluate_memory_constraints(\n        &mut self,\n        main_frame: &MainEvaluationFrame<E>,\n        aux_frame: &AuxEvaluationFrame<F>,\n        aux_rand_elements: &AuxTraceRandElements<F>,\n    );\n    fn evaluate_range_check_constraints(\n        &mut self,\n        main_frame: &MainEvaluationFrame<E>,\n        aux_frame: &AuxEvaluationFrame<F>,\n        aux_rand_elements: &AuxTraceRandElements<F>,\n    );\n}\n\n/// Main constraint identifiers\nconst INST: usize = 16;\nconst DST_ADDR: usize = 17;\nconst OP0_ADDR: usize = 18;\nconst OP1_ADDR: usize = 19;\nconst NEXT_AP: usize = 20;\nconst NEXT_FP: usize = 21;\nconst NEXT_PC_1: usize = 22;\nconst NEXT_PC_2: usize = 23;\nconst T0: usize = 24;\nconst T1: usize = 25;\nconst MUL_1: usize = 26;\nconst MUL_2: usize = 27;\nconst CALL_1: usize = 28;\nconst CALL_2: usize = 29;\nconst ASSERT_EQ: usize = 30;\n\n/// Aux constraint identifiers\nconst A_M_PRIME: Range<usize> = range(0, 4);\nconst V_M_PRIME: Range<usize> = range(4, 4);\nconst P_M: Range<usize> = range(8, 4);\nconst A_RC_PRIME: Range<usize> = range(12, 3);\nconst P_RC: Range<usize> = range(15, 3);\n\nconst TWO: Felt = Felt::TWO;\n\nimpl<E: FieldElement + From<Felt>> EvaluationResult<E> for [E] {\n    fn evaluate_instr_constraints(&mut self, frame: &MainEvaluationFrame<E>) {\n        let curr = frame.current();\n        // Bit constraints\n        for (n, flag) in curr.flags().into_iter().enumerate() {\n            self[n] = match n {\n                0..=14 => flag * (flag - Felt::ONE.into()),\n                15 => flag,\n                _ => panic!(\"Unknown flag offset\"),\n            };\n        }\n        // Instruction unpacking\n        let b15: E = TWO.exp(15u32.into()).into();\n        let b16: E = TWO.exp(16u32.into()).into();\n        let b32: E = TWO.exp(32u32.into()).into();\n        let b48: E = TWO.exp(48u32.into()).into();\n        let a: E = curr\n            .flags()\n            .into_iter()\n            .enumerate()\n            .take(15)\n            .fold(Felt::ZERO.into(), |acc, (n, flag)| {\n                acc + E::from(2u128.pow(n as u32)) * flag\n            });\n        self[INST] = (curr.off_dst() + b15)\n            + b16 * (curr.off_op0() + b15)\n            + b32 * (curr.off_op1() + b15)\n            + b48 * a\n            - curr.inst();\n    }\n\n    fn evaluate_operand_constraints(&mut self, frame: &MainEvaluationFrame<E>) {\n        let curr = frame.current();\n        let ap = curr.ap();\n        let fp = curr.fp();\n        let pc = curr.pc();\n        let one: E = Felt::ONE.into();\n\n        self[DST_ADDR] =\n            curr.f_dst_fp() * fp + (one - curr.f_dst_fp()) * ap + curr.off_dst() - curr.dst_addr();\n        self[OP0_ADDR] =\n            curr.f_op0_fp() * fp + (one - curr.f_op0_fp()) * ap + curr.off_op0() - curr.op0_addr();\n        self[OP1_ADDR] = curr.f_op1_val() * pc\n            + curr.f_op1_ap() * ap\n            + curr.f_op1_fp() * fp\n            + (one - curr.f_op1_val() - curr.f_op1_ap() - curr.f_op1_fp()) * curr.op0()\n            + curr.off_op1()\n            - curr.op1_addr();\n    }\n\n    fn evaluate_register_constraints(&mut self, frame: &MainEvaluationFrame<E>) {\n        let curr = frame.current();\n        let next = frame.next();\n        let one: E = Felt::ONE.into();\n\n        // ap and fp constraints\n        self[NEXT_AP] = curr.ap()\n            + curr.f_ap_add() * curr.res()\n            + curr.f_ap_one()\n            + curr.f_opc_call() * TWO.into()\n            - next.ap();\n        self[NEXT_FP] = curr.f_opc_ret() * curr.dst()\n            + curr.f_opc_call() * (curr.ap() + TWO.into())\n            + (one - curr.f_opc_ret() - curr.f_opc_call()) * curr.fp()\n            - next.fp();\n\n        // pc constraints\n        self[NEXT_PC_1] =\n            (curr.t1() - curr.f_pc_jnz()) * (next.pc() - (curr.pc() + curr.inst_size()));\n        self[NEXT_PC_2] = curr.t0() * (next.pc() - (curr.pc() + curr.op1()))\n           + (one - curr.f_pc_jnz()) * next.pc()\n           - ((one - curr.f_pc_abs() - curr.f_pc_rel() - curr.f_pc_jnz())\n                   * (curr.pc() + curr.inst_size())\n               + curr.f_pc_abs() * curr.res()\n               + curr.f_pc_rel() * (curr.pc() + curr.res()));\n        self[T0] = curr.f_pc_jnz() * curr.dst() - curr.t0();\n        self[T1] = curr.t0() * curr.res() - curr.t1();\n    }\n\n    fn evaluate_opcode_constraints(&mut self, frame: &MainEvaluationFrame<E>) {\n        let curr = frame.current();\n        let one: E = Felt::ONE.into();\n        self[MUL_1] = curr.mul() - (curr.op0() * curr.op1());\n        self[MUL_2] = curr.f_res_add() * (curr.op0() + curr.op1())\n            + curr.f_res_mul() * curr.mul()\n            + (one - curr.f_res_add() - curr.f_res_mul() - curr.f_pc_jnz()) * curr.op1()\n            - (one - curr.f_pc_jnz()) * curr.res();\n        self[CALL_1] = curr.f_opc_call() * (curr.dst() - curr.fp());\n        self[CALL_2] = curr.f_opc_call() * (curr.op0() - (curr.pc() + curr.inst_size()));\n        self[ASSERT_EQ] = curr.f_opc_aeq() * (curr.dst() - curr.res());\n    }\n\n    fn enforce_selector(&mut self, frame: &MainEvaluationFrame<E>) {\n        let curr = frame.current();\n        for n in INST..=ASSERT_EQ {\n            self[n] *= curr.selector();\n        }\n    }\n}\n\nimpl<E, F> AuxEvaluationResult<E, F> for [F]\nwhere\n    E: FieldElement + From<Felt>,\n    F: FieldElement + From<Felt> + ExtensionOf<E>,\n{\n    fn evaluate_memory_constraints(\n        &mut self,\n        main_frame: &MainEvaluationFrame<E>,\n        aux_frame: &AuxEvaluationFrame<F>,\n        aux_rand_elements: &AuxTraceRandElements<F>,\n    ) {\n        let curr = main_frame.segment();\n        let aux = aux_frame.segment();\n\n        let random_elements = aux_rand_elements.get_segment_elements(0);\n        let z = random_elements[0];\n        let alpha = random_elements[1];\n\n        // Continuity constraint\n        for (i, n) in A_M_PRIME.enumerate() {\n            self[n] = (aux.a_m_prime(i + 1) - aux.a_m_prime(i))\n                * (aux.a_m_prime(i + 1) - aux.a_m_prime(i) - F::ONE);\n        }\n        // Single-valued constraint\n        for (i, n) in V_M_PRIME.enumerate() {\n            self[n] = (aux.v_m_prime(i + 1) - aux.v_m_prime(i))\n                * (aux.a_m_prime(i + 1) - aux.a_m_prime(i) - F::ONE);\n        }\n        // Cumulative product step\n        for (i, n) in P_M.enumerate() {\n            let a_m: F = curr.a_m(i + 1).into();\n            let v_m: F = curr.v_m(i + 1).into();\n            self[n] = (z - (aux.a_m_prime(i + 1) + alpha * aux.v_m_prime(i + 1))) * aux.p_m(i + 1)\n                - (z - (a_m + alpha * v_m)) * aux.p_m(i);\n        }\n    }\n\n    fn evaluate_range_check_constraints(\n        &mut self,\n        main_frame: &MainEvaluationFrame<E>,\n        aux_frame: &AuxEvaluationFrame<F>,\n        aux_rand_elements: &AuxTraceRandElements<F>,\n    ) {\n        let curr = main_frame.segment();\n        let aux = aux_frame.segment();\n\n        let random_elements = aux_rand_elements.get_segment_elements(1);\n        let z = random_elements[0];\n\n        // Continuity constraint\n        for (i, n) in A_RC_PRIME.enumerate() {\n            self[n] = (aux.a_rc_prime(i + 1) - aux.a_rc_prime(i))\n                * (aux.a_rc_prime(i + 1) - aux.a_rc_prime(i) - F::ONE);\n        }\n        // Cumulative product step\n        for (i, n) in P_RC.enumerate() {\n            self[n] = (z - aux.a_rc_prime(i + 1)) * aux.p_rc(i + 1)\n                - (z - curr.a_rc(i + 1).into()) * aux.p_rc(i)\n        }\n    }\n}\n"
  },
  {
    "path": "air/src/frame.rs",
    "content": "use super::FieldElement;\nuse giza_core::{flags::*, *};\nuse winter_air::{Air, EvaluationFrame, Table};\nuse winter_utils::TableReader;\n\n// MAIN FRAME\n// --------------------------------------------------------------------------------------------\n\n#[derive(Debug, Clone)]\npub struct MainEvaluationFrame<E: FieldElement> {\n    table: Table<E>, // row-major indexing\n}\n\nimpl<E: FieldElement> EvaluationFrame<E> for MainEvaluationFrame<E> {\n    // CONSTRUCTORS\n    // --------------------------------------------------------------------------------------------\n\n    fn new<A: Air>(air: &A) -> Self {\n        let num_cols = air.trace_layout().main_trace_width();\n        let num_rows = Self::num_rows();\n        MainEvaluationFrame {\n            table: Table::new(num_rows, num_cols),\n        }\n    }\n\n    fn from_table(table: Table<E>) -> Self {\n        Self { table }\n    }\n\n    // ROW MUTATORS\n    // --------------------------------------------------------------------------------------------\n\n    fn read_from<R: TableReader<E>>(\n        &mut self,\n        data: R,\n        step: usize,\n        _offset: usize,\n        blowup: usize,\n    ) {\n        let trace_len = data.num_rows();\n        for (row, row_idx) in self.table.rows_mut().zip(Self::offsets().into_iter()) {\n            for col_idx in 0..data.num_cols() {\n                row[col_idx] = data.get(col_idx, (step + row_idx * blowup) % trace_len);\n            }\n        }\n    }\n\n    // ROW ACCESSORS\n    // --------------------------------------------------------------------------------------------\n\n    fn row<'a>(&'a self, row_idx: usize) -> &'a [E] {\n        &self.table.get_row(row_idx)\n    }\n\n    fn to_table(&self) -> Table<E> {\n        self.table.clone()\n    }\n\n    fn offsets() -> &'static [usize] {\n        &[0, 1]\n    }\n}\n\nimpl<'a, E: FieldElement> MainEvaluationFrame<E> {\n    pub fn current(&'a self) -> MainFrameSegment<'a, E> {\n        MainFrameSegment::new(&self.table, 0)\n    }\n    pub fn next(&'a self) -> MainFrameSegment<'a, E> {\n        MainFrameSegment::new(&self.table, 1)\n    }\n    pub fn segment(&'a self) -> MainFrameSegment<'a, E> {\n        MainFrameSegment::new(&self.table, 0)\n    }\n}\n\npub struct MainFrameSegment<'a, E: FieldElement> {\n    table: &'a Table<E>,\n    row_start: usize,\n}\n\nenum DataSegment {\n    Flags,\n    ResValue,\n    TempMemoryPointer,\n    MemoryAddress,\n    MemoryValues,\n    Offsets,\n    TempValues,\n    Selector,\n}\n\nimpl<'a, E: FieldElement> MainFrameSegment<'a, E> {\n    fn new(table: &'a Table<E>, row_start: usize) -> Self {\n        Self { table, row_start }\n    }\n\n    fn get(&self, pos: usize, data_type: DataSegment) -> E {\n        // Should this function be inlined?\n        let offset = match data_type {\n            DataSegment::Flags => FLAG_TRACE_OFFSET,\n            DataSegment::ResValue => RES_TRACE_OFFSET,\n            DataSegment::TempMemoryPointer => MEM_P_TRACE_OFFSET,\n            DataSegment::MemoryAddress => MEM_A_TRACE_OFFSET,\n            DataSegment::MemoryValues => MEM_V_TRACE_OFFSET,\n            DataSegment::Offsets => OFF_X_TRACE_OFFSET,\n            DataSegment::TempValues => DERIVED_TRACE_OFFSET,\n            DataSegment::Selector => SELECTOR_TRACE_OFFSET,\n        };\n        self.table.get_row(self.row_start)[offset + pos]\n    }\n\n    fn get_virtual(&self, idx: usize, offset: usize, width: usize) -> E {\n        if (0..width).contains(&idx) {\n            self.table.get_row(0)[offset + idx]\n        } else if (width..width * 2).contains(&idx) {\n            self.table.get_row(1)[offset + idx - width]\n        } else {\n            panic!()\n        }\n    }\n}\n\nimpl<'a, E: FieldElement + From<Felt>> MainFrameSegment<'a, E> {\n    /// Result\n    pub fn res(&self) -> E {\n        self.get(0, DataSegment::ResValue)\n    }\n    /// Registers\n    pub fn pc(&self) -> E {\n        self.get(0, DataSegment::MemoryAddress)\n    }\n    pub fn ap(&self) -> E {\n        self.get(0, DataSegment::TempMemoryPointer)\n    }\n    pub fn fp(&self) -> E {\n        self.get(1, DataSegment::TempMemoryPointer)\n    }\n    /// Memory addresses\n    pub fn dst_addr(&self) -> E {\n        self.get(1, DataSegment::MemoryAddress)\n    }\n    pub fn op0_addr(&self) -> E {\n        self.get(2, DataSegment::MemoryAddress)\n    }\n    pub fn op1_addr(&self) -> E {\n        self.get(3, DataSegment::MemoryAddress)\n    }\n    /// Memory values\n    pub fn inst(&self) -> E {\n        self.get(0, DataSegment::MemoryValues)\n    }\n    pub fn dst(&self) -> E {\n        self.get(1, DataSegment::MemoryValues)\n    }\n    pub fn op0(&self) -> E {\n        self.get(2, DataSegment::MemoryValues)\n    }\n    pub fn op1(&self) -> E {\n        self.get(3, DataSegment::MemoryValues)\n    }\n    /// Instruction size\n    pub fn inst_size(&self) -> E {\n        self.f_op1_val() + Felt::ONE.into()\n    }\n    /// Derived trace values\n    pub fn t0(&self) -> E {\n        self.get(0, DataSegment::TempValues)\n    }\n    pub fn t1(&self) -> E {\n        self.get(1, DataSegment::TempValues)\n    }\n    pub fn mul(&self) -> E {\n        self.get(2, DataSegment::TempValues)\n    }\n    /// Virtual columns of memory addreses and values\n    pub fn a_m(&self, idx: usize) -> E {\n        self.get_virtual(idx, MEM_A_TRACE_OFFSET, MEM_A_TRACE_WIDTH)\n    }\n    pub fn v_m(&self, idx: usize) -> E {\n        self.get_virtual(idx, MEM_V_TRACE_OFFSET, MEM_V_TRACE_WIDTH)\n    }\n    /// Virtual columns of offsets\n    pub fn a_rc(&self, idx: usize) -> E {\n        self.get_virtual(idx, OFF_X_TRACE_OFFSET, OFF_X_TRACE_WIDTH)\n    }\n    /// Selector\n    pub fn selector(&self) -> E {\n        self.get(0, DataSegment::Selector)\n    }\n}\n\nimpl<'a, E: FieldElement + From<Felt>> OffsetDecomposition<E> for MainFrameSegment<'a, E> {\n    fn off_dst(&self) -> E {\n        bias(self.get(0, DataSegment::Offsets))\n    }\n\n    fn off_op0(&self) -> E {\n        bias(self.get(1, DataSegment::Offsets))\n    }\n\n    fn off_op1(&self) -> E {\n        bias(self.get(2, DataSegment::Offsets))\n    }\n}\n\nimpl<'a, E: FieldElement + From<Felt>> FlagDecomposition<E> for MainFrameSegment<'a, E> {\n    fn flags(&self) -> Vec<E> {\n        let mut flags = Vec::with_capacity(NUM_FLAGS);\n        for i in 0..NUM_FLAGS {\n            flags.push(self.flag_at(i));\n        }\n        flags\n    }\n\n    fn flag_at(&self, pos: usize) -> E {\n        self.get(pos, DataSegment::Flags)\n    }\n}\n\n// AUX FRAME\n// --------------------------------------------------------------------------------------------\n\n#[derive(Debug, Clone)]\npub struct AuxEvaluationFrame<E: FieldElement> {\n    table: Table<E>, // row-major indexing\n}\n\nimpl<E: FieldElement> EvaluationFrame<E> for AuxEvaluationFrame<E> {\n    // CONSTRUCTORS\n    // --------------------------------------------------------------------------------------------\n\n    fn new<A: Air>(air: &A) -> Self {\n        let num_rows = Self::num_rows();\n        let num_cols = air.trace_layout().aux_trace_width();\n        AuxEvaluationFrame {\n            table: Table::new(num_rows, num_cols),\n        }\n    }\n\n    fn from_table(table: Table<E>) -> Self {\n        Self { table }\n    }\n\n    // ROW MUTATORS\n    // --------------------------------------------------------------------------------------------\n\n    fn read_from<R: TableReader<E>>(&mut self, data: R, step: usize, offset: usize, blowup: usize) {\n        let trace_len = data.num_rows();\n        for (row, row_idx) in self.table.rows_mut().zip(Self::offsets().into_iter()) {\n            for col_idx in 0..data.num_cols() {\n                row[col_idx + offset] = data.get(col_idx, (step + row_idx * blowup) % trace_len);\n            }\n        }\n    }\n\n    // ROW ACCESSORS\n    // --------------------------------------------------------------------------------------------\n\n    fn row<'a>(&'a self, row_idx: usize) -> &'a [E] {\n        &self.table.get_row(row_idx)\n    }\n\n    fn to_table(&self) -> Table<E> {\n        self.table.clone()\n    }\n\n    fn offsets() -> &'static [usize] {\n        &[0, 1]\n    }\n}\n\nimpl<'a, E: FieldElement> AuxEvaluationFrame<E> {\n    pub fn segment(&'a self) -> AuxFrameSegment<'a, E> {\n        AuxFrameSegment::new(&self.table, 0)\n    }\n}\n\npub struct AuxFrameSegment<'a, E: FieldElement> {\n    curr_row: &'a [E],\n    next_row: &'a [E],\n}\n\nimpl<'a, E: FieldElement> AuxFrameSegment<'a, E> {\n    fn new(table: &'a Table<E>, row_idx: usize) -> Self {\n        let curr_row = table.get_row(row_idx);\n        let next_row = table.get_row(row_idx + 1);\n        Self { curr_row, next_row }\n    }\n\n    fn get_virtual(&self, idx: usize, offset: usize, width: usize) -> E {\n        if (0..width).contains(&idx) {\n            self.curr_row[offset + idx]\n        } else if (width..width * 2).contains(&idx) {\n            self.next_row[offset + idx - width]\n        } else {\n            panic!()\n        }\n    }\n\n    /// Memory\n    pub fn a_m_prime(&self, idx: usize) -> E {\n        self.get_virtual(idx, A_M_PRIME_OFFSET, A_M_PRIME_WIDTH)\n    }\n    pub fn v_m_prime(&self, idx: usize) -> E {\n        self.get_virtual(idx, V_M_PRIME_OFFSET, V_M_PRIME_WIDTH)\n    }\n    pub fn p_m(&self, idx: usize) -> E {\n        self.get_virtual(idx, P_M_OFFSET, P_M_WIDTH)\n    }\n\n    /// Permutation range check\n    pub fn a_rc_prime(&self, idx: usize) -> E {\n        self.get_virtual(idx, A_RC_PRIME_OFFSET, A_RC_PRIME_WIDTH)\n    }\n    pub fn p_rc(&self, idx: usize) -> E {\n        self.get_virtual(idx, P_RC_OFFSET, P_RC_WIDTH)\n    }\n}\n"
  },
  {
    "path": "air/src/lib.rs",
    "content": "#![feature(generic_associated_types)]\n\nuse giza_core::{\n    Builtin, ExtensionOf, Felt, FieldElement, RegisterState, Word, A_RC_PRIME_FIRST,\n    A_RC_PRIME_LAST, MEM_A_TRACE_OFFSET, MEM_P_TRACE_OFFSET, P_M_LAST,\n};\nuse winter_air::{\n    Air, AirContext, Assertion, AuxTraceRandElements, ProofOptions as WinterProofOptions,\n    TraceInfo, TransitionConstraintDegree,\n};\nuse winter_utils::{ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable};\n\n// EXPORTS\n// ================================================================================================\n\npub use winter_air::{EvaluationFrame, FieldExtension, HashFunction};\n\nmod options;\npub use options::ProofOptions;\n\nmod constraints;\nuse constraints::{AuxEvaluationResult, EvaluationResult};\n\nmod frame;\npub use frame::{AuxEvaluationFrame, MainEvaluationFrame};\n\n// PROCESSOR AIR\n// ================================================================================================\n\npub struct ProcessorAir {\n    context: AirContext<Felt>,\n    pub_inputs: PublicInputs,\n}\n\nimpl Air for ProcessorAir {\n    type BaseField = Felt;\n    type PublicInputs = PublicInputs;\n    type Frame<E: FieldElement> = MainEvaluationFrame<E>;\n    type AuxFrame<E: FieldElement> = AuxEvaluationFrame<E>;\n\n    fn new(trace_info: TraceInfo, pub_inputs: PublicInputs, options: WinterProofOptions) -> Self {\n        let mut main_degrees = vec![];\n        // Instruction constraints\n        for _ in 0..=14 {\n            main_degrees.push(TransitionConstraintDegree::new(2)); // F0-F14\n        }\n        main_degrees.push(TransitionConstraintDegree::new(1)); // F15\n\n        // Operand constraints\n        main_degrees.push(TransitionConstraintDegree::new(4)); // INST\n        main_degrees.push(TransitionConstraintDegree::new(4)); // DST_ADDR\n        main_degrees.push(TransitionConstraintDegree::new(4)); // OP0_ADDR\n        main_degrees.push(TransitionConstraintDegree::new(4)); // OP1_ADDR\n\n        // Register constraints\n        main_degrees.push(TransitionConstraintDegree::new(4)); // NEXT_AP\n        main_degrees.push(TransitionConstraintDegree::new(4)); // NEXT_FP\n        main_degrees.push(TransitionConstraintDegree::new(4)); // NEXT_PC_1\n        main_degrees.push(TransitionConstraintDegree::new(4)); // NEXT_PC_2\n        main_degrees.push(TransitionConstraintDegree::new(4)); // T0\n        main_degrees.push(TransitionConstraintDegree::new(4)); // T1\n\n        // Opcode constraints\n        main_degrees.push(TransitionConstraintDegree::new(4)); // MUL_1\n        main_degrees.push(TransitionConstraintDegree::new(4)); // MUL_2\n        main_degrees.push(TransitionConstraintDegree::new(4)); // CALL_1\n        main_degrees.push(TransitionConstraintDegree::new(4)); // CALL_2\n        main_degrees.push(TransitionConstraintDegree::new(4)); // ASSERT_EQ\n\n        let aux_degrees = vec![\n            // Memory constraints\n            TransitionConstraintDegree::new(2), // A_M_PRIME 0\n            TransitionConstraintDegree::new(2), //     \"     1\n            TransitionConstraintDegree::new(2), //     \"     2\n            TransitionConstraintDegree::new(2), //     \"     3\n            TransitionConstraintDegree::new(2), // V_M_PRIME 0\n            TransitionConstraintDegree::new(2), //     \"     1\n            TransitionConstraintDegree::new(2), //     \"     2\n            TransitionConstraintDegree::new(2), //     \"     3\n            TransitionConstraintDegree::new(2), //    P_M    0\n            TransitionConstraintDegree::new(2), //     \"     1\n            TransitionConstraintDegree::new(2), //     \"     2\n            TransitionConstraintDegree::new(2), //     \"     3\n            // Range check constraints\n            TransitionConstraintDegree::new(2), // A_RC_PRIME 0\n            TransitionConstraintDegree::new(2), //     \"      1\n            TransitionConstraintDegree::new(2), //     \"      2\n            TransitionConstraintDegree::new(2), //    P_RC    0\n            TransitionConstraintDegree::new(2), //     \"      1\n            TransitionConstraintDegree::new(2), //     \"      2\n        ];\n\n        let mut transition_exemptions = vec![];\n        transition_exemptions.extend(vec![1; main_degrees.len()]);\n        transition_exemptions.extend(vec![1; aux_degrees.len()]);\n\n        let mut context =\n            AirContext::new_multi_segment(trace_info, main_degrees, aux_degrees, 4, 3, options);\n        context.set_transition_exemptions(transition_exemptions);\n\n        Self {\n            context,\n            pub_inputs,\n        }\n    }\n\n    fn get_assertions(&self) -> Vec<Assertion<Felt>> {\n        let last_step = self.pub_inputs.num_steps - 1;\n        vec![\n            // Initial and final 'pc' register\n            Assertion::single(MEM_A_TRACE_OFFSET, 0, self.pub_inputs.init.pc),\n            Assertion::single(MEM_A_TRACE_OFFSET, last_step, self.pub_inputs.fin.pc),\n            // Initial and final 'ap' register\n            Assertion::single(MEM_P_TRACE_OFFSET, 0, self.pub_inputs.init.ap),\n            Assertion::single(MEM_P_TRACE_OFFSET, last_step, self.pub_inputs.fin.ap),\n        ]\n    }\n\n    fn get_aux_assertions<E: FieldElement + From<Self::BaseField>>(\n        &self,\n        aux_rand_elements: &AuxTraceRandElements<E>,\n    ) -> Vec<Assertion<E>> {\n        let last_step = self.trace_length() - 1;\n        let random_elements = aux_rand_elements.get_segment_elements(0);\n        let mem = &self.pub_inputs.mem;\n        let z = random_elements[0];\n        let alpha = random_elements[1];\n        let num = z.exp((mem.0.len() as u64).into());\n\n        let den = mem\n            .0\n            .iter()\n            .zip(&mem.1)\n            .map(|(a, v)| z - (E::from(*a as u64) + alpha * E::from(v.unwrap().word())))\n            .reduce(|a, b| a * b)\n            .unwrap();\n\n        vec![\n            // Public memory\n            Assertion::single(P_M_LAST, last_step, num / den),\n            // Minimum range check value\n            Assertion::single(A_RC_PRIME_FIRST, 0, E::from(self.pub_inputs.rc_min)),\n            // Maximum range check value\n            Assertion::single(A_RC_PRIME_LAST, last_step, E::from(self.pub_inputs.rc_max)),\n        ]\n    }\n\n    fn evaluate_transition<E: FieldElement + From<Felt>>(\n        &self,\n        frame: &MainEvaluationFrame<E>,\n        _periodic_values: &[E],\n        result: &mut [E],\n    ) {\n        result.evaluate_instr_constraints(frame);\n        result.evaluate_operand_constraints(frame);\n        result.evaluate_register_constraints(frame);\n        result.evaluate_opcode_constraints(frame);\n        result.enforce_selector(frame);\n    }\n\n    fn evaluate_aux_transition<\n        E: FieldElement + From<Felt>,\n        F: FieldElement + From<Felt> + ExtensionOf<E>,\n    >(\n        &self,\n        main_frame: &MainEvaluationFrame<E>,\n        aux_frame: &AuxEvaluationFrame<F>,\n        _periodic_values: &[E],\n        aux_rand_elements: &AuxTraceRandElements<F>,\n        result: &mut [F],\n    ) {\n        result.evaluate_memory_constraints(main_frame, aux_frame, aux_rand_elements);\n        result.evaluate_range_check_constraints(main_frame, aux_frame, aux_rand_elements);\n    }\n\n    fn context(&self) -> &AirContext<Felt> {\n        &self.context\n    }\n}\n\n// PUBLIC INPUTS\n// ================================================================================================\n\npub struct PublicInputs {\n    pub init: RegisterState,                // initial register state\n    pub fin: RegisterState,                 // final register state\n    pub rc_min: u16, // minimum range check value (0 < rc_min < rc_max < 2^16)\n    pub rc_max: u16, // maximum range check value\n    pub mem: (Vec<u64>, Vec<Option<Word>>), // public memory\n    pub num_steps: usize, // number of execution steps\n    pub builtins: Vec<Builtin>, // list of builtins\n}\n\nimpl PublicInputs {\n    pub fn new(\n        init: RegisterState,\n        fin: RegisterState,\n        rc_min: u16,\n        rc_max: u16,\n        mem: (Vec<u64>, Vec<Option<Word>>),\n        num_steps: usize,\n        builtins: Vec<Builtin>,\n    ) -> Self {\n        Self {\n            init,\n            fin,\n            rc_min,\n            rc_max,\n            mem,\n            num_steps,\n            builtins,\n        }\n    }\n}\n\n// TODO: Implement Serializable/Deserializable traits in RegisterState and Memory\n// structs instead of manually managing it here\nimpl Serializable for PublicInputs {\n    fn write_into<W: ByteWriter>(&self, target: &mut W) {\n        target.write(self.init.pc);\n        target.write(self.init.ap);\n        target.write(self.init.fp);\n        target.write(self.fin.pc);\n        target.write(self.fin.ap);\n        target.write(self.fin.fp);\n        target.write_u16(self.rc_min);\n        target.write_u16(self.rc_max);\n        target.write_u64(self.mem.1.len() as u64);\n        for i in 0..self.mem.1.len() as usize {\n            target.write_u64(self.mem.0[i]);\n        }\n        target.write(\n            self.mem\n                .1\n                .iter()\n                .map(|x| x.unwrap().word())\n                .collect::<Vec<_>>(),\n        );\n        target.write_u64(self.num_steps as u64);\n        // TODO: Use bit representation once multiple builtins are supported\n        for builtin in self.builtins.iter() {\n            if let Builtin::Output(_) = builtin {\n                target.write_u8(1);\n            } else {\n                target.write_u8(0);\n            }\n        }\n    }\n}\n\nimpl Deserializable for PublicInputs {\n    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {\n        let init = RegisterState::new(\n            Felt::read_from(source)?,\n            Felt::read_from(source)?,\n            Felt::read_from(source)?,\n        );\n        let fin = RegisterState::new(\n            Felt::read_from(source)?,\n            Felt::read_from(source)?,\n            Felt::read_from(source)?,\n        );\n        let rc_min = source.read_u16()?;\n        let rc_max = source.read_u16()?;\n        let mem_len = source.read_u64()?;\n        let mut mem_a = vec![0u64; mem_len as usize];\n        for i in 0..mem_len as usize {\n            mem_a[i] = source.read_u64()?;\n        }\n        let mem_v = Felt::read_batch_from(source, mem_len as usize)?\n            .into_iter()\n            .map(|x| Some(Word::new(x)))\n            .collect::<Vec<_>>();\n        let num_steps = source.read_u64()?;\n        // TODO: Interpret as bits once multiple builtins are supported\n        let builtins = match source.read_u8()? {\n            1 => vec![Builtin::Output(0)],\n            _ => vec![],\n        };\n        Ok(PublicInputs::new(\n            init,\n            fin,\n            rc_min,\n            rc_max,\n            (mem_a, mem_v),\n            num_steps as usize,\n            builtins,\n        ))\n    }\n}\n"
  },
  {
    "path": "air/src/options.rs",
    "content": "use core::ops::Deref;\nuse winter_air::{FieldExtension, HashFunction, ProofOptions as WinterProofOptions};\n\n/// TODO: add docs\n#[derive(Clone)]\npub struct ProofOptions(WinterProofOptions);\n\nimpl ProofOptions {\n    pub fn new(\n        num_queries: usize,\n        blowup_factor: usize,\n        grinding_factor: u32,\n        hash_fn: HashFunction,\n        field_extension: FieldExtension,\n        fri_folding_factor: usize,\n        fri_max_remainder_size: usize,\n    ) -> Self {\n        Self(WinterProofOptions::new(\n            num_queries,\n            blowup_factor,\n            grinding_factor,\n            hash_fn,\n            field_extension,\n            fri_folding_factor,\n            fri_max_remainder_size,\n        ))\n    }\n\n    pub fn with_proof_options(\n        num_queries: Option<usize>,\n        blowup_factor: Option<usize>,\n        grinding_factor: Option<u32>,\n        fri_folding_factor: Option<usize>,\n        fri_max_remainder_size: Option<usize>,\n    ) -> Self {\n        Self(WinterProofOptions::new(\n            num_queries.unwrap_or(54),  // 27\n            blowup_factor.unwrap_or(4), //8,\n            grinding_factor.unwrap_or(16),\n            HashFunction::Blake3_192,\n            FieldExtension::None,\n            fri_folding_factor.unwrap_or(8),\n            fri_max_remainder_size.unwrap_or(256),\n        ))\n    }\n\n    pub fn into_inner(self) -> WinterProofOptions {\n        self.0\n    }\n}\n\nimpl Default for ProofOptions {\n    fn default() -> Self {\n        Self::with_proof_options(None, None, None, None, None)\n    }\n}\n\nimpl Deref for ProofOptions {\n    type Target = WinterProofOptions;\n\n    fn deref(&self) -> &Self::Target {\n        &self.0\n    }\n}\n"
  },
  {
    "path": "cli/Cargo.toml",
    "content": "[package]\nname = \"giza-cli\"\nversion = \"0.1.0\"\nedition = \"2021\"\nrust-version = \"1.57\"\n\n[dependencies]\nclap = { version = \"3.1.18\", features = [\"derive\"] }\nair = { package = \"giza-air\", path = \"../air\", version = \"0.1\", default-features = false }\nprover = { package = \"giza-prover\", path = \"../prover\", version = \"0.1\", default-features = false }\nrunner = { package = \"giza-runner\", path = \"../runner\", version = \"0.1\", default-features = false }\nwinterfell = { package = \"winter-verifier\", git = \"https://github.com/maxgillett/winterfell\", rev = \"0aad6a5\", features = [\"std\"], default-features = false }\nwinter-utils = { package = \"winter-utils\", git = \"https://github.com/maxgillett/winterfell\", rev = \"0aad6a5\", default-features = false }\nserde = \"1.0.137\"\nbincode = \"1.3.3\"\n\n[[bin]]\nname = \"giza\"\npath = \"src/giza.rs\"\ndoc = false\n"
  },
  {
    "path": "cli/README.md",
    "content": "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",
    "content": "use serde::{Deserialize, Serialize};\n\npub mod prove;\npub mod verify;\n\n#[derive(Serialize, Deserialize)]\nstruct ProofData {\n    input_bytes: Vec<u8>,\n    proof_bytes: Vec<u8>,\n}\n"
  },
  {
    "path": "cli/src/cmd/prove/args.rs",
    "content": "use clap::{Error, ErrorKind, Parser, ValueHint};\nuse std::path::PathBuf;\n\n#[derive(Parser, Debug)]\n#[clap(author, version, about, long_about = None)]\npub struct ProveArgs {\n    #[clap(\n        help = \"Path to the compiled Cairo program JSON file\",\n        long,\n        value_hint = ValueHint::FilePath\n    )]\n    pub program: PathBuf,\n\n    #[clap(\n        help = \"Path to the execution trace output file\",\n        long,\n        value_hint = ValueHint::FilePath\n    )]\n    pub trace: PathBuf,\n\n    #[clap(\n        help = \"Path to the memory output file\",\n        long,\n        value_hint = ValueHint::FilePath\n    )]\n    pub memory: PathBuf,\n\n    #[clap(\n        help = \"Path to write the STARK proof\",\n        long,\n        value_hint = ValueHint::FilePath\n    )]\n    pub output: PathBuf,\n\n    #[clap(help = \"Number of serialized outputs\", long)]\n    pub num_outputs: Option<u64>,\n\n    #[clap(\n        help = \"Number of queries for a STARK proof\",\n        long,\n        value_parser(clap::builder::ValueParser::new(parse_num_queries))\n    )]\n    pub num_queries: Option<usize>,\n\n    #[clap(\n        help = \"Blowup factor for a STARK proof\",\n        long,\n        value_parser(clap::builder::ValueParser::new(parse_blowup_factor))\n    )]\n    pub blowup_factor: Option<usize>,\n\n    #[clap(\n        help = \"Query seed grinding factor for a STARK proof\",\n        long,\n        value_parser(clap::value_parser!(u32).range(..33))\n    )]\n    pub grinding_factor: Option<u32>,\n\n    #[clap(\n        help = \"Factor by which the degree of a polynomial is reduced with each FRI layer\",\n        long,\n        value_parser(clap::builder::ValueParser::new(parse_fri_folding_factor))\n    )]\n    pub fri_folding_factor: Option<usize>,\n\n    #[clap(\n        help = \"Maximum allowed remainder (last FRI layer) size\",\n        long,\n        value_parser(clap::builder::ValueParser::new(parse_fri_max_remainder_size))\n    )]\n    pub fri_max_remainder_size: Option<usize>,\n}\n\nfn parse_num_queries(value: &str) -> Result<usize, Error> {\n    let value = value\n        .parse::<usize>()\n        .map_err(|e| Error::raw(ErrorKind::InvalidValue, format!(\"{}\", e)))?;\n\n    match value {\n        0 => Err(Error::raw(ErrorKind::ValueValidation, \"cannot be 0\")),\n        129.. => Err(Error::raw(\n            ErrorKind::ValueValidation,\n            \"cannot be more than 128\",\n        )),\n        _ => Ok(value),\n    }\n}\n\nfn parse_blowup_factor(value: &str) -> Result<usize, Error> {\n    let value = value\n        .parse::<usize>()\n        .map_err(|e| Error::raw(ErrorKind::InvalidValue, format!(\"{}\", e)))?;\n\n    if !value.is_power_of_two() {\n        return Err(Error::raw(\n            ErrorKind::ValueValidation,\n            \"must be a power of two\",\n        ));\n    }\n\n    match value {\n        0..=3 => Err(Error::raw(\n            ErrorKind::ValueValidation,\n            \"cannot be smaller than 4\",\n        )),\n        257.. => Err(Error::raw(\n            ErrorKind::ValueValidation,\n            \"cannot be more than 256\",\n        )),\n        _ => Ok(value),\n    }\n}\n\nfn parse_fri_folding_factor(value: &str) -> Result<usize, Error> {\n    let value = value\n        .parse::<usize>()\n        .map_err(|e| Error::raw(ErrorKind::InvalidValue, format!(\"{}\", e)))?;\n\n    if value != 4 && value != 8 && value != 16 {\n        Err(Error::raw(ErrorKind::ValueValidation, \"must be 4, 8 or 16\"))\n    } else {\n        Ok(value)\n    }\n}\n\nfn parse_fri_max_remainder_size(value: &str) -> Result<usize, Error> {\n    let value = value\n        .parse::<usize>()\n        .map_err(|e| Error::raw(ErrorKind::InvalidValue, format!(\"{}\", e)))?;\n\n    if !value.is_power_of_two() {\n        return Err(Error::raw(\n            ErrorKind::ValueValidation,\n            \"must be a power of two\",\n        ));\n    }\n\n    match value {\n        0..=31 => Err(Error::raw(\n            ErrorKind::ValueValidation,\n            \"cannot be smaller than 32\",\n        )),\n        1025.. => Err(Error::raw(\n            ErrorKind::ValueValidation,\n            \"cannot be more than 1024\",\n        )),\n        _ => Ok(value),\n    }\n}\n"
  },
  {
    "path": "cli/src/cmd/prove/mod.rs",
    "content": "mod args;\nmod prove;\n\npub use args::ProveArgs;\n"
  },
  {
    "path": "cli/src/cmd/prove/prove.rs",
    "content": "use std::fs::File;\nuse std::io::Write;\n\nuse super::ProveArgs;\nuse crate::{cmd::ProofData, utils::Cmd};\nuse air::ProofOptions;\nuse runner::ExecutionTrace;\nuse winter_utils::Serializable;\n\npub struct ProveOutput {}\n\n#[derive(Debug)]\npub enum Error {}\n\nimpl Cmd for ProveArgs {\n    type Output = Result<ProveOutput, Error>;\n\n    fn run(self) -> Self::Output {\n        // Load trace from file\n        let trace =\n            ExecutionTrace::from_file(self.program, self.trace, self.memory, self.num_outputs);\n\n        // Generate proof\n        let proof_options = ProofOptions::with_proof_options(\n            self.num_queries,\n            self.blowup_factor,\n            self.grinding_factor,\n            self.fri_folding_factor,\n            self.fri_max_remainder_size,\n        );\n        let (proof, pub_inputs) = prover::prove_trace(trace, &proof_options).unwrap();\n        let input_bytes = pub_inputs.to_bytes();\n        let proof_bytes = proof.to_bytes();\n        println!(\"Proof size: {:.1} KB\", proof_bytes.len() as f64 / 1024f64);\n\n        // Write proof to disk\n        let data = ProofData {\n            input_bytes,\n            proof_bytes,\n        };\n        let b = bincode::serialize(&data).unwrap();\n        let mut f = File::create(self.output).unwrap();\n        f.write_all(&b).unwrap();\n\n        Ok(ProveOutput {})\n    }\n}\n"
  },
  {
    "path": "cli/src/cmd/verify.rs",
    "content": "use std::fs::File;\nuse std::io::Read;\nuse std::path::PathBuf;\n\nuse super::ProofData;\nuse crate::utils::Cmd;\nuse air::{ProcessorAir, PublicInputs};\nuse clap::{Parser, ValueHint};\nuse winter_utils::{Deserializable, SliceReader};\nuse winterfell::StarkProof;\n\npub struct VerifyOutput {}\n\n#[derive(Parser, Debug)]\n#[clap(author, version, about, long_about = None)]\npub struct VerifyArgs {\n    #[clap(\n        help = \"Path to the STARK proof\",\n        long,\n        value_hint = ValueHint::FilePath\n    )]\n    pub proof: PathBuf,\n}\n\n#[derive(Debug)]\npub enum Error {}\n\nimpl Cmd for VerifyArgs {\n    type Output = Result<VerifyOutput, Error>;\n\n    fn run(self) -> Self::Output {\n        // Load proof and public inputs from file\n        let mut b = Vec::new();\n        let mut f = File::open(self.proof).unwrap();\n        f.read_to_end(&mut b).unwrap();\n        let data: ProofData = bincode::deserialize(&b).unwrap();\n        let pub_inputs =\n            PublicInputs::read_from(&mut SliceReader::new(&data.input_bytes[..])).unwrap();\n        let proof = StarkProof::from_bytes(&data.proof_bytes).unwrap();\n\n        // Verify execution\n        match winterfell::verify::<ProcessorAir>(proof, pub_inputs) {\n            Ok(_) => println!(\"Execution verified\"),\n            Err(err) => println!(\"Failed to verify execution: {}\", err),\n        }\n\n        Ok(VerifyOutput {})\n    }\n}\n"
  },
  {
    "path": "cli/src/giza.rs",
    "content": "pub mod cmd;\nmod utils;\n\nuse crate::utils::Cmd;\nuse clap::{Parser, Subcommand};\nuse cmd::{prove::ProveArgs, verify::VerifyArgs};\n\n#[derive(Debug, Parser)]\n#[clap(name = \"giza\")]\npub struct Opts {\n    #[clap(subcommand)]\n    pub sub: Subcommands,\n}\n\n#[derive(Debug, Subcommand)]\n#[allow(clippy::large_enum_variant)]\npub enum Subcommands {\n    Prove(ProveArgs),\n    Verify(VerifyArgs),\n}\n\nfn main() {\n    let opts = Opts::parse();\n    match opts.sub {\n        Subcommands::Prove(cmd) => {\n            cmd.run().unwrap();\n        }\n        Subcommands::Verify(cmd) => {\n            cmd.run().unwrap();\n        }\n    }\n\n    // TODO: consider returning Result<T,E> for error codes.\n    // Ok(())\n}\n"
  },
  {
    "path": "cli/src/utils.rs",
    "content": "/// Common trait for all cli commands\npub trait Cmd: clap::Parser + Sized {\n    type Output;\n\n    fn run(self) -> Self::Output;\n}\n"
  },
  {
    "path": "core/Cargo.toml",
    "content": "[package]\nname = \"giza-core\"\nversion = \"0.1.0\"\nedition = \"2021\"\nrust-version = \"1.57\"\n\n[dependencies]\nmath = { package = \"winter-math\", git = \"https://github.com/maxgillett/winterfell\", rev = \"0aad6a5\", version = \"0.4\", default-features = false }\nwinter-utils = { package = \"winter-utils\", git = \"https://github.com/maxgillett/winterfell\", rev = \"0aad6a5\", version = \"0.4\", default-features = false }\nff = { version = \"0.12\", features = [\"derive\"] }\nhex = \"0.4\"\n\n"
  },
  {
    "path": "core/src/field/f252/mod.rs",
    "content": "//! An implementation of the 252-bit STARK-friendly prime field chosen by Starkware\n//! with modulus $2^{251} + 17 \\cdot 2^{192} + 1$.\n//! TODO: Worth switching to Barrett reduction for efficiency?\n\nuse core::{\n    convert::{TryFrom, TryInto},\n    fmt::{Debug, Display, Formatter, LowerHex},\n    ops::{\n        Add, AddAssign, BitAnd, Div, DivAssign, Mul, MulAssign, Neg, Shl, Shr, ShrAssign, Sub,\n        SubAssign,\n    },\n    slice,\n};\npub use math::{ExtensibleField, FieldElement, StarkField};\nuse winter_utils::{\n    collections::Vec, string::String, AsBytes, ByteReader, ByteWriter, Deserializable,\n    DeserializationError, Randomizable, Serializable,\n};\n\nuse ff::{Field, PrimeField};\n\n#[cfg(test)]\nmod tests;\n\n// FIELD ELEMENT\n// ================================================================================================\n\n// Note that the internal representation of Fr is assumed to be in Montgomery form with R=2^256\n#[derive(PrimeField)]\n#[PrimeFieldModulus = \"3618502788666131213697322783095070105623107215331596699973092056135872020481\"]\n#[PrimeFieldGenerator = \"3\"]\n#[PrimeFieldReprEndianness = \"little\"]\nstruct Fr([u64; 4]);\n\n// Number of bytes needed to represent field element\nconst ELEMENT_BYTES: usize = core::mem::size_of::<Fr>();\n\n// A wrapper around the internal representation of Fr for non-finite field integer manipulation\n#[derive(PartialOrd, Ord, PartialEq, Eq, Copy, Clone, Debug)]\npub struct BigInt(pub [u64; 4]);\n\n// Represents a base field element, using Fr as the backing type.\n#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]\npub struct BaseElement(Fr);\n\nimpl FieldElement for BaseElement {\n    type PositiveInteger = BigInt;\n    type BaseField = Self;\n\n    const ZERO: Self = BaseElement(Fr([0, 0, 0, 0]));\n    const ONE: Self = BaseElement(Fr(R.0)); // equal to 2^256 mod M\n\n    const ELEMENT_BYTES: usize = ELEMENT_BYTES;\n\n    const IS_CANONICAL: bool = true;\n\n    fn inv(self) -> Self {\n        Self(self.0.invert().unwrap())\n    }\n\n    fn conjugate(&self) -> Self {\n        Self(self.0)\n    }\n\n    fn elements_as_bytes(elements: &[Self]) -> &[u8] {\n        let p = elements.as_ptr();\n        let len = elements.len() * Self::ELEMENT_BYTES;\n        unsafe { slice::from_raw_parts(p as *const u8, len) }\n    }\n\n    unsafe fn bytes_as_elements(_bytes: &[u8]) -> Result<&[Self], DeserializationError> {\n        unimplemented!()\n    }\n\n    fn zeroed_vector(n: usize) -> Vec<Self> {\n        // TODO: use more efficient initialization\n        let result = vec![Self::ZERO.0; n];\n\n        // translate a zero-filled vector of Fr into a vector of base field elements\n        let mut v = core::mem::ManuallyDrop::new(result);\n        let p = v.as_mut_ptr();\n        let len = v.len();\n        let cap = v.capacity();\n        unsafe { Vec::from_raw_parts(p as *mut Self, len, cap) }\n    }\n\n    fn as_base_elements(elements: &[Self]) -> &[Self::BaseField] {\n        elements\n    }\n}\n\nimpl BaseElement {\n    // Equal to 2*2^256 mod M (R is derived from the macro)\n    pub const TWO: Self = BaseElement(Fr([\n        0xffff_ffff_ffff_ffc1,\n        0xffff_ffff_ffff_ffff,\n        0xffff_ffff_ffff_ffff,\n        0x7fff_ffff_ffff_bd0,\n    ]));\n\n    pub fn from_raw(value: [u64; 4]) -> Self {\n        BaseElement(Fr::from_raw(value))\n    }\n\n    pub fn to_raw(&self) -> BigInt {\n        self.0.to_raw()\n    }\n}\n\nimpl StarkField for BaseElement {\n    /// sage: MODULUS = 2^251 + 17 * 2^192 + 1 \\\n    /// sage: GF(MODULUS).is_prime_field() \\\n    /// True \\\n    /// sage: GF(MODULUS).order() \\\n    /// 3618502788666131213697322783095070105623107215331596699973092056135872020481\n    const MODULUS: Self::PositiveInteger = BigInt([0x1, 0x0, 0x0, 0x8000_0000_0000_011]);\n    const MODULUS_BITS: u32 = 252;\n\n    /// sage: GF(MODULUS).primitive_element() \\\n    /// 3\n    const GENERATOR: Self = BaseElement(GENERATOR);\n\n    /// sage: is_odd((MODULUS - 1) / 2^192) \\\n    /// True\n    const TWO_ADICITY: u32 = 192;\n\n    /// sage: k = (MODULUS - 1) / 2^192 \\\n    /// sage: GF(MODULUS).primitive_element()^k \\\n    /// 145784604816374866144131285430889962727208297722245411306711449302875041684\n    const TWO_ADIC_ROOT_OF_UNITY: Self = BaseElement(ROOT_OF_UNITY);\n\n    fn get_modulus_le_bytes() -> Vec<u8> {\n        Self::MODULUS.to_le_bytes()\n    }\n\n    /// Convert from Montgomery form\n    #[inline]\n    fn as_int(&self) -> Self::PositiveInteger {\n        self.0.to_raw()\n    }\n}\n\nimpl Randomizable for BaseElement {\n    const VALUE_SIZE: usize = Self::ELEMENT_BYTES;\n\n    fn from_random_bytes(bytes: &[u8]) -> Option<Self> {\n        Self::try_from(bytes).ok()\n    }\n}\n\nimpl Display for BaseElement {\n    fn fmt(&self, f: &mut Formatter) -> core::fmt::Result {\n        write!(f, \"{}\", self.to_raw())\n    }\n}\n\n// OVERLOADED OPERATORS\n// ================================================================================================\n\nimpl Add for BaseElement {\n    type Output = Self;\n\n    fn add(self, rhs: Self) -> Self {\n        Self(self.0 + rhs.0)\n    }\n}\n\nimpl AddAssign for BaseElement {\n    fn add_assign(&mut self, rhs: Self) {\n        *self = *self + rhs\n    }\n}\n\nimpl Sub for BaseElement {\n    type Output = Self;\n\n    fn sub(self, rhs: Self) -> Self {\n        Self(self.0 - rhs.0)\n    }\n}\n\nimpl SubAssign for BaseElement {\n    fn sub_assign(&mut self, rhs: Self) {\n        *self = *self - rhs;\n    }\n}\n\nimpl Mul for BaseElement {\n    type Output = Self;\n\n    fn mul(self, rhs: Self) -> Self {\n        Self(self.0 * rhs.0)\n    }\n}\n\nimpl MulAssign for BaseElement {\n    fn mul_assign(&mut self, rhs: Self) {\n        *self = *self * rhs\n    }\n}\n\nimpl Div for BaseElement {\n    type Output = Self;\n\n    fn div(self, rhs: Self) -> Self {\n        Self(self.0 * rhs.0.invert().unwrap())\n    }\n}\n\nimpl DivAssign for BaseElement {\n    fn div_assign(&mut self, rhs: Self) {\n        *self = *self / rhs\n    }\n}\n\nimpl Neg for BaseElement {\n    type Output = Self;\n\n    fn neg(self) -> Self {\n        Self(-self.0)\n    }\n}\n\n// QUADRATIC EXTENSION\n// ================================================================================================\n\n/// Defines a quadratic extension of the base field over an irreducible polynomial x<sup>2</sup> -\n/// x - 1. Thus, an extension element is defined as α + β * φ, where φ is a root of this polynomial,\n/// and α and β are base field elements.\nimpl ExtensibleField<2> for BaseElement {\n    #[inline(always)]\n    fn mul(a: [Self; 2], b: [Self; 2]) -> [Self; 2] {\n        let z = a[0] * b[0];\n        [z + a[1] * b[1], (a[0] + a[1]) * (b[0] + b[1]) - z]\n    }\n\n    #[inline(always)]\n    fn mul_base(a: [Self; 2], b: Self) -> [Self; 2] {\n        [a[0] * b, a[1] * b]\n    }\n\n    #[inline(always)]\n    fn frobenius(x: [Self; 2]) -> [Self; 2] {\n        [x[0] + x[1], Self::ZERO - x[1]]\n    }\n}\n\n// CUBIC EXTENSION\n// ================================================================================================\n\n/// Cubic extension for this field is not implemented as quadratic extension already provides\n/// sufficient security level.\nimpl ExtensibleField<3> for BaseElement {\n    fn mul(_a: [Self; 3], _b: [Self; 3]) -> [Self; 3] {\n        unimplemented!()\n    }\n\n    #[inline(always)]\n    fn mul_base(_a: [Self; 3], _b: Self) -> [Self; 3] {\n        unimplemented!()\n    }\n\n    #[inline(always)]\n    fn frobenius(_x: [Self; 3]) -> [Self; 3] {\n        unimplemented!()\n    }\n\n    fn is_supported() -> bool {\n        false\n    }\n}\n\n// TYPE CONVERSIONS\n// ================================================================================================\n\nimpl From<u128> for BaseElement {\n    /// Converts a 128-bit value into a field element.\n    fn from(value: u128) -> Self {\n        let hi: u64 = (value >> 64) as u64;\n        let lo: u64 = value as u64;\n        Self(Fr::from_raw([lo, hi, 0, 0]))\n    }\n}\n\nimpl From<u64> for BaseElement {\n    /// Converts a 64-bit value into a field element.\n    fn from(value: u64) -> Self {\n        Self(Fr::from_raw([value, 0, 0, 0]))\n    }\n}\n\nimpl From<u32> for BaseElement {\n    /// Converts a 32-bit value into a field element.\n    fn from(value: u32) -> Self {\n        Self(Fr::from_raw([value as u64, 0, 0, 0]))\n    }\n}\n\nimpl From<u16> for BaseElement {\n    /// Converts a 16-bit value into a field element.\n    fn from(value: u16) -> Self {\n        Self(Fr::from_raw([value as u64, 0, 0, 0]))\n    }\n}\n\nimpl From<u8> for BaseElement {\n    /// Converts an 8-bit value into a field element.\n    fn from(value: u8) -> Self {\n        Self(Fr::from_raw([value as u64, 0, 0, 0]))\n    }\n}\n\nimpl From<[u64; 4]> for BaseElement {\n    /// Converts the value encoded in an array of 4 64-bit words into a field element. The bytes\n    /// are assumed to be in little-endian byte order. If the value is greater than or equal\n    /// to the field modulus, modular reduction is silently performed.\n    fn from(bytes: [u64; 4]) -> Self {\n        Self(Fr::from_raw(bytes))\n    }\n}\n\nimpl From<[u8; 32]> for BaseElement {\n    /// Converts the value encoded in an array of 32 bytes into a field element. The bytes\n    /// are assumed to be in little-endian byte order. If the value is greater than or equal\n    /// to the field modulus, modular reduction is silently performed.\n    fn from(bytes: [u8; 32]) -> Self {\n        let value: [u64; 4] = bytes\n            .array_chunks::<8>()\n            .map(|c| u64::from_le_bytes(*c))\n            .collect::<Vec<u64>>()\n            .try_into()\n            .unwrap();\n        Self(Fr::from_raw(value))\n    }\n}\n\nimpl<'a> TryFrom<&'a [u8]> for BaseElement {\n    type Error = String;\n\n    /// Converts a slice of bytes into a field element. The bytes are assumed to be in\n    /// little-endian byte order. If the value is greater than or equal to the field modulus,\n    /// modular reduction is silently performed.\n    fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {\n        let mut value: [u64; 4] = [0; 4];\n        for (i, c) in bytes.chunks(8).enumerate() {\n            value[i] = u64::from_le_bytes(TryInto::<[u8; 8]>::try_into(c).unwrap());\n        }\n        Ok(Self(Fr::from_raw(value)))\n    }\n}\n\n// TODO: Why is this method not working? See commented lines in core/src/word/helpers.rs\nimpl AsBytes for BaseElement {\n    fn as_bytes(&self) -> &[u8] {\n        //let ptr: *const Vec<u8> = &self.as_int().to_le_bytes();\n        //unsafe { slice::from_raw_parts(ptr as *const u8, ELEMENT_BYTES) }\n        let ptr: *const BigInt = &self.to_raw();\n        unsafe { slice::from_raw_parts(ptr as *const u8, ELEMENT_BYTES) }\n    }\n}\n\n// SERIALIZATION / DESERIALIZATION\n// ------------------------------------------------------------------------------------------------\n\nimpl Serializable for BaseElement {\n    fn write_into<W: ByteWriter>(&self, target: &mut W) {\n        target.write_u8_slice(&self.0.to_le_bytes());\n    }\n}\n\nimpl Deserializable for BaseElement {\n    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {\n        let bytes: [u8; 32] = source.read_u8_array()?;\n        let value: [u64; 4] = bytes\n            .array_chunks::<8>()\n            .map(|c| u64::from_le_bytes(*c))\n            .collect::<Vec<u64>>()\n            .try_into()\n            .unwrap();\n        Ok(BaseElement(Fr(value)))\n    }\n}\n\n// OVERLOADED OPERATORS (BIGINT)\n// ================================================================================================\n\nimpl Shr<u32> for BigInt {\n    type Output = BigInt;\n    fn shr(self, rhs: u32) -> BigInt {\n        shr_vartime(&self, rhs as usize)\n    }\n}\n\nimpl Shr<u32> for &BigInt {\n    type Output = BigInt;\n    fn shr(self, rhs: u32) -> BigInt {\n        shr_vartime(&self, rhs as usize)\n    }\n}\n\nimpl ShrAssign for BigInt {\n    fn shr_assign(&mut self, rhs: BigInt) {\n        let shift: u64 = rhs.try_into().unwrap();\n        *self = shr_vartime(&self, shift as usize);\n    }\n}\n\nimpl Shl<u32> for BigInt {\n    type Output = BigInt;\n    fn shl(self, rhs: u32) -> BigInt {\n        shl_vartime(&self, rhs as usize)\n    }\n}\n\nimpl Shl<u32> for &BigInt {\n    type Output = BigInt;\n    fn shl(self, rhs: u32) -> BigInt {\n        shl_vartime(&self, rhs as usize)\n    }\n}\n\nimpl BitAnd for BigInt {\n    type Output = Self;\n    fn bitand(self, Self(rhs): Self) -> Self::Output {\n        let mut limbs = [0u64; 4];\n        for i in 0..4 {\n            limbs[i] = self.0[i] & rhs[i];\n        }\n        Self(limbs)\n    }\n}\n\n// Modified from https://github.com/RustCrypto/crypto-bigint/blob/master/src/uint/shr.rs\nfn shr_vartime(value: &BigInt, shift: usize) -> BigInt {\n    let full_shifts = shift / 64;\n    let small_shift = shift & (64 - 1);\n    let mut limbs = [0u64; 4];\n\n    if shift > 64 * 4 {\n        return BigInt(limbs);\n    }\n\n    let n = 4 - full_shifts;\n    let mut i = 0;\n\n    if small_shift == 0 {\n        while i < n {\n            limbs[i] = value.0[i + full_shifts];\n            i += 1;\n        }\n    } else {\n        while i < n {\n            let mut lo = value.0[i + full_shifts] >> small_shift;\n\n            if i < (4 - 1) - full_shifts {\n                lo |= value.0[i + full_shifts + 1] << (64 - small_shift);\n            }\n\n            limbs[i] = lo;\n            i += 1;\n        }\n    }\n    BigInt(limbs)\n}\n\n// Modified from https://github.com/RustCrypto/crypto-bigint/blob/171f6745b98b6dccf05f7d25263981949967f398/src/uint/shl.rs\nfn shl_vartime(value: &BigInt, n: usize) -> BigInt {\n    let mut limbs = [0u64; 4];\n\n    if n >= 64 * 4 {\n        return BigInt(limbs);\n    }\n\n    let shift_num = n / 64;\n    let lshift_rem = n % 64;\n    let nz = lshift_rem == 0;\n    let rshift_rem = if nz { 0 } else { 64 - lshift_rem };\n    let mut i = 4 - 1;\n    while i > shift_num {\n        let mut limb = value.0[i - shift_num] << lshift_rem;\n        let hi = value.0[i - shift_num - 1] >> rshift_rem;\n        limb |= hi & nz as u64;\n        limbs[i] = limb;\n        i -= 1\n    }\n    limbs[shift_num] = value.0[0] << lshift_rem;\n    BigInt(limbs)\n}\n\n// TYPE CONVERSIONS (BIGINT, FR)\n// ------------------------------------------------------------------------------------------------\n\nimpl From<u128> for BigInt {\n    /// Converts a 128-bit value into a field element.\n    fn from(value: u128) -> Self {\n        let hi: u64 = (value >> 64) as u64;\n        let lo: u64 = value as u64;\n        BigInt([lo, hi, 0, 0])\n    }\n}\n\nimpl From<u64> for BigInt {\n    /// Converts a 64-bit value into a field element.\n    fn from(value: u64) -> Self {\n        BigInt([value, 0, 0, 0])\n    }\n}\n\nimpl From<u32> for BigInt {\n    /// Converts a 32-bit value into a field element.\n    fn from(value: u32) -> Self {\n        BigInt([value as u64, 0, 0, 0])\n    }\n}\n\nimpl From<u16> for BigInt {\n    /// Converts a 16-bit value into a field element.\n    fn from(value: u16) -> Self {\n        BigInt([value as u64, 0, 0, 0])\n    }\n}\n\nimpl From<u8> for BigInt {\n    /// Converts an 8-bit value into a field element.\n    fn from(value: u8) -> Self {\n        BigInt([value as u64, 0, 0, 0])\n    }\n}\n\nimpl TryInto<u64> for BigInt {\n    type Error = ();\n    fn try_into(self) -> Result<u64, Self::Error> {\n        Ok(self.0[0])\n    }\n}\n\nimpl TryInto<u16> for BigInt {\n    type Error = ();\n    fn try_into(self) -> Result<u16, Self::Error> {\n        Ok(self.0[0] as u16)\n    }\n}\n\nimpl BigInt {\n    pub fn to_le_bytes(&self) -> Vec<u8> {\n        let mut result = [0u8; 32];\n        write_le_bytes(self.0, &mut result);\n        result.to_vec()\n    }\n}\n\nimpl Display for BigInt {\n    fn fmt(&self, f: &mut Formatter) -> core::fmt::Result {\n        for i in (0..4).rev() {\n            LowerHex::fmt(&self.0[i], f)?;\n        }\n        Ok(())\n    }\n}\n\nimpl Fr {\n    pub fn from_raw(value: [u64; 4]) -> Self {\n        Fr(value).mul(&R2)\n    }\n\n    pub fn to_raw(&self) -> BigInt {\n        let limbs = self.0;\n        let mut val = self.clone();\n        val.mont_reduce(limbs[0], limbs[1], limbs[2], limbs[3], 0, 0, 0, 0);\n        BigInt(val.0)\n    }\n\n    pub fn to_le_bytes(&self) -> Vec<u8> {\n        let mut result = [0u8; 32];\n        write_le_bytes(self.0, &mut result);\n        result.to_vec()\n    }\n}\n\n// Modified from https://github.com/RustCrypto/crypto-bigint/blob/171f6745b98b6dccf05f7d25263981949967f398/src/uint/encoding.rs\nfn write_le_bytes(value: [u64; 4], out: &mut [u8]) {\n    for (src, dst) in value.iter().cloned().zip(out.chunks_exact_mut(8)) {\n        dst.copy_from_slice(&src.to_le_bytes());\n    }\n}\n\n#[test]\nfn as_int() {\n    let a = BaseElement::from_raw([3, 0, 0, 0]);\n    let b: u64 = a.as_int().try_into().unwrap();\n    assert_eq!(b, 3);\n}\n"
  },
  {
    "path": "core/src/field/f252/tests.rs",
    "content": ""
  },
  {
    "path": "core/src/field/mod.rs",
    "content": "pub mod f252;\n"
  },
  {
    "path": "core/src/flags/mod.rs",
    "content": "// Modified from https://github.com/o1-labs/proof-systems\n\n//! Definition of some constants for easier readability of the steps.\n//! When they refer to single bit flagsets, only one constant is needed.\n\n/// Number of Cairo flags\npub const NUM_FLAGS: usize = 16;\n/// Position of destination offset of 16 bits within instruction decomposition\npub const POS_DST: usize = 0;\n/// Position of first operand offset of 16 bits within instruction decomposition\npub const POS_OP0: usize = 1;\n/// Position of second operand offset of 16 bits within instruction decomposition\npub const POS_OP1: usize = 2;\n/// Bit position of the beginning of the flags in a Cairo instruction\npub const POS_FLAGS: usize = 48;\n\n/// Destination refers to ap register\npub const DST_AP: u8 = 0;\n\n/// First operand refers to ap register\npub const OP0_AP: u8 = 0;\n\n/// Second operand is double indexing\npub const OP1_DBL: u8 = 0;\n/// Second operand is immediate value\npub const OP1_VAL: u8 = 1;\n/// Second operand refers to fp register\npub const OP1_FP: u8 = 2;\n/// Second operand refers to ap register\npub const OP1_AP: u8 = 4;\n\n/// Result is a single operand\npub const RES_ONE: u8 = 0;\n/// Result is an addition\npub const RES_ADD: u8 = 1;\n/// Result is a multiplication\npub const RES_MUL: u8 = 2;\n\n/// Default increase of pc by adding instruction size\npub const PC_SIZ: u8 = 0;\n/// Update pc by an absolute jump\npub const PC_ABS: u8 = 1;\n/// Update pc by a relative jump\npub const PC_REL: u8 = 2;\n/// Update pc by a conditional relative jump\npub const PC_JNZ: u8 = 4;\n\n/// Update by 2 in call instructions or zero behaviour for other instructions\npub const AP_Z2: u8 = 0;\n/// Update ap by adding a number of positions\npub const AP_ADD: u8 = 1;\n/// Update ap by self increment\npub const AP_ONE: u8 = 2;\n\n/// Operation code is a jump or an increment\npub const OPC_JMP_INC: u8 = 0;\n/// Operation code is a call\npub const OPC_CALL: u8 = 1;\n/// Operation code is a return\npub const OPC_RET: u8 = 2;\n/// Operation code is an assert-equal\npub const OPC_AEQ: u8 = 4;\n"
  },
  {
    "path": "core/src/inputs/mod.rs",
    "content": "#[derive(Default)]\npub struct ProgramInputs {}\n"
  },
  {
    "path": "core/src/lib.rs",
    "content": "#![feature(array_chunks)]\n\npub use core::ops::Range;\n\npub use math::{ExtensionOf, FieldElement, StarkField};\n\npub mod word;\npub use word::{\n    bias, FieldHelpers, FlagDecomposition, FlagGroupDecomposition, OffsetDecomposition, Word,\n};\n\n// TODO: Make the field element configurable in the CLI\n//pub use math::fields::f128::BaseElement as Felt;\npub mod field;\npub use field::f252::{BaseElement as Felt, BigInt};\n\npub mod inputs;\npub use inputs::ProgramInputs;\n\npub mod flags;\n\n// MAIN TRACE LAYOUT\n// -----------------------------------------------------------------------------------------\n//  A.  flags   (16) : Decoded instruction flags\n//  B.  res     (1)  : Res value\n//  C.  mem_p   (2)  : Temporary memory pointers (ap and fp)\n//  D.  mem_a   (4)  : Memory addresses (pc, dst_addr, op0_addr, op1_addr)\n//  E.  mem_v   (4)  : Memory values (inst, dst, op0, op1)\n//  F.  offsets (3)  : (off_dst, off_op0, off_op1)\n//  G.  derived (3)  : (t0, t1, mul)\n//\n//  A                B C  D    E    F   G\n// ├xxxxxxxxxxxxxxxx|x|xx|xxxx|xxxx|xxx|xxx┤\n//\n\npub const FLAG_TRACE_OFFSET: usize = 0;\npub const FLAG_TRACE_WIDTH: usize = 16;\npub const FLAG_TRACE_RANGE: Range<usize> = range(FLAG_TRACE_OFFSET, FLAG_TRACE_WIDTH);\n\npub const RES_TRACE_OFFSET: usize = 16;\npub const RES_TRACE_WIDTH: usize = 1;\npub const RES_TRACE_RANGE: Range<usize> = range(RES_TRACE_OFFSET, RES_TRACE_WIDTH);\n\npub const MEM_P_TRACE_OFFSET: usize = 17;\npub const MEM_P_TRACE_WIDTH: usize = 2;\npub const MEM_P_TRACE_RANGE: Range<usize> = range(MEM_P_TRACE_OFFSET, MEM_P_TRACE_WIDTH);\n\npub const MEM_A_TRACE_OFFSET: usize = 19;\npub const MEM_A_TRACE_WIDTH: usize = 4;\npub const MEM_A_TRACE_RANGE: Range<usize> = range(MEM_A_TRACE_OFFSET, MEM_A_TRACE_WIDTH);\n\npub const MEM_V_TRACE_OFFSET: usize = 23;\npub const MEM_V_TRACE_WIDTH: usize = 4;\npub const MEM_V_TRACE_RANGE: Range<usize> = range(MEM_V_TRACE_OFFSET, MEM_V_TRACE_WIDTH);\n\npub const OFF_X_TRACE_OFFSET: usize = 27;\npub const OFF_X_TRACE_WIDTH: usize = 3;\npub const OFF_X_TRACE_RANGE: Range<usize> = range(OFF_X_TRACE_OFFSET, OFF_X_TRACE_WIDTH);\n\npub const DERIVED_TRACE_OFFSET: usize = 30;\npub const DERIVED_TRACE_WIDTH: usize = 3;\npub const DERIVED_TRACE_RANGE: Range<usize> = range(DERIVED_TRACE_OFFSET, DERIVED_TRACE_WIDTH);\n\npub const SELECTOR_TRACE_OFFSET: usize = 33;\npub const SELECTOR_TRACE_WIDTH: usize = 1;\npub const SELECTOR_TRACE_RANGE: Range<usize> = range(SELECTOR_TRACE_OFFSET, SELECTOR_TRACE_WIDTH);\n\npub const TRACE_WIDTH: usize = 34;\n\n// AUX TRACE LAYOUT (Memory)\n// -----------------------------------------------------------------------------------------\n//  A.  a_m_prime  (4) : Sorted memory address\n//  B.  v_m_prime  (4) : Sorted memory values\n//  C.  p_m        (4) : Permutation product (memory)\n//\n//  A    B    C\n// ├xxxx|xxxx|xxxx┤\n\npub const A_M_PRIME_OFFSET: usize = 0;\npub const A_M_PRIME_WIDTH: usize = 4;\n\npub const V_M_PRIME_OFFSET: usize = 4;\npub const V_M_PRIME_WIDTH: usize = 4;\n\npub const P_M_OFFSET: usize = 8;\npub const P_M_WIDTH: usize = 4;\n\n// AUX TRACE LAYOUT (Range check)\n// -----------------------------------------------------------------------------------------\n//  D.  a_rc_prime (3) : Sorted offset values\n//  E.  p_rc       (3) : Permutation product (range check)\n//\n//  D   E\n// ├xxx|xxx┤\n//\n\npub const A_RC_PRIME_OFFSET: usize = 12;\npub const A_RC_PRIME_WIDTH: usize = 3;\n\npub const P_RC_OFFSET: usize = 15;\npub const P_RC_WIDTH: usize = 3;\n\n// Main column indices\n\npub const AP: usize = MEM_P_TRACE_OFFSET;\n\n// Aux column indices\n\npub const P_M_LAST: usize = P_M_OFFSET + P_M_WIDTH - 1;\npub const A_RC_PRIME_FIRST: usize = A_RC_PRIME_OFFSET;\npub const A_RC_PRIME_LAST: usize = A_RC_PRIME_OFFSET + 2;\n\n/// Returns a [Range] initialized with the specified `start` and with `end` set to `start` + `len`.\npub const fn range(start: usize, len: usize) -> Range<usize> {\n    Range {\n        start,\n        end: start + len,\n    }\n}\n\n/// A structure to store program counter, allocation pointer and frame pointer\n#[derive(Clone, Copy, Debug)]\npub struct RegisterState {\n    /// Program counter: points to address in memory\n    pub pc: Felt,\n    /// Allocation pointer: points to first free space in memory\n    pub ap: Felt,\n    /// Frame pointer: points to the beginning of the stack in memory (for arguments)\n    pub fp: Felt,\n}\n\npub struct InstructionState {\n    /// Instruction\n    pub inst: Word,\n    pub inst_size: Felt,\n    /// Addresses\n    pub dst_addr: Felt,\n    pub op0_addr: Felt,\n    pub op1_addr: Felt,\n    /// Values\n    pub dst: Option<Felt>,\n    pub op0: Option<Felt>,\n    pub op1: Option<Felt>,\n    /// Result\n    pub res: Option<Felt>,\n}\n\nimpl RegisterState {\n    /// Creates a new triple of pointers\n    pub fn new<T: Into<Felt>>(pc: T, ap: T, fp: T) -> Self {\n        RegisterState {\n            pc: pc.into(),\n            ap: ap.into(),\n            fp: fp.into(),\n        }\n    }\n}\n\nimpl InstructionState {\n    /// Creates a new set instruction word and operand state\n    pub fn new(\n        inst: Word,\n        inst_size: Felt,\n        dst: Option<Felt>,\n        op0: Option<Felt>,\n        op1: Option<Felt>,\n        res: Option<Felt>,\n        dst_addr: Felt,\n        op0_addr: Felt,\n        op1_addr: Felt,\n    ) -> Self {\n        InstructionState {\n            inst,\n            inst_size,\n            dst,\n            op0,\n            op1,\n            res,\n            dst_addr,\n            op0_addr,\n            op1_addr,\n        }\n    }\n}\n\n#[derive(PartialEq, Eq, Copy, Clone, Debug)]\npub enum Builtin {\n    Output(u64),\n    RangeCheck,\n}\n"
  },
  {
    "path": "core/src/word/helpers.rs",
    "content": "// Modified from https://github.com/o1-labs/proof-systems\n\nuse super::{super::StarkField, Felt};\n//use winter_utils::AsBytes;\n\npub trait FieldHelpers {\n    /// Return field element as byte, if it fits. Otherwise returns least significant byte\n    fn lsb(self) -> u8;\n\n    /// Return pos-th 16-bit chunk as another field element\n    fn chunk_u16(self, pos: usize) -> Felt;\n\n    /// Return first 64 bits of the field element\n    fn to_u64(self) -> u64;\n\n    /// Return a field element in hexadecimal in little endian\n    fn to_hex_le(self) -> String;\n\n    /// Return a vector of field elements from a vector of i128\n    fn vec_to_field(vec: &[i128]) -> Vec<Felt>;\n\n    /// Return a vector of bits\n    fn to_bits(self) -> Vec<bool>;\n}\n\nimpl FieldHelpers for Felt {\n    fn lsb(self) -> u8 {\n        //self.as_bytes()[0]\n        self.as_int().to_le_bytes()[0]\n    }\n\n    fn chunk_u16(self, pos: usize) -> Felt {\n        //let bytes = self.as_bytes();\n        let bytes = self.as_int().to_le_bytes();\n        let chunk = u16::from(bytes[2 * pos]) + u16::from(bytes[2 * pos + 1]) * 2u16.pow(8);\n        Felt::from(chunk)\n    }\n\n    fn to_u64(self) -> u64 {\n        //let bytes = self.as_bytes();\n        let bytes = self.as_int().to_le_bytes();\n        let mut acc: u64 = 0;\n        for i in 0..8 {\n            acc += 2u64.pow(i * 8) * (bytes[i as usize] as u64);\n        }\n        acc\n    }\n\n    fn to_hex_le(self) -> String {\n        let mut bytes = self.as_int().to_le_bytes();\n        bytes.reverse();\n        hex::encode(bytes)\n    }\n\n    fn vec_to_field(vec: &[i128]) -> Vec<Felt> {\n        vec.iter()\n            .map(|i| {\n                if *i < 0 {\n                    -Felt::from((-(*i)) as u64)\n                } else {\n                    Felt::from((*i) as u64)\n                }\n            })\n            .collect()\n    }\n\n    fn to_bits(self) -> Vec<bool> {\n        //self.as_bytes().iter().fold(vec![], |mut bits, byte| {\n        let bytes = self.as_int().to_le_bytes();\n        bytes.iter().fold(vec![], |mut bits, byte| {\n            let mut byte = *byte;\n            for _ in 0..8 {\n                bits.push(byte & 0x01 == 0x01);\n                byte >>= 1;\n            }\n            bits\n        })\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_field_to_bits() {\n        let fe = Felt::from(256u32);\n        let bits = fe.to_bits();\n        println!(\"{:?}\", &bits[0..16]);\n    }\n\n    #[test]\n    fn test_field_to_chunks() {\n        let fe = Felt::from(0x480680017fff8000u64);\n        let chunk = fe.chunk_u16(1);\n        println!(\"chunk {:?}\", chunk);\n        println!(\"chunk2 {:?}\", Felt::from(0x7fffu64));\n        assert_eq!(chunk, Felt::from(0x7fffu64));\n    }\n}\n"
  },
  {
    "path": "core/src/word/mod.rs",
    "content": "// Modified from https://github.com/o1-labs/proof-systems\n\nuse super::{Felt, FieldElement};\nuse crate::flags::*;\n\nmod helpers;\npub use helpers::FieldHelpers;\n\n/// A  word for the runner. Some words are instructions (which fit inside a `u64`). Others are immediate values (any `F` element).\n#[derive(Clone, Copy, Debug)]\npub struct Word(Felt);\n\n/// Returns an offset of 16 bits to its biased representation in the interval `[-2^15,2^15)` as a field element\npub fn bias<E: FieldElement>(offset: E) -> E {\n    offset - E::from(2u16.pow(15u32)) // -2^15 + sum_(i=0..15) b_i * 2^i\n}\n\nimpl Word {\n    /// Creates a [Word] from a field element\n    pub fn new(word: Felt) -> Word {\n        Word(word)\n    }\n\n    /// Returns the content of the word as a field element\n    pub fn word(&self) -> Felt {\n        self.0\n    }\n}\n\npub trait OffsetDecomposition<F> {\n    /// Returns the destination offset in biased representation\n    fn off_dst(&self) -> F;\n\n    /// Returns the first operand offset in biased representation\n    fn off_op0(&self) -> F;\n\n    /// Returns the second operand offset in biased representation\n    fn off_op1(&self) -> F;\n}\n\n/// This trait contains methods that decompose a field element into [Word] components\npub trait FlagDecomposition<F> {\n    /// Returns vector of 16 flags\n    fn flags(&self) -> Vec<F>;\n\n    /// Returns i-th bit-flag\n    fn flag_at(&self, pos: usize) -> F;\n\n    /// Returns bit-flag for destination register as `F`\n    fn f_dst_fp(&self) -> F {\n        self.flag_at(0)\n    }\n\n    /// Returns bit-flag for first operand register as `F`\n    fn f_op0_fp(&self) -> F {\n        self.flag_at(1)\n    }\n\n    /// Returns bit-flag for immediate value for second register as `F`\n    fn f_op1_val(&self) -> F {\n        self.flag_at(2)\n    }\n\n    /// Returns bit-flag for frame pointer for second register as `F`\n    fn f_op1_fp(&self) -> F {\n        self.flag_at(3)\n    }\n\n    /// Returns bit-flag for allocation pointer for second regsiter as `F`\n    fn f_op1_ap(&self) -> F {\n        self.flag_at(4)\n    }\n\n    /// Returns bit-flag for addition operation in right side as `F`\n    fn f_res_add(&self) -> F {\n        self.flag_at(5)\n    }\n\n    /// Returns bit-flag for multiplication operation in right side as `F`\n    fn f_res_mul(&self) -> F {\n        self.flag_at(6)\n    }\n\n    /// Returns bit-flag for program counter update being absolute jump as `F`\n    fn f_pc_abs(&self) -> F {\n        self.flag_at(7)\n    }\n\n    /// Returns bit-flag for program counter update being relative jump as `F`\n    fn f_pc_rel(&self) -> F {\n        self.flag_at(8)\n    }\n\n    /// Returns bit-flag for program counter update being conditional jump as `F`\n    fn f_pc_jnz(&self) -> F {\n        self.flag_at(9)\n    }\n\n    /// Returns bit-flag for allocation counter update being a manual addition as `F`\n    fn f_ap_add(&self) -> F {\n        self.flag_at(10)\n    }\n\n    /// Returns bit-flag for allocation counter update being a self increment as `F`\n    fn f_ap_one(&self) -> F {\n        self.flag_at(11)\n    }\n\n    /// Returns bit-flag for operation being a call as `F`\n    fn f_opc_call(&self) -> F {\n        self.flag_at(12)\n    }\n\n    /// Returns bit-flag for operation being a return as `F`\n    fn f_opc_ret(&self) -> F {\n        self.flag_at(13)\n    }\n\n    /// Returns bit-flag for operation being an assert-equal as `F`\n    fn f_opc_aeq(&self) -> F {\n        self.flag_at(14)\n    }\n\n    /// Returns bit-flag for 16th position\n    fn f15(&self) -> F {\n        self.flag_at(15)\n    }\n}\n\npub trait FlagGroupDecomposition<F> {\n    /// Returns flagset for destination register\n    fn dst_reg(&self) -> u8;\n\n    /// Returns flagset for first operand register\n    fn op0_reg(&self) -> u8;\n\n    /// Returns flagset for second operand register\n    fn op1_src(&self) -> u8;\n\n    /// Returns flagset for result logics\n    fn res_log(&self) -> u8;\n\n    /// Returns flagset for program counter update\n    fn pc_up(&self) -> u8;\n\n    /// Returns flagset for allocation pointer update\n    fn ap_up(&self) -> u8;\n\n    /// Returns flagset for operation code\n    fn opcode(&self) -> u8;\n}\n\nimpl OffsetDecomposition<Felt> for Word {\n    fn off_dst(&self) -> Felt {\n        // The least significant 16 bits\n        bias(self.word().chunk_u16(POS_DST))\n    }\n\n    fn off_op0(&self) -> Felt {\n        // From the 32nd bit to the 17th\n        bias(self.word().chunk_u16(POS_OP0))\n    }\n\n    fn off_op1(&self) -> Felt {\n        // From the 48th bit to the 33rd\n        bias(self.word().chunk_u16(POS_OP1))\n    }\n}\n\nimpl FlagDecomposition<Felt> for Word {\n    fn flags(&self) -> Vec<Felt> {\n        let mut flags = Vec::with_capacity(NUM_FLAGS);\n        // The most significant 16 bits\n        for i in 0..NUM_FLAGS {\n            flags.push(self.flag_at(i));\n        }\n        flags\n    }\n\n    fn flag_at(&self, pos: usize) -> Felt {\n        Felt::from(self.word().to_bits()[POS_FLAGS + pos] as u32)\n    }\n}\n\nimpl FlagGroupDecomposition<Felt> for Word {\n    fn dst_reg(&self) -> u8 {\n        // dst_reg = fDST_REG\n        self.f_dst_fp().lsb()\n    }\n\n    fn op0_reg(&self) -> u8 {\n        // op0_reg = fOP0_REG\n        self.f_op0_fp().lsb()\n    }\n\n    fn op1_src(&self) -> u8 {\n        // op1_src = 4*fOP1_AP + 2*fOP1_FP + fOP1_VAL\n        2 * (2 * self.f_op1_ap().lsb() + self.f_op1_fp().lsb()) + self.f_op1_val().lsb()\n    }\n\n    fn res_log(&self) -> u8 {\n        // res_log = 2*fRES_MUL + fRES_ADD\n        2 * self.f_res_mul().lsb() + self.f_res_add().lsb()\n    }\n\n    fn pc_up(&self) -> u8 {\n        // pc_up = 4*fPC_JNZ + 2*fPC_REL + fPC_ABS\n        2 * (2 * self.f_pc_jnz().lsb() + self.f_pc_rel().lsb()) + self.f_pc_abs().lsb()\n    }\n\n    fn ap_up(&self) -> u8 {\n        // ap_up = 2*fAP_ONE + fAP_ADD\n        2 * self.f_ap_one().lsb() + self.f_ap_add().lsb()\n    }\n\n    fn opcode(&self) -> u8 {\n        // opcode = 4*fOPC_AEQ + 2*fOPC_RET + fOPC_CALL\n        2 * (2 * self.f_opc_aeq().lsb() + self.f_opc_ret().lsb()) + self.f_opc_call().lsb()\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::Felt as F;\n\n    #[test]\n    fn test_biased() {\n        assert_eq!(F::from(1u32), super::bias(F::from(0x8001u32)));\n        assert_eq!(F::from(0u32), super::bias(F::from(0x8000u32)));\n        println!(\"{:?} {:?}\", -F::from(1u32), super::bias(F::from(0x7fffu32)));\n        assert_eq!(-F::from(1u32), super::bias(F::from(0x7fffu32)));\n    }\n}\n"
  },
  {
    "path": "examples/Cargo.toml",
    "content": "[package]\nname = \"examples\"\nversion = \"0.1.0\"\nedition = \"2021\"\nrust-version = \"1.57\"\n\n[[bin]]\nname = \"giza-examples\"\npath = \"src/main.rs\"\nbench = false\ndoctest = false\n\n[dependencies]\nair = { package = \"giza-air\", path = \"../air\", version = \"0.1\", default-features = false }\nprover = { package = \"giza-prover\", path = \"../prover\", version = \"0.1\", default-features = false }\nrunner = { package = \"giza-runner\", path = \"../runner\", version = \"0.1\", default-features = false }\ngiza_core = { package = \"giza-core\", path = \"../core\", version = \"0.1\", default-features = false }\nwinterfell = { package = \"winter-verifier\", git = \"https://github.com/maxgillett/winterfell\", rev = \"0aad6a5\", features = [\"std\"], version = \"0.4\", default-features = false }\n"
  },
  {
    "path": "examples/src/main.rs",
    "content": "use air::{ProcessorAir, ProofOptions};\nuse giza_core::Felt;\nuse runner::{Memory, Program};\n\nfn main() {\n    //  %builtins output\n    //  from starkware.cairo.common.serialize import serialize_word\n    //  func main{output_ptr : felt*}():\n    //      tempvar x = 10\n    //      tempvar y = x + x\n    //      tempvar z = y * y + x\n    //      serialize_word(x)\n    //      serialize_word(y)\n    //      serialize_word(z)\n    //      return ()\n    //  end\n    //  */\n    let instrs: Vec<Felt> = vec![\n        Felt::from(0x400380007ffc7ffdu64),\n        Felt::from(0x482680017ffc8000u64),\n        Felt::from(1u64),\n        Felt::from(0x208b7fff7fff7ffeu64),\n        Felt::from(0x480680017fff8000u64),\n        Felt::from(10u64),\n        Felt::from(0x48307fff7fff8000u64),\n        Felt::from(0x48507fff7fff8000u64),\n        Felt::from(0x48307ffd7fff8000u64),\n        Felt::from(0x480a7ffd7fff8000u64),\n        Felt::from(0x48127ffb7fff8000u64),\n        Felt::from(0x1104800180018000u64),\n        -Felt::from(11u64),\n        Felt::from(0x48127ff87fff8000u64),\n        Felt::from(0x1104800180018000u64),\n        -Felt::from(14u64),\n        Felt::from(0x48127ff67fff8000u64),\n        Felt::from(0x1104800180018000u64),\n        -Felt::from(17u64),\n        //Felt::from(0x208b7fff7fff7ffeu64),\n        Felt::from(0x10780017fff7fffu64), // infinite loop\n    ];\n    let mut mem = Memory::new(instrs);\n    mem.write_pub(Felt::from(21u32), Felt::from(41u32)); // beginning of output\n    mem.write_pub(Felt::from(22u32), Felt::from(44u32)); // end of output\n    mem.write_pub(Felt::from(23u32), Felt::from(44u32)); // end of program\n\n    // run the program to create an execution trace\n    let mut program = Program::new(&mut mem, 5, 24);\n    let trace = program.execute().unwrap();\n\n    // generate the proof of execution\n    let proof_options = ProofOptions::with_proof_options(None, None, None, None, None);\n    let (proof, pub_inputs) = prover::prove_trace(trace, &proof_options).unwrap();\n    let proof_bytes = proof.to_bytes();\n    println!(\"Proof size: {:.1} KB\", proof_bytes.len() as f64 / 1024f64);\n\n    // verify correct program execution\n    match winterfell::verify::<ProcessorAir>(proof, pub_inputs) {\n        Ok(_) => println!(\"Execution verified\"),\n        Err(err) => println!(\"Failed to verify execution: {}\", err),\n    }\n}\n"
  },
  {
    "path": "program.json",
    "content": ""
  },
  {
    "path": "prover/Cargo.toml",
    "content": "[package]\nname = \"giza-prover\"\nversion = \"0.1.0\"\nedition = \"2021\"\nrust-version = \"1.57\"\n\n[dependencies]\nair = { package = \"giza-air\", path = \"../air\", version = \"0.1\", default-features = false }\nprover = { package = \"winter-prover\", git = \"https://github.com/maxgillett/winterfell\", rev = \"0aad6a5\", version = \"0.4\", features = [\"concurrent\"], default-features = false }\nrunner = { package = \"giza-runner\", path = \"../runner\", version = \"0.1\", default-features = false }\ngiza_core = { package = \"giza-core\", path = \"../core\", version = \"0.1\", default-features = false }\n"
  },
  {
    "path": "prover/src/lib.rs",
    "content": "use air::{ProcessorAir, PublicInputs};\nuse giza_core::{Felt, RegisterState, MEM_A_TRACE_OFFSET, MEM_P_TRACE_OFFSET};\nuse prover::{Prover, Trace};\nuse runner::{ExecutionError, ExecutionTrace};\n\n// EXPORTS\n// ================================================================================================\n\npub use air::{FieldExtension, HashFunction, ProofOptions};\npub use prover::StarkProof;\n\n// EXECUTOR\n// ================================================================================================\n\n/// Proves an execution trace and returns the result together with a STARK-based proof\n/// of execution.\npub fn prove_trace(\n    trace: ExecutionTrace,\n    options: &ProofOptions,\n) -> Result<(StarkProof, PublicInputs), ExecutionError> {\n    let prover = ExecutionProver::new(options.clone());\n    let public_inputs = prover.get_pub_inputs(&trace);\n    let proof = prover.prove(trace).map_err(ExecutionError::ProverError)?;\n    Ok((proof, public_inputs))\n}\n\n// PROVER\n// ================================================================================================\n\npub struct ExecutionProver {\n    options: ProofOptions,\n}\n\nimpl ExecutionProver {\n    pub fn new(options: ProofOptions) -> Self {\n        Self { options }\n    }\n}\n\nimpl Prover for ExecutionProver {\n    type BaseField = Felt;\n    type Air = ProcessorAir;\n    type Trace = ExecutionTrace;\n\n    fn options(&self) -> &prover::ProofOptions {\n        &self.options\n    }\n\n    fn get_pub_inputs(&self, trace: &ExecutionTrace) -> PublicInputs {\n        let last_step = trace.num_steps - 1;\n\n        let pc_init = trace.main_segment().get(MEM_A_TRACE_OFFSET, 0);\n        let ap_init = trace.main_segment().get(MEM_P_TRACE_OFFSET, 0);\n        let init = RegisterState::new(pc_init, ap_init, ap_init);\n\n        let pc_fin = trace.main_segment().get(MEM_A_TRACE_OFFSET, last_step);\n        let ap_fin = trace.main_segment().get(MEM_P_TRACE_OFFSET, last_step);\n        let fin = RegisterState::new(pc_fin, ap_fin, ap_fin);\n\n        let rc_min = trace.rc_min;\n        let rc_max = trace.rc_max;\n\n        let mem = trace.get_public_mem();\n\n        PublicInputs::new(\n            init,\n            fin,\n            rc_min,\n            rc_max,\n            mem,\n            trace.num_steps,\n            trace.builtins.clone(),\n        )\n    }\n}\n"
  },
  {
    "path": "runner/Cargo.toml",
    "content": "[package]\nname = \"giza-runner\"\nversion = \"0.1.0\"\nedition = \"2021\"\nrust-version = \"1.57\"\n\n[lib]\nbench = false\ndoctest = false\n\n[dependencies]\nair = { package = \"giza-air\", path = \"../air\", version = \"0.1\", default-features = false }\ngiza_core = { package = \"giza-core\", path = \"../core\", version = \"0.1\", default-features = false }\nwinterfell = { package = \"winter-prover\", git = \"https://github.com/maxgillett/winterfell\", rev = \"0aad6a5\", version = \"0.4\", features = [\"concurrent\"], default-features = false }\nserde = { version = \"1.0.136\", features = [\"derive\"] }\nserde_json = \"1.0.79\"\nitertools = \"0.10.3\"\nhex = \"0.4\"\npyo3 = { package = \"pyo3\", version = \"0.16.3\", features = [\"auto-initialize\"], optional = true }\nindicatif = {version = \"*\", features = [\"rayon\"]}\nrayon = \"1.5.3\"\n\n[features]\nhints = [\"dep:pyo3\"]\n\n"
  },
  {
    "path": "runner/src/cairo_interop.rs",
    "content": "/// Code for parsing the outputs of Starkware's cairo-runner.\n/// Note the following:\n/// - Field elements are encoded in little-endian byte order.\n/// - Cairo serializes field elements as 32 bytes (the program\n///   prime is assumed to be equal to the 252-bit Starkware prime).\n///\nuse crate::memory::Memory;\nuse giza_core::{Builtin, Felt, RegisterState, Word};\nuse serde::{Deserialize, Serialize};\nuse std::fs::{metadata, File};\nuse std::io::{BufReader, Read};\nuse std::path::PathBuf;\n\n#[derive(Serialize, Deserialize)]\nstruct CompiledProgram {\n    builtins: Vec<String>,\n    data: Vec<String>,\n    prime: String,\n}\n\n/// Parses an execution trace outputted by the cairo-runner.\n/// e.g. cairo-runner --trace_file out/trace.bin\npub fn read_trace_bin(path: &PathBuf) -> Vec<RegisterState> {\n    let mut f = File::open(&path).expect(\"no file found\");\n    let metadata = metadata(&path).expect(\"unable to read metadata\");\n    let length = metadata.len() as usize;\n\n    // Buffer for register values\n    let mut pc: [u8; 8] = Default::default();\n    let mut ap: [u8; 8] = Default::default();\n    let mut fp: [u8; 8] = Default::default();\n\n    let mut ptrs: Vec<RegisterState> = vec![];\n    let mut bytes_read = 0;\n    while bytes_read < length {\n        bytes_read += f.read(&mut ap).unwrap();\n        bytes_read += f.read(&mut fp).unwrap();\n        bytes_read += f.read(&mut pc).unwrap();\n        let reg = RegisterState::new(\n            u64::from_le_bytes(pc),\n            u64::from_le_bytes(ap),\n            u64::from_le_bytes(fp),\n        );\n        ptrs.push(reg);\n    }\n\n    //print_registers(&ptrs);\n\n    ptrs\n}\n\n/// Parses a memory dump outputted by the cairo-runner.\n/// e.g. cairo-runner --memory_file out/memory.bin\npub fn read_memory_bin(mem_path: &PathBuf, program_path: &PathBuf) -> Memory {\n    // Read memory trace\n    let mut f = File::open(&mem_path).expect(\"Memory trace file not found\");\n    let metadata = metadata(&mem_path).expect(\"Unable to read metadata\");\n    let length = metadata.len() as usize;\n\n    // Buffer for memory accesses\n    let mut address: [u8; 8] = Default::default();\n    let mut value: [u8; 32] = Default::default();\n\n    let mut mem = Memory::new(vec![]).clone();\n    let mut bytes_read = 0;\n    while bytes_read < length {\n        bytes_read += f.read(&mut address).unwrap();\n        bytes_read += f.read(&mut value).unwrap();\n        mem.write(\n            Felt::try_from(u64::from_le_bytes(address)).unwrap(),\n            Felt::try_from(value).unwrap(),\n        );\n    }\n\n    // Read compiled program and set memory codelen (the length of the public memory)\n    let file = File::open(&program_path).expect(\"Compiled program file not found\");\n    let reader = BufReader::new(file);\n    let p: CompiledProgram = serde_json::from_reader(reader).unwrap();\n    mem.set_codelen(p.data.len());\n\n    //print_memory(&mem);\n\n    mem\n}\n\npub fn read_builtins(program_path: &PathBuf, output_len: Option<u64>) -> Vec<Builtin> {\n    // Read compiled program and set memory codelen (the length of the public memory)\n    let file = File::open(&program_path).expect(\"Compiled program file not found\");\n    let reader = BufReader::new(file);\n    let p: CompiledProgram = serde_json::from_reader(reader).unwrap();\n    let builtins = p\n        .builtins\n        .iter()\n        .filter_map(|b| match b.as_str() {\n            \"output\" => Some(Builtin::Output(output_len.unwrap())),\n            _ => None,\n        })\n        .collect::<Vec<_>>();\n    builtins\n}\n\nfn print_registers(reg: &[RegisterState]) {\n    for (n, r) in reg.iter().enumerate() {\n        println!(\"{} {} {} {}\", n, r.pc, r.ap, r.fp,);\n    }\n}\n\nfn print_memory(mem: &Memory) {\n    for n in 0..mem.size() as usize {\n        println!(\n            \"{} {}\",\n            n,\n            mem.data[n].unwrap_or(Word::new(Felt::from(0u8))).word()\n        );\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_trace_bin() {\n        let trace = read_trace_bin(&PathBuf::from(\"../tmp/trace.bin\"));\n        println!(\"{:?}\", trace);\n    }\n\n    #[test]\n    fn test_memory_bin() {\n        let mem = read_memory_bin(\n            &PathBuf::from(\"../tmp/memory.bin\"),\n            &PathBuf::from(\"../tmp/program.json\"),\n        );\n        println!(\"{:?}\", mem.data);\n    }\n}\n"
  },
  {
    "path": "runner/src/errors.rs",
    "content": "use winterfell::ProverError;\n\n#[derive(Debug)]\npub enum ExecutionError {\n    ProverError(ProverError),\n}\n"
  },
  {
    "path": "runner/src/hints.rs",
    "content": "use crate::memory::Memory;\nuse crate::runner::Step;\nuse giza_core::{Felt, StarkField, Word};\n\nuse pyo3::conversion::{FromPyObject, ToPyObject};\nuse pyo3::prelude::*;\nuse pyo3::types::PyDict;\nuse serde::{Deserialize, Serialize};\nuse std::collections::HashMap;\nuse std::convert::TryInto;\n\n#[derive(Default)]\npub struct HintManager {\n    pub hints: HashMap<u64, Vec<Hint>>,\n}\n\nimpl HintManager {\n    pub fn push_hint(&mut self, pc: u64, hint: Hint) {\n        self.hints.entry(pc).or_default().push(hint);\n    }\n    pub fn get_hints(&self, pc: Felt) -> Option<&Vec<Hint>> {\n        let pc: u64 = pc.as_int().try_into().unwrap();\n        self.hints.get(&pc)\n    }\n}\n\n#[derive(Serialize, Deserialize)]\npub struct Hint {\n    code: String,\n    accessible_scopes: Vec<String>,\n    flow_tracking_data: Option<FlowTrackingData>,\n}\n\nimpl Hint {\n    pub fn new(\n        code: String,\n        accessible_scopes: Vec<String>,\n        flow_tracking_data: Option<FlowTrackingData>,\n    ) -> Self {\n        Hint {\n            code,\n            accessible_scopes,\n            flow_tracking_data,\n        }\n    }\n}\n\n#[derive(Serialize, Deserialize)]\npub struct FlowTrackingData {\n    ap_tracking: ApTracking,\n    reference_ids: HashMap<String, u64>,\n}\n\n#[derive(Serialize, Deserialize)]\npub struct ApTracking {\n    group: u64,\n    offset: u64,\n}\n\n#[derive(Default, Debug)]\npub struct MemoryUpdate(pub Vec<(u64, Word)>);\n\n/// Data structure containing all register and memory updates effected by hint execution\n#[derive(Default, Debug)]\npub struct ExecutionEffect {\n    pub pc: Felt,\n    pub ap: Felt,\n    pub fp: Felt,\n    pub mem_updates: Option<MemoryUpdate>,\n}\n\nimpl Hint {\n    /// Run hint code in a Python environment, and return the aggregated effect\n    /// on program state\n    pub fn exec(&self, step: &Step) -> PyResult<ExecutionEffect> {\n        // TODO: Import Cairo toolchain and monkey patch methods\n        // (e.g. reference manager setter method) to track memory updates\n        Python::with_gil(|py| {\n            let locals = PyDict::new(py);\n            locals.set_item(\n                \"pc\",\n                TryInto::<u64>::try_into(step.curr.pc.as_int()).unwrap(),\n            )?;\n            locals.set_item(\n                \"ap\",\n                TryInto::<u64>::try_into(step.curr.ap.as_int()).unwrap(),\n            )?;\n            locals.set_item(\n                \"fp\",\n                TryInto::<u64>::try_into(step.curr.fp.as_int()).unwrap(),\n            )?;\n            locals.set_item(\"memory\", &*step.mem)?;\n            locals.set_item(\"memory_updates\", PyDict::new(py))?;\n            py.run(self.code.as_str(), None, Some(&locals))\n                .expect(\"error executing hint code\");\n            ExecutionEffect::from_locals(locals)\n        })\n    }\n}\n\nimpl ExecutionEffect {\n    fn from_locals(locals: &PyDict) -> PyResult<ExecutionEffect> {\n        let pc = locals.get_item(\"pc\").unwrap().extract::<u64>()?;\n        let ap = locals.get_item(\"ap\").unwrap().extract::<u64>()?;\n        let fp = locals.get_item(\"fp\").unwrap().extract::<u64>()?;\n        let mem_updates: Option<MemoryUpdate> = locals\n            .get_item(\"memory_updates\")\n            .unwrap()\n            .extract::<MemoryUpdate>()\n            .ok();\n        Ok(ExecutionEffect {\n            pc: Felt::from(pc),\n            ap: Felt::from(ap),\n            fp: Felt::from(fp),\n            mem_updates,\n        })\n    }\n}\n\nimpl<'a> FromPyObject<'a> for MemoryUpdate {\n    fn extract(dict: &PyAny) -> PyResult<Self> {\n        let mut mem_update = MemoryUpdate::default();\n        for (key, val) in dict.downcast::<PyDict>()?.iter() {\n            mem_update.0.push((\n                key.extract::<u64>()?,\n                Word::new(Felt::from(val.extract::<u128>()?)),\n            ));\n        }\n        Ok(mem_update)\n    }\n}\n\nimpl ToPyObject for Memory {\n    fn to_object(&self, py: Python) -> PyObject {\n        let dict = PyDict::new(py);\n        dict.into()\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use giza_core::{Felt, RegisterState};\n\n    #[test]\n    fn test_hint_execution() {\n        let mut memory = Memory::new(vec![]);\n        memory.write(Felt::from(memory.size()), Felt::from(1u64));\n        memory.write(Felt::from(memory.size()), Felt::from(2u64));\n        println!(\"{}\", memory);\n        let step = Step::new(\n            &mut memory,\n            None,\n            RegisterState::new(Felt::from(1u64), Felt::from(1u64), Felt::from(1u64)),\n        );\n        let hint = Hint::new(String::from(\"pc = 2; ap = 5; memory[1] = 10\"), vec![], None);\n        let res = hint.exec(&step);\n        println!(\"res {:?}\", res);\n    }\n}\n"
  },
  {
    "path": "runner/src/lib.rs",
    "content": "pub mod memory;\npub use memory::Memory;\n\npub mod runner;\npub use runner::Program;\n\n#[cfg(feature = \"hints\")]\npub mod hints;\n\nmod trace;\npub use trace::ExecutionTrace;\n\nmod errors;\npub use errors::ExecutionError;\n\nmod cairo_interop;\n"
  },
  {
    "path": "runner/src/memory.rs",
    "content": "// Modified from https://github.com/o1-labs/proof-systems\n\nuse std::convert::TryInto;\nuse std::fmt::{Display, Formatter, Result};\nuse std::ops::{Index, IndexMut};\n\nuse core::iter::repeat;\nuse giza_core::{Felt, FieldHelpers, StarkField, Word};\n\n/// This data structure stores the memory of the program\n#[derive(Clone)]\npub struct Memory {\n    /// length of the public memory\n    codelen: usize,\n    /// full memory vector, None if non initialized\n    pub data: Vec<Option<Word>>,\n}\n\nimpl Index<Felt> for Memory {\n    type Output = Option<Word>;\n    fn index(&self, idx: Felt) -> &Self::Output {\n        let addr: u64 = idx.to_u64();\n        &self.data[addr as usize]\n    }\n}\n\nimpl IndexMut<Felt> for Memory {\n    fn index_mut(&mut self, idx: Felt) -> &mut Self::Output {\n        let addr: u64 = idx.to_u64();\n        self.resize(addr);\n        &mut self.data[addr as usize]\n    }\n}\n\nimpl Display for Memory {\n    fn fmt(&self, f: &mut Formatter<'_>) -> Result {\n        for i in 1..self.size() {\n            // Visualize content of memory\n            if let Some(elem) = self[Felt::from(i as u64)] {\n                if writeln!(f, \"{0:>6}: 0x{1:}\", i, elem.word().to_hex_le()).is_err() {\n                    println!(\"Error while writing\")\n                }\n            } else if writeln!(f, \"{0:>6}: None\", i).is_err() {\n                println!(\"Error while writing\")\n            }\n        }\n        Ok(())\n    }\n}\n\nimpl Memory {\n    /// Create a new memory structure from a vector of field elements\n    pub fn new(input: Vec<Felt>) -> Memory {\n        // Initialized with the public memory (compiled instructions only)\n        let mut aux = vec![Felt::from(0u8)];\n        aux.extend(input);\n        Memory {\n            codelen: aux.len(),\n            data: aux.into_iter().map(|i| Some(Word::new(i))).collect(),\n        }\n    }\n\n    /// Get size of the public memory\n    pub fn get_codelen(&self) -> usize {\n        self.codelen\n    }\n\n    /// Set size of the public memory\n    pub fn set_codelen(&mut self, len: usize) {\n        self.codelen = len;\n    }\n\n    /// Get size of the full memory\n    pub fn size(&self) -> u64 {\n        self.data.len() as u64\n    }\n\n    /// Resizes memory with enough additional None slots if necessary before writing or reading\n    fn resize(&mut self, addr: u64) {\n        if let Some(additional) = addr.checked_sub(self.size() - 1) {\n            self.data.extend(repeat(None).take(additional as usize));\n        }\n    }\n\n    /// Write u64 element in memory address\n    pub fn write(&mut self, addr: Felt, elem: Felt) {\n        self[addr] = Some(Word::new(elem));\n    }\n\n    /// Write u64 element in memory address\n    pub fn write_pub(&mut self, addr: Felt, elem: Felt) {\n        self.write(addr, elem);\n        self.codelen += 1;\n    }\n\n    /// Read element in memory address\n    pub fn read(&self, addr: Felt) -> Option<Felt> {\n        //self.resize(addr.to_u64()); // Resize if necessary\n        self[addr].map(|x| x.word())\n    }\n\n    /// Returns a list of all memory holes (defined as missing private memory\n    /// accesses from the provided trace vec)\n    /// TODO: Memory should be stored as a BTreeMap in data, not a Vec.\n    pub fn get_holes(&self, vec: Vec<Felt>) -> Vec<Felt> {\n        let mut accesses = vec\n            .iter()\n            .map(|x| TryInto::<u64>::try_into(x.as_int()).unwrap())\n            .collect::<Vec<_>>();\n        accesses.sort_unstable();\n\n        let mut holes = vec![];\n        for s in accesses.windows(2) {\n            match s[1] - s[0] {\n                0 | 1 => {}\n                _ => {\n                    if s[0] > self.codelen as u64 {\n                        holes.extend((s[0] + 1..s[1]).map(|x| Felt::from(x)).collect::<Vec<_>>());\n                    }\n                }\n            }\n        }\n        holes\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::Felt as F;\n    use super::*;\n    use giza_core::{Felt, FieldHelpers, Word};\n\n    #[test]\n    fn test_cairo_bytecode() {\n        // This test starts with the public memory corresponding to a simple  program\n        // func main{}():\n        //    tempvar x = 10;\n        //    return()\n        // end\n        // And checks that memory writing and reading works as expected by completing\n        // the total memory of executing the program\n        let instrs = vec![\n            F::from(0x480680017fff8000u64),\n            F::from(10u64),\n            F::from(0x208b7fff7fff7ffeu64),\n        ];\n        let mut memory = Memory::new(instrs);\n        memory.write(F::from(memory.size() as u64), F::from(7u64));\n        memory.write(F::from(memory.size() as u64), F::from(7u64));\n        memory.write(F::from(memory.size() as u64), F::from(10u64));\n        println!(\"{}\", memory);\n        // Check content of an address\n        assert_eq!(\n            memory.read(F::from(1u32)).unwrap(),\n            F::from(0x480680017fff8000u64)\n        );\n        // Check that the program contained 3 words\n        assert_eq!(3, memory.get_codelen());\n        // Check we have 6 words, excluding the dummy entry\n        assert_eq!(6, memory.size() - 1);\n        memory.read(F::from(10u32));\n    }\n}\n"
  },
  {
    "path": "runner/src/runner.rs",
    "content": "// Modified from https://github.com/o1-labs/proof-systems\n\nuse crate::errors::ExecutionError;\nuse crate::memory::Memory;\nuse crate::trace::ExecutionTrace;\nuse giza_core::{flags::*, *};\n\n#[cfg(feature = \"hints\")]\nuse crate::hints::{ExecutionEffect as HintExecutionEffect, HintManager};\n\n/// A data structure to store a current step of computation\npub struct Step<'a> {\n    pub mem: &'a Memory,\n    pub curr: RegisterState,\n    pub next: Option<RegisterState>,\n    #[cfg(feature = \"hints\")]\n    hints: Option<&'a HintManager>,\n}\n\nimpl<'a> Step<'a> {\n    /// Creates a new execution step from a step index, a word, and current pointers\n    pub fn new(mem: &'a Memory, ptrs: RegisterState) -> Step<'a> {\n        Step {\n            mem,\n            curr: ptrs,\n            next: None,\n        }\n    }\n\n    /// Executes a step from the current registers and returns the instruction state\n    pub fn execute(&mut self, write: bool) -> InstructionState {\n        // Execute hints and apply changes\n        #[cfg(feature = \"hints\")]\n        self.execute_hints();\n\n        // Execute instruction\n        let (op0_addr, mut op0) = self.set_op0();\n        let (op1_addr, mut op1, size) = self.set_op1(op0);\n        let (dst_addr, mut dst) = self.set_dst();\n        let mut res = self.set_res(op0, op1, dst);\n        let next_pc = self.next_pc(size, res, dst, op1);\n        let (next_ap, next_fp, op0_update, op1_update, res_update, dst_update) =\n            self.next_apfp(size, res, dst, dst_addr, op1_addr, write);\n        if op0_update.is_some() {\n            op0 = op0_update;\n        }\n        if op1_update.is_some() {\n            op1 = op1_update;\n        }\n        if res_update.is_some() {\n            res = res_update;\n        }\n        if dst_update.is_some() {\n            dst = dst_update;\n        }\n        self.next = Some(RegisterState::new(\n            next_pc.expect(\"Empty next program counter\"),\n            next_ap.expect(\"Empty next allocation pointer\"),\n            next_fp.expect(\"Empty next frame pointer\"),\n        ));\n        InstructionState::new(\n            self.inst(),\n            size,\n            dst,\n            op0,\n            op1,\n            res,\n            dst_addr,\n            op0_addr,\n            op1_addr,\n        )\n    }\n\n    #[cfg(feature = \"hints\")]\n    fn set_hint_manager(&mut self, hints: &'a HintManager) {\n        self.hints = hints;\n    }\n\n    #[cfg(feature = \"hints\")]\n    fn execute_hints(&mut self) {\n        if let Some(manager) = self.hints {\n            for hint in manager.get_hints(self.curr.pc).into_iter().flatten() {\n                let changes = hint.exec(&self).unwrap();\n                self.apply_hint_effects(changes);\n            }\n        }\n    }\n\n    #[cfg(feature = \"hints\")]\n    fn apply_hint_effects(&mut self, res: HintExecutionEffect) {\n        self.curr.pc = res.pc;\n        self.curr.ap = res.ap;\n        self.curr.fp = res.fp;\n        if let Some(updates) = res.mem_updates {\n            for (addr, elem) in updates.0.iter() {\n                self.mem.write(Felt::from(*addr), elem.word());\n            }\n        }\n    }\n\n    /// This function returns the current word instruction being executed\n    fn inst(&mut self) -> Word {\n        Word::new(self.mem.read(self.curr.pc).expect(\"pc points to None cell\"))\n    }\n\n    /// This function computes the first operand address.\n    /// Outputs: `(op0_addr, op0)`\n    fn set_op0(&mut self) -> (Felt, Option<Felt>) {\n        let reg = match self.inst().op0_reg() {\n            /*0*/ OP0_AP => self.curr.ap, // reads first word from allocated memory\n            /*1*/ _ => self.curr.fp, // reads first word from input stack\n        };\n        let op0_addr = reg + self.inst().off_op0();\n        let op0 = self.mem.read(op0_addr);\n        (op0_addr, op0)\n    }\n\n    /// This function computes the second operand address and content and the instruction size\n    /// Panics if the flagset `OP1_SRC` has more than 1 nonzero bit\n    /// Inputs: `op0`\n    /// Outputs: `(op1_addr, op1, size)`\n    fn set_op1(&mut self, op0: Option<Felt>) -> (Felt, Option<Felt>, Felt) {\n        let (reg, size) = match self.inst().op1_src() {\n            /*0*/\n            OP1_DBL => (op0.expect(\"None op0 for OP1_DBL\"), Felt::ONE), // double indexing, op0 should be positive for address\n            /*1*/\n            OP1_VAL => (self.curr.pc, Felt::TWO), // off_op1 will be 1 and then op1 contains an immediate value\n            /*2*/ OP1_FP => (self.curr.fp, Felt::ONE),\n            /*4*/ OP1_AP => (self.curr.ap, Felt::ONE),\n            _ => panic!(\"Invalid op1_src flagset\"),\n        };\n        let op1_addr = reg + self.inst().off_op1(); // apply second offset to corresponding register\n        let op1 = self.mem.read(op1_addr);\n        (op1_addr, op1, size)\n    }\n\n    /// This function computes the value of the result of the arithmetic operation\n    /// Panics if a `jnz` instruction is used with an invalid format\n    ///     or if the flagset `RES_LOG` has more than 1 nonzero bit\n    /// Inputs: `op0`, `op1`\n    /// Outputs: `res`\n    fn set_res(&mut self, op0: Option<Felt>, op1: Option<Felt>, dst: Option<Felt>) -> Option<Felt> {\n        let res;\n        if self.inst().pc_up() == PC_JNZ {\n            /*4*/\n            // jnz instruction\n            if self.inst().res_log() == RES_ONE /*0*/\n                && self.inst().opcode() == OPC_JMP_INC /*0*/\n                && self.inst().ap_up() != AP_ADD\n            /* not 1*/\n            {\n                // in the context of a jnz instruction, the res register is unused, so we repurpose\n                // it to hold the value v = dst^(-1), which is used in the pc update constraint\n                let dst = dst.expect(\"None dst after JNZ\");\n                if dst == Felt::ZERO {\n                    res = Some(dst)\n                } else {\n                    res = Some(dst.inv());\n                }\n            } else {\n                panic!(\"Invalid JNZ instruction\");\n            }\n        } else if self.inst().pc_up() == PC_SIZ /*0*/\n            || self.inst().pc_up() == PC_ABS /*1*/\n            || self.inst().pc_up() == PC_REL\n        /*2*/\n        {\n            // rest of types of updates\n            // common increase || absolute jump || relative jump\n            res = {\n                match self.inst().res_log() {\n                    /*0*/\n                    RES_ONE => op1, // right part is single operand\n                    /*1*/\n                    RES_ADD => Some(\n                        op0.expect(\"None op0 after RES_ADD\") + op1.expect(\"None op1 after RES_ADD\"),\n                    ), // right part is addition\n                    /*2*/\n                    RES_MUL => Some(\n                        op0.expect(\"None op0 after RES_MUL\") * op1.expect(\"None op1 after RES_MUL\"),\n                    ), // right part is multiplication\n                    _ => panic!(\"Invalid res_log flagset\"),\n                }\n            };\n        } else {\n            // multiple bits take value 1\n            panic!(\"Invalid pc_up flagset\");\n        }\n        res\n    }\n\n    /// This function computes the destination address\n    /// Outputs: `(dst_addr, dst)`\n    fn set_dst(&mut self) -> (Felt, Option<Felt>) {\n        let reg = match self.inst().dst_reg() {\n            /*0*/ DST_AP => self.curr.ap, // read from stack\n            /*1*/ _ => self.curr.fp, // read from parameters\n        };\n        let dst_addr = reg + self.inst().off_dst();\n        let dst = self.mem.read(dst_addr);\n        (dst_addr, dst)\n    }\n\n    /// This function computes the next program counter\n    /// Panics if the flagset `PC_UP` has more than 1 nonzero bit\n    /// Inputs: `size`, `res`, `dst`, `op1`,\n    /// Outputs: `next_pc`\n    fn next_pc(\n        &mut self,\n        size: Felt,\n        res: Option<Felt>,\n        dst: Option<Felt>,\n        op1: Option<Felt>,\n    ) -> Option<Felt> {\n        match self.inst().pc_up() {\n            /*0*/\n            PC_SIZ => Some(self.curr.pc + size), // common case, next instruction is right after the current one\n            /*1*/\n            PC_ABS => Some(res.expect(\"None res after PC_ABS\")), // absolute jump, next instruction is in res,\n            /*2*/\n            PC_REL => Some(self.curr.pc + res.expect(\"None res after PC_REL\")), // relative jump, go to some address relative to pc\n            /*4*/\n            PC_JNZ => {\n                // conditional relative jump (jnz)\n                if dst == Some(Felt::ZERO) {\n                    // if condition false, common case\n                    Some(self.curr.pc + size)\n                } else {\n                    // if condition true, relative jump with second operand\n                    Some(self.curr.pc + op1.expect(\"None op1 after PC_JNZ\"))\n                }\n            }\n            _ => panic!(\"Invalid pc_up flagset\"),\n        }\n    }\n\n    /// This function computes the next values of the allocation and frame pointers\n    /// Panics if in a `call` instruction the flagset [AP_UP] is incorrect\n    ///     or if in any other instruction the flagset AP_UP has more than 1 nonzero bit\n    ///     or if the flagset `OPCODE` has more than 1 nonzero bit\n    /// Inputs: `size`, `res`, `dst`, `dst_addr`, `op1_addr`\n    /// Outputs: `(next_ap, next_fp, op0_update, op1_update, res_update, dst_update)`\n    fn next_apfp(\n        &mut self,\n        size: Felt,\n        res: Option<Felt>,\n        dst: Option<Felt>,\n        dst_addr: Felt,\n        op1_addr: Felt,\n        write: bool,\n    ) -> (\n        Option<Felt>,\n        Option<Felt>,\n        Option<Felt>,\n        Option<Felt>,\n        Option<Felt>,\n        Option<Felt>,\n    ) {\n        let (next_ap, next_fp);\n        let mut op0_update = None;\n        let mut op1_update = None;\n        let mut res_update = None;\n        let mut dst_update = None;\n        if self.inst().opcode() == OPC_CALL {\n            /*1*/\n            // \"call\" instruction\n            if write {\n                //self.mem.write(self.curr.ap, self.curr.fp);\n                //self.mem\n                //    .write(self.curr.ap + Felt::ONE, self.curr.pc + size);\n            } else {\n                let expected_a = self.mem.read(self.curr.ap).unwrap();\n                let expected_b = self.mem.read(self.curr.ap + Felt::ONE).unwrap();\n                assert_eq!(expected_a, self.curr.fp);\n                assert_eq!(expected_b, self.curr.pc + size);\n            }\n\n            dst_update = self.mem.read(self.curr.ap);\n            op0_update = self.mem.read(self.curr.ap + Felt::ONE);\n\n            // Update fp\n            // pointer for next frame is after current fp and instruction after call\n            next_fp = Some(self.curr.ap + Felt::TWO);\n\n            // Update ap\n            match self.inst().ap_up() {\n                /*0*/\n                AP_Z2 => next_ap = Some(self.curr.ap + Felt::TWO), // two words were written so advance 2 positions\n                _ => panic!(\"ap increment in call instruction\"),\n            };\n        } else if self.inst().opcode() == OPC_JMP_INC /*0*/\n            || self.inst().opcode() == OPC_RET /*2*/\n            || self.inst().opcode() == OPC_AEQ\n        /*4*/\n        {\n            // rest of types of instruction\n            // jumps and increments || return || assert equal\n            match self.inst().ap_up() {\n                /*0*/ AP_Z2 => next_ap = Some(self.curr.ap), // no modification on ap\n                /*1*/\n                AP_ADD => {\n                    // ap += <op> should be larger than current ap\n                    next_ap = Some(self.curr.ap + res.expect(\"None res after AP_ADD\"))\n                }\n                /*2*/ AP_ONE => next_ap = Some(self.curr.ap + Felt::ONE), // ap++\n                _ => panic!(\"Invalid ap_up flagset\"),\n            }\n\n            match self.inst().opcode() {\n                /*0*/\n                OPC_JMP_INC => next_fp = Some(self.curr.fp), // no modification on fp\n                /*2*/\n                OPC_RET => next_fp = Some(dst.expect(\"None dst after OPC_RET\")), // ret sets fp to previous fp that was in [ap-2]\n                /*4*/\n                OPC_AEQ => {\n                    // The following conditional is a fix that is not explained in the whitepaper\n                    // The goal is to distinguish two types of ASSERT_EQUAL where one checks that\n                    // dst = res , but in order for this to be true, one sometimes needs to write\n                    // the res in mem(dst_addr) and sometimes write dst in mem(res_dir). The only\n                    // case where res can be None is when res = op1 and thus res_dir = op1_addr\n                    if res.is_none() {\n                        // res = dst\n                        if write {\n                            //self.mem\n                            //    .write(op1_addr, dst.expect(\"None dst after OPC_AEQ\"));\n                        } else {\n                            let expected_a = self.mem.read(op1_addr).unwrap();\n                            assert_eq!(expected_a, dst.unwrap());\n                        }\n                        op1_update = self.mem.read(op1_addr);\n                        res_update = self.mem.read(op1_addr);\n                    } else {\n                        // dst = res\n                        if write {\n                            //self.mem\n                            //    .write(dst_addr, res.expect(\"None res after OPC_AEQ\"));\n                        } else {\n                            let expected_a = self.mem.read(dst_addr).unwrap();\n                            assert_eq!(expected_a, res.unwrap());\n                        }\n                        dst_update = self.mem.read(dst_addr);\n                    }\n                    next_fp = Some(self.curr.fp); // no modification on fp\n                }\n                _ => {\n                    panic!(\"This case must never happen\")\n                }\n            }\n        } else {\n            panic!(\"Invalid opcode flagset\");\n        }\n        (\n            next_ap, next_fp, op0_update, op1_update, res_update, dst_update,\n        )\n    }\n}\n\n/// Trace-friendly record of registers and instruction state across\n/// all program execution steps\npub struct State {\n    pub flags: [Vec<Felt>; FLAG_TRACE_WIDTH],\n    pub res: [Vec<Felt>; RES_TRACE_WIDTH],\n    pub mem_p: [Vec<Felt>; MEM_P_TRACE_WIDTH],\n    pub mem_a: [Vec<Felt>; MEM_A_TRACE_WIDTH],\n    pub mem_v: [Vec<Felt>; MEM_V_TRACE_WIDTH],\n    pub offsets: [Vec<Felt>; OFF_X_TRACE_WIDTH],\n}\n\nimpl State {\n    pub fn new(init_trace_len: usize) -> Self {\n        let mut flags: Vec<Vec<Felt>> = Vec::with_capacity(FLAG_TRACE_WIDTH);\n        let mut res: Vec<Vec<Felt>> = Vec::with_capacity(RES_TRACE_WIDTH);\n        let mut mem_p: Vec<Vec<Felt>> = Vec::with_capacity(MEM_P_TRACE_WIDTH);\n        let mut mem_a: Vec<Vec<Felt>> = Vec::with_capacity(MEM_A_TRACE_WIDTH);\n        let mut mem_v: Vec<Vec<Felt>> = Vec::with_capacity(MEM_V_TRACE_WIDTH);\n        let mut offsets: Vec<Vec<Felt>> = Vec::with_capacity(OFF_X_TRACE_WIDTH);\n        for _ in 0..FLAG_TRACE_WIDTH {\n            let column = Felt::zeroed_vector(init_trace_len);\n            flags.push(column);\n        }\n        for _ in 0..RES_TRACE_WIDTH {\n            let column = Felt::zeroed_vector(init_trace_len);\n            res.push(column);\n        }\n        for _ in 0..MEM_P_TRACE_WIDTH {\n            let column = Felt::zeroed_vector(init_trace_len);\n            mem_p.push(column);\n        }\n        for _ in 0..MEM_A_TRACE_WIDTH {\n            let column = Felt::zeroed_vector(init_trace_len);\n            mem_a.push(column);\n        }\n        for _ in 0..MEM_V_TRACE_WIDTH {\n            let column = Felt::zeroed_vector(init_trace_len);\n            mem_v.push(column);\n        }\n        for _ in 0..OFF_X_TRACE_WIDTH {\n            let column = Felt::zeroed_vector(init_trace_len);\n            offsets.push(column);\n        }\n        State {\n            flags: flags.try_into().unwrap(),\n            res: res.try_into().unwrap(),\n            mem_p: mem_p.try_into().unwrap(),\n            mem_a: mem_a.try_into().unwrap(),\n            mem_v: mem_v.try_into().unwrap(),\n            offsets: offsets.try_into().unwrap(),\n        }\n    }\n\n    pub fn set_register_state(&mut self, step: usize, s: RegisterState) {\n        self.mem_a[0][step] = s.pc;\n        self.mem_p[0][step] = s.ap;\n        self.mem_p[1][step] = s.fp;\n    }\n\n    pub fn set_instruction_state(&mut self, step: usize, s: InstructionState) {\n        // Flags\n        let flags = s.inst.flags();\n        for i in 0..=15 {\n            self.flags[i][step] = flags[i];\n        }\n\n        // Result\n        self.res[0][step] = s.res.unwrap_or(Felt::ZERO);\n\n        // Instruction\n        self.mem_v[0][step] = s.inst.word();\n\n        // Auxiliary values\n        self.mem_v[1][step] = s.dst.unwrap_or(Felt::ZERO);\n        self.mem_v[2][step] = s.op0.unwrap_or(Felt::ZERO);\n        self.mem_v[3][step] = s.op1.unwrap_or(Felt::ZERO);\n\n        // Operands\n        self.mem_a[1][step] = s.dst_addr;\n        self.mem_a[2][step] = s.op0_addr;\n        self.mem_a[3][step] = s.op1_addr;\n\n        // Offsets\n        self.offsets[0][step] = s.inst.off_dst();\n        self.offsets[1][step] = s.inst.off_op0();\n        self.offsets[2][step] = s.inst.off_op1();\n    }\n}\n\n/// Stores all information needed to run a program\npub struct Program<'a> {\n    /// total number of steps\n    steps: usize,\n    /// full execution memory\n    mem: &'a mut Memory,\n    /// initial register state\n    init: RegisterState,\n    /// final register state\n    fin: RegisterState,\n    /// requested builtins\n    builtins: Vec<Builtin>,\n    /// hints\n    #[cfg(feature = \"hints\")]\n    hints: Option<HintManager>,\n}\n\nimpl<'a> Program<'a> {\n    /// Creates an execution from the public information (memory and initial pointers)\n    #[cfg(feature = \"hints\")]\n    pub fn new(mem: &mut Memory, pc: u64, ap: u64, hints: Option<HintManager>) -> Program {\n        Program {\n            steps: 0,\n            mem,\n            init: RegisterState::new(Felt::from(pc), Felt::from(ap), Felt::from(ap)),\n            fin: RegisterState::new(Felt::ZERO, Felt::ZERO, Felt::ZERO),\n            builtins: vec![],\n            hints,\n        }\n    }\n\n    #[cfg(not(feature = \"hints\"))]\n    pub fn new(mem: &mut Memory, pc: u64, ap: u64) -> Program {\n        Program {\n            steps: 0,\n            mem,\n            init: RegisterState::new(Felt::from(pc), Felt::from(ap), Felt::from(ap)),\n            fin: RegisterState::new(Felt::ZERO, Felt::ZERO, Felt::ZERO),\n            builtins: vec![],\n        }\n    }\n\n    /// Outputs the total number of steps of the execution carried out by the runner\n    pub fn get_steps(&self) -> usize {\n        self.steps\n    }\n\n    /// Outputs the final value of the pointers after the execution carried out by the runner\n    pub fn get_final(&self) -> RegisterState {\n        self.fin\n    }\n\n    /// This function simulates an execution of the program received as input\n    /// and returns an execution trace\n    pub fn execute(&mut self) -> Result<ExecutionTrace, ExecutionError> {\n        let mut state = State::new(self.mem.size() as usize);\n        let mut n: usize = 0;\n        let mut end = false;\n        let mut curr = self.init;\n        let mut next = curr;\n\n        // keep executing steps until the end is reached\n        while !end {\n            // create current step of computation\n            let mut step = Step::new(self.mem, next);\n            curr = step.curr;\n\n            #[cfg(feature = \"hints\")]\n            step.set_hint_manager(self.hints.as_ref());\n\n            // execute current step and save state\n            let inst_state = step.execute(true);\n            state.set_register_state(n, curr);\n            state.set_instruction_state(n, inst_state);\n\n            n += 1;\n            match step.next {\n                None => end = true,\n                _ => {\n                    next = step.next.expect(\"Empty next pointers\");\n                    if curr.ap.as_int() <= next.pc.as_int() {\n                        // if reading from unallocated memory, end\n                        end = true;\n                    }\n                }\n            }\n        }\n        self.fin = curr;\n        self.steps = n;\n\n        Ok(ExecutionTrace::new(\n            n,\n            &mut state,\n            &self.mem,\n            self.builtins.clone(),\n        ))\n    }\n}\n"
  },
  {
    "path": "runner/src/trace.rs",
    "content": "use crate::cairo_interop::{read_builtins, read_memory_bin, read_trace_bin};\nuse crate::memory::Memory;\nuse crate::runner::{State, Step};\nuse giza_core::{\n    Builtin, Felt, FieldElement, StarkField, Word, AP, A_M_PRIME_WIDTH, A_RC_PRIME_WIDTH,\n    MEM_A_TRACE_RANGE, MEM_A_TRACE_WIDTH, MEM_V_TRACE_RANGE, OFF_X_TRACE_RANGE, OFF_X_TRACE_WIDTH,\n    P_M_WIDTH, P_RC_WIDTH, TRACE_WIDTH, V_M_PRIME_WIDTH,\n};\nuse winterfell::{Matrix, Trace, TraceLayout};\n\nuse indicatif::ParallelProgressIterator;\nuse indicatif::ProgressIterator;\nuse itertools::Itertools;\nuse rayon::prelude::*;\nuse std::path::PathBuf;\n\npub struct ExecutionTrace {\n    layout: TraceLayout,\n    meta: Vec<u8>,\n    trace: Matrix<Felt>,\n    pub memory: Memory,\n    pub rc_min: u16,\n    pub rc_max: u16,\n    pub num_steps: usize,\n    pub builtins: Vec<Builtin>,\n}\n\n/// A virtual column is composed of one or more subcolumns.\nstruct VirtualColumn<'a, E: FieldElement> {\n    subcols: &'a [Vec<E>],\n}\n\nimpl<'a, E: FieldElement> VirtualColumn<'a, E> {\n    fn new(subcols: &'a [Vec<E>]) -> Self {\n        Self { subcols }\n    }\n\n    /// Pack subcolumns into a single output column: cycle through each subcolumn, appending\n    /// a single value to the output column for each iteration step until exhausted.\n    fn to_column(&self) -> Vec<E> {\n        let mut col: Vec<E> = vec![];\n        for n in 0..self.subcols[0].len() {\n            for subcol in self.subcols {\n                col.push(subcol[n]);\n            }\n        }\n        col\n    }\n\n    /// Split subcolumns into multiple output columns: for each subcolumn, output a single\n    /// value to each output column, cycling through each output column until exhuasted.\n    fn to_columns(&self, num_rows: &[usize]) -> Vec<Vec<E>> {\n        let mut n = 0;\n        let mut cols: Vec<Vec<E>> = vec![vec![]; num_rows.iter().sum()];\n        for (subcol, width) in self.subcols.iter().zip(num_rows) {\n            for (elem, idx) in subcol.iter().zip((0..*width).cycle()) {\n                cols[idx + n].push(*elem);\n            }\n            n += width;\n        }\n        cols\n    }\n}\n\nstruct Layouter<'a, E: FieldElement> {\n    columns: &'a mut Vec<Vec<E>>,\n    frame_len: usize,\n}\n\nimpl<'a, E: FieldElement> Layouter<'a, E> {\n    fn new(columns: &'a mut Vec<Vec<E>>, frame_len: usize) -> Self {\n        Self { columns, frame_len }\n    }\n\n    /// Add one or more columns to the trace. The chunk size determines the number\n    /// of subcolumn elements to place within each frame chunk (defaults to 1)\n    /// starting from the top most row of the chunk.\n    fn add_columns(&mut self, subcols: &[Vec<E>], chunk_size: Option<usize>) {\n        for subcol in subcols.iter() {\n            let mut col = E::zeroed_vector(subcol.len());\n            for (col_chunk, subcol_chunk) in col\n                .chunks_mut(self.frame_len)\n                .zip(subcol.chunks(chunk_size.unwrap_or(1)))\n            {\n                for (n, elem) in subcol_chunk.iter().enumerate() {\n                    col_chunk[n] = *elem\n                }\n            }\n            self.columns.push(col);\n        }\n    }\n\n    /// Resize columns to next power of two\n    fn resize_all(&mut self) {\n        resize_to_pow2(&mut self.columns);\n    }\n}\n\nimpl ExecutionTrace {\n    /// Builds an execution trace\n    pub(super) fn new(\n        num_steps: usize,\n        state: &mut State,\n        memory: &Memory,\n        builtins: Vec<Builtin>,\n    ) -> Self {\n        // Compute the derived (\"auxiliary\") trace values: t0, t1, and mul.\n        // Note that in a conditional jump instruction we substitute res with dst^{-1}\n        // (see page 53 of the whitepaper).\n        let mut t0 = vec![];\n        let mut t1 = vec![];\n        let mut mul = vec![];\n        for step in 0..num_steps {\n            // TODO: Don't hardcode index values\n            let f_pc_jnz = state.flags[9][step];\n            let dst = state.mem_v[1][step];\n            let res = state.res[0][step];\n            t0.push(f_pc_jnz * dst); // f_pc_jnz * dst\n            t1.push(t0[step] * res); // t_0 * res\n            mul.push(state.mem_v[2][step] * state.mem_v[3][step]); // op0 * op1\n        }\n\n        // 1. Append dummy artificial accesses to mem_a and mem_v to fill memory holes.\n        //    These gaps are due to interaction with builtins, and they still need to be handled\n        //    elsewhere in the code for soundness.\n        // 2. Append dummy (0,0) public memory values to mem_a and mem_v.\n        //    Note that we don't need to worry about precise placement (i.e. ensuring that they are\n        //    the final n entries in the columns), because these dummy values will extend into the\n        //    resized column cells.\n        //    TODO: We should also append dummy output (not just program) public memory, in case the\n        //    trace length is not already long enough to contain these values.\n        let mut col_extension = memory.get_holes(VirtualColumn::new(&state.mem_a).to_column());\n        col_extension.extend(vec![Felt::ZERO; memory.get_codelen()]);\n        for (n, col) in VirtualColumn::new(&[col_extension])\n            .to_columns(&[MEM_A_TRACE_WIDTH])\n            .iter()\n            .enumerate()\n        {\n            state.mem_a[n].extend(col);\n            state.mem_v[n].extend(Felt::zeroed_vector(col.len()));\n        }\n\n        // 1. Convert offsets into an unbiased representation by adding 2^15, so that values are\n        //    within [0, 2^16].\n        // 2. Fill gaps between sorted offsets so that we can compute the proper permutation\n        //    product column in the range check auxiliary segment (if we implemented Ord for Felt\n        //    we could achieve a speedup here)\n        let b15 = Felt::from(2u8).exp(15u32.into());\n        let mut rc_column: Vec<Felt> = VirtualColumn::new(&state.offsets)\n            .to_column()\n            .into_iter()\n            .map(|x| x + b15)\n            .collect();\n        let mut rc_sorted: Vec<u16> = rc_column\n            .iter()\n            .map(|x| x.as_int().try_into().unwrap())\n            .collect();\n        rc_sorted.sort_unstable();\n        let rc_min = rc_sorted.first().unwrap().clone();\n        let rc_max = rc_sorted.last().unwrap().clone();\n        for s in rc_sorted.windows(2).progress() {\n            match s[1] - s[0] {\n                0 | 1 => {}\n                _ => {\n                    rc_column.extend((s[0] + 1..s[1]).map(|x| Felt::from(x)).collect::<Vec<_>>());\n                }\n            }\n        }\n        let offsets = VirtualColumn::new(&[rc_column]).to_columns(&[3]);\n\n        // This is hacky... We're adding a selector to the main trace to disable the Cairo\n        // transition constraints for public memory (and any extended trace cells that were added\n        // to ensure that that length is a power of two). If we instead used transition\n        // exemptions, then proving/verifying time would be too slow for programs with a large\n        // number of instructions.\n        //\n        // There are two methods that can be combined to avoid selectors:\n        // - Transform traces so that they end in an inifite loop (use the instruction\n        //   0x10780017fff7fffu64).\n        // - Use a short bootloader program so that the number of transition exemptions is small\n        //   and doesn't harm performance. This bootloader will compute and expose a hash of the\n        //   private memory containing the program instructions to be run.\n        let mut selector = vec![Felt::ONE; num_steps];\n        selector[num_steps - 1] = Felt::ZERO;\n\n        // Layout the trace\n        let mut columns: Vec<Vec<Felt>> = Vec::with_capacity(TRACE_WIDTH);\n        let mut layouter = Layouter::new(&mut columns, 1);\n        layouter.add_columns(&state.flags, None);\n        layouter.add_columns(&state.res, None);\n        layouter.add_columns(&state.mem_p, None);\n        layouter.add_columns(&state.mem_a, None);\n        layouter.add_columns(&state.mem_v, None);\n        layouter.add_columns(&offsets, None);\n        layouter.add_columns(&[t0, t1, mul], None);\n        layouter.add_columns(&[selector], None);\n\n        layouter.resize_all();\n\n        Self {\n            layout: TraceLayout::new(\n                TRACE_WIDTH,\n                &[12, 6], // aux_segment widths\n                &[2, 1],  // aux_segment rands\n            ),\n            meta: Vec::new(),\n            trace: Matrix::new(columns),\n            memory: memory.clone(),\n            rc_min,\n            rc_max,\n            num_steps,\n            builtins,\n        }\n    }\n\n    /// Reconstructs the execution trace from file\n    pub fn from_file(\n        program_path: PathBuf,\n        trace_path: PathBuf,\n        memory_path: PathBuf,\n        output_len: Option<u64>,\n    ) -> ExecutionTrace {\n        let mem = read_memory_bin(&memory_path, &program_path);\n        let registers = read_trace_bin(&trace_path);\n        let builtins = read_builtins(&program_path, output_len);\n        let num_steps = registers.len();\n\n        let inst_states = registers\n            .par_iter()\n            .progress()\n            .map(|ptrs| {\n                let mut step = Step::new(&mem, *ptrs);\n                step.execute(false)\n            })\n            .collect::<Vec<_>>();\n\n        let mut state = State::new(registers.len() + 1);\n        for (n, (reg_state, inst_state)) in registers.iter().zip(inst_states).enumerate() {\n            state.set_register_state(n, *reg_state);\n            state.set_instruction_state(n, inst_state);\n        }\n\n        Self::new(num_steps, &mut state, &mem, builtins)\n    }\n\n    /// Return the program public memory\n    pub fn get_program_mem(&self) -> (Vec<u64>, Vec<Option<Word>>) {\n        let addrs = (0..self.memory.get_codelen() as u64).collect::<Vec<_>>();\n        let vals = self.memory.data[..self.memory.get_codelen()].to_vec();\n        (addrs, vals)\n    }\n\n    /// Return the output public memory\n    pub fn get_output_mem(&self) -> (Vec<u64>, Vec<Option<Word>>) {\n        for builtin in self.builtins.iter() {\n            if let Builtin::Output(len) = builtin {\n                let ptr_start: u64 = self.main_segment().get_column(AP)[self.num_steps - 1]\n                    .as_int()\n                    .try_into()\n                    .unwrap();\n                let ptr_end = ptr_start + len;\n                let addrs = (ptr_start..ptr_end).collect::<Vec<_>>();\n                let vals = addrs\n                    .iter()\n                    .map(|i| self.memory.data[*i as usize])\n                    .collect::<Vec<_>>();\n                return (addrs, vals);\n            }\n        }\n        return (vec![], vec![]);\n    }\n\n    /// Return the combined public memory\n    pub fn get_public_mem(&self) -> (Vec<u64>, Vec<Option<Word>>) {\n        let (mut a, mut v) = self.get_program_mem();\n        let (out_a, out_v) = self.get_output_mem();\n        a.extend(out_a);\n        v.extend(out_v);\n        (a, v)\n    }\n}\n\nimpl Trace for ExecutionTrace {\n    type BaseField = Felt;\n\n    fn layout(&self) -> &TraceLayout {\n        &self.layout\n    }\n\n    fn length(&self) -> usize {\n        self.trace.num_rows()\n    }\n\n    fn meta(&self) -> &[u8] {\n        &self.meta\n    }\n\n    fn main_segment(&self) -> &Matrix<Felt> {\n        &self.trace\n    }\n\n    fn build_aux_segment<E>(\n        &mut self,\n        aux_segments: &[Matrix<E>],\n        rand_elements: &[E],\n    ) -> Option<Matrix<E>>\n    where\n        E: FieldElement<BaseField = Self::BaseField>,\n    {\n        match aux_segments.len() {\n            0 => build_aux_segment_mem(self, rand_elements),\n            1 => build_aux_segment_rc(self, rand_elements),\n            _ => None,\n        }\n    }\n}\n\n/// Write documentation\nfn build_aux_segment_mem<E>(trace: &ExecutionTrace, rand_elements: &[E]) -> Option<Matrix<E>>\nwhere\n    E: FieldElement + From<Felt>,\n{\n    let z = rand_elements[0];\n    let alpha = rand_elements[1];\n\n    // Pack main memory access trace columns into two virtual columns\n    let main = trace.main_segment();\n    let (a, v) = [MEM_A_TRACE_RANGE, MEM_V_TRACE_RANGE]\n        .iter()\n        .map(|range| {\n            VirtualColumn::new(\n                &range\n                    .clone()\n                    .map(|i| main.get_column(i).to_vec())\n                    .collect::<Vec<_>>()[..],\n            )\n            .to_column()\n        })\n        .collect_tuple()\n        .unwrap();\n\n    // Construct duplicate virtual columns sorted by memory access, with dummy public\n    // memory addresses/values replaced by their true values\n    let mut a_prime = vec![E::ZERO; a.len()];\n    let mut v_prime = vec![E::ZERO; a.len()];\n    let mut a_replaced = a.clone();\n    let mut v_replaced = v.clone();\n    let (pub_a, pub_v) = trace.get_public_mem();\n    let l = a.len() - pub_a.len() - 1;\n    for (i, (n, x)) in pub_a.iter().copied().zip(pub_v).enumerate() {\n        a_replaced[l + i] = Felt::from(n);\n        v_replaced[l + i] = x.unwrap().word().into();\n    }\n    let mut indices = (0..a.len()).collect::<Vec<_>>();\n    indices.sort_by_key(|&i| a_replaced[i].as_int());\n    for (i, j) in indices.iter().copied().enumerate() {\n        a_prime[i] = a_replaced[j].into();\n        v_prime[i] = v_replaced[j].into();\n    }\n\n    // Construct virtual column of computed permutation products\n    let mut p = vec![E::ZERO; trace.length() * MEM_A_TRACE_WIDTH];\n    let a_0: E = a[0].into();\n    let v_0: E = v[0].into();\n    p[0] = (z - (a_0 + alpha * v_0).into()) / (z - (a_prime[0] + alpha * v_prime[0]).into());\n    for i in (1..p.len()).progress() {\n        let a_i: E = a[i].into();\n        let v_i: E = v[i].into();\n        p[i] = (z - (a_i + alpha * v_i).into()) * p[i - 1]\n            / (z - (a_prime[i] + alpha * v_prime[i]).into());\n    }\n\n    // Split virtual columns into separate auxiliary columns\n    let mut aux_columns = VirtualColumn::new(&[a_prime, v_prime, p]).to_columns(&[\n        A_M_PRIME_WIDTH,\n        V_M_PRIME_WIDTH,\n        P_M_WIDTH,\n    ]);\n    resize_to_pow2(&mut aux_columns);\n\n    Some(Matrix::new(aux_columns))\n}\n\n/// Write documentation\nfn build_aux_segment_rc<E>(trace: &ExecutionTrace, rand_elements: &[E]) -> Option<Matrix<E>>\nwhere\n    E: FieldElement + From<Felt>,\n{\n    let z = rand_elements[0];\n\n    // Pack main offset trace columns into a single virtual column\n    let main = trace.main_segment();\n    let a = VirtualColumn::new(\n        &OFF_X_TRACE_RANGE\n            .map(|i| main.get_column(i).to_vec())\n            .collect::<Vec<_>>()[..],\n    )\n    .to_column();\n\n    // Construct duplicate virtual column sorted by offset value\n    let mut indices = (0..a.len()).collect::<Vec<_>>();\n    indices.sort_by_key(|&i| a[i].as_int());\n    let a_prime = indices.iter().map(|x| a[*x].into()).collect::<Vec<E>>();\n\n    // Construct virtual column of computed permutation products\n    let mut p = vec![E::ZERO; trace.length() * OFF_X_TRACE_WIDTH];\n    let a_0: E = a[0].into();\n    p[0] = (z - a_0) / (z - a_prime[0]);\n    for i in (1..p.len()).progress() {\n        let a_i: E = a[i].into();\n        p[i] = (z - a_i) * p[i - 1] / (z - a_prime[i]);\n    }\n\n    // Split virtual columns into separate auxiliary columns\n    let mut aux_columns =\n        VirtualColumn::new(&[a_prime, p]).to_columns(&[A_RC_PRIME_WIDTH, P_RC_WIDTH]);\n    resize_to_pow2(&mut aux_columns);\n\n    Some(Matrix::new(aux_columns))\n}\n\n/// Resize columns to next power of two\nfn resize_to_pow2<E: FieldElement>(columns: &mut [Vec<E>]) {\n    let trace_len_pow2 = columns\n        .iter()\n        .map(|x| x.len().next_power_of_two())\n        .max()\n        .unwrap();\n    for column in columns.iter_mut() {\n        let last_value = column.last().copied().unwrap();\n        column.resize(trace_len_pow2, last_value);\n    }\n}\n"
  },
  {
    "path": "rust-toolchain.toml",
    "content": "[toolchain]\nchannel = \"nightly\"\n"
  },
  {
    "path": "wasm/.gitignore",
    "content": "node_modules/\npkg/\ndist/\noutput.bin\n"
  },
  {
    "path": "wasm/Cargo.toml",
    "content": "[package]\nname = \"giza-wasm\"\nversion = \"0.1.0\"\nedition = \"2021\"\nrust-version = \"1.57\"\n\n[lib]\ncrate-type = [\"cdylib\"]\n\n[dependencies]\nwasm-bindgen = \"0.2.74\"\njs-sys = \"0.3.57\"\nair = { package = \"giza-air\", path = \"../air\", version = \"0.1\", default-features = false }\ngiza_core = { package = \"giza-core\", path = \"../core\", version = \"0.1\", default-features = false }\nwinterfell = { package = \"winter-verifier\", git = \"https://github.com/maxgillett/winterfell\", rev = \"0aad6a5\", version = \"0.4\", default-features = false }\nwinter-utils = { package = \"winter-utils\", git = \"https://github.com/maxgillett/winterfell\", rev = \"0aad6a5\", version = \"0.4\", default-features = false }\nbincode = \"1.3.3\"\nserde = { version = \"1.0.136\", features = [\"derive\"] }\n\n[profile.release]\nlto = true\nopt-level = 's'\n\n[package.metadata.wasm-pack.profile.release]\nwasm-opt = false\n"
  },
  {
    "path": "wasm/index.js",
    "content": "// Note that a dynamic `import` statement here is required due to\n// webpack/webpack#6615, but in theory `import { greet } from './pkg';`\n// will work here one day as well!\nconst rust = import('./pkg');\n\n// Load a Cairo proof\nimport data from './output.bin';\n\nrust\n  .then(m => m.verify(data.data))\n  .catch(console.error);\n\n\n"
  },
  {
    "path": "wasm/package.json",
    "content": "{\n  \"scripts\": {\n    \"build\": \"webpack\",\n    \"serve\": \"webpack-dev-server\"\n  },\n  \"devDependencies\": {\n    \"@wasm-tool/wasm-pack-plugin\": \"1.6.0\",\n    \"html-webpack-plugin\": \"^5.5.0\",\n    \"text-encoding\": \"^0.7.0\",\n    \"webpack\": \"^5.73.0\",\n    \"webpack-cli\": \"^4.9.2\",\n    \"webpack-dev-server\": \"^4.9.1\"\n  }\n}\n"
  },
  {
    "path": "wasm/src/lib.rs",
    "content": "use air::{ProcessorAir, PublicInputs};\nuse serde::{Deserialize, Serialize};\nuse winter_utils::{Deserializable, SliceReader};\nuse winterfell::StarkProof;\n\nuse js_sys::Uint8Array;\nuse wasm_bindgen::prelude::*;\n\n#[wasm_bindgen]\nextern \"C\" {\n    #[wasm_bindgen(js_namespace = console)]\n    fn log(s: &str);\n}\n\n#[wasm_bindgen]\npub fn verify(buffer: &Uint8Array) {\n    // Load proof and public inputs\n    let b = buffer.to_vec();\n    let data: ProofData = bincode::deserialize(&b).unwrap();\n    let pub_inputs = PublicInputs::read_from(&mut SliceReader::new(&data.input_bytes[..])).unwrap();\n    let proof = StarkProof::from_bytes(&data.proof_bytes).unwrap();\n\n    // Verify execution\n    match winterfell::verify::<ProcessorAir>(proof, pub_inputs) {\n        Ok(_) => log(\"Execution verified\"),\n        Err(err) => log(format!(\"Failed to verify execution: {}\", err).as_str()),\n    }\n}\n\n#[derive(Serialize, Deserialize)]\nstruct ProofData {\n    input_bytes: Vec<u8>,\n    proof_bytes: Vec<u8>,\n}\n"
  },
  {
    "path": "wasm/webpack.config.js",
    "content": "const path = require('path');\nconst HtmlWebpackPlugin = require('html-webpack-plugin');\nconst webpack = require('webpack');\nconst WasmPackPlugin = require(\"@wasm-tool/wasm-pack-plugin\");\n\nmodule.exports = {\n    entry: './index.js',\n    output: {\n        path: path.resolve(__dirname, 'dist'),\n        filename: 'index.js',\n    },\n    plugins: [\n        new HtmlWebpackPlugin(),\n        new WasmPackPlugin({\n            crateDirectory: path.resolve(__dirname, \".\")\n        }),\n        // Have this example work in Edge which doesn't ship `TextEncoder` or\n        // `TextDecoder` at this time.\n        new webpack.ProvidePlugin({\n          TextDecoder: ['text-encoding', 'TextDecoder'],\n          TextEncoder: ['text-encoding', 'TextEncoder']\n        })\n    ],\n    experiments: {\n      asyncWebAssembly: true,\n    },\n    module: {\n        rules: [\n          {\n            test: /\\.bin/,\n            type: 'asset/inline',\n            generator: {\n              dataUrl: content => {\n                return content;\n              }\n            }\n          }\n        ],\n    },\n    mode: 'production',\n    performance: {\n      maxEntrypointSize: 2000000,\n      maxAssetSize: 2000000,\n    }\n};\n\n"
  }
]