binius_circuits/lasso/
u8add.rs1use std::vec;
4
5use anyhow::Result;
6use binius_core::oracle::OracleId;
7use binius_field::{BinaryField1b, BinaryField32b, BinaryField8b, TowerField};
8
9use super::batch::LookupBatch;
10use crate::builder::{types::F, ConstraintSystemBuilder};
11
12type B1 = BinaryField1b;
13type B8 = BinaryField8b;
14type B32 = BinaryField32b;
15
16pub fn u8add(
17 builder: &mut ConstraintSystemBuilder,
18 lookup_batch: &mut LookupBatch,
19 name: impl ToString + Clone,
20 x_in: OracleId,
21 y_in: OracleId,
22 carry_in: OracleId,
23 log_size: usize,
24) -> Result<(OracleId, OracleId), anyhow::Error> {
25 builder.push_namespace(name);
26
27 let sum = builder.add_committed("sum", log_size, B8::TOWER_LEVEL);
28
29 let carry_out = builder.add_committed("cout", log_size, B1::TOWER_LEVEL);
30
31 let lookup_u = builder.add_linear_combination(
32 "lookup_u",
33 log_size,
34 [
35 (carry_in, <F as TowerField>::basis(0, 25)?),
36 (carry_out, <F as TowerField>::basis(3, 3)?),
37 (x_in, <F as TowerField>::basis(3, 2)?),
38 (y_in, <F as TowerField>::basis(3, 1)?),
39 (sum, <F as TowerField>::basis(3, 0)?),
40 ],
41 )?;
42
43 let mut u_to_t_mapping = vec![];
44
45 if let Some(witness) = builder.witness() {
46 let mut sum_witness = witness.new_column::<B8>(sum);
47 let mut carry_out_witness = witness.new_column::<B1>(carry_out);
48 let mut lookup_u_witness = witness.new_column::<B32>(lookup_u);
49 let mut u_to_t_mapping_witness = vec![0; 1 << log_size];
50
51 let x_in_u8 = witness.get::<B8>(x_in)?.as_slice::<u8>();
52 let y_in_u8 = witness.get::<B8>(y_in)?.as_slice::<u8>();
53 let carry_in_u8_packed = witness.get::<B1>(carry_in)?.as_slice::<u8>();
54
55 let sum_u8 = sum_witness.as_mut_slice::<u8>();
56 let carry_out_u8_packed = carry_out_witness.as_mut_slice::<u8>();
57 let lookup_u_u32 = lookup_u_witness.as_mut_slice::<u32>();
58
59 for row_idx in 0..1 << log_size {
60 let carry_in_usize = ((carry_in_u8_packed[row_idx / 8] >> (row_idx % 8)) & 1) as usize;
61
62 let x_in_usize = x_in_u8[row_idx] as usize;
63 let y_in_usize = y_in_u8[row_idx] as usize;
64 let xy_sum_with_carry_out = x_in_usize + y_in_usize + carry_in_usize;
65 let xy_sum_usize = xy_sum_with_carry_out & 0xff;
66 let carry_out_usize = xy_sum_with_carry_out >> 8;
67 let lookup_index = (carry_in_usize << 16) | (x_in_usize << 8) | y_in_usize;
68 let lookup_value = (carry_in_usize << 25)
69 | (carry_out_usize << 24)
70 | (x_in_usize << 16)
71 | (y_in_usize << 8)
72 | xy_sum_usize;
73
74 lookup_u_u32[row_idx] = lookup_value as u32;
75
76 sum_u8[row_idx] = xy_sum_usize as u8;
77
78 carry_out_u8_packed[row_idx / 8] &= 0xff ^ (1 << (row_idx % 8));
80
81 carry_out_u8_packed[row_idx / 8] |= (carry_out_usize << (row_idx % 8)) as u8;
83
84 u_to_t_mapping_witness[row_idx] = lookup_index;
85 }
86
87 u_to_t_mapping = u_to_t_mapping_witness;
88 }
89
90 lookup_batch.add([lookup_u], u_to_t_mapping, 1 << log_size);
91
92 builder.pop_namespace();
93 Ok((carry_out, sum))
94}