Skip to content

Commit 5c80ce8

Browse files
committed
Added BNLike chainId input and return types for ecsign, added tests
1 parent 1c9d742 commit 5c80ce8

File tree

2 files changed

+106
-18
lines changed

2 files changed

+106
-18
lines changed

src/signature.ts

Lines changed: 76 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,98 @@
1-
const { ecdsaSign, ecdsaRecover, publicKeyConvert } = require('ethereum-cryptography/secp256k1')
1+
import { ecdsaSign, ecdsaRecover, publicKeyConvert } from 'ethereum-cryptography/secp256k1'
22
import BN from 'bn.js'
33
import { toBuffer, setLengthLeft, bufferToHex, bufferToInt } from './bytes'
44
import { keccak } from './hash'
55
import { assertIsBuffer } from './helpers'
6-
import { BNLike } from './types'
6+
import { BNLike, PrefixedHexString } from './types'
7+
import { isHexString } from '.'
78

89
export interface ECDSASignature {
910
v: number
1011
r: Buffer
1112
s: Buffer
1213
}
1314

15+
export interface ECDSASignatureBN {
16+
v: BN
17+
r: Buffer
18+
s: Buffer
19+
}
20+
21+
export interface ECDSASignatureBuffer {
22+
v: Buffer
23+
r: Buffer
24+
s: Buffer
25+
}
26+
27+
export interface ECDSASignatureHexString {
28+
v: PrefixedHexString
29+
r: Buffer
30+
s: Buffer
31+
}
32+
1433
/**
1534
* Returns the ECDSA signature of a message hash.
1635
*/
17-
export const ecsign = function(
36+
export function ecsign(msgHash: Buffer, privateKey: Buffer, chainId?: number): ECDSASignature
37+
export function ecsign(msgHash: Buffer, privateKey: Buffer, chainId: BN): ECDSASignatureBN
38+
export function ecsign(msgHash: Buffer, privateKey: Buffer, chainId: Buffer): ECDSASignatureBuffer
39+
export function ecsign(
1840
msgHash: Buffer,
1941
privateKey: Buffer,
20-
chainId?: number
21-
): ECDSASignature {
42+
chainId: PrefixedHexString
43+
): ECDSASignatureHexString
44+
export function ecsign(msgHash: Buffer, privateKey: Buffer, chainId: any): any {
2245
const sig = ecdsaSign(msgHash, privateKey)
2346
const recovery: number = sig.recid
2447

25-
const ret = {
26-
r: Buffer.from(sig.signature.slice(0, 32)),
27-
s: Buffer.from(sig.signature.slice(32, 64)),
28-
v: chainId ? recovery + (chainId * 2 + 35) : recovery + 27
48+
let ret
49+
if (typeof chainId === 'number') {
50+
return {
51+
r: Buffer.from(sig.signature.slice(0, 32)),
52+
s: Buffer.from(sig.signature.slice(32, 64)),
53+
v: recovery + (chainId * 2 + 35)
54+
}
55+
} else if (BN.isBN(chainId)) {
56+
ret = {
57+
r: Buffer.from(sig.signature.slice(0, 32)),
58+
s: Buffer.from(sig.signature.slice(32, 64)),
59+
v: (chainId as BN)
60+
.muln(2)
61+
.addn(35)
62+
.addn(recovery)
63+
}
64+
} else if (Buffer.isBuffer(chainId)) {
65+
ret = {
66+
r: Buffer.from(sig.signature.slice(0, 32)),
67+
s: Buffer.from(sig.signature.slice(32, 64)),
68+
v: toBuffer(
69+
new BN(chainId)
70+
.muln(2)
71+
.addn(35)
72+
.addn(recovery)
73+
)
74+
}
75+
} else if (typeof chainId === 'string') {
76+
if (!isHexString(chainId)) {
77+
throw new Error(`A chainId string must be provided with a 0x-prefix, given: ${chainId}`)
78+
}
79+
ret = {
80+
r: Buffer.from(sig.signature.slice(0, 32)),
81+
s: Buffer.from(sig.signature.slice(32, 64)),
82+
v:
83+
'0x' +
84+
new BN(toBuffer(chainId))
85+
.muln(2)
86+
.addn(35)
87+
.addn(recovery)
88+
.toString('hex')
89+
}
90+
} else {
91+
ret = {
92+
r: Buffer.from(sig.signature.slice(0, 32)),
93+
s: Buffer.from(sig.signature.slice(32, 64)),
94+
v: recovery + 27
95+
}
2996
}
3097

3198
return ret

test/signature.spec.ts

Lines changed: 30 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -48,17 +48,38 @@ describe('ecsign', function() {
4848
})
4949

5050
it('should produce a signature for chainId=150', function() {
51-
const chainId = 150
52-
const sig = ecsign(echash, ecprivkey, chainId)
53-
assert.deepEqual(
54-
sig.r,
55-
Buffer.from('99e71a99cb2270b8cac5254f9e99b6210c6c10224a1579cf389ef88b20a1abe9', 'hex')
51+
const expectedSigR = Buffer.from(
52+
'99e71a99cb2270b8cac5254f9e99b6210c6c10224a1579cf389ef88b20a1abe9',
53+
'hex'
5654
)
57-
assert.deepEqual(
58-
sig.s,
59-
Buffer.from('129ff05af364204442bdb53ab6f18a99ab48acc9326fa689f228040429e3ca66', 'hex')
55+
const expectedSigS = Buffer.from(
56+
'129ff05af364204442bdb53ab6f18a99ab48acc9326fa689f228040429e3ca66',
57+
'hex'
6058
)
61-
assert.equal(sig.v, chainId * 2 + 35)
59+
60+
const sig = ecsign(echash, ecprivkey, 150)
61+
assert.deepEqual(sig.r, expectedSigR)
62+
assert.deepEqual(sig.s, expectedSigS)
63+
assert.equal(sig.v, 150 * 2 + 35)
64+
65+
const sigBN = ecsign(echash, ecprivkey, new BN(150))
66+
assert.deepEqual(sigBN.r, expectedSigR)
67+
assert.deepEqual(sigBN.s, expectedSigS)
68+
assert.deepEqual(sigBN.v, new BN(150).muln(2).addn(35))
69+
70+
const sigBuffer = ecsign(echash, ecprivkey, Buffer.from([150]))
71+
assert.deepEqual(sigBuffer.r, expectedSigR)
72+
assert.deepEqual(sigBuffer.s, expectedSigS)
73+
assert.deepEqual(sigBuffer.v, Buffer.from('014f', 'hex'))
74+
75+
const sigHexString = ecsign(echash, ecprivkey, '0x96')
76+
assert.deepEqual(sigHexString.r, expectedSigR)
77+
assert.deepEqual(sigHexString.s, expectedSigS)
78+
assert.equal(sigHexString.v, '0x14f')
79+
80+
assert.throws(function() {
81+
ecsign(echash, ecprivkey, '96')
82+
})
6283
})
6384
})
6485

0 commit comments

Comments
 (0)