# try to find large probabilistic primes p=1 (mod 4) using the fermat # test, then another probabilistic algorithm for a^2=-1 (mod p), then # use euclidean algorithm for gcd(p,a+i)=x+i*y to get x^2+y^2=p #p=9803474966134690376465720540454742554948058284709716773786346238772238946915778867291080693884180623789816995764235428002178763863520827222672353925424999953422514409016978450637879713288057295291195721692275342183679433460387937973114478952352651431388328222476788583480418082448601642511728111116047184746878182612162434188622047795303529951812688394587550614258143574534644479883786449654330746574569266253398279054057380966796258501349107269768484412671739256945245066879823296150129928116397412638167987390517008778807113888933881998531913693118937103333334961259215026760333222355450200556687955735701646498823330020165340782432739845600376204206320707824645643137597111287881218654512623810050561511354139581757404518718661196564774319662489552456958430488451298700094848010513718765141237862574529890065496468833058884559361179412031923479880319066355585678923223543293198082239974978168105490056508573545199128790183112045968175287965989720651093052807100830720150896473934195139475308803557 #s=sqrt(-1)=7608434785405590471068876121620287988329044197121664480578407165392262999047301569025182695798916041326663300321504271128768897214475619168676492795720666925744169171283873356879515722994562053265155100120293394884712401662790212751876422396677762410189646293813710668276202981565911561222692769608350705862018102579033512392612715840384436488067200971815132660603463175285195447489931493625665893916692580694575077225075852365147016878104989464986995417063366672972097326489059953659492348195635113337154969794582044471850626026528111912979369470316475917945617420452393986395153204579856005151090671524660953811725356723554446447562466462542063711646169794220221928961754746190584019746391370982265180692013485606920270598098854265314129871087988077626167022090320364988532131737390378422144728323915387309541012231411542834548678392701815107488122431850690519670021893279607324638684524130345538584192134365040207277306291279727795938475766892936475936979203840884191983759966250045628981547497265 s^2=9803474966134690376465720540454742554948058284709716773786346238772238946915778867291080693884180623789816995764235428002178763863520827222672353925424999953422514409016978450637879713288057295291195721692275342183679433460387937973114478952352651431388328222476788583480418082448601642511728111116047184746878182612162434188622047795303529951812688394587550614258143574534644479883786449654330746574569266253398279054057380966796258501349107269768484412671739256945245066879823296150129928116397412638167987390517008778807113888933881998531913693118937103333334961259215026760333222355450200556687955735701646498823330020165340782432739845600376204206320707824645643137597111287881218654512623810050561511354139581757404518718661196564774319662489552456958430488451298700094848010513718765141237862574529890065496468833058884559361179412031923479880319066355585678923223543293198082239974978168105490056508573545199128790183112045968175287965989720651093052807100830720150896473934195139475308803556 (mod p) #(83076941929367118790255467969039566443955379987961263412088514903828279869864747271025532842863119916507374894871881159490218480925846648661797142762445963678707045859315284397203140499733583773102113135762759219843614555269884952602203978871764276470287790913978012990269872585455297269103976001487096852148084667095202577668311560337679533012591104095562546098617812324545325182506584982896766173020564956345322796240965117928128003280204471971110141754664265849368064802173076811494145912538332081)^2+(53867399100005319660833497053624715198904362306023870023621446913837014976119731421673530618235362147934317496586969027951941536999377386172610487487498890772738196858539270089985257197373219733861926981943523899222206258940036371758052843734180995482829064124887927884741663506273482531534890340027823487686621748276320003357700540269286211568692306219085577126425981514047344904501639719869107116855934752942102140027380616302655201705576552360352326895904163431210993046847114312098919268593750114)^2=9803474966134690376465720540454742554948058284709716773786346238772238946915778867291080693884180623789816995764235428002178763863520827222672353925424999953422514409016978450637879713288057295291195721692275342183679433460387937973114478952352651431388328222476788583480418082448601642511728111116047184746878182612162434188622047795303529951812688394587550614258143574534644479883786449654330746574569266253398279054057380966796258501349107269768484412671739256945245066879823296150129928116397412638167987390517008778807113888933881998531913693118937103333334961259215026760333222355450200556687955735701646498823330020165340782432739845600376204206320707824645643137597111287881218654512623810050561511354139581757404518718661196564774319662489552456958430488451298700094848010513718765141237862574529890065496468833058884559361179412031923479880319066355585678923223543293198082239974978168105490056508573545199128790183112045968175287965989720651093052807100830720150896473934195139475308803557 use warnings; use Math::BigInt; my $n = 1000; my $T = 5; sub randdigits($) { my $n = shift; return join("",map { int(rand(10)) } 1..$n); } my $maxprime = 100000; my @composite; for (my $i=2;$i<=$maxprime;$i++) { for (my $j=2;($j*$i)<=$maxprime;$j++) { $composite[$j*$i] = 1; } } my @primes = grep { !$composite[$_] } 2..$maxprime; candidate: for (my $i=3;$i<=$maxprime;$i+=2) { for (my $j=3;$j*$j<=$i;$j+=2) { next candidate if ($i%$j==0); } push @primes, $i; } my $prime_test; my $fermat_test; sub testprime($) { $prime_test++; print "prime_test=$prime_test\n"; my $p = shift; foreach my $q (@primes) { if ($p%$q==0) { print "$p divisible by $q\n"; return 0; } } $fermat_test++; print "prime_test=$prime_test fermat_test=$fermat_test\n"; my $phi = $p-1; # print "putative prime $p, phi $phi\n"; for (my $t=0;$t<$T;$t++) { my $a = Math::BigInt->new(randdigits($n)); my $aphi = $a->bmodpow($phi,$p); # print "a=$a a^phi=$aphi (mod p)\n"; if ($a != 1) { # print "bad\n"; print "p=$p failed on test $t\n"; return 0; } } print "p=$p passes $T tests\n"; return 1; } my $p; do { $p = Math::BigInt->new(randdigits($n)); } until (($p%4==1)&&(testprime($p))); sub sqrt_negative_one($) { my $p = shift; while (1) { my $r = Math::BigInt->new(randdigits($n)); my $s = $r->copy()->bmodpow(($p-1)/4,$p); my $check = $s->copy()->bmodpow(2,$p); # print "r=$r s=$s check=$check\n"; return $s if ($p==$check+1); } } # just to be safe, only trust perl div for non-negative numerator and # positive denominator. assume in that case, perl n/d=q such that for # n=d*q+r_full, such that 0<=r_full=0 d>0, # (n+d/2)=q*d+r_full, n=q*d+(r_full-d/2). for any n and d<0, if # n=q*(-d)+r_half, n=(-q)*d+r_half. if n<0, use -n=q*d+r_half, # n=(-q)*d+(-r_half) sub half_div($$); sub half_div($$) { my ($n,$d) = @_; my $q; if ($d<0) { $q = -half_div($n,-$d); } elsif ($n<0) { $q = -half_div(-$n,$d); } else { my $half = $d/2; $q = ($n+$half)/$d; } return $q; } sub gaussian_div($$$$) { my ($nr,$nc,$dr,$dc) = @_; my $norm = $dr*$dr+$dc*$dc; my $njr = $nr*$dr+$nc*$dc; my $njc = -$nr*$dc+$nc*$dr; my $qr = half_div($njr,$norm); my $qc = half_div($njc,$norm); my $qdr = $qr*$dr-$qc*$dc; my $qdc = $qr*$dc+$qc*$dr; my $rr = $nr-$qdr; my $rc = $nc-$qdc; return ($rr,$rc); } sub gaussian_gcd($$$$) { my ($ar,$ac,$br,$bc) = @_; while (1) { return ($ar,$ac) if (($br==0) and ($bc==0)); return ($br,$bc) if (($ar==0) and ($ac==0)); my ($rr,$rc) = gaussian_div($ar,$ac,$br,$bc); $ar = $br; $ac = $bc; $br = $rr; $bc = $rc; } } sub fermat($) { my $p = shift; print "p=$p\n"; my $s = sqrt_negative_one($p); my $s2 = $s->copy()->bmodpow(2,$p); print "s=sqrt(-1)=$s s^2=$s2 (mod p)\n"; my @f = gaussian_gcd($p,0,$s,1); $f[0] = -$f[0] if $f[0]<0; $f[1] = -$f[1] if $f[1]<0; my $sum = $f[0]*$f[0]+$f[1]*$f[1]; print "($f[0])^2+($f[1])^2=$sum\n"; } fermat($p);