Java

Java

Java

Topics on Semeru (Java) on IBM Z

 View Only

PQC on Java: ML-DSA Tutorial (IBMJCECCA)

By Emily Popovic posted 23 days ago

  

Overview

ML-DSA is a lattice-based digital signature scheme whose security is based on the hardness of finding short vectors in lattices.

Support for ML-DSA is now supported on IBM Semeru Java versions 17 and 21 on the IBMJCECCA security provider. IBMJCECCA currently offers the following implementations:

  • Pure ML-DSA (4,4)

  • Pure ML-DSA (6,5)

  • Pure ML-DSA (8,7)

  • Pre-Hash ML-DSA (4,4) with SHA-512

  • Pre-Hash ML-DSA (6,5) with SHA-512

  • Pre-Hash ML-DSA (8,7) with SHA-512

  • CRYSTALS-Dilithium (6,5) Round 2 (superseded by ML-DSA)

  • CRYSTALS-Dilithium (8,7) Round 2 (superseded by ML-DSA)

  • CRYSTALS-Dilithium (6,5) Round 3 (superseded by ML-DSA)

  • CRYSTALS-Dilithium (8,7) Round 3 (superseded by ML-DSA)

The strength of an ML-DSA key is represented by the size of its matrix of polynomials. For example, ML-DSA (6,5) has a matrix size of 6x5. The bigger the matrix size, the stronger the key. ML-DSA keys can only be used for Digital Signature Generation and Verification.

This tutorial will demonstrate how to integrate ML-DSA into a Java application. Before you continue reading, please ensure your environment is properly configured by reading PQC on Java: Configuring your IBM Z system to use Quantum-safe algorithms.

Step 1: Create ML-DSA key pair

The first step is to create a ML-DSA key pair using the KeyPairGenerator and MLDSAKeyParameterSpec classes.

The MLDSAKeyParameterSpec class accepts the following values based on the desired implementation outlined in the Overview section:

  • dilithium65r2

  • dilithium87r2

  • dilithium65r3

  • dilithium87r3

  • puremldsa44

  • puremldsa65

  • puremldsa87

  • prehashmldsa44

  • prehashmldsa65

  • prehashmldsa87

KeyPairGenerator kpg =
    KeyPairGenerator.getInstance("ML-DSA", "IBMJCECCA");
MLDSAKeyParameterSpec kps =
    new MLDSAKeyParameterSpec("puremldsa65");
kpg.initialize(kps, null);
KeyPair keyPair = kpg.generateKeyPair();

Step 2: Get public and private keys

Now that we have the key pair, we can separate the keys into their own variables.

MLDSAPrivateKey privKey = (MLDSAPrivateKey) keyPair.getPrivate();
MLDSAPublicKey pubKey = (MLDSAPublicKey) keyPair.getPublic();

Step 3: Create Signature object

If you're already experienced with the JCE framework, the remainder of the steps may look familiar with other Signature algorithms. Use the Signature class and specify ML-DSA and IBMJCECCA.

Signature sign = Signature.getInstance("ML-DSA", "IBMJCECCA");

Step 4: Initialize Signature for signing

Use the ML-DSA private key to initialize the Signature object.

sign.initSign(privKey);

Step 5: Add bytes to Signature

Pass the data to be signend to the update() method of the Signature object.

byte[] bytes = "IBM - Let's create".getBytes();
sign.update(bytes);

Step 6: Perform signature

Finally, use the sign() method to get the signature bytes of the updated data.

byte[] sigBytes = sign.sign();

Step 7: Initialize the Signature for verification

Now, we can initialize the Signature object to verify the signature bytes in the next step.

sign.initVerify(pubKey);
sign.update(bytes);

Step 8: Verify

Verify the signature.

boolean verified = sign.verify(sigBytes);
if (verified) {
    System.out.println("Signature verified");
} else {
    System.out.println("Signature could NOT be verified");
}

Example

import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.Signature;

import com.ibm.crypto.hdwrCCA.provider.MLDSAKeyParameterSpec;
import com.ibm.crypto.hdwrCCA.provider.MLDSAPrivateKey;
import com.ibm.crypto.hdwrCCA.provider.MLDSAPublicKey;

public class MLDSAExample {

    public static void main(String[] args) throws Exception {

        // STEP 1: Creat key pair
        KeyPairGenerator kpg =
            KeyPairGenerator.getInstance("ML-DSA", "IBMJCECCA");
        MLDSAKeyParameterSpec kps =
            new MLDSAKeyParameterSpec("puremldsa65");
        kpg.initialize(kps, null);
        KeyPair keyPair = kpg.generateKeyPair();

        // STEP 2: Get public and private keys
        MLDSAPrivateKey privKey = (MLDSAPrivateKey) keyPair.getPrivate();
        MLDSAPublicKey pubKey = (MLDSAPublicKey) keyPair.getPublic();

        // STEP 3: Create Signature object
        Signature sign = Signature.getInstance("ML-DSA", "IBMJCECCA");

        // STEP 4: Initialize Signature for signing
        sign.initSign(privKey);

        // STEP 5: Add bytes to Signature
        byte[] bytes = "IBM - Let's create".getBytes();
        sign.update(bytes);

        // STEP 6: Perform signature
        byte[] sigBytes = sign.sign();

        // STEP 7: Initialize the Signature for verification
        sign.initVerify(pubKey);
        sign.update(bytes);

        // STEP 8: Verify
        boolean verified = sign.verify(sigBytes);
        if (verified) {
            System.out.println("Signature verified");
        } else {
            System.out.println("Signature could NOT be verified");
        }
    }
}

Output

The previous Example should produce the following output:

Signature verified

Conclusion

In this tutorial, we learned how to use the ML-DSA PQC algorithm with IBMJCECCA to create keys and use a Signature to sign & verify bytes. Thanks for reading!

If you have additional questions, please email me at Emily.Popovic1@ibm.com

References

  1. PQC on Java: Configuring your IBM Z system to use Post-Quantum Cryptography

  2. ML-DSA, CRYSTALS-Dilithium Digital Signature Algorithm

  3. z17 IBM Semeru Runtimes: PQC Cryptography Enhancements

0 comments
6 views

Permalink