Merge pull request #118 from mir-protocol/avoid_rotating

Avoid rotating in `compute_evaluation`
This commit is contained in:
wborgeaud 2021-07-22 11:23:45 +02:00 committed by GitHub
commit 1d5cd4430e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 44 additions and 10 deletions

View File

@ -28,20 +28,26 @@ impl<F: Extendable<D>, const D: usize> CircuitBuilder<F, D> {
debug_assert_eq!(last_evals.len(), 1 << arity_bits);
let g = F::primitive_root_of_unity(arity_bits);
let gt = self.constant(g);
// The evaluation vector needs to be reordered first.
let mut evals = last_evals.to_vec();
reverse_index_bits_in_place(&mut evals);
let mut old_x_index_bits = self.split_le(old_x_index, arity_bits);
old_x_index_bits.reverse();
let evals = self.rotate_left_from_bits(&old_x_index_bits, &evals);
// Want `g^(arity - rev_old_x_index)` as in the out-of-circuit version.
// Compute it as `g^(arity-1-rev_old_x_index) * g`, where the first term is gotten using two's complement.
// TODO: Once the exponentiation gate lands, we won't need the bits and will be able to compute
// `g^(arity-rev_old_x_index)` directly.
let start = self.exp_from_complement_bits(gt, &old_x_index_bits);
let coset_start = self.mul_many(&[start, gt, x]);
// The answer is gotten by interpolating {(x*g^i, P(x*g^i))} and evaluating at beta.
let points = g
.powers()
.map(|y| {
let yt = self.constant(y);
self.mul(x, yt)
self.mul(coset_start, yt)
})
.zip(evals)
.collect::<Vec<_>>();

View File

@ -22,20 +22,21 @@ fn compute_evaluation<F: Field + Extendable<D>, const D: usize>(
last_evals: &[F::Extension],
beta: F::Extension,
) -> F::Extension {
debug_assert_eq!(last_evals.len(), 1 << arity_bits);
let arity = 1 << arity_bits;
debug_assert_eq!(last_evals.len(), arity);
let g = F::primitive_root_of_unity(arity_bits);
// The evaluation vector needs to be reordered first.
let mut evals = last_evals.to_vec();
reverse_index_bits_in_place(&mut evals);
evals.rotate_left(reverse_bits(old_x_index, arity_bits));
let rev_old_x_index = reverse_bits(old_x_index, arity_bits);
let coset_start = x * g.exp((arity - rev_old_x_index) as u64);
// The answer is gotten by interpolating {(x*g^i, P(x*g^i))} and evaluating at beta.
let points = g
.powers()
.zip(evals)
.map(|(y, e)| ((x * y).into(), e))
.map(|(y, e)| ((coset_start * y).into(), e))
.collect::<Vec<_>>();
let barycentric_weights = barycentric_weights(&points);
interpolate(&points, beta, &barycentric_weights)

View File

@ -167,14 +167,14 @@ impl<F: Extendable<D>, const D: usize> CircuitBuilder<F, D> {
// TODO: Optimize this, maybe with a new gate.
// TODO: Test
/// Exponentiate `base` to the power of `exponent`, where `exponent < 2^num_bits`.
pub fn exp(&mut self, base: Target, exponent: Target, num_bits: usize) -> Target {
/// Exponentiate `base` to the power of `exponent`, given by its little-endian bits.
pub fn exp_from_bits(&mut self, base: Target, exponent_bits: &[Target]) -> Target {
let mut current = base;
let one_ext = self.one_extension();
let mut product = self.one();
let exponent_bits = self.split_le(exponent, num_bits);
for bit in exponent_bits.into_iter() {
for &bit in exponent_bits {
// TODO: Add base field select.
let current_ext = self.convert_to_ext(current);
let multiplicand = self.select(bit, current_ext, one_ext);
product = self.mul(product, multiplicand.0[0]);
@ -184,6 +184,33 @@ impl<F: Extendable<D>, const D: usize> CircuitBuilder<F, D> {
product
}
// TODO: Optimize this, maybe with a new gate.
// TODO: Test
/// Exponentiate `base` to the power of `2^bit_length-1-exponent`, given by its little-endian bits.
pub fn exp_from_complement_bits(&mut self, base: Target, exponent_bits: &[Target]) -> Target {
let mut current = base;
let one_ext = self.one_extension();
let mut product = self.one();
for &bit in exponent_bits {
let current_ext = self.convert_to_ext(current);
// TODO: Add base field select.
let multiplicand = self.select(bit, one_ext, current_ext);
product = self.mul(product, multiplicand.0[0]);
current = self.mul(current, current);
}
product
}
// TODO: Optimize this, maybe with a new gate.
// TODO: Test
/// Exponentiate `base` to the power of `exponent`, where `exponent < 2^num_bits`.
pub fn exp(&mut self, base: Target, exponent: Target, num_bits: usize) -> Target {
let exponent_bits = self.split_le(exponent, num_bits);
self.exp_from_bits(base, &exponent_bits)
}
/// Exponentiate `base` to the power of a known `exponent`.
// TODO: Test
pub fn exp_u64(&mut self, base: Target, exponent: u64) -> Target {