p3_field/coset.rs
1use crate::{BoundedPowers, TwoAdicField};
2
3/// Coset of a subgroup of the group of units of a finite field of order equal
4/// to a power of two.
5///
6/// # Examples
7///
8/// ```
9/// # use p3_field::{
10/// TwoAdicField,
11/// PrimeCharacteristicRing,
12/// coset::TwoAdicMultiplicativeCoset
13/// };
14/// # use itertools::Itertools;
15/// # use p3_baby_bear::BabyBear;
16/// #
17/// type F = BabyBear;
18/// let log_size = 3;
19/// let shift = F::from_u64(7);
20/// let mut coset = TwoAdicMultiplicativeCoset::new(shift, log_size).unwrap();
21/// let generator = coset.subgroup_generator();
22///
23/// // Coset elements can be queried by index
24/// assert_eq!(coset.element(4), shift * generator.exp_u64(4));
25///
26/// // Coset elements can be iterated over in the canonical order
27/// assert_eq!(
28/// coset.iter().collect_vec(),
29/// (0..1 << log_size).map(|i| shift * generator.exp_u64(i)).collect_vec()
30/// );
31///
32/// // Cosets can be (element-wise) raised to a power of 2, either maintaining
33/// // the shift and raising only the subgroup, or raising both.
34/// let coset_shrunk_subgroup = coset.shrink_coset(2).unwrap();
35/// assert_eq!(
36/// coset_shrunk_subgroup.subgroup_generator(),
37/// coset.subgroup_generator().exp_power_of_2(2),
38/// );
39/// assert_eq!(
40/// coset_shrunk_subgroup.shift(),
41/// coset.shift()
42/// );
43///
44/// let coset_power = coset.exp_power_of_2(2).unwrap();
45/// assert_eq!(
46/// coset_power.subgroup_generator(),
47/// coset.subgroup_generator().exp_power_of_2(2),
48/// );
49/// assert_eq!(
50/// coset_power.shift(),
51/// coset.shift().exp_power_of_2(2),
52/// );
53/// ```
54#[derive(Clone, Copy, Debug)]
55pub struct TwoAdicMultiplicativeCoset<F: TwoAdicField> {
56 // Letting s = shift, and g = generator (of order 2^log_size), the coset in
57 // question is
58 // s * <g> = {s, s * g, shift * g^2, ..., s * g^(2^log_size - 1)]
59 shift: F,
60 shift_inverse: F,
61 log_size: usize,
62}
63
64impl<F: TwoAdicField> TwoAdicMultiplicativeCoset<F> {
65 /// Returns the coset `shift * <generator>`, where `generator` is a
66 /// canonical (i. e. fixed in the implementation of `F: TwoAdicField`)
67 /// generator of the unique subgroup of the units of `F` of order `2 ^
68 /// log_size`. Returns `None` if `log_size > F::TWO_ADICITY` or if `shift` is zero.
69 ///
70 /// # Arguments
71 ///
72 /// - `shift`: the value by which the subgroup is (multiplicatively)
73 /// shifted
74 /// - `log_size`: the size of the subgroup (and hence of the coset) is `2 ^
75 /// log_size`. This determines the subgroup uniquely.
76 #[must_use]
77 pub fn new(shift: F, log_size: usize) -> Option<Self> {
78 (shift != F::ZERO && log_size <= F::TWO_ADICITY).then(|| {
79 let shift_inverse = shift.inverse();
80 Self {
81 shift,
82 shift_inverse,
83 log_size,
84 }
85 })
86 }
87
88 /// Returns the generator of the subgroup of order `self.size()`.
89 #[inline]
90 #[must_use]
91 pub fn subgroup_generator(&self) -> F {
92 F::two_adic_generator(self.log_size)
93 }
94
95 /// Returns the shift of the coset.
96 #[inline]
97 #[must_use]
98 pub const fn shift(&self) -> F {
99 self.shift
100 }
101
102 /// Returns the inverse of the coset shift.
103 #[inline]
104 #[must_use]
105 pub const fn shift_inverse(&self) -> F {
106 self.shift_inverse
107 }
108
109 /// Returns the log2 of the size of the coset.
110 #[inline]
111 #[must_use]
112 pub const fn log_size(&self) -> usize {
113 self.log_size
114 }
115
116 /// Returns the size of the coset.
117 #[inline]
118 #[must_use]
119 pub const fn size(&self) -> usize {
120 1 << self.log_size
121 }
122
123 /// Returns a new coset with its subgroup reduced by a factor of
124 /// `2^log_scale_factor` in size (i. e. with generator equal to the
125 /// `2^log_scale_factor`-th power of that of the original coset), leaving
126 /// the shift untouched. Note that new coset is contained in the original one.
127 /// Returns `None` if `log_scale_factor` is greater than `self.log_size()`.
128 #[inline]
129 #[must_use]
130 pub fn shrink_coset(&self, log_scale_factor: usize) -> Option<Self> {
131 self.log_size
132 .checked_sub(log_scale_factor)
133 .map(|new_log_size| Self {
134 shift: self.shift,
135 shift_inverse: self.shift_inverse,
136 log_size: new_log_size,
137 })
138 }
139
140 /// Returns the coset `self^(2^log_scale_factor)` (i. e. with shift and
141 /// subgroup generator equal to the `2^log_scale_factor`-th power of the
142 /// original ones). Returns `None` if `log_scale_factor` is greater than `self.log_size()`.
143 #[inline]
144 #[must_use]
145 pub fn exp_power_of_2(&self, log_scale_factor: usize) -> Option<Self> {
146 self.shrink_coset(log_scale_factor).map(|mut coset| {
147 coset.shift = self.shift.exp_power_of_2(log_scale_factor);
148 coset.shift_inverse = self.shift_inverse.exp_power_of_2(log_scale_factor);
149 coset
150 })
151 }
152
153 /// Returns a new coset of the same size whose shift is equal to `scale * self.shift`.
154 #[inline]
155 #[must_use]
156 pub fn shift_by(&self, scale: F) -> Self {
157 let shift = self.shift * scale;
158 Self {
159 shift,
160 shift_inverse: shift.inverse(),
161 log_size: self.log_size,
162 }
163 }
164
165 /// Returns a new coset where the shift has been set to `shift`
166 #[inline]
167 #[must_use]
168 pub fn set_shift(&self, shift: F) -> Self {
169 Self {
170 shift,
171 shift_inverse: shift.inverse(),
172 log_size: self.log_size,
173 }
174 }
175
176 /// Checks if the given field element is in the coset
177 #[inline]
178 #[must_use]
179 pub fn contains(&self, element: F) -> bool {
180 // Note that, in a finite field F (this is not true of a general finite
181 // commutative ring), there is exactly one subgroup of |F^*| of order n
182 // for each divisor n of |F| - 1, and its elements e are uniquely
183 // characterised by the condition e^n = 1.
184
185 // We check (shift^{-1} * element)^(2^log_size) = 1, which is equivalent
186 // to checking shift^(2^log_size) = element^(2^log_size) - this avoids
187 // inversion at the cost of a few squarings. The loop terminates early
188 // if possible.
189 let (mut shift, mut element) = (self.shift, element);
190
191 for _ in 0..self.log_size {
192 if element == shift {
193 return true;
194 }
195 element = element.square();
196 shift = shift.square();
197 }
198
199 element == shift
200 }
201
202 /// Returns the element `shift * generator^index`, which is the `index %
203 /// self.size()`-th element of `self` (and, in particular, the `index`-th
204 /// element of `self` whenever `index` < self.size()).
205 #[inline]
206 #[must_use]
207 pub fn element(&mut self, index: usize) -> F {
208 self.shift * self.generator_exp(index)
209 }
210
211 // Internal function which computes `generator^exp`. It uses the
212 // square-and-multiply algorithm with the caveat that squares of the
213 // generator are queried from the field (which typically should have them
214 // stored), i. e. rather "fetch-and-multiply".
215 #[inline]
216 #[must_use]
217 fn generator_exp(&self, exp: usize) -> F {
218 let mut gen_power = F::ONE;
219 // As `generator` satisfies `generator^{self.size()} == 1` we can replace `exp` by `exp mod self.size()`.
220 // As `self.size()` is a power of `2` this can be done with an `&` instead of a `%`.
221 let mut exp = exp & (self.size() - 1);
222 let mut i = self.log_size();
223
224 while exp > 0 {
225 if exp & 1 != 0 {
226 gen_power *= F::two_adic_generator(i);
227 }
228 exp >>= 1;
229
230 i -= 1;
231 }
232
233 gen_power
234 }
235
236 /// Returns an iterator over the elements of the coset in the canonical order
237 /// `shift * generator^0, shift * generator^1, ...,
238 /// shift * generator^(2^log_size - 1)`.
239 #[inline]
240 #[must_use]
241 pub fn iter(&self) -> BoundedPowers<F> {
242 self.subgroup_generator()
243 .shifted_powers(self.shift)
244 .take(self.size())
245 }
246}
247
248impl<F: TwoAdicField> IntoIterator for TwoAdicMultiplicativeCoset<F> {
249 type Item = F;
250 type IntoIter = BoundedPowers<F>;
251
252 fn into_iter(self) -> Self::IntoIter {
253 self.iter()
254 }
255}
256
257impl<F: TwoAdicField> IntoIterator for &TwoAdicMultiplicativeCoset<F> {
258 type Item = F;
259 type IntoIter = BoundedPowers<F>;
260
261 fn into_iter(self) -> Self::IntoIter {
262 self.iter()
263 }
264}