// SPDX-License-Identifier: MIT

pragma solidity ^0.8.20;

import {AbstractSigner} from "./AbstractSigner.sol";
import {P256} from "../P256.sol";

/**
 * @dev Implementation of {AbstractSigner} using xref:api:utils/cryptography#P256[P256] signatures.
 *
 * For {Account} usage, a {_setSigner} function is provided to set the {signer} public key.
 * Doing so is easier for a factory, who is likely to use initializable clones of this contract.
 *
 * Example of usage:
 *
 * ```solidity
 * contract MyAccountP256 is Account, SignerP256, Initializable {
 *     function initialize(bytes32 qx, bytes32 qy) public initializer {
 *       _setSigner(qx, qy);
 *     }
 * }
 * ```
 *
 * IMPORTANT: Failing to call {_setSigner} either during construction (if used standalone)
 * or during initialization (if used as a clone) may leave the signer either front-runnable or unusable.
 */
abstract contract SignerP256 is AbstractSigner {
    bytes32 private _qx;
    bytes32 private _qy;

    error SignerP256InvalidPublicKey(bytes32 qx, bytes32 qy);

    /**
     * @dev Sets the signer with a P256 public key. This function should be called during construction
     * or through an initializer.
     */
    function _setSigner(bytes32 qx, bytes32 qy) internal {
        if (!P256.isValidPublicKey(qx, qy)) revert SignerP256InvalidPublicKey(qx, qy);
        _qx = qx;
        _qy = qy;
    }

    /// @dev Return the signer's P256 public key.
    function signer() public view virtual returns (bytes32 qx, bytes32 qy) {
        return (_qx, _qy);
    }

    /// @inheritdoc AbstractSigner
    function _rawSignatureValidation(
        bytes32 hash,
        bytes calldata signature
    ) internal view virtual override returns (bool) {
        if (signature.length < 0x40) return false;
        bytes32 r = bytes32(signature[0x00:0x20]);
        bytes32 s = bytes32(signature[0x20:0x40]);
        (bytes32 qx, bytes32 qy) = signer();
        return P256.verify(hash, r, s, qx, qy);
    }
}
