import java.security.*;
import java.security.spec.*;
import javax.crypto.*;
import javax.crypto.spec.*;

/** Round-trips ML-KEM and ML-DSA with the JDK's own providers and prints real object sizes. */
public class PqcSizes {
    public static void main(String[] args) throws Exception {
        System.out.println("java.version=" + System.getProperty("java.version"));

        System.out.println("\n== ML-KEM (JEP 496): key encapsulation ==");
        for (String alg : new String[] {"ML-KEM-512", "ML-KEM-768", "ML-KEM-1024"}) {
            KeyPair kp = KeyPairGenerator.getInstance(alg).generateKeyPair();
            KEM kem = KEM.getInstance("ML-KEM");
            KEM.Encapsulated enc = kem.newEncapsulator(kp.getPublic()).encapsulate();
            SecretKey viaDecap = kem.newDecapsulator(kp.getPrivate()).decapsulate(enc.encapsulation());
            boolean same = MessageDigest.isEqual(enc.key().getEncoded(), viaDecap.getEncoded());
            System.out.printf("%-12s publicKey=%4d B  privateKey=%4d B  ciphertext=%4d B  sharedSecret=%d B  secretsMatch=%b%n",
                alg, kp.getPublic().getEncoded().length, kp.getPrivate().getEncoded().length,
                enc.encapsulation().length, enc.key().getEncoded().length, same);
        }

        System.out.println("\n== ML-DSA (JEP 497): signatures ==");
        byte[] msg = "invoice 1042: pay 2249.00".getBytes();
        for (String alg : new String[] {"ML-DSA-44", "ML-DSA-65", "ML-DSA-87"}) {
            KeyPair kp = KeyPairGenerator.getInstance(alg).generateKeyPair();
            Signature s = Signature.getInstance(alg);
            s.initSign(kp.getPrivate()); s.update(msg); byte[] sig = s.sign();
            Signature v = Signature.getInstance(alg);
            v.initVerify(kp.getPublic()); v.update(msg);
            boolean ok = v.verify(sig);
            Signature v2 = Signature.getInstance(alg);
            v2.initVerify(kp.getPublic()); v2.update("invoice 1042: pay 9999.00".getBytes());
            boolean tampered = v2.verify(sig);
            System.out.printf("%-10s publicKey=%4d B  privateKey=%4d B  signature=%4d B  verifies=%b  tamperedVerifies=%b%n",
                alg, kp.getPublic().getEncoded().length, kp.getPrivate().getEncoded().length, sig.length, ok, tampered);
        }

        System.out.println("\n== Classical baselines for comparison ==");
        for (int bits : new int[] {2048, 3072}) {
            KeyPairGenerator g = KeyPairGenerator.getInstance("RSA"); g.initialize(bits);
            KeyPair kp = g.generateKeyPair();
            Signature s = Signature.getInstance("SHA256withRSA"); s.initSign(kp.getPrivate()); s.update(msg);
            System.out.printf("RSA-%-6d publicKey=%4d B  privateKey=%4d B  signature=%4d B%n", bits,
                kp.getPublic().getEncoded().length, kp.getPrivate().getEncoded().length, s.sign().length);
        }
        KeyPairGenerator ec = KeyPairGenerator.getInstance("EC"); ec.initialize(new ECGenParameterSpec("secp256r1"));
        KeyPair ekp = ec.generateKeyPair();
        Signature es = Signature.getInstance("SHA256withECDSA"); es.initSign(ekp.getPrivate()); es.update(msg);
        System.out.printf("ECDSA P-256 publicKey=%4d B  privateKey=%4d B  signature~%4d B (DER, varies)%n",
            ekp.getPublic().getEncoded().length, ekp.getPrivate().getEncoded().length, es.sign().length);
        KeyPair ed = KeyPairGenerator.getInstance("Ed25519").generateKeyPair();
        Signature eds = Signature.getInstance("Ed25519"); eds.initSign(ed.getPrivate()); eds.update(msg);
        System.out.printf("Ed25519     publicKey=%4d B  privateKey=%4d B  signature=%4d B%n",
            ed.getPublic().getEncoded().length, ed.getPrivate().getEncoded().length, eds.sign().length);
        KeyPair x = KeyPairGenerator.getInstance("X25519").generateKeyPair();
        System.out.printf("X25519 key agreement: publicKey=%d B (this is what a classical TLS 1.3 client sends)%n", x.getPublic().getEncoded().length);
    }
}
