From 422fcd005a91447acd8e4f158a9f688be7f942d2 Mon Sep 17 00:00:00 2001 From: Jay Logelin Date: Thu, 3 Oct 2024 21:56:58 -0300 Subject: [PATCH] refactor(compute): Clean up and separate operations module --- Cargo.toml | 2 + benchmark/benches/benchmarks.rs | 10 +- compute/src/lib.rs | 1 - compute/src/operations/bitwise.rs | 5 +- compute/src/u256.rs | 229 ------------------------------ compute/src/uint.rs | 5 +- 6 files changed, 11 insertions(+), 241 deletions(-) delete mode 100644 compute/src/u256.rs diff --git a/Cargo.toml b/Cargo.toml index d9aca9e..765ab5c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,4 +1,6 @@ [workspace] +resolver = "2" + members = [ "benchmark", "compute", diff --git a/benchmark/benches/benchmarks.rs b/benchmark/benches/benchmarks.rs index c7fcee0..62933e7 100644 --- a/benchmark/benches/benchmarks.rs +++ b/benchmark/benches/benchmarks.rs @@ -1,4 +1,4 @@ -use criterion::{black_box, criterion_group, criterion_main, Criterion}; +use criterion::{criterion_group, criterion_main, Criterion}; // Function to benchmark (example function) fn tfhe_encrypted_addition() -> Result<(), Box> { @@ -21,7 +21,7 @@ fn tfhe_encrypted_addition() -> Result<(), Box> { set_server_key(server_keys); // Clear equivalent computations: 12297829382473034410 + 1 - let mut encrypted_res_mul = &encrypted_a + &encrypted_b; + let encrypted_res_mul = &encrypted_a + &encrypted_b; let clear_res: u128 = encrypted_res_mul.decrypt(&client_key); assert_eq!(clear_res, clear_a + clear_b); @@ -31,7 +31,7 @@ fn tfhe_encrypted_addition() -> Result<(), Box> { // Another function to benchmark fn gateway_encrypted_addition() -> Result<(), Box> { - use compute::operations::Uint; + use compute::uint::Uint; let clear_a = 12297829382473034410u128; let clear_b = 424242424242u128; @@ -47,14 +47,14 @@ fn gateway_encrypted_addition() -> Result<(), Box> { // Benchmark 1: Benchmarking benchmark_gateway_encrypted_addition fn benchmark_gateway_encrypted_addition(c: &mut Criterion) { c.bench_function("gateway_encrypted_addition", |b| { - b.iter(|| gateway_encrypted_addition()) + b.iter(gateway_encrypted_addition) }); } // Benchmark 2: Benchmarking benchmark_tfhe_encrypted_addition fn benchmark_tfhe_encrypted_addition(c: &mut Criterion) { c.bench_function("tfhe_encrypted_addition", |b| { - b.iter(|| tfhe_encrypted_addition()) + b.iter(tfhe_encrypted_addition) }); } diff --git a/compute/src/lib.rs b/compute/src/lib.rs index 40c46e5..56f97b9 100644 --- a/compute/src/lib.rs +++ b/compute/src/lib.rs @@ -1,3 +1,2 @@ pub mod operations; -pub mod u256; pub mod uint; diff --git a/compute/src/operations/bitwise.rs b/compute/src/operations/bitwise.rs index 64e245b..9ab2e80 100644 --- a/compute/src/operations/bitwise.rs +++ b/compute/src/operations/bitwise.rs @@ -235,6 +235,7 @@ impl Not for &Uint { } // Implement Shift Left operation for Uint and &Uint +#[allow(clippy::suspicious_arithmetic_impl)] impl Shl for Uint { type Output = Self; @@ -445,14 +446,14 @@ mod tests { let a = Uint::<4>::new(vec![false, false, false, true]); // Binary 1000 let result = a << 1; // Perform left shift by 1 - assert_eq!(result.to_u8(), 0b0000 as u8); // Binary 0000 (Left shift result of 1000) + assert_eq!(result.to_u8(), 0b0000_u8); // Binary 0000 (Left shift result of 1000) // binary literal of 0000 let a = Uint::<4>::new(vec![false, false, false, true]); // Binary 1000 let result = a << 2; // Perform left shift by 2 - assert_eq!(result.to_u8(), 0b0000); // Binary 0000 (Left shift result of 1000) + assert_eq!(result.to_u8(), 0b0000_u8); // Binary 0000 (Left shift result of 1000) let a = Uint::<4>::new(vec![false, false, false, true]); // Binary 1000 diff --git a/compute/src/u256.rs b/compute/src/u256.rs deleted file mode 100644 index 70dc4f6..0000000 --- a/compute/src/u256.rs +++ /dev/null @@ -1,229 +0,0 @@ -use std::fmt; -use std::ops::{Add, Div, Mul, Rem, Sub}; - -// A struct representing a 256-bit unsigned integer -#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq)] -pub struct U256(pub [u64; 4]); - -impl U256 { - // Constructor to create a new U256 from a u64 array - pub fn new(value: [u64; 4]) -> Self { - U256(value) - } - - // Create a U256 from a single u64 value - pub fn from_u64(value: u64) -> Self { - U256([value, 0, 0, 0]) - } - - // Function to return the zero U256 value - pub fn zero() -> Self { - U256([0, 0, 0, 0]) - } - - // Function to return the one U256 value - pub fn one() -> Self { - U256([1, 0, 0, 0]) - } - - // Function to check if the U256 value is zero - pub fn is_zero(&self) -> bool { - self.0 == [0, 0, 0, 0] - } -} - -// Implementing the Add trait for U256 -impl Add for U256 { - type Output = U256; - - fn add(self, rhs: U256) -> U256 { - let mut carry = 0u64; - let mut result = [0u64; 4]; - for i in 0..4 { - let (sum, overflow1) = self.0[i].overflowing_add(rhs.0[i]); - let (sum, overflow2) = sum.overflowing_add(carry); - result[i] = sum; - carry = (overflow1 as u64) + (overflow2 as u64); - } - U256(result) - } -} - -// Implementing the Sub trait for U256 -impl Sub for U256 { - type Output = U256; - - fn sub(self, rhs: U256) -> U256 { - let mut borrow = 0u64; - let mut result = [0u64; 4]; - for i in 0..4 { - let (diff, overflow1) = self.0[i].overflowing_sub(rhs.0[i]); - let (diff, overflow2) = diff.overflowing_sub(borrow); - result[i] = diff; - borrow = (overflow1 as u64) + (overflow2 as u64); - } - U256(result) - } -} - -// Implementing the Mul trait for U256 -impl Mul for U256 { - type Output = U256; - - fn mul(self, rhs: U256) -> U256 { - let mut result = U256::zero(); - for i in 0..4 { - let mut carry = 0u64; - for j in 0..(4 - i) { - let (low, high) = mul_u64(self.0[i], rhs.0[j]); - let (sum_low, carry1) = result.0[i + j].overflowing_add(low); - let (sum_low, carry2) = sum_low.overflowing_add(carry); - let (sum_high, carry3) = - result.0[i + j + 1].overflowing_add(high + (carry1 as u64) + (carry2 as u64)); - - result.0[i + j] = sum_low; - result.0[i + j + 1] = sum_high; - carry = carry3 as u64; - } - } - result - } -} - -// A helper function to multiply two u64 values, returning the low and high parts of the result -fn mul_u64(lhs: u64, rhs: u64) -> (u64, u64) { - let (low, high) = ((lhs as u128) * (rhs as u128)).overflowing_shr(64); - (low as u64, high as u64) -} - -// Implementing the Div trait for U256 (naive long division) -impl Div for U256 { - type Output = U256; - - fn div(self, rhs: U256) -> U256 { - if rhs.is_zero() { - panic!("Division by zero"); - } - - let mut quotient = U256::zero(); - let mut remainder = U256::zero(); - - for i in (0..256).rev() { - remainder = remainder << 1; - remainder.0[0] |= (self >> i).0[0] & 1; - - if remainder >= rhs { - remainder = remainder - rhs; - quotient.0[0] |= 1 << i; - } - } - - quotient - } -} - -// Implementing the Rem trait for U256 -impl Rem for U256 { - type Output = U256; - - fn rem(self, rhs: U256) -> U256 { - let mut remainder = U256::zero(); - - for i in (0..256).rev() { - remainder = remainder << 1; - remainder.0[0] |= (self >> i).0[0] & 1; - - if remainder >= rhs { - remainder = remainder - rhs; - } - } - - remainder - } -} - -// Implementing the Display trait for U256 for pretty printing -impl fmt::Display for U256 { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "0x")?; - for &val in self.0.iter().rev() { - write!(f, "{:016x}", val)?; - } - Ok(()) - } -} - -// Implementing shift left and right -impl std::ops::Shl for U256 { - type Output = U256; - - fn shl(self, shift: u32) -> U256 { - let mut result = [0u64; 4]; - let word_shift = (shift / 64) as usize; - let bit_shift = shift % 64; - - for i in (0..4).rev() { - if i + word_shift < 4 { - result[i + word_shift] = self.0[i] << bit_shift; - if i + word_shift + 1 < 4 && bit_shift != 0 { - result[i + word_shift + 1] |= self.0[i] >> (64 - bit_shift); - } - } - } - U256(result) - } -} - -impl std::ops::Shr for U256 { - type Output = U256; - - fn shr(self, shift: u32) -> U256 { - let mut result = [0u64; 4]; - let word_shift = (shift / 64) as usize; - let bit_shift = shift % 64; - - for i in 0..4 { - if i >= word_shift { - result[i - word_shift] = self.0[i] >> bit_shift; - if i >= word_shift + 1 && bit_shift != 0 { - result[i - word_shift - 1] |= self.0[i] << (64 - bit_shift); - } - } - } - U256(result) - } -} - -// implement BitOrAssign for U256 - -impl std::ops::BitOrAssign for U256 { - fn bitor_assign(&mut self, rhs: U256) { - for i in 0..4 { - self.0[i] |= rhs.0[i]; - } - } -} - -// core::ops::bit::BitAnd -impl std::ops::BitAnd for U256 { - type Output = U256; - - fn bitand(self, rhs: U256) -> U256 { - let mut result = [0u64; 4]; - for i in 0..4 { - result[i] = self.0[i] & rhs.0[i]; - } - U256(result) - } -} - -// Example usage of U256 -fn main() { - let a = U256::from_u64(123456789); - let b = U256::from_u64(987654321); - let c = a + b; - println!("a + b = {}", c); - - let d = a * b; - println!("a * b = {}", d); -} diff --git a/compute/src/uint.rs b/compute/src/uint.rs index 94cb238..b1be6a5 100644 --- a/compute/src/uint.rs +++ b/compute/src/uint.rs @@ -1,11 +1,8 @@ -use crate::u256::U256; use rand_chacha::rand_core::SeedableRng; use rand_chacha::ChaCha20Rng; use std::marker::PhantomData; -use std::ops::{BitOr, BitXor, Not, Shl, Shr}; use tandem::states::{Contributor, Evaluator}; -use tandem::GateIndex; -use tandem::{Circuit, Error, Gate}; +use tandem::{Circuit, Error}; // Define a new type Uint #[derive(Debug, Clone)]