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

Commit

Permalink
Added BNLike chainId input and return types for ecsign, added tests
Browse files Browse the repository at this point in the history
  • Loading branch information
holgerd77 committed Mar 2, 2021
1 parent 1c9d742 commit 5c80ce8
Show file tree
Hide file tree
Showing 2 changed files with 106 additions and 18 deletions.
85 changes: 76 additions & 9 deletions src/signature.ts
Original file line number Diff line number Diff line change
@@ -1,31 +1,98 @@
const { ecdsaSign, ecdsaRecover, publicKeyConvert } = require('ethereum-cryptography/secp256k1')
import { ecdsaSign, ecdsaRecover, publicKeyConvert } from 'ethereum-cryptography/secp256k1'
import BN from 'bn.js'
import { toBuffer, setLengthLeft, bufferToHex, bufferToInt } from './bytes'
import { keccak } from './hash'
import { assertIsBuffer } from './helpers'
import { BNLike } from './types'
import { BNLike, PrefixedHexString } from './types'
import { isHexString } from '.'

export interface ECDSASignature {
v: number
r: Buffer
s: Buffer
}

export interface ECDSASignatureBN {
v: BN
r: Buffer
s: Buffer
}

export interface ECDSASignatureBuffer {
v: Buffer
r: Buffer
s: Buffer
}

export interface ECDSASignatureHexString {
v: PrefixedHexString
r: Buffer
s: Buffer
}

/**
* Returns the ECDSA signature of a message hash.
*/
export const ecsign = function(
export function ecsign(msgHash: Buffer, privateKey: Buffer, chainId?: number): ECDSASignature
export function ecsign(msgHash: Buffer, privateKey: Buffer, chainId: BN): ECDSASignatureBN
export function ecsign(msgHash: Buffer, privateKey: Buffer, chainId: Buffer): ECDSASignatureBuffer
export function ecsign(
msgHash: Buffer,
privateKey: Buffer,
chainId?: number
): ECDSASignature {
chainId: PrefixedHexString
): ECDSASignatureHexString
export function ecsign(msgHash: Buffer, privateKey: Buffer, chainId: any): any {
const sig = ecdsaSign(msgHash, privateKey)
const recovery: number = sig.recid

const ret = {
r: Buffer.from(sig.signature.slice(0, 32)),
s: Buffer.from(sig.signature.slice(32, 64)),
v: chainId ? recovery + (chainId * 2 + 35) : recovery + 27
let ret
if (typeof chainId === 'number') {
return {
r: Buffer.from(sig.signature.slice(0, 32)),
s: Buffer.from(sig.signature.slice(32, 64)),
v: recovery + (chainId * 2 + 35)
}
} else if (BN.isBN(chainId)) {
ret = {
r: Buffer.from(sig.signature.slice(0, 32)),
s: Buffer.from(sig.signature.slice(32, 64)),
v: (chainId as BN)
.muln(2)
.addn(35)
.addn(recovery)
}
} else if (Buffer.isBuffer(chainId)) {
ret = {
r: Buffer.from(sig.signature.slice(0, 32)),
s: Buffer.from(sig.signature.slice(32, 64)),
v: toBuffer(
new BN(chainId)
.muln(2)
.addn(35)
.addn(recovery)
)
}
} else if (typeof chainId === 'string') {
if (!isHexString(chainId)) {
throw new Error(`A chainId string must be provided with a 0x-prefix, given: ${chainId}`)
}
ret = {
r: Buffer.from(sig.signature.slice(0, 32)),
s: Buffer.from(sig.signature.slice(32, 64)),
v:
'0x' +
new BN(toBuffer(chainId))
.muln(2)
.addn(35)
.addn(recovery)
.toString('hex')
}
} else {
ret = {
r: Buffer.from(sig.signature.slice(0, 32)),
s: Buffer.from(sig.signature.slice(32, 64)),
v: recovery + 27
}
}

return ret
Expand Down
39 changes: 30 additions & 9 deletions test/signature.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,17 +48,38 @@ describe('ecsign', function() {
})

it('should produce a signature for chainId=150', function() {
const chainId = 150
const sig = ecsign(echash, ecprivkey, chainId)
assert.deepEqual(
sig.r,
Buffer.from('99e71a99cb2270b8cac5254f9e99b6210c6c10224a1579cf389ef88b20a1abe9', 'hex')
const expectedSigR = Buffer.from(
'99e71a99cb2270b8cac5254f9e99b6210c6c10224a1579cf389ef88b20a1abe9',
'hex'
)
assert.deepEqual(
sig.s,
Buffer.from('129ff05af364204442bdb53ab6f18a99ab48acc9326fa689f228040429e3ca66', 'hex')
const expectedSigS = Buffer.from(
'129ff05af364204442bdb53ab6f18a99ab48acc9326fa689f228040429e3ca66',
'hex'
)
assert.equal(sig.v, chainId * 2 + 35)

const sig = ecsign(echash, ecprivkey, 150)
assert.deepEqual(sig.r, expectedSigR)
assert.deepEqual(sig.s, expectedSigS)
assert.equal(sig.v, 150 * 2 + 35)

const sigBN = ecsign(echash, ecprivkey, new BN(150))
assert.deepEqual(sigBN.r, expectedSigR)
assert.deepEqual(sigBN.s, expectedSigS)
assert.deepEqual(sigBN.v, new BN(150).muln(2).addn(35))

const sigBuffer = ecsign(echash, ecprivkey, Buffer.from([150]))
assert.deepEqual(sigBuffer.r, expectedSigR)
assert.deepEqual(sigBuffer.s, expectedSigS)
assert.deepEqual(sigBuffer.v, Buffer.from('014f', 'hex'))

const sigHexString = ecsign(echash, ecprivkey, '0x96')
assert.deepEqual(sigHexString.r, expectedSigR)
assert.deepEqual(sigHexString.s, expectedSigS)
assert.equal(sigHexString.v, '0x14f')

assert.throws(function() {
ecsign(echash, ecprivkey, '96')
})
})
})

Expand Down

0 comments on commit 5c80ce8

Please sign in to comment.