Skip to content

Commit

Permalink
Precompute complex conjugate line constants. (#546)
Browse files Browse the repository at this point in the history
  • Loading branch information
alonh5 authored Mar 27, 2024
1 parent 50c8a20 commit 6594763
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 12 deletions.
60 changes: 49 additions & 11 deletions src/core/backend/cpu/quotients.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
use num_traits::Zero;
use itertools::zip_eq;
use num_traits::{One, 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::commitment_scheme::quotients::{ColumnSampleBatch, PointSample, QuotientOps};
use crate::core::constraints::{complex_conjugate_line_coefficients, pair_vanishing};
use crate::core::fields::m31::BaseField;
use crate::core::fields::qm31::SecureField;
use crate::core::fields::secure_column::SecureColumn;
Expand All @@ -20,11 +21,19 @@ impl QuotientOps for CPUBackend {
sample_batches: &[ColumnSampleBatch],
) -> SecureColumn<Self> {
let mut res = SecureColumn::zeros(domain.size());
let column_constants = column_constants(sample_batches, random_coeff);

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(sample_batches, columns, row, random_coeff, domain_point);
let row_value = accumulate_row_quotients(
sample_batches,
columns,
&column_constants,
row,
random_coeff,
domain_point,
);
res.set(row, row_value);
}
res
Expand All @@ -34,19 +43,21 @@ impl QuotientOps for CPUBackend {
pub fn accumulate_row_quotients(
sample_batches: &[ColumnSampleBatch],
columns: &[&CircleEvaluation<CPUBackend, BaseField, BitReversedOrder>],
column_constants: &[Vec<(SecureField, SecureField, SecureField)>],
row: usize,
random_coeff: SecureField,
domain_point: CirclePoint<BaseField>,
) -> SecureField {
let mut row_accumulator = SecureField::zero();
for sample_batch in sample_batches {
for (sample_batch, sample_constants) in zip_eq(sample_batches, column_constants) {
let mut numerator = SecureField::zero();
for (column_index, sampled_value) in &sample_batch.columns_and_values {
for ((column_index, _sampled_value), (a, b, c)) in
zip_eq(&sample_batch.columns_and_values, sample_constants)
{
let column = &columns[*column_index];
let value = column[row];
let linear_term =
complex_conjugate_line(sample_batch.point, *sampled_value, domain_point);
numerator = numerator * random_coeff + value - linear_term;
let value = column[row] * *c;
let linear_term = *a * domain_point.y + *b;
numerator += value - linear_term;
}

let denominator = pair_vanishing(
Expand All @@ -62,6 +73,33 @@ pub fn accumulate_row_quotients(
row_accumulator
}

/// Precompute the complex conjugate line constants for each column in each sample batch.
/// Specifically, for the i-th (in a sample batch) column's numerator term
/// `alpha^i * (F(p) - (a * p.y + b))`, we precompute the constants `alpha^i * a` and alpha^i * `b`.
pub fn column_constants(
sample_batches: &[ColumnSampleBatch],
random_coeff: SecureField,
) -> Vec<Vec<(SecureField, SecureField, SecureField)>> {
sample_batches
.iter()
.map(|sample_batch| {
let mut alpha = SecureField::one();
sample_batch
.columns_and_values
.iter()
.map(|(_, sampled_value)| {
alpha *= random_coeff;
let sample = PointSample {
point: sample_batch.point,
value: *sampled_value,
};
complex_conjugate_line_coefficients(&sample, alpha)
})
.collect()
})
.collect()
}

#[cfg(test)]
mod tests {
use crate::core::backend::cpu::{CPUCircleEvaluation, CPUCirclePoly};
Expand Down
5 changes: 4 additions & 1 deletion src/core/commitment_scheme/quotients.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use std::iter::zip;

use itertools::{izip, multiunzip, Itertools};

use crate::core::backend::cpu::quotients::accumulate_row_quotients;
use crate::core::backend::cpu::quotients::{accumulate_row_quotients, column_constants};
use crate::core::backend::Backend;
use crate::core::circle::CirclePoint;
use crate::core::fields::m31::BaseField;
Expand Down Expand Up @@ -39,6 +39,7 @@ pub struct ColumnSampleBatch {
/// The sampled column indices and their values at the point.
pub columns_and_values: Vec<(usize, SecureField)>,
}

impl ColumnSampleBatch {
/// Groups column samples by sampled point.
/// # Arguments
Expand Down Expand Up @@ -124,6 +125,7 @@ pub fn fri_answers_for_log_size(
) -> Result<SparseCircleEvaluation<SecureField>, VerificationError> {
let commitment_domain = CanonicCoset::new(log_size).circle_domain();
let sample_batches = ColumnSampleBatch::new_vec(samples);
let column_constants = column_constants(&sample_batches, random_coeff);
for queried_values in queried_values_per_column {
if queried_values.len() != query_domain.flatten().len() {
return Err(VerificationError::InvalidStructure(
Expand Down Expand Up @@ -154,6 +156,7 @@ pub fn fri_answers_for_log_size(
let value = accumulate_row_quotients(
&sample_batches,
&column_evals.iter().collect_vec(),
&column_constants,
row,
random_coeff,
domain_point,
Expand Down

0 comments on commit 6594763

Please sign in to comment.