poulpy/base2k/src/scalar_znx_dft.rs
base2k/src/scalar_znx_dft.rsRaw
1use std::marker::PhantomData;
2
3use crate::ffi::svp::{self, svp_ppol_t};
4use crate::ffi::vec_znx_dft::vec_znx_dft_t;
5use crate::znx_base::{ZnxBase, ZnxInfos, ZnxLayout, ZnxSliceSize};
6use crate::{Backend, FFT64, Module, VecZnx, VecZnxDft, alloc_aligned, assert_alignement, cast_mut};
7use rand::seq::SliceRandom;
8use rand_core::RngCore;
9use rand_distr::{Distribution, weighted::WeightedIndex};
10use sampling::source::Source;
11
12pub struct Scalar {
13 pub n: usize,
14 pub data: Vec<i64>,
15 pub ptr: *mut i64,
16}
17
18impl<B: Backend> Module<B> {
19 pub fn new_scalar(&self) -> Scalar {
20 Scalar::new(self.n())
21 }
22}
23
24impl Scalar {
25 pub fn new(n: usize) -> Self {
26 let mut data: Vec<i64> = alloc_aligned::<i64>(n);
27 let ptr: *mut i64 = data.as_mut_ptr();
28 Self {
29 n: n,
30 data: data,
31 ptr: ptr,
32 }
33 }
34
35 pub fn n(&self) -> usize {
36 self.n
37 }
38
39 pub fn bytes_of(n: usize) -> usize {
40 n * std::mem::size_of::<i64>()
41 }
42
43 pub fn from_bytes(n: usize, bytes: &mut [u8]) -> Self {
44 let size: usize = Self::bytes_of(n);
45 debug_assert!(
46 bytes.len() == size,
47 "invalid buffer: bytes.len()={} < self.bytes_of(n={})={}",
48 bytes.len(),
49 n,
50 size
51 );
52 #[cfg(debug_assertions)]
53 {
54 assert_alignement(bytes.as_ptr())
55 }
56 unsafe {
57 let bytes_i64: &mut [i64] = cast_mut::<u8, i64>(bytes);
58 let ptr: *mut i64 = bytes_i64.as_mut_ptr();
59 Self {
60 n: n,
61 data: Vec::from_raw_parts(bytes_i64.as_mut_ptr(), bytes.len(), bytes.len()),
62 ptr: ptr,
63 }
64 }
65 }
66
67 pub fn from_bytes_borrow(n: usize, bytes: &mut [u8]) -> Self {
68 let size: usize = Self::bytes_of(n);
69 debug_assert!(
70 bytes.len() == size,
71 "invalid buffer: bytes.len()={} < self.bytes_of(n={})={}",
72 bytes.len(),
73 n,
74 size
75 );
76 #[cfg(debug_assertions)]
77 {
78 assert_alignement(bytes.as_ptr())
79 }
80 let bytes_i64: &mut [i64] = cast_mut::<u8, i64>(bytes);
81 let ptr: *mut i64 = bytes_i64.as_mut_ptr();
82 Self {
83 n: n,
84 data: Vec::new(),
85 ptr: ptr,
86 }
87 }
88
89 pub fn as_ptr(&self) -> *const i64 {
90 self.ptr
91 }
92
93 pub fn raw(&self) -> &[i64] {
94 unsafe { std::slice::from_raw_parts(self.ptr, self.n) }
95 }
96
97 pub fn raw_mut(&self) -> &mut [i64] {
98 unsafe { std::slice::from_raw_parts_mut(self.ptr, self.n) }
99 }
100
101 pub fn fill_ternary_prob(&mut self, prob: f64, source: &mut Source) {
102 let choices: [i64; 3] = [-1, 0, 1];
103 let weights: [f64; 3] = [prob / 2.0, 1.0 - prob, prob / 2.0];
104 let dist: WeightedIndex<f64> = WeightedIndex::new(&weights).unwrap();
105 self.data
106 .iter_mut()
107 .for_each(|x: &mut i64| *x = choices[dist.sample(source)]);
108 }
109
110 pub fn fill_ternary_hw(&mut self, hw: usize, source: &mut Source) {
111 assert!(hw <= self.n());
112 self.data[..hw]
113 .iter_mut()
114 .for_each(|x: &mut i64| *x = (((source.next_u32() & 1) as i64) << 1) - 1);
115 self.data.shuffle(source);
116 }
117
118 pub fn as_vec_znx(&self) -> VecZnx {
119 VecZnx {
120 inner: ZnxBase {
121 n: self.n,
122 rows: 1,
123 cols: 1,
124 size: 1,
125 data: Vec::new(),
126 ptr: self.ptr as *mut u8,
127 },
128 }
129 }
130}
131
132pub trait ScalarOps {
133 fn bytes_of_scalar(&self) -> usize;
134 fn new_scalar(&self) -> Scalar;
135 fn new_scalar_from_bytes(&self, bytes: &mut [u8]) -> Scalar;
136 fn new_scalar_from_bytes_borrow(&self, tmp_bytes: &mut [u8]) -> Scalar;
137}
138impl<B: Backend> ScalarOps for Module<B> {
139 fn bytes_of_scalar(&self) -> usize {
140 Scalar::bytes_of(self.n())
141 }
142 fn new_scalar(&self) -> Scalar {
143 Scalar::new(self.n())
144 }
145 fn new_scalar_from_bytes(&self, bytes: &mut [u8]) -> Scalar {
146 Scalar::from_bytes(self.n(), bytes)
147 }
148 fn new_scalar_from_bytes_borrow(&self, tmp_bytes: &mut [u8]) -> Scalar {
149 Scalar::from_bytes_borrow(self.n(), tmp_bytes)
150 }
151}
152
153pub struct ScalarZnxDft<B: Backend> {
154 pub n: usize,
155 pub data: Vec<u8>,
156 pub ptr: *mut u8,
157 _marker: PhantomData<B>,
158}
159
160/// A prepared [crate::Scalar] for [SvpPPolOps::svp_apply_dft].
161/// An [SvpPPol] an be seen as a [VecZnxDft] of one limb.
162impl ScalarZnxDft<FFT64> {
163 pub fn new(module: &Module<FFT64>) -> Self {
164 module.new_scalar_znx_dft()
165 }
166
167 /// Returns the ring degree of the [SvpPPol].
168 pub fn n(&self) -> usize {
169 self.n
170 }
171
172 pub fn bytes_of(module: &Module<FFT64>) -> usize {
173 module.bytes_of_scalar_znx_dft()
174 }
175
176 pub fn from_bytes(module: &Module<FFT64>, bytes: &mut [u8]) -> Self {
177 #[cfg(debug_assertions)]
178 {
179 assert_alignement(bytes.as_ptr());
180 assert_eq!(bytes.len(), module.bytes_of_scalar_znx_dft());
181 }
182 unsafe {
183 Self {
184 n: module.n(),
185 data: Vec::from_raw_parts(bytes.as_mut_ptr(), bytes.len(), bytes.len()),
186 ptr: bytes.as_mut_ptr(),
187 _marker: PhantomData,
188 }
189 }
190 }
191
192 pub fn from_bytes_borrow(module: &Module<FFT64>, tmp_bytes: &mut [u8]) -> Self {
193 #[cfg(debug_assertions)]
194 {
195 assert_alignement(tmp_bytes.as_ptr());
196 assert_eq!(tmp_bytes.len(), module.bytes_of_scalar_znx_dft());
197 }
198 Self {
199 n: module.n(),
200 data: Vec::new(),
201 ptr: tmp_bytes.as_mut_ptr(),
202 _marker: PhantomData,
203 }
204 }
205
206 /// Returns the number of cols of the [SvpPPol], which is always 1.
207 pub fn cols(&self) -> usize {
208 1
209 }
210}
211
212pub trait ScalarZnxDftOps<B: Backend> {
213 /// Allocates a new [SvpPPol].
214 fn new_scalar_znx_dft(&self) -> ScalarZnxDft<B>;
215
216 /// Returns the minimum number of bytes necessary to allocate
217 /// a new [SvpPPol] through [SvpPPol::from_bytes] ro.
218 fn bytes_of_scalar_znx_dft(&self) -> usize;
219
220 /// Allocates a new [SvpPPol] from an array of bytes.
221 /// The array of bytes is owned by the [SvpPPol].
222 /// The method will panic if bytes.len() < [SvpPPolOps::bytes_of_svp_ppol]
223 fn new_scalar_znx_dft_from_bytes(&self, bytes: &mut [u8]) -> ScalarZnxDft<B>;
224
225 /// Allocates a new [SvpPPol] from an array of bytes.
226 /// The array of bytes is borrowed by the [SvpPPol].
227 /// The method will panic if bytes.len() < [SvpPPolOps::bytes_of_svp_ppol]
228 fn new_scalar_znx_dft_from_bytes_borrow(&self, tmp_bytes: &mut [u8]) -> ScalarZnxDft<B>;
229
230 /// Prepares a [crate::Scalar] for a [SvpPPolOps::svp_apply_dft].
231 fn svp_prepare(&self, svp_ppol: &mut ScalarZnxDft<B>, a: &Scalar);
232
233 /// Applies the [SvpPPol] x [VecZnxDft] product, where each limb of
234 /// the [VecZnxDft] is multiplied with [SvpPPol].
235 fn svp_apply_dft(&self, res: &mut VecZnxDft<B>, res_col: usize, a: &ScalarZnxDft<B>, b: &VecZnx, b_col: usize);
236}
237
238impl ScalarZnxDftOps<FFT64> for Module<FFT64> {
239 fn new_scalar_znx_dft(&self) -> ScalarZnxDft<FFT64> {
240 let mut data: Vec<u8> = alloc_aligned::<u8>(self.bytes_of_scalar_znx_dft());
241 let ptr: *mut u8 = data.as_mut_ptr();
242 ScalarZnxDft::<FFT64> {
243 data: data,
244 ptr: ptr,
245 n: self.n(),
246 _marker: PhantomData,
247 }
248 }
249
250 fn bytes_of_scalar_znx_dft(&self) -> usize {
251 unsafe { svp::bytes_of_svp_ppol(self.ptr) as usize }
252 }
253
254 fn new_scalar_znx_dft_from_bytes(&self, bytes: &mut [u8]) -> ScalarZnxDft<FFT64> {
255 ScalarZnxDft::from_bytes(self, bytes)
256 }
257
258 fn new_scalar_znx_dft_from_bytes_borrow(&self, tmp_bytes: &mut [u8]) -> ScalarZnxDft<FFT64> {
259 ScalarZnxDft::from_bytes_borrow(self, tmp_bytes)
260 }
261
262 fn svp_prepare(&self, res: &mut ScalarZnxDft<FFT64>, a: &Scalar) {
263 unsafe { svp::svp_prepare(self.ptr, res.ptr as *mut svp_ppol_t, a.as_ptr()) }
264 }
265
266 fn svp_apply_dft(&self, res: &mut VecZnxDft<FFT64>, res_col: usize, a: &ScalarZnxDft<FFT64>, b: &VecZnx, b_col: usize) {
267 unsafe {
268 svp::svp_apply_dft(
269 self.ptr,
270 res.at_mut_ptr(res_col, 0) as *mut vec_znx_dft_t,
271 res.size() as u64,
272 a.ptr as *const svp_ppol_t,
273 b.at_ptr(b_col, 0),
274 b.size() as u64,
275 b.sl() as u64,
276 )
277 }
278 }
279}