diff --git a/src/air/traces.cairo b/src/air/traces.cairo index b2f0659a4..313708043 100644 --- a/src/air/traces.cairo +++ b/src/air/traces.cairo @@ -36,7 +36,7 @@ struct TracesCommitment { // Responses for queries to the AIR commitment. // The queries are usually generated by the next component down the line (e.g. FRI). -#[derive(Drop)] +#[derive(Drop, Copy)] struct TracesDecommitment { // Responses for queries to the original trace. original: TableDecommitment, @@ -45,7 +45,7 @@ struct TracesDecommitment { } // A witness for a decommitment of the AIR traces over queries. -#[derive(Drop)] +#[derive(Drop, Copy)] struct TracesWitness { original: TableCommitmentWitness, interaction: TableCommitmentWitness, diff --git a/src/deserialization.cairo b/src/deserialization.cairo index 8109743e9..caf18e069 100644 --- a/src/deserialization.cairo +++ b/src/deserialization.cairo @@ -3,3 +3,4 @@ mod pow; mod stark; mod traces; mod vector; +mod table; diff --git a/src/deserialization/table.cairo b/src/deserialization/table.cairo new file mode 100644 index 000000000..86070689b --- /dev/null +++ b/src/deserialization/table.cairo @@ -0,0 +1,39 @@ +use cairo_verifier::table_commitment::table_commitment::{ + TableCommitmentConfig, TableCommitmentWitness, TableDecommitment +}; +use cairo_verifier::deserialization::vector::{ + VectorCommitmentConfigWithSerde, VectorCommitmentWitnessWithSerde +}; + +#[derive(Drop, Serde)] +struct TableCommitmentConfigWithSerde { + n_columns: felt252, + vector: VectorCommitmentConfigWithSerde, +} + +impl IntoTableCommitmentConfig of Into { + fn into(self: TableCommitmentConfigWithSerde) -> TableCommitmentConfig { + TableCommitmentConfig { n_columns: self.n_columns, vector: self.vector.into(), } + } +} + +#[derive(Drop, Serde)] +struct TableDecommitmentWithSerde { + n_values: felt252, + values: Array, +} +impl IntoTableDecommitment of Into { + fn into(self: TableDecommitmentWithSerde) -> TableDecommitment { + TableDecommitment { values: self.values.span(), } + } +} + +#[derive(Drop, Serde)] +struct TableCommitmentWitnessWithSerde { + vector: VectorCommitmentWitnessWithSerde, +} +impl IntoTableCommitmentWitness of Into { + fn into(self: TableCommitmentWitnessWithSerde) -> TableCommitmentWitness { + TableCommitmentWitness { vector: self.vector.into(), } + } +} diff --git a/src/deserialization/traces.cairo b/src/deserialization/traces.cairo index d3bd2a5df..073e7255d 100644 --- a/src/deserialization/traces.cairo +++ b/src/deserialization/traces.cairo @@ -1,3 +1,4 @@ +use core::traits::Into; use cairo_verifier::{ air::{ traces_config::TracesConfig, @@ -7,6 +8,10 @@ use cairo_verifier::{ vector::{ VectorCommitmentConfig, VectorCommitmentWitness, VectorCommitmentConfigWithSerde, VectorCommitmentWitnessWithSerde + }, + table::{ + TableCommitmentConfigWithSerde, TableDecommitmentWithSerde, + TableCommitmentWitnessWithSerde, } }, table_commitment::table_commitment::{ @@ -25,17 +30,6 @@ impl IntoTracesConfig of Into { } } -#[derive(Drop, Serde)] -struct TableCommitmentConfigWithSerde { - n_columns: felt252, - vector: VectorCommitmentConfigWithSerde, -} -impl IntoTableCommitmentConfig of Into { - fn into(self: TableCommitmentConfigWithSerde) -> TableCommitmentConfig { - TableCommitmentConfig { n_columns: self.n_columns, vector: self.vector.into(), } - } -} - #[derive(Drop, Serde)] struct TracesDecommitmentWithSerde { original: TableDecommitmentWithSerde, @@ -58,17 +52,6 @@ impl IntoTracesUnsentCommitment of Into, -} -impl IntoTableDecommitment of Into { - fn into(self: TableDecommitmentWithSerde) -> TableDecommitment { - TableDecommitment { values: self.values.span(), } - } -} - #[derive(Drop, Serde)] struct TracesWitnessWithSerde { original: TableCommitmentWitnessWithSerde, @@ -80,12 +63,3 @@ impl IntoTracesWitness of Into { } } -#[derive(Drop, Serde)] -struct TableCommitmentWitnessWithSerde { - vector: VectorCommitmentWitnessWithSerde, -} -impl IntoTableCommitmentWitness of Into { - fn into(self: TableCommitmentWitnessWithSerde) -> TableCommitmentWitness { - TableCommitmentWitness { vector: self.vector.into(), } - } -} diff --git a/src/queries/queries.cairo b/src/queries/queries.cairo index f62d47a82..adf84f7be 100644 --- a/src/queries/queries.cairo +++ b/src/queries/queries.cairo @@ -2,7 +2,8 @@ use cairo_verifier::{ channel::channel::{Channel, ChannelTrait}, common::{ merge_sort::merge_sort, math::pow, consts::FIELD_GENERATOR, bit_reverse::BitReverseTrait - } + }, + domains::StarkDomains }; // 2^64 = 18446744073709551616 @@ -86,17 +87,15 @@ fn usort(input: Array) -> Array { result } -fn queries_to_points( - queries: Span, log_eval_domain_size: u8, eval_generator: felt252 -) -> Array { +fn queries_to_points(queries: Span, stark_domains: @StarkDomains) -> Array { let mut points = ArrayTrait::::new(); // Evaluation domains of size greater than 2**64 are not supported - assert(log_eval_domain_size <= 64, 'Eval domain too big'); + assert((*stark_domains.log_eval_domain_size).into() <= 64_u256, 'Eval domain too big'); // A 'log_eval_domain_size' bits index can be bit reversed using bit_reverse_u64 if it is // multiplied by 2**(64 - log_eval_domain_size) first. - let shift = pow(2, 64 - log_eval_domain_size.into()); + let shift = pow(2, 64 - (*stark_domains.log_eval_domain_size).into()); let mut i: u32 = 0; loop { @@ -108,7 +107,10 @@ fn queries_to_points( // Compute the x value of the query in the evaluation domain coset: // FIELD_GENERATOR * eval_generator ^ reversed_index. - points.append(FIELD_GENERATOR * pow(eval_generator, index.bit_reverse().into())); + points + .append( + FIELD_GENERATOR * pow(*stark_domains.eval_generator, index.bit_reverse().into()) + ); }; points } diff --git a/src/stark.cairo b/src/stark.cairo index 443e5ed70..fc6175b7a 100644 --- a/src/stark.cairo +++ b/src/stark.cairo @@ -1,12 +1,15 @@ use cairo_verifier::{ air::{ traces_config::{TracesConfig, TracesConfigTrait}, public_input::PublicInput, - traces::{TracesUnsentCommitment, TracesDecommitment, TracesWitness} + traces::{TracesUnsentCommitment, TracesCommitment, TracesDecommitment, TracesWitness} + }, + fri::{ + fri_config::{FriConfig, FriConfigTrait}, + fri::{FriUnsentCommitment, FriWitness, FriCommitment} }, - fri::{fri_config::{FriConfig, FriConfigTrait}, fri::{FriUnsentCommitment, FriWitness}}, domains::StarkDomainsImpl, table_commitment::table_commitment::{ - TableCommitmentConfig, TableCommitmentWitness, TableDecommitment + TableCommitmentConfig, TableCommitmentWitness, TableDecommitment, TableCommitment }, proof_of_work::{ config::{ProofOfWorkConfig, ProofOfWorkConfigTrait}, @@ -74,16 +77,63 @@ impl StarkConfigImpl of StarkConfigTrait { } } +// Protocol components: +// ====================== +// The verifier is built from protocol components. Each component is responsible for commitment +// and decommitment phase. The decommitment part can be regarded as proving a statement with certain +// parameters that are known only after the commitment phase. The XDecommitment struct holds these +// parameters. +// The XWitness struct is the witness required to prove this statement. +// +// For example, VectorDecommitment holds some indices to the committed vector and the corresponding +// values. +// The VectorWitness struct has the authentication paths of the merkle tree, required to prove the +// validity of the values. +// +// The Stark protocol itself is a component, with the statement having no parameters known only +// after the commitment phase, and thus, there is no StarkDecommitment. +// +// The interface of a component named X is: +// +// Structs: +// * XConfig: Configuration for the component. +// * XUnsentCommitment: Commitment values (e.g. hashes), before sending in the channel. +// Those values shouldn't be used directly (only by the channel). +// Used by x_commit() to generate a commitment XCommitment. +// * XCommitment: Represents the commitment after it is read from the channel. +// * XDecommitment: Responses for queries. +// * XWitness: Auxiliary information for proving the decommitment. +// +// Functions: +// * x_commit() - The commitment phase. Takes XUnsentCommitment and returns XCommitment. +// * x_decommit() - The decommitment phase. Verifies a decommitment. Uses the commitment and the +// witness. + +// n_oods_values := air.mask_size + air.constraint_degree. + #[derive(Drop)] struct StarkUnsentCommitment { traces: TracesUnsentCommitment, composition: felt252, + // n_oods_values elements. The i-th value is the evaluation of the i-th mask item polynomial at + // the OODS point, where the mask item polynomial is the interpolation polynomial of the + // corresponding column shifted by the corresponding row_offset. oods_values: Span, fri: FriUnsentCommitment, proof_of_work: ProofOfWorkUnsentCommitment, } #[derive(Drop)] +struct StarkCommitment { + traces: TracesCommitment, + composition: TableCommitment, + interaction_after_composition: felt252, + oods_values: Span, + interaction_after_oods: Span, + fri: FriCommitment, +} + +#[derive(Drop, Copy)] struct StarkWitness { traces_decommitment: TracesDecommitment, traces_witness: TracesWitness, diff --git a/src/stark/stark_verify.cairo b/src/stark/stark_verify.cairo index 8b1378917..cf3de5068 100644 --- a/src/stark/stark_verify.cairo +++ b/src/stark/stark_verify.cairo @@ -1 +1,60 @@ +use core::array::ArrayTrait; +use cairo_verifier::{ + queries::queries::queries_to_points, domains::StarkDomains, + fri::fri::{FriDecommitment, fri_verify}, + stark::{StarkUnsentCommitment, StarkWitness, StarkCommitment}, air::traces::traces_decommit, + table_commitment::table_commitment::table_decommit, + oods::{OodsEvaluationInfo, eval_oods_boundary_poly_at_points}, +}; +// STARK decommitment phase. +fn stark_verify( + n_original_columns: u32, + n_interaction_columns: u32, + queries: Span, + commitment: StarkCommitment, + witness: StarkWitness, + stark_domains: StarkDomains, +) { + // First layer decommit. + traces_decommit( + queries, commitment.traces, witness.traces_decommitment, witness.traces_witness + ); + + table_decommit( + commitment.composition, + queries, + witness.composition_decommitment, + witness.composition_witness, + ); + + // Compute query points. + let points = queries_to_points(queries, @stark_domains); + + // Evaluate the FRI input layer at query points. + let eval_info = OodsEvaluationInfo { + oods_values: commitment.oods_values, + oods_point: commitment.interaction_after_composition, + trace_generator: stark_domains.trace_generator, + constraint_coefficients: commitment.interaction_after_oods, + }; + let oods_poly_evals = eval_oods_boundary_poly_at_points( + n_original_columns, + n_interaction_columns, + eval_info, + points.span(), + witness.traces_decommitment, + witness.composition_decommitment, + ); + + // Decommit FRI. + let fri_decommitment = FriDecommitment { + values: oods_poly_evals.span(), points: points.span(), + }; + fri_verify( + queries: queries, + commitment: commitment.fri, + decommitment: fri_decommitment, + witness: witness.fri_witness, + ) +}