snarkvm_circuit_types_integers/
neg.rsuse super::*;
impl<E: Environment, I: IntegerType> Neg for Integer<E, I> {
type Output = Integer<E, I>;
fn neg(self) -> Self::Output {
(&self).neg()
}
}
impl<E: Environment, I: IntegerType> Neg for &Integer<E, I> {
type Output = Integer<E, I>;
fn neg(self) -> Self::Output {
match I::is_signed() {
true => Integer::one().add_checked(&!self),
false => E::halt("Attempted to negate an unsigned integer"),
}
}
}
impl<E: Environment, I: IntegerType> Metrics<dyn Neg<Output = Integer<E, I>>> for Integer<E, I> {
type Case = Mode;
fn count(case: &Self::Case) -> Count {
match I::is_signed() {
false => E::halt("Unsigned integers cannot be negated"),
true => match case {
Mode::Constant => Count::is(2 * I::BITS, 0, 0, 0),
_ => Count::is(I::BITS, 0, I::BITS + 2, I::BITS + 4),
},
}
}
}
impl<E: Environment, I: IntegerType> OutputMode<dyn Neg<Output = Integer<E, I>>> for Integer<E, I> {
type Case = Mode;
fn output_mode(case: &Self::Case) -> Mode {
match case {
Mode::Constant => Mode::Constant,
_ => Mode::Private,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use snarkvm_circuit_environment::Circuit;
use test_utilities::*;
use core::{ops::RangeInclusive, panic::UnwindSafe};
const ITERATIONS: u64 = 128;
fn check_neg<I: IntegerType + UnwindSafe + Neg<Output = I>>(
name: &str,
value: console::Integer<<Circuit as Environment>::Network, I>,
mode: Mode,
) {
let a = Integer::<Circuit, I>::new(mode, value);
match value.checked_neg() {
Some(expected) => Circuit::scope(name, || {
let candidate = a.neg();
assert_eq!(expected, *candidate.eject_value());
assert_eq!(console::Integer::new(expected), candidate.eject_value());
assert_count!(Neg(Integer<I>) => Integer<I>, &mode);
assert_output_mode!(Neg(Integer<I>) => Integer<I>, &mode, candidate);
}),
None => match mode {
Mode::Constant => check_unary_operation_halts(a, |a: Integer<Circuit, I>| a.neg()),
_ => Circuit::scope(name, || {
let _candidate = a.neg();
assert_count_fails!(Neg(Integer<I>) => Integer<I>, &mode);
}),
},
}
Circuit::reset();
}
fn run_test<I: IntegerType + UnwindSafe + Neg<Output = I>>(mode: Mode) {
check_neg::<I>(&format!("Neg: {mode} zero"), console::Integer::zero(), mode);
check_neg::<I>(&format!("Neg: {mode} one"), -console::Integer::one(), mode);
let mut rng = TestRng::default();
for i in 0..ITERATIONS {
let value = Uniform::rand(&mut rng);
check_neg::<I>(&format!("Neg: {mode} {i}"), value, mode);
}
}
fn assert_unsigned_neg_halts<I: IntegerType + UnwindSafe>(mode: Mode) {
let candidate = Integer::<Circuit, I>::new(mode, Uniform::rand(&mut TestRng::default()));
let operation = std::panic::catch_unwind(|| candidate.neg());
assert!(operation.is_err());
}
fn run_exhaustive_test<I: IntegerType + UnwindSafe + Neg<Output = I>>(mode: Mode)
where
RangeInclusive<I>: Iterator<Item = I>,
{
for value in I::MIN..=I::MAX {
let value = console::Integer::<_, I>::new(value);
let name = format!("Neg: {mode}");
check_neg::<I>(&name, value, mode);
}
}
test_integer_unary!(run_test, i8, neg);
test_integer_unary!(run_test, i16, neg);
test_integer_unary!(run_test, i32, neg);
test_integer_unary!(run_test, i64, neg);
test_integer_unary!(run_test, i128, neg);
test_integer_unary!(assert_unsigned_neg_halts, u8, neg);
test_integer_unary!(assert_unsigned_neg_halts, u16, neg);
test_integer_unary!(assert_unsigned_neg_halts, u32, neg);
test_integer_unary!(assert_unsigned_neg_halts, u64, neg);
test_integer_unary!(assert_unsigned_neg_halts, u128, neg);
test_integer_unary!(#[ignore], assert_unsigned_neg_halts, u8, neg, exhaustive);
test_integer_unary!(#[ignore], run_exhaustive_test, i8, neg, exhaustive);
}