FRI tweaks (#111)

- Call `exp_power_of_2` instead of manual squaring
- Replace `evaluations[i]` with `evals`
This commit is contained in:
Daniel Lubarov 2021-07-20 12:49:02 -07:00 committed by GitHub
parent dff950c502
commit ac1872a8c8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 22 additions and 20 deletions

View File

@ -246,7 +246,6 @@ impl<F: Extendable<D>, const D: usize> CircuitBuilder<F, D> {
) { ) {
let config = &common_data.config.fri_config; let config = &common_data.config.fri_config;
let n_log = log2_strict(n); let n_log = log2_strict(n);
let mut evaluations: Vec<Vec<ExtensionTarget<D>>> = Vec::new();
// TODO: Do we need to range check `x_index` to a target smaller than `p`? // TODO: Do we need to range check `x_index` to a target smaller than `p`?
let mut x_index = challenger.get_challenge(self); let mut x_index = challenger.get_challenge(self);
x_index = self.split_low_high(x_index, n_log, 64).0; x_index = self.split_low_high(x_index, n_log, 64).0;
@ -273,6 +272,7 @@ impl<F: Extendable<D>, const D: usize> CircuitBuilder<F, D> {
self.mul(g, phi) self.mul(g, phi)
}); });
let mut evaluations: Vec<Vec<ExtensionTarget<D>>> = Vec::new();
for (i, &arity_bits) in config.reduction_arity_bits.iter().enumerate() { for (i, &arity_bits) in config.reduction_arity_bits.iter().enumerate() {
let next_domain_size = domain_size >> arity_bits; let next_domain_size = domain_size >> arity_bits;
let e_x = if i == 0 { let e_x = if i == 0 {
@ -308,23 +308,21 @@ impl<F: Extendable<D>, const D: usize> CircuitBuilder<F, D> {
let (low_x_index, high_x_index) = let (low_x_index, high_x_index) =
self.split_low_high(x_index, arity_bits, x_index_num_bits); self.split_low_high(x_index, arity_bits, x_index_num_bits);
evals = self.insert(low_x_index, e_x, evals); evals = self.insert(low_x_index, e_x, evals);
evaluations.push(evals);
context!( context!(
self, self,
"verify FRI round Merkle proof.", "verify FRI round Merkle proof.",
self.verify_merkle_proof( self.verify_merkle_proof(
flatten_target(&evaluations[i]), flatten_target(&evals),
high_x_index, high_x_index,
proof.commit_phase_merkle_roots[i], proof.commit_phase_merkle_roots[i],
&round_proof.steps[i].merkle_proof, &round_proof.steps[i].merkle_proof,
) )
); );
evaluations.push(evals);
if i > 0 { if i > 0 {
// Update the point x to x^arity. // Update the point x to x^arity.
for _ in 0..config.reduction_arity_bits[i - 1] { subgroup_x = self.exp_power_of_2(subgroup_x, config.reduction_arity_bits[i - 1]);
subgroup_x = self.square(subgroup_x);
}
} }
domain_size = next_domain_size; domain_size = next_domain_size;
old_x_index = low_x_index; old_x_index = low_x_index;
@ -345,9 +343,7 @@ impl<F: Extendable<D>, const D: usize> CircuitBuilder<F, D> {
*betas.last().unwrap(), *betas.last().unwrap(),
) )
); );
for _ in 0..final_arity_bits { subgroup_x = self.exp_power_of_2(subgroup_x, final_arity_bits);
subgroup_x = self.square(subgroup_x);
}
// Final check of FRI. After all the reductions, we check that the final polynomial is equal // Final check of FRI. After all the reductions, we check that the final polynomial is equal
// to the one sent by the prover. // to the one sent by the prover.

View File

@ -248,7 +248,6 @@ fn fri_verifier_query_round<F: Field + Extendable<D>, const D: usize>(
common_data: &CommonCircuitData<F, D>, common_data: &CommonCircuitData<F, D>,
) -> Result<()> { ) -> Result<()> {
let config = &common_data.config.fri_config; let config = &common_data.config.fri_config;
let mut evaluations: Vec<Vec<F::Extension>> = Vec::new();
let x = challenger.get_challenge(); let x = challenger.get_challenge();
let mut domain_size = n; let mut domain_size = n;
let mut x_index = x.to_canonical_u64() as usize % n; let mut x_index = x.to_canonical_u64() as usize % n;
@ -262,6 +261,8 @@ fn fri_verifier_query_round<F: Field + Extendable<D>, const D: usize>(
let log_n = log2_strict(n); let log_n = log2_strict(n);
let mut subgroup_x = F::MULTIPLICATIVE_GROUP_GENERATOR let mut subgroup_x = F::MULTIPLICATIVE_GROUP_GENERATOR
* F::primitive_root_of_unity(log_n).exp(reverse_bits(x_index, log_n) as u64); * F::primitive_root_of_unity(log_n).exp(reverse_bits(x_index, log_n) as u64);
let mut evaluations: Vec<Vec<F::Extension>> = Vec::new();
for (i, &arity_bits) in config.reduction_arity_bits.iter().enumerate() { for (i, &arity_bits) in config.reduction_arity_bits.iter().enumerate() {
let arity = 1 << arity_bits; let arity = 1 << arity_bits;
let next_domain_size = domain_size >> arity_bits; let next_domain_size = domain_size >> arity_bits;
@ -288,20 +289,18 @@ fn fri_verifier_query_round<F: Field + Extendable<D>, const D: usize>(
let mut evals = round_proof.steps[i].evals.clone(); let mut evals = round_proof.steps[i].evals.clone();
// Insert P(y) into the evaluation vector, since it wasn't included by the prover. // Insert P(y) into the evaluation vector, since it wasn't included by the prover.
evals.insert(x_index & (arity - 1), e_x); evals.insert(x_index & (arity - 1), e_x);
evaluations.push(evals);
verify_merkle_proof( verify_merkle_proof(
flatten(&evaluations[i]), flatten(&evals),
x_index >> arity_bits, x_index >> arity_bits,
proof.commit_phase_merkle_roots[i], proof.commit_phase_merkle_roots[i],
&round_proof.steps[i].merkle_proof, &round_proof.steps[i].merkle_proof,
false, false,
)?; )?;
evaluations.push(evals);
if i > 0 { if i > 0 {
// Update the point x to x^arity. // Update the point x to x^arity.
for _ in 0..config.reduction_arity_bits[i - 1] { subgroup_x = subgroup_x.exp_power_of_2(config.reduction_arity_bits[i - 1]);
subgroup_x = subgroup_x.square();
}
} }
domain_size = next_domain_size; domain_size = next_domain_size;
old_x_index = x_index & (arity - 1); old_x_index = x_index & (arity - 1);
@ -317,9 +316,7 @@ fn fri_verifier_query_round<F: Field + Extendable<D>, const D: usize>(
last_evals, last_evals,
*betas.last().unwrap(), *betas.last().unwrap(),
); );
for _ in 0..final_arity_bits { subgroup_x = subgroup_x.exp_power_of_2(final_arity_bits);
subgroup_x = subgroup_x.square();
}
// Final check of FRI. After all the reductions, we check that the final polynomial is equal // Final check of FRI. After all the reductions, we check that the final polynomial is equal
// to the one sent by the prover. // to the one sent by the prover.

View File

@ -153,6 +153,15 @@ impl<F: Extendable<D>, const D: usize> CircuitBuilder<F, D> {
product product
} }
/// Exponentiate `base` to the power of `2^power_log`.
// TODO: Test
pub fn exp_power_of_2(&mut self, mut base: Target, power_log: usize) -> Target {
for _ in 0..power_log {
base = self.square(base);
}
base
}
// TODO: Optimize this, maybe with a new gate. // TODO: Optimize this, maybe with a new gate.
// TODO: Test // TODO: Test
/// Exponentiate `base` to the power of `exponent`, where `exponent < 2^num_bits`. /// Exponentiate `base` to the power of `exponent`, where `exponent < 2^num_bits`.

View File

@ -292,7 +292,7 @@ impl<F: Extendable<D>, const D: usize> CircuitBuilder<F, D> {
/// Exponentiate `base` to the power of `2^power_log`. /// Exponentiate `base` to the power of `2^power_log`.
// TODO: Test // TODO: Test
pub fn exp_power_of_2( pub fn exp_power_of_2_extension(
&mut self, &mut self,
mut base: ExtensionTarget<D>, mut base: ExtensionTarget<D>,
power_log: usize, power_log: usize,

View File

@ -59,7 +59,7 @@ impl<F: Extendable<D>, const D: usize> CircuitBuilder<F, D> {
let s_sigmas = &proof.openings.plonk_sigmas; let s_sigmas = &proof.openings.plonk_sigmas;
let partial_products = &proof.openings.partial_products; let partial_products = &proof.openings.partial_products;
let zeta_pow_deg = self.exp_power_of_2(zeta, inner_common_data.degree_bits); let zeta_pow_deg = self.exp_power_of_2_extension(zeta, inner_common_data.degree_bits);
let vanishing_polys_zeta = context!( let vanishing_polys_zeta = context!(
self, self,
"evaluate the vanishing polynomial at our challenge point, zeta.", "evaluate the vanishing polynomial at our challenge point, zeta.",