From ccfaaf0b6fe77b710b8ec39ffbca2bbc4576a73a Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Tue, 25 Aug 2015 20:43:32 +1000 Subject: [PATCH] ecdsa: remove curve parameter --- src/ecdsa.js | 60 ++++++++++++++++++++++++++------------------------ src/ecpair.js | 8 +++---- src/message.js | 7 ++---- test/ecdsa.js | 33 ++++++++++++++------------- 4 files changed, 53 insertions(+), 55 deletions(-) diff --git a/src/ecdsa.js b/src/ecdsa.js index a5190b7..103095d 100644 --- a/src/ecdsa.js +++ b/src/ecdsa.js @@ -8,16 +8,17 @@ var ECSignature = require('./ecsignature') var ZERO = new Buffer([0]) var ONE = new Buffer([1]) +var ecurve = require('ecurve') +var secp256k1 = ecurve.getCurveByName('secp256k1') + // https://tools.ietf.org/html/rfc6979#section-3.2 -function deterministicGenerateK (curve, hash, d, checkSig) { +function deterministicGenerateK (hash, x, checkSig) { typeforce(types.tuple( - types.ECCurve, types.Hash256bit, - types.BigInt, + types.Buffer256bit, types.Function ), arguments) - var x = d.toBuffer(32) var k = new Buffer(32) var v = new Buffer(32) @@ -57,7 +58,7 @@ function deterministicGenerateK (curve, hash, d, checkSig) { var T = BigInteger.fromBuffer(v) // Step H3, repeat until T is within the interval [1, n - 1] and is suitable for ECDSA - while ((T.signum() <= 0) || (T.compareTo(curve.n) >= 0) || !checkSig(T)) { + while (T.signum() <= 0 || T.compareTo(secp256k1.n) >= 0 || !checkSig(T)) { k = createHmac('sha256', k) .update(v) .update(ZERO) @@ -74,18 +75,21 @@ function deterministicGenerateK (curve, hash, d, checkSig) { return T } -function sign (curve, hash, d) { - typeforce(types.tuple(types.ECCurve, types.Hash256bit, types.BigInt), arguments) +var N_OVER_TWO = secp256k1.n.shiftRight(1) +function sign (hash, d) { + typeforce(types.tuple(types.Hash256bit, types.BigInt), arguments) + + var x = d.toBuffer(32) var e = BigInteger.fromBuffer(hash) - var n = curve.n - var G = curve.G + var n = secp256k1.n + var G = secp256k1.G var r, s - deterministicGenerateK(curve, hash, d, function (k) { + deterministicGenerateK(hash, x, function (k) { var Q = G.multiply(k) - if (curve.isInfinity(Q)) return false + if (secp256k1.isInfinity(Q)) return false r = Q.affineX.mod(n) if (r.signum() === 0) return false @@ -96,8 +100,6 @@ function sign (curve, hash, d) { return true }) - var N_OVER_TWO = n.shiftRight(1) - // enforce low S values, see bip62: 'low s values in signatures' if (s.compareTo(N_OVER_TWO) > 0) { s = n.subtract(s) @@ -106,16 +108,15 @@ function sign (curve, hash, d) { return new ECSignature(r, s) } -function verify (curve, hash, signature, Q) { +function verify (hash, signature, Q) { typeforce(types.tuple( - types.ECCurve, types.Hash256bit, types.ECSignature, types.ECPoint ), arguments) - var n = curve.n - var G = curve.G + var n = secp256k1.n + var G = secp256k1.G var r = signature.r var s = signature.s @@ -141,7 +142,7 @@ function verify (curve, hash, signature, Q) { var R = G.multiplyTwo(u1, Q, u2) // 1.4.5 (cont.) Enforce R is not at infinity - if (curve.isInfinity(R)) return false + if (secp256k1.isInfinity(R)) return false // 1.4.6 Convert the field element R.x to an integer var xR = R.affineX @@ -161,16 +162,15 @@ function verify (curve, hash, signature, Q) { * * http://www.secg.org/download/aid-780/sec1-v2.pdf */ -function recoverPubKey (curve, e, signature, i) { +function recoverPubKey (e, signature, i) { typeforce(types.tuple( - types.ECCurve, types.BigInt, types.ECSignature, types.UInt2 ), arguments) - var n = curve.n - var G = curve.G + var n = secp256k1.n + var G = secp256k1.G var r = signature.r var s = signature.s @@ -186,11 +186,11 @@ function recoverPubKey (curve, e, signature, i) { // 1.1 Let x = r + jn var x = isSecondKey ? r.add(n) : r - var R = curve.pointFromX(isYOdd, x) + var R = secp256k1.pointFromX(isYOdd, x) // 1.4 Check that nR is at infinity var nR = R.multiply(n) - if (!curve.isInfinity(nR)) throw new Error('nR is not a valid curve point') + if (!secp256k1.isInfinity(nR)) throw new Error('nR is not a valid curve point') // Compute r^-1 var rInv = r.modInverse(n) @@ -202,7 +202,7 @@ function recoverPubKey (curve, e, signature, i) { // Q = r^-1 (sR + -eG) var Q = R.multiplyTwo(s, G, eNeg).multiply(rInv) - curve.validate(Q) + secp256k1.validate(Q) return Q } @@ -218,16 +218,15 @@ function recoverPubKey (curve, e, signature, i) { * This function simply tries all four cases and returns the value * that resulted in a successful pubkey recovery. */ -function calcPubKeyRecoveryParam (curve, e, signature, Q) { +function calcPubKeyRecoveryParam (e, signature, Q) { typeforce(types.tuple( - types.ECCurve, types.BigInt, types.ECSignature, types.ECPoint ), arguments) for (var i = 0; i < 4; i++) { - var Qprime = recoverPubKey(curve, e, signature, i) + var Qprime = recoverPubKey(e, signature, i) // 1.6.2 Verify Q if (Qprime.equals(Q)) { @@ -243,5 +242,8 @@ module.exports = { deterministicGenerateK: deterministicGenerateK, recoverPubKey: recoverPubKey, sign: sign, - verify: verify + verify: verify, + + // TODO: remove + __curve: secp256k1 } diff --git a/src/ecpair.js b/src/ecpair.js index 9e8698b..e469638 100644 --- a/src/ecpair.js +++ b/src/ecpair.js @@ -1,7 +1,6 @@ var bcrypto = require('./crypto') var bs58check = require('bs58check') var ecdsa = require('./ecdsa') -var ecurve = require('ecurve') var randomBytes = require('randombytes') var typeforce = require('typeforce') var types = require('./types') @@ -10,7 +9,8 @@ var wif = require('wif') var NETWORKS = require('./networks') var BigInteger = require('bigi') -var secp256k1 = ecurve.getCurveByName('secp256k1') +var ecurve = require('ecurve') +var secp256k1 = ecdsa.__curve function ECPair (d, Q, options) { if (options) { @@ -112,7 +112,7 @@ ECPair.prototype.getPublicKeyBuffer = function () { ECPair.prototype.sign = function (hash) { if (!this.d) throw new Error('Missing private key') - return ecdsa.sign(secp256k1, hash, this.d) + return ecdsa.sign(hash, this.d) } ECPair.prototype.toWIF = function () { @@ -122,7 +122,7 @@ ECPair.prototype.toWIF = function () { } ECPair.prototype.verify = function (hash, signature) { - return ecdsa.verify(secp256k1, hash, signature, this.Q) + return ecdsa.verify(hash, signature, this.Q) } module.exports = ECPair diff --git a/src/message.js b/src/message.js index 16fc1fe..29fe7dc 100644 --- a/src/message.js +++ b/src/message.js @@ -7,9 +7,6 @@ var BigInteger = require('bigi') var ECPair = require('./ecpair') var ECSignature = require('./ecsignature') -var ecurve = require('ecurve') -var ecparams = ecurve.getCurveByName('secp256k1') - function magicHash (message, network) { var messagePrefix = new Buffer(network.messagePrefix) var messageBuffer = new Buffer(message) @@ -25,7 +22,7 @@ function sign (keyPair, message, network) { var hash = magicHash(message, network) var signature = keyPair.sign(hash) var e = BigInteger.fromBuffer(hash) - var i = ecdsa.calcPubKeyRecoveryParam(ecparams, e, signature, keyPair.Q) + var i = ecdsa.calcPubKeyRecoveryParam(e, signature, keyPair.Q) return signature.toCompact(i, keyPair.compressed) } @@ -40,7 +37,7 @@ function verify (address, signature, message, network) { var hash = magicHash(message, network) var parsed = ECSignature.parseCompact(signature) var e = BigInteger.fromBuffer(hash) - var Q = ecdsa.recoverPubKey(ecparams, e, parsed.signature, parsed.i) + var Q = ecdsa.recoverPubKey(e, parsed.signature, parsed.i) var keyPair = new ECPair(null, Q, { compressed: parsed.compressed, diff --git a/test/ecdsa.js b/test/ecdsa.js index be83455..db7c8b3 100644 --- a/test/ecdsa.js +++ b/test/ecdsa.js @@ -10,8 +10,7 @@ var sinon = require('sinon') var BigInteger = require('bigi') var ECSignature = require('../src/ecsignature') -var ecurve = require('ecurve') -var curve = ecurve.getCurveByName('secp256k1') +var curve = ecdsa.__curve var fixtures = require('./fixtures/ecdsa.json') @@ -23,10 +22,10 @@ describe('ecdsa', function () { fixtures.valid.ecdsa.forEach(function (f) { it('for "' + f.message + '"', function () { - var d = BigInteger.fromHex(f.d) + var x = BigInteger.fromHex(f.d).toBuffer(32) var h1 = bcrypto.sha256(f.message) - var k = ecdsa.deterministicGenerateK(curve, h1, d, checkSig) + var k = ecdsa.deterministicGenerateK(h1, x, checkSig) assert.strictEqual(k.toHex(), f.k) }) }) @@ -38,9 +37,9 @@ describe('ecdsa', function () { .onCall(1).returns(curve.n) // > n-1 .onCall(2).returns(new BigInteger('42')) // valid - var d = new BigInteger('1') + var x = new BigInteger('1').toBuffer(32) var h1 = new Buffer(32) - var k = ecdsa.deterministicGenerateK(curve, h1, d, checkSig) + var k = ecdsa.deterministicGenerateK(h1, x, checkSig) assert.strictEqual(k.toString(), '42') })) @@ -58,20 +57,20 @@ describe('ecdsa', function () { checkSig.onCall(0).returns(false) // bad signature checkSig.onCall(1).returns(true) // good signature - var d = new BigInteger('1') + var x = new BigInteger('1').toBuffer(32) var h1 = new Buffer(32) - var k = ecdsa.deterministicGenerateK(curve, h1, d, checkSig) + var k = ecdsa.deterministicGenerateK(h1, x, checkSig) assert.strictEqual(k.toString(), '53') })) fixtures.valid.rfc6979.forEach(function (f) { it('produces the expected k values for ' + f.message + " if k wasn't suitable", function () { - var d = BigInteger.fromHex(f.d) + var x = BigInteger.fromHex(f.d).toBuffer(32) var h1 = bcrypto.sha256(f.message) var results = [] - ecdsa.deterministicGenerateK(curve, h1, d, function (k) { + ecdsa.deterministicGenerateK(h1, x, function (k) { results.push(k) return results.length === 16 @@ -92,7 +91,7 @@ describe('ecdsa', function () { var signature = ECSignature.fromDER(new Buffer(f.signature, 'hex')) var h1 = bcrypto.sha256(f.message) var e = BigInteger.fromBuffer(h1) - var Qprime = ecdsa.recoverPubKey(curve, e, signature, f.i) + var Qprime = ecdsa.recoverPubKey(e, signature, f.i) assert(Qprime.equals(Q)) }) @@ -113,7 +112,7 @@ describe('ecdsa', function () { points.forEach(function (expectedHex, i) { it('recovers an expected point for i of ' + i, function () { - var Qprime = ecdsa.recoverPubKey(curve, e, signature, i) + var Qprime = ecdsa.recoverPubKey(e, signature, i) var QprimeHex = Qprime.getEncoded().toString('hex') assert.strictEqual(QprimeHex, expectedHex) @@ -127,7 +126,7 @@ describe('ecdsa', function () { var signature = new ECSignature(new BigInteger(f.signatureRaw.r, 16), new BigInteger(f.signatureRaw.s, 16)) assert.throws(function () { - ecdsa.recoverPubKey(curve, e, signature, f.i) + ecdsa.recoverPubKey(e, signature, f.i) }, new RegExp(f.exception)) }) }) @@ -138,7 +137,7 @@ describe('ecdsa', function () { it('produces a deterministic signature for "' + f.message + '"', function () { var d = BigInteger.fromHex(f.d) var hash = bcrypto.sha256(f.message) - var signature = ecdsa.sign(curve, hash, d).toDER() + var signature = ecdsa.sign(hash, d).toDER() assert.strictEqual(signature.toString('hex'), f.signature) }) @@ -146,7 +145,7 @@ describe('ecdsa', function () { it('should sign with low S value', function () { var hash = bcrypto.sha256('Vires in numeris') - var sig = ecdsa.sign(curve, hash, BigInteger.ONE) + var sig = ecdsa.sign(hash, BigInteger.ONE) // See BIP62 for more information var N_OVER_TWO = curve.n.shiftRight(1) @@ -162,7 +161,7 @@ describe('ecdsa', function () { var signature = ECSignature.fromDER(new Buffer(f.signature, 'hex')) var Q = curve.G.multiply(d) - assert(ecdsa.verify(curve, H, signature, Q)) + assert(ecdsa.verify(H, signature, Q)) }) }) @@ -180,7 +179,7 @@ describe('ecdsa', function () { var Q = curve.G.multiply(d) - assert.strictEqual(ecdsa.verify(curve, H, signature, Q), false) + assert.strictEqual(ecdsa.verify(H, signature, Q), false) }) }) })