Signing content and providing the content and signature to a Contract allows on-chain validation that a signer has access to the private key of a specific address.
The ecrecover algorithm allows the public key to be determined given some message digest and the signature generated by the private key for that digest. From the public key, the address can then be computed.
How a digest is derived depends on the type of data being signed and a variety of encoding formats are employed. Each format is designed to ensure that they do not collide, so for example, a user cannot be tricked into signing a message which is actually a valid transaction.
For this reason, most APIs in Ethereum do not permit signing a raw digest, and instead require a separate API for each format type and require the related data be specified, protecting the user from accidentally authorizing an action they didn't intend.
A signed message can be any data, but it is generally recommended to use human-readable text, as this is easier for a user to verify visually.
This technique could be used, for example, to sign into a service by using the text "I am signing into ethers.org on 2023-06-04 12:57pm". The user can then see the message in MetaMask or on a Ledger Hardware Wallet and accept that they wish to sign the message which the site can then authenticate them with. By providing a timestamp the site can ensure that an older signed message cannot be used again in the future.
The format that is signed uses EIP-191 with the personal sign version code (0x45, or "E").
For those interested in the choice of this prefix, signed messages began as a Bitcoin feature, which used "\x18Bitcoin Signed Message:\n", which was a Bitcoin var-int length-prefixed string (as 0x18 is 24, the length of "Bitcoin Signed Message:\n".). When Ethereum adopted the similar feature, the relevant string was "\x19Ethereum Signed Message:\n".
In one of the most brilliant instances of technical retcon-ing, since 0x19 is invalid as the first byte of a transaction (in Recursive-Length Prefix it indicates a single byte of value 25), the initial byte \x19 has now been adopted as a prefix for some sort of signed data, where the second byte determines how to interpret that data. If the second byte is 69 (the letter "E", as in "Ethereum Signed Message:\n"), then the format is a the above prefixed message format.
So, all existing messages, tools and instances using the signed message format were already EIP-191 compliant, long before the standard existed or was even conceived and allowed for an extensible format for future formats (of which there now a few).
Anyways, the necessary JavaScript and Solidity are provided below.
The Solidity Contract has been deployed and verified on the Sepolia testnet at the address 0xf554DA5e35b2e40C09DDB481545A395da1736513.
It provides a variety of examples using various Signature encodings and formats, to recover the address for an EIP-191 signed message.