/** * An implementation of the protocol described * in "Coin Flipping by Telephone" by Manuel Blum, * ACM SIGACT News 15 (1), Winter-Spring 1983, pp. 23 - 27. * * @author Rob Simmons * @author Andrew Appel **/ import java.awt.*; import java.awt.event.*; import javax.swing.*; import javax.swing.event.*; import java.math.BigInteger; import java.util.Random; class Calculations { /** A few useful "global" BigIntegers **/ BigInteger zero = BigInteger.ZERO; BigInteger one = BigInteger.ONE; BigInteger two = BigInteger.valueOf(2); BigInteger three = BigInteger.valueOf(3); BigInteger four = BigInteger.valueOf(4); BigInteger seven = BigInteger.valueOf(7); BigInteger eight = BigInteger.valueOf(8); BigInteger neg_one = one.negate(); /** Random number generator (provided by Java) **/ Random rand = new Random(); /** Find an acceptable prime (equal to 3 mod 4) **/ BigInteger makeBlumInt(int size) { for(;;) { BigInteger p = BigInteger.probablePrime(size,rand); if (p.mod(four).equals(three)) return p; } } /** Calculate x^2 mod n **/ BigInteger squareMod(BigInteger x, BigInteger n) { return x.multiply(x).mod(n); } /** Calculate the Jacobi Number of x and n **/ int jacobi(BigInteger x, BigInteger n) { if (! x.gcd(n).equals(one)) return 0; if (x.equals(one)) return 1; if (x.equals(two)) { BigInteger nmod8 = n.mod(eight); if (nmod8.equals(one) || nmod8.equals(seven)) return 1; else return -1; } if (x.compareTo(n) >= 0) return jacobi (x.mod(n), n); if (x.mod(two).equals(zero)) return (jacobi(x.divide(two),n)*jacobi(two,n)); if (n.mod(two).equals(zero)) return (jacobi(x,n.divide(two))*jacobi(x,two)); if (x.mod(four).equals(one) || n.mod(four).equals(one)) return jacobi(n,x); if (x.mod(four).equals(three) && n.mod(four).equals(three)) return - jacobi(n,x); if (x.equals(neg_one)) { if (n.mod(four).equals(one)) return 1; else return -1; } throw new RuntimeException ("Error in jacobi"); } } public class Toss implements ActionListener, CaretListener { /** The components of the user interface **/ JFrame coinFrame; JPanel coinPanel, bigPanel; JLabel resultLabel, pLabel, qLabel, x2Label; JTextField kField, nField, xField, x2modField; JButton makeN; /** There will be roughly KEYLENGTH*2/3 decimal digits. **/ final int DEFAULT_KEYLENGTH = 10; int KEYLENGTH = DEFAULT_KEYLENGTH; final int FIELD_WIDTH = 10; /** The three BigIntegers the program keeps track of. **/ BigInteger n = null, p = null, q = null; Calculations calc = new Calculations(); /** The constructor function starts the user interface. **/ Toss() { // Create and set up the window. coinFrame = new JFrame("Coin Toss"); coinFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); coinFrame.setLocation(200, 200); // Build the user interface inside of the window - separated // because it's long and messy buildUserInterface(); // Receive notification of important events. xField.addActionListener(this); nField.addActionListener(this); makeN.addActionListener(this); xField.addCaretListener(this); nField.addCaretListener(this); // Put the user interface (which is in bigPanel) in the window. coinFrame.getContentPane().add(bigPanel, BorderLayout.CENTER); // Display the window. coinFrame.pack(); coinFrame.setVisible(true); } /** Build the user interface. **/ void buildUserInterface() { // Create and set up the panel. coinPanel = new JPanel(new GridLayout(6, 1)); JPanel temp; // Create the fields, buttons, and labels we need pLabel = new JLabel(" p = ?"); qLabel = new JLabel(" q = ?"); x2Label = new JLabel("", SwingConstants.RIGHT); kField = new JTextField(5); nField = new JTextField(FIELD_WIDTH); xField = new JTextField(FIELD_WIDTH); resultLabel = new JLabel(""); makeN = new JButton("Generate N"); // K temp = new JPanel(new FlowLayout()); temp.add(new JLabel("Bits = ", SwingConstants.RIGHT)); temp.add(kField); temp.add(makeN); coinPanel.add(temp); // The P and Q indicators temp = new JPanel(new GridLayout(1, 2)); temp.add(pLabel); temp.add(qLabel); coinPanel.add(temp); // N temp = new JPanel(new FlowLayout(FlowLayout.RIGHT)); temp.add(new JLabel("N = ", SwingConstants.RIGHT)); temp.add(nField); coinPanel.add(temp); // X temp = new JPanel(new FlowLayout(FlowLayout.RIGHT)); temp.add(new JLabel("X = ", SwingConstants.RIGHT)); temp.add(xField); coinPanel.add(temp); // X^2 mod N temp = new JPanel(new FlowLayout(FlowLayout.LEFT)); temp.add(new JLabel(" X^2 mod N = ")); temp.add(x2Label); coinPanel.add(temp); // Result temp = new JPanel(new FlowLayout(FlowLayout.LEFT)); temp.add(new JLabel(" Jacobi(n,x) = ")); temp.add(resultLabel); coinPanel.add(temp); bigPanel = new JPanel(new BorderLayout()); bigPanel.add(coinPanel, BorderLayout.NORTH); } /** Listen for text movements in the N & X fields **/ public void caretUpdate(CaretEvent e) { clearResidueAndJacobi(); if (e.getSource() == nField) { p = null; q = null; pLabel.setText(" p = ?"); qLabel.setText(" q = ?"); } } /** Listen for Button events. **/ public void actionPerformed(ActionEvent event) { // Make a new n - set p, q, n, and labels. if (event.getSource() == makeN) { try { KEYLENGTH = Integer.parseInt(kField.getText()); } catch (NumberFormatException e) { KEYLENGTH = DEFAULT_KEYLENGTH; kField.setText(Integer.toString(KEYLENGTH)); } p = calc.makeBlumInt(KEYLENGTH); q = calc.makeBlumInt(KEYLENGTH); n = p.multiply(q); pLabel.setText(" p = " + p); qLabel.setText(" q = " + q); nField.removeCaretListener(this); nField.setText(n.toString()); nField.addCaretListener(this); xField.setText(""); clearResidueAndJacobi(); } else if (event.getSource() == xField || event.getSource() == nField) calculateResidueAndJacobi(); } void clearResidueAndJacobi() { resultLabel.setText(""); x2Label.setText(""); } /** Calculate the residue and the jacobi number **/ void calculateResidueAndJacobi() { try { BigInteger n = new BigInteger(nField.getText()); BigInteger x = new BigInteger(xField.getText()); x2Label.setText(calc.squareMod(x,n).toString()); resultLabel.setText("" + calc.jacobi(x, n)); } catch (NumberFormatException e) { clearResidueAndJacobi(); } } /** Run the Toss program **/ public static void main(String[] args) { //Schedule a job for the event-dispatching thread: //creating and showing this application's GUI. javax.swing.SwingUtilities.invokeLater(new Runnable() { public void run() { new Toss(); } }); } }