feanor_math/algorithms/
discrete_log.rs

1
2use crate::algorithms::eea::{inv_crt, signed_gcd};
3use crate::algorithms::int_bisect::root_floor;
4use crate::algorithms::int_factor::factor;
5use crate::algorithms::linsolve::smith::{determinant_using_pre_smith, pre_smith};
6use crate::algorithms::linsolve::LinSolveRingStore;
7use crate::algorithms::lll::exact::lll;
8use crate::algorithms::matmul::MatmulAlgorithm;
9use crate::algorithms::matmul::STANDARD_MATMUL;
10use crate::divisibility::DivisibilityRing;
11use crate::divisibility::DivisibilityRingStore;
12use crate::group::*;
13use crate::group::HashableGroupEl;
14use crate::group::MultGroup;
15use crate::iters::multi_cartesian_product;
16use crate::matrix::transform::TransformTarget;
17use crate::pid::PrincipalIdealRingStore;
18use crate::rings::finite::FiniteRingStore;
19use crate::field::FieldStore;
20use crate::homomorphism::Homomorphism;
21use crate::integer::int_cast;
22use crate::integer::BigIntRing;
23use crate::matrix::*;
24use crate::primitive_int::StaticRing;
25use crate::ring::*;
26use crate::rings::rational::RationalField;
27use crate::ordered::OrderedRingStore;
28use crate::rings::zn::ZnRingStore;
29use crate::rings::zn::zn_big;
30use crate::rings::zn::ZnRing;
31use crate::serialization::{DeserializeWithRing, SerializeWithRing};
32
33use serde::{Deserialize, Serialize};
34use feanor_serde::dependent_tuple::DeserializeSeedDependentTuple;
35use feanor_serde::impl_deserialize_seed_for_dependent_struct;
36use feanor_serde::map::DeserializeSeedMapped;
37use feanor_serde::newtype_struct::{DeserializeSeedNewtypeStruct, SerializableNewtypeStruct};
38use feanor_serde::seq::{DeserializeSeedSeq, SerializableSeq};
39
40use std::alloc::Global;
41use std::collections::HashMap;
42use std::marker::PhantomData;
43use std::mem::replace;
44use std::rc::Rc;
45
46const ZZ: StaticRing<i64> = StaticRing::<i64>::RING;
47const ZZbig: BigIntRing = BigIntRing::RING;
48
49///
50/// Represents a subgroup of an [`AbelianGroupBase`] by a set of generators.
51/// Supports computing discrete logarithms, i.e. representing a given element
52/// as a combination of the generators.
53/// 
54/// Note that the used algorithms have a worst case complexity of `O(sqrt(ord^n))`
55/// where `ord` is the given multiple of the orders of each generator, and `n`
56/// is the number of generators. However, if `ord` is smooth, much faster algorithms
57/// are used.
58/// 
59#[stability::unstable(feature = "enable")]
60pub struct SubgroupBase<G: AbelianGroupStore> {
61    parent: G,
62    generators: Vec<GroupEl<G>>,
63    order_multiple: El<BigIntRing>,
64    order_factorization: Vec<(i64, usize)>,
65    /// the `(i, j)`-th entry has rows that form a basis of the relation lattice of
66    /// the set `n/pi^j g1, ..., n/pi^j gk` (where `n` is the order of the group, 
67    /// and the `pi^ei` are its prime power factors)
68    scaled_relation_lattices: Vec<Vec<OwnedMatrix<i64>>>,
69    /// the `(i, j, k)`-th entry contains `sum_l row[l] n/pi^(j + 1) gl`, where
70    /// `row` is the `k`-th row of `scaled_relation_lattice[i, j]`; These values
71    /// are important, since they form a basis of the `p`-torsion subgroup of
72    /// `< n/pi^(j + 1) g1, ..., n/pi^(j + 1) gk >`
73    scaled_generating_sets: Vec<Vec<Vec<GroupEl<G>>>>
74}
75
76///
77/// [`GroupStore`] of [`SubgroupBase`]
78/// 
79#[stability::unstable(feature = "enable")]
80#[allow(type_alias_bounds)]
81pub type Subgroup<G: AbelianGroupStore> = GroupValue<SubgroupBase<G>>;
82
83impl<G: AbelianGroupStore> Subgroup<G> {
84
85    ///
86    /// Creates a new [`GeneratingSet`] representing the subgroup generated
87    /// by the given generators.
88    /// 
89    /// The value `order_multiple` should be a multiple of the order of every
90    /// generator, including generators that will be added later on via
91    /// [`GeneratingSet::add_generator()`].
92    /// 
93    #[stability::unstable(feature = "enable")]
94    pub fn new(group: G, order_multiple: El<BigIntRing>, generators: Vec<GroupEl<G>>) -> Self {
95        let n = generators.len();
96        if n == 0 {
97            return GroupValue::from(SubgroupBase {
98                parent: group,
99                generators: Vec::new(),
100                order_multiple: ZZbig.clone_el(&order_multiple),
101                order_factorization: factor(ZZbig, order_multiple).into_iter().map(|(p, e)| (int_cast(p, ZZ, ZZbig), e)).collect(),
102                scaled_generating_sets: Vec::new(),
103                scaled_relation_lattices: Vec::new()
104            });
105        } else {
106            let mut result = Self::new(group, order_multiple, Vec::new());
107            for g in generators {
108                result = result.add_generator(g);
109            }
110            return result;
111        }
112    }
113
114    ///
115    /// Returns the group that this group is a subgroup of.
116    /// 
117    #[stability::unstable(feature = "enable")]
118    pub fn parent(&self) -> &G {
119        self.get_group().parent()
120    }
121
122    ///
123    /// Returns the order of the subgroup, i.e. the number of elements.
124    /// 
125    #[stability::unstable(feature = "enable")]
126    pub fn subgroup_order(&self) -> El<BigIntRing> {
127        self.get_group().subgroup_order()
128    }
129
130    ///
131    /// Returns the stored generating set of the subgroup.
132    /// 
133    #[stability::unstable(feature = "enable")]
134    pub fn generators(&self) -> &[GroupEl<G>] {
135        self.get_group().generators()
136    }
137
138    ///
139    /// Adds a generator to this subgroup, returning a new, larger subgroup.
140    /// 
141    #[stability::unstable(feature = "enable")]
142    pub fn add_generator(self, new_gen_base: GroupEl<G>) -> Self {
143        Self::from(self.into().add_generator(new_gen_base))
144    }
145
146    ///
147    /// Checks whether the given element of the parent group is contained
148    /// in the subgroup.
149    /// 
150    #[stability::unstable(feature = "enable")]
151    pub fn contains(&self, element: &GroupEl<G>) -> bool {
152        self.get_group().contains(element)
153    }
154
155    ///
156    /// Writes the given element of the parent group as a combination of the
157    /// subgroup generators, if this exists.
158    /// 
159    #[stability::unstable(feature = "enable")]
160    pub fn dlog(&self, target: &GroupEl<G>) -> Option<Vec<i64>> {
161        self.get_group().dlog(target)
162    }
163    
164    ///
165    /// Returns an iterator over all elements of the subgroup.
166    /// 
167    #[stability::unstable(feature = "enable")]
168    pub fn enumerate_elements<'a>(&'a self) -> impl use<'a, G> + Clone + Iterator<Item = GroupEl<G>> {
169        self.get_group().enumerate_elements()
170    }
171}
172
173impl<G: AbelianGroupStore> SubgroupBase<G> {
174
175    #[stability::unstable(feature = "enable")]
176    pub fn parent(&self) -> &G {
177        &self.parent
178    }
179
180    ///
181    /// The number of elements in the subgroup generated by this generating set.
182    /// 
183    #[stability::unstable(feature = "enable")]
184    pub fn subgroup_order(&self) -> El<BigIntRing> {
185        let mut result = ZZbig.one();
186        let n = self.generators.len();
187        if n == 0 {
188            return result;
189        }
190        for i in 0..self.order_factorization.len() {
191            let (p, e) = self.order_factorization[i];
192            let relation_lattice = self.scaled_relation_lattices[i][e].data();
193            let Zpne = zn_big::Zn::new(ZZbig, ZZbig.pow(int_cast(p, ZZbig, StaticRing::<i64>::RING), e * n));
194            let mod_pne = Zpne.can_hom(&StaticRing::<i64>::RING).unwrap();
195            let relation_lattice_det = determinant_using_pre_smith(
196                &Zpne, 
197                OwnedMatrix::from_fn(relation_lattice.row_count(), relation_lattice.col_count(), |k, l| mod_pne.map(*relation_lattice.at(k, l))).data_mut(), 
198                Global
199            );
200            ZZbig.mul_assign(&mut result, signed_gcd(ZZbig.clone_el(Zpne.modulus()), Zpne.smallest_positive_lift(relation_lattice_det), ZZbig));
201        }
202        return result;
203    }
204
205    ///
206    /// Returns a multiple of the order of each element in the subgroup
207    /// generated by this generating set.
208    /// 
209    #[stability::unstable(feature = "enable")]
210    pub fn order_multiple(&self) -> &El<BigIntRing> {
211        &self.order_multiple
212    }
213
214    ///
215    /// Returns a set of generators of this subgroup.
216    /// 
217    #[stability::unstable(feature = "enable")]
218    pub fn generators(&self) -> &[GroupEl<G>] {
219        &self.generators
220    }
221
222    ///
223    /// Extends the generating set by an additional generator, which is likely
224    /// to grow the represented subgroup.
225    /// 
226    /// The new generator must be of order dividing [`GeneratingSet::order_multiple()`].
227    /// 
228    #[stability::unstable(feature = "enable")]
229    pub fn add_generator(self, new_gen_base: GroupEl<G>) -> Self {
230        let group = &self.parent;
231        assert!(group.is_identity(&group.pow(&new_gen_base, &self.order_multiple)));
232        let ZZ_to_ZZbig = ZZbig.can_hom(&ZZ).unwrap();
233
234        let mut scaled_relation_lattices = Vec::new();
235        let mut scaled_generating_sets = Vec::new();
236        for p_idx in 0..self.order_factorization.len() {
237            
238            let (p, e) = self.order_factorization[p_idx];
239            let p_bigint = ZZ_to_ZZbig.map(p);
240            let power = ZZbig.checked_div(
241                &self.order_multiple, 
242                &ZZbig.pow(ZZbig.clone_el(&p_bigint), e)
243            ).unwrap();
244            let gens = self.generators.iter().map(|g| group.pow(g, &power)).collect::<Vec<_>>();
245            let new_gen = group.pow(&new_gen_base, &power);
246            
247            let n = self.generators.len();
248
249            let mut main_relation_matrix = OwnedMatrix::zero(n + 1, n + 1, ZZ);
250            for i in 0..n {
251                for j in 0..n {
252                    *main_relation_matrix.at_mut(i, j) = *self.scaled_relation_lattices[p_idx][e].at(i, j);
253                }
254            }
255            *main_relation_matrix.at_mut(n, n) = -ZZ.pow(p, e);
256            for k in 0..e {
257                if let Some(dlog) = self.padic_dlog(p_idx, e, &group.pow(&new_gen, &ZZbig.pow(ZZbig.clone_el(&p_bigint), k))) {
258                    *main_relation_matrix.at_mut(n, n) = -ZZ.pow(p, k);
259                    for j in 0..n {
260                        *main_relation_matrix.at_mut(n, j) = dlog[j];
261                    }
262                    break;
263                }
264            }
265            debug_assert!(main_relation_matrix.data().row_iter().all(|row| group.is_identity(
266                &(0..n).fold(group.pow(&new_gen, &ZZ_to_ZZbig.map(row[n])), |current, i| group.op(current, group.pow(&gens[i], &ZZ_to_ZZbig.map(row[i]))))
267            )));
268
269            let mut result = Vec::with_capacity(e + 1);
270            result.push(main_relation_matrix);
271            for _ in 0..e {
272                result.push(Self::relation_lattice_basis_downscale_p(result.last().unwrap().data(), p));
273            }
274            result.reverse();
275            scaled_relation_lattices.push(result);
276            
277            let mut generating_sets = Vec::new();
278            for i in 0..e {
279                let generating_set = scaled_relation_lattices.last().unwrap()[i].data().row_iter().map(|row| {
280                    let scale = ZZbig.pow(ZZbig.clone_el(&p_bigint), e - i - 1);
281                    let result = (0..n).fold(group.pow(&new_gen, &ZZ_to_ZZbig.mul_ref_map(&scale, &row[n])), |current, j| 
282                        group.op(current, group.pow(&gens[j], &ZZ_to_ZZbig.mul_ref_map(&scale, &row[j])))
283                    );
284                    debug_assert!(group.is_identity(&group.pow(&result, &p_bigint)));
285                    result
286                }).collect::<Vec<_>>();
287                generating_sets.push(generating_set);
288            }
289            scaled_generating_sets.push(generating_sets);
290        }
291        
292        return Self {
293            generators: self.generators.iter().map(|g| group.clone_el(g)).chain([new_gen_base].into_iter()).collect(),
294            order_multiple: ZZbig.clone_el(&self.order_multiple),
295            order_factorization: self.order_factorization.clone(),
296            scaled_generating_sets: scaled_generating_sets,
297            scaled_relation_lattices: scaled_relation_lattices,
298            parent: self.parent
299        };
300    }
301
302    /// 
303    /// # Algorithm
304    ///  
305    /// We are working over `G = ord/p^e global_group`, in which every element
306    /// has order dividing `p^e`. Clearly, it is generated by the global generators,
307    /// scaled by `ord/p^e`.
308    /// 
309    /// We want to compute a dlog of `x` w.r.t. `g1, ..., gn`. For this, we use the exact sequence
310    /// ```text
311    ///   0  ->  H  ->  G  ->  G/H  ->  0
312    /// ```
313    /// where `H = { a in G | p a = 0 }` is the `p`-torsion subgroup. Note that the
314    /// power-of-`p` map gives an isomorphism `G/H -> pG`, which allows us to recursively
315    /// solve dlog in `G/H`. Hence, we want to solve dlog in `H`, which we can do using
316    /// the baby-giant step method - if we can find a generating set of `H`. We find it
317    /// using the already provided basis of the relation modulo of the generators.
318    /// 
319    fn padic_dlog(&self, p_idx: usize, e: usize, target: &GroupEl<G>) -> Option<Vec<i64>> {
320        let group = &self.parent;
321        let ZZ_to_ZZbig = ZZbig.can_hom(&ZZ).unwrap();
322        
323        let n = self.generators.len();
324        if n == 0 {
325            return if group.is_identity(target) { Some(Vec::new()) } else { None };
326        } else if e == 0 {
327            debug_assert!(group.is_identity(target));
328            return Some((0..n).map(|_| 0).collect());
329        }
330
331        let p = self.order_factorization[p_idx].0;
332        debug_assert!(group.is_identity(&group.pow(target, &ZZbig.pow(ZZ_to_ZZbig.map(p), e))));
333
334        let power = ZZbig.checked_div(
335            &self.order_multiple, 
336            &ZZbig.pow(int_cast(p, ZZbig, ZZ), e)
337        ).unwrap();
338        let gens = self.generators.iter().map(|g| group.pow(g, &power)).collect::<Vec<_>>();
339
340        // here we use the power-of-`p` map and the fact that `G/H ~ pG` to compute the dlog in `G/H`
341        let G_mod_H_dlog = self.padic_dlog(
342            p_idx,
343            e - 1,
344            &group.pow(target, &ZZ_to_ZZbig.map(p))
345        )?;
346        debug_assert!(group.eq_el(
347            &group.pow(target, &ZZ_to_ZZbig.map(p)),
348            &(0..n).fold(group.identity(), |current, i| group.op(current, group.pow(&gens[i], &ZZ_to_ZZbig.map(p * G_mod_H_dlog[i]))))
349        ));
350
351        // delta is now in H, i.e. is a p-torsion element
352        let delta = (0..n).fold(group.clone_el(target), |current, i|
353            group.op(current, group.pow(&gens[i], &ZZ_to_ZZbig.map(-G_mod_H_dlog[i])))
354        );
355        debug_assert!(group.is_identity(&group.pow(&delta, &ZZ_to_ZZbig.map(p))));
356
357        let H_generators = &self.scaled_generating_sets[p_idx][e - 1];
358
359        let H_dlog_wrt_H_gens = baby_giant_step(
360            group, 
361            delta, 
362            &H_generators, 
363            &(0..n).map(|_| int_cast(p, ZZbig, ZZ)).collect::<Vec<_>>()
364        )?;
365        let H_dlog = {
366            let mut result = (0..n).map(|_| 0).collect::<Vec<_>>();
367            STANDARD_MATMUL.matmul(
368                TransposableSubmatrix::from(Submatrix::from_1d(&H_dlog_wrt_H_gens, 1, n)),
369                TransposableSubmatrix::from(self.scaled_relation_lattices[p_idx][e - 1].data()),
370                TransposableSubmatrixMut::from(SubmatrixMut::from_1d(&mut result, 1, n)),
371                ZZ
372            );
373            result
374        };
375
376        let result = G_mod_H_dlog.into_iter().zip(H_dlog.into_iter()).map(|(x, y)| x + y).collect::<Vec<_>>();
377        debug_assert!(group.eq_el(
378            target,
379            &(0..n).fold(group.identity(), |current, i| group.op(current, group.pow(&gens[i], &ZZ_to_ZZbig.map(result[i]))))
380        ));
381
382        return Some(result);
383    }
384
385    ///
386    /// Returns `true` if the given element is contained in this subgroup.
387    /// 
388    #[stability::unstable(feature = "enable")]
389    pub fn contains(&self, element: &GroupEl<G>) -> bool {
390        self.dlog(element).is_some()
391    }
392
393    ///
394    /// Computes a discrete logarithm of `target` w.r.t. the stored set
395    /// if generators, or `None` if `target` is not in the subgroup generated by
396    /// these generators
397    /// 
398    #[stability::unstable(feature = "enable")]
399    pub fn dlog(&self, target: &GroupEl<G>) -> Option<Vec<i64>> {
400        let group = &self.parent;
401        let ZZ_to_ZZbig = ZZbig.can_hom(&ZZ).unwrap();
402        
403        let n = self.generators.len();
404        if n == 0 {
405            return if group.is_identity(target) { Some(Vec::new()) } else { None };
406        }
407
408        let mut current_dlog = (0..n).map(|_| 0).collect::<Vec<_>>();
409        let mut current_order = (0..n).map(|_| 1).collect::<Vec<_>>();
410
411        for p_idx in 0..self.order_factorization.len() {
412            let (p, e) = self.order_factorization[p_idx];
413            let power = ZZbig.checked_div(
414                &self.order_multiple, 
415                &ZZbig.pow(int_cast(p, ZZbig, ZZ), e)
416            ).unwrap();
417            let padic_dlog = self.padic_dlog(p_idx, e, &group.pow(target, &power))?;
418            for j in 0..n {
419                current_dlog[j] = inv_crt(current_dlog[j], padic_dlog[j], &current_order[j], &ZZ.pow(p, e), ZZ);
420                current_order[j] *= ZZ.pow(p, e);
421            }
422        }
423        debug_assert!(group.eq_el(
424            target,
425            &(0..n).fold(group.identity(), |current, i| group.op(current, group.pow(&self.generators[i], &ZZ_to_ZZbig.map(current_dlog[i]))))
426        ));
427
428        return Some(current_dlog);
429    }
430
431    fn padic_rectangular_form<'a>(&'a self, p_idx: usize) -> Vec<(GroupEl<G>, usize)> {
432        let group = &self.parent;
433        let (p, e) = self.order_factorization[p_idx];
434        let power = ZZbig.checked_div(
435            &self.order_multiple, 
436            &ZZbig.pow(int_cast(p, ZZbig, ZZ), e)
437        ).unwrap();
438        let n = self.generators.len();
439
440        if n == 0 {
441            return Vec::new();
442        }
443
444        let Zpne = zn_big::Zn::new(ZZbig, ZZbig.pow(int_cast(p, ZZbig, StaticRing::<i64>::RING), e * n));
445        let mod_pne = Zpne.can_hom(&StaticRing::<i64>::RING).unwrap();
446        let relation_lattice = self.scaled_relation_lattices[p_idx][e].data();
447        let mut relation_lattice_mod_pne = OwnedMatrix::from_fn(relation_lattice.row_count(), relation_lattice.col_count(), |k, l| mod_pne.map(*relation_lattice.at(k, l)));
448        let mut generators = self.generators.iter().map(|g| group.pow(g, &power)).collect::<Vec<_>>();
449     
450        struct TransformGenerators<'a, G: AbelianGroupStore> {
451            group: &'a G,
452            generators: &'a mut [GroupEl<G>]
453        }
454        impl<'a, G: AbelianGroupStore> TransformTarget<zn_big::ZnBase<BigIntRing>> for TransformGenerators<'a, G> {
455         fn transform<S: Copy + RingStore<Type = zn_big::ZnBase<BigIntRing>>>(&mut self, ring: S, i: usize, j: usize, transform: &[El<zn_big::Zn<BigIntRing>>; 4]) {
456                let transform_inv_det = ring.invert(&ring.sub(
457                    ring.mul_ref(&transform[0], &transform[3]),
458                    ring.mul_ref(&transform[1], &transform[2])
459                )).unwrap();
460                let inv_transform = [
461                    ring.smallest_positive_lift(ring.mul_ref(&transform[3], &transform_inv_det)),
462                    ring.smallest_positive_lift(ring.negate(ring.mul_ref(&transform[1], &transform_inv_det))),
463                    ring.smallest_positive_lift(ring.negate(ring.mul_ref(&transform[2], &transform_inv_det))),
464                    ring.smallest_positive_lift(ring.mul_ref(&transform[0], &transform_inv_det))
465                ];
466                let new_gens = (
467                    self.group.op(self.group.pow(&self.generators[i], &inv_transform[0]), self.group.pow(&self.generators[j], &inv_transform[1])),
468                    self.group.op(self.group.pow(&self.generators[i], &inv_transform[2]), self.group.pow(&self.generators[j], &inv_transform[3])),
469                );
470                self.generators[i] = new_gens.0;
471                self.generators[j] = new_gens.1;
472            }
473        }
474     
475        pre_smith(
476            &Zpne,
477            &mut (),
478            &mut TransformGenerators { group: group, generators: &mut generators },
479            relation_lattice_mod_pne.data_mut()
480        );
481     
482        return generators.into_iter().enumerate().map(|(i, g)| (
483            g,
484            int_cast(ZZbig.ideal_gen(Zpne.modulus(), &Zpne.smallest_positive_lift(Zpne.clone_el(relation_lattice_mod_pne.at(i, i)))), ZZ, ZZbig) as usize
485        )).collect()
486    }
487
488    ///
489    /// Returns a list (g[i], l[i]) such that every element of the subgroup
490    /// can be uniquely written as `prod_i g[i]^k[i]` with `0 <= k[i] < l[i]`.
491    /// 
492    #[stability::unstable(feature = "enable")]
493    pub fn rectangular_form<'a>(&'a self) -> Vec<(GroupEl<G>, usize)> {
494        (0..self.order_factorization.len()).flat_map(|p_idx| self.padic_rectangular_form(p_idx)).collect()
495    }
496
497    ///
498    /// Returns an iterator that yields every element contained in the subgroup
499    /// exactly once.
500    /// 
501    #[stability::unstable(feature = "enable")]
502    pub fn enumerate_elements<'a>(&'a self) -> impl use<'a, G> + Clone + Iterator<Item = GroupEl<G>> {
503        let rectangular_form = Rc::new(self.rectangular_form());
504        multi_cartesian_product(
505            rectangular_form.iter().map(|(_, l)| 0..*l).collect::<Vec<_>>().into_iter(),
506            move |pows| pows.iter().enumerate().fold(self.parent().identity(), |current, (i, e)| 
507                self.parent().op(current, self.parent().pow(&rectangular_form[i].0, &int_cast(*e as i64, ZZbig, ZZ)))
508            ),
509            |_, x| *x
510        )
511    }
512
513    ///
514    /// Takes a matrix whose rows form a basis of the relation lattice w.r.t. group
515    /// elements `g1, ..., gn` and computes a matrix whose rows form a basis of the relation
516    /// lattice of `p g1, ..., p gn`.
517    /// 
518    fn relation_lattice_basis_downscale_p<V>(basis: Submatrix<V, i64>, p: i64) -> OwnedMatrix<i64>
519        where V: AsPointerToSlice<i64>
520    {
521        let n = basis.row_count();
522        assert_eq!(n, basis.col_count());
523
524        let QQ = RationalField::new(ZZbig);
525        let ZZ_to_QQ = QQ.inclusion().compose(QQ.base_ring().can_hom(&ZZ).unwrap());
526        let as_ZZ = |x| int_cast(ZZbig.checked_div(QQ.num(x), QQ.den(x)).unwrap(), ZZ, ZZbig);
527
528        let mut dual_basis = OwnedMatrix::identity(n, 2 * n, &QQ);
529        let mut Binv = dual_basis.data_mut().submatrix(0..n, n..(2 * n));
530        let mut rhs = OwnedMatrix::identity(n, n, &QQ);
531        QQ.solve_right(
532            OwnedMatrix::from_fn(n, n, |i, j| ZZ_to_QQ.map_ref(basis.at(i, j))).data_mut(), 
533            rhs.data_mut(),
534            Binv.reborrow()
535        ).assert_solved();
536        Binv.reborrow().row_iter().flat_map(|row| row.iter_mut()).for_each(|x| ZZ_to_QQ.mul_assign_map(x, p));
537
538        let mut identity = OwnedMatrix::identity(n, n, &QQ);
539        lll(
540            &QQ, 
541            identity.data(), 
542            dual_basis.data_mut(), 
543            &QQ.div(&ZZ_to_QQ.map(9), &ZZ_to_QQ.map(10)),
544            Global, 
545            false
546        );
547
548        let mut result_QQ = rhs;
549        QQ.solve_right(
550            dual_basis.data_mut().submatrix(0..n, n..(2 * n)),
551            identity.data_mut(),
552            result_QQ.data_mut()
553        ).assert_solved();
554
555        let result = OwnedMatrix::from_fn(n, n, |i, j| as_ZZ(result_QQ.at(i, j)));
556
557        return result;
558    }
559}
560
561impl<G: AbelianGroupStore> PartialEq for SubgroupBase<G> {
562
563    fn eq(&self, other: &Self) -> bool {
564        self.parent().get_group() == other.parent().get_group() &&
565            other.generators().iter().all(|g| self.contains(g)) &&
566            self.generators().iter().all(|g| other.contains(g))
567    }
568}
569
570impl<G: AbelianGroupStore> AbelianGroupBase for SubgroupBase<G> {
571
572    type Element = GroupEl<G>;
573
574    fn clone_el(&self, x: &Self::Element) -> Self::Element {
575        self.parent().clone_el(x)
576    }
577
578    fn eq_el(&self, lhs: &Self::Element, rhs: &Self::Element) -> bool {
579        self.parent().eq_el(lhs, rhs)
580    }
581
582    fn hash<H: std::hash::Hasher>(&self, x: &Self::Element, hasher: &mut H) {
583        self.parent().hash(x, hasher)
584    }
585    
586    fn identity(&self) -> Self::Element {
587        self.parent().identity()
588    }
589
590    fn inv(&self, x: &Self::Element) -> Self::Element {
591        self.parent().inv(x)
592    }
593
594    fn is_identity(&self, x: &Self::Element) -> bool {
595        self.parent().is_identity(x)
596    }
597
598    fn op(&self, lhs: Self::Element, rhs: Self::Element) -> Self::Element {
599        self.parent().op(lhs, rhs)
600    }
601
602    fn pow(&self, x: &Self::Element, e: &El<BigIntRing>) -> Self::Element {
603        self.parent().pow(x, e)
604    }
605
606    fn op_ref(&self, lhs: &Self::Element, rhs: &Self::Element) -> Self::Element {
607        self.parent().op_ref(lhs, rhs)
608    }
609
610    fn op_ref_snd(&self, lhs:Self::Element, rhs: &Self::Element) -> Self::Element {
611        self.parent().op_ref_snd(lhs, rhs)
612    }
613}
614
615impl<G: AbelianGroupStore + Serialize> Serialize for SubgroupBase<G>
616    where G::Type: SerializableElementGroup
617{
618    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
619        where S: serde::Serializer
620    {
621        #[derive(Serialize)]
622        struct SubgroupData<'a, Gens: Serialize> {
623            order_multiple: SerializeWithRing<'a, BigIntRing>,
624            generators: Gens,
625            group: ()
626        }
627        SerializableNewtypeStruct::new("Subgroup", (self.parent(), SubgroupData {
628            order_multiple: SerializeWithRing::new(&self.order_multiple, ZZbig), 
629            generators: SerializableSeq::new(self.generators.iter().map(|g| SerializeWithGroup::new(g, self.parent()))),
630            group: ()
631        })).serialize(serializer)
632    }
633}
634
635impl<'de, G: AbelianGroupStore + Clone + Deserialize<'de>> Deserialize<'de> for SubgroupBase<G>
636    where G::Type: SerializableElementGroup
637{
638    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
639        where  D: serde::Deserializer<'de>
640    {
641        use serde::de::DeserializeSeed;
642
643        struct DeserializeSeedSubgroupData<G: AbelianGroupStore>
644            where G::Type: SerializableElementGroup
645        {
646            group: G
647        }
648
649        impl_deserialize_seed_for_dependent_struct!{
650            <{ 'de, G }> pub struct SubgroupData<{'de, G}> using DeserializeSeedSubgroupData<G> {
651                order_multiple: El<BigIntRing>: |_| DeserializeWithRing::new(ZZbig),
652                generators: Vec<GroupEl<G>>: |master: &DeserializeSeedSubgroupData<G>| {
653                    let group_clone = master.group.clone();
654                    DeserializeSeedSeq::new((0..).map(move |_| DeserializeWithGroup::new(group_clone.clone())), Vec::new(), |mut current, next| { current.push(next); current })
655                },
656                group: G: |master: &DeserializeSeedSubgroupData<G>| {
657                    let group_clone = master.group.clone();
658                    DeserializeSeedMapped::new(PhantomData::<()>, move |()| group_clone)
659                }
660            } where G: AbelianGroupStore + Clone, G::Type: SerializableElementGroup
661        }
662
663        DeserializeSeedNewtypeStruct::new("Subgroup", DeserializeSeedDependentTuple::new(
664            PhantomData::<G>,
665            |group| DeserializeSeedSubgroupData { group }
666        )).deserialize(deserializer).map(|data| Subgroup::new(data.group, data.order_multiple, data.generators).into())
667    }
668}
669
670impl<G: AbelianGroupStore> Clone for SubgroupBase<G>
671    where G: Clone
672{
673    fn clone(&self) -> Self {
674        Self {
675            parent: self.parent.clone(),
676            generators: self.generators.iter().map(|g| self.parent.clone_el(g)).collect(),
677            order_factorization: self.order_factorization.clone(),
678            order_multiple: self.order_multiple.clone(),
679            scaled_generating_sets: self.scaled_generating_sets.iter().map(|sets| sets.iter().map(|set| set.iter().map(|g| self.parent.clone_el(g)).collect()).collect()).collect(),
680            scaled_relation_lattices: self.scaled_relation_lattices.iter().map(|x| x.iter().map(|x| x.clone_matrix(StaticRing::<i64>::RING)).collect()).collect()
681        }
682    }
683}
684
685impl<R> Subgroup<MultGroup<R>>
686    where R: RingStore,
687        R::Type: ZnRing + HashableElRing + DivisibilityRing
688{
689    #[stability::unstable(feature = "enable")]
690    pub fn for_zn(group: MultGroup<R>, generators: Vec<GroupEl<MultGroup<R>>>) -> Self {
691        let n = generators.len();
692        if n == 0 {
693            let n_factorization = factor(ZZbig, group.underlying_ring().size(ZZbig).unwrap());
694            let mut order_factorization = n_factorization.into_iter().flat_map(|(p, e)| 
695                factor(ZZbig, ZZbig.sub_ref_fst(&p, ZZbig.one())).into_iter().chain([(p, e - 1)].into_iter())
696            ).collect::<Vec<_>>();
697            order_factorization.sort_unstable_by(|(pl, _), (pr, _)| ZZbig.cmp(pl, pr));
698            order_factorization.dedup_by(|(p1, e1), (p2, e2)| if ZZbig.eq_el(p1, p2) {
699                *e2 += *e1;
700                true
701            } else {
702                false
703            });
704            order_factorization.retain(|(_, e)| *e > 0);
705            let order = ZZbig.prod(order_factorization.iter().map(|(p, e)| ZZbig.pow(ZZbig.clone_el(p), *e)));
706            let order_factorization = order_factorization.into_iter().map(|(p, e)| (int_cast(p, ZZ, ZZbig), e)).collect();
707            return Self::from(SubgroupBase {
708                parent: group,
709                generators: Vec::new(),
710                order_multiple: order,
711                order_factorization: order_factorization,
712                scaled_generating_sets: Vec::new(),
713                scaled_relation_lattices: Vec::new()
714            });
715        } else {
716            let mut result = Self::for_zn(group, Vec::new());
717            for g in generators {
718                result = result.add_generator(g);
719            }
720            return result;
721        }
722    }
723}
724
725///
726/// Computes the a vector `k` with entries `1 <= k[i] <= dlog_bounds[i]` such that
727/// `generators^k = value` (`generators` is a list of elements of an abelian group).
728/// 
729/// If there is no such vector, then `None` is returned. If there are multiple such
730/// vectors, any one of them is returned. In the 1d-case, it is guaranteed that this
731/// is the smallest one, but in the multidimensional case, no such guarantee can be made
732/// (in particular, the vector in general won't be the shortest one w.r.t. any natural
733/// ordering like lex or degrevlex).
734/// 
735/// Note: The vector `k` is required to have positive entries. In particular, this
736/// function won't return the zero vector if the given element is the identity.
737/// This can have unexpected consequences, like
738/// ```
739/// # use feanor_math::algorithms::discrete_log::*;
740/// # use feanor_math::integer::*;
741/// # use feanor_math::group::*;
742/// # use feanor_math::primitive_int::*;
743/// let group = AddGroup::new(StaticRing::<i64>::RING);
744/// assert_eq!(Some(vec![1]), baby_giant_step(&group, 0, &[0], &[BigIntRing::RING.power_of_two(10)]));
745/// ```
746/// 
747/// # Implementation notes
748/// 
749/// The complexity of the algorithm is `O(sqrt(prod_i dlog_bounds[i]))`. 
750/// Thus, when possible, `order_bound[i]` should be the order of `generators[i]`
751/// in the group.
752/// 
753/// Why do we need a group? Because we search for collisions `ab = ac`, and assume
754/// that this implies `b = c`. So actually,  a cancelable abelian monoid would be sufficient...
755/// 
756/// Why don't we use Pollard's rhos? Because Pollard's rho cannot deterministically
757/// detect the case that `value` is not in the subgroup generated by `generators`.
758/// It can do so with high probability, but only if the used hash function satisfies
759/// certain properties. With BSGS, the correctness does not depend on the used hash
760/// function (although performance does, of course).
761/// 
762/// # Example
763/// 
764/// ```rust
765/// # use feanor_math::ring::*;
766/// # use feanor_math::group::*;
767/// # use feanor_math::homomorphism::*;
768/// # use feanor_math::rings::zn::*;
769/// # use feanor_math::integer::*;
770/// # use feanor_math::primitive_int::StaticRing;
771/// # use feanor_math::rings::zn::zn_64::*;
772/// # use feanor_math::wrapper::*;
773/// # use feanor_math::algorithms::discrete_log::*;
774/// let ring = Zn::new(17);
775/// let group = MultGroup::new(ring);
776/// let x = group.from_ring_el(ring.int_hom().map(9)).unwrap();
777/// assert_eq!(Some(vec![3]), baby_giant_step(&group, group.pow(&x, &int_cast(3, BigIntRing::RING, StaticRing::<i64>::RING)), &[x], &[BigIntRing::RING.power_of_two(4)]));
778/// ```
779/// 
780#[stability::unstable(feature = "enable")]
781pub fn baby_giant_step<G>(group: G, value: GroupEl<G>, generators: &[GroupEl<G>], dlog_bounds: &[El<BigIntRing>]) -> Option<Vec<i64>> 
782    where G: AbelianGroupStore
783{
784    let n = generators.len();
785    assert_eq!(n, dlog_bounds.len());
786    if generators.len() == 0 {
787        if group.is_identity(&value) {
788            return Some(Vec::new());
789        } else {
790            return None;
791        }
792    }
793    let ns = dlog_bounds.iter().map(|n| int_cast(root_floor(ZZbig, n.clone(), 2), ZZ, ZZbig) + 1).collect::<Vec<_>>();
794    let count = int_cast(ZZbig.prod(ns.iter().map(|n| int_cast(*n, ZZbig, ZZ))), ZZ, ZZbig);
795    let mut baby_step_table: HashMap<HashableGroupEl<_>, i64> = HashMap::with_capacity(count as usize);
796    
797    // fill baby step table
798    {
799        let mut current_els = (0..n).map(|_| group.clone_el(&value)).collect::<Vec<_>>();
800        let mut current_idxs = (0..n).map(|_| 0).collect::<Vec<_>>();
801        for idx in 0..count {
802            _ = baby_step_table.insert(HashableGroupEl::new(&group, group.clone_el(&current_els[n - 1])), idx);
803
804            let mut i = n - 1;
805            while current_idxs[i] == ns[i] - 1 {
806                if i == 0 {
807                    assert!(idx + 1 == count);
808                    break;
809                }
810                current_idxs[i] = 0;
811                i -= 1;
812            }
813            current_idxs[i] += 1;
814            current_els[i] = group.op_ref_snd(replace(&mut current_els[i], group.identity()), &generators[i]);
815            for j in (i + 1)..n {
816                current_els[j] = group.clone_el(&current_els[i]);
817            }
818        }
819    }
820
821    let giant_steps = generators.iter().zip(ns.iter()).map(|(g, n)| group.pow(g, &int_cast(*n, ZZbig, ZZ))).collect::<Vec<_>>();
822    // iterate through giant steps
823    {
824        let start_el = giant_steps.iter().fold(group.identity(), |x, y| group.op_ref_snd(x, y));
825        let mut current_els = (0..n).map(|_| group.clone_el(&start_el)).collect::<Vec<_>>();
826        let mut current_idxs = (0..n).map(|_| 1).collect::<Vec<_>>();
827        for idx in 0..count {
828            if let Some(bs_idx) = baby_step_table.get(&HashableGroupEl::new(&group, group.clone_el(&current_els[n - 1]))) {
829                let mut bs_idx = *bs_idx;
830                let mut result = current_idxs.clone();
831                for j in (0..n).rev() {
832                    let bs_idxs_j = bs_idx % ns[j];
833                    bs_idx = bs_idx / ns[j];
834                    result[j] = result[j] * ns[j] - bs_idxs_j;
835                }
836                if (0..dlog_bounds.len()).all(|j| ZZbig.is_leq(&int_cast(result[j], ZZbig, ZZ), &dlog_bounds[j])) {
837                    debug_assert_eq!(n, result.len());
838                    return Some(result);
839                }
840            }
841
842            let mut i = n - 1;
843            while current_idxs[i] == ns[i] {
844                if i == 0 {
845                    assert!(idx + 1 == count);
846                    break;
847                }
848                current_idxs[i] = 1;
849                i -= 1;
850            }
851            current_idxs[i] += 1;
852            current_els[i] = group.op_ref_snd(replace(&mut current_els[i], group.identity()), &giant_steps[i]);
853            for j in (i + 1)..n {
854                current_els[j] = group.clone_el(&current_els[i]);
855            }
856        }
857    }
858
859    return None;
860}
861
862///
863/// Computes the discrete log in the group `(Z/nZ)*`.
864/// 
865/// This only called `finite_field_discrete_log` for backwards compatibility,
866/// it now completely supports `(Z/nZ)*` for any `n`.
867/// 
868pub fn finite_field_discrete_log<R: RingStore>(value: El<R>, base: El<R>, Zn: R) -> Option<i64>
869    where R::Type: ZnRing + HashableElRing
870{
871    let group = MultGroup::new(Zn);
872    let generators = vec![group.from_ring_el(base).unwrap()];
873    let subgroup = Subgroup::for_zn(group, generators);
874    return subgroup.dlog(&subgroup.parent().from_ring_el(value).unwrap())
875        .map(|res| res[0]);
876}
877
878///
879/// Computes the multiplicative order in the group `(Z/nZ)*`.
880/// 
881pub fn multiplicative_order<R: RingStore>(x: El<R>, Zn: R) -> i64
882    where R::Type: ZnRing + HashableElRing
883{
884    let group = MultGroup::new(Zn);
885    let gen_set = Subgroup::for_zn(group, Vec::new());
886    let Zn = gen_set.parent().underlying_ring();
887
888    let mut result = ZZbig.one();
889    for (p, e) in &gen_set.get_group().order_factorization {
890        let mut current = Zn.pow_gen(
891            Zn.clone_el(&x), 
892            &ZZbig.checked_div(&gen_set.get_group().order_multiple, &ZZbig.pow(int_cast(*p, ZZbig, ZZ), *e)).unwrap(), 
893            ZZbig
894        );
895        while !Zn.is_one(&current) {
896            current = Zn.pow(current, *p as usize);
897            ZZbig.mul_assign(&mut result, int_cast(*p, ZZbig, ZZ));
898        }
899    }
900    return int_cast(result, ZZ, ZZbig);
901}
902
903#[cfg(test)]
904struct ProdGroupBase<G: AbelianGroupStore, const N: usize>(G);
905
906#[cfg(test)]
907impl<G: AbelianGroupStore, const N: usize> PartialEq for ProdGroupBase<G, N> {
908    fn eq(&self, other: &Self) -> bool {
909        self.0.get_group() == other.0.get_group()
910    }
911}
912
913#[cfg(test)]
914impl<G: AbelianGroupStore, const N: usize> AbelianGroupBase for ProdGroupBase<G, N> {
915    type Element = [GroupEl<G>; N];
916
917    fn clone_el(&self, x: &Self::Element) -> Self::Element {
918        from_fn(|i| self.0.clone_el(&x[i]))
919    }
920
921    fn eq_el(&self, lhs: &Self::Element, rhs: &Self::Element) -> bool {
922        (0..N).all(|i| self.0.eq_el(&lhs[i], &rhs[i]))
923    }
924
925    fn op(&self, lhs: Self::Element, rhs: Self::Element) -> Self::Element {
926        from_fn(|i| self.0.op_ref(&lhs[i], &rhs[i]))
927    }
928    
929    fn hash<H: std::hash::Hasher>(&self, x: &Self::Element, hasher: &mut H) {
930        for i in 0..N {
931            self.0.hash(&x[i], hasher)
932        }
933    }
934
935    fn inv(&self, x: &Self::Element) -> Self::Element {
936        from_fn(|i| self.0.inv(&x[i]))
937    }
938
939    fn identity(&self) -> Self::Element {
940        from_fn(|_| self.0.identity())
941    }
942}
943
944#[cfg(test)]
945use crate::rings::zn::zn_static::Zn;
946#[cfg(test)]
947use oorandom::Rand64;
948#[cfg(test)]
949use crate::algorithms::matmul::ComputeInnerProduct;
950#[cfg(test)]
951use crate::group::AddGroup;
952#[cfg(test)]
953use crate::assert_matrix_eq;
954#[cfg(test)]
955use crate::RANDOM_TEST_INSTANCE_COUNT;
956#[cfg(test)]
957use std::array::from_fn;
958
959#[test]
960fn test_baby_giant_step() {
961    for base_bound in [21, 26, 31, 37] {
962        let dlog_bound = [int_cast(base_bound, ZZbig, ZZ)];
963        let G = AddGroup::new(ZZ);
964        assert_eq!(
965            Some(vec![6]), 
966            baby_giant_step(&G, 6, &[1], &dlog_bound)
967        );
968        assert_eq!(
969            None, 
970            baby_giant_step(&G, 0, &[1], &dlog_bound)
971        );
972
973        let G = AddGroup::new(Zn::<20>::RING);
974        assert_eq!(
975            Some(vec![20]), 
976            baby_giant_step(&G, 0, &[1], &dlog_bound)
977        );
978        assert_eq!(
979            Some(vec![10]), 
980            baby_giant_step(&G, 10, &[1], &dlog_bound)
981        );
982        assert_eq!(
983            Some(vec![5]), 
984            baby_giant_step(&G, 0, &[16], &dlog_bound)
985        );
986    }
987    
988    let G = AddGroup::new(ZZ);
989
990    // the collision point is at 96
991    assert_eq!(
992        Some(vec![9 - 1, 6 - 1]), 
993        baby_giant_step(&G, 85, &[10, 1], &from_fn::<_, 2, _>(|_| int_cast(8, ZZbig, ZZ)))
994    );
995    // the collision point is at 105
996    assert_eq!(
997        Some(vec![10 - 2, 5 - 0]), 
998        baby_giant_step(&G, 85, &[10, 1], &from_fn::<_, 2, _>(|_| int_cast(21, ZZbig, ZZ)))
999    );
1000    // the collision point is at 90
1001    assert_eq!(
1002        Some(vec![6 - 0, 30 - 5]), 
1003        baby_giant_step(&G, 85, &[10, 1], &from_fn::<_, 2, _>(|_| int_cast(31, ZZbig, ZZ)))
1004    );
1005}
1006
1007
1008#[test]
1009fn test_padic_relation_lattice() {
1010    let G = AddGroup::new(Zn::<81>::RING);
1011
1012    let subgroup = Subgroup::new(&G, int_cast(81, ZZbig, ZZ), vec![1]);
1013    assert_matrix_eq!(ZZ, [[-81]], subgroup.get_group().scaled_relation_lattices[0][4]);
1014    assert_matrix_eq!(ZZ, [[-27]], subgroup.get_group().scaled_relation_lattices[0][3]);
1015    assert_matrix_eq!(ZZ, [[-9]], subgroup.get_group().scaled_relation_lattices[0][2]);
1016    assert_matrix_eq!(ZZ, [[-3]], subgroup.get_group().scaled_relation_lattices[0][1]);
1017    assert_matrix_eq!(ZZ, [[1]], subgroup.get_group().scaled_relation_lattices[0][0]);
1018
1019    let subgroup = Subgroup::new(&G, int_cast(81, ZZbig, ZZ), vec![3, 6]);
1020    let matrix = &subgroup.get_group().scaled_relation_lattices[0][4];
1021    assert_eq!(-27, *matrix.at(0, 0));
1022    assert_eq!(-1, *matrix.at(1, 1));
1023    assert_eq!(0, ZZ.get_ring().inner_product_ref(matrix.data().row_at(1).iter().zip([3, 6].iter())) % 81);
1024
1025    let subgroup = Subgroup::new(&G, int_cast(81, ZZbig, ZZ), vec![3, 9]);
1026    let matrix = &subgroup.get_group().scaled_relation_lattices[0][4];
1027    assert_eq!(-27, *matrix.at(0, 0));
1028    assert_eq!(-1, *matrix.at(1, 1));
1029    assert_eq!(0, ZZ.get_ring().inner_product_ref(matrix.data().row_at(1).iter().zip([3, 9].iter())) % 81);
1030
1031    let subgroup = Subgroup::new(&G, int_cast(81, ZZbig, ZZ), vec![6, 18, 9]);
1032    let matrix = &subgroup.get_group().scaled_relation_lattices[0][4];
1033    assert_eq!(-27, *matrix.at(0, 0));
1034    assert_eq!(-1, *matrix.at(1, 1));
1035    assert_eq!(-1, *matrix.at(2, 2));
1036    assert_eq!(0, ZZ.get_ring().inner_product_ref(matrix.data().row_at(1).iter().zip([6, 18, 9].iter())) % 81);
1037    assert_eq!(0, ZZ.get_ring().inner_product_ref(matrix.data().row_at(2).iter().zip([6, 18, 9].iter())) % 81);
1038
1039    let G = GroupValue::from(ProdGroupBase(AddGroup::new(Zn::<81>::RING)));
1040
1041    let subgroup = Subgroup::new(&G, int_cast(81, ZZbig, ZZ), vec![[1, 4], [1, 1]]);
1042    let matrix = &subgroup.get_group().scaled_relation_lattices[0][4];
1043    assert_eq!(-81, *matrix.at(0, 0));
1044    assert_eq!(-27, *matrix.at(1, 1));
1045    assert_eq!(0, ZZ.get_ring().inner_product_ref(matrix.data().row_at(1).iter().zip([1, 1].iter())) % 81);
1046    assert_eq!(0, ZZ.get_ring().inner_product_ref(matrix.data().row_at(1).iter().zip([4, 1].iter())) % 81);
1047
1048    let G = GroupValue::from(ProdGroupBase(AddGroup::new(Zn::<8>::RING)));
1049
1050    let subgroup = Subgroup::new(&G, int_cast(8, ZZbig, ZZ), vec![[6, 3, 5], [6, 2, 6], [4, 5, 7]]);
1051    let matrix = &subgroup.get_group().scaled_relation_lattices[0][3];
1052    assert_eq!(-8, *matrix.at(0, 0));
1053    assert_eq!(-4, *matrix.at(1, 1));
1054    assert_eq!(-2, *matrix.at(2, 2));
1055    assert_eq!(0, ZZ.get_ring().inner_product_ref(matrix.data().row_at(1).iter().zip([6, 6, 4].iter())) % 8);
1056    assert_eq!(0, ZZ.get_ring().inner_product_ref(matrix.data().row_at(1).iter().zip([3, 2, 5].iter())) % 8);
1057    assert_eq!(0, ZZ.get_ring().inner_product_ref(matrix.data().row_at(1).iter().zip([5, 6, 7].iter())) % 8);
1058    assert_eq!(0, ZZ.get_ring().inner_product_ref(matrix.data().row_at(2).iter().zip([6, 6, 4].iter())) % 8);
1059    assert_eq!(0, ZZ.get_ring().inner_product_ref(matrix.data().row_at(2).iter().zip([3, 2, 5].iter())) % 8);
1060    assert_eq!(0, ZZ.get_ring().inner_product_ref(matrix.data().row_at(2).iter().zip([5, 6, 7].iter())) % 8);
1061}
1062
1063#[test]
1064fn random_test_dlog() {
1065    let ring = Zn::<1400>::RING;
1066    let i = ring.can_hom(&ZZ).unwrap();
1067    let mut rng = Rand64::new(0);
1068    let G = GroupValue::from(ProdGroupBase(AddGroup::new(ring)));
1069    let rand_gs = |rng: &mut Rand64| from_fn::<_, 3, _>(|_| ring.random_element(|| rng.rand_u64()));
1070
1071    for _ in 0..RANDOM_TEST_INSTANCE_COUNT {
1072        let gs = from_fn::<_, 3, _>(|_| rand_gs(&mut rng));
1073        let subgroup = Subgroup::new(&G, int_cast(1400, ZZbig, ZZ), gs.into());
1074
1075        let coeffs = rand_gs(&mut rng);
1076        let val = (0..3).fold(G.identity(), |current, i| G.op(current, G.pow(&gs[i], &int_cast(coeffs[i] as i64, ZZbig, ZZ))));
1077        let dlog = subgroup.dlog(&val);
1078        println!("{:?} * x + {:?} * y + {:?} * z = {:?} mod 1400", gs[0], gs[1], gs[2], val);
1079        if let Some(dlog) = dlog {
1080            for k in 0..3 {
1081                assert_el_eq!(ring, val[k], ring.sum([i.mul_map(gs[0][k], dlog[0]), i.mul_map(gs[1][k], dlog[1]), i.mul_map(gs[2][k], dlog[2])]));
1082            }
1083            println!("checked solution");
1084        }
1085    }
1086
1087    for _ in 0..RANDOM_TEST_INSTANCE_COUNT {
1088        let gs = from_fn::<_, 3, _>(|_| rand_gs(&mut rng));
1089        let subgroup = Subgroup::new(&G, int_cast(1400, ZZbig, ZZ), gs.into());
1090
1091        let val = rand_gs(&mut rng);
1092        let dlog = subgroup.dlog(&val);
1093        println!("{:?} * x + {:?} * y + {:?} * z = {:?} mod 1400", gs[0], gs[1], gs[2], val);
1094        if let Some(dlog) = dlog {
1095            for k in 0..3 {
1096                assert_el_eq!(ring, val[k], ring.sum([i.mul_map(gs[0][k], dlog[0]), i.mul_map(gs[1][k], dlog[1]), i.mul_map(gs[2][k], dlog[2])]));
1097            }
1098            println!("checked solution");
1099        } else {
1100            let mut gen_matrix = OwnedMatrix::from_fn(3, 3, |i, j| gs[j][i]);
1101            let mut value = OwnedMatrix::from_fn(3, 1, |i, _| val[i]);
1102            let mut res = OwnedMatrix::zero(3, 1, ring);
1103            let solved = ring.solve_right(gen_matrix.data_mut(), value.data_mut(), res.data_mut());
1104            println!("[{}, {}, {}]", res.at(0, 0), res.at(1, 0), res.at(2, 0));
1105            if solved.is_solved() {
1106                for k in 0..3 {
1107                    assert_el_eq!(ring, val[k], ring.sum([ring.mul(gs[0][k], *res.at(0, 0)), ring.mul(gs[1][k], *res.at(1, 0)), ring.mul(gs[2][k], *res.at(2, 0))]));
1108                }
1109                assert!(solved == crate::algorithms::linsolve::SolveResult::NoSolution);
1110            }
1111            println!("has no solution");
1112        }
1113    }
1114}
1115
1116#[test]
1117fn test_zn_dlog() {
1118    let ring = Zn::<51>::RING;
1119    let g1 = ring.int_hom().map(37);
1120    let g2 = ring.int_hom().map(35);
1121
1122    assert_eq!(0, finite_field_discrete_log(ring.one(), g1, ring).unwrap() % 16);
1123    assert_eq!(0, finite_field_discrete_log(ring.one(), g2, ring).unwrap() % 2);
1124    assert_eq!(1, finite_field_discrete_log(g2, g2, ring).unwrap() % 2);
1125    for i in 0..16 {
1126        assert_eq!(i, finite_field_discrete_log(ring.pow(g1, i as usize), g1, ring).unwrap() % 16);
1127    }
1128    for i in 0..16 {
1129        assert_eq!(None, finite_field_discrete_log(ring.mul(ring.pow(g1, i as usize), g2), g1, ring));
1130    }
1131
1132    assert_eq!(16, multiplicative_order(g1, ring));
1133    assert_eq!(8, multiplicative_order(ring.pow(g1, 2), ring));
1134    assert_eq!(4, multiplicative_order(ring.pow(g1, 4), ring));
1135    assert_eq!(2, multiplicative_order(ring.pow(g1, 8), ring));
1136    assert_eq!(2, multiplicative_order(g2, ring));
1137}
1138
1139#[test]
1140fn test_zn_subgroup_size() {
1141    let ring = Zn::<153>::RING;
1142    let group = MultGroup::new(ring);
1143    let g1 = group.from_ring_el(ring.int_hom().map(2)).unwrap();
1144    let g2 = group.from_ring_el(ring.int_hom().map(37)).unwrap();
1145
1146    let mut subgroup = Subgroup::for_zn(group.clone(), Vec::new());
1147    assert_el_eq!(ZZbig, ZZbig.int_hom().map(1), subgroup.subgroup_order());
1148
1149    let next_gen = subgroup.parent().clone_el(&g1);
1150    subgroup = subgroup.add_generator(next_gen);
1151    assert_el_eq!(ZZbig, ZZbig.int_hom().map(24), subgroup.subgroup_order());
1152    
1153    let next_gen = subgroup.parent().pow(&g1, &ZZbig.int_hom().map(2));
1154    subgroup = subgroup.add_generator(next_gen);
1155    assert_el_eq!(ZZbig, ZZbig.int_hom().map(24), subgroup.subgroup_order());
1156    
1157    let next_gen = subgroup.parent().clone_el(&g2);
1158    subgroup = subgroup.add_generator(next_gen);
1159    assert_el_eq!(ZZbig, ZZbig.int_hom().map(96), subgroup.subgroup_order());
1160    
1161    let generating_set = Subgroup::for_zn(group, vec![g2]);
1162    assert_el_eq!(ZZbig, ZZbig.int_hom().map(16), generating_set.subgroup_order());
1163
1164}
1165
1166#[test]
1167fn test_enumerate_elements() {
1168    let ring = Zn::<45>::RING;
1169    let group = AddGroup::new(ring);
1170
1171    assert_eq!(vec![ring.zero()], Subgroup::new(group.clone(), int_cast(45, ZZbig, ZZ), Vec::new()).enumerate_elements().collect::<Vec<_>>());
1172
1173    let subgroup = Subgroup::new(group, int_cast(45, ZZbig, ZZ), vec![9, 15]);
1174    let mut elements = subgroup.enumerate_elements().collect::<Vec<_>>();
1175    elements.sort_unstable();
1176    assert_eq!((0..45).step_by(3).collect::<Vec<_>>(), elements);
1177}