With signatures in Ethereum, there may be an issue if a valid signature might be used several times in other places where it’s not intended to be used.
This types of security issues are called Replay Attacks. ⏮🤺
More about them 👇
Imagine a scenario where we have a function that transfers funds, but only when a valid signature is provided.
At first glance, the code looks good.
But the devil is in the details 😈
So, what happens in the code?
We check the address of the ECDSA signature by providing `v,r,s` values.
We compare the returned address with the owner address, and if it’s an owner, we proceed with the transfer of funds.
What are we missing? 🤔
The problem is in the signed message.
The message only contains the receiver address and the amount to be unlocked.
There is nothing in the message that could prevent the same signatures from being used multiple times.😨
How can we prevent that?
To prevent the signature replay attack, we can store the signature we used in the `executed` mapping.
This way, whenever someone would want to replay our signature, it would fail, as we can check if this signature was already used by simply checking the mapping.
Code below:
There are still issues with the code above ☝️
It does not follow the recommended best practice for signature verification, especially the `S` value.
This can lead to signature malleability.
What does that mean?
Within Solidity, an ECDSA signature is represented by its *r, s* and *v* values.
The relationship between the public key, the message hash, *r*, *s*, and *v* can be checked to ensure that only the person who knows the corresponding *private* key calculates *r*, *s*, and *v*...
...However, due to the symmetric structure of elliptic curves, for every set of *r*, *s*, and *v*, there is another set of *r*, *s*, and *v* that *also* has the same precise mathematical relationship.
This results in TWO valid signatures 🤯
Fortunately, it’s easy to detect the duplicate signature 😎
Not going much into mathematical details, we need to choose the proper "half" of the eliptic curve.
Value of *s* is the one that helps us determine which half we need.
As seen below, an Elliptic Curve is symmetric on the X-axis, meaning two points can exist with the same X value.
We can carefully adjust *s* to produce a valid signature for the same *r* on the other side of the X-axis.
The meaning behind all of this is we can invert one valid signature to get another valid signature which will still be valid and basically replay a signature!
There is a way to prevent that, and the first major hard-fork of Ethereum introduced a solution to this:
EIP-2
EIP-2 introduced limits on the *s* values to prevent signature malleability by only considering lower levels of *s* as valid.
By restricting valid range, EIP-2 effectively removes half the points from the group, ensuring there is at most one valid point at each **x** coordinate.
EIP-2 was introduced into EVM, it didn’t affect the precompiled contract `ecrecover`
So, whenever we’re using plain `ecrecover`, we’re still prone to signature malleability!
Don’t worry, because OpenZeppelin created an appropriate library ECDSA.sol that solves this issue.
The trick is simple: we restrict the s value to be in the lower-end.
Another way to combat signature malleability *and* replay is the usage of an application-level nonce.
“Nonce” is cryptographer short-hand for “number used once”.
We can use a nonce for every signature and store the next nonce inside the contract.
This covers the most *common* issues with signatures.
We still need to cover EIP-712 but that's in another 🧶
And if you prefer reading a blog post instead of a 🧵, check out awesome article at our Medium:
This is part 1 out of a 2 part thread series dedicated to Signatures in Ethereum.
It was inevitable that sooner or later, we would need to talk about this.
But bear with us, as we're going to make this as digestible as possible!
First stop, Public Key Cryptography 🔐👩🏫
👇
There are two main purposes of cryptography
- prove knowledge of a secret without revealing the secret
- prove authenticity of data (digital signature)
Cryptography is used extensively within Ethereum, and one place that users meet with cryptography is via Ethereum accounts.👩💻
Proof of ownership of Externally Owned Accounts (EOAs) is established through private keys and digital signatures.
The private keys are used almost everywhere within Ethereum during user interactions, and the Ethereum address of an EOA is derived from the private key.