The previous article introduced the usage of ecrecover, but the built-in ecrecover has a signature malleability problem. This article will explain this problem and how to solve it.
Problem
Examples from the previous article:
1 2 3 4 5 6 7
functiontest() externalviewreturns(address) { bytes32 hash =0xc1af4b94166cd32fc49b7b926cbb91ee421de2d04450e8ae57857b9b56ac7e53; uint8 v =0x1b; bytes32 r =0xe1077fb9321c187d8a43926896abac5455ce6add269e098f855ff059d6b846a3; bytes32 s =0x56320be5f6d79c4d0e5583d6b9a2e50fae78f1fb5ff0553541e69c66dae2b2f8; returnecrecover(hash , v, r, s); }
The signer’s wallet address is 0xDD980c315dFA75682F04381E98ea38BD2A151540. We made the following changes to the signature:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
functiontest() externalviewreturns(address) { bytes32 hash =0xc1af4b94166cd32fc49b7b926cbb91ee421de2d04450e8ae57857b9b56ac7e53; uint8 v =0x1b; bytes32 r =0xe1077fb9321c187d8a43926896abac5455ce6add269e098f855ff059d6b846a3; bytes32 s =0x56320be5f6d79c4d0e5583d6b9a2e50fae78f1fb5ff0553541e69c66dae2b2f8;
// tamper with // v: 0x1c // s: 0xa9cdf41a092863b2f1aa7c29465d1aef0c35eaeb4f584b067debc225f5538e49 v = v ==0x1b ? 0x1c : 0x1b; s =bytes32(uint(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141) -uint(s));
returnecrecover(hash , v, r, s); }
You will find that it return the same signer, and the signature may be reused. For example, modify the example of the previous article and use s as the test to see whether the signature has been used: