Advertisement
kyroskoh

Genesis Block Generator

Aug 15th, 2018
220
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. #include <stdlib.h>
  2. #include <stdio.h>
  3. #include <stdbool.h>
  4. #include <inttypes.h>
  5. #include <ctype.h>
  6. #include <string.h>
  7. #include <time.h>
  8. #include <openssl/sha.h>
  9.  
  10. //Copied from Bitcoin source
  11. const uint64_t COIN = 100000000;
  12. const uint64_t CENT = 1000000;
  13.  
  14. uint32_t OP_CHECKSIG = 172; // This is expressed as 0xAC
  15. bool generateBlock = false;
  16. uint32_t startNonce = 0;
  17. uint32_t unixtime = 0;
  18.  
  19. typedef struct {
  20. /* Hash of Tx */
  21. uint8_t merkleHash[32];
  22.  
  23. /* Tx serialization before hashing */
  24. uint8_t *serializedData;
  25.  
  26. /* Tx version */
  27. uint32_t version;
  28.  
  29. /* Input */
  30. uint8_t numInputs; // Program assumes one input
  31. uint8_t prevOutput[32];
  32. uint32_t prevoutIndex;
  33. uint8_t *scriptSig;
  34. uint32_t sequence;
  35.  
  36. /* Output */
  37. uint8_t numOutputs; // Program assumes one output
  38. uint64_t outValue;
  39. uint8_t *pubkeyScript;
  40.  
  41. /* Final */
  42. uint32_t locktime;
  43. } Transaction;
  44.  
  45. // Got this off the internet. Am not sure if it can fail in some circumstances
  46. void byteswap(uint8_t *buf, int length)
  47. {
  48. int i;
  49. uint8_t temp;
  50.  
  51. for(i = 0; i < length / 2; i++)
  52. {
  53. temp = buf[i];
  54. buf[i] = buf[length - i - 1];
  55. buf[length - i - 1] = temp;
  56. }
  57. }
  58.  
  59. // Following two functions are borrowed from cgminer.
  60. char *bin2hex(const unsigned char *p, size_t len)
  61. {
  62. char *s = malloc((len * 2) + 1);
  63. unsigned int i;
  64.  
  65. if (!s)
  66. return NULL;
  67.  
  68. for (i = 0; i < len; i++)
  69. sprintf(s + (i * 2), "%02x", (unsigned int) p[i]);
  70.  
  71. return s;
  72. }
  73.  
  74. size_t hex2bin(unsigned char *p, const char *hexstr, size_t len)
  75. {
  76. int ret = 0;
  77. size_t retlen = len;
  78.  
  79. while (*hexstr && len) {
  80. char hex_byte[4];
  81. unsigned int v;
  82.  
  83. if (!hexstr[1]) {
  84. return ret;
  85. }
  86.  
  87. memset(hex_byte, 0, 4);
  88. hex_byte[0] = hexstr[0];
  89. hex_byte[1] = hexstr[1];
  90.  
  91. if (sscanf(hex_byte, "%x", &v) != 1) {
  92. return ret;
  93. }
  94.  
  95. *p = (unsigned char) v;
  96.  
  97. p++;
  98. hexstr += 2;
  99. len--;
  100. }
  101.  
  102. if (len == 0 && *hexstr == 0)
  103. ret = retlen;
  104.  
  105. return ret;
  106. }
  107.  
  108. Transaction *InitTransaction()
  109. {
  110. Transaction *transaction;
  111.  
  112. transaction = calloc(1, sizeof(*transaction));
  113. if(!transaction)
  114. {
  115. return NULL;
  116. }
  117.  
  118. // Set some initial data that will remain constant throughout the program
  119. transaction->version = 1;
  120. transaction->numInputs = 1;
  121. transaction->numOutputs = 1;
  122. transaction->locktime = 0;
  123. transaction->prevoutIndex = 0xFFFFFFFF;
  124. transaction->sequence = 0xFFFFFFFF;
  125. transaction->outValue = 50*COIN;
  126.  
  127. // We initialize the previous output to 0 as there is none
  128. memset(transaction->prevOutput, 0, 32);
  129.  
  130. return transaction;
  131. }
  132.  
  133. int main(int argc, char *argv[])
  134. {
  135. Transaction *transaction;
  136. unsigned char hash1[32], hash2[32];
  137. char timestamp[255], pubkey[132];
  138. uint32_t timestamp_len = 0, scriptSig_len = 0, pubkey_len = 0, pubkeyScript_len = 0;
  139. uint32_t nBits = 0;
  140.  
  141. if((argc-1) < 3)
  142. {
  143. fprintf(stderr, "Usage: genesisgen [options] <pubkey> \"<timestamp>\" <nBits>\n");
  144. return 0;
  145. }
  146.  
  147. pubkey_len = strlen(argv[1]) / 2; // One byte is represented as two hex characters, thus we divide by two to get real length.
  148. timestamp_len = strlen(argv[2]);
  149.  
  150. if(pubkey_len != 65)
  151. {
  152. fprintf(stderr, "Invalid public key length! %s\n", argv[1]);
  153. return 0;
  154. }
  155.  
  156. if(timestamp_len > 254 || timestamp_len <= 0)
  157. {
  158. fprintf(stderr, "Size of timestamp is 0 or exceeds maximum length of 254 characters!\n");
  159. return 0;
  160. }
  161.  
  162. transaction = InitTransaction();
  163. if(!transaction)
  164. {
  165. fprintf(stderr, "Could not allocate memory! Exiting...\n");
  166. return 0;
  167. }
  168.  
  169. strncpy(pubkey, argv[1], sizeof(pubkey));
  170. strncpy(timestamp, argv[2], sizeof(timestamp));
  171. sscanf(argv[3], "%lu", (long unsigned int *)&nBits);
  172.  
  173. pubkey_len = strlen(pubkey) >> 1;
  174. scriptSig_len = timestamp_len;
  175.  
  176. // Encode pubkey to binary and prepend pubkey size, then append the OP_CHECKSIG byte
  177. transaction->pubkeyScript = malloc((pubkey_len+2)*sizeof(uint8_t));
  178. pubkeyScript_len = hex2bin(transaction->pubkeyScript+1, pubkey, pubkey_len); // No error checking, yeah.
  179. transaction->pubkeyScript[0] = 0x41; // A public key is 32 bytes X coordinate, 32 bytes Y coordinate and one byte 0x04, so 65 bytes i.e 0x41 in Hex.
  180. pubkeyScript_len+=1;
  181. transaction->pubkeyScript[pubkeyScript_len++] = OP_CHECKSIG;
  182.  
  183. // Encode timestamp to binary
  184. transaction->scriptSig = malloc(scriptSig_len*sizeof(uint8_t));
  185. uint32_t scriptSig_pos = 0;
  186.  
  187.  
  188. // This is basically how I believe the size of the nBits is calculated
  189. if(nBits <= 255)
  190. {
  191. transaction->scriptSig[scriptSig_pos++] = 0x01;
  192. transaction->scriptSig[scriptSig_pos++] = (uint8_t)nBits;
  193. }
  194. else if(nBits <= 65535)
  195. {
  196. transaction->scriptSig[scriptSig_pos++] = 0x02;
  197. memcpy(transaction->scriptSig+scriptSig_pos, &nBits, 2);
  198. scriptSig_pos+=2;
  199. }
  200. else if(nBits <= 16777215)
  201. {
  202. transaction->scriptSig[scriptSig_pos++] = 0x03;
  203. memcpy(transaction->scriptSig+scriptSig_pos, &nBits, 3);
  204. scriptSig_pos+=3;
  205. }
  206. else //else if(nBits <= 4294967296LL)
  207. {
  208. transaction->scriptSig[scriptSig_pos++] = 0x04;
  209. memcpy(transaction->scriptSig+scriptSig_pos, &nBits, 4);
  210. scriptSig_pos+=4;
  211. }
  212.  
  213. // Important! In the Bitcoin code there is a statement 'CBigNum(4)'
  214. // i've been wondering for a while what it is but
  215. // seeing as alt-coins keep it the same, we'll do it here as well
  216. // It should essentially mean PUSH 1 byte on the stack which in this case is 0x04 or just 4
  217. transaction->scriptSig[scriptSig_pos++] = 0x01;
  218. transaction->scriptSig[scriptSig_pos++] = 0x04;
  219.  
  220. transaction->scriptSig[scriptSig_pos++] = (uint8_t)scriptSig_len;
  221.  
  222. scriptSig_len += scriptSig_pos;
  223. transaction->scriptSig = realloc(transaction->scriptSig, scriptSig_len*sizeof(uint8_t));
  224. memcpy(transaction->scriptSig+scriptSig_pos, (const unsigned char *)timestamp, timestamp_len);
  225.  
  226. // Here we are asuming some values will have the same size
  227. uint32_t serializedLen =
  228. 4 // tx version
  229. +1 // number of inputs
  230. +32 // hash of previous output
  231. +4 // previous output's index
  232. +1 // 1 byte for the size of scriptSig
  233. +scriptSig_len
  234. +4 // size of sequence
  235. +1 // number of outputs
  236. +8 // 8 bytes for coin value
  237. +1 // 1 byte to represent size of the pubkey Script
  238. +pubkeyScript_len
  239. +4; // 4 bytes for lock time
  240.  
  241. // Now let's serialize the data
  242. uint32_t serializedData_pos = 0;
  243. transaction->serializedData = malloc(serializedLen*sizeof(uint8_t));
  244. memcpy(transaction->serializedData+serializedData_pos, &transaction->version, 4);
  245. serializedData_pos += 4;
  246. memcpy(transaction->serializedData+serializedData_pos, &transaction->numInputs, 1);
  247. serializedData_pos += 1;
  248. memcpy(transaction->serializedData+serializedData_pos, transaction->prevOutput, 32);
  249. serializedData_pos += 32;
  250. memcpy(transaction->serializedData+serializedData_pos, &transaction->prevoutIndex, 4);
  251. serializedData_pos += 4;
  252. memcpy(transaction->serializedData+serializedData_pos, &scriptSig_len, 1);
  253. serializedData_pos += 1;
  254. memcpy(transaction->serializedData+serializedData_pos, transaction->scriptSig, scriptSig_len);
  255. serializedData_pos += scriptSig_len;
  256. memcpy(transaction->serializedData+serializedData_pos, &transaction->sequence, 4);
  257. serializedData_pos += 4;
  258. memcpy(transaction->serializedData+serializedData_pos, &transaction->numOutputs, 1);
  259. serializedData_pos += 1;
  260. memcpy(transaction->serializedData+serializedData_pos, &transaction->outValue, 8);
  261. serializedData_pos += 8;
  262. memcpy(transaction->serializedData+serializedData_pos, &pubkeyScript_len, 1);
  263. serializedData_pos += 1;
  264. memcpy(transaction->serializedData+serializedData_pos, transaction->pubkeyScript, pubkeyScript_len);
  265. serializedData_pos += pubkeyScript_len;
  266. memcpy(transaction->serializedData+serializedData_pos, &transaction->locktime, 4);
  267. serializedData_pos += 4;
  268.  
  269. // Now that the data is serialized
  270. // we hash it with SHA256 and then hash that result to get merkle hash
  271. SHA256(transaction->serializedData, serializedLen, hash1);
  272. SHA256(hash1, 32, hash2);
  273.  
  274. // This copy isn't necessary imo, but here for clarity
  275. memcpy(transaction->merkleHash, hash2, 32);
  276.  
  277. char *merkleHash = bin2hex(transaction->merkleHash, 32);
  278. byteswap(transaction->merkleHash, 32);
  279. char *merkleHashSwapped = bin2hex(transaction->merkleHash, 32);
  280. char *txScriptSig = bin2hex(transaction->scriptSig, scriptSig_len);
  281. char *pubScriptSig = bin2hex(transaction->pubkeyScript, pubkeyScript_len);
  282. printf("\nCoinbase: %s\n\nPubkeyScript: %s\n\nMerkle Hash: %s\nByteswapped: %s\n",txScriptSig, pubScriptSig, merkleHash, merkleHashSwapped);
  283.  
  284. //if(generateBlock)
  285. {
  286. printf("Generating block...\n");
  287. if(!unixtime)
  288. {
  289. unixtime = time(NULL);
  290. }
  291.  
  292. unsigned char block_header[80], block_hash1[32], block_hash2[32];
  293. uint32_t blockversion = 1;
  294. memcpy(block_header, &blockversion, 4);
  295. memset(block_header+4, 0, 32);
  296. byteswap(transaction->merkleHash, 32); // We swapped it before, so do it again now.
  297. memcpy(block_header+36, transaction->merkleHash, 32);
  298. memcpy(block_header+68, &unixtime, 4);
  299. memcpy(block_header+72, &nBits, 4);
  300. memcpy(block_header+76, &startNonce, 4);
  301.  
  302. uint32_t *pNonce = (uint32_t *)(block_header + 76);
  303. uint32_t *pUnixtime = (uint32_t *)(block_header + 68);
  304. unsigned int counter, start = time(NULL);
  305. while(1)
  306. {
  307. SHA256(block_header, 80, block_hash1);
  308. SHA256(block_hash1, 32, block_hash2);
  309.  
  310. unsigned int check = *((uint32_t *)(block_hash2 + 28)); // The hash is in little-endian, so we check the last 4 bytes.
  311. if(check == 0) // \x00\x00\x00\x00
  312. {
  313. byteswap(block_hash2, 32);
  314. char *blockHash = bin2hex(block_hash2, 32);
  315. printf("\nBlock found!\nHash: %s\nNonce: %u\nUnix time: %u", blockHash, startNonce, unixtime);
  316. free(blockHash);
  317. break;
  318. }
  319.  
  320. startNonce++;
  321. counter+=1;
  322. if(time(NULL)-start >= 1)
  323. {
  324. printf("\r%d Hashes/s, Nonce %u\r", counter, startNonce);
  325. counter = 0;
  326. start = time(NULL);
  327. }
  328. *pNonce = startNonce;
  329. if(startNonce > 4294967294LL)
  330. {
  331. //printf("\nBlock found!\nHash: %s\nNonce: %u\nUnix time: %u", blockHash, startNonce, unixtime);
  332. unixtime++;
  333. *pUnixtime = unixtime;
  334. startNonce = 0;
  335. }
  336. }
  337. }
  338.  
  339.  
  340. // Lots of cleanup
  341. free(merkleHash);
  342. free(merkleHashSwapped);
  343. free(txScriptSig);
  344. free(pubScriptSig);
  345. free(transaction->serializedData);
  346. free(transaction->scriptSig);
  347. free(transaction->pubkeyScript);
  348. free(transaction);
  349.  
  350. return 0;
  351. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement