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#[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 scaled_relation_lattices: Vec<Vec<OwnedMatrix<i64>>>,
69 scaled_generating_sets: Vec<Vec<Vec<GroupEl<G>>>>
74}
75
76#[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 #[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 #[stability::unstable(feature = "enable")]
118 pub fn parent(&self) -> &G {
119 self.get_group().parent()
120 }
121
122 #[stability::unstable(feature = "enable")]
126 pub fn subgroup_order(&self) -> El<BigIntRing> {
127 self.get_group().subgroup_order()
128 }
129
130 #[stability::unstable(feature = "enable")]
134 pub fn generators(&self) -> &[GroupEl<G>] {
135 self.get_group().generators()
136 }
137
138 #[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 #[stability::unstable(feature = "enable")]
151 pub fn contains(&self, element: &GroupEl<G>) -> bool {
152 self.get_group().contains(element)
153 }
154
155 #[stability::unstable(feature = "enable")]
160 pub fn dlog(&self, target: &GroupEl<G>) -> Option<Vec<i64>> {
161 self.get_group().dlog(target)
162 }
163
164 #[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 #[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 #[stability::unstable(feature = "enable")]
210 pub fn order_multiple(&self) -> &El<BigIntRing> {
211 &self.order_multiple
212 }
213
214 #[stability::unstable(feature = "enable")]
218 pub fn generators(&self) -> &[GroupEl<G>] {
219 &self.generators
220 }
221
222 #[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 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 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 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 #[stability::unstable(feature = "enable")]
389 pub fn contains(&self, element: &GroupEl<G>) -> bool {
390 self.dlog(element).is_some()
391 }
392
393 #[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], ¤t_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 #[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 #[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 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#[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 {
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(¤t_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(¤t_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 {
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(¤t_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(¤t_els[i]);
855 }
856 }
857 }
858
859 return None;
860}
861
862pub 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
878pub 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(¤t) {
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 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 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 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}