2

我不知道这应该是超级简单的。

我有C#和 BouncyCastle(也是 C#)加密库。

我只需要提供一个字节数组作为私钥,指定使用的曲线并获取公钥。

我的曲线是 SEC-P-256-K1/secp256k1,但如果你能帮助我在我不需要或关心的选项和课程的海洋中导航,我可以自己设置。

4

3 回答 3

1

这就是解决方案。我被 Curve 构造函数采用参数“q”弄糊涂了,该参数实际上应该是“p”(该字段的素数模数)。

我也不明白为什么我必须自己做这么多,比如点乘法来获得公钥。其他没有读过 EC 数学的人怎么会知道这样做呢?

为什么没有“GetPubKey”方法!?!

哦,我希望这对某人有所帮助。我想,用户友好并不是 BouncyCastle 的意义所在。

using Org.BouncyCastle.Security;
using Org.BouncyCastle.Math.EC;
using Org.BouncyCastle.Math;
using Org.BouncyCastle.Crypto.Parameters;
using System.Text.RegularExpressions;

public static Tuple<byte[], byte[]> GetSecp256k1PublicKey(byte[] privateKey)
        {
            //Secp256k1 curve variables - https://en.bitcoin.it/wiki/Secp256k1
            var privKeyInt = new BigInteger(+1, privateKey);
            var a = new BigInteger("0");
            var b = new BigInteger("7");
            var GX = new BigInteger(+1, HexStringToByteArray("79BE667E F9DCBBAC 55A06295 CE870B07 029BFCDB 2DCE28D9 59F2815B 16F81798"));
            var GY = new BigInteger(+1, HexStringToByteArray("483ADA77 26A3C465 5DA4FBFC 0E1108A8 FD17B448 A6855419 9C47D08F FB10D4B8"));
            var n = new BigInteger(+1, HexStringToByteArray("FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE BAAEDCE6 AF48A03B BFD25E8C D0364141"));
            var h = new BigInteger("1");
            var p = new BigInteger(+1, HexStringToByteArray("FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE FFFFFC2F"));
            var q = h.Multiply(n).Mod(p); //Is this right???
            //- http://en.wikipedia.org/wiki/Elliptic_curve_cryptography

            ECCurve curve = new Org.BouncyCastle.Math.EC.FpCurve(p, a, b);
            ECPoint G = new Org.BouncyCastle.Math.EC.FpPoint(curve, new FpFieldElement(p, GX), new FpFieldElement(p, GY));

            var Qa = G.Multiply(privKeyInt);

            byte[] PubKeyX = Qa.X.ToBigInteger().ToByteArrayUnsigned();
            byte[] PubKeyY = Qa.Y.ToBigInteger().ToByteArrayUnsigned();

            return Tuple.Create<byte[], byte[]>(PubKeyX, PubKeyY);
        }

        public static byte[] HexStringToByteArray(string hex)
        {
            if(String.IsNullOrWhiteSpace(hex))
                return new byte[0];

            hex = Regex.Replace(hex, "[\\s-\\{}]", "");

            if (hex.Length % 2 == 1)
                throw new Exception("The binary key cannot have an odd number of digits.");

            if (!Regex.IsMatch(hex, "(^|\\A)[0-9A-Fa-f]*(\\Z|$)"))
                throw new Exception("Not hex.");

            byte[] arr = new byte[hex.Length >> 1];

            hex = hex.ToUpper();

            for (int i = 0; i < hex.Length >> 1; ++i)
            {
                arr[i] = (byte)((GetHexVal(hex[i << 1]) << 4) + (GetHexVal(hex[(i << 1) + 1])));
            }

            return arr;
        }
于 2015-02-19T01:46:49.623 回答
1

马丁的回答似乎很好,但可能更容易做到:

public Tuple<byte[],byte[]> GetPublicKey(byte[] privateKey)
{
    BigInteger privKeyInt = new BigInteger(+1, privateKey);

    var parameters = SecNamedCurves.GetByName("secp256k1");
    ECPoint qa = parameters.G.Multiply(privKeyInt);

    byte[] pubKeyX = qa.X.ToBigInteger().ToByteArrayUnsigned();
    byte[] pubKeyY = qa.Y.ToBigInteger().ToByteArrayUnsigned();

    return Tuple.Create(pubKeyX, pubKeyY);
}
于 2015-11-16T04:49:36.270 回答
0

使用Vasiliy的答案,我一直在努力获得与教程相同的结果,但在通过添加更改他的代码后终于得到了正确的结果.Normalize()

public Tuple<byte[],byte[]> GetPublicKey(byte[] privateKey){
    BigInteger privKeyInt = new BigInteger(+1, privateKey);

    var parameters = SecNamedCurves.GetByName("secp256k1");
    ECPoint qa = parameters.G.Multiply(privKeyInt).Normalize();

    byte[] pubKeyX = qa.XCoord.ToBigInteger().ToByteArrayUnsigned();
    byte[] pubKeyY = qa.YCoord.ToBigInteger().ToByteArrayUnsigned();

    return Tuple.Create(pubKeyX, pubKeyY);
}

我会将其添加为评论,但可惜声誉不足。

于 2019-05-31T15:39:06.973 回答