How to sign with owner address and verify signature comes from owner?

Hi, I’m trying to sign a message with an my address as the owner of a contract to send that signature in a method of my contract. Then have my contract to verify that the signature comes from my address. Sign it like you mean it: creating and verifying Ethereum signatures I have the signing part in my dapp

const EthCrypto = require("eth-crypto");
const signerIdentity = EthCrypto.createIdentity();
const message = EthCrypto.hash.keccak256([
  {type: "string",value: "Hello World!"}
]);
const signature = EthCrypto.sign(signerIdentity.privateKey, message);

and this function in my contract to check if the signer of the signature is the me (the owner of the contract) as


function verifyThenProceed(bytes calldata _signature) public {
    require(verifyOwnerSignature(keccak256(abi.encode(_msgSender())), _signature), "Invalid Signature");
// logic if passed
  }


function checkSignature(bytes32 hash, bytes memory signature) private view returns(bool) {
    return hash.toEthSignedMessageHash().recover(signature) == owner();
  }

But it keeps failing. How do I make sure to sign the signature with my address?

this line: const signerIdentity = EthCrypto.createIdentity();, generates a new private key, which then you use to sign the message (the address for it is stored at signerIdentity.address). That's probably why the call to checkSignature is failing (i'm assuming you are following the article and deployed with remix). You would have to deploy the contract with that same key or change the contract owner.

Try interacting with the contract below. It's single purpose is to verify EOAs (contract's don't have private keys, can't sign messages). It generates an hash for the address provided (messageHash), which is then signed and the signature passed to verifyEOA.
verifiedEOA returns true or false depending on the account verification.

Can't provide much input on the JS side of things (i use python in my environment + web3js on the frontend).
You will need to generate a new key with const signerIdentity = EthCrypto.createIdentity();, then call the contract method messageHash with signerIdentity.address as argument, and sign the hash returned, probably with const signature = EthCrypto.sign(signerIdentity.privateKey, hashRetrivedFromTheContract);.

pragma solidity ^0.8.0;


interface IEOAVerify {
    event EOAVerification(address indexed account);

    function verifiedEOA(address account) external view returns (bool);
    function messageHash(address acc) external pure returns (bytes32);
    function verifyEOA(address signer, bytes memory signature) external;
}

contract EOAVerify is IEOAVerify {
    mapping(address => bool) public override verifiedEOA;

    function messageHash(address acc) public pure override returns (bytes32) {
        return keccak256(abi.encodePacked("EOAVerification:", acc));
    }

    function verifyEOA(address signer, bytes memory signature) public override {
        bytes32 h = messageHash(signer);
        bytes32 ethSignedMessageHash = signedMessageHash(h);
        address s = signer == address(0) ? msg.sender : signer;
        require(recoverSigner(ethSignedMessageHash, signature) == s, 'EOAVerify: Signed mismatch');
        verifiedEOA[s] = true;
        emit EOAVerification(s);
    }

    function signedMessageHash(bytes32 _messageHash) internal pure returns (bytes32) {
        // "\x19Ethereum Signed Message\n" + len(msg) + msg
        return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", _messageHash));
    }

    function recoverSigner(bytes32 signedHash, bytes memory _signature)
        internal pure
        returns (address)
    {
        (bytes32 r, bytes32 s, uint8 v) = splitSignature(_signature);
        return ecrecover(signedHash, v, r, s);
    }

    function splitSignature(bytes memory sig)
        internal pure
        returns (bytes32 r, bytes32 s, uint8 v)
    {
        require(sig.length == 65, "invalid signature length");
        assembly {
            // first 32 bytes, after the length prefix
            r := mload(add(sig, 32))
            // second 32 bytes
            s := mload(add(sig, 64))
            // final byte (first byte of the next 32 bytes)
            v := byte(0, mload(add(sig, 96)))
        }
    }
}
1 Like

So this is what I got so far but I kept getting different address of the signer and they are all incorrect (signer should accounts[0] address). Could you please help? @helio.rosa Thank you

Here is my Truffle signing code:

const accounts = await web3.eth.getAccounts();

    const signerIdentity = EthCrypto.createIdentity();

    signerIdentity.address = accounts[0];

    const message = EthCrypto.hash.keccak256([ {type: "address",value: accounts[1]} ]);

    const signature = EthCrypto.sign(signerIdentity.privateKey, message);

const t = await contract.isValidData(signature, {from: accounts[1]});

Here is contract to verify signer

function isValidData(bytes memory sig) public view returns(address){
       bytes32 message = keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", msg.sender));
       return recoverSigner(message, sig);
  }

  function recoverSigner(bytes32 message, bytes memory sig)
       public
       pure
       returns (address)
    {
       uint8 v;
       bytes32 r;
       bytes32 s;

       (v, r, s) = splitSignature(sig);
       return ecrecover(message, v, r, s);
  }

  function splitSignature(bytes memory sig)
       public
       pure
       returns (uint8, bytes32, bytes32)
   {
       require(sig.length == 65);

       bytes32 r;
       bytes32 s;
       uint8 v;

       assembly {
           // first 32 bytes, after the length prefix
           r := mload(add(sig, 32))
           // second 32 bytes
           s := mload(add(sig, 64))
           // final byte (first byte of the next 32 bytes)
           v := byte(0, mload(add(sig, 96)))
       }

       return (v, r, s);
   }

Some console log:

accounts:
[
  '0x6f9F7fB9e3a322B282aE0b12759F8bFb0178fe9e',
  '0xC635812305DAba1a9FA888606e6f01476012E37c',
  '0xE84B810361d5712304FbA7B4d5814Cb220d265A6',
  '0x9EaeFD4a3ECCEe4A40B9EFFb86c011B50483c2aC',
  '0x555f0D2D1BaAe410c8861a1207B37cfb179ad974',
  '0x7b05CBCb6C0b2E35137FaFF1EEEDB51Ecd61C2f3',
  '0xe4078a7568960C00B547eDCfB321f8C0CEbFA34b',
  '0xD11869C5C6c7209565aFC5c48187c60a2A829857',
  '0x29Ac1553D9332F470Fb7D0349A6f41f4d4d07ab7',
  '0x4DD07119E4479fc07aDACa79caf5AE3c37b6f9d5'
]

owner: 0x6f9F7fB9e3a322B282aE0b12759F8bFb0178fe9e
signerIdentity {
  address: '0x6f9F7fB9e3a322B282aE0b12759F8bFb0178fe9e',
  privateKey: '0x81547019bef04f65f91163b765453859aa7b1dc4d0047bd0940adf2cc6b9e84b',
  publicKey: '0x6f9F7fB9e3a322B282aE0b12759F8bFb0178fe9e'
}

unsigned signer: 0x3f72F05a8fB6894da9D7690b2D74ade90dF15465


as i mentioned my test environment is python, don't really use Truffle that much but can spot some mistakes in your code:

const signerIdentity = EthCrypto.createIdentity(); creates a new key.
signerIdentity.address = accounts[0]; has no effect, addresses are derived from the public key, which is derived from the private key
isValidData only accepts one argument

if you need to sign with the key for the address at accounts[0], maybe you could try using web3.eth.sign() to sign instead:

const accounts = await web3.eth.getAccounts();
const message = EthCrypto.hash.keccak256([ {type: "address",value: accounts[1]} ]);
const signature = await web3.eth.sign(message, accounts[0);
// IsValidData returns the signer
// (await contract.isValidData(signature)) == accounts[0]

isValidData now returns 0x0 :(. So frustrating I cannot get this simple singing to work.

EthCrypto.sign is not what you want.

toEthSignedMessageHash specifically creates the hash as used by the eth_sign and personal_sign RPC calls. It prefixes the signed data with "\x19Ethereum Signed Message:\n" + len(message), whereas EthCrypto.sign is signing the data as is. (See the docs.)

You should either use Web3.js or Ethers.js to generate the signature, or you should use a library like eth-sig-util that implement this signing algorithm with the prefix.