

/*****************************************************************************\

MODULE: ZZ_p

SUMMARY:

The class ZZ_p is used to represent integers mod p.
The modulus p may be any positive integer, not necessarily prime.
Here is a simple program that reads a modulus p,
and then reads two numbers and prints their product mod p.

#include "ZZ_p.h"

main()
{
   ZZ p;

   cin >> p;  
   ZZ_pInit(p);

   ZZ_p a, b, prod;

   cin >> a;  
   cin >> b;
   mul(prod, a, b);
   cout << prod << "\n";
}

Objects of the class ZZ_p are represented as a ZZ in the range 0..p-1.

An executing program maintains a "current modulus",
which is set to p using ZZ_pInit(p).
The current modulus *must* be initialized before any ZZ_p constructors
are invoked.

The modulus may be changed, and a mechanism is provided
for saving and restoring a modulus.
When the modulus is changed, there may be extant ZZ_p objects.
These objects may be destroyed at any later time.
If the old modulus was saved and then later restored, these objects can be
used again as if the modulus had never changed.
Note, however, that if a ZZ_p object is created under
one modulus and then used in any way under another,
this condition is not checked for and program behavior is
not predictable when this happens.

\*****************************************************************************/

#include "ZZ.h"

class ZZ_p {
public:
   
   ZZ_p(); // initial value 0
   ZZ_p(const ZZ_p& a);
   void operator=(const ZZ_p& a);
   ~ZZ_p();
   
   ZZ_p(INIT_VAL_TYPE, const ZZ& a); 
   // Initial value (a mod p).  Invoke as ZZ_p(INIT_VAL, a)
   
   ZZ_p(INIT_VAL_TYPE, long a);
   // Initial value (a mod p).  Invoke as ZZ_p(INIT_VAL, a)
   
   static const ZZ& modulus();
   // read-only access to modulus p.
   
   static long ModulusSize();
   // return ZZ_p::modulus().size()
   
   static const ZZ_p& zero();
   // read-only access to 0
   
   
   /* The following is an error-handler for division */
   
   typedef void (*DivHandlerPtr)(const ZZ_p& a);   
   static DivHandlerPtr DivHandler;

};


void ZZ_pInit(const ZZ& p); 
// set the modulus to p, where p > 1.
// This must be called before any ZZ_p constructors are invoked.

const ZZ& rep(const ZZ_p& a); // read-only access to representation

void clear(ZZ_p& x); // x = 0

void set(ZZ_p& x); // x = 1

void swap(ZZ_p& x, ZZ_p& y); 
// swap x and y by swapping pointers, if possible;
// otherwise by copy.


/*****************************************************************************\

                                    Addition 

\*****************************************************************************/

void add(ZZ_p& x, const ZZ_p& a, const ZZ_p& b); // x = a + b

void add(ZZ_p& x, const ZZ_p& a, long b); // x = a + b
void add(ZZ_p& x, long a, const ZZ_p& b); // x = a + b

void sub(ZZ_p& x, const ZZ_p& a, const ZZ_p& b); // x = a - b 
void sub(ZZ_p& x, const ZZ_p& a, long b); // x = a - b 
void sub(ZZ_p& x, long a, const ZZ_p& b); // x = a - b 

void negate(ZZ_p& x, const ZZ_p& a); // x = -a


/*****************************************************************************\

                                  Multiplication 

\*****************************************************************************/


void mul(ZZ_p& x, const ZZ_p& a, const ZZ_p& b); // x = a * b

void mul(ZZ_p& x, const ZZ_p& a, long b); // x = a * b 
void mul(ZZ_p& x, long a, const ZZ_p& b); // x = a * b

void sqr(ZZ_p& x, const ZZ_p& a); // x = a^2


/*****************************************************************************\

                                     Division

\*****************************************************************************/


void div(ZZ_p& x, const ZZ_p& a, const ZZ_p& b);
// x = a/b
// If b != 0 and b not invertible and DivHandler != 0,
// then DivHandler will be called with the offending b.
// In this case, of course, p is not really prime, and one

// can factor p by taking a gcd with rep(b).
// Otherwise, if b is not invertible, an error occurs.

void div(ZZ_p& x, const ZZ_p& a, long b);
void div(ZZ_p& x, long a, const ZZ_p& b);

void inv(ZZ_p& x, const ZZ_p& a);
// x = 1/a
// Error handling is the same as above.


/*****************************************************************************\

                                  Exponentiation

\*****************************************************************************/


void power(ZZ_p& x, const ZZ_p& a, long e); // x = a^e (e >= 0)

void power(ZZ_p& x, const ZZ_p& a, const ZZ& e); // x = a^e (e >= 0)


/*****************************************************************************\

                                  Conversion

\*****************************************************************************/

void operator<<(ZZ_p& x, const ZZ& a); // x = (a mod p)

void operator<<(ZZ_p& x, long a); // x = (a mod p)

void operator<<(ZZ& x, const ZZ_p& a); // x = rep(a)

/*****************************************************************************\

                                  Comparison

\*****************************************************************************/

long IsZero(const ZZ_p& a);  // test for 0

long IsOne(const ZZ_p& a);  // test for 1

long operator==(const ZZ_p& a, const ZZ_p& b);
long operator!=(const ZZ_p& a, const ZZ_p& b);


/*****************************************************************************\

                               Random Elements

\*****************************************************************************/


void random(ZZ_p& x);
// x = random element in ZZ_p.
// Uses RandomBnd from ZZ.


/*****************************************************************************\

                                Input/Output

\*****************************************************************************/


ostream& operator<<(ostream& s, const ZZ_p& a);

istream& operator>>(istream& s, ZZ_p& x);
// a ZZ is read and reduced mod p

/*****************************************************************************\

                       Modulus Switching 

Generally you do the following:

   ZZ_pBak bak;
   bak.save();   // save current modulus (if any)

   ZZ_pInit(p);  // set modulus to desired value p

      // ...

   bak.restore(); // restore old modulus (if any)

Note that between the save and restore, you may have
several calls to ZZ_pInit, each of which simply clobbers
the previous modulus.

\*****************************************************************************/


class ZZ_pBak {
public:

   ZZ_pBak();
   ~ZZ_pBak();

   void save();
   // bak.save() moves the current modulus into bak.
   // It clobbers whatever was previously saved in bak, and effectively
   // makes the current modulus "empty".
   // If this modulus is not restored before the destructor is
   // is called, the destructor will restore it.

   void move();
   // same semantics as save(), except that if this modulus
   // is not restored before the destructor is called, the
   // destructor will not restore it.

   // The main reason for these two different methods is in
   // the context of exceptions: a saved modulus will automatically
   // be restored, while a moved modulus will not.

   void restore();
   // bak.restore() moves the modulus stored in bak into the current modulus.
   // It clobbers the current modulus, and effectively makes the contents
   // of bak "empty"

private:

   ZZ_pBak(const ZZ_pBak&);  // disabled
   void operator=(const ZZ_pBak&);  // disabled
};

