Cryptography 椭圆(JS-lib)和弹性城堡(.NET-lib)之间的公钥派生不一致

Cryptography 椭圆(JS-lib)和弹性城堡(.NET-lib)之间的公钥派生不一致,cryptography,bouncycastle,elliptic-curve,Cryptography,Bouncycastle,Elliptic Curve,我使用库(JavaScript)生成了两个密钥对(secp256k1)。当我获取生成的私钥并使用库(.NET)来派生公钥时,我并不总是获得与椭圆机相同的公钥 在下面的示例中,案例1在两个库中生成了相同的公钥,但案例2生成了不同的公钥 Case 1: Private Key: 1bd86a6ed359cbbd342ac1b35be5ac112ee71210a542ff86c2f5d304d1f6bd72 Public Key (elliptic): 0478eec03dac240f1be5bd81

我使用库(JavaScript)生成了两个密钥对(secp256k1)。当我获取生成的私钥并使用库(.NET)来派生公钥时,我并不总是获得与椭圆机相同的公钥

在下面的示例中,案例1在两个库中生成了相同的公钥,但案例2生成了不同的公钥

Case 1:
Private Key: 1bd86a6ed359cbbd342ac1b35be5ac112ee71210a542ff86c2f5d304d1f6bd72
Public Key (elliptic): 0478eec03dac240f1be5bd816b8a5a7ca0d41126a524abf0ae217200570e5ba34c47b96d57510779f443af3e9e7e434354bac205c210e2f96ca875d77976a436e6
Public Key (Bouncy Castle): 0478eec03dac240f1be5bd816b8a5a7ca0d41126a524abf0ae217200570e5ba34c47b96d57510779f443af3e9e7e434354bac205c210e2f96ca875d77976a436e6

Case 2:
Private Key: 9ede1270644719a1ab2557c11b99a0d5e00b2e7f1e4d073b794bf5424868be06
Public Key (elliptic): 0462097811d7af637460e86046a1ef7996f784aa6c1ca78adf2c19e49d9ce7a47cb9542164c2ee96b9a866efded0ab88042d155006adf8095b8b07157f0924f437
Public Key (Bouncy Castle): 048e22b2295c14505800610d6cc0cd8169852da500e2199281bacbdd5944a67da018d7f8864d1ce43c593eefd06b2f97f20dadb9452085989a26bbc87cf918a614
值得一提的是,如果我使用Bouncy Castle生成密钥对,那么当使用椭圆曲线进行派生时,它们总是得到相同的公钥

我不确定这是否是一个库问题,或者我使用它的方式,但代码(JS)非常简单:

var EC = require('elliptic').ec;
var ec = new EC('secp256k1');

// Generate a key pair
var keyPair = ec.genKeyPair();
var privateKey = keyPair.getPrivate('hex');
var publicKey = keyPair.getPublic('hex');

// Calculate public key from private key
ec.keyFromPrivate(somePrivateKey, 'hex').getPublic('hex');
这是在F#中使用Bouncy Castle lib的代码:


有谁能提供关于这个问题的见解,或者推荐我可以使用的不同JS库吗?

正如@dave_thompson_085所建议的,问题在于
biginger
实例化。BC
biginger
构造函数,它将单个
字节[]
参数的第一个字节的第一位作为符号。在第二种情况下,私钥以
9e
开头,BC创建负数。将私钥转换为公钥的正确C#代码:

byte[] data = Org.BouncyCastle.Utilities.Encoders.Hex.Decode("9ede1270644719a1ab2557c11b99a0d5e00b2e7f1e4d073b794bf5424868be06");

var curve = Org.BouncyCastle.Asn1.Sec.SecNamedCurves.GetByName("secp256k1");
var privateKey = new Org.BouncyCastle.Math.BigInteger(1, data); // 1 means positive number
var publicKey = curve.G.Multiply(privateKey);
byte[] pubKeyEncoded = publicKey.GetEncoded(false);

Console.WriteLine(Org.BouncyCastle.Utilities.Encoders.Hex.ToHexString(pubKeyEncoded));

在案例2中,椭圆密钥是正确的。不看你的BC代码就不能说任何东西。@Zergatul我用Bouncy添加了F代码Castle@Zergatul顺便问一下,你是如何检查哪一个是正确的?你用什么作为参考?我签入了OpenSSL和我自己的ECC代码。两者都获得
046209…
。我自己试过了,结果和你一样。我不相信,但它看起来像是BC中的一个bug。我不知道dotnet是否也一样,但在Java中,如果你用1-arg
BigInteger
ctor转换字节数组,它会将字节数组视为有符号数组,并将高位设置为第二个值,这会使它为负值,这对于ECC来说是非常错误的,因此,必须使用2-arg向量将其视为始终为正。
byte[] data = Org.BouncyCastle.Utilities.Encoders.Hex.Decode("9ede1270644719a1ab2557c11b99a0d5e00b2e7f1e4d073b794bf5424868be06");

var curve = Org.BouncyCastle.Asn1.Sec.SecNamedCurves.GetByName("secp256k1");
var privateKey = new Org.BouncyCastle.Math.BigInteger(1, data); // 1 means positive number
var publicKey = curve.G.Multiply(privateKey);
byte[] pubKeyEncoded = publicKey.GetEncoded(false);

Console.WriteLine(Org.BouncyCastle.Utilities.Encoders.Hex.ToHexString(pubKeyEncoded));