Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(hlapi): add Array types #1089

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 0 additions & 42 deletions tfhe/src/high_level_api/array.rs

This file was deleted.

39 changes: 39 additions & 0 deletions tfhe/src/high_level_api/array/clear_ops.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
use crate::high_level_api::array::traits::{
ArrayBackend, BackendDataContainer, ClearBitwiseArrayBackend, HasClear,
};
use crate::high_level_api::array::FheArrayBase;
use crate::FheId;
use std::ops::BitAnd;

impl<'a, C, Id> BitAnd<&'a [<Self as HasClear>::Clear]> for FheArrayBase<C, Id>
where
Id: FheId,
Self: HasClear,
C: BackendDataContainer,
C::Backend: ClearBitwiseArrayBackend<<Self as HasClear>::Clear>,
{
type Output = FheArrayBase<<C::Backend as ArrayBackend>::Owned, Id>;

fn bitand(self, rhs: &'a [<Self as HasClear>::Clear]) -> Self::Output {
let lhs_slice = self.elems.as_slice();
let inner = C::Backend::bitand_slice(lhs_slice, rhs);
FheArrayBase::new(inner)
}
}

impl<'a, 'b, C, Id> BitAnd<&'a [<FheArrayBase<C, Id> as HasClear>::Clear]>
for &'b FheArrayBase<C, Id>
where
Id: FheId,
FheArrayBase<C, Id>: HasClear,
C: BackendDataContainer,
C::Backend: ClearBitwiseArrayBackend<<FheArrayBase<C, Id> as HasClear>::Clear>,
{
type Output = FheArrayBase<<C::Backend as ArrayBackend>::Owned, Id>;

fn bitand(self, rhs: &'a [<FheArrayBase<C, Id> as HasClear>::Clear]) -> Self::Output {
let lhs_slice = self.elems.as_slice();
let inner = C::Backend::bitand_slice(lhs_slice, rhs);
FheArrayBase::new(inner)
}
}
177 changes: 177 additions & 0 deletions tfhe/src/high_level_api/array/cpu_boolean_backend.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
//! This module contains the implementation of the FheBool array backend
//! where the values and computations are always done on CPU
use super::helpers::{create_sub_mut_slice_with_bound, create_sub_slice_with_bound};
use super::traits::{BitwiseArrayBackend, ClearBitwiseArrayBackend};
use crate::high_level_api::array::{ArrayBackend, BackendDataContainer, BackendDataContainerMut};
use crate::high_level_api::global_state;
use crate::integer::BooleanBlock;
use crate::prelude::{FheDecrypt, FheTryEncrypt};
use crate::{ClientKey, FheId};
use rayon::prelude::*;
use std::ops::RangeBounds;

#[derive(Default, Copy, Clone)]
pub struct FheBoolId;

impl FheId for FheBoolId {}

pub struct CpuFheBoolArrayBackend;

pub type CpuFheBoolArray = super::FheBackendArray<CpuFheBoolArrayBackend, FheBoolId>;
pub type CpuFheBoolSlice<'a> = super::FheBackendArraySlice<'a, CpuFheBoolArrayBackend, FheBoolId>;
pub type CpuFheBoolSliceMut<'a> =
super::FheBackendArraySliceMut<'a, CpuFheBoolArrayBackend, FheBoolId>;

impl ArrayBackend for CpuFheBoolArrayBackend {
type Slice<'a> = &'a [BooleanBlock] where Self: 'a;
type SliceMut<'a> = &'a mut [BooleanBlock] where Self: 'a;
type Owned = Vec<BooleanBlock>;
}

impl<'a> BackendDataContainer for &'a [BooleanBlock] {
type Backend = CpuFheBoolArrayBackend;

fn as_sub_slice(
&self,
range: impl RangeBounds<usize>,
) -> <Self::Backend as ArrayBackend>::Slice<'_> {
create_sub_slice_with_bound(*self, range)
}

fn into_owned(self) -> <Self::Backend as ArrayBackend>::Owned {
self.to_vec()
}
}

impl<'a> BackendDataContainer for &'a mut [BooleanBlock] {
type Backend = CpuFheBoolArrayBackend;
fn as_sub_slice(
&self,
range: impl RangeBounds<usize>,
) -> <Self::Backend as ArrayBackend>::Slice<'_> {
create_sub_slice_with_bound(*self, range)
}

fn into_owned(self) -> <Self::Backend as ArrayBackend>::Owned {
self.to_vec()
}
}

impl<'a> BackendDataContainerMut for &'a mut [BooleanBlock] {
fn as_sub_slice_mut(
&mut self,
range: impl RangeBounds<usize>,
) -> <Self::Backend as ArrayBackend>::SliceMut<'_> {
create_sub_mut_slice_with_bound(*self, range)
}
}

impl BackendDataContainer for Vec<BooleanBlock> {
type Backend = CpuFheBoolArrayBackend;

fn as_sub_slice(
&self,
range: impl RangeBounds<usize>,
) -> <Self::Backend as ArrayBackend>::Slice<'_> {
create_sub_slice_with_bound(self, range)
}

fn into_owned(self) -> <Self::Backend as ArrayBackend>::Owned {
self
}
}

impl BackendDataContainerMut for Vec<BooleanBlock> {
fn as_sub_slice_mut(
&mut self,
range: impl RangeBounds<usize>,
) -> <Self::Backend as ArrayBackend>::SliceMut<'_> {
create_sub_mut_slice_with_bound(self.as_mut_slice(), range)
}
}

impl BitwiseArrayBackend for CpuFheBoolArrayBackend {
fn bitand<'a>(lhs: Self::Slice<'a>, rhs: Self::Slice<'a>) -> Self::Owned {
global_state::with_cpu_internal_keys(|cpu_key| {
lhs.par_iter()
.zip(rhs.par_iter())
.map(|(lhs, rhs)| cpu_key.pbs_key().boolean_bitand(lhs, rhs))
.collect()
})
}

fn bitor<'a>(lhs: Self::Slice<'a>, rhs: Self::Slice<'a>) -> Self::Owned {
global_state::with_cpu_internal_keys(|cpu_key| {
lhs.par_iter()
.zip(rhs.par_iter())
.map(|(lhs, rhs)| cpu_key.pbs_key().boolean_bitor(lhs, rhs))
.collect()
})
}

fn bitxor<'a>(lhs: Self::Slice<'a>, rhs: Self::Slice<'a>) -> Self::Owned {
global_state::with_cpu_internal_keys(|cpu_key| {
lhs.par_iter()
.zip(rhs.par_iter())
.map(|(lhs, rhs)| cpu_key.pbs_key().boolean_bitxor(lhs, rhs))
.collect()
})
}

fn bitnot(lhs: Self::Slice<'_>) -> Self::Owned {
global_state::with_cpu_internal_keys(|cpu_key| {
lhs.par_iter()
.map(|lhs| cpu_key.pbs_key().boolean_bitnot(lhs))
.collect()
})
}
}

impl ClearBitwiseArrayBackend<bool> for CpuFheBoolArrayBackend {
fn bitand_slice(lhs: Self::Slice<'_>, rhs: &[bool]) -> Self::Owned {
global_state::with_cpu_internal_keys(|cpu_key| {
lhs.par_iter()
.zip(rhs.par_iter().copied())
.map(|(lhs, rhs)| {
BooleanBlock::new_unchecked(
cpu_key.pbs_key().key.scalar_bitand(&lhs.0, rhs as u8),
)
})
.collect()
})
}
}

impl FheTryEncrypt<&[bool], ClientKey> for CpuFheBoolArray {
type Error = crate::Error;

fn try_encrypt(values: &[bool], cks: &ClientKey) -> Result<Self, Self::Error> {
let encrypted = values
.iter()
.copied()
.map(|value| cks.key.key.encrypt_bool(value))
.collect::<Vec<_>>();
Ok(Self::new(encrypted))
}
}

impl<'a> FheDecrypt<Vec<bool>> for CpuFheBoolSlice<'a> {
fn decrypt(&self, key: &ClientKey) -> Vec<bool> {
self.elems
.iter()
.map(|encrypted_value| key.key.key.decrypt_bool(encrypted_value))
.collect()
}
}

impl<'a> FheDecrypt<Vec<bool>> for CpuFheBoolSliceMut<'a> {
fn decrypt(&self, key: &ClientKey) -> Vec<bool> {
self.as_slice().decrypt(key)
}
}

impl FheDecrypt<Vec<bool>> for CpuFheBoolArray {
fn decrypt(&self, key: &ClientKey) -> Vec<bool> {
self.as_slice().decrypt(key)
}
}
Loading
Loading