#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#include <inttypes.h>
#include <ctype.h>
#include <string.h>
#include <time.h>
#include <openssl/sha.h>
const uint64_t COIN = 100000000;
const uint64_t CENT = 1000000;
uint32_t OP_CHECKSIG = 172;
bool generateBlock = false;
uint32_t startNonce = 0;
uint32_t unixtime = 0;
typedef struct {
uint8_t merkleHash[32];
uint8_t *serializedData;
uint32_t version;
uint8_t numInputs;
uint8_t prevOutput[32];
uint32_t prevoutIndex;
uint8_t *scriptSig;
uint32_t sequence;
uint8_t numOutputs;
uint64_t outValue;
uint8_t *pubkeyScript;
uint32_t locktime;
} Transaction;
void byteswap(uint8_t *buf, int length)
{
int i;
uint8_t temp;
for (i = 0; i < length / 2; i++)
{
temp = buf[i];
buf[i] = buf[length - i - 1];
buf[length - i - 1] = temp;
}
}
char *bin2hex(const unsigned char *p, size_t len)
{
char *s = (char*)malloc((len * 2) + 1);
unsigned int i;
if (!s)
return NULL;
for (i = 0; i < len; i++)
sprintf_s(s + (i * 2), 3, "%02x", (unsigned int)p[i]);
return s;
}
size_t hex2bin(unsigned char *p, const char *hexstr, size_t len)
{
int ret = 0;
size_t retlen = len;
while (*hexstr && len) {
char hex_byte[4];
unsigned int v;
if (!hexstr[1]) {
return ret;
}
memset(hex_byte, 0, 4);
hex_byte[0] = hexstr[0];
hex_byte[1] = hexstr[1];
if (sscanf_s(hex_byte, "%x", &v) != 1) {
return ret;
}
*p = (unsigned char)v;
p++;
hexstr += 2;
len--;
}
if (len == 0 && *hexstr == 0)
ret = retlen;
return ret;
}
Transaction *InitTransaction()
{
Transaction *transaction;
transaction = (Transaction *)calloc(1, sizeof(*transaction));
if (!transaction)
{
return NULL;
}
transaction->version = 1;
transaction->numInputs = 1;
transaction->numOutputs = 1;
transaction->locktime = 0;
transaction->prevoutIndex = 0xFFFFFFFF;
transaction->sequence = 0xFFFFFFFF;
transaction->outValue = 50 * COIN;
memset(transaction->prevOutput, 0, 32);
return transaction;
}
int main(int argc, char *argv[])
{
Transaction *transaction;
unsigned char hash1[32], hash2[32];
char timestamp[255], pubkey[132];
uint32_t timestamp_len = 0, scriptSig_len = 0, pubkey_len = 0, pubkeyScript_len = 0;
uint32_t nBits = 0;
if ((argc - 1) < 3)
{
fprintf(stderr, "Usage: genesisgen [options] <pubkey> \"<timestamp>\" <nBits>\n");
return 0;
}
pubkey_len = strlen(argv[1]) / 2;
timestamp_len = strlen(argv[2]);
if (pubkey_len != 65)
{
fprintf(stderr, "Invalid public key length! %s\n", argv[1]);
return 0;
}
if (timestamp_len > 254 || timestamp_len <= 0)
{
fprintf(stderr, "Size of timestamp is 0 or exceeds maximum length of 254 characters!\n");
return 0;
}
transaction = InitTransaction();
if (!transaction)
{
fprintf(stderr, "Could not allocate memory! Exiting...\n");
return 0;
}
strncpy_s(pubkey, argv[1], sizeof(pubkey));
strncpy_s(timestamp, argv[2], sizeof(timestamp));
sscanf_s(argv[3], "%lu", (long unsigned int *)&nBits);
pubkey_len = strlen(pubkey) >> 1;
scriptSig_len = timestamp_len;
transaction->pubkeyScript = (uint8_t*)malloc((pubkey_len + 2) * sizeof(uint8_t));
pubkeyScript_len = hex2bin(transaction->pubkeyScript + 1, pubkey, pubkey_len);
transaction->pubkeyScript[0] = 0x41;
pubkeyScript_len += 1;
transaction->pubkeyScript[pubkeyScript_len++] = OP_CHECKSIG;
transaction->scriptSig = (uint8_t*)malloc(scriptSig_len * sizeof(uint8_t));
uint32_t scriptSig_pos = 0;
if (nBits <= 255)
{
transaction->scriptSig[scriptSig_pos++] = 0x01;
transaction->scriptSig[scriptSig_pos++] = (uint8_t)nBits;
}
else if (nBits <= 65535)
{
transaction->scriptSig[scriptSig_pos++] = 0x02;
memcpy(transaction->scriptSig + scriptSig_pos, &nBits, 2);
scriptSig_pos += 2;
}
else if (nBits <= 16777215)
{
transaction->scriptSig[scriptSig_pos++] = 0x03;
memcpy(transaction->scriptSig + scriptSig_pos, &nBits, 3);
scriptSig_pos += 3;
}
else
{
transaction->scriptSig[scriptSig_pos++] = 0x04;
memcpy(transaction->scriptSig + scriptSig_pos, &nBits, 4);
scriptSig_pos += 4;
}
transaction->scriptSig[scriptSig_pos++] = 0x01;
transaction->scriptSig[scriptSig_pos++] = 0x04;
transaction->scriptSig[scriptSig_pos++] = (uint8_t)scriptSig_len;
scriptSig_len += scriptSig_pos;
transaction->scriptSig = (uint8_t*)realloc(transaction->scriptSig, scriptSig_len * sizeof(uint8_t));
memcpy(transaction->scriptSig + scriptSig_pos, (const unsigned char *)timestamp, timestamp_len);
uint32_t serializedLen =
4
+ 1
+ 32
+ 4
+ 1
+ scriptSig_len
+ 4
+ 1
+ 8
+ 1
+ pubkeyScript_len
+ 4;
uint32_t serializedData_pos = 0;
transaction->serializedData = (uint8_t*)malloc(serializedLen * sizeof(uint8_t));
memcpy(transaction->serializedData + serializedData_pos, &transaction->version, 4);
serializedData_pos += 4;
memcpy(transaction->serializedData + serializedData_pos, &transaction->numInputs, 1);
serializedData_pos += 1;
memcpy(transaction->serializedData + serializedData_pos, transaction->prevOutput, 32);
serializedData_pos += 32;
memcpy(transaction->serializedData + serializedData_pos, &transaction->prevoutIndex, 4);
serializedData_pos += 4;
memcpy(transaction->serializedData + serializedData_pos, &scriptSig_len, 1);
serializedData_pos += 1;
memcpy(transaction->serializedData + serializedData_pos, transaction->scriptSig, scriptSig_len);
serializedData_pos += scriptSig_len;
memcpy(transaction->serializedData + serializedData_pos, &transaction->sequence, 4);
serializedData_pos += 4;
memcpy(transaction->serializedData + serializedData_pos, &transaction->numOutputs, 1);
serializedData_pos += 1;
memcpy(transaction->serializedData + serializedData_pos, &transaction->outValue, 8);
serializedData_pos += 8;
memcpy(transaction->serializedData + serializedData_pos, &pubkeyScript_len, 1);
serializedData_pos += 1;
memcpy(transaction->serializedData + serializedData_pos, transaction->pubkeyScript, pubkeyScript_len);
serializedData_pos += pubkeyScript_len;
memcpy(transaction->serializedData + serializedData_pos, &transaction->locktime, 4);
serializedData_pos += 4;
SHA256(transaction->serializedData, serializedLen, hash1);
SHA256(hash1, 32, hash2);
memcpy(transaction->merkleHash, hash2, 32);
char *merkleHash = bin2hex(transaction->merkleHash, 32);
byteswap(transaction->merkleHash, 32);
char *merkleHashSwapped = bin2hex(transaction->merkleHash, 32);
char *txScriptSig = bin2hex(transaction->scriptSig, scriptSig_len);
char *pubScriptSig = bin2hex(transaction->pubkeyScript, pubkeyScript_len);
printf("\nCoinbase: %s\n\nPubkeyScript: %s\n\nMerkle Hash: %s\nByteswapped: %s\n", txScriptSig, pubScriptSig, merkleHash, merkleHashSwapped);
{
printf("Generating block...\n");
if (!unixtime)
{
unixtime = time(NULL);
}
unsigned char block_header[80], block_hash1[32], block_hash2[32];
uint32_t blockversion = 1;
memcpy(block_header, &blockversion, 4);
memset(block_header + 4, 0, 32);
byteswap(transaction->merkleHash, 32);
memcpy(block_header + 36, transaction->merkleHash, 32);
memcpy(block_header + 68, &unixtime, 4);
memcpy(block_header + 72, &nBits, 4);
memcpy(block_header + 76, &startNonce, 4);
uint32_t *pNonce = (uint32_t *)(block_header + 76);
uint32_t *pUnixtime = (uint32_t *)(block_header + 68);
unsigned int counter = 0, start = time(NULL);
while (1)
{
SHA256(block_header, 80, block_hash1);
SHA256(block_hash1, 32, block_hash2);
unsigned int check = *((uint32_t *)(block_hash2 + 28));
if (check == 0)
{
byteswap(block_hash2, 32);
char *blockHash = bin2hex(block_hash2, 32);
printf("\nBlock found!\nHash: %s\nNonce: %u\nUnix time: %u", blockHash, startNonce, unixtime);
free(blockHash);
break;
}
startNonce++;
counter += 1;
if (time(NULL) - start >= 1)
{
printf("\r%d Hashes/s, Nonce %u\r", counter, startNonce);
counter = 0;
start = time(NULL);
}
*pNonce = startNonce;
if (startNonce > 4294967294LL)
{
unixtime++;
*pUnixtime = unixtime;
startNonce = 0;
}
}
}
free(merkleHash);
free(merkleHashSwapped);
free(txScriptSig);
free(pubScriptSig);
free(transaction->serializedData);
free(transaction->scriptSig);
free(transaction->pubkeyScript);
free(transaction);
getchar();
return 0;
}