1

I have a question regarding use of keys in Ethereum for signing requests/data OUTSIDE of Ethereum.

Let's say I have a regular Ethereum EOA with an address and keypair. I now want to have a piece of information transferred to a third party (off-chain) and allow this third party to verify that this information came from me, i.e. the owner of the EOA in question. Approach: digitally sign the information with my private key associated with my EOA.

Now the question is, how the third party is verifying the signature. What he has is the signature, the data, and (lets assume we specified this) the address of my EOA.

For allowing him to verify the signature, he will need the public key of my EOA. To get this to him, I see two options:

  1. GIVE him the public key directly, e.g. by using a ERC1056 registry where I store the public key for each address. Now, I'd be required to verify on-chain (i.e. in Solidity) that the public key set as an attribute is matching the address (i.e. that the first 20 bytes of the hash of the public key are the same). Seems pretty cost-intensive Gas-wise to me. Anyhow First question: How to compute the address from a public key (string) in Solidity for such a check?
  2. Derive the public key off-chain (on the receiver's side) from the signature. I read this would be possible, I'm just unsure how exactly to do this. The recipient would then compute the public key, verify the signature, and verify that the signature was actually created by the EOA (address) it claims to be from. Hence, my second question: How to do this in Java? Is there a lib for that?

Is there a third, even better option?

2 Answers 2

2

First, it's not possible to derive the public key from just an address. The address is a part of the Keccak256 hash of the public key, and hash functions are one way functions. You can calculate an address from a public key by taking the last 20 bytes of the keccak256 hash (or the last 40 characters).

However, you don't need the public key to verify a signature. Assuming you are using ECDSA signatures (standard in Ethereum), you can recover the public key from a signature and message. If you sign a message using MyCrypto for example, the "signed message" looks like this:

{
  "address": "0xa6ad0945cd3c5539d92d49b140842a0673e17041",
  "msg": "Hello, world!",
  "sig": "0x1e15325a942ae03788b63902ccc4703a65993dc9c692cf14d2bf16d62407da6824f045ebbbc0eb8423934a87c95872703fcec742ea03ded4d88aa5e219d9494c1c",
  "version": "2"
}

Then you can calculate the public key using ECDSA's recovery function (ecrecover in Solidity), by calculating the public key of the message and signature, hashing the public key using Keccak256, and taking the last 20 bytes to get the address. The signature is valid if the recovered address matches with the one provided in the signed message.

You should include some specific information in the message (e.g., "message signed by person on date"), to guarantee that the message was actually signed by the person who claimed to sign it (and to prevent possible replay attacks).

Using Java, you can use web3j's Sign.recoverFromSignature. Unfortunately it seems like this is not documentated, but the source code should get you started.

I wrote an in-depth article about ECDSA signatures on Ethereum which you can find here, if you are interested.

1

This library helps you to recover public key from ECDSA signed message https://github.com/0xcyphered/secp256k1-solidity

Example:

//SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.0;
import "@0xcyphered/secp256k1-solidity/contracts/SECP256K1.sol";
contract Example {
    function recoverPersonalSignPublicKey(
        bytes32 message,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) public pure returns (bytes memory) {
        string memory header = '\x19Ethereum Signed Message:\n32';
        bytes32 _message = keccak256(abi.encodePacked(header, message));
        (uint256 x, uint256 y) = SECP256K1.recover(uint256(_message), v - 27, uint256(r), uint256(s));
        return abi.encodePacked(x, y);
    }
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.