var Web3 = require('web3');
const keccak256 = require('keccak256')
var web3 = new Web3();

console.log("version :", web3.version);

var pv = '';

// load address
var ac = web3.eth.accounts.privateKeyToAccount(pv);

console.log(ac);

// data privatekey

var message = "0x" + keccak256('hello').toString('hex');
//another way keccak256(Buffer.from('hello')).toString('hex')

console.log("msg hash is ",message);


var signature = web3.eth.accounts.sign(message, pv);

console.log("signature :", signature);


var messageHash= web3.eth.accounts.hashMessage(message);
// recover 1
var recover_1 = web3.eth.accounts.recover({
    messageHash: messageHash,
    v: signature.v,
    r: signature.r,
    s: signature.s
});

console.log("recover 1 :", recover_1);


// message, signature
var recover_2 = web3.eth.accounts.recover(message, signature.signature);
console.log("recover 2 :", recover_2);

// message, v, r, s
var recover_3 = web3.eth.accounts.recover(message, signature.v, signature.r, signature.s);
console.log("recover 3 :", recover_3);
// contracts/MyContract.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";

contract Demo {
    using ECDSA for bytes32;
    event Log(bytes32 dataHash);
    event Log2(address mess);

    address public signer;

    constructor(){

        signer = 0x;
    }


    function verify(bytes32 hash, bytes memory signature) public returns (bool) {
        bytes32 ethSignedHash = hash.toEthSignedMessageHash();
        emit Log(ethSignedHash);

        address res = ethSignedHash.recover(signature);
        emit Log2(res);
        return ethSignedHash.recover(signature) == signer;
    }


    function verify2(bytes32 ethSignedHash, bytes memory signature) public returns (address) {
            address res = ethSignedHash.recover(signature);
            return res;
    }

    function main(
        // Verification
        bytes memory signature,
        // Data
        string calldata data
    ) public returns (bool){
        bytes32 txHash = keccak256(abi.encodePacked(data));
        require(verify(txHash, signature), "Beta: Unauthorised");
        return true;
    }


    function getHash(string calldata data) external {
        bytes32 dataHash = keccak256(abi.encodePacked(data));
        bytes32 ethSignedHash = dataHash.toEthSignedMessageHash();
        emit Log(ethSignedHash);
    }

    function msgHash(string calldata data) external {
        bytes32 dataHash = keccak256(abi.encodePacked(data));

        emit Log(dataHash);
    }


}

参考文献
https://solidity-by-example.org/hashing/ Use Keccak256
web3.js sign
https://web3js.readthedocs.io/en/v1.2.4/web3-eth-accounts.html?highlight=web3.eth.accounts#privatekeytoaccount
openzeppelin 4.x
https://docs.openzeppelin.com/contracts/4.x/api/utils#ECDSA-toEthSignedMessageHash-bytes-