indutny/elliptic

Curves p384 and p521 produce incorrect results

guidovranken opened this issue · 1 comments

Reproducer using Botan:

#include <botan/ecdsa.h>
#include <botan/system_rng.h>
#include <string>
#include <iostream>

static void PrivToPub(const std::string curve)
{
    static ::Botan::System_RNG rng;
    const ::Botan::EC_Group group(curve);
    const ::Botan::BigInt priv_bn("12345");
    const auto priv = std::make_unique<::Botan::ECDSA_PrivateKey>(::Botan::ECDSA_PrivateKey(rng, group, priv_bn));

    std::cout << "Curve: " << curve << std::endl;
    std::cout << "X: " << priv->public_point().get_affine_x().to_dec_string() << std::endl;
    std::cout << "Y: " << priv->public_point().get_affine_y().to_dec_string() << std::endl;
    std::cout << std::endl;
}

int main(void)
{
    PrivToPub("secp256k1");
    PrivToPub("secp224r1");
    PrivToPub("secp384r1");
    PrivToPub("secp521r1");
    return 0;
}

Equivalent program using elliptic:

var elliptic = require('elliptic');

{
	var ec = new elliptic.ec({curve: elliptic.curves.secp256k1});
	var key = ec.keyFromPrivate('3039');
	console.log('curve: secp256k1');
	console.log('X: ' + key.getPublic().x.toString(10));
	console.log('Y: ' + key.getPublic().y.toString(10));
	console.log('');
}

{
	var ec = new elliptic.ec({curve: elliptic.curves.p224});
	var key = ec.keyFromPrivate('3039');
	console.log('curve: p224');
	console.log('X: ' + key.getPublic().x.toString(10));
	console.log('Y: ' + key.getPublic().y.toString(10));
	console.log('');
}

{
	var ec = new elliptic.ec({curve: elliptic.curves.p384});
	var key = ec.keyFromPrivate('3039');
	console.log('curve: p384');
	console.log('X: ' + key.getPublic().x.toString(10));
	console.log('Y: ' + key.getPublic().y.toString(10));
	console.log('');
}

{
	var ec = new elliptic.ec({curve: elliptic.curves.p521});
	var key = ec.keyFromPrivate('3039');
	console.log('curve: p521');
	console.log('X: ' + key.getPublic().x.toString(10));
	console.log('Y: ' + key.getPublic().y.toString(10));
	console.log('');
}

Botan reproducer prints:

Curve: secp256k1
X: 108607064596551879580190606910245687803607295064141551927605737287325610911759
Y: 6661302038839728943522144359728938428925407345457796456954441906546235843221

Curve: secp224r1
X: 3061900986193955425366457130965731838162532927611279465996423024034
Y: 18436067477095612653254216315762663287666664157889344177897564496249

Curve: secp384r1
X: 35772759585181787162268297474325652116815155765657644698345476493584618538330055829427528668512916462287191873719067
Y: 11136899713791192969974754349937219423803684580341842804433199322289941602306230647993576394757614557497720559657288

Curve: secp521r1
X: 99544213233443820423376623401842180038965950176775066024883365929328361117690710401394035951689292192082505666564905615167418780069649851129620356638766987
Y: 2400946881406844793138710845595355668053990247257733123230579507952350364035969673918344323836676104120174871607342463555389727042619568128535308503671291243

Elliptic reproducer prints:

curve: secp256k1
X: 108607064596551879580190606910245687803607295064141551927605737287325610911759
Y: 6661302038839728943522144359728938428925407345457796456954441906546235843221

curve: p224
X: 3061900986193955425366457130965731838162532927611279465996423024034
Y: 18436067477095612653254216315762663287666664157889344177897564496249

curve: p384
X: 15941129259703095806264506659575749372880183073752251579688675604437627307921357714103205186440293320524822325334223
Y: 22114920023073815056562105355911861035316317138200933415326341832754453118525583611873937475730301300025198969292291

curve: p521
X: 6719624281204685093485624880339661406616448960108927079674841988221937850012818464143226635650263055104211416481283153210468239891263449137663298022106688673
Y: 6149109476795150499310805847422629696752311120031290394754441545101372775372418633331331052611061203579528734291675940658254460750694406316130731176620134943
tiran commented

PyCA/cryptography gives the same results as Botan. PyCA/cryptography is Python package that wraps OpenSSL.

>>> for curve in [ec.SECP224R1(), ec.SECP256K1(), ec.SECP256R1(), ec.SECP384R1(), ec.SECP521R1()]:
...     print(f"\ncurve: {curve.name}")
...     private = ec.derive_private_key(12345, curve)
...     pn = private.public_key().public_numbers()
...     print(f"X: {pn.x}")
...     print(f"Y: {pn.y}")
... 

curve: secp224r1
X: 3061900986193955425366457130965731838162532927611279465996423024034
Y: 18436067477095612653254216315762663287666664157889344177897564496249

curve: secp256k1
X: 108607064596551879580190606910245687803607295064141551927605737287325610911759
Y: 6661302038839728943522144359728938428925407345457796456954441906546235843221

curve: secp256r1
X: 17611591551394103526348166819472991346437344487394483771310531299395461896210
Y: 65195855187618849542991473502236155813942564250927181129449382163772576288998

curve: secp384r1
X: 35772759585181787162268297474325652116815155765657644698345476493584618538330055829427528668512916462287191873719067
Y: 11136899713791192969974754349937219423803684580341842804433199322289941602306230647993576394757614557497720559657288

curve: secp521r1
X: 99544213233443820423376623401842180038965950176775066024883365929328361117690710401394035951689292192082505666564905615167418780069649851129620356638766987
Y: 2400946881406844793138710845595355668053990247257733123230579507952350364035969673918344323836676104120174871607342463555389727042619568128535308503671291243

I'm also getting wrong results for p256:

> var elliptic = require('elliptic');
undefined
> {
...     var ec = new elliptic.ec({curve: elliptic.curves.p256});
...     var key = ec.keyFromPrivate('3039');
...     console.log('curve: p256');
...     console.log('X: ' + key.getPublic().x.toString(10));
...     console.log('Y: ' + key.getPublic().y.toString(10));
...     console.log('');
... }
curve: p256
X: 105003158266435578313975033833341595362026738309362563411293911691181582754198
Y: 1182522404204752220518975651306205864863731740355544177119796735558160832019

undefined