use std::num::Wrapping;
use std::ops::*;
macro_rules! define_wrapping_op {
($name:ident, $op:tt, $op_name:ident, $func_op:ident, $assign_name:ident, $assign_func:ident, $checked_func_op:ident) => {
impl $op_name for $name {
type Output = Self;
#[inline]
fn $func_op(self, rhs: Self) -> Self {
let $name(i1) = self;
let $name(i2) = rhs;
$name((Wrapping(i1) $op Wrapping(i2)).0)
}
}
impl $name {
pub fn $checked_func_op(self, rhs: Self) -> Self {
let $name(i1) = self;
let $name(i2) = rhs;
match i1.$checked_func_op(i2) {
None => panic!("Secret integer {} overflow!", stringify!($func_op)),
Some(r) => $name(r)
}
}
}
impl $assign_name for $name {
#[inline]
fn $assign_func(&mut self, rhs: Self) {
*self = *self $op rhs
}
}
}
}
macro_rules! define_bitwise_op {
($name:ident, $op:tt, $op_name:ident, $func_op:ident, $assign_name:ident, $assign_func:ident) => {
impl $op_name for $name {
type Output = Self;
#[inline]
fn $func_op(self, rhs: Self) -> Self {
let $name(i1) = self;
let $name(i2) = rhs;
$name(i1 $op i2)
}
}
impl $assign_name for $name {
#[inline]
fn $assign_func(&mut self, rhs: Self) {
*self = *self $op rhs
}
}
}
}
macro_rules! define_unary_op {
($name:ident, $op:tt, $op_name:ident, $func_op:ident) => {
impl $op_name for $name {
type Output = Self;
#[inline]
fn $func_op(self) -> Self {
let $name(i1) = self;
$name($op i1)
}
}
}
}
macro_rules! define_shift {
($name:ident, $op:tt, $op_name:ident, $func_op:ident, $assign_name:ident, $assign_func:ident) => {
impl $op_name<u32> for $name {
type Output = Self;
#[inline]
fn $func_op(self, rhs: u32) -> Self {
let $name(i1) = self;
$name(i1 $op rhs)
}
}
impl $assign_name<u32> for $name {
#[inline]
fn $assign_func(&mut self, rhs: u32) {
*self = *self $op rhs
}
}
}
}
macro_rules! define_secret_integer {
($name:ident, $repr:ty, $bits:tt) => {
#[derive(Clone, Copy, Default)]
pub struct $name(pub(crate) $repr);
impl $name {
pub fn classify<T : Into<$repr>>(x: T) -> Self {
$name(x.into())
}
pub fn declassify(self) -> $repr {
self.0
}
pub fn zero() -> Self {
$name(0)
}
pub fn one() -> Self {
$name(1)
}
pub fn ones() -> Self {
!Self::zero()
}
}
impl From<$repr> for $name {
fn from(x:$repr) -> Self {
Self::classify(x)
}
}
define_wrapping_op!($name, +, Add, add, AddAssign, add_assign, checked_add);
define_wrapping_op!($name, -, Sub, sub, SubAssign, sub_assign, checked_sub);
define_wrapping_op!($name, *, Mul, mul, MulAssign, mul_assign, checked_mul);
define_shift!($name, <<, Shl, shl, ShlAssign, shl_assign);
define_shift!($name, >>, Shr, shr, ShrAssign, shr_assign);
impl $name {
pub fn rotate_left(self, rotval:u32) -> Self {
let $name(i) = self;
$name(i.rotate_left(rotval))
}
pub fn rotate_right(self, rotval:u32) -> Self {
let $name(i) = self;
$name(i.rotate_right(rotval))
}
}
define_bitwise_op!($name, &, BitAnd, bitand, BitAndAssign, bitand_assign);
define_bitwise_op!($name, |, BitOr, bitor, BitOrAssign, bitor_assign);
define_bitwise_op!($name, ^, BitXor, bitxor, BitXorAssign, bitxor_assign);
define_unary_op!($name, !, Not, not);
}
}
macro_rules! define_secret_unsigned_integer {
($name:ident, $repr:ty, $bits:tt) => {
define_secret_integer!($name, $repr, $bits);
impl Neg for $name {
type Output = Self;
#[inline]
fn neg(self) -> Self {
let $name(i1) = self;
$name((Wrapping(!i1) + Wrapping(1)).0)
}
}
impl $name {
pub fn comp_eq(self, rhs: Self) -> Self {
let a = self; let b = rhs;
let x = a | b;
let minus_x = - x;
let x_or_minus_x = x | minus_x;
let xnx = x_or_minus_x >> ($bits - 1);
let c = xnx - Self::one();
c
}
pub fn comp_ne(self, rhs:Self) -> Self {
!self.comp_eq(rhs) ^ Self::ones()
}
pub fn comp_gte(self, rhs: Self) -> Self {
let x = self; let y = rhs;
let x_xor_y = x | y;
let x_sub_y = x - y;
let x_sub_y_xor_y = x_sub_y ^ y;
let q = x_xor_y ^ x_sub_y_xor_y;
let x_xor_q = x ^ q;
let x_xor_q_ = x_xor_q >> ($bits - 1 );
let c = x_xor_q_ - Self::one();
c
}
pub fn comp_gt(self, rhs:Self) -> Self {
self.comp_gte(rhs) ^ self.comp_eq(rhs)
}
pub fn comp_lte(self, rhs:Self) -> Self {
!self.comp_gt(rhs)
}
pub fn comp_lt(self, rhs:Self) -> Self {
!self.comp_gte(rhs)
}
}
};
}
macro_rules! define_secret_signed_integer {
($name:ident, $repr:ty, $bits:tt) => {
define_secret_integer!($name, $repr, $bits);
define_unary_op!($name, -, Neg, neg);
}
}
define_secret_unsigned_integer!(U8, u8, 8);
define_secret_unsigned_integer!(U16, u16, 16);
define_secret_unsigned_integer!(U32, u32, 32);
define_secret_unsigned_integer!(U64, u64, 64);
define_secret_unsigned_integer!(U128, u128, 128);
define_secret_signed_integer!(I8, i8, 8);
define_secret_signed_integer!(I16, i16, 16);
define_secret_signed_integer!(I32, i32, 32);
define_secret_signed_integer!(I64, i64, 64);
define_secret_signed_integer!(I128, i128, 128);
macro_rules! define_safe_casting {
($from:ident, $to:ident, $to_repr:ident) => {
impl From<$from> for $to {
fn from(x:$from) -> $to {
$to(x.0 as $to_repr)
}
}
}
}
macro_rules! define_unsafe_casting {
($from:ident, $to:ident, $to_repr:ident) => {
impl From<$from> for $to {
fn from(x:$from) -> $to {
$to(x.0 as $to_repr)
}
}
}
}
macro_rules! define_signed_unsigned_casting {
($unsigned:ident, $unsiged_repr:ident, $signed:ident, $signed_repr:ident) => {
impl From<$unsigned> for $signed {
fn from(x:$unsigned) -> $signed {
$signed(x.0 as $signed_repr)
}
}
}
}
define_safe_casting!(U8, U128, u128);
define_unsafe_casting!(U128, U8, u8);
define_safe_casting!(U16, U128, u128);
define_unsafe_casting!(U128, U16, u16);
define_safe_casting!(U32, U128, u128);
define_unsafe_casting!(U128, U32, u32);
define_safe_casting!(U64, U128, u128);
define_unsafe_casting!(U128, U64, u64);
define_safe_casting!(U8, U64, u64);
define_unsafe_casting!(U64, U8, u8);
define_safe_casting!(U16, U64, u64);
define_unsafe_casting!(U64, U16, u16);
define_safe_casting!(U32, U64, u64);
define_unsafe_casting!(U64, U32, u32);
define_safe_casting!(U8, U32, u32);
define_unsafe_casting!(U32, U8, u8);
define_safe_casting!(U16, U32, u32);
define_unsafe_casting!(U32, U16, u16);
define_safe_casting!(U8, U16, u16);
define_unsafe_casting!(U16, U8, u8);
define_safe_casting!(I8, I128, i128);
define_unsafe_casting!(I128, I8, i8);
define_safe_casting!(I16, I128, i128);
define_unsafe_casting!(I128, I16, i16);
define_safe_casting!(I32, I128, i128);
define_unsafe_casting!(I128, I32, i32);
define_safe_casting!(I64, I128, i128);
define_unsafe_casting!(I128, I64, i64);
define_safe_casting!(I8, I64, i64);
define_unsafe_casting!(I64, I8, i8);
define_safe_casting!(I16, I64, i64);
define_unsafe_casting!(I64, I16, i16);
define_safe_casting!(I32, I64, i64);
define_unsafe_casting!(I64, I32, i32);
define_safe_casting!(I8, I32, i32);
define_unsafe_casting!(I32, I8, i8);
define_safe_casting!(I16, I32, i32);
define_unsafe_casting!(I32, I16, i16);
define_safe_casting!(I8, I16, i16);
define_unsafe_casting!(I16, I8, i8);
define_signed_unsigned_casting!(U128, u128, I128, i128);
define_signed_unsigned_casting!(U64, u64, I64, i64);
define_signed_unsigned_casting!(U32, u32, I32, i32);
define_signed_unsigned_casting!(U16, u16, I16, i16);
define_signed_unsigned_casting!(U8, u8, I8, i8);