diff --git a/gadgets/src/binary/rca.rs b/gadgets/src/binary/rca.rs index 2a29754066..f3a48bfad9 100644 --- a/gadgets/src/binary/rca.rs +++ b/gadgets/src/binary/rca.rs @@ -19,6 +19,29 @@ where ) -> Result, SynthesisError>; } +// Generic impl +impl RippleCarryAdder for &[Boolean] { + fn add_bits>( + &self, + mut cs: CS, + other: &Self, + ) -> Result, SynthesisError> { + let mut result = vec![]; + let mut carry = Boolean::constant(false); + for (i, (a, b)) in self.iter().zip(other.iter()).enumerate() { + let (sum, next) = Boolean::add(cs.ns(|| format!("rpc {}", i)), a, b, &carry)?; + + carry = next; + result.push(sum); + } + + // append the carry bit to the end + result.push(carry); + + Ok(result) + } +} + macro_rules! rpc_impl { ($($gadget: ident)*) => ($( impl RippleCarryAdder for $gadget { diff --git a/gadgets/src/signed_integer/arithmetic/mul.rs b/gadgets/src/signed_integer/arithmetic/mul.rs index 03b9b46b08..457ee0ae54 100644 --- a/gadgets/src/signed_integer/arithmetic/mul.rs +++ b/gadgets/src/signed_integer/arithmetic/mul.rs @@ -1,7 +1,13 @@ -use crate::{errors::IntegerError, Int16, Int32, Int64, Int8}; -use snarkos_models::{curves::PrimeField, gadgets::r1cs::ConstraintSystem}; +use crate::{binary::RippleCarryAdder, errors::IntegerError, sign_extend::SignExtend, Int, Int16, Int32, Int64, Int8}; +use snarkos_models::{ + curves::PrimeField, + gadgets::{r1cs::ConstraintSystem, utilities::boolean::Boolean}, +}; /// Multiplication for a signed integer gadget +/// 1. Sign extend both integers to double precision. +/// 2. Compute double and add. +/// 3. Truncate to original bit size. pub trait Mul where Self: std::marker::Sized, @@ -11,13 +17,28 @@ where } macro_rules! mul_int_impl { - ($($t:ty)*) => ($( - impl Mul for $t { - fn mul>(&self, _cs: CS, _other: &Self) -> Result<(), IntegerError> { + ($($gadget: ident)*) => ($( + impl Mul for $gadget { + fn mul>(&self, cs: CS, other: &Self) -> Result<(), IntegerError> { + // let is_constant = Boolean::constant(Self::result_is_constant(&self, &other)); + // let constant_result = Self::constant(0 as <$gadget as Int>::) + // + // let double = <$gadget as Int>::SIZE * 2; + // + // let a = Boolean::sign_extend(&self.bits, double); + // let b = Boolean::sign_extend(&other.bits, double); + // + // let result = + // + // for bit in b.iter() { + // + // } + Ok(()) } } )*) } -mul_int_impl!(Int8 Int16 Int32 Int64); +// mul_int_impl!(Int8 Int16 Int32 Int64); +mul_int_impl!(Int8); diff --git a/gadgets/src/signed_integer/arithmetic/sub.rs b/gadgets/src/signed_integer/arithmetic/sub.rs index 1882f62510..d0bcf9f385 100644 --- a/gadgets/src/signed_integer/arithmetic/sub.rs +++ b/gadgets/src/signed_integer/arithmetic/sub.rs @@ -11,8 +11,8 @@ where } macro_rules! sub_int_impl { - ($($t:ty)*) => ($( - impl Sub for $t { + ($($gadget: ident)*) => ($( + impl Sub for $gadget { fn sub>(&self, mut cs: CS, other: &Self) -> Result { // Evaluate the two's complement of the subtrahend let s = other.twos_comp(cs.ns(|| format!("complement")))?; diff --git a/gadgets/src/signed_integer/utilities/mod.rs b/gadgets/src/signed_integer/utilities/mod.rs index 9e7a824a44..2250e72047 100644 --- a/gadgets/src/signed_integer/utilities/mod.rs +++ b/gadgets/src/signed_integer/utilities/mod.rs @@ -1,3 +1,9 @@ #[macro_use] pub mod alloc; pub use self::alloc::*; + +pub mod select; +pub use self::select::*; + +pub mod sign_extend; +pub use self::sign_extend::*; diff --git a/gadgets/src/signed_integer/utilities/select.rs b/gadgets/src/signed_integer/utilities/select.rs new file mode 100644 index 0000000000..de93156fbb --- /dev/null +++ b/gadgets/src/signed_integer/utilities/select.rs @@ -0,0 +1,68 @@ +use crate::signed_integer::*; + +use snarkos_errors::gadgets::SynthesisError; +use snarkos_models::{ + curves::PrimeField, + gadgets::{ + r1cs::{Assignment, ConstraintSystem}, + utilities::{alloc::AllocGadget, boolean::Boolean, eq::EqGadget, select::CondSelectGadget}, + }, +}; + +macro_rules! select_int_impl { + ($($gadget: ident)*) => ($( + impl CondSelectGadget for $gadget { + fn conditionally_select> ( + mut cs: CS, + cond: &Boolean, + first: &Self, + second: &Self, + ) -> Result { + if let Boolean::Constant(cond) = *cond { + if cond { + Ok(first.clone()) + } else { + Ok(second.clone()) + } + } else { + let result_val = cond.get_value().and_then(|c| { + if c { + first.value + } else { + second.value + } + }); + + let result = Self::alloc(cs.ns(|| "cond_select_result"), || result_val.get().map(|v| v))?; + + let expected_bits = first + .bits + .iter() + .zip(&second.bits) + .enumerate() + .map(|(i, (a, b))| { + Boolean::conditionally_select( + &mut cs.ns(|| format!("{}_cond_select_{}", <$gadget as Int>::SIZE, i)), + cond, + a, + b, + ).unwrap() + }) + .collect::>(); + + for (i, (actual, expected)) in result.bits.iter().zip(expected_bits.iter()).enumerate() { + actual.enforce_equal(&mut cs.ns(|| format!("selected_result_bit_{}", i)), expected)?; + } + + Ok(result) + } + } + + fn cost() -> usize { + unimplemented!(); + } + } + )*) +} + +select_int_impl!(Int8 Int16 Int32 Int64 Int128); diff --git a/gadgets/src/signed_integer/utilities/sign_extend.rs b/gadgets/src/signed_integer/utilities/sign_extend.rs new file mode 100644 index 0000000000..8589e1551c --- /dev/null +++ b/gadgets/src/signed_integer/utilities/sign_extend.rs @@ -0,0 +1,23 @@ +use snarkos_models::gadgets::utilities::boolean::Boolean; + +/// Sign extends an array of bits to the desired length. +/// Least significant bit first +pub trait SignExtend +where + Self: std::marker::Sized, +{ + #[must_use] + fn sign_extend(bits: &[Self], length: usize) -> Vec; +} + +impl SignExtend for Boolean { + fn sign_extend(bits: &[Boolean], length: usize) -> Vec { + let msb = bits.last().expect("empty bit list"); + let mut extension = vec![msb.clone(); length]; + let mut result = Vec::from(bits); + + result.append(&mut extension); + + result + } +}