binius_core/constraint_system/
constraint.rs1use std::array;
3
4use binius_utils::serialization::{DeserializeBytes, SerializationError, SerializeBytes};
5use bytes::{Buf, BufMut};
6
7use super::{ShiftedValueIndex, ValueIndex};
8
9pub type Operand = Vec<ShiftedValueIndex>;
23
24const AND_ARITY: usize = 3;
26const IMUL_ARITY: usize = 4;
28const BMUL_ARITY: usize = 6;
30
31fn serialize_operands(
33 operands: &[Operand],
34 mut write_buf: impl BufMut,
35) -> Result<(), SerializationError> {
36 for operand in operands {
37 operand.serialize(&mut write_buf)?;
38 }
39 Ok(())
40}
41
42fn deserialize_operands<const ARITY: usize>(
44 mut read_buf: impl Buf,
45) -> Result<[Operand; ARITY], SerializationError> {
46 let mut operands = array::from_fn::<_, ARITY, _>(|_| Operand::new());
47 for operand in &mut operands {
48 *operand = Vec::<ShiftedValueIndex>::deserialize(&mut read_buf)?;
49 }
50 Ok(operands)
51}
52
53#[derive(Debug, Clone, Default)]
60pub struct AndConstraint(pub [Operand; AND_ARITY]);
61
62impl AndConstraint {
63 pub const ARITY: usize = AND_ARITY;
65 pub const OPERAND_NAMES: [&'static str; AND_ARITY] = ["a", "b", "c"];
67
68 pub fn plain_abc(
70 a: impl IntoIterator<Item = ValueIndex>,
71 b: impl IntoIterator<Item = ValueIndex>,
72 c: impl IntoIterator<Item = ValueIndex>,
73 ) -> AndConstraint {
74 AndConstraint::abc(
75 a.into_iter().map(ShiftedValueIndex::plain),
76 b.into_iter().map(ShiftedValueIndex::plain),
77 c.into_iter().map(ShiftedValueIndex::plain),
78 )
79 }
80
81 pub fn abc(
83 a: impl IntoIterator<Item = ShiftedValueIndex>,
84 b: impl IntoIterator<Item = ShiftedValueIndex>,
85 c: impl IntoIterator<Item = ShiftedValueIndex>,
86 ) -> AndConstraint {
87 AndConstraint([
88 a.into_iter().collect(),
89 b.into_iter().collect(),
90 c.into_iter().collect(),
91 ])
92 }
93
94 pub const fn a(&self) -> &Operand {
96 &self.0[0]
97 }
98
99 pub const fn b(&self) -> &Operand {
101 &self.0[1]
102 }
103
104 pub const fn c(&self) -> &Operand {
106 &self.0[2]
107 }
108}
109
110impl AsRef<[Operand; AND_ARITY]> for AndConstraint {
111 fn as_ref(&self) -> &[Operand; AND_ARITY] {
112 &self.0
113 }
114}
115
116impl SerializeBytes for AndConstraint {
117 fn serialize(&self, write_buf: impl BufMut) -> Result<(), SerializationError> {
118 serialize_operands(&self.0, write_buf)
119 }
120}
121
122impl DeserializeBytes for AndConstraint {
123 fn deserialize(read_buf: impl Buf) -> Result<Self, SerializationError>
124 where
125 Self: Sized,
126 {
127 Ok(AndConstraint(deserialize_operands(read_buf)?))
128 }
129}
130
131#[derive(Debug, Clone, Default)]
138pub struct ImulConstraint(pub [Operand; IMUL_ARITY]);
139
140impl ImulConstraint {
141 pub const ARITY: usize = IMUL_ARITY;
143 pub const OPERAND_NAMES: [&'static str; IMUL_ARITY] = ["a", "b", "lo", "hi"];
145
146 pub const fn a(&self) -> &Operand {
148 &self.0[0]
149 }
150
151 pub const fn b(&self) -> &Operand {
153 &self.0[1]
154 }
155
156 pub const fn lo(&self) -> &Operand {
160 &self.0[2]
161 }
162
163 pub const fn hi(&self) -> &Operand {
167 &self.0[3]
168 }
169}
170
171impl AsRef<[Operand; IMUL_ARITY]> for ImulConstraint {
172 fn as_ref(&self) -> &[Operand; IMUL_ARITY] {
173 &self.0
174 }
175}
176
177impl SerializeBytes for ImulConstraint {
178 fn serialize(&self, write_buf: impl BufMut) -> Result<(), SerializationError> {
179 serialize_operands(&self.0, write_buf)
180 }
181}
182
183impl DeserializeBytes for ImulConstraint {
184 fn deserialize(read_buf: impl Buf) -> Result<Self, SerializationError>
185 where
186 Self: Sized,
187 {
188 Ok(ImulConstraint(deserialize_operands(read_buf)?))
189 }
190}
191
192#[derive(Debug, Clone, Default)]
200pub struct BmulConstraint(pub [Operand; BMUL_ARITY]);
201
202impl BmulConstraint {
203 pub const ARITY: usize = BMUL_ARITY;
205 pub const OPERAND_NAMES: [&'static str; BMUL_ARITY] =
207 ["a_lo", "a_hi", "b_lo", "b_hi", "c_lo", "c_hi"];
208
209 pub const fn a_lo(&self) -> &Operand {
211 &self.0[0]
212 }
213
214 pub const fn a_hi(&self) -> &Operand {
216 &self.0[1]
217 }
218
219 pub const fn b_lo(&self) -> &Operand {
221 &self.0[2]
222 }
223
224 pub const fn b_hi(&self) -> &Operand {
226 &self.0[3]
227 }
228
229 pub const fn c_lo(&self) -> &Operand {
231 &self.0[4]
232 }
233
234 pub const fn c_hi(&self) -> &Operand {
236 &self.0[5]
237 }
238}
239
240impl AsRef<[Operand; BMUL_ARITY]> for BmulConstraint {
241 fn as_ref(&self) -> &[Operand; BMUL_ARITY] {
242 &self.0
243 }
244}
245
246impl SerializeBytes for BmulConstraint {
247 fn serialize(&self, write_buf: impl BufMut) -> Result<(), SerializationError> {
248 serialize_operands(&self.0, write_buf)
249 }
250}
251
252impl DeserializeBytes for BmulConstraint {
253 fn deserialize(read_buf: impl Buf) -> Result<Self, SerializationError>
254 where
255 Self: Sized,
256 {
257 Ok(BmulConstraint(deserialize_operands(read_buf)?))
258 }
259}
260
261#[cfg(test)]
262mod tests {
263 use super::*;
264
265 #[test]
266 fn test_and_constraint_serialization_round_trip() {
267 let constraint = AndConstraint::abc(
268 vec![ShiftedValueIndex::sll(ValueIndex(1), 5)],
269 vec![ShiftedValueIndex::srl(ValueIndex(2), 10)],
270 vec![
271 ShiftedValueIndex::sar(ValueIndex(3), 15),
272 ShiftedValueIndex::plain(ValueIndex(4)),
273 ],
274 );
275
276 let mut buf = Vec::new();
277 constraint.serialize(&mut buf).unwrap();
278
279 let deserialized = AndConstraint::deserialize(&mut buf.as_slice()).unwrap();
280 assert_eq!(constraint.a().len(), deserialized.a().len());
281 assert_eq!(constraint.b().len(), deserialized.b().len());
282 assert_eq!(constraint.c().len(), deserialized.c().len());
283
284 for (orig, deser) in constraint.a().iter().zip(deserialized.a().iter()) {
285 assert_eq!(orig.value_index, deser.value_index);
286 assert_eq!(orig.amount, deser.amount);
287 }
288 }
289
290 #[test]
291 fn test_imul_constraint_serialization_round_trip() {
292 let constraint = ImulConstraint([
293 vec![ShiftedValueIndex::plain(ValueIndex(0))],
294 vec![ShiftedValueIndex::srl(ValueIndex(1), 32)],
295 vec![ShiftedValueIndex::plain(ValueIndex(2))],
296 vec![ShiftedValueIndex::plain(ValueIndex(3))],
297 ]);
298
299 let mut buf = Vec::new();
300 constraint.serialize(&mut buf).unwrap();
301
302 let deserialized = ImulConstraint::deserialize(&mut buf.as_slice()).unwrap();
303 assert_eq!(constraint.a().len(), deserialized.a().len());
304 assert_eq!(constraint.b().len(), deserialized.b().len());
305 assert_eq!(constraint.lo().len(), deserialized.lo().len());
306 assert_eq!(constraint.hi().len(), deserialized.hi().len());
307 }
308
309 #[test]
310 fn test_bmul_constraint_serialization_round_trip() {
311 let constraint = BmulConstraint([
312 vec![ShiftedValueIndex::plain(ValueIndex(0))],
313 vec![ShiftedValueIndex::srl(ValueIndex(1), 32)],
314 vec![ShiftedValueIndex::plain(ValueIndex(2))],
315 vec![ShiftedValueIndex::sll(ValueIndex(3), 5)],
316 vec![ShiftedValueIndex::plain(ValueIndex(4))],
317 vec![
318 ShiftedValueIndex::sar(ValueIndex(5), 15),
319 ShiftedValueIndex::plain(ValueIndex(6)),
320 ],
321 ]);
322
323 let mut buf = Vec::new();
324 constraint.serialize(&mut buf).unwrap();
325
326 let deserialized = BmulConstraint::deserialize(&mut buf.as_slice()).unwrap();
327 assert_eq!(constraint.a_lo().len(), deserialized.a_lo().len());
328 assert_eq!(constraint.a_hi().len(), deserialized.a_hi().len());
329 assert_eq!(constraint.b_lo().len(), deserialized.b_lo().len());
330 assert_eq!(constraint.b_hi().len(), deserialized.b_hi().len());
331 assert_eq!(constraint.c_lo().len(), deserialized.c_lo().len());
332 assert_eq!(constraint.c_hi().len(), deserialized.c_hi().len());
333 }
334}