Skip to content

Commit

Permalink
refactor(squash_me): Move zerofier to Domain
Browse files Browse the repository at this point in the history
  • Loading branch information
jan-ferdinand committed Oct 9, 2024
1 parent c261878 commit 940dc06
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 35 deletions.
43 changes: 42 additions & 1 deletion triton-vm/src/arithmetic_domain.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
use std::ops::Mul;
use std::ops::MulAssign;

use num_traits::ConstOne;
use num_traits::One;
use num_traits::Zero;
use rayon::prelude::*;
use twenty_first::math::traits::FiniteField;
use twenty_first::math::traits::PrimitiveRootOfUnity;
Expand All @@ -27,7 +29,7 @@ impl ArithmeticDomain {
/// Errors if the domain length is not a power of 2.
pub fn of_length(length: usize) -> Result<Self> {
let domain = Self {
offset: bfe!(1),
offset: BFieldElement::ONE,
generator: Self::generator_for_length(length as u64)?,
length,
};
Expand Down Expand Up @@ -126,6 +128,29 @@ impl ArithmeticDomain {
domain_values
}

/// A polynomial that evaluates to 0 on (and only on)
/// a [domain value][Self::domain_values].
pub fn zerofier(&self) -> Polynomial<BFieldElement> {
if self.offset.is_zero() {
return Polynomial::x_to_the(1);
}

Polynomial::x_to_the(self.length)
- Polynomial::from_constant(self.offset.mod_pow(self.length as u64))
}

/// [`Self::zerofier`] times the argument.
/// More performant than polynomial multiplication.
/// See [`Self::zerofier`] for details.
pub fn mul_zerofier_with<FF>(&self, polynomial: Polynomial<FF>) -> Polynomial<FF>
where
FF: FiniteField + Mul<BFieldElement, Output = FF>,
{
// use knowledge of zerofier's shape for faster multiplication
polynomial.shift_coefficients(self.length)
- polynomial.scalar_mul(self.offset.mod_pow(self.length as u64))
}

pub(crate) fn halve(&self) -> Result<Self> {
if self.length < 2 {
return Err(ArithmeticDomainError::TooSmallForHalving(self.length));
Expand Down Expand Up @@ -316,4 +341,20 @@ mod tests {
let values1 = polynomial.batch_evaluate(&domain.domain_values());
assert_eq!(values0, values1);
}

#[proptest]
fn zerofier_is_actually_zerofier(#[strategy(arbitrary_domain())] domain: ArithmeticDomain) {
let actual_zerofier = Polynomial::zerofier(&domain.domain_values());
prop_assert_eq!(actual_zerofier, domain.zerofier());
}

#[proptest]
fn multiplication_with_zerofier_is_identical_to_method_mul_with_zerofier(
#[strategy(arbitrary_domain())] domain: ArithmeticDomain,
#[strategy(arbitrary_polynomial())] polynomial: Polynomial<XFieldElement>,
) {
let mul = domain.zerofier() * polynomial.clone();
let mul_with = domain.mul_zerofier_with(polynomial);
prop_assert_eq!(mul, mul_with);
}
}
53 changes: 19 additions & 34 deletions triton-vm/src/table/master_table.rs
Original file line number Diff line number Diff line change
Expand Up @@ -327,7 +327,7 @@ where
.inverse();

let ood_trace_domain_zerofier: XFieldElement =
self.trace_domain_zerofier().evaluate(indeterminate);
self.trace_domain().zerofier().evaluate(indeterminate);

let trace_table = self.trace_table();
(0..Self::NUM_COLUMNS)
Expand Down Expand Up @@ -357,42 +357,27 @@ where
.trace_domain()
.interpolate(column_codeword.as_slice().unwrap());

let randomizer = self.mul_trace_domain_zerofier_with(self.trace_randomizer_for_column(idx));
let randomizer = self
.trace_domain()
.mul_zerofier_with(self.trace_randomizer_for_column(idx));

column_interpolant + randomizer
}

/// The zerofier for the [trace domain][Self::trace_domain]. When used in
/// combination with a [trace randomizer][Self::trace_randomizer_for_column],
/// this zerofier makes sure that the trace is not influenced anywhere on the
/// trace domain. In particular, use the following formula:
/// When added to a column in the correct way (see below), allows revealing up
/// to `num_trace_randomizers` entries of the column without breaking
/// zero-knowledge.
///
/// `column + zerofier·randomizer`
/// In order for the trace randomizer to not influence the trace on the
/// [trace domain][Self::trace_domain], it must be multiplied with a polynomial
/// that evaluates to zero on that domain. The polynomial of lowest degree with
/// this property is the corresponding [zerofier][ArithmeticDomain::zerofier].
/// The randomized trace column interpolant can then be obtained through:
///
/// If _only_ the randomized column is needed, see
/// [`Self::randomized_column_interpolant`].
/// `column + zerofier·randomizer`
///
/// If you _only_ need this zerofier for multiplication, see
/// [`Self::mul_trace_domain_zerofier_with`], which is faster for
/// this particular operation.
fn trace_domain_zerofier(&self) -> Polynomial<BFieldElement> {
Polynomial::x_to_the(self.trace_domain().length) - Polynomial::one()
}

/// [`Self::trace_domain_zerofier`] times the argument.
/// See [`Self::trace_domain_zerofier`] for more details.
fn mul_trace_domain_zerofier_with<FF: FiniteField>(
&self,
poly: Polynomial<FF>,
) -> Polynomial<FF> {
// use knowledge of zerofier's shape for faster multiplication
poly.shift_coefficients(self.trace_domain().length) - poly
}

/// When added to a column in the correct way (see
/// [`Self::trace_domain_zerofier`]), allows revealing up to
/// `num_trace_randomizers` entries of the column without breaking
/// zero-knowledge.
/// If you want to multiply the trace randomizer with the zerofier, the most
/// performant approach is [`ArithmeticDomain::mul_zerofier_with`].
///
/// # Panics
///
Expand Down Expand Up @@ -510,8 +495,9 @@ where
.enumerate()
.map(|(i, &w)| self.trace_randomizer_for_column(i).scalar_mul(w))
.reduce(Polynomial::zero, |sum, x| sum + x);
let randomizer_contribution =
self.mul_trace_domain_zerofier_with(weighted_sum_of_trace_randomizer_polynomials);
let randomizer_contribution = self
.trace_domain()
.mul_zerofier_with(weighted_sum_of_trace_randomizer_polynomials);

weighted_sum_of_trace_columns + randomizer_contribution
}
Expand Down Expand Up @@ -546,10 +532,9 @@ where
// add trace randomizers to their columns
// todo: this could be done using `Polynomial::batch_evaluate` if that function
// had more general trait bounds 🤷
let zerofier = self.trace_domain_zerofier();
let zerofier_evals = indeterminates
.par_iter()
.map(|&i| zerofier.evaluate::<_, Self::Field>(i))
.map(|&i| self.trace_domain().zerofier().evaluate::<_, Self::Field>(i))
.collect::<Vec<_>>();

let trace_randomizers = (0..Self::NUM_COLUMNS)
Expand Down

0 comments on commit 940dc06

Please sign in to comment.