/* All work, inefficiencies, and bugs Copyright 2001 Kevin Fu October 18, 2001 Demo implementation of Shoup's RSA threshold signature scheme protocol I from "Practical Threshold Signatures" EUROCRYPT 2000 For 6.857 Network and Computer Security http://web.mit.edu/6.857/www/ May be freely reproduced for educational or personal use */ import java.math.*; import java.io.*; import java.util.*; public class genShares { static BigInteger TWO = new BigInteger("2"); static Random rnd = new Random(); // insecure randomness, but good for problem set public static void main(String args[]) { if (args.length != 4) { System.out.println("Usage: java genShares "); System.out.println("Try java genShares 3 21 64 10"); System.out.println("Primes are probably prime with probability 1 - 2^{-certainty}"); System.exit(1); } int threshold = Integer.parseInt(args[0]); int groups = Integer.parseInt(args[1]); int bitsize = Integer.parseInt(args[2]); int certainty = Integer.parseInt(args[3]); /* p_1, q_1 511-bit primes p = 2p_1 + 1 512-bit prime q = 2q_1 + 1 512-bit prime */ BigInteger sp[] = new BigInteger[2]; sp = safePrime (bitsize, certainty); BigInteger p = sp[0]; BigInteger p1 = sp[1]; System.out.println("p = " + p + " = 2*p1 +1"); System.out.println("p1 = " + p1); sp = safePrime (bitsize, certainty); BigInteger q = sp[0]; BigInteger q1 = sp[1]; System.out.println("q = " + q + " = 2*q1 +1"); System.out.println("q1 = " + q1); BigInteger n = p.multiply (q); System.out.println("n = " + n + " = p*q"); BigInteger m = p1.multiply (q1); System.out.println("m = " + m + " = p1*q1"); String groupsbits = Integer.toBinaryString (groups); BigInteger e = new BigInteger(groupsbits.length () +1, certainty, rnd); System.out.println("e = " + e); if (e.compareTo (new BigInteger(Integer.toString(groups))) <= 0) { System.out.println ("FAIL: e <= l"); System.exit(1); } BigInteger d = e.modInverse (m); System.out.println("d = " + d); // System.out.println("de mod m = " + (d.multiply(e)).mod(m) + " sanity check"); System.out.println ("Coefficients:"); BigInteger a[] = new BigInteger[threshold]; a[0] = d; System.out.println ("a[0] = " + a[0]); for (int i=1; i < threshold; i++) { a[i] = bigRandom (m); System.out.println ("a[" + i + "] = " + a[i]); } System.out.println ("Key shares:"); BigInteger s[] = new BigInteger[groups]; for (int i=0; i < groups; i++) { // Note, start at 1, not 0 because s[0] = a[0] = d = secret! s[i] = polynomial (i + 1, threshold, a, m); System.out.println ("key share s[" + i + "] for group " + (i+1) + " = " + s[i]); } System.out.println ("QRs mod n:"); BigInteger V = bigRandQR (p, q); System.out.println ("V = " + V); BigInteger v[] = new BigInteger[groups]; for (int i=0; i < groups; i++) { v[i] = V.modPow (s[i], n); System.out.println ("v[" + i + "] for group " + (i+1) + " = " + v[i]); } // Sanity checks BigInteger x = new BigInteger ("quiessettantusfructus", 36); //BigInteger x = new BigInteger ("quiessettantusfructusinprosperis", 36); // nisihaberesquiillisaequeactuipse System.out.println ("Message = " + x); if ((x.gcd (n)).compareTo (BigInteger.ONE) != 0) { System.out.println ("FAIL: Message not relatively prime! You got really lucky."); System.exit(1); } BigInteger signature = genRsaSignature (d, n, x); System.out.println ("Signature = " + signature); if (verifyRsa (e, n, signature, x)) System.out.println ("PASS: Signature good"); else { System.out.println ("FAIL: Signature invalid"); System.exit (1); } if (verifyRsa (e, n, signature, x.add (BigInteger.ONE))) { System.out.println ("FAIL: Bad Signature good"); System.exit (1); } else System.out.println ("PASS: Bad Signature invalid"); BigInteger sigShare[] = new BigInteger[groups]; BigInteger l = new BigInteger (Integer.toString (groups)); for (int i=0; i < groups; i++) { sigShare[i] = genRsaSignatureShare (s[i], n, x, l); System.out.println ("Signature share from group " + i + " = " + sigShare[i]); // fake the proof of correctness BigInteger c = new BigInteger (bitsize, rnd); BigInteger r = new BigInteger (bitsize, rnd); BigInteger z = (s[i].multiply (c)).add (r); BigInteger xhat = x.modPow ((new BigInteger ("4")).multiply (factorial (l)), n); BigInteger vt = V.modPow (r, n); BigInteger xt = xhat.modPow (r, n); if (verifySignatureShare (sigShare[i], n, V, c, v[i], z, xhat, vt, xt)) { System.out.println ("Signature share x[" + i + "] NIZK valid"); } else { System.out.println ("Signature share x[" + i + "] NIZK invalid"); } } testShares (x, e, n, signature, V, v, sigShare, groups, threshold); } static void testShares (BigInteger x, BigInteger e, BigInteger n, BigInteger signature, BigInteger V, BigInteger v[], BigInteger sigShare[], int groups, int threshold) { BigInteger l = new BigInteger (Integer.toString (groups)); System.out.println ("Signature shares verification:"); // assume threshold =3 // Try every way of choosing t sigshares to produce a signature for (int jj=0; jj 0) { result = result.multiply (count); count = count.subtract (BigInteger.ONE); } // ystem.out.println ("fact(" + l + ") = " + result); return result; } }