Skip to content

Instantly share code, notes, and snippets.

@MurageKibicho
Created July 25, 2025 11:46
Show Gist options
  • Save MurageKibicho/076d5096d20a1f9f9f743a8e554664e2 to your computer and use it in GitHub Desktop.
Save MurageKibicho/076d5096d20a1f9f9f743a8e554664e2 to your computer and use it in GitHub Desktop.
Hacking a dormant bitcoin wallet involves finding the wallet’s private key. Owning a bitcoin is equivalent to knowing a wallet’s private key. The process can be summarized as: A private key generates a public key. The public key is hashed by SHA256 + RIPEMD. The hash is encoded in Base58. The encoded Base58 string is the wallet address. We wrote…
//Complete guide : https://leetarxiv.substack.com/p/hacking-dormant-bitcoin-wallets-c
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <assert.h>
#include <secp256k1.h>
#include <openssl/sha.h>
#include <openssl/ripemd.h>
//Run: clear && gcc PrivateKey.c -lsecp256k1 -lcrypto -o m.o && ./m.o
const char *BASE58_ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
void EncodeInBase58(size_t inputLength, uint8_t *input, size_t outputLength, char *output)
{
uint8_t temp[32] = {0};memcpy(temp, input, inputLength);
uint8_t result[64] = {0};int resultLength = 0;
for(size_t i = 0; i < inputLength; i++)
{
int carry = temp[i];
for(int j = 0; j < resultLength || carry; j++)
{
if(j == resultLength) resultLength++;
carry += 256 * result[j];
result[j] = carry % 58;
carry /= 58;
}
}
int leading_zeros = 0;
for(size_t i = 0; i < inputLength && input[i] == 0; i++) {output[leading_zeros++] = '1';}
for(int i = resultLength - 1; i >= 0; i--) {output[leading_zeros++] = BASE58_ALPHABET[result[i]];}
output[leading_zeros] = '\0';
}
void PrintHexadecimalString(size_t stringLength, uint8_t *string)
{
for(size_t i = 0; i < stringLength; i++)
{
printf("%02X", string[i]);
}
printf("\n");
}
//Assumes publicKeyString is 33 bytes
//Assumes generatedAddress is 64 bytes
void PublicKeyToBitcoinWalletAddress(uint8_t *publicKeyString, char *generatedAddress)
{
uint8_t sha256Hash[32];
SHA256(publicKeyString, 33, sha256Hash);
uint8_t ripemd160Hash[20];
RIPEMD160(sha256Hash, 32, ripemd160Hash);
uint8_t versionedPayload[21];
versionedPayload[0] = 0x00; // version byte for mainnet
memcpy(versionedPayload + 1, ripemd160Hash, 20);
uint8_t checksumInput[25];
memcpy(checksumInput, versionedPayload, 21);
uint8_t hash1[32], hash2[32];
SHA256(checksumInput, 21, hash1);
SHA256(hash1, 32, hash2);
memcpy(checksumInput + 21, hash2, 4);
EncodeInBase58(25, checksumInput, 64, generatedAddress);
}
int main()
{
//Initialize secpContext
secp256k1_context *secpContext = secp256k1_context_create(SECP256K1_CONTEXT_SIGN);
//Set upper bound and target wallet address
uint32_t upperBound = 7;
char *walletAddress = "19ZewH8Kk1PDbSNdJ97FP4EiCjTRaZMZQA";
printf("%s\n", walletAddress);
//Test different private keys
for(uint8_t privateKey = 1; privateKey <= upperBound; privateKey++)
{
uint8_t privateKeyString[32] = {0};
privateKeyString[31] = privateKey;
assert(secp256k1_ec_seckey_verify(secpContext, privateKeyString) != 0);
printf("\nPrivate Key:\n");PrintHexadecimalString(32, privateKeyString);
//Generate public key
secp256k1_pubkey publicKey;
size_t publicKeyLength = 33;
uint8_t publicKeyString[33];
assert(secp256k1_ec_pubkey_create(secpContext, &publicKey, privateKeyString) != 0);
secp256k1_ec_pubkey_serialize(secpContext, publicKeyString, &publicKeyLength, &publicKey, SECP256K1_EC_COMPRESSED);
printf("Public Key:\n");PrintHexadecimalString(33, publicKeyString);
//Generate wallet address
char generatedAddress[64];
PublicKeyToBitcoinWalletAddress(publicKeyString, generatedAddress);
printf("Generated Address:%s\n",generatedAddress);
if(strcmp(generatedAddress, walletAddress) == 0)
{
printf("**MATCH FOUND: Private Key = %u\n", privateKey);
break;
}
}
//Destroy secpContext
secp256k1_context_destroy(secpContext);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment