fn eval_range_check_28bits(
        &mut self,
        value: impl Into<Self::Expr>,
        limb_16: impl Into<Self::Expr> + Clone,
        limb_12: impl Into<Self::Expr> + Clone,
        is_real: impl Into<Self::Expr> + Clone,
    ) {
        // Verify that value = limb_16 + limb_12 * 2^16.
        self.when(is_real.clone()).assert_eq(
            value,
            limb_16.clone().into() +
                limb_12.clone().into() * Self::Expr::from_canonical_u32(1 << 16),
        );

        // Send the range checks for the limbs.
        self.send_range_check(
            Self::Expr::from_canonical_u8(RangeCheckOpcode::U16 as u8),
            limb_16,
            is_real.clone(),
        );

        self.send_range_check(
            Self::Expr::from_canonical_u8(RangeCheckOpcode::U12 as u8),
            limb_12,
            is_real,
        )
    }
Verifies the inputted value is within 28 bits.

This method verifies that the inputted is less than 2^24 by doing a 16 bit and 12 bit range
check on it's limbs.  It will also verify that the limbs are correct.  This method is needed
since the memory access timestamp check (see [Self::eval_memory_access_timestamp]) needs to
assume the clk is within 28 bits.
crates/recursion/core/src/air/builder.rs