pollard-strassen_factorization_method.pl 1.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758
  1. #!/usr/bin/perl
  2. # Pollard-Strassen O(n^(1/4)) factorization algorithm.
  3. # Illustrated by David Harvey in the following video:
  4. # https://yewtu.be/watch?v=_53s-0ZLxbQ
  5. use 5.020;
  6. use warnings;
  7. use bigint try => 'GMP';
  8. use experimental qw(signatures);
  9. use ntheory qw(random_prime rootint gcd);
  10. use Math::Polynomial;
  11. use Math::ModInt qw(mod);
  12. use Math::Polynomial::ModInt;
  13. sub pollard_strassen_factorization ($n, $d = 1 + rootint($n, 4), $tries = $d) {
  14. my $a = random_prime($n);
  15. my @baby_steps;
  16. my $bs = mod(1, $n);
  17. foreach my $k (1 .. $d) {
  18. push @baby_steps, $bs;
  19. $bs *= $a;
  20. }
  21. my $x = Math::Polynomial::ModInt->new(mod(0, $n), mod(1, $n));
  22. my @f = map { $x - $_ } @baby_steps;
  23. my $f = Math::Polynomial::ModInt->new(mod(1, $n));
  24. while (@f) {
  25. $f = $f->mul(shift(@f));
  26. }
  27. my $r = mod($a, $n);
  28. foreach my $k (1 .. $tries) {
  29. my $b = $r**($k * $d);
  30. my $v = $f->evaluate($b)->residue;
  31. my $g = gcd($v, $n);
  32. if ($g > 1 and $g < $n) {
  33. return $g;
  34. }
  35. }
  36. return 1;
  37. }
  38. say pollard_strassen_factorization(1207);
  39. say pollard_strassen_factorization(503 * 863);
  40. say pollard_strassen_factorization(2**64 + 1, 300, 5 * 300);