Skip to content

Commit

Permalink
Verify Multiple P-256 Verifiers Are Supported
Browse files Browse the repository at this point in the history
  • Loading branch information
nlordell committed Mar 7, 2024
1 parent a2914d2 commit 22f1097
Show file tree
Hide file tree
Showing 19 changed files with 456 additions and 110 deletions.
1 change: 1 addition & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
module.exports = {
root: true,
env: {
browser: true,
es2021: true,
Expand Down
2 changes: 0 additions & 2 deletions modules/passkey/.env.sample

This file was deleted.

3 changes: 3 additions & 0 deletions modules/passkey/.eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
coverage/
dist/
typechain-types/
1 change: 0 additions & 1 deletion modules/passkey/contracts/test/TestP256VerifierLib.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
// SPDX-License-Identifier: LGPL-3.0-only
/* solhint-disable payable-fallback */
pragma solidity ^0.8.0;

import {IP256Verifier, P256VerifierLib} from "../verifiers/IP256Verifier.sol";
Expand Down
86 changes: 86 additions & 0 deletions modules/passkey/contracts/test/TestWebAuthnSignerFactory.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
// SPDX-License-Identifier: LGPL-3.0-only
/* solhint-disable one-contract-per-file */
pragma solidity ^0.8.0;

import {IP256Verifier, P256VerifierLib} from "../verifiers/IP256Verifier.sol";

contract TestWebAuthnSignerFactory {
function createSigner(address verifier, uint256 x, uint256 y) external returns (TestWebAuthnSigner signer) {
signer = new TestWebAuthnSigner{salt: 0}(verifier, x, y);
}
}

contract TestWebAuthnSigner {
using P256VerifierLib for IP256Verifier;

struct SignatureData {
bytes authenticatorData;
bytes clientDataFields;
uint256 r;
uint256 s;
}

string private constant _BASE64URL = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";

address private immutable _VERIFIER;
uint256 private immutable _X;
uint256 private immutable _Y;

constructor(address verifier, uint256 x, uint256 y) {
_VERIFIER = verifier;
_X = x;
_Y = y;
}

function isValidSignature(bytes32 hash, bytes calldata signature) external view returns (bytes4 magicValue) {
SignatureData calldata sig;
// solhint-disable-next-line no-inline-assembly
assembly ("memory-safe") {
sig := signature.offset
}

if (
IP256Verifier(_VERIFIER).verifySignatureAllowMalleability(
_signingMessage(hash, sig.authenticatorData, sig.clientDataFields),
sig.r,
sig.s,
_X,
_Y
)
) {
magicValue = this.isValidSignature.selector;
}
}

function _signingMessage(
bytes32 challenge,
bytes calldata authenticatorData,
bytes calldata clientDataFields
) internal pure returns (bytes32 message) {
/* solhint-disable quotes */
bytes memory clientDataJson = abi.encodePacked(
'{"type":"webauthn.get","challenge":"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",',
clientDataFields,
"}"
);
/* solhint-enable quotes */

string memory alphabet = _BASE64URL;
// solhint-disable-next-line no-inline-assembly
assembly ("memory-safe") {
let lut := add(alphabet, 1)
let ptr := add(clientDataJson, 68)

for {
let i := 0
} lt(i, 42) {
i := add(i, 1)
} {
mstore8(add(ptr, i), mload(add(lut, and(0x3f, shr(sub(250, mul(6, i)), challenge)))))
}
mstore8(add(ptr, 42), mload(add(lut, and(0x3f, shl(2, challenge)))))
}

message = sha256(abi.encodePacked(authenticatorData, sha256(clientDataJson)));
}
}
4 changes: 1 addition & 3 deletions modules/passkey/docker-compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@ services:
build:
context: .
dockerfile: docker/bundler/Dockerfile
args:
TAG: 26e4f4c433916a6a2ea8ecc91ba8a56cd904f27f
restart: always
command: ['--auto', '--network=http://geth:8545']
ports:
Expand All @@ -30,7 +28,7 @@ services:
context: .
dockerfile: docker/bundler/Dockerfile
args:
TAG: 26e4f4c433916a6a2ea8ecc91ba8a56cd904f27f
TAG: main
restart: always
command: ['--auto', '--network=http://geth:8545']
ports:
Expand Down
4 changes: 1 addition & 3 deletions modules/passkey/hardhat.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import dotenv from 'dotenv'
import type { HardhatUserConfig } from 'hardhat/config'
import 'hardhat-deploy'

// Load environment variables.
dotenv.config()

const config: HardhatUserConfig = {
Expand All @@ -16,10 +15,9 @@ const config: HardhatUserConfig = {
networks: {
localhost: {
url: 'http://localhost:8545',
tags: ['dev', 'safe'],
tags: ['dev'],
},
hardhat: {
gasPrice: 10000000000,
tags: ['test'],
},
},
Expand Down
7 changes: 4 additions & 3 deletions modules/passkey/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,15 +35,16 @@
"fmt:check": "prettier --check .",
"lint": "npm run lint:sol && npm run lint:ts",
"lint:sol": "solhint 'contracts/**/*.sol'",
"lint:ts": "eslint --fix ./src && eslint --fix ./test",
"lint:ts": "eslint .",
"test": "hardhat test",
"test:e2e": "./test/4337-e2e/run.sh"
"test:4337": "./test/4337/run.sh"
},
"devDependencies": {
"@account-abstraction/contracts": "^0.7.0",
"@noble/curves": "^1.3.0",
"@nomicfoundation/hardhat-toolbox": "^4.0.0",
"@account-abstraction/contracts": "^0.7.0",
"@safe-global/safe-erc4337": "^0.3.0",
"@simplewebauthn/server": "^9.0.3",
"cbor": "^9.0.2",
"dotenv": "^16.4.5",
"hardhat": "^2.21.0",
Expand Down
16 changes: 5 additions & 11 deletions modules/passkey/src/deploy/launchpad.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,19 @@
import { DeployFunction } from 'hardhat-deploy/types'
import { LAUNCHPAD_DEPLOYMENT_ENTRY_POINT_ADDRESS } from '../constants'

const deploy: DeployFunction = async ({ deployments, getNamedAccounts, network }) => {
if (!network.tags.dev && !network.tags.test) {
return
}

const deploy: DeployFunction = async ({ deployments, getNamedAccounts }) => {
const { deployer } = await getNamedAccounts()
const { deploy } = deployments

const entryPoint = (await deployments.getOrNull('EntryPoint').then((d) => d?.address)) || LAUNCHPAD_DEPLOYMENT_ENTRY_POINT_ADDRESS
if (!entryPoint) {
throw new Error('Entry point contract should be deployed or set in LAUNCHPAD_DEPLOYMENT_ENTRY_POINT_ADDRESS')
}
const entryPoint = await deployments.get('EntryPoint')

await deploy('Safe256BitECSignerLaunchpad', {
from: deployer,
args: [entryPoint],
args: [entryPoint.address],
log: true,
deterministicDeployment: true,
})
}

deploy.dependencies = ['entrypoint']

export default deploy
12 changes: 5 additions & 7 deletions modules/passkey/src/deploy/safe.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,15 @@ import { DeployFunction } from 'hardhat-deploy/types'
import { LAUNCHPAD_DEPLOYMENT_ENTRY_POINT_ADDRESS } from '../constants'

Check failure on line 7 in modules/passkey/src/deploy/safe.ts

View workflow job for this annotation

GitHub Actions / lint

'LAUNCHPAD_DEPLOYMENT_ENTRY_POINT_ADDRESS' is defined but never used

const deploy: DeployFunction = async ({ deployments, getNamedAccounts, network }) => {
if (!network.tags.safe && !network.tags.test) {
if (!network.tags.dev && !network.tags.test) {
return
}

const entryPoint = (await deployments.getOrNull('EntryPoint').then((d) => d?.address)) || LAUNCHPAD_DEPLOYMENT_ENTRY_POINT_ADDRESS
if (!entryPoint) {
throw new Error('Entry point contract should be deployed or set in LAUNCHPAD_DEPLOYMENT_ENTRY_POINT_ADDRESS')
}

const { deployer } = await getNamedAccounts()
const { deploy } = deployments

const entryPoint = await deployments.get('EntryPoint')

await deploy('MultiSend', {
from: deployer,
contract: MultiSend,
Expand Down Expand Up @@ -50,12 +47,13 @@ const deploy: DeployFunction = async ({ deployments, getNamedAccounts, network }
await deploy('Safe4337Module', {
from: deployer,
contract: Safe4337Module,
args: [entryPoint],
args: [entryPoint.address],
log: true,
deterministicDeployment: true,
})
}

deploy.dependencies = ['entrypoint']
deploy.tags = ['safe']

export default deploy
10 changes: 10 additions & 0 deletions modules/passkey/src/deploy/verifiers.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,19 @@
import type { DeployFunction } from 'hardhat-deploy/types'

import DaimoP256Verifier from '../vendor/daimo-eth/P256Verifier.json'

const deploy: DeployFunction = async ({ deployments, getNamedAccounts }) => {
const { deployer } = await getNamedAccounts()
const { deploy } = deployments

await deploy('DaimoP256Verifier', {
from: deployer,
contract: DaimoP256Verifier,
args: [],
deterministicDeployment: true,
log: true,
})

const FCLP256Verifier = await deploy('FCLP256Verifier', {
from: deployer,
args: [],
Expand Down
Loading

0 comments on commit 22f1097

Please sign in to comment.