diff --git a/mpc-algebra/examples/algebra.rs b/mpc-algebra/examples/algebra.rs index 01138096..61eb341c 100644 --- a/mpc-algebra/examples/algebra.rs +++ b/mpc-algebra/examples/algebra.rs @@ -5,6 +5,7 @@ use ark_ff::{One, Zero}; use ark_poly::reveal; use ark_std::{end_timer, start_timer}; use log::debug; +use mpc_algebra::boolean_field::MpcBooleanField; use mpc_algebra::{ share, AdditiveFieldShare, BitAdd, BitDecomposition, BitwiseLessThan, EqualityZero, LessThan, LogicalOperations, MpcField, Reveal, UniformBitRand }; @@ -27,6 +28,8 @@ struct Opt { type F = ark_bls12_377::Fr; type S = AdditiveFieldShare; type MF = MpcField; +type MBF = MpcBooleanField; + fn test_add() { // init communication protocol @@ -64,7 +67,7 @@ fn test_div() { } fn test_sum() { - let a = vec![ + let a = [ MF::from_public(F::from(1u64)), MF::from_public(F::from(2u64)), MF::from_public(F::from(3u64)), @@ -80,7 +83,7 @@ fn test_bit_rand() { let mut counter = [0, 0, 0]; for _ in 0..1000 { - let a = MF::bit_rand(&mut rng).reveal(); + let a = MBF::bit_rand(&mut rng).reveal(); if a.is_zero() { counter[0] += 1; @@ -99,7 +102,7 @@ fn test_rand_number_bitwise() { let mut rng = thread_rng(); for _ in 0..10 { - let (a, b) = MF::rand_number_bitwise(&mut rng); + let (a, b) = MBF::rand_number_bitwise(&mut rng); let revealed_a = a.iter().map(|x| x.reveal()).collect::>(); let revealed_b = b.reveal(); @@ -128,10 +131,10 @@ fn test_bitwise_lt() { for _ in 0..10 { let a = (0..modulus_size) - .map(|_| MF::bit_rand(rng)) + .map(|_| MBF::bit_rand(rng)) .collect::>(); let b = (0..modulus_size) - .map(|_| MF::bit_rand(rng)) + .map(|_| MBF::bit_rand(rng)) .collect::>(); let a_bigint = @@ -186,9 +189,9 @@ fn test_less_than() { fn test_and() { let mut rng = ark_std::test_rng(); - let a00 = vec![MF::zero(), MF::zero()]; - let a10 = vec![MF::one(), MF::zero()]; - let a11 = vec![MF::one(), MF::one()]; + let a00 = vec![MBF::pub_false(),MBF::pub_true()]; + let a10 = vec![MBF::pub_true(), MBF::pub_false()]; + let a11 = vec![MBF::pub_true(), MBF::pub_true()]; assert_eq!(a00.kary_and().reveal(), F::zero()); assert_eq!(a10.kary_and().reveal(), F::zero()); @@ -197,7 +200,7 @@ fn test_and() { let mut counter = [0, 0]; for _ in 0..100 { - let a = (0..3).map(|_| MF::bit_rand(&mut rng)).collect::>(); + let a = (0..3).map(|_| MBF::bit_rand(&mut rng)).collect::>(); let res = a.kary_and(); @@ -214,9 +217,9 @@ fn test_and() { fn test_or() { let mut rng = thread_rng(); - let a00 = vec![MF::zero(), MF::zero()]; - let a10 = vec![MF::one(), MF::zero()]; - let a11 = vec![MF::one(), MF::one()]; + let a00 = vec![MBF::pub_false(), MBF::pub_false()]; + let a10 = vec![MBF::pub_true(), MBF::pub_false()]; + let a11 = vec![MBF::pub_true(), MBF::pub_true()]; assert_eq!(a00.kary_or().reveal(), F::zero()); assert_eq!(a10.kary_or().reveal(), F::one()); @@ -225,7 +228,7 @@ fn test_or() { let mut counter = [0, 0]; for _ in 0..100 { - let a = (0..3).map(|_| MF::bit_rand(&mut rng)).collect::>(); + let a = (0..3).map(|_| MBF::bit_rand(&mut rng)).collect::>(); let res = a.kary_or(); @@ -239,6 +242,28 @@ fn test_or() { println!("OR counter is {:?}", counter); } +fn test_xor() { + let mut rng = ark_std::test_rng(); + let mut counter = [0, 0]; + + for _ in 0..100 { + let a = MBF::bit_rand(&mut rng); + let b = MBF::bit_rand(&mut rng); + + let res = a ^ b; + + println!("unbounded and is {:?}", res.reveal()); + assert_eq!(res.reveal().is_one(),a.reveal().is_one() ^ b.reveal().is_one()); + if res.reveal().is_zero() { + counter[0] += 1; + } else if res.reveal().is_one() { + counter[1] += 1; + } + } + println!("AND counter is {:?}", counter); +} + + fn test_equality_zero() { let mut rng = ark_std::test_rng(); @@ -268,12 +293,15 @@ fn test_equality_zero() { fn test_carries() { // a = 0101 = 5, b = 1100= 12 - let mut a = vec![MF::from_add_shared(F::from(0u64)); 4]; - let mut b = vec![MF::from_add_shared(F::from(0u64)); 4]; - a[0] += MF::from_public(F::from(1u64)); - a[2] += MF::one(); - b[2] += MF::one(); - b[3] += MF::one(); + let mut a = vec![MBF::from_add_shared(F::zero()); 4]; + let mut b = vec![MBF::from_add_shared(F::zero()); 4]; + // TODO: improve how to initialize + a[0] = a[0] | MBF::pub_true(); + a[2] = a[2] | MBF::pub_true(); + b[2] = b[2] | MBF::pub_true(); + b[3] = b[3] | MBF::pub_true(); + + // TODO: better way to initialize let c = a.carries(&b); @@ -281,14 +309,14 @@ fn test_carries() { assert_eq!(c.reveal(), vec![F::zero(), F::zero(), F::one(), F::one()]); // a = 010011 = 19, b = 101010= 42 - let mut a = vec![MF::from_add_shared(F::from(0u64)); 6]; - let mut b = vec![MF::from_add_shared(F::from(0u64)); 6]; - a[0] += MF::one(); - a[1] += MF::one(); - a[4] += MF::one(); - b[1] += MF::one(); - b[3] += MF::one(); - b[5] += MF::one(); + let mut a = vec![MBF::from_add_shared(F::from(0u64)); 6]; + let mut b = vec![MBF::from_add_shared(F::from(0u64)); 6]; + a[0] = a[0] | MBF::pub_true(); + a[1] = a[1] | MBF::pub_true(); + a[4] = a[4] | MBF::pub_true(); + b[1] = b[1] | MBF::pub_true(); + b[3] = b[3] | MBF::pub_true(); + b[5] = b[5] | MBF::pub_true(); let c = a.carries(&b); @@ -309,8 +337,8 @@ fn test_carries() { fn test_bit_add() { let rng = &mut thread_rng(); - let (rand_a, a) = MF::rand_number_bitwise(rng); - let (rand_b, b) = MF::rand_number_bitwise(rng); + let (rand_a, a) = MBF::rand_number_bitwise(rng); + let (rand_b, b) = MBF::rand_number_bitwise(rng); let c_vec = rand_a.bit_add(&rand_b); @@ -372,6 +400,8 @@ fn main() { println!("Test and passed"); test_or(); println!("Test or passed"); + test_xor(); + println!("Test xor passed"); test_equality_zero(); println!("Test equality_zero passed"); diff --git a/mpc-algebra/src/mpc_primitives.rs b/mpc-algebra/src/mpc_primitives.rs index 081d202e..c4fde21c 100644 --- a/mpc-algebra/src/mpc_primitives.rs +++ b/mpc-algebra/src/mpc_primitives.rs @@ -1,9 +1,11 @@ use rand::Rng; pub trait UniformBitRand: Sized { + type BaseField; + fn bit_rand(rng: &mut R) -> Self; // little-endian - fn rand_number_bitwise(rng: &mut R) -> (Vec, Self); + fn rand_number_bitwise(rng: &mut R) -> (Vec, Self::BaseField); } pub trait BitwiseLessThan { @@ -12,7 +14,7 @@ pub trait BitwiseLessThan { fn is_smaller_than_le(&self, other: &Self) -> Self::Output; } -pub trait LessThan : UniformBitRand { +pub trait LessThan { type Output; fn is_smaller_or_equal_than_mod_minus_one_div_two(&self) -> Self::Output; @@ -28,13 +30,14 @@ pub trait LogicalOperations { } pub trait EqualityZero { - fn is_zero_shared(&self) -> Self; + type Output; + fn is_zero_shared(&self) -> Self::Output; } pub trait BitDecomposition { - type Output; + type BooleanField; - fn bit_decomposition(&self) -> Self::Output; + fn bit_decomposition(&self) -> Vec; } pub trait BitAdd { diff --git a/mpc-algebra/src/r1cs_helper/mpc_fp.rs b/mpc-algebra/src/r1cs_helper/mpc_fp.rs index a6e12e65..cb78bc3e 100644 --- a/mpc-algebra/src/r1cs_helper/mpc_fp.rs +++ b/mpc-algebra/src/r1cs_helper/mpc_fp.rs @@ -3,13 +3,9 @@ use std::borrow::Borrow; use ark_ff::{Field, PrimeField, SquareRootField}; use ark_r1cs_std::{ alloc::{AllocVar, AllocationMode}, - fields::{ - fp::{AllocatedFp, FpVar}, - FieldOpsBounds, FieldVar, - }, + fields::FieldOpsBounds, impl_ops, - select::CondSelectGadget, - R1CSVar, ToConstraintFieldGadget, + R1CSVar, }; use ark_r1cs_std::{impl_bounded_ops, Assignment}; use ark_relations::{ @@ -159,7 +155,7 @@ impl> MpcAllocatedFp { #[tracing::instrument(target = "r1cs")] pub fn add(&self, other: &Self) -> Self { let value = match (self.value, other.value) { - (Some(val1), Some(val2)) => Some(val1 + &val2), + (Some(val1), Some(val2)) => Some(val1 + val2), (..) => None, }; @@ -176,7 +172,7 @@ impl> MpcAllocatedFp { #[tracing::instrument(target = "r1cs")] pub fn sub(&self, other: &Self) -> Self { let value = match (self.value, other.value) { - (Some(val1), Some(val2)) => Some(val1 - &val2), + (Some(val1), Some(val2)) => Some(val1 - val2), (..) => None, }; @@ -193,7 +189,7 @@ impl> MpcAllocatedFp { #[tracing::instrument(target = "r1cs")] pub fn mul(&self, other: &Self) -> Self { let product = MpcAllocatedFp::new_witness(self.cs.clone(), || { - Ok(self.value.get()? * &other.value.get()?) + Ok(self.value.get()? * other.value.get()?) }) .unwrap(); self.cs @@ -463,11 +459,11 @@ impl> MpcAllocatedFp { let is_zero_value = self.value.get()?.is_zero_shared(); let is_not_zero = - MpcBoolean::new_witness(self.cs.clone(), || Ok(MpcField::one() - is_zero_value))?; + MpcBoolean::new_witness(self.cs.clone(), || Ok((!is_zero_value).field()))?; let multiplier = self .cs - .new_witness_variable(|| (self.value.get()? + is_zero_value).inverse().get())?; + .new_witness_variable(|| (self.value.get()? + is_zero_value.field()).inverse().get())?; self.cs .enforce_constraint(lc!() + self.variable, lc!() + multiplier, is_not_zero.lc())?; @@ -554,8 +550,7 @@ impl> MpcToBitsGadget #[tracing::instrument(target = "r1cs")] fn to_non_unique_bits_le(&self) -> Result>, SynthesisError> { let cs = self.cs.clone(); - use ark_ff::BitIteratorBE; - let mut bits = if let Some(value) = self.value { + let bits = if let Some(value) = self.value { // let field_char = BitIteratorBE::new(F::characteristic()); // let bits: Vec<_> = BitIteratorBE::new(value.into_repr()) // .zip(field_char) @@ -574,7 +569,7 @@ impl> MpcToBitsGadget let bits: Vec<_> = bits .into_iter() - .map(|b| MpcBoolean::new_witness(cs.clone(), || b.get())) + .map(|b| MpcBoolean::new_witness(cs.clone(), || b.get().map(|b| b.field()))) .collect::>()?; let mut lc = LinearCombination::zero(); @@ -690,9 +685,9 @@ impl> MpcTwoBitLookupGadget for MpcAllocat })?; let one = Variable::One; b.cs().enforce_constraint( - lc!() + b[1].lc() * (c[3] - &c[2] - &c[1] + &c[0]) + (c[1] - &c[0], one), + lc!() + b[1].lc() * (c[3] - c[2] - c[1] + c[0]) + (c[1] - c[0], one), lc!() + b[0].lc(), - lc!() + result.variable - (c[0], one) + b[1].lc() * (c[0] - &c[2]), + lc!() + result.variable - (c[0], one) + b[1].lc() * (c[0] - c[2]), )?; Ok(result) diff --git a/mpc-algebra/src/wire.rs b/mpc-algebra/src/wire.rs index 0b08b635..53387960 100644 --- a/mpc-algebra/src/wire.rs +++ b/mpc-algebra/src/wire.rs @@ -1,4 +1,5 @@ pub mod field; +pub mod boolean_field; pub use field::*; pub mod group; pub use group::*; diff --git a/mpc-algebra/src/wire/boolean_field.rs b/mpc-algebra/src/wire/boolean_field.rs new file mode 100644 index 00000000..35396b04 --- /dev/null +++ b/mpc-algebra/src/wire/boolean_field.rs @@ -0,0 +1,310 @@ +use core::panic; +use std::ops::{BitAnd, BitOr, BitXor, Not}; +use ark_ff::{BigInteger, Field, FpParameters, One, PrimeField, SquareRootField, UniformRand, Zero}; +use mpc_trait::MpcWire; +use rand::Rng; +use crate::{BitAdd, BitwiseLessThan, FieldShare, MpcField, Reveal, UniformBitRand}; + +#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub struct MpcBooleanField>(MpcField); + +impl> MpcBooleanField { + pub fn pub_true() -> Self { + Self(MpcField::one()) + } + + pub fn pub_false() -> Self { + Self(MpcField::zero()) + } + + pub fn field(&self) -> MpcField { + self.0 + } + + pub fn and(self, other: Self) -> Self { + Self(self.0 * other.0) + } + + pub fn or(self, other: Self) -> Self { + Self(self.0 + other.0 - (self.0 * other.0)) + } + + pub fn xor(self, other: Self) -> Self { + Self(self.0 + other.0 - (self.0 * other.0 * MpcField::from_public(F::from(2u8)))) + } +} + +impl> Not for MpcBooleanField { + type Output = Self; + + fn not(self) -> Self::Output { + Self (MpcField::one() - self.0) + } +} + +impl> BitAnd for MpcBooleanField { + type Output = Self; + + fn bitand(self, rhs: Self) -> Self::Output { + self.and(rhs) + } +} + +impl> BitOr for MpcBooleanField { + type Output = Self; + + fn bitor(self, rhs: Self) -> Self::Output { + self.or(rhs) + } +} + +impl> BitXor for MpcBooleanField { + type Output = Self; + + fn bitxor(self, rhs: Self) -> Self::Output { + self.xor(rhs) + } +} + +// from MpcBooleanField to MpcField +impl> From> for MpcField { + fn from(b: MpcBooleanField) -> Self { + b.0 + } +} + +// from MpcField to MpcBooleanField +impl> From> for MpcBooleanField { + fn from(f: MpcField) -> Self { + Self(f) + } +} + +// from bool to MpcBooleanField +impl> From for MpcBooleanField { + fn from(b: bool) -> Self { + if b { + Self::pub_true() + } else { + Self::pub_false() + } + } +} + +impl> BitwiseLessThan for Vec> { + type Output = MpcBooleanField; + + fn is_smaller_than_le(&self, other: &Self) -> Self::Output { + let modulus_size = F::Params::MODULUS_BITS as usize; + assert_eq!(self.len(), modulus_size); + assert_eq!(other.len(), modulus_size); + + // [c_i] = [a_i \oplus b_i] + let c = self + .iter() + .zip(other.iter()) + .map(|(&a, &b)| a ^ b) + .collect::>(); + let rev_c = c.into_iter().rev().collect::>(); + + // d_i = OR_{j=i}^{modulus_size-1} c_j + let mut d = vec![rev_c[0]]; + for i in 0..modulus_size -1 { + d.push(d[i]|rev_c[i+1]); + } + d.reverse(); + + let e = (0..modulus_size) + .map(|i| { + if i == modulus_size - 1 { + d[modulus_size - 1].field() + } else { + d[i].field() - d[i + 1].field() + } + }) + .collect::>>(); + + Self::Output::from(e.iter().zip(other.iter()).map(|(&e, &b)| e * b.field()).sum::>()) + } +} + +impl> UniformBitRand for MpcBooleanField { + type BaseField = MpcField; + + fn bit_rand(rng: &mut R) -> Self { + let r = Self::BaseField::rand(rng); + let r2 = (r * r).reveal(); + let mut root_r2; + + loop { + root_r2 = r2.sqrt().unwrap(); + + if !root_r2.is_zero() { + break; + } + } + + Self((r / Self::BaseField::from_public(root_r2) + Self::BaseField::one()) / Self::BaseField::from_public(F::from(2u8))) + } + + fn rand_number_bitwise(rng: &mut R) -> (Vec, Self::BaseField) { + let modulus_size = F::Params::MODULUS_BITS as usize; + + let mut modulus_bits = F::Params::MODULUS + .to_bits_le() + .iter() + .map(|&b| Self::from(b)) + .collect::>(); + + modulus_bits = modulus_bits[..modulus_size].to_vec(); + + let valid_bits = loop { + let bits = (0..modulus_size) + .map(|_| Self::bit_rand(rng)) + .collect::>(); + + if bits.clone().is_smaller_than_le(&modulus_bits).field().reveal().is_one() { + break bits; + } + }; + + // bits to field elemetn (little endian) + let num = valid_bits.iter().map(|b|b.field()).rev().fold(Self::BaseField::zero(), |acc, x| { + acc * Self::BaseField::from_public(F::from(2u8)) + x + }); + + (valid_bits, num) + } +} + +impl > MpcWire for MpcBooleanField { + fn is_shared(&self) -> bool { + self.field().is_shared() + } + + fn publicize(&mut self) { + self.field().publicize(); + } + + fn publicize_cow<'b>(&'b self) -> std::borrow::Cow<'b, Self> { + if self.is_shared() { + let mut s = self.clone(); + s.publicize(); + std::borrow::Cow::Owned(s) + } else { + std::borrow::Cow::Borrowed(self) + } + } +} + + +impl> BitAdd for Vec> { + type Output = Self; + + fn carries(&self, other: &Self) -> Self::Output { + match self.is_shared() { + true => { + assert_eq!(self.len(), other.len()); + let l = self.len(); // l is the bit length. + + let s_vec = self + .iter() + .zip(other.iter()) + .map(|(a, b)| *a & *b) + .collect::>(); + + let p_vec = (0..l) + .map(|i| { + self[i].field() + other[i].field() - MpcField::::from_public(F::from(2u64)) * s_vec[i].field() + }) + .collect::>(); + + let ret = (0..l) + .scan(MpcField::::zero(), |is_s, i| { + *is_s = s_vec[i].field() + p_vec[i] * *is_s; + Some(*is_s) + }) + .collect::>(); + + ret.into_iter().map(MpcBooleanField::::from).collect() + } + false => { + panic!("public is not expected here"); + } + } + } + + /// This function is used to add two bit vectors of lenght l. + /// Returns a bit vector of length l+1 (bit length always increase by 1). + fn bit_add(self, other: &Self) -> Self::Output { + match self.is_shared() { + true => { + assert_eq!(self.len(), other.len()); + let l = self.len(); // l is the bit length. + let c_vec = self.carries(other); + + (0..=l) + .map(|i| { + if i == 0 { + (self[0].field() + other[0].field() + - MpcField::::from_public(F::from(2u64)) * c_vec[0].field()).into() + } else if i == l { + c_vec[l - 1] + } else { + (self[i].field() + other[i].field() + c_vec[i - 1].field() + - MpcField::::from_public(F::from(2u64)) * c_vec[i].field()).into() + } + }) + .collect() + } + false => { + panic!("public is not expected here"); + } + } + } +} + + +impl> Reveal for MpcBooleanField { + type Base = F; + #[inline] + fn reveal(self) -> Self::Base { + self.0.reveal() + } + #[inline] + fn from_public(b: Self::Base) -> Self { + if b == F::zero() { + Self::pub_false() + } else if b == F::one() { + Self::pub_true() + } else { + panic!("not boolean") + } + + } + #[inline] + fn from_add_shared(b: Self::Base) -> Self { + MpcField::Shared(S::from_add_shared(b)).into() + } + #[inline] + fn unwrap_as_public(self) -> Self::Base { + match self.field() { + MpcField::::Shared(s) => s.unwrap_as_public(), + MpcField::::Public(s) => s, + } + } + #[inline] + fn king_share(_f: Self::Base, _rng: &mut R) -> Self { + todo!() + } + #[inline] + fn king_share_batch(_f: Vec, _rng: &mut R) -> Vec { + todo!() + } + fn init_protocol() { + MpcField::::init_protocol() + } + fn deinit_protocol() { + MpcField::::deinit_protocol() + } +} \ No newline at end of file diff --git a/mpc-algebra/src/wire/field.rs b/mpc-algebra/src/wire/field.rs index 8437c1b7..7b959ad2 100644 --- a/mpc-algebra/src/wire/field.rs +++ b/mpc-algebra/src/wire/field.rs @@ -14,13 +14,14 @@ use zeroize::Zeroize; use log::debug; -use ark_ff::{poly_stub, prelude::*, BigInteger256, BitIteratorBE, FftField}; +use ark_ff::{poly_stub, prelude::*, BitIteratorBE, FftField}; use ark_ff::{FromBytes, ToBytes}; use ark_serialize::{ CanonicalDeserialize, CanonicalDeserializeWithFlags, CanonicalSerialize, CanonicalSerializeWithFlags, }; +use crate::boolean_field::MpcBooleanField; // use crate::channel::MpcSerNet; use crate::share::field::FieldShare; use crate::{BeaverSource, BitAdd, BitDecomposition, BitwiseLessThan, LessThan, LogicalOperations, Reveal}; @@ -218,93 +219,8 @@ impl> PubUniformRand for MpcField { } } -impl> UniformBitRand for MpcField { - fn bit_rand(rng: &mut R) -> Self { - let r = MpcField::::rand(rng); - let r2 = (r * r).reveal(); - let mut root_r2; - - loop { - root_r2 = r2.sqrt().unwrap(); - - if !root_r2.is_zero() { - break; - } - } - - (r / Self::from_public(root_r2) + Self::one()) / Self::from_public(F::from(2u8)) - } - - fn rand_number_bitwise(rng: &mut R) -> (Vec, Self) { - let modulus_size = F::Params::MODULUS_BITS as usize; - - let mut modulus_bits = F::Params::MODULUS - .to_bits_le() - .iter() - .map(|b| Self::from_public(F::from(*b))) - .collect::>(); - - modulus_bits = modulus_bits[..modulus_size].to_vec(); - - let valid_bits = loop { - let bits = (0..modulus_size) - .map(|_| Self::bit_rand(rng)) - .collect::>(); - - if bits.clone().is_smaller_than_le(&modulus_bits).reveal().is_one() { - break bits; - } - }; - - // bits to field elemetn (little endian) - let num = valid_bits.iter().rev().fold(Self::zero(), |acc, x| { - acc * Self::from_public(F::from(2u8)) + x - }); - - (valid_bits, num) - } -} - -impl> BitwiseLessThan for Vec> { - type Output = MpcField; - - fn is_smaller_than_le(&self, other: &Self) -> Self::Output { - let modulus_size = F::Params::MODULUS_BITS as usize; - assert_eq!(self.len(), modulus_size); - assert_eq!(other.len(), modulus_size); - - // [c_i] = [a_i \oplus b_i] - let c = self - .iter() - .zip(other.iter()) - .map(|(a, b)| *a + b - MpcField::::from_public(F::from(2u8)) * a * b) - .collect::>(); - let rev_c = c.into_iter().rev().collect::>(); - - // d_i = OR_{j=i}^{modulus_size-1} c_j - let mut d = vec![rev_c[0]]; - for i in 0..modulus_size -1 { - d.push(vec![d[i],rev_c[i+1]].kary_or()); - } - d.reverse(); - - let e = (0..modulus_size) - .map(|i| { - if i == modulus_size - 1 { - d[modulus_size - 1] - } else { - d[i] - d[i + 1] - } - }) - .collect::>(); - - e.iter().zip(other.iter()).map(|(e, b)| *e * b).sum() - } -} - - impl> LessThan for MpcField { - type Output = Self; + type Output = MpcBooleanField; // check if shared value a is in the interval [0, modulus/2) fn is_smaller_or_equal_than_mod_minus_one_div_two(&self) -> Self::Output { // define double self as x @@ -312,11 +228,11 @@ impl> LessThan for MpcField>(); + let mut vec_c = c.into_repr().to_bits_le().iter().map(|&b| Self::Output::from(b)).collect::>(); vec_c.truncate(F::Params::MODULUS_BITS as usize); // Get least significant bits of c let lsb_c = *vec_c.first().unwrap(); @@ -327,44 +243,42 @@ impl> LessThan for MpcField Self::Output { // [z]=[other−self

p/2] // ([z]∧[x])∨([z]∧[y])∨(¬[z]∧[x]∧[y])=[z(x+y)+(1−2*z)xy]. - let z = (*other-self).is_smaller_or_equal_than_mod_minus_one_div_two(); - let x = self.is_smaller_or_equal_than_mod_minus_one_div_two(); - let y = Self::one() - other.is_smaller_or_equal_than_mod_minus_one_div_two(); - z*(x+y)+(Self::one()-Self::from_public(F::from(2u8))*z)*x*y + let z = (*other-self).is_smaller_or_equal_than_mod_minus_one_div_two().field(); + let x = self.is_smaller_or_equal_than_mod_minus_one_div_two().field(); + let y = Self::one() - other.is_smaller_or_equal_than_mod_minus_one_div_two().field(); + (z*(x+y)+(Self::one()-Self::from_public(F::from(2u8))*z)*x*y).into() } } -impl> LogicalOperations for Vec> { - type Output = MpcField; +impl> LogicalOperations for Vec> { + type Output = MpcBooleanField; // TODO: Implement kary_nand fn kary_and(&self) -> Self::Output { debug_assert!({ // each element is 0 or 1 self.iter() - .all(|x| x.reveal().is_zero() || x.reveal().is_one()) + .all(|x| x.field().reveal().is_zero() || x.field().reveal().is_one()) }); - self.iter().fold(MpcField::::one(), |acc, x| acc * x) + self.iter().fold(Self::Output::pub_true(), |acc, &x| acc & x) } fn kary_or(&self) -> Self::Output { let not_self = self .iter() - .map(|x| MpcField::::one() - x) + .map(|&x| !x) .collect::>(); - MpcField::::one() - not_self.kary_and() + !not_self.kary_and() } } @@ -643,7 +557,8 @@ impl> Zero for MpcField { } impl> EqualityZero for MpcField { - fn is_zero_shared(&self) -> Self { + type Output = MpcBooleanField; + fn is_zero_shared(&self) -> Self::Output { let res = match self { MpcField::Public(_) => { panic!("public is not expected here"); @@ -651,7 +566,7 @@ impl> EqualityZero for MpcFiel MpcField::Shared(_) => { let rng = &mut ark_std::test_rng(); - let (vec_r, r) = Self::rand_number_bitwise(rng); + let (vec_r, r) = Self::Output::rand_number_bitwise(rng); let c = (r + self).reveal(); @@ -670,12 +585,12 @@ impl> EqualityZero for MpcFiel .iter() .rev() .zip(vec_r.iter()) - .map(|(b, r)| match b { + .map(|(&b, &r)| match b { Some(b) => { - if *b { - *r + if b { + r } else { - Self::one() - r + !r } } None => panic!("bits decomposition failed"), @@ -690,8 +605,8 @@ impl> EqualityZero for MpcFiel } impl> BitDecomposition for MpcField { - type Output = Vec; - fn bit_decomposition(&self) -> Self::Output { + type BooleanField = MpcBooleanField; + fn bit_decomposition(&self) -> Vec { match self.is_shared() { true => { let timer = start_timer!(|| "Bit Decomposition"); @@ -700,7 +615,7 @@ impl> BitDecomposition for Mpc let l = F::Params::MODULUS_BITS as usize; // 1 - let (vec_r, r) = Self::rand_number_bitwise(rng); + let (vec_r, r) = Self::BooleanField::rand_number_bitwise(rng); // 2 let c = -r + self; @@ -719,10 +634,10 @@ impl> BitDecomposition for Mpc let p_minus_c_field = p_minus_c_bool .iter() - .map(|b| Self::from_public(F::from(*b))) + .map(|b| Self::BooleanField::from(*b)) .collect::>(); - let q = Self::one() - vec_r.is_smaller_than_le(&p_minus_c_field); + let q = !vec_r.is_smaller_than_le(&p_minus_c_field); // 4 let mut two_l = F::BigInt::from(1u64); @@ -735,20 +650,20 @@ impl> BitDecomposition for Mpc let vec_f = bigint_f .to_bits_le() .iter() - .map(|b| Self::from_public(F::from(*b))) + .map(|&b| Self::BooleanField::from(b)) .collect::>(); let vec_f_prime = revealed_c .into_repr() .to_bits_le() .iter() - .map(|b| Self::from_public(F::from(*b))) + .map(|&b| Self::BooleanField::from(b)) .collect::>(); let g_vec = vec_f .iter() .zip(vec_f_prime.iter()) - .map(|(f, f_prime)| (*f - f_prime) * q + f_prime) + .map(|(f, f_prime)| ((f.field() - f_prime.field()) * q.field() + f_prime.field()).into()) .collect::>(); // set length to l @@ -769,70 +684,6 @@ impl> BitDecomposition for Mpc } } -impl> BitAdd for Vec> { - type Output = Self; - - fn carries(&self, other: &Self) -> Self::Output { - match self.is_shared() { - true => { - assert_eq!(self.len(), other.len()); - let l = self.len(); // l is the bit length. - - let s_vec = self - .iter() - .zip(other.iter()) - .map(|(a, b)| *a * b) - .collect::>(); - - let p_vec = (0..l) - .map(|i| { - self[i] + other[i] - MpcField::::from_public(F::from(2u64)) * s_vec[i] - }) - .collect::>(); - - (0..l) - .scan(MpcField::::zero(), |is_s, i| { - *is_s = s_vec[i] + p_vec[i] * *is_s; - Some(*is_s) - }) - .collect() - } - false => { - panic!("public is not expected here"); - } - } - } - - /// This function is used to add two bit vectors of lenght l. - /// Returns a bit vector of length l+1 (bit length always increase by 1). - fn bit_add(self, other: &Self) -> Self::Output { - match self.is_shared() { - true => { - assert_eq!(self.len(), other.len()); - let l = self.len(); // l is the bit length. - let c_vec = self.carries(other); - - (0..=l) - .map(|i| { - if i == 0 { - self[0] + other[0] - - MpcField::::from_public(F::from(2u64)) * c_vec[0] - } else if i == l { - c_vec[l - 1] - } else { - self[i] + other[i] + c_vec[i - 1] - - MpcField::::from_public(F::from(2u64)) * c_vec[i] - } - }) - .collect() - } - false => { - panic!("public is not expected here"); - } - } - } -} - impl> Zeroize for MpcField { fn zeroize(&mut self) { *self = MpcField::Public(F::zero());