LCOV - code coverage report
Current view: top level - ecm/aprtcle - mpz_aprcl.c (source / functions) Hit Total Coverage
Test: unnamed Lines: 423 443 95.5 %
Date: 2022-03-21 11:19:20 Functions: 10 10 100.0 %

          Line data    Source code
       1             : /* Copyright 2011-2015 David Cleaver
       2             :  *
       3             :  * This program is free software: you can redistribute it and/or modify
       4             :  * it under the terms of the GNU Lesser General Public License as published by
       5             :  * the Free Software Foundation, either version 3 of the License, or
       6             :  * (at your option) any later version.
       7             :  *
       8             :  * This program is distributed in the hope that it will be useful,
       9             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      10             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      11             :  * GNU Lesser General Public License for more details.
      12             :  *
      13             :  * You should have received a copy of the GNU Lesser General Public License
      14             :  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
      15             :  */
      16             : 
      17             : /*
      18             :  * v1.0 Posted to SourceForge on 2013/07/04
      19             :  *
      20             :  * v1.1 Posted to SourceForge on 2013/12/27
      21             :  * [The following improvements/fixes were recommended by Laurent Desnogues in 2013/08]
      22             :  *      - Speed improvement 1: Removed extraneous NormalizeJS calls in ARPCL
      23             :  *      - Speed improvement 2: Removed/consolidated calls to mpz_mod in APRCL
      24             :  *        (these improvements make the APRCL code about 1.5-2.2x faster)
      25             :  *      - Bug fix: Final test in APRCL routine is now correct
      26             :  */
      27             : 
      28             : 
      29             : #include <stdio.h>
      30             : #include <stdlib.h>
      31             : #include <gmp.h>
      32             : #include "mpz_aprcl.h"
      33             : 
      34             : #ifndef HAVE_U64_T
      35             : #define HAVE_U64_T
      36             : typedef long long s64_t;
      37             : typedef unsigned long long u64_t;
      38             : #endif
      39             : 
      40             : 
      41             : /* **********************************************************************************
      42             :  * APR-CL (also known as APRT-CLE) is a prime proving algorithm developed by:
      43             :  * L. Adleman, C. Pomerance, R. Rumely, H. Cohen, and H. W. Lenstra
      44             :  * APRT-CLE = Adleman-Pomerance-Rumely Test Cohen-Lenstra Extended version
      45             :  * You can find all the details of this implementation in the Cohen & Lenstra paper:
      46             :  *    H. Cohen and A. K. Lenstra, "Implementation of a new primality test",
      47             :  *    Math. Comp., 48 (1987) 103--121
      48             :  *
      49             :  * ----------------------------------------------------------------------------------
      50             :  *
      51             :  * This C/GMP version is a conversion of Dario Alpern's Java based APRT-CLE code
      52             :  * His code was based on Yuji Kida's UBASIC code
      53             :  *
      54             :  * Based on APRT-CLE Written by Dario Alejandro Alpern (Buenos Aires - Argentina)
      55             :  * From: Last updated September 10th, 2011. See http://www.alpertron.com.ar/ECM.HTM
      56             :  *
      57             :  * On 2012/11/12 Dario Alpern has approved the conversion, from Java to C/GMP, of 
      58             :  * his implementation of the APR-CL algorithm, and that it be licensed under the LGPL.
      59             :  *
      60             :  * ----------------------------------------------------------------------------------
      61             :  *
      62             :  * With improvements based on Jason Moxham's APRCL v1.15 code, from 2003/01/01
      63             :  *
      64             :  * On 2013/04/14 Toby Moxham has approved the APR-CL code and data tables, 
      65             :  * originally written by his brother Jason Moxham on 2003/01/01, to be released 
      66             :  * under the LGPL.
      67             :  *
      68             :  * *********************************************************************************/
      69             : 
      70             : /* int PWmax = 32, Qmax = 55441, LEVELmax = 11; */
      71             : /* QMax is the largest Q in the aiQ array */
      72             : /* PWmax is the largest p^k that divides any (Q-1) */
      73             : /* #define Qmax 55441 */
      74             : /* #define PWmax 32 */
      75             : /*
      76             :  2-max =  2^5 =  32 from t[ 4]=    4324320
      77             :  3-max =  3^3 =  27 from t[ 4]=    4324320
      78             :  5-max =  5^2 =  25 from t[ 6]=  367567200
      79             :  7-max =  7^1 =   7 from t[ 1]=       5040
      80             : 11-max = 11^1 =  11 from t[ 2]=      55440
      81             : 13-max = 13^1 =  13 from t[ 3]=     720720
      82             : 17-max = 17^1 =  17 from t[ 5]=   73513440
      83             : 19-max = 19^1 =  19 from t[ 7]= 1396755360
      84             : */
      85             : 
      86             : /* largest value of p^k that divides any t value */
      87             : #define PWmax 32
      88             : 
      89             : /* Qmax[]: list of largest q-prime for each t value */
      90             : int Qmax[] = {61,2521,55441,180181,4324321,10501921,367567201,232792561,
      91             : 1745944201};
      92             : 
      93             : /* number of values in Qmax[], aiNP[], aiNQ[] */
      94             : int LEVELmax = 9;
      95             : 
      96             : /* list of primes that divide our t values */
      97             : int aiP[] = {2,3,5,7,11,13,17,19};
      98             : 
      99             : /* list of q-primes from all t values */
     100             : int aiQ[] = {2,3,5,7,11,13,31,61,17,19,29,37,41,43,71,73,113,127,181,211,241,
     101             : 281,337,421,631,1009,2521,23,67,89,199,331,397,463,617,661,881,991,1321,2311,
     102             : 3697,4621,9241,18481,55441,53,79,131,157,313,521,547,859,911,937,1093,1171,
     103             : 1873,2003,2341,2731,2861,3121,3433,6007,6553,8009,8191,8581,16381,20021,20593,
     104             : 21841,25741,36037,48049,51481,65521,72073,120121,180181,97,109,271,353,379,433,
     105             : 541,673,757,1249,2017,2081,2161,2377,2971,3169,3361,3511,4159,5281,7393,7561,
     106             : 7723,8317,8737,9829,13729,14561,15121,16633,23761,24571,26209,28081,30241,
     107             : 38611,39313,47521,66529,96097,108109,110881,123553,131041,196561,216217,270271,
     108             : 332641,393121,432433,540541,617761,4324321,103,137,239,307,409,443,613,919,953,
     109             : 1021,1123,1327,1361,1429,1531,1871,2143,2381,2857,3061,3571,3673,4421,4591,
     110             : 5237,6121,6427,6733,7481,8161,9181,9283,9521,10099,10711,12241,12377,12853,
     111             : 14281,15913,16831,17137,17681,19891,22441,23563,23869,24481,27847,29173,29921,
     112             : 30941,34273,36721,42841,43759,46411,47737,52361,53857,59671,63649,70687,72931,
     113             : 74257,78541,79561,87517,92821,97241,100981,102103,116689,117811,128521,145861,
     114             : 148513,157081,161569,167077,185641,201961,209441,235621,238681,269281,291721,
     115             : 314161,371281,388961,417691,445537,471241,477361,514081,565489,612613,656371,
     116             : 680681,700129,816817,1633633,1670761,1837837,2625481,4084081,5250961,5654881,
     117             : 8168161,9189181,10501921,101,151,401,601,701,1051,1201,1301,1801,1951,2551,
     118             : 2801,3301,3851,4201,4951,5101,5851,6301,7151,9901,11551,11701,12601,14851,
     119             : 15401,15601,17551,17851,18701,19801,21601,23801,28051,33151,34651,40801,42901,
     120             : 44201,50051,53551,54601,56101,66301,70201,77351,79201,81901,91801,92401,93601,
     121             : 103951,107101,109201,118801,122401,140401,150151,151201,160651,193051,198901,
     122             : 200201,218401,224401,232051,243101,257401,300301,321301,367201,415801,428401,
     123             : 448801,450451,504901,530401,600601,673201,729301,795601,800801,982801,1029601,
     124             : 1093951,1178101,1201201,1458601,2088451,2187901,2402401,2570401,2702701,
     125             : 3088801,3141601,3712801,5105101,5834401,6806801,7068601,8353801,17503201,
     126             : 22972951,52509601,183783601,367567201,191,229,419,457,571,647,761,1483,1597,
     127             : 2053,2129,2281,2927,3041,3877,4447,4523,4561,4789,6271,6689,6841,6917,7411,
     128             : 7753,8209,8779,8893,10337,11287,11971,12541,13339,13567,13681,14821,16417,
     129             : 17291,17443,18089,19381,20521,20749,21319,21737,22573,25841,27361,28729,29641,
     130             : 30097,31123,35531,35569,35911,38039,39521,40699,43891,46817,47881,48907,51871,
     131             : 53353,56431,57457,58787,59281,63841,71821,72353,75583,77521,87211,90289,97813,
     132             : 105337,106591,108529,114913,117041,124489,131671,134369,135661,139537,140449,
     133             : 146719,163021,177841,186733,207481,213181,217057,217361,225721,251941,279073,
     134             : 287281,300961,302329,342343,351121,377911,391249,406981,451441,456457,461891,
     135             : 489061,511633,526681,554269,568481,608609,651169,652081,697681,733591,782497,
     136             : 790021,813961,895357,1027027,1053361,1058149,1108537,1133731,1264033,1279081,
     137             : 1369369,1492261,1580041,1790713,1813969,1867321,1939939,2217073,2238391,
     138             : 2282281,2351441,2489761,2645371,2771341,2934361,2984521,3233231,3627937,
     139             : 3837241,3912481,3979361,4157011,4232593,4476781,5135131,5372137,5868721,
     140             : 6046561,6348889,6651217,6715171,6846841,7162849,7674481,9767521,11737441,
     141             : 12471031,12697777,17907121,24942061,27387361,31744441,35814241,41081041,
     142             : 46558513,53721361,107442721,174594421,232792561,1901,2851,5701,39901,41801,
     143             : 53201,62701,64601,74101,79801,98801,113051,119701,135851,148201,205201,219451,
     144             : 290701,292601,319201,333451,339151,359101,410401,452201,478801,501601,532951,
     145             : 564301,658351,666901,778051,839801,957601,1037401,1065901,1128601,1222651,
     146             : 1259701,1504801,1808801,1889551,2074801,2173601,2445301,2667601,3052351,
     147             : 3511201,3730651,3779101,3950101,4069801,4149601,4408951,5038801,6104701,
     148             : 6224401,8558551,9781201,11191951,11411401,14922601,16279201,17117101,17635801,
     149             : 19186201,19562401,22383901,22822801,23514401,25581601,25675651,31600801,
     150             : 35271601,37346401,38372401,45349201,59690401,67151701,83140201,129329201,
     151             : 134303401,193993801,249420601,436486051,634888801,1163962801,1745944201};
     152             : /* number of q primes in the above array: 618 */
     153             : 
     154             : /* a primitive root for each q-prime in the above array */
     155             : int aiG[] = {1,2,2,3,2,2,3,2,3,2,2,2,6,3,7,5,3,3,2,2,7,3,10,2,3,11,17,5,2,3,3,
     156             : 3,5,3,3,2,3,6,13,3,5,2,13,13,38,2,3,2,5,10,3,2,2,17,5,5,2,10,5,7,3,2,7,5,3,10,
     157             : 3,17,6,2,3,5,11,6,2,17,17,17,5,29,6,5,6,6,3,2,5,2,5,2,7,5,3,23,5,10,7,22,7,3,7,
     158             : 5,13,3,6,5,10,23,6,11,15,7,7,11,19,11,3,10,17,19,5,2,69,5,17,11,15,7,19,23,5,
     159             : 14,19,17,5,3,7,5,21,2,2,7,3,10,2,3,3,6,2,14,3,3,11,6,2,5,3,11,3,7,3,2,6,7,2,2,
     160             : 3,2,3,7,6,5,19,5,6,5,3,2,14,2,2,11,6,2,3,2,5,37,23,3,3,5,6,5,12,7,5,10,5,2,7,2,
     161             : 6,3,7,5,7,2,22,2,5,26,13,5,41,13,3,10,29,7,14,37,19,3,12,29,19,14,33,13,2,2,6,
     162             : 28,5,5,19,5,7,19,29,13,23,6,7,2,6,3,7,2,7,11,2,11,3,6,3,6,2,11,6,6,2,10,7,2,7,
     163             : 6,11,2,6,23,3,2,2,13,7,3,2,3,2,13,6,6,2,3,22,7,22,14,14,13,2,13,34,22,6,6,17,
     164             : 17,7,11,6,17,2,2,2,3,22,31,3,2,29,2,2,11,31,19,13,2,2,23,37,23,7,19,3,17,7,3,6,
     165             : 31,23,7,2,19,26,6,31,26,29,10,14,3,19,29,37,6,37,41,23,19,6,2,13,3,5,6,2,11,2,
     166             : 3,7,5,3,2,3,5,11,2,11,3,22,2,2,10,7,11,5,3,3,10,14,2,3,22,2,10,6,2,3,7,11,2,14,
     167             : 6,6,3,7,22,7,10,3,6,11,12,7,3,2,3,3,29,2,7,7,3,5,2,7,17,2,3,5,7,13,23,2,10,3,
     168             : 23,5,3,11,3,3,10,5,17,6,6,7,5,31,10,10,6,17,6,10,13,7,7,3,29,3,7,6,29,5,18,17,
     169             : 13,29,6,3,3,22,14,14,6,10,17,13,6,7,34,2,5,2,10,31,43,6,13,13,21,29,2,5,7,17,3,
     170             : 22,7,7,7,29,14,5,13,21,6,10,15,6,2,5,14,14,11,5,7,23,13,7,37,29,11,5,13,22,37,
     171             : 58,26,29,5,43,23,2,71,2,2,2,2,3,3,2,3,2,23,3,6,2,2,17,14,2,2,3,23,26,3,2,11,11,
     172             : 29,31,15,2,7,10,3,3,22,11,6,14,3,6,31,6,3,47,3,10,7,6,13,10,6,6,13,17,3,7,2,11,
     173             : 6,42,3,23,13,37,26,11,21,7,6,37,6,7,2,13,29,59,26,22,59,10,31,3,23,53,42,19,11,
     174             : 46,23};
     175             : 
     176             : 
     177             : /* number of primes from aiP, not necessarily in order, that divides each t */
     178             : int aiNP[] = {3,4,5,6,6,7,7,8,8};
     179             : 
     180             : /* number of q-primes for each t */
     181             : int aiNQ[] = {8,27,45,81,134,245,351,424,618};
     182             : 
     183             : /*         t     |       e(t)   | #Qp |      Qmax  |   divisors of t         */
     184             : /* --------------|--------------|-----|------------|------------------------ */
     185             : s64_t aiT[] =  {
     186             :           60, /* | 6.8144 E   9 |   8 |         61 | p={2,3,5}               */
     187             :         5040, /* | 1.5321 E  52 |  27 |       2521 | p={2,3,5,7}             */
     188             :        55440, /* | 4.9209 E 106 |  45 |      55441 | p={2,3,5,7,11}          */
     189             :       720720, /* | 2.5992 E 237 |  81 |     180181 | p={2,3,5,7,11,13}       */
     190             :      4324320, /* | 7.9285 E 455 | 134 |    4324321 | p={2,3,5,7,11,13}       */
     191             :     73513440, /* | 7.0821 E 966 | 245 |   10501921 | p={2,3,5,7,11,13,17}    */
     192             :    367567200, /* | 6.2087 E1501 | 351 |  367567201 | p={2,3,5,7,11,13,17}    */
     193             :   1396755360, /* | 4.0165 E1913 | 424 |  232792561 | p={2,3,5,7,11,13,17,19} */
     194             :   6983776800};/* | 7.4712 E3010 | 618 | 1745944201 | p={2,3,5,7,11,13,17,19} */
     195             : 
     196             : 
     197             : int aiInv[PWmax];
     198             : mpz_t biTmp;
     199             : mpz_t biExp;
     200             : mpz_t biN;
     201             : mpz_t biR;
     202             : mpz_t biS;
     203             : mpz_t biT;
     204             : mpz_t *aiJS; /* [PWmax] */
     205             : mpz_t *aiJW; /* [PWmax] */
     206             : mpz_t *aiJX; /* [PWmax] */
     207             : mpz_t *aiJ0; /* [PWmax] */
     208             : mpz_t *aiJ1; /* [PWmax] */
     209             : mpz_t *aiJ2; /* [PWmax] */
     210             : mpz_t *aiJ00; /* [PWmax] */
     211             : mpz_t *aiJ01; /* [PWmax] */
     212             : int NumberLength; /* Length of multiple precision nbrs */
     213             : mpz_t TestNbr;
     214             : 
     215             : /* ============================================================================================== */
     216             : 
     217        2587 : void allocate_vars()
     218             : {
     219        2587 :   int i = 0;
     220        2587 :   aiJS = malloc(PWmax * sizeof(mpz_t));
     221        2587 :   aiJW = malloc(PWmax * sizeof(mpz_t));
     222        2587 :   aiJX = malloc(PWmax * sizeof(mpz_t));
     223        2587 :   aiJ0 = malloc(PWmax * sizeof(mpz_t));
     224        2587 :   aiJ1 = malloc(PWmax * sizeof(mpz_t));
     225        2587 :   aiJ2 = malloc(PWmax * sizeof(mpz_t));
     226        2587 :   aiJ00 = malloc(PWmax * sizeof(mpz_t));
     227        2587 :   aiJ01 = malloc(PWmax * sizeof(mpz_t));
     228       85371 :   for (i = 0 ; i < PWmax; i++)
     229             :   {
     230       82784 :     mpz_init(aiJS[i]);
     231       82784 :     mpz_init(aiJW[i]);
     232       82784 :     mpz_init(aiJX[i]);
     233       82784 :     mpz_init(aiJ0[i]);
     234       82784 :     mpz_init(aiJ1[i]);
     235       82784 :     mpz_init(aiJ2[i]);
     236       82784 :     mpz_init(aiJ00[i]);
     237       82784 :     mpz_init(aiJ01[i]);
     238             :   }
     239             : 
     240        2587 :   mpz_init(TestNbr);
     241        2587 :   mpz_init(biN);
     242        2587 :   mpz_init(biR);
     243        2587 :   mpz_init(biS);
     244        2587 :   mpz_init(biT);
     245        2587 :   mpz_init(biExp);
     246        2587 :   mpz_init(biTmp);
     247        2587 : }
     248             : 
     249             : /* ============================================================================================== */
     250             : 
     251        2587 : void free_vars()
     252             : {
     253        2587 :   int i = 0;
     254       85371 :   for (i = 0 ; i < PWmax; i++)
     255             :   {
     256       82784 :     mpz_clear(aiJS[i]);
     257       82784 :     mpz_clear(aiJW[i]);
     258       82784 :     mpz_clear(aiJX[i]);
     259       82784 :     mpz_clear(aiJ0[i]);
     260       82784 :     mpz_clear(aiJ1[i]);
     261       82784 :     mpz_clear(aiJ2[i]);
     262       82784 :     mpz_clear(aiJ00[i]);
     263       82784 :     mpz_clear(aiJ01[i]);
     264             :   }
     265        2587 :   free(aiJS);
     266        2587 :   free(aiJW);
     267        2587 :   free(aiJX);
     268        2587 :   free(aiJ0);
     269        2587 :   free(aiJ1);
     270        2587 :   free(aiJ2);
     271        2587 :   free(aiJ00);
     272        2587 :   free(aiJ01);
     273             : 
     274        2587 :   mpz_clear(TestNbr);
     275        2587 :   mpz_clear(biN);
     276        2587 :   mpz_clear(biR);
     277        2587 :   mpz_clear(biS);
     278        2587 :   mpz_clear(biT);
     279        2587 :   mpz_clear(biExp);
     280        2587 :   mpz_clear(biTmp);
     281        2587 : }
     282             : 
     283             : /* ============================================================================================== */
     284             : 
     285             : // Compare Nbr1^2 vs. Nbr2
     286             : // -1 -> Nbr1^2 < Nbr2
     287             : //  0 -> Nbr1^2 == Nbr2
     288             : //  1 -> Nbr1^2 > Nbr2
     289       68636 : int CompareSquare(mpz_t Nbr1, mpz_t Nbr2)
     290             : {
     291             :   mpz_t tmp;
     292       68636 :   int cmp = 0;
     293             : 
     294       68636 :   mpz_init(tmp);
     295       68636 :   mpz_mul(tmp, Nbr1, Nbr1);
     296             : 
     297       68636 :   cmp = mpz_cmp(tmp, Nbr2);
     298       68636 :   mpz_clear(tmp);
     299             : 
     300       68636 :   return cmp;
     301             : }
     302             : 
     303             : /* ============================================================================================== */
     304             : 
     305             : // Normalize coefficient of JS
     306    18143805 : void NormalizeJS(int PK, int PL, int PM, int P)
     307             : {
     308             :   int I, J;
     309    50106484 :   for (I = PL; I < PK; I++)
     310             :   {
     311    31962679 :     if (mpz_cmp_ui(aiJS[I], 0) != 0) /* (!BigNbrIsZero(aiJS[I])) */
     312             :     {
     313             :       /* biT = aiJS[I]; */
     314    25467342 :       mpz_set(biT, aiJS[I]);
     315   105659183 :       for (J = 1; J < P; J++)
     316             :       {
     317             :         /* SubtractBigNbrModN(aiJS[I - J * PM], biT, aiJS[I - J * PM], TestNbr, NumberLength); */
     318    80191841 :         mpz_sub(aiJS[I - J * PM], aiJS[I - J * PM], biT);
     319             :       }
     320             :       /* aiJS[I] = 0; */
     321    25467342 :       mpz_set_ui(aiJS[I], 0);
     322             :     }
     323             :   }
     324   136940207 :   for (I = 0; I < PK; I++)
     325   118796402 :     mpz_mod(aiJS[I], aiJS[I], TestNbr);
     326    18143805 : }
     327             : 
     328             : /* ============================================================================================== */
     329             : 
     330             : // Normalize coefficient of JW
     331      167857 : void NormalizeJW(int PK, int PL, int PM, int P)
     332             : {
     333             :   int I, J;
     334      450114 :   for (I = PL; I < PK; I++)
     335             :   {
     336      282257 :     if (mpz_cmp_ui(aiJW[I], 0) != 0) /* (!BigNbrIsZero(aiJW[I])) */
     337             :     {
     338             :       /* biT = aiJW[I]; */
     339      170644 :       mpz_set(biT, aiJW[I]);
     340             : 
     341      926880 :       for (J = 1; J < P; J++)
     342             :       {
     343             :         /* SubtractBigNbrModN(aiJW[I - J * PM], biT, aiJW[I - J * PM], TestNbr, NumberLength); */
     344      756236 :         mpz_sub(aiJW[I - J * PM], aiJW[I - J * PM], biT);
     345             :       }
     346             :       /* aiJW[I] = 0; */
     347      170644 :       mpz_set_ui(aiJW[I], 0);
     348             :     }
     349             :   }
     350     1404971 :   for (I = 0; I < PK; I++)
     351     1237114 :     mpz_mod(aiJW[I], aiJW[I], TestNbr);
     352      167857 : }
     353             : 
     354             : /* ============================================================================================== */
     355             : 
     356             : // Perform JS <- JS * JW
     357             : 
     358     5801557 : void JS_JW(int PK, int PL, int PM, int P)
     359             : {
     360             :   int I, J, K;
     361    34022339 :   for (I = 0; I < PL; I++)
     362             :   {
     363   231679974 :     for (J = 0; J < PL; J++)
     364             :     {
     365   203459192 :       K = (I + J) % PK;
     366             :       /* MontgomeryMult(aiJS[I], aiJW[J], biTmp); */
     367             :       /* AddBigNbrModN(aiJX[K], biTmp, aiJX[K], TestNbr, NumberLength); */
     368   203459192 :       mpz_mul(biTmp, aiJS[I], aiJW[J]);
     369   203459192 :       mpz_add(aiJX[K], aiJX[K], biTmp);
     370             :     }
     371             :   }
     372    44089135 :   for (I = 0; I < PK; I++)
     373             :   {
     374             :     /* aiJS[I] = aiJX[I]; */
     375             :     /* aiJX[I] = 0; */
     376    38287578 :     mpz_swap(aiJS[I], aiJX[I]);
     377    38287578 :     mpz_set_ui(aiJX[I], 0);
     378             :   }
     379     5801557 :   NormalizeJS(PK, PL, PM, P);
     380     5801557 : }
     381             : 
     382             : /* ============================================================================================== */
     383             : 
     384             : // Perform JS <- JS ^ 2
     385             : 
     386    12332224 : void JS_2(int PK, int PL, int PM, int P)
     387             : {
     388             :   int I, J, K;
     389    70875605 :   for (I = 0; I < PL; I++)
     390             :   {
     391    58543381 :     K = 2 * I % PK;
     392             :     /* MontgomeryMult(aiJS[I], aiJS[I], biTmp); */
     393             :     /* AddBigNbrModN(aiJX[K], biTmp, aiJX[K], TestNbr, NumberLength); */
     394             :     /* AddBigNbrModN(aiJS[I], aiJS[I], biT, TestNbr, NumberLength); */
     395    58543381 :     mpz_mul(biTmp, aiJS[I], aiJS[I]);
     396    58543381 :     mpz_add(aiJX[K], aiJX[K], biTmp);
     397    58543381 :     mpz_add(biT, aiJS[I], aiJS[I]);
     398   236302927 :     for (J = I + 1; J < PL; J++)
     399             :     {
     400   177759546 :       K = (I + J) % PK;
     401             :       /* MontgomeryMult(biT, aiJS[J], biTmp); */
     402             :       /* AddBigNbrModN(aiJX[K], biTmp, aiJX[K], TestNbr, NumberLength); */
     403   177759546 :       mpz_mul(biTmp, biT, aiJS[J]);
     404   177759546 :       mpz_add(aiJX[K], aiJX[K], biTmp);
     405             :     }
     406             :   }
     407    92701928 :   for (I = 0; I < PK; I++)
     408             :   {
     409             :     /* aiJS[I] = aiJX[I]; */
     410             :     /* aiJX[I] = 0; */
     411    80369704 :     mpz_swap(aiJS[I], aiJX[I]);
     412    80369704 :     mpz_set_ui(aiJX[I], 0);
     413             :   }
     414    12332224 :   NormalizeJS(PK, PL, PM, P);
     415    12332224 : }
     416             : 
     417             : /* ============================================================================================== */
     418             : 
     419             : // Perform JS <- JS ^ E
     420             : 
     421      167857 : void JS_E(int PK, int PL, int PM, int P)
     422             : {
     423             :   int K;
     424             :   long Mask;
     425             : 
     426      167857 :   if (mpz_cmp_ui(biExp, 1) == 0)
     427             :   {
     428       39008 :     return;
     429             :   } // Return if E == 1
     430             : 
     431             : 
     432      881176 :   for (K = 0; K < PL; K++)
     433             :   {
     434      752327 :     mpz_set(aiJW[K], aiJS[K]);
     435             :   }
     436             : 
     437             : 
     438      128849 :   Mask = mpz_sizeinbase(biExp, 2)-1;
     439             : 
     440             :   do
     441             :   {
     442    12324358 :     JS_2(PK, PL, PM, P);
     443    12324358 :     Mask--;
     444    12324358 :     if (mpz_tstbit(biExp, Mask))
     445             :     {
     446     5665619 :       JS_JW(PK, PL, PM, P);
     447             :     }
     448             :   }
     449    12324358 :   while (Mask > 0);
     450             : }
     451             : 
     452             : /* ============================================================================================== */
     453             : 
     454             : // if mode==0 then store J(p,q) ie x+f(x)
     455             : // if mode==1 then p=2, look for p==1, and stores Jstar(q) ie 2x+f(x)
     456             : // if mode==2 then p=2, look for p==4, and stores Jhash(q) ie 3x+f(x)
     457             : // This is based on ideas and code from Jason Moxham
     458             : 
     459       30224 : void JacobiSum(int mode, int P, int PL, int Q)
     460             : {
     461             :   int I, a, myP;
     462             : 
     463      159870 :   for (I = 0; I < PL; I++)
     464      129646 :     mpz_set_ui(aiJ0[I], 0);
     465             : 
     466       30224 :   myP = P; /* if (mode == 0) */
     467       30224 :   if (mode == 1) myP = 1;
     468       30224 :   if (mode == 2) myP = 4;
     469             : 
     470     1708232 :   for(a = 0; a < JPQSMAX; a++)
     471     1708232 :     if(jpqs[a].p == myP && jpqs[a].q == Q)
     472       30224 :       break;
     473             : 
     474      159870 :   for (I = 0; I < PL; I++)
     475      129646 :     mpz_set_si(aiJ0[I], sls[jpqs[a].index+I]);
     476       30224 : }
     477             : 
     478             : /* ============================================================================================== */
     479             : 
     480             : /* Prime checking routine                       */
     481             : /* Return codes: 0 = N is composite.            */
     482             : /*               1 = N is a bpsw probable prime */
     483             : /*               2 = N is prime.                */
     484        3230 : int mpz_aprtcle(mpz_t N, int verbose)
     485             : {
     486             :   s64_t T, U;
     487             :   int i, j, H, I, J, K, P, Q, W, X;
     488             :   int IV, InvX, LEVELnow, NP, PK, PL, PM, SW, VK, TestedQs, TestingQs;
     489             :   int QQ, T1, T3, U1, U3, V1, V3;
     490        3230 :   int break_this = 0;
     491             : 
     492             : 
     493             :   /* make sure the input is >= 2 and odd */
     494        3230 :   if (mpz_cmp_ui(N, 2) < 0)
     495         613 :     return APRTCLE_COMPOSITE;
     496             : 
     497        2617 :   if (mpz_divisible_ui_p(N, 2))
     498             :   {
     499          20 :     if (mpz_cmp_ui(N, 2) == 0)
     500          20 :       return APRTCLE_PRIME;
     501             :     else
     502           0 :       return APRTCLE_COMPOSITE;
     503             :   }
     504             : 
     505             : /* only three small exceptions for this implementation */
     506             : /* with this set of P and Q primes */
     507        2597 :   if (mpz_cmp_ui(N, 3) == 0)
     508           0 :     return APRTCLE_PRIME;
     509        2597 :   if (mpz_cmp_ui(N, 7) == 0)
     510           0 :     return APRTCLE_PRIME;
     511        2597 :   if (mpz_cmp_ui(N, 11) == 0)
     512          10 :     return APRTCLE_PRIME;
     513             : 
     514             :   /* If the input number is larger than 7000 decimal digits
     515             :      we will just return whether it is a BPSW (probable) prime */
     516        2587 :   NumberLength = mpz_sizeinbase(N, 10);
     517        2587 :   if (NumberLength > 7000)
     518             :   {
     519           0 :     return mpz_probab_prime_p(N, 1); // mpz_probab_prime_p mpz_bpsw_prp
     520             :   }
     521             : 
     522        2587 :   allocate_vars();
     523             : 
     524        2587 :   mpz_set(TestNbr, N);
     525        2587 :   mpz_set_si(biS, 0);
     526             : 
     527        2587 :   j = PK = PL = PM = 0;
     528       85371 :   for (J = 0; J < PWmax; J++)
     529             :   {
     530             :     /* aiJX[J] = 0; */
     531       82784 :     mpz_set_ui(aiJX[J], 0);
     532             :   }
     533        2587 :   break_this = 0;
     534             : /* GetPrimes2Test : */
     535        4285 :   for (i = 0; i < LEVELmax; i++)
     536             :   {
     537             :     /* biS[0] = 2; */
     538        4285 :     mpz_set_ui(biS, 2);
     539             :     
     540       69950 :     for (j = 0; j < aiNQ[i]; j++)
     541             :     {
     542       68252 :       Q = aiQ[j];
     543       68252 :       if (aiT[i]%(Q-1) != 0) continue;
     544       68252 :       U = aiT[i] * Q;
     545             :       do
     546             :       {
     547       92468 :         U /= Q;
     548             :         /* MultBigNbrByLong(biS, Q, biS, NumberLength); */
     549       92468 :         mpz_mul_ui(biS, biS, Q);
     550             :       }
     551       92468 :       while (U % Q == 0);
     552             : 
     553             :       // Exit loop if S^2 > N.
     554       68252 :       if (CompareSquare(biS, TestNbr) > 0)
     555             :       {
     556             :         /* break GetPrimes2Test; */
     557        2587 :         break_this = 1;
     558        2587 :         break;
     559             :       }
     560             :     } /* End for j */
     561        4285 :     if (break_this) break;
     562             :   } /* End for i */
     563        2587 :   if (i == LEVELmax)
     564             :   { /* too big */
     565           0 :     free_vars();
     566           0 :     return mpz_probab_prime_p(N, 1);
     567             :   }
     568        2587 :   LEVELnow = i;
     569        2587 :   TestingQs = j;
     570        2587 :   T = aiT[LEVELnow];
     571        2587 :   NP = aiNP[LEVELnow];
     572             : 
     573        2683 : MainStart:
     574             :   for (;;)
     575             :   {
     576        9941 :     for (i = 0; i < NP; i++)
     577             :     {
     578        7792 :       P = aiP[i];
     579        7792 :       if (T%P != 0) continue;
     580             : 
     581        7792 :       SW = TestedQs = 0;
     582             :       /* Q = W = (int) BigNbrModLong(TestNbr, P * P); */
     583        7792 :       Q = W = mpz_fdiv_ui(TestNbr, P * P);
     584       20903 :       for (J = P - 2; J > 0; J--)
     585             :       {
     586       13111 :         W = (W * Q) % (P * P);
     587             :       }
     588        7792 :       if (P > 2 && W != 1)
     589             :       {
     590        4077 :         SW = 1;
     591             :       }
     592             :       for (;;)
     593             :       {
     594       82977 :         for (j = TestedQs; j <= TestingQs; j++)
     595             :         {
     596       73185 :           Q = aiQ[j] - 1;
     597             :           /* G = aiG[j]; */
     598       73185 :           K = 0;
     599      121469 :           while (Q % P == 0)
     600             :           {
     601       48284 :             K++;
     602       48284 :             Q /= P;
     603             :           }
     604       73185 :           Q = aiQ[j];
     605       73185 :           if (K == 0)
     606             :           {
     607       37828 :             continue;
     608             :           }
     609             : 
     610       35357 :           if (verbose >= APRTCLE_VERBOSE1)
     611             :           {
     612        5000 :             printf("APR primality test: P = %2d, Q = %12d  (%3.2f%%)\r", P, Q, (i * (TestingQs + 1) + j) * 100.0 / (NP * (TestingQs + 1)));
     613        5000 :             fflush(stdout);
     614             :           }
     615             : 
     616       35357 :           PM = 1;
     617       48284 :           for (I = 1; I < K; I++)
     618             :           {
     619       12927 :             PM = PM * P;
     620             :           }
     621       35357 :           PL = (P - 1) * PM;
     622       35357 :           PK = P * PM;
     623      203771 :           for (I = 0; I < PK; I++)
     624             :           {
     625             :             /* aiJ0[I] = aiJ1[I] = 0; */
     626      168414 :             mpz_set_ui(aiJ0[I], 0);
     627      168414 :             mpz_set_ui(aiJ1[I], 0);
     628             :           }
     629       35357 :           if (P > 2)
     630             :           {
     631       18124 :             JacobiSum(0, P, PL, Q);
     632             :           }
     633             :           else
     634             :           {
     635       17233 :             if (K != 1)
     636             :             {
     637        7866 :               JacobiSum(0, P, PL, Q);
     638       57142 :               for (I = 0; I < PK; I++)
     639             :               {
     640             :                 /* aiJW[I] = 0; */
     641       49276 :                 mpz_set_ui(aiJW[I], 0);
     642             :               }
     643        7866 :               if (K != 2)
     644             :               {
     645       15257 :                 for (I = 0; I < PM; I++)
     646             :                 {
     647             :                   /* aiJW[I] = aiJ0[I]; */
     648       13140 :                   mpz_set(aiJW[I], aiJ0[I]);
     649             :                 }
     650        2117 :                 JacobiSum(1, P, PL, Q);
     651       15257 :                 for (I = 0; I < PM; I++)
     652             :                 {
     653             :                   /* aiJS[I] = aiJ0[I]; */
     654       13140 :                   mpz_set(aiJS[I], aiJ0[I]);
     655             :                 }
     656        2117 :                 JS_JW(PK, PL, PM, P);
     657       15257 :                 for (I = 0; I < PM; I++)
     658             :                 {
     659             :                   /* aiJ1[I] = aiJS[I]; */
     660       13140 :                   mpz_set(aiJ1[I], aiJS[I]);
     661             :                 }
     662        2117 :                 JacobiSum(2, P, PL, Q);
     663       28397 :                 for (I = 0; I < PK; I++)
     664             :                 {
     665             :                   /* aiJW[I] = 0; */
     666       26280 :                   mpz_set_ui(aiJW[I], 0);
     667             :                 }
     668       15257 :                 for (I = 0; I < PM; I++)
     669             :                 {
     670             :                   /* aiJS[I] = aiJ0[I]; */
     671       13140 :                   mpz_set(aiJS[I], aiJ0[I]);
     672             :                 }
     673        2117 :                 JS_2(PK, PL, PM, P);
     674       15257 :                 for (I = 0; I < PM; I++)
     675             :                 {
     676             :                   /* aiJ2[I] = aiJS[I]; */
     677       13140 :                   mpz_set(aiJ2[I], aiJS[I]);
     678             :                 }
     679             :               }
     680             :             }
     681             :           }
     682             :           /* aiJ00[0] = aiJ01[0] = 1; */
     683       35357 :           mpz_set_ui(aiJ00[0], 1);
     684       35357 :           mpz_set_ui(aiJ01[0], 1);
     685      168414 :           for (I = 1; I < PK; I++)
     686             :           {
     687             :             /* aiJ00[I] = aiJ01[I] = 0; */
     688      133057 :             mpz_set_ui(aiJ00[I], 0);
     689      133057 :             mpz_set_ui(aiJ01[I], 0);
     690             :           }
     691             :           /* VK = (int) BigNbrModLong(TestNbr, PK); */
     692       35357 :           VK = mpz_fdiv_ui(TestNbr, PK);
     693      168414 :           for (I = 1; I < PK; I++)
     694             :           {
     695      133057 :             if (I % P != 0)
     696             :             {
     697      112733 :               U1 = 1;
     698      112733 :               U3 = I;
     699      112733 :               V1 = 0;
     700      112733 :               V3 = PK;
     701      452402 :               while (V3 != 0)
     702             :               {
     703      339669 :                 QQ = U3 / V3;
     704      339669 :                 T1 = U1 - V1 * QQ;
     705      339669 :                 T3 = U3 - V3 * QQ;
     706      339669 :                 U1 = V1;
     707      339669 :                 U3 = V3;
     708      339669 :                 V1 = T1;
     709      339669 :                 V3 = T3;
     710             :               }
     711      112733 :               aiInv[I] = (U1 + PK) % PK;
     712             :             }
     713             :             else
     714             :             {
     715       20324 :               aiInv[I] = 0;
     716             :             }
     717             :           }
     718       35357 :           if (P != 2)
     719             :           {
     720       54372 :             for (IV = 0; IV <= 1; IV++)
     721             :             {
     722      200808 :               for (X = 1; X < PK; X++)
     723             :               {
     724     1356784 :                 for (I = 0; I < PK; I++)
     725             :                 {
     726             :                   /* aiJS[I] = aiJ0[I]; */
     727     1192224 :                   mpz_set(aiJS[I], aiJ0[I]);
     728             :                 }
     729      164560 :                 if (X % P == 0)
     730             :                 {
     731        7104 :                   continue;
     732             :                 }
     733      157456 :                 if (IV == 0)
     734             :                 {
     735             :                   /* LongToBigNbr(X, biExp, NumberLength); */
     736       78728 :                   mpz_set_ui(biExp, X);
     737             :                 }
     738             :                 else
     739             :                 {
     740             :                   /* LongToBigNbr(VK * X / PK, biExp, NumberLength); */
     741       78728 :                   mpz_set_ui(biExp, (VK * X) / PK);
     742       78728 :                   if ((VK * X) / PK == 0)
     743             :                   {
     744       34980 :                     continue;
     745             :                   }
     746             :                 }
     747      122476 :                 JS_E(PK, PL, PM, P);
     748     1052056 :                 for (I = 0; I < PK; I++)
     749             :                 {
     750             :                   /* aiJW[I] = 0; */
     751      929580 :                   mpz_set_ui(aiJW[I], 0);
     752             :                 }
     753      122476 :                 InvX = aiInv[X];
     754     1052056 :                 for (I = 0; I < PK; I++)
     755             :                 {
     756      929580 :                   J = (I * InvX) % PK;
     757             :                   /* AddBigNbrModN(aiJW[J], aiJS[I], aiJW[J], TestNbr, NumberLength); */
     758      929580 :                   mpz_add(aiJW[J], aiJW[J], aiJS[I]);
     759             :                 }
     760      122476 :                 NormalizeJW(PK, PL, PM, P);
     761      122476 :                 if (IV == 0)
     762             :                 {
     763      642872 :                   for (I = 0; I < PK; I++)
     764             :                   {
     765             :                     /* aiJS[I] = aiJ00[I]; */
     766      564144 :                     mpz_set(aiJS[I], aiJ00[I]);
     767             :                   }
     768             :                 }
     769             :                 else
     770             :                 {
     771      409184 :                   for (I = 0; I < PK; I++)
     772             :                   {
     773             :                     /* aiJS[I] = aiJ01[I]; */
     774      365436 :                     mpz_set(aiJS[I], aiJ01[I]);
     775             :                   }
     776             :                 }
     777      122476 :                 JS_JW(PK, PL, PM, P);
     778      122476 :                 if (IV == 0)
     779             :                 {
     780      642872 :                   for (I = 0; I < PK; I++)
     781             :                   {
     782             :                     /* aiJ00[I] = aiJS[I]; */
     783      564144 :                     mpz_set(aiJ00[I], aiJS[I]);
     784             :                   }
     785             :                 }
     786             :                 else
     787             :                 {
     788      409184 :                   for (I = 0; I < PK; I++)
     789             :                   {
     790             :                     /* aiJ01[I] = aiJS[I]; */
     791      365436 :                     mpz_set(aiJ01[I], aiJS[I]);
     792             :                   }
     793             :                 }
     794             :               } /* end for X */
     795             :             } /* end for IV */
     796             :           }
     797             :           else
     798             :           {
     799       17233 :             if (K == 1)
     800             :             {
     801             :               /* MultBigNbrByLongModN(1, Q, aiJ00[0], TestNbr, NumberLength); */
     802        9367 :               mpz_set_ui(aiJ00[0], Q);
     803             :               /* aiJ01[0] = 1; */
     804        9367 :               mpz_set_ui(aiJ01[0], 1);
     805             :             }
     806             :             else
     807             :             {
     808        7866 :               if (K == 2)
     809             :               {
     810        5749 :                 if (VK == 1)
     811             :                 {
     812             :                   /* aiJ01[0] = 1; */
     813        2823 :                   mpz_set_ui(aiJ01[0], 1);
     814             :                 }
     815             :                 /* aiJS[0] = aiJ0[0]; */
     816             :                 /* aiJS[1] = aiJ0[1]; */
     817        5749 :                 mpz_set(aiJS[0], aiJ0[0]);
     818        5749 :                 mpz_set(aiJS[1], aiJ0[1]);
     819        5749 :                 JS_2(PK, PL, PM, P);
     820        5749 :                 if (VK == 3)
     821             :                 {
     822             :                   /* aiJ01[0] = aiJS[0]; */
     823             :                   /* aiJ01[1] = aiJS[1]; */
     824        2926 :                   mpz_set(aiJ01[0], aiJS[0]);
     825        2926 :                   mpz_set(aiJ01[1], aiJS[1]);
     826             :                 }
     827             :                 /* MultBigNbrByLongModN(aiJS[0], Q, aiJ00[0], TestNbr, NumberLength); */
     828        5749 :                 mpz_mul_ui(aiJ00[0], aiJS[0], Q);
     829             :                 /* MultBigNbrByLongModN(aiJS[1], Q, aiJ00[1], TestNbr, NumberLength); */
     830        5749 :                 mpz_mul_ui(aiJ00[1], aiJS[1], Q);
     831             :               }
     832             :               else
     833             :               {
     834        6351 :                 for (IV = 0; IV <= 1; IV++)
     835             :                 {
     836       30514 :                   for (X = 1; X < PK; X += 2)
     837             :                   {
     838      232432 :                     for (I = 0; I <= PM; I++)
     839             :                     {
     840             :                       /* aiJS[I] = aiJ1[I]; */
     841      206152 :                       mpz_set(aiJS[I], aiJ1[I]);
     842             :                     }
     843       26280 :                     if (X % 8 == 5 || X % 8 == 7)
     844             :                     {
     845       13140 :                       continue;
     846             :                     }
     847       13140 :                     if (IV == 0)
     848             :                     {
     849             :                       /* LongToBigNbr(X, biExp, NumberLength); */
     850        6570 :                       mpz_set_ui(biExp, X);
     851             :                     }
     852             :                     else
     853             :                     {
     854             :                       /* LongToBigNbr(VK * X / PK, biExp, NumberLength); */
     855        6570 :                       mpz_set_ui(biExp, VK * X / PK);
     856        6570 :                       if (VK * X / PK == 0)
     857             :                       {
     858        3116 :                         continue;
     859             :                       }
     860             :                     }
     861       10024 :                     JS_E(PK, PL, PM, P);
     862      149144 :                     for (I = 0; I < PK; I++)
     863             :                     {
     864             :                       /* aiJW[I] = 0; */
     865      139120 :                       mpz_set_ui(aiJW[I], 0);
     866             :                     }
     867       10024 :                     InvX = aiInv[X];
     868      149144 :                     for (I = 0; I < PK; I++)
     869             :                     {
     870      139120 :                       J = I * InvX % PK;
     871             :                       /* AddBigNbrModN(aiJW[J], aiJS[I], aiJW[J], TestNbr, NumberLength); */
     872      139120 :                       mpz_add(aiJW[J], aiJW[J], aiJS[I]);
     873             :                     }
     874       10024 :                     NormalizeJW(PK, PL, PM, P);
     875       10024 :                     if (IV == 0)
     876             :                     {
     877       96506 :                       for (I = 0; I < PK; I++)
     878             :                       {
     879             :                         /* aiJS[I] = aiJ00[I]; */
     880       89936 :                         mpz_set(aiJS[I], aiJ00[I]);
     881             :                       }
     882             :                     }
     883             :                     else
     884             :                     {
     885       52638 :                       for (I = 0; I < PK; I++)
     886             :                       {
     887             :                         /* aiJS[I] = aiJ01[I]; */
     888       49184 :                         mpz_set(aiJS[I], aiJ01[I]);
     889             :                       }
     890             :                     }
     891       10024 :                     NormalizeJS(PK, PL, PM, P);
     892       10024 :                     JS_JW(PK, PL, PM, P);
     893       10024 :                     if (IV == 0)
     894             :                     {
     895       96506 :                       for (I = 0; I < PK; I++)
     896             :                       {
     897             :                         /* aiJ00[I] = aiJS[I]; */
     898       89936 :                         mpz_set(aiJ00[I], aiJS[I]);
     899             :                       }
     900             :                     }
     901             :                     else
     902             :                     {
     903       52638 :                       for (I = 0; I < PK; I++)
     904             :                       {
     905             :                         /* aiJ01[I] = aiJS[I]; */
     906       49184 :                         mpz_set(aiJ01[I], aiJS[I]);
     907             :                       }
     908             :                     }
     909             :                   } /* end for X */
     910        4234 :                   if (IV == 0 || VK % 8 == 1 || VK % 8 == 3)
     911             :                   {
     912        2913 :                     continue;
     913             :                   }
     914        9505 :                   for (I = 0; I < PM; I++)
     915             :                   {
     916             :                     /* aiJW[I] = aiJ2[I]; */
     917             :                     /* aiJS[I] = aiJ01[I]; */
     918        8184 :                     mpz_set(aiJW[I], aiJ2[I]);
     919        8184 :                     mpz_set(aiJS[I], aiJ01[I]);
     920             :                   }
     921        9505 :                   for (; I < PK; I++)
     922             :                   {
     923             :                     /* aiJW[I] = aiJS[I] = 0; */
     924        8184 :                     mpz_set_ui(aiJW[I], 0);
     925        8184 :                     mpz_set_ui(aiJS[I], 0);
     926             :                   }
     927        1321 :                   JS_JW(PK, PL, PM, P);
     928        9505 :                   for (I = 0; I < PM; I++)
     929             :                   {
     930             :                     /* aiJ01[I] = aiJS[I]; */
     931        8184 :                     mpz_set(aiJ01[I], aiJS[I]);
     932             :                   }
     933             :                 } /* end for IV */
     934             :               }
     935             :             }
     936             :           }
     937      148090 :           for (I = 0; I < PL; I++)
     938             :           {
     939             :             /* aiJS[I] = aiJ00[I]; */
     940      112733 :             mpz_set(aiJS[I], aiJ00[I]);
     941             :           }
     942       91038 :           for (; I < PK; I++)
     943             :           {
     944             :             /* aiJS[I] = 0; */
     945       55681 :             mpz_set_ui(aiJS[I], 0);
     946             :           }
     947             :           /* DivBigNbrByLong(TestNbr, PK, biExp, NumberLength); */
     948       35357 :           mpz_fdiv_q_ui(biExp, TestNbr, PK);
     949       35357 :           JS_E(PK, PL, PM, P);
     950      203771 :           for (I = 0; I < PK; I++)
     951             :           {
     952             :             /* aiJW[I] = 0; */
     953      168414 :             mpz_set_ui(aiJW[I], 0);
     954             :           }
     955      148090 :           for (I = 0; I < PL; I++)
     956             :           {
     957      699136 :             for (J = 0; J < PL; J++)
     958             :             {
     959             :               /* MontgomeryMult(aiJS[I], aiJ01[J], biTmp); */
     960             :               /* AddBigNbrModN(biTmp, aiJW[(I + J) % PK], aiJW[(I + J) % PK], TestNbr, NumberLength); */
     961      586403 :               mpz_mul(biTmp, aiJS[I], aiJ01[J]);
     962      586403 :               mpz_add(aiJW[(I + J) % PK], biTmp, aiJW[(I + J) % PK]);
     963             :             }
     964             :           }
     965       35357 :           NormalizeJW(PK, PL, PM, P);
     966             : /* MatchingRoot : */
     967             :           do
     968             :           {
     969       35357 :             H = -1;
     970       35357 :             W = 0;
     971      148090 :             for (I = 0; I < PL; I++)
     972             :             {
     973      112733 :               if (mpz_cmp_ui(aiJW[I], 0) != 0)/* (!BigNbrIsZero(aiJW[I])) */
     974             :               {
     975             :                 /* if (H == -1 && BigNbrAreEqual(aiJW[I], 1)) */
     976       45706 :                 if (H == -1 && (mpz_cmp_ui(aiJW[I], 1) == 0))
     977             :                 {
     978       21355 :                   H = I;
     979             :                 }
     980             :                 else
     981             :                 {
     982       24351 :                   H = -2;
     983             :                   /* AddBigNbrModN(aiJW[I], MontgomeryMultR1, biTmp, TestNbr, NumberLength); */
     984       24351 :                   mpz_add_ui(biTmp, aiJW[I], 1);
     985       24351 :                   mpz_mod(biTmp, biTmp, TestNbr);
     986       24351 :                   if (mpz_cmp_ui(biTmp, 0) == 0) /* (BigNbrIsZero(biTmp)) */
     987             :                   {
     988       23923 :                     W++;
     989             :                   }
     990             :                 }
     991             :               }
     992             :             }
     993       35357 :             if (H >= 0)
     994             :             {
     995             :               /* break MatchingRoot; */
     996       21355 :               break;
     997             :             }
     998       14002 :             if (W != P - 1)
     999             :             {
    1000             :               /* Not prime */
    1001         438 :               free_vars();
    1002         438 :               return APRTCLE_COMPOSITE;
    1003             :             }
    1004       18831 :             for (I = 0; I < PM; I++)
    1005             :             {
    1006             :               /* AddBigNbrModN(aiJW[I], 1, biTmp, TestNbr, NumberLength); */
    1007       18831 :               mpz_add_ui(biTmp, aiJW[I], 1);
    1008       18831 :               mpz_mod(biTmp, biTmp, TestNbr);
    1009       18831 :               if (mpz_cmp_ui(biTmp, 0) == 0) /* (BigNbrIsZero(biTmp)) */
    1010             :               {
    1011       13564 :                 break;
    1012             :               }
    1013             :             }
    1014       13564 :             if (I == PM)
    1015             :             {
    1016             :               /* Not prime */
    1017           0 :               free_vars();
    1018           0 :               return APRTCLE_COMPOSITE;
    1019             :             }
    1020       23923 :             for (J = 1; J <= P - 2; J++)
    1021             :             {
    1022             :               /* AddBigNbrModN(aiJW[I + J * PM], 1, biTmp, TestNbr, NumberLength); */
    1023       10359 :               mpz_add_ui(biTmp, aiJW[I + J * PM], 1);
    1024       10359 :               mpz_mod(biTmp, biTmp, TestNbr);
    1025       10359 :               if (mpz_cmp_ui(biTmp, 0) != 0)/* (!BigNbrIsZero(biTmp)) */
    1026             :               {
    1027             :                 /* Not prime */
    1028           0 :                 free_vars();
    1029           0 :                 return APRTCLE_COMPOSITE;
    1030             :               }
    1031             :             }
    1032       13564 :             H = I + PL;
    1033             :           }
    1034             :           while (0);
    1035             : 
    1036       34919 :           if (SW == 1 || H % P == 0)
    1037             :           {
    1038       30230 :             continue;
    1039             :           }
    1040        4689 :           if (P != 2)
    1041             :           {
    1042        1022 :             SW = 1;
    1043        1022 :             continue;
    1044             :           }
    1045        3667 :           if (K == 1)
    1046             :           {
    1047        2207 :             if ((mpz_get_ui(TestNbr) & 3) == 1)
    1048             :             {
    1049         699 :               SW = 1;
    1050             :             }
    1051        2207 :             continue;
    1052             :           }
    1053             : 
    1054             :           // if (Q^((N-1)/2) mod N != N-1), N is not prime.
    1055             : 
    1056             :           /* MultBigNbrByLongModN(1, Q, biTmp, TestNbr, NumberLength); */
    1057        1460 :           mpz_set_ui(biTmp, Q);
    1058        1460 :           mpz_mod(biTmp, biTmp, TestNbr);
    1059             : 
    1060        1460 :           mpz_sub_ui(biT, TestNbr, 1); /* biT = n-1 */
    1061        1460 :           mpz_divexact_ui(biT, biT, 2); /* biT = (n-1)/2 */
    1062        1460 :           mpz_powm(biR, biTmp, biT, TestNbr); /* biR = Q^((n-1)/2) mod n */
    1063        1460 :           mpz_add_ui(biTmp, biR, 1);
    1064        1460 :           mpz_mod(biTmp, biTmp, TestNbr);
    1065             : 
    1066        1460 :           if (mpz_cmp_ui(biTmp, 0) != 0)/* (!BigNbrIsZero(biTmp)) */
    1067             :           {
    1068             :             /* Not prime */
    1069           0 :             free_vars();
    1070           0 :             return APRTCLE_COMPOSITE;
    1071             :           }
    1072        1460 :           SW = 1;
    1073             :         } /* end for j */
    1074        9792 :         if (SW == 0)
    1075             :         {
    1076        2534 :           TestedQs = TestingQs + 1;
    1077        2534 :           if (TestingQs < aiNQ[LEVELnow] - 1)
    1078             :           {
    1079        2438 :             TestingQs++;
    1080        2438 :             Q = aiQ[TestingQs];
    1081        2438 :             U = T * Q;
    1082             :             do
    1083             :             {
    1084             :               /* MultBigNbrByLong(biS, Q, biS, NumberLength); */
    1085        3128 :               mpz_mul_ui(biS, biS, Q);
    1086        3128 :               U /= Q;
    1087             :             }
    1088        3128 :             while (U % Q == 0);
    1089             : 
    1090        2438 :             continue; /* Retry */
    1091             :           }
    1092          96 :           LEVELnow++;
    1093          96 :           if (LEVELnow == LEVELmax)
    1094             :           {
    1095           0 :             free_vars();
    1096           0 :             return mpz_probab_prime_p(N, 1); /* Cannot tell */
    1097             :           }
    1098          96 :           T = aiT[LEVELnow];
    1099          96 :           NP = aiNP[LEVELnow];
    1100             :           /* biS = 2; */
    1101          96 :           mpz_set_ui(biS, 2);
    1102         384 :           for (J = 0; J <= aiNQ[LEVELnow]; J++)
    1103             :           {
    1104         384 :             Q = aiQ[J];
    1105         384 :             if (T%(Q-1) != 0) continue;
    1106         384 :             U = T * Q;
    1107             :             do
    1108             :             {
    1109             :               /* MultBigNbrByLong(biS, Q, biS, NumberLength); */
    1110        1072 :               mpz_mul_ui(biS, biS, Q);
    1111        1072 :               U /= Q;
    1112             :             }
    1113        1072 :             while (U % Q == 0);
    1114         384 :             if (CompareSquare(biS, TestNbr) > 0)
    1115             :             {
    1116          96 :               TestingQs = J;
    1117             :               /* continue MainStart; */ /* Retry from the beginning */
    1118          96 :               goto MainStart;
    1119             :             }
    1120             :           } /* end for J */
    1121           0 :           free_vars();
    1122           0 :           return mpz_probab_prime_p(N, 1); /* Program error */
    1123             :         } /* end if */
    1124        7258 :         break;
    1125             :       } /* end for (;;) */
    1126             :     } /* end for i */
    1127             : 
    1128             :     // Final Test
    1129             :    
    1130             :     /* biR = 1 */
    1131        2149 :     mpz_set_ui(biR, 1);
    1132             :     /* biN <- TestNbr mod biS */ /* Compute N mod S */
    1133        2149 :     mpz_fdiv_r(biN, TestNbr, biS);
    1134             :    
    1135    23891100 :     for (U = 1; U <= T; U++)
    1136             :     {
    1137             :       /* biR <- (biN * biR) mod biS */
    1138    23891100 :       mpz_mul(biR, biN, biR);
    1139    23891100 :       mpz_mod(biR, biR, biS);
    1140    23891100 :       if (mpz_cmp_ui(biR, 1) == 0) /* biR == 1 */
    1141             :       {
    1142             :         /* Number is prime */
    1143        2149 :         free_vars();
    1144        2149 :         return APRTCLE_PRIME;
    1145             :       }
    1146    23888951 :       if (mpz_divisible_p(TestNbr, biR) && mpz_cmp(biR, TestNbr) < 0) /* biR < N and biR | TestNbr */
    1147             :       {
    1148             :         /* Number is composite */
    1149           0 :         free_vars();
    1150           0 :         return APRTCLE_COMPOSITE;
    1151             :       }
    1152             :     } /* End for U */
    1153             :     /* This should never be reached. */
    1154           0 :     free_vars();
    1155           0 :     return mpz_probab_prime_p(N, 1);
    1156             :   }
    1157             : }
    1158             : 
    1159             : /* ============================================================================================== */

Generated by: LCOV version 1.14