Skip to content

Commit ebea878

Browse files
util/tx: change ecsign to not add 27 to v value (#3941)
* util/tx: change ecsign to not add 27 to `v` value * util: add changelog entry * client: fix build * block: fix clique signing * common/tx/vm: first round to fix tests * util: fix tests * client: fix tests * tx: update changelog
1 parent a57c0a9 commit ebea878

File tree

20 files changed

+48
-142
lines changed

20 files changed

+48
-142
lines changed

packages/block/src/consensus/clique.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ export function generateCliqueBlockExtraData(
153153

154154
const ecSignFunction = header.common.customCrypto?.ecsign ?? ecsign
155155
const signature = ecSignFunction(cliqueSigHash(header), cliqueSigner)
156-
const signatureB = concatBytes(signature.r, signature.s, bigIntToBytes(signature.v - BIGINT_27))
156+
const signatureB = concatBytes(signature.r, signature.s, bigIntToBytes(signature.v))
157157

158158
const extraDataWithoutSeal = header.extraData.subarray(
159159
0,

packages/client/bin/utils.ts

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ import {
1515
getPresetChainConfig,
1616
} from '@ethereumjs/common'
1717
import {
18-
BIGINT_2,
1918
EthereumJSErrorWithoutCode,
2019
bytesToHex,
2120
calculateSigRecovery,
@@ -648,23 +647,15 @@ export async function generateClientConfig(args: ClientOpts) {
648647
),
649648
).slice(1)
650649
cryptoFunctions.sha256 = wasmSha256
651-
cryptoFunctions.ecsign = (
652-
msg: Uint8Array,
653-
pk: Uint8Array,
654-
ecSignOpts: { chainId?: bigint } = {},
655-
) => {
650+
cryptoFunctions.ecsign = (msg: Uint8Array, pk: Uint8Array) => {
656651
if (msg.length < 32) {
657652
// WASM errors with `unreachable` if we try to pass in less than 32 bytes in the message
658653
throw EthereumJSErrorWithoutCode('message length must be 32 bytes or greater')
659654
}
660-
const { chainId } = ecSignOpts
661655
const buf = secp256k1Sign(msg, pk)
662656
const r = buf.slice(0, 32)
663657
const s = buf.slice(32, 64)
664-
const v =
665-
chainId === undefined
666-
? BigInt(buf[64] + 27)
667-
: BigInt(buf[64] + 35) + BigInt(chainId) * BIGINT_2
658+
const v = BigInt(buf[64])
668659

669660
return { r, s, v }
670661
}

packages/client/test/util/wasmCrypto.spec.ts

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import { Common, Mainnet } from '@ethereumjs/common'
22
import { createLegacyTx } from '@ethereumjs/tx'
33
import {
4-
BIGINT_2,
54
bytesToHex,
65
calculateSigRecovery,
76
concatBytes,
@@ -66,18 +65,15 @@ describe('WASM crypto tests', () => {
6665
})
6766

6867
it('should compute the same signature whether js or WASM signature used', async () => {
69-
const wasmSign = (msg: Uint8Array, pk: Uint8Array, chainId?: bigint) => {
68+
const wasmSign = (msg: Uint8Array, pk: Uint8Array) => {
7069
if (msg.length < 32) {
7170
// WASM errors with `unreachable` if we try to pass in less than 32 bytes in the message
7271
throw new Error('message length must be 32 bytes or greater')
7372
}
7473
const buf = secp256k1Sign(msg, pk)
7574
const r = buf.slice(0, 32)
7675
const s = buf.slice(32, 64)
77-
const v =
78-
chainId === undefined
79-
? BigInt(buf[64] + 27)
80-
: BigInt(buf[64] + 35) + BigInt(chainId) * BIGINT_2
76+
const v = BigInt(buf[64])
8177

8278
return { r, s, v }
8379
}

packages/common/src/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ export interface CustomCrypto {
9494
ecsign?: (
9595
msg: Uint8Array,
9696
pk: Uint8Array,
97-
ecSignOpts?: { chainId?: bigint; extraEntropy?: Uint8Array | boolean },
97+
ecSignOpts?: { extraEntropy?: Uint8Array | boolean },
9898
) => ECDSASignature
9999
ecdsaSign?: (msg: Uint8Array, pk: Uint8Array) => { signature: Uint8Array; recid: number }
100100
ecdsaRecover?: (sig: Uint8Array, recId: number, hash: Uint8Array) => Uint8Array

packages/common/test/customCrypto.spec.ts

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,9 @@ describe('[Common]: Custom Crypto', () => {
2424
return msg
2525
}
2626

27-
const customEcSign = (
28-
_msg: Uint8Array,
29-
_pk: Uint8Array,
30-
ecSignOpts?: { chainId?: bigint; extraEntropy?: Uint8Array | boolean },
31-
): ECDSASignature => {
27+
const customEcSign = (_msg: Uint8Array, _pk: Uint8Array): ECDSASignature => {
3228
return {
33-
v: ecSignOpts?.chainId ?? 27n,
29+
v: 0n,
3430
r: Uint8Array.from([0, 1, 2, 3]),
3531
s: Uint8Array.from([0, 1, 2, 3]),
3632
}
@@ -85,7 +81,6 @@ describe('[Common]: Custom Crypto', () => {
8581
ecsign: customEcSign,
8682
}
8783
const c = new Common({ chain: Mainnet, customCrypto })
88-
assert.equal(c.customCrypto.ecsign!(randomBytes(32), randomBytes(32), { chainId: 0n }).v, 0n)
89-
assert.equal(c.customCrypto.ecsign!(randomBytes(32), randomBytes(32)).v, 27n)
84+
assert.equal(c.customCrypto.ecsign!(randomBytes(32), randomBytes(32)).v, 0n)
9085
})
9186
})

packages/tx/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
66
(modification: no type change headlines) and this project adheres to
77
[Semantic Versioning](http://semver.org/spec/v2.0.0.html).
88

9+
## 10.x.x - UNPUBLISHED
10+
11+
Update transaction test runner to correctly report tests and fix edge case of invalid 7702 txs with nested lists inside the authority list, PR[3942](https://github.com/ethereumjs/ethereumjs-monorepo/pull/3942)
12+
913
## 10.0.0-rc.1 - 2025-03-24
1014

1115
This is the first (and likely the last) round of `RC` releases for the upcoming breaking releases, following the `alpha` releases from October 2024 (see `alpha` release release notes for full/main change description). The releases are somewhat delayed (sorry for that), but final releases can now be expected very very soon, to be released once the Ethereum [Pectra](https://eips.ethereum.org/EIPS/eip-7600) hardfork is scheduled for mainnet and all EIPs are fully finalized. Pectra will then also be the default hardfork setting for all EthereumJS libraries.

packages/tx/src/1559/tx.ts

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import {
22
BIGINT_0,
3-
BIGINT_27,
43
EthereumJSErrorWithoutCode,
54
MAX_INTEGER,
65
bigIntToHex,
@@ -295,12 +294,7 @@ export class FeeMarket1559Tx
295294
return Legacy.getSenderPublicKey(this)
296295
}
297296

298-
addSignature(
299-
v: bigint,
300-
r: Uint8Array | bigint,
301-
s: Uint8Array | bigint,
302-
convertV: boolean = false,
303-
): FeeMarket1559Tx {
297+
addSignature(v: bigint, r: Uint8Array | bigint, s: Uint8Array | bigint): FeeMarket1559Tx {
304298
r = toBytes(r)
305299
s = toBytes(s)
306300
const opts = { ...this.txOptions, common: this.common }
@@ -316,7 +310,7 @@ export class FeeMarket1559Tx
316310
value: this.value,
317311
data: this.data,
318312
accessList: this.accessList,
319-
v: convertV ? v - BIGINT_27 : v, // This looks extremely hacky: @ethereumjs/util actually adds 27 to the value, the recovery bit is either 0 or 1.
313+
v,
320314
r: bytesToBigInt(r),
321315
s: bytesToBigInt(s),
322316
},

packages/tx/src/2930/tx.ts

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import {
2-
BIGINT_27,
32
EthereumJSErrorWithoutCode,
43
MAX_INTEGER,
54
bigIntToHex,
@@ -271,12 +270,7 @@ export class AccessList2930Tx
271270
return Legacy.getSenderPublicKey(this)
272271
}
273272

274-
addSignature(
275-
v: bigint,
276-
r: Uint8Array | bigint,
277-
s: Uint8Array | bigint,
278-
convertV: boolean = false,
279-
): AccessList2930Tx {
273+
addSignature(v: bigint, r: Uint8Array | bigint, s: Uint8Array | bigint): AccessList2930Tx {
280274
r = toBytes(r)
281275
s = toBytes(s)
282276
const opts = { ...this.txOptions, common: this.common }
@@ -291,7 +285,7 @@ export class AccessList2930Tx
291285
value: this.value,
292286
data: this.data,
293287
accessList: this.accessList,
294-
v: convertV ? v - BIGINT_27 : v, // This looks extremely hacky: @ethereumjs/util actually adds 27 to the value, the recovery bit is either 0 or 1.
288+
v,
295289
r: bytesToBigInt(r),
296290
s: bytesToBigInt(s),
297291
},

packages/tx/src/4844/tx.ts

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import {
22
BIGINT_0,
3-
BIGINT_27,
43
EthereumJSErrorWithoutCode,
54
MAX_INTEGER,
65
TypeOutput,
@@ -396,12 +395,7 @@ export class Blob4844Tx implements TransactionInterface<typeof TransactionType.B
396395
}
397396
}
398397

399-
addSignature(
400-
v: bigint,
401-
r: Uint8Array | bigint,
402-
s: Uint8Array | bigint,
403-
convertV: boolean = false,
404-
): Blob4844Tx {
398+
addSignature(v: bigint, r: Uint8Array | bigint, s: Uint8Array | bigint): Blob4844Tx {
405399
r = toBytes(r)
406400
s = toBytes(s)
407401
const opts = { ...this.txOptions, common: this.common }
@@ -417,7 +411,7 @@ export class Blob4844Tx implements TransactionInterface<typeof TransactionType.B
417411
value: this.value,
418412
data: this.data,
419413
accessList: this.accessList,
420-
v: convertV ? v - BIGINT_27 : v, // This looks extremely hacky: @ethereumjs/util actually adds 27 to the value, the recovery bit is either 0 or 1.
414+
v,
421415
r: bytesToBigInt(r),
422416
s: bytesToBigInt(s),
423417
maxFeePerBlobGas: this.maxFeePerBlobGas,

packages/tx/src/7702/tx.ts

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import {
22
BIGINT_0,
3-
BIGINT_27,
43
EthereumJSErrorWithoutCode,
54
MAX_INTEGER,
65
bigIntToHex,
@@ -329,12 +328,7 @@ export class EOACode7702Tx implements TransactionInterface<typeof TransactionTyp
329328
return Legacy.getSenderPublicKey(this)
330329
}
331330

332-
addSignature(
333-
v: bigint,
334-
r: Uint8Array | bigint,
335-
s: Uint8Array | bigint,
336-
convertV: boolean = false,
337-
): EOACode7702Tx {
331+
addSignature(v: bigint, r: Uint8Array | bigint, s: Uint8Array | bigint): EOACode7702Tx {
338332
r = toBytes(r)
339333
s = toBytes(s)
340334
const opts = { ...this.txOptions, common: this.common }
@@ -351,7 +345,7 @@ export class EOACode7702Tx implements TransactionInterface<typeof TransactionTyp
351345
data: this.data,
352346
accessList: this.accessList,
353347
authorizationList: this.authorizationList,
354-
v: convertV ? v - BIGINT_27 : v, // This looks extremely hacky: @ethereumjs/util actually adds 27 to the value, the recovery bit is either 0 or 1.
348+
v,
355349
r: bytesToBigInt(r),
356350
s: bytesToBigInt(s),
357351
},

0 commit comments

Comments
 (0)