arnaucube
arnaucube/poulpyPublic Self-hosted repository
poulpy/poulpy-backend/src/hal/layouts/module.rs
poulpy-backend/src/hal/layouts/module.rsRaw
 1use std::{marker::PhantomData, ptr::NonNull};
 2
 3use crate::GALOISGENERATOR;
 4
 5#[allow(clippy::missing_safety_doc)]
 6pub trait Backend: Sized {
 7    type Handle: 'static;
 8    unsafe fn destroy(handle: NonNull<Self::Handle>);
 9}
10
11pub struct Module<B: Backend> {
12    ptr: NonNull<B::Handle>,
13    n: u64,
14    _marker: PhantomData<B>,
15}
16
17impl<B: Backend> Module<B> {
18    /// Construct from a raw pointer managed elsewhere.
19    /// SAFETY: `ptr` must be non-null and remain valid for the lifetime of this Module.
20    #[inline]
21    #[allow(clippy::missing_safety_doc)]
22    pub unsafe fn from_raw_parts(ptr: *mut B::Handle, n: u64) -> Self {
23        Self {
24            ptr: NonNull::new(ptr).expect("null module ptr"),
25            n,
26            _marker: PhantomData,
27        }
28    }
29
30    #[allow(clippy::missing_safety_doc)]
31    #[inline]
32    pub unsafe fn ptr(&self) -> *mut <B as Backend>::Handle {
33        self.ptr.as_ptr()
34    }
35
36    #[inline]
37    pub fn n(&self) -> usize {
38        self.n as usize
39    }
40    #[inline]
41    pub fn as_mut_ptr(&self) -> *mut B::Handle {
42        self.ptr.as_ptr()
43    }
44
45    #[inline]
46    pub fn log_n(&self) -> usize {
47        (usize::BITS - (self.n() - 1).leading_zeros()) as _
48    }
49
50    #[inline]
51    pub fn cyclotomic_order(&self) -> u64 {
52        (self.n() << 1) as _
53    }
54
55    // Returns GALOISGENERATOR^|generator| * sign(generator)
56    #[inline]
57    pub fn galois_element(&self, generator: i64) -> i64 {
58        if generator == 0 {
59            return 1;
60        }
61        ((mod_exp_u64(GALOISGENERATOR, generator.unsigned_abs() as usize) & (self.cyclotomic_order() - 1)) as i64)
62            * generator.signum()
63    }
64
65    // Returns gen^-1
66    #[inline]
67    pub fn galois_element_inv(&self, gal_el: i64) -> i64 {
68        if gal_el == 0 {
69            panic!("cannot invert 0")
70        }
71        ((mod_exp_u64(
72            gal_el.unsigned_abs(),
73            (self.cyclotomic_order() - 1) as usize,
74        ) & (self.cyclotomic_order() - 1)) as i64)
75            * gal_el.signum()
76    }
77}
78
79impl<B: Backend> Drop for Module<B> {
80    fn drop(&mut self) {
81        unsafe { B::destroy(self.ptr) }
82    }
83}
84
85pub fn mod_exp_u64(x: u64, e: usize) -> u64 {
86    let mut y: u64 = 1;
87    let mut x_pow: u64 = x;
88    let mut exp = e;
89    while exp > 0 {
90        if exp & 1 == 1 {
91            y = y.wrapping_mul(x_pow);
92        }
93        x_pow = x_pow.wrapping_mul(x_pow);
94        exp >>= 1;
95    }
96    y
97}