Skip to content

Commit

Permalink
WIP, NonZero (#198)
Browse files Browse the repository at this point in the history
  • Loading branch information
tlepoint authored Sep 7, 2023
1 parent 6234350 commit 00ea23b
Show file tree
Hide file tree
Showing 8 changed files with 50 additions and 78 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ fhe-traits = "0.1.0-beta.5"

## Minimum supported version / toolchain

Rust **1.64** or newer.
Rust **1.67** or newer.

## ⚠️ Security / Stability

Expand Down
10 changes: 5 additions & 5 deletions crates/fhe-math/src/rns/scaler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
use super::RnsContext;
use crypto_bigint::U192;
use fhe_util::{div_ceil, ilog2, U256};
use fhe_util::{div_ceil, U256};
use itertools::{izip, Itertools};
use ndarray::{ArrayView1, ArrayViewMut1};
use num_bigint::BigUint;
Expand Down Expand Up @@ -123,9 +123,9 @@ impl RnsScaler {
.iter()
.map(|qi| {
192 - 1
- ilog2(
((*qi as u128) * (from.moduli_u64.len() as u128)).next_power_of_two(),
)
- ((*qi as u128) * (from.moduli_u64.len() as u128))
.next_power_of_two()
.ilog2()
})
.min()
.unwrap(),
Expand Down Expand Up @@ -160,7 +160,7 @@ impl RnsScaler {
theta_omega_sign: theta_omega_sign.into_boxed_slice(),
theta_garner_lo: theta_garner_lo.into_boxed_slice(),
theta_garner_hi: theta_garner_hi.into_boxed_slice(),
theta_garner_shift,
theta_garner_shift: theta_garner_shift as usize,
}
}

Expand Down
42 changes: 8 additions & 34 deletions crates/fhe-util/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ pub use u256::U256;

use num_bigint_dig::{prime::probably_prime, BigUint, ModInverse};
use num_traits::{cast::ToPrimitive, PrimInt};
use std::{mem::size_of, panic::UnwindSafe};
use std::panic::UnwindSafe;

/// Define catch_unwind to silence the panic in unit tests.
pub fn catch_unwind<F, R>(f: F) -> std::thread::Result<R>
Expand Down Expand Up @@ -72,8 +72,7 @@ pub fn sample_vec_cbd<R: RngCore + CryptoRng>(

/// Transcodes a vector of u64 of `nbits`-bit numbers into a vector of bytes.
pub fn transcode_to_bytes(a: &[u64], nbits: usize) -> Vec<u8> {
assert!(nbits <= 64);
assert!(nbits > 0);
assert!(0 < nbits && nbits <= 64);

let mask = (u64::MAX >> (64 - nbits)) as u128;
let nbytes = div_ceil(a.len() * nbits, 8);
Expand Down Expand Up @@ -108,8 +107,7 @@ pub fn transcode_to_bytes(a: &[u64], nbits: usize) -> Vec<u8> {

/// Transcodes a vector of u8 into a vector of u64 of `nbits`-bit numbers.
pub fn transcode_from_bytes(b: &[u8], nbits: usize) -> Vec<u64> {
assert!(nbits <= 64);
assert!(nbits > 0);
assert!(0 < nbits && nbits <= 64);
let mask = (u64::MAX >> (64 - nbits)) as u128;

let nelements = div_ceil(b.len() * 8, nbits);
Expand Down Expand Up @@ -143,10 +141,9 @@ pub fn transcode_from_bytes(b: &[u8], nbits: usize) -> Vec<u64> {
/// Transcodes a vector of u64 of `input_nbits`-bit numbers into a vector of u64
/// of `output_nbits`-bit numbers.
pub fn transcode_bidirectional(a: &[u64], input_nbits: usize, output_nbits: usize) -> Vec<u64> {
assert!(input_nbits <= 64);
assert!(output_nbits <= 64);
assert!(input_nbits > 0);
assert!(output_nbits > 0);
assert!(0 < input_nbits && input_nbits <= 64);
assert!(0 < output_nbits && output_nbits <= 64);

let input_mask = (u64::MAX >> (64 - input_nbits)) as u128;
let output_mask = (u64::MAX >> (64 - output_nbits)) as u128;
let output_size = div_ceil(a.len() * input_nbits, output_nbits);
Expand Down Expand Up @@ -187,16 +184,6 @@ pub fn inverse(a: u64, p: u64) -> Option<u64> {
a.mod_inverse(p)?.to_u64()
}

/// Returns the number of bits b such that 2^b <= value
/// to simulate the `.ilog2()` function from <https://github.com/rust-lang/rust/issues/70887>.
/// Panics when `value` is 0.
pub fn ilog2<T: PrimInt>(value: T) -> usize {
assert!(value > T::zero());
// For this, we compute sizeof(T) - 1 - value.leading_zeros(). Indeed, when 2^b
// <= value < 2^(b+1), then value.leading_zeros() = sizeof(T) - (b + 1).
size_of::<T>() * 8 - 1 - value.leading_zeros() as usize
}

/// Returns the ceil of a divided by b, to simulate the
/// `.div_ceil()` function from <https://github.com/rust-lang/rust/issues/88581>.
/// Panics when `b` is 0.
Expand All @@ -220,7 +207,7 @@ mod tests {
use itertools::Itertools;
use rand::{thread_rng, RngCore};

use crate::{div_ceil, ilog2, variance};
use crate::{div_ceil, variance};

use super::{
inverse, is_prime, sample_vec_cbd, transcode_bidirectional, transcode_from_bytes,
Expand All @@ -244,19 +231,6 @@ mod tests {
assert!(!is_prime(4611686018326724607));
}

#[test]
fn ilog2_is_correct() {
assert_eq!(ilog2(1), 0);
assert_eq!(ilog2(2), 1);
assert_eq!(ilog2(3), 1);
assert_eq!(ilog2(4), 2);
for i in 2..=110 {
assert_eq!(ilog2(1u128 << i), i);
assert_eq!(ilog2((1u128 << i) + 1), i);
assert_eq!(ilog2((1u128 << (i + 1)) - 1), i);
}
}

#[test]
fn div_ceil_is_correct() {
for _ in 0..100 {
Expand Down Expand Up @@ -295,7 +269,7 @@ mod tests {

for size in 1..=100 {
let input = (0..size).map(|_| rng.next_u64()).collect_vec();
for input_nbits in 1..63 {
for input_nbits in 1usize..63 {
let masked_input = input
.iter()
.map(|i| (*i) & (u64::MAX >> (64 - input_nbits)))
Expand Down
6 changes: 3 additions & 3 deletions crates/fhe/benches/bfv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use fhe::bfv::{
use fhe_math::rns::{RnsContext, ScalingFactor};
use fhe_math::zq::primes::generate_prime;
use fhe_traits::{FheEncoder, FheEncrypter};
use fhe_util::{div_ceil, ilog2};
use fhe_util::div_ceil;
use itertools::Itertools;
use num_bigint::BigUint;
use rand::{rngs::OsRng, thread_rng};
Expand All @@ -29,7 +29,7 @@ pub fn bfv_benchmark(c: &mut Criterion) {
.unwrap()
.enable_column_rotation(1)
.unwrap()
.enable_expansion(ilog2(par.degree() as u64))
.enable_expansion(par.degree().ilog2() as usize)
.unwrap()
.build(&mut rng)
.unwrap(),
Expand Down Expand Up @@ -194,7 +194,7 @@ pub fn bfv_benchmark(c: &mut Criterion) {
},
);

for i in 1..=ilog2(par.degree() as u64) {
for i in 1..=par.degree().ilog2() {
if par.degree() > 2048 && i > 4 {
continue; // Skip slow benchmarks
}
Expand Down
14 changes: 7 additions & 7 deletions crates/fhe/examples/mulpir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use fhe::bfv;
use fhe_traits::{
DeserializeParametrized, FheDecoder, FheDecrypter, FheEncoder, FheEncrypter, Serialize,
};
use fhe_util::{ilog2, inverse, transcode_to_bytes};
use fhe_util::{inverse, transcode_to_bytes};
use indicatif::HumanBytes;
use rand::{rngs::OsRng, thread_rng, RngCore};
use std::{env, error::Error, process::exit};
Expand Down Expand Up @@ -53,7 +53,7 @@ fn main() -> Result<(), Box<dyn Error>> {
// Compute what is the maximum byte-length of an element to fit within one
// ciphertext. Each coefficient of the ciphertext polynomial can contain
// floor(log2(plaintext_modulus)) bits.
let max_element_size = (ilog2(plaintext_modulus) * degree) / 8;
let max_element_size = ((plaintext_modulus.ilog2() as usize) * degree) / 8;

// This executable is a command line tool which enables to specify different
// database and element sizes.
Expand Down Expand Up @@ -145,7 +145,7 @@ fn main() -> Result<(), Box<dyn Error>> {
// relinearization key.
let (sk, ek_expansion_serialized, rk_serialized) = timeit!("Client setup", {
let sk = bfv::SecretKey::random(&params, &mut OsRng);
let level = ilog2((dim1 + dim2).next_power_of_two() as u64);
let level = (dim1 + dim2).next_power_of_two().ilog2() as usize;
println!("level = {level}");
let ek_expansion = bfv::EvaluationKeyBuilder::new_leveled(&sk, 1, 0)?
.enable_expansion(level)?
Expand Down Expand Up @@ -185,11 +185,11 @@ fn main() -> Result<(), Box<dyn Error>> {
// to reduce the noise.
let index = (thread_rng().next_u64() as usize) % database_size;
let query = timeit!("Client query", {
let level = ilog2((dim1 + dim2).next_power_of_two() as u64);
let level = (dim1 + dim2).next_power_of_two().ilog2();
let query_index = index
/ number_elements_per_plaintext(
params.degree(),
ilog2(plaintext_modulus),
plaintext_modulus.ilog2() as usize,
elements_size,
);
let mut pt = vec![0u64; dim1 + dim2];
Expand Down Expand Up @@ -246,11 +246,11 @@ fn main() -> Result<(), Box<dyn Error>> {

let pt = sk.try_decrypt(&response)?;
let pt = Vec::<u64>::try_decode(&pt, bfv::Encoding::poly_at_level(2))?;
let plaintext = transcode_to_bytes(&pt, ilog2(plaintext_modulus));
let plaintext = transcode_to_bytes(&pt, plaintext_modulus.ilog2() as usize);
let offset = index
% number_elements_per_plaintext(
params.degree(),
ilog2(plaintext_modulus),
plaintext_modulus.ilog2() as usize,
elements_size,
);

Expand Down
28 changes: 14 additions & 14 deletions crates/fhe/examples/sealpir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use fhe_traits::{
DeserializeParametrized, FheDecoder, FheDecrypter, FheEncoder, FheEncoderVariableTime,
FheEncrypter, Serialize,
};
use fhe_util::{div_ceil, ilog2, inverse, transcode_bidirectional, transcode_to_bytes};
use fhe_util::{div_ceil, inverse, transcode_bidirectional, transcode_to_bytes};
use indicatif::HumanBytes;
use itertools::Itertools;
use rand::{rngs::OsRng, thread_rng, RngCore};
Expand Down Expand Up @@ -49,13 +49,13 @@ fn print_notice_and_exit(max_element_size: usize, error: Option<String>) {

fn main() -> Result<(), Box<dyn Error>> {
let degree = 4096usize;
let plaintext_modulus = 2056193;
let plaintext_modulus = 2056193u64;
let moduli_sizes = [36, 36, 37];

// Compute what is the maximum byte-length of an element to fit within one
// ciphertext. Each coefficient of the ciphertext polynomial can contain
// floor(log2(plaintext_modulus)) bits.
let max_element_size = (ilog2(plaintext_modulus) * degree) / 8;
let max_element_size = ((plaintext_modulus.ilog2() as usize) * degree) / 8;

// This executable is a command line tool which enables to specify different
// database and element sizes.
Expand Down Expand Up @@ -145,7 +145,7 @@ fn main() -> Result<(), Box<dyn Error>> {
// dim2) values, i.e. with expansion level ceil(log2(dim1 + dim2)).
let (sk, ek_expansion_serialized) = timeit!("Client setup", {
let sk = bfv::SecretKey::random(&params, &mut OsRng);
let level = ilog2((dim1 + dim2).next_power_of_two() as u64);
let level = (dim1 + dim2).next_power_of_two().ilog2() as usize;
println!("expansion_level = {level}");
let ek_expansion = bfv::EvaluationKeyBuilder::new_leveled(&sk, 1, 0)?
.enable_expansion(level)?
Expand Down Expand Up @@ -176,11 +176,11 @@ fn main() -> Result<(), Box<dyn Error>> {
// to reduce the noise.
let index = (thread_rng().next_u64() as usize) % database_size;
let query = timeit!("Client query", {
let level = ilog2((dim1 + dim2).next_power_of_two() as u64);
let level = (dim1 + dim2).next_power_of_two().ilog2();
let query_index = index
/ number_elements_per_plaintext(
params.degree(),
ilog2(plaintext_modulus),
plaintext_modulus.ilog2() as usize,
elements_size,
);
let mut pt = vec![0u64; dim1 + dim2];
Expand Down Expand Up @@ -229,17 +229,17 @@ fn main() -> Result<(), Box<dyn Error>> {
.map(|c| {
let mut pt_values = Vec::with_capacity(div_ceil(
2 * (params.degree() * (64 - params.moduli()[0].leading_zeros() as usize)),
ilog2(plaintext_modulus),
plaintext_modulus.ilog2() as usize,
));
pt_values.append(&mut transcode_bidirectional(
c.get(0).unwrap().coefficients().as_slice().unwrap(),
64 - params.moduli()[0].leading_zeros() as usize,
ilog2(plaintext_modulus),
plaintext_modulus.ilog2() as usize,
));
pt_values.append(&mut transcode_bidirectional(
c.get(1).unwrap().coefficients().as_slice().unwrap(),
64 - params.moduli()[0].leading_zeros() as usize,
ilog2(plaintext_modulus),
plaintext_modulus.ilog2() as usize,
));
unsafe {
Ok(bfv::PlaintextVec::try_encode_vt(
Expand Down Expand Up @@ -287,17 +287,17 @@ fn main() -> Result<(), Box<dyn Error>> {
.collect_vec();
let expect_ncoefficients = div_ceil(
params.degree() * (64 - params.moduli()[0].leading_zeros() as usize),
ilog2(plaintext_modulus),
plaintext_modulus.ilog2() as usize,
);
assert!(decrypted_vec.len() >= 2 * expect_ncoefficients);
let mut poly0 = transcode_bidirectional(
&decrypted_vec[..expect_ncoefficients],
ilog2(plaintext_modulus),
plaintext_modulus.ilog2() as usize,
64 - params.moduli()[0].leading_zeros() as usize,
);
let mut poly1 = transcode_bidirectional(
&decrypted_vec[expect_ncoefficients..2 * expect_ncoefficients],
ilog2(plaintext_modulus),
plaintext_modulus.ilog2() as usize,
64 - params.moduli()[0].leading_zeros() as usize,
);
assert!(poly0.len() >= params.degree());
Expand All @@ -316,11 +316,11 @@ fn main() -> Result<(), Box<dyn Error>> {

let pt = sk.try_decrypt(&ct).unwrap();
let pt = Vec::<u64>::try_decode(&pt, bfv::Encoding::poly_at_level(2))?;
let plaintext = transcode_to_bytes(&pt, ilog2(plaintext_modulus));
let plaintext = transcode_to_bytes(&pt, plaintext_modulus.ilog2() as usize);
let offset = index
% number_elements_per_plaintext(
params.degree(),
ilog2(plaintext_modulus),
plaintext_modulus.ilog2() as usize,
elements_size,
);

Expand Down
6 changes: 3 additions & 3 deletions crates/fhe/examples/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
use fhe::bfv;
use fhe_traits::FheEncoder;
use fhe_util::{ilog2, transcode_from_bytes};
use fhe_util::transcode_from_bytes;
use std::{cmp::min, fmt, sync::Arc, time::Duration};

/// Macros to time code and display a human-readable duration.
Expand Down Expand Up @@ -65,7 +65,7 @@ impl fmt::Display for DisplayDuration {
/// the encoding is truncated.
#[allow(dead_code)]
pub fn generate_database(database_size: usize, elements_size: usize) -> Vec<Vec<u8>> {
assert!(elements_size > 0 && database_size > 0);
assert!(database_size > 0 && elements_size > 0);
let mut database = vec![vec![0u8; elements_size]; database_size];
for (i, element) in database.iter_mut().enumerate() {
element[..min(4, elements_size)]
Expand All @@ -92,7 +92,7 @@ pub fn encode_database(
assert!(!database.is_empty());

let elements_size = database[0].len();
let plaintext_nbits = ilog2(par.plaintext());
let plaintext_nbits = par.plaintext().ilog2() as usize;
let number_elements_per_plaintext =
number_elements_per_plaintext(par.degree(), plaintext_nbits, elements_size);
let number_rows =
Expand Down
Loading

0 comments on commit 00ea23b

Please sign in to comment.