poulpy/math/src/ring.rs
math/src/ring.rsRaw
1pub mod impl_u64;
2use crate::dft::DFT;
3use crate::modulus::prime::Prime;
4use crate::modulus::WordOps;
5use crate::poly::{Poly, PolyRNS};
6use crate::GALOISGENERATOR;
7use num::traits::Unsigned;
8use std::rc::Rc;
9
10pub struct Ring<O: Unsigned> {
11 pub n: usize,
12 pub modulus: Prime<O>,
13 pub cyclotomic_order: usize,
14 pub dft: Box<dyn DFT<O>>,
15}
16
17impl<O: Unsigned> Ring<O> {
18 pub fn log_n(&self) -> usize {
19 return self.n().log2();
20 }
21
22 pub fn n(&self) -> usize {
23 return self.n;
24 }
25
26 pub fn new_poly(&self) -> Poly<u64> {
27 Poly::<u64>::new(self.n())
28 }
29
30 pub fn cyclotomic_order(&self) -> usize {
31 self.cyclotomic_order
32 }
33
34 // Returns GALOISGENERATOR^gen_1 * (-1)^gen_2 mod 2^log_nth_root.
35 pub fn galois_element(&self, gen_1: usize, gen_2: bool) -> usize {
36 let mut gal_el: usize = 1;
37 let mut gen_1_pow: usize = GALOISGENERATOR;
38 let mut e: usize = gen_1;
39 while e > 0 {
40 if e & 1 == 1 {
41 gal_el = gal_el.wrapping_mul(gen_1_pow);
42 }
43
44 gen_1_pow = gen_1_pow.wrapping_mul(gen_1_pow);
45 e >>= 1;
46 }
47
48 let nth_root = 1 << self.cyclotomic_order;
49 gal_el &= nth_root - 1;
50
51 if gen_2 {
52 return nth_root - gal_el;
53 }
54 gal_el
55 }
56}
57
58pub struct RingRNS<O: Unsigned>(pub Vec<Rc<Ring<O>>>);
59
60impl<O: Unsigned> RingRNS<O> {
61 pub fn log_n(&self) -> usize {
62 return self.n().log2();
63 }
64
65 pub fn n(&self) -> usize {
66 self.0[0].n()
67 }
68
69 pub fn new_polyrns(&self) -> PolyRNS<u64> {
70 PolyRNS::<u64>::new(self.n(), self.level())
71 }
72
73 pub fn new_poly(&self) -> Poly<u64> {
74 Poly::<u64>::new(self.n())
75 }
76
77 pub fn max_level(&self) -> usize {
78 self.0.len() - 1
79 }
80
81 pub fn level(&self) -> usize {
82 self.0.len() - 1
83 }
84
85 pub fn at_level(&self, level: usize) -> RingRNS<O> {
86 assert!(level <= self.0.len());
87 RingRNS(self.0[..level + 1].to_vec())
88 }
89}