Skip to content

Commit

Permalink
Implementation of bitwise operations between BigInteger (#713)
Browse files Browse the repository at this point in the history
Co-authored-by: Michele Orrù <michele.orru@berkeley.edu>
  • Loading branch information
hdvanegasm and mmaker authored Dec 14, 2023
1 parent ee0a407 commit b7b988f
Show file tree
Hide file tree
Showing 3 changed files with 125 additions and 4 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

- [\#689](https://github.com/arkworks-rs/algebra/pull/689) (`ark-serialize`) Add `CanonicalSerialize` and `CanonicalDeserialize` impls for `VecDeque` and `LinkedList`.
- [\#693](https://github.com/arkworks-rs/algebra/pull/693) (`ark-serialize`) Add `serialize_to_vec!` convenience macro.
- [\#713](https://github.com/arkworks-rs/algebra/pull/713) (`ark-ff`) Add support for bitwise operations AND, OR, and XOR between `BigInteger`.

### Breaking changes

Expand Down
78 changes: 75 additions & 3 deletions ff/src/biginteger/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use core::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Not};

use crate::{
bits::{BitIteratorBE, BitIteratorLE},
const_for, UniformRand,
Expand All @@ -8,6 +10,7 @@ use ark_serialize::{
CanonicalDeserialize, CanonicalSerialize, Compress, SerializationError, Valid, Validate,
};
use ark_std::{
borrow::Borrow,
convert::TryFrom,
fmt::{Debug, Display, UpperHex},
io::{Read, Write},
Expand Down Expand Up @@ -681,6 +684,63 @@ impl<const N: usize> From<BigInt<N>> for BigUint {
}
}

impl<B: Borrow<Self>, const N: usize> BitXorAssign<B> for BigInt<N> {
fn bitxor_assign(&mut self, rhs: B) {
(0..N).for_each(|i| self.0[i] ^= rhs.borrow().0[i])
}
}

impl<B: Borrow<Self>, const N: usize> BitXor<B> for BigInt<N> {
type Output = Self;

fn bitxor(mut self, rhs: B) -> Self::Output {
self ^= rhs;
self
}
}

impl<B: Borrow<Self>, const N: usize> BitAndAssign<B> for BigInt<N> {
fn bitand_assign(&mut self, rhs: B) {
(0..N).for_each(|i| self.0[i] &= rhs.borrow().0[i])
}
}

impl<B: Borrow<Self>, const N: usize> BitAnd<B> for BigInt<N> {
type Output = Self;

fn bitand(mut self, rhs: B) -> Self::Output {
self &= rhs;
self
}
}

impl<B: Borrow<Self>, const N: usize> BitOrAssign<B> for BigInt<N> {
fn bitor_assign(&mut self, rhs: B) {
(0..N).for_each(|i| self.0[i] |= rhs.borrow().0[i])
}
}

impl<B: Borrow<Self>, const N: usize> BitOr<B> for BigInt<N> {
type Output = Self;

fn bitor(mut self, rhs: B) -> Self::Output {
self |= rhs;
self
}
}

impl<const N: usize> Not for BigInt<N> {
type Output = Self;

fn not(self) -> Self::Output {
let mut result = Self::zero();
for i in 0..N {
result.0[i] = !self.0[i];
}
result
}
}

/// Compute the signed modulo operation on a u64 representation, returning the result.
/// If n % modulus > modulus / 2, return modulus - n
/// # Example
Expand Down Expand Up @@ -737,6 +797,18 @@ pub trait BigInteger:
+ From<u8>
+ TryFrom<BigUint, Error = ()>
+ Into<BigUint>
+ BitXorAssign<Self>
+ for<'a> BitXorAssign<&'a Self>
+ BitXor<Self>
+ for<'a> BitXor<&'a Self, Output = Self>
+ BitAndAssign<Self>
+ for<'a> BitAndAssign<&'a Self>
+ BitAnd<Self>
+ for<'a> BitAnd<&'a Self, Output = Self>
+ BitOrAssign<Self>
+ for<'a> BitOrAssign<&'a Self>
+ BitOr<Self>
+ for<'a> BitOr<&'a Self, Output = Self>
{
/// Number of 64-bit limbs representing `Self`.
const NUM_LIMBS: usize;
Expand Down Expand Up @@ -949,7 +1021,7 @@ pub trait BigInteger:
/// arr[63] = true;
/// let mut one = B::from(1u64);
/// assert_eq!(B::from_bits_be(&arr), one);
/// ```
/// ```
fn from_bits_be(bits: &[bool]) -> Self;

/// Returns the big integer representation of a given little endian boolean
Expand All @@ -963,7 +1035,7 @@ pub trait BigInteger:
/// arr[0] = true;
/// let mut one = B::from(1u64);
/// assert_eq!(B::from_bits_le(&arr), one);
/// ```
/// ```
fn from_bits_le(bits: &[bool]) -> Self;

/// Returns the bit representation in a big endian boolean array,
Expand All @@ -978,7 +1050,7 @@ pub trait BigInteger:
/// let mut vec = vec![false; 64];
/// vec[63] = true;
/// assert_eq!(arr, vec);
/// ```
/// ```
fn to_bits_be(&self) -> Vec<bool> {
BitIteratorBE::new(self).collect::<Vec<_>>()
}
Expand Down
50 changes: 49 additions & 1 deletion ff/src/biginteger/tests.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::{biginteger::BigInteger, UniformRand};
use crate::{biginteger::BigInteger, BigInt, UniformRand};
use ark_std::rand::Rng;
use num_bigint::BigUint;

// Test elementary math operations for BigInteger.
Expand Down Expand Up @@ -51,6 +52,52 @@ fn biginteger_arithmetic_test<B: BigInteger>(a: B, b: B, zero: B) {
assert_eq!(a_mul2, a_plus_a);
}

// Test for BigInt's bitwise operations
fn biginteger_bitwise_ops_test<B: BigInteger>() {
let mut rng = ark_std::test_rng();

// Test XOR
// a xor a = 0
let a: BigInt<4> = UniformRand::rand(&mut rng);
assert_eq!(a ^ &a, BigInt::from(0_u64));

// Testing a xor b xor b
let a: BigInt<4> = UniformRand::rand(&mut rng);
let b: BigInt<4> = UniformRand::rand(&mut rng);
let xor_ab = a ^ b;
assert_eq!(xor_ab ^ b, a);

// Test OR
// a or a = a
let a = rng.gen::<BigInt<4>>();
assert_eq!(a | &a, a);

// Testing a or b or b
let a = rng.gen::<BigInt<4>>();
let b = rng.gen::<BigInt<4>>();
let or_ab = a | b;
assert_eq!(or_ab | &b, a | b);

// Test AND
// a and a = a
let a = rng.gen::<BigInt<4>>();
assert_eq!(a & (&a), a);

// Testing a and a and b.
let a = rng.gen::<BigInt<4>>();
let b = rng.gen::<BigInt<4>>();
let b_clone = b.clone();
let and_ab = a & b;
assert_eq!(and_ab & b_clone, a & b);

// Testing De Morgan's law
let a = rng.gen::<BigInt<4>>();
let b = rng.gen::<BigInt<4>>();
let de_morgan_lhs = !(a | b);
let de_morgan_rhs = (!a) & (!b);
assert_eq!(de_morgan_lhs, de_morgan_rhs);
}

// Test correctness of BigInteger's bit values
fn biginteger_bits_test<B: BigInteger>() {
let mut one = B::from(1u64);
Expand Down Expand Up @@ -93,6 +140,7 @@ fn test_biginteger<B: BigInteger>(zero: B) {
biginteger_arithmetic_test(a, b, zero);
biginteger_bits_test::<B>();
biginteger_conversion_test::<B>();
biginteger_bitwise_ops_test::<B>()
}

#[test]
Expand Down

0 comments on commit b7b988f

Please sign in to comment.