椭圆(JS lib)和Bouncy Castle(.NET lib)之间不一致的公钥派生

时间:2022-05-02 18:23:52

I have generated two key pairs (secp256k1) using elliptic library (JavaScript). When I take generated private key and use Bouncy Castle library (.NET) to derive the public key, I don't always get the same public key as from elliptic.

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

In the examples below, case 1 produced same public key in both libraries, but case 2 produced a different public key.

在下面的示例中,案例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

It is worth mentioning that if I generate the key pairs using Bouncy Castle, they always result in same public key when derived using elliptic.

值得一提的是,如果我使用Bouncy Castle生成密钥对,它们在使用椭圆导出时总是会产生相同的公钥。

I'm not sure if this is a library problem, or the way I'm using it, but the code (JS) is very simple:

我不确定这是一个库问题,还是我使用它的方式,但代码(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');

This is the code using Bouncy Castle lib in F#:

这是使用F#中的Bouncy Castle lib的代码:

let curve = SecNamedCurves.GetByName("secp256k1")
let domain = ECDomainParameters(curve.Curve, curve.G, curve.N, curve.H)

// Generate a key pair
let secureRandom = SecureRandom()
let keyGenParams = ECKeyGenerationParameters(domain, secureRandom)

let gen = ECKeyPairGenerator()
gen.Init(keyGenParams)

let keyPair = gen.GenerateKeyPair()

let privateKey = (keyPair.Private :?> ECPrivateKeyParameters).D.ToByteArray()
let publicKey = (keyPair.Public :?> ECPublicKeyParameters).Q.GetEncoded()

// Calculate public key from private key
curve.G.Multiply(BigInteger privateKey).GetEncoded()

Can anyone provide any insight into this issue, or recommend a different JS library I could use?

任何人都可以提供任何有关此问题的见解,或推荐一个我可以使用的不同的JS库?

1 个解决方案

#1


1  

As @dave_thompson_085 suggested, the problem is in BigInteger instantiation. BC BigInteger constructor, which take single byte[] parameter threats first bit of first byte as sign. In your second case private key starts with 9e, and BC creates negative number. The correct C# code to convert private key to public:

正如@ dave_thompson_085建议的那样,问题出在BigInteger实例化中。 BC BigInteger构造函数,它将单字节[]参数威胁第一个字节的第一位作为符号。在第二种情况下,私钥以9e开头,BC创建负数。将私钥转换为public的正确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));

#1


1  

As @dave_thompson_085 suggested, the problem is in BigInteger instantiation. BC BigInteger constructor, which take single byte[] parameter threats first bit of first byte as sign. In your second case private key starts with 9e, and BC creates negative number. The correct C# code to convert private key to public:

正如@ dave_thompson_085建议的那样,问题出在BigInteger实例化中。 BC BigInteger构造函数,它将单字节[]参数威胁第一个字节的第一位作为符号。在第二种情况下,私钥以9e开头,BC创建负数。将私钥转换为public的正确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));