arnaucube
arnaucube/poulpyPublic Self-hosted repository
poulpy/poulpy-schemes/src/tfhe/bdd_arithmetic/eval.rs
poulpy-schemes/src/tfhe/bdd_arithmetic/eval.rsRaw
  1use itertools::Itertools;
  2use poulpy_core::{
  3    GLWEAdd, GLWECopy, GLWEExternalProduct, GLWESub, ScratchTakeCore,
  4    layouts::{
  5        GLWE, LWEInfos,
  6        prepared::{GGSWPrepared, GGSWPreparedToRef},
  7    },
  8};
  9use poulpy_hal::layouts::{Backend, DataMut, DataRef, Module, Scratch, ZnxZero};
 10
 11use crate::tfhe::bdd_arithmetic::UnsignedInteger;
 12
 13pub trait BitCircuitInfo {
 14    fn info(&self) -> (&[Node], &[usize], usize);
 15}
 16
 17pub trait GetBitCircuitInfo<T: UnsignedInteger> {
 18    fn input_size(&self) -> usize;
 19    fn output_size(&self) -> usize;
 20    fn get_circuit(&self, bit: usize) -> (&[Node], &[usize], usize);
 21}
 22
 23pub(crate) struct BitCircuit<const N: usize, const K: usize> {
 24    pub(crate) nodes: [Node; N],
 25    pub(crate) levels: [usize; K],
 26    pub(crate) max_inter_state: usize,
 27}
 28
 29pub struct Circuit<C: BitCircuitInfo, const N: usize>(pub [C; N]);
 30
 31pub trait ExecuteBDDCircuit<T: UnsignedInteger, BE: Backend> {
 32    fn execute_bdd_circuit<C, O>(
 33        &self,
 34        out: &mut [GLWE<O>],
 35        inputs: &[&dyn GGSWPreparedToRef<BE>],
 36        circuit: &C,
 37        scratch: &mut Scratch<BE>,
 38    ) where
 39        C: GetBitCircuitInfo<T>,
 40        O: DataMut;
 41}
 42
 43impl<T: UnsignedInteger, BE: Backend> ExecuteBDDCircuit<T, BE> for Module<BE>
 44where
 45    Self: Cmux<BE> + GLWECopy,
 46    Scratch<BE>: ScratchTakeCore<BE>,
 47{
 48    fn execute_bdd_circuit<C, O>(
 49        &self,
 50        out: &mut [GLWE<O>],
 51        inputs: &[&dyn GGSWPreparedToRef<BE>],
 52        circuit: &C,
 53        scratch: &mut Scratch<BE>,
 54    ) where
 55        C: GetBitCircuitInfo<T>,
 56        O: DataMut,
 57    {
 58        #[cfg(debug_assertions)]
 59        {
 60            assert_eq!(inputs.len(), circuit.input_size());
 61            assert!(out.len() >= circuit.output_size());
 62        }
 63
 64        for (i, out_i) in out.iter_mut().enumerate().take(circuit.output_size()) {
 65            let (nodes, levels, max_inter_state) = circuit.get_circuit(i);
 66
 67            let (mut level, scratch_1) = scratch.take_glwe_slice(max_inter_state * 2, out_i);
 68
 69            level.iter_mut().for_each(|ct| ct.data_mut().zero());
 70
 71            // TODO: implement API on GLWE
 72            level[1]
 73                .data_mut()
 74                .encode_coeff_i64(out_i.base2k().into(), 0, 2, 0, 1);
 75
 76            let mut level_ref = level.iter_mut().collect_vec();
 77            let (mut prev_level, mut next_level) = level_ref.split_at_mut(max_inter_state);
 78
 79            for i in 0..levels.len() - 1 {
 80                let start: usize = levels[i];
 81                let end: usize = levels[i + 1];
 82
 83                let nodes_lvl: &[Node] = &nodes[start..end];
 84
 85                for (j, node) in nodes_lvl.iter().enumerate() {
 86                    if node.low_index == node.high_index {
 87                        self.glwe_copy(next_level[j], prev_level[node.low_index]);
 88                    } else {
 89                        self.cmux(
 90                            next_level[j],
 91                            prev_level[node.high_index],
 92                            prev_level[node.low_index],
 93                            &inputs[node.input_index].to_ref(),
 94                            scratch_1,
 95                        );
 96                    }
 97                }
 98
 99                (prev_level, next_level) = (next_level, prev_level);
100            }
101
102            // handle last output
103            // there's always only 1 node at last level
104            let node: &Node = nodes.last().unwrap();
105            self.cmux(
106                out_i,
107                prev_level[node.high_index],
108                prev_level[node.low_index],
109                &inputs[node.input_index].to_ref(),
110                scratch_1,
111            );
112        }
113
114        for out_i in out.iter_mut().skip(circuit.output_size()) {
115            out_i.data_mut().zero();
116        }
117    }
118}
119
120impl<const N: usize, const K: usize> BitCircuit<N, K> {
121    pub(crate) const fn new(nodes: [Node; N], levels: [usize; K], max_inter_state: usize) -> Self {
122        Self {
123            nodes,
124            levels,
125            max_inter_state,
126        }
127    }
128}
129impl<const N: usize, const K: usize> BitCircuitInfo for BitCircuit<N, K> {
130    fn info(&self) -> (&[Node], &[usize], usize) {
131        (
132            self.nodes.as_ref(),
133            self.levels.as_ref(),
134            self.max_inter_state,
135        )
136    }
137}
138
139#[derive(Debug)]
140pub struct Node {
141    input_index: usize,
142    high_index: usize,
143    low_index: usize,
144}
145
146impl Node {
147    pub(crate) const fn new(input_index: usize, high_index: usize, low_index: usize) -> Self {
148        Self {
149            input_index,
150            high_index,
151            low_index,
152        }
153    }
154}
155
156pub trait Cmux<BE: Backend> {
157    fn cmux<O, T, F, S>(&self, out: &mut GLWE<O>, t: &GLWE<T>, f: &GLWE<F>, s: &GGSWPrepared<S, BE>, scratch: &mut Scratch<BE>)
158    where
159        O: DataMut,
160        T: DataRef,
161        F: DataRef,
162        S: DataRef;
163}
164
165impl<BE: Backend> Cmux<BE> for Module<BE>
166where
167    Module<BE>: GLWEExternalProduct<BE> + GLWESub + GLWEAdd,
168    Scratch<BE>: ScratchTakeCore<BE>,
169{
170    fn cmux<O, T, F, S>(&self, out: &mut GLWE<O>, t: &GLWE<T>, f: &GLWE<F>, s: &GGSWPrepared<S, BE>, scratch: &mut Scratch<BE>)
171    where
172        O: DataMut,
173        T: DataRef,
174        F: DataRef,
175        S: DataRef,
176    {
177        // let mut out: GLWECiphertext<&mut [u8]> = out.to_mut();
178        self.glwe_sub(out, t, f);
179        self.glwe_external_product_inplace(out, s, scratch);
180        self.glwe_add_inplace(out, f);
181    }
182}