Skip to content

Commit

Permalink
Merge pull request #37 from Yoii-Inc/feat/bit_decomposition
Browse files Browse the repository at this point in the history
Feat/bit decomposition
  • Loading branch information
taskooh authored Mar 26, 2024
2 parents 89a0380 + a0a53da commit 3c9e7da
Show file tree
Hide file tree
Showing 3 changed files with 240 additions and 4 deletions.
84 changes: 82 additions & 2 deletions mpc-algebra/examples/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ use ark_ff::{One, Zero};
use ark_poly::reveal;
use log::debug;
use mpc_algebra::{
AdditiveFieldShare, BitwiseLessThan, EqualityZero, LogicalOperations, MpcField, Reveal,
UniformBitRand,
AdditiveFieldShare, BitAdd, BitDecomposition, BitwiseLessThan, EqualityZero, LogicalOperations,
MpcField, Reveal, UniformBitRand,
};
use mpc_net::{MpcMultiNet as Net, MpcNet};

Expand Down Expand Up @@ -227,6 +227,79 @@ 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 c = a.carries(&b);

// expected carries: 1100
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 c = a.carries(&b);

// expected carries: 000010
assert_eq!(
c.reveal(),
vec![
F::zero(),
F::one(),
F::zero(),
F::zero(),
F::zero(),
F::zero()
]
);
}

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 c_vec = rand_a.bit_add(&rand_b);

let c = c_vec
.reveal()
.iter()
.rev()
.fold(F::zero(), |acc, x| acc * F::from(2u64) + x);

assert_eq!(c, (a + b).reveal());
}

fn test_bit_decomposition() {
let rng = &mut thread_rng();

let random = MF::rand(rng);

let bit = random.bit_decomposition();

let res = bit
.reveal()
.iter()
.rev()
.fold(F::zero(), |acc, x| acc * F::from(2u64) + x);

assert_eq!(res, random.reveal());
}

fn main() {
env_logger::builder().format_timestamp(None).init();
debug!("Start");
Expand Down Expand Up @@ -258,4 +331,11 @@ fn main() {
println!("Test or passed");
test_equality_zero();
println!("Test equality_zero passed");

test_carries();
println!("Test carries passed");
test_bit_add();
println!("Test bit_add passed");
test_bit_decomposition();
println!("Test bit_decomposition passed");
}
14 changes: 14 additions & 0 deletions mpc-algebra/src/mpc_primitives.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,17 @@ pub trait LogicalOperations {
pub trait EqualityZero {
fn is_zero_shared(&self) -> Self;
}

pub trait BitDecomposition {
type Output;

fn bit_decomposition(&self) -> Self::Output;
}

pub trait BitAdd {
type Output;

fn carries(&self, other: &Self) -> Self::Output;

fn bit_add(self, other: &Self) -> Self::Output;
}
146 changes: 144 additions & 2 deletions mpc-algebra/src/wire/field.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use zeroize::Zeroize;

use log::debug;

use ark_ff::{poly_stub, prelude::*, BitIteratorBE, FftField};
use ark_ff::{poly_stub, prelude::*, BigInteger256, BitIteratorBE, FftField};
use ark_ff::{FromBytes, ToBytes};
use ark_serialize::{
CanonicalDeserialize, CanonicalDeserializeWithFlags, CanonicalSerialize,
Expand All @@ -22,7 +22,7 @@ use ark_serialize::{

// use crate::channel::MpcSerNet;
use crate::share::field::FieldShare;
use crate::{BeaverSource, BitwiseLessThan, LogicalOperations, Reveal};
use crate::{BeaverSource, BitAdd, BitDecomposition, BitwiseLessThan, LogicalOperations, Reveal};
use crate::{EqualityZero, UniformBitRand};
use mpc_net::{MpcMultiNet as Net, MpcNet};

Expand Down Expand Up @@ -645,6 +645,148 @@ impl<F: PrimeField + SquareRootField, S: FieldShare<F>> EqualityZero for MpcFiel
}
}

impl<S: FieldShare<ark_bls12_377::Fr>> BitDecomposition for MpcField<ark_bls12_377::Fr, S> {
type Output = Vec<Self>;
fn bit_decomposition(&self) -> Self::Output {
match self.is_shared() {
true => {
let rng = &mut ark_std::test_rng();

let l = ark_bls12_377::FrParameters::MODULUS_BITS as usize;

// 1
let (vec_r, r) = Self::rand_number_bitwise(rng);

// 2
let c = -r + self;
let revealed_c = c.reveal();
if revealed_c.is_zero() {
return vec_r;
}

// 3
let p_minus_c_bool = (-revealed_c).into_repr().to_bits_le();

// set length to l
let p_minus_c_bool = p_minus_c_bool[..l].to_vec();

assert_eq!(p_minus_c_bool.len(), l);

let p_minus_c_field = p_minus_c_bool
.iter()
.map(|b| Self::from_public(ark_bls12_377::Fr::from(*b)))
.collect::<Vec<_>>();

let q = Self::one() - vec_r.bitwise_lt(&p_minus_c_field);

// 4
let mut two_l = BigInteger256::from(1u64);
two_l.muln(l as u32);

let mut bigint_f = two_l;
bigint_f.add_nocarry(&revealed_c.into_repr());
bigint_f.sub_noborrow(&ark_bls12_377::FrParameters::MODULUS);

let vec_f = bigint_f
.to_bits_le()
.iter()
.map(|b| Self::from_public(ark_bls12_377::Fr::from(*b)))
.collect::<Vec<_>>();

let vec_f_prime = revealed_c
.into_repr()
.to_bits_le()
.iter()
.map(|b| Self::from_public(ark_bls12_377::Fr::from(*b)))
.collect::<Vec<_>>();

let g_vec = vec_f
.iter()
.zip(vec_f_prime.iter())
.map(|(f, f_prime)| (*f - f_prime) * q + f_prime)
.collect::<Vec<_>>();

// set length to l
let g_vec = g_vec[..l].to_vec();

// 5
let h = vec_r.bit_add(&g_vec);

// 6
assert!(h.len() == l + 1);
h[..l].to_vec() // remove the last element
}
false => {
panic!("public is not expected here");
}
}
}
}

impl<F: Field, S: FieldShare<F>> BitAdd for Vec<MpcField<F, S>> {
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::<Vec<_>>();

let p_vec = (0..l)
.map(|i| {
self[i] + other[i] - MpcField::<F, S>::from_public(F::from(2u64)) * s_vec[i]
})
.collect::<Vec<_>>();

(0..l)
.scan(MpcField::<F, S>::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::<F, S>::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::<F, S>::from_public(F::from(2u64)) * c_vec[i]
}
})
.collect()
}
false => {
panic!("public is not expected here");
}
}
}
}

impl<F: Field, S: FieldShare<F>> Zeroize for MpcField<F, S> {
fn zeroize(&mut self) {
*self = MpcField::Public(F::zero());
Expand Down

0 comments on commit 3c9e7da

Please sign in to comment.