../../.cargo/katex-header.html

plonky2/gadgets/
split_join.rs

1#[cfg(not(feature = "std"))]
2use alloc::{
3    string::{String, ToString},
4    vec,
5    vec::Vec,
6};
7
8use anyhow::Result;
9
10use crate::field::extension::Extendable;
11use crate::gates::base_sum::BaseSumGate;
12use crate::hash::hash_types::RichField;
13use crate::iop::generator::{GeneratedValues, SimpleGenerator};
14use crate::iop::target::{BoolTarget, Target};
15use crate::iop::witness::{PartitionWitness, Witness, WitnessWrite};
16use crate::plonk::circuit_builder::CircuitBuilder;
17use crate::plonk::circuit_data::CommonCircuitData;
18use crate::util::serialization::{Buffer, IoResult, Read, Write};
19
20impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
21    /// Split the given integer into a list of wires, where each one represents a
22    /// bit of the integer, with little-endian ordering.
23    /// Verifies that the decomposition is correct by using `k` `BaseSum<2>` gates
24    /// with `k` such that `k * num_routed_wires >= num_bits`.
25    pub fn split_le(&mut self, integer: Target, num_bits: usize) -> Vec<BoolTarget> {
26        if num_bits == 0 {
27            return Vec::new();
28        }
29        let gate_type = BaseSumGate::<2>::new_from_config::<F>(&self.config);
30        let k = num_bits.div_ceil(gate_type.num_limbs);
31        let gates = (0..k)
32            .map(|_| self.add_gate(gate_type, vec![]))
33            .collect::<Vec<_>>();
34
35        let mut bits = Vec::with_capacity(num_bits);
36        for &gate in &gates {
37            for limb_column in gate_type.limbs() {
38                // `new_unsafe` is safe here because BaseSumGate::<2> forces it to be in `{0, 1}`.
39                bits.push(BoolTarget::new_unsafe(Target::wire(gate, limb_column)));
40            }
41        }
42        for b in bits.drain(num_bits..) {
43            self.assert_zero(b.target);
44        }
45
46        let zero = self.zero();
47        let base = F::TWO.exp_u64(gate_type.num_limbs as u64);
48        let mut acc = zero;
49        for &gate in gates.iter().rev() {
50            let sum = Target::wire(gate, BaseSumGate::<2>::WIRE_SUM);
51            acc = self.mul_const_add(base, acc, sum);
52        }
53        self.connect(acc, integer);
54
55        self.add_simple_generator(WireSplitGenerator {
56            integer,
57            gates,
58            num_limbs: gate_type.num_limbs,
59        });
60
61        bits
62    }
63}
64
65#[derive(Debug, Default)]
66pub struct SplitGenerator {
67    integer: Target,
68    bits: Vec<Target>,
69}
70
71impl<F: RichField + Extendable<D>, const D: usize> SimpleGenerator<F, D> for SplitGenerator {
72    fn id(&self) -> String {
73        "SplitGenerator".to_string()
74    }
75
76    fn dependencies(&self) -> Vec<Target> {
77        vec![self.integer]
78    }
79
80    fn run_once(
81        &self,
82        witness: &PartitionWitness<F>,
83        out_buffer: &mut GeneratedValues<F>,
84    ) -> Result<()> {
85        let mut integer_value = witness.get_target(self.integer).to_canonical_u64();
86
87        for &b in &self.bits {
88            let b_value = integer_value & 1;
89            out_buffer.set_target(b, F::from_canonical_u64(b_value))?;
90            integer_value >>= 1;
91        }
92
93        debug_assert_eq!(
94            integer_value, 0,
95            "Integer too large to fit in given number of bits"
96        );
97
98        Ok(())
99    }
100
101    fn serialize(&self, dst: &mut Vec<u8>, _common_data: &CommonCircuitData<F, D>) -> IoResult<()> {
102        dst.write_target(self.integer)?;
103        dst.write_target_vec(&self.bits)
104    }
105
106    fn deserialize(src: &mut Buffer, _common_data: &CommonCircuitData<F, D>) -> IoResult<Self> {
107        let integer = src.read_target()?;
108        let bits = src.read_target_vec()?;
109        Ok(Self { integer, bits })
110    }
111}
112
113#[derive(Debug, Default)]
114pub struct WireSplitGenerator {
115    integer: Target,
116    gates: Vec<usize>,
117    num_limbs: usize,
118}
119
120impl<F: RichField + Extendable<D>, const D: usize> SimpleGenerator<F, D> for WireSplitGenerator {
121    fn id(&self) -> String {
122        "WireSplitGenerator".to_string()
123    }
124
125    fn dependencies(&self) -> Vec<Target> {
126        vec![self.integer]
127    }
128
129    fn run_once(
130        &self,
131        witness: &PartitionWitness<F>,
132        out_buffer: &mut GeneratedValues<F>,
133    ) -> Result<()> {
134        let mut integer_value = witness.get_target(self.integer).to_canonical_u64();
135
136        for &gate in &self.gates {
137            let sum = Target::wire(gate, BaseSumGate::<2>::WIRE_SUM);
138
139            // If num_limbs >= 64, we don't need to truncate since `integer_value` is already
140            // limited to 64 bits, and trying to do so would cause overflow. Hence the conditional.
141            let mut truncated_value = integer_value;
142            if self.num_limbs < 64 {
143                truncated_value = integer_value & ((1 << self.num_limbs) - 1);
144                integer_value >>= self.num_limbs;
145            } else {
146                integer_value = 0;
147            };
148
149            out_buffer.set_target(sum, F::from_canonical_u64(truncated_value))?;
150        }
151
152        debug_assert_eq!(
153            integer_value,
154            0,
155            "Integer too large to fit in {} many `BaseSumGate`s",
156            self.gates.len()
157        );
158
159        Ok(())
160    }
161
162    fn serialize(&self, dst: &mut Vec<u8>, _common_data: &CommonCircuitData<F, D>) -> IoResult<()> {
163        dst.write_target(self.integer)?;
164        dst.write_usize_vec(&self.gates)?;
165        dst.write_usize(self.num_limbs)
166    }
167
168    fn deserialize(src: &mut Buffer, _common_data: &CommonCircuitData<F, D>) -> IoResult<Self> {
169        let integer = src.read_target()?;
170        let gates = src.read_usize_vec()?;
171        let num_limbs = src.read_usize()?;
172        Ok(Self {
173            integer,
174            gates,
175            num_limbs,
176        })
177    }
178}