1use vectoreyes::U8x16;
6
7use crate::{Bundle, HasModulus};
8
9pub(crate) fn tweak(i: usize) -> u128 {
14 i as u128
15}
16
17pub(crate) fn tweak2(i: u64, j: u64) -> u128 {
19 (j as u128) << 64 | (i as u128)
20}
21
22pub fn output_tweak(i: usize, k: u16) -> u128 {
25 let (left, _) = (i as u128).overflowing_shl(64);
26 left + k as u128
27}
28
29#[cfg(test)]
34fn as_base_q(x: u128, q: u16, n: usize) -> Vec<u16> {
35 let ms = std::iter::repeat_n(q, n).collect::<Vec<_>>();
36 as_mixed_radix(x, &ms)
37}
38
39pub(crate) fn digits_per_u128(modulus: u16) -> usize {
42 debug_assert_ne!(modulus, 0);
43 debug_assert_ne!(modulus, 1);
44 if modulus == 2 {
45 128
46 } else if modulus <= 4 {
47 64
48 } else if modulus <= 8 {
49 42
50 } else if modulus <= 16 {
51 32
52 } else if modulus <= 32 {
53 25
54 } else if modulus <= 64 {
55 21
56 } else if modulus <= 128 {
57 18
58 } else if modulus <= 256 {
59 16
60 } else if modulus <= 512 {
61 14
62 } else {
63 (128.0 / (modulus as f64).log2().ceil()).floor() as usize
64 }
65}
66
67#[cfg(test)]
69pub(crate) fn as_base_q_u128(x: u128, q: u16) -> Vec<u16> {
70 as_base_q(x, q, digits_per_u128(q))
71}
72
73pub(crate) fn as_mixed_radix(x: u128, radii: &[u16]) -> Vec<u16> {
75 let mut x = x;
76 radii
77 .iter()
78 .map(|&m| {
79 if x >= m as u128 {
80 let d = x % m as u128;
81 x = (x - d) / m as u128;
82 d as u16
83 } else {
84 let d = x as u16;
85 x = 0;
86 d
87 }
88 })
89 .collect()
90}
91
92pub(crate) fn from_base_q(ds: &[u16], q: u16) -> u128 {
94 let mut x = 0u128;
95 for &d in ds.iter().rev() {
96 let (xp, overflow) = x.overflowing_mul(q.into());
97 debug_assert!(!overflow, "overflow!!!! x={}", x);
98 x = xp + d as u128;
99 }
100 x
101}
102
103pub(crate) fn u128_to_bits(x: u128, n: usize) -> Vec<u16> {
109 let mut bits = Vec::with_capacity(n);
110 let mut y = x;
111 for _ in 0..n {
112 let b = y & 1;
113 bits.push(b as u16);
114 y -= b;
115 y /= 2;
116 }
117 bits
118}
119
120pub fn u128_from_bits(bs: &[u16]) -> u128 {
122 let mut x = 0;
123 for &b in bs.iter().skip(1).rev() {
124 x += b as u128;
125 x *= 2;
126 }
127 x += bs[0] as u128;
128 x
129}
130
131pub fn factor(inp: u128) -> Vec<u16> {
140 let mut x = inp;
141 let mut fs = Vec::new();
142 for &p in PRIMES.iter() {
143 let q = p as u128;
144 if x.is_multiple_of(q) {
145 fs.push(p);
146 x /= q;
147 }
148 }
149 if x != 1 {
150 panic!("can only factor numbers with unique prime factors");
151 }
152 fs
153}
154
155pub fn crt(x: u128, ps: &[u16]) -> Vec<u16> {
157 ps.iter().map(|&p| (x % p as u128) as u16).collect()
158}
159
160pub fn crt_factor(x: u128, q: u128) -> Vec<u16> {
163 crt(x, &factor(q))
164}
165
166pub fn crt_inv(xs: &[u16], ps: &[u16]) -> u128 {
168 let mut ret = 0;
169 let M = ps.iter().fold(1, |acc, &x| x as i128 * acc);
170 for (&p, &a) in ps.iter().zip(xs.iter()) {
171 let p = p as i128;
172 let q = M / p;
173 ret += a as i128 * inv(q, p) * q;
174 ret %= &M;
175 }
176 ret as u128
177}
178
179pub fn crt_inv_factor(xs: &[u16], q: u128) -> u128 {
181 crt_inv(xs, &factor(q))
182}
183
184pub(crate) fn inv(inp_a: i128, inp_b: i128) -> i128 {
186 let mut a = inp_a;
187 let mut b = inp_b;
188 let mut q;
189 let mut tmp;
190
191 let (mut x0, mut x1) = (0, 1);
192
193 if b == 1 {
194 return 1;
195 }
196
197 while a > 1 {
198 q = a / b;
199
200 tmp = b;
202 b = a % b;
203 a = tmp;
204
205 tmp = x0;
206 x0 = x1 - q * x0;
207 x1 = tmp;
208 }
209
210 if x1 < 0 {
211 x1 += inp_b;
212 }
213
214 x1
215}
216
217const NPRIMES: usize = 29;
218
219pub const PRIMES: [u16; NPRIMES] = [
221 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97,
222 101, 103, 107, 109,
223];
224
225pub fn modulus_with_nprimes(n: usize) -> u128 {
227 product(&PRIMES[0..n])
228}
229
230pub fn modulus_with_width(n: u32) -> u128 {
233 product(&base_primes_with_width(n, &PRIMES))
234}
235
236pub fn primes_with_width(n: u32) -> Vec<u16> {
239 base_primes_with_width(n, &PRIMES)
240}
241
242fn base_primes_with_width(nbits: u32, primes: &[u16]) -> Vec<u16> {
245 let mut res = 1;
246 let mut ps = Vec::new();
247 for &p in primes.iter() {
248 res *= u128::from(p);
249 ps.push(p);
250 if (res >> nbits) > 0 {
251 break;
252 }
253 }
254 assert!((res >> nbits) > 0, "not enough primes!");
255 ps
256}
257
258pub fn product(xs: &[u16]) -> u128 {
260 xs.iter().fold(1, |acc, &x| acc * x as u128)
261}
262
263pub(crate) fn get_ms<W: Clone + HasModulus>(x: &Bundle<W>, accuracy: &str) -> Vec<u16> {
268 match accuracy {
269 "100%" => match x.moduli().len() {
270 3 => vec![2; 5],
271 4 => vec![3, 26],
272 5 => vec![3, 4, 54],
273 6 => vec![5, 5, 5, 60],
274 7 => vec![5, 6, 6, 7, 86],
275 8 => vec![5, 7, 8, 8, 9, 98],
276 9 => vec![5, 5, 7, 7, 7, 7, 7, 76],
277 10 => vec![5, 5, 6, 6, 6, 6, 11, 11, 202],
278 11 => vec![5, 5, 5, 5, 5, 6, 6, 6, 7, 7, 8, 150],
279 n => panic!("unknown exact Ms for {} primes!", n),
280 },
281 "99.999%" => match x.moduli().len() {
282 8 => vec![5, 5, 6, 7, 102],
283 9 => vec![5, 5, 6, 7, 114],
284 10 => vec![5, 6, 6, 7, 102],
285 11 => vec![5, 5, 6, 7, 130],
286 n => panic!("unknown 99.999% accurate Ms for {} primes!", n),
287 },
288 "99.99%" => match x.moduli().len() {
289 6 => vec![5, 5, 5, 42],
290 7 => vec![4, 5, 6, 88],
291 8 => vec![4, 5, 7, 78],
292 9 => vec![5, 5, 6, 84],
293 10 => vec![4, 5, 6, 112],
294 11 => vec![7, 11, 174],
295 n => panic!("unknown 99.99% accurate Ms for {} primes!", n),
296 },
297 "99.9%" => match x.moduli().len() {
298 5 => vec![3, 5, 30],
299 6 => vec![4, 5, 48],
300 7 => vec![4, 5, 60],
301 8 => vec![3, 5, 78],
302 9 => vec![9, 140],
303 10 => vec![7, 190],
304 n => panic!("unknown 99.9% accurate Ms for {} primes!", n),
305 },
306 "99%" => match x.moduli().len() {
307 4 => vec![3, 18],
308 5 => vec![3, 36],
309 6 => vec![3, 40],
310 7 => vec![3, 40],
311 8 => vec![126],
312 9 => vec![138],
313 10 => vec![140],
314 n => panic!("unknown 99% accurate Ms for {} primes!", n),
315 },
316 _ => panic!("get_ms: unsupported accuracy {}", accuracy),
317 }
318}
319
320pub trait RngExt: rand::Rng + Sized {
322 fn gen_bool(&mut self) -> bool {
324 self.r#gen()
325 }
326 fn gen_u16(&mut self) -> u16 {
328 self.r#gen()
329 }
330 fn gen_u64(&mut self) -> u64 {
332 self.r#gen()
333 }
334 fn gen_usize(&mut self) -> usize {
336 self.r#gen()
337 }
338 fn gen_u128(&mut self) -> u128 {
340 self.r#gen()
341 }
342 fn gen_usable_block(&mut self, modulus: u16) -> U8x16 {
344 if modulus.is_power_of_two() {
345 let nbits = (modulus - 1).count_ones();
346 if 128 % nbits == 0 {
347 return U8x16::from(self.gen_u128());
348 }
349 }
350 let n = digits_per_u128(modulus);
351 let max = (modulus as u128).pow(n as u32);
352 U8x16::from(self.gen_u128() % max)
353 }
354 fn gen_prime(&mut self) -> u16 {
356 PRIMES[self.r#gen::<usize>() % NPRIMES]
357 }
358 fn gen_modulus(&mut self) -> u16 {
360 2 + (self.r#gen::<u16>() % 111)
361 }
362 fn gen_usable_composite_modulus(&mut self) -> u128 {
364 product(&self.gen_usable_factors())
365 }
366 fn gen_usable_factors(&mut self) -> Vec<u16> {
368 let mut x: u128 = 1;
369 PRIMES[..25]
370 .iter()
371 .cloned()
372 .filter(|_| self.r#gen()) .take_while(|&q| {
374 match x.checked_mul(q as u128) {
376 None => false,
377 Some(y) => {
378 x = y;
379 true
380 }
381 }
382 })
383 .collect()
384 }
385}
386
387impl<R: rand::Rng + Sized> RngExt for R {}
388
389#[cfg(test)]
393mod tests {
394 use super::*;
395 use crate::util::RngExt;
396 use rand::thread_rng;
397
398 #[test]
399 fn crt_conversion() {
400 let mut rng = thread_rng();
401 let ps = &PRIMES[..25];
402 let modulus = product(ps);
403
404 for _ in 0..128 {
405 let x = rng.gen_u128() % modulus;
406 assert_eq!(crt_inv(&crt(x, ps), ps), x);
407 }
408 }
409
410 #[test]
411 fn factoring() {
412 let mut rng = thread_rng();
413 for _ in 0..16 {
414 let mut ps = Vec::new();
415 let mut q: u128 = 1;
416 for &p in PRIMES.iter() {
417 if rng.gen_bool() {
418 match q.checked_mul(p as u128) {
419 None => break,
420 Some(z) => q = z,
421 }
422 ps.push(p);
423 }
424 }
425 assert_eq!(factor(q), ps);
426 }
427 }
428
429 #[test]
430 fn bits() {
431 let mut rng = thread_rng();
432 for _ in 0..128 {
433 let x = rng.gen_u128();
434 assert_eq!(u128_from_bits(&u128_to_bits(x, 128)), x);
435 }
436 }
437
438 #[test]
439 fn base_q_conversion() {
440 let mut rng = thread_rng();
441 for _ in 0..1000 {
442 let q = 2 + (rng.gen_u16() % 111);
443 let x = u128::from(rng.gen_usable_block(q));
444 let y = as_base_q(x, q, digits_per_u128(q));
445 let z = from_base_q(&y, q);
446 assert_eq!(x, z);
447 }
448 }
449}