Problem generating Bitcoin public key in C#

Problem generating Bitcoin public key in C#

I'm working on a program that converts a Bitcoin private key to a public key. I've done a lot of searching and looked at a lot of documentation and code. And I've tested the following C# code presented here: Read more It converts some private keys to public keys correctly, but it doesn't convert some private keys to public keys correctly. For example, consider the following private key: b5639dccd31e3694e53e4d2cfea652dc0ab4be5183fdfc6017eb09b1def82970

The public key is exactly as follows: 04cbadea7f70bb1c885773e3727699773febe8ced1ec1ee73ea952409e6a77b4483a1eb131d0a9e0e3588a88cfbb8a0c74136967e97c297939f2e1b75b3d4bc757

But the program generates the key as follows: It produces 0479BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8 which is wrong but for the following private key 22c355eaf7cf3822520e6e02b1fc996d7c2cd8376451599101a64f8d5ddc4634 it generates the following public key which is correct is 048a4ea6d6db213b32f6c5e48f041481539303ce755dad8e0e042ca012c234f30d36c1f5348a8bdeed856af5948c645cce1eb86813c467bd5e89a8386311be4420

Apparently all parts of the code are correct but I don't know what exactly is the problem. Can anyone help me with this?

Answer

This is the code:

class CalcPub
{
    public static void Main()
    {
        var p = BigInteger.Parse("0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F", NumberStyles.HexNumber);
        var b = (BigInteger)7;
        var a = BigInteger.Zero;
        var Gx = BigInteger.Parse("79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798", NumberStyles.HexNumber);
        var Gy = BigInteger.Parse("483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8", NumberStyles.HexNumber);

        CurveFp curve256 = new CurveFp(p, a, b);
        Point generator256 = new Point(curve256, Gx, Gy);

        var secret = BigInteger.Parse("18E14A7B6A307F426A94F8114701E7C8E774E7F9A47E2C2035DB29A206321725", NumberStyles.HexNumber);

        Console.WriteLine("secret {0}", secret.ToString("X"));
        var pubkeyPoint = generator256 * secret;
        Console.WriteLine("pubkey {0}{1}", pubkeyPoint.X.ToString("X"), pubkeyPoint.Y.ToString("X"));
    }
}
class Point
{
    public static readonly Point INFINITY = new Point(null, default(BigInteger), default(BigInteger));
    public CurveFp Curve { get; private set; }
    public BigInteger X { get; private set; }
    public BigInteger Y { get; private set; }

    public Point(CurveFp curve, BigInteger x, BigInteger y)
    {
        this.Curve = curve;
        this.X = x;
        this.Y = y;
    }
    public Point Double()
    {
        if (this == INFINITY)
            return INFINITY;

        BigInteger p = this.Curve.p;
        BigInteger a = this.Curve.a;
        BigInteger l = ((3 * this.X * this.X + a) * InverseMod(2 * this.Y, p)) % p;
        BigInteger x3 = (l * l - 2 * this.X) % p;
        BigInteger y3 = (l * (this.X - x3) - this.Y) % p;
        return new Point(this.Curve, x3, y3);
    }
    public override string ToString()
    {
        if (this == INFINITY)
            return "infinity";
        return string.Format("({0},{1})", this.X, this.Y);
    }
    public static Point operator +(Point left, Point right)
    {
        if (right == INFINITY)
            return left;
        if (left == INFINITY)
            return right;
        if (left.X == right.X)
        {
            if ((left.Y + right.Y) % left.Curve.p == 0)
                return INFINITY;
            else
                return left.Double();
        }

        var p = left.Curve.p;
        var l = ((right.Y - left.Y) * InverseMod(right.X - left.X, p)) % p;
        var x3 = (l * l - left.X - right.X) % p;
        var y3 = (l * (left.X - x3) - left.Y) % p;
        return new Point(left.Curve, x3, y3);
    }
    public static Point operator *(Point left, BigInteger right)
    {
        var e = right;
        if (e == 0 || left == INFINITY)
            return INFINITY;
        var e3 = 3 * e;
        var negativeLeft = new Point(left.Curve, left.X, -left.Y);
        var i = LeftmostBit(e3) / 2;
        var result = left;
        while (i > 1)
        {
            result = result.Double();
            if ((e3 & i) != 0 && (e & i) == 0)
                result += left;
            if ((e3 & i) == 0 && (e & i) != 0)
                result += negativeLeft;
            i /= 2;
        }
        return result;
    }

    private static BigInteger LeftmostBit(BigInteger x)
    {
        BigInteger result = 1;
        while (result <= x)
            result = 2 * result;
        return result / 2;
    }
    private static BigInteger InverseMod(BigInteger a, BigInteger m)
    {
        while (a < 0) a += m;
        if (a < 0 || m <= a)
            a = a % m;
        BigInteger c = a;
        BigInteger d = m;

        BigInteger uc = 1;
        BigInteger vc = 0;
        BigInteger ud = 0;
        BigInteger vd = 1;

        while (c != 0)
        {
            BigInteger r;
            //q, c, d = divmod( d, c ) + ( c, );
            var q = BigInteger.DivRem(d, c, out r);
            d = c;
            c = r;

            //uc, vc, ud, vd = ud - q*uc, vd - q*vc, uc, vc;
            var uct = uc;
            var vct = vc;
            var udt = ud;
            var vdt = vd;
            uc = udt - q * uct;
            vc = vdt - q * vct;
            ud = uct;
            vd = vct;
        }
        if (ud > 0) return ud;
        else return ud + m;
    }
}
class CurveFp
{
    public BigInteger p { get; private set; }
    public BigInteger a { get; private set; }
    public BigInteger b { get; private set; }
    public CurveFp(BigInteger p, BigInteger a, BigInteger b)
    {
        this.p = p;
        this.a = a;
        this.b = b;
    }
}

Enjoyed this article?

Check out more content on our blog or follow us on social media.

Browse more articles