/** * SignSchnorr01.java */ import java.math.BigInteger; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import java.security.MessageDigest; public class SignSchnorr01 { public static void main(String[] args) throws Exception { WL(SignSchnorr01.class.getName() + ": implémentation de la Signature de C.P. Schnorr"); SecureRandom rng = new SecureRandom(); // La clé publique est (p, q, a, v), la clé privée est s. // 1024 - 160 BigInteger p = new BigInteger("117822791132212360282319042495098062018900067431188858134335306441718433396022535700377650424200391288200595237888914161611075533199086425686586392363618740409306609526644410395845522930968359416803342139094547219284128018587148978659289451574290844773820459847528736213553282176885653081965700143263037869023"); BigInteger q = new BigInteger("1305324072425053147510044539688912262438899454117"); BigInteger a = new BigInteger("85681060152664308838468721674150014027878629530985885400990136320680366451555760229697595346325545254108144099136025271407513873997434121911773702496519385597582414160239927061687532081590778951636737211614798338007184810425777455424436921570373692293491327786185216159049210700437805071779016788426952369978"); // ===================================== // // Check initials parameters // // TODO: Assert that : q|p-1 ? // // Assert that : q >= 2^140, p >= 2^512 if (q.bitLength() < 140 || p.bitLength() < 512) { fatalError("Invalid size for parameters"); } // Assert that : a^q = 1 (mod p), a != 1 if (a.equals(BigInteger.ZERO) || a.equals(BigInteger.ONE) || !a.modPow(q, p).equals(BigInteger.ONE)) { fatalError("Invalid parameter 'a'"); } // ===================================== // // Generate user keys // s the secret key // v the public key // BigInteger s, v; // a private key s which is a random number in {1,2,...,q } do { s = new BigInteger(q.bitLength(), rng).mod(q); } while (s == BigInteger.ZERO); // The corresponding public key is the number v = a^-s (mod p) v = a.modPow(s.negate(), p); // ===================================== // // Sign a message // // TODO: Assert that e € { 0,...,(2^t)-1 } // String message = "Lorem ipsum dolor sit amet, consectetur adipiscing elit."; BigInteger r, x, e, y; // Pick a random number € {1,...,q} do { r = new BigInteger(q.bitLength(), rng); r = r.mod(q); } while (r == BigInteger.ZERO); // Compute x := a^r (mod p) x = a.modPow(r, p); MessageDigest h = MessageDigest.getInstance("SHA1"); h.update(x.toByteArray()); h.update(message.getBytes()); // Compute e := h(x,m) € { 0,...,(2^t)-1 } e = new BigInteger(h.digest()); // Compute y := r + se (mod q) y = r.add(s.multiply(e)).mod(q); // ===================================== // // Verify the signature // BigInteger ve, ay, xi, ei; // Compute xi = a^y * v^e (mod p) ay = a.modPow(y, p); ve = v.modPow(e, p); xi = ay.multiply(ve).mod(p); // check e = h(xi,m) MessageDigest hi = MessageDigest.getInstance("SHA1"); hi.update(xi.toByteArray()); hi.update(message.getBytes()); ei = new BigInteger(hi.digest()); if (ei.equals(e)) { WL("Signature match"); } else { WL("Signature does not match"); } } static void WL(String s) { System.out.println(s); } static void W(String s) { System.out.print(s); } static void fatalError(String s) { System.out.println(s); Runtime.getRuntime().exit(-1); } }