plonky2/src/gadgets/split_base.rs

101 lines
3.7 KiB
Rust
Raw Normal View History

2021-06-04 16:02:48 +02:00
use crate::circuit_builder::CircuitBuilder;
use crate::field::extension_field::Extendable;
2021-06-14 10:33:38 +02:00
use crate::gates::base_sum::BaseSumGate;
2021-06-04 16:02:48 +02:00
use crate::target::Target;
2021-06-14 10:33:38 +02:00
use crate::util::ceil_div_usize;
2021-06-04 16:02:48 +02:00
impl<F: Extendable<D>, const D: usize> CircuitBuilder<F, D> {
/// Split the given element into a list of targets, where each one represents a
/// base-B limb of the element, with little-endian ordering.
2021-06-10 16:48:05 +02:00
pub(crate) fn split_le_base<const B: usize>(
&mut self,
x: Target,
num_limbs: usize,
) -> Vec<Target> {
2021-06-04 17:07:14 +02:00
let gate = self.add_gate(BaseSumGate::<B>::new(num_limbs), vec![]);
let sum = Target::wire(gate, BaseSumGate::<B>::WIRE_SUM);
2021-06-04 16:02:48 +02:00
self.route(x, sum);
Target::wires_from_range(
gate,
2021-06-15 19:13:15 +02:00
BaseSumGate::<B>::START_LIMBS..BaseSumGate::<B>::START_LIMBS + num_limbs,
)
2021-06-04 16:02:48 +02:00
}
2021-06-16 11:37:07 +02:00
/// Asserts that `x`'s big-endian bit representation has at least `trailing_zeros` trailing zeros.
2021-06-04 17:07:14 +02:00
pub(crate) fn assert_trailing_zeros<const B: usize>(&mut self, x: Target, trailing_zeros: u32) {
2021-06-10 16:48:05 +02:00
let num_limbs = num_limbs(64, B);
2021-06-04 17:07:14 +02:00
let num_limbs_to_check = num_limbs_to_check(trailing_zeros, B);
2021-06-10 16:48:05 +02:00
let limbs = self.split_le_base::<B>(x, num_limbs);
2021-06-04 17:07:14 +02:00
assert!(
2021-06-16 11:37:07 +02:00
num_limbs_to_check <= self.config.num_routed_wires,
2021-06-04 17:07:14 +02:00
"Not enough routed wires."
);
for i in 0..num_limbs_to_check {
2021-06-04 16:02:48 +02:00
self.assert_zero(limbs[i]);
}
}
pub(crate) fn reverse_bits<const B: usize>(&mut self, x: Target, num_limbs: usize) -> Target {
let gate = self.add_gate(BaseSumGate::<B>::new(num_limbs), vec![]);
let sum = Target::wire(gate, BaseSumGate::<B>::WIRE_SUM);
self.route(x, sum);
Target::wire(gate, BaseSumGate::<B>::WIRE_REVERSED_SUM)
}
2021-06-04 16:02:48 +02:00
}
2021-06-04 17:07:14 +02:00
/// Returns `k` such that any number with `k` trailing zeros in base `base` has at least
/// `n` trailing zeros in base 2.
2021-06-10 16:48:05 +02:00
#[allow(unconditional_panic)]
const fn num_limbs_to_check(n: u32, base: usize) -> usize {
2021-06-09 17:55:49 +02:00
if base % 2 == 1 {
// Dirty trick to panic if the base is odd.
// TODO: replace with `assert_eq!(base % 2, 0, "Base should be even.")` when stable.
[][0]
} else {
ceil_div_usize(n as usize, base.trailing_zeros() as usize)
}
2021-06-04 17:07:14 +02:00
}
2021-06-10 16:48:05 +02:00
fn num_limbs(n_log: u32, base: usize) -> usize {
((n_log as f64) * 2.0_f64.log(base as f64)).ceil() as usize
}
2021-06-04 17:07:14 +02:00
#[cfg(test)]
mod tests {
use super::*;
use crate::circuit_data::CircuitConfig;
use crate::field::crandall_field::CrandallField;
2021-06-14 10:37:02 +02:00
use crate::field::field::Field;
use crate::witness::PartialWitness;
2021-06-04 17:07:14 +02:00
#[test]
2021-06-10 16:48:05 +02:00
fn test_split_base() {
2021-06-04 17:07:14 +02:00
type F = CrandallField;
let config = CircuitConfig::large_config();
2021-06-04 17:07:14 +02:00
let mut builder = CircuitBuilder::<F, 4>::new(config);
2021-06-10 16:48:05 +02:00
let x = F::from_canonical_usize(0b110100000); // 416 = 1532 in base 6.
2021-06-04 17:07:14 +02:00
let xt = builder.constant(x);
2021-06-10 16:48:05 +02:00
let limbs = builder.split_le_base::<6>(xt, 24);
2021-06-04 17:07:14 +02:00
let one = builder.one();
let two = builder.two();
2021-06-10 16:48:05 +02:00
let three = builder.constant(F::from_canonical_u64(3));
let five = builder.constant(F::from_canonical_u64(5));
builder.route(limbs[0], two);
builder.route(limbs[1], three);
builder.route(limbs[2], five);
builder.route(limbs[3], one);
let rev = builder.constant(F::from_canonical_u64(11));
let revt = builder.reverse_bits::<2>(xt, 9);
builder.route(revt, rev);
2021-06-04 17:07:14 +02:00
2021-06-10 16:48:05 +02:00
builder.assert_trailing_zeros::<6>(xt, 4);
builder.assert_trailing_zeros::<4>(xt, 5);
builder.assert_trailing_zeros::<12>(xt, 5);
2021-06-04 17:07:14 +02:00
let data = builder.build();
let proof = data.prove(PartialWitness::new());
}
}