Skip to content

Commit 7c3bef2

Browse files
committed
add RSA signature verifier
1 parent 6878710 commit 7c3bef2

File tree

2 files changed

+94
-29
lines changed

2 files changed

+94
-29
lines changed
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// SPDX-License-Identifier: MIT
2+
3+
pragma solidity ^0.8.20;
4+
5+
import {RSA} from "@openzeppelin/contracts/utils/cryptography/RSA.sol";
6+
import {IERC7913SignatureVerifier} from "../../interfaces/IERC7913.sol";
7+
8+
/**
9+
* @dev ERC-7913 signature verifier that support RSA keys.
10+
*/
11+
contract ERC7913SignatureVerifierRSA is IERC7913SignatureVerifier {
12+
/// @inheritdoc IERC7913SignatureVerifier
13+
function verify(bytes calldata key, bytes32 hash, bytes calldata signature) public view virtual returns (bytes4) {
14+
(bytes memory e, bytes memory n) = abi.decode(key, (bytes, bytes));
15+
return
16+
RSA.pkcs1Sha256(abi.encodePacked(hash), signature, e, n)
17+
? IERC7913SignatureVerifier.verify.selector
18+
: bytes4(0xFFFFFFFF);
19+
}
20+
}

test/account/AccountERC7913.test.js

Lines changed: 74 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -3,59 +3,104 @@ const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers');
33

44
const { getDomain } = require('@openzeppelin/contracts/test/helpers/eip712');
55
const { ERC4337Helper } = require('../helpers/erc4337');
6-
const { NonNativeSigner, P256SigningKey } = require('../helpers/signers');
6+
const { NonNativeSigner, P256SigningKey, RSASHA256SigningKey } = require('../helpers/signers');
77
const { PackedUserOperation } = require('../helpers/eip712-types');
88

99
const { shouldBehaveLikeAccountCore, shouldBehaveLikeAccountHolder } = require('./Account.behavior');
1010
const { shouldBehaveLikeERC1271 } = require('../utils/cryptography/ERC1271.behavior');
1111
const { shouldBehaveLikeERC7821 } = require('./extensions/ERC7821.behavior');
1212

13+
// Prepare signer in advance (RSA are long to initialize)
14+
const signerECDSA = ethers.Wallet.createRandom();
15+
const signerP256 = new NonNativeSigner(P256SigningKey.random());
16+
const signerRSA = new NonNativeSigner(RSASHA256SigningKey.random());
17+
18+
// Minimal fixture common to the different signer verifiers
1319
async function fixture() {
1420
// EOAs and environment
1521
const [beneficiary, other] = await ethers.getSigners();
1622
const target = await ethers.deployContract('CallReceiverMockExtended');
1723

18-
// P256 signer
19-
const signer = new NonNativeSigner(P256SigningKey.random());
20-
const verifier = await ethers.deployContract('ERC7913SignatureVerifierP256');
24+
// ERC-7913 verifiers
25+
const verifierP256 = await ethers.deployContract('ERC7913SignatureVerifierP256');
26+
const verifierRSA = await ethers.deployContract('ERC7913SignatureVerifierRSA');
2127

22-
// ERC-4337 account
28+
// ERC-4337 env
2329
const helper = new ERC4337Helper();
24-
const mock = await helper.newAccount('$AccountERC7913Mock', [
25-
'AccountERC7913',
26-
'1',
27-
ethers.solidityPacked(
28-
['address', 'bytes32', 'bytes32'],
29-
[verifier.target, signer.signingKey.publicKey.qx, signer.signingKey.publicKey.qy],
30-
),
31-
]);
32-
33-
// ERC-4337 Entrypoint domain
30+
await helper.wait();
3431
const entrypointDomain = await getDomain(entrypoint.v08);
32+
const domain = { name: 'AccountERC7913', version: '1', chainId: entrypointDomain.chainId }; // Missing verifyingContract,
3533

36-
// domain cannot be fetched using getDomain(mock) before the mock is deployed
37-
const domain = {
38-
name: 'AccountERC7913',
39-
version: '1',
40-
chainId: entrypointDomain.chainId,
41-
verifyingContract: mock.address,
42-
};
34+
const makeMock = signer =>
35+
helper.newAccount('$AccountERC7913Mock', ['AccountERC7913', '1', signer]).then(mock => {
36+
domain.verifyingContract = mock.address;
37+
return mock;
38+
});
4339

44-
const signUserOp = userOp =>
45-
signer
40+
const signUserOp = function (userOp) {
41+
return this.signer
4642
.signTypedData(entrypointDomain, { PackedUserOperation }, userOp.packed)
4743
.then(signature => Object.assign(userOp, { signature }));
44+
};
4845

49-
return { helper, mock, domain, signer, target, beneficiary, other, signUserOp };
46+
return { helper, verifierP256, verifierRSA, domain, target, beneficiary, other, makeMock, signUserOp };
5047
}
5148

5249
describe('AccountERC7913', function () {
5350
beforeEach(async function () {
5451
Object.assign(this, await loadFixture(fixture));
5552
});
5653

57-
shouldBehaveLikeAccountCore();
58-
shouldBehaveLikeAccountHolder();
59-
shouldBehaveLikeERC1271({ erc7739: true });
60-
shouldBehaveLikeERC7821();
54+
// Using ECDSA key as verifier
55+
describe('ECDSA key', function () {
56+
beforeEach(async function () {
57+
this.signer = signerECDSA;
58+
this.mock = await this.makeMock(this.signer.address);
59+
});
60+
61+
shouldBehaveLikeAccountCore();
62+
shouldBehaveLikeAccountHolder();
63+
shouldBehaveLikeERC1271({ erc7739: true });
64+
shouldBehaveLikeERC7821();
65+
});
66+
67+
// Using P256 key with an ERC-7913 verifier
68+
describe('P256 key', function () {
69+
beforeEach(async function () {
70+
this.signer = signerP256;
71+
this.mock = await this.makeMock(
72+
ethers.concat([
73+
this.verifierP256.target,
74+
this.signer.signingKey.publicKey.qx,
75+
this.signer.signingKey.publicKey.qy,
76+
]),
77+
);
78+
});
79+
80+
shouldBehaveLikeAccountCore();
81+
shouldBehaveLikeAccountHolder();
82+
shouldBehaveLikeERC1271({ erc7739: true });
83+
shouldBehaveLikeERC7821();
84+
});
85+
86+
// Using RSA key with an ERC-7913 verifier
87+
describe('RSA key', function () {
88+
beforeEach(async function () {
89+
this.signer = signerRSA;
90+
this.mock = await this.makeMock(
91+
ethers.concat([
92+
this.verifierRSA.target,
93+
ethers.AbiCoder.defaultAbiCoder().encode(
94+
['bytes', 'bytes'],
95+
[this.signer.signingKey.publicKey.e, this.signer.signingKey.publicKey.n],
96+
),
97+
]),
98+
);
99+
});
100+
101+
shouldBehaveLikeAccountCore();
102+
shouldBehaveLikeAccountHolder();
103+
shouldBehaveLikeERC1271({ erc7739: true });
104+
shouldBehaveLikeERC7821();
105+
});
61106
});

0 commit comments

Comments
 (0)