/*----------------------------------------------------------------------+
|      Title:   PublicKey.java                                          |
|                                                                       |
|      Author:  David E. Joyce                                          |
|           Department of Mathematics and Computer Science              |
|           Clark University                                            |
|           Worcester, MA 01610-1477                                    |
|           U.S.A.                                                      |
|                                                                       |
|           http://aleph0.clarku.edu/~djoyce/                           |
|           djoyce@clarku.edu                                           |
|                                                                       |
|      Date:   Feb, 2006.                                               |
+----------------------------------------------------------------------*/

import java.awt.*;
import java.awt.event.*;
import java.applet.*;

public class PublicKey extends Applet
    implements ActionListener, KeyListener {

  final int MAXDEGREE = 5;
  TextArea  reportArea;
  Button makeKeysButton;
  TextField textp, textq, texte = new TextField();
  
  long p = 11, q = 13;      // The two prime numbers
  long e = 7;               // The encoding key
  long d;                   // The decoding key, computed later, inverse of e modulo phin
  long n = p*q;             // The modulus
  long phin = (p-1)*(q-1);  // Phi(n), Euler's totient function evaluated at n

  // Initialize the applet
  public void init() {
  
    // construct and place the components in the applet window
    BorderLayout appletLayout = new BorderLayout();
    appletLayout.setHgap(5);
    appletLayout.setVgap(5);
    setLayout(appletLayout);
    setFont(new Font("Serif",Font.PLAIN,12));

    // set up the report area
    reportArea = new TextArea(5,20);
    reportArea.setEditable(false);
    reportArea.append("\nSet primes p and q, select e relatively prime to both, then press MAKE KEYS.\n");
    add(reportArea);

    // Set up the control panel
    Panel controlPanel = new Panel();
    BorderLayout controlLayout = new BorderLayout();
    controlLayout.setHgap(20);
    controlPanel.setLayout(controlLayout);
    add("North",controlPanel);

    // The buttonPanel will make up part of the control panel
    Panel buttonPanel = new Panel();
    buttonPanel.setLayout(new GridLayout(2,1));
    controlPanel.add("West",buttonPanel);

    makeKeysButton = new Button("Make keys");
    makeKeysButton.addActionListener(this);
    buttonPanel.add(makeKeysButton);

    // set up the input panel
    Panel inputPanel = new Panel();
    inputPanel.setLayout(new FlowLayout());
    
    inputPanel.add(new Label("p: "));
    textp = new TextField(9);
    textp.setText(Long.toString(p));
    textp.addKeyListener(this);
    inputPanel.add(textp);
    
    inputPanel.add(new Label("q: "));
    textq = new TextField(9);
    textq.setText(Long.toString(q));
    textq.addKeyListener(this);
    inputPanel.add(textq);
    
    inputPanel.add(new Label("e: "));
    texte = new TextField(5);
    texte.setText(Long.toString(e));
    texte.addKeyListener(this);
    inputPanel.add(texte);

    controlPanel.add("East",inputPanel);
  } // init
  
    
  private void makeKeys() {
    reportArea.append("\n");
    
    // convert and check the inputs p, q, and e
    
    String text = textp.getText();
    try { p = Long.parseLong(text);}
    catch (NumberFormatException exc) {
       reportArea.append("\nThe value for p, \""+text+"\", is not an integer.");
       reportArea.append("\nEnter a prime number for p.");
       return;
    } // try/catch
    if (p <= 0) {
       reportArea.append("\nThe value p = "+p+" is not a positive integer.");
       reportArea.append("\nEnter a prime number for p.");
       return;    
    } // if
    
    text = textq.getText();
    try { q = Long.parseLong(text);}
    catch (NumberFormatException exc) {
       reportArea.append("\nThe value for q, \""+text+"\", is not an integer.");
       reportArea.append("\nEnter a prime number for q.");
       return;
    } // try/catch
    if (q <= 0) {
       reportArea.append("\nThe value q = "+q+" is not a positive integer.");
       reportArea.append("\nEnter a prime number for q.");
       return;    
    } // if
    
    text = texte.getText();
    try { e = Long.parseLong(text);}
    catch (NumberFormatException exc) {
       reportArea.append("\nThe value for e, \""+text+"\", is not an integer.");
       reportArea.append("\nEnter a positive integer for e.");
       return;
    } // try/catch
    if (e <= 0) {
       reportArea.append("\nThe value e = "+e+" is not a positive integer.");
       reportArea.append("\nEnter a positive integer for e.");
       return;    
    } // if
    
    
    if (!Mod.pseudoprime(p,2)) {
       reportArea.append("\nThe value of p = "+p+" is not a prime number.");
       reportArea.append("\nChose a different value for p.");
       return;
    } // if
    if (!Mod.pseudoprime(q,2)) {
       reportArea.append("\nThe value of q = "+q+" is not a prime number.");
       reportArea.append("\nChose a different value for q.");
       return;
    } // if
    
    if (p == q) {
       reportArea.append("\nThe values of p and q need to be different prime numbers.");
       reportArea.append("\nChose a different value for one of them."); 
       return;   
    }
    
    n = p*q;
    phin = (p-1)*(q-1);
    
    if (LongPair.GCD(e,phin) != 1) {
       reportArea.append("\nThe value of e = "+e
         +" is not relatively prime to (p-1)(q-1) = ("+(p-1)+")("+(q-1)+") = "+phin+".");
       reportArea.append("\nChose a different value for e.");
       return;
    } // if
    
    // compute the decoding key
    d = (new Mod(e,phin)).inverse().getValue();
    
    // report the keys
    reportArea.append("\n\nThe public key is (n,e)=("+n+","+e+").");
    reportArea.append("\nTo encode a message a, raise it to the e-th power modulo n.");
    reportArea.append("\nThe private key is (n,d)=("+n+","+d+").");
    reportArea.append("\nTo decode a message a, raise it to the d-th power modulo n.");
    reportArea.append("\nThe number n is the product of the two primes p = "+p
                       +" and q = "+q+".");
    reportArea.append("\nPhi(n) = (p-1)(q-1) = "+phin+".");
    
  } // makeKeys
  
  
  public void actionPerformed(ActionEvent ev) {
    if (ev.getActionCommand().equals("Make keys"))
      makeKeys();  
  } // actionPerformed

  public void keyPressed(KeyEvent ev) {}

  public void keyReleased(KeyEvent ev) {}

  public void keyTyped(KeyEvent ev) {}

} // applet

