use crate::{Sbu1, SecretBinary, SecretBinaryFixedSize};
use pbc_traits::{ReadInt, WriteInt};
use std::cmp::Ordering;
use std::io::{Read, Write};
use std::num::Wrapping;
use std::ops::{Add, BitAnd, BitOr, BitXor, Mul, Shl, Shr, Sub};
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub struct Sbi<NT> {
secret: NT,
}
impl<NT> From<NT> for Sbi<NT> {
fn from(secret: NT) -> Self {
Sbi { secret }
}
}
impl<NT> Mul for Sbi<NT>
where
NT: Mul<Output = NT>,
{
type Output = Sbi<NT>;
fn mul(self, rhs: Self) -> Self::Output {
Self {
secret: self.secret * rhs.secret,
}
}
}
impl<NT> Add for Sbi<NT>
where
Wrapping<NT>: Add<Output = Wrapping<NT>>,
{
type Output = Sbi<NT>;
fn add(self, rhs: Self) -> Self::Output {
let wrapped = Wrapping(self.secret) + Wrapping(rhs.secret);
Self { secret: wrapped.0 }
}
}
impl<NT> Sub for Sbi<NT>
where
Wrapping<NT>: Sub<Output = Wrapping<NT>>,
{
type Output = Sbi<NT>;
fn sub(self, rhs: Self) -> Self::Output {
let wrapped = Wrapping(self.secret) - Wrapping(rhs.secret);
Self { secret: wrapped.0 }
}
}
impl<NT, Rhs> Shl<Rhs> for Sbi<NT>
where
Wrapping<NT>: Shl<Rhs, Output = Wrapping<NT>>,
{
type Output = Sbi<NT>;
fn shl(self, rhs: Rhs) -> Self::Output {
let wrapped = Wrapping(self.secret) << rhs;
Self { secret: wrapped.0 }
}
}
impl<NT, Rhs> Shr<Rhs> for Sbi<NT>
where
Wrapping<NT>: Shr<Rhs, Output = Wrapping<NT>>,
{
type Output = Sbi<NT>;
fn shr(self, rhs: Rhs) -> Self::Output {
let wrapped = Wrapping(self.secret) >> rhs;
Self { secret: wrapped.0 }
}
}
impl<NT> BitAnd for Sbi<NT>
where
NT: BitAnd<Output = NT>,
{
type Output = Sbi<NT>;
fn bitand(self, rhs: Self) -> Self::Output {
Self {
secret: self.secret & rhs.secret,
}
}
}
impl<NT> BitXor for Sbi<NT>
where
NT: BitXor<Output = NT>,
{
type Output = Sbi<NT>;
fn bitxor(self, rhs: Self) -> Self::Output {
Self {
secret: self.secret ^ rhs.secret,
}
}
}
impl<NT> BitOr for Sbi<NT>
where
NT: BitOr<Output = NT>,
{
type Output = Sbi<NT>;
fn bitor(self, rhs: Self) -> Self::Output {
Self {
secret: self.secret | rhs.secret,
}
}
}
impl<NT> PartialOrd for Sbi<NT>
where
NT: PartialOrd,
{
fn partial_cmp(&self, rhs: &Self) -> Option<Ordering> {
self.secret.partial_cmp(&rhs.secret)
}
fn lt(&self, rhs: &Self) -> Sbu1 {
self.secret < rhs.secret
}
fn le(&self, rhs: &Self) -> Sbu1 {
self.secret <= rhs.secret
}
fn gt(&self, rhs: &Self) -> Sbu1 {
self.secret > rhs.secret
}
fn ge(&self, rhs: &Self) -> Sbu1 {
self.secret >= rhs.secret
}
}
pub trait FromToBits {
type BitsType;
fn to_le_bits(self) -> Self::BitsType;
fn from_le_bits(bits: Self::BitsType) -> Self;
}
fn bytes_to_bits<const NBITS: usize, const NBYTES: usize>(bytes: [u8; NBYTES]) -> [Sbu1; NBITS] {
let mut bits = [false; NBITS];
for i in 0..NBITS {
bits[i] = 0x1 == (0x1 & (bytes[i >> 3] >> (i & 0x7)));
}
bits
}
fn bits_to_bytes<const NBITS: usize, const NBYTES: usize>(bits: [Sbu1; NBITS]) -> [u8; NBYTES] {
let mut bytes = [0; NBYTES];
for i in 0..NBYTES {
let mut byte = 0;
for j in 0..8 {
byte ^= (bits[(i << 3) ^ j] as u8) << j
}
bytes[i] = byte;
}
bytes
}
macro_rules! impl_from_to_bits {
($($inner_type:ty)*) => {
$(
#[doc = concat!("Allows conversions from [`Sbi<", stringify!($inner_type), ">`] to array of bits and back.")]
impl FromToBits for Sbi<$inner_type> {
type BitsType = [Sbu1; <$inner_type>::BITS as usize];
fn to_le_bits(self) -> Self::BitsType {
bytes_to_bits(<$inner_type>::to_le_bytes(self.secret))
}
fn from_le_bits(bits: Self::BitsType) -> Self {
Self::from(<$inner_type>::from_le_bytes(bits_to_bytes(bits)))
}
}
)*
}
}
impl_from_to_bits!(
u8
u16
u32
u64
u128
i8
i16
i32
i64
i128
);
#[doc = "Implementation of [`SecretBinaryFixedSize`] trait for [`Sbu1`]."]
impl SecretBinaryFixedSize for Sbu1 {
const BITS: u32 = 1;
}
#[doc = "Implementation of [`SecretBinary`] trait for [`Sbu1`]. Uses a full byte to present a single bit."]
impl SecretBinary for Sbu1 {
fn secret_read_from<T: Read>(reader: &mut T) -> Self {
reader.read_u8() != 0
}
fn secret_write_to<T: Write>(&self, writer: &mut T) -> std::io::Result<()> {
writer.write_u8(u8::from(*self))
}
}
macro_rules! read_write_secret {
($($inner_type:ty, $read_method:ident, $write_method:ident)*) => {
$(
#[doc = concat!("Implementation of [`SecretBinaryFixedSize`] trait for [`Sbi<", stringify!($inner_type), ">`].")]
impl SecretBinaryFixedSize for Sbi<$inner_type> {
const BITS: u32 = <$inner_type>::BITS;
}
#[doc = concat!("Implementation of [`SecretBinary`] trait for [`Sbi<", stringify!($inner_type), ">`]. Encoded as a little-endian integer.")]
impl SecretBinary for Sbi<$inner_type> {
fn secret_read_from<T: Read>(reader: &mut T) -> Self {
Self::from(reader.$read_method())
}
fn secret_write_to<T: Write>(&self, writer: &mut T) -> std::io::Result<()> {
writer.$write_method(self.secret)
}
}
)*
}
}
read_write_secret!(i8, read_i8, write_i8);
read_write_secret!(i16, read_i16_le, write_i16_le);
read_write_secret!(i32, read_i32_le, write_i32_le);
read_write_secret!(i64, read_i64_le, write_i64_le);
read_write_secret!(i128, read_i128_le, write_i128_le);
read_write_secret!(u8, read_u8, write_u8);
read_write_secret!(u16, read_u16_le, write_u16_le);
read_write_secret!(u32, read_u32_le, write_u32_le);
read_write_secret!(u64, read_u64_le, write_u64_le);
read_write_secret!(u128, read_u128_le, write_u128_le);
macro_rules! sbi_from_inner {
($($type_from:ty, $type_to:ty)*) => {
$(
impl From<$type_from> for Sbi<$type_to> {
#[doc = concat!("Create a secret [`Sbi<", stringify!($type_to), ">`] from an [`", stringify!($type_from), "`].")]
fn from(secret: $type_from) -> Self {
Sbi { secret: secret as $type_to }
}
}
impl From<Sbi<$type_from>> for Sbi<$type_to> {
#[doc = concat!("Cast to a [`Sbi<", stringify!($type_to), ">`] from an [`Sbi<", stringify!($type_from), ">`].")]
fn from(secret: Sbi<$type_from>) -> Self {
Sbi { secret: secret.secret as $type_to }
}
}
)*
};
}
macro_rules! sbi_from {
($ty_to:ty, $($ty_from:ty),*) => {
$(
sbi_from_inner!($ty_from, $ty_to);
)*
};
}
sbi_from!(i8, i16, i32, i64, i128, u8, u16, u32, u64, u128);
sbi_from!(i16, i8, i32, i64, i128, u8, u16, u32, u64, u128);
sbi_from!(i32, i8, i16, i64, i128, u8, u16, u32, u64, u128);
sbi_from!(i64, i8, i16, i32, i128, u8, u16, u32, u64, u128);
sbi_from!(i128, i8, i16, i32, i64, u8, u16, u32, u64, u128);
sbi_from!(u8, i8, i16, i32, i64, i128, u16, u32, u64, u128);
sbi_from!(u16, i8, i16, i32, i64, i128, u8, u32, u64, u128);
sbi_from!(u32, i8, i16, i32, i64, i128, u8, u16, u64, u128);
sbi_from!(u64, i8, i16, i32, i64, i128, u8, u16, u32, u128);
sbi_from!(u128, i8, i16, i32, i64, i128, u8, u16, u32, u64);