Archive for the ‘Pari/GP’ Category

AfterMath issue 5 is out

30 November 2008 Leave a comment

It’s now the end of Semester 2 of 2008, all examinations are over and done with, and issue 5 of AfterMath is out for your reading pleasure. You can grab the latest issue here, hot off the digital press.

This issue contains articles covering topics such as:

  • the Hairy Ball Theorem
  • a differential equation variant of Gronwall’s inequality
  • a survey on Maxima
  • using PARI/GP to study number theory and cryptography

Mark Ioppolo’s article, “The Hairy Ball Theorem,” contains a proof of a version of Henri Poincare’s conjecture popularly known as the Hairy Ball Theorem. Poincare was able to provide a proof [5] of the version he conjectured, and Brouwer [1] provides a proof of a generalization of Poincare’s version. The proofs in [1, 5] rely upon rather advanced techniques, whereas Milnor’s proof [4] uses a clever argument that relies on less sophisticated techniques. Ioppolo’s article aims to recount Milnor’s clever arguments.

The article “Differential Inequalities” by Wilson Ong considers Gronwall’s inequality, a result originally published in [3]. Gronwall’s inequality is usually stated as follows [2]: Let x, \Psi and \chi be real continuous functions defined in \,[a, b], with \chi (t) \geq 0 for t \in [a, b]. Suppose that on \,[a, b] we have the inequality

x(t) \leq \Psi(t) + \displaystyle{\int_a^t} \chi(s) x(s) \, ds


x(t) \leq \Psi(t) + \displaystyle{\int_a^t} \chi(s) \Psi(s) \exp \left[ \displaystyle{\int_s^t} \chi(u) \, du \right] \, ds

This inequality is clearly an inequality involving integrals. Ong’s exposition covers a variant of this, where the Gronwall type inequalities involve first and second order differential equations.

In issue 4 of AfterMath, there’s an article on using the computer algebra system (CAS) Maxima to study basic linear algebra. In this issue (issue 5), Alasdair McAndrew’s article “A Morsel of Maxima” presents an overview of this venerable CAS. McAndrew first provides a sketch of Maxima’s history, followed by an outline of Maxima’s state as of March 2007. The article then considers various interfaces to Maxima, including command line based and graphical user interfaces. The remainder of the article surveys features of Maxima that are useful in studying undergraduate mathematics: arithmetic, polynomial and rational functions, calculus, linear algebra, basic Maxima programming, solving equations, differential equations, plotting, and help and documentation.

And there’s the article “Number Theory and Cryptography using PARI/GP” written by yours truly. It introduces various PARI/GP commands that are useful for studying elementary number theory and undergraduate cryptography, in particular the RSA public key cryptosystem. But be warned that the exposition on RSA and cryptography is for educational purposes only, and readers who require more detailed discussions should consult specialized texts on the subject.

Issue 5 also contains a section on mathematics jokes, as well as a section containing some basic mathematical problems.


  1. L. E. J. Brouwer. Uber Abbildung von Mannigfaltigkeiten. Math. Ann., pages 97-115, 1912.
  2. S. S. Dragomir. Some Gronwall Type Inequalities and Applications. Nova Science Publishers, Hauppauge, New York, USA, 2003.
  3. T. H. Gronwall. Note on the derivatives with respect to a parameter of the solutions of a system of differential equations. Ann. Math., 20(2):293-296, 1919.
  4. J. Milnor. Analytic proofs of the “Hairy Ball Theorem” and the Brouwer Fixed Point Theorem. The American Mathematical Monthly, 85(7):521-524, 1978.
  5. H. Poincare. Sur les courbes definies par les equations differentielles. J. Math. Pures. Appl., 4(1):167-244, 1885.

The shift cipher using Pari/GP

20 August 2008 Leave a comment

Representing letters

Let \Sigma = \{ \tt{A}, \tt{B}, \tt{C}, \dots, \tt{Z} \} be the set of capital letters of the English alphabet. Furthermore, let \Phi = \{ 65, 66, 67, \dots, 90 \} be the ASCII (American Standard Code for Information Interchange) encodings of the upper case English letters. Then Table 1 explicitly describes the mapping f : \Sigma \longrightarrow \Phi. To assign a message M written using the alphabet \Sigma to a number, we simply replace each letter of M with its corresponding integer.

ASCII encodings of English capital letters.

ASCII encodings of English capital letters.

Sometimes it is convenient to work with integers modulo 26. In that case, we subtract 65 from each ASCII encoding in Table 1 to obtain the modulo 26 encoding presented in Table 2. In other words, Table 2 explicitly describes the mapping f : \Sigma \longrightarrow \mathbb{Z}_{26}.

Encoding English capital letters using integers modulo 26.

Encoding English capital letters using integers modulo 26.

Shift cipher

The shift cipher encrypts and decrypts messages by shifting each letter along the alphabet by a certain number of positions. This cipher belongs to the category of private key cryptography. Thus any chosen key K can be used for both encryption and decryption. When shifting a letter along the alphabet \Sigma, it’s sometimes necessary to wrap around the alphabet. If x \in \Sigma is represented as a modulo 26 integer, shifting x by k positions is equivalent to addition modulo 26. The wrapping around is accomplished by reducing the result of the addition by modulo 26. Here’s a PARI/GP function that implements the shift operation:

/* Shift the capital letter "letter" by "shiftLength" number of positions
 * along the capital letters of the English alphabet. If necessary, this
 * operation will wrap back to the beginning of the alphabet. For example,
 * if letter = A and shiftLength = 3, then shift(letter, shiftLength)
 * returns "D". If letter = Y and shiftLength = 4, then
 * shift(letter, shiftLength) returns "C".
 * INPUT   letter   a capital letter of the English alphabet.
 *         shiftLength   an integer. Any integer would suffice, but if it is
 *            outside of the closed interval [0, 25] then shiftLength is
 *            equivalent to shiftLength mod 26.
 * OUTPUT   the capital English letter resulting from shifting "letter" by
 *          the specified number of positions. If "letter" is not a capital
 *          English letter, then -1 is returned.
shiftAlph(letter, shiftLength) = {
    local(CAPITAL_A, CAPITAL_Z, letterAscii, SHIFT);
    CAPITAL_A = 65;  /* ASCII encoding of 'A' */
    CAPITAL_Z = 90;  /* ASCII encoding of 'Z' */
    letterAscii = Vecsmall(letter)[1];
    SHIFT = 65;
    if (((CAPITAL_A <= letterAscii) && (letterAscii <= CAPITAL_Z)),

        /*** then block ***/
        letterAscii = ((letterAscii - SHIFT) + shiftLength) % 26;
        letterAscii = letterAscii + SHIFT;

        /*** else block ***/

Shifting the letter \texttt{A} by 3 positions results in \texttt{D}:

gp > shiftAlph("A", 3)
%3 = "D"

Furthermore, shifting \texttt{A} by -3 positions is equivalent to counting backwards from \texttt{Z} by 3 positions to get \texttt{X}. In terms of modular arithmetic, -3 positions is -3 \equiv 23 \pmod{26} so shifting \texttt{A} by -3 is the same as shifting that letter by 23 positions:

gp > shiftAlph("A", -3)
%4 = "X"
gp > Mod(-3, 26)
%5 = Mod(23, 26)
gp > shiftAlph("A", 23)
%6 = "X"

The shift cipher applies a shift key to each letter of the message M. In \mathbb{Z}_{26} encoding, it can be rather difficult to distinguish letters of M in a sequence of modulo 26 integers such as 012. The latter sequence can represent \texttt{ABC}, \texttt{AM}, \texttt{BC} or \texttt{M}. To keep track of the \mathbb{Z}_{26} encoding of M, we represent M as a list of capital letters, preserving position. The shifting could then operate on each list element in turn. The following function returns the list representation of a string over \Sigma:

/* Splice up the characters in a string and insert those characters into a
 * list. That is, we obtain the list representation of a string, where each
 * character of the string is an element of the list. The order of the
 * characters is preserved in the list representation.
 * INPUT   str   a string of characters.
 * OUTPUT   the list representation of the specified string. If the string is
 *          empty, then -1 is returned. It should be noted that the string ""
 *          is an empty string, while " " is a string containing the character
 *          ' ' obtained by a single stroke of the spacebar.
str2list(str) = {
    local(asciiInts, charList);
    if (str != "",

        /*** then block ***/
        asciiInts = Vecsmall(str);
        charList = listcreate(length(asciiInts));
        for (i = 1, length(asciiInts),
            listput(charList, Strchr(asciiInts[i]));

        /*** else block ***/

For example, here’s a list representation of the string \texttt{ABC}:

gp > str2list("ABC")
%7 = List(["A", "B", "C"])

Encryption in the shift cipher

Suppose elements of \Sigma are represented using modulo 26 encoding as given in Table 2. A key of the shift cipher is an integer k such that 0 \leq k \leq 25, that is, k \in \mathbb{Z}_{26}. For each x \in \mathbb{Z}_{26}, the encryption function \mathcal{E} : \mathbb{Z}_{26} \longrightarrow \mathbb{Z}_{26} is given by

\mathcal{E} : x \longmapsto x + k \pmod{26}

The following PARI/GP function implements this encryption process:

/* Encrypt a plaintext using the shift cipher.
 * INPUT   plaintext   the plaintext to be encrypted. The plaintext is
 *            assumed to contain only capital English letters, without space
 *            or punctuation characters.
 *         key   the encryption key. Any non-negative integer would suffice,
 *            but if it is outside of the closed interval [0, 25] then
 *            key is equivalent to key mod 26.
 * OUTPUT   the ciphertext corresponding to the specified plaintext, encrypted
 *          using the shift cipher with key "key". If any character of the
 *          plaintext is not a capital English letter, or the plaintext is an
 *          empty string, then -1 is returned.
shiftEncrypt(plaintext, key) = {
    local(charList, char);
    charList = str2list(plaintext);
    if (charList != -1,

        /*** then block ***/
        for (i = 1, length(charList),
            char = shiftAlph(charList[i], key);
            if (char != -1,
                /*** then block ***/
                charList[i] = char,

                /*** else block ***/

        /*** else block ***/

Suppose we want to encrypt the message M = \texttt{HELLOWORLD} using the shift cipher. Let our key be k = 17. Here’s how we obtain the ciphertext corresponding to M:

gp > M = "HELLOWORLD";
gp > k = 17;
gp > C = shiftEncrypt(M, k)

Thus our required ciphertext is C = \texttt{YVCCFNFICU}.

Decryption in the shift cipher

The decryption function corresponding to \mathcal{E} is \mathcal{D} : \mathbb{Z}_{26} \longrightarrow \mathbb{Z}_{26}, given by

\mathcal{D} : x \longmapsto x - k \pmod{26}

Here’s a PARI/GP function implementing the decryption process:

/* Decrypt a ciphertext using the shift cipher.
 * INPUT   ciphertext   a ciphertext encrypted using the shift cipher with
 *            key "key". It is assumed that the ciphertext consists of only
 *            capital letters of the English alphabet, without space or
 *            punctuation characters.
 *         key   the encryption key. Any non-negative integer would suffice,
 *            but if it is outside of the closed interval [0, 25] then
 *            key is equivalent to key mod 26.
 * OUTPUT   the plaintext corresponding to the specified ciphertext, decrypted
 *          using the shift cipher with key "key". If any character of the
 *          ciphertext is not a capital letter of the English alphabet, or
 *          the ciphertext is an empty string, then -1 is returned.
shiftDecrypt(ciphertext, key) = {
    local(charList, char);
    charList = str2list(ciphertext);
    if (charList != -1,

        /*** then block ***/
        for (i = 1, length(charList),
            char = shiftAlph(charList[i], -key);
            if (char != -1,
                /*** then block ***/
                charList[i] = char,

                /*** else block ***/

        /*** else block ***/

To decrypt the ciphertext C = \texttt{YVCCFNFICU} using the key k = 17, we proceed as follows:

gp > shiftDecrypt(C, k)

Notice that the last output is precisely our original message.

Brute force attack

Without knowing the value of the key, we can mount a brute force attack on the shift cipher. A brute force attack on a cryptosystem attempts to decrypt a ciphertext using all possible keys within that cryptosystem. As each key of the shift cipher is an element of \mathbb{Z}_{26}, there are precisely 26 possible keys with which we can use to decrypt a ciphertext. The following function attempts a brute force decryption on a given ciphertext encrypted using the shift cipher:

/* An attempt to crack a ciphertext using the brute force attack. All
 * possible keys will be tried on the ciphertext. As the shift cipher shifts
 * capital letters along the English alphabet, there are only 26 distinct
 * possible keys to try.
 * INPUT   ciphertext   a ciphertext encrypted using the shift cipher. It is
 *            assumed that the ciphertext is comprised of only capital letters
 *            of the English alphabet, without any white space or
 *            punctuation characters.
 * OUTPUT   For each of the 26 distinct possible keys, return the
 *          decrypted counterpart of "ciphertext" using that key. If any
 *          character of the ciphertext is not a capital English letter, then
 *          -1 is returned.
shiftBruteforce(ciphertext) = {
    for (i = 1, 26,
        print("key = ", i, "   ", shiftDecrypt(ciphertext, i));


To mount a brute force attack on the ciphertext C = \texttt{YVCCFNFICU}, we proceed as follows:

gp > shiftBruteforce(C)

From the above list of 26 possible plaintexts, we see that our original message is contained in the line \verb!key = 17 HELLOWORLD!. Not only have we recovered our original message, but we also obtain the encryption/decryption key.

Pari/GP programming for basic cryptography

1 August 2008 5 comments

In studying cryptography, there are occasions in which we need to convert a string of plaintext characters into an integer. The integer corresponding to the plaintext string can then be encrypted using various encryption schemes that operate on numbers. A case in point is the RSA public key cryptosystem. Encryption and decryption in RSA work with integers and use number theoretic operations. Given a plaintext p represented as a string of characters, we require a way to convert p to an integer prior to encryption. Furthermore, if c is the ciphertext corresponding to p, then it is most likely that c is an integer. After decrypting c, we recover the original integer representation of p.

In this post, we use PARI/GP to study the RSA cryptosystem. The reader is assumed to have some familiarity with basic concepts from elementary number theory, basic programming constructs, and public key cryptography, in particular, the RSA cryptosystem. This post is not a beginner’s howto on PARI/GP. We assume that the reader has some prior experience in using PARI/GP.

What is PARI/GP?

The computer algebra system PARI/GP [2] is primarily aimed at computation in number theory. It can be used as a powerful, programmable desktop calculator similar to the Linux command \texttt{bc}. It can also be used to study number theory and basic cryptography. Here are screenshots of PARI/GP sessions under Linux and Windows:

A PARI/GP session under Ubuntu Linux.

A PARI/GP session under Windows.

A PARI/GP session under Windows XP.

Strings to numbers & vice versa

PARI/GP provides two commands to convert from a string of characters to integers and vice versa. The command \texttt{Vecsmall} is able to convert a character string into a corresponding vector of ASCII encodings. Let M be the plaintext string \texttt{HELLO WORLD}. To get a vector of ASCII encodings corresponding to M, we proceed as follows:

gp > M = "HELLO WORLD"
gp > P = Vecsmall(M)
%2 = Vecsmall([72, 69, 76, 76, 79, 32, 87, 79, 82, 76, 68])

Now P is a vector of ASCII encodings. Notice that \texttt{H} has the ASCII encoding \texttt{72}, \texttt{E} has the encoding \texttt{69} and so on. We also need to pay particular attention to the white space between \texttt{HELLO} and \texttt{WORLD}. The white space character that is obtained with the spacebar key has ASCII encoding \texttt{32}. To convert P to a character string, we use the command \texttt{Strchr}:

gp > Strchr(P)

We need to concatenate all ASCII encodings in the vector P to obtain an integer corresponding to the message M. This can be accomplished using the command \texttt{Str}, which concatenates all of its arguments into a single string. The result of concatenating all elements of the vector P is a string representation of an integer. We need to somehow convert that string into the integer that it represents. One simple method is to assign the digits to some variable, excluding the double quotation characters:

gp > a = "";
gp > for (i = 1, length(P), a = Str(a,P[i]))
gp > a
%5 = "7269767679328779827668"
gp > a = 7269767679328779827668
%6 = 7269767679328779827668

The RSA cryptosystem

We now consider the RSA algorithm for encryption and decryption. The following is a list of steps in this algorithm, taken from the book [3, p.165]:

  1. Choose two primes p and q and let n = pq.
  2. Let e \in \mathbb{Z} be positive such that \gcd \big( e, \varphi(n) \big) = 1.
  3. Compute d \in \mathbb{Z} such that de \equiv 1 \pmod{\varphi(n)}.
  4. Our public key is the pair (n,e) and our private key is the triple (p,q,d).
  5. For any non-zero integer m, encrypt m using c \equiv m^e \pmod{n}.
  6. Decrypt c using m \equiv c^d \pmod{n}.

Public and private keys

Choosing a prime number is easy. PARI/GP provides a list of precomputed primes, accessible via the command \texttt{primes}. For example, \texttt{primes(100)} returns a list of the first 100 primes. The command \texttt{random(n)} returns a pseudo-random integer k such that 0 \leq k \leq n-1. Thus we can work through step 1 in the algorithm as follows:

gp > p = primes(40000)[random(40000) + 1]
%7 = 338251
gp > q = primes(40000)[random(40000) + 1]
%8 = 140333
gp > n = p * q
%9 = 47467777583

For step 2, we need to find a positive integer that is coprime to \varphi(n), called Euler’s totient (or phi) function. The command \texttt{eulerphi(n)} counts the number of integers k, with 1 \leq k \leq n, such that \gcd( k,n) = 1. The greatest common divisor of two integers can be computed using the command \texttt{gcd}. Using a loop, we can compute the required value of e as follows:

gp > e = random(eulerphi(n))
%10 = 43556566359
gp > while (gcd(e, eulerphi(n)) != 1, e = random(eulerphi(n)))
gp > e
%11 = 3511612661

To calculate a value for d in step 3, we use the extended Euclidean algorithm. By definition of congruence, the congruence

de \equiv 1 \pmod{\varphi(n)}

is equivalent to

de - k \cdot \varphi(n) = 1

where k \in \mathbb{Z}. From above, we already know the numeric values of e and \varphi(n). The extended Euclidean algorithm allows us to compute d and -k. In PARI/GP, this can be accomplished via the command \texttt{bezout}. Given two integers x and y, the command \texttt{bezout(x, y)} returns a vector \texttt{[u, v, g]} such that g = \gcd(x,y) and ux + vy = g:

gp > d = bezout(e, eulerphi(n))[1]
%12 = 5558100941

Thus our RSA public key is (n, e) = (47467777583,\, 3511612661) and our corresponding private key is (p, q, d) = (338251,\, 140333,\, 5558100941).

Encryption and decryption

Recall that our message is the string \texttt{HELLO WORLD}, which can be represented by the integer \texttt{m = 7269767679328779827668}. To encrypt our message, we raise m to the power of e and reduce the result modulo n. The command \verb!Mod(a^b, n)! first computes \verb!a^b!, then reduces the result modulo \texttt{n}. If the exponent \texttt{b} is a “large” integer, say with more than 20 digits, then performing modular exponentiation takes more than a few seconds. Sometimes this can result in the PARI stack to overflow. Brute force modular exponentiation is inefficient and, when performed using a computer, can quickly consume the computer’s memory.

There is a trick to efficiently perform modular exponentiation. Called the squaring trick, or the method of repeated squaring [1, p.879], we use the binary representation of the exponent to repeatedly perform squaring and reduce the running result modulo some fixed integer. The following is a PARI/GP script to perform modular exponentiation using repeated squaring. The pseudocode can be found in [1, p.879].

/* Modular exponentiation using repeated squaring. */
/* That is, we want to compute a^b mod n. */
modexp(a, b, n) = { \
    local(d, bin); \
    d = 1; \
    bin = binary(b); \
    for (i = 1, length(bin), \
        d = Mod(d*d, n); \
        if (bin[i] == 1, \
            d = Mod(d*a, n); \
        ); \
    ); \
    return(d); \

The script can be saved to a file called, say, \texttt{/home/mvngu/}. The file can then be read into PARI/GP using the command \verb!\r!. Notice the backslash character \verb!\ ! at the end of each line, except for the last line. This character tells PARI/GP that the script continues on the next line. If we perform brute force modular exponentiation, we would get something similar to the following:

gp > m = 7269767679328779827668;
gp > Mod(m^e, n)
*** length (lg) overflow

On the other hand, let us read our script into PARI/GP and perform modular exponentiation using repeated squaring:

gp > \r /home/mvngu/
gp > modexp(m, e, n)
%14 = Mod(16017121090, 47467777583)
gp > c = 16017121090
%15 = 16017121090

Thus \texttt{c = 16017121090} is the ciphertext. To recover our plaintext, we raise \texttt{c} to the power of \texttt{d} and reduce the result modulo \texttt{n}. Again, we can use modular exponentiation via repeated squaring to decrypt \texttt{c}:

gp > modexp(c, d, n)
%16 = Mod(32758012945, 47467777583)
gp > Mod(m, n)
%17 = Mod(32758012945, 47467777583)

Although our result is \texttt{32758012945}, this integer is equivalent to \texttt{m = 7269767679328779827668} modulo \texttt{n = 47467777583}. Hence we have recovered our plaintext.


  1. T. H. Cormen, C. E. Leiserson, R. L. Rivest and C. Stein. Introduction to Algorithms (2nd ed.). The MIT Press, 2001.
  2. PARI/GP version 2.3.4, Bordeaux, France, 2008, viewed 2008-07-31
  3. W. Trappe and L. C. Washington. Introduction to Cryptography with Coding Theory (2nd ed.). Pearson Prentice Hall, 2006.