ECDSA 在 C# 中获取 public 密钥
ECDSA get public key in C#
我想不出来应该超级简单。
我有 C# 和 BouncyCastle(也是 C#)加密库。
我只需要给出一个字节数组作为私钥,指定使用的曲线并获取public密钥。
我的曲线是 SEC-P-256-K1/secp256k1,但真的,如果你能帮助我在选项的海洋中导航并且 类 我不需要或不关心我可以自己设置。
这就是解决方案。我对采用参数 'q' 的曲线构造函数感到困惑,该参数实际上应该是 'p'(场的素模)。
我也不明白为什么要自己做这么多点乘法来得到public密钥。其他没有读过 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;
}
Martin 的回答似乎不错,但可能更容易完成:
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);
}
使用 Vasiliy's answer I was struggling to get the same results as this 教程,但在通过添加 .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);
}
我会把它添加为评论,但遗憾的是没有足够的声誉。
我想不出来应该超级简单。
我有 C# 和 BouncyCastle(也是 C#)加密库。
我只需要给出一个字节数组作为私钥,指定使用的曲线并获取public密钥。
我的曲线是 SEC-P-256-K1/secp256k1,但真的,如果你能帮助我在选项的海洋中导航并且 类 我不需要或不关心我可以自己设置。
这就是解决方案。我对采用参数 'q' 的曲线构造函数感到困惑,该参数实际上应该是 'p'(场的素模)。
我也不明白为什么要自己做这么多点乘法来得到public密钥。其他没有读过 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;
}
Martin 的回答似乎不错,但可能更容易完成:
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);
}
使用 Vasiliy's answer I was struggling to get the same results as this 教程,但在通过添加 .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);
}
我会把它添加为评论,但遗憾的是没有足够的声誉。