1
+ #include < bits/stdc++.h>
2
+ using namespace std ;
1
3
4
+ class Keccak256 final {
5
+ public: static constexpr int HASH_LEN = 32 ;
6
+ private: static constexpr int BLOCK_SIZE = 200 - HASH_LEN * 2 ;
7
+ private: static constexpr int NUM_ROUNDS = 24 ;
8
+ public: static void getHash (const std::uint8_t msg[], std::size_t len, std::uint8_t hashResult[HASH_LEN]);
9
+ private: static void absorb (std::uint64_t state[5 ][5 ]);
10
+ // Requires 0 <= i <= 63
11
+ private: static std::uint64_t rotl64 (std::uint64_t x, int i);
12
+ Keccak256 () = delete ; // Not instantiable
13
+ private: static const unsigned char ROTATION[5 ][5 ];
14
+
15
+ };
16
+
17
+ void Keccak256::getHash (const uint8_t msg[], size_t len, uint8_t hashResult[HASH_LEN]) {
18
+ assert ((msg != nullptr || len == 0 ) && hashResult != nullptr );
19
+ uint64_t state[5 ][5 ] = {};
20
+
21
+ // XOR each message byte into the state, and absorb full blocks
22
+ int blockOff = 0 ;
23
+ for (size_t i = 0 ; i < len; i++) {
24
+ int j = blockOff >> 3 ;
25
+ state[j % 5 ][j / 5 ] ^= static_cast <uint64_t >(msg[i]) << ((blockOff & 7 ) << 3 );
26
+ blockOff++;
27
+ if (blockOff == BLOCK_SIZE) {
28
+ absorb (state);
29
+ blockOff = 0 ;
30
+ }
31
+ }
32
+
33
+ // Final block and padding
34
+ {
35
+ int i = blockOff >> 3 ;
36
+ state[i % 5 ][i / 5 ] ^= UINT64_C (0x01 ) << ((blockOff & 7 ) << 3 );
37
+ blockOff = BLOCK_SIZE - 1 ;
38
+ int j = blockOff >> 3 ;
39
+ state[j % 5 ][j / 5 ] ^= UINT64_C (0x80 ) << ((blockOff & 7 ) << 3 );
40
+ absorb (state);
41
+ }
42
+
43
+ // Uint64 array to bytes in little endian
44
+ for (int i = 0 ; i < HASH_LEN; i++) {
45
+ int j = i >> 3 ;
46
+ hashResult[i] = static_cast <uint8_t >(state[j % 5 ][j / 5 ] >> ((i & 7 ) << 3 ));
47
+ }
48
+ }
49
+
50
+ void Keccak256::absorb (uint64_t state[5 ][5 ]) {
51
+ uint64_t (*a)[5 ] = state;
52
+ uint8_t r = 1 ; // LFSR
53
+ for (int i = 0 ; i < NUM_ROUNDS; i++) {
54
+ // Theta step
55
+ uint64_t c[5 ] = {};
56
+ for (int x = 0 ; x < 5 ; x++) {
57
+ for (int y = 0 ; y < 5 ; y++)
58
+ c[x] ^= a[x][y];
59
+ }
60
+ for (int x = 0 ; x < 5 ; x++) {
61
+ uint64_t d = c[(x + 4 ) % 5 ] ^ rotl64 (c[(x + 1 ) % 5 ], 1 );
62
+ for (int y = 0 ; y < 5 ; y++)
63
+ a[x][y] ^= d;
64
+ }
65
+
66
+ // Rho and pi steps
67
+ uint64_t b[5 ][5 ];
68
+ for (int x = 0 ; x < 5 ; x++) {
69
+ for (int y = 0 ; y < 5 ; y++)
70
+ b[y][(x * 2 + y * 3 ) % 5 ] = rotl64 (a[x][y], ROTATION[x][y]);
71
+ }
72
+
73
+ // Chi step
74
+ for (int x = 0 ; x < 5 ; x++) {
75
+ for (int y = 0 ; y < 5 ; y++)
76
+ a[x][y] = b[x][y] ^ (~b[(x + 1 ) % 5 ][y] & b[(x + 2 ) % 5 ][y]);
77
+ }
78
+
79
+ // Iota step
80
+ for (int j = 0 ; j < 7 ; j++) {
81
+ a[0 ][0 ] ^= static_cast <uint64_t >(r & 1 ) << ((1 << j) - 1 );
82
+ r = static_cast <uint8_t >((r << 1 ) ^ ((r >> 7 ) * 0x171 ));
83
+ }
84
+ }
85
+ }
86
+
87
+ uint64_t Keccak256::rotl64 (uint64_t x, int i) {
88
+ return ((0U + x) << i) | (x >> ((64 - i) & 63 ));
89
+ }
90
+
91
+ // Static initializers
92
+ const unsigned char Keccak256::ROTATION[5 ][5 ] = {
93
+ { 0 , 36 , 3 , 41 , 18 },
94
+ { 1 , 44 , 10 , 45 , 2 },
95
+ {62 , 6 , 43 , 15 , 61 },
96
+ {28 , 55 , 25 , 21 , 56 },
97
+ {27 , 20 , 39 , 8 , 14 },
98
+ };
99
+
100
+ /*
101
+ function getAddress(bytes memory bytecode, uint256 _salt) public view returns (address) {
102
+ bytes32 hash = keccak256(
103
+ abi.encodePacked(bytes1(0xff), address(this), _salt, keccak256(bytecode)));
104
+ return address(uint160(uint(hash)));
105
+ }
106
+ */
107
+ vector<std::uint8_t > getAddress (string bytecodeStr, string thisAddress, std::uint32_t salt) {
108
+ // calculate keccak256(bytecode)
109
+ std::uint8_t bytecode[6 ] = {0 };
110
+ for (int i = 0 ; i < 6 ; i++) {
111
+ string hexStr = bytecodeStr.substr (2 *i+2 , 2 );
112
+ bytecode[i] = (uint8_t )stoi (hexStr, nullptr , 16 );
113
+ }
114
+ std::uint8_t hashResult[32 ];
115
+ Keccak256::getHash (bytecode, 6 , hashResult);
116
+
117
+ std::uint8_t thisAddressBytes[20 ] = {0 };
118
+ for (int i = 0 ; i < 20 ; i++) {
119
+ string hexStr = thisAddress.substr (2 *i+2 , 2 );
120
+ thisAddressBytes[i] = (uint8_t )stoi (hexStr, nullptr , 16 );
121
+ }
122
+
123
+ std::uint8_t msg[1 +20 +32 +32 ] = {0 };
124
+ msg[0 ] = 0xff ;
125
+ for (int i = 0 ; i < 20 ; i++) {
126
+ msg[i+1 ] = thisAddressBytes[i];
127
+ }
128
+
129
+ // salt last 4 bytes are filled, others are 0
130
+ msg[1 +20 +32 -4 ] = (uint8_t )(salt >> 24 );
131
+ msg[1 +20 +32 -3 ] = (uint8_t )(salt >> 16 );
132
+ msg[1 +20 +32 -2 ] = (uint8_t )(salt >> 8 );
133
+ msg[1 +20 +32 -1 ] = (uint8_t )(salt);
134
+
135
+ for (int i = 0 ; i < 32 ; i++) {
136
+ msg[1 +20 +32 +i] = hashResult[i];
137
+ }
138
+
139
+ uint8_t finalHash[32 ] = {0 };
140
+ Keccak256::getHash (msg, 1 +20 +32 +32 , finalHash);
141
+ vector<std::uint8_t > result;
142
+ // last 20 bytes
143
+ for (int i = 12 ; i < 32 ; i++) {
144
+ result.push_back (finalHash[i]);
145
+ }
146
+ return result;
147
+ }
148
+
149
+ int main (int argc, char **argv) {
150
+ /*
151
+ Sanity check:
152
+ address(this): 0x44338f8D58F86cdcB26Ee00BF587Ad6ca4a10659
153
+ _salt: 0
154
+ bytecode: 0x3859818153F3
155
+ msg.sender: 0x56c6c9954fb166ff6d485f126ed31346c418d4db
156
+ final hash: 0x11a692fd4eac1948abc70e1964177165a8dd968c79747848baf1857c89256c3b
157
+ */
158
+ string bytecodeStr = argv[1 ];
159
+ string thisAddress = argv[2 ];
160
+
161
+ for (std::uint32_t salt = 0 ; salt < 4 *1e6 ; salt++) {
162
+ // keccak256(abi.encodePacked(msg.sender, proof.a))
163
+ auto res = getAddress (bytecodeStr, thisAddress, salt);
164
+ std::uint8_t msg[20 +32 ] = {0 };
165
+ for (int i = 0 ; i < 20 ; i++) {
166
+ msg[i] = res[i];
167
+ }
168
+ uint8_t hashResult[32 ] = {0 };
169
+ Keccak256::getHash (msg, 20 +32 , hashResult);
170
+ string result = " 0x" ;
171
+ for (int i = 0 ; i < 32 ; i++) {
172
+ char buf[3 ];
173
+ sprintf (buf, " %02x" , hashResult[i]);
174
+ result += buf;
175
+ }
176
+ cout << result << " ," ;
177
+ }
178
+ return 0 ;
179
+ }
0 commit comments