diff --git a/gadgets/src/errors/signed_integer.rs b/gadgets/src/errors/signed_integer.rs index 6cee056445..a819966ef0 100644 --- a/gadgets/src/errors/signed_integer.rs +++ b/gadgets/src/errors/signed_integer.rs @@ -2,6 +2,9 @@ use snarkos_errors::gadgets::SynthesisError; #[derive(Debug, Error)] pub enum IntegerError { + #[error("Negative zero")] + NegativeZero, + #[error("Integer overflow")] Overflow, diff --git a/gadgets/src/signed_integer/arithmetic/add.rs b/gadgets/src/signed_integer/arithmetic/add.rs index e6be0fcef6..dd1c12955c 100644 --- a/gadgets/src/signed_integer/arithmetic/add.rs +++ b/gadgets/src/signed_integer/arithmetic/add.rs @@ -11,7 +11,7 @@ use snarkos_models::{ }, }; -/// Modular addition for a signed integer gadget +/// Addition for a signed integer gadget pub trait Add where Self: std::marker::Sized, diff --git a/gadgets/src/signed_integer/arithmetic/div.rs b/gadgets/src/signed_integer/arithmetic/div.rs index 80d45e8ece..5412577cec 100644 --- a/gadgets/src/signed_integer/arithmetic/div.rs +++ b/gadgets/src/signed_integer/arithmetic/div.rs @@ -1,7 +1,7 @@ use crate::{errors::IntegerError, Int16, Int32, Int64, Int8}; use snarkos_models::{curves::PrimeField, gadgets::r1cs::ConstraintSystem}; -/// Modular division for a signed integer gadget +/// Division for a signed integer gadget pub trait Div where Self: std::marker::Sized, diff --git a/gadgets/src/signed_integer/arithmetic/mod.rs b/gadgets/src/signed_integer/arithmetic/mod.rs index a7a64be042..ae4970b62e 100644 --- a/gadgets/src/signed_integer/arithmetic/mod.rs +++ b/gadgets/src/signed_integer/arithmetic/mod.rs @@ -8,6 +8,9 @@ pub use self::div::*; pub mod mul; pub use self::mul::*; +pub mod twos_complement; +pub use self::twos_complement::*; + pub mod pow; pub use self::pow::*; diff --git a/gadgets/src/signed_integer/arithmetic/mul.rs b/gadgets/src/signed_integer/arithmetic/mul.rs index 275bdb9a6b..03b9b46b08 100644 --- a/gadgets/src/signed_integer/arithmetic/mul.rs +++ b/gadgets/src/signed_integer/arithmetic/mul.rs @@ -1,7 +1,7 @@ use crate::{errors::IntegerError, Int16, Int32, Int64, Int8}; use snarkos_models::{curves::PrimeField, gadgets::r1cs::ConstraintSystem}; -/// Modular multiplication for a signed integer gadget +/// Multiplication for a signed integer gadget pub trait Mul where Self: std::marker::Sized, diff --git a/gadgets/src/signed_integer/arithmetic/pow.rs b/gadgets/src/signed_integer/arithmetic/pow.rs index 95f92c7083..d08dacf073 100644 --- a/gadgets/src/signed_integer/arithmetic/pow.rs +++ b/gadgets/src/signed_integer/arithmetic/pow.rs @@ -1,7 +1,7 @@ use crate::{errors::IntegerError, Int16, Int32, Int64, Int8}; use snarkos_models::{curves::PrimeField, gadgets::r1cs::ConstraintSystem}; -/// Modular exponentiation for a signed integer gadget +/// Exponentiation for a signed integer gadget pub trait Pow where Self: std::marker::Sized, diff --git a/gadgets/src/signed_integer/arithmetic/sub.rs b/gadgets/src/signed_integer/arithmetic/sub.rs index ecf0a46d2a..04baf70a53 100644 --- a/gadgets/src/signed_integer/arithmetic/sub.rs +++ b/gadgets/src/signed_integer/arithmetic/sub.rs @@ -1,7 +1,7 @@ -use crate::{errors::IntegerError, Int16, Int32, Int64, Int8}; +use crate::{errors::IntegerError, Int128, Int16, Int32, Int64, Int8}; use snarkos_models::{curves::PrimeField, gadgets::r1cs::ConstraintSystem}; -/// Modular subtraction for a signed integer gadget +/// Subtraction for a signed integer gadget pub trait Sub where Self: std::marker::Sized, @@ -20,4 +20,4 @@ macro_rules! sub_int_impl { )*) } -sub_int_impl!(Int8 Int16 Int32 Int64); +sub_int_impl!(Int8 Int16 Int32 Int64 Int128); diff --git a/gadgets/src/signed_integer/arithmetic/twos_complement.rs b/gadgets/src/signed_integer/arithmetic/twos_complement.rs new file mode 100644 index 0000000000..171f36d843 --- /dev/null +++ b/gadgets/src/signed_integer/arithmetic/twos_complement.rs @@ -0,0 +1,58 @@ +use crate::{binary::RippleCarryAdder, errors::IntegerError, signed_integer::*}; + +use snarkos_models::{curves::PrimeField, gadgets::r1cs::ConstraintSystem}; + +/// Inverts the given number and adds 1 to the lsb of the result +pub trait TwosComplement +where + Self: std::marker::Sized, +{ + #[must_use] + fn twos_comp>(&self, cs: CS) -> Result; +} + +macro_rules! twos_comp_int_impl { + ($($gadget: ident)*) => ($( + impl TwosComplement for $gadget { + fn twos_comp>( + &self, + mut cs: CS + ) -> Result { + let value = match self.value { + Some(val) => { + match val.checked_neg() { + Some(val_neg) => Some(val_neg), + None => return Err(IntegerError::NegativeZero) // -0 should fail + } + } + None => None, + }; + println!("val {}", value.unwrap()); + + // flip all bits + let flipped_bits = self.bits + .iter() + .map(|bit| bit.not()) + .collect(); + + let flipped = Self { + bits: flipped_bits, + value, + }; + + // add one + let one = Self::one(); + + let mut bits = flipped.add_bits(cs.ns(|| format!("add one")), &one)?; + let _carry = bits.pop(); // we already accounted for overflow above + + Ok(Self { + bits, + value, + }) + } + } + )*) +} + +twos_comp_int_impl!(Int8 Int16 Int32 Int64 Int128); diff --git a/gadgets/src/signed_integer/int_impl.rs b/gadgets/src/signed_integer/int_impl.rs index b5a3e7fd82..b61fde07a6 100644 --- a/gadgets/src/signed_integer/int_impl.rs +++ b/gadgets/src/signed_integer/int_impl.rs @@ -6,6 +6,8 @@ pub trait Int: Debug + Clone { type IntegerType; const SIZE: usize; + fn one() -> Self; + /// Returns true if all bits in this `Int` are constant fn is_constant(&self) -> bool; @@ -13,8 +15,6 @@ pub trait Int: Debug + Clone { fn result_is_constant(first: &Self, second: &Self) -> bool { first.is_constant() && second.is_constant() } - - fn is_negative(&self) -> bool; } /// Implements the base struct for a signed integer gadget @@ -55,6 +55,10 @@ macro_rules! int_impl { const SIZE: usize = $size; + fn one() -> Self { + Self::constant(1 as $type_) + } + fn is_constant(&self) -> bool { let mut constant = true; @@ -69,10 +73,6 @@ macro_rules! int_impl { constant } - - fn is_negative(&self) -> bool { - true - } } }; } diff --git a/gadgets/tests/signed_integer/i8.rs b/gadgets/tests/signed_integer/i8.rs index 6271cca340..468bf91e90 100644 --- a/gadgets/tests/signed_integer/i8.rs +++ b/gadgets/tests/signed_integer/i8.rs @@ -1,4 +1,7 @@ -use leo_gadgets::{arithmetic::Add, Int8}; +use leo_gadgets::{ + arithmetic::{Add, Neg}, + Int8, +}; use snarkos_models::{ curves::{One, Zero}, gadgets::{ @@ -102,3 +105,29 @@ fn test_int8_add() { assert!(!cs.is_satisfied()); } } + +#[test] +fn test_int8_neg_constants() { + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + + for _ in 0..1 { + let a: i8 = rng.gen(); + + println!("{}", a); + + let a_bit = Int8::constant(a); + + let r = a_bit.neg(); + + match a.checked_neg() { + Some(expected) => { + println!("result {}", expected); + let result = r.unwrap(); + assert!(result.value == Some(expected)); + + check_all_constant_bits(expected, result); + } + None => assert!(r.is_none()), + } + } +}