Skip to content

Commit e7dc0b2

Browse files
committed
Add back simulation
1 parent 904e16e commit e7dc0b2

File tree

1 file changed

+178
-0
lines changed

1 file changed

+178
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -1 +1,179 @@
1+
#include <bits/stdc++.h>
2+
using namespace std;
13

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

Comments
 (0)