diff --git a/triton-vm/src/fri_domain.rs b/triton-vm/src/arithmetic_domain.rs similarity index 61% rename from triton-vm/src/fri_domain.rs rename to triton-vm/src/arithmetic_domain.rs index 5b918a327..92fe39544 100644 --- a/triton-vm/src/fri_domain.rs +++ b/triton-vm/src/arithmetic_domain.rs @@ -1,71 +1,75 @@ use std::marker::PhantomData; -use std::ops::MulAssign; +use std::ops::{Mul, MulAssign}; use twenty_first::shared_math::b_field_element::BFieldElement; use twenty_first::shared_math::polynomial::Polynomial; use twenty_first::shared_math::traits::{FiniteField, ModPowU32}; #[derive(Debug, Clone, PartialEq, Eq)] -pub struct FriDomain { +pub struct ArithmeticDomain { pub offset: BFieldElement, - pub omega: BFieldElement, + pub generator: BFieldElement, pub length: usize, - _field: PhantomData, + _finite_field: PhantomData, } -impl FriDomain +impl ArithmeticDomain where - FF: FiniteField + From + MulAssign, + FF: FiniteField + + From + + Mul + + MulAssign, { - pub fn new(offset: BFieldElement, omega: BFieldElement, length: usize) -> Self { - let _field = PhantomData; + pub fn new(offset: BFieldElement, generator: BFieldElement, length: usize) -> Self { Self { offset, - omega, + generator, length, - _field, + _finite_field: PhantomData, } } - pub fn evaluate(&self, polynomial: &Polynomial) -> Vec { - polynomial.fast_coset_evaluate(&self.offset, self.omega, self.length) + pub fn evaluate(&self, polynomial: &Polynomial) -> Vec + where + GF: FiniteField + From + MulAssign, + { + polynomial.fast_coset_evaluate(&self.offset, self.generator, self.length) } - pub fn interpolate(&self, values: &[FF]) -> Polynomial { - Polynomial::::fast_coset_interpolate(&self.offset, self.omega, values) + pub fn interpolate(&self, values: &[GF]) -> Polynomial + where + GF: FiniteField + From + MulAssign, + { + Polynomial::::fast_coset_interpolate(&self.offset, self.generator, values) } pub fn domain_value(&self, index: u32) -> FF { - let domain_value: BFieldElement = self.omega.mod_pow_u32(index) * self.offset; + let domain_value = self.generator.mod_pow_u32(index) * self.offset; domain_value.into() } pub fn domain_values(&self) -> Vec { - let mut res = Vec::with_capacity(self.length); - let mut acc = FF::one(); + let mut accumulator = FF::one(); + let mut domain_values = Vec::with_capacity(self.length); for _ in 0..self.length { - let domain_value = { - let mut tmp = acc; - tmp *= self.offset; - tmp - }; - res.push(domain_value); - acc *= self.omega; + domain_values.push(accumulator * self.offset); + accumulator *= self.generator; } - res + domain_values } } #[cfg(test)] -mod fri_domain_tests { - use super::*; +mod domain_tests { use itertools::Itertools; use twenty_first::shared_math::b_field_element::BFieldElement; use twenty_first::shared_math::traits::PrimitiveRootOfUnity; use twenty_first::shared_math::x_field_element::XFieldElement; + use super::*; + #[test] fn domain_values_test() { // f(x) = x^3 @@ -73,24 +77,26 @@ mod fri_domain_tests { let poly = Polynomial::::new(x_squared_coefficients.clone()); for order in [4, 8, 32] { - let omega = BFieldElement::primitive_root_of_unity(order).unwrap(); + let generator = BFieldElement::primitive_root_of_unity(order).unwrap(); let offset = BFieldElement::generator(); - let b_domain = FriDomain::::new(offset, omega, order as usize); - let x_domain = FriDomain::::new(offset, omega, order as usize); + let b_domain = + ArithmeticDomain::::new(offset, generator, order as usize); + let x_domain = + ArithmeticDomain::::new(offset, generator, order as usize); let expected_b_values: Vec = - (0..order).map(|i| offset * omega.mod_pow(i)).collect(); + (0..order).map(|i| offset * generator.mod_pow(i)).collect(); let actual_b_values_1 = b_domain.domain_values(); let actual_b_values_2 = (0..order as u32) .map(|i| b_domain.domain_value(i)) .collect_vec(); assert_eq!( expected_b_values, actual_b_values_1, - "domain_values() generates the FRI domain BFieldElement values" + "domain_values() generates the arithmetic domain's BFieldElement values" ); assert_eq!( expected_b_values, actual_b_values_2, - "domain_value() generates the given FRI domain BFieldElement value" + "domain_value() generates the given domain BFieldElement value" ); let expected_x_values: Vec = @@ -101,11 +107,11 @@ mod fri_domain_tests { .collect_vec(); assert_eq!( expected_x_values, actual_x_values_1, - "domain_values() generates the FRI domain XFieldElement values" + "domain_values() generates the arithmetic domain's XFieldElement values" ); assert_eq!( expected_x_values, actual_x_values_2, - "domain_value() generates the given FRI domain XFieldElement values" + "domain_value() generates the given domain XFieldElement values" ); let values = b_domain.evaluate(&poly); diff --git a/triton-vm/src/cross_table_arguments.rs b/triton-vm/src/cross_table_arguments.rs index 0a73b812f..700f447fb 100644 --- a/triton-vm/src/cross_table_arguments.rs +++ b/triton-vm/src/cross_table_arguments.rs @@ -8,7 +8,7 @@ use twenty_first::shared_math::mpolynomial::Degree; use twenty_first::shared_math::traits::{FiniteField, Inverse}; use twenty_first::shared_math::x_field_element::XFieldElement; -use crate::fri_domain::FriDomain; +use crate::arithmetic_domain::ArithmeticDomain; use crate::table::processor_table::PROCESSOR_TABLE_NUM_PERMUTATION_ARGUMENTS; use crate::table::table_collection::TableId::{ HashTable, InstructionTable, JumpStackTable, OpStackTable, ProcessorTable, ProgramTable, @@ -44,18 +44,19 @@ pub trait CrossTableArg { fn terminal_quotient( &self, ext_codeword_tables: &ExtTableCollection, - fri_domain: &FriDomain, - omicron: XFieldElement, + quotient_domain: &ArithmeticDomain, + trace_domain_generator: BFieldElement, ) -> Vec { let from_codeword = self.combined_from_codeword(ext_codeword_tables); let to_codeword = self.combined_to_codeword(ext_codeword_tables); - let zerofier = fri_domain + let trace_domain_generator_inverse = trace_domain_generator.inverse(); + let zerofier = quotient_domain .domain_values() .into_iter() - .map(|x| x - omicron.inverse()) + .map(|x| x - trace_domain_generator_inverse) .collect(); - let zerofier_inverse = XFieldElement::batch_inversion(zerofier); + let zerofier_inverse = BFieldElement::batch_inversion(zerofier); zerofier_inverse .into_iter() @@ -453,10 +454,10 @@ impl GrandCrossTableArg { pub fn terminal_quotient_codeword( &self, ext_codeword_tables: &ExtTableCollection, - fri_domain: &FriDomain, - omicron: XFieldElement, + quotient_domain: &ArithmeticDomain, + trace_domain_generator: BFieldElement, ) -> Vec { - let mut non_linear_sum_codeword = vec![XFieldElement::zero(); fri_domain.length]; + let mut non_linear_sum_codeword = vec![XFieldElement::zero(); quotient_domain.length]; // cross-table arguments for (arg, weight) in self.into_iter() { @@ -472,7 +473,7 @@ impl GrandCrossTableArg { } // standard input - let input_terminal_codeword = vec![self.input_terminal; fri_domain.length]; + let input_terminal_codeword = vec![self.input_terminal; quotient_domain.length]; let (to_table, to_column) = self.input_to_processor; let to_codeword = &ext_codeword_tables.data(to_table)[to_column]; let weight = self.input_to_processor_weight; @@ -487,7 +488,7 @@ impl GrandCrossTableArg { // standard output let (from_table, from_column) = self.processor_to_output; let from_codeword = &ext_codeword_tables.data(from_table)[from_column]; - let output_terminal_codeword = vec![self.output_terminal; fri_domain.length]; + let output_terminal_codeword = vec![self.output_terminal; quotient_domain.length]; let weight = self.processor_to_output_weight; let non_linear_summand = weighted_difference_codeword(from_codeword, &output_terminal_codeword, weight); @@ -497,12 +498,13 @@ impl GrandCrossTableArg { XFieldElement::add, ); - let zerofier = fri_domain + let trace_domain_generator_inverse = trace_domain_generator.inverse(); + let zerofier = quotient_domain .domain_values() .into_iter() - .map(|x| x - omicron.inverse()) + .map(|x| x - trace_domain_generator_inverse) .collect(); - let zerofier_inverse = XFieldElement::batch_inversion(zerofier); + let zerofier_inverse = BFieldElement::batch_inversion(zerofier); zerofier_inverse .into_iter() diff --git a/triton-vm/src/fri.rs b/triton-vm/src/fri.rs index 8fecc7da4..49a536b55 100644 --- a/triton-vm/src/fri.rs +++ b/triton-vm/src/fri.rs @@ -20,7 +20,7 @@ use twenty_first::shared_math::x_field_element::XFieldElement; use twenty_first::util_types::algebraic_hasher::{AlgebraicHasher, Hashable}; use twenty_first::util_types::merkle_tree::{MerkleTree, PartialAuthenticationPath}; -use crate::fri_domain::FriDomain; +use crate::arithmetic_domain::ArithmeticDomain; use crate::proof_item::{FriResponse, ProofItem}; use crate::proof_stream::ProofStream; @@ -50,19 +50,19 @@ pub struct Fri { // nearest power of 2. pub expansion_factor: usize, pub colinearity_checks_count: usize, - pub domain: FriDomain, + pub domain: ArithmeticDomain, _hasher: PhantomData, } impl Fri { pub fn new( offset: BFieldElement, - omega: BFieldElement, + fri_domain_generator: BFieldElement, domain_length: usize, expansion_factor: usize, colinearity_checks_count: usize, ) -> Self { - let domain = FriDomain::new(offset, omega, domain_length); + let domain = ArithmeticDomain::new(offset, fri_domain_generator, domain_length); let _hasher = PhantomData; Self { domain, @@ -166,7 +166,7 @@ impl Fri { codeword: &[XFieldElement], proof_stream: &mut ProofStream, ) -> Result, MerkleTree)>, Box> { - let mut subgroup_generator = self.domain.omega; + let mut subgroup_generator = self.domain.generator; let mut offset = self.domain.offset; let mut codeword_local = codeword.to_vec(); @@ -346,9 +346,11 @@ impl Fri { let log_2_of_n = log_2_floor(last_codeword.len() as u128) as u32; let mut last_polynomial = last_codeword.clone(); - // XXX - let last_omega = self.domain.omega.mod_pow_u32(2u32.pow(num_rounds as u32)); - intt::(&mut last_polynomial, last_omega, log_2_of_n); + let last_fri_domain_generator = self + .domain + .generator + .mod_pow_u32(2u32.pow(num_rounds as u32)); + intt::(&mut last_polynomial, last_fri_domain_generator, log_2_of_n); let last_poly_degree: isize = (Polynomial:: { coefficients: last_polynomial, @@ -445,7 +447,7 @@ impl Fri { /// FRI (co-)domain. This corresponds to `ω^i` in `f(ω^i)` from /// [STARK-Anatomy](https://neptune.cash/learn/stark-anatomy/fri/#split-and-fold). fn get_evaluation_argument(&self, idx: usize, round: usize) -> XFieldElement { - let domain_value = self.domain.offset * self.domain.omega.mod_pow_u32(idx as u32); + let domain_value = self.domain.offset * self.domain.generator.mod_pow_u32(idx as u32); let round_exponent = 2u32.pow(round as u32); let evaluation_argument = domain_value.mod_pow_u32(round_exponent); @@ -574,7 +576,7 @@ mod triton_xfri_tests { let fri: Fri = get_x_field_fri_test_object(subgroup_order, expansion_factor, colinearity_check_count); let mut proof_stream: ProofStream = ProofStream::new(); - let subgroup = fri.domain.omega.lift().get_cyclic_group_elements(None); + let subgroup = fri.domain.generator.lift().get_cyclic_group_elements(None); let (_, merkle_root_of_round_0) = fri.prove(&subgroup, &mut proof_stream).unwrap(); let verdict = fri.verify(&mut proof_stream, &merkle_root_of_round_0, &mut None); @@ -616,7 +618,7 @@ mod triton_xfri_tests { let colinearity_check_count = 6; let fri: Fri = get_x_field_fri_test_object(subgroup_order, expansion_factor, colinearity_check_count); - let subgroup = fri.domain.omega.lift().get_cyclic_group_elements(None); + let subgroup = fri.domain.generator.lift().get_cyclic_group_elements(None); let mut points: Vec; for n in [1, 5, 20, 30, 31] { @@ -664,7 +666,7 @@ mod triton_xfri_tests { expansion_factor: usize, colinearity_checks: usize, ) -> Fri { - let omega = BFieldElement::primitive_root_of_unity(subgroup_order).unwrap(); + let fri_domain_generator = BFieldElement::primitive_root_of_unity(subgroup_order).unwrap(); // The following offset was picked arbitrarily by copying the one found in // `get_b_field_fri_test_object`. It does not generate the full Z_p\{0}, but @@ -673,7 +675,7 @@ mod triton_xfri_tests { let fri: Fri = Fri::new( offset, - omega, + fri_domain_generator, subgroup_order as usize, expansion_factor, colinearity_checks, diff --git a/triton-vm/src/lib.rs b/triton-vm/src/lib.rs index 38e8e4e1d..516f9002c 100644 --- a/triton-vm/src/lib.rs +++ b/triton-vm/src/lib.rs @@ -1,8 +1,8 @@ +pub mod arithmetic_domain; pub mod bfield_codec; pub mod cross_table_arguments; pub mod error; pub mod fri; -pub mod fri_domain; pub mod instruction; pub mod op_stack; pub mod ord_n; diff --git a/triton-vm/src/stark.rs b/triton-vm/src/stark.rs index 0269c4662..a81555fc4 100644 --- a/triton-vm/src/stark.rs +++ b/triton-vm/src/stark.rs @@ -21,17 +21,19 @@ use twenty_first::util_types::merkle_tree::MerkleTree; use triton_profiler::triton_profiler::TritonProfiler; use triton_profiler::{prof_itr0, prof_start, prof_stop}; +use crate::arithmetic_domain::ArithmeticDomain; use crate::cross_table_arguments::{ CrossTableArg, EvalArg, GrandCrossTableArg, NUM_CROSS_TABLE_ARGS, NUM_PUBLIC_EVAL_ARGS, }; use crate::fri::{Fri, FriValidationError}; -use crate::fri_domain::FriDomain; use crate::proof::{Claim, Proof}; use crate::proof_item::ProofItem; use crate::proof_stream::ProofStream; use crate::table::base_matrix::AlgebraicExecutionTrace; use crate::table::challenges::AllChallenges; -use crate::table::table_collection::{derive_omicron, BaseTableCollection, ExtTableCollection}; +use crate::table::table_collection::{ + derive_trace_domain_generator, BaseTableCollection, ExtTableCollection, +}; use super::table::base_matrix::BaseMatrices; @@ -108,7 +110,6 @@ pub struct Stark { parameters: StarkParameters, claim: Claim, max_degree: Degree, - fri_domain: FriDomain, fri: Fri, } @@ -119,14 +120,12 @@ impl Stark { empty_table_collection.max_degree_with_origin(parameters.num_trace_randomizers); let max_degree = (other::roundup_npo2(max_degree_with_origin.degree as u64) - 1) as i64; let fri_domain_length = parameters.fri_expansion_factor * (max_degree as usize + 1); - let omega = + let fri_domain_generator = BFieldElement::primitive_root_of_unity(fri_domain_length.try_into().unwrap()).unwrap(); let coset_offset = BFieldElement::generator(); - let fri_domain: FriDomain = - FriDomain::new(coset_offset, omega, fri_domain_length); let fri = Fri::new( coset_offset, - omega, + fri_domain_generator, fri_domain_length, parameters.fri_expansion_factor, parameters.num_colinearity_checks, @@ -135,7 +134,6 @@ impl Stark { parameters, claim, max_degree, - fri_domain, fri, } } @@ -152,13 +150,19 @@ impl Stark { let (x_rand_codeword, b_rand_codewords) = self.get_randomizer_codewords(); - prof_start!(maybe_profiler, "LDE 1"); - let base_fri_domain_tables = base_trace_tables - .to_fri_domain_tables(&self.fri_domain, self.parameters.num_trace_randomizers); + prof_start!(maybe_profiler, "dual LDE 1"); + let quotient_domain = self.quotient_domain(); + let (base_quotient_domain_tables, base_fri_domain_tables) = base_trace_tables + .to_quotient_and_fri_domain_tables( + "ient_domain, + &self.fri.domain, + self.parameters.num_trace_randomizers, + ); + let base_quotient_domain_codewords = base_quotient_domain_tables.get_all_base_columns(); let base_fri_domain_codewords = base_fri_domain_tables.get_all_base_columns(); let randomizer_and_base_fri_domain_codewords = - vec![b_rand_codewords, base_fri_domain_codewords.clone()].concat(); - prof_stop!(maybe_profiler, "LDE 1"); + vec![b_rand_codewords, base_fri_domain_codewords].concat(); + prof_stop!(maybe_profiler, "dual LDE 1"); prof_start!(maybe_profiler, "Merkle tree 1"); let transposed_base_codewords = transpose(&randomizer_and_base_fri_domain_codewords); @@ -187,12 +191,16 @@ impl Stark { ); prof_stop!(maybe_profiler, "extend"); - prof_start!(maybe_profiler, "LDE 2"); - let ext_fri_domain_tables = ext_trace_tables - .to_fri_domain_tables(&self.fri.domain, self.parameters.num_trace_randomizers); + prof_start!(maybe_profiler, "dual LDE 2"); + let (ext_quotient_domain_tables, ext_fri_domain_tables) = ext_trace_tables + .to_quotient_and_fri_domain_tables( + "ient_domain, + &self.fri.domain, + self.parameters.num_trace_randomizers, + ); + let extension_quotient_domain_codewords = ext_quotient_domain_tables.collect_all_columns(); let extension_fri_domain_codewords = ext_fri_domain_tables.collect_all_columns(); - - prof_stop!(maybe_profiler, "LDE 2"); + prof_stop!(maybe_profiler, "dual LDE 2"); prof_start!(maybe_profiler, "Merkle tree 2"); let transposed_ext_codewords = transpose(&extension_fri_domain_codewords); @@ -204,26 +212,26 @@ impl Stark { prof_start!(maybe_profiler, "degree bounds"); prof_start!(maybe_profiler, "base"); - let base_degree_bounds = - base_fri_domain_tables.get_base_degree_bounds(self.parameters.num_trace_randomizers); + let base_degree_bounds = base_quotient_domain_tables + .get_base_degree_bounds(self.parameters.num_trace_randomizers); prof_stop!(maybe_profiler, "base"); prof_start!(maybe_profiler, "extension"); - let extension_degree_bounds = ext_fri_domain_tables + let extension_degree_bounds = ext_quotient_domain_tables .get_extension_degree_bounds(self.parameters.num_trace_randomizers); prof_stop!(maybe_profiler, "extension"); prof_start!(maybe_profiler, "quotient"); - let full_fri_domain_tables = - ExtTableCollection::join(base_fri_domain_tables, ext_fri_domain_tables); - let mut quotient_degree_bounds = full_fri_domain_tables + let full_quotient_domain_tables = + ExtTableCollection::join(base_quotient_domain_tables, ext_quotient_domain_tables); + let mut quotient_degree_bounds = full_quotient_domain_tables .get_all_quotient_degree_bounds(self.parameters.num_trace_randomizers); prof_stop!(maybe_profiler, "quotient"); prof_stop!(maybe_profiler, "degree bounds"); prof_start!(maybe_profiler, "quotient codewords"); - let mut quotient_codewords = full_fri_domain_tables.get_all_quotients( - &self.fri.domain, + let mut quotient_codewords = full_quotient_domain_tables.get_all_quotients( + "ient_domain, &extension_challenges, maybe_profiler, ); @@ -232,8 +240,8 @@ impl Stark { prof_start!(maybe_profiler, "grand cross table"); let num_grand_cross_table_args = 1; let num_non_lin_combi_weights = self.parameters.num_randomizer_polynomials - + 2 * base_fri_domain_codewords.len() - + 2 * extension_fri_domain_codewords.len() + + 2 * base_quotient_domain_codewords.len() + + 2 * extension_quotient_domain_codewords.len() + 2 * quotient_degree_bounds.len() + 2 * num_grand_cross_table_args; let num_grand_cross_table_arg_weights = NUM_CROSS_TABLE_ARGS + NUM_PUBLIC_EVAL_ARGS; @@ -270,38 +278,52 @@ impl Stark { ); let grand_cross_table_arg_quotient_codeword = grand_cross_table_arg .terminal_quotient_codeword( - &full_fri_domain_tables, - &self.fri.domain, - derive_omicron(full_fri_domain_tables.padded_height as u64), + &full_quotient_domain_tables, + "ient_domain, + derive_trace_domain_generator(full_quotient_domain_tables.padded_height as u64), ); quotient_codewords.push(grand_cross_table_arg_quotient_codeword); let grand_cross_table_arg_quotient_degree_bound = grand_cross_table_arg .quotient_degree_bound( - &full_fri_domain_tables, + &full_quotient_domain_tables, self.parameters.num_trace_randomizers, ); quotient_degree_bounds.push(grand_cross_table_arg_quotient_degree_bound); prof_stop!(maybe_profiler, "grand cross table"); prof_start!(maybe_profiler, "nonlinear combination"); + // magic number `1` corresponds to `num_randomizer_polynomials`, which is currently ignored + let (randomizer_weight, base_ext_quot_weights) = non_lin_combi_weights.split_at(1); let combination_codeword = self.create_combination_codeword( - vec![x_rand_codeword], - base_fri_domain_codewords, - extension_fri_domain_codewords, + "ient_domain, + base_quotient_domain_codewords, + extension_quotient_domain_codewords, quotient_codewords, - non_lin_combi_weights.to_vec(), + base_ext_quot_weights.to_vec(), base_degree_bounds, extension_degree_bounds, quotient_degree_bounds, maybe_profiler, ); + + prof_start!(maybe_profiler, "LDE 3"); + let combination_polynomial = quotient_domain.interpolate(&combination_codeword); + let fri_combination_codeword_without_randomizer = + self.fri.domain.evaluate(&combination_polynomial); + prof_stop!(maybe_profiler, "LDE 3"); + + let fri_combination_codeword: Vec<_> = fri_combination_codeword_without_randomizer + .into_par_iter() + .zip_eq(x_rand_codeword.into_par_iter()) + .map(|(cc_elem, rand_elem)| cc_elem + randomizer_weight[0] * rand_elem) + .collect(); prof_stop!(maybe_profiler, "nonlinear combination"); prof_start!(maybe_profiler, "Merkle tree 3"); let mut combination_codeword_digests: Vec = - Vec::with_capacity(combination_codeword.len()); - combination_codeword + Vec::with_capacity(fri_combination_codeword.len()); + fri_combination_codeword .clone() .into_par_iter() .map(|elem| StarkHasher::hash(&elem)) @@ -315,21 +337,17 @@ impl Stark { prof_stop!(maybe_profiler, "Merkle tree 3"); // Get indices of slices that go across codewords to prove nonlinear combination - if let Some(profiler) = maybe_profiler.as_mut() { - profiler.start("Fiat-Shamir 3"); - } + prof_start!(maybe_profiler, "Fiat-Shamir 3"); let indices_seed = proof_stream.prover_fiat_shamir(); let cross_codeword_slice_indices = StarkHasher::sample_indices( self.parameters.security_level, &indices_seed, self.fri.domain.length, ); - if let Some(profiler) = maybe_profiler.as_mut() { - profiler.stop("Fiat-Shamir 3"); - } + prof_stop!(maybe_profiler, "Fiat-Shamir 3"); prof_start!(maybe_profiler, "FRI"); - match self.fri.prove(&combination_codeword, &mut proof_stream) { + match self.fri.prove(&fri_combination_codeword, &mut proof_stream) { Ok((_, fri_first_round_merkle_root)) => assert_eq!( combination_root, fri_first_round_merkle_root, "Combination root from STARK and from FRI must agree." @@ -339,7 +357,7 @@ impl Stark { prof_stop!(maybe_profiler, "FRI"); prof_start!(maybe_profiler, "open trace leafs"); - // the relation between the FRI domain and the omicron domain + // the relation between the FRI domain and the trace domain let unit_distance = self.fri.domain.length / base_trace_tables.padded_height; // Open leafs of zipped codewords at indicated positions let revealed_indices = @@ -366,7 +384,7 @@ impl Stark { // as the latter includes adjacent table rows relative to the values in `indices` let revealed_combination_elements: Vec = cross_codeword_slice_indices .iter() - .map(|i| combination_codeword[*i]) + .map(|i| fri_combination_codeword[*i]) .collect(); let revealed_combination_auth_paths = combination_tree.get_authentication_structure(&cross_codeword_slice_indices); @@ -389,6 +407,14 @@ impl Stark { proof_stream.to_proof() } + fn quotient_domain(&self) -> ArithmeticDomain { + let offset = self.fri.domain.offset; + let expansion_factor = self.fri.expansion_factor; + let generator = self.fri.domain.generator.mod_pow(expansion_factor as u64); + let length = self.fri.domain.length / expansion_factor; + ArithmeticDomain::new(offset, generator, length) + } + fn get_revealed_indices( &self, unit_distance: usize, @@ -419,7 +445,7 @@ impl Stark { #[allow(clippy::too_many_arguments)] fn create_combination_codeword( &self, - randomizer_codewords: Vec>, + quotient_domain: &ArithmeticDomain, base_codewords: Vec>, extension_codewords: Vec>, quotient_codewords: Vec>, @@ -429,13 +455,7 @@ impl Stark { quotient_degree_bounds: Vec, maybe_profiler: &mut Option, ) -> Vec { - assert_eq!( - self.parameters.num_randomizer_polynomials, - randomizer_codewords.len() - ); - prof_start!(maybe_profiler, "create combination codeword"); - let base_codewords_lifted = base_codewords .into_iter() .map(|base_codeword| { @@ -446,20 +466,9 @@ impl Stark { }) .collect_vec(); let mut weights_iterator = weights.into_iter(); - let mut combination_codeword: Vec = vec![0.into(); self.fri.domain.length]; - - // TODO don't keep the entire domain's values in memory, create them lazily when needed - let fri_x_values = self.fri.domain.domain_values(); - - for randomizer_codeword in randomizer_codewords { - combination_codeword = Self::non_linearly_add_to_codeword( - &combination_codeword, - &randomizer_codeword, - &weights_iterator.next().unwrap(), - &randomizer_codeword, - &0.into(), - ); - } + let mut combination_codeword: Vec = vec![0.into(); quotient_domain.length]; + + let quotient_domain_values = quotient_domain.domain_values(); for (codewords, bounds, identifier) in [ (base_codewords_lifted, base_degree_bounds, "base"), @@ -474,7 +483,8 @@ impl Stark { codewords.into_iter().zip_eq(bounds.iter()).enumerate() { let shift = (self.max_degree as Degree - degree_bound) as u32; - let codeword_shifted = Self::shift_codeword(&fri_x_values, &codeword, shift); + let codeword_shifted = + Self::shift_codeword("ient_domain_values, &codeword, shift); combination_codeword = Self::non_linearly_add_to_codeword( &combination_codeword, @@ -484,6 +494,7 @@ impl Stark { &weights_iterator.next().unwrap(), ); self.debug_check_degrees( + quotient_domain, &idx, degree_bound, &shift, @@ -497,7 +508,7 @@ impl Stark { if std::env::var("DEBUG").is_ok() { println!( "The combination codeword corresponds to a polynomial of degree {}", - self.fri.domain.interpolate(&combination_codeword).degree() + quotient_domain.interpolate(&combination_codeword).degree() ); } @@ -509,6 +520,7 @@ impl Stark { #[allow(clippy::too_many_arguments)] fn debug_check_degrees( &self, + domain: &ArithmeticDomain, idx: &usize, degree_bound: &Degree, shift: &u32, @@ -519,8 +531,8 @@ impl Stark { if std::env::var("DEBUG").is_err() { return; } - let interpolated = self.fri.domain.interpolate(extension_codeword); - let interpolated_shifted = self.fri.domain.interpolate(extension_codeword_shifted); + let interpolated = domain.interpolate(extension_codeword); + let interpolated_shifted = domain.interpolate(extension_codeword_shifted); let int_shift_deg = interpolated_shifted.degree(); let maybe_excl_mark = if int_shift_deg > self.max_degree as isize { "!!!" @@ -558,11 +570,11 @@ impl Stark { } fn shift_codeword( - fri_x_values: &Vec, - codeword: &Vec, + quotient_domain_values: &[BFieldElement], + codeword: &[XFieldElement], shift: u32, ) -> Vec { - fri_x_values + quotient_domain_values .par_iter() .zip_eq(codeword.par_iter()) .map(|(x, &codeword_element)| (codeword_element * x.mod_pow_u32(shift))) @@ -607,7 +619,7 @@ impl Stark { fn get_randomizer_codewords(&self) -> (Vec, Vec>) { let randomizer_coefficients = random_elements(self.max_degree as usize + 1); - let randomizer_polynomial = Polynomial::new(randomizer_coefficients); + let randomizer_polynomial = Polynomial::::new(randomizer_coefficients); let x_randomizer_codeword = self.fri.domain.evaluate(&randomizer_polynomial); let mut b_randomizer_codewords = vec![vec![], vec![], vec![]]; @@ -745,7 +757,7 @@ impl Stark { prof_start!(maybe_profiler, "check leafs"); prof_start!(maybe_profiler, "get indices"); - // the relation between the FRI domain and the omicron domain + // the relation between the FRI domain and the trace domain let unit_distance = self.fri.domain.length / ext_table_collection.padded_height; // Open leafs of zipped codewords at indicated positions let revealed_indices = self.get_revealed_indices(unit_distance, &combination_check_indices); @@ -850,8 +862,8 @@ impl Stark { let base_offset = self.parameters.num_randomizer_polynomials; let ext_offset = base_offset + num_base_polynomials; let final_offset = ext_offset + num_extension_polynomials; - let omicron: XFieldElement = derive_omicron(padded_height as u64); - let omicron_inverse = omicron.inverse(); + let trace_domain_generator = derive_trace_domain_generator(padded_height as u64); + let trace_domain_generator_inverse = trace_domain_generator.inverse(); for (combination_check_index, revealed_combination_leaf) in combination_check_indices .into_iter() .zip_eq(revealed_combination_leafs) @@ -952,7 +964,8 @@ impl Stark { .zip_eq(initial_quotient_degree_bounds.iter()) { let shift = self.max_degree - degree_bound; - let quotient = evaluated_bc / (current_fri_domain_value - BFieldElement::one()); + let quotient = + evaluated_bc / (current_fri_domain_value - BFieldElement::one()).lift(); let quotient_shifted = quotient * current_fri_domain_value.mod_pow_u32(shift as u32); summands.push(quotient); @@ -969,7 +982,8 @@ impl Stark { let shift = self.max_degree - degree_bound; let quotient = evaluated_cc / (current_fri_domain_value.mod_pow_u32(padded_height as u32) - - BFieldElement::one()); + - BFieldElement::one()) + .lift(); let quotient_shifted = quotient * current_fri_domain_value.mod_pow_u32(shift as u32); summands.push(quotient); @@ -989,11 +1003,11 @@ impl Stark { { let shift = self.max_degree - degree_bound; let quotient = { - let numerator = current_fri_domain_value - omicron_inverse; + let numerator = current_fri_domain_value - trace_domain_generator_inverse; let denominator = current_fri_domain_value .mod_pow_u32(padded_height as u32) - BFieldElement::one(); - evaluated_tc * numerator / denominator + evaluated_tc * numerator / denominator.lift() }; let quotient_shifted = quotient * current_fri_domain_value.mod_pow_u32(shift as u32); @@ -1009,7 +1023,8 @@ impl Stark { .zip_eq(terminal_quotient_degree_bounds.iter()) { let shift = self.max_degree - degree_bound; - let quotient = evaluated_termc / (current_fri_domain_value - omicron_inverse); + let quotient = evaluated_termc + / (current_fri_domain_value - trace_domain_generator_inverse).lift(); let quotient_shifted = quotient * current_fri_domain_value.mod_pow_u32(shift as u32); summands.push(quotient); @@ -1029,8 +1044,8 @@ impl Stark { let shift = self.max_degree - grand_cross_table_arg_degree_bound; let grand_cross_table_arg_evaluated = grand_cross_table_arg.evaluate_non_linear_sum_of_differences(&cross_slice_by_table); - let grand_cross_table_arg_quotient = - grand_cross_table_arg_evaluated / (current_fri_domain_value - omicron_inverse); + let grand_cross_table_arg_quotient = grand_cross_table_arg_evaluated + / (current_fri_domain_value - trace_domain_generator_inverse).lift(); let grand_cross_table_arg_quotient_shifted = grand_cross_table_arg_quotient * current_fri_domain_value.mod_pow_u32(shift as u32); summands.push(grand_cross_table_arg_quotient); @@ -1301,7 +1316,7 @@ pub(crate) mod triton_stark_tests { ntt( &mut test_codeword, - stark.fri.domain.omega, + stark.fri.domain.generator, log_2_floor(stark.fri.domain.length as u128) as u32, ); for shift in [0, 1, 5, 17, 63, 121, 128] { diff --git a/triton-vm/src/table/base_table.rs b/triton-vm/src/table/base_table.rs index e40cd51a5..531242125 100644 --- a/triton-vm/src/table/base_table.rs +++ b/triton-vm/src/table/base_table.rs @@ -1,14 +1,14 @@ -use super::super::fri_domain::FriDomain; -use itertools::Itertools; +use super::super::arithmetic_domain::ArithmeticDomain; +use crate::table::table_collection::derive_trace_domain_generator; use num_traits::Zero; use rand_distr::{Distribution, Standard}; -use rayon::iter::{IntoParallelRefIterator, ParallelIterator}; -use std::ops::{MulAssign, Range}; +use rayon::iter::{IntoParallelIterator, IntoParallelRefIterator, ParallelIterator}; +use std::ops::{Mul, MulAssign, Range}; use twenty_first::shared_math::b_field_element::BFieldElement; use twenty_first::shared_math::mpolynomial::{Degree, MPolynomial}; -use twenty_first::shared_math::other::random_elements; +use twenty_first::shared_math::other::{random_elements, roundup_npo2}; use twenty_first::shared_math::polynomial::Polynomial; -use twenty_first::shared_math::traits::FiniteField; +use twenty_first::shared_math::traits::{FiniteField, PrimitiveRootOfUnity}; use twenty_first::shared_math::x_field_element::XFieldElement; #[derive(Debug, Clone, PartialEq, Eq)] @@ -256,7 +256,10 @@ fn disjoint_domain(domain_length: usize, disjoint_domain: &[FF] pub trait TableLike: InheritsFromTable where - FF: FiniteField + From + MulAssign, + FF: FiniteField + + From + + Mul + + MulAssign, Standard: Distribution, { // Generic functions common to all tables @@ -265,25 +268,33 @@ where self.inherited_table().name.clone() } - fn low_degree_extension( + /// Low-degree extends the trace that is `self` over the indicated columns `columns` and + /// returns two codewords per column: + /// - one codeword evaluated on the `quotient_domain`, and + /// - one codeword evaluated on the `fri_domain`, + /// in that order. + fn dual_low_degree_extension( &self, - fri_domain: &FriDomain, - omicron: FF, - padded_height: usize, + quotient_domain: &ArithmeticDomain, + fri_domain: &ArithmeticDomain, num_trace_randomizers: usize, columns: Range, - ) -> Vec> { - // FIXME: Table<> supports Vec<[FF; WIDTH]>, but FriDomain does not (yet). - self.interpolate_columns( - fri_domain, - omicron, - padded_height, - num_trace_randomizers, - columns, - ) - .par_iter() - .map(|polynomial| fri_domain.evaluate(polynomial)) - .collect() + ) -> (Table, Table) { + // FIXME: Table<> supports Vec<[FF; WIDTH]>, but Domain does not (yet). + let interpolated_columns = self.interpolate_columns(num_trace_randomizers, columns); + let quotient_domain_codewords = interpolated_columns + .par_iter() + .map(|polynomial| quotient_domain.evaluate(polynomial)) + .collect(); + let quotient_domain_codeword_table = + self.inherited_table().with_data(quotient_domain_codewords); + let fri_domain_codewords = interpolated_columns + .par_iter() + .map(|polynomial| fri_domain.evaluate(polynomial)) + .collect(); + let fri_domain_codeword_table = self.inherited_table().with_data(fri_domain_codewords); + + (quotient_domain_codeword_table, fri_domain_codeword_table) } /// Return the interpolation of columns. The `column_indices` variable @@ -291,56 +302,47 @@ where /// if it is called with a subset, it *will* fail. fn interpolate_columns( &self, - fri_domain: &FriDomain, - omicron: FF, - padded_height: usize, num_trace_randomizers: usize, columns: Range, ) -> Vec> { - // Ensure that `matrix` is set and padded before running this function - assert_eq!( - padded_height, - self.data().len(), - "{}: Table data must be padded before interpolation", - self.name() - ); - + let all_trace_columns = self.data(); + let padded_height = all_trace_columns.len(); if padded_height == 0 { return vec![Polynomial::zero(); columns.len()]; } - // FIXME: Unfold with multiplication instead of mapping with power. - let omicron_domain = (0..padded_height) - .map(|i| omicron.mod_pow_u32(i as u32)) - .collect_vec(); - - let num_trace_randomizers = num_trace_randomizers; - let randomizer_domain = disjoint_domain(num_trace_randomizers, &omicron_domain); - - let interpolation_domain = vec![omicron_domain, randomizer_domain].concat(); - let mut all_randomized_traces = vec![]; - let data = self.data(); - - for col in columns { - let trace = data.iter().map(|row| row[col]).collect(); - let randomizers = random_elements(num_trace_randomizers); - let randomized_trace = vec![trace, randomizers].concat(); - assert_eq!( - randomized_trace.len(), - interpolation_domain.len(), - "Length of x values and y values must match" - ); - all_randomized_traces.push(randomized_trace); - } + assert!( + padded_height.is_power_of_two(), + "{}: Table data must be padded before interpolation", + self.name() + ); - all_randomized_traces - .par_iter() - .map(|randomized_trace| { + let trace_domain_generator = derive_trace_domain_generator(padded_height as u64); + let trace_domain = + ArithmeticDomain::new(1_u32.into(), trace_domain_generator, padded_height) + .domain_values(); + + let randomizer_domain = disjoint_domain(num_trace_randomizers, &trace_domain); + let interpolation_domain = vec![trace_domain, randomizer_domain].concat(); + + // Generator (and its order) for a subgroup of the B-field. The subgroup is as small as + // possible given the constraints that its length is + // - larger than or equal to `interpolation_domain`, and + // - a power of two. + let order_of_root_of_unity = roundup_npo2(interpolation_domain.len() as u64); + let root_of_unity = BFieldElement::primitive_root_of_unity(order_of_root_of_unity).unwrap(); + + columns + .into_par_iter() + .map(|col| { + let trace = all_trace_columns.iter().map(|row| row[col]).collect(); + let randomizers = random_elements(num_trace_randomizers); + let randomized_trace = vec![trace, randomizers].concat(); Polynomial::fast_interpolate( &interpolation_domain, - randomized_trace, - &fri_domain.omega, - fri_domain.length, + &randomized_trace, + &root_of_unity, + order_of_root_of_unity as usize, ) }) .collect() diff --git a/triton-vm/src/table/extension_table.rs b/triton-vm/src/table/extension_table.rs index 56bd08640..db79e1353 100644 --- a/triton-vm/src/table/extension_table.rs +++ b/triton-vm/src/table/extension_table.rs @@ -5,14 +5,16 @@ use num_traits::One; use rayon::iter::{ IndexedParallelIterator, IntoParallelIterator, IntoParallelRefIterator, ParallelIterator, }; -use triton_profiler::triton_profiler::TritonProfiler; use twenty_first::shared_math::b_field_element::BFieldElement; use twenty_first::shared_math::mpolynomial::{Degree, MPolynomial}; use twenty_first::shared_math::other::transpose; use twenty_first::shared_math::traits::{FiniteField, Inverse, ModPowU32}; use twenty_first::shared_math::x_field_element::XFieldElement; -use crate::fri_domain::FriDomain; +use triton_profiler::triton_profiler::TritonProfiler; +use triton_profiler::{prof_start, prof_stop}; + +use crate::arithmetic_domain::ArithmeticDomain; use crate::table::extension_table; use crate::table::table_collection::interpolant_degree; @@ -193,101 +195,103 @@ pub trait Quotientable: ExtensionTable + Evaluable { fn initial_quotients( &self, - fri_domain: &FriDomain, + domain: &ArithmeticDomain, transposed_codewords: &[Vec], challenges: &AllChallenges, ) -> Vec> { - debug_assert_eq!(fri_domain.length, transposed_codewords.len()); + debug_assert_eq!(domain.length, transposed_codewords.len()); - let zerofier_codeword = fri_domain + let zerofier_codeword = domain .domain_values() .into_iter() .map(|x| x - BFieldElement::one()) .collect(); - let zerofier_inverse = XFieldElement::batch_inversion(zerofier_codeword); + let zerofier_inverse = BFieldElement::batch_inversion(zerofier_codeword); let transposed_quotient_codewords: Vec<_> = zerofier_inverse .par_iter() .enumerate() - .map(|(fri_dom_i, &z_inv)| { - let row = &transposed_codewords[fri_dom_i]; + .map(|(domain_index, &z_inv)| { + let row = &transposed_codewords[domain_index]; let evaluated_bcs = self.evaluate_initial_constraints(row, challenges); evaluated_bcs.iter().map(|&ebc| ebc * z_inv).collect() }) .collect(); let quotient_codewords = transpose(&transposed_quotient_codewords); - self.debug_fri_domain_bound_check(fri_domain, "ient_codewords, "initial"); + self.debug_domain_bound_check(domain, "ient_codewords, "initial"); quotient_codewords } fn consistency_quotients( &self, - fri_domain: &FriDomain, + domain: &ArithmeticDomain, transposed_codewords: &[Vec], challenges: &AllChallenges, padded_height: usize, ) -> Vec> { - debug_assert_eq!(fri_domain.length, transposed_codewords.len()); + debug_assert_eq!(domain.length, transposed_codewords.len()); - let zerofier_codeword = fri_domain + let zerofier_codeword = domain .domain_values() .iter() .map(|x| x.mod_pow_u32(padded_height as u32) - BFieldElement::one()) .collect(); - let zerofier_inverse = XFieldElement::batch_inversion(zerofier_codeword); + let zerofier_inverse = BFieldElement::batch_inversion(zerofier_codeword); let transposed_quotient_codewords: Vec<_> = zerofier_inverse .par_iter() .enumerate() - .map(|(fri_dom_i, &z_inv)| { - let row = &transposed_codewords[fri_dom_i]; + .map(|(domain_index, &z_inv)| { + let row = &transposed_codewords[domain_index]; let evaluated_ccs = self.evaluate_consistency_constraints(row, challenges); evaluated_ccs.iter().map(|&ecc| ecc * z_inv).collect() }) .collect(); let quotient_codewords = transpose(&transposed_quotient_codewords); - self.debug_fri_domain_bound_check(fri_domain, "ient_codewords, "consistency"); + self.debug_domain_bound_check(domain, "ient_codewords, "consistency"); quotient_codewords } fn transition_quotients( &self, - fri_domain: &FriDomain, + domain: &ArithmeticDomain, transposed_codewords: &[Vec], challenges: &AllChallenges, - omicron: XFieldElement, + trace_domain_generator: BFieldElement, padded_height: usize, ) -> Vec> { - debug_assert_eq!(fri_domain.length, transposed_codewords.len()); + debug_assert_eq!(domain.length, transposed_codewords.len()); let one = XFieldElement::one(); - let omicron_inverse = omicron.inverse(); - let fri_domain_values = fri_domain.domain_values(); + let trace_domain_generator_inverse = trace_domain_generator.inverse(); + let domain_values = domain.domain_values(); - let subgroup_zerofier: Vec<_> = fri_domain_values + let subgroup_zerofier: Vec<_> = domain_values .par_iter() - .map(|fri_dom_v| fri_dom_v.mod_pow_u32(padded_height as u32) - one) + .map(|domain_value| domain_value.mod_pow_u32(padded_height as u32) - one) .collect(); let subgroup_zerofier_inverse = XFieldElement::batch_inversion(subgroup_zerofier); - let zerofier_inverse: Vec<_> = fri_domain_values + let zerofier_inverse: Vec<_> = domain_values .into_par_iter() .zip_eq(subgroup_zerofier_inverse.into_par_iter()) - .map(|(fri_dom_v, sub_z_inv)| (fri_dom_v - omicron_inverse) * sub_z_inv) + .map(|(domain_value, sub_z_inv)| { + (domain_value - trace_domain_generator_inverse) * sub_z_inv + }) .collect(); - // the relation between the FRI domain and the omicron domain - let unit_distance = fri_domain.length / padded_height; + // the relation between the quotient domain and the trace domain + let unit_distance = domain.length / padded_height; - let fri_domain_bit_mask = fri_domain.length - 1; + let domain_length_bit_mask = domain.length - 1; let transposed_quotient_codewords: Vec<_> = zerofier_inverse .par_iter() .enumerate() .map(|(current_row_idx, &z_inv)| { - // `& fri_domain_bit_mask` performs cheap modulo: - // `fri_domain.length - 1` is a bit-mask with all 1s - // because fri_domain.length is 2^k for some k. - let next_row_index = (current_row_idx + unit_distance) & fri_domain_bit_mask; + // `&domain_length_bit_mask` performs the modulo operation cheaply: + // `domain.length - 1` is a bit-mask with all 1s because `domain.length` is 2^k + // for some k. + let next_row_index = (current_row_idx + unit_distance) & domain_length_bit_mask; let current_row = &transposed_codewords[current_row_idx]; let next_row = &transposed_codewords[next_row_index]; @@ -297,97 +301,85 @@ pub trait Quotientable: ExtensionTable + Evaluable { }) .collect(); let quotient_codewords = transpose(&transposed_quotient_codewords); - self.debug_fri_domain_bound_check(fri_domain, "ient_codewords, "transition"); + self.debug_domain_bound_check(domain, "ient_codewords, "transition"); quotient_codewords } fn terminal_quotients( &self, - fri_domain: &FriDomain, + quotient_domain: &ArithmeticDomain, transposed_codewords: &[Vec], challenges: &AllChallenges, - omicron: XFieldElement, + trace_domain_generator: BFieldElement, ) -> Vec> { - debug_assert_eq!(fri_domain.length, transposed_codewords.len()); + debug_assert_eq!(quotient_domain.length, transposed_codewords.len()); // The zerofier for the terminal quotient has a root in the last - // value in the cyclical group generated from omicron. - let zerofier_codeword = fri_domain + // value in the cyclical group generated from the trace domain's generator. + let zerofier_codeword = quotient_domain .domain_values() .into_iter() - .map(|x| x - omicron.inverse()) + .map(|x| x - trace_domain_generator.inverse()) .collect_vec(); - let zerofier_inverse = XFieldElement::batch_inversion(zerofier_codeword); + let zerofier_inverse = BFieldElement::batch_inversion(zerofier_codeword); let transposed_quotient_codewords: Vec<_> = zerofier_inverse .par_iter() .enumerate() - .map(|(fri_dom_i, &z_inv)| { - let row = &transposed_codewords[fri_dom_i]; + .map(|(domain_index, &z_inv)| { + let row = &transposed_codewords[domain_index]; let evaluated_termcs = self.evaluate_terminal_constraints(row, challenges); evaluated_termcs.iter().map(|&etc| etc * z_inv).collect() }) .collect(); let quotient_codewords = transpose(&transposed_quotient_codewords); - self.debug_fri_domain_bound_check(fri_domain, "ient_codewords, "terminal"); + self.debug_domain_bound_check(quotient_domain, "ient_codewords, "terminal"); quotient_codewords } fn all_quotients( &self, - fri_domain: &FriDomain, + quotient_domain: &ArithmeticDomain, transposed_codewords: Vec>, challenges: &AllChallenges, - omicron: XFieldElement, + trace_domain_generator: BFieldElement, padded_height: usize, maybe_profiler: &mut Option, ) -> Vec> { - if let Some(p) = maybe_profiler.as_mut() { - p.start("initial quotients") - } + prof_start!(maybe_profiler, "initial quotients"); let initial_quotients = - self.initial_quotients(fri_domain, &transposed_codewords, challenges); - if let Some(p) = maybe_profiler.as_mut() { - p.stop("initial quotients") - } + self.initial_quotients(quotient_domain, &transposed_codewords, challenges); + prof_stop!(maybe_profiler, "initial quotients"); - if let Some(p) = maybe_profiler.as_mut() { - p.start("consistency quotients") - } + prof_start!(maybe_profiler, "consistency quotients"); let consistency_quotients = self.consistency_quotients( - fri_domain, + quotient_domain, &transposed_codewords, challenges, padded_height, ); - if let Some(p) = maybe_profiler.as_mut() { - p.stop("consistency quotients") - } + prof_stop!(maybe_profiler, "consistency quotients"); - if let Some(p) = maybe_profiler.as_mut() { - p.start("transition quotients") - } + prof_start!(maybe_profiler, "transition quotients"); let transition_quotients = self.transition_quotients( - fri_domain, + quotient_domain, &transposed_codewords, challenges, - omicron, + trace_domain_generator, padded_height, ); - if let Some(p) = maybe_profiler.as_mut() { - p.stop("transition quotients") - } + prof_stop!(maybe_profiler, "transition quotients"); - if let Some(p) = maybe_profiler.as_mut() { - p.start("terminal quotients") - } - let terminal_quotients = - self.terminal_quotients(fri_domain, &transposed_codewords, challenges, omicron); - if let Some(p) = maybe_profiler.as_mut() { - p.stop("terminal quotients") - } + prof_start!(maybe_profiler, "terminal quotients"); + let terminal_quotients = self.terminal_quotients( + quotient_domain, + &transposed_codewords, + challenges, + trace_domain_generator, + ); + prof_stop!(maybe_profiler, "terminal quotients"); vec![ initial_quotients, @@ -401,14 +393,14 @@ pub trait Quotientable: ExtensionTable + Evaluable { /// Intended for debugging. Will not do anything unless environment variable `DEBUG` is set. /// The performed check /// 1. takes `quotients` in value form (i.e., as codewords), - /// 1. interpolates them over the given `fri_domain`, and + /// 1. interpolates them over the given `domain`, and /// 1. checks their degree. /// /// Panics if an interpolant has maximal degree, indicating that the quotient codeword is most /// probably the result of un-clean division. - fn debug_fri_domain_bound_check( + fn debug_domain_bound_check( &self, - fri_domain: &FriDomain, + quotient_domain: &ArithmeticDomain, quotient_codewords: &[Vec], quotient_type: &str, ) { @@ -416,16 +408,16 @@ pub trait Quotientable: ExtensionTable + Evaluable { return; } for (idx, qc) in quotient_codewords.iter().enumerate() { - let interpolated = fri_domain.interpolate(qc); + let interpolated = quotient_domain.interpolate(qc); assert!( - interpolated.degree() < fri_domain.length as isize - 1, + interpolated.degree() < quotient_domain.length as isize - 1, "Degree of {} quotient index {idx} (total {} quotients) in {} must not be maximal. \ - Got degree {}, and FRI domain length was {}.", + Got degree {}, and domain length was {}.", quotient_type, quotient_codewords.len(), self.name(), interpolated.degree(), - fri_domain.length, + quotient_domain.length, ); } } diff --git a/triton-vm/src/table/hash_table.rs b/triton-vm/src/table/hash_table.rs index 7c3262fcd..ce5424f50 100644 --- a/triton-vm/src/table/hash_table.rs +++ b/triton-vm/src/table/hash_table.rs @@ -15,8 +15,8 @@ use twenty_first::shared_math::traits::ModPowU32; use twenty_first::shared_math::traits::ModPowU64; use twenty_first::shared_math::x_field_element::XFieldElement; +use crate::arithmetic_domain::ArithmeticDomain; use crate::cross_table_arguments::{CrossTableArg, EvalArg}; -use crate::fri_domain::FriDomain; use crate::table::base_table::Extendable; use crate::table::extension_table::Evaluable; use crate::table::table_collection::interpolant_degree; @@ -631,28 +631,32 @@ impl ExtHashTable { } impl HashTable { + pub fn new(inherited_table: Table) -> Self { + Self { inherited_table } + } + pub fn new_prover(matrix: Vec>) -> Self { let inherited_table = Table::new(BASE_WIDTH, FULL_WIDTH, matrix, "HashTable".to_string()); Self { inherited_table } } - pub fn to_fri_domain_table( + pub fn to_quotient_and_fri_domain_table( &self, - fri_domain: &FriDomain, - omicron: BFieldElement, - padded_height: usize, + quotient_domain: &ArithmeticDomain, + fri_domain: &ArithmeticDomain, num_trace_randomizers: usize, - ) -> Self { + ) -> (Self, Self) { let base_columns = 0..self.base_width(); - let fri_domain_codewords = self.low_degree_extension( + let (quotient_domain_table, fri_domain_table) = self.dual_low_degree_extension( + quotient_domain, fri_domain, - omicron, - padded_height, num_trace_randomizers, base_columns, ); - let inherited_table = self.inherited_table.with_data(fri_domain_codewords); - Self { inherited_table } + ( + Self::new(quotient_domain_table), + Self::new(fri_domain_table), + ) } pub fn extend( @@ -790,24 +794,27 @@ impl HashTable { } impl ExtHashTable { - pub fn to_fri_domain_table( + pub fn new(inherited_table: Table) -> Self { + Self { inherited_table } + } + + pub fn to_quotient_and_fri_domain_table( &self, - fri_domain: &FriDomain, - omicron: XFieldElement, - padded_height: usize, + quotient_domain: &ArithmeticDomain, + fri_domain: &ArithmeticDomain, num_trace_randomizers: usize, - ) -> Self { + ) -> (Self, Self) { let ext_columns = self.base_width()..self.full_width(); - let fri_domain_codewords_ext = self.low_degree_extension( + let (quotient_domain_table_ext, fri_domain_table_ext) = self.dual_low_degree_extension( + quotient_domain, fri_domain, - omicron, - padded_height, num_trace_randomizers, ext_columns, ); - - let inherited_table = self.inherited_table.with_data(fri_domain_codewords_ext); - ExtHashTable { inherited_table } + ( + Self::new(quotient_domain_table_ext), + Self::new(fri_domain_table_ext), + ) } } diff --git a/triton-vm/src/table/instruction_table.rs b/triton-vm/src/table/instruction_table.rs index 333be7800..bc0a99703 100644 --- a/triton-vm/src/table/instruction_table.rs +++ b/triton-vm/src/table/instruction_table.rs @@ -6,8 +6,8 @@ use twenty_first::shared_math::b_field_element::BFieldElement; use twenty_first::shared_math::mpolynomial::{Degree, MPolynomial}; use twenty_first::shared_math::x_field_element::XFieldElement; +use crate::arithmetic_domain::ArithmeticDomain; use crate::cross_table_arguments::{CrossTableArg, EvalArg, PermArg}; -use crate::fri_domain::FriDomain; use crate::table::base_table::Extendable; use super::base_table::{InheritsFromTable, Table, TableLike}; @@ -330,6 +330,10 @@ impl ExtInstructionTable { } impl InstructionTable { + pub fn new(inherited_table: Table) -> Self { + Self { inherited_table } + } + pub fn new_prover(matrix: Vec>) -> Self { let inherited_table = Table::new( BASE_WIDTH, @@ -340,23 +344,23 @@ impl InstructionTable { Self { inherited_table } } - pub fn to_fri_domain_table( + pub fn to_quotient_and_fri_domain_table( &self, - fri_domain: &FriDomain, - omicron: BFieldElement, - padded_height: usize, + quotient_domain: &ArithmeticDomain, + fri_domain: &ArithmeticDomain, num_trace_randomizers: usize, - ) -> Self { + ) -> (Self, Self) { let base_columns = 0..self.base_width(); - let fri_domain_codewords = self.low_degree_extension( + let (quotient_domain_table, fri_domain_table) = self.dual_low_degree_extension( + quotient_domain, fri_domain, - omicron, - padded_height, num_trace_randomizers, base_columns, ); - let inherited_table = self.inherited_table.with_data(fri_domain_codewords); - Self { inherited_table } + ( + Self::new(quotient_domain_table), + Self::new(fri_domain_table), + ) } pub fn extend( @@ -475,24 +479,28 @@ impl InstructionTable { } impl ExtInstructionTable { - pub fn to_fri_domain_table( + pub fn new(inherited_table: Table) -> Self { + Self { inherited_table } + } + + pub fn to_quotient_and_fri_domain_table( &self, - fri_domain: &FriDomain, - omicron: XFieldElement, - padded_height: usize, + quotient_domain: &ArithmeticDomain, + fri_domain: &ArithmeticDomain, num_trace_randomizers: usize, - ) -> Self { + ) -> (Self, Self) { let ext_columns = self.base_width()..self.full_width(); - let fri_domain_codewords_ext = self.low_degree_extension( + let (quotient_domain_table, fri_domain_table) = self.dual_low_degree_extension( + quotient_domain, fri_domain, - omicron, - padded_height, num_trace_randomizers, ext_columns, ); - let inherited_table = self.inherited_table.with_data(fri_domain_codewords_ext); - ExtInstructionTable { inherited_table } + ( + Self::new(quotient_domain_table), + Self::new(fri_domain_table), + ) } } diff --git a/triton-vm/src/table/jump_stack_table.rs b/triton-vm/src/table/jump_stack_table.rs index ea617b33d..aca8f078f 100644 --- a/triton-vm/src/table/jump_stack_table.rs +++ b/triton-vm/src/table/jump_stack_table.rs @@ -7,8 +7,8 @@ use twenty_first::shared_math::mpolynomial::{Degree, MPolynomial}; use twenty_first::shared_math::traits::Inverse; use twenty_first::shared_math::x_field_element::XFieldElement; +use crate::arithmetic_domain::ArithmeticDomain; use crate::cross_table_arguments::{CrossTableArg, PermArg}; -use crate::fri_domain::FriDomain; use crate::instruction::Instruction; use crate::table::base_table::Extendable; use crate::table::table_column::JumpStackBaseTableColumn::{self, *}; @@ -320,29 +320,34 @@ impl ExtJumpStackTable { } impl JumpStackTable { + pub fn new(inherited_table: Table) -> Self { + Self { inherited_table } + } + pub fn new_prover(matrix: Vec>) -> Self { let inherited_table = Table::new(BASE_WIDTH, FULL_WIDTH, matrix, "JumpStackTable".to_string()); Self { inherited_table } } - pub fn to_fri_domain_table( + pub fn to_quotient_and_fri_domain_table( &self, - fri_domain: &FriDomain, - omicron: BFieldElement, - padded_height: usize, + quotient_domain: &ArithmeticDomain, + fri_domain: &ArithmeticDomain, num_trace_randomizers: usize, - ) -> Self { + ) -> (Self, Self) { let base_columns = 0..self.base_width(); - let fri_domain_codewords = self.low_degree_extension( + let (quotient_domain_table, fri_domain_table) = self.dual_low_degree_extension( + quotient_domain, fri_domain, - omicron, - padded_height, num_trace_randomizers, base_columns, ); - let inherited_table = self.inherited_table.with_data(fri_domain_codewords); - Self { inherited_table } + + ( + Self::new(quotient_domain_table), + Self::new(fri_domain_table), + ) } pub fn extend( @@ -454,24 +459,27 @@ impl JumpStackTable { } impl ExtJumpStackTable { - pub fn to_fri_domain_table( + pub fn new(inherited_table: Table) -> Self { + Self { inherited_table } + } + + pub fn to_quotient_and_fri_domain_table( &self, - fri_domain: &FriDomain, - omicron: XFieldElement, - padded_height: usize, + quotient_domain: &ArithmeticDomain, + fri_domain: &ArithmeticDomain, num_trace_randomizers: usize, - ) -> Self { + ) -> (Self, Self) { let ext_columns = self.base_width()..self.full_width(); - let fri_domain_codewords_ext = self.low_degree_extension( + let (quotient_domain_table, fri_domain_table) = self.dual_low_degree_extension( + quotient_domain, fri_domain, - omicron, - padded_height, num_trace_randomizers, ext_columns, ); - - let inherited_table = self.inherited_table.with_data(fri_domain_codewords_ext); - ExtJumpStackTable { inherited_table } + ( + Self::new(quotient_domain_table), + Self::new(fri_domain_table), + ) } } diff --git a/triton-vm/src/table/op_stack_table.rs b/triton-vm/src/table/op_stack_table.rs index 005e9b4fd..21c00ff32 100644 --- a/triton-vm/src/table/op_stack_table.rs +++ b/triton-vm/src/table/op_stack_table.rs @@ -8,8 +8,8 @@ use twenty_first::shared_math::traits::Inverse; use twenty_first::shared_math::x_field_element::XFieldElement; use super::constraint_circuit::DualRowIndicator::*; +use crate::arithmetic_domain::ArithmeticDomain; use crate::cross_table_arguments::{CrossTableArg, PermArg}; -use crate::fri_domain::FriDomain; use crate::table::base_table::Extendable; use crate::table::table_column::OpStackBaseTableColumn::{self, *}; use crate::table::table_column::OpStackExtTableColumn::{self, *}; @@ -278,29 +278,33 @@ impl ExtOpStackTable { } impl OpStackTable { + pub fn new(inherited_table: Table) -> Self { + Self { inherited_table } + } + pub fn new_prover(matrix: Vec>) -> Self { let inherited_table = Table::new(BASE_WIDTH, FULL_WIDTH, matrix, "OpStackTable".to_string()); Self { inherited_table } } - pub fn to_fri_domain_table( + pub fn to_quotient_and_fri_domain_table( &self, - fri_domain: &FriDomain, - omicron: BFieldElement, - padded_height: usize, + quotient_domain: &ArithmeticDomain, + fri_domain: &ArithmeticDomain, num_trace_randomizers: usize, - ) -> Self { + ) -> (Self, Self) { let base_columns = 0..self.base_width(); - let fri_domain_codewords = self.low_degree_extension( + let (quotient_domain_table, fri_domain_table) = self.dual_low_degree_extension( + quotient_domain, fri_domain, - omicron, - padded_height, num_trace_randomizers, base_columns, ); - let inherited_table = self.inherited_table.with_data(fri_domain_codewords); - Self { inherited_table } + ( + Self::new(quotient_domain_table), + Self::new(fri_domain_table), + ) } pub fn extend( @@ -400,24 +404,28 @@ impl OpStackTable { } impl ExtOpStackTable { - pub fn to_fri_domain_table( + pub fn new(inherited_table: Table) -> Self { + Self { inherited_table } + } + + pub fn to_quotient_and_fri_domain_table( &self, - fri_domain: &FriDomain, - omicron: XFieldElement, - padded_height: usize, + quotient_domain: &ArithmeticDomain, + fri_domain: &ArithmeticDomain, num_trace_randomizers: usize, - ) -> Self { + ) -> (Self, Self) { let ext_columns = self.base_width()..self.full_width(); - let fri_domain_codewords_ext = self.low_degree_extension( + let (quotient_domain_table, fri_domain_table) = self.dual_low_degree_extension( + quotient_domain, fri_domain, - omicron, - padded_height, num_trace_randomizers, ext_columns, ); - let inherited_table = self.inherited_table.with_data(fri_domain_codewords_ext); - ExtOpStackTable { inherited_table } + ( + Self::new(quotient_domain_table), + Self::new(fri_domain_table), + ) } } diff --git a/triton-vm/src/table/processor_table.rs b/triton-vm/src/table/processor_table.rs index 74f88f0d3..3a9e2574d 100644 --- a/triton-vm/src/table/processor_table.rs +++ b/triton-vm/src/table/processor_table.rs @@ -11,8 +11,8 @@ use twenty_first::shared_math::b_field_element::BFieldElement; use twenty_first::shared_math::mpolynomial::{Degree, MPolynomial}; use twenty_first::shared_math::x_field_element::XFieldElement; +use crate::arithmetic_domain::ArithmeticDomain; use crate::cross_table_arguments::{CrossTableArg, EvalArg, PermArg}; -use crate::fri_domain::FriDomain; use crate::instruction::{all_instructions_without_args, AnInstruction::*, Instruction}; use crate::ord_n::Ord7; use crate::table::base_table::{Extendable, InheritsFromTable, Table, TableLike}; @@ -52,29 +52,33 @@ impl InheritsFromTable for ProcessorTable { } impl ProcessorTable { + pub fn new(inherited_table: Table) -> Self { + Self { inherited_table } + } + pub fn new_prover(matrix: Vec>) -> Self { let inherited_table = Table::new(BASE_WIDTH, FULL_WIDTH, matrix, "ProcessorTable".to_string()); Self { inherited_table } } - pub fn to_fri_domain_table( + pub fn to_quotient_and_fri_domain_table( &self, - fri_domain: &FriDomain, - omicron: BFieldElement, - padded_height: usize, + quotient_domain: &ArithmeticDomain, + fri_domain: &ArithmeticDomain, num_trace_randomizers: usize, - ) -> Self { + ) -> (Self, Self) { let base_columns = 0..self.base_width(); - let fri_domain_codewords = self.low_degree_extension( + let (quotient_domain_table, fri_domain_table) = self.dual_low_degree_extension( + quotient_domain, fri_domain, - omicron, - padded_height, num_trace_randomizers, base_columns, ); - let inherited_table = self.inherited_table.with_data(fri_domain_codewords); - Self { inherited_table } + ( + Self::new(quotient_domain_table), + Self::new(fri_domain_table), + ) } pub fn extend( @@ -356,30 +360,28 @@ impl ProcessorTable { } impl ExtProcessorTable { - pub fn to_fri_domain_table( + pub fn new(inherited_table: Table) -> Self { + Self { inherited_table } + } + + pub fn to_quotient_and_fri_domain_table( &self, - fri_domain: &FriDomain, - omicron: XFieldElement, - padded_height: usize, + quotient_domain: &ArithmeticDomain, + fri_domain: &ArithmeticDomain, num_trace_randomizers: usize, - ) -> Self { + ) -> (Self, Self) { let ext_columns = self.base_width()..self.full_width(); - let fri_domain_codewords_ext = self.low_degree_extension( + let (quotient_domain_table, fri_domain_table) = self.dual_low_degree_extension( + quotient_domain, fri_domain, - omicron, - padded_height, num_trace_randomizers, ext_columns, ); - let inherited_table = self.inherited_table.with_data(fri_domain_codewords_ext); - Self::new(inherited_table) - } - - pub fn new(base: Table) -> ExtProcessorTable { - Self { - inherited_table: base, - } + ( + Self::new(quotient_domain_table), + Self::new(fri_domain_table), + ) } /// Instruction-specific transition constraints are combined with deselectors in such a way diff --git a/triton-vm/src/table/program_table.rs b/triton-vm/src/table/program_table.rs index 1a64481df..20ddd490c 100644 --- a/triton-vm/src/table/program_table.rs +++ b/triton-vm/src/table/program_table.rs @@ -7,8 +7,8 @@ use twenty_first::shared_math::mpolynomial::{Degree, MPolynomial}; use twenty_first::shared_math::x_field_element::XFieldElement; use super::constraint_circuit::DualRowIndicator::*; +use crate::arithmetic_domain::ArithmeticDomain; use crate::cross_table_arguments::{CrossTableArg, EvalArg}; -use crate::fri_domain::FriDomain; use crate::table::base_table::Extendable; use crate::table::table_column::ProgramBaseTableColumn::{self, *}; use crate::table::table_column::ProgramExtTableColumn::{self, *}; @@ -185,29 +185,33 @@ impl ExtProgramTable { } impl ProgramTable { + pub fn new(inherited_table: Table) -> Self { + Self { inherited_table } + } + pub fn new_prover(matrix: Vec>) -> Self { let inherited_table = Table::new(BASE_WIDTH, FULL_WIDTH, matrix, "ProgramTable".to_string()); Self { inherited_table } } - pub fn to_fri_domain_table( + pub fn to_quotient_and_fri_domain_table( &self, - fri_domain: &FriDomain, - omicron: BFieldElement, - padded_height: usize, + quotient_domain: &ArithmeticDomain, + fri_domain: &ArithmeticDomain, num_trace_randomizers: usize, - ) -> Self { + ) -> (Self, Self) { let base_columns = 0..self.base_width(); - let fri_domain_codewords = self.low_degree_extension( + let (quotient_domain_table, fri_domain_table) = self.dual_low_degree_extension( + quotient_domain, fri_domain, - omicron, - padded_height, num_trace_randomizers, base_columns, ); - let inherited_table = self.inherited_table.with_data(fri_domain_codewords); - Self { inherited_table } + ( + Self::new(quotient_domain_table), + Self::new(fri_domain_table), + ) } pub fn extend( @@ -297,24 +301,28 @@ impl ProgramTable { } impl ExtProgramTable { - pub fn to_fri_domain_table( + pub fn new(inherited_table: Table) -> Self { + Self { inherited_table } + } + + pub fn to_quotient_and_fri_domain_table( &self, - fri_domain: &FriDomain, - omicron: XFieldElement, - padded_height: usize, + quotient_domain: &ArithmeticDomain, + fri_domain: &ArithmeticDomain, num_trace_randomizers: usize, - ) -> Self { + ) -> (Self, Self) { let ext_columns = self.base_width()..self.full_width(); - let fri_domain_codewords_ext = self.low_degree_extension( + let (quotient_domain_table, fri_domain_table) = self.dual_low_degree_extension( + quotient_domain, fri_domain, - omicron, - padded_height, num_trace_randomizers, ext_columns, ); - let inherited_table = self.inherited_table.with_data(fri_domain_codewords_ext); - ExtProgramTable { inherited_table } + ( + Self::new(quotient_domain_table), + Self::new(fri_domain_table), + ) } } diff --git a/triton-vm/src/table/ram_table.rs b/triton-vm/src/table/ram_table.rs index 5e4ee50fd..2972e4d34 100644 --- a/triton-vm/src/table/ram_table.rs +++ b/triton-vm/src/table/ram_table.rs @@ -8,8 +8,8 @@ use twenty_first::shared_math::traits::Inverse; use twenty_first::shared_math::x_field_element::XFieldElement; use super::constraint_circuit::DualRowIndicator::*; +use crate::arithmetic_domain::ArithmeticDomain; use crate::cross_table_arguments::{CrossTableArg, PermArg}; -use crate::fri_domain::FriDomain; use crate::table::base_table::Extendable; use crate::table::table_column::RamBaseTableColumn::{self, *}; use crate::table::table_column::RamExtTableColumn::{self, *}; @@ -79,28 +79,33 @@ impl InheritsFromTable for ExtRamTable { } impl RamTable { + pub fn new(inherited_table: Table) -> Self { + Self { inherited_table } + } + pub fn new_prover(matrix: Vec>) -> Self { let inherited_table = Table::new(BASE_WIDTH, FULL_WIDTH, matrix, "RamTable".to_string()); Self { inherited_table } } - pub fn to_fri_domain_table( + pub fn to_quotient_and_fri_domain_table( &self, - fri_domain: &FriDomain, - omicron: BFieldElement, - padded_height: usize, + quotient_domain: &ArithmeticDomain, + fri_domain: &ArithmeticDomain, num_trace_randomizers: usize, - ) -> Self { + ) -> (Self, Self) { let base_columns = 0..self.base_width(); - let fri_domain_codewords = self.low_degree_extension( + let (quotient_domain_table, fri_domain_table) = self.dual_low_degree_extension( + quotient_domain, fri_domain, - omicron, - padded_height, num_trace_randomizers, base_columns, ); - let inherited_table = self.inherited_table.with_data(fri_domain_codewords); - Self { inherited_table } + + ( + Self::new(quotient_domain_table), + Self::new(fri_domain_table), + ) } pub fn extend( @@ -219,24 +224,28 @@ impl RamTable { } impl ExtRamTable { - pub fn to_fri_domain_table( + pub fn new(inherited_table: Table) -> Self { + Self { inherited_table } + } + + pub fn to_quotient_and_fri_domain_table( &self, - fri_domain: &FriDomain, - omicron: XFieldElement, - padded_height: usize, + quotient_domain: &ArithmeticDomain, + fri_domain: &ArithmeticDomain, num_trace_randomizers: usize, - ) -> Self { + ) -> (Self, Self) { let ext_columns = self.base_width()..self.full_width(); - let fri_domain_codewords_ext = self.low_degree_extension( + let (quotient_domain_table, fri_domain_table) = self.dual_low_degree_extension( + quotient_domain, fri_domain, - omicron, - padded_height, num_trace_randomizers, ext_columns, ); - let inherited_table = self.inherited_table.with_data(fri_domain_codewords_ext); - ExtRamTable { inherited_table } + ( + Self::new(quotient_domain_table), + Self::new(fri_domain_table), + ) } } diff --git a/triton-vm/src/table/table_collection.rs b/triton-vm/src/table/table_collection.rs index bde1454ff..dbc74682e 100644 --- a/triton-vm/src/table/table_collection.rs +++ b/triton-vm/src/table/table_collection.rs @@ -1,15 +1,16 @@ use itertools::Itertools; -use triton_profiler::{prof_start, prof_stop}; use twenty_first::shared_math::b_field_element::BFieldElement; use twenty_first::shared_math::mpolynomial::Degree; use twenty_first::shared_math::other::{is_power_of_two, roundup_npo2, transpose}; -use twenty_first::shared_math::traits::FiniteField; +use twenty_first::shared_math::traits::PrimitiveRootOfUnity; use twenty_first::shared_math::x_field_element::XFieldElement; -use crate::fri_domain::FriDomain; +use triton_profiler::triton_profiler::TritonProfiler; +use triton_profiler::{prof_start, prof_stop}; + +use crate::arithmetic_domain::ArithmeticDomain; use crate::table::base_table::{Extendable, InheritsFromTable}; use crate::table::extension_table::DegreeWithOrigin; -use triton_profiler::triton_profiler::TritonProfiler; use super::base_matrix::BaseMatrices; use super::base_table::TableLike; @@ -77,13 +78,13 @@ pub fn interpolant_degree(padded_height: usize, num_trace_randomizers: usize) -> (padded_height + num_trace_randomizers - 1) as Degree } -pub fn derive_omicron(padded_height: u64) -> FF { +pub fn derive_trace_domain_generator(padded_height: u64) -> BFieldElement { debug_assert!( 0 == padded_height || is_power_of_two(padded_height), "The padded height was: {}", padded_height ); - FF::primitive_root_of_unity(padded_height).unwrap() + BFieldElement::primitive_root_of_unity(padded_height).unwrap() } impl BaseTableCollection { @@ -131,67 +132,58 @@ impl BaseTableCollection { roundup_npo2(max_height as u64) as usize } - pub fn to_fri_domain_tables( + pub fn to_quotient_and_fri_domain_tables( &self, - fri_domain: &FriDomain, + quotient_domain: &ArithmeticDomain, + fri_domain: &ArithmeticDomain, num_trace_randomizers: usize, - ) -> BaseTableCollection { - let padded_height = self.padded_height; - let omicron = derive_omicron(padded_height as u64); - - let program_table = self.program_table.to_fri_domain_table( - fri_domain, - omicron, - padded_height, - num_trace_randomizers, - ); - let instruction_table = self.instruction_table.to_fri_domain_table( - fri_domain, - omicron, - padded_height, - num_trace_randomizers, - ); - let processor_table = self.processor_table.to_fri_domain_table( - fri_domain, - omicron, - padded_height, - num_trace_randomizers, - ); - let op_stack_table = self.op_stack_table.to_fri_domain_table( - fri_domain, - omicron, - padded_height, - num_trace_randomizers, - ); - let ram_table = self.ram_table.to_fri_domain_table( - fri_domain, - omicron, - padded_height, - num_trace_randomizers, - ); - let jump_stack_table = self.jump_stack_table.to_fri_domain_table( - fri_domain, - omicron, - padded_height, - num_trace_randomizers, - ); - let hash_table = self.hash_table.to_fri_domain_table( + ) -> (Self, Self) { + let (program_table_quotient, program_table_fri) = self + .program_table + .to_quotient_and_fri_domain_table(quotient_domain, fri_domain, num_trace_randomizers); + let (instruction_table_quotient, instruction_table_fri) = self + .instruction_table + .to_quotient_and_fri_domain_table(quotient_domain, fri_domain, num_trace_randomizers); + let (processor_table_quotient, processor_table_fri) = self + .processor_table + .to_quotient_and_fri_domain_table(quotient_domain, fri_domain, num_trace_randomizers); + let (op_stack_table_quotient, op_stack_table_fri) = self + .op_stack_table + .to_quotient_and_fri_domain_table(quotient_domain, fri_domain, num_trace_randomizers); + let (ram_table_quotient, ram_table_fri) = self.ram_table.to_quotient_and_fri_domain_table( + quotient_domain, fri_domain, - omicron, - padded_height, num_trace_randomizers, ); + let (jump_stack_table_quotient, jump_stack_table_fri) = self + .jump_stack_table + .to_quotient_and_fri_domain_table(quotient_domain, fri_domain, num_trace_randomizers); + let (hash_table_quotient, hash_table_fri) = self + .hash_table + .to_quotient_and_fri_domain_table(quotient_domain, fri_domain, num_trace_randomizers); + + let quotient_domain_tables = BaseTableCollection { + padded_height: self.padded_height, + program_table: program_table_quotient, + instruction_table: instruction_table_quotient, + processor_table: processor_table_quotient, + op_stack_table: op_stack_table_quotient, + ram_table: ram_table_quotient, + jump_stack_table: jump_stack_table_quotient, + hash_table: hash_table_quotient, + }; + let fri_domain_tables = BaseTableCollection { + padded_height: self.padded_height, + program_table: program_table_fri, + instruction_table: instruction_table_fri, + processor_table: processor_table_fri, + op_stack_table: op_stack_table_fri, + ram_table: ram_table_fri, + jump_stack_table: jump_stack_table_fri, + hash_table: hash_table_fri, + }; - BaseTableCollection { - padded_height, - program_table, - instruction_table, - processor_table, - op_stack_table, - ram_table, - jump_stack_table, - hash_table, - } + (quotient_domain_tables, fri_domain_tables) } pub fn get_all_base_columns(&self) -> Vec> { @@ -367,67 +359,58 @@ impl ExtTableCollection { } /// Heads up: only extension columns are being low degree extended. todo: better naming. - pub fn to_fri_domain_tables( + pub fn to_quotient_and_fri_domain_tables( &self, - fri_domain: &FriDomain, + quotient_domain: &ArithmeticDomain, + fri_domain: &ArithmeticDomain, num_trace_randomizers: usize, - ) -> Self { - let padded_height = self.padded_height; - let omicron = derive_omicron(padded_height as u64); - - let program_table = self.program_table.to_fri_domain_table( - fri_domain, - omicron, - padded_height, - num_trace_randomizers, - ); - let instruction_table = self.instruction_table.to_fri_domain_table( - fri_domain, - omicron, - padded_height, - num_trace_randomizers, - ); - let processor_table = self.processor_table.to_fri_domain_table( - fri_domain, - omicron, - padded_height, - num_trace_randomizers, - ); - let op_stack_table = self.op_stack_table.to_fri_domain_table( - fri_domain, - omicron, - padded_height, - num_trace_randomizers, - ); - let ram_table = self.ram_table.to_fri_domain_table( - fri_domain, - omicron, - padded_height, - num_trace_randomizers, - ); - let jump_stack_table = self.jump_stack_table.to_fri_domain_table( - fri_domain, - omicron, - padded_height, - num_trace_randomizers, - ); - let hash_table = self.hash_table.to_fri_domain_table( + ) -> (Self, Self) { + let (program_table_quotient, program_table_fri) = self + .program_table + .to_quotient_and_fri_domain_table(quotient_domain, fri_domain, num_trace_randomizers); + let (instruction_table_quotient, instruction_table_fri) = self + .instruction_table + .to_quotient_and_fri_domain_table(quotient_domain, fri_domain, num_trace_randomizers); + let (processor_table_quotient, processor_table_fri) = self + .processor_table + .to_quotient_and_fri_domain_table(quotient_domain, fri_domain, num_trace_randomizers); + let (op_stack_table_quotient, op_stack_table_fri) = self + .op_stack_table + .to_quotient_and_fri_domain_table(quotient_domain, fri_domain, num_trace_randomizers); + let (ram_table_quotient, ram_table_fri) = self.ram_table.to_quotient_and_fri_domain_table( + quotient_domain, fri_domain, - omicron, - padded_height, num_trace_randomizers, ); + let (jump_stack_table_quotient, jump_stack_table_fri) = self + .jump_stack_table + .to_quotient_and_fri_domain_table(quotient_domain, fri_domain, num_trace_randomizers); + let (hash_table_quotient, hash_table_fri) = self + .hash_table + .to_quotient_and_fri_domain_table(quotient_domain, fri_domain, num_trace_randomizers); + + let quotient_domain_tables = ExtTableCollection { + padded_height: self.padded_height, + program_table: program_table_quotient, + instruction_table: instruction_table_quotient, + processor_table: processor_table_quotient, + op_stack_table: op_stack_table_quotient, + ram_table: ram_table_quotient, + jump_stack_table: jump_stack_table_quotient, + hash_table: hash_table_quotient, + }; + let fri_domain_tables = ExtTableCollection { + padded_height: self.padded_height, + program_table: program_table_fri, + instruction_table: instruction_table_fri, + processor_table: processor_table_fri, + op_stack_table: op_stack_table_fri, + ram_table: ram_table_fri, + jump_stack_table: jump_stack_table_fri, + hash_table: hash_table_fri, + }; - ExtTableCollection { - padded_height, - program_table, - instruction_table, - processor_table, - op_stack_table, - ram_table, - jump_stack_table, - hash_table, - } + (quotient_domain_tables, fri_domain_tables) } pub fn collect_all_columns(&self) -> Vec> { @@ -469,32 +452,28 @@ impl ExtTableCollection { pub fn get_all_quotients( &self, - fri_domain: &FriDomain, + domain: &ArithmeticDomain, challenges: &AllChallenges, maybe_profiler: &mut Option, ) -> Vec> { let padded_height = self.padded_height; - let omicron = derive_omicron(padded_height as u64); + let trace_domain_generator = derive_trace_domain_generator(padded_height as u64); self.into_iter() .map(|ext_codeword_table| { - if let Some(profiler) = maybe_profiler.as_mut() { - profiler.start(&ext_codeword_table.name()); - } + prof_start!(maybe_profiler, &ext_codeword_table.name()); // TODO: Consider if we can use `transposed_ext_codewords` from caller, Stark::prove(). // This would require more complicated indexing, but it would save a lot of allocation. let transposed_codewords = transpose(ext_codeword_table.data()); let res = ext_codeword_table.all_quotients( - fri_domain, + domain, transposed_codewords, challenges, - omicron, + trace_domain_generator, padded_height, maybe_profiler, ); - if let Some(profiler) = maybe_profiler.as_mut() { - profiler.stop(&ext_codeword_table.name()); - } + prof_stop!(maybe_profiler, &ext_codeword_table.name()); res }) .concat()