chinese_factorization_method.pl 1.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. #!/usr/bin/perl
  2. # Daniel "Trizen" Șuteu
  3. # Date: 01 June 2022
  4. # https://github.com/trizen
  5. # Concept for an integer factorization method based on the Chinese Remainder Theorem (CRT).
  6. # Example:
  7. # n = 43*97
  8. # We have:
  9. # n == 1 mod 2
  10. # n == 1 mod 3
  11. # n == 1 mod 5
  12. # n == 6 mod 7
  13. # n == 2 mod 11
  14. # 43 = chinese(Mod(1,2), Mod(1,3), Mod(3,5), Mod(1,7))
  15. # 97 = chinese(Mod(1,2), Mod(1,3), Mod(2,5), Mod(6,7))
  16. # For some small primes p, we try to find pairs of a and b, such that:
  17. # a*b == n mod p
  18. # Then using either the `a` or the `b` values, we can construct a factor of n, using the CRT.
  19. use 5.020;
  20. use strict;
  21. use warnings;
  22. use ntheory qw(:all);
  23. use experimental qw(signatures);
  24. use Math::GMPz;
  25. sub CRT_factor ($n) {
  26. return $n if is_prime($n);
  27. my $congruences = [0];
  28. my $LCM = 1;
  29. my $limit = vecmin(sqrtint($n), 1e6);
  30. for (my $p = 2 ; $p <= $limit ; $p = next_prime($p)) {
  31. my $r = modint($n, $p);
  32. if ($r == 0) {
  33. return $p;
  34. }
  35. my @new_congruences;
  36. foreach my $c (@$congruences) {
  37. foreach my $d (1 .. $p - 1) {
  38. my $t = [$d, $p];
  39. my $z = chinese([$c, $LCM], $t);
  40. my $g = gcd($z, $n);
  41. if ($g > 1 and $g < $n) {
  42. return $g;
  43. }
  44. push @new_congruences, $z;
  45. }
  46. }
  47. $LCM = lcm($LCM, $p);
  48. $congruences = \@new_congruences;
  49. }
  50. return 1;
  51. }
  52. say CRT_factor(43 * 97); #=> 97
  53. say CRT_factor(503 * 863); #=> 863
  54. say CRT_factor(Math::GMPz->new(2)**32 + 1); #=> 641
  55. say CRT_factor(Math::GMPz->new(2)**64 + 1); #=> 274177
  56. say CRT_factor(Math::GMPz->new("273511610089")); #=> 377827
  57. say CRT_factor(Math::GMPz->new("24259337155997")); #=> 5944711