Skip to content

Commit

Permalink
QuotientOps (#481)
Browse files Browse the repository at this point in the history
<!-- Reviewable:start -->
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/starkware-libs/stwo/481)
<!-- Reviewable:end -->
  • Loading branch information
spapinistarkware authored Mar 24, 2024
1 parent 584c52d commit 20412e4
Show file tree
Hide file tree
Showing 4 changed files with 128 additions and 0 deletions.
1 change: 1 addition & 0 deletions src/core/backend/cpu/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
mod circle;
mod fri;
pub mod quotients;

use std::fmt::Debug;

Expand Down
95 changes: 95 additions & 0 deletions src/core/backend/cpu/quotients.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
use num_traits::Zero;

use super::CPUBackend;
use crate::core::circle::CirclePoint;
use crate::core::commitment_scheme::quotients::{ColumnSampleBatch, QuotientOps};
use crate::core::constraints::{complex_conjugate_line, pair_vanishing};
use crate::core::fields::m31::BaseField;
use crate::core::fields::qm31::SecureField;
use crate::core::fields::secure_column::SecureColumn;
use crate::core::fields::{ComplexConjugate, FieldExpOps};
use crate::core::poly::circle::{CircleDomain, CircleEvaluation};
use crate::core::poly::BitReversedOrder;
use crate::core::utils::bit_reverse_index;

impl QuotientOps for CPUBackend {
fn accumulate_quotients(
domain: CircleDomain,
columns: &[&CircleEvaluation<Self, BaseField, BitReversedOrder>],
random_coeff: SecureField,
samples: &[ColumnSampleBatch],
) -> SecureColumn<Self> {
let mut res = SecureColumn::zeros(domain.size());
for row in 0..domain.size() {
// TODO(alonh): Make an efficient bit reverse domain iterator, possibly for AVX backend.
let domain_point = domain.at(bit_reverse_index(row, domain.log_size()));
let row_value =
accumulate_row_quotients(samples, columns, row, random_coeff, domain_point);
res.set(row, row_value);
}
res
}
}

pub fn accumulate_row_quotients(
samples: &[ColumnSampleBatch],
columns: &[&CircleEvaluation<CPUBackend, BaseField, BitReversedOrder>],
row: usize,
random_coeff: SecureField,
domain_point: CirclePoint<BaseField>,
) -> SecureField {
let mut row_accumlator = SecureField::zero();
for sample in samples {
let mut numerator = SecureField::zero();
for (column_index, sampled_value) in &sample.column_indices_and_values {
let column = &columns[*column_index];
let value = column[row];
let linear_term = complex_conjugate_line(sample.point, *sampled_value, domain_point);
numerator = numerator * random_coeff + value - linear_term;
}

let denominator = pair_vanishing(
sample.point,
sample.point.complex_conjugate(),
domain_point.into_ef(),
);

row_accumlator = row_accumlator
* random_coeff.pow(sample.column_indices_and_values.len() as u128)
+ numerator / denominator;
}
row_accumlator
}

#[cfg(test)]
mod tests {
use crate::core::backend::cpu::{CPUCircleEvaluation, CPUCirclePoly};
use crate::core::backend::CPUBackend;
use crate::core::circle::SECURE_FIELD_CIRCLE_GEN;
use crate::core::commitment_scheme::quotients::{ColumnSampleBatch, QuotientOps};
use crate::core::poly::circle::CanonicCoset;
use crate::{m31, qm31};

#[test]
fn test_quotients_are_low_degree() {
const LOG_SIZE: u32 = 7;
let polynomial = CPUCirclePoly::new((0..1 << LOG_SIZE).map(|i| m31!(i)).collect());
let eval_domain = CanonicCoset::new(LOG_SIZE + 1).circle_domain();
let eval = polynomial.evaluate(eval_domain);
let point = SECURE_FIELD_CIRCLE_GEN;
let value = polynomial.eval_at_point(point);
let coeff = qm31!(1, 2, 3, 4);
let quot_eval = CPUBackend::accumulate_quotients(
eval_domain,
&[&eval],
coeff,
&[ColumnSampleBatch {
point,
column_indices_and_values: vec![(0, value)],
}],
);
let quot_poly_base_field =
CPUCircleEvaluation::new(eval_domain, quot_eval.columns[0].clone()).interpolate();
assert!(quot_poly_base_field.is_in_fft_space(LOG_SIZE));
}
}
2 changes: 2 additions & 0 deletions src/core/commitment_scheme/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
//! the unique decoding regime. This is enough for a STARK proof though, where we only want to imply
//! the existence of such polynomials, and are ok with having a small decoding list.
//! Note: Opened points cannot come from the commitment domain.
pub mod quotients;
pub mod utils;
use std::iter::zip;
use std::ops::Deref;
Expand Down
30 changes: 30 additions & 0 deletions src/core/commitment_scheme/quotients.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
use crate::core::backend::Backend;
use crate::core::circle::CirclePoint;
use crate::core::fields::m31::BaseField;
use crate::core::fields::qm31::SecureField;
use crate::core::fields::secure_column::SecureColumn;
use crate::core::poly::circle::{CircleDomain, CircleEvaluation};
use crate::core::poly::BitReversedOrder;

pub trait QuotientOps: Backend {
/// Accumulates the quotients of the columns at the given domain.
/// For a column f(x), and a point sample (p,v), the quotient is
/// (f(x) - V0(x))/V1(x)
/// where V0(p)=v, V0(conj(p))=conj(v), and V1 is a vanishing polynomial for p,conj(p).
/// This ensures that if f(p)=v, then the quotient is a polynomial.
/// The result is a linear combination of the quotients using powers of random_coeff.
fn accumulate_quotients(
domain: CircleDomain,
columns: &[&CircleEvaluation<Self, BaseField, BitReversedOrder>],
random_coeff: SecureField,
samples: &[ColumnSampleBatch],
) -> SecureColumn<Self>;
}

/// A batch of column samplings at a point.
pub struct ColumnSampleBatch {
/// The point at which the columns are sampled.
pub point: CirclePoint<SecureField>,
/// The sampled column indices and their values at the point.
pub column_indices_and_values: Vec<(usize, SecureField)>,
}

0 comments on commit 20412e4

Please sign in to comment.