Skip to content

Commit 0e71ce5

Browse files
ernestognwAmxx
andauthored
Add ERC7913WebAuthnVerifier for external WebAuthn verification (#188)
Co-authored-by: Hadrien Croubois <[email protected]>
1 parent b7220cc commit 0e71ce5

File tree

4 files changed

+62
-2
lines changed

4 files changed

+62
-2
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 16-07-2025
2+
3+
- `ERC7913WebAuthnVerifier`: Add an ERC-7913 signature verifier that supports WebAuthn authentication assertions using P256 keys.
4+
15
## 08-07-2025
26

37
- `WebAuthn.sol`: Add library for on-chain verification of WebAuthn authentication assertions and P256 signatures.

contracts/utils/cryptography/README.adoc

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ A collection of contracts and libraries that implement various signature validat
1616
* {SignerERC7913}, {MultiSignerERC7913}, {MultiSignerERC7913Weighted}: Implementations of {AbstractSigner} that validate signatures based on ERC-7913. Including a simple and weighted multisignature scheme.
1717
* {SignerZKEmail}: Implementation of an {AbstractSigner} that enables email-based authentication through zero-knowledge proofs.
1818
* {SignerWebAuthn}: Implementation of {SignerP256} that supports WebAuthn authentication assertions.
19-
* {ERC7913P256Verifier}, {ERC7913RSAVerifier}, {ERC7913ZKEmailVerifier}: Ready to use ERC-7913 signature verifiers for P256, RSA keys, and ZKEmail.
19+
* {ERC7913P256Verifier}, {ERC7913RSAVerifier}, {ERC7913ZKEmailVerifier}, {ERC7913WebAuthnVerifier}: Ready to use ERC-7913 signature verifiers for P256, RSA keys, ZKEmail and WebAuthn.
2020

2121
== Utils
2222

@@ -60,3 +60,5 @@ A collection of contracts and libraries that implement various signature validat
6060
{{ERC7913RSAVerifier}}
6161

6262
{{ERC7913ZKEmailVerifier}}
63+
64+
{{ERC7913WebAuthnVerifier}}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// SPDX-License-Identifier: MIT
2+
3+
pragma solidity ^0.8.24;
4+
5+
import {WebAuthn} from "../WebAuthn.sol";
6+
import {IERC7913SignatureVerifier} from "@openzeppelin/contracts/interfaces/IERC7913.sol";
7+
8+
/**
9+
* @dev ERC-7913 signature verifier that supports WebAuthn authentication assertions.
10+
*
11+
* This verifier enables the validation of WebAuthn signatures using P256 public keys.
12+
* The key is expected to be a 64-byte concatenation of the P256 public key coordinates (qx || qy).
13+
* The signature is expected to be an abi-encoded {WebAuthn-WebAuthnAuth} struct.
14+
*
15+
* Uses {WebAuthn-verifyMinimal} for signature verification, which performs the essential
16+
* WebAuthn checks: type validation, challenge matching, and cryptographic signature verification.
17+
*
18+
* NOTE: Wallets that may require default P256 validation may install a P256 verifier separately.
19+
*/
20+
contract ERC7913WebAuthnVerifier is IERC7913SignatureVerifier {
21+
/// @inheritdoc IERC7913SignatureVerifier
22+
function verify(bytes calldata key, bytes32 hash, bytes calldata signature) public view virtual returns (bytes4) {
23+
(bool decodeSuccess, WebAuthn.WebAuthnAuth calldata auth) = WebAuthn.tryDecodeAuth(signature);
24+
25+
return
26+
decodeSuccess &&
27+
key.length == 0x40 &&
28+
WebAuthn.verifyMinimal(abi.encodePacked(hash), auth, bytes32(key[0x00:0x20]), bytes32(key[0x20:0x40]))
29+
? IERC7913SignatureVerifier.verify.selector
30+
: bytes4(0xFFFFFFFF);
31+
}
32+
}

test/account/AccountERC7913.test.js

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ const {
88
P256SigningKey,
99
RSASHA256SigningKey,
1010
} = require('@openzeppelin/contracts/test/helpers/signers');
11-
const { ZKEmailSigningKey } = require('../helpers/signers');
11+
const { ZKEmailSigningKey, WebAuthnSigningKey } = require('../helpers/signers');
1212

1313
const { shouldBehaveLikeAccountCore, shouldBehaveLikeAccountHolder } = require('./Account.behavior');
1414
const { shouldBehaveLikeERC1271 } = require('../utils/cryptography/ERC1271.behavior');
@@ -18,6 +18,7 @@ const { shouldBehaveLikeERC7821 } = require('./extensions/ERC7821.behavior');
1818
const signerECDSA = ethers.Wallet.createRandom();
1919
const signerP256 = new NonNativeSigner(P256SigningKey.random());
2020
const signerRSA = new NonNativeSigner(RSASHA256SigningKey.random());
21+
const signerWebAuthn = new NonNativeSigner(WebAuthnSigningKey.random());
2122

2223
// Constants for ZKEmail
2324
const accountSalt = '0x046582bce36cdd0a8953b9d40b8f20d58302bacf3bcecffeb6741c98a52725e2'; // keccak256("[email protected]")
@@ -48,6 +49,7 @@ async function fixture() {
4849
// ERC-7913 verifiers
4950
const verifierP256 = await ethers.deployContract('ERC7913P256Verifier');
5051
const verifierRSA = await ethers.deployContract('ERC7913RSAVerifier');
52+
const verifierWebAuthn = await ethers.deployContract('ERC7913WebAuthnVerifier');
5153
const verifierZKEmail = await ethers.deployContract('$ERC7913ZKEmailVerifier');
5254

5355
// ERC-4337 env
@@ -72,6 +74,7 @@ async function fixture() {
7274
helper,
7375
verifierP256,
7476
verifierRSA,
77+
verifierWebAuthn,
7578
verifierZKEmail,
7679
dkim,
7780
zkEmailVerifier,
@@ -142,6 +145,25 @@ describe('AccountERC7913', function () {
142145
shouldBehaveLikeERC7821();
143146
});
144147

148+
// Using WebAuthn key with an ERC-7913 verifier
149+
describe('WebAuthn key', function () {
150+
beforeEach(async function () {
151+
this.signer = signerWebAuthn;
152+
this.mock = await this.makeMock(
153+
ethers.concat([
154+
this.verifierWebAuthn.target,
155+
this.signer.signingKey.publicKey.qx,
156+
this.signer.signingKey.publicKey.qy,
157+
]),
158+
);
159+
});
160+
161+
shouldBehaveLikeAccountCore();
162+
shouldBehaveLikeAccountHolder();
163+
shouldBehaveLikeERC1271({ erc7739: true });
164+
shouldBehaveLikeERC7821();
165+
});
166+
145167
// Using ZKEmail with an ERC-7913 verifier
146168
describe('ZKEmail', function () {
147169
beforeEach(async function () {

0 commit comments

Comments
 (0)