Skip to content

Instantly share code, notes, and snippets.

@josh-hernandez-exe
Last active August 31, 2023 13:24
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save josh-hernandez-exe/f7e173f85733830bdcf9b591caffd5ae to your computer and use it in GitHub Desktop.
Save josh-hernandez-exe/f7e173f85733830bdcf9b591caffd5ae to your computer and use it in GitHub Desktop.
`secp256k1` specified key generation in different languages

Making secp256k1 public keys with a given private key in different languages and different libraries

Using Bouncy Castle in C#

using System;
using System.Collections;
using System.Linq;
using System.Text;

using Org.BouncyCastle.Asn1.Sec;
using Org.BouncyCastle.Asn1.X9;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Math;
using Org.BouncyCastle.Math.EC;

namespace Program.Main
{
    class Program
    {
        public static readonly X9ECParameters _ecparameters = SecNamedCurves.GetByName("secp256k1");
        public static readonly ECDomainParameters domain = new ECDomainParameters(_ecparameters.Curve, _ecparameters.G, _ecparameters.N, _ecparameters.H);

        public static string ByteArrayToString(byte[] ba)
        {
            StringBuilder hex = new StringBuilder(ba.Length * 2);
            foreach (byte b in ba)
                hex.AppendFormat("{0:x2}", b);
            return hex.ToString();
        }

        public static (string,string) GetPublicKey(BigInteger privKeyInt)
        {
            var publicParams = new ECPublicKeyParameters(qa, domain);
            byte[] publicKeyByteArray = publicParams.Q.GetEncoded();
            int size = (publicKeyByteArray.Length - 1) / 2;
            byte[] publicX = publicKeyByteArray.Skip(1).Take(size).ToArray();
            byte[] publicY = publicKeyByteArray.Skip(1+size).Take(size).ToArray();

            return (ByteArrayToString(publicX),ByteArrayToString(publicY));
        }
        static void Main()
        {
            string pKeyStr = "7511fcc16faa2e06b7e0672e258f2d3721a8191e1553444b21e16e95609e1030";
            string expectedX = "7afa3a377b5808e4223dd62542a6e7e46ab0be95873464520193c1857ec2bb8f";
            string expectedY = "58b050b73f31f1b8b98c0b04513257433bdad2a51188642d8b0e515fbfb3125f";
            BigInteger privKeyInt = new BigInteger(pKeyStr,16);
            var (pubXStr,pubYStr) = GetPublicKey(privKeyInt);

            // compare x on public key
            Console.Write($"X:{pubXStr == expectedX}");
            // compare y on public key
            Console.Write($"Y:{pubYStr == expectedY}");
        }
    }
}

Using pyecdsa in python

from ecdsa import SECP256k1, SigningKey

pkey_str = "7511fcc16faa2e06b7e0672e258f2d3721a8191e1553444b21e16e95609e1030"
expected_x = int("7afa3a377b5808e4223dd62542a6e7e46ab0be95873464520193c1857ec2bb8f",16)
expected_y = int("58b050b73f31f1b8b98c0b04513257433bdad2a51188642d8b0e515fbfb3125f",16)

aa = SigningKey.from_string(bytes(bytearray.fromhex(pkey_str)),curve=SECP256k1)
# sanity check on private key
print("p:{}".format(aa.privkey.secret_multiplier == int(pkey_str,16)))
# compare x on public key
print("x:{}".format(aa.privkey.public_key.point.x() == expected_x))
# compare y on public key
print("y:{}".format(aa.privkey.public_key.point.y() == expected_y))

Using a python wrapper for libsecp256k1

import secp256k1

pkey_str = "7511fcc16faa2e06b7e0672e258f2d3721a8191e1553444b21e16e95609e1030"
expected_x = "7afa3a377b5808e4223dd62542a6e7e46ab0be95873464520193c1857ec2bb8f"
expected_y = "58b050b73f31f1b8b98c0b04513257433bdad2a51188642d8b0e515fbfb3125f"
aa = secp256k1.PrivateKey(bytes.fromhex(pkey_str), raw=True)
bb = aa.pubkey.serialize(compressed=False)
bb = bb[1:] # get rid of the first byte
bx = bb[:len(bb)//2]
by = bb[len(bb)//2:]
print("x:{}".format(bx.hex() == expected_x))
print("y:{}".format(by.hex() == expected_y))

Using elliptic in nodeJS

const EC = require('elliptic').ec;
const ec = new EC('secp256k1');
const pKeyStr = "7511fcc16faa2e06b7e0672e258f2d3721a8191e1553444b21e16e95609e1030";
const expectedX = "7afa3a377b5808e4223dd62542a6e7e46ab0be95873464520193c1857ec2bb8f";
const expectedY = "58b050b73f31f1b8b98c0b04513257433bdad2a51188642d8b0e515fbfb3125f";

aa = ec.keyFromPrivate(pKeyStr,'hex')
bb = aa.getPublic()
console.log(`x:${bb.x.toBuffer().toString('hex') === expectedX}`)
console.log(`y:${bb.y.toBuffer().toString('hex') === expectedY}`)

Using a nodeJS wrapper for libsecp256k1

const secp256k1 = require('secp256k1')
const pKeyStr = "7511fcc16faa2e06b7e0672e258f2d3721a8191e1553444b21e16e95609e1030";
const expectedX = "7afa3a377b5808e4223dd62542a6e7e46ab0be95873464520193c1857ec2bb8f";
const expectedY = "58b050b73f31f1b8b98c0b04513257433bdad2a51188642d8b0e515fbfb3125f";

// get the public key in a compressed format
const pubKey = secp256k1.publicKeyCreate(Buffer.from(pKeyStr,"hex"),false)
const bb = pubKey.slice(1) // get rid of the first byte
const bx = bb.slice(0,bb.length/2)
const by = bb.slice(bb.length/2)
console.log(`x:${bx.toString('hex') === expectedX}`)
console.log(`y:${by.toString('hex') === expectedY}`)
@chobyungkwon
Copy link

ECPublicKeyParameters(qa, domain); parameter qa ?

@christmas96
Copy link

ECPublicKeyParameters(qa, domain); parameter qa ?

domain.G.Multiply(privKeyInt)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment