├── .gitignore ├── .travis.yml ├── README.md ├── include └── README ├── lib └── README ├── platformio.ini ├── src └── main.cpp └── test └── README /.gitignore: -------------------------------------------------------------------------------- 1 | .pio 2 | .pioenvs 3 | .piolibdeps 4 | 5 | .vscode 6 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # Continuous Integration (CI) is the practice, in software 2 | # engineering, of merging all developer working copies with a shared mainline 3 | # several times a day < https://docs.platformio.org/page/ci/index.html > 4 | # 5 | # Documentation: 6 | # 7 | # * Travis CI Embedded Builds with PlatformIO 8 | # < https://docs.travis-ci.com/user/integration/platformio/ > 9 | # 10 | # * PlatformIO integration with Travis CI 11 | # < https://docs.platformio.org/page/ci/travis.html > 12 | # 13 | # * User Guide for `platformio ci` command 14 | # < https://docs.platformio.org/page/userguide/cmd_ci.html > 15 | # 16 | # 17 | # Please choose one of the following templates (proposed below) and uncomment 18 | # it (remove "# " before each line) or use own configuration according to the 19 | # Travis CI documentation (see above). 20 | # 21 | 22 | 23 | # 24 | # Template #1: General project. Test it using existing `platformio.ini`. 25 | # 26 | 27 | # language: python 28 | # python: 29 | # - "2.7" 30 | # 31 | # sudo: false 32 | # cache: 33 | # directories: 34 | # - "~/.platformio" 35 | # 36 | # install: 37 | # - pip install -U platformio 38 | # - platformio update 39 | # 40 | # script: 41 | # - platformio run 42 | 43 | 44 | # 45 | # Template #2: The project is intended to be used as a library with examples. 46 | # 47 | 48 | # language: python 49 | # python: 50 | # - "2.7" 51 | # 52 | # sudo: false 53 | # cache: 54 | # directories: 55 | # - "~/.platformio" 56 | # 57 | # env: 58 | # - PLATFORMIO_CI_SRC=path/to/test/file.c 59 | # - PLATFORMIO_CI_SRC=examples/file.ino 60 | # - PLATFORMIO_CI_SRC=path/to/test/directory 61 | # 62 | # install: 63 | # - pip install -U platformio 64 | # - platformio update 65 | # 66 | # script: 67 | # - platformio ci --lib="." --board=ID_1 --board=ID_2 --board=ID_N 68 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [](https://api.gitsponsors.com/api/badge/link?p=geRLHB9gG7O844yXmOsdMDkT54Dv8iku2Sc8pV94VZgDF2FHm8PE78j963NT2XbWrwsgUczkNPW/xVnhCKJp98EmGUbidMh/NAkwlEXM33auuLs5V056193812+/f/On) 2 | # ESP32-Bitcoin 3 | Bitcoin mining algorithm implemented on the ESP32 ;) 4 | 5 | A small platformIO project to test the mining performance with a predefined hash count. 6 | 7 | More info: https://blog.ja-ke.tech/2019/03/16/esp32-bitcoin.html 8 | -------------------------------------------------------------------------------- /include/README: -------------------------------------------------------------------------------- 1 | 2 | This directory is intended for project header files. 3 | 4 | A header file is a file containing C declarations and macro definitions 5 | to be shared between several project source files. You request the use of a 6 | header file in your project source file (C, C++, etc) located in `src` folder 7 | by including it, with the C preprocessing directive `#include'. 8 | 9 | ```src/main.c 10 | 11 | #include "header.h" 12 | 13 | int main (void) 14 | { 15 | ... 16 | } 17 | ``` 18 | 19 | Including a header file produces the same results as copying the header file 20 | into each source file that needs it. Such copying would be time-consuming 21 | and error-prone. With a header file, the related declarations appear 22 | in only one place. If they need to be changed, they can be changed in one 23 | place, and programs that include the header file will automatically use the 24 | new version when next recompiled. The header file eliminates the labor of 25 | finding and changing all the copies as well as the risk that a failure to 26 | find one copy will result in inconsistencies within a program. 27 | 28 | In C, the usual convention is to give header files names that end with `.h'. 29 | It is most portable to use only letters, digits, dashes, and underscores in 30 | header file names, and at most one dot. 31 | 32 | Read more about using header files in official GCC documentation: 33 | 34 | * Include Syntax 35 | * Include Operation 36 | * Once-Only Headers 37 | * Computed Includes 38 | 39 | https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html 40 | -------------------------------------------------------------------------------- /lib/README: -------------------------------------------------------------------------------- 1 | 2 | This directory is intended for project specific (private) libraries. 3 | PlatformIO will compile them to static libraries and link into executable file. 4 | 5 | The source code of each library should be placed in a an own separate directory 6 | ("lib/your_library_name/[here are source files]"). 7 | 8 | For example, see a structure of the following two libraries `Foo` and `Bar`: 9 | 10 | |--lib 11 | | | 12 | | |--Bar 13 | | | |--docs 14 | | | |--examples 15 | | | |--src 16 | | | |- Bar.c 17 | | | |- Bar.h 18 | | | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html 19 | | | 20 | | |--Foo 21 | | | |- Foo.c 22 | | | |- Foo.h 23 | | | 24 | | |- README --> THIS FILE 25 | | 26 | |- platformio.ini 27 | |--src 28 | |- main.c 29 | 30 | and a contents of `src/main.c`: 31 | ``` 32 | #include 33 | #include 34 | 35 | int main (void) 36 | { 37 | ... 38 | } 39 | 40 | ``` 41 | 42 | PlatformIO Library Dependency Finder will find automatically dependent 43 | libraries scanning project source files. 44 | 45 | More information about PlatformIO Library Dependency Finder 46 | - https://docs.platformio.org/page/librarymanager/ldf.html 47 | -------------------------------------------------------------------------------- /platformio.ini: -------------------------------------------------------------------------------- 1 | ; PlatformIO Project Configuration File 2 | ; 3 | ; Build options: build flags, source filter 4 | ; Upload options: custom upload port, speed and extra flags 5 | ; Library options: dependencies, extra library storages 6 | ; Advanced options: extra scripting 7 | ; 8 | ; Please visit documentation for the other options and examples 9 | ; https://docs.platformio.org/page/projectconf.html 10 | 11 | [env:esp32doit-devkit-v1] 12 | platform = espressif32 13 | board = esp32doit-devkit-v1 14 | framework = arduino 15 | upload_port=/dev/ttyUSB0 16 | upload_protocol=esptool 17 | upload_speed=921600 18 | -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "mbedtls/md.h" 3 | 4 | #define THREADS 4 5 | #define SHARE_DIFF 20000 6 | 7 | int shares = 0; 8 | 9 | // Print sha256 in little endian 10 | void printHash(unsigned char* string) { 11 | Serial.print("Hash: "); 12 | for(int i=31; i>=0; i--){ 13 | char str[3]; 14 | 15 | sprintf(str, "%02x", (int)string[i]); 16 | Serial.print(str); 17 | } 18 | Serial.println(); 19 | } 20 | 21 | // check if first 9 bytes are zero 22 | bool checkHash(unsigned char* string) { 23 | bool valid = true; 24 | for(uint8_t i=31; i>22; i--) { 25 | if(string[i] != 0) 26 | valid = false; 27 | } 28 | return valid; 29 | } 30 | 31 | void runWorker(void *name) { 32 | Serial.printf("\nRunning %s on core %d\n", (char *)name, xPortGetCoreID()); 33 | 34 | // Header of Bitcoin block nr. 563333 35 | byte payload[] = { 36 | 0x0, 0x0, 0x0, 0x20, // version 37 | 0xa2, 0x17, 0x62, 0x4e, 0xf7, 0x72, 0x1b, 0x95, 0x4c, 0x7d, 0x93, 0x75, 0xaa, 0x85, 0xc1, 0x34, 0xe5, 0xb7, 0x66, 0xd2, 0x26, 0xa, 0x2c, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, // prev hash 38 | 0xa5, 0x12, 0x42, 0x48, 0xfa, 0x62, 0xcb, 0xef, 0x22, 0xc1, 0x26, 0x8c, 0xc0, 0x24, 0x86, 0xec, 0xfb, 0x5, 0xc2, 0x6d, 0x45, 0xba, 0x42, 0xff, 0x7e, 0x9b, 0x34, 0x6c, 0x0, 0xdf, 0x60, 0xaf, // merkle root 39 | 0x5d, 0x80, 0x68, 0x5c, // time (2019-02-16) 40 | 0x88, 0x6f, 0x2e, 0x17, // difficulty bits 41 | 0x94, 0x4b, 0x40, 0x19 // nonce 42 | }; 43 | const size_t payloadLength = 80; 44 | uint32_t targetNonce = 423644052; // 0x19404b94 45 | 46 | 47 | byte interResult[32]; // 256 bit 48 | byte shaResult[32]; // 256 bit 49 | 50 | mbedtls_md_context_t ctx; 51 | mbedtls_md_type_t md_type = MBEDTLS_MD_SHA256; 52 | 53 | mbedtls_md_init(&ctx); 54 | mbedtls_md_setup(&ctx, mbedtls_md_info_from_type(md_type), 0); 55 | 56 | uint32_t nonce = targetNonce-SHARE_DIFF; 57 | 58 | uint32_t startT = micros(); 59 | while(true) { 60 | payload[76] = (nonce >> 0) & 0xFF; 61 | payload[77] = (nonce >> 8) & 0xFF; 62 | payload[78] = (nonce >> 16) & 0xFF; 63 | payload[79] = (nonce >> 24) & 0xFF; 64 | 65 | mbedtls_md_starts(&ctx); 66 | mbedtls_md_update(&ctx, payload, payloadLength); 67 | mbedtls_md_finish(&ctx, interResult); 68 | 69 | mbedtls_md_starts(&ctx); 70 | mbedtls_md_update(&ctx, interResult, 32); 71 | mbedtls_md_finish(&ctx, shaResult); 72 | 73 | if(checkHash(shaResult)) { 74 | // Comment this in if you want to run only a single time 75 | // break; 76 | nonce = targetNonce-SHARE_DIFF; 77 | Serial.printf("%s on core %d: ", (char *)name, xPortGetCoreID()); 78 | Serial.printf("Share completed with nonce: %d | 0x%x\n", nonce, nonce); 79 | shares++; 80 | // vTaskDelay(1); 81 | } 82 | 83 | nonce++; 84 | } 85 | uint32_t duration = micros() - startT; 86 | 87 | mbedtls_md_free(&ctx); 88 | 89 | Serial.println(checkHash(shaResult)? "Valid Block found!" : "no valid block..."); 90 | printHash(shaResult); 91 | Serial.printf("With nonce: %d | 0x%x\n", nonce, nonce); 92 | Serial.printf("In %d rounds, %f ms\n", SHARE_DIFF, duration/1000.0); 93 | Serial.printf("Hash Rate: %f kH/s", (1000.0/duration)*SHARE_DIFF); 94 | } 95 | 96 | void runMonitor(void *name) { 97 | unsigned long start = millis(); 98 | 99 | while (1) { 100 | unsigned long elapsed = millis()-start; 101 | Serial.printf(">>> Completed %d share(s), %d hashes, avg. hashrate %.3f KH/s\n", 102 | shares, shares*SHARE_DIFF, (1.0*shares*SHARE_DIFF)/elapsed); 103 | delay(5000); 104 | } 105 | } 106 | 107 | void setup(){ 108 | Serial.begin(9600); 109 | delay(3000); 110 | 111 | // Idle task that would reset WDT never runs, because core 0 gets fully utilized 112 | disableCore0WDT(); 113 | 114 | for (size_t i = 0; i < THREADS; i++) { 115 | char *name = (char*) malloc(32); 116 | sprintf(name, "Worker[%d]", i); 117 | 118 | // Start mining tasks 119 | BaseType_t res = xTaskCreate(runWorker, name, 30000, (void*)name, 1, NULL); 120 | Serial.printf("Starting %s %s!\n", name, res == pdPASS? "successful":"failed"); 121 | } 122 | 123 | // Higher prio monitor task 124 | xTaskCreate(runMonitor, "Monitor", 5000, NULL, 4, NULL); 125 | } 126 | 127 | 128 | void loop(){} 129 | -------------------------------------------------------------------------------- /test/README: -------------------------------------------------------------------------------- 1 | 2 | This directory is intended for PIO Unit Testing and project tests. 3 | 4 | Unit Testing is a software testing method by which individual units of 5 | source code, sets of one or more MCU program modules together with associated 6 | control data, usage procedures, and operating procedures, are tested to 7 | determine whether they are fit for use. Unit testing finds problems early 8 | in the development cycle. 9 | 10 | More information about PIO Unit Testing: 11 | - https://docs.platformio.org/page/plus/unit-testing.html 12 | --------------------------------------------------------------------------------