Search code examples
bouncycastleelliptic-curve

Get X, Y coords from private and public from AsymmetricKeyParameter


public class EccGenerator
{
    public AsymmetricCipherKeyPair GenerateKeyPairs(int keySize)
    {
        ECKeyPairGenerator gen = new ECKeyPairGenerator("ECDSA");
        KeyGenerationParameters keyGenParam = new KeyGenerationParameters(new SecureRandom(), keySize);
        gen.Init(keyGenParam);
        AsymmetricCipherKeyPair keyPair = gen.GenerateKeyPair();
        return keyPair;
    }

    public static void  PrintPublicX_Y(AsymmetricKeyParameter publicKey)
    {
        ECPublicKeyParameters key = (ECPublicKeyParameters)publicKey;
        string X = Encoding.ASCII.GetString(UrlBase64.Encode(key.Q.XCoord.ToBigInteger().ToByteArrayUnsigned()));
        string Y = Encoding.ASCII.GetString(UrlBase64.Encode(key.Q.YCoord.ToBigInteger().ToByteArrayUnsigned()));
        Console.WriteLine(X + "--" + Y);
    }

    public static void PrintPrivateX_Y(AsymmetricKeyParameter privateKey)
    {
        ECPrivateKeyParameters key = (ECPrivateKeyParameters)privateKey;
        string D = Encoding.ASCII.GetString(UrlBase64.Encode(key.D.ToByteArrayUnsigned()));
        string X = Encoding.ASCII.GetString(UrlBase64.Encode(key.Parameters.G.XCoord.ToBigInteger().ToByteArrayUnsigned()));
        string Y = Encoding.ASCII.GetString(UrlBase64.Encode(key.Parameters.G.YCoord.ToBigInteger().ToByteArrayUnsigned()));
        Console.WriteLine(X + "--" + Y);
    }

    public static void Main(string[] args)
    {
        EccGenerator ecc = new EccGenerator();
        AsymmetricCipherKeyPair pair = ecc.GenerateKeyPairs(256);
        PrintPublicX_Y(pair.Public);
        PrintPrivateX_Y(pair.Private);
    }
}

The problem here is the X in public and private are not identical, also the same with the Y, how can I get the right x and y and D for private

I am using Bouncy Castle C#


Solution

  • The public key is obtained by multiplying the base point G with the private key D. The result has generally to be normalized (the latter takes care of the transformation of the projective coordinates, which are used for performance reasons, into the affine coordinates, for details see e.g. here).

    Therefore, in PrintPrivateX_Y() the expression key.Parameters.G must be replaced by key.Parameters.G.Multiply(key.D).Normalize().

    The following alternative code:

    using Org.BouncyCastle.Crypto;
    using Org.BouncyCastle.Crypto.Generators;
    using Org.BouncyCastle.Crypto.Parameters;
    using Org.BouncyCastle.Math.EC;
    using Org.BouncyCastle.Security;
    using Org.BouncyCastle.Utilities.Encoders;
    using System;
    ...
    AsymmetricCipherKeyPair pair = GenerateKeyPairs(256);
    
    ECPublicKeyParameters publicKeyParams = (ECPublicKeyParameters)pair.Public;
    ECPoint publicKey = publicKeyParams.Q;
    PrintKey(publicKey);
    
    ECPrivateKeyParameters privateKeyParams = (ECPrivateKeyParameters)pair.Private;
    ECPoint publicKeyViaPrivate = privateKeyParams.Parameters.G.Multiply(privateKeyParams.D).Normalize();
    PrintKey(publicKeyViaPrivate);
    

    with

    public static void PrintKey(ECPoint ecPoint)
    {
        string X = Hex.ToHexString(ecPoint.XCoord.ToBigInteger().ToByteArrayUnsigned());
        string Y = Hex.ToHexString(ecPoint.YCoord.ToBigInteger().ToByteArrayUnsigned());
        Console.WriteLine(X + " -- " + Y);
    }
    

    and the (static) GenerateKeyPairs(int keySize) posted in the question shows, using the hexadecimal representation, that both public keys are identical as expected.