Skip to content
This repository was archived by the owner on Jun 17, 2021. It is now read-only.

Commit 752585c

Browse files
committed
Add EIP-155 support
1 parent 19d2b1f commit 752585c

File tree

2 files changed

+48
-13
lines changed

2 files changed

+48
-13
lines changed

index.js

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -359,15 +359,16 @@ exports.importPublic = function (publicKey) {
359359
* ECDSA sign
360360
* @param {Buffer} msgHash
361361
* @param {Buffer} privateKey
362+
* @param {Number} [chainId]
362363
* @return {Object}
363364
*/
364-
exports.ecsign = function (msgHash, privateKey) {
365+
exports.ecsign = function (msgHash, privateKey, chainId) {
365366
const sig = secp256k1.sign(msgHash, privateKey)
366367

367368
const ret = {}
368369
ret.r = sig.signature.slice(0, 32)
369370
ret.s = sig.signature.slice(32, 64)
370-
ret.v = sig.recovery + 27
371+
ret.v = chainId ? sig.recovery + (chainId * 2 + 35) : sig.recovery + 27
371372
return ret
372373
}
373374

@@ -390,12 +391,13 @@ exports.hashPersonalMessage = function (message) {
390391
* @param {Number} v
391392
* @param {Buffer} r
392393
* @param {Buffer} s
394+
* @param {Number} [chainId]
393395
* @return {Buffer} publicKey
394396
*/
395-
exports.ecrecover = function (msgHash, v, r, s) {
397+
exports.ecrecover = function (msgHash, v, r, s, chainId) {
396398
const signature = Buffer.concat([exports.setLength(r, 32), exports.setLength(s, 32)], 64)
397-
const recovery = v - 27
398-
if (recovery !== 0 && recovery !== 1) {
399+
const recovery = calculateSigRecovery(v, chainId)
400+
if (!isValidSigRecovery(recovery)) {
399401
throw new Error('Invalid signature v value')
400402
}
401403
const senderPubKey = secp256k1.recover(msgHash, signature, recovery)
@@ -407,12 +409,13 @@ exports.ecrecover = function (msgHash, v, r, s) {
407409
* @param {Number} v
408410
* @param {Buffer} r
409411
* @param {Buffer} s
412+
* @param {Number} [chainId]
410413
* @return {String} sig
411414
*/
412-
exports.toRpcSig = function (v, r, s) {
413-
// NOTE: with potential introduction of chainId this might need to be updated
414-
if (v !== 27 && v !== 28) {
415-
throw new Error('Invalid recovery id')
415+
exports.toRpcSig = function (v, r, s, chainId) {
416+
let recovery = calculateSigRecovery(v, chainId)
417+
if (!isValidSigRecovery(recovery)) {
418+
throw new Error('Invalid signature v value')
416419
}
417420

418421
// geth (and the RPC eth_sign method) uses the 65 byte format used by Bitcoin
@@ -561,18 +564,19 @@ exports.addHexPrefix = function (str) {
561564
* @param {Buffer} r
562565
* @param {Buffer} s
563566
* @param {Boolean} [homestead=true]
567+
* @param {Number} [chainId]
564568
* @return {Boolean}
565569
*/
566570

567-
exports.isValidSignature = function (v, r, s, homestead) {
571+
exports.isValidSignature = function (v, r, s, homestead, chainId) {
568572
const SECP256K1_N_DIV_2 = new BN('7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0', 16)
569573
const SECP256K1_N = new BN('fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141', 16)
570574

571575
if (r.length !== 32 || s.length !== 32) {
572576
return false
573577
}
574578

575-
if (v !== 27 && v !== 28) {
579+
if (!isValidSigRecovery(calculateSigRecovery(v, chainId))) {
576580
return false
577581
}
578582

@@ -711,3 +715,11 @@ exports.defineProperties = function (self, fields, data) {
711715
}
712716
}
713717
}
718+
719+
function calculateSigRecovery (v, chainId) {
720+
return chainId ? v - (2 * chainId + 35) : v - 27
721+
}
722+
723+
function isValidSigRecovery (recovery) {
724+
return recovery === 0 || recovery === 1
725+
}

test/index.js

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -475,6 +475,7 @@ describe('baToJSON', function () {
475475

476476
var echash = Buffer.from('82ff40c0a986c6a5cfad4ddf4c3aa6996f1a7837f9c398e17e5de5cbd5a12b28', 'hex')
477477
var ecprivkey = Buffer.from('3c9229289a6125f7fdf1885a77bb12c37a8d3b4962d936f7e3084dece32a3ca1', 'hex')
478+
var chainId = 3 // ropsten
478479

479480
describe('ecsign', function () {
480481
it('should produce a signature', function () {
@@ -483,13 +484,28 @@ describe('ecsign', function () {
483484
assert.deepEqual(sig.s, Buffer.from('129ff05af364204442bdb53ab6f18a99ab48acc9326fa689f228040429e3ca66', 'hex'))
484485
assert.equal(sig.v, 27)
485486
})
487+
488+
it('should produce a signature for Ropsten testnet', function () {
489+
var sig = ethUtils.ecsign(echash, ecprivkey, chainId)
490+
assert.deepEqual(sig.r, Buffer.from('99e71a99cb2270b8cac5254f9e99b6210c6c10224a1579cf389ef88b20a1abe9', 'hex'))
491+
assert.deepEqual(sig.s, Buffer.from('129ff05af364204442bdb53ab6f18a99ab48acc9326fa689f228040429e3ca66', 'hex'))
492+
assert.equal(sig.v, 41)
493+
})
486494
})
487495

488496
describe('ecrecover', function () {
489497
it('should recover a public key', function () {
490498
var r = Buffer.from('99e71a99cb2270b8cac5254f9e99b6210c6c10224a1579cf389ef88b20a1abe9', 'hex')
491499
var s = Buffer.from('129ff05af364204442bdb53ab6f18a99ab48acc9326fa689f228040429e3ca66', 'hex')
492-
var pubkey = ethUtils.ecrecover(echash, 27, r, s)
500+
var v = 27
501+
var pubkey = ethUtils.ecrecover(echash, v, r, s)
502+
assert.deepEqual(pubkey, ethUtils.privateToPublic(ecprivkey))
503+
})
504+
it('should recover a public key (chainId = 3)', function () {
505+
var r = Buffer.from('99e71a99cb2270b8cac5254f9e99b6210c6c10224a1579cf389ef88b20a1abe9', 'hex')
506+
var s = Buffer.from('129ff05af364204442bdb53ab6f18a99ab48acc9326fa689f228040429e3ca66', 'hex')
507+
var v = 41
508+
var pubkey = ethUtils.ecrecover(echash, v, r, s, chainId)
493509
assert.deepEqual(pubkey, ethUtils.privateToPublic(ecprivkey))
494510
})
495511
it('should fail on an invalid signature (v = 21)', function () {
@@ -546,7 +562,14 @@ describe('isValidSignature', function () {
546562
it('should work otherwise', function () {
547563
var r = Buffer.from('99e71a99cb2270b8cac5254f9e99b6210c6c10224a1579cf389ef88b20a1abe9', 'hex')
548564
var s = Buffer.from('129ff05af364204442bdb53ab6f18a99ab48acc9326fa689f228040429e3ca66', 'hex')
549-
assert.equal(ethUtils.isValidSignature(27, r, s), true)
565+
var v = 27
566+
assert.equal(ethUtils.isValidSignature(v, r, s), true)
567+
})
568+
it('should work otherwise(chainId=3)', function () {
569+
var r = Buffer.from('99e71a99cb2270b8cac5254f9e99b6210c6c10224a1579cf389ef88b20a1abe9', 'hex')
570+
var s = Buffer.from('129ff05af364204442bdb53ab6f18a99ab48acc9326fa689f228040429e3ca66', 'hex')
571+
var v = 41
572+
assert.equal(ethUtils.isValidSignature(v, r, s, false, chainId), true)
550573
})
551574
// FIXME: add homestead test
552575
})

0 commit comments

Comments
 (0)