1

I want to create a smart contract that contains the public key of a party (the key is generated outside the blockchain) and contains a function to verify signed data. How can we implement this function in solidity? I took a look at ecrecover but I think it needs an ethereum address instead of a public key.

[UPDATE]: the public key isn't related to any Ethereum address.

Yilmaz
  • 1,580
  • 10
  • 24
maroodb
  • 1,111
  • 1
  • 10
  • 32

3 Answers3

1

As long as the public key is a point on the secp256k1 elliptic curve, their ECDSA signatures can be verified via Ethereum's ecrecover precompile.

Note that an Ethereum address is just the rightmost 160 bit of the keccak256 hash of the concatenation of the hex-encoded x and y coordinates of the public key, see Appendix F: Signing Transactions" §134 in the Yellow Paper.

Example function to compute the address of a public key:

function toAddress(uint x, uint y) public view returns (address) {
    return address(uint160(uint(keccak256(abi.encode(x, y)))));
}
merkleplant
  • 128
  • 6
0

you can use the ecrecover function in Solidity. The ecrecover function will return Ethereum address associated with the public key that signed the data, but you can then compare this address with the one derived from the public key you provided.

smart contract code that contains a public key and verify function:


contract SignatureVerifier {
    bytes32 public publicKey;
constructor(bytes32 _publicKey) {
    publicKey = _publicKey;
}

function verify(
    bytes32 hash,
    uint8 v,
    bytes32 r,
    bytes32 s
) public view returns (bool) {
    address recoveredAddress = ecrecover(hash, v, r, s);

    address publicKeyAddress = address(uint160(uint256(publicKey)));

key return recoveredAddress == publicKeyAddress; } }

The verify function takes the hash of the message that was signed, and the signature components v, r, and s. The ecrecover function is used to recover the Ethereum address associated with the public key that was used to sign the data. Then, the function compares this recovered address with the one derived from the provided public key.

Please note that this example assumes that the provided public key is indeed related to an Ethereum address.

Offchain code to sign the data:

async function signData() {
  const accounts = await web3.eth.getAccounts();
  const account = accounts[0];

const data = 'your data';

// Hash the data const dataHash = web3.utils.keccak256(data);

web3.eth.personal.sign(dataHash, account, (error, signature) => { if (error) { console.error('Error signing data:', error); } else { console.log('Signature:', signature);

  const r = signature.slice(0, 66);
  const s = '0x' + signature.slice(66, 130);
  const v = '0x' + signature.slice(130, 132);
  const v_decimal = web3.utils.toDecimal(v);

  console.log('v:', v_decimal);
  console.log('r:', r);
  console.log('s:', s);
}

}); }

If you are looking for typed data signature verification, you can refer to my this answer Verifying signed typed message hash on-chain.

Please accept and upvote if it helps

Naveed Ali
  • 604
  • 1
  • 10
  • The formula to calculate the address from the public key is wrong publicKeyAddress = address(uint160(uint256(publicKey))). See the correct formula in this answer https://ethereum.stackexchange.com/a/29480. – Ismael Apr 18 '23 at 00:22
0

When you need to verify public key, just use

address addrfrompub = address(bytes20(keccak256(pubkeyPart1, pubkeyPart2) << 96)));

address addrrecovered = ecrecover(hash, v, r, s);

Then compare them:

require(addrfrompub == addrrecovered);

Hope it helps.

Roman Frolov
  • 3,177
  • 2
  • 11
  • 29
  • thank u for your answer. but what I need is to verify a signature that it is generated outside the ethereum context using a private key. in other words I want to create a smart contract that will be able to verify old signatures made outside the blockchain, and the public key isn't related to any ethereum address – maroodb Apr 12 '18 at 15:48