sp1_core_machine/operations/
add4.rs1use slop_algebra::{AbstractField, Field};
2use sp1_derive::AlignedBorrow;
3
4use sp1_core_executor::events::ByteRecord;
5use sp1_hypercube::air::SP1AirBuilder;
6use sp1_primitives::consts::u32_to_u16_limbs;
7
8use crate::{air::WordAirBuilder, utils::u32_to_half_word};
9
10#[derive(AlignedBorrow, Default, Debug, Clone, Copy)]
12#[repr(C)]
13pub struct Add4Operation<T> {
14 pub value: [T; 2],
16}
17
18impl<F: Field> Add4Operation<F> {
19 #[allow(clippy::too_many_arguments)]
20 pub fn populate(
21 &mut self,
22 record: &mut impl ByteRecord,
23 a_u32: u32,
24 b_u32: u32,
25 c_u32: u32,
26 d_u32: u32,
27 ) -> u32 {
28 let expected = a_u32.wrapping_add(b_u32).wrapping_add(c_u32).wrapping_add(d_u32);
29 let expected_limbs = u32_to_u16_limbs(expected);
30 self.value = u32_to_half_word(expected);
31 let a = u32_to_u16_limbs(a_u32);
32 let b = u32_to_u16_limbs(b_u32);
33 let c = u32_to_u16_limbs(c_u32);
34 let d = u32_to_u16_limbs(d_u32);
35
36 let base = 1u32 << 16;
37 let mut carry_limbs = [0u8; 2];
38 let mut carry = 0;
39 for i in 0..2 {
40 carry = ((a[i] as u32) + (b[i] as u32) + (c[i] as u32) + (d[i] as u32) + carry
41 - expected_limbs[i] as u32)
42 / base;
43 carry_limbs[i] = carry as u8;
44 }
45
46 record.add_u16_range_checks(&expected_limbs);
48 record.add_u8_range_checks(&carry_limbs);
49 expected
50 }
51
52 #[allow(clippy::too_many_arguments)]
57 pub fn eval<AB: SP1AirBuilder>(
58 builder: &mut AB,
59 a: [AB::Expr; 2],
60 b: [AB::Expr; 2],
61 c: [AB::Expr; 2],
62 d: [AB::Expr; 2],
63 is_real: AB::Var,
64 cols: Add4Operation<AB::Var>,
65 ) {
66 builder.assert_bool(is_real);
67
68 let base = AB::F::from_canonical_u32(1 << 16);
69 let mut carry_limbs = [AB::Expr::zero(), AB::Expr::zero()];
70 let mut carry = AB::Expr::zero(); for i in 0..2 {
80 carry = (a[i].clone() + b[i].clone() + c[i].clone() + d[i].clone() - cols.value[i]
81 + carry)
82 * base.inverse();
83 carry_limbs[i] = carry.clone();
84 }
85 builder.slice_range_check_u16(&cols.value, is_real);
87 builder.slice_range_check_u8(&carry_limbs, is_real);
88 }
89}