Search code examples
javabitcoinprivate-keyelliptic-curve

Derive EC public key from private key string in native Java for curve secp256k1


I need to derive an EC Public Key from an EC private key string without the "help" of any third party library.

The Private key is externally produced and provided and I need to get the Public Key to generate a Bitcoin address. As my project is working "offline" I do not need a library like Bouncy Castle for any other purpose, so I would like to eliminate it.

The following program is fully working and shows the (very short) example when working with Bouncy Castle to get a solution. The second part is the native Java solution with the kindly help from the routines by the so user SkateScout, for details see his answer https://stackoverflow.com/a/42797410/8166854.

Please keep in mind that this solution is working only for the Elliptic curve "secp256k1". You can check my keypair on https://gobittest.appspot.com/Address.

My question: is there any other solution available to avoid the mass of code for scalar operations?

import org.bouncycastle.jce.ECNamedCurveTable;
import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec;
import java.math.BigInteger;
import java.security.*;
import java.security.interfaces.ECPrivateKey;
import java.security.interfaces.ECPublicKey;
import java.security.spec.*;

public class DerivePublicKeyFromPrivateKeyCurveSecp256k1 {
    // get bouncycastle here: https://mvnrepository.com/artifact/org.bouncycastle/bcprov-jdk15on/1.65
    // tested with version 15 1.65
    final static BigInteger FieldP_2 = BigInteger.TWO; // constant for scalar operations
    final static BigInteger FieldP_3 = BigInteger.valueOf(3); // constant for scalar operations

    public static void main(String[] args) throws GeneralSecurityException {
        System.out.println("Generate ECPublicKey from PrivateKey (String) for curve secp256k1");
        System.out.println("Check keys with https://gobittest.appspot.com/Address");
        // https://gobittest.appspot.com/Address
        String privateKey = "D12D2FACA9AD92828D89683778CB8DFCCDBD6C9E92F6AB7D6065E8AACC1FF6D6";
        String publicKeyExpected = "04661BA57FED0D115222E30FE7E9509325EE30E7E284D3641E6FB5E67368C2DB185ADA8EFC5DC43AF6BF474A41ED6237573DC4ED693D49102C42FFC88510500799";
        System.out.println("\nprivatekey given : " + privateKey);
        System.out.println("publicKeyExpected: " + publicKeyExpected);
        // routine with bouncy castle
        System.out.println("\nGenerate PublicKey from PrivateKey with BouncyCastle");
        ECNamedCurveParameterSpec spec = ECNamedCurveTable.getParameterSpec("secp256k1"); // this ec curve is used for bitcoin operations
        org.bouncycastle.math.ec.ECPoint pointQ = spec.getG().multiply(new BigInteger(1, hexStringToByteArray(privateKey)));
        byte[] publickKeyByte = pointQ.getEncoded(false);
        String publicKeyBc = byteArrayToHexString(publickKeyByte);
        System.out.println("publicKeyExpected: " + publicKeyExpected);
        System.out.println("publicKey BC     : " + publicKeyBc);
        System.out.println("publicKeys match : " + publicKeyBc.contentEquals(publicKeyExpected));

        // regeneration of ECPublicKey with java native starts here
        System.out.println("\nGenerate PublicKey from PrivateKey with Java native routines");
        // the preset "303E.." only works for elliptic curve secp256k1
        // see answer by user dave_thompson_085
        // https://stackoverflow.com/questions/48832170/generate-ec-public-key-from-byte-array-private-key-in-native-java-7
        String privateKeyFull = "303E020100301006072A8648CE3D020106052B8104000A042730250201010420" +
                privateKey;
        byte[] privateKeyFullByte = hexStringToByteArray(privateKeyFull);
        System.out.println("privateKey full  : " + privateKeyFull);
        KeyFactory kecFactory = KeyFactory.getInstance("EC");
        PrivateKey privateKeyNative = kecFactory.generatePrivate(new PKCS8EncodedKeySpec(privateKeyFullByte));
        ECPrivateKey ecPrivateKeyNative = (ECPrivateKey) privateKeyNative;
        ECPublicKey ecPublicKeyNative = getPublicKey(ecPrivateKeyNative);
        byte[] ecPublicKeyNativeByte = ecPublicKeyNative.getEncoded();
        String publicKeyNativeFull = byteArrayToHexString(ecPublicKeyNativeByte);
        String publicKeyNativeHeader = publicKeyNativeFull.substring(0, 46);
        String publicKeyNativeKey = publicKeyNativeFull.substring(46, 176);
        System.out.println("ecPublicKeyFull  : " + publicKeyNativeFull);
        System.out.println("ecPublicKeyHeader: " + publicKeyNativeHeader);
        System.out.println("ecPublicKeyKey   : " + publicKeyNativeKey);
        System.out.println("publicKeyExpected: " + publicKeyExpected);
        System.out.println("publicKeys match : " + publicKeyNativeKey.contentEquals(publicKeyExpected));
    }

    private static String byteArrayToHexString(byte[] a) {
        StringBuilder sb = new StringBuilder(a.length * 2);
        for (byte b : a)
            sb.append(String.format("%02X", b));
        return sb.toString();
    }

    public static byte[] hexStringToByteArray(String s) {
        int len = s.length();
        byte[] data = new byte[len / 2];
        for (int i = 0; i < len; i += 2) {
            data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
                    + Character.digit(s.charAt(i + 1), 16));
        }
        return data;
    }

    // scalar operations for native java
    // see https://stackoverflow.com/a/42797410/8166854
    // written by author: SkateScout
    private static ECPoint doublePoint(final BigInteger p, final BigInteger a, final ECPoint R) {
        if (R.equals(ECPoint.POINT_INFINITY)) return R;
        BigInteger slope = (R.getAffineX().pow(2)).multiply(FieldP_3);
        slope = slope.add(a);
        slope = slope.multiply((R.getAffineY().multiply(FieldP_2)).modInverse(p));
        final BigInteger Xout = slope.pow(2).subtract(R.getAffineX().multiply(FieldP_2)).mod(p);
        final BigInteger Yout = (R.getAffineY().negate()).add(slope.multiply(R.getAffineX().subtract(Xout))).mod(p);
        return new ECPoint(Xout, Yout);
    }

    private static ECPoint addPoint(final BigInteger p, final BigInteger a, final ECPoint r, final ECPoint g) {
        if (r.equals(ECPoint.POINT_INFINITY)) return g;
        if (g.equals(ECPoint.POINT_INFINITY)) return r;
        if (r == g || r.equals(g)) return doublePoint(p, a, r);
        final BigInteger gX = g.getAffineX();
        final BigInteger sY = g.getAffineY();
        final BigInteger rX = r.getAffineX();
        final BigInteger rY = r.getAffineY();
        final BigInteger slope = (rY.subtract(sY)).multiply(rX.subtract(gX).modInverse(p)).mod(p);
        final BigInteger Xout = (slope.modPow(FieldP_2, p).subtract(rX)).subtract(gX).mod(p);
        BigInteger Yout = sY.negate().mod(p);
        Yout = Yout.add(slope.multiply(gX.subtract(Xout))).mod(p);
        return new ECPoint(Xout, Yout);
    }

    public static ECPoint scalmult(final EllipticCurve curve, final ECPoint g, final BigInteger kin) {
        final ECField field = curve.getField();
        if (!(field instanceof ECFieldFp)) throw new UnsupportedOperationException(field.getClass().getCanonicalName());
        final BigInteger p = ((ECFieldFp) field).getP();
        final BigInteger a = curve.getA();
        ECPoint R = ECPoint.POINT_INFINITY;
        // value only valid for curve secp256k1, code taken from https://www.secg.org/sec2-v2.pdf, 
        // see "Finally the order n of G and the cofactor are: n = "FF.."
        BigInteger SECP256K1_Q = new BigInteger("00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141",16);
        BigInteger k = kin.mod(SECP256K1_Q); // uses this !
        // wrong as per comment from President James Moveon Polk
        // BigInteger k = kin.mod(p); // do not use this !
        final int length = k.bitLength();
        final byte[] binarray = new byte[length];
        for (int i = 0; i <= length - 1; i++) {
            binarray[i] = k.mod(FieldP_2).byteValue();
            k = k.shiftRight(1);
        }
        for (int i = length - 1; i >= 0; i--) {
            R = doublePoint(p, a, R);
            if (binarray[i] == 1) R = addPoint(p, a, R, g);
        }
        return R;
    }

    public static ECPublicKey getPublicKey(final ECPrivateKey pk) throws GeneralSecurityException {
        final ECParameterSpec params = pk.getParams();
        final ECPoint w = scalmult(params.getCurve(), pk.getParams().getGenerator(), pk.getS());
        final KeyFactory kg = KeyFactory.getInstance("EC");
        return (ECPublicKey) kg.generatePublic(new ECPublicKeySpec(w, params));
    }
}

The output looks like:

Generate ECPublicKey from PrivateKey (String) for curve secp256k1
Check keys with https://gobittest.appspot.com/Address

privatekey given : D12D2FACA9AD92828D89683778CB8DFCCDBD6C9E92F6AB7D6065E8AACC1FF6D6
publicKeyExpected: 04661BA57FED0D115222E30FE7E9509325EE30E7E284D3641E6FB5E67368C2DB185ADA8EFC5DC43AF6BF474A41ED6237573DC4ED693D49102C42FFC88510500799

Generate PublicKey from PrivateKey with BouncyCastle
publicKeyExpected: 04661BA57FED0D115222E30FE7E9509325EE30E7E284D3641E6FB5E67368C2DB185ADA8EFC5DC43AF6BF474A41ED6237573DC4ED693D49102C42FFC88510500799
publicKey BC     : 04661BA57FED0D115222E30FE7E9509325EE30E7E284D3641E6FB5E67368C2DB185ADA8EFC5DC43AF6BF474A41ED6237573DC4ED693D49102C42FFC88510500799
publicKeys match : true

Generate PublicKey from PrivateKey with Java native routines
privateKey full  : 303E020100301006072A8648CE3D020106052B8104000A042730250201010420D12D2FACA9AD92828D89683778CB8DFCCDBD6C9E92F6AB7D6065E8AACC1FF6D6
ecPublicKeyFull  : 3056301006072A8648CE3D020106052B8104000A03420004661BA57FED0D115222E30FE7E9509325EE30E7E284D3641E6FB5E67368C2DB185ADA8EFC5DC43AF6BF474A41ED6237573DC4ED693D49102C42FFC88510500799
ecPublicKeyHeader: 3056301006072A8648CE3D020106052B8104000A034200
ecPublicKeyKey   : 04661BA57FED0D115222E30FE7E9509325EE30E7E284D3641E6FB5E67368C2DB185ADA8EFC5DC43AF6BF474A41ED6237573DC4ED693D49102C42FFC88510500799
publicKeyExpected: 04661BA57FED0D115222E30FE7E9509325EE30E7E284D3641E6FB5E67368C2DB185ADA8EFC5DC43AF6BF474A41ED6237573DC4ED693D49102C42FFC88510500799
publicKeys match : true

Code above corrected as commented from President James Moveon Polk


Solution

  • I'm providing the final solution for my problem, just in case anybody encounters the same problem. Thanks to user President James Moveon Polk and dave_thompson_085 for guiding.

    The source code is additionally available on my github-repository https://github.com/java-crypto/Stackoverflow/tree/master/DervicePublicKeyFromPrivateKeyCurveSecp256k1.

    import org.bouncycastle.jce.ECNamedCurveTable;
    import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec;
    import java.math.BigInteger;
    import java.security.GeneralSecurityException;
    import java.security.KeyFactory;
    import java.security.PrivateKey;
    import java.security.interfaces.ECPrivateKey;
    import java.security.interfaces.ECPublicKey;
    import java.security.spec.*;
    
    public class DerivePublicKeyFromPrivateKeyCurveSecp256k1Final {
        // sourcecode available https://github.com/java-crypto/Stackoverflow/tree/master/DervicePublicKeyFromPrivateKeyCurveSecp256k1
        // get bouncycastle here: https://mvnrepository.com/artifact/org.bouncycastle/bcprov-jdk15on/1.65
        // tested with version 15 1.65
        // java open jdk 11.0.5
        final static BigInteger FieldP_2 = BigInteger.TWO; // constant for scalar operations
        final static BigInteger FieldP_3 = BigInteger.valueOf(3); // constant for scalar operations
    
        public static void main(String[] args) throws GeneralSecurityException {
            System.out.println("Generate ECPublicKey from PrivateKey (String) for curve secp256k1 (final)");
            System.out.println("Check keys with https://gobittest.appspot.com/Address");
            // https://gobittest.appspot.com/Address
            String privateKey = "D12D2FACA9AD92828D89683778CB8DFCCDBD6C9E92F6AB7D6065E8AACC1FF6D6";
            String publicKeyExpected = "04661BA57FED0D115222E30FE7E9509325EE30E7E284D3641E6FB5E67368C2DB185ADA8EFC5DC43AF6BF474A41ED6237573DC4ED693D49102C42FFC88510500799";
            System.out.println("\nprivatekey given : " + privateKey);
            System.out.println("publicKeyExpected: " + publicKeyExpected);
            // routine with bouncy castle
            System.out.println("\nGenerate PublicKey from PrivateKey with BouncyCastle");
            ECNamedCurveParameterSpec spec = ECNamedCurveTable.getParameterSpec("secp256k1"); // this ec curve is used for bitcoin operations
            org.bouncycastle.math.ec.ECPoint pointQ = spec.getG().multiply(new BigInteger(1, hexStringToByteArray(privateKey)));
            byte[] publickKeyByte = pointQ.getEncoded(false);
            String publicKeyBc = byteArrayToHexString(publickKeyByte);
            System.out.println("publicKeyExpected: " + publicKeyExpected);
            System.out.println("publicKey BC     : " + publicKeyBc);
            System.out.println("publicKeys match : " + publicKeyBc.contentEquals(publicKeyExpected));
    
            // regeneration of ECPublicKey with java native starts here
            System.out.println("\nGenerate PublicKey from PrivateKey with Java native routines");
            // the preset "303E.." only works for elliptic curve secp256k1
            // see answer by user dave_thompson_085
            // https://stackoverflow.com/questions/48832170/generate-ec-public-key-from-byte-array-private-key-in-native-java-7
            String privateKeyFull = "303E020100301006072A8648CE3D020106052B8104000A042730250201010420" +
                    privateKey;
            byte[] privateKeyFullByte = hexStringToByteArray(privateKeyFull);
            System.out.println("privateKey full  : " + privateKeyFull);
            KeyFactory keyFactory = KeyFactory.getInstance("EC");
            PrivateKey privateKeyNative = keyFactory.generatePrivate(new PKCS8EncodedKeySpec(privateKeyFullByte));
            ECPrivateKey ecPrivateKeyNative = (ECPrivateKey) privateKeyNative;
            ECPublicKey ecPublicKeyNative = getPublicKey(ecPrivateKeyNative);
            byte[] ecPublicKeyNativeByte = ecPublicKeyNative.getEncoded();
            String publicKeyNativeFull = byteArrayToHexString(ecPublicKeyNativeByte);
            String publicKeyNativeHeader = publicKeyNativeFull.substring(0, 46);
            String publicKeyNativeKey = publicKeyNativeFull.substring(46, 176);
            System.out.println("ecPublicKeyFull  : " + publicKeyNativeFull);
            System.out.println("ecPublicKeyHeader: " + publicKeyNativeHeader);
            System.out.println("ecPublicKeyKey   : " + publicKeyNativeKey);
            System.out.println("publicKeyExpected: " + publicKeyExpected);
            System.out.println("publicKeys match : " + publicKeyNativeKey.contentEquals(publicKeyExpected));
        }
    
        private static String byteArrayToHexString(byte[] a) {
            StringBuilder sb = new StringBuilder(a.length * 2);
            for (byte b : a)
                sb.append(String.format("%02X", b));
            return sb.toString();
        }
    
        public static byte[] hexStringToByteArray(String s) {
            int len = s.length();
            byte[] data = new byte[len / 2];
            for (int i = 0; i < len; i += 2) {
                data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
                        + Character.digit(s.charAt(i + 1), 16));
            }
            return data;
        }
    
        // scalar operations for native java
        // see https://stackoverflow.com/a/42797410/8166854
        // written by author: SkateScout
        private static ECPoint doublePoint(final BigInteger p, final BigInteger a, final ECPoint R) {
            if (R.equals(ECPoint.POINT_INFINITY)) return R;
            BigInteger slope = (R.getAffineX().pow(2)).multiply(FieldP_3);
            slope = slope.add(a);
            slope = slope.multiply((R.getAffineY().multiply(FieldP_2)).modInverse(p));
            final BigInteger Xout = slope.pow(2).subtract(R.getAffineX().multiply(FieldP_2)).mod(p);
            final BigInteger Yout = (R.getAffineY().negate()).add(slope.multiply(R.getAffineX().subtract(Xout))).mod(p);
            return new ECPoint(Xout, Yout);
        }
    
        private static ECPoint addPoint(final BigInteger p, final BigInteger a, final ECPoint r, final ECPoint g) {
            if (r.equals(ECPoint.POINT_INFINITY)) return g;
            if (g.equals(ECPoint.POINT_INFINITY)) return r;
            if (r == g || r.equals(g)) return doublePoint(p, a, r);
            final BigInteger gX = g.getAffineX();
            final BigInteger sY = g.getAffineY();
            final BigInteger rX = r.getAffineX();
            final BigInteger rY = r.getAffineY();
            final BigInteger slope = (rY.subtract(sY)).multiply(rX.subtract(gX).modInverse(p)).mod(p);
            final BigInteger Xout = (slope.modPow(FieldP_2, p).subtract(rX)).subtract(gX).mod(p);
            BigInteger Yout = sY.negate().mod(p);
            Yout = Yout.add(slope.multiply(gX.subtract(Xout))).mod(p);
            return new ECPoint(Xout, Yout);
        }
    
        public static ECPoint scalmultNew(final ECParameterSpec params, final ECPoint g, final BigInteger kin) {
            EllipticCurve curve = params.getCurve();
            final ECField field = curve.getField();
            if (!(field instanceof ECFieldFp)) throw new UnsupportedOperationException(field.getClass().getCanonicalName());
            final BigInteger p = ((ECFieldFp) field).getP();
            final BigInteger a = curve.getA();
            ECPoint R = ECPoint.POINT_INFINITY;
            // value only valid for curve secp256k1, code taken from https://www.secg.org/sec2-v2.pdf,
            // see "Finally the order n of G and the cofactor are: n = "FF.."
            BigInteger SECP256K1_Q = params.getOrder();
            //BigInteger SECP256K1_Q = new BigInteger("00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141",16);
            BigInteger k = kin.mod(SECP256K1_Q); // uses this !
            // BigInteger k = kin.mod(p); // do not use this ! wrong as per comment from President James Moveon Polk
            final int length = k.bitLength();
            final byte[] binarray = new byte[length];
            for (int i = 0; i <= length - 1; i++) {
                binarray[i] = k.mod(FieldP_2).byteValue();
                k = k.shiftRight(1);
            }
            for (int i = length - 1; i >= 0; i--) {
                R = doublePoint(p, a, R);
                if (binarray[i] == 1) R = addPoint(p, a, R, g);
            }
            return R;
        }
    
        public static ECPoint scalmultOrg(final EllipticCurve curve, final ECPoint g, final BigInteger kin) {
            final ECField field = curve.getField();
            if (!(field instanceof ECFieldFp)) throw new UnsupportedOperationException(field.getClass().getCanonicalName());
            final BigInteger p = ((ECFieldFp) field).getP();
            final BigInteger a = curve.getA();
            ECPoint R = ECPoint.POINT_INFINITY;
            // value only valid for curve secp256k1, code taken from https://www.secg.org/sec2-v2.pdf,
            // see "Finally the order n of G and the cofactor are: n = "FF.."
            BigInteger SECP256K1_Q = new BigInteger("00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141",16);
            BigInteger k = kin.mod(SECP256K1_Q); // uses this !
            // wrong as per comment from President James Moveon Polk
            // BigInteger k = kin.mod(p); // do not use this !
            System.out.println(" SECP256K1_Q: " + SECP256K1_Q);
            System.out.println("           p: " + p);
            System.out.println("curve: " + curve.toString());
            final int length = k.bitLength();
            final byte[] binarray = new byte[length];
            for (int i = 0; i <= length - 1; i++) {
                binarray[i] = k.mod(FieldP_2).byteValue();
                k = k.shiftRight(1);
            }
            for (int i = length - 1; i >= 0; i--) {
                R = doublePoint(p, a, R);
                if (binarray[i] == 1) R = addPoint(p, a, R, g);
            }
            return R;
        }
    
        public static ECPublicKey getPublicKey(final ECPrivateKey pk) throws GeneralSecurityException {
            final ECParameterSpec params = pk.getParams();
            final ECPoint w = scalmultNew(params, pk.getParams().getGenerator(), pk.getS());
            //final ECPoint w = scalmult(params.getCurve(), pk.getParams().getGenerator(), pk.getS());
            final KeyFactory kg = KeyFactory.getInstance("EC");
            return (ECPublicKey) kg.generatePublic(new ECPublicKeySpec(w, params));
        }
    }
    

    This is the output:

    Generate ECPublicKey from PrivateKey (String) for curve secp256k1 (final)
    Check keys with https://gobittest.appspot.com/Address
    
    privatekey given : D12D2FACA9AD92828D89683778CB8DFCCDBD6C9E92F6AB7D6065E8AACC1FF6D6
    publicKeyExpected: 04661BA57FED0D115222E30FE7E9509325EE30E7E284D3641E6FB5E67368C2DB185ADA8EFC5DC43AF6BF474A41ED6237573DC4ED693D49102C42FFC88510500799
    
    Generate PublicKey from PrivateKey with BouncyCastle
    publicKeyExpected: 04661BA57FED0D115222E30FE7E9509325EE30E7E284D3641E6FB5E67368C2DB185ADA8EFC5DC43AF6BF474A41ED6237573DC4ED693D49102C42FFC88510500799
    publicKey BC     : 04661BA57FED0D115222E30FE7E9509325EE30E7E284D3641E6FB5E67368C2DB185ADA8EFC5DC43AF6BF474A41ED6237573DC4ED693D49102C42FFC88510500799
    publicKeys match : true
    
    Generate PublicKey from PrivateKey with Java native routines
    privateKey full  : 303E020100301006072A8648CE3D020106052B8104000A042730250201010420D12D2FACA9AD92828D89683778CB8DFCCDBD6C9E92F6AB7D6065E8AACC1FF6D6
    ecPublicKeyFull  : 3056301006072A8648CE3D020106052B8104000A03420004661BA57FED0D115222E30FE7E9509325EE30E7E284D3641E6FB5E67368C2DB185ADA8EFC5DC43AF6BF474A41ED6237573DC4ED693D49102C42FFC88510500799
    ecPublicKeyHeader: 3056301006072A8648CE3D020106052B8104000A034200
    ecPublicKeyKey   : 04661BA57FED0D115222E30FE7E9509325EE30E7E284D3641E6FB5E67368C2DB185ADA8EFC5DC43AF6BF474A41ED6237573DC4ED693D49102C42FFC88510500799
    publicKeyExpected: 04661BA57FED0D115222E30FE7E9509325EE30E7E284D3641E6FB5E67368C2DB185ADA8EFC5DC43AF6BF474A41ED6237573DC4ED693D49102C42FFC88510500799
    publicKeys match : true
    

    If anyone needs this solution for another curve here is a solution from user Maarten Bodewes to generate the "magic string":

    import java.security.InvalidAlgorithmParameterException;
    import java.security.KeyPairGenerator;
    import java.security.NoSuchAlgorithmException;
    import java.security.interfaces.ECPrivateKey;
    import java.security.spec.ECGenParameterSpec;
    import java.security.spec.PKCS8EncodedKeySpec;
    
    public class CreateHeadForNamedCurveSo {
        public static void main(String[] args) throws InvalidAlgorithmParameterException, NoSuchAlgorithmException {
            System.out.println("create private key head for named curve");
            System.out.println("see https://stackoverflow.com/a/30471945/8166854");
            System.out.println("author: Maarten Bodewes\n");
            // input
            String curvename = "secp256k1";
            String privateKeyHeaderExpected = "303E020100301006072A8648CE3D020106052B8104000A042730250201010420";
            String privateKeyHeaderFromCurve = createPrivateKeyHeaderForNamedCurve(curvename);
            // output
            System.out.println("Curvename                    : " + curvename);
            System.out.println("expected private key header  : " + privateKeyHeaderExpected);
            System.out.println("calculated private key header: " + privateKeyHeaderFromCurve);
            System.out.println("private key headers matching : " + privateKeyHeaderExpected.contentEquals(privateKeyHeaderFromCurve));
        }
    
        private static String createPrivateKeyHeaderForNamedCurve(String name)
                throws NoSuchAlgorithmException,
                InvalidAlgorithmParameterException {
            KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC");
            ECGenParameterSpec m = new ECGenParameterSpec(name);
            kpg.initialize(m);
            ECPrivateKey privateKey = (ECPrivateKey) kpg.generateKeyPair().getPrivate();
            PKCS8EncodedKeySpec pKCS8EncodedKeySpec = new PKCS8EncodedKeySpec(privateKey.getEncoded());
            String pKCS8EncodedKeySpecString = byteArrayToHexString(pKCS8EncodedKeySpec.getEncoded());
            return pKCS8EncodedKeySpecString.substring(0,64);
        }
    
        private static String byteArrayToHexString(byte[] a) {
            StringBuilder sb = new StringBuilder(a.length * 2);
            for (byte b : a)
                sb.append(String.format("%02X", b));
            return sb.toString();
        }
    
        public static byte[] hexStringToByteArray(String s) {
            int len = s.length();
            byte[] data = new byte[len / 2];
            for (int i = 0; i < len; i += 2) {
                data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
                        + Character.digit(s.charAt(i + 1), 16));
            }
            return data;
        }
    }
    

    Enjoy !