Browse Source

Merge pull request #226 from dcousens/rfc6979fix

Stricter ecdsa RFC 6979 adherence
hk-custom-address
Kyle Drake 11 years ago
parent
commit
0198477c6d
  1. 34
      package.json
  2. 52
      src/ecdsa.js
  3. 18
      test/ecdsa.js
  4. 2
      test/eckey.js

34
package.json

@ -36,42 +36,42 @@
"url": "https://github.com/bitcoinjs/bitcoinjs-lib.git"
},
"devDependencies": {
"mocha": "1.18.2",
"istanbul": "0.1.30",
"uglify-js": "2.4.13",
"sinon": "1.9.0",
"browserify": "~4.1.5",
"coveralls": "~2.10.0",
"mocha-lcov-reporter": "0.0.1",
"helloblock-js": "^0.2.1",
"browserify": "~4.1.5",
"jshint": "2.5.1"
"istanbul": "0.1.30",
"jshint": "2.5.1",
"mocha": "1.18.2",
"mocha-lcov-reporter": "0.0.1",
"sinon": "1.9.0",
"uglify-js": "2.4.13"
},
"testling": {
"browsers": [
"android-browser/4.2..latest",
"chrome/20..latest",
"firefox/21..latest",
"safari/latest",
"opera/15..latest",
"iphone/6..latest",
"ipad/6..latest",
"android-browser/4.2..latest"
"iphone/6..latest",
"opera/15..latest",
"safari/latest"
],
"harness": "mocha-bdd",
"files": "test/*.js"
},
"scripts": {
"unit": "./node_modules/.bin/istanbul test ./node_modules/.bin/_mocha -- --reporter list `find test -maxdepth 1 -not -type d`",
"test": "npm run-script unit",
"integration": "./node_modules/.bin/_mocha --reporter list test/integration/*.js",
"jshint": "./node_modules/.bin/jshint --config jshint.json src/*.js ; true",
"compile": "./node_modules/.bin/browserify ./src/index.js -s Bitcoin | ./node_modules/.bin/uglifyjs > bitcoinjs-min.js",
"coverage": "./node_modules/.bin/istanbul cover ./node_modules/.bin/_mocha -- --reporter list test/*.js",
"coveralls": "npm run-script coverage && node ./node_modules/.bin/coveralls < coverage/lcov.info",
"compile": "./node_modules/.bin/browserify ./src/index.js -s Bitcoin | ./node_modules/.bin/uglifyjs > bitcoinjs-min.js"
"integration": "./node_modules/.bin/_mocha --reporter list test/integration/*.js",
"jshint": "./node_modules/.bin/jshint --config jshint.json src/*.js ; true",
"test": "npm run-script unit",
"unit": "./node_modules/.bin/istanbul test ./node_modules/.bin/_mocha -- --reporter list `find test -maxdepth 1 -not -type d`"
},
"dependencies": {
"bigi": "1.1.0",
"crypto-js": "3.1.2-3",
"ecurve": "0.9.0",
"ecurve": "0.10.0",
"secure-random": "0.2.1"
}
}

52
src/ecdsa.js

@ -5,6 +5,7 @@ var BigInteger = require('bigi')
var ECSignature = require('./ecsignature')
var Point = require('ecurve').Point
// https://tools.ietf.org/html/rfc6979#section-3.2
function deterministicGenerateK(curve, hash, d) {
assert(Buffer.isBuffer(hash), 'Hash must be a Buffer, not ' + hash)
assert.equal(hash.length, 32, 'Hash must be 256 bit')
@ -13,22 +14,40 @@ function deterministicGenerateK(curve, hash, d) {
var x = d.toBuffer(32)
var k = new Buffer(32)
var v = new Buffer(32)
k.fill(0)
// Step B
v.fill(1)
// Step C
k.fill(0)
// Step D
k = crypto.HmacSHA256(Buffer.concat([v, new Buffer([0]), x, hash]), k)
// Step E
v = crypto.HmacSHA256(v, k)
// Step F
k = crypto.HmacSHA256(Buffer.concat([v, new Buffer([1]), x, hash]), k)
// Step G
v = crypto.HmacSHA256(v, k)
// Step H1/H2a, ignored as tlen === qlen (256 bit)
// Step H2b
v = crypto.HmacSHA256(v, k)
var n = curve.n
var kB = BigInteger.fromBuffer(v).mod(n)
assert(kB.compareTo(BigInteger.ONE) > 0, 'Invalid k value')
assert(kB.compareTo(n) < 0, 'Invalid k value')
var T = BigInteger.fromBuffer(v)
return kB
// Step H3, repeat until T is within the interval [1, n - 1]
while ((T.signum() <= 0) || (T.compareTo(curve.n) >= 0)) {
k = crypto.HmacSHA256(Buffer.concat([v, new Buffer([0])]), k)
v = crypto.HmacSHA256(v, k)
T = BigInteger.fromBuffer(v)
}
return T
}
function sign(curve, hash, d) {
@ -97,8 +116,7 @@ function recoverPubKey(curve, e, signature, i) {
var s = signature.s
// A set LSB signifies that the y-coordinate is odd
// By reduction, the y-coordinate is even if it is clear
var isYEven = !(i & 1)
var isYOdd = i & 1
// The more significant bit specifies whether we should use the
// first or second candidate key.
@ -106,28 +124,12 @@ function recoverPubKey(curve, e, signature, i) {
var n = curve.n
var G = curve.G
var p = curve.p
var a = curve.a
var b = curve.b
// We precalculate (p + 1) / 4 where p is the field order
if (!curve.P_OVER_FOUR) {
curve.P_OVER_FOUR = p.add(BigInteger.ONE).shiftRight(2)
}
// 1.1 Let x = r + jn
var x = isSecondKey ? r.add(n) : r
// 1.2, 1.3 Convert x to a point R using routine specified in Section 2.3.4
var alpha = x.pow(3).add(a.multiply(x)).add(b).mod(p)
var beta = alpha.modPow(curve.P_OVER_FOUR, p)
// If beta is even, but y isn't, or vice versa, then convert it,
// otherwise we're done and y == beta.
var y = (beta.isEven() ^ isYEven) ? p.subtract(beta) : beta
var R = curve.pointFromX(isYOdd, x)
// 1.4 Check that nR is at infinity
var R = Point.fromAffine(curve, x, y)
var nR = R.multiply(n)
assert(curve.isInfinity(nR), 'nR is not a valid curve point')

18
test/ecdsa.js

@ -3,6 +3,7 @@ var crypto = require('../src/crypto')
var ecdsa = require('../src/ecdsa')
var message = require('../src/message')
var networks = require('../src/networks')
var sinon = require('sinon')
var BigInteger = require('bigi')
var ECSignature = require('../src/ecsignature')
@ -15,7 +16,7 @@ var fixtures = require('./fixtures/ecdsa.json')
describe('ecdsa', function() {
describe('deterministicGenerateK', function() {
fixtures.valid.forEach(function(f) {
it('determines k for \"' + f.message + '\"', function() {
it('for \"' + f.message + '\"', function() {
var d = BigInteger.fromHex(f.d)
var h1 = crypto.sha256(f.message)
@ -23,6 +24,21 @@ describe('ecdsa', function() {
assert.equal(k.toHex(), f.k)
})
})
it('loops until an appropriate k value is found', sinon.test(function() {
this.mock(BigInteger).expects('fromBuffer')
.exactly(3)
.onCall(0).returns(new BigInteger('0'))
.onCall(1).returns(curve.n)
.onCall(2).returns(new BigInteger('42'))
var d = new BigInteger('1')
var h1 = new Buffer(32)
var k = ecdsa.deterministicGenerateK(curve, h1, d)
assert.equal(k.toString(), '42')
}))
})
describe('recoverPubKey', function() {

2
test/eckey.js

@ -26,7 +26,7 @@ describe('ECKey', function() {
var d = new BigInteger(f.d)
var privKey = new ECKey(d)
assert.equal(privKey.pub.Q.toString(), f.Q.toString())
assert.equal(privKey.pub.Q.toString(), f.Q)
})
})

Loading…
Cancel
Save