mirror of
https://github.com/zama-ai/tfhe-rs.git
synced 2026-01-10 07:08:03 -05:00
feat: add OverflowingAdd trait
Add a OverflowingAdd trait and make UnsignedInteger and SignedInteger depend on it This is so that other parts of the code can use the OverflowingAdd trait without requiring the big Unsigned/Signed Bound
This commit is contained in:
@@ -130,3 +130,9 @@ where
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait OverflowingAdd<Rhs> {
|
||||
type Output;
|
||||
|
||||
fn overflowing_add(self, other: Rhs) -> (Self::Output, bool);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use super::{CastFrom, CastInto, Numeric, SignedNumeric, UnsignedInteger};
|
||||
use crate::core_crypto::prelude::OverflowingAdd;
|
||||
use std::ops::{
|
||||
Add, AddAssign, BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Div, DivAssign,
|
||||
Mul, MulAssign, Neg, Not, Rem, RemAssign, Shl, ShlAssign, Shr, ShrAssign, Sub, SubAssign,
|
||||
@@ -29,6 +30,7 @@ pub trait SignedInteger:
|
||||
+ ShlAssign<usize>
|
||||
+ Shr<usize, Output = Self>
|
||||
+ ShrAssign<usize>
|
||||
+ OverflowingAdd<Self, Output = Self>
|
||||
+ CastFrom<f64>
|
||||
+ CastInto<f64>
|
||||
{
|
||||
@@ -61,6 +63,15 @@ macro_rules! implement {
|
||||
type NumericUnsignedType = $UnsignedType;
|
||||
}
|
||||
|
||||
impl OverflowingAdd<Self> for $Type {
|
||||
type Output = Self;
|
||||
|
||||
#[inline]
|
||||
fn overflowing_add(self, rhs: Self) -> (Self, bool) {
|
||||
self.overflowing_add(rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl SignedInteger for $Type {
|
||||
type Unsigned = $UnsignedType;
|
||||
#[inline]
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use super::{CastFrom, CastInto, Numeric, SignedInteger, UnsignedNumeric};
|
||||
use crate::core_crypto::prelude::OverflowingAdd;
|
||||
use std::ops::{
|
||||
Add, AddAssign, BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Div, DivAssign,
|
||||
Mul, MulAssign, Not, Rem, RemAssign, Shl, ShlAssign, Shr, ShrAssign, Sub, SubAssign,
|
||||
@@ -30,6 +31,7 @@ pub trait UnsignedInteger:
|
||||
+ ShlAssign<usize>
|
||||
+ Shr<usize, Output = Self>
|
||||
+ ShrAssign<usize>
|
||||
+ OverflowingAdd<Self, Output = Self>
|
||||
+ CastFrom<Self::Signed>
|
||||
+ CastFrom<f64>
|
||||
+ CastInto<f64>
|
||||
@@ -83,8 +85,6 @@ pub trait UnsignedInteger:
|
||||
#[must_use]
|
||||
fn wrapping_shr(self, rhs: u32) -> Self;
|
||||
#[must_use]
|
||||
fn overflowing_add(self, rhs: Self) -> (Self, bool);
|
||||
#[must_use]
|
||||
fn overflowing_sub(self, rhs: Self) -> (Self, bool);
|
||||
#[must_use]
|
||||
fn is_power_of_two(self) -> bool;
|
||||
@@ -121,6 +121,15 @@ macro_rules! implement {
|
||||
type NumericSignedType = $SignedType;
|
||||
}
|
||||
|
||||
impl OverflowingAdd<Self> for $Type {
|
||||
type Output = Self;
|
||||
|
||||
#[inline]
|
||||
fn overflowing_add(self, rhs: Self) -> (Self, bool) {
|
||||
self.overflowing_add(rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl UnsignedInteger for $Type {
|
||||
type Signed = $SignedType;
|
||||
#[inline]
|
||||
@@ -219,10 +228,6 @@ macro_rules! implement {
|
||||
self.wrapping_pow(exp)
|
||||
}
|
||||
#[inline]
|
||||
fn overflowing_add(self, rhs: Self) -> (Self, bool) {
|
||||
self.overflowing_add(rhs)
|
||||
}
|
||||
#[inline]
|
||||
fn overflowing_sub(self, rhs: Self) -> (Self, bool) {
|
||||
self.overflowing_sub(rhs)
|
||||
}
|
||||
|
||||
@@ -150,6 +150,13 @@ pub(crate) fn wrapping_add_with_carry<T: UnsignedInteger>(l: T, r: T, c: bool) -
|
||||
}
|
||||
|
||||
pub(crate) fn wrapping_add_assign_words<T: UnsignedInteger>(lhs: &mut [T], rhs: &[T]) {
|
||||
let _carry = unsigned_overflowing_add_assign_words(lhs, rhs);
|
||||
}
|
||||
|
||||
pub(crate) fn unsigned_overflowing_add_assign_words<T: UnsignedInteger>(
|
||||
lhs: &mut [T],
|
||||
rhs: &[T],
|
||||
) -> bool {
|
||||
let iter = lhs
|
||||
.iter_mut()
|
||||
.zip(rhs.iter().copied().chain(std::iter::repeat(T::ZERO)));
|
||||
@@ -160,6 +167,8 @@ pub(crate) fn wrapping_add_assign_words<T: UnsignedInteger>(lhs: &mut [T], rhs:
|
||||
*lhs_block = result;
|
||||
carry = out_carry;
|
||||
}
|
||||
|
||||
carry
|
||||
}
|
||||
|
||||
/// lhs and rhs are slice of words.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use crate::core_crypto::prelude::{CastFrom, Numeric, UnsignedNumeric};
|
||||
use crate::core_crypto::prelude::{CastFrom, Numeric, OverflowingAdd, UnsignedNumeric};
|
||||
use std::ops::ShlAssign;
|
||||
|
||||
const fn one_for_unsigned_u64_based_integer<const N: usize>() -> [u64; N] {
|
||||
@@ -261,6 +261,18 @@ impl<const N: usize> std::ops::ShlAssign<usize> for StaticUnsignedBigInt<N> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<const N: usize> OverflowingAdd<Self> for StaticUnsignedBigInt<N> {
|
||||
type Output = Self;
|
||||
|
||||
fn overflowing_add(self, other: Self) -> (Self::Output, bool) {
|
||||
let mut result = self;
|
||||
let overflowed =
|
||||
super::algorithms::unsigned_overflowing_add_assign_words(&mut result.0, &other.0);
|
||||
|
||||
(result, overflowed)
|
||||
}
|
||||
}
|
||||
|
||||
impl<const N: usize> std::ops::Not for StaticUnsignedBigInt<N> {
|
||||
type Output = Self;
|
||||
|
||||
|
||||
@@ -25,12 +25,11 @@ impl U256 {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::panic::catch_unwind;
|
||||
|
||||
use rand::Rng;
|
||||
|
||||
use super::super::{u64_with_even_bits_set, u64_with_odd_bits_set};
|
||||
use super::*;
|
||||
use crate::core_crypto::prelude::OverflowingAdd;
|
||||
use rand::Rng;
|
||||
use std::panic::catch_unwind;
|
||||
|
||||
#[test]
|
||||
fn test_const() {
|
||||
@@ -221,6 +220,17 @@ mod tests {
|
||||
assert_eq!(U256::MAX + U256::from(1u32), U256::MIN);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_overflowing_add() {
|
||||
let (r, o) = U256::MAX.overflowing_add(U256::from(1u32));
|
||||
assert_eq!(r, U256::MIN);
|
||||
assert!(o);
|
||||
|
||||
let (r, o) = U256::MAX.overflowing_add(U256::from(0u32));
|
||||
assert_eq!(r, U256::MAX);
|
||||
assert!(!o);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sub_wrap_around() {
|
||||
assert_eq!(U256::MIN - U256::from(1u32), U256::MAX);
|
||||
|
||||
Reference in New Issue
Block a user