1+ // SPDX-License-Identifier: UNLICENSED
2+ pragma solidity >= 0.6.0 < 0.8.12 ;
3+
4+ contract ECRecoverSMTest {
5+ event Address (address addr );
6+
7+ function genValidParams () private pure returns (bytes memory ){
8+ bytes memory data = abi.encode (
9+ bytes32 (0xaa0f7414b7f8648410f9818df3a1f43419d5c30313f430712033937ae57854c8 ),
10+ uint8 (28 ),
11+ bytes32 (0xacd0d6c91242e514655815073f5f0e9aed671f68a4ed3e3e9d693095779f704b ),
12+ bytes32 (0x01932751f4431c3b4c9d6fb1c826d138ee155ea72ac9013d66929f6a265386b4 ));
13+
14+ return data;
15+ }
16+
17+ function genInvalidParams () private pure returns (bytes memory ){
18+ bytes memory data = abi.encodeWithSignature ("ecrecover(bytes32,uint8,bytes32,bytes32) " ,
19+ bytes32 (0xaa0f7414b7f8648410f9818df3a1f43419d5c30313f430712033937ae57854c8 ),
20+ uint8 (28 ),
21+ bytes32 (0xacd0d6c91242e514655815073f5f0e9aed671f68a4ed3e3e9d693095779f704b ),
22+ bytes32 (0x01932751f4431c3b4c9d6fb1c826d138ee155ea72ac9013d66929f6a265386b5 ));
23+
24+ return data;
25+ }
26+
27+ function genLargerInvalidParams (uint addNum ) private pure returns (bytes memory ){
28+ // append genValidParams() addNum byte
29+ bytes memory addBytes = new bytes (addNum);
30+ bytes memory data = abi.encodePacked (genValidParams (), addBytes);
31+ require (genValidParams ().length + addNum == data.length , "genLargerInvalidParams failed " );
32+
33+ return data;
34+ }
35+
36+ function genShorterInvalidParams (uint cutNum ) private pure returns (bytes memory ){
37+ // remove genValidParams() cutNum byte
38+ bytes memory validParams = genValidParams ();
39+ require (validParams.length >= cutNum, "genShorterInvalidParams failed " );
40+ bytes memory data = new bytes (validParams.length - cutNum);
41+ for (uint i = 0 ; i < validParams.length - cutNum; i++ ){
42+ data[i] = validParams[i];
43+ }
44+
45+ require (genValidParams ().length - cutNum == data.length , "genShorterInvalidParams failed " );
46+ return data;
47+ }
48+
49+ function callECRecover (bytes memory params ) public returns (address ){
50+ // 调用预编译合约的ECRecover函数
51+ address precompiledContract = address (0x1 );
52+ (bool success , bytes memory result ) = precompiledContract.call (params);
53+ require (success, "Call to precompiled contract failed " );
54+
55+ if (result.length == 0 ) {
56+ return address (0 );
57+ }
58+
59+ address addr;
60+ assembly {
61+ addr := mload (add (result, 32 ))
62+ }
63+
64+ return addr;
65+ }
66+
67+ function callECRecoverValid () public returns (address ){
68+ bytes memory params = genValidParams ();
69+ return callECRecover (params);
70+ }
71+
72+ function callECRecoverInvalid () public returns (address ){
73+ bytes memory params = genInvalidParams ();
74+ return callECRecover (params); // must return 0x0000000000000000000000000000000000000084
75+ }
76+
77+ function callECRecoverDirect () public pure returns (address ){
78+ bytes32 hash = bytes32 (0xaa0f7414b7f8648410f9818df3a1f43419d5c30313f430712033937ae57854c8 );
79+ uint8 v = uint8 (28 );
80+ bytes32 r = bytes32 (0xacd0d6c91242e514655815073f5f0e9aed671f68a4ed3e3e9d693095779f704b );
81+ bytes32 s = bytes32 (0x01932751f4431c3b4c9d6fb1c826d138ee155ea72ac9013d66929f6a265386b4 );
82+
83+ address addr = ecrecover (hash, v, r, s);
84+ require (addr == address (0x6DA0599583855f1618b380f6782c0c5c25cB96Ec ), "ecrecover failed " );
85+ return addr;
86+ }
87+
88+ function testRecoverEmptyParams () public {
89+ bytes memory data = abi.encode ();
90+ address addr = callECRecover (data);
91+ require (addr == address (0x0 ), "should recover failed " );
92+ }
93+
94+ function testRecoverVRange () public {
95+ uint8 [9 ] memory vs = [uint8 (0 ), uint8 (1 ), uint8 (2 ), uint8 (10 ), uint8 (27 ), uint8 (28 ), uint8 (100 ), uint8 (200 ), uint8 (255 )];
96+
97+ for (uint i = 0 ; i < vs.length ; i++ ){
98+ uint8 v = vs[i];
99+ bytes memory data = abi.encode (
100+ bytes32 (0xaa0f7414b7f8648410f9818df3a1f43419d5c30313f430712033937ae57854c8 ),
101+ v,
102+ bytes32 (0xacd0d6c91242e514655815073f5f0e9aed671f68a4ed3e3e9d693095779f704b ),
103+ bytes32 (0x01932751f4431c3b4c9d6fb1c826d138ee155ea72ac9013d66929f6a265386b4 ));
104+
105+ address addr = callECRecover (data);
106+ // only v = 27 or 28 is valid
107+ if (v == 27 ){
108+ require (addr == address (0xA5B4792Dcad4FE78D13f6aBD7bA1f302945De4F7 ), "ecrecover failed " );
109+ } else if (v == 28 ){
110+ require (addr == address (0x6DA0599583855f1618b380f6782c0c5c25cB96Ec ), "ecrecover failed " );
111+ } else {
112+ require (addr == address (0x0 ), "should recover failed " );
113+ }
114+ }
115+ }
116+
117+ function testRecoverLargerParams () public {
118+ uint [10 ] memory addNums = [uint (1 ), uint (5 ), uint (32 ), uint (33 ), uint (64 ), uint (65 ), uint (256 ), uint (257 ), uint (512 ), uint (513 )];
119+
120+ for (uint i = 0 ; i < addNums.length ; i++ ){
121+ uint addNum = addNums[i];
122+ bytes memory data = genLargerInvalidParams (addNum);
123+ address addr = callECRecover (data);
124+ require (addr == address (0x6DA0599583855f1618b380f6782c0c5c25cB96Ec ), "added bytes should be ignored " );
125+ }
126+ }
127+
128+ function testRecoverShorterParams () public {
129+ uint [11 ] memory cutNums = [uint (1 ), uint (5 ), uint (10 ), uint (18 ), uint (27 ), uint (31 ), uint (32 ), uint (33 ), uint (63 ), uint (64 ), uint (65 )];
130+
131+ for (uint i = 0 ; i < cutNums.length ; i++ ){
132+ uint cutNum = cutNums[i];
133+ bytes memory data = genShorterInvalidParams (cutNum);
134+ address addr = callECRecover (data);
135+ // should failed when cutNum >= 32
136+
137+ if (cutNum == 1 ) {
138+ require (addr == address (0x509EAd8b20064F21e35f920cb0c6d6cbC0c0AA0D ), "should success when cutNum == 1 " );
139+ } else if (cutNum == 5 ) {
140+ require (addr == address (0x571A110cE923c9354B11B247f087b6DAB1AD9089 ), "should success when cutNum == 5 " );
141+ } else if (cutNum == 10 ) {
142+ require (addr == address (0xFaCF3c4d9C0197bF621c39D461970E7a5D2F6947 ), "should success when cutNum == 10 " );
143+ } else if (cutNum == 18 ) {
144+ require (addr == address (0xCc63021A8a9E4c5C58F275C1DbA8536D398C46f5 ), "should success when cutNum == 18 " );
145+ } else if (cutNum == 27 ) {
146+ require (addr == address (0xc6a74652861114A92a30b8399e6eBe2e2e90313e ), "should success when cutNum == 27 " );
147+ } else if (cutNum == 31 ) {
148+ require (addr == address (0xC275cac475391eEEAdc7a4d0A09781177776D8b5 ), "should success when cutNum == 31 " );
149+ } else {
150+ require (addr == address (0x0 ), "should failed when cutNum >= 32 " );
151+ }
152+
153+ }
154+ }
155+
156+ function testRecoverBasic () public {
157+ require (callECRecoverValid () == address (0x6DA0599583855f1618b380f6782c0c5c25cB96Ec ), "callECRecoverValid failed " );
158+ require (callECRecoverDirect () == address (0x6DA0599583855f1618b380f6782c0c5c25cB96Ec ), "callECRecoverDirect failed " );
159+ }
160+
161+ function testEmitEvent () public {
162+ emit Address (address (0x6DA0599583855f1618b380f6782c0c5c25cB96Ec ));
163+ callECRecoverDirect ();
164+ }
165+
166+ function compareAddressAndString (address _address , string memory _string ) public pure returns (bool ) {
167+ bytes32 addressHash = keccak256 (abi.encodePacked (_address));
168+ bytes32 stringHash = keccak256 (bytes (_string));
169+
170+ return (addressHash == stringHash);
171+ }
172+
173+ function check () public {
174+ testRecoverBasic ();
175+ testRecoverEmptyParams ();
176+ testRecoverVRange ();
177+ testRecoverLargerParams ();
178+ testRecoverShorterParams ();
179+ }
180+ }
0 commit comments