sp1_core_machine/operations/
add5.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 Add5Operation<T> {
14 pub value: [T; 2],
16}
17
18impl<F: Field> Add5Operation<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 e_u32: u32,
28 ) -> u32 {
29 let expected =
30 a_u32.wrapping_add(b_u32).wrapping_add(c_u32).wrapping_add(d_u32).wrapping_add(e_u32);
31 let expected_limbs = u32_to_u16_limbs(expected);
32 self.value = u32_to_half_word(expected);
33 let a = u32_to_u16_limbs(a_u32);
34 let b = u32_to_u16_limbs(b_u32);
35 let c = u32_to_u16_limbs(c_u32);
36 let d = u32_to_u16_limbs(d_u32);
37 let e = u32_to_u16_limbs(e_u32);
38 let base = 1u32 << 16;
39 let mut carry = 0;
40 let mut carry_limbs = [0u8; 2];
41 for i in 0..2 {
42 carry = ((a[i] as u32)
43 + (b[i] as u32)
44 + (c[i] as u32)
45 + (d[i] as u32)
46 + (e[i] as u32)
47 + carry
48 - expected_limbs[i] as u32)
49 / base;
50 carry_limbs[i] = carry as u8;
51 }
52
53 record.add_u16_range_checks(&expected_limbs);
55 record.add_u8_range_checks(&carry_limbs);
56 expected
57 }
58
59 pub fn eval<AB: SP1AirBuilder>(
64 builder: &mut AB,
65 words: &[[AB::Expr; 2]; 5],
66 is_real: AB::Var,
67 cols: Add5Operation<AB::Var>,
68 ) {
69 builder.assert_bool(is_real);
70
71 let base = AB::F::from_canonical_u32(1 << 16);
72 let mut carry_limbs = [AB::Expr::zero(), AB::Expr::zero()];
73 let mut carry = AB::Expr::zero(); for i in 0..2 {
83 carry = (words[0][i].clone()
84 + words[1][i].clone()
85 + words[2][i].clone()
86 + words[3][i].clone()
87 + words[4][i].clone()
88 - cols.value[i]
89 + carry.clone())
90 * base.inverse();
91 carry_limbs[i] = carry.clone();
92 }
93 builder.slice_range_check_u16(&cols.value, is_real);
95 builder.slice_range_check_u8(&carry_limbs, is_real);
96 }
97}