Merge pull request #137 from BitMaker-hub/dev

Release 1.6.1

¡We are supporting ESP32-WROOM boards!

Use this code on cheapest hardware possible. Run up to 50Khs on a single ESP32.

Added best difficulty share to screen. (@golden-guy)
Improved watchdog functions (@golden-guy)
Added a pool connectivity delay to reduce overload connection at pool (@BitMaker-hub)
Added new sha version up to 56Khs on TTGO T-DISPLAY s3 (@BitMaker-hub)
Added support for ESP32-WROOM devices (@BitMaker-hub)

You can also build it easily using the flasher tool:
https://bitmaker-hub.github.io/diyflasher/
This commit is contained in:
BitMaker 2023-08-27 12:44:46 +02:00 committed by GitHub
commit af416251fd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
43 changed files with 2962 additions and 5313 deletions

Binary file not shown.

View File

@ -11,20 +11,20 @@ Original project https://github.com/valerio-vaccaro/HAN
![image](images/NerdMinerv2.jpg)
## Requirements
- TTGO T-Display S3
- TTGO T-Display S3 or any supported boards (check Build tutorial 👇)
- 3D BOX [here](3d_files/)
### Project description
**ESP32 implementing Stratum protocol** to mine on solo pool. Pool can be changed but originally works with ckpool.
**ESP32 implementing Stratum protocol** to mine on solo pool. Pool can be changed but originally works with Public-pool.io (where Nerdminers are supported).
This project is using ESP32-S3, uses WifiManager to modify miner settings and save them to SPIFF.
This project was initialy developed using ESP32-S3, but currently support other boards. It uses WifiManager to modify miner settings and save them to SPIFF.
The microMiner comes with several screens to monitor it's working procedure and also to show you network mining stats.
Currently includes:
- NerdMiner Screen > Mining data of Nerdminer
- ClockMiner Screen > Fashion style clock miner
- GlobalStats Screen > Global minery stats and relevant data
This miner is multicore and multithreads, one thread is used to mine and other is implementing stratum work and wifi stuff.
This miner is multicore and multithreads, both cores are used to mine and several threads are used to implementing stratum work and wifi stuff.
Every time an stratum job notification is received miner update its current work to not create stale shares.
**IMPORTANT** Miner is not seen by all standard pools due to its low share difficulty. You can check miner work remotely using specific pools specified down or seeing logs via UART.
@ -34,20 +34,24 @@ Every time an stratum job notification is received miner update its current work
## Build Tutorial
### Hardware requirements
- TTGO T-Display S3 > Buy it on aliexpress or amazon
- 3D BOX
- 3D BOX [here](3d_files/)
#### Current Supported Boards
- TTGO T-Display S3 ([Aliexpress link](https://s.click.aliexpress.com/e/_Ddy7739))
- ESP32-WROOM-32, ESP32-Devkit1.. ([Aliexpress link](https://s.click.aliexpress.com/e/_DCzlUiX))
### Flash firmware
#### microMiners Flashtool [Recommended]
Easyiest way to flash firmware. Build your own miner using the folowing firwmare flash tool:
1. Get a TTGO T-display S3
1. Get a TTGO T-display S3 or any other supported board
1. Go to NM2 flasher online: https://bitmaker-hub.github.io/diyflasher/
#### Standard tool
Create your own miner using the online firwmare flash tool **ESPtool** and the **binary files** that you will find in the src/bin folder.
If you want you can compile the entire project using Arduino, PlatformIO or Expressif IDF.
1. Get a TTGO T-display S3
1. Get a TTGO T-display S3 or any supported board
1. Download this repository
1. Go to ESPtool online: https://espressif.github.io/esptool-js/
1. Load the firmware with the binaries from the src/bin folder.
@ -61,6 +65,7 @@ Update NerdMiner firmware following same flashing steps but only adding 0x10000_
1. ESPtool recommendations: use 115200bps
1. Build errors > If during firmware download upload stops, it's recommended to enter the board in boot mode. Unplug cable, hold right bottom button and then plug cable. Try programming
1. In extreme case you can "Erase all flash" on ESPtool to clean all current configuration before uploading firmware. There has been cases that experimented Wifi failures until this was made.
1. In case of ESP32-WROOM Boards, could be necessary to put your board on boot mode. Hold boot button, press reset button and then program.
### NerdMiner configuration
After programming, you will only need to setup your Wifi and BTC address.
@ -108,11 +113,11 @@ With the USB-C port to the right:
## Developers
### Project guidelines
- Current project was addapted to work with PlatformIO
- Current project works with ESP32-S3 but any ESP32 can be used.
- Current project works with ESP32-S3 and ESP32-wroom.
- Partition squeme should be build as huge app
- All libraries needed shown on platform.ini
### On process
### Job done
- [x] Move project to platformIO
- [x] Bug rectangle on screen when 1milion shares
- [x] Bug memory leaks
@ -123,6 +128,16 @@ With the USB-C port to the right:
- [x] Add blockHeight to screen
- [x] Add clock to show current time
- [x] Add new screen with global mining stats
- [x] Add pool support for low difficulty miners
- [x] Add best difficulty on miner screen
- [x] Add suport to standard ESP32 dev-kit / ESP32-WROOM
### On process
- [ ] Code changes to support adding multiple boards
- [ ] Create a daisy chain protocol via UART or I2C to support ESP32 hashboards
- [ ] Add support to TTGO T-display 1.14
- [ ] Add support to Amoled
- [ ] Create new screen like clockMiner but with BTC price
- [ ] Add support to control BM1397
### Donations/Project contributions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -81,9 +81,9 @@
//#include <User_Setups/Setup44_TTGO_CameraPlus.h> // Setup file for ESP32 and TTGO T-CameraPlus ST7789 SPI bus TFT 240x240
//#include <User_Setups/Setup45_TTGO_T_Watch.h> // Setup file for ESP32 and TTGO T-Watch ST7789 SPI bus TFT 240x240
//#include <User_Setups/Setup46_GC9A01_ESP32.h> // Setup file for ESP32 and GC9A01 SPI bus TFT 240x240
//#include <User_Setups/Setup47_ST7735.h> // Setup file for ESP32 configured for ST7735 128 x 128 animated eyes
#ifdef DEVKITV1
#include <User_Setups/Setup47_ST7735.h> // Setup file for ESP32 configured for ST7735 128 x 128 animated eyes
#endif
//#include <User_Setups/Setup50_SSD1963_Parallel.h> // Setup file for ESP32 and SSD1963 TFT display
//#include <User_Setups/Setup51_LilyPi_ILI9481.h> // Setup file for LilyGo LilyPi with ILI9481 display
@ -127,9 +127,9 @@
//#include <User_Setups/Setup204_ESP32_TouchDown.h> // Setup file for the ESP32 TouchDown based on ILI9488 480 x 320 TFT
//#include <User_Setups/Setup205_ESP32_TouchDown_S3.h> // Setup file for the ESP32 TouchDown S3 based on ILI9488 480 x 320 TFT
#ifdef NERDMINERV2
#include <User_Setups/Setup206_LilyGo_T_Display_S3.h>
#endif
//#include <User_Setups/Setup301_BW16_ST7735.h> // Setup file for Bw16-based boards with ST7735 160 x 80 TFT
//#include <User_Setups/SetupX_Template.h> // Template file for a setup

View File

@ -10,7 +10,7 @@
[platformio]
globallib_dir = lib
default_envs = NerminerV2 ;, ESP32-devKitv1 TTGO-T-Display
default_envs = NerminerV2, ESP32-devKitv1
[env:NerminerV2]
platform = espressif32
@ -35,6 +35,7 @@ build_flags =
-D BOARD_HAS_PSRAM
-D ARDUINO_USB_MODE=1
-D ARDUINO_USB_CDC_ON_BOOT=1
-D NERDMINERV2=1
;-D DEBUG_MINING=1
lib_deps =
https://github.com/takkaO/OpenFontRender
@ -42,7 +43,7 @@ lib_deps =
https://github.com/tzapu/WiFiManager.git
mathertel/OneButton @ ^2.0.3
arduino-libraries/NTPClient
https://github.com/golden-guy/Arduino_wolfssl.git#v5.5.4
;https://github.com/golden-guy/Arduino_wolfssl.git#v5.5.4
[env:ESP32-devKitv1]
@ -58,14 +59,10 @@ monitor_speed = 115200
upload_speed = 115200
# 2 x 4.5MB app, 6.875MB SPIFFS
;board_build.partitions = large_spiffs_16MB.csv
;board_build.partitions = default_8MB.csv
;board_build.partitions = huge_app.csv
board_build.partitions = default.csv
board_build.partitions = huge_app.csv
build_flags =
-D ARDUINO_USB_MODE=1
-U FREERTOS
-D DEVKITV1=1
;-D DEBUG_MINING=1
lib_deps =
https://github.com/takkaO/OpenFontRender
@ -73,11 +70,11 @@ lib_deps =
https://github.com/tzapu/WiFiManager.git
mathertel/OneButton @ ^2.0.3
arduino-libraries/NTPClient
https://github.com/golden-guy/Arduino_wolfssl.git#v5.5.4
[env:TTGO-T-Display]
platform = espressif32
board = esp-wrover-kit
board = esp32dev ;esp-wrover-kit
framework = arduino
monitor_filters =
esp32_exception_decoder
@ -87,16 +84,17 @@ board_build.arduino.memory_type = qio_opi
monitor_speed = 115200
upload_speed = 115200
# 2 x 4.5MB app, 6.875MB SPIFFS
board_build.partitions = huge_app.csv
;build_flags =
; -D ARDUINO_USB_MODE=1
build_flags =
;-D DEBUG_MINING=1
-D TDISPLAY=1
lib_deps =
https://github.com/takkaO/OpenFontRender
bblanchon/ArduinoJson@^6.21.2
https://github.com/tzapu/WiFiManager.git
mathertel/OneButton @ ^2.0.3
arduino-libraries/NTPClient
https://github.com/golden-guy/Arduino_wolfssl.git#v5.5.4
;https://github.com/golden-guy/Arduino_wolfssl.git#v5.5.4

View File

@ -16,17 +16,18 @@
#include "mining.h"
#include "monitor.h"
#define CURRENT_VERSION "V1.6.0"
#define CURRENT_VERSION "V1.6.1"
//3 seconds WDT
#define WDT_TIMEOUT 3
//120 seconds WDT for miner task
#define WDT_MINER_TIMEOUT 120
//15 minutes WDT for miner task
#define WDT_MINER_TIMEOUT 900
OneButton button1(PIN_BUTTON_1);
OneButton button2(PIN_BUTTON_2);
OpenFontRender render;
extern monitor_data mMonitor;
/**********************⚡ GLOBAL Vars *******************************/
TFT_eSPI tft = TFT_eSPI(); // Invoke library, pins defined in User_Setup.h
@ -38,10 +39,12 @@ const char* ntpServer = "pool.ntp.org";
//void runMonitor(void *name);
void alternate_screen_state() {
#ifdef NERDMINERV2
int screen_state= digitalRead(TFT_BL);
//Serial.printf("Screen state is '%s', switching to '%s'", screen_state, !screen_state);
Serial.println("Switching display state");
digitalWrite(TFT_BL, !screen_state);
#endif
}
void alternate_screen_rotation() {
@ -64,21 +67,23 @@ void setup()
//disableCore1WDT();
// Setup the buttons
#ifdef NERDMINERV2
// Button 1 (Boot)
button1.setPressTicks(5000);
button1.attachClick(alternate_screen_state);
button1.attachDoubleClick(alternate_screen_rotation);
// button1.attachLongPressStart([]{Serial.println("Button 1 started a long press");});
// button1.attachLongPressStop([]{Serial.println("Button 1 stopped a long press");});
// button1.attachDuringLongPress([]{Serial.println("Button 1 is being held down");});
// Button 2 (GPIO14)
button2.setPressTicks(5000);
button2.attachClick(changeScreen);
// button2.attachDoubleClick([]{Serial.println("Button 2 was double clicked");});
button2.attachLongPressStart(reset_configurations);
// button2.attachLongPressStop(reset_configurations);
// button2.attachDuringLongPress([]{Serial.println("Button 2 is being held down");});
#elif defined(DEVKITV1)
//Standard ESP32-devKit
button1.setPressTicks(5000);
button1.attachLongPressStart(reset_configurations);
pinMode(LED_PIN, OUTPUT);
#endif
/******** INIT NERDMINER ************/
@ -105,9 +110,15 @@ void setup()
tft.fillScreen(TFT_BLACK);
tft.pushImage(0, 0, initWidth, initHeight, initScreen);
tft.setTextColor(TFT_BLACK);
tft.drawString(CURRENT_VERSION, 24, 130, FONT2);
tft.drawString(CURRENT_VERSION, 24, 147, FONT2);
delay(2000);
/******** SHOW LED INIT STATUS (devices without screen) *****/
mMonitor.NerdStatus = NM_waitingConfig;
#ifdef DEVKITV1
doLedStuff(LED_PIN);
#endif
/******** INIT WIFI ************/
init_WifiManager();
@ -122,7 +133,7 @@ void setup()
/******** CREATE STRATUM TASK *****/
sprintf(name, "(%s)", "Stratum");
BaseType_t res2 = xTaskCreatePinnedToCore(runStratumWorker, "Stratum", 20000, (void*)name, 3, NULL,1);
BaseType_t res2 = xTaskCreatePinnedToCore(runStratumWorker, "Stratum", 15000, (void*)name, 3, NULL,1);
/******** CREATE MINER TASKS *****/
@ -130,19 +141,12 @@ void setup()
// char *name = (char*) malloc(32);
// sprintf(name, "(%d)", i);
// Start stratum tasks
sprintf(name, "(%s)", "Miner0");
//BaseType_t res = xTaskCreatePinnedToCore(runMiner, "0", 10000, (void*)name, 1, NULL, 0);
//BaseType_t res3 = xTaskCreatePinnedToCore(runMiner, "0", 10000, (void*)name, 1,NULL, 0);
//sprintf(name, "(%s)", "Miner1");
//BaseType_t res4 = xTaskCreatePinnedToCore(runMiner, "1", 10000, (void*)name, 1,NULL, 0);
//Serial.printf("Starting %s %s!\n", "1", res3 == pdPASS? "successful":"failed");
// Start mining tasks
//BaseType_t res = xTaskCreate(runWorker, name, 35000, (void*)name, 1, NULL);
TaskHandle_t minerTask1, minerTask2 = NULL;
xTaskCreate(runMiner, "Miner0", 15000, (void*)0, 1, &minerTask1);
xTaskCreate(runMiner, "Miner1", 15000, (void*)1, 1, &minerTask2);
xTaskCreate(runMiner, "Miner0", 6000, (void*)0, 1, &minerTask1);
xTaskCreate(runMiner, "Miner1", 6000, (void*)1, 1, &minerTask2);
esp_task_wdt_add(minerTask1);
esp_task_wdt_add(minerTask2);
@ -169,5 +173,9 @@ void loop() {
wifiManagerProcess(); // avoid delays() in loop when non-blocking and other long running code
#ifdef DEVKITV1
doLedStuff(LED_PIN);
#endif
vTaskDelay(50 / portTICK_PERIOD_MS);
}

View File

@ -1,574 +0,0 @@
#define NDEBUG
#include <stdio.h>
#include <string.h>
#include <Arduino.h>
//#include <wally_address.h>
//#include <wally_transaction.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include <esp_log.h>
#include <esp_timer.h>
#include "jadeSHA256.h"
#include <math.h>
#include <string.h>
#define HASH_SIZE 32
#define ROTR(x, n) ((x >> n) | (x << ((sizeof(x) << 3) - n)))
#ifndef PUT_UINT32_BE
#define PUT_UINT32_BE(n, data, offset) \
{ \
u.num = n; \
p = (data) + (offset); \
*p = u.b[3]; \
*(p + 1) = u.b[2]; \
*(p + 2) = u.b[1]; \
*(p + 3) = u.b[0]; \
}
#endif
#ifndef GET_UINT32_BE
#define GET_UINT32_BE(b, i) \
(((uint32_t)(b)[(i)] << 24) | ((uint32_t)(b)[(i) + 1] << 16) | ((uint32_t)(b)[(i) + 2] << 8) \
| ((uint32_t)(b)[(i) + 3]))
#endif
DRAM_ATTR static const uint32_t K[] = {
0x428A2F98,
0x71374491,
0xB5C0FBCF,
0xE9B5DBA5,
0x3956C25B,
0x59F111F1,
0x923F82A4,
0xAB1C5ED5,
0xD807AA98,
0x12835B01,
0x243185BE,
0x550C7DC3,
0x72BE5D74,
0x80DEB1FE,
0x9BDC06A7,
0xC19BF174,
0xE49B69C1,
0xEFBE4786,
0x0FC19DC6,
0x240CA1CC,
0x2DE92C6F,
0x4A7484AA,
0x5CB0A9DC,
0x76F988DA,
0x983E5152,
0xA831C66D,
0xB00327C8,
0xBF597FC7,
0xC6E00BF3,
0xD5A79147,
0x06CA6351,
0x14292967,
0x27B70A85,
0x2E1B2138,
0x4D2C6DFC,
0x53380D13,
0x650A7354,
0x766A0ABB,
0x81C2C92E,
0x92722C85,
0xA2BFE8A1,
0xA81A664B,
0xC24B8B70,
0xC76C51A3,
0xD192E819,
0xD6990624,
0xF40E3585,
0x106AA070,
0x19A4C116,
0x1E376C08,
0x2748774C,
0x34B0BCB5,
0x391C0CB3,
0x4ED8AA4A,
0x5B9CCA4F,
0x682E6FF3,
0x748F82EE,
0x78A5636F,
0x84C87814,
0x8CC70208,
0x90BEFFFA,
0xA4506CEB,
0xBEF9A3F7,
0xC67178F2,
};
#define SHR(x, n) ((x & 0xFFFFFFFF) >> n)
#define S0(x) (ROTR(x, 7) ^ ROTR(x, 18) ^ SHR(x, 3))
#define S1(x) (ROTR(x, 17) ^ ROTR(x, 19) ^ SHR(x, 10))
#define S2(x) (ROTR(x, 2) ^ ROTR(x, 13) ^ ROTR(x, 22))
#define S3(x) (ROTR(x, 6) ^ ROTR(x, 11) ^ ROTR(x, 25))
#define F0(x, y, z) ((x & y) | (z & (x | y)))
#define F1(x, y, z) (z ^ (x & (y ^ z)))
#define R(t) (W[t] = S1(W[t - 2]) + W[t - 7] + S0(W[t - 15]) + W[t - 16])
#define P(a, b, c, d, e, f, g, h, x, K) \
{ \
temp1 = h + S3(e) + F1(e, f, g) + K + x; \
temp2 = S2(a) + F0(a, b, c); \
d += temp1; \
h = temp1 + temp2; \
}
#define CHECK_BYTES(u1, u2, offset) \
{ \
temp1 = u1 + u2; \
for (int i = 0; i < 4; ++i) { \
temp3 = (uint8_t)((temp1 >> (i * 8)) & 0xff); \
temp4 = *(target + offset + i); \
if (__builtin_expect(temp4 < temp3, true)) { \
return false; \
} \
if (__builtin_expect(temp4 > temp3, false)) { \
return true; \
} \
} \
}
#define MAINET_TESTNET_INTERVAL 210000
#define REGTEST_INTERVAL 150
const char* TAG = "MINER";
typedef struct {
uint32_t version;
uint8_t prev_block[32];
uint8_t merkle_root[32];
uint32_t timestamp;
uint32_t bits;
uint32_t nonce;
} block_header;
typedef struct headerandtarget {
block_header bh;
uint8_t target[32];
} headerandtarget;
typedef struct task_ctx {
headerandtarget ht;
uint32_t hashespersec;
uint32_t nonce_start;
uint32_t* nonce_solution;
uint8_t task_n;
bool* solution_found;
bool newwork;
} task_ctx;
typedef struct miner_ctx {
uint8_t rawtx[300];
block_header bh;
int64_t start;
TaskHandle_t xHandle1;
TaskHandle_t xHandle2;
solution_cb cb;
void* cbctx;
task_ctx ctx1;
task_ctx ctx2;
size_t txlen;
bool solution_found;
} miner_ctx;
IRAM_ATTR void calc_midstate(uint8_t* buf_ptr, _sha256_context* midstate)
{
uint32_t A[8] = { 0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A, 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19 };
uint32_t temp1, temp2, W[64];
W[0] = GET_UINT32_BE(buf_ptr, 0);
W[1] = GET_UINT32_BE(buf_ptr, 4);
W[2] = GET_UINT32_BE(buf_ptr, 8);
W[3] = GET_UINT32_BE(buf_ptr, 12);
W[4] = GET_UINT32_BE(buf_ptr, 16);
W[5] = GET_UINT32_BE(buf_ptr, 20);
W[6] = GET_UINT32_BE(buf_ptr, 24);
W[7] = GET_UINT32_BE(buf_ptr, 28);
W[8] = GET_UINT32_BE(buf_ptr, 32);
W[9] = GET_UINT32_BE(buf_ptr, 36);
W[10] = GET_UINT32_BE(buf_ptr, 40);
W[11] = GET_UINT32_BE(buf_ptr, 44);
W[12] = GET_UINT32_BE(buf_ptr, 48);
W[13] = GET_UINT32_BE(buf_ptr, 52);
W[14] = GET_UINT32_BE(buf_ptr, 56);
W[15] = GET_UINT32_BE(buf_ptr, 60);
P(A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], W[0], K[0]);
P(A[7], A[0], A[1], A[2], A[3], A[4], A[5], A[6], W[1], K[1]);
P(A[6], A[7], A[0], A[1], A[2], A[3], A[4], A[5], W[2], K[2]);
P(A[5], A[6], A[7], A[0], A[1], A[2], A[3], A[4], W[3], K[3]);
P(A[4], A[5], A[6], A[7], A[0], A[1], A[2], A[3], W[4], K[4]);
P(A[3], A[4], A[5], A[6], A[7], A[0], A[1], A[2], W[5], K[5]);
P(A[2], A[3], A[4], A[5], A[6], A[7], A[0], A[1], W[6], K[6]);
P(A[1], A[2], A[3], A[4], A[5], A[6], A[7], A[0], W[7], K[7]);
P(A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], W[8], K[8]);
P(A[7], A[0], A[1], A[2], A[3], A[4], A[5], A[6], W[9], K[9]);
P(A[6], A[7], A[0], A[1], A[2], A[3], A[4], A[5], W[10], K[10]);
P(A[5], A[6], A[7], A[0], A[1], A[2], A[3], A[4], W[11], K[11]);
P(A[4], A[5], A[6], A[7], A[0], A[1], A[2], A[3], W[12], K[12]);
P(A[3], A[4], A[5], A[6], A[7], A[0], A[1], A[2], W[13], K[13]);
P(A[2], A[3], A[4], A[5], A[6], A[7], A[0], A[1], W[14], K[14]);
P(A[1], A[2], A[3], A[4], A[5], A[6], A[7], A[0], W[15], K[15]);
P(A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], R(16), K[16]);
P(A[7], A[0], A[1], A[2], A[3], A[4], A[5], A[6], R(17), K[17]);
P(A[6], A[7], A[0], A[1], A[2], A[3], A[4], A[5], R(18), K[18]);
P(A[5], A[6], A[7], A[0], A[1], A[2], A[3], A[4], R(19), K[19]);
P(A[4], A[5], A[6], A[7], A[0], A[1], A[2], A[3], R(20), K[20]);
P(A[3], A[4], A[5], A[6], A[7], A[0], A[1], A[2], R(21), K[21]);
P(A[2], A[3], A[4], A[5], A[6], A[7], A[0], A[1], R(22), K[22]);
P(A[1], A[2], A[3], A[4], A[5], A[6], A[7], A[0], R(23), K[23]);
P(A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], R(24), K[24]);
P(A[7], A[0], A[1], A[2], A[3], A[4], A[5], A[6], R(25), K[25]);
P(A[6], A[7], A[0], A[1], A[2], A[3], A[4], A[5], R(26), K[26]);
P(A[5], A[6], A[7], A[0], A[1], A[2], A[3], A[4], R(27), K[27]);
P(A[4], A[5], A[6], A[7], A[0], A[1], A[2], A[3], R(28), K[28]);
P(A[3], A[4], A[5], A[6], A[7], A[0], A[1], A[2], R(29), K[29]);
P(A[2], A[3], A[4], A[5], A[6], A[7], A[0], A[1], R(30), K[30]);
P(A[1], A[2], A[3], A[4], A[5], A[6], A[7], A[0], R(31), K[31]);
P(A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], R(32), K[32]);
P(A[7], A[0], A[1], A[2], A[3], A[4], A[5], A[6], R(33), K[33]);
P(A[6], A[7], A[0], A[1], A[2], A[3], A[4], A[5], R(34), K[34]);
P(A[5], A[6], A[7], A[0], A[1], A[2], A[3], A[4], R(35), K[35]);
P(A[4], A[5], A[6], A[7], A[0], A[1], A[2], A[3], R(36), K[36]);
P(A[3], A[4], A[5], A[6], A[7], A[0], A[1], A[2], R(37), K[37]);
P(A[2], A[3], A[4], A[5], A[6], A[7], A[0], A[1], R(38), K[38]);
P(A[1], A[2], A[3], A[4], A[5], A[6], A[7], A[0], R(39), K[39]);
P(A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], R(40), K[40]);
P(A[7], A[0], A[1], A[2], A[3], A[4], A[5], A[6], R(41), K[41]);
P(A[6], A[7], A[0], A[1], A[2], A[3], A[4], A[5], R(42), K[42]);
P(A[5], A[6], A[7], A[0], A[1], A[2], A[3], A[4], R(43), K[43]);
P(A[4], A[5], A[6], A[7], A[0], A[1], A[2], A[3], R(44), K[44]);
P(A[3], A[4], A[5], A[6], A[7], A[0], A[1], A[2], R(45), K[45]);
P(A[2], A[3], A[4], A[5], A[6], A[7], A[0], A[1], R(46), K[46]);
P(A[1], A[2], A[3], A[4], A[5], A[6], A[7], A[0], R(47), K[47]);
P(A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], R(48), K[48]);
P(A[7], A[0], A[1], A[2], A[3], A[4], A[5], A[6], R(49), K[49]);
P(A[6], A[7], A[0], A[1], A[2], A[3], A[4], A[5], R(50), K[50]);
P(A[5], A[6], A[7], A[0], A[1], A[2], A[3], A[4], R(51), K[51]);
P(A[4], A[5], A[6], A[7], A[0], A[1], A[2], A[3], R(52), K[52]);
P(A[3], A[4], A[5], A[6], A[7], A[0], A[1], A[2], R(53), K[53]);
P(A[2], A[3], A[4], A[5], A[6], A[7], A[0], A[1], R(54), K[54]);
P(A[1], A[2], A[3], A[4], A[5], A[6], A[7], A[0], R(55), K[55]);
P(A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], R(56), K[56]);
P(A[7], A[0], A[1], A[2], A[3], A[4], A[5], A[6], R(57), K[57]);
P(A[6], A[7], A[0], A[1], A[2], A[3], A[4], A[5], R(58), K[58]);
P(A[5], A[6], A[7], A[0], A[1], A[2], A[3], A[4], R(59), K[59]);
P(A[4], A[5], A[6], A[7], A[0], A[1], A[2], A[3], R(60), K[60]);
P(A[3], A[4], A[5], A[6], A[7], A[0], A[1], A[2], R(61), K[61]);
P(A[2], A[3], A[4], A[5], A[6], A[7], A[0], A[1], R(62), K[62]);
P(A[1], A[2], A[3], A[4], A[5], A[6], A[7], A[0], R(63), K[63]);
midstate->state[0] = 0x6A09E667 + A[0];
midstate->state[1] = 0xBB67AE85 + A[1];
midstate->state[2] = 0x3C6EF372 + A[2];
midstate->state[3] = 0xA54FF53A + A[3];
midstate->state[4] = 0x510E527F + A[4];
midstate->state[5] = 0x9B05688C + A[5];
midstate->state[6] = 0x1F83D9AB + A[6];
midstate->state[7] = 0x5BE0CD19 + A[7];
midstate->buffer[16] = 0x80;
memcpy(midstate->buffer, buf_ptr + 64, 12);
}
IRAM_ATTR bool make_double_sha(_sha256_context* midstate)
{
uint32_t temp1, temp2;
uint8_t temp3, temp4;
uint32_t W[64] = { GET_UINT32_BE(midstate->buffer, 0), GET_UINT32_BE(midstate->buffer, 4),
GET_UINT32_BE(midstate->buffer, 8), GET_UINT32_BE(midstate->buffer, 12), 2147483648, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 640, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
uint32_t A[8] = { midstate->state[0], midstate->state[1], midstate->state[2], midstate->state[3],
midstate->state[4], midstate->state[5], midstate->state[6], midstate->state[7] };
union {
uint32_t num;
uint8_t b[4];
} u;
uint8_t* p = NULL;
P(A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], W[0], K[0]);
P(A[7], A[0], A[1], A[2], A[3], A[4], A[5], A[6], W[1], K[1]);
P(A[6], A[7], A[0], A[1], A[2], A[3], A[4], A[5], W[2], K[2]);
P(A[5], A[6], A[7], A[0], A[1], A[2], A[3], A[4], W[3], K[3]);
P(A[4], A[5], A[6], A[7], A[0], A[1], A[2], A[3], W[4], K[4]);
P(A[3], A[4], A[5], A[6], A[7], A[0], A[1], A[2], W[5], K[5]);
P(A[2], A[3], A[4], A[5], A[6], A[7], A[0], A[1], W[6], K[6]);
P(A[1], A[2], A[3], A[4], A[5], A[6], A[7], A[0], W[7], K[7]);
P(A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], W[8], K[8]);
P(A[7], A[0], A[1], A[2], A[3], A[4], A[5], A[6], W[9], K[9]);
P(A[6], A[7], A[0], A[1], A[2], A[3], A[4], A[5], W[10], K[10]);
P(A[5], A[6], A[7], A[0], A[1], A[2], A[3], A[4], W[11], K[11]);
P(A[4], A[5], A[6], A[7], A[0], A[1], A[2], A[3], W[12], K[12]);
P(A[3], A[4], A[5], A[6], A[7], A[0], A[1], A[2], W[13], K[13]);
P(A[2], A[3], A[4], A[5], A[6], A[7], A[0], A[1], W[14], K[14]);
P(A[1], A[2], A[3], A[4], A[5], A[6], A[7], A[0], W[15], K[15]);
P(A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], R(16), K[16]);
P(A[7], A[0], A[1], A[2], A[3], A[4], A[5], A[6], R(17), K[17]);
P(A[6], A[7], A[0], A[1], A[2], A[3], A[4], A[5], R(18), K[18]);
P(A[5], A[6], A[7], A[0], A[1], A[2], A[3], A[4], R(19), K[19]);
P(A[4], A[5], A[6], A[7], A[0], A[1], A[2], A[3], R(20), K[20]);
P(A[3], A[4], A[5], A[6], A[7], A[0], A[1], A[2], R(21), K[21]);
P(A[2], A[3], A[4], A[5], A[6], A[7], A[0], A[1], R(22), K[22]);
P(A[1], A[2], A[3], A[4], A[5], A[6], A[7], A[0], R(23), K[23]);
P(A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], R(24), K[24]);
P(A[7], A[0], A[1], A[2], A[3], A[4], A[5], A[6], R(25), K[25]);
P(A[6], A[7], A[0], A[1], A[2], A[3], A[4], A[5], R(26), K[26]);
P(A[5], A[6], A[7], A[0], A[1], A[2], A[3], A[4], R(27), K[27]);
P(A[4], A[5], A[6], A[7], A[0], A[1], A[2], A[3], R(28), K[28]);
P(A[3], A[4], A[5], A[6], A[7], A[0], A[1], A[2], R(29), K[29]);
P(A[2], A[3], A[4], A[5], A[6], A[7], A[0], A[1], R(30), K[30]);
P(A[1], A[2], A[3], A[4], A[5], A[6], A[7], A[0], R(31), K[31]);
P(A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], R(32), K[32]);
P(A[7], A[0], A[1], A[2], A[3], A[4], A[5], A[6], R(33), K[33]);
P(A[6], A[7], A[0], A[1], A[2], A[3], A[4], A[5], R(34), K[34]);
P(A[5], A[6], A[7], A[0], A[1], A[2], A[3], A[4], R(35), K[35]);
P(A[4], A[5], A[6], A[7], A[0], A[1], A[2], A[3], R(36), K[36]);
P(A[3], A[4], A[5], A[6], A[7], A[0], A[1], A[2], R(37), K[37]);
P(A[2], A[3], A[4], A[5], A[6], A[7], A[0], A[1], R(38), K[38]);
P(A[1], A[2], A[3], A[4], A[5], A[6], A[7], A[0], R(39), K[39]);
P(A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], R(40), K[40]);
P(A[7], A[0], A[1], A[2], A[3], A[4], A[5], A[6], R(41), K[41]);
P(A[6], A[7], A[0], A[1], A[2], A[3], A[4], A[5], R(42), K[42]);
P(A[5], A[6], A[7], A[0], A[1], A[2], A[3], A[4], R(43), K[43]);
P(A[4], A[5], A[6], A[7], A[0], A[1], A[2], A[3], R(44), K[44]);
P(A[3], A[4], A[5], A[6], A[7], A[0], A[1], A[2], R(45), K[45]);
P(A[2], A[3], A[4], A[5], A[6], A[7], A[0], A[1], R(46), K[46]);
P(A[1], A[2], A[3], A[4], A[5], A[6], A[7], A[0], R(47), K[47]);
P(A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], R(48), K[48]);
P(A[7], A[0], A[1], A[2], A[3], A[4], A[5], A[6], R(49), K[49]);
P(A[6], A[7], A[0], A[1], A[2], A[3], A[4], A[5], R(50), K[50]);
P(A[5], A[6], A[7], A[0], A[1], A[2], A[3], A[4], R(51), K[51]);
P(A[4], A[5], A[6], A[7], A[0], A[1], A[2], A[3], R(52), K[52]);
P(A[3], A[4], A[5], A[6], A[7], A[0], A[1], A[2], R(53), K[53]);
P(A[2], A[3], A[4], A[5], A[6], A[7], A[0], A[1], R(54), K[54]);
P(A[1], A[2], A[3], A[4], A[5], A[6], A[7], A[0], R(55), K[55]);
P(A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], R(56), K[56]);
P(A[7], A[0], A[1], A[2], A[3], A[4], A[5], A[6], R(57), K[57]);
P(A[6], A[7], A[0], A[1], A[2], A[3], A[4], A[5], R(58), K[58]);
P(A[5], A[6], A[7], A[0], A[1], A[2], A[3], A[4], R(59), K[59]);
P(A[4], A[5], A[6], A[7], A[0], A[1], A[2], A[3], R(60), K[60]);
P(A[3], A[4], A[5], A[6], A[7], A[0], A[1], A[2], R(61), K[61]);
P(A[2], A[3], A[4], A[5], A[6], A[7], A[0], A[1], R(62), K[62]);
P(A[1], A[2], A[3], A[4], A[5], A[6], A[7], A[0], R(63), K[63]);
PUT_UINT32_BE(midstate->state[0] + A[0], midstate->buffer, 0);
PUT_UINT32_BE(midstate->state[1] + A[1], midstate->buffer, 4);
PUT_UINT32_BE(midstate->state[2] + A[2], midstate->buffer, 8);
PUT_UINT32_BE(midstate->state[3] + A[3], midstate->buffer, 12);
PUT_UINT32_BE(midstate->state[4] + A[4], midstate->buffer, 16);
PUT_UINT32_BE(midstate->state[5] + A[5], midstate->buffer, 20);
PUT_UINT32_BE(midstate->state[6] + A[6], midstate->buffer, 24);
PUT_UINT32_BE(midstate->state[7] + A[7], midstate->buffer, 28);
/* Calculate the second hash (double SHA-256) */
A[0] = 0x6A09E667;
A[1] = 0xBB67AE85;
A[2] = 0x3C6EF372;
A[3] = 0xA54FF53A;
A[4] = 0x510E527F;
A[5] = 0x9B05688C;
A[6] = 0x1F83D9AB;
A[7] = 0x5BE0CD19;
midstate->buffer[32] = 0x80;
W[0] = GET_UINT32_BE(midstate->buffer, 0);
W[1] = GET_UINT32_BE(midstate->buffer, 4);
W[2] = GET_UINT32_BE(midstate->buffer, 8);
W[3] = GET_UINT32_BE(midstate->buffer, 12);
W[4] = GET_UINT32_BE(midstate->buffer, 16);
W[5] = GET_UINT32_BE(midstate->buffer, 20);
W[6] = GET_UINT32_BE(midstate->buffer, 24);
W[7] = GET_UINT32_BE(midstate->buffer, 28);
W[8] = GET_UINT32_BE(midstate->buffer, 32);
W[9] = GET_UINT32_BE(midstate->buffer, 36);
W[10] = GET_UINT32_BE(midstate->buffer, 40);
W[11] = GET_UINT32_BE(midstate->buffer, 44);
W[12] = GET_UINT32_BE(midstate->buffer, 48);
W[13] = GET_UINT32_BE(midstate->buffer, 52);
W[14] = 0;
W[15] = 256;
P(A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], W[0], K[0]);
P(A[7], A[0], A[1], A[2], A[3], A[4], A[5], A[6], W[1], K[1]);
P(A[6], A[7], A[0], A[1], A[2], A[3], A[4], A[5], W[2], K[2]);
P(A[5], A[6], A[7], A[0], A[1], A[2], A[3], A[4], W[3], K[3]);
P(A[4], A[5], A[6], A[7], A[0], A[1], A[2], A[3], W[4], K[4]);
P(A[3], A[4], A[5], A[6], A[7], A[0], A[1], A[2], W[5], K[5]);
P(A[2], A[3], A[4], A[5], A[6], A[7], A[0], A[1], W[6], K[6]);
P(A[1], A[2], A[3], A[4], A[5], A[6], A[7], A[0], W[7], K[7]);
P(A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], W[8], K[8]);
P(A[7], A[0], A[1], A[2], A[3], A[4], A[5], A[6], W[9], K[9]);
P(A[6], A[7], A[0], A[1], A[2], A[3], A[4], A[5], W[10], K[10]);
P(A[5], A[6], A[7], A[0], A[1], A[2], A[3], A[4], W[11], K[11]);
P(A[4], A[5], A[6], A[7], A[0], A[1], A[2], A[3], W[12], K[12]);
P(A[3], A[4], A[5], A[6], A[7], A[0], A[1], A[2], W[13], K[13]);
P(A[2], A[3], A[4], A[5], A[6], A[7], A[0], A[1], W[14], K[14]);
P(A[1], A[2], A[3], A[4], A[5], A[6], A[7], A[0], W[15], K[15]);
P(A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], R(16), K[16]);
P(A[7], A[0], A[1], A[2], A[3], A[4], A[5], A[6], R(17), K[17]);
P(A[6], A[7], A[0], A[1], A[2], A[3], A[4], A[5], R(18), K[18]);
P(A[5], A[6], A[7], A[0], A[1], A[2], A[3], A[4], R(19), K[19]);
P(A[4], A[5], A[6], A[7], A[0], A[1], A[2], A[3], R(20), K[20]);
P(A[3], A[4], A[5], A[6], A[7], A[0], A[1], A[2], R(21), K[21]);
P(A[2], A[3], A[4], A[5], A[6], A[7], A[0], A[1], R(22), K[22]);
P(A[1], A[2], A[3], A[4], A[5], A[6], A[7], A[0], R(23), K[23]);
P(A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], R(24), K[24]);
P(A[7], A[0], A[1], A[2], A[3], A[4], A[5], A[6], R(25), K[25]);
P(A[6], A[7], A[0], A[1], A[2], A[3], A[4], A[5], R(26), K[26]);
P(A[5], A[6], A[7], A[0], A[1], A[2], A[3], A[4], R(27), K[27]);
P(A[4], A[5], A[6], A[7], A[0], A[1], A[2], A[3], R(28), K[28]);
P(A[3], A[4], A[5], A[6], A[7], A[0], A[1], A[2], R(29), K[29]);
P(A[2], A[3], A[4], A[5], A[6], A[7], A[0], A[1], R(30), K[30]);
P(A[1], A[2], A[3], A[4], A[5], A[6], A[7], A[0], R(31), K[31]);
P(A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], R(32), K[32]);
P(A[7], A[0], A[1], A[2], A[3], A[4], A[5], A[6], R(33), K[33]);
P(A[6], A[7], A[0], A[1], A[2], A[3], A[4], A[5], R(34), K[34]);
P(A[5], A[6], A[7], A[0], A[1], A[2], A[3], A[4], R(35), K[35]);
P(A[4], A[5], A[6], A[7], A[0], A[1], A[2], A[3], R(36), K[36]);
P(A[3], A[4], A[5], A[6], A[7], A[0], A[1], A[2], R(37), K[37]);
P(A[2], A[3], A[4], A[5], A[6], A[7], A[0], A[1], R(38), K[38]);
P(A[1], A[2], A[3], A[4], A[5], A[6], A[7], A[0], R(39), K[39]);
P(A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], R(40), K[40]);
P(A[7], A[0], A[1], A[2], A[3], A[4], A[5], A[6], R(41), K[41]);
P(A[6], A[7], A[0], A[1], A[2], A[3], A[4], A[5], R(42), K[42]);
P(A[5], A[6], A[7], A[0], A[1], A[2], A[3], A[4], R(43), K[43]);
P(A[4], A[5], A[6], A[7], A[0], A[1], A[2], A[3], R(44), K[44]);
P(A[3], A[4], A[5], A[6], A[7], A[0], A[1], A[2], R(45), K[45]);
P(A[2], A[3], A[4], A[5], A[6], A[7], A[0], A[1], R(46), K[46]);
P(A[1], A[2], A[3], A[4], A[5], A[6], A[7], A[0], R(47), K[47]);
P(A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], R(48), K[48]);
P(A[7], A[0], A[1], A[2], A[3], A[4], A[5], A[6], R(49), K[49]);
P(A[6], A[7], A[0], A[1], A[2], A[3], A[4], A[5], R(50), K[50]);
P(A[5], A[6], A[7], A[0], A[1], A[2], A[3], A[4], R(51), K[51]);
P(A[4], A[5], A[6], A[7], A[0], A[1], A[2], A[3], R(52), K[52]);
P(A[3], A[4], A[5], A[6], A[7], A[0], A[1], A[2], R(53), K[53]);
P(A[2], A[3], A[4], A[5], A[6], A[7], A[0], A[1], R(54), K[54]);
P(A[1], A[2], A[3], A[4], A[5], A[6], A[7], A[0], R(55), K[55]);
P(A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], R(56), K[56]);
P(A[7], A[0], A[1], A[2], A[3], A[4], A[5], A[6], R(57), K[57]);
P(A[6], A[7], A[0], A[1], A[2], A[3], A[4], A[5], R(58), K[58]);
P(A[5], A[6], A[7], A[0], A[1], A[2], A[3], A[4], R(59), K[59]);
P(A[4], A[5], A[6], A[7], A[0], A[1], A[2], A[3], R(60), K[60]);
//CHECK_BYTES(0x5BE0CD19, A[7], 0);
P(A[3], A[4], A[5], A[6], A[7], A[0], A[1], A[2], R(61), K[61]);
//CHECK_BYTES(0x1F83D9AB, A[6], 4);
P(A[2], A[3], A[4], A[5], A[6], A[7], A[0], A[1], R(62), K[62]);
//CHECK_BYTES(0x9B05688C, A[5], 8);
P(A[1], A[2], A[3], A[4], A[5], A[6], A[7], A[0], R(63), K[63]);
/*CHECK_BYTES(0x510E527F, A[4], 12);
CHECK_BYTES(0xA54FF53A, A[3], 16);
CHECK_BYTES(0x3C6EF372, A[2], 20);
CHECK_BYTES(0xBB67AE85, A[1], 24);
CHECK_BYTES(0x6A09E667, A[0], 28);*/
PUT_UINT32_BE(midstate->state[0] + A[0], midstate->buffer, 0);
PUT_UINT32_BE(midstate->state[1] + A[1], midstate->buffer, 4);
PUT_UINT32_BE(midstate->state[2] + A[2], midstate->buffer, 8);
PUT_UINT32_BE(midstate->state[3] + A[3], midstate->buffer, 12);
PUT_UINT32_BE(midstate->state[4] + A[4], midstate->buffer, 16);
PUT_UINT32_BE(midstate->state[5] + A[5], midstate->buffer, 20);
PUT_UINT32_BE(midstate->state[6] + A[6], midstate->buffer, 24);
PUT_UINT32_BE(midstate->state[7] + A[7], midstate->buffer, 28);
return true;
}
static void minertask(void* pctx)
{
assert(pctx);
task_ctx* tctx ;
headerandtarget header;
bool* newwork = &tctx->newwork;
while (1) {
if (*newwork) {
*newwork = false;
break;
}
vTaskDelay(1 / portTICK_PERIOD_MS);
}
header = tctx->ht;
uint32_t* hashespersec = &tctx->hashespersec;
while (true) {
_sha256_context midstate_cached = { 0 };
calc_midstate((uint8_t*)&header.bh, &midstate_cached);
*((uint32_t*)&midstate_cached.buffer[12]) = tctx->nonce_start;
_sha256_context ctx = midstate_cached;
while (true) {
//const bool within = verify_nonce(&ctx, header.target);
const bool within = false;
if (__builtin_expect(within, false)) {
*tctx->nonce_solution = *((uint32_t*)&midstate_cached.buffer[12]);
*tctx->solution_found = true;
/* wait until we have a new header to work on */
while (1) {
if (__builtin_expect(*newwork, false)) {
*newwork = false;
header = tctx->ht;
break;
}
vTaskDelay(1 / portTICK_PERIOD_MS);
}
break;
}
if (__builtin_expect(*newwork, false)) {
*newwork = false;
header = tctx->ht;
break;
}
*hashespersec = (*((uint32_t*)&midstate_cached.buffer[12]) += 1) - tctx->nonce_start;
ctx = midstate_cached;
}
}
}
bool check_solutions(void* ctx)
{
assert(ctx);
miner_ctx* mctx;
/* missing memory barrier but appers to work */
/* FIXME: find upper bound for solution len ?*/
if (!mctx->solution_found) {
return false;
}
uint8_t solution[600];
memcpy(solution, &mctx->bh, 80);
solution[80] = 0x01; /* number of transactions, solo mining :( */
memcpy(solution + 81, mctx->rawtx, mctx->txlen);
mctx->cb(mctx->cbctx, solution, 81 + mctx->txlen);
mctx->solution_found = false;
return true;
}
void check_speed(void* ctx, uint32_t* speed)
{
/* missing memory barrier but appers to work */
assert(ctx);
miner_ctx* mctx;
*speed = ((mctx->ctx1.hashespersec + mctx->ctx2.hashespersec) / ((esp_timer_get_time() - mctx->start) / 1000000.0));
}

View File

@ -1,22 +0,0 @@
#ifndef jadeSHA256_H_
#define jadeSHA256_H_
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
typedef struct _sha256_context {
uint8_t buffer[64];
uint32_t state[8];
} _sha256_context;
/* Calculate midstate */
IRAM_ATTR void calc_midstate(uint8_t* buf_ptr, _sha256_context* midstate);
IRAM_ATTR bool make_double_sha(_sha256_context* midstate);
/* We need a way to tell the miner to us that there is a solution */
typedef void (*solution_cb)(void* ctx, const uint8_t*, uint32_t);
#endif /* jadeSHA256_H_ */

View File

@ -13,6 +13,32 @@
#define HASH_SIZE 32
//------------- JADE
#define SHR(x, n) ((x & 0xFFFFFFFF) >> n)
#define ROTR(x, n) ((x >> n) | (x << ((sizeof(x) << 3) - n)))
#define S0(x) (ROTR(x, 7) ^ ROTR(x, 18) ^ SHR(x, 3))
#define S1(x) (ROTR(x, 17) ^ ROTR(x, 19) ^ SHR(x, 10))
#define S2(x) (ROTR(x, 2) ^ ROTR(x, 13) ^ ROTR(x, 22))
#define S3(x) (ROTR(x, 6) ^ ROTR(x, 11) ^ ROTR(x, 25))
#define F0(x, y, z) ((x & y) | (z & (x | y)))
#define F1(x, y, z) (z ^ (x & (y ^ z)))
#define RJ(t) (W[t] = S1(W[t - 2]) + W[t - 7] + S0(W[t - 15]) + W[t - 16])
#define P(a, b, c, d, e, f, g, h, x, K) \
{ \
temp1 = h + S3(e) + F1(e, f, g) + K + x; \
temp2 = S2(a) + F0(a, b, c); \
d += temp1; \
h = temp1 + temp2; \
}
//--------------
IRAM_ATTR static inline uint32_t rotlFixed(uint32_t x, uint32_t y)
{
return (x << y) | (x >> (sizeof(y) * 8 - y));
@ -56,7 +82,12 @@ IRAM_ATTR static inline uint32_t rotrFixed(uint32_t x, uint32_t y)
)
#define RND1(j) \
t0 = h(j) + Sigma1(e(j)) + Ch(e(j), f(j), g(j)) + K[i+j] + SCHED1(j); \
t0 = h(j) + Sigma1(e(j)) + Ch(e(j), f(j), g(j)) + K[j] + SCHED1(j); \
t1 = Sigma0(a(j)) + Maj(a(j), b(j), c(j)); \
d(j) += t0; \
h(j) = t0 + t1
#define RND(j) \
t0 = h(j) + Sigma1(e(j)) + Ch(e(j), f(j), g(j)) + K[j] + SCHED(j); \
t1 = Sigma0(a(j)) + Maj(a(j), b(j), c(j)); \
d(j) += t0; \
h(j) = t0 + t1
@ -66,7 +97,6 @@ IRAM_ATTR static inline uint32_t rotrFixed(uint32_t x, uint32_t y)
d(j) += t0; \
h(j) = t0 + t1
//DRAM_ATTR static const uint32_t K[] = {
DRAM_ATTR static const uint32_t K[64] = {
0x428A2F98L, 0x71374491L, 0xB5C0FBCFL, 0xE9B5DBA5L, 0x3956C25BL,
0x59F111F1L, 0x923F82A4L, 0xAB1C5ED5L, 0xD807AA98L, 0x12835B01L,
@ -83,11 +113,11 @@ DRAM_ATTR static const uint32_t K[64] = {
0x90BEFFFAL, 0xA4506CEBL, 0xBEF9A3F7L, 0xC67178F2L
};
IRAM_ATTR static int Transform_Sha256(nerd_sha256* sha256, const uint8_t* data)
IRAM_ATTR inline static int Transform_Sha256(nerd_sha256* sha256, const uint8_t* data)
{
uint32_t S[8], t0, t1;
int i;
uint32_t W[NERD_BLOCK_SIZE/sizeof(uint32_t)];
IRAM_DATA_ATTR uint32_t W[NERD_BLOCK_SIZE/sizeof(uint32_t)];
/* Copy digest to working vars */
S[0] = sha256->digest[0];
@ -104,7 +134,6 @@ IRAM_ATTR static int Transform_Sha256(nerd_sha256* sha256, const uint8_t* data)
RND1( 4); RND1( 5); RND1( 6); RND1( 7);
RND1( 8); RND1( 9); RND1(10); RND1(11);
RND1(12); RND1(13); RND1(14); RND1(15);
/* 64 operations, partially loop unrolled */
for (i = 16; i < 64; i += 16) {
RNDN( 0); RNDN( 1); RNDN( 2); RNDN( 3);
RNDN( 4); RNDN( 5); RNDN( 6); RNDN( 7);
@ -138,7 +167,7 @@ IRAM_ATTR static void ByteReverseWords(uint32_t* out, const uint32_t* in, uint32
}
IRAM_ATTR static int nerd_update(nerd_sha256* sha256, uint8_t* data, uint32_t len)
static int nerd_update(nerd_sha256* sha256, uint8_t* data, uint32_t len)
{
int ret = 0;
uint32_t blocksLen;
@ -198,48 +227,8 @@ IRAM_ATTR static int nerd_update(nerd_sha256* sha256, uint8_t* data, uint32_t le
return ret;
}
IRAM_ATTR static int nerd_finishSHA(nerd_sha256* sha256, uint8_t* hash){
int ret;
uint8_t* local;
local = (uint8_t*)sha256->buffer;
local[sha256->buffLen++] = 0x80; // add 1
//Padd with zeros
if (sha256->buffLen > NERD_PAD_SIZE) {
XMEMSET(&local[sha256->buffLen], 0, NERD_BLOCK_SIZE - sha256->buffLen);
sha256->buffLen += NERD_BLOCK_SIZE - sha256->buffLen;
ByteReverseWords(sha256->buffer, sha256->buffer, NERD_BLOCK_SIZE);
XTRANSFORM(sha256, (const uint8_t*)local);
sha256->buffLen = 0;
}
XMEMSET(&local[sha256->buffLen], 0, NERD_PAD_SIZE - sha256->buffLen);
// put lengths in bits
sha256->hiLen = (sha256->loLen >> (8 * sizeof(sha256->loLen) - 3)) + (sha256->hiLen << 3);
sha256->loLen = sha256->loLen << 3;
ByteReverseWords(sha256->buffer, sha256->buffer, NERD_BLOCK_SIZE);
// ! length ordering dependent on digest endian type !
XMEMCPY(&local[NERD_PAD_SIZE], &sha256->hiLen, sizeof(uint32_t));
XMEMCPY(&local[NERD_PAD_SIZE + sizeof(uint32_t)], &sha256->loLen, sizeof(uint32_t));
XTRANSFORM(sha256, (const uint8_t*)local);
ByteReverseWords(sha256->digest, sha256->digest, NERD_DIGEST_SIZE);
//Copy temp hash
XMEMCPY(hash, sha256->digest, NERD_DIGEST_SIZE);
return 0;
}
IRAM_ATTR int nerd_midstate(nerd_sha256* sha256, uint8_t* data, uint32_t len)
int nerd_midstate(nerd_sha256* sha256, uint8_t* data, uint32_t len)
{
int ret = 0;
uint32_t blocksLen;
@ -266,42 +255,96 @@ IRAM_ATTR int nerd_midstate(nerd_sha256* sha256, uint8_t* data, uint32_t len)
return 0;
}
/*
IRAM_ATTR int nerd_double_sha(nerd_sha256* midstate, uint8_t* data, uint8_t* doubleHash)
IRAM_ATTR int nerd_double_sha2(nerd_sha256* midstate, uint8_t* dataIn, uint8_t* doubleHash)
{
nerd_sha256 sha256;
int ret = 0;
uint8_t hash[32];
uint32_t S[8], t0, t1;
uint32_t W[16];
int i;
uint8_t* data;
//Copy current context
XMEMCPY(&sha256, midstate, sizeof(nerd_sha256));
//*********** Init 1rst SHA ***********
uint8_t data1rstSHA[64] = { dataIn[3],dataIn[2],dataIn[1],dataIn[0],dataIn[7],dataIn[6],dataIn[5],dataIn[4],
dataIn[11],dataIn[10],dataIn[9],dataIn[8],dataIn[15],dataIn[14],dataIn[13],dataIn[12],
0,0,0,0x80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x80,0x02,0,0};
// ------ First SHA ------
nerd_update(&sha256,data,16); //Pending 16 bytes from 80 of blockheader
nerd_finishSHA(&sha256,hash);
data = data1rstSHA;
// Copy digest to working vars
S[0] = midstate->digest[0];
S[1] = midstate->digest[1];
S[2] = midstate->digest[2];
S[3] = midstate->digest[3];
S[4] = midstate->digest[4];
S[5] = midstate->digest[5];
S[6] = midstate->digest[6];
S[7] = midstate->digest[7];
// ------ Second SHA ------
//Init SHA context
XMEMSET(sha256.digest, 0, sizeof(sha256.digest));
sha256.digest[0] = 0x6A09E667L;
sha256.digest[1] = 0xBB67AE85L;
sha256.digest[2] = 0x3C6EF372L;
sha256.digest[3] = 0xA54FF53AL;
sha256.digest[4] = 0x510E527FL;
sha256.digest[5] = 0x9B05688CL;
sha256.digest[6] = 0x1F83D9ABL;
sha256.digest[7] = 0x5BE0CD19L;
RND1( 0); RND1( 1); RND1( 2); RND1( 3);
RND1( 4); RND1( 5); RND1( 6); RND1( 7);
RND1( 8); RND1( 9); RND1(10); RND1(11);
RND1(12); RND1(13); RND1(14); RND1(15);
// 64 operations, partially loop unrolled
for (i = 16; i < 64; i += 16) {
RNDN( 0); RNDN( 1); RNDN( 2); RNDN( 3);
RNDN( 4); RNDN( 5); RNDN( 6); RNDN( 7);
RNDN( 8); RNDN( 9); RNDN(10); RNDN(11);
RNDN(12); RNDN(13); RNDN(14); RNDN(15);
}
sha256.buffLen = 0;
sha256.loLen = 0;
sha256.hiLen = 0;
//endINIT Sha context
nerd_update(&sha256,hash,32);
nerd_finishSHA(&sha256,doubleHash);
// Add the working vars back into digest
S[0] += midstate->digest[0];
S[1] += midstate->digest[1];
S[2] += midstate->digest[2];
S[3] += midstate->digest[3];
S[4] += midstate->digest[4];
S[5] += midstate->digest[5];
S[6] += midstate->digest[6];
S[7] += midstate->digest[7];
//*********** end SHA_finish ***********
// ----- 2nd SHA ------------
uint32_t data2nSha[64] = {S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],
0x80000000,0,0,0,0,0,0,256};
data = (uint8_t*)data2nSha;
S[0] = 0x6A09E667L;
S[1] = 0xBB67AE85L;
S[2] = 0x3C6EF372L;
S[3] = 0xA54FF53AL;
S[4] = 0x510E527FL;
S[5] = 0x9B05688CL;
S[6] = 0x1F83D9ABL;
S[7] = 0x5BE0CD19L;
RND1( 0); RND1( 1); RND1( 2); RND1( 3);
RND1( 4); RND1( 5); RND1( 6); RND1( 7);
RND1( 8); RND1( 9); RND1(10); RND1(11);
RND1(12); RND1(13); RND1(14); RND1(15);
// 64 operations, partially loop unrolled
for (i = 16; i < 64; i += 16) {
RNDN( 0); RNDN( 1); RNDN( 2); RNDN( 3);
RNDN( 4); RNDN( 5); RNDN( 6); RNDN( 7);
RNDN( 8); RNDN( 9); RNDN(10); RNDN(11);
RNDN(12); RNDN(13); RNDN(14); RNDN(15);
}
// Add the working vars back into digest
S[0] += 0x6A09E667L;
S[1] += 0xBB67AE85L;
S[2] += 0x3C6EF372L;
S[3] += 0xA54FF53AL;
S[4] += 0x510E527FL;
S[5] += 0x9B05688CL;
S[6] += 0x1F83D9ABL;
S[7] += 0x5BE0CD19L;
ByteReverseWords((uint32_t*)doubleHash, S, NERD_DIGEST_SIZE);
return 0;
}
*/
IRAM_ATTR int nerd_double_sha(nerd_sha256* midstate, uint8_t* data, uint8_t* doubleHash)
{
@ -310,38 +353,25 @@ IRAM_ATTR int nerd_double_sha(nerd_sha256* midstate, uint8_t* data, uint8_t* dou
int ret = 0;
uint32_t blocksLen;
uint8_t* local;
uint8_t* local2;
uint8_t tmpHash[32];
uint8_t* hash;
//Copy current context
XMEMCPY(&sha256, midstate, sizeof(nerd_sha256));
sha256 = *midstate;
// ----- 1rst SHA ------------
//*********** ShaUpdate ***********
uint32_t len = 16; //Pending bytes to make the sha256
uint32_t tmp = sha256.loLen;
if ((sha256.loLen += len) < tmp) {
sha256.hiLen++;
}
local = (uint8_t*)sha256.buffer;
// save remainder
if (ret == 0 && len > 0) {
XMEMCPY(local, data, len);
sha256.buffLen = len;
}
XMEMCPY(local, data, 16); //Pending bytes to make the sha256
//*********** end update ***********
//*********** Init SHA_finish ***********
local[sha256.buffLen++] = 0x80; // add 1
XMEMSET(&local[sha256.buffLen], 0, NERD_PAD_SIZE - sha256.buffLen);
local[16] = 0x80; // add 1
//ADD final zeros
XMEMSET(&local[17], 0, 39); //NERD_PAD_SIZE - sha256.buffLen);
// put lengths in bits
sha256.hiLen = (sha256.loLen >> (8 * sizeof(sha256.loLen) - 3)) + (sha256.hiLen << 3);
sha256.loLen = sha256.loLen << 3;
sha256.hiLen = 0;
sha256.loLen = 640;
ByteReverseWords(sha256.buffer, sha256.buffer, NERD_BLOCK_SIZE);
@ -351,117 +381,30 @@ IRAM_ATTR int nerd_double_sha(nerd_sha256* midstate, uint8_t* data, uint8_t* dou
XTRANSFORM(&sha256, (const uint8_t*)local);
ByteReverseWords((uint32_t* )tmpHash, sha256.digest, NERD_DIGEST_SIZE);
hash = tmpHash;
//*********** end SHA_finish ***********
// ----- 2nd SHA ------------
//Init SHA context again
XMEMSET(sha256.digest, 0, sizeof(sha256.digest));
sha256.digest[0] = 0x6A09E667L;
sha256.digest[1] = 0xBB67AE85L;
sha256.digest[2] = 0x3C6EF372L;
sha256.digest[3] = 0xA54FF53AL;
sha256.digest[4] = 0x510E527FL;
sha256.digest[5] = 0x9B05688CL;
sha256.digest[6] = 0x1F83D9ABL;
sha256.digest[7] = 0x5BE0CD19L;
IRAM_DATA_ATTR nerd_sha256 secondSha256 = {
// Init with initial sha data
.digest = {0x6A09E667L, 0xBB67AE85L, 0x3C6EF372L, 0xA54FF53AL, 0x510E527FL, 0x9B05688CL, 0x1F83D9ABL, 0x5BE0CD19L},
// Init with past SHA done
.buffer = {sha256.digest[0],sha256.digest[1],sha256.digest[2],sha256.digest[3],sha256.digest[4],sha256.digest[5],sha256.digest[6],sha256.digest[7],
0x80000000,0,0,0,0,0,0,0}, // Init with past hash and 0x80
.buffLen = 32, // Bytes to hash
.loLen = 256, // Init to 256 bits
.hiLen = 0, // Inicializar a cero
.heap = NULL // Inicializar a NULL
};
sha256.buffLen = 0;
sha256.loLen = 0;
sha256.hiLen = 0;
//endINIT Sha context
//*********** ShaUpdate ***********
len = 32; //Current hash size to make the 2nd sha256
tmp = sha256.loLen;
if ((sha256.loLen += len) < tmp) {
sha256.hiLen++;
}
local2 = (uint8_t*)sha256.buffer;
// process any remainder from previous operation
if (sha256.buffLen > 0) {
blocksLen = min(len, NERD_BLOCK_SIZE - sha256.buffLen);
XMEMCPY(&local2[sha256.buffLen], hash, blocksLen);
sha256.buffLen += blocksLen;
hash += blocksLen;
len -= blocksLen;
if (sha256.buffLen == NERD_BLOCK_SIZE) {
ByteReverseWords(sha256.buffer, sha256.buffer, NERD_BLOCK_SIZE);
ret = XTRANSFORM(&sha256, (const uint8_t*)local2);
if (ret == 0)
sha256.buffLen = 0;
else
len = 0; // error
}
}
// process blocks
while (len >= NERD_BLOCK_SIZE) {
uint32_t* local32 = sha256.buffer;
XMEMCPY(local32, hash, NERD_BLOCK_SIZE);
hash += NERD_BLOCK_SIZE;
len -= NERD_BLOCK_SIZE;
ByteReverseWords(local32, local32, NERD_BLOCK_SIZE);
ret = XTRANSFORM(&sha256, (const uint8_t*)local32);
if (ret != 0)
break;
}
// save remainder
if (ret == 0 && len > 0) {
XMEMCPY(local2, hash, len);
sha256.buffLen = len;
}
//*********** end update ***********
//*********** Init SHA_finish ***********
//local2 = (uint8_t*)sha256.buffer;
local2[sha256.buffLen++] = 0x80; // add 1
//local2[33] = 0x80; // add 1
//Padd with zeros
if (sha256.buffLen > NERD_PAD_SIZE) {
XMEMSET(&local2[sha256.buffLen], 0, NERD_BLOCK_SIZE - sha256.buffLen);
sha256.buffLen += NERD_BLOCK_SIZE - sha256.buffLen;
//ByteReverseWords(sha256_2.buffer, sha256_2.buffer, NERD_BLOCK_SIZE);
XTRANSFORM(&sha256, (const uint8_t*)local2);
sha256.buffLen = 0;
}
XMEMSET(&local2[sha256.buffLen], 0, NERD_PAD_SIZE - sha256.buffLen);
// put lengths in bits
sha256.hiLen = (sha256.loLen >> (8 * sizeof(sha256.loLen) - 3)) + (sha256.hiLen << 3);
sha256.loLen = sha256.loLen << 3;
ByteReverseWords(sha256.buffer, sha256.buffer, NERD_BLOCK_SIZE);
local = (uint8_t*)secondSha256.buffer;
// ! length ordering dependent on digest endian type !
XMEMCPY(&local2[NERD_PAD_SIZE], &sha256.hiLen, sizeof(uint32_t));
XMEMCPY(&local2[NERD_PAD_SIZE + sizeof(uint32_t)], &sha256.loLen, sizeof(uint32_t));
XMEMCPY(&local[NERD_PAD_SIZE + sizeof(uint32_t)], &secondSha256.loLen, sizeof(uint32_t));
XTRANSFORM(&sha256, (const uint8_t*)local2);
XTRANSFORM(&secondSha256, (const uint8_t*)local);
ByteReverseWords((uint32_t*)doubleHash, sha256.digest, NERD_DIGEST_SIZE);
ByteReverseWords((uint32_t*)doubleHash, secondSha256.digest, NERD_DIGEST_SIZE);
return 0;
}

View File

@ -21,6 +21,8 @@ struct nerd_sha256 {
/* Calculate midstate */
IRAM_ATTR int nerd_midstate(nerd_sha256* sha256, uint8_t* data, uint32_t len);
IRAM_ATTR int nerd_double_sha(nerd_sha256* midstate, uint8_t* data, uint8_t* doubleHash);
//IRAM_ATTR int nerd_double_sha(nerd_sha256* midstate, uint8_t* data, uint8_t* doubleHash);
IRAM_ATTR int nerd_double_sha2(nerd_sha256* midstate, uint8_t* dataIn, uint8_t* doubleHash);
#endif /* nerdSHA256_H_ */

File diff suppressed because it is too large Load Diff

View File

@ -1278,175 +1278,273 @@ const unsigned char NotoSans_Bold[] PROGMEM = {
0x2b, 0x2b, 0x2b, 0x00, 0x2b, 0x2b, 0x18, 0x00
};
// Digital Numbers is a fixed width (web)font in a cool liquid-crystal display (LCD) style.
// https://github.com/s-a/digital-numbers-font/blob/gh-pages/dist/DigitalNumbers-Regular.ttf
// License: https://github.com/s-a/digital-numbers-font/blob/gh-pages/OFL.txt
// Supported glyphs: 0123456789 ,.:;KMGTPE
// This font is a subset of the full font to reduce array size, ONLY these characters are present:
// 0123456789 ,.:;
// array size is 2644
// array size is 4184
const unsigned char DigitalNumbers[] PROGMEM = {
0x00, 0x01, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x80, 0x00, 0x03, 0x00, 0x30, 0x63, 0x6d, 0x61, 0x70,
0x0d, 0x24, 0x11, 0x80, 0x00, 0x00, 0x00, 0xbc, 0x00, 0x00, 0x02, 0x2c, 0x63, 0x76, 0x74, 0x20,
0x00, 0x21, 0x02, 0x79, 0x00, 0x00, 0x02, 0xe8, 0x00, 0x00, 0x00, 0x04, 0x67, 0x6c, 0x79, 0x66,
0xc0, 0x73, 0xb8, 0x3c, 0x00, 0x00, 0x02, 0xec, 0x00, 0x00, 0x04, 0x61, 0x68, 0x65, 0x61, 0x64,
0x22, 0x9e, 0x74, 0x25, 0x00, 0x00, 0x07, 0x50, 0x00, 0x00, 0x00, 0x36, 0x68, 0x68, 0x65, 0x61,
0x02, 0x96, 0x03, 0x14, 0x00, 0x00, 0x07, 0x88, 0x00, 0x00, 0x00, 0x24, 0x68, 0x6d, 0x74, 0x78,
0x2b, 0xc0, 0x08, 0x89, 0x00, 0x00, 0x07, 0xac, 0x00, 0x00, 0x00, 0x40, 0x6c, 0x6f, 0x63, 0x61,
0x00, 0x00, 0x20, 0xd0, 0x00, 0x00, 0x07, 0xec, 0x00, 0x00, 0x00, 0x44, 0x6d, 0x61, 0x78, 0x70,
0x07, 0x4e, 0x11, 0x4e, 0x00, 0x00, 0x08, 0x30, 0x00, 0x00, 0x00, 0x20, 0x6e, 0x61, 0x6d, 0x65,
0x7b, 0xb1, 0x4f, 0xe5, 0x00, 0x00, 0x08, 0x50, 0x00, 0x00, 0x01, 0x8c, 0x4f, 0x53, 0x2f, 0x32,
0x56, 0xf0, 0x61, 0xa3, 0x00, 0x00, 0x09, 0xdc, 0x00, 0x00, 0x00, 0x56, 0x70, 0x6f, 0x73, 0x74,
0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x34, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x03,
0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xcc,
0x00, 0x03, 0x00, 0x01, 0x00, 0x00, 0x01, 0x7c, 0x00, 0x04, 0x00, 0xb0, 0x00, 0x00, 0x00, 0x20,
0x00, 0x20, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x2c, 0x00, 0x2e, 0x00, 0x30, 0x00, 0x31,
0x00, 0x32, 0x00, 0x33, 0x00, 0x34, 0x00, 0x35, 0x00, 0x36, 0x00, 0x37, 0x00, 0x38, 0x00, 0x39,
0x00, 0x3a, 0x00, 0x3b, 0xff, 0xff, 0x00, 0x00, 0x00, 0x20, 0x00, 0x2c, 0x00, 0x2e, 0x00, 0x30,
0x00, 0x31, 0x00, 0x32, 0x00, 0x33, 0x00, 0x34, 0x00, 0x35, 0x00, 0x36, 0x00, 0x37, 0x00, 0x38,
0x00, 0x39, 0x00, 0x3a, 0x00, 0x3b, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x01, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x80, 0x00, 0x03, 0x00, 0x50, 0x46, 0x46, 0x54, 0x4d,
0x8c, 0xbf, 0x2d, 0x05, 0x00, 0x00, 0x10, 0x3c, 0x00, 0x00, 0x00, 0x1c, 0x4f, 0x53, 0x2f, 0x32,
0x57, 0x08, 0x60, 0xb5, 0x00, 0x00, 0x01, 0x58, 0x00, 0x00, 0x00, 0x56, 0x63, 0x6d, 0x61, 0x70,
0x2b, 0x1d, 0x57, 0xf6, 0x00, 0x00, 0x01, 0xf0, 0x00, 0x00, 0x01, 0x8a, 0x63, 0x76, 0x74, 0x20,
0x00, 0x21, 0x02, 0x79, 0x00, 0x00, 0x03, 0x7c, 0x00, 0x00, 0x00, 0x04, 0x67, 0x61, 0x73, 0x70,
0xff, 0xff, 0x00, 0x03, 0x00, 0x00, 0x10, 0x34, 0x00, 0x00, 0x00, 0x08, 0x67, 0x6c, 0x79, 0x66,
0x54, 0x33, 0x1d, 0x9f, 0x00, 0x00, 0x03, 0xb4, 0x00, 0x00, 0x07, 0x64, 0x68, 0x65, 0x61, 0x64,
0x14, 0xb4, 0x99, 0xc0, 0x00, 0x00, 0x00, 0xdc, 0x00, 0x00, 0x00, 0x36, 0x68, 0x68, 0x65, 0x61,
0x06, 0xda, 0x01, 0xcf, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x24, 0x68, 0x6d, 0x74, 0x78,
0x0f, 0x23, 0x06, 0x12, 0x00, 0x00, 0x01, 0xb0, 0x00, 0x00, 0x00, 0x3e, 0x6c, 0x6f, 0x63, 0x61,
0x13, 0x80, 0x11, 0xfa, 0x00, 0x00, 0x03, 0x80, 0x00, 0x00, 0x00, 0x32, 0x6d, 0x61, 0x78, 0x70,
0x00, 0x62, 0x00, 0x73, 0x00, 0x00, 0x01, 0x38, 0x00, 0x00, 0x00, 0x20, 0x6e, 0x61, 0x6d, 0x65,
0x41, 0x6d, 0x32, 0x9a, 0x00, 0x00, 0x0b, 0x18, 0x00, 0x00, 0x04, 0xc5, 0x70, 0x6f, 0x73, 0x74,
0x00, 0xd9, 0x01, 0x5c, 0x00, 0x00, 0x0f, 0xe0, 0x00, 0x00, 0x00, 0x52, 0x00, 0x01, 0x00, 0x00,
0x00, 0x01, 0x1a, 0x1c, 0xcc, 0x53, 0x37, 0xdb, 0x5f, 0x0f, 0x3c, 0xf5, 0x00, 0x0b, 0x03, 0xe8,
0x00, 0x00, 0x00, 0x00, 0xd1, 0x98, 0x6e, 0xf9, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xf3, 0xcd, 0x87,
0x00, 0x00, 0xff, 0x0b, 0x03, 0x09, 0x03, 0x34, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x03, 0xce, 0xfe, 0xc3, 0x00, 0x00, 0x03, 0x20,
0x00, 0x00, 0xff, 0xe4, 0x03, 0x09, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x01, 0x00, 0x00, 0x00, 0x18, 0x00, 0x42,
0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00,
0x00, 0x40, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0xdd, 0x01, 0x90, 0x00, 0x05,
0x00, 0x00, 0x02, 0x8a, 0x02, 0xbb, 0x00, 0x00, 0x00, 0x8c, 0x02, 0x8a, 0x02, 0xbb, 0x00, 0x00,
0x01, 0xdf, 0x00, 0x31, 0x01, 0x02, 0x00, 0x00, 0x02, 0x00, 0x05, 0x03, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x50, 0x66, 0x45, 0x64, 0x00, 0x40, 0x00, 0x20, 0x00, 0x54, 0x03, 0xce, 0xfe, 0xc3,
0x00, 0x00, 0x03, 0xce, 0x01, 0x3d, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 0x6c, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, 0x01, 0x4d, 0x00, 0x00, 0x03, 0x20, 0x00, 0x00,
0x00, 0x64, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x03, 0x20, 0x00, 0x90, 0x00, 0x90, 0x00, 0x93,
0x00, 0xb1, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0xb4, 0x00, 0x90, 0x00, 0x90, 0x01, 0x51,
0x01, 0x50, 0x00, 0xa0, 0x00, 0x90, 0x00, 0x9c, 0x00, 0x56, 0x00, 0x91, 0x00, 0x17, 0x00, 0x00,
0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x01, 0x00, 0x00,
0x00, 0x00, 0x00, 0x84, 0x00, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x04, 0x00, 0x68,
0x00, 0x00, 0x00, 0x16, 0x00, 0x10, 0x00, 0x03, 0x00, 0x06, 0x00, 0x20, 0x00, 0x2c, 0x00, 0x2e,
0x00, 0x3b, 0x00, 0x45, 0x00, 0x47, 0x00, 0x4b, 0x00, 0x4d, 0x00, 0x50, 0x00, 0x54, 0xff, 0xff,
0x00, 0x00, 0x00, 0x20, 0x00, 0x2c, 0x00, 0x2e, 0x00, 0x30, 0x00, 0x45, 0x00, 0x47, 0x00, 0x4b,
0x00, 0x4d, 0x00, 0x50, 0x00, 0x54, 0xff, 0xff, 0xff, 0xe3, 0xff, 0xd8, 0xff, 0xd7, 0xff, 0xd6,
0xff, 0xcd, 0xff, 0xcc, 0xff, 0xc9, 0xff, 0xc8, 0xff, 0xc6, 0xff, 0xc3, 0x00, 0x01, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20,
0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20,
0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x04,
0x00, 0x05, 0x00, 0x06, 0x00, 0x07, 0x00, 0x08, 0x00, 0x09, 0x00, 0x0a, 0x00, 0x0b, 0x00, 0x0c,
0x00, 0x0d, 0x00, 0x0e, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x04, 0x00, 0xb0, 0x00, 0x00, 0x00, 0x20,
0x00, 0x20, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x2c, 0x00, 0x2e, 0x00, 0x30, 0x00, 0x31,
0x00, 0x32, 0x00, 0x33, 0x00, 0x34, 0x00, 0x35, 0x00, 0x36, 0x00, 0x37, 0x00, 0x38, 0x00, 0x39,
0x00, 0x3a, 0x00, 0x3b, 0xff, 0xff, 0x00, 0x00, 0x00, 0x20, 0x00, 0x2c, 0x00, 0x2e, 0x00, 0x30,
0x00, 0x31, 0x00, 0x32, 0x00, 0x33, 0x00, 0x34, 0x00, 0x35, 0x00, 0x36, 0x00, 0x37, 0x00, 0x38,
0x00, 0x39, 0x00, 0x3a, 0x00, 0x3b, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x05, 0x00, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12,
0x00, 0x13, 0x00, 0x00, 0x00, 0x14, 0x00, 0x15, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x17, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20,
0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20,
0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x04,
0x00, 0x05, 0x00, 0x06, 0x00, 0x07, 0x00, 0x08, 0x00, 0x09, 0x00, 0x0a, 0x00, 0x0b, 0x00, 0x0c,
0x00, 0x0d, 0x00, 0x0e, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x04, 0x00, 0xb0, 0x00, 0x00, 0x00, 0x20,
0x00, 0x20, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x2c, 0x00, 0x2e, 0x00, 0x30, 0x00, 0x31,
0x00, 0x32, 0x00, 0x33, 0x00, 0x34, 0x00, 0x35, 0x00, 0x36, 0x00, 0x37, 0x00, 0x38, 0x00, 0x39,
0x00, 0x3a, 0x00, 0x3b, 0xff, 0xff, 0x00, 0x00, 0x00, 0x20, 0x00, 0x2c, 0x00, 0x2e, 0x00, 0x30,
0x00, 0x31, 0x00, 0x32, 0x00, 0x33, 0x00, 0x34, 0x00, 0x35, 0x00, 0x36, 0x00, 0x37, 0x00, 0x38,
0x00, 0x39, 0x00, 0x3a, 0x00, 0x3b, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20,
0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20,
0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x04,
0x00, 0x05, 0x00, 0x06, 0x00, 0x07, 0x00, 0x08, 0x00, 0x09, 0x00, 0x0a, 0x00, 0x0b, 0x00, 0x0c,
0x00, 0x0d, 0x00, 0x0e, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x21, 0x02, 0x79, 0x00, 0x02, 0x00, 0x00,
0x00, 0x00, 0x02, 0x58, 0x08, 0x00, 0x00, 0x03, 0x00, 0x07, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x02, 0x58, 0x00, 0x00, 0xfd, 0xad, 0x02, 0x4e,
0x00, 0x00, 0xfd, 0xb2, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x05, 0x00, 0x00,
0x07, 0xf6, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0xff, 0x0b, 0x00, 0x80, 0x00, 0x5e, 0x00, 0x03,
0x00, 0x0d, 0x00, 0x00, 0x35, 0x33, 0x15, 0x23, 0x17, 0x0e, 0x04, 0x23, 0x22, 0x26, 0x27, 0x7f,
0x7f, 0x80, 0x16, 0x27, 0x18, 0x12, 0x0c, 0x03, 0x04, 0x03, 0x02, 0x5e, 0x80, 0x21, 0x09, 0x2c,
0x31, 0x2e, 0x1e, 0x46, 0x6c, 0x00, 0x01, 0x00, 0x00, 0xff, 0x3f, 0x00, 0x7e, 0xff, 0xbf, 0x00,
0x03, 0x00, 0x00, 0x15, 0x33, 0x15, 0x23, 0x7e, 0x7e, 0x41, 0x80, 0x00, 0x06, 0x00, 0x90, 0xff,
0x2b, 0x02, 0x90, 0x03, 0x23, 0x00, 0x03, 0x00, 0x07, 0x00, 0x0b, 0x00, 0x0f, 0x00, 0x13, 0x00,
0x17, 0x00, 0x00, 0x17, 0x37, 0x33, 0x17, 0x01, 0x17, 0x15, 0x07, 0x21, 0x27, 0x35, 0x37, 0x01,
0x21, 0x07, 0x23, 0x03, 0x11, 0x17, 0x15, 0x01, 0x11, 0x27, 0x35, 0xb1, 0x67, 0xf7, 0x61, 0xfe,
0x23, 0x6c, 0x6c, 0x01, 0xfd, 0x6c, 0x6c, 0xfe, 0x20, 0x01, 0xbf, 0x63, 0xf5, 0x87, 0x6c, 0x01,
0x91, 0x6c, 0xd5, 0x6c, 0x6c, 0x01, 0xeb, 0x68, 0xf5, 0x62, 0x67, 0xf6, 0x62, 0x02, 0x0d, 0x6c,
0xfe, 0x82, 0x01, 0xbf, 0x61, 0xf8, 0x01, 0x59, 0xfe, 0x41, 0x61, 0xf7, 0x00, 0x03, 0x00, 0x90,
0xff, 0x57, 0x02, 0x90, 0x02, 0xf8, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x13, 0x01,
0x27, 0x35, 0x37, 0x03, 0x11, 0x27, 0x35, 0x90, 0x02, 0x00, 0x6c, 0x6c, 0x03, 0x6c, 0x02, 0x24,
0xfd, 0x33, 0x67, 0xf6, 0x62, 0x01, 0xe2, 0xfe, 0x41, 0x61, 0xf7, 0x00, 0x05, 0x00, 0x93, 0xff,
0x2b, 0x02, 0x8d, 0x03, 0x23, 0x00, 0x03, 0x00, 0x07, 0x00, 0x0e, 0x00, 0x12, 0x00, 0x16, 0x00,
0x00, 0x17, 0x37, 0x33, 0x17, 0x01, 0x17, 0x15, 0x07, 0x13, 0x26, 0x27, 0x37, 0x21, 0x17, 0x07,
0x01, 0x21, 0x07, 0x23, 0x25, 0x11, 0x27, 0x35, 0xb1, 0x67, 0xf7, 0x61, 0xfe, 0x23, 0x6c, 0x6c,
0x74, 0x23, 0x24, 0x47, 0x01, 0x11, 0x46, 0x46, 0xfe, 0x98, 0x01, 0xbf, 0x63, 0xf5, 0x01, 0x76,
0x6c, 0xd5, 0x6c, 0x6c, 0x01, 0xeb, 0x68, 0xf5, 0x62, 0x01, 0x9b, 0x1c, 0x1b, 0x35, 0x35, 0x37,
0x02, 0x31, 0x6c, 0x41, 0xfe, 0x41, 0x61, 0xf7, 0x00, 0x05, 0x00, 0xb1, 0xff, 0x2b, 0x02, 0x91,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x02, 0x79,
0x00, 0x00, 0x00, 0x2a, 0x00, 0x2a, 0x00, 0x2a, 0x00, 0x2a, 0x00, 0x4c, 0x00, 0x58, 0x00, 0x8a,
0x00, 0xa2, 0x00, 0xd2, 0x01, 0x00, 0x01, 0x28, 0x01, 0x56, 0x01, 0x8c, 0x01, 0xa8, 0x01, 0xe6,
0x02, 0x16, 0x02, 0x28, 0x02, 0x52, 0x02, 0x82, 0x02, 0xb8, 0x03, 0x28, 0x03, 0x62, 0x03, 0x92,
0x03, 0xb2, 0x00, 0x00, 0x00, 0x02, 0x00, 0x21, 0x00, 0x00, 0x01, 0x2a, 0x02, 0x9a, 0x00, 0x03,
0x00, 0x07, 0x00, 0x2e, 0xb1, 0x01, 0x00, 0x2f, 0x3c, 0xb2, 0x07, 0x04, 0x00, 0xed, 0x32, 0xb1,
0x06, 0x05, 0xdc, 0x3c, 0xb2, 0x03, 0x02, 0x00, 0xed, 0x32, 0x00, 0xb1, 0x03, 0x00, 0x2f, 0x3c,
0xb2, 0x05, 0x04, 0x00, 0xed, 0x32, 0xb2, 0x07, 0x06, 0x01, 0xfc, 0x3c, 0xb2, 0x01, 0x02, 0x00,
0xed, 0x32, 0x33, 0x11, 0x21, 0x11, 0x27, 0x33, 0x11, 0x23, 0x21, 0x01, 0x09, 0xe8, 0xc7, 0xc7,
0x02, 0x9a, 0xfd, 0x66, 0x21, 0x02, 0x58, 0x00, 0x00, 0x02, 0x00, 0x00, 0xff, 0x0b, 0x00, 0x80,
0x00, 0x5e, 0x00, 0x03, 0x00, 0x12, 0x00, 0x00, 0x35, 0x33, 0x15, 0x23, 0x17, 0x0e, 0x01, 0x07,
0x06, 0x07, 0x0e, 0x01, 0x07, 0x06, 0x23, 0x22, 0x27, 0x26, 0x27, 0x7f, 0x7f, 0x80, 0x17, 0x26,
0x0c, 0x09, 0x0c, 0x03, 0x0a, 0x02, 0x06, 0x03, 0x04, 0x02, 0x01, 0x02, 0x5e, 0x80, 0x21, 0x09,
0x2c, 0x18, 0x12, 0x1e, 0x08, 0x1a, 0x04, 0x0f, 0x23, 0x22, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x00,
0xff, 0x3f, 0x00, 0x7e, 0xff, 0xbf, 0x00, 0x03, 0x00, 0x00, 0x15, 0x33, 0x15, 0x23, 0x7e, 0x7e,
0x41, 0x80, 0x00, 0x00, 0x00, 0x06, 0x00, 0x90, 0xff, 0x2b, 0x02, 0x90, 0x03, 0x23, 0x00, 0x03,
0x00, 0x07, 0x00, 0x0b, 0x00, 0x0f, 0x00, 0x13, 0x00, 0x17, 0x00, 0x00, 0x17, 0x37, 0x33, 0x17,
0x01, 0x17, 0x15, 0x07, 0x21, 0x27, 0x35, 0x37, 0x01, 0x21, 0x07, 0x23, 0x03, 0x11, 0x17, 0x15,
0x01, 0x11, 0x27, 0x35, 0xb1, 0x67, 0xf7, 0x61, 0xfe, 0x23, 0x6c, 0x6c, 0x01, 0xfd, 0x6c, 0x6c,
0xfe, 0x20, 0x01, 0xbf, 0x63, 0xf5, 0x87, 0x6c, 0x01, 0x91, 0x6c, 0xd5, 0x6c, 0x6c, 0x01, 0xeb,
0x68, 0xf5, 0x62, 0x67, 0xf6, 0x62, 0x02, 0x0d, 0x6c, 0xfe, 0x82, 0x01, 0xbf, 0x61, 0xf8, 0x01,
0x59, 0xfe, 0x41, 0x61, 0xf7, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x90, 0xff, 0x57, 0x02, 0x90,
0x02, 0xf8, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x13, 0x01, 0x27, 0x35, 0x37, 0x03,
0x11, 0x27, 0x35, 0x90, 0x02, 0x00, 0x6c, 0x6c, 0x03, 0x6c, 0x02, 0x24, 0xfd, 0x33, 0x67, 0xf6,
0x62, 0x01, 0xe2, 0xfe, 0x41, 0x61, 0xf7, 0x00, 0x00, 0x05, 0x00, 0x93, 0xff, 0x2b, 0x02, 0x8d,
0x03, 0x23, 0x00, 0x03, 0x00, 0x07, 0x00, 0x0e, 0x00, 0x12, 0x00, 0x16, 0x00, 0x00, 0x17, 0x37,
0x33, 0x17, 0x01, 0x17, 0x15, 0x07, 0x13, 0x26, 0x27, 0x37, 0x21, 0x17, 0x07, 0x01, 0x21, 0x07,
0x23, 0x25, 0x11, 0x27, 0x35, 0xb1, 0x67, 0xf7, 0x61, 0xfe, 0x23, 0x6c, 0x6c, 0x74, 0x17, 0x30,
0x47, 0x01, 0x11, 0x46, 0x46, 0xfe, 0x98, 0x01, 0xbf, 0x63, 0xf5, 0x01, 0x76, 0x6c, 0xd5, 0x6c,
0x6c, 0x01, 0xeb, 0x68, 0xf5, 0x62, 0x01, 0x9b, 0x13, 0x24, 0x35, 0x35, 0x37, 0x02, 0x31, 0x6c,
0x41, 0xfe, 0x41, 0x61, 0xf7, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0xb1, 0xff, 0x2b, 0x02, 0x91,
0x03, 0x23, 0x00, 0x03, 0x00, 0x07, 0x00, 0x0e, 0x00, 0x12, 0x00, 0x16, 0x00, 0x00, 0x17, 0x37,
0x33, 0x17, 0x37, 0x27, 0x35, 0x37, 0x05, 0x26, 0x27, 0x37, 0x21, 0x17, 0x07, 0x01, 0x21, 0x07,
0x23, 0x25, 0x11, 0x27, 0x35, 0xb4, 0x65, 0xf8, 0x61, 0x1f, 0x6b, 0x6b, 0xfe, 0x77, 0x22, 0x24,
0x23, 0x25, 0x11, 0x27, 0x35, 0xb4, 0x65, 0xf8, 0x61, 0x1f, 0x6b, 0x6b, 0xfe, 0x77, 0x21, 0x25,
0x46, 0x01, 0x11, 0x46, 0x46, 0xfe, 0x98, 0x01, 0xc0, 0x62, 0xf7, 0x01, 0x76, 0x6b, 0xd5, 0x6c,
0x6c, 0x2c, 0x67, 0xf6, 0x62, 0x24, 0x1c, 0x1b, 0x35, 0x35, 0x37, 0x02, 0x31, 0x6c, 0x41, 0xfe,
0x41, 0x61, 0xf7, 0x00, 0x04, 0x00, 0x90, 0xff, 0x57, 0x02, 0x90, 0x02, 0xf8, 0x00, 0x03, 0x00,
0x0a, 0x00, 0x0e, 0x00, 0x12, 0x00, 0x00, 0x05, 0x27, 0x35, 0x37, 0x05, 0x26, 0x27, 0x37, 0x21,
0x17, 0x07, 0x25, 0x11, 0x17, 0x15, 0x01, 0x11, 0x27, 0x35, 0x02, 0x90, 0x6c, 0x6c, 0xfe, 0x77,
0x23, 0x24, 0x47, 0x01, 0x11, 0x46, 0x46, 0xfe, 0x78, 0x6c, 0x01, 0x91, 0x6c, 0xa9, 0x67, 0xf6,
0x62, 0x24, 0x1c, 0x1b, 0x35, 0x35, 0x37, 0x47, 0x01, 0xbf, 0x61, 0xf8, 0x01, 0x59, 0xfe, 0x41,
0x61, 0xf7, 0x00, 0x05, 0x00, 0x90, 0xff, 0x2b, 0x02, 0x90, 0x03, 0x23, 0x00, 0x03, 0x00, 0x07,
0x00, 0x0e, 0x00, 0x12, 0x00, 0x16, 0x00, 0x00, 0x17, 0x37, 0x33, 0x17, 0x37, 0x27, 0x35, 0x37,
0x05, 0x26, 0x27, 0x37, 0x21, 0x17, 0x07, 0x01, 0x21, 0x07, 0x23, 0x03, 0x11, 0x17, 0x15, 0xb1,
0x67, 0xf7, 0x61, 0x20, 0x6c, 0x6c, 0xfe, 0x77, 0x23, 0x24, 0x47, 0x01, 0x11, 0x46, 0x46, 0xfe,
0x98, 0x01, 0xbf, 0x63, 0xf5, 0x87, 0x6c, 0xd5, 0x6c, 0x6c, 0x2c, 0x67, 0xf6, 0x62, 0x24, 0x1c,
0x1b, 0x35, 0x35, 0x37, 0x02, 0x31, 0x6c, 0xfe, 0x82, 0x01, 0xbf, 0x61, 0xf8, 0x00, 0x06, 0x00,
0x90, 0xff, 0x2b, 0x02, 0x90, 0x03, 0x23, 0x00, 0x03, 0x00, 0x07, 0x00, 0x0b, 0x00, 0x12, 0x00,
0x16, 0x00, 0x1a, 0x00, 0x00, 0x17, 0x37, 0x33, 0x17, 0x01, 0x17, 0x15, 0x07, 0x21, 0x27, 0x35,
0x37, 0x05, 0x26, 0x27, 0x37, 0x21, 0x17, 0x07, 0x01, 0x21, 0x07, 0x23, 0x03, 0x11, 0x17, 0x15,
0xb1, 0x67, 0xf7, 0x61, 0xfe, 0x23, 0x6c, 0x6c, 0x01, 0xfd, 0x6c, 0x6c, 0xfe, 0x77, 0x23, 0x24,
0x47, 0x01, 0x11, 0x46, 0x46, 0xfe, 0x98, 0x01, 0xbf, 0x63, 0xf5, 0x87, 0x6c, 0xd5, 0x6c, 0x6c,
0x01, 0xeb, 0x68, 0xf5, 0x62, 0x67, 0xf6, 0x62, 0x24, 0x1c, 0x1b, 0x35, 0x35, 0x37, 0x02, 0x31,
0x6c, 0xfe, 0x82, 0x01, 0xbf, 0x61, 0xf8, 0x00, 0x03, 0x00, 0xb4, 0xff, 0x57, 0x02, 0x94, 0x03,
0x23, 0x00, 0x03, 0x00, 0x07, 0x00, 0x0b, 0x00, 0x00, 0x05, 0x27, 0x35, 0x37, 0x01, 0x21, 0x07,
0x23, 0x25, 0x11, 0x27, 0x35, 0x02, 0x94, 0x6b, 0x6b, 0xfe, 0x20, 0x01, 0xc0, 0x62, 0xf7, 0x01,
0x76, 0x6b, 0xa9, 0x67, 0xf6, 0x62, 0x02, 0x0d, 0x6c, 0x41, 0xfe, 0x41, 0x61, 0xf7, 0x00, 0x07,
0x00, 0x90, 0xff, 0x2b, 0x02, 0x90, 0x03, 0x23, 0x00, 0x03, 0x00, 0x07, 0x00, 0x0b, 0x00, 0x12,
0x00, 0x16, 0x00, 0x1a, 0x00, 0x1e, 0x00, 0x00, 0x17, 0x37, 0x33, 0x17, 0x01, 0x17, 0x15, 0x07,
0x6c, 0x2c, 0x67, 0xf6, 0x62, 0x24, 0x1b, 0x1c, 0x35, 0x35, 0x37, 0x02, 0x31, 0x6c, 0x41, 0xfe,
0x41, 0x61, 0xf7, 0x00, 0x00, 0x04, 0x00, 0x90, 0xff, 0x57, 0x02, 0x90, 0x02, 0xf8, 0x00, 0x03,
0x00, 0x0a, 0x00, 0x0e, 0x00, 0x12, 0x00, 0x00, 0x05, 0x27, 0x35, 0x37, 0x05, 0x26, 0x27, 0x37,
0x21, 0x17, 0x07, 0x25, 0x11, 0x17, 0x15, 0x01, 0x11, 0x27, 0x35, 0x02, 0x90, 0x6c, 0x6c, 0xfe,
0x77, 0x17, 0x30, 0x47, 0x01, 0x11, 0x46, 0x46, 0xfe, 0x78, 0x6c, 0x01, 0x91, 0x6c, 0xa9, 0x67,
0xf6, 0x62, 0x24, 0x13, 0x24, 0x35, 0x35, 0x37, 0x47, 0x01, 0xbf, 0x61, 0xf8, 0x01, 0x59, 0xfe,
0x41, 0x61, 0xf7, 0x00, 0x00, 0x05, 0x00, 0x90, 0xff, 0x2b, 0x02, 0x90, 0x03, 0x23, 0x00, 0x03,
0x00, 0x07, 0x00, 0x0e, 0x00, 0x12, 0x00, 0x16, 0x00, 0x00, 0x17, 0x37, 0x33, 0x17, 0x37, 0x27,
0x35, 0x37, 0x05, 0x26, 0x27, 0x37, 0x21, 0x17, 0x07, 0x01, 0x21, 0x07, 0x23, 0x03, 0x11, 0x17,
0x15, 0xb1, 0x67, 0xf7, 0x61, 0x20, 0x6c, 0x6c, 0xfe, 0x77, 0x17, 0x30, 0x47, 0x01, 0x11, 0x46,
0x46, 0xfe, 0x98, 0x01, 0xbf, 0x63, 0xf5, 0x87, 0x6c, 0xd5, 0x6c, 0x6c, 0x2c, 0x67, 0xf6, 0x62,
0x24, 0x13, 0x24, 0x35, 0x35, 0x37, 0x02, 0x31, 0x6c, 0xfe, 0x82, 0x01, 0xbf, 0x61, 0xf8, 0x00,
0x00, 0x06, 0x00, 0x90, 0xff, 0x2b, 0x02, 0x90, 0x03, 0x23, 0x00, 0x03, 0x00, 0x07, 0x00, 0x0b,
0x00, 0x12, 0x00, 0x16, 0x00, 0x1a, 0x00, 0x00, 0x17, 0x37, 0x33, 0x17, 0x01, 0x17, 0x15, 0x07,
0x21, 0x27, 0x35, 0x37, 0x05, 0x26, 0x27, 0x37, 0x21, 0x17, 0x07, 0x01, 0x21, 0x07, 0x23, 0x03,
0x11, 0x17, 0x15, 0x01, 0x11, 0x27, 0x35, 0xb1, 0x67, 0xf7, 0x61, 0xfe, 0x23, 0x6c, 0x6c, 0x01,
0xfd, 0x6c, 0x6c, 0xfe, 0x77, 0x23, 0x24, 0x47, 0x01, 0x11, 0x46, 0x46, 0xfe, 0x98, 0x01, 0xbf,
0x63, 0xf5, 0x87, 0x6c, 0x01, 0x91, 0x6c, 0xd5, 0x6c, 0x6c, 0x01, 0xeb, 0x68, 0xf5, 0x62, 0x67,
0xf6, 0x62, 0x24, 0x1c, 0x1b, 0x35, 0x35, 0x37, 0x02, 0x31, 0x6c, 0xfe, 0x82, 0x01, 0xbf, 0x61,
0xf8, 0x01, 0x59, 0xfe, 0x41, 0x61, 0xf7, 0x00, 0x05, 0x00, 0x90, 0xff, 0x57, 0x02, 0x90, 0x03,
0x23, 0x00, 0x03, 0x00, 0x0a, 0x00, 0x0e, 0x00, 0x12, 0x00, 0x16, 0x00, 0x00, 0x05, 0x27, 0x35,
0x37, 0x05, 0x26, 0x27, 0x37, 0x21, 0x17, 0x07, 0x01, 0x21, 0x07, 0x23, 0x03, 0x11, 0x17, 0x15,
0x01, 0x11, 0x27, 0x35, 0x02, 0x90, 0x6c, 0x6c, 0xfe, 0x77, 0x23, 0x24, 0x47, 0x01, 0x11, 0x46,
0x46, 0xfe, 0x98, 0x01, 0xbf, 0x63, 0xf5, 0x87, 0x6c, 0x01, 0x91, 0x6c, 0xa9, 0x67, 0xf6, 0x62,
0x24, 0x1c, 0x1b, 0x35, 0x35, 0x37, 0x02, 0x31, 0x6c, 0xfe, 0x82, 0x01, 0xbf, 0x61, 0xf8, 0x01,
0x59, 0xfe, 0x41, 0x61, 0xf7, 0x00, 0x02, 0x01, 0x51, 0x00, 0xa3, 0x01, 0xcf, 0x02, 0x49, 0x00,
0x03, 0x00, 0x07, 0x00, 0x00, 0x01, 0x33, 0x15, 0x23, 0x11, 0x33, 0x15, 0x23, 0x01, 0x51, 0x7e,
0x7e, 0x7e, 0x7e, 0x01, 0x20, 0x7d, 0x01, 0xa6, 0x80, 0x00, 0x04, 0x01, 0x50, 0x00, 0x22, 0x01,
0xd0, 0x02, 0x52, 0x00, 0x0c, 0x00, 0x10, 0x00, 0x15, 0x00, 0x1a, 0x00, 0x00, 0x01, 0x33, 0x15,
0x23, 0x15, 0x33, 0x06, 0x07, 0x06, 0x23, 0x22, 0x27, 0x23, 0x11, 0x33, 0x15, 0x23, 0x17, 0x32,
0x31, 0x35, 0x23, 0x15, 0x15, 0x23, 0x36, 0x36, 0x01, 0x50, 0x7f, 0x7e, 0x6e, 0x2c, 0x28, 0x0d,
0x03, 0x07, 0x03, 0x01, 0x7f, 0x7f, 0x7f, 0x01, 0x01, 0x10, 0x03, 0x0a, 0x01, 0x49, 0x74, 0x0b,
0x1f, 0x69, 0x20, 0xa8, 0x01, 0x88, 0x80, 0xfe, 0x01, 0x01, 0x0a, 0x01, 0x08, 0x00, 0x00, 0x00,
0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0xe0, 0x86, 0xa0, 0x5f, 0x0f, 0x3c, 0xf5,
0x00, 0x0b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x30, 0x16, 0x4c, 0x00, 0x00, 0x00, 0x00,
0xe0, 0x30, 0x16, 0x4c, 0xff, 0x8f, 0xfe, 0xc3, 0x03, 0x91, 0x03, 0xce, 0x00, 0x00, 0x00, 0x06,
0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x03, 0x20, 0x00, 0x00, 0xff, 0xe4, 0x02, 0x94, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x02, 0x58, 0x00, 0x00,
0x03, 0x20, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x03, 0x20, 0x00, 0x90,
0x03, 0x20, 0x00, 0x90, 0x03, 0x20, 0x00, 0x93, 0x03, 0x20, 0x00, 0xb1, 0x03, 0x20, 0x00, 0x90,
0x03, 0x20, 0x00, 0x90, 0x03, 0x20, 0x00, 0x90, 0x03, 0x20, 0x00, 0xb4, 0x03, 0x20, 0x00, 0x90,
0x03, 0x20, 0x00, 0x90, 0x03, 0x20, 0x01, 0x51, 0x03, 0x20, 0x01, 0x50, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, 0x00, 0x7f,
0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x01, 0x0f, 0x00, 0x00, 0x01, 0x6c, 0x00, 0x00, 0x01, 0xc7,
0x00, 0x00, 0x02, 0x16, 0x00, 0x00, 0x02, 0x71, 0x00, 0x00, 0x02, 0xdb, 0x00, 0x00, 0x03, 0x12,
0x00, 0x00, 0x03, 0x8b, 0x00, 0x00, 0x03, 0xe9, 0x00, 0x00, 0x04, 0x0d, 0x00, 0x00, 0x04, 0x61,
0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x10, 0x00, 0x04, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x02,
0x00, 0x00, 0x00, 0x01, 0x00, 0xff, 0x00, 0x00, 0x00, 0x40, 0x00, 0x2e, 0x00, 0xff, 0x00, 0x1e,
0x00, 0x00, 0x00, 0x0c, 0x00, 0x96, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x0d,
0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x07, 0x00, 0x0d, 0x00, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x21, 0x00, 0x14, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
0x00, 0x04, 0x00, 0x0d, 0x00, 0x35, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03,
0x00, 0x42, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x0d, 0x00, 0x45, 0x00, 0x03,
0x00, 0x01, 0x04, 0x09, 0x00, 0x01, 0x00, 0x1a, 0x00, 0x52, 0x00, 0x03, 0x00, 0x01, 0x04, 0x09,
0x00, 0x02, 0x00, 0x0e, 0x00, 0x6c, 0x00, 0x03, 0x00, 0x01, 0x04, 0x09, 0x00, 0x03, 0x00, 0x42,
0x00, 0x7a, 0x00, 0x03, 0x00, 0x01, 0x04, 0x09, 0x00, 0x04, 0x00, 0x1a, 0x00, 0xbc, 0x00, 0x03,
0x00, 0x01, 0x04, 0x09, 0x00, 0x05, 0x00, 0x06, 0x00, 0xd6, 0x00, 0x03, 0x00, 0x01, 0x04, 0x09,
0x00, 0x06, 0x00, 0x1a, 0x00, 0xdc, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x46,
0x6f, 0x6e, 0x74, 0x52, 0x65, 0x67, 0x75, 0x6c, 0x61, 0x72, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61,
0x74, 0x65, 0x64, 0x46, 0x6f, 0x6e, 0x74, 0x20, 0x52, 0x65, 0x67, 0x75, 0x6c, 0x61, 0x72, 0x3a,
0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x31, 0x2e, 0x30, 0x47, 0x65, 0x6e, 0x65, 0x72,
0x61, 0x74, 0x65, 0x64, 0x46, 0x6f, 0x6e, 0x74, 0x31, 0x2e, 0x30, 0x47, 0x65, 0x6e, 0x65, 0x72,
0x61, 0x74, 0x65, 0x64, 0x46, 0x6f, 0x6e, 0x74, 0x00, 0x47, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x65,
0x00, 0x72, 0x00, 0x61, 0x00, 0x74, 0x00, 0x65, 0x00, 0x64, 0x00, 0x46, 0x00, 0x6f, 0x00, 0x6e,
0x00, 0x74, 0x00, 0x52, 0x00, 0x65, 0x00, 0x67, 0x00, 0x75, 0x00, 0x6c, 0x00, 0x61, 0x00, 0x72,
0x00, 0x47, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x65, 0x00, 0x72, 0x00, 0x61, 0x00, 0x74, 0x00, 0x65,
0x00, 0x64, 0x00, 0x46, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x74, 0x00, 0x20, 0x00, 0x52, 0x00, 0x65,
0x00, 0x67, 0x00, 0x75, 0x00, 0x6c, 0x00, 0x61, 0x00, 0x72, 0x00, 0x3a, 0x00, 0x56, 0x00, 0x65,
0x00, 0x72, 0x00, 0x73, 0x00, 0x69, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x20, 0x00, 0x31, 0x00, 0x2e,
0x00, 0x30, 0x00, 0x47, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x65, 0x00, 0x72, 0x00, 0x61, 0x00, 0x74,
0x00, 0x65, 0x00, 0x64, 0x00, 0x46, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x74, 0x00, 0x31, 0x00, 0x2e,
0x00, 0x30, 0x00, 0x47, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x65, 0x00, 0x72, 0x00, 0x61, 0x00, 0x74,
0x00, 0x65, 0x00, 0x64, 0x00, 0x46, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x74, 0x00, 0x01, 0x03, 0x20,
0x01, 0x90, 0x00, 0x05, 0x00, 0x08, 0x02, 0x8a, 0x02, 0xbb, 0x00, 0x00, 0x00, 0x8c, 0x02, 0x8a,
0x02, 0xbb, 0x00, 0x00, 0x01, 0xdf, 0x00, 0x31, 0x01, 0x02, 0x00, 0x00, 0x02, 0x00, 0x05, 0x03,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x66, 0x45, 0x64, 0x00, 0x40, 0x00, 0x00, 0x00, 0xff,
0x03, 0xce, 0xfe, 0xc3, 0x00, 0x00, 0x03, 0xce, 0x01, 0x3d, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x11, 0x17, 0x15, 0xb1, 0x67, 0xf7, 0x61, 0xfe, 0x23, 0x6c, 0x6c, 0x01, 0xfd, 0x6c, 0x6c, 0xfe,
0x77, 0x17, 0x30, 0x47, 0x01, 0x11, 0x46, 0x46, 0xfe, 0x98, 0x01, 0xbf, 0x63, 0xf5, 0x87, 0x6c,
0xd5, 0x6c, 0x6c, 0x01, 0xeb, 0x68, 0xf5, 0x62, 0x67, 0xf6, 0x62, 0x24, 0x13, 0x24, 0x35, 0x35,
0x37, 0x02, 0x31, 0x6c, 0xfe, 0x82, 0x01, 0xbf, 0x61, 0xf8, 0x00, 0x00, 0x00, 0x03, 0x00, 0xb4,
0xff, 0x57, 0x02, 0x94, 0x03, 0x23, 0x00, 0x03, 0x00, 0x07, 0x00, 0x0b, 0x00, 0x00, 0x05, 0x27,
0x35, 0x37, 0x01, 0x21, 0x07, 0x23, 0x25, 0x11, 0x27, 0x35, 0x02, 0x94, 0x6b, 0x6b, 0xfe, 0x20,
0x01, 0xc0, 0x62, 0xf7, 0x01, 0x76, 0x6b, 0xa9, 0x67, 0xf6, 0x62, 0x02, 0x0d, 0x6c, 0x41, 0xfe,
0x41, 0x61, 0xf7, 0x00, 0x00, 0x07, 0x00, 0x90, 0xff, 0x2b, 0x02, 0x90, 0x03, 0x23, 0x00, 0x03,
0x00, 0x07, 0x00, 0x0b, 0x00, 0x12, 0x00, 0x16, 0x00, 0x1a, 0x00, 0x1e, 0x00, 0x00, 0x17, 0x37,
0x33, 0x17, 0x01, 0x17, 0x15, 0x07, 0x21, 0x27, 0x35, 0x37, 0x05, 0x26, 0x27, 0x37, 0x21, 0x17,
0x07, 0x01, 0x21, 0x07, 0x23, 0x03, 0x11, 0x17, 0x15, 0x01, 0x11, 0x27, 0x35, 0xb1, 0x67, 0xf7,
0x61, 0xfe, 0x23, 0x6c, 0x6c, 0x01, 0xfd, 0x6c, 0x6c, 0xfe, 0x77, 0x17, 0x30, 0x47, 0x01, 0x11,
0x46, 0x46, 0xfe, 0x98, 0x01, 0xbf, 0x63, 0xf5, 0x87, 0x6c, 0x01, 0x91, 0x6c, 0xd5, 0x6c, 0x6c,
0x01, 0xeb, 0x68, 0xf5, 0x62, 0x67, 0xf6, 0x62, 0x24, 0x13, 0x24, 0x35, 0x35, 0x37, 0x02, 0x31,
0x6c, 0xfe, 0x82, 0x01, 0xbf, 0x61, 0xf8, 0x01, 0x59, 0xfe, 0x41, 0x61, 0xf7, 0x00, 0x00, 0x00,
0x00, 0x05, 0x00, 0x90, 0xff, 0x57, 0x02, 0x90, 0x03, 0x23, 0x00, 0x03, 0x00, 0x0a, 0x00, 0x0e,
0x00, 0x12, 0x00, 0x16, 0x00, 0x00, 0x05, 0x27, 0x35, 0x37, 0x05, 0x26, 0x27, 0x37, 0x21, 0x17,
0x07, 0x01, 0x21, 0x07, 0x23, 0x03, 0x11, 0x17, 0x15, 0x01, 0x11, 0x27, 0x35, 0x02, 0x90, 0x6c,
0x6c, 0xfe, 0x77, 0x17, 0x30, 0x47, 0x01, 0x11, 0x46, 0x46, 0xfe, 0x98, 0x01, 0xbf, 0x63, 0xf5,
0x87, 0x6c, 0x01, 0x91, 0x6c, 0xa9, 0x67, 0xf6, 0x62, 0x24, 0x13, 0x24, 0x35, 0x35, 0x37, 0x02,
0x31, 0x6c, 0xfe, 0x82, 0x01, 0xbf, 0x61, 0xf8, 0x01, 0x59, 0xfe, 0x41, 0x61, 0xf7, 0x00, 0x00,
0x00, 0x02, 0x01, 0x51, 0x00, 0xa3, 0x01, 0xcf, 0x02, 0x49, 0x00, 0x03, 0x00, 0x07, 0x00, 0x00,
0x01, 0x33, 0x15, 0x23, 0x11, 0x33, 0x15, 0x23, 0x01, 0x51, 0x7e, 0x7e, 0x7e, 0x7e, 0x01, 0x20,
0x7d, 0x01, 0xa6, 0x80, 0x00, 0x04, 0x01, 0x50, 0x00, 0x22, 0x01, 0xd0, 0x02, 0x52, 0x00, 0x0c,
0x00, 0x10, 0x00, 0x15, 0x00, 0x1a, 0x00, 0x00, 0x01, 0x33, 0x15, 0x23, 0x15, 0x33, 0x06, 0x07,
0x06, 0x23, 0x22, 0x27, 0x23, 0x11, 0x33, 0x15, 0x23, 0x17, 0x30, 0x33, 0x35, 0x23, 0x1d, 0x01,
0x23, 0x3e, 0x01, 0x01, 0x50, 0x7f, 0x7e, 0x6e, 0x2c, 0x28, 0x0e, 0x02, 0x07, 0x03, 0x01, 0x7f,
0x7f, 0x7f, 0x01, 0x01, 0x10, 0x06, 0x04, 0x01, 0x49, 0x74, 0x0b, 0x20, 0x68, 0x20, 0xa8, 0x01,
0x88, 0x80, 0xfe, 0x01, 0x01, 0x0a, 0x03, 0x04, 0x00, 0x05, 0x00, 0xa0, 0xff, 0x2b, 0x02, 0x80,
0x03, 0x23, 0x00, 0x03, 0x00, 0x07, 0x00, 0x0f, 0x00, 0x13, 0x00, 0x17, 0x00, 0x00, 0x17, 0x37,
0x33, 0x17, 0x01, 0x17, 0x15, 0x07, 0x13, 0x2e, 0x01, 0x27, 0x37, 0x21, 0x17, 0x07, 0x01, 0x21,
0x07, 0x23, 0x03, 0x11, 0x17, 0x15, 0xc0, 0x67, 0xf7, 0x62, 0xfe, 0x23, 0x6b, 0x6b, 0x73, 0x0e,
0x2f, 0x09, 0x46, 0x01, 0x11, 0x46, 0x46, 0xfe, 0x98, 0x01, 0xbe, 0x61, 0xf7, 0x85, 0x6b, 0xd5,
0x6c, 0x6c, 0x01, 0xeb, 0x68, 0xf5, 0x62, 0x01, 0x9b, 0x0b, 0x25, 0x07, 0x35, 0x35, 0x37, 0x02,
0x31, 0x6c, 0xfe, 0x82, 0x01, 0xbf, 0x61, 0xf8, 0x00, 0x06, 0x00, 0x90, 0xff, 0x2b, 0x02, 0x90,
0x03, 0x23, 0x00, 0x03, 0x00, 0x07, 0x00, 0x0b, 0x00, 0x12, 0x00, 0x16, 0x00, 0x1a, 0x00, 0x00,
0x17, 0x37, 0x33, 0x17, 0x01, 0x17, 0x15, 0x07, 0x21, 0x27, 0x35, 0x37, 0x05, 0x26, 0x27, 0x37,
0x21, 0x17, 0x07, 0x01, 0x21, 0x07, 0x23, 0x03, 0x11, 0x17, 0x15, 0xb1, 0x67, 0xf7, 0x61, 0xfe,
0x23, 0x6c, 0x6c, 0x01, 0xfd, 0x6c, 0x6c, 0xfe, 0x77, 0x17, 0x30, 0x47, 0x01, 0x11, 0x46, 0x46,
0xfe, 0x98, 0x01, 0xbf, 0x63, 0xf5, 0x87, 0x6c, 0xd5, 0x6c, 0x6c, 0x01, 0xeb, 0x68, 0xf5, 0x62,
0x67, 0xf6, 0x62, 0x24, 0x13, 0x24, 0x35, 0x35, 0x37, 0x02, 0x31, 0x6c, 0xfe, 0x82, 0x01, 0xbf,
0x61, 0xf8, 0x00, 0x00, 0x00, 0x08, 0x00, 0x9c, 0xff, 0x57, 0x02, 0x83, 0x02, 0xf8, 0x00, 0x03,
0x00, 0x0e, 0x00, 0x18, 0x00, 0x1c, 0x00, 0x23, 0x00, 0x27, 0x00, 0x32, 0x00, 0x41, 0x00, 0x00,
0x25, 0x15, 0x07, 0x11, 0x05, 0x30, 0x17, 0x16, 0x17, 0x16, 0x17, 0x14, 0x33, 0x1f, 0x01, 0x03,
0x37, 0x36, 0x37, 0x36, 0x3f, 0x01, 0x36, 0x35, 0x37, 0x01, 0x17, 0x15, 0x07, 0x13, 0x26, 0x27,
0x37, 0x33, 0x17, 0x07, 0x27, 0x11, 0x17, 0x15, 0x17, 0x33, 0x1e, 0x01, 0x17, 0x07, 0x2f, 0x01,
0x26, 0x35, 0x27, 0x03, 0x3f, 0x01, 0x36, 0x37, 0x36, 0x3f, 0x01, 0x36, 0x35, 0x37, 0x17, 0x0e,
0x01, 0x07, 0x01, 0x09, 0x6b, 0x01, 0x3c, 0x02, 0x02, 0x02, 0x05, 0x01, 0x01, 0x01, 0x92, 0xa0,
0x02, 0x02, 0x02, 0x05, 0x01, 0x01, 0x01, 0x92, 0xfe, 0x24, 0x6b, 0x6b, 0x73, 0x03, 0x41, 0x44,
0x05, 0x45, 0x45, 0x7a, 0x6b, 0x3c, 0x95, 0x29, 0x6a, 0x18, 0x09, 0x92, 0x01, 0x01, 0x0c, 0x97,
0x97, 0x02, 0x02, 0x02, 0x05, 0x01, 0x01, 0x01, 0x92, 0x09, 0x18, 0x6a, 0x29, 0x96, 0xdd, 0x62,
0x01, 0xbf, 0xf3, 0x01, 0x02, 0x02, 0x05, 0x02, 0x01, 0x02, 0x96, 0x02, 0xb0, 0x02, 0x01, 0x02,
0x05, 0x02, 0x01, 0x01, 0x01, 0x96, 0xfe, 0x43, 0x68, 0xf5, 0x62, 0x01, 0x9b, 0x02, 0x35, 0x35,
0x35, 0x37, 0x47, 0x01, 0xbf, 0x61, 0xf8, 0xde, 0x29, 0x72, 0x18, 0x90, 0x96, 0x01, 0x01, 0x01,
0x0c, 0x01, 0x6d, 0x9e, 0x02, 0x01, 0x02, 0x05, 0x02, 0x01, 0x01, 0x01, 0x96, 0x90, 0x18, 0x72,
0x29, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x56, 0xff, 0x57, 0x02, 0xca, 0x03, 0x03, 0x00, 0x03,
0x00, 0x07, 0x00, 0x0e, 0x00, 0x12, 0x00, 0x16, 0x00, 0x1d, 0x00, 0x00, 0x13, 0x17, 0x15, 0x07,
0x21, 0x27, 0x35, 0x37, 0x01, 0x17, 0x2f, 0x02, 0x1f, 0x01, 0x01, 0x11, 0x17, 0x15, 0x25, 0x11,
0x27, 0x35, 0x07, 0x3f, 0x02, 0x0f, 0x02, 0x65, 0x6c, 0x6c, 0x02, 0x61, 0x6c, 0x6c, 0xfe, 0xb9,
0x05, 0x57, 0xc9, 0x0e, 0x57, 0xc9, 0xfe, 0xed, 0x6c, 0x01, 0xf5, 0x6c, 0xb7, 0x09, 0xc9, 0x57,
0x0e, 0xc9, 0x57, 0x01, 0x16, 0x68, 0xf5, 0x62, 0x67, 0xf6, 0x62, 0x01, 0x00, 0x2c, 0x08, 0xbb,
0x56, 0x08, 0xb9, 0xfe, 0xf7, 0x01, 0x47, 0x62, 0x7f, 0xe1, 0xfe, 0xb9, 0x61, 0x7f, 0x03, 0x2c,
0xb9, 0x08, 0x56, 0xbb, 0x08, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x91, 0xff, 0x57, 0x02, 0x8f,
0x03, 0x23, 0x00, 0x03, 0x00, 0x0a, 0x00, 0x0e, 0x00, 0x12, 0x00, 0x16, 0x00, 0x00, 0x13, 0x17,
0x15, 0x07, 0x13, 0x26, 0x27, 0x37, 0x21, 0x17, 0x07, 0x01, 0x21, 0x07, 0x23, 0x03, 0x11, 0x17,
0x15, 0x01, 0x11, 0x27, 0x35, 0x94, 0x6c, 0x6c, 0x73, 0x26, 0x20, 0x46, 0x01, 0x12, 0x46, 0x46,
0xfe, 0x98, 0x01, 0xbe, 0x61, 0xf7, 0x86, 0x6c, 0x01, 0x92, 0x6c, 0x01, 0x16, 0x68, 0xf5, 0x62,
0x01, 0x9b, 0x1f, 0x18, 0x35, 0x35, 0x37, 0x02, 0x31, 0x6c, 0xfe, 0x82, 0x01, 0xbf, 0x61, 0xf8,
0x01, 0x59, 0xfe, 0x41, 0x61, 0xf7, 0x00, 0x00, 0x00, 0x02, 0x00, 0x17, 0xff, 0x57, 0x03, 0x09,
0x03, 0x34, 0x00, 0x03, 0x00, 0x0f, 0x00, 0x00, 0x05, 0x27, 0x35, 0x37, 0x01, 0x26, 0x27, 0x37,
0x21, 0x17, 0x07, 0x23, 0x11, 0x27, 0x35, 0x37, 0x01, 0xc7, 0x6c, 0x6c, 0xfe, 0x96, 0x0e, 0x38,
0x46, 0x02, 0x66, 0x46, 0x46, 0xff, 0x6c, 0x3b, 0xa9, 0x67, 0xf6, 0x62, 0x01, 0xb3, 0x0c, 0x29,
0x36, 0x36, 0x35, 0xfe, 0x70, 0x61, 0xf7, 0x38, 0x00, 0x00, 0x00, 0x12, 0x00, 0xde, 0x00, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6a, 0x00, 0xd6, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
0x00, 0x01, 0x00, 0x0f, 0x01, 0x61, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x07,
0x01, 0x81, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x2a, 0x01, 0xdf, 0x00, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x0f, 0x02, 0x2a, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
0x00, 0x05, 0x00, 0x0f, 0x02, 0x5a, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x16,
0x02, 0x98, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x4c, 0x03, 0x49, 0x00, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x1a, 0x03, 0xcc, 0x00, 0x03, 0x00, 0x01, 0x04, 0x09,
0x00, 0x00, 0x00, 0xd4, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x04, 0x09, 0x00, 0x01, 0x00, 0x1e,
0x01, 0x41, 0x00, 0x03, 0x00, 0x01, 0x04, 0x09, 0x00, 0x02, 0x00, 0x0e, 0x01, 0x71, 0x00, 0x03,
0x00, 0x01, 0x04, 0x09, 0x00, 0x03, 0x00, 0x54, 0x01, 0x89, 0x00, 0x03, 0x00, 0x01, 0x04, 0x09,
0x00, 0x04, 0x00, 0x1e, 0x02, 0x0a, 0x00, 0x03, 0x00, 0x01, 0x04, 0x09, 0x00, 0x05, 0x00, 0x1e,
0x02, 0x3a, 0x00, 0x03, 0x00, 0x01, 0x04, 0x09, 0x00, 0x06, 0x00, 0x2c, 0x02, 0x6a, 0x00, 0x03,
0x00, 0x01, 0x04, 0x09, 0x00, 0x0d, 0x00, 0x98, 0x02, 0xaf, 0x00, 0x03, 0x00, 0x01, 0x04, 0x09,
0x00, 0x0e, 0x00, 0x34, 0x03, 0x96, 0x00, 0x43, 0x00, 0x6f, 0x00, 0x70, 0x00, 0x79, 0x00, 0x72,
0x00, 0x69, 0x00, 0x67, 0x00, 0x68, 0x00, 0x74, 0x00, 0x20, 0x00, 0x28, 0x00, 0x63, 0x00, 0x29,
0x00, 0x20, 0x00, 0x32, 0x00, 0x30, 0x00, 0x31, 0x00, 0x35, 0x00, 0x2c, 0x00, 0x20, 0x00, 0x53,
0x00, 0x74, 0x00, 0x65, 0x00, 0x70, 0x00, 0x68, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x20, 0x00, 0x41,
0x00, 0x68, 0x00, 0x6c, 0x00, 0x66, 0x00, 0x20, 0x00, 0x28, 0x00, 0x68, 0x00, 0x74, 0x00, 0x74,
0x00, 0x70, 0x00, 0x73, 0x00, 0x3a, 0x00, 0x2f, 0x00, 0x2f, 0x00, 0x67, 0x00, 0x69, 0x00, 0x74,
0x00, 0x68, 0x00, 0x75, 0x00, 0x62, 0x00, 0x2e, 0x00, 0x63, 0x00, 0x6f, 0x00, 0x6d, 0x00, 0x2f,
0x00, 0x73, 0x00, 0x2d, 0x00, 0x61, 0x00, 0x2f, 0x00, 0x64, 0x00, 0x69, 0x00, 0x67, 0x00, 0x69,
0x00, 0x74, 0x00, 0x61, 0x00, 0x6c, 0x00, 0x2d, 0x00, 0x6e, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x62,
0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x2d, 0x00, 0x66, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x74,
0x00, 0x20, 0x00, 0x73, 0x00, 0x74, 0x00, 0x65, 0x00, 0x70, 0x00, 0x68, 0x00, 0x61, 0x00, 0x6e,
0x00, 0x2e, 0x00, 0x61, 0x00, 0x68, 0x00, 0x6c, 0x00, 0x66, 0x00, 0x40, 0x00, 0x67, 0x00, 0x6f,
0x00, 0x6f, 0x00, 0x67, 0x00, 0x6c, 0x00, 0x65, 0x00, 0x6d, 0x00, 0x61, 0x00, 0x69, 0x00, 0x6c,
0x00, 0x2e, 0x00, 0x63, 0x00, 0x6f, 0x00, 0x6d, 0x00, 0x29, 0x00, 0x00, 0x43, 0x6f, 0x70, 0x79,
0x72, 0x69, 0x67, 0x68, 0x74, 0x20, 0x28, 0x63, 0x29, 0x20, 0x32, 0x30, 0x31, 0x35, 0x2c, 0x20,
0x53, 0x74, 0x65, 0x70, 0x68, 0x61, 0x6e, 0x20, 0x41, 0x68, 0x6c, 0x66, 0x20, 0x28, 0x68, 0x74,
0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d,
0x2f, 0x73, 0x2d, 0x61, 0x2f, 0x64, 0x69, 0x67, 0x69, 0x74, 0x61, 0x6c, 0x2d, 0x6e, 0x75, 0x6d,
0x62, 0x65, 0x72, 0x73, 0x2d, 0x66, 0x6f, 0x6e, 0x74, 0x20, 0x73, 0x74, 0x65, 0x70, 0x68, 0x61,
0x6e, 0x2e, 0x61, 0x68, 0x6c, 0x66, 0x40, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x6d, 0x61, 0x69,
0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x29, 0x00, 0x00, 0x44, 0x00, 0x69, 0x00, 0x67, 0x00, 0x69, 0x00,
0x74, 0x00, 0x61, 0x00, 0x6c, 0x00, 0x20, 0x00, 0x4e, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x62, 0x00,
0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x44, 0x69, 0x67, 0x69, 0x74, 0x61, 0x6c, 0x20, 0x4e,
0x75, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x00, 0x00, 0x52, 0x00, 0x65, 0x00, 0x67, 0x00, 0x75, 0x00,
0x6c, 0x00, 0x61, 0x00, 0x72, 0x00, 0x00, 0x52, 0x65, 0x67, 0x75, 0x6c, 0x61, 0x72, 0x00, 0x00,
0x46, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x74, 0x00, 0x46, 0x00, 0x6f, 0x00, 0x72, 0x00, 0x67, 0x00,
0x65, 0x00, 0x20, 0x00, 0x32, 0x00, 0x2e, 0x00, 0x30, 0x00, 0x20, 0x00, 0x3a, 0x00, 0x20, 0x00,
0x44, 0x00, 0x69, 0x00, 0x67, 0x00, 0x69, 0x00, 0x74, 0x00, 0x61, 0x00, 0x6c, 0x00, 0x20, 0x00,
0x4e, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x62, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x20, 0x00,
0x3a, 0x00, 0x20, 0x00, 0x36, 0x00, 0x2d, 0x00, 0x36, 0x00, 0x2d, 0x00, 0x32, 0x00, 0x30, 0x00,
0x31, 0x00, 0x35, 0x00, 0x00, 0x46, 0x6f, 0x6e, 0x74, 0x46, 0x6f, 0x72, 0x67, 0x65, 0x20, 0x32,
0x2e, 0x30, 0x20, 0x3a, 0x20, 0x44, 0x69, 0x67, 0x69, 0x74, 0x61, 0x6c, 0x20, 0x4e, 0x75, 0x6d,
0x62, 0x65, 0x72, 0x73, 0x20, 0x3a, 0x20, 0x36, 0x2d, 0x36, 0x2d, 0x32, 0x30, 0x31, 0x35, 0x00,
0x00, 0x44, 0x00, 0x69, 0x00, 0x67, 0x00, 0x69, 0x00, 0x74, 0x00, 0x61, 0x00, 0x6c, 0x00, 0x20,
0x00, 0x4e, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x62, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00,
0x44, 0x69, 0x67, 0x69, 0x74, 0x61, 0x6c, 0x20, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x00,
0x00, 0x56, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x69, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x20,
0x00, 0x30, 0x00, 0x30, 0x00, 0x31, 0x00, 0x2e, 0x00, 0x31, 0x00, 0x30, 0x00, 0x32, 0x00, 0x00,
0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x30, 0x30, 0x31, 0x2e, 0x31, 0x30, 0x32, 0x00,
0x00, 0x44, 0x00, 0x69, 0x00, 0x67, 0x00, 0x69, 0x00, 0x74, 0x00, 0x61, 0x00, 0x6c, 0x00, 0x4e,
0x00, 0x75, 0x00, 0x6d, 0x00, 0x62, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x2d, 0x00, 0x52,
0x00, 0x65, 0x00, 0x67, 0x00, 0x75, 0x00, 0x6c, 0x00, 0x61, 0x00, 0x72, 0x00, 0x00, 0x44, 0x69,
0x67, 0x69, 0x74, 0x61, 0x6c, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x2d, 0x52, 0x65, 0x67,
0x75, 0x6c, 0x61, 0x72, 0x00, 0x00, 0x54, 0x00, 0x68, 0x00, 0x69, 0x00, 0x73, 0x00, 0x20, 0x00,
0x46, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x74, 0x00, 0x20, 0x00, 0x53, 0x00, 0x6f, 0x00, 0x66, 0x00,
0x74, 0x00, 0x77, 0x00, 0x61, 0x00, 0x72, 0x00, 0x65, 0x00, 0x20, 0x00, 0x69, 0x00, 0x73, 0x00,
0x20, 0x00, 0x6c, 0x00, 0x69, 0x00, 0x63, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x73, 0x00, 0x65, 0x00,
0x64, 0x00, 0x20, 0x00, 0x75, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x65, 0x00, 0x72, 0x00, 0x20, 0x00,
0x74, 0x00, 0x68, 0x00, 0x65, 0x00, 0x20, 0x00, 0x53, 0x00, 0x49, 0x00, 0x4c, 0x00, 0x20, 0x00,
0x4f, 0x00, 0x70, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x20, 0x00, 0x46, 0x00, 0x6f, 0x00, 0x6e, 0x00,
0x74, 0x00, 0x20, 0x00, 0x4c, 0x00, 0x69, 0x00, 0x63, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x73, 0x00,
0x65, 0x00, 0x2c, 0x00, 0x20, 0x00, 0x56, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x69, 0x00,
0x6f, 0x00, 0x6e, 0x00, 0x20, 0x00, 0x31, 0x00, 0x2e, 0x00, 0x31, 0x00, 0x2e, 0x00, 0x00, 0x54,
0x68, 0x69, 0x73, 0x20, 0x46, 0x6f, 0x6e, 0x74, 0x20, 0x53, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72,
0x65, 0x20, 0x69, 0x73, 0x20, 0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x64, 0x20, 0x75, 0x6e,
0x64, 0x65, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x53, 0x49, 0x4c, 0x20, 0x4f, 0x70, 0x65, 0x6e,
0x20, 0x46, 0x6f, 0x6e, 0x74, 0x20, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x2c, 0x20, 0x56,
0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x31, 0x2e, 0x31, 0x2e, 0x00, 0x00, 0x68, 0x00, 0x74,
0x00, 0x74, 0x00, 0x70, 0x00, 0x3a, 0x00, 0x2f, 0x00, 0x2f, 0x00, 0x73, 0x00, 0x63, 0x00, 0x72,
0x00, 0x69, 0x00, 0x70, 0x00, 0x74, 0x00, 0x73, 0x00, 0x2e, 0x00, 0x73, 0x00, 0x69, 0x00, 0x6c,
0x00, 0x2e, 0x00, 0x6f, 0x00, 0x72, 0x00, 0x67, 0x00, 0x2f, 0x00, 0x4f, 0x00, 0x46, 0x00, 0x4c,
0x00, 0x00, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x73,
0x2e, 0x73, 0x69, 0x6c, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x4f, 0x46, 0x4c, 0x00, 0x00, 0x00, 0x00,
0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x83, 0x00, 0x32, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00
0x00, 0x18, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x0f, 0x00, 0x11, 0x00, 0x13,
0x00, 0x14, 0x00, 0x15, 0x00, 0x16, 0x00, 0x17, 0x00, 0x18, 0x00, 0x19, 0x00, 0x1a, 0x00, 0x1b,
0x00, 0x1c, 0x00, 0x1d, 0x00, 0x1e, 0x00, 0x28, 0x00, 0x2a, 0x00, 0x2e, 0x00, 0x30, 0x00, 0x33,
0x00, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01,
0x00, 0x00, 0x00, 0x00, 0xda, 0x32, 0xf0, 0x84, 0x00, 0x00, 0x00, 0x00, 0xd1, 0x98, 0x6e, 0xf9,
0x00, 0x00, 0x00, 0x00, 0xe0, 0xf3, 0xcd, 0x87
};

View File

@ -3,8 +3,8 @@
#include <WiFi.h>
#include <esp_task_wdt.h>
#include <TFT_eSPI.h> // Graphics and font library for ILI9341 driver chip
#include <wolfssl/wolfcrypt/sha256.h>
//#include "ShaTests/nerdSHA256.h"
#include "ShaTests/nerdSHA256.h"
//#include "ShaTests/nerdSHA256plus.h"
#include "media/Free_Fonts.h"
#include "media/images.h"
#include "OpenFontRender.h"
@ -19,10 +19,12 @@ unsigned long Mhashes = 0;
unsigned long totalKHashes = 0;
unsigned long elapsedKHs = 0;
unsigned long halfshares; // increase if blockhash has 16 bits of zeroes
unsigned int shares; // increase if blockhash has 32 bits of zeroes
unsigned int valids; // increased if blockhash <= target
// Track best diff
double best_diff = 0.0;
// Variables to hold data from custom textboxes
extern char poolString[80];
extern int portNumber;
@ -41,10 +43,10 @@ monitor_data mMonitor;
bool isMinerSuscribed = false;
unsigned long mLastTXtoPool = millis();
void checkPoolConnection(void) {
bool checkPoolConnection(void) {
if (client.connected()) {
return;
return true;
}
isMinerSuscribed = false;
@ -63,7 +65,10 @@ void checkPoolConnection(void) {
WiFi.hostByName(poolString, serverIP);
Serial.printf("Resolved DNS got: %s\n", serverIP.toString());
vTaskDelay(1000 / portTICK_PERIOD_MS);
return false;
}
return true;
}
//Implements a socketKeepAlive function and
@ -118,6 +123,7 @@ void runStratumWorker(void *name) {
if(WiFi.status() != WL_CONNECTED){
// WiFi is disconnected, so reconnect now
mMonitor.NerdStatus = NM_Connecting;
WiFi.reconnect();
vTaskDelay(5000 / portTICK_PERIOD_MS);
continue;
@ -138,7 +144,11 @@ void runStratumWorker(void *name) {
//portNumber = 3333;
//strcpy(btcString,"test");
checkPoolConnection();
if(!checkPoolConnection())
//If server is not reachable add random delay for connection retries
srand(millis());
//Generate value between 1 and 15 secs
vTaskDelay(((1 + rand() % 15) * 1000) / portTICK_PERIOD_MS);
if(!isMinerSuscribed){
@ -217,13 +227,13 @@ void runStratumWorker(void *name) {
//This works only with one thread, TODO -> Class or miner_data for each thread
//#include "shaTests/jadeSHA256.h"
//#include "shaTests/customSHA256.h"
//#include "mbedtls/sha256.h"
void runMiner(void * task_id) {
unsigned int miner_id = (uint32_t)task_id;
Serial.printf("[MINER] %d Started runMiner Task!\n", miner_id);
while(1){
//Wait new job
@ -239,27 +249,19 @@ void runMiner(void * task_id) {
mMiner.newJob2 = false; //Clear newJob flag
mMiner.inRun = true; //Set inRun flag
mMonitor.NerdStatus = NM_hashing;
//Prepare Premining data
Sha256 midstate[32];
//nerd_sha256 nerdMidstate;
nerd_sha256 nerdMidstate;
//nerdSHA256_context nerdMidstate; //NerdShaplus
uint8_t hash[32];
Sha256 sha256;
//Calcular midstate WOLF
wc_InitSha256(midstate);
wc_Sha256Update(midstate, mMiner.bytearray_blockheader, 64);
//nerd_midstate(&nerdMidstate, mMiner.bytearray_blockheader, 64);
/*Serial.println("Blockheader:");
for (size_t i = 0; i < 80; i++)
Serial.printf("%02x", mMiner.bytearray_blockheader[i]);
//Calcular midstate
nerd_midstate(&nerdMidstate, mMiner.bytearray_blockheader, 64);
//nerd_mids(&nerdMidstate, mMiner.bytearray_blockheader); //NerdShaplus
Serial.println("Midstate:");
for (size_t i = 0; i < 32; i++)
Serial.printf("%02x", midstate[i]);
Serial.println("");
*/
// search a valid nonce
unsigned long nonce = TARGET_NONCE - MAX_NONCE;
// split up odd/even nonces between miner tasks
@ -267,11 +269,15 @@ void runMiner(void * task_id) {
uint32_t startT = micros();
unsigned char *header64;
// each miner thread needs to track its own blockheader template
uint8_t temp;
memcpy(mMiner.bytearray_blockheader2, &mMiner.bytearray_blockheader, 80);
if (miner_id == 0)
header64 = mMiner.bytearray_blockheader + 64;
else
header64 = mMiner.bytearray_blockheader2 + 64;
bool is16BitShare=true;
Serial.println(">>> STARTING TO HASH NONCES");
while(true) {
if (miner_id == 0)
@ -279,23 +285,17 @@ void runMiner(void * task_id) {
else
memcpy(mMiner.bytearray_blockheader2 + 76, &nonce, 4);
//Con midstate
// Primer SHA-256
wc_Sha256Copy(midstate, &sha256);
wc_Sha256Update(&sha256, header64, 16);
wc_Sha256Final(&sha256, hash);
// Segundo SHA-256
wc_Sha256Update(&sha256, hash, 32);
wc_Sha256Final(&sha256, hash);
//nerd_double_sha(&nerdMidstate, header64, hash);
nerd_double_sha2(&nerdMidstate, header64, hash);
//is16BitShare=nerd_sha256d(&nerdMidstate, header64, hash); //Boosted 80Khs sha
/*for (size_t i = 0; i < 32; i++)
/*Serial.print("hash1: ");
for (size_t i = 0; i < 32; i++)
Serial.printf("%02x", hash[i]);
Serial.println("");
Serial.print("hash2: ");
for (size_t i = 0; i < 32; i++)
Serial.printf("%02x", midstate_jade.buffer[i]);
Serial.printf("%02x", hash2[i]);
Serial.println(""); */
hashes++;
@ -304,11 +304,11 @@ void runMiner(void * task_id) {
// check if 16bit share
if(hash[31] !=0 || hash[30] !=0) {
//if(!is16BitShare){
// increment nonce
nonce += 2;
continue;
}
halfshares++;
//Check target to submit
//Difficulty of 1 > 0x00000000FFFF0000000000000000000000000000000000000000000000000000
@ -316,6 +316,11 @@ void runMiner(void * task_id) {
//Swapping diff bytes little endian >>>>>>>>>>>>>>>> 0x0000DC59D300....00
//if((hash[29] <= 0xDC) && (hash[28] <= 0x59)) //0x00003B9ACA00 > diff value for 1e-9
double diff_hash = diff_from_target(hash);
// update best diff
if (diff_hash > best_diff)
best_diff = diff_hash;
if(diff_hash > mMiner.poolDifficulty)//(hash[29] <= 0x3B)//(diff_hash > 1e-9)
{
tx_mining_submit(client, mWorker, mJob, nonce);
@ -349,26 +354,22 @@ void runMiner(void * task_id) {
Serial.printf("[WORKER] %d CONGRATULATIONS! Valid block found with nonce: %d | 0x%x\n", miner_id, nonce, nonce);
valids++;
Serial.printf("[WORKER] %d Submitted work valid!\n", miner_id);
// STEP 3: Submit mining job
tx_mining_submit(client, mWorker, mJob, nonce);
client.stop();
// exit
nonce = MAX_NONCE;
// wait for new job
break;
}
// increment nonce
nonce += 2;
} // exit if found a valid result or nonce > MAX_NONCE
wc_Sha256Free(&sha256);
wc_Sha256Free(midstate);
//wc_Sha256Free(&sha256);
//wc_Sha256Free(midstate);
mMiner.inRun = false;
Serial.print(">>> Finished job waiting new data from pool");
if(hashes>=MAX_NONCE) {
Mhashes=Mhashes+MAX_NONCE/1000000;
hashes=hashes-MAX_NONCE;
if(hashes>=MAX_NONCE_STEP) {
Mhashes=Mhashes+MAX_NONCE_STEP/1000000;
hashes=hashes-MAX_NONCE_STEP;
}
uint32_t duration = micros() - startT;
@ -384,6 +385,10 @@ void runMonitor(void *name){
unsigned long mLastCheck = 0;
mMonitor.screen = SCREEN_MINING;
#ifdef DEVKITV1
mMonitor.screen = NO_SCREEN;
#endif
while(1){
@ -397,6 +402,7 @@ void runMonitor(void *name){
case SCREEN_MINING: show_MinerScreen(mElapsed); break;
case SCREEN_CLOCK: show_ClockScreen(mElapsed); break;
case SCREEN_GLOBAL: show_GlobalHashScreen(mElapsed); break;
case NO_SCREEN: show_NoScreen(mElapsed); break;
}
//Monitor state when hashrate is 0.0

View File

@ -3,7 +3,8 @@
#define MINING_API_H
// Mining
#define MAX_NONCE 5000000U
#define MAX_NONCE_STEP 5000000U
#define MAX_NONCE 25000000U
#define TARGET_NONCE 471136297U
#define DEFAULT_DIFFICULTY 1e-4
#define KEEPALIVE_TIME_ms 30000

View File

@ -19,9 +19,10 @@ extern unsigned long Mhashes;
extern unsigned long totalKHashes;
extern unsigned long elapsedKHs;
extern unsigned long halfshares; // increase if blockhash has 16 bits of zeroes
extern unsigned int shares; // increase if blockhash has 32 bits of zeroes
extern unsigned int valids; // increased if blockhash <= targethalfshares
extern unsigned int valids; // increased if blockhash <= target
extern double best_diff; // track best diff
extern OpenFontRender render;
extern TFT_eSprite background;
@ -218,6 +219,16 @@ void changeScreen(void){
mMonitor.screen++;
if(mMonitor.screen> SCREEN_GLOBAL) mMonitor.screen = SCREEN_MINING;
}
void show_NoScreen(unsigned long mElapsed){
char CurrentHashrate[10] = {0};
sprintf(CurrentHashrate, "%.2f", (1.0*(elapsedKHs*1000))/mElapsed);
//Print hashrate to serial
Serial.printf(">>> Completed %d share(s), %d Khashes, avg. hashrate %s KH/s\n",
shares, totalKHashes, CurrentHashrate);
}
void show_MinerScreen(unsigned long mElapsed){
//Print background screen
@ -232,22 +243,24 @@ void show_MinerScreen(unsigned long mElapsed){
shares, totalKHashes, CurrentHashrate);
//Hashrate
render.setFontSize(70);
render.setFontSize(35);
render.setCursor(19, 118);
render.setFontColor(TFT_BLACK);
render.rdrawString(CurrentHashrate, 118, 114, TFT_BLACK);
//Total hashes
render.setFontSize(36);
render.setFontSize(18);
render.rdrawString(String(Mhashes).c_str(), 268, 138, TFT_BLACK);
//Block templates
render.setFontSize(36);
render.setFontSize(18);
render.drawString(String(templates).c_str(), 186, 20, 0xDEDB);
//16Bit shares
render.setFontSize(36);
render.drawString(String(halfshares).c_str(), 186, 48, 0xDEDB);
//Best diff
char best_diff_string[16] = {0};
suffix_string(best_diff, best_diff_string, 16, 0);
render.setFontSize(18);
render.drawString(String(best_diff_string).c_str(), 186, 48, 0xDEDB);
//32Bit shares
render.setFontSize(36);
render.setFontSize(18);
render.drawString(String(shares).c_str(), 186, 76, 0xDEDB);
//Hores
char timeMining[15];
@ -258,23 +271,23 @@ void show_MinerScreen(unsigned long mElapsed){
int mins = (secElapsed - (days * 86400) - (hours * 3600)) / 60; //Remove the number of hours and calculate the minutes.
int secs = secElapsed - (days * 86400) - (hours * 3600) - (mins * 60);
sprintf(timeMining, "%01d %02d:%02d:%02d", days, hours, mins, secs);
render.setFontSize(27);
render.setFontSize(14);
render.rdrawString(String(timeMining).c_str(), 315, 104, 0xDEDB);
//Valid Blocks
render.setFontSize(48);
render.setFontSize(24);
render.drawString(String(valids).c_str(), 285, 56, 0xDEDB);
//Print Temp
String temp = String(temperatureRead(), 0);
render.setFontSize(20);
render.setFontSize(10);
render.rdrawString(String(temp).c_str(), 239, 1, TFT_BLACK);
render.setFontSize(7);
render.setFontSize(4);
render.rdrawString(String(0).c_str(), 244, 3, TFT_BLACK);
//Print Hour
render.setFontSize(20);
render.setFontSize(10);
render.rdrawString(getTime().c_str(), 286, 1, TFT_BLACK);
// pool url
@ -302,7 +315,7 @@ void show_ClockScreen(unsigned long mElapsed){
shares, totalKHashes, CurrentHashrate);
//Hashrate
render.setFontSize(50);
render.setFontSize(25);
render.setCursor(19, 122);
render.setFontColor(TFT_BLACK);
@ -318,7 +331,7 @@ void show_ClockScreen(unsigned long mElapsed){
background.drawString(getBTCprice().c_str(), 202, 3, GFXFF);
//Print BlockHeight
render.setFontSize(36);
render.setFontSize(18);
render.rdrawString(getBlockHeight().c_str(), 254, 140, TFT_BLACK);
//Print Hour
@ -380,11 +393,11 @@ void show_GlobalHashScreen(unsigned long mElapsed){
background.drawString(gData.difficulty.c_str(), 302, 88, GFXFF);
//Print Global Hashrate
render.setFontSize(34);
render.setFontSize(17);
render.rdrawString(gData.globalHash.c_str(), 274, 145, TFT_BLACK);
//Print BlockHeight
render.setFontSize(55);
render.setFontSize(28);
gData.currentBlock = getBlockHeight();
render.rdrawString(gData.currentBlock.c_str(), 140, 104, 0xDEDB);
@ -408,3 +421,29 @@ void show_GlobalHashScreen(unsigned long mElapsed){
//Push prepared background to screen
background.pushSprite(0,0);
}
// Variables para controlar el parpadeo con millis()
unsigned long previousMillis = 0;
void doLedStuff(int ledPin){
unsigned long currentMillis = millis();
switch (mMonitor.NerdStatus) {
case NM_waitingConfig: digitalWrite(ledPin, HIGH); // LED encendido de forma continua
break;
case NM_Connecting: if (currentMillis - previousMillis >= 500) { //0.5sec blink
previousMillis = currentMillis;
digitalWrite(ledPin, !digitalRead(ledPin)); // Cambia el estado del LED
}
break;
case NM_hashing: if (currentMillis - previousMillis >= 100) { //0.1sec blink
previousMillis = currentMillis;
digitalWrite(ledPin, !digitalRead(ledPin)); // Cambia el estado del LED
}
break;
}
}

View File

@ -7,6 +7,7 @@
#define SCREEN_MINING 0
#define SCREEN_CLOCK 1
#define SCREEN_GLOBAL 2
#define NO_SCREEN 3 //Used when board has no TFT
//Time update period
#define UPDATE_PERIOD_h 5
@ -28,9 +29,16 @@
#define NEXT_HALVING_EVENT 840000
#define HALVING_BLOCKS 210000
enum NMState {
NM_waitingConfig,
NM_Connecting,
NM_hashing
};
typedef struct{
uint8_t screen;
bool rotation;
NMState NerdStatus;
}monitor_data;
typedef struct{
@ -43,10 +51,14 @@ typedef struct{
int halfHourFee;
}global_data;
void setup_monitor(void);
void show_MinerScreen(unsigned long mElapsed);
void show_ClockScreen(unsigned long mElapsed);
void show_GlobalHashScreen(unsigned long mElapsed);
void show_NoScreen(unsigned long mElapsed);
void changeScreen(void);
void doLedStuff(int ledPin);
#endif //MONITOR_API_H

View File

@ -113,15 +113,18 @@ double diff_from_target(void *target)
bool checkValid(unsigned char* hash, unsigned char* target) {
bool valid = true;
unsigned char diff_target[32];
memcpy(diff_target, &target, 32);
//convert target to little endian for comparison
reverse_bytes(diff_target, 32);
for(uint8_t i=31; i>=0; i--) {
if(hash[i] > target[i]) {
if(hash[i] > diff_target[i]) {
valid = false;
break;
} else if (hash[i] < target[i]) {
valid = true;
break;
}
}
#ifdef DEBUG_MINING
if (valid) {
Serial.print("\tvalid : ");
@ -392,3 +395,63 @@ miner_data calculateMiningData(mining_subscribe& mWorker, mining_job mJob){
#endif
return mMiner;
}
/* Convert a double value into a truncated string for displaying with its
* associated suitable for Mega, Giga etc. Buf array needs to be long enough */
void suffix_string(double val, char *buf, size_t bufsiz, int sigdigits)
{
const double kilo = 1000;
const double mega = 1000000;
const double giga = 1000000000;
const double tera = 1000000000000;
const double peta = 1000000000000000;
const double exa = 1000000000000000000;
// minimum diff value to display
const double min_diff = 0.001;
const byte maxNdigits = 2;
char suffix[2] = "";
bool decimal = true;
double dval;
if (val >= exa) {
val /= peta;
dval = val / kilo;
strcpy(suffix, "E");
} else if (val >= peta) {
val /= tera;
dval = val / kilo;
strcpy(suffix, "P");
} else if (val >= tera) {
val /= giga;
dval = val / kilo;
strcpy(suffix, "T");
} else if (val >= giga) {
val /= mega;
dval = val / kilo;
strcpy(suffix, "G");
} else if (val >= mega) {
val /= kilo;
dval = val / kilo;
strcpy(suffix, "M");
} else if (val >= kilo) {
dval = val / kilo;
strcpy(suffix, "K");
} else {
dval = val;
if (dval < min_diff)
dval = 0.0;
}
if (!sigdigits) {
if (decimal)
snprintf(buf, bufsiz, "%.3f%s", dval, suffix);
else
snprintf(buf, bufsiz, "%d%s", (unsigned int)dval, suffix);
} else {
/* Always show sigdigits + 1, padded on right with zeroes
* followed by suffix */
int ndigits = sigdigits - 1 - (dval > 0.0 ? floor(log10(dval)) : 0);
snprintf(buf, bufsiz, "%*.*f%s", sigdigits + 1, ndigits, dval, suffix);
}
}

View File

@ -22,6 +22,7 @@ double le256todouble(const void *target);
double diff_from_target(void *target);
miner_data calculateMiningData(mining_subscribe& mWorker, mining_job mJob);
bool checkValid(unsigned char* hash, unsigned char* target);
void suffix_string(double val, char *buf, size_t bufsiz, int sigdigits);

View File

@ -11,6 +11,7 @@
#include "media/images.h"
#include <TFT_eSPI.h> // Graphics and font library
#include "wManager.h"
#include "monitor.h"
// JSON configuration file
#define JSON_CONFIG_FILE "/config.json"
@ -19,7 +20,7 @@
bool shouldSaveConfig = false;
// Variables to hold data from custom textboxes
char poolString[80] = "public-pool.airdns.org";
char poolString[80] = "public-pool.io";
int portNumber = 21496;//3333;
char btcString[80] = "yourBtcAddress";
int GMTzone = 2; //Currently selected in spain
@ -30,6 +31,7 @@ WiFiManager wm;
extern TFT_eSPI tft; // tft variable declared on main
extern monitor_data mMonitor;
void saveConfigFile()
// Save Config in JSON format
@ -146,11 +148,16 @@ void init_WifiManager()
// Change to true when testing to force configuration every time we run
bool forceConfig = false;
#if !defined(DEVKITV1)
// Check if button2 is pressed to enter configMode with actual configuration
if(!digitalRead(PIN_BUTTON_2)){
Serial.println(F("Button pressed to force start config mode"));
forceConfig = true;
wm.setBreakAfterConfig(true); //Set to detect config edition and save
}
#endif
bool spiffsSetup = loadConfigFile();
if (!spiffsSetup)
{
@ -234,6 +241,7 @@ void init_WifiManager()
else
{
//Tratamos de conectar con la configuración inicial ya almacenada
mMonitor.NerdStatus = NM_Connecting;
wm.setCaptivePortalEnable(false); // disable captive portal redirection
if (!wm.autoConnect("NerdMinerAP","MineYourCoins"))
{
@ -245,6 +253,8 @@ void init_WifiManager()
}
}
mMonitor.NerdStatus = NM_Connecting;
//Conectado a la red Wifi
if(WiFi.status() == WL_CONNECTED){
//tft.pushImage(0, 0, MinerWidth, MinerHeight, MinerScreen);

View File

@ -1,7 +1,16 @@
//Botón configuración
#ifdef NERDMINERV2
//Define config buttons for TTGO-TDisplay-s3
#define PIN_BUTTON_1 0
#define PIN_BUTTON_2 14
#define PIN_ENABLE5V 15
#elif defined(DEVKITV1)
//Standard ESP32-devKit
#define PIN_BUTTON_1 0
#define PIN_BUTTON_2 19 //Not used
#define PIN_ENABLE5V 21 //Not used
#define LED_PIN 2
#endif
void init_WifiManager();
void wifiManagerProcess();

View File

@ -1,11 +0,0 @@
This directory is intended for PlatformIO Test Runner and project tests.
Unit Testing is a software testing method by which individual units of
source code, sets of one or more MCU program modules together with associated
control data, usage procedures, and operating procedures, are tested to
determine whether they are fit for use. Unit testing finds problems early
in the development cycle.
More information about PlatformIO Unit Testing:
- https://docs.platformio.org/en/latest/advanced/unit-testing/index.html

View File

@ -1,5 +0,0 @@
.pio
.vscode/.browse.c_cpp.db*
.vscode/c_cpp_properties.json
.vscode/launch.json
.vscode/ipch

View File

@ -1,39 +0,0 @@
This directory is intended for project header files.
A header file is a file containing C declarations and macro definitions
to be shared between several project source files. You request the use of a
header file in your project source file (C, C++, etc) located in `src` folder
by including it, with the C preprocessing directive `#include'.
```src/main.c
#include "header.h"
int main (void)
{
...
}
```
Including a header file produces the same results as copying the header file
into each source file that needs it. Such copying would be time-consuming
and error-prone. With a header file, the related declarations appear
in only one place. If they need to be changed, they can be changed in one
place, and programs that include the header file will automatically use the
new version when next recompiled. The header file eliminates the labor of
finding and changing all the copies as well as the risk that a failure to
find one copy will result in inconsistencies within a program.
In C, the usual convention is to give header files names that end with `.h'.
It is most portable to use only letters, digits, dashes, and underscores in
header file names, and at most one dot.
Read more about using header files in official GCC documentation:
* Include Syntax
* Include Operation
* Once-Only Headers
* Computed Includes
https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html

View File

@ -1,46 +0,0 @@
This directory is intended for project specific (private) libraries.
PlatformIO will compile them to static libraries and link into executable file.
The source code of each library should be placed in a an own separate directory
("lib/your_library_name/[here are source files]").
For example, see a structure of the following two libraries `Foo` and `Bar`:
|--lib
| |
| |--Bar
| | |--docs
| | |--examples
| | |--src
| | |- Bar.c
| | |- Bar.h
| | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html
| |
| |--Foo
| | |- Foo.c
| | |- Foo.h
| |
| |- README --> THIS FILE
|
|- platformio.ini
|--src
|- main.c
and a contents of `src/main.c`:
```
#include <Foo.h>
#include <Bar.h>
int main (void)
{
...
}
```
PlatformIO Library Dependency Finder will find automatically dependent
libraries scanning project source files.
More information about PlatformIO Library Dependency Finder
- https://docs.platformio.org/page/librarymanager/ldf.html

View File

@ -1,36 +0,0 @@
; PlatformIO Project Configuration File
;
; Build options: build flags, source filter
; Upload options: custom upload port, speed and extra flags
; Library options: dependencies, extra library storages
; Advanced options: extra scripting
;
; Please visit documentation for the other options and examples
; https://docs.platformio.org/page/projectconf.html
[platformio]
globallib_dir = lib
default_envs = TestSHA
[env:TestSHA]
platform = espressif32
board = esp32-s3-devkitc-1
framework = arduino
monitor_filters =
esp32_exception_decoder
time
log2file
board_build.arduino.memory_type = qio_opi
monitor_speed = 115200
upload_speed = 115200
# 2 x 4.5MB app, 6.875MB SPIFFS
board_build.partitions = huge_app.csv
build_flags =
-D BOARD_HAS_PSRAM
-D ARDUINO_USB_MODE=1
-D ARDUINO_USB_CDC_ON_BOOT=1
;-D DEBUG_MINING=1
lib_deps =
https://github.com/golden-guy/Arduino_wolfssl.git#v5.5.4

View File

@ -1,222 +0,0 @@
#include "customSHA256.h"
#define TOTAL_LEN_LEN 8
/*
* Comments from pseudo-code at https://en.wikipedia.org/wiki/SHA-2 are reproduced here.
* When useful for clarification, portions of the pseudo-code are reproduced here too.
*/
/*
* @brief Rotate a 32-bit value by a number of bits to the right.
* @param value The value to be rotated.
* @param count The number of bits to rotate by.
* @return The rotated value.
*/
static inline uint32_t right_rot(uint32_t value, unsigned int count)
{
/*
* Defined behaviour in standard C for all count where 0 < count < 32, which is what we need here.
*/
return value >> count | value << (32 - count);
}
/*
* @brief Update a hash value under calculation with a new chunk of data.
* @param h Pointer to the first hash item, of a total of eight.
* @param p Pointer to the chunk data, which has a standard length.
*
* @note This is the SHA-256 work horse.
*/
static inline void consume_chunk(uint32_t *h, const uint8_t *p)
{
unsigned i, j;
uint32_t ah[8];
/* Initialize working variables to current hash value: */
for (i = 0; i < 8; i++)
ah[i] = h[i];
/*
* The w-array is really w[64], but since we only need 16 of them at a time, we save stack by
* calculating 16 at a time.
*
* This optimization was not there initially and the rest of the comments about w[64] are kept in their
* initial state.
*/
/*
* create a 64-entry message schedule array w[0..63] of 32-bit words (The initial values in w[0..63]
* don't matter, so many implementations zero them here) copy chunk into first 16 words w[0..15] of the
* message schedule array
*/
uint32_t w[16];
/* Compression function main loop: */
for (i = 0; i < 4; i++) {
for (j = 0; j < 16; j++) {
if (i == 0) {
w[j] =
(uint32_t)p[0] << 24 | (uint32_t)p[1] << 16 | (uint32_t)p[2] << 8 | (uint32_t)p[3];
p += 4;
} else {
/* Extend the first 16 words into the remaining 48 words w[16..63] of the
* message schedule array: */
const uint32_t s0 = right_rot(w[(j + 1) & 0xf], 7) ^ right_rot(w[(j + 1) & 0xf], 18) ^
(w[(j + 1) & 0xf] >> 3);
const uint32_t s1 = right_rot(w[(j + 14) & 0xf], 17) ^
right_rot(w[(j + 14) & 0xf], 19) ^ (w[(j + 14) & 0xf] >> 10);
w[j] = w[j] + s0 + w[(j + 9) & 0xf] + s1;
}
const uint32_t s1 = right_rot(ah[4], 6) ^ right_rot(ah[4], 11) ^ right_rot(ah[4], 25);
const uint32_t ch = (ah[4] & ah[5]) ^ (~ah[4] & ah[6]);
/*
* Initialize array of round constants:
* (first 32 bits of the fractional parts of the cube roots of the first 64 primes 2..311):
*/
static const uint32_t k[] = {
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4,
0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe,
0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f,
0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc,
0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b,
0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116,
0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7,
0xc67178f2};
const uint32_t temp1 = ah[7] + s1 + ch + k[i << 4 | j] + w[j];
const uint32_t s0 = right_rot(ah[0], 2) ^ right_rot(ah[0], 13) ^ right_rot(ah[0], 22);
const uint32_t maj = (ah[0] & ah[1]) ^ (ah[0] & ah[2]) ^ (ah[1] & ah[2]);
const uint32_t temp2 = s0 + maj;
ah[7] = ah[6];
ah[6] = ah[5];
ah[5] = ah[4];
ah[4] = ah[3] + temp1;
ah[3] = ah[2];
ah[2] = ah[1];
ah[1] = ah[0];
ah[0] = temp1 + temp2;
}
}
/* Add the compressed chunk to the current hash value: */
for (i = 0; i < 8; i++)
h[i] += ah[i];
}
/*
* Public functions. See header file for documentation.
*/
void sha_256_init(struct Sha_256 *sha_256, uint8_t hash[SIZE_OF_SHA_256_HASH])
{
sha_256->hash = hash;
sha_256->chunk_pos = sha_256->chunk;
sha_256->space_left = SIZE_OF_SHA_256_CHUNK;
sha_256->total_len = 0;
/*
* Initialize hash values (first 32 bits of the fractional parts of the square roots of the first 8 primes
* 2..19):
*/
sha_256->h[0] = 0x6a09e667;
sha_256->h[1] = 0xbb67ae85;
sha_256->h[2] = 0x3c6ef372;
sha_256->h[3] = 0xa54ff53a;
sha_256->h[4] = 0x510e527f;
sha_256->h[5] = 0x9b05688c;
sha_256->h[6] = 0x1f83d9ab;
sha_256->h[7] = 0x5be0cd19;
}
void sha_256_write(struct Sha_256 *sha_256, const uint8_t *data, size_t len)
{
sha_256->total_len += len;
const uint8_t *p = data;
while (len > 0) {
/*
* If the input chunks have sizes that are multiples of the calculation chunk size, no copies are
* necessary. We operate directly on the input data instead.
*/
if (sha_256->space_left == SIZE_OF_SHA_256_CHUNK && len >= SIZE_OF_SHA_256_CHUNK) {
consume_chunk(sha_256->h, p);
len -= SIZE_OF_SHA_256_CHUNK;
p += SIZE_OF_SHA_256_CHUNK;
continue;
}
/* General case, no particular optimization. */
const size_t consumed_len = len < sha_256->space_left ? len : sha_256->space_left;
memcpy(sha_256->chunk_pos, p, consumed_len);
sha_256->space_left -= consumed_len;
len -= consumed_len;
p += consumed_len;
if (sha_256->space_left == 0) {
consume_chunk(sha_256->h, sha_256->chunk);
sha_256->chunk_pos = sha_256->chunk;
sha_256->space_left = SIZE_OF_SHA_256_CHUNK;
} else {
sha_256->chunk_pos += consumed_len;
}
}
}
uint8_t *sha_256_close(struct Sha_256 *sha_256)
{
uint8_t *pos = sha_256->chunk_pos;
size_t space_left = sha_256->space_left;
uint32_t *const h = sha_256->h;
/*
* The current chunk cannot be full. Otherwise, it would already have been consumed. I.e. there is space left for
* at least one byte. The next step in the calculation is to add a single one-bit to the data.
*/
*pos++ = 0x80;
--space_left;
/*
* Now, the last step is to add the total data length at the end of the last chunk, and zero padding before
* that. But we do not necessarily have enough space left. If not, we pad the current chunk with zeroes, and add
* an extra chunk at the end.
*/
if (space_left < TOTAL_LEN_LEN) {
memset(pos, 0x00, space_left);
consume_chunk(h, sha_256->chunk);
pos = sha_256->chunk;
space_left = SIZE_OF_SHA_256_CHUNK;
}
const size_t left = space_left - TOTAL_LEN_LEN;
memset(pos, 0x00, left);
pos += left;
size_t len = sha_256->total_len;
pos[7] = (uint8_t)(len << 3);
len >>= 5;
int i;
for (i = 6; i >= 0; --i) {
pos[i] = (uint8_t)len;
len >>= 8;
}
consume_chunk(h, sha_256->chunk);
/* Produce the final hash value (big-endian): */
int j;
uint8_t *const hash = sha_256->hash;
for (i = 0, j = 0; i < 8; i++) {
hash[j++] = (uint8_t)(h[i] >> 24);
hash[j++] = (uint8_t)(h[i] >> 16);
hash[j++] = (uint8_t)(h[i] >> 8);
hash[j++] = (uint8_t)h[i];
}
return sha_256->hash;
}
void calc_sha_256(uint8_t hash[SIZE_OF_SHA_256_HASH], const uint8_t *input, size_t len)
{
struct Sha_256 sha_256;
sha_256_init(&sha_256, hash);
sha_256_write(&sha_256, input, len);
(void)sha_256_close(&sha_256);
}

View File

@ -1,103 +0,0 @@
#ifndef SHA_256_H
#define SHA_256_H
#include <stdint.h>
#include <string.h>
#ifdef __cplusplus
extern "C" {
#endif
/*
* @brief Size of the SHA-256 sum. This times eight is 256 bits.
*/
#define SIZE_OF_SHA_256_HASH 32
/*
* @brief Size of the chunks used for the calculations.
*
* @note This should mostly be ignored by the user, although when using the streaming API, it has an impact for
* performance. Add chunks whose size is a multiple of this, and you will avoid a lot of superfluous copying in RAM!
*/
#define SIZE_OF_SHA_256_CHUNK 64
/*
* @brief The opaque SHA-256 type, that should be instantiated when using the streaming API.
*
* @note Although the details are exposed here, in order to make instantiation easy, you should refrain from directly
* accessing the fields, as they may change in the future.
*/
struct Sha_256 {
uint8_t *hash;
uint8_t chunk[SIZE_OF_SHA_256_CHUNK];
uint8_t *chunk_pos;
size_t space_left;
size_t total_len;
uint32_t h[8];
};
/*
* @brief The simple SHA-256 calculation function.
* @param hash Hash array, where the result is delivered.
* @param input Pointer to the data the hash shall be calculated on.
* @param len Length of the input data, in byte.
*
* @note If all of the data you are calculating the hash value on is available in a contiguous buffer in memory, this is
* the function you should use.
*
* @note If either of the passed pointers is NULL, the results are unpredictable.
*/
void calc_sha_256(uint8_t hash[SIZE_OF_SHA_256_HASH], const uint8_t *input, size_t len);
/*
* @brief Initialize a SHA-256 streaming calculation.
* @param sha_256 A pointer to a SHA-256 structure.
* @param hash Hash array, where the result will be delivered.
*
* @note If all of the data you are calculating the hash value on is not available in a contiguous buffer in memory, this is
* where you should start. Instantiate a SHA-256 structure, for instance by simply declaring it locally, make your hash
* buffer available, and invoke this function. Once a SHA-256 hash has been calculated (see further below) a SHA-256
* structure can be initialized again for the next calculation.
*
* @note If either of the passed pointers is NULL, the results are unpredictable.
*/
void sha_256_init(struct Sha_256 *sha_256, uint8_t hash[SIZE_OF_SHA_256_HASH]);
/*
* @brief Stream more input data for an on-going SHA-256 calculation.
* @param sha_256 A pointer to a previously initialized SHA-256 structure.
* @param data Pointer to the data to be added to the calculation.
* @param len Length of the data to add, in byte.
*
* @note This function may be invoked an arbitrary number of times between initialization and closing, but the maximum
* data length is limited by the SHA-256 algorithm: the total number of bits (i.e. the total number of bytes times
* eight) must be representable by a 64-bit unsigned integer. While that is not a practical limitation, the results are
* unpredictable if that limit is exceeded.
*
* @note This function may be invoked on empty data (zero length), although that obviously will not add any data.
*
* @note If either of the passed pointers is NULL, the results are unpredictable.
*/
void sha_256_write(struct Sha_256 *sha_256, const uint8_t *data, size_t len);
/*
* @brief Conclude a SHA-256 streaming calculation, making the hash value available.
* @param sha_256 A pointer to a previously initialized SHA-256 structure.
* @return Pointer to the hash array, where the result is delivered.
*
* @note After this function has been invoked, the result is available in the hash buffer that initially was provided. A
* pointer to the hash value is returned for convenience, but you should feel free to ignore it: it is simply a pointer
* to the first byte of your initially provided hash array.
*
* @note If the passed pointer is NULL, the results are unpredictable.
*
* @note Invoking this function for a calculation with no data (the writing function has never been invoked, or it only
* has been invoked with empty data) is legal. It will calculate the SHA-256 value of the empty string.
*/
uint8_t *sha_256_close(struct Sha_256 *sha_256);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,704 +0,0 @@
#define NDEBUG
#include <stdio.h>
#include <string.h>
#include <Arduino.h>
//#include <wally_address.h>
//#include <wally_transaction.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include <esp_log.h>
#include <esp_timer.h>
#include "jadeSHA256.h"
#include <math.h>
#include <string.h>
#define HASH_SIZE 32
#ifndef PUT_UINT32_BE
#define PUT_UINT32_BE(n, data, offset) \
{ \
u.num = n; \
p = (data) + (offset); \
*p = u.b[3]; \
*(p + 1) = u.b[2]; \
*(p + 2) = u.b[1]; \
*(p + 3) = u.b[0]; \
}
#endif
#ifndef GET_UINT32_BE
#define GET_UINT32_BE(b, i) \
(((uint32_t)(b)[(i)] << 24) | ((uint32_t)(b)[(i) + 1] << 16) | ((uint32_t)(b)[(i) + 2] << 8) \
| ((uint32_t)(b)[(i) + 3]))
#endif
//DRAM_ATTR static const uint32_t K[] = {
static const uint32_t K[] = {
0x428A2F98,
0x71374491,
0xB5C0FBCF,
0xE9B5DBA5,
0x3956C25B,
0x59F111F1,
0x923F82A4,
0xAB1C5ED5,
0xD807AA98,
0x12835B01,
0x243185BE,
0x550C7DC3,
0x72BE5D74,
0x80DEB1FE,
0x9BDC06A7,
0xC19BF174,
0xE49B69C1,
0xEFBE4786,
0x0FC19DC6,
0x240CA1CC,
0x2DE92C6F,
0x4A7484AA,
0x5CB0A9DC,
0x76F988DA,
0x983E5152,
0xA831C66D,
0xB00327C8,
0xBF597FC7,
0xC6E00BF3,
0xD5A79147,
0x06CA6351,
0x14292967,
0x27B70A85,
0x2E1B2138,
0x4D2C6DFC,
0x53380D13,
0x650A7354,
0x766A0ABB,
0x81C2C92E,
0x92722C85,
0xA2BFE8A1,
0xA81A664B,
0xC24B8B70,
0xC76C51A3,
0xD192E819,
0xD6990624,
0xF40E3585,
0x106AA070,
0x19A4C116,
0x1E376C08,
0x2748774C,
0x34B0BCB5,
0x391C0CB3,
0x4ED8AA4A,
0x5B9CCA4F,
0x682E6FF3,
0x748F82EE,
0x78A5636F,
0x84C87814,
0x8CC70208,
0x90BEFFFA,
0xA4506CEB,
0xBEF9A3F7,
0xC67178F2,
};
#define SHR(x, n) ((x & 0xFFFFFFFF) >> n)
//#define ROTR(x, n) ((x >> n) | (x << ((sizeof(x) << 3) - n)))
#define ROTR(x, n) (SHR(x, n) | ((x) << (32 - (n))))
#define S0(x) (ROTR(x, 7) ^ ROTR(x, 18) ^ SHR(x, 3))
#define S1(x) (ROTR(x, 17) ^ ROTR(x, 19) ^ SHR(x, 10))
#define S2(x) (ROTR(x, 2) ^ ROTR(x, 13) ^ ROTR(x, 22))
#define S3(x) (ROTR(x, 6) ^ ROTR(x, 11) ^ ROTR(x, 25))
#define F0(x, y, z) ((x & y) | (z & (x | y)))
#define F1(x, y, z) (z ^ (x & (y ^ z)))
#define R(t) (W[t] = S1(W[t - 2]) + W[t - 7] + S0(W[t - 15]) + W[t - 16])
#define P(a, b, c, d, e, f, g, h, x, K) \
{ \
temp1 = h + S3(e) + F1(e, f, g) + K + x; \
temp2 = S2(a) + F0(a, b, c); \
d += temp1; \
h = temp1 + temp2; \
}
#define CHECK_BYTES(u1, u2, offset) \
{ \
temp1 = u1 + u2; \
for (int i = 0; i < 4; ++i) { \
temp3 = (uint8_t)((temp1 >> (i * 8)) & 0xff); \
temp4 = *(target + offset + i); \
if (__builtin_expect(temp4 < temp3, true)) { \
return false; \
} \
if (__builtin_expect(temp4 > temp3, false)) { \
return true; \
} \
} \
}
#define MAINET_TESTNET_INTERVAL 210000
#define REGTEST_INTERVAL 150
const char* TAG = "MINER";
typedef struct {
uint32_t version;
uint8_t prev_block[32];
uint8_t merkle_root[32];
uint32_t timestamp;
uint32_t bits;
uint32_t nonce;
} block_header;
typedef struct headerandtarget {
block_header bh;
uint8_t target[32];
} headerandtarget;
typedef struct task_ctx {
headerandtarget ht;
uint32_t hashespersec;
uint32_t nonce_start;
uint32_t* nonce_solution;
uint8_t task_n;
bool* solution_found;
bool newwork;
} task_ctx;
typedef struct miner_ctx {
uint8_t rawtx[300];
block_header bh;
int64_t start;
TaskHandle_t xHandle1;
TaskHandle_t xHandle2;
solution_cb cb;
void* cbctx;
task_ctx ctx1;
task_ctx ctx2;
size_t txlen;
bool solution_found;
} miner_ctx;
IRAM_ATTR void calc_midstate(uint8_t* buf_ptr, _sha256_context* midstate)
{
uint32_t A[8] = { 0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A, 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19 };
uint32_t temp1, temp2, W[64];
uint8_t i;
/*for (i = 0; i < 16; i++) {
W[i] = GET_UINT32_BE(buf_ptr, 4 * i);
}*/
W[0] = GET_UINT32_BE(buf_ptr, 0);
W[1] = GET_UINT32_BE(buf_ptr, 4);
W[2] = GET_UINT32_BE(buf_ptr, 8);
W[3] = GET_UINT32_BE(buf_ptr, 12);
W[4] = GET_UINT32_BE(buf_ptr, 16);
W[5] = GET_UINT32_BE(buf_ptr, 20);
W[6] = GET_UINT32_BE(buf_ptr, 24);
W[7] = GET_UINT32_BE(buf_ptr, 28);
W[8] = GET_UINT32_BE(buf_ptr, 32);
W[9] = GET_UINT32_BE(buf_ptr, 36);
W[10] = GET_UINT32_BE(buf_ptr, 40);
W[11] = GET_UINT32_BE(buf_ptr, 44);
W[12] = GET_UINT32_BE(buf_ptr, 48);
W[13] = GET_UINT32_BE(buf_ptr, 52);
W[14] = GET_UINT32_BE(buf_ptr, 56);
W[15] = GET_UINT32_BE(buf_ptr, 60);
for (i = 0; i < 16; i += 8) {
P(A[0], A[1], A[2], A[3], A[4],
A[5], A[6], A[7], W[i+0], K[i+0]);
P(A[7], A[0], A[1], A[2], A[3],
A[4], A[5], A[6], W[i+1], K[i+1]);
P(A[6], A[7], A[0], A[1], A[2],
A[3], A[4], A[5], W[i+2], K[i+2]);
P(A[5], A[6], A[7], A[0], A[1],
A[2], A[3], A[4], W[i+3], K[i+3]);
P(A[4], A[5], A[6], A[7], A[0],
A[1], A[2], A[3], W[i+4], K[i+4]);
P(A[3], A[4], A[5], A[6], A[7],
A[0], A[1], A[2], W[i+5], K[i+5]);
P(A[2], A[3], A[4], A[5], A[6],
A[7], A[0], A[1], W[i+6], K[i+6]);
P(A[1], A[2], A[3], A[4], A[5],
A[6], A[7], A[0], W[i+7], K[i+7]);
}
for (i = 16; i < 64; i += 8) {
P(A[0], A[1], A[2], A[3], A[4],
A[5], A[6], A[7], R(i+0), K[i+0]);
P(A[7], A[0], A[1], A[2], A[3],
A[4], A[5], A[6], R(i+1), K[i+1]);
P(A[6], A[7], A[0], A[1], A[2],
A[3], A[4], A[5], R(i+2), K[i+2]);
P(A[5], A[6], A[7], A[0], A[1],
A[2], A[3], A[4], R(i+3), K[i+3]);
P(A[4], A[5], A[6], A[7], A[0],
A[1], A[2], A[3], R(i+4), K[i+4]);
P(A[3], A[4], A[5], A[6], A[7],
A[0], A[1], A[2], R(i+5), K[i+5]);
P(A[2], A[3], A[4], A[5], A[6],
A[7], A[0], A[1], R(i+6), K[i+6]);
P(A[1], A[2], A[3], A[4], A[5],
A[6], A[7], A[0], R(i+7), K[i+7]);
}
for (i = 0; i < 8; i++) {
midstate->state[i] += A[i];
}
/*
P(A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], W[0], K[0]);
P(A[7], A[0], A[1], A[2], A[3], A[4], A[5], A[6], W[1], K[1]);
P(A[6], A[7], A[0], A[1], A[2], A[3], A[4], A[5], W[2], K[2]);
P(A[5], A[6], A[7], A[0], A[1], A[2], A[3], A[4], W[3], K[3]);
P(A[4], A[5], A[6], A[7], A[0], A[1], A[2], A[3], W[4], K[4]);
P(A[3], A[4], A[5], A[6], A[7], A[0], A[1], A[2], W[5], K[5]);
P(A[2], A[3], A[4], A[5], A[6], A[7], A[0], A[1], W[6], K[6]);
P(A[1], A[2], A[3], A[4], A[5], A[6], A[7], A[0], W[7], K[7]);
P(A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], W[8], K[8]);
P(A[7], A[0], A[1], A[2], A[3], A[4], A[5], A[6], W[9], K[9]);
P(A[6], A[7], A[0], A[1], A[2], A[3], A[4], A[5], W[10], K[10]);
P(A[5], A[6], A[7], A[0], A[1], A[2], A[3], A[4], W[11], K[11]);
P(A[4], A[5], A[6], A[7], A[0], A[1], A[2], A[3], W[12], K[12]);
P(A[3], A[4], A[5], A[6], A[7], A[0], A[1], A[2], W[13], K[13]);
P(A[2], A[3], A[4], A[5], A[6], A[7], A[0], A[1], W[14], K[14]);
P(A[1], A[2], A[3], A[4], A[5], A[6], A[7], A[0], W[15], K[15]);
P(A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], R(16), K[16]);
P(A[7], A[0], A[1], A[2], A[3], A[4], A[5], A[6], R(17), K[17]);
P(A[6], A[7], A[0], A[1], A[2], A[3], A[4], A[5], R(18), K[18]);
P(A[5], A[6], A[7], A[0], A[1], A[2], A[3], A[4], R(19), K[19]);
P(A[4], A[5], A[6], A[7], A[0], A[1], A[2], A[3], R(20), K[20]);
P(A[3], A[4], A[5], A[6], A[7], A[0], A[1], A[2], R(21), K[21]);
P(A[2], A[3], A[4], A[5], A[6], A[7], A[0], A[1], R(22), K[22]);
P(A[1], A[2], A[3], A[4], A[5], A[6], A[7], A[0], R(23), K[23]);
P(A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], R(24), K[24]);
P(A[7], A[0], A[1], A[2], A[3], A[4], A[5], A[6], R(25), K[25]);
P(A[6], A[7], A[0], A[1], A[2], A[3], A[4], A[5], R(26), K[26]);
P(A[5], A[6], A[7], A[0], A[1], A[2], A[3], A[4], R(27), K[27]);
P(A[4], A[5], A[6], A[7], A[0], A[1], A[2], A[3], R(28), K[28]);
P(A[3], A[4], A[5], A[6], A[7], A[0], A[1], A[2], R(29), K[29]);
P(A[2], A[3], A[4], A[5], A[6], A[7], A[0], A[1], R(30), K[30]);
P(A[1], A[2], A[3], A[4], A[5], A[6], A[7], A[0], R(31), K[31]);
P(A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], R(32), K[32]);
P(A[7], A[0], A[1], A[2], A[3], A[4], A[5], A[6], R(33), K[33]);
P(A[6], A[7], A[0], A[1], A[2], A[3], A[4], A[5], R(34), K[34]);
P(A[5], A[6], A[7], A[0], A[1], A[2], A[3], A[4], R(35), K[35]);
P(A[4], A[5], A[6], A[7], A[0], A[1], A[2], A[3], R(36), K[36]);
P(A[3], A[4], A[5], A[6], A[7], A[0], A[1], A[2], R(37), K[37]);
P(A[2], A[3], A[4], A[5], A[6], A[7], A[0], A[1], R(38), K[38]);
P(A[1], A[2], A[3], A[4], A[5], A[6], A[7], A[0], R(39), K[39]);
P(A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], R(40), K[40]);
P(A[7], A[0], A[1], A[2], A[3], A[4], A[5], A[6], R(41), K[41]);
P(A[6], A[7], A[0], A[1], A[2], A[3], A[4], A[5], R(42), K[42]);
P(A[5], A[6], A[7], A[0], A[1], A[2], A[3], A[4], R(43), K[43]);
P(A[4], A[5], A[6], A[7], A[0], A[1], A[2], A[3], R(44), K[44]);
P(A[3], A[4], A[5], A[6], A[7], A[0], A[1], A[2], R(45), K[45]);
P(A[2], A[3], A[4], A[5], A[6], A[7], A[0], A[1], R(46), K[46]);
P(A[1], A[2], A[3], A[4], A[5], A[6], A[7], A[0], R(47), K[47]);
P(A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], R(48), K[48]);
P(A[7], A[0], A[1], A[2], A[3], A[4], A[5], A[6], R(49), K[49]);
P(A[6], A[7], A[0], A[1], A[2], A[3], A[4], A[5], R(50), K[50]);
P(A[5], A[6], A[7], A[0], A[1], A[2], A[3], A[4], R(51), K[51]);
P(A[4], A[5], A[6], A[7], A[0], A[1], A[2], A[3], R(52), K[52]);
P(A[3], A[4], A[5], A[6], A[7], A[0], A[1], A[2], R(53), K[53]);
P(A[2], A[3], A[4], A[5], A[6], A[7], A[0], A[1], R(54), K[54]);
P(A[1], A[2], A[3], A[4], A[5], A[6], A[7], A[0], R(55), K[55]);
P(A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], R(56), K[56]);
P(A[7], A[0], A[1], A[2], A[3], A[4], A[5], A[6], R(57), K[57]);
P(A[6], A[7], A[0], A[1], A[2], A[3], A[4], A[5], R(58), K[58]);
P(A[5], A[6], A[7], A[0], A[1], A[2], A[3], A[4], R(59), K[59]);
P(A[4], A[5], A[6], A[7], A[0], A[1], A[2], A[3], R(60), K[60]);
P(A[3], A[4], A[5], A[6], A[7], A[0], A[1], A[2], R(61), K[61]);
P(A[2], A[3], A[4], A[5], A[6], A[7], A[0], A[1], R(62), K[62]);
P(A[1], A[2], A[3], A[4], A[5], A[6], A[7], A[0], R(63), K[63]);
midstate->state[0] = 0x6A09E667 + A[0];
midstate->state[1] = 0xBB67AE85 + A[1];
midstate->state[2] = 0x3C6EF372 + A[2];
midstate->state[3] = 0xA54FF53A + A[3];
midstate->state[4] = 0x510E527F + A[4];
midstate->state[5] = 0x9B05688C + A[5];
midstate->state[6] = 0x1F83D9AB + A[6];
midstate->state[7] = 0x5BE0CD19 + A[7];
*/
//midstate->buffer[16] = 0x80;
memcpy(midstate->buffer, buf_ptr + 64, 12);
}
IRAM_ATTR bool make_double_sha(_sha256_context* midstate)
{
uint32_t temp1, temp2;
uint8_t temp3, temp4;
uint32_t W[64] = { GET_UINT32_BE(midstate->buffer, 0), GET_UINT32_BE(midstate->buffer, 4),
GET_UINT32_BE(midstate->buffer, 8), GET_UINT32_BE(midstate->buffer, 12), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 640, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
uint32_t A[8] = { midstate->state[0], midstate->state[1], midstate->state[2], midstate->state[3],
midstate->state[4], midstate->state[5], midstate->state[6], midstate->state[7] };
//0x80000000
union {
uint32_t num;
uint8_t b[4];
} u;
uint8_t* p = NULL;
uint8_t i;
for (i = 0; i < 16; i += 8) {
P(A[0], A[1], A[2], A[3], A[4],
A[5], A[6], A[7], W[i+0], K[i+0]);
P(A[7], A[0], A[1], A[2], A[3],
A[4], A[5], A[6], W[i+1], K[i+1]);
P(A[6], A[7], A[0], A[1], A[2],
A[3], A[4], A[5], W[i+2], K[i+2]);
P(A[5], A[6], A[7], A[0], A[1],
A[2], A[3], A[4], W[i+3], K[i+3]);
P(A[4], A[5], A[6], A[7], A[0],
A[1], A[2], A[3], W[i+4], K[i+4]);
P(A[3], A[4], A[5], A[6], A[7],
A[0], A[1], A[2], W[i+5], K[i+5]);
P(A[2], A[3], A[4], A[5], A[6],
A[7], A[0], A[1], W[i+6], K[i+6]);
P(A[1], A[2], A[3], A[4], A[5],
A[6], A[7], A[0], W[i+7], K[i+7]);
}
for (i = 16; i < 64; i += 8) {
P(A[0], A[1], A[2], A[3], A[4],
A[5], A[6], A[7], R(i+0), K[i+0]);
P(A[7], A[0], A[1], A[2], A[3],
A[4], A[5], A[6], R(i+1), K[i+1]);
P(A[6], A[7], A[0], A[1], A[2],
A[3], A[4], A[5], R(i+2), K[i+2]);
P(A[5], A[6], A[7], A[0], A[1],
A[2], A[3], A[4], R(i+3), K[i+3]);
P(A[4], A[5], A[6], A[7], A[0],
A[1], A[2], A[3], R(i+4), K[i+4]);
P(A[3], A[4], A[5], A[6], A[7],
A[0], A[1], A[2], R(i+5), K[i+5]);
P(A[2], A[3], A[4], A[5], A[6],
A[7], A[0], A[1], R(i+6), K[i+6]);
P(A[1], A[2], A[3], A[4], A[5],
A[6], A[7], A[0], R(i+7), K[i+7]);
}
/*
P(A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], W[0], K[0]);
P(A[7], A[0], A[1], A[2], A[3], A[4], A[5], A[6], W[1], K[1]);
P(A[6], A[7], A[0], A[1], A[2], A[3], A[4], A[5], W[2], K[2]);
P(A[5], A[6], A[7], A[0], A[1], A[2], A[3], A[4], W[3], K[3]);
P(A[4], A[5], A[6], A[7], A[0], A[1], A[2], A[3], W[4], K[4]);
P(A[3], A[4], A[5], A[6], A[7], A[0], A[1], A[2], W[5], K[5]);
P(A[2], A[3], A[4], A[5], A[6], A[7], A[0], A[1], W[6], K[6]);
P(A[1], A[2], A[3], A[4], A[5], A[6], A[7], A[0], W[7], K[7]);
P(A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], W[8], K[8]);
P(A[7], A[0], A[1], A[2], A[3], A[4], A[5], A[6], W[9], K[9]);
P(A[6], A[7], A[0], A[1], A[2], A[3], A[4], A[5], W[10], K[10]);
P(A[5], A[6], A[7], A[0], A[1], A[2], A[3], A[4], W[11], K[11]);
P(A[4], A[5], A[6], A[7], A[0], A[1], A[2], A[3], W[12], K[12]);
P(A[3], A[4], A[5], A[6], A[7], A[0], A[1], A[2], W[13], K[13]);
P(A[2], A[3], A[4], A[5], A[6], A[7], A[0], A[1], W[14], K[14]);
P(A[1], A[2], A[3], A[4], A[5], A[6], A[7], A[0], W[15], K[15]);
P(A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], R(16), K[16]);
P(A[7], A[0], A[1], A[2], A[3], A[4], A[5], A[6], R(17), K[17]);
P(A[6], A[7], A[0], A[1], A[2], A[3], A[4], A[5], R(18), K[18]);
P(A[5], A[6], A[7], A[0], A[1], A[2], A[3], A[4], R(19), K[19]);
P(A[4], A[5], A[6], A[7], A[0], A[1], A[2], A[3], R(20), K[20]);
P(A[3], A[4], A[5], A[6], A[7], A[0], A[1], A[2], R(21), K[21]);
P(A[2], A[3], A[4], A[5], A[6], A[7], A[0], A[1], R(22), K[22]);
P(A[1], A[2], A[3], A[4], A[5], A[6], A[7], A[0], R(23), K[23]);
P(A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], R(24), K[24]);
P(A[7], A[0], A[1], A[2], A[3], A[4], A[5], A[6], R(25), K[25]);
P(A[6], A[7], A[0], A[1], A[2], A[3], A[4], A[5], R(26), K[26]);
P(A[5], A[6], A[7], A[0], A[1], A[2], A[3], A[4], R(27), K[27]);
P(A[4], A[5], A[6], A[7], A[0], A[1], A[2], A[3], R(28), K[28]);
P(A[3], A[4], A[5], A[6], A[7], A[0], A[1], A[2], R(29), K[29]);
P(A[2], A[3], A[4], A[5], A[6], A[7], A[0], A[1], R(30), K[30]);
P(A[1], A[2], A[3], A[4], A[5], A[6], A[7], A[0], R(31), K[31]);
P(A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], R(32), K[32]);
P(A[7], A[0], A[1], A[2], A[3], A[4], A[5], A[6], R(33), K[33]);
P(A[6], A[7], A[0], A[1], A[2], A[3], A[4], A[5], R(34), K[34]);
P(A[5], A[6], A[7], A[0], A[1], A[2], A[3], A[4], R(35), K[35]);
P(A[4], A[5], A[6], A[7], A[0], A[1], A[2], A[3], R(36), K[36]);
P(A[3], A[4], A[5], A[6], A[7], A[0], A[1], A[2], R(37), K[37]);
P(A[2], A[3], A[4], A[5], A[6], A[7], A[0], A[1], R(38), K[38]);
P(A[1], A[2], A[3], A[4], A[5], A[6], A[7], A[0], R(39), K[39]);
P(A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], R(40), K[40]);
P(A[7], A[0], A[1], A[2], A[3], A[4], A[5], A[6], R(41), K[41]);
P(A[6], A[7], A[0], A[1], A[2], A[3], A[4], A[5], R(42), K[42]);
P(A[5], A[6], A[7], A[0], A[1], A[2], A[3], A[4], R(43), K[43]);
P(A[4], A[5], A[6], A[7], A[0], A[1], A[2], A[3], R(44), K[44]);
P(A[3], A[4], A[5], A[6], A[7], A[0], A[1], A[2], R(45), K[45]);
P(A[2], A[3], A[4], A[5], A[6], A[7], A[0], A[1], R(46), K[46]);
P(A[1], A[2], A[3], A[4], A[5], A[6], A[7], A[0], R(47), K[47]);
P(A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], R(48), K[48]);
P(A[7], A[0], A[1], A[2], A[3], A[4], A[5], A[6], R(49), K[49]);
P(A[6], A[7], A[0], A[1], A[2], A[3], A[4], A[5], R(50), K[50]);
P(A[5], A[6], A[7], A[0], A[1], A[2], A[3], A[4], R(51), K[51]);
P(A[4], A[5], A[6], A[7], A[0], A[1], A[2], A[3], R(52), K[52]);
P(A[3], A[4], A[5], A[6], A[7], A[0], A[1], A[2], R(53), K[53]);
P(A[2], A[3], A[4], A[5], A[6], A[7], A[0], A[1], R(54), K[54]);
P(A[1], A[2], A[3], A[4], A[5], A[6], A[7], A[0], R(55), K[55]);
P(A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], R(56), K[56]);
P(A[7], A[0], A[1], A[2], A[3], A[4], A[5], A[6], R(57), K[57]);
P(A[6], A[7], A[0], A[1], A[2], A[3], A[4], A[5], R(58), K[58]);
P(A[5], A[6], A[7], A[0], A[1], A[2], A[3], A[4], R(59), K[59]);
P(A[4], A[5], A[6], A[7], A[0], A[1], A[2], A[3], R(60), K[60]);
P(A[3], A[4], A[5], A[6], A[7], A[0], A[1], A[2], R(61), K[61]);
P(A[2], A[3], A[4], A[5], A[6], A[7], A[0], A[1], R(62), K[62]);
P(A[1], A[2], A[3], A[4], A[5], A[6], A[7], A[0], R(63), K[63]);
*/
PUT_UINT32_BE(midstate->state[0] + A[0], midstate->buffer, 0);
PUT_UINT32_BE(midstate->state[1] + A[1], midstate->buffer, 4);
PUT_UINT32_BE(midstate->state[2] + A[2], midstate->buffer, 8);
PUT_UINT32_BE(midstate->state[3] + A[3], midstate->buffer, 12);
PUT_UINT32_BE(midstate->state[4] + A[4], midstate->buffer, 16);
PUT_UINT32_BE(midstate->state[5] + A[5], midstate->buffer, 20);
PUT_UINT32_BE(midstate->state[6] + A[6], midstate->buffer, 24);
PUT_UINT32_BE(midstate->state[7] + A[7], midstate->buffer, 28);
/* Calculate the second hash (double SHA-256) */
A[0] = 0x6A09E667;
A[1] = 0xBB67AE85;
A[2] = 0x3C6EF372;
A[3] = 0xA54FF53A;
A[4] = 0x510E527F;
A[5] = 0x9B05688C;
A[6] = 0x1F83D9AB;
A[7] = 0x5BE0CD19;
midstate->buffer[32] = 0x80;
W[0] = GET_UINT32_BE(midstate->buffer, 0);
W[1] = GET_UINT32_BE(midstate->buffer, 4);
W[2] = GET_UINT32_BE(midstate->buffer, 8);
W[3] = GET_UINT32_BE(midstate->buffer, 12);
W[4] = GET_UINT32_BE(midstate->buffer, 16);
W[5] = GET_UINT32_BE(midstate->buffer, 20);
W[6] = GET_UINT32_BE(midstate->buffer, 24);
W[7] = GET_UINT32_BE(midstate->buffer, 28);
W[8] = GET_UINT32_BE(midstate->buffer, 32);
W[9] = GET_UINT32_BE(midstate->buffer, 36);
W[10] = GET_UINT32_BE(midstate->buffer, 40);
W[11] = GET_UINT32_BE(midstate->buffer, 44);
W[12] = GET_UINT32_BE(midstate->buffer, 48);
W[13] = GET_UINT32_BE(midstate->buffer, 52);
W[14] = 0;
W[15] = 256;
for (i = 0; i < 16; i += 8) {
P(A[0], A[1], A[2], A[3], A[4],
A[5], A[6], A[7], W[i+0], K[i+0]);
P(A[7], A[0], A[1], A[2], A[3],
A[4], A[5], A[6], W[i+1], K[i+1]);
P(A[6], A[7], A[0], A[1], A[2],
A[3], A[4], A[5], W[i+2], K[i+2]);
P(A[5], A[6], A[7], A[0], A[1],
A[2], A[3], A[4], W[i+3], K[i+3]);
P(A[4], A[5], A[6], A[7], A[0],
A[1], A[2], A[3], W[i+4], K[i+4]);
P(A[3], A[4], A[5], A[6], A[7],
A[0], A[1], A[2], W[i+5], K[i+5]);
P(A[2], A[3], A[4], A[5], A[6],
A[7], A[0], A[1], W[i+6], K[i+6]);
P(A[1], A[2], A[3], A[4], A[5],
A[6], A[7], A[0], W[i+7], K[i+7]);
}
for (i = 16; i < 64; i += 8) {
P(A[0], A[1], A[2], A[3], A[4],
A[5], A[6], A[7], R(i+0), K[i+0]);
P(A[7], A[0], A[1], A[2], A[3],
A[4], A[5], A[6], R(i+1), K[i+1]);
P(A[6], A[7], A[0], A[1], A[2],
A[3], A[4], A[5], R(i+2), K[i+2]);
P(A[5], A[6], A[7], A[0], A[1],
A[2], A[3], A[4], R(i+3), K[i+3]);
P(A[4], A[5], A[6], A[7], A[0],
A[1], A[2], A[3], R(i+4), K[i+4]);
P(A[3], A[4], A[5], A[6], A[7],
A[0], A[1], A[2], R(i+5), K[i+5]);
P(A[2], A[3], A[4], A[5], A[6],
A[7], A[0], A[1], R(i+6), K[i+6]);
P(A[1], A[2], A[3], A[4], A[5],
A[6], A[7], A[0], R(i+7), K[i+7]);
}
/*
P(A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], W[0], K[0]);
P(A[7], A[0], A[1], A[2], A[3], A[4], A[5], A[6], W[1], K[1]);
P(A[6], A[7], A[0], A[1], A[2], A[3], A[4], A[5], W[2], K[2]);
P(A[5], A[6], A[7], A[0], A[1], A[2], A[3], A[4], W[3], K[3]);
P(A[4], A[5], A[6], A[7], A[0], A[1], A[2], A[3], W[4], K[4]);
P(A[3], A[4], A[5], A[6], A[7], A[0], A[1], A[2], W[5], K[5]);
P(A[2], A[3], A[4], A[5], A[6], A[7], A[0], A[1], W[6], K[6]);
P(A[1], A[2], A[3], A[4], A[5], A[6], A[7], A[0], W[7], K[7]);
P(A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], W[8], K[8]);
P(A[7], A[0], A[1], A[2], A[3], A[4], A[5], A[6], W[9], K[9]);
P(A[6], A[7], A[0], A[1], A[2], A[3], A[4], A[5], W[10], K[10]);
P(A[5], A[6], A[7], A[0], A[1], A[2], A[3], A[4], W[11], K[11]);
P(A[4], A[5], A[6], A[7], A[0], A[1], A[2], A[3], W[12], K[12]);
P(A[3], A[4], A[5], A[6], A[7], A[0], A[1], A[2], W[13], K[13]);
P(A[2], A[3], A[4], A[5], A[6], A[7], A[0], A[1], W[14], K[14]);
P(A[1], A[2], A[3], A[4], A[5], A[6], A[7], A[0], W[15], K[15]);
P(A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], R(16), K[16]);
P(A[7], A[0], A[1], A[2], A[3], A[4], A[5], A[6], R(17), K[17]);
P(A[6], A[7], A[0], A[1], A[2], A[3], A[4], A[5], R(18), K[18]);
P(A[5], A[6], A[7], A[0], A[1], A[2], A[3], A[4], R(19), K[19]);
P(A[4], A[5], A[6], A[7], A[0], A[1], A[2], A[3], R(20), K[20]);
P(A[3], A[4], A[5], A[6], A[7], A[0], A[1], A[2], R(21), K[21]);
P(A[2], A[3], A[4], A[5], A[6], A[7], A[0], A[1], R(22), K[22]);
P(A[1], A[2], A[3], A[4], A[5], A[6], A[7], A[0], R(23), K[23]);
P(A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], R(24), K[24]);
P(A[7], A[0], A[1], A[2], A[3], A[4], A[5], A[6], R(25), K[25]);
P(A[6], A[7], A[0], A[1], A[2], A[3], A[4], A[5], R(26), K[26]);
P(A[5], A[6], A[7], A[0], A[1], A[2], A[3], A[4], R(27), K[27]);
P(A[4], A[5], A[6], A[7], A[0], A[1], A[2], A[3], R(28), K[28]);
P(A[3], A[4], A[5], A[6], A[7], A[0], A[1], A[2], R(29), K[29]);
P(A[2], A[3], A[4], A[5], A[6], A[7], A[0], A[1], R(30), K[30]);
P(A[1], A[2], A[3], A[4], A[5], A[6], A[7], A[0], R(31), K[31]);
P(A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], R(32), K[32]);
P(A[7], A[0], A[1], A[2], A[3], A[4], A[5], A[6], R(33), K[33]);
P(A[6], A[7], A[0], A[1], A[2], A[3], A[4], A[5], R(34), K[34]);
P(A[5], A[6], A[7], A[0], A[1], A[2], A[3], A[4], R(35), K[35]);
P(A[4], A[5], A[6], A[7], A[0], A[1], A[2], A[3], R(36), K[36]);
P(A[3], A[4], A[5], A[6], A[7], A[0], A[1], A[2], R(37), K[37]);
P(A[2], A[3], A[4], A[5], A[6], A[7], A[0], A[1], R(38), K[38]);
P(A[1], A[2], A[3], A[4], A[5], A[6], A[7], A[0], R(39), K[39]);
P(A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], R(40), K[40]);
P(A[7], A[0], A[1], A[2], A[3], A[4], A[5], A[6], R(41), K[41]);
P(A[6], A[7], A[0], A[1], A[2], A[3], A[4], A[5], R(42), K[42]);
P(A[5], A[6], A[7], A[0], A[1], A[2], A[3], A[4], R(43), K[43]);
P(A[4], A[5], A[6], A[7], A[0], A[1], A[2], A[3], R(44), K[44]);
P(A[3], A[4], A[5], A[6], A[7], A[0], A[1], A[2], R(45), K[45]);
P(A[2], A[3], A[4], A[5], A[6], A[7], A[0], A[1], R(46), K[46]);
P(A[1], A[2], A[3], A[4], A[5], A[6], A[7], A[0], R(47), K[47]);
P(A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], R(48), K[48]);
P(A[7], A[0], A[1], A[2], A[3], A[4], A[5], A[6], R(49), K[49]);
P(A[6], A[7], A[0], A[1], A[2], A[3], A[4], A[5], R(50), K[50]);
P(A[5], A[6], A[7], A[0], A[1], A[2], A[3], A[4], R(51), K[51]);
P(A[4], A[5], A[6], A[7], A[0], A[1], A[2], A[3], R(52), K[52]);
P(A[3], A[4], A[5], A[6], A[7], A[0], A[1], A[2], R(53), K[53]);
P(A[2], A[3], A[4], A[5], A[6], A[7], A[0], A[1], R(54), K[54]);
P(A[1], A[2], A[3], A[4], A[5], A[6], A[7], A[0], R(55), K[55]);
P(A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], R(56), K[56]);
P(A[7], A[0], A[1], A[2], A[3], A[4], A[5], A[6], R(57), K[57]);
P(A[6], A[7], A[0], A[1], A[2], A[3], A[4], A[5], R(58), K[58]);
P(A[5], A[6], A[7], A[0], A[1], A[2], A[3], A[4], R(59), K[59]);
P(A[4], A[5], A[6], A[7], A[0], A[1], A[2], A[3], R(60), K[60]);
//CHECK_BYTES(0x5BE0CD19, A[7], 0);
P(A[3], A[4], A[5], A[6], A[7], A[0], A[1], A[2], R(61), K[61]);
//CHECK_BYTES(0x1F83D9AB, A[6], 4);
P(A[2], A[3], A[4], A[5], A[6], A[7], A[0], A[1], R(62), K[62]);
//CHECK_BYTES(0x9B05688C, A[5], 8);
P(A[1], A[2], A[3], A[4], A[5], A[6], A[7], A[0], R(63), K[63]);
*/
/*CHECK_BYTES(0x510E527F, A[4], 12);
CHECK_BYTES(0xA54FF53A, A[3], 16);
CHECK_BYTES(0x3C6EF372, A[2], 20);
CHECK_BYTES(0xBB67AE85, A[1], 24);
CHECK_BYTES(0x6A09E667, A[0], 28);*/
PUT_UINT32_BE(midstate->state[0] + A[0], midstate->buffer, 0);
PUT_UINT32_BE(midstate->state[1] + A[1], midstate->buffer, 4);
PUT_UINT32_BE(midstate->state[2] + A[2], midstate->buffer, 8);
PUT_UINT32_BE(midstate->state[3] + A[3], midstate->buffer, 12);
PUT_UINT32_BE(midstate->state[4] + A[4], midstate->buffer, 16);
PUT_UINT32_BE(midstate->state[5] + A[5], midstate->buffer, 20);
PUT_UINT32_BE(midstate->state[6] + A[6], midstate->buffer, 24);
PUT_UINT32_BE(midstate->state[7] + A[7], midstate->buffer, 28);
return true;
}
static void minertask(void* pctx)
{
assert(pctx);
task_ctx* tctx ;
headerandtarget header;
bool* newwork = &tctx->newwork;
while (1) {
if (*newwork) {
*newwork = false;
break;
}
vTaskDelay(1 / portTICK_PERIOD_MS);
}
header = tctx->ht;
uint32_t* hashespersec = &tctx->hashespersec;
while (true) {
_sha256_context midstate_cached = { 0 };
calc_midstate((uint8_t*)&header.bh, &midstate_cached);
*((uint32_t*)&midstate_cached.buffer[12]) = tctx->nonce_start;
_sha256_context ctx = midstate_cached;
while (true) {
//const bool within = verify_nonce(&ctx, header.target);
const bool within = false;
if (__builtin_expect(within, false)) {
*tctx->nonce_solution = *((uint32_t*)&midstate_cached.buffer[12]);
*tctx->solution_found = true;
/* wait until we have a new header to work on */
while (1) {
if (__builtin_expect(*newwork, false)) {
*newwork = false;
header = tctx->ht;
break;
}
vTaskDelay(1 / portTICK_PERIOD_MS);
}
break;
}
if (__builtin_expect(*newwork, false)) {
*newwork = false;
header = tctx->ht;
break;
}
*hashespersec = (*((uint32_t*)&midstate_cached.buffer[12]) += 1) - tctx->nonce_start;
ctx = midstate_cached;
}
}
}
bool check_solutions(void* ctx)
{
assert(ctx);
miner_ctx* mctx;
/* missing memory barrier but appers to work */
/* FIXME: find upper bound for solution len ?*/
if (!mctx->solution_found) {
return false;
}
uint8_t solution[600];
memcpy(solution, &mctx->bh, 80);
solution[80] = 0x01; /* number of transactions, solo mining :( */
memcpy(solution + 81, mctx->rawtx, mctx->txlen);
mctx->cb(mctx->cbctx, solution, 81 + mctx->txlen);
mctx->solution_found = false;
return true;
}
void check_speed(void* ctx, uint32_t* speed)
{
/* missing memory barrier but appers to work */
assert(ctx);
miner_ctx* mctx;
*speed = ((mctx->ctx1.hashespersec + mctx->ctx2.hashespersec) / ((esp_timer_get_time() - mctx->start) / 1000000.0));
}

View File

@ -1,22 +0,0 @@
#ifndef jadeSHA256_H_
#define jadeSHA256_H_
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
typedef struct _sha256_context {
uint8_t buffer[64];
uint32_t state[8];
} _sha256_context;
/* Calculate midstate */
IRAM_ATTR void calc_midstate(uint8_t* buf_ptr, _sha256_context* midstate);
IRAM_ATTR bool make_double_sha(_sha256_context* midstate);
/* We need a way to tell the miner to us that there is a solution */
typedef void (*solution_cb)(void* ctx, const uint8_t*, uint32_t);
#endif /* jadeSHA256_H_ */

View File

@ -1,567 +0,0 @@
#define NDEBUG
#include <stdio.h>
#include <string.h>
#include <Arduino.h>
//#include <wolfssl/wolfcrypt/sha256.h>
#include <esp_log.h>
#include <esp_timer.h>
#include "nerdSHA256.h"
#include <math.h>
#include <string.h>
#define HASH_SIZE 32
IRAM_ATTR static inline uint32_t rotlFixed(uint32_t x, uint32_t y)
{
return (x << y) | (x >> (sizeof(y) * 8 - y));
}
IRAM_ATTR static inline uint32_t rotrFixed(uint32_t x, uint32_t y)
{
return (x >> y) | (x << (sizeof(y) * 8 - y));
}
/* SHA256 math based on specification */
#define Ch(x,y,z) ((z) ^ ((x) & ((y) ^ (z))))
#define Maj(x,y,z) ((((x) | (y)) & (z)) | ((x) & (y)))
//#define R(x, n) (((x) & 0xFFFFFFFFU) >> (n))
#define S(x, n) rotrFixed(x, n)
#define Sigma0(x) (S(x, 2) ^ S(x, 13) ^ S(x, 22))
#define Sigma1(x) (S(x, 6) ^ S(x, 11) ^ S(x, 25))
#define Gamma0(x) (S(x, 7) ^ S(x, 18) ^ R(x, 3))
#define Gamma1(x) (S(x, 17) ^ S(x, 19) ^ R(x, 10))
#define a(i) S[(0-(i)) & 7]
#define b(i) S[(1-(i)) & 7]
#define c(i) S[(2-(i)) & 7]
#define d(i) S[(3-(i)) & 7]
#define e(i) S[(4-(i)) & 7]
#define f(i) S[(5-(i)) & 7]
#define g(i) S[(6-(i)) & 7]
#define h(i) S[(7-(i)) & 7]
#define XTRANSFORM(S, D) Transform_Sha256((S),(D))
#define XMEMCPY(d,s,l) memcpy((d),(s),(l))
#define XMEMSET(b,c,l) memset((b),(c),(l))
/* SHA256 version that keeps all data in registers */
#define SCHED1(j) (W[j] = *((uint32_t*)&data[j*sizeof(uint32_t)]))
#define SCHED(j) ( \
W[ j & 15] += \
Gamma1(W[(j-2) & 15])+ \
W[(j-7) & 15] + \
Gamma0(W[(j-15) & 15]) \
)
#define RND1(j) \
t0 = h(j) + Sigma1(e(j)) + Ch(e(j), f(j), g(j)) + K[i+j] + SCHED1(j); \
t1 = Sigma0(a(j)) + Maj(a(j), b(j), c(j)); \
d(j) += t0; \
h(j) = t0 + t1
#define RNDN(j) \
t0 = h(j) + Sigma1(e(j)) + Ch(e(j), f(j), g(j)) + K[i+j] + SCHED(j); \
t1 = Sigma0(a(j)) + Maj(a(j), b(j), c(j)); \
d(j) += t0; \
h(j) = t0 + t1
#define SHR(x, n) ((x & 0xFFFFFFFF) >> n)
//#define ROTR(x, n) ((x >> n) | (x << ((sizeof(x) << 3) - n)))
#define ROTR(x, n) (SHR(x, n) | ((x) << (32 - (n))))
#define S0(x) (ROTR(x, 7) ^ ROTR(x, 18) ^ SHR(x, 3))
#define S1(x) (ROTR(x, 17) ^ ROTR(x, 19) ^ SHR(x, 10))
#define S2(x) (ROTR(x, 2) ^ ROTR(x, 13) ^ ROTR(x, 22))
#define S3(x) (ROTR(x, 6) ^ ROTR(x, 11) ^ ROTR(x, 25))
#define F0(x, y, z) ((x & y) | (z & (x | y)))
#define F1(x, y, z) (z ^ (x & (y ^ z)))
#define R(t) (W[t] = S1(W[t - 2]) + W[t - 7] + S0(W[t - 15]) + W[t - 16])
#define P(a, b, c, d, e, f, g, h, x, K) \
{ \
temp1 = h + S3(e) + F1(e, f, g) + K + x; \
temp2 = S2(a) + F0(a, b, c); \
d += temp1; \
h = temp1 + temp2; \
}
#define GET_UINT32_BE(b, i) \
(((uint32_t)(b)[(i)] << 24) | ((uint32_t)(b)[(i) + 1] << 16) | ((uint32_t)(b)[(i) + 2] << 8) \
| ((uint32_t)(b)[(i) + 3]))
//DRAM_ATTR static const uint32_t K[] = {
DRAM_ATTR static const uint32_t K[64] = {
0x428A2F98L, 0x71374491L, 0xB5C0FBCFL, 0xE9B5DBA5L, 0x3956C25BL,
0x59F111F1L, 0x923F82A4L, 0xAB1C5ED5L, 0xD807AA98L, 0x12835B01L,
0x243185BEL, 0x550C7DC3L, 0x72BE5D74L, 0x80DEB1FEL, 0x9BDC06A7L,
0xC19BF174L, 0xE49B69C1L, 0xEFBE4786L, 0x0FC19DC6L, 0x240CA1CCL,
0x2DE92C6FL, 0x4A7484AAL, 0x5CB0A9DCL, 0x76F988DAL, 0x983E5152L,
0xA831C66DL, 0xB00327C8L, 0xBF597FC7L, 0xC6E00BF3L, 0xD5A79147L,
0x06CA6351L, 0x14292967L, 0x27B70A85L, 0x2E1B2138L, 0x4D2C6DFCL,
0x53380D13L, 0x650A7354L, 0x766A0ABBL, 0x81C2C92EL, 0x92722C85L,
0xA2BFE8A1L, 0xA81A664BL, 0xC24B8B70L, 0xC76C51A3L, 0xD192E819L,
0xD6990624L, 0xF40E3585L, 0x106AA070L, 0x19A4C116L, 0x1E376C08L,
0x2748774CL, 0x34B0BCB5L, 0x391C0CB3L, 0x4ED8AA4AL, 0x5B9CCA4FL,
0x682E6FF3L, 0x748F82EEL, 0x78A5636FL, 0x84C87814L, 0x8CC70208L,
0x90BEFFFAL, 0xA4506CEBL, 0xBEF9A3F7L, 0xC67178F2L
};
/*
IRAM_ATTR static int Transform_Sha256(nerd_sha256* sha256, const uint8_t* buf_ptr)
{
uint32_t A[8] = {0 };
uint32_t temp1, temp2, W[64];
int i=0;
for (i = 0; i < 8; i++) {
A[i] = sha256->digest[i];
}
W[0] = GET_UINT32_BE(buf_ptr, 0);
W[1] = GET_UINT32_BE(buf_ptr, 4);
W[2] = GET_UINT32_BE(buf_ptr, 8);
W[3] = GET_UINT32_BE(buf_ptr, 12);
W[4] = GET_UINT32_BE(buf_ptr, 16);
W[5] = GET_UINT32_BE(buf_ptr, 20);
W[6] = GET_UINT32_BE(buf_ptr, 24);
W[7] = GET_UINT32_BE(buf_ptr, 28);
W[8] = GET_UINT32_BE(buf_ptr, 32);
W[9] = GET_UINT32_BE(buf_ptr, 36);
W[10] = GET_UINT32_BE(buf_ptr, 40);
W[11] = GET_UINT32_BE(buf_ptr, 44);
W[12] = GET_UINT32_BE(buf_ptr, 48);
W[13] = GET_UINT32_BE(buf_ptr, 52);
W[14] = GET_UINT32_BE(buf_ptr, 56);
W[15] = GET_UINT32_BE(buf_ptr, 60);
for (i = 0; i < 16; i += 8) {
P(A[0], A[1], A[2], A[3], A[4],
A[5], A[6], A[7], W[i+0], K[i+0]);
P(A[7], A[0], A[1], A[2], A[3],
A[4], A[5], A[6], W[i+1], K[i+1]);
P(A[6], A[7], A[0], A[1], A[2],
A[3], A[4], A[5], W[i+2], K[i+2]);
P(A[5], A[6], A[7], A[0], A[1],
A[2], A[3], A[4], W[i+3], K[i+3]);
P(A[4], A[5], A[6], A[7], A[0],
A[1], A[2], A[3], W[i+4], K[i+4]);
P(A[3], A[4], A[5], A[6], A[7],
A[0], A[1], A[2], W[i+5], K[i+5]);
P(A[2], A[3], A[4], A[5], A[6],
A[7], A[0], A[1], W[i+6], K[i+6]);
P(A[1], A[2], A[3], A[4], A[5],
A[6], A[7], A[0], W[i+7], K[i+7]);
}
for (i = 16; i < 64; i += 8) {
P(A[0], A[1], A[2], A[3], A[4],
A[5], A[6], A[7], R(i+0), K[i+0]);
P(A[7], A[0], A[1], A[2], A[3],
A[4], A[5], A[6], R(i+1), K[i+1]);
P(A[6], A[7], A[0], A[1], A[2],
A[3], A[4], A[5], R(i+2), K[i+2]);
P(A[5], A[6], A[7], A[0], A[1],
A[2], A[3], A[4], R(i+3), K[i+3]);
P(A[4], A[5], A[6], A[7], A[0],
A[1], A[2], A[3], R(i+4), K[i+4]);
P(A[3], A[4], A[5], A[6], A[7],
A[0], A[1], A[2], R(i+5), K[i+5]);
P(A[2], A[3], A[4], A[5], A[6],
A[7], A[0], A[1], R(i+6), K[i+6]);
P(A[1], A[2], A[3], A[4], A[5],
A[6], A[7], A[0], R(i+7), K[i+7]);
}
for (i = 0; i < 8; i++) {
sha256->digest[i] += A[i];
}
}
*/
IRAM_ATTR static int Transform_Sha256(nerd_sha256* sha256, const uint8_t* data)
{
uint32_t S[8], t0, t1;
int i;
uint32_t W[NERD_BLOCK_SIZE/sizeof(uint32_t)];
// Copy digest to working vars
S[0] = sha256->digest[0];
S[1] = sha256->digest[1];
S[2] = sha256->digest[2];
S[3] = sha256->digest[3];
S[4] = sha256->digest[4];
S[5] = sha256->digest[5];
S[6] = sha256->digest[6];
S[7] = sha256->digest[7];
i = 0;
RND1( 0); RND1( 1); RND1( 2); RND1( 3);
RND1( 4); RND1( 5); RND1( 6); RND1( 7);
RND1( 8); RND1( 9); RND1(10); RND1(11);
RND1(12); RND1(13); RND1(14); RND1(15);
// 64 operations, partially loop unrolled
for (i = 16; i < 64; i += 16) {
RNDN( 0); RNDN( 1); RNDN( 2); RNDN( 3);
RNDN( 4); RNDN( 5); RNDN( 6); RNDN( 7);
RNDN( 8); RNDN( 9); RNDN(10); RNDN(11);
RNDN(12); RNDN(13); RNDN(14); RNDN(15);
}
// Add the working vars back into digest
sha256->digest[0] += S[0];
sha256->digest[1] += S[1];
sha256->digest[2] += S[2];
sha256->digest[3] += S[3];
sha256->digest[4] += S[4];
sha256->digest[5] += S[5];
sha256->digest[6] += S[6];
sha256->digest[7] += S[7];
return 0;
}
IRAM_ATTR static uint32_t ByteReverseWord32(uint32_t value){
value = ((value & 0xFF00FF00) >> 8) | ((value & 0x00FF00FF) << 8);
return rotlFixed(value, 16U);
}
IRAM_ATTR static void ByteReverseWords(uint32_t* out, const uint32_t* in, uint32_t byteCount)
{
uint32_t count, i;
count = byteCount/(uint32_t)sizeof(uint32_t);
for (i = 0; i < count; i++) out[i] = ByteReverseWord32(in[i]);
}
IRAM_ATTR static int nerd_update(nerd_sha256* sha256, uint8_t* data, uint32_t len)
{
int ret = 0;
uint32_t blocksLen;
uint8_t* local;
//ShaUpdate
uint32_t tmp = sha256->loLen;
if ((sha256->loLen += len) < tmp) {
sha256->hiLen++; /* carry low to high */
}
local = (uint8_t*)sha256->buffer;
/* process any remainder from previous operation */
if (sha256->buffLen > 0) {
blocksLen = min(len, NERD_BLOCK_SIZE - sha256->buffLen);
XMEMCPY(&local[sha256->buffLen], data, blocksLen);
sha256->buffLen += blocksLen;
data += blocksLen;
len -= blocksLen;
if (sha256->buffLen == NERD_BLOCK_SIZE) {
ByteReverseWords(sha256->buffer, sha256->buffer, NERD_BLOCK_SIZE);
ret = XTRANSFORM(sha256, (const uint8_t*)local);
if (ret == 0)
sha256->buffLen = 0;
else
len = 0; /* error */
}
}
/* process blocks */
while (len >= NERD_BLOCK_SIZE) {
uint32_t* local32 = sha256->buffer;
XMEMCPY(local32, data, NERD_BLOCK_SIZE);
data += NERD_BLOCK_SIZE;
len -= NERD_BLOCK_SIZE;
ByteReverseWords(local32, local32, NERD_BLOCK_SIZE);
ret = XTRANSFORM(sha256, (const uint8_t*)local32);
if (ret != 0)
break;
}
/* save remainder */
if (ret == 0 && len > 0) {
XMEMCPY(local, data, len);
sha256->buffLen = len;
}
return ret;
}
IRAM_ATTR static int nerd_finishSHA(nerd_sha256* sha256, uint8_t* hash){
int ret;
uint8_t* local;
local = (uint8_t*)sha256->buffer;
local[sha256->buffLen++] = 0x80; // add 1
//Padd with zeros
if (sha256->buffLen > NERD_PAD_SIZE) {
XMEMSET(&local[sha256->buffLen], 0, NERD_BLOCK_SIZE - sha256->buffLen);
sha256->buffLen += NERD_BLOCK_SIZE - sha256->buffLen;
ByteReverseWords(sha256->buffer, sha256->buffer, NERD_BLOCK_SIZE);
XTRANSFORM(sha256, (const uint8_t*)local);
sha256->buffLen = 0;
}
XMEMSET(&local[sha256->buffLen], 0, NERD_PAD_SIZE - sha256->buffLen);
// put lengths in bits
sha256->hiLen = (sha256->loLen >> (8 * sizeof(sha256->loLen) - 3)) + (sha256->hiLen << 3);
sha256->loLen = sha256->loLen << 3;
ByteReverseWords(sha256->buffer, sha256->buffer, NERD_BLOCK_SIZE);
// ! length ordering dependent on digest endian type !
XMEMCPY(&local[NERD_PAD_SIZE], &sha256->hiLen, sizeof(uint32_t));
XMEMCPY(&local[NERD_PAD_SIZE + sizeof(uint32_t)], &sha256->loLen, sizeof(uint32_t));
XTRANSFORM(sha256, (const uint8_t*)local);
ByteReverseWords(sha256->digest, sha256->digest, NERD_DIGEST_SIZE);
//Copy temp hash
XMEMCPY(hash, sha256->digest, NERD_DIGEST_SIZE);
return 0;
}
IRAM_ATTR int nerd_midstate(nerd_sha256* sha256, uint8_t* data, uint32_t len)
{
int ret = 0;
uint32_t blocksLen;
uint8_t* local;
//Init SHA context
XMEMSET(sha256->digest, 0, sizeof(sha256->digest));
sha256->digest[0] = 0x6A09E667L;
sha256->digest[1] = 0xBB67AE85L;
sha256->digest[2] = 0x3C6EF372L;
sha256->digest[3] = 0xA54FF53AL;
sha256->digest[4] = 0x510E527FL;
sha256->digest[5] = 0x9B05688CL;
sha256->digest[6] = 0x1F83D9ABL;
sha256->digest[7] = 0x5BE0CD19L;
sha256->buffLen = 0;
sha256->loLen = 0;
sha256->hiLen = 0;
//endINIT Sha contexxt
nerd_update(sha256,data,len);
return 0;
}
/*
IRAM_ATTR int nerd_double_sha(nerd_sha256* midstate, uint8_t* data, uint8_t* doubleHash)
{
nerd_sha256 sha256;
int ret = 0;
uint8_t hash[32];
//Copy current context
XMEMCPY(&sha256, midstate, sizeof(nerd_sha256));
// ------ First SHA ------
nerd_update(&sha256,data,16); //Pending 16 bytes from 80 of blockheader
nerd_finishSHA(&sha256,hash);
// ------ Second SHA ------
//Init SHA context
XMEMSET(sha256.digest, 0, sizeof(sha256.digest));
sha256.digest[0] = 0x6A09E667L;
sha256.digest[1] = 0xBB67AE85L;
sha256.digest[2] = 0x3C6EF372L;
sha256.digest[3] = 0xA54FF53AL;
sha256.digest[4] = 0x510E527FL;
sha256.digest[5] = 0x9B05688CL;
sha256.digest[6] = 0x1F83D9ABL;
sha256.digest[7] = 0x5BE0CD19L;
sha256.buffLen = 0;
sha256.loLen = 0;
sha256.hiLen = 0;
//endINIT Sha context
nerd_update(&sha256,hash,32);
nerd_finishSHA(&sha256,doubleHash);
return 0;
}
*/
IRAM_ATTR int nerd_double_sha(nerd_sha256* midstate, uint8_t* data, uint8_t* doubleHash)
{
IRAM_DATA_ATTR nerd_sha256 sha256;
//nerd_sha256 sha256_2;
int ret = 0;
uint32_t blocksLen;
uint8_t* local;
uint8_t* local2;
uint8_t tmpHash[32];
uint8_t* hash;
//Copy current context
XMEMCPY(&sha256, midstate, sizeof(nerd_sha256));
// ----- 1rst SHA ------------
//*********** ShaUpdate ***********
uint32_t len = 16; //Pending bytes to make the sha256
uint32_t tmp = sha256.loLen;
if ((sha256.loLen += len) < tmp) {
sha256.hiLen++;
}
local = (uint8_t*)sha256.buffer;
// save remainder
if (ret == 0 && len > 0) {
XMEMCPY(local, data, len);
sha256.buffLen = len;
}
//*********** end update ***********
//*********** Init SHA_finish ***********
local[sha256.buffLen++] = 0x80; // add 1
XMEMSET(&local[sha256.buffLen], 0, NERD_PAD_SIZE - sha256.buffLen);
// put lengths in bits
sha256.hiLen = (sha256.loLen >> (8 * sizeof(sha256.loLen) - 3)) + (sha256.hiLen << 3);
sha256.loLen = sha256.loLen << 3;
ByteReverseWords(sha256.buffer, sha256.buffer, NERD_BLOCK_SIZE);
// ! length ordering dependent on digest endian type !
XMEMCPY(&local[NERD_PAD_SIZE], &sha256.hiLen, sizeof(uint32_t));
XMEMCPY(&local[NERD_PAD_SIZE + sizeof(uint32_t)], &sha256.loLen, sizeof(uint32_t));
XTRANSFORM(&sha256, (const uint8_t*)local);
ByteReverseWords((uint32_t* )tmpHash, sha256.digest, NERD_DIGEST_SIZE);
hash = tmpHash;
//*********** end SHA_finish ***********
// ----- 2nd SHA ------------
//Init SHA context again
XMEMSET(sha256.digest, 0, sizeof(sha256.digest));
sha256.digest[0] = 0x6A09E667L;
sha256.digest[1] = 0xBB67AE85L;
sha256.digest[2] = 0x3C6EF372L;
sha256.digest[3] = 0xA54FF53AL;
sha256.digest[4] = 0x510E527FL;
sha256.digest[5] = 0x9B05688CL;
sha256.digest[6] = 0x1F83D9ABL;
sha256.digest[7] = 0x5BE0CD19L;
sha256.buffLen = 0;
sha256.loLen = 0;
sha256.hiLen = 0;
//endINIT Sha context
//*********** ShaUpdate ***********
len = 32; //Current hash size to make the 2nd sha256
tmp = sha256.loLen;
if ((sha256.loLen += len) < tmp) {
sha256.hiLen++;
}
local2 = (uint8_t*)sha256.buffer;
// process any remainder from previous operation
if (sha256.buffLen > 0) {
blocksLen = min(len, NERD_BLOCK_SIZE - sha256.buffLen);
XMEMCPY(&local2[sha256.buffLen], hash, blocksLen);
sha256.buffLen += blocksLen;
hash += blocksLen;
len -= blocksLen;
if (sha256.buffLen == NERD_BLOCK_SIZE) {
ByteReverseWords(sha256.buffer, sha256.buffer, NERD_BLOCK_SIZE);
ret = XTRANSFORM(&sha256, (const uint8_t*)local2);
if (ret == 0)
sha256.buffLen = 0;
else
len = 0; // error
}
}
// process blocks
while (len >= NERD_BLOCK_SIZE) {
uint32_t* local32 = sha256.buffer;
XMEMCPY(local32, hash, NERD_BLOCK_SIZE);
hash += NERD_BLOCK_SIZE;
len -= NERD_BLOCK_SIZE;
ByteReverseWords(local32, local32, NERD_BLOCK_SIZE);
ret = XTRANSFORM(&sha256, (const uint8_t*)local32);
if (ret != 0)
break;
}
// save remainder
if (ret == 0 && len > 0) {
XMEMCPY(local2, hash, len);
sha256.buffLen = len;
}
//*********** end update ***********
//*********** Init SHA_finish ***********
//local2 = (uint8_t*)sha256.buffer;
local2[sha256.buffLen++] = 0x80; // add 1
//local2[33] = 0x80; // add 1
//Padd with zeros
if (sha256.buffLen > NERD_PAD_SIZE) {
XMEMSET(&local2[sha256.buffLen], 0, NERD_BLOCK_SIZE - sha256.buffLen);
sha256.buffLen += NERD_BLOCK_SIZE - sha256.buffLen;
//ByteReverseWords(sha256_2.buffer, sha256_2.buffer, NERD_BLOCK_SIZE);
XTRANSFORM(&sha256, (const uint8_t*)local2);
sha256.buffLen = 0;
}
XMEMSET(&local2[sha256.buffLen], 0, NERD_PAD_SIZE - sha256.buffLen);
// put lengths in bits
sha256.hiLen = (sha256.loLen >> (8 * sizeof(sha256.loLen) - 3)) + (sha256.hiLen << 3);
sha256.loLen = sha256.loLen << 3;
ByteReverseWords(sha256.buffer, sha256.buffer, NERD_BLOCK_SIZE);
// ! length ordering dependent on digest endian type !
XMEMCPY(&local2[NERD_PAD_SIZE], &sha256.hiLen, sizeof(uint32_t));
XMEMCPY(&local2[NERD_PAD_SIZE + sizeof(uint32_t)], &sha256.loLen, sizeof(uint32_t));
XTRANSFORM(&sha256, (const uint8_t*)local2);
ByteReverseWords((uint32_t*)doubleHash, sha256.digest, NERD_DIGEST_SIZE);
return 0;
}

View File

@ -1,26 +0,0 @@
#ifndef nerdSHA256_H_
#define nerdSHA256_H_
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#define NERD_DIGEST_SIZE 32
#define NERD_BLOCK_SIZE 64
#define NERD_PAD_SIZE 56
struct nerd_sha256 {
uint32_t digest[NERD_DIGEST_SIZE / sizeof(uint32_t)];
uint32_t buffer[NERD_BLOCK_SIZE / sizeof(uint32_t)];
uint32_t buffLen; /* in bytes */
uint32_t loLen; /* length in bytes */
uint32_t hiLen; /* length in bytes */
void* heap;
};
/* Calculate midstate */
IRAM_ATTR int nerd_midstate(nerd_sha256* sha256, uint8_t* data, uint32_t len);
IRAM_ATTR int nerd_double_sha(nerd_sha256* midstate, uint8_t* data, uint8_t* doubleHash);
#endif /* nerdSHA256_H_ */

View File

@ -1,168 +0,0 @@
#include <Arduino.h>
#include <esp_task_wdt.h>
#include "jadeSHA256.h"
#include "customSHA256.h"
#include "nerdSHA256.h"
#include "mbedtls/md.h"
#include "mbedtls/sha256.h"
#include <wolfssl/wolfcrypt/sha256.h>
/********* INIT *****/
void setup()
{
Serial.begin(115200);
Serial.setTimeout(0);
delay(100);
// Idle task that would reset WDT never runs, because core 0 gets fully utilized
//disableCore0WDT();
}
void loop() {
//Prepare Premining data
delay(3000);
uint8_t blockheader[80] = {0};
for(int i=0; i<80; i++){
if(i<10) blockheader[i]=0;
else blockheader[i]=0xFF;
}
/* blockheader: 0000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
1rstSHA: 2c6b82fa0260c2a3aca4e22444f3133a07990e5d0bb4c0faebef321027af214e
2ndSHA: 8063482c768e9a922566a895cbc5248ef29f8c0d5a65cc40c64fb74a64ec0a26
SHA256 from online resources:
blockheader: 00000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
1rstSHA: b36b04e42ed7ffc47f300d8b4f96fef9c987bacf0df40793ec8b194afad3cfbe
2ndSHA: 7201f38ecedb9b03df0101b407d5c232e62aa76c885d47055fa0f7bd1aa168ec
*/
Serial.println("");Serial.println("");
Serial.println("BlockHeader on test: ");
for (int i = 0; i < 80; i++)
Serial.printf("%02x", blockheader[i]);
Serial.println("SHA256 from online resources: ");
Serial.println("b36b04e42ed7ffc47f300d8b4f96fef9c987bacf0df40793ec8b194afad3cfbe");
Serial.println("Double SHA256 from online resources:");
Serial.println("7201f38ecedb9b03df0101b407d5c232e62aa76c885d47055fa0f7bd1aa168ec");
Serial.println("----------------------------------------------------------------");
//Test custom SHA
uint8_t hash[32];
uint8_t dhash[32];
uint32_t startT = micros();
calc_sha_256(hash, blockheader, 80);
calc_sha_256(dhash, hash, 32);
uint32_t expired = micros() - startT;
Serial.println("Custom double SHA [" + String(expired) + "us]:");
for (size_t i = 0; i < 32; i++)
Serial.printf("%02x", dhash[i]);
Serial.println("");
//Test WOLF
Sha256 midstate;
Sha256 sha256;
uint8_t hash2[32];
wc_InitSha256(&midstate);
wc_Sha256Update(&midstate, blockheader, 64);
Serial.print("Wolf midstate: ");
for (size_t i = 0; i < 8; i++)
Serial.printf("%02x", midstate.digest[i]);
Serial.println("");
// Mining starts here
//Primer sha
startT = micros();
wc_Sha256Copy(&midstate, &sha256);
wc_Sha256Update(&sha256, blockheader+64, 16);
wc_Sha256Final(&sha256, hash2);
// Segundo SHA-256
wc_Sha256Update(&sha256, hash2, 32);
wc_Sha256Final(&sha256, hash2);
expired = micros() - startT;
Serial.println("Wolf using midstate & double SHA[" + String(expired) + "us]:");
for (size_t i = 0; i < 32; i++)
Serial.printf("%02x", hash2[i]);
Serial.println("");
//Test mbed
mbedtls_sha256_context midstate3;
unsigned char hash3[32];
mbedtls_sha256_context ctx;
//Calcular midstate
mbedtls_sha256_init(&midstate3);
mbedtls_sha256_starts_ret(&midstate3, 0);
mbedtls_sha256_update_ret(&midstate3, blockheader, 64);
Serial.println("Mbed midstate:");
for (size_t i = 0; i < 8; i++)
Serial.printf("%02x", midstate3.state[i]);
Serial.println("");
for (size_t i = 0; i < 32; i++)
Serial.printf("%02x", midstate3.buffer[i]);
Serial.println("");
// Mining starts here
// Primer SHA-256
startT = micros();
mbedtls_sha256_clone(&ctx, &midstate3); //Clonamos el contexto anterior para continuar el SHA desde allí
mbedtls_sha256_update_ret(&ctx, blockheader+64, 16);
mbedtls_sha256_finish_ret(&ctx, hash3);
// Segundo SHA-256
mbedtls_sha256_starts_ret(&ctx, 0);
mbedtls_sha256_update_ret(&ctx, hash3, 32);
mbedtls_sha256_finish_ret(&ctx, hash3);
expired = micros() - startT;
Serial.println("Mbed double SHA[" + String(expired) + "us]:");
for (size_t i = 0; i < 32; i++)
Serial.printf("%02x", hash3[i]);
Serial.println("");
//Test Jade SHA
_sha256_context midstate_cached = { 0 };
memcpy(midstate_cached.buffer, blockheader, 64);
calc_midstate(blockheader, &midstate_cached);
Serial.println("Jade midstate:");
for (size_t i = 0; i < 8; i++)
Serial.printf("%02x", midstate_cached.state[i]);
Serial.println("");
for (size_t i = 0; i < 32; i++)
Serial.printf("%02x", midstate_cached.buffer[i]);
Serial.println("");
*((uint32_t*)&midstate_cached.buffer[12]) = 0xFFFFFFFF;//nonce;
// Mining starts here
startT = micros();
make_double_sha(&midstate_cached);
expired = micros() - startT;
Serial.println("Jade double SHA ["+ String(expired) + "us]:");
for (size_t i = 0; i < 32; i++)
Serial.printf("%02x", midstate_cached.buffer[i]);
Serial.println("");
//Test nerdSHA
nerd_sha256 nerdMidstate;
uint8_t nerdHash[32];
nerd_midstate(&nerdMidstate, blockheader, 64);
Serial.print("Nerd midstate: ");
for (size_t i = 0; i < 8; i++)
Serial.printf("%02x", nerdMidstate.digest[i]);
Serial.println("");
//Mining starts here
startT = micros();
nerd_double_sha(&nerdMidstate, blockheader+64,nerdHash);
expired = micros() - startT;
Serial.println("Nerd double SHA[" + String(expired) + "us]:");
for (size_t i = 0; i < 32; i++)
Serial.printf("%02x", nerdHash[i]);
Serial.println("");
}

View File

@ -1,11 +0,0 @@
This directory is intended for PlatformIO Test Runner and project tests.
Unit Testing is a software testing method by which individual units of
source code, sets of one or more MCU program modules together with associated
control data, usage procedures, and operating procedures, are tested to
determine whether they are fit for use. Unit testing finds problems early
in the development cycle.
More information about PlatformIO Unit Testing:
- https://docs.platformio.org/en/latest/advanced/unit-testing/index.html