Skip to content

Commit cb21616

Browse files
jochem-brouweracolytec3holgerd77
authored
Util: remove ecsign method (instead directly use secp256k1.sign from external ethereum-cryptography package (ethereumjs#3948)
* util/monorepo: remove ecsign (use secp256k1.sign directly from ethereum-cryptography external package) * client: read wasm from util * tx: update auth sign to read from common crypto * devp2p: convert deprecated ecsign to secp256k1.sign * update customCrypto.ecsign return type * fix wasmCrypto test * switch v to number * Revert "switch v to number" This reverts commit 99859e5. * remove old comment * dedupe ecdsaSign * fix test * remove compat version of ecdsaRecover * tx: remove TODO * block/clique: ensure customCrypto and left padding is adhered --------- Co-authored-by: acolytec3 <[email protected]> Co-authored-by: Holger Drewes <[email protected]>
1 parent 5410e22 commit cb21616

File tree

2 files changed

+6
-96
lines changed

2 files changed

+6
-96
lines changed

src/signature.ts

+6-49
Original file line numberDiff line numberDiff line change
@@ -23,54 +23,6 @@ import { assertIsBytes } from './helpers.ts'
2323

2424
import type { PrefixedHexString } from './types.ts'
2525

26-
export interface ECDSASignature {
27-
v: bigint // TODO: change this to number? It is either 0 or 1.
28-
r: Uint8Array
29-
s: Uint8Array
30-
}
31-
32-
export interface ECSignOpts {
33-
chainId?: bigint
34-
extraEntropy?: Uint8Array | boolean
35-
}
36-
37-
/**
38-
* Returns the ECDSA signature of a message hash.
39-
* {@link ECSignOpts.extraEntropy} defaults to `false`. If set to `true`, this will create a "hedged signature"
40-
* which is non-deterministic and provides additional protections against private key extraction attack vectors,
41-
* as described in https://github.com/ethereumjs/ethereumjs-monorepo/issues/3801. It will yield a
42-
* different, random signature each time `ecsign` is called on the same `msgHash` and `privateKey`.
43-
* In particular: each time a transaction is signed, this will thus yield a different, random
44-
* transaction hash.
45-
* Additionally, a `Uint8Array` can be passed to `extraEntropy` to provide custom entropy, which
46-
* will then still create a
47-
* To use this feature, pass `true` or a `Uint8Array` to `extraEntropy`.
48-
* For more information, see: https://github.com/ethereumjs/ethereumjs-monorepo/issues/3801
49-
*/
50-
export function ecsign(
51-
msgHash: Uint8Array,
52-
privateKey: Uint8Array,
53-
ecSignOpts: { extraEntropy?: Uint8Array | boolean } = { extraEntropy: false },
54-
): ECDSASignature {
55-
const { extraEntropy } = ecSignOpts
56-
const sig = secp256k1.sign(msgHash, privateKey, { extraEntropy: extraEntropy ?? false })
57-
const buf = sig.toCompactRawBytes()
58-
const r = buf.slice(0, 32)
59-
const s = buf.slice(32, 64)
60-
61-
if ([2, 3].includes(sig.recovery)) {
62-
// From the yellow paper:
63-
/* The recovery identifier is a 1 byte value specifying the parity and finiteness of the coordinates
64-
of the curve point for which r is the x-value; this value is in the range of [0, 3],
65-
however we declare the upper two possibilities, representing infinite values, invalid. */
66-
throw EthereumJSErrorWithoutCode(
67-
`Invalid recovery value: values 2/3 are invalid, received: ${sig.recovery}`,
68-
)
69-
}
70-
71-
return { r, s, v: BigInt(sig.recovery) }
72-
}
73-
7426
export function calculateSigRecovery(v: bigint, chainId?: bigint): bigint {
7527
if (v === BIGINT_0 || v === BIGINT_1) return v
7628

@@ -160,7 +112,11 @@ export const toCompactSig = function (
160112
* NOTE: After EIP1559, `v` could be `0` or `1` but this function assumes
161113
* it's a signed message (EIP-191 or EIP-712) adding `27` at the end. Remove if needed.
162114
*/
163-
export const fromRPCSig = function (sig: PrefixedHexString): ECDSASignature {
115+
export const fromRPCSig = function (sig: PrefixedHexString): {
116+
v: bigint
117+
r: Uint8Array
118+
s: Uint8Array
119+
} {
164120
const bytes: Uint8Array = toBytes(sig)
165121

166122
let r: Uint8Array
@@ -182,6 +138,7 @@ export const fromRPCSig = function (sig: PrefixedHexString): ECDSASignature {
182138

183139
// support both versions of `eth_sign` responses
184140
if (v < 27) {
141+
// TODO: verify this behavior, and verify in which context this method (`fromRPCSig`) is used
185142
v = v + BIGINT_27
186143
}
187144

test/signature.spec.ts

-47
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@ import { assert, describe, it } from 'vitest'
33
import {
44
bigIntToBytes,
55
ecrecover,
6-
ecsign,
7-
equalsBytes,
86
fromRPCSig,
97
hashPersonalMessage,
108
hexToBytes,
@@ -15,55 +13,10 @@ import {
1513
utf8ToBytes,
1614
} from '../src/index.ts'
1715

18-
import type { ECDSASignature } from '../src/index.ts'
19-
2016
const ecHash = hexToBytes('0x82ff40c0a986c6a5cfad4ddf4c3aa6996f1a7837f9c398e17e5de5cbd5a12b28')
2117
const ecPrivKey = hexToBytes('0x3c9229289a6125f7fdf1885a77bb12c37a8d3b4962d936f7e3084dece32a3ca1')
2218
const chainId = BigInt(3) // ropsten
2319

24-
/**
25-
* Returns `true` if the signatures are equal, or `false` otherwise.
26-
*/
27-
function sigCmp(sig1: ECDSASignature, sig2: ECDSASignature) {
28-
return equalsBytes(sig1.s, sig2.s) && equalsBytes(sig1.r, sig2.r) && sig1.v === sig2.v
29-
}
30-
31-
describe('ecsign', () => {
32-
it('should produce a deterministic signature by default', () => {
33-
const sig = ecsign(ecHash, ecPrivKey)
34-
assert.deepEqual(
35-
sig.r,
36-
hexToBytes('0x99e71a99cb2270b8cac5254f9e99b6210c6c10224a1579cf389ef88b20a1abe9'),
37-
)
38-
assert.deepEqual(
39-
sig.s,
40-
hexToBytes('0x129ff05af364204442bdb53ab6f18a99ab48acc9326fa689f228040429e3ca66'),
41-
)
42-
assert.equal(sig.v, BigInt(0))
43-
})
44-
45-
it('should produce hedged signatures (extraEntropy=true)', () => {
46-
const sig = ecsign(ecHash, ecPrivKey, { extraEntropy: true })
47-
const sig2 = ecsign(ecHash, ecPrivKey)
48-
assert.isFalse(sigCmp(sig, sig2), 'no chain id: signatures should be hedged and thus different')
49-
})
50-
51-
it('should produce hedged signatures by default (with provided chainID)', () => {
52-
const sigOpts = { extraEntropy: true }
53-
const sig = ecsign(ecHash, ecPrivKey, sigOpts)
54-
const sig2 = ecsign(ecHash, ecPrivKey, sigOpts)
55-
assert.isFalse(sigCmp(sig, sig2), 'chain id: signatures should be hedged and thus different')
56-
})
57-
58-
it('should produce deterministic signatures with set extraEntropy', () => {
59-
const extraEntropy = bigIntToBytes(BigInt(13371337))
60-
const sigOpts = { extraEntropy }
61-
const sig = ecsign(ecHash, ecPrivKey, sigOpts)
62-
const sig2 = ecsign(ecHash, ecPrivKey, sigOpts)
63-
assert.isTrue(sigCmp(sig, sig2), 'no chain id: signatures should be deterministic')
64-
})
65-
})
66-
6720
describe('ecrecover', () => {
6821
it('should recover a public key', () => {
6922
const r = hexToBytes('0x99e71a99cb2270b8cac5254f9e99b6210c6c10224a1579cf389ef88b20a1abe9')

0 commit comments

Comments
 (0)