diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 000000000..0c04c5309
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,3 @@
+{
+ "cmake.configureOnOpen": false
+}
diff --git a/Cargo.toml b/Cargo.toml
index 587b1b7e0..03e3c8f6b 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
[workspace]
-members = ["math", "crypto", "gpu", "benches", "provers/plonk", "provers/stark", "provers/cairo", "provers/groth16", "provers/groth16/arkworks-adapter", "provers/groth16/circom-adapter", "examples/merkle-tree-cli", "examples/prove-miden", "provers/winterfell_adapter", "examples/shamir_secret_sharing", "examples/prove-verify-circom", "provers/cairo/ffi"]
+members = ["math", "crypto", "gpu", "benches", "provers/plonk", "provers/stark", "provers/cairo", "provers/groth16", "provers/groth16/arkworks-adapter", "provers/groth16/circom-adapter", "examples/merkle-tree-cli", "examples/prove-miden", "provers/winterfell_adapter", "examples/shamir_secret_sharing", "examples/prove-verify-circom", "exercises/air_vm_workshop", "provers/cairo/ffi"]
exclude = ["ensure-no_std"]
resolver = "2"
diff --git a/docs/src/starks/api.md b/docs/src/starks/api.md
index 275696925..87e811bbe 100644
--- a/docs/src/starks/api.md
+++ b/docs/src/starks/api.md
@@ -127,7 +127,6 @@ let context = AirContext {
},
trace_columns: trace_table.n_cols,
transition_degrees: vec![1],
- transition_exemptions: vec![2],
transition_offsets: vec![0, 1, 2],
num_transition_constraints: 1,
};
diff --git a/examples/prove-gnark-plonk/go_exporter_example/frontend_precomputed_values.json b/examples/prove-gnark-plonk/go_exporter_example/frontend_precomputed_values.json
new file mode 100644
index 000000000..9a3412b82
--- /dev/null
+++ b/examples/prove-gnark-plonk/go_exporter_example/frontend_precomputed_values.json
@@ -0,0 +1,100 @@
+{
+ "N": 5,
+ "N_Padded": 8,
+ "Omega": "345766f603fa66e78c0625cd70d77ce2b38b21c28713b7007228fd3397743f7a",
+ "Input": [
+ "3",
+ "1b"
+ ],
+ "Ql": [
+ "73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000000",
+ "73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000000",
+ "0",
+ "0",
+ "1"
+ ],
+ "Qr": [
+ "0",
+ "0",
+ "0",
+ "0",
+ "73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000000"
+ ],
+ "Qm": [
+ "0",
+ "0",
+ "1",
+ "1",
+ "0"
+ ],
+ "Qo": [
+ "0",
+ "0",
+ "73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000000",
+ "73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000000",
+ "0"
+ ],
+ "Qc": [
+ "0",
+ "0",
+ "0",
+ "0",
+ "0"
+ ],
+ "A": [
+ "3",
+ "1b",
+ "3",
+ "9",
+ "1b",
+ "3",
+ "3",
+ "3"
+ ],
+ "B": [
+ "3",
+ "3",
+ "3",
+ "3",
+ "1b",
+ "3",
+ "3",
+ "3"
+ ],
+ "C": [
+ "3",
+ "3",
+ "9",
+ "1b",
+ "3",
+ "3",
+ "3",
+ "3"
+ ],
+ "Permutation": [
+ 23,
+ 4,
+ 0,
+ 18,
+ 1,
+ 2,
+ 5,
+ 6,
+ 7,
+ 8,
+ 9,
+ 10,
+ 19,
+ 11,
+ 13,
+ 14,
+ 15,
+ 16,
+ 3,
+ 12,
+ 17,
+ 20,
+ 21,
+ 22
+ ]
+}
\ No newline at end of file
diff --git a/examples/prove-gnark-plonk/go_exporter_example/witness.json b/examples/prove-gnark-plonk/go_exporter_example/witness.json
new file mode 100644
index 000000000..f3c570a5f
--- /dev/null
+++ b/examples/prove-gnark-plonk/go_exporter_example/witness.json
@@ -0,0 +1 @@
+{"witness":["3","27"]}
\ No newline at end of file
diff --git a/exercises/air_vm_workshop/Cargo.toml b/exercises/air_vm_workshop/Cargo.toml
new file mode 100644
index 000000000..0f54545d2
--- /dev/null
+++ b/exercises/air_vm_workshop/Cargo.toml
@@ -0,0 +1,15 @@
+[package]
+name = "mini_air_vm"
+version.workspace = true
+edition.workspace = true
+license.workspace = true
+repository.workspace = true
+
+[[bin]]
+name = "mini-air-cli"
+path = "src/main.rs"
+
+[dependencies]
+lambdaworks-math = { workspace = true }
+lambdaworks-crypto = { workspace = true }
+stark-platinum-prover = {workspace = true }
diff --git a/exercises/air_vm_workshop/README.md b/exercises/air_vm_workshop/README.md
new file mode 100644
index 000000000..327b9ed16
--- /dev/null
+++ b/exercises/air_vm_workshop/README.md
@@ -0,0 +1,5 @@
+
+
+# Lambdaworks Circom Proving & Verification Example
+
+This programs converts Circom & SnarkJS generated constraints and witnesses into Lambdaworks-compatible instances, performs trusted setup, generates proof, and finally verifies the integrity of witness assignments.
diff --git a/exercises/air_vm_workshop/src/main.rs b/exercises/air_vm_workshop/src/main.rs
new file mode 100644
index 000000000..ee0714f0c
--- /dev/null
+++ b/exercises/air_vm_workshop/src/main.rs
@@ -0,0 +1,301 @@
+
+use lambdaworks_crypto::fiat_shamir::default_transcript::DefaultTranscript;
+use stark_platinum_prover::{
+ constraints::{
+ boundary::BoundaryConstraints,
+ transition::TransitionConstraint,
+ }, context::AirContext, frame::Frame, proof::options::ProofOptions, prover::{IsStarkProver, Prover}, trace::TraceTable, traits::AIR, verifier::{IsStarkVerifier, Verifier}
+};
+use lambdaworks_math::field::{element::FieldElement, fields::fft_friendly::stark_252_prime_field::Stark252PrimeField, traits::IsFFTField};
+use std::marker::PhantomData;
+
+
+const STEP_SIZE: usize = 1;
+const NUMBER_OF_COLUMNS: usize = 7;
+
+#[derive(Clone)]
+struct FlagIsBinary {
+ phantom: PhantomData,
+}
+
+impl FlagIsBinary {
+ pub fn new() -> Self {
+ Self {
+ phantom: PhantomData,
+ }
+ }
+}
+
+impl TransitionConstraint for FlagIsBinary
+where
+ F: IsFFTField + Send + Sync,
+{
+ fn degree(&self) -> usize {
+ todo!()
+ }
+
+ fn constraint_idx(&self) -> usize {
+ 0
+ }
+
+ fn end_exemptions(&self) -> usize {
+ todo!()
+ }
+
+ fn evaluate(
+ &self,
+ frame: &Frame,
+ transition_evaluations: &mut [FieldElement],
+ _periodic_values: &[FieldElement],
+ _rap_challenges: &[FieldElement],
+ ) {
+ todo!()
+ }
+}
+
+
+#[derive(Clone)]
+struct OperationIsCorrect {
+ phantom: PhantomData,
+}
+
+impl OperationIsCorrect {
+ pub fn new() -> Self {
+ Self {
+ phantom: PhantomData,
+ }
+ }
+}
+
+impl TransitionConstraint for OperationIsCorrect
+where
+ F: IsFFTField + Send + Sync,
+{
+ fn degree(&self) -> usize {
+ todo!()
+ }
+
+ fn constraint_idx(&self) -> usize {
+ 1
+ }
+
+ fn end_exemptions(&self) -> usize {
+ todo!()
+ }
+
+ fn evaluate(
+ &self,
+ _frame: &Frame,
+ _transition_evaluations: &mut [FieldElement],
+ _periodic_values: &[FieldElement],
+ _rap_challenges: &[FieldElement],
+ ) {
+ todo!()
+ }
+}
+
+pub struct VM0Air
+where
+ F: IsFFTField,
+{
+ context: AirContext,
+ trace_length: usize,
+ constraints: Vec>>,
+ public_inputs: VM0PubInputs
+}
+
+
+// We won't use this, but the general AIR assumes there will be public inputs
+#[derive(Clone, Debug)]
+pub struct VM0PubInputs
+where F: IsFFTField {
+ _dummy: FieldElement
+}
+
+impl VM0PubInputs where F: IsFFTField {
+ pub fn default() -> Self {
+ Self {
+ _dummy: FieldElement::::zero()
+ }
+ }
+
+}
+
+impl AIR for VM0Air
+where
+ F: IsFFTField + Send + Sync + 'static,
+{
+ type Field = F;
+ type FieldExtension = F;
+ // This is not used in this example
+ type PublicInputs = VM0PubInputs;
+
+ const STEP_SIZE: usize = 1;
+
+ fn new(
+ trace_length: usize,
+ // unused
+ pub_inputs: &Self::PublicInputs,
+ proof_options: &ProofOptions,
+ ) -> Self {
+
+ let constraints: Vec>> =
+ vec![
+ Box::new(OperationIsCorrect::new()),
+ Box::new(FlagIsBinary::new())
+ ];
+
+ let context = AirContext {
+ proof_options: proof_options.clone(),
+ trace_columns: NUMBER_OF_COLUMNS,
+ // These are the relative indexes of rows needed to evaluate the constraints, in this case we need two consecutives rows so 0 and 1 is good.
+ transition_offsets: vec![0, 1],
+ num_transition_constraints: constraints.len(),
+ };
+
+ Self {
+ context,
+ trace_length,
+ constraints,
+ public_inputs: pub_inputs.clone()
+ }
+ }
+
+ fn composition_poly_degree_bound(&self) -> usize {
+ self.trace_length()
+ }
+
+ fn transition_constraints(&self) -> &Vec>> {
+ &self.constraints
+ }
+
+ fn context(&self) -> &AirContext {
+ &self.context
+ }
+
+ fn trace_length(&self) -> usize {
+ self.trace_length
+ }
+
+ // For the first example
+ fn trace_layout(&self) -> (usize, usize) {
+ (NUMBER_OF_COLUMNS, 0)
+ }
+
+ fn pub_inputs(&self) -> &Self::PublicInputs {
+ &self.public_inputs
+ }
+
+ // Rap is not used in this example
+ fn boundary_constraints(
+ &self,
+ _rap_challenges: &[FieldElement],
+ ) -> BoundaryConstraints {
+ todo!()
+ }
+
+ // This function can just call compute_transition_prover for this examples. It will be unified in just one compute_transition in the future.
+ fn compute_transition_verifier(
+ &self,
+ frame: &Frame,
+ periodic_values: &[FieldElement],
+ rap_challenges: &[FieldElement],
+ ) -> Vec> {
+ self.compute_transition_prover(frame, periodic_values, rap_challenges)
+ }
+}
+
+
+// Flag, A0, V0, A1, V1, A DST, V DST
+pub fn vm0_example_trace(
+) -> TraceTable {
+
+ let row0: Vec> = vec![
+ FieldElement::::from(0),
+ FieldElement::::from(0),
+ FieldElement::::from(3),
+ FieldElement::::from(1),
+ FieldElement::::from(3),
+ FieldElement::::from(2),
+ FieldElement::::from(6)
+ ];
+
+ let row1: Vec> = vec![
+ FieldElement::::from(1),
+ FieldElement::::from(4),
+ FieldElement::::from(3),
+ FieldElement::::from(5),
+ FieldElement::::from(3),
+ FieldElement::::from(6),
+ FieldElement::::from(9)
+ ];
+
+
+ let row2: Vec> = vec![
+ FieldElement::::from(0),
+ FieldElement::::from(6),
+ FieldElement::::from(9),
+ FieldElement::::from(2),
+ FieldElement::::from(6),
+ FieldElement::::from(7),
+ FieldElement::::from(15)
+ ];
+
+ // Trace length needs to be a power of 2 for FFT to work
+ // We pad it with another equal to the last one
+ // In a real VM this can be solved by adding a jmp rel 0 for example so the padding is valid, or some extra NOPs
+ let row3 = row2.clone();
+
+ let mut trace_data: Vec> = Vec::new();
+ trace_data.extend(row0);
+ trace_data.extend(row1);
+ trace_data.extend(row2);
+ trace_data.extend(row3);
+
+ TraceTable::new_main(trace_data, NUMBER_OF_COLUMNS, STEP_SIZE)
+}
+
+fn main() {
+ let mut trace: TraceTable = vm0_example_trace();
+
+ let row0_string: Vec = trace.get_column_main(0).iter().map(|x| x.to_string()).collect();
+ let row1_string: Vec = trace.get_column_main(1).iter().map(|x| x.to_string()).collect();
+ let row6_string: Vec = trace.get_column_main(6).iter().map(|x| x.to_string()).collect();
+
+ println!("First row of trace: {:?}", row0_string);
+ println!("Second row of trace: {:?}", row1_string);
+ println!("...");
+ println!("Sixth row row of trace: {:?}", row6_string);
+
+ // This can always be 3
+ let coset_offset = 3;
+ let proof_options = ProofOptions::new_secure(stark_platinum_prover::proof::options::SecurityLevel::Conjecturable100Bits, coset_offset);
+
+ let pub_inputs = VM0PubInputs::default();
+
+ println!("Generating proof ...");
+ let proof_result = Prover::>::prove(
+ &mut trace,
+ &pub_inputs,
+ &proof_options,
+ DefaultTranscript::default()
+ );
+
+ let proof = match proof_result {
+ Ok(x) => x,
+ Err(_) => {
+ println!("Error while generating the proof");
+ return
+ },
+ };
+
+ println!("Done!");
+ println!("Verifying proof ...");
+
+ assert!(Verifier::>::verify(
+ &proof,
+ &pub_inputs,
+ &proof_options,
+ DefaultTranscript::default()
+ ));
+}
diff --git a/objects.py b/objects.py
new file mode 100644
index 000000000..8438e1329
--- /dev/null
+++ b/objects.py
@@ -0,0 +1,395 @@
+import dataclasses
+from abc import abstractmethod
+from dataclasses import field
+from typing import ClassVar, Dict, List, Optional, Type
+
+import marshmallow
+import marshmallow.fields as mfields
+import marshmallow_dataclass
+from marshmallow_oneofschema import OneOfSchema
+
+from starkware.cairo.lang.compiler.program import Program, ProgramBase, StrippedProgram
+from starkware.cairo.lang.vm.cairo_pie import CairoPie
+from starkware.starkware_utils.marshmallow_dataclass_fields import additional_metadata
+from starkware.starkware_utils.validated_dataclass import ValidatedMarshmallowDataclass
+
+
+class TaskSpec(ValidatedMarshmallowDataclass):
+ """
+ Contains task's specification.
+ """
+
+ @abstractmethod
+ def load_task(self) -> "Task":
+ """
+ Returns the corresponding task.
+ """
+
+
+class Task:
+ @abstractmethod
+ def get_program(self) -> ProgramBase:
+ """
+ Returns the task's Cairo program.
+ """
+
+
+@marshmallow_dataclass.dataclass(frozen=True)
+class RunProgramTask(TaskSpec, Task):
+ TYPE: ClassVar[str] = "RunProgramTask"
+ program: Program
+ program_input: dict
+ use_poseidon: bool
+
+ def get_program(self) -> Program:
+ return self.program
+
+ def load_task(self) -> "Task":
+ return self
+
+
+@marshmallow_dataclass.dataclass(frozen=True)
+class CairoPiePath(TaskSpec):
+ TYPE: ClassVar[str] = "CairoPiePath"
+ path: str
+ use_poseidon: bool
+
+ def load_task(self) -> "CairoPieTask":
+ """
+ Loads the PIE to memory.
+ """
+ return CairoPieTask(cairo_pie=CairoPie.from_file(self.path), use_poseidon=self.use_poseidon)
+
+
+class TaskSchema(OneOfSchema):
+ """
+ Schema for Task/CairoPiePath.
+ OneOfSchema adds a "type" field.
+ """
+
+ type_schemas: Dict[str, Type[marshmallow.Schema]] = {
+ RunProgramTask.TYPE: RunProgramTask.Schema,
+ CairoPiePath.TYPE: CairoPiePath.Schema,
+ }
+
+ def get_obj_type(self, obj):
+ return obj.TYPE
+
+
+@dataclasses.dataclass(frozen=True)
+class CairoPieTask(Task):
+ cairo_pie: CairoPie
+ use_poseidon: bool
+
+ def get_program(self) -> StrippedProgram:
+ return self.cairo_pie.program
+
+
+@marshmallow_dataclass.dataclass(frozen=True)
+class SimpleBootloaderInput(ValidatedMarshmallowDataclass):
+ tasks: List[TaskSpec] = field(
+ metadata=additional_metadata(marshmallow_field=mfields.List(mfields.Nested(TaskSchema)))
+ )
+ fact_topologies_path: Optional[str]
+
+ # If true, the bootloader will put all the outputs in a single page, ignoring the
+ # tasks' fact topologies.
+ single_page: bool
+295 changes: 295 additions & 0 deletions 295
+src/starkware/cairo/bootloaders/simple_bootloader/utils.py
+@@ -0,0 +1,295 @@
+import json
+import os
+from typing import Any, List, Union
+
+import aiofiles
+
+from starkware.cairo.bootloaders.fact_topology import (
+ FactTopologiesFile,
+ FactTopology,
+ get_fact_topology_from_additional_data,
+)
+from starkware.cairo.bootloaders.simple_bootloader.objects import CairoPieTask, RunProgramTask, Task
+from starkware.cairo.common.hash_state import compute_hash_on_elements
+from starkware.cairo.lang.builtins.all_builtins import ALL_BUILTINS
+from starkware.cairo.lang.compiler.program import Program
+from starkware.cairo.lang.vm.cairo_pie import CairoPie, ExecutionResources
+from starkware.cairo.lang.vm.output_builtin_runner import OutputBuiltinRunner
+from starkware.cairo.lang.vm.relocatable import MaybeRelocatable, RelocatableValue, relocate_value
+from starkware.python.utils import WriteOnceDict, from_bytes
+
+SIMPLE_BOOTLOADER_COMPILED_PATH = os.path.join(
+ os.path.dirname(__file__), "simple_bootloader_compiled.json"
+)
+
+# Upper bounds on the numbers of builtin instances and steps that the simple_bootloader uses.
+SIMPLE_BOOTLOADER_N_OUTPUT = 2
+SIMPLE_BOOTLOADER_N_PEDERSEN = 20
+SIMPLE_BOOTLOADER_N_RANGE_CHECKS = 20
+SIMPLE_BOOTLOADER_N_STEPS_CONSTANT = 400
+SIMPLE_BOOTLOADER_N_STEPS_RATIO = 8
+
+
+async def get_simple_bootloader_program_json() -> str:
+ async with aiofiles.open(SIMPLE_BOOTLOADER_COMPILED_PATH, "r") as file:
+ return json.loads(await file.read())
+
+
+async def get_simple_bootloader_program() -> Program:
+ async with aiofiles.open(SIMPLE_BOOTLOADER_COMPILED_PATH, "r") as file:
+ return Program.Schema().loads(await file.read())
+
+
+async def get_simple_bootloader_program_hash() -> int:
+ """
+ Returns the hash of the simple bootloader program. Matches the Cairo verifier's expected simple
+ bootloader hash.
+ """
+ simple_bootloader_program: Program = await get_simple_bootloader_program()
+ return compute_hash_on_elements(data=simple_bootloader_program.data)
+
+
+def load_program(task: Task, memory, program_header, builtins_offset):
+ """
+ Fills the memory with the following:
+ 1. program header.
+ 2. program code.
+ Returns the program address and the size of the written program data.
+ """
+
+ builtins = task.get_program().builtins
+ n_builtins = len(builtins)
+ program_data = task.get_program().data
+
+ # Fill in the program header.
+ header_address = program_header.address_
+ # The program header ends with a list of builtins used by the program.
+ header_size = builtins_offset + n_builtins
+ # data_length does not include the data_length header field in the calculation.
+ program_header.data_length = (header_size - 1) + len(program_data)
+ program_header.program_main = task.get_program().main
+ program_header.n_builtins = n_builtins
+ # Fill in the builtin list in memory.
+ builtins_address = header_address + builtins_offset
+ for index, builtin in enumerate(builtins):
+ assert isinstance(builtin, str)
+ memory[builtins_address + index] = from_bytes(builtin.encode("ascii"))
+
+ # Fill in the program code in memory.
+ program_address = header_address + header_size
+ for index, opcode in enumerate(program_data):
+ memory[program_address + index] = opcode
+
+ return program_address, header_size + len(program_data)
+
+
+def write_return_builtins(
+ memory,
+ return_builtins_addr,
+ used_builtins,
+ used_builtins_addr,
+ pre_execution_builtins_addr,
+ task,
+):
+ """
+ Writes the updated builtin pointers after the program execution to the given return builtins
+ address.
+ used_builtins is the list of builtins used by the program and thus updated by it.
+ """
+
+ used_builtin_offset = 0
+ for index, builtin in enumerate(ALL_BUILTINS):
+ if builtin in used_builtins:
+ memory[return_builtins_addr + index] = memory[used_builtins_addr + used_builtin_offset]
+ used_builtin_offset += 1
+
+ if isinstance(task, CairoPie):
+ assert task.metadata.builtin_segments[builtin].size == (
+ memory[return_builtins_addr + index]
+ - memory[pre_execution_builtins_addr + index]
+ ), "Builtin usage is inconsistent with the CairoPie."
+ else:
+ # The builtin is unused, hence its value is the same as before calling the program.
+ memory[return_builtins_addr + index] = memory[pre_execution_builtins_addr + index]
+
+
+def load_cairo_pie(
+ task: CairoPie,
+ memory,
+ segments,
+ program_address,
+ execution_segment_address,
+ builtin_runners,
+ ret_fp,
+ ret_pc,
+):
+ """
+ Load memory entries of the inner program.
+ This replaces executing hints in a non-trusted program.
+ """
+ segment_offsets = WriteOnceDict()
+
+ segment_offsets[task.metadata.program_segment.index] = program_address
+ segment_offsets[task.metadata.execution_segment.index] = execution_segment_address
+ segment_offsets[task.metadata.ret_fp_segment.index] = ret_fp
+ segment_offsets[task.metadata.ret_pc_segment.index] = ret_pc
+
+ def extract_segment(value: MaybeRelocatable, value_name: str):
+ """
+ Returns the segment index for the given value.
+ Verifies that value is a RelocatableValue with offset 0.
+ """
+ assert isinstance(value, RelocatableValue), f"{value_name} is not relocatable."
+ assert value.offset == 0, f"{value_name} has a non-zero offset."
+ return value.segment_index
+
+ orig_execution_segment = RelocatableValue(
+ segment_index=task.metadata.execution_segment.index, offset=0
+ )
+
+ # Set initial stack relocations.
+ for idx, name in enumerate(task.program.builtins):
+ segment_offsets[
+ extract_segment(
+ value=task.memory[orig_execution_segment + idx],
+ value_name=f"{name} builtin start address",
+ )
+ ] = memory[execution_segment_address + idx]
+
+ for segment_info in task.metadata.extra_segments:
+ segment_offsets[segment_info.index] = segments.add(size=segment_info.size)
+
+ def local_relocate_value(value):
+ return relocate_value(value, segment_offsets, task.program.prime)
+
+ # Relocate builtin additional data.
+ # This should occur before the memory relocation, since the signature builtin assumes that a
+ # signature is added before the corresponding public key and message are both written to memory.
+ esdsa_additional_data = task.additional_data.get("ecdsa_builtin")
+ if esdsa_additional_data is not None:
+ ecdsa_builtin = builtin_runners.get("ecdsa_builtin")
+ assert ecdsa_builtin is not None, "The task requires the ecdsa builtin but it is missing."
+ ecdsa_builtin.extend_additional_data(esdsa_additional_data, local_relocate_value)
+
+ for addr, val in task.memory.items():
+ memory[local_relocate_value(addr)] = local_relocate_value(val)
+
+
+def prepare_output_runner(
+ task: Task, output_builtin: OutputBuiltinRunner, output_ptr: RelocatableValue
+):
+ """
+ Prepares the output builtin if the type of task is Task, so that pages of the inner program
+ will be recorded separately.
+ If the type of task is CairoPie, nothing should be done, as the program does not contain
+ hints that may affect the output builtin.
+ The return value of this function should be later passed to get_task_fact_topology().
+ """
+
+ if isinstance(task, RunProgramTask):
+ output_state = output_builtin.get_state()
+ output_builtin.new_state(base=output_ptr)
+ return output_state
+ elif isinstance(task, CairoPieTask):
+ return None
+ else:
+ raise NotImplementedError(f"Unexpected task type: {type(task).__name__}.")
+
+
+def get_task_fact_topology(
+ output_size: int,
+ task: Union[RunProgramTask, CairoPie],
+ output_builtin: OutputBuiltinRunner,
+ output_runner_data: Any,
+) -> FactTopology:
+ """
+ Returns the fact_topology that corresponds to 'task'. Restores output builtin state if 'task' is
+ a RunProgramTask.
+ """
+
+ # Obtain the fact_toplogy of 'task'.
+ if isinstance(task, RunProgramTask):
+ assert output_runner_data is not None
+ fact_topology = get_fact_topology_from_additional_data(
+ output_size=output_size,
+ output_builtin_additional_data=output_builtin.get_additional_data(),
+ )
+ # Restore the output builtin runner to its original state.
+ output_builtin.set_state(output_runner_data)
+ elif isinstance(task, CairoPieTask):
+ assert output_runner_data is None
+ fact_topology = get_fact_topology_from_additional_data(
+ output_size=output_size,
+ output_builtin_additional_data=task.cairo_pie.additional_data["output_builtin"],
+ )
+ else:
+ raise NotImplementedError(f"Unexpected task type: {type(task).__name__}.")
+
+ return fact_topology
+
+
+def add_consecutive_output_pages(
+ fact_topology: FactTopology,
+ output_builtin: OutputBuiltinRunner,
+ cur_page_id: int,
+ output_start: MaybeRelocatable,
+) -> int:
+ offset = 0
+ for i, page_size in enumerate(fact_topology.page_sizes):
+ output_builtin.add_page(
+ page_id=cur_page_id + i, page_start=output_start + offset, page_size=page_size
+ )
+ offset += page_size
+
+ return len(fact_topology.page_sizes)
+
+
+def configure_fact_topologies(
+ fact_topologies: List[FactTopology],
+ output_start: MaybeRelocatable,
+ output_builtin: OutputBuiltinRunner,
+):
+ """
+ Given the fact_topologies of the tasks that were run by bootloader, configure the
+ corresponding pages in the output builtin. Assumes that the bootloader output 2 words per task.
+ """
+ # Each task may use a few memory pages. Start from page 1 (as page 0 is reserved for the
+ # bootloader program and arguments).
+ cur_page_id = 1
+ for fact_topology in fact_topologies:
+ # Skip bootloader output for each task.
+ output_start += 2
+ cur_page_id += add_consecutive_output_pages(
+ fact_topology=fact_topology,
+ output_builtin=output_builtin,
+ cur_page_id=cur_page_id,
+ output_start=output_start,
+ )
+ output_start += sum(fact_topology.page_sizes)
+
+
+def write_to_fact_topologies_file(fact_topologies_path: str, fact_topologies: List[FactTopology]):
+ with open(fact_topologies_path, "w") as fp:
+ json.dump(
+ FactTopologiesFile.Schema().dump(FactTopologiesFile(fact_topologies=fact_topologies)),
+ fp,
+ indent=4,
+ sort_keys=True,
+ )
+ fp.write("\n")
+
+
+def calc_simple_bootloader_execution_resources(program_length: int) -> ExecutionResources:
+ """
+ Returns an upper bound on the number of steps and builtin instances that the simple bootloader
+ uses.
+ """
+ n_steps = SIMPLE_BOOTLOADER_N_STEPS_RATIO * program_length + SIMPLE_BOOTLOADER_N_STEPS_CONSTANT
+ builtin_instance_counter = {
+ "pedersen_builtin": SIMPLE_BOOTLOADER_N_PEDERSEN + program_length,
+ "range_check_builtin": SIMPLE_BOOTLOADER_N_RANGE_CHECKS,
+ "output_builtin": SIMPLE_BOOTLOADER_N_OUTPUT,
+ }
+ return ExecutionResources(
+ n_steps=n_steps, builtin_instance_counter=builtin_instance_counter, n_memory_holes=0
+ )
diff --git a/provers/cairo/benches/criterion_prover.rs b/provers/cairo/benches/criterion_prover.rs
index 7a8e91308..b908d090a 100644
--- a/provers/cairo/benches/criterion_prover.rs
+++ b/provers/cairo/benches/criterion_prover.rs
@@ -4,6 +4,7 @@ use cairo_platinum_prover::{
use criterion::{
black_box, criterion_group, criterion_main, measurement::WallTime, BenchmarkGroup, Criterion,
};
+
use stark_platinum_prover::proof::options::{ProofOptions, SecurityLevel};
pub mod functions;
@@ -53,12 +54,12 @@ fn run_cairo_bench(
) {
let program_content = std::fs::read(program_path).unwrap();
let proof_options = ProofOptions::new_secure(SecurityLevel::Provable80Bits, 3);
- let (main_trace, pub_inputs) = generate_prover_args(&program_content, layout).unwrap();
- println!("Generated main trace with {} rows", main_trace.n_rows());
+ let (mut main_trace, pub_inputs) = generate_prover_args(&program_content, layout).unwrap();
+ println!("Generated main trace with {} rows", main_trace.num_rows());
group.bench_function(benchname, |bench| {
bench.iter(|| {
- black_box(generate_cairo_proof(&main_trace, &pub_inputs, &proof_options).unwrap())
+ black_box(generate_cairo_proof(&mut main_trace, &pub_inputs, &proof_options).unwrap())
});
});
}
diff --git a/provers/cairo/benches/criterion_prover_70k.rs b/provers/cairo/benches/criterion_prover_70k.rs
index 31f73e3a1..216916af0 100644
--- a/provers/cairo/benches/criterion_prover_70k.rs
+++ b/provers/cairo/benches/criterion_prover_70k.rs
@@ -48,11 +48,11 @@ fn run_cairo_bench(
) {
let program_content = std::fs::read(program_path).unwrap();
let proof_options = ProofOptions::new_secure(SecurityLevel::Provable80Bits, 3);
- let (main_trace, pub_inputs) = generate_prover_args(&program_content, layout).unwrap();
+ let (mut main_trace, pub_inputs) = generate_prover_args(&program_content, layout).unwrap();
group.bench_function(benchname, |bench| {
bench.iter(|| {
- black_box(generate_cairo_proof(&main_trace, &pub_inputs, &proof_options).unwrap())
+ black_box(generate_cairo_proof(&mut main_trace, &pub_inputs, &proof_options).unwrap())
});
});
}
diff --git a/provers/cairo/benches/criterion_verifier.rs b/provers/cairo/benches/criterion_verifier.rs
index f4a82c957..89bf18768 100644
--- a/provers/cairo/benches/criterion_verifier.rs
+++ b/provers/cairo/benches/criterion_verifier.rs
@@ -5,11 +5,11 @@ use criterion::{
use lambdaworks_math::{
field::fields::fft_friendly::stark_252_prime_field::Stark252PrimeField, traits::Deserializable,
};
+
use stark_platinum_prover::proof::{
options::{ProofOptions, SecurityLevel},
stark::StarkProof,
};
-
pub mod functions;
fn load_proof_and_pub_inputs(
diff --git a/provers/cairo/benches/criterion_verifier_70k.rs b/provers/cairo/benches/criterion_verifier_70k.rs
index 6597d56e3..4442996d0 100644
--- a/provers/cairo/benches/criterion_verifier_70k.rs
+++ b/provers/cairo/benches/criterion_verifier_70k.rs
@@ -6,6 +6,7 @@ use criterion::{
use lambdaworks_math::{
field::fields::fft_friendly::stark_252_prime_field::Stark252PrimeField, traits::Deserializable,
};
+
use stark_platinum_prover::proof::{
options::{ProofOptions, SecurityLevel},
stark::StarkProof,
diff --git a/provers/cairo/cairo_programs/cairo0/fibonacci_stone.cairo b/provers/cairo/cairo_programs/cairo0/fibonacci_stone.cairo
new file mode 100644
index 000000000..4a32b246d
--- /dev/null
+++ b/provers/cairo/cairo_programs/cairo0/fibonacci_stone.cairo
@@ -0,0 +1,33 @@
+// Copyright 2023 StarkWare Industries Ltd.
+//
+// Licensed under the Apache License, Version 2.0 (the "License").
+// You may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.starkware.co/open-source-license/
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions
+// and limitations under the License.
+
+func main() {
+ alloc_locals;
+
+ let res = fib(1, 1, 10);
+
+ assert res = 144;
+ // Return the updated output_ptr.
+ return ();
+}
+
+func fib(first_element: felt, second_element: felt, n: felt) -> felt {
+ if (n == 0) {
+ return second_element;
+ }
+
+ return fib(
+ first_element=second_element, second_element=first_element + second_element, n=n - 1
+ );
+}
diff --git a/provers/cairo/ffi/src/lib.rs b/provers/cairo/ffi/src/lib.rs
index b5ea7e0a5..468dd9dce 100644
--- a/provers/cairo/ffi/src/lib.rs
+++ b/provers/cairo/ffi/src/lib.rs
@@ -1,10 +1,11 @@
-use cairo_platinum_prover::air::CairoAIR;
+use cairo_platinum_prover::layouts::plain::air::CairoAIR;
use stark_platinum_prover::proof::options::ProofOptions;
use stark_platinum_prover::proof::options::SecurityLevel;
use stark_platinum_prover::transcript::StoneProverTranscript;
use stark_platinum_prover::verifier::{IsStarkVerifier, Verifier};
fn verify_cairo_proof_ffi(proof_bytes: &[u8], proof_options: &ProofOptions) -> bool {
+
let bytes = proof_bytes;
// This logic is the same as main verify, with only error handling changing. In ffi, we simply return a false if the proof is invalid, instead of rising an error.
@@ -54,6 +55,8 @@ pub extern "C" fn verify_cairo_proof_ffi_100_bits(
verify_cairo_proof_ffi(real_proof_bytes, &proof_options)
}
+
+/*
#[cfg(test)]
mod tests {
use super::*;
@@ -69,3 +72,4 @@ mod tests {
assert!(result)
}
}
+*/
diff --git a/provers/cairo/fibonacci.mem b/provers/cairo/fibonacci.mem
new file mode 100644
index 000000000..415476292
Binary files /dev/null and b/provers/cairo/fibonacci.mem differ
diff --git a/provers/cairo/fibonacci.trace b/provers/cairo/fibonacci.trace
new file mode 100644
index 000000000..ea329514d
Binary files /dev/null and b/provers/cairo/fibonacci.trace differ
diff --git a/provers/cairo/fibonacci_1000.json b/provers/cairo/fibonacci_1000.json
new file mode 100644
index 000000000..8cb0eba04
--- /dev/null
+++ b/provers/cairo/fibonacci_1000.json
@@ -0,0 +1,626 @@
+{
+ "attributes": [],
+ "builtins": [],
+ "compiler_version": "0.12.2",
+ "data": [
+ "0x40780017fff7fff",
+ "0x0",
+ "0x1104800180018000",
+ "0x4",
+ "0x10780017fff7fff",
+ "0x0",
+ "0x480680017fff8000",
+ "0x0",
+ "0x480680017fff8000",
+ "0x1",
+ "0x48307fff7ffe8000",
+ "0x480680017fff8000",
+ "0x2710",
+ "0x48127ffd7fff8000",
+ "0x48127ffd7fff8000",
+ "0x48307fff7ffe8000",
+ "0x482480017ffc8000",
+ "0x800000000000011000000000000000000000000000000000000000000000000",
+ "0x20680017fff7fff",
+ "0x800000000000010fffffffffffffffffffffffffffffffffffffffffffffffc",
+ "0x400680017fff7ffe",
+ "0xd",
+ "0x208b7fff7fff7ffe"
+ ],
+ "debug_info": {
+ "file_contents": {
+ "": "__start__:\nap += main.Args.SIZE + main.ImplicitArgs.SIZE;\ncall main;\n\n__end__:\njmp rel 0;\n"
+ },
+ "instruction_locations": {
+ "0": {
+ "accessible_scopes": [
+ "__main__"
+ ],
+ "flow_tracking_data": {
+ "ap_tracking": {
+ "group": 0,
+ "offset": 0
+ },
+ "reference_ids": {}
+ },
+ "hints": [],
+ "inst": {
+ "end_col": 46,
+ "end_line": 2,
+ "input_file": {
+ "filename": ""
+ },
+ "start_col": 1,
+ "start_line": 2
+ }
+ },
+ "2": {
+ "accessible_scopes": [
+ "__main__"
+ ],
+ "flow_tracking_data": {
+ "ap_tracking": {
+ "group": 0,
+ "offset": 0
+ },
+ "reference_ids": {}
+ },
+ "hints": [],
+ "inst": {
+ "end_col": 10,
+ "end_line": 3,
+ "input_file": {
+ "filename": ""
+ },
+ "start_col": 1,
+ "start_line": 3
+ }
+ },
+ "4": {
+ "accessible_scopes": [
+ "__main__"
+ ],
+ "flow_tracking_data": {
+ "ap_tracking": {
+ "group": 1,
+ "offset": 0
+ },
+ "reference_ids": {}
+ },
+ "hints": [],
+ "inst": {
+ "end_col": 10,
+ "end_line": 6,
+ "input_file": {
+ "filename": ""
+ },
+ "start_col": 1,
+ "start_line": 6
+ }
+ },
+ "6": {
+ "accessible_scopes": [
+ "__main__",
+ "__main__.main"
+ ],
+ "flow_tracking_data": {
+ "ap_tracking": {
+ "group": 2,
+ "offset": 0
+ },
+ "reference_ids": {}
+ },
+ "hints": [],
+ "inst": {
+ "end_col": 19,
+ "end_line": 8,
+ "input_file": {
+ "filename": "cairo_programs/cairo0/fibonacci_10000_loop.cairo"
+ },
+ "start_col": 18,
+ "start_line": 8
+ }
+ },
+ "8": {
+ "accessible_scopes": [
+ "__main__",
+ "__main__.main"
+ ],
+ "flow_tracking_data": {
+ "ap_tracking": {
+ "group": 2,
+ "offset": 1
+ },
+ "reference_ids": {
+ "__main__.main.x0": 0
+ }
+ },
+ "hints": [],
+ "inst": {
+ "end_col": 19,
+ "end_line": 9,
+ "input_file": {
+ "filename": "cairo_programs/cairo0/fibonacci_10000_loop.cairo"
+ },
+ "start_col": 18,
+ "start_line": 9
+ }
+ },
+ "10": {
+ "accessible_scopes": [
+ "__main__",
+ "__main__.main"
+ ],
+ "flow_tracking_data": {
+ "ap_tracking": {
+ "group": 2,
+ "offset": 2
+ },
+ "reference_ids": {
+ "__main__.main.x0": 0,
+ "__main__.main.x1": 1
+ }
+ },
+ "hints": [],
+ "inst": {
+ "end_col": 30,
+ "end_line": 10,
+ "input_file": {
+ "filename": "cairo_programs/cairo0/fibonacci_10000_loop.cairo"
+ },
+ "start_col": 23,
+ "start_line": 10
+ }
+ },
+ "11": {
+ "accessible_scopes": [
+ "__main__",
+ "__main__.main"
+ ],
+ "flow_tracking_data": {
+ "ap_tracking": {
+ "group": 2,
+ "offset": 3
+ },
+ "reference_ids": {
+ "__main__.main.fib_acc": 2,
+ "__main__.main.x0": 0,
+ "__main__.main.x1": 1
+ }
+ },
+ "hints": [],
+ "inst": {
+ "end_col": 22,
+ "end_line": 11,
+ "input_file": {
+ "filename": "cairo_programs/cairo0/fibonacci_10000_loop.cairo"
+ },
+ "start_col": 17,
+ "start_line": 11
+ }
+ },
+ "13": {
+ "accessible_scopes": [
+ "__main__",
+ "__main__.main"
+ ],
+ "flow_tracking_data": {
+ "ap_tracking": {
+ "group": 2,
+ "offset": 4
+ },
+ "reference_ids": {
+ "__main__.main.fib_acc": 2,
+ "__main__.main.n": 3,
+ "__main__.main.x0": 0,
+ "__main__.main.x1": 1
+ }
+ },
+ "hints": [],
+ "inst": {
+ "end_col": 15,
+ "end_line": 9,
+ "input_file": {
+ "filename": "cairo_programs/cairo0/fibonacci_10000_loop.cairo"
+ },
+ "parent_location": [
+ {
+ "end_col": 24,
+ "end_line": 13,
+ "input_file": {
+ "filename": "cairo_programs/cairo0/fibonacci_10000_loop.cairo"
+ },
+ "start_col": 22,
+ "start_line": 13
+ },
+ "While expanding the reference 'x1' in:"
+ ],
+ "start_col": 13,
+ "start_line": 9
+ }
+ },
+ "14": {
+ "accessible_scopes": [
+ "__main__",
+ "__main__.main"
+ ],
+ "flow_tracking_data": {
+ "ap_tracking": {
+ "group": 2,
+ "offset": 5
+ },
+ "reference_ids": {
+ "__main__.main.fib_acc": 2,
+ "__main__.main.n": 3,
+ "__main__.main.x0": 4,
+ "__main__.main.x1": 1
+ }
+ },
+ "hints": [],
+ "inst": {
+ "end_col": 20,
+ "end_line": 10,
+ "input_file": {
+ "filename": "cairo_programs/cairo0/fibonacci_10000_loop.cairo"
+ },
+ "parent_location": [
+ {
+ "end_col": 29,
+ "end_line": 14,
+ "input_file": {
+ "filename": "cairo_programs/cairo0/fibonacci_10000_loop.cairo"
+ },
+ "start_col": 22,
+ "start_line": 14
+ },
+ "While expanding the reference 'fib_acc' in:"
+ ],
+ "start_col": 13,
+ "start_line": 10
+ }
+ },
+ "15": {
+ "accessible_scopes": [
+ "__main__",
+ "__main__.main"
+ ],
+ "flow_tracking_data": {
+ "ap_tracking": {
+ "group": 2,
+ "offset": 6
+ },
+ "reference_ids": {
+ "__main__.main.fib_acc": 2,
+ "__main__.main.n": 3,
+ "__main__.main.x0": 4,
+ "__main__.main.x1": 5
+ }
+ },
+ "hints": [],
+ "inst": {
+ "end_col": 34,
+ "end_line": 15,
+ "input_file": {
+ "filename": "cairo_programs/cairo0/fibonacci_10000_loop.cairo"
+ },
+ "start_col": 27,
+ "start_line": 15
+ }
+ },
+ "16": {
+ "accessible_scopes": [
+ "__main__",
+ "__main__.main"
+ ],
+ "flow_tracking_data": {
+ "ap_tracking": {
+ "group": 2,
+ "offset": 7
+ },
+ "reference_ids": {
+ "__main__.main.fib_acc": 6,
+ "__main__.main.n": 3,
+ "__main__.main.x0": 4,
+ "__main__.main.x1": 5
+ }
+ },
+ "hints": [],
+ "inst": {
+ "end_col": 26,
+ "end_line": 16,
+ "input_file": {
+ "filename": "cairo_programs/cairo0/fibonacci_10000_loop.cairo"
+ },
+ "start_col": 21,
+ "start_line": 16
+ }
+ },
+ "18": {
+ "accessible_scopes": [
+ "__main__",
+ "__main__.main"
+ ],
+ "flow_tracking_data": {
+ "ap_tracking": {
+ "group": 2,
+ "offset": 8
+ },
+ "reference_ids": {
+ "__main__.main.fib_acc": 6,
+ "__main__.main.n": 7,
+ "__main__.main.x0": 4,
+ "__main__.main.x1": 5
+ }
+ },
+ "hints": [],
+ "inst": {
+ "end_col": 27,
+ "end_line": 17,
+ "input_file": {
+ "filename": "cairo_programs/cairo0/fibonacci_10000_loop.cairo"
+ },
+ "start_col": 9,
+ "start_line": 17
+ }
+ },
+ "20": {
+ "accessible_scopes": [
+ "__main__",
+ "__main__.main"
+ ],
+ "flow_tracking_data": {
+ "ap_tracking": {
+ "group": 2,
+ "offset": 8
+ },
+ "reference_ids": {
+ "__main__.main.fib_acc": 6,
+ "__main__.main.n": 7,
+ "__main__.main.x0": 4,
+ "__main__.main.x1": 5
+ }
+ },
+ "hints": [],
+ "inst": {
+ "end_col": 25,
+ "end_line": 19,
+ "input_file": {
+ "filename": "cairo_programs/cairo0/fibonacci_10000_loop.cairo"
+ },
+ "start_col": 5,
+ "start_line": 19
+ }
+ },
+ "22": {
+ "accessible_scopes": [
+ "__main__",
+ "__main__.main"
+ ],
+ "flow_tracking_data": {
+ "ap_tracking": {
+ "group": 2,
+ "offset": 8
+ },
+ "reference_ids": {
+ "__main__.main.fib_acc": 6,
+ "__main__.main.n": 7,
+ "__main__.main.x0": 4,
+ "__main__.main.x1": 5
+ }
+ },
+ "hints": [],
+ "inst": {
+ "end_col": 15,
+ "end_line": 20,
+ "input_file": {
+ "filename": "cairo_programs/cairo0/fibonacci_10000_loop.cairo"
+ },
+ "start_col": 5,
+ "start_line": 20
+ }
+ }
+ }
+ },
+ "hints": {},
+ "identifiers": {
+ "__main__.__end__": {
+ "pc": 4,
+ "type": "label"
+ },
+ "__main__.__start__": {
+ "pc": 0,
+ "type": "label"
+ },
+ "__main__.main": {
+ "decorators": [],
+ "pc": 6,
+ "type": "function"
+ },
+ "__main__.main.Args": {
+ "full_name": "__main__.main.Args",
+ "members": {},
+ "size": 0,
+ "type": "struct"
+ },
+ "__main__.main.ImplicitArgs": {
+ "full_name": "__main__.main.ImplicitArgs",
+ "members": {},
+ "size": 0,
+ "type": "struct"
+ },
+ "__main__.main.Return": {
+ "cairo_type": "()",
+ "type": "type_definition"
+ },
+ "__main__.main.SIZEOF_LOCALS": {
+ "type": "const",
+ "value": 0
+ },
+ "__main__.main.fib_acc": {
+ "cairo_type": "felt",
+ "full_name": "__main__.main.fib_acc",
+ "references": [
+ {
+ "ap_tracking_data": {
+ "group": 2,
+ "offset": 3
+ },
+ "pc": 11,
+ "value": "[cast(ap + (-1), felt*)]"
+ },
+ {
+ "ap_tracking_data": {
+ "group": 2,
+ "offset": 7
+ },
+ "pc": 16,
+ "value": "[cast(ap + (-1), felt*)]"
+ }
+ ],
+ "type": "reference"
+ },
+ "__main__.main.loop": {
+ "pc": 13,
+ "type": "label"
+ },
+ "__main__.main.n": {
+ "cairo_type": "felt",
+ "full_name": "__main__.main.n",
+ "references": [
+ {
+ "ap_tracking_data": {
+ "group": 2,
+ "offset": 4
+ },
+ "pc": 13,
+ "value": "[cast(ap + (-1), felt*)]"
+ },
+ {
+ "ap_tracking_data": {
+ "group": 2,
+ "offset": 8
+ },
+ "pc": 18,
+ "value": "[cast(ap + (-1), felt*)]"
+ }
+ ],
+ "type": "reference"
+ },
+ "__main__.main.x0": {
+ "cairo_type": "felt",
+ "full_name": "__main__.main.x0",
+ "references": [
+ {
+ "ap_tracking_data": {
+ "group": 2,
+ "offset": 1
+ },
+ "pc": 8,
+ "value": "[cast(ap + (-1), felt*)]"
+ },
+ {
+ "ap_tracking_data": {
+ "group": 2,
+ "offset": 5
+ },
+ "pc": 14,
+ "value": "[cast(ap + (-1), felt*)]"
+ }
+ ],
+ "type": "reference"
+ },
+ "__main__.main.x1": {
+ "cairo_type": "felt",
+ "full_name": "__main__.main.x1",
+ "references": [
+ {
+ "ap_tracking_data": {
+ "group": 2,
+ "offset": 2
+ },
+ "pc": 10,
+ "value": "[cast(ap + (-1), felt*)]"
+ },
+ {
+ "ap_tracking_data": {
+ "group": 2,
+ "offset": 6
+ },
+ "pc": 15,
+ "value": "[cast(ap + (-1), felt*)]"
+ }
+ ],
+ "type": "reference"
+ }
+ },
+ "main_scope": "__main__",
+ "prime": "0x800000000000011000000000000000000000000000000000000000000000001",
+ "reference_manager": {
+ "references": [
+ {
+ "ap_tracking_data": {
+ "group": 2,
+ "offset": 1
+ },
+ "pc": 8,
+ "value": "[cast(ap + (-1), felt*)]"
+ },
+ {
+ "ap_tracking_data": {
+ "group": 2,
+ "offset": 2
+ },
+ "pc": 10,
+ "value": "[cast(ap + (-1), felt*)]"
+ },
+ {
+ "ap_tracking_data": {
+ "group": 2,
+ "offset": 3
+ },
+ "pc": 11,
+ "value": "[cast(ap + (-1), felt*)]"
+ },
+ {
+ "ap_tracking_data": {
+ "group": 2,
+ "offset": 4
+ },
+ "pc": 13,
+ "value": "[cast(ap + (-1), felt*)]"
+ },
+ {
+ "ap_tracking_data": {
+ "group": 2,
+ "offset": 5
+ },
+ "pc": 14,
+ "value": "[cast(ap + (-1), felt*)]"
+ },
+ {
+ "ap_tracking_data": {
+ "group": 2,
+ "offset": 6
+ },
+ "pc": 15,
+ "value": "[cast(ap + (-1), felt*)]"
+ },
+ {
+ "ap_tracking_data": {
+ "group": 2,
+ "offset": 7
+ },
+ "pc": 16,
+ "value": "[cast(ap + (-1), felt*)]"
+ },
+ {
+ "ap_tracking_data": {
+ "group": 2,
+ "offset": 8
+ },
+ "pc": 18,
+ "value": "[cast(ap + (-1), felt*)]"
+ }
+ ]
+ }
+}
diff --git a/provers/cairo/new_proof.proof b/provers/cairo/new_proof.proof
new file mode 100644
index 000000000..10202eff7
Binary files /dev/null and b/provers/cairo/new_proof.proof differ
diff --git a/provers/cairo/simple.cairo b/provers/cairo/simple.cairo
new file mode 100644
index 000000000..455c84525
--- /dev/null
+++ b/provers/cairo/simple.cairo
@@ -0,0 +1,3 @@
+fn main() -> bool {
+ 2 == 2
+}
diff --git a/provers/cairo/simple.memory b/provers/cairo/simple.memory
new file mode 100644
index 000000000..8c57ff3d4
Binary files /dev/null and b/provers/cairo/simple.memory differ
diff --git a/provers/cairo/simple.trace b/provers/cairo/simple.trace
new file mode 100644
index 000000000..62903d8e4
Binary files /dev/null and b/provers/cairo/simple.trace differ
diff --git a/provers/cairo/src/decode/instruction_offsets.rs b/provers/cairo/src/decode/instruction_offsets.rs
index 09716045a..f29aeb345 100644
--- a/provers/cairo/src/decode/instruction_offsets.rs
+++ b/provers/cairo/src/decode/instruction_offsets.rs
@@ -34,12 +34,12 @@ impl InstructionOffsets {
i32::from(i16::from_le_bytes(aux))
}
- pub fn to_trace_representation(&self) -> [FieldElement; 3] {
- [
+ pub fn to_trace_representation(&self) -> (Felt252, Felt252, Felt252) {
+ (
to_unbiased_representation(self.off_dst),
to_unbiased_representation(self.off_op0),
to_unbiased_representation(self.off_op1),
- ]
+ )
}
}
diff --git a/provers/cairo/src/execution_trace.rs b/provers/cairo/src/execution_trace.rs
index eece1d28d..a9fc47e4f 100644
--- a/provers/cairo/src/execution_trace.rs
+++ b/provers/cairo/src/execution_trace.rs
@@ -1,3 +1,5 @@
+use std::{collections::VecDeque, iter};
+
use super::{
cairo_mem::CairoMemory,
decode::{
@@ -9,92 +11,21 @@ use super::{
},
register_states::RegisterStates,
};
-use crate::air::{EXTRA_ADDR, RC_HOLES};
-use crate::{
- air::{
- PublicInputs, FRAME_DST_ADDR, FRAME_OP0_ADDR, FRAME_OP1_ADDR, FRAME_PC, OFF_DST, OFF_OP0,
- OFF_OP1,
- },
- Felt252,
-};
+use crate::layouts::plain::air::PublicInputs;
use cairo_vm::without_std::collections::HashMap;
+use itertools::Itertools;
use lambdaworks_math::{
field::fields::fft_friendly::stark_252_prime_field::Stark252PrimeField,
unsigned_integer::element::UnsignedInteger,
};
-use stark_platinum_prover::trace::TraceTable;
-
-type CairoTraceTable = TraceTable;
-
-// MAIN TRACE LAYOUT
-// -----------------------------------------------------------------------------------------
-// A. flags (16) : Decoded instruction flags
-// B. res (1) : Res value
-// C. mem_p (2) : Temporary memory pointers (ap and fp)
-// D. mem_a (4) : Memory addresses (pc, dst_addr, op0_addr, op1_addr)
-// E. mem_v (4) : Memory values (inst, dst, op0, op1)
-// F. offsets (3) : (off_dst, off_op0, off_op1)
-// G. derived (3) : (t0, t1, mul)
-//
-// A B C D E F G
-// ├xxxxxxxxxxxxxxxx|x|xx|xxxx|xxxx|xxx|xxx┤
-//
-
-/// Builds the Cairo main trace (i.e. the trace without the auxiliary columns).
-/// Builds the execution trace, fills the offset range-check holes and memory holes, adds
-/// public memory dummy accesses (See section 9.8 of the Cairo whitepaper) and pads the result
-/// so that it has a trace length equal to the closest power of two.
-pub fn build_main_trace(
- register_states: &RegisterStates,
- memory: &CairoMemory,
- public_input: &mut PublicInputs,
-) -> CairoTraceTable {
- let mut main_trace = build_cairo_execution_trace(register_states, memory);
-
- let mut address_cols =
- main_trace.merge_columns(&[FRAME_PC, FRAME_DST_ADDR, FRAME_OP0_ADDR, FRAME_OP1_ADDR]);
-
- address_cols.sort_by_key(|x| x.representative());
-
- let (rc_holes, rc_min, rc_max) = get_rc_holes(&main_trace, &[OFF_DST, OFF_OP0, OFF_OP1]);
+use stark_platinum_prover::{fri::FieldElement, trace::TraceTable, Felt252};
+pub type CairoTraceTable = TraceTable;
- // this will avaluate to true if the public inputs weren't obtained from the run_program() function
- if public_input.range_check_min.is_none() && public_input.range_check_max.is_none() {
- public_input.range_check_min = Some(rc_min);
- public_input.range_check_max = Some(rc_max);
- }
- fill_rc_holes(&mut main_trace, &rc_holes);
-
- let memory_holes = get_memory_holes(&address_cols, &public_input.public_memory);
-
- if !memory_holes.is_empty() {
- fill_memory_holes(&mut main_trace, &memory_holes);
- }
-
- add_pub_memory_dummy_accesses(
- &mut main_trace,
- public_input.public_memory.len(),
- memory_holes.len(),
- );
-
- let trace_len_next_power_of_two = main_trace.n_rows().next_power_of_two();
- let padding_len = trace_len_next_power_of_two - main_trace.n_rows();
- main_trace.pad_with_last_row(padding_len);
+// NOTE: This should be deleted and use CairoAIR::STEP_SIZE once it is set to 16
+const CAIRO_STEP: usize = 16;
- main_trace
-}
-
-/// Artificial `(0, 0)` dummy memory accesses must be added for the public memory.
-/// See section 9.8 of the Cairo whitepaper.
-fn add_pub_memory_dummy_accesses(
- main_trace: &mut CairoTraceTable,
- pub_memory_len: usize,
- last_memory_hole_idx: usize,
-) {
- for i in 0..pub_memory_len {
- main_trace.set_or_extend(last_memory_hole_idx + i, EXTRA_ADDR, &Felt252::zero());
- }
-}
+const PLAIN_LAYOUT_NUM_MAIN_COLUMNS: usize = 6;
+const PLAIN_LAYOUT_NUM_AUX_COLUMNS: usize = 2;
/// Gets holes from the range-checked columns. These holes must be filled for the
/// permutation range-checks, as can be read in section 9.9 of the Cairo whitepaper.
@@ -103,52 +34,25 @@ fn add_pub_memory_dummy_accesses(
/// values rc_min and rc_max, corresponding to the minimum and maximum values of the range.
/// NOTE: These extreme values should be received as public inputs in the future and not
/// calculated here.
-fn get_rc_holes(trace: &CairoTraceTable, columns_indices: &[usize]) -> (Vec, u16, u16) {
- let offset_columns = trace.merge_columns(columns_indices);
+fn get_rc_holes(sorted_rc_values: &[u16]) -> VecDeque {
+ let mut rc_holes = VecDeque::new();
- let mut sorted_offset_representatives: Vec = offset_columns
- .iter()
- .map(|x| x.representative().into())
- .collect();
- sorted_offset_representatives.sort();
+ let mut prev_rc_value = sorted_rc_values[0];
- let mut all_missing_values: Vec = Vec::new();
+ for rc_value in sorted_rc_values.iter() {
+ let rc_diff = rc_value - prev_rc_value;
+ if rc_diff != 1 && rc_diff != 0 {
+ let mut rc_hole = prev_rc_value + 1;
- for window in sorted_offset_representatives.windows(2) {
- if window[1] != window[0] {
- let mut missing_range: Vec<_> = ((window[0] + 1)..window[1])
- .map(|x| Felt252::from(x as u64))
- .collect();
- all_missing_values.append(&mut missing_range);
+ while rc_hole < *rc_value {
+ rc_holes.push_back(Felt252::from(rc_hole as u64));
+ rc_hole += 1;
+ }
}
+ prev_rc_value = *rc_value;
}
- let multiple_of_three_padding =
- ((all_missing_values.len() + 2) / 3) * 3 - all_missing_values.len();
- let padding_element = Felt252::from(*sorted_offset_representatives.last().unwrap() as u64);
- all_missing_values.append(&mut vec![padding_element; multiple_of_three_padding]);
-
- (
- all_missing_values,
- sorted_offset_representatives[0],
- sorted_offset_representatives.last().cloned().unwrap(),
- )
-}
-
-/// Fills holes found in the range-checked columns.
-fn fill_rc_holes(trace: &mut CairoTraceTable, holes: &[Felt252]) {
- holes.iter().enumerate().for_each(|(i, hole)| {
- trace.set_or_extend(i, RC_HOLES, hole);
- });
-
- // Fill the rest of the RC_HOLES column to avoid inexistent zeros
- let mut offsets = trace.merge_columns(&[OFF_DST, OFF_OP0, OFF_OP1, RC_HOLES]);
-
- offsets.sort_by_key(|x| x.representative());
- let greatest_offset = offsets.last().unwrap();
- (holes.len()..trace.n_rows()).for_each(|i| {
- trace.set_or_extend(i, RC_HOLES, greatest_offset);
- });
+ rc_holes
}
/// Get memory holes from accessed addresses. These memory holes appear
@@ -158,13 +62,14 @@ fn fill_rc_holes(trace: &mut CairoTraceTable, holes: &[Felt252]) {
/// # Arguments
///
/// * `sorted_addrs` - Vector of sorted memory addresses.
-/// * `pub_memory` - The public memory of the executed program.
+/// * `codelen` - the length of the Cairo program instructions.
fn get_memory_holes(
sorted_addrs: &[Felt252],
pub_memory: &HashMap,
-) -> Vec {
- let mut memory_holes = Vec::new();
+) -> VecDeque {
+ let mut memory_holes = VecDeque::new();
let mut prev_addr = &sorted_addrs[0];
+ let one = Felt252::one();
for addr in sorted_addrs.iter() {
let addr_diff = addr - prev_addr;
@@ -172,27 +77,23 @@ fn get_memory_holes(
// If the candidate memory hole has an address belonging to the program segment (public
// memory), that is not accounted here since public memory is added in a posterior step of
// the protocol.
- if addr_diff != Felt252::one() && addr_diff != Felt252::zero() {
- let mut hole_addr = prev_addr + Felt252::one();
+ if addr_diff != one && addr_diff != Felt252::zero() {
+ let mut hole_addr = prev_addr + one;
while hole_addr.representative() < addr.representative() {
if !pub_memory.contains_key(&hole_addr) {
- memory_holes.push(hole_addr);
+ memory_holes.push_back(hole_addr);
}
- hole_addr += Felt252::one();
+ hole_addr += one;
}
}
prev_addr = addr;
}
- memory_holes
-}
+ let max_addr_plus_one = sorted_addrs.last().unwrap() + one;
+ memory_holes.push_back(max_addr_plus_one);
-/// Fill memory holes in the extra address column of the trace with the missing addresses.
-fn fill_memory_holes(trace: &mut CairoTraceTable, memory_holes: &[Felt252]) {
- memory_holes.iter().enumerate().for_each(|(i, hole)| {
- trace.set_or_extend(i, EXTRA_ADDR, hole);
- });
+ memory_holes
}
/// Receives the raw Cairo trace and memory as outputted from the Cairo VM and returns
@@ -202,24 +103,26 @@ fn fill_memory_holes(trace: &mut CairoTraceTable, memory_holes: &[Felt252]) {
pub fn build_cairo_execution_trace(
register_states: &RegisterStates,
memory: &CairoMemory,
+ public_input: &mut PublicInputs,
) -> CairoTraceTable {
- let n_steps = register_states.steps();
+ let num_steps = register_states.steps();
// Instruction flags and offsets are decoded from the raw instructions and represented
// by the CairoInstructionFlags and InstructionOffsets as an intermediate representation
- let (flags, offsets): (Vec, Vec) = register_states
- .flags_and_offsets(memory)
- .unwrap()
- .into_iter()
- .unzip();
+ let (flags, biased_offsets): (Vec, Vec) =
+ register_states
+ .flags_and_offsets(memory)
+ .unwrap()
+ .into_iter()
+ .unzip();
// dst, op0, op1 and res are computed from flags and offsets
let (dst_addrs, mut dsts): (Vec, Vec) =
- compute_dst(&flags, &offsets, register_states, memory);
+ compute_dst(&flags, &biased_offsets, register_states, memory);
let (op0_addrs, mut op0s): (Vec, Vec) =
- compute_op0(&flags, &offsets, register_states, memory);
+ compute_op0(&flags, &biased_offsets, register_states, memory);
let (op1_addrs, op1s): (Vec, Vec) =
- compute_op1(&flags, &offsets, register_states, memory, &op0s);
+ compute_op1(&flags, &biased_offsets, register_states, memory, &op0s);
let mut res = compute_res(&flags, &op0s, &op1s, &dsts);
// In some cases op0, dst or res may need to be updated from the already calculated values
@@ -227,11 +130,11 @@ pub fn build_cairo_execution_trace(
// Flags and offsets are transformed to a bit representation. This is needed since
// the flag constraints of the Cairo AIR are defined over bit representations of these
- let trace_repr_flags: Vec<[Felt252; 16]> = flags
+ let bit_prefix_flags: Vec<[Felt252; 16]> = flags
.iter()
.map(CairoInstructionFlags::to_trace_representation)
.collect();
- let trace_repr_offsets: Vec<[Felt252; 3]> = offsets
+ let unbiased_offsets: Vec<(Felt252, Felt252, Felt252)> = biased_offsets
.iter()
.map(InstructionOffsets::to_trace_representation)
.collect();
@@ -242,16 +145,19 @@ pub fn build_cairo_execution_trace(
.iter()
.map(|t| Felt252::from(t.ap))
.collect();
+
let fps: Vec = register_states
.rows
.iter()
.map(|t| Felt252::from(t.fp))
.collect();
+
let pcs: Vec = register_states
.rows
.iter()
.map(|t| Felt252::from(t.pc))
.collect();
+
let instructions: Vec = register_states
.rows
.iter()
@@ -261,7 +167,7 @@ pub fn build_cairo_execution_trace(
// t0, t1 and mul derived values are constructed. For details reFelt252r to
// section 9.1 of the Cairo whitepaper
let two = Felt252::from(2);
- let t0: Vec = trace_repr_flags
+ let t0: Vec = bit_prefix_flags
.iter()
.zip(&dsts)
.map(|(repr_flags, dst)| (repr_flags[9] - two * repr_flags[10]) * dst)
@@ -269,39 +175,53 @@ pub fn build_cairo_execution_trace(
let t1: Vec = t0.iter().zip(&res).map(|(t, r)| t * r).collect();
let mul: Vec = op0s.iter().zip(&op1s).map(|(op0, op1)| op0 * op1).collect();
- // A structure change of the flags and offsets representations to fit into the arguments
- // expected by the TraceTable constructor. A vector of columns of the representations
- // is obtained from the rows representation.
- let trace_repr_flags = rows_to_cols(&trace_repr_flags);
- let trace_repr_offsets = rows_to_cols(&trace_repr_offsets);
-
- let extra_addrs = vec![Felt252::zero(); n_steps];
- let extra_vals = extra_addrs.clone();
- let rc_holes = extra_addrs.clone();
-
- // Build Cairo trace columns to instantiate TraceTable struct as defined in the trace layout
- let mut trace_cols: Vec> = Vec::new();
- (0..trace_repr_flags.len()).for_each(|n| trace_cols.push(trace_repr_flags[n].clone()));
- trace_cols.push(res);
- trace_cols.push(aps);
- trace_cols.push(fps);
- trace_cols.push(pcs);
- trace_cols.push(dst_addrs);
- trace_cols.push(op0_addrs);
- trace_cols.push(op1_addrs);
- trace_cols.push(instructions);
- trace_cols.push(dsts);
- trace_cols.push(op0s);
- trace_cols.push(op1s);
- (0..trace_repr_offsets.len()).for_each(|n| trace_cols.push(trace_repr_offsets[n].clone()));
- trace_cols.push(t0);
- trace_cols.push(t1);
- trace_cols.push(mul);
- trace_cols.push(extra_addrs);
- trace_cols.push(extra_vals);
- trace_cols.push(rc_holes);
-
- TraceTable::from_columns_main(trace_cols, 1)
+ let mut trace: CairoTraceTable = TraceTable::allocate_with_zeros(
+ num_steps,
+ PLAIN_LAYOUT_NUM_MAIN_COLUMNS,
+ PLAIN_LAYOUT_NUM_AUX_COLUMNS,
+ CAIRO_STEP,
+ );
+
+ let rc_values = set_rc_pool(&mut trace, unbiased_offsets);
+ set_bit_prefix_flags(&mut trace, bit_prefix_flags);
+ let mut sorted_addrs = set_mem_pool(
+ &mut trace,
+ pcs,
+ instructions,
+ op0_addrs,
+ op0s,
+ dst_addrs,
+ dsts,
+ op1_addrs,
+ op1s,
+ );
+ set_update_pc(&mut trace, aps, t0, t1, mul, fps, res);
+
+ // Sort values in rc pool
+ let mut sorted_rc_value_representatives: Vec = rc_values
+ .iter()
+ .map(|x| x.representative().into())
+ .collect();
+ sorted_rc_value_representatives.sort();
+ let rc_holes = get_rc_holes(&sorted_rc_value_representatives);
+ let rc_max = Felt252::from(*(sorted_rc_value_representatives.last().unwrap()) as u64);
+ finalize_rc_pool(&mut trace, rc_holes, rc_max);
+
+ // Get all rc values.
+ // NOTE: We are sorting these values again, once for finding rc holes and one for the sorted column construction.
+ // This could be rethinked for better performance
+ let mut sorted_rc_column = trace.get_column_main(0);
+ sorted_rc_column.sort_by_key(|x| x.representative());
+ set_sorted_rc_pool(&mut trace, sorted_rc_column);
+
+ // Add memory holes
+ sorted_addrs.sort_by_key(|x| x.representative());
+ let memory_holes = get_memory_holes(&sorted_addrs, &public_input.public_memory);
+ finalize_mem_pool(&mut trace, memory_holes);
+ // Sort memory and insert to trace
+ set_sorted_mem_pool(&mut trace, public_input.public_memory.clone());
+
+ trace
}
/// Returns the vector of res values.
@@ -522,20 +442,6 @@ fn update_values(
}
}
-/// Utility function to change from a rows representation to a columns
-/// representation of a slice of arrays.
-fn rows_to_cols(rows: &[[Felt252; N]]) -> Vec> {
- let n_cols = rows[0].len();
-
- (0..n_cols)
- .map(|col_idx| {
- rows.iter()
- .map(|elem| elem[col_idx])
- .collect::>()
- })
- .collect::>>()
-}
-
// NOTE: Leaving this function despite not being used anywhere. It could be useful once
// we implement layouts with the range-check builtin.
#[allow(dead_code)]
@@ -561,13 +467,365 @@ fn decompose_rc_values_into_trace_columns(rc_values: &[&Felt252]) -> [Vec) {
+ for (step_idx, flags) in bit_prefix_flags.into_iter().enumerate() {
+ for (flag_idx, flag) in flags.into_iter().enumerate() {
+ trace.set_main(flag_idx + CAIRO_STEP * step_idx, 1, flag);
+ }
+ }
+}
+
+// Column 0
+fn set_rc_pool(
+ trace: &mut CairoTraceTable,
+ offsets: Vec<(Felt252, Felt252, Felt252)>,
+) -> Vec {
+ // NOTE: We should check that these offsets correspond to the off0, off1 and off2.
+ const OFF_DST_OFFSET: usize = 0;
+ const OFF_OP0_OFFSET: usize = 8;
+ const OFF_OP1_OFFSET: usize = 4;
+
+ let mut rc_values = Vec::new();
+ for (step_idx, (off_dst, off_op0, off_op1)) in offsets.into_iter().enumerate() {
+ trace.set_main(OFF_DST_OFFSET + CAIRO_STEP * step_idx, 0, off_dst);
+ trace.set_main(OFF_OP0_OFFSET + CAIRO_STEP * step_idx, 0, off_op0);
+ trace.set_main(OFF_OP1_OFFSET + CAIRO_STEP * step_idx, 0, off_op1);
+
+ rc_values.push(off_dst);
+ rc_values.push(off_op0);
+ rc_values.push(off_op1);
+ }
+
+ rc_values
+}
+
+// Column 3
+#[allow(clippy::too_many_arguments)]
+fn set_mem_pool(
+ trace: &mut CairoTraceTable,
+ pcs: Vec,
+ instructions: Vec,
+ op0_addrs: Vec,
+ op0_vals: Vec,
+ dst_addrs: Vec,
+ dst_vals: Vec,
+ op1_addrs: Vec,
+ op1_vals: Vec,
+) -> Vec {
+ const PC_OFFSET: usize = 0;
+ const INST_OFFSET: usize = 1;
+ const OP0_ADDR_OFFSET: usize = 4;
+ const OP0_VAL_OFFSET: usize = 5;
+ const DST_ADDR_OFFSET: usize = 8;
+ const DST_VAL_OFFSET: usize = 9;
+ const OP1_ADDR_OFFSET: usize = 12;
+ const OP1_VAL_OFFSET: usize = 13;
+
+ let mut addrs: Vec = Vec::new();
+ for (step_idx, (pc, inst, op0_addr, op0_val, dst_addr, dst_val, op1_addr, op1_val)) in
+ itertools::izip!(
+ pcs,
+ instructions,
+ op0_addrs,
+ op0_vals,
+ dst_addrs,
+ dst_vals,
+ op1_addrs,
+ op1_vals
+ )
+ .enumerate()
+ {
+ trace.set_main(PC_OFFSET + CAIRO_STEP * step_idx, 3, pc);
+ trace.set_main(INST_OFFSET + CAIRO_STEP * step_idx, 3, inst);
+ trace.set_main(OP0_ADDR_OFFSET + CAIRO_STEP * step_idx, 3, op0_addr);
+ trace.set_main(OP0_VAL_OFFSET + CAIRO_STEP * step_idx, 3, op0_val);
+ trace.set_main(DST_ADDR_OFFSET + CAIRO_STEP * step_idx, 3, dst_addr);
+ trace.set_main(DST_VAL_OFFSET + CAIRO_STEP * step_idx, 3, dst_val);
+ trace.set_main(OP1_ADDR_OFFSET + CAIRO_STEP * step_idx, 3, op1_addr);
+ trace.set_main(OP1_VAL_OFFSET + CAIRO_STEP * step_idx, 3, op1_val);
+
+ addrs.push(pc);
+ addrs.push(op0_addr);
+ addrs.push(dst_addr);
+ addrs.push(op1_addr);
+ }
+
+ addrs
+}
+
+// Column 5
+fn set_update_pc(
+ trace: &mut CairoTraceTable,
+ aps: Vec,
+ t0s: Vec,
+ t1s: Vec,
+ mul: Vec,
+ fps: Vec,
+ res: Vec,
+) {
+ const AP_OFFSET: usize = 0;
+ const TMP0_OFFSET: usize = 2;
+ const OPS_MUL_OFFSET: usize = 4;
+ const FP_OFFSET: usize = 8;
+ const TMP1_OFFSET: usize = 10;
+ const RES_OFFSET: usize = 12;
+
+ for (step_idx, (ap, tmp0, m, fp, tmp1, res)) in
+ itertools::izip!(aps, t0s, mul, fps, t1s, res).enumerate()
+ {
+ trace.set_main(AP_OFFSET + CAIRO_STEP * step_idx, 5, ap);
+ trace.set_main(TMP0_OFFSET + CAIRO_STEP * step_idx, 5, tmp0);
+ trace.set_main(OPS_MUL_OFFSET + CAIRO_STEP * step_idx, 5, m);
+ trace.set_main(FP_OFFSET + CAIRO_STEP * step_idx, 5, fp);
+ trace.set_main(TMP1_OFFSET + CAIRO_STEP * step_idx, 5, tmp1);
+ trace.set_main(RES_OFFSET + CAIRO_STEP * step_idx, 5, res);
+ }
+}
+
+fn finalize_mem_pool(trace: &mut CairoTraceTable, memory_holes: VecDeque) {
+ const MEM_POOL_UNUSED_ADDR_OFFSET: usize = 6;
+ const MEM_POOL_UNUSED_VALUE_OFFSET: usize = 7;
+ const MEM_POOL_UNUSED_CELL_STEP: usize = 8;
+
+ let mut memory_holes = memory_holes;
+
+ let last_hole_addr = memory_holes.pop_back().unwrap();
+
+ for step_idx in 0..trace.num_steps() {
+ if let Some(hole_addr) = memory_holes.pop_front() {
+ trace.set_main(
+ MEM_POOL_UNUSED_ADDR_OFFSET + CAIRO_STEP * step_idx,
+ 3,
+ hole_addr,
+ );
+ trace.set_main(
+ MEM_POOL_UNUSED_VALUE_OFFSET + CAIRO_STEP * step_idx,
+ 3,
+ Felt252::zero(),
+ );
+ } else {
+ trace.set_main(
+ MEM_POOL_UNUSED_ADDR_OFFSET + CAIRO_STEP * step_idx,
+ 3,
+ last_hole_addr,
+ );
+ trace.set_main(
+ MEM_POOL_UNUSED_VALUE_OFFSET + CAIRO_STEP * step_idx,
+ 3,
+ Felt252::zero(),
+ );
+ }
+
+ if let Some(hole_addr) = memory_holes.pop_front() {
+ trace.set_main(
+ MEM_POOL_UNUSED_ADDR_OFFSET + MEM_POOL_UNUSED_CELL_STEP + CAIRO_STEP * step_idx,
+ 3,
+ hole_addr,
+ );
+ trace.set_main(
+ MEM_POOL_UNUSED_VALUE_OFFSET + MEM_POOL_UNUSED_CELL_STEP + CAIRO_STEP * step_idx,
+ 3,
+ Felt252::zero(),
+ );
+ } else {
+ trace.set_main(
+ MEM_POOL_UNUSED_ADDR_OFFSET + MEM_POOL_UNUSED_CELL_STEP + CAIRO_STEP * step_idx,
+ 3,
+ last_hole_addr,
+ );
+ trace.set_main(
+ MEM_POOL_UNUSED_VALUE_OFFSET + MEM_POOL_UNUSED_CELL_STEP + CAIRO_STEP * step_idx,
+ 3,
+ Felt252::zero(),
+ );
+ }
+
+ assert!(memory_holes.is_empty());
+ }
+}
+
+fn set_sorted_rc_pool(trace: &mut CairoTraceTable, sorted_rc_column: Vec) {
+ for (row_idx, rc_value) in sorted_rc_column.into_iter().enumerate() {
+ trace.set_main(row_idx, 2, rc_value);
+ }
+}
+
+fn finalize_rc_pool(trace: &mut CairoTraceTable, rc_holes: VecDeque, rc_max: Felt252) {
+ let mut rc_holes = rc_holes;
+
+ let reserved_cell_idxs = [4, 8];
+ for step_idx in 0..trace.num_steps() {
+ for step_cell_idx in 1..CAIRO_STEP {
+ if reserved_cell_idxs.contains(&step_cell_idx) {
+ continue;
+ };
+ if let Some(rc_hole) = rc_holes.pop_front() {
+ trace.set_main(step_idx * CAIRO_STEP + step_cell_idx, 0, rc_hole);
+ } else {
+ trace.set_main(step_idx * CAIRO_STEP + step_cell_idx, 0, rc_max);
+ }
+ }
+ }
+
+ assert!(rc_holes.is_empty());
+}
+
+fn set_sorted_mem_pool(trace: &mut CairoTraceTable, pub_memory: HashMap) {
+ const PUB_MEMORY_ADDR_OFFSET: usize = 2;
+ const PUB_MEMORY_VALUE_OFFSET: usize = 3;
+ const PUB_MEMORY_STEP: usize = 8;
+
+ assert!(2 * trace.num_steps() >= pub_memory.len());
+
+ let mut mem_pool = trace.get_column_main(3);
+ let first_pub_memory_addr = Felt252::one();
+ let first_pub_memory_value = *pub_memory.get(&first_pub_memory_addr).unwrap();
+ let first_pub_memory_entry_padding_len = 2 * trace.num_steps() - pub_memory.len();
+
+ let padding_num_steps = first_pub_memory_entry_padding_len.div_ceil(2);
+ let mut first_addr_padding =
+ iter::repeat(first_pub_memory_addr).take(first_pub_memory_entry_padding_len);
+ let mut padding_step_flag = 0;
+
+ // this loop is for padding with (first_pub_addr, first_pub_value)
+ for step_idx in 0..padding_num_steps {
+ if let Some(first_addr) = first_addr_padding.next() {
+ mem_pool[PUB_MEMORY_ADDR_OFFSET + CAIRO_STEP * step_idx] = first_addr;
+ mem_pool[PUB_MEMORY_VALUE_OFFSET + CAIRO_STEP * step_idx] = first_pub_memory_value;
+ } else {
+ padding_step_flag = 0;
+ break;
+ }
+ if let Some(first_addr) = first_addr_padding.next() {
+ mem_pool[PUB_MEMORY_STEP + PUB_MEMORY_ADDR_OFFSET + CAIRO_STEP * step_idx] = first_addr;
+ mem_pool[PUB_MEMORY_STEP + PUB_MEMORY_VALUE_OFFSET + CAIRO_STEP * step_idx] =
+ first_pub_memory_value;
+ } else {
+ padding_step_flag = 1;
+ break;
+ }
+ }
+
+ let mut pub_memory_iter = pub_memory.iter();
+ if padding_step_flag == 1 {
+ let (pub_memory_addr, pub_memory_value) = pub_memory_iter.next().unwrap();
+ mem_pool[PUB_MEMORY_STEP + PUB_MEMORY_ADDR_OFFSET + CAIRO_STEP * (padding_num_steps - 1)] =
+ *pub_memory_addr;
+ mem_pool
+ [PUB_MEMORY_STEP + PUB_MEMORY_VALUE_OFFSET + CAIRO_STEP * (padding_num_steps - 1)] =
+ *pub_memory_value;
+ }
+
+ for step_idx in padding_num_steps..trace.num_steps() {
+ let (pub_memory_addr, pub_memory_value) = pub_memory_iter.next().unwrap();
+ mem_pool[PUB_MEMORY_ADDR_OFFSET + CAIRO_STEP * step_idx] = *pub_memory_addr;
+ mem_pool[PUB_MEMORY_VALUE_OFFSET + CAIRO_STEP * step_idx] = *pub_memory_value;
+
+ let (pub_memory_addr, pub_memory_value) = pub_memory_iter.next().unwrap();
+ mem_pool[PUB_MEMORY_STEP + PUB_MEMORY_ADDR_OFFSET + CAIRO_STEP * step_idx] =
+ *pub_memory_addr;
+ mem_pool[PUB_MEMORY_STEP + PUB_MEMORY_VALUE_OFFSET + CAIRO_STEP * step_idx] =
+ *pub_memory_value;
+ }
+
+ let mut addrs = Vec::with_capacity(trace.num_rows() / 2);
+ let mut values = Vec::with_capacity(trace.num_rows() / 2);
+ let mut sorted_addrs = Vec::with_capacity(trace.num_rows() / 2);
+ let mut sorted_values = Vec::with_capacity(trace.num_rows() / 2);
+ for (idx, mem_cell) in mem_pool.into_iter().enumerate() {
+ if idx % 2 == 0 {
+ let addr = mem_cell;
+ addrs.push(addr);
+ } else {
+ let value = mem_cell;
+ values.push(value);
+ }
+ }
+
+ let mut sorted_addr_idxs: Vec = (0..addrs.len()).collect();
+ sorted_addr_idxs.sort_by_key(|&idx| addrs[idx]);
+ for idx in sorted_addr_idxs.iter() {
+ sorted_addrs.push(addrs[*idx]);
+ sorted_values.push(values[*idx]);
+ }
+
+ let mut sorted_addrs_iter = sorted_addrs.into_iter();
+ let mut sorted_values_iter = sorted_values.into_iter();
+ for row_idx in 0..trace.num_rows() {
+ if row_idx % 2 == 0 {
+ let addr = sorted_addrs_iter.next().unwrap();
+ trace.set_main(row_idx, 4, addr);
+ } else {
+ let value = sorted_values_iter.next().unwrap();
+ trace.set_main(row_idx, 4, value);
+ }
+ }
+}
+
+pub(crate) fn set_rc_permutation_column(trace: &mut CairoTraceTable, z: &Felt252) {
+ let mut denominator_evaluations = trace
+ .get_column_main(2)
+ .iter()
+ .map(|a_prime| z - a_prime)
+ .collect_vec();
+ FieldElement::inplace_batch_inverse(&mut denominator_evaluations).unwrap();
+
+ let rc_cumulative_procuts = trace
+ .get_column_main(0)
+ .iter()
+ .zip(&denominator_evaluations)
+ .scan(Felt252::one(), |product, (num_i, den_i)| {
+ let ret = *product;
+ *product = ret * (z - num_i) * den_i;
+ Some(*product)
+ })
+ .collect_vec();
+
+ for (i, rc_perm_i) in rc_cumulative_procuts.into_iter().enumerate() {
+ trace.set_aux(i, 0, rc_perm_i)
+ }
+}
+
+pub(crate) fn set_mem_permutation_column(
+ trace: &mut CairoTraceTable,
+ alpha_mem: &Felt252,
+ z_mem: &Felt252,
+) {
+ let sorted_mem_pool = trace.get_column_main(4);
+ let sorted_addrs = sorted_mem_pool.iter().step_by(2).collect_vec();
+ let sorted_values = sorted_mem_pool[1..].iter().step_by(2).collect_vec();
+
+ let mut denominator = std::iter::zip(sorted_addrs, sorted_values)
+ .map(|(ap, vp)| z_mem - (ap + alpha_mem * vp))
+ .collect_vec();
+ FieldElement::inplace_batch_inverse(&mut denominator).unwrap();
+
+ let mem_pool = trace.get_column_main(3);
+ let addrs = mem_pool.iter().step_by(2).collect_vec();
+ let values = mem_pool[1..].iter().step_by(2).collect_vec();
+
+ let mem_cumulative_products = itertools::izip!(addrs, values, denominator)
+ .scan(Felt252::one(), |product, (a_i, v_i, den_i)| {
+ let ret = *product;
+ *product = ret * ((z_mem - (a_i + alpha_mem * v_i)) * den_i);
+ Some(*product)
+ })
+ .collect_vec();
+
+ for (i, row_idx) in (0..trace.num_rows()).step_by(2).enumerate() {
+ let mem_cumul_prod = mem_cumulative_products[i];
+ trace.set_aux(row_idx, 1, mem_cumul_prod);
+ }
+}
+
#[cfg(test)]
mod test {
- use crate::air::EXTRA_VAL;
use super::*;
- use lambdaworks_math::field::element::FieldElement;
- use stark_platinum_prover::table::Table;
+ use crate::{
+ cairo_layout::CairoLayout, runner::run::run_program, tests::utils::cairo0_program_path,
+ };
#[test]
fn test_rc_decompose() {
@@ -593,75 +851,13 @@ mod test {
assert_eq!(decomposition_columns[7][2], Felt252::from_hex("1").unwrap());
}
- #[test]
- fn test_fill_range_check_values() {
- let columns = vec![
- vec![FieldElement::from(1); 3],
- vec![FieldElement::from(4); 3],
- vec![FieldElement::from(7); 3],
- ];
- let expected_col = vec![
- FieldElement::from(2),
- FieldElement::from(3),
- FieldElement::from(5),
- FieldElement::from(6),
- FieldElement::from(7),
- FieldElement::from(7),
- ];
- let table = TraceTable::::from_columns(columns, 3, 1);
-
- let (col, rc_min, rc_max) = get_rc_holes(&table, &[0, 1, 2]);
- assert_eq!(col, expected_col);
- assert_eq!(rc_min, 1);
- assert_eq!(rc_max, 7);
- }
-
- #[test]
- fn test_add_missing_values_to_rc_holes_column() {
- let mut row = vec![Felt252::from(5); 36];
- row[35] = Felt252::zero();
- let data = row.repeat(8);
- let table = Table::new(data, 36);
-
- let mut main_trace = TraceTable:: {
- table,
- num_main_columns: 36,
- num_aux_columns: 23,
- step_size: 1,
- };
-
- let rc_holes = vec![
- Felt252::from(1),
- Felt252::from(2),
- Felt252::from(3),
- Felt252::from(4),
- Felt252::from(5),
- Felt252::from(6),
- ];
-
- fill_rc_holes(&mut main_trace, &rc_holes);
-
- let expected_rc_holes_column = vec![
- Felt252::from(1),
- Felt252::from(2),
- Felt252::from(3),
- Felt252::from(4),
- Felt252::from(5),
- Felt252::from(6),
- Felt252::from(6),
- Felt252::from(6),
- ];
-
- let rc_holes_column = main_trace.columns()[35].clone();
-
- assert_eq!(expected_rc_holes_column, rc_holes_column);
- }
-
#[test]
fn test_get_memory_holes_empty_pub_memory() {
// We construct a sorted addresses list [1, 2, 3, 6, 7, 8, 9, 13, 14, 15], and
// an empty public memory. This way, any holes present between
// the min and max addresses should be returned by the function.
+ // NOTE: The memory hole at address 16 will also be returned because the max addr
+ // +1 is considered a memory hole too.
let mut addrs: Vec = (1..4).map(Felt252::from).collect();
let addrs_extension: Vec = (6..10).map(Felt252::from).collect();
addrs.extend_from_slice(&addrs_extension);
@@ -669,13 +865,14 @@ mod test {
addrs.extend_from_slice(&addrs_extension);
let pub_memory = HashMap::new();
- let expected_memory_holes = vec![
+ let expected_memory_holes = VecDeque::from([
Felt252::from(4),
Felt252::from(5),
Felt252::from(10),
Felt252::from(11),
Felt252::from(12),
- ];
+ Felt252::from(16),
+ ]);
let calculated_memory_holes = get_memory_holes(&addrs, &pub_memory);
assert_eq!(expected_memory_holes, calculated_memory_holes);
@@ -692,13 +889,15 @@ mod test {
addrs.extend_from_slice(&addrs_extension);
let mut pub_memory = HashMap::new();
- (1..=9).for_each(|k| {
- let addr = Felt252::from(k);
- pub_memory.insert(addr, addr * Felt252::from(2));
- });
+ for addr in 1..=9 {
+ let addr = Felt252::from(addr);
+ pub_memory.insert(addr, Felt252::zero());
+ }
let calculated_memory_holes = get_memory_holes(&addrs, &pub_memory);
- let expected_memory_holes: Vec = Vec::new();
+
+ // max_addr + 1 (10, in this case) is always returned by the get_memory_holes function
+ let expected_memory_holes = VecDeque::from([Felt252::from(10)]);
assert_eq!(expected_memory_holes, calculated_memory_holes);
}
@@ -714,37 +913,252 @@ mod test {
addrs.extend_from_slice(&addrs_extension);
let mut pub_memory = HashMap::new();
- (1..=6).for_each(|k| {
- let addr = Felt252::from(k);
- pub_memory.insert(addr, addr * Felt252::from(2));
- });
+ for addr in 0..=6 {
+ let addr = Felt252::from(addr);
+ pub_memory.insert(addr, Felt252::zero());
+ }
let calculated_memory_holes = get_memory_holes(&addrs, &pub_memory);
- let expected_memory_holes = vec![Felt252::from(7)];
+ let expected_memory_holes = VecDeque::from([Felt252::from(7), Felt252::from(10)]);
assert_eq!(expected_memory_holes, calculated_memory_holes);
}
#[test]
- fn test_fill_memory_holes() {
- const TRACE_COL_LEN: usize = 2;
- const NUM_TRACE_COLS: usize = EXTRA_VAL + 1;
-
- let mut trace_cols = vec![vec![Felt252::zero(); TRACE_COL_LEN]; NUM_TRACE_COLS];
- trace_cols[FRAME_PC][0] = Felt252::one();
- trace_cols[FRAME_DST_ADDR][0] = Felt252::from(2);
- trace_cols[FRAME_OP0_ADDR][0] = Felt252::from(3);
- trace_cols[FRAME_OP1_ADDR][0] = Felt252::from(5);
- trace_cols[FRAME_PC][1] = Felt252::from(6);
- trace_cols[FRAME_DST_ADDR][1] = Felt252::from(9);
- trace_cols[FRAME_OP0_ADDR][1] = Felt252::from(10);
- trace_cols[FRAME_OP1_ADDR][1] = Felt252::from(11);
- let mut trace = TraceTable::from_columns(trace_cols, 2, 1);
-
- let memory_holes = vec![Felt252::from(4), Felt252::from(7), Felt252::from(8)];
- fill_memory_holes(&mut trace, &memory_holes);
-
- let extra_addr = &trace.columns()[EXTRA_ADDR];
- assert_eq!(extra_addr, &memory_holes);
+ fn set_rc_pool_works() {
+ let program_content = std::fs::read(cairo0_program_path("fibonacci_stone.json")).unwrap();
+ let mut trace: CairoTraceTable = TraceTable::allocate_with_zeros(128, 6, 2, 16);
+ let (register_states, memory, _) =
+ run_program(None, CairoLayout::Plain, &program_content).unwrap();
+
+ let (_, biased_offsets): (Vec, Vec) =
+ register_states
+ .flags_and_offsets(&memory)
+ .unwrap()
+ .into_iter()
+ .unzip();
+
+ let unbiased_offsets: Vec<(Felt252, Felt252, Felt252)> = biased_offsets
+ .iter()
+ .map(InstructionOffsets::to_trace_representation)
+ .collect();
+
+ let rc_values = set_rc_pool(&mut trace, unbiased_offsets);
+ let mut sorted_rc_values: Vec = rc_values
+ .iter()
+ .map(|x| x.representative().into())
+ .collect();
+ sorted_rc_values.sort();
+ let rc_holes = get_rc_holes(&sorted_rc_values);
+ let rc_max = Felt252::from(*(sorted_rc_values.last().unwrap()) as u64);
+ finalize_rc_pool(&mut trace, rc_holes, rc_max);
+
+ let mut sorted_rc_column = trace.get_column_main(0);
+ sorted_rc_column.sort_by_key(|x| x.representative());
+ set_sorted_rc_pool(&mut trace, sorted_rc_column);
+
+ trace.main_table.columns()[2]
+ .iter()
+ .enumerate()
+ .for_each(|(i, v)| println!("SORTED RC VAL {} - {}", i, v));
+ }
+
+ #[test]
+ fn set_update_pc_works() {
+ let program_content = std::fs::read(cairo0_program_path("fibonacci_stone.json")).unwrap();
+ let mut trace: CairoTraceTable = TraceTable::allocate_with_zeros(128, 6, 2, 16);
+ let (register_states, memory, _) =
+ run_program(None, CairoLayout::Plain, &program_content).unwrap();
+
+ let (flags, biased_offsets): (Vec, Vec) =
+ register_states
+ .flags_and_offsets(&memory)
+ .unwrap()
+ .into_iter()
+ .unzip();
+
+ // dst, op0, op1 and res are computed from flags and offsets
+ let (_dst_addrs, mut dsts): (Vec, Vec) =
+ compute_dst(&flags, &biased_offsets, ®ister_states, &memory);
+ let (_op0_addrs, mut op0s): (Vec, Vec) =
+ compute_op0(&flags, &biased_offsets, ®ister_states, &memory);
+ let (_op1_addrs, op1s): (Vec, Vec) =
+ compute_op1(&flags, &biased_offsets, ®ister_states, &memory, &op0s);
+ let mut res = compute_res(&flags, &op0s, &op1s, &dsts);
+
+ update_values(&flags, ®ister_states, &mut op0s, &mut dsts, &mut res);
+
+ let aps: Vec = register_states
+ .rows
+ .iter()
+ .map(|t| Felt252::from(t.ap))
+ .collect();
+ let fps: Vec = register_states
+ .rows
+ .iter()
+ .map(|t| Felt252::from(t.fp))
+ .collect();
+
+ let trace_repr_flags: Vec<[Felt252; 16]> = flags
+ .iter()
+ .map(CairoInstructionFlags::to_trace_representation)
+ .collect();
+
+ let two = Felt252::from(2);
+ let t0: Vec = trace_repr_flags
+ .iter()
+ .zip(&dsts)
+ .map(|(repr_flags, dst)| (repr_flags[9] - two * repr_flags[10]) * dst)
+ .collect();
+ let t1: Vec = t0.iter().zip(&res).map(|(t, r)| t * r).collect();
+ let mul: Vec = op0s.iter().zip(&op1s).map(|(op0, op1)| op0 * op1).collect();
+
+ set_update_pc(&mut trace, aps, t0, t1, mul, fps, res);
+
+ trace.main_table.columns()[5][0..50]
+ .iter()
+ .enumerate()
+ .for_each(|(i, v)| println!("ROW {} - VALUE: {}", i, v));
+ }
+
+ #[test]
+ fn set_mem_pool_works() {
+ let program_content = std::fs::read(cairo0_program_path("fibonacci_stone.json")).unwrap();
+ let mut trace: CairoTraceTable = TraceTable::allocate_with_zeros(128, 6, 2, 16);
+ let (register_states, memory, pub_inputs) =
+ run_program(None, CairoLayout::Plain, &program_content).unwrap();
+
+ let (flags, biased_offsets): (Vec, Vec) =
+ register_states
+ .flags_and_offsets(&memory)
+ .unwrap()
+ .into_iter()
+ .unzip();
+
+ // dst, op0, op1 and res are computed from flags and offsets
+ let (dst_addrs, mut dsts): (Vec, Vec) =
+ compute_dst(&flags, &biased_offsets, ®ister_states, &memory);
+ let (op0_addrs, mut op0s): (Vec, Vec) =
+ compute_op0(&flags, &biased_offsets, ®ister_states, &memory);
+ let (op1_addrs, op1s): (Vec, Vec) =
+ compute_op1(&flags, &biased_offsets, ®ister_states, &memory, &op0s);
+ let mut res = compute_res(&flags, &op0s, &op1s, &dsts);
+
+ update_values(&flags, ®ister_states, &mut op0s, &mut dsts, &mut res);
+
+ let pcs: Vec = register_states
+ .rows
+ .iter()
+ .map(|t| Felt252::from(t.pc))
+ .collect();
+ let instructions: Vec = register_states
+ .rows
+ .iter()
+ .map(|t| *memory.get(&t.pc).unwrap())
+ .collect();
+
+ let mut sorted_addrs = set_mem_pool(
+ &mut trace,
+ pcs,
+ instructions,
+ op0_addrs,
+ op0s,
+ dst_addrs,
+ dsts,
+ op1_addrs,
+ op1s,
+ );
+
+ sorted_addrs.sort_by_key(|x| x.representative());
+ let memory_holes = get_memory_holes(&sorted_addrs, &pub_inputs.public_memory);
+ finalize_mem_pool(&mut trace, memory_holes);
+
+ set_sorted_mem_pool(&mut trace, pub_inputs.public_memory);
+
+ let z = Felt252::from_hex_unchecked(
+ "0x6896a2e62f03d4d1f625efb97468ef93f31105bb51a83d550bca6fdebd035de",
+ );
+ let alpha = Felt252::from_hex_unchecked(
+ "0x64de8f5be59594e112d438c13ec4916e138b013e7d388b681c11b03ede7962e",
+ );
+ set_mem_permutation_column(&mut trace, &alpha, &z);
+
+ trace.aux_table.columns()[1]
+ .iter()
+ .enumerate()
+ .for_each(|(i, v)| println!("ROW {} - MEM CUMUL PROD: {}", i, v));
+ }
+
+ #[test]
+ fn set_bit_prefix_flags_works() {
+ let program_content = std::fs::read(cairo0_program_path("fibonacci_stone.json")).unwrap();
+ let mut trace: CairoTraceTable = TraceTable::allocate_with_zeros(128, 6, 2, 16);
+ let (register_states, memory, _) =
+ run_program(None, CairoLayout::Plain, &program_content).unwrap();
+
+ let (flags, _biased_offsets): (Vec, Vec) =
+ register_states
+ .flags_and_offsets(&memory)
+ .unwrap()
+ .into_iter()
+ .unzip();
+
+ let bit_prefix_flags: Vec<[Felt252; 16]> = flags
+ .iter()
+ .map(CairoInstructionFlags::to_trace_representation)
+ .collect();
+
+ set_bit_prefix_flags(&mut trace, bit_prefix_flags);
+
+ trace.main_table.columns()[1][0..50]
+ .iter()
+ .enumerate()
+ .for_each(|(i, v)| println!("ROW {} - VALUE: {}", i, v));
+ }
+
+ #[test]
+ fn set_rc_permutation_col_works() {
+ let program_content = std::fs::read(cairo0_program_path("fibonacci_stone.json")).unwrap();
+ let mut trace: CairoTraceTable = TraceTable::allocate_with_zeros(128, 6, 2, 16);
+ let (register_states, memory, _) =
+ run_program(None, CairoLayout::Plain, &program_content).unwrap();
+
+ let (_, biased_offsets): (Vec, Vec) =
+ register_states
+ .flags_and_offsets(&memory)
+ .unwrap()
+ .into_iter()
+ .unzip();
+
+ let unbiased_offsets: Vec<(Felt252, Felt252, Felt252)> = biased_offsets
+ .iter()
+ .map(InstructionOffsets::to_trace_representation)
+ .collect();
+
+ let rc_values = set_rc_pool(&mut trace, unbiased_offsets);
+ let mut sorted_rc_values: Vec = rc_values
+ .iter()
+ .map(|x| x.representative().into())
+ .collect();
+ sorted_rc_values.sort();
+
+ let rc_holes = get_rc_holes(&sorted_rc_values);
+ let rc_max = Felt252::from(*(sorted_rc_values.last().unwrap()) as u64);
+ finalize_rc_pool(&mut trace, rc_holes, rc_max);
+
+ let mut sorted_rc_column = trace.get_column_main(0);
+ sorted_rc_column.sort_by_key(|x| x.representative());
+ set_sorted_rc_pool(&mut trace, sorted_rc_column);
+
+ let z = Felt252::from_hex_unchecked(
+ "0x221ee7f99bdf1f11e16445f06fd90f413146e1764a1d16d46525148456cc3eb",
+ );
+
+ set_rc_permutation_column(&mut trace, &z);
+
+ trace.aux_table.columns()[0][..20]
+ .iter()
+ .enumerate()
+ .for_each(|(i, v)| println!("RC PERMUTATION ARG {} - {}", i, v));
}
}
diff --git a/provers/cairo/src/layouts/mod.rs b/provers/cairo/src/layouts/mod.rs
new file mode 100644
index 000000000..6c83de882
--- /dev/null
+++ b/provers/cairo/src/layouts/mod.rs
@@ -0,0 +1 @@
+pub mod plain;
diff --git a/provers/cairo/src/air.rs b/provers/cairo/src/layouts/plain/air.rs
similarity index 61%
rename from provers/cairo/src/air.rs
rename to provers/cairo/src/layouts/plain/air.rs
index 2d15f5672..9e0436e10 100644
--- a/provers/cairo/src/air.rs
+++ b/provers/cairo/src/layouts/plain/air.rs
@@ -1,7 +1,10 @@
-use super::{cairo_mem::CairoMemory, register_states::RegisterStates};
-use crate::transition_constraints::*;
+use crate::{
+ cairo_mem::CairoMemory,
+ execution_trace::{set_mem_permutation_column, set_rc_permutation_column, CairoTraceTable},
+ register_states::RegisterStates,
+ transition_constraints::*,
+};
use cairo_vm::{air_public_input::MemorySegmentAddresses, without_std::collections::HashMap};
-#[cfg(debug_assertions)]
use itertools::Itertools;
use lambdaworks_crypto::fiat_shamir::is_transcript::IsTranscript;
use lambdaworks_math::{
@@ -11,6 +14,7 @@ use lambdaworks_math::{
},
traits::{AsBytes, ByteConversion, Deserializable},
};
+use stark_platinum_prover::constraints::transition::TransitionConstraint;
use stark_platinum_prover::{
constraints::boundary::{BoundaryConstraint, BoundaryConstraints},
context::AirContext,
@@ -23,63 +27,6 @@ use stark_platinum_prover::{
verifier::{IsStarkVerifier, Verifier},
Felt252,
};
-use stark_platinum_prover::{constraints::transition::TransitionConstraint, table::Table};
-
-// TODO: These should probably be in the TraceTable module.
-pub const FRAME_RES: usize = 16;
-pub const FRAME_AP: usize = 17;
-pub const FRAME_FP: usize = 18;
-pub const FRAME_PC: usize = 19;
-pub const FRAME_DST_ADDR: usize = 20;
-pub const FRAME_OP0_ADDR: usize = 21;
-pub const FRAME_OP1_ADDR: usize = 22;
-pub const FRAME_INST: usize = 23;
-pub const FRAME_DST: usize = 24;
-pub const FRAME_OP0: usize = 25;
-pub const FRAME_OP1: usize = 26;
-pub const OFF_DST: usize = 27;
-pub const OFF_OP0: usize = 28;
-pub const OFF_OP1: usize = 29;
-pub const FRAME_T0: usize = 30;
-pub const FRAME_T1: usize = 31;
-pub const FRAME_MUL: usize = 32;
-pub const EXTRA_ADDR: usize = 33;
-pub const EXTRA_VAL: usize = 34;
-pub const RC_HOLES: usize = 35;
-
-// Auxiliary range check columns
-pub const RANGE_CHECK_COL_1: usize = 0;
-pub const RANGE_CHECK_COL_2: usize = 1;
-pub const RANGE_CHECK_COL_3: usize = 2;
-pub const RANGE_CHECK_COL_4: usize = 3;
-
-// Auxiliary memory columns
-pub const MEMORY_ADDR_SORTED_0: usize = 4;
-pub const MEMORY_ADDR_SORTED_1: usize = 5;
-pub const MEMORY_ADDR_SORTED_2: usize = 6;
-pub const MEMORY_ADDR_SORTED_3: usize = 7;
-pub const MEMORY_ADDR_SORTED_4: usize = 8;
-
-pub const MEMORY_VALUES_SORTED_0: usize = 9;
-pub const MEMORY_VALUES_SORTED_1: usize = 10;
-pub const MEMORY_VALUES_SORTED_2: usize = 11;
-pub const MEMORY_VALUES_SORTED_3: usize = 12;
-pub const MEMORY_VALUES_SORTED_4: usize = 13;
-
-pub const PERMUTATION_ARGUMENT_COL_0: usize = 14;
-pub const PERMUTATION_ARGUMENT_COL_1: usize = 15;
-pub const PERMUTATION_ARGUMENT_COL_2: usize = 16;
-pub const PERMUTATION_ARGUMENT_COL_3: usize = 17;
-pub const PERMUTATION_ARGUMENT_COL_4: usize = 18;
-
-pub const PERMUTATION_ARGUMENT_RANGE_CHECK_COL_1: usize = 19;
-pub const PERMUTATION_ARGUMENT_RANGE_CHECK_COL_2: usize = 20;
-pub const PERMUTATION_ARGUMENT_RANGE_CHECK_COL_3: usize = 21;
-pub const PERMUTATION_ARGUMENT_RANGE_CHECK_COL_4: usize = 22;
-
-// Trace layout
-pub const MEM_P_TRACE_OFFSET: usize = 17;
-pub const MEM_A_TRACE_OFFSET: usize = 19;
#[derive(Debug, Clone, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
pub enum SegmentName {
@@ -435,110 +382,12 @@ pub struct CairoAIR {
Vec>>,
}
-/// Receives two slices corresponding to the accessed addresses and values, filled with
-/// the memory holes and with the (0, 0) public memory dummy accesses.
-/// Each (address, value) public memory pair is written in a (0, 0) dummy access until
-/// there is no one left.
-///
-/// NOTE: At the end of this process there might be some additional (0, 0) dummy accesses
-/// that were not overwritten. This is not a problem as long as all the public memory pairs
-/// have been written.
-fn add_pub_memory_in_public_input_section(
- addresses: &[Felt252],
- values: &[Felt252],
- public_input: &PublicInputs,
-) -> (Vec, Vec) {
- let mut a_aux = addresses.to_owned();
- let mut v_aux = values.to_owned();
-
- let mut pub_addrs = public_input.public_memory.iter();
-
- // Iterate over addresses
- for (i, a) in a_aux.iter_mut().enumerate() {
- // When address `0` is found, it means it corresponds to a dummy access.
- if a == &Felt252::zero() {
- // While there are public memory addresses left, overwrite the dummy
- // (addr, value) accesses with the real public memory pairs.
- if let Some((pub_addr, pub_value)) = pub_addrs.next() {
- *a = *pub_addr;
- v_aux[i] = *pub_value;
- } else {
- // When there are no public memory pairs left to write, break the
- // loop and return the (addr, value) pairs with dummy accesses
- // overwritten.
- break;
- }
- }
- }
-
- (a_aux, v_aux)
-}
-
-fn sort_columns_by_memory_address(
- adresses: Vec,
- values: Vec,
-) -> (Vec, Vec) {
- let mut tuples: Vec<_> = adresses.into_iter().zip(values).collect();
- tuples.sort_by(|(x, _), (y, _)| x.representative().cmp(&y.representative()));
- tuples.into_iter().unzip()
-}
-
-fn generate_memory_permutation_argument_column(
- addresses_original: Vec,
- values_original: Vec,
- addresses_sorted: &[Felt252],
- values_sorted: &[Felt252],
- rap_challenges: &[Felt252],
-) -> Vec {
- let z = &rap_challenges[1];
- let alpha = &rap_challenges[0];
-
- let mut denom: Vec<_> = addresses_sorted
- .iter()
- .zip(values_sorted)
- .map(|(ap, vp)| z - (ap + alpha * vp))
- .collect();
- FieldElement::inplace_batch_inverse(&mut denom).unwrap();
- // Returns the cumulative products of the numerators and denominators
- addresses_original
- .iter()
- .zip(&values_original)
- .zip(&denom)
- .scan(Felt252::one(), |product, ((a_i, v_i), den_i)| {
- let ret = *product;
- *product = ret * ((z - (a_i + alpha * v_i)) * den_i);
- Some(*product)
- })
- .collect::>()
-}
-
-fn generate_range_check_permutation_argument_column(
- offset_column_original: &[Felt252],
- offset_column_sorted: &[Felt252],
- rap_challenges: &[Felt252],
-) -> Vec {
- let z = rap_challenges[2];
-
- let mut denom: Vec<_> = offset_column_sorted.iter().map(|x| z - x).collect();
- FieldElement::inplace_batch_inverse(&mut denom).unwrap();
-
- offset_column_original
- .iter()
- .zip(&denom)
- .scan(Felt252::one(), |product, (num_i, den_i)| {
- let ret = *product;
- *product = ret * (z - num_i) * den_i;
- Some(*product)
- })
- .collect::>()
-}
-
impl AIR for CairoAIR {
type Field = Stark252PrimeField;
type FieldExtension = Stark252PrimeField;
type PublicInputs = PublicInputs;
- const STEP_SIZE: usize = 1;
+ const STEP_SIZE: usize = 16;
/// Creates a new CairoAIR from proof_options
///
@@ -553,26 +402,12 @@ impl AIR for CairoAIR {
proof_options: &ProofOptions,
) -> Self {
debug_assert!(trace_length.is_power_of_two());
- let trace_columns = 59;
+ let trace_columns = 8;
let transition_constraints: Vec<
Box>,
> = vec![
- Box::new(BitPrefixFlag0::new()),
- Box::new(BitPrefixFlag1::new()),
- Box::new(BitPrefixFlag2::new()),
- Box::new(BitPrefixFlag3::new()),
- Box::new(BitPrefixFlag4::new()),
- Box::new(BitPrefixFlag5::new()),
- Box::new(BitPrefixFlag6::new()),
- Box::new(BitPrefixFlag7::new()),
- Box::new(BitPrefixFlag8::new()),
- Box::new(BitPrefixFlag9::new()),
- Box::new(BitPrefixFlag10::new()),
- Box::new(BitPrefixFlag11::new()),
- Box::new(BitPrefixFlag12::new()),
- Box::new(BitPrefixFlag13::new()),
- Box::new(BitPrefixFlag14::new()),
+ Box::new(BitPrefixFlag::new()),
Box::new(ZeroFlagConstraint::new()),
Box::new(InstructionUnpacking::new()),
Box::new(CpuOperandsMemDstAddr::new()),
@@ -589,29 +424,11 @@ impl AIR for CairoAIR {
Box::new(CpuOpcodesCallPushFp::new()),
Box::new(CpuOpcodesCallPushPc::new()),
Box::new(CpuOpcodesAssertEq::new()),
- Box::new(MemoryDiffIsBit0::new()),
- Box::new(MemoryDiffIsBit1::new()),
- Box::new(MemoryDiffIsBit2::new()),
- Box::new(MemoryDiffIsBit3::new()),
- Box::new(MemoryDiffIsBit4::new()),
- Box::new(MemoryIsFunc0::new()),
- Box::new(MemoryIsFunc1::new()),
- Box::new(MemoryIsFunc2::new()),
- Box::new(MemoryIsFunc3::new()),
- Box::new(MemoryIsFunc4::new()),
- Box::new(MemoryMultiColumnPermStep0_0::new()),
- Box::new(MemoryMultiColumnPermStep0_1::new()),
- Box::new(MemoryMultiColumnPermStep0_2::new()),
- Box::new(MemoryMultiColumnPermStep0_3::new()),
- Box::new(MemoryMultiColumnPermStep0_4::new()),
- Box::new(Rc16DiffIsBit0::new()),
- Box::new(Rc16DiffIsBit1::new()),
- Box::new(Rc16DiffIsBit2::new()),
- Box::new(Rc16DiffIsBit3::new()),
- Box::new(Rc16PermStep0_0::new()),
- Box::new(Rc16PermStep0_1::new()),
- Box::new(Rc16PermStep0_2::new()),
- Box::new(Rc16PermStep0_3::new()),
+ Box::new(MemoryDiffIsBit::new()),
+ Box::new(MemoryIsFunc::new()),
+ Box::new(MemoryMultiColumnPermStep0::new()),
+ Box::new(Rc16DiffIsBit::new()),
+ Box::new(Rc16PermStep0::new()),
Box::new(FlagOp1BaseOp0BitConstraint::new()),
Box::new(FlagResOp1BitConstraint::new()),
Box::new(FlagPcUpdateRegularBit::new()),
@@ -639,30 +456,24 @@ impl AIR for CairoAIR {
(0..transition_constraints.len())
.for_each(|idx| debug_assert!(constraints_set.iter().contains(&idx)));
- assert_eq!(transition_constraints.len(), 64);
+ assert_eq!(transition_constraints.len(), 32);
}
-
- assert_eq!(transition_constraints.len(), 64);
-
- let transition_exemptions = transition_constraints
- .iter()
- .map(|c| c.end_exemptions())
- .collect();
-
+
let context = AirContext {
proof_options: proof_options.clone(),
trace_columns,
- transition_exemptions,
transition_offsets: vec![0, 1],
num_transition_constraints: transition_constraints.len(),
};
// The number of the transition constraints
// and transition exemptions should be the same always.
+ /*
debug_assert_eq!(
context.transition_exemptions.len(),
context.num_transition_constraints
);
+ */
Self {
context,
@@ -674,92 +485,15 @@ impl AIR for CairoAIR {
fn build_auxiliary_trace(
&self,
- main_trace: &TraceTable,
+ trace: &mut TraceTable,
rap_challenges: &[Felt252],
- ) -> TraceTable {
- let addresses_original = main_trace.merge_columns(&[
- FRAME_PC,
- FRAME_DST_ADDR,
- FRAME_OP0_ADDR,
- FRAME_OP1_ADDR,
- EXTRA_ADDR,
- ]);
-
- let values_original =
- main_trace.merge_columns(&[FRAME_INST, FRAME_DST, FRAME_OP0, FRAME_OP1, EXTRA_VAL]);
-
- let (addresses, values) = add_pub_memory_in_public_input_section(
- &addresses_original,
- &values_original,
- &self.pub_inputs,
- );
-
- let (addresses, values) = sort_columns_by_memory_address(addresses, values);
-
- let permutation_col = generate_memory_permutation_argument_column(
- addresses_original,
- values_original,
- &addresses,
- &values,
- rap_challenges,
- );
+ ) {
+ let alpha_mem = rap_challenges[0];
+ let z_mem = rap_challenges[1];
+ let z_rc = rap_challenges[2];
- // Range Check
- let offsets_original = main_trace.merge_columns(&[OFF_DST, OFF_OP0, OFF_OP1, RC_HOLES]);
-
- let mut offsets_sorted: Vec = offsets_original
- .iter()
- .map(|x| x.representative().into())
- .collect();
- offsets_sorted.sort();
- let offsets_sorted: Vec<_> = offsets_sorted
- .iter()
- .map(|x| FieldElement::from(*x as u64))
- .collect();
-
- let range_check_permutation_col = generate_range_check_permutation_argument_column(
- &offsets_original,
- &offsets_sorted,
- rap_challenges,
- );
-
- // Convert from long-format to wide-format again
- let mut aux_data = Vec::new();
- for i in 0..main_trace.n_rows() {
- aux_data.push(offsets_sorted[4 * i]);
- aux_data.push(offsets_sorted[4 * i + 1]);
- aux_data.push(offsets_sorted[4 * i + 2]);
- aux_data.push(offsets_sorted[4 * i + 3]);
- aux_data.push(addresses[5 * i]);
- aux_data.push(addresses[5 * i + 1]);
- aux_data.push(addresses[5 * i + 2]);
- aux_data.push(addresses[5 * i + 3]);
- aux_data.push(addresses[5 * i + 4]);
- aux_data.push(values[5 * i]);
- aux_data.push(values[5 * i + 1]);
- aux_data.push(values[5 * i + 2]);
- aux_data.push(values[5 * i + 3]);
- aux_data.push(values[5 * i + 4]);
- aux_data.push(permutation_col[5 * i]);
- aux_data.push(permutation_col[5 * i + 1]);
- aux_data.push(permutation_col[5 * i + 2]);
- aux_data.push(permutation_col[5 * i + 3]);
- aux_data.push(permutation_col[5 * i + 4]);
- aux_data.push(range_check_permutation_col[4 * i]);
- aux_data.push(range_check_permutation_col[4 * i + 1]);
- aux_data.push(range_check_permutation_col[4 * i + 2]);
- aux_data.push(range_check_permutation_col[4 * i + 3]);
- }
-
- let aux_table = Table::new(aux_data, self.num_auxiliary_rap_columns());
-
- let (num_main_columns, num_aux_columns) = self.trace_layout();
- TraceTable {
- table: aux_table,
- num_main_columns,
- num_aux_columns,
- step_size: Self::STEP_SIZE,
- }
+ set_rc_permutation_column(trace, &z_rc);
+ set_mem_permutation_column(trace, &alpha_mem, &z_mem);
}
fn build_rap_challenges(
@@ -774,7 +508,7 @@ impl AIR for CairoAIR {
}
fn trace_layout(&self) -> (usize, usize) {
- (36, 23)
+ (6, 2)
}
/// From the Cairo whitepaper, section 9.10.
@@ -786,57 +520,60 @@ impl AIR for CairoAIR {
/// * pc_0 = pc_i
/// * pc_t = pc_f
fn boundary_constraints(&self, rap_challenges: &[Felt252]) -> BoundaryConstraints {
- let initial_pc =
- BoundaryConstraint::new_main(MEM_A_TRACE_OFFSET, 0, self.pub_inputs.pc_init);
- let initial_ap =
- BoundaryConstraint::new_main(MEM_P_TRACE_OFFSET, 0, self.pub_inputs.ap_init);
+ let initial_pc = BoundaryConstraint::new_main(3, 0, self.pub_inputs.pc_init);
+ let initial_ap = BoundaryConstraint::new_main(5, 0, self.pub_inputs.ap_init);
let final_pc = BoundaryConstraint::new_main(
- MEM_A_TRACE_OFFSET,
- self.pub_inputs.num_steps - 1,
+ 3,
+ self.trace_length - Self::STEP_SIZE,
self.pub_inputs.pc_final,
);
let final_ap = BoundaryConstraint::new_main(
- MEM_P_TRACE_OFFSET,
- self.pub_inputs.num_steps - 1,
+ 5,
+ self.trace_length - Self::STEP_SIZE,
self.pub_inputs.ap_final,
);
- // Auxiliary constraint: permutation argument final value
- let final_index = self.trace_length - 1;
-
let z_memory = rap_challenges[1];
let alpha_memory = rap_challenges[0];
+ let one: FieldElement = FieldElement::one();
- let cumulative_product = self
+ let mem_cumul_prod_denominator_no_padding = self
.pub_inputs
.public_memory
.iter()
- .fold(FieldElement::one(), |product, (address, value)| {
+ .fold(one, |product, (address, value)| {
product * (z_memory - (address + alpha_memory * value))
- })
+ });
+
+ const PUB_MEMORY_ADDR_OFFSET: usize = 8;
+ let pad_addr = Felt252::one();
+ let pad_value = self.pub_inputs.public_memory.get(&pad_addr).unwrap();
+ let val = z_memory - (pad_addr + alpha_memory * pad_value);
+ let mem_cumul_prod_denominator_pad = val
+ .pow(self.trace_length / PUB_MEMORY_ADDR_OFFSET - self.pub_inputs.public_memory.len());
+ let mem_cumul_prod_denominator = (mem_cumul_prod_denominator_no_padding
+ * mem_cumul_prod_denominator_pad)
.inv()
.unwrap();
+ let mem_cumul_prod_final =
+ z_memory.pow(self.trace_length / PUB_MEMORY_ADDR_OFFSET) * mem_cumul_prod_denominator;
- let permutation_final =
- z_memory.pow(self.pub_inputs.public_memory.len()) * cumulative_product;
-
- let permutation_final_constraint =
- BoundaryConstraint::new_aux(PERMUTATION_ARGUMENT_COL_4, final_index, permutation_final);
+ let mem_cumul_prod_final_constraint =
+ BoundaryConstraint::new_aux(1, self.trace_length - 2, mem_cumul_prod_final);
- let one: FieldElement = FieldElement::one();
- let range_check_final_constraint =
- BoundaryConstraint::new_aux(PERMUTATION_ARGUMENT_RANGE_CHECK_COL_4, final_index, one);
+ let rc_cumul_prod_final_constraint =
+ BoundaryConstraint::new_aux(0, self.trace_length - 1, one);
- let range_check_min = BoundaryConstraint::new_aux(
- RANGE_CHECK_COL_1,
+ let rc_min_constraint = BoundaryConstraint::new_main(
+ 2,
0,
FieldElement::from(self.pub_inputs.range_check_min.unwrap() as u64),
);
- let range_check_max = BoundaryConstraint::new_aux(
- RANGE_CHECK_COL_4,
- final_index,
+ let rc_max_constraint = BoundaryConstraint::new_main(
+ 2,
+ self.trace_length - 1,
FieldElement::from(self.pub_inputs.range_check_max.unwrap() as u64),
);
@@ -845,10 +582,10 @@ impl AIR for CairoAIR {
initial_ap,
final_pc,
final_ap,
- permutation_final_constraint,
- range_check_final_constraint,
- range_check_min,
- range_check_max,
+ mem_cumul_prod_final_constraint,
+ rc_cumul_prod_final_constraint,
+ rc_min_constraint,
+ rc_max_constraint,
];
BoundaryConstraints::from_constraints(constraints)
@@ -890,7 +627,7 @@ impl AIR for CairoAIR {
/// concrete types.
/// The field is set to Stark252PrimeField and the AIR to CairoAIR.
pub fn generate_cairo_proof(
- trace: &TraceTable,
+ trace: &mut CairoTraceTable,
pub_input: &PublicInputs,
proof_options: &ProofOptions,
) -> Result, ProvingError> {
@@ -918,93 +655,6 @@ pub fn verify_cairo_proof(
)
}
-#[cfg(test)]
-#[cfg(debug_assertions)]
-mod test {
- use super::*;
- use lambdaworks_math::field::element::FieldElement;
-
- #[test]
- fn test_build_auxiliary_trace_sort_columns_by_memory_address() {
- let a = vec![
- FieldElement::from(2),
- FieldElement::one(),
- FieldElement::from(3),
- FieldElement::from(2),
- ];
- let v = vec![
- FieldElement::from(6),
- FieldElement::from(4),
- FieldElement::from(5),
- FieldElement::from(6),
- ];
- let (ap, vp) = sort_columns_by_memory_address(a, v);
- assert_eq!(
- ap,
- vec![
- FieldElement::one(),
- FieldElement::from(2),
- FieldElement::from(2),
- FieldElement::from(3)
- ]
- );
- assert_eq!(
- vp,
- vec![
- FieldElement::from(4),
- FieldElement::from(6),
- FieldElement::from(6),
- FieldElement::from(5),
- ]
- );
- }
-
- #[test]
- fn test_build_auxiliary_trace_generate_permutation_argument_column() {
- let a = vec![
- FieldElement::from(3),
- FieldElement::one(),
- FieldElement::from(2),
- ];
- let v = vec![
- FieldElement::from(5),
- FieldElement::one(),
- FieldElement::from(2),
- ];
- let ap = vec![
- FieldElement::one(),
- FieldElement::from(2),
- FieldElement::from(3),
- ];
- let vp = vec![
- FieldElement::one(),
- FieldElement::from(2),
- FieldElement::from(5),
- ];
- let rap_challenges = vec![
- FieldElement::from(15),
- FieldElement::from(10),
- FieldElement::zero(),
- ];
-
- let p = generate_memory_permutation_argument_column(a, v, &ap, &vp, &rap_challenges);
- assert_eq!(
- p,
- vec![
- FieldElement::from_hex(
- "2aaaaaaaaaaaab0555555555555555555555555555555555555555555555561"
- )
- .unwrap(),
- FieldElement::from_hex(
- "1745d1745d174602e8ba2e8ba2e8ba2e8ba2e8ba2e8ba2e8ba2e8ba2e8ba2ec"
- )
- .unwrap(),
- FieldElement::one(),
- ]
- );
- }
-}
-
#[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
#[cfg(test)]
mod prop_test {
@@ -1016,8 +666,8 @@ mod prop_test {
use stark_platinum_prover::proof::{options::ProofOptions, stark::StarkProof};
use crate::{
- air::{generate_cairo_proof, verify_cairo_proof},
cairo_layout::CairoLayout,
+ layouts::plain::air::{generate_cairo_proof, verify_cairo_proof},
runner::run::generate_prover_args,
tests::utils::cairo0_program_path,
Felt252,
@@ -1084,13 +734,13 @@ mod prop_test {
#[test]
fn deserialize_and_verify() {
let program_content = std::fs::read(cairo0_program_path("fibonacci_10.json")).unwrap();
- let (main_trace, pub_inputs) =
+ let (mut main_trace, pub_inputs) =
generate_prover_args(&program_content, CairoLayout::Plain).unwrap();
let proof_options = ProofOptions::default_test_options();
// The proof is generated and serialized.
- let proof = generate_cairo_proof(&main_trace, &pub_inputs, &proof_options).unwrap();
+ let proof = generate_cairo_proof(&mut main_trace, &pub_inputs, &proof_options).unwrap();
let proof_bytes: Vec = serde_cbor::to_vec(&proof).unwrap();
// The trace and original proof are dropped to show that they are decoupled from
diff --git a/provers/cairo/src/layouts/plain/mod.rs b/provers/cairo/src/layouts/plain/mod.rs
new file mode 100644
index 000000000..83aab11fa
--- /dev/null
+++ b/provers/cairo/src/layouts/plain/mod.rs
@@ -0,0 +1 @@
+pub mod air;
diff --git a/provers/cairo/src/lib.rs b/provers/cairo/src/lib.rs
index 54384a63c..2013cb087 100644
--- a/provers/cairo/src/lib.rs
+++ b/provers/cairo/src/lib.rs
@@ -2,12 +2,12 @@ use lambdaworks_math::field::{
element::FieldElement, fields::fft_friendly::stark_252_prime_field::Stark252PrimeField,
};
-pub mod air;
pub mod cairo_layout;
pub mod cairo_mem;
pub mod decode;
pub mod errors;
pub mod execution_trace;
+pub mod layouts;
pub mod register_states;
pub mod runner;
pub mod transition_constraints;
diff --git a/provers/cairo/src/main.rs b/provers/cairo/src/main.rs
index b64a51f26..72f1b827e 100644
--- a/provers/cairo/src/main.rs
+++ b/provers/cairo/src/main.rs
@@ -3,6 +3,15 @@ use cairo_platinum_prover::cairo_layout::CairoLayout;
use cairo_platinum_prover::runner::run::generate_prover_args;
use cairo_platinum_prover::runner::run::generate_prover_args_from_trace;
use lambdaworks_math::field::fields::fft_friendly::stark_252_prime_field::Stark252PrimeField;
+<<<<<<< HEAD
+use platinum_prover::cairo_layout::CairoLayout;
+use platinum_prover::layouts::plain::air::{
+ generate_cairo_proof, verify_cairo_proof, PublicInputs,
+};
+use platinum_prover::runner::run::generate_prover_args;
+use platinum_prover::runner::run::generate_prover_args_from_trace;
+=======
+>>>>>>> main
use stark_platinum_prover::proof::options::{ProofOptions, SecurityLevel};
use stark_platinum_prover::proof::stark::StarkProof;
mod commands;
@@ -122,7 +131,7 @@ fn generate_proof(
// FIXME: We should set this through the CLI in the future
let layout = CairoLayout::Plain;
- let Ok((main_trace, pub_inputs)) = generate_prover_args(&program_content, layout) else {
+ let Ok((mut main_trace, pub_inputs)) = generate_prover_args(&program_content, layout) else {
eprintln!("Error generating prover args");
return None;
};
@@ -131,7 +140,7 @@ fn generate_proof(
let timer = Instant::now();
println!("Making proof ...");
- let proof = match generate_cairo_proof(&main_trace, &pub_inputs, proof_options) {
+ let proof = match generate_cairo_proof(&mut main_trace, &pub_inputs, proof_options) {
Ok(p) => p,
Err(err) => {
eprintln!("Error generating proof: {:?}", err);
@@ -154,7 +163,7 @@ fn generate_proof_from_trace(
)> {
// ## Generating the prover args
let timer = Instant::now();
- let Ok((main_trace, pub_inputs)) =
+ let Ok((mut main_trace, pub_inputs)) =
generate_prover_args_from_trace(trace_bin_path, memory_bin_path)
else {
eprintln!("Error generating prover args");
@@ -165,7 +174,7 @@ fn generate_proof_from_trace(
// ## Prove
let timer = Instant::now();
println!("Making proof ...");
- let proof = match generate_cairo_proof(&main_trace, &pub_inputs, proof_options) {
+ let proof = match generate_cairo_proof(&mut main_trace, &pub_inputs, proof_options) {
Ok(p) => p,
Err(err) => {
eprintln!("Error generating proof: {:?}", err);
diff --git a/provers/cairo/src/runner/run.rs b/provers/cairo/src/runner/run.rs
index 45b22b3c0..a3fd427ff 100644
--- a/provers/cairo/src/runner/run.rs
+++ b/provers/cairo/src/runner/run.rs
@@ -1,22 +1,16 @@
-use crate::air::{PublicInputs, Segment, SegmentName};
+use super::vec_writer::VecWriter;
use crate::cairo_layout::CairoLayout;
use crate::cairo_mem::CairoMemory;
-use crate::execution_trace::build_main_trace;
+use crate::execution_trace::{build_cairo_execution_trace, CairoTraceTable};
+use crate::layouts::plain::air::{PublicInputs, Segment, SegmentName};
use crate::register_states::RegisterStates;
use crate::Felt252;
-
-use super::vec_writer::VecWriter;
use cairo_vm::cairo_run::{self, EncodeTraceError};
-
use cairo_vm::hint_processor::builtin_hint_processor::builtin_hint_processor_definition::BuiltinHintProcessor;
-
use cairo_vm::vm::errors::{
cairo_run_errors::CairoRunError, trace_errors::TraceError, vm_errors::VirtualMachineError,
};
-
use cairo_vm::without_std::collections::HashMap;
-use lambdaworks_math::field::fields::fft_friendly::stark_252_prime_field::Stark252PrimeField;
-use stark_platinum_prover::trace::TraceTable;
#[derive(Debug)]
pub enum Error {
@@ -159,18 +153,18 @@ pub fn run_program(
pub fn generate_prover_args(
program_content: &[u8],
layout: CairoLayout,
-) -> Result<(TraceTable, PublicInputs), Error> {
- let (register_states, memory, mut public_inputs) = run_program(None, layout, program_content)?;
+) -> Result<(CairoTraceTable, PublicInputs), Error> {
+ let (register_states, memory, mut pub_inputs) = run_program(None, layout, program_content)?;
- let main_trace = build_main_trace(®ister_states, &memory, &mut public_inputs);
+ let main_trace = build_cairo_execution_trace(®ister_states, &memory, &mut pub_inputs);
- Ok((main_trace, public_inputs))
+ Ok((main_trace, pub_inputs))
}
pub fn generate_prover_args_from_trace(
trace_bin_path: &str,
memory_bin_path: &str,
-) -> Result<(TraceTable, PublicInputs), Error> {
+) -> Result<(CairoTraceTable, PublicInputs), Error> {
// ## Generating the prover args
let register_states =
RegisterStates::from_file(trace_bin_path).expect("Cairo trace bin file not found");
@@ -181,7 +175,7 @@ pub fn generate_prover_args_from_trace(
let data_len = 0_usize;
let mut pub_inputs = PublicInputs::from_regs_and_mem(®ister_states, &memory, data_len);
- let main_trace = build_main_trace(®ister_states, &memory, &mut pub_inputs);
+ let main_trace = build_cairo_execution_trace(®ister_states, &memory, &mut pub_inputs);
Ok((main_trace, pub_inputs))
}
diff --git a/provers/cairo/src/tests/integration_tests.rs b/provers/cairo/src/tests/integration_tests.rs
index 79f051830..4b0fea0ed 100644
--- a/provers/cairo/src/tests/integration_tests.rs
+++ b/provers/cairo/src/tests/integration_tests.rs
@@ -1,10 +1,8 @@
use crate::{
- air::{generate_cairo_proof, verify_cairo_proof, CairoAIR},
cairo_layout::CairoLayout,
+ layouts::plain::air::{generate_cairo_proof, verify_cairo_proof, CairoAIR},
runner::run::generate_prover_args,
- tests::utils::{
- cairo0_program_path, test_prove_cairo_program, test_prove_cairo_program_from_trace,
- },
+ tests::utils::{cairo0_program_path, test_prove_cairo_program},
Felt252,
};
use lambdaworks_math::field::fields::fft_friendly::stark_252_prime_field::Stark252PrimeField;
@@ -31,24 +29,24 @@ fn test_prove_cairo_fibonacci_5() {
test_prove_cairo_program(&cairo0_program_path("fibonacci_5.json"), layout);
}
-#[test_log::test]
-fn test_prove_cairo_fibonacci_5_from_trace() {
- test_prove_cairo_program_from_trace(
- &cairo0_program_path("fibonacci_5_trace.bin"),
- &cairo0_program_path("fibonacci_5_memory.bin"),
- );
-}
+// #[test_log::test]
+// fn test_prove_cairo_fibonacci_5_from_trace() {
+// test_prove_cairo_program_from_trace(
+// &cairo0_program_path("fibonacci_5_trace.bin"),
+// &cairo0_program_path("fibonacci_5_memory.bin"),
+// );
+// }
#[test_log::test]
fn test_verifier_rejects_wrong_authentication_paths() {
// Setup
let proof_options = ProofOptions::default_test_options();
let program_content = std::fs::read(cairo0_program_path("fibonacci_5.json")).unwrap();
- let (main_trace, pub_inputs) =
+ let (mut main_trace, pub_inputs) =
generate_prover_args(&program_content, CairoLayout::Plain).unwrap();
// Generate the proof
- let mut proof = generate_cairo_proof(&main_trace, &pub_inputs, &proof_options).unwrap();
+ let mut proof = generate_cairo_proof(&mut main_trace, &pub_inputs, &proof_options).unwrap();
// Change order of authentication path hashes
let query = 0;
@@ -70,6 +68,7 @@ fn test_verifier_rejects_wrong_authentication_paths() {
assert!(!verify_cairo_proof(&proof, &pub_inputs, &proof_options));
}
+#[ignore = "too much time"]
#[test_log::test]
fn test_prove_cairo_fibonacci_1000() {
let layout = CairoLayout::Plain;
@@ -86,16 +85,16 @@ fn test_prove_cairo_fibonacci_1000() {
#[test_log::test]
fn test_verifier_rejects_proof_of_a_slightly_different_program() {
let program_content = std::fs::read(cairo0_program_path("simple_program.json")).unwrap();
- let (main_trace, mut pub_input) =
+ let (mut main_trace, mut pub_input) =
generate_prover_args(&program_content, CairoLayout::Plain).unwrap();
let proof_options = ProofOptions::default_test_options();
- let proof = generate_cairo_proof(&main_trace, &pub_input, &proof_options).unwrap();
+ let proof = generate_cairo_proof(&mut main_trace, &pub_input, &proof_options).unwrap();
// We modify the original program and verify using this new "corrupted" version
let mut corrupted_program = pub_input.public_memory.clone();
- corrupted_program.insert(Felt252::one(), Felt252::from(5));
+ corrupted_program.insert(Felt252::one(), Felt252::from(6));
corrupted_program.insert(Felt252::from(3), Felt252::from(5));
// Here we use the corrupted version of the program in the public inputs
@@ -106,11 +105,11 @@ fn test_verifier_rejects_proof_of_a_slightly_different_program() {
#[test_log::test]
fn test_verifier_rejects_proof_with_different_range_bounds() {
let program_content = std::fs::read(cairo0_program_path("simple_program.json")).unwrap();
- let (main_trace, mut pub_inputs) =
+ let (mut main_trace, mut pub_inputs) =
generate_prover_args(&program_content, CairoLayout::Plain).unwrap();
let proof_options = ProofOptions::default_test_options();
- let proof = generate_cairo_proof(&main_trace, &pub_inputs, &proof_options).unwrap();
+ let proof = generate_cairo_proof(&mut main_trace, &pub_inputs, &proof_options).unwrap();
pub_inputs.range_check_min = Some(pub_inputs.range_check_min.unwrap() + 1);
assert!(!verify_cairo_proof(&proof, &pub_inputs, &proof_options));
@@ -123,12 +122,12 @@ fn test_verifier_rejects_proof_with_different_range_bounds() {
#[test_log::test]
fn test_verifier_rejects_proof_with_different_security_params() {
let program_content = std::fs::read(cairo0_program_path("fibonacci_5.json")).unwrap();
- let (main_trace, pub_inputs) =
+ let (mut main_trace, pub_inputs) =
generate_prover_args(&program_content, CairoLayout::Plain).unwrap();
let proof_options_prover = ProofOptions::new_secure(SecurityLevel::Conjecturable80Bits, 3);
- let proof = generate_cairo_proof(&main_trace, &pub_inputs, &proof_options_prover).unwrap();
+ let proof = generate_cairo_proof(&mut main_trace, &pub_inputs, &proof_options_prover).unwrap();
let proof_options_verifier = ProofOptions::new_secure(SecurityLevel::Conjecturable128Bits, 3);
@@ -139,29 +138,28 @@ fn test_verifier_rejects_proof_with_different_security_params() {
));
}
-#[test]
+#[test_log::test]
fn check_simple_cairo_trace_evaluates_to_zero() {
let program_content = std::fs::read(cairo0_program_path("simple_program.json")).unwrap();
- let (main_trace, public_input) =
+ let (mut trace, public_input) =
generate_prover_args(&program_content, CairoLayout::Plain).unwrap();
- let mut trace_polys = main_trace.compute_trace_polys::();
+ let main_trace_polys = trace.compute_trace_polys_main::();
let mut transcript = StoneProverTranscript::new(&[]);
let proof_options = ProofOptions::default_test_options();
- let cairo_air = CairoAIR::new(main_trace.n_rows(), &public_input, &proof_options);
+ let cairo_air = CairoAIR::new(trace.num_rows(), &public_input, &proof_options);
let rap_challenges = cairo_air.build_rap_challenges(&mut transcript);
- let aux_trace = cairo_air.build_auxiliary_trace(&main_trace, &rap_challenges);
- let aux_polys = aux_trace.compute_trace_polys::();
+ cairo_air.build_auxiliary_trace(&mut trace, &rap_challenges);
- trace_polys.extend_from_slice(&aux_polys);
+ let aux_trace_polys = trace.compute_trace_polys_aux::();
let domain = Domain::new(&cairo_air);
assert!(validate_trace(
&cairo_air,
- &trace_polys,
- &aux_polys,
+ &main_trace_polys,
+ &aux_trace_polys,
&domain,
&rap_challenges
));
@@ -170,13 +168,13 @@ fn check_simple_cairo_trace_evaluates_to_zero() {
#[test]
fn deserialize_and_verify() {
let program_content = std::fs::read(cairo0_program_path("fibonacci_10.json")).unwrap();
- let (main_trace, pub_inputs) =
+ let (mut main_trace, pub_inputs) =
generate_prover_args(&program_content, CairoLayout::Plain).unwrap();
let proof_options = ProofOptions::default_test_options();
// The proof is generated and serialized.
- let proof = generate_cairo_proof(&main_trace, &pub_inputs, &proof_options).unwrap();
+ let proof = generate_cairo_proof(&mut main_trace, &pub_inputs, &proof_options).unwrap();
let proof_bytes: Vec = serde_cbor::to_vec(&proof).unwrap();
// The trace and original proof are dropped to show that they are decoupled from
diff --git a/provers/cairo/src/tests/utils.rs b/provers/cairo/src/tests/utils.rs
index 671d74f94..e4cfdf1b5 100644
--- a/provers/cairo/src/tests/utils.rs
+++ b/provers/cairo/src/tests/utils.rs
@@ -1,6 +1,6 @@
use crate::{
- air::{generate_cairo_proof, verify_cairo_proof},
cairo_layout::CairoLayout,
+ layouts::plain::air::{generate_cairo_proof, verify_cairo_proof},
runner::run::generate_prover_args,
runner::run::generate_prover_args_from_trace,
};
@@ -28,8 +28,8 @@ pub fn test_prove_cairo_program(file_path: &str, layout: CairoLayout) {
println!("Making proof ...");
let program_content = std::fs::read(file_path).unwrap();
- let (main_trace, pub_inputs) = generate_prover_args(&program_content, layout).unwrap();
- let proof = generate_cairo_proof(&main_trace, &pub_inputs, &proof_options).unwrap();
+ let (mut main_trace, pub_inputs) = generate_prover_args(&program_content, layout).unwrap();
+ let proof = generate_cairo_proof(&mut main_trace, &pub_inputs, &proof_options).unwrap();
println!(" Time spent in proving: {:?} \n", timer.elapsed());
assert!(verify_cairo_proof(&proof, &pub_inputs, &proof_options));
@@ -37,13 +37,13 @@ pub fn test_prove_cairo_program(file_path: &str, layout: CairoLayout) {
pub fn test_prove_cairo_program_from_trace(trace_bin_path: &str, memory_bin_path: &str) {
let proof_options = ProofOptions::default_test_options();
- let (main_trace, pub_inputs) =
+ let (mut main_trace, pub_inputs) =
generate_prover_args_from_trace(trace_bin_path, memory_bin_path).unwrap();
// println
let timer = Instant::now();
println!("Making proof ...");
- let proof = generate_cairo_proof(&main_trace, &pub_inputs, &proof_options).unwrap();
+ let proof = generate_cairo_proof(&mut main_trace, &pub_inputs, &proof_options).unwrap();
println!(" Time spent in proving: {:?} \n", timer.elapsed());
assert!(verify_cairo_proof(&proof, &pub_inputs, &proof_options));
}
diff --git a/provers/cairo/src/transition_constraints.rs b/provers/cairo/src/transition_constraints.rs
index c5a761622..3de99aa4c 100644
--- a/provers/cairo/src/transition_constraints.rs
+++ b/provers/cairo/src/transition_constraints.rs
@@ -5,19 +5,19 @@ use stark_platinum_prover::{
};
#[derive(Clone)]
-pub struct BitPrefixFlag0;
-impl BitPrefixFlag0 {
+pub struct BitPrefixFlag;
+impl BitPrefixFlag {
pub fn new() -> Self {
Self
}
}
-impl Default for BitPrefixFlag0 {
+impl Default for BitPrefixFlag {
fn default() -> Self {
Self::new()
}
}
-impl TransitionConstraint for BitPrefixFlag0 {
+impl TransitionConstraint for BitPrefixFlag {
fn degree(&self) -> usize {
2
}
@@ -37,8 +37,8 @@ impl TransitionConstraint for BitPrefixF
let constraint_idx = self.constraint_idx();
- let current_flag = current_step.get_main_evaluation_element(0, constraint_idx);
- let next_flag = current_step.get_main_evaluation_element(0, constraint_idx + 1);
+ let current_flag = current_step.get_main_evaluation_element(0, 1);
+ let next_flag = current_step.get_main_evaluation_element(1, 1);
let one = Felt252::one();
let two = Felt252::from(2);
@@ -50,1506 +50,12 @@ impl TransitionConstraint for BitPrefixF
transition_evaluations[constraint_idx] = res;
}
- fn end_exemptions(&self) -> usize {
- 0
- }
-}
-
-#[derive(Clone)]
-pub struct BitPrefixFlag1;
-impl BitPrefixFlag1 {
- pub fn new() -> Self {
- Self
- }
-}
-impl Default for BitPrefixFlag1 {
- fn default() -> Self {
- Self::new()
- }
-}
-
-impl TransitionConstraint for BitPrefixFlag1 {
- fn degree(&self) -> usize {
- 2
- }
-
- fn constraint_idx(&self) -> usize {
- 1
- }
-
- fn evaluate(
- &self,
- frame: &stark_platinum_prover::frame::Frame,
- transition_evaluations: &mut [Felt252],
- _periodic_values: &[Felt252],
- _rap_challenges: &[Felt252],
- ) {
- let current_step = frame.get_evaluation_step(0);
-
- let constraint_idx = self.constraint_idx();
-
- let current_flag = current_step.get_main_evaluation_element(0, constraint_idx);
- let next_flag = current_step.get_main_evaluation_element(0, constraint_idx + 1);
-
- let one = Felt252::one();
- let two = Felt252::from(2);
-
- let bit = current_flag - two * next_flag;
-
- let res = bit * (bit - one);
-
- transition_evaluations[constraint_idx] = res;
- }
-
- fn end_exemptions(&self) -> usize {
- 0
- }
-}
-
-#[derive(Clone)]
-pub struct BitPrefixFlag2;
-impl BitPrefixFlag2 {
- pub fn new() -> Self {
- Self
- }
-}
-impl Default for BitPrefixFlag2 {
- fn default() -> Self {
- Self::new()
- }
-}
-
-impl TransitionConstraint for BitPrefixFlag2 {
- fn degree(&self) -> usize {
- 2
- }
-
- fn constraint_idx(&self) -> usize {
- 2
- }
-
- fn evaluate(
- &self,
- frame: &stark_platinum_prover::frame::Frame,
- transition_evaluations: &mut [Felt252],
- _periodic_values: &[Felt252],
- _rap_challenges: &[Felt252],
- ) {
- let current_step = frame.get_evaluation_step(0);
-
- let constraint_idx = self.constraint_idx();
-
- let current_flag = current_step.get_main_evaluation_element(0, constraint_idx);
- let next_flag = current_step.get_main_evaluation_element(0, constraint_idx + 1);
-
- let one = Felt252::one();
- let two = Felt252::from(2);
-
- let bit = current_flag - two * next_flag;
-
- let res = bit * (bit - one);
-
- transition_evaluations[constraint_idx] = res;
- }
-
- fn end_exemptions(&self) -> usize {
- 0
- }
-}
-
-#[derive(Clone)]
-pub struct BitPrefixFlag3;
-impl BitPrefixFlag3 {
- pub fn new() -> Self {
- Self
- }
-}
-impl Default for BitPrefixFlag3 {
- fn default() -> Self {
- Self::new()
- }
-}
-
-impl TransitionConstraint for BitPrefixFlag3 {
- fn degree(&self) -> usize {
- 2
- }
-
- fn constraint_idx(&self) -> usize {
- 3
- }
-
- fn evaluate(
- &self,
- frame: &stark_platinum_prover::frame::Frame,
- transition_evaluations: &mut [Felt252],
- _periodic_values: &[Felt252],
- _rap_challenges: &[Felt252],
- ) {
- let current_step = frame.get_evaluation_step(0);
-
- let constraint_idx = self.constraint_idx();
-
- let current_flag = current_step.get_main_evaluation_element(0, constraint_idx);
- let next_flag = current_step.get_main_evaluation_element(0, constraint_idx + 1);
-
- let one = Felt252::one();
- let two = Felt252::from(2);
-
- let bit = current_flag - two * next_flag;
-
- let res = bit * (bit - one);
-
- transition_evaluations[constraint_idx] = res;
- }
-
- fn end_exemptions(&self) -> usize {
- 0
- }
-}
-
-#[derive(Clone)]
-pub struct BitPrefixFlag4;
-impl BitPrefixFlag4 {
- pub fn new() -> Self {
- Self
- }
-}
-impl Default for BitPrefixFlag4 {
- fn default() -> Self {
- Self::new()
- }
-}
-
-impl TransitionConstraint for BitPrefixFlag4 {
- fn degree(&self) -> usize {
- 2
- }
-
- fn constraint_idx(&self) -> usize {
- 4
- }
-
- fn evaluate(
- &self,
- frame: &stark_platinum_prover::frame::Frame,
- transition_evaluations: &mut [Felt252],
- _periodic_values: &[Felt252],
- _rap_challenges: &[Felt252],
- ) {
- let current_step = frame.get_evaluation_step(0);
-
- let constraint_idx = self.constraint_idx();
-
- let current_flag = current_step.get_main_evaluation_element(0, constraint_idx);
- let next_flag = current_step.get_main_evaluation_element(0, constraint_idx + 1);
-
- let one = Felt252::one();
- let two = Felt252::from(2);
-
- let bit = current_flag - two * next_flag;
-
- let res = bit * (bit - one);
-
- transition_evaluations[constraint_idx] = res;
- }
-
- fn end_exemptions(&self) -> usize {
- 0
- }
-}
-
-#[derive(Clone)]
-pub struct BitPrefixFlag5;
-impl BitPrefixFlag5 {
- pub fn new() -> Self {
- Self
- }
-}
-impl Default for BitPrefixFlag5 {
- fn default() -> Self {
- Self::new()
- }
-}
-
-impl TransitionConstraint for BitPrefixFlag5 {
- fn degree(&self) -> usize {
- 2
- }
-
- fn constraint_idx(&self) -> usize {
- 5
- }
-
- fn evaluate(
- &self,
- frame: &stark_platinum_prover::frame::Frame,
- transition_evaluations: &mut [Felt252],
- _periodic_values: &[Felt252],
- _rap_challenges: &[Felt252],
- ) {
- let current_step = frame.get_evaluation_step(0);
-
- let constraint_idx = self.constraint_idx();
-
- let current_flag = current_step.get_main_evaluation_element(0, constraint_idx);
- let next_flag = current_step.get_main_evaluation_element(0, constraint_idx + 1);
-
- let one = Felt252::one();
- let two = Felt252::from(2);
-
- let bit = current_flag - two * next_flag;
-
- let res = bit * (bit - one);
-
- transition_evaluations[constraint_idx] = res;
- }
-
- fn end_exemptions(&self) -> usize {
- 0
- }
-}
-
-#[derive(Clone)]
-pub struct BitPrefixFlag6;
-impl BitPrefixFlag6 {
- pub fn new() -> Self {
- Self
- }
-}
-impl Default for BitPrefixFlag6 {
- fn default() -> Self {
- Self::new()
- }
-}
-
-impl TransitionConstraint for BitPrefixFlag6 {
- fn degree(&self) -> usize {
- 2
- }
-
- fn constraint_idx(&self) -> usize {
- 6
- }
-
- fn evaluate(
- &self,
- frame: &stark_platinum_prover::frame::Frame,
- transition_evaluations: &mut [Felt252],
- _periodic_values: &[Felt252],
- _rap_challenges: &[Felt252],
- ) {
- let current_step = frame.get_evaluation_step(0);
-
- let constraint_idx = self.constraint_idx();
-
- let current_flag = current_step.get_main_evaluation_element(0, constraint_idx);
- let next_flag = current_step.get_main_evaluation_element(0, constraint_idx + 1);
-
- let one = Felt252::one();
- let two = Felt252::from(2);
-
- let bit = current_flag - two * next_flag;
-
- let res = bit * (bit - one);
-
- transition_evaluations[constraint_idx] = res;
- }
-
- fn end_exemptions(&self) -> usize {
- 0
- }
-}
-
-#[derive(Clone)]
-pub struct BitPrefixFlag7;
-impl Default for BitPrefixFlag7 {
- fn default() -> Self {
- Self::new()
- }
-}
-
-impl BitPrefixFlag7 {
- pub fn new() -> Self {
- Self
- }
-}
-
-impl TransitionConstraint for BitPrefixFlag7 {
- fn degree(&self) -> usize {
- 2
- }
-
- fn constraint_idx(&self) -> usize {
- 7
- }
-
- fn evaluate(
- &self,
- frame: &stark_platinum_prover::frame::Frame,
- transition_evaluations: &mut [Felt252],
- _periodic_values: &[Felt252],
- _rap_challenges: &[Felt252],
- ) {
- let current_step = frame.get_evaluation_step(0);
-
- let constraint_idx = self.constraint_idx();
-
- let current_flag = current_step.get_main_evaluation_element(0, constraint_idx);
- let next_flag = current_step.get_main_evaluation_element(0, constraint_idx + 1);
-
- let one = Felt252::one();
- let two = Felt252::from(2);
-
- let bit = current_flag - two * next_flag;
-
- let res = bit * (bit - one);
-
- transition_evaluations[constraint_idx] = res;
- }
-
- fn end_exemptions(&self) -> usize {
- 0
- }
-}
-
-#[derive(Clone)]
-pub struct BitPrefixFlag8;
-impl Default for BitPrefixFlag8 {
- fn default() -> Self {
- Self::new()
- }
-}
-
-impl BitPrefixFlag8 {
- pub fn new() -> Self {
- Self
- }
-}
-
-impl TransitionConstraint for BitPrefixFlag8 {
- fn degree(&self) -> usize {
- 2
- }
-
- fn constraint_idx(&self) -> usize {
- 8
- }
-
- fn evaluate(
- &self,
- frame: &stark_platinum_prover::frame::Frame,
- transition_evaluations: &mut [Felt252],
- _periodic_values: &[Felt252],
- _rap_challenges: &[Felt252],
- ) {
- let current_step = frame.get_evaluation_step(0);
-
- let constraint_idx = self.constraint_idx();
-
- let current_flag = current_step.get_main_evaluation_element(0, constraint_idx);
- let next_flag = current_step.get_main_evaluation_element(0, constraint_idx + 1);
-
- let one = Felt252::one();
- let two = Felt252::from(2);
-
- let bit = current_flag - two * next_flag;
-
- let res = bit * (bit - one);
-
- transition_evaluations[constraint_idx] = res;
- }
-
- fn end_exemptions(&self) -> usize {
- 0
- }
-}
-
-#[derive(Clone)]
-pub struct BitPrefixFlag9;
-impl Default for BitPrefixFlag9 {
- fn default() -> Self {
- Self::new()
- }
-}
-
-impl BitPrefixFlag9 {
- pub fn new() -> Self {
- Self
- }
-}
-
-impl TransitionConstraint for BitPrefixFlag9 {
- fn degree(&self) -> usize {
- 2
- }
-
- fn constraint_idx(&self) -> usize {
- 9
- }
-
- fn evaluate(
- &self,
- frame: &stark_platinum_prover::frame::Frame,
- transition_evaluations: &mut [Felt252],
- _periodic_values: &[Felt252],
- _rap_challenges: &[Felt252],
- ) {
- let current_step = frame.get_evaluation_step(0);
-
- let constraint_idx = self.constraint_idx();
-
- let current_flag = current_step.get_main_evaluation_element(0, constraint_idx);
- let next_flag = current_step.get_main_evaluation_element(0, constraint_idx + 1);
-
- let one = Felt252::one();
- let two = Felt252::from(2);
-
- let bit = current_flag - two * next_flag;
-
- let res = bit * (bit - one);
-
- transition_evaluations[constraint_idx] = res;
- }
-
- fn end_exemptions(&self) -> usize {
- 0
- }
-}
-
-#[derive(Clone)]
-pub struct BitPrefixFlag10;
-impl Default for BitPrefixFlag10 {
- fn default() -> Self {
- Self::new()
- }
-}
-
-impl BitPrefixFlag10 {
- pub fn new() -> Self {
- Self
- }
-}
-
-impl TransitionConstraint for BitPrefixFlag10 {
- fn degree(&self) -> usize {
- 2
- }
-
- fn constraint_idx(&self) -> usize {
- 10
- }
-
- fn evaluate(
- &self,
- frame: &stark_platinum_prover::frame::Frame,
- transition_evaluations: &mut [Felt252],
- _periodic_values: &[Felt252],
- _rap_challenges: &[Felt252],
- ) {
- let current_step = frame.get_evaluation_step(0);
-
- let constraint_idx = self.constraint_idx();
-
- let current_flag = current_step.get_main_evaluation_element(0, constraint_idx);
- let next_flag = current_step.get_main_evaluation_element(0, constraint_idx + 1);
-
- let one = Felt252::one();
- let two = Felt252::from(2);
-
- let bit = current_flag - two * next_flag;
-
- let res = bit * (bit - one);
-
- transition_evaluations[constraint_idx] = res;
- }
-
- fn end_exemptions(&self) -> usize {
- 0
- }
-}
-
-pub struct BitPrefixFlag11;
-impl Default for BitPrefixFlag11 {
- fn default() -> Self {
- Self::new()
- }
-}
-
-impl BitPrefixFlag11 {
- pub fn new() -> Self {
- Self
- }
-}
-
-impl TransitionConstraint for BitPrefixFlag11 {
- fn degree(&self) -> usize {
- 2
- }
-
- fn constraint_idx(&self) -> usize {
- 11
- }
-
- fn evaluate(
- &self,
- frame: &stark_platinum_prover::frame::Frame,
- transition_evaluations: &mut [Felt252],
- _periodic_values: &[Felt252],
- _rap_challenges: &[Felt252],
- ) {
- let current_step = frame.get_evaluation_step(0);
-
- let constraint_idx = self.constraint_idx();
-
- let current_flag = current_step.get_main_evaluation_element(0, constraint_idx);
- let next_flag = current_step.get_main_evaluation_element(0, constraint_idx + 1);
-
- let one = Felt252::one();
- let two = Felt252::from(2);
-
- let bit = current_flag - two * next_flag;
-
- let res = bit * (bit - one);
-
- transition_evaluations[constraint_idx] = res;
- }
-
- fn end_exemptions(&self) -> usize {
- 0
- }
-}
-
-pub struct BitPrefixFlag12;
-impl Default for BitPrefixFlag12 {
- fn default() -> Self {
- Self::new()
- }
-}
-
-impl BitPrefixFlag12 {
- pub fn new() -> Self {
- Self
- }
-}
-
-impl TransitionConstraint for BitPrefixFlag12 {
- fn degree(&self) -> usize {
- 2
- }
-
- fn constraint_idx(&self) -> usize {
- 12
- }
-
- fn evaluate(
- &self,
- frame: &stark_platinum_prover::frame::Frame,
- transition_evaluations: &mut [Felt252],
- _periodic_values: &[Felt252],
- _rap_challenges: &[Felt252],
- ) {
- let current_step = frame.get_evaluation_step(0);
-
- let constraint_idx = self.constraint_idx();
-
- let current_flag = current_step.get_main_evaluation_element(0, constraint_idx);
- let next_flag = current_step.get_main_evaluation_element(0, constraint_idx + 1);
-
- let one = Felt252::one();
- let two = Felt252::from(2);
-
- let bit = current_flag - two * next_flag;
-
- let res = bit * (bit - one);
-
- transition_evaluations[constraint_idx] = res;
- }
-
- fn end_exemptions(&self) -> usize {
- 0
- }
-}
-
-pub struct BitPrefixFlag13;
-impl Default for BitPrefixFlag13 {
- fn default() -> Self {
- Self::new()
- }
-}
-
-impl BitPrefixFlag13 {
- pub fn new() -> Self {
- Self
- }
-}
-
-impl TransitionConstraint for BitPrefixFlag13 {
- fn degree(&self) -> usize {
- 2
- }
-
- fn constraint_idx(&self) -> usize {
- 13
- }
-
- fn evaluate(
- &self,
- frame: &Frame,
- transition_evaluations: &mut [Felt252],
- _periodic_values: &[Felt252],
- _rap_challenges: &[Felt252],
- ) {
- let current_step = frame.get_evaluation_step(0);
-
- let constraint_idx = self.constraint_idx();
-
- let current_flag = current_step.get_main_evaluation_element(0, constraint_idx);
- let next_flag = current_step.get_main_evaluation_element(0, constraint_idx + 1);
-
- let one = Felt252::one();
- let two = Felt252::from(2);
-
- let bit = current_flag - two * next_flag;
-
- let res = bit * (bit - one);
-
- transition_evaluations[constraint_idx] = res;
- }
-
- fn end_exemptions(&self) -> usize {
- 0
- }
-}
-
-pub struct BitPrefixFlag14;
-impl Default for BitPrefixFlag14 {
- fn default() -> Self {
- Self::new()
- }
-}
-
-impl BitPrefixFlag14 {
- pub fn new() -> Self {
- Self
- }
-}
-
-impl TransitionConstraint for BitPrefixFlag14 {
- fn degree(&self) -> usize {
- 2
- }
-
- fn constraint_idx(&self) -> usize {
- 14
- }
-
- fn evaluate(
- &self,
- frame: &stark_platinum_prover::frame::Frame,
- transition_evaluations: &mut [Felt252],
- _periodic_values: &[Felt252],
- _rap_challenges: &[Felt252],
- ) {
- let current_step = frame.get_evaluation_step(0);
-
- let constraint_idx = self.constraint_idx();
-
- let current_flag = current_step.get_main_evaluation_element(0, constraint_idx);
- let next_flag = current_step.get_main_evaluation_element(0, constraint_idx + 1);
-
- let one = Felt252::one();
- let two = Felt252::from(2);
-
- let bit = current_flag - two * next_flag;
-
- let res = bit * (bit - one);
-
- transition_evaluations[constraint_idx] = res;
- }
-
- fn end_exemptions(&self) -> usize {
- 0
- }
-}
-
-pub struct ZeroFlagConstraint;
-impl Default for ZeroFlagConstraint {
- fn default() -> Self {
- Self::new()
- }
-}
-
-impl ZeroFlagConstraint {
- pub fn new() -> Self {
- Self
- }
-}
-
-impl TransitionConstraint for ZeroFlagConstraint {
- fn degree(&self) -> usize {
- 1
- }
-
- fn constraint_idx(&self) -> usize {
- 15
- }
-
- fn evaluate(
- &self,
- frame: &stark_platinum_prover::frame::Frame,
- transition_evaluations: &mut [Felt252],
- _periodic_values: &[Felt252],
- _rap_challenges: &[Felt252],
- ) {
- let current_step = frame.get_evaluation_step(0);
-
- let zero_flag = current_step.get_main_evaluation_element(0, 15);
-
- transition_evaluations[self.constraint_idx()] = *zero_flag;
- }
-
- fn end_exemptions(&self) -> usize {
- 0
- }
-}
-
-pub struct FlagOp1BaseOp0BitConstraint;
-impl Default for FlagOp1BaseOp0BitConstraint {
- fn default() -> Self {
- Self::new()
- }
-}
-
-impl FlagOp1BaseOp0BitConstraint {
- pub fn new() -> Self {
- Self
- }
-}
-
-impl TransitionConstraint for FlagOp1BaseOp0BitConstraint {
- fn degree(&self) -> usize {
- 2
- }
-
- fn constraint_idx(&self) -> usize {
- 54
- }
-
- fn evaluate(
- &self,
- frame: &Frame,
- transition_evaluations: &mut [Felt252],
- _periodic_values: &[Felt252],
- _rap_challenges: &[Felt252],
- ) {
- let current_step = frame.get_evaluation_step(0);
-
- let one = Felt252::one();
- let two = Felt252::from(2);
-
- let f_op1_imm = current_step.get_main_evaluation_element(0, 2)
- - two * current_step.get_main_evaluation_element(0, 3);
- let f_op1_fp = current_step.get_main_evaluation_element(0, 3)
- - two * current_step.get_main_evaluation_element(0, 4);
- let f_op1_ap = current_step.get_main_evaluation_element(0, 4)
- - two * current_step.get_main_evaluation_element(0, 5);
-
- let f_op1_base_op0_bit = one - f_op1_imm - f_op1_fp - f_op1_ap;
-
- let res = f_op1_base_op0_bit * (f_op1_base_op0_bit - one);
-
- transition_evaluations[self.constraint_idx()] = res;
- }
-
- fn end_exemptions(&self) -> usize {
- 0
- }
-}
-
-pub struct FlagResOp1BitConstraint;
-impl Default for FlagResOp1BitConstraint {
- fn default() -> Self {
- Self::new()
- }
-}
-
-impl FlagResOp1BitConstraint {
- pub fn new() -> Self {
- Self
- }
-}
-
-impl TransitionConstraint for FlagResOp1BitConstraint {
- fn degree(&self) -> usize {
- 2
- }
-
- fn constraint_idx(&self) -> usize {
- 55
- }
-
- fn evaluate(
- &self,
- frame: &Frame,
- transition_evaluations: &mut [Felt252],
- _periodic_values: &[Felt252],
- _rap_challenges: &[Felt252],
- ) {
- let current_step = frame.get_evaluation_step(0);
-
- let one = Felt252::one();
- let two = Felt252::from(2);
-
- let f_res_add = current_step.get_main_evaluation_element(0, 5)
- - two * current_step.get_main_evaluation_element(0, 6);
- let f_res_mul = current_step.get_main_evaluation_element(0, 6)
- - two * current_step.get_main_evaluation_element(0, 7);
- let f_pc_jnz = current_step.get_main_evaluation_element(0, 9)
- - two * current_step.get_main_evaluation_element(0, 10);
-
- let f_res_op1_bit = one - f_res_add - f_res_mul - f_pc_jnz;
-
- let res = f_res_op1_bit * (f_res_op1_bit - one);
-
- transition_evaluations[self.constraint_idx()] = res;
- }
-
- fn end_exemptions(&self) -> usize {
- 0
- }
-}
-
-pub struct FlagPcUpdateRegularBit;
-impl Default for FlagPcUpdateRegularBit {
- fn default() -> Self {
- Self::new()
- }
-}
-
-impl FlagPcUpdateRegularBit {
- pub fn new() -> Self {
- Self
- }
-}
-
-impl TransitionConstraint for FlagPcUpdateRegularBit {
- fn degree(&self) -> usize {
- 2
- }
-
- fn constraint_idx(&self) -> usize {
- 56
- }
-
- fn evaluate(
- &self,
- frame: &Frame,
- transition_evaluations: &mut [Felt252],
- _periodic_values: &[Felt252],
- _rap_challenges: &[Felt252],
- ) {
- let current_step = frame.get_evaluation_step(0);
-
- let one = Felt252::one();
- let two = Felt252::from(2);
-
- let f_jump_abs = current_step.get_main_evaluation_element(0, 7)
- - two * current_step.get_main_evaluation_element(0, 8);
- let f_jump_rel = current_step.get_main_evaluation_element(0, 8)
- - two * current_step.get_main_evaluation_element(0, 9);
- let f_pc_jnz = current_step.get_main_evaluation_element(0, 9)
- - two * current_step.get_main_evaluation_element(0, 10);
-
- let flag_pc_update_regular_bit = one - f_jump_abs - f_jump_rel - f_pc_jnz;
-
- let res = flag_pc_update_regular_bit * (flag_pc_update_regular_bit - one);
-
- transition_evaluations[self.constraint_idx()] = res;
- }
-
- fn end_exemptions(&self) -> usize {
- 0
- }
-}
-
-pub struct FlagFpUpdateRegularBit;
-impl Default for FlagFpUpdateRegularBit {
- fn default() -> Self {
- Self::new()
- }
-}
-
-impl FlagFpUpdateRegularBit {
- pub fn new() -> Self {
- Self
- }
-}
-
-impl TransitionConstraint for FlagFpUpdateRegularBit {
- fn degree(&self) -> usize {
- 2
- }
-
- fn constraint_idx(&self) -> usize {
- 57
- }
-
- fn evaluate(
- &self,
- frame: &Frame,
- transition_evaluations: &mut [Felt252],
- _periodic_values: &[Felt252],
- _rap_challenges: &[Felt252],
- ) {
- let current_step = frame.get_evaluation_step(0);
-
- let one = Felt252::one();
- let two = Felt252::from(2);
-
- let f_opcode_call = current_step.get_main_evaluation_element(0, 12)
- - two * current_step.get_main_evaluation_element(0, 13);
- let f_opcode_ret = current_step.get_main_evaluation_element(0, 13)
- - two * current_step.get_main_evaluation_element(0, 14);
-
- let flag_fp_update_regular_bit = one - f_opcode_call - f_opcode_ret;
-
- let res = flag_fp_update_regular_bit * (flag_fp_update_regular_bit - one);
-
- transition_evaluations[self.constraint_idx()] = res;
- }
-
- fn end_exemptions(&self) -> usize {
- 0
- }
-}
-
-pub struct InstructionUnpacking;
-impl Default for InstructionUnpacking {
- fn default() -> Self {
- Self::new()
- }
-}
-
-impl InstructionUnpacking {
- pub fn new() -> Self {
- Self
- }
-}
-
-impl TransitionConstraint for InstructionUnpacking {
- fn degree(&self) -> usize {
- 1
- }
-
- fn constraint_idx(&self) -> usize {
- 16
- }
-
- fn evaluate(
- &self,
- frame: &Frame,
- transition_evaluations: &mut [Felt252],
- _periodic_values: &[Felt252],
- _rap_challenges: &[Felt252],
- ) {
- let current_step = frame.get_evaluation_step(0);
-
- let two = Felt252::from(2);
- let b16 = two.pow(16u32);
- let b32 = two.pow(32u32);
- let b48 = two.pow(48u32);
-
- // Named like this to match the Cairo whitepaper's notation.
- let f0_squiggle = current_step.get_main_evaluation_element(0, 0);
-
- let instruction = current_step.get_main_evaluation_element(0, 23);
- let off_dst = current_step.get_main_evaluation_element(0, 27);
- let off_op0 = current_step.get_main_evaluation_element(0, 28);
- let off_op1 = current_step.get_main_evaluation_element(0, 29);
-
- let res = off_dst + b16 * off_op0 + b32 * off_op1 + b48 * f0_squiggle - instruction;
-
- transition_evaluations[self.constraint_idx()] = res;
- }
-
- fn end_exemptions(&self) -> usize {
- 0
- }
-}
-
-pub struct CpuOpcodesCallOff0;
-impl Default for CpuOpcodesCallOff0 {
- fn default() -> Self {
- Self::new()
- }
-}
-
-impl CpuOpcodesCallOff0 {
- pub fn new() -> Self {
- Self
- }
-}
-
-impl TransitionConstraint for CpuOpcodesCallOff0 {
- fn degree(&self) -> usize {
- 2
- }
-
- fn constraint_idx(&self) -> usize {
- 58
- }
-
- fn evaluate(
- &self,
- frame: &Frame,
- transition_evaluations: &mut [Felt252],
- _periodic_values: &[Felt252],
- _rap_challenges: &[Felt252],
- ) {
- let current_step = frame.get_evaluation_step(0);
- let two = Felt252::from(2);
- let b15 = two.pow(15u32);
-
- let f_opcode_call = current_step.get_main_evaluation_element(0, 12)
- - two * current_step.get_main_evaluation_element(0, 13);
-
- let off_dst = current_step.get_main_evaluation_element(0, 27);
-
- let res = f_opcode_call * (off_dst - b15);
-
- transition_evaluations[self.constraint_idx()] = res;
- }
-
- fn end_exemptions(&self) -> usize {
- 0
- }
-}
-
-pub struct CpuOpcodesCallOff1;
-impl Default for CpuOpcodesCallOff1 {
- fn default() -> Self {
- Self::new()
- }
-}
-
-impl CpuOpcodesCallOff1 {
- pub fn new() -> Self {
- Self
- }
-}
-
-impl TransitionConstraint for CpuOpcodesCallOff1 {
- fn degree(&self) -> usize {
- 2
- }
-
- fn constraint_idx(&self) -> usize {
- 59
- }
-
- fn evaluate(
- &self,
- frame: &Frame,
- transition_evaluations: &mut [Felt252],
- _periodic_values: &[Felt252],
- _rap_challenges: &[Felt252],
- ) {
- let current_step = frame.get_evaluation_step(0);
-
- let one = Felt252::one();
- let two = Felt252::from(2);
- let b15 = two.pow(15u32);
-
- let f_opcode_call = current_step.get_main_evaluation_element(0, 12)
- - two * current_step.get_main_evaluation_element(0, 13);
- let off_op0 = current_step.get_main_evaluation_element(0, 28);
-
- let res = f_opcode_call * (off_op0 - b15 - one);
-
- transition_evaluations[self.constraint_idx()] = res;
- }
-
- fn end_exemptions(&self) -> usize {
- 0
- }
-}
-
-pub struct CpuOpcodesCallFlags;
-impl Default for CpuOpcodesCallFlags {
- fn default() -> Self {
- Self::new()
- }
-}
-
-impl CpuOpcodesCallFlags {
- pub fn new() -> Self {
- Self
- }
-}
-
-impl TransitionConstraint for CpuOpcodesCallFlags {
- fn degree(&self) -> usize {
- 2
- }
-
- fn constraint_idx(&self) -> usize {
- 60
- }
-
- fn evaluate(
- &self,
- frame: &Frame,
- transition_evaluations: &mut [Felt252],
- _periodic_values: &[Felt252],
- _rap_challenges: &[Felt252],
- ) {
- let current_step = frame.get_evaluation_step(0);
-
- let one = Felt252::one();
- let two = Felt252::from(2);
-
- let f_opcode_call = current_step.get_main_evaluation_element(0, 12)
- - two * current_step.get_main_evaluation_element(0, 13);
-
- let bit_flag0 = current_step.get_main_evaluation_element(0, 0)
- - two * current_step.get_main_evaluation_element(0, 1);
- let bit_flag1 = current_step.get_main_evaluation_element(0, 1)
- - two * current_step.get_main_evaluation_element(0, 2);
-
- let res =
- f_opcode_call * (two * f_opcode_call + one + one - bit_flag0 - bit_flag1 - two - two);
-
- transition_evaluations[self.constraint_idx()] = res;
- }
-
- fn end_exemptions(&self) -> usize {
- 0
- }
-}
-
-pub struct CpuOpcodesRetOff0;
-impl Default for CpuOpcodesRetOff0 {
- fn default() -> Self {
- Self::new()
- }
-}
-
-impl CpuOpcodesRetOff0 {
- pub fn new() -> Self {
- Self
- }
-}
-
-impl TransitionConstraint