2021-04-21 22:31:45 +02:00
|
|
|
use crate::circuit_builder::CircuitBuilder;
|
2021-05-30 13:25:53 -07:00
|
|
|
use crate::field::extension_field::Extendable;
|
2021-03-18 12:44:45 -07:00
|
|
|
use crate::field::field::Field;
|
2021-06-09 17:39:45 +02:00
|
|
|
use crate::gates::base_sum::BaseSumGate;
|
2021-03-18 12:44:45 -07:00
|
|
|
use crate::generator::{SimpleGenerator, WitnessGenerator};
|
|
|
|
|
use crate::target::Target;
|
2021-06-09 17:39:45 +02:00
|
|
|
use crate::util::ceil_div_usize;
|
2021-03-18 12:44:45 -07:00
|
|
|
use crate::wire::Wire;
|
2021-03-30 20:16:20 -07:00
|
|
|
use crate::witness::PartialWitness;
|
2021-03-18 12:44:45 -07:00
|
|
|
|
2021-05-30 13:25:53 -07:00
|
|
|
impl<F: Extendable<D>, const D: usize> CircuitBuilder<F, D> {
|
2021-07-01 08:12:12 -07:00
|
|
|
/// Split the given integer into a list of virtual targets, where each one represents a bit of
|
|
|
|
|
/// the integer, with little-endian ordering.
|
2021-04-12 10:38:07 +02:00
|
|
|
///
|
|
|
|
|
/// Note that this only handles witness generation; it does not enforce that the decomposition
|
|
|
|
|
/// is correct. The output should be treated as a "purported" decomposition which must be
|
|
|
|
|
/// enforced elsewhere.
|
2021-04-21 22:31:45 +02:00
|
|
|
pub(crate) fn split_le_virtual(&mut self, integer: Target, num_bits: usize) -> Vec<Target> {
|
2021-07-01 08:12:12 -07:00
|
|
|
let bit_targets = self.add_virtual_targets(num_bits);
|
2021-04-22 09:27:59 +02:00
|
|
|
self.add_generator(SplitGenerator {
|
|
|
|
|
integer,
|
|
|
|
|
bits: bit_targets.clone(),
|
|
|
|
|
});
|
2021-04-12 10:38:07 +02:00
|
|
|
bit_targets
|
|
|
|
|
}
|
2021-06-09 17:39:45 +02:00
|
|
|
|
|
|
|
|
/// Split the given integer into a list of wires, where each one represents a
|
|
|
|
|
/// bit of the integer, with little-endian ordering.
|
|
|
|
|
/// Verifies that the decomposition is correct by using `k` `BaseSum<2>` gates
|
2021-06-11 16:22:29 +02:00
|
|
|
/// with `k` such that `k*num_routed_wires>=num_bits`.
|
|
|
|
|
pub(crate) fn split_le(&mut self, integer: Target, num_bits: usize) -> Vec<Target> {
|
2021-06-16 11:17:45 +02:00
|
|
|
if num_bits == 0 {
|
|
|
|
|
return Vec::new();
|
|
|
|
|
}
|
2021-06-16 11:37:07 +02:00
|
|
|
let bits_per_gate = self.config.num_routed_wires - BaseSumGate::<2>::START_LIMBS;
|
|
|
|
|
let k = ceil_div_usize(num_bits, bits_per_gate);
|
2021-06-09 17:39:45 +02:00
|
|
|
let gates = (0..k)
|
2021-06-16 11:37:07 +02:00
|
|
|
.map(|_| self.add_gate_no_constants(BaseSumGate::<2>::new(bits_per_gate)))
|
2021-06-09 17:39:45 +02:00
|
|
|
.collect::<Vec<_>>();
|
|
|
|
|
|
2021-06-11 16:22:29 +02:00
|
|
|
let mut bits = Vec::with_capacity(num_bits);
|
2021-06-09 17:39:45 +02:00
|
|
|
for &gate in &gates {
|
|
|
|
|
bits.extend(Target::wires_from_range(
|
|
|
|
|
gate,
|
2021-06-16 11:37:07 +02:00
|
|
|
BaseSumGate::<2>::START_LIMBS..BaseSumGate::<2>::START_LIMBS + bits_per_gate,
|
2021-06-09 17:39:45 +02:00
|
|
|
));
|
|
|
|
|
}
|
2021-06-11 16:22:29 +02:00
|
|
|
bits.drain(num_bits..);
|
2021-06-09 17:39:45 +02:00
|
|
|
|
|
|
|
|
let zero = self.zero();
|
2021-06-16 11:37:07 +02:00
|
|
|
let one = self.one();
|
2021-06-09 17:39:45 +02:00
|
|
|
let mut acc = zero;
|
|
|
|
|
for &gate in gates.iter().rev() {
|
2021-06-09 17:55:49 +02:00
|
|
|
let sum = Target::wire(gate, BaseSumGate::<2>::WIRE_SUM);
|
2021-06-09 17:39:45 +02:00
|
|
|
acc = self.arithmetic(
|
2021-06-16 11:37:07 +02:00
|
|
|
F::from_canonical_usize(1 << bits_per_gate),
|
2021-06-09 17:39:45 +02:00
|
|
|
acc,
|
2021-06-16 11:37:07 +02:00
|
|
|
one,
|
2021-06-09 17:39:45 +02:00
|
|
|
F::ONE,
|
|
|
|
|
sum,
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
self.assert_equal(acc, integer);
|
|
|
|
|
|
|
|
|
|
self.add_generator(WireSplitGenerator {
|
|
|
|
|
integer,
|
|
|
|
|
gates,
|
2021-06-16 11:37:07 +02:00
|
|
|
num_limbs: bits_per_gate,
|
2021-06-09 17:39:45 +02:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
bits
|
|
|
|
|
}
|
2021-04-12 10:38:07 +02:00
|
|
|
}
|
2021-03-18 12:44:45 -07:00
|
|
|
|
|
|
|
|
/// Generator for a little-endian split.
|
2021-04-12 10:18:16 -07:00
|
|
|
#[must_use]
|
2021-03-18 12:44:45 -07:00
|
|
|
pub fn split_le_generator<F: Field>(
|
|
|
|
|
integer: Target,
|
|
|
|
|
bits: Vec<Target>,
|
|
|
|
|
) -> Box<dyn WitnessGenerator<F>> {
|
|
|
|
|
Box::new(SplitGenerator { integer, bits })
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Generator for a little-endian split.
|
2021-04-12 10:18:16 -07:00
|
|
|
#[must_use]
|
2021-03-18 12:44:45 -07:00
|
|
|
pub fn split_le_generator_local_wires<F: Field>(
|
|
|
|
|
gate: usize,
|
|
|
|
|
integer_input_index: usize,
|
|
|
|
|
bit_input_indices: &[usize],
|
|
|
|
|
) -> Box<dyn WitnessGenerator<F>> {
|
2021-04-21 22:31:45 +02:00
|
|
|
let integer = Target::Wire(Wire {
|
|
|
|
|
gate,
|
|
|
|
|
input: integer_input_index,
|
|
|
|
|
});
|
|
|
|
|
let bits = bit_input_indices
|
|
|
|
|
.iter()
|
2021-03-18 12:44:45 -07:00
|
|
|
.map(|&input| Target::Wire(Wire { gate, input }))
|
|
|
|
|
.collect();
|
|
|
|
|
Box::new(SplitGenerator { integer, bits })
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-25 15:20:14 -07:00
|
|
|
#[derive(Debug)]
|
2021-03-18 12:44:45 -07:00
|
|
|
struct SplitGenerator {
|
|
|
|
|
integer: Target,
|
|
|
|
|
bits: Vec<Target>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<F: Field> SimpleGenerator<F> for SplitGenerator {
|
|
|
|
|
fn dependencies(&self) -> Vec<Target> {
|
|
|
|
|
vec![self.integer]
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-21 11:17:00 -07:00
|
|
|
fn run_once(&self, witness: &PartialWitness<F>) -> PartialWitness<F> {
|
2021-03-18 12:44:45 -07:00
|
|
|
let mut integer_value = witness.get_target(self.integer).to_canonical_u64();
|
|
|
|
|
|
|
|
|
|
let mut result = PartialWitness::new();
|
|
|
|
|
for &b in &self.bits {
|
|
|
|
|
let b_value = integer_value & 1;
|
|
|
|
|
result.set_target(b, F::from_canonical_u64(b_value));
|
|
|
|
|
integer_value >>= 1;
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-21 22:31:45 +02:00
|
|
|
debug_assert_eq!(
|
|
|
|
|
integer_value, 0,
|
|
|
|
|
"Integer too large to fit in given number of bits"
|
|
|
|
|
);
|
2021-03-18 12:44:45 -07:00
|
|
|
|
|
|
|
|
result
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-06-09 17:39:45 +02:00
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
|
struct WireSplitGenerator {
|
|
|
|
|
integer: Target,
|
|
|
|
|
gates: Vec<usize>,
|
|
|
|
|
num_limbs: usize,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<F: Field> SimpleGenerator<F> for WireSplitGenerator {
|
|
|
|
|
fn dependencies(&self) -> Vec<Target> {
|
|
|
|
|
vec![self.integer]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn run_once(&self, witness: &PartialWitness<F>) -> PartialWitness<F> {
|
|
|
|
|
let mut integer_value = witness.get_target(self.integer).to_canonical_u64();
|
|
|
|
|
|
|
|
|
|
let mut result = PartialWitness::new();
|
2021-06-09 17:55:49 +02:00
|
|
|
for &gate in &self.gates {
|
|
|
|
|
let sum = Target::wire(gate, BaseSumGate::<2>::WIRE_SUM);
|
2021-06-09 17:39:45 +02:00
|
|
|
result.set_target(
|
|
|
|
|
sum,
|
|
|
|
|
F::from_canonical_u64(integer_value & ((1 << self.num_limbs) - 1)),
|
|
|
|
|
);
|
2021-06-10 16:48:05 +02:00
|
|
|
integer_value >>= self.num_limbs;
|
2021-06-09 17:39:45 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
debug_assert_eq!(
|
|
|
|
|
integer_value,
|
|
|
|
|
0,
|
|
|
|
|
"Integer too large to fit in {} many `BaseSumGate`s",
|
|
|
|
|
self.gates.len()
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
result
|
|
|
|
|
}
|
|
|
|
|
}
|