Skip to content

Commit

Permalink
[#312] Use immutables for storing values
Browse files Browse the repository at this point in the history
  • Loading branch information
akshay-ap committed Apr 25, 2024
1 parent a5693e0 commit c2309a9
Show file tree
Hide file tree
Showing 4 changed files with 126 additions and 38 deletions.
44 changes: 41 additions & 3 deletions modules/passkey/contracts/SafeWebAuthnSignerProxy.sol
Original file line number Diff line number Diff line change
@@ -1,7 +1,45 @@
// SPDX-License-Identifier: LGPL-3.0-only
pragma solidity >=0.8.0;
import {SafeProxy} from "@safe-global/safe-contracts/contracts/proxies/SafeProxy.sol";
import {IP256Verifier} from "./interfaces/IP256Verifier.sol";

contract SafeWebAuthnSignerProxy is SafeProxy {
constructor(address implementation) SafeProxy(implementation) {}
/**
* @title SafeWebAuthnSignerProxy
* @dev A proxy contract that points to SafeWebAuthnSigner.
*/
contract SafeWebAuthnSignerProxy {
uint256 internal immutable X;
uint256 internal immutable Y;
IP256Verifier internal immutable VERIFIER;
address internal singleton;
constructor(address implementation, uint256 x, uint256 y, address verifier) {
singleton = implementation;
X = x;
Y = y;
VERIFIER = IP256Verifier(verifier);
}

/// @dev Fallback function forwards all transactions and returns all received return data.
// solhint-disable-next-line no-complex-fallback
fallback() external payable {
bytes memory data = abi.encodePacked(msg.data, X, Y, VERIFIER);

// solhint-disable-next-line no-inline-assembly
assembly {
let _singleton := and(sload(0), 0xffffffffffffffffffffffffffffffffffffffff)
// 0xa619486e == keccak("masterCopy()"). The value is right padded to 32-bytes with 0s
if eq(calldataload(0), 0xa619486e00000000000000000000000000000000000000000000000000000000) {
mstore(0, _singleton)
return(0, 0x20)
}
let dataSize := mload(data)
let dataLocation := add(data, 0x20)

let success := delegatecall(gas(), _singleton, dataLocation, dataSize, 0, 0)
returndatacopy(0, 0, returndatasize())
if eq(success, 0) {
revert(0, returndatasize())
}
return(0, returndatasize())
}
}
}
16 changes: 7 additions & 9 deletions modules/passkey/contracts/SafeWebAuthnSignerProxyFactory.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,19 @@ import {IP256Verifier} from "./interfaces/IP256Verifier.sol";
import {ERC1271} from "./libraries/ERC1271.sol";
import {WebAuthn} from "./libraries/WebAuthn.sol";
import {SafeWebAuthnSignerProxy} from "./SafeWebAuthnSignerProxy.sol";
import {SafeWebAuthnSignerSingleton} from "./SafeWebAuthnSignerSingleton.sol";
/**
* @title WebAuthnSignerFactory
* @dev A factory contract for creating and managing WebAuthn signers.
* @title SafeWebAuthnSignerProxyFactory
* @dev A factory contract for creating and managing WebAuthn proxy signers.
*/
contract SafeWebAuthnSignerProxyFactory is ICustomECDSASignerProxyFactory {
/**
* @inheritdoc ICustomECDSASignerProxyFactory
*/
function getSigner(address singleton, uint256 x, uint256 y, address verifier) public view override returns (address signer) {
bytes32 codeHash = keccak256(abi.encodePacked(type(SafeWebAuthnSignerProxy).creationCode, uint256(uint160(singleton))));
bytes32 salt = keccak256(abi.encodePacked(x, y, verifier));
signer = address(uint160(uint256(keccak256(abi.encodePacked(hex"ff", address(this), salt, codeHash)))));
bytes32 codeHash = keccak256(
abi.encodePacked(type(SafeWebAuthnSignerProxy).creationCode, uint256(uint160(singleton)), x, y, uint256(uint160(verifier)))
);
signer = address(uint160(uint256(keccak256(abi.encodePacked(hex"ff", address(this), bytes32(0), codeHash)))));
}

/**
Expand All @@ -27,10 +27,8 @@ contract SafeWebAuthnSignerProxyFactory is ICustomECDSASignerProxyFactory {
function createSigner(address singleton, uint256 x, uint256 y, address verifier) external returns (address signer) {
signer = getSigner(singleton, x, y, verifier);

bytes32 salt = keccak256(abi.encodePacked(x, y, verifier));
if (_hasNoCode(signer)) {
SafeWebAuthnSignerProxy created = new SafeWebAuthnSignerProxy{salt: salt}(singleton);
SafeWebAuthnSignerSingleton(address(created)).setup(x, y, verifier);
SafeWebAuthnSignerProxy created = new SafeWebAuthnSignerProxy{salt: bytes32(0)}(singleton, x, y, verifier);
require(address(created) == signer);
}
}
Expand Down
38 changes: 12 additions & 26 deletions modules/passkey/contracts/SafeWebAuthnSignerSingleton.sol
Original file line number Diff line number Diff line change
@@ -1,41 +1,27 @@
// SPDX-License-Identifier: LGPL-3.0-only
pragma solidity >=0.8.0;

import {SignatureValidator} from "./base/SignatureValidator.sol";
import {SignatureValidatorProxy} from "./base/SignatureValidatorProxy.sol";
import {IP256Verifier} from "./interfaces/IP256Verifier.sol";
import {WebAuthn} from "./libraries/WebAuthn.sol";

/**
* @title WebAuthn Safe Signature Validator Singleton
* @dev A contract that represents a WebAuthn signer.
* @custom:security-contact [email protected]
*/
contract SafeWebAuthnSignerSingleton is SignatureValidator {
address public singleton;
uint256 public x;
uint256 public y;
IP256Verifier public verifier;

// TODO: Constructor to disable use of singleton for signature verification

/**
* @dev Setup function.
* @param _x The X coordinate of the signer's public key.
* @param _y The Y coordinate of the signer's public key.
* @param _verifier The P-256 verifier to use for signature validation. It MUST implement the
* same interface as the EIP-7212 precompile.
*/
function setup(uint256 _x, uint256 _y, address _verifier) external {
require(x == 0, "SafeWebAuthnSigner: already initialized");
x = _x;
y = _y;
verifier = IP256Verifier(_verifier);
}
contract SafeWebAuthnSignerSingleton is SignatureValidatorProxy {
address internal singleton;

/**
* @inheritdoc SignatureValidator
* @inheritdoc SignatureValidatorProxy
*/
function _verifySignature(bytes32 message, bytes calldata signature) internal view virtual override returns (bool success) {
success = WebAuthn.verifySignature(message, signature, WebAuthn.USER_VERIFICATION, x, y, verifier);
function _verifySignature(
bytes32 message,
bytes calldata signature,
uint256 x,
uint256 y,
address verifier
) public view virtual override returns (bool success) {
success = WebAuthn.verifySignature(message, signature, WebAuthn.USER_VERIFICATION, x, y, IP256Verifier(verifier));
}
}
66 changes: 66 additions & 0 deletions modules/passkey/contracts/base/SignatureValidatorProxy.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// SPDX-License-Identifier: LGPL-3.0-only
pragma solidity >=0.8.0;

import {ERC1271} from "../libraries/ERC1271.sol";
/**
* @title Signature Validator Base Contract
* @dev A interface for smart contract Safe owners that supports multiple ERC-1271 `isValidSignature` versions.
* @custom:security-contact [email protected]
*/
abstract contract SignatureValidatorProxy {
/**
* @dev Validates the signature for the given data.
* bytes data The signed data bytes.
* bytes calldata signature The signature to be validated.
* @return magicValue The magic value indicating the validity of the signature.
*/
function isValidSignature(bytes memory data, bytes calldata signature) external view returns (bytes4 magicValue) {
uint256 x;
uint256 y;
address verifier;
// solhint-disable-next-line no-inline-assembly
assembly {
x := calldataload(sub(calldatasize(), 84))
y := calldataload(sub(calldatasize(), 52))
verifier := shr(96, calldataload(sub(calldatasize(), 20)))
}
if (_verifySignature(keccak256(data), signature, x, y, verifier)) {
magicValue = ERC1271.LEGACY_MAGIC_VALUE;
}
}

/**
* @dev Validates the signature for a given data hash.
* bytes32 message The signed message.
* bytes calldata signature The signature to be validated.
* @return magicValue The magic value indicating the validity of the signature.
*/
function isValidSignature(bytes32 message, bytes calldata signature) external view returns (bytes4 magicValue) {
uint256 x;
uint256 y;
address verifier;
// solhint-disable-next-line no-inline-assembly
assembly {
x := calldataload(sub(calldatasize(), 84))
y := calldataload(sub(calldatasize(), 52))
verifier := shr(96, calldataload(sub(calldatasize(), 20)))
}

if (_verifySignature(message, signature, x, y, verifier)) {
magicValue = ERC1271.MAGIC_VALUE;
}
}

/**
* @dev Verifies a signature.
* @param message The signed message.
* @return success Whether the signature is valid.
*/
function _verifySignature(
bytes32 message,
bytes calldata signature,
uint256 x,
uint256 y,
address verifier
) public view virtual returns (bool success);
}

0 comments on commit c2309a9

Please sign in to comment.