Sindbad~EG File Manager

Current Path : /usr/home/beeson/MathXpert/bignums/
Upload File :
Current File : /usr/home/beeson/MathXpert/bignums/bigmod.c

/*  Arithmetic mod m,  where m is a bignum  */
/*  Strong pseudoprime test                 */
/*
3.7.90 first draft
5.21.91 completed
1.14.93 corrected space allocation errors in pseudoprime
11.18.93 added heap.h
5.3.94  modified for Windows
1.29.98 last modified for Microsoft Visual C++
4.6.04  rewrote pseudoprime following CLRS p. 891
        Moved primality_test into this file from nfactor.c
4.6.04 corrected primality_test, where the test for being less than 25 billion 
        up to now presumed 16-bit digits.  Removed display_progress from primality_test.
        Rewrote primality_test to call rand() so it is the Miller-Rabin primality test.
*/

#include <stdlib.h>
#include <time.h>
#include <string.h>  /* memset */
#include <assert.h>

#include "heap.h"
#include "bignum.h"
/*  in modular arithmetic mod m,  we arrange that all bignums have
m.ln + 1 digits allocated, so that they can be used as quotients
for receiving answers from bigdivide by m.  */

#define MAKEMOD(m,u)  (u).val = getspace((m).ln + 2)
/*________________________________________________________________*/

void mod2(bignum m, bignum u, bignum *ansp)
/* reduce u mod m */
/*  ansp->val must have m.ln +1 digits allocated */
{  int test;
   bignum q;
   digit ansdigit;
   if( m.ln == 1)  /*  m is really just a digit */
     {if( u.ln == 1 && (u.val[0] < m.val[0] ))
         { ansp->ln = 1;
           ansp->val[0] = u.val[0];
           return;
         }
      if( u.ln == 1 )
         { ansp->ln = 1;
           ansp->val[0] = u.val[0] % m.val[0];
           return;
         }
       /* if we get here then m has only one digit but u has more than one */
      { divide_by_digit(u,m.val[0],&q,&ansdigit);
        ansp->ln = 1;
        ansp->val[0] = ansdigit;
        freespace(q.val);
        return;
      }
     }
   test = compare(u,m);
   if( test < 0)
      { ansp->ln = u.ln;
        memcpy(ansp->val,u.val,u.ln*sizeof(digit));
        return;
      }
   if(test == 0)
      { ansp->ln = 1;
        ansp->val[0] = 0;
        return;
      }
   else
     {  MAKEMOD(m,q);
        bigdivide2(u,m,&q,ansp);  /* assumes divisor is less than dividend */
        freespace(q.val);
      }
    return;
 }
/*____________________________________________________________*/

void mod(bignum m, bignum u, bignum *ansp)
/* reduce u mod m  returning in freshly allocated space */
{
  MAKEMOD(m, *ansp);
  mod2(m,u,ansp);
}
/*___________________________________________________________________*/
void bigplusmod2(bignum m, bignum a, bignum b, bignum *ans)
/* compute a+b mod m, where 0 <= a < m and 0 <= b < m */
/* assume *ans has m.ln + 1 digits available */
{ bigplus2(a,b,ans);
  if( compare(m,*ans) != 1)
     bigminus2(*ans,m,ans);
  return;
}
/*____________________________________________________________________*/
void bigplusmod(bignum m, bignum a, bignum b, bignum *ans)
/* compute a+b mod m, where 0 <= a < m and 0 <= b < m */
/* allocate space for the answer */
{ MAKEMOD(m,*ans);
  bigplusmod2(m,a,b,ans);
}
/*___________________________________________________________________*/
void bigmultmod2(bignum m, bignum a, bignum b, bignum *ans)
/* compute a*b mod m for 0 <= a,b < m  */
/* assumes space already allocated for the answer */
/* bigmultmod(m,a,a,&a) is ok */

{ bignum temp;
  bigmult(a,b,&temp);
  mod2(m,temp,ans);
  freespace(temp.val);
}
/*___________________________________________________________________*/
void bigmultmod(bignum m, bignum a, bignum b, bignum *ans)
/* allocates space for the answer */
{ MAKEMOD(m,*ans);
  bigmultmod2(m,a,b,ans);
}
/*___________________________________________________________________*/
/*  compute  u^x mod m  where u, x and m are bignums */
/*  assuming 0 <= u < m */

/*  Algorithm 3.3, page 34 of Bressoud, Factorization and Primality Testing */
/*  adapted to the realities of bignum arithmetic;  two variables neven and
    nodd are used instead of one variable n, to avoid copying; space is
    for the answer,  workspace is freed before returning;  nonzero return
    value signals error, either out of space or attempt to compute 0^0 mod m.
    Unlike most bignum algorithms, the one that puts the answer in
    specified storage is defined in terms of the one that allocates storage.
*/

void modexp2(bignum m, bignum u, bignum x, bignum *ansp)
/* puts the answer in preallocated space */
{ bignum ans;
  modexp(m,u,x,&ans);   /* allocates space for the answer */
  ansp->ln = ans.ln;
  memcpy(ansp->val,ans.val,ans.ln * sizeof(digit));
  freespace(ans.val);
}

/*______________________________________________________________*/

void modexp(bignum m, bignum u, bignum x, bignum *ansp)
{ bignum a;  /* local copy of u */
  bignum b;  /* local copy of x */
  int ctr;
  bignum neven,nodd;  /* workspace */
  MAKEMOD(m,a);
  assert(u.ln <= m.ln);
  a.ln = u.ln;
  memcpy(a.val,u.val,a.ln * sizeof(digit));    /* make a copy of u */
  if( x.ln == 1 && x.val[0] == 0) /*  x = 0, so fail unless a= 0 also */
     { if (a.ln == 1 && a.val[0] == 0)
          assert(0);   /*error, 0^0 mod m */
       else { a.ln = 1; a.val[0] = 1; return;}
     }
     /* Now x isn't zero and a < m ; make b a copy of x */
  b.val = getspace(x.ln + 1); b.ln = x.ln;
  memcpy(b.val,x.val,x.ln *sizeof(digit));

  MAKEMOD(m,neven);     /* set up workspace */
  MAKEMOD(m,nodd);
  neven.ln = 1; neven.val[0] = 1;   /* initialize n= (bignum) 1 */
  ctr = 0;
  while (b.ln != 1 || b.val[0] != 0 )   /* while b != 0 */
     {  if (b.val[0] & 1)                      /* if b is odd */
          { if( ctr & 1)
               bigmultmod2(m,nodd,a,&neven);
            else
               bigmultmod2(m,neven,a,&nodd);
            ++ctr;
          }
        right_shift(b,1,&b);   /*  b = (integer)(b/2)  */
        bigmultmod2(m,a,a,&a);       /*  a = a*a mod m */
     }
 if (ctr & 1)    /* ctr is odd, so answer is in nodd */
    {
     ansp->ln = nodd.ln;
     ansp->val = nodd.val;
     freespace(neven.val);
    }
 else            /* ctr is even, so answer is in neven */
    {
     ansp->ln = neven.ln;
     ansp->val = neven.val;
     freespace(nodd.val);
    }
}

/*____________________________________________________________________*/
static  int pseudoprime(bignum n, bignum x)
/*  apply strong pseudoprime test to n using x as the base.
n  is assumed to be odd.
After CLRS page 891; compare also Knuth vol. 2 page 379.
Return value 1 means passed the test, is a pseudoprime.
Return value 0 means flunked the test, is definitely composite.
*/

{ unsigned j;
  int i = 0;
  int offset=0;
  unsigned k = 0;
  bignum q,y,temp;
  q.val = getspace(n.ln + 2);  /* the 2 extra is needed because q is used
                       below to hold a quotient from bigdivide2, which requires
                       2 extra quotient digits */
  temp.val = getspace(2*n.ln + 2);
  memcpy(q.val,n.val, n.ln * sizeof(digit));
  q.ln = n.ln;
  --q.val[0];   /*  q = n-1, since n is odd */
  while (q.val[0] == 0)  /* take out k factors of 2 */
     { ++q.val;
       ++offset;   /* keep track of it so we can free q.val correctly */
       k+= NN;
       --q.ln;
     }
  while((q.val[0] & (1 << i)) == 0)
     ++i;
  right_shift(q,i,&q);
  k += i;   /* now n = 1 + 2^k q where q is odd */
  if(q.ln == 1 && q.val[0] == 1)  /* n = 1 + 2^k */
     { MAKEMOD(n,y);
       y.ln = x.ln;  /* make y a copy of x without calling modexp */
       memcpy(y.val,x.val,y.ln *sizeof(digit));
     }
  else
     modexp(n,x,q,&y);   /* (Step P2) y = x^q mod n */
  q.val -= offset;
    /* Now q.val points to n.ln + 2 digits of valid space again */
  for(j=0;j<k;j++)
    { int flag = 0; // set it if y == n-1 or y == 1
      if(y.ln == n.ln)   /* then check if y == n-1  */
         { for(i=y.ln-1; i >= 0; --i)
              { if (y.val[i] != n.val[i])
                    break;
              }
           if(i==0 && y.val[0] +1 == n.val[0])  /* then y == n-1 */
               flag = 1;
         }
      if(y.ln == 1 && y.val[0] == 1)
         flag = 1;  // y is 1
      bigmult2(y,y,&temp);   /* two lines for y = y* mod n */
      bigdivide2(temp,n,&q,&y);
      if(!flag && y.ln==1 && y.val[0]==1)
         goto fail;  // y is a nontrivial square root of 1 mod n, so n is composite
    }
 if(y.ln == 1 && y.val[0] == 1)
    goto pass;
 fail:
    freespace(temp.val);
    freespace(y.val);
    freespace(q.val);
    return 0;   /* definitely not prime, flunks the test */
 pass:
    freespace(temp.val);
    freespace(y.val);
    freespace(q.val);
    return 1;  /* pass the test */
}
/*___________________________________________________________________*/
#define NPSEUDOPRIMETESTS 20
static unsigned tests[] = {2,3,5};

/* The following is the Miller-Rabin primality test. 
The chance of it saying that a composite number is prime
is less that (1/2)^ N PSEUDOPRIMETESTS, i.e. less than 
one in a million with NPSEUDOPRIMETESTS set to 20.
Compare CLRS page 891.
*/

int primality_test(bignum b)
/* return 0 if
      (a) it's less than 25 billion, passes the strong pseudoprime test for
             2,3,5, and isn't 151*171*28351
      (b) it passes the strong pseudoprime test for
             the first NPSEUDOPRIMETESTS odd integers
   Return 1 if definitely composite, i.e. flunks the test
*/
{  bignum x;
   int i,prime;
   unsigned j;
   x.val = getspace(b.ln);
   if(b.ln == 1 || (b.ln == 2 && b.val[1] <= 6))  /* b < 25 billion appx */
       { for(i=0;i<3;i++)
            { x.val[0] = tests[i];
              if(!pseudoprime(b,x))
                  return 1;   /* flunks the test, definitely composite */
            }
         if( b.ln == 1 && b.val[0] == 3215031751UL)
            { /* 3215031751  is the one number < 25 billion that passes the
                 primality test, see Bressoud page 78 */
              return 1;   /* composite, factors are 151, 171, 28351 */
            }
         return 0;    /* definitely prime */
       }
   /* Now the number is more than 25 billion */
   srand((unsigned)time(NULL));
   for(i=0;i<= NPSEUDOPRIMETESTS ;i++)
       { x.ln = b.ln -1;  // at least 1
         for(j=0;j<x.ln;j++)
            { unsigned t1 = rand();
              unsigned t2 = rand(); 
              x.val[j] = t1 << 16 | t2;  
              /* t1 and t2 are between 0 and RAND_MAX, which is 0x7fff,
                 the largest 16-bit signed integer.  So these digits aren't
                 quite random because they always have bits 15 and 31 zero.
                 But they're random enough. 
              */
            }
         if(x.val[x.ln-1] == 0)
            x.val[x.ln-1] = 1;  /* force it to be nonzero and have x.ln digits */
         prime = pseudoprime(b,x);
         /* pseudoprime returns 1 if it passes the test */
         if(!prime)
           return 1;
       }
   freespace(x.val);
   return 0;   /* passes the test for 2 and the first 100 odd integers */
}



Sindbad File Manager Version 1.0, Coded By Sindbad EG ~ The Terrorists