he_ring/lintransform/
mod.rs

1use std::sync::{MappedRwLockReadGuard, RwLock, RwLockReadGuard};
2
3use feanor_math::primitive_int::StaticRing;
4use feanor_math::rings::zn::zn_64::*;
5use feanor_math::ring::*;
6use feanor_math::rings::zn::ZnRingStore;
7
8///
9/// Contains algorithms for computing linear transforms and representing them
10/// as linear combination of Galois automorphisms.
11/// 
12pub mod matmul;
13
14///
15/// Contains an implementation of the homomorphic trace.
16/// 
17pub mod trace;
18
19///
20/// Contains an implementation of the Slots-to-Coefficients transform and its inverse
21/// for odd, composite cyclotomic number rings.
22/// 
23pub mod composite;
24
25///
26/// Contains an implementation of the Slots-to-Coefficients transform and its inverse
27/// for power-of-two cyclotomic number rings.
28/// 
29pub mod pow2;
30
31///
32/// Contains an implementation of the slot-broadcast transform.
33/// 
34// pub mod broadcast;
35
36///
37/// Provides access to arbitrary powers of a single element of a finite ring,
38/// caching intermediate powers for faster access.
39/// 
40/// The main use case are HE-style rings, in which multiplication can be quite
41/// expensive.
42/// 
43pub struct PowerTable<R>
44    where R: RingStore
45{
46    ring: R,
47    exponent_ring: Zn,
48    powers: RwLock<Vec<El<R>>>
49}
50
51impl<R> PowerTable<R>
52    where R: RingStore
53{
54    pub fn new(ring: R, base: El<R>, order_of_base: usize) -> Self {
55        debug_assert!(ring.is_one(&ring.pow(ring.clone_el(&base), order_of_base)));
56        Self {
57            powers: RwLock::new(vec![ring.one(), base]),
58            ring: ring,
59            exponent_ring: Zn::new(order_of_base as u64),
60        }
61    }
62
63    pub fn get_power<'a>(&'a self, power: i64) -> MappedRwLockReadGuard<'a, El<R>> {
64        let power = self.exponent_ring.smallest_positive_lift(self.exponent_ring.coerce(&StaticRing::<i64>::RING, power)) as usize;
65        let powers = self.powers.read().unwrap();
66        if powers.len() > power {
67            return RwLockReadGuard::map(powers, |powers| &powers[power]);
68        }
69        drop(powers);
70        let mut powers = self.powers.write().unwrap();
71        while powers.len() <= power {
72            let new = self.ring.mul_ref(powers.last().unwrap(), &powers[1]);
73            powers.push(new);
74        }
75        drop(powers);
76        return RwLockReadGuard::map(self.powers.read().unwrap(), |powers| &powers[power]);
77    }
78}