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 gal_el &= self.cyclotomic_order - 1;
49
50 if gen_2 {
51 return self.cyclotomic_order - gal_el;
52 }
53 gal_el
54 }
55}
56
57pub struct RingRNS<O: Unsigned>(pub Vec<Rc<Ring<O>>>);
58
59impl<O: Unsigned> RingRNS<O> {
60 pub fn log_n(&self) -> usize {
61 return self.n().log2();
62 }
63
64 pub fn n(&self) -> usize {
65 self.0[0].n()
66 }
67
68 pub fn new_polyrns(&self) -> PolyRNS<u64> {
69 PolyRNS::<u64>::new(self.n(), self.level())
70 }
71
72 pub fn new_poly(&self) -> Poly<u64> {
73 Poly::<u64>::new(self.n())
74 }
75
76 pub fn max_level(&self) -> usize {
77 self.0.len() - 1
78 }
79
80 pub fn level(&self) -> usize {
81 self.0.len() - 1
82 }
83
84 pub fn at_level(&self, level: usize) -> RingRNS<O> {
85 assert!(level <= self.0.len());
86 RingRNS(self.0[..level + 1].to_vec())
87 }
88}