Skip to main content

sp1_core_machine/operations/
not_u32.rs

1use slop_air::AirBuilder;
2use slop_algebra::{AbstractField, Field};
3use sp1_derive::AlignedBorrow;
4use sp1_hypercube::air::SP1AirBuilder;
5use sp1_primitives::consts::u32_to_u16_limbs;
6
7/// A set of columns needed to compute the NOT of an u32 value.
8#[derive(AlignedBorrow, Default, Debug, Clone, Copy)]
9#[repr(C)]
10pub struct NotU32Operation<T> {
11    /// The result of `!x`.
12    pub value: [T; 2],
13}
14
15impl<F: Field> NotU32Operation<F> {
16    pub fn populate(&mut self, x: u32) -> u32 {
17        let x_limbs = u32_to_u16_limbs(x);
18        self.value[0] = F::from_canonical_u16(!x_limbs[0]);
19        self.value[1] = F::from_canonical_u16(!x_limbs[1]);
20        !x
21    }
22
23    /// Evaluate the NOT operation over a u32 of two u16 limbs.
24    /// Assumes that the input is a valid u32 of two u16 limbs.
25    /// If `is_real` is non-zero, constrains that the `value` is correct.
26    #[allow(unused_variables)]
27    pub fn eval<AB: SP1AirBuilder>(
28        builder: &mut AB,
29        a: [AB::Expr; 2],
30        cols: NotU32Operation<AB::Var>,
31        is_real: impl Into<AB::Expr> + Copy,
32    ) {
33        // For any u16 limb b, b + !b = 0xFFFF.
34        for i in 0..2 {
35            builder
36                .when(is_real)
37                .assert_eq(cols.value[i] + a[i].clone(), AB::F::from_canonical_u16(u16::MAX));
38        }
39    }
40}