plonky2/gadgets/
split_join.rs1#[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 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 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 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}