use crate::error::FancyError;
use itertools::Itertools;
mod binary;
mod bundle;
mod crt;
mod input;
pub use binary::{BinaryBundle, BinaryGadgets};
pub use bundle::{Bundle, BundleGadgets};
pub use crt::{CrtBundle, CrtGadgets};
pub use input::FancyInput;
pub trait HasModulus {
fn modulus(&self) -> u16;
}
pub trait Fancy {
type Item: Clone + HasModulus;
type Error: std::fmt::Debug + std::fmt::Display + std::convert::From<FancyError>;
fn constant(&mut self, x: u16, q: u16) -> Result<Self::Item, Self::Error>;
fn add(&mut self, x: &Self::Item, y: &Self::Item) -> Result<Self::Item, Self::Error>;
fn sub(&mut self, x: &Self::Item, y: &Self::Item) -> Result<Self::Item, Self::Error>;
fn cmul(&mut self, x: &Self::Item, c: u16) -> Result<Self::Item, Self::Error>;
fn mul(&mut self, x: &Self::Item, y: &Self::Item) -> Result<Self::Item, Self::Error>;
fn proj(
&mut self,
x: &Self::Item,
q: u16,
tt: Option<Vec<u16>>,
) -> Result<Self::Item, Self::Error>;
fn output(&mut self, x: &Self::Item) -> Result<(), Self::Error>;
fn add_many(&mut self, args: &[Self::Item]) -> Result<Self::Item, Self::Error> {
if args.len() < 2 {
return Err(Self::Error::from(FancyError::InvalidArgNum {
got: args.len(),
needed: 2,
}));
}
let mut z = args[0].clone();
for x in args.iter().skip(1) {
z = self.add(&z, x)?;
}
Ok(z)
}
fn xor(&mut self, x: &Self::Item, y: &Self::Item) -> Result<Self::Item, Self::Error> {
if x.modulus() != 2 {
return Err(Self::Error::from(FancyError::InvalidArgMod {
got: x.modulus(),
needed: 2,
}));
}
if y.modulus() != 2 {
return Err(Self::Error::from(FancyError::InvalidArgMod {
got: y.modulus(),
needed: 2,
}));
}
self.add(x, y)
}
fn negate(&mut self, x: &Self::Item) -> Result<Self::Item, Self::Error> {
if x.modulus() != 2 {
return Err(Self::Error::from(FancyError::InvalidArgMod {
got: x.modulus(),
needed: 2,
}));
}
let one = self.constant(1, 2)?;
self.xor(x, &one)
}
fn and(&mut self, x: &Self::Item, y: &Self::Item) -> Result<Self::Item, Self::Error> {
if x.modulus() != 2 {
return Err(Self::Error::from(FancyError::InvalidArgMod {
got: x.modulus(),
needed: 2,
}));
}
if y.modulus() != 2 {
return Err(Self::Error::from(FancyError::InvalidArgMod {
got: y.modulus(),
needed: 2,
}));
}
self.mul(x, y)
}
fn or(&mut self, x: &Self::Item, y: &Self::Item) -> Result<Self::Item, Self::Error> {
if x.modulus() != 2 {
return Err(Self::Error::from(FancyError::InvalidArgMod {
got: x.modulus(),
needed: 2,
}));
}
if y.modulus() != 2 {
return Err(Self::Error::from(FancyError::InvalidArgMod {
got: y.modulus(),
needed: 2,
}));
}
let notx = self.negate(x)?;
let noty = self.negate(y)?;
let z = self.and(¬x, ¬y)?;
self.negate(&z)
}
fn and_many(&mut self, args: &[Self::Item]) -> Result<Self::Item, Self::Error> {
if args.len() < 2 {
return Err(Self::Error::from(FancyError::InvalidArgNum {
got: args.len(),
needed: 2,
}));
}
args.iter()
.skip(1)
.fold(Ok(args[0].clone()), |acc, x| self.and(&(acc?), x))
}
fn or_many(&mut self, args: &[Self::Item]) -> Result<Self::Item, Self::Error> {
if args.len() < 2 {
return Err(Self::Error::from(FancyError::InvalidArgNum {
got: args.len(),
needed: 2,
}));
}
args.iter()
.skip(1)
.fold(Ok(args[0].clone()), |acc, x| self.or(&(acc?), x))
}
fn mod_change(&mut self, x: &Self::Item, to_modulus: u16) -> Result<Self::Item, Self::Error> {
let from_modulus = x.modulus();
if from_modulus == to_modulus {
return Ok(x.clone());
}
let tab = (0..from_modulus).map(|x| x % to_modulus).collect_vec();
self.proj(x, to_modulus, Some(tab))
}
fn adder(
&mut self,
x: &Self::Item,
y: &Self::Item,
carry_in: Option<&Self::Item>,
) -> Result<(Self::Item, Self::Item), Self::Error> {
if x.modulus() != 2 {
return Err(Self::Error::from(FancyError::InvalidArgMod {
got: x.modulus(),
needed: 2,
}));
}
if y.modulus() != 2 {
return Err(Self::Error::from(FancyError::InvalidArgMod {
got: y.modulus(),
needed: 2,
}));
}
if let Some(c) = carry_in {
let z1 = self.xor(x, y)?;
let z2 = self.xor(&z1, c)?;
let z3 = self.xor(x, c)?;
let z4 = self.and(&z1, &z3)?;
let carry = self.xor(&z4, x)?;
Ok((z2, carry))
} else {
let z = self.xor(x, y)?;
let carry = self.and(x, y)?;
Ok((z, carry))
}
}
fn mux(
&mut self,
b: &Self::Item,
x: &Self::Item,
y: &Self::Item,
) -> Result<Self::Item, Self::Error> {
let notb = self.negate(b)?;
let xsel = self.mul(¬b, x)?;
let ysel = self.mul(b, y)?;
self.add(&xsel, &ysel)
}
fn mux_constant_bits(
&mut self,
x: &Self::Item,
b1: bool,
b2: bool,
) -> Result<Self::Item, Self::Error> {
if x.modulus() != 2 {
return Err(Self::Error::from(FancyError::InvalidArgMod {
got: x.modulus(),
needed: 2,
}));
}
if !b1 && b2 {
Ok(x.clone())
} else if b1 && !b2 {
self.negate(x)
} else if !b1 && !b2 {
self.constant(0, 2)
} else {
self.constant(1, 2)
}
}
fn outputs(&mut self, xs: &[Self::Item]) -> Result<(), Self::Error> {
for x in xs.iter() {
self.output(x)?;
}
Ok(())
}
}