From d5460804d6605b32475685ae8b09b437b44e8a21 Mon Sep 17 00:00:00 2001 From: Nicole Date: Wed, 13 Nov 2024 16:55:50 -0300 Subject: [PATCH 01/15] create file --- provers/stark/src/examples/mod.rs | 1 + .../stark/src/examples/read_only_memory.rs | 370 ++++++++++++++++++ 2 files changed, 371 insertions(+) create mode 100644 provers/stark/src/examples/read_only_memory.rs diff --git a/provers/stark/src/examples/mod.rs b/provers/stark/src/examples/mod.rs index 6a8949f7a..ba4f6586e 100644 --- a/provers/stark/src/examples/mod.rs +++ b/provers/stark/src/examples/mod.rs @@ -4,5 +4,6 @@ pub mod fibonacci_2_cols_shifted; pub mod fibonacci_2_columns; pub mod fibonacci_rap; pub mod quadratic_air; +pub mod read_only_memory; pub mod simple_fibonacci; pub mod simple_periodic_cols; diff --git a/provers/stark/src/examples/read_only_memory.rs b/provers/stark/src/examples/read_only_memory.rs new file mode 100644 index 000000000..18084f86f --- /dev/null +++ b/provers/stark/src/examples/read_only_memory.rs @@ -0,0 +1,370 @@ +use std::{marker::PhantomData, ops::Div}; + +use crate::{ + constraints::{ + boundary::{BoundaryConstraint, BoundaryConstraints}, + transition::TransitionConstraint, + }, + context::AirContext, + frame::Frame, + proof::options::ProofOptions, + trace::TraceTable, + traits::AIR, +}; +use lambdaworks_crypto::fiat_shamir::is_transcript::IsTranscript; +use lambdaworks_math::{ + field::{element::FieldElement, traits::IsFFTField}, + helpers::resize_to_next_power_of_two, + traits::ByteConversion, +}; + +#[derive(Clone)] +struct FibConstraint { + phantom: PhantomData, +} + +impl FibConstraint { + pub fn new() -> Self { + Self { + phantom: PhantomData, + } + } +} + +impl TransitionConstraint for FibConstraint +where + F: IsFFTField + Send + Sync, +{ + fn degree(&self) -> usize { + 1 + } + + fn constraint_idx(&self) -> usize { + 0 + } + + fn end_exemptions(&self) -> usize { + // NOTE: This is hard-coded for the example of steps = 16 in the integration tests. + // If that number changes in the test, this should be changed too or the test will fail. + 3 + 32 - 16 - 1 + } + + fn evaluate( + &self, + frame: &Frame, + transition_evaluations: &mut [FieldElement], + _periodic_values: &[FieldElement], + _rap_challenges: &[FieldElement], + ) { + let first_step = frame.get_evaluation_step(0); + let second_step = frame.get_evaluation_step(1); + let third_step = frame.get_evaluation_step(2); + + let a0 = first_step.get_main_evaluation_element(0, 0); + let a1 = second_step.get_main_evaluation_element(0, 0); + let a2 = third_step.get_main_evaluation_element(0, 0); + + let res = a2 - a1 - a0; + + transition_evaluations[self.constraint_idx()] = res; + } +} + +#[derive(Clone)] +struct PermutationConstraint { + phantom: PhantomData, +} + +impl PermutationConstraint { + pub fn new() -> Self { + Self { + phantom: PhantomData, + } + } +} + +impl TransitionConstraint for PermutationConstraint +where + F: IsFFTField + Send + Sync, +{ + fn degree(&self) -> usize { + 2 + } + + fn constraint_idx(&self) -> usize { + 1 + } + + fn end_exemptions(&self) -> usize { + 1 + } + + fn evaluate( + &self, + frame: &Frame, + transition_evaluations: &mut [FieldElement], + _periodic_values: &[FieldElement], + rap_challenges: &[FieldElement], + ) { + let first_step = frame.get_evaluation_step(0); + let second_step = frame.get_evaluation_step(1); + + // Auxiliary constraints + let z_i = first_step.get_aux_evaluation_element(0, 0); + let z_i_plus_one = second_step.get_aux_evaluation_element(0, 0); + let gamma = &rap_challenges[0]; + + let a_i = first_step.get_main_evaluation_element(0, 0); + let b_i = first_step.get_main_evaluation_element(0, 1); + + let res = z_i_plus_one * (b_i + gamma) - z_i * (a_i + gamma); + + transition_evaluations[self.constraint_idx()] = res; + } +} + +pub struct FibonacciRAP +where + F: IsFFTField, +{ + context: AirContext, + trace_length: usize, + pub_inputs: FibonacciRAPPublicInputs, + transition_constraints: Vec>>, +} + +#[derive(Clone, Debug)] +pub struct FibonacciRAPPublicInputs +where + F: IsFFTField, +{ + pub steps: usize, + pub a0: FieldElement, + pub a1: FieldElement, +} + +impl AIR for FibonacciRAP +where + F: IsFFTField + Send + Sync + 'static, + FieldElement: ByteConversion, +{ + type Field = F; + type FieldExtension = F; + type PublicInputs = FibonacciRAPPublicInputs; + + const STEP_SIZE: usize = 1; + + fn new( + trace_length: usize, + pub_inputs: &Self::PublicInputs, + proof_options: &ProofOptions, + ) -> Self { + let transition_constraints: Vec< + Box>, + > = vec![ + Box::new(FibConstraint::new()), + Box::new(PermutationConstraint::new()), + ]; + + let exemptions = 3 + trace_length - pub_inputs.steps - 1; + + let context = AirContext { + proof_options: proof_options.clone(), + trace_columns: 3, + transition_offsets: vec![0, 1, 2], + transition_exemptions: vec![exemptions, 1], + num_transition_constraints: transition_constraints.len(), + }; + + Self { + context, + trace_length, + pub_inputs: pub_inputs.clone(), + transition_constraints, + } + } + + fn build_auxiliary_trace( + &self, + main_trace: &TraceTable, + challenges: &[FieldElement], + ) -> TraceTable { + let main_segment_cols = main_trace.columns(); + let not_perm = &main_segment_cols[0]; + let perm = &main_segment_cols[1]; + let gamma = &challenges[0]; + + let trace_len = main_trace.n_rows(); + + let mut aux_col = Vec::new(); + for i in 0..trace_len { + if i == 0 { + aux_col.push(FieldElement::::one()); + } else { + let z_i = &aux_col[i - 1]; + let n_p_term = not_perm[i - 1].clone() + gamma; + let p_term = &perm[i - 1] + gamma; + + aux_col.push(z_i * n_p_term.div(p_term)); + } + } + TraceTable::from_columns(vec![aux_col], 0, 1) + } + + fn build_rap_challenges( + &self, + transcript: &mut impl IsTranscript, + ) -> Vec> { + vec![transcript.sample_field_element()] + } + + fn trace_layout(&self) -> (usize, usize) { + (2, 1) + } + + fn boundary_constraints( + &self, + _rap_challenges: &[FieldElement], + ) -> BoundaryConstraints { + // Main boundary constraints + let a0 = + BoundaryConstraint::new_simple_main(0, FieldElement::::one()); + let a1 = + BoundaryConstraint::new_simple_main(1, FieldElement::::one()); + + // Auxiliary boundary constraints + let a0_aux = BoundaryConstraint::new_aux(0, 0, FieldElement::::one()); + + BoundaryConstraints::from_constraints(vec![a0, a1, a0_aux]) + // BoundaryConstraints::from_constraints(vec![a0, a1]) + } + + fn transition_constraints( + &self, + ) -> &Vec>> { + &self.transition_constraints + } + + fn context(&self) -> &AirContext { + &self.context + } + + fn composition_poly_degree_bound(&self) -> usize { + self.trace_length() + } + + fn trace_length(&self) -> usize { + self.trace_length + } + + fn pub_inputs(&self) -> &Self::PublicInputs { + &self.pub_inputs + } + + fn compute_transition_verifier( + &self, + frame: &Frame, + periodic_values: &[FieldElement], + rap_challenges: &[FieldElement], + ) -> Vec> { + self.compute_transition_prover(frame, periodic_values, rap_challenges) + } +} + +pub fn fibonacci_rap_trace( + initial_values: [FieldElement; 2], + trace_length: usize, +) -> TraceTable { + let mut fib_seq: Vec> = vec![]; + + fib_seq.push(initial_values[0].clone()); + fib_seq.push(initial_values[1].clone()); + + for i in 2..(trace_length) { + fib_seq.push(fib_seq[i - 1].clone() + fib_seq[i - 2].clone()); + } + + let last_value = fib_seq[trace_length - 1].clone(); + let mut fib_permuted = fib_seq.clone(); + fib_permuted[0] = last_value; + fib_permuted[trace_length - 1] = initial_values[0].clone(); + + fib_seq.push(FieldElement::::zero()); + fib_permuted.push(FieldElement::::zero()); + let mut trace_cols = vec![fib_seq, fib_permuted]; + resize_to_next_power_of_two(&mut trace_cols); + + TraceTable::from_columns(trace_cols, 2, 1) +} + +#[cfg(test)] +mod test { + use super::*; + use lambdaworks_math::field::fields::u64_prime_field::FE17; + + #[test] + fn test_build_fibonacci_rap_trace() { + // The fibonacci RAP trace should have two columns: + // * The usual fibonacci sequence column + // * The permuted fibonacci sequence column. The first and last elements are permuted. + // Also, a 0 is appended at the end of both columns. The reason for this can be read in + // https://hackmd.io/@aztec-network/plonk-arithmetiization-air#RAPs---PAIRs-with-interjected-verifier-randomness + + let trace = fibonacci_rap_trace([FE17::from(1), FE17::from(1)], 8); + let mut expected_trace = vec![ + vec![ + FE17::one(), + FE17::one(), + FE17::from(2), + FE17::from(3), + FE17::from(5), + FE17::from(8), + FE17::from(13), + FE17::from(21), + FE17::zero(), + ], + vec![ + FE17::from(21), + FE17::one(), + FE17::from(2), + FE17::from(3), + FE17::from(5), + FE17::from(8), + FE17::from(13), + FE17::one(), + FE17::zero(), + ], + ]; + resize_to_next_power_of_two(&mut expected_trace); + + assert_eq!(trace.columns(), expected_trace); + } + + #[test] + fn aux_col() { + let trace = fibonacci_rap_trace([FE17::from(1), FE17::from(1)], 64); + let trace_cols = trace.columns(); + + let not_perm = trace_cols[0].clone(); + let perm = trace_cols[1].clone(); + let gamma = FE17::from(10); + + assert_eq!(perm.len(), not_perm.len()); + let trace_len = not_perm.len(); + + let mut aux_col = Vec::new(); + for i in 0..trace_len { + if i == 0 { + aux_col.push(FE17::one()); + } else { + let z_i = aux_col[i - 1]; + let n_p_term = not_perm[i - 1] + gamma; + let p_term = perm[i - 1] + gamma; + + aux_col.push(z_i * n_p_term.div(p_term)); + } + } + + assert_eq!(aux_col.last().unwrap(), &FE17::one()); + } +} From 7ff029063ac4caf7ef6eac2e5189a30630c569b8 Mon Sep 17 00:00:00 2001 From: Nicole Date: Wed, 13 Nov 2024 17:21:25 -0300 Subject: [PATCH 02/15] continuity and single value constraint --- .../stark/src/examples/read_only_memory.rs | 73 +++++++++++++++---- 1 file changed, 60 insertions(+), 13 deletions(-) diff --git a/provers/stark/src/examples/read_only_memory.rs b/provers/stark/src/examples/read_only_memory.rs index 18084f86f..51e32c2ca 100644 --- a/provers/stark/src/examples/read_only_memory.rs +++ b/provers/stark/src/examples/read_only_memory.rs @@ -19,11 +19,11 @@ use lambdaworks_math::{ }; #[derive(Clone)] -struct FibConstraint { +struct ContinuityConstraint { phantom: PhantomData, } -impl FibConstraint { +impl ContinuityConstraint { pub fn new() -> Self { Self { phantom: PhantomData, @@ -31,12 +31,12 @@ impl FibConstraint { } } -impl TransitionConstraint for FibConstraint +impl TransitionConstraint for ContinuityConstraint where F: IsFFTField + Send + Sync, { fn degree(&self) -> usize { - 1 + 2 } fn constraint_idx(&self) -> usize { @@ -44,9 +44,56 @@ where } fn end_exemptions(&self) -> usize { - // NOTE: This is hard-coded for the example of steps = 16 in the integration tests. - // If that number changes in the test, this should be changed too or the test will fail. - 3 + 32 - 16 - 1 + // NOTE: We are assuming that hte trace has as length a power of 2. + 1 + } + + fn evaluate( + &self, + frame: &Frame, + transition_evaluations: &mut [FieldElement], + _periodic_values: &[FieldElement], + _rap_challenges: &[FieldElement], + ) { + let first_step = frame.get_evaluation_step(0); + let second_step = frame.get_evaluation_step(1); + + let a0 = first_step.get_main_evaluation_element(0, 2); + let a1 = second_step.get_main_evaluation_element(0, 2); + let res = (a1 - a0) * (a1 - a0 - FieldElement::::one()); + + transition_evaluations[self.constraint_idx()] = res; + } +} + +#[derive(Clone)] +struct SingleValueConstraint { + phantom: PhantomData, +} + +impl SingleValueConstraint { + pub fn new() -> Self { + Self { + phantom: PhantomData, + } + } +} + +impl TransitionConstraint for SingleValueConstraint +where + F: IsFFTField + Send + Sync, +{ + fn degree(&self) -> usize { + 2 + } + + fn constraint_idx(&self) -> usize { + 1 + } + + fn end_exemptions(&self) -> usize { + // NOTE: We are assuming that hte trace has as length a power of 2. + 1 } fn evaluate( @@ -58,13 +105,13 @@ where ) { let first_step = frame.get_evaluation_step(0); let second_step = frame.get_evaluation_step(1); - let third_step = frame.get_evaluation_step(2); - let a0 = first_step.get_main_evaluation_element(0, 0); - let a1 = second_step.get_main_evaluation_element(0, 0); - let a2 = third_step.get_main_evaluation_element(0, 0); + let a0 = first_step.get_main_evaluation_element(0, 2); + let a1 = second_step.get_main_evaluation_element(0, 2); + let v0 = first_step.get_main_evaluation_element(0, 3); + let v1 = second_step.get_main_evaluation_element(0, 3); - let res = a2 - a1 - a0; + let res = (v1 - v0) * (a1 - a0 - FieldElement::::one()); transition_evaluations[self.constraint_idx()] = res; } @@ -162,7 +209,7 @@ where let transition_constraints: Vec< Box>, > = vec![ - Box::new(FibConstraint::new()), + Box::new(ContinuityConstraint::new()), Box::new(PermutationConstraint::new()), ]; From e9929700ef034c0613a2401bbe26ee734878141e Mon Sep 17 00:00:00 2001 From: Joaquin Carletti Date: Wed, 13 Nov 2024 18:00:22 -0300 Subject: [PATCH 03/15] imp air --- .../stark/src/examples/read_only_memory.rs | 51 +++++++++---------- 1 file changed, 24 insertions(+), 27 deletions(-) diff --git a/provers/stark/src/examples/read_only_memory.rs b/provers/stark/src/examples/read_only_memory.rs index 51e32c2ca..1332fadf4 100644 --- a/provers/stark/src/examples/read_only_memory.rs +++ b/provers/stark/src/examples/read_only_memory.rs @@ -213,13 +213,11 @@ where Box::new(PermutationConstraint::new()), ]; - let exemptions = 3 + trace_length - pub_inputs.steps - 1; - let context = AirContext { proof_options: proof_options.clone(), - trace_columns: 3, - transition_offsets: vec![0, 1, 2], - transition_exemptions: vec![exemptions, 1], + trace_columns: 5, + transition_offsets: vec![0, 1], + transition_exemptions: vec![1], num_transition_constraints: transition_constraints.len(), }; @@ -237,24 +235,26 @@ where challenges: &[FieldElement], ) -> TraceTable { let main_segment_cols = main_trace.columns(); - let not_perm = &main_segment_cols[0]; - let perm = &main_segment_cols[1]; - let gamma = &challenges[0]; + let a = &main_segment_cols[0]; + let v = &main_segment_cols[1]; + let a_perm = &main_segment_cols[2]; + let v_perm = &main_segment_cols[3]; + let z = &challenges[0]; + let alpha = &challenges[1]; let trace_len = main_trace.n_rows(); let mut aux_col = Vec::new(); - for i in 0..trace_len { - if i == 0 { - aux_col.push(FieldElement::::one()); - } else { - let z_i = &aux_col[i - 1]; - let n_p_term = not_perm[i - 1].clone() + gamma; - let p_term = &perm[i - 1] + gamma; - - aux_col.push(z_i * n_p_term.div(p_term)); - } + let num = z - (&a[0] + alpha * &v[0]); + let den = z - (&a_perm[0] + alpha * &v_perm[0]); + aux_col.push(num / den); + + for i in 0..trace_len - 1 { + let num = (z - (&a[i + 1] + alpha * &v[i + 1])) * &aux_col[i]; + let den = z - (&a_perm[i + 1] + alpha * &v_perm[i + 1]); + aux_col.push(num / den); } + TraceTable::from_columns(vec![aux_col], 0, 1) } @@ -262,27 +262,24 @@ where &self, transcript: &mut impl IsTranscript, ) -> Vec> { - vec![transcript.sample_field_element()] + vec![ + transcript.sample_field_element(), + transcript.sample_field_element(), + ] } fn trace_layout(&self) -> (usize, usize) { - (2, 1) + (4, 1) } fn boundary_constraints( &self, _rap_challenges: &[FieldElement], ) -> BoundaryConstraints { - // Main boundary constraints - let a0 = - BoundaryConstraint::new_simple_main(0, FieldElement::::one()); - let a1 = - BoundaryConstraint::new_simple_main(1, FieldElement::::one()); - // Auxiliary boundary constraints let a0_aux = BoundaryConstraint::new_aux(0, 0, FieldElement::::one()); - BoundaryConstraints::from_constraints(vec![a0, a1, a0_aux]) + BoundaryConstraints::from_constraints(vec![a0_aux]) // BoundaryConstraints::from_constraints(vec![a0, a1]) } From 821e1f628672c0a0cb1c670d0d1b7fdb1fea6d95 Mon Sep 17 00:00:00 2001 From: Nicole Date: Wed, 13 Nov 2024 18:01:50 -0300 Subject: [PATCH 04/15] permutation constraint --- .../stark/src/examples/read_only_memory.rs | 51 ++++++++----------- 1 file changed, 21 insertions(+), 30 deletions(-) diff --git a/provers/stark/src/examples/read_only_memory.rs b/provers/stark/src/examples/read_only_memory.rs index 1332fadf4..f2d2d2938 100644 --- a/provers/stark/src/examples/read_only_memory.rs +++ b/provers/stark/src/examples/read_only_memory.rs @@ -58,9 +58,9 @@ where let first_step = frame.get_evaluation_step(0); let second_step = frame.get_evaluation_step(1); - let a0 = first_step.get_main_evaluation_element(0, 2); - let a1 = second_step.get_main_evaluation_element(0, 2); - let res = (a1 - a0) * (a1 - a0 - FieldElement::::one()); + let a_perm0 = first_step.get_main_evaluation_element(0, 2); + let a_perm1 = second_step.get_main_evaluation_element(0, 2); + let res = (a_perm1 - a_perm0) * (a_perm1 - a_perm0 - FieldElement::::one()); transition_evaluations[self.constraint_idx()] = res; } @@ -106,12 +106,12 @@ where let first_step = frame.get_evaluation_step(0); let second_step = frame.get_evaluation_step(1); - let a0 = first_step.get_main_evaluation_element(0, 2); - let a1 = second_step.get_main_evaluation_element(0, 2); - let v0 = first_step.get_main_evaluation_element(0, 3); - let v1 = second_step.get_main_evaluation_element(0, 3); + let a_perm0 = first_step.get_main_evaluation_element(0, 2); + let a_perm1 = second_step.get_main_evaluation_element(0, 2); + let v_perm0 = first_step.get_main_evaluation_element(0, 3); + let v_perm1 = second_step.get_main_evaluation_element(0, 3); - let res = (v1 - v0) * (a1 - a0 - FieldElement::::one()); + let res = (v_perm1 - v_perm0) * (a_perm1 - a_perm0 - FieldElement::::one()); transition_evaluations[self.constraint_idx()] = res; } @@ -139,7 +139,7 @@ where } fn constraint_idx(&self) -> usize { - 1 + 2 } fn end_exemptions(&self) -> usize { @@ -157,47 +157,38 @@ where let second_step = frame.get_evaluation_step(1); // Auxiliary constraints - let z_i = first_step.get_aux_evaluation_element(0, 0); - let z_i_plus_one = second_step.get_aux_evaluation_element(0, 0); - let gamma = &rap_challenges[0]; + let p0 = first_step.get_aux_evaluation_element(0, 0); + let p1 = second_step.get_aux_evaluation_element(0, 0); + let alpha = &rap_challenges[0]; + let z = &rap_challenges[1]; + let a1 = second_step.get_main_evaluation_element(0, 0); + let v1 = second_step.get_main_evaluation_element(0, 1); + let a_perm_1 = second_step.get_main_evaluation_element(0, 2); + let v_perm_1 = second_step.get_main_evaluation_element(0, 3); - let a_i = first_step.get_main_evaluation_element(0, 0); - let b_i = first_step.get_main_evaluation_element(0, 1); - - let res = z_i_plus_one * (b_i + gamma) - z_i * (a_i + gamma); + let res = (z - (a_perm_1 + alpha * v_perm_1)) * p1 - (z - (a1 + alpha * v1)) * p0; transition_evaluations[self.constraint_idx()] = res; } } -pub struct FibonacciRAP +pub struct ReadOnlyRAP where F: IsFFTField, { context: AirContext, trace_length: usize, - pub_inputs: FibonacciRAPPublicInputs, transition_constraints: Vec>>, } -#[derive(Clone, Debug)] -pub struct FibonacciRAPPublicInputs -where - F: IsFFTField, -{ - pub steps: usize, - pub a0: FieldElement, - pub a1: FieldElement, -} - -impl AIR for FibonacciRAP +impl AIR for ReadOnlyRAP where F: IsFFTField + Send + Sync + 'static, FieldElement: ByteConversion, { type Field = F; type FieldExtension = F; - type PublicInputs = FibonacciRAPPublicInputs; + type PublicInputs = (); const STEP_SIZE: usize = 1; From 56de567d84be95d6a7bc3ef3d21d88eb9cd5b071 Mon Sep 17 00:00:00 2001 From: Nicole Date: Thu, 14 Nov 2024 12:06:53 -0300 Subject: [PATCH 05/15] evaluate function for SingleValueConstraint --- provers/stark/src/examples/read_only_memory.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/provers/stark/src/examples/read_only_memory.rs b/provers/stark/src/examples/read_only_memory.rs index f2d2d2938..4b6c1fe4f 100644 --- a/provers/stark/src/examples/read_only_memory.rs +++ b/provers/stark/src/examples/read_only_memory.rs @@ -215,7 +215,6 @@ where Self { context, trace_length, - pub_inputs: pub_inputs.clone(), transition_constraints, } } @@ -293,7 +292,7 @@ where } fn pub_inputs(&self) -> &Self::PublicInputs { - &self.pub_inputs + &() } fn compute_transition_verifier( From 52912f12884819f2271203ba1b47c5b4b3f1752a Mon Sep 17 00:00:00 2001 From: Joaquin Carletti Date: Thu, 14 Nov 2024 12:18:27 -0300 Subject: [PATCH 06/15] add last element constraint --- provers/stark/src/examples/read_only_memory.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/provers/stark/src/examples/read_only_memory.rs b/provers/stark/src/examples/read_only_memory.rs index 4b6c1fe4f..c9fb9eb9b 100644 --- a/provers/stark/src/examples/read_only_memory.rs +++ b/provers/stark/src/examples/read_only_memory.rs @@ -267,7 +267,11 @@ where _rap_challenges: &[FieldElement], ) -> BoundaryConstraints { // Auxiliary boundary constraints - let a0_aux = BoundaryConstraint::new_aux(0, 0, FieldElement::::one()); + let a0_aux = BoundaryConstraint::new_aux( + 0, + self.trace_length - 1, + FieldElement::::one(), + ); BoundaryConstraints::from_constraints(vec![a0_aux]) // BoundaryConstraints::from_constraints(vec![a0, a1]) From 0b5ac615e878ccda7b6583630b22e24b45d2ca0b Mon Sep 17 00:00:00 2001 From: Joaquin Carletti Date: Thu, 14 Nov 2024 15:20:39 -0300 Subject: [PATCH 07/15] add public inputs --- .../stark/src/examples/read_only_memory.rs | 53 ++++++++++++++----- 1 file changed, 41 insertions(+), 12 deletions(-) diff --git a/provers/stark/src/examples/read_only_memory.rs b/provers/stark/src/examples/read_only_memory.rs index c9fb9eb9b..505b99749 100644 --- a/provers/stark/src/examples/read_only_memory.rs +++ b/provers/stark/src/examples/read_only_memory.rs @@ -178,9 +178,21 @@ where { context: AirContext, trace_length: usize, + pub_inputs: ReadOnlyPublicInputs, transition_constraints: Vec>>, } +#[derive(Clone, Debug)] +pub struct ReadOnlyPublicInputs +where + F: IsFFTField, +{ + pub a0: FieldElement, + pub v0: FieldElement, + pub a_perm0: FieldElement, + pub v_perm0: FieldElement, +} + impl AIR for ReadOnlyRAP where F: IsFFTField + Send + Sync + 'static, @@ -188,7 +200,7 @@ where { type Field = F; type FieldExtension = F; - type PublicInputs = (); + type PublicInputs = ReadOnlyPublicInputs; const STEP_SIZE: usize = 1; @@ -208,23 +220,23 @@ where proof_options: proof_options.clone(), trace_columns: 5, transition_offsets: vec![0, 1], - transition_exemptions: vec![1], num_transition_constraints: transition_constraints.len(), }; Self { context, trace_length, + pub_inputs: pub_inputs.clone(), transition_constraints, } } fn build_auxiliary_trace( &self, - main_trace: &TraceTable, + trace: &mut TraceTable, challenges: &[FieldElement], - ) -> TraceTable { - let main_segment_cols = main_trace.columns(); + ) { + let main_segment_cols = trace.columns_main(); let a = &main_segment_cols[0]; let v = &main_segment_cols[1]; let a_perm = &main_segment_cols[2]; @@ -232,7 +244,7 @@ where let z = &challenges[0]; let alpha = &challenges[1]; - let trace_len = main_trace.n_rows(); + let trace_len = trace.num_rows(); let mut aux_col = Vec::new(); let num = z - (&a[0] + alpha * &v[0]); @@ -245,7 +257,9 @@ where aux_col.push(num / den); } - TraceTable::from_columns(vec![aux_col], 0, 1) + for (i, aux_elem) in aux_col.iter().enumerate().take(trace.num_rows()) { + trace.set_aux(i, 0, aux_elem.clone()) + } } fn build_rap_challenges( @@ -264,17 +278,32 @@ where fn boundary_constraints( &self, - _rap_challenges: &[FieldElement], + rap_challenges: &[FieldElement], ) -> BoundaryConstraints { + let a0 = &self.pub_inputs.a0; + let v0 = &self.pub_inputs.v0; + let a_perm0 = &self.pub_inputs.a_perm0; + let v_perm0 = &self.pub_inputs.v_perm0; + let alpha = &rap_challenges[0]; + let z = &rap_challenges[1]; + // Main boundary constraints + let c1 = BoundaryConstraint::new_main(0, 0, a0.clone()); + let c2 = BoundaryConstraint::new_main(1, 0, v0.clone()); + let c3 = BoundaryConstraint::new_main(2, 0, a_perm0.clone()); + let c4 = BoundaryConstraint::new_main(3, 0, v_perm0.clone()); + // Auxiliary boundary constraints - let a0_aux = BoundaryConstraint::new_aux( + let num = z - (a0 + alpha * v0); + let den = z - (a_perm0 + alpha * v_perm0); + let p0_value = (num / den); + let c_aux1 = BoundaryConstraint::new_aux(0, 0, p0_value); + let c_aux2 = BoundaryConstraint::new_aux( 0, self.trace_length - 1, FieldElement::::one(), ); - BoundaryConstraints::from_constraints(vec![a0_aux]) - // BoundaryConstraints::from_constraints(vec![a0, a1]) + BoundaryConstraints::from_constraints(vec![c1, c2, c3, c4, c_aux1, c_aux2]) } fn transition_constraints( @@ -296,7 +325,7 @@ where } fn pub_inputs(&self) -> &Self::PublicInputs { - &() + &self.pub_inputs } fn compute_transition_verifier( From f9118377864b3d96c168253e6257bc1d8eefbdd2 Mon Sep 17 00:00:00 2001 From: jotabulacios Date: Thu, 14 Nov 2024 17:56:35 -0300 Subject: [PATCH 08/15] add sort function for the trace --- .../stark/src/examples/read_only_memory.rs | 146 ++++++++---------- 1 file changed, 62 insertions(+), 84 deletions(-) diff --git a/provers/stark/src/examples/read_only_memory.rs b/provers/stark/src/examples/read_only_memory.rs index 505b99749..9d41d6d98 100644 --- a/provers/stark/src/examples/read_only_memory.rs +++ b/provers/stark/src/examples/read_only_memory.rs @@ -12,6 +12,7 @@ use crate::{ traits::AIR, }; use lambdaworks_crypto::fiat_shamir::is_transcript::IsTranscript; +use lambdaworks_math::field::traits::IsPrimeField; use lambdaworks_math::{ field::{element::FieldElement, traits::IsFFTField}, helpers::resize_to_next_power_of_two, @@ -338,30 +339,23 @@ where } } -pub fn fibonacci_rap_trace( - initial_values: [FieldElement; 2], - trace_length: usize, -) -> TraceTable { - let mut fib_seq: Vec> = vec![]; - - fib_seq.push(initial_values[0].clone()); - fib_seq.push(initial_values[1].clone()); - - for i in 2..(trace_length) { - fib_seq.push(fib_seq[i - 1].clone() + fib_seq[i - 2].clone()); - } - - let last_value = fib_seq[trace_length - 1].clone(); - let mut fib_permuted = fib_seq.clone(); - fib_permuted[0] = last_value; - fib_permuted[trace_length - 1] = initial_values[0].clone(); - - fib_seq.push(FieldElement::::zero()); - fib_permuted.push(FieldElement::::zero()); - let mut trace_cols = vec![fib_seq, fib_permuted]; - resize_to_next_power_of_two(&mut trace_cols); - - TraceTable::from_columns(trace_cols, 2, 1) +pub fn sort_rap_trace( + address: Vec>, + value: Vec>, +) -> TraceTable { + let mut address_value_pairs: Vec<_> = address.iter().zip(value.iter()).collect(); + + address_value_pairs.sort_by_key(|(addr, _)| addr.representative()); + + let (sorted_address, sorted_value): (Vec>, Vec>) = + address_value_pairs + .into_iter() + .map(|(addr, val)| (addr.clone(), val.clone())) + .unzip(); + let main_columns = vec![address.clone(), value.clone(), sorted_address, sorted_value]; + // create a vector with zeros of the same length as the main columns + let zero_vec = vec![FieldElement::::zero(); main_columns[0].len()]; + TraceTable::from_columns(main_columns, vec![zero_vec], 1) } #[cfg(test)] @@ -370,68 +364,52 @@ mod test { use lambdaworks_math::field::fields::u64_prime_field::FE17; #[test] - fn test_build_fibonacci_rap_trace() { - // The fibonacci RAP trace should have two columns: - // * The usual fibonacci sequence column - // * The permuted fibonacci sequence column. The first and last elements are permuted. - // Also, a 0 is appended at the end of both columns. The reason for this can be read in - // https://hackmd.io/@aztec-network/plonk-arithmetiization-air#RAPs---PAIRs-with-interjected-verifier-randomness - - let trace = fibonacci_rap_trace([FE17::from(1), FE17::from(1)], 8); - let mut expected_trace = vec![ - vec![ - FE17::one(), - FE17::one(), - FE17::from(2), - FE17::from(3), - FE17::from(5), - FE17::from(8), - FE17::from(13), - FE17::from(21), - FE17::zero(), - ], - vec![ - FE17::from(21), - FE17::one(), - FE17::from(2), - FE17::from(3), - FE17::from(5), - FE17::from(8), - FE17::from(13), - FE17::one(), - FE17::zero(), - ], + fn test_sort_rap_trace() { + let address_col = vec![ + FE17::from(5), + FE17::from(2), + FE17::from(3), + FE17::from(4), + FE17::from(1), + FE17::from(6), + FE17::from(7), + FE17::from(8), + ]; + let value_col = vec![ + FE17::from(50), + FE17::from(20), + FE17::from(30), + FE17::from(40), + FE17::from(10), + FE17::from(60), + FE17::from(70), + FE17::from(80), ]; - resize_to_next_power_of_two(&mut expected_trace); - - assert_eq!(trace.columns(), expected_trace); - } - - #[test] - fn aux_col() { - let trace = fibonacci_rap_trace([FE17::from(1), FE17::from(1)], 64); - let trace_cols = trace.columns(); - - let not_perm = trace_cols[0].clone(); - let perm = trace_cols[1].clone(); - let gamma = FE17::from(10); - - assert_eq!(perm.len(), not_perm.len()); - let trace_len = not_perm.len(); - let mut aux_col = Vec::new(); - for i in 0..trace_len { - if i == 0 { - aux_col.push(FE17::one()); - } else { - let z_i = aux_col[i - 1]; - let n_p_term = not_perm[i - 1] + gamma; - let p_term = perm[i - 1] + gamma; - - aux_col.push(z_i * n_p_term.div(p_term)); - } - } + let sorted_trace = sort_rap_trace(address_col.clone(), value_col.clone()); + + let expected_sorted_addresses = vec![ + FE17::from(1), + FE17::from(2), + FE17::from(3), + FE17::from(4), + FE17::from(5), + FE17::from(6), + FE17::from(7), + FE17::from(8), + ]; + let expected_sorted_values = vec![ + FE17::from(10), + FE17::from(20), + FE17::from(30), + FE17::from(40), + FE17::from(50), + FE17::from(60), + FE17::from(70), + FE17::from(80), + ]; - assert_eq!(aux_col.last().unwrap(), &FE17::one()); + assert_eq!(sorted_trace.columns_main()[2], expected_sorted_addresses); + assert_eq!(sorted_trace.columns_main()[3], expected_sorted_values); } } From e25efde96ec35a474b29231125b158eae27d65ef Mon Sep 17 00:00:00 2001 From: Nicole Date: Thu, 14 Nov 2024 18:32:10 -0300 Subject: [PATCH 09/15] add integration test --- .../stark/src/examples/read_only_memory.rs | 1 + provers/stark/src/tests/integration_tests.rs | 47 +++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/provers/stark/src/examples/read_only_memory.rs b/provers/stark/src/examples/read_only_memory.rs index 9d41d6d98..1dca83f37 100644 --- a/provers/stark/src/examples/read_only_memory.rs +++ b/provers/stark/src/examples/read_only_memory.rs @@ -214,6 +214,7 @@ where Box>, > = vec![ Box::new(ContinuityConstraint::new()), + Box::new(SingleValueConstraint::new()), Box::new(PermutationConstraint::new()), ]; diff --git a/provers/stark/src/tests/integration_tests.rs b/provers/stark/src/tests/integration_tests.rs index c7f2f6a4c..08604bfc2 100644 --- a/provers/stark/src/tests/integration_tests.rs +++ b/provers/stark/src/tests/integration_tests.rs @@ -10,6 +10,7 @@ use crate::{ fibonacci_2_columns::{self, Fibonacci2ColsAIR}, fibonacci_rap::{fibonacci_rap_trace, FibonacciRAP, FibonacciRAPPublicInputs}, quadratic_air::{self, QuadraticAIR, QuadraticPublicInputs}, + read_only_memory::{sort_rap_trace, ReadOnlyPublicInputs, ReadOnlyRAP}, simple_fibonacci::{self, FibonacciAIR, FibonacciPublicInputs}, simple_periodic_cols::{self, SimplePeriodicAIR, SimplePeriodicPublicInputs}, // simple_periodic_cols::{self, SimplePeriodicAIR, SimplePeriodicPublicInputs}, }, @@ -247,3 +248,49 @@ fn test_prove_bit_flags() { StoneProverTranscript::new(&[]), )); } + +#[test_log::test] +fn test_prove_read_only_memory() { + let address_col = vec![ + FieldElement::::from(4), + FieldElement::::from(5), + FieldElement::::from(2), + FieldElement::::from(6), + FieldElement::::from(8), + FieldElement::::from(7), + FieldElement::::from(1), + FieldElement::::from(3), + ]; + let value_col = vec![ + FieldElement::::from(1), + FieldElement::::from(2), + FieldElement::::from(3), + FieldElement::::from(4), + FieldElement::::from(5), + FieldElement::::from(6), + FieldElement::::from(7), + FieldElement::::from(8), + ]; + + let pub_inputs = ReadOnlyPublicInputs { + a0: FieldElement::::from(4), + v0: FieldElement::::from(1), + a_perm0: FieldElement::::from(1), + v_perm0: FieldElement::::from(7), + }; + let mut trace = sort_rap_trace(address_col, value_col); + let proof_options = ProofOptions::default_test_options(); + let proof = Prover::>::prove( + &mut trace, + &pub_inputs, + &proof_options, + StoneProverTranscript::new(&[]), + ) + .unwrap(); + assert!(Verifier::>::verify( + &proof, + &pub_inputs, + &proof_options, + StoneProverTranscript::new(&[]) + )); +} From b975d36093b4a8049fd038e7308f91146d69d7fe Mon Sep 17 00:00:00 2001 From: Joaquin Carletti Date: Fri, 15 Nov 2024 11:36:25 -0300 Subject: [PATCH 10/15] fix clippy --- provers/stark/src/examples/read_only_memory.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/provers/stark/src/examples/read_only_memory.rs b/provers/stark/src/examples/read_only_memory.rs index 1dca83f37..5f76559ae 100644 --- a/provers/stark/src/examples/read_only_memory.rs +++ b/provers/stark/src/examples/read_only_memory.rs @@ -1,4 +1,4 @@ -use std::{marker::PhantomData, ops::Div}; +use std::marker::PhantomData; use crate::{ constraints::{ @@ -15,7 +15,6 @@ use lambdaworks_crypto::fiat_shamir::is_transcript::IsTranscript; use lambdaworks_math::field::traits::IsPrimeField; use lambdaworks_math::{ field::{element::FieldElement, traits::IsFFTField}, - helpers::resize_to_next_power_of_two, traits::ByteConversion, }; @@ -297,7 +296,7 @@ where // Auxiliary boundary constraints let num = z - (a0 + alpha * v0); let den = z - (a_perm0 + alpha * v_perm0); - let p0_value = (num / den); + let p0_value = num / den; let c_aux1 = BoundaryConstraint::new_aux(0, 0, p0_value); let c_aux2 = BoundaryConstraint::new_aux( 0, From ca1fe3d46db49575745f6487b0a2fed1ae4bd26f Mon Sep 17 00:00:00 2001 From: Joaquin Carletti Date: Fri, 15 Nov 2024 12:21:21 -0300 Subject: [PATCH 11/15] fix constraints --- provers/stark/src/examples/read_only_memory.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/provers/stark/src/examples/read_only_memory.rs b/provers/stark/src/examples/read_only_memory.rs index 5f76559ae..ac6e84447 100644 --- a/provers/stark/src/examples/read_only_memory.rs +++ b/provers/stark/src/examples/read_only_memory.rs @@ -159,8 +159,8 @@ where // Auxiliary constraints let p0 = first_step.get_aux_evaluation_element(0, 0); let p1 = second_step.get_aux_evaluation_element(0, 0); - let alpha = &rap_challenges[0]; - let z = &rap_challenges[1]; + let z = &rap_challenges[0]; + let alpha = &rap_challenges[1]; let a1 = second_step.get_main_evaluation_element(0, 0); let v1 = second_step.get_main_evaluation_element(0, 1); let a_perm_1 = second_step.get_main_evaluation_element(0, 2); @@ -285,8 +285,9 @@ where let v0 = &self.pub_inputs.v0; let a_perm0 = &self.pub_inputs.a_perm0; let v_perm0 = &self.pub_inputs.v_perm0; - let alpha = &rap_challenges[0]; - let z = &rap_challenges[1]; + let z = &rap_challenges[0]; + let alpha = &rap_challenges[1]; + // Main boundary constraints let c1 = BoundaryConstraint::new_main(0, 0, a0.clone()); let c2 = BoundaryConstraint::new_main(1, 0, v0.clone()); @@ -297,6 +298,7 @@ where let num = z - (a0 + alpha * v0); let den = z - (a_perm0 + alpha * v_perm0); let p0_value = num / den; + let c_aux1 = BoundaryConstraint::new_aux(0, 0, p0_value); let c_aux2 = BoundaryConstraint::new_aux( 0, From cceb719d572a7c90842f41784a57c11c3e8ab512 Mon Sep 17 00:00:00 2001 From: Nicole Date: Fri, 15 Nov 2024 18:02:18 -0300 Subject: [PATCH 12/15] add documentation --- .../stark/src/examples/read_only_memory.rs | 63 +++++++++++-------- provers/stark/src/tests/integration_tests.rs | 40 ++++++------ 2 files changed, 56 insertions(+), 47 deletions(-) diff --git a/provers/stark/src/examples/read_only_memory.rs b/provers/stark/src/examples/read_only_memory.rs index ac6e84447..edc5a1d6f 100644 --- a/provers/stark/src/examples/read_only_memory.rs +++ b/provers/stark/src/examples/read_only_memory.rs @@ -18,6 +18,8 @@ use lambdaworks_math::{ traits::ByteConversion, }; +/// This condition ensures the continuity in a read-only memory structure, preserving strict ordering. +/// Equation based on Cairo Whitepaper section 9.7.2 #[derive(Clone)] struct ContinuityConstraint { phantom: PhantomData, @@ -44,7 +46,7 @@ where } fn end_exemptions(&self) -> usize { - // NOTE: We are assuming that hte trace has as length a power of 2. + // NOTE: We are assuming that the trace has as length a power of 2. 1 } @@ -58,15 +60,18 @@ where let first_step = frame.get_evaluation_step(0); let second_step = frame.get_evaluation_step(1); - let a_perm0 = first_step.get_main_evaluation_element(0, 2); - let a_perm1 = second_step.get_main_evaluation_element(0, 2); - let res = (a_perm1 - a_perm0) * (a_perm1 - a_perm0 - FieldElement::::one()); + let a_sorted0 = first_step.get_main_evaluation_element(0, 2); + let a_sorted1 = second_step.get_main_evaluation_element(0, 2); + // (a'_{i+1} - a'_i)(a'_{i+1} - a'_i - 1) = 0 where a' is the sorted address + let res = (a_sorted1 - a_sorted0) * (a_sorted1 - a_sorted0 - FieldElement::::one()); transition_evaluations[self.constraint_idx()] = res; } } #[derive(Clone)] +/// Transition constraint that ensures that same addresses have same values, making the memory read-only. +/// Equation based on Cairo Whitepaper section 9.7.2 struct SingleValueConstraint { phantom: PhantomData, } @@ -92,7 +97,7 @@ where } fn end_exemptions(&self) -> usize { - // NOTE: We are assuming that hte trace has as length a power of 2. + // NOTE: We are assuming that the trace has as length a power of 2. 1 } @@ -106,16 +111,18 @@ where let first_step = frame.get_evaluation_step(0); let second_step = frame.get_evaluation_step(1); - let a_perm0 = first_step.get_main_evaluation_element(0, 2); - let a_perm1 = second_step.get_main_evaluation_element(0, 2); - let v_perm0 = first_step.get_main_evaluation_element(0, 3); - let v_perm1 = second_step.get_main_evaluation_element(0, 3); - - let res = (v_perm1 - v_perm0) * (a_perm1 - a_perm0 - FieldElement::::one()); + let a_sorted0 = first_step.get_main_evaluation_element(0, 2); + let a_sorted1 = second_step.get_main_evaluation_element(0, 2); + let v_sorted0 = first_step.get_main_evaluation_element(0, 3); + let v_sorted1 = second_step.get_main_evaluation_element(0, 3); + // (v'_{i+1} - v'_i) * (a'_{i+1} - a'_i - 1) = 0 + let res = (v_sorted1 - v_sorted0) * (a_sorted1 - a_sorted0 - FieldElement::::one()); transition_evaluations[self.constraint_idx()] = res; } } +/// Permutation constraint ensures that the values are permuted in the memory. +/// Equation based on Cairo Whitepaper section 9.7.2 #[derive(Clone)] struct PermutationConstraint { @@ -163,10 +170,10 @@ where let alpha = &rap_challenges[1]; let a1 = second_step.get_main_evaluation_element(0, 0); let v1 = second_step.get_main_evaluation_element(0, 1); - let a_perm_1 = second_step.get_main_evaluation_element(0, 2); - let v_perm_1 = second_step.get_main_evaluation_element(0, 3); - - let res = (z - (a_perm_1 + alpha * v_perm_1)) * p1 - (z - (a1 + alpha * v1)) * p0; + let a_sorted_1 = second_step.get_main_evaluation_element(0, 2); + let v_sorted_1 = second_step.get_main_evaluation_element(0, 3); + // (z - (a'_{i+1} + α * v'_{i+1})) * p_{i+1} = (z - (a_{i+1} + α * v_{i+1})) * p_i + let res = (z - (a_sorted_1 + alpha * v_sorted_1)) * p1 - (z - (a1 + alpha * v1)) * p0; transition_evaluations[self.constraint_idx()] = res; } @@ -189,8 +196,8 @@ where { pub a0: FieldElement, pub v0: FieldElement, - pub a_perm0: FieldElement, - pub v_perm0: FieldElement, + pub a_sorted0: FieldElement, + pub v_sorted0: FieldElement, } impl AIR for ReadOnlyRAP @@ -240,8 +247,8 @@ where let main_segment_cols = trace.columns_main(); let a = &main_segment_cols[0]; let v = &main_segment_cols[1]; - let a_perm = &main_segment_cols[2]; - let v_perm = &main_segment_cols[3]; + let a_sorted = &main_segment_cols[2]; + let v_sorted = &main_segment_cols[3]; let z = &challenges[0]; let alpha = &challenges[1]; @@ -249,12 +256,12 @@ where let mut aux_col = Vec::new(); let num = z - (&a[0] + alpha * &v[0]); - let den = z - (&a_perm[0] + alpha * &v_perm[0]); + let den = z - (&a_sorted[0] + alpha * &v_sorted[0]); aux_col.push(num / den); - + // Apply the same equation given in the permutation case to the rest of the trace for i in 0..trace_len - 1 { let num = (z - (&a[i + 1] + alpha * &v[i + 1])) * &aux_col[i]; - let den = z - (&a_perm[i + 1] + alpha * &v_perm[i + 1]); + let den = z - (&a_sorted[i + 1] + alpha * &v_sorted[i + 1]); aux_col.push(num / den); } @@ -283,20 +290,20 @@ where ) -> BoundaryConstraints { let a0 = &self.pub_inputs.a0; let v0 = &self.pub_inputs.v0; - let a_perm0 = &self.pub_inputs.a_perm0; - let v_perm0 = &self.pub_inputs.v_perm0; + let a_sorted0 = &self.pub_inputs.a_sorted0; + let v_sorted0 = &self.pub_inputs.v_sorted0; let z = &rap_challenges[0]; let alpha = &rap_challenges[1]; // Main boundary constraints let c1 = BoundaryConstraint::new_main(0, 0, a0.clone()); let c2 = BoundaryConstraint::new_main(1, 0, v0.clone()); - let c3 = BoundaryConstraint::new_main(2, 0, a_perm0.clone()); - let c4 = BoundaryConstraint::new_main(3, 0, v_perm0.clone()); + let c3 = BoundaryConstraint::new_main(2, 0, a_sorted0.clone()); + let c4 = BoundaryConstraint::new_main(3, 0, v_sorted0.clone()); // Auxiliary boundary constraints let num = z - (a0 + alpha * v0); - let den = z - (a_perm0 + alpha * v_perm0); + let den = z - (a_sorted0 + alpha * v_sorted0); let p0_value = num / den; let c_aux1 = BoundaryConstraint::new_aux(0, 0, p0_value); @@ -341,6 +348,8 @@ where } } +/// Given the adress and value columns, it returns the trace table with 5 columns, which are: +/// Addres, Value, Adress Sorted, Value Sorted and a Column of Zeroes (where we'll insert the auxiliary colunn). pub fn sort_rap_trace( address: Vec>, value: Vec>, diff --git a/provers/stark/src/tests/integration_tests.rs b/provers/stark/src/tests/integration_tests.rs index 08604bfc2..7513caad0 100644 --- a/provers/stark/src/tests/integration_tests.rs +++ b/provers/stark/src/tests/integration_tests.rs @@ -252,31 +252,31 @@ fn test_prove_bit_flags() { #[test_log::test] fn test_prove_read_only_memory() { let address_col = vec![ - FieldElement::::from(4), - FieldElement::::from(5), - FieldElement::::from(2), - FieldElement::::from(6), - FieldElement::::from(8), - FieldElement::::from(7), - FieldElement::::from(1), - FieldElement::::from(3), + FieldElement::::from(3), // a0 + FieldElement::::from(2), // a1 + FieldElement::::from(2), // a2 + FieldElement::::from(3), // a3 + FieldElement::::from(4), // a4 + FieldElement::::from(5), // a5 + FieldElement::::from(1), // a6 + FieldElement::::from(3), // a7 ]; let value_col = vec![ - FieldElement::::from(1), - FieldElement::::from(2), - FieldElement::::from(3), - FieldElement::::from(4), - FieldElement::::from(5), - FieldElement::::from(6), - FieldElement::::from(7), - FieldElement::::from(8), + FieldElement::::from(10), // v0 + FieldElement::::from(5), // v1 + FieldElement::::from(5), // v2 + FieldElement::::from(10), // v3 + FieldElement::::from(25), // v4 + FieldElement::::from(25), // v5 + FieldElement::::from(7), // v6 + FieldElement::::from(10), // v7 ]; let pub_inputs = ReadOnlyPublicInputs { - a0: FieldElement::::from(4), - v0: FieldElement::::from(1), - a_perm0: FieldElement::::from(1), - v_perm0: FieldElement::::from(7), + a0: FieldElement::::from(3), + v0: FieldElement::::from(10), + a_sorted0: FieldElement::::from(1), // a6 + v_sorted0: FieldElement::::from(7), // v6 }; let mut trace = sort_rap_trace(address_col, value_col); let proof_options = ProofOptions::default_test_options(); From 57241311981792918a26ba935532aad2a94e337a Mon Sep 17 00:00:00 2001 From: Joaquin Carletti Date: Thu, 21 Nov 2024 10:57:44 -0300 Subject: [PATCH 13/15] handle possible panic --- provers/stark/src/examples/read_only_memory.rs | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/provers/stark/src/examples/read_only_memory.rs b/provers/stark/src/examples/read_only_memory.rs index edc5a1d6f..1c93802b0 100644 --- a/provers/stark/src/examples/read_only_memory.rs +++ b/provers/stark/src/examples/read_only_memory.rs @@ -65,7 +65,10 @@ where // (a'_{i+1} - a'_i)(a'_{i+1} - a'_i - 1) = 0 where a' is the sorted address let res = (a_sorted1 - a_sorted0) * (a_sorted1 - a_sorted0 - FieldElement::::one()); - transition_evaluations[self.constraint_idx()] = res; + // The eval always exists, except if the constraint idx were incorrectly defined. + if let Some(eval) = transition_evaluations.get_mut(self.constraint_idx()) { + *eval = res; + } } } @@ -118,7 +121,10 @@ where // (v'_{i+1} - v'_i) * (a'_{i+1} - a'_i - 1) = 0 let res = (v_sorted1 - v_sorted0) * (a_sorted1 - a_sorted0 - FieldElement::::one()); - transition_evaluations[self.constraint_idx()] = res; + // The eval always exists, except if the constraint idx were incorrectly defined. + if let Some(eval) = transition_evaluations.get_mut(self.constraint_idx()) { + *eval = res; + } } } /// Permutation constraint ensures that the values are permuted in the memory. @@ -175,7 +181,10 @@ where // (z - (a'_{i+1} + α * v'_{i+1})) * p_{i+1} = (z - (a_{i+1} + α * v_{i+1})) * p_i let res = (z - (a_sorted_1 + alpha * v_sorted_1)) * p1 - (z - (a1 + alpha * v1)) * p0; - transition_evaluations[self.constraint_idx()] = res; + // The eval always exists, except if the constraint idx were incorrectly defined. + if let Some(eval) = transition_evaluations.get_mut(self.constraint_idx()) { + *eval = res; + } } } From 0fc7284c1bb4566b7557ffc2f88a329662bb3e6f Mon Sep 17 00:00:00 2001 From: jotabulacios Date: Thu, 21 Nov 2024 11:09:39 -0300 Subject: [PATCH 14/15] rename variables --- provers/stark/src/examples/read_only_memory.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/provers/stark/src/examples/read_only_memory.rs b/provers/stark/src/examples/read_only_memory.rs index 1c93802b0..95526c9c3 100644 --- a/provers/stark/src/examples/read_only_memory.rs +++ b/provers/stark/src/examples/read_only_memory.rs @@ -60,10 +60,10 @@ where let first_step = frame.get_evaluation_step(0); let second_step = frame.get_evaluation_step(1); - let a_sorted0 = first_step.get_main_evaluation_element(0, 2); - let a_sorted1 = second_step.get_main_evaluation_element(0, 2); + let a_sorted_0 = first_step.get_main_evaluation_element(0, 2); + let a_sorted_1 = second_step.get_main_evaluation_element(0, 2); // (a'_{i+1} - a'_i)(a'_{i+1} - a'_i - 1) = 0 where a' is the sorted address - let res = (a_sorted1 - a_sorted0) * (a_sorted1 - a_sorted0 - FieldElement::::one()); + let res = (a_sorted_1 - a_sorted_0) * (a_sorted_1 - a_sorted_0 - FieldElement::::one()); // The eval always exists, except if the constraint idx were incorrectly defined. if let Some(eval) = transition_evaluations.get_mut(self.constraint_idx()) { From 59c8b2681bf85c79d3bd5c484569d4ceb3a63612 Mon Sep 17 00:00:00 2001 From: Nicole Date: Mon, 25 Nov 2024 14:59:02 -0300 Subject: [PATCH 15/15] fix doc --- provers/stark/src/examples/read_only_memory.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/provers/stark/src/examples/read_only_memory.rs b/provers/stark/src/examples/read_only_memory.rs index 95526c9c3..8b5b01b07 100644 --- a/provers/stark/src/examples/read_only_memory.rs +++ b/provers/stark/src/examples/read_only_memory.rs @@ -71,10 +71,9 @@ where } } } - -#[derive(Clone)] /// Transition constraint that ensures that same addresses have same values, making the memory read-only. /// Equation based on Cairo Whitepaper section 9.7.2 +#[derive(Clone)] struct SingleValueConstraint { phantom: PhantomData, } @@ -129,7 +128,6 @@ where } /// Permutation constraint ensures that the values are permuted in the memory. /// Equation based on Cairo Whitepaper section 9.7.2 - #[derive(Clone)] struct PermutationConstraint { phantom: PhantomData,