solutions_to_x_squared_equals_a_mod_n.pl 2.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. #!/usr/bin/perl
  2. # Daniel "Trizen" Șuteu
  3. # Date: 27 October 2017
  4. # https://github.com/trizen
  5. # Find (almost) all the positive solutions to the quadratic congruence: x^2 = a (mod n), where `n` and `a` are known.
  6. # For finding all the solutions for the special case `a = 1`, see:
  7. # https://github.com/trizen/perl-scripts/blob/master/Math/solutions_to_x%5E2%20=%201%20(mod%20n).pl
  8. # For finding all the solutions to `x^2 = a (mod n)`, see:
  9. # https://github.com/trizen/sidef-scripts/blob/master/Math/square_root_modulo_n.sf
  10. # https://github.com/trizen/sidef-scripts/blob/master/Math/square_root_modulo_n_tonelli-shanks.sf
  11. # See also:
  12. # https://en.wikipedia.org/wiki/Quadratic_residue
  13. use 5.010;
  14. use strict;
  15. use warnings;
  16. use ntheory qw(sqrtmod factor_exp chinese mulmod forsetproduct);
  17. sub modular_square_root {
  18. my ($k, $n) = @_;
  19. my %table;
  20. foreach my $f (factor_exp($n)) {
  21. my $pp = $f->[0]**$f->[1];
  22. my $r = sqrtmod($k, $pp) || return;
  23. push @{$table{$pp}}, [$r, $pp], [$pp - $r, $pp];
  24. }
  25. my %solutions;
  26. forsetproduct {
  27. undef $solutions{chinese(@_)};
  28. } values %table;
  29. return sort { $a <=> $b } keys %solutions;
  30. }
  31. foreach my $n (2 .. 1000) {
  32. my $k = 1+int(rand($n));
  33. (my @solutions = modular_square_root($k, $n)) || next;
  34. say "x^2 = $k (mod $n); x = { ", join(', ', @solutions), ' }';
  35. # Verify solutions
  36. foreach my $solution (@solutions) {
  37. if (mulmod($solution, $solution, $n) != $k) {
  38. die "error for $n: $solution\n";
  39. }
  40. }
  41. }
  42. __END__
  43. x^2 = 81 (mod 863); x = { 9, 854 }
  44. x^2 = 459 (mod 865); x = { 247, 272, 593, 618 }
  45. x^2 = 535 (mod 873); x = { 70, 124, 749, 803 }
  46. x^2 = 685 (mod 877); x = { 135, 742 }
  47. x^2 = 388 (mod 879); x = { 55, 238, 641, 824 }
  48. x^2 = 441 (mod 883); x = { 21, 862 }
  49. x^2 = 813 (mod 886); x = { 195, 691 }
  50. x^2 = 83 (mod 887); x = { 227, 660 }
  51. x^2 = 757 (mod 898); x = { 245, 653 }
  52. x^2 = 848 (mod 907); x = { 162, 745 }
  53. x^2 = 259 (mod 919); x = { 190, 729 }
  54. x^2 = 121 (mod 929); x = { 11, 918 }
  55. x^2 = 737 (mod 934); x = { 175, 759 }
  56. x^2 = 509 (mod 935); x = { 38, 72, 302, 412, 523, 633, 863, 897 }
  57. x^2 = 831 (mod 937); x = { 101, 836 }
  58. x^2 = 511 (mod 939); x = { 220, 406, 533, 719 }
  59. x^2 = 841 (mod 940); x = { 29, 159, 311, 441, 499, 629, 781, 911 }
  60. x^2 = 427 (mod 941); x = { 380, 561 }
  61. x^2 = 606 (mod 943); x = { 355, 424, 519, 588 }
  62. x^2 = 865 (mod 954); x = { 127, 233, 721, 827 }
  63. x^2 = 886 (mod 963); x = { 43, 385, 578, 920 }
  64. x^2 = 142 (mod 967); x = { 143, 824 }
  65. x^2 = 547 (mod 982); x = { 283, 699 }
  66. x^2 = 563 (mod 983); x = { 386, 597 }
  67. x^2 = 565 (mod 991); x = { 245, 746 }
  68. x^2 = 866 (mod 997); x = { 350, 647 }