diff --git a/.changeset/ninety-suits-invite.md b/.changeset/ninety-suits-invite.md new file mode 100644 index 0000000000..87ede0700a --- /dev/null +++ b/.changeset/ninety-suits-invite.md @@ -0,0 +1,5 @@ +--- +"viem": minor +--- + +Improved security of signature generation. Resolves #3028. diff --git a/site/pages/op-stack/guides/deposits.md b/site/pages/op-stack/guides/deposits.md index d2d9647d11..e1fcbae1fc 100644 --- a/site/pages/op-stack/guides/deposits.md +++ b/site/pages/op-stack/guides/deposits.md @@ -193,7 +193,7 @@ import { publicClientL2 } from './config' // Build parameters for the transaction on the L2. const args = await publicClientL2.buildDepositTransaction({ - mint: parseEther('1') + mint: parseEther('1'), to: account.address, }) ``` @@ -265,7 +265,7 @@ import { account, publicClientL2, walletClientL1 } from './config' // Build parameters for the transaction on the L2. const args = await publicClientL2.buildDepositTransaction({ - mint: parseEther('1') + mint: parseEther('1'), to: account.address, }) @@ -350,7 +350,7 @@ import { // Build parameters for the transaction on the L2. const args = await publicClientL2.buildDepositTransaction({ - mint: parseEther('1') + mint: parseEther('1'), to: account.address, }) @@ -432,7 +432,7 @@ import { // Build parameters for the transaction on the L2. const args = await publicClientL2.buildDepositTransaction({ - mint: parseEther('1') + mint: parseEther('1'), to: account.address, }) @@ -519,7 +519,7 @@ import { // Build parameters for the transaction on the L2. const args = await publicClientL2.buildDepositTransaction({ - mint: parseEther('1') + mint: parseEther('1'), to: account.address, }) diff --git a/src/accounts/utils/sign.ts b/src/accounts/utils/sign.ts index 8cbcb7045d..311170f462 100644 --- a/src/accounts/utils/sign.ts +++ b/src/accounts/utils/sign.ts @@ -25,6 +25,13 @@ export type SignReturnType = export type SignErrorType = NumberToHexErrorType | ErrorType +let extraEntropy: Hex | boolean = true + +/** @internal */ +export function setSignEntropy(entropy: Hex | boolean) { + extraEntropy = entropy +} + /** * @description Signs a hash with a given private key. * @@ -38,7 +45,11 @@ export async function sign({ privateKey, to = 'object', }: SignParameters): Promise> { - const { r, s, recovery } = secp256k1.sign(hash.slice(2), privateKey.slice(2)) + const { r, s, recovery } = secp256k1.sign( + hash.slice(2), + privateKey.slice(2), + { lowS: true, extraEntropy }, + ) const signature = { r: numberToHex(r, { size: 32 }), s: numberToHex(s, { size: 32 }), diff --git a/src/zksync/formatters.ts b/src/zksync/formatters.ts index f4857ffc80..4548fd092d 100644 --- a/src/zksync/formatters.ts +++ b/src/zksync/formatters.ts @@ -81,7 +81,9 @@ export const formatters = { return { blockNumber: hexToBigInt(l2ToL1Log.blockHash), blockHash: l2ToL1Log.blockHash, - l1BatchNumber: l2ToL1Log.l1BatchNumber ? hexToBigInt(l2ToL1Log.l1BatchNumber) : null, + l1BatchNumber: l2ToL1Log.l1BatchNumber + ? hexToBigInt(l2ToL1Log.l1BatchNumber) + : null, transactionIndex: hexToBigInt(l2ToL1Log.transactionIndex), shardId: hexToBigInt(l2ToL1Log.shardId), isService: l2ToL1Log.isService, diff --git a/test/setup.ts b/test/setup.ts index 3b551fbc17..ab33cf025a 100644 --- a/test/setup.ts +++ b/test/setup.ts @@ -5,6 +5,7 @@ import { cleanupCache, listenersCache } from '~viem/utils/observe.js' import { promiseCache, responseCache } from '~viem/utils/promise/withCache.js' import { socketClientCache } from '~viem/utils/rpc/socket.js' +import { setSignEntropy } from '../src/accounts/utils/sign.js' import { setErrorConfig } from '../src/errors/base.js' import * as instances from './src/anvil.js' @@ -19,6 +20,7 @@ beforeAll(() => { }, version: 'viem@x.y.z', }) + setSignEntropy(false) vi.mock('../src/errors/utils.ts', () => ({ getContractAddress: vi .fn() diff --git a/vectors/src/transaction.vectors.test.ts b/vectors/src/transaction.vectors.test.ts index 0acb44ce34..b500e97a81 100644 --- a/vectors/src/transaction.vectors.test.ts +++ b/vectors/src/transaction.vectors.test.ts @@ -7,6 +7,9 @@ import { signTransaction } from '../../src/accounts/utils/signTransaction.js' import { parseTransaction } from '../../src/index.js' import { serializeTransaction } from '../../src/utils/transaction/serializeTransaction.js' import { readGzippedJson } from '../utils.js' +import { setSignEntropy } from '../../src/accounts/utils/sign.js' + +setSignEntropy(false) const transactions_ = await readGzippedJson( join(import.meta.dir, './transaction.json.gz'),