-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Open
Labels
A-cheatcodesArea: cheatcodesArea: cheatcodesT-featureType: featureType: featureT-to-discussType: requires discussionType: requires discussion
Description
Component
Forge
Describe the feature you would like
Feature request: vm.signWithNonce(privateKey, digest, nonce)
cheatcode
Summary
Add a new Foundry cheatcode for signing a 32-byte digest on secp256k1 with a user-supplied nonce k
.
This bypasses RFC6979 deterministic nonce derivation and allows precise control of k
for testing purposes.
(v, r, s) = vm.signWithNonce(uint256 privateKey, bytes32 digest, uint256 nonce);
privateKey
: secp256k1 private key (0 < pk < n
)digest
: 32-byte prehash (as invm.sign
)nonce
: ephemeral scalark
(0 < k < n
)
Return values are (v, r, s)
with v ∈ {27, 28}
for compatibility with ecrecover
.
Motivation / Problem it solves
Currently, vm.sign
derives k
deterministically (RFC6979), which is safe for normal signing but does not allow controlling k
in tests.
Security researchers and test writers often need to:
- Test systems relying on signature uniqueness by intentionally producing multiple valid signatures for the same message or key.
- Perform fuzzing and stress testing of signature verification code under controlled, reproducible conditions with chosen
k
.
This cheatcode enables those scenarios.
Safety Notes
- WARNING: Using the same nonce
k
with the same private key for two different messages will leak the private key. nonce
must be generated with a cryptographically secure RNG.- This feature is intended primarily for security testing, not production signing.
Implementation sketch
- Implemented in
cheatcodes/src/crypto.rs
usingk256
hazmat ECDSA APIs. - Strict scalar construction (
Scalar::from_repr(...).into_option()
), rejects 0 and ≥n
. - Low-s normalization applied to match Ethereum consensus rules.
- Recovery id from hazmat when available, otherwise determined by trial recovery against the expected address.
- Solidity tests in
testdata/default/cheats/test/Sign.t.sol
.
Example usage
function testSignWithNonce() public {
uint256 pk = 1234;
bytes32 digest = keccak256("hello");
uint256 nonce = 42;
(uint8 v, bytes32 r, bytes32 s) = vm.signWithNonce(pk, digest, nonce);
assertEq(ecrecover(digest, v, r, s), vm.addr(pk));
}
Additional context
No response
Metadata
Metadata
Assignees
Labels
A-cheatcodesArea: cheatcodesArea: cheatcodesT-featureType: featureType: featureT-to-discussType: requires discussionType: requires discussion
Type
Projects
Status
Backlog