Merge pull request #133 from mir-protocol/exp_gadget

Exponentiation gadget
This commit is contained in:
Nicholas Ward 2021-07-28 17:37:46 -07:00 committed by GitHub
commit f7e9af6f0a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 36 additions and 18 deletions

View File

@ -2,7 +2,10 @@ use std::borrow::Borrow;
use crate::circuit_builder::CircuitBuilder;
use crate::field::extension_field::Extendable;
use crate::gates::exponentiation::ExponentiationGate;
use crate::plonk_common::reduce_with_powers_recursive;
use crate::target::Target;
use crate::util::log2_ceil;
impl<F: Extendable<D>, const D: usize> CircuitBuilder<F, D> {
/// Computes `-x`.
@ -167,7 +170,6 @@ impl<F: Extendable<D>, const D: usize> CircuitBuilder<F, D> {
base
}
// TODO: Optimize this, maybe with a new gate.
// TODO: Test
/// Exponentiate `base` to the power of `exponent`, given by its little-endian bits.
pub fn exp_from_bits(
@ -175,32 +177,36 @@ impl<F: Extendable<D>, const D: usize> CircuitBuilder<F, D> {
base: Target,
exponent_bits: impl Iterator<Item = impl Borrow<Target>>,
) -> Target {
let mut current = base;
let one = self.one();
let mut product = one;
let exp_bits_vec: Vec<Target> = exponent_bits.map(|b| *b.borrow()).collect();
let gate = ExponentiationGate::new(exp_bits_vec.len());
let gate_index = self.add_gate(gate.clone(), vec![]);
for bit in exponent_bits {
let multiplicand = self.select(*bit.borrow(), current, one);
product = self.mul(product, multiplicand);
current = self.mul(current, current);
}
let two = self.constant(F::TWO);
let exponent = reduce_with_powers_recursive(self, &exp_bits_vec[..], two);
product
self.route(base, Target::wire(gate_index, gate.wire_base()));
self.route(exponent, Target::wire(gate_index, gate.wire_power()));
exp_bits_vec.iter().enumerate().for_each(|(i, bit)| {
self.route(*bit, Target::wire(gate_index, gate.wire_power_bit(i)));
});
Target::wire(gate_index, gate.wire_output())
}
// 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.iter())
}
/// Exponentiate `base` to the power of a known `exponent`.
// TODO: Test
pub fn exp_u64(&mut self, base: Target, exponent: u64) -> Target {
let base_ext = self.convert_to_ext(base);
self.exp_u64_extension(base_ext, exponent).0[0]
let exp_target = self.constant(F::from_canonical_u64(exponent));
let num_bits = log2_ceil(exponent as usize + 1);
self.exp(base, exp_target, num_bits)
}
/// Computes `x / y`. Results in an unsatisfiable instance if `y = 0`.

View File

@ -6,7 +6,7 @@ use crate::field::extension_field::Extendable;
use crate::field::field::Field;
use crate::gates::gate::{Gate, GateRef};
use crate::generator::{GeneratedValues, SimpleGenerator, WitnessGenerator};
use crate::plonk_common::{reduce_with_powers, reduce_with_powers_recursive};
use crate::plonk_common::{reduce_with_powers, reduce_with_powers_ext_recursive};
use crate::target::Target;
use crate::vars::{EvaluationTargets, EvaluationVars, EvaluationVarsBase};
use crate::witness::PartialWitness;
@ -80,9 +80,9 @@ impl<F: Extendable<D>, const D: usize, const B: usize> Gate<F, D> for BaseSumGat
let sum = vars.local_wires[Self::WIRE_SUM];
let reversed_sum = vars.local_wires[Self::WIRE_REVERSED_SUM];
let mut limbs = vars.local_wires[self.limbs()].to_vec();
let computed_sum = reduce_with_powers_recursive(builder, &limbs, base);
let computed_sum = reduce_with_powers_ext_recursive(builder, &limbs, base);
limbs.reverse();
let computed_reversed_sum = reduce_with_powers_recursive(builder, &limbs, base);
let computed_reversed_sum = reduce_with_powers_ext_recursive(builder, &limbs, base);
let mut constraints = vec![
builder.sub_extension(computed_sum, sum),
builder.sub_extension(computed_reversed_sum, reversed_sum),

View File

@ -6,7 +6,7 @@ use crate::field::extension_field::Extendable;
use crate::field::field::Field;
use crate::gates::gate::Gate;
use crate::generator::{GeneratedValues, SimpleGenerator, WitnessGenerator};
use crate::plonk_common::{reduce_with_powers, reduce_with_powers_recursive};
use crate::plonk_common::{reduce_with_powers, reduce_with_powers_ext_recursive};
use crate::target::Target;
use crate::vars::{EvaluationTargets, EvaluationVars, EvaluationVarsBase};
use crate::wire::Wire;
@ -160,7 +160,7 @@ impl<F: Extendable<D>, const D: usize> Gate<F, D> for ExponentiationGate<F, D> {
let mut constraints = Vec::new();
let two = builder.constant(F::TWO);
let computed_power = reduce_with_powers_recursive(builder, &power_bits, two);
let computed_power = reduce_with_powers_ext_recursive(builder, &power_bits, two);
let power_diff = builder.sub_extension(power, computed_power);
constraints.push(power_diff);

View File

@ -158,6 +158,18 @@ pub(crate) fn reduce_with_powers<F: Field>(terms: &[F], alpha: F) -> F {
}
pub(crate) fn reduce_with_powers_recursive<F: Extendable<D>, const D: usize>(
builder: &mut CircuitBuilder<F, D>,
terms: &[Target],
alpha: Target,
) -> Target {
let mut sum = builder.zero();
for &term in terms.iter().rev() {
sum = builder.mul_add(sum, alpha, term);
}
sum
}
pub(crate) fn reduce_with_powers_ext_recursive<F: Extendable<D>, const D: usize>(
builder: &mut CircuitBuilder<F, D>,
terms: &[ExtensionTarget<D>],
alpha: Target,