Skip to content

Commit f29bc0b

Browse files
KONFeatureleekt
authored andcommitted
⚡️ Optimise gas usage when enabling p256 validator, add a few comments (#52)
* ⚡️ Optimise gas usage when enabling p256 validator, add a few comments - Reducing the number of indexed variable inside a log highly decrease his gas usage, in the p256 validator, we only matter about the kernel account as index (it's 375 gas per topic, so per indexed props, so reducing the index on both key reduce the enabling gas cost by 375 * 4 -> 1500 gas) - Add a few reflexion todo comment, do you rly need to send the previous key in the event? Since it's cost with a `sload`& also in the event itself * ⚡️ Remove the oldKeys for the event signature * ⚡️ Only compare to raw msg signing instead of eth signed message for p256
1 parent 51d7b54 commit f29bc0b

File tree

6 files changed

+51
-32
lines changed

6 files changed

+51
-32
lines changed

src/Kernel.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ contract Kernel is EIP712, Compatibility, KernelStorage {
2929
/// @dev Selector of the `DisabledMode()` error, to be used in assembly, 'bytes4(keccak256(bytes("DisabledMode()")))', same as DisabledMode.selector()
3030
uint256 private constant _DISABLED_MODE_SELECTOR = 0xfc2f51c5;
3131

32-
/// @dev Current kernel name and version, todo: Need to expose getter for this variables?
32+
/// @dev Current kernel name and version, todo: Need to expose getter for this variables?
3333
string public constant name = KERNEL_NAME;
3434
string public constant version = KERNEL_VERSION;
3535

src/validator/P256Validator.sol

Lines changed: 35 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -9,55 +9,72 @@ import {ValidationData} from "../common/Types.sol";
99
import {SIG_VALIDATION_FAILED} from "../common/Constants.sol";
1010
import {P256} from "p256-verifier/P256.sol";
1111

12+
/// @title P256Validator
13+
/// @notice This validator uses the P256 curve to validate signatures.
1214
contract P256Validator is IKernelValidator {
13-
event P256PublicKeysChanged(address indexed kernel, PublicKey indexed oldKeys, PublicKey indexed newKeys);
15+
/// @notice Emitted when a bad key is provided.
16+
error BadKey();
17+
18+
/// @notice Emitted when the public key of a kernel is changed.
19+
event P256PublicKeysChanged(address indexed kernel, PublicKey newKeys);
1420

21+
/// @notice The P256 public key of a kernel.
1522
struct PublicKey {
1623
uint256 x;
1724
uint256 y;
1825
}
1926

20-
error BadKey();
21-
22-
mapping(address => PublicKey) public p256PublicKey;
27+
/// @notice The P256 public keys of a kernel.
28+
mapping(address kernel => PublicKey PublicKey) public p256PublicKey;
2329

30+
/// @notice Enable this validator for a kernel account.
31+
/// @dev The kernel account need to be the `msg.sender`.
32+
/// @dev The public key is encoded as `abi.encode(PublicKey)` inside the data, so (uint256,uint256).
2433
function enable(bytes calldata _data) external payable override {
2534
PublicKey memory key = abi.decode(_data, (PublicKey));
2635
if (key.x == 0 || key.y == 0) {
2736
revert BadKey();
2837
}
29-
PublicKey memory oldKey = p256PublicKey[msg.sender];
38+
// Update the key (so a sstore)
3039
p256PublicKey[msg.sender] = key;
31-
emit P256PublicKeysChanged(msg.sender, oldKey, key);
40+
// And emit the event
41+
emit P256PublicKeysChanged(msg.sender, key);
3242
}
3343

44+
/// @notice Disable this validator for a kernel account.
45+
/// @dev The kernel account need to be the `msg.sender`.
3446
function disable(bytes calldata) external payable override {
3547
delete p256PublicKey[msg.sender];
3648
}
3749

38-
function validateUserOp(UserOperation calldata _userOp, bytes32 _userOpHash, uint256) external payable override returns (ValidationData validationData) {
50+
/// @notice Validate a user operation.
51+
function validateUserOp(UserOperation calldata _userOp, bytes32 _userOpHash, uint256)
52+
external
53+
payable
54+
override
55+
returns (ValidationData validationData)
56+
{
3957
(uint256 r, uint256 s) = abi.decode(_userOp.signature, (uint256, uint256));
4058
PublicKey memory key = p256PublicKey[_userOp.sender];
41-
bytes32 hash = ECDSA.toEthSignedMessageHash(_userOpHash);
42-
if (P256.verifySignature(hash, r, s, key.x, key.y)) {
59+
if (P256.verifySignature(_userOpHash, r, s, key.x, key.y)) {
4360
return ValidationData.wrap(0);
44-
}
45-
if (!P256.verifySignature(_userOpHash, r, s, key.x, key.y)) {
46-
return SIG_VALIDATION_FAILED;
4761
}
62+
return SIG_VALIDATION_FAILED;
4863
}
4964

50-
function validateSignature(bytes32 hash, bytes calldata signature) external view override returns (ValidationData) {
65+
/// @notice Validate a signature.
66+
function validateSignature(bytes32 hash, bytes calldata signature)
67+
external
68+
view
69+
override
70+
returns (ValidationData)
71+
{
5172
(uint256 r, uint256 s) = abi.decode(signature, (uint256, uint256));
5273
PublicKey memory key = p256PublicKey[msg.sender];
5374
if (P256.verifySignature(hash, r, s, key.x, key.y)) {
5475
return ValidationData.wrap(0);
5576
}
56-
bytes32 ethHash = ECDSA.toEthSignedMessageHash(hash);
57-
if (!P256.verifySignature(ethHash, r, s, key.x, key.y)) {
58-
return SIG_VALIDATION_FAILED;
59-
}
60-
return ValidationData.wrap(0);
77+
return SIG_VALIDATION_FAILED;
6178
}
6279

6380
function validCaller(address _caller, bytes calldata) external view override returns (bool) {

test/foundry/KernelLiteECDSA.t.sol

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,8 @@ contract KernelECDSATest is KernelTestBase {
9797

9898
function test_transfer_ownership() external {
9999
address newOwner = makeAddr("new owner");
100-
UserOperation memory op = buildUserOperation(abi.encodeWithSelector(KernelLiteECDSA.transferOwnership.selector, newOwner));
100+
UserOperation memory op =
101+
buildUserOperation(abi.encodeWithSelector(KernelLiteECDSA.transferOwnership.selector, newOwner));
101102
vm.expectEmit(true, true, true, false, address(entryPoint));
102103
emit UserOperationEvent(entryPoint.getUserOpHash(op), address(kernel), address(0), op.nonce, false, 0, 0);
103104
performUserOperationWithSig(op);

test/foundry/KernelTestBase.sol

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -272,7 +272,9 @@ abstract contract KernelTestBase is Test {
272272
function test_disable_mode() external {
273273
vm.warp(1000);
274274
bytes memory empty;
275-
UserOperation memory op = buildUserOperation(abi.encodeWithSelector(IKernel.disableMode.selector, bytes4(0x00000001), address(0), empty));
275+
UserOperation memory op = buildUserOperation(
276+
abi.encodeWithSelector(IKernel.disableMode.selector, bytes4(0x00000001), address(0), empty)
277+
);
276278
performUserOperationWithSig(op);
277279
assertEq(uint256(bytes32(IKernel(address(kernel)).getDisabledMode())), 1 << 224);
278280
assertEq(uint256(IKernel(address(kernel)).getLastDisabledTime()), block.timestamp);
@@ -336,7 +338,8 @@ abstract contract KernelTestBase is Test {
336338
function test_revert_when_mode_disabled() external {
337339
vm.warp(1000);
338340
bytes memory empty;
339-
UserOperation memory op = buildUserOperation(abi.encodeWithSelector(IKernel.disableMode.selector, bytes4(0x00000001), address(0), empty)
341+
UserOperation memory op = buildUserOperation(
342+
abi.encodeWithSelector(IKernel.disableMode.selector, bytes4(0x00000001), address(0), empty)
340343
);
341344
performUserOperationWithSig(op);
342345

test/foundry/validator/KillSwitchValidator.t.sol

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,8 @@ contract KillSwitchValidatorTest is KernelECDSATest {
6868
}
6969

7070
function test_force_unblock() external {
71-
UserOperation memory op = buildUserOperation(abi.encodeWithSelector(Kernel.execute.selector, owner, 0, "", Operation.Call));
71+
UserOperation memory op =
72+
buildUserOperation(abi.encodeWithSelector(Kernel.execute.selector, owner, 0, "", Operation.Call));
7273

7374
op.signature = bytes.concat(bytes4(0), entryPoint.signUserOpHash(vm, ownerKey, op));
7475
performUserOperation(op);

test/foundry/validator/P256Validator.t.sol

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,17 +16,14 @@ import {P256} from "p256-verifier/P256.sol";
1616
import {FCL_ecdsa_utils} from "FreshCryptoLib/FCL_ecdsa_utils.sol";
1717
import {IKernel} from "src/interfaces/IKernel.sol";
1818

19-
2019
using ERC4337Utils for IEntryPoint;
2120

2221
contract P256ValidatorTest is KernelTestBase {
2322
P256Verifier p256Verifier;
2423
P256Validator p256Validator;
2524

2625
// Curve order (number of points)
27-
uint256 constant n =
28-
0xFFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551;
29-
26+
uint256 constant n = 0xFFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551;
3027

3128
uint256 x;
3229
uint256 y;
@@ -55,7 +52,7 @@ contract P256ValidatorTest is KernelTestBase {
5552
return abi.encodePacked(bytes4(0x00000000), abi.encode(r, s));
5653
}
5754

58-
function getOwners() internal virtual override returns (address[] memory _owners){
55+
function getOwners() internal virtual override returns (address[] memory _owners) {
5956
_owners = new address[](1);
6057
_owners[0] = address(0);
6158
return _owners;
@@ -69,7 +66,7 @@ contract P256ValidatorTest is KernelTestBase {
6966
return abi.encodeWithSelector(KernelStorage.initialize.selector, p256Validator, abi.encode(x, y));
7067
}
7168

72-
function test_default_validator_enable() external override{
69+
function test_default_validator_enable() external override {
7370
UserOperation memory op = buildUserOperation(
7471
abi.encodeWithSelector(
7572
IKernel.execute.selector,
@@ -106,7 +103,7 @@ contract P256ValidatorTest is KernelTestBase {
106103
function test_external_call_execute_success() external override {
107104
vm.skip(true);
108105
}
109-
106+
110107
function test_external_call_execute_delegatecall_success() external override {
111108
vm.skip(true);
112109
}
@@ -150,7 +147,7 @@ contract P256ValidatorTest is KernelTestBase {
150147
vm.assume(privateKey != 0);
151148
(uint256 x1, uint256 y1) = generatePublicKey(privateKey);
152149
(uint256 r, uint256 s) = generateSignature(privateKey, hash);
153-
150+
154151
vm.assume(x1 != 0);
155152
vm.assume(y1 != 0);
156153
vm.assume(r != 0);
@@ -161,7 +158,7 @@ contract P256ValidatorTest is KernelTestBase {
161158
function test_validate_signature() external override {
162159
Kernel kernel2 = Kernel(payable(factory.createAccount(address(kernelImpl), getInitializeData(), 3)));
163160
bytes32 hash = keccak256(abi.encodePacked("hello world"));
164-
161+
165162
bytes32 digest = keccak256(
166163
abi.encodePacked(
167164
"\x19\x01", ERC4337Utils._buildDomainSeparator(KERNEL_NAME, KERNEL_VERSION, address(kernel)), hash

0 commit comments

Comments
 (0)